From 871480933a1c28f8a9fed4c4d34d06c439a7a422 Mon Sep 17 00:00:00 2001 From: Srikant Patnaik Date: Sun, 11 Jan 2015 12:28:04 +0530 Subject: Moved, renamed, and deleted files The original directory structure was scattered and unorganized. Changes are basically to make it look like kernel structure. --- ANDROID_3.4.5/drivers/scsi/3w-9xxx.c | 2350 --- ANDROID_3.4.5/drivers/scsi/3w-9xxx.h | 686 - ANDROID_3.4.5/drivers/scsi/3w-sas.c | 1931 --- ANDROID_3.4.5/drivers/scsi/3w-sas.h | 396 - ANDROID_3.4.5/drivers/scsi/3w-xxxx.c | 2459 --- ANDROID_3.4.5/drivers/scsi/3w-xxxx.h | 435 - ANDROID_3.4.5/drivers/scsi/53c700.c | 2177 --- ANDROID_3.4.5/drivers/scsi/53c700.h | 524 - ANDROID_3.4.5/drivers/scsi/53c700.scr | 411 - ANDROID_3.4.5/drivers/scsi/53c700_d.h_shipped | 1329 -- ANDROID_3.4.5/drivers/scsi/BusLogic.c | 3631 ----- ANDROID_3.4.5/drivers/scsi/BusLogic.h | 1332 -- ANDROID_3.4.5/drivers/scsi/FlashPoint.c | 7644 --------- ANDROID_3.4.5/drivers/scsi/Kconfig | 1923 --- ANDROID_3.4.5/drivers/scsi/Makefile | 205 - ANDROID_3.4.5/drivers/scsi/NCR5380.c | 2846 ---- ANDROID_3.4.5/drivers/scsi/NCR5380.h | 437 - ANDROID_3.4.5/drivers/scsi/NCR53c406a.c | 1091 -- ANDROID_3.4.5/drivers/scsi/NCR_D700.c | 405 - ANDROID_3.4.5/drivers/scsi/NCR_D700.h | 29 - ANDROID_3.4.5/drivers/scsi/NCR_Q720.c | 377 - ANDROID_3.4.5/drivers/scsi/NCR_Q720.h | 28 - ANDROID_3.4.5/drivers/scsi/a100u2w.c | 1245 -- ANDROID_3.4.5/drivers/scsi/a100u2w.h | 371 - ANDROID_3.4.5/drivers/scsi/a2091.c | 281 - ANDROID_3.4.5/drivers/scsi/a2091.h | 69 - ANDROID_3.4.5/drivers/scsi/a3000.c | 297 - ANDROID_3.4.5/drivers/scsi/a3000.h | 72 - ANDROID_3.4.5/drivers/scsi/a4000t.c | 138 - ANDROID_3.4.5/drivers/scsi/aacraid/Makefile | 8 - ANDROID_3.4.5/drivers/scsi/aacraid/TODO | 3 - ANDROID_3.4.5/drivers/scsi/aacraid/aachba.c | 3011 ---- ANDROID_3.4.5/drivers/scsi/aacraid/aacraid.h | 2022 --- ANDROID_3.4.5/drivers/scsi/aacraid/commctrl.c | 885 - ANDROID_3.4.5/drivers/scsi/aacraid/comminit.c | 473 - ANDROID_3.4.5/drivers/scsi/aacraid/commsup.c | 1922 --- ANDROID_3.4.5/drivers/scsi/aacraid/dpcsup.c | 418 - ANDROID_3.4.5/drivers/scsi/aacraid/linit.c | 1366 -- ANDROID_3.4.5/drivers/scsi/aacraid/nark.c | 84 - ANDROID_3.4.5/drivers/scsi/aacraid/rkt.c | 107 - ANDROID_3.4.5/drivers/scsi/aacraid/rx.c | 683 - ANDROID_3.4.5/drivers/scsi/aacraid/sa.c | 417 - ANDROID_3.4.5/drivers/scsi/aacraid/src.c | 784 - ANDROID_3.4.5/drivers/scsi/advansys.c | 12857 --------------- ANDROID_3.4.5/drivers/scsi/aha152x.c | 3984 ----- ANDROID_3.4.5/drivers/scsi/aha152x.h | 337 - ANDROID_3.4.5/drivers/scsi/aha1542.c | 1744 -- ANDROID_3.4.5/drivers/scsi/aha1542.h | 150 - ANDROID_3.4.5/drivers/scsi/aha1740.c | 697 - ANDROID_3.4.5/drivers/scsi/aha1740.h | 154 - ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic79xx | 85 - ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic7xxx | 90 - ANDROID_3.4.5/drivers/scsi/aic7xxx/Makefile | 85 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770.c | 391 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770_osm.c | 156 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.h | 1478 -- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.reg | 4281 ----- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.seq | 2290 --- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_core.c | 10823 ------------- .../drivers/scsi/aic7xxx/aic79xx_inline.h | 172 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.c | 2903 ---- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.h | 703 - .../drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 398 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.c | 1022 -- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.h | 72 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_proc.c | 382 - .../drivers/scsi/aic7xxx/aic79xx_reg.h_shipped | 2685 ---- .../scsi/aic7xxx/aic79xx_reg_print.c_shipped | 745 - .../drivers/scsi/aic7xxx/aic79xx_seq.h_shipped | 1190 -- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.h | 1284 -- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.reg | 1761 -- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.seq | 2399 --- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c | 324 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h | 102 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_core.c | 7973 --------- .../drivers/scsi/aic7xxx/aic7xxx_inline.h | 97 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.c | 2624 --- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.h | 713 - .../drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 471 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.c | 2469 --- ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.h | 125 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_proc.c | 407 - .../drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped | 912 -- .../scsi/aic7xxx/aic7xxx_reg_print.c_shipped | 413 - .../drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped | 1308 -- ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/Makefile | 80 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.c | 844 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.h | 95 - .../drivers/scsi/aic7xxx/aicasm/aicasm_gram.y | 2004 --- .../drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h | 219 - .../scsi/aic7xxx/aicasm/aicasm_macro_gram.y | 165 - .../scsi/aic7xxx/aicasm/aicasm_macro_scan.l | 157 - .../drivers/scsi/aic7xxx/aicasm/aicasm_scan.l | 622 - .../drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c | 693 - .../drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h | 209 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.c | 34 - ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.h | 195 - ANDROID_3.4.5/drivers/scsi/aic7xxx/cam.h | 111 - ANDROID_3.4.5/drivers/scsi/aic7xxx/queue.h | 501 - ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_iu.h | 39 - ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_message.h | 70 - ANDROID_3.4.5/drivers/scsi/aic7xxx_old.c | 11149 ------------- ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.h | 28 - ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.reg | 1401 -- ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.seq | 1539 -- .../drivers/scsi/aic7xxx_old/aic7xxx_proc.c | 373 - .../drivers/scsi/aic7xxx_old/aic7xxx_reg.h | 629 - .../drivers/scsi/aic7xxx_old/aic7xxx_seq.c | 817 - .../drivers/scsi/aic7xxx_old/scsi_message.h | 49 - ANDROID_3.4.5/drivers/scsi/aic7xxx_old/sequencer.h | 135 - ANDROID_3.4.5/drivers/scsi/aic94xx/Kconfig | 42 - ANDROID_3.4.5/drivers/scsi/aic94xx/Makefile | 37 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx.h | 101 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dev.c | 363 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.c | 967 -- ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.h | 43 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.c | 1391 -- ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.h | 398 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_init.c | 1091 -- ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.c | 331 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.h | 302 - .../drivers/scsi/aic94xx/aic94xx_reg_def.h | 2399 --- ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sas.h | 787 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_scb.c | 937 -- ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.c | 1475 -- ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.h | 121 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.c | 1416 -- ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.h | 68 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_task.c | 643 - ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_tmf.c | 714 - ANDROID_3.4.5/drivers/scsi/arcmsr/Makefile | 6 - ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr.h | 692 - ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_attr.c | 402 - ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_hba.c | 3127 ---- ANDROID_3.4.5/drivers/scsi/arm/Kconfig | 84 - ANDROID_3.4.5/drivers/scsi/arm/Makefile | 13 - ANDROID_3.4.5/drivers/scsi/arm/acornscsi-io.S | 138 - ANDROID_3.4.5/drivers/scsi/arm/acornscsi.c | 3088 ---- ANDROID_3.4.5/drivers/scsi/arm/acornscsi.h | 353 - ANDROID_3.4.5/drivers/scsi/arm/arxescsi.c | 385 - ANDROID_3.4.5/drivers/scsi/arm/cumana_1.c | 344 - ANDROID_3.4.5/drivers/scsi/arm/cumana_2.c | 546 - ANDROID_3.4.5/drivers/scsi/arm/eesox.c | 670 - ANDROID_3.4.5/drivers/scsi/arm/fas216.c | 3045 ---- ANDROID_3.4.5/drivers/scsi/arm/fas216.h | 393 - ANDROID_3.4.5/drivers/scsi/arm/msgqueue.c | 171 - ANDROID_3.4.5/drivers/scsi/arm/msgqueue.h | 82 - ANDROID_3.4.5/drivers/scsi/arm/oak.c | 227 - ANDROID_3.4.5/drivers/scsi/arm/powertec.c | 462 - ANDROID_3.4.5/drivers/scsi/arm/queue.c | 317 - ANDROID_3.4.5/drivers/scsi/arm/queue.h | 107 - ANDROID_3.4.5/drivers/scsi/arm/scsi.h | 128 - ANDROID_3.4.5/drivers/scsi/atari_NCR5380.c | 2993 ---- ANDROID_3.4.5/drivers/scsi/atari_scsi.c | 1111 -- ANDROID_3.4.5/drivers/scsi/atari_scsi.h | 184 - ANDROID_3.4.5/drivers/scsi/atp870u.c | 3915 ----- ANDROID_3.4.5/drivers/scsi/atp870u.h | 67 - ANDROID_3.4.5/drivers/scsi/be2iscsi/Kconfig | 9 - ANDROID_3.4.5/drivers/scsi/be2iscsi/Makefile | 8 - ANDROID_3.4.5/drivers/scsi/be2iscsi/be.h | 190 - ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.c | 890 - ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.h | 1028 -- ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.c | 787 - ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.h | 76 - ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.c | 4485 ------ ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.h | 862 - ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.c | 449 - ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.h | 251 - ANDROID_3.4.5/drivers/scsi/bfa/Makefile | 6 - ANDROID_3.4.5/drivers/scsi/bfa/bfa.h | 448 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_core.c | 1925 --- ANDROID_3.4.5/drivers/scsi/bfa/bfa_cs.h | 366 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs.h | 1152 -- ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_fcs.h | 460 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_svc.h | 1328 -- ANDROID_3.4.5/drivers/scsi/bfa/bfa_fc.h | 1598 -- ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.c | 1438 -- ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.h | 326 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.c | 3825 ----- ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.h | 420 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.c | 1548 -- ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.h | 828 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_fcpim.c | 826 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_lport.c | 6069 ------- ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_rport.c | 3019 ---- ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_cb.c | 191 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_ct.c | 178 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.c | 5937 ------- ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.h | 981 -- ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_cb.c | 313 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_ct.c | 921 -- ANDROID_3.4.5/drivers/scsi/bfa/bfa_modules.h | 137 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_plog.h | 155 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.c | 848 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.h | 123 - ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.c | 5721 ------- ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.h | 714 - ANDROID_3.4.5/drivers/scsi/bfa/bfad.c | 1652 -- ANDROID_3.4.5/drivers/scsi/bfa/bfad_attr.c | 978 -- ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.c | 3216 ---- ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.h | 744 - ANDROID_3.4.5/drivers/scsi/bfa/bfad_debugfs.c | 572 - ANDROID_3.4.5/drivers/scsi/bfa/bfad_drv.h | 357 - ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.c | 1323 -- ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.h | 196 - ANDROID_3.4.5/drivers/scsi/bfa/bfi.h | 1152 -- ANDROID_3.4.5/drivers/scsi/bfa/bfi_ms.h | 865 - ANDROID_3.4.5/drivers/scsi/bfa/bfi_reg.h | 456 - .../drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h | 990 -- ANDROID_3.4.5/drivers/scsi/bnx2fc/Kconfig | 12 - ANDROID_3.4.5/drivers/scsi/bnx2fc/Makefile | 3 - ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc.h | 554 - .../drivers/scsi/bnx2fc/bnx2fc_constants.h | 274 - ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_debug.h | 70 - ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_els.c | 929 -- ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_fcoe.c | 2559 --- ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_hwi.c | 2189 --- ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_io.c | 2032 --- ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_tgt.c | 870 - .../drivers/scsi/bnx2i/57xx_iscsi_constants.h | 159 - ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_hsi.h | 1514 -- ANDROID_3.4.5/drivers/scsi/bnx2i/Kconfig | 12 - ANDROID_3.4.5/drivers/scsi/bnx2i/Makefile | 3 - ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i.h | 821 - ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_hwi.c | 2751 ---- ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_init.c | 565 - ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_iscsi.c | 2287 --- ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_sysfs.c | 143 - ANDROID_3.4.5/drivers/scsi/bvme6000_scsi.c | 139 - ANDROID_3.4.5/drivers/scsi/ch.c | 1030 -- ANDROID_3.4.5/drivers/scsi/constants.c | 1462 -- ANDROID_3.4.5/drivers/scsi/cxgbi/Kconfig | 2 - ANDROID_3.4.5/drivers/scsi/cxgbi/Makefile | 2 - ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kbuild | 3 - ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kconfig | 10 - ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c | 1412 -- ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h | 62 - ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kbuild | 3 - ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kconfig | 10 - ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 1593 -- ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h | 43 - ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.c | 2645 --- ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.h | 743 - ANDROID_3.4.5/drivers/scsi/dc395x.c | 4924 ------ ANDROID_3.4.5/drivers/scsi/dc395x.h | 648 - ANDROID_3.4.5/drivers/scsi/device_handler/Kconfig | 40 - ANDROID_3.4.5/drivers/scsi/device_handler/Makefile | 8 - .../drivers/scsi/device_handler/scsi_dh.c | 559 - .../drivers/scsi/device_handler/scsi_dh_alua.c | 798 - .../drivers/scsi/device_handler/scsi_dh_emc.c | 755 - .../drivers/scsi/device_handler/scsi_dh_hp_sw.c | 431 - .../drivers/scsi/device_handler/scsi_dh_rdac.c | 978 -- ANDROID_3.4.5/drivers/scsi/dmx3191d.c | 171 - ANDROID_3.4.5/drivers/scsi/dpt/dpti_i2o.h | 446 - ANDROID_3.4.5/drivers/scsi/dpt/dpti_ioctl.h | 139 - ANDROID_3.4.5/drivers/scsi/dpt/dptsig.h | 336 - ANDROID_3.4.5/drivers/scsi/dpt/osd_defs.h | 79 - ANDROID_3.4.5/drivers/scsi/dpt/osd_util.h | 358 - ANDROID_3.4.5/drivers/scsi/dpt/sys_info.h | 417 - ANDROID_3.4.5/drivers/scsi/dpt_i2o.c | 3700 ----- ANDROID_3.4.5/drivers/scsi/dpti.h | 337 - ANDROID_3.4.5/drivers/scsi/dtc.c | 485 - ANDROID_3.4.5/drivers/scsi/dtc.h | 99 - ANDROID_3.4.5/drivers/scsi/eata.c | 2590 --- ANDROID_3.4.5/drivers/scsi/eata_generic.h | 400 - ANDROID_3.4.5/drivers/scsi/eata_pio.c | 1001 -- ANDROID_3.4.5/drivers/scsi/eata_pio.h | 53 - ANDROID_3.4.5/drivers/scsi/esp_scsi.c | 2734 ---- ANDROID_3.4.5/drivers/scsi/esp_scsi.h | 566 - ANDROID_3.4.5/drivers/scsi/fcoe/Makefile | 4 - ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.c | 2734 ---- ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.h | 98 - ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_ctlr.c | 2749 ---- ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_transport.c | 831 - ANDROID_3.4.5/drivers/scsi/fcoe/libfcoe.h | 31 - ANDROID_3.4.5/drivers/scsi/fd_mcs.c | 1354 -- ANDROID_3.4.5/drivers/scsi/fdomain.c | 1784 --- ANDROID_3.4.5/drivers/scsi/fdomain.h | 24 - ANDROID_3.4.5/drivers/scsi/fnic/Makefile | 15 - ANDROID_3.4.5/drivers/scsi/fnic/cq_desc.h | 78 - ANDROID_3.4.5/drivers/scsi/fnic/cq_enet_desc.h | 167 - ANDROID_3.4.5/drivers/scsi/fnic/cq_exch_desc.h | 182 - ANDROID_3.4.5/drivers/scsi/fnic/fcpio.h | 780 - ANDROID_3.4.5/drivers/scsi/fnic/fnic.h | 270 - ANDROID_3.4.5/drivers/scsi/fnic/fnic_attrs.c | 56 - ANDROID_3.4.5/drivers/scsi/fnic/fnic_fcs.c | 720 - ANDROID_3.4.5/drivers/scsi/fnic/fnic_io.h | 67 - ANDROID_3.4.5/drivers/scsi/fnic/fnic_isr.c | 332 - ANDROID_3.4.5/drivers/scsi/fnic/fnic_main.c | 947 -- ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.c | 443 - ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.h | 249 - ANDROID_3.4.5/drivers/scsi/fnic/fnic_scsi.c | 1824 --- ANDROID_3.4.5/drivers/scsi/fnic/rq_enet_desc.h | 58 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.c | 85 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.h | 121 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq_copy.h | 62 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.c | 691 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.h | 161 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_devcmd.h | 281 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.c | 60 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.h | 118 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_nic.h | 69 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_resource.h | 61 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.c | 197 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.h | 235 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_scsi.h | 100 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_stats.h | 68 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.c | 183 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.h | 175 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.c | 117 - ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.h | 128 - ANDROID_3.4.5/drivers/scsi/fnic/wq_enet_desc.h | 96 - ANDROID_3.4.5/drivers/scsi/g_NCR5380.c | 956 -- ANDROID_3.4.5/drivers/scsi/g_NCR5380.h | 137 - ANDROID_3.4.5/drivers/scsi/g_NCR5380_mmio.c | 10 - ANDROID_3.4.5/drivers/scsi/gdth.c | 5243 ------ ANDROID_3.4.5/drivers/scsi/gdth.h | 1021 -- ANDROID_3.4.5/drivers/scsi/gdth_ioctl.h | 339 - ANDROID_3.4.5/drivers/scsi/gdth_proc.c | 760 - ANDROID_3.4.5/drivers/scsi/gdth_proc.h | 25 - ANDROID_3.4.5/drivers/scsi/gvp11.c | 433 - ANDROID_3.4.5/drivers/scsi/gvp11.h | 52 - ANDROID_3.4.5/drivers/scsi/hosts.c | 585 - ANDROID_3.4.5/drivers/scsi/hpsa.c | 4716 ------ ANDROID_3.4.5/drivers/scsi/hpsa.h | 373 - ANDROID_3.4.5/drivers/scsi/hpsa_cmd.h | 366 - ANDROID_3.4.5/drivers/scsi/hptiop.c | 1311 -- ANDROID_3.4.5/drivers/scsi/hptiop.h | 311 - ANDROID_3.4.5/drivers/scsi/ibmmca.c | 2379 --- ANDROID_3.4.5/drivers/scsi/ibmvscsi/Makefile | 7 - ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.c | 4973 ------ ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.h | 774 - ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.c | 2102 --- ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.h | 132 - ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvstgt.c | 1001 -- ANDROID_3.4.5/drivers/scsi/ibmvscsi/rpa_vscsi.c | 368 - ANDROID_3.4.5/drivers/scsi/ibmvscsi/viosrp.h | 217 - ANDROID_3.4.5/drivers/scsi/imm.c | 1286 -- ANDROID_3.4.5/drivers/scsi/imm.h | 143 - ANDROID_3.4.5/drivers/scsi/in2000.c | 2336 --- ANDROID_3.4.5/drivers/scsi/in2000.h | 412 - ANDROID_3.4.5/drivers/scsi/initio.c | 3013 ---- ANDROID_3.4.5/drivers/scsi/initio.h | 667 - ANDROID_3.4.5/drivers/scsi/ipr.c | 9330 ----------- ANDROID_3.4.5/drivers/scsi/ipr.h | 1898 --- ANDROID_3.4.5/drivers/scsi/ips.c | 7247 --------- ANDROID_3.4.5/drivers/scsi/ips.h | 1260 -- ANDROID_3.4.5/drivers/scsi/isci/Makefile | 8 - ANDROID_3.4.5/drivers/scsi/isci/host.c | 3034 ---- ANDROID_3.4.5/drivers/scsi/isci/host.h | 568 - ANDROID_3.4.5/drivers/scsi/isci/init.c | 596 - ANDROID_3.4.5/drivers/scsi/isci/isci.h | 539 - ANDROID_3.4.5/drivers/scsi/isci/phy.c | 1421 -- ANDROID_3.4.5/drivers/scsi/isci/phy.h | 467 - ANDROID_3.4.5/drivers/scsi/isci/port.c | 1764 -- ANDROID_3.4.5/drivers/scsi/isci/port.h | 284 - ANDROID_3.4.5/drivers/scsi/isci/port_config.c | 763 - ANDROID_3.4.5/drivers/scsi/isci/probe_roms.c | 243 - ANDROID_3.4.5/drivers/scsi/isci/probe_roms.h | 332 - ANDROID_3.4.5/drivers/scsi/isci/registers.h | 1855 --- ANDROID_3.4.5/drivers/scsi/isci/remote_device.c | 1436 -- ANDROID_3.4.5/drivers/scsi/isci/remote_device.h | 336 - .../drivers/scsi/isci/remote_node_context.c | 624 - .../drivers/scsi/isci/remote_node_context.h | 213 - .../drivers/scsi/isci/remote_node_table.c | 598 - .../drivers/scsi/isci/remote_node_table.h | 188 - ANDROID_3.4.5/drivers/scsi/isci/request.c | 3631 ----- ANDROID_3.4.5/drivers/scsi/isci/request.h | 425 - ANDROID_3.4.5/drivers/scsi/isci/sas.h | 217 - .../drivers/scsi/isci/scu_completion_codes.h | 283 - ANDROID_3.4.5/drivers/scsi/isci/scu_event_codes.h | 336 - .../drivers/scsi/isci/scu_remote_node_context.h | 229 - ANDROID_3.4.5/drivers/scsi/isci/scu_task_context.h | 965 -- ANDROID_3.4.5/drivers/scsi/isci/task.c | 1323 -- ANDROID_3.4.5/drivers/scsi/isci/task.h | 320 - .../drivers/scsi/isci/unsolicited_frame_control.c | 225 - .../drivers/scsi/isci/unsolicited_frame_control.h | 278 - ANDROID_3.4.5/drivers/scsi/iscsi_boot_sysfs.c | 494 - ANDROID_3.4.5/drivers/scsi/iscsi_tcp.c | 1011 -- ANDROID_3.4.5/drivers/scsi/iscsi_tcp.h | 68 - ANDROID_3.4.5/drivers/scsi/jazz_esp.c | 249 - ANDROID_3.4.5/drivers/scsi/lasi700.c | 187 - ANDROID_3.4.5/drivers/scsi/libfc/Makefile | 14 - ANDROID_3.4.5/drivers/scsi/libfc/fc_disc.c | 743 - ANDROID_3.4.5/drivers/scsi/libfc/fc_elsct.c | 152 - ANDROID_3.4.5/drivers/scsi/libfc/fc_exch.c | 2519 --- ANDROID_3.4.5/drivers/scsi/libfc/fc_fcp.c | 2286 --- ANDROID_3.4.5/drivers/scsi/libfc/fc_frame.c | 91 - ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.c | 331 - ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.h | 139 - ANDROID_3.4.5/drivers/scsi/libfc/fc_lport.c | 2135 --- ANDROID_3.4.5/drivers/scsi/libfc/fc_npiv.c | 159 - ANDROID_3.4.5/drivers/scsi/libfc/fc_rport.c | 2042 --- ANDROID_3.4.5/drivers/scsi/libiscsi.c | 3472 ---- ANDROID_3.4.5/drivers/scsi/libiscsi_tcp.c | 1206 -- ANDROID_3.4.5/drivers/scsi/libsas/Kconfig | 48 - ANDROID_3.4.5/drivers/scsi/libsas/Makefile | 35 - ANDROID_3.4.5/drivers/scsi/libsas/sas_ata.c | 828 - ANDROID_3.4.5/drivers/scsi/libsas/sas_discover.c | 534 - ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.c | 72 - ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.h | 30 - ANDROID_3.4.5/drivers/scsi/libsas/sas_event.c | 165 - ANDROID_3.4.5/drivers/scsi/libsas/sas_expander.c | 2184 --- ANDROID_3.4.5/drivers/scsi/libsas/sas_host_smp.c | 383 - ANDROID_3.4.5/drivers/scsi/libsas/sas_init.c | 513 - ANDROID_3.4.5/drivers/scsi/libsas/sas_internal.h | 201 - ANDROID_3.4.5/drivers/scsi/libsas/sas_phy.c | 160 - ANDROID_3.4.5/drivers/scsi/libsas/sas_port.c | 305 - ANDROID_3.4.5/drivers/scsi/libsas/sas_scsi_host.c | 1071 -- ANDROID_3.4.5/drivers/scsi/libsas/sas_task.c | 37 - ANDROID_3.4.5/drivers/scsi/libsrp.c | 447 - ANDROID_3.4.5/drivers/scsi/lpfc/Makefile | 31 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc.h | 1004 -- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_attr.c | 4950 ------ ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.c | 5195 ------ ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.h | 285 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_compat.h | 96 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_crtn.h | 465 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_ct.c | 1910 --- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.c | 4468 ------ ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.h | 269 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_disc.h | 265 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_els.c | 7898 --------- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hbadisc.c | 6143 ------- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw.h | 3835 ----- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw4.h | 3505 ---- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_init.c | 10329 ------------ ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_logmsg.h | 58 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mbox.c | 2344 --- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mem.c | 529 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nl.h | 179 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nportdisc.c | 2382 --- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.c | 5031 ------ ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.h | 167 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.c | 16044 ------------------- ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.h | 304 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli4.h | 663 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_version.h | 28 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.c | 877 - ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.h | 119 - ANDROID_3.4.5/drivers/scsi/mac53c94.c | 572 - ANDROID_3.4.5/drivers/scsi/mac53c94.h | 214 - ANDROID_3.4.5/drivers/scsi/mac_esp.c | 641 - ANDROID_3.4.5/drivers/scsi/mac_scsi.c | 580 - ANDROID_3.4.5/drivers/scsi/mac_scsi.h | 83 - ANDROID_3.4.5/drivers/scsi/megaraid.c | 5072 ------ ANDROID_3.4.5/drivers/scsi/megaraid.h | 1063 -- .../drivers/scsi/megaraid/Kconfig.megaraid | 85 - ANDROID_3.4.5/drivers/scsi/megaraid/Makefile | 5 - ANDROID_3.4.5/drivers/scsi/megaraid/mbox_defs.h | 790 - ANDROID_3.4.5/drivers/scsi/megaraid/mega_common.h | 290 - .../drivers/scsi/megaraid/megaraid_ioctl.h | 300 - .../drivers/scsi/megaraid/megaraid_mbox.c | 4173 ----- .../drivers/scsi/megaraid/megaraid_mbox.h | 238 - ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.c | 1261 -- ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.h | 101 - ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas.h | 1492 -- .../drivers/scsi/megaraid/megaraid_sas_base.c | 5487 ------- .../drivers/scsi/megaraid/megaraid_sas_fp.c | 526 - .../drivers/scsi/megaraid/megaraid_sas_fusion.c | 2358 --- .../drivers/scsi/megaraid/megaraid_sas_fusion.h | 706 - ANDROID_3.4.5/drivers/scsi/mesh.c | 2076 --- ANDROID_3.4.5/drivers/scsi/mesh.h | 127 - ANDROID_3.4.5/drivers/scsi/mpt2sas/Kconfig | 67 - ANDROID_3.4.5/drivers/scsi/mpt2sas/Makefile | 7 - ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2.h | 1149 -- ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h | 2978 ---- ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_init.h | 452 - ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h | 1648 -- ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_raid.h | 356 - ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_sas.h | 288 - ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_tool.h | 437 - ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_type.h | 61 - ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.c | 4614 ------ ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.h | 1161 -- .../drivers/scsi/mpt2sas/mpt2sas_config.c | 1454 -- ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.c | 3058 ---- ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.h | 418 - ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_debug.h | 181 - ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_scsih.c | 8384 ---------- .../drivers/scsi/mpt2sas/mpt2sas_transport.c | 2022 --- ANDROID_3.4.5/drivers/scsi/mvme147.c | 165 - ANDROID_3.4.5/drivers/scsi/mvme147.h | 24 - ANDROID_3.4.5/drivers/scsi/mvme16x_scsi.c | 162 - ANDROID_3.4.5/drivers/scsi/mvsas/Kconfig | 50 - ANDROID_3.4.5/drivers/scsi/mvsas/Makefile | 31 - ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.c | 828 - ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.h | 152 - ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.c | 1062 -- ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.h | 288 - ANDROID_3.4.5/drivers/scsi/mvsas/mv_chips.h | 270 - ANDROID_3.4.5/drivers/scsi/mvsas/mv_defs.h | 510 - ANDROID_3.4.5/drivers/scsi/mvsas/mv_init.c | 869 - ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.c | 2194 --- ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.h | 486 - ANDROID_3.4.5/drivers/scsi/mvumi.c | 2018 --- ANDROID_3.4.5/drivers/scsi/mvumi.h | 505 - ANDROID_3.4.5/drivers/scsi/ncr53c8xx.c | 8629 ---------- ANDROID_3.4.5/drivers/scsi/ncr53c8xx.h | 1329 -- ANDROID_3.4.5/drivers/scsi/nsp32.c | 3461 ---- ANDROID_3.4.5/drivers/scsi/nsp32.h | 617 - ANDROID_3.4.5/drivers/scsi/nsp32_debug.c | 263 - ANDROID_3.4.5/drivers/scsi/nsp32_io.h | 259 - ANDROID_3.4.5/drivers/scsi/osd/Kbuild | 20 - ANDROID_3.4.5/drivers/scsi/osd/Kconfig | 49 - ANDROID_3.4.5/drivers/scsi/osd/osd_debug.h | 30 - ANDROID_3.4.5/drivers/scsi/osd/osd_initiator.c | 2067 --- ANDROID_3.4.5/drivers/scsi/osd/osd_uld.c | 571 - ANDROID_3.4.5/drivers/scsi/osst.c | 6095 ------- ANDROID_3.4.5/drivers/scsi/osst.h | 650 - ANDROID_3.4.5/drivers/scsi/osst_detect.h | 6 - ANDROID_3.4.5/drivers/scsi/osst_options.h | 106 - ANDROID_3.4.5/drivers/scsi/pas16.c | 637 - ANDROID_3.4.5/drivers/scsi/pas16.h | 175 - ANDROID_3.4.5/drivers/scsi/pcmcia/Kconfig | 83 - ANDROID_3.4.5/drivers/scsi/pcmcia/Makefile | 13 - ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_core.c | 3 - ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_stub.c | 235 - ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_core.c | 2 - ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_stub.c | 209 - ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.c | 1791 --- ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.h | 397 - ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_debug.c | 215 - ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_io.h | 274 - ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_message.c | 78 - ANDROID_3.4.5/drivers/scsi/pcmcia/qlogic_stub.c | 318 - ANDROID_3.4.5/drivers/scsi/pcmcia/sym53c500_cs.c | 898 -- ANDROID_3.4.5/drivers/scsi/pm8001/Makefile | 12 - ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_chips.h | 89 - ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.c | 574 - ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.h | 57 - ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_defs.h | 112 - ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.c | 4712 ------ ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.h | 1029 -- ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_init.c | 908 -- ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.c | 1185 -- ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.h | 502 - ANDROID_3.4.5/drivers/scsi/pmcraid.c | 6158 ------- ANDROID_3.4.5/drivers/scsi/pmcraid.h | 1095 -- ANDROID_3.4.5/drivers/scsi/ppa.c | 1148 -- ANDROID_3.4.5/drivers/scsi/ppa.h | 150 - ANDROID_3.4.5/drivers/scsi/ps3rom.c | 460 - ANDROID_3.4.5/drivers/scsi/qla1280.c | 4505 ------ ANDROID_3.4.5/drivers/scsi/qla1280.h | 1081 -- ANDROID_3.4.5/drivers/scsi/qla2xxx/Kconfig | 27 - ANDROID_3.4.5/drivers/scsi/qla2xxx/Makefile | 5 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_attr.c | 1971 --- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.c | 1716 -- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.h | 186 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.c | 2495 --- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.h | 341 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_def.h | 3068 ---- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_devtbl.h | 99 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dfs.c | 181 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_fw.h | 1891 --- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gbl.h | 611 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gs.c | 2025 --- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_init.c | 5558 ------- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_inline.h | 189 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_iocb.c | 2647 --- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_isr.c | 2597 --- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mbx.c | 4571 ------ ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mid.c | 836 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.c | 4428 ----- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.h | 1181 -- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_os.c | 4533 ------ ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_settings.h | 12 - ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_sup.c | 3044 ---- ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_version.h | 15 - ANDROID_3.4.5/drivers/scsi/qla4xxx/Kconfig | 8 - ANDROID_3.4.5/drivers/scsi/qla4xxx/Makefile | 5 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_attr.c | 145 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.c | 513 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.h | 19 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.c | 133 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.h | 55 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_def.h | 939 -- ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_fw.h | 1193 -- ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_glbl.h | 205 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_init.c | 1131 -- ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_inline.h | 84 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_iocb.c | 539 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_isr.c | 1253 -- ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_mbx.c | 1882 --- ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.c | 256 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.h | 254 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.c | 2420 --- ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.h | 795 - ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_os.c | 6044 ------- ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_version.h | 8 - ANDROID_3.4.5/drivers/scsi/qlogicfas.c | 228 - ANDROID_3.4.5/drivers/scsi/qlogicfas408.c | 617 - ANDROID_3.4.5/drivers/scsi/qlogicfas408.h | 118 - ANDROID_3.4.5/drivers/scsi/qlogicpti.c | 1493 -- ANDROID_3.4.5/drivers/scsi/qlogicpti.h | 507 - ANDROID_3.4.5/drivers/scsi/raid_class.c | 317 - ANDROID_3.4.5/drivers/scsi/script_asm.pl | 984 -- ANDROID_3.4.5/drivers/scsi/scsi.c | 1356 -- ANDROID_3.4.5/drivers/scsi/scsi.h | 48 - ANDROID_3.4.5/drivers/scsi/scsi_debug.c | 4076 ----- ANDROID_3.4.5/drivers/scsi/scsi_devinfo.c | 896 -- ANDROID_3.4.5/drivers/scsi/scsi_error.c | 2207 --- ANDROID_3.4.5/drivers/scsi/scsi_ioctl.c | 330 - ANDROID_3.4.5/drivers/scsi/scsi_lib.c | 2589 --- ANDROID_3.4.5/drivers/scsi/scsi_lib_dma.c | 51 - ANDROID_3.4.5/drivers/scsi/scsi_logging.h | 83 - ANDROID_3.4.5/drivers/scsi/scsi_module.c | 73 - ANDROID_3.4.5/drivers/scsi/scsi_netlink.c | 680 - ANDROID_3.4.5/drivers/scsi/scsi_pm.c | 246 - ANDROID_3.4.5/drivers/scsi/scsi_priv.h | 175 - ANDROID_3.4.5/drivers/scsi/scsi_proc.c | 492 - ANDROID_3.4.5/drivers/scsi/scsi_sas_internal.h | 42 - ANDROID_3.4.5/drivers/scsi/scsi_scan.c | 1953 --- ANDROID_3.4.5/drivers/scsi/scsi_sysctl.c | 51 - ANDROID_3.4.5/drivers/scsi/scsi_sysfs.c | 1126 -- ANDROID_3.4.5/drivers/scsi/scsi_tgt_if.c | 399 - ANDROID_3.4.5/drivers/scsi/scsi_tgt_lib.c | 660 - ANDROID_3.4.5/drivers/scsi/scsi_tgt_priv.h | 32 - ANDROID_3.4.5/drivers/scsi/scsi_trace.c | 288 - ANDROID_3.4.5/drivers/scsi/scsi_transport_api.h | 6 - ANDROID_3.4.5/drivers/scsi/scsi_transport_fc.c | 4180 ----- .../drivers/scsi/scsi_transport_fc_internal.h | 26 - ANDROID_3.4.5/drivers/scsi/scsi_transport_iscsi.c | 3020 ---- ANDROID_3.4.5/drivers/scsi/scsi_transport_sas.c | 1971 --- ANDROID_3.4.5/drivers/scsi/scsi_transport_spi.c | 1609 -- ANDROID_3.4.5/drivers/scsi/scsi_transport_srp.c | 383 - .../drivers/scsi/scsi_transport_srp_internal.h | 25 - ANDROID_3.4.5/drivers/scsi/scsi_typedefs.h | 2 - ANDROID_3.4.5/drivers/scsi/scsi_wait_scan.c | 42 - ANDROID_3.4.5/drivers/scsi/scsicam.c | 259 - ANDROID_3.4.5/drivers/scsi/sd.c | 2990 ---- ANDROID_3.4.5/drivers/scsi/sd.h | 177 - ANDROID_3.4.5/drivers/scsi/sd_dif.c | 481 - ANDROID_3.4.5/drivers/scsi/ses.c | 754 - ANDROID_3.4.5/drivers/scsi/sg.c | 2625 --- ANDROID_3.4.5/drivers/scsi/sgiwd93.c | 338 - ANDROID_3.4.5/drivers/scsi/sim710.c | 375 - ANDROID_3.4.5/drivers/scsi/sni_53c710.c | 155 - ANDROID_3.4.5/drivers/scsi/sr.c | 1000 -- ANDROID_3.4.5/drivers/scsi/sr.h | 77 - ANDROID_3.4.5/drivers/scsi/sr_ioctl.c | 598 - ANDROID_3.4.5/drivers/scsi/sr_vendor.c | 329 - ANDROID_3.4.5/drivers/scsi/st.c | 4649 ------ ANDROID_3.4.5/drivers/scsi/st.h | 224 - ANDROID_3.4.5/drivers/scsi/st_options.h | 104 - ANDROID_3.4.5/drivers/scsi/stex.c | 1837 --- ANDROID_3.4.5/drivers/scsi/storvsc_drv.c | 1548 -- ANDROID_3.4.5/drivers/scsi/sun3_NCR5380.c | 2960 ---- ANDROID_3.4.5/drivers/scsi/sun3_scsi.c | 646 - ANDROID_3.4.5/drivers/scsi/sun3_scsi.h | 379 - ANDROID_3.4.5/drivers/scsi/sun3_scsi_vme.c | 589 - ANDROID_3.4.5/drivers/scsi/sun3x_esp.c | 319 - ANDROID_3.4.5/drivers/scsi/sun_esp.c | 661 - ANDROID_3.4.5/drivers/scsi/sym53c416.c | 845 - ANDROID_3.4.5/drivers/scsi/sym53c416.h | 33 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/Makefile | 4 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym53c8xx.h | 215 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_defs.h | 792 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.c | 554 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.h | 205 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw1.h | 1790 --- ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw2.h | 1875 --- ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.c | 2157 --- ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.h | 270 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.c | 5838 ------- ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.h | 1226 -- .../drivers/scsi/sym53c8xx_2/sym_malloc.c | 378 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_misc.h | 190 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_nvram.c | 779 - ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_nvram.h | 214 - ANDROID_3.4.5/drivers/scsi/t128.c | 446 - ANDROID_3.4.5/drivers/scsi/t128.h | 152 - ANDROID_3.4.5/drivers/scsi/tmscsim.c | 2622 --- ANDROID_3.4.5/drivers/scsi/tmscsim.h | 550 - ANDROID_3.4.5/drivers/scsi/u14-34f.c | 1971 --- ANDROID_3.4.5/drivers/scsi/ufs/Kconfig | 49 - ANDROID_3.4.5/drivers/scsi/ufs/Makefile | 2 - ANDROID_3.4.5/drivers/scsi/ufs/ufs.h | 207 - ANDROID_3.4.5/drivers/scsi/ufs/ufshcd.c | 1978 --- ANDROID_3.4.5/drivers/scsi/ufs/ufshci.h | 376 - ANDROID_3.4.5/drivers/scsi/ultrastor.c | 1210 -- ANDROID_3.4.5/drivers/scsi/ultrastor.h | 80 - ANDROID_3.4.5/drivers/scsi/virtio_scsi.c | 596 - ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.c | 1474 -- ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.h | 458 - ANDROID_3.4.5/drivers/scsi/wd33c93.c | 2232 --- ANDROID_3.4.5/drivers/scsi/wd33c93.h | 351 - ANDROID_3.4.5/drivers/scsi/wd7000.c | 1676 -- ANDROID_3.4.5/drivers/scsi/zalon.c | 205 - ANDROID_3.4.5/drivers/scsi/zorro7xx.c | 184 - 690 files changed, 768453 deletions(-) delete mode 100644 ANDROID_3.4.5/drivers/scsi/3w-9xxx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/3w-9xxx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/3w-sas.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/3w-sas.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/3w-xxxx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/3w-xxxx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/53c700.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/53c700.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/53c700.scr delete mode 100644 ANDROID_3.4.5/drivers/scsi/53c700_d.h_shipped delete mode 100644 ANDROID_3.4.5/drivers/scsi/BusLogic.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/BusLogic.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/FlashPoint.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/NCR5380.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/NCR5380.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/NCR53c406a.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/NCR_D700.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/NCR_D700.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/NCR_Q720.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/NCR_Q720.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/a100u2w.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/a100u2w.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/a2091.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/a2091.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/a3000.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/a3000.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/a4000t.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/TODO delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/aachba.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/aacraid.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/commctrl.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/comminit.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/commsup.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/dpcsup.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/linit.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/nark.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/rkt.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/rx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/sa.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aacraid/src.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/advansys.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aha152x.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aha152x.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aha1542.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aha1542.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aha1740.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aha1740.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic79xx delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic7xxx delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770_osm.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.reg delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.seq delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_core.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_inline.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm_pci.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_proc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.reg delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.seq delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_core.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_inline.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_proc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/cam.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/queue.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_iu.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_message.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.reg delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.seq delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_proc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_reg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_seq.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old/scsi_message.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic7xxx_old/sequencer.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dev.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg_def.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sas.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_scb.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_task.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_tmf.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arcmsr/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_attr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_hba.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/acornscsi-io.S delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/acornscsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/acornscsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/arxescsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/cumana_1.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/cumana_2.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/eesox.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/fas216.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/fas216.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/msgqueue.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/msgqueue.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/oak.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/powertec.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/queue.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/queue.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/arm/scsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/atari_NCR5380.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/atari_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/atari_scsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/atp870u.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/atp870u.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_core.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_cs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_fcs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_svc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_fcpim.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_lport.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_rport.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_cb.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_ct.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_cb.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_ct.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_modules.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_plog.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfad.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfad_attr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfad_debugfs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfad_drv.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfi_ms.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bfa/bfi_reg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_constants.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_debug.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_els.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_fcoe.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_hwi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_io.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_tgt.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_constants.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_hsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_hwi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_iscsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_sysfs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/bvme6000_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ch.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/constants.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kbuild delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kbuild delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/dc395x.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/dc395x.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/device_handler/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/device_handler/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_alua.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_emc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_hp_sw.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_rdac.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/dmx3191d.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/dpt/dpti_i2o.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/dpt/dpti_ioctl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/dpt/dptsig.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/dpt/osd_defs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/dpt/osd_util.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/dpt/sys_info.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/dpt_i2o.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/dpti.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/dtc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/dtc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/eata.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/eata_generic.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/eata_pio.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/eata_pio.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/esp_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/esp_scsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fcoe/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_ctlr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_transport.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fcoe/libfcoe.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fd_mcs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fdomain.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fdomain.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/cq_desc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/cq_enet_desc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/cq_exch_desc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fcpio.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic_attrs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic_fcs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic_io.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic_isr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic_main.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/fnic_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/rq_enet_desc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq_copy.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_devcmd.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_nic.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_resource.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_scsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_stats.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/fnic/wq_enet_desc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/g_NCR5380.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/g_NCR5380.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/g_NCR5380_mmio.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/gdth.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/gdth.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/gdth_ioctl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/gdth_proc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/gdth_proc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/gvp11.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/gvp11.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/hosts.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/hpsa.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/hpsa.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/hpsa_cmd.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/hptiop.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/hptiop.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmmca.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmvscsi/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvstgt.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmvscsi/rpa_vscsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ibmvscsi/viosrp.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/imm.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/imm.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/in2000.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/in2000.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/initio.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/initio.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ipr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ipr.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ips.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ips.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/host.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/host.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/isci.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/phy.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/phy.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/port.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/port.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/port_config.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/probe_roms.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/probe_roms.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/registers.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/remote_device.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/remote_device.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/remote_node_context.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/remote_node_context.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/remote_node_table.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/remote_node_table.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/request.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/request.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/sas.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/scu_completion_codes.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/scu_event_codes.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/scu_remote_node_context.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/scu_task_context.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/task.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/task.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/unsolicited_frame_control.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/isci/unsolicited_frame_control.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/iscsi_boot_sysfs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/iscsi_tcp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/iscsi_tcp.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/jazz_esp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lasi700.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_disc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_elsct.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_exch.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_fcp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_frame.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_lport.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_npiv.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libfc/fc_rport.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libiscsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libiscsi_tcp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_ata.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_discover.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_event.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_expander.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_host_smp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_internal.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_phy.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_port.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_scsi_host.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsas/sas_task.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/libsrp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_attr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_compat.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_crtn.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_ct.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_disc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_els.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hbadisc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw4.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_logmsg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mbox.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mem.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nportdisc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli4.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_version.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mac53c94.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mac53c94.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mac_esp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mac_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mac_scsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/Kconfig.megaraid delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/mbox_defs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/mega_common.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_ioctl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mbox.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mbox.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_base.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fusion.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fusion.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mesh.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mesh.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_init.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_raid.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_sas.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_tool.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_type.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_config.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_debug.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_scsih.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_transport.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvme147.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvme147.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvme16x_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_chips.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_defs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvumi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/mvumi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ncr53c8xx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ncr53c8xx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/nsp32.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/nsp32.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/nsp32_debug.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/nsp32_io.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/osd/Kbuild delete mode 100644 ANDROID_3.4.5/drivers/scsi/osd/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/osd/osd_debug.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/osd/osd_initiator.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/osd/osd_uld.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/osst.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/osst.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/osst_detect.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/osst_options.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pas16.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pas16.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_core.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_stub.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_core.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_stub.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_debug.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_io.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_message.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/qlogic_stub.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pcmcia/sym53c500_cs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_chips.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_defs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/pmcraid.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/pmcraid.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ppa.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ppa.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ps3rom.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla1280.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla1280.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_attr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_def.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_devtbl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dfs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_fw.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gbl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_inline.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_iocb.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_isr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mbx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mid.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_os.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_settings.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_sup.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_version.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_attr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_def.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_fw.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_glbl.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_init.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_inline.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_iocb.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_isr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_mbx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_os.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_version.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qlogicfas.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qlogicfas408.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qlogicfas408.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/qlogicpti.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/qlogicpti.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/raid_class.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/script_asm.pl delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_debug.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_devinfo.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_error.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_ioctl.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_lib.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_lib_dma.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_logging.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_module.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_netlink.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_pm.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_priv.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_proc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_sas_internal.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_scan.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_sysctl.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_sysfs.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_tgt_if.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_tgt_lib.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_tgt_priv.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_trace.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_transport_api.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_transport_fc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_transport_fc_internal.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_transport_iscsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_transport_sas.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_transport_spi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_transport_srp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_transport_srp_internal.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_typedefs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsi_wait_scan.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/scsicam.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sd.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sd.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sd_dif.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ses.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sg.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sgiwd93.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sim710.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sni_53c710.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sr.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sr.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sr_ioctl.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sr_vendor.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/st.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/st.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/st_options.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/stex.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/storvsc_drv.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sun3_NCR5380.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sun3_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sun3_scsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sun3_scsi_vme.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sun3x_esp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sun_esp.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c416.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c416.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym53c8xx.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_defs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw1.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw2.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_malloc.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_misc.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_nvram.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_nvram.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/t128.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/t128.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/tmscsim.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/tmscsim.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/u14-34f.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ufs/Kconfig delete mode 100644 ANDROID_3.4.5/drivers/scsi/ufs/Makefile delete mode 100644 ANDROID_3.4.5/drivers/scsi/ufs/ufs.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ufs/ufshcd.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ufs/ufshci.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/ultrastor.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/ultrastor.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/virtio_scsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/wd33c93.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/wd33c93.h delete mode 100644 ANDROID_3.4.5/drivers/scsi/wd7000.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/zalon.c delete mode 100644 ANDROID_3.4.5/drivers/scsi/zorro7xx.c (limited to 'ANDROID_3.4.5/drivers/scsi') diff --git a/ANDROID_3.4.5/drivers/scsi/3w-9xxx.c b/ANDROID_3.4.5/drivers/scsi/3w-9xxx.c deleted file mode 100644 index 3868ab23..00000000 --- a/ANDROID_3.4.5/drivers/scsi/3w-9xxx.c +++ /dev/null @@ -1,2350 +0,0 @@ -/* - 3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux. - - Written By: Adam Radford - Modifications By: Tom Couch - - Copyright (C) 2004-2009 Applied Micro Circuits Corporation. - Copyright (C) 2010 LSI Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - NO WARRANTY - THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - DISCLAIMER OF LIABILITY - NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com - - Note: This version of the driver does not contain a bundled firmware - image. - - History - ------- - 2.26.02.000 - Driver cleanup for kernel submission. - 2.26.02.001 - Replace schedule_timeout() calls with msleep(). - 2.26.02.002 - Add support for PAE mode. - Add lun support. - Fix twa_remove() to free irq handler/unregister_chrdev() - before shutting down card. - Change to new 'change_queue_depth' api. - Fix 'handled=1' ISR usage, remove bogus IRQ check. - Remove un-needed eh_abort handler. - Add support for embedded firmware error strings. - 2.26.02.003 - Correctly handle single sgl's with use_sg=1. - 2.26.02.004 - Add support for 9550SX controllers. - 2.26.02.005 - Fix use_sg == 0 mapping on systems with 4GB or higher. - 2.26.02.006 - Fix 9550SX pchip reset timeout. - Add big endian support. - 2.26.02.007 - Disable local interrupts during kmap/unmap_atomic(). - 2.26.02.008 - Free irq handler in __twa_shutdown(). - Serialize reset code. - Add support for 9650SE controllers. - 2.26.02.009 - Fix dma mask setting to fallback to 32-bit if 64-bit fails. - 2.26.02.010 - Add support for 9690SA controllers. - 2.26.02.011 - Increase max AENs drained to 256. - Add MSI support and "use_msi" module parameter. - Fix bug in twa_get_param() on 4GB+. - Use pci_resource_len() for ioremap(). - 2.26.02.012 - Add power management support. - 2.26.02.013 - Fix bug in twa_load_sgl(). - 2.26.02.014 - Force 60 second timeout default. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "3w-9xxx.h" - -/* Globals */ -#define TW_DRIVER_VERSION "2.26.02.014" -static DEFINE_MUTEX(twa_chrdev_mutex); -static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT]; -static unsigned int twa_device_extension_count; -static int twa_major = -1; -extern struct timezone sys_tz; - -/* Module parameters */ -MODULE_AUTHOR ("LSI"); -MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(TW_DRIVER_VERSION); - -static int use_msi = 0; -module_param(use_msi, int, S_IRUGO); -MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0"); - -/* Function prototypes */ -static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header); -static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id); -static char *twa_aen_severity_lookup(unsigned char severity_code); -static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id); -static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -static int twa_chrdev_open(struct inode *inode, struct file *file); -static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host); -static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id); -static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id); -static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, - u32 set_features, unsigned short current_fw_srl, - unsigned short current_fw_arch_id, - unsigned short current_fw_branch, - unsigned short current_fw_build, - unsigned short *fw_on_ctlr_srl, - unsigned short *fw_on_ctlr_arch_id, - unsigned short *fw_on_ctlr_branch, - unsigned short *fw_on_ctlr_build, - u32 *init_connect_result); -static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length); -static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds); -static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds); -static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal); -static int twa_reset_device_extension(TW_Device_Extension *tw_dev); -static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset); -static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg); -static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id); -static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code); -static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id); - -/* Functions */ - -/* Show some statistics about the card */ -static ssize_t twa_show_stats(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - unsigned long flags = 0; - ssize_t len; - - spin_lock_irqsave(tw_dev->host->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n" - "Current commands posted: %4d\n" - "Max commands posted: %4d\n" - "Current pending commands: %4d\n" - "Max pending commands: %4d\n" - "Last sgl length: %4d\n" - "Max sgl length: %4d\n" - "Last sector count: %4d\n" - "Max sector count: %4d\n" - "SCSI Host Resets: %4d\n" - "AEN's: %4d\n", - TW_DRIVER_VERSION, - tw_dev->posted_request_count, - tw_dev->max_posted_request_count, - tw_dev->pending_request_count, - tw_dev->max_pending_request_count, - tw_dev->sgl_entries, - tw_dev->max_sgl_entries, - tw_dev->sector_count, - tw_dev->max_sector_count, - tw_dev->num_resets, - tw_dev->aen_count); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - return len; -} /* End twa_show_stats() */ - -/* This function will set a devices queue depth */ -static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (queue_depth > TW_Q_LENGTH-2) - queue_depth = TW_Q_LENGTH-2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); - return queue_depth; -} /* End twa_change_queue_depth() */ - -/* Create sysfs 'stats' entry */ -static struct device_attribute twa_host_stats_attr = { - .attr = { - .name = "stats", - .mode = S_IRUGO, - }, - .show = twa_show_stats -}; - -/* Host attributes initializer */ -static struct device_attribute *twa_host_attrs[] = { - &twa_host_stats_attr, - NULL, -}; - -/* File operations struct for character device */ -static const struct file_operations twa_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = twa_chrdev_ioctl, - .open = twa_chrdev_open, - .release = NULL, - .llseek = noop_llseek, -}; - -/* This function will complete an aen request from the isr */ -static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Command_Full *full_command_packet; - TW_Command *command_packet; - TW_Command_Apache_Header *header; - unsigned short aen; - int retval = 1; - - header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; - tw_dev->posted_request_count--; - aen = le16_to_cpu(header->status_block.error); - full_command_packet = tw_dev->command_packet_virt[request_id]; - command_packet = &full_command_packet->command.oldcommand; - - /* First check for internal completion of set param for time sync */ - if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) { - /* Keep reading the queue in case there are more aen's */ - if (twa_aen_read_queue(tw_dev, request_id)) - goto out2; - else { - retval = 0; - goto out; - } - } - - switch (aen) { - case TW_AEN_QUEUE_EMPTY: - /* Quit reading the queue if this is the last one */ - break; - case TW_AEN_SYNC_TIME_WITH_HOST: - twa_aen_sync_time(tw_dev, request_id); - retval = 0; - goto out; - default: - twa_aen_queue_event(tw_dev, header); - - /* If there are more aen's, keep reading the queue */ - if (twa_aen_read_queue(tw_dev, request_id)) - goto out2; - else { - retval = 0; - goto out; - } - } - retval = 0; -out2: - tw_dev->state[request_id] = TW_S_COMPLETED; - twa_free_request_id(tw_dev, request_id); - clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); -out: - return retval; -} /* End twa_aen_complete() */ - -/* This function will drain aen queue */ -static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) -{ - int request_id = 0; - char cdb[TW_MAX_CDB_LEN]; - TW_SG_Entry sglist[1]; - int finished = 0, count = 0; - TW_Command_Full *full_command_packet; - TW_Command_Apache_Header *header; - unsigned short aen; - int first_reset = 0, queue = 0, retval = 1; - - if (no_check_reset) - first_reset = 0; - else - first_reset = 1; - - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - - /* Initialize cdb */ - memset(&cdb, 0, TW_MAX_CDB_LEN); - cdb[0] = REQUEST_SENSE; /* opcode */ - cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ - - /* Initialize sglist */ - memset(&sglist, 0, sizeof(TW_SG_Entry)); - sglist[0].length = TW_SECTOR_SIZE; - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; - - if (sglist[0].address & TW_ALIGNMENT_9000_SGL) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain"); - goto out; - } - - /* Mark internal command */ - tw_dev->srb[request_id] = NULL; - - do { - /* Send command to the board */ - if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense"); - goto out; - } - - /* Now poll for completion */ - if (twa_poll_response(tw_dev, request_id, 30)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue"); - tw_dev->posted_request_count--; - goto out; - } - - tw_dev->posted_request_count--; - header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; - aen = le16_to_cpu(header->status_block.error); - queue = 0; - count++; - - switch (aen) { - case TW_AEN_QUEUE_EMPTY: - if (first_reset != 1) - goto out; - else - finished = 1; - break; - case TW_AEN_SOFT_RESET: - if (first_reset == 0) - first_reset = 1; - else - queue = 1; - break; - case TW_AEN_SYNC_TIME_WITH_HOST: - break; - default: - queue = 1; - } - - /* Now queue an event info */ - if (queue) - twa_aen_queue_event(tw_dev, header); - } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN)); - - if (count == TW_MAX_AEN_DRAIN) - goto out; - - retval = 0; -out: - tw_dev->state[request_id] = TW_S_INITIAL; - return retval; -} /* End twa_aen_drain_queue() */ - -/* This function will queue an event */ -static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header) -{ - u32 local_time; - struct timeval time; - TW_Event *event; - unsigned short aen; - char host[16]; - char *error_str; - - tw_dev->aen_count++; - - /* Fill out event info */ - event = tw_dev->event_queue[tw_dev->error_index]; - - /* Check for clobber */ - host[0] = '\0'; - if (tw_dev->host) { - sprintf(host, " scsi%d:", tw_dev->host->host_no); - if (event->retrieved == TW_AEN_NOT_RETRIEVED) - tw_dev->aen_clobber = 1; - } - - aen = le16_to_cpu(header->status_block.error); - memset(event, 0, sizeof(TW_Event)); - - event->severity = TW_SEV_OUT(header->status_block.severity__reserved); - do_gettimeofday(&time); - local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); - event->time_stamp_sec = local_time; - event->aen_code = aen; - event->retrieved = TW_AEN_NOT_RETRIEVED; - event->sequence_id = tw_dev->error_sequence_id; - tw_dev->error_sequence_id++; - - /* Check for embedded error string */ - error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]); - - header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0'; - event->parameter_len = strlen(header->err_specific_desc); - memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + (error_str[0] == '\0' ? 0 : (1 + strlen(error_str)))); - if (event->severity != TW_AEN_SEVERITY_DEBUG) - printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n", - host, - twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)), - TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, - error_str[0] == '\0' ? twa_string_lookup(twa_aen_table, aen) : error_str, - header->err_specific_desc); - else - tw_dev->aen_count--; - - if ((tw_dev->error_index + 1) == TW_Q_LENGTH) - tw_dev->event_queue_wrapped = 1; - tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH; -} /* End twa_aen_queue_event() */ - -/* This function will read the aen queue from the isr */ -static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) -{ - char cdb[TW_MAX_CDB_LEN]; - TW_SG_Entry sglist[1]; - TW_Command_Full *full_command_packet; - int retval = 1; - - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - - /* Initialize cdb */ - memset(&cdb, 0, TW_MAX_CDB_LEN); - cdb[0] = REQUEST_SENSE; /* opcode */ - cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ - - /* Initialize sglist */ - memset(&sglist, 0, sizeof(TW_SG_Entry)); - sglist[0].length = TW_SECTOR_SIZE; - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; - - /* Mark internal command */ - tw_dev->srb[request_id] = NULL; - - /* Now post the command packet */ - if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue"); - goto out; - } - retval = 0; -out: - return retval; -} /* End twa_aen_read_queue() */ - -/* This function will look up an AEN severity string */ -static char *twa_aen_severity_lookup(unsigned char severity_code) -{ - char *retval = NULL; - - if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) || - (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG)) - goto out; - - retval = twa_aen_severity_table[severity_code]; -out: - return retval; -} /* End twa_aen_severity_lookup() */ - -/* This function will sync firmware time with the host time */ -static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) -{ - u32 schedulertime; - struct timeval utc; - TW_Command_Full *full_command_packet; - TW_Command *command_packet; - TW_Param_Apache *param; - u32 local_time; - - /* Fill out the command packet */ - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - command_packet = &full_command_packet->command.oldcommand; - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); - command_packet->request_id = request_id; - command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); - command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE); - command_packet->size = TW_COMMAND_SIZE; - command_packet->byte6_offset.parameter_count = cpu_to_le16(1); - - /* Setup the param */ - param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; - memset(param, 0, TW_SECTOR_SIZE); - param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */ - param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */ - param->parameter_size_bytes = cpu_to_le16(4); - - /* Convert system time in UTC to local time seconds since last - Sunday 12:00AM */ - do_gettimeofday(&utc); - local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); - schedulertime = local_time - (3 * 86400); - schedulertime = cpu_to_le32(schedulertime % 604800); - - memcpy(param->data, &schedulertime, sizeof(u32)); - - /* Mark internal command */ - tw_dev->srb[request_id] = NULL; - - /* Now post the command */ - twa_post_command_packet(tw_dev, request_id, 1); -} /* End twa_aen_sync_time() */ - -/* This function will allocate memory and check if it is correctly aligned */ -static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) -{ - int i; - dma_addr_t dma_handle; - unsigned long *cpu_addr; - int retval = 1; - - cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); - if (!cpu_addr) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); - goto out; - } - - if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory"); - pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle); - goto out; - } - - memset(cpu_addr, 0, size*TW_Q_LENGTH); - - for (i = 0; i < TW_Q_LENGTH; i++) { - switch(which) { - case 0: - tw_dev->command_packet_phys[i] = dma_handle+(i*size); - tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size)); - break; - case 1: - tw_dev->generic_buffer_phys[i] = dma_handle+(i*size); - tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); - break; - } - } - retval = 0; -out: - return retval; -} /* End twa_allocate_memory() */ - -/* This function will check the status register for unexpected bits */ -static int twa_check_bits(u32 status_reg_value) -{ - int retval = 1; - - if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) - goto out; - if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) - goto out; - - retval = 0; -out: - return retval; -} /* End twa_check_bits() */ - -/* This function will check the srl and decide if we are compatible */ -static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed) -{ - int retval = 1; - unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0; - unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0; - u32 init_connect_result = 0; - - if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, - TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL, - TW_9000_ARCH_ID, TW_CURRENT_DRIVER_BRANCH, - TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl, - &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, - &fw_on_ctlr_build, &init_connect_result)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL"); - goto out; - } - - tw_dev->tw_compat_info.working_srl = fw_on_ctlr_srl; - tw_dev->tw_compat_info.working_branch = fw_on_ctlr_branch; - tw_dev->tw_compat_info.working_build = fw_on_ctlr_build; - - /* Try base mode compatibility */ - if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { - if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, - TW_EXTENDED_INIT_CONNECT, - TW_BASE_FW_SRL, TW_9000_ARCH_ID, - TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD, - &fw_on_ctlr_srl, &fw_on_ctlr_arch_id, - &fw_on_ctlr_branch, &fw_on_ctlr_build, - &init_connect_result)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL"); - goto out; - } - if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) { - if (TW_CURRENT_DRIVER_SRL > fw_on_ctlr_srl) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware"); - } else { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver"); - } - goto out; - } - tw_dev->tw_compat_info.working_srl = TW_BASE_FW_SRL; - tw_dev->tw_compat_info.working_branch = TW_BASE_FW_BRANCH; - tw_dev->tw_compat_info.working_build = TW_BASE_FW_BUILD; - } - - /* Load rest of compatibility struct */ - strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); - tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; - tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; - tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; - tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL; - tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH; - tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD; - tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl; - tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch; - tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build; - - retval = 0; -out: - return retval; -} /* End twa_check_srl() */ - -/* This function handles ioctl for the character device */ -static long twa_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = file->f_path.dentry->d_inode; - long timeout; - unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0; - dma_addr_t dma_handle; - int request_id = 0; - unsigned int sequence_id = 0; - unsigned char event_index, start_index; - TW_Ioctl_Driver_Command driver_command; - TW_Ioctl_Buf_Apache *tw_ioctl; - TW_Lock *tw_lock; - TW_Command_Full *full_command_packet; - TW_Compatibility_Info *tw_compat_info; - TW_Event *event; - struct timeval current_time; - u32 current_time_ms; - TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)]; - int retval = TW_IOCTL_ERROR_OS_EFAULT; - void __user *argp = (void __user *)arg; - - mutex_lock(&twa_chrdev_mutex); - - /* Only let one of these through at a time */ - if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { - retval = TW_IOCTL_ERROR_OS_EINTR; - goto out; - } - - /* First copy down the driver command */ - if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command))) - goto out2; - - /* Check data buffer size */ - if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) { - retval = TW_IOCTL_ERROR_OS_EINVAL; - goto out2; - } - - /* Hardware can only do multiple of 512 byte transfers */ - data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511; - - /* Now allocate ioctl buf memory */ - cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL); - if (!cpu_addr) { - retval = TW_IOCTL_ERROR_OS_ENOMEM; - goto out2; - } - - tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr; - - /* Now copy down the entire ioctl */ - if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1)) - goto out3; - - /* See which ioctl we are doing */ - switch (cmd) { - case TW_IOCTL_FIRMWARE_PASS_THROUGH: - spin_lock_irqsave(tw_dev->host->host_lock, flags); - twa_get_request_id(tw_dev, &request_id); - - /* Flag internal command */ - tw_dev->srb[request_id] = NULL; - - /* Flag chrdev ioctl */ - tw_dev->chrdev_request_id = request_id; - - full_command_packet = &tw_ioctl->firmware_command; - - /* Load request id and sglist for both command types */ - twa_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); - - memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); - - /* Now post the command packet to the controller */ - twa_post_command_packet(tw_dev, request_id, 1); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - - timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; - - /* Now wait for command to complete */ - timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); - - /* We timed out, and didn't get an interrupt */ - if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { - /* Now we need to reset the board */ - printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", - tw_dev->host->host_no, TW_DRIVER, 0x37, - cmd); - retval = TW_IOCTL_ERROR_OS_EIO; - twa_reset_device_extension(tw_dev); - goto out3; - } - - /* Now copy in the command packet response */ - memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full)); - - /* Now complete the io */ - spin_lock_irqsave(tw_dev->host->host_lock, flags); - tw_dev->posted_request_count--; - tw_dev->state[request_id] = TW_S_COMPLETED; - twa_free_request_id(tw_dev, request_id); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - break; - case TW_IOCTL_GET_COMPATIBILITY_INFO: - tw_ioctl->driver_command.status = 0; - /* Copy compatibility struct into ioctl data buffer */ - tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer; - memcpy(tw_compat_info, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info)); - break; - case TW_IOCTL_GET_LAST_EVENT: - if (tw_dev->event_queue_wrapped) { - if (tw_dev->aen_clobber) { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; - tw_dev->aen_clobber = 0; - } else - tw_ioctl->driver_command.status = 0; - } else { - if (!tw_dev->error_index) { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; - break; - } - tw_ioctl->driver_command.status = 0; - } - event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH; - memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); - tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; - break; - case TW_IOCTL_GET_FIRST_EVENT: - if (tw_dev->event_queue_wrapped) { - if (tw_dev->aen_clobber) { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; - tw_dev->aen_clobber = 0; - } else - tw_ioctl->driver_command.status = 0; - event_index = tw_dev->error_index; - } else { - if (!tw_dev->error_index) { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; - break; - } - tw_ioctl->driver_command.status = 0; - event_index = 0; - } - memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); - tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; - break; - case TW_IOCTL_GET_NEXT_EVENT: - event = (TW_Event *)tw_ioctl->data_buffer; - sequence_id = event->sequence_id; - tw_ioctl->driver_command.status = 0; - - if (tw_dev->event_queue_wrapped) { - if (tw_dev->aen_clobber) { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; - tw_dev->aen_clobber = 0; - } - start_index = tw_dev->error_index; - } else { - if (!tw_dev->error_index) { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; - break; - } - start_index = 0; - } - event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH; - - if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) { - if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER) - tw_dev->aen_clobber = 1; - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; - break; - } - memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); - tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; - break; - case TW_IOCTL_GET_PREVIOUS_EVENT: - event = (TW_Event *)tw_ioctl->data_buffer; - sequence_id = event->sequence_id; - tw_ioctl->driver_command.status = 0; - - if (tw_dev->event_queue_wrapped) { - if (tw_dev->aen_clobber) { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER; - tw_dev->aen_clobber = 0; - } - start_index = tw_dev->error_index; - } else { - if (!tw_dev->error_index) { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; - break; - } - start_index = 0; - } - event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH; - - if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) { - if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER) - tw_dev->aen_clobber = 1; - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS; - break; - } - memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event)); - tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED; - break; - case TW_IOCTL_GET_LOCK: - tw_lock = (TW_Lock *)tw_ioctl->data_buffer; - do_gettimeofday(¤t_time); - current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000); - - if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) { - tw_dev->ioctl_sem_lock = 1; - tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec; - tw_ioctl->driver_command.status = 0; - tw_lock->time_remaining_msec = tw_lock->timeout_msec; - } else { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED; - tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms; - } - break; - case TW_IOCTL_RELEASE_LOCK: - if (tw_dev->ioctl_sem_lock == 1) { - tw_dev->ioctl_sem_lock = 0; - tw_ioctl->driver_command.status = 0; - } else { - tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED; - } - break; - default: - retval = TW_IOCTL_ERROR_OS_ENOTTY; - goto out3; - } - - /* Now copy the entire response to userspace */ - if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0) - retval = 0; -out3: - /* Now free ioctl buf memory */ - dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle); -out2: - mutex_unlock(&tw_dev->ioctl_lock); -out: - mutex_unlock(&twa_chrdev_mutex); - return retval; -} /* End twa_chrdev_ioctl() */ - -/* This function handles open for the character device */ -/* NOTE that this function will race with remove. */ -static int twa_chrdev_open(struct inode *inode, struct file *file) -{ - unsigned int minor_number; - int retval = TW_IOCTL_ERROR_OS_ENODEV; - - minor_number = iminor(inode); - if (minor_number >= twa_device_extension_count) - goto out; - retval = 0; -out: - return retval; -} /* End twa_chrdev_open() */ - -/* This function will print readable messages from status register errors */ -static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value) -{ - int retval = 1; - - /* Check for various error conditions and handle them appropriately */ - if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing"); - writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); - } - - if (status_reg_value & TW_STATUS_PCI_ABORT) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing"); - writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev)); - pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); - } - - if (status_reg_value & TW_STATUS_QUEUE_ERROR) { - if (((tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9650SE) && - (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9690SA)) || - (!test_bit(TW_IN_RESET, &tw_dev->flags))) - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing"); - writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); - } - - if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) { - if (tw_dev->reset_print == 0) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing"); - tw_dev->reset_print = 1; - } - goto out; - } - retval = 0; -out: - return retval; -} /* End twa_decode_bits() */ - -/* This function will empty the response queue */ -static int twa_empty_response_queue(TW_Device_Extension *tw_dev) -{ - u32 status_reg_value, response_que_value; - int count = 0, retval = 1; - - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - - while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) { - response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - count++; - } - if (count == TW_MAX_RESPONSE_DRAIN) - goto out; - - retval = 0; -out: - return retval; -} /* End twa_empty_response_queue() */ - -/* This function will clear the pchip/response queue on 9550SX */ -static int twa_empty_response_queue_large(TW_Device_Extension *tw_dev) -{ - u32 response_que_value = 0; - unsigned long before; - int retval = 1; - - if (tw_dev->tw_pci_dev->device != PCI_DEVICE_ID_3WARE_9000) { - before = jiffies; - while ((response_que_value & TW_9550SX_DRAIN_COMPLETED) != TW_9550SX_DRAIN_COMPLETED) { - response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR_LARGE(tw_dev)); - msleep(1); - if (time_after(jiffies, before + HZ * 30)) - goto out; - } - /* P-chip settle time */ - msleep(500); - retval = 0; - } else - retval = 0; -out: - return retval; -} /* End twa_empty_response_queue_large() */ - -/* This function passes sense keys from firmware to scsi layer */ -static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host) -{ - TW_Command_Full *full_command_packet; - unsigned short error; - int retval = 1; - char *error_str; - - full_command_packet = tw_dev->command_packet_virt[request_id]; - - /* Check for embedded error string */ - error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]); - - /* Don't print error for Logical unit not supported during rollcall */ - error = le16_to_cpu(full_command_packet->header.status_block.error); - if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) { - if (print_host) - printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", - tw_dev->host->host_no, - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, - full_command_packet->header.status_block.error, - error_str[0] == '\0' ? - twa_string_lookup(twa_error_table, - full_command_packet->header.status_block.error) : error_str, - full_command_packet->header.err_specific_desc); - else - printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n", - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, - full_command_packet->header.status_block.error, - error_str[0] == '\0' ? - twa_string_lookup(twa_error_table, - full_command_packet->header.status_block.error) : error_str, - full_command_packet->header.err_specific_desc); - } - - if (copy_sense) { - memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH); - tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1); - retval = TW_ISR_DONT_RESULT; - goto out; - } - retval = 0; -out: - return retval; -} /* End twa_fill_sense() */ - -/* This function will free up device extension resources */ -static void twa_free_device_extension(TW_Device_Extension *tw_dev) -{ - if (tw_dev->command_packet_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - sizeof(TW_Command_Full)*TW_Q_LENGTH, - tw_dev->command_packet_virt[0], - tw_dev->command_packet_phys[0]); - - if (tw_dev->generic_buffer_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - TW_SECTOR_SIZE*TW_Q_LENGTH, - tw_dev->generic_buffer_virt[0], - tw_dev->generic_buffer_phys[0]); - - kfree(tw_dev->event_queue[0]); -} /* End twa_free_device_extension() */ - -/* This function will free a request id */ -static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id) -{ - tw_dev->free_queue[tw_dev->free_tail] = request_id; - tw_dev->state[request_id] = TW_S_FINISHED; - tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH; -} /* End twa_free_request_id() */ - -/* This function will get parameter table entries from the firmware */ -static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes) -{ - TW_Command_Full *full_command_packet; - TW_Command *command_packet; - TW_Param_Apache *param; - void *retval = NULL; - - /* Setup the command packet */ - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - command_packet = &full_command_packet->command.oldcommand; - - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = TW_COMMAND_SIZE; - command_packet->request_id = request_id; - command_packet->byte6_offset.block_count = cpu_to_le16(1); - - /* Now setup the param */ - param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; - memset(param, 0, TW_SECTOR_SIZE); - param->table_id = cpu_to_le16(table_id | 0x8000); - param->parameter_id = cpu_to_le16(parameter_id); - param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes); - - command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); - command_packet->byte8_offset.param.sgl[0].length = cpu_to_le32(TW_SECTOR_SIZE); - - /* Post the command packet to the board */ - twa_post_command_packet(tw_dev, request_id, 1); - - /* Poll for completion */ - if (twa_poll_response(tw_dev, request_id, 30)) - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param") - else - retval = (void *)&(param->data[0]); - - tw_dev->posted_request_count--; - tw_dev->state[request_id] = TW_S_INITIAL; - - return retval; -} /* End twa_get_param() */ - -/* This function will assign an available request id */ -static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id) -{ - *request_id = tw_dev->free_queue[tw_dev->free_head]; - tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH; - tw_dev->state[*request_id] = TW_S_STARTED; -} /* End twa_get_request_id() */ - -/* This function will send an initconnection command to controller */ -static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits, - u32 set_features, unsigned short current_fw_srl, - unsigned short current_fw_arch_id, - unsigned short current_fw_branch, - unsigned short current_fw_build, - unsigned short *fw_on_ctlr_srl, - unsigned short *fw_on_ctlr_arch_id, - unsigned short *fw_on_ctlr_branch, - unsigned short *fw_on_ctlr_build, - u32 *init_connect_result) -{ - TW_Command_Full *full_command_packet; - TW_Initconnect *tw_initconnect; - int request_id = 0, retval = 1; - - /* Initialize InitConnection command packet */ - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - full_command_packet->header.header_desc.size_header = 128; - - tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; - tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); - tw_initconnect->request_id = request_id; - tw_initconnect->message_credits = cpu_to_le16(message_credits); - tw_initconnect->features = set_features; - - /* Turn on 64-bit sgl support if we need to */ - tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0; - - tw_initconnect->features = cpu_to_le32(tw_initconnect->features); - - if (set_features & TW_EXTENDED_INIT_CONNECT) { - tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; - tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl); - tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id); - tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch); - tw_initconnect->fw_build = cpu_to_le16(current_fw_build); - } else - tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; - - /* Send command packet to the board */ - twa_post_command_packet(tw_dev, request_id, 1); - - /* Poll for completion */ - if (twa_poll_response(tw_dev, request_id, 30)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection"); - } else { - if (set_features & TW_EXTENDED_INIT_CONNECT) { - *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl); - *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id); - *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch); - *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build); - *init_connect_result = le32_to_cpu(tw_initconnect->result); - } - retval = 0; - } - - tw_dev->posted_request_count--; - tw_dev->state[request_id] = TW_S_INITIAL; - - return retval; -} /* End twa_initconnection() */ - -/* This function will initialize the fields of a device extension */ -static int twa_initialize_device_extension(TW_Device_Extension *tw_dev) -{ - int i, retval = 1; - - /* Initialize command packet buffers */ - if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed"); - goto out; - } - - /* Initialize generic buffer */ - if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed"); - goto out; - } - - /* Allocate event info space */ - tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL); - if (!tw_dev->event_queue[0]) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed"); - goto out; - } - - - for (i = 0; i < TW_Q_LENGTH; i++) { - tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); - tw_dev->free_queue[i] = i; - tw_dev->state[i] = TW_S_INITIAL; - } - - tw_dev->pending_head = TW_Q_START; - tw_dev->pending_tail = TW_Q_START; - tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_START; - tw_dev->error_sequence_id = 1; - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - - mutex_init(&tw_dev->ioctl_lock); - init_waitqueue_head(&tw_dev->ioctl_wqueue); - - retval = 0; -out: - return retval; -} /* End twa_initialize_device_extension() */ - -/* This function is the interrupt service routine */ -static irqreturn_t twa_interrupt(int irq, void *dev_instance) -{ - int request_id, error = 0; - u32 status_reg_value; - TW_Response_Queue response_que; - TW_Command_Full *full_command_packet; - TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; - int handled = 0; - - /* Get the per adapter lock */ - spin_lock(tw_dev->host->host_lock); - - /* Read the registers */ - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - - /* Check if this is our interrupt, otherwise bail */ - if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT)) - goto twa_interrupt_bail; - - handled = 1; - - /* If we are resetting, bail */ - if (test_bit(TW_IN_RESET, &tw_dev->flags)) - goto twa_interrupt_bail; - - /* Check controller for errors */ - if (twa_check_bits(status_reg_value)) { - if (twa_decode_bits(tw_dev, status_reg_value)) { - TW_CLEAR_ALL_INTERRUPTS(tw_dev); - goto twa_interrupt_bail; - } - } - - /* Handle host interrupt */ - if (status_reg_value & TW_STATUS_HOST_INTERRUPT) - TW_CLEAR_HOST_INTERRUPT(tw_dev); - - /* Handle attention interrupt */ - if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) { - TW_CLEAR_ATTENTION_INTERRUPT(tw_dev); - if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) { - twa_get_request_id(tw_dev, &request_id); - - error = twa_aen_read_queue(tw_dev, request_id); - if (error) { - tw_dev->state[request_id] = TW_S_COMPLETED; - twa_free_request_id(tw_dev, request_id); - clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); - } - } - } - - /* Handle command interrupt */ - if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) { - TW_MASK_COMMAND_INTERRUPT(tw_dev); - /* Drain as many pending commands as we can */ - while (tw_dev->pending_request_count > 0) { - request_id = tw_dev->pending_queue[tw_dev->pending_head]; - if (tw_dev->state[request_id] != TW_S_PENDING) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending"); - TW_CLEAR_ALL_INTERRUPTS(tw_dev); - goto twa_interrupt_bail; - } - if (twa_post_command_packet(tw_dev, request_id, 1)==0) { - tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH; - tw_dev->pending_request_count--; - } else { - /* If we get here, we will continue re-posting on the next command interrupt */ - break; - } - } - } - - /* Handle response interrupt */ - if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) { - - /* Drain the response queue from the board */ - while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { - /* Complete the response */ - response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); - request_id = TW_RESID_OUT(response_que.response_id); - full_command_packet = tw_dev->command_packet_virt[request_id]; - error = 0; - /* Check for command packet errors */ - if (full_command_packet->command.newcommand.status != 0) { - if (tw_dev->srb[request_id] != NULL) { - error = twa_fill_sense(tw_dev, request_id, 1, 1); - } else { - /* Skip ioctl error prints */ - if (request_id != tw_dev->chrdev_request_id) { - error = twa_fill_sense(tw_dev, request_id, 0, 1); - } - } - } - - /* Check for correct state */ - if (tw_dev->state[request_id] != TW_S_POSTED) { - if (tw_dev->srb[request_id] != NULL) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted"); - TW_CLEAR_ALL_INTERRUPTS(tw_dev); - goto twa_interrupt_bail; - } - } - - /* Check for internal command completion */ - if (tw_dev->srb[request_id] == NULL) { - if (request_id != tw_dev->chrdev_request_id) { - if (twa_aen_complete(tw_dev, request_id)) - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt"); - } else { - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - wake_up(&tw_dev->ioctl_wqueue); - } - } else { - struct scsi_cmnd *cmd; - - cmd = tw_dev->srb[request_id]; - - twa_scsiop_execute_scsi_complete(tw_dev, request_id); - /* If no error command was a success */ - if (error == 0) { - cmd->result = (DID_OK << 16); - } - - /* If error, command failed */ - if (error == 1) { - /* Ask for a host reset */ - cmd->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - } - - /* Report residual bytes for single sgl */ - if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) { - if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id])) - scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length); - } - - /* Now complete the io */ - tw_dev->state[request_id] = TW_S_COMPLETED; - twa_free_request_id(tw_dev, request_id); - tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - twa_unmap_scsi_data(tw_dev, request_id); - } - - /* Check for valid status after each drain */ - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - if (twa_check_bits(status_reg_value)) { - if (twa_decode_bits(tw_dev, status_reg_value)) { - TW_CLEAR_ALL_INTERRUPTS(tw_dev); - goto twa_interrupt_bail; - } - } - } - } - -twa_interrupt_bail: - spin_unlock(tw_dev->host->host_lock); - return IRQ_RETVAL(handled); -} /* End twa_interrupt() */ - -/* This function will load the request id and various sgls for ioctls */ -static void twa_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length) -{ - TW_Command *oldcommand; - TW_Command_Apache *newcommand; - TW_SG_Entry *sgl; - unsigned int pae = 0; - - if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4)) - pae = 1; - - if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { - newcommand = &full_command_packet->command.newcommand; - newcommand->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); - if (length) { - newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); - newcommand->sg_list[0].length = cpu_to_le32(length); - } - newcommand->sgl_entries__lunh = - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0)); - } else { - oldcommand = &full_command_packet->command.oldcommand; - oldcommand->request_id = request_id; - - if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { - /* Load the sg list */ - if (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA) - sgl = (TW_SG_Entry *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry)/4) + pae); - else - sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset)); - sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); - sgl->length = cpu_to_le32(length); - - oldcommand->size += pae; - } - } -} /* End twa_load_sgl() */ - -/* This function will perform a pci-dma mapping for a scatter gather list */ -static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) -{ - int use_sg; - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - use_sg = scsi_dma_map(cmd); - if (!use_sg) - return 0; - else if (use_sg < 0) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list"); - return 0; - } - - cmd->SCp.phase = TW_PHASE_SGLIST; - cmd->SCp.have_data_in = use_sg; - - return use_sg; -} /* End twa_map_scsi_sg_data() */ - -/* This function will poll for a response interrupt of a request */ -static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) -{ - int retval = 1, found = 0, response_request_id; - TW_Response_Queue response_queue; - TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id]; - - if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) { - response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); - response_request_id = TW_RESID_OUT(response_queue.response_id); - if (request_id != response_request_id) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response"); - goto out; - } - if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { - if (full_command_packet->command.newcommand.status != 0) { - /* bad response */ - twa_fill_sense(tw_dev, request_id, 0, 0); - goto out; - } - found = 1; - } else { - if (full_command_packet->command.oldcommand.status != 0) { - /* bad response */ - twa_fill_sense(tw_dev, request_id, 0, 0); - goto out; - } - found = 1; - } - } - - if (found) - retval = 0; -out: - return retval; -} /* End twa_poll_response() */ - -/* This function will poll the status register for a flag */ -static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds) -{ - u32 status_reg_value; - unsigned long before; - int retval = 1; - - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - before = jiffies; - - if (twa_check_bits(status_reg_value)) - twa_decode_bits(tw_dev, status_reg_value); - - while ((status_reg_value & flag) != flag) { - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - - if (twa_check_bits(status_reg_value)) - twa_decode_bits(tw_dev, status_reg_value); - - if (time_after(jiffies, before + HZ * seconds)) - goto out; - - msleep(50); - } - retval = 0; -out: - return retval; -} /* End twa_poll_status() */ - -/* This function will poll the status register for disappearance of a flag */ -static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds) -{ - u32 status_reg_value; - unsigned long before; - int retval = 1; - - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - before = jiffies; - - if (twa_check_bits(status_reg_value)) - twa_decode_bits(tw_dev, status_reg_value); - - while ((status_reg_value & flag) != 0) { - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - if (twa_check_bits(status_reg_value)) - twa_decode_bits(tw_dev, status_reg_value); - - if (time_after(jiffies, before + HZ * seconds)) - goto out; - - msleep(50); - } - retval = 0; -out: - return retval; -} /* End twa_poll_status_gone() */ - -/* This function will attempt to post a command packet to the board */ -static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal) -{ - u32 status_reg_value; - dma_addr_t command_que_value; - int retval = 1; - - command_que_value = tw_dev->command_packet_phys[request_id]; - - /* For 9650SE write low 4 bytes first */ - if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) || - (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) { - command_que_value += TW_COMMAND_OFFSET; - writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev)); - } - - status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev)); - - if (twa_check_bits(status_reg_value)) - twa_decode_bits(tw_dev, status_reg_value); - - if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) { - - /* Only pend internal driver commands */ - if (!internal) { - retval = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - - /* Couldn't post the command packet, so we do it later */ - if (tw_dev->state[request_id] != TW_S_PENDING) { - tw_dev->state[request_id] = TW_S_PENDING; - tw_dev->pending_request_count++; - if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) { - tw_dev->max_pending_request_count = tw_dev->pending_request_count; - } - tw_dev->pending_queue[tw_dev->pending_tail] = request_id; - tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH; - } - TW_UNMASK_COMMAND_INTERRUPT(tw_dev); - goto out; - } else { - if ((tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9650SE) || - (tw_dev->tw_pci_dev->device == PCI_DEVICE_ID_3WARE_9690SA)) { - /* Now write upper 4 bytes */ - writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR_LARGE(tw_dev) + 0x4); - } else { - if (sizeof(dma_addr_t) > 4) { - command_que_value += TW_COMMAND_OFFSET; - writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); - writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4); - } else { - writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); - } - } - tw_dev->state[request_id] = TW_S_POSTED; - tw_dev->posted_request_count++; - if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) { - tw_dev->max_posted_request_count = tw_dev->posted_request_count; - } - } - retval = 0; -out: - return retval; -} /* End twa_post_command_packet() */ - -/* This function will reset a device extension */ -static int twa_reset_device_extension(TW_Device_Extension *tw_dev) -{ - int i = 0; - int retval = 1; - unsigned long flags = 0; - - set_bit(TW_IN_RESET, &tw_dev->flags); - TW_DISABLE_INTERRUPTS(tw_dev); - TW_MASK_COMMAND_INTERRUPT(tw_dev); - spin_lock_irqsave(tw_dev->host->host_lock, flags); - - /* Abort all requests that are in progress */ - for (i = 0; i < TW_Q_LENGTH; i++) { - if ((tw_dev->state[i] != TW_S_FINISHED) && - (tw_dev->state[i] != TW_S_INITIAL) && - (tw_dev->state[i] != TW_S_COMPLETED)) { - if (tw_dev->srb[i]) { - tw_dev->srb[i]->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); - twa_unmap_scsi_data(tw_dev, i); - } - } - } - - /* Reset queues and counts */ - for (i = 0; i < TW_Q_LENGTH; i++) { - tw_dev->free_queue[i] = i; - tw_dev->state[i] = TW_S_INITIAL; - } - tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_START; - tw_dev->posted_request_count = 0; - tw_dev->pending_request_count = 0; - tw_dev->pending_head = TW_Q_START; - tw_dev->pending_tail = TW_Q_START; - tw_dev->reset_print = 0; - - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - - if (twa_reset_sequence(tw_dev, 1)) - goto out; - - TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); - clear_bit(TW_IN_RESET, &tw_dev->flags); - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - - retval = 0; -out: - return retval; -} /* End twa_reset_device_extension() */ - -/* This function will reset a controller */ -static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) -{ - int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset; - - while (tries < TW_MAX_RESET_TRIES) { - if (do_soft_reset) { - TW_SOFT_RESET(tw_dev); - /* Clear pchip/response queue on 9550SX */ - if (twa_empty_response_queue_large(tw_dev)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x36, "Response queue (large) empty failed during reset sequence"); - do_soft_reset = 1; - tries++; - continue; - } - } - - /* Make sure controller is in a good state */ - if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence"); - do_soft_reset = 1; - tries++; - continue; - } - - /* Empty response queue */ - if (twa_empty_response_queue(tw_dev)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence"); - do_soft_reset = 1; - tries++; - continue; - } - - flashed = 0; - - /* Check for compatibility/flash */ - if (twa_check_srl(tw_dev, &flashed)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence"); - do_soft_reset = 1; - tries++; - continue; - } else { - if (flashed) { - tries++; - continue; - } - } - - /* Drain the AEN queue */ - if (twa_aen_drain_queue(tw_dev, soft_reset)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence"); - do_soft_reset = 1; - tries++; - continue; - } - - /* If we got here, controller is in a good state */ - retval = 0; - goto out; - } -out: - return retval; -} /* End twa_reset_sequence() */ - -/* This funciton returns unit geometry in cylinders/heads/sectors */ -static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) -{ - int heads, sectors, cylinders; - TW_Device_Extension *tw_dev; - - tw_dev = (TW_Device_Extension *)sdev->host->hostdata; - - if (capacity >= 0x200000) { - heads = 255; - sectors = 63; - cylinders = sector_div(capacity, heads * sectors); - } else { - heads = 64; - sectors = 32; - cylinders = sector_div(capacity, heads * sectors); - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return 0; -} /* End twa_scsi_biosparam() */ - -/* This is the new scsi eh reset function */ -static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt) -{ - TW_Device_Extension *tw_dev = NULL; - int retval = FAILED; - - tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; - - tw_dev->num_resets++; - - sdev_printk(KERN_WARNING, SCpnt->device, - "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n", - TW_DRIVER, 0x2c, SCpnt->cmnd[0]); - - /* Make sure we are not issuing an ioctl or resetting from ioctl */ - mutex_lock(&tw_dev->ioctl_lock); - - /* Now reset the card and some of the device extension data */ - if (twa_reset_device_extension(tw_dev)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset"); - goto out; - } - - retval = SUCCESS; -out: - mutex_unlock(&tw_dev->ioctl_lock); - return retval; -} /* End twa_scsi_eh_reset() */ - -/* This is the main scsi queue function to handle scsi opcodes */ -static int twa_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) -{ - int request_id, retval; - TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; - - /* If we are resetting due to timed out ioctl, report as busy */ - if (test_bit(TW_IN_RESET, &tw_dev->flags)) { - retval = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - - /* Check if this FW supports luns */ - if ((SCpnt->device->lun != 0) && (tw_dev->tw_compat_info.working_srl < TW_FW_SRL_LUNS_SUPPORTED)) { - SCpnt->result = (DID_BAD_TARGET << 16); - done(SCpnt); - retval = 0; - goto out; - } - - /* Save done function into scsi_cmnd struct */ - SCpnt->scsi_done = done; - - /* Get a free request id */ - twa_get_request_id(tw_dev, &request_id); - - /* Save the scsi command for use by the ISR */ - tw_dev->srb[request_id] = SCpnt; - - /* Initialize phase to zero */ - SCpnt->SCp.phase = TW_PHASE_INITIAL; - - retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); - switch (retval) { - case SCSI_MLQUEUE_HOST_BUSY: - twa_free_request_id(tw_dev, request_id); - twa_unmap_scsi_data(tw_dev, request_id); - break; - case 1: - tw_dev->state[request_id] = TW_S_COMPLETED; - twa_free_request_id(tw_dev, request_id); - twa_unmap_scsi_data(tw_dev, request_id); - SCpnt->result = (DID_ERROR << 16); - done(SCpnt); - retval = 0; - } -out: - return retval; -} /* End twa_scsi_queue() */ - -static DEF_SCSI_QCMD(twa_scsi_queue) - -/* This function hands scsi cdb's to the firmware */ -static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg) -{ - TW_Command_Full *full_command_packet; - TW_Command_Apache *command_packet; - u32 num_sectors = 0x0; - int i, sg_count; - struct scsi_cmnd *srb = NULL; - struct scatterlist *sglist = NULL, *sg; - int retval = 1; - - if (tw_dev->srb[request_id]) { - srb = tw_dev->srb[request_id]; - if (scsi_sglist(srb)) - sglist = scsi_sglist(srb); - } - - /* Initialize command packet */ - full_command_packet = tw_dev->command_packet_virt[request_id]; - full_command_packet->header.header_desc.size_header = 128; - full_command_packet->header.status_block.error = 0; - full_command_packet->header.status_block.severity__reserved = 0; - - command_packet = &full_command_packet->command.newcommand; - command_packet->status = 0; - command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI); - - /* We forced 16 byte cdb use earlier */ - if (!cdb) - memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN); - else - memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN); - - if (srb) { - command_packet->unit = srb->device->id; - command_packet->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id)); - } else { - command_packet->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(0, request_id)); - command_packet->unit = 0; - } - - command_packet->sgl_offset = 16; - - if (!sglistarg) { - /* Map sglist from scsi layer to cmd packet */ - - if (scsi_sg_count(srb)) { - if ((scsi_sg_count(srb) == 1) && - (scsi_bufflen(srb) < TW_MIN_SGL_LENGTH)) { - if (srb->sc_data_direction == DMA_TO_DEVICE || - srb->sc_data_direction == DMA_BIDIRECTIONAL) - scsi_sg_copy_to_buffer(srb, - tw_dev->generic_buffer_virt[request_id], - TW_SECTOR_SIZE); - command_packet->sg_list[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); - command_packet->sg_list[0].length = cpu_to_le32(TW_MIN_SGL_LENGTH); - } else { - sg_count = twa_map_scsi_sg_data(tw_dev, request_id); - if (sg_count == 0) - goto out; - - scsi_for_each_sg(srb, sg, sg_count, i) { - command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg)); - command_packet->sg_list[i].length = cpu_to_le32(sg_dma_len(sg)); - if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi"); - goto out; - } - } - } - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id]))); - } - } else { - /* Internal cdb post */ - for (i = 0; i < use_sg; i++) { - command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address); - command_packet->sg_list[i].length = cpu_to_le32(sglistarg[i].length); - if (command_packet->sg_list[i].address & TW_CPU_TO_SGL(TW_ALIGNMENT_9000_SGL)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post"); - goto out; - } - } - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg)); - } - - if (srb) { - if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) - num_sectors = (u32)srb->cmnd[4]; - - if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10) - num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8); - } - - /* Update sector statistic */ - tw_dev->sector_count = num_sectors; - if (tw_dev->sector_count > tw_dev->max_sector_count) - tw_dev->max_sector_count = tw_dev->sector_count; - - /* Update SG statistics */ - if (srb) { - tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]); - if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) - tw_dev->max_sgl_entries = tw_dev->sgl_entries; - } - - /* Now post the command to the board */ - if (srb) { - retval = twa_post_command_packet(tw_dev, request_id, 0); - } else { - twa_post_command_packet(tw_dev, request_id, 1); - retval = 0; - } -out: - return retval; -} /* End twa_scsiop_execute_scsi() */ - -/* This function completes an execute scsi operation */ -static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id) -{ - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - if (scsi_bufflen(cmd) < TW_MIN_SGL_LENGTH && - (cmd->sc_data_direction == DMA_FROM_DEVICE || - cmd->sc_data_direction == DMA_BIDIRECTIONAL)) { - if (scsi_sg_count(cmd) == 1) { - void *buf = tw_dev->generic_buffer_virt[request_id]; - - scsi_sg_copy_from_buffer(cmd, buf, TW_SECTOR_SIZE); - } - } -} /* End twa_scsiop_execute_scsi_complete() */ - -/* This function tells the controller to shut down */ -static void __twa_shutdown(TW_Device_Extension *tw_dev) -{ - /* Disable interrupts */ - TW_DISABLE_INTERRUPTS(tw_dev); - - /* Free up the IRQ */ - free_irq(tw_dev->tw_pci_dev->irq, tw_dev); - - printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no); - - /* Tell the card we are shutting down */ - if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed"); - } else { - printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n"); - } - - /* Clear all interrupts just before exit */ - TW_CLEAR_ALL_INTERRUPTS(tw_dev); -} /* End __twa_shutdown() */ - -/* Wrapper for __twa_shutdown */ -static void twa_shutdown(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - - __twa_shutdown(tw_dev); -} /* End twa_shutdown() */ - -/* This function will look up a string */ -static char *twa_string_lookup(twa_message_type *table, unsigned int code) -{ - int index; - - for (index = 0; ((code != table[index].code) && - (table[index].text != (char *)0)); index++); - return(table[index].text); -} /* End twa_string_lookup() */ - -/* This function will perform a pci-dma unmap */ -static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) -{ - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - if (cmd->SCp.phase == TW_PHASE_SGLIST) - scsi_dma_unmap(cmd); -} /* End twa_unmap_scsi_data() */ - -/* This function gets called when a disk is coming on-line */ -static int twa_slave_configure(struct scsi_device *sdev) -{ - /* Force 60 second timeout */ - blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); - - return 0; -} /* End twa_slave_configure() */ - -/* scsi_host_template initializer */ -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = "3ware 9000 Storage Controller", - .queuecommand = twa_scsi_queue, - .eh_host_reset_handler = twa_scsi_eh_reset, - .bios_param = twa_scsi_biosparam, - .change_queue_depth = twa_change_queue_depth, - .can_queue = TW_Q_LENGTH-2, - .slave_configure = twa_slave_configure, - .this_id = -1, - .sg_tablesize = TW_APACHE_MAX_SGL_LENGTH, - .max_sectors = TW_MAX_SECTORS, - .cmd_per_lun = TW_MAX_CMDS_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = twa_host_attrs, - .emulated = 1 -}; - -/* This function will probe and initialize a card */ -static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) -{ - struct Scsi_Host *host = NULL; - TW_Device_Extension *tw_dev; - unsigned long mem_addr, mem_len; - int retval = -ENODEV; - - retval = pci_enable_device(pdev); - if (retval) { - TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device"); - goto out_disable_device; - } - - pci_set_master(pdev); - pci_try_set_mwi(pdev); - - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask"); - retval = -ENODEV; - goto out_disable_device; - } - - host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); - if (!host) { - TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension"); - retval = -ENOMEM; - goto out_disable_device; - } - tw_dev = (TW_Device_Extension *)host->hostdata; - - /* Save values to device extension */ - tw_dev->host = host; - tw_dev->tw_pci_dev = pdev; - - if (twa_initialize_device_extension(tw_dev)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension"); - goto out_free_device_extension; - } - - /* Request IO regions */ - retval = pci_request_regions(pdev, "3w-9xxx"); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region"); - goto out_free_device_extension; - } - - if (pdev->device == PCI_DEVICE_ID_3WARE_9000) { - mem_addr = pci_resource_start(pdev, 1); - mem_len = pci_resource_len(pdev, 1); - } else { - mem_addr = pci_resource_start(pdev, 2); - mem_len = pci_resource_len(pdev, 2); - } - - /* Save base address */ - tw_dev->base_addr = ioremap(mem_addr, mem_len); - if (!tw_dev->base_addr) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap"); - goto out_release_mem_region; - } - - /* Disable interrupts on the card */ - TW_DISABLE_INTERRUPTS(tw_dev); - - /* Initialize the card */ - if (twa_reset_sequence(tw_dev, 0)) - goto out_iounmap; - - /* Set host specific parameters */ - if ((pdev->device == PCI_DEVICE_ID_3WARE_9650SE) || - (pdev->device == PCI_DEVICE_ID_3WARE_9690SA)) - host->max_id = TW_MAX_UNITS_9650SE; - else - host->max_id = TW_MAX_UNITS; - - host->max_cmd_len = TW_MAX_CDB_LEN; - - /* Channels aren't supported by adapter */ - host->max_lun = TW_MAX_LUNS(tw_dev->tw_compat_info.working_srl); - host->max_channel = 0; - - /* Register the card with the kernel SCSI layer */ - retval = scsi_add_host(host, &pdev->dev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed"); - goto out_iounmap; - } - - pci_set_drvdata(pdev, host); - - printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%lx, IRQ: %d.\n", - host->host_no, mem_addr, pdev->irq); - printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n", - host->host_no, - (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE, - TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), - (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE, - TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), - le32_to_cpu(*(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE, - TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH))); - - /* Try to enable MSI */ - if (use_msi && (pdev->device != PCI_DEVICE_ID_3WARE_9000) && - !pci_enable_msi(pdev)) - set_bit(TW_USING_MSI, &tw_dev->flags); - - /* Now setup the interrupt handler */ - retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ"); - goto out_remove_host; - } - - twa_device_extension_list[twa_device_extension_count] = tw_dev; - twa_device_extension_count++; - - /* Re-enable interrupts on the card */ - TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); - - /* Finally, scan the host */ - scsi_scan_host(host); - - if (twa_major == -1) { - if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0) - TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device"); - } - return 0; - -out_remove_host: - if (test_bit(TW_USING_MSI, &tw_dev->flags)) - pci_disable_msi(pdev); - scsi_remove_host(host); -out_iounmap: - iounmap(tw_dev->base_addr); -out_release_mem_region: - pci_release_regions(pdev); -out_free_device_extension: - twa_free_device_extension(tw_dev); - scsi_host_put(host); -out_disable_device: - pci_disable_device(pdev); - - return retval; -} /* End twa_probe() */ - -/* This function is called to remove a device */ -static void twa_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - - scsi_remove_host(tw_dev->host); - - /* Unregister character device */ - if (twa_major >= 0) { - unregister_chrdev(twa_major, "twa"); - twa_major = -1; - } - - /* Shutdown the card */ - __twa_shutdown(tw_dev); - - /* Disable MSI if enabled */ - if (test_bit(TW_USING_MSI, &tw_dev->flags)) - pci_disable_msi(pdev); - - /* Free IO remapping */ - iounmap(tw_dev->base_addr); - - /* Free up the mem region */ - pci_release_regions(pdev); - - /* Free up device extension resources */ - twa_free_device_extension(tw_dev); - - scsi_host_put(tw_dev->host); - pci_disable_device(pdev); - twa_device_extension_count--; -} /* End twa_remove() */ - -#ifdef CONFIG_PM -/* This function is called on PCI suspend */ -static int twa_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - - printk(KERN_WARNING "3w-9xxx: Suspending host %d.\n", tw_dev->host->host_no); - - TW_DISABLE_INTERRUPTS(tw_dev); - free_irq(tw_dev->tw_pci_dev->irq, tw_dev); - - if (test_bit(TW_USING_MSI, &tw_dev->flags)) - pci_disable_msi(pdev); - - /* Tell the card we are shutting down */ - if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x38, "Connection shutdown failed during suspend"); - } else { - printk(KERN_WARNING "3w-9xxx: Suspend complete.\n"); - } - TW_CLEAR_ALL_INTERRUPTS(tw_dev); - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} /* End twa_suspend() */ - -/* This function is called on PCI resume */ -static int twa_resume(struct pci_dev *pdev) -{ - int retval = 0; - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - - printk(KERN_WARNING "3w-9xxx: Resuming host %d.\n", tw_dev->host->host_no); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - retval = pci_enable_device(pdev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x39, "Enable device failed during resume"); - return retval; - } - - pci_set_master(pdev); - pci_try_set_mwi(pdev); - - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x40, "Failed to set dma mask during resume"); - retval = -ENODEV; - goto out_disable_device; - } - - /* Initialize the card */ - if (twa_reset_sequence(tw_dev, 0)) { - retval = -ENODEV; - goto out_disable_device; - } - - /* Now setup the interrupt handler */ - retval = request_irq(pdev->irq, twa_interrupt, IRQF_SHARED, "3w-9xxx", tw_dev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x42, "Error requesting IRQ during resume"); - retval = -ENODEV; - goto out_disable_device; - } - - /* Now enable MSI if enabled */ - if (test_bit(TW_USING_MSI, &tw_dev->flags)) - pci_enable_msi(pdev); - - /* Re-enable interrupts on the card */ - TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); - - printk(KERN_WARNING "3w-9xxx: Resume complete.\n"); - return 0; - -out_disable_device: - scsi_remove_host(host); - pci_disable_device(pdev); - - return retval; -} /* End twa_resume() */ -#endif - -/* PCI Devices supported by this driver */ -static struct pci_device_id twa_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9550SX, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9650SE, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9690SA, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { } -}; -MODULE_DEVICE_TABLE(pci, twa_pci_tbl); - -/* pci_driver initializer */ -static struct pci_driver twa_driver = { - .name = "3w-9xxx", - .id_table = twa_pci_tbl, - .probe = twa_probe, - .remove = twa_remove, -#ifdef CONFIG_PM - .suspend = twa_suspend, - .resume = twa_resume, -#endif - .shutdown = twa_shutdown -}; - -/* This function is called on driver initialization */ -static int __init twa_init(void) -{ - printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION); - - return pci_register_driver(&twa_driver); -} /* End twa_init() */ - -/* This function is called on driver exit */ -static void __exit twa_exit(void) -{ - pci_unregister_driver(&twa_driver); -} /* End twa_exit() */ - -module_init(twa_init); -module_exit(twa_exit); - diff --git a/ANDROID_3.4.5/drivers/scsi/3w-9xxx.h b/ANDROID_3.4.5/drivers/scsi/3w-9xxx.h deleted file mode 100644 index 040f7214..00000000 --- a/ANDROID_3.4.5/drivers/scsi/3w-9xxx.h +++ /dev/null @@ -1,686 +0,0 @@ -/* - 3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux. - - Written By: Adam Radford - Modifications By: Tom Couch - - Copyright (C) 2004-2009 Applied Micro Circuits Corporation. - Copyright (C) 2010 LSI Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - NO WARRANTY - THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - DISCLAIMER OF LIABILITY - NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com -*/ - -#ifndef _3W_9XXX_H -#define _3W_9XXX_H - -/* AEN string type */ -typedef struct TAG_twa_message_type { - unsigned int code; - char* text; -} twa_message_type; - -/* AEN strings */ -static twa_message_type twa_aen_table[] = { - {0x0000, "AEN queue empty"}, - {0x0001, "Controller reset occurred"}, - {0x0002, "Degraded unit detected"}, - {0x0003, "Controller error occurred"}, - {0x0004, "Background rebuild failed"}, - {0x0005, "Background rebuild done"}, - {0x0006, "Incomplete unit detected"}, - {0x0007, "Background initialize done"}, - {0x0008, "Unclean shutdown detected"}, - {0x0009, "Drive timeout detected"}, - {0x000A, "Drive error detected"}, - {0x000B, "Rebuild started"}, - {0x000C, "Background initialize started"}, - {0x000D, "Entire logical unit was deleted"}, - {0x000E, "Background initialize failed"}, - {0x000F, "SMART attribute exceeded threshold"}, - {0x0010, "Power supply reported AC under range"}, - {0x0011, "Power supply reported DC out of range"}, - {0x0012, "Power supply reported a malfunction"}, - {0x0013, "Power supply predicted malfunction"}, - {0x0014, "Battery charge is below threshold"}, - {0x0015, "Fan speed is below threshold"}, - {0x0016, "Temperature sensor is above threshold"}, - {0x0017, "Power supply was removed"}, - {0x0018, "Power supply was inserted"}, - {0x0019, "Drive was removed from a bay"}, - {0x001A, "Drive was inserted into a bay"}, - {0x001B, "Drive bay cover door was opened"}, - {0x001C, "Drive bay cover door was closed"}, - {0x001D, "Product case was opened"}, - {0x0020, "Prepare for shutdown (power-off)"}, - {0x0021, "Downgrade UDMA mode to lower speed"}, - {0x0022, "Upgrade UDMA mode to higher speed"}, - {0x0023, "Sector repair completed"}, - {0x0024, "Sbuf memory test failed"}, - {0x0025, "Error flushing cached write data to array"}, - {0x0026, "Drive reported data ECC error"}, - {0x0027, "DCB has checksum error"}, - {0x0028, "DCB version is unsupported"}, - {0x0029, "Background verify started"}, - {0x002A, "Background verify failed"}, - {0x002B, "Background verify done"}, - {0x002C, "Bad sector overwritten during rebuild"}, - {0x002D, "Background rebuild error on source drive"}, - {0x002E, "Replace failed because replacement drive too small"}, - {0x002F, "Verify failed because array was never initialized"}, - {0x0030, "Unsupported ATA drive"}, - {0x0031, "Synchronize host/controller time"}, - {0x0032, "Spare capacity is inadequate for some units"}, - {0x0033, "Background migration started"}, - {0x0034, "Background migration failed"}, - {0x0035, "Background migration done"}, - {0x0036, "Verify detected and fixed data/parity mismatch"}, - {0x0037, "SO-DIMM incompatible"}, - {0x0038, "SO-DIMM not detected"}, - {0x0039, "Corrected Sbuf ECC error"}, - {0x003A, "Drive power on reset detected"}, - {0x003B, "Background rebuild paused"}, - {0x003C, "Background initialize paused"}, - {0x003D, "Background verify paused"}, - {0x003E, "Background migration paused"}, - {0x003F, "Corrupt flash file system detected"}, - {0x0040, "Flash file system repaired"}, - {0x0041, "Unit number assignments were lost"}, - {0x0042, "Error during read of primary DCB"}, - {0x0043, "Latent error found in backup DCB"}, - {0x00FC, "Recovered/finished array membership update"}, - {0x00FD, "Handler lockup"}, - {0x00FE, "Retrying PCI transfer"}, - {0x00FF, "AEN queue is full"}, - {0xFFFFFFFF, (char*) 0} -}; - -/* AEN severity table */ -static char *twa_aen_severity_table[] = -{ - "None", "ERROR", "WARNING", "INFO", "DEBUG", (char*) 0 -}; - -/* Error strings */ -static twa_message_type twa_error_table[] = { - {0x0100, "SGL entry contains zero data"}, - {0x0101, "Invalid command opcode"}, - {0x0102, "SGL entry has unaligned address"}, - {0x0103, "SGL size does not match command"}, - {0x0104, "SGL entry has illegal length"}, - {0x0105, "Command packet is not aligned"}, - {0x0106, "Invalid request ID"}, - {0x0107, "Duplicate request ID"}, - {0x0108, "ID not locked"}, - {0x0109, "LBA out of range"}, - {0x010A, "Logical unit not supported"}, - {0x010B, "Parameter table does not exist"}, - {0x010C, "Parameter index does not exist"}, - {0x010D, "Invalid field in CDB"}, - {0x010E, "Specified port has invalid drive"}, - {0x010F, "Parameter item size mismatch"}, - {0x0110, "Failed memory allocation"}, - {0x0111, "Memory request too large"}, - {0x0112, "Out of memory segments"}, - {0x0113, "Invalid address to deallocate"}, - {0x0114, "Out of memory"}, - {0x0115, "Out of heap"}, - {0x0120, "Double degrade"}, - {0x0121, "Drive not degraded"}, - {0x0122, "Reconstruct error"}, - {0x0123, "Replace not accepted"}, - {0x0124, "Replace drive capacity too small"}, - {0x0125, "Sector count not allowed"}, - {0x0126, "No spares left"}, - {0x0127, "Reconstruct error"}, - {0x0128, "Unit is offline"}, - {0x0129, "Cannot update status to DCB"}, - {0x0130, "Invalid stripe handle"}, - {0x0131, "Handle that was not locked"}, - {0x0132, "Handle that was not empty"}, - {0x0133, "Handle has different owner"}, - {0x0140, "IPR has parent"}, - {0x0150, "Illegal Pbuf address alignment"}, - {0x0151, "Illegal Pbuf transfer length"}, - {0x0152, "Illegal Sbuf address alignment"}, - {0x0153, "Illegal Sbuf transfer length"}, - {0x0160, "Command packet too large"}, - {0x0161, "SGL exceeds maximum length"}, - {0x0162, "SGL has too many entries"}, - {0x0170, "Insufficient resources for rebuilder"}, - {0x0171, "Verify error (data != parity)"}, - {0x0180, "Requested segment not in directory of this DCB"}, - {0x0181, "DCB segment has unsupported version"}, - {0x0182, "DCB segment has checksum error"}, - {0x0183, "DCB support (settings) segment invalid"}, - {0x0184, "DCB UDB (unit descriptor block) segment invalid"}, - {0x0185, "DCB GUID (globally unique identifier) segment invalid"}, - {0x01A0, "Could not clear Sbuf"}, - {0x01C0, "Flash identify failed"}, - {0x01C1, "Flash out of bounds"}, - {0x01C2, "Flash verify error"}, - {0x01C3, "Flash file object not found"}, - {0x01C4, "Flash file already present"}, - {0x01C5, "Flash file system full"}, - {0x01C6, "Flash file not present"}, - {0x01C7, "Flash file size error"}, - {0x01C8, "Bad flash file checksum"}, - {0x01CA, "Corrupt flash file system detected"}, - {0x01D0, "Invalid field in parameter list"}, - {0x01D1, "Parameter list length error"}, - {0x01D2, "Parameter item is not changeable"}, - {0x01D3, "Parameter item is not saveable"}, - {0x0200, "UDMA CRC error"}, - {0x0201, "Internal CRC error"}, - {0x0202, "Data ECC error"}, - {0x0203, "ADP level 1 error"}, - {0x0204, "Port timeout"}, - {0x0205, "Drive power on reset"}, - {0x0206, "ADP level 2 error"}, - {0x0207, "Soft reset failed"}, - {0x0208, "Drive not ready"}, - {0x0209, "Unclassified port error"}, - {0x020A, "Drive aborted command"}, - {0x0210, "Internal CRC error"}, - {0x0211, "PCI abort error"}, - {0x0212, "PCI parity error"}, - {0x0213, "Port handler error"}, - {0x0214, "Token interrupt count error"}, - {0x0215, "Timeout waiting for PCI transfer"}, - {0x0216, "Corrected buffer ECC"}, - {0x0217, "Uncorrected buffer ECC"}, - {0x0230, "Unsupported command during flash recovery"}, - {0x0231, "Next image buffer expected"}, - {0x0232, "Binary image architecture incompatible"}, - {0x0233, "Binary image has no signature"}, - {0x0234, "Binary image has bad checksum"}, - {0x0235, "Image downloaded overflowed buffer"}, - {0x0240, "I2C device not found"}, - {0x0241, "I2C transaction aborted"}, - {0x0242, "SO-DIMM parameter(s) incompatible using defaults"}, - {0x0243, "SO-DIMM unsupported"}, - {0x0248, "SPI transfer status error"}, - {0x0249, "SPI transfer timeout error"}, - {0x0250, "Invalid unit descriptor size in CreateUnit"}, - {0x0251, "Unit descriptor size exceeds data buffer in CreateUnit"}, - {0x0252, "Invalid value in CreateUnit descriptor"}, - {0x0253, "Inadequate disk space to support descriptor in CreateUnit"}, - {0x0254, "Unable to create data channel for this unit descriptor"}, - {0x0255, "CreateUnit descriptor specifies a drive already in use"}, - {0x0256, "Unable to write configuration to all disks during CreateUnit"}, - {0x0257, "CreateUnit does not support this descriptor version"}, - {0x0258, "Invalid subunit for RAID 0 or 5 in CreateUnit"}, - {0x0259, "Too many descriptors in CreateUnit"}, - {0x025A, "Invalid configuration specified in CreateUnit descriptor"}, - {0x025B, "Invalid LBA offset specified in CreateUnit descriptor"}, - {0x025C, "Invalid stripelet size specified in CreateUnit descriptor"}, - {0x0260, "SMART attribute exceeded threshold"}, - {0xFFFFFFFF, (char*) 0} -}; - -/* Control register bit definitions */ -#define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 -#define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT 0x00040000 -#define TW_CONTROL_MASK_COMMAND_INTERRUPT 0x00020000 -#define TW_CONTROL_MASK_RESPONSE_INTERRUPT 0x00010000 -#define TW_CONTROL_UNMASK_COMMAND_INTERRUPT 0x00008000 -#define TW_CONTROL_UNMASK_RESPONSE_INTERRUPT 0x00004000 -#define TW_CONTROL_CLEAR_ERROR_STATUS 0x00000200 -#define TW_CONTROL_ISSUE_SOFT_RESET 0x00000100 -#define TW_CONTROL_ENABLE_INTERRUPTS 0x00000080 -#define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040 -#define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020 -#define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000 -#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000 -#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 - -/* Status register bit definitions */ -#define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000 -#define TW_STATUS_MINOR_VERSION_MASK 0x0F000000 -#define TW_STATUS_PCI_PARITY_ERROR 0x00800000 -#define TW_STATUS_QUEUE_ERROR 0x00400000 -#define TW_STATUS_MICROCONTROLLER_ERROR 0x00200000 -#define TW_STATUS_PCI_ABORT 0x00100000 -#define TW_STATUS_HOST_INTERRUPT 0x00080000 -#define TW_STATUS_ATTENTION_INTERRUPT 0x00040000 -#define TW_STATUS_COMMAND_INTERRUPT 0x00020000 -#define TW_STATUS_RESPONSE_INTERRUPT 0x00010000 -#define TW_STATUS_COMMAND_QUEUE_FULL 0x00008000 -#define TW_STATUS_RESPONSE_QUEUE_EMPTY 0x00004000 -#define TW_STATUS_MICROCONTROLLER_READY 0x00002000 -#define TW_STATUS_COMMAND_QUEUE_EMPTY 0x00001000 -#define TW_STATUS_EXPECTED_BITS 0x00002000 -#define TW_STATUS_UNEXPECTED_BITS 0x00F00000 -#define TW_STATUS_VALID_INTERRUPT 0x00DF0000 - -/* PCI related defines */ -#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100 -#define TW_PCI_CLEAR_PCI_ABORT 0x2000 - -/* Command packet opcodes used by the driver */ -#define TW_OP_INIT_CONNECTION 0x1 -#define TW_OP_GET_PARAM 0x12 -#define TW_OP_SET_PARAM 0x13 -#define TW_OP_EXECUTE_SCSI 0x10 -#define TW_OP_DOWNLOAD_FIRMWARE 0x16 -#define TW_OP_RESET 0x1C - -/* Asynchronous Event Notification (AEN) codes used by the driver */ -#define TW_AEN_QUEUE_EMPTY 0x0000 -#define TW_AEN_SOFT_RESET 0x0001 -#define TW_AEN_SYNC_TIME_WITH_HOST 0x031 -#define TW_AEN_SEVERITY_ERROR 0x1 -#define TW_AEN_SEVERITY_DEBUG 0x4 -#define TW_AEN_NOT_RETRIEVED 0x1 -#define TW_AEN_RETRIEVED 0x2 - -/* Command state defines */ -#define TW_S_INITIAL 0x1 /* Initial state */ -#define TW_S_STARTED 0x2 /* Id in use */ -#define TW_S_POSTED 0x4 /* Posted to the controller */ -#define TW_S_PENDING 0x8 /* Waiting to be posted in isr */ -#define TW_S_COMPLETED 0x10 /* Completed by isr */ -#define TW_S_FINISHED 0x20 /* I/O completely done */ - -/* Compatibility defines */ -#define TW_9000_ARCH_ID 0x5 -#define TW_CURRENT_DRIVER_SRL 35 -#define TW_CURRENT_DRIVER_BUILD 0 -#define TW_CURRENT_DRIVER_BRANCH 0 - -/* Phase defines */ -#define TW_PHASE_INITIAL 0 -#define TW_PHASE_SINGLE 1 -#define TW_PHASE_SGLIST 2 - -/* Misc defines */ -#define TW_9550SX_DRAIN_COMPLETED 0xFFFF -#define TW_SECTOR_SIZE 512 -#define TW_ALIGNMENT_9000 4 /* 4 bytes */ -#define TW_ALIGNMENT_9000_SGL 0x3 -#define TW_MAX_UNITS 16 -#define TW_MAX_UNITS_9650SE 32 -#define TW_INIT_MESSAGE_CREDITS 0x100 -#define TW_INIT_COMMAND_PACKET_SIZE 0x3 -#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6 -#define TW_EXTENDED_INIT_CONNECT 0x2 -#define TW_BUNDLED_FW_SAFE_TO_FLASH 0x4 -#define TW_CTLR_FW_RECOMMENDS_FLASH 0x8 -#define TW_CTLR_FW_COMPATIBLE 0x2 -#define TW_BASE_FW_SRL 24 -#define TW_BASE_FW_BRANCH 0 -#define TW_BASE_FW_BUILD 1 -#define TW_FW_SRL_LUNS_SUPPORTED 28 -#define TW_Q_LENGTH 256 -#define TW_Q_START 0 -#define TW_MAX_SLOT 32 -#define TW_MAX_RESET_TRIES 2 -#define TW_MAX_CMDS_PER_LUN 254 -#define TW_MAX_RESPONSE_DRAIN 256 -#define TW_MAX_AEN_DRAIN 255 -#define TW_IN_RESET 2 -#define TW_USING_MSI 3 -#define TW_IN_ATTENTION_LOOP 4 -#define TW_MAX_SECTORS 256 -#define TW_AEN_WAIT_TIME 1000 -#define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */ -#define TW_MAX_CDB_LEN 16 -#define TW_ISR_DONT_COMPLETE 2 -#define TW_ISR_DONT_RESULT 3 -#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */ -#define TW_IOCTL_CHRDEV_FREE -1 -#define TW_COMMAND_OFFSET 128 /* 128 bytes */ -#define TW_VERSION_TABLE 0x0402 -#define TW_TIMEKEEP_TABLE 0x040A -#define TW_INFORMATION_TABLE 0x0403 -#define TW_PARAM_FWVER 3 -#define TW_PARAM_FWVER_LENGTH 16 -#define TW_PARAM_BIOSVER 4 -#define TW_PARAM_BIOSVER_LENGTH 16 -#define TW_PARAM_PORTCOUNT 3 -#define TW_PARAM_PORTCOUNT_LENGTH 1 -#define TW_MIN_SGL_LENGTH 0x200 /* 512 bytes */ -#define TW_MAX_SENSE_LENGTH 256 -#define TW_EVENT_SOURCE_AEN 0x1000 -#define TW_EVENT_SOURCE_COMMAND 0x1001 -#define TW_EVENT_SOURCE_PCHIP 0x1002 -#define TW_EVENT_SOURCE_DRIVER 0x1003 -#define TW_IOCTL_GET_COMPATIBILITY_INFO 0x101 -#define TW_IOCTL_GET_LAST_EVENT 0x102 -#define TW_IOCTL_GET_FIRST_EVENT 0x103 -#define TW_IOCTL_GET_NEXT_EVENT 0x104 -#define TW_IOCTL_GET_PREVIOUS_EVENT 0x105 -#define TW_IOCTL_GET_LOCK 0x106 -#define TW_IOCTL_RELEASE_LOCK 0x107 -#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108 -#define TW_IOCTL_ERROR_STATUS_NOT_LOCKED 0x1001 // Not locked -#define TW_IOCTL_ERROR_STATUS_LOCKED 0x1002 // Already locked -#define TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS 0x1003 // No more events -#define TW_IOCTL_ERROR_STATUS_AEN_CLOBBER 0x1004 // AEN clobber occurred -#define TW_IOCTL_ERROR_OS_EFAULT -EFAULT // Bad address -#define TW_IOCTL_ERROR_OS_EINTR -EINTR // Interrupted system call -#define TW_IOCTL_ERROR_OS_EINVAL -EINVAL // Invalid argument -#define TW_IOCTL_ERROR_OS_ENOMEM -ENOMEM // Out of memory -#define TW_IOCTL_ERROR_OS_ERESTARTSYS -ERESTARTSYS // Restart system call -#define TW_IOCTL_ERROR_OS_EIO -EIO // I/O error -#define TW_IOCTL_ERROR_OS_ENOTTY -ENOTTY // Not a typewriter -#define TW_IOCTL_ERROR_OS_ENODEV -ENODEV // No such device -#define TW_ALLOCATION_LENGTH 128 -#define TW_SENSE_DATA_LENGTH 18 -#define TW_STATUS_CHECK_CONDITION 2 -#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x10a -#define TW_ERROR_UNIT_OFFLINE 0x128 -#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR 3 -#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT 4 -#define TW_MESSAGE_SOURCE_LINUX_DRIVER 6 -#define TW_DRIVER TW_MESSAGE_SOURCE_LINUX_DRIVER -#define TW_MESSAGE_SOURCE_LINUX_OS 9 -#define TW_OS TW_MESSAGE_SOURCE_LINUX_OS -#ifndef PCI_DEVICE_ID_3WARE_9000 -#define PCI_DEVICE_ID_3WARE_9000 0x1002 -#endif -#ifndef PCI_DEVICE_ID_3WARE_9550SX -#define PCI_DEVICE_ID_3WARE_9550SX 0x1003 -#endif -#ifndef PCI_DEVICE_ID_3WARE_9650SE -#define PCI_DEVICE_ID_3WARE_9650SE 0x1004 -#endif -#ifndef PCI_DEVICE_ID_3WARE_9690SA -#define PCI_DEVICE_ID_3WARE_9690SA 0x1005 -#endif - -/* Bitmask macros to eliminate bitfields */ - -/* opcode: 5, reserved: 3 */ -#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f)) -#define TW_OP_OUT(x) (x & 0x1f) - -/* opcode: 5, sgloffset: 3 */ -#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f)) -#define TW_SGL_OUT(x) ((x >> 5) & 0x7) - -/* severity: 3, reserved: 5 */ -#define TW_SEV_OUT(x) (x & 0x7) - -/* reserved_1: 4, response_id: 8, reserved_2: 20 */ -#define TW_RESID_OUT(x) ((x >> 4) & 0xff) - -/* request_id: 12, lun: 4 */ -#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff)) -#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf) - -/* Macros */ -#define TW_CONTROL_REG_ADDR(x) (x->base_addr) -#define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4) -#define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8)) -#define TW_COMMAND_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x20) -#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC) -#define TW_RESPONSE_QUEUE_REG_ADDR_LARGE(x) ((unsigned char __iomem *)x->base_addr + 0x30) -#define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_CLEAR_HOST_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_DISABLE_INTERRUPTS(x) (writel(TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) -#define TW_ENABLE_AND_CLEAR_INTERRUPTS(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) -#define TW_MASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_MASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_UNMASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_UNMASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_SOFT_RESET(x) (writel(TW_CONTROL_ISSUE_SOFT_RESET | \ - TW_CONTROL_CLEAR_HOST_INTERRUPT | \ - TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | \ - TW_CONTROL_MASK_COMMAND_INTERRUPT | \ - TW_CONTROL_MASK_RESPONSE_INTERRUPT | \ - TW_CONTROL_CLEAR_ERROR_STATUS | \ - TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) -#define TW_PRINTK(h,a,b,c) { \ -if (h) \ -printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \ -else \ -printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \ -} -#define TW_MAX_LUNS(srl) (srl < TW_FW_SRL_LUNS_SUPPORTED ? 1 : 16) -#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 5 : 4) -#define TW_APACHE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 72 : 109) -#define TW_ESCALADE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 41 : 62) -#define TW_PADDING_LENGTH (sizeof(dma_addr_t) > 4 ? 8 : 0) -#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x)) - -#pragma pack(1) - -/* Scatter Gather List Entry */ -typedef struct TAG_TW_SG_Entry { - dma_addr_t address; - u32 length; -} TW_SG_Entry; - -/* Command Packet */ -typedef struct TW_Command { - unsigned char opcode__sgloffset; - unsigned char size; - unsigned char request_id; - unsigned char unit__hostid; - /* Second DWORD */ - unsigned char status; - unsigned char flags; - union { - unsigned short block_count; - unsigned short parameter_count; - } byte6_offset; - union { - struct { - u32 lba; - TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH]; - dma_addr_t padding; - } io; - struct { - TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH]; - u32 padding; - dma_addr_t padding2; - } param; - } byte8_offset; -} TW_Command; - -/* Command Packet for 9000+ controllers */ -typedef struct TAG_TW_Command_Apache { - unsigned char opcode__reserved; - unsigned char unit; - unsigned short request_id__lunl; - unsigned char status; - unsigned char sgl_offset; - unsigned short sgl_entries__lunh; - unsigned char cdb[16]; - TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH]; - unsigned char padding[TW_PADDING_LENGTH]; -} TW_Command_Apache; - -/* New command packet header */ -typedef struct TAG_TW_Command_Apache_Header { - unsigned char sense_data[TW_SENSE_DATA_LENGTH]; - struct { - char reserved[4]; - unsigned short error; - unsigned char padding; - unsigned char severity__reserved; - } status_block; - unsigned char err_specific_desc[98]; - struct { - unsigned char size_header; - unsigned short reserved; - unsigned char size_sense; - } header_desc; -} TW_Command_Apache_Header; - -/* This struct is a union of the 2 command packets */ -typedef struct TAG_TW_Command_Full { - TW_Command_Apache_Header header; - union { - TW_Command oldcommand; - TW_Command_Apache newcommand; - } command; -} TW_Command_Full; - -/* Initconnection structure */ -typedef struct TAG_TW_Initconnect { - unsigned char opcode__reserved; - unsigned char size; - unsigned char request_id; - unsigned char res2; - unsigned char status; - unsigned char flags; - unsigned short message_credits; - u32 features; - unsigned short fw_srl; - unsigned short fw_arch_id; - unsigned short fw_branch; - unsigned short fw_build; - u32 result; -} TW_Initconnect; - -/* Event info structure */ -typedef struct TAG_TW_Event -{ - unsigned int sequence_id; - unsigned int time_stamp_sec; - unsigned short aen_code; - unsigned char severity; - unsigned char retrieved; - unsigned char repeat_count; - unsigned char parameter_len; - unsigned char parameter_data[98]; -} TW_Event; - -typedef struct TAG_TW_Ioctl_Driver_Command { - unsigned int control_code; - unsigned int status; - unsigned int unique_id; - unsigned int sequence_id; - unsigned int os_specific; - unsigned int buffer_length; -} TW_Ioctl_Driver_Command; - -typedef struct TAG_TW_Ioctl_Apache { - TW_Ioctl_Driver_Command driver_command; - char padding[488]; - TW_Command_Full firmware_command; - char data_buffer[1]; -} TW_Ioctl_Buf_Apache; - -/* Lock structure for ioctl get/release lock */ -typedef struct TAG_TW_Lock { - unsigned long timeout_msec; - unsigned long time_remaining_msec; - unsigned long force_flag; -} TW_Lock; - -/* GetParam descriptor */ -typedef struct { - unsigned short table_id; - unsigned short parameter_id; - unsigned short parameter_size_bytes; - unsigned short actual_parameter_size_bytes; - unsigned char data[1]; -} TW_Param_Apache, *PTW_Param_Apache; - -/* Response queue */ -typedef union TAG_TW_Response_Queue { - u32 response_id; - u32 value; -} TW_Response_Queue; - -/* Compatibility information structure */ -typedef struct TAG_TW_Compatibility_Info -{ - char driver_version[32]; - unsigned short working_srl; - unsigned short working_branch; - unsigned short working_build; - unsigned short driver_srl_high; - unsigned short driver_branch_high; - unsigned short driver_build_high; - unsigned short driver_srl_low; - unsigned short driver_branch_low; - unsigned short driver_build_low; - unsigned short fw_on_ctlr_srl; - unsigned short fw_on_ctlr_branch; - unsigned short fw_on_ctlr_build; -} TW_Compatibility_Info; - -#pragma pack() - -typedef struct TAG_TW_Device_Extension { - u32 __iomem *base_addr; - unsigned long *generic_buffer_virt[TW_Q_LENGTH]; - dma_addr_t generic_buffer_phys[TW_Q_LENGTH]; - TW_Command_Full *command_packet_virt[TW_Q_LENGTH]; - dma_addr_t command_packet_phys[TW_Q_LENGTH]; - struct pci_dev *tw_pci_dev; - struct scsi_cmnd *srb[TW_Q_LENGTH]; - unsigned char free_queue[TW_Q_LENGTH]; - unsigned char free_head; - unsigned char free_tail; - unsigned char pending_queue[TW_Q_LENGTH]; - unsigned char pending_head; - unsigned char pending_tail; - int state[TW_Q_LENGTH]; - unsigned int posted_request_count; - unsigned int max_posted_request_count; - unsigned int pending_request_count; - unsigned int max_pending_request_count; - unsigned int max_sgl_entries; - unsigned int sgl_entries; - unsigned int num_resets; - unsigned int sector_count; - unsigned int max_sector_count; - unsigned int aen_count; - struct Scsi_Host *host; - long flags; - int reset_print; - TW_Event *event_queue[TW_Q_LENGTH]; - unsigned char error_index; - unsigned char event_queue_wrapped; - unsigned int error_sequence_id; - int ioctl_sem_lock; - u32 ioctl_msec; - int chrdev_request_id; - wait_queue_head_t ioctl_wqueue; - struct mutex ioctl_lock; - char aen_clobber; - TW_Compatibility_Info tw_compat_info; -} TW_Device_Extension; - -#endif /* _3W_9XXX_H */ - diff --git a/ANDROID_3.4.5/drivers/scsi/3w-sas.c b/ANDROID_3.4.5/drivers/scsi/3w-sas.c deleted file mode 100644 index 13e39e1f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/3w-sas.c +++ /dev/null @@ -1,1931 +0,0 @@ -/* - 3w-sas.c -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux. - - Written By: Adam Radford - - Copyright (C) 2009 LSI Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - NO WARRANTY - THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - DISCLAIMER OF LIABILITY - NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Controllers supported by this driver: - - LSI 3ware 9750 6Gb/s SAS/SATA-RAID - - Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com - - History - ------- - 3.26.02.000 - Initial driver release. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "3w-sas.h" - -/* Globals */ -#define TW_DRIVER_VERSION "3.26.02.000" -static DEFINE_MUTEX(twl_chrdev_mutex); -static TW_Device_Extension *twl_device_extension_list[TW_MAX_SLOT]; -static unsigned int twl_device_extension_count; -static int twl_major = -1; -extern struct timezone sys_tz; - -/* Module parameters */ -MODULE_AUTHOR ("LSI"); -MODULE_DESCRIPTION ("LSI 3ware SAS/SATA-RAID Linux Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(TW_DRIVER_VERSION); - -static int use_msi; -module_param(use_msi, int, S_IRUGO); -MODULE_PARM_DESC(use_msi, "Use Message Signaled Interrupts. Default: 0"); - -/* Function prototypes */ -static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset); - -/* Functions */ - -/* This function returns AENs through sysfs */ -static ssize_t twl_sysfs_aen_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *outbuf, loff_t offset, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata; - unsigned long flags = 0; - ssize_t ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - spin_lock_irqsave(tw_dev->host->host_lock, flags); - ret = memory_read_from_buffer(outbuf, count, &offset, tw_dev->event_queue[0], sizeof(TW_Event) * TW_Q_LENGTH); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - - return ret; -} /* End twl_sysfs_aen_read() */ - -/* aen_read sysfs attribute initializer */ -static struct bin_attribute twl_sysfs_aen_read_attr = { - .attr = { - .name = "3ware_aen_read", - .mode = S_IRUSR, - }, - .size = 0, - .read = twl_sysfs_aen_read -}; - -/* This function returns driver compatibility info through sysfs */ -static ssize_t twl_sysfs_compat_info(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *outbuf, loff_t offset, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)shost->hostdata; - unsigned long flags = 0; - ssize_t ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - spin_lock_irqsave(tw_dev->host->host_lock, flags); - ret = memory_read_from_buffer(outbuf, count, &offset, &tw_dev->tw_compat_info, sizeof(TW_Compatibility_Info)); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - - return ret; -} /* End twl_sysfs_compat_info() */ - -/* compat_info sysfs attribute initializer */ -static struct bin_attribute twl_sysfs_compat_info_attr = { - .attr = { - .name = "3ware_compat_info", - .mode = S_IRUSR, - }, - .size = 0, - .read = twl_sysfs_compat_info -}; - -/* Show some statistics about the card */ -static ssize_t twl_show_stats(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - unsigned long flags = 0; - ssize_t len; - - spin_lock_irqsave(tw_dev->host->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "3w-sas Driver version: %s\n" - "Current commands posted: %4d\n" - "Max commands posted: %4d\n" - "Last sgl length: %4d\n" - "Max sgl length: %4d\n" - "Last sector count: %4d\n" - "Max sector count: %4d\n" - "SCSI Host Resets: %4d\n" - "AEN's: %4d\n", - TW_DRIVER_VERSION, - tw_dev->posted_request_count, - tw_dev->max_posted_request_count, - tw_dev->sgl_entries, - tw_dev->max_sgl_entries, - tw_dev->sector_count, - tw_dev->max_sector_count, - tw_dev->num_resets, - tw_dev->aen_count); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - return len; -} /* End twl_show_stats() */ - -/* This function will set a devices queue depth */ -static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (queue_depth > TW_Q_LENGTH-2) - queue_depth = TW_Q_LENGTH-2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); - return queue_depth; -} /* End twl_change_queue_depth() */ - -/* stats sysfs attribute initializer */ -static struct device_attribute twl_host_stats_attr = { - .attr = { - .name = "3ware_stats", - .mode = S_IRUGO, - }, - .show = twl_show_stats -}; - -/* Host attributes initializer */ -static struct device_attribute *twl_host_attrs[] = { - &twl_host_stats_attr, - NULL, -}; - -/* This function will look up an AEN severity string */ -static char *twl_aen_severity_lookup(unsigned char severity_code) -{ - char *retval = NULL; - - if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) || - (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG)) - goto out; - - retval = twl_aen_severity_table[severity_code]; -out: - return retval; -} /* End twl_aen_severity_lookup() */ - -/* This function will queue an event */ -static void twl_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header) -{ - u32 local_time; - struct timeval time; - TW_Event *event; - unsigned short aen; - char host[16]; - char *error_str; - - tw_dev->aen_count++; - - /* Fill out event info */ - event = tw_dev->event_queue[tw_dev->error_index]; - - host[0] = '\0'; - if (tw_dev->host) - sprintf(host, " scsi%d:", tw_dev->host->host_no); - - aen = le16_to_cpu(header->status_block.error); - memset(event, 0, sizeof(TW_Event)); - - event->severity = TW_SEV_OUT(header->status_block.severity__reserved); - do_gettimeofday(&time); - local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60)); - event->time_stamp_sec = local_time; - event->aen_code = aen; - event->retrieved = TW_AEN_NOT_RETRIEVED; - event->sequence_id = tw_dev->error_sequence_id; - tw_dev->error_sequence_id++; - - /* Check for embedded error string */ - error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]); - - header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0'; - event->parameter_len = strlen(header->err_specific_desc); - memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len + 1 + strlen(error_str)); - if (event->severity != TW_AEN_SEVERITY_DEBUG) - printk(KERN_WARNING "3w-sas:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n", - host, - twl_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)), - TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen, error_str, - header->err_specific_desc); - else - tw_dev->aen_count--; - - tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH; -} /* End twl_aen_queue_event() */ - -/* This function will attempt to post a command packet to the board */ -static int twl_post_command_packet(TW_Device_Extension *tw_dev, int request_id) -{ - dma_addr_t command_que_value; - - command_que_value = tw_dev->command_packet_phys[request_id]; - command_que_value += TW_COMMAND_OFFSET; - - /* First write upper 4 bytes */ - writel((u32)((u64)command_que_value >> 32), TWL_HIBQPH_REG_ADDR(tw_dev)); - /* Then the lower 4 bytes */ - writel((u32)(command_que_value | TWL_PULL_MODE), TWL_HIBQPL_REG_ADDR(tw_dev)); - - tw_dev->state[request_id] = TW_S_POSTED; - tw_dev->posted_request_count++; - if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) - tw_dev->max_posted_request_count = tw_dev->posted_request_count; - - return 0; -} /* End twl_post_command_packet() */ - -/* This function will perform a pci-dma mapping for a scatter gather list */ -static int twl_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id) -{ - int use_sg; - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - use_sg = scsi_dma_map(cmd); - if (!use_sg) - return 0; - else if (use_sg < 0) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Failed to map scatter gather list"); - return 0; - } - - cmd->SCp.phase = TW_PHASE_SGLIST; - cmd->SCp.have_data_in = use_sg; - - return use_sg; -} /* End twl_map_scsi_sg_data() */ - -/* This function hands scsi cdb's to the firmware */ -static int twl_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry_ISO *sglistarg) -{ - TW_Command_Full *full_command_packet; - TW_Command_Apache *command_packet; - int i, sg_count; - struct scsi_cmnd *srb = NULL; - struct scatterlist *sglist = NULL, *sg; - int retval = 1; - - if (tw_dev->srb[request_id]) { - srb = tw_dev->srb[request_id]; - if (scsi_sglist(srb)) - sglist = scsi_sglist(srb); - } - - /* Initialize command packet */ - full_command_packet = tw_dev->command_packet_virt[request_id]; - full_command_packet->header.header_desc.size_header = 128; - full_command_packet->header.status_block.error = 0; - full_command_packet->header.status_block.severity__reserved = 0; - - command_packet = &full_command_packet->command.newcommand; - command_packet->status = 0; - command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI); - - /* We forced 16 byte cdb use earlier */ - if (!cdb) - memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN); - else - memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN); - - if (srb) { - command_packet->unit = srb->device->id; - command_packet->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(srb->device->lun, request_id)); - } else { - command_packet->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(0, request_id)); - command_packet->unit = 0; - } - - command_packet->sgl_offset = 16; - - if (!sglistarg) { - /* Map sglist from scsi layer to cmd packet */ - if (scsi_sg_count(srb)) { - sg_count = twl_map_scsi_sg_data(tw_dev, request_id); - if (sg_count == 0) - goto out; - - scsi_for_each_sg(srb, sg, sg_count, i) { - command_packet->sg_list[i].address = TW_CPU_TO_SGL(sg_dma_address(sg)); - command_packet->sg_list[i].length = TW_CPU_TO_SGL(sg_dma_len(sg)); - } - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN((srb->device->lun >> 4), scsi_sg_count(tw_dev->srb[request_id]))); - } - } else { - /* Internal cdb post */ - for (i = 0; i < use_sg; i++) { - command_packet->sg_list[i].address = TW_CPU_TO_SGL(sglistarg[i].address); - command_packet->sg_list[i].length = TW_CPU_TO_SGL(sglistarg[i].length); - } - command_packet->sgl_entries__lunh = cpu_to_le16(TW_REQ_LUN_IN(0, use_sg)); - } - - /* Update some stats */ - if (srb) { - tw_dev->sector_count = scsi_bufflen(srb) / 512; - if (tw_dev->sector_count > tw_dev->max_sector_count) - tw_dev->max_sector_count = tw_dev->sector_count; - tw_dev->sgl_entries = scsi_sg_count(srb); - if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) - tw_dev->max_sgl_entries = tw_dev->sgl_entries; - } - - /* Now post the command to the board */ - retval = twl_post_command_packet(tw_dev, request_id); - -out: - return retval; -} /* End twl_scsiop_execute_scsi() */ - -/* This function will read the aen queue from the isr */ -static int twl_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) -{ - char cdb[TW_MAX_CDB_LEN]; - TW_SG_Entry_ISO sglist[1]; - TW_Command_Full *full_command_packet; - int retval = 1; - - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - - /* Initialize cdb */ - memset(&cdb, 0, TW_MAX_CDB_LEN); - cdb[0] = REQUEST_SENSE; /* opcode */ - cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ - - /* Initialize sglist */ - memset(&sglist, 0, sizeof(TW_SG_Entry_ISO)); - sglist[0].length = TW_SECTOR_SIZE; - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; - - /* Mark internal command */ - tw_dev->srb[request_id] = NULL; - - /* Now post the command packet */ - if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Post failed while reading AEN queue"); - goto out; - } - retval = 0; -out: - return retval; -} /* End twl_aen_read_queue() */ - -/* This function will sync firmware time with the host time */ -static void twl_aen_sync_time(TW_Device_Extension *tw_dev, int request_id) -{ - u32 schedulertime; - struct timeval utc; - TW_Command_Full *full_command_packet; - TW_Command *command_packet; - TW_Param_Apache *param; - u32 local_time; - - /* Fill out the command packet */ - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - command_packet = &full_command_packet->command.oldcommand; - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); - command_packet->request_id = request_id; - command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); - command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE); - command_packet->size = TW_COMMAND_SIZE; - command_packet->byte6_offset.parameter_count = cpu_to_le16(1); - - /* Setup the param */ - param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; - memset(param, 0, TW_SECTOR_SIZE); - param->table_id = cpu_to_le16(TW_TIMEKEEP_TABLE | 0x8000); /* Controller time keep table */ - param->parameter_id = cpu_to_le16(0x3); /* SchedulerTime */ - param->parameter_size_bytes = cpu_to_le16(4); - - /* Convert system time in UTC to local time seconds since last - Sunday 12:00AM */ - do_gettimeofday(&utc); - local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60)); - schedulertime = local_time - (3 * 86400); - schedulertime = cpu_to_le32(schedulertime % 604800); - - memcpy(param->data, &schedulertime, sizeof(u32)); - - /* Mark internal command */ - tw_dev->srb[request_id] = NULL; - - /* Now post the command */ - twl_post_command_packet(tw_dev, request_id); -} /* End twl_aen_sync_time() */ - -/* This function will assign an available request id */ -static void twl_get_request_id(TW_Device_Extension *tw_dev, int *request_id) -{ - *request_id = tw_dev->free_queue[tw_dev->free_head]; - tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH; - tw_dev->state[*request_id] = TW_S_STARTED; -} /* End twl_get_request_id() */ - -/* This function will free a request id */ -static void twl_free_request_id(TW_Device_Extension *tw_dev, int request_id) -{ - tw_dev->free_queue[tw_dev->free_tail] = request_id; - tw_dev->state[request_id] = TW_S_FINISHED; - tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH; -} /* End twl_free_request_id() */ - -/* This function will complete an aen request from the isr */ -static int twl_aen_complete(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Command_Full *full_command_packet; - TW_Command *command_packet; - TW_Command_Apache_Header *header; - unsigned short aen; - int retval = 1; - - header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; - tw_dev->posted_request_count--; - aen = le16_to_cpu(header->status_block.error); - full_command_packet = tw_dev->command_packet_virt[request_id]; - command_packet = &full_command_packet->command.oldcommand; - - /* First check for internal completion of set param for time sync */ - if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) { - /* Keep reading the queue in case there are more aen's */ - if (twl_aen_read_queue(tw_dev, request_id)) - goto out2; - else { - retval = 0; - goto out; - } - } - - switch (aen) { - case TW_AEN_QUEUE_EMPTY: - /* Quit reading the queue if this is the last one */ - break; - case TW_AEN_SYNC_TIME_WITH_HOST: - twl_aen_sync_time(tw_dev, request_id); - retval = 0; - goto out; - default: - twl_aen_queue_event(tw_dev, header); - - /* If there are more aen's, keep reading the queue */ - if (twl_aen_read_queue(tw_dev, request_id)) - goto out2; - else { - retval = 0; - goto out; - } - } - retval = 0; -out2: - tw_dev->state[request_id] = TW_S_COMPLETED; - twl_free_request_id(tw_dev, request_id); - clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); -out: - return retval; -} /* End twl_aen_complete() */ - -/* This function will poll for a response */ -static int twl_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds) -{ - unsigned long before; - dma_addr_t mfa; - u32 regh, regl; - u32 response; - int retval = 1; - int found = 0; - - before = jiffies; - - while (!found) { - if (sizeof(dma_addr_t) > 4) { - regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev)); - regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); - mfa = ((u64)regh << 32) | regl; - } else - mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); - - response = (u32)mfa; - - if (TW_RESID_OUT(response) == request_id) - found = 1; - - if (time_after(jiffies, before + HZ * seconds)) - goto out; - - msleep(50); - } - retval = 0; -out: - return retval; -} /* End twl_poll_response() */ - -/* This function will drain the aen queue */ -static int twl_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset) -{ - int request_id = 0; - char cdb[TW_MAX_CDB_LEN]; - TW_SG_Entry_ISO sglist[1]; - int finished = 0, count = 0; - TW_Command_Full *full_command_packet; - TW_Command_Apache_Header *header; - unsigned short aen; - int first_reset = 0, queue = 0, retval = 1; - - if (no_check_reset) - first_reset = 0; - else - first_reset = 1; - - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - - /* Initialize cdb */ - memset(&cdb, 0, TW_MAX_CDB_LEN); - cdb[0] = REQUEST_SENSE; /* opcode */ - cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */ - - /* Initialize sglist */ - memset(&sglist, 0, sizeof(TW_SG_Entry_ISO)); - sglist[0].length = TW_SECTOR_SIZE; - sglist[0].address = tw_dev->generic_buffer_phys[request_id]; - - /* Mark internal command */ - tw_dev->srb[request_id] = NULL; - - do { - /* Send command to the board */ - if (twl_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "Error posting request sense"); - goto out; - } - - /* Now poll for completion */ - if (twl_poll_response(tw_dev, request_id, 30)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "No valid response while draining AEN queue"); - tw_dev->posted_request_count--; - goto out; - } - - tw_dev->posted_request_count--; - header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id]; - aen = le16_to_cpu(header->status_block.error); - queue = 0; - count++; - - switch (aen) { - case TW_AEN_QUEUE_EMPTY: - if (first_reset != 1) - goto out; - else - finished = 1; - break; - case TW_AEN_SOFT_RESET: - if (first_reset == 0) - first_reset = 1; - else - queue = 1; - break; - case TW_AEN_SYNC_TIME_WITH_HOST: - break; - default: - queue = 1; - } - - /* Now queue an event info */ - if (queue) - twl_aen_queue_event(tw_dev, header); - } while ((finished == 0) && (count < TW_MAX_AEN_DRAIN)); - - if (count == TW_MAX_AEN_DRAIN) - goto out; - - retval = 0; -out: - tw_dev->state[request_id] = TW_S_INITIAL; - return retval; -} /* End twl_aen_drain_queue() */ - -/* This function will allocate memory and check if it is correctly aligned */ -static int twl_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) -{ - int i; - dma_addr_t dma_handle; - unsigned long *cpu_addr; - int retval = 1; - - cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); - if (!cpu_addr) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed"); - goto out; - } - - memset(cpu_addr, 0, size*TW_Q_LENGTH); - - for (i = 0; i < TW_Q_LENGTH; i++) { - switch(which) { - case 0: - tw_dev->command_packet_phys[i] = dma_handle+(i*size); - tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size)); - break; - case 1: - tw_dev->generic_buffer_phys[i] = dma_handle+(i*size); - tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); - break; - case 2: - tw_dev->sense_buffer_phys[i] = dma_handle+(i*size); - tw_dev->sense_buffer_virt[i] = (TW_Command_Apache_Header *)((unsigned char *)cpu_addr + (i*size)); - break; - } - } - retval = 0; -out: - return retval; -} /* End twl_allocate_memory() */ - -/* This function will load the request id and various sgls for ioctls */ -static void twl_load_sgl(TW_Device_Extension *tw_dev, TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length) -{ - TW_Command *oldcommand; - TW_Command_Apache *newcommand; - TW_SG_Entry_ISO *sgl; - unsigned int pae = 0; - - if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4)) - pae = 1; - - if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) { - newcommand = &full_command_packet->command.newcommand; - newcommand->request_id__lunl = - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id)); - if (length) { - newcommand->sg_list[0].address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); - newcommand->sg_list[0].length = TW_CPU_TO_SGL(length); - } - newcommand->sgl_entries__lunh = - cpu_to_le16(TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), length ? 1 : 0)); - } else { - oldcommand = &full_command_packet->command.oldcommand; - oldcommand->request_id = request_id; - - if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) { - /* Load the sg list */ - sgl = (TW_SG_Entry_ISO *)((u32 *)oldcommand+oldcommand->size - (sizeof(TW_SG_Entry_ISO)/4) + pae + (sizeof(dma_addr_t) > 4 ? 1 : 0)); - sgl->address = TW_CPU_TO_SGL(dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1); - sgl->length = TW_CPU_TO_SGL(length); - oldcommand->size += pae; - oldcommand->size += sizeof(dma_addr_t) > 4 ? 1 : 0; - } - } -} /* End twl_load_sgl() */ - -/* This function handles ioctl for the character device - This interface is used by smartmontools open source software */ -static long twl_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long timeout; - unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0; - dma_addr_t dma_handle; - int request_id = 0; - TW_Ioctl_Driver_Command driver_command; - struct inode *inode = file->f_dentry->d_inode; - TW_Ioctl_Buf_Apache *tw_ioctl; - TW_Command_Full *full_command_packet; - TW_Device_Extension *tw_dev = twl_device_extension_list[iminor(inode)]; - int retval = -EFAULT; - void __user *argp = (void __user *)arg; - - mutex_lock(&twl_chrdev_mutex); - - /* Only let one of these through at a time */ - if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { - retval = -EINTR; - goto out; - } - - /* First copy down the driver command */ - if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command))) - goto out2; - - /* Check data buffer size */ - if (driver_command.buffer_length > TW_MAX_SECTORS * 2048) { - retval = -EINVAL; - goto out2; - } - - /* Hardware can only do multiple of 512 byte transfers */ - data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511; - - /* Now allocate ioctl buf memory */ - cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL); - if (!cpu_addr) { - retval = -ENOMEM; - goto out2; - } - - tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr; - - /* Now copy down the entire ioctl */ - if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1)) - goto out3; - - /* See which ioctl we are doing */ - switch (cmd) { - case TW_IOCTL_FIRMWARE_PASS_THROUGH: - spin_lock_irqsave(tw_dev->host->host_lock, flags); - twl_get_request_id(tw_dev, &request_id); - - /* Flag internal command */ - tw_dev->srb[request_id] = NULL; - - /* Flag chrdev ioctl */ - tw_dev->chrdev_request_id = request_id; - - full_command_packet = (TW_Command_Full *)&tw_ioctl->firmware_command; - - /* Load request id and sglist for both command types */ - twl_load_sgl(tw_dev, full_command_packet, request_id, dma_handle, data_buffer_length_adjusted); - - memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full)); - - /* Now post the command packet to the controller */ - twl_post_command_packet(tw_dev, request_id); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - - timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; - - /* Now wait for command to complete */ - timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); - - /* We timed out, and didn't get an interrupt */ - if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { - /* Now we need to reset the board */ - printk(KERN_WARNING "3w-sas: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n", - tw_dev->host->host_no, TW_DRIVER, 0x6, - cmd); - retval = -EIO; - twl_reset_device_extension(tw_dev, 1); - goto out3; - } - - /* Now copy in the command packet response */ - memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full)); - - /* Now complete the io */ - spin_lock_irqsave(tw_dev->host->host_lock, flags); - tw_dev->posted_request_count--; - tw_dev->state[request_id] = TW_S_COMPLETED; - twl_free_request_id(tw_dev, request_id); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - break; - default: - retval = -ENOTTY; - goto out3; - } - - /* Now copy the entire response to userspace */ - if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0) - retval = 0; -out3: - /* Now free ioctl buf memory */ - dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle); -out2: - mutex_unlock(&tw_dev->ioctl_lock); -out: - mutex_unlock(&twl_chrdev_mutex); - return retval; -} /* End twl_chrdev_ioctl() */ - -/* This function handles open for the character device */ -static int twl_chrdev_open(struct inode *inode, struct file *file) -{ - unsigned int minor_number; - int retval = -ENODEV; - - if (!capable(CAP_SYS_ADMIN)) { - retval = -EACCES; - goto out; - } - - minor_number = iminor(inode); - if (minor_number >= twl_device_extension_count) - goto out; - retval = 0; -out: - return retval; -} /* End twl_chrdev_open() */ - -/* File operations struct for character device */ -static const struct file_operations twl_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = twl_chrdev_ioctl, - .open = twl_chrdev_open, - .release = NULL, - .llseek = noop_llseek, -}; - -/* This function passes sense data from firmware to scsi layer */ -static int twl_fill_sense(TW_Device_Extension *tw_dev, int i, int request_id, int copy_sense, int print_host) -{ - TW_Command_Apache_Header *header; - TW_Command_Full *full_command_packet; - unsigned short error; - char *error_str; - int retval = 1; - - header = tw_dev->sense_buffer_virt[i]; - full_command_packet = tw_dev->command_packet_virt[request_id]; - - /* Get embedded firmware error string */ - error_str = &(header->err_specific_desc[strlen(header->err_specific_desc) + 1]); - - /* Don't print error for Logical unit not supported during rollcall */ - error = le16_to_cpu(header->status_block.error); - if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE) && (error != TW_ERROR_INVALID_FIELD_IN_CDB)) { - if (print_host) - printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n", - tw_dev->host->host_no, - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, - header->status_block.error, - error_str, - header->err_specific_desc); - else - printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s:%s.\n", - TW_MESSAGE_SOURCE_CONTROLLER_ERROR, - header->status_block.error, - error_str, - header->err_specific_desc); - } - - if (copy_sense) { - memcpy(tw_dev->srb[request_id]->sense_buffer, header->sense_data, TW_SENSE_DATA_LENGTH); - tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1); - goto out; - } -out: - return retval; -} /* End twl_fill_sense() */ - -/* This function will free up device extension resources */ -static void twl_free_device_extension(TW_Device_Extension *tw_dev) -{ - if (tw_dev->command_packet_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - sizeof(TW_Command_Full)*TW_Q_LENGTH, - tw_dev->command_packet_virt[0], - tw_dev->command_packet_phys[0]); - - if (tw_dev->generic_buffer_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - TW_SECTOR_SIZE*TW_Q_LENGTH, - tw_dev->generic_buffer_virt[0], - tw_dev->generic_buffer_phys[0]); - - if (tw_dev->sense_buffer_virt[0]) - pci_free_consistent(tw_dev->tw_pci_dev, - sizeof(TW_Command_Apache_Header)* - TW_Q_LENGTH, - tw_dev->sense_buffer_virt[0], - tw_dev->sense_buffer_phys[0]); - - kfree(tw_dev->event_queue[0]); -} /* End twl_free_device_extension() */ - -/* This function will get parameter table entries from the firmware */ -static void *twl_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes) -{ - TW_Command_Full *full_command_packet; - TW_Command *command_packet; - TW_Param_Apache *param; - void *retval = NULL; - - /* Setup the command packet */ - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - command_packet = &full_command_packet->command.oldcommand; - - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = TW_COMMAND_SIZE; - command_packet->request_id = request_id; - command_packet->byte6_offset.block_count = cpu_to_le16(1); - - /* Now setup the param */ - param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id]; - memset(param, 0, TW_SECTOR_SIZE); - param->table_id = cpu_to_le16(table_id | 0x8000); - param->parameter_id = cpu_to_le16(parameter_id); - param->parameter_size_bytes = cpu_to_le16(parameter_size_bytes); - - command_packet->byte8_offset.param.sgl[0].address = TW_CPU_TO_SGL(tw_dev->generic_buffer_phys[request_id]); - command_packet->byte8_offset.param.sgl[0].length = TW_CPU_TO_SGL(TW_SECTOR_SIZE); - - /* Post the command packet to the board */ - twl_post_command_packet(tw_dev, request_id); - - /* Poll for completion */ - if (twl_poll_response(tw_dev, request_id, 30)) - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "No valid response during get param") - else - retval = (void *)&(param->data[0]); - - tw_dev->posted_request_count--; - tw_dev->state[request_id] = TW_S_INITIAL; - - return retval; -} /* End twl_get_param() */ - -/* This function will send an initconnection command to controller */ -static int twl_initconnection(TW_Device_Extension *tw_dev, int message_credits, - u32 set_features, unsigned short current_fw_srl, - unsigned short current_fw_arch_id, - unsigned short current_fw_branch, - unsigned short current_fw_build, - unsigned short *fw_on_ctlr_srl, - unsigned short *fw_on_ctlr_arch_id, - unsigned short *fw_on_ctlr_branch, - unsigned short *fw_on_ctlr_build, - u32 *init_connect_result) -{ - TW_Command_Full *full_command_packet; - TW_Initconnect *tw_initconnect; - int request_id = 0, retval = 1; - - /* Initialize InitConnection command packet */ - full_command_packet = tw_dev->command_packet_virt[request_id]; - memset(full_command_packet, 0, sizeof(TW_Command_Full)); - full_command_packet->header.header_desc.size_header = 128; - - tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand; - tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION); - tw_initconnect->request_id = request_id; - tw_initconnect->message_credits = cpu_to_le16(message_credits); - tw_initconnect->features = set_features; - - /* Turn on 64-bit sgl support if we need to */ - tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0; - - tw_initconnect->features = cpu_to_le32(tw_initconnect->features); - - if (set_features & TW_EXTENDED_INIT_CONNECT) { - tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED; - tw_initconnect->fw_srl = cpu_to_le16(current_fw_srl); - tw_initconnect->fw_arch_id = cpu_to_le16(current_fw_arch_id); - tw_initconnect->fw_branch = cpu_to_le16(current_fw_branch); - tw_initconnect->fw_build = cpu_to_le16(current_fw_build); - } else - tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE; - - /* Send command packet to the board */ - twl_post_command_packet(tw_dev, request_id); - - /* Poll for completion */ - if (twl_poll_response(tw_dev, request_id, 30)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x8, "No valid response during init connection"); - } else { - if (set_features & TW_EXTENDED_INIT_CONNECT) { - *fw_on_ctlr_srl = le16_to_cpu(tw_initconnect->fw_srl); - *fw_on_ctlr_arch_id = le16_to_cpu(tw_initconnect->fw_arch_id); - *fw_on_ctlr_branch = le16_to_cpu(tw_initconnect->fw_branch); - *fw_on_ctlr_build = le16_to_cpu(tw_initconnect->fw_build); - *init_connect_result = le32_to_cpu(tw_initconnect->result); - } - retval = 0; - } - - tw_dev->posted_request_count--; - tw_dev->state[request_id] = TW_S_INITIAL; - - return retval; -} /* End twl_initconnection() */ - -/* This function will initialize the fields of a device extension */ -static int twl_initialize_device_extension(TW_Device_Extension *tw_dev) -{ - int i, retval = 1; - - /* Initialize command packet buffers */ - if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x9, "Command packet memory allocation failed"); - goto out; - } - - /* Initialize generic buffer */ - if (twl_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Generic memory allocation failed"); - goto out; - } - - /* Allocate sense buffers */ - if (twl_allocate_memory(tw_dev, sizeof(TW_Command_Apache_Header), 2)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xb, "Sense buffer allocation failed"); - goto out; - } - - /* Allocate event info space */ - tw_dev->event_queue[0] = kcalloc(TW_Q_LENGTH, sizeof(TW_Event), GFP_KERNEL); - if (!tw_dev->event_queue[0]) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "Event info memory allocation failed"); - goto out; - } - - for (i = 0; i < TW_Q_LENGTH; i++) { - tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event))); - tw_dev->free_queue[i] = i; - tw_dev->state[i] = TW_S_INITIAL; - } - - tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_START; - tw_dev->error_sequence_id = 1; - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - - mutex_init(&tw_dev->ioctl_lock); - init_waitqueue_head(&tw_dev->ioctl_wqueue); - - retval = 0; -out: - return retval; -} /* End twl_initialize_device_extension() */ - -/* This function will perform a pci-dma unmap */ -static void twl_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) -{ - struct scsi_cmnd *cmd = tw_dev->srb[request_id]; - - if (cmd->SCp.phase == TW_PHASE_SGLIST) - scsi_dma_unmap(cmd); -} /* End twl_unmap_scsi_data() */ - -/* This function will handle attention interrupts */ -static int twl_handle_attention_interrupt(TW_Device_Extension *tw_dev) -{ - int retval = 1; - u32 request_id, doorbell; - - /* Read doorbell status */ - doorbell = readl(TWL_HOBDB_REG_ADDR(tw_dev)); - - /* Check for controller errors */ - if (doorbell & TWL_DOORBELL_CONTROLLER_ERROR) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "Microcontroller Error: clearing"); - goto out; - } - - /* Check if we need to perform an AEN drain */ - if (doorbell & TWL_DOORBELL_ATTENTION_INTERRUPT) { - if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) { - twl_get_request_id(tw_dev, &request_id); - if (twl_aen_read_queue(tw_dev, request_id)) { - tw_dev->state[request_id] = TW_S_COMPLETED; - twl_free_request_id(tw_dev, request_id); - clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags); - } - } - } - - retval = 0; -out: - /* Clear doorbell interrupt */ - TWL_CLEAR_DB_INTERRUPT(tw_dev); - - /* Make sure the clear was flushed by reading it back */ - readl(TWL_HOBDBC_REG_ADDR(tw_dev)); - - return retval; -} /* End twl_handle_attention_interrupt() */ - -/* Interrupt service routine */ -static irqreturn_t twl_interrupt(int irq, void *dev_instance) -{ - TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; - int i, handled = 0, error = 0; - dma_addr_t mfa = 0; - u32 reg, regl, regh, response, request_id = 0; - struct scsi_cmnd *cmd; - TW_Command_Full *full_command_packet; - - spin_lock(tw_dev->host->host_lock); - - /* Read host interrupt status */ - reg = readl(TWL_HISTAT_REG_ADDR(tw_dev)); - - /* Check if this is our interrupt, otherwise bail */ - if (!(reg & TWL_HISTATUS_VALID_INTERRUPT)) - goto twl_interrupt_bail; - - handled = 1; - - /* If we are resetting, bail */ - if (test_bit(TW_IN_RESET, &tw_dev->flags)) - goto twl_interrupt_bail; - - /* Attention interrupt */ - if (reg & TWL_HISTATUS_ATTENTION_INTERRUPT) { - if (twl_handle_attention_interrupt(tw_dev)) { - TWL_MASK_INTERRUPTS(tw_dev); - goto twl_interrupt_bail; - } - } - - /* Response interrupt */ - while (reg & TWL_HISTATUS_RESPONSE_INTERRUPT) { - if (sizeof(dma_addr_t) > 4) { - regh = readl(TWL_HOBQPH_REG_ADDR(tw_dev)); - regl = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); - mfa = ((u64)regh << 32) | regl; - } else - mfa = readl(TWL_HOBQPL_REG_ADDR(tw_dev)); - - error = 0; - response = (u32)mfa; - - /* Check for command packet error */ - if (!TW_NOTMFA_OUT(response)) { - for (i=0;isense_buffer_phys[i] == mfa) { - request_id = le16_to_cpu(tw_dev->sense_buffer_virt[i]->header_desc.request_id); - if (tw_dev->srb[request_id] != NULL) - error = twl_fill_sense(tw_dev, i, request_id, 1, 1); - else { - /* Skip ioctl error prints */ - if (request_id != tw_dev->chrdev_request_id) - error = twl_fill_sense(tw_dev, i, request_id, 0, 1); - else - memcpy(tw_dev->command_packet_virt[request_id], tw_dev->sense_buffer_virt[i], sizeof(TW_Command_Apache_Header)); - } - - /* Now re-post the sense buffer */ - writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev)); - writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev)); - break; - } - } - } else - request_id = TW_RESID_OUT(response); - - full_command_packet = tw_dev->command_packet_virt[request_id]; - - /* Check for correct state */ - if (tw_dev->state[request_id] != TW_S_POSTED) { - if (tw_dev->srb[request_id] != NULL) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Received a request id that wasn't posted"); - TWL_MASK_INTERRUPTS(tw_dev); - goto twl_interrupt_bail; - } - } - - /* Check for internal command completion */ - if (tw_dev->srb[request_id] == NULL) { - if (request_id != tw_dev->chrdev_request_id) { - if (twl_aen_complete(tw_dev, request_id)) - TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "Error completing AEN during attention interrupt"); - } else { - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - wake_up(&tw_dev->ioctl_wqueue); - } - } else { - cmd = tw_dev->srb[request_id]; - - if (!error) - cmd->result = (DID_OK << 16); - - /* Report residual bytes for single sgl */ - if ((scsi_sg_count(cmd) <= 1) && (full_command_packet->command.newcommand.status == 0)) { - if (full_command_packet->command.newcommand.sg_list[0].length < scsi_bufflen(tw_dev->srb[request_id])) - scsi_set_resid(cmd, scsi_bufflen(cmd) - full_command_packet->command.newcommand.sg_list[0].length); - } - - /* Now complete the io */ - tw_dev->state[request_id] = TW_S_COMPLETED; - twl_free_request_id(tw_dev, request_id); - tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - twl_unmap_scsi_data(tw_dev, request_id); - } - - /* Check for another response interrupt */ - reg = readl(TWL_HISTAT_REG_ADDR(tw_dev)); - } - -twl_interrupt_bail: - spin_unlock(tw_dev->host->host_lock); - return IRQ_RETVAL(handled); -} /* End twl_interrupt() */ - -/* This function will poll for a register change */ -static int twl_poll_register(TW_Device_Extension *tw_dev, void *reg, u32 value, u32 result, int seconds) -{ - unsigned long before; - int retval = 1; - u32 reg_value; - - reg_value = readl(reg); - before = jiffies; - - while ((reg_value & value) != result) { - reg_value = readl(reg); - if (time_after(jiffies, before + HZ * seconds)) - goto out; - msleep(50); - } - retval = 0; -out: - return retval; -} /* End twl_poll_register() */ - -/* This function will reset a controller */ -static int twl_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) -{ - int retval = 1; - int i = 0; - u32 status = 0; - unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0; - unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0; - u32 init_connect_result = 0; - int tries = 0; - int do_soft_reset = soft_reset; - - while (tries < TW_MAX_RESET_TRIES) { - /* Do a soft reset if one is needed */ - if (do_soft_reset) { - TWL_SOFT_RESET(tw_dev); - - /* Make sure controller is in a good state */ - if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, 0x0, 30)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Controller never went non-ready during reset sequence"); - tries++; - continue; - } - if (twl_poll_register(tw_dev, TWL_SCRPD3_REG_ADDR(tw_dev), TWL_CONTROLLER_READY, TWL_CONTROLLER_READY, 60)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x11, "Controller not ready during reset sequence"); - tries++; - continue; - } - } - - /* Initconnect */ - if (twl_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS, - TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL, - TW_9750_ARCH_ID, TW_CURRENT_DRIVER_BRANCH, - TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl, - &fw_on_ctlr_arch_id, &fw_on_ctlr_branch, - &fw_on_ctlr_build, &init_connect_result)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x12, "Initconnection failed while checking SRL"); - do_soft_reset = 1; - tries++; - continue; - } - - /* Load sense buffers */ - while (i < TW_Q_LENGTH) { - writel((u32)((u64)tw_dev->sense_buffer_phys[i] >> 32), TWL_HOBQPH_REG_ADDR(tw_dev)); - writel((u32)tw_dev->sense_buffer_phys[i], TWL_HOBQPL_REG_ADDR(tw_dev)); - - /* Check status for over-run after each write */ - status = readl(TWL_STATUS_REG_ADDR(tw_dev)); - if (!(status & TWL_STATUS_OVERRUN_SUBMIT)) - i++; - } - - /* Now check status */ - status = readl(TWL_STATUS_REG_ADDR(tw_dev)); - if (status) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "Bad controller status after loading sense buffers"); - do_soft_reset = 1; - tries++; - continue; - } - - /* Drain the AEN queue */ - if (twl_aen_drain_queue(tw_dev, soft_reset)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x14, "AEN drain failed during reset sequence"); - do_soft_reset = 1; - tries++; - continue; - } - - /* Load rest of compatibility struct */ - strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); - tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; - tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; - tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; - tw_dev->tw_compat_info.driver_srl_low = TW_BASE_FW_SRL; - tw_dev->tw_compat_info.driver_branch_low = TW_BASE_FW_BRANCH; - tw_dev->tw_compat_info.driver_build_low = TW_BASE_FW_BUILD; - tw_dev->tw_compat_info.fw_on_ctlr_srl = fw_on_ctlr_srl; - tw_dev->tw_compat_info.fw_on_ctlr_branch = fw_on_ctlr_branch; - tw_dev->tw_compat_info.fw_on_ctlr_build = fw_on_ctlr_build; - - /* If we got here, controller is in a good state */ - retval = 0; - goto out; - } -out: - return retval; -} /* End twl_reset_sequence() */ - -/* This function will reset a device extension */ -static int twl_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) -{ - int i = 0, retval = 1; - unsigned long flags = 0; - - /* Block SCSI requests while we are resetting */ - if (ioctl_reset) - scsi_block_requests(tw_dev->host); - - set_bit(TW_IN_RESET, &tw_dev->flags); - TWL_MASK_INTERRUPTS(tw_dev); - TWL_CLEAR_DB_INTERRUPT(tw_dev); - - spin_lock_irqsave(tw_dev->host->host_lock, flags); - - /* Abort all requests that are in progress */ - for (i = 0; i < TW_Q_LENGTH; i++) { - if ((tw_dev->state[i] != TW_S_FINISHED) && - (tw_dev->state[i] != TW_S_INITIAL) && - (tw_dev->state[i] != TW_S_COMPLETED)) { - if (tw_dev->srb[i]) { - tw_dev->srb[i]->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); - twl_unmap_scsi_data(tw_dev, i); - } - } - } - - /* Reset queues and counts */ - for (i = 0; i < TW_Q_LENGTH; i++) { - tw_dev->free_queue[i] = i; - tw_dev->state[i] = TW_S_INITIAL; - } - tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_START; - tw_dev->posted_request_count = 0; - - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - - if (twl_reset_sequence(tw_dev, 1)) - goto out; - - TWL_UNMASK_INTERRUPTS(tw_dev); - - clear_bit(TW_IN_RESET, &tw_dev->flags); - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - - retval = 0; -out: - if (ioctl_reset) - scsi_unblock_requests(tw_dev->host); - return retval; -} /* End twl_reset_device_extension() */ - -/* This funciton returns unit geometry in cylinders/heads/sectors */ -static int twl_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) -{ - int heads, sectors; - TW_Device_Extension *tw_dev; - - tw_dev = (TW_Device_Extension *)sdev->host->hostdata; - - if (capacity >= 0x200000) { - heads = 255; - sectors = 63; - } else { - heads = 64; - sectors = 32; - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = sector_div(capacity, heads * sectors); /* cylinders */ - - return 0; -} /* End twl_scsi_biosparam() */ - -/* This is the new scsi eh reset function */ -static int twl_scsi_eh_reset(struct scsi_cmnd *SCpnt) -{ - TW_Device_Extension *tw_dev = NULL; - int retval = FAILED; - - tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; - - tw_dev->num_resets++; - - sdev_printk(KERN_WARNING, SCpnt->device, - "WARNING: (0x%02X:0x%04X): Command (0x%x) timed out, resetting card.\n", - TW_DRIVER, 0x2c, SCpnt->cmnd[0]); - - /* Make sure we are not issuing an ioctl or resetting from ioctl */ - mutex_lock(&tw_dev->ioctl_lock); - - /* Now reset the card and some of the device extension data */ - if (twl_reset_device_extension(tw_dev, 0)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "Controller reset failed during scsi host reset"); - goto out; - } - - retval = SUCCESS; -out: - mutex_unlock(&tw_dev->ioctl_lock); - return retval; -} /* End twl_scsi_eh_reset() */ - -/* This is the main scsi queue function to handle scsi opcodes */ -static int twl_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) -{ - int request_id, retval; - TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; - - /* If we are resetting due to timed out ioctl, report as busy */ - if (test_bit(TW_IN_RESET, &tw_dev->flags)) { - retval = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - - /* Save done function into scsi_cmnd struct */ - SCpnt->scsi_done = done; - - /* Get a free request id */ - twl_get_request_id(tw_dev, &request_id); - - /* Save the scsi command for use by the ISR */ - tw_dev->srb[request_id] = SCpnt; - - /* Initialize phase to zero */ - SCpnt->SCp.phase = TW_PHASE_INITIAL; - - retval = twl_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL); - if (retval) { - tw_dev->state[request_id] = TW_S_COMPLETED; - twl_free_request_id(tw_dev, request_id); - SCpnt->result = (DID_ERROR << 16); - done(SCpnt); - retval = 0; - } -out: - return retval; -} /* End twl_scsi_queue() */ - -static DEF_SCSI_QCMD(twl_scsi_queue) - -/* This function tells the controller to shut down */ -static void __twl_shutdown(TW_Device_Extension *tw_dev) -{ - /* Disable interrupts */ - TWL_MASK_INTERRUPTS(tw_dev); - - /* Free up the IRQ */ - free_irq(tw_dev->tw_pci_dev->irq, tw_dev); - - printk(KERN_WARNING "3w-sas: Shutting down host %d.\n", tw_dev->host->host_no); - - /* Tell the card we are shutting down */ - if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Connection shutdown failed"); - } else { - printk(KERN_WARNING "3w-sas: Shutdown complete.\n"); - } - - /* Clear doorbell interrupt just before exit */ - TWL_CLEAR_DB_INTERRUPT(tw_dev); -} /* End __twl_shutdown() */ - -/* Wrapper for __twl_shutdown */ -static void twl_shutdown(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev; - - if (!host) - return; - - tw_dev = (TW_Device_Extension *)host->hostdata; - - if (tw_dev->online) - __twl_shutdown(tw_dev); -} /* End twl_shutdown() */ - -/* This function configures unit settings when a unit is coming on-line */ -static int twl_slave_configure(struct scsi_device *sdev) -{ - /* Force 60 second timeout */ - blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); - - return 0; -} /* End twl_slave_configure() */ - -/* scsi_host_template initializer */ -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = "3w-sas", - .queuecommand = twl_scsi_queue, - .eh_host_reset_handler = twl_scsi_eh_reset, - .bios_param = twl_scsi_biosparam, - .change_queue_depth = twl_change_queue_depth, - .can_queue = TW_Q_LENGTH-2, - .slave_configure = twl_slave_configure, - .this_id = -1, - .sg_tablesize = TW_LIBERATOR_MAX_SGL_LENGTH, - .max_sectors = TW_MAX_SECTORS, - .cmd_per_lun = TW_MAX_CMDS_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = twl_host_attrs, - .emulated = 1 -}; - -/* This function will probe and initialize a card */ -static int __devinit twl_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) -{ - struct Scsi_Host *host = NULL; - TW_Device_Extension *tw_dev; - int retval = -ENODEV; - int *ptr_phycount, phycount=0; - - retval = pci_enable_device(pdev); - if (retval) { - TW_PRINTK(host, TW_DRIVER, 0x17, "Failed to enable pci device"); - goto out_disable_device; - } - - pci_set_master(pdev); - pci_try_set_mwi(pdev); - - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x18, "Failed to set dma mask"); - retval = -ENODEV; - goto out_disable_device; - } - - host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); - if (!host) { - TW_PRINTK(host, TW_DRIVER, 0x19, "Failed to allocate memory for device extension"); - retval = -ENOMEM; - goto out_disable_device; - } - tw_dev = shost_priv(host); - - /* Save values to device extension */ - tw_dev->host = host; - tw_dev->tw_pci_dev = pdev; - - if (twl_initialize_device_extension(tw_dev)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Failed to initialize device extension"); - goto out_free_device_extension; - } - - /* Request IO regions */ - retval = pci_request_regions(pdev, "3w-sas"); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Failed to get mem region"); - goto out_free_device_extension; - } - - /* Save base address, use region 1 */ - tw_dev->base_addr = pci_iomap(pdev, 1, 0); - if (!tw_dev->base_addr) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to ioremap"); - goto out_release_mem_region; - } - - /* Disable interrupts on the card */ - TWL_MASK_INTERRUPTS(tw_dev); - - /* Initialize the card */ - if (twl_reset_sequence(tw_dev, 0)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Controller reset failed during probe"); - goto out_iounmap; - } - - /* Set host specific parameters */ - host->max_id = TW_MAX_UNITS; - host->max_cmd_len = TW_MAX_CDB_LEN; - host->max_lun = TW_MAX_LUNS; - host->max_channel = 0; - - /* Register the card with the kernel SCSI layer */ - retval = scsi_add_host(host, &pdev->dev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "scsi add host failed"); - goto out_iounmap; - } - - pci_set_drvdata(pdev, host); - - printk(KERN_WARNING "3w-sas: scsi%d: Found an LSI 3ware %s Controller at 0x%llx, IRQ: %d.\n", - host->host_no, - (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE, - TW_PARAM_MODEL, TW_PARAM_MODEL_LENGTH), - (u64)pci_resource_start(pdev, 1), pdev->irq); - - ptr_phycount = twl_get_param(tw_dev, 2, TW_PARAM_PHY_SUMMARY_TABLE, - TW_PARAM_PHYCOUNT, TW_PARAM_PHYCOUNT_LENGTH); - if (ptr_phycount) - phycount = le32_to_cpu(*(int *)ptr_phycount); - - printk(KERN_WARNING "3w-sas: scsi%d: Firmware %s, BIOS %s, Phys: %d.\n", - host->host_no, - (char *)twl_get_param(tw_dev, 1, TW_VERSION_TABLE, - TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH), - (char *)twl_get_param(tw_dev, 2, TW_VERSION_TABLE, - TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH), - phycount); - - /* Try to enable MSI */ - if (use_msi && !pci_enable_msi(pdev)) - set_bit(TW_USING_MSI, &tw_dev->flags); - - /* Now setup the interrupt handler */ - retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Error requesting IRQ"); - goto out_remove_host; - } - - twl_device_extension_list[twl_device_extension_count] = tw_dev; - twl_device_extension_count++; - - /* Re-enable interrupts on the card */ - TWL_UNMASK_INTERRUPTS(tw_dev); - - /* Finally, scan the host */ - scsi_scan_host(host); - - /* Add sysfs binary files */ - if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr)) - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Failed to create sysfs binary file: 3ware_aen_read"); - if (sysfs_create_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr)) - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Failed to create sysfs binary file: 3ware_compat_info"); - - if (twl_major == -1) { - if ((twl_major = register_chrdev (0, "twl", &twl_fops)) < 0) - TW_PRINTK(host, TW_DRIVER, 0x22, "Failed to register character device"); - } - tw_dev->online = 1; - return 0; - -out_remove_host: - if (test_bit(TW_USING_MSI, &tw_dev->flags)) - pci_disable_msi(pdev); - scsi_remove_host(host); -out_iounmap: - iounmap(tw_dev->base_addr); -out_release_mem_region: - pci_release_regions(pdev); -out_free_device_extension: - twl_free_device_extension(tw_dev); - scsi_host_put(host); -out_disable_device: - pci_disable_device(pdev); - - return retval; -} /* End twl_probe() */ - -/* This function is called to remove a device */ -static void twl_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev; - - if (!host) - return; - - tw_dev = (TW_Device_Extension *)host->hostdata; - - if (!tw_dev->online) - return; - - /* Remove sysfs binary files */ - sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_aen_read_attr); - sysfs_remove_bin_file(&host->shost_dev.kobj, &twl_sysfs_compat_info_attr); - - scsi_remove_host(tw_dev->host); - - /* Unregister character device */ - if (twl_major >= 0) { - unregister_chrdev(twl_major, "twl"); - twl_major = -1; - } - - /* Shutdown the card */ - __twl_shutdown(tw_dev); - - /* Disable MSI if enabled */ - if (test_bit(TW_USING_MSI, &tw_dev->flags)) - pci_disable_msi(pdev); - - /* Free IO remapping */ - iounmap(tw_dev->base_addr); - - /* Free up the mem region */ - pci_release_regions(pdev); - - /* Free up device extension resources */ - twl_free_device_extension(tw_dev); - - scsi_host_put(tw_dev->host); - pci_disable_device(pdev); - twl_device_extension_count--; -} /* End twl_remove() */ - -#ifdef CONFIG_PM -/* This function is called on PCI suspend */ -static int twl_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - - printk(KERN_WARNING "3w-sas: Suspending host %d.\n", tw_dev->host->host_no); - /* Disable interrupts */ - TWL_MASK_INTERRUPTS(tw_dev); - - free_irq(tw_dev->tw_pci_dev->irq, tw_dev); - - /* Tell the card we are shutting down */ - if (twl_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x23, "Connection shutdown failed during suspend"); - } else { - printk(KERN_WARNING "3w-sas: Suspend complete.\n"); - } - - /* Clear doorbell interrupt */ - TWL_CLEAR_DB_INTERRUPT(tw_dev); - - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} /* End twl_suspend() */ - -/* This function is called on PCI resume */ -static int twl_resume(struct pci_dev *pdev) -{ - int retval = 0; - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - - printk(KERN_WARNING "3w-sas: Resuming host %d.\n", tw_dev->host->host_no); - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - retval = pci_enable_device(pdev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x24, "Enable device failed during resume"); - return retval; - } - - pci_set_master(pdev); - pci_try_set_mwi(pdev); - - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - || pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - TW_PRINTK(host, TW_DRIVER, 0x25, "Failed to set dma mask during resume"); - retval = -ENODEV; - goto out_disable_device; - } - - /* Initialize the card */ - if (twl_reset_sequence(tw_dev, 0)) { - retval = -ENODEV; - goto out_disable_device; - } - - /* Now setup the interrupt handler */ - retval = request_irq(pdev->irq, twl_interrupt, IRQF_SHARED, "3w-sas", tw_dev); - if (retval) { - TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Error requesting IRQ during resume"); - retval = -ENODEV; - goto out_disable_device; - } - - /* Now enable MSI if enabled */ - if (test_bit(TW_USING_MSI, &tw_dev->flags)) - pci_enable_msi(pdev); - - /* Re-enable interrupts on the card */ - TWL_UNMASK_INTERRUPTS(tw_dev); - - printk(KERN_WARNING "3w-sas: Resume complete.\n"); - return 0; - -out_disable_device: - scsi_remove_host(host); - pci_disable_device(pdev); - - return retval; -} /* End twl_resume() */ -#endif - -/* PCI Devices supported by this driver */ -static struct pci_device_id twl_pci_tbl[] __devinitdata = { - { PCI_VDEVICE(3WARE, PCI_DEVICE_ID_3WARE_9750) }, - { } -}; -MODULE_DEVICE_TABLE(pci, twl_pci_tbl); - -/* pci_driver initializer */ -static struct pci_driver twl_driver = { - .name = "3w-sas", - .id_table = twl_pci_tbl, - .probe = twl_probe, - .remove = twl_remove, -#ifdef CONFIG_PM - .suspend = twl_suspend, - .resume = twl_resume, -#endif - .shutdown = twl_shutdown -}; - -/* This function is called on driver initialization */ -static int __init twl_init(void) -{ - printk(KERN_INFO "LSI 3ware SAS/SATA-RAID Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION); - - return pci_register_driver(&twl_driver); -} /* End twl_init() */ - -/* This function is called on driver exit */ -static void __exit twl_exit(void) -{ - pci_unregister_driver(&twl_driver); -} /* End twl_exit() */ - -module_init(twl_init); -module_exit(twl_exit); - diff --git a/ANDROID_3.4.5/drivers/scsi/3w-sas.h b/ANDROID_3.4.5/drivers/scsi/3w-sas.h deleted file mode 100644 index d4748927..00000000 --- a/ANDROID_3.4.5/drivers/scsi/3w-sas.h +++ /dev/null @@ -1,396 +0,0 @@ -/* - 3w-sas.h -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux. - - Written By: Adam Radford - - Copyright (C) 2009 LSI Corporation. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - NO WARRANTY - THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - DISCLAIMER OF LIABILITY - NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com -*/ - -#ifndef _3W_SAS_H -#define _3W_SAS_H - -/* AEN severity table */ -static char *twl_aen_severity_table[] = -{ - "None", "ERROR", "WARNING", "INFO", "DEBUG", NULL -}; - -/* Liberator register offsets */ -#define TWL_STATUS 0x0 /* Status */ -#define TWL_HIBDB 0x20 /* Inbound doorbell */ -#define TWL_HISTAT 0x30 /* Host interrupt status */ -#define TWL_HIMASK 0x34 /* Host interrupt mask */ -#define TWL_HOBDB 0x9C /* Outbound doorbell */ -#define TWL_HOBDBC 0xA0 /* Outbound doorbell clear */ -#define TWL_SCRPD3 0xBC /* Scratchpad */ -#define TWL_HIBQPL 0xC0 /* Host inbound Q low */ -#define TWL_HIBQPH 0xC4 /* Host inbound Q high */ -#define TWL_HOBQPL 0xC8 /* Host outbound Q low */ -#define TWL_HOBQPH 0xCC /* Host outbound Q high */ -#define TWL_HISTATUS_VALID_INTERRUPT 0xC -#define TWL_HISTATUS_ATTENTION_INTERRUPT 0x4 -#define TWL_HISTATUS_RESPONSE_INTERRUPT 0x8 -#define TWL_STATUS_OVERRUN_SUBMIT 0x2000 -#define TWL_ISSUE_SOFT_RESET 0x100 -#define TWL_CONTROLLER_READY 0x2000 -#define TWL_DOORBELL_CONTROLLER_ERROR 0x200000 -#define TWL_DOORBELL_ATTENTION_INTERRUPT 0x40000 -#define TWL_PULL_MODE 0x1 - -/* Command packet opcodes used by the driver */ -#define TW_OP_INIT_CONNECTION 0x1 -#define TW_OP_GET_PARAM 0x12 -#define TW_OP_SET_PARAM 0x13 -#define TW_OP_EXECUTE_SCSI 0x10 - -/* Asynchronous Event Notification (AEN) codes used by the driver */ -#define TW_AEN_QUEUE_EMPTY 0x0000 -#define TW_AEN_SOFT_RESET 0x0001 -#define TW_AEN_SYNC_TIME_WITH_HOST 0x031 -#define TW_AEN_SEVERITY_ERROR 0x1 -#define TW_AEN_SEVERITY_DEBUG 0x4 -#define TW_AEN_NOT_RETRIEVED 0x1 - -/* Command state defines */ -#define TW_S_INITIAL 0x1 /* Initial state */ -#define TW_S_STARTED 0x2 /* Id in use */ -#define TW_S_POSTED 0x4 /* Posted to the controller */ -#define TW_S_COMPLETED 0x8 /* Completed by isr */ -#define TW_S_FINISHED 0x10 /* I/O completely done */ - -/* Compatibility defines */ -#define TW_9750_ARCH_ID 10 -#define TW_CURRENT_DRIVER_SRL 40 -#define TW_CURRENT_DRIVER_BUILD 0 -#define TW_CURRENT_DRIVER_BRANCH 0 - -/* Phase defines */ -#define TW_PHASE_INITIAL 0 -#define TW_PHASE_SGLIST 2 - -/* Misc defines */ -#define TW_SECTOR_SIZE 512 -#define TW_MAX_UNITS 32 -#define TW_INIT_MESSAGE_CREDITS 0x100 -#define TW_INIT_COMMAND_PACKET_SIZE 0x3 -#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED 0x6 -#define TW_EXTENDED_INIT_CONNECT 0x2 -#define TW_BASE_FW_SRL 24 -#define TW_BASE_FW_BRANCH 0 -#define TW_BASE_FW_BUILD 1 -#define TW_Q_LENGTH 256 -#define TW_Q_START 0 -#define TW_MAX_SLOT 32 -#define TW_MAX_RESET_TRIES 2 -#define TW_MAX_CMDS_PER_LUN 254 -#define TW_MAX_AEN_DRAIN 255 -#define TW_IN_RESET 2 -#define TW_USING_MSI 3 -#define TW_IN_ATTENTION_LOOP 4 -#define TW_MAX_SECTORS 256 -#define TW_MAX_CDB_LEN 16 -#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */ -#define TW_IOCTL_CHRDEV_FREE -1 -#define TW_COMMAND_OFFSET 128 /* 128 bytes */ -#define TW_VERSION_TABLE 0x0402 -#define TW_TIMEKEEP_TABLE 0x040A -#define TW_INFORMATION_TABLE 0x0403 -#define TW_PARAM_FWVER 3 -#define TW_PARAM_FWVER_LENGTH 16 -#define TW_PARAM_BIOSVER 4 -#define TW_PARAM_BIOSVER_LENGTH 16 -#define TW_PARAM_MODEL 8 -#define TW_PARAM_MODEL_LENGTH 16 -#define TW_PARAM_PHY_SUMMARY_TABLE 1 -#define TW_PARAM_PHYCOUNT 2 -#define TW_PARAM_PHYCOUNT_LENGTH 1 -#define TW_IOCTL_FIRMWARE_PASS_THROUGH 0x108 // Used by smartmontools -#define TW_ALLOCATION_LENGTH 128 -#define TW_SENSE_DATA_LENGTH 18 -#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED 0x10a -#define TW_ERROR_INVALID_FIELD_IN_CDB 0x10d -#define TW_ERROR_UNIT_OFFLINE 0x128 -#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR 3 -#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT 4 -#define TW_DRIVER 6 -#ifndef PCI_DEVICE_ID_3WARE_9750 -#define PCI_DEVICE_ID_3WARE_9750 0x1010 -#endif - -/* Bitmask macros to eliminate bitfields */ - -/* opcode: 5, reserved: 3 */ -#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f)) -#define TW_OP_OUT(x) (x & 0x1f) - -/* opcode: 5, sgloffset: 3 */ -#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f)) -#define TW_SGL_OUT(x) ((x >> 5) & 0x7) - -/* severity: 3, reserved: 5 */ -#define TW_SEV_OUT(x) (x & 0x7) - -/* not_mfa: 1, reserved: 7, status: 8, request_id: 16 */ -#define TW_RESID_OUT(x) ((x >> 16) & 0xffff) -#define TW_NOTMFA_OUT(x) (x & 0x1) - -/* request_id: 12, lun: 4 */ -#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff)) -#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf) - -/* Register access macros */ -#define TWL_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_STATUS) -#define TWL_HOBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPL) -#define TWL_HOBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBQPH) -#define TWL_HOBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDB) -#define TWL_HOBDBC_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HOBDBC) -#define TWL_HIMASK_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIMASK) -#define TWL_HISTAT_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HISTAT) -#define TWL_HIBQPH_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPH) -#define TWL_HIBQPL_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBQPL) -#define TWL_HIBDB_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_HIBDB) -#define TWL_SCRPD3_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + TWL_SCRPD3) -#define TWL_MASK_INTERRUPTS(x) (writel(~0, TWL_HIMASK_REG_ADDR(tw_dev))) -#define TWL_UNMASK_INTERRUPTS(x) (writel(~TWL_HISTATUS_VALID_INTERRUPT, TWL_HIMASK_REG_ADDR(tw_dev))) -#define TWL_CLEAR_DB_INTERRUPT(x) (writel(~0, TWL_HOBDBC_REG_ADDR(tw_dev))) -#define TWL_SOFT_RESET(x) (writel(TWL_ISSUE_SOFT_RESET, TWL_HIBDB_REG_ADDR(tw_dev))) - -/* Macros */ -#define TW_PRINTK(h,a,b,c) { \ -if (h) \ -printk(KERN_WARNING "3w-sas: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \ -else \ -printk(KERN_WARNING "3w-sas: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \ -} -#define TW_MAX_LUNS 16 -#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 6 : 4) -#define TW_LIBERATOR_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 46 : 92) -#define TW_LIBERATOR_MAX_SGL_LENGTH_OLD (sizeof(dma_addr_t) > 4 ? 47 : 94) -#define TW_PADDING_LENGTH_LIBERATOR 136 -#define TW_PADDING_LENGTH_LIBERATOR_OLD 132 -#define TW_CPU_TO_SGL(x) (sizeof(dma_addr_t) > 4 ? cpu_to_le64(x) : cpu_to_le32(x)) - -#pragma pack(1) - -/* SGL entry */ -typedef struct TAG_TW_SG_Entry_ISO { - dma_addr_t address; - dma_addr_t length; -} TW_SG_Entry_ISO; - -/* Old Command Packet with ISO SGL */ -typedef struct TW_Command { - unsigned char opcode__sgloffset; - unsigned char size; - unsigned char request_id; - unsigned char unit__hostid; - /* Second DWORD */ - unsigned char status; - unsigned char flags; - union { - unsigned short block_count; - unsigned short parameter_count; - } byte6_offset; - union { - struct { - u32 lba; - TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD]; - unsigned char padding[TW_PADDING_LENGTH_LIBERATOR_OLD]; - } io; - struct { - TW_SG_Entry_ISO sgl[TW_LIBERATOR_MAX_SGL_LENGTH_OLD]; - u32 padding; - unsigned char padding2[TW_PADDING_LENGTH_LIBERATOR_OLD]; - } param; - } byte8_offset; -} TW_Command; - -/* New Command Packet with ISO SGL */ -typedef struct TAG_TW_Command_Apache { - unsigned char opcode__reserved; - unsigned char unit; - unsigned short request_id__lunl; - unsigned char status; - unsigned char sgl_offset; - unsigned short sgl_entries__lunh; - unsigned char cdb[16]; - TW_SG_Entry_ISO sg_list[TW_LIBERATOR_MAX_SGL_LENGTH]; - unsigned char padding[TW_PADDING_LENGTH_LIBERATOR]; -} TW_Command_Apache; - -/* New command packet header */ -typedef struct TAG_TW_Command_Apache_Header { - unsigned char sense_data[TW_SENSE_DATA_LENGTH]; - struct { - char reserved[4]; - unsigned short error; - unsigned char padding; - unsigned char severity__reserved; - } status_block; - unsigned char err_specific_desc[98]; - struct { - unsigned char size_header; - unsigned short request_id; - unsigned char size_sense; - } header_desc; -} TW_Command_Apache_Header; - -/* This struct is a union of the 2 command packets */ -typedef struct TAG_TW_Command_Full { - TW_Command_Apache_Header header; - union { - TW_Command oldcommand; - TW_Command_Apache newcommand; - } command; -} TW_Command_Full; - -/* Initconnection structure */ -typedef struct TAG_TW_Initconnect { - unsigned char opcode__reserved; - unsigned char size; - unsigned char request_id; - unsigned char res2; - unsigned char status; - unsigned char flags; - unsigned short message_credits; - u32 features; - unsigned short fw_srl; - unsigned short fw_arch_id; - unsigned short fw_branch; - unsigned short fw_build; - u32 result; -} TW_Initconnect; - -/* Event info structure */ -typedef struct TAG_TW_Event -{ - unsigned int sequence_id; - unsigned int time_stamp_sec; - unsigned short aen_code; - unsigned char severity; - unsigned char retrieved; - unsigned char repeat_count; - unsigned char parameter_len; - unsigned char parameter_data[98]; -} TW_Event; - -typedef struct TAG_TW_Ioctl_Driver_Command { - unsigned int control_code; - unsigned int status; - unsigned int unique_id; - unsigned int sequence_id; - unsigned int os_specific; - unsigned int buffer_length; -} TW_Ioctl_Driver_Command; - -typedef struct TAG_TW_Ioctl_Apache { - TW_Ioctl_Driver_Command driver_command; - char padding[488]; - TW_Command_Full firmware_command; - char data_buffer[1]; -} TW_Ioctl_Buf_Apache; - -/* GetParam descriptor */ -typedef struct { - unsigned short table_id; - unsigned short parameter_id; - unsigned short parameter_size_bytes; - unsigned short actual_parameter_size_bytes; - unsigned char data[1]; -} TW_Param_Apache; - -/* Compatibility information structure */ -typedef struct TAG_TW_Compatibility_Info -{ - char driver_version[32]; - unsigned short working_srl; - unsigned short working_branch; - unsigned short working_build; - unsigned short driver_srl_high; - unsigned short driver_branch_high; - unsigned short driver_build_high; - unsigned short driver_srl_low; - unsigned short driver_branch_low; - unsigned short driver_build_low; - unsigned short fw_on_ctlr_srl; - unsigned short fw_on_ctlr_branch; - unsigned short fw_on_ctlr_build; -} TW_Compatibility_Info; - -#pragma pack() - -typedef struct TAG_TW_Device_Extension { - void __iomem *base_addr; - unsigned long *generic_buffer_virt[TW_Q_LENGTH]; - dma_addr_t generic_buffer_phys[TW_Q_LENGTH]; - TW_Command_Full *command_packet_virt[TW_Q_LENGTH]; - dma_addr_t command_packet_phys[TW_Q_LENGTH]; - TW_Command_Apache_Header *sense_buffer_virt[TW_Q_LENGTH]; - dma_addr_t sense_buffer_phys[TW_Q_LENGTH]; - struct pci_dev *tw_pci_dev; - struct scsi_cmnd *srb[TW_Q_LENGTH]; - unsigned char free_queue[TW_Q_LENGTH]; - unsigned char free_head; - unsigned char free_tail; - int state[TW_Q_LENGTH]; - unsigned int posted_request_count; - unsigned int max_posted_request_count; - unsigned int max_sgl_entries; - unsigned int sgl_entries; - unsigned int num_resets; - unsigned int sector_count; - unsigned int max_sector_count; - unsigned int aen_count; - struct Scsi_Host *host; - long flags; - TW_Event *event_queue[TW_Q_LENGTH]; - unsigned char error_index; - unsigned int error_sequence_id; - int chrdev_request_id; - wait_queue_head_t ioctl_wqueue; - struct mutex ioctl_lock; - TW_Compatibility_Info tw_compat_info; - char online; -} TW_Device_Extension; - -#endif /* _3W_SAS_H */ - diff --git a/ANDROID_3.4.5/drivers/scsi/3w-xxxx.c b/ANDROID_3.4.5/drivers/scsi/3w-xxxx.c deleted file mode 100644 index 7fe96ff6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/3w-xxxx.c +++ /dev/null @@ -1,2459 +0,0 @@ -/* - 3w-xxxx.c -- 3ware Storage Controller device driver for Linux. - - Written By: Adam Radford - Modifications By: Joel Jacobson - Arnaldo Carvalho de Melo - Brad Strand - - Copyright (C) 1999-2010 3ware Inc. - - Kernel compatibility By: Andre Hedrick - Non-Copyright (C) 2000 Andre Hedrick - - Further tiny build fixes and trivial hoovering Alan Cox - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - NO WARRANTY - THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - DISCLAIMER OF LIABILITY - NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com - - History - ------- - 0.1.000 - Initial release. - 0.4.000 - Added support for Asynchronous Event Notification through - ioctls for 3DM. - 1.0.000 - Added DPO & FUA bit support for WRITE_10 & WRITE_6 cdb - to disable drive write-cache before writes. - 1.1.000 - Fixed performance bug with DPO & FUA not existing for WRITE_6. - 1.2.000 - Added support for clean shutdown notification/feature table. - 1.02.00.001 - Added support for full command packet posts through ioctls - for 3DM. - Bug fix so hot spare drives don't show up. - 1.02.00.002 - Fix bug with tw_setfeature() call that caused oops on some - systems. - 08/21/00 - release previously allocated resources on failure at - tw_allocate_memory (acme) - 1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when - controller status is non-zero. - Added handling of request_sense opcode. - Fix possible null pointer dereference in - tw_reset_device_extension() - 1.02.00.004 - Add support for device id of 3ware 7000 series controllers. - Make tw_setfeature() call with interrupts disabled. - Register interrupt handler before enabling interrupts. - Clear attention interrupt before draining aen queue. - 1.02.00.005 - Allocate bounce buffers and custom queue depth for raid5 for - 6000 and 5000 series controllers. - Reduce polling mdelays causing problems on some systems. - Fix use_sg = 1 calculation bug. - Check for scsi_register returning NULL. - Add aen count to /proc/scsi/3w-xxxx. - Remove aen code unit masking in tw_aen_complete(). - 1.02.00.006 - Remove unit from printk in tw_scsi_eh_abort(), causing - possible oops. - Fix possible null pointer dereference in tw_scsi_queue() - if done function pointer was invalid. - 1.02.00.007 - Fix possible null pointer dereferences in tw_ioctl(). - Remove check for invalid done function pointer from - tw_scsi_queue(). - 1.02.00.008 - Set max sectors per io to TW_MAX_SECTORS in tw_findcards(). - Add tw_decode_error() for printing readable error messages. - Print some useful information on certain aen codes. - Add tw_decode_bits() for interpreting status register output. - Make scsi_set_pci_device() for kernels >= 2.4.4 - Fix bug where aen's could be lost before a reset. - Re-add spinlocks in tw_scsi_detect(). - Fix possible null pointer dereference in tw_aen_drain_queue() - during initialization. - Clear pci parity errors during initialization and during io. - 1.02.00.009 - Remove redundant increment in tw_state_request_start(). - Add ioctl support for direct ATA command passthru. - Add entire aen code string list. - 1.02.00.010 - Cleanup queueing code, fix jbod thoughput. - Fix get_param for specific units. - 1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost. - Fix tw_aen_drain_queue() to display useful info at init. - Set tw_host->max_id for 12 port cards. - Add ioctl support for raw command packet post from userspace - with sglist fragments (parameter and io). - 1.02.00.012 - Fix read capacity to under report by 1 sector to fix get - last sector ioctl. - 1.02.00.013 - Fix bug where more AEN codes weren't coming out during - driver initialization. - Improved handling of PCI aborts. - 1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost. - Increase timeout in tw_aen_drain_queue() to 30 seconds. - 1.02.00.015 - Re-write raw command post with data ioctl method. - Remove raid5 bounce buffers for raid5 for 6XXX for kernel 2.5 - Add tw_map/unmap_scsi_sg/single_data() for kernel 2.5 - Replace io_request_lock with host_lock for kernel 2.5 - Set max_cmd_len to 16 for 3dm for kernel 2.5 - 1.02.00.016 - Set host->max_sectors back up to 256. - 1.02.00.017 - Modified pci parity error handling/clearing from config space - during initialization. - 1.02.00.018 - Better handling of request sense opcode and sense information - for failed commands. Add tw_decode_sense(). - Replace all mdelay()'s with scsi_sleep(). - 1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on - some SMP systems. - 1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to - pci_alloc/free_consistent(). - Better alignment checking in tw_allocate_memory(). - Cleanup tw_initialize_device_extension(). - 1.02.00.021 - Bump cmd_per_lun in SHT to 255 for better jbod performance. - Improve handling of errors in tw_interrupt(). - Add handling/clearing of controller queue error. - Empty stale responses before draining aen queue. - Fix tw_scsi_eh_abort() to not reset on every io abort. - Set can_queue in SHT to 255 to prevent hang from AEN. - 1.02.00.022 - Fix possible null pointer dereference in tw_scsi_release(). - 1.02.00.023 - Fix bug in tw_aen_drain_queue() where unit # was always zero. - 1.02.00.024 - Add severity levels to AEN strings. - 1.02.00.025 - Fix command interrupt spurious error messages. - Fix bug in raw command post with data ioctl method. - Fix bug where rollcall sometimes failed with cable errors. - Print unit # on all command timeouts. - 1.02.00.026 - Fix possible infinite retry bug with power glitch induced - drive timeouts. - Cleanup some AEN severity levels. - 1.02.00.027 - Add drive not supported AEN code for SATA controllers. - Remove spurious unknown ioctl error message. - 1.02.00.028 - Fix bug where multiple controllers with no units were the - same card number. - Fix bug where cards were being shut down more than once. - 1.02.00.029 - Add missing pci_free_consistent() in tw_allocate_memory(). - Replace pci_map_single() with pci_map_page() for highmem. - Check for tw_setfeature() failure. - 1.02.00.030 - Make driver 64-bit clean. - 1.02.00.031 - Cleanup polling timeouts/routines in several places. - Add support for mode sense opcode. - Add support for cache mode page. - Add support for synchronize cache opcode. - 1.02.00.032 - Fix small multicard rollcall bug. - Make driver stay loaded with no units for hot add/swap. - Add support for "twe" character device for ioctls. - Clean up request_id queueing code. - Fix tw_scsi_queue() spinlocks. - 1.02.00.033 - Fix tw_aen_complete() to not queue 'queue empty' AEN's. - Initialize queues correctly when loading with no valid units. - 1.02.00.034 - Fix tw_decode_bits() to handle multiple errors. - Add support for user configurable cmd_per_lun. - Add support for sht->slave_configure(). - 1.02.00.035 - Improve tw_allocate_memory() memory allocation. - Fix tw_chrdev_ioctl() to sleep correctly. - 1.02.00.036 - Increase character ioctl timeout to 60 seconds. - 1.02.00.037 - Fix tw_ioctl() to handle all non-data ATA passthru cmds - for 'smartmontools' support. - 1.26.00.038 - Roll driver minor version to 26 to denote kernel 2.6. - Add support for cmds_per_lun module parameter. - 1.26.00.039 - Fix bug in tw_chrdev_ioctl() polling code. - Fix data_buffer_length usage in tw_chrdev_ioctl(). - Update contact information. - 1.26.02.000 - Convert driver to pci_driver format. - 1.26.02.001 - Increase max ioctl buffer size to 512 sectors. - Make tw_scsi_queue() return 0 for 'Unknown scsi opcode'. - Fix tw_remove() to free irq handler/unregister_chrdev() - before shutting down card. - Change to new 'change_queue_depth' api. - Fix 'handled=1' ISR usage, remove bogus IRQ check. - 1.26.02.002 - Free irq handler in __tw_shutdown(). - Turn on RCD bit for caching mode page. - Serialize reset code. - 1.26.02.003 - Force 60 second timeout default. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "3w-xxxx.h" - -/* Globals */ -#define TW_DRIVER_VERSION "1.26.02.003" -static DEFINE_MUTEX(tw_mutex); -static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; -static int tw_device_extension_count = 0; -static int twe_major = -1; - -/* Module parameters */ -MODULE_AUTHOR("LSI"); -MODULE_DESCRIPTION("3ware Storage Controller Linux Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(TW_DRIVER_VERSION); - -/* Function prototypes */ -static int tw_reset_device_extension(TW_Device_Extension *tw_dev); - -/* Functions */ - -/* This function will check the status register for unexpected bits */ -static int tw_check_bits(u32 status_reg_value) -{ - if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) { - dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value); - return 1; - } - if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) { - dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value); - return 1; - } - - return 0; -} /* End tw_check_bits() */ - -/* This function will print readable messages from status register errors */ -static int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host) -{ - char host[16]; - - dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n"); - - if (print_host) - sprintf(host, " scsi%d:", tw_dev->host->host_no); - else - host[0] = '\0'; - - if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) { - printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host); - outl(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); - } - - if (status_reg_value & TW_STATUS_PCI_ABORT) { - printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host); - outl(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev)); - pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); - } - - if (status_reg_value & TW_STATUS_QUEUE_ERROR) { - printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host); - outl(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); - } - - if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) { - printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host); - outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev)); - } - - if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) { - if (tw_dev->reset_print == 0) { - printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host); - tw_dev->reset_print = 1; - } - return 1; - } - - return 0; -} /* End tw_decode_bits() */ - -/* This function will poll the status register for a flag */ -static int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds) -{ - u32 status_reg_value; - unsigned long before; - int retval = 1; - - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - before = jiffies; - - if (tw_check_bits(status_reg_value)) - tw_decode_bits(tw_dev, status_reg_value, 0); - - while ((status_reg_value & flag) != flag) { - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - - if (tw_check_bits(status_reg_value)) - tw_decode_bits(tw_dev, status_reg_value, 0); - - if (time_after(jiffies, before + HZ * seconds)) - goto out; - - msleep(50); - } - retval = 0; -out: - return retval; -} /* End tw_poll_status() */ - -/* This function will poll the status register for disappearance of a flag */ -static int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds) -{ - u32 status_reg_value; - unsigned long before; - int retval = 1; - - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - before = jiffies; - - if (tw_check_bits(status_reg_value)) - tw_decode_bits(tw_dev, status_reg_value, 0); - - while ((status_reg_value & flag) != 0) { - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - - if (tw_check_bits(status_reg_value)) - tw_decode_bits(tw_dev, status_reg_value, 0); - - if (time_after(jiffies, before + HZ * seconds)) - goto out; - - msleep(50); - } - retval = 0; -out: - return retval; -} /* End tw_poll_status_gone() */ - -/* This function will attempt to post a command packet to the board */ -static int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id) -{ - u32 status_reg_value; - unsigned long command_que_value; - - dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n"); - command_que_value = tw_dev->command_packet_physical_address[request_id]; - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value, 1); - } - - if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { - /* We successfully posted the command packet */ - outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); - tw_dev->state[request_id] = TW_S_POSTED; - tw_dev->posted_request_count++; - if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) { - tw_dev->max_posted_request_count = tw_dev->posted_request_count; - } - } else { - /* Couldn't post the command packet, so we do it in the isr */ - if (tw_dev->state[request_id] != TW_S_PENDING) { - tw_dev->state[request_id] = TW_S_PENDING; - tw_dev->pending_request_count++; - if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) { - tw_dev->max_pending_request_count = tw_dev->pending_request_count; - } - tw_dev->pending_queue[tw_dev->pending_tail] = request_id; - if (tw_dev->pending_tail == TW_Q_LENGTH-1) { - tw_dev->pending_tail = TW_Q_START; - } else { - tw_dev->pending_tail = tw_dev->pending_tail + 1; - } - } - TW_UNMASK_COMMAND_INTERRUPT(tw_dev); - return 1; - } - return 0; -} /* End tw_post_command_packet() */ - -/* This function will return valid sense buffer information for failed cmds */ -static int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense) -{ - int i; - TW_Command *command; - - dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n"); - command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - - printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, TW_UNIT_OUT(command->unit__hostid)); - - /* Attempt to return intelligent sense information */ - if (fill_sense) { - if ((command->status == 0xc7) || (command->status == 0xcb)) { - for (i = 0; i < ARRAY_SIZE(tw_sense_table); i++) { - if (command->flags == tw_sense_table[i][0]) { - - /* Valid bit and 'current errors' */ - tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70); - - /* Sense key */ - tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1]; - - /* Additional sense length */ - tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */ - - /* Additional sense code */ - tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2]; - - /* Additional sense code qualifier */ - tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3]; - - tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */ - } - } - } - - /* If no table match, error so we get a reset */ - return 1; - } - - return 0; -} /* End tw_decode_sense() */ - -/* This function will report controller error status */ -static int tw_check_errors(TW_Device_Extension *tw_dev) -{ - u32 status_reg_value; - - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - - if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) { - tw_decode_bits(tw_dev, status_reg_value, 0); - return 1; - } - - return 0; -} /* End tw_check_errors() */ - -/* This function will empty the response que */ -static void tw_empty_response_que(TW_Device_Extension *tw_dev) -{ - u32 status_reg_value, response_que_value; - - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - - while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { - response_que_value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - } -} /* End tw_empty_response_que() */ - -/* This function will free a request_id */ -static void tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id) -{ - tw_dev->free_queue[tw_dev->free_tail] = request_id; - tw_dev->state[request_id] = TW_S_FINISHED; - tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH; -} /* End tw_state_request_finish() */ - -/* This function will assign an available request_id */ -static void tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id) -{ - *request_id = tw_dev->free_queue[tw_dev->free_head]; - tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH; - tw_dev->state[*request_id] = TW_S_STARTED; -} /* End tw_state_request_start() */ - -/* Show some statistics about the card */ -static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - unsigned long flags = 0; - ssize_t len; - - spin_lock_irqsave(tw_dev->host->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "3w-xxxx Driver version: %s\n" - "Current commands posted: %4d\n" - "Max commands posted: %4d\n" - "Current pending commands: %4d\n" - "Max pending commands: %4d\n" - "Last sgl length: %4d\n" - "Max sgl length: %4d\n" - "Last sector count: %4d\n" - "Max sector count: %4d\n" - "SCSI Host Resets: %4d\n" - "AEN's: %4d\n", - TW_DRIVER_VERSION, - tw_dev->posted_request_count, - tw_dev->max_posted_request_count, - tw_dev->pending_request_count, - tw_dev->max_pending_request_count, - tw_dev->sgl_entries, - tw_dev->max_sgl_entries, - tw_dev->sector_count, - tw_dev->max_sector_count, - tw_dev->num_resets, - tw_dev->aen_count); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - return len; -} /* End tw_show_stats() */ - -/* This function will set a devices queue depth */ -static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (queue_depth > TW_Q_LENGTH-2) - queue_depth = TW_Q_LENGTH-2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); - return queue_depth; -} /* End tw_change_queue_depth() */ - -/* Create sysfs 'stats' entry */ -static struct device_attribute tw_host_stats_attr = { - .attr = { - .name = "stats", - .mode = S_IRUGO, - }, - .show = tw_show_stats -}; - -/* Host attributes initializer */ -static struct device_attribute *tw_host_attrs[] = { - &tw_host_stats_attr, - NULL, -}; - -/* This function will read the aen queue from the isr */ -static int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Command *command_packet; - TW_Param *param; - unsigned long command_que_value; - u32 status_reg_value; - unsigned long param_value = 0; - - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n"); - - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value, 1); - return 1; - } - if (tw_dev->command_packet_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet virtual address.\n"); - return 1; - } - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - memset(command_packet, 0, sizeof(TW_Sector)); - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = 4; - command_packet->request_id = request_id; - command_packet->status = 0; - command_packet->flags = 0; - command_packet->byte6.parameter_count = 1; - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet physical address.\n"); - return 1; - } - /* Now setup the param */ - if (tw_dev->alignment_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment virtual address.\n"); - return 1; - } - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - memset(param, 0, sizeof(TW_Sector)); - param->table_id = 0x401; /* AEN table */ - param->parameter_id = 2; /* Unit code */ - param->parameter_size_bytes = 2; - param_value = tw_dev->alignment_physical_address[request_id]; - if (param_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment physical address.\n"); - return 1; - } - command_packet->byte8.param.sgl[0].address = param_value; - command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); - - /* Now post the command packet */ - if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { - dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n"); - tw_dev->srb[request_id] = NULL; /* Flag internal command */ - tw_dev->state[request_id] = TW_S_POSTED; - outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); - } else { - printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post failed, will retry.\n"); - return 1; - } - - return 0; -} /* End tw_aen_read_queue() */ - -/* This function will complete an aen request from the isr */ -static int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Param *param; - unsigned short aen; - int error = 0, table_max = 0; - - dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n"); - if (tw_dev->alignment_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n"); - return 1; - } - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - aen = *(unsigned short *)(param->data); - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen); - - /* Print some useful info when certain aen codes come out */ - if (aen == 0x0ff) { - printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no); - } else { - table_max = ARRAY_SIZE(tw_aen_string); - if ((aen & 0x0ff) < table_max) { - if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { - printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8); - } else { - if (aen != 0x0) - printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]); - } - } else { - printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen); - } - } - if (aen != TW_AEN_QUEUE_EMPTY) { - tw_dev->aen_count++; - - /* Now queue the code */ - tw_dev->aen_queue[tw_dev->aen_tail] = aen; - if (tw_dev->aen_tail == TW_Q_LENGTH - 1) { - tw_dev->aen_tail = TW_Q_START; - } else { - tw_dev->aen_tail = tw_dev->aen_tail + 1; - } - if (tw_dev->aen_head == tw_dev->aen_tail) { - if (tw_dev->aen_head == TW_Q_LENGTH - 1) { - tw_dev->aen_head = TW_Q_START; - } else { - tw_dev->aen_head = tw_dev->aen_head + 1; - } - } - - error = tw_aen_read_queue(tw_dev, request_id); - if (error) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no); - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - } - } else { - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - } - - return 0; -} /* End tw_aen_complete() */ - -/* This function will drain the aen queue after a soft reset */ -static int tw_aen_drain_queue(TW_Device_Extension *tw_dev) -{ - TW_Command *command_packet; - TW_Param *param; - int request_id = 0; - unsigned long command_que_value; - unsigned long param_value; - TW_Response_Queue response_queue; - unsigned short aen; - unsigned short aen_code; - int finished = 0; - int first_reset = 0; - int queue = 0; - int found = 0, table_max = 0; - - dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n"); - - if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) { - dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count); - return 1; - } - TW_CLEAR_ATTENTION_INTERRUPT(tw_dev); - - /* Empty response queue */ - tw_empty_response_que(tw_dev); - - /* Initialize command packet */ - if (tw_dev->command_packet_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n"); - return 1; - } - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - memset(command_packet, 0, sizeof(TW_Sector)); - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = 4; - command_packet->request_id = request_id; - command_packet->status = 0; - command_packet->flags = 0; - command_packet->byte6.parameter_count = 1; - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet physical address.\n"); - return 1; - } - - /* Now setup the param */ - if (tw_dev->alignment_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment virtual address.\n"); - return 1; - } - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - memset(param, 0, sizeof(TW_Sector)); - param->table_id = 0x401; /* AEN table */ - param->parameter_id = 2; /* Unit code */ - param->parameter_size_bytes = 2; - param_value = tw_dev->alignment_physical_address[request_id]; - if (param_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment physical address.\n"); - return 1; - } - command_packet->byte8.param.sgl[0].address = param_value; - command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); - - /* Now drain the controller's aen queue */ - do { - /* Post command packet */ - outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); - - /* Now poll for completion */ - if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) { - response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); - request_id = TW_RESID_OUT(response_queue.response_id); - - if (request_id != 0) { - /* Unexpected request id */ - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n"); - return 1; - } - - if (command_packet->status != 0) { - if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) { - /* Bad response */ - tw_decode_sense(tw_dev, request_id, 0); - return 1; - } else { - /* We know this is a 3w-1x00, and doesn't support aen's */ - return 0; - } - } - - /* Now check the aen */ - aen = *(unsigned short *)(param->data); - aen_code = (aen & 0x0ff); - queue = 0; - switch (aen_code) { - case TW_AEN_QUEUE_EMPTY: - dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); - if (first_reset != 1) { - return 1; - } else { - finished = 1; - } - break; - case TW_AEN_SOFT_RESET: - if (first_reset == 0) { - first_reset = 1; - } else { - printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); - tw_dev->aen_count++; - queue = 1; - } - break; - default: - if (aen == 0x0ff) { - printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n"); - } else { - table_max = ARRAY_SIZE(tw_aen_string); - if ((aen & 0x0ff) < table_max) { - if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') { - printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8); - } else { - printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]); - } - } else - printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen); - } - tw_dev->aen_count++; - queue = 1; - } - - /* Now put the aen on the aen_queue */ - if (queue == 1) { - tw_dev->aen_queue[tw_dev->aen_tail] = aen; - if (tw_dev->aen_tail == TW_Q_LENGTH - 1) { - tw_dev->aen_tail = TW_Q_START; - } else { - tw_dev->aen_tail = tw_dev->aen_tail + 1; - } - if (tw_dev->aen_head == tw_dev->aen_tail) { - if (tw_dev->aen_head == TW_Q_LENGTH - 1) { - tw_dev->aen_head = TW_Q_START; - } else { - tw_dev->aen_head = tw_dev->aen_head + 1; - } - } - } - found = 1; - } - if (found == 0) { - printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n"); - return 1; - } - } while (finished == 0); - - return 0; -} /* End tw_aen_drain_queue() */ - -/* This function will allocate memory */ -static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which) -{ - int i; - dma_addr_t dma_handle; - unsigned long *cpu_addr = NULL; - - dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n"); - - cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle); - if (cpu_addr == NULL) { - printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n"); - return 1; - } - - if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) { - printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n"); - pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle); - return 1; - } - - memset(cpu_addr, 0, size*TW_Q_LENGTH); - - for (i=0;icommand_packet_physical_address[i] = dma_handle+(i*size); - tw_dev->command_packet_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); - break; - case 1: - tw_dev->alignment_physical_address[i] = dma_handle+(i*size); - tw_dev->alignment_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size)); - break; - default: - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n"); - return 1; - } - } - - return 0; -} /* End tw_allocate_memory() */ - -/* This function handles ioctl for the character device */ -static long tw_chrdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - int request_id; - dma_addr_t dma_handle; - unsigned short tw_aen_code; - unsigned long flags; - unsigned int data_buffer_length = 0; - unsigned long data_buffer_length_adjusted = 0; - struct inode *inode = file->f_dentry->d_inode; - unsigned long *cpu_addr; - long timeout; - TW_New_Ioctl *tw_ioctl; - TW_Passthru *passthru; - TW_Device_Extension *tw_dev = tw_device_extension_list[iminor(inode)]; - int retval = -EFAULT; - void __user *argp = (void __user *)arg; - - dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n"); - - mutex_lock(&tw_mutex); - /* Only let one of these through at a time */ - if (mutex_lock_interruptible(&tw_dev->ioctl_lock)) { - mutex_unlock(&tw_mutex); - return -EINTR; - } - - /* First copy down the buffer length */ - if (copy_from_user(&data_buffer_length, argp, sizeof(unsigned int))) - goto out; - - /* Check size */ - if (data_buffer_length > TW_MAX_IOCTL_SECTORS * 512) { - retval = -EINVAL; - goto out; - } - - /* Hardware can only do multiple of 512 byte transfers */ - data_buffer_length_adjusted = (data_buffer_length + 511) & ~511; - - /* Now allocate ioctl buf memory */ - cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle, GFP_KERNEL); - if (cpu_addr == NULL) { - retval = -ENOMEM; - goto out; - } - - tw_ioctl = (TW_New_Ioctl *)cpu_addr; - - /* Now copy down the entire ioctl */ - if (copy_from_user(tw_ioctl, argp, data_buffer_length + sizeof(TW_New_Ioctl) - 1)) - goto out2; - - passthru = (TW_Passthru *)&tw_ioctl->firmware_command; - - /* See which ioctl we are doing */ - switch (cmd) { - case TW_OP_NOP: - dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_OP_NOP.\n"); - break; - case TW_OP_AEN_LISTEN: - dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n"); - memset(tw_ioctl->data_buffer, 0, data_buffer_length); - - spin_lock_irqsave(tw_dev->host->host_lock, flags); - if (tw_dev->aen_head == tw_dev->aen_tail) { - tw_aen_code = TW_AEN_QUEUE_EMPTY; - } else { - tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head]; - if (tw_dev->aen_head == TW_Q_LENGTH - 1) { - tw_dev->aen_head = TW_Q_START; - } else { - tw_dev->aen_head = tw_dev->aen_head + 1; - } - } - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code)); - break; - case TW_CMD_PACKET_WITH_DATA: - dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n"); - spin_lock_irqsave(tw_dev->host->host_lock, flags); - - tw_state_request_start(tw_dev, &request_id); - - /* Flag internal command */ - tw_dev->srb[request_id] = NULL; - - /* Flag chrdev ioctl */ - tw_dev->chrdev_request_id = request_id; - - tw_ioctl->firmware_command.request_id = request_id; - - /* Load the sg list */ - switch (TW_SGL_OUT(tw_ioctl->firmware_command.opcode__sgloffset)) { - case 2: - tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; - tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted; - break; - case 3: - tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; - tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted; - break; - case 5: - passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1; - passthru->sg_list[0].length = data_buffer_length_adjusted; - break; - } - - memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command)); - - /* Now post the command packet to the controller */ - tw_post_command_packet(tw_dev, request_id); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - - timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ; - - /* Now wait for the command to complete */ - timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout); - - /* We timed out, and didn't get an interrupt */ - if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) { - /* Now we need to reset the board */ - printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd); - retval = -EIO; - if (tw_reset_device_extension(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no); - } - goto out2; - } - - /* Now copy in the command packet response */ - memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command)); - - /* Now complete the io */ - spin_lock_irqsave(tw_dev->host->host_lock, flags); - tw_dev->posted_request_count--; - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - break; - default: - retval = -ENOTTY; - goto out2; - } - - /* Now copy the response to userspace */ - if (copy_to_user(argp, tw_ioctl, sizeof(TW_New_Ioctl) + data_buffer_length - 1)) - goto out2; - retval = 0; -out2: - /* Now free ioctl buf memory */ - dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle); -out: - mutex_unlock(&tw_dev->ioctl_lock); - mutex_unlock(&tw_mutex); - return retval; -} /* End tw_chrdev_ioctl() */ - -/* This function handles open for the character device */ -/* NOTE that this function races with remove. */ -static int tw_chrdev_open(struct inode *inode, struct file *file) -{ - unsigned int minor_number; - - dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n"); - - minor_number = iminor(inode); - if (minor_number >= tw_device_extension_count) - return -ENODEV; - - return 0; -} /* End tw_chrdev_open() */ - -/* File operations struct for character device */ -static const struct file_operations tw_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = tw_chrdev_ioctl, - .open = tw_chrdev_open, - .release = NULL, - .llseek = noop_llseek, -}; - -/* This function will free up device extension resources */ -static void tw_free_device_extension(TW_Device_Extension *tw_dev) -{ - dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n"); - - /* Free command packet and generic buffer memory */ - if (tw_dev->command_packet_virtual_address[0]) - pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]); - - if (tw_dev->alignment_virtual_address[0]) - pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]); -} /* End tw_free_device_extension() */ - -/* This function will send an initconnection command to controller */ -static int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) -{ - unsigned long command_que_value; - TW_Command *command_packet; - TW_Response_Queue response_queue; - int request_id = 0; - - dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n"); - - /* Initialize InitConnection command packet */ - if (tw_dev->command_packet_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet virtual address.\n"); - return 1; - } - - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - memset(command_packet, 0, sizeof(TW_Sector)); - command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_INIT_CONNECTION); - command_packet->size = TW_INIT_COMMAND_PACKET_SIZE; - command_packet->request_id = request_id; - command_packet->status = 0x0; - command_packet->flags = 0x0; - command_packet->byte6.message_credits = message_credits; - command_packet->byte8.init_connection.response_queue_pointer = 0x0; - command_que_value = tw_dev->command_packet_physical_address[request_id]; - - if (command_que_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet physical address.\n"); - return 1; - } - - /* Send command packet to the board */ - outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); - - /* Poll for completion */ - if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) { - response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); - request_id = TW_RESID_OUT(response_queue.response_id); - - if (request_id != 0) { - /* unexpected request id */ - printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n"); - return 1; - } - if (command_packet->status != 0) { - /* bad response */ - tw_decode_sense(tw_dev, request_id, 0); - return 1; - } - } - return 0; -} /* End tw_initconnection() */ - -/* Set a value in the features table */ -static int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, - unsigned char *val) -{ - TW_Param *param; - TW_Command *command_packet; - TW_Response_Queue response_queue; - int request_id = 0; - unsigned long command_que_value; - unsigned long param_value; - - /* Initialize SetParam command packet */ - if (tw_dev->command_packet_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet virtual address.\n"); - return 1; - } - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - memset(command_packet, 0, sizeof(TW_Sector)); - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM); - param->table_id = 0x404; /* Features table */ - param->parameter_id = parm; - param->parameter_size_bytes = param_size; - memcpy(param->data, val, param_size); - - param_value = tw_dev->alignment_physical_address[request_id]; - if (param_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad alignment physical address.\n"); - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - tw_dev->srb[request_id]->result = (DID_OK << 16); - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - } - command_packet->byte8.param.sgl[0].address = param_value; - command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); - - command_packet->size = 4; - command_packet->request_id = request_id; - command_packet->byte6.parameter_count = 1; - - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet physical address.\n"); - return 1; - } - - /* Send command packet to the board */ - outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev)); - - /* Poll for completion */ - if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) { - response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); - request_id = TW_RESID_OUT(response_queue.response_id); - - if (request_id != 0) { - /* unexpected request id */ - printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n"); - return 1; - } - if (command_packet->status != 0) { - /* bad response */ - tw_decode_sense(tw_dev, request_id, 0); - return 1; - } - } - - return 0; -} /* End tw_setfeature() */ - -/* This function will reset a controller */ -static int tw_reset_sequence(TW_Device_Extension *tw_dev) -{ - int error = 0; - int tries = 0; - unsigned char c = 1; - - /* Reset the board */ - while (tries < TW_MAX_RESET_TRIES) { - TW_SOFT_RESET(tw_dev); - - error = tw_aen_drain_queue(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no); - tries++; - continue; - } - - /* Check for controller errors */ - if (tw_check_errors(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no); - tries++; - continue; - } - - /* Now the controller is in a good state */ - break; - } - - if (tries >= TW_MAX_RESET_TRIES) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no); - return 1; - } - - error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS); - if (error) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no); - return 1; - } - - error = tw_setfeature(tw_dev, 2, 1, &c); - if (error) { - printk(KERN_WARNING "3w-xxxx: Unable to set features for card, probable old firmware or card.\n"); - } - - return 0; -} /* End tw_reset_sequence() */ - -/* This function will initialize the fields of a device extension */ -static int tw_initialize_device_extension(TW_Device_Extension *tw_dev) -{ - int i, error=0; - - dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n"); - - /* Initialize command packet buffers */ - error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0); - if (error) { - printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n"); - return 1; - } - - /* Initialize generic buffer */ - error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1); - if (error) { - printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n"); - return 1; - } - - for (i=0;ifree_queue[i] = i; - tw_dev->state[i] = TW_S_INITIAL; - } - - tw_dev->pending_head = TW_Q_START; - tw_dev->pending_tail = TW_Q_START; - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - - mutex_init(&tw_dev->ioctl_lock); - init_waitqueue_head(&tw_dev->ioctl_wqueue); - - return 0; -} /* End tw_initialize_device_extension() */ - -static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) -{ - int use_sg; - - dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n"); - - use_sg = scsi_dma_map(cmd); - if (use_sg < 0) { - printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n"); - return 0; - } - - cmd->SCp.phase = TW_PHASE_SGLIST; - cmd->SCp.have_data_in = use_sg; - - return use_sg; -} /* End tw_map_scsi_sg_data() */ - -static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) -{ - dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n"); - - if (cmd->SCp.phase == TW_PHASE_SGLIST) - scsi_dma_unmap(cmd); -} /* End tw_unmap_scsi_data() */ - -/* This function will reset a device extension */ -static int tw_reset_device_extension(TW_Device_Extension *tw_dev) -{ - int i = 0; - struct scsi_cmnd *srb; - unsigned long flags = 0; - - dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n"); - - set_bit(TW_IN_RESET, &tw_dev->flags); - TW_DISABLE_INTERRUPTS(tw_dev); - TW_MASK_COMMAND_INTERRUPT(tw_dev); - spin_lock_irqsave(tw_dev->host->host_lock, flags); - - /* Abort all requests that are in progress */ - for (i=0;istate[i] != TW_S_FINISHED) && - (tw_dev->state[i] != TW_S_INITIAL) && - (tw_dev->state[i] != TW_S_COMPLETED)) { - srb = tw_dev->srb[i]; - if (srb != NULL) { - srb->result = (DID_RESET << 16); - tw_dev->srb[i]->scsi_done(tw_dev->srb[i]); - tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]); - } - } - } - - /* Reset queues and counts */ - for (i=0;ifree_queue[i] = i; - tw_dev->state[i] = TW_S_INITIAL; - } - tw_dev->free_head = TW_Q_START; - tw_dev->free_tail = TW_Q_START; - tw_dev->posted_request_count = 0; - tw_dev->pending_request_count = 0; - tw_dev->pending_head = TW_Q_START; - tw_dev->pending_tail = TW_Q_START; - tw_dev->reset_print = 0; - - spin_unlock_irqrestore(tw_dev->host->host_lock, flags); - - if (tw_reset_sequence(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no); - return 1; - } - - TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); - clear_bit(TW_IN_RESET, &tw_dev->flags); - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - - return 0; -} /* End tw_reset_device_extension() */ - -/* This funciton returns unit geometry in cylinders/heads/sectors */ -static int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - int heads, sectors, cylinders; - TW_Device_Extension *tw_dev; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n"); - tw_dev = (TW_Device_Extension *)sdev->host->hostdata; - - heads = 64; - sectors = 32; - cylinders = sector_div(capacity, heads * sectors); - - if (capacity >= 0x200000) { - heads = 255; - sectors = 63; - cylinders = sector_div(capacity, heads * sectors); - } - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders); - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return 0; -} /* End tw_scsi_biosparam() */ - -/* This is the new scsi eh reset function */ -static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt) -{ - TW_Device_Extension *tw_dev=NULL; - int retval = FAILED; - - tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; - - tw_dev->num_resets++; - - sdev_printk(KERN_WARNING, SCpnt->device, - "WARNING: Command (0x%x) timed out, resetting card.\n", - SCpnt->cmnd[0]); - - /* Make sure we are not issuing an ioctl or resetting from ioctl */ - mutex_lock(&tw_dev->ioctl_lock); - - /* Now reset the card and some of the device extension data */ - if (tw_reset_device_extension(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no); - goto out; - } - - retval = SUCCESS; -out: - mutex_unlock(&tw_dev->ioctl_lock); - return retval; -} /* End tw_scsi_eh_reset() */ - -/* This function handles scsi inquiry commands */ -static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Param *param; - TW_Command *command_packet; - unsigned long command_que_value; - unsigned long param_value; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n"); - - /* Initialize command packet */ - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - if (command_packet == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet virtual address.\n"); - return 1; - } - memset(command_packet, 0, sizeof(TW_Sector)); - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = 4; - command_packet->request_id = request_id; - command_packet->status = 0; - command_packet->flags = 0; - command_packet->byte6.parameter_count = 1; - - /* Now setup the param */ - if (tw_dev->alignment_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment virtual address.\n"); - return 1; - } - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - memset(param, 0, sizeof(TW_Sector)); - param->table_id = 3; /* unit summary table */ - param->parameter_id = 3; /* unitsstatus parameter */ - param->parameter_size_bytes = TW_MAX_UNITS; - param_value = tw_dev->alignment_physical_address[request_id]; - if (param_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment physical address.\n"); - return 1; - } - - command_packet->byte8.param.sgl[0].address = param_value; - command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet physical address.\n"); - return 1; - } - - /* Now try to post the command packet */ - tw_post_command_packet(tw_dev, request_id); - - return 0; -} /* End tw_scsiop_inquiry() */ - -static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id, - void *data, unsigned int len) -{ - scsi_sg_copy_from_buffer(tw_dev->srb[request_id], data, len); -} - -/* This function is called by the isr to complete an inquiry command */ -static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id) -{ - unsigned char *is_unit_present; - unsigned char request_buffer[36]; - TW_Param *param; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n"); - - memset(request_buffer, 0, sizeof(request_buffer)); - request_buffer[0] = TYPE_DISK; /* Peripheral device type */ - request_buffer[1] = 0; /* Device type modifier */ - request_buffer[2] = 0; /* No ansi/iso compliance */ - request_buffer[4] = 31; /* Additional length */ - memcpy(&request_buffer[8], "3ware ", 8); /* Vendor ID */ - sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id); - memcpy(&request_buffer[32], TW_DRIVER_VERSION, 3); - tw_transfer_internal(tw_dev, request_id, request_buffer, - sizeof(request_buffer)); - - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - if (param == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Bad alignment virtual address.\n"); - return 1; - } - is_unit_present = &(param->data[0]); - - if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) { - tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1; - } else { - tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0; - tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); - return TW_ISR_DONT_RESULT; - } - - return 0; -} /* End tw_scsiop_inquiry_complete() */ - -/* This function handles scsi mode_sense commands */ -static int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Param *param; - TW_Command *command_packet; - unsigned long command_que_value; - unsigned long param_value; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n"); - - /* Only page control = 0, page code = 0x8 (cache page) supported */ - if (tw_dev->srb[request_id]->cmnd[2] != 0x8) { - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - tw_dev->srb[request_id]->result = (DID_OK << 16); - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - return 0; - } - - /* Now read firmware cache setting for this unit */ - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - if (command_packet == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n"); - return 1; - } - - /* Setup the command packet */ - memset(command_packet, 0, sizeof(TW_Sector)); - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = 4; - command_packet->request_id = request_id; - command_packet->status = 0; - command_packet->flags = 0; - command_packet->byte6.parameter_count = 1; - - /* Setup the param */ - if (tw_dev->alignment_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n"); - return 1; - } - - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - memset(param, 0, sizeof(TW_Sector)); - param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->device->id; - param->parameter_id = 7; /* unit flags */ - param->parameter_size_bytes = 1; - param_value = tw_dev->alignment_physical_address[request_id]; - if (param_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n"); - return 1; - } - - command_packet->byte8.param.sgl[0].address = param_value; - command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n"); - return 1; - } - - /* Now try to post the command packet */ - tw_post_command_packet(tw_dev, request_id); - - return 0; -} /* End tw_scsiop_mode_sense() */ - -/* This function is called by the isr to complete a mode sense command */ -static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Param *param; - unsigned char *flags; - unsigned char request_buffer[8]; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n"); - - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - if (param == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n"); - return 1; - } - flags = (char *)&(param->data[0]); - memset(request_buffer, 0, sizeof(request_buffer)); - - request_buffer[0] = 0xf; /* mode data length */ - request_buffer[1] = 0; /* default medium type */ - request_buffer[2] = 0x10; /* dpo/fua support on */ - request_buffer[3] = 0; /* no block descriptors */ - request_buffer[4] = 0x8; /* caching page */ - request_buffer[5] = 0xa; /* page length */ - if (*flags & 0x1) - request_buffer[6] = 0x5; /* WCE on, RCD on */ - else - request_buffer[6] = 0x1; /* WCE off, RCD on */ - tw_transfer_internal(tw_dev, request_id, request_buffer, - sizeof(request_buffer)); - - return 0; -} /* End tw_scsiop_mode_sense_complete() */ - -/* This function handles scsi read_capacity commands */ -static int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Param *param; - TW_Command *command_packet; - unsigned long command_que_value; - unsigned long param_value; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n"); - - /* Initialize command packet */ - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - - if (command_packet == NULL) { - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet virtual address.\n"); - return 1; - } - memset(command_packet, 0, sizeof(TW_Sector)); - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = 4; - command_packet->request_id = request_id; - command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id); - command_packet->status = 0; - command_packet->flags = 0; - command_packet->byte6.block_count = 1; - - /* Now setup the param */ - if (tw_dev->alignment_virtual_address[request_id] == NULL) { - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment virtual address.\n"); - return 1; - } - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - memset(param, 0, sizeof(TW_Sector)); - param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + - tw_dev->srb[request_id]->device->id; - param->parameter_id = 4; /* unitcapacity parameter */ - param->parameter_size_bytes = 4; - param_value = tw_dev->alignment_physical_address[request_id]; - if (param_value == 0) { - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment physical address.\n"); - return 1; - } - - command_packet->byte8.param.sgl[0].address = param_value; - command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet physical address.\n"); - return 1; - } - - /* Now try to post the command to the board */ - tw_post_command_packet(tw_dev, request_id); - - return 0; -} /* End tw_scsiop_read_capacity() */ - -/* This function is called by the isr to complete a readcapacity command */ -static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id) -{ - unsigned char *param_data; - u32 capacity; - char buff[8]; - TW_Param *param; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n"); - - memset(buff, 0, sizeof(buff)); - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - if (param == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n"); - return 1; - } - param_data = &(param->data[0]); - - capacity = (param_data[3] << 24) | (param_data[2] << 16) | - (param_data[1] << 8) | param_data[0]; - - /* Subtract one sector to fix get last sector ioctl */ - capacity -= 1; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity); - - /* Number of LBA's */ - buff[0] = (capacity >> 24); - buff[1] = (capacity >> 16) & 0xff; - buff[2] = (capacity >> 8) & 0xff; - buff[3] = capacity & 0xff; - - /* Block size in bytes (512) */ - buff[4] = (TW_BLOCK_SIZE >> 24); - buff[5] = (TW_BLOCK_SIZE >> 16) & 0xff; - buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff; - buff[7] = TW_BLOCK_SIZE & 0xff; - - tw_transfer_internal(tw_dev, request_id, buff, sizeof(buff)); - - return 0; -} /* End tw_scsiop_read_capacity_complete() */ - -/* This function handles scsi read or write commands */ -static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Command *command_packet; - unsigned long command_que_value; - u32 lba = 0x0, num_sectors = 0x0; - int i, use_sg; - struct scsi_cmnd *srb; - struct scatterlist *sglist, *sg; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n"); - - srb = tw_dev->srb[request_id]; - - sglist = scsi_sglist(srb); - if (!sglist) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n"); - return 1; - } - - /* Initialize command packet */ - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - if (command_packet == NULL) { - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): Bad command packet virtual address.\n"); - return 1; - } - - if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == READ_10) { - command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_READ); - } else { - command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_WRITE); - } - - command_packet->size = 3; - command_packet->request_id = request_id; - command_packet->unit__hostid = TW_UNITHOST_IN(0, srb->device->id); - command_packet->status = 0; - command_packet->flags = 0; - - if (srb->cmnd[0] == WRITE_10) { - if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10)) - command_packet->flags = 1; - } - - if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) { - lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3]; - num_sectors = (u32)srb->cmnd[4]; - } else { - lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5]; - num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8); - } - - /* Update sector statistic */ - tw_dev->sector_count = num_sectors; - if (tw_dev->sector_count > tw_dev->max_sector_count) - tw_dev->max_sector_count = tw_dev->sector_count; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): lba = 0x%x num_sectors = 0x%x\n", lba, num_sectors); - command_packet->byte8.io.lba = lba; - command_packet->byte6.block_count = num_sectors; - - use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); - if (!use_sg) - return 1; - - scsi_for_each_sg(tw_dev->srb[request_id], sg, use_sg, i) { - command_packet->byte8.io.sgl[i].address = sg_dma_address(sg); - command_packet->byte8.io.sgl[i].length = sg_dma_len(sg); - command_packet->size+=2; - } - - /* Update SG statistics */ - tw_dev->sgl_entries = scsi_sg_count(tw_dev->srb[request_id]); - if (tw_dev->sgl_entries > tw_dev->max_sgl_entries) - tw_dev->max_sgl_entries = tw_dev->sgl_entries; - - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Bad command packet physical address.\n"); - return 1; - } - - /* Now try to post the command to the board */ - tw_post_command_packet(tw_dev, request_id); - - return 0; -} /* End tw_scsiop_read_write() */ - -/* This function will handle the request sense scsi command */ -static int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id) -{ - char request_buffer[18]; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n"); - - memset(request_buffer, 0, sizeof(request_buffer)); - request_buffer[0] = 0x70; /* Immediate fixed format */ - request_buffer[7] = 10; /* minimum size per SPC: 18 bytes */ - /* leave all other fields zero, giving effectively NO_SENSE return */ - tw_transfer_internal(tw_dev, request_id, request_buffer, - sizeof(request_buffer)); - - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - - /* If we got a request_sense, we probably want a reset, return error */ - tw_dev->srb[request_id]->result = (DID_ERROR << 16); - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - - return 0; -} /* End tw_scsiop_request_sense() */ - -/* This function will handle synchronize cache scsi command */ -static int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Command *command_packet; - unsigned long command_que_value; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n"); - - /* Send firmware flush command for this unit */ - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - if (command_packet == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n"); - return 1; - } - - /* Setup the command packet */ - memset(command_packet, 0, sizeof(TW_Sector)); - command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_FLUSH_CACHE); - command_packet->size = 2; - command_packet->request_id = request_id; - command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id); - command_packet->status = 0; - command_packet->flags = 0; - command_packet->byte6.parameter_count = 1; - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n"); - return 1; - } - - /* Now try to post the command packet */ - tw_post_command_packet(tw_dev, request_id); - - return 0; -} /* End tw_scsiop_synchronize_cache() */ - -/* This function will handle test unit ready scsi command */ -static int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id) -{ - TW_Param *param; - TW_Command *command_packet; - unsigned long command_que_value; - unsigned long param_value; - - dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n"); - - /* Initialize command packet */ - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - if (command_packet == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n"); - return 1; - } - memset(command_packet, 0, sizeof(TW_Sector)); - command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM); - command_packet->size = 4; - command_packet->request_id = request_id; - command_packet->status = 0; - command_packet->flags = 0; - command_packet->byte6.parameter_count = 1; - - /* Now setup the param */ - if (tw_dev->alignment_virtual_address[request_id] == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n"); - return 1; - } - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - memset(param, 0, sizeof(TW_Sector)); - param->table_id = 3; /* unit summary table */ - param->parameter_id = 3; /* unitsstatus parameter */ - param->parameter_size_bytes = TW_MAX_UNITS; - param_value = tw_dev->alignment_physical_address[request_id]; - if (param_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n"); - return 1; - } - - command_packet->byte8.param.sgl[0].address = param_value; - command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector); - command_que_value = tw_dev->command_packet_physical_address[request_id]; - if (command_que_value == 0) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n"); - return 1; - } - - /* Now try to post the command packet */ - tw_post_command_packet(tw_dev, request_id); - - return 0; -} /* End tw_scsiop_test_unit_ready() */ - -/* This function is called by the isr to complete a testunitready command */ -static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id) -{ - unsigned char *is_unit_present; - TW_Param *param; - - dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n"); - - param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; - if (param == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n"); - return 1; - } - is_unit_present = &(param->data[0]); - - if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) { - tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1; - } else { - tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0; - tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); - return TW_ISR_DONT_RESULT; - } - - return 0; -} /* End tw_scsiop_test_unit_ready_complete() */ - -/* This is the main scsi queue function to handle scsi opcodes */ -static int tw_scsi_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) -{ - unsigned char *command = SCpnt->cmnd; - int request_id = 0; - int retval = 1; - TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata; - - /* If we are resetting due to timed out ioctl, report as busy */ - if (test_bit(TW_IN_RESET, &tw_dev->flags)) - return SCSI_MLQUEUE_HOST_BUSY; - - /* Save done function into Scsi_Cmnd struct */ - SCpnt->scsi_done = done; - - /* Queue the command and get a request id */ - tw_state_request_start(tw_dev, &request_id); - - /* Save the scsi command for use by the ISR */ - tw_dev->srb[request_id] = SCpnt; - - /* Initialize phase to zero */ - SCpnt->SCp.phase = TW_PHASE_INITIAL; - - switch (*command) { - case READ_10: - case READ_6: - case WRITE_10: - case WRITE_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ/WRITE.\n"); - retval = tw_scsiop_read_write(tw_dev, request_id); - break; - case TEST_UNIT_READY: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TEST_UNIT_READY.\n"); - retval = tw_scsiop_test_unit_ready(tw_dev, request_id); - break; - case INQUIRY: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught INQUIRY.\n"); - retval = tw_scsiop_inquiry(tw_dev, request_id); - break; - case READ_CAPACITY: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n"); - retval = tw_scsiop_read_capacity(tw_dev, request_id); - break; - case REQUEST_SENSE: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n"); - retval = tw_scsiop_request_sense(tw_dev, request_id); - break; - case MODE_SENSE: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught MODE_SENSE.\n"); - retval = tw_scsiop_mode_sense(tw_dev, request_id); - break; - case SYNCHRONIZE_CACHE: - dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught SYNCHRONIZE_CACHE.\n"); - retval = tw_scsiop_synchronize_cache(tw_dev, request_id); - break; - case TW_IOCTL: - printk(KERN_WARNING "3w-xxxx: SCSI_IOCTL_SEND_COMMAND deprecated, please update your 3ware tools.\n"); - break; - default: - printk(KERN_NOTICE "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x\n", tw_dev->host->host_no, *command); - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - SCpnt->result = (DID_BAD_TARGET << 16); - done(SCpnt); - retval = 0; - } - if (retval) { - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - SCpnt->result = (DID_ERROR << 16); - done(SCpnt); - retval = 0; - } - return retval; -} /* End tw_scsi_queue() */ - -static DEF_SCSI_QCMD(tw_scsi_queue) - -/* This function is the interrupt service routine */ -static irqreturn_t tw_interrupt(int irq, void *dev_instance) -{ - int request_id; - u32 status_reg_value; - TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; - TW_Response_Queue response_que; - int error = 0, retval = 0; - TW_Command *command_packet; - int handled = 0; - - /* Get the host lock for io completions */ - spin_lock(tw_dev->host->host_lock); - - /* Read the registers */ - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - - /* Check if this is our interrupt, otherwise bail */ - if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT)) - goto tw_interrupt_bail; - - handled = 1; - - /* If we are resetting, bail */ - if (test_bit(TW_IN_RESET, &tw_dev->flags)) - goto tw_interrupt_bail; - - /* Check controller for errors */ - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); - if (tw_decode_bits(tw_dev, status_reg_value, 1)) { - TW_CLEAR_ALL_INTERRUPTS(tw_dev); - goto tw_interrupt_bail; - } - } - - /* Handle host interrupt */ - if (status_reg_value & TW_STATUS_HOST_INTERRUPT) { - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n"); - TW_CLEAR_HOST_INTERRUPT(tw_dev); - } - - /* Handle attention interrupt */ - if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) { - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n"); - TW_CLEAR_ATTENTION_INTERRUPT(tw_dev); - tw_state_request_start(tw_dev, &request_id); - error = tw_aen_read_queue(tw_dev, request_id); - if (error) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no); - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - } - } - - /* Handle command interrupt */ - if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) { - /* Drain as many pending commands as we can */ - while (tw_dev->pending_request_count > 0) { - request_id = tw_dev->pending_queue[tw_dev->pending_head]; - if (tw_dev->state[request_id] != TW_S_PENDING) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no); - break; - } - if (tw_post_command_packet(tw_dev, request_id)==0) { - if (tw_dev->pending_head == TW_Q_LENGTH-1) { - tw_dev->pending_head = TW_Q_START; - } else { - tw_dev->pending_head = tw_dev->pending_head + 1; - } - tw_dev->pending_request_count--; - } else { - /* If we get here, we will continue re-posting on the next command interrupt */ - break; - } - } - /* If there are no more pending requests, we mask command interrupt */ - if (tw_dev->pending_request_count == 0) - TW_MASK_COMMAND_INTERRUPT(tw_dev); - } - - /* Handle response interrupt */ - if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) { - /* Drain the response queue from the board */ - while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { - /* Read response queue register */ - response_que.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev)); - request_id = TW_RESID_OUT(response_que.response_id); - command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; - error = 0; - - /* Check for bad response */ - if (command_packet->status != 0) { - /* If internal command, don't error, don't fill sense */ - if (tw_dev->srb[request_id] == NULL) { - tw_decode_sense(tw_dev, request_id, 0); - } else { - error = tw_decode_sense(tw_dev, request_id, 1); - } - } - - /* Check for correct state */ - if (tw_dev->state[request_id] != TW_S_POSTED) { - if (tw_dev->srb[request_id] != NULL) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id that wasn't posted.\n", tw_dev->host->host_no); - error = 1; - } - } - - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id); - - /* Check for internal command completion */ - if (tw_dev->srb[request_id] == NULL) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n"); - /* Check for chrdev ioctl completion */ - if (request_id != tw_dev->chrdev_request_id) { - retval = tw_aen_complete(tw_dev, request_id); - if (retval) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no); - } - } else { - tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE; - wake_up(&tw_dev->ioctl_wqueue); - } - } else { - switch (tw_dev->srb[request_id]->cmnd[0]) { - case READ_10: - case READ_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n"); - break; - case WRITE_10: - case WRITE_6: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n"); - break; - case TEST_UNIT_READY: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n"); - error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id); - break; - case INQUIRY: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n"); - error = tw_scsiop_inquiry_complete(tw_dev, request_id); - break; - case READ_CAPACITY: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n"); - error = tw_scsiop_read_capacity_complete(tw_dev, request_id); - break; - case MODE_SENSE: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n"); - error = tw_scsiop_mode_sense_complete(tw_dev, request_id); - break; - case SYNCHRONIZE_CACHE: - dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n"); - break; - default: - printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n"); - error = 1; - } - - /* If no error command was a success */ - if (error == 0) { - tw_dev->srb[request_id]->result = (DID_OK << 16); - } - - /* If error, command failed */ - if (error == 1) { - /* Ask for a host reset */ - tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - } - - /* Now complete the io */ - if ((error != TW_ISR_DONT_COMPLETE)) { - tw_dev->state[request_id] = TW_S_COMPLETED; - tw_state_request_finish(tw_dev, request_id); - tw_dev->posted_request_count--; - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - - tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]); - } - } - - /* Check for valid status after each drain */ - status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev)); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); - if (tw_decode_bits(tw_dev, status_reg_value, 1)) { - TW_CLEAR_ALL_INTERRUPTS(tw_dev); - goto tw_interrupt_bail; - } - } - } - } - -tw_interrupt_bail: - spin_unlock(tw_dev->host->host_lock); - return IRQ_RETVAL(handled); -} /* End tw_interrupt() */ - -/* This function tells the controller to shut down */ -static void __tw_shutdown(TW_Device_Extension *tw_dev) -{ - /* Disable interrupts */ - TW_DISABLE_INTERRUPTS(tw_dev); - - /* Free up the IRQ */ - free_irq(tw_dev->tw_pci_dev->irq, tw_dev); - - printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no); - - /* Tell the card we are shutting down */ - if (tw_initconnection(tw_dev, 1)) { - printk(KERN_WARNING "3w-xxxx: Connection shutdown failed.\n"); - } else { - printk(KERN_WARNING "3w-xxxx: Shutdown complete.\n"); - } - - /* Clear all interrupts just before exit */ - TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); -} /* End __tw_shutdown() */ - -/* Wrapper for __tw_shutdown */ -static void tw_shutdown(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - - __tw_shutdown(tw_dev); -} /* End tw_shutdown() */ - -/* This function gets called when a disk is coming online */ -static int tw_slave_configure(struct scsi_device *sdev) -{ - /* Force 60 second timeout */ - blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); - - return 0; -} /* End tw_slave_configure() */ - -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = "3ware Storage Controller", - .queuecommand = tw_scsi_queue, - .eh_host_reset_handler = tw_scsi_eh_reset, - .bios_param = tw_scsi_biosparam, - .change_queue_depth = tw_change_queue_depth, - .can_queue = TW_Q_LENGTH-2, - .slave_configure = tw_slave_configure, - .this_id = -1, - .sg_tablesize = TW_MAX_SGL_LENGTH, - .max_sectors = TW_MAX_SECTORS, - .cmd_per_lun = TW_MAX_CMDS_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = tw_host_attrs, - .emulated = 1 -}; - -/* This function will probe and initialize a card */ -static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id) -{ - struct Scsi_Host *host = NULL; - TW_Device_Extension *tw_dev; - int retval = -ENODEV; - - retval = pci_enable_device(pdev); - if (retval) { - printk(KERN_WARNING "3w-xxxx: Failed to enable pci device."); - goto out_disable_device; - } - - pci_set_master(pdev); - - retval = pci_set_dma_mask(pdev, TW_DMA_MASK); - if (retval) { - printk(KERN_WARNING "3w-xxxx: Failed to set dma mask."); - goto out_disable_device; - } - - host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension)); - if (!host) { - printk(KERN_WARNING "3w-xxxx: Failed to allocate memory for device extension."); - retval = -ENOMEM; - goto out_disable_device; - } - tw_dev = (TW_Device_Extension *)host->hostdata; - - /* Save values to device extension */ - tw_dev->host = host; - tw_dev->tw_pci_dev = pdev; - - if (tw_initialize_device_extension(tw_dev)) { - printk(KERN_WARNING "3w-xxxx: Failed to initialize device extension."); - goto out_free_device_extension; - } - - /* Request IO regions */ - retval = pci_request_regions(pdev, "3w-xxxx"); - if (retval) { - printk(KERN_WARNING "3w-xxxx: Failed to get mem region."); - goto out_free_device_extension; - } - - /* Save base address */ - tw_dev->base_addr = pci_resource_start(pdev, 0); - if (!tw_dev->base_addr) { - printk(KERN_WARNING "3w-xxxx: Failed to get io address."); - goto out_release_mem_region; - } - - /* Disable interrupts on the card */ - TW_DISABLE_INTERRUPTS(tw_dev); - - /* Initialize the card */ - if (tw_reset_sequence(tw_dev)) - goto out_release_mem_region; - - /* Set host specific parameters */ - host->max_id = TW_MAX_UNITS; - host->max_cmd_len = TW_MAX_CDB_LEN; - - /* Luns and channels aren't supported by adapter */ - host->max_lun = 0; - host->max_channel = 0; - - /* Register the card with the kernel SCSI layer */ - retval = scsi_add_host(host, &pdev->dev); - if (retval) { - printk(KERN_WARNING "3w-xxxx: scsi add host failed"); - goto out_release_mem_region; - } - - pci_set_drvdata(pdev, host); - - printk(KERN_WARNING "3w-xxxx: scsi%d: Found a 3ware Storage Controller at 0x%x, IRQ: %d.\n", host->host_no, tw_dev->base_addr, pdev->irq); - - /* Now setup the interrupt handler */ - retval = request_irq(pdev->irq, tw_interrupt, IRQF_SHARED, "3w-xxxx", tw_dev); - if (retval) { - printk(KERN_WARNING "3w-xxxx: Error requesting IRQ."); - goto out_remove_host; - } - - tw_device_extension_list[tw_device_extension_count] = tw_dev; - tw_device_extension_count++; - - /* Re-enable interrupts on the card */ - TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev); - - /* Finally, scan the host */ - scsi_scan_host(host); - - if (twe_major == -1) { - if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0) - printk(KERN_WARNING "3w-xxxx: Failed to register character device."); - } - return 0; - -out_remove_host: - scsi_remove_host(host); -out_release_mem_region: - pci_release_regions(pdev); -out_free_device_extension: - tw_free_device_extension(tw_dev); - scsi_host_put(host); -out_disable_device: - pci_disable_device(pdev); - - return retval; -} /* End tw_probe() */ - -/* This function is called to remove a device */ -static void tw_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata; - - scsi_remove_host(tw_dev->host); - - /* Unregister character device */ - if (twe_major >= 0) { - unregister_chrdev(twe_major, "twe"); - twe_major = -1; - } - - /* Shutdown the card */ - __tw_shutdown(tw_dev); - - /* Free up the mem region */ - pci_release_regions(pdev); - - /* Free up device extension resources */ - tw_free_device_extension(tw_dev); - - scsi_host_put(tw_dev->host); - pci_disable_device(pdev); - tw_device_extension_count--; -} /* End tw_remove() */ - -/* PCI Devices supported by this driver */ -static struct pci_device_id tw_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_1000, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_7000, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { } -}; -MODULE_DEVICE_TABLE(pci, tw_pci_tbl); - -/* pci_driver initializer */ -static struct pci_driver tw_driver = { - .name = "3w-xxxx", - .id_table = tw_pci_tbl, - .probe = tw_probe, - .remove = tw_remove, - .shutdown = tw_shutdown, -}; - -/* This function is called on driver initialization */ -static int __init tw_init(void) -{ - printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION); - - return pci_register_driver(&tw_driver); -} /* End tw_init() */ - -/* This function is called on driver exit */ -static void __exit tw_exit(void) -{ - pci_unregister_driver(&tw_driver); -} /* End tw_exit() */ - -module_init(tw_init); -module_exit(tw_exit); - diff --git a/ANDROID_3.4.5/drivers/scsi/3w-xxxx.h b/ANDROID_3.4.5/drivers/scsi/3w-xxxx.h deleted file mode 100644 index 49dcf03c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/3w-xxxx.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - 3w-xxxx.h -- 3ware Storage Controller device driver for Linux. - - Written By: Adam Radford - Modifications By: Joel Jacobson - Arnaldo Carvalho de Melo - Brad Strand - - Copyright (C) 1999-2010 3ware Inc. - - Kernel compatibility By: Andre Hedrick - Non-Copyright (C) 2000 Andre Hedrick - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - NO WARRANTY - THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - solely responsible for determining the appropriateness of using and - distributing the Program and assumes all risks associated with its - exercise of rights under this Agreement, including but not limited to - the risks and costs of program errors, damage to or loss of data, - programs or equipment, and unavailability or interruption of operations. - - DISCLAIMER OF LIABILITY - NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com -*/ - -#ifndef _3W_XXXX_H -#define _3W_XXXX_H - -#include - -/* AEN strings */ -static char *tw_aen_string[] = { - [0x000] = "INFO: AEN queue empty", - [0x001] = "INFO: Soft reset occurred", - [0x002] = "ERROR: Unit degraded: Unit #", - [0x003] = "ERROR: Controller error", - [0x004] = "ERROR: Rebuild failed: Unit #", - [0x005] = "INFO: Rebuild complete: Unit #", - [0x006] = "ERROR: Incomplete unit detected: Unit #", - [0x007] = "INFO: Initialization complete: Unit #", - [0x008] = "WARNING: Unclean shutdown detected: Unit #", - [0x009] = "WARNING: ATA port timeout: Port #", - [0x00A] = "ERROR: Drive error: Port #", - [0x00B] = "INFO: Rebuild started: Unit #", - [0x00C] = "INFO: Initialization started: Unit #", - [0x00D] = "ERROR: Logical unit deleted: Unit #", - [0x00F] = "WARNING: SMART threshold exceeded: Port #", - [0x021] = "WARNING: ATA UDMA downgrade: Port #", - [0x022] = "WARNING: ATA UDMA upgrade: Port #", - [0x023] = "WARNING: Sector repair occurred: Port #", - [0x024] = "ERROR: SBUF integrity check failure", - [0x025] = "ERROR: Lost cached write: Port #", - [0x026] = "ERROR: Drive ECC error detected: Port #", - [0x027] = "ERROR: DCB checksum error: Port #", - [0x028] = "ERROR: DCB unsupported version: Port #", - [0x029] = "INFO: Verify started: Unit #", - [0x02A] = "ERROR: Verify failed: Port #", - [0x02B] = "INFO: Verify complete: Unit #", - [0x02C] = "WARNING: Overwrote bad sector during rebuild: Port #", - [0x02D] = "ERROR: Encountered bad sector during rebuild: Port #", - [0x02E] = "ERROR: Replacement drive is too small: Port #", - [0x02F] = "WARNING: Verify error: Unit not previously initialized: Unit #", - [0x030] = "ERROR: Drive not supported: Port #" -}; - -/* - Sense key lookup table - Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier -*/ -static unsigned char tw_sense_table[][4] = -{ - /* Codes for newer firmware */ - // ATA Error SCSI Error - {0x01, 0x03, 0x13, 0x00}, // Address mark not found Address mark not found for data field - {0x04, 0x0b, 0x00, 0x00}, // Aborted command Aborted command - {0x10, 0x0b, 0x14, 0x00}, // ID not found Recorded entity not found - {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error Unrecovered read error - {0x61, 0x04, 0x00, 0x00}, // Device fault Hardware error - {0x84, 0x0b, 0x47, 0x00}, // Data CRC error SCSI parity error - {0xd0, 0x0b, 0x00, 0x00}, // Device busy Aborted command - {0xd1, 0x0b, 0x00, 0x00}, // Device busy Aborted command - {0x37, 0x02, 0x04, 0x00}, // Unit offline Not ready - {0x09, 0x02, 0x04, 0x00}, // Unrecovered disk error Not ready - - /* Codes for older firmware */ - // 3ware Error SCSI Error - {0x51, 0x0b, 0x00, 0x00} // Unspecified Aborted command -}; - -/* Control register bit definitions */ -#define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 -#define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT 0x00040000 -#define TW_CONTROL_MASK_COMMAND_INTERRUPT 0x00020000 -#define TW_CONTROL_MASK_RESPONSE_INTERRUPT 0x00010000 -#define TW_CONTROL_UNMASK_COMMAND_INTERRUPT 0x00008000 -#define TW_CONTROL_UNMASK_RESPONSE_INTERRUPT 0x00004000 -#define TW_CONTROL_CLEAR_ERROR_STATUS 0x00000200 -#define TW_CONTROL_ISSUE_SOFT_RESET 0x00000100 -#define TW_CONTROL_ENABLE_INTERRUPTS 0x00000080 -#define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040 -#define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020 -#define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000 -#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000 -#define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 -#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008 - -/* Status register bit definitions */ -#define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000 -#define TW_STATUS_MINOR_VERSION_MASK 0x0F000000 -#define TW_STATUS_PCI_PARITY_ERROR 0x00800000 -#define TW_STATUS_QUEUE_ERROR 0x00400000 -#define TW_STATUS_MICROCONTROLLER_ERROR 0x00200000 -#define TW_STATUS_PCI_ABORT 0x00100000 -#define TW_STATUS_HOST_INTERRUPT 0x00080000 -#define TW_STATUS_ATTENTION_INTERRUPT 0x00040000 -#define TW_STATUS_COMMAND_INTERRUPT 0x00020000 -#define TW_STATUS_RESPONSE_INTERRUPT 0x00010000 -#define TW_STATUS_COMMAND_QUEUE_FULL 0x00008000 -#define TW_STATUS_RESPONSE_QUEUE_EMPTY 0x00004000 -#define TW_STATUS_MICROCONTROLLER_READY 0x00002000 -#define TW_STATUS_COMMAND_QUEUE_EMPTY 0x00001000 -#define TW_STATUS_ALL_INTERRUPTS 0x000F0000 -#define TW_STATUS_CLEARABLE_BITS 0x00D00000 -#define TW_STATUS_EXPECTED_BITS 0x00002000 -#define TW_STATUS_UNEXPECTED_BITS 0x00F00008 -#define TW_STATUS_SBUF_WRITE_ERROR 0x00000008 -#define TW_STATUS_VALID_INTERRUPT 0x00DF0008 - -/* RESPONSE QUEUE BIT DEFINITIONS */ -#define TW_RESPONSE_ID_MASK 0x00000FF0 - -/* PCI related defines */ -#define TW_IO_ADDRESS_RANGE 0x10 -#define TW_DEVICE_NAME "3ware Storage Controller" -#define TW_VENDOR_ID (0x13C1) /* 3ware */ -#define TW_DEVICE_ID (0x1000) /* Storage Controller */ -#define TW_DEVICE_ID2 (0x1001) /* 7000 series controller */ -#define TW_NUMDEVICES 2 -#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100 -#define TW_PCI_CLEAR_PCI_ABORT 0x2000 - -/* Command packet opcodes */ -#define TW_OP_NOP 0x0 -#define TW_OP_INIT_CONNECTION 0x1 -#define TW_OP_READ 0x2 -#define TW_OP_WRITE 0x3 -#define TW_OP_VERIFY 0x4 -#define TW_OP_GET_PARAM 0x12 -#define TW_OP_SET_PARAM 0x13 -#define TW_OP_SECTOR_INFO 0x1a -#define TW_OP_AEN_LISTEN 0x1c -#define TW_OP_FLUSH_CACHE 0x0e -#define TW_CMD_PACKET 0x1d -#define TW_CMD_PACKET_WITH_DATA 0x1f - -/* Asynchronous Event Notification (AEN) Codes */ -#define TW_AEN_QUEUE_EMPTY 0x0000 -#define TW_AEN_SOFT_RESET 0x0001 -#define TW_AEN_DEGRADED_MIRROR 0x0002 -#define TW_AEN_CONTROLLER_ERROR 0x0003 -#define TW_AEN_REBUILD_FAIL 0x0004 -#define TW_AEN_REBUILD_DONE 0x0005 -#define TW_AEN_QUEUE_FULL 0x00ff -#define TW_AEN_TABLE_UNDEFINED 0x15 -#define TW_AEN_APORT_TIMEOUT 0x0009 -#define TW_AEN_DRIVE_ERROR 0x000A -#define TW_AEN_SMART_FAIL 0x000F -#define TW_AEN_SBUF_FAIL 0x0024 - -/* Phase defines */ -#define TW_PHASE_INITIAL 0 -#define TW_PHASE_SINGLE 1 -#define TW_PHASE_SGLIST 2 - -/* Misc defines */ -#define TW_ALIGNMENT_6000 64 /* 64 bytes */ -#define TW_ALIGNMENT_7000 4 /* 4 bytes */ -#define TW_MAX_UNITS 16 -#define TW_COMMAND_ALIGNMENT_MASK 0x1ff -#define TW_INIT_MESSAGE_CREDITS 0x100 -#define TW_INIT_COMMAND_PACKET_SIZE 0x3 -#define TW_POLL_MAX_RETRIES 20000 -#define TW_MAX_SGL_LENGTH 62 -#define TW_ATA_PASS_SGL_MAX 60 -#define TW_Q_LENGTH 256 -#define TW_Q_START 0 -#define TW_MAX_SLOT 32 -#define TW_MAX_PCI_BUSES 255 -#define TW_MAX_RESET_TRIES 3 -#define TW_UNIT_INFORMATION_TABLE_BASE 0x300 -#define TW_MAX_CMDS_PER_LUN 254 /* 254 for io, 1 for - chrdev ioctl, one for - internal aen post */ -#define TW_BLOCK_SIZE 0x200 /* 512-byte blocks */ -#define TW_IOCTL 0x80 -#define TW_UNIT_ONLINE 1 -#define TW_IN_INTR 1 -#define TW_IN_RESET 2 -#define TW_IN_CHRDEV_IOCTL 3 -#define TW_MAX_SECTORS 256 -#define TW_MAX_IOCTL_SECTORS 512 -#define TW_AEN_WAIT_TIME 1000 -#define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */ -#define TW_ISR_DONT_COMPLETE 2 -#define TW_ISR_DONT_RESULT 3 -#define TW_IOCTL_TIMEOUT 25 /* 25 seconds */ -#define TW_IOCTL_CHRDEV_TIMEOUT 60 /* 60 seconds */ -#define TW_IOCTL_CHRDEV_FREE -1 -#define TW_DMA_MASK DMA_BIT_MASK(32) -#define TW_MAX_CDB_LEN 16 - -/* Bitmask macros to eliminate bitfields */ - -/* opcode: 5, sgloffset: 3 */ -#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f)) -#define TW_SGL_OUT(x) ((x >> 5) & 0x7) - -/* reserved_1: 4, response_id: 8, reserved_2: 20 */ -#define TW_RESID_OUT(x) ((x >> 4) & 0xff) - -/* unit: 4, host_id: 4 */ -#define TW_UNITHOST_IN(x,y) ((x << 4) | ( y & 0xf)) -#define TW_UNIT_OUT(x) (x & 0xf) - -/* Macros */ -#define TW_CONTROL_REG_ADDR(x) (x->base_addr) -#define TW_STATUS_REG_ADDR(x) (x->base_addr + 0x4) -#define TW_COMMAND_QUEUE_REG_ADDR(x) (x->base_addr + 0x8) -#define TW_RESPONSE_QUEUE_REG_ADDR(x) (x->base_addr + 0xC) -#define TW_CLEAR_ALL_INTERRUPTS(x) (outl(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_CLEAR_ATTENTION_INTERRUPT(x) (outl(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_CLEAR_HOST_INTERRUPT(x) (outl(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_DISABLE_INTERRUPTS(x) (outl(TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) -#define TW_ENABLE_AND_CLEAR_INTERRUPTS(x) (outl(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) -#define TW_MASK_COMMAND_INTERRUPT(x) (outl(TW_CONTROL_MASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_UNMASK_COMMAND_INTERRUPT(x) (outl(TW_CONTROL_UNMASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x))) -#define TW_SOFT_RESET(x) (outl(TW_CONTROL_ISSUE_SOFT_RESET | \ - TW_CONTROL_CLEAR_HOST_INTERRUPT | \ - TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | \ - TW_CONTROL_MASK_COMMAND_INTERRUPT | \ - TW_CONTROL_MASK_RESPONSE_INTERRUPT | \ - TW_CONTROL_CLEAR_ERROR_STATUS | \ - TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x))) -#define TW_STATUS_ERRORS(x) \ - (((x & TW_STATUS_PCI_ABORT) || \ - (x & TW_STATUS_PCI_PARITY_ERROR) || \ - (x & TW_STATUS_QUEUE_ERROR) || \ - (x & TW_STATUS_MICROCONTROLLER_ERROR)) && \ - (x & TW_STATUS_MICROCONTROLLER_READY)) - -#ifdef TW_DEBUG -#define dprintk(msg...) printk(msg) -#else -#define dprintk(msg...) do { } while(0) -#endif - -#pragma pack(1) - -/* Scatter Gather List Entry */ -typedef struct TAG_TW_SG_Entry { - u32 address; - u32 length; -} TW_SG_Entry; - -typedef unsigned char TW_Sector[512]; - -/* Command Packet */ -typedef struct TW_Command { - unsigned char opcode__sgloffset; - unsigned char size; - unsigned char request_id; - unsigned char unit__hostid; - /* Second DWORD */ - unsigned char status; - unsigned char flags; - union { - unsigned short block_count; - unsigned short parameter_count; - unsigned short message_credits; - } byte6; - union { - struct { - u32 lba; - TW_SG_Entry sgl[TW_MAX_SGL_LENGTH]; - u32 padding; /* pad to 512 bytes */ - } io; - struct { - TW_SG_Entry sgl[TW_MAX_SGL_LENGTH]; - u32 padding[2]; - } param; - struct { - u32 response_queue_pointer; - u32 padding[125]; - } init_connection; - struct { - char version[504]; - } ioctl_miniport_version; - } byte8; -} TW_Command; - -#pragma pack() - -typedef struct TAG_TW_Ioctl { - unsigned char opcode; - unsigned short table_id; - unsigned char parameter_id; - unsigned char parameter_size_bytes; - unsigned char unit_index; - unsigned char data[1]; -} TW_Ioctl; - -#pragma pack(1) - -/* Structure for new chardev ioctls */ -typedef struct TAG_TW_New_Ioctl { - unsigned int data_buffer_length; - unsigned char padding [508]; - TW_Command firmware_command; - char data_buffer[1]; -} TW_New_Ioctl; - -/* GetParam descriptor */ -typedef struct { - unsigned short table_id; - unsigned char parameter_id; - unsigned char parameter_size_bytes; - unsigned char data[1]; -} TW_Param, *PTW_Param; - -/* Response queue */ -typedef union TAG_TW_Response_Queue { - u32 response_id; - u32 value; -} TW_Response_Queue; - -typedef int TW_Cmd_State; - -#define TW_S_INITIAL 0x1 /* Initial state */ -#define TW_S_STARTED 0x2 /* Id in use */ -#define TW_S_POSTED 0x4 /* Posted to the controller */ -#define TW_S_PENDING 0x8 /* Waiting to be posted in isr */ -#define TW_S_COMPLETED 0x10 /* Completed by isr */ -#define TW_S_FINISHED 0x20 /* I/O completely done */ -#define TW_START_MASK (TW_S_STARTED | TW_S_POSTED | TW_S_PENDING | TW_S_COMPLETED) - -/* Command header for ATA pass-thru */ -typedef struct TAG_TW_Passthru -{ - unsigned char opcode__sgloffset; - unsigned char size; - unsigned char request_id; - unsigned char aport__hostid; - unsigned char status; - unsigned char flags; - unsigned short param; - unsigned short features; - unsigned short sector_count; - unsigned short sector_num; - unsigned short cylinder_lo; - unsigned short cylinder_hi; - unsigned char drive_head; - unsigned char command; - TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX]; - unsigned char padding[12]; -} TW_Passthru; - -typedef struct TAG_TW_Device_Extension { - u32 base_addr; - unsigned long *alignment_virtual_address[TW_Q_LENGTH]; - unsigned long alignment_physical_address[TW_Q_LENGTH]; - int is_unit_present[TW_MAX_UNITS]; - unsigned long *command_packet_virtual_address[TW_Q_LENGTH]; - unsigned long command_packet_physical_address[TW_Q_LENGTH]; - struct pci_dev *tw_pci_dev; - struct scsi_cmnd *srb[TW_Q_LENGTH]; - unsigned char free_queue[TW_Q_LENGTH]; - unsigned char free_head; - unsigned char free_tail; - unsigned char pending_queue[TW_Q_LENGTH]; - unsigned char pending_head; - unsigned char pending_tail; - TW_Cmd_State state[TW_Q_LENGTH]; - u32 posted_request_count; - u32 max_posted_request_count; - u32 request_count_marked_pending; - u32 pending_request_count; - u32 max_pending_request_count; - u32 max_sgl_entries; - u32 sgl_entries; - u32 num_resets; - u32 sector_count; - u32 max_sector_count; - u32 aen_count; - struct Scsi_Host *host; - struct mutex ioctl_lock; - unsigned short aen_queue[TW_Q_LENGTH]; - unsigned char aen_head; - unsigned char aen_tail; - volatile long flags; /* long req'd for set_bit --RR */ - int reset_print; - volatile int chrdev_request_id; - wait_queue_head_t ioctl_wqueue; -} TW_Device_Extension; - -#pragma pack() - -#endif /* _3W_XXXX_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/53c700.c b/ANDROID_3.4.5/drivers/scsi/53c700.c deleted file mode 100644 index a3adfb43..00000000 --- a/ANDROID_3.4.5/drivers/scsi/53c700.c +++ /dev/null @@ -1,2177 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ - -/* NCR (or Symbios) 53c700 and 53c700-66 Driver - * - * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- - */ - -/* Notes: - * - * This driver is designed exclusively for these chips (virtually the - * earliest of the scripts engine chips). They need their own drivers - * because they are missing so many of the scripts and snazzy register - * features of their elder brothers (the 710, 720 and 770). - * - * The 700 is the lowliest of the line, it can only do async SCSI. - * The 700-66 can at least do synchronous SCSI up to 10MHz. - * - * The 700 chip has no host bus interface logic of its own. However, - * it is usually mapped to a location with well defined register - * offsets. Therefore, if you can determine the base address and the - * irq your board incorporating this chip uses, you can probably use - * this driver to run it (although you'll probably have to write a - * minimal wrapper for the purpose---see the NCR_D700 driver for - * details about how to do this). - * - * - * TODO List: - * - * 1. Better statistics in the proc fs - * - * 2. Implement message queue (queues SCSI messages like commands) and make - * the abort and device reset functions use them. - * */ - -/* CHANGELOG - * - * Version 2.8 - * - * Fixed bad bug affecting tag starvation processing (previously the - * driver would hang the system if too many tags starved. Also fixed - * bad bug having to do with 10 byte command processing and REQUEST - * SENSE (the command would loop forever getting a transfer length - * mismatch in the CMD phase). - * - * Version 2.7 - * - * Fixed scripts problem which caused certain devices (notably CDRWs) - * to hang on initial INQUIRY. Updated NCR_700_readl/writel to use - * __raw_readl/writel for parisc compatibility (Thomas - * Bogendoerfer). Added missing SCp->request_bufflen initialisation - * for sense requests (Ryan Bradetich). - * - * Version 2.6 - * - * Following test of the 64 bit parisc kernel by Richard Hirst, - * several problems have now been corrected. Also adds support for - * consistent memory allocation. - * - * Version 2.5 - * - * More Compatibility changes for 710 (now actually works). Enhanced - * support for odd clock speeds which constrain SDTR negotiations. - * correct cacheline separation for scsi messages and status for - * incoherent architectures. Use of the pci mapping functions on - * buffers to begin support for 64 bit drivers. - * - * Version 2.4 - * - * Added support for the 53c710 chip (in 53c700 emulation mode only---no - * special 53c710 instructions or registers are used). - * - * Version 2.3 - * - * More endianness/cache coherency changes. - * - * Better bad device handling (handles devices lying about tag - * queueing support and devices which fail to provide sense data on - * contingent allegiance conditions) - * - * Many thanks to Richard Hirst for patiently - * debugging this driver on the parisc architecture and suggesting - * many improvements and bug fixes. - * - * Thanks also go to Linuxcare Inc. for providing several PARISC - * machines for me to debug the driver on. - * - * Version 2.2 - * - * Made the driver mem or io mapped; added endian invariance; added - * dma cache flushing operations for architectures which need it; - * added support for more varied clocking speeds. - * - * Version 2.1 - * - * Initial modularisation from the D700. See NCR_D700.c for the rest of - * the changelog. - * */ -#define NCR_700_VERSION "2.8" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "53c700.h" - -/* NOTE: For 64 bit drivers there are points in the code where we use - * a non dereferenceable pointer to point to a structure in dma-able - * memory (which is 32 bits) so that we can use all of the structure - * operations but take the address at the end. This macro allows us - * to truncate the 64 bit pointer down to 32 bits without the compiler - * complaining */ -#define to32bit(x) ((__u32)((unsigned long)(x))) - -#ifdef NCR_700_DEBUG -#define STATIC -#else -#define STATIC static -#endif - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("53c700 and 53c700-66 Driver"); -MODULE_LICENSE("GPL"); - -/* This is the script */ -#include "53c700_d.h" - - -STATIC int NCR_700_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *); -STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt); -STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt); -STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt); -STATIC void NCR_700_chip_setup(struct Scsi_Host *host); -STATIC void NCR_700_chip_reset(struct Scsi_Host *host); -STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt); -STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt); -STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt); -static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth, int reason); -static int NCR_700_change_queue_type(struct scsi_device *SDpnt, int depth); - -STATIC struct device_attribute *NCR_700_dev_attrs[]; - -STATIC struct scsi_transport_template *NCR_700_transport_template = NULL; - -static char *NCR_700_phase[] = { - "", - "after selection", - "before command phase", - "after command phase", - "after status phase", - "after data in phase", - "after data out phase", - "during data phase", -}; - -static char *NCR_700_condition[] = { - "", - "NOT MSG_OUT", - "UNEXPECTED PHASE", - "NOT MSG_IN", - "UNEXPECTED MSG", - "MSG_IN", - "SDTR_MSG RECEIVED", - "REJECT_MSG RECEIVED", - "DISCONNECT_MSG RECEIVED", - "MSG_OUT", - "DATA_IN", - -}; - -static char *NCR_700_fatal_messages[] = { - "unexpected message after reselection", - "still MSG_OUT after message injection", - "not MSG_IN after selection", - "Illegal message length received", -}; - -static char *NCR_700_SBCL_bits[] = { - "IO ", - "CD ", - "MSG ", - "ATN ", - "SEL ", - "BSY ", - "ACK ", - "REQ ", -}; - -static char *NCR_700_SBCL_to_phase[] = { - "DATA_OUT", - "DATA_IN", - "CMD_OUT", - "STATE", - "ILLEGAL PHASE", - "ILLEGAL PHASE", - "MSG OUT", - "MSG IN", -}; - -/* This translates the SDTR message offset and period to a value - * which can be loaded into the SXFER_REG. - * - * NOTE: According to SCSI-2, the true transfer period (in ns) is - * actually four times this period value */ -static inline __u8 -NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata, - __u8 offset, __u8 period) -{ - int XFERP; - - __u8 min_xferp = (hostdata->chip710 - ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); - __u8 max_offset = (hostdata->chip710 - ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET); - - if(offset == 0) - return 0; - - if(period < hostdata->min_period) { - printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_MIN_PERIOD*4); - period = hostdata->min_period; - } - XFERP = (period*4 * hostdata->sync_clock)/1000 - 4; - if(offset > max_offset) { - printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n", - offset, max_offset); - offset = max_offset; - } - if(XFERP < min_xferp) { - XFERP = min_xferp; - } - return (offset & 0x0f) | (XFERP & 0x07)<<4; -} - -static inline __u8 -NCR_700_get_SXFER(struct scsi_device *SDp) -{ - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; - - return NCR_700_offset_period_to_sxfer(hostdata, - spi_offset(SDp->sdev_target), - spi_period(SDp->sdev_target)); -} - -struct Scsi_Host * -NCR_700_detect(struct scsi_host_template *tpnt, - struct NCR_700_Host_Parameters *hostdata, struct device *dev) -{ - dma_addr_t pScript, pSlots; - __u8 *memory; - __u32 *script; - struct Scsi_Host *host; - static int banner = 0; - int j; - - if(tpnt->sdev_attrs == NULL) - tpnt->sdev_attrs = NCR_700_dev_attrs; - - memory = dma_alloc_noncoherent(hostdata->dev, TOTAL_MEM_SIZE, - &pScript, GFP_KERNEL); - if(memory == NULL) { - printk(KERN_ERR "53c700: Failed to allocate memory for driver, detatching\n"); - return NULL; - } - - script = (__u32 *)memory; - hostdata->msgin = memory + MSGIN_OFFSET; - hostdata->msgout = memory + MSGOUT_OFFSET; - hostdata->status = memory + STATUS_OFFSET; - hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET); - hostdata->dev = dev; - - pSlots = pScript + SLOTS_OFFSET; - - /* Fill in the missing routines from the host template */ - tpnt->queuecommand = NCR_700_queuecommand; - tpnt->eh_abort_handler = NCR_700_abort; - tpnt->eh_bus_reset_handler = NCR_700_bus_reset; - tpnt->eh_host_reset_handler = NCR_700_host_reset; - tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST; - tpnt->sg_tablesize = NCR_700_SG_SEGMENTS; - tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN; - tpnt->use_clustering = ENABLE_CLUSTERING; - tpnt->slave_configure = NCR_700_slave_configure; - tpnt->slave_destroy = NCR_700_slave_destroy; - tpnt->slave_alloc = NCR_700_slave_alloc; - tpnt->change_queue_depth = NCR_700_change_queue_depth; - tpnt->change_queue_type = NCR_700_change_queue_type; - - if(tpnt->name == NULL) - tpnt->name = "53c700"; - if(tpnt->proc_name == NULL) - tpnt->proc_name = "53c700"; - - host = scsi_host_alloc(tpnt, 4); - if (!host) - return NULL; - memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot) - * NCR_700_COMMAND_SLOTS_PER_HOST); - for (j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) { - dma_addr_t offset = (dma_addr_t)((unsigned long)&hostdata->slots[j].SG[0] - - (unsigned long)&hostdata->slots[0].SG[0]); - hostdata->slots[j].pSG = (struct NCR_700_SG_List *)((unsigned long)(pSlots + offset)); - if(j == 0) - hostdata->free_list = &hostdata->slots[j]; - else - hostdata->slots[j-1].ITL_forw = &hostdata->slots[j]; - hostdata->slots[j].state = NCR_700_SLOT_FREE; - } - - for (j = 0; j < ARRAY_SIZE(SCRIPT); j++) - script[j] = bS_to_host(SCRIPT[j]); - - /* adjust all labels to be bus physical */ - for (j = 0; j < PATCHES; j++) - script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]); - /* now patch up fixed addresses. */ - script_patch_32(hostdata->dev, script, MessageLocation, - pScript + MSGOUT_OFFSET); - script_patch_32(hostdata->dev, script, StatusAddress, - pScript + STATUS_OFFSET); - script_patch_32(hostdata->dev, script, ReceiveMsgAddress, - pScript + MSGIN_OFFSET); - - hostdata->script = script; - hostdata->pScript = pScript; - dma_sync_single_for_device(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE); - hostdata->state = NCR_700_HOST_FREE; - hostdata->cmd = NULL; - host->max_id = 8; - host->max_lun = NCR_700_MAX_LUNS; - BUG_ON(NCR_700_transport_template == NULL); - host->transportt = NCR_700_transport_template; - host->unique_id = (unsigned long)hostdata->base; - hostdata->eh_complete = NULL; - host->hostdata[0] = (unsigned long)hostdata; - /* kick the chip */ - NCR_700_writeb(0xff, host, CTEST9_REG); - if (hostdata->chip710) - hostdata->rev = (NCR_700_readb(host, CTEST8_REG)>>4) & 0x0f; - else - hostdata->rev = (NCR_700_readb(host, CTEST7_REG)>>4) & 0x0f; - hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0); - if (banner == 0) { - printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n"); - banner = 1; - } - printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no, - hostdata->chip710 ? "53c710" : - (hostdata->fast ? "53c700-66" : "53c700"), - hostdata->rev, hostdata->differential ? - "(Differential)" : ""); - /* reset the chip */ - NCR_700_chip_reset(host); - - if (scsi_add_host(host, dev)) { - dev_printk(KERN_ERR, dev, "53c700: scsi_add_host failed\n"); - scsi_host_put(host); - return NULL; - } - - spi_signalling(host) = hostdata->differential ? SPI_SIGNAL_HVD : - SPI_SIGNAL_SE; - - return host; -} - -int -NCR_700_release(struct Scsi_Host *host) -{ - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - - dma_free_noncoherent(hostdata->dev, TOTAL_MEM_SIZE, - hostdata->script, hostdata->pScript); - return 1; -} - -static inline __u8 -NCR_700_identify(int can_disconnect, __u8 lun) -{ - return IDENTIFY_BASE | - ((can_disconnect) ? 0x40 : 0) | - (lun & NCR_700_LUN_MASK); -} - -/* - * Function : static int data_residual (Scsi_Host *host) - * - * Purpose : return residual data count of what's in the chip. If you - * really want to know what this function is doing, it's almost a - * direct transcription of the algorithm described in the 53c710 - * guide, except that the DBC and DFIFO registers are only 6 bits - * wide on a 53c700. - * - * Inputs : host - SCSI host */ -static inline int -NCR_700_data_residual (struct Scsi_Host *host) { - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - int count, synchronous = 0; - unsigned int ddir; - - if(hostdata->chip710) { - count = ((NCR_700_readb(host, DFIFO_REG) & 0x7f) - - (NCR_700_readl(host, DBC_REG) & 0x7f)) & 0x7f; - } else { - count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) - - (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f; - } - - if(hostdata->fast) - synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f; - - /* get the data direction */ - ddir = NCR_700_readb(host, CTEST0_REG) & 0x01; - - if (ddir) { - /* Receive */ - if (synchronous) - count += (NCR_700_readb(host, SSTAT2_REG) & 0xf0) >> 4; - else - if (NCR_700_readb(host, SSTAT1_REG) & SIDL_REG_FULL) - ++count; - } else { - /* Send */ - __u8 sstat = NCR_700_readb(host, SSTAT1_REG); - if (sstat & SODL_REG_FULL) - ++count; - if (synchronous && (sstat & SODR_REG_FULL)) - ++count; - } -#ifdef NCR_700_DEBUG - if(count) - printk("RESIDUAL IS %d (ddir %d)\n", count, ddir); -#endif - return count; -} - -/* print out the SCSI wires and corresponding phase from the SBCL register - * in the chip */ -static inline char * -sbcl_to_string(__u8 sbcl) -{ - int i; - static char ret[256]; - - ret[0]='\0'; - for(i=0; i<8; i++) { - if((1<free_list; - - if(slot == NULL) { - /* sanity check */ - if(hostdata->command_slot_count != NCR_700_COMMAND_SLOTS_PER_HOST) - printk(KERN_ERR "SLOTS FULL, but count is %d, should be %d\n", hostdata->command_slot_count, NCR_700_COMMAND_SLOTS_PER_HOST); - return NULL; - } - - if(slot->state != NCR_700_SLOT_FREE) - /* should panic! */ - printk(KERN_ERR "BUSY SLOT ON FREE LIST!!!\n"); - - - hostdata->free_list = slot->ITL_forw; - slot->ITL_forw = NULL; - - - /* NOTE: set the state to busy here, not queued, since this - * indicates the slot is in use and cannot be run by the IRQ - * finish routine. If we cannot queue the command when it - * is properly build, we then change to NCR_700_SLOT_QUEUED */ - slot->state = NCR_700_SLOT_BUSY; - slot->flags = 0; - hostdata->command_slot_count++; - - return slot; -} - -STATIC void -free_slot(struct NCR_700_command_slot *slot, - struct NCR_700_Host_Parameters *hostdata) -{ - if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) { - printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot); - } - if(slot->state == NCR_700_SLOT_FREE) { - printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot); - } - - slot->resume_offset = 0; - slot->cmnd = NULL; - slot->state = NCR_700_SLOT_FREE; - slot->ITL_forw = hostdata->free_list; - hostdata->free_list = slot; - hostdata->command_slot_count--; -} - - -/* This routine really does very little. The command is indexed on - the ITL and (if tagged) the ITLQ lists in _queuecommand */ -STATIC void -save_for_reselection(struct NCR_700_Host_Parameters *hostdata, - struct scsi_cmnd *SCp, __u32 dsp) -{ - /* Its just possible that this gets executed twice */ - if(SCp != NULL) { - struct NCR_700_command_slot *slot = - (struct NCR_700_command_slot *)SCp->host_scribble; - - slot->resume_offset = dsp; - } - hostdata->state = NCR_700_HOST_FREE; - hostdata->cmd = NULL; -} - -STATIC inline void -NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp, - struct NCR_700_command_slot *slot) -{ - if(SCp->sc_data_direction != DMA_NONE && - SCp->sc_data_direction != DMA_BIDIRECTIONAL) - scsi_dma_unmap(SCp); -} - -STATIC inline void -NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata, - struct scsi_cmnd *SCp, int result) -{ - hostdata->state = NCR_700_HOST_FREE; - hostdata->cmd = NULL; - - if(SCp != NULL) { - struct NCR_700_command_slot *slot = - (struct NCR_700_command_slot *)SCp->host_scribble; - - dma_unmap_single(hostdata->dev, slot->pCmd, - MAX_COMMAND_SIZE, DMA_TO_DEVICE); - if (slot->flags == NCR_700_FLAG_AUTOSENSE) { - char *cmnd = NCR_700_get_sense_cmnd(SCp->device); -#ifdef NCR_700_DEBUG - printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n", - SCp, SCp->cmnd[7], result); - scsi_print_sense("53c700", SCp); - -#endif - dma_unmap_single(hostdata->dev, slot->dma_handle, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - /* restore the old result if the request sense was - * successful */ - if (result == 0) - result = cmnd[7]; - /* restore the original length */ - SCp->cmd_len = cmnd[8]; - } else - NCR_700_unmap(hostdata, SCp, slot); - - free_slot(slot, hostdata); -#ifdef NCR_700_DEBUG - if(NCR_700_get_depth(SCp->device) == 0 || - NCR_700_get_depth(SCp->device) > SCp->device->queue_depth) - printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n", - NCR_700_get_depth(SCp->device)); -#endif /* NCR_700_DEBUG */ - NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1); - - SCp->host_scribble = NULL; - SCp->result = result; - SCp->scsi_done(SCp); - } else { - printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n"); - } -} - - -STATIC void -NCR_700_internal_bus_reset(struct Scsi_Host *host) -{ - /* Bus reset */ - NCR_700_writeb(ASSERT_RST, host, SCNTL1_REG); - udelay(50); - NCR_700_writeb(0, host, SCNTL1_REG); - -} - -STATIC void -NCR_700_chip_setup(struct Scsi_Host *host) -{ - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - __u8 min_period; - __u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP); - - if(hostdata->chip710) { - __u8 burst_disable = 0; - __u8 burst_length = 0; - - switch (hostdata->burst_length) { - case 1: - burst_length = BURST_LENGTH_1; - break; - case 2: - burst_length = BURST_LENGTH_2; - break; - case 4: - burst_length = BURST_LENGTH_4; - break; - case 8: - burst_length = BURST_LENGTH_8; - break; - default: - burst_disable = BURST_DISABLE; - break; - } - hostdata->dcntl_extra |= COMPAT_700_MODE; - - NCR_700_writeb(hostdata->dcntl_extra, host, DCNTL_REG); - NCR_700_writeb(burst_length | hostdata->dmode_extra, - host, DMODE_710_REG); - NCR_700_writeb(burst_disable | hostdata->ctest7_extra | - (hostdata->differential ? DIFF : 0), - host, CTEST7_REG); - NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG); - NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY - | AUTO_ATN, host, SCNTL0_REG); - } else { - NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra, - host, DMODE_700_REG); - NCR_700_writeb(hostdata->differential ? - DIFF : 0, host, CTEST7_REG); - if(hostdata->fast) { - /* this is for 700-66, does nothing on 700 */ - NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION - | GENERATE_RECEIVE_PARITY, host, - CTEST8_REG); - } else { - NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY - | PARITY | AUTO_ATN, host, SCNTL0_REG); - } - } - - NCR_700_writeb(1 << host->this_id, host, SCID_REG); - NCR_700_writeb(0, host, SBCL_REG); - NCR_700_writeb(ASYNC_OPERATION, host, SXFER_REG); - - NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT - | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG); - - NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG); - NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG); - if(hostdata->clock > 75) { - printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock); - /* do the best we can, but the async clock will be out - * of spec: sync divider 2, async divider 3 */ - DEBUG(("53c700: sync 2 async 3\n")); - NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG); - hostdata->sync_clock = hostdata->clock/2; - } else if(hostdata->clock > 50 && hostdata->clock <= 75) { - /* sync divider 1.5, async divider 3 */ - DEBUG(("53c700: sync 1.5 async 3\n")); - NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_3_0 | hostdata->dcntl_extra, host, DCNTL_REG); - hostdata->sync_clock = hostdata->clock*2; - hostdata->sync_clock /= 3; - - } else if(hostdata->clock > 37 && hostdata->clock <= 50) { - /* sync divider 1, async divider 2 */ - DEBUG(("53c700: sync 1 async 2\n")); - NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_2_0 | hostdata->dcntl_extra, host, DCNTL_REG); - hostdata->sync_clock = hostdata->clock; - } else if(hostdata->clock > 25 && hostdata->clock <=37) { - /* sync divider 1, async divider 1.5 */ - DEBUG(("53c700: sync 1 async 1.5\n")); - NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_1_5 | hostdata->dcntl_extra, host, DCNTL_REG); - hostdata->sync_clock = hostdata->clock; - } else { - DEBUG(("53c700: sync 1 async 1\n")); - NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG); - NCR_700_writeb(ASYNC_DIV_1_0 | hostdata->dcntl_extra, host, DCNTL_REG); - /* sync divider 1, async divider 1 */ - hostdata->sync_clock = hostdata->clock; - } - /* Calculate the actual minimum period that can be supported - * by our synchronous clock speed. See the 710 manual for - * exact details of this calculation which is based on a - * setting of the SXFER register */ - min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock); - hostdata->min_period = NCR_700_MIN_PERIOD; - if(min_period > NCR_700_MIN_PERIOD) - hostdata->min_period = min_period; -} - -STATIC void -NCR_700_chip_reset(struct Scsi_Host *host) -{ - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - if(hostdata->chip710) { - NCR_700_writeb(SOFTWARE_RESET_710, host, ISTAT_REG); - udelay(100); - - NCR_700_writeb(0, host, ISTAT_REG); - } else { - NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG); - udelay(100); - - NCR_700_writeb(0, host, DCNTL_REG); - } - - mdelay(1000); - - NCR_700_chip_setup(host); -} - -/* The heart of the message processing engine is that the instruction - * immediately after the INT is the normal case (and so must be CLEAR - * ACK). If we want to do something else, we call that routine in - * scripts and set temp to be the normal case + 8 (skipping the CLEAR - * ACK) so that the routine returns correctly to resume its activity - * */ -STATIC __u32 -process_extended_message(struct Scsi_Host *host, - struct NCR_700_Host_Parameters *hostdata, - struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps) -{ - __u32 resume_offset = dsp, temp = dsp + 8; - __u8 pun = 0xff, lun = 0xff; - - if(SCp != NULL) { - pun = SCp->device->id; - lun = SCp->device->lun; - } - - switch(hostdata->msgin[2]) { - case A_SDTR_MSG: - if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { - struct scsi_target *starget = SCp->device->sdev_target; - __u8 period = hostdata->msgin[3]; - __u8 offset = hostdata->msgin[4]; - - if(offset == 0 || period == 0) { - offset = 0; - period = 0; - } - - spi_offset(starget) = offset; - spi_period(starget) = period; - - if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) { - spi_display_xfer_agreement(starget); - NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION); - } - - NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); - NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); - - NCR_700_writeb(NCR_700_get_SXFER(SCp->device), - host, SXFER_REG); - - } else { - /* SDTR message out of the blue, reject it */ - shost_printk(KERN_WARNING, host, - "Unexpected SDTR msg\n"); - hostdata->msgout[0] = A_REJECT_MSG; - dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE); - script_patch_16(hostdata->dev, hostdata->script, - MessageCount, 1); - /* SendMsgOut returns, so set up the return - * address */ - resume_offset = hostdata->pScript + Ent_SendMessageWithATN; - } - break; - - case A_WDTR_MSG: - printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n", - host->host_no, pun, lun); - hostdata->msgout[0] = A_REJECT_MSG; - dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE); - script_patch_16(hostdata->dev, hostdata->script, MessageCount, - 1); - resume_offset = hostdata->pScript + Ent_SendMessageWithATN; - - break; - - default: - printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ", - host->host_no, pun, lun, - NCR_700_phase[(dsps & 0xf00) >> 8]); - spi_print_msg(hostdata->msgin); - printk("\n"); - /* just reject it */ - hostdata->msgout[0] = A_REJECT_MSG; - dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE); - script_patch_16(hostdata->dev, hostdata->script, MessageCount, - 1); - /* SendMsgOut returns, so set up the return - * address */ - resume_offset = hostdata->pScript + Ent_SendMessageWithATN; - } - NCR_700_writel(temp, host, TEMP_REG); - return resume_offset; -} - -STATIC __u32 -process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata, - struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps) -{ - /* work out where to return to */ - __u32 temp = dsp + 8, resume_offset = dsp; - __u8 pun = 0xff, lun = 0xff; - - if(SCp != NULL) { - pun = SCp->device->id; - lun = SCp->device->lun; - } - -#ifdef NCR_700_DEBUG - printk("scsi%d (%d:%d): message %s: ", host->host_no, pun, lun, - NCR_700_phase[(dsps & 0xf00) >> 8]); - spi_print_msg(hostdata->msgin); - printk("\n"); -#endif - - switch(hostdata->msgin[0]) { - - case A_EXTENDED_MSG: - resume_offset = process_extended_message(host, hostdata, SCp, - dsp, dsps); - break; - - case A_REJECT_MSG: - if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) { - /* Rejected our sync negotiation attempt */ - spi_period(SCp->device->sdev_target) = - spi_offset(SCp->device->sdev_target) = 0; - NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); - NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); - } else if(SCp != NULL && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION) { - /* rejected our first simple tag message */ - scmd_printk(KERN_WARNING, SCp, - "Rejected first tag queue attempt, turning off tag queueing\n"); - /* we're done negotiating */ - NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION); - hostdata->tag_negotiated &= ~(1<device->tagged_supported = 0; - scsi_deactivate_tcq(SCp->device, host->cmd_per_lun); - } else { - shost_printk(KERN_WARNING, host, - "(%d:%d) Unexpected REJECT Message %s\n", - pun, lun, - NCR_700_phase[(dsps & 0xf00) >> 8]); - /* however, just ignore it */ - } - break; - - case A_PARITY_ERROR_MSG: - printk(KERN_ERR "scsi%d (%d:%d) Parity Error!\n", host->host_no, - pun, lun); - NCR_700_internal_bus_reset(host); - break; - case A_SIMPLE_TAG_MSG: - printk(KERN_INFO "scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no, - pun, lun, hostdata->msgin[1], - NCR_700_phase[(dsps & 0xf00) >> 8]); - /* just ignore it */ - break; - default: - printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ", - host->host_no, pun, lun, - NCR_700_phase[(dsps & 0xf00) >> 8]); - - spi_print_msg(hostdata->msgin); - printk("\n"); - /* just reject it */ - hostdata->msgout[0] = A_REJECT_MSG; - dma_cache_sync(hostdata->dev, hostdata->msgout, 1, DMA_TO_DEVICE); - script_patch_16(hostdata->dev, hostdata->script, MessageCount, - 1); - /* SendMsgOut returns, so set up the return - * address */ - resume_offset = hostdata->pScript + Ent_SendMessageWithATN; - - break; - } - NCR_700_writel(temp, host, TEMP_REG); - /* set us up to receive another message */ - dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE, DMA_FROM_DEVICE); - return resume_offset; -} - -STATIC __u32 -process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp, - struct Scsi_Host *host, - struct NCR_700_Host_Parameters *hostdata) -{ - __u32 resume_offset = 0; - __u8 pun = 0xff, lun=0xff; - - if(SCp != NULL) { - pun = SCp->device->id; - lun = SCp->device->lun; - } - - if(dsps == A_GOOD_STATUS_AFTER_STATUS) { - DEBUG((" COMMAND COMPLETE, status=%02x\n", - hostdata->status[0])); - /* OK, if TCQ still under negotiation, we now know it works */ - if (NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION) - NCR_700_set_tag_neg_state(SCp->device, - NCR_700_FINISHED_TAG_NEGOTIATION); - - /* check for contingent allegiance contitions */ - if(status_byte(hostdata->status[0]) == CHECK_CONDITION || - status_byte(hostdata->status[0]) == COMMAND_TERMINATED) { - struct NCR_700_command_slot *slot = - (struct NCR_700_command_slot *)SCp->host_scribble; - if(slot->flags == NCR_700_FLAG_AUTOSENSE) { - /* OOPS: bad device, returning another - * contingent allegiance condition */ - scmd_printk(KERN_ERR, SCp, - "broken device is looping in contingent allegiance: ignoring\n"); - NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]); - } else { - char *cmnd = - NCR_700_get_sense_cmnd(SCp->device); -#ifdef NCR_DEBUG - scsi_print_command(SCp); - printk(" cmd %p has status %d, requesting sense\n", - SCp, hostdata->status[0]); -#endif - /* we can destroy the command here - * because the contingent allegiance - * condition will cause a retry which - * will re-copy the command from the - * saved data_cmnd. We also unmap any - * data associated with the command - * here */ - NCR_700_unmap(hostdata, SCp, slot); - dma_unmap_single(hostdata->dev, slot->pCmd, - MAX_COMMAND_SIZE, - DMA_TO_DEVICE); - - cmnd[0] = REQUEST_SENSE; - cmnd[1] = (SCp->device->lun & 0x7) << 5; - cmnd[2] = 0; - cmnd[3] = 0; - cmnd[4] = SCSI_SENSE_BUFFERSIZE; - cmnd[5] = 0; - /* Here's a quiet hack: the - * REQUEST_SENSE command is six bytes, - * so store a flag indicating that - * this was an internal sense request - * and the original status at the end - * of the command */ - cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC; - cmnd[7] = hostdata->status[0]; - cmnd[8] = SCp->cmd_len; - SCp->cmd_len = 6; /* command length for - * REQUEST_SENSE */ - slot->pCmd = dma_map_single(hostdata->dev, cmnd, MAX_COMMAND_SIZE, DMA_TO_DEVICE); - slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | SCSI_SENSE_BUFFERSIZE); - slot->SG[0].pAddr = bS_to_host(slot->dma_handle); - slot->SG[1].ins = bS_to_host(SCRIPT_RETURN); - slot->SG[1].pAddr = 0; - slot->resume_offset = hostdata->pScript; - dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE); - dma_cache_sync(hostdata->dev, SCp->sense_buffer, SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - - /* queue the command for reissue */ - slot->state = NCR_700_SLOT_QUEUED; - slot->flags = NCR_700_FLAG_AUTOSENSE; - hostdata->state = NCR_700_HOST_FREE; - hostdata->cmd = NULL; - } - } else { - // Currently rely on the mid layer evaluation - // of the tag queuing capability - // - //if(status_byte(hostdata->status[0]) == GOOD && - // SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) { - // /* Piggy back the tag queueing support - // * on this command */ - // dma_sync_single_for_cpu(hostdata->dev, - // slot->dma_handle, - // SCp->request_bufflen, - // DMA_FROM_DEVICE); - // if(((char *)SCp->request_buffer)[7] & 0x02) { - // scmd_printk(KERN_INFO, SCp, - // "Enabling Tag Command Queuing\n"); - // hostdata->tag_negotiated |= (1<device, NCR_700_DEV_BEGIN_TAG_QUEUEING); - // } else { - // NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING); - // hostdata->tag_negotiated &= ~(1<status[0]); - } - } else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) { - __u8 i = (dsps & 0xf00) >> 8; - - scmd_printk(KERN_ERR, SCp, "UNEXPECTED PHASE %s (%s)\n", - NCR_700_phase[i], - sbcl_to_string(NCR_700_readb(host, SBCL_REG))); - scmd_printk(KERN_ERR, SCp, " len = %d, cmd =", - SCp->cmd_len); - scsi_print_command(SCp); - - NCR_700_internal_bus_reset(host); - } else if((dsps & 0xfffff000) == A_FATAL) { - int i = (dsps & 0xfff); - - printk(KERN_ERR "scsi%d: (%d:%d) FATAL ERROR: %s\n", - host->host_no, pun, lun, NCR_700_fatal_messages[i]); - if(dsps == A_FATAL_ILLEGAL_MSG_LENGTH) { - printk(KERN_ERR " msg begins %02x %02x\n", - hostdata->msgin[0], hostdata->msgin[1]); - } - NCR_700_internal_bus_reset(host); - } else if((dsps & 0xfffff0f0) == A_DISCONNECT) { -#ifdef NCR_700_DEBUG - __u8 i = (dsps & 0xf00) >> 8; - - printk("scsi%d: (%d:%d), DISCONNECTED (%d) %s\n", - host->host_no, pun, lun, - i, NCR_700_phase[i]); -#endif - save_for_reselection(hostdata, SCp, dsp); - - } else if(dsps == A_RESELECTION_IDENTIFIED) { - __u8 lun; - struct NCR_700_command_slot *slot; - __u8 reselection_id = hostdata->reselection_id; - struct scsi_device *SDp; - - lun = hostdata->msgin[0] & 0x1f; - - hostdata->reselection_id = 0xff; - DEBUG(("scsi%d: (%d:%d) RESELECTED!\n", - host->host_no, reselection_id, lun)); - /* clear the reselection indicator */ - SDp = __scsi_device_lookup(host, 0, reselection_id, lun); - if(unlikely(SDp == NULL)) { - printk(KERN_ERR "scsi%d: (%d:%d) HAS NO device\n", - host->host_no, reselection_id, lun); - BUG(); - } - if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) { - struct scsi_cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]); - if(unlikely(SCp == NULL)) { - printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n", - host->host_no, reselection_id, lun, hostdata->msgin[2]); - BUG(); - } - - slot = (struct NCR_700_command_slot *)SCp->host_scribble; - DDEBUG(KERN_DEBUG, SDp, - "reselection is tag %d, slot %p(%d)\n", - hostdata->msgin[2], slot, slot->tag); - } else { - struct scsi_cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG); - if(unlikely(SCp == NULL)) { - sdev_printk(KERN_ERR, SDp, - "no saved request for untagged cmd\n"); - BUG(); - } - slot = (struct NCR_700_command_slot *)SCp->host_scribble; - } - - if(slot == NULL) { - printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n", - host->host_no, reselection_id, lun, - hostdata->msgin[0], hostdata->msgin[1], - hostdata->msgin[2]); - } else { - if(hostdata->state != NCR_700_HOST_BUSY) - printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n", - host->host_no); - resume_offset = slot->resume_offset; - hostdata->cmd = slot->cmnd; - - /* re-patch for this command */ - script_patch_32_abs(hostdata->dev, hostdata->script, - CommandAddress, slot->pCmd); - script_patch_16(hostdata->dev, hostdata->script, - CommandCount, slot->cmnd->cmd_len); - script_patch_32_abs(hostdata->dev, hostdata->script, - SGScriptStartAddress, - to32bit(&slot->pSG[0].ins)); - - /* Note: setting SXFER only works if we're - * still in the MESSAGE phase, so it is vital - * that ACK is still asserted when we process - * the reselection message. The resume offset - * should therefore always clear ACK */ - NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device), - host, SXFER_REG); - dma_cache_sync(hostdata->dev, hostdata->msgin, - MSG_ARRAY_SIZE, DMA_FROM_DEVICE); - dma_cache_sync(hostdata->dev, hostdata->msgout, - MSG_ARRAY_SIZE, DMA_TO_DEVICE); - /* I'm just being paranoid here, the command should - * already have been flushed from the cache */ - dma_cache_sync(hostdata->dev, slot->cmnd->cmnd, - slot->cmnd->cmd_len, DMA_TO_DEVICE); - - - - } - } else if(dsps == A_RESELECTED_DURING_SELECTION) { - - /* This section is full of debugging code because I've - * never managed to reach it. I think what happens is - * that, because the 700 runs with selection - * interrupts enabled the whole time that we take a - * selection interrupt before we manage to get to the - * reselected script interrupt */ - - __u8 reselection_id = NCR_700_readb(host, SFBR_REG); - struct NCR_700_command_slot *slot; - - /* Take out our own ID */ - reselection_id &= ~(1<this_id); - - /* I've never seen this happen, so keep this as a printk rather - * than a debug */ - printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%08x[%04x] state=%d, count=%d\n", - host->host_no, reselection_id, lun, dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count); - - { - /* FIXME: DEBUGGING CODE */ - __u32 SG = (__u32)bS_to_cpu(hostdata->script[A_SGScriptStartAddress_used[0]]); - int i; - - for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) { - if(SG >= to32bit(&hostdata->slots[i].pSG[0]) - && SG <= to32bit(&hostdata->slots[i].pSG[NCR_700_SG_SEGMENTS])) - break; - } - printk(KERN_INFO "IDENTIFIED SG segment as being %08x in slot %p, cmd %p, slot->resume_offset=%08x\n", SG, &hostdata->slots[i], hostdata->slots[i].cmnd, hostdata->slots[i].resume_offset); - SCp = hostdata->slots[i].cmnd; - } - - if(SCp != NULL) { - slot = (struct NCR_700_command_slot *)SCp->host_scribble; - /* change slot from busy to queued to redo command */ - slot->state = NCR_700_SLOT_QUEUED; - } - hostdata->cmd = NULL; - - if(reselection_id == 0) { - if(hostdata->reselection_id == 0xff) { - printk(KERN_ERR "scsi%d: Invalid reselection during selection!!\n", host->host_no); - return 0; - } else { - printk(KERN_ERR "scsi%d: script reselected and we took a selection interrupt\n", - host->host_no); - reselection_id = hostdata->reselection_id; - } - } else { - - /* convert to real ID */ - reselection_id = bitmap_to_number(reselection_id); - } - hostdata->reselection_id = reselection_id; - /* just in case we have a stale simple tag message, clear it */ - hostdata->msgin[1] = 0; - dma_cache_sync(hostdata->dev, hostdata->msgin, - MSG_ARRAY_SIZE, DMA_BIDIRECTIONAL); - if(hostdata->tag_negotiated & (1<pScript + Ent_GetReselectionWithTag; - } else { - resume_offset = hostdata->pScript + Ent_GetReselectionData; - } - } else if(dsps == A_COMPLETED_SELECTION_AS_TARGET) { - /* we've just disconnected from the bus, do nothing since - * a return here will re-run the queued command slot - * that may have been interrupted by the initial selection */ - DEBUG((" SELECTION COMPLETED\n")); - } else if((dsps & 0xfffff0f0) == A_MSG_IN) { - resume_offset = process_message(host, hostdata, SCp, - dsp, dsps); - } else if((dsps & 0xfffff000) == 0) { - __u8 i = (dsps & 0xf0) >> 4, j = (dsps & 0xf00) >> 8; - printk(KERN_ERR "scsi%d: (%d:%d), unhandled script condition %s %s at %04x\n", - host->host_no, pun, lun, NCR_700_condition[i], - NCR_700_phase[j], dsp - hostdata->pScript); - if(SCp != NULL) { - struct scatterlist *sg; - - scsi_print_command(SCp); - scsi_for_each_sg(SCp, sg, scsi_sg_count(SCp) + 1, i) { - printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, sg->length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr); - } - } - NCR_700_internal_bus_reset(host); - } else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) { - printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n", - host->host_no, pun, lun, dsps & 0xfff, dsp, dsp - hostdata->pScript); - resume_offset = dsp; - } else { - printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n", - host->host_no, pun, lun, dsps, dsp - hostdata->pScript); - NCR_700_internal_bus_reset(host); - } - return resume_offset; -} - -/* We run the 53c700 with selection interrupts always enabled. This - * means that the chip may be selected as soon as the bus frees. On a - * busy bus, this can be before the scripts engine finishes its - * processing. Therefore, part of the selection processing has to be - * to find out what the scripts engine is doing and complete the - * function if necessary (i.e. process the pending disconnect or save - * the interrupted initial selection */ -STATIC inline __u32 -process_selection(struct Scsi_Host *host, __u32 dsp) -{ - __u8 id = 0; /* Squash compiler warning */ - int count = 0; - __u32 resume_offset = 0; - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - struct scsi_cmnd *SCp = hostdata->cmd; - __u8 sbcl; - - for(count = 0; count < 5; count++) { - id = NCR_700_readb(host, hostdata->chip710 ? - CTEST9_REG : SFBR_REG); - - /* Take out our own ID */ - id &= ~(1<this_id); - if(id != 0) - break; - udelay(5); - } - sbcl = NCR_700_readb(host, SBCL_REG); - if((sbcl & SBCL_IO) == 0) { - /* mark as having been selected rather than reselected */ - id = 0xff; - } else { - /* convert to real ID */ - hostdata->reselection_id = id = bitmap_to_number(id); - DEBUG(("scsi%d: Reselected by %d\n", - host->host_no, id)); - } - if(hostdata->state == NCR_700_HOST_BUSY && SCp != NULL) { - struct NCR_700_command_slot *slot = - (struct NCR_700_command_slot *)SCp->host_scribble; - DEBUG((" ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %x [%04x], resume %x!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset)); - - switch(dsp - hostdata->pScript) { - case Ent_Disconnect1: - case Ent_Disconnect2: - save_for_reselection(hostdata, SCp, Ent_Disconnect2 + hostdata->pScript); - break; - case Ent_Disconnect3: - case Ent_Disconnect4: - save_for_reselection(hostdata, SCp, Ent_Disconnect4 + hostdata->pScript); - break; - case Ent_Disconnect5: - case Ent_Disconnect6: - save_for_reselection(hostdata, SCp, Ent_Disconnect6 + hostdata->pScript); - break; - case Ent_Disconnect7: - case Ent_Disconnect8: - save_for_reselection(hostdata, SCp, Ent_Disconnect8 + hostdata->pScript); - break; - case Ent_Finish1: - case Ent_Finish2: - process_script_interrupt(A_GOOD_STATUS_AFTER_STATUS, dsp, SCp, host, hostdata); - break; - - default: - slot->state = NCR_700_SLOT_QUEUED; - break; - } - } - hostdata->state = NCR_700_HOST_BUSY; - hostdata->cmd = NULL; - /* clear any stale simple tag message */ - hostdata->msgin[1] = 0; - dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE, - DMA_BIDIRECTIONAL); - - if(id == 0xff) { - /* Selected as target, Ignore */ - resume_offset = hostdata->pScript + Ent_SelectedAsTarget; - } else if(hostdata->tag_negotiated & (1<pScript + Ent_GetReselectionWithTag; - } else { - resume_offset = hostdata->pScript + Ent_GetReselectionData; - } - return resume_offset; -} - -static inline void -NCR_700_clear_fifo(struct Scsi_Host *host) { - const struct NCR_700_Host_Parameters *hostdata - = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - if(hostdata->chip710) { - NCR_700_writeb(CLR_FIFO_710, host, CTEST8_REG); - } else { - NCR_700_writeb(CLR_FIFO, host, DFIFO_REG); - } -} - -static inline void -NCR_700_flush_fifo(struct Scsi_Host *host) { - const struct NCR_700_Host_Parameters *hostdata - = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - if(hostdata->chip710) { - NCR_700_writeb(FLUSH_DMA_FIFO_710, host, CTEST8_REG); - udelay(10); - NCR_700_writeb(0, host, CTEST8_REG); - } else { - NCR_700_writeb(FLUSH_DMA_FIFO, host, DFIFO_REG); - udelay(10); - NCR_700_writeb(0, host, DFIFO_REG); - } -} - - -/* The queue lock with interrupts disabled must be held on entry to - * this function */ -STATIC int -NCR_700_start_command(struct scsi_cmnd *SCp) -{ - struct NCR_700_command_slot *slot = - (struct NCR_700_command_slot *)SCp->host_scribble; - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; - __u16 count = 1; /* for IDENTIFY message */ - - if(hostdata->state != NCR_700_HOST_FREE) { - /* keep this inside the lock to close the race window where - * the running command finishes on another CPU while we don't - * change the state to queued on this one */ - slot->state = NCR_700_SLOT_QUEUED; - - DEBUG(("scsi%d: host busy, queueing command %p, slot %p\n", - SCp->device->host->host_no, slot->cmnd, slot)); - return 0; - } - hostdata->state = NCR_700_HOST_BUSY; - hostdata->cmd = SCp; - slot->state = NCR_700_SLOT_BUSY; - /* keep interrupts disabled until we have the command correctly - * set up so we cannot take a selection interrupt */ - - hostdata->msgout[0] = NCR_700_identify((SCp->cmnd[0] != REQUEST_SENSE && - slot->flags != NCR_700_FLAG_AUTOSENSE), - SCp->device->lun); - /* for INQUIRY or REQUEST_SENSE commands, we cannot be sure - * if the negotiated transfer parameters still hold, so - * always renegotiate them */ - if(SCp->cmnd[0] == INQUIRY || SCp->cmnd[0] == REQUEST_SENSE || - slot->flags == NCR_700_FLAG_AUTOSENSE) { - NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC); - } - - /* REQUEST_SENSE is asking for contingent I_T_L(_Q) status. - * If a contingent allegiance condition exists, the device - * will refuse all tags, so send the request sense as untagged - * */ - if((hostdata->tag_negotiated & (1<tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE && - slot->flags != NCR_700_FLAG_AUTOSENSE)) { - count += scsi_populate_tag_msg(SCp, &hostdata->msgout[count]); - } - - if(hostdata->fast && - NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) { - count += spi_populate_sync_msg(&hostdata->msgout[count], - spi_period(SCp->device->sdev_target), - spi_offset(SCp->device->sdev_target)); - NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); - } - - script_patch_16(hostdata->dev, hostdata->script, MessageCount, count); - - - script_patch_ID(hostdata->dev, hostdata->script, - Device_ID, 1<dev, hostdata->script, CommandAddress, - slot->pCmd); - script_patch_16(hostdata->dev, hostdata->script, CommandCount, - SCp->cmd_len); - /* finally plumb the beginning of the SG list into the script - * */ - script_patch_32_abs(hostdata->dev, hostdata->script, - SGScriptStartAddress, to32bit(&slot->pSG[0].ins)); - NCR_700_clear_fifo(SCp->device->host); - - if(slot->resume_offset == 0) - slot->resume_offset = hostdata->pScript; - /* now perform all the writebacks and invalidates */ - dma_cache_sync(hostdata->dev, hostdata->msgout, count, DMA_TO_DEVICE); - dma_cache_sync(hostdata->dev, hostdata->msgin, MSG_ARRAY_SIZE, - DMA_FROM_DEVICE); - dma_cache_sync(hostdata->dev, SCp->cmnd, SCp->cmd_len, DMA_TO_DEVICE); - dma_cache_sync(hostdata->dev, hostdata->status, 1, DMA_FROM_DEVICE); - - /* set the synchronous period/offset */ - NCR_700_writeb(NCR_700_get_SXFER(SCp->device), - SCp->device->host, SXFER_REG); - NCR_700_writel(slot->temp, SCp->device->host, TEMP_REG); - NCR_700_writel(slot->resume_offset, SCp->device->host, DSP_REG); - - return 1; -} - -irqreturn_t -NCR_700_intr(int irq, void *dev_id) -{ - struct Scsi_Host *host = (struct Scsi_Host *)dev_id; - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - __u8 istat; - __u32 resume_offset = 0; - __u8 pun = 0xff, lun = 0xff; - unsigned long flags; - int handled = 0; - - /* Use the host lock to serialise access to the 53c700 - * hardware. Note: In future, we may need to take the queue - * lock to enter the done routines. When that happens, we - * need to ensure that for this driver, the host lock and the - * queue lock point to the same thing. */ - spin_lock_irqsave(host->host_lock, flags); - if((istat = NCR_700_readb(host, ISTAT_REG)) - & (SCSI_INT_PENDING | DMA_INT_PENDING)) { - __u32 dsps; - __u8 sstat0 = 0, dstat = 0; - __u32 dsp; - struct scsi_cmnd *SCp = hostdata->cmd; - enum NCR_700_Host_State state; - - handled = 1; - state = hostdata->state; - SCp = hostdata->cmd; - - if(istat & SCSI_INT_PENDING) { - udelay(10); - - sstat0 = NCR_700_readb(host, SSTAT0_REG); - } - - if(istat & DMA_INT_PENDING) { - udelay(10); - - dstat = NCR_700_readb(host, DSTAT_REG); - } - - dsps = NCR_700_readl(host, DSPS_REG); - dsp = NCR_700_readl(host, DSP_REG); - - DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n", - host->host_no, istat, sstat0, dstat, - (dsp - (__u32)(hostdata->pScript))/4, - dsp, dsps)); - - if(SCp != NULL) { - pun = SCp->device->id; - lun = SCp->device->lun; - } - - if(sstat0 & SCSI_RESET_DETECTED) { - struct scsi_device *SDp; - int i; - - hostdata->state = NCR_700_HOST_BUSY; - - printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n", - host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript); - - scsi_report_bus_reset(host, 0); - - /* clear all the negotiated parameters */ - __shost_for_each_device(SDp, host) - NCR_700_clear_flag(SDp, ~0); - - /* clear all the slots and their pending commands */ - for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { - struct scsi_cmnd *SCp; - struct NCR_700_command_slot *slot = - &hostdata->slots[i]; - - if(slot->state == NCR_700_SLOT_FREE) - continue; - - SCp = slot->cmnd; - printk(KERN_ERR " failing command because of reset, slot %p, cmnd %p\n", - slot, SCp); - free_slot(slot, hostdata); - SCp->host_scribble = NULL; - NCR_700_set_depth(SCp->device, 0); - /* NOTE: deadlock potential here: we - * rely on mid-layer guarantees that - * scsi_done won't try to issue the - * command again otherwise we'll - * deadlock on the - * hostdata->state_lock */ - SCp->result = DID_RESET << 16; - SCp->scsi_done(SCp); - } - mdelay(25); - NCR_700_chip_setup(host); - - hostdata->state = NCR_700_HOST_FREE; - hostdata->cmd = NULL; - /* signal back if this was an eh induced reset */ - if(hostdata->eh_complete != NULL) - complete(hostdata->eh_complete); - goto out_unlock; - } else if(sstat0 & SELECTION_TIMEOUT) { - DEBUG(("scsi%d: (%d:%d) selection timeout\n", - host->host_no, pun, lun)); - NCR_700_scsi_done(hostdata, SCp, DID_NO_CONNECT<<16); - } else if(sstat0 & PHASE_MISMATCH) { - struct NCR_700_command_slot *slot = (SCp == NULL) ? NULL : - (struct NCR_700_command_slot *)SCp->host_scribble; - - if(dsp == Ent_SendMessage + 8 + hostdata->pScript) { - /* It wants to reply to some part of - * our message */ -#ifdef NCR_700_DEBUG - __u32 temp = NCR_700_readl(host, TEMP_REG); - int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((NCR_700_readl(host, DBC_REG) & 0xffffff) + NCR_700_data_residual(host)); - printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG))); -#endif - resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch; - } else if(dsp >= to32bit(&slot->pSG[0].ins) && - dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) { - int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff; - int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List); - int residual = NCR_700_data_residual(host); - int i; -#ifdef NCR_700_DEBUG - __u32 naddr = NCR_700_readl(host, DNAD_REG); - - printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n", - host->host_no, pun, lun, - SGcount, data_transfer); - scsi_print_command(SCp); - if(residual) { - printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x, residual %d\n", - host->host_no, pun, lun, - SGcount, data_transfer, residual); - } -#endif - data_transfer += residual; - - if(data_transfer != 0) { - int count; - __u32 pAddr; - - SGcount--; - - count = (bS_to_cpu(slot->SG[SGcount].ins) & 0x00ffffff); - DEBUG(("DATA TRANSFER MISMATCH, count = %d, transferred %d\n", count, count-data_transfer)); - slot->SG[SGcount].ins &= bS_to_host(0xff000000); - slot->SG[SGcount].ins |= bS_to_host(data_transfer); - pAddr = bS_to_cpu(slot->SG[SGcount].pAddr); - pAddr += (count - data_transfer); -#ifdef NCR_700_DEBUG - if(pAddr != naddr) { - printk("scsi%d (%d:%d) transfer mismatch pAddr=%lx, naddr=%lx, data_transfer=%d, residual=%d\n", host->host_no, pun, lun, (unsigned long)pAddr, (unsigned long)naddr, data_transfer, residual); - } -#endif - slot->SG[SGcount].pAddr = bS_to_host(pAddr); - } - /* set the executed moves to nops */ - for(i=0; iSG[i].ins = bS_to_host(SCRIPT_NOP); - slot->SG[i].pAddr = 0; - } - dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG), DMA_TO_DEVICE); - /* and pretend we disconnected after - * the command phase */ - resume_offset = hostdata->pScript + Ent_MsgInDuringData; - /* make sure all the data is flushed */ - NCR_700_flush_fifo(host); - } else { - __u8 sbcl = NCR_700_readb(host, SBCL_REG); - printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n", - host->host_no, pun, lun, dsp - hostdata->pScript, sbcl_to_string(sbcl)); - NCR_700_internal_bus_reset(host); - } - - } else if(sstat0 & SCSI_GROSS_ERROR) { - printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n", - host->host_no, pun, lun); - NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); - } else if(sstat0 & PARITY_ERROR) { - printk(KERN_ERR "scsi%d: (%d:%d) PARITY ERROR\n", - host->host_no, pun, lun); - NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); - } else if(dstat & SCRIPT_INT_RECEIVED) { - DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n", - host->host_no, pun, lun)); - resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata); - } else if(dstat & (ILGL_INST_DETECTED)) { - printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%08x[0x%x]!!!\n" - " Please email James.Bottomley@HansenPartnership.com with the details\n", - host->host_no, pun, lun, - dsp, dsp - hostdata->pScript); - NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); - } else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) { - printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n", - host->host_no, pun, lun, dstat); - NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16); - } - - - /* NOTE: selection interrupt processing MUST occur - * after script interrupt processing to correctly cope - * with the case where we process a disconnect and - * then get reselected before we process the - * disconnection */ - if(sstat0 & SELECTED) { - /* FIXME: It currently takes at least FOUR - * interrupts to complete a command that - * disconnects: one for the disconnect, one - * for the reselection, one to get the - * reselection data and one to complete the - * command. If we guess the reselected - * command here and prepare it, we only need - * to get a reselection data interrupt if we - * guessed wrongly. Since the interrupt - * overhead is much greater than the command - * setup, this would be an efficient - * optimisation particularly as we probably - * only have one outstanding command on a - * target most of the time */ - - resume_offset = process_selection(host, dsp); - - } - - } - - if(resume_offset) { - if(hostdata->state != NCR_700_HOST_BUSY) { - printk(KERN_ERR "scsi%d: Driver error: resume at 0x%08x [0x%04x] with non busy host!\n", - host->host_no, resume_offset, resume_offset - hostdata->pScript); - hostdata->state = NCR_700_HOST_BUSY; - } - - DEBUG(("Attempting to resume at %x\n", resume_offset)); - NCR_700_clear_fifo(host); - NCR_700_writel(resume_offset, host, DSP_REG); - } - /* There is probably a technical no-no about this: If we're a - * shared interrupt and we got this interrupt because the - * other device needs servicing not us, we're still going to - * check our queued commands here---of course, there shouldn't - * be any outstanding.... */ - if(hostdata->state == NCR_700_HOST_FREE) { - int i; - - for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) { - /* fairness: always run the queue from the last - * position we left off */ - int j = (i + hostdata->saved_slot_position) - % NCR_700_COMMAND_SLOTS_PER_HOST; - - if(hostdata->slots[j].state != NCR_700_SLOT_QUEUED) - continue; - if(NCR_700_start_command(hostdata->slots[j].cmnd)) { - DEBUG(("scsi%d: Issuing saved command slot %p, cmd %p\t\n", - host->host_no, &hostdata->slots[j], - hostdata->slots[j].cmnd)); - hostdata->saved_slot_position = j + 1; - } - - break; - } - } - out_unlock: - spin_unlock_irqrestore(host->host_lock, flags); - return IRQ_RETVAL(handled); -} - -static int -NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)) -{ - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; - __u32 move_ins; - enum dma_data_direction direction; - struct NCR_700_command_slot *slot; - - if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) { - /* We're over our allocation, this should never happen - * since we report the max allocation to the mid layer */ - printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->device->host->host_no); - return 1; - } - /* check for untagged commands. We cannot have any outstanding - * commands if we accept them. Commands could be untagged because: - * - * - The tag negotiated bitmap is clear - * - The blk layer sent and untagged command - */ - if(NCR_700_get_depth(SCp->device) != 0 - && (!(hostdata->tag_negotiated & (1<request))) { - CDEBUG(KERN_ERR, SCp, "has non zero depth %d\n", - NCR_700_get_depth(SCp->device)); - return SCSI_MLQUEUE_DEVICE_BUSY; - } - if(NCR_700_get_depth(SCp->device) >= SCp->device->queue_depth) { - CDEBUG(KERN_ERR, SCp, "has max tag depth %d\n", - NCR_700_get_depth(SCp->device)); - return SCSI_MLQUEUE_DEVICE_BUSY; - } - NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) + 1); - - /* begin the command here */ - /* no need to check for NULL, test for command_slot_count above - * ensures a slot is free */ - slot = find_empty_slot(hostdata); - - slot->cmnd = SCp; - - SCp->scsi_done = done; - SCp->host_scribble = (unsigned char *)slot; - SCp->SCp.ptr = NULL; - SCp->SCp.buffer = NULL; - -#ifdef NCR_700_DEBUG - printk("53c700: scsi%d, command ", SCp->device->host->host_no); - scsi_print_command(SCp); -#endif - if(blk_rq_tagged(SCp->request) - && (hostdata->tag_negotiated &(1<device) == NCR_700_START_TAG_NEGOTIATION) { - scmd_printk(KERN_ERR, SCp, "Enabling Tag Command Queuing\n"); - hostdata->tag_negotiated |= (1<device, NCR_700_DURING_TAG_NEGOTIATION); - } - - /* here we may have to process an untagged command. The gate - * above ensures that this will be the only one outstanding, - * so clear the tag negotiated bit. - * - * FIXME: This will royally screw up on multiple LUN devices - * */ - if(!blk_rq_tagged(SCp->request) - && (hostdata->tag_negotiated &(1<tag_negotiated &= ~(1<tag_negotiated &(1<device)) { - slot->tag = SCp->request->tag; - CDEBUG(KERN_DEBUG, SCp, "sending out tag %d, slot %p\n", - slot->tag, slot); - } else { - slot->tag = SCSI_NO_TAG; - /* must populate current_cmnd for scsi_find_tag to work */ - SCp->device->current_cmnd = SCp; - } - /* sanity check: some of the commands generated by the mid-layer - * have an eccentric idea of their sc_data_direction */ - if(!scsi_sg_count(SCp) && !scsi_bufflen(SCp) && - SCp->sc_data_direction != DMA_NONE) { -#ifdef NCR_700_DEBUG - printk("53c700: Command"); - scsi_print_command(SCp); - printk("Has wrong data direction %d\n", SCp->sc_data_direction); -#endif - SCp->sc_data_direction = DMA_NONE; - } - - switch (SCp->cmnd[0]) { - case REQUEST_SENSE: - /* clear the internal sense magic */ - SCp->cmnd[6] = 0; - /* fall through */ - default: - /* OK, get it from the command */ - switch(SCp->sc_data_direction) { - case DMA_BIDIRECTIONAL: - default: - printk(KERN_ERR "53c700: Unknown command for data direction "); - scsi_print_command(SCp); - - move_ins = 0; - break; - case DMA_NONE: - move_ins = 0; - break; - case DMA_FROM_DEVICE: - move_ins = SCRIPT_MOVE_DATA_IN; - break; - case DMA_TO_DEVICE: - move_ins = SCRIPT_MOVE_DATA_OUT; - break; - } - } - - /* now build the scatter gather list */ - direction = SCp->sc_data_direction; - if(move_ins != 0) { - int i; - int sg_count; - dma_addr_t vPtr = 0; - struct scatterlist *sg; - __u32 count = 0; - - sg_count = scsi_dma_map(SCp); - BUG_ON(sg_count < 0); - - scsi_for_each_sg(SCp, sg, sg_count, i) { - vPtr = sg_dma_address(sg); - count = sg_dma_len(sg); - - slot->SG[i].ins = bS_to_host(move_ins | count); - DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n", - i, count, slot->SG[i].ins, (unsigned long)vPtr)); - slot->SG[i].pAddr = bS_to_host(vPtr); - } - slot->SG[i].ins = bS_to_host(SCRIPT_RETURN); - slot->SG[i].pAddr = 0; - dma_cache_sync(hostdata->dev, slot->SG, sizeof(slot->SG), DMA_TO_DEVICE); - DEBUG((" SETTING %08lx to %x\n", - (&slot->pSG[i].ins), - slot->SG[i].ins)); - } - slot->resume_offset = 0; - slot->pCmd = dma_map_single(hostdata->dev, SCp->cmnd, - MAX_COMMAND_SIZE, DMA_TO_DEVICE); - NCR_700_start_command(SCp); - return 0; -} - -STATIC DEF_SCSI_QCMD(NCR_700_queuecommand) - -STATIC int -NCR_700_abort(struct scsi_cmnd * SCp) -{ - struct NCR_700_command_slot *slot; - - scmd_printk(KERN_INFO, SCp, - "New error handler wants to abort command\n\t"); - scsi_print_command(SCp); - - slot = (struct NCR_700_command_slot *)SCp->host_scribble; - - if(slot == NULL) - /* no outstanding command to abort */ - return SUCCESS; - if(SCp->cmnd[0] == TEST_UNIT_READY) { - /* FIXME: This is because of a problem in the new - * error handler. When it is in error recovery, it - * will send a TUR to a device it thinks may still be - * showing a problem. If the TUR isn't responded to, - * it will abort it and mark the device off line. - * Unfortunately, it does no other error recovery, so - * this would leave us with an outstanding command - * occupying a slot. Rather than allow this to - * happen, we issue a bus reset to force all - * outstanding commands to terminate here. */ - NCR_700_internal_bus_reset(SCp->device->host); - /* still drop through and return failed */ - } - return FAILED; - -} - -STATIC int -NCR_700_bus_reset(struct scsi_cmnd * SCp) -{ - DECLARE_COMPLETION_ONSTACK(complete); - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0]; - - scmd_printk(KERN_INFO, SCp, - "New error handler wants BUS reset, cmd %p\n\t", SCp); - scsi_print_command(SCp); - - /* In theory, eh_complete should always be null because the - * eh is single threaded, but just in case we're handling a - * reset via sg or something */ - spin_lock_irq(SCp->device->host->host_lock); - while (hostdata->eh_complete != NULL) { - spin_unlock_irq(SCp->device->host->host_lock); - msleep_interruptible(100); - spin_lock_irq(SCp->device->host->host_lock); - } - - hostdata->eh_complete = &complete; - NCR_700_internal_bus_reset(SCp->device->host); - - spin_unlock_irq(SCp->device->host->host_lock); - wait_for_completion(&complete); - spin_lock_irq(SCp->device->host->host_lock); - - hostdata->eh_complete = NULL; - /* Revalidate the transport parameters of the failing device */ - if(hostdata->fast) - spi_schedule_dv_device(SCp->device); - - spin_unlock_irq(SCp->device->host->host_lock); - return SUCCESS; -} - -STATIC int -NCR_700_host_reset(struct scsi_cmnd * SCp) -{ - scmd_printk(KERN_INFO, SCp, "New error handler wants HOST reset\n\t"); - scsi_print_command(SCp); - - spin_lock_irq(SCp->device->host->host_lock); - - NCR_700_internal_bus_reset(SCp->device->host); - NCR_700_chip_reset(SCp->device->host); - - spin_unlock_irq(SCp->device->host->host_lock); - - return SUCCESS; -} - -STATIC void -NCR_700_set_period(struct scsi_target *STp, int period) -{ - struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent); - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)SHp->hostdata[0]; - - if(!hostdata->fast) - return; - - if(period < hostdata->min_period) - period = hostdata->min_period; - - spi_period(STp) = period; - spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC | - NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); - spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION; -} - -STATIC void -NCR_700_set_offset(struct scsi_target *STp, int offset) -{ - struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent); - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)SHp->hostdata[0]; - int max_offset = hostdata->chip710 - ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET; - - if(!hostdata->fast) - return; - - if(offset > max_offset) - offset = max_offset; - - /* if we're currently async, make sure the period is reasonable */ - if(spi_offset(STp) == 0 && (spi_period(STp) < hostdata->min_period || - spi_period(STp) > 0xff)) - spi_period(STp) = hostdata->min_period; - - spi_offset(STp) = offset; - spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC | - NCR_700_DEV_BEGIN_SYNC_NEGOTIATION); - spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION; -} - -STATIC int -NCR_700_slave_alloc(struct scsi_device *SDp) -{ - SDp->hostdata = kzalloc(sizeof(struct NCR_700_Device_Parameters), - GFP_KERNEL); - - if (!SDp->hostdata) - return -ENOMEM; - - return 0; -} - -STATIC int -NCR_700_slave_configure(struct scsi_device *SDp) -{ - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; - - /* to do here: allocate memory; build a queue_full list */ - if(SDp->tagged_supported) { - scsi_set_tag_type(SDp, MSG_ORDERED_TAG); - scsi_activate_tcq(SDp, NCR_700_DEFAULT_TAGS); - NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); - } else { - /* initialise to default depth */ - scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun); - } - if(hostdata->fast) { - /* Find the correct offset and period via domain validation */ - if (!spi_initial_dv(SDp->sdev_target)) - spi_dv_device(SDp); - } else { - spi_offset(SDp->sdev_target) = 0; - spi_period(SDp->sdev_target) = 0; - } - return 0; -} - -STATIC void -NCR_700_slave_destroy(struct scsi_device *SDp) -{ - kfree(SDp->hostdata); - SDp->hostdata = NULL; -} - -static int -NCR_700_change_queue_depth(struct scsi_device *SDp, int depth, int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (depth > NCR_700_MAX_TAGS) - depth = NCR_700_MAX_TAGS; - - scsi_adjust_queue_depth(SDp, scsi_get_tag_type(SDp), depth); - return depth; -} - -static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type) -{ - int change_tag = ((tag_type ==0 && scsi_get_tag_type(SDp) != 0) - || (tag_type != 0 && scsi_get_tag_type(SDp) == 0)); - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)SDp->host->hostdata[0]; - - scsi_set_tag_type(SDp, tag_type); - - /* We have a global (per target) flag to track whether TCQ is - * enabled, so we'll be turning it off for the entire target here. - * our tag algorithm will fail if we mix tagged and untagged commands, - * so quiesce the device before doing this */ - if (change_tag) - scsi_target_quiesce(SDp->sdev_target); - - if (!tag_type) { - /* shift back to the default unqueued number of commands - * (the user can still raise this) */ - scsi_deactivate_tcq(SDp, SDp->host->cmd_per_lun); - hostdata->tag_negotiated &= ~(1 << sdev_id(SDp)); - } else { - /* Here, we cleared the negotiation flag above, so this - * will force the driver to renegotiate */ - scsi_activate_tcq(SDp, SDp->queue_depth); - if (change_tag) - NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION); - } - if (change_tag) - scsi_target_resume(SDp->sdev_target); - - return tag_type; -} - -static ssize_t -NCR_700_show_active_tags(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *SDp = to_scsi_device(dev); - - return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp)); -} - -static struct device_attribute NCR_700_active_tags_attr = { - .attr = { - .name = "active_tags", - .mode = S_IRUGO, - }, - .show = NCR_700_show_active_tags, -}; - -STATIC struct device_attribute *NCR_700_dev_attrs[] = { - &NCR_700_active_tags_attr, - NULL, -}; - -EXPORT_SYMBOL(NCR_700_detect); -EXPORT_SYMBOL(NCR_700_release); -EXPORT_SYMBOL(NCR_700_intr); - -static struct spi_function_template NCR_700_transport_functions = { - .set_period = NCR_700_set_period, - .show_period = 1, - .set_offset = NCR_700_set_offset, - .show_offset = 1, -}; - -static int __init NCR_700_init(void) -{ - NCR_700_transport_template = spi_attach_transport(&NCR_700_transport_functions); - if(!NCR_700_transport_template) - return -ENODEV; - return 0; -} - -static void __exit NCR_700_exit(void) -{ - spi_release_transport(NCR_700_transport_template); -} - -module_init(NCR_700_init); -module_exit(NCR_700_exit); - diff --git a/ANDROID_3.4.5/drivers/scsi/53c700.h b/ANDROID_3.4.5/drivers/scsi/53c700.h deleted file mode 100644 index e06bdfea..00000000 --- a/ANDROID_3.4.5/drivers/scsi/53c700.h +++ /dev/null @@ -1,524 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ - -/* Driver for 53c700 and 53c700-66 chips from NCR and Symbios - * - * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com - */ - -#ifndef _53C700_H -#define _53C700_H - -#include -#include - -#include -#include - -/* Turn on for general debugging---too verbose for normal use */ -#undef NCR_700_DEBUG -/* Debug the tag queues, checking hash queue allocation and deallocation - * and search for duplicate tags */ -#undef NCR_700_TAG_DEBUG - -#ifdef NCR_700_DEBUG -#define DEBUG(x) printk x -#define DDEBUG(prefix, sdev, fmt, a...) \ - sdev_printk(prefix, sdev, fmt, ##a) -#define CDEBUG(prefix, scmd, fmt, a...) \ - scmd_printk(prefix, scmd, fmt, ##a) -#else -#define DEBUG(x) do {} while (0) -#define DDEBUG(prefix, scmd, fmt, a...) do {} while (0) -#define CDEBUG(prefix, scmd, fmt, a...) do {} while (0) -#endif - -/* The number of available command slots */ -#define NCR_700_COMMAND_SLOTS_PER_HOST 64 -/* The maximum number of Scatter Gathers we allow */ -#define NCR_700_SG_SEGMENTS 32 -/* The maximum number of luns (make this of the form 2^n) */ -#define NCR_700_MAX_LUNS 32 -#define NCR_700_LUN_MASK (NCR_700_MAX_LUNS - 1) -/* Maximum number of tags the driver ever allows per device */ -#define NCR_700_MAX_TAGS 16 -/* Tag depth the driver starts out with (can be altered in sysfs) */ -#define NCR_700_DEFAULT_TAGS 4 -/* This is the default number of commands per LUN in the untagged case. - * two is a good value because it means we can have one command active and - * one command fully prepared and waiting - */ -#define NCR_700_CMD_PER_LUN 2 -/* magic byte identifying an internally generated REQUEST_SENSE command */ -#define NCR_700_INTERNAL_SENSE_MAGIC 0x42 - -struct NCR_700_Host_Parameters; - -/* These are the externally used routines */ -struct Scsi_Host *NCR_700_detect(struct scsi_host_template *, - struct NCR_700_Host_Parameters *, struct device *); -int NCR_700_release(struct Scsi_Host *host); -irqreturn_t NCR_700_intr(int, void *); - - -enum NCR_700_Host_State { - NCR_700_HOST_BUSY, - NCR_700_HOST_FREE, -}; - -struct NCR_700_SG_List { - /* The following is a script fragment to move the buffer onto the - * bus and then link the next fragment or return */ - #define SCRIPT_MOVE_DATA_IN 0x09000000 - #define SCRIPT_MOVE_DATA_OUT 0x08000000 - __u32 ins; - __u32 pAddr; - #define SCRIPT_NOP 0x80000000 - #define SCRIPT_RETURN 0x90080000 -}; - -struct NCR_700_Device_Parameters { - /* space for creating a request sense command. Really, except - * for the annoying SCSI-2 requirement for LUN information in - * cmnd[1], this could be in static storage */ - unsigned char cmnd[MAX_COMMAND_SIZE]; - __u8 depth; -}; - - -/* The SYNC negotiation sequence looks like: - * - * If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the - * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION - * If we get an SDTR reply, work out the SXFER parameters, squirrel - * them away here, clear DEV_BEGIN_SYNC_NEGOTIATION and set - * DEV_NEGOTIATED_SYNC. If we get a REJECT msg, squirrel - * - * - * 0:7 SXFER_REG negotiated value for this device - * 8:15 Current queue depth - * 16 negotiated SYNC flag - * 17 begin SYNC negotiation flag - * 18 device supports tag queueing */ -#define NCR_700_DEV_NEGOTIATED_SYNC (1<<16) -#define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION (1<<17) -#define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19) - -static inline char *NCR_700_get_sense_cmnd(struct scsi_device *SDp) -{ - struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; - - return hostdata->cmnd; -} - -static inline void -NCR_700_set_depth(struct scsi_device *SDp, __u8 depth) -{ - struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; - - hostdata->depth = depth; -} -static inline __u8 -NCR_700_get_depth(struct scsi_device *SDp) -{ - struct NCR_700_Device_Parameters *hostdata = SDp->hostdata; - - return hostdata->depth; -} -static inline int -NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag) -{ - return (spi_flags(SDp->sdev_target) & flag) == flag; -} -static inline int -NCR_700_is_flag_clear(struct scsi_device *SDp, __u32 flag) -{ - return (spi_flags(SDp->sdev_target) & flag) == 0; -} -static inline void -NCR_700_set_flag(struct scsi_device *SDp, __u32 flag) -{ - spi_flags(SDp->sdev_target) |= flag; -} -static inline void -NCR_700_clear_flag(struct scsi_device *SDp, __u32 flag) -{ - spi_flags(SDp->sdev_target) &= ~flag; -} - -enum NCR_700_tag_neg_state { - NCR_700_START_TAG_NEGOTIATION = 0, - NCR_700_DURING_TAG_NEGOTIATION = 1, - NCR_700_FINISHED_TAG_NEGOTIATION = 2, -}; - -static inline enum NCR_700_tag_neg_state -NCR_700_get_tag_neg_state(struct scsi_device *SDp) -{ - return (enum NCR_700_tag_neg_state)((spi_flags(SDp->sdev_target)>>20) & 0x3); -} - -static inline void -NCR_700_set_tag_neg_state(struct scsi_device *SDp, - enum NCR_700_tag_neg_state state) -{ - /* clear the slot */ - spi_flags(SDp->sdev_target) &= ~(0x3 << 20); - spi_flags(SDp->sdev_target) |= ((__u32)state) << 20; -} - -struct NCR_700_command_slot { - struct NCR_700_SG_List SG[NCR_700_SG_SEGMENTS+1]; - struct NCR_700_SG_List *pSG; - #define NCR_700_SLOT_MASK 0xFC - #define NCR_700_SLOT_MAGIC 0xb8 - #define NCR_700_SLOT_FREE (0|NCR_700_SLOT_MAGIC) /* slot may be used */ - #define NCR_700_SLOT_BUSY (1|NCR_700_SLOT_MAGIC) /* slot has command active on HA */ - #define NCR_700_SLOT_QUEUED (2|NCR_700_SLOT_MAGIC) /* slot has command to be made active on HA */ - __u8 state; - #define NCR_700_FLAG_AUTOSENSE 0x01 - __u8 flags; - __u8 pad1[2]; /* Needed for m68k where min alignment is 2 bytes */ - int tag; - __u32 resume_offset; - struct scsi_cmnd *cmnd; - /* The pci_mapped address of the actual command in cmnd */ - dma_addr_t pCmd; - __u32 temp; - /* if this command is a pci_single mapping, holds the dma address - * for later unmapping in the done routine */ - dma_addr_t dma_handle; - /* historical remnant, now used to link free commands */ - struct NCR_700_command_slot *ITL_forw; -}; - -struct NCR_700_Host_Parameters { - /* These must be filled in by the calling driver */ - int clock; /* board clock speed in MHz */ - void __iomem *base; /* the base for the port (copied to host) */ - struct device *dev; - __u32 dmode_extra; /* adjustable bus settings */ - __u32 dcntl_extra; /* adjustable bus settings */ - __u32 ctest7_extra; /* adjustable bus settings */ - __u32 differential:1; /* if we are differential */ -#ifdef CONFIG_53C700_LE_ON_BE - /* This option is for HP only. Set it if your chip is wired for - * little endian on this platform (which is big endian) */ - __u32 force_le_on_be:1; -#endif - __u32 chip710:1; /* set if really a 710 not 700 */ - __u32 burst_length:4; /* set to 0 to disable 710 bursting */ - - /* NOTHING BELOW HERE NEEDS ALTERING */ - __u32 fast:1; /* if we can alter the SCSI bus clock - speed (so can negiotiate sync) */ - int sync_clock; /* The speed of the SYNC core */ - - __u32 *script; /* pointer to script location */ - __u32 pScript; /* physical mem addr of script */ - - enum NCR_700_Host_State state; /* protected by state lock */ - struct scsi_cmnd *cmd; - /* Note: pScript contains the single consistent block of - * memory. All the msgin, msgout and status are allocated in - * this memory too (at separate cache lines). TOTAL_MEM_SIZE - * represents the total size of this area */ -#define MSG_ARRAY_SIZE 8 -#define MSGOUT_OFFSET (L1_CACHE_ALIGN(sizeof(SCRIPT))) - __u8 *msgout; -#define MSGIN_OFFSET (MSGOUT_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE)) - __u8 *msgin; -#define STATUS_OFFSET (MSGIN_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE)) - __u8 *status; -#define SLOTS_OFFSET (STATUS_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE)) - struct NCR_700_command_slot *slots; -#define TOTAL_MEM_SIZE (SLOTS_OFFSET + L1_CACHE_ALIGN(sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST)) - int saved_slot_position; - int command_slot_count; /* protected by state lock */ - __u8 tag_negotiated; - __u8 rev; - __u8 reselection_id; - __u8 min_period; - - /* Free list, singly linked by ITL_forw elements */ - struct NCR_700_command_slot *free_list; - /* Completion for waited for ops, like reset, abort or - * device reset. - * - * NOTE: relies on single threading in the error handler to - * have only one outstanding at once */ - struct completion *eh_complete; -}; - -/* - * 53C700 Register Interface - the offset from the Selected base - * I/O address */ -#ifdef CONFIG_53C700_LE_ON_BE -#define bE (hostdata->force_le_on_be ? 0 : 3) -#define bSWAP (hostdata->force_le_on_be) -#define bEBus (!hostdata->force_le_on_be) -#elif defined(__BIG_ENDIAN) -#define bE 3 -#define bSWAP 0 -#elif defined(__LITTLE_ENDIAN) -#define bE 0 -#define bSWAP 0 -#else -#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined, did you include byteorder.h?" -#endif -#ifndef bEBus -#ifdef CONFIG_53C700_BE_BUS -#define bEBus 1 -#else -#define bEBus 0 -#endif -#endif -#define bS_to_cpu(x) (bSWAP ? le32_to_cpu(x) : (x)) -#define bS_to_host(x) (bSWAP ? cpu_to_le32(x) : (x)) - -/* NOTE: These registers are in the LE register space only, the required byte - * swapping is done by the NCR_700_{read|write}[b] functions */ -#define SCNTL0_REG 0x00 -#define FULL_ARBITRATION 0xc0 -#define PARITY 0x08 -#define ENABLE_PARITY 0x04 -#define AUTO_ATN 0x02 -#define SCNTL1_REG 0x01 -#define SLOW_BUS 0x80 -#define ENABLE_SELECT 0x20 -#define ASSERT_RST 0x08 -#define ASSERT_EVEN_PARITY 0x04 -#define SDID_REG 0x02 -#define SIEN_REG 0x03 -#define PHASE_MM_INT 0x80 -#define FUNC_COMP_INT 0x40 -#define SEL_TIMEOUT_INT 0x20 -#define SELECT_INT 0x10 -#define GROSS_ERR_INT 0x08 -#define UX_DISC_INT 0x04 -#define RST_INT 0x02 -#define PAR_ERR_INT 0x01 -#define SCID_REG 0x04 -#define SXFER_REG 0x05 -#define ASYNC_OPERATION 0x00 -#define SODL_REG 0x06 -#define SOCL_REG 0x07 -#define SFBR_REG 0x08 -#define SIDL_REG 0x09 -#define SBDL_REG 0x0A -#define SBCL_REG 0x0B -/* read bits */ -#define SBCL_IO 0x01 -/*write bits */ -#define SYNC_DIV_AS_ASYNC 0x00 -#define SYNC_DIV_1_0 0x01 -#define SYNC_DIV_1_5 0x02 -#define SYNC_DIV_2_0 0x03 -#define DSTAT_REG 0x0C -#define ILGL_INST_DETECTED 0x01 -#define WATCH_DOG_INTERRUPT 0x02 -#define SCRIPT_INT_RECEIVED 0x04 -#define ABORTED 0x10 -#define SSTAT0_REG 0x0D -#define PARITY_ERROR 0x01 -#define SCSI_RESET_DETECTED 0x02 -#define UNEXPECTED_DISCONNECT 0x04 -#define SCSI_GROSS_ERROR 0x08 -#define SELECTED 0x10 -#define SELECTION_TIMEOUT 0x20 -#define FUNCTION_COMPLETE 0x40 -#define PHASE_MISMATCH 0x80 -#define SSTAT1_REG 0x0E -#define SIDL_REG_FULL 0x80 -#define SODR_REG_FULL 0x40 -#define SODL_REG_FULL 0x20 -#define SSTAT2_REG 0x0F -#define CTEST0_REG 0x14 -#define BTB_TIMER_DISABLE 0x40 -#define CTEST1_REG 0x15 -#define CTEST2_REG 0x16 -#define CTEST3_REG 0x17 -#define CTEST4_REG 0x18 -#define DISABLE_FIFO 0x00 -#define SLBE 0x10 -#define SFWR 0x08 -#define BYTE_LANE0 0x04 -#define BYTE_LANE1 0x05 -#define BYTE_LANE2 0x06 -#define BYTE_LANE3 0x07 -#define SCSI_ZMODE 0x20 -#define ZMODE 0x40 -#define CTEST5_REG 0x19 -#define MASTER_CONTROL 0x10 -#define DMA_DIRECTION 0x08 -#define CTEST7_REG 0x1B -#define BURST_DISABLE 0x80 /* 710 only */ -#define SEL_TIMEOUT_DISABLE 0x10 /* 710 only */ -#define DFP 0x08 -#define EVP 0x04 -#define CTEST7_TT1 0x02 -#define DIFF 0x01 -#define CTEST6_REG 0x1A -#define TEMP_REG 0x1C -#define DFIFO_REG 0x20 -#define FLUSH_DMA_FIFO 0x80 -#define CLR_FIFO 0x40 -#define ISTAT_REG 0x21 -#define ABORT_OPERATION 0x80 -#define SOFTWARE_RESET_710 0x40 -#define DMA_INT_PENDING 0x01 -#define SCSI_INT_PENDING 0x02 -#define CONNECTED 0x08 -#define CTEST8_REG 0x22 -#define LAST_DIS_ENBL 0x01 -#define SHORTEN_FILTERING 0x04 -#define ENABLE_ACTIVE_NEGATION 0x10 -#define GENERATE_RECEIVE_PARITY 0x20 -#define CLR_FIFO_710 0x04 -#define FLUSH_DMA_FIFO_710 0x08 -#define CTEST9_REG 0x23 -#define DBC_REG 0x24 -#define DCMD_REG 0x27 -#define DNAD_REG 0x28 -#define DIEN_REG 0x39 -#define BUS_FAULT 0x20 -#define ABORT_INT 0x10 -#define INT_INST_INT 0x04 -#define WD_INT 0x02 -#define ILGL_INST_INT 0x01 -#define DCNTL_REG 0x3B -#define SOFTWARE_RESET 0x01 -#define COMPAT_700_MODE 0x01 -#define SCRPTS_16BITS 0x20 -#define EA_710 0x20 -#define ASYNC_DIV_2_0 0x00 -#define ASYNC_DIV_1_5 0x40 -#define ASYNC_DIV_1_0 0x80 -#define ASYNC_DIV_3_0 0xc0 -#define DMODE_710_REG 0x38 -#define DMODE_700_REG 0x34 -#define BURST_LENGTH_1 0x00 -#define BURST_LENGTH_2 0x40 -#define BURST_LENGTH_4 0x80 -#define BURST_LENGTH_8 0xC0 -#define DMODE_FC1 0x10 -#define DMODE_FC2 0x20 -#define BW16 32 -#define MODE_286 16 -#define IO_XFER 8 -#define FIXED_ADDR 4 - -#define DSP_REG 0x2C -#define DSPS_REG 0x30 - -/* Parameters to begin SDTR negotiations. Empirically, I find that - * the 53c700-66 cannot handle an offset >8, so don't change this */ -#define NCR_700_MAX_OFFSET 8 -/* Was hoping the max offset would be greater for the 710, but - * empirically it seems to be 8 also */ -#define NCR_710_MAX_OFFSET 8 -#define NCR_700_MIN_XFERP 1 -#define NCR_710_MIN_XFERP 0 -#define NCR_700_MIN_PERIOD 25 /* for SDTR message, 100ns */ - -#define script_patch_32(dev, script, symbol, value) \ -{ \ - int i; \ - for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + value; \ - (script)[A_##symbol##_used[i]] = bS_to_host(val); \ - dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \ - DEBUG((" script, patching %s at %d to 0x%lx\n", \ - #symbol, A_##symbol##_used[i], (value))); \ - } \ -} - -#define script_patch_32_abs(dev, script, symbol, value) \ -{ \ - int i; \ - for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - (script)[A_##symbol##_used[i]] = bS_to_host(value); \ - dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \ - DEBUG((" script, patching %s at %d to 0x%lx\n", \ - #symbol, A_##symbol##_used[i], (value))); \ - } \ -} - -/* Used for patching the SCSI ID in the SELECT instruction */ -#define script_patch_ID(dev, script, symbol, value) \ -{ \ - int i; \ - for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]); \ - val &= 0xff00ffff; \ - val |= ((value) & 0xff) << 16; \ - (script)[A_##symbol##_used[i]] = bS_to_host(val); \ - dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \ - DEBUG((" script, patching ID field %s at %d to 0x%x\n", \ - #symbol, A_##symbol##_used[i], val)); \ - } \ -} - -#define script_patch_16(dev, script, symbol, value) \ -{ \ - int i; \ - for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \ - __u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]); \ - val &= 0xffff0000; \ - val |= ((value) & 0xffff); \ - (script)[A_##symbol##_used[i]] = bS_to_host(val); \ - dma_cache_sync((dev), &(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \ - DEBUG((" script, patching short field %s at %d to 0x%x\n", \ - #symbol, A_##symbol##_used[i], val)); \ - } \ -} - - -static inline __u8 -NCR_700_readb(struct Scsi_Host *host, __u32 reg) -{ - const struct NCR_700_Host_Parameters *hostdata - = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - - return ioread8(hostdata->base + (reg^bE)); -} - -static inline __u32 -NCR_700_readl(struct Scsi_Host *host, __u32 reg) -{ - const struct NCR_700_Host_Parameters *hostdata - = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - __u32 value = bEBus ? ioread32be(hostdata->base + reg) : - ioread32(hostdata->base + reg); -#if 1 - /* sanity check the register */ - BUG_ON((reg & 0x3) != 0); -#endif - - return value; -} - -static inline void -NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg) -{ - const struct NCR_700_Host_Parameters *hostdata - = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - - iowrite8(value, hostdata->base + (reg^bE)); -} - -static inline void -NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg) -{ - const struct NCR_700_Host_Parameters *hostdata - = (struct NCR_700_Host_Parameters *)host->hostdata[0]; - -#if 1 - /* sanity check the register */ - BUG_ON((reg & 0x3) != 0); -#endif - - bEBus ? iowrite32be(value, hostdata->base + reg): - iowrite32(value, hostdata->base + reg); -} - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/53c700.scr b/ANDROID_3.4.5/drivers/scsi/53c700.scr deleted file mode 100644 index ec822e3b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/53c700.scr +++ /dev/null @@ -1,411 +0,0 @@ -; Script for the NCR (or symbios) 53c700 and 53c700-66 chip -; -; Copyright (C) 2001 James.Bottomley@HansenPartnership.com -;;----------------------------------------------------------------------------- -;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2 of the License, or -;; (at your option) any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -;; -;;----------------------------------------------------------------------------- -; -; This script is designed to be modified for the particular command in -; operation. The particular variables pertaining to the commands are: -; -ABSOLUTE Device_ID = 0 ; ID of target for command -ABSOLUTE MessageCount = 0 ; Number of bytes in message -ABSOLUTE MessageLocation = 0 ; Addr of message -ABSOLUTE CommandCount = 0 ; Number of bytes in command -ABSOLUTE CommandAddress = 0 ; Addr of Command -ABSOLUTE StatusAddress = 0 ; Addr to receive status return -ABSOLUTE ReceiveMsgAddress = 0 ; Addr to receive msg -; -; This is the magic component for handling scatter-gather. Each of the -; SG components is preceded by a script fragment which moves the -; necessary amount of data and jumps to the next SG segment. The final -; SG segment jumps back to . However, this address is the first SG script -; segment. -; -ABSOLUTE SGScriptStartAddress = 0 - -; The following represent status interrupts we use 3 hex digits for -; this: 0xPRS where - -; P: -ABSOLUTE AFTER_SELECTION = 0x100 -ABSOLUTE BEFORE_CMD = 0x200 -ABSOLUTE AFTER_CMD = 0x300 -ABSOLUTE AFTER_STATUS = 0x400 -ABSOLUTE AFTER_DATA_IN = 0x500 -ABSOLUTE AFTER_DATA_OUT = 0x600 -ABSOLUTE DURING_DATA_IN = 0x700 - -; R: -ABSOLUTE NOT_MSG_OUT = 0x10 -ABSOLUTE UNEXPECTED_PHASE = 0x20 -ABSOLUTE NOT_MSG_IN = 0x30 -ABSOLUTE UNEXPECTED_MSG = 0x40 -ABSOLUTE MSG_IN = 0x50 -ABSOLUTE SDTR_MSG_R = 0x60 -ABSOLUTE REJECT_MSG_R = 0x70 -ABSOLUTE DISCONNECT = 0x80 -ABSOLUTE MSG_OUT = 0x90 -ABSOLUTE WDTR_MSG_R = 0xA0 - -; S: -ABSOLUTE GOOD_STATUS = 0x1 - -; Combinations, since the script assembler can't process | -ABSOLUTE NOT_MSG_OUT_AFTER_SELECTION = 0x110 -ABSOLUTE UNEXPECTED_PHASE_BEFORE_CMD = 0x220 -ABSOLUTE UNEXPECTED_PHASE_AFTER_CMD = 0x320 -ABSOLUTE NOT_MSG_IN_AFTER_STATUS = 0x430 -ABSOLUTE GOOD_STATUS_AFTER_STATUS = 0x401 -ABSOLUTE UNEXPECTED_PHASE_AFTER_DATA_IN = 0x520 -ABSOLUTE UNEXPECTED_PHASE_AFTER_DATA_OUT = 0x620 -ABSOLUTE UNEXPECTED_MSG_BEFORE_CMD = 0x240 -ABSOLUTE MSG_IN_BEFORE_CMD = 0x250 -ABSOLUTE MSG_IN_AFTER_CMD = 0x350 -ABSOLUTE SDTR_MSG_BEFORE_CMD = 0x260 -ABSOLUTE REJECT_MSG_BEFORE_CMD = 0x270 -ABSOLUTE DISCONNECT_AFTER_CMD = 0x380 -ABSOLUTE SDTR_MSG_AFTER_CMD = 0x360 -ABSOLUTE WDTR_MSG_AFTER_CMD = 0x3A0 -ABSOLUTE MSG_IN_AFTER_STATUS = 0x440 -ABSOLUTE DISCONNECT_AFTER_DATA = 0x580 -ABSOLUTE MSG_IN_AFTER_DATA_IN = 0x550 -ABSOLUTE MSG_IN_AFTER_DATA_OUT = 0x650 -ABSOLUTE MSG_OUT_AFTER_DATA_IN = 0x590 -ABSOLUTE DATA_IN_AFTER_DATA_IN = 0x5a0 -ABSOLUTE MSG_IN_DURING_DATA_IN = 0x750 -ABSOLUTE DISCONNECT_DURING_DATA = 0x780 - -; -; Other interrupt conditions -; -ABSOLUTE RESELECTED_DURING_SELECTION = 0x1000 -ABSOLUTE COMPLETED_SELECTION_AS_TARGET = 0x1001 -ABSOLUTE RESELECTION_IDENTIFIED = 0x1003 -; -; Fatal interrupt conditions. If you add to this, also add to the -; array of corresponding messages -; -ABSOLUTE FATAL = 0x2000 -ABSOLUTE FATAL_UNEXPECTED_RESELECTION_MSG = 0x2000 -ABSOLUTE FATAL_SEND_MSG = 0x2001 -ABSOLUTE FATAL_NOT_MSG_IN_AFTER_SELECTION = 0x2002 -ABSOLUTE FATAL_ILLEGAL_MSG_LENGTH = 0x2003 - -ABSOLUTE DEBUG_INTERRUPT = 0x3000 -ABSOLUTE DEBUG_INTERRUPT1 = 0x3001 -ABSOLUTE DEBUG_INTERRUPT2 = 0x3002 -ABSOLUTE DEBUG_INTERRUPT3 = 0x3003 -ABSOLUTE DEBUG_INTERRUPT4 = 0x3004 -ABSOLUTE DEBUG_INTERRUPT5 = 0x3005 -ABSOLUTE DEBUG_INTERRUPT6 = 0x3006 - - -; -; SCSI Messages we interpret in the script -; -ABSOLUTE COMMAND_COMPLETE_MSG = 0x00 -ABSOLUTE EXTENDED_MSG = 0x01 -ABSOLUTE SDTR_MSG = 0x01 -ABSOLUTE SAVE_DATA_PTRS_MSG = 0x02 -ABSOLUTE RESTORE_DATA_PTRS_MSG = 0x03 -ABSOLUTE WDTR_MSG = 0x03 -ABSOLUTE DISCONNECT_MSG = 0x04 -ABSOLUTE REJECT_MSG = 0x07 -ABSOLUTE PARITY_ERROR_MSG = 0x09 -ABSOLUTE SIMPLE_TAG_MSG = 0x20 -ABSOLUTE IDENTIFY_MSG = 0x80 -ABSOLUTE IDENTIFY_MSG_MASK = 0x7F -ABSOLUTE TWO_BYTE_MSG = 0x20 -ABSOLUTE TWO_BYTE_MSG_MASK = 0x0F - -; This is where the script begins - -ENTRY StartUp - -StartUp: - SELECT ATN Device_ID, Reselect - JUMP Finish, WHEN STATUS - JUMP SendIdentifyMsg, IF MSG_OUT - INT NOT_MSG_OUT_AFTER_SELECTION - -Reselect: - WAIT RESELECT SelectedAsTarget - INT RESELECTED_DURING_SELECTION, WHEN MSG_IN - INT FATAL_NOT_MSG_IN_AFTER_SELECTION - - ENTRY GetReselectionData -GetReselectionData: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - INT RESELECTION_IDENTIFIED - - ENTRY GetReselectionWithTag -GetReselectionWithTag: - MOVE 3, ReceiveMsgAddress, WHEN MSG_IN - INT RESELECTION_IDENTIFIED - - ENTRY SelectedAsTarget -SelectedAsTarget: -; Basically tell the selecting device that there's nothing here - SET TARGET - DISCONNECT - CLEAR TARGET - INT COMPLETED_SELECTION_AS_TARGET -; -; These are the messaging entries -; -; Send a message. Message count should be correctly patched - ENTRY SendMessage -SendMessage: - MOVE MessageCount, MessageLocation, WHEN MSG_OUT -ResumeSendMessage: - RETURN, WHEN NOT MSG_OUT - INT FATAL_SEND_MSG - - ENTRY SendMessagePhaseMismatch -SendMessagePhaseMismatch: - CLEAR ACK - JUMP ResumeSendMessage -; -; Receive a message. Need to identify the message to -; receive it correctly - ENTRY ReceiveMessage -ReceiveMessage: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN -; -; Use this entry if we've just tried to look at the first byte -; of the message and want to process it further -ProcessReceiveMessage: - JUMP ReceiveExtendedMessage, IF EXTENDED_MSG - RETURN, IF NOT TWO_BYTE_MSG, AND MASK TWO_BYTE_MSG_MASK - CLEAR ACK - MOVE 1, ReceiveMsgAddress + 1, WHEN MSG_IN - RETURN -ReceiveExtendedMessage: - CLEAR ACK - MOVE 1, ReceiveMsgAddress + 1, WHEN MSG_IN - JUMP Receive1Byte, IF 0x01 - JUMP Receive2Byte, IF 0x02 - JUMP Receive3Byte, IF 0x03 - JUMP Receive4Byte, IF 0x04 - JUMP Receive5Byte, IF 0x05 - INT FATAL_ILLEGAL_MSG_LENGTH -Receive1Byte: - CLEAR ACK - MOVE 1, ReceiveMsgAddress + 2, WHEN MSG_IN - RETURN -Receive2Byte: - CLEAR ACK - MOVE 2, ReceiveMsgAddress + 2, WHEN MSG_IN - RETURN -Receive3Byte: - CLEAR ACK - MOVE 3, ReceiveMsgAddress + 2, WHEN MSG_IN - RETURN -Receive4Byte: - CLEAR ACK - MOVE 4, ReceiveMsgAddress + 2, WHEN MSG_IN - RETURN -Receive5Byte: - CLEAR ACK - MOVE 5, ReceiveMsgAddress + 2, WHEN MSG_IN - RETURN -; -; Come here from the message processor to ignore the message -; - ENTRY IgnoreMessage -IgnoreMessage: - CLEAR ACK - RETURN -; -; Come here to send a reply to a message -; - ENTRY SendMessageWithATN -SendMessageWithATN: - SET ATN - CLEAR ACK - JUMP SendMessage - -SendIdentifyMsg: - CALL SendMessage - CLEAR ATN - -IgnoreMsgBeforeCommand: - CLEAR ACK - ENTRY SendCommand -SendCommand: - JUMP Finish, WHEN STATUS - JUMP MsgInBeforeCommand, IF MSG_IN - INT UNEXPECTED_PHASE_BEFORE_CMD, IF NOT CMD - MOVE CommandCount, CommandAddress, WHEN CMD -ResumeSendCommand: - JUMP Finish, WHEN STATUS - JUMP MsgInAfterCmd, IF MSG_IN - JUMP DataIn, IF DATA_IN - JUMP DataOut, IF DATA_OUT - INT UNEXPECTED_PHASE_AFTER_CMD - -IgnoreMsgDuringData: - CLEAR ACK - ; fall through to MsgInDuringData - -Entry MsgInDuringData -MsgInDuringData: -; -; Could be we have nothing more to transfer -; - JUMP Finish, WHEN STATUS - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - JUMP DisconnectDuringDataIn, IF DISCONNECT_MSG - JUMP IgnoreMsgDuringData, IF SAVE_DATA_PTRS_MSG - JUMP IgnoreMsgDuringData, IF RESTORE_DATA_PTRS_MSG - INT MSG_IN_DURING_DATA_IN - -MsgInAfterCmd: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - JUMP DisconnectAfterCmd, IF DISCONNECT_MSG - JUMP IgnoreMsgInAfterCmd, IF SAVE_DATA_PTRS_MSG - JUMP IgnoreMsgInAfterCmd, IF RESTORE_DATA_PTRS_MSG - CALL ProcessReceiveMessage - INT MSG_IN_AFTER_CMD - CLEAR ACK - JUMP ResumeSendCommand - -IgnoreMsgInAfterCmd: - CLEAR ACK - JUMP ResumeSendCommand - -DisconnectAfterCmd: - CLEAR ACK - WAIT DISCONNECT - ENTRY Disconnect1 -Disconnect1: - INT DISCONNECT_AFTER_CMD - ENTRY Disconnect2 -Disconnect2: -; We return here after a reselection - CLEAR ACK - JUMP ResumeSendCommand - -MsgInBeforeCommand: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - JUMP IgnoreMsgBeforeCommand, IF SAVE_DATA_PTRS_MSG - JUMP IgnoreMsgBeforeCommand, IF RESTORE_DATA_PTRS_MSG - CALL ProcessReceiveMessage - INT MSG_IN_BEFORE_CMD - CLEAR ACK - JUMP SendCommand - -DataIn: - CALL SGScriptStartAddress -ResumeDataIn: - JUMP Finish, WHEN STATUS - JUMP MsgInAfterDataIn, IF MSG_IN - JUMP DataInAfterDataIn, if DATA_IN - INT MSG_OUT_AFTER_DATA_IN, if MSG_OUT - INT UNEXPECTED_PHASE_AFTER_DATA_IN - -DataInAfterDataIn: - INT DATA_IN_AFTER_DATA_IN - JUMP ResumeDataIn - -DataOut: - CALL SGScriptStartAddress -ResumeDataOut: - JUMP Finish, WHEN STATUS - JUMP MsgInAfterDataOut, IF MSG_IN - INT UNEXPECTED_PHASE_AFTER_DATA_OUT - -MsgInAfterDataIn: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - JUMP DisconnectAfterDataIn, IF DISCONNECT_MSG - JUMP IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG - JUMP IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG - CALL ProcessReceiveMessage - INT MSG_IN_AFTER_DATA_IN - CLEAR ACK - JUMP ResumeDataIn - -DisconnectDuringDataIn: - CLEAR ACK - WAIT DISCONNECT - ENTRY Disconnect3 -Disconnect3: - INT DISCONNECT_DURING_DATA - ENTRY Disconnect4 -Disconnect4: -; we return here after a reselection - CLEAR ACK - JUMP ResumeSendCommand - - -DisconnectAfterDataIn: - CLEAR ACK - WAIT DISCONNECT - ENTRY Disconnect5 -Disconnect5: - INT DISCONNECT_AFTER_DATA - ENTRY Disconnect6 -Disconnect6: -; we return here after a reselection - CLEAR ACK - JUMP ResumeDataIn - -MsgInAfterDataOut: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - JUMP DisconnectAfterDataOut, if DISCONNECT_MSG - JUMP IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG - JUMP IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG - CALL ProcessReceiveMessage - INT MSG_IN_AFTER_DATA_OUT - CLEAR ACK - JUMP ResumeDataOut - -IgnoreMsgAfterData: - CLEAR ACK -; Data in and out do the same thing on resume, so pick one - JUMP ResumeDataIn - -DisconnectAfterDataOut: - CLEAR ACK - WAIT DISCONNECT - ENTRY Disconnect7 -Disconnect7: - INT DISCONNECT_AFTER_DATA - ENTRY Disconnect8 -Disconnect8: -; we return here after a reselection - CLEAR ACK - JUMP ResumeDataOut - -Finish: - MOVE 1, StatusAddress, WHEN STATUS - INT NOT_MSG_IN_AFTER_STATUS, WHEN NOT MSG_IN - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - JUMP FinishCommandComplete, IF COMMAND_COMPLETE_MSG - CALL ProcessReceiveMessage - INT MSG_IN_AFTER_STATUS - ENTRY FinishCommandComplete -FinishCommandComplete: - CLEAR ACK - WAIT DISCONNECT - ENTRY Finish1 -Finish1: - INT GOOD_STATUS_AFTER_STATUS - ENTRY Finish2 -Finish2: - diff --git a/ANDROID_3.4.5/drivers/scsi/53c700_d.h_shipped b/ANDROID_3.4.5/drivers/scsi/53c700_d.h_shipped deleted file mode 100644 index aa623da3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/53c700_d.h_shipped +++ /dev/null @@ -1,1329 +0,0 @@ -/* DO NOT EDIT - Generated automatically by script_asm.pl */ -static u32 SCRIPT[] = { -/* -; Script for the NCR (or symbios) 53c700 and 53c700-66 chip -; -; Copyright (C) 2001 James.Bottomley@HansenPartnership.com -;;----------------------------------------------------------------------------- -;; -;; This program is free software; you can redistribute it and/or modify -;; it under the terms of the GNU General Public License as published by -;; the Free Software Foundation; either version 2 of the License, or -;; (at your option) any later version. -;; -;; This program is distributed in the hope that it will be useful, -;; but WITHOUT ANY WARRANTY; without even the implied warranty of -;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -;; GNU General Public License for more details. -;; -;; You should have received a copy of the GNU General Public License -;; along with this program; if not, write to the Free Software -;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -;; -;;----------------------------------------------------------------------------- -; -; This script is designed to be modified for the particular command in -; operation. The particular variables pertaining to the commands are: -; -ABSOLUTE Device_ID = 0 ; ID of target for command -ABSOLUTE MessageCount = 0 ; Number of bytes in message -ABSOLUTE MessageLocation = 0 ; Addr of message -ABSOLUTE CommandCount = 0 ; Number of bytes in command -ABSOLUTE CommandAddress = 0 ; Addr of Command -ABSOLUTE StatusAddress = 0 ; Addr to receive status return -ABSOLUTE ReceiveMsgAddress = 0 ; Addr to receive msg -; -; This is the magic component for handling scatter-gather. Each of the -; SG components is preceded by a script fragment which moves the -; necessary amount of data and jumps to the next SG segment. The final -; SG segment jumps back to . However, this address is the first SG script -; segment. -; -ABSOLUTE SGScriptStartAddress = 0 - -; The following represent status interrupts we use 3 hex digits for -; this: 0xPRS where - -; P: -ABSOLUTE AFTER_SELECTION = 0x100 -ABSOLUTE BEFORE_CMD = 0x200 -ABSOLUTE AFTER_CMD = 0x300 -ABSOLUTE AFTER_STATUS = 0x400 -ABSOLUTE AFTER_DATA_IN = 0x500 -ABSOLUTE AFTER_DATA_OUT = 0x600 -ABSOLUTE DURING_DATA_IN = 0x700 - -; R: -ABSOLUTE NOT_MSG_OUT = 0x10 -ABSOLUTE UNEXPECTED_PHASE = 0x20 -ABSOLUTE NOT_MSG_IN = 0x30 -ABSOLUTE UNEXPECTED_MSG = 0x40 -ABSOLUTE MSG_IN = 0x50 -ABSOLUTE SDTR_MSG_R = 0x60 -ABSOLUTE REJECT_MSG_R = 0x70 -ABSOLUTE DISCONNECT = 0x80 -ABSOLUTE MSG_OUT = 0x90 -ABSOLUTE WDTR_MSG_R = 0xA0 - -; S: -ABSOLUTE GOOD_STATUS = 0x1 - -; Combinations, since the script assembler can't process | -ABSOLUTE NOT_MSG_OUT_AFTER_SELECTION = 0x110 -ABSOLUTE UNEXPECTED_PHASE_BEFORE_CMD = 0x220 -ABSOLUTE UNEXPECTED_PHASE_AFTER_CMD = 0x320 -ABSOLUTE NOT_MSG_IN_AFTER_STATUS = 0x430 -ABSOLUTE GOOD_STATUS_AFTER_STATUS = 0x401 -ABSOLUTE UNEXPECTED_PHASE_AFTER_DATA_IN = 0x520 -ABSOLUTE UNEXPECTED_PHASE_AFTER_DATA_OUT = 0x620 -ABSOLUTE UNEXPECTED_MSG_BEFORE_CMD = 0x240 -ABSOLUTE MSG_IN_BEFORE_CMD = 0x250 -ABSOLUTE MSG_IN_AFTER_CMD = 0x350 -ABSOLUTE SDTR_MSG_BEFORE_CMD = 0x260 -ABSOLUTE REJECT_MSG_BEFORE_CMD = 0x270 -ABSOLUTE DISCONNECT_AFTER_CMD = 0x380 -ABSOLUTE SDTR_MSG_AFTER_CMD = 0x360 -ABSOLUTE WDTR_MSG_AFTER_CMD = 0x3A0 -ABSOLUTE MSG_IN_AFTER_STATUS = 0x440 -ABSOLUTE DISCONNECT_AFTER_DATA = 0x580 -ABSOLUTE MSG_IN_AFTER_DATA_IN = 0x550 -ABSOLUTE MSG_IN_AFTER_DATA_OUT = 0x650 -ABSOLUTE MSG_OUT_AFTER_DATA_IN = 0x590 -ABSOLUTE DATA_IN_AFTER_DATA_IN = 0x5a0 -ABSOLUTE MSG_IN_DURING_DATA_IN = 0x750 -ABSOLUTE DISCONNECT_DURING_DATA = 0x780 - -; -; Other interrupt conditions -; -ABSOLUTE RESELECTED_DURING_SELECTION = 0x1000 -ABSOLUTE COMPLETED_SELECTION_AS_TARGET = 0x1001 -ABSOLUTE RESELECTION_IDENTIFIED = 0x1003 -; -; Fatal interrupt conditions. If you add to this, also add to the -; array of corresponding messages -; -ABSOLUTE FATAL = 0x2000 -ABSOLUTE FATAL_UNEXPECTED_RESELECTION_MSG = 0x2000 -ABSOLUTE FATAL_SEND_MSG = 0x2001 -ABSOLUTE FATAL_NOT_MSG_IN_AFTER_SELECTION = 0x2002 -ABSOLUTE FATAL_ILLEGAL_MSG_LENGTH = 0x2003 - -ABSOLUTE DEBUG_INTERRUPT = 0x3000 -ABSOLUTE DEBUG_INTERRUPT1 = 0x3001 -ABSOLUTE DEBUG_INTERRUPT2 = 0x3002 -ABSOLUTE DEBUG_INTERRUPT3 = 0x3003 -ABSOLUTE DEBUG_INTERRUPT4 = 0x3004 -ABSOLUTE DEBUG_INTERRUPT5 = 0x3005 -ABSOLUTE DEBUG_INTERRUPT6 = 0x3006 - - -; -; SCSI Messages we interpret in the script -; -ABSOLUTE COMMAND_COMPLETE_MSG = 0x00 -ABSOLUTE EXTENDED_MSG = 0x01 -ABSOLUTE SDTR_MSG = 0x01 -ABSOLUTE SAVE_DATA_PTRS_MSG = 0x02 -ABSOLUTE RESTORE_DATA_PTRS_MSG = 0x03 -ABSOLUTE WDTR_MSG = 0x03 -ABSOLUTE DISCONNECT_MSG = 0x04 -ABSOLUTE REJECT_MSG = 0x07 -ABSOLUTE PARITY_ERROR_MSG = 0x09 -ABSOLUTE SIMPLE_TAG_MSG = 0x20 -ABSOLUTE IDENTIFY_MSG = 0x80 -ABSOLUTE IDENTIFY_MSG_MASK = 0x7F -ABSOLUTE TWO_BYTE_MSG = 0x20 -ABSOLUTE TWO_BYTE_MSG_MASK = 0x0F - -; This is where the script begins - -ENTRY StartUp - -StartUp: - SELECT ATN Device_ID, Reselect - -at 0x00000000 : */ 0x41000000,0x00000020, -/* - JUMP Finish, WHEN STATUS - -at 0x00000002 : */ 0x830b0000,0x00000460, -/* - JUMP SendIdentifyMsg, IF MSG_OUT - -at 0x00000004 : */ 0x860a0000,0x000001b0, -/* - INT NOT_MSG_OUT_AFTER_SELECTION - -at 0x00000006 : */ 0x98080000,0x00000110, -/* - -Reselect: - WAIT RESELECT SelectedAsTarget - -at 0x00000008 : */ 0x50000000,0x00000058, -/* - INT RESELECTED_DURING_SELECTION, WHEN MSG_IN - -at 0x0000000a : */ 0x9f0b0000,0x00001000, -/* - INT FATAL_NOT_MSG_IN_AFTER_SELECTION - -at 0x0000000c : */ 0x98080000,0x00002002, -/* - - ENTRY GetReselectionData -GetReselectionData: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - -at 0x0000000e : */ 0x0f000001,0x00000000, -/* - INT RESELECTION_IDENTIFIED - -at 0x00000010 : */ 0x98080000,0x00001003, -/* - - ENTRY GetReselectionWithTag -GetReselectionWithTag: - MOVE 3, ReceiveMsgAddress, WHEN MSG_IN - -at 0x00000012 : */ 0x0f000003,0x00000000, -/* - INT RESELECTION_IDENTIFIED - -at 0x00000014 : */ 0x98080000,0x00001003, -/* - - ENTRY SelectedAsTarget -SelectedAsTarget: -; Basically tell the selecting device that there's nothing here - SET TARGET - -at 0x00000016 : */ 0x58000200,0x00000000, -/* - DISCONNECT - -at 0x00000018 : */ 0x48000000,0x00000000, -/* - CLEAR TARGET - -at 0x0000001a : */ 0x60000200,0x00000000, -/* - INT COMPLETED_SELECTION_AS_TARGET - -at 0x0000001c : */ 0x98080000,0x00001001, -/* -; -; These are the messaging entries -; -; Send a message. Message count should be correctly patched - ENTRY SendMessage -SendMessage: - MOVE MessageCount, MessageLocation, WHEN MSG_OUT - -at 0x0000001e : */ 0x0e000000,0x00000000, -/* -ResumeSendMessage: - RETURN, WHEN NOT MSG_OUT - -at 0x00000020 : */ 0x96030000,0x00000000, -/* - INT FATAL_SEND_MSG - -at 0x00000022 : */ 0x98080000,0x00002001, -/* - - ENTRY SendMessagePhaseMismatch -SendMessagePhaseMismatch: - CLEAR ACK - -at 0x00000024 : */ 0x60000040,0x00000000, -/* - JUMP ResumeSendMessage - -at 0x00000026 : */ 0x80080000,0x00000080, -/* -; -; Receive a message. Need to identify the message to -; receive it correctly - ENTRY ReceiveMessage -ReceiveMessage: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - -at 0x00000028 : */ 0x0f000001,0x00000000, -/* -; -; Use this entry if we've just tried to look at the first byte -; of the message and want to process it further -ProcessReceiveMessage: - JUMP ReceiveExtendedMessage, IF EXTENDED_MSG - -at 0x0000002a : */ 0x800c0001,0x000000d0, -/* - RETURN, IF NOT TWO_BYTE_MSG, AND MASK TWO_BYTE_MSG_MASK - -at 0x0000002c : */ 0x90040f20,0x00000000, -/* - CLEAR ACK - -at 0x0000002e : */ 0x60000040,0x00000000, -/* - MOVE 1, ReceiveMsgAddress + 1, WHEN MSG_IN - -at 0x00000030 : */ 0x0f000001,0x00000001, -/* - RETURN - -at 0x00000032 : */ 0x90080000,0x00000000, -/* -ReceiveExtendedMessage: - CLEAR ACK - -at 0x00000034 : */ 0x60000040,0x00000000, -/* - MOVE 1, ReceiveMsgAddress + 1, WHEN MSG_IN - -at 0x00000036 : */ 0x0f000001,0x00000001, -/* - JUMP Receive1Byte, IF 0x01 - -at 0x00000038 : */ 0x800c0001,0x00000110, -/* - JUMP Receive2Byte, IF 0x02 - -at 0x0000003a : */ 0x800c0002,0x00000128, -/* - JUMP Receive3Byte, IF 0x03 - -at 0x0000003c : */ 0x800c0003,0x00000140, -/* - JUMP Receive4Byte, IF 0x04 - -at 0x0000003e : */ 0x800c0004,0x00000158, -/* - JUMP Receive5Byte, IF 0x05 - -at 0x00000040 : */ 0x800c0005,0x00000170, -/* - INT FATAL_ILLEGAL_MSG_LENGTH - -at 0x00000042 : */ 0x98080000,0x00002003, -/* -Receive1Byte: - CLEAR ACK - -at 0x00000044 : */ 0x60000040,0x00000000, -/* - MOVE 1, ReceiveMsgAddress + 2, WHEN MSG_IN - -at 0x00000046 : */ 0x0f000001,0x00000002, -/* - RETURN - -at 0x00000048 : */ 0x90080000,0x00000000, -/* -Receive2Byte: - CLEAR ACK - -at 0x0000004a : */ 0x60000040,0x00000000, -/* - MOVE 2, ReceiveMsgAddress + 2, WHEN MSG_IN - -at 0x0000004c : */ 0x0f000002,0x00000002, -/* - RETURN - -at 0x0000004e : */ 0x90080000,0x00000000, -/* -Receive3Byte: - CLEAR ACK - -at 0x00000050 : */ 0x60000040,0x00000000, -/* - MOVE 3, ReceiveMsgAddress + 2, WHEN MSG_IN - -at 0x00000052 : */ 0x0f000003,0x00000002, -/* - RETURN - -at 0x00000054 : */ 0x90080000,0x00000000, -/* -Receive4Byte: - CLEAR ACK - -at 0x00000056 : */ 0x60000040,0x00000000, -/* - MOVE 4, ReceiveMsgAddress + 2, WHEN MSG_IN - -at 0x00000058 : */ 0x0f000004,0x00000002, -/* - RETURN - -at 0x0000005a : */ 0x90080000,0x00000000, -/* -Receive5Byte: - CLEAR ACK - -at 0x0000005c : */ 0x60000040,0x00000000, -/* - MOVE 5, ReceiveMsgAddress + 2, WHEN MSG_IN - -at 0x0000005e : */ 0x0f000005,0x00000002, -/* - RETURN - -at 0x00000060 : */ 0x90080000,0x00000000, -/* -; -; Come here from the message processor to ignore the message -; - ENTRY IgnoreMessage -IgnoreMessage: - CLEAR ACK - -at 0x00000062 : */ 0x60000040,0x00000000, -/* - RETURN - -at 0x00000064 : */ 0x90080000,0x00000000, -/* -; -; Come here to send a reply to a message -; - ENTRY SendMessageWithATN -SendMessageWithATN: - SET ATN - -at 0x00000066 : */ 0x58000008,0x00000000, -/* - CLEAR ACK - -at 0x00000068 : */ 0x60000040,0x00000000, -/* - JUMP SendMessage - -at 0x0000006a : */ 0x80080000,0x00000078, -/* - -SendIdentifyMsg: - CALL SendMessage - -at 0x0000006c : */ 0x88080000,0x00000078, -/* - CLEAR ATN - -at 0x0000006e : */ 0x60000008,0x00000000, -/* - -IgnoreMsgBeforeCommand: - CLEAR ACK - -at 0x00000070 : */ 0x60000040,0x00000000, -/* - ENTRY SendCommand -SendCommand: - JUMP Finish, WHEN STATUS - -at 0x00000072 : */ 0x830b0000,0x00000460, -/* - JUMP MsgInBeforeCommand, IF MSG_IN - -at 0x00000074 : */ 0x870a0000,0x000002c0, -/* - INT UNEXPECTED_PHASE_BEFORE_CMD, IF NOT CMD - -at 0x00000076 : */ 0x9a020000,0x00000220, -/* - MOVE CommandCount, CommandAddress, WHEN CMD - -at 0x00000078 : */ 0x0a000000,0x00000000, -/* -ResumeSendCommand: - JUMP Finish, WHEN STATUS - -at 0x0000007a : */ 0x830b0000,0x00000460, -/* - JUMP MsgInAfterCmd, IF MSG_IN - -at 0x0000007c : */ 0x870a0000,0x00000248, -/* - JUMP DataIn, IF DATA_IN - -at 0x0000007e : */ 0x810a0000,0x000002f8, -/* - JUMP DataOut, IF DATA_OUT - -at 0x00000080 : */ 0x800a0000,0x00000338, -/* - INT UNEXPECTED_PHASE_AFTER_CMD - -at 0x00000082 : */ 0x98080000,0x00000320, -/* - -IgnoreMsgDuringData: - CLEAR ACK - -at 0x00000084 : */ 0x60000040,0x00000000, -/* - ; fall through to MsgInDuringData - -Entry MsgInDuringData -MsgInDuringData: -; -; Could be we have nothing more to transfer -; - JUMP Finish, WHEN STATUS - -at 0x00000086 : */ 0x830b0000,0x00000460, -/* - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - -at 0x00000088 : */ 0x0f000001,0x00000000, -/* - JUMP DisconnectDuringDataIn, IF DISCONNECT_MSG - -at 0x0000008a : */ 0x800c0004,0x00000398, -/* - JUMP IgnoreMsgDuringData, IF SAVE_DATA_PTRS_MSG - -at 0x0000008c : */ 0x800c0002,0x00000210, -/* - JUMP IgnoreMsgDuringData, IF RESTORE_DATA_PTRS_MSG - -at 0x0000008e : */ 0x800c0003,0x00000210, -/* - INT MSG_IN_DURING_DATA_IN - -at 0x00000090 : */ 0x98080000,0x00000750, -/* - -MsgInAfterCmd: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - -at 0x00000092 : */ 0x0f000001,0x00000000, -/* - JUMP DisconnectAfterCmd, IF DISCONNECT_MSG - -at 0x00000094 : */ 0x800c0004,0x00000298, -/* - JUMP IgnoreMsgInAfterCmd, IF SAVE_DATA_PTRS_MSG - -at 0x00000096 : */ 0x800c0002,0x00000288, -/* - JUMP IgnoreMsgInAfterCmd, IF RESTORE_DATA_PTRS_MSG - -at 0x00000098 : */ 0x800c0003,0x00000288, -/* - CALL ProcessReceiveMessage - -at 0x0000009a : */ 0x88080000,0x000000a8, -/* - INT MSG_IN_AFTER_CMD - -at 0x0000009c : */ 0x98080000,0x00000350, -/* - CLEAR ACK - -at 0x0000009e : */ 0x60000040,0x00000000, -/* - JUMP ResumeSendCommand - -at 0x000000a0 : */ 0x80080000,0x000001e8, -/* - -IgnoreMsgInAfterCmd: - CLEAR ACK - -at 0x000000a2 : */ 0x60000040,0x00000000, -/* - JUMP ResumeSendCommand - -at 0x000000a4 : */ 0x80080000,0x000001e8, -/* - -DisconnectAfterCmd: - CLEAR ACK - -at 0x000000a6 : */ 0x60000040,0x00000000, -/* - WAIT DISCONNECT - -at 0x000000a8 : */ 0x48000000,0x00000000, -/* - ENTRY Disconnect1 -Disconnect1: - INT DISCONNECT_AFTER_CMD - -at 0x000000aa : */ 0x98080000,0x00000380, -/* - ENTRY Disconnect2 -Disconnect2: -; We return here after a reselection - CLEAR ACK - -at 0x000000ac : */ 0x60000040,0x00000000, -/* - JUMP ResumeSendCommand - -at 0x000000ae : */ 0x80080000,0x000001e8, -/* - -MsgInBeforeCommand: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - -at 0x000000b0 : */ 0x0f000001,0x00000000, -/* - JUMP IgnoreMsgBeforeCommand, IF SAVE_DATA_PTRS_MSG - -at 0x000000b2 : */ 0x800c0002,0x000001c0, -/* - JUMP IgnoreMsgBeforeCommand, IF RESTORE_DATA_PTRS_MSG - -at 0x000000b4 : */ 0x800c0003,0x000001c0, -/* - CALL ProcessReceiveMessage - -at 0x000000b6 : */ 0x88080000,0x000000a8, -/* - INT MSG_IN_BEFORE_CMD - -at 0x000000b8 : */ 0x98080000,0x00000250, -/* - CLEAR ACK - -at 0x000000ba : */ 0x60000040,0x00000000, -/* - JUMP SendCommand - -at 0x000000bc : */ 0x80080000,0x000001c8, -/* - -DataIn: - CALL SGScriptStartAddress - -at 0x000000be : */ 0x88080000,0x00000000, -/* -ResumeDataIn: - JUMP Finish, WHEN STATUS - -at 0x000000c0 : */ 0x830b0000,0x00000460, -/* - JUMP MsgInAfterDataIn, IF MSG_IN - -at 0x000000c2 : */ 0x870a0000,0x00000358, -/* - JUMP DataInAfterDataIn, if DATA_IN - -at 0x000000c4 : */ 0x810a0000,0x00000328, -/* - INT MSG_OUT_AFTER_DATA_IN, if MSG_OUT - -at 0x000000c6 : */ 0x9e0a0000,0x00000590, -/* - INT UNEXPECTED_PHASE_AFTER_DATA_IN - -at 0x000000c8 : */ 0x98080000,0x00000520, -/* - -DataInAfterDataIn: - INT DATA_IN_AFTER_DATA_IN - -at 0x000000ca : */ 0x98080000,0x000005a0, -/* - JUMP ResumeDataIn - -at 0x000000cc : */ 0x80080000,0x00000300, -/* - -DataOut: - CALL SGScriptStartAddress - -at 0x000000ce : */ 0x88080000,0x00000000, -/* -ResumeDataOut: - JUMP Finish, WHEN STATUS - -at 0x000000d0 : */ 0x830b0000,0x00000460, -/* - JUMP MsgInAfterDataOut, IF MSG_IN - -at 0x000000d2 : */ 0x870a0000,0x000003e8, -/* - INT UNEXPECTED_PHASE_AFTER_DATA_OUT - -at 0x000000d4 : */ 0x98080000,0x00000620, -/* - -MsgInAfterDataIn: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - -at 0x000000d6 : */ 0x0f000001,0x00000000, -/* - JUMP DisconnectAfterDataIn, IF DISCONNECT_MSG - -at 0x000000d8 : */ 0x800c0004,0x000003c0, -/* - JUMP IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG - -at 0x000000da : */ 0x800c0002,0x00000428, -/* - JUMP IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG - -at 0x000000dc : */ 0x800c0003,0x00000428, -/* - CALL ProcessReceiveMessage - -at 0x000000de : */ 0x88080000,0x000000a8, -/* - INT MSG_IN_AFTER_DATA_IN - -at 0x000000e0 : */ 0x98080000,0x00000550, -/* - CLEAR ACK - -at 0x000000e2 : */ 0x60000040,0x00000000, -/* - JUMP ResumeDataIn - -at 0x000000e4 : */ 0x80080000,0x00000300, -/* - -DisconnectDuringDataIn: - CLEAR ACK - -at 0x000000e6 : */ 0x60000040,0x00000000, -/* - WAIT DISCONNECT - -at 0x000000e8 : */ 0x48000000,0x00000000, -/* - ENTRY Disconnect3 -Disconnect3: - INT DISCONNECT_DURING_DATA - -at 0x000000ea : */ 0x98080000,0x00000780, -/* - ENTRY Disconnect4 -Disconnect4: -; we return here after a reselection - CLEAR ACK - -at 0x000000ec : */ 0x60000040,0x00000000, -/* - JUMP ResumeSendCommand - -at 0x000000ee : */ 0x80080000,0x000001e8, -/* - - -DisconnectAfterDataIn: - CLEAR ACK - -at 0x000000f0 : */ 0x60000040,0x00000000, -/* - WAIT DISCONNECT - -at 0x000000f2 : */ 0x48000000,0x00000000, -/* - ENTRY Disconnect5 -Disconnect5: - INT DISCONNECT_AFTER_DATA - -at 0x000000f4 : */ 0x98080000,0x00000580, -/* - ENTRY Disconnect6 -Disconnect6: -; we return here after a reselection - CLEAR ACK - -at 0x000000f6 : */ 0x60000040,0x00000000, -/* - JUMP ResumeDataIn - -at 0x000000f8 : */ 0x80080000,0x00000300, -/* - -MsgInAfterDataOut: - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - -at 0x000000fa : */ 0x0f000001,0x00000000, -/* - JUMP DisconnectAfterDataOut, if DISCONNECT_MSG - -at 0x000000fc : */ 0x800c0004,0x00000438, -/* - JUMP IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG - -at 0x000000fe : */ 0x800c0002,0x00000428, -/* - JUMP IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG - -at 0x00000100 : */ 0x800c0003,0x00000428, -/* - CALL ProcessReceiveMessage - -at 0x00000102 : */ 0x88080000,0x000000a8, -/* - INT MSG_IN_AFTER_DATA_OUT - -at 0x00000104 : */ 0x98080000,0x00000650, -/* - CLEAR ACK - -at 0x00000106 : */ 0x60000040,0x00000000, -/* - JUMP ResumeDataOut - -at 0x00000108 : */ 0x80080000,0x00000340, -/* - -IgnoreMsgAfterData: - CLEAR ACK - -at 0x0000010a : */ 0x60000040,0x00000000, -/* -; Data in and out do the same thing on resume, so pick one - JUMP ResumeDataIn - -at 0x0000010c : */ 0x80080000,0x00000300, -/* - -DisconnectAfterDataOut: - CLEAR ACK - -at 0x0000010e : */ 0x60000040,0x00000000, -/* - WAIT DISCONNECT - -at 0x00000110 : */ 0x48000000,0x00000000, -/* - ENTRY Disconnect7 -Disconnect7: - INT DISCONNECT_AFTER_DATA - -at 0x00000112 : */ 0x98080000,0x00000580, -/* - ENTRY Disconnect8 -Disconnect8: -; we return here after a reselection - CLEAR ACK - -at 0x00000114 : */ 0x60000040,0x00000000, -/* - JUMP ResumeDataOut - -at 0x00000116 : */ 0x80080000,0x00000340, -/* - -Finish: - MOVE 1, StatusAddress, WHEN STATUS - -at 0x00000118 : */ 0x0b000001,0x00000000, -/* - INT NOT_MSG_IN_AFTER_STATUS, WHEN NOT MSG_IN - -at 0x0000011a : */ 0x9f030000,0x00000430, -/* - MOVE 1, ReceiveMsgAddress, WHEN MSG_IN - -at 0x0000011c : */ 0x0f000001,0x00000000, -/* - JUMP FinishCommandComplete, IF COMMAND_COMPLETE_MSG - -at 0x0000011e : */ 0x800c0000,0x00000490, -/* - CALL ProcessReceiveMessage - -at 0x00000120 : */ 0x88080000,0x000000a8, -/* - INT MSG_IN_AFTER_STATUS - -at 0x00000122 : */ 0x98080000,0x00000440, -/* - ENTRY FinishCommandComplete -FinishCommandComplete: - CLEAR ACK - -at 0x00000124 : */ 0x60000040,0x00000000, -/* - WAIT DISCONNECT - -at 0x00000126 : */ 0x48000000,0x00000000, -/* - ENTRY Finish1 -Finish1: - INT GOOD_STATUS_AFTER_STATUS - -at 0x00000128 : */ 0x98080000,0x00000401, -}; - -#define A_AFTER_CMD 0x00000300 -static u32 A_AFTER_CMD_used[] __attribute((unused)) = { -}; - -#define A_AFTER_DATA_IN 0x00000500 -static u32 A_AFTER_DATA_IN_used[] __attribute((unused)) = { -}; - -#define A_AFTER_DATA_OUT 0x00000600 -static u32 A_AFTER_DATA_OUT_used[] __attribute((unused)) = { -}; - -#define A_AFTER_SELECTION 0x00000100 -static u32 A_AFTER_SELECTION_used[] __attribute((unused)) = { -}; - -#define A_AFTER_STATUS 0x00000400 -static u32 A_AFTER_STATUS_used[] __attribute((unused)) = { -}; - -#define A_BEFORE_CMD 0x00000200 -static u32 A_BEFORE_CMD_used[] __attribute((unused)) = { -}; - -#define A_COMMAND_COMPLETE_MSG 0x00000000 -static u32 A_COMMAND_COMPLETE_MSG_used[] __attribute((unused)) = { - 0x0000011e, -}; - -#define A_COMPLETED_SELECTION_AS_TARGET 0x00001001 -static u32 A_COMPLETED_SELECTION_AS_TARGET_used[] __attribute((unused)) = { - 0x0000001d, -}; - -#define A_CommandAddress 0x00000000 -static u32 A_CommandAddress_used[] __attribute((unused)) = { - 0x00000079, -}; - -#define A_CommandCount 0x00000000 -static u32 A_CommandCount_used[] __attribute((unused)) = { - 0x00000078, -}; - -#define A_DATA_IN_AFTER_DATA_IN 0x000005a0 -static u32 A_DATA_IN_AFTER_DATA_IN_used[] __attribute((unused)) = { - 0x000000cb, -}; - -#define A_DEBUG_INTERRUPT 0x00003000 -static u32 A_DEBUG_INTERRUPT_used[] __attribute((unused)) = { -}; - -#define A_DEBUG_INTERRUPT1 0x00003001 -static u32 A_DEBUG_INTERRUPT1_used[] __attribute((unused)) = { -}; - -#define A_DEBUG_INTERRUPT2 0x00003002 -static u32 A_DEBUG_INTERRUPT2_used[] __attribute((unused)) = { -}; - -#define A_DEBUG_INTERRUPT3 0x00003003 -static u32 A_DEBUG_INTERRUPT3_used[] __attribute((unused)) = { -}; - -#define A_DEBUG_INTERRUPT4 0x00003004 -static u32 A_DEBUG_INTERRUPT4_used[] __attribute((unused)) = { -}; - -#define A_DEBUG_INTERRUPT5 0x00003005 -static u32 A_DEBUG_INTERRUPT5_used[] __attribute((unused)) = { -}; - -#define A_DEBUG_INTERRUPT6 0x00003006 -static u32 A_DEBUG_INTERRUPT6_used[] __attribute((unused)) = { -}; - -#define A_DISCONNECT 0x00000080 -static u32 A_DISCONNECT_used[] __attribute((unused)) = { -}; - -#define A_DISCONNECT_AFTER_CMD 0x00000380 -static u32 A_DISCONNECT_AFTER_CMD_used[] __attribute((unused)) = { - 0x000000ab, -}; - -#define A_DISCONNECT_AFTER_DATA 0x00000580 -static u32 A_DISCONNECT_AFTER_DATA_used[] __attribute((unused)) = { - 0x000000f5, - 0x00000113, -}; - -#define A_DISCONNECT_DURING_DATA 0x00000780 -static u32 A_DISCONNECT_DURING_DATA_used[] __attribute((unused)) = { - 0x000000eb, -}; - -#define A_DISCONNECT_MSG 0x00000004 -static u32 A_DISCONNECT_MSG_used[] __attribute((unused)) = { - 0x0000008a, - 0x00000094, - 0x000000d8, - 0x000000fc, -}; - -#define A_DURING_DATA_IN 0x00000700 -static u32 A_DURING_DATA_IN_used[] __attribute((unused)) = { -}; - -#define A_Device_ID 0x00000000 -static u32 A_Device_ID_used[] __attribute((unused)) = { - 0x00000000, -}; - -#define A_EXTENDED_MSG 0x00000001 -static u32 A_EXTENDED_MSG_used[] __attribute((unused)) = { - 0x0000002a, -}; - -#define A_FATAL 0x00002000 -static u32 A_FATAL_used[] __attribute((unused)) = { -}; - -#define A_FATAL_ILLEGAL_MSG_LENGTH 0x00002003 -static u32 A_FATAL_ILLEGAL_MSG_LENGTH_used[] __attribute((unused)) = { - 0x00000043, -}; - -#define A_FATAL_NOT_MSG_IN_AFTER_SELECTION 0x00002002 -static u32 A_FATAL_NOT_MSG_IN_AFTER_SELECTION_used[] __attribute((unused)) = { - 0x0000000d, -}; - -#define A_FATAL_SEND_MSG 0x00002001 -static u32 A_FATAL_SEND_MSG_used[] __attribute((unused)) = { - 0x00000023, -}; - -#define A_FATAL_UNEXPECTED_RESELECTION_MSG 0x00002000 -static u32 A_FATAL_UNEXPECTED_RESELECTION_MSG_used[] __attribute((unused)) = { -}; - -#define A_GOOD_STATUS 0x00000001 -static u32 A_GOOD_STATUS_used[] __attribute((unused)) = { -}; - -#define A_GOOD_STATUS_AFTER_STATUS 0x00000401 -static u32 A_GOOD_STATUS_AFTER_STATUS_used[] __attribute((unused)) = { - 0x00000129, -}; - -#define A_IDENTIFY_MSG 0x00000080 -static u32 A_IDENTIFY_MSG_used[] __attribute((unused)) = { -}; - -#define A_IDENTIFY_MSG_MASK 0x0000007f -static u32 A_IDENTIFY_MSG_MASK_used[] __attribute((unused)) = { -}; - -#define A_MSG_IN 0x00000050 -static u32 A_MSG_IN_used[] __attribute((unused)) = { -}; - -#define A_MSG_IN_AFTER_CMD 0x00000350 -static u32 A_MSG_IN_AFTER_CMD_used[] __attribute((unused)) = { - 0x0000009d, -}; - -#define A_MSG_IN_AFTER_DATA_IN 0x00000550 -static u32 A_MSG_IN_AFTER_DATA_IN_used[] __attribute((unused)) = { - 0x000000e1, -}; - -#define A_MSG_IN_AFTER_DATA_OUT 0x00000650 -static u32 A_MSG_IN_AFTER_DATA_OUT_used[] __attribute((unused)) = { - 0x00000105, -}; - -#define A_MSG_IN_AFTER_STATUS 0x00000440 -static u32 A_MSG_IN_AFTER_STATUS_used[] __attribute((unused)) = { - 0x00000123, -}; - -#define A_MSG_IN_BEFORE_CMD 0x00000250 -static u32 A_MSG_IN_BEFORE_CMD_used[] __attribute((unused)) = { - 0x000000b9, -}; - -#define A_MSG_IN_DURING_DATA_IN 0x00000750 -static u32 A_MSG_IN_DURING_DATA_IN_used[] __attribute((unused)) = { - 0x00000091, -}; - -#define A_MSG_OUT 0x00000090 -static u32 A_MSG_OUT_used[] __attribute((unused)) = { -}; - -#define A_MSG_OUT_AFTER_DATA_IN 0x00000590 -static u32 A_MSG_OUT_AFTER_DATA_IN_used[] __attribute((unused)) = { - 0x000000c7, -}; - -#define A_MessageCount 0x00000000 -static u32 A_MessageCount_used[] __attribute((unused)) = { - 0x0000001e, -}; - -#define A_MessageLocation 0x00000000 -static u32 A_MessageLocation_used[] __attribute((unused)) = { - 0x0000001f, -}; - -#define A_NOT_MSG_IN 0x00000030 -static u32 A_NOT_MSG_IN_used[] __attribute((unused)) = { -}; - -#define A_NOT_MSG_IN_AFTER_STATUS 0x00000430 -static u32 A_NOT_MSG_IN_AFTER_STATUS_used[] __attribute((unused)) = { - 0x0000011b, -}; - -#define A_NOT_MSG_OUT 0x00000010 -static u32 A_NOT_MSG_OUT_used[] __attribute((unused)) = { -}; - -#define A_NOT_MSG_OUT_AFTER_SELECTION 0x00000110 -static u32 A_NOT_MSG_OUT_AFTER_SELECTION_used[] __attribute((unused)) = { - 0x00000007, -}; - -#define A_PARITY_ERROR_MSG 0x00000009 -static u32 A_PARITY_ERROR_MSG_used[] __attribute((unused)) = { -}; - -#define A_REJECT_MSG 0x00000007 -static u32 A_REJECT_MSG_used[] __attribute((unused)) = { -}; - -#define A_REJECT_MSG_BEFORE_CMD 0x00000270 -static u32 A_REJECT_MSG_BEFORE_CMD_used[] __attribute((unused)) = { -}; - -#define A_REJECT_MSG_R 0x00000070 -static u32 A_REJECT_MSG_R_used[] __attribute((unused)) = { -}; - -#define A_RESELECTED_DURING_SELECTION 0x00001000 -static u32 A_RESELECTED_DURING_SELECTION_used[] __attribute((unused)) = { - 0x0000000b, -}; - -#define A_RESELECTION_IDENTIFIED 0x00001003 -static u32 A_RESELECTION_IDENTIFIED_used[] __attribute((unused)) = { - 0x00000011, - 0x00000015, -}; - -#define A_RESTORE_DATA_PTRS_MSG 0x00000003 -static u32 A_RESTORE_DATA_PTRS_MSG_used[] __attribute((unused)) = { - 0x0000008e, - 0x00000098, - 0x000000b4, - 0x000000dc, - 0x00000100, -}; - -#define A_ReceiveMsgAddress 0x00000000 -static u32 A_ReceiveMsgAddress_used[] __attribute((unused)) = { - 0x0000000f, - 0x00000013, - 0x00000029, - 0x00000031, - 0x00000037, - 0x00000047, - 0x0000004d, - 0x00000053, - 0x00000059, - 0x0000005f, - 0x00000089, - 0x00000093, - 0x000000b1, - 0x000000d7, - 0x000000fb, - 0x0000011d, -}; - -#define A_SAVE_DATA_PTRS_MSG 0x00000002 -static u32 A_SAVE_DATA_PTRS_MSG_used[] __attribute((unused)) = { - 0x0000008c, - 0x00000096, - 0x000000b2, - 0x000000da, - 0x000000fe, -}; - -#define A_SDTR_MSG 0x00000001 -static u32 A_SDTR_MSG_used[] __attribute((unused)) = { -}; - -#define A_SDTR_MSG_AFTER_CMD 0x00000360 -static u32 A_SDTR_MSG_AFTER_CMD_used[] __attribute((unused)) = { -}; - -#define A_SDTR_MSG_BEFORE_CMD 0x00000260 -static u32 A_SDTR_MSG_BEFORE_CMD_used[] __attribute((unused)) = { -}; - -#define A_SDTR_MSG_R 0x00000060 -static u32 A_SDTR_MSG_R_used[] __attribute((unused)) = { -}; - -#define A_SGScriptStartAddress 0x00000000 -static u32 A_SGScriptStartAddress_used[] __attribute((unused)) = { - 0x000000bf, - 0x000000cf, -}; - -#define A_SIMPLE_TAG_MSG 0x00000020 -static u32 A_SIMPLE_TAG_MSG_used[] __attribute((unused)) = { -}; - -#define A_StatusAddress 0x00000000 -static u32 A_StatusAddress_used[] __attribute((unused)) = { - 0x00000119, -}; - -#define A_TWO_BYTE_MSG 0x00000020 -static u32 A_TWO_BYTE_MSG_used[] __attribute((unused)) = { - 0x0000002c, -}; - -#define A_TWO_BYTE_MSG_MASK 0x0000000f -static u32 A_TWO_BYTE_MSG_MASK_used[] __attribute((unused)) = { - 0x0000002c, -}; - -#define A_UNEXPECTED_MSG 0x00000040 -static u32 A_UNEXPECTED_MSG_used[] __attribute((unused)) = { -}; - -#define A_UNEXPECTED_MSG_BEFORE_CMD 0x00000240 -static u32 A_UNEXPECTED_MSG_BEFORE_CMD_used[] __attribute((unused)) = { -}; - -#define A_UNEXPECTED_PHASE 0x00000020 -static u32 A_UNEXPECTED_PHASE_used[] __attribute((unused)) = { -}; - -#define A_UNEXPECTED_PHASE_AFTER_CMD 0x00000320 -static u32 A_UNEXPECTED_PHASE_AFTER_CMD_used[] __attribute((unused)) = { - 0x00000083, -}; - -#define A_UNEXPECTED_PHASE_AFTER_DATA_IN 0x00000520 -static u32 A_UNEXPECTED_PHASE_AFTER_DATA_IN_used[] __attribute((unused)) = { - 0x000000c9, -}; - -#define A_UNEXPECTED_PHASE_AFTER_DATA_OUT 0x00000620 -static u32 A_UNEXPECTED_PHASE_AFTER_DATA_OUT_used[] __attribute((unused)) = { - 0x000000d5, -}; - -#define A_UNEXPECTED_PHASE_BEFORE_CMD 0x00000220 -static u32 A_UNEXPECTED_PHASE_BEFORE_CMD_used[] __attribute((unused)) = { - 0x00000077, -}; - -#define A_WDTR_MSG 0x00000003 -static u32 A_WDTR_MSG_used[] __attribute((unused)) = { -}; - -#define A_WDTR_MSG_AFTER_CMD 0x000003a0 -static u32 A_WDTR_MSG_AFTER_CMD_used[] __attribute((unused)) = { -}; - -#define A_WDTR_MSG_R 0x000000a0 -static u32 A_WDTR_MSG_R_used[] __attribute((unused)) = { -}; - -#define Ent_Disconnect1 0x000002a8 -#define Ent_Disconnect2 0x000002b0 -#define Ent_Disconnect3 0x000003a8 -#define Ent_Disconnect4 0x000003b0 -#define Ent_Disconnect5 0x000003d0 -#define Ent_Disconnect6 0x000003d8 -#define Ent_Disconnect7 0x00000448 -#define Ent_Disconnect8 0x00000450 -#define Ent_Finish1 0x000004a0 -#define Ent_Finish2 0x000004a8 -#define Ent_FinishCommandComplete 0x00000490 -#define Ent_GetReselectionData 0x00000038 -#define Ent_GetReselectionWithTag 0x00000048 -#define Ent_IgnoreMessage 0x00000188 -#define Ent_MsgInDuringData 0x00000218 -#define Ent_ReceiveMessage 0x000000a0 -#define Ent_SelectedAsTarget 0x00000058 -#define Ent_SendCommand 0x000001c8 -#define Ent_SendMessage 0x00000078 -#define Ent_SendMessagePhaseMismatch 0x00000090 -#define Ent_SendMessageWithATN 0x00000198 -#define Ent_StartUp 0x00000000 -static u32 LABELPATCHES[] __attribute((unused)) = { - 0x00000001, - 0x00000003, - 0x00000005, - 0x00000009, - 0x00000027, - 0x0000002b, - 0x00000039, - 0x0000003b, - 0x0000003d, - 0x0000003f, - 0x00000041, - 0x0000006b, - 0x0000006d, - 0x00000073, - 0x00000075, - 0x0000007b, - 0x0000007d, - 0x0000007f, - 0x00000081, - 0x00000087, - 0x0000008b, - 0x0000008d, - 0x0000008f, - 0x00000095, - 0x00000097, - 0x00000099, - 0x0000009b, - 0x000000a1, - 0x000000a5, - 0x000000af, - 0x000000b3, - 0x000000b5, - 0x000000b7, - 0x000000bd, - 0x000000c1, - 0x000000c3, - 0x000000c5, - 0x000000cd, - 0x000000d1, - 0x000000d3, - 0x000000d9, - 0x000000db, - 0x000000dd, - 0x000000df, - 0x000000e5, - 0x000000ef, - 0x000000f9, - 0x000000fd, - 0x000000ff, - 0x00000101, - 0x00000103, - 0x00000109, - 0x0000010d, - 0x00000117, - 0x0000011f, - 0x00000121, -}; - -static struct { - u32 offset; - void *address; -} EXTERNAL_PATCHES[] __attribute((unused)) = { -}; - -static u32 INSTRUCTIONS __attribute((unused)) = 149; -static u32 PATCHES __attribute((unused)) = 56; -static u32 EXTERNAL_PATCHES_LEN __attribute((unused)) = 0; diff --git a/ANDROID_3.4.5/drivers/scsi/BusLogic.c b/ANDROID_3.4.5/drivers/scsi/BusLogic.c deleted file mode 100644 index d4da3708..00000000 --- a/ANDROID_3.4.5/drivers/scsi/BusLogic.c +++ /dev/null @@ -1,3631 +0,0 @@ - -/* - - Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters - - Copyright 1995-1998 by Leonard N. Zubkoff - - This program is free software; you may redistribute and/or modify it under - the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for complete details. - - The author respectfully requests that any modifications to this software be - sent directly to him for evaluation and testing. - - Special thanks to Wayne Yen, Jin-Lon Hon, and Alex Win of BusLogic, whose - advice has been invaluable, to David Gentzel, for writing the original Linux - BusLogic driver, and to Paul Gortmaker, for being such a dedicated test site. - - Finally, special thanks to Mylex/BusLogic for making the FlashPoint SCCB - Manager available as freely redistributable source code. - -*/ - -#define BusLogic_DriverVersion "2.1.16" -#define BusLogic_DriverDate "18 July 2002" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include "BusLogic.h" -#include "FlashPoint.c" - -#ifndef FAILURE -#define FAILURE (-1) -#endif - -static struct scsi_host_template Bus_Logic_template; - -/* - BusLogic_DriverOptionsCount is a count of the number of BusLogic Driver - Options specifications provided via the Linux Kernel Command Line or via - the Loadable Kernel Module Installation Facility. -*/ - -static int BusLogic_DriverOptionsCount; - - -/* - BusLogic_DriverOptions is an array of Driver Options structures representing - BusLogic Driver Options specifications provided via the Linux Kernel Command - Line or via the Loadable Kernel Module Installation Facility. -*/ - -static struct BusLogic_DriverOptions BusLogic_DriverOptions[BusLogic_MaxHostAdapters]; - - -/* - BusLogic can be assigned a string by insmod. -*/ - -MODULE_LICENSE("GPL"); -#ifdef MODULE -static char *BusLogic; -module_param(BusLogic, charp, 0); -#endif - - -/* - BusLogic_ProbeOptions is a set of Probe Options to be applied across - all BusLogic Host Adapters. -*/ - -static struct BusLogic_ProbeOptions BusLogic_ProbeOptions; - - -/* - BusLogic_GlobalOptions is a set of Global Options to be applied across - all BusLogic Host Adapters. -*/ - -static struct BusLogic_GlobalOptions BusLogic_GlobalOptions; - -static LIST_HEAD(BusLogic_host_list); - -/* - BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList. -*/ - -static int BusLogic_ProbeInfoCount; - - -/* - BusLogic_ProbeInfoList is the list of I/O Addresses and Bus Probe Information - to be checked for potential BusLogic Host Adapters. It is initialized by - interrogating the PCI Configuration Space on PCI machines as well as from the - list of standard BusLogic I/O Addresses. -*/ - -static struct BusLogic_ProbeInfo *BusLogic_ProbeInfoList; - - -/* - BusLogic_CommandFailureReason holds a string identifying the reason why a - call to BusLogic_Command failed. It is only non-NULL when BusLogic_Command - returns a failure code. -*/ - -static char *BusLogic_CommandFailureReason; - -/* - BusLogic_AnnounceDriver announces the Driver Version and Date, Author's - Name, Copyright Notice, and Electronic Mail Address. -*/ - -static void BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter) -{ - BusLogic_Announce("***** BusLogic SCSI Driver Version " BusLogic_DriverVersion " of " BusLogic_DriverDate " *****\n", HostAdapter); - BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff " "\n", HostAdapter); -} - - -/* - BusLogic_DriverInfo returns the Host Adapter Name to identify this SCSI - Driver and Host Adapter. -*/ - -static const char *BusLogic_DriverInfo(struct Scsi_Host *Host) -{ - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; - return HostAdapter->FullModelName; -} - -/* - BusLogic_InitializeCCBs initializes a group of Command Control Blocks (CCBs) - for Host Adapter from the BlockSize bytes located at BlockPointer. The newly - created CCBs are added to Host Adapter's free list. -*/ - -static void BusLogic_InitializeCCBs(struct BusLogic_HostAdapter *HostAdapter, void *BlockPointer, int BlockSize, dma_addr_t BlockPointerHandle) -{ - struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) BlockPointer; - unsigned int offset = 0; - memset(BlockPointer, 0, BlockSize); - CCB->AllocationGroupHead = BlockPointerHandle; - CCB->AllocationGroupSize = BlockSize; - while ((BlockSize -= sizeof(struct BusLogic_CCB)) >= 0) { - CCB->Status = BusLogic_CCB_Free; - CCB->HostAdapter = HostAdapter; - CCB->DMA_Handle = (u32) BlockPointerHandle + offset; - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - CCB->CallbackFunction = BusLogic_QueueCompletedCCB; - CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress; - } - CCB->Next = HostAdapter->Free_CCBs; - CCB->NextAll = HostAdapter->All_CCBs; - HostAdapter->Free_CCBs = CCB; - HostAdapter->All_CCBs = CCB; - HostAdapter->AllocatedCCBs++; - CCB++; - offset += sizeof(struct BusLogic_CCB); - } -} - - -/* - BusLogic_CreateInitialCCBs allocates the initial CCBs for Host Adapter. -*/ - -static bool __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *HostAdapter) -{ - int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); - void *BlockPointer; - dma_addr_t BlockPointerHandle; - while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) { - BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, &BlockPointerHandle); - if (BlockPointer == NULL) { - BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", HostAdapter); - return false; - } - BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, BlockPointerHandle); - } - return true; -} - - -/* - BusLogic_DestroyCCBs deallocates the CCBs for Host Adapter. -*/ - -static void BusLogic_DestroyCCBs(struct BusLogic_HostAdapter *HostAdapter) -{ - struct BusLogic_CCB *NextCCB = HostAdapter->All_CCBs, *CCB, *Last_CCB = NULL; - HostAdapter->All_CCBs = NULL; - HostAdapter->Free_CCBs = NULL; - while ((CCB = NextCCB) != NULL) { - NextCCB = CCB->NextAll; - if (CCB->AllocationGroupHead) { - if (Last_CCB) - pci_free_consistent(HostAdapter->PCI_Device, Last_CCB->AllocationGroupSize, Last_CCB, Last_CCB->AllocationGroupHead); - Last_CCB = CCB; - } - } - if (Last_CCB) - pci_free_consistent(HostAdapter->PCI_Device, Last_CCB->AllocationGroupSize, Last_CCB, Last_CCB->AllocationGroupHead); -} - - -/* - BusLogic_CreateAdditionalCCBs allocates Additional CCBs for Host Adapter. If - allocation fails and there are no remaining CCBs available, the Driver Queue - Depth is decreased to a known safe value to avoid potential deadlocks when - multiple host adapters share the same IRQ Channel. -*/ - -static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, int AdditionalCCBs, bool SuccessMessageP) -{ - int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB); - int PreviouslyAllocated = HostAdapter->AllocatedCCBs; - void *BlockPointer; - dma_addr_t BlockPointerHandle; - if (AdditionalCCBs <= 0) - return; - while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) { - BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, &BlockPointerHandle); - if (BlockPointer == NULL) - break; - BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, BlockPointerHandle); - } - if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) { - if (SuccessMessageP) - BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", HostAdapter, HostAdapter->AllocatedCCBs - PreviouslyAllocated, HostAdapter->AllocatedCCBs); - return; - } - BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter); - if (HostAdapter->DriverQueueDepth > HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) { - HostAdapter->DriverQueueDepth = HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount; - HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth; - } -} - -/* - BusLogic_AllocateCCB allocates a CCB from Host Adapter's free list, - allocating more memory from the Kernel if necessary. The Host Adapter's - Lock should already have been acquired by the caller. -*/ - -static struct BusLogic_CCB *BusLogic_AllocateCCB(struct BusLogic_HostAdapter - *HostAdapter) -{ - static unsigned long SerialNumber = 0; - struct BusLogic_CCB *CCB; - CCB = HostAdapter->Free_CCBs; - if (CCB != NULL) { - CCB->SerialNumber = ++SerialNumber; - HostAdapter->Free_CCBs = CCB->Next; - CCB->Next = NULL; - if (HostAdapter->Free_CCBs == NULL) - BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true); - return CCB; - } - BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true); - CCB = HostAdapter->Free_CCBs; - if (CCB == NULL) - return NULL; - CCB->SerialNumber = ++SerialNumber; - HostAdapter->Free_CCBs = CCB->Next; - CCB->Next = NULL; - return CCB; -} - - -/* - BusLogic_DeallocateCCB deallocates a CCB, returning it to the Host Adapter's - free list. The Host Adapter's Lock should already have been acquired by the - caller. -*/ - -static void BusLogic_DeallocateCCB(struct BusLogic_CCB *CCB) -{ - struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; - - scsi_dma_unmap(CCB->Command); - pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer, - CCB->SenseDataLength, PCI_DMA_FROMDEVICE); - - CCB->Command = NULL; - CCB->Status = BusLogic_CCB_Free; - CCB->Next = HostAdapter->Free_CCBs; - HostAdapter->Free_CCBs = CCB; -} - - -/* - BusLogic_Command sends the command OperationCode to HostAdapter, optionally - providing ParameterLength bytes of ParameterData and receiving at most - ReplyLength bytes of ReplyData; any excess reply data is received but - discarded. - - On success, this function returns the number of reply bytes read from - the Host Adapter (including any discarded data); on failure, it returns - -1 if the command was invalid, or -2 if a timeout occurred. - - BusLogic_Command is called exclusively during host adapter detection and - initialization, so performance and latency are not critical, and exclusive - access to the Host Adapter hardware is assumed. Once the host adapter and - driver are initialized, the only Host Adapter command that is issued is the - single byte Execute Mailbox Command operation code, which does not require - waiting for the Host Adapter Ready bit to be set in the Status Register. -*/ - -static int BusLogic_Command(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_OperationCode OperationCode, void *ParameterData, int ParameterLength, void *ReplyData, int ReplyLength) -{ - unsigned char *ParameterPointer = (unsigned char *) ParameterData; - unsigned char *ReplyPointer = (unsigned char *) ReplyData; - union BusLogic_StatusRegister StatusRegister; - union BusLogic_InterruptRegister InterruptRegister; - unsigned long ProcessorFlags = 0; - int ReplyBytes = 0, Result; - long TimeoutCounter; - /* - Clear out the Reply Data if provided. - */ - if (ReplyLength > 0) - memset(ReplyData, 0, ReplyLength); - /* - If the IRQ Channel has not yet been acquired, then interrupts must be - disabled while issuing host adapter commands since a Command Complete - interrupt could occur if the IRQ Channel was previously enabled by another - BusLogic Host Adapter or another driver sharing the same IRQ Channel. - */ - if (!HostAdapter->IRQ_ChannelAcquired) - local_irq_save(ProcessorFlags); - /* - Wait for the Host Adapter Ready bit to be set and the Command/Parameter - Register Busy bit to be reset in the Status Register. - */ - TimeoutCounter = 10000; - while (--TimeoutCounter >= 0) { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.HostAdapterReady && !StatusRegister.sr.CommandParameterRegisterBusy) - break; - udelay(100); - } - if (TimeoutCounter < 0) { - BusLogic_CommandFailureReason = "Timeout waiting for Host Adapter Ready"; - Result = -2; - goto Done; - } - /* - Write the OperationCode to the Command/Parameter Register. - */ - HostAdapter->HostAdapterCommandCompleted = false; - BusLogic_WriteCommandParameterRegister(HostAdapter, OperationCode); - /* - Write any additional Parameter Bytes. - */ - TimeoutCounter = 10000; - while (ParameterLength > 0 && --TimeoutCounter >= 0) { - /* - Wait 100 microseconds to give the Host Adapter enough time to determine - whether the last value written to the Command/Parameter Register was - valid or not. If the Command Complete bit is set in the Interrupt - Register, then the Command Invalid bit in the Status Register will be - reset if the Operation Code or Parameter was valid and the command - has completed, or set if the Operation Code or Parameter was invalid. - If the Data In Register Ready bit is set in the Status Register, then - the Operation Code was valid, and data is waiting to be read back - from the Host Adapter. Otherwise, wait for the Command/Parameter - Register Busy bit in the Status Register to be reset. - */ - udelay(100); - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (InterruptRegister.ir.CommandComplete) - break; - if (HostAdapter->HostAdapterCommandCompleted) - break; - if (StatusRegister.sr.DataInRegisterReady) - break; - if (StatusRegister.sr.CommandParameterRegisterBusy) - continue; - BusLogic_WriteCommandParameterRegister(HostAdapter, *ParameterPointer++); - ParameterLength--; - } - if (TimeoutCounter < 0) { - BusLogic_CommandFailureReason = "Timeout waiting for Parameter Acceptance"; - Result = -2; - goto Done; - } - /* - The Modify I/O Address command does not cause a Command Complete Interrupt. - */ - if (OperationCode == BusLogic_ModifyIOAddress) { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.CommandInvalid) { - BusLogic_CommandFailureReason = "Modify I/O Address Invalid"; - Result = -1; - goto Done; - } - if (BusLogic_GlobalOptions.TraceConfiguration) - BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " "(Modify I/O Address)\n", HostAdapter, OperationCode, StatusRegister.All); - Result = 0; - goto Done; - } - /* - Select an appropriate timeout value for awaiting command completion. - */ - switch (OperationCode) { - case BusLogic_InquireInstalledDevicesID0to7: - case BusLogic_InquireInstalledDevicesID8to15: - case BusLogic_InquireTargetDevices: - /* Approximately 60 seconds. */ - TimeoutCounter = 60 * 10000; - break; - default: - /* Approximately 1 second. */ - TimeoutCounter = 10000; - break; - } - /* - Receive any Reply Bytes, waiting for either the Command Complete bit to - be set in the Interrupt Register, or for the Interrupt Handler to set the - Host Adapter Command Completed bit in the Host Adapter structure. - */ - while (--TimeoutCounter >= 0) { - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (InterruptRegister.ir.CommandComplete) - break; - if (HostAdapter->HostAdapterCommandCompleted) - break; - if (StatusRegister.sr.DataInRegisterReady) { - if (++ReplyBytes <= ReplyLength) - *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter); - else - BusLogic_ReadDataInRegister(HostAdapter); - } - if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && StatusRegister.sr.HostAdapterReady) - break; - udelay(100); - } - if (TimeoutCounter < 0) { - BusLogic_CommandFailureReason = "Timeout waiting for Command Complete"; - Result = -2; - goto Done; - } - /* - Clear any pending Command Complete Interrupt. - */ - BusLogic_InterruptReset(HostAdapter); - /* - Provide tracing information if requested. - */ - if (BusLogic_GlobalOptions.TraceConfiguration) { - int i; - BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", HostAdapter, OperationCode, StatusRegister.All, ReplyLength, ReplyBytes); - if (ReplyLength > ReplyBytes) - ReplyLength = ReplyBytes; - for (i = 0; i < ReplyLength; i++) - BusLogic_Notice(" %02X", HostAdapter, ((unsigned char *) ReplyData)[i]); - BusLogic_Notice("\n", HostAdapter); - } - /* - Process Command Invalid conditions. - */ - if (StatusRegister.sr.CommandInvalid) { - /* - Some early BusLogic Host Adapters may not recover properly from - a Command Invalid condition, so if this appears to be the case, - a Soft Reset is issued to the Host Adapter. Potentially invalid - commands are never attempted after Mailbox Initialization is - performed, so there should be no Host Adapter state lost by a - Soft Reset in response to a Command Invalid condition. - */ - udelay(1000); - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.CommandInvalid || - StatusRegister.sr.Reserved || - StatusRegister.sr.DataInRegisterReady || - StatusRegister.sr.CommandParameterRegisterBusy || !StatusRegister.sr.HostAdapterReady || !StatusRegister.sr.InitializationRequired || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.DiagnosticFailure) { - BusLogic_SoftReset(HostAdapter); - udelay(1000); - } - BusLogic_CommandFailureReason = "Command Invalid"; - Result = -1; - goto Done; - } - /* - Handle Excess Parameters Supplied conditions. - */ - if (ParameterLength > 0) { - BusLogic_CommandFailureReason = "Excess Parameters Supplied"; - Result = -1; - goto Done; - } - /* - Indicate the command completed successfully. - */ - BusLogic_CommandFailureReason = NULL; - Result = ReplyBytes; - /* - Restore the interrupt status if necessary and return. - */ - Done: - if (!HostAdapter->IRQ_ChannelAcquired) - local_irq_restore(ProcessorFlags); - return Result; -} - - -/* - BusLogic_AppendProbeAddressISA appends a single ISA I/O Address to the list - of I/O Address and Bus Probe Information to be checked for potential BusLogic - Host Adapters. -*/ - -static void __init BusLogic_AppendProbeAddressISA(unsigned long IO_Address) -{ - struct BusLogic_ProbeInfo *ProbeInfo; - if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) - return; - ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Device = NULL; -} - - -/* - BusLogic_InitializeProbeInfoListISA initializes the list of I/O Address and - Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters - only from the list of standard BusLogic MultiMaster ISA I/O Addresses. -*/ - -static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapter - *PrototypeHostAdapter) -{ - /* - If BusLogic Driver Options specifications requested that ISA Bus Probes - be inhibited, do not proceed further. - */ - if (BusLogic_ProbeOptions.NoProbeISA) - return; - /* - Append the list of standard BusLogic MultiMaster ISA I/O Addresses. - */ - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe330) - BusLogic_AppendProbeAddressISA(0x330); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe334) - BusLogic_AppendProbeAddressISA(0x334); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe230) - BusLogic_AppendProbeAddressISA(0x230); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe234) - BusLogic_AppendProbeAddressISA(0x234); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe130) - BusLogic_AppendProbeAddressISA(0x130); - if (!BusLogic_ProbeOptions.LimitedProbeISA || BusLogic_ProbeOptions.Probe134) - BusLogic_AppendProbeAddressISA(0x134); -} - - -#ifdef CONFIG_PCI - - -/* - BusLogic_SortProbeInfo sorts a section of BusLogic_ProbeInfoList in order - of increasing PCI Bus and Device Number. -*/ - -static void __init BusLogic_SortProbeInfo(struct BusLogic_ProbeInfo *ProbeInfoList, int ProbeInfoCount) -{ - int LastInterchange = ProbeInfoCount - 1, Bound, j; - while (LastInterchange > 0) { - Bound = LastInterchange; - LastInterchange = 0; - for (j = 0; j < Bound; j++) { - struct BusLogic_ProbeInfo *ProbeInfo1 = &ProbeInfoList[j]; - struct BusLogic_ProbeInfo *ProbeInfo2 = &ProbeInfoList[j + 1]; - if (ProbeInfo1->Bus > ProbeInfo2->Bus || (ProbeInfo1->Bus == ProbeInfo2->Bus && (ProbeInfo1->Device > ProbeInfo2->Device))) { - struct BusLogic_ProbeInfo TempProbeInfo; - memcpy(&TempProbeInfo, ProbeInfo1, sizeof(struct BusLogic_ProbeInfo)); - memcpy(ProbeInfo1, ProbeInfo2, sizeof(struct BusLogic_ProbeInfo)); - memcpy(ProbeInfo2, &TempProbeInfo, sizeof(struct BusLogic_ProbeInfo)); - LastInterchange = j; - } - } - } -} - - -/* - BusLogic_InitializeMultiMasterProbeInfo initializes the list of I/O Address - and Bus Probe Information to be checked for potential BusLogic MultiMaster - SCSI Host Adapters by interrogating the PCI Configuration Space on PCI - machines as well as from the list of standard BusLogic MultiMaster ISA - I/O Addresses. It returns the number of PCI MultiMaster Host Adapters found. -*/ - -static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAdapter - *PrototypeHostAdapter) -{ - struct BusLogic_ProbeInfo *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount]; - int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1; - int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0; - bool ForceBusDeviceScanningOrder = false; - bool ForceBusDeviceScanningOrderChecked = false; - bool StandardAddressSeen[6]; - struct pci_dev *PCI_Device = NULL; - int i; - if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) - return 0; - BusLogic_ProbeInfoCount++; - for (i = 0; i < 6; i++) - StandardAddressSeen[i] = false; - /* - Iterate over the MultiMaster PCI Host Adapters. For each enumerated host - adapter, determine whether its ISA Compatible I/O Port is enabled and if - so, whether it is assigned the Primary I/O Address. A host adapter that is - assigned the Primary I/O Address will always be the preferred boot device. - The MultiMaster BIOS will first recognize a host adapter at the Primary I/O - Address, then any other PCI host adapters, and finally any host adapters - located at the remaining standard ISA I/O Addresses. When a PCI host - adapter is found with its ISA Compatible I/O Port enabled, a command is - issued to disable the ISA Compatible I/O Port, and it is noted that the - particular standard ISA I/O Address need not be probed. - */ - PrimaryProbeInfo->IO_Address = 0; - while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) { - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; - enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest; - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long BaseAddress0; - unsigned long BaseAddress1; - unsigned long IO_Address; - unsigned long PCI_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, DMA_BIT_MASK(32) )) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); - PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); - - if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { - BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "MultiMaster Host Adapter\n", NULL, BaseAddress0); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); - continue; - } - if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) { - BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "MultiMaster Host Adapter\n", NULL, BaseAddress1); - BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, Bus, Device, PCI_Address); - continue; - } - if (IRQ_Channel == 0) { - BusLogic_Error("BusLogic: IRQ Channel %d invalid for " "MultiMaster Host Adapter\n", NULL, IRQ_Channel); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); - continue; - } - if (BusLogic_GlobalOptions.TraceProbe) { - BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL); - BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, Bus, Device, IO_Address, PCI_Address); - } - /* - Issue the Inquire PCI Host Adapter Information command to determine - the ISA Compatible I/O Port. If the ISA Compatible I/O Port is - known and enabled, note that the particular Standard ISA I/O - Address should not be probed. - */ - HostAdapter->IO_Address = IO_Address; - BusLogic_InterruptReset(HostAdapter); - if (BusLogic_Command(HostAdapter, BusLogic_InquirePCIHostAdapterInformation, NULL, 0, &PCIHostAdapterInformation, sizeof(PCIHostAdapterInformation)) - == sizeof(PCIHostAdapterInformation)) { - if (PCIHostAdapterInformation.ISACompatibleIOPort < 6) - StandardAddressSeen[PCIHostAdapterInformation.ISACompatibleIOPort] = true; - } else - PCIHostAdapterInformation.ISACompatibleIOPort = BusLogic_IO_Disable; - /* - * Issue the Modify I/O Address command to disable the ISA Compatible - * I/O Port. On PCI Host Adapters, the Modify I/O Address command - * allows modification of the ISA compatible I/O Address that the Host - * Adapter responds to; it does not affect the PCI compliant I/O Address - * assigned at system initialization. - */ - ModifyIOAddressRequest = BusLogic_IO_Disable; - BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress, &ModifyIOAddressRequest, sizeof(ModifyIOAddressRequest), NULL, 0); - /* - For the first MultiMaster Host Adapter enumerated, issue the Fetch - Host Adapter Local RAM command to read byte 45 of the AutoSCSI area, - for the setting of the "Use Bus And Device # For PCI Scanning Seq." - option. Issue the Inquire Board ID command since this option is - only valid for the BT-948/958/958D. - */ - if (!ForceBusDeviceScanningOrderChecked) { - struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; - struct BusLogic_AutoSCSIByte45 AutoSCSIByte45; - struct BusLogic_BoardID BoardID; - FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset + 45; - FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIByte45); - BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &AutoSCSIByte45, sizeof(AutoSCSIByte45)); - BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, &BoardID, sizeof(BoardID)); - if (BoardID.FirmwareVersion1stDigit == '5') - ForceBusDeviceScanningOrder = AutoSCSIByte45.ForceBusDeviceScanningOrder; - ForceBusDeviceScanningOrderChecked = true; - } - /* - Determine whether this MultiMaster Host Adapter has its ISA - Compatible I/O Port enabled and is assigned the Primary I/O Address. - If it does, then it is the Primary MultiMaster Host Adapter and must - be recognized first. If it does not, then it is added to the list - for probing after any Primary MultiMaster Host Adapter is probed. - */ - if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330) { - PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; - PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - PrimaryProbeInfo->IO_Address = IO_Address; - PrimaryProbeInfo->PCI_Address = PCI_Address; - PrimaryProbeInfo->Bus = Bus; - PrimaryProbeInfo->Device = Device; - PrimaryProbeInfo->IRQ_Channel = IRQ_Channel; - PrimaryProbeInfo->PCI_Device = pci_dev_get(PCI_Device); - PCIMultiMasterCount++; - } else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_MultiMaster; - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = pci_dev_get(PCI_Device); - NonPrimaryPCIMultiMasterCount++; - PCIMultiMasterCount++; - } else - BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL); - } - /* - If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option is ON - for the first enumerated MultiMaster Host Adapter, and if that host adapter - is a BT-948/958/958D, then the MultiMaster BIOS will recognize MultiMaster - Host Adapters in the order of increasing PCI Bus and Device Number. In - that case, sort the probe information into the same order the BIOS uses. - If this option is OFF, then the MultiMaster BIOS will recognize MultiMaster - Host Adapters in the order they are enumerated by the PCI BIOS, and hence - no sorting is necessary. - */ - if (ForceBusDeviceScanningOrder) - BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[NonPrimaryPCIMultiMasterIndex], NonPrimaryPCIMultiMasterCount); - /* - If no PCI MultiMaster Host Adapter is assigned the Primary I/O Address, - then the Primary I/O Address must be probed explicitly before any PCI - host adapters are probed. - */ - if (!BusLogic_ProbeOptions.NoProbeISA) - if (PrimaryProbeInfo->IO_Address == 0 && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe330)) { - PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster; - PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus; - PrimaryProbeInfo->IO_Address = 0x330; - } - /* - Append the list of standard BusLogic MultiMaster ISA I/O Addresses, - omitting the Primary I/O Address which has already been handled. - */ - if (!BusLogic_ProbeOptions.NoProbeISA) { - if (!StandardAddressSeen[1] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe334)) - BusLogic_AppendProbeAddressISA(0x334); - if (!StandardAddressSeen[2] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe230)) - BusLogic_AppendProbeAddressISA(0x230); - if (!StandardAddressSeen[3] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe234)) - BusLogic_AppendProbeAddressISA(0x234); - if (!StandardAddressSeen[4] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe130)) - BusLogic_AppendProbeAddressISA(0x130); - if (!StandardAddressSeen[5] && - (!BusLogic_ProbeOptions.LimitedProbeISA || - BusLogic_ProbeOptions.Probe134)) - BusLogic_AppendProbeAddressISA(0x134); - } - /* - Iterate over the older non-compliant MultiMaster PCI Host Adapters, - noting the PCI bus location and assigned IRQ Channel. - */ - PCI_Device = NULL; - while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) { - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long IO_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, DMA_BIT_MASK(32))) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = pci_resource_start(PCI_Device, 0); - - if (IO_Address == 0 || IRQ_Channel == 0) - continue; - for (i = 0; i < BusLogic_ProbeInfoCount; i++) { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[i]; - if (ProbeInfo->IO_Address == IO_Address && ProbeInfo->HostAdapterType == BusLogic_MultiMaster) { - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->PCI_Address = 0; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = pci_dev_get(PCI_Device); - break; - } - } - } - return PCIMultiMasterCount; -} - - -/* - BusLogic_InitializeFlashPointProbeInfo initializes the list of I/O Address - and Bus Probe Information to be checked for potential BusLogic FlashPoint - Host Adapters by interrogating the PCI Configuration Space. It returns the - number of FlashPoint Host Adapters found. -*/ - -static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAdapter - *PrototypeHostAdapter) -{ - int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0; - struct pci_dev *PCI_Device = NULL; - /* - Interrogate PCI Configuration Space for any FlashPoint Host Adapters. - */ - while ((PCI_Device = pci_get_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) { - unsigned char Bus; - unsigned char Device; - unsigned int IRQ_Channel; - unsigned long BaseAddress0; - unsigned long BaseAddress1; - unsigned long IO_Address; - unsigned long PCI_Address; - - if (pci_enable_device(PCI_Device)) - continue; - - if (pci_set_dma_mask(PCI_Device, DMA_BIT_MASK(32))) - continue; - - Bus = PCI_Device->bus->number; - Device = PCI_Device->devfn >> 3; - IRQ_Channel = PCI_Device->irq; - IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0); - PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1); -#ifdef CONFIG_SCSI_FLASHPOINT - if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) { - BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "FlashPoint Host Adapter\n", NULL, BaseAddress0); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); - continue; - } - if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) { - BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "FlashPoint Host Adapter\n", NULL, BaseAddress1); - BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, Bus, Device, PCI_Address); - continue; - } - if (IRQ_Channel == 0) { - BusLogic_Error("BusLogic: IRQ Channel %d invalid for " "FlashPoint Host Adapter\n", NULL, IRQ_Channel); - BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address); - continue; - } - if (BusLogic_GlobalOptions.TraceProbe) { - BusLogic_Notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL); - BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, Bus, Device, IO_Address, PCI_Address); - } - if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++]; - ProbeInfo->HostAdapterType = BusLogic_FlashPoint; - ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus; - ProbeInfo->IO_Address = IO_Address; - ProbeInfo->PCI_Address = PCI_Address; - ProbeInfo->Bus = Bus; - ProbeInfo->Device = Device; - ProbeInfo->IRQ_Channel = IRQ_Channel; - ProbeInfo->PCI_Device = pci_dev_get(PCI_Device); - FlashPointCount++; - } else - BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL); -#else - BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", NULL, Bus, Device); - BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, irq %d, " "but FlashPoint\n", NULL, IO_Address, PCI_Address, IRQ_Channel); - BusLogic_Error("BusLogic: support was omitted in this kernel " "configuration.\n", NULL); -#endif - } - /* - The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of - increasing PCI Bus and Device Number, so sort the probe information into - the same order the BIOS uses. - */ - BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[FlashPointIndex], FlashPointCount); - return FlashPointCount; -} - - -/* - BusLogic_InitializeProbeInfoList initializes the list of I/O Address and Bus - Probe Information to be checked for potential BusLogic SCSI Host Adapters by - interrogating the PCI Configuration Space on PCI machines as well as from the - list of standard BusLogic MultiMaster ISA I/O Addresses. By default, if both - FlashPoint and PCI MultiMaster Host Adapters are present, this driver will - probe for FlashPoint Host Adapters first unless the BIOS primary disk is - controlled by the first PCI MultiMaster Host Adapter, in which case - MultiMaster Host Adapters will be probed first. The BusLogic Driver Options - specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force - a particular probe order. -*/ - -static void __init BusLogic_InitializeProbeInfoList(struct BusLogic_HostAdapter - *PrototypeHostAdapter) -{ - /* - If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint - Host Adapters; otherwise, default to the standard ISA MultiMaster probe. - */ - if (!BusLogic_ProbeOptions.NoProbePCI) { - if (BusLogic_ProbeOptions.MultiMasterFirst) { - BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - } else if (BusLogic_ProbeOptions.FlashPointFirst) { - BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - } else { - int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter); - int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter); - if (FlashPointCount > 0 && PCIMultiMasterCount > 0) { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[FlashPointCount]; - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; - struct BusLogic_BIOSDriveMapByte Drive0MapByte; - while (ProbeInfo->HostAdapterBusType != BusLogic_PCI_Bus) - ProbeInfo++; - HostAdapter->IO_Address = ProbeInfo->IO_Address; - FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_BIOS_BaseOffset + BusLogic_BIOS_DriveMapOffset + 0; - FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(Drive0MapByte); - BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &Drive0MapByte, sizeof(Drive0MapByte)); - /* - If the Map Byte for BIOS Drive 0 indicates that BIOS Drive 0 - is controlled by this PCI MultiMaster Host Adapter, then - reverse the probe order so that MultiMaster Host Adapters are - probed before FlashPoint Host Adapters. - */ - if (Drive0MapByte.DiskGeometry != BusLogic_BIOS_Disk_Not_Installed) { - struct BusLogic_ProbeInfo SavedProbeInfo[BusLogic_MaxHostAdapters]; - int MultiMasterCount = BusLogic_ProbeInfoCount - FlashPointCount; - memcpy(SavedProbeInfo, BusLogic_ProbeInfoList, BusLogic_ProbeInfoCount * sizeof(struct BusLogic_ProbeInfo)); - memcpy(&BusLogic_ProbeInfoList[0], &SavedProbeInfo[FlashPointCount], MultiMasterCount * sizeof(struct BusLogic_ProbeInfo)); - memcpy(&BusLogic_ProbeInfoList[MultiMasterCount], &SavedProbeInfo[0], FlashPointCount * sizeof(struct BusLogic_ProbeInfo)); - } - } - } - } else - BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter); -} - - -#else -#define BusLogic_InitializeProbeInfoList(adapter) \ - BusLogic_InitializeProbeInfoListISA(adapter) -#endif /* CONFIG_PCI */ - - -/* - BusLogic_Failure prints a standardized error message, and then returns false. -*/ - -static bool BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *ErrorMessage) -{ - BusLogic_AnnounceDriver(HostAdapter); - if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) { - BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n", HostAdapter); - BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device, HostAdapter->IO_Address, HostAdapter->PCI_Address); - } else - BusLogic_Error("While configuring BusLogic Host Adapter at " "I/O Address 0x%X:\n", HostAdapter, HostAdapter->IO_Address); - BusLogic_Error("%s FAILED - DETACHING\n", HostAdapter, ErrorMessage); - if (BusLogic_CommandFailureReason != NULL) - BusLogic_Error("ADDITIONAL FAILURE INFO - %s\n", HostAdapter, BusLogic_CommandFailureReason); - return false; -} - - -/* - BusLogic_ProbeHostAdapter probes for a BusLogic Host Adapter. -*/ - -static bool __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *HostAdapter) -{ - union BusLogic_StatusRegister StatusRegister; - union BusLogic_InterruptRegister InterruptRegister; - union BusLogic_GeometryRegister GeometryRegister; - /* - FlashPoint Host Adapters are Probed by the FlashPoint SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - FlashPointInfo->BaseAddress = (u32) HostAdapter->IO_Address; - FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel; - FlashPointInfo->Present = false; - if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && FlashPointInfo->Present)) { - BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device); - BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, " "but FlashPoint\n", HostAdapter, HostAdapter->IO_Address, HostAdapter->PCI_Address); - BusLogic_Error("BusLogic: Probe Function failed to validate it.\n", HostAdapter); - return false; - } - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n", HostAdapter, HostAdapter->IO_Address); - /* - Indicate the Host Adapter Probe completed successfully. - */ - return true; - } - /* - Read the Status, Interrupt, and Geometry Registers to test if there are I/O - ports that respond, and to check the values to determine if they are from a - BusLogic Host Adapter. A nonexistent I/O port will return 0xFF, in which - case there is definitely no BusLogic Host Adapter at this base I/O Address. - The test here is a subset of that used by the BusLogic Host Adapter BIOS. - */ - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " "Geometry 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All, InterruptRegister.All, GeometryRegister.All); - if (StatusRegister.All == 0 || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.CommandParameterRegisterBusy || StatusRegister.sr.Reserved || StatusRegister.sr.CommandInvalid || InterruptRegister.ir.Reserved != 0) - return false; - /* - Check the undocumented Geometry Register to test if there is an I/O port - that responded. Adaptec Host Adapters do not implement the Geometry - Register, so this test helps serve to avoid incorrectly recognizing an - Adaptec 1542A or 1542B as a BusLogic. Unfortunately, the Adaptec 1542C - series does respond to the Geometry Register I/O port, but it will be - rejected later when the Inquire Extended Setup Information command is - issued in BusLogic_CheckHostAdapter. The AMI FastDisk Host Adapter is a - BusLogic clone that implements the same interface as earlier BusLogic - Host Adapters, including the undocumented commands, and is therefore - supported by this driver. However, the AMI FastDisk always returns 0x00 - upon reading the Geometry Register, so the extended translation option - should always be left disabled on the AMI FastDisk. - */ - if (GeometryRegister.All == 0xFF) - return false; - /* - Indicate the Host Adapter Probe completed successfully. - */ - return true; -} - - -/* - BusLogic_HardwareResetHostAdapter issues a Hardware Reset to the Host Adapter - and waits for Host Adapter Diagnostics to complete. If HardReset is true, a - Hard Reset is performed which also initiates a SCSI Bus Reset. Otherwise, a - Soft Reset is performed which only resets the Host Adapter without forcing a - SCSI Bus Reset. -*/ - -static bool BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter - *HostAdapter, bool HardReset) -{ - union BusLogic_StatusRegister StatusRegister; - int TimeoutCounter; - /* - FlashPoint Host Adapters are Hard Reset by the FlashPoint SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - FlashPointInfo->HostSoftReset = !HardReset; - FlashPointInfo->ReportDataUnderrun = true; - HostAdapter->CardHandle = FlashPoint_HardwareResetHostAdapter(FlashPointInfo); - if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) - return false; - /* - Indicate the Host Adapter Hard Reset completed successfully. - */ - return true; - } - /* - Issue a Hard Reset or Soft Reset Command to the Host Adapter. The Host - Adapter should respond by setting Diagnostic Active in the Status Register. - */ - if (HardReset) - BusLogic_HardReset(HostAdapter); - else - BusLogic_SoftReset(HostAdapter); - /* - Wait until Diagnostic Active is set in the Status Register. - */ - TimeoutCounter = 5 * 10000; - while (--TimeoutCounter >= 0) { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.DiagnosticActive) - break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) - return false; - /* - Wait 100 microseconds to allow completion of any initial diagnostic - activity which might leave the contents of the Status Register - unpredictable. - */ - udelay(100); - /* - Wait until Diagnostic Active is reset in the Status Register. - */ - TimeoutCounter = 10 * 10000; - while (--TimeoutCounter >= 0) { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (!StatusRegister.sr.DiagnosticActive) - break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) - return false; - /* - Wait until at least one of the Diagnostic Failure, Host Adapter Ready, - or Data In Register Ready bits is set in the Status Register. - */ - TimeoutCounter = 10000; - while (--TimeoutCounter >= 0) { - StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter); - if (StatusRegister.sr.DiagnosticFailure || StatusRegister.sr.HostAdapterReady || StatusRegister.sr.DataInRegisterReady) - break; - udelay(100); - } - if (BusLogic_GlobalOptions.TraceHardwareReset) - BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All); - if (TimeoutCounter < 0) - return false; - /* - If Diagnostic Failure is set or Host Adapter Ready is reset, then an - error occurred during the Host Adapter diagnostics. If Data In Register - Ready is set, then there is an Error Code available. - */ - if (StatusRegister.sr.DiagnosticFailure || !StatusRegister.sr.HostAdapterReady) { - BusLogic_CommandFailureReason = NULL; - BusLogic_Failure(HostAdapter, "HARD RESET DIAGNOSTICS"); - BusLogic_Error("HOST ADAPTER STATUS REGISTER = %02X\n", HostAdapter, StatusRegister.All); - if (StatusRegister.sr.DataInRegisterReady) { - unsigned char ErrorCode = BusLogic_ReadDataInRegister(HostAdapter); - BusLogic_Error("HOST ADAPTER ERROR CODE = %d\n", HostAdapter, ErrorCode); - } - return false; - } - /* - Indicate the Host Adapter Hard Reset completed successfully. - */ - return true; -} - - -/* - BusLogic_CheckHostAdapter checks to be sure this really is a BusLogic - Host Adapter. -*/ - -static bool __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *HostAdapter) -{ - struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; - unsigned char RequestedReplyLength; - bool Result = true; - /* - FlashPoint Host Adapters do not require this protection. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - return true; - /* - Issue the Inquire Extended Setup Information command. Only genuine - BusLogic Host Adapters and true clones support this command. Adaptec 1542C - series Host Adapters that respond to the Geometry Register I/O port will - fail this command. - */ - RequestedReplyLength = sizeof(ExtendedSetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &ExtendedSetupInformation, sizeof(ExtendedSetupInformation)) - != sizeof(ExtendedSetupInformation)) - Result = false; - /* - Provide tracing information if requested and return. - */ - if (BusLogic_GlobalOptions.TraceProbe) - BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter, HostAdapter->IO_Address, (Result ? "Found" : "Not Found")); - return Result; -} - - -/* - BusLogic_ReadHostAdapterConfiguration reads the Configuration Information - from Host Adapter and initializes the Host Adapter structure. -*/ - -static bool __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_HostAdapter - *HostAdapter) -{ - struct BusLogic_BoardID BoardID; - struct BusLogic_Configuration Configuration; - struct BusLogic_SetupInformation SetupInformation; - struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation; - unsigned char HostAdapterModelNumber[5]; - unsigned char FirmwareVersion3rdDigit; - unsigned char FirmwareVersionLetter; - struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation; - struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest; - struct BusLogic_AutoSCSIData AutoSCSIData; - union BusLogic_GeometryRegister GeometryRegister; - unsigned char RequestedReplyLength; - unsigned char *TargetPointer, Character; - int TargetID, i; - /* - Configuration Information for FlashPoint Host Adapters is provided in the - FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function. - Initialize fields in the Host Adapter structure from the FlashPoint_Info - structure. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) { - struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo; - TargetPointer = HostAdapter->ModelName; - *TargetPointer++ = 'B'; - *TargetPointer++ = 'T'; - *TargetPointer++ = '-'; - for (i = 0; i < sizeof(FlashPointInfo->ModelNumber); i++) - *TargetPointer++ = FlashPointInfo->ModelNumber[i]; - *TargetPointer++ = '\0'; - strcpy(HostAdapter->FirmwareVersion, FlashPoint_FirmwareVersion); - HostAdapter->SCSI_ID = FlashPointInfo->SCSI_ID; - HostAdapter->ExtendedTranslationEnabled = FlashPointInfo->ExtendedTranslationEnabled; - HostAdapter->ParityCheckingEnabled = FlashPointInfo->ParityCheckingEnabled; - HostAdapter->BusResetEnabled = !FlashPointInfo->HostSoftReset; - HostAdapter->LevelSensitiveInterrupt = true; - HostAdapter->HostWideSCSI = FlashPointInfo->HostWideSCSI; - HostAdapter->HostDifferentialSCSI = false; - HostAdapter->HostSupportsSCAM = true; - HostAdapter->HostUltraSCSI = true; - HostAdapter->ExtendedLUNSupport = true; - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = FlashPointInfo->LowByteTerminated; - HostAdapter->HighByteTerminated = FlashPointInfo->HighByteTerminated; - HostAdapter->SCAM_Enabled = FlashPointInfo->SCAM_Enabled; - HostAdapter->SCAM_Level2 = FlashPointInfo->SCAM_Level2; - HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; - HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); - HostAdapter->MaxLogicalUnits = 32; - HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; - HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; - HostAdapter->DriverQueueDepth = 255; - HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth; - HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted; - HostAdapter->FastPermitted = FlashPointInfo->FastPermitted; - HostAdapter->UltraPermitted = FlashPointInfo->UltraPermitted; - HostAdapter->WidePermitted = FlashPointInfo->WidePermitted; - HostAdapter->DisconnectPermitted = FlashPointInfo->DisconnectPermitted; - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - goto Common; - } - /* - Issue the Inquire Board ID command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, &BoardID, sizeof(BoardID)) != sizeof(BoardID)) - return BusLogic_Failure(HostAdapter, "INQUIRE BOARD ID"); - /* - Issue the Inquire Configuration command. - */ - if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, NULL, 0, &Configuration, sizeof(Configuration)) - != sizeof(Configuration)) - return BusLogic_Failure(HostAdapter, "INQUIRE CONFIGURATION"); - /* - Issue the Inquire Setup Information command. - */ - RequestedReplyLength = sizeof(SetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &SetupInformation, sizeof(SetupInformation)) - != sizeof(SetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); - /* - Issue the Inquire Extended Setup Information command. - */ - RequestedReplyLength = sizeof(ExtendedSetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &ExtendedSetupInformation, sizeof(ExtendedSetupInformation)) - != sizeof(ExtendedSetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE EXTENDED SETUP INFORMATION"); - /* - Issue the Inquire Firmware Version 3rd Digit command. - */ - FirmwareVersion3rdDigit = '\0'; - if (BoardID.FirmwareVersion1stDigit > '0') - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, NULL, 0, &FirmwareVersion3rdDigit, sizeof(FirmwareVersion3rdDigit)) - != sizeof(FirmwareVersion3rdDigit)) - return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); - /* - Issue the Inquire Host Adapter Model Number command. - */ - if (ExtendedSetupInformation.BusType == 'A' && BoardID.FirmwareVersion1stDigit == '2') - /* BusLogic BT-542B ISA 2.xx */ - strcpy(HostAdapterModelNumber, "542B"); - else if (ExtendedSetupInformation.BusType == 'E' && BoardID.FirmwareVersion1stDigit == '2' && (BoardID.FirmwareVersion2ndDigit <= '1' || (BoardID.FirmwareVersion2ndDigit == '2' && FirmwareVersion3rdDigit == '0'))) - /* BusLogic BT-742A EISA 2.1x or 2.20 */ - strcpy(HostAdapterModelNumber, "742A"); - else if (ExtendedSetupInformation.BusType == 'E' && BoardID.FirmwareVersion1stDigit == '0') - /* AMI FastDisk EISA Series 441 0.x */ - strcpy(HostAdapterModelNumber, "747A"); - else { - RequestedReplyLength = sizeof(HostAdapterModelNumber); - if (BusLogic_Command(HostAdapter, BusLogic_InquireHostAdapterModelNumber, &RequestedReplyLength, sizeof(RequestedReplyLength), &HostAdapterModelNumber, sizeof(HostAdapterModelNumber)) - != sizeof(HostAdapterModelNumber)) - return BusLogic_Failure(HostAdapter, "INQUIRE HOST ADAPTER MODEL NUMBER"); - } - /* - BusLogic MultiMaster Host Adapters can be identified by their model number - and the major version number of their firmware as follows: - - 5.xx BusLogic "W" Series Host Adapters: - BT-948/958/958D - 4.xx BusLogic "C" Series Host Adapters: - BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF - 3.xx BusLogic "S" Series Host Adapters: - BT-747S/747D/757S/757D/445S/545S/542D - BT-542B/742A (revision H) - 2.xx BusLogic "A" Series Host Adapters: - BT-542B/742A (revision G and below) - 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter - */ - /* - Save the Model Name and Host Adapter Name in the Host Adapter structure. - */ - TargetPointer = HostAdapter->ModelName; - *TargetPointer++ = 'B'; - *TargetPointer++ = 'T'; - *TargetPointer++ = '-'; - for (i = 0; i < sizeof(HostAdapterModelNumber); i++) { - Character = HostAdapterModelNumber[i]; - if (Character == ' ' || Character == '\0') - break; - *TargetPointer++ = Character; - } - *TargetPointer++ = '\0'; - /* - Save the Firmware Version in the Host Adapter structure. - */ - TargetPointer = HostAdapter->FirmwareVersion; - *TargetPointer++ = BoardID.FirmwareVersion1stDigit; - *TargetPointer++ = '.'; - *TargetPointer++ = BoardID.FirmwareVersion2ndDigit; - if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0') - *TargetPointer++ = FirmwareVersion3rdDigit; - *TargetPointer = '\0'; - /* - Issue the Inquire Firmware Version Letter command. - */ - if (strcmp(HostAdapter->FirmwareVersion, "3.3") >= 0) { - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, NULL, 0, &FirmwareVersionLetter, sizeof(FirmwareVersionLetter)) - != sizeof(FirmwareVersionLetter)) - return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER"); - if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0') - *TargetPointer++ = FirmwareVersionLetter; - *TargetPointer = '\0'; - } - /* - Save the Host Adapter SCSI ID in the Host Adapter structure. - */ - HostAdapter->SCSI_ID = Configuration.HostAdapterID; - /* - Determine the Bus Type and save it in the Host Adapter structure, determine - and save the IRQ Channel if necessary, and determine and save the DMA - Channel for ISA Host Adapters. - */ - HostAdapter->HostAdapterBusType = BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4']; - if (HostAdapter->IRQ_Channel == 0) { - if (Configuration.IRQ_Channel9) - HostAdapter->IRQ_Channel = 9; - else if (Configuration.IRQ_Channel10) - HostAdapter->IRQ_Channel = 10; - else if (Configuration.IRQ_Channel11) - HostAdapter->IRQ_Channel = 11; - else if (Configuration.IRQ_Channel12) - HostAdapter->IRQ_Channel = 12; - else if (Configuration.IRQ_Channel14) - HostAdapter->IRQ_Channel = 14; - else if (Configuration.IRQ_Channel15) - HostAdapter->IRQ_Channel = 15; - } - if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus) { - if (Configuration.DMA_Channel5) - HostAdapter->DMA_Channel = 5; - else if (Configuration.DMA_Channel6) - HostAdapter->DMA_Channel = 6; - else if (Configuration.DMA_Channel7) - HostAdapter->DMA_Channel = 7; - } - /* - Determine whether Extended Translation is enabled and save it in - the Host Adapter structure. - */ - GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter); - HostAdapter->ExtendedTranslationEnabled = GeometryRegister.gr.ExtendedTranslationEnabled; - /* - Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide - SCSI flag, Differential SCSI flag, SCAM Supported flag, and - Ultra SCSI flag in the Host Adapter structure. - */ - HostAdapter->HostAdapterScatterGatherLimit = ExtendedSetupInformation.ScatterGatherLimit; - HostAdapter->DriverScatterGatherLimit = HostAdapter->HostAdapterScatterGatherLimit; - if (HostAdapter->HostAdapterScatterGatherLimit > BusLogic_ScatterGatherLimit) - HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit; - if (ExtendedSetupInformation.Misc.LevelSensitiveInterrupt) - HostAdapter->LevelSensitiveInterrupt = true; - HostAdapter->HostWideSCSI = ExtendedSetupInformation.HostWideSCSI; - HostAdapter->HostDifferentialSCSI = ExtendedSetupInformation.HostDifferentialSCSI; - HostAdapter->HostSupportsSCAM = ExtendedSetupInformation.HostSupportsSCAM; - HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI; - /* - Determine whether Extended LUN Format CCBs are supported and save the - information in the Host Adapter structure. - */ - if (HostAdapter->FirmwareVersion[0] == '5' || (HostAdapter->FirmwareVersion[0] == '4' && HostAdapter->HostWideSCSI)) - HostAdapter->ExtendedLUNSupport = true; - /* - Issue the Inquire PCI Host Adapter Information command to read the - Termination Information from "W" series MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] == '5') { - if (BusLogic_Command(HostAdapter, BusLogic_InquirePCIHostAdapterInformation, NULL, 0, &PCIHostAdapterInformation, sizeof(PCIHostAdapterInformation)) - != sizeof(PCIHostAdapterInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE PCI HOST ADAPTER INFORMATION"); - /* - Save the Termination Information in the Host Adapter structure. - */ - if (PCIHostAdapterInformation.GenericInfoValid) { - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = PCIHostAdapterInformation.LowByteTerminated; - HostAdapter->HighByteTerminated = PCIHostAdapterInformation.HighByteTerminated; - } - } - /* - Issue the Fetch Host Adapter Local RAM command to read the AutoSCSI data - from "W" and "C" series MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] >= '4') { - FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset; - FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIData); - if (BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &AutoSCSIData, sizeof(AutoSCSIData)) - != sizeof(AutoSCSIData)) - return BusLogic_Failure(HostAdapter, "FETCH HOST ADAPTER LOCAL RAM"); - /* - Save the Parity Checking Enabled, Bus Reset Enabled, and Termination - Information in the Host Adapter structure. - */ - HostAdapter->ParityCheckingEnabled = AutoSCSIData.ParityCheckingEnabled; - HostAdapter->BusResetEnabled = AutoSCSIData.BusResetEnabled; - if (HostAdapter->FirmwareVersion[0] == '4') { - HostAdapter->TerminationInfoValid = true; - HostAdapter->LowByteTerminated = AutoSCSIData.LowByteTerminated; - HostAdapter->HighByteTerminated = AutoSCSIData.HighByteTerminated; - } - /* - Save the Wide Permitted, Fast Permitted, Synchronous Permitted, - Disconnect Permitted, Ultra Permitted, and SCAM Information in the - Host Adapter structure. - */ - HostAdapter->WidePermitted = AutoSCSIData.WidePermitted; - HostAdapter->FastPermitted = AutoSCSIData.FastPermitted; - HostAdapter->SynchronousPermitted = AutoSCSIData.SynchronousPermitted; - HostAdapter->DisconnectPermitted = AutoSCSIData.DisconnectPermitted; - if (HostAdapter->HostUltraSCSI) - HostAdapter->UltraPermitted = AutoSCSIData.UltraPermitted; - if (HostAdapter->HostSupportsSCAM) { - HostAdapter->SCAM_Enabled = AutoSCSIData.SCAM_Enabled; - HostAdapter->SCAM_Level2 = AutoSCSIData.SCAM_Level2; - } - } - /* - Initialize fields in the Host Adapter structure for "S" and "A" series - MultiMaster Host Adapters. - */ - if (HostAdapter->FirmwareVersion[0] < '4') { - if (SetupInformation.SynchronousInitiationEnabled) { - HostAdapter->SynchronousPermitted = 0xFF; - if (HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus) { - if (ExtendedSetupInformation.Misc.FastOnEISA) - HostAdapter->FastPermitted = 0xFF; - if (strcmp(HostAdapter->ModelName, "BT-757") == 0) - HostAdapter->WidePermitted = 0xFF; - } - } - HostAdapter->DisconnectPermitted = 0xFF; - HostAdapter->ParityCheckingEnabled = SetupInformation.ParityCheckingEnabled; - HostAdapter->BusResetEnabled = true; - } - /* - Determine the maximum number of Target IDs and Logical Units supported by - this driver for Wide and Narrow Host Adapters. - */ - HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8); - HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8); - /* - Select appropriate values for the Mailbox Count, Driver Queue Depth, - Initial CCBs, and Incremental CCBs variables based on whether or not Strict - Round Robin Mode is supported. If Strict Round Robin Mode is supported, - then there is no performance degradation in using the maximum possible - number of Outgoing and Incoming Mailboxes and allowing the Tagged and - Untagged Queue Depths to determine the actual utilization. If Strict Round - Robin Mode is not supported, then the Host Adapter must scan all the - Outgoing Mailboxes whenever an Outgoing Mailbox entry is made, which can - cause a substantial performance penalty. The host adapters actually have - room to store the following number of CCBs internally; that is, they can - internally queue and manage this many active commands on the SCSI bus - simultaneously. Performance measurements demonstrate that the Driver Queue - Depth should be set to the Mailbox Count, rather than the Host Adapter - Queue Depth (internal CCB capacity), as it is more efficient to have the - queued commands waiting in Outgoing Mailboxes if necessary than to block - the process in the higher levels of the SCSI Subsystem. - - 192 BT-948/958/958D - 100 BT-946C/956C/956CD/747C/757C/757CD/445C - 50 BT-545C/540CF - 30 BT-747S/747D/757S/757D/445S/545S/542D/542B/742A - */ - if (HostAdapter->FirmwareVersion[0] == '5') - HostAdapter->HostAdapterQueueDepth = 192; - else if (HostAdapter->FirmwareVersion[0] == '4') - HostAdapter->HostAdapterQueueDepth = (HostAdapter->HostAdapterBusType != BusLogic_ISA_Bus ? 100 : 50); - else - HostAdapter->HostAdapterQueueDepth = 30; - if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) { - HostAdapter->StrictRoundRobinModeSupport = true; - HostAdapter->MailboxCount = BusLogic_MaxMailboxes; - } else { - HostAdapter->StrictRoundRobinModeSupport = false; - HostAdapter->MailboxCount = 32; - } - HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount; - HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize; - HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize; - /* - Tagged Queuing support is available and operates properly on all "W" series - MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with - firmware version 4.22 and above, and on "S" series MultiMaster Host - Adapters with firmware version 3.35 and above. - */ - HostAdapter->TaggedQueuingPermitted = 0; - switch (HostAdapter->FirmwareVersion[0]) { - case '5': - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - case '4': - if (strcmp(HostAdapter->FirmwareVersion, "4.22") >= 0) - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - case '3': - if (strcmp(HostAdapter->FirmwareVersion, "3.35") >= 0) - HostAdapter->TaggedQueuingPermitted = 0xFFFF; - break; - } - /* - Determine the Host Adapter BIOS Address if the BIOS is enabled and - save it in the Host Adapter structure. The BIOS is disabled if the - BIOS_Address is 0. - */ - HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12; - /* - ISA Host Adapters require Bounce Buffers if there is more than 16MB memory. - */ - if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus && (void *) high_memory > (void *) MAX_DMA_ADDRESS) - HostAdapter->BounceBuffersRequired = true; - /* - BusLogic BT-445S Host Adapters prior to board revision E have a hardware - bug whereby when the BIOS is enabled, transfers to/from the same address - range the BIOS occupies modulo 16MB are handled incorrectly. Only properly - functioning BT-445S Host Adapters have firmware version 3.37, so require - that ISA Bounce Buffers be used for the buggy BT-445S models if there is - more than 16MB memory. - */ - if (HostAdapter->BIOS_Address > 0 && strcmp(HostAdapter->ModelName, "BT-445S") == 0 && strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 && (void *) high_memory > (void *) MAX_DMA_ADDRESS) - HostAdapter->BounceBuffersRequired = true; - /* - Initialize parameters common to MultiMaster and FlashPoint Host Adapters. - */ - Common: - /* - Initialize the Host Adapter Full Model Name from the Model Name. - */ - strcpy(HostAdapter->FullModelName, "BusLogic "); - strcat(HostAdapter->FullModelName, HostAdapter->ModelName); - /* - Select an appropriate value for the Tagged Queue Depth either from a - BusLogic Driver Options specification, or based on whether this Host - Adapter requires that ISA Bounce Buffers be used. The Tagged Queue Depth - is left at 0 for automatic determination in BusLogic_SelectQueueDepths. - Initialize the Untagged Queue Depth. - */ - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) { - unsigned char QueueDepth = 0; - if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->QueueDepth[TargetID] > 0) - QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID]; - else if (HostAdapter->BounceBuffersRequired) - QueueDepth = BusLogic_TaggedQueueDepthBB; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - } - if (HostAdapter->BounceBuffersRequired) - HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB; - else - HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth; - if (HostAdapter->DriverOptions != NULL) - HostAdapter->CommonQueueDepth = HostAdapter->DriverOptions->CommonQueueDepth; - if (HostAdapter->CommonQueueDepth > 0 && HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth) - HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth; - /* - Tagged Queuing is only allowed if Disconnect/Reconnect is permitted. - Therefore, mask the Tagged Queuing Permitted Default bits with the - Disconnect/Reconnect Permitted bits. - */ - HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted; - /* - Combine the default Tagged Queuing Permitted bits with any BusLogic Driver - Options Tagged Queuing specification. - */ - if (HostAdapter->DriverOptions != NULL) - HostAdapter->TaggedQueuingPermitted = - (HostAdapter->DriverOptions->TaggedQueuingPermitted & HostAdapter->DriverOptions->TaggedQueuingPermittedMask) | (HostAdapter->TaggedQueuingPermitted & ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask); - - /* - Select an appropriate value for Bus Settle Time either from a BusLogic - Driver Options specification, or from BusLogic_DefaultBusSettleTime. - */ - if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->BusSettleTime > 0) - HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime; - else - HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime; - /* - Indicate reading the Host Adapter Configuration completed successfully. - */ - return true; -} - - -/* - BusLogic_ReportHostAdapterConfiguration reports the configuration of - Host Adapter. -*/ - -static bool __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_HostAdapter - *HostAdapter) -{ - unsigned short AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1; - unsigned short SynchronousPermitted, FastPermitted; - unsigned short UltraPermitted, WidePermitted; - unsigned short DisconnectPermitted, TaggedQueuingPermitted; - bool CommonSynchronousNegotiation, CommonTaggedQueueDepth; - char SynchronousString[BusLogic_MaxTargetDevices + 1]; - char WideString[BusLogic_MaxTargetDevices + 1]; - char DisconnectString[BusLogic_MaxTargetDevices + 1]; - char TaggedQueuingString[BusLogic_MaxTargetDevices + 1]; - char *SynchronousMessage = SynchronousString; - char *WideMessage = WideString; - char *DisconnectMessage = DisconnectString; - char *TaggedQueuingMessage = TaggedQueuingString; - int TargetID; - BusLogic_Info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n", - HostAdapter, HostAdapter->ModelName, - BusLogic_HostAdapterBusNames[HostAdapter->HostAdapterBusType], (HostAdapter->HostWideSCSI ? " Wide" : ""), (HostAdapter->HostDifferentialSCSI ? " Differential" : ""), (HostAdapter->HostUltraSCSI ? " Ultra" : "")); - BusLogic_Info(" Firmware Version: %s, I/O Address: 0x%X, " "IRQ Channel: %d/%s\n", HostAdapter, HostAdapter->FirmwareVersion, HostAdapter->IO_Address, HostAdapter->IRQ_Channel, (HostAdapter->LevelSensitiveInterrupt ? "Level" : "Edge")); - if (HostAdapter->HostAdapterBusType != BusLogic_PCI_Bus) { - BusLogic_Info(" DMA Channel: ", HostAdapter); - if (HostAdapter->DMA_Channel > 0) - BusLogic_Info("%d, ", HostAdapter, HostAdapter->DMA_Channel); - else - BusLogic_Info("None, ", HostAdapter); - if (HostAdapter->BIOS_Address > 0) - BusLogic_Info("BIOS Address: 0x%X, ", HostAdapter, HostAdapter->BIOS_Address); - else - BusLogic_Info("BIOS Address: None, ", HostAdapter); - } else { - BusLogic_Info(" PCI Bus: %d, Device: %d, Address: ", HostAdapter, HostAdapter->Bus, HostAdapter->Device); - if (HostAdapter->PCI_Address > 0) - BusLogic_Info("0x%X, ", HostAdapter, HostAdapter->PCI_Address); - else - BusLogic_Info("Unassigned, ", HostAdapter); - } - BusLogic_Info("Host Adapter SCSI ID: %d\n", HostAdapter, HostAdapter->SCSI_ID); - BusLogic_Info(" Parity Checking: %s, Extended Translation: %s\n", HostAdapter, (HostAdapter->ParityCheckingEnabled ? "Enabled" : "Disabled"), (HostAdapter->ExtendedTranslationEnabled ? "Enabled" : "Disabled")); - AllTargetsMask &= ~(1 << HostAdapter->SCSI_ID); - SynchronousPermitted = HostAdapter->SynchronousPermitted & AllTargetsMask; - FastPermitted = HostAdapter->FastPermitted & AllTargetsMask; - UltraPermitted = HostAdapter->UltraPermitted & AllTargetsMask; - if ((BusLogic_MultiMasterHostAdapterP(HostAdapter) && (HostAdapter->FirmwareVersion[0] >= '4' || HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus)) || BusLogic_FlashPointHostAdapterP(HostAdapter)) { - CommonSynchronousNegotiation = false; - if (SynchronousPermitted == 0) { - SynchronousMessage = "Disabled"; - CommonSynchronousNegotiation = true; - } else if (SynchronousPermitted == AllTargetsMask) { - if (FastPermitted == 0) { - SynchronousMessage = "Slow"; - CommonSynchronousNegotiation = true; - } else if (FastPermitted == AllTargetsMask) { - if (UltraPermitted == 0) { - SynchronousMessage = "Fast"; - CommonSynchronousNegotiation = true; - } else if (UltraPermitted == AllTargetsMask) { - SynchronousMessage = "Ultra"; - CommonSynchronousNegotiation = true; - } - } - } - if (!CommonSynchronousNegotiation) { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - SynchronousString[TargetID] = ((!(SynchronousPermitted & (1 << TargetID))) ? 'N' : (!(FastPermitted & (1 << TargetID)) ? 'S' : (!(UltraPermitted & (1 << TargetID)) ? 'F' : 'U'))); - SynchronousString[HostAdapter->SCSI_ID] = '#'; - SynchronousString[HostAdapter->MaxTargetDevices] = '\0'; - } - } else - SynchronousMessage = (SynchronousPermitted == 0 ? "Disabled" : "Enabled"); - WidePermitted = HostAdapter->WidePermitted & AllTargetsMask; - if (WidePermitted == 0) - WideMessage = "Disabled"; - else if (WidePermitted == AllTargetsMask) - WideMessage = "Enabled"; - else { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - WideString[TargetID] = ((WidePermitted & (1 << TargetID)) ? 'Y' : 'N'); - WideString[HostAdapter->SCSI_ID] = '#'; - WideString[HostAdapter->MaxTargetDevices] = '\0'; - } - DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask; - if (DisconnectPermitted == 0) - DisconnectMessage = "Disabled"; - else if (DisconnectPermitted == AllTargetsMask) - DisconnectMessage = "Enabled"; - else { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - DisconnectString[TargetID] = ((DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N'); - DisconnectString[HostAdapter->SCSI_ID] = '#'; - DisconnectString[HostAdapter->MaxTargetDevices] = '\0'; - } - TaggedQueuingPermitted = HostAdapter->TaggedQueuingPermitted & AllTargetsMask; - if (TaggedQueuingPermitted == 0) - TaggedQueuingMessage = "Disabled"; - else if (TaggedQueuingPermitted == AllTargetsMask) - TaggedQueuingMessage = "Enabled"; - else { - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - TaggedQueuingString[TargetID] = ((TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N'); - TaggedQueuingString[HostAdapter->SCSI_ID] = '#'; - TaggedQueuingString[HostAdapter->MaxTargetDevices] = '\0'; - } - BusLogic_Info(" Synchronous Negotiation: %s, Wide Negotiation: %s\n", HostAdapter, SynchronousMessage, WideMessage); - BusLogic_Info(" Disconnect/Reconnect: %s, Tagged Queuing: %s\n", HostAdapter, DisconnectMessage, TaggedQueuingMessage); - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { - BusLogic_Info(" Scatter/Gather Limit: %d of %d segments, " "Mailboxes: %d\n", HostAdapter, HostAdapter->DriverScatterGatherLimit, HostAdapter->HostAdapterScatterGatherLimit, HostAdapter->MailboxCount); - BusLogic_Info(" Driver Queue Depth: %d, " "Host Adapter Queue Depth: %d\n", HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->HostAdapterQueueDepth); - } else - BusLogic_Info(" Driver Queue Depth: %d, " "Scatter/Gather Limit: %d segments\n", HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->DriverScatterGatherLimit); - BusLogic_Info(" Tagged Queue Depth: ", HostAdapter); - CommonTaggedQueueDepth = true; - for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0]) { - CommonTaggedQueueDepth = false; - break; - } - if (CommonTaggedQueueDepth) { - if (HostAdapter->QueueDepth[0] > 0) - BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]); - else - BusLogic_Info("Automatic", HostAdapter); - } else - BusLogic_Info("Individual", HostAdapter); - BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter, HostAdapter->UntaggedQueueDepth); - if (HostAdapter->TerminationInfoValid) { - if (HostAdapter->HostWideSCSI) - BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, (HostAdapter->LowByteTerminated ? (HostAdapter->HighByteTerminated ? "Both Enabled" : "Low Enabled") - : (HostAdapter->HighByteTerminated ? "High Enabled" : "Both Disabled"))); - else - BusLogic_Info(" SCSI Bus Termination: %s", HostAdapter, (HostAdapter->LowByteTerminated ? "Enabled" : "Disabled")); - if (HostAdapter->HostSupportsSCAM) - BusLogic_Info(", SCAM: %s", HostAdapter, (HostAdapter->SCAM_Enabled ? (HostAdapter->SCAM_Level2 ? "Enabled, Level 2" : "Enabled, Level 1") - : "Disabled")); - BusLogic_Info("\n", HostAdapter); - } - /* - Indicate reporting the Host Adapter configuration completed successfully. - */ - return true; -} - - -/* - BusLogic_AcquireResources acquires the system resources necessary to use - Host Adapter. -*/ - -static bool __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *HostAdapter) -{ - if (HostAdapter->IRQ_Channel == 0) { - BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", HostAdapter); - return false; - } - /* - Acquire shared access to the IRQ Channel. - */ - if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, IRQF_SHARED, HostAdapter->FullModelName, HostAdapter) < 0) { - BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->IRQ_Channel); - return false; - } - HostAdapter->IRQ_ChannelAcquired = true; - /* - Acquire exclusive access to the DMA Channel. - */ - if (HostAdapter->DMA_Channel > 0) { - if (request_dma(HostAdapter->DMA_Channel, HostAdapter->FullModelName) < 0) { - BusLogic_Error("UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->DMA_Channel); - return false; - } - set_dma_mode(HostAdapter->DMA_Channel, DMA_MODE_CASCADE); - enable_dma(HostAdapter->DMA_Channel); - HostAdapter->DMA_ChannelAcquired = true; - } - /* - Indicate the System Resource Acquisition completed successfully, - */ - return true; -} - - -/* - BusLogic_ReleaseResources releases any system resources previously acquired - by BusLogic_AcquireResources. -*/ - -static void BusLogic_ReleaseResources(struct BusLogic_HostAdapter *HostAdapter) -{ - /* - Release shared access to the IRQ Channel. - */ - if (HostAdapter->IRQ_ChannelAcquired) - free_irq(HostAdapter->IRQ_Channel, HostAdapter); - /* - Release exclusive access to the DMA Channel. - */ - if (HostAdapter->DMA_ChannelAcquired) - free_dma(HostAdapter->DMA_Channel); - /* - Release any allocated memory structs not released elsewhere - */ - if (HostAdapter->MailboxSpace) - pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, HostAdapter->MailboxSpace, HostAdapter->MailboxSpaceHandle); - pci_dev_put(HostAdapter->PCI_Device); - HostAdapter->MailboxSpace = NULL; - HostAdapter->MailboxSpaceHandle = 0; - HostAdapter->MailboxSize = 0; -} - - -/* - BusLogic_InitializeHostAdapter initializes Host Adapter. This is the only - function called during SCSI Host Adapter detection which modifies the state - of the Host Adapter from its initial power on or hard reset state. -*/ - -static bool BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter - *HostAdapter) -{ - struct BusLogic_ExtendedMailboxRequest ExtendedMailboxRequest; - enum BusLogic_RoundRobinModeRequest RoundRobinModeRequest; - enum BusLogic_SetCCBFormatRequest SetCCBFormatRequest; - int TargetID; - /* - Initialize the pointers to the first and last CCBs that are queued for - completion processing. - */ - HostAdapter->FirstCompletedCCB = NULL; - HostAdapter->LastCompletedCCB = NULL; - /* - Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active, - Command Successful Flag, Active Commands, and Commands Since Reset - for each Target Device. - */ - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { - HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; - HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; - HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false; - HostAdapter->ActiveCommands[TargetID] = 0; - HostAdapter->CommandsSinceReset[TargetID] = 0; - } - /* - FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - goto Done; - /* - Initialize the Outgoing and Incoming Mailbox pointers. - */ - HostAdapter->MailboxSize = HostAdapter->MailboxCount * (sizeof(struct BusLogic_OutgoingMailbox) + sizeof(struct BusLogic_IncomingMailbox)); - HostAdapter->MailboxSpace = pci_alloc_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, &HostAdapter->MailboxSpaceHandle); - if (HostAdapter->MailboxSpace == NULL) - return BusLogic_Failure(HostAdapter, "MAILBOX ALLOCATION"); - HostAdapter->FirstOutgoingMailbox = (struct BusLogic_OutgoingMailbox *) HostAdapter->MailboxSpace; - HostAdapter->LastOutgoingMailbox = HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1; - HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->FirstIncomingMailbox = (struct BusLogic_IncomingMailbox *) (HostAdapter->LastOutgoingMailbox + 1); - HostAdapter->LastIncomingMailbox = HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1; - HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - - /* - Initialize the Outgoing and Incoming Mailbox structures. - */ - memset(HostAdapter->FirstOutgoingMailbox, 0, HostAdapter->MailboxCount * sizeof(struct BusLogic_OutgoingMailbox)); - memset(HostAdapter->FirstIncomingMailbox, 0, HostAdapter->MailboxCount * sizeof(struct BusLogic_IncomingMailbox)); - /* - Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. - */ - ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; - ExtendedMailboxRequest.BaseMailboxAddress = (u32) HostAdapter->MailboxSpaceHandle; - if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, &ExtendedMailboxRequest, sizeof(ExtendedMailboxRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "MAILBOX INITIALIZATION"); - /* - Enable Strict Round Robin Mode if supported by the Host Adapter. In - Strict Round Robin Mode, the Host Adapter only looks at the next Outgoing - Mailbox for each new command, rather than scanning through all the - Outgoing Mailboxes to find any that have new commands in them. Strict - Round Robin Mode is significantly more efficient. - */ - if (HostAdapter->StrictRoundRobinModeSupport) { - RoundRobinModeRequest = BusLogic_StrictRoundRobinMode; - if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode, &RoundRobinModeRequest, sizeof(RoundRobinModeRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "ENABLE STRICT ROUND ROBIN MODE"); - } - /* - For Host Adapters that support Extended LUN Format CCBs, issue the Set CCB - Format command to allow 32 Logical Units per Target Device. - */ - if (HostAdapter->ExtendedLUNSupport) { - SetCCBFormatRequest = BusLogic_ExtendedLUNFormatCCB; - if (BusLogic_Command(HostAdapter, BusLogic_SetCCBFormat, &SetCCBFormatRequest, sizeof(SetCCBFormatRequest), NULL, 0) < 0) - return BusLogic_Failure(HostAdapter, "SET CCB FORMAT"); - } - /* - Announce Successful Initialization. - */ - Done: - if (!HostAdapter->HostAdapterInitialized) { - BusLogic_Info("*** %s Initialized Successfully ***\n", HostAdapter, HostAdapter->FullModelName); - BusLogic_Info("\n", HostAdapter); - } else - BusLogic_Warning("*** %s Initialized Successfully ***\n", HostAdapter, HostAdapter->FullModelName); - HostAdapter->HostAdapterInitialized = true; - /* - Indicate the Host Adapter Initialization completed successfully. - */ - return true; -} - - -/* - BusLogic_TargetDeviceInquiry inquires about the Target Devices accessible - through Host Adapter. -*/ - -static bool __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter - *HostAdapter) -{ - u16 InstalledDevices; - u8 InstalledDevicesID0to7[8]; - struct BusLogic_SetupInformation SetupInformation; - u8 SynchronousPeriod[BusLogic_MaxTargetDevices]; - unsigned char RequestedReplyLength; - int TargetID; - /* - Wait a few seconds between the Host Adapter Hard Reset which initiates - a SCSI Bus Reset and issuing any SCSI Commands. Some SCSI devices get - confused if they receive SCSI Commands too soon after a SCSI Bus Reset. - */ - BusLogic_Delay(HostAdapter->BusSettleTime); - /* - FlashPoint Host Adapters do not provide for Target Device Inquiry. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - return true; - /* - Inhibit the Target Device Inquiry if requested. - */ - if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry) - return true; - /* - Issue the Inquire Target Devices command for host adapters with firmware - version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command - for older host adapters. This is necessary to force Synchronous Transfer - Negotiation so that the Inquire Setup Information and Inquire Synchronous - Period commands will return valid data. The Inquire Target Devices command - is preferable to Inquire Installed Devices ID 0 to 7 since it only probes - Logical Unit 0 of each Target Device. - */ - if (strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0) { - - /* - * Issue a Inquire Target Devices command. Inquire Target Devices only - * tests Logical Unit 0 of each Target Device unlike the Inquire Installed - * Devices commands which test Logical Units 0 - 7. Two bytes are - * returned, where byte 0 bit 0 set indicates that Target Device 0 exists, - * and so on. - */ - - if (BusLogic_Command(HostAdapter, BusLogic_InquireTargetDevices, NULL, 0, &InstalledDevices, sizeof(InstalledDevices)) - != sizeof(InstalledDevices)) - return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->TargetFlags[TargetID].TargetExists = (InstalledDevices & (1 << TargetID) ? true : false); - } else { - - /* - * Issue an Inquire Installed Devices command. For each Target Device, - * a byte is returned where bit 0 set indicates that Logical Unit 0 - * exists, bit 1 set indicates that Logical Unit 1 exists, and so on. - */ - - if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7, NULL, 0, &InstalledDevicesID0to7, sizeof(InstalledDevicesID0to7)) - != sizeof(InstalledDevicesID0to7)) - return BusLogic_Failure(HostAdapter, "INQUIRE INSTALLED DEVICES ID 0 TO 7"); - for (TargetID = 0; TargetID < 8; TargetID++) - HostAdapter->TargetFlags[TargetID].TargetExists = (InstalledDevicesID0to7[TargetID] != 0 ? true : false); - } - /* - Issue the Inquire Setup Information command. - */ - RequestedReplyLength = sizeof(SetupInformation); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &SetupInformation, sizeof(SetupInformation)) - != sizeof(SetupInformation)) - return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->SynchronousOffset[TargetID] = (TargetID < 8 ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset : SetupInformation.SynchronousValuesID8to15[TargetID - 8].Offset); - if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0) - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->TargetFlags[TargetID].WideTransfersActive = (TargetID < 8 ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID) - ? true : false) - : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID - 8)) - ? true : false)); - /* - Issue the Inquire Synchronous Period command. - */ - if (HostAdapter->FirmwareVersion[0] >= '3') { - - /* Issue a Inquire Synchronous Period command. For each Target Device, - * a byte is returned which represents the Synchronous Transfer Period - * in units of 10 nanoseconds. - */ - - RequestedReplyLength = sizeof(SynchronousPeriod); - if (BusLogic_Command(HostAdapter, BusLogic_InquireSynchronousPeriod, &RequestedReplyLength, sizeof(RequestedReplyLength), &SynchronousPeriod, sizeof(SynchronousPeriod)) - != sizeof(SynchronousPeriod)) - return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID]; - } else - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0) - HostAdapter->SynchronousPeriod[TargetID] = 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID] - .TransferPeriod; - /* - Indicate the Target Device Inquiry completed successfully. - */ - return true; -} - -/* - BusLogic_InitializeHostStructure initializes the fields in the SCSI Host - structure. The base, io_port, n_io_ports, irq, and dma_channel fields in the - SCSI Host structure are intentionally left uninitialized, as this driver - handles acquisition and release of these resources explicitly, as well as - ensuring exclusive access to the Host Adapter hardware and data structures - through explicit acquisition and release of the Host Adapter's Lock. -*/ - -static void __init BusLogic_InitializeHostStructure(struct BusLogic_HostAdapter - *HostAdapter, struct Scsi_Host *Host) -{ - Host->max_id = HostAdapter->MaxTargetDevices; - Host->max_lun = HostAdapter->MaxLogicalUnits; - Host->max_channel = 0; - Host->unique_id = HostAdapter->IO_Address; - Host->this_id = HostAdapter->SCSI_ID; - Host->can_queue = HostAdapter->DriverQueueDepth; - Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit; - Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired; - Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth; -} - -/* - BusLogic_SlaveConfigure will actually set the queue depth on individual - scsi devices as they are permanently added to the device chain. We - shamelessly rip off the SelectQueueDepths code to make this work mostly - like it used to. Since we don't get called once at the end of the scan - but instead get called for each device, we have to do things a bit - differently. -*/ -static int BusLogic_SlaveConfigure(struct scsi_device *Device) -{ - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Device->host->hostdata; - int TargetID = Device->id; - int QueueDepth = HostAdapter->QueueDepth[TargetID]; - - if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) { - if (QueueDepth == 0) - QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth); - } else { - HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID); - QueueDepth = HostAdapter->UntaggedQueueDepth; - HostAdapter->QueueDepth[TargetID] = QueueDepth; - scsi_adjust_queue_depth(Device, 0, QueueDepth); - } - QueueDepth = 0; - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) - if (HostAdapter->TargetFlags[TargetID].TargetExists) { - QueueDepth += HostAdapter->QueueDepth[TargetID]; - } - if (QueueDepth > HostAdapter->AllocatedCCBs) - BusLogic_CreateAdditionalCCBs(HostAdapter, QueueDepth - HostAdapter->AllocatedCCBs, false); - return 0; -} - -/* - BusLogic_DetectHostAdapter probes for BusLogic Host Adapters at the standard - I/O Addresses where they may be located, initializing, registering, and - reporting the configuration of each BusLogic Host Adapter it finds. It - returns the number of BusLogic Host Adapters successfully initialized and - registered. -*/ - -static int __init BusLogic_init(void) -{ - int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex; - struct BusLogic_HostAdapter *PrototypeHostAdapter; - int ret = 0; - -#ifdef MODULE - if (BusLogic) - BusLogic_Setup(BusLogic); -#endif - - if (BusLogic_ProbeOptions.NoProbe) - return -ENODEV; - BusLogic_ProbeInfoList = - kzalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_KERNEL); - if (BusLogic_ProbeInfoList == NULL) { - BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL); - return -ENOMEM; - } - - PrototypeHostAdapter = - kzalloc(sizeof(struct BusLogic_HostAdapter), GFP_KERNEL); - if (PrototypeHostAdapter == NULL) { - kfree(BusLogic_ProbeInfoList); - BusLogic_Error("BusLogic: Unable to allocate Prototype " "Host Adapter\n", NULL); - return -ENOMEM; - } - -#ifdef MODULE - if (BusLogic != NULL) - BusLogic_Setup(BusLogic); -#endif - BusLogic_InitializeProbeInfoList(PrototypeHostAdapter); - for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++) { - struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex]; - struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter; - struct Scsi_Host *Host; - if (ProbeInfo->IO_Address == 0) - continue; - memset(HostAdapter, 0, sizeof(struct BusLogic_HostAdapter)); - HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType; - HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType; - HostAdapter->IO_Address = ProbeInfo->IO_Address; - HostAdapter->PCI_Address = ProbeInfo->PCI_Address; - HostAdapter->Bus = ProbeInfo->Bus; - HostAdapter->Device = ProbeInfo->Device; - HostAdapter->PCI_Device = ProbeInfo->PCI_Device; - HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel; - HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType]; - - /* - Make sure region is free prior to probing. - */ - if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, - "BusLogic")) - continue; - /* - Probe the Host Adapter. If unsuccessful, abort further initialization. - */ - if (!BusLogic_ProbeHostAdapter(HostAdapter)) { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - continue; - } - /* - Hard Reset the Host Adapter. If unsuccessful, abort further - initialization. - */ - if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - continue; - } - /* - Check the Host Adapter. If unsuccessful, abort further initialization. - */ - if (!BusLogic_CheckHostAdapter(HostAdapter)) { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - continue; - } - /* - Initialize the Driver Options field if provided. - */ - if (DriverOptionsIndex < BusLogic_DriverOptionsCount) - HostAdapter->DriverOptions = &BusLogic_DriverOptions[DriverOptionsIndex++]; - /* - Announce the Driver Version and Date, Author's Name, Copyright Notice, - and Electronic Mail Address. - */ - BusLogic_AnnounceDriver(HostAdapter); - /* - Register the SCSI Host structure. - */ - - Host = scsi_host_alloc(&Bus_Logic_template, sizeof(struct BusLogic_HostAdapter)); - if (Host == NULL) { - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - continue; - } - HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata; - memcpy(HostAdapter, PrototypeHostAdapter, sizeof(struct BusLogic_HostAdapter)); - HostAdapter->SCSI_Host = Host; - HostAdapter->HostNumber = Host->host_no; - /* - Add Host Adapter to the end of the list of registered BusLogic - Host Adapters. - */ - list_add_tail(&HostAdapter->host_list, &BusLogic_host_list); - - /* - Read the Host Adapter Configuration, Configure the Host Adapter, - Acquire the System Resources necessary to use the Host Adapter, then - Create the Initial CCBs, Initialize the Host Adapter, and finally - perform Target Device Inquiry. - - From this point onward, any failure will be assumed to be due to a - problem with the Host Adapter, rather than due to having mistakenly - identified this port as belonging to a BusLogic Host Adapter. The - I/O Address range will not be released, thereby preventing it from - being incorrectly identified as any other type of Host Adapter. - */ - if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) && - BusLogic_ReportHostAdapterConfiguration(HostAdapter) && - BusLogic_AcquireResources(HostAdapter) && - BusLogic_CreateInitialCCBs(HostAdapter) && - BusLogic_InitializeHostAdapter(HostAdapter) && - BusLogic_TargetDeviceInquiry(HostAdapter)) { - /* - Initialization has been completed successfully. Release and - re-register usage of the I/O Address range so that the Model - Name of the Host Adapter will appear, and initialize the SCSI - Host structure. - */ - release_region(HostAdapter->IO_Address, - HostAdapter->AddressCount); - if (!request_region(HostAdapter->IO_Address, - HostAdapter->AddressCount, - HostAdapter->FullModelName)) { - printk(KERN_WARNING - "BusLogic: Release and re-register of " - "port 0x%04lx failed \n", - (unsigned long)HostAdapter->IO_Address); - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - list_del(&HostAdapter->host_list); - scsi_host_put(Host); - ret = -ENOMEM; - } else { - BusLogic_InitializeHostStructure(HostAdapter, - Host); - if (scsi_add_host(Host, HostAdapter->PCI_Device - ? &HostAdapter->PCI_Device->dev - : NULL)) { - printk(KERN_WARNING - "BusLogic: scsi_add_host()" - "failed!\n"); - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - list_del(&HostAdapter->host_list); - scsi_host_put(Host); - ret = -ENODEV; - } else { - scsi_scan_host(Host); - BusLogicHostAdapterCount++; - } - } - } else { - /* - An error occurred during Host Adapter Configuration Querying, Host - Adapter Configuration, Resource Acquisition, CCB Creation, Host - Adapter Initialization, or Target Device Inquiry, so remove Host - Adapter from the list of registered BusLogic Host Adapters, destroy - the CCBs, Release the System Resources, and Unregister the SCSI - Host. - */ - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - list_del(&HostAdapter->host_list); - scsi_host_put(Host); - ret = -ENODEV; - } - } - kfree(PrototypeHostAdapter); - kfree(BusLogic_ProbeInfoList); - BusLogic_ProbeInfoList = NULL; - return ret; -} - - -/* - BusLogic_ReleaseHostAdapter releases all resources previously acquired to - support a specific Host Adapter, including the I/O Address range, and - unregisters the BusLogic Host Adapter. -*/ - -static int __exit BusLogic_ReleaseHostAdapter(struct BusLogic_HostAdapter *HostAdapter) -{ - struct Scsi_Host *Host = HostAdapter->SCSI_Host; - - scsi_remove_host(Host); - - /* - FlashPoint Host Adapters must first be released by the FlashPoint - SCCB Manager. - */ - if (BusLogic_FlashPointHostAdapterP(HostAdapter)) - FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle); - /* - Destroy the CCBs and release any system resources acquired to - support Host Adapter. - */ - BusLogic_DestroyCCBs(HostAdapter); - BusLogic_ReleaseResources(HostAdapter); - /* - Release usage of the I/O Address range. - */ - release_region(HostAdapter->IO_Address, HostAdapter->AddressCount); - /* - Remove Host Adapter from the list of registered BusLogic Host Adapters. - */ - list_del(&HostAdapter->host_list); - - scsi_host_put(Host); - return 0; -} - - -/* - BusLogic_QueueCompletedCCB queues CCB for completion processing. -*/ - -static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *CCB) -{ - struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter; - CCB->Status = BusLogic_CCB_Completed; - CCB->Next = NULL; - if (HostAdapter->FirstCompletedCCB == NULL) { - HostAdapter->FirstCompletedCCB = CCB; - HostAdapter->LastCompletedCCB = CCB; - } else { - HostAdapter->LastCompletedCCB->Next = CCB; - HostAdapter->LastCompletedCCB = CCB; - } - HostAdapter->ActiveCommands[CCB->TargetID]--; -} - - -/* - BusLogic_ComputeResultCode computes a SCSI Subsystem Result Code from - the Host Adapter Status and Target Device Status. -*/ - -static int BusLogic_ComputeResultCode(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_HostAdapterStatus HostAdapterStatus, enum BusLogic_TargetDeviceStatus TargetDeviceStatus) -{ - int HostStatus; - switch (HostAdapterStatus) { - case BusLogic_CommandCompletedNormally: - case BusLogic_LinkedCommandCompleted: - case BusLogic_LinkedCommandCompletedWithFlag: - HostStatus = DID_OK; - break; - case BusLogic_SCSISelectionTimeout: - HostStatus = DID_TIME_OUT; - break; - case BusLogic_InvalidOutgoingMailboxActionCode: - case BusLogic_InvalidCommandOperationCode: - case BusLogic_InvalidCommandParameter: - BusLogic_Warning("BusLogic Driver Protocol Error 0x%02X\n", HostAdapter, HostAdapterStatus); - case BusLogic_DataUnderRun: - case BusLogic_DataOverRun: - case BusLogic_UnexpectedBusFree: - case BusLogic_LinkedCCBhasInvalidLUN: - case BusLogic_AutoRequestSenseFailed: - case BusLogic_TaggedQueuingMessageRejected: - case BusLogic_UnsupportedMessageReceived: - case BusLogic_HostAdapterHardwareFailed: - case BusLogic_TargetDeviceReconnectedImproperly: - case BusLogic_AbortQueueGenerated: - case BusLogic_HostAdapterSoftwareError: - case BusLogic_HostAdapterHardwareTimeoutError: - case BusLogic_SCSIParityErrorDetected: - HostStatus = DID_ERROR; - break; - case BusLogic_InvalidBusPhaseRequested: - case BusLogic_TargetFailedResponseToATN: - case BusLogic_HostAdapterAssertedRST: - case BusLogic_OtherDeviceAssertedRST: - case BusLogic_HostAdapterAssertedBusDeviceReset: - HostStatus = DID_RESET; - break; - default: - BusLogic_Warning("Unknown Host Adapter Status 0x%02X\n", HostAdapter, HostAdapterStatus); - HostStatus = DID_ERROR; - break; - } - return (HostStatus << 16) | TargetDeviceStatus; -} - - -/* - BusLogic_ScanIncomingMailboxes scans the Incoming Mailboxes saving any - Incoming Mailbox entries for completion processing. -*/ - -static void BusLogic_ScanIncomingMailboxes(struct BusLogic_HostAdapter *HostAdapter) -{ - /* - Scan through the Incoming Mailboxes in Strict Round Robin fashion, saving - any completed CCBs for further processing. It is essential that for each - CCB and SCSI Command issued, command completion processing is performed - exactly once. Therefore, only Incoming Mailboxes with completion code - Command Completed Without Error, Command Completed With Error, or Command - Aborted At Host Request are saved for completion processing. When an - Incoming Mailbox has a completion code of Aborted Command Not Found, the - CCB had already completed or been aborted before the current Abort request - was processed, and so completion processing has already occurred and no - further action should be taken. - */ - struct BusLogic_IncomingMailbox *NextIncomingMailbox = HostAdapter->NextIncomingMailbox; - enum BusLogic_CompletionCode CompletionCode; - while ((CompletionCode = NextIncomingMailbox->CompletionCode) != BusLogic_IncomingMailboxFree) { - /* - We are only allowed to do this because we limit our architectures we - run on to machines where bus_to_virt() actually works. There *needs* - to be a dma_addr_to_virt() in the new PCI DMA mapping interface to - replace bus_to_virt() or else this code is going to become very - innefficient. - */ - struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) Bus_to_Virtual(NextIncomingMailbox->CCB); - if (CompletionCode != BusLogic_AbortedCommandNotFound) { - if (CCB->Status == BusLogic_CCB_Active || CCB->Status == BusLogic_CCB_Reset) { - /* - Save the Completion Code for this CCB and queue the CCB - for completion processing. - */ - CCB->CompletionCode = CompletionCode; - BusLogic_QueueCompletedCCB(CCB); - } else { - /* - If a CCB ever appears in an Incoming Mailbox and is not marked - as status Active or Reset, then there is most likely a bug in - the Host Adapter firmware. - */ - BusLogic_Warning("Illegal CCB #%ld status %d in " "Incoming Mailbox\n", HostAdapter, CCB->SerialNumber, CCB->Status); - } - } - NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree; - if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox) - NextIncomingMailbox = HostAdapter->FirstIncomingMailbox; - } - HostAdapter->NextIncomingMailbox = NextIncomingMailbox; -} - - -/* - BusLogic_ProcessCompletedCCBs iterates over the completed CCBs for Host - Adapter setting the SCSI Command Result Codes, deallocating the CCBs, and - calling the SCSI Subsystem Completion Routines. The Host Adapter's Lock - should already have been acquired by the caller. -*/ - -static void BusLogic_ProcessCompletedCCBs(struct BusLogic_HostAdapter *HostAdapter) -{ - if (HostAdapter->ProcessCompletedCCBsActive) - return; - HostAdapter->ProcessCompletedCCBsActive = true; - while (HostAdapter->FirstCompletedCCB != NULL) { - struct BusLogic_CCB *CCB = HostAdapter->FirstCompletedCCB; - struct scsi_cmnd *Command = CCB->Command; - HostAdapter->FirstCompletedCCB = CCB->Next; - if (HostAdapter->FirstCompletedCCB == NULL) - HostAdapter->LastCompletedCCB = NULL; - /* - Process the Completed CCB. - */ - if (CCB->Opcode == BusLogic_BusDeviceReset) { - int TargetID = CCB->TargetID; - BusLogic_Warning("Bus Device Reset CCB #%ld to Target " "%d Completed\n", HostAdapter, CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted); - HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false; - HostAdapter->CommandsSinceReset[TargetID] = 0; - HostAdapter->LastResetCompleted[TargetID] = jiffies; - /* - Place CCB back on the Host Adapter's free list. - */ - BusLogic_DeallocateCCB(CCB); -#if 0 /* this needs to be redone different for new EH */ - /* - Bus Device Reset CCBs have the Command field non-NULL only when a - Bus Device Reset was requested for a Command that did not have a - currently active CCB in the Host Adapter (i.e., a Synchronous - Bus Device Reset), and hence would not have its Completion Routine - called otherwise. - */ - while (Command != NULL) { - struct scsi_cmnd *NextCommand = Command->reset_chain; - Command->reset_chain = NULL; - Command->result = DID_RESET << 16; - Command->scsi_done(Command); - Command = NextCommand; - } -#endif - /* - Iterate over the CCBs for this Host Adapter performing completion - processing for any CCBs marked as Reset for this Target. - */ - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Status == BusLogic_CCB_Reset && CCB->TargetID == TargetID) { - Command = CCB->Command; - BusLogic_DeallocateCCB(CCB); - HostAdapter->ActiveCommands[TargetID]--; - Command->result = DID_RESET << 16; - Command->scsi_done(Command); - } - HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL; - } else { - /* - Translate the Completion Code, Host Adapter Status, and Target - Device Status into a SCSI Subsystem Result Code. - */ - switch (CCB->CompletionCode) { - case BusLogic_IncomingMailboxFree: - case BusLogic_AbortedCommandNotFound: - case BusLogic_InvalidCCB: - BusLogic_Warning("CCB #%ld to Target %d Impossible State\n", HostAdapter, CCB->SerialNumber, CCB->TargetID); - break; - case BusLogic_CommandCompletedWithoutError: - HostAdapter->TargetStatistics[CCB->TargetID] - .CommandsCompleted++; - HostAdapter->TargetFlags[CCB->TargetID] - .CommandSuccessfulFlag = true; - Command->result = DID_OK << 16; - break; - case BusLogic_CommandAbortedAtHostRequest: - BusLogic_Warning("CCB #%ld to Target %d Aborted\n", HostAdapter, CCB->SerialNumber, CCB->TargetID); - BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[CCB->TargetID] - .CommandAbortsCompleted); - Command->result = DID_ABORT << 16; - break; - case BusLogic_CommandCompletedWithError: - Command->result = BusLogic_ComputeResultCode(HostAdapter, CCB->HostAdapterStatus, CCB->TargetDeviceStatus); - if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) { - HostAdapter->TargetStatistics[CCB->TargetID] - .CommandsCompleted++; - if (BusLogic_GlobalOptions.TraceErrors) { - int i; - BusLogic_Notice("CCB #%ld Target %d: Result %X Host " - "Adapter Status %02X " "Target Status %02X\n", HostAdapter, CCB->SerialNumber, CCB->TargetID, Command->result, CCB->HostAdapterStatus, CCB->TargetDeviceStatus); - BusLogic_Notice("CDB ", HostAdapter); - for (i = 0; i < CCB->CDB_Length; i++) - BusLogic_Notice(" %02X", HostAdapter, CCB->CDB[i]); - BusLogic_Notice("\n", HostAdapter); - BusLogic_Notice("Sense ", HostAdapter); - for (i = 0; i < CCB->SenseDataLength; i++) - BusLogic_Notice(" %02X", HostAdapter, Command->sense_buffer[i]); - BusLogic_Notice("\n", HostAdapter); - } - } - break; - } - /* - When an INQUIRY command completes normally, save the - CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit - Wide Data Transfers Supported) bits. - */ - if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[CCB->TargetID]; - struct SCSI_Inquiry *InquiryResult = - (struct SCSI_Inquiry *) scsi_sglist(Command); - TargetFlags->TargetExists = true; - TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue; - TargetFlags->WideTransfersSupported = InquiryResult->WBus16; - } - /* - Place CCB back on the Host Adapter's free list. - */ - BusLogic_DeallocateCCB(CCB); - /* - Call the SCSI Command Completion Routine. - */ - Command->scsi_done(Command); - } - } - HostAdapter->ProcessCompletedCCBsActive = false; -} - - -/* - BusLogic_InterruptHandler handles hardware interrupts from BusLogic Host - Adapters. -*/ - -static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier) -{ - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) DeviceIdentifier; - unsigned long ProcessorFlags; - /* - Acquire exclusive access to Host Adapter. - */ - spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, ProcessorFlags); - /* - Handle Interrupts appropriately for each Host Adapter type. - */ - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { - union BusLogic_InterruptRegister InterruptRegister; - /* - Read the Host Adapter Interrupt Register. - */ - InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter); - if (InterruptRegister.ir.InterruptValid) { - /* - Acknowledge the interrupt and reset the Host Adapter - Interrupt Register. - */ - BusLogic_InterruptReset(HostAdapter); - /* - Process valid External SCSI Bus Reset and Incoming Mailbox - Loaded Interrupts. Command Complete Interrupts are noted, - and Outgoing Mailbox Available Interrupts are ignored, as - they are never enabled. - */ - if (InterruptRegister.ir.ExternalBusReset) - HostAdapter->HostAdapterExternalReset = true; - else if (InterruptRegister.ir.IncomingMailboxLoaded) - BusLogic_ScanIncomingMailboxes(HostAdapter); - else if (InterruptRegister.ir.CommandComplete) - HostAdapter->HostAdapterCommandCompleted = true; - } - } else { - /* - Check if there is a pending interrupt for this Host Adapter. - */ - if (FlashPoint_InterruptPending(HostAdapter->CardHandle)) - switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)) { - case FlashPoint_NormalInterrupt: - break; - case FlashPoint_ExternalBusReset: - HostAdapter->HostAdapterExternalReset = true; - break; - case FlashPoint_InternalError: - BusLogic_Warning("Internal FlashPoint Error detected" " - Resetting Host Adapter\n", HostAdapter); - HostAdapter->HostAdapterInternalError = true; - break; - } - } - /* - Process any completed CCBs. - */ - if (HostAdapter->FirstCompletedCCB != NULL) - BusLogic_ProcessCompletedCCBs(HostAdapter); - /* - Reset the Host Adapter if requested. - */ - if (HostAdapter->HostAdapterExternalReset) { - BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", HostAdapter, HostAdapter->FullModelName); - BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets); - BusLogic_ResetHostAdapter(HostAdapter, false); - HostAdapter->HostAdapterExternalReset = false; - } else if (HostAdapter->HostAdapterInternalError) { - BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n", HostAdapter, HostAdapter->FullModelName); - BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors); - BusLogic_ResetHostAdapter(HostAdapter, true); - HostAdapter->HostAdapterInternalError = false; - } - /* - Release exclusive access to Host Adapter. - */ - spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, ProcessorFlags); - return IRQ_HANDLED; -} - - -/* - BusLogic_WriteOutgoingMailbox places CCB and Action Code into an Outgoing - Mailbox for execution by Host Adapter. The Host Adapter's Lock should - already have been acquired by the caller. -*/ - -static bool BusLogic_WriteOutgoingMailbox(struct BusLogic_HostAdapter - *HostAdapter, enum BusLogic_ActionCode ActionCode, struct BusLogic_CCB *CCB) -{ - struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; - NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox; - if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree) { - CCB->Status = BusLogic_CCB_Active; - /* - The CCB field must be written before the Action Code field since - the Host Adapter is operating asynchronously and the locking code - does not protect against simultaneous access by the Host Adapter. - */ - NextOutgoingMailbox->CCB = CCB->DMA_Handle; - NextOutgoingMailbox->ActionCode = ActionCode; - BusLogic_StartMailboxCommand(HostAdapter); - if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox) - NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox; - HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox; - if (ActionCode == BusLogic_MailboxStartCommand) { - HostAdapter->ActiveCommands[CCB->TargetID]++; - if (CCB->Opcode != BusLogic_BusDeviceReset) - HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++; - } - return true; - } - return false; -} - -/* Error Handling (EH) support */ - -static int BusLogic_host_reset(struct scsi_cmnd * SCpnt) -{ - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) SCpnt->device->host->hostdata; - - unsigned int id = SCpnt->device->id; - struct BusLogic_TargetStatistics *stats = &HostAdapter->TargetStatistics[id]; - int rc; - - spin_lock_irq(SCpnt->device->host->host_lock); - - BusLogic_IncrementErrorCounter(&stats->HostAdapterResetsRequested); - - rc = BusLogic_ResetHostAdapter(HostAdapter, false); - spin_unlock_irq(SCpnt->device->host->host_lock); - return rc; -} - -/* - BusLogic_QueueCommand creates a CCB for Command and places it into an - Outgoing Mailbox for execution by the associated Host Adapter. -*/ - -static int BusLogic_QueueCommand_lck(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *)) -{ - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata; - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[Command->device->id]; - struct BusLogic_TargetStatistics *TargetStatistics = HostAdapter->TargetStatistics; - unsigned char *CDB = Command->cmnd; - int CDB_Length = Command->cmd_len; - int TargetID = Command->device->id; - int LogicalUnit = Command->device->lun; - int BufferLength = scsi_bufflen(Command); - int Count; - struct BusLogic_CCB *CCB; - /* - SCSI REQUEST_SENSE commands will be executed automatically by the Host - Adapter for any errors, so they should not be executed explicitly unless - the Sense Data is zero indicating that no error occurred. - */ - if (CDB[0] == REQUEST_SENSE && Command->sense_buffer[0] != 0) { - Command->result = DID_OK << 16; - CompletionRoutine(Command); - return 0; - } - /* - Allocate a CCB from the Host Adapter's free list. In the unlikely event - that there are none available and memory allocation fails, wait 1 second - and try again. If that fails, the Host Adapter is probably hung so signal - an error as a Host Adapter Hard Reset should be initiated soon. - */ - CCB = BusLogic_AllocateCCB(HostAdapter); - if (CCB == NULL) { - spin_unlock_irq(HostAdapter->SCSI_Host->host_lock); - BusLogic_Delay(1); - spin_lock_irq(HostAdapter->SCSI_Host->host_lock); - CCB = BusLogic_AllocateCCB(HostAdapter); - if (CCB == NULL) { - Command->result = DID_ERROR << 16; - CompletionRoutine(Command); - return 0; - } - } - - /* - Initialize the fields in the BusLogic Command Control Block (CCB). - */ - Count = scsi_dma_map(Command); - BUG_ON(Count < 0); - if (Count) { - struct scatterlist *sg; - int i; - - CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; - CCB->DataLength = Count * sizeof(struct BusLogic_ScatterGatherSegment); - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) - CCB->DataPointer = (unsigned int) CCB->DMA_Handle + ((unsigned long) &CCB->ScatterGatherList - (unsigned long) CCB); - else - CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList); - - scsi_for_each_sg(Command, sg, Count, i) { - CCB->ScatterGatherList[i].SegmentByteCount = - sg_dma_len(sg); - CCB->ScatterGatherList[i].SegmentDataPointer = - sg_dma_address(sg); - } - } else if (!Count) { - CCB->Opcode = BusLogic_InitiatorCCB; - CCB->DataLength = BufferLength; - CCB->DataPointer = 0; - } - - switch (CDB[0]) { - case READ_6: - case READ_10: - CCB->DataDirection = BusLogic_DataInLengthChecked; - TargetStatistics[TargetID].ReadCommands++; - BusLogic_IncrementByteCounter(&TargetStatistics[TargetID].TotalBytesRead, BufferLength); - BusLogic_IncrementSizeBucket(TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength); - break; - case WRITE_6: - case WRITE_10: - CCB->DataDirection = BusLogic_DataOutLengthChecked; - TargetStatistics[TargetID].WriteCommands++; - BusLogic_IncrementByteCounter(&TargetStatistics[TargetID].TotalBytesWritten, BufferLength); - BusLogic_IncrementSizeBucket(TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength); - break; - default: - CCB->DataDirection = BusLogic_UncheckedDataTransfer; - break; - } - CCB->CDB_Length = CDB_Length; - CCB->HostAdapterStatus = 0; - CCB->TargetDeviceStatus = 0; - CCB->TargetID = TargetID; - CCB->LogicalUnit = LogicalUnit; - CCB->TagEnable = false; - CCB->LegacyTagEnable = false; - /* - BusLogic recommends that after a Reset the first couple of commands that - are sent to a Target Device be sent in a non Tagged Queue fashion so that - the Host Adapter and Target Device can establish Synchronous and Wide - Transfer before Queue Tag messages can interfere with the Synchronous and - Wide Negotiation messages. By waiting to enable Tagged Queuing until after - the first BusLogic_MaxTaggedQueueDepth commands have been queued, it is - assured that after a Reset any pending commands are requeued before Tagged - Queuing is enabled and that the Tagged Queuing message will not occur while - the partition table is being printed. In addition, some devices do not - properly handle the transition from non-tagged to tagged commands, so it is - necessary to wait until there are no pending commands for a target device - before queuing tagged commands. - */ - if (HostAdapter->CommandsSinceReset[TargetID]++ >= - BusLogic_MaxTaggedQueueDepth && !TargetFlags->TaggedQueuingActive && HostAdapter->ActiveCommands[TargetID] == 0 && TargetFlags->TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) { - TargetFlags->TaggedQueuingActive = true; - BusLogic_Notice("Tagged Queuing now active for Target %d\n", HostAdapter, TargetID); - } - if (TargetFlags->TaggedQueuingActive) { - enum BusLogic_QueueTag QueueTag = BusLogic_SimpleQueueTag; - /* - When using Tagged Queuing with Simple Queue Tags, it appears that disk - drive controllers do not guarantee that a queued command will not - remain in a disconnected state indefinitely if commands that read or - write nearer the head position continue to arrive without interruption. - Therefore, for each Target Device this driver keeps track of the last - time either the queue was empty or an Ordered Queue Tag was issued. If - more than 4 seconds (one fifth of the 20 second disk timeout) have - elapsed since this last sequence point, this command will be issued - with an Ordered Queue Tag rather than a Simple Queue Tag, which forces - the Target Device to complete all previously queued commands before - this command may be executed. - */ - if (HostAdapter->ActiveCommands[TargetID] == 0) - HostAdapter->LastSequencePoint[TargetID] = jiffies; - else if (time_after(jiffies, HostAdapter->LastSequencePoint[TargetID] + 4 * HZ)) { - HostAdapter->LastSequencePoint[TargetID] = jiffies; - QueueTag = BusLogic_OrderedQueueTag; - } - if (HostAdapter->ExtendedLUNSupport) { - CCB->TagEnable = true; - CCB->QueueTag = QueueTag; - } else { - CCB->LegacyTagEnable = true; - CCB->LegacyQueueTag = QueueTag; - } - } - memcpy(CCB->CDB, CDB, CDB_Length); - CCB->SenseDataLength = SCSI_SENSE_BUFFERSIZE; - CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE); - CCB->Command = Command; - Command->scsi_done = CompletionRoutine; - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { - /* - Place the CCB in an Outgoing Mailbox. The higher levels of the SCSI - Subsystem should not attempt to queue more commands than can be placed - in Outgoing Mailboxes, so there should always be one free. In the - unlikely event that there are none available, wait 1 second and try - again. If that fails, the Host Adapter is probably hung so signal an - error as a Host Adapter Hard Reset should be initiated soon. - */ - if (!BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxStartCommand, CCB)) { - spin_unlock_irq(HostAdapter->SCSI_Host->host_lock); - BusLogic_Warning("Unable to write Outgoing Mailbox - " "Pausing for 1 second\n", HostAdapter); - BusLogic_Delay(1); - spin_lock_irq(HostAdapter->SCSI_Host->host_lock); - if (!BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxStartCommand, CCB)) { - BusLogic_Warning("Still unable to write Outgoing Mailbox - " "Host Adapter Dead?\n", HostAdapter); - BusLogic_DeallocateCCB(CCB); - Command->result = DID_ERROR << 16; - Command->scsi_done(Command); - } - } - } else { - /* - Call the FlashPoint SCCB Manager to start execution of the CCB. - */ - CCB->Status = BusLogic_CCB_Active; - HostAdapter->ActiveCommands[TargetID]++; - TargetStatistics[TargetID].CommandsAttempted++; - FlashPoint_StartCCB(HostAdapter->CardHandle, CCB); - /* - The Command may have already completed and BusLogic_QueueCompletedCCB - been called, or it may still be pending. - */ - if (CCB->Status == BusLogic_CCB_Completed) - BusLogic_ProcessCompletedCCBs(HostAdapter); - } - return 0; -} - -static DEF_SCSI_QCMD(BusLogic_QueueCommand) - -#if 0 -/* - BusLogic_AbortCommand aborts Command if possible. -*/ - -static int BusLogic_AbortCommand(struct scsi_cmnd *Command) -{ - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata; - - int TargetID = Command->device->id; - struct BusLogic_CCB *CCB; - BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested); - /* - Attempt to find an Active CCB for this Command. If no Active CCB for this - Command is found, then no Abort is necessary. - */ - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Command == Command) - break; - if (CCB == NULL) { - BusLogic_Warning("Unable to Abort Command to Target %d - " "No CCB Found\n", HostAdapter, TargetID); - return SUCCESS; - } else if (CCB->Status == BusLogic_CCB_Completed) { - BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Completed\n", HostAdapter, TargetID); - return SUCCESS; - } else if (CCB->Status == BusLogic_CCB_Reset) { - BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Reset\n", HostAdapter, TargetID); - return SUCCESS; - } - if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) { - /* - Attempt to Abort this CCB. MultiMaster Firmware versions prior to 5.xx - do not generate Abort Tag messages, but only generate the non-tagged - Abort message. Since non-tagged commands are not sent by the Host - Adapter until the queue of outstanding tagged commands has completed, - and the Abort message is treated as a non-tagged command, it is - effectively impossible to abort commands when Tagged Queuing is active. - Firmware version 5.xx does generate Abort Tag messages, so it is - possible to abort commands when Tagged Queuing is active. - */ - if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && HostAdapter->FirmwareVersion[0] < '5') { - BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " "Abort Tag Not Supported\n", HostAdapter, CCB->SerialNumber, TargetID); - return FAILURE; - } else if (BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxAbortCommand, CCB)) { - BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); - return SUCCESS; - } else { - BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " "No Outgoing Mailboxes\n", HostAdapter, CCB->SerialNumber, TargetID); - return FAILURE; - } - } else { - /* - Call the FlashPoint SCCB Manager to abort execution of the CCB. - */ - BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID); - BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted); - FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB); - /* - The Abort may have already been completed and - BusLogic_QueueCompletedCCB been called, or it - may still be pending. - */ - if (CCB->Status == BusLogic_CCB_Completed) { - BusLogic_ProcessCompletedCCBs(HostAdapter); - } - return SUCCESS; - } - return SUCCESS; -} - -#endif -/* - BusLogic_ResetHostAdapter resets Host Adapter if possible, marking all - currently executing SCSI Commands as having been Reset. -*/ - -static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, bool HardReset) -{ - struct BusLogic_CCB *CCB; - int TargetID; - - /* - * Attempt to Reset and Reinitialize the Host Adapter. - */ - - if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) && BusLogic_InitializeHostAdapter(HostAdapter))) { - BusLogic_Error("Resetting %s Failed\n", HostAdapter, HostAdapter->FullModelName); - return FAILURE; - } - - /* - * Deallocate all currently executing CCBs. - */ - - for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll) - if (CCB->Status == BusLogic_CCB_Active) - BusLogic_DeallocateCCB(CCB); - /* - * Wait a few seconds between the Host Adapter Hard Reset which - * initiates a SCSI Bus Reset and issuing any SCSI Commands. Some - * SCSI devices get confused if they receive SCSI Commands too soon - * after a SCSI Bus Reset. - */ - - if (HardReset) { - spin_unlock_irq(HostAdapter->SCSI_Host->host_lock); - BusLogic_Delay(HostAdapter->BusSettleTime); - spin_lock_irq(HostAdapter->SCSI_Host->host_lock); - } - - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { - HostAdapter->LastResetAttempted[TargetID] = jiffies; - HostAdapter->LastResetCompleted[TargetID] = jiffies; - } - return SUCCESS; -} - -/* - BusLogic_BIOSDiskParameters returns the Heads/Sectors/Cylinders BIOS Disk - Parameters for Disk. The default disk geometry is 64 heads, 32 sectors, and - the appropriate number of cylinders so as not to exceed drive capacity. In - order for disks equal to or larger than 1 GB to be addressable by the BIOS - without exceeding the BIOS limitation of 1024 cylinders, Extended Translation - may be enabled in AutoSCSI on FlashPoint Host Adapters and on "W" and "C" - series MultiMaster Host Adapters, or by a dip switch setting on "S" and "A" - series MultiMaster Host Adapters. With Extended Translation enabled, drives - between 1 GB inclusive and 2 GB exclusive are given a disk geometry of 128 - heads and 32 sectors, and drives above 2 GB inclusive are given a disk - geometry of 255 heads and 63 sectors. However, if the BIOS detects that the - Extended Translation setting does not match the geometry in the partition - table, then the translation inferred from the partition table will be used by - the BIOS, and a warning may be displayed. -*/ - -static int BusLogic_BIOSDiskParameters(struct scsi_device *sdev, struct block_device *Device, sector_t capacity, int *Parameters) -{ - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) sdev->host->hostdata; - struct BIOS_DiskParameters *DiskParameters = (struct BIOS_DiskParameters *) Parameters; - unsigned char *buf; - if (HostAdapter->ExtendedTranslationEnabled && capacity >= 2 * 1024 * 1024 /* 1 GB in 512 byte sectors */ ) { - if (capacity >= 4 * 1024 * 1024 /* 2 GB in 512 byte sectors */ ) { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - } else { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - } - } else { - DiskParameters->Heads = 64; - DiskParameters->Sectors = 32; - } - DiskParameters->Cylinders = (unsigned long) capacity / (DiskParameters->Heads * DiskParameters->Sectors); - buf = scsi_bios_ptable(Device); - if (buf == NULL) - return 0; - /* - If the boot sector partition table flag is valid, search for a partition - table entry whose end_head matches one of the standard BusLogic geometry - translations (64/32, 128/32, or 255/63). - */ - if (*(unsigned short *) (buf + 64) == 0xAA55) { - struct partition *FirstPartitionEntry = (struct partition *) buf; - struct partition *PartitionEntry = FirstPartitionEntry; - int SavedCylinders = DiskParameters->Cylinders, PartitionNumber; - unsigned char PartitionEntryEndHead = 0, PartitionEntryEndSector = 0; - for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++) { - PartitionEntryEndHead = PartitionEntry->end_head; - PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F; - if (PartitionEntryEndHead == 64 - 1) { - DiskParameters->Heads = 64; - DiskParameters->Sectors = 32; - break; - } else if (PartitionEntryEndHead == 128 - 1) { - DiskParameters->Heads = 128; - DiskParameters->Sectors = 32; - break; - } else if (PartitionEntryEndHead == 255 - 1) { - DiskParameters->Heads = 255; - DiskParameters->Sectors = 63; - break; - } - PartitionEntry++; - } - if (PartitionNumber == 4) { - PartitionEntryEndHead = FirstPartitionEntry->end_head; - PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F; - } - DiskParameters->Cylinders = (unsigned long) capacity / (DiskParameters->Heads * DiskParameters->Sectors); - if (PartitionNumber < 4 && PartitionEntryEndSector == DiskParameters->Sectors) { - if (DiskParameters->Cylinders != SavedCylinders) - BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors); - } else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0) { - BusLogic_Warning("Warning: Partition Table appears to " "have Geometry %d/%d which is\n", HostAdapter, PartitionEntryEndHead + 1, PartitionEntryEndSector); - BusLogic_Warning("not compatible with current BusLogic " "Host Adapter Geometry %d/%d\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors); - } - } - kfree(buf); - return 0; -} - - -/* - BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/. -*/ - -static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, char **StartPointer, off_t Offset, int BytesAvailable, int WriteFlag) -{ - struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) shost->hostdata; - struct BusLogic_TargetStatistics *TargetStatistics; - int TargetID, Length; - char *Buffer; - - TargetStatistics = HostAdapter->TargetStatistics; - if (WriteFlag) { - HostAdapter->ExternalHostAdapterResets = 0; - HostAdapter->HostAdapterInternalErrors = 0; - memset(TargetStatistics, 0, BusLogic_MaxTargetDevices * sizeof(struct BusLogic_TargetStatistics)); - return 0; - } - Buffer = HostAdapter->MessageBuffer; - Length = HostAdapter->MessageBufferLength; - Length += sprintf(&Buffer[Length], "\n\ -Current Driver Queue Depth: %d\n\ -Currently Allocated CCBs: %d\n", HostAdapter->DriverQueueDepth, HostAdapter->AllocatedCCBs); - Length += sprintf(&Buffer[Length], "\n\n\ - DATA TRANSFER STATISTICS\n\ -\n\ -Target Tagged Queuing Queue Depth Active Attempted Completed\n\ -====== ============== =========== ====== ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) - continue; - Length += sprintf(&Buffer[Length], " %2d %s", TargetID, (TargetFlags->TaggedQueuingSupported ? (TargetFlags->TaggedQueuingActive ? " Active" : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID) - ? " Permitted" : " Disabled")) - : "Not Supported")); - Length += sprintf(&Buffer[Length], - " %3d %3u %9u %9u\n", HostAdapter->QueueDepth[TargetID], HostAdapter->ActiveCommands[TargetID], TargetStatistics[TargetID].CommandsAttempted, TargetStatistics[TargetID].CommandsCompleted); - } - Length += sprintf(&Buffer[Length], "\n\ -Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\ -====== ============= ============== =================== ===================\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) - continue; - Length += sprintf(&Buffer[Length], " %2d %9u %9u", TargetID, TargetStatistics[TargetID].ReadCommands, TargetStatistics[TargetID].WriteCommands); - if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0) - Length += sprintf(&Buffer[Length], " %9u%09u", TargetStatistics[TargetID].TotalBytesRead.Billions, TargetStatistics[TargetID].TotalBytesRead.Units); - else - Length += sprintf(&Buffer[Length], " %9u", TargetStatistics[TargetID].TotalBytesRead.Units); - if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0) - Length += sprintf(&Buffer[Length], " %9u%09u\n", TargetStatistics[TargetID].TotalBytesWritten.Billions, TargetStatistics[TargetID].TotalBytesWritten.Units); - else - Length += sprintf(&Buffer[Length], " %9u\n", TargetStatistics[TargetID].TotalBytesWritten.Units); - } - Length += sprintf(&Buffer[Length], "\n\ -Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\ -====== ======= ========= ========= ========= ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) - continue; - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].ReadCommandSizeBuckets[0], - TargetStatistics[TargetID].ReadCommandSizeBuckets[1], TargetStatistics[TargetID].ReadCommandSizeBuckets[2], TargetStatistics[TargetID].ReadCommandSizeBuckets[3], TargetStatistics[TargetID].ReadCommandSizeBuckets[4]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].WriteCommandSizeBuckets[0], - TargetStatistics[TargetID].WriteCommandSizeBuckets[1], TargetStatistics[TargetID].WriteCommandSizeBuckets[2], TargetStatistics[TargetID].WriteCommandSizeBuckets[3], TargetStatistics[TargetID].WriteCommandSizeBuckets[4]); - } - Length += sprintf(&Buffer[Length], "\n\ -Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\ -====== ======= ========= ========= ========= ========= =========\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) - continue; - Length += - sprintf(&Buffer[Length], - " %2d Read %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].ReadCommandSizeBuckets[5], - TargetStatistics[TargetID].ReadCommandSizeBuckets[6], TargetStatistics[TargetID].ReadCommandSizeBuckets[7], TargetStatistics[TargetID].ReadCommandSizeBuckets[8], TargetStatistics[TargetID].ReadCommandSizeBuckets[9]); - Length += - sprintf(&Buffer[Length], - " %2d Write %9u %9u %9u %9u %9u\n", TargetID, - TargetStatistics[TargetID].WriteCommandSizeBuckets[5], - TargetStatistics[TargetID].WriteCommandSizeBuckets[6], TargetStatistics[TargetID].WriteCommandSizeBuckets[7], TargetStatistics[TargetID].WriteCommandSizeBuckets[8], TargetStatistics[TargetID].WriteCommandSizeBuckets[9]); - } - Length += sprintf(&Buffer[Length], "\n\n\ - ERROR RECOVERY STATISTICS\n\ -\n\ - Command Aborts Bus Device Resets Host Adapter Resets\n\ -Target Requested Completed Requested Completed Requested Completed\n\ - ID \\\\\\\\ Attempted //// \\\\\\\\ Attempted //// \\\\\\\\ Attempted ////\n\ -====== ===== ===== ===== ===== ===== ===== ===== ===== =====\n"); - for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) { - struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID]; - if (!TargetFlags->TargetExists) - continue; - Length += sprintf(&Buffer[Length], "\ - %2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID, TargetStatistics[TargetID].CommandAbortsRequested, TargetStatistics[TargetID].CommandAbortsAttempted, TargetStatistics[TargetID].CommandAbortsCompleted, TargetStatistics[TargetID].BusDeviceResetsRequested, TargetStatistics[TargetID].BusDeviceResetsAttempted, TargetStatistics[TargetID].BusDeviceResetsCompleted, TargetStatistics[TargetID].HostAdapterResetsRequested, TargetStatistics[TargetID].HostAdapterResetsAttempted, TargetStatistics[TargetID].HostAdapterResetsCompleted); - } - Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", HostAdapter->ExternalHostAdapterResets); - Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", HostAdapter->HostAdapterInternalErrors); - if (Length >= BusLogic_MessageBufferSize) - BusLogic_Error("Message Buffer length %d exceeds size %d\n", HostAdapter, Length, BusLogic_MessageBufferSize); - if ((Length -= Offset) <= 0) - return 0; - if (Length >= BytesAvailable) - Length = BytesAvailable; - memcpy(ProcBuffer, HostAdapter->MessageBuffer + Offset, Length); - *StartPointer = ProcBuffer; - return Length; -} - - -/* - BusLogic_Message prints Driver Messages. -*/ - -static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, char *Format, struct BusLogic_HostAdapter *HostAdapter, ...) -{ - static char Buffer[BusLogic_LineBufferSize]; - static bool BeginningOfLine = true; - va_list Arguments; - int Length = 0; - va_start(Arguments, HostAdapter); - Length = vsprintf(Buffer, Format, Arguments); - va_end(Arguments); - if (MessageLevel == BusLogic_AnnounceLevel) { - static int AnnouncementLines = 0; - strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], Buffer); - HostAdapter->MessageBufferLength += Length; - if (++AnnouncementLines <= 2) - printk("%sscsi: %s", BusLogic_MessageLevelMap[MessageLevel], Buffer); - } else if (MessageLevel == BusLogic_InfoLevel) { - strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], Buffer); - HostAdapter->MessageBufferLength += Length; - if (BeginningOfLine) { - if (Buffer[0] != '\n' || Length > 1) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], HostAdapter->HostNumber, Buffer); - } else - printk("%s", Buffer); - } else { - if (BeginningOfLine) { - if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized) - printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], HostAdapter->HostNumber, Buffer); - else - printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer); - } else - printk("%s", Buffer); - } - BeginningOfLine = (Buffer[Length - 1] == '\n'); -} - - -/* - BusLogic_ParseKeyword parses an individual option keyword. It returns true - and updates the pointer if the keyword is recognized and false otherwise. -*/ - -static bool __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword) -{ - char *Pointer = *StringPointer; - while (*Keyword != '\0') { - char StringChar = *Pointer++; - char KeywordChar = *Keyword++; - if (StringChar >= 'A' && StringChar <= 'Z') - StringChar += 'a' - 'Z'; - if (KeywordChar >= 'A' && KeywordChar <= 'Z') - KeywordChar += 'a' - 'Z'; - if (StringChar != KeywordChar) - return false; - } - *StringPointer = Pointer; - return true; -} - - -/* - BusLogic_ParseDriverOptions handles processing of BusLogic Driver Options - specifications. - - BusLogic Driver Options may be specified either via the Linux Kernel Command - Line or via the Loadable Kernel Module Installation Facility. Driver Options - for multiple host adapters may be specified either by separating the option - strings by a semicolon, or by specifying multiple "BusLogic=" strings on the - command line. Individual option specifications for a single host adapter are - separated by commas. The Probing and Debugging Options apply to all host - adapters whereas the remaining options apply individually only to the - selected host adapter. - - The BusLogic Driver Probing Options are described in - . -*/ - -static int __init BusLogic_ParseDriverOptions(char *OptionsString) -{ - while (true) { - struct BusLogic_DriverOptions *DriverOptions = &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++]; - int TargetID; - memset(DriverOptions, 0, sizeof(struct BusLogic_DriverOptions)); - while (*OptionsString != '\0' && *OptionsString != ';') { - /* Probing Options. */ - if (BusLogic_ParseKeyword(&OptionsString, "IO:")) { - unsigned long IO_Address = simple_strtoul(OptionsString, &OptionsString, 0); - BusLogic_ProbeOptions.LimitedProbeISA = true; - switch (IO_Address) { - case 0x330: - BusLogic_ProbeOptions.Probe330 = true; - break; - case 0x334: - BusLogic_ProbeOptions.Probe334 = true; - break; - case 0x230: - BusLogic_ProbeOptions.Probe230 = true; - break; - case 0x234: - BusLogic_ProbeOptions.Probe234 = true; - break; - case 0x130: - BusLogic_ProbeOptions.Probe130 = true; - break; - case 0x134: - BusLogic_ProbeOptions.Probe134 = true; - break; - default: - BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid I/O Address 0x%X)\n", NULL, IO_Address); - return 0; - } - } else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA")) - BusLogic_ProbeOptions.NoProbeISA = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI")) - BusLogic_ProbeOptions.NoProbePCI = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe")) - BusLogic_ProbeOptions.NoProbe = true; - else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI")) - BusLogic_ProbeOptions.NoSortPCI = true; - else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst")) - BusLogic_ProbeOptions.MultiMasterFirst = true; - else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst")) - BusLogic_ProbeOptions.FlashPointFirst = true; - /* Tagged Queuing Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") || BusLogic_ParseKeyword(&OptionsString, "QD:[")) { - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) { - unsigned short QueueDepth = simple_strtoul(OptionsString, &OptionsString, 0); - if (QueueDepth > BusLogic_MaxTaggedQueueDepth) { - BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, QueueDepth); - return 0; - } - DriverOptions->QueueDepth[TargetID] = QueueDepth; - if (*OptionsString == ',') - OptionsString++; - else if (*OptionsString == ']') - break; - else { - BusLogic_Error("BusLogic: Invalid Driver Options " "(',' or ']' expected at '%s')\n", NULL, OptionsString); - return 0; - } - } - if (*OptionsString != ']') { - BusLogic_Error("BusLogic: Invalid Driver Options " "(']' expected at '%s')\n", NULL, OptionsString); - return 0; - } else - OptionsString++; - } else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") || BusLogic_ParseKeyword(&OptionsString, "QD:")) { - unsigned short QueueDepth = simple_strtoul(OptionsString, &OptionsString, 0); - if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth) { - BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, QueueDepth); - return 0; - } - DriverOptions->CommonQueueDepth = QueueDepth; - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - DriverOptions->QueueDepth[TargetID] = QueueDepth; - } else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") || BusLogic_ParseKeyword(&OptionsString, "TQ:")) { - if (BusLogic_ParseKeyword(&OptionsString, "Default")) { - DriverOptions->TaggedQueuingPermitted = 0x0000; - DriverOptions->TaggedQueuingPermittedMask = 0x0000; - } else if (BusLogic_ParseKeyword(&OptionsString, "Enable")) { - DriverOptions->TaggedQueuingPermitted = 0xFFFF; - DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; - } else if (BusLogic_ParseKeyword(&OptionsString, "Disable")) { - DriverOptions->TaggedQueuingPermitted = 0x0000; - DriverOptions->TaggedQueuingPermittedMask = 0xFFFF; - } else { - unsigned short TargetBit; - for (TargetID = 0, TargetBit = 1; TargetID < BusLogic_MaxTargetDevices; TargetID++, TargetBit <<= 1) - switch (*OptionsString++) { - case 'Y': - DriverOptions->TaggedQueuingPermitted |= TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - break; - case 'N': - DriverOptions->TaggedQueuingPermitted &= ~TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - break; - case 'X': - break; - default: - OptionsString--; - TargetID = BusLogic_MaxTargetDevices; - break; - } - } - } - /* Miscellaneous Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") || BusLogic_ParseKeyword(&OptionsString, "BST:")) { - unsigned short BusSettleTime = simple_strtoul(OptionsString, &OptionsString, 0); - if (BusSettleTime > 5 * 60) { - BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Bus Settle Time %d)\n", NULL, BusSettleTime); - return 0; - } - DriverOptions->BusSettleTime = BusSettleTime; - } else if (BusLogic_ParseKeyword(&OptionsString, "InhibitTargetInquiry")) - DriverOptions->LocalOptions.InhibitTargetInquiry = true; - /* Debugging Options. */ - else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe")) - BusLogic_GlobalOptions.TraceProbe = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset")) - BusLogic_GlobalOptions.TraceHardwareReset = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration")) - BusLogic_GlobalOptions.TraceConfiguration = true; - else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors")) - BusLogic_GlobalOptions.TraceErrors = true; - else if (BusLogic_ParseKeyword(&OptionsString, "Debug")) { - BusLogic_GlobalOptions.TraceProbe = true; - BusLogic_GlobalOptions.TraceHardwareReset = true; - BusLogic_GlobalOptions.TraceConfiguration = true; - BusLogic_GlobalOptions.TraceErrors = true; - } - if (*OptionsString == ',') - OptionsString++; - else if (*OptionsString != ';' && *OptionsString != '\0') { - BusLogic_Error("BusLogic: Unexpected Driver Option '%s' " "ignored\n", NULL, OptionsString); - *OptionsString = '\0'; - } - } - if (!(BusLogic_DriverOptionsCount == 0 || BusLogic_ProbeInfoCount == 0 || BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount)) { - BusLogic_Error("BusLogic: Invalid Driver Options " "(all or no I/O Addresses must be specified)\n", NULL); - return 0; - } - /* - Tagged Queuing is disabled when the Queue Depth is 1 since queuing - multiple commands is not possible. - */ - for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) - if (DriverOptions->QueueDepth[TargetID] == 1) { - unsigned short TargetBit = 1 << TargetID; - DriverOptions->TaggedQueuingPermitted &= ~TargetBit; - DriverOptions->TaggedQueuingPermittedMask |= TargetBit; - } - if (*OptionsString == ';') - OptionsString++; - if (*OptionsString == '\0') - return 0; - } - return 1; -} - -/* - Get it all started -*/ - -static struct scsi_host_template Bus_Logic_template = { - .module = THIS_MODULE, - .proc_name = "BusLogic", - .proc_info = BusLogic_ProcDirectoryInfo, - .name = "BusLogic", - .info = BusLogic_DriverInfo, - .queuecommand = BusLogic_QueueCommand, - .slave_configure = BusLogic_SlaveConfigure, - .bios_param = BusLogic_BIOSDiskParameters, - .eh_host_reset_handler = BusLogic_host_reset, -#if 0 - .eh_abort_handler = BusLogic_AbortCommand, -#endif - .unchecked_isa_dma = 1, - .max_sectors = 128, - .use_clustering = ENABLE_CLUSTERING, -}; - -/* - BusLogic_Setup handles processing of Kernel Command Line Arguments. -*/ - -static int __init BusLogic_Setup(char *str) -{ - int ints[3]; - - (void) get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] != 0) { - BusLogic_Error("BusLogic: Obsolete Command Line Entry " "Format Ignored\n", NULL); - return 0; - } - if (str == NULL || *str == '\0') - return 0; - return BusLogic_ParseDriverOptions(str); -} - -/* - * Exit function. Deletes all hosts associated with this driver. - */ - -static void __exit BusLogic_exit(void) -{ - struct BusLogic_HostAdapter *ha, *next; - - list_for_each_entry_safe(ha, next, &BusLogic_host_list, host_list) - BusLogic_ReleaseHostAdapter(ha); -} - -__setup("BusLogic=", BusLogic_Setup); - -#ifdef MODULE -static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { } -}; -#endif -MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl); - -module_init(BusLogic_init); -module_exit(BusLogic_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/BusLogic.h b/ANDROID_3.4.5/drivers/scsi/BusLogic.h deleted file mode 100644 index 649fcb31..00000000 --- a/ANDROID_3.4.5/drivers/scsi/BusLogic.h +++ /dev/null @@ -1,1332 +0,0 @@ -/* - - Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters - - Copyright 1995-1998 by Leonard N. Zubkoff - - This program is free software; you may redistribute and/or modify it under - the terms of the GNU General Public License Version 2 as published by the - Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - for complete details. - - The author respectfully requests that any modifications to this software be - sent directly to him for evaluation and testing. - - Special thanks to Wayne Yen, Jin-Lon Hon, and Alex Win of BusLogic, whose - advice has been invaluable, to David Gentzel, for writing the original Linux - BusLogic driver, and to Paul Gortmaker, for being such a dedicated test site. - - Finally, special thanks to Mylex/BusLogic for making the FlashPoint SCCB - Manager available as freely redistributable source code. - -*/ - -#ifndef _BUSLOGIC_H -#define _BUSLOGIC_H - - -#ifndef PACKED -#define PACKED __attribute__((packed)) -#endif - -/* - Define the maximum number of BusLogic Host Adapters supported by this driver. -*/ - -#define BusLogic_MaxHostAdapters 16 - - -/* - Define the maximum number of Target Devices supported by this driver. -*/ - -#define BusLogic_MaxTargetDevices 16 - - -/* - Define the maximum number of Scatter/Gather Segments used by this driver. - For optimal performance, it is important that this limit be at least as - large as the largest single request generated by the I/O Subsystem. -*/ - -#define BusLogic_ScatterGatherLimit 128 - - -/* - Define the maximum, maximum automatic, minimum automatic, and default Queue - Depth to allow for Target Devices depending on whether or not they support - Tagged Queuing and whether or not ISA Bounce Buffers are required. -*/ - -#define BusLogic_MaxTaggedQueueDepth 64 -#define BusLogic_MaxAutomaticTaggedQueueDepth 28 -#define BusLogic_MinAutomaticTaggedQueueDepth 7 -#define BusLogic_TaggedQueueDepthBB 3 -#define BusLogic_UntaggedQueueDepth 3 -#define BusLogic_UntaggedQueueDepthBB 2 - - -/* - Define the default amount of time in seconds to wait between a Host Adapter - Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI commands. - Some SCSI devices get confused if they receive SCSI commands too soon after - a SCSI Bus Reset. -*/ - -#define BusLogic_DefaultBusSettleTime 2 - - -/* - Define the maximum number of Mailboxes that should be used for MultiMaster - Host Adapters. This number is chosen to be larger than the maximum Host - Adapter Queue Depth and small enough so that the Host Adapter structure - does not cross an allocation block size boundary. -*/ - -#define BusLogic_MaxMailboxes 211 - - -/* - Define the number of CCBs that should be allocated as a group to optimize - Kernel memory allocation. -*/ - -#define BusLogic_CCB_AllocationGroupSize 7 - - -/* - Define the Host Adapter Line and Message Buffer Sizes. -*/ - -#define BusLogic_LineBufferSize 100 -#define BusLogic_MessageBufferSize 9700 - - -/* - Define the Driver Message Levels. -*/ - -enum BusLogic_MessageLevel { - BusLogic_AnnounceLevel = 0, - BusLogic_InfoLevel = 1, - BusLogic_NoticeLevel = 2, - BusLogic_WarningLevel = 3, - BusLogic_ErrorLevel = 4 -}; - -static char *BusLogic_MessageLevelMap[] = { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR }; - - -/* - Define Driver Message macros. -*/ - -#define BusLogic_Announce(Format, Arguments...) \ - BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments) - -#define BusLogic_Info(Format, Arguments...) \ - BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments) - -#define BusLogic_Notice(Format, Arguments...) \ - BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments) - -#define BusLogic_Warning(Format, Arguments...) \ - BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments) - -#define BusLogic_Error(Format, Arguments...) \ - BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments) - - -/* - Define the types of BusLogic Host Adapters that are supported and the number - of I/O Addresses required by each type. -*/ - -enum BusLogic_HostAdapterType { - BusLogic_MultiMaster = 1, - BusLogic_FlashPoint = 2 -} PACKED; - -#define BusLogic_MultiMasterAddressCount 4 -#define BusLogic_FlashPointAddressCount 256 - -static int BusLogic_HostAdapterAddressCount[3] = { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount }; - - -/* - Define macros for testing the Host Adapter Type. -*/ - -#ifdef CONFIG_SCSI_FLASHPOINT - -#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ - (HostAdapter->HostAdapterType == BusLogic_MultiMaster) - -#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ - (HostAdapter->HostAdapterType == BusLogic_FlashPoint) - -#else - -#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \ - (true) - -#define BusLogic_FlashPointHostAdapterP(HostAdapter) \ - (false) - -#endif - - -/* - Define the possible Host Adapter Bus Types. -*/ - -enum BusLogic_HostAdapterBusType { - BusLogic_Unknown_Bus = 0, - BusLogic_ISA_Bus = 1, - BusLogic_EISA_Bus = 2, - BusLogic_PCI_Bus = 3, - BusLogic_VESA_Bus = 4, - BusLogic_MCA_Bus = 5 -} PACKED; - -static char *BusLogic_HostAdapterBusNames[] = { "Unknown", "ISA", "EISA", "PCI", "VESA", "MCA" }; - -static enum BusLogic_HostAdapterBusType BusLogic_HostAdapterBusTypes[] = { - BusLogic_VESA_Bus, /* BT-4xx */ - BusLogic_ISA_Bus, /* BT-5xx */ - BusLogic_MCA_Bus, /* BT-6xx */ - BusLogic_EISA_Bus, /* BT-7xx */ - BusLogic_Unknown_Bus, /* BT-8xx */ - BusLogic_PCI_Bus /* BT-9xx */ -}; - -/* - Define the possible Host Adapter BIOS Disk Geometry Translations. -*/ - -enum BusLogic_BIOS_DiskGeometryTranslation { - BusLogic_BIOS_Disk_Not_Installed = 0, - BusLogic_BIOS_Disk_Installed_64x32 = 1, - BusLogic_BIOS_Disk_Installed_128x32 = 2, - BusLogic_BIOS_Disk_Installed_255x63 = 3 -} PACKED; - - -/* - Define a 10^18 Statistics Byte Counter data type. -*/ - -struct BusLogic_ByteCounter { - unsigned int Units; - unsigned int Billions; -}; - - -/* - Define the structure for I/O Address and Bus Probing Information. -*/ - -struct BusLogic_ProbeInfo { - enum BusLogic_HostAdapterType HostAdapterType; - enum BusLogic_HostAdapterBusType HostAdapterBusType; - unsigned long IO_Address; - unsigned long PCI_Address; - struct pci_dev *PCI_Device; - unsigned char Bus; - unsigned char Device; - unsigned char IRQ_Channel; -}; - -/* - Define the Probe Options. -*/ - -struct BusLogic_ProbeOptions { - bool NoProbe:1; /* Bit 0 */ - bool NoProbeISA:1; /* Bit 1 */ - bool NoProbePCI:1; /* Bit 2 */ - bool NoSortPCI:1; /* Bit 3 */ - bool MultiMasterFirst:1;/* Bit 4 */ - bool FlashPointFirst:1; /* Bit 5 */ - bool LimitedProbeISA:1; /* Bit 6 */ - bool Probe330:1; /* Bit 7 */ - bool Probe334:1; /* Bit 8 */ - bool Probe230:1; /* Bit 9 */ - bool Probe234:1; /* Bit 10 */ - bool Probe130:1; /* Bit 11 */ - bool Probe134:1; /* Bit 12 */ -}; - -/* - Define the Global Options. -*/ - -struct BusLogic_GlobalOptions { - bool TraceProbe:1; /* Bit 0 */ - bool TraceHardwareReset:1; /* Bit 1 */ - bool TraceConfiguration:1; /* Bit 2 */ - bool TraceErrors:1; /* Bit 3 */ -}; - -/* - Define the Local Options. -*/ - -struct BusLogic_LocalOptions { - bool InhibitTargetInquiry:1; /* Bit 0 */ -}; - -/* - Define the BusLogic SCSI Host Adapter I/O Register Offsets. -*/ - -#define BusLogic_ControlRegisterOffset 0 /* WO register */ -#define BusLogic_StatusRegisterOffset 0 /* RO register */ -#define BusLogic_CommandParameterRegisterOffset 1 /* WO register */ -#define BusLogic_DataInRegisterOffset 1 /* RO register */ -#define BusLogic_InterruptRegisterOffset 2 /* RO register */ -#define BusLogic_GeometryRegisterOffset 3 /* RO register */ - -/* - Define the structure of the write-only Control Register. -*/ - -union BusLogic_ControlRegister { - unsigned char All; - struct { - unsigned char:4; /* Bits 0-3 */ - bool SCSIBusReset:1; /* Bit 4 */ - bool InterruptReset:1; /* Bit 5 */ - bool SoftReset:1; /* Bit 6 */ - bool HardReset:1; /* Bit 7 */ - } cr; -}; - -/* - Define the structure of the read-only Status Register. -*/ - -union BusLogic_StatusRegister { - unsigned char All; - struct { - bool CommandInvalid:1; /* Bit 0 */ - bool Reserved:1; /* Bit 1 */ - bool DataInRegisterReady:1; /* Bit 2 */ - bool CommandParameterRegisterBusy:1; /* Bit 3 */ - bool HostAdapterReady:1; /* Bit 4 */ - bool InitializationRequired:1; /* Bit 5 */ - bool DiagnosticFailure:1; /* Bit 6 */ - bool DiagnosticActive:1; /* Bit 7 */ - } sr; -}; - -/* - Define the structure of the read-only Interrupt Register. -*/ - -union BusLogic_InterruptRegister { - unsigned char All; - struct { - bool IncomingMailboxLoaded:1; /* Bit 0 */ - bool OutgoingMailboxAvailable:1;/* Bit 1 */ - bool CommandComplete:1; /* Bit 2 */ - bool ExternalBusReset:1; /* Bit 3 */ - unsigned char Reserved:3; /* Bits 4-6 */ - bool InterruptValid:1; /* Bit 7 */ - } ir; -}; - -/* - Define the structure of the read-only Geometry Register. -*/ - -union BusLogic_GeometryRegister { - unsigned char All; - struct { - enum BusLogic_BIOS_DiskGeometryTranslation Drive0Geometry:2; /* Bits 0-1 */ - enum BusLogic_BIOS_DiskGeometryTranslation Drive1Geometry:2; /* Bits 2-3 */ - unsigned char:3; /* Bits 4-6 */ - bool ExtendedTranslationEnabled:1; /* Bit 7 */ - } gr; -}; - -/* - Define the BusLogic SCSI Host Adapter Command Register Operation Codes. -*/ - -enum BusLogic_OperationCode { - BusLogic_TestCommandCompleteInterrupt = 0x00, - BusLogic_InitializeMailbox = 0x01, - BusLogic_ExecuteMailboxCommand = 0x02, - BusLogic_ExecuteBIOSCommand = 0x03, - BusLogic_InquireBoardID = 0x04, - BusLogic_EnableOutgoingMailboxAvailableInt = 0x05, - BusLogic_SetSCSISelectionTimeout = 0x06, - BusLogic_SetPreemptTimeOnBus = 0x07, - BusLogic_SetTimeOffBus = 0x08, - BusLogic_SetBusTransferRate = 0x09, - BusLogic_InquireInstalledDevicesID0to7 = 0x0A, - BusLogic_InquireConfiguration = 0x0B, - BusLogic_EnableTargetMode = 0x0C, - BusLogic_InquireSetupInformation = 0x0D, - BusLogic_WriteAdapterLocalRAM = 0x1A, - BusLogic_ReadAdapterLocalRAM = 0x1B, - BusLogic_WriteBusMasterChipFIFO = 0x1C, - BusLogic_ReadBusMasterChipFIFO = 0x1D, - BusLogic_EchoCommandData = 0x1F, - BusLogic_HostAdapterDiagnostic = 0x20, - BusLogic_SetAdapterOptions = 0x21, - BusLogic_InquireInstalledDevicesID8to15 = 0x23, - BusLogic_InquireTargetDevices = 0x24, - BusLogic_DisableHostAdapterInterrupt = 0x25, - BusLogic_InitializeExtendedMailbox = 0x81, - BusLogic_ExecuteSCSICommand = 0x83, - BusLogic_InquireFirmwareVersion3rdDigit = 0x84, - BusLogic_InquireFirmwareVersionLetter = 0x85, - BusLogic_InquirePCIHostAdapterInformation = 0x86, - BusLogic_InquireHostAdapterModelNumber = 0x8B, - BusLogic_InquireSynchronousPeriod = 0x8C, - BusLogic_InquireExtendedSetupInformation = 0x8D, - BusLogic_EnableStrictRoundRobinMode = 0x8F, - BusLogic_StoreHostAdapterLocalRAM = 0x90, - BusLogic_FetchHostAdapterLocalRAM = 0x91, - BusLogic_StoreLocalDataInEEPROM = 0x92, - BusLogic_UploadAutoSCSICode = 0x94, - BusLogic_ModifyIOAddress = 0x95, - BusLogic_SetCCBFormat = 0x96, - BusLogic_WriteInquiryBuffer = 0x9A, - BusLogic_ReadInquiryBuffer = 0x9B, - BusLogic_FlashROMUploadDownload = 0xA7, - BusLogic_ReadSCAMData = 0xA8, - BusLogic_WriteSCAMData = 0xA9 -}; - -/* - Define the Inquire Board ID reply structure. -*/ - -struct BusLogic_BoardID { - unsigned char BoardType; /* Byte 0 */ - unsigned char CustomFeatures; /* Byte 1 */ - unsigned char FirmwareVersion1stDigit; /* Byte 2 */ - unsigned char FirmwareVersion2ndDigit; /* Byte 3 */ -}; - -/* - Define the Inquire Configuration reply structure. -*/ - -struct BusLogic_Configuration { - unsigned char:5; /* Byte 0 Bits 0-4 */ - bool DMA_Channel5:1; /* Byte 0 Bit 5 */ - bool DMA_Channel6:1; /* Byte 0 Bit 6 */ - bool DMA_Channel7:1; /* Byte 0 Bit 7 */ - bool IRQ_Channel9:1; /* Byte 1 Bit 0 */ - bool IRQ_Channel10:1; /* Byte 1 Bit 1 */ - bool IRQ_Channel11:1; /* Byte 1 Bit 2 */ - bool IRQ_Channel12:1; /* Byte 1 Bit 3 */ - unsigned char:1; /* Byte 1 Bit 4 */ - bool IRQ_Channel14:1; /* Byte 1 Bit 5 */ - bool IRQ_Channel15:1; /* Byte 1 Bit 6 */ - unsigned char:1; /* Byte 1 Bit 7 */ - unsigned char HostAdapterID:4; /* Byte 2 Bits 0-3 */ - unsigned char:4; /* Byte 2 Bits 4-7 */ -}; - -/* - Define the Inquire Setup Information reply structure. -*/ - -struct BusLogic_SynchronousValue { - unsigned char Offset:4; /* Bits 0-3 */ - unsigned char TransferPeriod:3; /* Bits 4-6 */ - bool Synchronous:1; /* Bit 7 */ -}; - -struct BusLogic_SetupInformation { - bool SynchronousInitiationEnabled:1; /* Byte 0 Bit 0 */ - bool ParityCheckingEnabled:1; /* Byte 0 Bit 1 */ - unsigned char:6; /* Byte 0 Bits 2-7 */ - unsigned char BusTransferRate; /* Byte 1 */ - unsigned char PreemptTimeOnBus; /* Byte 2 */ - unsigned char TimeOffBus; /* Byte 3 */ - unsigned char MailboxCount; /* Byte 4 */ - unsigned char MailboxAddress[3]; /* Bytes 5-7 */ - struct BusLogic_SynchronousValue SynchronousValuesID0to7[8]; /* Bytes 8-15 */ - unsigned char DisconnectPermittedID0to7; /* Byte 16 */ - unsigned char Signature; /* Byte 17 */ - unsigned char CharacterD; /* Byte 18 */ - unsigned char HostBusType; /* Byte 19 */ - unsigned char WideTransfersPermittedID0to7; /* Byte 20 */ - unsigned char WideTransfersActiveID0to7; /* Byte 21 */ - struct BusLogic_SynchronousValue SynchronousValuesID8to15[8]; /* Bytes 22-29 */ - unsigned char DisconnectPermittedID8to15; /* Byte 30 */ - unsigned char:8; /* Byte 31 */ - unsigned char WideTransfersPermittedID8to15; /* Byte 32 */ - unsigned char WideTransfersActiveID8to15; /* Byte 33 */ -}; - -/* - Define the Initialize Extended Mailbox request structure. -*/ - -struct BusLogic_ExtendedMailboxRequest { - unsigned char MailboxCount; /* Byte 0 */ - u32 BaseMailboxAddress; /* Bytes 1-4 */ -} PACKED; - - -/* - Define the Inquire PCI Host Adapter Information reply type. The ISA - Compatible I/O Port values are defined here and are also used with - the Modify I/O Address command. -*/ - -enum BusLogic_ISACompatibleIOPort { - BusLogic_IO_330 = 0, - BusLogic_IO_334 = 1, - BusLogic_IO_230 = 2, - BusLogic_IO_234 = 3, - BusLogic_IO_130 = 4, - BusLogic_IO_134 = 5, - BusLogic_IO_Disable = 6, - BusLogic_IO_Disable2 = 7 -} PACKED; - -struct BusLogic_PCIHostAdapterInformation { - enum BusLogic_ISACompatibleIOPort ISACompatibleIOPort; /* Byte 0 */ - unsigned char PCIAssignedIRQChannel; /* Byte 1 */ - bool LowByteTerminated:1; /* Byte 2 Bit 0 */ - bool HighByteTerminated:1; /* Byte 2 Bit 1 */ - unsigned char:2; /* Byte 2 Bits 2-3 */ - bool JP1:1; /* Byte 2 Bit 4 */ - bool JP2:1; /* Byte 2 Bit 5 */ - bool JP3:1; /* Byte 2 Bit 6 */ - bool GenericInfoValid:1;/* Byte 2 Bit 7 */ - unsigned char:8; /* Byte 3 */ -}; - -/* - Define the Inquire Extended Setup Information reply structure. -*/ - -struct BusLogic_ExtendedSetupInformation { - unsigned char BusType; /* Byte 0 */ - unsigned char BIOS_Address; /* Byte 1 */ - unsigned short ScatterGatherLimit; /* Bytes 2-3 */ - unsigned char MailboxCount; /* Byte 4 */ - u32 BaseMailboxAddress; /* Bytes 5-8 */ - struct { - unsigned char:2; /* Byte 9 Bits 0-1 */ - bool FastOnEISA:1; /* Byte 9 Bit 2 */ - unsigned char:3; /* Byte 9 Bits 3-5 */ - bool LevelSensitiveInterrupt:1; /* Byte 9 Bit 6 */ - unsigned char:1; /* Byte 9 Bit 7 */ - } Misc; - unsigned char FirmwareRevision[3]; /* Bytes 10-12 */ - bool HostWideSCSI:1; /* Byte 13 Bit 0 */ - bool HostDifferentialSCSI:1; /* Byte 13 Bit 1 */ - bool HostSupportsSCAM:1; /* Byte 13 Bit 2 */ - bool HostUltraSCSI:1; /* Byte 13 Bit 3 */ - bool HostSmartTermination:1; /* Byte 13 Bit 4 */ - unsigned char:3; /* Byte 13 Bits 5-7 */ -} PACKED; - -/* - Define the Enable Strict Round Robin Mode request type. -*/ - -enum BusLogic_RoundRobinModeRequest { - BusLogic_AggressiveRoundRobinMode = 0, - BusLogic_StrictRoundRobinMode = 1 -} PACKED; - - -/* - Define the Fetch Host Adapter Local RAM request type. -*/ - -#define BusLogic_BIOS_BaseOffset 0 -#define BusLogic_AutoSCSI_BaseOffset 64 - -struct BusLogic_FetchHostAdapterLocalRAMRequest { - unsigned char ByteOffset; /* Byte 0 */ - unsigned char ByteCount; /* Byte 1 */ -}; - -/* - Define the Host Adapter Local RAM AutoSCSI structure. -*/ - -struct BusLogic_AutoSCSIData { - unsigned char InternalFactorySignature[2]; /* Bytes 0-1 */ - unsigned char InformationByteCount; /* Byte 2 */ - unsigned char HostAdapterType[6]; /* Bytes 3-8 */ - unsigned char:8; /* Byte 9 */ - bool FloppyEnabled:1; /* Byte 10 Bit 0 */ - bool FloppySecondary:1; /* Byte 10 Bit 1 */ - bool LevelSensitiveInterrupt:1; /* Byte 10 Bit 2 */ - unsigned char:2; /* Byte 10 Bits 3-4 */ - unsigned char SystemRAMAreaForBIOS:3; /* Byte 10 Bits 5-7 */ - unsigned char DMA_Channel:7; /* Byte 11 Bits 0-6 */ - bool DMA_AutoConfiguration:1; /* Byte 11 Bit 7 */ - unsigned char IRQ_Channel:7; /* Byte 12 Bits 0-6 */ - bool IRQ_AutoConfiguration:1; /* Byte 12 Bit 7 */ - unsigned char DMA_TransferRate; /* Byte 13 */ - unsigned char SCSI_ID; /* Byte 14 */ - bool LowByteTerminated:1; /* Byte 15 Bit 0 */ - bool ParityCheckingEnabled:1; /* Byte 15 Bit 1 */ - bool HighByteTerminated:1; /* Byte 15 Bit 2 */ - bool NoisyCablingEnvironment:1; /* Byte 15 Bit 3 */ - bool FastSynchronousNegotiation:1; /* Byte 15 Bit 4 */ - bool BusResetEnabled:1; /* Byte 15 Bit 5 */ - bool:1; /* Byte 15 Bit 6 */ - bool ActiveNegationEnabled:1; /* Byte 15 Bit 7 */ - unsigned char BusOnDelay; /* Byte 16 */ - unsigned char BusOffDelay; /* Byte 17 */ - bool HostAdapterBIOSEnabled:1; /* Byte 18 Bit 0 */ - bool BIOSRedirectionOfINT19Enabled:1; /* Byte 18 Bit 1 */ - bool ExtendedTranslationEnabled:1; /* Byte 18 Bit 2 */ - bool MapRemovableAsFixedEnabled:1; /* Byte 18 Bit 3 */ - bool:1; /* Byte 18 Bit 4 */ - bool BIOSSupportsMoreThan2DrivesEnabled:1; /* Byte 18 Bit 5 */ - bool BIOSInterruptModeEnabled:1; /* Byte 18 Bit 6 */ - bool FlopticalSupportEnabled:1; /* Byte 19 Bit 7 */ - unsigned short DeviceEnabled; /* Bytes 19-20 */ - unsigned short WidePermitted; /* Bytes 21-22 */ - unsigned short FastPermitted; /* Bytes 23-24 */ - unsigned short SynchronousPermitted; /* Bytes 25-26 */ - unsigned short DisconnectPermitted; /* Bytes 27-28 */ - unsigned short SendStartUnitCommand; /* Bytes 29-30 */ - unsigned short IgnoreInBIOSScan; /* Bytes 31-32 */ - unsigned char PCIInterruptPin:2; /* Byte 33 Bits 0-1 */ - unsigned char HostAdapterIOPortAddress:2; /* Byte 33 Bits 2-3 */ - bool StrictRoundRobinModeEnabled:1; /* Byte 33 Bit 4 */ - bool VESABusSpeedGreaterThan33MHz:1; /* Byte 33 Bit 5 */ - bool VESABurstWriteEnabled:1; /* Byte 33 Bit 6 */ - bool VESABurstReadEnabled:1; /* Byte 33 Bit 7 */ - unsigned short UltraPermitted; /* Bytes 34-35 */ - unsigned int:32; /* Bytes 36-39 */ - unsigned char:8; /* Byte 40 */ - unsigned char AutoSCSIMaximumLUN; /* Byte 41 */ - bool:1; /* Byte 42 Bit 0 */ - bool SCAM_Dominant:1; /* Byte 42 Bit 1 */ - bool SCAM_Enabled:1; /* Byte 42 Bit 2 */ - bool SCAM_Level2:1; /* Byte 42 Bit 3 */ - unsigned char:4; /* Byte 42 Bits 4-7 */ - bool INT13ExtensionEnabled:1; /* Byte 43 Bit 0 */ - bool:1; /* Byte 43 Bit 1 */ - bool CDROMBootEnabled:1; /* Byte 43 Bit 2 */ - unsigned char:5; /* Byte 43 Bits 3-7 */ - unsigned char BootTargetID:4; /* Byte 44 Bits 0-3 */ - unsigned char BootChannel:4; /* Byte 44 Bits 4-7 */ - unsigned char ForceBusDeviceScanningOrder:1; /* Byte 45 Bit 0 */ - unsigned char:7; /* Byte 45 Bits 1-7 */ - unsigned short NonTaggedToAlternateLUNPermitted; /* Bytes 46-47 */ - unsigned short RenegotiateSyncAfterCheckCondition; /* Bytes 48-49 */ - unsigned char Reserved[10]; /* Bytes 50-59 */ - unsigned char ManufacturingDiagnostic[2]; /* Bytes 60-61 */ - unsigned short Checksum; /* Bytes 62-63 */ -} PACKED; - -/* - Define the Host Adapter Local RAM Auto SCSI Byte 45 structure. -*/ - -struct BusLogic_AutoSCSIByte45 { - unsigned char ForceBusDeviceScanningOrder:1; /* Bit 0 */ - unsigned char:7; /* Bits 1-7 */ -}; - -/* - Define the Host Adapter Local RAM BIOS Drive Map Byte structure. -*/ - -#define BusLogic_BIOS_DriveMapOffset 17 - -struct BusLogic_BIOSDriveMapByte { - unsigned char TargetIDBit3:1; /* Bit 0 */ - unsigned char:2; /* Bits 1-2 */ - enum BusLogic_BIOS_DiskGeometryTranslation DiskGeometry:2; /* Bits 3-4 */ - unsigned char TargetID:3; /* Bits 5-7 */ -}; - -/* - Define the Set CCB Format request type. Extended LUN Format CCBs are - necessary to support more than 8 Logical Units per Target Device. -*/ - -enum BusLogic_SetCCBFormatRequest { - BusLogic_LegacyLUNFormatCCB = 0, - BusLogic_ExtendedLUNFormatCCB = 1 -} PACKED; - -/* - Define the Outgoing Mailbox Action Codes. -*/ - -enum BusLogic_ActionCode { - BusLogic_OutgoingMailboxFree = 0x00, - BusLogic_MailboxStartCommand = 0x01, - BusLogic_MailboxAbortCommand = 0x02 -} PACKED; - - -/* - Define the Incoming Mailbox Completion Codes. The MultiMaster Firmware - only uses codes 0 - 4. The FlashPoint SCCB Manager has no mailboxes, so - completion codes are stored in the CCB; it only uses codes 1, 2, 4, and 5. -*/ - -enum BusLogic_CompletionCode { - BusLogic_IncomingMailboxFree = 0x00, - BusLogic_CommandCompletedWithoutError = 0x01, - BusLogic_CommandAbortedAtHostRequest = 0x02, - BusLogic_AbortedCommandNotFound = 0x03, - BusLogic_CommandCompletedWithError = 0x04, - BusLogic_InvalidCCB = 0x05 -} PACKED; - -/* - Define the Command Control Block (CCB) Opcodes. -*/ - -enum BusLogic_CCB_Opcode { - BusLogic_InitiatorCCB = 0x00, - BusLogic_TargetCCB = 0x01, - BusLogic_InitiatorCCB_ScatterGather = 0x02, - BusLogic_InitiatorCCB_ResidualDataLength = 0x03, - BusLogic_InitiatorCCB_ScatterGatherResidual = 0x04, - BusLogic_BusDeviceReset = 0x81 -} PACKED; - - -/* - Define the CCB Data Direction Codes. -*/ - -enum BusLogic_DataDirection { - BusLogic_UncheckedDataTransfer = 0, - BusLogic_DataInLengthChecked = 1, - BusLogic_DataOutLengthChecked = 2, - BusLogic_NoDataTransfer = 3 -}; - - -/* - Define the Host Adapter Status Codes. The MultiMaster Firmware does not - return status code 0x0C; it uses 0x12 for both overruns and underruns. -*/ - -enum BusLogic_HostAdapterStatus { - BusLogic_CommandCompletedNormally = 0x00, - BusLogic_LinkedCommandCompleted = 0x0A, - BusLogic_LinkedCommandCompletedWithFlag = 0x0B, - BusLogic_DataUnderRun = 0x0C, - BusLogic_SCSISelectionTimeout = 0x11, - BusLogic_DataOverRun = 0x12, - BusLogic_UnexpectedBusFree = 0x13, - BusLogic_InvalidBusPhaseRequested = 0x14, - BusLogic_InvalidOutgoingMailboxActionCode = 0x15, - BusLogic_InvalidCommandOperationCode = 0x16, - BusLogic_LinkedCCBhasInvalidLUN = 0x17, - BusLogic_InvalidCommandParameter = 0x1A, - BusLogic_AutoRequestSenseFailed = 0x1B, - BusLogic_TaggedQueuingMessageRejected = 0x1C, - BusLogic_UnsupportedMessageReceived = 0x1D, - BusLogic_HostAdapterHardwareFailed = 0x20, - BusLogic_TargetFailedResponseToATN = 0x21, - BusLogic_HostAdapterAssertedRST = 0x22, - BusLogic_OtherDeviceAssertedRST = 0x23, - BusLogic_TargetDeviceReconnectedImproperly = 0x24, - BusLogic_HostAdapterAssertedBusDeviceReset = 0x25, - BusLogic_AbortQueueGenerated = 0x26, - BusLogic_HostAdapterSoftwareError = 0x27, - BusLogic_HostAdapterHardwareTimeoutError = 0x30, - BusLogic_SCSIParityErrorDetected = 0x34 -} PACKED; - - -/* - Define the SCSI Target Device Status Codes. -*/ - -enum BusLogic_TargetDeviceStatus { - BusLogic_OperationGood = 0x00, - BusLogic_CheckCondition = 0x02, - BusLogic_DeviceBusy = 0x08 -} PACKED; - -/* - Define the Queue Tag Codes. -*/ - -enum BusLogic_QueueTag { - BusLogic_SimpleQueueTag = 0, - BusLogic_HeadOfQueueTag = 1, - BusLogic_OrderedQueueTag = 2, - BusLogic_ReservedQT = 3 -}; - -/* - Define the SCSI Command Descriptor Block (CDB). -*/ - -#define BusLogic_CDB_MaxLength 12 - -typedef unsigned char SCSI_CDB_T[BusLogic_CDB_MaxLength]; - - -/* - Define the Scatter/Gather Segment structure required by the MultiMaster - Firmware Interface and the FlashPoint SCCB Manager. -*/ - -struct BusLogic_ScatterGatherSegment { - u32 SegmentByteCount; /* Bytes 0-3 */ - u32 SegmentDataPointer; /* Bytes 4-7 */ -}; - -/* - Define the Driver CCB Status Codes. -*/ - -enum BusLogic_CCB_Status { - BusLogic_CCB_Free = 0, - BusLogic_CCB_Active = 1, - BusLogic_CCB_Completed = 2, - BusLogic_CCB_Reset = 3 -} PACKED; - - -/* - Define the 32 Bit Mode Command Control Block (CCB) structure. The first 40 - bytes are defined by and common to both the MultiMaster Firmware and the - FlashPoint SCCB Manager. The next 60 bytes are defined by the FlashPoint - SCCB Manager. The remaining components are defined by the Linux BusLogic - Driver. Extended LUN Format CCBs differ from Legacy LUN Format 32 Bit Mode - CCBs only in having the TagEnable and QueueTag fields moved from byte 17 to - byte 1, and the Logical Unit field in byte 17 expanded to 6 bits. In theory, - Extended LUN Format CCBs can support up to 64 Logical Units, but in practice - many devices will respond improperly to Logical Units between 32 and 63, and - the SCSI-2 specification defines Bit 5 as LUNTAR. Extended LUN Format CCBs - are used by recent versions of the MultiMaster Firmware, as well as by the - FlashPoint SCCB Manager; the FlashPoint SCCB Manager only supports 32 Logical - Units. Since 64 Logical Units are unlikely to be needed in practice, and - since they are problematic for the above reasons, and since limiting them to - 5 bits simplifies the CCB structure definition, this driver only supports - 32 Logical Units per Target Device. -*/ - -struct BusLogic_CCB { - /* - MultiMaster Firmware and FlashPoint SCCB Manager Common Portion. - */ - enum BusLogic_CCB_Opcode Opcode; /* Byte 0 */ - unsigned char:3; /* Byte 1 Bits 0-2 */ - enum BusLogic_DataDirection DataDirection:2; /* Byte 1 Bits 3-4 */ - bool TagEnable:1; /* Byte 1 Bit 5 */ - enum BusLogic_QueueTag QueueTag:2; /* Byte 1 Bits 6-7 */ - unsigned char CDB_Length; /* Byte 2 */ - unsigned char SenseDataLength; /* Byte 3 */ - u32 DataLength; /* Bytes 4-7 */ - u32 DataPointer; /* Bytes 8-11 */ - unsigned char:8; /* Byte 12 */ - unsigned char:8; /* Byte 13 */ - enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 14 */ - enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 15 */ - unsigned char TargetID; /* Byte 16 */ - unsigned char LogicalUnit:5; /* Byte 17 Bits 0-4 */ - bool LegacyTagEnable:1; /* Byte 17 Bit 5 */ - enum BusLogic_QueueTag LegacyQueueTag:2; /* Byte 17 Bits 6-7 */ - SCSI_CDB_T CDB; /* Bytes 18-29 */ - unsigned char:8; /* Byte 30 */ - unsigned char:8; /* Byte 31 */ - unsigned int:32; /* Bytes 32-35 */ - u32 SenseDataPointer; /* Bytes 36-39 */ - /* - FlashPoint SCCB Manager Defined Portion. - */ - void (*CallbackFunction) (struct BusLogic_CCB *); /* Bytes 40-43 */ - u32 BaseAddress; /* Bytes 44-47 */ - enum BusLogic_CompletionCode CompletionCode; /* Byte 48 */ -#ifdef CONFIG_SCSI_FLASHPOINT - unsigned char:8; /* Byte 49 */ - unsigned short OS_Flags; /* Bytes 50-51 */ - unsigned char Private[48]; /* Bytes 52-99 */ -#endif - /* - BusLogic Linux Driver Defined Portion. - */ - dma_addr_t AllocationGroupHead; - unsigned int AllocationGroupSize; - u32 DMA_Handle; - enum BusLogic_CCB_Status Status; - unsigned long SerialNumber; - struct scsi_cmnd *Command; - struct BusLogic_HostAdapter *HostAdapter; - struct BusLogic_CCB *Next; - struct BusLogic_CCB *NextAll; - struct BusLogic_ScatterGatherSegment - ScatterGatherList[BusLogic_ScatterGatherLimit]; -}; - -/* - Define the 32 Bit Mode Outgoing Mailbox structure. -*/ - -struct BusLogic_OutgoingMailbox { - u32 CCB; /* Bytes 0-3 */ - unsigned int:24; /* Bytes 4-6 */ - enum BusLogic_ActionCode ActionCode; /* Byte 7 */ -}; - -/* - Define the 32 Bit Mode Incoming Mailbox structure. -*/ - -struct BusLogic_IncomingMailbox { - u32 CCB; /* Bytes 0-3 */ - enum BusLogic_HostAdapterStatus HostAdapterStatus; /* Byte 4 */ - enum BusLogic_TargetDeviceStatus TargetDeviceStatus; /* Byte 5 */ - unsigned char:8; /* Byte 6 */ - enum BusLogic_CompletionCode CompletionCode; /* Byte 7 */ -}; - - -/* - Define the BusLogic Driver Options structure. -*/ - -struct BusLogic_DriverOptions { - unsigned short TaggedQueuingPermitted; - unsigned short TaggedQueuingPermittedMask; - unsigned short BusSettleTime; - struct BusLogic_LocalOptions LocalOptions; - unsigned char CommonQueueDepth; - unsigned char QueueDepth[BusLogic_MaxTargetDevices]; -}; - -/* - Define the Host Adapter Target Flags structure. -*/ - -struct BusLogic_TargetFlags { - bool TargetExists:1; - bool TaggedQueuingSupported:1; - bool WideTransfersSupported:1; - bool TaggedQueuingActive:1; - bool WideTransfersActive:1; - bool CommandSuccessfulFlag:1; - bool TargetInfoReported:1; -}; - -/* - Define the Host Adapter Target Statistics structure. -*/ - -#define BusLogic_SizeBuckets 10 - -typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets]; - -struct BusLogic_TargetStatistics { - unsigned int CommandsAttempted; - unsigned int CommandsCompleted; - unsigned int ReadCommands; - unsigned int WriteCommands; - struct BusLogic_ByteCounter TotalBytesRead; - struct BusLogic_ByteCounter TotalBytesWritten; - BusLogic_CommandSizeBuckets_T ReadCommandSizeBuckets; - BusLogic_CommandSizeBuckets_T WriteCommandSizeBuckets; - unsigned short CommandAbortsRequested; - unsigned short CommandAbortsAttempted; - unsigned short CommandAbortsCompleted; - unsigned short BusDeviceResetsRequested; - unsigned short BusDeviceResetsAttempted; - unsigned short BusDeviceResetsCompleted; - unsigned short HostAdapterResetsRequested; - unsigned short HostAdapterResetsAttempted; - unsigned short HostAdapterResetsCompleted; -}; - -/* - Define the FlashPoint Card Handle data type. -*/ - -#define FlashPoint_BadCardHandle 0xFFFFFFFF - -typedef unsigned int FlashPoint_CardHandle_T; - - -/* - Define the FlashPoint Information structure. This structure is defined - by the FlashPoint SCCB Manager. -*/ - -struct FlashPoint_Info { - u32 BaseAddress; /* Bytes 0-3 */ - bool Present; /* Byte 4 */ - unsigned char IRQ_Channel; /* Byte 5 */ - unsigned char SCSI_ID; /* Byte 6 */ - unsigned char SCSI_LUN; /* Byte 7 */ - unsigned short FirmwareRevision; /* Bytes 8-9 */ - unsigned short SynchronousPermitted; /* Bytes 10-11 */ - unsigned short FastPermitted; /* Bytes 12-13 */ - unsigned short UltraPermitted; /* Bytes 14-15 */ - unsigned short DisconnectPermitted; /* Bytes 16-17 */ - unsigned short WidePermitted; /* Bytes 18-19 */ - bool ParityCheckingEnabled:1; /* Byte 20 Bit 0 */ - bool HostWideSCSI:1; /* Byte 20 Bit 1 */ - bool HostSoftReset:1; /* Byte 20 Bit 2 */ - bool ExtendedTranslationEnabled:1; /* Byte 20 Bit 3 */ - bool LowByteTerminated:1; /* Byte 20 Bit 4 */ - bool HighByteTerminated:1; /* Byte 20 Bit 5 */ - bool ReportDataUnderrun:1; /* Byte 20 Bit 6 */ - bool SCAM_Enabled:1; /* Byte 20 Bit 7 */ - bool SCAM_Level2:1; /* Byte 21 Bit 0 */ - unsigned char:7; /* Byte 21 Bits 1-7 */ - unsigned char Family; /* Byte 22 */ - unsigned char BusType; /* Byte 23 */ - unsigned char ModelNumber[3]; /* Bytes 24-26 */ - unsigned char RelativeCardNumber; /* Byte 27 */ - unsigned char Reserved[4]; /* Bytes 28-31 */ - unsigned int OS_Reserved; /* Bytes 32-35 */ - unsigned char TranslationInfo[4]; /* Bytes 36-39 */ - unsigned int Reserved2[5]; /* Bytes 40-59 */ - unsigned int SecondaryRange; /* Bytes 60-63 */ -}; - -/* - Define the BusLogic Driver Host Adapter structure. -*/ - -struct BusLogic_HostAdapter { - struct Scsi_Host *SCSI_Host; - struct pci_dev *PCI_Device; - enum BusLogic_HostAdapterType HostAdapterType; - enum BusLogic_HostAdapterBusType HostAdapterBusType; - unsigned long IO_Address; - unsigned long PCI_Address; - unsigned short AddressCount; - unsigned char HostNumber; - unsigned char ModelName[9]; - unsigned char FirmwareVersion[6]; - unsigned char FullModelName[18]; - unsigned char Bus; - unsigned char Device; - unsigned char IRQ_Channel; - unsigned char DMA_Channel; - unsigned char SCSI_ID; - bool IRQ_ChannelAcquired:1; - bool DMA_ChannelAcquired:1; - bool ExtendedTranslationEnabled:1; - bool ParityCheckingEnabled:1; - bool BusResetEnabled:1; - bool LevelSensitiveInterrupt:1; - bool HostWideSCSI:1; - bool HostDifferentialSCSI:1; - bool HostSupportsSCAM:1; - bool HostUltraSCSI:1; - bool ExtendedLUNSupport:1; - bool TerminationInfoValid:1; - bool LowByteTerminated:1; - bool HighByteTerminated:1; - bool BounceBuffersRequired:1; - bool StrictRoundRobinModeSupport:1; - bool SCAM_Enabled:1; - bool SCAM_Level2:1; - bool HostAdapterInitialized:1; - bool HostAdapterExternalReset:1; - bool HostAdapterInternalError:1; - bool ProcessCompletedCCBsActive; - volatile bool HostAdapterCommandCompleted; - unsigned short HostAdapterScatterGatherLimit; - unsigned short DriverScatterGatherLimit; - unsigned short MaxTargetDevices; - unsigned short MaxLogicalUnits; - unsigned short MailboxCount; - unsigned short InitialCCBs; - unsigned short IncrementalCCBs; - unsigned short AllocatedCCBs; - unsigned short DriverQueueDepth; - unsigned short HostAdapterQueueDepth; - unsigned short UntaggedQueueDepth; - unsigned short CommonQueueDepth; - unsigned short BusSettleTime; - unsigned short SynchronousPermitted; - unsigned short FastPermitted; - unsigned short UltraPermitted; - unsigned short WidePermitted; - unsigned short DisconnectPermitted; - unsigned short TaggedQueuingPermitted; - unsigned short ExternalHostAdapterResets; - unsigned short HostAdapterInternalErrors; - unsigned short TargetDeviceCount; - unsigned short MessageBufferLength; - u32 BIOS_Address; - struct BusLogic_DriverOptions *DriverOptions; - struct FlashPoint_Info FlashPointInfo; - FlashPoint_CardHandle_T CardHandle; - struct list_head host_list; - struct BusLogic_CCB *All_CCBs; - struct BusLogic_CCB *Free_CCBs; - struct BusLogic_CCB *FirstCompletedCCB; - struct BusLogic_CCB *LastCompletedCCB; - struct BusLogic_CCB *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices]; - struct BusLogic_TargetFlags TargetFlags[BusLogic_MaxTargetDevices]; - unsigned char QueueDepth[BusLogic_MaxTargetDevices]; - unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices]; - unsigned char SynchronousOffset[BusLogic_MaxTargetDevices]; - unsigned char ActiveCommands[BusLogic_MaxTargetDevices]; - unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices]; - unsigned long LastSequencePoint[BusLogic_MaxTargetDevices]; - unsigned long LastResetAttempted[BusLogic_MaxTargetDevices]; - unsigned long LastResetCompleted[BusLogic_MaxTargetDevices]; - struct BusLogic_OutgoingMailbox *FirstOutgoingMailbox; - struct BusLogic_OutgoingMailbox *LastOutgoingMailbox; - struct BusLogic_OutgoingMailbox *NextOutgoingMailbox; - struct BusLogic_IncomingMailbox *FirstIncomingMailbox; - struct BusLogic_IncomingMailbox *LastIncomingMailbox; - struct BusLogic_IncomingMailbox *NextIncomingMailbox; - struct BusLogic_TargetStatistics TargetStatistics[BusLogic_MaxTargetDevices]; - unsigned char *MailboxSpace; - dma_addr_t MailboxSpaceHandle; - unsigned int MailboxSize; - unsigned long CCB_Offset; - char MessageBuffer[BusLogic_MessageBufferSize]; -}; - -/* - Define a structure for the BIOS Disk Parameters. -*/ - -struct BIOS_DiskParameters { - int Heads; - int Sectors; - int Cylinders; -}; - -/* - Define a structure for the SCSI Inquiry command results. -*/ - -struct SCSI_Inquiry { - unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */ - unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */ - unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */ - bool RMB:1; /* Byte 1 Bit 7 */ - unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */ - unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */ - unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */ - unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */ - unsigned char:2; /* Byte 3 Bits 4-5 */ - bool TrmIOP:1; /* Byte 3 Bit 6 */ - bool AENC:1; /* Byte 3 Bit 7 */ - unsigned char AdditionalLength; /* Byte 4 */ - unsigned char:8; /* Byte 5 */ - unsigned char:8; /* Byte 6 */ - bool SftRe:1; /* Byte 7 Bit 0 */ - bool CmdQue:1; /* Byte 7 Bit 1 */ - bool:1; /* Byte 7 Bit 2 */ - bool Linked:1; /* Byte 7 Bit 3 */ - bool Sync:1; /* Byte 7 Bit 4 */ - bool WBus16:1; /* Byte 7 Bit 5 */ - bool WBus32:1; /* Byte 7 Bit 6 */ - bool RelAdr:1; /* Byte 7 Bit 7 */ - unsigned char VendorIdentification[8]; /* Bytes 8-15 */ - unsigned char ProductIdentification[16]; /* Bytes 16-31 */ - unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */ -}; - - -/* - Define functions to provide an abstraction for reading and writing the - Host Adapter I/O Registers. -*/ - -static inline void BusLogic_SCSIBusReset(struct BusLogic_HostAdapter *HostAdapter) -{ - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.SCSIBusReset = true; - outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); -} - -static inline void BusLogic_InterruptReset(struct BusLogic_HostAdapter *HostAdapter) -{ - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.InterruptReset = true; - outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); -} - -static inline void BusLogic_SoftReset(struct BusLogic_HostAdapter *HostAdapter) -{ - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.SoftReset = true; - outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); -} - -static inline void BusLogic_HardReset(struct BusLogic_HostAdapter *HostAdapter) -{ - union BusLogic_ControlRegister ControlRegister; - ControlRegister.All = 0; - ControlRegister.cr.HardReset = true; - outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset); -} - -static inline unsigned char BusLogic_ReadStatusRegister(struct BusLogic_HostAdapter *HostAdapter) -{ - return inb(HostAdapter->IO_Address + BusLogic_StatusRegisterOffset); -} - -static inline void BusLogic_WriteCommandParameterRegister(struct BusLogic_HostAdapter - *HostAdapter, unsigned char Value) -{ - outb(Value, HostAdapter->IO_Address + BusLogic_CommandParameterRegisterOffset); -} - -static inline unsigned char BusLogic_ReadDataInRegister(struct BusLogic_HostAdapter *HostAdapter) -{ - return inb(HostAdapter->IO_Address + BusLogic_DataInRegisterOffset); -} - -static inline unsigned char BusLogic_ReadInterruptRegister(struct BusLogic_HostAdapter *HostAdapter) -{ - return inb(HostAdapter->IO_Address + BusLogic_InterruptRegisterOffset); -} - -static inline unsigned char BusLogic_ReadGeometryRegister(struct BusLogic_HostAdapter *HostAdapter) -{ - return inb(HostAdapter->IO_Address + BusLogic_GeometryRegisterOffset); -} - -/* - BusLogic_StartMailboxCommand issues an Execute Mailbox Command, which - notifies the Host Adapter that an entry has been made in an Outgoing - Mailbox. -*/ - -static inline void BusLogic_StartMailboxCommand(struct BusLogic_HostAdapter *HostAdapter) -{ - BusLogic_WriteCommandParameterRegister(HostAdapter, BusLogic_ExecuteMailboxCommand); -} - -/* - BusLogic_Delay waits for Seconds to elapse. -*/ - -static inline void BusLogic_Delay(int Seconds) -{ - mdelay(1000 * Seconds); -} - -/* - Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses - and PCI/VLB/EISA/ISA Bus Addresses. -*/ - -static inline u32 Virtual_to_Bus(void *VirtualAddress) -{ - return (u32) virt_to_bus(VirtualAddress); -} - -static inline void *Bus_to_Virtual(u32 BusAddress) -{ - return (void *) bus_to_virt(BusAddress); -} - -/* - Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and - 32 bit Kernel Virtual Addresses. This avoids compilation warnings - on 64 bit architectures. -*/ - -static inline u32 Virtual_to_32Bit_Virtual(void *VirtualAddress) -{ - return (u32) (unsigned long) VirtualAddress; -} - -/* - BusLogic_IncrementErrorCounter increments Error Counter by 1, stopping at - 65535 rather than wrapping around to 0. -*/ - -static inline void BusLogic_IncrementErrorCounter(unsigned short *ErrorCounter) -{ - if (*ErrorCounter < 65535) - (*ErrorCounter)++; -} - -/* - BusLogic_IncrementByteCounter increments Byte Counter by Amount. -*/ - -static inline void BusLogic_IncrementByteCounter(struct BusLogic_ByteCounter - *ByteCounter, unsigned int Amount) -{ - ByteCounter->Units += Amount; - if (ByteCounter->Units > 999999999) { - ByteCounter->Units -= 1000000000; - ByteCounter->Billions++; - } -} - -/* - BusLogic_IncrementSizeBucket increments the Bucket for Amount. -*/ - -static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T CommandSizeBuckets, unsigned int Amount) -{ - int Index = 0; - if (Amount < 8 * 1024) { - if (Amount < 2 * 1024) - Index = (Amount < 1 * 1024 ? 0 : 1); - else - Index = (Amount < 4 * 1024 ? 2 : 3); - } else if (Amount < 128 * 1024) { - if (Amount < 32 * 1024) - Index = (Amount < 16 * 1024 ? 4 : 5); - else - Index = (Amount < 64 * 1024 ? 6 : 7); - } else - Index = (Amount < 256 * 1024 ? 8 : 9); - CommandSizeBuckets[Index]++; -} - -/* - Define the version number of the FlashPoint Firmware (SCCB Manager). -*/ - -#define FlashPoint_FirmwareVersion "5.02" - -/* - Define the possible return values from FlashPoint_HandleInterrupt. -*/ - -#define FlashPoint_NormalInterrupt 0x00 -#define FlashPoint_InternalError 0xFE -#define FlashPoint_ExternalBusReset 0xFF - -/* - Define prototypes for the forward referenced BusLogic Driver - Internal Functions. -*/ - -static const char *BusLogic_DriverInfo(struct Scsi_Host *); -static int BusLogic_QueueCommand(struct Scsi_Host *h, struct scsi_cmnd *); -static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *); -static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int); -static int BusLogic_SlaveConfigure(struct scsi_device *); -static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *); -static irqreturn_t BusLogic_InterruptHandler(int, void *); -static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, bool HardReset); -static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...); -static int __init BusLogic_Setup(char *); - -#endif /* _BUSLOGIC_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/FlashPoint.c b/ANDROID_3.4.5/drivers/scsi/FlashPoint.c deleted file mode 100644 index dcd716d6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/FlashPoint.c +++ /dev/null @@ -1,7644 +0,0 @@ -/* - - FlashPoint.c -- FlashPoint SCCB Manager for Linux - - This file contains the FlashPoint SCCB Manager from BusLogic's FlashPoint - Driver Developer's Kit, with minor modifications by Leonard N. Zubkoff for - Linux compatibility. It was provided by BusLogic in the form of 16 separate - source files, which would have unnecessarily cluttered the scsi directory, so - the individual files have been combined into this single file. - - Copyright 1995-1996 by Mylex Corporation. All Rights Reserved - - This file is available under both the GNU General Public License - and a BSD-style copyright; see LICENSE.FlashPoint for details. - -*/ - - -#ifdef CONFIG_SCSI_FLASHPOINT - -#define MAX_CARDS 8 -#undef BUSTYPE_PCI - -#define CRCMASK 0xA001 - -#define FAILURE 0xFFFFFFFFL - -struct sccb; -typedef void (*CALL_BK_FN) (struct sccb *); - -struct sccb_mgr_info { - unsigned long si_baseaddr; - unsigned char si_present; - unsigned char si_intvect; - unsigned char si_id; - unsigned char si_lun; - unsigned short si_fw_revision; - unsigned short si_per_targ_init_sync; - unsigned short si_per_targ_fast_nego; - unsigned short si_per_targ_ultra_nego; - unsigned short si_per_targ_no_disc; - unsigned short si_per_targ_wide_nego; - unsigned short si_flags; - unsigned char si_card_family; - unsigned char si_bustype; - unsigned char si_card_model[3]; - unsigned char si_relative_cardnum; - unsigned char si_reserved[4]; - unsigned long si_OS_reserved; - unsigned char si_XlatInfo[4]; - unsigned long si_reserved2[5]; - unsigned long si_secondary_range; -}; - -#define SCSI_PARITY_ENA 0x0001 -#define LOW_BYTE_TERM 0x0010 -#define HIGH_BYTE_TERM 0x0020 -#define BUSTYPE_PCI 0x3 - -#define SUPPORT_16TAR_32LUN 0x0002 -#define SOFT_RESET 0x0004 -#define EXTENDED_TRANSLATION 0x0008 -#define POST_ALL_UNDERRRUNS 0x0040 -#define FLAG_SCAM_ENABLED 0x0080 -#define FLAG_SCAM_LEVEL2 0x0100 - -#define HARPOON_FAMILY 0x02 - -/* SCCB struct used for both SCCB and UCB manager compiles! - * The UCB Manager treats the SCCB as it's 'native hardware structure' - */ - -#pragma pack(1) -struct sccb { - unsigned char OperationCode; - unsigned char ControlByte; - unsigned char CdbLength; - unsigned char RequestSenseLength; - unsigned long DataLength; - unsigned long DataPointer; - unsigned char CcbRes[2]; - unsigned char HostStatus; - unsigned char TargetStatus; - unsigned char TargID; - unsigned char Lun; - unsigned char Cdb[12]; - unsigned char CcbRes1; - unsigned char Reserved1; - unsigned long Reserved2; - unsigned long SensePointer; - - CALL_BK_FN SccbCallback; /* VOID (*SccbCallback)(); */ - unsigned long SccbIOPort; /* Identifies board base port */ - unsigned char SccbStatus; - unsigned char SCCBRes2; - unsigned short SccbOSFlags; - - unsigned long Sccb_XferCnt; /* actual transfer count */ - unsigned long Sccb_ATC; - unsigned long SccbVirtDataPtr; /* virtual addr for OS/2 */ - unsigned long Sccb_res1; - unsigned short Sccb_MGRFlags; - unsigned short Sccb_sgseg; - unsigned char Sccb_scsimsg; /* identify msg for selection */ - unsigned char Sccb_tag; - unsigned char Sccb_scsistat; - unsigned char Sccb_idmsg; /* image of last msg in */ - struct sccb *Sccb_forwardlink; - struct sccb *Sccb_backlink; - unsigned long Sccb_savedATC; - unsigned char Save_Cdb[6]; - unsigned char Save_CdbLen; - unsigned char Sccb_XferState; - unsigned long Sccb_SGoffset; -}; - -#pragma pack() - -#define SCATTER_GATHER_COMMAND 0x02 -#define RESIDUAL_COMMAND 0x03 -#define RESIDUAL_SG_COMMAND 0x04 -#define RESET_COMMAND 0x81 - -#define F_USE_CMD_Q 0x20 /*Inidcates TAGGED command. */ -#define TAG_TYPE_MASK 0xC0 /*Type of tag msg to send. */ -#define SCCB_DATA_XFER_OUT 0x10 /* Write */ -#define SCCB_DATA_XFER_IN 0x08 /* Read */ - -#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */ - -#define BUS_FREE_ST 0 -#define SELECT_ST 1 -#define SELECT_BDR_ST 2 /* Select w\ Bus Device Reset */ -#define SELECT_SN_ST 3 /* Select w\ Sync Nego */ -#define SELECT_WN_ST 4 /* Select w\ Wide Data Nego */ -#define SELECT_Q_ST 5 /* Select w\ Tagged Q'ing */ -#define COMMAND_ST 6 -#define DATA_OUT_ST 7 -#define DATA_IN_ST 8 -#define DISCONNECT_ST 9 -#define ABORT_ST 11 - -#define F_HOST_XFER_DIR 0x01 -#define F_ALL_XFERRED 0x02 -#define F_SG_XFER 0x04 -#define F_AUTO_SENSE 0x08 -#define F_ODD_BALL_CNT 0x10 -#define F_NO_DATA_YET 0x80 - -#define F_STATUSLOADED 0x01 -#define F_DEV_SELECTED 0x04 - -#define SCCB_COMPLETE 0x00 /* SCCB completed without error */ -#define SCCB_DATA_UNDER_RUN 0x0C -#define SCCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */ -#define SCCB_DATA_OVER_RUN 0x12 -#define SCCB_PHASE_SEQUENCE_FAIL 0x14 /* Target bus phase sequence failure */ - -#define SCCB_GROSS_FW_ERR 0x27 /* Major problem! */ -#define SCCB_BM_ERR 0x30 /* BusMaster error. */ -#define SCCB_PARITY_ERR 0x34 /* SCSI parity error */ - -#define SCCB_IN_PROCESS 0x00 -#define SCCB_SUCCESS 0x01 -#define SCCB_ABORT 0x02 -#define SCCB_ERROR 0x04 - -#define ORION_FW_REV 3110 - -#define QUEUE_DEPTH 254+1 /*1 for Normal disconnect 32 for Q'ing. */ - -#define MAX_MB_CARDS 4 /* Max. no of cards suppoerted on Mother Board */ - -#define MAX_SCSI_TAR 16 -#define MAX_LUN 32 -#define LUN_MASK 0x1f - -#define SG_BUF_CNT 16 /*Number of prefetched elements. */ - -#define SG_ELEMENT_SIZE 8 /*Eight byte per element. */ - -#define RD_HARPOON(ioport) inb((u32)ioport) -#define RDW_HARPOON(ioport) inw((u32)ioport) -#define RD_HARP32(ioport,offset,data) (data = inl((u32)(ioport + offset))) -#define WR_HARPOON(ioport,val) outb((u8) val, (u32)ioport) -#define WRW_HARPOON(ioport,val) outw((u16)val, (u32)ioport) -#define WR_HARP32(ioport,offset,data) outl(data, (u32)(ioport + offset)) - -#define TAR_SYNC_MASK (BIT(7)+BIT(6)) -#define SYNC_TRYING BIT(6) -#define SYNC_SUPPORTED (BIT(7)+BIT(6)) - -#define TAR_WIDE_MASK (BIT(5)+BIT(4)) -#define WIDE_ENABLED BIT(4) -#define WIDE_NEGOCIATED BIT(5) - -#define TAR_TAG_Q_MASK (BIT(3)+BIT(2)) -#define TAG_Q_TRYING BIT(2) -#define TAG_Q_REJECT BIT(3) - -#define TAR_ALLOW_DISC BIT(0) - -#define EE_SYNC_MASK (BIT(0)+BIT(1)) -#define EE_SYNC_5MB BIT(0) -#define EE_SYNC_10MB BIT(1) -#define EE_SYNC_20MB (BIT(0)+BIT(1)) - -#define EE_WIDE_SCSI BIT(7) - -struct sccb_mgr_tar_info { - - struct sccb *TarSelQ_Head; - struct sccb *TarSelQ_Tail; - unsigned char TarLUN_CA; /*Contingent Allgiance */ - unsigned char TarTagQ_Cnt; - unsigned char TarSelQ_Cnt; - unsigned char TarStatus; - unsigned char TarEEValue; - unsigned char TarSyncCtrl; - unsigned char TarReserved[2]; /* for alignment */ - unsigned char LunDiscQ_Idx[MAX_LUN]; - unsigned char TarLUNBusy[MAX_LUN]; -}; - -struct nvram_info { - unsigned char niModel; /* Model No. of card */ - unsigned char niCardNo; /* Card no. */ - unsigned long niBaseAddr; /* Port Address of card */ - unsigned char niSysConf; /* Adapter Configuration byte - Byte 16 of eeprom map */ - unsigned char niScsiConf; /* SCSI Configuration byte - Byte 17 of eeprom map */ - unsigned char niScamConf; /* SCAM Configuration byte - Byte 20 of eeprom map */ - unsigned char niAdapId; /* Host Adapter ID - Byte 24 of eerpom map */ - unsigned char niSyncTbl[MAX_SCSI_TAR / 2]; /* Sync/Wide byte of targets */ - unsigned char niScamTbl[MAX_SCSI_TAR][4]; /* Compressed Scam name string of Targets */ -}; - -#define MODEL_LT 1 -#define MODEL_DL 2 -#define MODEL_LW 3 -#define MODEL_DW 4 - -struct sccb_card { - struct sccb *currentSCCB; - struct sccb_mgr_info *cardInfo; - - unsigned long ioPort; - - unsigned short cmdCounter; - unsigned char discQCount; - unsigned char tagQ_Lst; - unsigned char cardIndex; - unsigned char scanIndex; - unsigned char globalFlags; - unsigned char ourId; - struct nvram_info *pNvRamInfo; - struct sccb *discQ_Tbl[QUEUE_DEPTH]; - -}; - -#define F_TAG_STARTED 0x01 -#define F_CONLUN_IO 0x02 -#define F_DO_RENEGO 0x04 -#define F_NO_FILTER 0x08 -#define F_GREEN_PC 0x10 -#define F_HOST_XFER_ACT 0x20 -#define F_NEW_SCCB_CMD 0x40 -#define F_UPDATE_EEPROM 0x80 - -#define ID_STRING_LENGTH 32 -#define TYPE_CODE0 0x63 /*Level2 Mstr (bits 7-6), */ - -#define SLV_TYPE_CODE0 0xA3 /*Priority Bit set (bits 7-6), */ - -#define ASSIGN_ID 0x00 -#define SET_P_FLAG 0x01 -#define CFG_CMPLT 0x03 -#define DOM_MSTR 0x0F -#define SYNC_PTRN 0x1F - -#define ID_0_7 0x18 -#define ID_8_F 0x11 -#define MISC_CODE 0x14 -#define CLR_P_FLAG 0x18 - -#define INIT_SELTD 0x01 -#define LEVEL2_TAR 0x02 - -enum scam_id_st { ID0, ID1, ID2, ID3, ID4, ID5, ID6, ID7, ID8, ID9, ID10, ID11, - ID12, - ID13, ID14, ID15, ID_UNUSED, ID_UNASSIGNED, ID_ASSIGNED, LEGACY, - CLR_PRIORITY, NO_ID_AVAIL -}; - -typedef struct SCCBscam_info { - - unsigned char id_string[ID_STRING_LENGTH]; - enum scam_id_st state; - -} SCCBSCAM_INFO; - -#define SCSI_REQUEST_SENSE 0x03 -#define SCSI_READ 0x08 -#define SCSI_WRITE 0x0A -#define SCSI_START_STOP_UNIT 0x1B -#define SCSI_READ_EXTENDED 0x28 -#define SCSI_WRITE_EXTENDED 0x2A -#define SCSI_WRITE_AND_VERIFY 0x2E - -#define SSGOOD 0x00 -#define SSCHECK 0x02 -#define SSQ_FULL 0x28 - -#define SMCMD_COMP 0x00 -#define SMEXT 0x01 -#define SMSAVE_DATA_PTR 0x02 -#define SMREST_DATA_PTR 0x03 -#define SMDISC 0x04 -#define SMABORT 0x06 -#define SMREJECT 0x07 -#define SMNO_OP 0x08 -#define SMPARITY 0x09 -#define SMDEV_RESET 0x0C -#define SMABORT_TAG 0x0D -#define SMINIT_RECOVERY 0x0F -#define SMREL_RECOVERY 0x10 - -#define SMIDENT 0x80 -#define DISC_PRIV 0x40 - -#define SMSYNC 0x01 -#define SMWDTR 0x03 -#define SM8BIT 0x00 -#define SM16BIT 0x01 -#define SMIGNORWR 0x23 /* Ignore Wide Residue */ - -#define SIX_BYTE_CMD 0x06 -#define TWELVE_BYTE_CMD 0x0C - -#define ASYNC 0x00 -#define MAX_OFFSET 0x0F /* Maxbyteoffset for Sync Xfers */ - -#define EEPROM_WD_CNT 256 - -#define EEPROM_CHECK_SUM 0 -#define FW_SIGNATURE 2 -#define MODEL_NUMB_0 4 -#define MODEL_NUMB_2 6 -#define MODEL_NUMB_4 8 -#define SYSTEM_CONFIG 16 -#define SCSI_CONFIG 17 -#define BIOS_CONFIG 18 -#define SCAM_CONFIG 20 -#define ADAPTER_SCSI_ID 24 - -#define IGNORE_B_SCAN 32 -#define SEND_START_ENA 34 -#define DEVICE_ENABLE 36 - -#define SYNC_RATE_TBL 38 -#define SYNC_RATE_TBL01 38 -#define SYNC_RATE_TBL23 40 -#define SYNC_RATE_TBL45 42 -#define SYNC_RATE_TBL67 44 -#define SYNC_RATE_TBL89 46 -#define SYNC_RATE_TBLab 48 -#define SYNC_RATE_TBLcd 50 -#define SYNC_RATE_TBLef 52 - -#define EE_SCAMBASE 256 - -#define SCAM_ENABLED BIT(2) -#define SCAM_LEVEL2 BIT(3) - -#define RENEGO_ENA BIT(10) -#define CONNIO_ENA BIT(11) -#define GREEN_PC_ENA BIT(12) - -#define AUTO_RATE_00 00 -#define AUTO_RATE_05 01 -#define AUTO_RATE_10 02 -#define AUTO_RATE_20 03 - -#define WIDE_NEGO_BIT BIT(7) -#define DISC_ENABLE_BIT BIT(6) - -#define hp_vendor_id_0 0x00 /* LSB */ -#define ORION_VEND_0 0x4B - -#define hp_vendor_id_1 0x01 /* MSB */ -#define ORION_VEND_1 0x10 - -#define hp_device_id_0 0x02 /* LSB */ -#define ORION_DEV_0 0x30 - -#define hp_device_id_1 0x03 /* MSB */ -#define ORION_DEV_1 0x81 - - /* Sub Vendor ID and Sub Device ID only available in - Harpoon Version 2 and higher */ - -#define hp_sub_device_id_0 0x06 /* LSB */ - -#define hp_semaphore 0x0C -#define SCCB_MGR_ACTIVE BIT(0) -#define TICKLE_ME BIT(1) -#define SCCB_MGR_PRESENT BIT(3) -#define BIOS_IN_USE BIT(4) - -#define hp_sys_ctrl 0x0F - -#define STOP_CLK BIT(0) /*Turn off BusMaster Clock */ -#define DRVR_RST BIT(1) /*Firmware Reset to 80C15 chip */ -#define HALT_MACH BIT(3) /*Halt State Machine */ -#define HARD_ABORT BIT(4) /*Hard Abort */ - -#define hp_host_blk_cnt 0x13 - -#define XFER_BLK64 0x06 /* 1 1 0 64 byte per block */ - -#define BM_THRESHOLD 0x40 /* PCI mode can only xfer 16 bytes */ - -#define hp_int_mask 0x17 - -#define INT_CMD_COMPL BIT(0) /* DMA command complete */ -#define INT_EXT_STATUS BIT(1) /* Extended Status Set */ - -#define hp_xfer_cnt_lo 0x18 -#define hp_xfer_cnt_hi 0x1A -#define hp_xfer_cmd 0x1B - -#define XFER_HOST_DMA 0x00 /* 0 0 0 Transfer Host -> DMA */ -#define XFER_DMA_HOST 0x01 /* 0 0 1 Transfer DMA -> Host */ - -#define XFER_HOST_AUTO 0x00 /* 0 0 Auto Transfer Size */ - -#define XFER_DMA_8BIT 0x20 /* 0 1 8 BIT Transfer Size */ - -#define DISABLE_INT BIT(7) /*Do not interrupt at end of cmd. */ - -#define HOST_WRT_CMD ((DISABLE_INT + XFER_HOST_DMA + XFER_HOST_AUTO + XFER_DMA_8BIT)) -#define HOST_RD_CMD ((DISABLE_INT + XFER_DMA_HOST + XFER_HOST_AUTO + XFER_DMA_8BIT)) - -#define hp_host_addr_lo 0x1C -#define hp_host_addr_hmi 0x1E - -#define hp_ee_ctrl 0x22 - -#define EXT_ARB_ACK BIT(7) -#define SCSI_TERM_ENA_H BIT(6) /* SCSI high byte terminator */ -#define SEE_MS BIT(5) -#define SEE_CS BIT(3) -#define SEE_CLK BIT(2) -#define SEE_DO BIT(1) -#define SEE_DI BIT(0) - -#define EE_READ 0x06 -#define EE_WRITE 0x05 -#define EWEN 0x04 -#define EWEN_ADDR 0x03C0 -#define EWDS 0x04 -#define EWDS_ADDR 0x0000 - -#define hp_bm_ctrl 0x26 - -#define SCSI_TERM_ENA_L BIT(0) /*Enable/Disable external terminators */ -#define FLUSH_XFER_CNTR BIT(1) /*Flush transfer counter */ -#define FORCE1_XFER BIT(5) /*Always xfer one byte in byte mode */ -#define FAST_SINGLE BIT(6) /*?? */ - -#define BMCTRL_DEFAULT (FORCE1_XFER|FAST_SINGLE|SCSI_TERM_ENA_L) - -#define hp_sg_addr 0x28 -#define hp_page_ctrl 0x29 - -#define SCATTER_EN BIT(0) -#define SGRAM_ARAM BIT(1) -#define G_INT_DISABLE BIT(3) /* Enable/Disable all Interrupts */ -#define NARROW_SCSI_CARD BIT(4) /* NARROW/WIDE SCSI config pin */ - -#define hp_pci_stat_cfg 0x2D - -#define REC_MASTER_ABORT BIT(5) /*received Master abort */ - -#define hp_rev_num 0x33 - -#define hp_stack_data 0x34 -#define hp_stack_addr 0x35 - -#define hp_ext_status 0x36 - -#define BM_FORCE_OFF BIT(0) /*Bus Master is forced to get off */ -#define PCI_TGT_ABORT BIT(0) /*PCI bus master transaction aborted */ -#define PCI_DEV_TMOUT BIT(1) /*PCI Device Time out */ -#define CMD_ABORTED BIT(4) /*Command aborted */ -#define BM_PARITY_ERR BIT(5) /*parity error on data received */ -#define PIO_OVERRUN BIT(6) /*Slave data overrun */ -#define BM_CMD_BUSY BIT(7) /*Bus master transfer command busy */ -#define BAD_EXT_STATUS (BM_FORCE_OFF | PCI_DEV_TMOUT | CMD_ABORTED | \ - BM_PARITY_ERR | PIO_OVERRUN) - -#define hp_int_status 0x37 - -#define EXT_STATUS_ON BIT(1) /*Extended status is valid */ -#define SCSI_INTERRUPT BIT(2) /*Global indication of a SCSI int. */ -#define INT_ASSERTED BIT(5) /* */ - -#define hp_fifo_cnt 0x38 - -#define hp_intena 0x40 - -#define RESET BIT(7) -#define PROG_HLT BIT(6) -#define PARITY BIT(5) -#define FIFO BIT(4) -#define SEL BIT(3) -#define SCAM_SEL BIT(2) -#define RSEL BIT(1) -#define TIMEOUT BIT(0) -#define BUS_FREE BIT(15) -#define XFER_CNT_0 BIT(14) -#define PHASE BIT(13) -#define IUNKWN BIT(12) -#define ICMD_COMP BIT(11) -#define ITICKLE BIT(10) -#define IDO_STRT BIT(9) -#define ITAR_DISC BIT(8) -#define AUTO_INT (BIT(12)+BIT(11)+BIT(10)+BIT(9)+BIT(8)) -#define CLR_ALL_INT 0xFFFF -#define CLR_ALL_INT_1 0xFF00 - -#define hp_intstat 0x42 - -#define hp_scsisig 0x44 - -#define SCSI_SEL BIT(7) -#define SCSI_BSY BIT(6) -#define SCSI_REQ BIT(5) -#define SCSI_ACK BIT(4) -#define SCSI_ATN BIT(3) -#define SCSI_CD BIT(2) -#define SCSI_MSG BIT(1) -#define SCSI_IOBIT BIT(0) - -#define S_SCSI_PHZ (BIT(2)+BIT(1)+BIT(0)) -#define S_MSGO_PH (BIT(2)+BIT(1) ) -#define S_MSGI_PH (BIT(2)+BIT(1)+BIT(0)) -#define S_DATAI_PH ( BIT(0)) -#define S_DATAO_PH 0x00 -#define S_ILL_PH ( BIT(1) ) - -#define hp_scsictrl_0 0x45 - -#define SEL_TAR BIT(6) -#define ENA_ATN BIT(4) -#define ENA_RESEL BIT(2) -#define SCSI_RST BIT(1) -#define ENA_SCAM_SEL BIT(0) - -#define hp_portctrl_0 0x46 - -#define SCSI_PORT BIT(7) -#define SCSI_INBIT BIT(6) -#define DMA_PORT BIT(5) -#define DMA_RD BIT(4) -#define HOST_PORT BIT(3) -#define HOST_WRT BIT(2) -#define SCSI_BUS_EN BIT(1) -#define START_TO BIT(0) - -#define hp_scsireset 0x47 - -#define SCSI_INI BIT(6) -#define SCAM_EN BIT(5) -#define DMA_RESET BIT(3) -#define HPSCSI_RESET BIT(2) -#define PROG_RESET BIT(1) -#define FIFO_CLR BIT(0) - -#define hp_xfercnt_0 0x48 -#define hp_xfercnt_2 0x4A - -#define hp_fifodata_0 0x4C -#define hp_addstat 0x4E - -#define SCAM_TIMER BIT(7) -#define SCSI_MODE8 BIT(3) -#define SCSI_PAR_ERR BIT(0) - -#define hp_prgmcnt_0 0x4F - -#define hp_selfid_0 0x50 -#define hp_selfid_1 0x51 -#define hp_arb_id 0x52 - -#define hp_select_id 0x53 - -#define hp_synctarg_base 0x54 -#define hp_synctarg_12 0x54 -#define hp_synctarg_13 0x55 -#define hp_synctarg_14 0x56 -#define hp_synctarg_15 0x57 - -#define hp_synctarg_8 0x58 -#define hp_synctarg_9 0x59 -#define hp_synctarg_10 0x5A -#define hp_synctarg_11 0x5B - -#define hp_synctarg_4 0x5C -#define hp_synctarg_5 0x5D -#define hp_synctarg_6 0x5E -#define hp_synctarg_7 0x5F - -#define hp_synctarg_0 0x60 -#define hp_synctarg_1 0x61 -#define hp_synctarg_2 0x62 -#define hp_synctarg_3 0x63 - -#define NARROW_SCSI BIT(4) -#define DEFAULT_OFFSET 0x0F - -#define hp_autostart_0 0x64 -#define hp_autostart_1 0x65 -#define hp_autostart_3 0x67 - -#define AUTO_IMMED BIT(5) -#define SELECT BIT(6) -#define END_DATA (BIT(7)+BIT(6)) - -#define hp_gp_reg_0 0x68 -#define hp_gp_reg_1 0x69 -#define hp_gp_reg_3 0x6B - -#define hp_seltimeout 0x6C - -#define TO_4ms 0x67 /* 3.9959ms */ - -#define TO_5ms 0x03 /* 4.9152ms */ -#define TO_10ms 0x07 /* 11.xxxms */ -#define TO_250ms 0x99 /* 250.68ms */ -#define TO_290ms 0xB1 /* 289.99ms */ - -#define hp_clkctrl_0 0x6D - -#define PWR_DWN BIT(6) -#define ACTdeassert BIT(4) -#define CLK_40MHZ (BIT(1) + BIT(0)) - -#define CLKCTRL_DEFAULT (ACTdeassert | CLK_40MHZ) - -#define hp_fiforead 0x6E -#define hp_fifowrite 0x6F - -#define hp_offsetctr 0x70 -#define hp_xferstat 0x71 - -#define FIFO_EMPTY BIT(6) - -#define hp_portctrl_1 0x72 - -#define CHK_SCSI_P BIT(3) -#define HOST_MODE8 BIT(0) - -#define hp_xfer_pad 0x73 - -#define ID_UNLOCK BIT(3) - -#define hp_scsidata_0 0x74 -#define hp_scsidata_1 0x75 - -#define hp_aramBase 0x80 -#define BIOS_DATA_OFFSET 0x60 -#define BIOS_RELATIVE_CARD 0x64 - -#define AR3 (BIT(9) + BIT(8)) -#define SDATA BIT(10) - -#define CRD_OP BIT(11) /* Cmp Reg. w/ Data */ - -#define CRR_OP BIT(12) /* Cmp Reg. w. Reg. */ - -#define CPE_OP (BIT(14)+BIT(11)) /* Cmp SCSI phs & Branch EQ */ - -#define CPN_OP (BIT(14)+BIT(12)) /* Cmp SCSI phs & Branch NOT EQ */ - -#define ADATA_OUT 0x00 -#define ADATA_IN BIT(8) -#define ACOMMAND BIT(10) -#define ASTATUS (BIT(10)+BIT(8)) -#define AMSG_OUT (BIT(10)+BIT(9)) -#define AMSG_IN (BIT(10)+BIT(9)+BIT(8)) - -#define BRH_OP BIT(13) /* Branch */ - -#define ALWAYS 0x00 -#define EQUAL BIT(8) -#define NOT_EQ BIT(9) - -#define TCB_OP (BIT(13)+BIT(11)) /* Test condition & branch */ - -#define FIFO_0 BIT(10) - -#define MPM_OP BIT(15) /* Match phase and move data */ - -#define MRR_OP BIT(14) /* Move DReg. to Reg. */ - -#define S_IDREG (BIT(2)+BIT(1)+BIT(0)) - -#define D_AR0 0x00 -#define D_AR1 BIT(0) -#define D_BUCKET (BIT(2) + BIT(1) + BIT(0)) - -#define RAT_OP (BIT(14)+BIT(13)+BIT(11)) - -#define SSI_OP (BIT(15)+BIT(11)) - -#define SSI_ITAR_DISC (ITAR_DISC >> 8) -#define SSI_IDO_STRT (IDO_STRT >> 8) - -#define SSI_ICMD_COMP (ICMD_COMP >> 8) -#define SSI_ITICKLE (ITICKLE >> 8) - -#define SSI_IUNKWN (IUNKWN >> 8) -#define SSI_INO_CC (IUNKWN >> 8) -#define SSI_IRFAIL (IUNKWN >> 8) - -#define NP 0x10 /*Next Phase */ -#define NTCMD 0x02 /*Non- Tagged Command start */ -#define CMDPZ 0x04 /*Command phase */ -#define DINT 0x12 /*Data Out/In interrupt */ -#define DI 0x13 /*Data Out */ -#define DC 0x19 /*Disconnect Message */ -#define ST 0x1D /*Status Phase */ -#define UNKNWN 0x24 /*Unknown bus action */ -#define CC 0x25 /*Command Completion failure */ -#define TICK 0x26 /*New target reselected us. */ -#define SELCHK 0x28 /*Select & Check SCSI ID latch reg */ - -#define ID_MSG_STRT hp_aramBase + 0x00 -#define NON_TAG_ID_MSG hp_aramBase + 0x06 -#define CMD_STRT hp_aramBase + 0x08 -#define SYNC_MSGS hp_aramBase + 0x08 - -#define TAG_STRT 0x00 -#define DISCONNECT_START 0x10/2 -#define END_DATA_START 0x14/2 -#define CMD_ONLY_STRT CMDPZ/2 -#define SELCHK_STRT SELCHK/2 - -#define GET_XFER_CNT(port, xfercnt) {RD_HARP32(port,hp_xfercnt_0,xfercnt); xfercnt &= 0xFFFFFF;} -/* #define GET_XFER_CNT(port, xfercnt) (xfercnt = RD_HARPOON(port+hp_xfercnt_2), \ - xfercnt <<= 16,\ - xfercnt |= RDW_HARPOON((unsigned short)(port+hp_xfercnt_0))) - */ -#define HP_SETUP_ADDR_CNT(port,addr,count) (WRW_HARPOON((port+hp_host_addr_lo), (unsigned short)(addr & 0x0000FFFFL)),\ - addr >>= 16,\ - WRW_HARPOON((port+hp_host_addr_hmi), (unsigned short)(addr & 0x0000FFFFL)),\ - WR_HARP32(port,hp_xfercnt_0,count),\ - WRW_HARPOON((port+hp_xfer_cnt_lo), (unsigned short)(count & 0x0000FFFFL)),\ - count >>= 16,\ - WR_HARPOON(port+hp_xfer_cnt_hi, (count & 0xFF))) - -#define ACCEPT_MSG(port) {while(RD_HARPOON(port+hp_scsisig) & SCSI_REQ){}\ - WR_HARPOON(port+hp_scsisig, S_ILL_PH);} - -#define ACCEPT_MSG_ATN(port) {while(RD_HARPOON(port+hp_scsisig) & SCSI_REQ){}\ - WR_HARPOON(port+hp_scsisig, (S_ILL_PH|SCSI_ATN));} - -#define DISABLE_AUTO(port) (WR_HARPOON(port+hp_scsireset, PROG_RESET),\ - WR_HARPOON(port+hp_scsireset, 0x00)) - -#define ARAM_ACCESS(p_port) (WR_HARPOON(p_port+hp_page_ctrl, \ - (RD_HARPOON(p_port+hp_page_ctrl) | SGRAM_ARAM))) - -#define SGRAM_ACCESS(p_port) (WR_HARPOON(p_port+hp_page_ctrl, \ - (RD_HARPOON(p_port+hp_page_ctrl) & ~SGRAM_ARAM))) - -#define MDISABLE_INT(p_port) (WR_HARPOON(p_port+hp_page_ctrl, \ - (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE))) - -#define MENABLE_INT(p_port) (WR_HARPOON(p_port+hp_page_ctrl, \ - (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE))) - -static unsigned char FPT_sisyncn(unsigned long port, unsigned char p_card, - unsigned char syncFlag); -static void FPT_ssel(unsigned long port, unsigned char p_card); -static void FPT_sres(unsigned long port, unsigned char p_card, - struct sccb_card *pCurrCard); -static void FPT_shandem(unsigned long port, unsigned char p_card, - struct sccb *pCurrSCCB); -static void FPT_stsyncn(unsigned long port, unsigned char p_card); -static void FPT_sisyncr(unsigned long port, unsigned char sync_pulse, - unsigned char offset); -static void FPT_sssyncv(unsigned long p_port, unsigned char p_id, - unsigned char p_sync_value, - struct sccb_mgr_tar_info *currTar_Info); -static void FPT_sresb(unsigned long port, unsigned char p_card); -static void FPT_sxfrp(unsigned long p_port, unsigned char p_card); -static void FPT_schkdd(unsigned long port, unsigned char p_card); -static unsigned char FPT_RdStack(unsigned long port, unsigned char index); -static void FPT_WrStack(unsigned long portBase, unsigned char index, - unsigned char data); -static unsigned char FPT_ChkIfChipInitialized(unsigned long ioPort); - -static void FPT_SendMsg(unsigned long port, unsigned char message); -static void FPT_queueFlushTargSccb(unsigned char p_card, unsigned char thisTarg, - unsigned char error_code); - -static void FPT_sinits(struct sccb *p_sccb, unsigned char p_card); -static void FPT_RNVRamData(struct nvram_info *pNvRamInfo); - -static unsigned char FPT_siwidn(unsigned long port, unsigned char p_card); -static void FPT_stwidn(unsigned long port, unsigned char p_card); -static void FPT_siwidr(unsigned long port, unsigned char width); - -static void FPT_queueSelectFail(struct sccb_card *pCurrCard, - unsigned char p_card); -static void FPT_queueDisconnect(struct sccb *p_SCCB, unsigned char p_card); -static void FPT_queueCmdComplete(struct sccb_card *pCurrCard, - struct sccb *p_SCCB, unsigned char p_card); -static void FPT_queueSearchSelect(struct sccb_card *pCurrCard, - unsigned char p_card); -static void FPT_queueFlushSccb(unsigned char p_card, unsigned char error_code); -static void FPT_queueAddSccb(struct sccb *p_SCCB, unsigned char card); -static unsigned char FPT_queueFindSccb(struct sccb *p_SCCB, - unsigned char p_card); -static void FPT_utilUpdateResidual(struct sccb *p_SCCB); -static unsigned short FPT_CalcCrc16(unsigned char buffer[]); -static unsigned char FPT_CalcLrc(unsigned char buffer[]); - -static void FPT_Wait1Second(unsigned long p_port); -static void FPT_Wait(unsigned long p_port, unsigned char p_delay); -static void FPT_utilEEWriteOnOff(unsigned long p_port, unsigned char p_mode); -static void FPT_utilEEWrite(unsigned long p_port, unsigned short ee_data, - unsigned short ee_addr); -static unsigned short FPT_utilEERead(unsigned long p_port, - unsigned short ee_addr); -static unsigned short FPT_utilEEReadOrg(unsigned long p_port, - unsigned short ee_addr); -static void FPT_utilEESendCmdAddr(unsigned long p_port, unsigned char ee_cmd, - unsigned short ee_addr); - -static void FPT_phaseDataOut(unsigned long port, unsigned char p_card); -static void FPT_phaseDataIn(unsigned long port, unsigned char p_card); -static void FPT_phaseCommand(unsigned long port, unsigned char p_card); -static void FPT_phaseStatus(unsigned long port, unsigned char p_card); -static void FPT_phaseMsgOut(unsigned long port, unsigned char p_card); -static void FPT_phaseMsgIn(unsigned long port, unsigned char p_card); -static void FPT_phaseIllegal(unsigned long port, unsigned char p_card); - -static void FPT_phaseDecode(unsigned long port, unsigned char p_card); -static void FPT_phaseChkFifo(unsigned long port, unsigned char p_card); -static void FPT_phaseBusFree(unsigned long p_port, unsigned char p_card); - -static void FPT_XbowInit(unsigned long port, unsigned char scamFlg); -static void FPT_BusMasterInit(unsigned long p_port); -static void FPT_DiagEEPROM(unsigned long p_port); - -static void FPT_dataXferProcessor(unsigned long port, - struct sccb_card *pCurrCard); -static void FPT_busMstrSGDataXferStart(unsigned long port, - struct sccb *pCurrSCCB); -static void FPT_busMstrDataXferStart(unsigned long port, - struct sccb *pCurrSCCB); -static void FPT_hostDataXferAbort(unsigned long port, unsigned char p_card, - struct sccb *pCurrSCCB); -static void FPT_hostDataXferRestart(struct sccb *currSCCB); - -static unsigned char FPT_SccbMgr_bad_isr(unsigned long p_port, - unsigned char p_card, - struct sccb_card *pCurrCard, - unsigned short p_int); - -static void FPT_SccbMgrTableInitAll(void); -static void FPT_SccbMgrTableInitCard(struct sccb_card *pCurrCard, - unsigned char p_card); -static void FPT_SccbMgrTableInitTarget(unsigned char p_card, - unsigned char target); - -static void FPT_scini(unsigned char p_card, unsigned char p_our_id, - unsigned char p_power_up); - -static int FPT_scarb(unsigned long p_port, unsigned char p_sel_type); -static void FPT_scbusf(unsigned long p_port); -static void FPT_scsel(unsigned long p_port); -static void FPT_scasid(unsigned char p_card, unsigned long p_port); -static unsigned char FPT_scxferc(unsigned long p_port, unsigned char p_data); -static unsigned char FPT_scsendi(unsigned long p_port, - unsigned char p_id_string[]); -static unsigned char FPT_sciso(unsigned long p_port, - unsigned char p_id_string[]); -static void FPT_scwirod(unsigned long p_port, unsigned char p_data_bit); -static void FPT_scwiros(unsigned long p_port, unsigned char p_data_bit); -static unsigned char FPT_scvalq(unsigned char p_quintet); -static unsigned char FPT_scsell(unsigned long p_port, unsigned char targ_id); -static void FPT_scwtsel(unsigned long p_port); -static void FPT_inisci(unsigned char p_card, unsigned long p_port, - unsigned char p_our_id); -static void FPT_scsavdi(unsigned char p_card, unsigned long p_port); -static unsigned char FPT_scmachid(unsigned char p_card, - unsigned char p_id_string[]); - -static void FPT_autoCmdCmplt(unsigned long p_port, unsigned char p_card); -static void FPT_autoLoadDefaultMap(unsigned long p_port); - -static struct sccb_mgr_tar_info FPT_sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = - { {{0}} }; -static struct sccb_card FPT_BL_Card[MAX_CARDS] = { {0} }; -static SCCBSCAM_INFO FPT_scamInfo[MAX_SCSI_TAR] = { {{0}} }; -static struct nvram_info FPT_nvRamInfo[MAX_MB_CARDS] = { {0} }; - -static unsigned char FPT_mbCards = 0; -static unsigned char FPT_scamHAString[] = - { 0x63, 0x07, 'B', 'U', 'S', 'L', 'O', 'G', 'I', 'C', - ' ', 'B', 'T', '-', '9', '3', '0', - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 -}; - -static unsigned short FPT_default_intena = 0; - -static void (*FPT_s_PhaseTbl[8]) (unsigned long, unsigned char) = { -0}; - -/*--------------------------------------------------------------------- - * - * Function: FlashPoint_ProbeHostAdapter - * - * Description: Setup and/or Search for cards and return info to caller. - * - *---------------------------------------------------------------------*/ - -static int FlashPoint_ProbeHostAdapter(struct sccb_mgr_info *pCardInfo) -{ - static unsigned char first_time = 1; - - unsigned char i, j, id, ScamFlg; - unsigned short temp, temp2, temp3, temp4, temp5, temp6; - unsigned long ioport; - struct nvram_info *pCurrNvRam; - - ioport = pCardInfo->si_baseaddr; - - if (RD_HARPOON(ioport + hp_vendor_id_0) != ORION_VEND_0) - return (int)FAILURE; - - if ((RD_HARPOON(ioport + hp_vendor_id_1) != ORION_VEND_1)) - return (int)FAILURE; - - if ((RD_HARPOON(ioport + hp_device_id_0) != ORION_DEV_0)) - return (int)FAILURE; - - if ((RD_HARPOON(ioport + hp_device_id_1) != ORION_DEV_1)) - return (int)FAILURE; - - if (RD_HARPOON(ioport + hp_rev_num) != 0x0f) { - -/* For new Harpoon then check for sub_device ID LSB - the bits(0-3) must be all ZERO for compatible with - current version of SCCBMgr, else skip this Harpoon - device. */ - - if (RD_HARPOON(ioport + hp_sub_device_id_0) & 0x0f) - return (int)FAILURE; - } - - if (first_time) { - FPT_SccbMgrTableInitAll(); - first_time = 0; - FPT_mbCards = 0; - } - - if (FPT_RdStack(ioport, 0) != 0x00) { - if (FPT_ChkIfChipInitialized(ioport) == 0) { - pCurrNvRam = NULL; - WR_HARPOON(ioport + hp_semaphore, 0x00); - FPT_XbowInit(ioport, 0); /*Must Init the SCSI before attempting */ - FPT_DiagEEPROM(ioport); - } else { - if (FPT_mbCards < MAX_MB_CARDS) { - pCurrNvRam = &FPT_nvRamInfo[FPT_mbCards]; - FPT_mbCards++; - pCurrNvRam->niBaseAddr = ioport; - FPT_RNVRamData(pCurrNvRam); - } else - return (int)FAILURE; - } - } else - pCurrNvRam = NULL; - - WR_HARPOON(ioport + hp_clkctrl_0, CLKCTRL_DEFAULT); - WR_HARPOON(ioport + hp_sys_ctrl, 0x00); - - if (pCurrNvRam) - pCardInfo->si_id = pCurrNvRam->niAdapId; - else - pCardInfo->si_id = - (unsigned - char)(FPT_utilEERead(ioport, - (ADAPTER_SCSI_ID / - 2)) & (unsigned char)0x0FF); - - pCardInfo->si_lun = 0x00; - pCardInfo->si_fw_revision = ORION_FW_REV; - temp2 = 0x0000; - temp3 = 0x0000; - temp4 = 0x0000; - temp5 = 0x0000; - temp6 = 0x0000; - - for (id = 0; id < (16 / 2); id++) { - - if (pCurrNvRam) { - temp = (unsigned short)pCurrNvRam->niSyncTbl[id]; - temp = ((temp & 0x03) + ((temp << 4) & 0xc0)) + - (((temp << 4) & 0x0300) + ((temp << 8) & 0xc000)); - } else - temp = - FPT_utilEERead(ioport, - (unsigned short)((SYNC_RATE_TBL / 2) - + id)); - - for (i = 0; i < 2; temp >>= 8, i++) { - - temp2 >>= 1; - temp3 >>= 1; - temp4 >>= 1; - temp5 >>= 1; - temp6 >>= 1; - switch (temp & 0x3) { - case AUTO_RATE_20: /* Synchronous, 20 mega-transfers/second */ - temp6 |= 0x8000; /* Fall through */ - case AUTO_RATE_10: /* Synchronous, 10 mega-transfers/second */ - temp5 |= 0x8000; /* Fall through */ - case AUTO_RATE_05: /* Synchronous, 5 mega-transfers/second */ - temp2 |= 0x8000; /* Fall through */ - case AUTO_RATE_00: /* Asynchronous */ - break; - } - - if (temp & DISC_ENABLE_BIT) - temp3 |= 0x8000; - - if (temp & WIDE_NEGO_BIT) - temp4 |= 0x8000; - - } - } - - pCardInfo->si_per_targ_init_sync = temp2; - pCardInfo->si_per_targ_no_disc = temp3; - pCardInfo->si_per_targ_wide_nego = temp4; - pCardInfo->si_per_targ_fast_nego = temp5; - pCardInfo->si_per_targ_ultra_nego = temp6; - - if (pCurrNvRam) - i = pCurrNvRam->niSysConf; - else - i = (unsigned - char)(FPT_utilEERead(ioport, (SYSTEM_CONFIG / 2))); - - if (pCurrNvRam) - ScamFlg = pCurrNvRam->niScamConf; - else - ScamFlg = - (unsigned char)FPT_utilEERead(ioport, SCAM_CONFIG / 2); - - pCardInfo->si_flags = 0x0000; - - if (i & 0x01) - pCardInfo->si_flags |= SCSI_PARITY_ENA; - - if (!(i & 0x02)) - pCardInfo->si_flags |= SOFT_RESET; - - if (i & 0x10) - pCardInfo->si_flags |= EXTENDED_TRANSLATION; - - if (ScamFlg & SCAM_ENABLED) - pCardInfo->si_flags |= FLAG_SCAM_ENABLED; - - if (ScamFlg & SCAM_LEVEL2) - pCardInfo->si_flags |= FLAG_SCAM_LEVEL2; - - j = (RD_HARPOON(ioport + hp_bm_ctrl) & ~SCSI_TERM_ENA_L); - if (i & 0x04) { - j |= SCSI_TERM_ENA_L; - } - WR_HARPOON(ioport + hp_bm_ctrl, j); - - j = (RD_HARPOON(ioport + hp_ee_ctrl) & ~SCSI_TERM_ENA_H); - if (i & 0x08) { - j |= SCSI_TERM_ENA_H; - } - WR_HARPOON(ioport + hp_ee_ctrl, j); - - if (!(RD_HARPOON(ioport + hp_page_ctrl) & NARROW_SCSI_CARD)) - - pCardInfo->si_flags |= SUPPORT_16TAR_32LUN; - - pCardInfo->si_card_family = HARPOON_FAMILY; - pCardInfo->si_bustype = BUSTYPE_PCI; - - if (pCurrNvRam) { - pCardInfo->si_card_model[0] = '9'; - switch (pCurrNvRam->niModel & 0x0f) { - case MODEL_LT: - pCardInfo->si_card_model[1] = '3'; - pCardInfo->si_card_model[2] = '0'; - break; - case MODEL_LW: - pCardInfo->si_card_model[1] = '5'; - pCardInfo->si_card_model[2] = '0'; - break; - case MODEL_DL: - pCardInfo->si_card_model[1] = '3'; - pCardInfo->si_card_model[2] = '2'; - break; - case MODEL_DW: - pCardInfo->si_card_model[1] = '5'; - pCardInfo->si_card_model[2] = '2'; - break; - } - } else { - temp = FPT_utilEERead(ioport, (MODEL_NUMB_0 / 2)); - pCardInfo->si_card_model[0] = (unsigned char)(temp >> 8); - temp = FPT_utilEERead(ioport, (MODEL_NUMB_2 / 2)); - - pCardInfo->si_card_model[1] = (unsigned char)(temp & 0x00FF); - pCardInfo->si_card_model[2] = (unsigned char)(temp >> 8); - } - - if (pCardInfo->si_card_model[1] == '3') { - if (RD_HARPOON(ioport + hp_ee_ctrl) & BIT(7)) - pCardInfo->si_flags |= LOW_BYTE_TERM; - } else if (pCardInfo->si_card_model[2] == '0') { - temp = RD_HARPOON(ioport + hp_xfer_pad); - WR_HARPOON(ioport + hp_xfer_pad, (temp & ~BIT(4))); - if (RD_HARPOON(ioport + hp_ee_ctrl) & BIT(7)) - pCardInfo->si_flags |= LOW_BYTE_TERM; - WR_HARPOON(ioport + hp_xfer_pad, (temp | BIT(4))); - if (RD_HARPOON(ioport + hp_ee_ctrl) & BIT(7)) - pCardInfo->si_flags |= HIGH_BYTE_TERM; - WR_HARPOON(ioport + hp_xfer_pad, temp); - } else { - temp = RD_HARPOON(ioport + hp_ee_ctrl); - temp2 = RD_HARPOON(ioport + hp_xfer_pad); - WR_HARPOON(ioport + hp_ee_ctrl, (temp | SEE_CS)); - WR_HARPOON(ioport + hp_xfer_pad, (temp2 | BIT(4))); - temp3 = 0; - for (i = 0; i < 8; i++) { - temp3 <<= 1; - if (!(RD_HARPOON(ioport + hp_ee_ctrl) & BIT(7))) - temp3 |= 1; - WR_HARPOON(ioport + hp_xfer_pad, (temp2 & ~BIT(4))); - WR_HARPOON(ioport + hp_xfer_pad, (temp2 | BIT(4))); - } - WR_HARPOON(ioport + hp_ee_ctrl, temp); - WR_HARPOON(ioport + hp_xfer_pad, temp2); - if (!(temp3 & BIT(7))) - pCardInfo->si_flags |= LOW_BYTE_TERM; - if (!(temp3 & BIT(6))) - pCardInfo->si_flags |= HIGH_BYTE_TERM; - } - - ARAM_ACCESS(ioport); - - for (i = 0; i < 4; i++) { - - pCardInfo->si_XlatInfo[i] = - RD_HARPOON(ioport + hp_aramBase + BIOS_DATA_OFFSET + i); - } - - /* return with -1 if no sort, else return with - logical card number sorted by BIOS (zero-based) */ - - pCardInfo->si_relative_cardnum = - (unsigned - char)(RD_HARPOON(ioport + hp_aramBase + BIOS_RELATIVE_CARD) - 1); - - SGRAM_ACCESS(ioport); - - FPT_s_PhaseTbl[0] = FPT_phaseDataOut; - FPT_s_PhaseTbl[1] = FPT_phaseDataIn; - FPT_s_PhaseTbl[2] = FPT_phaseIllegal; - FPT_s_PhaseTbl[3] = FPT_phaseIllegal; - FPT_s_PhaseTbl[4] = FPT_phaseCommand; - FPT_s_PhaseTbl[5] = FPT_phaseStatus; - FPT_s_PhaseTbl[6] = FPT_phaseMsgOut; - FPT_s_PhaseTbl[7] = FPT_phaseMsgIn; - - pCardInfo->si_present = 0x01; - - return 0; -} - -/*--------------------------------------------------------------------- - * - * Function: FlashPoint_HardwareResetHostAdapter - * - * Description: Setup adapter for normal operation (hard reset). - * - *---------------------------------------------------------------------*/ - -static unsigned long FlashPoint_HardwareResetHostAdapter(struct sccb_mgr_info - *pCardInfo) -{ - struct sccb_card *CurrCard = NULL; - struct nvram_info *pCurrNvRam; - unsigned char i, j, thisCard, ScamFlg; - unsigned short temp, sync_bit_map, id; - unsigned long ioport; - - ioport = pCardInfo->si_baseaddr; - - for (thisCard = 0; thisCard <= MAX_CARDS; thisCard++) { - - if (thisCard == MAX_CARDS) { - - return FAILURE; - } - - if (FPT_BL_Card[thisCard].ioPort == ioport) { - - CurrCard = &FPT_BL_Card[thisCard]; - FPT_SccbMgrTableInitCard(CurrCard, thisCard); - break; - } - - else if (FPT_BL_Card[thisCard].ioPort == 0x00) { - - FPT_BL_Card[thisCard].ioPort = ioport; - CurrCard = &FPT_BL_Card[thisCard]; - - if (FPT_mbCards) - for (i = 0; i < FPT_mbCards; i++) { - if (CurrCard->ioPort == - FPT_nvRamInfo[i].niBaseAddr) - CurrCard->pNvRamInfo = - &FPT_nvRamInfo[i]; - } - FPT_SccbMgrTableInitCard(CurrCard, thisCard); - CurrCard->cardIndex = thisCard; - CurrCard->cardInfo = pCardInfo; - - break; - } - } - - pCurrNvRam = CurrCard->pNvRamInfo; - - if (pCurrNvRam) { - ScamFlg = pCurrNvRam->niScamConf; - } else { - ScamFlg = - (unsigned char)FPT_utilEERead(ioport, SCAM_CONFIG / 2); - } - - FPT_BusMasterInit(ioport); - FPT_XbowInit(ioport, ScamFlg); - - FPT_autoLoadDefaultMap(ioport); - - for (i = 0, id = 0x01; i != pCardInfo->si_id; i++, id <<= 1) { - } - - WR_HARPOON(ioport + hp_selfid_0, id); - WR_HARPOON(ioport + hp_selfid_1, 0x00); - WR_HARPOON(ioport + hp_arb_id, pCardInfo->si_id); - CurrCard->ourId = pCardInfo->si_id; - - i = (unsigned char)pCardInfo->si_flags; - if (i & SCSI_PARITY_ENA) - WR_HARPOON(ioport + hp_portctrl_1, (HOST_MODE8 | CHK_SCSI_P)); - - j = (RD_HARPOON(ioport + hp_bm_ctrl) & ~SCSI_TERM_ENA_L); - if (i & LOW_BYTE_TERM) - j |= SCSI_TERM_ENA_L; - WR_HARPOON(ioport + hp_bm_ctrl, j); - - j = (RD_HARPOON(ioport + hp_ee_ctrl) & ~SCSI_TERM_ENA_H); - if (i & HIGH_BYTE_TERM) - j |= SCSI_TERM_ENA_H; - WR_HARPOON(ioport + hp_ee_ctrl, j); - - if (!(pCardInfo->si_flags & SOFT_RESET)) { - - FPT_sresb(ioport, thisCard); - - FPT_scini(thisCard, pCardInfo->si_id, 0); - } - - if (pCardInfo->si_flags & POST_ALL_UNDERRRUNS) - CurrCard->globalFlags |= F_NO_FILTER; - - if (pCurrNvRam) { - if (pCurrNvRam->niSysConf & 0x10) - CurrCard->globalFlags |= F_GREEN_PC; - } else { - if (FPT_utilEERead(ioport, (SYSTEM_CONFIG / 2)) & GREEN_PC_ENA) - CurrCard->globalFlags |= F_GREEN_PC; - } - - /* Set global flag to indicate Re-Negotiation to be done on all - ckeck condition */ - if (pCurrNvRam) { - if (pCurrNvRam->niScsiConf & 0x04) - CurrCard->globalFlags |= F_DO_RENEGO; - } else { - if (FPT_utilEERead(ioport, (SCSI_CONFIG / 2)) & RENEGO_ENA) - CurrCard->globalFlags |= F_DO_RENEGO; - } - - if (pCurrNvRam) { - if (pCurrNvRam->niScsiConf & 0x08) - CurrCard->globalFlags |= F_CONLUN_IO; - } else { - if (FPT_utilEERead(ioport, (SCSI_CONFIG / 2)) & CONNIO_ENA) - CurrCard->globalFlags |= F_CONLUN_IO; - } - - temp = pCardInfo->si_per_targ_no_disc; - - for (i = 0, id = 1; i < MAX_SCSI_TAR; i++, id <<= 1) { - - if (temp & id) - FPT_sccbMgrTbl[thisCard][i].TarStatus |= TAR_ALLOW_DISC; - } - - sync_bit_map = 0x0001; - - for (id = 0; id < (MAX_SCSI_TAR / 2); id++) { - - if (pCurrNvRam) { - temp = (unsigned short)pCurrNvRam->niSyncTbl[id]; - temp = ((temp & 0x03) + ((temp << 4) & 0xc0)) + - (((temp << 4) & 0x0300) + ((temp << 8) & 0xc000)); - } else - temp = - FPT_utilEERead(ioport, - (unsigned short)((SYNC_RATE_TBL / 2) - + id)); - - for (i = 0; i < 2; temp >>= 8, i++) { - - if (pCardInfo->si_per_targ_init_sync & sync_bit_map) { - - FPT_sccbMgrTbl[thisCard][id * 2 + - i].TarEEValue = - (unsigned char)temp; - } - - else { - FPT_sccbMgrTbl[thisCard][id * 2 + - i].TarStatus |= - SYNC_SUPPORTED; - FPT_sccbMgrTbl[thisCard][id * 2 + - i].TarEEValue = - (unsigned char)(temp & ~EE_SYNC_MASK); - } - -/* if ((pCardInfo->si_per_targ_wide_nego & sync_bit_map) || - (id*2+i >= 8)){ -*/ - if (pCardInfo->si_per_targ_wide_nego & sync_bit_map) { - - FPT_sccbMgrTbl[thisCard][id * 2 + - i].TarEEValue |= - EE_WIDE_SCSI; - - } - - else { /* NARROW SCSI */ - FPT_sccbMgrTbl[thisCard][id * 2 + - i].TarStatus |= - WIDE_NEGOCIATED; - } - - sync_bit_map <<= 1; - - } - } - - WR_HARPOON((ioport + hp_semaphore), - (unsigned char)(RD_HARPOON((ioport + hp_semaphore)) | - SCCB_MGR_PRESENT)); - - return (unsigned long)CurrCard; -} - -static void FlashPoint_ReleaseHostAdapter(unsigned long pCurrCard) -{ - unsigned char i; - unsigned long portBase; - unsigned long regOffset; - unsigned long scamData; - unsigned long *pScamTbl; - struct nvram_info *pCurrNvRam; - - pCurrNvRam = ((struct sccb_card *)pCurrCard)->pNvRamInfo; - - if (pCurrNvRam) { - FPT_WrStack(pCurrNvRam->niBaseAddr, 0, pCurrNvRam->niModel); - FPT_WrStack(pCurrNvRam->niBaseAddr, 1, pCurrNvRam->niSysConf); - FPT_WrStack(pCurrNvRam->niBaseAddr, 2, pCurrNvRam->niScsiConf); - FPT_WrStack(pCurrNvRam->niBaseAddr, 3, pCurrNvRam->niScamConf); - FPT_WrStack(pCurrNvRam->niBaseAddr, 4, pCurrNvRam->niAdapId); - - for (i = 0; i < MAX_SCSI_TAR / 2; i++) - FPT_WrStack(pCurrNvRam->niBaseAddr, - (unsigned char)(i + 5), - pCurrNvRam->niSyncTbl[i]); - - portBase = pCurrNvRam->niBaseAddr; - - for (i = 0; i < MAX_SCSI_TAR; i++) { - regOffset = hp_aramBase + 64 + i * 4; - pScamTbl = (unsigned long *)&pCurrNvRam->niScamTbl[i]; - scamData = *pScamTbl; - WR_HARP32(portBase, regOffset, scamData); - } - - } else { - FPT_WrStack(((struct sccb_card *)pCurrCard)->ioPort, 0, 0); - } -} - -static void FPT_RNVRamData(struct nvram_info *pNvRamInfo) -{ - unsigned char i; - unsigned long portBase; - unsigned long regOffset; - unsigned long scamData; - unsigned long *pScamTbl; - - pNvRamInfo->niModel = FPT_RdStack(pNvRamInfo->niBaseAddr, 0); - pNvRamInfo->niSysConf = FPT_RdStack(pNvRamInfo->niBaseAddr, 1); - pNvRamInfo->niScsiConf = FPT_RdStack(pNvRamInfo->niBaseAddr, 2); - pNvRamInfo->niScamConf = FPT_RdStack(pNvRamInfo->niBaseAddr, 3); - pNvRamInfo->niAdapId = FPT_RdStack(pNvRamInfo->niBaseAddr, 4); - - for (i = 0; i < MAX_SCSI_TAR / 2; i++) - pNvRamInfo->niSyncTbl[i] = - FPT_RdStack(pNvRamInfo->niBaseAddr, (unsigned char)(i + 5)); - - portBase = pNvRamInfo->niBaseAddr; - - for (i = 0; i < MAX_SCSI_TAR; i++) { - regOffset = hp_aramBase + 64 + i * 4; - RD_HARP32(portBase, regOffset, scamData); - pScamTbl = (unsigned long *)&pNvRamInfo->niScamTbl[i]; - *pScamTbl = scamData; - } - -} - -static unsigned char FPT_RdStack(unsigned long portBase, unsigned char index) -{ - WR_HARPOON(portBase + hp_stack_addr, index); - return RD_HARPOON(portBase + hp_stack_data); -} - -static void FPT_WrStack(unsigned long portBase, unsigned char index, - unsigned char data) -{ - WR_HARPOON(portBase + hp_stack_addr, index); - WR_HARPOON(portBase + hp_stack_data, data); -} - -static unsigned char FPT_ChkIfChipInitialized(unsigned long ioPort) -{ - if ((RD_HARPOON(ioPort + hp_arb_id) & 0x0f) != FPT_RdStack(ioPort, 4)) - return 0; - if ((RD_HARPOON(ioPort + hp_clkctrl_0) & CLKCTRL_DEFAULT) - != CLKCTRL_DEFAULT) - return 0; - if ((RD_HARPOON(ioPort + hp_seltimeout) == TO_250ms) || - (RD_HARPOON(ioPort + hp_seltimeout) == TO_290ms)) - return 1; - return 0; - -} - -/*--------------------------------------------------------------------- - * - * Function: FlashPoint_StartCCB - * - * Description: Start a command pointed to by p_Sccb. When the - * command is completed it will be returned via the - * callback function. - * - *---------------------------------------------------------------------*/ -static void FlashPoint_StartCCB(unsigned long pCurrCard, struct sccb *p_Sccb) -{ - unsigned long ioport; - unsigned char thisCard, lun; - struct sccb *pSaveSccb; - CALL_BK_FN callback; - - thisCard = ((struct sccb_card *)pCurrCard)->cardIndex; - ioport = ((struct sccb_card *)pCurrCard)->ioPort; - - if ((p_Sccb->TargID >= MAX_SCSI_TAR) || (p_Sccb->Lun >= MAX_LUN)) { - - p_Sccb->HostStatus = SCCB_COMPLETE; - p_Sccb->SccbStatus = SCCB_ERROR; - callback = (CALL_BK_FN) p_Sccb->SccbCallback; - if (callback) - callback(p_Sccb); - - return; - } - - FPT_sinits(p_Sccb, thisCard); - - if (!((struct sccb_card *)pCurrCard)->cmdCounter) { - WR_HARPOON(ioport + hp_semaphore, - (RD_HARPOON(ioport + hp_semaphore) - | SCCB_MGR_ACTIVE)); - - if (((struct sccb_card *)pCurrCard)->globalFlags & F_GREEN_PC) { - WR_HARPOON(ioport + hp_clkctrl_0, CLKCTRL_DEFAULT); - WR_HARPOON(ioport + hp_sys_ctrl, 0x00); - } - } - - ((struct sccb_card *)pCurrCard)->cmdCounter++; - - if (RD_HARPOON(ioport + hp_semaphore) & BIOS_IN_USE) { - - WR_HARPOON(ioport + hp_semaphore, - (RD_HARPOON(ioport + hp_semaphore) - | TICKLE_ME)); - if (p_Sccb->OperationCode == RESET_COMMAND) { - pSaveSccb = - ((struct sccb_card *)pCurrCard)->currentSCCB; - ((struct sccb_card *)pCurrCard)->currentSCCB = p_Sccb; - FPT_queueSelectFail(&FPT_BL_Card[thisCard], thisCard); - ((struct sccb_card *)pCurrCard)->currentSCCB = - pSaveSccb; - } else { - FPT_queueAddSccb(p_Sccb, thisCard); - } - } - - else if ((RD_HARPOON(ioport + hp_page_ctrl) & G_INT_DISABLE)) { - - if (p_Sccb->OperationCode == RESET_COMMAND) { - pSaveSccb = - ((struct sccb_card *)pCurrCard)->currentSCCB; - ((struct sccb_card *)pCurrCard)->currentSCCB = p_Sccb; - FPT_queueSelectFail(&FPT_BL_Card[thisCard], thisCard); - ((struct sccb_card *)pCurrCard)->currentSCCB = - pSaveSccb; - } else { - FPT_queueAddSccb(p_Sccb, thisCard); - } - } - - else { - - MDISABLE_INT(ioport); - - if ((((struct sccb_card *)pCurrCard)->globalFlags & F_CONLUN_IO) - && - ((FPT_sccbMgrTbl[thisCard][p_Sccb->TargID]. - TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)) - lun = p_Sccb->Lun; - else - lun = 0; - if ((((struct sccb_card *)pCurrCard)->currentSCCB == NULL) && - (FPT_sccbMgrTbl[thisCard][p_Sccb->TargID].TarSelQ_Cnt == 0) - && (FPT_sccbMgrTbl[thisCard][p_Sccb->TargID].TarLUNBusy[lun] - == 0)) { - - ((struct sccb_card *)pCurrCard)->currentSCCB = p_Sccb; - FPT_ssel(p_Sccb->SccbIOPort, thisCard); - } - - else { - - if (p_Sccb->OperationCode == RESET_COMMAND) { - pSaveSccb = - ((struct sccb_card *)pCurrCard)-> - currentSCCB; - ((struct sccb_card *)pCurrCard)->currentSCCB = - p_Sccb; - FPT_queueSelectFail(&FPT_BL_Card[thisCard], - thisCard); - ((struct sccb_card *)pCurrCard)->currentSCCB = - pSaveSccb; - } else { - FPT_queueAddSccb(p_Sccb, thisCard); - } - } - - MENABLE_INT(ioport); - } - -} - -/*--------------------------------------------------------------------- - * - * Function: FlashPoint_AbortCCB - * - * Description: Abort the command pointed to by p_Sccb. When the - * command is completed it will be returned via the - * callback function. - * - *---------------------------------------------------------------------*/ -static int FlashPoint_AbortCCB(unsigned long pCurrCard, struct sccb *p_Sccb) -{ - unsigned long ioport; - - unsigned char thisCard; - CALL_BK_FN callback; - unsigned char TID; - struct sccb *pSaveSCCB; - struct sccb_mgr_tar_info *currTar_Info; - - ioport = ((struct sccb_card *)pCurrCard)->ioPort; - - thisCard = ((struct sccb_card *)pCurrCard)->cardIndex; - - if (!(RD_HARPOON(ioport + hp_page_ctrl) & G_INT_DISABLE)) { - - if (FPT_queueFindSccb(p_Sccb, thisCard)) { - - ((struct sccb_card *)pCurrCard)->cmdCounter--; - - if (!((struct sccb_card *)pCurrCard)->cmdCounter) - WR_HARPOON(ioport + hp_semaphore, - (RD_HARPOON(ioport + hp_semaphore) - & (unsigned - char)(~(SCCB_MGR_ACTIVE | - TICKLE_ME)))); - - p_Sccb->SccbStatus = SCCB_ABORT; - callback = p_Sccb->SccbCallback; - callback(p_Sccb); - - return 0; - } - - else { - if (((struct sccb_card *)pCurrCard)->currentSCCB == - p_Sccb) { - p_Sccb->SccbStatus = SCCB_ABORT; - return 0; - - } - - else { - - TID = p_Sccb->TargID; - - if (p_Sccb->Sccb_tag) { - MDISABLE_INT(ioport); - if (((struct sccb_card *)pCurrCard)-> - discQ_Tbl[p_Sccb->Sccb_tag] == - p_Sccb) { - p_Sccb->SccbStatus = SCCB_ABORT; - p_Sccb->Sccb_scsistat = - ABORT_ST; - p_Sccb->Sccb_scsimsg = - SMABORT_TAG; - - if (((struct sccb_card *) - pCurrCard)->currentSCCB == - NULL) { - ((struct sccb_card *) - pCurrCard)-> - currentSCCB = p_Sccb; - FPT_ssel(ioport, - thisCard); - } else { - pSaveSCCB = - ((struct sccb_card - *)pCurrCard)-> - currentSCCB; - ((struct sccb_card *) - pCurrCard)-> - currentSCCB = p_Sccb; - FPT_queueSelectFail((struct sccb_card *)pCurrCard, thisCard); - ((struct sccb_card *) - pCurrCard)-> - currentSCCB = pSaveSCCB; - } - } - MENABLE_INT(ioport); - return 0; - } else { - currTar_Info = - &FPT_sccbMgrTbl[thisCard][p_Sccb-> - TargID]; - - if (FPT_BL_Card[thisCard]. - discQ_Tbl[currTar_Info-> - LunDiscQ_Idx[p_Sccb->Lun]] - == p_Sccb) { - p_Sccb->SccbStatus = SCCB_ABORT; - return 0; - } - } - } - } - } - return -1; -} - -/*--------------------------------------------------------------------- - * - * Function: FlashPoint_InterruptPending - * - * Description: Do a quick check to determine if there is a pending - * interrupt for this card and disable the IRQ Pin if so. - * - *---------------------------------------------------------------------*/ -static unsigned char FlashPoint_InterruptPending(unsigned long pCurrCard) -{ - unsigned long ioport; - - ioport = ((struct sccb_card *)pCurrCard)->ioPort; - - if (RD_HARPOON(ioport + hp_int_status) & INT_ASSERTED) { - return 1; - } - - else - - return 0; -} - -/*--------------------------------------------------------------------- - * - * Function: FlashPoint_HandleInterrupt - * - * Description: This is our entry point when an interrupt is generated - * by the card and the upper level driver passes it on to - * us. - * - *---------------------------------------------------------------------*/ -static int FlashPoint_HandleInterrupt(unsigned long pCurrCard) -{ - struct sccb *currSCCB; - unsigned char thisCard, result, bm_status, bm_int_st; - unsigned short hp_int; - unsigned char i, target; - unsigned long ioport; - - thisCard = ((struct sccb_card *)pCurrCard)->cardIndex; - ioport = ((struct sccb_card *)pCurrCard)->ioPort; - - MDISABLE_INT(ioport); - - if ((bm_int_st = RD_HARPOON(ioport + hp_int_status)) & EXT_STATUS_ON) - bm_status = - RD_HARPOON(ioport + - hp_ext_status) & (unsigned char)BAD_EXT_STATUS; - else - bm_status = 0; - - WR_HARPOON(ioport + hp_int_mask, (INT_CMD_COMPL | SCSI_INTERRUPT)); - - while ((hp_int = - RDW_HARPOON((ioport + - hp_intstat)) & FPT_default_intena) | bm_status) { - - currSCCB = ((struct sccb_card *)pCurrCard)->currentSCCB; - - if (hp_int & (FIFO | TIMEOUT | RESET | SCAM_SEL) || bm_status) { - result = - FPT_SccbMgr_bad_isr(ioport, thisCard, - ((struct sccb_card *)pCurrCard), - hp_int); - WRW_HARPOON((ioport + hp_intstat), - (FIFO | TIMEOUT | RESET | SCAM_SEL)); - bm_status = 0; - - if (result) { - - MENABLE_INT(ioport); - return result; - } - } - - else if (hp_int & ICMD_COMP) { - - if (!(hp_int & BUS_FREE)) { - /* Wait for the BusFree before starting a new command. We - must also check for being reselected since the BusFree - may not show up if another device reselects us in 1.5us or - less. SRR Wednesday, 3/8/1995. - */ - while (! - (RDW_HARPOON((ioport + hp_intstat)) & - (BUS_FREE | RSEL))) ; - } - - if (((struct sccb_card *)pCurrCard)-> - globalFlags & F_HOST_XFER_ACT) - - FPT_phaseChkFifo(ioport, thisCard); - -/* WRW_HARPOON((ioport+hp_intstat), - (BUS_FREE | ICMD_COMP | ITAR_DISC | XFER_CNT_0)); - */ - - WRW_HARPOON((ioport + hp_intstat), CLR_ALL_INT_1); - - FPT_autoCmdCmplt(ioport, thisCard); - - } - - else if (hp_int & ITAR_DISC) { - - if (((struct sccb_card *)pCurrCard)-> - globalFlags & F_HOST_XFER_ACT) { - - FPT_phaseChkFifo(ioport, thisCard); - - } - - if (RD_HARPOON(ioport + hp_gp_reg_1) == SMSAVE_DATA_PTR) { - - WR_HARPOON(ioport + hp_gp_reg_1, 0x00); - currSCCB->Sccb_XferState |= F_NO_DATA_YET; - - currSCCB->Sccb_savedATC = currSCCB->Sccb_ATC; - } - - currSCCB->Sccb_scsistat = DISCONNECT_ST; - FPT_queueDisconnect(currSCCB, thisCard); - - /* Wait for the BusFree before starting a new command. We - must also check for being reselected since the BusFree - may not show up if another device reselects us in 1.5us or - less. SRR Wednesday, 3/8/1995. - */ - while (! - (RDW_HARPOON((ioport + hp_intstat)) & - (BUS_FREE | RSEL)) - && !((RDW_HARPOON((ioport + hp_intstat)) & PHASE) - && RD_HARPOON((ioport + hp_scsisig)) == - (SCSI_BSY | SCSI_REQ | SCSI_CD | SCSI_MSG | - SCSI_IOBIT))) ; - - /* - The additional loop exit condition above detects a timing problem - with the revision D/E harpoon chips. The caller should reset the - host adapter to recover when 0xFE is returned. - */ - if (! - (RDW_HARPOON((ioport + hp_intstat)) & - (BUS_FREE | RSEL))) { - MENABLE_INT(ioport); - return 0xFE; - } - - WRW_HARPOON((ioport + hp_intstat), - (BUS_FREE | ITAR_DISC)); - - ((struct sccb_card *)pCurrCard)->globalFlags |= - F_NEW_SCCB_CMD; - - } - - else if (hp_int & RSEL) { - - WRW_HARPOON((ioport + hp_intstat), - (PROG_HLT | RSEL | PHASE | BUS_FREE)); - - if (RDW_HARPOON((ioport + hp_intstat)) & ITAR_DISC) { - if (((struct sccb_card *)pCurrCard)-> - globalFlags & F_HOST_XFER_ACT) { - FPT_phaseChkFifo(ioport, thisCard); - } - - if (RD_HARPOON(ioport + hp_gp_reg_1) == - SMSAVE_DATA_PTR) { - WR_HARPOON(ioport + hp_gp_reg_1, 0x00); - currSCCB->Sccb_XferState |= - F_NO_DATA_YET; - currSCCB->Sccb_savedATC = - currSCCB->Sccb_ATC; - } - - WRW_HARPOON((ioport + hp_intstat), - (BUS_FREE | ITAR_DISC)); - currSCCB->Sccb_scsistat = DISCONNECT_ST; - FPT_queueDisconnect(currSCCB, thisCard); - } - - FPT_sres(ioport, thisCard, - ((struct sccb_card *)pCurrCard)); - FPT_phaseDecode(ioport, thisCard); - - } - - else if ((hp_int & IDO_STRT) && (!(hp_int & BUS_FREE))) { - - WRW_HARPOON((ioport + hp_intstat), - (IDO_STRT | XFER_CNT_0)); - FPT_phaseDecode(ioport, thisCard); - - } - - else if ((hp_int & IUNKWN) || (hp_int & PROG_HLT)) { - WRW_HARPOON((ioport + hp_intstat), - (PHASE | IUNKWN | PROG_HLT)); - if ((RD_HARPOON(ioport + hp_prgmcnt_0) & (unsigned char) - 0x3f) < (unsigned char)SELCHK) { - FPT_phaseDecode(ioport, thisCard); - } else { - /* Harpoon problem some SCSI target device respond to selection - with short BUSY pulse (<400ns) this will make the Harpoon is not able - to latch the correct Target ID into reg. x53. - The work around require to correct this reg. But when write to this - reg. (0x53) also increment the FIFO write addr reg (0x6f), thus we - need to read this reg first then restore it later. After update to 0x53 */ - - i = (unsigned - char)(RD_HARPOON(ioport + hp_fifowrite)); - target = - (unsigned - char)(RD_HARPOON(ioport + hp_gp_reg_3)); - WR_HARPOON(ioport + hp_xfer_pad, - (unsigned char)ID_UNLOCK); - WR_HARPOON(ioport + hp_select_id, - (unsigned char)(target | target << - 4)); - WR_HARPOON(ioport + hp_xfer_pad, - (unsigned char)0x00); - WR_HARPOON(ioport + hp_fifowrite, i); - WR_HARPOON(ioport + hp_autostart_3, - (AUTO_IMMED + TAG_STRT)); - } - } - - else if (hp_int & XFER_CNT_0) { - - WRW_HARPOON((ioport + hp_intstat), XFER_CNT_0); - - FPT_schkdd(ioport, thisCard); - - } - - else if (hp_int & BUS_FREE) { - - WRW_HARPOON((ioport + hp_intstat), BUS_FREE); - - if (((struct sccb_card *)pCurrCard)-> - globalFlags & F_HOST_XFER_ACT) { - - FPT_hostDataXferAbort(ioport, thisCard, - currSCCB); - } - - FPT_phaseBusFree(ioport, thisCard); - } - - else if (hp_int & ITICKLE) { - - WRW_HARPOON((ioport + hp_intstat), ITICKLE); - ((struct sccb_card *)pCurrCard)->globalFlags |= - F_NEW_SCCB_CMD; - } - - if (((struct sccb_card *)pCurrCard)-> - globalFlags & F_NEW_SCCB_CMD) { - - ((struct sccb_card *)pCurrCard)->globalFlags &= - ~F_NEW_SCCB_CMD; - - if (((struct sccb_card *)pCurrCard)->currentSCCB == - NULL) { - - FPT_queueSearchSelect(((struct sccb_card *) - pCurrCard), thisCard); - } - - if (((struct sccb_card *)pCurrCard)->currentSCCB != - NULL) { - ((struct sccb_card *)pCurrCard)->globalFlags &= - ~F_NEW_SCCB_CMD; - FPT_ssel(ioport, thisCard); - } - - break; - - } - - } /*end while */ - - MENABLE_INT(ioport); - - return 0; -} - -/*--------------------------------------------------------------------- - * - * Function: Sccb_bad_isr - * - * Description: Some type of interrupt has occurred which is slightly - * out of the ordinary. We will now decode it fully, in - * this routine. This is broken up in an attempt to save - * processing time. - * - *---------------------------------------------------------------------*/ -static unsigned char FPT_SccbMgr_bad_isr(unsigned long p_port, - unsigned char p_card, - struct sccb_card *pCurrCard, - unsigned short p_int) -{ - unsigned char temp, ScamFlg; - struct sccb_mgr_tar_info *currTar_Info; - struct nvram_info *pCurrNvRam; - - if (RD_HARPOON(p_port + hp_ext_status) & - (BM_FORCE_OFF | PCI_DEV_TMOUT | BM_PARITY_ERR | PIO_OVERRUN)) { - - if (pCurrCard->globalFlags & F_HOST_XFER_ACT) { - - FPT_hostDataXferAbort(p_port, p_card, - pCurrCard->currentSCCB); - } - - if (RD_HARPOON(p_port + hp_pci_stat_cfg) & REC_MASTER_ABORT) - { - WR_HARPOON(p_port + hp_pci_stat_cfg, - (RD_HARPOON(p_port + hp_pci_stat_cfg) & - ~REC_MASTER_ABORT)); - - WR_HARPOON(p_port + hp_host_blk_cnt, 0x00); - - } - - if (pCurrCard->currentSCCB != NULL) { - - if (!pCurrCard->currentSCCB->HostStatus) - pCurrCard->currentSCCB->HostStatus = - SCCB_BM_ERR; - - FPT_sxfrp(p_port, p_card); - - temp = (unsigned char)(RD_HARPOON(p_port + hp_ee_ctrl) & - (EXT_ARB_ACK | SCSI_TERM_ENA_H)); - WR_HARPOON(p_port + hp_ee_ctrl, - ((unsigned char)temp | SEE_MS | SEE_CS)); - WR_HARPOON(p_port + hp_ee_ctrl, temp); - - if (! - (RDW_HARPOON((p_port + hp_intstat)) & - (BUS_FREE | RESET))) { - FPT_phaseDecode(p_port, p_card); - } - } - } - - else if (p_int & RESET) { - - WR_HARPOON(p_port + hp_clkctrl_0, CLKCTRL_DEFAULT); - WR_HARPOON(p_port + hp_sys_ctrl, 0x00); - if (pCurrCard->currentSCCB != NULL) { - - if (pCurrCard->globalFlags & F_HOST_XFER_ACT) - - FPT_hostDataXferAbort(p_port, p_card, - pCurrCard->currentSCCB); - } - - DISABLE_AUTO(p_port); - - FPT_sresb(p_port, p_card); - - while (RD_HARPOON(p_port + hp_scsictrl_0) & SCSI_RST) { - } - - pCurrNvRam = pCurrCard->pNvRamInfo; - if (pCurrNvRam) { - ScamFlg = pCurrNvRam->niScamConf; - } else { - ScamFlg = - (unsigned char)FPT_utilEERead(p_port, - SCAM_CONFIG / 2); - } - - FPT_XbowInit(p_port, ScamFlg); - - FPT_scini(p_card, pCurrCard->ourId, 0); - - return 0xFF; - } - - else if (p_int & FIFO) { - - WRW_HARPOON((p_port + hp_intstat), FIFO); - - if (pCurrCard->currentSCCB != NULL) - FPT_sxfrp(p_port, p_card); - } - - else if (p_int & TIMEOUT) { - - DISABLE_AUTO(p_port); - - WRW_HARPOON((p_port + hp_intstat), - (PROG_HLT | TIMEOUT | SEL | BUS_FREE | PHASE | - IUNKWN)); - - pCurrCard->currentSCCB->HostStatus = SCCB_SELECTION_TIMEOUT; - - currTar_Info = - &FPT_sccbMgrTbl[p_card][pCurrCard->currentSCCB->TargID]; - if ((pCurrCard->globalFlags & F_CONLUN_IO) - && ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != - TAG_Q_TRYING)) - currTar_Info->TarLUNBusy[pCurrCard->currentSCCB->Lun] = - 0; - else - currTar_Info->TarLUNBusy[0] = 0; - - if (currTar_Info->TarEEValue & EE_SYNC_MASK) { - currTar_Info->TarSyncCtrl = 0; - currTar_Info->TarStatus &= ~TAR_SYNC_MASK; - } - - if (currTar_Info->TarEEValue & EE_WIDE_SCSI) { - currTar_Info->TarStatus &= ~TAR_WIDE_MASK; - } - - FPT_sssyncv(p_port, pCurrCard->currentSCCB->TargID, NARROW_SCSI, - currTar_Info); - - FPT_queueCmdComplete(pCurrCard, pCurrCard->currentSCCB, p_card); - - } - - else if (p_int & SCAM_SEL) { - - FPT_scarb(p_port, LEVEL2_TAR); - FPT_scsel(p_port); - FPT_scasid(p_card, p_port); - - FPT_scbusf(p_port); - - WRW_HARPOON((p_port + hp_intstat), SCAM_SEL); - } - - return 0x00; -} - -/*--------------------------------------------------------------------- - * - * Function: SccbMgrTableInit - * - * Description: Initialize all Sccb manager data structures. - * - *---------------------------------------------------------------------*/ - -static void FPT_SccbMgrTableInitAll() -{ - unsigned char thisCard; - - for (thisCard = 0; thisCard < MAX_CARDS; thisCard++) { - FPT_SccbMgrTableInitCard(&FPT_BL_Card[thisCard], thisCard); - - FPT_BL_Card[thisCard].ioPort = 0x00; - FPT_BL_Card[thisCard].cardInfo = NULL; - FPT_BL_Card[thisCard].cardIndex = 0xFF; - FPT_BL_Card[thisCard].ourId = 0x00; - FPT_BL_Card[thisCard].pNvRamInfo = NULL; - } -} - -/*--------------------------------------------------------------------- - * - * Function: SccbMgrTableInit - * - * Description: Initialize all Sccb manager data structures. - * - *---------------------------------------------------------------------*/ - -static void FPT_SccbMgrTableInitCard(struct sccb_card *pCurrCard, - unsigned char p_card) -{ - unsigned char scsiID, qtag; - - for (qtag = 0; qtag < QUEUE_DEPTH; qtag++) { - FPT_BL_Card[p_card].discQ_Tbl[qtag] = NULL; - } - - for (scsiID = 0; scsiID < MAX_SCSI_TAR; scsiID++) { - FPT_sccbMgrTbl[p_card][scsiID].TarStatus = 0; - FPT_sccbMgrTbl[p_card][scsiID].TarEEValue = 0; - FPT_SccbMgrTableInitTarget(p_card, scsiID); - } - - pCurrCard->scanIndex = 0x00; - pCurrCard->currentSCCB = NULL; - pCurrCard->globalFlags = 0x00; - pCurrCard->cmdCounter = 0x00; - pCurrCard->tagQ_Lst = 0x01; - pCurrCard->discQCount = 0; - -} - -/*--------------------------------------------------------------------- - * - * Function: SccbMgrTableInit - * - * Description: Initialize all Sccb manager data structures. - * - *---------------------------------------------------------------------*/ - -static void FPT_SccbMgrTableInitTarget(unsigned char p_card, - unsigned char target) -{ - - unsigned char lun, qtag; - struct sccb_mgr_tar_info *currTar_Info; - - currTar_Info = &FPT_sccbMgrTbl[p_card][target]; - - currTar_Info->TarSelQ_Cnt = 0; - currTar_Info->TarSyncCtrl = 0; - - currTar_Info->TarSelQ_Head = NULL; - currTar_Info->TarSelQ_Tail = NULL; - currTar_Info->TarTagQ_Cnt = 0; - currTar_Info->TarLUN_CA = 0; - - for (lun = 0; lun < MAX_LUN; lun++) { - currTar_Info->TarLUNBusy[lun] = 0; - currTar_Info->LunDiscQ_Idx[lun] = 0; - } - - for (qtag = 0; qtag < QUEUE_DEPTH; qtag++) { - if (FPT_BL_Card[p_card].discQ_Tbl[qtag] != NULL) { - if (FPT_BL_Card[p_card].discQ_Tbl[qtag]->TargID == - target) { - FPT_BL_Card[p_card].discQ_Tbl[qtag] = NULL; - FPT_BL_Card[p_card].discQCount--; - } - } - } -} - -/*--------------------------------------------------------------------- - * - * Function: sfetm - * - * Description: Read in a message byte from the SCSI bus, and check - * for a parity error. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_sfm(unsigned long port, struct sccb *pCurrSCCB) -{ - unsigned char message; - unsigned short TimeOutLoop; - - TimeOutLoop = 0; - while ((!(RD_HARPOON(port + hp_scsisig) & SCSI_REQ)) && - (TimeOutLoop++ < 20000)) { - } - - WR_HARPOON(port + hp_portctrl_0, SCSI_PORT); - - message = RD_HARPOON(port + hp_scsidata_0); - - WR_HARPOON(port + hp_scsisig, SCSI_ACK + S_MSGI_PH); - - if (TimeOutLoop > 20000) - message = 0x00; /* force message byte = 0 if Time Out on Req */ - - if ((RDW_HARPOON((port + hp_intstat)) & PARITY) && - (RD_HARPOON(port + hp_addstat) & SCSI_PAR_ERR)) { - WR_HARPOON(port + hp_scsisig, (SCSI_ACK + S_ILL_PH)); - WR_HARPOON(port + hp_xferstat, 0); - WR_HARPOON(port + hp_fiforead, 0); - WR_HARPOON(port + hp_fifowrite, 0); - if (pCurrSCCB != NULL) { - pCurrSCCB->Sccb_scsimsg = SMPARITY; - } - message = 0x00; - do { - ACCEPT_MSG_ATN(port); - TimeOutLoop = 0; - while ((!(RD_HARPOON(port + hp_scsisig) & SCSI_REQ)) && - (TimeOutLoop++ < 20000)) { - } - if (TimeOutLoop > 20000) { - WRW_HARPOON((port + hp_intstat), PARITY); - return message; - } - if ((RD_HARPOON(port + hp_scsisig) & S_SCSI_PHZ) != - S_MSGI_PH) { - WRW_HARPOON((port + hp_intstat), PARITY); - return message; - } - WR_HARPOON(port + hp_portctrl_0, SCSI_PORT); - - RD_HARPOON(port + hp_scsidata_0); - - WR_HARPOON(port + hp_scsisig, (SCSI_ACK + S_ILL_PH)); - - } while (1); - - } - WR_HARPOON(port + hp_scsisig, (SCSI_ACK + S_ILL_PH)); - WR_HARPOON(port + hp_xferstat, 0); - WR_HARPOON(port + hp_fiforead, 0); - WR_HARPOON(port + hp_fifowrite, 0); - return message; -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_ssel - * - * Description: Load up automation and select target device. - * - *---------------------------------------------------------------------*/ - -static void FPT_ssel(unsigned long port, unsigned char p_card) -{ - - unsigned char auto_loaded, i, target, *theCCB; - - unsigned long cdb_reg; - struct sccb_card *CurrCard; - struct sccb *currSCCB; - struct sccb_mgr_tar_info *currTar_Info; - unsigned char lastTag, lun; - - CurrCard = &FPT_BL_Card[p_card]; - currSCCB = CurrCard->currentSCCB; - target = currSCCB->TargID; - currTar_Info = &FPT_sccbMgrTbl[p_card][target]; - lastTag = CurrCard->tagQ_Lst; - - ARAM_ACCESS(port); - - if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_REJECT) - currSCCB->ControlByte &= ~F_USE_CMD_Q; - - if (((CurrCard->globalFlags & F_CONLUN_IO) && - ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))) - - lun = currSCCB->Lun; - else - lun = 0; - - if (CurrCard->globalFlags & F_TAG_STARTED) { - if (!(currSCCB->ControlByte & F_USE_CMD_Q)) { - if ((currTar_Info->TarLUN_CA == 0) - && ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) - == TAG_Q_TRYING)) { - - if (currTar_Info->TarTagQ_Cnt != 0) { - currTar_Info->TarLUNBusy[lun] = 1; - FPT_queueSelectFail(CurrCard, p_card); - SGRAM_ACCESS(port); - return; - } - - else { - currTar_Info->TarLUNBusy[lun] = 1; - } - - } - /*End non-tagged */ - else { - currTar_Info->TarLUNBusy[lun] = 1; - } - - } - /*!Use cmd Q Tagged */ - else { - if (currTar_Info->TarLUN_CA == 1) { - FPT_queueSelectFail(CurrCard, p_card); - SGRAM_ACCESS(port); - return; - } - - currTar_Info->TarLUNBusy[lun] = 1; - - } /*else use cmd Q tagged */ - - } - /*if glob tagged started */ - else { - currTar_Info->TarLUNBusy[lun] = 1; - } - - if ((((CurrCard->globalFlags & F_CONLUN_IO) && - ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)) - || (!(currSCCB->ControlByte & F_USE_CMD_Q)))) { - if (CurrCard->discQCount >= QUEUE_DEPTH) { - currTar_Info->TarLUNBusy[lun] = 1; - FPT_queueSelectFail(CurrCard, p_card); - SGRAM_ACCESS(port); - return; - } - for (i = 1; i < QUEUE_DEPTH; i++) { - if (++lastTag >= QUEUE_DEPTH) - lastTag = 1; - if (CurrCard->discQ_Tbl[lastTag] == NULL) { - CurrCard->tagQ_Lst = lastTag; - currTar_Info->LunDiscQ_Idx[lun] = lastTag; - CurrCard->discQ_Tbl[lastTag] = currSCCB; - CurrCard->discQCount++; - break; - } - } - if (i == QUEUE_DEPTH) { - currTar_Info->TarLUNBusy[lun] = 1; - FPT_queueSelectFail(CurrCard, p_card); - SGRAM_ACCESS(port); - return; - } - } - - auto_loaded = 0; - - WR_HARPOON(port + hp_select_id, target); - WR_HARPOON(port + hp_gp_reg_3, target); /* Use by new automation logic */ - - if (currSCCB->OperationCode == RESET_COMMAND) { - WRW_HARPOON((port + ID_MSG_STRT), (MPM_OP + AMSG_OUT + - (currSCCB-> - Sccb_idmsg & ~DISC_PRIV))); - - WRW_HARPOON((port + ID_MSG_STRT + 2), BRH_OP + ALWAYS + NP); - - currSCCB->Sccb_scsimsg = SMDEV_RESET; - - WR_HARPOON(port + hp_autostart_3, (SELECT + SELCHK_STRT)); - auto_loaded = 1; - currSCCB->Sccb_scsistat = SELECT_BDR_ST; - - if (currTar_Info->TarEEValue & EE_SYNC_MASK) { - currTar_Info->TarSyncCtrl = 0; - currTar_Info->TarStatus &= ~TAR_SYNC_MASK; - } - - if (currTar_Info->TarEEValue & EE_WIDE_SCSI) { - currTar_Info->TarStatus &= ~TAR_WIDE_MASK; - } - - FPT_sssyncv(port, target, NARROW_SCSI, currTar_Info); - FPT_SccbMgrTableInitTarget(p_card, target); - - } - - else if (currSCCB->Sccb_scsistat == ABORT_ST) { - WRW_HARPOON((port + ID_MSG_STRT), (MPM_OP + AMSG_OUT + - (currSCCB-> - Sccb_idmsg & ~DISC_PRIV))); - - WRW_HARPOON((port + ID_MSG_STRT + 2), BRH_OP + ALWAYS + CMDPZ); - - WRW_HARPOON((port + SYNC_MSGS + 0), (MPM_OP + AMSG_OUT + - (((unsigned - char)(currSCCB-> - ControlByte & - TAG_TYPE_MASK) - >> 6) | (unsigned char) - 0x20))); - WRW_HARPOON((port + SYNC_MSGS + 2), - (MPM_OP + AMSG_OUT + currSCCB->Sccb_tag)); - WRW_HARPOON((port + SYNC_MSGS + 4), (BRH_OP + ALWAYS + NP)); - - WR_HARPOON(port + hp_autostart_3, (SELECT + SELCHK_STRT)); - auto_loaded = 1; - - } - - else if (!(currTar_Info->TarStatus & WIDE_NEGOCIATED)) { - auto_loaded = FPT_siwidn(port, p_card); - currSCCB->Sccb_scsistat = SELECT_WN_ST; - } - - else if (!((currTar_Info->TarStatus & TAR_SYNC_MASK) - == SYNC_SUPPORTED)) { - auto_loaded = FPT_sisyncn(port, p_card, 0); - currSCCB->Sccb_scsistat = SELECT_SN_ST; - } - - if (!auto_loaded) { - - if (currSCCB->ControlByte & F_USE_CMD_Q) { - - CurrCard->globalFlags |= F_TAG_STARTED; - - if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) - == TAG_Q_REJECT) { - currSCCB->ControlByte &= ~F_USE_CMD_Q; - - /* Fix up the start instruction with a jump to - Non-Tag-CMD handling */ - WRW_HARPOON((port + ID_MSG_STRT), - BRH_OP + ALWAYS + NTCMD); - - WRW_HARPOON((port + NON_TAG_ID_MSG), - (MPM_OP + AMSG_OUT + - currSCCB->Sccb_idmsg)); - - WR_HARPOON(port + hp_autostart_3, - (SELECT + SELCHK_STRT)); - - /* Setup our STATE so we know what happened when - the wheels fall off. */ - currSCCB->Sccb_scsistat = SELECT_ST; - - currTar_Info->TarLUNBusy[lun] = 1; - } - - else { - WRW_HARPOON((port + ID_MSG_STRT), - (MPM_OP + AMSG_OUT + - currSCCB->Sccb_idmsg)); - - WRW_HARPOON((port + ID_MSG_STRT + 2), - (MPM_OP + AMSG_OUT + - (((unsigned char)(currSCCB-> - ControlByte & - TAG_TYPE_MASK) - >> 6) | (unsigned char)0x20))); - - for (i = 1; i < QUEUE_DEPTH; i++) { - if (++lastTag >= QUEUE_DEPTH) - lastTag = 1; - if (CurrCard->discQ_Tbl[lastTag] == - NULL) { - WRW_HARPOON((port + - ID_MSG_STRT + 6), - (MPM_OP + AMSG_OUT + - lastTag)); - CurrCard->tagQ_Lst = lastTag; - currSCCB->Sccb_tag = lastTag; - CurrCard->discQ_Tbl[lastTag] = - currSCCB; - CurrCard->discQCount++; - break; - } - } - - if (i == QUEUE_DEPTH) { - currTar_Info->TarLUNBusy[lun] = 1; - FPT_queueSelectFail(CurrCard, p_card); - SGRAM_ACCESS(port); - return; - } - - currSCCB->Sccb_scsistat = SELECT_Q_ST; - - WR_HARPOON(port + hp_autostart_3, - (SELECT + SELCHK_STRT)); - } - } - - else { - - WRW_HARPOON((port + ID_MSG_STRT), - BRH_OP + ALWAYS + NTCMD); - - WRW_HARPOON((port + NON_TAG_ID_MSG), - (MPM_OP + AMSG_OUT + currSCCB->Sccb_idmsg)); - - currSCCB->Sccb_scsistat = SELECT_ST; - - WR_HARPOON(port + hp_autostart_3, - (SELECT + SELCHK_STRT)); - } - - theCCB = (unsigned char *)&currSCCB->Cdb[0]; - - cdb_reg = port + CMD_STRT; - - for (i = 0; i < currSCCB->CdbLength; i++) { - WRW_HARPOON(cdb_reg, (MPM_OP + ACOMMAND + *theCCB)); - cdb_reg += 2; - theCCB++; - } - - if (currSCCB->CdbLength != TWELVE_BYTE_CMD) - WRW_HARPOON(cdb_reg, (BRH_OP + ALWAYS + NP)); - - } - /* auto_loaded */ - WRW_HARPOON((port + hp_fiforead), (unsigned short)0x00); - WR_HARPOON(port + hp_xferstat, 0x00); - - WRW_HARPOON((port + hp_intstat), (PROG_HLT | TIMEOUT | SEL | BUS_FREE)); - - WR_HARPOON(port + hp_portctrl_0, (SCSI_PORT)); - - if (!(currSCCB->Sccb_MGRFlags & F_DEV_SELECTED)) { - WR_HARPOON(port + hp_scsictrl_0, - (SEL_TAR | ENA_ATN | ENA_RESEL | ENA_SCAM_SEL)); - } else { - -/* auto_loaded = (RD_HARPOON(port+hp_autostart_3) & (unsigned char)0x1F); - auto_loaded |= AUTO_IMMED; */ - auto_loaded = AUTO_IMMED; - - DISABLE_AUTO(port); - - WR_HARPOON(port + hp_autostart_3, auto_loaded); - } - - SGRAM_ACCESS(port); -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sres - * - * Description: Hookup the correct CCB and handle the incoming messages. - * - *---------------------------------------------------------------------*/ - -static void FPT_sres(unsigned long port, unsigned char p_card, - struct sccb_card *pCurrCard) -{ - - unsigned char our_target, message, lun = 0, tag, msgRetryCount; - - struct sccb_mgr_tar_info *currTar_Info; - struct sccb *currSCCB; - - if (pCurrCard->currentSCCB != NULL) { - currTar_Info = - &FPT_sccbMgrTbl[p_card][pCurrCard->currentSCCB->TargID]; - DISABLE_AUTO(port); - - WR_HARPOON((port + hp_scsictrl_0), (ENA_RESEL | ENA_SCAM_SEL)); - - currSCCB = pCurrCard->currentSCCB; - if (currSCCB->Sccb_scsistat == SELECT_WN_ST) { - currTar_Info->TarStatus &= ~TAR_WIDE_MASK; - currSCCB->Sccb_scsistat = BUS_FREE_ST; - } - if (currSCCB->Sccb_scsistat == SELECT_SN_ST) { - currTar_Info->TarStatus &= ~TAR_SYNC_MASK; - currSCCB->Sccb_scsistat = BUS_FREE_ST; - } - if (((pCurrCard->globalFlags & F_CONLUN_IO) && - ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != - TAG_Q_TRYING))) { - currTar_Info->TarLUNBusy[currSCCB->Lun] = 0; - if (currSCCB->Sccb_scsistat != ABORT_ST) { - pCurrCard->discQCount--; - pCurrCard->discQ_Tbl[currTar_Info-> - LunDiscQ_Idx[currSCCB-> - Lun]] - = NULL; - } - } else { - currTar_Info->TarLUNBusy[0] = 0; - if (currSCCB->Sccb_tag) { - if (currSCCB->Sccb_scsistat != ABORT_ST) { - pCurrCard->discQCount--; - pCurrCard->discQ_Tbl[currSCCB-> - Sccb_tag] = NULL; - } - } else { - if (currSCCB->Sccb_scsistat != ABORT_ST) { - pCurrCard->discQCount--; - pCurrCard->discQ_Tbl[currTar_Info-> - LunDiscQ_Idx[0]] = - NULL; - } - } - } - - FPT_queueSelectFail(&FPT_BL_Card[p_card], p_card); - } - - WRW_HARPOON((port + hp_fiforead), (unsigned short)0x00); - - our_target = (unsigned char)(RD_HARPOON(port + hp_select_id) >> 4); - currTar_Info = &FPT_sccbMgrTbl[p_card][our_target]; - - msgRetryCount = 0; - do { - - currTar_Info = &FPT_sccbMgrTbl[p_card][our_target]; - tag = 0; - - while (!(RD_HARPOON(port + hp_scsisig) & SCSI_REQ)) { - if (!(RD_HARPOON(port + hp_scsisig) & SCSI_BSY)) { - - WRW_HARPOON((port + hp_intstat), PHASE); - return; - } - } - - WRW_HARPOON((port + hp_intstat), PHASE); - if ((RD_HARPOON(port + hp_scsisig) & S_SCSI_PHZ) == S_MSGI_PH) { - - message = FPT_sfm(port, pCurrCard->currentSCCB); - if (message) { - - if (message <= (0x80 | LUN_MASK)) { - lun = message & (unsigned char)LUN_MASK; - - if ((currTar_Info-> - TarStatus & TAR_TAG_Q_MASK) == - TAG_Q_TRYING) { - if (currTar_Info->TarTagQ_Cnt != - 0) { - - if (! - (currTar_Info-> - TarLUN_CA)) { - ACCEPT_MSG(port); /*Release the ACK for ID msg. */ - - message = - FPT_sfm - (port, - pCurrCard-> - currentSCCB); - if (message) { - ACCEPT_MSG - (port); - } - - else - message - = 0; - - if (message != - 0) { - tag = - FPT_sfm - (port, - pCurrCard-> - currentSCCB); - - if (! - (tag)) - message - = - 0; - } - - } - /*C.A. exists! */ - } - /*End Q cnt != 0 */ - } - /*End Tag cmds supported! */ - } - /*End valid ID message. */ - else { - - ACCEPT_MSG_ATN(port); - } - - } - /* End good id message. */ - else { - - message = 0; - } - } else { - ACCEPT_MSG_ATN(port); - - while (! - (RDW_HARPOON((port + hp_intstat)) & - (PHASE | RESET)) - && !(RD_HARPOON(port + hp_scsisig) & SCSI_REQ) - && (RD_HARPOON(port + hp_scsisig) & SCSI_BSY)) ; - - return; - } - - if (message == 0) { - msgRetryCount++; - if (msgRetryCount == 1) { - FPT_SendMsg(port, SMPARITY); - } else { - FPT_SendMsg(port, SMDEV_RESET); - - FPT_sssyncv(port, our_target, NARROW_SCSI, - currTar_Info); - - if (FPT_sccbMgrTbl[p_card][our_target]. - TarEEValue & EE_SYNC_MASK) { - - FPT_sccbMgrTbl[p_card][our_target]. - TarStatus &= ~TAR_SYNC_MASK; - - } - - if (FPT_sccbMgrTbl[p_card][our_target]. - TarEEValue & EE_WIDE_SCSI) { - - FPT_sccbMgrTbl[p_card][our_target]. - TarStatus &= ~TAR_WIDE_MASK; - } - - FPT_queueFlushTargSccb(p_card, our_target, - SCCB_COMPLETE); - FPT_SccbMgrTableInitTarget(p_card, our_target); - return; - } - } - } while (message == 0); - - if (((pCurrCard->globalFlags & F_CONLUN_IO) && - ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))) { - currTar_Info->TarLUNBusy[lun] = 1; - pCurrCard->currentSCCB = - pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[lun]]; - if (pCurrCard->currentSCCB != NULL) { - ACCEPT_MSG(port); - } else { - ACCEPT_MSG_ATN(port); - } - } else { - currTar_Info->TarLUNBusy[0] = 1; - - if (tag) { - if (pCurrCard->discQ_Tbl[tag] != NULL) { - pCurrCard->currentSCCB = - pCurrCard->discQ_Tbl[tag]; - currTar_Info->TarTagQ_Cnt--; - ACCEPT_MSG(port); - } else { - ACCEPT_MSG_ATN(port); - } - } else { - pCurrCard->currentSCCB = - pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[0]]; - if (pCurrCard->currentSCCB != NULL) { - ACCEPT_MSG(port); - } else { - ACCEPT_MSG_ATN(port); - } - } - } - - if (pCurrCard->currentSCCB != NULL) { - if (pCurrCard->currentSCCB->Sccb_scsistat == ABORT_ST) { - /* During Abort Tag command, the target could have got re-selected - and completed the command. Check the select Q and remove the CCB - if it is in the Select Q */ - FPT_queueFindSccb(pCurrCard->currentSCCB, p_card); - } - } - - while (!(RDW_HARPOON((port + hp_intstat)) & (PHASE | RESET)) && - !(RD_HARPOON(port + hp_scsisig) & SCSI_REQ) && - (RD_HARPOON(port + hp_scsisig) & SCSI_BSY)) ; -} - -static void FPT_SendMsg(unsigned long port, unsigned char message) -{ - while (!(RD_HARPOON(port + hp_scsisig) & SCSI_REQ)) { - if (!(RD_HARPOON(port + hp_scsisig) & SCSI_BSY)) { - - WRW_HARPOON((port + hp_intstat), PHASE); - return; - } - } - - WRW_HARPOON((port + hp_intstat), PHASE); - if ((RD_HARPOON(port + hp_scsisig) & S_SCSI_PHZ) == S_MSGO_PH) { - WRW_HARPOON((port + hp_intstat), - (BUS_FREE | PHASE | XFER_CNT_0)); - - WR_HARPOON(port + hp_portctrl_0, SCSI_BUS_EN); - - WR_HARPOON(port + hp_scsidata_0, message); - - WR_HARPOON(port + hp_scsisig, (SCSI_ACK + S_ILL_PH)); - - ACCEPT_MSG(port); - - WR_HARPOON(port + hp_portctrl_0, 0x00); - - if ((message == SMABORT) || (message == SMDEV_RESET) || - (message == SMABORT_TAG)) { - while (! - (RDW_HARPOON((port + hp_intstat)) & - (BUS_FREE | PHASE))) { - } - - if (RDW_HARPOON((port + hp_intstat)) & BUS_FREE) { - WRW_HARPOON((port + hp_intstat), BUS_FREE); - } - } - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sdecm - * - * Description: Determine the proper response to the message from the - * target device. - * - *---------------------------------------------------------------------*/ -static void FPT_sdecm(unsigned char message, unsigned long port, - unsigned char p_card) -{ - struct sccb *currSCCB; - struct sccb_card *CurrCard; - struct sccb_mgr_tar_info *currTar_Info; - - CurrCard = &FPT_BL_Card[p_card]; - currSCCB = CurrCard->currentSCCB; - - currTar_Info = &FPT_sccbMgrTbl[p_card][currSCCB->TargID]; - - if (message == SMREST_DATA_PTR) { - if (!(currSCCB->Sccb_XferState & F_NO_DATA_YET)) { - currSCCB->Sccb_ATC = currSCCB->Sccb_savedATC; - - FPT_hostDataXferRestart(currSCCB); - } - - ACCEPT_MSG(port); - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - - else if (message == SMCMD_COMP) { - - if (currSCCB->Sccb_scsistat == SELECT_Q_ST) { - currTar_Info->TarStatus &= - ~(unsigned char)TAR_TAG_Q_MASK; - currTar_Info->TarStatus |= (unsigned char)TAG_Q_REJECT; - } - - ACCEPT_MSG(port); - - } - - else if ((message == SMNO_OP) || (message >= SMIDENT) - || (message == SMINIT_RECOVERY) || (message == SMREL_RECOVERY)) { - - ACCEPT_MSG(port); - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - - else if (message == SMREJECT) { - - if ((currSCCB->Sccb_scsistat == SELECT_SN_ST) || - (currSCCB->Sccb_scsistat == SELECT_WN_ST) || - ((currTar_Info->TarStatus & TAR_SYNC_MASK) == SYNC_TRYING) - || ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == - TAG_Q_TRYING)) - { - WRW_HARPOON((port + hp_intstat), BUS_FREE); - - ACCEPT_MSG(port); - - while ((!(RD_HARPOON(port + hp_scsisig) & SCSI_REQ)) && - (!(RDW_HARPOON((port + hp_intstat)) & BUS_FREE))) - { - } - - if (currSCCB->Lun == 0x00) { - if ((currSCCB->Sccb_scsistat == SELECT_SN_ST)) { - - currTar_Info->TarStatus |= - (unsigned char)SYNC_SUPPORTED; - - currTar_Info->TarEEValue &= - ~EE_SYNC_MASK; - } - - else if ((currSCCB->Sccb_scsistat == - SELECT_WN_ST)) { - - currTar_Info->TarStatus = - (currTar_Info-> - TarStatus & ~WIDE_ENABLED) | - WIDE_NEGOCIATED; - - currTar_Info->TarEEValue &= - ~EE_WIDE_SCSI; - - } - - else if ((currTar_Info-> - TarStatus & TAR_TAG_Q_MASK) == - TAG_Q_TRYING) { - currTar_Info->TarStatus = - (currTar_Info-> - TarStatus & ~(unsigned char) - TAR_TAG_Q_MASK) | TAG_Q_REJECT; - - currSCCB->ControlByte &= ~F_USE_CMD_Q; - CurrCard->discQCount--; - CurrCard->discQ_Tbl[currSCCB-> - Sccb_tag] = NULL; - currSCCB->Sccb_tag = 0x00; - - } - } - - if (RDW_HARPOON((port + hp_intstat)) & BUS_FREE) { - - if (currSCCB->Lun == 0x00) { - WRW_HARPOON((port + hp_intstat), - BUS_FREE); - CurrCard->globalFlags |= F_NEW_SCCB_CMD; - } - } - - else { - - if ((CurrCard->globalFlags & F_CONLUN_IO) && - ((currTar_Info-> - TarStatus & TAR_TAG_Q_MASK) != - TAG_Q_TRYING)) - currTar_Info->TarLUNBusy[currSCCB-> - Lun] = 1; - else - currTar_Info->TarLUNBusy[0] = 1; - - currSCCB->ControlByte &= - ~(unsigned char)F_USE_CMD_Q; - - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - - } - } - - else { - ACCEPT_MSG(port); - - while ((!(RD_HARPOON(port + hp_scsisig) & SCSI_REQ)) && - (!(RDW_HARPOON((port + hp_intstat)) & BUS_FREE))) - { - } - - if (!(RDW_HARPOON((port + hp_intstat)) & BUS_FREE)) { - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - } - } - - else if (message == SMEXT) { - - ACCEPT_MSG(port); - FPT_shandem(port, p_card, currSCCB); - } - - else if (message == SMIGNORWR) { - - ACCEPT_MSG(port); /* ACK the RESIDUE MSG */ - - message = FPT_sfm(port, currSCCB); - - if (currSCCB->Sccb_scsimsg != SMPARITY) - ACCEPT_MSG(port); - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - - else { - - currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL; - currSCCB->Sccb_scsimsg = SMREJECT; - - ACCEPT_MSG_ATN(port); - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_shandem - * - * Description: Decide what to do with the extended message. - * - *---------------------------------------------------------------------*/ -static void FPT_shandem(unsigned long port, unsigned char p_card, - struct sccb *pCurrSCCB) -{ - unsigned char length, message; - - length = FPT_sfm(port, pCurrSCCB); - if (length) { - - ACCEPT_MSG(port); - message = FPT_sfm(port, pCurrSCCB); - if (message) { - - if (message == SMSYNC) { - - if (length == 0x03) { - - ACCEPT_MSG(port); - FPT_stsyncn(port, p_card); - } else { - - pCurrSCCB->Sccb_scsimsg = SMREJECT; - ACCEPT_MSG_ATN(port); - } - } else if (message == SMWDTR) { - - if (length == 0x02) { - - ACCEPT_MSG(port); - FPT_stwidn(port, p_card); - } else { - - pCurrSCCB->Sccb_scsimsg = SMREJECT; - ACCEPT_MSG_ATN(port); - - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + - DISCONNECT_START)); - } - } else { - - pCurrSCCB->Sccb_scsimsg = SMREJECT; - ACCEPT_MSG_ATN(port); - - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - } else { - if (pCurrSCCB->Sccb_scsimsg != SMPARITY) - ACCEPT_MSG(port); - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - } else { - if (pCurrSCCB->Sccb_scsimsg == SMPARITY) - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sisyncn - * - * Description: Read in a message byte from the SCSI bus, and check - * for a parity error. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_sisyncn(unsigned long port, unsigned char p_card, - unsigned char syncFlag) -{ - struct sccb *currSCCB; - struct sccb_mgr_tar_info *currTar_Info; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - currTar_Info = &FPT_sccbMgrTbl[p_card][currSCCB->TargID]; - - if (!((currTar_Info->TarStatus & TAR_SYNC_MASK) == SYNC_TRYING)) { - - WRW_HARPOON((port + ID_MSG_STRT), - (MPM_OP + AMSG_OUT + - (currSCCB-> - Sccb_idmsg & ~(unsigned char)DISC_PRIV))); - - WRW_HARPOON((port + ID_MSG_STRT + 2), BRH_OP + ALWAYS + CMDPZ); - - WRW_HARPOON((port + SYNC_MSGS + 0), - (MPM_OP + AMSG_OUT + SMEXT)); - WRW_HARPOON((port + SYNC_MSGS + 2), (MPM_OP + AMSG_OUT + 0x03)); - WRW_HARPOON((port + SYNC_MSGS + 4), - (MPM_OP + AMSG_OUT + SMSYNC)); - - if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_20MB) - - WRW_HARPOON((port + SYNC_MSGS + 6), - (MPM_OP + AMSG_OUT + 12)); - - else if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == - EE_SYNC_10MB) - - WRW_HARPOON((port + SYNC_MSGS + 6), - (MPM_OP + AMSG_OUT + 25)); - - else if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == - EE_SYNC_5MB) - - WRW_HARPOON((port + SYNC_MSGS + 6), - (MPM_OP + AMSG_OUT + 50)); - - else - WRW_HARPOON((port + SYNC_MSGS + 6), - (MPM_OP + AMSG_OUT + 00)); - - WRW_HARPOON((port + SYNC_MSGS + 8), (RAT_OP)); - WRW_HARPOON((port + SYNC_MSGS + 10), - (MPM_OP + AMSG_OUT + DEFAULT_OFFSET)); - WRW_HARPOON((port + SYNC_MSGS + 12), (BRH_OP + ALWAYS + NP)); - - if (syncFlag == 0) { - WR_HARPOON(port + hp_autostart_3, - (SELECT + SELCHK_STRT)); - currTar_Info->TarStatus = - ((currTar_Info-> - TarStatus & ~(unsigned char)TAR_SYNC_MASK) | - (unsigned char)SYNC_TRYING); - } else { - WR_HARPOON(port + hp_autostart_3, - (AUTO_IMMED + CMD_ONLY_STRT)); - } - - return 1; - } - - else { - - currTar_Info->TarStatus |= (unsigned char)SYNC_SUPPORTED; - currTar_Info->TarEEValue &= ~EE_SYNC_MASK; - return 0; - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_stsyncn - * - * Description: The has sent us a Sync Nego message so handle it as - * necessary. - * - *---------------------------------------------------------------------*/ -static void FPT_stsyncn(unsigned long port, unsigned char p_card) -{ - unsigned char sync_msg, offset, sync_reg, our_sync_msg; - struct sccb *currSCCB; - struct sccb_mgr_tar_info *currTar_Info; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - currTar_Info = &FPT_sccbMgrTbl[p_card][currSCCB->TargID]; - - sync_msg = FPT_sfm(port, currSCCB); - - if ((sync_msg == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY)) { - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - return; - } - - ACCEPT_MSG(port); - - offset = FPT_sfm(port, currSCCB); - - if ((offset == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY)) { - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - return; - } - - if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_20MB) - - our_sync_msg = 12; /* Setup our Message to 20mb/s */ - - else if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_10MB) - - our_sync_msg = 25; /* Setup our Message to 10mb/s */ - - else if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_5MB) - - our_sync_msg = 50; /* Setup our Message to 5mb/s */ - else - - our_sync_msg = 0; /* Message = Async */ - - if (sync_msg < our_sync_msg) { - sync_msg = our_sync_msg; /*if faster, then set to max. */ - } - - if (offset == ASYNC) - sync_msg = ASYNC; - - if (offset > MAX_OFFSET) - offset = MAX_OFFSET; - - sync_reg = 0x00; - - if (sync_msg > 12) - - sync_reg = 0x20; /* Use 10MB/s */ - - if (sync_msg > 25) - - sync_reg = 0x40; /* Use 6.6MB/s */ - - if (sync_msg > 38) - - sync_reg = 0x60; /* Use 5MB/s */ - - if (sync_msg > 50) - - sync_reg = 0x80; /* Use 4MB/s */ - - if (sync_msg > 62) - - sync_reg = 0xA0; /* Use 3.33MB/s */ - - if (sync_msg > 75) - - sync_reg = 0xC0; /* Use 2.85MB/s */ - - if (sync_msg > 87) - - sync_reg = 0xE0; /* Use 2.5MB/s */ - - if (sync_msg > 100) { - - sync_reg = 0x00; /* Use ASYNC */ - offset = 0x00; - } - - if (currTar_Info->TarStatus & WIDE_ENABLED) - - sync_reg |= offset; - - else - - sync_reg |= (offset | NARROW_SCSI); - - FPT_sssyncv(port, currSCCB->TargID, sync_reg, currTar_Info); - - if (currSCCB->Sccb_scsistat == SELECT_SN_ST) { - - ACCEPT_MSG(port); - - currTar_Info->TarStatus = ((currTar_Info->TarStatus & - ~(unsigned char)TAR_SYNC_MASK) | - (unsigned char)SYNC_SUPPORTED); - - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - - else { - - ACCEPT_MSG_ATN(port); - - FPT_sisyncr(port, sync_msg, offset); - - currTar_Info->TarStatus = ((currTar_Info->TarStatus & - ~(unsigned char)TAR_SYNC_MASK) | - (unsigned char)SYNC_SUPPORTED); - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sisyncr - * - * Description: Answer the targets sync message. - * - *---------------------------------------------------------------------*/ -static void FPT_sisyncr(unsigned long port, unsigned char sync_pulse, - unsigned char offset) -{ - ARAM_ACCESS(port); - WRW_HARPOON((port + SYNC_MSGS + 0), (MPM_OP + AMSG_OUT + SMEXT)); - WRW_HARPOON((port + SYNC_MSGS + 2), (MPM_OP + AMSG_OUT + 0x03)); - WRW_HARPOON((port + SYNC_MSGS + 4), (MPM_OP + AMSG_OUT + SMSYNC)); - WRW_HARPOON((port + SYNC_MSGS + 6), (MPM_OP + AMSG_OUT + sync_pulse)); - WRW_HARPOON((port + SYNC_MSGS + 8), (RAT_OP)); - WRW_HARPOON((port + SYNC_MSGS + 10), (MPM_OP + AMSG_OUT + offset)); - WRW_HARPOON((port + SYNC_MSGS + 12), (BRH_OP + ALWAYS + NP)); - SGRAM_ACCESS(port); - - WR_HARPOON(port + hp_portctrl_0, SCSI_PORT); - WRW_HARPOON((port + hp_intstat), CLR_ALL_INT_1); - - WR_HARPOON(port + hp_autostart_3, (AUTO_IMMED + CMD_ONLY_STRT)); - - while (!(RDW_HARPOON((port + hp_intstat)) & (BUS_FREE | AUTO_INT))) { - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_siwidn - * - * Description: Read in a message byte from the SCSI bus, and check - * for a parity error. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_siwidn(unsigned long port, unsigned char p_card) -{ - struct sccb *currSCCB; - struct sccb_mgr_tar_info *currTar_Info; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - currTar_Info = &FPT_sccbMgrTbl[p_card][currSCCB->TargID]; - - if (!((currTar_Info->TarStatus & TAR_WIDE_MASK) == WIDE_NEGOCIATED)) { - - WRW_HARPOON((port + ID_MSG_STRT), - (MPM_OP + AMSG_OUT + - (currSCCB-> - Sccb_idmsg & ~(unsigned char)DISC_PRIV))); - - WRW_HARPOON((port + ID_MSG_STRT + 2), BRH_OP + ALWAYS + CMDPZ); - - WRW_HARPOON((port + SYNC_MSGS + 0), - (MPM_OP + AMSG_OUT + SMEXT)); - WRW_HARPOON((port + SYNC_MSGS + 2), (MPM_OP + AMSG_OUT + 0x02)); - WRW_HARPOON((port + SYNC_MSGS + 4), - (MPM_OP + AMSG_OUT + SMWDTR)); - WRW_HARPOON((port + SYNC_MSGS + 6), (RAT_OP)); - WRW_HARPOON((port + SYNC_MSGS + 8), - (MPM_OP + AMSG_OUT + SM16BIT)); - WRW_HARPOON((port + SYNC_MSGS + 10), (BRH_OP + ALWAYS + NP)); - - WR_HARPOON(port + hp_autostart_3, (SELECT + SELCHK_STRT)); - - currTar_Info->TarStatus = ((currTar_Info->TarStatus & - ~(unsigned char)TAR_WIDE_MASK) | - (unsigned char)WIDE_ENABLED); - - return 1; - } - - else { - - currTar_Info->TarStatus = ((currTar_Info->TarStatus & - ~(unsigned char)TAR_WIDE_MASK) | - WIDE_NEGOCIATED); - - currTar_Info->TarEEValue &= ~EE_WIDE_SCSI; - return 0; - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_stwidn - * - * Description: The has sent us a Wide Nego message so handle it as - * necessary. - * - *---------------------------------------------------------------------*/ -static void FPT_stwidn(unsigned long port, unsigned char p_card) -{ - unsigned char width; - struct sccb *currSCCB; - struct sccb_mgr_tar_info *currTar_Info; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - currTar_Info = &FPT_sccbMgrTbl[p_card][currSCCB->TargID]; - - width = FPT_sfm(port, currSCCB); - - if ((width == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY)) { - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - return; - } - - if (!(currTar_Info->TarEEValue & EE_WIDE_SCSI)) - width = 0; - - if (width) { - currTar_Info->TarStatus |= WIDE_ENABLED; - width = 0; - } else { - width = NARROW_SCSI; - currTar_Info->TarStatus &= ~WIDE_ENABLED; - } - - FPT_sssyncv(port, currSCCB->TargID, width, currTar_Info); - - if (currSCCB->Sccb_scsistat == SELECT_WN_ST) { - - currTar_Info->TarStatus |= WIDE_NEGOCIATED; - - if (! - ((currTar_Info->TarStatus & TAR_SYNC_MASK) == - SYNC_SUPPORTED)) { - ACCEPT_MSG_ATN(port); - ARAM_ACCESS(port); - FPT_sisyncn(port, p_card, 1); - currSCCB->Sccb_scsistat = SELECT_SN_ST; - SGRAM_ACCESS(port); - } else { - ACCEPT_MSG(port); - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - } - - else { - - ACCEPT_MSG_ATN(port); - - if (currTar_Info->TarEEValue & EE_WIDE_SCSI) - width = SM16BIT; - else - width = SM8BIT; - - FPT_siwidr(port, width); - - currTar_Info->TarStatus |= (WIDE_NEGOCIATED | WIDE_ENABLED); - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_siwidr - * - * Description: Answer the targets Wide nego message. - * - *---------------------------------------------------------------------*/ -static void FPT_siwidr(unsigned long port, unsigned char width) -{ - ARAM_ACCESS(port); - WRW_HARPOON((port + SYNC_MSGS + 0), (MPM_OP + AMSG_OUT + SMEXT)); - WRW_HARPOON((port + SYNC_MSGS + 2), (MPM_OP + AMSG_OUT + 0x02)); - WRW_HARPOON((port + SYNC_MSGS + 4), (MPM_OP + AMSG_OUT + SMWDTR)); - WRW_HARPOON((port + SYNC_MSGS + 6), (RAT_OP)); - WRW_HARPOON((port + SYNC_MSGS + 8), (MPM_OP + AMSG_OUT + width)); - WRW_HARPOON((port + SYNC_MSGS + 10), (BRH_OP + ALWAYS + NP)); - SGRAM_ACCESS(port); - - WR_HARPOON(port + hp_portctrl_0, SCSI_PORT); - WRW_HARPOON((port + hp_intstat), CLR_ALL_INT_1); - - WR_HARPOON(port + hp_autostart_3, (AUTO_IMMED + CMD_ONLY_STRT)); - - while (!(RDW_HARPOON((port + hp_intstat)) & (BUS_FREE | AUTO_INT))) { - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sssyncv - * - * Description: Write the desired value to the Sync Register for the - * ID specified. - * - *---------------------------------------------------------------------*/ -static void FPT_sssyncv(unsigned long p_port, unsigned char p_id, - unsigned char p_sync_value, - struct sccb_mgr_tar_info *currTar_Info) -{ - unsigned char index; - - index = p_id; - - switch (index) { - - case 0: - index = 12; /* hp_synctarg_0 */ - break; - case 1: - index = 13; /* hp_synctarg_1 */ - break; - case 2: - index = 14; /* hp_synctarg_2 */ - break; - case 3: - index = 15; /* hp_synctarg_3 */ - break; - case 4: - index = 8; /* hp_synctarg_4 */ - break; - case 5: - index = 9; /* hp_synctarg_5 */ - break; - case 6: - index = 10; /* hp_synctarg_6 */ - break; - case 7: - index = 11; /* hp_synctarg_7 */ - break; - case 8: - index = 4; /* hp_synctarg_8 */ - break; - case 9: - index = 5; /* hp_synctarg_9 */ - break; - case 10: - index = 6; /* hp_synctarg_10 */ - break; - case 11: - index = 7; /* hp_synctarg_11 */ - break; - case 12: - index = 0; /* hp_synctarg_12 */ - break; - case 13: - index = 1; /* hp_synctarg_13 */ - break; - case 14: - index = 2; /* hp_synctarg_14 */ - break; - case 15: - index = 3; /* hp_synctarg_15 */ - - } - - WR_HARPOON(p_port + hp_synctarg_base + index, p_sync_value); - - currTar_Info->TarSyncCtrl = p_sync_value; -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sresb - * - * Description: Reset the desired card's SCSI bus. - * - *---------------------------------------------------------------------*/ -static void FPT_sresb(unsigned long port, unsigned char p_card) -{ - unsigned char scsiID, i; - - struct sccb_mgr_tar_info *currTar_Info; - - WR_HARPOON(port + hp_page_ctrl, - (RD_HARPOON(port + hp_page_ctrl) | G_INT_DISABLE)); - WRW_HARPOON((port + hp_intstat), CLR_ALL_INT); - - WR_HARPOON(port + hp_scsictrl_0, SCSI_RST); - - scsiID = RD_HARPOON(port + hp_seltimeout); - WR_HARPOON(port + hp_seltimeout, TO_5ms); - WRW_HARPOON((port + hp_intstat), TIMEOUT); - - WR_HARPOON(port + hp_portctrl_0, (SCSI_PORT | START_TO)); - - while (!(RDW_HARPOON((port + hp_intstat)) & TIMEOUT)) { - } - - WR_HARPOON(port + hp_seltimeout, scsiID); - - WR_HARPOON(port + hp_scsictrl_0, ENA_SCAM_SEL); - - FPT_Wait(port, TO_5ms); - - WRW_HARPOON((port + hp_intstat), CLR_ALL_INT); - - WR_HARPOON(port + hp_int_mask, (RD_HARPOON(port + hp_int_mask) | 0x00)); - - for (scsiID = 0; scsiID < MAX_SCSI_TAR; scsiID++) { - currTar_Info = &FPT_sccbMgrTbl[p_card][scsiID]; - - if (currTar_Info->TarEEValue & EE_SYNC_MASK) { - currTar_Info->TarSyncCtrl = 0; - currTar_Info->TarStatus &= ~TAR_SYNC_MASK; - } - - if (currTar_Info->TarEEValue & EE_WIDE_SCSI) { - currTar_Info->TarStatus &= ~TAR_WIDE_MASK; - } - - FPT_sssyncv(port, scsiID, NARROW_SCSI, currTar_Info); - - FPT_SccbMgrTableInitTarget(p_card, scsiID); - } - - FPT_BL_Card[p_card].scanIndex = 0x00; - FPT_BL_Card[p_card].currentSCCB = NULL; - FPT_BL_Card[p_card].globalFlags &= ~(F_TAG_STARTED | F_HOST_XFER_ACT - | F_NEW_SCCB_CMD); - FPT_BL_Card[p_card].cmdCounter = 0x00; - FPT_BL_Card[p_card].discQCount = 0x00; - FPT_BL_Card[p_card].tagQ_Lst = 0x01; - - for (i = 0; i < QUEUE_DEPTH; i++) - FPT_BL_Card[p_card].discQ_Tbl[i] = NULL; - - WR_HARPOON(port + hp_page_ctrl, - (RD_HARPOON(port + hp_page_ctrl) & ~G_INT_DISABLE)); - -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_ssenss - * - * Description: Setup for the Auto Sense command. - * - *---------------------------------------------------------------------*/ -static void FPT_ssenss(struct sccb_card *pCurrCard) -{ - unsigned char i; - struct sccb *currSCCB; - - currSCCB = pCurrCard->currentSCCB; - - currSCCB->Save_CdbLen = currSCCB->CdbLength; - - for (i = 0; i < 6; i++) { - - currSCCB->Save_Cdb[i] = currSCCB->Cdb[i]; - } - - currSCCB->CdbLength = SIX_BYTE_CMD; - currSCCB->Cdb[0] = SCSI_REQUEST_SENSE; - currSCCB->Cdb[1] = currSCCB->Cdb[1] & (unsigned char)0xE0; /*Keep LUN. */ - currSCCB->Cdb[2] = 0x00; - currSCCB->Cdb[3] = 0x00; - currSCCB->Cdb[4] = currSCCB->RequestSenseLength; - currSCCB->Cdb[5] = 0x00; - - currSCCB->Sccb_XferCnt = (unsigned long)currSCCB->RequestSenseLength; - - currSCCB->Sccb_ATC = 0x00; - - currSCCB->Sccb_XferState |= F_AUTO_SENSE; - - currSCCB->Sccb_XferState &= ~F_SG_XFER; - - currSCCB->Sccb_idmsg = currSCCB->Sccb_idmsg & ~(unsigned char)DISC_PRIV; - - currSCCB->ControlByte = 0x00; - - currSCCB->Sccb_MGRFlags &= F_STATUSLOADED; -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sxfrp - * - * Description: Transfer data into the bit bucket until the device - * decides to switch phase. - * - *---------------------------------------------------------------------*/ - -static void FPT_sxfrp(unsigned long p_port, unsigned char p_card) -{ - unsigned char curr_phz; - - DISABLE_AUTO(p_port); - - if (FPT_BL_Card[p_card].globalFlags & F_HOST_XFER_ACT) { - - FPT_hostDataXferAbort(p_port, p_card, - FPT_BL_Card[p_card].currentSCCB); - - } - - /* If the Automation handled the end of the transfer then do not - match the phase or we will get out of sync with the ISR. */ - - if (RDW_HARPOON((p_port + hp_intstat)) & - (BUS_FREE | XFER_CNT_0 | AUTO_INT)) - return; - - WR_HARPOON(p_port + hp_xfercnt_0, 0x00); - - curr_phz = RD_HARPOON(p_port + hp_scsisig) & (unsigned char)S_SCSI_PHZ; - - WRW_HARPOON((p_port + hp_intstat), XFER_CNT_0); - - WR_HARPOON(p_port + hp_scsisig, curr_phz); - - while (!(RDW_HARPOON((p_port + hp_intstat)) & (BUS_FREE | RESET)) && - (curr_phz == - (RD_HARPOON(p_port + hp_scsisig) & (unsigned char)S_SCSI_PHZ))) - { - if (curr_phz & (unsigned char)SCSI_IOBIT) { - WR_HARPOON(p_port + hp_portctrl_0, - (SCSI_PORT | HOST_PORT | SCSI_INBIT)); - - if (!(RD_HARPOON(p_port + hp_xferstat) & FIFO_EMPTY)) { - RD_HARPOON(p_port + hp_fifodata_0); - } - } else { - WR_HARPOON(p_port + hp_portctrl_0, - (SCSI_PORT | HOST_PORT | HOST_WRT)); - if (RD_HARPOON(p_port + hp_xferstat) & FIFO_EMPTY) { - WR_HARPOON(p_port + hp_fifodata_0, 0xFA); - } - } - } /* End of While loop for padding data I/O phase */ - - while (!(RDW_HARPOON((p_port + hp_intstat)) & (BUS_FREE | RESET))) { - if (RD_HARPOON(p_port + hp_scsisig) & SCSI_REQ) - break; - } - - WR_HARPOON(p_port + hp_portctrl_0, - (SCSI_PORT | HOST_PORT | SCSI_INBIT)); - while (!(RD_HARPOON(p_port + hp_xferstat) & FIFO_EMPTY)) { - RD_HARPOON(p_port + hp_fifodata_0); - } - - if (!(RDW_HARPOON((p_port + hp_intstat)) & (BUS_FREE | RESET))) { - WR_HARPOON(p_port + hp_autostart_0, - (AUTO_IMMED + DISCONNECT_START)); - while (!(RDW_HARPOON((p_port + hp_intstat)) & AUTO_INT)) { - } - - if (RDW_HARPOON((p_port + hp_intstat)) & - (ICMD_COMP | ITAR_DISC)) - while (! - (RDW_HARPOON((p_port + hp_intstat)) & - (BUS_FREE | RSEL))) ; - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_schkdd - * - * Description: Make sure data has been flushed from both FIFOs and abort - * the operations if necessary. - * - *---------------------------------------------------------------------*/ - -static void FPT_schkdd(unsigned long port, unsigned char p_card) -{ - unsigned short TimeOutLoop; - unsigned char sPhase; - - struct sccb *currSCCB; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - if ((currSCCB->Sccb_scsistat != DATA_OUT_ST) && - (currSCCB->Sccb_scsistat != DATA_IN_ST)) { - return; - } - - if (currSCCB->Sccb_XferState & F_ODD_BALL_CNT) { - - currSCCB->Sccb_ATC += (currSCCB->Sccb_XferCnt - 1); - - currSCCB->Sccb_XferCnt = 1; - - currSCCB->Sccb_XferState &= ~F_ODD_BALL_CNT; - WRW_HARPOON((port + hp_fiforead), (unsigned short)0x00); - WR_HARPOON(port + hp_xferstat, 0x00); - } - - else { - - currSCCB->Sccb_ATC += currSCCB->Sccb_XferCnt; - - currSCCB->Sccb_XferCnt = 0; - } - - if ((RDW_HARPOON((port + hp_intstat)) & PARITY) && - (currSCCB->HostStatus == SCCB_COMPLETE)) { - - currSCCB->HostStatus = SCCB_PARITY_ERR; - WRW_HARPOON((port + hp_intstat), PARITY); - } - - FPT_hostDataXferAbort(port, p_card, currSCCB); - - while (RD_HARPOON(port + hp_scsisig) & SCSI_ACK) { - } - - TimeOutLoop = 0; - - while (RD_HARPOON(port + hp_xferstat) & FIFO_EMPTY) { - if (RDW_HARPOON((port + hp_intstat)) & BUS_FREE) { - return; - } - if (RD_HARPOON(port + hp_offsetctr) & (unsigned char)0x1F) { - break; - } - if (RDW_HARPOON((port + hp_intstat)) & RESET) { - return; - } - if ((RD_HARPOON(port + hp_scsisig) & SCSI_REQ) - || (TimeOutLoop++ > 0x3000)) - break; - } - - sPhase = RD_HARPOON(port + hp_scsisig) & (SCSI_BSY | S_SCSI_PHZ); - if ((!(RD_HARPOON(port + hp_xferstat) & FIFO_EMPTY)) || - (RD_HARPOON(port + hp_offsetctr) & (unsigned char)0x1F) || - (sPhase == (SCSI_BSY | S_DATAO_PH)) || - (sPhase == (SCSI_BSY | S_DATAI_PH))) { - - WR_HARPOON(port + hp_portctrl_0, SCSI_PORT); - - if (!(currSCCB->Sccb_XferState & F_ALL_XFERRED)) { - if (currSCCB->Sccb_XferState & F_HOST_XFER_DIR) { - FPT_phaseDataIn(port, p_card); - } - - else { - FPT_phaseDataOut(port, p_card); - } - } else { - FPT_sxfrp(port, p_card); - if (!(RDW_HARPOON((port + hp_intstat)) & - (BUS_FREE | ICMD_COMP | ITAR_DISC | RESET))) { - WRW_HARPOON((port + hp_intstat), AUTO_INT); - FPT_phaseDecode(port, p_card); - } - } - - } - - else { - WR_HARPOON(port + hp_portctrl_0, 0x00); - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sinits - * - * Description: Setup SCCB manager fields in this SCCB. - * - *---------------------------------------------------------------------*/ - -static void FPT_sinits(struct sccb *p_sccb, unsigned char p_card) -{ - struct sccb_mgr_tar_info *currTar_Info; - - if ((p_sccb->TargID >= MAX_SCSI_TAR) || (p_sccb->Lun >= MAX_LUN)) { - return; - } - currTar_Info = &FPT_sccbMgrTbl[p_card][p_sccb->TargID]; - - p_sccb->Sccb_XferState = 0x00; - p_sccb->Sccb_XferCnt = p_sccb->DataLength; - - if ((p_sccb->OperationCode == SCATTER_GATHER_COMMAND) || - (p_sccb->OperationCode == RESIDUAL_SG_COMMAND)) { - - p_sccb->Sccb_SGoffset = 0; - p_sccb->Sccb_XferState = F_SG_XFER; - p_sccb->Sccb_XferCnt = 0x00; - } - - if (p_sccb->DataLength == 0x00) - - p_sccb->Sccb_XferState |= F_ALL_XFERRED; - - if (p_sccb->ControlByte & F_USE_CMD_Q) { - if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_REJECT) - p_sccb->ControlByte &= ~F_USE_CMD_Q; - - else - currTar_Info->TarStatus |= TAG_Q_TRYING; - } - -/* For !single SCSI device in system & device allow Disconnect - or command is tag_q type then send Cmd with Disconnect Enable - else send Cmd with Disconnect Disable */ - -/* - if (((!(FPT_BL_Card[p_card].globalFlags & F_SINGLE_DEVICE)) && - (currTar_Info->TarStatus & TAR_ALLOW_DISC)) || - (currTar_Info->TarStatus & TAG_Q_TRYING)) { -*/ - if ((currTar_Info->TarStatus & TAR_ALLOW_DISC) || - (currTar_Info->TarStatus & TAG_Q_TRYING)) { - p_sccb->Sccb_idmsg = - (unsigned char)(SMIDENT | DISC_PRIV) | p_sccb->Lun; - } - - else { - - p_sccb->Sccb_idmsg = (unsigned char)SMIDENT | p_sccb->Lun; - } - - p_sccb->HostStatus = 0x00; - p_sccb->TargetStatus = 0x00; - p_sccb->Sccb_tag = 0x00; - p_sccb->Sccb_MGRFlags = 0x00; - p_sccb->Sccb_sgseg = 0x00; - p_sccb->Sccb_ATC = 0x00; - p_sccb->Sccb_savedATC = 0x00; -/* - p_sccb->SccbVirtDataPtr = 0x00; - p_sccb->Sccb_forwardlink = NULL; - p_sccb->Sccb_backlink = NULL; - */ - p_sccb->Sccb_scsistat = BUS_FREE_ST; - p_sccb->SccbStatus = SCCB_IN_PROCESS; - p_sccb->Sccb_scsimsg = SMNO_OP; - -} - -/*--------------------------------------------------------------------- - * - * Function: Phase Decode - * - * Description: Determine the phase and call the appropriate function. - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseDecode(unsigned long p_port, unsigned char p_card) -{ - unsigned char phase_ref; - void (*phase) (unsigned long, unsigned char); - - DISABLE_AUTO(p_port); - - phase_ref = - (unsigned char)(RD_HARPOON(p_port + hp_scsisig) & S_SCSI_PHZ); - - phase = FPT_s_PhaseTbl[phase_ref]; - - (*phase) (p_port, p_card); /* Call the correct phase func */ -} - -/*--------------------------------------------------------------------- - * - * Function: Data Out Phase - * - * Description: Start up both the BusMaster and Xbow. - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseDataOut(unsigned long port, unsigned char p_card) -{ - - struct sccb *currSCCB; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - if (currSCCB == NULL) { - return; /* Exit if No SCCB record */ - } - - currSCCB->Sccb_scsistat = DATA_OUT_ST; - currSCCB->Sccb_XferState &= ~(F_HOST_XFER_DIR | F_NO_DATA_YET); - - WR_HARPOON(port + hp_portctrl_0, SCSI_PORT); - - WRW_HARPOON((port + hp_intstat), XFER_CNT_0); - - WR_HARPOON(port + hp_autostart_0, (END_DATA + END_DATA_START)); - - FPT_dataXferProcessor(port, &FPT_BL_Card[p_card]); - - if (currSCCB->Sccb_XferCnt == 0) { - - if ((currSCCB->ControlByte & SCCB_DATA_XFER_OUT) && - (currSCCB->HostStatus == SCCB_COMPLETE)) - currSCCB->HostStatus = SCCB_DATA_OVER_RUN; - - FPT_sxfrp(port, p_card); - if (!(RDW_HARPOON((port + hp_intstat)) & (BUS_FREE | RESET))) - FPT_phaseDecode(port, p_card); - } -} - -/*--------------------------------------------------------------------- - * - * Function: Data In Phase - * - * Description: Startup the BusMaster and the XBOW. - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseDataIn(unsigned long port, unsigned char p_card) -{ - - struct sccb *currSCCB; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - if (currSCCB == NULL) { - return; /* Exit if No SCCB record */ - } - - currSCCB->Sccb_scsistat = DATA_IN_ST; - currSCCB->Sccb_XferState |= F_HOST_XFER_DIR; - currSCCB->Sccb_XferState &= ~F_NO_DATA_YET; - - WR_HARPOON(port + hp_portctrl_0, SCSI_PORT); - - WRW_HARPOON((port + hp_intstat), XFER_CNT_0); - - WR_HARPOON(port + hp_autostart_0, (END_DATA + END_DATA_START)); - - FPT_dataXferProcessor(port, &FPT_BL_Card[p_card]); - - if (currSCCB->Sccb_XferCnt == 0) { - - if ((currSCCB->ControlByte & SCCB_DATA_XFER_IN) && - (currSCCB->HostStatus == SCCB_COMPLETE)) - currSCCB->HostStatus = SCCB_DATA_OVER_RUN; - - FPT_sxfrp(port, p_card); - if (!(RDW_HARPOON((port + hp_intstat)) & (BUS_FREE | RESET))) - FPT_phaseDecode(port, p_card); - - } -} - -/*--------------------------------------------------------------------- - * - * Function: Command Phase - * - * Description: Load the CDB into the automation and start it up. - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseCommand(unsigned long p_port, unsigned char p_card) -{ - struct sccb *currSCCB; - unsigned long cdb_reg; - unsigned char i; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - if (currSCCB->OperationCode == RESET_COMMAND) { - - currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL; - currSCCB->CdbLength = SIX_BYTE_CMD; - } - - WR_HARPOON(p_port + hp_scsisig, 0x00); - - ARAM_ACCESS(p_port); - - cdb_reg = p_port + CMD_STRT; - - for (i = 0; i < currSCCB->CdbLength; i++) { - - if (currSCCB->OperationCode == RESET_COMMAND) - - WRW_HARPOON(cdb_reg, (MPM_OP + ACOMMAND + 0x00)); - - else - WRW_HARPOON(cdb_reg, - (MPM_OP + ACOMMAND + currSCCB->Cdb[i])); - cdb_reg += 2; - } - - if (currSCCB->CdbLength != TWELVE_BYTE_CMD) - WRW_HARPOON(cdb_reg, (BRH_OP + ALWAYS + NP)); - - WR_HARPOON(p_port + hp_portctrl_0, (SCSI_PORT)); - - currSCCB->Sccb_scsistat = COMMAND_ST; - - WR_HARPOON(p_port + hp_autostart_3, (AUTO_IMMED | CMD_ONLY_STRT)); - SGRAM_ACCESS(p_port); -} - -/*--------------------------------------------------------------------- - * - * Function: Status phase - * - * Description: Bring in the status and command complete message bytes - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseStatus(unsigned long port, unsigned char p_card) -{ - /* Start-up the automation to finish off this command and let the - isr handle the interrupt for command complete when it comes in. - We could wait here for the interrupt to be generated? - */ - - WR_HARPOON(port + hp_scsisig, 0x00); - - WR_HARPOON(port + hp_autostart_0, (AUTO_IMMED + END_DATA_START)); -} - -/*--------------------------------------------------------------------- - * - * Function: Phase Message Out - * - * Description: Send out our message (if we have one) and handle whatever - * else is involed. - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseMsgOut(unsigned long port, unsigned char p_card) -{ - unsigned char message, scsiID; - struct sccb *currSCCB; - struct sccb_mgr_tar_info *currTar_Info; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - if (currSCCB != NULL) { - - message = currSCCB->Sccb_scsimsg; - scsiID = currSCCB->TargID; - - if (message == SMDEV_RESET) { - - currTar_Info = &FPT_sccbMgrTbl[p_card][scsiID]; - currTar_Info->TarSyncCtrl = 0; - FPT_sssyncv(port, scsiID, NARROW_SCSI, currTar_Info); - - if (FPT_sccbMgrTbl[p_card][scsiID]. - TarEEValue & EE_SYNC_MASK) { - - FPT_sccbMgrTbl[p_card][scsiID].TarStatus &= - ~TAR_SYNC_MASK; - - } - - if (FPT_sccbMgrTbl[p_card][scsiID]. - TarEEValue & EE_WIDE_SCSI) { - - FPT_sccbMgrTbl[p_card][scsiID].TarStatus &= - ~TAR_WIDE_MASK; - } - - FPT_queueFlushSccb(p_card, SCCB_COMPLETE); - FPT_SccbMgrTableInitTarget(p_card, scsiID); - } else if (currSCCB->Sccb_scsistat == ABORT_ST) { - currSCCB->HostStatus = SCCB_COMPLETE; - if (FPT_BL_Card[p_card].discQ_Tbl[currSCCB->Sccb_tag] != - NULL) { - FPT_BL_Card[p_card].discQ_Tbl[currSCCB-> - Sccb_tag] = NULL; - FPT_sccbMgrTbl[p_card][scsiID].TarTagQ_Cnt--; - } - - } - - else if (currSCCB->Sccb_scsistat < COMMAND_ST) { - - if (message == SMNO_OP) { - currSCCB->Sccb_MGRFlags |= F_DEV_SELECTED; - - FPT_ssel(port, p_card); - return; - } - } else { - - if (message == SMABORT) - - FPT_queueFlushSccb(p_card, SCCB_COMPLETE); - } - - } else { - message = SMABORT; - } - - WRW_HARPOON((port + hp_intstat), (BUS_FREE | PHASE | XFER_CNT_0)); - - WR_HARPOON(port + hp_portctrl_0, SCSI_BUS_EN); - - WR_HARPOON(port + hp_scsidata_0, message); - - WR_HARPOON(port + hp_scsisig, (SCSI_ACK + S_ILL_PH)); - - ACCEPT_MSG(port); - - WR_HARPOON(port + hp_portctrl_0, 0x00); - - if ((message == SMABORT) || (message == SMDEV_RESET) || - (message == SMABORT_TAG)) { - - while (!(RDW_HARPOON((port + hp_intstat)) & (BUS_FREE | PHASE))) { - } - - if (RDW_HARPOON((port + hp_intstat)) & BUS_FREE) { - WRW_HARPOON((port + hp_intstat), BUS_FREE); - - if (currSCCB != NULL) { - - if ((FPT_BL_Card[p_card]. - globalFlags & F_CONLUN_IO) - && - ((FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & TAR_TAG_Q_MASK) != - TAG_Q_TRYING)) - FPT_sccbMgrTbl[p_card][currSCCB-> - TargID]. - TarLUNBusy[currSCCB->Lun] = 0; - else - FPT_sccbMgrTbl[p_card][currSCCB-> - TargID]. - TarLUNBusy[0] = 0; - - FPT_queueCmdComplete(&FPT_BL_Card[p_card], - currSCCB, p_card); - } - - else { - FPT_BL_Card[p_card].globalFlags |= - F_NEW_SCCB_CMD; - } - } - - else { - - FPT_sxfrp(port, p_card); - } - } - - else { - - if (message == SMPARITY) { - currSCCB->Sccb_scsimsg = SMNO_OP; - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } else { - FPT_sxfrp(port, p_card); - } - } -} - -/*--------------------------------------------------------------------- - * - * Function: Message In phase - * - * Description: Bring in the message and determine what to do with it. - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseMsgIn(unsigned long port, unsigned char p_card) -{ - unsigned char message; - struct sccb *currSCCB; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - if (FPT_BL_Card[p_card].globalFlags & F_HOST_XFER_ACT) { - - FPT_phaseChkFifo(port, p_card); - } - - message = RD_HARPOON(port + hp_scsidata_0); - if ((message == SMDISC) || (message == SMSAVE_DATA_PTR)) { - - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + END_DATA_START)); - - } - - else { - - message = FPT_sfm(port, currSCCB); - if (message) { - - FPT_sdecm(message, port, p_card); - - } else { - if (currSCCB->Sccb_scsimsg != SMPARITY) - ACCEPT_MSG(port); - WR_HARPOON(port + hp_autostart_1, - (AUTO_IMMED + DISCONNECT_START)); - } - } - -} - -/*--------------------------------------------------------------------- - * - * Function: Illegal phase - * - * Description: Target switched to some illegal phase, so all we can do - * is report an error back to the host (if that is possible) - * and send an ABORT message to the misbehaving target. - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseIllegal(unsigned long port, unsigned char p_card) -{ - struct sccb *currSCCB; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - WR_HARPOON(port + hp_scsisig, RD_HARPOON(port + hp_scsisig)); - if (currSCCB != NULL) { - - currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL; - currSCCB->Sccb_scsistat = ABORT_ST; - currSCCB->Sccb_scsimsg = SMABORT; - } - - ACCEPT_MSG_ATN(port); -} - -/*--------------------------------------------------------------------- - * - * Function: Phase Check FIFO - * - * Description: Make sure data has been flushed from both FIFOs and abort - * the operations if necessary. - * - *---------------------------------------------------------------------*/ - -static void FPT_phaseChkFifo(unsigned long port, unsigned char p_card) -{ - unsigned long xfercnt; - struct sccb *currSCCB; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - if (currSCCB->Sccb_scsistat == DATA_IN_ST) { - - while ((!(RD_HARPOON(port + hp_xferstat) & FIFO_EMPTY)) && - (RD_HARPOON(port + hp_ext_status) & BM_CMD_BUSY)) { - } - - if (!(RD_HARPOON(port + hp_xferstat) & FIFO_EMPTY)) { - currSCCB->Sccb_ATC += currSCCB->Sccb_XferCnt; - - currSCCB->Sccb_XferCnt = 0; - - if ((RDW_HARPOON((port + hp_intstat)) & PARITY) && - (currSCCB->HostStatus == SCCB_COMPLETE)) { - currSCCB->HostStatus = SCCB_PARITY_ERR; - WRW_HARPOON((port + hp_intstat), PARITY); - } - - FPT_hostDataXferAbort(port, p_card, currSCCB); - - FPT_dataXferProcessor(port, &FPT_BL_Card[p_card]); - - while ((!(RD_HARPOON(port + hp_xferstat) & FIFO_EMPTY)) - && (RD_HARPOON(port + hp_ext_status) & - BM_CMD_BUSY)) { - } - - } - } - - /*End Data In specific code. */ - GET_XFER_CNT(port, xfercnt); - - WR_HARPOON(port + hp_xfercnt_0, 0x00); - - WR_HARPOON(port + hp_portctrl_0, 0x00); - - currSCCB->Sccb_ATC += (currSCCB->Sccb_XferCnt - xfercnt); - - currSCCB->Sccb_XferCnt = xfercnt; - - if ((RDW_HARPOON((port + hp_intstat)) & PARITY) && - (currSCCB->HostStatus == SCCB_COMPLETE)) { - - currSCCB->HostStatus = SCCB_PARITY_ERR; - WRW_HARPOON((port + hp_intstat), PARITY); - } - - FPT_hostDataXferAbort(port, p_card, currSCCB); - - WR_HARPOON(port + hp_fifowrite, 0x00); - WR_HARPOON(port + hp_fiforead, 0x00); - WR_HARPOON(port + hp_xferstat, 0x00); - - WRW_HARPOON((port + hp_intstat), XFER_CNT_0); -} - -/*--------------------------------------------------------------------- - * - * Function: Phase Bus Free - * - * Description: We just went bus free so figure out if it was - * because of command complete or from a disconnect. - * - *---------------------------------------------------------------------*/ -static void FPT_phaseBusFree(unsigned long port, unsigned char p_card) -{ - struct sccb *currSCCB; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - if (currSCCB != NULL) { - - DISABLE_AUTO(port); - - if (currSCCB->OperationCode == RESET_COMMAND) { - - if ((FPT_BL_Card[p_card].globalFlags & F_CONLUN_IO) && - ((FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)) - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[currSCCB->Lun] = 0; - else - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[0] = 0; - - FPT_queueCmdComplete(&FPT_BL_Card[p_card], currSCCB, - p_card); - - FPT_queueSearchSelect(&FPT_BL_Card[p_card], p_card); - - } - - else if (currSCCB->Sccb_scsistat == SELECT_SN_ST) { - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarStatus |= - (unsigned char)SYNC_SUPPORTED; - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue &= - ~EE_SYNC_MASK; - } - - else if (currSCCB->Sccb_scsistat == SELECT_WN_ST) { - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarStatus = - (FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & ~WIDE_ENABLED) | WIDE_NEGOCIATED; - - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue &= - ~EE_WIDE_SCSI; - } - - else if (currSCCB->Sccb_scsistat == SELECT_Q_ST) { - /* Make sure this is not a phony BUS_FREE. If we were - reselected or if BUSY is NOT on then this is a - valid BUS FREE. SRR Wednesday, 5/10/1995. */ - - if ((!(RD_HARPOON(port + hp_scsisig) & SCSI_BSY)) || - (RDW_HARPOON((port + hp_intstat)) & RSEL)) { - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus &= ~TAR_TAG_Q_MASK; - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus |= TAG_Q_REJECT; - } - - else { - return; - } - } - - else { - - currSCCB->Sccb_scsistat = BUS_FREE_ST; - - if (!currSCCB->HostStatus) { - currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL; - } - - if ((FPT_BL_Card[p_card].globalFlags & F_CONLUN_IO) && - ((FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)) - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[currSCCB->Lun] = 0; - else - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[0] = 0; - - FPT_queueCmdComplete(&FPT_BL_Card[p_card], currSCCB, - p_card); - return; - } - - FPT_BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD; - - } /*end if !=null */ -} - -/*--------------------------------------------------------------------- - * - * Function: Auto Load Default Map - * - * Description: Load the Automation RAM with the defualt map values. - * - *---------------------------------------------------------------------*/ -static void FPT_autoLoadDefaultMap(unsigned long p_port) -{ - unsigned long map_addr; - - ARAM_ACCESS(p_port); - map_addr = p_port + hp_aramBase; - - WRW_HARPOON(map_addr, (MPM_OP + AMSG_OUT + 0xC0)); /*ID MESSAGE */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + AMSG_OUT + 0x20)); /*SIMPLE TAG QUEUEING MSG */ - map_addr += 2; - WRW_HARPOON(map_addr, RAT_OP); /*RESET ATTENTION */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + AMSG_OUT + 0x00)); /*TAG ID MSG */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 0 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 1 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 2 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 3 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 4 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 5 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 6 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 7 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 8 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 9 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 10 */ - map_addr += 2; - WRW_HARPOON(map_addr, (MPM_OP + ACOMMAND + 0x00)); /*CDB BYTE 11 */ - map_addr += 2; - WRW_HARPOON(map_addr, (CPE_OP + ADATA_OUT + DINT)); /*JUMP IF DATA OUT */ - map_addr += 2; - WRW_HARPOON(map_addr, (TCB_OP + FIFO_0 + DI)); /*JUMP IF NO DATA IN FIFO */ - map_addr += 2; /*This means AYNC DATA IN */ - WRW_HARPOON(map_addr, (SSI_OP + SSI_IDO_STRT)); /*STOP AND INTERRUPT */ - map_addr += 2; - WRW_HARPOON(map_addr, (CPE_OP + ADATA_IN + DINT)); /*JUMP IF NOT DATA IN PHZ */ - map_addr += 2; - WRW_HARPOON(map_addr, (CPN_OP + AMSG_IN + ST)); /*IF NOT MSG IN CHECK 4 DATA IN */ - map_addr += 2; - WRW_HARPOON(map_addr, (CRD_OP + SDATA + 0x02)); /*SAVE DATA PTR MSG? */ - map_addr += 2; - WRW_HARPOON(map_addr, (BRH_OP + NOT_EQ + DC)); /*GO CHECK FOR DISCONNECT MSG */ - map_addr += 2; - WRW_HARPOON(map_addr, (MRR_OP + SDATA + D_AR1)); /*SAVE DATA PTRS MSG */ - map_addr += 2; - WRW_HARPOON(map_addr, (CPN_OP + AMSG_IN + ST)); /*IF NOT MSG IN CHECK DATA IN */ - map_addr += 2; - WRW_HARPOON(map_addr, (CRD_OP + SDATA + 0x04)); /*DISCONNECT MSG? */ - map_addr += 2; - WRW_HARPOON(map_addr, (BRH_OP + NOT_EQ + UNKNWN)); /*UKNKNOWN MSG */ - map_addr += 2; - WRW_HARPOON(map_addr, (MRR_OP + SDATA + D_BUCKET)); /*XFER DISCONNECT MSG */ - map_addr += 2; - WRW_HARPOON(map_addr, (SSI_OP + SSI_ITAR_DISC)); /*STOP AND INTERRUPT */ - map_addr += 2; - WRW_HARPOON(map_addr, (CPN_OP + ASTATUS + UNKNWN)); /*JUMP IF NOT STATUS PHZ. */ - map_addr += 2; - WRW_HARPOON(map_addr, (MRR_OP + SDATA + D_AR0)); /*GET STATUS BYTE */ - map_addr += 2; - WRW_HARPOON(map_addr, (CPN_OP + AMSG_IN + CC)); /*ERROR IF NOT MSG IN PHZ */ - map_addr += 2; - WRW_HARPOON(map_addr, (CRD_OP + SDATA + 0x00)); /*CHECK FOR CMD COMPLETE MSG. */ - map_addr += 2; - WRW_HARPOON(map_addr, (BRH_OP + NOT_EQ + CC)); /*ERROR IF NOT CMD COMPLETE MSG. */ - map_addr += 2; - WRW_HARPOON(map_addr, (MRR_OP + SDATA + D_BUCKET)); /*GET CMD COMPLETE MSG */ - map_addr += 2; - WRW_HARPOON(map_addr, (SSI_OP + SSI_ICMD_COMP)); /*END OF COMMAND */ - map_addr += 2; - - WRW_HARPOON(map_addr, (SSI_OP + SSI_IUNKWN)); /*RECEIVED UNKNOWN MSG BYTE */ - map_addr += 2; - WRW_HARPOON(map_addr, (SSI_OP + SSI_INO_CC)); /*NO COMMAND COMPLETE AFTER STATUS */ - map_addr += 2; - WRW_HARPOON(map_addr, (SSI_OP + SSI_ITICKLE)); /*BIOS Tickled the Mgr */ - map_addr += 2; - WRW_HARPOON(map_addr, (SSI_OP + SSI_IRFAIL)); /*EXPECTED ID/TAG MESSAGES AND */ - map_addr += 2; /* DIDN'T GET ONE */ - WRW_HARPOON(map_addr, (CRR_OP + AR3 + S_IDREG)); /* comp SCSI SEL ID & AR3 */ - map_addr += 2; - WRW_HARPOON(map_addr, (BRH_OP + EQUAL + 0x00)); /*SEL ID OK then Conti. */ - map_addr += 2; - WRW_HARPOON(map_addr, (SSI_OP + SSI_INO_CC)); /*NO COMMAND COMPLETE AFTER STATUS */ - - SGRAM_ACCESS(p_port); -} - -/*--------------------------------------------------------------------- - * - * Function: Auto Command Complete - * - * Description: Post command back to host and find another command - * to execute. - * - *---------------------------------------------------------------------*/ - -static void FPT_autoCmdCmplt(unsigned long p_port, unsigned char p_card) -{ - struct sccb *currSCCB; - unsigned char status_byte; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - - status_byte = RD_HARPOON(p_port + hp_gp_reg_0); - - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarLUN_CA = 0; - - if (status_byte != SSGOOD) { - - if (status_byte == SSQ_FULL) { - - if (((FPT_BL_Card[p_card].globalFlags & F_CONLUN_IO) && - ((FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))) { - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[currSCCB->Lun] = 1; - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card].discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl[FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - LunDiscQ_Idx[currSCCB->Lun]] = - NULL; - } else { - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[0] = 1; - if (currSCCB->Sccb_tag) { - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card]. - discQCount--; - FPT_BL_Card[p_card].discQ_Tbl[currSCCB-> - Sccb_tag] - = NULL; - } else { - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card]. - discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl[FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - LunDiscQ_Idx[0]] = NULL; - } - } - - currSCCB->Sccb_MGRFlags |= F_STATUSLOADED; - - FPT_queueSelectFail(&FPT_BL_Card[p_card], p_card); - - return; - } - - if (currSCCB->Sccb_scsistat == SELECT_SN_ST) { - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarStatus |= - (unsigned char)SYNC_SUPPORTED; - - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue &= - ~EE_SYNC_MASK; - FPT_BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD; - - if (((FPT_BL_Card[p_card].globalFlags & F_CONLUN_IO) && - ((FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))) { - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[currSCCB->Lun] = 1; - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card].discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl[FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - LunDiscQ_Idx[currSCCB->Lun]] = - NULL; - } else { - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[0] = 1; - if (currSCCB->Sccb_tag) { - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card]. - discQCount--; - FPT_BL_Card[p_card].discQ_Tbl[currSCCB-> - Sccb_tag] - = NULL; - } else { - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card]. - discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl[FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - LunDiscQ_Idx[0]] = NULL; - } - } - return; - - } - - if (currSCCB->Sccb_scsistat == SELECT_WN_ST) { - - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarStatus = - (FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & ~WIDE_ENABLED) | WIDE_NEGOCIATED; - - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue &= - ~EE_WIDE_SCSI; - FPT_BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD; - - if (((FPT_BL_Card[p_card].globalFlags & F_CONLUN_IO) && - ((FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))) { - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[currSCCB->Lun] = 1; - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card].discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl[FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - LunDiscQ_Idx[currSCCB->Lun]] = - NULL; - } else { - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUNBusy[0] = 1; - if (currSCCB->Sccb_tag) { - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card]. - discQCount--; - FPT_BL_Card[p_card].discQ_Tbl[currSCCB-> - Sccb_tag] - = NULL; - } else { - if (FPT_BL_Card[p_card].discQCount != 0) - FPT_BL_Card[p_card]. - discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl[FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - LunDiscQ_Idx[0]] = NULL; - } - } - return; - - } - - if (status_byte == SSCHECK) { - if (FPT_BL_Card[p_card].globalFlags & F_DO_RENEGO) { - if (FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarEEValue & EE_SYNC_MASK) { - FPT_sccbMgrTbl[p_card][currSCCB-> - TargID]. - TarStatus &= ~TAR_SYNC_MASK; - } - if (FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarEEValue & EE_WIDE_SCSI) { - FPT_sccbMgrTbl[p_card][currSCCB-> - TargID]. - TarStatus &= ~TAR_WIDE_MASK; - } - } - } - - if (!(currSCCB->Sccb_XferState & F_AUTO_SENSE)) { - - currSCCB->SccbStatus = SCCB_ERROR; - currSCCB->TargetStatus = status_byte; - - if (status_byte == SSCHECK) { - - FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarLUN_CA = 1; - - if (currSCCB->RequestSenseLength != - NO_AUTO_REQUEST_SENSE) { - - if (currSCCB->RequestSenseLength == 0) - currSCCB->RequestSenseLength = - 14; - - FPT_ssenss(&FPT_BL_Card[p_card]); - FPT_BL_Card[p_card].globalFlags |= - F_NEW_SCCB_CMD; - - if (((FPT_BL_Card[p_card]. - globalFlags & F_CONLUN_IO) - && - ((FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - TarStatus & TAR_TAG_Q_MASK) != - TAG_Q_TRYING))) { - FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - TarLUNBusy[currSCCB->Lun] = - 1; - if (FPT_BL_Card[p_card]. - discQCount != 0) - FPT_BL_Card[p_card]. - discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl[FPT_sccbMgrTbl - [p_card] - [currSCCB-> - TargID]. - LunDiscQ_Idx - [currSCCB->Lun]] = - NULL; - } else { - FPT_sccbMgrTbl[p_card] - [currSCCB->TargID]. - TarLUNBusy[0] = 1; - if (currSCCB->Sccb_tag) { - if (FPT_BL_Card[p_card]. - discQCount != 0) - FPT_BL_Card - [p_card]. - discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl[currSCCB-> - Sccb_tag] - = NULL; - } else { - if (FPT_BL_Card[p_card]. - discQCount != 0) - FPT_BL_Card - [p_card]. - discQCount--; - FPT_BL_Card[p_card]. - discQ_Tbl - [FPT_sccbMgrTbl - [p_card][currSCCB-> - TargID]. - LunDiscQ_Idx[0]] = - NULL; - } - } - return; - } - } - } - } - - if ((FPT_BL_Card[p_card].globalFlags & F_CONLUN_IO) && - ((FPT_sccbMgrTbl[p_card][currSCCB->TargID]. - TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)) - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB-> - Lun] = 0; - else - FPT_sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = 0; - - FPT_queueCmdComplete(&FPT_BL_Card[p_card], currSCCB, p_card); -} - -#define SHORT_WAIT 0x0000000F -#define LONG_WAIT 0x0000FFFFL - -/*--------------------------------------------------------------------- - * - * Function: Data Transfer Processor - * - * Description: This routine performs two tasks. - * (1) Start data transfer by calling HOST_DATA_XFER_START - * function. Once data transfer is started, (2) Depends - * on the type of data transfer mode Scatter/Gather mode - * or NON Scatter/Gather mode. In NON Scatter/Gather mode, - * this routine checks Sccb_MGRFlag (F_HOST_XFER_ACT bit) for - * data transfer done. In Scatter/Gather mode, this routine - * checks bus master command complete and dual rank busy - * bit to keep chaining SC transfer command. Similarly, - * in Scatter/Gather mode, it checks Sccb_MGRFlag - * (F_HOST_XFER_ACT bit) for data transfer done. - * - *---------------------------------------------------------------------*/ - -static void FPT_dataXferProcessor(unsigned long port, - struct sccb_card *pCurrCard) -{ - struct sccb *currSCCB; - - currSCCB = pCurrCard->currentSCCB; - - if (currSCCB->Sccb_XferState & F_SG_XFER) { - if (pCurrCard->globalFlags & F_HOST_XFER_ACT) - { - currSCCB->Sccb_sgseg += (unsigned char)SG_BUF_CNT; - currSCCB->Sccb_SGoffset = 0x00; - } - pCurrCard->globalFlags |= F_HOST_XFER_ACT; - - FPT_busMstrSGDataXferStart(port, currSCCB); - } - - else { - if (!(pCurrCard->globalFlags & F_HOST_XFER_ACT)) { - pCurrCard->globalFlags |= F_HOST_XFER_ACT; - - FPT_busMstrDataXferStart(port, currSCCB); - } - } -} - -/*--------------------------------------------------------------------- - * - * Function: BusMaster Scatter Gather Data Transfer Start - * - * Description: - * - *---------------------------------------------------------------------*/ -static void FPT_busMstrSGDataXferStart(unsigned long p_port, - struct sccb *pcurrSCCB) -{ - unsigned long count, addr, tmpSGCnt; - unsigned int sg_index; - unsigned char sg_count, i; - unsigned long reg_offset; - - if (pcurrSCCB->Sccb_XferState & F_HOST_XFER_DIR) { - - count = ((unsigned long)HOST_RD_CMD) << 24; - } - - else { - count = ((unsigned long)HOST_WRT_CMD) << 24; - } - - sg_count = 0; - tmpSGCnt = 0; - sg_index = pcurrSCCB->Sccb_sgseg; - reg_offset = hp_aramBase; - - i = (unsigned char)(RD_HARPOON(p_port + hp_page_ctrl) & - ~(SGRAM_ARAM | SCATTER_EN)); - - WR_HARPOON(p_port + hp_page_ctrl, i); - - while ((sg_count < (unsigned char)SG_BUF_CNT) && - ((unsigned long)(sg_index * (unsigned int)SG_ELEMENT_SIZE) < - pcurrSCCB->DataLength)) { - - tmpSGCnt += *(((unsigned long *)pcurrSCCB->DataPointer) + - (sg_index * 2)); - - count |= *(((unsigned long *)pcurrSCCB->DataPointer) + - (sg_index * 2)); - - addr = *(((unsigned long *)pcurrSCCB->DataPointer) + - ((sg_index * 2) + 1)); - - if ((!sg_count) && (pcurrSCCB->Sccb_SGoffset)) { - - addr += - ((count & 0x00FFFFFFL) - pcurrSCCB->Sccb_SGoffset); - count = - (count & 0xFF000000L) | pcurrSCCB->Sccb_SGoffset; - - tmpSGCnt = count & 0x00FFFFFFL; - } - - WR_HARP32(p_port, reg_offset, addr); - reg_offset += 4; - - WR_HARP32(p_port, reg_offset, count); - reg_offset += 4; - - count &= 0xFF000000L; - sg_index++; - sg_count++; - - } /*End While */ - - pcurrSCCB->Sccb_XferCnt = tmpSGCnt; - - WR_HARPOON(p_port + hp_sg_addr, (sg_count << 4)); - - if (pcurrSCCB->Sccb_XferState & F_HOST_XFER_DIR) { - - WR_HARP32(p_port, hp_xfercnt_0, tmpSGCnt); - - WR_HARPOON(p_port + hp_portctrl_0, - (DMA_PORT | SCSI_PORT | SCSI_INBIT)); - WR_HARPOON(p_port + hp_scsisig, S_DATAI_PH); - } - - else { - - if ((!(RD_HARPOON(p_port + hp_synctarg_0) & NARROW_SCSI)) && - (tmpSGCnt & 0x000000001)) { - - pcurrSCCB->Sccb_XferState |= F_ODD_BALL_CNT; - tmpSGCnt--; - } - - WR_HARP32(p_port, hp_xfercnt_0, tmpSGCnt); - - WR_HARPOON(p_port + hp_portctrl_0, - (SCSI_PORT | DMA_PORT | DMA_RD)); - WR_HARPOON(p_port + hp_scsisig, S_DATAO_PH); - } - - WR_HARPOON(p_port + hp_page_ctrl, (unsigned char)(i | SCATTER_EN)); - -} - -/*--------------------------------------------------------------------- - * - * Function: BusMaster Data Transfer Start - * - * Description: - * - *---------------------------------------------------------------------*/ -static void FPT_busMstrDataXferStart(unsigned long p_port, - struct sccb *pcurrSCCB) -{ - unsigned long addr, count; - - if (!(pcurrSCCB->Sccb_XferState & F_AUTO_SENSE)) { - - count = pcurrSCCB->Sccb_XferCnt; - - addr = - (unsigned long)pcurrSCCB->DataPointer + pcurrSCCB->Sccb_ATC; - } - - else { - addr = pcurrSCCB->SensePointer; - count = pcurrSCCB->RequestSenseLength; - - } - - HP_SETUP_ADDR_CNT(p_port, addr, count); - - if (pcurrSCCB->Sccb_XferState & F_HOST_XFER_DIR) { - - WR_HARPOON(p_port + hp_portctrl_0, - (DMA_PORT | SCSI_PORT | SCSI_INBIT)); - WR_HARPOON(p_port + hp_scsisig, S_DATAI_PH); - - WR_HARPOON(p_port + hp_xfer_cmd, - (XFER_DMA_HOST | XFER_HOST_AUTO | XFER_DMA_8BIT)); - } - - else { - - WR_HARPOON(p_port + hp_portctrl_0, - (SCSI_PORT | DMA_PORT | DMA_RD)); - WR_HARPOON(p_port + hp_scsisig, S_DATAO_PH); - - WR_HARPOON(p_port + hp_xfer_cmd, - (XFER_HOST_DMA | XFER_HOST_AUTO | XFER_DMA_8BIT)); - - } -} - -/*--------------------------------------------------------------------- - * - * Function: BusMaster Timeout Handler - * - * Description: This function is called after a bus master command busy time - * out is detected. This routines issue halt state machine - * with a software time out for command busy. If command busy - * is still asserted at the end of the time out, it issues - * hard abort with another software time out. It hard abort - * command busy is also time out, it'll just give up. - * - *---------------------------------------------------------------------*/ -static unsigned char FPT_busMstrTimeOut(unsigned long p_port) -{ - unsigned long timeout; - - timeout = LONG_WAIT; - - WR_HARPOON(p_port + hp_sys_ctrl, HALT_MACH); - - while ((!(RD_HARPOON(p_port + hp_ext_status) & CMD_ABORTED)) - && timeout--) { - } - - if (RD_HARPOON(p_port + hp_ext_status) & BM_CMD_BUSY) { - WR_HARPOON(p_port + hp_sys_ctrl, HARD_ABORT); - - timeout = LONG_WAIT; - while ((RD_HARPOON(p_port + hp_ext_status) & BM_CMD_BUSY) - && timeout--) { - } - } - - RD_HARPOON(p_port + hp_int_status); /*Clear command complete */ - - if (RD_HARPOON(p_port + hp_ext_status) & BM_CMD_BUSY) { - return 1; - } - - else { - return 0; - } -} - -/*--------------------------------------------------------------------- - * - * Function: Host Data Transfer Abort - * - * Description: Abort any in progress transfer. - * - *---------------------------------------------------------------------*/ -static void FPT_hostDataXferAbort(unsigned long port, unsigned char p_card, - struct sccb *pCurrSCCB) -{ - - unsigned long timeout; - unsigned long remain_cnt; - unsigned int sg_ptr; - - FPT_BL_Card[p_card].globalFlags &= ~F_HOST_XFER_ACT; - - if (pCurrSCCB->Sccb_XferState & F_AUTO_SENSE) { - - if (!(RD_HARPOON(port + hp_int_status) & INT_CMD_COMPL)) { - - WR_HARPOON(port + hp_bm_ctrl, - (RD_HARPOON(port + hp_bm_ctrl) | - FLUSH_XFER_CNTR)); - timeout = LONG_WAIT; - - while ((RD_HARPOON(port + hp_ext_status) & BM_CMD_BUSY) - && timeout--) { - } - - WR_HARPOON(port + hp_bm_ctrl, - (RD_HARPOON(port + hp_bm_ctrl) & - ~FLUSH_XFER_CNTR)); - - if (RD_HARPOON(port + hp_ext_status) & BM_CMD_BUSY) { - - if (FPT_busMstrTimeOut(port)) { - - if (pCurrSCCB->HostStatus == 0x00) - - pCurrSCCB->HostStatus = - SCCB_BM_ERR; - - } - - if (RD_HARPOON(port + hp_int_status) & - INT_EXT_STATUS) - - if (RD_HARPOON(port + hp_ext_status) & - BAD_EXT_STATUS) - - if (pCurrSCCB->HostStatus == - 0x00) - { - pCurrSCCB->HostStatus = - SCCB_BM_ERR; - } - } - } - } - - else if (pCurrSCCB->Sccb_XferCnt) { - - if (pCurrSCCB->Sccb_XferState & F_SG_XFER) { - - WR_HARPOON(port + hp_page_ctrl, - (RD_HARPOON(port + hp_page_ctrl) & - ~SCATTER_EN)); - - WR_HARPOON(port + hp_sg_addr, 0x00); - - sg_ptr = pCurrSCCB->Sccb_sgseg + SG_BUF_CNT; - - if (sg_ptr > - (unsigned int)(pCurrSCCB->DataLength / - SG_ELEMENT_SIZE)) { - - sg_ptr = - (unsigned int)(pCurrSCCB->DataLength / - SG_ELEMENT_SIZE); - } - - remain_cnt = pCurrSCCB->Sccb_XferCnt; - - while (remain_cnt < 0x01000000L) { - - sg_ptr--; - - if (remain_cnt > - (unsigned - long)(*(((unsigned long *)pCurrSCCB-> - DataPointer) + (sg_ptr * 2)))) { - - remain_cnt -= - (unsigned - long)(*(((unsigned long *) - pCurrSCCB->DataPointer) + - (sg_ptr * 2))); - } - - else { - - break; - } - } - - if (remain_cnt < 0x01000000L) { - - pCurrSCCB->Sccb_SGoffset = remain_cnt; - - pCurrSCCB->Sccb_sgseg = (unsigned short)sg_ptr; - - if ((unsigned long)(sg_ptr * SG_ELEMENT_SIZE) == - pCurrSCCB->DataLength && (remain_cnt == 0)) - - pCurrSCCB->Sccb_XferState |= - F_ALL_XFERRED; - } - - else { - - if (pCurrSCCB->HostStatus == 0x00) { - - pCurrSCCB->HostStatus = - SCCB_GROSS_FW_ERR; - } - } - } - - if (!(pCurrSCCB->Sccb_XferState & F_HOST_XFER_DIR)) { - - if (RD_HARPOON(port + hp_ext_status) & BM_CMD_BUSY) { - - FPT_busMstrTimeOut(port); - } - - else { - - if (RD_HARPOON(port + hp_int_status) & - INT_EXT_STATUS) { - - if (RD_HARPOON(port + hp_ext_status) & - BAD_EXT_STATUS) { - - if (pCurrSCCB->HostStatus == - 0x00) { - - pCurrSCCB->HostStatus = - SCCB_BM_ERR; - } - } - } - - } - } - - else { - - if ((RD_HARPOON(port + hp_fifo_cnt)) >= BM_THRESHOLD) { - - timeout = SHORT_WAIT; - - while ((RD_HARPOON(port + hp_ext_status) & - BM_CMD_BUSY) - && ((RD_HARPOON(port + hp_fifo_cnt)) >= - BM_THRESHOLD) && timeout--) { - } - } - - if (RD_HARPOON(port + hp_ext_status) & BM_CMD_BUSY) { - - WR_HARPOON(port + hp_bm_ctrl, - (RD_HARPOON(port + hp_bm_ctrl) | - FLUSH_XFER_CNTR)); - - timeout = LONG_WAIT; - - while ((RD_HARPOON(port + hp_ext_status) & - BM_CMD_BUSY) && timeout--) { - } - - WR_HARPOON(port + hp_bm_ctrl, - (RD_HARPOON(port + hp_bm_ctrl) & - ~FLUSH_XFER_CNTR)); - - if (RD_HARPOON(port + hp_ext_status) & - BM_CMD_BUSY) { - - if (pCurrSCCB->HostStatus == 0x00) { - - pCurrSCCB->HostStatus = - SCCB_BM_ERR; - } - - FPT_busMstrTimeOut(port); - } - } - - if (RD_HARPOON(port + hp_int_status) & INT_EXT_STATUS) { - - if (RD_HARPOON(port + hp_ext_status) & - BAD_EXT_STATUS) { - - if (pCurrSCCB->HostStatus == 0x00) { - - pCurrSCCB->HostStatus = - SCCB_BM_ERR; - } - } - } - } - - } - - else { - - if (RD_HARPOON(port + hp_ext_status) & BM_CMD_BUSY) { - - timeout = LONG_WAIT; - - while ((RD_HARPOON(port + hp_ext_status) & BM_CMD_BUSY) - && timeout--) { - } - - if (RD_HARPOON(port + hp_ext_status) & BM_CMD_BUSY) { - - if (pCurrSCCB->HostStatus == 0x00) { - - pCurrSCCB->HostStatus = SCCB_BM_ERR; - } - - FPT_busMstrTimeOut(port); - } - } - - if (RD_HARPOON(port + hp_int_status) & INT_EXT_STATUS) { - - if (RD_HARPOON(port + hp_ext_status) & BAD_EXT_STATUS) { - - if (pCurrSCCB->HostStatus == 0x00) { - - pCurrSCCB->HostStatus = SCCB_BM_ERR; - } - } - - } - - if (pCurrSCCB->Sccb_XferState & F_SG_XFER) { - - WR_HARPOON(port + hp_page_ctrl, - (RD_HARPOON(port + hp_page_ctrl) & - ~SCATTER_EN)); - - WR_HARPOON(port + hp_sg_addr, 0x00); - - pCurrSCCB->Sccb_sgseg += SG_BUF_CNT; - - pCurrSCCB->Sccb_SGoffset = 0x00; - - if ((unsigned long)(pCurrSCCB->Sccb_sgseg * - SG_ELEMENT_SIZE) >= - pCurrSCCB->DataLength) { - - pCurrSCCB->Sccb_XferState |= F_ALL_XFERRED; - - pCurrSCCB->Sccb_sgseg = - (unsigned short)(pCurrSCCB->DataLength / - SG_ELEMENT_SIZE); - - } - } - - else { - - if (!(pCurrSCCB->Sccb_XferState & F_AUTO_SENSE)) - - pCurrSCCB->Sccb_XferState |= F_ALL_XFERRED; - } - } - - WR_HARPOON(port + hp_int_mask, (INT_CMD_COMPL | SCSI_INTERRUPT)); -} - -/*--------------------------------------------------------------------- - * - * Function: Host Data Transfer Restart - * - * Description: Reset the available count due to a restore data - * pointers message. - * - *---------------------------------------------------------------------*/ -static void FPT_hostDataXferRestart(struct sccb *currSCCB) -{ - unsigned long data_count; - unsigned int sg_index; - unsigned long *sg_ptr; - - if (currSCCB->Sccb_XferState & F_SG_XFER) { - - currSCCB->Sccb_XferCnt = 0; - - sg_index = 0xffff; /*Index by long words into sg list. */ - data_count = 0; /*Running count of SG xfer counts. */ - - sg_ptr = (unsigned long *)currSCCB->DataPointer; - - while (data_count < currSCCB->Sccb_ATC) { - - sg_index++; - data_count += *(sg_ptr + (sg_index * 2)); - } - - if (data_count == currSCCB->Sccb_ATC) { - - currSCCB->Sccb_SGoffset = 0; - sg_index++; - } - - else { - currSCCB->Sccb_SGoffset = - data_count - currSCCB->Sccb_ATC; - } - - currSCCB->Sccb_sgseg = (unsigned short)sg_index; - } - - else { - currSCCB->Sccb_XferCnt = - currSCCB->DataLength - currSCCB->Sccb_ATC; - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scini - * - * Description: Setup all data structures necessary for SCAM selection. - * - *---------------------------------------------------------------------*/ - -static void FPT_scini(unsigned char p_card, unsigned char p_our_id, - unsigned char p_power_up) -{ - - unsigned char loser, assigned_id; - unsigned long p_port; - - unsigned char i, k, ScamFlg; - struct sccb_card *currCard; - struct nvram_info *pCurrNvRam; - - currCard = &FPT_BL_Card[p_card]; - p_port = currCard->ioPort; - pCurrNvRam = currCard->pNvRamInfo; - - if (pCurrNvRam) { - ScamFlg = pCurrNvRam->niScamConf; - i = pCurrNvRam->niSysConf; - } else { - ScamFlg = - (unsigned char)FPT_utilEERead(p_port, SCAM_CONFIG / 2); - i = (unsigned - char)(FPT_utilEERead(p_port, (SYSTEM_CONFIG / 2))); - } - if (!(i & 0x02)) /* check if reset bus in AutoSCSI parameter set */ - return; - - FPT_inisci(p_card, p_port, p_our_id); - - /* Force to wait 1 sec after SCSI bus reset. Some SCAM device FW - too slow to return to SCAM selection */ - - /* if (p_power_up) - FPT_Wait1Second(p_port); - else - FPT_Wait(p_port, TO_250ms); */ - - FPT_Wait1Second(p_port); - - if ((ScamFlg & SCAM_ENABLED) && (ScamFlg & SCAM_LEVEL2)) { - while (!(FPT_scarb(p_port, INIT_SELTD))) { - } - - FPT_scsel(p_port); - - do { - FPT_scxferc(p_port, SYNC_PTRN); - FPT_scxferc(p_port, DOM_MSTR); - loser = - FPT_scsendi(p_port, - &FPT_scamInfo[p_our_id].id_string[0]); - } while (loser == 0xFF); - - FPT_scbusf(p_port); - - if ((p_power_up) && (!loser)) { - FPT_sresb(p_port, p_card); - FPT_Wait(p_port, TO_250ms); - - while (!(FPT_scarb(p_port, INIT_SELTD))) { - } - - FPT_scsel(p_port); - - do { - FPT_scxferc(p_port, SYNC_PTRN); - FPT_scxferc(p_port, DOM_MSTR); - loser = - FPT_scsendi(p_port, - &FPT_scamInfo[p_our_id]. - id_string[0]); - } while (loser == 0xFF); - - FPT_scbusf(p_port); - } - } - - else { - loser = 0; - } - - if (!loser) { - - FPT_scamInfo[p_our_id].state = ID_ASSIGNED; - - if (ScamFlg & SCAM_ENABLED) { - - for (i = 0; i < MAX_SCSI_TAR; i++) { - if ((FPT_scamInfo[i].state == ID_UNASSIGNED) || - (FPT_scamInfo[i].state == ID_UNUSED)) { - if (FPT_scsell(p_port, i)) { - FPT_scamInfo[i].state = LEGACY; - if ((FPT_scamInfo[i]. - id_string[0] != 0xFF) - || (FPT_scamInfo[i]. - id_string[1] != 0xFA)) { - - FPT_scamInfo[i]. - id_string[0] = 0xFF; - FPT_scamInfo[i]. - id_string[1] = 0xFA; - if (pCurrNvRam == NULL) - currCard-> - globalFlags - |= - F_UPDATE_EEPROM; - } - } - } - } - - FPT_sresb(p_port, p_card); - FPT_Wait1Second(p_port); - while (!(FPT_scarb(p_port, INIT_SELTD))) { - } - FPT_scsel(p_port); - FPT_scasid(p_card, p_port); - } - - } - - else if ((loser) && (ScamFlg & SCAM_ENABLED)) { - FPT_scamInfo[p_our_id].id_string[0] = SLV_TYPE_CODE0; - assigned_id = 0; - FPT_scwtsel(p_port); - - do { - while (FPT_scxferc(p_port, 0x00) != SYNC_PTRN) { - } - - i = FPT_scxferc(p_port, 0x00); - if (i == ASSIGN_ID) { - if (! - (FPT_scsendi - (p_port, - &FPT_scamInfo[p_our_id].id_string[0]))) { - i = FPT_scxferc(p_port, 0x00); - if (FPT_scvalq(i)) { - k = FPT_scxferc(p_port, 0x00); - - if (FPT_scvalq(k)) { - currCard->ourId = - ((unsigned char)(i - << - 3) - + - (k & - (unsigned char)7)) - & (unsigned char) - 0x3F; - FPT_inisci(p_card, - p_port, - p_our_id); - FPT_scamInfo[currCard-> - ourId]. - state = ID_ASSIGNED; - FPT_scamInfo[currCard-> - ourId]. - id_string[0] - = SLV_TYPE_CODE0; - assigned_id = 1; - } - } - } - } - - else if (i == SET_P_FLAG) { - if (!(FPT_scsendi(p_port, - &FPT_scamInfo[p_our_id]. - id_string[0]))) - FPT_scamInfo[p_our_id].id_string[0] |= - 0x80; - } - } while (!assigned_id); - - while (FPT_scxferc(p_port, 0x00) != CFG_CMPLT) { - } - } - - if (ScamFlg & SCAM_ENABLED) { - FPT_scbusf(p_port); - if (currCard->globalFlags & F_UPDATE_EEPROM) { - FPT_scsavdi(p_card, p_port); - currCard->globalFlags &= ~F_UPDATE_EEPROM; - } - } - -/* - for (i=0,k=0; i < MAX_SCSI_TAR; i++) - { - if ((FPT_scamInfo[i].state == ID_ASSIGNED) || - (FPT_scamInfo[i].state == LEGACY)) - k++; - } - - if (k==2) - currCard->globalFlags |= F_SINGLE_DEVICE; - else - currCard->globalFlags &= ~F_SINGLE_DEVICE; -*/ -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scarb - * - * Description: Gain control of the bus and wait SCAM select time (250ms) - * - *---------------------------------------------------------------------*/ - -static int FPT_scarb(unsigned long p_port, unsigned char p_sel_type) -{ - if (p_sel_type == INIT_SELTD) { - - while (RD_HARPOON(p_port + hp_scsisig) & (SCSI_SEL | SCSI_BSY)) { - } - - if (RD_HARPOON(p_port + hp_scsisig) & SCSI_SEL) - return 0; - - if (RD_HARPOON(p_port + hp_scsidata_0) != 00) - return 0; - - WR_HARPOON(p_port + hp_scsisig, - (RD_HARPOON(p_port + hp_scsisig) | SCSI_BSY)); - - if (RD_HARPOON(p_port + hp_scsisig) & SCSI_SEL) { - - WR_HARPOON(p_port + hp_scsisig, - (RD_HARPOON(p_port + hp_scsisig) & - ~SCSI_BSY)); - return 0; - } - - WR_HARPOON(p_port + hp_scsisig, - (RD_HARPOON(p_port + hp_scsisig) | SCSI_SEL)); - - if (RD_HARPOON(p_port + hp_scsidata_0) != 00) { - - WR_HARPOON(p_port + hp_scsisig, - (RD_HARPOON(p_port + hp_scsisig) & - ~(SCSI_BSY | SCSI_SEL))); - return 0; - } - } - - WR_HARPOON(p_port + hp_clkctrl_0, (RD_HARPOON(p_port + hp_clkctrl_0) - & ~ACTdeassert)); - WR_HARPOON(p_port + hp_scsireset, SCAM_EN); - WR_HARPOON(p_port + hp_scsidata_0, 0x00); - WR_HARPOON(p_port + hp_scsidata_1, 0x00); - WR_HARPOON(p_port + hp_portctrl_0, SCSI_BUS_EN); - - WR_HARPOON(p_port + hp_scsisig, - (RD_HARPOON(p_port + hp_scsisig) | SCSI_MSG)); - - WR_HARPOON(p_port + hp_scsisig, (RD_HARPOON(p_port + hp_scsisig) - & ~SCSI_BSY)); - - FPT_Wait(p_port, TO_250ms); - - return 1; -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scbusf - * - * Description: Release the SCSI bus and disable SCAM selection. - * - *---------------------------------------------------------------------*/ - -static void FPT_scbusf(unsigned long p_port) -{ - WR_HARPOON(p_port + hp_page_ctrl, - (RD_HARPOON(p_port + hp_page_ctrl) | G_INT_DISABLE)); - - WR_HARPOON(p_port + hp_scsidata_0, 0x00); - - WR_HARPOON(p_port + hp_portctrl_0, (RD_HARPOON(p_port + hp_portctrl_0) - & ~SCSI_BUS_EN)); - - WR_HARPOON(p_port + hp_scsisig, 0x00); - - WR_HARPOON(p_port + hp_scsireset, (RD_HARPOON(p_port + hp_scsireset) - & ~SCAM_EN)); - - WR_HARPOON(p_port + hp_clkctrl_0, (RD_HARPOON(p_port + hp_clkctrl_0) - | ACTdeassert)); - - WRW_HARPOON((p_port + hp_intstat), (BUS_FREE | AUTO_INT | SCAM_SEL)); - - WR_HARPOON(p_port + hp_page_ctrl, - (RD_HARPOON(p_port + hp_page_ctrl) & ~G_INT_DISABLE)); -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scasid - * - * Description: Assign an ID to all the SCAM devices. - * - *---------------------------------------------------------------------*/ - -static void FPT_scasid(unsigned char p_card, unsigned long p_port) -{ - unsigned char temp_id_string[ID_STRING_LENGTH]; - - unsigned char i, k, scam_id; - unsigned char crcBytes[3]; - struct nvram_info *pCurrNvRam; - unsigned short *pCrcBytes; - - pCurrNvRam = FPT_BL_Card[p_card].pNvRamInfo; - - i = 0; - - while (!i) { - - for (k = 0; k < ID_STRING_LENGTH; k++) { - temp_id_string[k] = (unsigned char)0x00; - } - - FPT_scxferc(p_port, SYNC_PTRN); - FPT_scxferc(p_port, ASSIGN_ID); - - if (!(FPT_sciso(p_port, &temp_id_string[0]))) { - if (pCurrNvRam) { - pCrcBytes = (unsigned short *)&crcBytes[0]; - *pCrcBytes = FPT_CalcCrc16(&temp_id_string[0]); - crcBytes[2] = FPT_CalcLrc(&temp_id_string[0]); - temp_id_string[1] = crcBytes[2]; - temp_id_string[2] = crcBytes[0]; - temp_id_string[3] = crcBytes[1]; - for (k = 4; k < ID_STRING_LENGTH; k++) - temp_id_string[k] = (unsigned char)0x00; - } - i = FPT_scmachid(p_card, temp_id_string); - - if (i == CLR_PRIORITY) { - FPT_scxferc(p_port, MISC_CODE); - FPT_scxferc(p_port, CLR_P_FLAG); - i = 0; /*Not the last ID yet. */ - } - - else if (i != NO_ID_AVAIL) { - if (i < 8) - FPT_scxferc(p_port, ID_0_7); - else - FPT_scxferc(p_port, ID_8_F); - - scam_id = (i & (unsigned char)0x07); - - for (k = 1; k < 0x08; k <<= 1) - if (!(k & i)) - scam_id += 0x08; /*Count number of zeros in DB0-3. */ - - FPT_scxferc(p_port, scam_id); - - i = 0; /*Not the last ID yet. */ - } - } - - else { - i = 1; - } - - } /*End while */ - - FPT_scxferc(p_port, SYNC_PTRN); - FPT_scxferc(p_port, CFG_CMPLT); -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scsel - * - * Description: Select all the SCAM devices. - * - *---------------------------------------------------------------------*/ - -static void FPT_scsel(unsigned long p_port) -{ - - WR_HARPOON(p_port + hp_scsisig, SCSI_SEL); - FPT_scwiros(p_port, SCSI_MSG); - - WR_HARPOON(p_port + hp_scsisig, (SCSI_SEL | SCSI_BSY)); - - WR_HARPOON(p_port + hp_scsisig, - (SCSI_SEL | SCSI_BSY | SCSI_IOBIT | SCSI_CD)); - WR_HARPOON(p_port + hp_scsidata_0, - (unsigned char)(RD_HARPOON(p_port + hp_scsidata_0) | - (unsigned char)(BIT(7) + BIT(6)))); - - WR_HARPOON(p_port + hp_scsisig, (SCSI_BSY | SCSI_IOBIT | SCSI_CD)); - FPT_scwiros(p_port, SCSI_SEL); - - WR_HARPOON(p_port + hp_scsidata_0, - (unsigned char)(RD_HARPOON(p_port + hp_scsidata_0) & - ~(unsigned char)BIT(6))); - FPT_scwirod(p_port, BIT(6)); - - WR_HARPOON(p_port + hp_scsisig, - (SCSI_SEL | SCSI_BSY | SCSI_IOBIT | SCSI_CD)); -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scxferc - * - * Description: Handshake the p_data (DB4-0) across the bus. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_scxferc(unsigned long p_port, unsigned char p_data) -{ - unsigned char curr_data, ret_data; - - curr_data = p_data | BIT(7) | BIT(5); /*Start with DB7 & DB5 asserted. */ - - WR_HARPOON(p_port + hp_scsidata_0, curr_data); - - curr_data &= ~BIT(7); - - WR_HARPOON(p_port + hp_scsidata_0, curr_data); - - FPT_scwirod(p_port, BIT(7)); /*Wait for DB7 to be released. */ - while (!(RD_HARPOON(p_port + hp_scsidata_0) & BIT(5))) ; - - ret_data = (RD_HARPOON(p_port + hp_scsidata_0) & (unsigned char)0x1F); - - curr_data |= BIT(6); - - WR_HARPOON(p_port + hp_scsidata_0, curr_data); - - curr_data &= ~BIT(5); - - WR_HARPOON(p_port + hp_scsidata_0, curr_data); - - FPT_scwirod(p_port, BIT(5)); /*Wait for DB5 to be released. */ - - curr_data &= ~(BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); /*Release data bits */ - curr_data |= BIT(7); - - WR_HARPOON(p_port + hp_scsidata_0, curr_data); - - curr_data &= ~BIT(6); - - WR_HARPOON(p_port + hp_scsidata_0, curr_data); - - FPT_scwirod(p_port, BIT(6)); /*Wait for DB6 to be released. */ - - return ret_data; -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scsendi - * - * Description: Transfer our Identification string to determine if we - * will be the dominant master. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_scsendi(unsigned long p_port, - unsigned char p_id_string[]) -{ - unsigned char ret_data, byte_cnt, bit_cnt, defer; - - defer = 0; - - for (byte_cnt = 0; byte_cnt < ID_STRING_LENGTH; byte_cnt++) { - - for (bit_cnt = 0x80; bit_cnt != 0; bit_cnt >>= 1) { - - if (defer) - ret_data = FPT_scxferc(p_port, 00); - - else if (p_id_string[byte_cnt] & bit_cnt) - - ret_data = FPT_scxferc(p_port, 02); - - else { - - ret_data = FPT_scxferc(p_port, 01); - if (ret_data & 02) - defer = 1; - } - - if ((ret_data & 0x1C) == 0x10) - return 0x00; /*End of isolation stage, we won! */ - - if (ret_data & 0x1C) - return 0xFF; - - if ((defer) && (!(ret_data & 0x1F))) - return 0x01; /*End of isolation stage, we lost. */ - - } /*bit loop */ - - } /*byte loop */ - - if (defer) - return 0x01; /*We lost */ - else - return 0; /*We WON! Yeeessss! */ -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_sciso - * - * Description: Transfer the Identification string. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_sciso(unsigned long p_port, - unsigned char p_id_string[]) -{ - unsigned char ret_data, the_data, byte_cnt, bit_cnt; - - the_data = 0; - - for (byte_cnt = 0; byte_cnt < ID_STRING_LENGTH; byte_cnt++) { - - for (bit_cnt = 0; bit_cnt < 8; bit_cnt++) { - - ret_data = FPT_scxferc(p_port, 0); - - if (ret_data & 0xFC) - return 0xFF; - - else { - - the_data <<= 1; - if (ret_data & BIT(1)) { - the_data |= 1; - } - } - - if ((ret_data & 0x1F) == 0) { -/* - if(bit_cnt != 0 || bit_cnt != 8) - { - byte_cnt = 0; - bit_cnt = 0; - FPT_scxferc(p_port, SYNC_PTRN); - FPT_scxferc(p_port, ASSIGN_ID); - continue; - } -*/ - if (byte_cnt) - return 0x00; - else - return 0xFF; - } - - } /*bit loop */ - - p_id_string[byte_cnt] = the_data; - - } /*byte loop */ - - return 0; -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scwirod - * - * Description: Sample the SCSI data bus making sure the signal has been - * deasserted for the correct number of consecutive samples. - * - *---------------------------------------------------------------------*/ - -static void FPT_scwirod(unsigned long p_port, unsigned char p_data_bit) -{ - unsigned char i; - - i = 0; - while (i < MAX_SCSI_TAR) { - - if (RD_HARPOON(p_port + hp_scsidata_0) & p_data_bit) - - i = 0; - - else - - i++; - - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scwiros - * - * Description: Sample the SCSI Signal lines making sure the signal has been - * deasserted for the correct number of consecutive samples. - * - *---------------------------------------------------------------------*/ - -static void FPT_scwiros(unsigned long p_port, unsigned char p_data_bit) -{ - unsigned char i; - - i = 0; - while (i < MAX_SCSI_TAR) { - - if (RD_HARPOON(p_port + hp_scsisig) & p_data_bit) - - i = 0; - - else - - i++; - - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scvalq - * - * Description: Make sure we received a valid data byte. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_scvalq(unsigned char p_quintet) -{ - unsigned char count; - - for (count = 1; count < 0x08; count <<= 1) { - if (!(p_quintet & count)) - p_quintet -= 0x80; - } - - if (p_quintet & 0x18) - return 0; - - else - return 1; -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scsell - * - * Description: Select the specified device ID using a selection timeout - * less than 4ms. If somebody responds then it is a legacy - * drive and this ID must be marked as such. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_scsell(unsigned long p_port, unsigned char targ_id) -{ - unsigned long i; - - WR_HARPOON(p_port + hp_page_ctrl, - (RD_HARPOON(p_port + hp_page_ctrl) | G_INT_DISABLE)); - - ARAM_ACCESS(p_port); - - WR_HARPOON(p_port + hp_addstat, - (RD_HARPOON(p_port + hp_addstat) | SCAM_TIMER)); - WR_HARPOON(p_port + hp_seltimeout, TO_4ms); - - for (i = p_port + CMD_STRT; i < p_port + CMD_STRT + 12; i += 2) { - WRW_HARPOON(i, (MPM_OP + ACOMMAND)); - } - WRW_HARPOON(i, (BRH_OP + ALWAYS + NP)); - - WRW_HARPOON((p_port + hp_intstat), - (RESET | TIMEOUT | SEL | BUS_FREE | AUTO_INT)); - - WR_HARPOON(p_port + hp_select_id, targ_id); - - WR_HARPOON(p_port + hp_portctrl_0, SCSI_PORT); - WR_HARPOON(p_port + hp_autostart_3, (SELECT | CMD_ONLY_STRT)); - WR_HARPOON(p_port + hp_scsictrl_0, (SEL_TAR | ENA_RESEL)); - - while (!(RDW_HARPOON((p_port + hp_intstat)) & - (RESET | PROG_HLT | TIMEOUT | AUTO_INT))) { - } - - if (RDW_HARPOON((p_port + hp_intstat)) & RESET) - FPT_Wait(p_port, TO_250ms); - - DISABLE_AUTO(p_port); - - WR_HARPOON(p_port + hp_addstat, - (RD_HARPOON(p_port + hp_addstat) & ~SCAM_TIMER)); - WR_HARPOON(p_port + hp_seltimeout, TO_290ms); - - SGRAM_ACCESS(p_port); - - if (RDW_HARPOON((p_port + hp_intstat)) & (RESET | TIMEOUT)) { - - WRW_HARPOON((p_port + hp_intstat), - (RESET | TIMEOUT | SEL | BUS_FREE | PHASE)); - - WR_HARPOON(p_port + hp_page_ctrl, - (RD_HARPOON(p_port + hp_page_ctrl) & - ~G_INT_DISABLE)); - - return 0; /*No legacy device */ - } - - else { - - while (!(RDW_HARPOON((p_port + hp_intstat)) & BUS_FREE)) { - if (RD_HARPOON(p_port + hp_scsisig) & SCSI_REQ) { - WR_HARPOON(p_port + hp_scsisig, - (SCSI_ACK + S_ILL_PH)); - ACCEPT_MSG(p_port); - } - } - - WRW_HARPOON((p_port + hp_intstat), CLR_ALL_INT_1); - - WR_HARPOON(p_port + hp_page_ctrl, - (RD_HARPOON(p_port + hp_page_ctrl) & - ~G_INT_DISABLE)); - - return 1; /*Found one of them oldies! */ - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scwtsel - * - * Description: Wait to be selected by another SCAM initiator. - * - *---------------------------------------------------------------------*/ - -static void FPT_scwtsel(unsigned long p_port) -{ - while (!(RDW_HARPOON((p_port + hp_intstat)) & SCAM_SEL)) { - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_inisci - * - * Description: Setup the data Structure with the info from the EEPROM. - * - *---------------------------------------------------------------------*/ - -static void FPT_inisci(unsigned char p_card, unsigned long p_port, - unsigned char p_our_id) -{ - unsigned char i, k, max_id; - unsigned short ee_data; - struct nvram_info *pCurrNvRam; - - pCurrNvRam = FPT_BL_Card[p_card].pNvRamInfo; - - if (RD_HARPOON(p_port + hp_page_ctrl) & NARROW_SCSI_CARD) - max_id = 0x08; - - else - max_id = 0x10; - - if (pCurrNvRam) { - for (i = 0; i < max_id; i++) { - - for (k = 0; k < 4; k++) - FPT_scamInfo[i].id_string[k] = - pCurrNvRam->niScamTbl[i][k]; - for (k = 4; k < ID_STRING_LENGTH; k++) - FPT_scamInfo[i].id_string[k] = - (unsigned char)0x00; - - if (FPT_scamInfo[i].id_string[0] == 0x00) - FPT_scamInfo[i].state = ID_UNUSED; /*Default to unused ID. */ - else - FPT_scamInfo[i].state = ID_UNASSIGNED; /*Default to unassigned ID. */ - - } - } else { - for (i = 0; i < max_id; i++) { - for (k = 0; k < ID_STRING_LENGTH; k += 2) { - ee_data = - FPT_utilEERead(p_port, - (unsigned - short)((EE_SCAMBASE / 2) + - (unsigned short)(i * - ((unsigned short)ID_STRING_LENGTH / 2)) + (unsigned short)(k / 2))); - FPT_scamInfo[i].id_string[k] = - (unsigned char)ee_data; - ee_data >>= 8; - FPT_scamInfo[i].id_string[k + 1] = - (unsigned char)ee_data; - } - - if ((FPT_scamInfo[i].id_string[0] == 0x00) || - (FPT_scamInfo[i].id_string[0] == 0xFF)) - - FPT_scamInfo[i].state = ID_UNUSED; /*Default to unused ID. */ - - else - FPT_scamInfo[i].state = ID_UNASSIGNED; /*Default to unassigned ID. */ - - } - } - for (k = 0; k < ID_STRING_LENGTH; k++) - FPT_scamInfo[p_our_id].id_string[k] = FPT_scamHAString[k]; - -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scmachid - * - * Description: Match the Device ID string with our values stored in - * the EEPROM. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_scmachid(unsigned char p_card, - unsigned char p_id_string[]) -{ - - unsigned char i, k, match; - - for (i = 0; i < MAX_SCSI_TAR; i++) { - - match = 1; - - for (k = 0; k < ID_STRING_LENGTH; k++) { - if (p_id_string[k] != FPT_scamInfo[i].id_string[k]) - match = 0; - } - - if (match) { - FPT_scamInfo[i].state = ID_ASSIGNED; - return i; - } - - } - - if (p_id_string[0] & BIT(5)) - i = 8; - else - i = MAX_SCSI_TAR; - - if (((p_id_string[0] & 0x06) == 0x02) - || ((p_id_string[0] & 0x06) == 0x04)) - match = p_id_string[1] & (unsigned char)0x1F; - else - match = 7; - - while (i > 0) { - i--; - - if (FPT_scamInfo[match].state == ID_UNUSED) { - for (k = 0; k < ID_STRING_LENGTH; k++) { - FPT_scamInfo[match].id_string[k] = - p_id_string[k]; - } - - FPT_scamInfo[match].state = ID_ASSIGNED; - - if (FPT_BL_Card[p_card].pNvRamInfo == NULL) - FPT_BL_Card[p_card].globalFlags |= - F_UPDATE_EEPROM; - return match; - - } - - match--; - - if (match == 0xFF) { - if (p_id_string[0] & BIT(5)) - match = 7; - else - match = MAX_SCSI_TAR - 1; - } - } - - if (p_id_string[0] & BIT(7)) { - return CLR_PRIORITY; - } - - if (p_id_string[0] & BIT(5)) - i = 8; - else - i = MAX_SCSI_TAR; - - if (((p_id_string[0] & 0x06) == 0x02) - || ((p_id_string[0] & 0x06) == 0x04)) - match = p_id_string[1] & (unsigned char)0x1F; - else - match = 7; - - while (i > 0) { - - i--; - - if (FPT_scamInfo[match].state == ID_UNASSIGNED) { - for (k = 0; k < ID_STRING_LENGTH; k++) { - FPT_scamInfo[match].id_string[k] = - p_id_string[k]; - } - - FPT_scamInfo[match].id_string[0] |= BIT(7); - FPT_scamInfo[match].state = ID_ASSIGNED; - if (FPT_BL_Card[p_card].pNvRamInfo == NULL) - FPT_BL_Card[p_card].globalFlags |= - F_UPDATE_EEPROM; - return match; - - } - - match--; - - if (match == 0xFF) { - if (p_id_string[0] & BIT(5)) - match = 7; - else - match = MAX_SCSI_TAR - 1; - } - } - - return NO_ID_AVAIL; -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_scsavdi - * - * Description: Save off the device SCAM ID strings. - * - *---------------------------------------------------------------------*/ - -static void FPT_scsavdi(unsigned char p_card, unsigned long p_port) -{ - unsigned char i, k, max_id; - unsigned short ee_data, sum_data; - - sum_data = 0x0000; - - for (i = 1; i < EE_SCAMBASE / 2; i++) { - sum_data += FPT_utilEERead(p_port, i); - } - - FPT_utilEEWriteOnOff(p_port, 1); /* Enable write access to the EEPROM */ - - if (RD_HARPOON(p_port + hp_page_ctrl) & NARROW_SCSI_CARD) - max_id = 0x08; - - else - max_id = 0x10; - - for (i = 0; i < max_id; i++) { - - for (k = 0; k < ID_STRING_LENGTH; k += 2) { - ee_data = FPT_scamInfo[i].id_string[k + 1]; - ee_data <<= 8; - ee_data |= FPT_scamInfo[i].id_string[k]; - sum_data += ee_data; - FPT_utilEEWrite(p_port, ee_data, - (unsigned short)((EE_SCAMBASE / 2) + - (unsigned short)(i * - ((unsigned short)ID_STRING_LENGTH / 2)) + (unsigned short)(k / 2))); - } - } - - FPT_utilEEWrite(p_port, sum_data, EEPROM_CHECK_SUM / 2); - FPT_utilEEWriteOnOff(p_port, 0); /* Turn off write access */ -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_XbowInit - * - * Description: Setup the Xbow for normal operation. - * - *---------------------------------------------------------------------*/ - -static void FPT_XbowInit(unsigned long port, unsigned char ScamFlg) -{ - unsigned char i; - - i = RD_HARPOON(port + hp_page_ctrl); - WR_HARPOON(port + hp_page_ctrl, (unsigned char)(i | G_INT_DISABLE)); - - WR_HARPOON(port + hp_scsireset, 0x00); - WR_HARPOON(port + hp_portctrl_1, HOST_MODE8); - - WR_HARPOON(port + hp_scsireset, (DMA_RESET | HPSCSI_RESET | PROG_RESET | - FIFO_CLR)); - - WR_HARPOON(port + hp_scsireset, SCSI_INI); - - WR_HARPOON(port + hp_clkctrl_0, CLKCTRL_DEFAULT); - - WR_HARPOON(port + hp_scsisig, 0x00); /* Clear any signals we might */ - WR_HARPOON(port + hp_scsictrl_0, ENA_SCAM_SEL); - - WRW_HARPOON((port + hp_intstat), CLR_ALL_INT); - - FPT_default_intena = RESET | RSEL | PROG_HLT | TIMEOUT | - BUS_FREE | XFER_CNT_0 | AUTO_INT; - - if ((ScamFlg & SCAM_ENABLED) && (ScamFlg & SCAM_LEVEL2)) - FPT_default_intena |= SCAM_SEL; - - WRW_HARPOON((port + hp_intena), FPT_default_intena); - - WR_HARPOON(port + hp_seltimeout, TO_290ms); - - /* Turn on SCSI_MODE8 for narrow cards to fix the - strapping issue with the DUAL CHANNEL card */ - if (RD_HARPOON(port + hp_page_ctrl) & NARROW_SCSI_CARD) - WR_HARPOON(port + hp_addstat, SCSI_MODE8); - - WR_HARPOON(port + hp_page_ctrl, i); - -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_BusMasterInit - * - * Description: Initialize the BusMaster for normal operations. - * - *---------------------------------------------------------------------*/ - -static void FPT_BusMasterInit(unsigned long p_port) -{ - - WR_HARPOON(p_port + hp_sys_ctrl, DRVR_RST); - WR_HARPOON(p_port + hp_sys_ctrl, 0x00); - - WR_HARPOON(p_port + hp_host_blk_cnt, XFER_BLK64); - - WR_HARPOON(p_port + hp_bm_ctrl, (BMCTRL_DEFAULT)); - - WR_HARPOON(p_port + hp_ee_ctrl, (SCSI_TERM_ENA_H)); - - RD_HARPOON(p_port + hp_int_status); /*Clear interrupts. */ - WR_HARPOON(p_port + hp_int_mask, (INT_CMD_COMPL | SCSI_INTERRUPT)); - WR_HARPOON(p_port + hp_page_ctrl, (RD_HARPOON(p_port + hp_page_ctrl) & - ~SCATTER_EN)); -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_DiagEEPROM - * - * Description: Verfiy checksum and 'Key' and initialize the EEPROM if - * necessary. - * - *---------------------------------------------------------------------*/ - -static void FPT_DiagEEPROM(unsigned long p_port) -{ - unsigned short index, temp, max_wd_cnt; - - if (RD_HARPOON(p_port + hp_page_ctrl) & NARROW_SCSI_CARD) - max_wd_cnt = EEPROM_WD_CNT; - else - max_wd_cnt = EEPROM_WD_CNT * 2; - - temp = FPT_utilEERead(p_port, FW_SIGNATURE / 2); - - if (temp == 0x4641) { - - for (index = 2; index < max_wd_cnt; index++) { - - temp += FPT_utilEERead(p_port, index); - - } - - if (temp == FPT_utilEERead(p_port, EEPROM_CHECK_SUM / 2)) { - - return; /*EEPROM is Okay so return now! */ - } - } - - FPT_utilEEWriteOnOff(p_port, (unsigned char)1); - - for (index = 0; index < max_wd_cnt; index++) { - - FPT_utilEEWrite(p_port, 0x0000, index); - } - - temp = 0; - - FPT_utilEEWrite(p_port, 0x4641, FW_SIGNATURE / 2); - temp += 0x4641; - FPT_utilEEWrite(p_port, 0x3920, MODEL_NUMB_0 / 2); - temp += 0x3920; - FPT_utilEEWrite(p_port, 0x3033, MODEL_NUMB_2 / 2); - temp += 0x3033; - FPT_utilEEWrite(p_port, 0x2020, MODEL_NUMB_4 / 2); - temp += 0x2020; - FPT_utilEEWrite(p_port, 0x70D3, SYSTEM_CONFIG / 2); - temp += 0x70D3; - FPT_utilEEWrite(p_port, 0x0010, BIOS_CONFIG / 2); - temp += 0x0010; - FPT_utilEEWrite(p_port, 0x0003, SCAM_CONFIG / 2); - temp += 0x0003; - FPT_utilEEWrite(p_port, 0x0007, ADAPTER_SCSI_ID / 2); - temp += 0x0007; - - FPT_utilEEWrite(p_port, 0x0000, IGNORE_B_SCAN / 2); - temp += 0x0000; - FPT_utilEEWrite(p_port, 0x0000, SEND_START_ENA / 2); - temp += 0x0000; - FPT_utilEEWrite(p_port, 0x0000, DEVICE_ENABLE / 2); - temp += 0x0000; - - FPT_utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL01 / 2); - temp += 0x4242; - FPT_utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL23 / 2); - temp += 0x4242; - FPT_utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL45 / 2); - temp += 0x4242; - FPT_utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL67 / 2); - temp += 0x4242; - FPT_utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL89 / 2); - temp += 0x4242; - FPT_utilEEWrite(p_port, 0x4242, SYNC_RATE_TBLab / 2); - temp += 0x4242; - FPT_utilEEWrite(p_port, 0x4242, SYNC_RATE_TBLcd / 2); - temp += 0x4242; - FPT_utilEEWrite(p_port, 0x4242, SYNC_RATE_TBLef / 2); - temp += 0x4242; - - FPT_utilEEWrite(p_port, 0x6C46, 64 / 2); /*PRODUCT ID */ - temp += 0x6C46; - FPT_utilEEWrite(p_port, 0x7361, 66 / 2); /* FlashPoint LT */ - temp += 0x7361; - FPT_utilEEWrite(p_port, 0x5068, 68 / 2); - temp += 0x5068; - FPT_utilEEWrite(p_port, 0x696F, 70 / 2); - temp += 0x696F; - FPT_utilEEWrite(p_port, 0x746E, 72 / 2); - temp += 0x746E; - FPT_utilEEWrite(p_port, 0x4C20, 74 / 2); - temp += 0x4C20; - FPT_utilEEWrite(p_port, 0x2054, 76 / 2); - temp += 0x2054; - FPT_utilEEWrite(p_port, 0x2020, 78 / 2); - temp += 0x2020; - - index = ((EE_SCAMBASE / 2) + (7 * 16)); - FPT_utilEEWrite(p_port, (0x0700 + TYPE_CODE0), index); - temp += (0x0700 + TYPE_CODE0); - index++; - FPT_utilEEWrite(p_port, 0x5542, index); /*Vendor ID code */ - temp += 0x5542; /* BUSLOGIC */ - index++; - FPT_utilEEWrite(p_port, 0x4C53, index); - temp += 0x4C53; - index++; - FPT_utilEEWrite(p_port, 0x474F, index); - temp += 0x474F; - index++; - FPT_utilEEWrite(p_port, 0x4349, index); - temp += 0x4349; - index++; - FPT_utilEEWrite(p_port, 0x5442, index); /*Vendor unique code */ - temp += 0x5442; /* BT- 930 */ - index++; - FPT_utilEEWrite(p_port, 0x202D, index); - temp += 0x202D; - index++; - FPT_utilEEWrite(p_port, 0x3339, index); - temp += 0x3339; - index++; /*Serial # */ - FPT_utilEEWrite(p_port, 0x2030, index); /* 01234567 */ - temp += 0x2030; - index++; - FPT_utilEEWrite(p_port, 0x5453, index); - temp += 0x5453; - index++; - FPT_utilEEWrite(p_port, 0x5645, index); - temp += 0x5645; - index++; - FPT_utilEEWrite(p_port, 0x2045, index); - temp += 0x2045; - index++; - FPT_utilEEWrite(p_port, 0x202F, index); - temp += 0x202F; - index++; - FPT_utilEEWrite(p_port, 0x4F4A, index); - temp += 0x4F4A; - index++; - FPT_utilEEWrite(p_port, 0x204E, index); - temp += 0x204E; - index++; - FPT_utilEEWrite(p_port, 0x3539, index); - temp += 0x3539; - - FPT_utilEEWrite(p_port, temp, EEPROM_CHECK_SUM / 2); - - FPT_utilEEWriteOnOff(p_port, (unsigned char)0); - -} - -/*--------------------------------------------------------------------- - * - * Function: Queue Search Select - * - * Description: Try to find a new command to execute. - * - *---------------------------------------------------------------------*/ - -static void FPT_queueSearchSelect(struct sccb_card *pCurrCard, - unsigned char p_card) -{ - unsigned char scan_ptr, lun; - struct sccb_mgr_tar_info *currTar_Info; - struct sccb *pOldSccb; - - scan_ptr = pCurrCard->scanIndex; - do { - currTar_Info = &FPT_sccbMgrTbl[p_card][scan_ptr]; - if ((pCurrCard->globalFlags & F_CONLUN_IO) && - ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != - TAG_Q_TRYING)) { - if (currTar_Info->TarSelQ_Cnt != 0) { - - scan_ptr++; - if (scan_ptr == MAX_SCSI_TAR) - scan_ptr = 0; - - for (lun = 0; lun < MAX_LUN; lun++) { - if (currTar_Info->TarLUNBusy[lun] == 0) { - - pCurrCard->currentSCCB = - currTar_Info->TarSelQ_Head; - pOldSccb = NULL; - - while ((pCurrCard-> - currentSCCB != NULL) - && (lun != - pCurrCard-> - currentSCCB->Lun)) { - pOldSccb = - pCurrCard-> - currentSCCB; - pCurrCard->currentSCCB = - (struct sccb - *)(pCurrCard-> - currentSCCB)-> - Sccb_forwardlink; - } - if (pCurrCard->currentSCCB == - NULL) - continue; - if (pOldSccb != NULL) { - pOldSccb-> - Sccb_forwardlink = - (struct sccb - *)(pCurrCard-> - currentSCCB)-> - Sccb_forwardlink; - pOldSccb-> - Sccb_backlink = - (struct sccb - *)(pCurrCard-> - currentSCCB)-> - Sccb_backlink; - currTar_Info-> - TarSelQ_Cnt--; - } else { - currTar_Info-> - TarSelQ_Head = - (struct sccb - *)(pCurrCard-> - currentSCCB)-> - Sccb_forwardlink; - - if (currTar_Info-> - TarSelQ_Head == - NULL) { - currTar_Info-> - TarSelQ_Tail - = NULL; - currTar_Info-> - TarSelQ_Cnt - = 0; - } else { - currTar_Info-> - TarSelQ_Cnt--; - currTar_Info-> - TarSelQ_Head-> - Sccb_backlink - = - (struct sccb - *)NULL; - } - } - pCurrCard->scanIndex = scan_ptr; - - pCurrCard->globalFlags |= - F_NEW_SCCB_CMD; - - break; - } - } - } - - else { - scan_ptr++; - if (scan_ptr == MAX_SCSI_TAR) { - scan_ptr = 0; - } - } - - } else { - if ((currTar_Info->TarSelQ_Cnt != 0) && - (currTar_Info->TarLUNBusy[0] == 0)) { - - pCurrCard->currentSCCB = - currTar_Info->TarSelQ_Head; - - currTar_Info->TarSelQ_Head = - (struct sccb *)(pCurrCard->currentSCCB)-> - Sccb_forwardlink; - - if (currTar_Info->TarSelQ_Head == NULL) { - currTar_Info->TarSelQ_Tail = NULL; - currTar_Info->TarSelQ_Cnt = 0; - } else { - currTar_Info->TarSelQ_Cnt--; - currTar_Info->TarSelQ_Head-> - Sccb_backlink = (struct sccb *)NULL; - } - - scan_ptr++; - if (scan_ptr == MAX_SCSI_TAR) - scan_ptr = 0; - - pCurrCard->scanIndex = scan_ptr; - - pCurrCard->globalFlags |= F_NEW_SCCB_CMD; - - break; - } - - else { - scan_ptr++; - if (scan_ptr == MAX_SCSI_TAR) { - scan_ptr = 0; - } - } - } - } while (scan_ptr != pCurrCard->scanIndex); -} - -/*--------------------------------------------------------------------- - * - * Function: Queue Select Fail - * - * Description: Add the current SCCB to the head of the Queue. - * - *---------------------------------------------------------------------*/ - -static void FPT_queueSelectFail(struct sccb_card *pCurrCard, - unsigned char p_card) -{ - unsigned char thisTarg; - struct sccb_mgr_tar_info *currTar_Info; - - if (pCurrCard->currentSCCB != NULL) { - thisTarg = - (unsigned char)(((struct sccb *)(pCurrCard->currentSCCB))-> - TargID); - currTar_Info = &FPT_sccbMgrTbl[p_card][thisTarg]; - - pCurrCard->currentSCCB->Sccb_backlink = (struct sccb *)NULL; - - pCurrCard->currentSCCB->Sccb_forwardlink = - currTar_Info->TarSelQ_Head; - - if (currTar_Info->TarSelQ_Cnt == 0) { - currTar_Info->TarSelQ_Tail = pCurrCard->currentSCCB; - } - - else { - currTar_Info->TarSelQ_Head->Sccb_backlink = - pCurrCard->currentSCCB; - } - - currTar_Info->TarSelQ_Head = pCurrCard->currentSCCB; - - pCurrCard->currentSCCB = NULL; - currTar_Info->TarSelQ_Cnt++; - } -} - -/*--------------------------------------------------------------------- - * - * Function: Queue Command Complete - * - * Description: Call the callback function with the current SCCB. - * - *---------------------------------------------------------------------*/ - -static void FPT_queueCmdComplete(struct sccb_card *pCurrCard, - struct sccb *p_sccb, unsigned char p_card) -{ - - unsigned char i, SCSIcmd; - CALL_BK_FN callback; - struct sccb_mgr_tar_info *currTar_Info; - - SCSIcmd = p_sccb->Cdb[0]; - - if (!(p_sccb->Sccb_XferState & F_ALL_XFERRED)) { - - if ((p_sccb-> - ControlByte & (SCCB_DATA_XFER_OUT | SCCB_DATA_XFER_IN)) - && (p_sccb->HostStatus == SCCB_COMPLETE) - && (p_sccb->TargetStatus != SSCHECK)) - - if ((SCSIcmd == SCSI_READ) || - (SCSIcmd == SCSI_WRITE) || - (SCSIcmd == SCSI_READ_EXTENDED) || - (SCSIcmd == SCSI_WRITE_EXTENDED) || - (SCSIcmd == SCSI_WRITE_AND_VERIFY) || - (SCSIcmd == SCSI_START_STOP_UNIT) || - (pCurrCard->globalFlags & F_NO_FILTER) - ) - p_sccb->HostStatus = SCCB_DATA_UNDER_RUN; - } - - if (p_sccb->SccbStatus == SCCB_IN_PROCESS) { - if (p_sccb->HostStatus || p_sccb->TargetStatus) - p_sccb->SccbStatus = SCCB_ERROR; - else - p_sccb->SccbStatus = SCCB_SUCCESS; - } - - if (p_sccb->Sccb_XferState & F_AUTO_SENSE) { - - p_sccb->CdbLength = p_sccb->Save_CdbLen; - for (i = 0; i < 6; i++) { - p_sccb->Cdb[i] = p_sccb->Save_Cdb[i]; - } - } - - if ((p_sccb->OperationCode == RESIDUAL_SG_COMMAND) || - (p_sccb->OperationCode == RESIDUAL_COMMAND)) { - - FPT_utilUpdateResidual(p_sccb); - } - - pCurrCard->cmdCounter--; - if (!pCurrCard->cmdCounter) { - - if (pCurrCard->globalFlags & F_GREEN_PC) { - WR_HARPOON(pCurrCard->ioPort + hp_clkctrl_0, - (PWR_DWN | CLKCTRL_DEFAULT)); - WR_HARPOON(pCurrCard->ioPort + hp_sys_ctrl, STOP_CLK); - } - - WR_HARPOON(pCurrCard->ioPort + hp_semaphore, - (RD_HARPOON(pCurrCard->ioPort + hp_semaphore) & - ~SCCB_MGR_ACTIVE)); - - } - - if (pCurrCard->discQCount != 0) { - currTar_Info = &FPT_sccbMgrTbl[p_card][p_sccb->TargID]; - if (((pCurrCard->globalFlags & F_CONLUN_IO) && - ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != - TAG_Q_TRYING))) { - pCurrCard->discQCount--; - pCurrCard->discQ_Tbl[currTar_Info-> - LunDiscQ_Idx[p_sccb->Lun]] = NULL; - } else { - if (p_sccb->Sccb_tag) { - pCurrCard->discQCount--; - pCurrCard->discQ_Tbl[p_sccb->Sccb_tag] = NULL; - } else { - pCurrCard->discQCount--; - pCurrCard->discQ_Tbl[currTar_Info-> - LunDiscQ_Idx[0]] = NULL; - } - } - - } - - callback = (CALL_BK_FN) p_sccb->SccbCallback; - callback(p_sccb); - pCurrCard->globalFlags |= F_NEW_SCCB_CMD; - pCurrCard->currentSCCB = NULL; -} - -/*--------------------------------------------------------------------- - * - * Function: Queue Disconnect - * - * Description: Add SCCB to our disconnect array. - * - *---------------------------------------------------------------------*/ -static void FPT_queueDisconnect(struct sccb *p_sccb, unsigned char p_card) -{ - struct sccb_mgr_tar_info *currTar_Info; - - currTar_Info = &FPT_sccbMgrTbl[p_card][p_sccb->TargID]; - - if (((FPT_BL_Card[p_card].globalFlags & F_CONLUN_IO) && - ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))) { - FPT_BL_Card[p_card].discQ_Tbl[currTar_Info-> - LunDiscQ_Idx[p_sccb->Lun]] = - p_sccb; - } else { - if (p_sccb->Sccb_tag) { - FPT_BL_Card[p_card].discQ_Tbl[p_sccb->Sccb_tag] = - p_sccb; - FPT_sccbMgrTbl[p_card][p_sccb->TargID].TarLUNBusy[0] = - 0; - FPT_sccbMgrTbl[p_card][p_sccb->TargID].TarTagQ_Cnt++; - } else { - FPT_BL_Card[p_card].discQ_Tbl[currTar_Info-> - LunDiscQ_Idx[0]] = p_sccb; - } - } - FPT_BL_Card[p_card].currentSCCB = NULL; -} - -/*--------------------------------------------------------------------- - * - * Function: Queue Flush SCCB - * - * Description: Flush all SCCB's back to the host driver for this target. - * - *---------------------------------------------------------------------*/ - -static void FPT_queueFlushSccb(unsigned char p_card, unsigned char error_code) -{ - unsigned char qtag, thisTarg; - struct sccb *currSCCB; - struct sccb_mgr_tar_info *currTar_Info; - - currSCCB = FPT_BL_Card[p_card].currentSCCB; - if (currSCCB != NULL) { - thisTarg = (unsigned char)currSCCB->TargID; - currTar_Info = &FPT_sccbMgrTbl[p_card][thisTarg]; - - for (qtag = 0; qtag < QUEUE_DEPTH; qtag++) { - - if (FPT_BL_Card[p_card].discQ_Tbl[qtag] && - (FPT_BL_Card[p_card].discQ_Tbl[qtag]->TargID == - thisTarg)) { - - FPT_BL_Card[p_card].discQ_Tbl[qtag]-> - HostStatus = (unsigned char)error_code; - - FPT_queueCmdComplete(&FPT_BL_Card[p_card], - FPT_BL_Card[p_card]. - discQ_Tbl[qtag], p_card); - - FPT_BL_Card[p_card].discQ_Tbl[qtag] = NULL; - currTar_Info->TarTagQ_Cnt--; - - } - } - } - -} - -/*--------------------------------------------------------------------- - * - * Function: Queue Flush Target SCCB - * - * Description: Flush all SCCB's back to the host driver for this target. - * - *---------------------------------------------------------------------*/ - -static void FPT_queueFlushTargSccb(unsigned char p_card, unsigned char thisTarg, - unsigned char error_code) -{ - unsigned char qtag; - struct sccb_mgr_tar_info *currTar_Info; - - currTar_Info = &FPT_sccbMgrTbl[p_card][thisTarg]; - - for (qtag = 0; qtag < QUEUE_DEPTH; qtag++) { - - if (FPT_BL_Card[p_card].discQ_Tbl[qtag] && - (FPT_BL_Card[p_card].discQ_Tbl[qtag]->TargID == thisTarg)) { - - FPT_BL_Card[p_card].discQ_Tbl[qtag]->HostStatus = - (unsigned char)error_code; - - FPT_queueCmdComplete(&FPT_BL_Card[p_card], - FPT_BL_Card[p_card]. - discQ_Tbl[qtag], p_card); - - FPT_BL_Card[p_card].discQ_Tbl[qtag] = NULL; - currTar_Info->TarTagQ_Cnt--; - - } - } - -} - -static void FPT_queueAddSccb(struct sccb *p_SCCB, unsigned char p_card) -{ - struct sccb_mgr_tar_info *currTar_Info; - currTar_Info = &FPT_sccbMgrTbl[p_card][p_SCCB->TargID]; - - p_SCCB->Sccb_forwardlink = NULL; - - p_SCCB->Sccb_backlink = currTar_Info->TarSelQ_Tail; - - if (currTar_Info->TarSelQ_Cnt == 0) { - - currTar_Info->TarSelQ_Head = p_SCCB; - } - - else { - - currTar_Info->TarSelQ_Tail->Sccb_forwardlink = p_SCCB; - } - - currTar_Info->TarSelQ_Tail = p_SCCB; - currTar_Info->TarSelQ_Cnt++; -} - -/*--------------------------------------------------------------------- - * - * Function: Queue Find SCCB - * - * Description: Search the target select Queue for this SCCB, and - * remove it if found. - * - *---------------------------------------------------------------------*/ - -static unsigned char FPT_queueFindSccb(struct sccb *p_SCCB, - unsigned char p_card) -{ - struct sccb *q_ptr; - struct sccb_mgr_tar_info *currTar_Info; - - currTar_Info = &FPT_sccbMgrTbl[p_card][p_SCCB->TargID]; - - q_ptr = currTar_Info->TarSelQ_Head; - - while (q_ptr != NULL) { - - if (q_ptr == p_SCCB) { - - if (currTar_Info->TarSelQ_Head == q_ptr) { - - currTar_Info->TarSelQ_Head = - q_ptr->Sccb_forwardlink; - } - - if (currTar_Info->TarSelQ_Tail == q_ptr) { - - currTar_Info->TarSelQ_Tail = - q_ptr->Sccb_backlink; - } - - if (q_ptr->Sccb_forwardlink != NULL) { - q_ptr->Sccb_forwardlink->Sccb_backlink = - q_ptr->Sccb_backlink; - } - - if (q_ptr->Sccb_backlink != NULL) { - q_ptr->Sccb_backlink->Sccb_forwardlink = - q_ptr->Sccb_forwardlink; - } - - currTar_Info->TarSelQ_Cnt--; - - return 1; - } - - else { - q_ptr = q_ptr->Sccb_forwardlink; - } - } - - return 0; - -} - -/*--------------------------------------------------------------------- - * - * Function: Utility Update Residual Count - * - * Description: Update the XferCnt to the remaining byte count. - * If we transferred all the data then just write zero. - * If Non-SG transfer then report Total Cnt - Actual Transfer - * Cnt. For SG transfers add the count fields of all - * remaining SG elements, as well as any partial remaining - * element. - * - *---------------------------------------------------------------------*/ - -static void FPT_utilUpdateResidual(struct sccb *p_SCCB) -{ - unsigned long partial_cnt; - unsigned int sg_index; - unsigned long *sg_ptr; - - if (p_SCCB->Sccb_XferState & F_ALL_XFERRED) { - - p_SCCB->DataLength = 0x0000; - } - - else if (p_SCCB->Sccb_XferState & F_SG_XFER) { - - partial_cnt = 0x0000; - - sg_index = p_SCCB->Sccb_sgseg; - - sg_ptr = (unsigned long *)p_SCCB->DataPointer; - - if (p_SCCB->Sccb_SGoffset) { - - partial_cnt = p_SCCB->Sccb_SGoffset; - sg_index++; - } - - while (((unsigned long)sg_index * - (unsigned long)SG_ELEMENT_SIZE) < p_SCCB->DataLength) { - - partial_cnt += *(sg_ptr + (sg_index * 2)); - sg_index++; - } - - p_SCCB->DataLength = partial_cnt; - } - - else { - - p_SCCB->DataLength -= p_SCCB->Sccb_ATC; - } -} - -/*--------------------------------------------------------------------- - * - * Function: Wait 1 Second - * - * Description: Wait for 1 second. - * - *---------------------------------------------------------------------*/ - -static void FPT_Wait1Second(unsigned long p_port) -{ - unsigned char i; - - for (i = 0; i < 4; i++) { - - FPT_Wait(p_port, TO_250ms); - - if ((RD_HARPOON(p_port + hp_scsictrl_0) & SCSI_RST)) - break; - - if ((RDW_HARPOON((p_port + hp_intstat)) & SCAM_SEL)) - break; - } -} - -/*--------------------------------------------------------------------- - * - * Function: FPT_Wait - * - * Description: Wait the desired delay. - * - *---------------------------------------------------------------------*/ - -static void FPT_Wait(unsigned long p_port, unsigned char p_delay) -{ - unsigned char old_timer; - unsigned char green_flag; - - old_timer = RD_HARPOON(p_port + hp_seltimeout); - - green_flag = RD_HARPOON(p_port + hp_clkctrl_0); - WR_HARPOON(p_port + hp_clkctrl_0, CLKCTRL_DEFAULT); - - WR_HARPOON(p_port + hp_seltimeout, p_delay); - WRW_HARPOON((p_port + hp_intstat), TIMEOUT); - WRW_HARPOON((p_port + hp_intena), (FPT_default_intena & ~TIMEOUT)); - - WR_HARPOON(p_port + hp_portctrl_0, - (RD_HARPOON(p_port + hp_portctrl_0) | START_TO)); - - while (!(RDW_HARPOON((p_port + hp_intstat)) & TIMEOUT)) { - - if ((RD_HARPOON(p_port + hp_scsictrl_0) & SCSI_RST)) - break; - - if ((RDW_HARPOON((p_port + hp_intstat)) & SCAM_SEL)) - break; - } - - WR_HARPOON(p_port + hp_portctrl_0, - (RD_HARPOON(p_port + hp_portctrl_0) & ~START_TO)); - - WRW_HARPOON((p_port + hp_intstat), TIMEOUT); - WRW_HARPOON((p_port + hp_intena), FPT_default_intena); - - WR_HARPOON(p_port + hp_clkctrl_0, green_flag); - - WR_HARPOON(p_port + hp_seltimeout, old_timer); -} - -/*--------------------------------------------------------------------- - * - * Function: Enable/Disable Write to EEPROM - * - * Description: The EEPROM must first be enabled for writes - * A total of 9 clocks are needed. - * - *---------------------------------------------------------------------*/ - -static void FPT_utilEEWriteOnOff(unsigned long p_port, unsigned char p_mode) -{ - unsigned char ee_value; - - ee_value = - (unsigned char)(RD_HARPOON(p_port + hp_ee_ctrl) & - (EXT_ARB_ACK | SCSI_TERM_ENA_H)); - - if (p_mode) - - FPT_utilEESendCmdAddr(p_port, EWEN, EWEN_ADDR); - - else - - FPT_utilEESendCmdAddr(p_port, EWDS, EWDS_ADDR); - - WR_HARPOON(p_port + hp_ee_ctrl, (ee_value | SEE_MS)); /*Turn off CS */ - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); /*Turn off Master Select */ -} - -/*--------------------------------------------------------------------- - * - * Function: Write EEPROM - * - * Description: Write a word to the EEPROM at the specified - * address. - * - *---------------------------------------------------------------------*/ - -static void FPT_utilEEWrite(unsigned long p_port, unsigned short ee_data, - unsigned short ee_addr) -{ - - unsigned char ee_value; - unsigned short i; - - ee_value = - (unsigned - char)((RD_HARPOON(p_port + hp_ee_ctrl) & - (EXT_ARB_ACK | SCSI_TERM_ENA_H)) | (SEE_MS | SEE_CS)); - - FPT_utilEESendCmdAddr(p_port, EE_WRITE, ee_addr); - - ee_value |= (SEE_MS + SEE_CS); - - for (i = 0x8000; i != 0; i >>= 1) { - - if (i & ee_data) - ee_value |= SEE_DO; - else - ee_value &= ~SEE_DO; - - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - ee_value |= SEE_CLK; /* Clock data! */ - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - ee_value &= ~SEE_CLK; - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - } - ee_value &= (EXT_ARB_ACK | SCSI_TERM_ENA_H); - WR_HARPOON(p_port + hp_ee_ctrl, (ee_value | SEE_MS)); - - FPT_Wait(p_port, TO_10ms); - - WR_HARPOON(p_port + hp_ee_ctrl, (ee_value | SEE_MS | SEE_CS)); /* Set CS to EEPROM */ - WR_HARPOON(p_port + hp_ee_ctrl, (ee_value | SEE_MS)); /* Turn off CS */ - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); /* Turn off Master Select */ -} - -/*--------------------------------------------------------------------- - * - * Function: Read EEPROM - * - * Description: Read a word from the EEPROM at the desired - * address. - * - *---------------------------------------------------------------------*/ - -static unsigned short FPT_utilEERead(unsigned long p_port, - unsigned short ee_addr) -{ - unsigned short i, ee_data1, ee_data2; - - i = 0; - ee_data1 = FPT_utilEEReadOrg(p_port, ee_addr); - do { - ee_data2 = FPT_utilEEReadOrg(p_port, ee_addr); - - if (ee_data1 == ee_data2) - return ee_data1; - - ee_data1 = ee_data2; - i++; - - } while (i < 4); - - return ee_data1; -} - -/*--------------------------------------------------------------------- - * - * Function: Read EEPROM Original - * - * Description: Read a word from the EEPROM at the desired - * address. - * - *---------------------------------------------------------------------*/ - -static unsigned short FPT_utilEEReadOrg(unsigned long p_port, - unsigned short ee_addr) -{ - - unsigned char ee_value; - unsigned short i, ee_data; - - ee_value = - (unsigned - char)((RD_HARPOON(p_port + hp_ee_ctrl) & - (EXT_ARB_ACK | SCSI_TERM_ENA_H)) | (SEE_MS | SEE_CS)); - - FPT_utilEESendCmdAddr(p_port, EE_READ, ee_addr); - - ee_value |= (SEE_MS + SEE_CS); - ee_data = 0; - - for (i = 1; i <= 16; i++) { - - ee_value |= SEE_CLK; /* Clock data! */ - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - ee_value &= ~SEE_CLK; - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - - ee_data <<= 1; - - if (RD_HARPOON(p_port + hp_ee_ctrl) & SEE_DI) - ee_data |= 1; - } - - ee_value &= ~(SEE_MS + SEE_CS); - WR_HARPOON(p_port + hp_ee_ctrl, (ee_value | SEE_MS)); /*Turn off CS */ - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); /*Turn off Master Select */ - - return ee_data; -} - -/*--------------------------------------------------------------------- - * - * Function: Send EE command and Address to the EEPROM - * - * Description: Transfers the correct command and sends the address - * to the eeprom. - * - *---------------------------------------------------------------------*/ - -static void FPT_utilEESendCmdAddr(unsigned long p_port, unsigned char ee_cmd, - unsigned short ee_addr) -{ - unsigned char ee_value; - unsigned char narrow_flg; - - unsigned short i; - - narrow_flg = - (unsigned char)(RD_HARPOON(p_port + hp_page_ctrl) & - NARROW_SCSI_CARD); - - ee_value = SEE_MS; - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - - ee_value |= SEE_CS; /* Set CS to EEPROM */ - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - - for (i = 0x04; i != 0; i >>= 1) { - - if (i & ee_cmd) - ee_value |= SEE_DO; - else - ee_value &= ~SEE_DO; - - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - ee_value |= SEE_CLK; /* Clock data! */ - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - ee_value &= ~SEE_CLK; - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - } - - if (narrow_flg) - i = 0x0080; - - else - i = 0x0200; - - while (i != 0) { - - if (i & ee_addr) - ee_value |= SEE_DO; - else - ee_value &= ~SEE_DO; - - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - ee_value |= SEE_CLK; /* Clock data! */ - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - ee_value &= ~SEE_CLK; - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - WR_HARPOON(p_port + hp_ee_ctrl, ee_value); - - i >>= 1; - } -} - -static unsigned short FPT_CalcCrc16(unsigned char buffer[]) -{ - unsigned short crc = 0; - int i, j; - unsigned short ch; - for (i = 0; i < ID_STRING_LENGTH; i++) { - ch = (unsigned short)buffer[i]; - for (j = 0; j < 8; j++) { - if ((crc ^ ch) & 1) - crc = (crc >> 1) ^ CRCMASK; - else - crc >>= 1; - ch >>= 1; - } - } - return crc; -} - -static unsigned char FPT_CalcLrc(unsigned char buffer[]) -{ - int i; - unsigned char lrc; - lrc = 0; - for (i = 0; i < ID_STRING_LENGTH; i++) - lrc ^= buffer[i]; - return lrc; -} - -/* - The following inline definitions avoid type conflicts. -*/ - -static inline unsigned char -FlashPoint__ProbeHostAdapter(struct FlashPoint_Info *FlashPointInfo) -{ - return FlashPoint_ProbeHostAdapter((struct sccb_mgr_info *) - FlashPointInfo); -} - -static inline FlashPoint_CardHandle_T -FlashPoint__HardwareResetHostAdapter(struct FlashPoint_Info *FlashPointInfo) -{ - return FlashPoint_HardwareResetHostAdapter((struct sccb_mgr_info *) - FlashPointInfo); -} - -static inline void -FlashPoint__ReleaseHostAdapter(FlashPoint_CardHandle_T CardHandle) -{ - FlashPoint_ReleaseHostAdapter(CardHandle); -} - -static inline void -FlashPoint__StartCCB(FlashPoint_CardHandle_T CardHandle, - struct BusLogic_CCB *CCB) -{ - FlashPoint_StartCCB(CardHandle, (struct sccb *)CCB); -} - -static inline void -FlashPoint__AbortCCB(FlashPoint_CardHandle_T CardHandle, - struct BusLogic_CCB *CCB) -{ - FlashPoint_AbortCCB(CardHandle, (struct sccb *)CCB); -} - -static inline bool -FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle) -{ - return FlashPoint_InterruptPending(CardHandle); -} - -static inline int -FlashPoint__HandleInterrupt(FlashPoint_CardHandle_T CardHandle) -{ - return FlashPoint_HandleInterrupt(CardHandle); -} - -#define FlashPoint_ProbeHostAdapter FlashPoint__ProbeHostAdapter -#define FlashPoint_HardwareResetHostAdapter FlashPoint__HardwareResetHostAdapter -#define FlashPoint_ReleaseHostAdapter FlashPoint__ReleaseHostAdapter -#define FlashPoint_StartCCB FlashPoint__StartCCB -#define FlashPoint_AbortCCB FlashPoint__AbortCCB -#define FlashPoint_InterruptPending FlashPoint__InterruptPending -#define FlashPoint_HandleInterrupt FlashPoint__HandleInterrupt - -#else /* !CONFIG_SCSI_FLASHPOINT */ - -/* - Define prototypes for the FlashPoint SCCB Manager Functions. -*/ - -extern unsigned char FlashPoint_ProbeHostAdapter(struct FlashPoint_Info *); -extern FlashPoint_CardHandle_T -FlashPoint_HardwareResetHostAdapter(struct FlashPoint_Info *); -extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, struct BusLogic_CCB *); -extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, struct BusLogic_CCB *); -extern bool FlashPoint_InterruptPending(FlashPoint_CardHandle_T); -extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T); -extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T); - -#endif /* CONFIG_SCSI_FLASHPOINT */ diff --git a/ANDROID_3.4.5/drivers/scsi/Kconfig b/ANDROID_3.4.5/drivers/scsi/Kconfig deleted file mode 100644 index 29684c81..00000000 --- a/ANDROID_3.4.5/drivers/scsi/Kconfig +++ /dev/null @@ -1,1923 +0,0 @@ -menu "SCSI device support" - -config SCSI_MOD - tristate - default y if SCSI=n || SCSI=y - default m if SCSI=m - -config RAID_ATTRS - tristate "RAID Transport Class" - default n - depends on BLOCK - depends on SCSI_MOD - ---help--- - Provides RAID - -config SCSI - tristate "SCSI device support" - depends on BLOCK - select SCSI_DMA if HAS_DMA - ---help--- - If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or - any other SCSI device under Linux, say Y and make sure that you know - the name of your SCSI host adapter (the card inside your computer - that "speaks" the SCSI protocol, also called SCSI controller), - because you will be asked for it. - - You also need to say Y here if you have a device which speaks - the SCSI protocol. Examples of this include the parallel port - version of the IOMEGA ZIP drive, USB storage devices, Fibre - Channel, and FireWire storage. - - To compile this driver as a module, choose M here and read - . - The module will be called scsi_mod. - - However, do not compile this as a module if your root file system - (the one containing the directory /) is located on a SCSI device. - -config SCSI_DMA - bool - default n - -config SCSI_TGT - tristate "SCSI target support" - depends on SCSI && EXPERIMENTAL - ---help--- - If you want to use SCSI target mode drivers enable this option. - If you choose M, the module will be called scsi_tgt. - -config SCSI_NETLINK - bool - default n - select NET - -config SCSI_PROC_FS - bool "legacy /proc/scsi/ support" - depends on SCSI && PROC_FS - default y - ---help--- - This option enables support for the various files in - /proc/scsi. In Linux 2.6 this has been superseded by - files in sysfs but many legacy applications rely on this. - - If unsure say Y. - -comment "SCSI support type (disk, tape, CD-ROM)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - select CRC_T10DIF if BLK_DEV_INTEGRITY - ---help--- - If you want to use SCSI hard disks, Fibre Channel disks, - Serial ATA (SATA) or Parallel ATA (PATA) hard disks, - USB storage or the SCSI or parallel port version of - the IOMEGA ZIP drive, say Y and read the SCSI-HOWTO, - the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - To compile this driver as a module, choose M here and read - . - The module will be called sd_mod. - - Do not compile this driver as a module if your root file system - (the one containing the directory /) is located on a SCSI disk. - In this case, do not compile the driver for your SCSI host adapter - (below) as a module either. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT - for SCSI CD-ROMs. - - To compile this driver as a module, choose M here and read - . The module will be called st. - -config CHR_DEV_OSST - tristate "SCSI OnStream SC-x0 tape support" - depends on SCSI - ---help--- - The OnStream SC-x0 SCSI tape drives cannot be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). Via usb-storage, - you may be able to drive the USB-x0 and DI-x0 drives as well. - Note that there is also a second generation of OnStream - tape drives (ADR-x0) that supports the standard SCSI-2 commands for - tapes (QIC-157) and can be driven by the standard driver st. - For more information, you may have a look at the SCSI-HOWTO - and - in the kernel source. - More info on the OnStream driver may be found on - - Please also have a look at the standard st docu, as most of it - applies to osst as well. - - To compile this driver as a module, choose M here and read - . The module will be called osst. - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a CD or DVD drive attached to your computer - by SCSI, FireWire, USB or ATAPI, say Y and read the SCSI-HOWTO - and the CDROM-HOWTO at . - - Make sure to say Y or M to "ISO 9660 CD-ROM file system support". - - To compile this driver as a module, choose M here and read - . - The module will be called sr_mod. - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - To compile this driver as a module, choose M here and read - . The module will be called sg. - - If unsure, say N. - -config CHR_DEV_SCH - tristate "SCSI media changer support" - depends on SCSI - ---help--- - This is a driver for SCSI media changers. Most common devices are - tape libraries and MOD/CDROM jukeboxes. *Real* jukeboxes, you - don't need this for those tiny 6-slot cdrom changers. Media - changers are listed as "Type: Medium Changer" in /proc/scsi/scsi. - If you have such hardware and want to use it with linux, say Y - here. Check for details. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called ch.o. - If unsure, say N. - -config SCSI_ENCLOSURE - tristate "SCSI Enclosure Support" - depends on SCSI && ENCLOSURE_SERVICES - help - Enclosures are devices sitting on or in SCSI backplanes that - manage devices. If you have a disk cage, the chances are that - it has an enclosure device. Selecting this option will just allow - certain enclosure conditions to be reported and is not required. - -config SCSI_MULTI_LUN - bool "Probe all LUNs on each SCSI device" - depends on SCSI - help - Some devices support more than one LUN (Logical Unit Number) in order - to allow access to several media, e.g. CD jukebox, USB card reader, - mobile phone in mass storage mode. This option forces the kernel to - probe for all LUNs by default. This setting can be overriden by - max_luns boot/module parameter. Note that this option does not affect - devices conforming to SCSI-3 or higher as they can explicitely report - their number of LUNs. It is safe to say Y here unless you have one of - those rare devices which reacts in an unexpected way when probed for - multiple LUNs. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size +=12K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 12 KB. If in doubt, say Y. - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - ---help--- - This turns on a logging facility that can be used to debug a number - of SCSI related problems. - - If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo > /proc/sys/dev/scsi/logging_level - - where is a four byte value representing the logging type - and logging level for each type of logging selected. - - There are a number of logging types and you can find them in the - source at . The logging levels - are also described in that file and they determine the verbosity of - the logging for each logging type. - - If you say N here, it may be harder to track down some types of SCSI - problems. If you say Y here your kernel will be somewhat larger, but - there should be no noticeable performance impact as long as you have - logging turned off. - -config SCSI_SCAN_ASYNC - bool "Asynchronous SCSI scanning" - depends on SCSI - help - The SCSI subsystem can probe for devices while the rest of the - system continues booting, and even probe devices on different - busses in parallel, leading to a significant speed-up. - - If you have built SCSI as modules, enabling this option can - be a problem as the devices may not have been found by the - time your system expects them to have been. You can load the - scsi_wait_scan module to ensure that all scans have completed. - If you build your SCSI drivers into the kernel, then everything - will work fine if you say Y here. - - You can override this choice by specifying "scsi_mod.scan=sync" - or async on the kernel's command line. - -config SCSI_WAIT_SCAN - tristate # No prompt here, this is an invisible symbol. - default m - depends on SCSI - depends on MODULES -# scsi_wait_scan is a loadable module which waits until all the async scans are -# complete. The idea is to use it in initrd/ initramfs scripts. You modprobe -# it after all the modprobes of the root SCSI drivers and it will wait until -# they have all finished scanning their buses before allowing the boot to -# proceed. (This method is not applicable if targets boot independently in -# parallel with the initiator, or with transports with non-deterministic target -# discovery schemes, or if a transport driver does not support scsi_wait_scan.) -# -# This symbol is not exposed as a prompt because little is to be gained by -# disabling it, whereas people who accidentally switch it off may wonder why -# their mkinitrd gets into trouble. - -menu "SCSI Transports" - depends on SCSI - -config SCSI_SPI_ATTRS - tristate "Parallel SCSI (SPI) Transport Attributes" - depends on SCSI - help - If you wish to export transport-specific information about - each attached SCSI device to sysfs, say Y. Otherwise, say N. - -config SCSI_FC_ATTRS - tristate "FiberChannel Transport Attributes" - depends on SCSI - select SCSI_NETLINK - help - If you wish to export transport-specific information about - each attached FiberChannel device to sysfs, say Y. - Otherwise, say N. - -config SCSI_FC_TGT_ATTRS - bool "SCSI target support for FiberChannel Transport Attributes" - depends on SCSI_FC_ATTRS - depends on SCSI_TGT = y || SCSI_TGT = SCSI_FC_ATTRS - help - If you want to use SCSI target mode drivers enable this option. - -config SCSI_ISCSI_ATTRS - tristate "iSCSI Transport Attributes" - depends on SCSI && NET - select BLK_DEV_BSGLIB - help - If you wish to export transport-specific information about - each attached iSCSI device to sysfs, say Y. - Otherwise, say N. - -config SCSI_SAS_ATTRS - tristate "SAS Transport Attributes" - depends on SCSI - select BLK_DEV_BSG - help - If you wish to export transport-specific information about - each attached SAS device to sysfs, say Y. - -source "drivers/scsi/libsas/Kconfig" - -config SCSI_SRP_ATTRS - tristate "SRP Transport Attributes" - depends on SCSI - help - If you wish to export transport-specific information about - each attached SRP device to sysfs, say Y. - -config SCSI_SRP_TGT_ATTRS - bool "SCSI target support for SRP Transport Attributes" - depends on SCSI_SRP_ATTRS - depends on SCSI_TGT = y || SCSI_TGT = SCSI_SRP_ATTRS - help - If you want to use SCSI target mode drivers enable this option. - -endmenu - -menuconfig SCSI_LOWLEVEL - bool "SCSI low-level drivers" - depends on SCSI!=n - default y - -if SCSI_LOWLEVEL && SCSI - -config ISCSI_TCP - tristate "iSCSI Initiator over TCP/IP" - depends on SCSI && INET - select CRYPTO - select CRYPTO_MD5 - select CRYPTO_CRC32C - select SCSI_ISCSI_ATTRS - help - The iSCSI Driver provides a host with the ability to access storage - through an IP network. The driver uses the iSCSI protocol to transport - SCSI requests and responses over a TCP/IP network between the host - (the "initiator") and "targets". Architecturally, the iSCSI driver - combines with the host's TCP/IP stack, network drivers, and Network - Interface Card (NIC) to provide the same functions as a SCSI or a - Fibre Channel (FC) adapter driver with a Host Bus Adapter (HBA). - - To compile this driver as a module, choose M here: the - module will be called iscsi_tcp. - - The userspace component needed to initialize the driver, documentation, - and sample configuration files can be found here: - - http://open-iscsi.org - -config ISCSI_BOOT_SYSFS - tristate "iSCSI Boot Sysfs Interface" - default n - help - This option enables support for exposing iSCSI boot information - via sysfs to userspace. If you wish to export this information, - say Y. Otherwise, say N. - -source "drivers/scsi/cxgbi/Kconfig" -source "drivers/scsi/bnx2i/Kconfig" -source "drivers/scsi/bnx2fc/Kconfig" -source "drivers/scsi/be2iscsi/Kconfig" - -config SGIWD93_SCSI - tristate "SGI WD93C93 SCSI Driver" - depends on SGI_HAS_WD93 && SCSI - help - If you have a Western Digital WD93 SCSI controller on - an SGI MIPS system, say Y. Otherwise, say N. - -config BLK_DEV_3W_XXXX_RAID - tristate "3ware 5/6/7/8xxx ATA-RAID support" - depends on PCI && SCSI - help - 3ware is the only hardware ATA-Raid product in Linux to date. - This card is 2,4, or 8 channel master mode support only. - SCSI support required!!! - - - - Please read the comments at the top of - . - -config SCSI_HPSA - tristate "HP Smart Array SCSI driver" - depends on PCI && SCSI - help - This driver supports HP Smart Array Controllers (circa 2009). - It is a SCSI alternative to the cciss driver, which is a block - driver. Anyone wishing to use HP Smart Array controllers who - would prefer the devices be presented to linux as SCSI devices, - rather than as generic block devices should say Y here. - -config SCSI_3W_9XXX - tristate "3ware 9xxx SATA-RAID support" - depends on PCI && SCSI - help - This driver supports the 9000 series 3ware SATA-RAID cards. - - - - Please read the comments at the top of - . - -config SCSI_3W_SAS - tristate "3ware 97xx SAS/SATA-RAID support" - depends on PCI && SCSI - help - This driver supports the LSI 3ware 9750 6Gb/s SAS/SATA-RAID cards. - - - - Please read the comments at the top of - . - -config SCSI_7000FASST - tristate "7000FASST SCSI support" - depends on ISA && SCSI && ISA_DMA_API - select CHECK_SIGNATURE - help - This driver supports the Western Digital 7000 SCSI host adapter - family. Some information is in the source: - . - - To compile this driver as a module, choose M here: the - module will be called wd7000. - -config SCSI_ACARD - tristate "ACARD SCSI support" - depends on PCI && SCSI - help - This driver supports the ACARD SCSI host adapter. - Support Chip - To compile this driver as a module, choose M here: the - module will be called atp870u. - -config SCSI_AHA152X - tristate "Adaptec AHA152X/2825 support" - depends on ISA && SCSI && !64BIT - select SCSI_SPI_ATTRS - select CHECK_SIGNATURE - ---help--- - This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825 - SCSI host adapters. It also works for the AVA-1505, but the IRQ etc. - must be manually specified in this case. - - It is explained in section 3.3 of the SCSI-HOWTO, available from - . You might also want to - read the file . - - To compile this driver as a module, choose M here: the - module will be called aha152x. - -config SCSI_AHA1542 - tristate "Adaptec AHA1542 support" - depends on ISA && SCSI && ISA_DMA_API - ---help--- - This is support for a SCSI host adapter. It is explained in section - 3.4 of the SCSI-HOWTO, available from - . Note that Trantor was - purchased by Adaptec, and some former Trantor products are being - sold under the Adaptec name. If it doesn't work out of the box, you - may have to change some settings in . - - To compile this driver as a module, choose M here: the - module will be called aha1542. - -config SCSI_AHA1740 - tristate "Adaptec AHA1740 support" - depends on EISA && SCSI - ---help--- - This is support for a SCSI host adapter. It is explained in section - 3.5 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . - - To compile this driver as a module, choose M here: the - module will be called aha1740. - -config SCSI_AACRAID - tristate "Adaptec AACRAID support" - depends on SCSI && PCI - help - This driver supports a variety of Dell, HP, Adaptec, IBM and - ICP storage products. For a list of supported products, refer - to . - - To compile this driver as a module, choose M here: the module - will be called aacraid. - - -source "drivers/scsi/aic7xxx/Kconfig.aic7xxx" - -config SCSI_AIC7XXX_OLD - tristate "Adaptec AIC7xxx support (old driver)" - depends on (ISA || EISA || PCI ) && SCSI - help - WARNING This driver is an older aic7xxx driver and is no longer - under active development. Adaptec, Inc. is writing a new driver to - take the place of this one, and it is recommended that whenever - possible, people should use the new Adaptec written driver instead - of this one. This driver will eventually be phased out entirely. - - This is support for the various aic7xxx based Adaptec SCSI - controllers. These include the 274x EISA cards; 284x VLB cards; - 2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and - motherboard based SCSI controllers from Adaptec. It does not support - the AAA-13x RAID controllers from Adaptec, nor will it likely ever - support them. It does not support the 2920 cards from Adaptec that - use the Future Domain SCSI controller chip. For those cards, you - need the "Future Domain 16xx SCSI support" driver. - - In general, if the controller is based on an Adaptec SCSI controller - chip from the aic777x series or the aic78xx series, this driver - should work. The only exception is the 7810 which is specifically - not supported (that's the RAID controller chip on the AAA-13x - cards). - - Note that the AHA2920 SCSI host adapter is *not* supported by this - driver; choose "Future Domain 16xx SCSI support" instead if you have - one of those. - - Information on the configuration options for this controller can be - found by checking the help file for each of the available - configuration options. You should read - at a minimum before - contacting the maintainer with any questions. The SCSI-HOWTO, - available from , can also - be of great help. - - To compile this driver as a module, choose M here: the - module will be called aic7xxx_old. - -source "drivers/scsi/aic7xxx/Kconfig.aic79xx" -source "drivers/scsi/aic94xx/Kconfig" -source "drivers/scsi/mvsas/Kconfig" - -config SCSI_MVUMI - tristate "Marvell UMI driver" - depends on SCSI && PCI - help - Module for Marvell Universal Message Interface(UMI) driver - - To compile this driver as a module, choose M here: the - module will be called mvumi. - -config SCSI_DPT_I2O - tristate "Adaptec I2O RAID support " - depends on SCSI && PCI && VIRT_TO_BUS - help - This driver supports all of Adaptec's I2O based RAID controllers as - well as the DPT SmartRaid V cards. This is an Adaptec maintained - driver by Deanna Bonds. See . - - To compile this driver as a module, choose M here: the - module will be called dpt_i2o. - -config SCSI_ADVANSYS - tristate "AdvanSys SCSI support" - depends on SCSI && VIRT_TO_BUS - depends on ISA || EISA || PCI - help - This is a driver for all SCSI host adapters manufactured by - AdvanSys. It is documented in the kernel source in - . - - To compile this driver as a module, choose M here: the - module will be called advansys. - -config SCSI_IN2000 - tristate "Always IN2000 SCSI support" - depends on ISA && SCSI - help - This is support for an ISA bus SCSI host adapter. You'll find more - information in . If it doesn't work - out of the box, you may have to change the jumpers for IRQ or - address selection. - - To compile this driver as a module, choose M here: the - module will be called in2000. - -config SCSI_ARCMSR - tristate "ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Adapter" - depends on PCI && SCSI - help - This driver supports all of ARECA's SATA/SAS RAID controller cards. - This is an ARECA-maintained driver by Erich Chen. - If you have any problems, please mail to: . - Areca supports Linux RAID config tools. - Please link - - To compile this driver as a module, choose M here: the - module will be called arcmsr (modprobe arcmsr). - -source "drivers/scsi/megaraid/Kconfig.megaraid" -source "drivers/scsi/mpt2sas/Kconfig" -source "drivers/scsi/ufs/Kconfig" - -config SCSI_HPTIOP - tristate "HighPoint RocketRAID 3xxx/4xxx Controller support" - depends on SCSI && PCI - help - This option enables support for HighPoint RocketRAID 3xxx/4xxx - controllers. - - To compile this driver as a module, choose M here; the module - will be called hptiop. If unsure, say N. - -config SCSI_BUSLOGIC - tristate "BusLogic SCSI support" - depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API && VIRT_TO_BUS - ---help--- - This is support for BusLogic MultiMaster and FlashPoint SCSI Host - Adapters. Consult the SCSI-HOWTO, available from - , and the files - and - for more information. - Note that support for FlashPoint is only available for 32-bit - x86 configurations. - - To compile this driver as a module, choose M here: the - module will be called BusLogic. - -config SCSI_FLASHPOINT - bool "FlashPoint support" - depends on SCSI_BUSLOGIC && PCI && X86_32 - help - This option allows you to add FlashPoint support to the - BusLogic SCSI driver. The FlashPoint SCCB Manager code is - substantial, so users of MultiMaster Host Adapters may not - wish to include it. - -config VMWARE_PVSCSI - tristate "VMware PVSCSI driver support" - depends on PCI && SCSI && X86 - help - This driver supports VMware's para virtualized SCSI HBA. - To compile this driver as a module, choose M here: the - module will be called vmw_pvscsi. - -config HYPERV_STORAGE - tristate "Microsoft Hyper-V virtual storage driver" - depends on SCSI && HYPERV - default HYPERV - help - Select this option to enable the Hyper-V virtual storage driver. - -config LIBFC - tristate "LibFC module" - select SCSI_FC_ATTRS - select CRC32 - ---help--- - Fibre Channel library module - -config LIBFCOE - tristate "LibFCoE module" - select LIBFC - ---help--- - Library for Fibre Channel over Ethernet module - -config FCOE - tristate "FCoE module" - depends on PCI - select LIBFCOE - ---help--- - Fibre Channel over Ethernet module - -config FCOE_FNIC - tristate "Cisco FNIC Driver" - depends on PCI && X86 - select LIBFCOE - help - This is support for the Cisco PCI-Express FCoE HBA. - - To compile this driver as a module, choose M here and read - . - The module will be called fnic. - -config SCSI_DMX3191D - tristate "DMX3191D SCSI support" - depends on PCI && SCSI - select SCSI_SPI_ATTRS - help - This is support for Domex DMX3191D SCSI Host Adapters. - - To compile this driver as a module, choose M here: the - module will be called dmx3191d. - -config SCSI_DTC3280 - tristate "DTC3180/3280 SCSI support" - depends on ISA && SCSI - select SCSI_SPI_ATTRS - select CHECK_SIGNATURE - help - This is support for DTC 3180/3280 SCSI Host Adapters. Please read - the SCSI-HOWTO, available from - , and the file - . - - To compile this driver as a module, choose M here: the - module will be called dtc. - -config SCSI_EATA - tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support" - depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API - ---help--- - This driver supports all EATA/DMA-compliant SCSI host adapters. DPT - ISA and all EISA I/O addresses are probed looking for the "EATA" - signature. The addresses of all the PCI SCSI controllers reported - by the PCI subsystem are probed as well. - - You want to read the start of and the - SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called eata. - -config SCSI_EATA_TAGGED_QUEUE - bool "enable tagged command queueing" - depends on SCSI_EATA - help - This is a feature of SCSI-2 which improves performance: the host - adapter can send several SCSI commands to a device's queue even if - previous commands haven't finished yet. - This is equivalent to the "eata=tc:y" boot option. - -config SCSI_EATA_LINKED_COMMANDS - bool "enable elevator sorting" - depends on SCSI_EATA - help - This option enables elevator sorting for all probed SCSI disks and - CD-ROMs. It definitely reduces the average seek distance when doing - random seeks, but this does not necessarily result in a noticeable - performance improvement: your mileage may vary... - This is equivalent to the "eata=lc:y" boot option. - -config SCSI_EATA_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_EATA - default "16" - help - This specifies how many SCSI commands can be maximally queued for - each probed SCSI device. You should reduce the default value of 16 - only if you have disks with buggy or limited tagged command support. - Minimum is 2 and maximum is 62. This value is also the window size - used by the elevator sorting option above. The effective value used - by the driver for each probed SCSI device is reported at boot time. - This is equivalent to the "eata=mq:8" boot option. - -config SCSI_EATA_PIO - tristate "EATA-PIO (old DPT PM2001, PM2012A) support" - depends on (ISA || EISA || PCI) && SCSI && BROKEN - ---help--- - This driver supports all EATA-PIO protocol compliant SCSI Host - Adapters like the DPT PM2001 and the PM2012A. EATA-DMA compliant - host adapters could also use this driver but are discouraged from - doing so, since this driver only supports hard disks and lacks - numerous features. You might want to have a look at the SCSI-HOWTO, - available from . - - To compile this driver as a module, choose M here: the - module will be called eata_pio. - -config SCSI_FUTURE_DOMAIN - tristate "Future Domain 16xx SCSI/AHA-2920A support" - depends on (ISA || PCI) && SCSI - select CHECK_SIGNATURE - ---help--- - This is support for Future Domain's 16-bit SCSI host adapters - (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and - other adapters based on the Future Domain chipsets (Quantum - ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board). - It is explained in section 3.7 of the SCSI-HOWTO, available from - . - - NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip - and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI - controller support"). This Future Domain driver works with the older - Adaptec AHA-2920A boards with a Future Domain chip on them. - - To compile this driver as a module, choose M here: the - module will be called fdomain. - -config SCSI_FD_MCS - tristate "Future Domain MCS-600/700 SCSI support" - depends on MCA_LEGACY && SCSI - ---help--- - This is support for Future Domain MCS 600/700 MCA SCSI adapters. - Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which - is identical to the MCS 700 and hence also supported by this driver. - This driver also supports the Reply SB16/SCSI card (the SCSI part). - It supports multiple adapters in the same system. - - To compile this driver as a module, choose M here: the - module will be called fd_mcs. - -config SCSI_GDTH - tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" - depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API - ---help--- - Formerly called GDT SCSI Disk Array Controller Support. - - This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) - manufactured by Intel Corporation/ICP vortex GmbH. It is documented - in the kernel source in and - . - - To compile this driver as a module, choose M here: the - module will be called gdth. - -config SCSI_ISCI - tristate "Intel(R) C600 Series Chipset SAS Controller" - depends on PCI && SCSI - depends on X86 - select SCSI_SAS_LIBSAS - ---help--- - This driver supports the 6Gb/s SAS capabilities of the storage - control unit found in the Intel(R) C600 series chipset. - -config SCSI_GENERIC_NCR5380 - tristate "Generic NCR5380/53c400 SCSI PIO support" - depends on ISA && SCSI - select SCSI_SPI_ATTRS - ---help--- - This is a driver for the old NCR 53c80 series of SCSI controllers - on boards using PIO. Most boards such as the Trantor T130 fit this - category, along with a large number of ISA 8bit controllers shipped - for free with SCSI scanners. If you have a PAS16, T128 or DMX3191 - you should select the specific driver for that card rather than - generic 5380 support. - - It is explained in section 3.8 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . - - To compile this driver as a module, choose M here: the - module will be called g_NCR5380. - -config SCSI_GENERIC_NCR5380_MMIO - tristate "Generic NCR5380/53c400 SCSI MMIO support" - depends on ISA && SCSI - select SCSI_SPI_ATTRS - ---help--- - This is a driver for the old NCR 53c80 series of SCSI controllers - on boards using memory mapped I/O. - It is explained in section 3.8 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . - - To compile this driver as a module, choose M here: the - module will be called g_NCR5380_mmio. - -config SCSI_GENERIC_NCR53C400 - bool "Enable NCR53c400 extensions" - depends on SCSI_GENERIC_NCR5380 - help - This enables certain optimizations for the NCR53c400 SCSI cards. - You might as well try it out. Note that this driver will only probe - for the Trantor T130B in its default configuration; you might have - to pass a command line option to the kernel at boot time if it does - not detect your card. See the file - for details. - -config SCSI_IBMMCA - tristate "IBMMCA SCSI support" - depends on MCA && SCSI - ---help--- - This is support for the IBM SCSI adapter found in many of the PS/2 - series computers. These machines have an MCA bus, so you need to - answer Y to "MCA support" as well and read - . - - If the adapter isn't found during boot (a common problem for models - 56, 57, 76, and 77) you'll need to use the 'ibmmcascsi=' kernel - option, where is the id of the SCSI subsystem (usually 7, but - if that doesn't work check your reference diskette). Owners of - model 95 with a LED-matrix-display can in addition activate some - activity info like under OS/2, but more informative, by setting - 'ibmmcascsi=display' as an additional kernel parameter. Try "man - bootparam" or see the documentation of your boot loader about how to - pass options to the kernel. - - To compile this driver as a module, choose M here: the - module will be called ibmmca. - -config IBMMCA_SCSI_ORDER_STANDARD - bool "Standard SCSI-order" - depends on SCSI_IBMMCA - ---help--- - In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks - are assigned to the drive letters, starting with the lowest SCSI-id - (physical number -- pun) to be drive C:, as seen from DOS and - similar operating systems. When looking into papers describing the - ANSI-SCSI-standard, this assignment of drives appears to be wrong. - The SCSI-standard follows a hardware-hierarchy which says that id 7 - has the highest priority and id 0 the lowest. Therefore, the host - adapters are still today everywhere placed as SCSI-id 7 by default. - In the SCSI-standard, the drive letters express the priority of the - disk. C: should be the hard disk, or a partition on it, with the - highest priority. This must therefore be the disk with the highest - SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the - original definition of the SCSI-standard as also industrial- and - process-control-machines, like VME-CPUs running under realtime-OSes - (e.g. LynxOS, OS9) do. - - If you like to run Linux on your MCA-machine with the same - assignment of hard disks as seen from e.g. DOS or OS/2 on your - machine, which is in addition conformant to the SCSI-standard, you - must say Y here. This is also necessary for MCA-Linux users who want - to keep downward compatibility to older releases of the - IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than - June 1997). - - If you like to have the lowest SCSI-id assigned as drive C:, as - modern SCSI-BIOSes do, which does not conform to the standard, but - is widespread and common in the PC-world of today, you must say N - here. If unsure, say Y. - -config IBMMCA_SCSI_DEV_RESET - bool "Reset SCSI-devices at boottime" - depends on SCSI_IBMMCA - ---help--- - By default, SCSI-devices are reset when the machine is powered on. - However, some devices exist, like special-control-devices, - SCSI-CNC-machines, SCSI-printer or scanners of older type, that do - not reset when switched on. If you say Y here, each device connected - to your SCSI-bus will be issued a reset-command after it has been - probed, while the kernel is booting. This may cause problems with - more modern devices, like hard disks, which do not appreciate these - reset commands, and can cause your system to hang. So say Y only if - you know that one of your older devices needs it; N is the safe - answer. - -config SCSI_IPS - tristate "IBM ServeRAID support" - depends on PCI && SCSI - ---help--- - This is support for the IBM ServeRAID hardware RAID controllers. - See - and - for more information. If this driver does not work correctly - without modification please contact the author by email at - . - - To compile this driver as a module, choose M here: the - module will be called ips. - -config SCSI_IBMVSCSI - tristate "IBM Virtual SCSI support" - depends on PPC_PSERIES - select SCSI_SRP_ATTRS - help - This is the IBM POWER Virtual SCSI Client - - To compile this driver as a module, choose M here: the - module will be called ibmvscsic. - -config SCSI_IBMVSCSIS - tristate "IBM Virtual SCSI Server support" - depends on PPC_PSERIES && SCSI_SRP && SCSI_SRP_TGT_ATTRS - help - This is the SRP target driver for IBM pSeries virtual environments. - - The userspace component needed to initialize the driver and - documentation can be found: - - http://stgt.berlios.de/ - - To compile this driver as a module, choose M here: the - module will be called ibmvstgt. - -config SCSI_IBMVFC - tristate "IBM Virtual FC support" - depends on PPC_PSERIES && SCSI - select SCSI_FC_ATTRS - help - This is the IBM POWER Virtual FC Client - - To compile this driver as a module, choose M here: the - module will be called ibmvfc. - -config SCSI_IBMVFC_TRACE - bool "enable driver internal trace" - depends on SCSI_IBMVFC - default y - help - If you say Y here, the driver will trace all commands issued - to the adapter. Performance impact is minimal. Trace can be - dumped using /sys/class/scsi_host/hostXX/trace. - -config SCSI_INITIO - tristate "Initio 9100U(W) support" - depends on PCI && SCSI - help - This is support for the Initio 91XXU(W) SCSI host adapter. Please - read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called initio. - -config SCSI_INIA100 - tristate "Initio INI-A100U2W support" - depends on PCI && SCSI - help - This is support for the Initio INI-A100U2W SCSI host adapter. - Please read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called a100u2w. - -config SCSI_PPA - tristate "IOMEGA parallel port (ppa - older drives)" - depends on SCSI && PARPORT_PC - ---help--- - This driver supports older versions of IOMEGA's parallel port ZIP - drive (a 100 MB removable media device). - - Note that you can say N here if you have the SCSI version of the ZIP - drive: it will be supported automatically if you said Y to the - generic "SCSI disk support", above. - - If you have the ZIP Plus drive or a more recent parallel port ZIP - drive (if the supplied cable with the drive is labeled "AutoDetect") - then you should say N here and Y to "IOMEGA parallel port (imm - - newer drives)", below. - - For more information about this driver and how to use it you should - read the file . You should also read - the SCSI-HOWTO, which is available from - . If you use this driver, - you will still be able to use the parallel port for other tasks, - such as a printer; it is safe to compile both drivers into the - kernel. - - To compile this driver as a module, choose M here: the - module will be called ppa. - -config SCSI_IMM - tristate "IOMEGA parallel port (imm - newer drives)" - depends on SCSI && PARPORT_PC - ---help--- - This driver supports newer versions of IOMEGA's parallel port ZIP - drive (a 100 MB removable media device). - - Note that you can say N here if you have the SCSI version of the ZIP - drive: it will be supported automatically if you said Y to the - generic "SCSI disk support", above. - - If you have the ZIP Plus drive or a more recent parallel port ZIP - drive (if the supplied cable with the drive is labeled "AutoDetect") - then you should say Y here; if you have an older ZIP drive, say N - here and Y to "IOMEGA Parallel Port (ppa - older drives)", above. - - For more information about this driver and how to use it you should - read the file . You should also read - the SCSI-HOWTO, which is available from - . If you use this driver, - you will still be able to use the parallel port for other tasks, - such as a printer; it is safe to compile both drivers into the - kernel. - - To compile this driver as a module, choose M here: the - module will be called imm. - -config SCSI_IZIP_EPP16 - bool "ppa/imm option - Use slow (but safe) EPP-16" - depends on SCSI_PPA || SCSI_IMM - ---help--- - EPP (Enhanced Parallel Port) is a standard for parallel ports which - allows them to act as expansion buses that can handle up to 64 - peripheral devices. - - Some parallel port chipsets are slower than their motherboard, and - so we have to control the state of the chipset's FIFO queue every - now and then to avoid data loss. This will be done if you say Y - here. - - Generally, saying Y is the safe option and slows things down a bit. - -config SCSI_IZIP_SLOW_CTR - bool "ppa/imm option - Assume slow parport control register" - depends on SCSI_PPA || SCSI_IMM - help - Some parallel ports are known to have excessive delays between - changing the parallel port control register and good data being - available on the parallel port data/status register. This option - forces a small delay (1.0 usec to be exact) after changing the - control register to let things settle out. Enabling this option may - result in a big drop in performance but some very old parallel ports - (found in 386 vintage machines) will not work properly. - - Generally, saying N is fine. - -config SCSI_NCR53C406A - tristate "NCR53c406a SCSI support" - depends on ISA && SCSI - help - This is support for the NCR53c406a SCSI host adapter. For user - configurable parameters, check out - in the kernel source. Also read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called NCR53c406. - -config SCSI_NCR_D700 - tristate "NCR Dual 700 MCA SCSI support" - depends on MCA && SCSI - select SCSI_SPI_ATTRS - help - This is a driver for the MicroChannel Dual 700 card produced by - NCR and commonly used in 345x/35xx/4100 class machines. It always - tries to negotiate sync and uses tag command queueing. - - Unless you have an NCR manufactured machine, the chances are that - you do not have this SCSI card, so say N. - -config SCSI_LASI700 - tristate "HP Lasi SCSI support for 53c700/710" - depends on GSC && SCSI - select SCSI_SPI_ATTRS - help - This is a driver for the SCSI controller in the Lasi chip found in - many PA-RISC workstations & servers. If you do not know whether you - have a Lasi chip, it is safe to say "Y" here. - -config SCSI_SNI_53C710 - tristate "SNI RM SCSI support for 53c710" - depends on SNI_RM && SCSI - select SCSI_SPI_ATTRS - select 53C700_LE_ON_BE - help - This is a driver for the onboard SCSI controller found in older - SNI RM workstations & servers. - -config 53C700_LE_ON_BE - bool - depends on SCSI_LASI700 - default y - -config SCSI_STEX - tristate "Promise SuperTrak EX Series support" - depends on PCI && SCSI - ---help--- - This driver supports Promise SuperTrak EX series storage controllers. - - Promise provides Linux RAID configuration utility for these - controllers. Please visit to download. - - To compile this driver as a module, choose M here: the - module will be called stex. - -config 53C700_BE_BUS - bool - depends on SCSI_A4000T || SCSI_ZORRO7XX || MVME16x_SCSI || BVME6000_SCSI - default y - -config SCSI_SYM53C8XX_2 - tristate "SYM53C8XX Version 2 SCSI support" - depends on PCI && SCSI - select SCSI_SPI_ATTRS - ---help--- - This driver supports the whole NCR53C8XX/SYM53C8XX family of - PCI-SCSI controllers. It also supports the subset of LSI53C10XX - Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS - language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI - controllers; you need to use the Fusion MPT driver for that. - - Please read for more - information. - -config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE - int "DMA addressing mode" - depends on SCSI_SYM53C8XX_2 - default "1" - ---help--- - This option only applies to PCI-SCSI chips that are PCI DAC - capable (875A, 895A, 896, 1010-33, 1010-66, 1000). - - When set to 0, the driver will program the chip to only perform - 32-bit DMA. When set to 1, the chip will be able to perform DMA - to addresses up to 1TB. When set to 2, the driver supports the - full 64-bit DMA address range, but can only address 16 segments - of 4 GB each. This limits the total addressable range to 64 GB. - - Most machines with less than 4GB of memory should use a setting - of 0 for best performance. If your machine has 4GB of memory - or more, you should set this option to 1 (the default). - - The still experimental value 2 (64 bit DMA addressing with 16 - x 4GB segments limitation) can be used on systems that require - PCI address bits past bit 39 to be set for the addressing of - memory using PCI DAC cycles. - -config SCSI_SYM53C8XX_DEFAULT_TAGS - int "Default tagged command queue depth" - depends on SCSI_SYM53C8XX_2 - default "16" - help - This is the default value of the command queue depth the - driver will announce to the generic SCSI layer for devices - that support tagged command queueing. This value can be changed - from the boot command line. This is a soft limit that cannot - exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. - -config SCSI_SYM53C8XX_MAX_TAGS - int "Maximum number of queued commands" - depends on SCSI_SYM53C8XX_2 - default "64" - help - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The driver supports up to 256 queued commands per device. - This value is used as a compiled-in hard limit. - -config SCSI_SYM53C8XX_MMIO - bool "Use memory mapped IO" - depends on SCSI_SYM53C8XX_2 - default y - help - Memory mapped IO is faster than Port IO. Most people should - answer Y here, but some machines may have problems. If you have - to answer N here, please report the problem to the maintainer. - -config SCSI_IPR - tristate "IBM Power Linux RAID adapter support" - depends on PCI && SCSI && ATA - select FW_LOADER - ---help--- - This driver supports the IBM Power Linux family RAID adapters. - This includes IBM pSeries 5712, 5703, 5709, and 570A, as well - as IBM iSeries 5702, 5703, 5709, and 570A. - -config SCSI_IPR_TRACE - bool "enable driver internal trace" - depends on SCSI_IPR - default y - help - If you say Y here, the driver will trace all commands issued - to the adapter. Performance impact is minimal. Trace can be - dumped using /sys/bus/class/scsi_host/hostXX/trace. - -config SCSI_IPR_DUMP - bool "enable adapter dump support" - depends on SCSI_IPR - default y - help - If you say Y here, the driver will support adapter crash dump. - If you enable this support, the iprdump daemon can be used - to capture adapter failure analysis information. - -config SCSI_ZALON - tristate "Zalon SCSI support" - depends on GSC && SCSI - select SCSI_SPI_ATTRS - help - The Zalon is a GSC/HSC bus interface chip that sits between the - PA-RISC processor and the NCR 53c720 SCSI controller on C100, - C110, J200, J210 and some D, K & R-class machines. It's also - used on the add-in Bluefish, Barracuda & Shrike SCSI cards. - Say Y here if you have one of these machines or cards. - -config SCSI_NCR_Q720 - tristate "NCR Quad 720 MCA SCSI support" - depends on MCA && SCSI - select SCSI_SPI_ATTRS - help - This is a driver for the MicroChannel Quad 720 card produced by - NCR and commonly used in 345x/35xx/4100 class machines. It always - tries to negotiate sync and uses tag command queueing. - - Unless you have an NCR manufactured machine, the chances are that - you do not have this SCSI card, so say N. - -config SCSI_NCR53C8XX_DEFAULT_TAGS - int "default tagged command queue depth" - depends on SCSI_ZALON || SCSI_NCR_Q720 - default "8" - ---help--- - "Tagged command queuing" is a feature of SCSI-2 which improves - performance: the host adapter can send several SCSI commands to a - device's queue even if previous commands haven't finished yet. - Because the device is intelligent, it can optimize its operations - (like head positioning) based on its own request queue. Some SCSI - devices don't implement this properly; if you want to disable this - feature, enter 0 or 1 here (it doesn't matter which). - - The default value is 8 and should be supported by most hard disks. - This value can be overridden from the boot command line using the - 'tags' option as follows (example): - 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to - 4, set queue depth to 16 for target 2 and target 3 on controller 0 - and set queue depth to 10 for target 0 / lun 2 on controller 1. - - The normal answer therefore is to go with the default 8 and to use - a boot command line option for devices that need to use a different - command queue depth. - - There is no safe option other than using good SCSI devices. - -config SCSI_NCR53C8XX_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_ZALON || SCSI_NCR_Q720 - default "32" - ---help--- - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The default value is 32. Minimum is 2, maximum is 64. - Modern hard disks are able to support 64 tags and even more, but - do not seem to be faster when more than 32 tags are being used. - - So, the normal answer here is to go with the default value 32 unless - you are using very large hard disks with large cache (>= 1 MB) that - are able to take advantage of more than 32 tagged commands. - - There is no safe option and the default answer is recommended. - -config SCSI_NCR53C8XX_SYNC - int "synchronous transfers frequency in MHz" - depends on SCSI_ZALON || SCSI_NCR_Q720 - default "20" - ---help--- - The SCSI Parallel Interface-2 Standard defines 5 classes of transfer - rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers - are respectively the maximum data transfer rates in mega-transfers - per second for each class. For example, a FAST-20 Wide 16 device is - able to transfer data at 20 million 16 bit packets per second for a - total rate of 40 MB/s. - - You may specify 0 if you want to only use asynchronous data - transfers. This is the safest and slowest option. Otherwise, specify - a value between 5 and 80, depending on the capability of your SCSI - controller. The higher the number, the faster the data transfer. - Note that 80 should normally be ok since the driver decreases the - value automatically according to the controller's capabilities. - - Your answer to this question is ignored for controllers with NVRAM, - since the driver will get this information from the user set-up. It - also can be overridden using a boot setup option, as follows - (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate - for FAST-20 synchronous data transfer (20 mega-transfers per - second). - - The normal answer therefore is not to go with the default but to - select the maximum value 80 allowing the driver to use the maximum - value supported by each controller. If this causes problems with - your SCSI devices, you should come back and decrease the value. - - There is no safe option other than using good cabling, right - terminations and SCSI conformant devices. - -config SCSI_NCR53C8XX_NO_DISCONNECT - bool "not allow targets to disconnect" - depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0 - help - This option is only provided for safety if you suspect some SCSI - device of yours to not support properly the target-disconnect - feature. In that case, you would say Y here. In general however, to - not allow targets to disconnect is not reasonable if there is more - than 1 device on a SCSI bus. The normal answer therefore is N. - -config SCSI_PAS16 - tristate "PAS16 SCSI support" - depends on ISA && SCSI - select SCSI_SPI_ATTRS - ---help--- - This is support for a SCSI host adapter. It is explained in section - 3.10 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . - - To compile this driver as a module, choose M here: the - module will be called pas16. - -config SCSI_QLOGIC_FAS - tristate "Qlogic FAS SCSI support" - depends on ISA && SCSI - ---help--- - This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic - FastSCSI! cards as well as any other card based on the FASXX chip - (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards). - - This driver does NOT support the PCI versions of these cards. The - PCI versions are supported by the Qlogic ISP driver ("Qlogic ISP - SCSI support"), below. - - Information about this driver is contained in - . You should also read the - SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called qlogicfas. - -config SCSI_QLOGIC_1280 - tristate "Qlogic QLA 1240/1x80/1x160 SCSI support" - depends on PCI && SCSI - help - Say Y if you have a QLogic ISP1240/1x80/1x160 SCSI host adapter. - - To compile this driver as a module, choose M here: the - module will be called qla1280. - -config SCSI_QLOGICPTI - tristate "PTI Qlogic, ISP Driver" - depends on SBUS && SCSI - help - This driver supports SBUS SCSI controllers from PTI or QLogic. These - controllers are known under Solaris as qpti and in the openprom as - PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are - driven by a different driver. - - To compile this driver as a module, choose M here: the - module will be called qlogicpti. - -source "drivers/scsi/qla2xxx/Kconfig" -source "drivers/scsi/qla4xxx/Kconfig" - -config SCSI_LPFC - tristate "Emulex LightPulse Fibre Channel Support" - depends on PCI && SCSI - select SCSI_FC_ATTRS - help - This lpfc driver supports the Emulex LightPulse - Family of Fibre Channel PCI host adapters. - -config SCSI_LPFC_DEBUG_FS - bool "Emulex LightPulse Fibre Channel debugfs Support" - depends on SCSI_LPFC && DEBUG_FS - help - This makes debugging information from the lpfc driver - available via the debugfs filesystem. - -config SCSI_SIM710 - tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" - depends on (EISA || MCA) && SCSI - select SCSI_SPI_ATTRS - ---help--- - This driver is for NCR53c710 based SCSI host adapters. - - It currently supports Compaq EISA cards and NCR MCA cards - -config SCSI_SYM53C416 - tristate "Symbios 53c416 SCSI support" - depends on ISA && SCSI - ---help--- - This is support for the sym53c416 SCSI host adapter, the SCSI - adapter that comes with some HP scanners. This driver requires that - the sym53c416 is configured first using some sort of PnP - configuration program (e.g. isapnp) or by a PnP aware BIOS. If you - are using isapnp then you need to compile this driver as a module - and then load it using insmod after isapnp has run. The parameters - of the configured card(s) should be passed to the driver. The format - is: - - insmod sym53c416 sym53c416=, [sym53c416_1=,] - - To compile this driver as a module, choose M here: the - module will be called sym53c416. - -config SCSI_DC395x - tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support (EXPERIMENTAL)" - depends on PCI && SCSI && EXPERIMENTAL - ---help--- - This driver supports PCI SCSI host adapters based on the ASIC - TRM-S1040 chip, e.g Tekram DC395(U/UW/F) and DC315(U) variants. - - This driver works, but is still in experimental status. So better - have a bootable disk and a backup in case of emergency. - - Documentation can be found in . - - To compile this driver as a module, choose M here: the - module will be called dc395x. - -config SCSI_DC390T - tristate "Tekram DC390(T) and Am53/79C974 SCSI support" - depends on PCI && SCSI - ---help--- - This driver supports PCI SCSI host adapters based on the Am53C974A - chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard - PCscsi/PCnet (Am53/79C974) solutions. - - Documentation can be found in . - - Note that this driver does NOT support Tekram DC390W/U/F, which are - based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those. - - To compile this driver as a module, choose M here: the - module will be called tmscsim. - -config SCSI_T128 - tristate "Trantor T128/T128F/T228 SCSI support" - depends on ISA && SCSI - select SCSI_SPI_ATTRS - select CHECK_SIGNATURE - ---help--- - This is support for a SCSI host adapter. It is explained in section - 3.11 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . Note that Trantor was purchased by - Adaptec, and some former Trantor products are being sold under the - Adaptec name. - - To compile this driver as a module, choose M here: the - module will be called t128. - -config SCSI_U14_34F - tristate "UltraStor 14F/34F support" - depends on ISA && SCSI && ISA_DMA_API - ---help--- - This is support for the UltraStor 14F and 34F SCSI-2 host adapters. - The source at contains some - information about this hardware. If the driver doesn't work out of - the box, you may have to change some settings in - . Read the SCSI-HOWTO, available from - . Note that there is also - another driver for the same hardware: "UltraStor SCSI support", - below. You should say Y to both only if you want 24F support as - well. - - To compile this driver as a module, choose M here: the - module will be called u14-34f. - -config SCSI_U14_34F_TAGGED_QUEUE - bool "enable tagged command queueing" - depends on SCSI_U14_34F - help - This is a feature of SCSI-2 which improves performance: the host - adapter can send several SCSI commands to a device's queue even if - previous commands haven't finished yet. - This is equivalent to the "u14-34f=tc:y" boot option. - -config SCSI_U14_34F_LINKED_COMMANDS - bool "enable elevator sorting" - depends on SCSI_U14_34F - help - This option enables elevator sorting for all probed SCSI disks and - CD-ROMs. It definitely reduces the average seek distance when doing - random seeks, but this does not necessarily result in a noticeable - performance improvement: your mileage may vary... - This is equivalent to the "u14-34f=lc:y" boot option. - -config SCSI_U14_34F_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_U14_34F - default "8" - help - This specifies how many SCSI commands can be maximally queued for - each probed SCSI device. You should reduce the default value of 8 - only if you have disks with buggy or limited tagged command support. - Minimum is 2 and maximum is 14. This value is also the window size - used by the elevator sorting option above. The effective value used - by the driver for each probed SCSI device is reported at boot time. - This is equivalent to the "u14-34f=mq:8" boot option. - -config SCSI_ULTRASTOR - tristate "UltraStor SCSI support" - depends on X86 && ISA && SCSI - ---help--- - This is support for the UltraStor 14F, 24F and 34F SCSI-2 host - adapter family. This driver is explained in section 3.12 of the - SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . - - Note that there is also another driver for the same hardware: - "UltraStor 14F/34F support", above. - - To compile this driver as a module, choose M here: the - module will be called ultrastor. - -config SCSI_NSP32 - tristate "Workbit NinjaSCSI-32Bi/UDE support" - depends on PCI && SCSI && !64BIT - help - This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus - SCSI host adapter. Please read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called nsp32. - -config SCSI_DEBUG - tristate "SCSI debugging host simulator" - depends on SCSI - select CRC_T10DIF - help - This is a host adapter simulator that can simulate multiple hosts - each with multiple dummy SCSI devices (disks). It defaults to one - host adapter with one dummy SCSI disk. Each dummy disk uses kernel - RAM as storage (i.e. it is a ramdisk). To save space when multiple - dummy disks are simulated, they share the same kernel RAM for - their storage. See for more - information. This driver is primarily of use to those testing the - SCSI and block subsystems. If unsure, say N. - -config SCSI_MESH - tristate "MESH (Power Mac internal SCSI) support" - depends on PPC32 && PPC_PMAC && SCSI - help - Many Power Macintoshes and clones have a MESH (Macintosh Enhanced - SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the - other Power Macintoshes do). Say Y to include support for this SCSI - adaptor. - - To compile this driver as a module, choose M here: the - module will be called mesh. - -config SCSI_MESH_SYNC_RATE - int "maximum synchronous transfer rate (MB/s) (0 = async)" - depends on SCSI_MESH - default "5" - help - On Power Macintoshes (and clones) where the MESH SCSI bus adaptor - drives a bus which is entirely internal to the machine (such as the - 7500, 7600, 8500, etc.), the MESH is capable of synchronous - operation at up to 10 MB/s. On machines where the SCSI bus - controlled by the MESH can have external devices connected, it is - usually rated at 5 MB/s. 5 is a safe value here unless you know the - MESH SCSI bus is internal only; in that case you can say 10. Say 0 - to disable synchronous operation. - -config SCSI_MESH_RESET_DELAY_MS - int "initial bus reset delay (ms) (0 = no reset)" - depends on SCSI_MESH - default "4000" - -config SCSI_MAC53C94 - tristate "53C94 (Power Mac external SCSI) support" - depends on PPC32 && PPC_PMAC && SCSI - help - On Power Macintoshes (and clones) with two SCSI buses, the external - SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older - machines which only have one SCSI bus, such as the 7200, also use - the 53C94. Say Y to include support for the 53C94. - - To compile this driver as a module, choose M here: the - module will be called mac53c94. - -source "drivers/scsi/arm/Kconfig" - -config JAZZ_ESP - bool "MIPS JAZZ FAS216 SCSI support" - depends on MACH_JAZZ && SCSI - select SCSI_SPI_ATTRS - help - This is the driver for the onboard SCSI host adapter of MIPS Magnum - 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM - systems. - -config A3000_SCSI - tristate "A3000 WD33C93A support" - depends on AMIGA && SCSI - help - If you have an Amiga 3000 and have SCSI devices connected to the - built-in SCSI controller, say Y. Otherwise, say N. - - To compile this driver as a module, choose M here: the - module will be called a3000. - -config A2091_SCSI - tristate "A2091/A590 WD33C93A support" - depends on ZORRO && SCSI - help - If you have a Commodore A2091 SCSI controller, say Y. Otherwise, - say N. - - To compile this driver as a module, choose M here: the - module will be called a2091. - -config GVP11_SCSI - tristate "GVP Series II WD33C93A support" - depends on ZORRO && SCSI - ---help--- - If you have a Great Valley Products Series II SCSI controller, - answer Y. Also say Y if you have a later model of GVP SCSI - controller (such as the GVP A4008 or a Combo board). Otherwise, - answer N. This driver does NOT work for the T-Rex series of - accelerators from TekMagic and GVP-M. - - To compile this driver as a module, choose M here: the - module will be called gvp11. - -config SCSI_A4000T - tristate "A4000T NCR53c710 SCSI support (EXPERIMENTAL)" - depends on AMIGA && SCSI && EXPERIMENTAL - select SCSI_SPI_ATTRS - help - If you have an Amiga 4000T and have SCSI devices connected to the - built-in SCSI controller, say Y. Otherwise, say N. - - To compile this driver as a module, choose M here: the - module will be called a4000t. - -config SCSI_ZORRO7XX - tristate "Zorro NCR53c710 SCSI support (EXPERIMENTAL)" - depends on ZORRO && SCSI && EXPERIMENTAL - select SCSI_SPI_ATTRS - help - Support for various NCR53c710-based SCSI controllers on Zorro - expansion boards for the Amiga. - This includes: - - the Amiga 4091 Zorro III SCSI-2 controller, - - the MacroSystem Development's WarpEngine Amiga SCSI-2 controller - (info at - ), - - the SCSI controller on the Phase5 Blizzard PowerUP 603e+ - accelerator card for the Amiga 1200, - - the SCSI controller on the GVP Turbo 040/060 accelerator. - -config ATARI_SCSI - tristate "Atari native SCSI support" - depends on ATARI && SCSI - select SCSI_SPI_ATTRS - select NVRAM - ---help--- - If you have an Atari with built-in NCR5380 SCSI controller (TT, - Falcon, ...) say Y to get it supported. Of course also, if you have - a compatible SCSI controller (e.g. for Medusa). - - To compile this driver as a module, choose M here: the - module will be called atari_scsi. - - This driver supports both styles of NCR integration into the - system: the TT style (separate DMA), and the Falcon style (via - ST-DMA, replacing ACSI). It does NOT support other schemes, like - in the Hades (without DMA). - -config ATARI_SCSI_TOSHIBA_DELAY - bool "Long delays for Toshiba CD-ROMs" - depends on ATARI_SCSI - help - This option increases the delay after a SCSI arbitration to - accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to - use a Toshiba CD-ROM drive; otherwise, the option is not needed and - would impact performance a bit, so say N. - -config ATARI_SCSI_RESET_BOOT - bool "Reset SCSI-devices at boottime" - depends on ATARI_SCSI - help - Reset the devices on your Atari whenever it boots. This makes the - boot process fractionally longer but may assist recovery from errors - that leave the devices with SCSI operations partway completed. - -config MAC_SCSI - bool "Macintosh NCR5380 SCSI" - depends on MAC && SCSI=y - select SCSI_SPI_ATTRS - help - This is the NCR 5380 SCSI controller included on most of the 68030 - based Macintoshes. If you have one of these say Y and read the - SCSI-HOWTO, available from - . - -config SCSI_MAC_ESP - tristate "Macintosh NCR53c9[46] SCSI" - depends on MAC && SCSI - select SCSI_SPI_ATTRS - help - This is the NCR 53c9x SCSI controller found on most of the 68040 - based Macintoshes. - - To compile this driver as a module, choose M here: the module - will be called mac_esp. - -config MVME147_SCSI - bool "WD33C93 SCSI driver for MVME147" - depends on MVME147 && SCSI=y - select SCSI_SPI_ATTRS - help - Support for the on-board SCSI controller on the Motorola MVME147 - single-board computer. - -config MVME16x_SCSI - tristate "NCR53C710 SCSI driver for MVME16x" - depends on MVME16x && SCSI - select SCSI_SPI_ATTRS - help - The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 - SCSI controller chip. Almost everyone using one of these boards - will want to say Y to this question. - -config BVME6000_SCSI - tristate "NCR53C710 SCSI driver for BVME6000" - depends on BVME6000 && SCSI - select SCSI_SPI_ATTRS - help - The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710 - SCSI controller chip. Almost everyone using one of these boards - will want to say Y to this question. - -config SUN3_SCSI - tristate "Sun3 NCR5380 SCSI" - depends on SUN3 && SCSI - select SCSI_SPI_ATTRS - help - This option will enable support for the OBIO (onboard io) NCR5380 - SCSI controller found in the Sun 3/50 and 3/60, as well as for - "Sun3" type VME scsi controllers also based on the NCR5380. - General Linux information on the Sun 3 series (now discontinued) - is at . - -config SUN3X_ESP - bool "Sun3x ESP SCSI" - depends on SUN3X && SCSI=y - select SCSI_SPI_ATTRS - help - The ESP was an on-board SCSI controller used on Sun 3/80 - machines. Say Y here to compile in support for it. - -config SCSI_SUNESP - tristate "Sparc ESP Scsi Driver" - depends on SBUS && SCSI - select SCSI_SPI_ATTRS - help - This is the driver for the Sun ESP SCSI host adapter. The ESP - chipset is present in most SPARC SBUS-based computers and - supports the Emulex family of ESP SCSI chips (esp100, esp100A, - esp236, fas101, fas236) as well as the Qlogic fas366 SCSI chip. - - To compile this driver as a module, choose M here: the - module will be called sun_esp. - -config ZFCP - tristate "FCP host bus adapter driver for IBM eServer zSeries" - depends on S390 && QDIO && SCSI - select SCSI_FC_ATTRS - help - If you want to access SCSI devices attached to your IBM eServer - zSeries by means of Fibre Channel interfaces say Y. - For details please refer to the documentation provided by IBM at - - - This driver is also available as a module. This module will be - called zfcp. If you want to compile it as a module, say M here - and read . - -config SCSI_PMCRAID - tristate "PMC SIERRA Linux MaxRAID adapter support" - depends on PCI && SCSI && NET - ---help--- - This driver supports the PMC SIERRA MaxRAID adapters. - -config SCSI_PM8001 - tristate "PMC-Sierra SPC 8001 SAS/SATA Based Host Adapter driver" - depends on PCI && SCSI - select SCSI_SAS_LIBSAS - help - This driver supports PMC-Sierra PCIE SAS/SATA 8x6G SPC 8001 chip - based host adapters. - -config SCSI_SRP - tristate "SCSI RDMA Protocol helper library" - depends on SCSI && PCI - select SCSI_TGT - help - If you wish to use SRP target drivers, say Y. - - To compile this driver as a module, choose M here: the - module will be called libsrp. - -config SCSI_BFA_FC - tristate "Brocade BFA Fibre Channel Support" - depends on PCI && SCSI - select SCSI_FC_ATTRS - help - This bfa driver supports all Brocade PCIe FC/FCOE host adapters. - - To compile this driver as a module, choose M here. The module will - be called bfa. - -config SCSI_VIRTIO - tristate "virtio-scsi support (EXPERIMENTAL)" - depends on EXPERIMENTAL && VIRTIO - help - This is the virtual HBA driver for virtio. If the kernel will - be used in a virtual machine, say Y or M. - - -endif # SCSI_LOWLEVEL - -source "drivers/scsi/pcmcia/Kconfig" - -source "drivers/scsi/device_handler/Kconfig" - -source "drivers/scsi/osd/Kconfig" - -endmenu diff --git a/ANDROID_3.4.5/drivers/scsi/Makefile b/ANDROID_3.4.5/drivers/scsi/Makefile deleted file mode 100644 index 8deedeaf..00000000 --- a/ANDROID_3.4.5/drivers/scsi/Makefile +++ /dev/null @@ -1,205 +0,0 @@ -# -# Makefile for linux/drivers/scsi -# -# 30 May 2000, Christoph Hellwig -# Rewritten to use lists instead of if-statements. -# -# 20 Sep 2000, Torben Mathiasen -# Changed link order to reflect new scsi initialization. -# -# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! -# The link order must be, SCSI Core, SCSI HBA drivers, and -# lastly SCSI peripheral drivers (disk/tape/cdrom/etc.) to -# satisfy certain initialization assumptions in the SCSI layer. -# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*! - - -CFLAGS_aha152x.o = -DAHA152X_STAT -DAUTOCONF -CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS - -obj-$(CONFIG_PCMCIA) += pcmcia/ - -obj-$(CONFIG_SCSI) += scsi_mod.o -obj-$(CONFIG_SCSI_TGT) += scsi_tgt.o - -obj-$(CONFIG_RAID_ATTRS) += raid_class.o - -# --- NOTE ORDERING HERE --- -# For kernel non-modular link, transport attributes need to -# be initialised before drivers -# -------------------------- -obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o -obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o -obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o -obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o -obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ -obj-$(CONFIG_SCSI_SRP_ATTRS) += scsi_transport_srp.o -obj-$(CONFIG_SCSI_DH) += device_handler/ - -obj-$(CONFIG_LIBFC) += libfc/ -obj-$(CONFIG_LIBFCOE) += fcoe/ -obj-$(CONFIG_FCOE) += fcoe/ -obj-$(CONFIG_FCOE_FNIC) += fnic/ -obj-$(CONFIG_SCSI_BNX2X_FCOE) += libfc/ fcoe/ bnx2fc/ -obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o -obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o -obj-$(CONFIG_ISCSI_BOOT_SYSFS) += iscsi_boot_sysfs.o -obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o -obj-$(CONFIG_SCSI_ZORRO7XX) += 53c700.o zorro7xx.o -obj-$(CONFIG_A3000_SCSI) += a3000.o wd33c93.o -obj-$(CONFIG_A2091_SCSI) += a2091.o wd33c93.o -obj-$(CONFIG_GVP11_SCSI) += gvp11.o wd33c93.o -obj-$(CONFIG_MVME147_SCSI) += mvme147.o wd33c93.o -obj-$(CONFIG_SGIWD93_SCSI) += sgiwd93.o wd33c93.o -obj-$(CONFIG_ATARI_SCSI) += atari_scsi.o -obj-$(CONFIG_MAC_SCSI) += mac_scsi.o -obj-$(CONFIG_SCSI_MAC_ESP) += esp_scsi.o mac_esp.o -obj-$(CONFIG_SUN3_SCSI) += sun3_scsi.o sun3_scsi_vme.o -obj-$(CONFIG_MVME16x_SCSI) += 53c700.o mvme16x_scsi.o -obj-$(CONFIG_BVME6000_SCSI) += 53c700.o bvme6000_scsi.o -obj-$(CONFIG_SCSI_SIM710) += 53c700.o sim710.o -obj-$(CONFIG_SCSI_ADVANSYS) += advansys.o -obj-$(CONFIG_SCSI_BUSLOGIC) += BusLogic.o -obj-$(CONFIG_SCSI_DPT_I2O) += dpt_i2o.o -obj-$(CONFIG_SCSI_U14_34F) += u14-34f.o -obj-$(CONFIG_SCSI_ARCMSR) += arcmsr/ -obj-$(CONFIG_SCSI_ULTRASTOR) += ultrastor.o -obj-$(CONFIG_SCSI_AHA152X) += aha152x.o -obj-$(CONFIG_SCSI_AHA1542) += aha1542.o -obj-$(CONFIG_SCSI_AHA1740) += aha1740.o -obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/ -obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/ -obj-$(CONFIG_SCSI_AACRAID) += aacraid/ -obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o -obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/ -obj-$(CONFIG_SCSI_PM8001) += pm8001/ -obj-$(CONFIG_SCSI_ISCI) += isci/ -obj-$(CONFIG_SCSI_IPS) += ips.o -obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o -obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o -obj-$(CONFIG_SCSI_IN2000) += in2000.o -obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o -obj-$(CONFIG_SCSI_GENERIC_NCR5380_MMIO) += g_NCR5380_mmio.o -obj-$(CONFIG_SCSI_NCR53C406A) += NCR53c406a.o -obj-$(CONFIG_SCSI_NCR_D700) += 53c700.o NCR_D700.o -obj-$(CONFIG_SCSI_NCR_Q720) += NCR_Q720_mod.o -obj-$(CONFIG_SCSI_SYM53C416) += sym53c416.o -obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o -obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o -obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o -obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/ -obj-$(CONFIG_SCSI_QLA_ISCSI) += libiscsi.o qla4xxx/ -obj-$(CONFIG_SCSI_LPFC) += lpfc/ -obj-$(CONFIG_SCSI_BFA_FC) += bfa/ -obj-$(CONFIG_SCSI_PAS16) += pas16.o -obj-$(CONFIG_SCSI_T128) += t128.o -obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o -obj-$(CONFIG_SCSI_HPSA) += hpsa.o -obj-$(CONFIG_SCSI_DTC3280) += dtc.o -obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/ -obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o -obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o -obj-$(CONFIG_SCSI_7000FASST) += wd7000.o -obj-$(CONFIG_SCSI_IBMMCA) += ibmmca.o -obj-$(CONFIG_SCSI_EATA) += eata.o -obj-$(CONFIG_SCSI_DC395x) += dc395x.o -obj-$(CONFIG_SCSI_DC390T) += tmscsim.o -obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o -obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/ -obj-$(CONFIG_MEGARAID_SAS) += megaraid/ -obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas/ -obj-$(CONFIG_SCSI_UFSHCD) += ufs/ -obj-$(CONFIG_SCSI_ACARD) += atp870u.o -obj-$(CONFIG_SCSI_SUNESP) += esp_scsi.o sun_esp.o -obj-$(CONFIG_SCSI_GDTH) += gdth.o -obj-$(CONFIG_SCSI_INITIO) += initio.o -obj-$(CONFIG_SCSI_INIA100) += a100u2w.o -obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o -obj-$(CONFIG_SCSI_MESH) += mesh.o -obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o -obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o -obj-$(CONFIG_SCSI_3W_9XXX) += 3w-9xxx.o -obj-$(CONFIG_SCSI_3W_SAS) += 3w-sas.o -obj-$(CONFIG_SCSI_PPA) += ppa.o -obj-$(CONFIG_SCSI_IMM) += imm.o -obj-$(CONFIG_JAZZ_ESP) += esp_scsi.o jazz_esp.o -obj-$(CONFIG_SUN3X_ESP) += esp_scsi.o sun3x_esp.o -obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o -obj-$(CONFIG_SCSI_SNI_53C710) += 53c700.o sni_53c710.o -obj-$(CONFIG_SCSI_NSP32) += nsp32.o -obj-$(CONFIG_SCSI_IPR) += ipr.o -obj-$(CONFIG_SCSI_SRP) += libsrp.o -obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi/ -obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvscsi/ -obj-$(CONFIG_SCSI_IBMVFC) += ibmvscsi/ -obj-$(CONFIG_SCSI_HPTIOP) += hptiop.o -obj-$(CONFIG_SCSI_STEX) += stex.o -obj-$(CONFIG_SCSI_MVSAS) += mvsas/ -obj-$(CONFIG_SCSI_MVUMI) += mvumi.o -obj-$(CONFIG_PS3_ROM) += ps3rom.o -obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/ -obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/ -obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ -obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/ -obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o -obj-$(CONFIG_SCSI_VIRTIO) += virtio_scsi.o -obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o -obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o - -obj-$(CONFIG_ARM) += arm/ - -obj-$(CONFIG_CHR_DEV_ST) += st.o -obj-$(CONFIG_CHR_DEV_OSST) += osst.o -obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o -obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o -obj-$(CONFIG_CHR_DEV_SG) += sg.o -obj-$(CONFIG_CHR_DEV_SCH) += ch.o -obj-$(CONFIG_SCSI_ENCLOSURE) += ses.o - -obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/ - -# This goes last, so that "real" scsi devices probe earlier -obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o - -obj-$(CONFIG_SCSI_WAIT_SCAN) += scsi_wait_scan.o - -scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ - scsicam.o scsi_error.o scsi_lib.o -scsi_mod-$(CONFIG_SCSI_DMA) += scsi_lib_dma.o -scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o -scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o -scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o -scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o -scsi_mod-y += scsi_trace.o -scsi_mod-$(CONFIG_PM) += scsi_pm.o - -hv_storvsc-y := storvsc_drv.o - -scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o - -sd_mod-objs := sd.o -sd_mod-$(CONFIG_BLK_DEV_INTEGRITY) += sd_dif.o - -sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o -ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \ - := -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \ - -DCONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS -CFLAGS_ncr53c8xx.o := $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m) -zalon7xx-objs := zalon.o ncr53c8xx.o -NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o -oktagon_esp_mod-objs := oktagon_esp.o oktagon_io.o - -# Files generated that shall be removed upon make clean -clean-files := 53c700_d.h 53c700_u.h - -$(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h - -# If you want to play with the firmware, uncomment -# GENERATE_FIRMWARE := 1 - -ifdef GENERATE_FIRMWARE - -$(obj)/53c700_d.h: $(src)/53c700.scr $(src)/script_asm.pl - $(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h) < $< - -endif diff --git a/ANDROID_3.4.5/drivers/scsi/NCR5380.c b/ANDROID_3.4.5/drivers/scsi/NCR5380.c deleted file mode 100644 index 165e4dd8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/NCR5380.c +++ /dev/null @@ -1,2846 +0,0 @@ -/* - * NCR 5380 generic driver routines. These should make it *trivial* - * to implement 5380 SCSI drivers under Linux with a non-trantor - * architecture. - * - * Note that these routines also work with NR53c400 family chips. - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 - * - * DISTRIBUTION RELEASE 6. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * $Log: NCR5380.c,v $ - - * Revision 1.10 1998/9/2 Alan Cox - * (alan@lxorguk.ukuu.org.uk) - * Fixed up the timer lockups reported so far. Things still suck. Looking - * forward to 2.3 and per device request queues. Then it'll be possible to - * SMP thread this beast and improve life no end. - - * Revision 1.9 1997/7/27 Ronald van Cuijlenborg - * (ronald.van.cuijlenborg@tip.nl or nutty@dds.nl) - * (hopefully) fixed and enhanced USLEEP - * added support for DTC3181E card (for Mustek scanner) - * - - * Revision 1.8 Ingmar Baumgart - * (ingmar@gonzo.schwaben.de) - * added support for NCR53C400a card - * - - * Revision 1.7 1996/3/2 Ray Van Tassle (rayvt@comm.mot.com) - * added proc_info - * added support needed for DTC 3180/3280 - * fixed a couple of bugs - * - - * Revision 1.5 1994/01/19 09:14:57 drew - * Fixed udelay() hack that was being used on DATAOUT phases - * instead of a proper wait for the final handshake. - * - * Revision 1.4 1994/01/19 06:44:25 drew - * *** empty log message *** - * - * Revision 1.3 1994/01/19 05:24:40 drew - * Added support for TCR LAST_BYTE_SENT bit. - * - * Revision 1.2 1994/01/15 06:14:11 drew - * REAL DMA support, bug fixes. - * - * Revision 1.1 1994/01/15 06:00:54 drew - * Initial revision - * - */ - -/* - * Further development / testing that should be done : - * 1. Cleanup the NCR5380_transfer_dma function and DMA operation complete - * code so that everything does the same thing that's done at the - * end of a pseudo-DMA read operation. - * - * 2. Fix REAL_DMA (interrupt driven, polled works fine) - - * basically, transfer size needs to be reduced by one - * and the last byte read as is done with PSEUDO_DMA. - * - * 4. Test SCSI-II tagged queueing (I have no devices which support - * tagged queueing) - * - * 5. Test linked command handling code after Eric is ready with - * the high level code. - */ -#include -#include - -#ifndef NDEBUG -#define NDEBUG 0 -#endif -#ifndef NDEBUG_ABORT -#define NDEBUG_ABORT 0 -#endif - -#if (NDEBUG & NDEBUG_LISTS) -#define LIST(x,y) {printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); } -#define REMOVE(w,x,y,z) {printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); } -#else -#define LIST(x,y) -#define REMOVE(w,x,y,z) -#endif - -#ifndef notyet -#undef LINKED -#undef REAL_DMA -#endif - -#ifdef REAL_DMA_POLL -#undef READ_OVERRUNS -#define READ_OVERRUNS -#endif - -#ifdef BOARD_REQUIRES_NO_DELAY -#define io_recovery_delay(x) -#else -#define io_recovery_delay(x) udelay(x) -#endif - -/* - * Design - * - * This is a generic 5380 driver. To use it on a different platform, - * one simply writes appropriate system specific macros (ie, data - * transfer - some PC's will use the I/O bus, 68K's must use - * memory mapped) and drops this file in their 'C' wrapper. - * - * (Note from hch: unfortunately it was not enough for the different - * m68k folks and instead of improving this driver they copied it - * and hacked it up for their needs. As a consequence they lost - * most updates to this driver. Maybe someone will fix all these - * drivers to use a common core one day..) - * - * As far as command queueing, two queues are maintained for - * each 5380 in the system - commands that haven't been issued yet, - * and commands that are currently executing. This means that an - * unlimited number of commands may be queued, letting - * more commands propagate from the higher driver levels giving higher - * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, - * allowing multiple commands to propagate all the way to a SCSI-II device - * while a command is already executing. - * - * - * Issues specific to the NCR5380 : - * - * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead - * piece of hardware that requires you to sit in a loop polling for - * the REQ signal as long as you are connected. Some devices are - * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect - * while doing long seek operations. - * - * The workaround for this is to keep track of devices that have - * disconnected. If the device hasn't disconnected, for commands that - * should disconnect, we do something like - * - * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } - * - * Some tweaking of N and M needs to be done. An algorithm based - * on "time to data" would give the best results as long as short time - * to datas (ie, on the same track) were considered, however these - * broken devices are the exception rather than the rule and I'd rather - * spend my time optimizing for the normal case. - * - * Architecture : - * - * At the heart of the design is a coroutine, NCR5380_main, - * which is started from a workqueue for each NCR5380 host in the - * system. It attempts to establish I_T_L or I_T_L_Q nexuses by - * removing the commands from the issue queue and calling - * NCR5380_select() if a nexus is not established. - * - * Once a nexus is established, the NCR5380_information_transfer() - * phase goes through the various phases as instructed by the target. - * if the target goes into MSG IN and sends a DISCONNECT message, - * the command structure is placed into the per instance disconnected - * queue, and NCR5380_main tries to find more work. If the target is - * idle for too long, the system will try to sleep. - * - * If a command has disconnected, eventually an interrupt will trigger, - * calling NCR5380_intr() which will in turn call NCR5380_reselect - * to reestablish a nexus. This will run main if necessary. - * - * On command termination, the done function will be called as - * appropriate. - * - * SCSI pointers are maintained in the SCp field of SCSI command - * structures, being initialized after the command is connected - * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. - * Note that in violation of the standard, an implicit SAVE POINTERS operation - * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. - */ - -/* - * Using this file : - * This file a skeleton Linux SCSI driver for the NCR 5380 series - * of chips. To use it, you write an architecture specific functions - * and macros and include this file in your driver. - * - * These macros control options : - * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be - * defined. - * - * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. - * - * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential - * transceivers. - * - * DONT_USE_INTR - if defined, never use interrupts, even if we probe or - * override-configure an IRQ. - * - * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512 - * bytes at a time. Since interrupts are disabled by default during - * these transfers, we might need this to give reasonable interrupt - * service time if the transfer size gets too large. - * - * LINKED - if defined, linked commands are supported. - * - * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases. - * - * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. - * - * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't - * rely on phase mismatch and EOP interrupts to determine end - * of phase. - * - * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You - * only really want to use this if you're having a problem with - * dropped characters during high speed communications, and even - * then, you're going to be better off twiddling with transfersize - * in the high level code. - * - * Defaults for these will be provided although the user may want to adjust - * these to allocate CPU resources to the SCSI driver or "real" code. - * - * USLEEP_SLEEP - amount of time, in jiffies, to sleep - * - * USLEEP_POLL - amount of time, in jiffies, to poll - * - * These macros MUST be defined : - * NCR5380_local_declare() - declare any local variables needed for your - * transfer routines. - * - * NCR5380_setup(instance) - initialize any local variables needed from a given - * instance of the host adapter for NCR5380_{read,write,pread,pwrite} - * - * NCR5380_read(register) - read from the specified register - * - * NCR5380_write(register, value) - write to the specific register - * - * NCR5380_implementation_fields - additional fields needed for this - * specific implementation of the NCR5380 - * - * Either real DMA *or* pseudo DMA may be implemented - * REAL functions : - * NCR5380_REAL_DMA should be defined if real DMA is to be used. - * Note that the DMA setup functions should return the number of bytes - * that they were able to program the controller for. - * - * Also note that generic i386/PC versions of these macros are - * available as NCR5380_i386_dma_write_setup, - * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. - * - * NCR5380_dma_write_setup(instance, src, count) - initialize - * NCR5380_dma_read_setup(instance, dst, count) - initialize - * NCR5380_dma_residual(instance); - residual count - * - * PSEUDO functions : - * NCR5380_pwrite(instance, src, count) - * NCR5380_pread(instance, dst, count); - * - * The generic driver is initialized by calling NCR5380_init(instance), - * after setting the appropriate host specific fields and ID. If the - * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, - * possible) function may be used. - */ - -static int do_abort(struct Scsi_Host *host); -static void do_reset(struct Scsi_Host *host); - -/* - * initialize_SCp - init the scsi pointer field - * @cmd: command block to set up - * - * Set up the internal fields in the SCSI command. - */ - -static __inline__ void initialize_SCp(Scsi_Cmnd * cmd) -{ - /* - * Initialize the Scsi Pointer field so that all of the commands in the - * various queues are valid. - */ - - if (scsi_bufflen(cmd)) { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = NULL; - cmd->SCp.this_residual = 0; - } -} - -/** - * NCR5380_poll_politely - wait for NCR5380 status bits - * @instance: controller to poll - * @reg: 5380 register to poll - * @bit: Bitmask to check - * @val: Value required to exit - * - * Polls the NCR5380 in a reasonably efficient manner waiting for - * an event to occur, after a short quick poll we begin giving the - * CPU back in non IRQ contexts - * - * Returns the value of the register or a negative error code. - */ - -static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, int val, int t) -{ - NCR5380_local_declare(); - int n = 500; /* At about 8uS a cycle for the cpu access */ - unsigned long end = jiffies + t; - int r; - - NCR5380_setup(instance); - - while( n-- > 0) - { - r = NCR5380_read(reg); - if((r & bit) == val) - return 0; - cpu_relax(); - } - - /* t time yet ? */ - while(time_before(jiffies, end)) - { - r = NCR5380_read(reg); - if((r & bit) == val) - return 0; - if(!in_interrupt()) - cond_resched(); - else - cpu_relax(); - } - return -ETIMEDOUT; -} - -static struct { - unsigned char value; - const char *name; -} phases[] __maybe_unused = { - {PHASE_DATAOUT, "DATAOUT"}, - {PHASE_DATAIN, "DATAIN"}, - {PHASE_CMDOUT, "CMDOUT"}, - {PHASE_STATIN, "STATIN"}, - {PHASE_MSGOUT, "MSGOUT"}, - {PHASE_MSGIN, "MSGIN"}, - {PHASE_UNKNOWN, "UNKNOWN"} -}; - -#if NDEBUG -static struct { - unsigned char mask; - const char *name; -} signals[] = { - {SR_DBP, "PARITY"}, - {SR_RST, "RST"}, - {SR_BSY, "BSY"}, - {SR_REQ, "REQ"}, - {SR_MSG, "MSG"}, - {SR_CD, "CD"}, - {SR_IO, "IO"}, - {SR_SEL, "SEL"}, - {0, NULL} -}, -basrs[] = { - {BASR_ATN, "ATN"}, - {BASR_ACK, "ACK"}, - {0, NULL} -}, -icrs[] = { - {ICR_ASSERT_RST, "ASSERT RST"}, - {ICR_ASSERT_ACK, "ASSERT ACK"}, - {ICR_ASSERT_BSY, "ASSERT BSY"}, - {ICR_ASSERT_SEL, "ASSERT SEL"}, - {ICR_ASSERT_ATN, "ASSERT ATN"}, - {ICR_ASSERT_DATA, "ASSERT DATA"}, - {0, NULL} -}, -mrs[] = { - {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, - {MR_TARGET, "MODE TARGET"}, - {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, - {MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, - {MR_MONITOR_BSY, "MODE MONITOR BSY"}, - {MR_DMA_MODE, "MODE DMA"}, - {MR_ARBITRATE, "MODE ARBITRATION"}, - {0, NULL} -}; - -/** - * NCR5380_print - print scsi bus signals - * @instance: adapter state to dump - * - * Print the SCSI bus signals for debugging purposes - * - * Locks: caller holds hostdata lock (not essential) - */ - -static void NCR5380_print(struct Scsi_Host *instance) -{ - NCR5380_local_declare(); - unsigned char status, data, basr, mr, icr, i; - NCR5380_setup(instance); - - data = NCR5380_read(CURRENT_SCSI_DATA_REG); - status = NCR5380_read(STATUS_REG); - mr = NCR5380_read(MODE_REG); - icr = NCR5380_read(INITIATOR_COMMAND_REG); - basr = NCR5380_read(BUS_AND_STATUS_REG); - - printk("STATUS_REG: %02x ", status); - for (i = 0; signals[i].mask; ++i) - if (status & signals[i].mask) - printk(",%s", signals[i].name); - printk("\nBASR: %02x ", basr); - for (i = 0; basrs[i].mask; ++i) - if (basr & basrs[i].mask) - printk(",%s", basrs[i].name); - printk("\nICR: %02x ", icr); - for (i = 0; icrs[i].mask; ++i) - if (icr & icrs[i].mask) - printk(",%s", icrs[i].name); - printk("\nMODE: %02x ", mr); - for (i = 0; mrs[i].mask; ++i) - if (mr & mrs[i].mask) - printk(",%s", mrs[i].name); - printk("\n"); -} - - -/* - * NCR5380_print_phase - show SCSI phase - * @instance: adapter to dump - * - * Print the current SCSI phase for debugging purposes - * - * Locks: none - */ - -static void NCR5380_print_phase(struct Scsi_Host *instance) -{ - NCR5380_local_declare(); - unsigned char status; - int i; - NCR5380_setup(instance); - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); - printk("scsi%d : phase %s\n", instance->host_no, phases[i].name); - } -} -#endif - -/* - * These need tweaking, and would probably work best as per-device - * flags initialized differently for disk, tape, cd, etc devices. - * People with broken devices are free to experiment as to what gives - * the best results for them. - * - * USLEEP_SLEEP should be a minimum seek time. - * - * USLEEP_POLL should be a maximum rotational latency. - */ -#ifndef USLEEP_SLEEP -/* 20 ms (reasonable hard disk speed) */ -#define USLEEP_SLEEP (20*HZ/1000) -#endif -/* 300 RPM (floppy speed) */ -#ifndef USLEEP_POLL -#define USLEEP_POLL (200*HZ/1000) -#endif -#ifndef USLEEP_WAITLONG -/* RvC: (reasonable time to wait on select error) */ -#define USLEEP_WAITLONG USLEEP_SLEEP -#endif - -/* - * Function : int should_disconnect (unsigned char cmd) - * - * Purpose : decide whether a command would normally disconnect or - * not, since if it won't disconnect we should go to sleep. - * - * Input : cmd - opcode of SCSI command - * - * Returns : DISCONNECT_LONG if we should disconnect for a really long - * time (ie always, sleep, look for REQ active, sleep), - * DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal - * time-to-data delay, DISCONNECT_NONE if this command would return - * immediately. - * - * Future sleep algorithms based on time to data can exploit - * something like this so they can differentiate between "normal" - * (ie, read, write, seek) and unusual commands (ie, * format). - * - * Note : We don't deal with commands that handle an immediate disconnect, - * - */ - -static int should_disconnect(unsigned char cmd) -{ - switch (cmd) { - case READ_6: - case WRITE_6: - case SEEK_6: - case READ_10: - case WRITE_10: - case SEEK_10: - return DISCONNECT_TIME_TO_DATA; - case FORMAT_UNIT: - case SEARCH_HIGH: - case SEARCH_LOW: - case SEARCH_EQUAL: - return DISCONNECT_LONG; - default: - return DISCONNECT_NONE; - } -} - -static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout) -{ - hostdata->time_expires = jiffies + timeout; - schedule_delayed_work(&hostdata->coroutine, timeout); -} - - -static int probe_irq __initdata = 0; - -/** - * probe_intr - helper for IRQ autoprobe - * @irq: interrupt number - * @dev_id: unused - * @regs: unused - * - * Set a flag to indicate the IRQ in question was received. This is - * used by the IRQ probe code. - */ - -static irqreturn_t __init probe_intr(int irq, void *dev_id) -{ - probe_irq = irq; - return IRQ_HANDLED; -} - -/** - * NCR5380_probe_irq - find the IRQ of an NCR5380 - * @instance: NCR5380 controller - * @possible: bitmask of ISA IRQ lines - * - * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ - * and then looking to see what interrupt actually turned up. - * - * Locks: none, irqs must be enabled on entry - */ - -static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance, - int possible) -{ - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - unsigned long timeout; - int trying_irqs, i, mask; - NCR5380_setup(instance); - - for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1) - if ((mask & possible) && (request_irq(i, &probe_intr, IRQF_DISABLED, "NCR-probe", NULL) == 0)) - trying_irqs |= mask; - - timeout = jiffies + (250 * HZ / 1000); - probe_irq = SCSI_IRQ_NONE; - - /* - * A interrupt is triggered whenever BSY = false, SEL = true - * and a bit set in the SELECT_ENABLE_REG is asserted on the - * SCSI bus. - * - * Note that the bus is only driven when the phase control signals - * (I/O, C/D, and MSG) match those in the TCR, so we must reset that - * to zero. - */ - - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); - - while (probe_irq == SCSI_IRQ_NONE && time_before(jiffies, timeout)) - schedule_timeout_uninterruptible(1); - - NCR5380_write(SELECT_ENABLE_REG, 0); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - for (i = 0, mask = 1; i < 16; ++i, mask <<= 1) - if (trying_irqs & mask) - free_irq(i, NULL); - - return probe_irq; -} - -/** - * NCR58380_print_options - show options - * @instance: unused for now - * - * Called by probe code indicating the NCR5380 driver options that - * were selected. At some point this will switch to runtime options - * read from the adapter in question - * - * Locks: none - */ - -static void __init __maybe_unused -NCR5380_print_options(struct Scsi_Host *instance) -{ - printk(" generic options" -#ifdef AUTOPROBE_IRQ - " AUTOPROBE_IRQ" -#endif -#ifdef AUTOSENSE - " AUTOSENSE" -#endif -#ifdef DIFFERENTIAL - " DIFFERENTIAL" -#endif -#ifdef REAL_DMA - " REAL DMA" -#endif -#ifdef REAL_DMA_POLL - " REAL DMA POLL" -#endif -#ifdef PARITY - " PARITY" -#endif -#ifdef PSEUDO_DMA - " PSEUDO DMA" -#endif -#ifdef UNSAFE - " UNSAFE " -#endif - ); - printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP); - printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); - if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) { - printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE); - } -} - -/** - * NCR5380_print_status - dump controller info - * @instance: controller to dump - * - * Print commands in the various queues, called from NCR5380_abort - * and NCR5380_debug to aid debugging. - * - * Locks: called functions disable irqs - */ - -static void NCR5380_print_status(struct Scsi_Host *instance) -{ - NCR5380_dprint(NDEBUG_ANY, instance); - NCR5380_dprint_phase(NDEBUG_ANY, instance); -} - -/******************************************/ -/* - * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED] - * - * *buffer: I/O buffer - * **start: if inout == FALSE pointer into buffer where user read should start - * offset: current offset - * length: length of buffer - * hostno: Scsi_Host host_no - * inout: TRUE - user is writing; FALSE - user is reading - * - * Return the number of bytes read from or written - */ - -#undef SPRINTF -#define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0) -static -char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length); -static -char *lprint_command(unsigned char *cmd, char *pos, char *buffer, int len); -static -char *lprint_opcode(int opcode, char *pos, char *buffer, int length); - -static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance, - char *buffer, char **start, off_t offset, int length, int inout) -{ - char *pos = buffer; - struct NCR5380_hostdata *hostdata; - Scsi_Cmnd *ptr; - - hostdata = (struct NCR5380_hostdata *) instance->hostdata; - - if (inout) { /* Has data been written to the file ? */ -#ifdef DTC_PUBLIC_RELEASE - dtc_wmaxi = dtc_maxi = 0; -#endif -#ifdef PAS16_PUBLIC_RELEASE - pas_wmaxi = pas_maxi = 0; -#endif - return (-ENOSYS); /* Currently this is a no-op */ - } - SPRINTF("NCR5380 core release=%d. ", NCR5380_PUBLIC_RELEASE); - if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) - SPRINTF("ncr53c400 release=%d. ", NCR53C400_PUBLIC_RELEASE); -#ifdef DTC_PUBLIC_RELEASE - SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE); -#endif -#ifdef T128_PUBLIC_RELEASE - SPRINTF("T128 release %d", T128_PUBLIC_RELEASE); -#endif -#ifdef GENERIC_NCR5380_PUBLIC_RELEASE - SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE); -#endif -#ifdef PAS16_PUBLIC_RELEASE - SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE); -#endif - - SPRINTF("\nBase Addr: 0x%05lX ", (long) instance->base); - SPRINTF("io_port: %04x ", (int) instance->io_port); - if (instance->irq == SCSI_IRQ_NONE) - SPRINTF("IRQ: None.\n"); - else - SPRINTF("IRQ: %d.\n", instance->irq); - -#ifdef DTC_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", dtc_wmaxi, dtc_maxi); -#endif -#ifdef PAS16_PUBLIC_RELEASE - SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi); -#endif - spin_lock_irq(instance->host_lock); - if (!hostdata->connected) - SPRINTF("scsi%d: no currently connected command\n", instance->host_no); - else - pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length); - SPRINTF("scsi%d: issue_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - - SPRINTF("scsi%d: disconnected_queue\n", instance->host_no); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - spin_unlock_irq(instance->host_lock); - - *start = buffer; - if (pos - buffer < offset) - return 0; - else if (pos - buffer - offset < length) - return pos - buffer - offset; - return length; -} - -static char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length) -{ - SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun); - SPRINTF(" command = "); - pos = lprint_command(cmd->cmnd, pos, buffer, length); - return (pos); -} - -static char *lprint_command(unsigned char *command, char *pos, char *buffer, int length) -{ - int i, s; - pos = lprint_opcode(command[0], pos, buffer, length); - for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - SPRINTF("%02x ", command[i]); - SPRINTF("\n"); - return (pos); -} - -static char *lprint_opcode(int opcode, char *pos, char *buffer, int length) -{ - SPRINTF("%2d (0x%02x)", opcode, opcode); - return (pos); -} - - -/** - * NCR5380_init - initialise an NCR5380 - * @instance: adapter to configure - * @flags: control flags - * - * Initializes *instance and corresponding 5380 chip, - * with flags OR'd into the initial flags value. - * - * Notes : I assume that the host, hostno, and id bits have been - * set correctly. I don't care about the irq and other fields. - * - * Returns 0 for success - * - * Locks: interrupts must be enabled when we are called - */ - -static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags) -{ - NCR5380_local_declare(); - int i, pass; - unsigned long timeout; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - - if(in_interrupt()) - printk(KERN_ERR "NCR5380_init called with interrupts off!\n"); - /* - * On NCR53C400 boards, NCR5380 registers are mapped 8 past - * the base address. - */ - -#ifdef NCR53C400 - if (flags & FLAG_NCR53C400) - instance->NCR5380_instance_name += NCR53C400_address_adjust; -#endif - - NCR5380_setup(instance); - - hostdata->aborted = 0; - hostdata->id_mask = 1 << instance->this_id; - for (i = hostdata->id_mask; i <= 0x80; i <<= 1) - if (i > hostdata->id_mask) - hostdata->id_higher_mask |= i; - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; -#ifdef REAL_DMA - hostdata->dmalen = 0; -#endif - hostdata->targets_present = 0; - hostdata->connected = NULL; - hostdata->issue_queue = NULL; - hostdata->disconnected_queue = NULL; - - INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main); - -#ifdef NCR5380_STATS - for (i = 0; i < 8; ++i) { - hostdata->time_read[i] = 0; - hostdata->time_write[i] = 0; - hostdata->bytes_read[i] = 0; - hostdata->bytes_write[i] = 0; - } - hostdata->timebase = 0; - hostdata->pendingw = 0; - hostdata->pendingr = 0; -#endif - - /* The CHECK code seems to break the 53C400. Will check it later maybe */ - if (flags & FLAG_NCR53C400) - hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags; - else - hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags; - - hostdata->host = instance; - hostdata->time_expires = 0; - -#ifndef AUTOSENSE - if ((instance->cmd_per_lun > 1) || instance->can_queue > 1) - printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n" - " be incorrectly cleared.\n", instance->host_no); -#endif /* def AUTOSENSE */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, 0); - -#ifdef NCR53C400 - if (hostdata->flags & FLAG_NCR53C400) { - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); - } -#endif - - /* - * Detect and correct bus wedge problems. - * - * If the system crashed, it may have crashed in a state - * where a SCSI command was still executing, and the - * SCSI bus is not in a BUS FREE STATE. - * - * If this is the case, we'll try to abort the currently - * established nexus which we know nothing about, and that - * failing, do a hard reset of the SCSI bus - */ - - for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) { - switch (pass) { - case 1: - case 3: - case 5: - printk(KERN_INFO "scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no); - timeout = jiffies + 5 * HZ; - NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, 0, 5*HZ); - break; - case 2: - printk(KERN_WARNING "scsi%d: bus busy, attempting abort\n", instance->host_no); - do_abort(instance); - break; - case 4: - printk(KERN_WARNING "scsi%d: bus busy, attempting reset\n", instance->host_no); - do_reset(instance); - break; - case 6: - printk(KERN_ERR "scsi%d: bus locked solid or invalid override\n", instance->host_no); - return -ENXIO; - } - } - return 0; -} - -/** - * NCR5380_exit - remove an NCR5380 - * @instance: adapter to remove - */ - -static void NCR5380_exit(struct Scsi_Host *instance) -{ - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - - cancel_delayed_work_sync(&hostdata->coroutine); -} - -/** - * NCR5380_queue_command - queue a command - * @cmd: SCSI command - * @done: completion handler - * - * cmd is added to the per instance issue_queue, with minor - * twiddling done to the host specific fields of cmd. If the - * main coroutine is not running, it is restarted. - * - * Locks: host lock taken by caller - */ - -static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) -{ - struct Scsi_Host *instance = cmd->device->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - Scsi_Cmnd *tmp; - -#if (NDEBUG & NDEBUG_NO_WRITE) - switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no); - cmd->result = (DID_ERROR << 16); - done(cmd); - return 0; - } -#endif /* (NDEBUG & NDEBUG_NO_WRITE) */ - -#ifdef NCR5380_STATS - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); - hostdata->pendingw++; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); - hostdata->pendingr++; - break; - } -#endif - - /* - * We use the host_scribble field as a pointer to the next command - * in a queue - */ - - cmd->host_scribble = NULL; - cmd->scsi_done = done; - cmd->result = 0; - - /* - * Insert the cmd into the issue queue. Note that REQUEST SENSE - * commands are added to the head of the queue since any command will - * clear the contingent allegiance condition that exists and the - * sense data is only guaranteed to be valid while the condition exists. - */ - - if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { - LIST(cmd, hostdata->issue_queue); - cmd->host_scribble = (unsigned char *) hostdata->issue_queue; - hostdata->issue_queue = cmd; - } else { - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble); - LIST(cmd, tmp); - tmp->host_scribble = (unsigned char *) cmd; - } - dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail")); - - /* Run the coroutine if it isn't already running. */ - /* Kick off command processing */ - schedule_delayed_work(&hostdata->coroutine, 0); - return 0; -} - -static DEF_SCSI_QCMD(NCR5380_queue_command) - -/** - * NCR5380_main - NCR state machines - * - * NCR5380_main is a coroutine that runs as long as more work can - * be done on the NCR5380 host adapters in a system. Both - * NCR5380_queue_command() and NCR5380_intr() will try to start it - * in case it is not running. - * - * Locks: called as its own thread with no locks held. Takes the - * host lock and called routines may take the isa dma lock. - */ - -static void NCR5380_main(struct work_struct *work) -{ - struct NCR5380_hostdata *hostdata = - container_of(work, struct NCR5380_hostdata, coroutine.work); - struct Scsi_Host *instance = hostdata->host; - Scsi_Cmnd *tmp, *prev; - int done; - - spin_lock_irq(instance->host_lock); - do { - /* Lock held here */ - done = 1; - if (!hostdata->connected && !hostdata->selecting) { - dprintk(NDEBUG_MAIN, ("scsi%d : not connected\n", instance->host_no)); - /* - * Search through the issue_queue for a command destined - * for a target that's not busy. - */ - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) - { - if (prev != tmp) - dprintk(NDEBUG_LISTS, ("MAIN tmp=%p target=%d busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun)); - /* When we find one, remove it from the issue queue. */ - if (!(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))) { - if (prev) { - REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); - prev->host_scribble = tmp->host_scribble; - } else { - REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble); - hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble; - } - tmp->host_scribble = NULL; - - /* - * Attempt to establish an I_T_L nexus here. - * On success, instance->hostdata->connected is set. - * On failure, we must add the command back to the - * issue queue so we can keep trying. - */ - dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun)); - - /* - * A successful selection is defined as one that - * leaves us with the command connected and - * in hostdata->connected, OR has terminated the - * command. - * - * With successful commands, we fall through - * and see if we can do an information transfer, - * with failures we will restart. - */ - hostdata->selecting = NULL; - /* RvC: have to preset this to indicate a new command is being performed */ - - if (!NCR5380_select(instance, tmp, - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { - break; - } else { - LIST(tmp, hostdata->issue_queue); - tmp->host_scribble = (unsigned char *) hostdata->issue_queue; - hostdata->issue_queue = tmp; - done = 0; - dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no)); - } - /* lock held here still */ - } /* if target/lun is not busy */ - } /* for */ - /* exited locked */ - } /* if (!hostdata->connected) */ - if (hostdata->selecting) { - tmp = (Scsi_Cmnd *) hostdata->selecting; - /* Selection will drop and retake the lock */ - if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) { - /* Ok ?? */ - } else { - /* RvC: device failed, so we wait a long time - this is needed for Mustek scanners, that - do not respond to commands immediately - after a scan */ - printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->device->id); - LIST(tmp, hostdata->issue_queue); - tmp->host_scribble = (unsigned char *) hostdata->issue_queue; - hostdata->issue_queue = tmp; - NCR5380_set_timer(hostdata, USLEEP_WAITLONG); - } - } /* if hostdata->selecting */ - if (hostdata->connected -#ifdef REAL_DMA - && !hostdata->dmalen -#endif - && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies)) - ) { - dprintk(NDEBUG_MAIN, ("scsi%d : main() : performing information transfer\n", instance->host_no)); - NCR5380_information_transfer(instance); - dprintk(NDEBUG_MAIN, ("scsi%d : main() : done set false\n", instance->host_no)); - done = 0; - } else - break; - } while (!done); - - spin_unlock_irq(instance->host_lock); -} - -#ifndef DONT_USE_INTR - -/** - * NCR5380_intr - generic NCR5380 irq handler - * @irq: interrupt number - * @dev_id: device info - * - * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses - * from the disconnected queue, and restarting NCR5380_main() - * as required. - * - * Locks: takes the needed instance locks - */ - -static irqreturn_t NCR5380_intr(int dummy, void *dev_id) -{ - NCR5380_local_declare(); - struct Scsi_Host *instance = dev_id; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - int done; - unsigned char basr; - unsigned long flags; - - dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", - instance->irq)); - - do { - done = 1; - spin_lock_irqsave(instance->host_lock, flags); - /* Look for pending interrupts */ - NCR5380_setup(instance); - basr = NCR5380_read(BUS_AND_STATUS_REG); - /* XXX dispatch to appropriate routine if found and done=0 */ - if (basr & BASR_IRQ) { - NCR5380_dprint(NDEBUG_INTR, instance); - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { - done = 0; - dprintk(NDEBUG_INTR, ("scsi%d : SEL interrupt\n", instance->host_no)); - NCR5380_reselect(instance); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else if (basr & BASR_PARITY_ERROR) { - dprintk(NDEBUG_INTR, ("scsi%d : PARITY interrupt\n", instance->host_no)); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { - dprintk(NDEBUG_INTR, ("scsi%d : RESET interrupt\n", instance->host_no)); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else { -#if defined(REAL_DMA) - /* - * We should only get PHASE MISMATCH and EOP interrupts - * if we have DMA enabled, so do a sanity check based on - * the current setting of the MODE register. - */ - - if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) { - int transferred; - - if (!hostdata->connected) - panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno); - - transferred = (hostdata->dmalen - NCR5380_dma_residual(instance)); - hostdata->connected->SCp.this_residual -= transferred; - hostdata->connected->SCp.ptr += transferred; - hostdata->dmalen = 0; - - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - - /* FIXME: we need to poll briefly then defer a workqueue task ! */ - NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2*HZ); - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - } -#else - dprintk(NDEBUG_INTR, ("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG))); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); -#endif - } - } /* if BASR_IRQ */ - spin_unlock_irqrestore(instance->host_lock, flags); - if(!done) - schedule_delayed_work(&hostdata->coroutine, 0); - } while (!done); - return IRQ_HANDLED; -} - -#endif - -/** - * collect_stats - collect stats on a scsi command - * @hostdata: adapter - * @cmd: command being issued - * - * Update the statistical data by parsing the command in question - */ - -static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) -{ -#ifdef NCR5380_STATS - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[scmd_id(cmd)] += (jiffies - hostdata->timebase); - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[scmd_id(cmd)] += (jiffies - hostdata->timebase); - hostdata->pendingr--; - break; - } -#endif -} - - -/* - * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, - * int tag); - * - * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, - * including ARBITRATION, SELECTION, and initial message out for - * IDENTIFY and queue messages. - * - * Inputs : instance - instantiation of the 5380 driver on which this - * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for - * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for - * the command that is presently connected. - * - * Returns : -1 if selection could not execute for some reason, - * 0 if selection succeeded or failed because the target - * did not respond. - * - * Side effects : - * If bus busy, arbitration failed, etc, NCR5380_select() will exit - * with registers as they should have been on entry - ie - * SELECT_ENABLE will be set appropriately, the NCR5380 - * will cease to drive any SCSI bus signals. - * - * If successful : I_T_L or I_T_L_Q nexus will be established, - * instance->connected will be set to cmd. - * SELECT interrupt will be disabled. - * - * If failed (no target) : cmd->scsi_done() will be called, and the - * cmd->result host byte set to DID_BAD_TARGET. - * - * Locks: caller holds hostdata lock in IRQ mode - */ - -static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) -{ - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - unsigned char tmp[3], phase; - unsigned char *data; - int len; - unsigned long timeout; - unsigned char value; - int err; - NCR5380_setup(instance); - - if (hostdata->selecting) - goto part2; - - hostdata->restart_select = 0; - - NCR5380_dprint(NDEBUG_ARBITRATION, instance); - dprintk(NDEBUG_ARBITRATION, ("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id)); - - /* - * Set the phase bits to 0, otherwise the NCR5380 won't drive the - * data bus during SELECTION. - */ - - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* - * Start arbitration. - */ - - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); - - - /* We can be relaxed here, interrupts are on, we are - in workqueue context, the birds are singing in the trees */ - spin_unlock_irq(instance->host_lock); - err = NCR5380_poll_politely(instance, INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, ICR_ARBITRATION_PROGRESS, 5*HZ); - spin_lock_irq(instance->host_lock); - if (err < 0) { - printk(KERN_DEBUG "scsi: arbitration timeout at %d\n", __LINE__); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - goto failed; - } - - dprintk(NDEBUG_ARBITRATION, ("scsi%d : arbitration complete\n", instance->host_no)); - - /* - * The arbitration delay is 2.2us, but this is a minimum and there is - * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate - * the integral nature of udelay(). - * - */ - - udelay(3); - - /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { - NCR5380_write(MODE_REG, MR_BASE); - dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no)); - goto failed; - } - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL); - - if (!(hostdata->flags & FLAG_DTC3181E) && - /* RvC: DTC3181E has some trouble with this - * so we simply removed it. Seems to work with - * only Mustek scanner attached - */ - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no)); - goto failed; - } - /* - * Again, bus clear + bus settle time is 1.2us, however, this is - * a minimum so we'll udelay ceil(1.2) - */ - - udelay(2); - - dprintk(NDEBUG_ARBITRATION, ("scsi%d : won arbitration\n", instance->host_no)); - - /* - * Now that we have won arbitration, start Selection process, asserting - * the host and target ID's on the SCSI bus. - */ - - NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << scmd_id(cmd)))); - - /* - * Raise ATN while SEL is true before BSY goes false from arbitration, - * since this is the only way to guarantee that we'll get a MESSAGE OUT - * phase immediately after selection. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); - NCR5380_write(MODE_REG, MR_BASE); - - /* - * Reselect interrupts must be turned off prior to the dropping of BSY, - * otherwise we will trigger an interrupt. - */ - NCR5380_write(SELECT_ENABLE_REG, 0); - - /* - * The initiator shall then wait at least two deskew delays and release - * the BSY signal. - */ - udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ - - /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL)); - - /* - * Something weird happens when we cease to drive BSY - looks - * like the board/chip is letting us do another read before the - * appropriate propagation delay has expired, and we're confusing - * a BSY signal from ourselves as the target's response to SELECTION. - * - * A small delay (the 'C++' frontend breaks the pipeline with an - * unnecessary jump, making it work on my 386-33/Trantor T128, the - * tighter 'C' code breaks and requires this) solves the problem - - * the 1 us delay is arbitrary, and only used because this delay will - * be the same on other platforms and since it works here, it should - * work there. - * - * wingel suggests that this could be due to failing to wait - * one deskew delay. - */ - - udelay(1); - - dprintk(NDEBUG_SELECTION, ("scsi%d : selecting target %d\n", instance->host_no, scmd_id(cmd))); - - /* - * The SCSI specification calls for a 250 ms timeout for the actual - * selection. - */ - - timeout = jiffies + (250 * HZ / 1000); - - /* - * XXX very interesting - we're seeing a bounce where the BSY we - * asserted is being reflected / still asserted (propagation delay?) - * and it's detecting as true. Sigh. - */ - - hostdata->select_time = 0; /* we count the clock ticks at which we polled */ - hostdata->selecting = cmd; - -part2: - /* RvC: here we enter after a sleeping period, or immediately after - execution of part 1 - we poll only once ech clock tick */ - value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO); - - if (!value && (hostdata->select_time < HZ/4)) { - /* RvC: we still must wait for a device response */ - hostdata->select_time++; /* after 25 ticks the device has failed */ - NCR5380_set_timer(hostdata, 1); - return 0; /* RvC: we return here with hostdata->selecting set, - to go to sleep */ - } - - hostdata->selecting = NULL;/* clear this pointer, because we passed the - waiting period */ - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_reselect(instance); - printk("scsi%d : reselection after won arbitration?\n", instance->host_no); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - /* - * No less than two deskew delays after the initiator detects the - * BSY signal is true, it shall release the SEL signal and may - * change the DATA BUS. -wingel - */ - - udelay(1); - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if (hostdata->targets_present & (1 << scmd_id(cmd))) { - printk(KERN_DEBUG "scsi%d : weirdness\n", instance->host_no); - if (hostdata->restart_select) - printk(KERN_DEBUG "\trestart select\n"); - NCR5380_dprint(NDEBUG_SELECTION, instance); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - cmd->result = DID_BAD_TARGET << 16; - collect_stats(hostdata, cmd); - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - dprintk(NDEBUG_SELECTION, ("scsi%d : target did not respond within 250ms\n", instance->host_no)); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return 0; - } - hostdata->targets_present |= (1 << scmd_id(cmd)); - - /* - * Since we followed the SCSI spec, and raised ATN while SEL - * was true but before BSY was false during selection, the information - * transfer phase should be a MESSAGE OUT phase so that we can send the - * IDENTIFY message. - * - * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG - * message (2 bytes) with a tag ID that we increment with every command - * until it wraps back to 0. - * - * XXX - it turns out that there are some broken SCSI-II devices, - * which claim to support tagged queuing but fail when more than - * some number of commands are issued at once. - */ - - /* Wait for start of REQ/ACK handshake */ - - spin_unlock_irq(instance->host_lock); - err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ); - spin_lock_irq(instance->host_lock); - - if(err) { - printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - goto failed; - } - - dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id)); - tmp[0] = IDENTIFY(((instance->irq == SCSI_IRQ_NONE) ? 0 : 1), cmd->device->lun); - - len = 1; - cmd->tag = 0; - - /* Send message(s) */ - data = tmp; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(instance, &phase, &len, &data); - dprintk(NDEBUG_SELECTION, ("scsi%d : nexus established.\n", instance->host_no)); - /* XXX need to handle errors here */ - hostdata->connected = cmd; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - - initialize_SCp(cmd); - - return 0; - - /* Selection failed */ -failed: - return -1; - -} - -/* - * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, - * unsigned char *phase, int *count, unsigned char **data) - * - * Purpose : transfers data in given phase using polled I/O - * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. - * - * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transferred or exit - * is in same phase. - * - * Also, *phase, *count, *data are modified in place. - * - * XXX Note : handling for bus free may be useful. - */ - -/* - * Note : this code is not as quick as it could be, however it - * IS 100% reliable, and for the actual data transfer where speed - * counts, we will always do a pseudo DMA or DMA transfer. - */ - -static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { - NCR5380_local_declare(); - unsigned char p = *phase, tmp; - int c = *count; - unsigned char *d = *data; - /* - * RvC: some administrative data to process polling time - */ - int break_allowed = 0; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - NCR5380_setup(instance); - - if (!(p & SR_IO)) - dprintk(NDEBUG_PIO, ("scsi%d : pio write %d bytes\n", instance->host_no, c)); - else - dprintk(NDEBUG_PIO, ("scsi%d : pio read %d bytes\n", instance->host_no, c)); - - /* - * The NCR5380 chip will only drive the SCSI bus when the - * phase specified in the appropriate bits of the TARGET COMMAND - * REGISTER match the STATUS REGISTER - */ - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - - /* RvC: don't know if this is necessary, but other SCSI I/O is short - * so breaks are not necessary there - */ - if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) { - break_allowed = 1; - } - do { - /* - * Wait for assertion of REQ, after which the phase bits will be - * valid - */ - - /* RvC: we simply poll once, after that we stop temporarily - * and let the device buffer fill up - * if breaking is not allowed, we keep polling as long as needed - */ - - /* FIXME */ - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed); - if (!(tmp & SR_REQ)) { - /* timeout condition */ - NCR5380_set_timer(hostdata, USLEEP_SLEEP); - break; - } - - dprintk(NDEBUG_HANDSHAKE, ("scsi%d : REQ detected\n", instance->host_no)); - - /* Check for phase mismatch */ - if ((tmp & PHASE_MASK) != p) { - dprintk(NDEBUG_HANDSHAKE, ("scsi%d : phase mismatch\n", instance->host_no)); - NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance); - break; - } - /* Do actual transfer from SCSI bus to / from memory */ - if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); - else - *d = NCR5380_read(CURRENT_SCSI_DATA_REG); - - ++d; - - /* - * The SCSI standard suggests that in MSGOUT phase, the initiator - * should drop ATN on the last byte of the message phase - * after REQ has been asserted for the handshake but before - * the initiator raises ACK. - */ - - if (!(p & SR_IO)) { - if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); - NCR5380_dprint(NDEBUG_PIO, instance); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK); - } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN); - NCR5380_dprint(NDEBUG_PIO, instance); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - } - } else { - NCR5380_dprint(NDEBUG_PIO, instance); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); - } - - /* FIXME - if this fails bus reset ?? */ - NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 5*HZ); - dprintk(NDEBUG_HANDSHAKE, ("scsi%d : req false, handshake complete\n", instance->host_no)); - -/* - * We have several special cases to consider during REQ/ACK handshaking : - * 1. We were in MSGOUT phase, and we are on the last byte of the - * message. ATN must be dropped as ACK is dropped. - * - * 2. We are in a MSGIN phase, and we are on the last byte of the - * message. We must exit with ACK asserted, so that the calling - * code may raise ATN before dropping ACK to reject the message. - * - * 3. ACK and ATN are clear and the target may proceed as normal. - */ - if (!(p == PHASE_MSGIN && c == 1)) { - if (p == PHASE_MSGOUT && c > 1) - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - else - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - } - } while (--c); - - dprintk(NDEBUG_PIO, ("scsi%d : residual %d\n", instance->host_no, c)); - - *count = c; - *data = d; - tmp = NCR5380_read(STATUS_REG); - if (tmp & SR_REQ) - *phase = tmp & PHASE_MASK; - else - *phase = PHASE_UNKNOWN; - - if (!c || (*phase == p)) - return 0; - else - return -1; -} - -/** - * do_reset - issue a reset command - * @host: adapter to reset - * - * Issue a reset sequence to the NCR5380 and try and get the bus - * back into sane shape. - * - * Locks: caller holds queue lock - */ - -static void do_reset(struct Scsi_Host *host) { - NCR5380_local_declare(); - NCR5380_setup(host); - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - udelay(25); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); -} - -/* - * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * - * Returns : 0 on success, -1 on failure. - * - * Locks: queue lock held by caller - * FIXME: sort this out and get new_eh running - */ - -static int do_abort(struct Scsi_Host *host) { - NCR5380_local_declare(); - unsigned char *msgptr, phase, tmp; - int len; - int rc; - NCR5380_setup(host); - - - /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - /* - * Wait for the target to indicate a valid phase by asserting - * REQ. Once this happens, we'll have either a MSGOUT phase - * and can immediately send the ABORT message, or we'll have some - * other phase and will have to source/sink data. - * - * We really don't care what value was on the bus or what value - * the target sees, so we just handshake. - */ - - rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, SR_REQ, 60 * HZ); - - if(rc < 0) - return -1; - - tmp = (unsigned char)rc; - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, 0, 3*HZ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - if(rc == -1) - return -1; - } - tmp = ABORT; - msgptr = &tmp; - len = 1; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(host, &phase, &len, &msgptr); - - /* - * If we got here, and the command completed successfully, - * we're about to go into bus free state. - */ - - return len ? -1 : 0; -} - -#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL) -/* - * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, - * unsigned char *phase, int *count, unsigned char **data) - * - * Purpose : transfers data in given phase using either real - * or pseudo DMA. - * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. - * - * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transferred or exit - * is in same phase. - * - * Also, *phase, *count, *data are modified in place. - * - * Locks: io_request lock held by caller - */ - - -static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) { - NCR5380_local_declare(); - register int c = *count; - register unsigned char p = *phase; - register unsigned char *d = *data; - unsigned char tmp; - int foo; -#if defined(REAL_DMA_POLL) - int cnt, toPIO; - unsigned char saved_data = 0, overrun = 0, residue; -#endif - - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - - NCR5380_setup(instance); - - if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { - *phase = tmp; - return -1; - } -#if defined(REAL_DMA) || defined(REAL_DMA_POLL) -#ifdef READ_OVERRUNS - if (p & SR_IO) { - c -= 2; - } -#endif - dprintk(NDEBUG_DMA, ("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d)); - hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c); -#endif - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - -#ifdef REAL_DMA - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); -#elif defined(REAL_DMA_POLL) - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); -#else - /* - * Note : on my sample board, watch-dog timeouts occurred when interrupts - * were not disabled for the duration of a single DMA transfer, from - * before the setting of DMA mode to after transfer of the last byte. - */ - -#if defined(PSEUDO_DMA) && defined(UNSAFE) - spin_unlock_irq(instance->host_lock); -#endif - /* KLL May need eop and parity in 53c400 */ - if (hostdata->flags & FLAG_NCR53C400) - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | - MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | - MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); - else - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); -#endif /* def REAL_DMA */ - - dprintk(NDEBUG_DMA, ("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG))); - - /* - * On the PAS16 at least I/O recovery delays are not needed here. - * Everyone else seems to want them. - */ - - if (p & SR_IO) { - io_recovery_delay(1); - NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); - } else { - io_recovery_delay(1); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); - io_recovery_delay(1); - NCR5380_write(START_DMA_SEND_REG, 0); - io_recovery_delay(1); - } - -#if defined(REAL_DMA_POLL) - do { - tmp = NCR5380_read(BUS_AND_STATUS_REG); - } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER))); - -/* - At this point, either we've completed DMA, or we have a phase mismatch, - or we've unexpectedly lost BUSY (which is a real error). - - For write DMAs, we want to wait until the last byte has been - transferred out over the bus before we turn off DMA mode. Alas, there - seems to be no terribly good way of doing this on a 5380 under all - conditions. For non-scatter-gather operations, we can wait until REQ - and ACK both go false, or until a phase mismatch occurs. Gather-writes - are nastier, since the device will be expecting more data than we - are prepared to send it, and REQ will remain asserted. On a 53C8[01] we - could test LAST BIT SENT to assure transfer (I imagine this is precisely - why this signal was added to the newer chips) but on the older 538[01] - this signal does not exist. The workaround for this lack is a watchdog; - we bail out of the wait-loop after a modest amount of wait-time if - the usual exit conditions are not met. Not a terribly clean or - correct solution :-% - - Reads are equally tricky due to a nasty characteristic of the NCR5380. - If the chip is in DMA mode for an READ, it will respond to a target's - REQ by latching the SCSI data into the INPUT DATA register and asserting - ACK, even if it has _already_ been notified by the DMA controller that - the current DMA transfer has completed! If the NCR5380 is then taken - out of DMA mode, this already-acknowledged byte is lost. - - This is not a problem for "one DMA transfer per command" reads, because - the situation will never arise... either all of the data is DMA'ed - properly, or the target switches to MESSAGE IN phase to signal a - disconnection (either operation bringing the DMA to a clean halt). - However, in order to handle scatter-reads, we must work around the - problem. The chosen fix is to DMA N-2 bytes, then check for the - condition before taking the NCR5380 out of DMA mode. One or two extra - bytes are transferred via PIO as necessary to fill out the original - request. - */ - - if (p & SR_IO) { -#ifdef READ_OVERRUNS - udelay(10); - if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) { - saved_data = NCR5380_read(INPUT_DATA_REGISTER); - overrun = 1; - } -#endif - } else { - int limit = 100; - while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) { - if (!(tmp & BASR_PHASE_MATCH)) - break; - if (--limit < 0) - break; - } - } - - dprintk(NDEBUG_DMA, ("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG))); - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - residue = NCR5380_dma_residual(instance); - c -= residue; - *count -= c; - *data += c; - *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; - -#ifdef READ_OVERRUNS - if (*phase == p && (p & SR_IO) && residue == 0) { - if (overrun) { - dprintk(NDEBUG_DMA, ("Got an input overrun, using saved byte\n")); - **data = saved_data; - *data += 1; - *count -= 1; - cnt = toPIO = 1; - } else { - printk("No overrun??\n"); - cnt = toPIO = 2; - } - dprintk(NDEBUG_DMA, ("Doing %d-byte PIO to 0x%X\n", cnt, *data)); - NCR5380_transfer_pio(instance, phase, &cnt, data); - *count -= toPIO - cnt; - } -#endif - - dprintk(NDEBUG_DMA, ("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count))); - return 0; - -#elif defined(REAL_DMA) - return 0; -#else /* defined(REAL_DMA_POLL) */ - if (p & SR_IO) { -#ifdef DMA_WORKS_RIGHT - foo = NCR5380_pread(instance, d, c); -#else - int diff = 1; - if (hostdata->flags & FLAG_NCR53C400) { - diff = 0; - } - if (!(foo = NCR5380_pread(instance, d, c - diff))) { - /* - * We can't disable DMA mode after successfully transferring - * what we plan to be the last byte, since that would open up - * a race condition where if the target asserted REQ before - * we got the DMA mode reset, the NCR5380 would have latched - * an additional byte into the INPUT DATA register and we'd - * have dropped it. - * - * The workaround was to transfer one fewer bytes than we - * intended to with the pseudo-DMA read function, wait for - * the chip to latch the last byte, read it, and then disable - * pseudo-DMA mode. - * - * After REQ is asserted, the NCR5380 asserts DRQ and ACK. - * REQ is deasserted when ACK is asserted, and not reasserted - * until ACK goes false. Since the NCR5380 won't lower ACK - * until DACK is asserted, which won't happen unless we twiddle - * the DMA port or we take the NCR5380 out of DMA mode, we - * can guarantee that we won't handshake another extra - * byte. - */ - - if (!(hostdata->flags & FLAG_NCR53C400)) { - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); - /* Wait for clean handshake */ - while (NCR5380_read(STATUS_REG) & SR_REQ); - d[c - 1] = NCR5380_read(INPUT_DATA_REG); - } - } -#endif - } else { -#ifdef DMA_WORKS_RIGHT - foo = NCR5380_pwrite(instance, d, c); -#else - int timeout; - dprintk(NDEBUG_C400_PWRITE, ("About to pwrite %d bytes\n", c)); - if (!(foo = NCR5380_pwrite(instance, d, c))) { - /* - * Wait for the last byte to be sent. If REQ is being asserted for - * the byte we're interested, we'll ACK it and it will go false. - */ - if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { - timeout = 20000; - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)); - - if (!timeout) - dprintk(NDEBUG_LAST_BYTE_SENT, ("scsi%d : timed out on last byte\n", instance->host_no)); - - if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { - hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; - if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { - hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; - dprintk(NDEBUG_LAST_WRITE_SENT, ("scsi%d : last bit sent works\n", instance->host_no)); - } - } - } else { - dprintk(NDEBUG_C400_PWRITE, ("Waiting for LASTBYTE\n")); - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); - dprintk(NDEBUG_C400_PWRITE, ("Got LASTBYTE\n")); - } - } -#endif - } - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) { - dprintk(NDEBUG_C400_PWRITE, ("53C400w: Checking for IRQ\n")); - if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) { - dprintk(NDEBUG_C400_PWRITE, ("53C400w: got it, reading reset interrupt reg\n")); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else { - printk("53C400w: IRQ NOT THERE!\n"); - } - } - *data = d + c; - *count = 0; - *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; -#if defined(PSEUDO_DMA) && defined(UNSAFE) - spin_lock_irq(instance->host_lock); -#endif /* defined(REAL_DMA_POLL) */ - return foo; -#endif /* def REAL_DMA */ -} -#endif /* defined(REAL_DMA) | defined(PSEUDO_DMA) */ - -/* - * Function : NCR5380_information_transfer (struct Scsi_Host *instance) - * - * Purpose : run through the various SCSI phases and do as the target - * directs us to. Operates on the currently connected command, - * instance->connected. - * - * Inputs : instance, instance for which we are doing commands - * - * Side effects : SCSI things happen, the disconnected queue will be - * modified if a command disconnects, *instance->connected will - * change. - * - * XXX Note : we need to watch for bus free or a reset condition here - * to recover from an unexpected bus free condition. - * - * Locks: io_request_lock held by caller in IRQ mode - */ - -static void NCR5380_information_transfer(struct Scsi_Host *instance) { - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata; - unsigned char msgout = NOP; - int sink = 0; - int len; -#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) - int transfersize; -#endif - unsigned char *data; - unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; - Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; - /* RvC: we need to set the end of the polling time */ - unsigned long poll_time = jiffies + USLEEP_POLL; - - NCR5380_setup(instance); - - while (1) { - tmp = NCR5380_read(STATUS_REG); - /* We only have a valid SCSI phase when REQ is asserted */ - if (tmp & SR_REQ) { - phase = (tmp & PHASE_MASK); - if (phase != old_phase) { - old_phase = phase; - NCR5380_dprint_phase(NDEBUG_INFORMATION, instance); - } - if (sink && (phase != PHASE_MSGOUT)) { - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - sink = 0; - continue; - } - switch (phase) { - case PHASE_DATAIN: - case PHASE_DATAOUT: -#if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - return; -#endif - /* - * If there is no room left in the current buffer in the - * scatter-gather list, move onto the next one. - */ - - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual)); - } - /* - * The preferred transfer method is going to be - * PSEUDO-DMA for systems that are strictly PIO, - * since we can let the hardware do the handshaking. - * - * For this to work, we need to know the transfersize - * ahead of time, since the pseudo-DMA code will sit - * in an unconditional loop. - */ - -#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) - /* KLL - * PSEUDO_DMA is defined here. If this is the g_NCR5380 - * driver then it will always be defined, so the - * FLAG_NO_PSEUDO_DMA is used to inhibit PDMA in the base - * NCR5380 case. I think this is a fairly clean solution. - * We supplement these 2 if's with the flag. - */ -#ifdef NCR5380_dma_xfer_len - if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { -#else - transfersize = cmd->transfersize; - -#ifdef LIMIT_TRANSFERSIZE /* If we have problems with interrupt service */ - if (transfersize > 512) - transfersize = 512; -#endif /* LIMIT_TRANSFERSIZE */ - - if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) { - /* Limit transfers to 32K, for xx400 & xx406 - * pseudoDMA that transfers in 128 bytes blocks. */ - if (transfersize > 32 * 1024) - transfersize = 32 * 1024; -#endif - len = transfersize; - if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) { - /* - * If the watchdog timer fires, all future accesses to this - * device will use the polled-IO. - */ - scmd_printk(KERN_INFO, cmd, - "switching to slow handshake\n"); - cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - /* XXX - need to source or sink data here, as appropriate */ - } else - cmd->SCp.this_residual -= transfersize - len; - } else -#endif /* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */ - NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **) - &cmd->SCp.ptr); - break; - case PHASE_MSGIN: - len = 1; - data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Message = tmp; - - switch (tmp) { - /* - * Linking lets us reduce the time required to get the - * next command out to the device, hopefully this will - * mean we don't waste another revolution due to the delays - * required by ARBITRATION and another SELECTION. - * - * In the current implementation proposal, low level drivers - * merely have to start the next command, pointed to by - * next_link, done() is called as with unlinked commands. - */ -#ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->device->id, cmd->device->lun)); - /* - * Sanity check : A linked command should only terminate with - * one of these messages if there are more linked commands - * available. - */ - if (!cmd->next_link) { - printk("scsi%d : target %d lun %d linked command complete, no next_link\n" instance->host_no, cmd->device->id, cmd->device->lun); - sink = 1; - do_abort(instance); - return; - } - initialize_SCp(cmd->next_link); - /* The next command is still part of this process */ - cmd->next_link->tag = cmd->tag; - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->device->id, cmd->device->lun)); - collect_stats(hostdata, cmd); - cmd->scsi_done(cmd); - cmd = hostdata->connected; - break; -#endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: - /* Accept message by clearing ACK */ - sink = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - hostdata->connected = NULL; - dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->device->id, cmd->device->lun)); - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - - /* - * I'm not sure what the correct thing to do here is : - * - * If the command that just executed is NOT a request - * sense, the obvious thing to do is to set the result - * code to the values of the stored parameters. - * - * If it was a REQUEST SENSE command, we need some way - * to differentiate between the failure code of the original - * and the failure code of the REQUEST sense - the obvious - * case is success, where we fall through and leave the result - * code unchanged. - * - * The non-obvious place is where the REQUEST SENSE failed - */ - - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (status_byte(cmd->SCp.Status) != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - -#ifdef AUTOSENSE - if ((cmd->cmnd[0] == REQUEST_SENSE) && - hostdata->ses.cmd_len) { - scsi_eh_restore_cmnd(cmd, &hostdata->ses); - hostdata->ses.cmd_len = 0 ; - } - - if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { - scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); - - dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no)); - - LIST(cmd, hostdata->issue_queue); - cmd->host_scribble = (unsigned char *) - hostdata->issue_queue; - hostdata->issue_queue = (Scsi_Cmnd *) cmd; - dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no)); - } else -#endif /* def AUTOSENSE */ - { - collect_stats(hostdata, cmd); - cmd->scsi_done(cmd); - } - - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - return; - case MESSAGE_REJECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - cmd->device->simple_tags = 0; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - break; - default: - break; - } - case DISCONNECT:{ - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - cmd->device->disconnect = 1; - LIST(cmd, hostdata->disconnected_queue); - cmd->host_scribble = (unsigned char *) - hostdata->disconnected_queue; - hostdata->connected = NULL; - hostdata->disconnected_queue = cmd; - dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d lun %d was moved from connected to" " the disconnected_queue\n", instance->host_no, cmd->device->id, cmd->device->lun)); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* Wait for bus free to avoid nasty timeouts - FIXME timeout !*/ - /* NCR538_poll_politely(instance, STATUS_REG, SR_BSY, 0, 30 * HZ); */ - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - return; - } - /* - * The SCSI data pointer is *IMPLICITLY* saved on a disconnect - * operation, in violation of the SCSI spec so we can safely - * ignore SAVE/RESTORE pointers calls. - * - * Unfortunately, some disks violate the SCSI spec and - * don't issue the required SAVE_POINTERS message before - * disconnecting, and we have to break spec to remain - * compatible. - */ - case SAVE_POINTERS: - case RESTORE_POINTERS: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - break; - case EXTENDED_MESSAGE: -/* - * Extended messages are sent in the following format : - * Byte - * 0 EXTENDED_MESSAGE == 1 - * 1 length (includes one byte for code, doesn't - * include first two bytes) - * 2 code - * 3..length+1 arguments - * - * Start the extended message buffer with the EXTENDED_MESSAGE - * byte, since spi_print_msg() wants the whole thing. - */ - extended_msg[0] = EXTENDED_MESSAGE; - /* Accept first byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - dprintk(NDEBUG_EXTENDED, ("scsi%d : receiving extended message\n", instance->host_no)); - - len = 2; - data = extended_msg + 1; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - - dprintk(NDEBUG_EXTENDED, ("scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2])); - - if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) { - /* Accept third byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - len = extended_msg[1] - 1; - data = extended_msg + 3; - phase = PHASE_MSGIN; - - NCR5380_transfer_pio(instance, &phase, &len, &data); - dprintk(NDEBUG_EXTENDED, ("scsi%d : message received, residual %d\n", instance->host_no, len)); - - switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; - } - } else if (len) { - printk("scsi%d: error receiving extended message\n", instance->host_no); - tmp = 0; - } else { - printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]); - tmp = 0; - } - /* Fall through to reject message */ - - /* - * If we get something weird that we aren't expecting, - * reject it. - */ - default: - if (!tmp) { - printk("scsi%d: rejecting message ", instance->host_no); - spi_print_msg(extended_msg); - printk("\n"); - } else if (tmp != EXTENDED_MESSAGE) - scmd_printk(KERN_INFO, cmd, - "rejecting unknown message %02x\n",tmp); - else - scmd_printk(KERN_INFO, cmd, - "rejecting unknown extended message code %02x, length %d\n", extended_msg[1], extended_msg[0]); - - msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - break; - } /* switch (tmp) */ - break; - case PHASE_MSGOUT: - len = 1; - data = &msgout; - hostdata->last_message = msgout; - NCR5380_transfer_pio(instance, &phase, &len, &data); - if (msgout == ABORT) { - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->connected = NULL; - cmd->result = DID_ERROR << 16; - collect_stats(hostdata, cmd); - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return; - } - msgout = NOP; - break; - case PHASE_CMDOUT: - len = cmd->cmd_len; - data = cmd->cmnd; - /* - * XXX for performance reasons, on machines with a - * PSEUDO-DMA architecture we should probably - * use the dma transfer function. - */ - NCR5380_transfer_pio(instance, &phase, &len, &data); - if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) { - NCR5380_set_timer(hostdata, USLEEP_SLEEP); - dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); - return; - } - break; - case PHASE_STATIN: - len = 1; - data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Status = tmp; - break; - default: - printk("scsi%d : unknown phase\n", instance->host_no); - NCR5380_dprint(NDEBUG_ALL, instance); - } /* switch(phase) */ - } /* if (tmp * SR_REQ) */ - else { - /* RvC: go to sleep if polling time expired - */ - if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) { - NCR5380_set_timer(hostdata, USLEEP_SLEEP); - dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires)); - return; - } - } - } /* while (1) */ -} - -/* - * Function : void NCR5380_reselect (struct Scsi_Host *instance) - * - * Purpose : does reselection, initializing the instance->connected - * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q - * nexus has been reestablished, - * - * Inputs : instance - this instance of the NCR5380. - * - * Locks: io_request_lock held by caller if IRQ driven - */ - -static void NCR5380_reselect(struct Scsi_Host *instance) { - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) - instance->hostdata; - unsigned char target_mask; - unsigned char lun, phase; - int len; - unsigned char msg[3]; - unsigned char *data; - Scsi_Cmnd *tmp = NULL, *prev; - int abort = 0; - NCR5380_setup(instance); - - /* - * Disable arbitration, etc. since the host adapter obviously - * lost, and tell an interrupted NCR5380_select() to restart. - */ - - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); - dprintk(NDEBUG_SELECTION, ("scsi%d : reselect\n", instance->host_no)); - - /* - * At this point, we have detected that our SCSI ID is on the bus, - * SEL is true and BSY was false for at least one bus settle delay - * (400 ns). - * - * We must assert BSY ourselves, until the target drops the SEL - * signal. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); - - /* FIXME: timeout too long, must fail to workqueue */ - if(NCR5380_poll_politely(instance, STATUS_REG, SR_SEL, 0, 2*HZ)<0) - abort = 1; - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - /* - * Wait for target to go into MSGIN. - * FIXME: timeout needed and fail to work queeu - */ - - if(NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 2*HZ)) - abort = 1; - - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - - if (!(msg[0] & 0x80)) { - printk(KERN_ERR "scsi%d : expecting IDENTIFY message, got ", instance->host_no); - spi_print_msg(msg); - abort = 1; - } else { - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - lun = (msg[0] & 0x07); - - /* - * We need to add code for SCSI-II to track which devices have - * I_T_L_Q nexuses established, and which have simple I_T_L - * nexuses so we can chose to do additional data transfer. - */ - - /* - * Find the command corresponding to the I_T_L or I_T_L_Q nexus we - * just reestablished, and remove it from the disconnected queue. - */ - - - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) - if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) - ) { - if (prev) { - REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble); - prev->host_scribble = tmp->host_scribble; - } else { - REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble); - hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble; - } - tmp->host_scribble = NULL; - break; - } - if (!tmp) { - printk(KERN_ERR "scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun); - /* - * Since we have an established nexus that we can't do anything with, - * we must abort it. - */ - abort = 1; - } - } - - if (abort) { - do_abort(instance); - } else { - hostdata->connected = tmp; - dprintk(NDEBUG_RESELECTION, ("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", instance->host_no, tmp->target, tmp->lun, tmp->tag)); - } -} - -/* - * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) - * - * Purpose : called by interrupt handler when DMA finishes or a phase - * mismatch occurs (which would finish the DMA transfer). - * - * Inputs : instance - this instance of the NCR5380. - * - * Returns : pointer to the Scsi_Cmnd structure for which the I_T_L - * nexus has been reestablished, on failure NULL is returned. - */ - -#ifdef REAL_DMA -static void NCR5380_dma_complete(NCR5380_instance * instance) { - NCR5380_local_declare(); - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - int transferred; - NCR5380_setup(instance); - - /* - * XXX this might not be right. - * - * Wait for final byte to transfer, ie wait for ACK to go false. - * - * We should use the Last Byte Sent bit, unfortunately this is - * not available on the 5380/5381 (only the various CMOS chips) - * - * FIXME: timeout, and need to handle long timeout/irq case - */ - - NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ); - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - /* - * The only places we should see a phase mismatch and have to send - * data from the same set of pointers will be the data transfer - * phases. So, residual, requested length are only important here. - */ - - if (!(hostdata->connected->SCp.phase & SR_CD)) { - transferred = instance->dmalen - NCR5380_dma_residual(); - hostdata->connected->SCp.this_residual -= transferred; - hostdata->connected->SCp.ptr += transferred; - } -} -#endif /* def REAL_DMA */ - -/* - * Function : int NCR5380_abort (Scsi_Cmnd *cmd) - * - * Purpose : abort a command - * - * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the - * host byte of the result field to, if zero DID_ABORTED is - * used. - * - * Returns : 0 - success, -1 on failure. - * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is - * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). - * - * Locks: host lock taken by caller - */ - -static int NCR5380_abort(Scsi_Cmnd * cmd) { - NCR5380_local_declare(); - struct Scsi_Host *instance = cmd->device->host; - struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata; - Scsi_Cmnd *tmp, **prev; - - printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no); - scsi_print_command(cmd); - - NCR5380_print_status(instance); - - NCR5380_setup(instance); - - dprintk(NDEBUG_ABORT, ("scsi%d : abort called\n", instance->host_no)); - dprintk(NDEBUG_ABORT, (" basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG))); - -#if 0 -/* - * Case 1 : If the command is the currently executing command, - * we'll set the aborted flag and return control so that - * information transfer routine can exit cleanly. - */ - - if (hostdata->connected == cmd) { - dprintk(NDEBUG_ABORT, ("scsi%d : aborting connected command\n", instance->host_no)); - hostdata->aborted = 1; -/* - * We should perform BSY checking, and make sure we haven't slipped - * into BUS FREE. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); -/* - * Since we can't change phases until we've completed the current - * handshake, we have to source or sink a byte of data if the current - * phase is not MSGOUT. - */ - -/* - * Return control to the executing NCR drive so we can clear the - * aborted flag and get back into our main loop. - */ - - return 0; - } -#endif - -/* - * Case 2 : If the command hasn't been issued yet, we simply remove it - * from the issue queue. - */ - - dprintk(NDEBUG_ABORT, ("scsi%d : abort going into loop.\n", instance->host_no)); - for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) - if (cmd == tmp) { - REMOVE(5, *prev, tmp, tmp->host_scribble); - (*prev) = (Scsi_Cmnd *) tmp->host_scribble; - tmp->host_scribble = NULL; - tmp->result = DID_ABORT << 16; - dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no)); - tmp->scsi_done(tmp); - return SUCCESS; - } -#if (NDEBUG & NDEBUG_ABORT) - /* KLL */ - else if (prev == tmp) - printk(KERN_ERR "scsi%d : LOOP\n", instance->host_no); -#endif - -/* - * Case 3 : If any commands are connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. - * - * Timeouts, and therefore aborted commands, will be highly unlikely - * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. - */ - - if (hostdata->connected) { - dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no)); - return FAILED; - } -/* - * Case 4: If the command is currently disconnected from the bus, and - * there are no connected commands, we reconnect the I_T_L or - * I_T_L_Q nexus associated with it, go into message out, and send - * an abort message. - * - * This case is especially ugly. In order to reestablish the nexus, we - * need to call NCR5380_select(). The easiest way to implement this - * function was to abort if the bus was busy, and let the interrupt - * handler triggered on the SEL for reselect take care of lost arbitrations - * where necessary, meaning interrupts need to be enabled. - * - * When interrupts are enabled, the queues may change - so we - * can't remove it from the disconnected queue before selecting it - * because that could cause a failure in hashing the nexus if that - * device reselected. - * - * Since the queues may change, we can't use the pointers from when we - * first locate it. - * - * So, we must first locate the command, and if NCR5380_select() - * succeeds, then issue the abort, relocate the command and remove - * it from the disconnected queue. - */ - - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble) - if (cmd == tmp) { - dprintk(NDEBUG_ABORT, ("scsi%d : aborting disconnected command.\n", instance->host_no)); - - if (NCR5380_select(instance, cmd, (int) cmd->tag)) - return FAILED; - dprintk(NDEBUG_ABORT, ("scsi%d : nexus reestablished.\n", instance->host_no)); - - do_abort(instance); - - for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble) - if (cmd == tmp) { - REMOVE(5, *prev, tmp, tmp->host_scribble); - *prev = (Scsi_Cmnd *) tmp->host_scribble; - tmp->host_scribble = NULL; - tmp->result = DID_ABORT << 16; - tmp->scsi_done(tmp); - return SUCCESS; - } - } -/* - * Case 5 : If we reached this point, the command was not found in any of - * the queues. - * - * We probably reached this point because of an unlikely race condition - * between the command completing successfully and the abortion code, - * so we won't panic, but we will notify the user in case something really - * broke. - */ - printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n" - " before abortion\n", instance->host_no); - return FAILED; -} - - -/* - * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd) - * - * Purpose : reset the SCSI bus. - * - * Returns : SUCCESS - * - * Locks: host lock taken by caller - */ - -static int NCR5380_bus_reset(Scsi_Cmnd * cmd) -{ - struct Scsi_Host *instance = cmd->device->host; - - NCR5380_local_declare(); - NCR5380_setup(instance); - NCR5380_print_status(instance); - - spin_lock_irq(instance->host_lock); - do_reset(instance); - spin_unlock_irq(instance->host_lock); - - return SUCCESS; -} diff --git a/ANDROID_3.4.5/drivers/scsi/NCR5380.h b/ANDROID_3.4.5/drivers/scsi/NCR5380.h deleted file mode 100644 index fd40a32b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/NCR5380.h +++ /dev/null @@ -1,437 +0,0 @@ -/* - * NCR 5380 defines - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 - * - * DISTRIBUTION RELEASE 7 - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * $Log: NCR5380.h,v $ - */ - -#ifndef NCR5380_H -#define NCR5380_H - -#include - -#ifdef AUTOSENSE -#include -#endif - -#define NCR5380_PUBLIC_RELEASE 7 -#define NCR53C400_PUBLIC_RELEASE 2 - -#define NDEBUG_ARBITRATION 0x1 -#define NDEBUG_AUTOSENSE 0x2 -#define NDEBUG_DMA 0x4 -#define NDEBUG_HANDSHAKE 0x8 -#define NDEBUG_INFORMATION 0x10 -#define NDEBUG_INIT 0x20 -#define NDEBUG_INTR 0x40 -#define NDEBUG_LINKED 0x80 -#define NDEBUG_MAIN 0x100 -#define NDEBUG_NO_DATAOUT 0x200 -#define NDEBUG_NO_WRITE 0x400 -#define NDEBUG_PIO 0x800 -#define NDEBUG_PSEUDO_DMA 0x1000 -#define NDEBUG_QUEUES 0x2000 -#define NDEBUG_RESELECTION 0x4000 -#define NDEBUG_SELECTION 0x8000 -#define NDEBUG_USLEEP 0x10000 -#define NDEBUG_LAST_BYTE_SENT 0x20000 -#define NDEBUG_RESTART_SELECT 0x40000 -#define NDEBUG_EXTENDED 0x80000 -#define NDEBUG_C400_PREAD 0x100000 -#define NDEBUG_C400_PWRITE 0x200000 -#define NDEBUG_LISTS 0x400000 - -#define NDEBUG_ANY 0xFFFFFFFFUL - -/* - * The contents of the OUTPUT DATA register are asserted on the bus when - * either arbitration is occurring or the phase-indicating signals ( - * IO, CD, MSG) in the TARGET COMMAND register and the ASSERT DATA - * bit in the INITIATOR COMMAND register is set. - */ - -#define OUTPUT_DATA_REG 0 /* wo DATA lines on SCSI bus */ -#define CURRENT_SCSI_DATA_REG 0 /* ro same */ - -#define INITIATOR_COMMAND_REG 1 /* rw */ -#define ICR_ASSERT_RST 0x80 /* rw Set to assert RST */ -#define ICR_ARBITRATION_PROGRESS 0x40 /* ro Indicates arbitration complete */ -#define ICR_TRI_STATE 0x40 /* wo Set to tri-state drivers */ -#define ICR_ARBITRATION_LOST 0x20 /* ro Indicates arbitration lost */ -#define ICR_DIFF_ENABLE 0x20 /* wo Set to enable diff. drivers */ -#define ICR_ASSERT_ACK 0x10 /* rw ini Set to assert ACK */ -#define ICR_ASSERT_BSY 0x08 /* rw Set to assert BSY */ -#define ICR_ASSERT_SEL 0x04 /* rw Set to assert SEL */ -#define ICR_ASSERT_ATN 0x02 /* rw Set to assert ATN */ -#define ICR_ASSERT_DATA 0x01 /* rw SCSI_DATA_REG is asserted */ - -#ifdef DIFFERENTIAL -#define ICR_BASE ICR_DIFF_ENABLE -#else -#define ICR_BASE 0 -#endif - -#define MODE_REG 2 -/* - * Note : BLOCK_DMA code will keep DRQ asserted for the duration of the - * transfer, causing the chip to hog the bus. You probably don't want - * this. - */ -#define MR_BLOCK_DMA_MODE 0x80 /* rw block mode DMA */ -#define MR_TARGET 0x40 /* rw target mode */ -#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */ -#define MR_ENABLE_PAR_INTR 0x10 /* rw enable bad parity interrupt */ -#define MR_ENABLE_EOP_INTR 0x08 /* rw enable eop interrupt */ -#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */ -#define MR_DMA_MODE 0x02 /* rw DMA / pseudo DMA mode */ -#define MR_ARBITRATE 0x01 /* rw start arbitration */ - -#ifdef PARITY -#define MR_BASE MR_ENABLE_PAR_CHECK -#else -#define MR_BASE 0 -#endif - -#define TARGET_COMMAND_REG 3 -#define TCR_LAST_BYTE_SENT 0x80 /* ro DMA done */ -#define TCR_ASSERT_REQ 0x08 /* tgt rw assert REQ */ -#define TCR_ASSERT_MSG 0x04 /* tgt rw assert MSG */ -#define TCR_ASSERT_CD 0x02 /* tgt rw assert CD */ -#define TCR_ASSERT_IO 0x01 /* tgt rw assert IO */ - -#define STATUS_REG 4 /* ro */ -/* - * Note : a set bit indicates an active signal, driven by us or another - * device. - */ -#define SR_RST 0x80 -#define SR_BSY 0x40 -#define SR_REQ 0x20 -#define SR_MSG 0x10 -#define SR_CD 0x08 -#define SR_IO 0x04 -#define SR_SEL 0x02 -#define SR_DBP 0x01 - -/* - * Setting a bit in this register will cause an interrupt to be generated when - * BSY is false and SEL true and this bit is asserted on the bus. - */ -#define SELECT_ENABLE_REG 4 /* wo */ - -#define BUS_AND_STATUS_REG 5 /* ro */ -#define BASR_END_DMA_TRANSFER 0x80 /* ro set on end of transfer */ -#define BASR_DRQ 0x40 /* ro mirror of DRQ pin */ -#define BASR_PARITY_ERROR 0x20 /* ro parity error detected */ -#define BASR_IRQ 0x10 /* ro mirror of IRQ pin */ -#define BASR_PHASE_MATCH 0x08 /* ro Set when MSG CD IO match TCR */ -#define BASR_BUSY_ERROR 0x04 /* ro Unexpected change to inactive state */ -#define BASR_ATN 0x02 /* ro BUS status */ -#define BASR_ACK 0x01 /* ro BUS status */ - -/* Write any value to this register to start a DMA send */ -#define START_DMA_SEND_REG 5 /* wo */ - -/* - * Used in DMA transfer mode, data is latched from the SCSI bus on - * the falling edge of REQ (ini) or ACK (tgt) - */ -#define INPUT_DATA_REG 6 /* ro */ - -/* Write any value to this register to start a DMA receive */ -#define START_DMA_TARGET_RECEIVE_REG 6 /* wo */ - -/* Read this register to clear interrupt conditions */ -#define RESET_PARITY_INTERRUPT_REG 7 /* ro */ - -/* Write any value to this register to start an ini mode DMA receive */ -#define START_DMA_INITIATOR_RECEIVE_REG 7 /* wo */ - -#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8 /* rw */ - -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_53C80_REG 0x80 /* ro 5380 registers busy */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_53C80_INTR 0x10 /* rw Enable 53c80 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Is Host buffer ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer read */ -#define CSR_GATED_53C80_IRQ 0x01 /* ro Last block xferred */ - -#if 0 -#define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR -#else -#define CSR_BASE CSR_53C80_INTR -#endif - -/* Number of 128-byte blocks to be transferred */ -#define C400_BLOCK_COUNTER_REG NCR53C400_register_offset-7 /* rw */ - -/* Resume transfer after disconnect */ -#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6 /* wo */ - -/* Access to host buffer stack */ -#define C400_HOST_BUFFER NCR53C400_register_offset-4 /* rw */ - - -/* Note : PHASE_* macros are based on the values of the STATUS register */ -#define PHASE_MASK (SR_MSG | SR_CD | SR_IO) - -#define PHASE_DATAOUT 0 -#define PHASE_DATAIN SR_IO -#define PHASE_CMDOUT SR_CD -#define PHASE_STATIN (SR_CD | SR_IO) -#define PHASE_MSGOUT (SR_MSG | SR_CD) -#define PHASE_MSGIN (SR_MSG | SR_CD | SR_IO) -#define PHASE_UNKNOWN 0xff - -/* - * Convert status register phase to something we can use to set phase in - * the target register so we can get phase mismatch interrupts on DMA - * transfers. - */ - -#define PHASE_SR_TO_TCR(phase) ((phase) >> 2) - -/* - * The internal should_disconnect() function returns these based on the - * expected length of a disconnect if a device supports disconnect/ - * reconnect. - */ - -#define DISCONNECT_NONE 0 -#define DISCONNECT_TIME_TO_DATA 1 -#define DISCONNECT_LONG 2 - -/* - * These are "special" values for the tag parameter passed to NCR5380_select. - */ - -#define TAG_NEXT -1 /* Use next free tag */ -#define TAG_NONE -2 /* - * Establish I_T_L nexus instead of I_T_L_Q - * even on SCSI-II devices. - */ - -/* - * These are "special" values for the irq and dma_channel fields of the - * Scsi_Host structure - */ - -#define SCSI_IRQ_NONE 255 -#define DMA_NONE 255 -#define IRQ_AUTO 254 -#define DMA_AUTO 254 -#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ - -#define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */ -#define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */ -#define FLAG_NCR53C400 4 /* NCR53c400 */ -#define FLAG_NO_PSEUDO_DMA 8 /* Inhibit DMA */ -#define FLAG_DTC3181E 16 /* DTC3181E */ - -#ifndef ASM -struct NCR5380_hostdata { - NCR5380_implementation_fields; /* implementation specific */ - struct Scsi_Host *host; /* Host backpointer */ - unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */ - unsigned char targets_present; /* targets we have connected - to, so we can call a select - failure a retryable condition */ - volatile unsigned char busy[8]; /* index = target, bit = lun */ -#if defined(REAL_DMA) || defined(REAL_DMA_POLL) - volatile int dma_len; /* requested length of DMA */ -#endif - volatile unsigned char last_message; /* last message OUT */ - volatile Scsi_Cmnd *connected; /* currently connected command */ - volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */ - volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */ - volatile int restart_select; /* we have disconnected, - used to restart - NCR5380_select() */ - volatile unsigned aborted:1; /* flag, says aborted */ - int flags; - unsigned long time_expires; /* in jiffies, set prior to sleeping */ - int select_time; /* timer in select for target response */ - volatile Scsi_Cmnd *selecting; - struct delayed_work coroutine; /* our co-routine */ -#ifdef NCR5380_STATS - unsigned timebase; /* Base for time calcs */ - long time_read[8]; /* time to do reads */ - long time_write[8]; /* time to do writes */ - unsigned long bytes_read[8]; /* bytes read */ - unsigned long bytes_write[8]; /* bytes written */ - unsigned pendingr; - unsigned pendingw; -#endif -#ifdef AUTOSENSE - struct scsi_eh_save ses; -#endif -}; - -#ifdef __KERNEL__ - -#define dprintk(a,b) do {} while(0) -#define NCR5380_dprint(a,b) do {} while(0) -#define NCR5380_dprint_phase(a,b) do {} while(0) - -#if defined(AUTOPROBE_IRQ) -static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); -#endif -static int NCR5380_init(struct Scsi_Host *instance, int flags); -static void NCR5380_exit(struct Scsi_Host *instance); -static void NCR5380_information_transfer(struct Scsi_Host *instance); -#ifndef DONT_USE_INTR -static irqreturn_t NCR5380_intr(int irq, void *dev_id); -#endif -static void NCR5380_main(struct work_struct *work); -static void __maybe_unused NCR5380_print_options(struct Scsi_Host *instance); -#ifdef NDEBUG -static void NCR5380_print_phase(struct Scsi_Host *instance); -static void NCR5380_print(struct Scsi_Host *instance); -#endif -static int NCR5380_abort(Scsi_Cmnd * cmd); -static int NCR5380_bus_reset(Scsi_Cmnd * cmd); -static int NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static int __maybe_unused NCR5380_proc_info(struct Scsi_Host *instance, - char *buffer, char **start, off_t offset, int length, int inout); - -static void NCR5380_reselect(struct Scsi_Host *instance); -static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag); -#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL) -static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); -#endif -static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data); - -#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) - -#if defined(i386) || defined(__alpha__) - -/** - * NCR5380_pc_dma_setup - setup ISA DMA - * @instance: adapter to set up - * @ptr: block to transfer (virtual address) - * @count: number of bytes to transfer - * @mode: DMA controller mode to use - * - * Program the DMA controller ready to perform an ISA DMA transfer - * on this chip. - * - * Locks: takes and releases the ISA DMA lock. - */ - -static __inline__ int NCR5380_pc_dma_setup(struct Scsi_Host *instance, unsigned char *ptr, unsigned int count, unsigned char mode) -{ - unsigned limit; - unsigned long bus_addr = virt_to_bus(ptr); - unsigned long flags; - - if (instance->dma_channel <= 3) { - if (count > 65536) - count = 65536; - limit = 65536 - (bus_addr & 0xFFFF); - } else { - if (count > 65536 * 2) - count = 65536 * 2; - limit = 65536 * 2 - (bus_addr & 0x1FFFF); - } - - if (count > limit) - count = limit; - - if ((count & 1) || (bus_addr & 1)) - panic("scsi%d : attempted unaligned DMA transfer\n", instance->host_no); - - flags=claim_dma_lock(); - disable_dma(instance->dma_channel); - clear_dma_ff(instance->dma_channel); - set_dma_addr(instance->dma_channel, bus_addr); - set_dma_count(instance->dma_channel, count); - set_dma_mode(instance->dma_channel, mode); - enable_dma(instance->dma_channel); - release_dma_lock(flags); - - return count; -} - -/** - * NCR5380_pc_dma_write_setup - setup ISA DMA write - * @instance: adapter to set up - * @ptr: block to transfer (virtual address) - * @count: number of bytes to transfer - * - * Program the DMA controller ready to perform an ISA DMA write to the - * SCSI controller. - * - * Locks: called routines take and release the ISA DMA lock. - */ - -static __inline__ int NCR5380_pc_dma_write_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) -{ - return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_WRITE); -} - -/** - * NCR5380_pc_dma_read_setup - setup ISA DMA read - * @instance: adapter to set up - * @ptr: block to transfer (virtual address) - * @count: number of bytes to transfer - * - * Program the DMA controller ready to perform an ISA DMA read from the - * SCSI controller. - * - * Locks: called routines take and release the ISA DMA lock. - */ - -static __inline__ int NCR5380_pc_dma_read_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count) -{ - return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_READ); -} - -/** - * NCR5380_pc_dma_residual - return bytes left - * @instance: adapter - * - * Reports the number of bytes left over after the DMA was terminated. - * - * Locks: takes and releases the ISA DMA lock. - */ - -static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance) -{ - unsigned long flags; - int tmp; - - flags = claim_dma_lock(); - clear_dma_ff(instance->dma_channel); - tmp = get_dma_residue(instance->dma_channel); - release_dma_lock(flags); - - return tmp; -} -#endif /* defined(i386) || defined(__alpha__) */ -#endif /* defined(REAL_DMA) */ -#endif /* __KERNEL__ */ -#endif /* ndef ASM */ -#endif /* NCR5380_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/NCR53c406a.c b/ANDROID_3.4.5/drivers/scsi/NCR53c406a.c deleted file mode 100644 index c91888a0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/NCR53c406a.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * NCR53c406.c - * Low-level SCSI driver for NCR53c406a chip. - * Copyright (C) 1994, 1995, 1996 Normunds Saumanis (normunds@fi.ibm.com) - * - * LILO command line usage: ncr53c406a=[,[,]] - * Specify IRQ = 0 for non-interrupt driven mode. - * FASTPIO = 1 for fast pio mode, 0 for slow mode. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#define NCR53C406A_DEBUG 0 -#define VERBOSE_NCR53C406A_DEBUG 0 - -/* Set this to 1 for PIO mode (recommended) or to 0 for DMA mode */ -#define USE_PIO 1 - -#define USE_BIOS 0 - /* #define BIOS_ADDR 0xD8000 *//* define this if autoprobe fails */ - /* #define PORT_BASE 0x330 *//* define this if autoprobe fails */ - /* #define IRQ_LEV 0 *//* define this if autoprobe fails */ -#define DMA_CHAN 5 /* this is ignored if DMA is disabled */ - -/* Set this to 0 if you encounter kernel lockups while transferring - * data in PIO mode */ -#define USE_FAST_PIO 1 - -/* ============= End of user configurable parameters ============= */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "scsi.h" -#include - -/* ============================================================= */ - -#define WATCHDOG 5000000 - -#define SYNC_MODE 0 /* Synchronous transfer mode */ - -#ifdef DEBUG -#undef NCR53C406A_DEBUG -#define NCR53C406A_DEBUG 1 -#endif - -#if USE_PIO -#define USE_DMA 0 -#else -#define USE_DMA 1 -#endif - -/* Default configuration */ -#define C1_IMG 0x07 /* ID=7 */ -#define C2_IMG 0x48 /* FE SCSI2 */ -#if USE_DMA -#define C3_IMG 0x21 /* CDB TE */ -#else -#define C3_IMG 0x20 /* CDB */ -#endif -#define C4_IMG 0x04 /* ANE */ -#define C5_IMG 0xb6 /* AA PI SIE POL */ - -#define REG0 (outb(C4_IMG, CONFIG4)) -#define REG1 (outb(C5_IMG, CONFIG5)) - -#if NCR53C406A_DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - -#if VERBOSE_NCR53C406A_DEBUG -#define VDEB(x) x -#else -#define VDEB(x) -#endif - -#define LOAD_DMA_COUNT(count) \ - outb(count & 0xff, TC_LSB); \ - outb((count >> 8) & 0xff, TC_MSB); \ - outb((count >> 16) & 0xff, TC_HIGH); - -/* Chip commands */ -#define DMA_OP 0x80 - -#define SCSI_NOP 0x00 -#define FLUSH_FIFO 0x01 -#define CHIP_RESET 0x02 -#define SCSI_RESET 0x03 -#define RESELECT 0x40 -#define SELECT_NO_ATN 0x41 -#define SELECT_ATN 0x42 -#define SELECT_ATN_STOP 0x43 -#define ENABLE_SEL 0x44 -#define DISABLE_SEL 0x45 -#define SELECT_ATN3 0x46 -#define RESELECT3 0x47 -#define TRANSFER_INFO 0x10 -#define INIT_CMD_COMPLETE 0x11 -#define MSG_ACCEPT 0x12 -#define TRANSFER_PAD 0x18 -#define SET_ATN 0x1a -#define RESET_ATN 0x1b -#define SEND_MSG 0x20 -#define SEND_STATUS 0x21 -#define SEND_DATA 0x22 -#define DISCONN_SEQ 0x23 -#define TERMINATE_SEQ 0x24 -#define TARG_CMD_COMPLETE 0x25 -#define DISCONN 0x27 -#define RECV_MSG 0x28 -#define RECV_CMD 0x29 -#define RECV_DATA 0x2a -#define RECV_CMD_SEQ 0x2b -#define TARGET_ABORT_DMA 0x04 - -/*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at */ -/* 1 = blue - 2 = green - 3 = cyan - 4 = red - 5 = magenta - 6 = yellow - 7 = white -*/ - -#if NCR53C406A_DEBUG -#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);} -#else -#define rtrc(i) {} -#endif -/*----------------------------------------------------------------*/ - -enum Phase { - idle, - data_out, - data_in, - command_ph, - status_ph, - message_out, - message_in -}; - -/* Static function prototypes */ -static void NCR53c406a_intr(void *); -static irqreturn_t do_NCR53c406a_intr(int, void *); -static void chip_init(void); -static void calc_port_addr(void); -#ifndef IRQ_LEV -static int irq_probe(void); -#endif - -/* ================================================================= */ - -#if USE_BIOS -static void *bios_base; -#endif - -#ifdef PORT_BASE -static int port_base = PORT_BASE; -#else -static int port_base; -#endif - -#ifdef IRQ_LEV -static int irq_level = IRQ_LEV; -#else -static int irq_level = -1; /* 0 is 'no irq', so use -1 for 'uninitialized' */ -#endif - -#if USE_DMA -static int dma_chan; -#endif - -#if USE_PIO -static int fast_pio = USE_FAST_PIO; -#endif - -static Scsi_Cmnd *current_SC; -static char info_msg[256]; - -/* ================================================================= */ - -/* possible BIOS locations */ -#if USE_BIOS -static void *addresses[] = { - (void *) 0xd8000, - (void *) 0xc8000 -}; -#define ADDRESS_COUNT ARRAY_SIZE(addresses) -#endif /* USE_BIOS */ - -/* possible i/o port addresses */ -static unsigned short ports[] = { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 }; -#define PORT_COUNT ARRAY_SIZE(ports) - -#ifndef MODULE -/* possible interrupt channels */ -static unsigned short intrs[] = { 10, 11, 12, 15 }; -#define INTR_COUNT ARRAY_SIZE(intrs) -#endif /* !MODULE */ - -/* signatures for NCR 53c406a based controllers */ -#if USE_BIOS -struct signature { - char *signature; - int sig_offset; - int sig_length; -} signatures[] __initdata = { - /* 1 2 3 4 5 6 */ - /* 123456789012345678901234567890123456789012345678901234567890 */ - { -"Copyright (C) Acculogic, Inc.\r\n2.8M Diskette Extension Bios ver 4.04.03 03/01/1993", 61, 82},}; - -#define SIGNATURE_COUNT ARRAY_SIZE(signatures) -#endif /* USE_BIOS */ - -/* ============================================================ */ - -/* Control Register Set 0 */ -static int TC_LSB; /* transfer counter lsb */ -static int TC_MSB; /* transfer counter msb */ -static int SCSI_FIFO; /* scsi fifo register */ -static int CMD_REG; /* command register */ -static int STAT_REG; /* status register */ -static int DEST_ID; /* selection/reselection bus id */ -static int INT_REG; /* interrupt status register */ -static int SRTIMOUT; /* select/reselect timeout reg */ -static int SEQ_REG; /* sequence step register */ -static int SYNCPRD; /* synchronous transfer period */ -static int FIFO_FLAGS; /* indicates # of bytes in fifo */ -static int SYNCOFF; /* synchronous offset register */ -static int CONFIG1; /* configuration register */ -static int CLKCONV; /* clock conversion reg */ - /*static int TESTREG;*//* test mode register */ -static int CONFIG2; /* Configuration 2 Register */ -static int CONFIG3; /* Configuration 3 Register */ -static int CONFIG4; /* Configuration 4 Register */ -static int TC_HIGH; /* Transfer Counter High */ - /*static int FIFO_BOTTOM;*//* Reserve FIFO byte register */ - -/* Control Register Set 1 */ - /*static int JUMPER_SENSE;*//* Jumper sense port reg (r/w) */ - /*static int SRAM_PTR;*//* SRAM address pointer reg (r/w) */ - /*static int SRAM_DATA;*//* SRAM data register (r/w) */ -static int PIO_FIFO; /* PIO FIFO registers (r/w) */ - /*static int PIO_FIFO1;*//* */ - /*static int PIO_FIFO2;*//* */ - /*static int PIO_FIFO3;*//* */ -static int PIO_STATUS; /* PIO status (r/w) */ - /*static int ATA_CMD;*//* ATA command/status reg (r/w) */ - /*static int ATA_ERR;*//* ATA features/error register (r/w) */ -static int PIO_FLAG; /* PIO flag interrupt enable (r/w) */ -static int CONFIG5; /* Configuration 5 register (r/w) */ - /*static int SIGNATURE;*//* Signature Register (r) */ - /*static int CONFIG6;*//* Configuration 6 register (r) */ - -/* ============================================================== */ - -#if USE_DMA -static __inline__ int NCR53c406a_dma_setup(unsigned char *ptr, unsigned int count, unsigned char mode) -{ - unsigned limit; - unsigned long flags = 0; - - VDEB(printk("dma: before count=%d ", count)); - if (dma_chan <= 3) { - if (count > 65536) - count = 65536; - limit = 65536 - (((unsigned) ptr) & 0xFFFF); - } else { - if (count > (65536 << 1)) - count = (65536 << 1); - limit = (65536 << 1) - (((unsigned) ptr) & 0x1FFFF); - } - - if (count > limit) - count = limit; - - VDEB(printk("after count=%d\n", count)); - if ((count & 1) || (((unsigned) ptr) & 1)) - panic("NCR53c406a: attempted unaligned DMA transfer\n"); - - flags = claim_dma_lock(); - disable_dma(dma_chan); - clear_dma_ff(dma_chan); - set_dma_addr(dma_chan, (long) ptr); - set_dma_count(dma_chan, count); - set_dma_mode(dma_chan, mode); - enable_dma(dma_chan); - release_dma_lock(flags); - - return count; -} - -static __inline__ int NCR53c406a_dma_write(unsigned char *src, unsigned int count) -{ - return NCR53c406a_dma_setup(src, count, DMA_MODE_WRITE); -} - -static __inline__ int NCR53c406a_dma_read(unsigned char *src, unsigned int count) -{ - return NCR53c406a_dma_setup(src, count, DMA_MODE_READ); -} - -static __inline__ int NCR53c406a_dma_residual(void) -{ - register int tmp; - unsigned long flags; - - flags = claim_dma_lock(); - clear_dma_ff(dma_chan); - tmp = get_dma_residue(dma_chan); - release_dma_lock(flags); - - return tmp; -} -#endif /* USE_DMA */ - -#if USE_PIO -static __inline__ int NCR53c406a_pio_read(unsigned char *request, unsigned int reqlen) -{ - int i; - int len; /* current scsi fifo size */ - - REG1; - while (reqlen) { - i = inb(PIO_STATUS); - /* VDEB(printk("pio_status=%x\n", i)); */ - if (i & 0x80) - return 0; - - switch (i & 0x1e) { - default: - case 0x10: - len = 0; - break; - case 0x0: - len = 1; - break; - case 0x8: - len = 42; - break; - case 0xc: - len = 84; - break; - case 0xe: - len = 128; - break; - } - - if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */ - return 0; - } - - if (len) { - if (len > reqlen) - len = reqlen; - - if (fast_pio && len > 3) { - insl(PIO_FIFO, request, len >> 2); - request += len & 0xfc; - reqlen -= len & 0xfc; - } else { - while (len--) { - *request++ = inb(PIO_FIFO); - reqlen--; - } - } - } - } - return 0; -} - -static __inline__ int NCR53c406a_pio_write(unsigned char *request, unsigned int reqlen) -{ - int i = 0; - int len; /* current scsi fifo size */ - - REG1; - while (reqlen && !(i & 0x40)) { - i = inb(PIO_STATUS); - /* VDEB(printk("pio_status=%x\n", i)); */ - if (i & 0x80) /* error */ - return 0; - - switch (i & 0x1e) { - case 0x10: - len = 128; - break; - case 0x0: - len = 84; - break; - case 0x8: - len = 42; - break; - case 0xc: - len = 1; - break; - default: - case 0xe: - len = 0; - break; - } - - if (len) { - if (len > reqlen) - len = reqlen; - - if (fast_pio && len > 3) { - outsl(PIO_FIFO, request, len >> 2); - request += len & 0xfc; - reqlen -= len & 0xfc; - } else { - while (len--) { - outb(*request++, PIO_FIFO); - reqlen--; - } - } - } - } - return 0; -} -#endif /* USE_PIO */ - -static int __init NCR53c406a_detect(struct scsi_host_template * tpnt) -{ - int present = 0; - struct Scsi_Host *shpnt = NULL; -#ifndef PORT_BASE - int i; -#endif - -#if USE_BIOS - int ii, jj; - bios_base = 0; - /* look for a valid signature */ - for (ii = 0; ii < ADDRESS_COUNT && !bios_base; ii++) - for (jj = 0; (jj < SIGNATURE_COUNT) && !bios_base; jj++) - if (!memcmp((void *) addresses[ii] + signatures[jj].sig_offset, (void *) signatures[jj].signature, (int) signatures[jj].sig_length)) - bios_base = addresses[ii]; - - if (!bios_base) { - printk("NCR53c406a: BIOS signature not found\n"); - return 0; - } - - DEB(printk("NCR53c406a BIOS found at 0x%x\n", (unsigned int) bios_base); - ); -#endif /* USE_BIOS */ - -#ifdef PORT_BASE - if (!request_region(port_base, 0x10, "NCR53c406a")) /* ports already snatched */ - port_base = 0; - -#else /* autodetect */ - if (port_base) { /* LILO override */ - if (!request_region(port_base, 0x10, "NCR53c406a")) - port_base = 0; - } else { - for (i = 0; i < PORT_COUNT && !port_base; i++) { - if (!request_region(ports[i], 0x10, "NCR53c406a")) { - DEB(printk("NCR53c406a: port 0x%x in use\n", ports[i])); - } else { - VDEB(printk("NCR53c406a: port 0x%x available\n", ports[i])); - outb(C5_IMG, ports[i] + 0x0d); /* reg set 1 */ - if ((inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) & 0xf8) == 0x58) { - port_base = ports[i]; - VDEB(printk("NCR53c406a: Sig register valid\n")); - VDEB(printk("port_base=0x%x\n", port_base)); - break; - } - release_region(ports[i], 0x10); - } - } - } -#endif /* PORT_BASE */ - - if (!port_base) { /* no ports found */ - printk("NCR53c406a: no available ports found\n"); - return 0; - } - - DEB(printk("NCR53c406a detected\n")); - - calc_port_addr(); - chip_init(); - -#ifndef IRQ_LEV - if (irq_level < 0) { /* LILO override if >= 0 */ - irq_level = irq_probe(); - if (irq_level < 0) { /* Trouble */ - printk("NCR53c406a: IRQ problem, irq_level=%d, giving up\n", irq_level); - goto err_release; - } - } -#endif - - DEB(printk("NCR53c406a: using port_base 0x%x\n", port_base)); - - present = 1; - tpnt->proc_name = "NCR53c406a"; - - shpnt = scsi_register(tpnt, 0); - if (!shpnt) { - printk("NCR53c406a: Unable to register host, giving up.\n"); - goto err_release; - } - - if (irq_level > 0) { - if (request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", shpnt)) { - printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level); - goto err_free_scsi; - } - tpnt->can_queue = 1; - DEB(printk("NCR53c406a: allocated IRQ %d\n", irq_level)); - } else if (irq_level == 0) { - tpnt->can_queue = 0; - DEB(printk("NCR53c406a: No interrupts detected\n")); - printk("NCR53c406a driver no longer supports polling interface\n"); - printk("Please email linux-scsi@vger.kernel.org\n"); - -#if USE_DMA - printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n"); -#endif /* USE_DMA */ - goto err_free_scsi; - } else { - DEB(printk("NCR53c406a: Shouldn't get here!\n")); - goto err_free_scsi; - } - -#if USE_DMA - dma_chan = DMA_CHAN; - if (request_dma(dma_chan, "NCR53c406a") != 0) { - printk("NCR53c406a: unable to allocate DMA channel %d\n", dma_chan); - goto err_free_irq; - } - - DEB(printk("Allocated DMA channel %d\n", dma_chan)); -#endif /* USE_DMA */ - - shpnt->irq = irq_level; - shpnt->io_port = port_base; - shpnt->n_io_port = 0x10; -#if USE_DMA - shpnt->dma = dma_chan; -#endif - -#if USE_DMA - sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, DMA channel %d.", port_base, irq_level, dma_chan); -#else - sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, %s PIO mode.", port_base, irq_level, fast_pio ? "fast" : "slow"); -#endif - - return (present); - -#if USE_DMA - err_free_irq: - if (irq_level) - free_irq(irq_level, shpnt); -#endif - err_free_scsi: - scsi_unregister(shpnt); - err_release: - release_region(port_base, 0x10); - return 0; -} - -static int NCR53c406a_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); -#ifdef USE_DMA - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); -#endif - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - - scsi_unregister(shost); - return 0; -} - -#ifndef MODULE -/* called from init/main.c */ -static int __init NCR53c406a_setup(char *str) -{ - static size_t setup_idx = 0; - size_t i; - int ints[4]; - - DEB(printk("NCR53c406a: Setup called\n"); - ); - - if (setup_idx >= PORT_COUNT - 1) { - printk("NCR53c406a: Setup called too many times. Bad LILO params?\n"); - return 0; - } - get_options(str, 4, ints); - if (ints[0] < 1 || ints[0] > 3) { - printk("NCR53c406a: Malformed command line\n"); - printk("NCR53c406a: Usage: ncr53c406a=[,[,]]\n"); - return 0; - } - for (i = 0; i < PORT_COUNT && !port_base; i++) - if (ports[i] == ints[1]) { - port_base = ints[1]; - DEB(printk("NCR53c406a: Specified port_base 0x%x\n", port_base); - ) - } - if (!port_base) { - printk("NCR53c406a: Invalid PORTBASE 0x%x specified\n", ints[1]); - return 0; - } - - if (ints[0] > 1) { - if (ints[2] == 0) { - irq_level = 0; - DEB(printk("NCR53c406a: Specified irq %d\n", irq_level); - ) - } else - for (i = 0; i < INTR_COUNT && irq_level < 0; i++) - if (intrs[i] == ints[2]) { - irq_level = ints[2]; - DEB(printk("NCR53c406a: Specified irq %d\n", port_base); - ) - } - if (irq_level < 0) - printk("NCR53c406a: Invalid IRQ %d specified\n", ints[2]); - } - - if (ints[0] > 2) - fast_pio = ints[3]; - - DEB(printk("NCR53c406a: port_base=0x%x, irq=%d, fast_pio=%d\n", port_base, irq_level, fast_pio);) - return 1; -} - -__setup("ncr53c406a=", NCR53c406a_setup); - -#endif /* !MODULE */ - -static const char *NCR53c406a_info(struct Scsi_Host *SChost) -{ - DEB(printk("NCR53c406a_info called\n")); - return (info_msg); -} - -#if 0 -static void wait_intr(void) -{ - unsigned long i = jiffies + WATCHDOG; - - while (time_after(i, jiffies) && !(inb(STAT_REG) & 0xe0)) { /* wait for a pseudo-interrupt */ - cpu_relax(); - barrier(); - } - - if (time_before_eq(i, jiffies)) { /* Timed out */ - rtrc(0); - current_SC->result = DID_TIME_OUT << 16; - current_SC->SCp.phase = idle; - current_SC->scsi_done(current_SC); - return; - } - - NCR53c406a_intr(NULL); -} -#endif - -static int NCR53c406a_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) -{ - int i; - - VDEB(printk("NCR53c406a_queue called\n")); - DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->target, SCpnt->lun, scsi_bufflen(SCpnt))); - -#if 0 - VDEB(for (i = 0; i < SCpnt->cmd_len; i++) - printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i])); - VDEB(printk("\n")); -#endif - - current_SC = SCpnt; - current_SC->scsi_done = done; - current_SC->SCp.phase = command_ph; - current_SC->SCp.Status = 0; - current_SC->SCp.Message = 0; - - /* We are locked here already by the mid layer */ - REG0; - outb(scmd_id(SCpnt), DEST_ID); /* set destination */ - outb(FLUSH_FIFO, CMD_REG); /* reset the fifos */ - - for (i = 0; i < SCpnt->cmd_len; i++) { - outb(SCpnt->cmnd[i], SCSI_FIFO); - } - outb(SELECT_NO_ATN, CMD_REG); - - rtrc(1); - return 0; -} - -static DEF_SCSI_QCMD(NCR53c406a_queue) - -static int NCR53c406a_host_reset(Scsi_Cmnd * SCpnt) -{ - DEB(printk("NCR53c406a_reset called\n")); - - spin_lock_irq(SCpnt->device->host->host_lock); - - outb(C4_IMG, CONFIG4); /* Select reg set 0 */ - outb(CHIP_RESET, CMD_REG); - outb(SCSI_NOP, CMD_REG); /* required after reset */ - outb(SCSI_RESET, CMD_REG); - chip_init(); - - rtrc(2); - - spin_unlock_irq(SCpnt->device->host->host_lock); - - return SUCCESS; -} - -static int NCR53c406a_biosparm(struct scsi_device *disk, - struct block_device *dev, - sector_t capacity, int *info_array) -{ - int size; - - DEB(printk("NCR53c406a_biosparm called\n")); - - size = capacity; - info_array[0] = 64; /* heads */ - info_array[1] = 32; /* sectors */ - info_array[2] = size >> 11; /* cylinders */ - if (info_array[2] > 1024) { /* big disk */ - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = size / (255 * 63); - } - return 0; -} - -static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave(dev->host_lock, flags); - NCR53c406a_intr(dev_id); - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} - -static void NCR53c406a_intr(void *dev_id) -{ - DEB(unsigned char fifo_size; - ) - DEB(unsigned char seq_reg; - ) - unsigned char status, int_reg; -#if USE_PIO - unsigned char pio_status; - struct scatterlist *sg; - int i; -#endif - - VDEB(printk("NCR53c406a_intr called\n")); - -#if USE_PIO - REG1; - pio_status = inb(PIO_STATUS); -#endif - REG0; - status = inb(STAT_REG); - DEB(seq_reg = inb(SEQ_REG)); - int_reg = inb(INT_REG); - DEB(fifo_size = inb(FIFO_FLAGS) & 0x1f); - -#if NCR53C406A_DEBUG - printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", status, seq_reg, int_reg, fifo_size); -#if (USE_DMA) - printk("\n"); -#else - printk(", pio=%02x\n", pio_status); -#endif /* USE_DMA */ -#endif /* NCR53C406A_DEBUG */ - - if (int_reg & 0x80) { /* SCSI reset intr */ - rtrc(3); - DEB(printk("NCR53c406a: reset intr received\n")); - current_SC->SCp.phase = idle; - current_SC->result = DID_RESET << 16; - current_SC->scsi_done(current_SC); - return; - } -#if USE_PIO - if (pio_status & 0x80) { - printk("NCR53C406A: Warning: PIO error!\n"); - current_SC->SCp.phase = idle; - current_SC->result = DID_ERROR << 16; - current_SC->scsi_done(current_SC); - return; - } -#endif /* USE_PIO */ - - if (status & 0x20) { /* Parity error */ - printk("NCR53c406a: Warning: parity error!\n"); - current_SC->SCp.phase = idle; - current_SC->result = DID_PARITY << 16; - current_SC->scsi_done(current_SC); - return; - } - - if (status & 0x40) { /* Gross error */ - printk("NCR53c406a: Warning: gross error!\n"); - current_SC->SCp.phase = idle; - current_SC->result = DID_ERROR << 16; - current_SC->scsi_done(current_SC); - return; - } - - if (int_reg & 0x20) { /* Disconnect */ - DEB(printk("NCR53c406a: disconnect intr received\n")); - if (current_SC->SCp.phase != message_in) { /* Unexpected disconnect */ - current_SC->result = DID_NO_CONNECT << 16; - } else { /* Command complete, return status and message */ - current_SC->result = (current_SC->SCp.Status & 0xff) - | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16); - } - - rtrc(0); - current_SC->SCp.phase = idle; - current_SC->scsi_done(current_SC); - return; - } - - switch (status & 0x07) { /* scsi phase */ - case 0x00: /* DATA-OUT */ - if (int_reg & 0x10) { /* Target requesting info transfer */ - rtrc(5); - current_SC->SCp.phase = data_out; - VDEB(printk("NCR53c406a: Data-Out phase\n")); - outb(FLUSH_FIFO, CMD_REG); - LOAD_DMA_COUNT(scsi_bufflen(current_SC)); /* Max transfer size */ -#if USE_DMA /* No s/g support for DMA */ - NCR53c406a_dma_write(scsi_sglist(current_SC), - scsdi_bufflen(current_SC)); - -#endif /* USE_DMA */ - outb(TRANSFER_INFO | DMA_OP, CMD_REG); -#if USE_PIO - scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) { - NCR53c406a_pio_write(sg_virt(sg), sg->length); - } - REG0; -#endif /* USE_PIO */ - } - break; - - case 0x01: /* DATA-IN */ - if (int_reg & 0x10) { /* Target requesting info transfer */ - rtrc(6); - current_SC->SCp.phase = data_in; - VDEB(printk("NCR53c406a: Data-In phase\n")); - outb(FLUSH_FIFO, CMD_REG); - LOAD_DMA_COUNT(scsi_bufflen(current_SC)); /* Max transfer size */ -#if USE_DMA /* No s/g support for DMA */ - NCR53c406a_dma_read(scsi_sglist(current_SC), - scsdi_bufflen(current_SC)); -#endif /* USE_DMA */ - outb(TRANSFER_INFO | DMA_OP, CMD_REG); -#if USE_PIO - scsi_for_each_sg(current_SC, sg, scsi_sg_count(current_SC), i) { - NCR53c406a_pio_read(sg_virt(sg), sg->length); - } - REG0; -#endif /* USE_PIO */ - } - break; - - case 0x02: /* COMMAND */ - current_SC->SCp.phase = command_ph; - printk("NCR53c406a: Warning: Unknown interrupt occurred in command phase!\n"); - break; - - case 0x03: /* STATUS */ - rtrc(7); - current_SC->SCp.phase = status_ph; - VDEB(printk("NCR53c406a: Status phase\n")); - outb(FLUSH_FIFO, CMD_REG); - outb(INIT_CMD_COMPLETE, CMD_REG); - break; - - case 0x04: /* Reserved */ - case 0x05: /* Reserved */ - printk("NCR53c406a: WARNING: Reserved phase!!!\n"); - break; - - case 0x06: /* MESSAGE-OUT */ - DEB(printk("NCR53c406a: Message-Out phase\n")); - current_SC->SCp.phase = message_out; - outb(SET_ATN, CMD_REG); /* Reject the message */ - outb(MSG_ACCEPT, CMD_REG); - break; - - case 0x07: /* MESSAGE-IN */ - rtrc(4); - VDEB(printk("NCR53c406a: Message-In phase\n")); - current_SC->SCp.phase = message_in; - - current_SC->SCp.Status = inb(SCSI_FIFO); - current_SC->SCp.Message = inb(SCSI_FIFO); - - VDEB(printk("SCSI FIFO size=%d\n", inb(FIFO_FLAGS) & 0x1f)); - DEB(printk("Status = %02x Message = %02x\n", current_SC->SCp.Status, current_SC->SCp.Message)); - - if (current_SC->SCp.Message == SAVE_POINTERS || current_SC->SCp.Message == DISCONNECT) { - outb(SET_ATN, CMD_REG); /* Reject message */ - DEB(printk("Discarding SAVE_POINTERS message\n")); - } - outb(MSG_ACCEPT, CMD_REG); - break; - } -} - -#ifndef IRQ_LEV -static int irq_probe(void) -{ - int irqs, irq; - unsigned long i; - - inb(INT_REG); /* clear the interrupt register */ - irqs = probe_irq_on(); - - /* Invalid command will cause an interrupt */ - REG0; - outb(0xff, CMD_REG); - - /* Wait for the interrupt to occur */ - i = jiffies + WATCHDOG; - while (time_after(i, jiffies) && !(inb(STAT_REG) & 0x80)) - barrier(); - if (time_before_eq(i, jiffies)) { /* Timed out, must be hardware trouble */ - probe_irq_off(irqs); - return -1; - } - - irq = probe_irq_off(irqs); - - /* Kick the chip */ - outb(CHIP_RESET, CMD_REG); - outb(SCSI_NOP, CMD_REG); - chip_init(); - - return irq; -} -#endif /* IRQ_LEV */ - -static void chip_init(void) -{ - REG1; -#if USE_DMA - outb(0x00, PIO_STATUS); -#else /* USE_PIO */ - outb(0x01, PIO_STATUS); -#endif - outb(0x00, PIO_FLAG); - - outb(C4_IMG, CONFIG4); /* REG0; */ - outb(C3_IMG, CONFIG3); - outb(C2_IMG, CONFIG2); - outb(C1_IMG, CONFIG1); - - outb(0x05, CLKCONV); /* clock conversion factor */ - outb(0x9C, SRTIMOUT); /* Selection timeout */ - outb(0x05, SYNCPRD); /* Synchronous transfer period */ - outb(SYNC_MODE, SYNCOFF); /* synchronous mode */ -} - -static void __init calc_port_addr(void) -{ - /* Control Register Set 0 */ - TC_LSB = (port_base + 0x00); - TC_MSB = (port_base + 0x01); - SCSI_FIFO = (port_base + 0x02); - CMD_REG = (port_base + 0x03); - STAT_REG = (port_base + 0x04); - DEST_ID = (port_base + 0x04); - INT_REG = (port_base + 0x05); - SRTIMOUT = (port_base + 0x05); - SEQ_REG = (port_base + 0x06); - SYNCPRD = (port_base + 0x06); - FIFO_FLAGS = (port_base + 0x07); - SYNCOFF = (port_base + 0x07); - CONFIG1 = (port_base + 0x08); - CLKCONV = (port_base + 0x09); - /* TESTREG = (port_base+0x0A); */ - CONFIG2 = (port_base + 0x0B); - CONFIG3 = (port_base + 0x0C); - CONFIG4 = (port_base + 0x0D); - TC_HIGH = (port_base + 0x0E); - /* FIFO_BOTTOM = (port_base+0x0F); */ - - /* Control Register Set 1 */ - /* JUMPER_SENSE = (port_base+0x00); */ - /* SRAM_PTR = (port_base+0x01); */ - /* SRAM_DATA = (port_base+0x02); */ - PIO_FIFO = (port_base + 0x04); - /* PIO_FIFO1 = (port_base+0x05); */ - /* PIO_FIFO2 = (port_base+0x06); */ - /* PIO_FIFO3 = (port_base+0x07); */ - PIO_STATUS = (port_base + 0x08); - /* ATA_CMD = (port_base+0x09); */ - /* ATA_ERR = (port_base+0x0A); */ - PIO_FLAG = (port_base + 0x0B); - CONFIG5 = (port_base + 0x0D); - /* SIGNATURE = (port_base+0x0E); */ - /* CONFIG6 = (port_base+0x0F); */ -} - -MODULE_LICENSE("GPL"); - -/* NOTE: scatter-gather support only works in PIO mode. - * Use SG_NONE if DMA mode is enabled! - */ - -static struct scsi_host_template driver_template = -{ - .proc_name = "NCR53c406a" /* proc_name */, - .name = "NCR53c406a" /* name */, - .detect = NCR53c406a_detect /* detect */, - .release = NCR53c406a_release, - .info = NCR53c406a_info /* info */, - .queuecommand = NCR53c406a_queue /* queuecommand */, - .eh_host_reset_handler = NCR53c406a_host_reset /* reset */, - .bios_param = NCR53c406a_biosparm /* biosparm */, - .can_queue = 1 /* can_queue */, - .this_id = 7 /* SCSI ID of the chip */, - .sg_tablesize = 32 /*SG_ALL*/ /*SG_NONE*/, - .cmd_per_lun = 1 /* commands per lun */, - .unchecked_isa_dma = 1 /* unchecked_isa_dma */, - .use_clustering = ENABLE_CLUSTERING, -}; - -#include "scsi_module.c" - -/* - * Overrides for Emacs so that we get a uniform tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/ANDROID_3.4.5/drivers/scsi/NCR_D700.c b/ANDROID_3.4.5/drivers/scsi/NCR_D700.c deleted file mode 100644 index 8647256a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/NCR_D700.c +++ /dev/null @@ -1,405 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ - -/* NCR Dual 700 MCA SCSI Driver - * - * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- - */ - -/* Notes: - * - * Most of the work is done in the chip specific module, 53c700.o - * - * TODO List: - * - * 1. Extract the SCSI ID from the voyager CMOS table (necessary to - * support multi-host environments. - * - * */ - - -/* CHANGELOG - * - * Version 2.2 - * - * Added mca_set_adapter_name(). - * - * Version 2.1 - * - * Modularise the driver into a Board piece (this file) and a chip - * piece 53c700.[ch] and 53c700.scr, added module options. You can - * now specify the scsi id by the parameters - * - * NCR_D700=slot: [siop:] id: .... - * - * They need to be comma separated if compiled into the kernel - * - * Version 2.0 - * - * Initial implementation of TCQ (Tag Command Queueing). TCQ is full - * featured and uses the clock algorithm to keep track of outstanding - * tags and guard against individual tag starvation. Also fixed a bug - * in all of the 1.x versions where the D700_data_residue() function - * was returning results off by 32 bytes (and thus causing the same 32 - * bytes to be written twice corrupting the data block). It turns out - * the 53c700 only has a 6 bit DBC and DFIFO registers not 7 bit ones - * like the 53c710 (The 710 is the only data manual still available, - * which I'd been using to program the 700). - * - * Version 1.2 - * - * Much improved message handling engine - * - * Version 1.1 - * - * Add code to handle selection reasonably correctly. By the time we - * get the selection interrupt, we've already responded, but drop off the - * bus and hope the selector will go away. - * - * Version 1.0: - * - * Initial release. Fully functional except for procfs and tag - * command queueing. Has only been tested on cards with 53c700-66 - * chips and only single ended. Features are - * - * 1. Synchronous data transfers to offset 8 (limit of 700-66) and - * 100ns (10MHz) limit of SCSI-2 - * - * 2. Disconnection and reselection - * - * Testing: - * - * I've only really tested this with the 700-66 chip, but have done - * soak tests in multi-device environments to verify that - * disconnections and reselections are being processed correctly. - * */ - -#define NCR_D700_VERSION "2.2" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "53c700.h" -#include "NCR_D700.h" - -static char *NCR_D700; /* command line from insmod */ - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("NCR Dual700 SCSI Driver"); -MODULE_LICENSE("GPL"); -module_param(NCR_D700, charp, 0); - -static __u8 __devinitdata id_array[2*(MCA_MAX_SLOT_NR + 1)] = - { [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 }; - -#ifdef MODULE -#define ARG_SEP ' ' -#else -#define ARG_SEP ',' -#endif - -static int __init -param_setup(char *string) -{ - char *pos = string, *next; - int slot = -1, siop = -1; - - while(pos != NULL && (next = strchr(pos, ':')) != NULL) { - int val = (int)simple_strtoul(++next, NULL, 0); - - if(!strncmp(pos, "slot:", 5)) - slot = val; - else if(!strncmp(pos, "siop:", 5)) - siop = val; - else if(!strncmp(pos, "id:", 3)) { - if(slot == -1) { - printk(KERN_WARNING "NCR D700: Must specify slot for id parameter\n"); - } else if(slot > MCA_MAX_SLOT_NR) { - printk(KERN_WARNING "NCR D700: Illegal slot %d for id %d\n", slot, val); - } else { - if(siop != 0 && siop != 1) { - id_array[slot*2] = val; - id_array[slot*2 + 1] =val; - } else { - id_array[slot*2 + siop] = val; - } - } - } - if((pos = strchr(pos, ARG_SEP)) != NULL) - pos++; - } - return 1; -} - -/* Host template. The 53c700 routine NCR_700_detect will - * fill in all of the missing routines */ -static struct scsi_host_template NCR_D700_driver_template = { - .module = THIS_MODULE, - .name = "NCR Dual 700 MCA", - .proc_name = "NCR_D700", - .this_id = 7, -}; - -/* We needs this helper because we have two hosts per struct device */ -struct NCR_D700_private { - struct device *dev; - struct Scsi_Host *hosts[2]; - char name[30]; - char pad; -}; - -static int __devinit -NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq, - int slot, u32 region, int differential) -{ - struct NCR_700_Host_Parameters *hostdata; - struct Scsi_Host *host; - int ret; - - hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); - if (!hostdata) { - printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host" - "data, detatching\n", siop); - return -ENOMEM; - } - - if (!request_region(region, 64, "NCR_D700")) { - printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", - region); - ret = -ENODEV; - goto region_failed; - } - - /* Fill in the three required pieces of hostdata */ - hostdata->base = ioport_map(region, 64); - hostdata->differential = (((1<clock = NCR_D700_CLOCK_MHZ; - hostdata->burst_length = 8; - - /* and register the siop */ - host = NCR_700_detect(&NCR_D700_driver_template, hostdata, p->dev); - if (!host) { - ret = -ENOMEM; - goto detect_failed; - } - - p->hosts[siop] = host; - /* FIXME: read this from SUS */ - host->this_id = id_array[slot * 2 + siop]; - host->irq = irq; - host->base = region; - scsi_scan_host(host); - - return 0; - - detect_failed: - release_region(region, 64); - region_failed: - kfree(hostdata); - - return ret; -} - -static irqreturn_t -NCR_D700_intr(int irq, void *data) -{ - struct NCR_D700_private *p = (struct NCR_D700_private *)data; - int i, found = 0; - - for (i = 0; i < 2; i++) - if (p->hosts[i] && - NCR_700_intr(irq, p->hosts[i]) == IRQ_HANDLED) - found++; - - return found ? IRQ_HANDLED : IRQ_NONE; -} - -/* Detect a D700 card. Note, because of the setup --- the chips are - * essentially connectecd to the MCA bus independently, it is easier - * to set them up as two separate host adapters, rather than one - * adapter with two channels */ -static int __devinit -NCR_D700_probe(struct device *dev) -{ - struct NCR_D700_private *p; - int differential; - static int banner = 1; - struct mca_device *mca_dev = to_mca_device(dev); - int slot = mca_dev->slot; - int found = 0; - int irq, i; - int pos3j, pos3k, pos3a, pos3b, pos4; - __u32 base_addr, offset_addr; - - /* enable board interrupt */ - pos4 = mca_device_read_pos(mca_dev, 4); - pos4 |= 0x4; - mca_device_write_pos(mca_dev, 4, pos4); - - mca_device_write_pos(mca_dev, 6, 9); - pos3j = mca_device_read_pos(mca_dev, 3); - mca_device_write_pos(mca_dev, 6, 10); - pos3k = mca_device_read_pos(mca_dev, 3); - mca_device_write_pos(mca_dev, 6, 0); - pos3a = mca_device_read_pos(mca_dev, 3); - mca_device_write_pos(mca_dev, 6, 1); - pos3b = mca_device_read_pos(mca_dev, 3); - - base_addr = ((pos3j << 8) | pos3k) & 0xfffffff0; - offset_addr = ((pos3a << 8) | pos3b) & 0xffffff70; - - irq = (pos4 & 0x3) + 11; - if(irq >= 13) - irq++; - if(banner) { - printk(KERN_NOTICE "NCR D700: Driver Version " NCR_D700_VERSION "\n" - "NCR D700: Copyright (c) 2001 by James.Bottomley@HansenPartnership.com\n" - "NCR D700:\n"); - banner = 0; - } - /* now do the bus related transforms */ - irq = mca_device_transform_irq(mca_dev, irq); - base_addr = mca_device_transform_ioport(mca_dev, base_addr); - offset_addr = mca_device_transform_ioport(mca_dev, offset_addr); - - printk(KERN_NOTICE "NCR D700: found in slot %d irq = %d I/O base = 0x%x\n", slot, irq, offset_addr); - - /*outb(BOARD_RESET, base_addr);*/ - - /* clear any pending interrupts */ - (void)inb(base_addr + 0x08); - /* get modctl, used later for setting diff bits */ - switch(differential = (inb(base_addr + 0x08) >> 6)) { - case 0x00: - /* only SIOP1 differential */ - differential = 0x02; - break; - case 0x01: - /* Both SIOPs differential */ - differential = 0x03; - break; - case 0x03: - /* No SIOPs differential */ - differential = 0x00; - break; - default: - printk(KERN_ERR "D700: UNEXPECTED DIFFERENTIAL RESULT 0x%02x\n", - differential); - differential = 0x00; - break; - } - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - p->dev = dev; - snprintf(p->name, sizeof(p->name), "D700(%s)", dev_name(dev)); - if (request_irq(irq, NCR_D700_intr, IRQF_SHARED, p->name, p)) { - printk(KERN_ERR "D700: request_irq failed\n"); - kfree(p); - return -EBUSY; - } - /* plumb in both 700 chips */ - for (i = 0; i < 2; i++) { - int err; - - if ((err = NCR_D700_probe_one(p, i, irq, slot, - offset_addr + (0x80 * i), - differential)) != 0) - printk("D700: SIOP%d: probe failed, error = %d\n", - i, err); - else - found++; - } - - if (!found) { - kfree(p); - return -ENODEV; - } - - mca_device_set_claim(mca_dev, 1); - mca_device_set_name(mca_dev, "NCR_D700"); - dev_set_drvdata(dev, p); - return 0; -} - -static void __devexit -NCR_D700_remove_one(struct Scsi_Host *host) -{ - scsi_remove_host(host); - NCR_700_release(host); - kfree((struct NCR_700_Host_Parameters *)host->hostdata[0]); - free_irq(host->irq, host); - release_region(host->base, 64); -} - -static int __devexit -NCR_D700_remove(struct device *dev) -{ - struct NCR_D700_private *p = dev_get_drvdata(dev); - int i; - - for (i = 0; i < 2; i++) - NCR_D700_remove_one(p->hosts[i]); - - kfree(p); - return 0; -} - -static short NCR_D700_id_table[] = { NCR_D700_MCA_ID, 0 }; - -static struct mca_driver NCR_D700_driver = { - .id_table = NCR_D700_id_table, - .driver = { - .name = "NCR_D700", - .bus = &mca_bus_type, - .probe = NCR_D700_probe, - .remove = __devexit_p(NCR_D700_remove), - }, -}; - -static int __init NCR_D700_init(void) -{ -#ifdef MODULE - if (NCR_D700) - param_setup(NCR_D700); -#endif - - return mca_register_driver(&NCR_D700_driver); -} - -static void __exit NCR_D700_exit(void) -{ - mca_unregister_driver(&NCR_D700_driver); -} - -module_init(NCR_D700_init); -module_exit(NCR_D700_exit); - -__setup("NCR_D700=", param_setup); diff --git a/ANDROID_3.4.5/drivers/scsi/NCR_D700.h b/ANDROID_3.4.5/drivers/scsi/NCR_D700.h deleted file mode 100644 index f167af6b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/NCR_D700.h +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ - -/* NCR Dual 700 MCA SCSI Driver - * - * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com - */ - -#ifndef _NCR_D700_H -#define _NCR_D700_H - -/* Don't turn on debugging messages */ -#undef NCR_D700_DEBUG - -/* The MCA identifier */ -#define NCR_D700_MCA_ID 0x0092 - -/* Defines for the Board registers */ -#define BOARD_RESET 0x80 /* board level reset */ -#define ADD_PARENB 0x04 /* Address Parity Enabled */ -#define DAT_PARENB 0x01 /* Data Parity Enabled */ -#define SFBK_ENB 0x10 /* SFDBK Interrupt Enabled */ -#define LED0GREEN 0x20 /* Led 0 (red 0; green 1) */ -#define LED1GREEN 0x40 /* Led 1 (red 0; green 1) */ -#define LED0RED 0xDF /* Led 0 (red 0; green 1) */ -#define LED1RED 0xBF /* Led 1 (red 0; green 1) */ - -#define NCR_D700_CLOCK_MHZ 50 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/NCR_Q720.c b/ANDROID_3.4.5/drivers/scsi/NCR_Q720.c deleted file mode 100644 index afdbb9ad..00000000 --- a/ANDROID_3.4.5/drivers/scsi/NCR_Q720.c +++ /dev/null @@ -1,377 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ - -/* NCR Quad 720 MCA SCSI Driver - * - * Copyright (C) 2003 by James.Bottomley@HansenPartnership.com - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include - -#include "ncr53c8xx.h" - -#include "NCR_Q720.h" - -static struct ncr_chip q720_chip __initdata = { - .revision_id = 0x0f, - .burst_max = 3, - .offset_max = 8, - .nr_divisor = 4, - .features = FE_WIDE | FE_DIFF | FE_VARCLK, -}; - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("NCR Quad 720 SCSI Driver"); -MODULE_LICENSE("GPL"); - -#define NCR_Q720_VERSION "0.9" - -/* We needs this helper because we have up to four hosts per struct device */ -struct NCR_Q720_private { - struct device *dev; - void __iomem * mem_base; - __u32 phys_mem_base; - __u32 mem_size; - __u8 irq; - __u8 siops; - __u8 irq_enable; - struct Scsi_Host *hosts[4]; -}; - -static struct scsi_host_template NCR_Q720_tpnt = { - .module = THIS_MODULE, - .proc_name = "NCR_Q720", -}; - -static irqreturn_t -NCR_Q720_intr(int irq, void *data) -{ - struct NCR_Q720_private *p = (struct NCR_Q720_private *)data; - __u8 sir = (readb(p->mem_base + 0x0d) & 0xf0) >> 4; - __u8 siop; - - sir |= ~p->irq_enable; - - if(sir == 0xff) - return IRQ_NONE; - - - while((siop = ffz(sir)) < p->siops) { - sir |= 1<hosts[siop]); - } - return IRQ_HANDLED; -} - -static int __init -NCR_Q720_probe_one(struct NCR_Q720_private *p, int siop, - int irq, int slot, __u32 paddr, void __iomem *vaddr) -{ - struct ncr_device device; - __u8 scsi_id; - static int unit = 0; - __u8 scsr1 = readb(vaddr + NCR_Q720_SCSR_OFFSET + 1); - __u8 differential = readb(vaddr + NCR_Q720_SCSR_OFFSET) & 0x20; - __u8 version; - int error; - - scsi_id = scsr1 >> 4; - /* enable burst length 16 (FIXME: should allow this) */ - scsr1 |= 0x02; - /* force a siop reset */ - scsr1 |= 0x04; - writeb(scsr1, vaddr + NCR_Q720_SCSR_OFFSET + 1); - udelay(10); - version = readb(vaddr + 0x18) >> 4; - - memset(&device, 0, sizeof(struct ncr_device)); - /* Initialise ncr_device structure with items required by ncr_attach. */ - device.chip = q720_chip; - device.chip.revision_id = version; - device.host_id = scsi_id; - device.dev = p->dev; - device.slot.base = paddr; - device.slot.base_c = paddr; - device.slot.base_v = vaddr; - device.slot.irq = irq; - device.differential = differential ? 2 : 0; - printk("Q720 probe unit %d (siop%d) at 0x%lx, diff = %d, vers = %d\n", unit, siop, - (unsigned long)paddr, differential, version); - - p->hosts[siop] = ncr_attach(&NCR_Q720_tpnt, unit++, &device); - - if (!p->hosts[siop]) - goto fail; - - p->irq_enable |= (1<hosts[siop], p->dev); - if (error) - ncr53c8xx_release(p->hosts[siop]); - else - scsi_scan_host(p->hosts[siop]); - return error; - - fail: - return -ENODEV; -} - -/* Detect a Q720 card. Note, because of the setup --- the chips are - * essentially connectecd to the MCA bus independently, it is easier - * to set them up as two separate host adapters, rather than one - * adapter with two channels */ -static int __init -NCR_Q720_probe(struct device *dev) -{ - struct NCR_Q720_private *p; - static int banner = 1; - struct mca_device *mca_dev = to_mca_device(dev); - int slot = mca_dev->slot; - int found = 0; - int irq, i, siops; - __u8 pos2, pos4, asr2, asr9, asr10; - __u16 io_base; - __u32 base_addr, mem_size; - void __iomem *mem_base; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - pos2 = mca_device_read_pos(mca_dev, 2); - /* enable device */ - pos2 |= NCR_Q720_POS2_BOARD_ENABLE | NCR_Q720_POS2_INTERRUPT_ENABLE; - mca_device_write_pos(mca_dev, 2, pos2); - - io_base = (pos2 & NCR_Q720_POS2_IO_MASK) << NCR_Q720_POS2_IO_SHIFT; - - - if(banner) { - printk(KERN_NOTICE "NCR Q720: Driver Version " NCR_Q720_VERSION "\n" - "NCR Q720: Copyright (c) 2003 by James.Bottomley@HansenPartnership.com\n" - "NCR Q720:\n"); - banner = 0; - } - io_base = mca_device_transform_ioport(mca_dev, io_base); - - /* OK, this is phase one of the bootstrap, we now know the - * I/O space base address. All the configuration registers - * are mapped here (including pos) */ - - /* sanity check I/O mapping */ - i = inb(io_base) | (inb(io_base+1)<<8); - if(i != NCR_Q720_MCA_ID) { - printk(KERN_ERR "NCR_Q720, adapter failed to I/O map registers correctly at 0x%x(0x%x)\n", io_base, i); - kfree(p); - return -ENODEV; - } - - /* Phase II, find the ram base and memory map the board register */ - pos4 = inb(io_base + 4); - /* enable streaming data */ - pos4 |= 0x01; - outb(pos4, io_base + 4); - base_addr = (pos4 & 0x7e) << 20; - base_addr += (pos4 & 0x80) << 23; - asr10 = inb(io_base + 0x12); - base_addr += (asr10 & 0x80) << 24; - base_addr += (asr10 & 0x70) << 23; - - /* OK, got the base addr, now we need to find the ram size, - * enable and map it */ - asr9 = inb(io_base + 0x11); - i = (asr9 & 0xc0) >> 6; - if(i == 0) - mem_size = 1024; - else - mem_size = 1 << (19 + i); - - /* enable the sram mapping */ - asr9 |= 0x20; - - /* disable the rom mapping */ - asr9 &= ~0x10; - - outb(asr9, io_base + 0x11); - - if(!request_mem_region(base_addr, mem_size, "NCR_Q720")) { - printk(KERN_ERR "NCR_Q720: Failed to claim memory region 0x%lx\n-0x%lx", - (unsigned long)base_addr, - (unsigned long)(base_addr + mem_size)); - goto out_free; - } - - if (dma_declare_coherent_memory(dev, base_addr, base_addr, - mem_size, DMA_MEMORY_MAP) - != DMA_MEMORY_MAP) { - printk(KERN_ERR "NCR_Q720: DMA declare memory failed\n"); - goto out_release_region; - } - - /* The first 1k of the memory buffer is a memory map of the registers - */ - mem_base = dma_mark_declared_memory_occupied(dev, base_addr, - 1024); - if (IS_ERR(mem_base)) { - printk("NCR_Q720 failed to reserve memory mapped region\n"); - goto out_release; - } - - /* now also enable accesses in asr 2 */ - asr2 = inb(io_base + 0x0a); - - asr2 |= 0x01; - - outb(asr2, io_base + 0x0a); - - /* get the number of SIOPs (this should be 2 or 4) */ - siops = ((asr2 & 0xe0) >> 5) + 1; - - /* sanity check mapping (again) */ - i = readw(mem_base); - if(i != NCR_Q720_MCA_ID) { - printk(KERN_ERR "NCR_Q720, adapter failed to memory map registers correctly at 0x%lx(0x%x)\n", (unsigned long)base_addr, i); - goto out_release; - } - - irq = readb(mem_base + 5) & 0x0f; - - - /* now do the bus related transforms */ - irq = mca_device_transform_irq(mca_dev, irq); - - printk(KERN_NOTICE "NCR Q720: found in slot %d irq = %d mem base = 0x%lx siops = %d\n", slot, irq, (unsigned long)base_addr, siops); - printk(KERN_NOTICE "NCR Q720: On board ram %dk\n", mem_size/1024); - - p->dev = dev; - p->mem_base = mem_base; - p->phys_mem_base = base_addr; - p->mem_size = mem_size; - p->irq = irq; - p->siops = siops; - - if (request_irq(irq, NCR_Q720_intr, IRQF_SHARED, "NCR_Q720", p)) { - printk(KERN_ERR "NCR_Q720: request irq %d failed\n", irq); - goto out_release; - } - /* disable all the siop interrupts */ - for(i = 0; i < siops; i++) { - void __iomem *reg_scsr1 = mem_base + NCR_Q720_CHIP_REGISTER_OFFSET - + i*NCR_Q720_SIOP_SHIFT + NCR_Q720_SCSR_OFFSET + 1; - __u8 scsr1 = readb(reg_scsr1); - scsr1 |= 0x01; - writeb(scsr1, reg_scsr1); - } - - /* plumb in all 720 chips */ - for (i = 0; i < siops; i++) { - void __iomem *siop_v_base = mem_base + NCR_Q720_CHIP_REGISTER_OFFSET - + i*NCR_Q720_SIOP_SHIFT; - __u32 siop_p_base = base_addr + NCR_Q720_CHIP_REGISTER_OFFSET - + i*NCR_Q720_SIOP_SHIFT; - __u16 port = io_base + NCR_Q720_CHIP_REGISTER_OFFSET - + i*NCR_Q720_SIOP_SHIFT; - int err; - - outb(0xff, port + 0x40); - outb(0x07, port + 0x41); - if ((err = NCR_Q720_probe_one(p, i, irq, slot, - siop_p_base, siop_v_base)) != 0) - printk("Q720: SIOP%d: probe failed, error = %d\n", - i, err); - else - found++; - } - - if (!found) { - kfree(p); - return -ENODEV; - } - - mca_device_set_claim(mca_dev, 1); - mca_device_set_name(mca_dev, "NCR_Q720"); - dev_set_drvdata(dev, p); - - return 0; - - out_release: - dma_release_declared_memory(dev); - out_release_region: - release_mem_region(base_addr, mem_size); - out_free: - kfree(p); - - return -ENODEV; -} - -static void __exit -NCR_Q720_remove_one(struct Scsi_Host *host) -{ - scsi_remove_host(host); - ncr53c8xx_release(host); -} - -static int __exit -NCR_Q720_remove(struct device *dev) -{ - struct NCR_Q720_private *p = dev_get_drvdata(dev); - int i; - - for (i = 0; i < p->siops; i++) - if(p->hosts[i]) - NCR_Q720_remove_one(p->hosts[i]); - - dma_release_declared_memory(dev); - release_mem_region(p->phys_mem_base, p->mem_size); - free_irq(p->irq, p); - kfree(p); - return 0; -} - -static short NCR_Q720_id_table[] = { NCR_Q720_MCA_ID, 0 }; - -static struct mca_driver NCR_Q720_driver = { - .id_table = NCR_Q720_id_table, - .driver = { - .name = "NCR_Q720", - .bus = &mca_bus_type, - .probe = NCR_Q720_probe, - .remove = __devexit_p(NCR_Q720_remove), - }, -}; - -static int __init -NCR_Q720_init(void) -{ - int ret = ncr53c8xx_init(); - if (!ret) - ret = mca_register_driver(&NCR_Q720_driver); - if (ret) - ncr53c8xx_exit(); - return ret; -} - -static void __exit -NCR_Q720_exit(void) -{ - mca_unregister_driver(&NCR_Q720_driver); - ncr53c8xx_exit(); -} - -module_init(NCR_Q720_init); -module_exit(NCR_Q720_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/NCR_Q720.h b/ANDROID_3.4.5/drivers/scsi/NCR_Q720.h deleted file mode 100644 index 7b920900..00000000 --- a/ANDROID_3.4.5/drivers/scsi/NCR_Q720.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ - -/* NCR Quad 720 MCA SCSI Driver - * - * Copyright (C) 2003 by James.Bottomley@HansenPartnership.com - */ - -#ifndef _NCR_Q720_H -#define _NCR_Q720_H - -/* The MCA identifier */ -#define NCR_Q720_MCA_ID 0x0720 - -#define NCR_Q720_CLOCK_MHZ 30 - -#define NCR_Q720_POS2_BOARD_ENABLE 0x01 -#define NCR_Q720_POS2_INTERRUPT_ENABLE 0x02 -#define NCR_Q720_POS2_PARITY_DISABLE 0x04 -#define NCR_Q720_POS2_IO_MASK 0xf8 -#define NCR_Q720_POS2_IO_SHIFT 8 - -#define NCR_Q720_CHIP_REGISTER_OFFSET 0x200 -#define NCR_Q720_SCSR_OFFSET 0x070 -#define NCR_Q720_SIOP_SHIFT 0x080 - -#endif - - diff --git a/ANDROID_3.4.5/drivers/scsi/a100u2w.c b/ANDROID_3.4.5/drivers/scsi/a100u2w.c deleted file mode 100644 index a391090a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/a100u2w.c +++ /dev/null @@ -1,1245 +0,0 @@ -/* - * Initio A100 device driver for Linux. - * - * Copyright (c) 1994-1998 Initio Corporation - * Copyright (c) 2003-2004 Christoph Hellwig - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Revision History: - * 07/02/98 hl - v.91n Initial drivers. - * 09/14/98 hl - v1.01 Support new Kernel. - * 09/22/98 hl - v1.01a Support reset. - * 09/24/98 hl - v1.01b Fixed reset. - * 10/05/98 hl - v1.02 split the source code and release. - * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up - * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause - * 08/08/99 bv - v1.02c Use waitForPause again. - * 06/25/02 Doug Ledford - v1.02d - * - Remove limit on number of controllers - * - Port to DMA mapping API - * - Clean up interrupt handler registration - * - Fix memory leaks - * - Fix allocation of scsi host structs and private data - * 11/18/03 Christoph Hellwig - * - Port to new probing API - * - Fix some more leaks in init failure cases - * 9/28/04 Christoph Hellwig - * - merge the two source files - * - remove internal queueing code - * 14/06/07 Alan Cox - * - Grand cleanup and Linuxisation - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include "a100u2w.h" - - -static struct orc_scb *__orc_alloc_scb(struct orc_host * host); -static void inia100_scb_handler(struct orc_host *host, struct orc_scb *scb); - -static struct orc_nvram nvram, *nvramp = &nvram; - -static u8 default_nvram[64] = -{ -/*----------header -------------*/ - 0x01, /* 0x00: Sub System Vendor ID 0 */ - 0x11, /* 0x01: Sub System Vendor ID 1 */ - 0x60, /* 0x02: Sub System ID 0 */ - 0x10, /* 0x03: Sub System ID 1 */ - 0x00, /* 0x04: SubClass */ - 0x01, /* 0x05: Vendor ID 0 */ - 0x11, /* 0x06: Vendor ID 1 */ - 0x60, /* 0x07: Device ID 0 */ - 0x10, /* 0x08: Device ID 1 */ - 0x00, /* 0x09: Reserved */ - 0x00, /* 0x0A: Reserved */ - 0x01, /* 0x0B: Revision of Data Structure */ - /* -- Host Adapter Structure --- */ - 0x01, /* 0x0C: Number Of SCSI Channel */ - 0x01, /* 0x0D: BIOS Configuration 1 */ - 0x00, /* 0x0E: BIOS Configuration 2 */ - 0x00, /* 0x0F: BIOS Configuration 3 */ - /* --- SCSI Channel 0 Configuration --- */ - 0x07, /* 0x10: H/A ID */ - 0x83, /* 0x11: Channel Configuration */ - 0x20, /* 0x12: MAX TAG per target */ - 0x0A, /* 0x13: SCSI Reset Recovering time */ - 0x00, /* 0x14: Channel Configuration4 */ - 0x00, /* 0x15: Channel Configuration5 */ - /* SCSI Channel 0 Target Configuration */ - /* 0x16-0x25 */ - 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, - 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, - /* --- SCSI Channel 1 Configuration --- */ - 0x07, /* 0x26: H/A ID */ - 0x83, /* 0x27: Channel Configuration */ - 0x20, /* 0x28: MAX TAG per target */ - 0x0A, /* 0x29: SCSI Reset Recovering time */ - 0x00, /* 0x2A: Channel Configuration4 */ - 0x00, /* 0x2B: Channel Configuration5 */ - /* SCSI Channel 1 Target Configuration */ - /* 0x2C-0x3B */ - 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, - 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, - 0x00, /* 0x3C: Reserved */ - 0x00, /* 0x3D: Reserved */ - 0x00, /* 0x3E: Reserved */ - 0x00 /* 0x3F: Checksum */ -}; - - -static u8 wait_chip_ready(struct orc_host * host) -{ - int i; - - for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if (inb(host->base + ORC_HCTRL) & HOSTSTOP) /* Wait HOSTSTOP set */ - return 1; - mdelay(100); - } - return 0; -} - -static u8 wait_firmware_ready(struct orc_host * host) -{ - int i; - - for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if (inb(host->base + ORC_HSTUS) & RREADY) /* Wait READY set */ - return 1; - mdelay(100); /* wait 100ms before try again */ - } - return 0; -} - -/***************************************************************************/ -static u8 wait_scsi_reset_done(struct orc_host * host) -{ - int i; - - for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if (!(inb(host->base + ORC_HCTRL) & SCSIRST)) /* Wait SCSIRST done */ - return 1; - mdelay(100); /* wait 100ms before try again */ - } - return 0; -} - -/***************************************************************************/ -static u8 wait_HDO_off(struct orc_host * host) -{ - int i; - - for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if (!(inb(host->base + ORC_HCTRL) & HDO)) /* Wait HDO off */ - return 1; - mdelay(100); /* wait 100ms before try again */ - } - return 0; -} - -/***************************************************************************/ -static u8 wait_hdi_set(struct orc_host * host, u8 * data) -{ - int i; - - for (i = 0; i < 10; i++) { /* Wait 1 second for report timeout */ - if ((*data = inb(host->base + ORC_HSTUS)) & HDI) - return 1; /* Wait HDI set */ - mdelay(100); /* wait 100ms before try again */ - } - return 0; -} - -/***************************************************************************/ -static unsigned short orc_read_fwrev(struct orc_host * host) -{ - u16 version; - u8 data; - - outb(ORC_CMD_VERSION, host->base + ORC_HDATA); - outb(HDO, host->base + ORC_HCTRL); - if (wait_HDO_off(host) == 0) /* Wait HDO off */ - return 0; - - if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */ - return 0; - version = inb(host->base + ORC_HDATA); - outb(data, host->base + ORC_HSTUS); /* Clear HDI */ - - if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */ - return 0; - version |= inb(host->base + ORC_HDATA) << 8; - outb(data, host->base + ORC_HSTUS); /* Clear HDI */ - - return version; -} - -/***************************************************************************/ -static u8 orc_nv_write(struct orc_host * host, unsigned char address, unsigned char value) -{ - outb(ORC_CMD_SET_NVM, host->base + ORC_HDATA); /* Write command */ - outb(HDO, host->base + ORC_HCTRL); - if (wait_HDO_off(host) == 0) /* Wait HDO off */ - return 0; - - outb(address, host->base + ORC_HDATA); /* Write address */ - outb(HDO, host->base + ORC_HCTRL); - if (wait_HDO_off(host) == 0) /* Wait HDO off */ - return 0; - - outb(value, host->base + ORC_HDATA); /* Write value */ - outb(HDO, host->base + ORC_HCTRL); - if (wait_HDO_off(host) == 0) /* Wait HDO off */ - return 0; - - return 1; -} - -/***************************************************************************/ -static u8 orc_nv_read(struct orc_host * host, u8 address, u8 *ptr) -{ - unsigned char data; - - outb(ORC_CMD_GET_NVM, host->base + ORC_HDATA); /* Write command */ - outb(HDO, host->base + ORC_HCTRL); - if (wait_HDO_off(host) == 0) /* Wait HDO off */ - return 0; - - outb(address, host->base + ORC_HDATA); /* Write address */ - outb(HDO, host->base + ORC_HCTRL); - if (wait_HDO_off(host) == 0) /* Wait HDO off */ - return 0; - - if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */ - return 0; - *ptr = inb(host->base + ORC_HDATA); - outb(data, host->base + ORC_HSTUS); /* Clear HDI */ - - return 1; - -} - -/** - * orc_exec_sb - Queue an SCB with the HA - * @host: host adapter the SCB belongs to - * @scb: SCB to queue for execution - */ - -static void orc_exec_scb(struct orc_host * host, struct orc_scb * scb) -{ - scb->status = ORCSCB_POST; - outb(scb->scbidx, host->base + ORC_PQUEUE); -} - - -/** - * se2_rd_all - read SCSI parameters from EEPROM - * @host: Host whose EEPROM is being loaded - * - * Read SCSI H/A configuration parameters from serial EEPROM - */ - -static int se2_rd_all(struct orc_host * host) -{ - int i; - u8 *np, chksum = 0; - - np = (u8 *) nvramp; - for (i = 0; i < 64; i++, np++) { /* <01> */ - if (orc_nv_read(host, (u8) i, np) == 0) - return -1; - } - - /*------ Is ckecksum ok ? ------*/ - np = (u8 *) nvramp; - for (i = 0; i < 63; i++) - chksum += *np++; - - if (nvramp->CheckSum != (u8) chksum) - return -1; - return 1; -} - -/** - * se2_update_all - update the EEPROM - * @host: Host whose EEPROM is being updated - * - * Update changed bytes in the EEPROM image. - */ - -static void se2_update_all(struct orc_host * host) -{ /* setup default pattern */ - int i; - u8 *np, *np1, chksum = 0; - - /* Calculate checksum first */ - np = (u8 *) default_nvram; - for (i = 0; i < 63; i++) - chksum += *np++; - *np = chksum; - - np = (u8 *) default_nvram; - np1 = (u8 *) nvramp; - for (i = 0; i < 64; i++, np++, np1++) { - if (*np != *np1) - orc_nv_write(host, (u8) i, *np); - } -} - -/** - * read_eeprom - load EEPROM - * @host: Host EEPROM to read - * - * Read the EEPROM for a given host. If it is invalid or fails - * the restore the defaults and use them. - */ - -static void read_eeprom(struct orc_host * host) -{ - if (se2_rd_all(host) != 1) { - se2_update_all(host); /* setup default pattern */ - se2_rd_all(host); /* load again */ - } -} - - -/** - * orc_load_firmware - initialise firmware - * @host: Host to set up - * - * Load the firmware from the EEPROM into controller SRAM. This - * is basically a 4K block copy and then a 4K block read to check - * correctness. The rest is convulted by the indirect interfaces - * in the hardware - */ - -static u8 orc_load_firmware(struct orc_host * host) -{ - u32 data32; - u16 bios_addr; - u16 i; - u8 *data32_ptr, data; - - - /* Set up the EEPROM for access */ - - data = inb(host->base + ORC_GCFG); - outb(data | EEPRG, host->base + ORC_GCFG); /* Enable EEPROM programming */ - outb(0x00, host->base + ORC_EBIOSADR2); - outw(0x0000, host->base + ORC_EBIOSADR0); - if (inb(host->base + ORC_EBIOSDATA) != 0x55) { - outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */ - return 0; - } - outw(0x0001, host->base + ORC_EBIOSADR0); - if (inb(host->base + ORC_EBIOSDATA) != 0xAA) { - outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */ - return 0; - } - - outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Enable SRAM programming */ - data32_ptr = (u8 *) & data32; - data32 = cpu_to_le32(0); /* Initial FW address to 0 */ - outw(0x0010, host->base + ORC_EBIOSADR0); - *data32_ptr = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ - outw(0x0011, host->base + ORC_EBIOSADR0); - *(data32_ptr + 1) = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ - outw(0x0012, host->base + ORC_EBIOSADR0); - *(data32_ptr + 2) = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ - outw(*(data32_ptr + 2), host->base + ORC_EBIOSADR2); - outl(le32_to_cpu(data32), host->base + ORC_FWBASEADR); /* Write FW address */ - - /* Copy the code from the BIOS to the SRAM */ - - udelay(500); /* Required on Sun Ultra 5 ... 350 -> failures */ - bios_addr = (u16) le32_to_cpu(data32); /* FW code locate at BIOS address + ? */ - for (i = 0, data32_ptr = (u8 *) & data32; /* Download the code */ - i < 0x1000; /* Firmware code size = 4K */ - i++, bios_addr++) { - outw(bios_addr, host->base + ORC_EBIOSADR0); - *data32_ptr++ = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ - if ((i % 4) == 3) { - outl(le32_to_cpu(data32), host->base + ORC_RISCRAM); /* Write every 4 bytes */ - data32_ptr = (u8 *) & data32; - } - } - - /* Go back and check they match */ - - outb(PRGMRST | DOWNLOAD, host->base + ORC_RISCCTL); /* Reset program count 0 */ - bios_addr -= 0x1000; /* Reset the BIOS address */ - for (i = 0, data32_ptr = (u8 *) & data32; /* Check the code */ - i < 0x1000; /* Firmware code size = 4K */ - i++, bios_addr++) { - outw(bios_addr, host->base + ORC_EBIOSADR0); - *data32_ptr++ = inb(host->base + ORC_EBIOSDATA); /* Read from BIOS */ - if ((i % 4) == 3) { - if (inl(host->base + ORC_RISCRAM) != le32_to_cpu(data32)) { - outb(PRGMRST, host->base + ORC_RISCCTL); /* Reset program to 0 */ - outb(data, host->base + ORC_GCFG); /*Disable EEPROM programming */ - return 0; - } - data32_ptr = (u8 *) & data32; - } - } - - /* Success */ - outb(PRGMRST, host->base + ORC_RISCCTL); /* Reset program to 0 */ - outb(data, host->base + ORC_GCFG); /* Disable EEPROM programming */ - return 1; -} - -/***************************************************************************/ -static void setup_SCBs(struct orc_host * host) -{ - struct orc_scb *scb; - int i; - struct orc_extended_scb *escb; - dma_addr_t escb_phys; - - /* Setup SCB base and SCB Size registers */ - outb(ORC_MAXQUEUE, host->base + ORC_SCBSIZE); /* Total number of SCBs */ - /* SCB base address 0 */ - outl(host->scb_phys, host->base + ORC_SCBBASE0); - /* SCB base address 1 */ - outl(host->scb_phys, host->base + ORC_SCBBASE1); - - /* setup scatter list address with one buffer */ - scb = host->scb_virt; - escb = host->escb_virt; - - for (i = 0; i < ORC_MAXQUEUE; i++) { - escb_phys = (host->escb_phys + (sizeof(struct orc_extended_scb) * i)); - scb->sg_addr = cpu_to_le32((u32) escb_phys); - scb->sense_addr = cpu_to_le32((u32) escb_phys); - scb->escb = escb; - scb->scbidx = i; - scb++; - escb++; - } -} - -/** - * init_alloc_map - initialise allocation map - * @host: host map to configure - * - * Initialise the allocation maps for this device. If the device - * is not quiescent the caller must hold the allocation lock - */ - -static void init_alloc_map(struct orc_host * host) -{ - u8 i, j; - - for (i = 0; i < MAX_CHANNELS; i++) { - for (j = 0; j < 8; j++) { - host->allocation_map[i][j] = 0xffffffff; - } - } -} - -/** - * init_orchid - initialise the host adapter - * @host:host adapter to initialise - * - * Initialise the controller and if necessary load the firmware. - * - * Returns -1 if the initialisation fails. - */ - -static int init_orchid(struct orc_host * host) -{ - u8 *ptr; - u16 revision; - u8 i; - - init_alloc_map(host); - outb(0xFF, host->base + ORC_GIMSK); /* Disable all interrupts */ - - if (inb(host->base + ORC_HSTUS) & RREADY) { /* Orchid is ready */ - revision = orc_read_fwrev(host); - if (revision == 0xFFFF) { - outb(DEVRST, host->base + ORC_HCTRL); /* Reset Host Adapter */ - if (wait_chip_ready(host) == 0) - return -1; - orc_load_firmware(host); /* Download FW */ - setup_SCBs(host); /* Setup SCB base and SCB Size registers */ - outb(0x00, host->base + ORC_HCTRL); /* clear HOSTSTOP */ - if (wait_firmware_ready(host) == 0) - return -1; - /* Wait for firmware ready */ - } else { - setup_SCBs(host); /* Setup SCB base and SCB Size registers */ - } - } else { /* Orchid is not Ready */ - outb(DEVRST, host->base + ORC_HCTRL); /* Reset Host Adapter */ - if (wait_chip_ready(host) == 0) - return -1; - orc_load_firmware(host); /* Download FW */ - setup_SCBs(host); /* Setup SCB base and SCB Size registers */ - outb(HDO, host->base + ORC_HCTRL); /* Do Hardware Reset & */ - - /* clear HOSTSTOP */ - if (wait_firmware_ready(host) == 0) /* Wait for firmware ready */ - return -1; - } - - /* Load an EEProm copy into RAM */ - /* Assumes single threaded at this point */ - read_eeprom(host); - - if (nvramp->revision != 1) - return -1; - - host->scsi_id = nvramp->scsi_id; - host->BIOScfg = nvramp->BIOSConfig1; - host->max_targets = MAX_TARGETS; - ptr = (u8 *) & (nvramp->Target00Config); - for (i = 0; i < 16; ptr++, i++) { - host->target_flag[i] = *ptr; - host->max_tags[i] = ORC_MAXTAGS; - } - - if (nvramp->SCSI0Config & NCC_BUSRESET) - host->flags |= HCF_SCSI_RESET; - outb(0xFB, host->base + ORC_GIMSK); /* enable RP FIFO interrupt */ - return 0; -} - -/** - * orc_reset_scsi_bus - perform bus reset - * @host: host being reset - * - * Perform a full bus reset on the adapter. - */ - -static int orc_reset_scsi_bus(struct orc_host * host) -{ /* I need Host Control Block Information */ - unsigned long flags; - - spin_lock_irqsave(&host->allocation_lock, flags); - - init_alloc_map(host); - /* reset scsi bus */ - outb(SCSIRST, host->base + ORC_HCTRL); - /* FIXME: We can spend up to a second with the lock held and - interrupts off here */ - if (wait_scsi_reset_done(host) == 0) { - spin_unlock_irqrestore(&host->allocation_lock, flags); - return FAILED; - } else { - spin_unlock_irqrestore(&host->allocation_lock, flags); - return SUCCESS; - } -} - -/** - * orc_device_reset - device reset handler - * @host: host to reset - * @cmd: command causing the reset - * @target; target device - * - * Reset registers, reset a hanging bus and kill active and disconnected - * commands for target w/o soft reset - */ - -static int orc_device_reset(struct orc_host * host, struct scsi_cmnd *cmd, unsigned int target) -{ /* I need Host Control Block Information */ - struct orc_scb *scb; - struct orc_extended_scb *escb; - struct orc_scb *host_scb; - u8 i; - unsigned long flags; - - spin_lock_irqsave(&(host->allocation_lock), flags); - scb = (struct orc_scb *) NULL; - escb = (struct orc_extended_scb *) NULL; - - /* setup scatter list address with one buffer */ - host_scb = host->scb_virt; - - /* FIXME: is this safe if we then fail to issue the reset or race - a completion ? */ - init_alloc_map(host); - - /* Find the scb corresponding to the command */ - for (i = 0; i < ORC_MAXQUEUE; i++) { - escb = host_scb->escb; - if (host_scb->status && escb->srb == cmd) - break; - host_scb++; - } - - if (i == ORC_MAXQUEUE) { - printk(KERN_ERR "Unable to Reset - No SCB Found\n"); - spin_unlock_irqrestore(&(host->allocation_lock), flags); - return FAILED; - } - - /* Allocate a new SCB for the reset command to the firmware */ - if ((scb = __orc_alloc_scb(host)) == NULL) { - /* Can't happen.. */ - spin_unlock_irqrestore(&(host->allocation_lock), flags); - return FAILED; - } - - /* Reset device is handled by the firmware, we fill in an SCB and - fire it at the controller, it does the rest */ - scb->opcode = ORC_BUSDEVRST; - scb->target = target; - scb->hastat = 0; - scb->tastat = 0; - scb->status = 0x0; - scb->link = 0xFF; - scb->reserved0 = 0; - scb->reserved1 = 0; - scb->xferlen = cpu_to_le32(0); - scb->sg_len = cpu_to_le32(0); - - escb->srb = NULL; - escb->srb = cmd; - orc_exec_scb(host, scb); /* Start execute SCB */ - spin_unlock_irqrestore(&host->allocation_lock, flags); - return SUCCESS; -} - -/** - * __orc_alloc_scb - allocate an SCB - * @host: host to allocate from - * - * Allocate an SCB and return a pointer to the SCB object. NULL - * is returned if no SCB is free. The caller must already hold - * the allocator lock at this point. - */ - - -static struct orc_scb *__orc_alloc_scb(struct orc_host * host) -{ - u8 channel; - unsigned long idx; - u8 index; - u8 i; - - channel = host->index; - for (i = 0; i < 8; i++) { - for (index = 0; index < 32; index++) { - if ((host->allocation_map[channel][i] >> index) & 0x01) { - host->allocation_map[channel][i] &= ~(1 << index); - idx = index + 32 * i; - /* - * Translate the index to a structure instance - */ - return host->scb_virt + idx; - } - } - } - return NULL; -} - -/** - * orc_alloc_scb - allocate an SCB - * @host: host to allocate from - * - * Allocate an SCB and return a pointer to the SCB object. NULL - * is returned if no SCB is free. - */ - -static struct orc_scb *orc_alloc_scb(struct orc_host * host) -{ - struct orc_scb *scb; - unsigned long flags; - - spin_lock_irqsave(&host->allocation_lock, flags); - scb = __orc_alloc_scb(host); - spin_unlock_irqrestore(&host->allocation_lock, flags); - return scb; -} - -/** - * orc_release_scb - release an SCB - * @host: host owning the SCB - * @scb: SCB that is now free - * - * Called to return a completed SCB to the allocation pool. Before - * calling the SCB must be out of use on both the host and the HA. - */ - -static void orc_release_scb(struct orc_host *host, struct orc_scb *scb) -{ - unsigned long flags; - u8 index, i, channel; - - spin_lock_irqsave(&(host->allocation_lock), flags); - channel = host->index; /* Channel */ - index = scb->scbidx; - i = index / 32; - index %= 32; - host->allocation_map[channel][i] |= (1 << index); - spin_unlock_irqrestore(&(host->allocation_lock), flags); -} - -/** - * orchid_abort_scb - abort a command - * - * Abort a queued command that has been passed to the firmware layer - * if possible. This is all handled by the firmware. We aks the firmware - * and it either aborts the command or fails - */ - -static int orchid_abort_scb(struct orc_host * host, struct orc_scb * scb) -{ - unsigned char data, status; - - outb(ORC_CMD_ABORT_SCB, host->base + ORC_HDATA); /* Write command */ - outb(HDO, host->base + ORC_HCTRL); - if (wait_HDO_off(host) == 0) /* Wait HDO off */ - return 0; - - outb(scb->scbidx, host->base + ORC_HDATA); /* Write address */ - outb(HDO, host->base + ORC_HCTRL); - if (wait_HDO_off(host) == 0) /* Wait HDO off */ - return 0; - - if (wait_hdi_set(host, &data) == 0) /* Wait HDI set */ - return 0; - status = inb(host->base + ORC_HDATA); - outb(data, host->base + ORC_HSTUS); /* Clear HDI */ - - if (status == 1) /* 0 - Successfully */ - return 0; /* 1 - Fail */ - return 1; -} - -static int inia100_abort_cmd(struct orc_host * host, struct scsi_cmnd *cmd) -{ - struct orc_extended_scb *escb; - struct orc_scb *scb; - u8 i; - unsigned long flags; - - spin_lock_irqsave(&(host->allocation_lock), flags); - - scb = host->scb_virt; - - /* Walk the queue until we find the SCB that belongs to the command - block. This isn't a performance critical path so a walk in the park - here does no harm */ - - for (i = 0; i < ORC_MAXQUEUE; i++, scb++) { - escb = scb->escb; - if (scb->status && escb->srb == cmd) { - if (scb->tag_msg == 0) { - goto out; - } else { - /* Issue an ABORT to the firmware */ - if (orchid_abort_scb(host, scb)) { - escb->srb = NULL; - spin_unlock_irqrestore(&host->allocation_lock, flags); - return SUCCESS; - } else - goto out; - } - } - } -out: - spin_unlock_irqrestore(&host->allocation_lock, flags); - return FAILED; -} - -/** - * orc_interrupt - IRQ processing - * @host: Host causing the interrupt - * - * This function is called from the IRQ handler and protected - * by the host lock. While the controller reports that there are - * scb's for processing we pull them off the controller, turn the - * index into a host address pointer to the scb and call the scb - * handler. - * - * Returns IRQ_HANDLED if any SCBs were processed, IRQ_NONE otherwise - */ - -static irqreturn_t orc_interrupt(struct orc_host * host) -{ - u8 scb_index; - struct orc_scb *scb; - - /* Check if we have an SCB queued for servicing */ - if (inb(host->base + ORC_RQUEUECNT) == 0) - return IRQ_NONE; - - do { - /* Get the SCB index of the SCB to service */ - scb_index = inb(host->base + ORC_RQUEUE); - - /* Translate it back to a host pointer */ - scb = (struct orc_scb *) ((unsigned long) host->scb_virt + (unsigned long) (sizeof(struct orc_scb) * scb_index)); - scb->status = 0x0; - /* Process the SCB */ - inia100_scb_handler(host, scb); - } while (inb(host->base + ORC_RQUEUECNT)); - return IRQ_HANDLED; -} /* End of I1060Interrupt() */ - -/** - * inia100_build_scb - build SCB - * @host: host owing the control block - * @scb: control block to use - * @cmd: Mid layer command - * - * Build a host adapter control block from the SCSI mid layer command - */ - -static int inia100_build_scb(struct orc_host * host, struct orc_scb * scb, struct scsi_cmnd * cmd) -{ /* Create corresponding SCB */ - struct scatterlist *sg; - struct orc_sgent *sgent; /* Pointer to SG list */ - int i, count_sg; - struct orc_extended_scb *escb; - - /* Links between the escb, scb and Linux scsi midlayer cmd */ - escb = scb->escb; - escb->srb = cmd; - sgent = NULL; - - /* Set up the SCB to do a SCSI command block */ - scb->opcode = ORC_EXECSCSI; - scb->flags = SCF_NO_DCHK; /* Clear done bit */ - scb->target = cmd->device->id; - scb->lun = cmd->device->lun; - scb->reserved0 = 0; - scb->reserved1 = 0; - scb->sg_len = cpu_to_le32(0); - - scb->xferlen = cpu_to_le32((u32) scsi_bufflen(cmd)); - sgent = (struct orc_sgent *) & escb->sglist[0]; - - count_sg = scsi_dma_map(cmd); - if (count_sg < 0) - return count_sg; - BUG_ON(count_sg > TOTAL_SG_ENTRY); - - /* Build the scatter gather lists */ - if (count_sg) { - scb->sg_len = cpu_to_le32((u32) (count_sg * 8)); - scsi_for_each_sg(cmd, sg, count_sg, i) { - sgent->base = cpu_to_le32((u32) sg_dma_address(sg)); - sgent->length = cpu_to_le32((u32) sg_dma_len(sg)); - sgent++; - } - } else { - scb->sg_len = cpu_to_le32(0); - sgent->base = cpu_to_le32(0); - sgent->length = cpu_to_le32(0); - } - scb->sg_addr = (u32) scb->sense_addr; /* sense_addr is already little endian */ - scb->hastat = 0; - scb->tastat = 0; - scb->link = 0xFF; - scb->sense_len = SENSE_SIZE; - scb->cdb_len = cmd->cmd_len; - if (scb->cdb_len >= IMAX_CDB) { - printk("max cdb length= %x\b", cmd->cmd_len); - scb->cdb_len = IMAX_CDB; - } - scb->ident = cmd->device->lun | DISC_ALLOW; - if (cmd->device->tagged_supported) { /* Tag Support */ - scb->tag_msg = SIMPLE_QUEUE_TAG; /* Do simple tag only */ - } else { - scb->tag_msg = 0; /* No tag support */ - } - memcpy(scb->cdb, cmd->cmnd, scb->cdb_len); - return 0; -} - -/** - * inia100_queue - queue command with host - * @cmd: Command block - * @done: Completion function - * - * Called by the mid layer to queue a command. Process the command - * block, build the host specific scb structures and if there is room - * queue the command down to the controller - */ - -static int inia100_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) -{ - struct orc_scb *scb; - struct orc_host *host; /* Point to Host adapter control block */ - - host = (struct orc_host *) cmd->device->host->hostdata; - cmd->scsi_done = done; - /* Get free SCSI control block */ - if ((scb = orc_alloc_scb(host)) == NULL) - return SCSI_MLQUEUE_HOST_BUSY; - - if (inia100_build_scb(host, scb, cmd)) { - orc_release_scb(host, scb); - return SCSI_MLQUEUE_HOST_BUSY; - } - orc_exec_scb(host, scb); /* Start execute SCB */ - return 0; -} - -static DEF_SCSI_QCMD(inia100_queue) - -/***************************************************************************** - Function name : inia100_abort - Description : Abort a queued command. - (commands that are on the bus can't be aborted easily) - Input : host - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static int inia100_abort(struct scsi_cmnd * cmd) -{ - struct orc_host *host; - - host = (struct orc_host *) cmd->device->host->hostdata; - return inia100_abort_cmd(host, cmd); -} - -/***************************************************************************** - Function name : inia100_reset - Description : Reset registers, reset a hanging bus and - kill active and disconnected commands for target w/o soft reset - Input : host - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static int inia100_bus_reset(struct scsi_cmnd * cmd) -{ /* I need Host Control Block Information */ - struct orc_host *host; - host = (struct orc_host *) cmd->device->host->hostdata; - return orc_reset_scsi_bus(host); -} - -/***************************************************************************** - Function name : inia100_device_reset - Description : Reset the device - Input : host - Pointer to host adapter structure - Output : None. - Return : pSRB - Pointer to SCSI request block. -*****************************************************************************/ -static int inia100_device_reset(struct scsi_cmnd * cmd) -{ /* I need Host Control Block Information */ - struct orc_host *host; - host = (struct orc_host *) cmd->device->host->hostdata; - return orc_device_reset(host, cmd, scmd_id(cmd)); - -} - -/** - * inia100_scb_handler - interrupt callback - * @host: Host causing the interrupt - * @scb: SCB the controller returned as needing processing - * - * Perform completion processing on a control block. Do the conversions - * from host to SCSI midlayer error coding, save any sense data and - * the complete with the midlayer and recycle the scb. - */ - -static void inia100_scb_handler(struct orc_host *host, struct orc_scb *scb) -{ - struct scsi_cmnd *cmd; /* Pointer to SCSI request block */ - struct orc_extended_scb *escb; - - escb = scb->escb; - if ((cmd = (struct scsi_cmnd *) escb->srb) == NULL) { - printk(KERN_ERR "inia100_scb_handler: SRB pointer is empty\n"); - orc_release_scb(host, scb); /* Release SCB for current channel */ - return; - } - escb->srb = NULL; - - switch (scb->hastat) { - case 0x0: - case 0xa: /* Linked command complete without error and linked normally */ - case 0xb: /* Linked command complete without error interrupt generated */ - scb->hastat = 0; - break; - - case 0x11: /* Selection time out-The initiator selection or target - reselection was not complete within the SCSI Time out period */ - scb->hastat = DID_TIME_OUT; - break; - - case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus - phase sequence was requested by the target. The host adapter - will generate a SCSI Reset Condition, notifying the host with - a SCRD interrupt */ - scb->hastat = DID_RESET; - break; - - case 0x1a: /* SCB Aborted. 07/21/98 */ - scb->hastat = DID_ABORT; - break; - - case 0x12: /* Data overrun/underrun-The target attempted to transfer more data - than was allocated by the Data Length field or the sum of the - Scatter / Gather Data Length fields. */ - case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ - case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. */ - - default: - printk(KERN_DEBUG "inia100: %x %x\n", scb->hastat, scb->tastat); - scb->hastat = DID_ERROR; /* Couldn't find any better */ - break; - } - - if (scb->tastat == 2) { /* Check condition */ - memcpy((unsigned char *) &cmd->sense_buffer[0], - (unsigned char *) &escb->sglist[0], SENSE_SIZE); - } - cmd->result = scb->tastat | (scb->hastat << 16); - scsi_dma_unmap(cmd); - cmd->scsi_done(cmd); /* Notify system DONE */ - orc_release_scb(host, scb); /* Release SCB for current channel */ -} - -/** - * inia100_intr - interrupt handler - * @irqno: Interrupt value - * @devid: Host adapter - * - * Entry point for IRQ handling. All the real work is performed - * by orc_interrupt. - */ -static irqreturn_t inia100_intr(int irqno, void *devid) -{ - struct Scsi_Host *shost = (struct Scsi_Host *)devid; - struct orc_host *host = (struct orc_host *)shost->hostdata; - unsigned long flags; - irqreturn_t res; - - spin_lock_irqsave(shost->host_lock, flags); - res = orc_interrupt(host); - spin_unlock_irqrestore(shost->host_lock, flags); - - return res; -} - -static struct scsi_host_template inia100_template = { - .proc_name = "inia100", - .name = inia100_REVID, - .queuecommand = inia100_queue, - .eh_abort_handler = inia100_abort, - .eh_bus_reset_handler = inia100_bus_reset, - .eh_device_reset_handler = inia100_device_reset, - .can_queue = 1, - .this_id = 1, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -static int __devinit inia100_probe_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct Scsi_Host *shost; - struct orc_host *host; - unsigned long port, bios; - int error = -ENODEV; - u32 sz; - unsigned long biosaddr; - char *bios_phys; - - if (pci_enable_device(pdev)) - goto out; - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "Unable to set 32bit DMA " - "on inia100 adapter, ignoring.\n"); - goto out_disable_device; - } - - pci_set_master(pdev); - - port = pci_resource_start(pdev, 0); - if (!request_region(port, 256, "inia100")) { - printk(KERN_WARNING "inia100: io port 0x%lx, is busy.\n", port); - goto out_disable_device; - } - - /* <02> read from base address + 0x50 offset to get the bios value. */ - bios = inw(port + 0x50); - - - shost = scsi_host_alloc(&inia100_template, sizeof(struct orc_host)); - if (!shost) - goto out_release_region; - - host = (struct orc_host *)shost->hostdata; - host->pdev = pdev; - host->base = port; - host->BIOScfg = bios; - spin_lock_init(&host->allocation_lock); - - /* Get total memory needed for SCB */ - sz = ORC_MAXQUEUE * sizeof(struct orc_scb); - host->scb_virt = pci_alloc_consistent(pdev, sz, - &host->scb_phys); - if (!host->scb_virt) { - printk("inia100: SCB memory allocation error\n"); - goto out_host_put; - } - memset(host->scb_virt, 0, sz); - - /* Get total memory needed for ESCB */ - sz = ORC_MAXQUEUE * sizeof(struct orc_extended_scb); - host->escb_virt = pci_alloc_consistent(pdev, sz, - &host->escb_phys); - if (!host->escb_virt) { - printk("inia100: ESCB memory allocation error\n"); - goto out_free_scb_array; - } - memset(host->escb_virt, 0, sz); - - biosaddr = host->BIOScfg; - biosaddr = (biosaddr << 4); - bios_phys = phys_to_virt(biosaddr); - if (init_orchid(host)) { /* Initialize orchid chip */ - printk("inia100: initial orchid fail!!\n"); - goto out_free_escb_array; - } - - shost->io_port = host->base; - shost->n_io_port = 0xff; - shost->can_queue = ORC_MAXQUEUE; - shost->unique_id = shost->io_port; - shost->max_id = host->max_targets; - shost->max_lun = 16; - shost->irq = pdev->irq; - shost->this_id = host->scsi_id; /* Assign HCS index */ - shost->sg_tablesize = TOTAL_SG_ENTRY; - - /* Initial orc chip */ - error = request_irq(pdev->irq, inia100_intr, IRQF_SHARED, - "inia100", shost); - if (error < 0) { - printk(KERN_WARNING "inia100: unable to get irq %d\n", - pdev->irq); - goto out_free_escb_array; - } - - pci_set_drvdata(pdev, shost); - - error = scsi_add_host(shost, &pdev->dev); - if (error) - goto out_free_irq; - - scsi_scan_host(shost); - return 0; - -out_free_irq: - free_irq(shost->irq, shost); -out_free_escb_array: - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb), - host->escb_virt, host->escb_phys); -out_free_scb_array: - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb), - host->scb_virt, host->scb_phys); -out_host_put: - scsi_host_put(shost); -out_release_region: - release_region(port, 256); -out_disable_device: - pci_disable_device(pdev); -out: - return error; -} - -static void __devexit inia100_remove_one(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct orc_host *host = (struct orc_host *)shost->hostdata; - - scsi_remove_host(shost); - - free_irq(shost->irq, shost); - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_extended_scb), - host->escb_virt, host->escb_phys); - pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(struct orc_scb), - host->scb_virt, host->scb_phys); - release_region(shost->io_port, 256); - - scsi_host_put(shost); -} - -static struct pci_device_id inia100_pci_tbl[] = { - {PCI_VENDOR_ID_INIT, 0x1060, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; -MODULE_DEVICE_TABLE(pci, inia100_pci_tbl); - -static struct pci_driver inia100_pci_driver = { - .name = "inia100", - .id_table = inia100_pci_tbl, - .probe = inia100_probe_one, - .remove = __devexit_p(inia100_remove_one), -}; - -static int __init inia100_init(void) -{ - return pci_register_driver(&inia100_pci_driver); -} - -static void __exit inia100_exit(void) -{ - pci_unregister_driver(&inia100_pci_driver); -} - -MODULE_DESCRIPTION("Initio A100U2W SCSI driver"); -MODULE_AUTHOR("Initio Corporation"); -MODULE_LICENSE("Dual BSD/GPL"); - -module_init(inia100_init); -module_exit(inia100_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/a100u2w.h b/ANDROID_3.4.5/drivers/scsi/a100u2w.h deleted file mode 100644 index d40e0c52..00000000 --- a/ANDROID_3.4.5/drivers/scsi/a100u2w.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Initio A100 device driver for Linux. - * - * Copyright (c) 1994-1998 Initio Corporation - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Revision History: - * 06/18/98 HL, Initial production Version 1.02 - * 12/19/98 bv, Use spinlocks for 2.1.95 and up - * 06/25/02 Doug Ledford - * - This and the i60uscsi.h file are almost identical, - * merged them into a single header used by both .c files. - * 14/06/07 Alan Cox - * - Grand cleanup and Linuxisation - */ - -#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02d" - -#if 1 -#define ORC_MAXQUEUE 245 -#define ORC_MAXTAGS 64 -#else -#define ORC_MAXQUEUE 25 -#define ORC_MAXTAGS 8 -#endif - -#define TOTAL_SG_ENTRY 32 -#define MAX_TARGETS 16 -#define IMAX_CDB 15 -#define SENSE_SIZE 14 - -/************************************************************************/ -/* Scatter-Gather Element Structure */ -/************************************************************************/ -struct orc_sgent { - u32 base; /* Data Pointer */ - u32 length; /* Data Length */ -}; - -/* SCSI related definition */ -#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */ -#define DISC_ALLOW 0xC0 /* Disconnect is allowed */ - - -#define ORC_OFFSET_SCB 16 -#define ORC_MAX_SCBS 250 -#define MAX_CHANNELS 2 -#define MAX_ESCB_ELE 64 -#define TCF_DRV_255_63 0x0400 - -/********************************************************/ -/* Orchid Host Command Set */ -/********************************************************/ -#define ORC_CMD_NOP 0x00 /* Host command - NOP */ -#define ORC_CMD_VERSION 0x01 /* Host command - Get F/W version */ -#define ORC_CMD_ECHO 0x02 /* Host command - ECHO */ -#define ORC_CMD_SET_NVM 0x03 /* Host command - Set NVRAM */ -#define ORC_CMD_GET_NVM 0x04 /* Host command - Get NVRAM */ -#define ORC_CMD_GET_BUS_STATUS 0x05 /* Host command - Get SCSI bus status */ -#define ORC_CMD_ABORT_SCB 0x06 /* Host command - Abort SCB */ -#define ORC_CMD_ISSUE_SCB 0x07 /* Host command - Issue SCB */ - -/********************************************************/ -/* Orchid Register Set */ -/********************************************************/ -#define ORC_GINTS 0xA0 /* Global Interrupt Status */ -#define QINT 0x04 /* Reply Queue Interrupt */ -#define ORC_GIMSK 0xA1 /* Global Interrupt MASK */ -#define MQINT 0x04 /* Mask Reply Queue Interrupt */ -#define ORC_GCFG 0xA2 /* Global Configure */ -#define EEPRG 0x01 /* Enable EEPROM programming */ -#define ORC_GSTAT 0xA3 /* Global status */ -#define WIDEBUS 0x10 /* Wide SCSI Devices connected */ -#define ORC_HDATA 0xA4 /* Host Data */ -#define ORC_HCTRL 0xA5 /* Host Control */ -#define SCSIRST 0x80 /* SCSI bus reset */ -#define HDO 0x40 /* Host data out */ -#define HOSTSTOP 0x02 /* Host stop RISC engine */ -#define DEVRST 0x01 /* Device reset */ -#define ORC_HSTUS 0xA6 /* Host Status */ -#define HDI 0x02 /* Host data in */ -#define RREADY 0x01 /* RISC engine is ready to receive */ -#define ORC_NVRAM 0xA7 /* Nvram port address */ -#define SE2CS 0x008 -#define SE2CLK 0x004 -#define SE2DO 0x002 -#define SE2DI 0x001 -#define ORC_PQUEUE 0xA8 /* Posting queue FIFO */ -#define ORC_PQCNT 0xA9 /* Posting queue FIFO Cnt */ -#define ORC_RQUEUE 0xAA /* Reply queue FIFO */ -#define ORC_RQUEUECNT 0xAB /* Reply queue FIFO Cnt */ -#define ORC_FWBASEADR 0xAC /* Firmware base address */ - -#define ORC_EBIOSADR0 0xB0 /* External Bios address */ -#define ORC_EBIOSADR1 0xB1 /* External Bios address */ -#define ORC_EBIOSADR2 0xB2 /* External Bios address */ -#define ORC_EBIOSDATA 0xB3 /* External Bios address */ - -#define ORC_SCBSIZE 0xB7 /* SCB size register */ -#define ORC_SCBBASE0 0xB8 /* SCB base address 0 */ -#define ORC_SCBBASE1 0xBC /* SCB base address 1 */ - -#define ORC_RISCCTL 0xE0 /* RISC Control */ -#define PRGMRST 0x002 -#define DOWNLOAD 0x001 -#define ORC_PRGMCTR0 0xE2 /* RISC program counter */ -#define ORC_PRGMCTR1 0xE3 /* RISC program counter */ -#define ORC_RISCRAM 0xEC /* RISC RAM data port 4 bytes */ - -struct orc_extended_scb { /* Extended SCB */ - struct orc_sgent sglist[TOTAL_SG_ENTRY]; /*0 Start of SG list */ - struct scsi_cmnd *srb; /*50 SRB Pointer */ -}; - -/*********************************************************************** - SCSI Control Block - - 0x40 bytes long, the last 8 are user bytes -************************************************************************/ -struct orc_scb { /* Scsi_Ctrl_Blk */ - u8 opcode; /*00 SCB command code&residual */ - u8 flags; /*01 SCB Flags */ - u8 target; /*02 Target Id */ - u8 lun; /*03 Lun */ - u32 reserved0; /*04 Reserved for ORCHID must 0 */ - u32 xferlen; /*08 Data Transfer Length */ - u32 reserved1; /*0C Reserved for ORCHID must 0 */ - u32 sg_len; /*10 SG list # * 8 */ - u32 sg_addr; /*14 SG List Buf physical Addr */ - u32 sg_addrhigh; /*18 SG Buffer high physical Addr */ - u8 hastat; /*1C Host Status */ - u8 tastat; /*1D Target Status */ - u8 status; /*1E SCB status */ - u8 link; /*1F Link pointer, default 0xFF */ - u8 sense_len; /*20 Sense Allocation Length */ - u8 cdb_len; /*21 CDB Length */ - u8 ident; /*22 Identify */ - u8 tag_msg; /*23 Tag Message */ - u8 cdb[IMAX_CDB]; /*24 SCSI CDBs */ - u8 scbidx; /*3C Index for this ORCSCB */ - u32 sense_addr; /*34 Sense Buffer physical Addr */ - - struct orc_extended_scb *escb; /*38 Extended SCB Pointer */ - /* 64bit pointer or 32bit pointer + reserved ? */ -#ifndef CONFIG_64BIT - u8 reserved2[4]; /*3E Reserved for Driver use */ -#endif -}; - -/* Opcodes of ORCSCB_Opcode */ -#define ORC_EXECSCSI 0x00 /* SCSI initiator command with residual */ -#define ORC_BUSDEVRST 0x01 /* SCSI Bus Device Reset */ - -/* Status of ORCSCB_Status */ -#define ORCSCB_COMPLETE 0x00 /* SCB request completed */ -#define ORCSCB_POST 0x01 /* SCB is posted by the HOST */ - -/* Bit Definition for ORCSCB_Flags */ -#define SCF_DISINT 0x01 /* Disable HOST interrupt */ -#define SCF_DIR 0x18 /* Direction bits */ -#define SCF_NO_DCHK 0x00 /* Direction determined by SCSI */ -#define SCF_DIN 0x08 /* From Target to Initiator */ -#define SCF_DOUT 0x10 /* From Initiator to Target */ -#define SCF_NO_XF 0x18 /* No data transfer */ -#define SCF_POLL 0x40 - -/* Error Codes for ORCSCB_HaStat */ -#define HOST_SEL_TOUT 0x11 -#define HOST_DO_DU 0x12 -#define HOST_BUS_FREE 0x13 -#define HOST_BAD_PHAS 0x14 -#define HOST_INV_CMD 0x16 -#define HOST_SCSI_RST 0x1B -#define HOST_DEV_RST 0x1C - - -/* Error Codes for ORCSCB_TaStat */ -#define TARGET_CHK_COND 0x02 -#define TARGET_BUSY 0x08 -#define TARGET_TAG_FULL 0x28 - - -/*********************************************************************** - Target Device Control Structure -**********************************************************************/ - -struct orc_target { - u8 TCS_DrvDASD; /* 6 */ - u8 TCS_DrvSCSI; /* 7 */ - u8 TCS_DrvHead; /* 8 */ - u16 TCS_DrvFlags; /* 4 */ - u8 TCS_DrvSector; /* 7 */ -}; - -/* Bit Definition for TCF_DrvFlags */ -#define TCS_DF_NODASD_SUPT 0x20 /* Suppress OS/2 DASD Mgr support */ -#define TCS_DF_NOSCSI_SUPT 0x40 /* Suppress OS/2 SCSI Mgr support */ - - -/*********************************************************************** - Host Adapter Control Structure -************************************************************************/ -struct orc_host { - unsigned long base; /* Base address */ - u8 index; /* Index (Channel)*/ - u8 scsi_id; /* H/A SCSI ID */ - u8 BIOScfg; /*BIOS configuration */ - u8 flags; - u8 max_targets; /* SCSI0MAXTags */ - struct orc_scb *scb_virt; /* Virtual Pointer to SCB array */ - dma_addr_t scb_phys; /* Scb Physical address */ - struct orc_extended_scb *escb_virt; /* Virtual pointer to ESCB Scatter list */ - dma_addr_t escb_phys; /* scatter list Physical address */ - u8 target_flag[16]; /* target configuration, TCF_EN_TAG */ - u8 max_tags[16]; /* ORC_MAX_SCBS */ - u32 allocation_map[MAX_CHANNELS][8]; /* Max STB is 256, So 256/32 */ - spinlock_t allocation_lock; - struct pci_dev *pdev; -}; - -/* Bit Definition for HCS_Flags */ - -#define HCF_SCSI_RESET 0x01 /* SCSI BUS RESET */ -#define HCF_PARITY 0x02 /* parity card */ -#define HCF_LVDS 0x10 /* parity card */ - -/* Bit Definition for TargetFlag */ - -#define TCF_EN_255 0x08 -#define TCF_EN_TAG 0x10 -#define TCF_BUSY 0x20 -#define TCF_DISCONNECT 0x40 -#define TCF_SPIN_UP 0x80 - -/* Bit Definition for HCS_AFlags */ -#define HCS_AF_IGNORE 0x01 /* Adapter ignore */ -#define HCS_AF_DISABLE_RESET 0x10 /* Adapter disable reset */ -#define HCS_AF_DISABLE_ADPT 0x80 /* Adapter disable */ - -struct orc_nvram { -/*----------header ---------------*/ - u8 SubVendorID0; /* 00 - Sub Vendor ID */ - u8 SubVendorID1; /* 00 - Sub Vendor ID */ - u8 SubSysID0; /* 02 - Sub System ID */ - u8 SubSysID1; /* 02 - Sub System ID */ - u8 SubClass; /* 04 - Sub Class */ - u8 VendorID0; /* 05 - Vendor ID */ - u8 VendorID1; /* 05 - Vendor ID */ - u8 DeviceID0; /* 07 - Device ID */ - u8 DeviceID1; /* 07 - Device ID */ - u8 Reserved0[2]; /* 09 - Reserved */ - u8 revision; /* 0B - revision of data structure */ - /* ----Host Adapter Structure ---- */ - u8 NumOfCh; /* 0C - Number of SCSI channel */ - u8 BIOSConfig1; /* 0D - BIOS configuration 1 */ - u8 BIOSConfig2; /* 0E - BIOS boot channel&target ID */ - u8 BIOSConfig3; /* 0F - BIOS configuration 3 */ - /* ----SCSI channel Structure ---- */ - /* from "CTRL-I SCSI Host Adapter SetUp menu " */ - u8 scsi_id; /* 10 - Channel 0 SCSI ID */ - u8 SCSI0Config; /* 11 - Channel 0 SCSI configuration */ - u8 SCSI0MaxTags; /* 12 - Channel 0 Maximum tags */ - u8 SCSI0ResetTime; /* 13 - Channel 0 Reset recovering time */ - u8 ReservedforChannel0[2]; /* 14 - Reserved */ - - /* ----SCSI target Structure ---- */ - /* from "CTRL-I SCSI device SetUp menu " */ - u8 Target00Config; /* 16 - Channel 0 Target 0 config */ - u8 Target01Config; /* 17 - Channel 0 Target 1 config */ - u8 Target02Config; /* 18 - Channel 0 Target 2 config */ - u8 Target03Config; /* 19 - Channel 0 Target 3 config */ - u8 Target04Config; /* 1A - Channel 0 Target 4 config */ - u8 Target05Config; /* 1B - Channel 0 Target 5 config */ - u8 Target06Config; /* 1C - Channel 0 Target 6 config */ - u8 Target07Config; /* 1D - Channel 0 Target 7 config */ - u8 Target08Config; /* 1E - Channel 0 Target 8 config */ - u8 Target09Config; /* 1F - Channel 0 Target 9 config */ - u8 Target0AConfig; /* 20 - Channel 0 Target A config */ - u8 Target0BConfig; /* 21 - Channel 0 Target B config */ - u8 Target0CConfig; /* 22 - Channel 0 Target C config */ - u8 Target0DConfig; /* 23 - Channel 0 Target D config */ - u8 Target0EConfig; /* 24 - Channel 0 Target E config */ - u8 Target0FConfig; /* 25 - Channel 0 Target F config */ - - u8 SCSI1Id; /* 26 - Channel 1 SCSI ID */ - u8 SCSI1Config; /* 27 - Channel 1 SCSI configuration */ - u8 SCSI1MaxTags; /* 28 - Channel 1 Maximum tags */ - u8 SCSI1ResetTime; /* 29 - Channel 1 Reset recovering time */ - u8 ReservedforChannel1[2]; /* 2A - Reserved */ - - /* ----SCSI target Structure ---- */ - /* from "CTRL-I SCSI device SetUp menu " */ - u8 Target10Config; /* 2C - Channel 1 Target 0 config */ - u8 Target11Config; /* 2D - Channel 1 Target 1 config */ - u8 Target12Config; /* 2E - Channel 1 Target 2 config */ - u8 Target13Config; /* 2F - Channel 1 Target 3 config */ - u8 Target14Config; /* 30 - Channel 1 Target 4 config */ - u8 Target15Config; /* 31 - Channel 1 Target 5 config */ - u8 Target16Config; /* 32 - Channel 1 Target 6 config */ - u8 Target17Config; /* 33 - Channel 1 Target 7 config */ - u8 Target18Config; /* 34 - Channel 1 Target 8 config */ - u8 Target19Config; /* 35 - Channel 1 Target 9 config */ - u8 Target1AConfig; /* 36 - Channel 1 Target A config */ - u8 Target1BConfig; /* 37 - Channel 1 Target B config */ - u8 Target1CConfig; /* 38 - Channel 1 Target C config */ - u8 Target1DConfig; /* 39 - Channel 1 Target D config */ - u8 Target1EConfig; /* 3A - Channel 1 Target E config */ - u8 Target1FConfig; /* 3B - Channel 1 Target F config */ - u8 reserved[3]; /* 3C - Reserved */ - /* ---------- CheckSum ---------- */ - u8 CheckSum; /* 3F - Checksum of NVRam */ -}; - -/* Bios Configuration for nvram->BIOSConfig1 */ -#define NBC_BIOSENABLE 0x01 /* BIOS enable */ -#define NBC_CDROM 0x02 /* Support bootable CDROM */ -#define NBC_REMOVABLE 0x04 /* Support removable drive */ - -/* Bios Configuration for nvram->BIOSConfig2 */ -#define NBB_TARGET_MASK 0x0F /* Boot SCSI target ID number */ -#define NBB_CHANL_MASK 0xF0 /* Boot SCSI channel number */ - -/* Bit definition for nvram->SCSIConfig */ -#define NCC_BUSRESET 0x01 /* Reset SCSI bus at power up */ -#define NCC_PARITYCHK 0x02 /* SCSI parity enable */ -#define NCC_LVDS 0x10 /* Enable LVDS */ -#define NCC_ACTTERM1 0x20 /* Enable active terminator 1 */ -#define NCC_ACTTERM2 0x40 /* Enable active terminator 2 */ -#define NCC_AUTOTERM 0x80 /* Enable auto termination */ - -/* Bit definition for nvram->TargetxConfig */ -#define NTC_PERIOD 0x07 /* Maximum Sync. Speed */ -#define NTC_1GIGA 0x08 /* 255 head / 63 sectors (64/32) */ -#define NTC_NO_SYNC 0x10 /* NO SYNC. NEGO */ -#define NTC_NO_WIDESYNC 0x20 /* NO WIDE SYNC. NEGO */ -#define NTC_DISC_ENABLE 0x40 /* Enable SCSI disconnect */ -#define NTC_SPINUP 0x80 /* Start disk drive */ - -/* Default NVRam values */ -#define NBC_DEFAULT (NBC_ENABLE) -#define NCC_DEFAULT (NCC_BUSRESET | NCC_AUTOTERM | NCC_PARITYCHK) -#define NCC_MAX_TAGS 0x20 /* Maximum tags per target */ -#define NCC_RESET_TIME 0x0A /* SCSI RESET recovering time */ -#define NTC_DEFAULT (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE) - diff --git a/ANDROID_3.4.5/drivers/scsi/a2091.c b/ANDROID_3.4.5/drivers/scsi/a2091.c deleted file mode 100644 index 79a30633..00000000 --- a/ANDROID_3.4.5/drivers/scsi/a2091.c +++ /dev/null @@ -1,281 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "scsi.h" -#include "wd33c93.h" -#include "a2091.h" - - -struct a2091_hostdata { - struct WD33C93_hostdata wh; - struct a2091_scsiregs *regs; -}; - -static irqreturn_t a2091_intr(int irq, void *data) -{ - struct Scsi_Host *instance = data; - struct a2091_hostdata *hdata = shost_priv(instance); - unsigned int status = hdata->regs->ISTR; - unsigned long flags; - - if (!(status & (ISTR_INT_F | ISTR_INT_P)) || !(status & ISTR_INTS)) - return IRQ_NONE; - - spin_lock_irqsave(instance->host_lock, flags); - wd33c93_intr(instance); - spin_unlock_irqrestore(instance->host_lock, flags); - return IRQ_HANDLED; -} - -static int dma_setup(struct scsi_cmnd *cmd, int dir_in) -{ - struct Scsi_Host *instance = cmd->device->host; - struct a2091_hostdata *hdata = shost_priv(instance); - struct WD33C93_hostdata *wh = &hdata->wh; - struct a2091_scsiregs *regs = hdata->regs; - unsigned short cntr = CNTR_PDMD | CNTR_INTEN; - unsigned long addr = virt_to_bus(cmd->SCp.ptr); - - /* don't allow DMA if the physical address is bad */ - if (addr & A2091_XFER_MASK) { - wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; - wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len, - GFP_KERNEL); - - /* can't allocate memory; use PIO */ - if (!wh->dma_bounce_buffer) { - wh->dma_bounce_len = 0; - return 1; - } - - /* get the physical address of the bounce buffer */ - addr = virt_to_bus(wh->dma_bounce_buffer); - - /* the bounce buffer may not be in the first 16M of physmem */ - if (addr & A2091_XFER_MASK) { - /* we could use chipmem... maybe later */ - kfree(wh->dma_bounce_buffer); - wh->dma_bounce_buffer = NULL; - wh->dma_bounce_len = 0; - return 1; - } - - if (!dir_in) { - /* copy to bounce buffer for a write */ - memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr, - cmd->SCp.this_residual); - } - } - - /* setup dma direction */ - if (!dir_in) - cntr |= CNTR_DDIR; - - /* remember direction */ - wh->dma_dir = dir_in; - - regs->CNTR = cntr; - - /* setup DMA *physical* address */ - regs->ACR = addr; - - if (dir_in) { - /* invalidate any cache */ - cache_clear(addr, cmd->SCp.this_residual); - } else { - /* push any dirty cache */ - cache_push(addr, cmd->SCp.this_residual); - } - /* start DMA */ - regs->ST_DMA = 1; - - /* return success */ - return 0; -} - -static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, - int status) -{ - struct a2091_hostdata *hdata = shost_priv(instance); - struct WD33C93_hostdata *wh = &hdata->wh; - struct a2091_scsiregs *regs = hdata->regs; - - /* disable SCSI interrupts */ - unsigned short cntr = CNTR_PDMD; - - if (!wh->dma_dir) - cntr |= CNTR_DDIR; - - /* disable SCSI interrupts */ - regs->CNTR = cntr; - - /* flush if we were reading */ - if (wh->dma_dir) { - regs->FLUSH = 1; - while (!(regs->ISTR & ISTR_FE_FLG)) - ; - } - - /* clear a possible interrupt */ - regs->CINT = 1; - - /* stop DMA */ - regs->SP_DMA = 1; - - /* restore the CONTROL bits (minus the direction flag) */ - regs->CNTR = CNTR_PDMD | CNTR_INTEN; - - /* copy from a bounce buffer, if necessary */ - if (status && wh->dma_bounce_buffer) { - if (wh->dma_dir) - memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer, - SCpnt->SCp.this_residual); - kfree(wh->dma_bounce_buffer); - wh->dma_bounce_buffer = NULL; - wh->dma_bounce_len = 0; - } -} - -static int a2091_bus_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *instance = cmd->device->host; - - /* FIXME perform bus-specific reset */ - - /* FIXME 2: kill this function, and let midlayer fall back - to the same action, calling wd33c93_host_reset() */ - - spin_lock_irq(instance->host_lock); - wd33c93_host_reset(cmd); - spin_unlock_irq(instance->host_lock); - - return SUCCESS; -} - -static struct scsi_host_template a2091_scsi_template = { - .module = THIS_MODULE, - .name = "Commodore A2091/A590 SCSI", - .proc_info = wd33c93_proc_info, - .proc_name = "A2901", - .queuecommand = wd33c93_queuecommand, - .eh_abort_handler = wd33c93_abort, - .eh_bus_reset_handler = a2091_bus_reset, - .eh_host_reset_handler = wd33c93_host_reset, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING -}; - -static int __devinit a2091_probe(struct zorro_dev *z, - const struct zorro_device_id *ent) -{ - struct Scsi_Host *instance; - int error; - struct a2091_scsiregs *regs; - wd33c93_regs wdregs; - struct a2091_hostdata *hdata; - - if (!request_mem_region(z->resource.start, 256, "wd33c93")) - return -EBUSY; - - instance = scsi_host_alloc(&a2091_scsi_template, - sizeof(struct a2091_hostdata)); - if (!instance) { - error = -ENOMEM; - goto fail_alloc; - } - - instance->irq = IRQ_AMIGA_PORTS; - instance->unique_id = z->slotaddr; - - regs = (struct a2091_scsiregs *)ZTWO_VADDR(z->resource.start); - regs->DAWR = DAWR_A2091; - - wdregs.SASR = ®s->SASR; - wdregs.SCMD = ®s->SCMD; - - hdata = shost_priv(instance); - hdata->wh.no_sync = 0xff; - hdata->wh.fast = 0; - hdata->wh.dma_mode = CTRL_DMA; - hdata->regs = regs; - - wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_8_10); - error = request_irq(IRQ_AMIGA_PORTS, a2091_intr, IRQF_SHARED, - "A2091 SCSI", instance); - if (error) - goto fail_irq; - - regs->CNTR = CNTR_PDMD | CNTR_INTEN; - - error = scsi_add_host(instance, NULL); - if (error) - goto fail_host; - - zorro_set_drvdata(z, instance); - - scsi_scan_host(instance); - return 0; - -fail_host: - free_irq(IRQ_AMIGA_PORTS, instance); -fail_irq: - scsi_host_put(instance); -fail_alloc: - release_mem_region(z->resource.start, 256); - return error; -} - -static void __devexit a2091_remove(struct zorro_dev *z) -{ - struct Scsi_Host *instance = zorro_get_drvdata(z); - struct a2091_hostdata *hdata = shost_priv(instance); - - hdata->regs->CNTR = 0; - scsi_remove_host(instance); - free_irq(IRQ_AMIGA_PORTS, instance); - scsi_host_put(instance); - release_mem_region(z->resource.start, 256); -} - -static struct zorro_device_id a2091_zorro_tbl[] __devinitdata = { - { ZORRO_PROD_CBM_A590_A2091_1 }, - { ZORRO_PROD_CBM_A590_A2091_2 }, - { 0 } -}; -MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl); - -static struct zorro_driver a2091_driver = { - .name = "a2091", - .id_table = a2091_zorro_tbl, - .probe = a2091_probe, - .remove = __devexit_p(a2091_remove), -}; - -static int __init a2091_init(void) -{ - return zorro_register_driver(&a2091_driver); -} -module_init(a2091_init); - -static void __exit a2091_exit(void) -{ - zorro_unregister_driver(&a2091_driver); -} -module_exit(a2091_exit); - -MODULE_DESCRIPTION("Commodore A2091/A590 SCSI"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/a2091.h b/ANDROID_3.4.5/drivers/scsi/a2091.h deleted file mode 100644 index 794b8e65..00000000 --- a/ANDROID_3.4.5/drivers/scsi/a2091.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef A2091_H -#define A2091_H - -/* $Id: a2091.h,v 1.4 1997/01/19 23:07:09 davem Exp $ - * - * Header file for the Commodore A2091 Zorro II SCSI controller for Linux - * - * Written and (C) 1993, Hamish Macdonald, see a2091.c for more info - * - */ - -#include - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 16 -#endif - -/* - * if the transfer address ANDed with this results in a non-zero - * result, then we can't use DMA. - */ -#define A2091_XFER_MASK (0xff000001) - -struct a2091_scsiregs { - unsigned char pad1[64]; - volatile unsigned short ISTR; - volatile unsigned short CNTR; - unsigned char pad2[60]; - volatile unsigned int WTC; - volatile unsigned long ACR; - unsigned char pad3[6]; - volatile unsigned short DAWR; - unsigned char pad4; - volatile unsigned char SASR; - unsigned char pad5; - volatile unsigned char SCMD; - unsigned char pad6[76]; - volatile unsigned short ST_DMA; - volatile unsigned short SP_DMA; - volatile unsigned short CINT; - unsigned char pad7[2]; - volatile unsigned short FLUSH; -}; - -#define DAWR_A2091 (3) - -/* CNTR bits. */ -#define CNTR_TCEN (1<<7) -#define CNTR_PREST (1<<6) -#define CNTR_PDMD (1<<5) -#define CNTR_INTEN (1<<4) -#define CNTR_DDIR (1<<3) - -/* ISTR bits. */ -#define ISTR_INTX (1<<8) -#define ISTR_INT_F (1<<7) -#define ISTR_INTS (1<<6) -#define ISTR_E_INT (1<<5) -#define ISTR_INT_P (1<<4) -#define ISTR_UE_INT (1<<3) -#define ISTR_OE_INT (1<<2) -#define ISTR_FF_FLG (1<<1) -#define ISTR_FE_FLG (1<<0) - -#endif /* A2091_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/a3000.c b/ANDROID_3.4.5/drivers/scsi/a3000.c deleted file mode 100644 index e29fe0e7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/a3000.c +++ /dev/null @@ -1,297 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "scsi.h" -#include "wd33c93.h" -#include "a3000.h" - - -struct a3000_hostdata { - struct WD33C93_hostdata wh; - struct a3000_scsiregs *regs; -}; - -static irqreturn_t a3000_intr(int irq, void *data) -{ - struct Scsi_Host *instance = data; - struct a3000_hostdata *hdata = shost_priv(instance); - unsigned int status = hdata->regs->ISTR; - unsigned long flags; - - if (!(status & ISTR_INT_P)) - return IRQ_NONE; - if (status & ISTR_INTS) { - spin_lock_irqsave(instance->host_lock, flags); - wd33c93_intr(instance); - spin_unlock_irqrestore(instance->host_lock, flags); - return IRQ_HANDLED; - } - pr_warning("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status); - return IRQ_NONE; -} - -static int dma_setup(struct scsi_cmnd *cmd, int dir_in) -{ - struct Scsi_Host *instance = cmd->device->host; - struct a3000_hostdata *hdata = shost_priv(instance); - struct WD33C93_hostdata *wh = &hdata->wh; - struct a3000_scsiregs *regs = hdata->regs; - unsigned short cntr = CNTR_PDMD | CNTR_INTEN; - unsigned long addr = virt_to_bus(cmd->SCp.ptr); - - /* - * if the physical address has the wrong alignment, or if - * physical address is bad, or if it is a write and at the - * end of a physical memory chunk, then allocate a bounce - * buffer - */ - if (addr & A3000_XFER_MASK) { - wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; - wh->dma_bounce_buffer = kmalloc(wh->dma_bounce_len, - GFP_KERNEL); - - /* can't allocate memory; use PIO */ - if (!wh->dma_bounce_buffer) { - wh->dma_bounce_len = 0; - return 1; - } - - if (!dir_in) { - /* copy to bounce buffer for a write */ - memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr, - cmd->SCp.this_residual); - } - - addr = virt_to_bus(wh->dma_bounce_buffer); - } - - /* setup dma direction */ - if (!dir_in) - cntr |= CNTR_DDIR; - - /* remember direction */ - wh->dma_dir = dir_in; - - regs->CNTR = cntr; - - /* setup DMA *physical* address */ - regs->ACR = addr; - - if (dir_in) { - /* invalidate any cache */ - cache_clear(addr, cmd->SCp.this_residual); - } else { - /* push any dirty cache */ - cache_push(addr, cmd->SCp.this_residual); - } - - /* start DMA */ - mb(); /* make sure setup is completed */ - regs->ST_DMA = 1; - mb(); /* make sure DMA has started before next IO */ - - /* return success */ - return 0; -} - -static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, - int status) -{ - struct a3000_hostdata *hdata = shost_priv(instance); - struct WD33C93_hostdata *wh = &hdata->wh; - struct a3000_scsiregs *regs = hdata->regs; - - /* disable SCSI interrupts */ - unsigned short cntr = CNTR_PDMD; - - if (!wh->dma_dir) - cntr |= CNTR_DDIR; - - regs->CNTR = cntr; - mb(); /* make sure CNTR is updated before next IO */ - - /* flush if we were reading */ - if (wh->dma_dir) { - regs->FLUSH = 1; - mb(); /* don't allow prefetch */ - while (!(regs->ISTR & ISTR_FE_FLG)) - barrier(); - mb(); /* no IO until FLUSH is done */ - } - - /* clear a possible interrupt */ - /* I think that this CINT is only necessary if you are - * using the terminal count features. HM 7 Mar 1994 - */ - regs->CINT = 1; - - /* stop DMA */ - regs->SP_DMA = 1; - mb(); /* make sure DMA is stopped before next IO */ - - /* restore the CONTROL bits (minus the direction flag) */ - regs->CNTR = CNTR_PDMD | CNTR_INTEN; - mb(); /* make sure CNTR is updated before next IO */ - - /* copy from a bounce buffer, if necessary */ - if (status && wh->dma_bounce_buffer) { - if (SCpnt) { - if (wh->dma_dir && SCpnt) - memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer, - SCpnt->SCp.this_residual); - kfree(wh->dma_bounce_buffer); - wh->dma_bounce_buffer = NULL; - wh->dma_bounce_len = 0; - } else { - kfree(wh->dma_bounce_buffer); - wh->dma_bounce_buffer = NULL; - wh->dma_bounce_len = 0; - } - } -} - -static int a3000_bus_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *instance = cmd->device->host; - - /* FIXME perform bus-specific reset */ - - /* FIXME 2: kill this entire function, which should - cause mid-layer to call wd33c93_host_reset anyway? */ - - spin_lock_irq(instance->host_lock); - wd33c93_host_reset(cmd); - spin_unlock_irq(instance->host_lock); - - return SUCCESS; -} - -static struct scsi_host_template amiga_a3000_scsi_template = { - .module = THIS_MODULE, - .name = "Amiga 3000 built-in SCSI", - .proc_info = wd33c93_proc_info, - .proc_name = "A3000", - .queuecommand = wd33c93_queuecommand, - .eh_abort_handler = wd33c93_abort, - .eh_bus_reset_handler = a3000_bus_reset, - .eh_host_reset_handler = wd33c93_host_reset, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING -}; - -static int __init amiga_a3000_scsi_probe(struct platform_device *pdev) -{ - struct resource *res; - struct Scsi_Host *instance; - int error; - struct a3000_scsiregs *regs; - wd33c93_regs wdregs; - struct a3000_hostdata *hdata; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - if (!request_mem_region(res->start, resource_size(res), "wd33c93")) - return -EBUSY; - - instance = scsi_host_alloc(&amiga_a3000_scsi_template, - sizeof(struct a3000_hostdata)); - if (!instance) { - error = -ENOMEM; - goto fail_alloc; - } - - instance->irq = IRQ_AMIGA_PORTS; - - regs = (struct a3000_scsiregs *)ZTWO_VADDR(res->start); - regs->DAWR = DAWR_A3000; - - wdregs.SASR = ®s->SASR; - wdregs.SCMD = ®s->SCMD; - - hdata = shost_priv(instance); - hdata->wh.no_sync = 0xff; - hdata->wh.fast = 0; - hdata->wh.dma_mode = CTRL_DMA; - hdata->regs = regs; - - wd33c93_init(instance, wdregs, dma_setup, dma_stop, WD33C93_FS_12_15); - error = request_irq(IRQ_AMIGA_PORTS, a3000_intr, IRQF_SHARED, - "A3000 SCSI", instance); - if (error) - goto fail_irq; - - regs->CNTR = CNTR_PDMD | CNTR_INTEN; - - error = scsi_add_host(instance, NULL); - if (error) - goto fail_host; - - platform_set_drvdata(pdev, instance); - - scsi_scan_host(instance); - return 0; - -fail_host: - free_irq(IRQ_AMIGA_PORTS, instance); -fail_irq: - scsi_host_put(instance); -fail_alloc: - release_mem_region(res->start, resource_size(res)); - return error; -} - -static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) -{ - struct Scsi_Host *instance = platform_get_drvdata(pdev); - struct a3000_hostdata *hdata = shost_priv(instance); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - hdata->regs->CNTR = 0; - scsi_remove_host(instance); - free_irq(IRQ_AMIGA_PORTS, instance); - scsi_host_put(instance); - release_mem_region(res->start, resource_size(res)); - return 0; -} - -static struct platform_driver amiga_a3000_scsi_driver = { - .remove = __exit_p(amiga_a3000_scsi_remove), - .driver = { - .name = "amiga-a3000-scsi", - .owner = THIS_MODULE, - }, -}; - -static int __init amiga_a3000_scsi_init(void) -{ - return platform_driver_probe(&amiga_a3000_scsi_driver, - amiga_a3000_scsi_probe); -} -module_init(amiga_a3000_scsi_init); - -static void __exit amiga_a3000_scsi_exit(void) -{ - platform_driver_unregister(&amiga_a3000_scsi_driver); -} -module_exit(amiga_a3000_scsi_exit); - -MODULE_DESCRIPTION("Amiga 3000 built-in SCSI"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:amiga-a3000-scsi"); diff --git a/ANDROID_3.4.5/drivers/scsi/a3000.h b/ANDROID_3.4.5/drivers/scsi/a3000.h deleted file mode 100644 index 49db4a33..00000000 --- a/ANDROID_3.4.5/drivers/scsi/a3000.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef A3000_H -#define A3000_H - -/* $Id: a3000.h,v 1.4 1997/01/19 23:07:10 davem Exp $ - * - * Header file for the Amiga 3000 built-in SCSI controller for Linux - * - * Written and (C) 1993, Hamish Macdonald, see a3000.c for more info - * - */ - -#include - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 16 -#endif - -/* - * if the transfer address ANDed with this results in a non-zero - * result, then we can't use DMA. - */ -#define A3000_XFER_MASK (0x00000003) - -struct a3000_scsiregs { - unsigned char pad1[2]; - volatile unsigned short DAWR; - volatile unsigned int WTC; - unsigned char pad2[2]; - volatile unsigned short CNTR; - volatile unsigned long ACR; - unsigned char pad3[2]; - volatile unsigned short ST_DMA; - unsigned char pad4[2]; - volatile unsigned short FLUSH; - unsigned char pad5[2]; - volatile unsigned short CINT; - unsigned char pad6[2]; - volatile unsigned short ISTR; - unsigned char pad7[30]; - volatile unsigned short SP_DMA; - unsigned char pad8; - volatile unsigned char SASR; - unsigned char pad9; - volatile unsigned char SCMD; -}; - -#define DAWR_A3000 (3) - -/* CNTR bits. */ -#define CNTR_TCEN (1<<5) -#define CNTR_PREST (1<<4) -#define CNTR_PDMD (1<<3) -#define CNTR_INTEN (1<<2) -#define CNTR_DDIR (1<<1) -#define CNTR_IO_DX (1<<0) - -/* ISTR bits. */ -#define ISTR_INTX (1<<8) -#define ISTR_INT_F (1<<7) -#define ISTR_INTS (1<<6) -#define ISTR_E_INT (1<<5) -#define ISTR_INT_P (1<<4) -#define ISTR_UE_INT (1<<3) -#define ISTR_OE_INT (1<<2) -#define ISTR_FF_FLG (1<<1) -#define ISTR_FE_FLG (1<<0) - -#endif /* A3000_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/a4000t.c b/ANDROID_3.4.5/drivers/scsi/a4000t.c deleted file mode 100644 index 23c76f41..00000000 --- a/ANDROID_3.4.5/drivers/scsi/a4000t.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux. - * Amiga Technologies A4000T SCSI controller. - * - * Written 1997 by Alan Hourihane - * plus modifications of the 53c7xx.c driver to support the Amiga. - * - * Rewritten to use 53c700.c by Kars de Jong - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "53c700.h" - - -static struct scsi_host_template a4000t_scsi_driver_template = { - .name = "A4000T builtin SCSI", - .proc_name = "A4000t", - .this_id = 7, - .module = THIS_MODULE, -}; - - -#define A4000T_SCSI_OFFSET 0x40 - -static int __init amiga_a4000t_scsi_probe(struct platform_device *pdev) -{ - struct resource *res; - phys_addr_t scsi_addr; - struct NCR_700_Host_Parameters *hostdata; - struct Scsi_Host *host; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - if (!request_mem_region(res->start, resource_size(res), - "A4000T builtin SCSI")) - return -EBUSY; - - hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), - GFP_KERNEL); - if (!hostdata) { - dev_err(&pdev->dev, "Failed to allocate host data\n"); - goto out_release; - } - - scsi_addr = res->start + A4000T_SCSI_OFFSET; - - /* Fill in the required pieces of hostdata */ - hostdata->base = (void __iomem *)ZTWO_VADDR(scsi_addr); - hostdata->clock = 50; - hostdata->chip710 = 1; - hostdata->dmode_extra = DMODE_FC2; - hostdata->dcntl_extra = EA_710; - - /* and register the chip */ - host = NCR_700_detect(&a4000t_scsi_driver_template, hostdata, - &pdev->dev); - if (!host) { - dev_err(&pdev->dev, - "No host detected; board configuration problem?\n"); - goto out_free; - } - - host->this_id = 7; - host->base = scsi_addr; - host->irq = IRQ_AMIGA_PORTS; - - if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "a4000t-scsi", - host)) { - dev_err(&pdev->dev, "request_irq failed\n"); - goto out_put_host; - } - - platform_set_drvdata(pdev, host); - scsi_scan_host(host); - return 0; - - out_put_host: - scsi_host_put(host); - out_free: - kfree(hostdata); - out_release: - release_mem_region(res->start, resource_size(res)); - return -ENODEV; -} - -static int __exit amiga_a4000t_scsi_remove(struct platform_device *pdev) -{ - struct Scsi_Host *host = platform_get_drvdata(pdev); - struct NCR_700_Host_Parameters *hostdata = shost_priv(host); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - scsi_remove_host(host); - NCR_700_release(host); - kfree(hostdata); - free_irq(host->irq, host); - release_mem_region(res->start, resource_size(res)); - return 0; -} - -static struct platform_driver amiga_a4000t_scsi_driver = { - .remove = __exit_p(amiga_a4000t_scsi_remove), - .driver = { - .name = "amiga-a4000t-scsi", - .owner = THIS_MODULE, - }, -}; - -static int __init amiga_a4000t_scsi_init(void) -{ - return platform_driver_probe(&amiga_a4000t_scsi_driver, - amiga_a4000t_scsi_probe); -} - -module_init(amiga_a4000t_scsi_init); - -static void __exit amiga_a4000t_scsi_exit(void) -{ - platform_driver_unregister(&amiga_a4000t_scsi_driver); -} - -module_exit(amiga_a4000t_scsi_exit); - -MODULE_AUTHOR("Alan Hourihane / " - "Kars de Jong "); -MODULE_DESCRIPTION("Amiga A4000T NCR53C710 driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:amiga-a4000t-scsi"); diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/Makefile b/ANDROID_3.4.5/drivers/scsi/aacraid/Makefile deleted file mode 100644 index 1bd9fd18..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# Adaptec aacraid - -obj-$(CONFIG_SCSI_AACRAID) := aacraid.o - -aacraid-objs := linit.o aachba.o commctrl.o comminit.o commsup.o \ - dpcsup.o rx.o sa.o rkt.o nark.o src.o - -ccflags-y := -Idrivers/scsi diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/TODO b/ANDROID_3.4.5/drivers/scsi/aacraid/TODO deleted file mode 100644 index 78dc863e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/TODO +++ /dev/null @@ -1,3 +0,0 @@ -o Testing -o More testing -o I/O size increase diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/aachba.c b/ANDROID_3.4.5/drivers/scsi/aacraid/aachba.c deleted file mode 100644 index 52551662..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/aachba.c +++ /dev/null @@ -1,3011 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For flush_kernel_dcache_page */ -#include - -#include -#include -#include -#include - -#include "aacraid.h" - -/* values for inqd_pdt: Peripheral device type in plain English */ -#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ -#define INQD_PDT_PROC 0x03 /* Processor device */ -#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ -#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ -#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ -#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ - -#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ -#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ - -/* - * Sense codes - */ - -#define SENCODE_NO_SENSE 0x00 -#define SENCODE_END_OF_DATA 0x00 -#define SENCODE_BECOMING_READY 0x04 -#define SENCODE_INIT_CMD_REQUIRED 0x04 -#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A -#define SENCODE_INVALID_COMMAND 0x20 -#define SENCODE_LBA_OUT_OF_RANGE 0x21 -#define SENCODE_INVALID_CDB_FIELD 0x24 -#define SENCODE_LUN_NOT_SUPPORTED 0x25 -#define SENCODE_INVALID_PARAM_FIELD 0x26 -#define SENCODE_PARAM_NOT_SUPPORTED 0x26 -#define SENCODE_PARAM_VALUE_INVALID 0x26 -#define SENCODE_RESET_OCCURRED 0x29 -#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E -#define SENCODE_INQUIRY_DATA_CHANGED 0x3F -#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 -#define SENCODE_DIAGNOSTIC_FAILURE 0x40 -#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 -#define SENCODE_INVALID_MESSAGE_ERROR 0x49 -#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c -#define SENCODE_OVERLAPPED_COMMAND 0x4E - -/* - * Additional sense codes - */ - -#define ASENCODE_NO_SENSE 0x00 -#define ASENCODE_END_OF_DATA 0x05 -#define ASENCODE_BECOMING_READY 0x01 -#define ASENCODE_INIT_CMD_REQUIRED 0x02 -#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 -#define ASENCODE_INVALID_COMMAND 0x00 -#define ASENCODE_LBA_OUT_OF_RANGE 0x00 -#define ASENCODE_INVALID_CDB_FIELD 0x00 -#define ASENCODE_LUN_NOT_SUPPORTED 0x00 -#define ASENCODE_INVALID_PARAM_FIELD 0x00 -#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 -#define ASENCODE_PARAM_VALUE_INVALID 0x02 -#define ASENCODE_RESET_OCCURRED 0x00 -#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 -#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 -#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 -#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 -#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 -#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 -#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 -#define ASENCODE_OVERLAPPED_COMMAND 0x00 - -#define BYTE0(x) (unsigned char)(x) -#define BYTE1(x) (unsigned char)((x) >> 8) -#define BYTE2(x) (unsigned char)((x) >> 16) -#define BYTE3(x) (unsigned char)((x) >> 24) - -/*------------------------------------------------------------------------------ - * S T R U C T S / T Y P E D E F S - *----------------------------------------------------------------------------*/ -/* SCSI inquiry data */ -struct inquiry_data { - u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ - u8 inqd_dtq; /* RMB | Device Type Qualifier */ - u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ - u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ - u8 inqd_len; /* Additional length (n-4) */ - u8 inqd_pad1[2];/* Reserved - must be zero */ - u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ - u8 inqd_vid[8]; /* Vendor ID */ - u8 inqd_pid[16];/* Product ID */ - u8 inqd_prl[4]; /* Product Revision Level */ -}; - -/* - * M O D U L E G L O B A L S - */ - -static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap); -static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg); -static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg); -static int aac_send_srb_fib(struct scsi_cmnd* scsicmd); -#ifdef AAC_DETAILED_STATUS_INFO -static char *aac_get_status_string(u32 status); -#endif - -/* - * Non dasd selection is handled entirely in aachba now - */ - -static int nondasd = -1; -static int aac_cache = 2; /* WCE=0 to avoid performance problems */ -static int dacmode = -1; -int aac_msi; -int aac_commit = -1; -int startup_timeout = 180; -int aif_timeout = 120; -int aac_sync_mode; /* Only Sync. transfer - disabled */ - -module_param(aac_sync_mode, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(aac_sync_mode, "Force sync. transfer mode" - " 0=off, 1=on"); -module_param(nondasd, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices." - " 0=off, 1=on"); -module_param_named(cache, aac_cache, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(cache, "Disable Queue Flush commands:\n" - "\tbit 0 - Disable FUA in WRITE SCSI commands\n" - "\tbit 1 - Disable SYNCHRONIZE_CACHE SCSI command\n" - "\tbit 2 - Disable only if Battery is protecting Cache"); -module_param(dacmode, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC." - " 0=off, 1=on"); -module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the" - " adapter for foreign arrays.\n" - "This is typically needed in systems that do not have a BIOS." - " 0=off, 1=on"); -module_param_named(msi, aac_msi, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(msi, "IRQ handling." - " 0=PIC(default), 1=MSI, 2=MSI-X(unsupported, uses MSI)"); -module_param(startup_timeout, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for" - " adapter to have it's kernel up and\n" - "running. This is typically adjusted for large systems that do not" - " have a BIOS."); -module_param(aif_timeout, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(aif_timeout, "The duration of time in seconds to wait for" - " applications to pick up AIFs before\n" - "deregistering them. This is typically adjusted for heavily burdened" - " systems."); - -int numacb = -1; -module_param(numacb, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(numacb, "Request a limit to the number of adapter control" - " blocks (FIB) allocated. Valid values are 512 and down. Default is" - " to use suggestion from Firmware."); - -int acbsize = -1; -module_param(acbsize, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(acbsize, "Request a specific adapter control block (FIB)" - " size. Valid values are 512, 2048, 4096 and 8192. Default is to use" - " suggestion from Firmware."); - -int update_interval = 30 * 60; -module_param(update_interval, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(update_interval, "Interval in seconds between time sync" - " updates issued to adapter."); - -int check_interval = 24 * 60 * 60; -module_param(check_interval, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(check_interval, "Interval in seconds between adapter health" - " checks."); - -int aac_check_reset = 1; -module_param_named(check_reset, aac_check_reset, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(check_reset, "If adapter fails health check, reset the" - " adapter. a value of -1 forces the reset to adapters programmed to" - " ignore it."); - -int expose_physicals = -1; -module_param(expose_physicals, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays." - " -1=protect 0=off, 1=on"); - -int aac_reset_devices; -module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization."); - -int aac_wwn = 1; -module_param_named(wwn, aac_wwn, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(wwn, "Select a WWN type for the arrays:\n" - "\t0 - Disable\n" - "\t1 - Array Meta Data Signature (default)\n" - "\t2 - Adapter Serial Number"); - - -static inline int aac_valid_context(struct scsi_cmnd *scsicmd, - struct fib *fibptr) { - struct scsi_device *device; - - if (unlikely(!scsicmd || !scsicmd->scsi_done)) { - dprintk((KERN_WARNING "aac_valid_context: scsi command corrupt\n")); - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - return 0; - } - scsicmd->SCp.phase = AAC_OWNER_MIDLEVEL; - device = scsicmd->device; - if (unlikely(!device || !scsi_device_online(device))) { - dprintk((KERN_WARNING "aac_valid_context: scsi device corrupt\n")); - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - return 0; - } - return 1; -} - -/** - * aac_get_config_status - check the adapter configuration - * @common: adapter to query - * - * Query config status, and commit the configuration if needed. - */ -int aac_get_config_status(struct aac_dev *dev, int commit_flag) -{ - int status = 0; - struct fib * fibptr; - - if (!(fibptr = aac_fib_alloc(dev))) - return -ENOMEM; - - aac_fib_init(fibptr); - { - struct aac_get_config_status *dinfo; - dinfo = (struct aac_get_config_status *) fib_data(fibptr); - - dinfo->command = cpu_to_le32(VM_ContainerConfig); - dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS); - dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data)); - } - - status = aac_fib_send(ContainerCommand, - fibptr, - sizeof (struct aac_get_config_status), - FsaNormal, - 1, 1, - NULL, NULL); - if (status < 0) { - printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n"); - } else { - struct aac_get_config_status_resp *reply - = (struct aac_get_config_status_resp *) fib_data(fibptr); - dprintk((KERN_WARNING - "aac_get_config_status: response=%d status=%d action=%d\n", - le32_to_cpu(reply->response), - le32_to_cpu(reply->status), - le32_to_cpu(reply->data.action))); - if ((le32_to_cpu(reply->response) != ST_OK) || - (le32_to_cpu(reply->status) != CT_OK) || - (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) { - printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n"); - status = -EINVAL; - } - } - /* Do not set XferState to zero unless receives a response from F/W */ - if (status >= 0) - aac_fib_complete(fibptr); - - /* Send a CT_COMMIT_CONFIG to enable discovery of devices */ - if (status >= 0) { - if ((aac_commit == 1) || commit_flag) { - struct aac_commit_config * dinfo; - aac_fib_init(fibptr); - dinfo = (struct aac_commit_config *) fib_data(fibptr); - - dinfo->command = cpu_to_le32(VM_ContainerConfig); - dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG); - - status = aac_fib_send(ContainerCommand, - fibptr, - sizeof (struct aac_commit_config), - FsaNormal, - 1, 1, - NULL, NULL); - /* Do not set XferState to zero unless - * receives a response from F/W */ - if (status >= 0) - aac_fib_complete(fibptr); - } else if (aac_commit == 0) { - printk(KERN_WARNING - "aac_get_config_status: Foreign device configurations are being ignored\n"); - } - } - /* FIB should be freed only after getting the response from the F/W */ - if (status != -ERESTARTSYS) - aac_fib_free(fibptr); - return status; -} - -static void aac_expose_phy_device(struct scsi_cmnd *scsicmd) -{ - char inq_data; - scsi_sg_copy_to_buffer(scsicmd, &inq_data, sizeof(inq_data)); - if ((inq_data & 0x20) && (inq_data & 0x1f) == TYPE_DISK) { - inq_data &= 0xdf; - scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); - } -} - -/** - * aac_get_containers - list containers - * @common: adapter to probe - * - * Make a list of all containers on this controller - */ -int aac_get_containers(struct aac_dev *dev) -{ - struct fsa_dev_info *fsa_dev_ptr; - u32 index; - int status = 0; - struct fib * fibptr; - struct aac_get_container_count *dinfo; - struct aac_get_container_count_resp *dresp; - int maximum_num_containers = MAXIMUM_NUM_CONTAINERS; - - if (!(fibptr = aac_fib_alloc(dev))) - return -ENOMEM; - - aac_fib_init(fibptr); - dinfo = (struct aac_get_container_count *) fib_data(fibptr); - dinfo->command = cpu_to_le32(VM_ContainerConfig); - dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT); - - status = aac_fib_send(ContainerCommand, - fibptr, - sizeof (struct aac_get_container_count), - FsaNormal, - 1, 1, - NULL, NULL); - if (status >= 0) { - dresp = (struct aac_get_container_count_resp *)fib_data(fibptr); - maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries); - aac_fib_complete(fibptr); - } - /* FIB should be freed only after getting the response from the F/W */ - if (status != -ERESTARTSYS) - aac_fib_free(fibptr); - - if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS) - maximum_num_containers = MAXIMUM_NUM_CONTAINERS; - fsa_dev_ptr = kzalloc(sizeof(*fsa_dev_ptr) * maximum_num_containers, - GFP_KERNEL); - if (!fsa_dev_ptr) - return -ENOMEM; - - dev->fsa_dev = fsa_dev_ptr; - dev->maximum_num_containers = maximum_num_containers; - - for (index = 0; index < dev->maximum_num_containers; ) { - fsa_dev_ptr[index].devname[0] = '\0'; - - status = aac_probe_container(dev, index); - - if (status < 0) { - printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n"); - break; - } - - /* - * If there are no more containers, then stop asking. - */ - if (++index >= status) - break; - } - return status; -} - -static void get_container_name_callback(void *context, struct fib * fibptr) -{ - struct aac_get_name_resp * get_name_reply; - struct scsi_cmnd * scsicmd; - - scsicmd = (struct scsi_cmnd *) context; - - if (!aac_valid_context(scsicmd, fibptr)) - return; - - dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies)); - BUG_ON(fibptr == NULL); - - get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr); - /* Failure is irrelevant, using default value instead */ - if ((le32_to_cpu(get_name_reply->status) == CT_OK) - && (get_name_reply->data[0] != '\0')) { - char *sp = get_name_reply->data; - sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0'; - while (*sp == ' ') - ++sp; - if (*sp) { - struct inquiry_data inq; - char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]; - int count = sizeof(d); - char *dp = d; - do { - *dp++ = (*sp) ? *sp++ : ' '; - } while (--count > 0); - - scsi_sg_copy_to_buffer(scsicmd, &inq, sizeof(inq)); - memcpy(inq.inqd_pid, d, sizeof(d)); - scsi_sg_copy_from_buffer(scsicmd, &inq, sizeof(inq)); - } - } - - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - scsicmd->scsi_done(scsicmd); -} - -/** - * aac_get_container_name - get container name, none blocking. - */ -static int aac_get_container_name(struct scsi_cmnd * scsicmd) -{ - int status; - struct aac_get_name *dinfo; - struct fib * cmd_fibcontext; - struct aac_dev * dev; - - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - - if (!(cmd_fibcontext = aac_fib_alloc(dev))) - return -ENOMEM; - - aac_fib_init(cmd_fibcontext); - dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext); - - dinfo->command = cpu_to_le32(VM_ContainerConfig); - dinfo->type = cpu_to_le32(CT_READ_NAME); - dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); - dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data)); - - status = aac_fib_send(ContainerCommand, - cmd_fibcontext, - sizeof (struct aac_get_name), - FsaNormal, - 0, 1, - (fib_callback)get_container_name_callback, - (void *) scsicmd); - - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - - printk(KERN_WARNING "aac_get_container_name: aac_fib_send failed with status: %d.\n", status); - aac_fib_complete(cmd_fibcontext); - aac_fib_free(cmd_fibcontext); - return -1; -} - -static int aac_probe_container_callback2(struct scsi_cmnd * scsicmd) -{ - struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; - - if ((fsa_dev_ptr[scmd_id(scsicmd)].valid & 1)) - return aac_scsi_cmd(scsicmd); - - scsicmd->result = DID_NO_CONNECT << 16; - scsicmd->scsi_done(scsicmd); - return 0; -} - -static void _aac_probe_container2(void * context, struct fib * fibptr) -{ - struct fsa_dev_info *fsa_dev_ptr; - int (*callback)(struct scsi_cmnd *); - struct scsi_cmnd * scsicmd = (struct scsi_cmnd *)context; - - - if (!aac_valid_context(scsicmd, fibptr)) - return; - - scsicmd->SCp.Status = 0; - fsa_dev_ptr = fibptr->dev->fsa_dev; - if (fsa_dev_ptr) { - struct aac_mount * dresp = (struct aac_mount *) fib_data(fibptr); - fsa_dev_ptr += scmd_id(scsicmd); - - if ((le32_to_cpu(dresp->status) == ST_OK) && - (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) && - (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) { - fsa_dev_ptr->valid = 1; - /* sense_key holds the current state of the spin-up */ - if (dresp->mnt[0].state & cpu_to_le32(FSCS_NOT_READY)) - fsa_dev_ptr->sense_data.sense_key = NOT_READY; - else if (fsa_dev_ptr->sense_data.sense_key == NOT_READY) - fsa_dev_ptr->sense_data.sense_key = NO_SENSE; - fsa_dev_ptr->type = le32_to_cpu(dresp->mnt[0].vol); - fsa_dev_ptr->size - = ((u64)le32_to_cpu(dresp->mnt[0].capacity)) + - (((u64)le32_to_cpu(dresp->mnt[0].capacityhigh)) << 32); - fsa_dev_ptr->ro = ((le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY) != 0); - } - if ((fsa_dev_ptr->valid & 1) == 0) - fsa_dev_ptr->valid = 0; - scsicmd->SCp.Status = le32_to_cpu(dresp->count); - } - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - callback = (int (*)(struct scsi_cmnd *))(scsicmd->SCp.ptr); - scsicmd->SCp.ptr = NULL; - (*callback)(scsicmd); - return; -} - -static void _aac_probe_container1(void * context, struct fib * fibptr) -{ - struct scsi_cmnd * scsicmd; - struct aac_mount * dresp; - struct aac_query_mount *dinfo; - int status; - - dresp = (struct aac_mount *) fib_data(fibptr); - dresp->mnt[0].capacityhigh = 0; - if ((le32_to_cpu(dresp->status) != ST_OK) || - (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) { - _aac_probe_container2(context, fibptr); - return; - } - scsicmd = (struct scsi_cmnd *) context; - - if (!aac_valid_context(scsicmd, fibptr)) - return; - - aac_fib_init(fibptr); - - dinfo = (struct aac_query_mount *)fib_data(fibptr); - - dinfo->command = cpu_to_le32(VM_NameServe64); - dinfo->count = cpu_to_le32(scmd_id(scsicmd)); - dinfo->type = cpu_to_le32(FT_FILESYS); - - status = aac_fib_send(ContainerCommand, - fibptr, - sizeof(struct aac_query_mount), - FsaNormal, - 0, 1, - _aac_probe_container2, - (void *) scsicmd); - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - else if (status < 0) { - /* Inherit results from VM_NameServe, if any */ - dresp->status = cpu_to_le32(ST_OK); - _aac_probe_container2(context, fibptr); - } -} - -static int _aac_probe_container(struct scsi_cmnd * scsicmd, int (*callback)(struct scsi_cmnd *)) -{ - struct fib * fibptr; - int status = -ENOMEM; - - if ((fibptr = aac_fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) { - struct aac_query_mount *dinfo; - - aac_fib_init(fibptr); - - dinfo = (struct aac_query_mount *)fib_data(fibptr); - - dinfo->command = cpu_to_le32(VM_NameServe); - dinfo->count = cpu_to_le32(scmd_id(scsicmd)); - dinfo->type = cpu_to_le32(FT_FILESYS); - scsicmd->SCp.ptr = (char *)callback; - - status = aac_fib_send(ContainerCommand, - fibptr, - sizeof(struct aac_query_mount), - FsaNormal, - 0, 1, - _aac_probe_container1, - (void *) scsicmd); - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - if (status < 0) { - scsicmd->SCp.ptr = NULL; - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - } - } - if (status < 0) { - struct fsa_dev_info *fsa_dev_ptr = ((struct aac_dev *)(scsicmd->device->host->hostdata))->fsa_dev; - if (fsa_dev_ptr) { - fsa_dev_ptr += scmd_id(scsicmd); - if ((fsa_dev_ptr->valid & 1) == 0) { - fsa_dev_ptr->valid = 0; - return (*callback)(scsicmd); - } - } - } - return status; -} - -/** - * aac_probe_container - query a logical volume - * @dev: device to query - * @cid: container identifier - * - * Queries the controller about the given volume. The volume information - * is updated in the struct fsa_dev_info structure rather than returned. - */ -static int aac_probe_container_callback1(struct scsi_cmnd * scsicmd) -{ - scsicmd->device = NULL; - return 0; -} - -int aac_probe_container(struct aac_dev *dev, int cid) -{ - struct scsi_cmnd *scsicmd = kmalloc(sizeof(*scsicmd), GFP_KERNEL); - struct scsi_device *scsidev = kmalloc(sizeof(*scsidev), GFP_KERNEL); - int status; - - if (!scsicmd || !scsidev) { - kfree(scsicmd); - kfree(scsidev); - return -ENOMEM; - } - scsicmd->list.next = NULL; - scsicmd->scsi_done = (void (*)(struct scsi_cmnd*))aac_probe_container_callback1; - - scsicmd->device = scsidev; - scsidev->sdev_state = 0; - scsidev->id = cid; - scsidev->host = dev->scsi_host_ptr; - - if (_aac_probe_container(scsicmd, aac_probe_container_callback1) == 0) - while (scsicmd->device == scsidev) - schedule(); - kfree(scsidev); - status = scsicmd->SCp.Status; - kfree(scsicmd); - return status; -} - -/* Local Structure to set SCSI inquiry data strings */ -struct scsi_inq { - char vid[8]; /* Vendor ID */ - char pid[16]; /* Product ID */ - char prl[4]; /* Product Revision Level */ -}; - -/** - * InqStrCopy - string merge - * @a: string to copy from - * @b: string to copy to - * - * Copy a String from one location to another - * without copying \0 - */ - -static void inqstrcpy(char *a, char *b) -{ - - while (*a != (char)0) - *b++ = *a++; -} - -static char *container_types[] = { - "None", - "Volume", - "Mirror", - "Stripe", - "RAID5", - "SSRW", - "SSRO", - "Morph", - "Legacy", - "RAID4", - "RAID10", - "RAID00", - "V-MIRRORS", - "PSEUDO R4", - "RAID50", - "RAID5D", - "RAID5D0", - "RAID1E", - "RAID6", - "RAID60", - "Unknown" -}; - -char * get_container_type(unsigned tindex) -{ - if (tindex >= ARRAY_SIZE(container_types)) - tindex = ARRAY_SIZE(container_types) - 1; - return container_types[tindex]; -} - -/* Function: setinqstr - * - * Arguments: [1] pointer to void [1] int - * - * Purpose: Sets SCSI inquiry data strings for vendor, product - * and revision level. Allows strings to be set in platform dependent - * files instead of in OS dependent driver source. - */ - -static void setinqstr(struct aac_dev *dev, void *data, int tindex) -{ - struct scsi_inq *str; - - str = (struct scsi_inq *)(data); /* cast data to scsi inq block */ - memset(str, ' ', sizeof(*str)); - - if (dev->supplement_adapter_info.AdapterTypeText[0]) { - char * cp = dev->supplement_adapter_info.AdapterTypeText; - int c; - if ((cp[0] == 'A') && (cp[1] == 'O') && (cp[2] == 'C')) - inqstrcpy("SMC", str->vid); - else { - c = sizeof(str->vid); - while (*cp && *cp != ' ' && --c) - ++cp; - c = *cp; - *cp = '\0'; - inqstrcpy (dev->supplement_adapter_info.AdapterTypeText, - str->vid); - *cp = c; - while (*cp && *cp != ' ') - ++cp; - } - while (*cp == ' ') - ++cp; - /* last six chars reserved for vol type */ - c = 0; - if (strlen(cp) > sizeof(str->pid)) { - c = cp[sizeof(str->pid)]; - cp[sizeof(str->pid)] = '\0'; - } - inqstrcpy (cp, str->pid); - if (c) - cp[sizeof(str->pid)] = c; - } else { - struct aac_driver_ident *mp = aac_get_driver_ident(dev->cardtype); - - inqstrcpy (mp->vname, str->vid); - /* last six chars reserved for vol type */ - inqstrcpy (mp->model, str->pid); - } - - if (tindex < ARRAY_SIZE(container_types)){ - char *findit = str->pid; - - for ( ; *findit != ' '; findit++); /* walk till we find a space */ - /* RAID is superfluous in the context of a RAID device */ - if (memcmp(findit-4, "RAID", 4) == 0) - *(findit -= 4) = ' '; - if (((findit - str->pid) + strlen(container_types[tindex])) - < (sizeof(str->pid) + sizeof(str->prl))) - inqstrcpy (container_types[tindex], findit + 1); - } - inqstrcpy ("V1.0", str->prl); -} - -static void get_container_serial_callback(void *context, struct fib * fibptr) -{ - struct aac_get_serial_resp * get_serial_reply; - struct scsi_cmnd * scsicmd; - - BUG_ON(fibptr == NULL); - - scsicmd = (struct scsi_cmnd *) context; - if (!aac_valid_context(scsicmd, fibptr)) - return; - - get_serial_reply = (struct aac_get_serial_resp *) fib_data(fibptr); - /* Failure is irrelevant, using default value instead */ - if (le32_to_cpu(get_serial_reply->status) == CT_OK) { - char sp[13]; - /* EVPD bit set */ - sp[0] = INQD_PDT_DA; - sp[1] = scsicmd->cmnd[2]; - sp[2] = 0; - sp[3] = snprintf(sp+4, sizeof(sp)-4, "%08X", - le32_to_cpu(get_serial_reply->uid)); - scsi_sg_copy_from_buffer(scsicmd, sp, sizeof(sp)); - } - - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - scsicmd->scsi_done(scsicmd); -} - -/** - * aac_get_container_serial - get container serial, none blocking. - */ -static int aac_get_container_serial(struct scsi_cmnd * scsicmd) -{ - int status; - struct aac_get_serial *dinfo; - struct fib * cmd_fibcontext; - struct aac_dev * dev; - - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - - if (!(cmd_fibcontext = aac_fib_alloc(dev))) - return -ENOMEM; - - aac_fib_init(cmd_fibcontext); - dinfo = (struct aac_get_serial *) fib_data(cmd_fibcontext); - - dinfo->command = cpu_to_le32(VM_ContainerConfig); - dinfo->type = cpu_to_le32(CT_CID_TO_32BITS_UID); - dinfo->cid = cpu_to_le32(scmd_id(scsicmd)); - - status = aac_fib_send(ContainerCommand, - cmd_fibcontext, - sizeof (struct aac_get_serial), - FsaNormal, - 0, 1, - (fib_callback) get_container_serial_callback, - (void *) scsicmd); - - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - - printk(KERN_WARNING "aac_get_container_serial: aac_fib_send failed with status: %d.\n", status); - aac_fib_complete(cmd_fibcontext); - aac_fib_free(cmd_fibcontext); - return -1; -} - -/* Function: setinqserial - * - * Arguments: [1] pointer to void [1] int - * - * Purpose: Sets SCSI Unit Serial number. - * This is a fake. We should read a proper - * serial number from the container. But - * without docs it's quite hard to do it :-) - * So this will have to do in the meantime. - */ - -static int setinqserial(struct aac_dev *dev, void *data, int cid) -{ - /* - * This breaks array migration. - */ - return snprintf((char *)(data), sizeof(struct scsi_inq) - 4, "%08X%02X", - le32_to_cpu(dev->adapter_info.serial[0]), cid); -} - -static inline void set_sense(struct sense_data *sense_data, u8 sense_key, - u8 sense_code, u8 a_sense_code, u8 bit_pointer, u16 field_pointer) -{ - u8 *sense_buf = (u8 *)sense_data; - /* Sense data valid, err code 70h */ - sense_buf[0] = 0x70; /* No info field */ - sense_buf[1] = 0; /* Segment number, always zero */ - - sense_buf[2] = sense_key; /* Sense key */ - - sense_buf[12] = sense_code; /* Additional sense code */ - sense_buf[13] = a_sense_code; /* Additional sense code qualifier */ - - if (sense_key == ILLEGAL_REQUEST) { - sense_buf[7] = 10; /* Additional sense length */ - - sense_buf[15] = bit_pointer; - /* Illegal parameter is in the parameter block */ - if (sense_code == SENCODE_INVALID_CDB_FIELD) - sense_buf[15] |= 0xc0;/* Std sense key specific field */ - /* Illegal parameter is in the CDB block */ - sense_buf[16] = field_pointer >> 8; /* MSB */ - sense_buf[17] = field_pointer; /* LSB */ - } else - sense_buf[7] = 6; /* Additional sense length */ -} - -static int aac_bounds_32(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) -{ - if (lba & 0xffffffff00000000LL) { - int cid = scmd_id(cmd); - dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); - cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); - memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - cmd->scsi_done(cmd); - return 1; - } - return 0; -} - -static int aac_bounds_64(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba) -{ - return 0; -} - -static void io_callback(void *context, struct fib * fibptr); - -static int aac_read_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) -{ - u16 fibsize; - struct aac_raw_io *readcmd; - aac_fib_init(fib); - readcmd = (struct aac_raw_io *) fib_data(fib); - readcmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); - readcmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); - readcmd->count = cpu_to_le32(count<<9); - readcmd->cid = cpu_to_le16(scmd_id(cmd)); - readcmd->flags = cpu_to_le16(IO_TYPE_READ); - readcmd->bpTotal = 0; - readcmd->bpComplete = 0; - - aac_build_sgraw(cmd, &readcmd->sg); - fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw)); - BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - return aac_fib_send(ContainerRawIo, - fib, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) cmd); -} - -static int aac_read_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) -{ - u16 fibsize; - struct aac_read64 *readcmd; - aac_fib_init(fib); - readcmd = (struct aac_read64 *) fib_data(fib); - readcmd->command = cpu_to_le32(VM_CtHostRead64); - readcmd->cid = cpu_to_le16(scmd_id(cmd)); - readcmd->sector_count = cpu_to_le16(count); - readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); - readcmd->pad = 0; - readcmd->flags = 0; - - aac_build_sg64(cmd, &readcmd->sg); - fibsize = sizeof(struct aac_read64) + - ((le32_to_cpu(readcmd->sg.count) - 1) * - sizeof (struct sgentry64)); - BUG_ON (fibsize > (fib->dev->max_fib_size - - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - return aac_fib_send(ContainerCommand64, - fib, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) cmd); -} - -static int aac_read_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count) -{ - u16 fibsize; - struct aac_read *readcmd; - aac_fib_init(fib); - readcmd = (struct aac_read *) fib_data(fib); - readcmd->command = cpu_to_le32(VM_CtBlockRead); - readcmd->cid = cpu_to_le32(scmd_id(cmd)); - readcmd->block = cpu_to_le32((u32)(lba&0xffffffff)); - readcmd->count = cpu_to_le32(count * 512); - - aac_build_sg(cmd, &readcmd->sg); - fibsize = sizeof(struct aac_read) + - ((le32_to_cpu(readcmd->sg.count) - 1) * - sizeof (struct sgentry)); - BUG_ON (fibsize > (fib->dev->max_fib_size - - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - return aac_fib_send(ContainerCommand, - fib, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) cmd); -} - -static int aac_write_raw_io(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) -{ - u16 fibsize; - struct aac_raw_io *writecmd; - aac_fib_init(fib); - writecmd = (struct aac_raw_io *) fib_data(fib); - writecmd->block[0] = cpu_to_le32((u32)(lba&0xffffffff)); - writecmd->block[1] = cpu_to_le32((u32)((lba&0xffffffff00000000LL)>>32)); - writecmd->count = cpu_to_le32(count<<9); - writecmd->cid = cpu_to_le16(scmd_id(cmd)); - writecmd->flags = (fua && ((aac_cache & 5) != 1) && - (((aac_cache & 5) != 5) || !fib->dev->cache_protected)) ? - cpu_to_le16(IO_TYPE_WRITE|IO_SUREWRITE) : - cpu_to_le16(IO_TYPE_WRITE); - writecmd->bpTotal = 0; - writecmd->bpComplete = 0; - - aac_build_sgraw(cmd, &writecmd->sg); - fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw)); - BUG_ON(fibsize > (fib->dev->max_fib_size - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - return aac_fib_send(ContainerRawIo, - fib, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) cmd); -} - -static int aac_write_block64(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) -{ - u16 fibsize; - struct aac_write64 *writecmd; - aac_fib_init(fib); - writecmd = (struct aac_write64 *) fib_data(fib); - writecmd->command = cpu_to_le32(VM_CtHostWrite64); - writecmd->cid = cpu_to_le16(scmd_id(cmd)); - writecmd->sector_count = cpu_to_le16(count); - writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); - writecmd->pad = 0; - writecmd->flags = 0; - - aac_build_sg64(cmd, &writecmd->sg); - fibsize = sizeof(struct aac_write64) + - ((le32_to_cpu(writecmd->sg.count) - 1) * - sizeof (struct sgentry64)); - BUG_ON (fibsize > (fib->dev->max_fib_size - - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - return aac_fib_send(ContainerCommand64, - fib, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) cmd); -} - -static int aac_write_block(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua) -{ - u16 fibsize; - struct aac_write *writecmd; - aac_fib_init(fib); - writecmd = (struct aac_write *) fib_data(fib); - writecmd->command = cpu_to_le32(VM_CtBlockWrite); - writecmd->cid = cpu_to_le32(scmd_id(cmd)); - writecmd->block = cpu_to_le32((u32)(lba&0xffffffff)); - writecmd->count = cpu_to_le32(count * 512); - writecmd->sg.count = cpu_to_le32(1); - /* ->stable is not used - it did mean which type of write */ - - aac_build_sg(cmd, &writecmd->sg); - fibsize = sizeof(struct aac_write) + - ((le32_to_cpu(writecmd->sg.count) - 1) * - sizeof (struct sgentry)); - BUG_ON (fibsize > (fib->dev->max_fib_size - - sizeof(struct aac_fibhdr))); - /* - * Now send the Fib to the adapter - */ - return aac_fib_send(ContainerCommand, - fib, - fibsize, - FsaNormal, - 0, 1, - (fib_callback) io_callback, - (void *) cmd); -} - -static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd) -{ - struct aac_srb * srbcmd; - u32 flag; - u32 timeout; - - aac_fib_init(fib); - switch(cmd->sc_data_direction){ - case DMA_TO_DEVICE: - flag = SRB_DataOut; - break; - case DMA_BIDIRECTIONAL: - flag = SRB_DataIn | SRB_DataOut; - break; - case DMA_FROM_DEVICE: - flag = SRB_DataIn; - break; - case DMA_NONE: - default: /* shuts up some versions of gcc */ - flag = SRB_NoDataXfer; - break; - } - - srbcmd = (struct aac_srb*) fib_data(fib); - srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); - srbcmd->channel = cpu_to_le32(aac_logical_to_phys(scmd_channel(cmd))); - srbcmd->id = cpu_to_le32(scmd_id(cmd)); - srbcmd->lun = cpu_to_le32(cmd->device->lun); - srbcmd->flags = cpu_to_le32(flag); - timeout = cmd->request->timeout/HZ; - if (timeout == 0) - timeout = 1; - srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds - srbcmd->retry_limit = 0; /* Obsolete parameter */ - srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len); - return srbcmd; -} - -static void aac_srb_callback(void *context, struct fib * fibptr); - -static int aac_scsi_64(struct fib * fib, struct scsi_cmnd * cmd) -{ - u16 fibsize; - struct aac_srb * srbcmd = aac_scsi_common(fib, cmd); - - aac_build_sg64(cmd, (struct sgmap64*) &srbcmd->sg); - srbcmd->count = cpu_to_le32(scsi_bufflen(cmd)); - - memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); - memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len); - /* - * Build Scatter/Gather list - */ - fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) + - ((le32_to_cpu(srbcmd->sg.count) & 0xff) * - sizeof (struct sgentry64)); - BUG_ON (fibsize > (fib->dev->max_fib_size - - sizeof(struct aac_fibhdr))); - - /* - * Now send the Fib to the adapter - */ - return aac_fib_send(ScsiPortCommand64, fib, - fibsize, FsaNormal, 0, 1, - (fib_callback) aac_srb_callback, - (void *) cmd); -} - -static int aac_scsi_32(struct fib * fib, struct scsi_cmnd * cmd) -{ - u16 fibsize; - struct aac_srb * srbcmd = aac_scsi_common(fib, cmd); - - aac_build_sg(cmd, (struct sgmap*)&srbcmd->sg); - srbcmd->count = cpu_to_le32(scsi_bufflen(cmd)); - - memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb)); - memcpy(srbcmd->cdb, cmd->cmnd, cmd->cmd_len); - /* - * Build Scatter/Gather list - */ - fibsize = sizeof (struct aac_srb) + - (((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * - sizeof (struct sgentry)); - BUG_ON (fibsize > (fib->dev->max_fib_size - - sizeof(struct aac_fibhdr))); - - /* - * Now send the Fib to the adapter - */ - return aac_fib_send(ScsiPortCommand, fib, fibsize, FsaNormal, 0, 1, - (fib_callback) aac_srb_callback, (void *) cmd); -} - -static int aac_scsi_32_64(struct fib * fib, struct scsi_cmnd * cmd) -{ - if ((sizeof(dma_addr_t) > 4) && fib->dev->needs_dac && - (fib->dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) - return FAILED; - return aac_scsi_32(fib, cmd); -} - -int aac_get_adapter_info(struct aac_dev* dev) -{ - struct fib* fibptr; - int rcode; - u32 tmp; - struct aac_adapter_info *info; - struct aac_bus_info *command; - struct aac_bus_info_response *bus_info; - - if (!(fibptr = aac_fib_alloc(dev))) - return -ENOMEM; - - aac_fib_init(fibptr); - info = (struct aac_adapter_info *) fib_data(fibptr); - memset(info,0,sizeof(*info)); - - rcode = aac_fib_send(RequestAdapterInfo, - fibptr, - sizeof(*info), - FsaNormal, - -1, 1, /* First `interrupt' command uses special wait */ - NULL, - NULL); - - if (rcode < 0) { - /* FIB should be freed only after - * getting the response from the F/W */ - if (rcode != -ERESTARTSYS) { - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - } - return rcode; - } - memcpy(&dev->adapter_info, info, sizeof(*info)); - - if (dev->adapter_info.options & AAC_OPT_SUPPLEMENT_ADAPTER_INFO) { - struct aac_supplement_adapter_info * sinfo; - - aac_fib_init(fibptr); - - sinfo = (struct aac_supplement_adapter_info *) fib_data(fibptr); - - memset(sinfo,0,sizeof(*sinfo)); - - rcode = aac_fib_send(RequestSupplementAdapterInfo, - fibptr, - sizeof(*sinfo), - FsaNormal, - 1, 1, - NULL, - NULL); - - if (rcode >= 0) - memcpy(&dev->supplement_adapter_info, sinfo, sizeof(*sinfo)); - if (rcode == -ERESTARTSYS) { - fibptr = aac_fib_alloc(dev); - if (!fibptr) - return -ENOMEM; - } - - } - - - /* - * GetBusInfo - */ - - aac_fib_init(fibptr); - - bus_info = (struct aac_bus_info_response *) fib_data(fibptr); - - memset(bus_info, 0, sizeof(*bus_info)); - - command = (struct aac_bus_info *)bus_info; - - command->Command = cpu_to_le32(VM_Ioctl); - command->ObjType = cpu_to_le32(FT_DRIVE); - command->MethodId = cpu_to_le32(1); - command->CtlCmd = cpu_to_le32(GetBusInfo); - - rcode = aac_fib_send(ContainerCommand, - fibptr, - sizeof (*bus_info), - FsaNormal, - 1, 1, - NULL, NULL); - - /* reasoned default */ - dev->maximum_num_physicals = 16; - if (rcode >= 0 && le32_to_cpu(bus_info->Status) == ST_OK) { - dev->maximum_num_physicals = le32_to_cpu(bus_info->TargetsPerBus); - dev->maximum_num_channels = le32_to_cpu(bus_info->BusCount); - } - - if (!dev->in_reset) { - char buffer[16]; - tmp = le32_to_cpu(dev->adapter_info.kernelrev); - printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d] %.*s\n", - dev->name, - dev->id, - tmp>>24, - (tmp>>16)&0xff, - tmp&0xff, - le32_to_cpu(dev->adapter_info.kernelbuild), - (int)sizeof(dev->supplement_adapter_info.BuildDate), - dev->supplement_adapter_info.BuildDate); - tmp = le32_to_cpu(dev->adapter_info.monitorrev); - printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n", - dev->name, dev->id, - tmp>>24,(tmp>>16)&0xff,tmp&0xff, - le32_to_cpu(dev->adapter_info.monitorbuild)); - tmp = le32_to_cpu(dev->adapter_info.biosrev); - printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n", - dev->name, dev->id, - tmp>>24,(tmp>>16)&0xff,tmp&0xff, - le32_to_cpu(dev->adapter_info.biosbuild)); - buffer[0] = '\0'; - if (aac_get_serial_number( - shost_to_class(dev->scsi_host_ptr), buffer)) - printk(KERN_INFO "%s%d: serial %s", - dev->name, dev->id, buffer); - if (dev->supplement_adapter_info.VpdInfo.Tsid[0]) { - printk(KERN_INFO "%s%d: TSID %.*s\n", - dev->name, dev->id, - (int)sizeof(dev->supplement_adapter_info.VpdInfo.Tsid), - dev->supplement_adapter_info.VpdInfo.Tsid); - } - if (!aac_check_reset || ((aac_check_reset == 1) && - (dev->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_IGNORE_RESET))) { - printk(KERN_INFO "%s%d: Reset Adapter Ignored\n", - dev->name, dev->id); - } - } - - dev->cache_protected = 0; - dev->jbod = ((dev->supplement_adapter_info.FeatureBits & - AAC_FEATURE_JBOD) != 0); - dev->nondasd_support = 0; - dev->raid_scsi_mode = 0; - if(dev->adapter_info.options & AAC_OPT_NONDASD) - dev->nondasd_support = 1; - - /* - * If the firmware supports ROMB RAID/SCSI mode and we are currently - * in RAID/SCSI mode, set the flag. For now if in this mode we will - * force nondasd support on. If we decide to allow the non-dasd flag - * additional changes changes will have to be made to support - * RAID/SCSI. the function aac_scsi_cmd in this module will have to be - * changed to support the new dev->raid_scsi_mode flag instead of - * leaching off of the dev->nondasd_support flag. Also in linit.c the - * function aac_detect will have to be modified where it sets up the - * max number of channels based on the aac->nondasd_support flag only. - */ - if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) && - (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) { - dev->nondasd_support = 1; - dev->raid_scsi_mode = 1; - } - if (dev->raid_scsi_mode != 0) - printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n", - dev->name, dev->id); - - if (nondasd != -1) - dev->nondasd_support = (nondasd!=0); - if (dev->nondasd_support && !dev->in_reset) - printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id); - - if (dma_get_required_mask(&dev->pdev->dev) > DMA_BIT_MASK(32)) - dev->needs_dac = 1; - dev->dac_support = 0; - if ((sizeof(dma_addr_t) > 4) && dev->needs_dac && - (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)) { - if (!dev->in_reset) - printk(KERN_INFO "%s%d: 64bit support enabled.\n", - dev->name, dev->id); - dev->dac_support = 1; - } - - if(dacmode != -1) { - dev->dac_support = (dacmode!=0); - } - - /* avoid problems with AAC_QUIRK_SCSI_32 controllers */ - if (dev->dac_support && (aac_get_driver_ident(dev->cardtype)->quirks - & AAC_QUIRK_SCSI_32)) { - dev->nondasd_support = 0; - dev->jbod = 0; - expose_physicals = 0; - } - - if(dev->dac_support != 0) { - if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(64)) && - !pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(64))) { - if (!dev->in_reset) - printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n", - dev->name, dev->id); - } else if (!pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(32)) && - !pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32))) { - printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n", - dev->name, dev->id); - dev->dac_support = 0; - } else { - printk(KERN_WARNING"%s%d: No suitable DMA available.\n", - dev->name, dev->id); - rcode = -ENOMEM; - } - } - /* - * Deal with configuring for the individualized limits of each packet - * interface. - */ - dev->a_ops.adapter_scsi = (dev->dac_support) - ? ((aac_get_driver_ident(dev->cardtype)->quirks & AAC_QUIRK_SCSI_32) - ? aac_scsi_32_64 - : aac_scsi_64) - : aac_scsi_32; - if (dev->raw_io_interface) { - dev->a_ops.adapter_bounds = (dev->raw_io_64) - ? aac_bounds_64 - : aac_bounds_32; - dev->a_ops.adapter_read = aac_read_raw_io; - dev->a_ops.adapter_write = aac_write_raw_io; - } else { - dev->a_ops.adapter_bounds = aac_bounds_32; - dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write) + sizeof(struct sgentry)) / - sizeof(struct sgentry); - if (dev->dac_support) { - dev->a_ops.adapter_read = aac_read_block64; - dev->a_ops.adapter_write = aac_write_block64; - /* - * 38 scatter gather elements - */ - dev->scsi_host_ptr->sg_tablesize = - (dev->max_fib_size - - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write64) + - sizeof(struct sgentry64)) / - sizeof(struct sgentry64); - } else { - dev->a_ops.adapter_read = aac_read_block; - dev->a_ops.adapter_write = aac_write_block; - } - dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; - if (dev->adapter_info.options & AAC_OPT_NEW_COMM_TYPE1) - dev->adapter_info.options |= AAC_OPT_NEW_COMM; - if (!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { - /* - * Worst case size that could cause sg overflow when - * we break up SG elements that are larger than 64KB. - * Would be nice if we could tell the SCSI layer what - * the maximum SG element size can be. Worst case is - * (sg_tablesize-1) 4KB elements with one 64KB - * element. - * 32bit -> 468 or 238KB 64bit -> 424 or 212KB - */ - dev->scsi_host_ptr->max_sectors = - (dev->scsi_host_ptr->sg_tablesize * 8) + 112; - } - } - /* FIB should be freed only after getting the response from the F/W */ - if (rcode != -ERESTARTSYS) { - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - } - - return rcode; -} - - -static void io_callback(void *context, struct fib * fibptr) -{ - struct aac_dev *dev; - struct aac_read_reply *readreply; - struct scsi_cmnd *scsicmd; - u32 cid; - - scsicmd = (struct scsi_cmnd *) context; - - if (!aac_valid_context(scsicmd, fibptr)) - return; - - dev = fibptr->dev; - cid = scmd_id(scsicmd); - - if (nblank(dprintk(x))) { - u64 lba; - switch (scsicmd->cmnd[0]) { - case WRITE_6: - case READ_6: - lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | - (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; - break; - case WRITE_16: - case READ_16: - lba = ((u64)scsicmd->cmnd[2] << 56) | - ((u64)scsicmd->cmnd[3] << 48) | - ((u64)scsicmd->cmnd[4] << 40) | - ((u64)scsicmd->cmnd[5] << 32) | - ((u64)scsicmd->cmnd[6] << 24) | - (scsicmd->cmnd[7] << 16) | - (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; - break; - case WRITE_12: - case READ_12: - lba = ((u64)scsicmd->cmnd[2] << 24) | - (scsicmd->cmnd[3] << 16) | - (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - break; - default: - lba = ((u64)scsicmd->cmnd[2] << 24) | - (scsicmd->cmnd[3] << 16) | - (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - break; - } - printk(KERN_DEBUG - "io_callback[cpu %d]: lba = %llu, t = %ld.\n", - smp_processor_id(), (unsigned long long)lba, jiffies); - } - - BUG_ON(fibptr == NULL); - - scsi_dma_unmap(scsicmd); - - readreply = (struct aac_read_reply *)fib_data(fibptr); - switch (le32_to_cpu(readreply->status)) { - case ST_OK: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_GOOD; - dev->fsa_dev[cid].sense_data.sense_key = NO_SENSE; - break; - case ST_NOT_READY: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, NOT_READY, - SENCODE_BECOMING_READY, ASENCODE_BECOMING_READY, 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - break; - default: -#ifdef AAC_DETAILED_STATUS_INFO - printk(KERN_WARNING "io_callback: io failed, status = %d\n", - le32_to_cpu(readreply->status)); -#endif - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - break; - } - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - - scsicmd->scsi_done(scsicmd); -} - -static int aac_read(struct scsi_cmnd * scsicmd) -{ - u64 lba; - u32 count; - int status; - struct aac_dev *dev; - struct fib * cmd_fibcontext; - int cid; - - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - /* - * Get block address and transfer length - */ - switch (scsicmd->cmnd[0]) { - case READ_6: - dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", scmd_id(scsicmd))); - - lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | - (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; - count = scsicmd->cmnd[4]; - - if (count == 0) - count = 256; - break; - case READ_16: - dprintk((KERN_DEBUG "aachba: received a read(16) command on id %d.\n", scmd_id(scsicmd))); - - lba = ((u64)scsicmd->cmnd[2] << 56) | - ((u64)scsicmd->cmnd[3] << 48) | - ((u64)scsicmd->cmnd[4] << 40) | - ((u64)scsicmd->cmnd[5] << 32) | - ((u64)scsicmd->cmnd[6] << 24) | - (scsicmd->cmnd[7] << 16) | - (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; - count = (scsicmd->cmnd[10] << 24) | - (scsicmd->cmnd[11] << 16) | - (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; - break; - case READ_12: - dprintk((KERN_DEBUG "aachba: received a read(12) command on id %d.\n", scmd_id(scsicmd))); - - lba = ((u64)scsicmd->cmnd[2] << 24) | - (scsicmd->cmnd[3] << 16) | - (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - count = (scsicmd->cmnd[6] << 24) | - (scsicmd->cmnd[7] << 16) | - (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; - break; - default: - dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", scmd_id(scsicmd))); - - lba = ((u64)scsicmd->cmnd[2] << 24) | - (scsicmd->cmnd[3] << 16) | - (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; - break; - } - - if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { - cid = scmd_id(scsicmd); - dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - scsicmd->scsi_done(scsicmd); - return 1; - } - - dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n", - smp_processor_id(), (unsigned long long)lba, jiffies)); - if (aac_adapter_bounds(dev,scsicmd,lba)) - return 0; - /* - * Alocate and initialize a Fib - */ - if (!(cmd_fibcontext = aac_fib_alloc(dev))) { - printk(KERN_WARNING "aac_read: fib allocation failed\n"); - return -1; - } - - status = aac_adapter_read(cmd_fibcontext, scsicmd, lba, count); - - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - - printk(KERN_WARNING "aac_read: aac_fib_send failed with status: %d.\n", status); - /* - * For some reason, the Fib didn't queue, return QUEUE_FULL - */ - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL; - scsicmd->scsi_done(scsicmd); - aac_fib_complete(cmd_fibcontext); - aac_fib_free(cmd_fibcontext); - return 0; -} - -static int aac_write(struct scsi_cmnd * scsicmd) -{ - u64 lba; - u32 count; - int fua; - int status; - struct aac_dev *dev; - struct fib * cmd_fibcontext; - int cid; - - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - /* - * Get block address and transfer length - */ - if (scsicmd->cmnd[0] == WRITE_6) /* 6 byte command */ - { - lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; - count = scsicmd->cmnd[4]; - if (count == 0) - count = 256; - fua = 0; - } else if (scsicmd->cmnd[0] == WRITE_16) { /* 16 byte command */ - dprintk((KERN_DEBUG "aachba: received a write(16) command on id %d.\n", scmd_id(scsicmd))); - - lba = ((u64)scsicmd->cmnd[2] << 56) | - ((u64)scsicmd->cmnd[3] << 48) | - ((u64)scsicmd->cmnd[4] << 40) | - ((u64)scsicmd->cmnd[5] << 32) | - ((u64)scsicmd->cmnd[6] << 24) | - (scsicmd->cmnd[7] << 16) | - (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; - count = (scsicmd->cmnd[10] << 24) | (scsicmd->cmnd[11] << 16) | - (scsicmd->cmnd[12] << 8) | scsicmd->cmnd[13]; - fua = scsicmd->cmnd[1] & 0x8; - } else if (scsicmd->cmnd[0] == WRITE_12) { /* 12 byte command */ - dprintk((KERN_DEBUG "aachba: received a write(12) command on id %d.\n", scmd_id(scsicmd))); - - lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) - | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - count = (scsicmd->cmnd[6] << 24) | (scsicmd->cmnd[7] << 16) - | (scsicmd->cmnd[8] << 8) | scsicmd->cmnd[9]; - fua = scsicmd->cmnd[1] & 0x8; - } else { - dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", scmd_id(scsicmd))); - lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; - fua = scsicmd->cmnd[1] & 0x8; - } - - if ((lba + count) > (dev->fsa_dev[scmd_id(scsicmd)].size)) { - cid = scmd_id(scsicmd); - dprintk((KERN_DEBUG "aacraid: Illegal lba\n")); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - scsicmd->scsi_done(scsicmd); - return 1; - } - - dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n", - smp_processor_id(), (unsigned long long)lba, jiffies)); - if (aac_adapter_bounds(dev,scsicmd,lba)) - return 0; - /* - * Allocate and initialize a Fib then setup a BlockWrite command - */ - if (!(cmd_fibcontext = aac_fib_alloc(dev))) { - /* FIB temporarily unavailable,not catastrophic failure */ - - /* scsicmd->result = DID_ERROR << 16; - * scsicmd->scsi_done(scsicmd); - * return 0; - */ - printk(KERN_WARNING "aac_write: fib allocation failed\n"); - return -1; - } - - status = aac_adapter_write(cmd_fibcontext, scsicmd, lba, count, fua); - - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - - printk(KERN_WARNING "aac_write: aac_fib_send failed with status: %d\n", status); - /* - * For some reason, the Fib didn't queue, return QUEUE_FULL - */ - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL; - scsicmd->scsi_done(scsicmd); - - aac_fib_complete(cmd_fibcontext); - aac_fib_free(cmd_fibcontext); - return 0; -} - -static void synchronize_callback(void *context, struct fib *fibptr) -{ - struct aac_synchronize_reply *synchronizereply; - struct scsi_cmnd *cmd; - - cmd = context; - - if (!aac_valid_context(cmd, fibptr)) - return; - - dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", - smp_processor_id(), jiffies)); - BUG_ON(fibptr == NULL); - - - synchronizereply = fib_data(fibptr); - if (le32_to_cpu(synchronizereply->status) == CT_OK) - cmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - else { - struct scsi_device *sdev = cmd->device; - struct aac_dev *dev = fibptr->dev; - u32 cid = sdev_id(sdev); - printk(KERN_WARNING - "synchronize_callback: synchronize failed, status = %d\n", - le32_to_cpu(synchronizereply->status)); - cmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); - memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - } - - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - cmd->scsi_done(cmd); -} - -static int aac_synchronize(struct scsi_cmnd *scsicmd) -{ - int status; - struct fib *cmd_fibcontext; - struct aac_synchronize *synchronizecmd; - struct scsi_cmnd *cmd; - struct scsi_device *sdev = scsicmd->device; - int active = 0; - struct aac_dev *aac; - u64 lba = ((u64)scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | - (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5]; - u32 count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8]; - unsigned long flags; - - /* - * Wait for all outstanding queued commands to complete to this - * specific target (block). - */ - spin_lock_irqsave(&sdev->list_lock, flags); - list_for_each_entry(cmd, &sdev->cmd_list, list) - if (cmd->SCp.phase == AAC_OWNER_FIRMWARE) { - u64 cmnd_lba; - u32 cmnd_count; - - if (cmd->cmnd[0] == WRITE_6) { - cmnd_lba = ((cmd->cmnd[1] & 0x1F) << 16) | - (cmd->cmnd[2] << 8) | - cmd->cmnd[3]; - cmnd_count = cmd->cmnd[4]; - if (cmnd_count == 0) - cmnd_count = 256; - } else if (cmd->cmnd[0] == WRITE_16) { - cmnd_lba = ((u64)cmd->cmnd[2] << 56) | - ((u64)cmd->cmnd[3] << 48) | - ((u64)cmd->cmnd[4] << 40) | - ((u64)cmd->cmnd[5] << 32) | - ((u64)cmd->cmnd[6] << 24) | - (cmd->cmnd[7] << 16) | - (cmd->cmnd[8] << 8) | - cmd->cmnd[9]; - cmnd_count = (cmd->cmnd[10] << 24) | - (cmd->cmnd[11] << 16) | - (cmd->cmnd[12] << 8) | - cmd->cmnd[13]; - } else if (cmd->cmnd[0] == WRITE_12) { - cmnd_lba = ((u64)cmd->cmnd[2] << 24) | - (cmd->cmnd[3] << 16) | - (cmd->cmnd[4] << 8) | - cmd->cmnd[5]; - cmnd_count = (cmd->cmnd[6] << 24) | - (cmd->cmnd[7] << 16) | - (cmd->cmnd[8] << 8) | - cmd->cmnd[9]; - } else if (cmd->cmnd[0] == WRITE_10) { - cmnd_lba = ((u64)cmd->cmnd[2] << 24) | - (cmd->cmnd[3] << 16) | - (cmd->cmnd[4] << 8) | - cmd->cmnd[5]; - cmnd_count = (cmd->cmnd[7] << 8) | - cmd->cmnd[8]; - } else - continue; - if (((cmnd_lba + cmnd_count) < lba) || - (count && ((lba + count) < cmnd_lba))) - continue; - ++active; - break; - } - - spin_unlock_irqrestore(&sdev->list_lock, flags); - - /* - * Yield the processor (requeue for later) - */ - if (active) - return SCSI_MLQUEUE_DEVICE_BUSY; - - aac = (struct aac_dev *)sdev->host->hostdata; - if (aac->in_reset) - return SCSI_MLQUEUE_HOST_BUSY; - - /* - * Allocate and initialize a Fib - */ - if (!(cmd_fibcontext = aac_fib_alloc(aac))) - return SCSI_MLQUEUE_HOST_BUSY; - - aac_fib_init(cmd_fibcontext); - - synchronizecmd = fib_data(cmd_fibcontext); - synchronizecmd->command = cpu_to_le32(VM_ContainerConfig); - synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE); - synchronizecmd->cid = cpu_to_le32(scmd_id(scsicmd)); - synchronizecmd->count = - cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data)); - - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ContainerCommand, - cmd_fibcontext, - sizeof(struct aac_synchronize), - FsaNormal, - 0, 1, - (fib_callback)synchronize_callback, - (void *)scsicmd); - - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - - printk(KERN_WARNING - "aac_synchronize: aac_fib_send failed with status: %d.\n", status); - aac_fib_complete(cmd_fibcontext); - aac_fib_free(cmd_fibcontext); - return SCSI_MLQUEUE_HOST_BUSY; -} - -static void aac_start_stop_callback(void *context, struct fib *fibptr) -{ - struct scsi_cmnd *scsicmd = context; - - if (!aac_valid_context(scsicmd, fibptr)) - return; - - BUG_ON(fibptr == NULL); - - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - scsicmd->scsi_done(scsicmd); -} - -static int aac_start_stop(struct scsi_cmnd *scsicmd) -{ - int status; - struct fib *cmd_fibcontext; - struct aac_power_management *pmcmd; - struct scsi_device *sdev = scsicmd->device; - struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata; - - if (!(aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_POWER_MANAGEMENT)) { - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; - } - - if (aac->in_reset) - return SCSI_MLQUEUE_HOST_BUSY; - - /* - * Allocate and initialize a Fib - */ - cmd_fibcontext = aac_fib_alloc(aac); - if (!cmd_fibcontext) - return SCSI_MLQUEUE_HOST_BUSY; - - aac_fib_init(cmd_fibcontext); - - pmcmd = fib_data(cmd_fibcontext); - pmcmd->command = cpu_to_le32(VM_ContainerConfig); - pmcmd->type = cpu_to_le32(CT_POWER_MANAGEMENT); - /* Eject bit ignored, not relevant */ - pmcmd->sub = (scsicmd->cmnd[4] & 1) ? - cpu_to_le32(CT_PM_START_UNIT) : cpu_to_le32(CT_PM_STOP_UNIT); - pmcmd->cid = cpu_to_le32(sdev_id(sdev)); - pmcmd->parm = (scsicmd->cmnd[1] & 1) ? - cpu_to_le32(CT_PM_UNIT_IMMEDIATE) : 0; - - /* - * Now send the Fib to the adapter - */ - status = aac_fib_send(ContainerCommand, - cmd_fibcontext, - sizeof(struct aac_power_management), - FsaNormal, - 0, 1, - (fib_callback)aac_start_stop_callback, - (void *)scsicmd); - - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - - aac_fib_complete(cmd_fibcontext); - aac_fib_free(cmd_fibcontext); - return SCSI_MLQUEUE_HOST_BUSY; -} - -/** - * aac_scsi_cmd() - Process SCSI command - * @scsicmd: SCSI command block - * - * Emulate a SCSI command and queue the required request for the - * aacraid firmware. - */ - -int aac_scsi_cmd(struct scsi_cmnd * scsicmd) -{ - u32 cid; - struct Scsi_Host *host = scsicmd->device->host; - struct aac_dev *dev = (struct aac_dev *)host->hostdata; - struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev; - - if (fsa_dev_ptr == NULL) - return -1; - /* - * If the bus, id or lun is out of range, return fail - * Test does not apply to ID 16, the pseudo id for the controller - * itself. - */ - cid = scmd_id(scsicmd); - if (cid != host->this_id) { - if (scmd_channel(scsicmd) == CONTAINER_CHANNEL) { - if((cid >= dev->maximum_num_containers) || - (scsicmd->device->lun != 0)) { - scsicmd->result = DID_NO_CONNECT << 16; - scsicmd->scsi_done(scsicmd); - return 0; - } - - /* - * If the target container doesn't exist, it may have - * been newly created - */ - if (((fsa_dev_ptr[cid].valid & 1) == 0) || - (fsa_dev_ptr[cid].sense_data.sense_key == - NOT_READY)) { - switch (scsicmd->cmnd[0]) { - case SERVICE_ACTION_IN: - if (!(dev->raw_io_interface) || - !(dev->raw_io_64) || - ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) - break; - case INQUIRY: - case READ_CAPACITY: - case TEST_UNIT_READY: - if (dev->in_reset) - return -1; - return _aac_probe_container(scsicmd, - aac_probe_container_callback2); - default: - break; - } - } - } else { /* check for physical non-dasd devices */ - if (dev->nondasd_support || expose_physicals || - dev->jbod) { - if (dev->in_reset) - return -1; - return aac_send_srb_fib(scsicmd); - } else { - scsicmd->result = DID_NO_CONNECT << 16; - scsicmd->scsi_done(scsicmd); - return 0; - } - } - } - /* - * else Command for the controller itself - */ - else if ((scsicmd->cmnd[0] != INQUIRY) && /* only INQUIRY & TUR cmnd supported for controller */ - (scsicmd->cmnd[0] != TEST_UNIT_READY)) - { - dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0])); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, - ASENCODE_INVALID_COMMAND, 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - scsicmd->scsi_done(scsicmd); - return 0; - } - - - /* Handle commands here that don't really require going out to the adapter */ - switch (scsicmd->cmnd[0]) { - case INQUIRY: - { - struct inquiry_data inq_data; - - dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", cid)); - memset(&inq_data, 0, sizeof (struct inquiry_data)); - - if ((scsicmd->cmnd[1] & 0x1) && aac_wwn) { - char *arr = (char *)&inq_data; - - /* EVPD bit set */ - arr[0] = (scmd_id(scsicmd) == host->this_id) ? - INQD_PDT_PROC : INQD_PDT_DA; - if (scsicmd->cmnd[2] == 0) { - /* supported vital product data pages */ - arr[3] = 2; - arr[4] = 0x0; - arr[5] = 0x80; - arr[1] = scsicmd->cmnd[2]; - scsi_sg_copy_from_buffer(scsicmd, &inq_data, - sizeof(inq_data)); - scsicmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - } else if (scsicmd->cmnd[2] == 0x80) { - /* unit serial number page */ - arr[3] = setinqserial(dev, &arr[4], - scmd_id(scsicmd)); - arr[1] = scsicmd->cmnd[2]; - scsi_sg_copy_from_buffer(scsicmd, &inq_data, - sizeof(inq_data)); - if (aac_wwn != 2) - return aac_get_container_serial( - scsicmd); - /* SLES 10 SP1 special */ - scsicmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - } else { - /* vpd page not implemented */ - scsicmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_CDB_FIELD, - ASENCODE_NO_SENSE, 7, 2); - memcpy(scsicmd->sense_buffer, - &dev->fsa_dev[cid].sense_data, - min_t(size_t, - sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - } - scsicmd->scsi_done(scsicmd); - return 0; - } - inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ - inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ - inq_data.inqd_len = 31; - /*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ - inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ - /* - * Set the Vendor, Product, and Revision Level - * see: .c i.e. aac.c - */ - if (cid == host->this_id) { - setinqstr(dev, (void *) (inq_data.inqd_vid), ARRAY_SIZE(container_types)); - inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */ - scsi_sg_copy_from_buffer(scsicmd, &inq_data, - sizeof(inq_data)); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; - } - if (dev->in_reset) - return -1; - setinqstr(dev, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type); - inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ - scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data)); - return aac_get_container_name(scsicmd); - } - case SERVICE_ACTION_IN: - if (!(dev->raw_io_interface) || - !(dev->raw_io_64) || - ((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) - break; - { - u64 capacity; - char cp[13]; - unsigned int alloc_len; - - dprintk((KERN_DEBUG "READ CAPACITY_16 command.\n")); - capacity = fsa_dev_ptr[cid].size - 1; - cp[0] = (capacity >> 56) & 0xff; - cp[1] = (capacity >> 48) & 0xff; - cp[2] = (capacity >> 40) & 0xff; - cp[3] = (capacity >> 32) & 0xff; - cp[4] = (capacity >> 24) & 0xff; - cp[5] = (capacity >> 16) & 0xff; - cp[6] = (capacity >> 8) & 0xff; - cp[7] = (capacity >> 0) & 0xff; - cp[8] = 0; - cp[9] = 0; - cp[10] = 2; - cp[11] = 0; - cp[12] = 0; - - alloc_len = ((scsicmd->cmnd[10] << 24) - + (scsicmd->cmnd[11] << 16) - + (scsicmd->cmnd[12] << 8) + scsicmd->cmnd[13]); - - alloc_len = min_t(size_t, alloc_len, sizeof(cp)); - scsi_sg_copy_from_buffer(scsicmd, cp, alloc_len); - if (alloc_len < scsi_bufflen(scsicmd)) - scsi_set_resid(scsicmd, - scsi_bufflen(scsicmd) - alloc_len); - - /* Do not cache partition table for arrays */ - scsicmd->device->removable = 1; - - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - - return 0; - } - - case READ_CAPACITY: - { - u32 capacity; - char cp[8]; - - dprintk((KERN_DEBUG "READ CAPACITY command.\n")); - if (fsa_dev_ptr[cid].size <= 0x100000000ULL) - capacity = fsa_dev_ptr[cid].size - 1; - else - capacity = (u32)-1; - - cp[0] = (capacity >> 24) & 0xff; - cp[1] = (capacity >> 16) & 0xff; - cp[2] = (capacity >> 8) & 0xff; - cp[3] = (capacity >> 0) & 0xff; - cp[4] = 0; - cp[5] = 0; - cp[6] = 2; - cp[7] = 0; - scsi_sg_copy_from_buffer(scsicmd, cp, sizeof(cp)); - /* Do not cache partition table for arrays */ - scsicmd->device->removable = 1; - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - - return 0; - } - - case MODE_SENSE: - { - char mode_buf[7]; - int mode_buf_length = 4; - - dprintk((KERN_DEBUG "MODE SENSE command.\n")); - mode_buf[0] = 3; /* Mode data length */ - mode_buf[1] = 0; /* Medium type - default */ - mode_buf[2] = 0; /* Device-specific param, - bit 8: 0/1 = write enabled/protected - bit 4: 0/1 = FUA enabled */ - if (dev->raw_io_interface && ((aac_cache & 5) != 1)) - mode_buf[2] = 0x10; - mode_buf[3] = 0; /* Block descriptor length */ - if (((scsicmd->cmnd[2] & 0x3f) == 8) || - ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) { - mode_buf[0] = 6; - mode_buf[4] = 8; - mode_buf[5] = 1; - mode_buf[6] = ((aac_cache & 6) == 2) - ? 0 : 0x04; /* WCE */ - mode_buf_length = 7; - if (mode_buf_length > scsicmd->cmnd[4]) - mode_buf_length = scsicmd->cmnd[4]; - } - scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - - return 0; - } - case MODE_SENSE_10: - { - char mode_buf[11]; - int mode_buf_length = 8; - - dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n")); - mode_buf[0] = 0; /* Mode data length (MSB) */ - mode_buf[1] = 6; /* Mode data length (LSB) */ - mode_buf[2] = 0; /* Medium type - default */ - mode_buf[3] = 0; /* Device-specific param, - bit 8: 0/1 = write enabled/protected - bit 4: 0/1 = FUA enabled */ - if (dev->raw_io_interface && ((aac_cache & 5) != 1)) - mode_buf[3] = 0x10; - mode_buf[4] = 0; /* reserved */ - mode_buf[5] = 0; /* reserved */ - mode_buf[6] = 0; /* Block descriptor length (MSB) */ - mode_buf[7] = 0; /* Block descriptor length (LSB) */ - if (((scsicmd->cmnd[2] & 0x3f) == 8) || - ((scsicmd->cmnd[2] & 0x3f) == 0x3f)) { - mode_buf[1] = 9; - mode_buf[8] = 8; - mode_buf[9] = 1; - mode_buf[10] = ((aac_cache & 6) == 2) - ? 0 : 0x04; /* WCE */ - mode_buf_length = 11; - if (mode_buf_length > scsicmd->cmnd[8]) - mode_buf_length = scsicmd->cmnd[8]; - } - scsi_sg_copy_from_buffer(scsicmd, mode_buf, mode_buf_length); - - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - - return 0; - } - case REQUEST_SENSE: - dprintk((KERN_DEBUG "REQUEST SENSE command.\n")); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, sizeof (struct sense_data)); - memset(&dev->fsa_dev[cid].sense_data, 0, sizeof (struct sense_data)); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; - - case ALLOW_MEDIUM_REMOVAL: - dprintk((KERN_DEBUG "LOCK command.\n")); - if (scsicmd->cmnd[4]) - fsa_dev_ptr[cid].locked = 1; - else - fsa_dev_ptr[cid].locked = 0; - - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; - /* - * These commands are all No-Ops - */ - case TEST_UNIT_READY: - if (fsa_dev_ptr[cid].sense_data.sense_key == NOT_READY) { - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - NOT_READY, SENCODE_BECOMING_READY, - ASENCODE_BECOMING_READY, 0, 0); - memcpy(scsicmd->sense_buffer, - &dev->fsa_dev[cid].sense_data, - min_t(size_t, - sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - scsicmd->scsi_done(scsicmd); - return 0; - } - /* FALLTHRU */ - case RESERVE: - case RELEASE: - case REZERO_UNIT: - case REASSIGN_BLOCKS: - case SEEK_10: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; - - case START_STOP: - return aac_start_stop(scsicmd); - } - - switch (scsicmd->cmnd[0]) - { - case READ_6: - case READ_10: - case READ_12: - case READ_16: - if (dev->in_reset) - return -1; - /* - * Hack to keep track of ordinal number of the device that - * corresponds to a container. Needed to convert - * containers to /dev/sd device names - */ - - if (scsicmd->request->rq_disk) - strlcpy(fsa_dev_ptr[cid].devname, - scsicmd->request->rq_disk->disk_name, - min(sizeof(fsa_dev_ptr[cid].devname), - sizeof(scsicmd->request->rq_disk->disk_name) + 1)); - - return aac_read(scsicmd); - - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_16: - if (dev->in_reset) - return -1; - return aac_write(scsicmd); - - case SYNCHRONIZE_CACHE: - if (((aac_cache & 6) == 6) && dev->cache_protected) { - scsicmd->result = DID_OK << 16 | - COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - scsicmd->scsi_done(scsicmd); - return 0; - } - /* Issue FIB to tell Firmware to flush it's cache */ - if ((aac_cache & 6) != 2) - return aac_synchronize(scsicmd); - /* FALLTHRU */ - default: - /* - * Unhandled commands - */ - dprintk((KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0])); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense(&dev->fsa_dev[cid].sense_data, - ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND, - ASENCODE_INVALID_COMMAND, 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - min_t(size_t, - sizeof(dev->fsa_dev[cid].sense_data), - SCSI_SENSE_BUFFERSIZE)); - scsicmd->scsi_done(scsicmd); - return 0; - } -} - -static int query_disk(struct aac_dev *dev, void __user *arg) -{ - struct aac_query_disk qd; - struct fsa_dev_info *fsa_dev_ptr; - - fsa_dev_ptr = dev->fsa_dev; - if (!fsa_dev_ptr) - return -EBUSY; - if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk))) - return -EFAULT; - if (qd.cnum == -1) - qd.cnum = qd.id; - else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) - { - if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers) - return -EINVAL; - qd.instance = dev->scsi_host_ptr->host_no; - qd.bus = 0; - qd.id = CONTAINER_TO_ID(qd.cnum); - qd.lun = CONTAINER_TO_LUN(qd.cnum); - } - else return -EINVAL; - - qd.valid = fsa_dev_ptr[qd.cnum].valid != 0; - qd.locked = fsa_dev_ptr[qd.cnum].locked; - qd.deleted = fsa_dev_ptr[qd.cnum].deleted; - - if (fsa_dev_ptr[qd.cnum].devname[0] == '\0') - qd.unmapped = 1; - else - qd.unmapped = 0; - - strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname, - min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1)); - - if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk))) - return -EFAULT; - return 0; -} - -static int force_delete_disk(struct aac_dev *dev, void __user *arg) -{ - struct aac_delete_disk dd; - struct fsa_dev_info *fsa_dev_ptr; - - fsa_dev_ptr = dev->fsa_dev; - if (!fsa_dev_ptr) - return -EBUSY; - - if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) - return -EFAULT; - - if (dd.cnum >= dev->maximum_num_containers) - return -EINVAL; - /* - * Mark this container as being deleted. - */ - fsa_dev_ptr[dd.cnum].deleted = 1; - /* - * Mark the container as no longer valid - */ - fsa_dev_ptr[dd.cnum].valid = 0; - return 0; -} - -static int delete_disk(struct aac_dev *dev, void __user *arg) -{ - struct aac_delete_disk dd; - struct fsa_dev_info *fsa_dev_ptr; - - fsa_dev_ptr = dev->fsa_dev; - if (!fsa_dev_ptr) - return -EBUSY; - - if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk))) - return -EFAULT; - - if (dd.cnum >= dev->maximum_num_containers) - return -EINVAL; - /* - * If the container is locked, it can not be deleted by the API. - */ - if (fsa_dev_ptr[dd.cnum].locked) - return -EBUSY; - else { - /* - * Mark the container as no longer being valid. - */ - fsa_dev_ptr[dd.cnum].valid = 0; - fsa_dev_ptr[dd.cnum].devname[0] = '\0'; - return 0; - } -} - -int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg) -{ - switch (cmd) { - case FSACTL_QUERY_DISK: - return query_disk(dev, arg); - case FSACTL_DELETE_DISK: - return delete_disk(dev, arg); - case FSACTL_FORCE_DELETE_DISK: - return force_delete_disk(dev, arg); - case FSACTL_GET_CONTAINERS: - return aac_get_containers(dev); - default: - return -ENOTTY; - } -} - -/** - * - * aac_srb_callback - * @context: the context set in the fib - here it is scsi cmd - * @fibptr: pointer to the fib - * - * Handles the completion of a scsi command to a non dasd device - * - */ - -static void aac_srb_callback(void *context, struct fib * fibptr) -{ - struct aac_dev *dev; - struct aac_srb_reply *srbreply; - struct scsi_cmnd *scsicmd; - - scsicmd = (struct scsi_cmnd *) context; - - if (!aac_valid_context(scsicmd, fibptr)) - return; - - BUG_ON(fibptr == NULL); - - dev = fibptr->dev; - - srbreply = (struct aac_srb_reply *) fib_data(fibptr); - - scsicmd->sense_buffer[0] = '\0'; /* Initialize sense valid flag to false */ - /* - * Calculate resid for sg - */ - - scsi_set_resid(scsicmd, scsi_bufflen(scsicmd) - - le32_to_cpu(srbreply->data_xfer_length)); - - scsi_dma_unmap(scsicmd); - - /* expose physical device if expose_physicald flag is on */ - if (scsicmd->cmnd[0] == INQUIRY && !(scsicmd->cmnd[1] & 0x01) - && expose_physicals > 0) - aac_expose_phy_device(scsicmd); - - /* - * First check the fib status - */ - - if (le32_to_cpu(srbreply->status) != ST_OK){ - int len; - printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status)); - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); - scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); - } - - /* - * Next check the srb status - */ - switch( (le32_to_cpu(srbreply->srb_status))&0x3f){ - case SRB_STATUS_ERROR_RECOVERY: - case SRB_STATUS_PENDING: - case SRB_STATUS_SUCCESS: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_DATA_OVERRUN: - switch(scsicmd->cmnd[0]){ - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - case READ_16: - case WRITE_16: - if (le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow) { - printk(KERN_WARNING"aacraid: SCSI CMD underflow\n"); - } else { - printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n"); - } - scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; - break; - case INQUIRY: { - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - } - default: - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - } - break; - case SRB_STATUS_ABORTED: - scsicmd->result = DID_ABORT << 16 | ABORT << 8; - break; - case SRB_STATUS_ABORT_FAILED: - // Not sure about this one - but assuming the hba was trying to abort for some reason - scsicmd->result = DID_ERROR << 16 | ABORT << 8; - break; - case SRB_STATUS_PARITY_ERROR: - scsicmd->result = DID_PARITY << 16 | MSG_PARITY_ERROR << 8; - break; - case SRB_STATUS_NO_DEVICE: - case SRB_STATUS_INVALID_PATH_ID: - case SRB_STATUS_INVALID_TARGET_ID: - case SRB_STATUS_INVALID_LUN: - case SRB_STATUS_SELECTION_TIMEOUT: - scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; - break; - - case SRB_STATUS_COMMAND_TIMEOUT: - case SRB_STATUS_TIMEOUT: - scsicmd->result = DID_TIME_OUT << 16 | COMMAND_COMPLETE << 8; - break; - - case SRB_STATUS_BUSY: - scsicmd->result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; - break; - - case SRB_STATUS_BUS_RESET: - scsicmd->result = DID_RESET << 16 | COMMAND_COMPLETE << 8; - break; - - case SRB_STATUS_MESSAGE_REJECTED: - scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8; - break; - case SRB_STATUS_REQUEST_FLUSHED: - case SRB_STATUS_ERROR: - case SRB_STATUS_INVALID_REQUEST: - case SRB_STATUS_REQUEST_SENSE_FAILED: - case SRB_STATUS_NO_HBA: - case SRB_STATUS_UNEXPECTED_BUS_FREE: - case SRB_STATUS_PHASE_SEQUENCE_FAILURE: - case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: - case SRB_STATUS_DELAYED_RETRY: - case SRB_STATUS_BAD_FUNCTION: - case SRB_STATUS_NOT_STARTED: - case SRB_STATUS_NOT_IN_USE: - case SRB_STATUS_FORCE_ABORT: - case SRB_STATUS_DOMAIN_VALIDATION_FAIL: - default: -#ifdef AAC_DETAILED_STATUS_INFO - printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n", - le32_to_cpu(srbreply->srb_status) & 0x3F, - aac_get_status_string( - le32_to_cpu(srbreply->srb_status) & 0x3F), - scsicmd->cmnd[0], - le32_to_cpu(srbreply->scsi_status)); -#endif - if ((scsicmd->cmnd[0] == ATA_12) - || (scsicmd->cmnd[0] == ATA_16)) { - if (scsicmd->cmnd[2] & (0x01 << 5)) { - scsicmd->result = DID_OK << 16 - | COMMAND_COMPLETE << 8; - break; - } else { - scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8; - break; - } - } else { - scsicmd->result = DID_ERROR << 16 - | COMMAND_COMPLETE << 8; - break; - } - } - if (le32_to_cpu(srbreply->scsi_status) == SAM_STAT_CHECK_CONDITION) { - int len; - scsicmd->result |= SAM_STAT_CHECK_CONDITION; - len = min_t(u32, le32_to_cpu(srbreply->sense_data_size), - SCSI_SENSE_BUFFERSIZE); -#ifdef AAC_DETAILED_STATUS_INFO - printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", - le32_to_cpu(srbreply->status), len); -#endif - memcpy(scsicmd->sense_buffer, srbreply->sense_data, len); - } - /* - * OR in the scsi status (already shifted up a bit) - */ - scsicmd->result |= le32_to_cpu(srbreply->scsi_status); - - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - scsicmd->scsi_done(scsicmd); -} - -/** - * - * aac_send_scb_fib - * @scsicmd: the scsi command block - * - * This routine will form a FIB and fill in the aac_srb from the - * scsicmd passed in. - */ - -static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) -{ - struct fib* cmd_fibcontext; - struct aac_dev* dev; - int status; - - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - if (scmd_id(scsicmd) >= dev->maximum_num_physicals || - scsicmd->device->lun > 7) { - scsicmd->result = DID_NO_CONNECT << 16; - scsicmd->scsi_done(scsicmd); - return 0; - } - - /* - * Allocate and initialize a Fib then setup a BlockWrite command - */ - if (!(cmd_fibcontext = aac_fib_alloc(dev))) { - return -1; - } - status = aac_adapter_scsi(cmd_fibcontext, scsicmd); - - /* - * Check that the command queued to the controller - */ - if (status == -EINPROGRESS) { - scsicmd->SCp.phase = AAC_OWNER_FIRMWARE; - return 0; - } - - printk(KERN_WARNING "aac_srb: aac_fib_send failed with status: %d\n", status); - aac_fib_complete(cmd_fibcontext); - aac_fib_free(cmd_fibcontext); - - return -1; -} - -static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg) -{ - struct aac_dev *dev; - unsigned long byte_count = 0; - int nseg; - - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - // Get rid of old data - psg->count = 0; - psg->sg[0].addr = 0; - psg->sg[0].count = 0; - - nseg = scsi_dma_map(scsicmd); - BUG_ON(nseg < 0); - if (nseg) { - struct scatterlist *sg; - int i; - - psg->count = cpu_to_le32(nseg); - - scsi_for_each_sg(scsicmd, sg, nseg, i) { - psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg)); - psg->sg[i].count = cpu_to_le32(sg_dma_len(sg)); - byte_count += sg_dma_len(sg); - } - /* hba wants the size to be exact */ - if (byte_count > scsi_bufflen(scsicmd)) { - u32 temp = le32_to_cpu(psg->sg[i-1].count) - - (byte_count - scsi_bufflen(scsicmd)); - psg->sg[i-1].count = cpu_to_le32(temp); - byte_count = scsi_bufflen(scsicmd); - } - /* Check for command underflow */ - if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ - printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", - byte_count, scsicmd->underflow); - } - } - return byte_count; -} - - -static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg) -{ - struct aac_dev *dev; - unsigned long byte_count = 0; - u64 addr; - int nseg; - - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - // Get rid of old data - psg->count = 0; - psg->sg[0].addr[0] = 0; - psg->sg[0].addr[1] = 0; - psg->sg[0].count = 0; - - nseg = scsi_dma_map(scsicmd); - BUG_ON(nseg < 0); - if (nseg) { - struct scatterlist *sg; - int i; - - scsi_for_each_sg(scsicmd, sg, nseg, i) { - int count = sg_dma_len(sg); - addr = sg_dma_address(sg); - psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); - psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - psg->sg[i].count = cpu_to_le32(count); - byte_count += count; - } - psg->count = cpu_to_le32(nseg); - /* hba wants the size to be exact */ - if (byte_count > scsi_bufflen(scsicmd)) { - u32 temp = le32_to_cpu(psg->sg[i-1].count) - - (byte_count - scsi_bufflen(scsicmd)); - psg->sg[i-1].count = cpu_to_le32(temp); - byte_count = scsi_bufflen(scsicmd); - } - /* Check for command underflow */ - if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ - printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", - byte_count, scsicmd->underflow); - } - } - return byte_count; -} - -static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg) -{ - unsigned long byte_count = 0; - int nseg; - - // Get rid of old data - psg->count = 0; - psg->sg[0].next = 0; - psg->sg[0].prev = 0; - psg->sg[0].addr[0] = 0; - psg->sg[0].addr[1] = 0; - psg->sg[0].count = 0; - psg->sg[0].flags = 0; - - nseg = scsi_dma_map(scsicmd); - BUG_ON(nseg < 0); - if (nseg) { - struct scatterlist *sg; - int i; - - scsi_for_each_sg(scsicmd, sg, nseg, i) { - int count = sg_dma_len(sg); - u64 addr = sg_dma_address(sg); - psg->sg[i].next = 0; - psg->sg[i].prev = 0; - psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32)); - psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); - psg->sg[i].count = cpu_to_le32(count); - psg->sg[i].flags = 0; - byte_count += count; - } - psg->count = cpu_to_le32(nseg); - /* hba wants the size to be exact */ - if (byte_count > scsi_bufflen(scsicmd)) { - u32 temp = le32_to_cpu(psg->sg[i-1].count) - - (byte_count - scsi_bufflen(scsicmd)); - psg->sg[i-1].count = cpu_to_le32(temp); - byte_count = scsi_bufflen(scsicmd); - } - /* Check for command underflow */ - if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ - printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", - byte_count, scsicmd->underflow); - } - } - return byte_count; -} - -#ifdef AAC_DETAILED_STATUS_INFO - -struct aac_srb_status_info { - u32 status; - char *str; -}; - - -static struct aac_srb_status_info srb_status_info[] = { - { SRB_STATUS_PENDING, "Pending Status"}, - { SRB_STATUS_SUCCESS, "Success"}, - { SRB_STATUS_ABORTED, "Aborted Command"}, - { SRB_STATUS_ABORT_FAILED, "Abort Failed"}, - { SRB_STATUS_ERROR, "Error Event"}, - { SRB_STATUS_BUSY, "Device Busy"}, - { SRB_STATUS_INVALID_REQUEST, "Invalid Request"}, - { SRB_STATUS_INVALID_PATH_ID, "Invalid Path ID"}, - { SRB_STATUS_NO_DEVICE, "No Device"}, - { SRB_STATUS_TIMEOUT, "Timeout"}, - { SRB_STATUS_SELECTION_TIMEOUT, "Selection Timeout"}, - { SRB_STATUS_COMMAND_TIMEOUT, "Command Timeout"}, - { SRB_STATUS_MESSAGE_REJECTED, "Message Rejected"}, - { SRB_STATUS_BUS_RESET, "Bus Reset"}, - { SRB_STATUS_PARITY_ERROR, "Parity Error"}, - { SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"}, - { SRB_STATUS_NO_HBA, "No HBA"}, - { SRB_STATUS_DATA_OVERRUN, "Data Overrun/Data Underrun"}, - { SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"}, - { SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"}, - { SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"}, - { SRB_STATUS_REQUEST_FLUSHED, "Request Flushed"}, - { SRB_STATUS_DELAYED_RETRY, "Delayed Retry"}, - { SRB_STATUS_INVALID_LUN, "Invalid LUN"}, - { SRB_STATUS_INVALID_TARGET_ID, "Invalid TARGET ID"}, - { SRB_STATUS_BAD_FUNCTION, "Bad Function"}, - { SRB_STATUS_ERROR_RECOVERY, "Error Recovery"}, - { SRB_STATUS_NOT_STARTED, "Not Started"}, - { SRB_STATUS_NOT_IN_USE, "Not In Use"}, - { SRB_STATUS_FORCE_ABORT, "Force Abort"}, - { SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"}, - { 0xff, "Unknown Error"} -}; - -char *aac_get_status_string(u32 status) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(srb_status_info); i++) - if (srb_status_info[i].status == status) - return srb_status_info[i].str; - - return "Bad Status Code"; -} - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/aacraid.h b/ANDROID_3.4.5/drivers/scsi/aacraid/aacraid.h deleted file mode 100644 index 3fcf6272..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/aacraid.h +++ /dev/null @@ -1,2022 +0,0 @@ -#ifndef dprintk -# define dprintk(x) -#endif -/* eg: if (nblank(dprintk(x))) */ -#define _nblank(x) #x -#define nblank(x) _nblank(x)[0] - -#include - -/*------------------------------------------------------------------------------ - * D E F I N E S - *----------------------------------------------------------------------------*/ - -#ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 28900 -# define AAC_DRIVER_BRANCH "-ms" -#endif -#define MAXIMUM_NUM_CONTAINERS 32 - -#define AAC_NUM_MGT_FIB 8 -#define AAC_NUM_IO_FIB (512 - AAC_NUM_MGT_FIB) -#define AAC_NUM_FIB (AAC_NUM_IO_FIB + AAC_NUM_MGT_FIB) - -#define AAC_MAX_LUN (8) - -#define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff) -#define AAC_MAX_32BIT_SGBCOUNT ((unsigned short)256) - -#define AAC_DEBUG_INSTRUMENT_AIF_DELETE - -/* - * These macros convert from physical channels to virtual channels - */ -#define CONTAINER_CHANNEL (0) -#define CONTAINER_TO_CHANNEL(cont) (CONTAINER_CHANNEL) -#define CONTAINER_TO_ID(cont) (cont) -#define CONTAINER_TO_LUN(cont) (0) - -#define aac_phys_to_logical(x) ((x)+1) -#define aac_logical_to_phys(x) ((x)?(x)-1:0) - -/* #define AAC_DETAILED_STATUS_INFO */ - -struct diskparm -{ - int heads; - int sectors; - int cylinders; -}; - - -/* - * Firmware constants - */ - -#define CT_NONE 0 -#define CT_OK 218 -#define FT_FILESYS 8 /* ADAPTEC's "FSA"(tm) filesystem */ -#define FT_DRIVE 9 /* physical disk - addressable in scsi by bus/id/lun */ - -/* - * Host side memory scatter gather list - * Used by the adapter for read, write, and readdirplus operations - * We have separate 32 and 64 bit version because even - * on 64 bit systems not all cards support the 64 bit version - */ -struct sgentry { - __le32 addr; /* 32-bit address. */ - __le32 count; /* Length. */ -}; - -struct user_sgentry { - u32 addr; /* 32-bit address. */ - u32 count; /* Length. */ -}; - -struct sgentry64 { - __le32 addr[2]; /* 64-bit addr. 2 pieces for data alignment */ - __le32 count; /* Length. */ -}; - -struct user_sgentry64 { - u32 addr[2]; /* 64-bit addr. 2 pieces for data alignment */ - u32 count; /* Length. */ -}; - -struct sgentryraw { - __le32 next; /* reserved for F/W use */ - __le32 prev; /* reserved for F/W use */ - __le32 addr[2]; - __le32 count; - __le32 flags; /* reserved for F/W use */ -}; - -struct user_sgentryraw { - u32 next; /* reserved for F/W use */ - u32 prev; /* reserved for F/W use */ - u32 addr[2]; - u32 count; - u32 flags; /* reserved for F/W use */ -}; - -/* - * SGMAP - * - * This is the SGMAP structure for all commands that use - * 32-bit addressing. - */ - -struct sgmap { - __le32 count; - struct sgentry sg[1]; -}; - -struct user_sgmap { - u32 count; - struct user_sgentry sg[1]; -}; - -struct sgmap64 { - __le32 count; - struct sgentry64 sg[1]; -}; - -struct user_sgmap64 { - u32 count; - struct user_sgentry64 sg[1]; -}; - -struct sgmapraw { - __le32 count; - struct sgentryraw sg[1]; -}; - -struct user_sgmapraw { - u32 count; - struct user_sgentryraw sg[1]; -}; - -struct creation_info -{ - u8 buildnum; /* e.g., 588 */ - u8 usec; /* e.g., 588 */ - u8 via; /* e.g., 1 = FSU, - * 2 = API - */ - u8 year; /* e.g., 1997 = 97 */ - __le32 date; /* - * unsigned Month :4; // 1 - 12 - * unsigned Day :6; // 1 - 32 - * unsigned Hour :6; // 0 - 23 - * unsigned Minute :6; // 0 - 60 - * unsigned Second :6; // 0 - 60 - */ - __le32 serial[2]; /* e.g., 0x1DEADB0BFAFAF001 */ -}; - - -/* - * Define all the constants needed for the communication interface - */ - -/* - * Define how many queue entries each queue will have and the total - * number of entries for the entire communication interface. Also define - * how many queues we support. - * - * This has to match the controller - */ - -#define NUMBER_OF_COMM_QUEUES 8 // 4 command; 4 response -#define HOST_HIGH_CMD_ENTRIES 4 -#define HOST_NORM_CMD_ENTRIES 8 -#define ADAP_HIGH_CMD_ENTRIES 4 -#define ADAP_NORM_CMD_ENTRIES 512 -#define HOST_HIGH_RESP_ENTRIES 4 -#define HOST_NORM_RESP_ENTRIES 512 -#define ADAP_HIGH_RESP_ENTRIES 4 -#define ADAP_NORM_RESP_ENTRIES 8 - -#define TOTAL_QUEUE_ENTRIES \ - (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \ - HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES) - - -/* - * Set the queues on a 16 byte alignment - */ - -#define QUEUE_ALIGNMENT 16 - -/* - * The queue headers define the Communication Region queues. These - * are physically contiguous and accessible by both the adapter and the - * host. Even though all queue headers are in the same contiguous block - * they will be represented as individual units in the data structures. - */ - -struct aac_entry { - __le32 size; /* Size in bytes of Fib which this QE points to */ - __le32 addr; /* Receiver address of the FIB */ -}; - -/* - * The adapter assumes the ProducerIndex and ConsumerIndex are grouped - * adjacently and in that order. - */ - -struct aac_qhdr { - __le64 header_addr;/* Address to hand the adapter to access - to this queue head */ - __le32 *producer; /* The producer index for this queue (host address) */ - __le32 *consumer; /* The consumer index for this queue (host address) */ -}; - -/* - * Define all the events which the adapter would like to notify - * the host of. - */ - -#define HostNormCmdQue 1 /* Change in host normal priority command queue */ -#define HostHighCmdQue 2 /* Change in host high priority command queue */ -#define HostNormRespQue 3 /* Change in host normal priority response queue */ -#define HostHighRespQue 4 /* Change in host high priority response queue */ -#define AdapNormRespNotFull 5 -#define AdapHighRespNotFull 6 -#define AdapNormCmdNotFull 7 -#define AdapHighCmdNotFull 8 -#define SynchCommandComplete 9 -#define AdapInternalError 0xfe /* The adapter detected an internal error shutting down */ - -/* - * Define all the events the host wishes to notify the - * adapter of. The first four values much match the Qid the - * corresponding queue. - */ - -#define AdapNormCmdQue 2 -#define AdapHighCmdQue 3 -#define AdapNormRespQue 6 -#define AdapHighRespQue 7 -#define HostShutdown 8 -#define HostPowerFail 9 -#define FatalCommError 10 -#define HostNormRespNotFull 11 -#define HostHighRespNotFull 12 -#define HostNormCmdNotFull 13 -#define HostHighCmdNotFull 14 -#define FastIo 15 -#define AdapPrintfDone 16 - -/* - * Define all the queues that the adapter and host use to communicate - * Number them to match the physical queue layout. - */ - -enum aac_queue_types { - HostNormCmdQueue = 0, /* Adapter to host normal priority command traffic */ - HostHighCmdQueue, /* Adapter to host high priority command traffic */ - AdapNormCmdQueue, /* Host to adapter normal priority command traffic */ - AdapHighCmdQueue, /* Host to adapter high priority command traffic */ - HostNormRespQueue, /* Adapter to host normal priority response traffic */ - HostHighRespQueue, /* Adapter to host high priority response traffic */ - AdapNormRespQueue, /* Host to adapter normal priority response traffic */ - AdapHighRespQueue /* Host to adapter high priority response traffic */ -}; - -/* - * Assign type values to the FSA communication data structures - */ - -#define FIB_MAGIC 0x0001 - -/* - * Define the priority levels the FSA communication routines support. - */ - -#define FsaNormal 1 - -/* transport FIB header (PMC) */ -struct aac_fib_xporthdr { - u64 HostAddress; /* FIB host address w/o xport header */ - u32 Size; /* FIB size excluding xport header */ - u32 Handle; /* driver handle to reference the FIB */ - u64 Reserved[2]; -}; - -#define ALIGN32 32 - -/* - * Define the FIB. The FIB is the where all the requested data and - * command information are put to the application on the FSA adapter. - */ - -struct aac_fibhdr { - __le32 XferState; /* Current transfer state for this CCB */ - __le16 Command; /* Routing information for the destination */ - u8 StructType; /* Type FIB */ - u8 Flags; /* Flags for FIB */ - __le16 Size; /* Size of this FIB in bytes */ - __le16 SenderSize; /* Size of the FIB in the sender - (for response sizing) */ - __le32 SenderFibAddress; /* Host defined data in the FIB */ - __le32 ReceiverFibAddress;/* Logical address of this FIB for - the adapter */ - u32 SenderData; /* Place holder for the sender to store data */ - union { - struct { - __le32 _ReceiverTimeStart; /* Timestamp for - receipt of fib */ - __le32 _ReceiverTimeDone; /* Timestamp for - completion of fib */ - } _s; - } _u; -}; - -struct hw_fib { - struct aac_fibhdr header; - u8 data[512-sizeof(struct aac_fibhdr)]; // Command specific data -}; - -/* - * FIB commands - */ - -#define TestCommandResponse 1 -#define TestAdapterCommand 2 -/* - * Lowlevel and comm commands - */ -#define LastTestCommand 100 -#define ReinitHostNormCommandQueue 101 -#define ReinitHostHighCommandQueue 102 -#define ReinitHostHighRespQueue 103 -#define ReinitHostNormRespQueue 104 -#define ReinitAdapNormCommandQueue 105 -#define ReinitAdapHighCommandQueue 107 -#define ReinitAdapHighRespQueue 108 -#define ReinitAdapNormRespQueue 109 -#define InterfaceShutdown 110 -#define DmaCommandFib 120 -#define StartProfile 121 -#define TermProfile 122 -#define SpeedTest 123 -#define TakeABreakPt 124 -#define RequestPerfData 125 -#define SetInterruptDefTimer 126 -#define SetInterruptDefCount 127 -#define GetInterruptDefStatus 128 -#define LastCommCommand 129 -/* - * Filesystem commands - */ -#define NuFileSystem 300 -#define UFS 301 -#define HostFileSystem 302 -#define LastFileSystemCommand 303 -/* - * Container Commands - */ -#define ContainerCommand 500 -#define ContainerCommand64 501 -#define ContainerRawIo 502 -/* - * Scsi Port commands (scsi passthrough) - */ -#define ScsiPortCommand 600 -#define ScsiPortCommand64 601 -/* - * Misc house keeping and generic adapter initiated commands - */ -#define AifRequest 700 -#define CheckRevision 701 -#define FsaHostShutdown 702 -#define RequestAdapterInfo 703 -#define IsAdapterPaused 704 -#define SendHostTime 705 -#define RequestSupplementAdapterInfo 706 -#define LastMiscCommand 707 - -/* - * Commands that will target the failover level on the FSA adapter - */ - -enum fib_xfer_state { - HostOwned = (1<<0), - AdapterOwned = (1<<1), - FibInitialized = (1<<2), - FibEmpty = (1<<3), - AllocatedFromPool = (1<<4), - SentFromHost = (1<<5), - SentFromAdapter = (1<<6), - ResponseExpected = (1<<7), - NoResponseExpected = (1<<8), - AdapterProcessed = (1<<9), - HostProcessed = (1<<10), - HighPriority = (1<<11), - NormalPriority = (1<<12), - Async = (1<<13), - AsyncIo = (1<<13), // rpbfix: remove with new regime - PageFileIo = (1<<14), // rpbfix: remove with new regime - ShutdownRequest = (1<<15), - LazyWrite = (1<<16), // rpbfix: remove with new regime - AdapterMicroFib = (1<<17), - BIOSFibPath = (1<<18), - FastResponseCapable = (1<<19), - ApiFib = (1<<20), /* Its an API Fib */ - /* PMC NEW COMM: There is no more AIF data pending */ - NoMoreAifDataAvailable = (1<<21) -}; - -/* - * The following defines needs to be updated any time there is an - * incompatible change made to the aac_init structure. - */ - -#define ADAPTER_INIT_STRUCT_REVISION 3 -#define ADAPTER_INIT_STRUCT_REVISION_4 4 // rocket science -#define ADAPTER_INIT_STRUCT_REVISION_6 6 /* PMC src */ - -struct aac_init -{ - __le32 InitStructRevision; - __le32 MiniPortRevision; - __le32 fsrev; - __le32 CommHeaderAddress; - __le32 FastIoCommAreaAddress; - __le32 AdapterFibsPhysicalAddress; - __le32 AdapterFibsVirtualAddress; - __le32 AdapterFibsSize; - __le32 AdapterFibAlign; - __le32 printfbuf; - __le32 printfbufsiz; - __le32 HostPhysMemPages; /* number of 4k pages of host - physical memory */ - __le32 HostElapsedSeconds; /* number of seconds since 1970. */ - /* - * ADAPTER_INIT_STRUCT_REVISION_4 begins here - */ - __le32 InitFlags; /* flags for supported features */ -#define INITFLAGS_NEW_COMM_SUPPORTED 0x00000001 -#define INITFLAGS_DRIVER_USES_UTC_TIME 0x00000010 -#define INITFLAGS_DRIVER_SUPPORTS_PM 0x00000020 -#define INITFLAGS_NEW_COMM_TYPE1_SUPPORTED 0x00000041 - __le32 MaxIoCommands; /* max outstanding commands */ - __le32 MaxIoSize; /* largest I/O command */ - __le32 MaxFibSize; /* largest FIB to adapter */ - /* ADAPTER_INIT_STRUCT_REVISION_5 begins here */ - __le32 MaxNumAif; /* max number of aif */ - /* ADAPTER_INIT_STRUCT_REVISION_6 begins here */ - __le32 HostRRQ_AddrLow; - __le32 HostRRQ_AddrHigh; /* Host RRQ (response queue) for SRC */ -}; - -enum aac_log_level { - LOG_AAC_INIT = 10, - LOG_AAC_INFORMATIONAL = 20, - LOG_AAC_WARNING = 30, - LOG_AAC_LOW_ERROR = 40, - LOG_AAC_MEDIUM_ERROR = 50, - LOG_AAC_HIGH_ERROR = 60, - LOG_AAC_PANIC = 70, - LOG_AAC_DEBUG = 80, - LOG_AAC_WINDBG_PRINT = 90 -}; - -#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT 0x030b -#define FSAFS_NTC_FIB_CONTEXT 0x030c - -struct aac_dev; -struct fib; -struct scsi_cmnd; - -struct adapter_ops -{ - /* Low level operations */ - void (*adapter_interrupt)(struct aac_dev *dev); - void (*adapter_notify)(struct aac_dev *dev, u32 event); - void (*adapter_disable_int)(struct aac_dev *dev); - void (*adapter_enable_int)(struct aac_dev *dev); - int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); - int (*adapter_check_health)(struct aac_dev *dev); - int (*adapter_restart)(struct aac_dev *dev, int bled); - /* Transport operations */ - int (*adapter_ioremap)(struct aac_dev * dev, u32 size); - irq_handler_t adapter_intr; - /* Packet operations */ - int (*adapter_deliver)(struct fib * fib); - int (*adapter_bounds)(struct aac_dev * dev, struct scsi_cmnd * cmd, u64 lba); - int (*adapter_read)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count); - int (*adapter_write)(struct fib * fib, struct scsi_cmnd * cmd, u64 lba, u32 count, int fua); - int (*adapter_scsi)(struct fib * fib, struct scsi_cmnd * cmd); - /* Administrative operations */ - int (*adapter_comm)(struct aac_dev * dev, int comm); -}; - -/* - * Define which interrupt handler needs to be installed - */ - -struct aac_driver_ident -{ - int (*init)(struct aac_dev *dev); - char * name; - char * vname; - char * model; - u16 channels; - int quirks; -}; -/* - * Some adapter firmware needs communication memory - * below 2gig. This tells the init function to set the - * dma mask such that fib memory will be allocated where the - * adapter firmware can get to it. - */ -#define AAC_QUIRK_31BIT 0x0001 - -/* - * Some adapter firmware, when the raid card's cache is turned off, can not - * split up scatter gathers in order to deal with the limits of the - * underlying CHIM. This limit is 34 scatter gather elements. - */ -#define AAC_QUIRK_34SG 0x0002 - -/* - * This adapter is a slave (no Firmware) - */ -#define AAC_QUIRK_SLAVE 0x0004 - -/* - * This adapter is a master. - */ -#define AAC_QUIRK_MASTER 0x0008 - -/* - * Some adapter firmware perform poorly when it must split up scatter gathers - * in order to deal with the limits of the underlying CHIM. This limit in this - * class of adapters is 17 scatter gather elements. - */ -#define AAC_QUIRK_17SG 0x0010 - -/* - * Some adapter firmware does not support 64 bit scsi passthrough - * commands. - */ -#define AAC_QUIRK_SCSI_32 0x0020 - -/* - * The adapter interface specs all queues to be located in the same - * physically contiguous block. The host structure that defines the - * commuication queues will assume they are each a separate physically - * contiguous memory region that will support them all being one big - * contiguous block. - * There is a command and response queue for each level and direction of - * commuication. These regions are accessed by both the host and adapter. - */ - -struct aac_queue { - u64 logical; /*address we give the adapter */ - struct aac_entry *base; /*system virtual address */ - struct aac_qhdr headers; /*producer,consumer q headers*/ - u32 entries; /*Number of queue entries */ - wait_queue_head_t qfull; /*Event to wait on if q full */ - wait_queue_head_t cmdready; /*Cmd ready from the adapter */ - /* This is only valid for adapter to host command queues. */ - spinlock_t *lock; /* Spinlock for this queue must take this lock before accessing the lock */ - spinlock_t lockdata; /* Actual lock (used only on one side of the lock) */ - struct list_head cmdq; /* A queue of FIBs which need to be prcessed by the FS thread. This is */ - /* only valid for command queues which receive entries from the adapter. */ - u32 numpending; /* Number of entries on outstanding queue. */ - struct aac_dev * dev; /* Back pointer to adapter structure */ -}; - -/* - * Message queues. The order here is important, see also the - * queue type ordering - */ - -struct aac_queue_block -{ - struct aac_queue queue[8]; -}; - -/* - * SaP1 Message Unit Registers - */ - -struct sa_drawbridge_CSR { - /* Offset | Name */ - __le32 reserved[10]; /* 00h-27h | Reserved */ - u8 LUT_Offset; /* 28h | Lookup Table Offset */ - u8 reserved1[3]; /* 29h-2bh | Reserved */ - __le32 LUT_Data; /* 2ch | Looup Table Data */ - __le32 reserved2[26]; /* 30h-97h | Reserved */ - __le16 PRICLEARIRQ; /* 98h | Primary Clear Irq */ - __le16 SECCLEARIRQ; /* 9ah | Secondary Clear Irq */ - __le16 PRISETIRQ; /* 9ch | Primary Set Irq */ - __le16 SECSETIRQ; /* 9eh | Secondary Set Irq */ - __le16 PRICLEARIRQMASK;/* a0h | Primary Clear Irq Mask */ - __le16 SECCLEARIRQMASK;/* a2h | Secondary Clear Irq Mask */ - __le16 PRISETIRQMASK; /* a4h | Primary Set Irq Mask */ - __le16 SECSETIRQMASK; /* a6h | Secondary Set Irq Mask */ - __le32 MAILBOX0; /* a8h | Scratchpad 0 */ - __le32 MAILBOX1; /* ach | Scratchpad 1 */ - __le32 MAILBOX2; /* b0h | Scratchpad 2 */ - __le32 MAILBOX3; /* b4h | Scratchpad 3 */ - __le32 MAILBOX4; /* b8h | Scratchpad 4 */ - __le32 MAILBOX5; /* bch | Scratchpad 5 */ - __le32 MAILBOX6; /* c0h | Scratchpad 6 */ - __le32 MAILBOX7; /* c4h | Scratchpad 7 */ - __le32 ROM_Setup_Data; /* c8h | Rom Setup and Data */ - __le32 ROM_Control_Addr;/* cch | Rom Control and Address */ - __le32 reserved3[12]; /* d0h-ffh | reserved */ - __le32 LUT[64]; /* 100h-1ffh | Lookup Table Entries */ -}; - -#define Mailbox0 SaDbCSR.MAILBOX0 -#define Mailbox1 SaDbCSR.MAILBOX1 -#define Mailbox2 SaDbCSR.MAILBOX2 -#define Mailbox3 SaDbCSR.MAILBOX3 -#define Mailbox4 SaDbCSR.MAILBOX4 -#define Mailbox5 SaDbCSR.MAILBOX5 -#define Mailbox6 SaDbCSR.MAILBOX6 -#define Mailbox7 SaDbCSR.MAILBOX7 - -#define DoorbellReg_p SaDbCSR.PRISETIRQ -#define DoorbellReg_s SaDbCSR.SECSETIRQ -#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ - - -#define DOORBELL_0 0x0001 -#define DOORBELL_1 0x0002 -#define DOORBELL_2 0x0004 -#define DOORBELL_3 0x0008 -#define DOORBELL_4 0x0010 -#define DOORBELL_5 0x0020 -#define DOORBELL_6 0x0040 - - -#define PrintfReady DOORBELL_5 -#define PrintfDone DOORBELL_5 - -struct sa_registers { - struct sa_drawbridge_CSR SaDbCSR; /* 98h - c4h */ -}; - - -#define Sa_MINIPORT_REVISION 1 - -#define sa_readw(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) -#define sa_readl(AEP, CSR) readl(&((AEP)->regs.sa->CSR)) -#define sa_writew(AEP, CSR, value) writew(value, &((AEP)->regs.sa->CSR)) -#define sa_writel(AEP, CSR, value) writel(value, &((AEP)->regs.sa->CSR)) - -/* - * Rx Message Unit Registers - */ - -struct rx_mu_registers { - /* Local | PCI*| Name */ - __le32 ARSR; /* 1300h | 00h | APIC Register Select Register */ - __le32 reserved0; /* 1304h | 04h | Reserved */ - __le32 AWR; /* 1308h | 08h | APIC Window Register */ - __le32 reserved1; /* 130Ch | 0Ch | Reserved */ - __le32 IMRx[2]; /* 1310h | 10h | Inbound Message Registers */ - __le32 OMRx[2]; /* 1318h | 18h | Outbound Message Registers */ - __le32 IDR; /* 1320h | 20h | Inbound Doorbell Register */ - __le32 IISR; /* 1324h | 24h | Inbound Interrupt - Status Register */ - __le32 IIMR; /* 1328h | 28h | Inbound Interrupt - Mask Register */ - __le32 ODR; /* 132Ch | 2Ch | Outbound Doorbell Register */ - __le32 OISR; /* 1330h | 30h | Outbound Interrupt - Status Register */ - __le32 OIMR; /* 1334h | 34h | Outbound Interrupt - Mask Register */ - __le32 reserved2; /* 1338h | 38h | Reserved */ - __le32 reserved3; /* 133Ch | 3Ch | Reserved */ - __le32 InboundQueue;/* 1340h | 40h | Inbound Queue Port relative to firmware */ - __le32 OutboundQueue;/*1344h | 44h | Outbound Queue Port relative to firmware */ - /* * Must access through ATU Inbound - Translation Window */ -}; - -struct rx_inbound { - __le32 Mailbox[8]; -}; - -#define INBOUNDDOORBELL_0 0x00000001 -#define INBOUNDDOORBELL_1 0x00000002 -#define INBOUNDDOORBELL_2 0x00000004 -#define INBOUNDDOORBELL_3 0x00000008 -#define INBOUNDDOORBELL_4 0x00000010 -#define INBOUNDDOORBELL_5 0x00000020 -#define INBOUNDDOORBELL_6 0x00000040 - -#define OUTBOUNDDOORBELL_0 0x00000001 -#define OUTBOUNDDOORBELL_1 0x00000002 -#define OUTBOUNDDOORBELL_2 0x00000004 -#define OUTBOUNDDOORBELL_3 0x00000008 -#define OUTBOUNDDOORBELL_4 0x00000010 - -#define InboundDoorbellReg MUnit.IDR -#define OutboundDoorbellReg MUnit.ODR - -struct rx_registers { - struct rx_mu_registers MUnit; /* 1300h - 1347h */ - __le32 reserved1[2]; /* 1348h - 134ch */ - struct rx_inbound IndexRegs; -}; - -#define rx_readb(AEP, CSR) readb(&((AEP)->regs.rx->CSR)) -#define rx_readl(AEP, CSR) readl(&((AEP)->regs.rx->CSR)) -#define rx_writeb(AEP, CSR, value) writeb(value, &((AEP)->regs.rx->CSR)) -#define rx_writel(AEP, CSR, value) writel(value, &((AEP)->regs.rx->CSR)) - -/* - * Rkt Message Unit Registers (same as Rx, except a larger reserve region) - */ - -#define rkt_mu_registers rx_mu_registers -#define rkt_inbound rx_inbound - -struct rkt_registers { - struct rkt_mu_registers MUnit; /* 1300h - 1347h */ - __le32 reserved1[1006]; /* 1348h - 22fch */ - struct rkt_inbound IndexRegs; /* 2300h - */ -}; - -#define rkt_readb(AEP, CSR) readb(&((AEP)->regs.rkt->CSR)) -#define rkt_readl(AEP, CSR) readl(&((AEP)->regs.rkt->CSR)) -#define rkt_writeb(AEP, CSR, value) writeb(value, &((AEP)->regs.rkt->CSR)) -#define rkt_writel(AEP, CSR, value) writel(value, &((AEP)->regs.rkt->CSR)) - -/* - * PMC SRC message unit registers - */ - -#define src_inbound rx_inbound - -struct src_mu_registers { - /* PCI*| Name */ - __le32 reserved0[8]; /* 00h | Reserved */ - __le32 IDR; /* 20h | Inbound Doorbell Register */ - __le32 IISR; /* 24h | Inbound Int. Status Register */ - __le32 reserved1[3]; /* 28h | Reserved */ - __le32 OIMR; /* 34h | Outbound Int. Mask Register */ - __le32 reserved2[25]; /* 38h | Reserved */ - __le32 ODR_R; /* 9ch | Outbound Doorbell Read */ - __le32 ODR_C; /* a0h | Outbound Doorbell Clear */ - __le32 reserved3[6]; /* a4h | Reserved */ - __le32 OMR; /* bch | Outbound Message Register */ - __le32 IQ_L; /* c0h | Inbound Queue (Low address) */ - __le32 IQ_H; /* c4h | Inbound Queue (High address) */ -}; - -struct src_registers { - struct src_mu_registers MUnit; /* 00h - c7h */ - union { - struct { - __le32 reserved1[130790]; /* c8h - 7fc5fh */ - struct src_inbound IndexRegs; /* 7fc60h */ - } tupelo; - struct { - __le32 reserved1[974]; /* c8h - fffh */ - struct src_inbound IndexRegs; /* 1000h */ - } denali; - } u; -}; - -#define src_readb(AEP, CSR) readb(&((AEP)->regs.src.bar0->CSR)) -#define src_readl(AEP, CSR) readl(&((AEP)->regs.src.bar0->CSR)) -#define src_writeb(AEP, CSR, value) writeb(value, \ - &((AEP)->regs.src.bar0->CSR)) -#define src_writel(AEP, CSR, value) writel(value, \ - &((AEP)->regs.src.bar0->CSR)) - -#define SRC_ODR_SHIFT 12 -#define SRC_IDR_SHIFT 9 - -typedef void (*fib_callback)(void *ctxt, struct fib *fibctx); - -struct aac_fib_context { - s16 type; // used for verification of structure - s16 size; - u32 unique; // unique value representing this context - ulong jiffies; // used for cleanup - dmb changed to ulong - struct list_head next; // used to link context's into a linked list - struct semaphore wait_sem; // this is used to wait for the next fib to arrive. - int wait; // Set to true when thread is in WaitForSingleObject - unsigned long count; // total number of FIBs on FibList - struct list_head fib_list; // this holds fibs and their attachd hw_fibs -}; - -struct sense_data { - u8 error_code; /* 70h (current errors), 71h(deferred errors) */ - u8 valid:1; /* A valid bit of one indicates that the information */ - /* field contains valid information as defined in the - * SCSI-2 Standard. - */ - u8 segment_number; /* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */ - u8 sense_key:4; /* Sense Key */ - u8 reserved:1; - u8 ILI:1; /* Incorrect Length Indicator */ - u8 EOM:1; /* End Of Medium - reserved for random access devices */ - u8 filemark:1; /* Filemark - reserved for random access devices */ - - u8 information[4]; /* for direct-access devices, contains the unsigned - * logical block address or residue associated with - * the sense key - */ - u8 add_sense_len; /* number of additional sense bytes to follow this field */ - u8 cmnd_info[4]; /* not used */ - u8 ASC; /* Additional Sense Code */ - u8 ASCQ; /* Additional Sense Code Qualifier */ - u8 FRUC; /* Field Replaceable Unit Code - not used */ - u8 bit_ptr:3; /* indicates which byte of the CDB or parameter data - * was in error - */ - u8 BPV:1; /* bit pointer valid (BPV): 1- indicates that - * the bit_ptr field has valid value - */ - u8 reserved2:2; - u8 CD:1; /* command data bit: 1- illegal parameter in CDB. - * 0- illegal parameter in data. - */ - u8 SKSV:1; - u8 field_ptr[2]; /* byte of the CDB or parameter data in error */ -}; - -struct fsa_dev_info { - u64 last; - u64 size; - u32 type; - u32 config_waiting_on; - unsigned long config_waiting_stamp; - u16 queue_depth; - u8 config_needed; - u8 valid; - u8 ro; - u8 locked; - u8 deleted; - char devname[8]; - struct sense_data sense_data; -}; - -struct fib { - void *next; /* this is used by the allocator */ - s16 type; - s16 size; - /* - * The Adapter that this I/O is destined for. - */ - struct aac_dev *dev; - /* - * This is the event the sendfib routine will wait on if the - * caller did not pass one and this is synch io. - */ - struct semaphore event_wait; - spinlock_t event_lock; - - u32 done; /* gets set to 1 when fib is complete */ - fib_callback callback; - void *callback_data; - u32 flags; // u32 dmb was ulong - /* - * And for the internal issue/reply queues (we may be able - * to merge these two) - */ - struct list_head fiblink; - void *data; - struct hw_fib *hw_fib_va; /* Actual shared object */ - dma_addr_t hw_fib_pa; /* physical address of hw_fib*/ -}; - -/* - * Adapter Information Block - * - * This is returned by the RequestAdapterInfo block - */ - -struct aac_adapter_info -{ - __le32 platform; - __le32 cpu; - __le32 subcpu; - __le32 clock; - __le32 execmem; - __le32 buffermem; - __le32 totalmem; - __le32 kernelrev; - __le32 kernelbuild; - __le32 monitorrev; - __le32 monitorbuild; - __le32 hwrev; - __le32 hwbuild; - __le32 biosrev; - __le32 biosbuild; - __le32 cluster; - __le32 clusterchannelmask; - __le32 serial[2]; - __le32 battery; - __le32 options; - __le32 OEM; -}; - -struct aac_supplement_adapter_info -{ - u8 AdapterTypeText[17+1]; - u8 Pad[2]; - __le32 FlashMemoryByteSize; - __le32 FlashImageId; - __le32 MaxNumberPorts; - __le32 Version; - __le32 FeatureBits; - u8 SlotNumber; - u8 ReservedPad0[3]; - u8 BuildDate[12]; - __le32 CurrentNumberPorts; - struct { - u8 AssemblyPn[8]; - u8 FruPn[8]; - u8 BatteryFruPn[8]; - u8 EcVersionString[8]; - u8 Tsid[12]; - } VpdInfo; - __le32 FlashFirmwareRevision; - __le32 FlashFirmwareBuild; - __le32 RaidTypeMorphOptions; - __le32 FlashFirmwareBootRevision; - __le32 FlashFirmwareBootBuild; - u8 MfgPcbaSerialNo[12]; - u8 MfgWWNName[8]; - __le32 SupportedOptions2; - __le32 StructExpansion; - /* StructExpansion == 1 */ - __le32 FeatureBits3; - __le32 SupportedPerformanceModes; - __le32 ReservedForFutureGrowth[80]; -}; -#define AAC_FEATURE_FALCON cpu_to_le32(0x00000010) -#define AAC_FEATURE_JBOD cpu_to_le32(0x08000000) -/* SupportedOptions2 */ -#define AAC_OPTION_MU_RESET cpu_to_le32(0x00000001) -#define AAC_OPTION_IGNORE_RESET cpu_to_le32(0x00000002) -#define AAC_OPTION_POWER_MANAGEMENT cpu_to_le32(0x00000004) -#define AAC_OPTION_DOORBELL_RESET cpu_to_le32(0x00004000) -#define AAC_SIS_VERSION_V3 3 -#define AAC_SIS_SLOT_UNKNOWN 0xFF - -#define GetBusInfo 0x00000009 -struct aac_bus_info { - __le32 Command; /* VM_Ioctl */ - __le32 ObjType; /* FT_DRIVE */ - __le32 MethodId; /* 1 = SCSI Layer */ - __le32 ObjectId; /* Handle */ - __le32 CtlCmd; /* GetBusInfo */ -}; - -struct aac_bus_info_response { - __le32 Status; /* ST_OK */ - __le32 ObjType; - __le32 MethodId; /* unused */ - __le32 ObjectId; /* unused */ - __le32 CtlCmd; /* unused */ - __le32 ProbeComplete; - __le32 BusCount; - __le32 TargetsPerBus; - u8 InitiatorBusId[10]; - u8 BusValid[10]; -}; - -/* - * Battery platforms - */ -#define AAC_BAT_REQ_PRESENT (1) -#define AAC_BAT_REQ_NOTPRESENT (2) -#define AAC_BAT_OPT_PRESENT (3) -#define AAC_BAT_OPT_NOTPRESENT (4) -#define AAC_BAT_NOT_SUPPORTED (5) -/* - * cpu types - */ -#define AAC_CPU_SIMULATOR (1) -#define AAC_CPU_I960 (2) -#define AAC_CPU_STRONGARM (3) - -/* - * Supported Options - */ -#define AAC_OPT_SNAPSHOT cpu_to_le32(1) -#define AAC_OPT_CLUSTERS cpu_to_le32(1<<1) -#define AAC_OPT_WRITE_CACHE cpu_to_le32(1<<2) -#define AAC_OPT_64BIT_DATA cpu_to_le32(1<<3) -#define AAC_OPT_HOST_TIME_FIB cpu_to_le32(1<<4) -#define AAC_OPT_RAID50 cpu_to_le32(1<<5) -#define AAC_OPT_4GB_WINDOW cpu_to_le32(1<<6) -#define AAC_OPT_SCSI_UPGRADEABLE cpu_to_le32(1<<7) -#define AAC_OPT_SOFT_ERR_REPORT cpu_to_le32(1<<8) -#define AAC_OPT_SUPPORTED_RECONDITION cpu_to_le32(1<<9) -#define AAC_OPT_SGMAP_HOST64 cpu_to_le32(1<<10) -#define AAC_OPT_ALARM cpu_to_le32(1<<11) -#define AAC_OPT_NONDASD cpu_to_le32(1<<12) -#define AAC_OPT_SCSI_MANAGED cpu_to_le32(1<<13) -#define AAC_OPT_RAID_SCSI_MODE cpu_to_le32(1<<14) -#define AAC_OPT_SUPPLEMENT_ADAPTER_INFO cpu_to_le32(1<<16) -#define AAC_OPT_NEW_COMM cpu_to_le32(1<<17) -#define AAC_OPT_NEW_COMM_64 cpu_to_le32(1<<18) -#define AAC_OPT_NEW_COMM_TYPE1 cpu_to_le32(1<<28) -#define AAC_OPT_NEW_COMM_TYPE2 cpu_to_le32(1<<29) -#define AAC_OPT_NEW_COMM_TYPE3 cpu_to_le32(1<<30) -#define AAC_OPT_NEW_COMM_TYPE4 cpu_to_le32(1<<31) - - -struct aac_dev -{ - struct list_head entry; - const char *name; - int id; - - /* - * negotiated FIB settings - */ - unsigned max_fib_size; - unsigned sg_tablesize; - unsigned max_num_aif; - - /* - * Map for 128 fib objects (64k) - */ - dma_addr_t hw_fib_pa; - struct hw_fib *hw_fib_va; - struct hw_fib *aif_base_va; - /* - * Fib Headers - */ - struct fib *fibs; - - struct fib *free_fib; - spinlock_t fib_lock; - - struct aac_queue_block *queues; - /* - * The user API will use an IOCTL to register itself to receive - * FIBs from the adapter. The following list is used to keep - * track of all the threads that have requested these FIBs. The - * mutex is used to synchronize access to all data associated - * with the adapter fibs. - */ - struct list_head fib_list; - - struct adapter_ops a_ops; - unsigned long fsrev; /* Main driver's revision number */ - - unsigned long dbg_base; /* address of UART - * debug buffer */ - - unsigned base_size, dbg_size; /* Size of - * mapped in region */ - - struct aac_init *init; /* Holds initialization info to communicate with adapter */ - dma_addr_t init_pa; /* Holds physical address of the init struct */ - - u32 *host_rrq; /* response queue - * if AAC_COMM_MESSAGE_TYPE1 */ - - dma_addr_t host_rrq_pa; /* phys. address */ - u32 host_rrq_idx; /* index into rrq buffer */ - - struct pci_dev *pdev; /* Our PCI interface */ - void * printfbuf; /* pointer to buffer used for printf's from the adapter */ - void * comm_addr; /* Base address of Comm area */ - dma_addr_t comm_phys; /* Physical Address of Comm area */ - size_t comm_size; - - struct Scsi_Host *scsi_host_ptr; - int maximum_num_containers; - int maximum_num_physicals; - int maximum_num_channels; - struct fsa_dev_info *fsa_dev; - struct task_struct *thread; - int cardtype; - - /* - * The following is the device specific extension. - */ -#ifndef AAC_MIN_FOOTPRINT_SIZE -# define AAC_MIN_FOOTPRINT_SIZE 8192 -# define AAC_MIN_SRC_BAR0_SIZE 0x400000 -# define AAC_MIN_SRC_BAR1_SIZE 0x800 -# define AAC_MIN_SRCV_BAR0_SIZE 0x100000 -# define AAC_MIN_SRCV_BAR1_SIZE 0x400 -#endif - union - { - struct sa_registers __iomem *sa; - struct rx_registers __iomem *rx; - struct rkt_registers __iomem *rkt; - struct { - struct src_registers __iomem *bar0; - char __iomem *bar1; - } src; - } regs; - volatile void __iomem *base, *dbg_base_mapped; - volatile struct rx_inbound __iomem *IndexRegs; - u32 OIMR; /* Mask Register Cache */ - /* - * AIF thread states - */ - u32 aif_thread; - struct aac_adapter_info adapter_info; - struct aac_supplement_adapter_info supplement_adapter_info; - /* These are in adapter info but they are in the io flow so - * lets break them out so we don't have to do an AND to check them - */ - u8 nondasd_support; - u8 jbod; - u8 cache_protected; - u8 dac_support; - u8 needs_dac; - u8 raid_scsi_mode; - u8 comm_interface; -# define AAC_COMM_PRODUCER 0 -# define AAC_COMM_MESSAGE 1 -# define AAC_COMM_MESSAGE_TYPE1 3 - u8 raw_io_interface; - u8 raw_io_64; - u8 printf_enabled; - u8 in_reset; - u8 msi; - int management_fib_count; - spinlock_t manage_lock; - spinlock_t sync_lock; - int sync_mode; - struct fib *sync_fib; - struct list_head sync_fib_list; -}; - -#define aac_adapter_interrupt(dev) \ - (dev)->a_ops.adapter_interrupt(dev) - -#define aac_adapter_notify(dev, event) \ - (dev)->a_ops.adapter_notify(dev, event) - -#define aac_adapter_disable_int(dev) \ - (dev)->a_ops.adapter_disable_int(dev) - -#define aac_adapter_enable_int(dev) \ - (dev)->a_ops.adapter_enable_int(dev) - -#define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \ - (dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) - -#define aac_adapter_check_health(dev) \ - (dev)->a_ops.adapter_check_health(dev) - -#define aac_adapter_restart(dev,bled) \ - (dev)->a_ops.adapter_restart(dev,bled) - -#define aac_adapter_ioremap(dev, size) \ - (dev)->a_ops.adapter_ioremap(dev, size) - -#define aac_adapter_deliver(fib) \ - ((fib)->dev)->a_ops.adapter_deliver(fib) - -#define aac_adapter_bounds(dev,cmd,lba) \ - dev->a_ops.adapter_bounds(dev,cmd,lba) - -#define aac_adapter_read(fib,cmd,lba,count) \ - ((fib)->dev)->a_ops.adapter_read(fib,cmd,lba,count) - -#define aac_adapter_write(fib,cmd,lba,count,fua) \ - ((fib)->dev)->a_ops.adapter_write(fib,cmd,lba,count,fua) - -#define aac_adapter_scsi(fib,cmd) \ - ((fib)->dev)->a_ops.adapter_scsi(fib,cmd) - -#define aac_adapter_comm(dev,comm) \ - (dev)->a_ops.adapter_comm(dev, comm) - -#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001) -#define FIB_CONTEXT_FLAG (0x00000002) -#define FIB_CONTEXT_FLAG_WAIT (0x00000004) - -/* - * Define the command values - */ - -#define Null 0 -#define GetAttributes 1 -#define SetAttributes 2 -#define Lookup 3 -#define ReadLink 4 -#define Read 5 -#define Write 6 -#define Create 7 -#define MakeDirectory 8 -#define SymbolicLink 9 -#define MakeNode 10 -#define Removex 11 -#define RemoveDirectoryx 12 -#define Rename 13 -#define Link 14 -#define ReadDirectory 15 -#define ReadDirectoryPlus 16 -#define FileSystemStatus 17 -#define FileSystemInfo 18 -#define PathConfigure 19 -#define Commit 20 -#define Mount 21 -#define UnMount 22 -#define Newfs 23 -#define FsCheck 24 -#define FsSync 25 -#define SimReadWrite 26 -#define SetFileSystemStatus 27 -#define BlockRead 28 -#define BlockWrite 29 -#define NvramIoctl 30 -#define FsSyncWait 31 -#define ClearArchiveBit 32 -#define SetAcl 33 -#define GetAcl 34 -#define AssignAcl 35 -#define FaultInsertion 36 /* Fault Insertion Command */ -#define CrazyCache 37 /* Crazycache */ - -#define MAX_FSACOMMAND_NUM 38 - - -/* - * Define the status returns. These are very unixlike although - * most are not in fact used - */ - -#define ST_OK 0 -#define ST_PERM 1 -#define ST_NOENT 2 -#define ST_IO 5 -#define ST_NXIO 6 -#define ST_E2BIG 7 -#define ST_ACCES 13 -#define ST_EXIST 17 -#define ST_XDEV 18 -#define ST_NODEV 19 -#define ST_NOTDIR 20 -#define ST_ISDIR 21 -#define ST_INVAL 22 -#define ST_FBIG 27 -#define ST_NOSPC 28 -#define ST_ROFS 30 -#define ST_MLINK 31 -#define ST_WOULDBLOCK 35 -#define ST_NAMETOOLONG 63 -#define ST_NOTEMPTY 66 -#define ST_DQUOT 69 -#define ST_STALE 70 -#define ST_REMOTE 71 -#define ST_NOT_READY 72 -#define ST_BADHANDLE 10001 -#define ST_NOT_SYNC 10002 -#define ST_BAD_COOKIE 10003 -#define ST_NOTSUPP 10004 -#define ST_TOOSMALL 10005 -#define ST_SERVERFAULT 10006 -#define ST_BADTYPE 10007 -#define ST_JUKEBOX 10008 -#define ST_NOTMOUNTED 10009 -#define ST_MAINTMODE 10010 -#define ST_STALEACL 10011 - -/* - * On writes how does the client want the data written. - */ - -#define CACHE_CSTABLE 1 -#define CACHE_UNSTABLE 2 - -/* - * Lets the client know at which level the data was committed on - * a write request - */ - -#define CMFILE_SYNCH_NVRAM 1 -#define CMDATA_SYNCH_NVRAM 2 -#define CMFILE_SYNCH 3 -#define CMDATA_SYNCH 4 -#define CMUNSTABLE 5 - -struct aac_read -{ - __le32 command; - __le32 cid; - __le32 block; - __le32 count; - struct sgmap sg; // Must be last in struct because it is variable -}; - -struct aac_read64 -{ - __le32 command; - __le16 cid; - __le16 sector_count; - __le32 block; - __le16 pad; - __le16 flags; - struct sgmap64 sg; // Must be last in struct because it is variable -}; - -struct aac_read_reply -{ - __le32 status; - __le32 count; -}; - -struct aac_write -{ - __le32 command; - __le32 cid; - __le32 block; - __le32 count; - __le32 stable; // Not used - struct sgmap sg; // Must be last in struct because it is variable -}; - -struct aac_write64 -{ - __le32 command; - __le16 cid; - __le16 sector_count; - __le32 block; - __le16 pad; - __le16 flags; -#define IO_TYPE_WRITE 0x00000000 -#define IO_TYPE_READ 0x00000001 -#define IO_SUREWRITE 0x00000008 - struct sgmap64 sg; // Must be last in struct because it is variable -}; -struct aac_write_reply -{ - __le32 status; - __le32 count; - __le32 committed; -}; - -struct aac_raw_io -{ - __le32 block[2]; - __le32 count; - __le16 cid; - __le16 flags; /* 00 W, 01 R */ - __le16 bpTotal; /* reserved for F/W use */ - __le16 bpComplete; /* reserved for F/W use */ - struct sgmapraw sg; -}; - -#define CT_FLUSH_CACHE 129 -struct aac_synchronize { - __le32 command; /* VM_ContainerConfig */ - __le32 type; /* CT_FLUSH_CACHE */ - __le32 cid; - __le32 parm1; - __le32 parm2; - __le32 parm3; - __le32 parm4; - __le32 count; /* sizeof(((struct aac_synchronize_reply *)NULL)->data) */ -}; - -struct aac_synchronize_reply { - __le32 dummy0; - __le32 dummy1; - __le32 status; /* CT_OK */ - __le32 parm1; - __le32 parm2; - __le32 parm3; - __le32 parm4; - __le32 parm5; - u8 data[16]; -}; - -#define CT_POWER_MANAGEMENT 245 -#define CT_PM_START_UNIT 2 -#define CT_PM_STOP_UNIT 3 -#define CT_PM_UNIT_IMMEDIATE 1 -struct aac_power_management { - __le32 command; /* VM_ContainerConfig */ - __le32 type; /* CT_POWER_MANAGEMENT */ - __le32 sub; /* CT_PM_* */ - __le32 cid; - __le32 parm; /* CT_PM_sub_* */ -}; - -#define CT_PAUSE_IO 65 -#define CT_RELEASE_IO 66 -struct aac_pause { - __le32 command; /* VM_ContainerConfig */ - __le32 type; /* CT_PAUSE_IO */ - __le32 timeout; /* 10ms ticks */ - __le32 min; - __le32 noRescan; - __le32 parm3; - __le32 parm4; - __le32 count; /* sizeof(((struct aac_pause_reply *)NULL)->data) */ -}; - -struct aac_srb -{ - __le32 function; - __le32 channel; - __le32 id; - __le32 lun; - __le32 timeout; - __le32 flags; - __le32 count; // Data xfer size - __le32 retry_limit; - __le32 cdb_size; - u8 cdb[16]; - struct sgmap sg; -}; - -/* - * This and associated data structs are used by the - * ioctl caller and are in cpu order. - */ -struct user_aac_srb -{ - u32 function; - u32 channel; - u32 id; - u32 lun; - u32 timeout; - u32 flags; - u32 count; // Data xfer size - u32 retry_limit; - u32 cdb_size; - u8 cdb[16]; - struct user_sgmap sg; -}; - -#define AAC_SENSE_BUFFERSIZE 30 - -struct aac_srb_reply -{ - __le32 status; - __le32 srb_status; - __le32 scsi_status; - __le32 data_xfer_length; - __le32 sense_data_size; - u8 sense_data[AAC_SENSE_BUFFERSIZE]; // Can this be SCSI_SENSE_BUFFERSIZE -}; -/* - * SRB Flags - */ -#define SRB_NoDataXfer 0x0000 -#define SRB_DisableDisconnect 0x0004 -#define SRB_DisableSynchTransfer 0x0008 -#define SRB_BypassFrozenQueue 0x0010 -#define SRB_DisableAutosense 0x0020 -#define SRB_DataIn 0x0040 -#define SRB_DataOut 0x0080 - -/* - * SRB Functions - set in aac_srb->function - */ -#define SRBF_ExecuteScsi 0x0000 -#define SRBF_ClaimDevice 0x0001 -#define SRBF_IO_Control 0x0002 -#define SRBF_ReceiveEvent 0x0003 -#define SRBF_ReleaseQueue 0x0004 -#define SRBF_AttachDevice 0x0005 -#define SRBF_ReleaseDevice 0x0006 -#define SRBF_Shutdown 0x0007 -#define SRBF_Flush 0x0008 -#define SRBF_AbortCommand 0x0010 -#define SRBF_ReleaseRecovery 0x0011 -#define SRBF_ResetBus 0x0012 -#define SRBF_ResetDevice 0x0013 -#define SRBF_TerminateIO 0x0014 -#define SRBF_FlushQueue 0x0015 -#define SRBF_RemoveDevice 0x0016 -#define SRBF_DomainValidation 0x0017 - -/* - * SRB SCSI Status - set in aac_srb->scsi_status - */ -#define SRB_STATUS_PENDING 0x00 -#define SRB_STATUS_SUCCESS 0x01 -#define SRB_STATUS_ABORTED 0x02 -#define SRB_STATUS_ABORT_FAILED 0x03 -#define SRB_STATUS_ERROR 0x04 -#define SRB_STATUS_BUSY 0x05 -#define SRB_STATUS_INVALID_REQUEST 0x06 -#define SRB_STATUS_INVALID_PATH_ID 0x07 -#define SRB_STATUS_NO_DEVICE 0x08 -#define SRB_STATUS_TIMEOUT 0x09 -#define SRB_STATUS_SELECTION_TIMEOUT 0x0A -#define SRB_STATUS_COMMAND_TIMEOUT 0x0B -#define SRB_STATUS_MESSAGE_REJECTED 0x0D -#define SRB_STATUS_BUS_RESET 0x0E -#define SRB_STATUS_PARITY_ERROR 0x0F -#define SRB_STATUS_REQUEST_SENSE_FAILED 0x10 -#define SRB_STATUS_NO_HBA 0x11 -#define SRB_STATUS_DATA_OVERRUN 0x12 -#define SRB_STATUS_UNEXPECTED_BUS_FREE 0x13 -#define SRB_STATUS_PHASE_SEQUENCE_FAILURE 0x14 -#define SRB_STATUS_BAD_SRB_BLOCK_LENGTH 0x15 -#define SRB_STATUS_REQUEST_FLUSHED 0x16 -#define SRB_STATUS_DELAYED_RETRY 0x17 -#define SRB_STATUS_INVALID_LUN 0x20 -#define SRB_STATUS_INVALID_TARGET_ID 0x21 -#define SRB_STATUS_BAD_FUNCTION 0x22 -#define SRB_STATUS_ERROR_RECOVERY 0x23 -#define SRB_STATUS_NOT_STARTED 0x24 -#define SRB_STATUS_NOT_IN_USE 0x30 -#define SRB_STATUS_FORCE_ABORT 0x31 -#define SRB_STATUS_DOMAIN_VALIDATION_FAIL 0x32 - -/* - * Object-Server / Volume-Manager Dispatch Classes - */ - -#define VM_Null 0 -#define VM_NameServe 1 -#define VM_ContainerConfig 2 -#define VM_Ioctl 3 -#define VM_FilesystemIoctl 4 -#define VM_CloseAll 5 -#define VM_CtBlockRead 6 -#define VM_CtBlockWrite 7 -#define VM_SliceBlockRead 8 /* raw access to configured "storage objects" */ -#define VM_SliceBlockWrite 9 -#define VM_DriveBlockRead 10 /* raw access to physical devices */ -#define VM_DriveBlockWrite 11 -#define VM_EnclosureMgt 12 /* enclosure management */ -#define VM_Unused 13 /* used to be diskset management */ -#define VM_CtBlockVerify 14 -#define VM_CtPerf 15 /* performance test */ -#define VM_CtBlockRead64 16 -#define VM_CtBlockWrite64 17 -#define VM_CtBlockVerify64 18 -#define VM_CtHostRead64 19 -#define VM_CtHostWrite64 20 -#define VM_DrvErrTblLog 21 -#define VM_NameServe64 22 - -#define MAX_VMCOMMAND_NUM 23 /* used for sizing stats array - leave last */ - -/* - * Descriptive information (eg, vital stats) - * that a content manager might report. The - * FileArray filesystem component is one example - * of a content manager. Raw mode might be - * another. - */ - -struct aac_fsinfo { - __le32 fsTotalSize; /* Consumed by fs, incl. metadata */ - __le32 fsBlockSize; - __le32 fsFragSize; - __le32 fsMaxExtendSize; - __le32 fsSpaceUnits; - __le32 fsMaxNumFiles; - __le32 fsNumFreeFiles; - __le32 fsInodeDensity; -}; /* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */ - -union aac_contentinfo { - struct aac_fsinfo filesys; /* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */ -}; - -/* - * Query for Container Configuration Status - */ - -#define CT_GET_CONFIG_STATUS 147 -struct aac_get_config_status { - __le32 command; /* VM_ContainerConfig */ - __le32 type; /* CT_GET_CONFIG_STATUS */ - __le32 parm1; - __le32 parm2; - __le32 parm3; - __le32 parm4; - __le32 parm5; - __le32 count; /* sizeof(((struct aac_get_config_status_resp *)NULL)->data) */ -}; - -#define CFACT_CONTINUE 0 -#define CFACT_PAUSE 1 -#define CFACT_ABORT 2 -struct aac_get_config_status_resp { - __le32 response; /* ST_OK */ - __le32 dummy0; - __le32 status; /* CT_OK */ - __le32 parm1; - __le32 parm2; - __le32 parm3; - __le32 parm4; - __le32 parm5; - struct { - __le32 action; /* CFACT_CONTINUE, CFACT_PAUSE or CFACT_ABORT */ - __le16 flags; - __le16 count; - } data; -}; - -/* - * Accept the configuration as-is - */ - -#define CT_COMMIT_CONFIG 152 - -struct aac_commit_config { - __le32 command; /* VM_ContainerConfig */ - __le32 type; /* CT_COMMIT_CONFIG */ -}; - -/* - * Query for Container Configuration Status - */ - -#define CT_GET_CONTAINER_COUNT 4 -struct aac_get_container_count { - __le32 command; /* VM_ContainerConfig */ - __le32 type; /* CT_GET_CONTAINER_COUNT */ -}; - -struct aac_get_container_count_resp { - __le32 response; /* ST_OK */ - __le32 dummy0; - __le32 MaxContainers; - __le32 ContainerSwitchEntries; - __le32 MaxPartitions; -}; - - -/* - * Query for "mountable" objects, ie, objects that are typically - * associated with a drive letter on the client (host) side. - */ - -struct aac_mntent { - __le32 oid; - u8 name[16]; /* if applicable */ - struct creation_info create_info; /* if applicable */ - __le32 capacity; - __le32 vol; /* substrate structure */ - __le32 obj; /* FT_FILESYS, etc. */ - __le32 state; /* unready for mounting, - readonly, etc. */ - union aac_contentinfo fileinfo; /* Info specific to content - manager (eg, filesystem) */ - __le32 altoid; /* != oid <==> snapshot or - broken mirror exists */ - __le32 capacityhigh; -}; - -#define FSCS_NOTCLEAN 0x0001 /* fsck is necessary before mounting */ -#define FSCS_READONLY 0x0002 /* possible result of broken mirror */ -#define FSCS_HIDDEN 0x0004 /* should be ignored - set during a clear */ -#define FSCS_NOT_READY 0x0008 /* Array spinning up to fulfil request */ - -struct aac_query_mount { - __le32 command; - __le32 type; - __le32 count; -}; - -struct aac_mount { - __le32 status; - __le32 type; /* should be same as that requested */ - __le32 count; - struct aac_mntent mnt[1]; -}; - -#define CT_READ_NAME 130 -struct aac_get_name { - __le32 command; /* VM_ContainerConfig */ - __le32 type; /* CT_READ_NAME */ - __le32 cid; - __le32 parm1; - __le32 parm2; - __le32 parm3; - __le32 parm4; - __le32 count; /* sizeof(((struct aac_get_name_resp *)NULL)->data) */ -}; - -struct aac_get_name_resp { - __le32 dummy0; - __le32 dummy1; - __le32 status; /* CT_OK */ - __le32 parm1; - __le32 parm2; - __le32 parm3; - __le32 parm4; - __le32 parm5; - u8 data[16]; -}; - -#define CT_CID_TO_32BITS_UID 165 -struct aac_get_serial { - __le32 command; /* VM_ContainerConfig */ - __le32 type; /* CT_CID_TO_32BITS_UID */ - __le32 cid; -}; - -struct aac_get_serial_resp { - __le32 dummy0; - __le32 dummy1; - __le32 status; /* CT_OK */ - __le32 uid; -}; - -/* - * The following command is sent to shut down each container. - */ - -struct aac_close { - __le32 command; - __le32 cid; -}; - -struct aac_query_disk -{ - s32 cnum; - s32 bus; - s32 id; - s32 lun; - u32 valid; - u32 locked; - u32 deleted; - s32 instance; - s8 name[10]; - u32 unmapped; -}; - -struct aac_delete_disk { - u32 disknum; - u32 cnum; -}; - -struct fib_ioctl -{ - u32 fibctx; - s32 wait; - char __user *fib; -}; - -struct revision -{ - u32 compat; - __le32 version; - __le32 build; -}; - - -/* - * Ugly - non Linux like ioctl coding for back compat. - */ - -#define CTL_CODE(function, method) ( \ - (4<< 16) | ((function) << 2) | (method) \ -) - -/* - * Define the method codes for how buffers are passed for I/O and FS - * controls - */ - -#define METHOD_BUFFERED 0 -#define METHOD_NEITHER 3 - -/* - * Filesystem ioctls - */ - -#define FSACTL_SENDFIB CTL_CODE(2050, METHOD_BUFFERED) -#define FSACTL_SEND_RAW_SRB CTL_CODE(2067, METHOD_BUFFERED) -#define FSACTL_DELETE_DISK 0x163 -#define FSACTL_QUERY_DISK 0x173 -#define FSACTL_OPEN_GET_ADAPTER_FIB CTL_CODE(2100, METHOD_BUFFERED) -#define FSACTL_GET_NEXT_ADAPTER_FIB CTL_CODE(2101, METHOD_BUFFERED) -#define FSACTL_CLOSE_GET_ADAPTER_FIB CTL_CODE(2102, METHOD_BUFFERED) -#define FSACTL_MINIPORT_REV_CHECK CTL_CODE(2107, METHOD_BUFFERED) -#define FSACTL_GET_PCI_INFO CTL_CODE(2119, METHOD_BUFFERED) -#define FSACTL_FORCE_DELETE_DISK CTL_CODE(2120, METHOD_NEITHER) -#define FSACTL_GET_CONTAINERS 2131 -#define FSACTL_SEND_LARGE_FIB CTL_CODE(2138, METHOD_BUFFERED) - - -struct aac_common -{ - /* - * If this value is set to 1 then interrupt moderation will occur - * in the base commuication support. - */ - u32 irq_mod; - u32 peak_fibs; - u32 zero_fibs; - u32 fib_timeouts; - /* - * Statistical counters in debug mode - */ -#ifdef DBG - u32 FibsSent; - u32 FibRecved; - u32 NoResponseSent; - u32 NoResponseRecved; - u32 AsyncSent; - u32 AsyncRecved; - u32 NormalSent; - u32 NormalRecved; -#endif -}; - -extern struct aac_common aac_config; - - -/* - * The following macro is used when sending and receiving FIBs. It is - * only used for debugging. - */ - -#ifdef DBG -#define FIB_COUNTER_INCREMENT(counter) (counter)++ -#else -#define FIB_COUNTER_INCREMENT(counter) -#endif - -/* - * Adapter direct commands - * Monitor/Kernel API - */ - -#define BREAKPOINT_REQUEST 0x00000004 -#define INIT_STRUCT_BASE_ADDRESS 0x00000005 -#define READ_PERMANENT_PARAMETERS 0x0000000a -#define WRITE_PERMANENT_PARAMETERS 0x0000000b -#define HOST_CRASHING 0x0000000d -#define SEND_SYNCHRONOUS_FIB 0x0000000c -#define COMMAND_POST_RESULTS 0x00000014 -#define GET_ADAPTER_PROPERTIES 0x00000019 -#define GET_DRIVER_BUFFER_PROPERTIES 0x00000023 -#define RCV_TEMP_READINGS 0x00000025 -#define GET_COMM_PREFERRED_SETTINGS 0x00000026 -#define IOP_RESET 0x00001000 -#define IOP_RESET_ALWAYS 0x00001001 -#define RE_INIT_ADAPTER 0x000000ee - -/* - * Adapter Status Register - * - * Phase Staus mailbox is 32bits: - * <31:16> = Phase Status - * <15:0> = Phase - * - * The adapter reports is present state through the phase. Only - * a single phase should be ever be set. Each phase can have multiple - * phase status bits to provide more detailed information about the - * state of the board. Care should be taken to ensure that any phase - * status bits that are set when changing the phase are also valid - * for the new phase or be cleared out. Adapter software (monitor, - * iflash, kernel) is responsible for properly maintining the phase - * status mailbox when it is running. - * - * MONKER_API Phases - * - * Phases are bit oriented. It is NOT valid to have multiple bits set - */ - -#define SELF_TEST_FAILED 0x00000004 -#define MONITOR_PANIC 0x00000020 -#define KERNEL_UP_AND_RUNNING 0x00000080 -#define KERNEL_PANIC 0x00000100 - -/* - * Doorbell bit defines - */ - -#define DoorBellSyncCmdAvailable (1<<0) /* Host -> Adapter */ -#define DoorBellPrintfDone (1<<5) /* Host -> Adapter */ -#define DoorBellAdapterNormCmdReady (1<<1) /* Adapter -> Host */ -#define DoorBellAdapterNormRespReady (1<<2) /* Adapter -> Host */ -#define DoorBellAdapterNormCmdNotFull (1<<3) /* Adapter -> Host */ -#define DoorBellAdapterNormRespNotFull (1<<4) /* Adapter -> Host */ -#define DoorBellPrintfReady (1<<5) /* Adapter -> Host */ -#define DoorBellAifPending (1<<6) /* Adapter -> Host */ - -/* PMC specific outbound doorbell bits */ -#define PmDoorBellResponseSent (1<<1) /* Adapter -> Host */ - -/* - * For FIB communication, we need all of the following things - * to send back to the user. - */ - -#define AifCmdEventNotify 1 /* Notify of event */ -#define AifEnConfigChange 3 /* Adapter configuration change */ -#define AifEnContainerChange 4 /* Container configuration change */ -#define AifEnDeviceFailure 5 /* SCSI device failed */ -#define AifEnEnclosureManagement 13 /* EM_DRIVE_* */ -#define EM_DRIVE_INSERTION 31 -#define EM_DRIVE_REMOVAL 32 -#define AifEnBatteryEvent 14 /* Change in Battery State */ -#define AifEnAddContainer 15 /* A new array was created */ -#define AifEnDeleteContainer 16 /* A container was deleted */ -#define AifEnExpEvent 23 /* Firmware Event Log */ -#define AifExeFirmwarePanic 3 /* Firmware Event Panic */ -#define AifHighPriority 3 /* Highest Priority Event */ -#define AifEnAddJBOD 30 /* JBOD created */ -#define AifEnDeleteJBOD 31 /* JBOD deleted */ - -#define AifCmdJobProgress 2 /* Progress report */ -#define AifJobCtrZero 101 /* Array Zero progress */ -#define AifJobStsSuccess 1 /* Job completes */ -#define AifJobStsRunning 102 /* Job running */ -#define AifCmdAPIReport 3 /* Report from other user of API */ -#define AifCmdDriverNotify 4 /* Notify host driver of event */ -#define AifDenMorphComplete 200 /* A morph operation completed */ -#define AifDenVolumeExtendComplete 201 /* A volume extend completed */ -#define AifReqJobList 100 /* Gets back complete job list */ -#define AifReqJobsForCtr 101 /* Gets back jobs for specific container */ -#define AifReqJobsForScsi 102 /* Gets back jobs for specific SCSI device */ -#define AifReqJobReport 103 /* Gets back a specific job report or list of them */ -#define AifReqTerminateJob 104 /* Terminates job */ -#define AifReqSuspendJob 105 /* Suspends a job */ -#define AifReqResumeJob 106 /* Resumes a job */ -#define AifReqSendAPIReport 107 /* API generic report requests */ -#define AifReqAPIJobStart 108 /* Start a job from the API */ -#define AifReqAPIJobUpdate 109 /* Update a job report from the API */ -#define AifReqAPIJobFinish 110 /* Finish a job from the API */ - -/* PMC NEW COMM: Request the event data */ -#define AifReqEvent 200 - -/* - * Adapter Initiated FIB command structures. Start with the adapter - * initiated FIBs that really come from the adapter, and get responded - * to by the host. - */ - -struct aac_aifcmd { - __le32 command; /* Tell host what type of notify this is */ - __le32 seqnum; /* To allow ordering of reports (if necessary) */ - u8 data[1]; /* Undefined length (from kernel viewpoint) */ -}; - -/** - * Convert capacity to cylinders - * accounting for the fact capacity could be a 64 bit value - * - */ -static inline unsigned int cap_to_cyls(sector_t capacity, unsigned divisor) -{ - sector_div(capacity, divisor); - return capacity; -} - -/* SCp.phase values */ -#define AAC_OWNER_MIDLEVEL 0x101 -#define AAC_OWNER_LOWLEVEL 0x102 -#define AAC_OWNER_ERROR_HANDLER 0x103 -#define AAC_OWNER_FIRMWARE 0x106 - -const char *aac_driverinfo(struct Scsi_Host *); -struct fib *aac_fib_alloc(struct aac_dev *dev); -int aac_fib_setup(struct aac_dev *dev); -void aac_fib_map_free(struct aac_dev *dev); -void aac_fib_free(struct fib * context); -void aac_fib_init(struct fib * context); -void aac_printf(struct aac_dev *dev, u32 val); -int aac_fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt); -int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry); -void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum); -int aac_fib_complete(struct fib * context); -#define fib_data(fibctx) ((void *)(fibctx)->hw_fib_va->data) -struct aac_dev *aac_init_adapter(struct aac_dev *dev); -int aac_get_config_status(struct aac_dev *dev, int commit_flag); -int aac_get_containers(struct aac_dev *dev); -int aac_scsi_cmd(struct scsi_cmnd *cmd); -int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg); -#ifndef shost_to_class -#define shost_to_class(shost) &shost->shost_dev -#endif -ssize_t aac_get_serial_number(struct device *dev, char *buf); -int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg); -int aac_rx_init(struct aac_dev *dev); -int aac_rkt_init(struct aac_dev *dev); -int aac_nark_init(struct aac_dev *dev); -int aac_sa_init(struct aac_dev *dev); -int aac_src_init(struct aac_dev *dev); -int aac_srcv_init(struct aac_dev *dev); -int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify); -unsigned int aac_response_normal(struct aac_queue * q); -unsigned int aac_command_normal(struct aac_queue * q); -unsigned int aac_intr_normal(struct aac_dev *dev, u32 Index, - int isAif, int isFastResponse, - struct hw_fib *aif_fib); -int aac_reset_adapter(struct aac_dev * dev, int forced); -int aac_check_health(struct aac_dev * dev); -int aac_command_thread(void *data); -int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx); -int aac_fib_adapter_complete(struct fib * fibptr, unsigned short size); -struct aac_driver_ident* aac_get_driver_ident(int devtype); -int aac_get_adapter_info(struct aac_dev* dev); -int aac_send_shutdown(struct aac_dev *dev); -int aac_probe_container(struct aac_dev *dev, int cid); -int _aac_rx_init(struct aac_dev *dev); -int aac_rx_select_comm(struct aac_dev *dev, int comm); -int aac_rx_deliver_producer(struct fib * fib); -char * get_container_type(unsigned type); -extern int numacb; -extern int acbsize; -extern char aac_driver_version[]; -extern int startup_timeout; -extern int aif_timeout; -extern int expose_physicals; -extern int aac_reset_devices; -extern int aac_msi; -extern int aac_commit; -extern int update_interval; -extern int check_interval; -extern int aac_check_reset; diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/commctrl.c b/ANDROID_3.4.5/drivers/scsi/aacraid/commctrl.c deleted file mode 100644 index 0bd38da4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/commctrl.c +++ /dev/null @@ -1,885 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * commctrl.c - * - * Abstract: Contains all routines for control of the AFA comm layer - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* ssleep prototype */ -#include -#include -#include -#include - -#include "aacraid.h" - -/** - * ioctl_send_fib - send a FIB from userspace - * @dev: adapter is being processed - * @arg: arguments to the ioctl call - * - * This routine sends a fib to the adapter on behalf of a user level - * program. - */ -# define AAC_DEBUG_PREAMBLE KERN_INFO -# define AAC_DEBUG_POSTAMBLE - -static int ioctl_send_fib(struct aac_dev * dev, void __user *arg) -{ - struct hw_fib * kfib; - struct fib *fibptr; - struct hw_fib * hw_fib = (struct hw_fib *)0; - dma_addr_t hw_fib_pa = (dma_addr_t)0LL; - unsigned size; - int retval; - - if (dev->in_reset) { - return -EBUSY; - } - fibptr = aac_fib_alloc(dev); - if(fibptr == NULL) { - return -ENOMEM; - } - - kfib = fibptr->hw_fib_va; - /* - * First copy in the header so that we can check the size field. - */ - if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) { - aac_fib_free(fibptr); - return -EFAULT; - } - /* - * Since we copy based on the fib header size, make sure that we - * will not overrun the buffer when we copy the memory. Return - * an error if we would. - */ - size = le16_to_cpu(kfib->header.Size) + sizeof(struct aac_fibhdr); - if (size < le16_to_cpu(kfib->header.SenderSize)) - size = le16_to_cpu(kfib->header.SenderSize); - if (size > dev->max_fib_size) { - dma_addr_t daddr; - - if (size > 2048) { - retval = -EINVAL; - goto cleanup; - } - - kfib = pci_alloc_consistent(dev->pdev, size, &daddr); - if (!kfib) { - retval = -ENOMEM; - goto cleanup; - } - - /* Highjack the hw_fib */ - hw_fib = fibptr->hw_fib_va; - hw_fib_pa = fibptr->hw_fib_pa; - fibptr->hw_fib_va = kfib; - fibptr->hw_fib_pa = daddr; - memset(((char *)kfib) + dev->max_fib_size, 0, size - dev->max_fib_size); - memcpy(kfib, hw_fib, dev->max_fib_size); - } - - if (copy_from_user(kfib, arg, size)) { - retval = -EFAULT; - goto cleanup; - } - - if (kfib->header.Command == cpu_to_le16(TakeABreakPt)) { - aac_adapter_interrupt(dev); - /* - * Since we didn't really send a fib, zero out the state to allow - * cleanup code not to assert. - */ - kfib->header.XferState = 0; - } else { - retval = aac_fib_send(le16_to_cpu(kfib->header.Command), fibptr, - le16_to_cpu(kfib->header.Size) , FsaNormal, - 1, 1, NULL, NULL); - if (retval) { - goto cleanup; - } - if (aac_fib_complete(fibptr) != 0) { - retval = -EINVAL; - goto cleanup; - } - } - /* - * Make sure that the size returned by the adapter (which includes - * the header) is less than or equal to the size of a fib, so we - * don't corrupt application data. Then copy that size to the user - * buffer. (Don't try to add the header information again, since it - * was already included by the adapter.) - */ - - retval = 0; - if (copy_to_user(arg, (void *)kfib, size)) - retval = -EFAULT; -cleanup: - if (hw_fib) { - pci_free_consistent(dev->pdev, size, kfib, fibptr->hw_fib_pa); - fibptr->hw_fib_pa = hw_fib_pa; - fibptr->hw_fib_va = hw_fib; - } - if (retval != -ERESTARTSYS) - aac_fib_free(fibptr); - return retval; -} - -/** - * open_getadapter_fib - Get the next fib - * - * This routine will get the next Fib, if available, from the AdapterFibContext - * passed in from the user. - */ - -static int open_getadapter_fib(struct aac_dev * dev, void __user *arg) -{ - struct aac_fib_context * fibctx; - int status; - - fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL); - if (fibctx == NULL) { - status = -ENOMEM; - } else { - unsigned long flags; - struct list_head * entry; - struct aac_fib_context * context; - - fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; - fibctx->size = sizeof(struct aac_fib_context); - /* - * Yes yes, I know this could be an index, but we have a - * better guarantee of uniqueness for the locked loop below. - * Without the aid of a persistent history, this also helps - * reduce the chance that the opaque context would be reused. - */ - fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF); - /* - * Initialize the mutex used to wait for the next AIF. - */ - sema_init(&fibctx->wait_sem, 0); - fibctx->wait = 0; - /* - * Initialize the fibs and set the count of fibs on - * the list to 0. - */ - fibctx->count = 0; - INIT_LIST_HEAD(&fibctx->fib_list); - fibctx->jiffies = jiffies/HZ; - /* - * Now add this context onto the adapter's - * AdapterFibContext list. - */ - spin_lock_irqsave(&dev->fib_lock, flags); - /* Ensure that we have a unique identifier */ - entry = dev->fib_list.next; - while (entry != &dev->fib_list) { - context = list_entry(entry, struct aac_fib_context, next); - if (context->unique == fibctx->unique) { - /* Not unique (32 bits) */ - fibctx->unique++; - entry = dev->fib_list.next; - } else { - entry = entry->next; - } - } - list_add_tail(&fibctx->next, &dev->fib_list); - spin_unlock_irqrestore(&dev->fib_lock, flags); - if (copy_to_user(arg, &fibctx->unique, - sizeof(fibctx->unique))) { - status = -EFAULT; - } else { - status = 0; - } - } - return status; -} - -/** - * next_getadapter_fib - get the next fib - * @dev: adapter to use - * @arg: ioctl argument - * - * This routine will get the next Fib, if available, from the AdapterFibContext - * passed in from the user. - */ - -static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) -{ - struct fib_ioctl f; - struct fib *fib; - struct aac_fib_context *fibctx; - int status; - struct list_head * entry; - unsigned long flags; - - if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl))) - return -EFAULT; - /* - * Verify that the HANDLE passed in was a valid AdapterFibContext - * - * Search the list of AdapterFibContext addresses on the adapter - * to be sure this is a valid address - */ - spin_lock_irqsave(&dev->fib_lock, flags); - entry = dev->fib_list.next; - fibctx = NULL; - - while (entry != &dev->fib_list) { - fibctx = list_entry(entry, struct aac_fib_context, next); - /* - * Extract the AdapterFibContext from the Input parameters. - */ - if (fibctx->unique == f.fibctx) { /* We found a winner */ - break; - } - entry = entry->next; - fibctx = NULL; - } - if (!fibctx) { - spin_unlock_irqrestore(&dev->fib_lock, flags); - dprintk ((KERN_INFO "Fib Context not found\n")); - return -EINVAL; - } - - if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || - (fibctx->size != sizeof(struct aac_fib_context))) { - spin_unlock_irqrestore(&dev->fib_lock, flags); - dprintk ((KERN_INFO "Fib Context corrupt?\n")); - return -EINVAL; - } - status = 0; - /* - * If there are no fibs to send back, then either wait or return - * -EAGAIN - */ -return_fib: - if (!list_empty(&fibctx->fib_list)) { - /* - * Pull the next fib from the fibs - */ - entry = fibctx->fib_list.next; - list_del(entry); - - fib = list_entry(entry, struct fib, fiblink); - fibctx->count--; - spin_unlock_irqrestore(&dev->fib_lock, flags); - if (copy_to_user(f.fib, fib->hw_fib_va, sizeof(struct hw_fib))) { - kfree(fib->hw_fib_va); - kfree(fib); - return -EFAULT; - } - /* - * Free the space occupied by this copy of the fib. - */ - kfree(fib->hw_fib_va); - kfree(fib); - status = 0; - } else { - spin_unlock_irqrestore(&dev->fib_lock, flags); - /* If someone killed the AIF aacraid thread, restart it */ - status = !dev->aif_thread; - if (status && !dev->in_reset && dev->queues && dev->fsa_dev) { - /* Be paranoid, be very paranoid! */ - kthread_stop(dev->thread); - ssleep(1); - dev->aif_thread = 0; - dev->thread = kthread_run(aac_command_thread, dev, dev->name); - ssleep(1); - } - if (f.wait) { - if(down_interruptible(&fibctx->wait_sem) < 0) { - status = -ERESTARTSYS; - } else { - /* Lock again and retry */ - spin_lock_irqsave(&dev->fib_lock, flags); - goto return_fib; - } - } else { - status = -EAGAIN; - } - } - fibctx->jiffies = jiffies/HZ; - return status; -} - -int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx) -{ - struct fib *fib; - - /* - * First free any FIBs that have not been consumed. - */ - while (!list_empty(&fibctx->fib_list)) { - struct list_head * entry; - /* - * Pull the next fib from the fibs - */ - entry = fibctx->fib_list.next; - list_del(entry); - fib = list_entry(entry, struct fib, fiblink); - fibctx->count--; - /* - * Free the space occupied by this copy of the fib. - */ - kfree(fib->hw_fib_va); - kfree(fib); - } - /* - * Remove the Context from the AdapterFibContext List - */ - list_del(&fibctx->next); - /* - * Invalidate context - */ - fibctx->type = 0; - /* - * Free the space occupied by the Context - */ - kfree(fibctx); - return 0; -} - -/** - * close_getadapter_fib - close down user fib context - * @dev: adapter - * @arg: ioctl arguments - * - * This routine will close down the fibctx passed in from the user. - */ - -static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) -{ - struct aac_fib_context *fibctx; - int status; - unsigned long flags; - struct list_head * entry; - - /* - * Verify that the HANDLE passed in was a valid AdapterFibContext - * - * Search the list of AdapterFibContext addresses on the adapter - * to be sure this is a valid address - */ - - entry = dev->fib_list.next; - fibctx = NULL; - - while(entry != &dev->fib_list) { - fibctx = list_entry(entry, struct aac_fib_context, next); - /* - * Extract the fibctx from the input parameters - */ - if (fibctx->unique == (u32)(uintptr_t)arg) /* We found a winner */ - break; - entry = entry->next; - fibctx = NULL; - } - - if (!fibctx) - return 0; /* Already gone */ - - if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) || - (fibctx->size != sizeof(struct aac_fib_context))) - return -EINVAL; - spin_lock_irqsave(&dev->fib_lock, flags); - status = aac_close_fib_context(dev, fibctx); - spin_unlock_irqrestore(&dev->fib_lock, flags); - return status; -} - -/** - * check_revision - close down user fib context - * @dev: adapter - * @arg: ioctl arguments - * - * This routine returns the driver version. - * Under Linux, there have been no version incompatibilities, so this is - * simple! - */ - -static int check_revision(struct aac_dev *dev, void __user *arg) -{ - struct revision response; - char *driver_version = aac_driver_version; - u32 version; - - response.compat = 1; - version = (simple_strtol(driver_version, - &driver_version, 10) << 24) | 0x00000400; - version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; - version += simple_strtol(driver_version + 1, NULL, 10); - response.version = cpu_to_le32(version); -# ifdef AAC_DRIVER_BUILD - response.build = cpu_to_le32(AAC_DRIVER_BUILD); -# else - response.build = cpu_to_le32(9999); -# endif - - if (copy_to_user(arg, &response, sizeof(response))) - return -EFAULT; - return 0; -} - - -/** - * - * aac_send_raw_scb - * - */ - -static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg) -{ - struct fib* srbfib; - int status; - struct aac_srb *srbcmd = NULL; - struct user_aac_srb *user_srbcmd = NULL; - struct user_aac_srb __user *user_srb = arg; - struct aac_srb_reply __user *user_reply; - struct aac_srb_reply* reply; - u32 fibsize = 0; - u32 flags = 0; - s32 rcode = 0; - u32 data_dir; - void __user *sg_user[32]; - void *sg_list[32]; - u32 sg_indx = 0; - u32 byte_count = 0; - u32 actual_fibsize64, actual_fibsize = 0; - int i; - - - if (dev->in_reset) { - dprintk((KERN_DEBUG"aacraid: send raw srb -EBUSY\n")); - return -EBUSY; - } - if (!capable(CAP_SYS_ADMIN)){ - dprintk((KERN_DEBUG"aacraid: No permission to send raw srb\n")); - return -EPERM; - } - /* - * Allocate and initialize a Fib then setup a SRB command - */ - if (!(srbfib = aac_fib_alloc(dev))) { - return -ENOMEM; - } - aac_fib_init(srbfib); - - srbcmd = (struct aac_srb*) fib_data(srbfib); - - memset(sg_list, 0, sizeof(sg_list)); /* cleanup may take issue */ - if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){ - dprintk((KERN_DEBUG"aacraid: Could not copy data size from user\n")); - rcode = -EFAULT; - goto cleanup; - } - - if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))) { - rcode = -EINVAL; - goto cleanup; - } - - user_srbcmd = kmalloc(fibsize, GFP_KERNEL); - if (!user_srbcmd) { - dprintk((KERN_DEBUG"aacraid: Could not make a copy of the srb\n")); - rcode = -ENOMEM; - goto cleanup; - } - if(copy_from_user(user_srbcmd, user_srb,fibsize)){ - dprintk((KERN_DEBUG"aacraid: Could not copy srb from user\n")); - rcode = -EFAULT; - goto cleanup; - } - - user_reply = arg+fibsize; - - flags = user_srbcmd->flags; /* from user in cpu order */ - // Fix up srb for endian and force some values - - srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi); // Force this - srbcmd->channel = cpu_to_le32(user_srbcmd->channel); - srbcmd->id = cpu_to_le32(user_srbcmd->id); - srbcmd->lun = cpu_to_le32(user_srbcmd->lun); - srbcmd->timeout = cpu_to_le32(user_srbcmd->timeout); - srbcmd->flags = cpu_to_le32(flags); - srbcmd->retry_limit = 0; // Obsolete parameter - srbcmd->cdb_size = cpu_to_le32(user_srbcmd->cdb_size); - memcpy(srbcmd->cdb, user_srbcmd->cdb, sizeof(srbcmd->cdb)); - - switch (flags & (SRB_DataIn | SRB_DataOut)) { - case SRB_DataOut: - data_dir = DMA_TO_DEVICE; - break; - case (SRB_DataIn | SRB_DataOut): - data_dir = DMA_BIDIRECTIONAL; - break; - case SRB_DataIn: - data_dir = DMA_FROM_DEVICE; - break; - default: - data_dir = DMA_NONE; - } - if (user_srbcmd->sg.count > ARRAY_SIZE(sg_list)) { - dprintk((KERN_DEBUG"aacraid: too many sg entries %d\n", - le32_to_cpu(srbcmd->sg.count))); - rcode = -EINVAL; - goto cleanup; - } - actual_fibsize = sizeof(struct aac_srb) - sizeof(struct sgentry) + - ((user_srbcmd->sg.count & 0xff) * sizeof(struct sgentry)); - actual_fibsize64 = actual_fibsize + (user_srbcmd->sg.count & 0xff) * - (sizeof(struct sgentry64) - sizeof(struct sgentry)); - /* User made a mistake - should not continue */ - if ((actual_fibsize != fibsize) && (actual_fibsize64 != fibsize)) { - dprintk((KERN_DEBUG"aacraid: Bad Size specified in " - "Raw SRB command calculated fibsize=%lu;%lu " - "user_srbcmd->sg.count=%d aac_srb=%lu sgentry=%lu;%lu " - "issued fibsize=%d\n", - actual_fibsize, actual_fibsize64, user_srbcmd->sg.count, - sizeof(struct aac_srb), sizeof(struct sgentry), - sizeof(struct sgentry64), fibsize)); - rcode = -EINVAL; - goto cleanup; - } - if ((data_dir == DMA_NONE) && user_srbcmd->sg.count) { - dprintk((KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n")); - rcode = -EINVAL; - goto cleanup; - } - byte_count = 0; - if (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) { - struct user_sgmap64* upsg = (struct user_sgmap64*)&user_srbcmd->sg; - struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg; - - /* - * This should also catch if user used the 32 bit sgmap - */ - if (actual_fibsize64 == fibsize) { - actual_fibsize = actual_fibsize64; - for (i = 0; i < upsg->count; i++) { - u64 addr; - void* p; - if (upsg->sg[i].count > - ((dev->adapter_info.options & - AAC_OPT_NEW_COMM) ? - (dev->scsi_host_ptr->max_sectors << 9) : - 65536)) { - rcode = -EINVAL; - goto cleanup; - } - /* Does this really need to be GFP_DMA? */ - p = kmalloc(upsg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(!p) { - dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - upsg->sg[i].count,i,upsg->count)); - rcode = -ENOMEM; - goto cleanup; - } - addr = (u64)upsg->sg[i].addr[0]; - addr += ((u64)upsg->sg[i].addr[1]) << 32; - sg_user[i] = (void __user *)(uintptr_t)addr; - sg_list[i] = p; // save so we can clean up later - sg_indx = i; - - if (flags & SRB_DataOut) { - if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ - dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); - rcode = -EFAULT; - goto cleanup; - } - } - addr = pci_map_single(dev->pdev, p, upsg->sg[i].count, data_dir); - - psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); - psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - byte_count += upsg->sg[i].count; - psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); - } - } else { - struct user_sgmap* usg; - usg = kmalloc(actual_fibsize - sizeof(struct aac_srb) - + sizeof(struct sgmap), GFP_KERNEL); - if (!usg) { - dprintk((KERN_DEBUG"aacraid: Allocation error in Raw SRB command\n")); - rcode = -ENOMEM; - goto cleanup; - } - memcpy (usg, upsg, actual_fibsize - sizeof(struct aac_srb) - + sizeof(struct sgmap)); - actual_fibsize = actual_fibsize64; - - for (i = 0; i < usg->count; i++) { - u64 addr; - void* p; - if (usg->sg[i].count > - ((dev->adapter_info.options & - AAC_OPT_NEW_COMM) ? - (dev->scsi_host_ptr->max_sectors << 9) : - 65536)) { - kfree(usg); - rcode = -EINVAL; - goto cleanup; - } - /* Does this really need to be GFP_DMA? */ - p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(!p) { - dprintk((KERN_DEBUG "aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - usg->sg[i].count,i,usg->count)); - kfree(usg); - rcode = -ENOMEM; - goto cleanup; - } - sg_user[i] = (void __user *)(uintptr_t)usg->sg[i].addr; - sg_list[i] = p; // save so we can clean up later - sg_indx = i; - - if (flags & SRB_DataOut) { - if(copy_from_user(p,sg_user[i],upsg->sg[i].count)){ - kfree (usg); - dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); - rcode = -EFAULT; - goto cleanup; - } - } - addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); - - psg->sg[i].addr[0] = cpu_to_le32(addr & 0xffffffff); - psg->sg[i].addr[1] = cpu_to_le32(addr>>32); - byte_count += usg->sg[i].count; - psg->sg[i].count = cpu_to_le32(usg->sg[i].count); - } - kfree (usg); - } - srbcmd->count = cpu_to_le32(byte_count); - psg->count = cpu_to_le32(sg_indx+1); - status = aac_fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL); - } else { - struct user_sgmap* upsg = &user_srbcmd->sg; - struct sgmap* psg = &srbcmd->sg; - - if (actual_fibsize64 == fibsize) { - struct user_sgmap64* usg = (struct user_sgmap64 *)upsg; - for (i = 0; i < upsg->count; i++) { - uintptr_t addr; - void* p; - if (usg->sg[i].count > - ((dev->adapter_info.options & - AAC_OPT_NEW_COMM) ? - (dev->scsi_host_ptr->max_sectors << 9) : - 65536)) { - rcode = -EINVAL; - goto cleanup; - } - /* Does this really need to be GFP_DMA? */ - p = kmalloc(usg->sg[i].count,GFP_KERNEL|__GFP_DMA); - if(!p) { - dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - usg->sg[i].count,i,usg->count)); - rcode = -ENOMEM; - goto cleanup; - } - addr = (u64)usg->sg[i].addr[0]; - addr += ((u64)usg->sg[i].addr[1]) << 32; - sg_user[i] = (void __user *)addr; - sg_list[i] = p; // save so we can clean up later - sg_indx = i; - - if (flags & SRB_DataOut) { - if(copy_from_user(p,sg_user[i],usg->sg[i].count)){ - dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); - rcode = -EFAULT; - goto cleanup; - } - } - addr = pci_map_single(dev->pdev, p, usg->sg[i].count, data_dir); - - psg->sg[i].addr = cpu_to_le32(addr & 0xffffffff); - byte_count += usg->sg[i].count; - psg->sg[i].count = cpu_to_le32(usg->sg[i].count); - } - } else { - for (i = 0; i < upsg->count; i++) { - dma_addr_t addr; - void* p; - if (upsg->sg[i].count > - ((dev->adapter_info.options & - AAC_OPT_NEW_COMM) ? - (dev->scsi_host_ptr->max_sectors << 9) : - 65536)) { - rcode = -EINVAL; - goto cleanup; - } - p = kmalloc(upsg->sg[i].count, GFP_KERNEL); - if (!p) { - dprintk((KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - upsg->sg[i].count, i, upsg->count)); - rcode = -ENOMEM; - goto cleanup; - } - sg_user[i] = (void __user *)(uintptr_t)upsg->sg[i].addr; - sg_list[i] = p; // save so we can clean up later - sg_indx = i; - - if (flags & SRB_DataOut) { - if(copy_from_user(p, sg_user[i], - upsg->sg[i].count)) { - dprintk((KERN_DEBUG"aacraid: Could not copy sg data from user\n")); - rcode = -EFAULT; - goto cleanup; - } - } - addr = pci_map_single(dev->pdev, p, - upsg->sg[i].count, data_dir); - - psg->sg[i].addr = cpu_to_le32(addr); - byte_count += upsg->sg[i].count; - psg->sg[i].count = cpu_to_le32(upsg->sg[i].count); - } - } - srbcmd->count = cpu_to_le32(byte_count); - psg->count = cpu_to_le32(sg_indx+1); - status = aac_fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL); - } - if (status == -ERESTARTSYS) { - rcode = -ERESTARTSYS; - goto cleanup; - } - - if (status != 0){ - dprintk((KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n")); - rcode = -ENXIO; - goto cleanup; - } - - if (flags & SRB_DataIn) { - for(i = 0 ; i <= sg_indx; i++){ - byte_count = le32_to_cpu( - (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64) - ? ((struct sgmap64*)&srbcmd->sg)->sg[i].count - : srbcmd->sg.sg[i].count); - if(copy_to_user(sg_user[i], sg_list[i], byte_count)){ - dprintk((KERN_DEBUG"aacraid: Could not copy sg data to user\n")); - rcode = -EFAULT; - goto cleanup; - - } - } - } - - reply = (struct aac_srb_reply *) fib_data(srbfib); - if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){ - dprintk((KERN_DEBUG"aacraid: Could not copy reply to user\n")); - rcode = -EFAULT; - goto cleanup; - } - -cleanup: - kfree(user_srbcmd); - for(i=0; i <= sg_indx; i++){ - kfree(sg_list[i]); - } - if (rcode != -ERESTARTSYS) { - aac_fib_complete(srbfib); - aac_fib_free(srbfib); - } - - return rcode; -} - -struct aac_pci_info { - u32 bus; - u32 slot; -}; - - -static int aac_get_pci_info(struct aac_dev* dev, void __user *arg) -{ - struct aac_pci_info pci_info; - - pci_info.bus = dev->pdev->bus->number; - pci_info.slot = PCI_SLOT(dev->pdev->devfn); - - if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) { - dprintk((KERN_DEBUG "aacraid: Could not copy pci info\n")); - return -EFAULT; - } - return 0; -} - - -int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg) -{ - int status; - - /* - * HBA gets first crack - */ - - status = aac_dev_ioctl(dev, cmd, arg); - if (status != -ENOTTY) - return status; - - switch (cmd) { - case FSACTL_MINIPORT_REV_CHECK: - status = check_revision(dev, arg); - break; - case FSACTL_SEND_LARGE_FIB: - case FSACTL_SENDFIB: - status = ioctl_send_fib(dev, arg); - break; - case FSACTL_OPEN_GET_ADAPTER_FIB: - status = open_getadapter_fib(dev, arg); - break; - case FSACTL_GET_NEXT_ADAPTER_FIB: - status = next_getadapter_fib(dev, arg); - break; - case FSACTL_CLOSE_GET_ADAPTER_FIB: - status = close_getadapter_fib(dev, arg); - break; - case FSACTL_SEND_RAW_SRB: - status = aac_send_raw_srb(dev,arg); - break; - case FSACTL_GET_PCI_INFO: - status = aac_get_pci_info(dev,arg); - break; - default: - status = -ENOTTY; - break; - } - return status; -} - diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/comminit.c b/ANDROID_3.4.5/drivers/scsi/aacraid/comminit.c deleted file mode 100644 index a35f54eb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/comminit.c +++ /dev/null @@ -1,473 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * comminit.c - * - * Abstract: This supports the initialization of the host adapter commuication interface. - * This is a platform dependent module for the pci cyclone board. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aacraid.h" - -struct aac_common aac_config = { - .irq_mod = 1 -}; - -static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign) -{ - unsigned char *base; - unsigned long size, align; - const unsigned long fibsize = 4096; - const unsigned long printfbufsiz = 256; - unsigned long host_rrq_size = 0; - struct aac_init *init; - dma_addr_t phys; - unsigned long aac_max_hostphysmempages; - - if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) - host_rrq_size = (dev->scsi_host_ptr->can_queue - + AAC_NUM_MGT_FIB) * sizeof(u32); - size = fibsize + sizeof(struct aac_init) + commsize + - commalign + printfbufsiz + host_rrq_size; - - base = pci_alloc_consistent(dev->pdev, size, &phys); - - if(base == NULL) - { - printk(KERN_ERR "aacraid: unable to create mapping.\n"); - return 0; - } - dev->comm_addr = (void *)base; - dev->comm_phys = phys; - dev->comm_size = size; - - if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { - dev->host_rrq = (u32 *)(base + fibsize); - dev->host_rrq_pa = phys + fibsize; - memset(dev->host_rrq, 0, host_rrq_size); - } - - dev->init = (struct aac_init *)(base + fibsize + host_rrq_size); - dev->init_pa = phys + fibsize + host_rrq_size; - - init = dev->init; - - init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION); - if (dev->max_fib_size != sizeof(struct hw_fib)) - init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4); - init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION); - init->fsrev = cpu_to_le32(dev->fsrev); - - /* - * Adapter Fibs are the first thing allocated so that they - * start page aligned - */ - dev->aif_base_va = (struct hw_fib *)base; - - init->AdapterFibsVirtualAddress = 0; - init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys); - init->AdapterFibsSize = cpu_to_le32(fibsize); - init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib)); - /* - * number of 4k pages of host physical memory. The aacraid fw needs - * this number to be less than 4gb worth of pages. New firmware doesn't - * have any issues with the mapping system, but older Firmware did, and - * had *troubles* dealing with the math overloading past 32 bits, thus - * we must limit this field. - */ - aac_max_hostphysmempages = dma_get_required_mask(&dev->pdev->dev) >> 12; - if (aac_max_hostphysmempages < AAC_MAX_HOSTPHYSMEMPAGES) - init->HostPhysMemPages = cpu_to_le32(aac_max_hostphysmempages); - else - init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES); - - init->InitFlags = 0; - if (dev->comm_interface == AAC_COMM_MESSAGE) { - init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_SUPPORTED); - dprintk((KERN_WARNING"aacraid: New Comm Interface enabled\n")); - } else if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { - init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_6); - init->InitFlags |= cpu_to_le32(INITFLAGS_NEW_COMM_TYPE1_SUPPORTED); - dprintk((KERN_WARNING - "aacraid: New Comm Interface type1 enabled\n")); - } - init->InitFlags |= cpu_to_le32(INITFLAGS_DRIVER_USES_UTC_TIME | - INITFLAGS_DRIVER_SUPPORTS_PM); - init->MaxIoCommands = cpu_to_le32(dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); - init->MaxIoSize = cpu_to_le32(dev->scsi_host_ptr->max_sectors << 9); - init->MaxFibSize = cpu_to_le32(dev->max_fib_size); - - init->MaxNumAif = cpu_to_le32(dev->max_num_aif); - init->HostRRQ_AddrHigh = (u32)((u64)dev->host_rrq_pa >> 32); - init->HostRRQ_AddrLow = (u32)(dev->host_rrq_pa & 0xffffffff); - - - /* - * Increment the base address by the amount already used - */ - base = base + fibsize + host_rrq_size + sizeof(struct aac_init); - phys = (dma_addr_t)((ulong)phys + fibsize + host_rrq_size + - sizeof(struct aac_init)); - - /* - * Align the beginning of Headers to commalign - */ - align = (commalign - ((uintptr_t)(base) & (commalign - 1))); - base = base + align; - phys = phys + align; - /* - * Fill in addresses of the Comm Area Headers and Queues - */ - *commaddr = base; - init->CommHeaderAddress = cpu_to_le32((u32)phys); - /* - * Increment the base address by the size of the CommArea - */ - base = base + commsize; - phys = phys + commsize; - /* - * Place the Printf buffer area after the Fast I/O comm area. - */ - dev->printfbuf = (void *)base; - init->printfbuf = cpu_to_le32(phys); - init->printfbufsiz = cpu_to_le32(printfbufsiz); - memset(base, 0, printfbufsiz); - return 1; -} - -static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize) -{ - q->numpending = 0; - q->dev = dev; - init_waitqueue_head(&q->cmdready); - INIT_LIST_HEAD(&q->cmdq); - init_waitqueue_head(&q->qfull); - spin_lock_init(&q->lockdata); - q->lock = &q->lockdata; - q->headers.producer = (__le32 *)mem; - q->headers.consumer = (__le32 *)(mem+1); - *(q->headers.producer) = cpu_to_le32(qsize); - *(q->headers.consumer) = cpu_to_le32(qsize); - q->entries = qsize; -} - -/** - * aac_send_shutdown - shutdown an adapter - * @dev: Adapter to shutdown - * - * This routine will send a VM_CloseAll (shutdown) request to the adapter. - */ - -int aac_send_shutdown(struct aac_dev * dev) -{ - struct fib * fibctx; - struct aac_close *cmd; - int status; - - fibctx = aac_fib_alloc(dev); - if (!fibctx) - return -ENOMEM; - aac_fib_init(fibctx); - - cmd = (struct aac_close *) fib_data(fibctx); - - cmd->command = cpu_to_le32(VM_CloseAll); - cmd->cid = cpu_to_le32(0xffffffff); - - status = aac_fib_send(ContainerCommand, - fibctx, - sizeof(struct aac_close), - FsaNormal, - -2 /* Timeout silently */, 1, - NULL, NULL); - - if (status >= 0) - aac_fib_complete(fibctx); - /* FIB should be freed only after getting the response from the F/W */ - if (status != -ERESTARTSYS) - aac_fib_free(fibctx); - return status; -} - -/** - * aac_comm_init - Initialise FSA data structures - * @dev: Adapter to initialise - * - * Initializes the data structures that are required for the FSA commuication - * interface to operate. - * Returns - * 1 - if we were able to init the commuication interface. - * 0 - If there were errors initing. This is a fatal error. - */ - -static int aac_comm_init(struct aac_dev * dev) -{ - unsigned long hdrsize = (sizeof(u32) * NUMBER_OF_COMM_QUEUES) * 2; - unsigned long queuesize = sizeof(struct aac_entry) * TOTAL_QUEUE_ENTRIES; - u32 *headers; - struct aac_entry * queues; - unsigned long size; - struct aac_queue_block * comm = dev->queues; - /* - * Now allocate and initialize the zone structures used as our - * pool of FIB context records. The size of the zone is based - * on the system memory size. We also initialize the mutex used - * to protect the zone. - */ - spin_lock_init(&dev->fib_lock); - - /* - * Allocate the physically contiguous space for the commuication - * queue headers. - */ - - size = hdrsize + queuesize; - - if (!aac_alloc_comm(dev, (void * *)&headers, size, QUEUE_ALIGNMENT)) - return -ENOMEM; - - queues = (struct aac_entry *)(((ulong)headers) + hdrsize); - - /* Adapter to Host normal priority Command queue */ - comm->queue[HostNormCmdQueue].base = queues; - aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES); - queues += HOST_NORM_CMD_ENTRIES; - headers += 2; - - /* Adapter to Host high priority command queue */ - comm->queue[HostHighCmdQueue].base = queues; - aac_queue_init(dev, &comm->queue[HostHighCmdQueue], headers, HOST_HIGH_CMD_ENTRIES); - - queues += HOST_HIGH_CMD_ENTRIES; - headers +=2; - - /* Host to adapter normal priority command queue */ - comm->queue[AdapNormCmdQueue].base = queues; - aac_queue_init(dev, &comm->queue[AdapNormCmdQueue], headers, ADAP_NORM_CMD_ENTRIES); - - queues += ADAP_NORM_CMD_ENTRIES; - headers += 2; - - /* host to adapter high priority command queue */ - comm->queue[AdapHighCmdQueue].base = queues; - aac_queue_init(dev, &comm->queue[AdapHighCmdQueue], headers, ADAP_HIGH_CMD_ENTRIES); - - queues += ADAP_HIGH_CMD_ENTRIES; - headers += 2; - - /* adapter to host normal priority response queue */ - comm->queue[HostNormRespQueue].base = queues; - aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES); - queues += HOST_NORM_RESP_ENTRIES; - headers += 2; - - /* adapter to host high priority response queue */ - comm->queue[HostHighRespQueue].base = queues; - aac_queue_init(dev, &comm->queue[HostHighRespQueue], headers, HOST_HIGH_RESP_ENTRIES); - - queues += HOST_HIGH_RESP_ENTRIES; - headers += 2; - - /* host to adapter normal priority response queue */ - comm->queue[AdapNormRespQueue].base = queues; - aac_queue_init(dev, &comm->queue[AdapNormRespQueue], headers, ADAP_NORM_RESP_ENTRIES); - - queues += ADAP_NORM_RESP_ENTRIES; - headers += 2; - - /* host to adapter high priority response queue */ - comm->queue[AdapHighRespQueue].base = queues; - aac_queue_init(dev, &comm->queue[AdapHighRespQueue], headers, ADAP_HIGH_RESP_ENTRIES); - - comm->queue[AdapNormCmdQueue].lock = comm->queue[HostNormRespQueue].lock; - comm->queue[AdapHighCmdQueue].lock = comm->queue[HostHighRespQueue].lock; - comm->queue[AdapNormRespQueue].lock = comm->queue[HostNormCmdQueue].lock; - comm->queue[AdapHighRespQueue].lock = comm->queue[HostHighCmdQueue].lock; - - return 0; -} - -struct aac_dev *aac_init_adapter(struct aac_dev *dev) -{ - u32 status[5]; - struct Scsi_Host * host = dev->scsi_host_ptr; - extern int aac_sync_mode; - - /* - * Check the preferred comm settings, defaults from template. - */ - dev->management_fib_count = 0; - spin_lock_init(&dev->manage_lock); - spin_lock_init(&dev->sync_lock); - dev->max_fib_size = sizeof(struct hw_fib); - dev->sg_tablesize = host->sg_tablesize = (dev->max_fib_size - - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write) + sizeof(struct sgentry)) - / sizeof(struct sgentry); - dev->comm_interface = AAC_COMM_PRODUCER; - dev->raw_io_interface = dev->raw_io_64 = 0; - - if ((!aac_adapter_sync_cmd(dev, GET_ADAPTER_PROPERTIES, - 0, 0, 0, 0, 0, 0, status+0, status+1, status+2, NULL, NULL)) && - (status[0] == 0x00000001)) { - if (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_64)) - dev->raw_io_64 = 1; - dev->sync_mode = aac_sync_mode; - if (dev->a_ops.adapter_comm && - (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM))) { - dev->comm_interface = AAC_COMM_MESSAGE; - dev->raw_io_interface = 1; - if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE1))) { - /* driver supports TYPE1 (Tupelo) */ - dev->comm_interface = AAC_COMM_MESSAGE_TYPE1; - } else if ((status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE4)) || - (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE3)) || - (status[1] & le32_to_cpu(AAC_OPT_NEW_COMM_TYPE2))) { - /* driver doesn't support TYPE2 (Series7), TYPE3 and TYPE4 */ - /* switch to sync. mode */ - dev->comm_interface = AAC_COMM_MESSAGE_TYPE1; - dev->sync_mode = 1; - } - } - if ((dev->comm_interface == AAC_COMM_MESSAGE) && - (status[2] > dev->base_size)) { - aac_adapter_ioremap(dev, 0); - dev->base_size = status[2]; - if (aac_adapter_ioremap(dev, status[2])) { - /* remap failed, go back ... */ - dev->comm_interface = AAC_COMM_PRODUCER; - if (aac_adapter_ioremap(dev, AAC_MIN_FOOTPRINT_SIZE)) { - printk(KERN_WARNING - "aacraid: unable to map adapter.\n"); - return NULL; - } - } - } - } - if ((!aac_adapter_sync_cmd(dev, GET_COMM_PREFERRED_SETTINGS, - 0, 0, 0, 0, 0, 0, - status+0, status+1, status+2, status+3, status+4)) - && (status[0] == 0x00000001)) { - /* - * status[1] >> 16 maximum command size in KB - * status[1] & 0xFFFF maximum FIB size - * status[2] >> 16 maximum SG elements to driver - * status[2] & 0xFFFF maximum SG elements from driver - * status[3] & 0xFFFF maximum number FIBs outstanding - */ - host->max_sectors = (status[1] >> 16) << 1; - /* Multiple of 32 for PMC */ - dev->max_fib_size = status[1] & 0xFFE0; - host->sg_tablesize = status[2] >> 16; - dev->sg_tablesize = status[2] & 0xFFFF; - host->can_queue = (status[3] & 0xFFFF) - AAC_NUM_MGT_FIB; - dev->max_num_aif = status[4] & 0xFFFF; - /* - * NOTE: - * All these overrides are based on a fixed internal - * knowledge and understanding of existing adapters, - * acbsize should be set with caution. - */ - if (acbsize == 512) { - host->max_sectors = AAC_MAX_32BIT_SGBCOUNT; - dev->max_fib_size = 512; - dev->sg_tablesize = host->sg_tablesize - = (512 - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write) + sizeof(struct sgentry)) - / sizeof(struct sgentry); - host->can_queue = AAC_NUM_IO_FIB; - } else if (acbsize == 2048) { - host->max_sectors = 512; - dev->max_fib_size = 2048; - host->sg_tablesize = 65; - dev->sg_tablesize = 81; - host->can_queue = 512 - AAC_NUM_MGT_FIB; - } else if (acbsize == 4096) { - host->max_sectors = 1024; - dev->max_fib_size = 4096; - host->sg_tablesize = 129; - dev->sg_tablesize = 166; - host->can_queue = 256 - AAC_NUM_MGT_FIB; - } else if (acbsize == 8192) { - host->max_sectors = 2048; - dev->max_fib_size = 8192; - host->sg_tablesize = 257; - dev->sg_tablesize = 337; - host->can_queue = 128 - AAC_NUM_MGT_FIB; - } else if (acbsize > 0) { - printk("Illegal acbsize=%d ignored\n", acbsize); - } - } - { - - if (numacb > 0) { - if (numacb < host->can_queue) - host->can_queue = numacb; - else - printk("numacb=%d ignored\n", numacb); - } - } - - /* - * Ok now init the communication subsystem - */ - - dev->queues = kzalloc(sizeof(struct aac_queue_block), GFP_KERNEL); - if (dev->queues == NULL) { - printk(KERN_ERR "Error could not allocate comm region.\n"); - return NULL; - } - - if (aac_comm_init(dev)<0){ - kfree(dev->queues); - return NULL; - } - /* - * Initialize the list of fibs - */ - if (aac_fib_setup(dev) < 0) { - kfree(dev->queues); - return NULL; - } - - INIT_LIST_HEAD(&dev->fib_list); - INIT_LIST_HEAD(&dev->sync_fib_list); - - return dev; -} - - diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/commsup.c b/ANDROID_3.4.5/drivers/scsi/aacraid/commsup.c deleted file mode 100644 index 4b32ca44..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/commsup.c +++ /dev/null @@ -1,1922 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * commsup.c - * - * Abstract: Contain all routines that are required for FSA host/adapter - * communication. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aacraid.h" - -/** - * fib_map_alloc - allocate the fib objects - * @dev: Adapter to allocate for - * - * Allocate and map the shared PCI space for the FIB blocks used to - * talk to the Adaptec firmware. - */ - -static int fib_map_alloc(struct aac_dev *dev) -{ - dprintk((KERN_INFO - "allocate hardware fibs pci_alloc_consistent(%p, %d * (%d + %d), %p)\n", - dev->pdev, dev->max_fib_size, dev->scsi_host_ptr->can_queue, - AAC_NUM_MGT_FIB, &dev->hw_fib_pa)); - dev->hw_fib_va = pci_alloc_consistent(dev->pdev, - (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) - * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) + (ALIGN32 - 1), - &dev->hw_fib_pa); - if (dev->hw_fib_va == NULL) - return -ENOMEM; - return 0; -} - -/** - * aac_fib_map_free - free the fib objects - * @dev: Adapter to free - * - * Free the PCI mappings and the memory allocated for FIB blocks - * on this adapter. - */ - -void aac_fib_map_free(struct aac_dev *dev) -{ - pci_free_consistent(dev->pdev, - dev->max_fib_size * (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB), - dev->hw_fib_va, dev->hw_fib_pa); - dev->hw_fib_va = NULL; - dev->hw_fib_pa = 0; -} - -/** - * aac_fib_setup - setup the fibs - * @dev: Adapter to set up - * - * Allocate the PCI space for the fibs, map it and then initialise the - * fib area, the unmapped fib data and also the free list - */ - -int aac_fib_setup(struct aac_dev * dev) -{ - struct fib *fibptr; - struct hw_fib *hw_fib; - dma_addr_t hw_fib_pa; - int i; - - while (((i = fib_map_alloc(dev)) == -ENOMEM) - && (dev->scsi_host_ptr->can_queue > (64 - AAC_NUM_MGT_FIB))) { - dev->init->MaxIoCommands = cpu_to_le32((dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB) >> 1); - dev->scsi_host_ptr->can_queue = le32_to_cpu(dev->init->MaxIoCommands) - AAC_NUM_MGT_FIB; - } - if (i<0) - return -ENOMEM; - - /* 32 byte alignment for PMC */ - hw_fib_pa = (dev->hw_fib_pa + (ALIGN32 - 1)) & ~(ALIGN32 - 1); - dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + - (hw_fib_pa - dev->hw_fib_pa)); - dev->hw_fib_pa = hw_fib_pa; - memset(dev->hw_fib_va, 0, - (dev->max_fib_size + sizeof(struct aac_fib_xporthdr)) * - (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB)); - - /* add Xport header */ - dev->hw_fib_va = (struct hw_fib *)((unsigned char *)dev->hw_fib_va + - sizeof(struct aac_fib_xporthdr)); - dev->hw_fib_pa += sizeof(struct aac_fib_xporthdr); - - hw_fib = dev->hw_fib_va; - hw_fib_pa = dev->hw_fib_pa; - /* - * Initialise the fibs - */ - for (i = 0, fibptr = &dev->fibs[i]; - i < (dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); - i++, fibptr++) - { - fibptr->dev = dev; - fibptr->hw_fib_va = hw_fib; - fibptr->data = (void *) fibptr->hw_fib_va->data; - fibptr->next = fibptr+1; /* Forward chain the fibs */ - sema_init(&fibptr->event_wait, 0); - spin_lock_init(&fibptr->event_lock); - hw_fib->header.XferState = cpu_to_le32(0xffffffff); - hw_fib->header.SenderSize = cpu_to_le16(dev->max_fib_size); - fibptr->hw_fib_pa = hw_fib_pa; - hw_fib = (struct hw_fib *)((unsigned char *)hw_fib + - dev->max_fib_size + sizeof(struct aac_fib_xporthdr)); - hw_fib_pa = hw_fib_pa + - dev->max_fib_size + sizeof(struct aac_fib_xporthdr); - } - /* - * Add the fib chain to the free list - */ - dev->fibs[dev->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB - 1].next = NULL; - /* - * Enable this to debug out of queue space - */ - dev->free_fib = &dev->fibs[0]; - return 0; -} - -/** - * aac_fib_alloc - allocate a fib - * @dev: Adapter to allocate the fib for - * - * Allocate a fib from the adapter fib pool. If the pool is empty we - * return NULL. - */ - -struct fib *aac_fib_alloc(struct aac_dev *dev) -{ - struct fib * fibptr; - unsigned long flags; - spin_lock_irqsave(&dev->fib_lock, flags); - fibptr = dev->free_fib; - if(!fibptr){ - spin_unlock_irqrestore(&dev->fib_lock, flags); - return fibptr; - } - dev->free_fib = fibptr->next; - spin_unlock_irqrestore(&dev->fib_lock, flags); - /* - * Set the proper node type code and node byte size - */ - fibptr->type = FSAFS_NTC_FIB_CONTEXT; - fibptr->size = sizeof(struct fib); - /* - * Null out fields that depend on being zero at the start of - * each I/O - */ - fibptr->hw_fib_va->header.XferState = 0; - fibptr->flags = 0; - fibptr->callback = NULL; - fibptr->callback_data = NULL; - - return fibptr; -} - -/** - * aac_fib_free - free a fib - * @fibptr: fib to free up - * - * Frees up a fib and places it on the appropriate queue - */ - -void aac_fib_free(struct fib *fibptr) -{ - unsigned long flags, flagsv; - - spin_lock_irqsave(&fibptr->event_lock, flagsv); - if (fibptr->done == 2) { - spin_unlock_irqrestore(&fibptr->event_lock, flagsv); - return; - } - spin_unlock_irqrestore(&fibptr->event_lock, flagsv); - - spin_lock_irqsave(&fibptr->dev->fib_lock, flags); - if (unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) - aac_config.fib_timeouts++; - if (fibptr->hw_fib_va->header.XferState != 0) { - printk(KERN_WARNING "aac_fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", - (void*)fibptr, - le32_to_cpu(fibptr->hw_fib_va->header.XferState)); - } - fibptr->next = fibptr->dev->free_fib; - fibptr->dev->free_fib = fibptr; - spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags); -} - -/** - * aac_fib_init - initialise a fib - * @fibptr: The fib to initialize - * - * Set up the generic fib fields ready for use - */ - -void aac_fib_init(struct fib *fibptr) -{ - struct hw_fib *hw_fib = fibptr->hw_fib_va; - - hw_fib->header.StructType = FIB_MAGIC; - hw_fib->header.Size = cpu_to_le16(fibptr->dev->max_fib_size); - hw_fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable); - hw_fib->header.SenderFibAddress = 0; /* Filled in later if needed */ - hw_fib->header.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa); - hw_fib->header.SenderSize = cpu_to_le16(fibptr->dev->max_fib_size); -} - -/** - * fib_deallocate - deallocate a fib - * @fibptr: fib to deallocate - * - * Will deallocate and return to the free pool the FIB pointed to by the - * caller. - */ - -static void fib_dealloc(struct fib * fibptr) -{ - struct hw_fib *hw_fib = fibptr->hw_fib_va; - BUG_ON(hw_fib->header.StructType != FIB_MAGIC); - hw_fib->header.XferState = 0; -} - -/* - * Commuication primitives define and support the queuing method we use to - * support host to adapter commuication. All queue accesses happen through - * these routines and are the only routines which have a knowledge of the - * how these queues are implemented. - */ - -/** - * aac_get_entry - get a queue entry - * @dev: Adapter - * @qid: Queue Number - * @entry: Entry return - * @index: Index return - * @nonotify: notification control - * - * With a priority the routine returns a queue entry if the queue has free entries. If the queue - * is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is - * returned. - */ - -static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) -{ - struct aac_queue * q; - unsigned long idx; - - /* - * All of the queues wrap when they reach the end, so we check - * to see if they have reached the end and if they have we just - * set the index back to zero. This is a wrap. You could or off - * the high bits in all updates but this is a bit faster I think. - */ - - q = &dev->queues->queue[qid]; - - idx = *index = le32_to_cpu(*(q->headers.producer)); - /* Interrupt Moderation, only interrupt for first two entries */ - if (idx != le32_to_cpu(*(q->headers.consumer))) { - if (--idx == 0) { - if (qid == AdapNormCmdQueue) - idx = ADAP_NORM_CMD_ENTRIES; - else - idx = ADAP_NORM_RESP_ENTRIES; - } - if (idx != le32_to_cpu(*(q->headers.consumer))) - *nonotify = 1; - } - - if (qid == AdapNormCmdQueue) { - if (*index >= ADAP_NORM_CMD_ENTRIES) - *index = 0; /* Wrap to front of the Producer Queue. */ - } else { - if (*index >= ADAP_NORM_RESP_ENTRIES) - *index = 0; /* Wrap to front of the Producer Queue. */ - } - - /* Queue is full */ - if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { - printk(KERN_WARNING "Queue %d full, %u outstanding.\n", - qid, q->numpending); - return 0; - } else { - *entry = q->base + *index; - return 1; - } -} - -/** - * aac_queue_get - get the next free QE - * @dev: Adapter - * @index: Returned index - * @priority: Priority of fib - * @fib: Fib to associate with the queue entry - * @wait: Wait if queue full - * @fibptr: Driver fib object to go with fib - * @nonotify: Don't notify the adapter - * - * Gets the next free QE off the requested priorty adapter command - * queue and associates the Fib with the QE. The QE represented by - * index is ready to insert on the queue when this routine returns - * success. - */ - -int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify) -{ - struct aac_entry * entry = NULL; - int map = 0; - - if (qid == AdapNormCmdQueue) { - /* if no entries wait for some if caller wants to */ - while (!aac_get_entry(dev, qid, &entry, index, nonotify)) { - printk(KERN_ERR "GetEntries failed\n"); - } - /* - * Setup queue entry with a command, status and fib mapped - */ - entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); - map = 1; - } else { - while (!aac_get_entry(dev, qid, &entry, index, nonotify)) { - /* if no entries wait for some if caller wants to */ - } - /* - * Setup queue entry with command, status and fib mapped - */ - entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size)); - entry->addr = hw_fib->header.SenderFibAddress; - /* Restore adapters pointer to the FIB */ - hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress; /* Let the adapter now where to find its data */ - map = 0; - } - /* - * If MapFib is true than we need to map the Fib and put pointers - * in the queue entry. - */ - if (map) - entry->addr = cpu_to_le32(fibptr->hw_fib_pa); - return 0; -} - -/* - * Define the highest level of host to adapter communication routines. - * These routines will support host to adapter FS commuication. These - * routines have no knowledge of the commuication method used. This level - * sends and receives FIBs. This level has no knowledge of how these FIBs - * get passed back and forth. - */ - -/** - * aac_fib_send - send a fib to the adapter - * @command: Command to send - * @fibptr: The fib - * @size: Size of fib data area - * @priority: Priority of Fib - * @wait: Async/sync select - * @reply: True if a reply is wanted - * @callback: Called with reply - * @callback_data: Passed to callback - * - * Sends the requested FIB to the adapter and optionally will wait for a - * response FIB. If the caller does not wish to wait for a response than - * an event to wait on must be supplied. This event will be set when a - * response FIB is received from the adapter. - */ - -int aac_fib_send(u16 command, struct fib *fibptr, unsigned long size, - int priority, int wait, int reply, fib_callback callback, - void *callback_data) -{ - struct aac_dev * dev = fibptr->dev; - struct hw_fib * hw_fib = fibptr->hw_fib_va; - unsigned long flags = 0; - unsigned long qflags; - unsigned long mflags = 0; - unsigned long sflags = 0; - - - if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned))) - return -EBUSY; - /* - * There are 5 cases with the wait and response requested flags. - * The only invalid cases are if the caller requests to wait and - * does not request a response and if the caller does not want a - * response and the Fib is not allocated from pool. If a response - * is not requesed the Fib will just be deallocaed by the DPC - * routine when the response comes back from the adapter. No - * further processing will be done besides deleting the Fib. We - * will have a debug mode where the adapter can notify the host - * it had a problem and the host can log that fact. - */ - fibptr->flags = 0; - if (wait && !reply) { - return -EINVAL; - } else if (!wait && reply) { - hw_fib->header.XferState |= cpu_to_le32(Async | ResponseExpected); - FIB_COUNTER_INCREMENT(aac_config.AsyncSent); - } else if (!wait && !reply) { - hw_fib->header.XferState |= cpu_to_le32(NoResponseExpected); - FIB_COUNTER_INCREMENT(aac_config.NoResponseSent); - } else if (wait && reply) { - hw_fib->header.XferState |= cpu_to_le32(ResponseExpected); - FIB_COUNTER_INCREMENT(aac_config.NormalSent); - } - /* - * Map the fib into 32bits by using the fib number - */ - - hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr - dev->fibs)) << 2); - hw_fib->header.SenderData = (u32)(fibptr - dev->fibs); - /* - * Set FIB state to indicate where it came from and if we want a - * response from the adapter. Also load the command from the - * caller. - * - * Map the hw fib pointer as a 32bit value - */ - hw_fib->header.Command = cpu_to_le16(command); - hw_fib->header.XferState |= cpu_to_le32(SentFromHost); - fibptr->hw_fib_va->header.Flags = 0; /* 0 the flags field - internal only*/ - /* - * Set the size of the Fib we want to send to the adapter - */ - hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size); - if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) { - return -EMSGSIZE; - } - /* - * Get a queue entry connect the FIB to it and send an notify - * the adapter a command is ready. - */ - hw_fib->header.XferState |= cpu_to_le32(NormalPriority); - - /* - * Fill in the Callback and CallbackContext if we are not - * going to wait. - */ - if (!wait) { - fibptr->callback = callback; - fibptr->callback_data = callback_data; - fibptr->flags = FIB_CONTEXT_FLAG; - } - - fibptr->done = 0; - - FIB_COUNTER_INCREMENT(aac_config.FibsSent); - - dprintk((KERN_DEBUG "Fib contents:.\n")); - dprintk((KERN_DEBUG " Command = %d.\n", le32_to_cpu(hw_fib->header.Command))); - dprintk((KERN_DEBUG " SubCommand = %d.\n", le32_to_cpu(((struct aac_query_mount *)fib_data(fibptr))->command))); - dprintk((KERN_DEBUG " XferState = %x.\n", le32_to_cpu(hw_fib->header.XferState))); - dprintk((KERN_DEBUG " hw_fib va being sent=%p\n",fibptr->hw_fib_va)); - dprintk((KERN_DEBUG " hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa)); - dprintk((KERN_DEBUG " fib being sent=%p\n",fibptr)); - - if (!dev->queues) - return -EBUSY; - - if (wait) { - - spin_lock_irqsave(&dev->manage_lock, mflags); - if (dev->management_fib_count >= AAC_NUM_MGT_FIB) { - printk(KERN_INFO "No management Fibs Available:%d\n", - dev->management_fib_count); - spin_unlock_irqrestore(&dev->manage_lock, mflags); - return -EBUSY; - } - dev->management_fib_count++; - spin_unlock_irqrestore(&dev->manage_lock, mflags); - spin_lock_irqsave(&fibptr->event_lock, flags); - } - - if (dev->sync_mode) { - if (wait) - spin_unlock_irqrestore(&fibptr->event_lock, flags); - spin_lock_irqsave(&dev->sync_lock, sflags); - if (dev->sync_fib) { - list_add_tail(&fibptr->fiblink, &dev->sync_fib_list); - spin_unlock_irqrestore(&dev->sync_lock, sflags); - } else { - dev->sync_fib = fibptr; - spin_unlock_irqrestore(&dev->sync_lock, sflags); - aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, - (u32)fibptr->hw_fib_pa, 0, 0, 0, 0, 0, - NULL, NULL, NULL, NULL, NULL); - } - if (wait) { - fibptr->flags |= FIB_CONTEXT_FLAG_WAIT; - if (down_interruptible(&fibptr->event_wait)) { - fibptr->flags &= ~FIB_CONTEXT_FLAG_WAIT; - return -EFAULT; - } - return 0; - } - return -EINPROGRESS; - } - - if (aac_adapter_deliver(fibptr) != 0) { - printk(KERN_ERR "aac_fib_send: returned -EBUSY\n"); - if (wait) { - spin_unlock_irqrestore(&fibptr->event_lock, flags); - spin_lock_irqsave(&dev->manage_lock, mflags); - dev->management_fib_count--; - spin_unlock_irqrestore(&dev->manage_lock, mflags); - } - return -EBUSY; - } - - - /* - * If the caller wanted us to wait for response wait now. - */ - - if (wait) { - spin_unlock_irqrestore(&fibptr->event_lock, flags); - /* Only set for first known interruptable command */ - if (wait < 0) { - /* - * *VERY* Dangerous to time out a command, the - * assumption is made that we have no hope of - * functioning because an interrupt routing or other - * hardware failure has occurred. - */ - unsigned long count = 36000000L; /* 3 minutes */ - while (down_trylock(&fibptr->event_wait)) { - int blink; - if (--count == 0) { - struct aac_queue * q = &dev->queues->queue[AdapNormCmdQueue]; - spin_lock_irqsave(q->lock, qflags); - q->numpending--; - spin_unlock_irqrestore(q->lock, qflags); - if (wait == -1) { - printk(KERN_ERR "aacraid: aac_fib_send: first asynchronous command timed out.\n" - "Usually a result of a PCI interrupt routing problem;\n" - "update mother board BIOS or consider utilizing one of\n" - "the SAFE mode kernel options (acpi, apic etc)\n"); - } - return -ETIMEDOUT; - } - if ((blink = aac_adapter_check_health(dev)) > 0) { - if (wait == -1) { - printk(KERN_ERR "aacraid: aac_fib_send: adapter blinkLED 0x%x.\n" - "Usually a result of a serious unrecoverable hardware problem\n", - blink); - } - return -EFAULT; - } - udelay(5); - } - } else if (down_interruptible(&fibptr->event_wait)) { - /* Do nothing ... satisfy - * down_interruptible must_check */ - } - - spin_lock_irqsave(&fibptr->event_lock, flags); - if (fibptr->done == 0) { - fibptr->done = 2; /* Tell interrupt we aborted */ - spin_unlock_irqrestore(&fibptr->event_lock, flags); - return -ERESTARTSYS; - } - spin_unlock_irqrestore(&fibptr->event_lock, flags); - BUG_ON(fibptr->done == 0); - - if(unlikely(fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) - return -ETIMEDOUT; - return 0; - } - /* - * If the user does not want a response than return success otherwise - * return pending - */ - if (reply) - return -EINPROGRESS; - else - return 0; -} - -/** - * aac_consumer_get - get the top of the queue - * @dev: Adapter - * @q: Queue - * @entry: Return entry - * - * Will return a pointer to the entry on the top of the queue requested that - * we are a consumer of, and return the address of the queue entry. It does - * not change the state of the queue. - */ - -int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry) -{ - u32 index; - int status; - if (le32_to_cpu(*q->headers.producer) == le32_to_cpu(*q->headers.consumer)) { - status = 0; - } else { - /* - * The consumer index must be wrapped if we have reached - * the end of the queue, else we just use the entry - * pointed to by the header index - */ - if (le32_to_cpu(*q->headers.consumer) >= q->entries) - index = 0; - else - index = le32_to_cpu(*q->headers.consumer); - *entry = q->base + index; - status = 1; - } - return(status); -} - -/** - * aac_consumer_free - free consumer entry - * @dev: Adapter - * @q: Queue - * @qid: Queue ident - * - * Frees up the current top of the queue we are a consumer of. If the - * queue was full notify the producer that the queue is no longer full. - */ - -void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid) -{ - int wasfull = 0; - u32 notify; - - if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer)) - wasfull = 1; - - if (le32_to_cpu(*q->headers.consumer) >= q->entries) - *q->headers.consumer = cpu_to_le32(1); - else - le32_add_cpu(q->headers.consumer, 1); - - if (wasfull) { - switch (qid) { - - case HostNormCmdQueue: - notify = HostNormCmdNotFull; - break; - case HostNormRespQueue: - notify = HostNormRespNotFull; - break; - default: - BUG(); - return; - } - aac_adapter_notify(dev, notify); - } -} - -/** - * aac_fib_adapter_complete - complete adapter issued fib - * @fibptr: fib to complete - * @size: size of fib - * - * Will do all necessary work to complete a FIB that was sent from - * the adapter. - */ - -int aac_fib_adapter_complete(struct fib *fibptr, unsigned short size) -{ - struct hw_fib * hw_fib = fibptr->hw_fib_va; - struct aac_dev * dev = fibptr->dev; - struct aac_queue * q; - unsigned long nointr = 0; - unsigned long qflags; - - if (dev->comm_interface == AAC_COMM_MESSAGE_TYPE1) { - kfree(hw_fib); - return 0; - } - - if (hw_fib->header.XferState == 0) { - if (dev->comm_interface == AAC_COMM_MESSAGE) - kfree(hw_fib); - return 0; - } - /* - * If we plan to do anything check the structure type first. - */ - if (hw_fib->header.StructType != FIB_MAGIC) { - if (dev->comm_interface == AAC_COMM_MESSAGE) - kfree(hw_fib); - return -EINVAL; - } - /* - * This block handles the case where the adapter had sent us a - * command and we have finished processing the command. We - * call completeFib when we are done processing the command - * and want to send a response back to the adapter. This will - * send the completed cdb to the adapter. - */ - if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) { - if (dev->comm_interface == AAC_COMM_MESSAGE) { - kfree (hw_fib); - } else { - u32 index; - hw_fib->header.XferState |= cpu_to_le32(HostProcessed); - if (size) { - size += sizeof(struct aac_fibhdr); - if (size > le16_to_cpu(hw_fib->header.SenderSize)) - return -EMSGSIZE; - hw_fib->header.Size = cpu_to_le16(size); - } - q = &dev->queues->queue[AdapNormRespQueue]; - spin_lock_irqsave(q->lock, qflags); - aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr); - *(q->headers.producer) = cpu_to_le32(index + 1); - spin_unlock_irqrestore(q->lock, qflags); - if (!(nointr & (int)aac_config.irq_mod)) - aac_adapter_notify(dev, AdapNormRespQueue); - } - } else { - printk(KERN_WARNING "aac_fib_adapter_complete: " - "Unknown xferstate detected.\n"); - BUG(); - } - return 0; -} - -/** - * aac_fib_complete - fib completion handler - * @fib: FIB to complete - * - * Will do all necessary work to complete a FIB. - */ - -int aac_fib_complete(struct fib *fibptr) -{ - unsigned long flags; - struct hw_fib * hw_fib = fibptr->hw_fib_va; - - /* - * Check for a fib which has already been completed - */ - - if (hw_fib->header.XferState == 0) - return 0; - /* - * If we plan to do anything check the structure type first. - */ - - if (hw_fib->header.StructType != FIB_MAGIC) - return -EINVAL; - /* - * This block completes a cdb which orginated on the host and we - * just need to deallocate the cdb or reinit it. At this point the - * command is complete that we had sent to the adapter and this - * cdb could be reused. - */ - spin_lock_irqsave(&fibptr->event_lock, flags); - if (fibptr->done == 2) { - spin_unlock_irqrestore(&fibptr->event_lock, flags); - return 0; - } - spin_unlock_irqrestore(&fibptr->event_lock, flags); - - if((hw_fib->header.XferState & cpu_to_le32(SentFromHost)) && - (hw_fib->header.XferState & cpu_to_le32(AdapterProcessed))) - { - fib_dealloc(fibptr); - } - else if(hw_fib->header.XferState & cpu_to_le32(SentFromHost)) - { - /* - * This handles the case when the host has aborted the I/O - * to the adapter because the adapter is not responding - */ - fib_dealloc(fibptr); - } else if(hw_fib->header.XferState & cpu_to_le32(HostOwned)) { - fib_dealloc(fibptr); - } else { - BUG(); - } - return 0; -} - -/** - * aac_printf - handle printf from firmware - * @dev: Adapter - * @val: Message info - * - * Print a message passed to us by the controller firmware on the - * Adaptec board - */ - -void aac_printf(struct aac_dev *dev, u32 val) -{ - char *cp = dev->printfbuf; - if (dev->printf_enabled) - { - int length = val & 0xffff; - int level = (val >> 16) & 0xffff; - - /* - * The size of the printfbuf is set in port.c - * There is no variable or define for it - */ - if (length > 255) - length = 255; - if (cp[length] != 0) - cp[length] = 0; - if (level == LOG_AAC_HIGH_ERROR) - printk(KERN_WARNING "%s:%s", dev->name, cp); - else - printk(KERN_INFO "%s:%s", dev->name, cp); - } - memset(cp, 0, 256); -} - - -/** - * aac_handle_aif - Handle a message from the firmware - * @dev: Which adapter this fib is from - * @fibptr: Pointer to fibptr from adapter - * - * This routine handles a driver notify fib from the adapter and - * dispatches it to the appropriate routine for handling. - */ - -#define AIF_SNIFF_TIMEOUT (30*HZ) -static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) -{ - struct hw_fib * hw_fib = fibptr->hw_fib_va; - struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data; - u32 channel, id, lun, container; - struct scsi_device *device; - enum { - NOTHING, - DELETE, - ADD, - CHANGE - } device_config_needed = NOTHING; - - /* Sniff for container changes */ - - if (!dev || !dev->fsa_dev) - return; - container = channel = id = lun = (u32)-1; - - /* - * We have set this up to try and minimize the number of - * re-configures that take place. As a result of this when - * certain AIF's come in we will set a flag waiting for another - * type of AIF before setting the re-config flag. - */ - switch (le32_to_cpu(aifcmd->command)) { - case AifCmdDriverNotify: - switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) { - /* - * Morph or Expand complete - */ - case AifDenMorphComplete: - case AifDenVolumeExtendComplete: - container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); - if (container >= dev->maximum_num_containers) - break; - - /* - * Find the scsi_device associated with the SCSI - * address. Make sure we have the right array, and if - * so set the flag to initiate a new re-config once we - * see an AifEnConfigChange AIF come through. - */ - - if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) { - device = scsi_device_lookup(dev->scsi_host_ptr, - CONTAINER_TO_CHANNEL(container), - CONTAINER_TO_ID(container), - CONTAINER_TO_LUN(container)); - if (device) { - dev->fsa_dev[container].config_needed = CHANGE; - dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; - dev->fsa_dev[container].config_waiting_stamp = jiffies; - scsi_device_put(device); - } - } - } - - /* - * If we are waiting on something and this happens to be - * that thing then set the re-configure flag. - */ - if (container != (u32)-1) { - if (container >= dev->maximum_num_containers) - break; - if ((dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(__le32 *)aifcmd->data)) && - time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) - dev->fsa_dev[container].config_waiting_on = 0; - } else for (container = 0; - container < dev->maximum_num_containers; ++container) { - if ((dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(__le32 *)aifcmd->data)) && - time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) - dev->fsa_dev[container].config_waiting_on = 0; - } - break; - - case AifCmdEventNotify: - switch (le32_to_cpu(((__le32 *)aifcmd->data)[0])) { - case AifEnBatteryEvent: - dev->cache_protected = - (((__le32 *)aifcmd->data)[1] == cpu_to_le32(3)); - break; - /* - * Add an Array. - */ - case AifEnAddContainer: - container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); - if (container >= dev->maximum_num_containers) - break; - dev->fsa_dev[container].config_needed = ADD; - dev->fsa_dev[container].config_waiting_on = - AifEnConfigChange; - dev->fsa_dev[container].config_waiting_stamp = jiffies; - break; - - /* - * Delete an Array. - */ - case AifEnDeleteContainer: - container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); - if (container >= dev->maximum_num_containers) - break; - dev->fsa_dev[container].config_needed = DELETE; - dev->fsa_dev[container].config_waiting_on = - AifEnConfigChange; - dev->fsa_dev[container].config_waiting_stamp = jiffies; - break; - - /* - * Container change detected. If we currently are not - * waiting on something else, setup to wait on a Config Change. - */ - case AifEnContainerChange: - container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); - if (container >= dev->maximum_num_containers) - break; - if (dev->fsa_dev[container].config_waiting_on && - time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) - break; - dev->fsa_dev[container].config_needed = CHANGE; - dev->fsa_dev[container].config_waiting_on = - AifEnConfigChange; - dev->fsa_dev[container].config_waiting_stamp = jiffies; - break; - - case AifEnConfigChange: - break; - - case AifEnAddJBOD: - case AifEnDeleteJBOD: - container = le32_to_cpu(((__le32 *)aifcmd->data)[1]); - if ((container >> 28)) { - container = (u32)-1; - break; - } - channel = (container >> 24) & 0xF; - if (channel >= dev->maximum_num_channels) { - container = (u32)-1; - break; - } - id = container & 0xFFFF; - if (id >= dev->maximum_num_physicals) { - container = (u32)-1; - break; - } - lun = (container >> 16) & 0xFF; - container = (u32)-1; - channel = aac_phys_to_logical(channel); - device_config_needed = - (((__le32 *)aifcmd->data)[0] == - cpu_to_le32(AifEnAddJBOD)) ? ADD : DELETE; - if (device_config_needed == ADD) { - device = scsi_device_lookup(dev->scsi_host_ptr, - channel, - id, - lun); - if (device) { - scsi_remove_device(device); - scsi_device_put(device); - } - } - break; - - case AifEnEnclosureManagement: - /* - * If in JBOD mode, automatic exposure of new - * physical target to be suppressed until configured. - */ - if (dev->jbod) - break; - switch (le32_to_cpu(((__le32 *)aifcmd->data)[3])) { - case EM_DRIVE_INSERTION: - case EM_DRIVE_REMOVAL: - container = le32_to_cpu( - ((__le32 *)aifcmd->data)[2]); - if ((container >> 28)) { - container = (u32)-1; - break; - } - channel = (container >> 24) & 0xF; - if (channel >= dev->maximum_num_channels) { - container = (u32)-1; - break; - } - id = container & 0xFFFF; - lun = (container >> 16) & 0xFF; - container = (u32)-1; - if (id >= dev->maximum_num_physicals) { - /* legacy dev_t ? */ - if ((0x2000 <= id) || lun || channel || - ((channel = (id >> 7) & 0x3F) >= - dev->maximum_num_channels)) - break; - lun = (id >> 4) & 7; - id &= 0xF; - } - channel = aac_phys_to_logical(channel); - device_config_needed = - (((__le32 *)aifcmd->data)[3] - == cpu_to_le32(EM_DRIVE_INSERTION)) ? - ADD : DELETE; - break; - } - break; - } - - /* - * If we are waiting on something and this happens to be - * that thing then set the re-configure flag. - */ - if (container != (u32)-1) { - if (container >= dev->maximum_num_containers) - break; - if ((dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(__le32 *)aifcmd->data)) && - time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) - dev->fsa_dev[container].config_waiting_on = 0; - } else for (container = 0; - container < dev->maximum_num_containers; ++container) { - if ((dev->fsa_dev[container].config_waiting_on == - le32_to_cpu(*(__le32 *)aifcmd->data)) && - time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) - dev->fsa_dev[container].config_waiting_on = 0; - } - break; - - case AifCmdJobProgress: - /* - * These are job progress AIF's. When a Clear is being - * done on a container it is initially created then hidden from - * the OS. When the clear completes we don't get a config - * change so we monitor the job status complete on a clear then - * wait for a container change. - */ - - if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) && - (((__le32 *)aifcmd->data)[6] == ((__le32 *)aifcmd->data)[5] || - ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess))) { - for (container = 0; - container < dev->maximum_num_containers; - ++container) { - /* - * Stomp on all config sequencing for all - * containers? - */ - dev->fsa_dev[container].config_waiting_on = - AifEnContainerChange; - dev->fsa_dev[container].config_needed = ADD; - dev->fsa_dev[container].config_waiting_stamp = - jiffies; - } - } - if (((__le32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero) && - ((__le32 *)aifcmd->data)[6] == 0 && - ((__le32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning)) { - for (container = 0; - container < dev->maximum_num_containers; - ++container) { - /* - * Stomp on all config sequencing for all - * containers? - */ - dev->fsa_dev[container].config_waiting_on = - AifEnContainerChange; - dev->fsa_dev[container].config_needed = DELETE; - dev->fsa_dev[container].config_waiting_stamp = - jiffies; - } - } - break; - } - - container = 0; -retry_next: - if (device_config_needed == NOTHING) - for (; container < dev->maximum_num_containers; ++container) { - if ((dev->fsa_dev[container].config_waiting_on == 0) && - (dev->fsa_dev[container].config_needed != NOTHING) && - time_before(jiffies, dev->fsa_dev[container].config_waiting_stamp + AIF_SNIFF_TIMEOUT)) { - device_config_needed = - dev->fsa_dev[container].config_needed; - dev->fsa_dev[container].config_needed = NOTHING; - channel = CONTAINER_TO_CHANNEL(container); - id = CONTAINER_TO_ID(container); - lun = CONTAINER_TO_LUN(container); - break; - } - } - if (device_config_needed == NOTHING) - return; - - /* - * If we decided that a re-configuration needs to be done, - * schedule it here on the way out the door, please close the door - * behind you. - */ - - /* - * Find the scsi_device associated with the SCSI address, - * and mark it as changed, invalidating the cache. This deals - * with changes to existing device IDs. - */ - - if (!dev || !dev->scsi_host_ptr) - return; - /* - * force reload of disk info via aac_probe_container - */ - if ((channel == CONTAINER_CHANNEL) && - (device_config_needed != NOTHING)) { - if (dev->fsa_dev[container].valid == 1) - dev->fsa_dev[container].valid = 2; - aac_probe_container(dev, container); - } - device = scsi_device_lookup(dev->scsi_host_ptr, channel, id, lun); - if (device) { - switch (device_config_needed) { - case DELETE: -#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE)) - scsi_remove_device(device); -#else - if (scsi_device_online(device)) { - scsi_device_set_state(device, SDEV_OFFLINE); - sdev_printk(KERN_INFO, device, - "Device offlined - %s\n", - (channel == CONTAINER_CHANNEL) ? - "array deleted" : - "enclosure services event"); - } -#endif - break; - case ADD: - if (!scsi_device_online(device)) { - sdev_printk(KERN_INFO, device, - "Device online - %s\n", - (channel == CONTAINER_CHANNEL) ? - "array created" : - "enclosure services event"); - scsi_device_set_state(device, SDEV_RUNNING); - } - /* FALLTHRU */ - case CHANGE: - if ((channel == CONTAINER_CHANNEL) - && (!dev->fsa_dev[container].valid)) { -#if (defined(AAC_DEBUG_INSTRUMENT_AIF_DELETE)) - scsi_remove_device(device); -#else - if (!scsi_device_online(device)) - break; - scsi_device_set_state(device, SDEV_OFFLINE); - sdev_printk(KERN_INFO, device, - "Device offlined - %s\n", - "array failed"); -#endif - break; - } - scsi_rescan_device(&device->sdev_gendev); - - default: - break; - } - scsi_device_put(device); - device_config_needed = NOTHING; - } - if (device_config_needed == ADD) - scsi_add_device(dev->scsi_host_ptr, channel, id, lun); - if (channel == CONTAINER_CHANNEL) { - container++; - device_config_needed = NOTHING; - goto retry_next; - } -} - -static int _aac_reset_adapter(struct aac_dev *aac, int forced) -{ - int index, quirks; - int retval; - struct Scsi_Host *host; - struct scsi_device *dev; - struct scsi_cmnd *command; - struct scsi_cmnd *command_list; - int jafo = 0; - - /* - * Assumptions: - * - host is locked, unless called by the aacraid thread. - * (a matter of convenience, due to legacy issues surrounding - * eh_host_adapter_reset). - * - in_reset is asserted, so no new i/o is getting to the - * card. - * - The card is dead, or will be very shortly ;-/ so no new - * commands are completing in the interrupt service. - */ - host = aac->scsi_host_ptr; - scsi_block_requests(host); - aac_adapter_disable_int(aac); - if (aac->thread->pid != current->pid) { - spin_unlock_irq(host->host_lock); - kthread_stop(aac->thread); - jafo = 1; - } - - /* - * If a positive health, means in a known DEAD PANIC - * state and the adapter could be reset to `try again'. - */ - retval = aac_adapter_restart(aac, forced ? 0 : aac_adapter_check_health(aac)); - - if (retval) - goto out; - - /* - * Loop through the fibs, close the synchronous FIBS - */ - for (retval = 1, index = 0; index < (aac->scsi_host_ptr->can_queue + AAC_NUM_MGT_FIB); index++) { - struct fib *fib = &aac->fibs[index]; - if (!(fib->hw_fib_va->header.XferState & cpu_to_le32(NoResponseExpected | Async)) && - (fib->hw_fib_va->header.XferState & cpu_to_le32(ResponseExpected))) { - unsigned long flagv; - spin_lock_irqsave(&fib->event_lock, flagv); - up(&fib->event_wait); - spin_unlock_irqrestore(&fib->event_lock, flagv); - schedule(); - retval = 0; - } - } - /* Give some extra time for ioctls to complete. */ - if (retval == 0) - ssleep(2); - index = aac->cardtype; - - /* - * Re-initialize the adapter, first free resources, then carefully - * apply the initialization sequence to come back again. Only risk - * is a change in Firmware dropping cache, it is assumed the caller - * will ensure that i/o is queisced and the card is flushed in that - * case. - */ - aac_fib_map_free(aac); - pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys); - aac->comm_addr = NULL; - aac->comm_phys = 0; - kfree(aac->queues); - aac->queues = NULL; - free_irq(aac->pdev->irq, aac); - if (aac->msi) - pci_disable_msi(aac->pdev); - kfree(aac->fsa_dev); - aac->fsa_dev = NULL; - quirks = aac_get_driver_ident(index)->quirks; - if (quirks & AAC_QUIRK_31BIT) { - if (((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(31)))) || - ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_BIT_MASK(31))))) - goto out; - } else { - if (((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(32)))) || - ((retval = pci_set_consistent_dma_mask(aac->pdev, DMA_BIT_MASK(32))))) - goto out; - } - if ((retval = (*(aac_get_driver_ident(index)->init))(aac))) - goto out; - if (quirks & AAC_QUIRK_31BIT) - if ((retval = pci_set_dma_mask(aac->pdev, DMA_BIT_MASK(32)))) - goto out; - if (jafo) { - aac->thread = kthread_run(aac_command_thread, aac, aac->name); - if (IS_ERR(aac->thread)) { - retval = PTR_ERR(aac->thread); - goto out; - } - } - (void)aac_get_adapter_info(aac); - if ((quirks & AAC_QUIRK_34SG) && (host->sg_tablesize > 34)) { - host->sg_tablesize = 34; - host->max_sectors = (host->sg_tablesize * 8) + 112; - } - if ((quirks & AAC_QUIRK_17SG) && (host->sg_tablesize > 17)) { - host->sg_tablesize = 17; - host->max_sectors = (host->sg_tablesize * 8) + 112; - } - aac_get_config_status(aac, 1); - aac_get_containers(aac); - /* - * This is where the assumption that the Adapter is quiesced - * is important. - */ - command_list = NULL; - __shost_for_each_device(dev, host) { - unsigned long flags; - spin_lock_irqsave(&dev->list_lock, flags); - list_for_each_entry(command, &dev->cmd_list, list) - if (command->SCp.phase == AAC_OWNER_FIRMWARE) { - command->SCp.buffer = (struct scatterlist *)command_list; - command_list = command; - } - spin_unlock_irqrestore(&dev->list_lock, flags); - } - while ((command = command_list)) { - command_list = (struct scsi_cmnd *)command->SCp.buffer; - command->SCp.buffer = NULL; - command->result = DID_OK << 16 - | COMMAND_COMPLETE << 8 - | SAM_STAT_TASK_SET_FULL; - command->SCp.phase = AAC_OWNER_ERROR_HANDLER; - command->scsi_done(command); - } - retval = 0; - -out: - aac->in_reset = 0; - scsi_unblock_requests(host); - if (jafo) { - spin_lock_irq(host->host_lock); - } - return retval; -} - -int aac_reset_adapter(struct aac_dev * aac, int forced) -{ - unsigned long flagv = 0; - int retval; - struct Scsi_Host * host; - - if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0) - return -EBUSY; - - if (aac->in_reset) { - spin_unlock_irqrestore(&aac->fib_lock, flagv); - return -EBUSY; - } - aac->in_reset = 1; - spin_unlock_irqrestore(&aac->fib_lock, flagv); - - /* - * Wait for all commands to complete to this specific - * target (block maximum 60 seconds). Although not necessary, - * it does make us a good storage citizen. - */ - host = aac->scsi_host_ptr; - scsi_block_requests(host); - if (forced < 2) for (retval = 60; retval; --retval) { - struct scsi_device * dev; - struct scsi_cmnd * command; - int active = 0; - - __shost_for_each_device(dev, host) { - spin_lock_irqsave(&dev->list_lock, flagv); - list_for_each_entry(command, &dev->cmd_list, list) { - if (command->SCp.phase == AAC_OWNER_FIRMWARE) { - active++; - break; - } - } - spin_unlock_irqrestore(&dev->list_lock, flagv); - if (active) - break; - - } - /* - * We can exit If all the commands are complete - */ - if (active == 0) - break; - ssleep(1); - } - - /* Quiesce build, flush cache, write through mode */ - if (forced < 2) - aac_send_shutdown(aac); - spin_lock_irqsave(host->host_lock, flagv); - retval = _aac_reset_adapter(aac, forced ? forced : ((aac_check_reset != 0) && (aac_check_reset != 1))); - spin_unlock_irqrestore(host->host_lock, flagv); - - if ((forced < 2) && (retval == -ENODEV)) { - /* Unwind aac_send_shutdown() IOP_RESET unsupported/disabled */ - struct fib * fibctx = aac_fib_alloc(aac); - if (fibctx) { - struct aac_pause *cmd; - int status; - - aac_fib_init(fibctx); - - cmd = (struct aac_pause *) fib_data(fibctx); - - cmd->command = cpu_to_le32(VM_ContainerConfig); - cmd->type = cpu_to_le32(CT_PAUSE_IO); - cmd->timeout = cpu_to_le32(1); - cmd->min = cpu_to_le32(1); - cmd->noRescan = cpu_to_le32(1); - cmd->count = cpu_to_le32(0); - - status = aac_fib_send(ContainerCommand, - fibctx, - sizeof(struct aac_pause), - FsaNormal, - -2 /* Timeout silently */, 1, - NULL, NULL); - - if (status >= 0) - aac_fib_complete(fibctx); - /* FIB should be freed only after getting - * the response from the F/W */ - if (status != -ERESTARTSYS) - aac_fib_free(fibctx); - } - } - - return retval; -} - -int aac_check_health(struct aac_dev * aac) -{ - int BlinkLED; - unsigned long time_now, flagv = 0; - struct list_head * entry; - struct Scsi_Host * host; - - /* Extending the scope of fib_lock slightly to protect aac->in_reset */ - if (spin_trylock_irqsave(&aac->fib_lock, flagv) == 0) - return 0; - - if (aac->in_reset || !(BlinkLED = aac_adapter_check_health(aac))) { - spin_unlock_irqrestore(&aac->fib_lock, flagv); - return 0; /* OK */ - } - - aac->in_reset = 1; - - /* Fake up an AIF: - * aac_aifcmd.command = AifCmdEventNotify = 1 - * aac_aifcmd.seqnum = 0xFFFFFFFF - * aac_aifcmd.data[0] = AifEnExpEvent = 23 - * aac_aifcmd.data[1] = AifExeFirmwarePanic = 3 - * aac.aifcmd.data[2] = AifHighPriority = 3 - * aac.aifcmd.data[3] = BlinkLED - */ - - time_now = jiffies/HZ; - entry = aac->fib_list.next; - - /* - * For each Context that is on the - * fibctxList, make a copy of the - * fib, and then set the event to wake up the - * thread that is waiting for it. - */ - while (entry != &aac->fib_list) { - /* - * Extract the fibctx - */ - struct aac_fib_context *fibctx = list_entry(entry, struct aac_fib_context, next); - struct hw_fib * hw_fib; - struct fib * fib; - /* - * Check if the queue is getting - * backlogged - */ - if (fibctx->count > 20) { - /* - * It's *not* jiffies folks, - * but jiffies / HZ, so do not - * panic ... - */ - u32 time_last = fibctx->jiffies; - /* - * Has it been > 2 minutes - * since the last read off - * the queue? - */ - if ((time_now - time_last) > aif_timeout) { - entry = entry->next; - aac_close_fib_context(aac, fibctx); - continue; - } - } - /* - * Warning: no sleep allowed while - * holding spinlock - */ - hw_fib = kzalloc(sizeof(struct hw_fib), GFP_ATOMIC); - fib = kzalloc(sizeof(struct fib), GFP_ATOMIC); - if (fib && hw_fib) { - struct aac_aifcmd * aif; - - fib->hw_fib_va = hw_fib; - fib->dev = aac; - aac_fib_init(fib); - fib->type = FSAFS_NTC_FIB_CONTEXT; - fib->size = sizeof (struct fib); - fib->data = hw_fib->data; - aif = (struct aac_aifcmd *)hw_fib->data; - aif->command = cpu_to_le32(AifCmdEventNotify); - aif->seqnum = cpu_to_le32(0xFFFFFFFF); - ((__le32 *)aif->data)[0] = cpu_to_le32(AifEnExpEvent); - ((__le32 *)aif->data)[1] = cpu_to_le32(AifExeFirmwarePanic); - ((__le32 *)aif->data)[2] = cpu_to_le32(AifHighPriority); - ((__le32 *)aif->data)[3] = cpu_to_le32(BlinkLED); - - /* - * Put the FIB onto the - * fibctx's fibs - */ - list_add_tail(&fib->fiblink, &fibctx->fib_list); - fibctx->count++; - /* - * Set the event to wake up the - * thread that will waiting. - */ - up(&fibctx->wait_sem); - } else { - printk(KERN_WARNING "aifd: didn't allocate NewFib.\n"); - kfree(fib); - kfree(hw_fib); - } - entry = entry->next; - } - - spin_unlock_irqrestore(&aac->fib_lock, flagv); - - if (BlinkLED < 0) { - printk(KERN_ERR "%s: Host adapter dead %d\n", aac->name, BlinkLED); - goto out; - } - - printk(KERN_ERR "%s: Host adapter BLINK LED 0x%x\n", aac->name, BlinkLED); - - if (!aac_check_reset || ((aac_check_reset == 1) && - (aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_IGNORE_RESET))) - goto out; - host = aac->scsi_host_ptr; - if (aac->thread->pid != current->pid) - spin_lock_irqsave(host->host_lock, flagv); - BlinkLED = _aac_reset_adapter(aac, aac_check_reset != 1); - if (aac->thread->pid != current->pid) - spin_unlock_irqrestore(host->host_lock, flagv); - return BlinkLED; - -out: - aac->in_reset = 0; - return BlinkLED; -} - - -/** - * aac_command_thread - command processing thread - * @dev: Adapter to monitor - * - * Waits on the commandready event in it's queue. When the event gets set - * it will pull FIBs off it's queue. It will continue to pull FIBs off - * until the queue is empty. When the queue is empty it will wait for - * more FIBs. - */ - -int aac_command_thread(void *data) -{ - struct aac_dev *dev = data; - struct hw_fib *hw_fib, *hw_newfib; - struct fib *fib, *newfib; - struct aac_fib_context *fibctx; - unsigned long flags; - DECLARE_WAITQUEUE(wait, current); - unsigned long next_jiffies = jiffies + HZ; - unsigned long next_check_jiffies = next_jiffies; - long difference = HZ; - - /* - * We can only have one thread per adapter for AIF's. - */ - if (dev->aif_thread) - return -EINVAL; - - /* - * Let the DPC know it has a place to send the AIF's to. - */ - dev->aif_thread = 1; - add_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait); - set_current_state(TASK_INTERRUPTIBLE); - dprintk ((KERN_INFO "aac_command_thread start\n")); - while (1) { - spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags); - while(!list_empty(&(dev->queues->queue[HostNormCmdQueue].cmdq))) { - struct list_head *entry; - struct aac_aifcmd * aifcmd; - - set_current_state(TASK_RUNNING); - - entry = dev->queues->queue[HostNormCmdQueue].cmdq.next; - list_del(entry); - - spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags); - fib = list_entry(entry, struct fib, fiblink); - /* - * We will process the FIB here or pass it to a - * worker thread that is TBD. We Really can't - * do anything at this point since we don't have - * anything defined for this thread to do. - */ - hw_fib = fib->hw_fib_va; - memset(fib, 0, sizeof(struct fib)); - fib->type = FSAFS_NTC_FIB_CONTEXT; - fib->size = sizeof(struct fib); - fib->hw_fib_va = hw_fib; - fib->data = hw_fib->data; - fib->dev = dev; - /* - * We only handle AifRequest fibs from the adapter. - */ - aifcmd = (struct aac_aifcmd *) hw_fib->data; - if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) { - /* Handle Driver Notify Events */ - aac_handle_aif(dev, fib); - *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); - aac_fib_adapter_complete(fib, (u16)sizeof(u32)); - } else { - /* The u32 here is important and intended. We are using - 32bit wrapping time to fit the adapter field */ - - u32 time_now, time_last; - unsigned long flagv; - unsigned num; - struct hw_fib ** hw_fib_pool, ** hw_fib_p; - struct fib ** fib_pool, ** fib_p; - - /* Sniff events */ - if ((aifcmd->command == - cpu_to_le32(AifCmdEventNotify)) || - (aifcmd->command == - cpu_to_le32(AifCmdJobProgress))) { - aac_handle_aif(dev, fib); - } - - time_now = jiffies/HZ; - - /* - * Warning: no sleep allowed while - * holding spinlock. We take the estimate - * and pre-allocate a set of fibs outside the - * lock. - */ - num = le32_to_cpu(dev->init->AdapterFibsSize) - / sizeof(struct hw_fib); /* some extra */ - spin_lock_irqsave(&dev->fib_lock, flagv); - entry = dev->fib_list.next; - while (entry != &dev->fib_list) { - entry = entry->next; - ++num; - } - spin_unlock_irqrestore(&dev->fib_lock, flagv); - hw_fib_pool = NULL; - fib_pool = NULL; - if (num - && ((hw_fib_pool = kmalloc(sizeof(struct hw_fib *) * num, GFP_KERNEL))) - && ((fib_pool = kmalloc(sizeof(struct fib *) * num, GFP_KERNEL)))) { - hw_fib_p = hw_fib_pool; - fib_p = fib_pool; - while (hw_fib_p < &hw_fib_pool[num]) { - if (!(*(hw_fib_p++) = kmalloc(sizeof(struct hw_fib), GFP_KERNEL))) { - --hw_fib_p; - break; - } - if (!(*(fib_p++) = kmalloc(sizeof(struct fib), GFP_KERNEL))) { - kfree(*(--hw_fib_p)); - break; - } - } - if ((num = hw_fib_p - hw_fib_pool) == 0) { - kfree(fib_pool); - fib_pool = NULL; - kfree(hw_fib_pool); - hw_fib_pool = NULL; - } - } else { - kfree(hw_fib_pool); - hw_fib_pool = NULL; - } - spin_lock_irqsave(&dev->fib_lock, flagv); - entry = dev->fib_list.next; - /* - * For each Context that is on the - * fibctxList, make a copy of the - * fib, and then set the event to wake up the - * thread that is waiting for it. - */ - hw_fib_p = hw_fib_pool; - fib_p = fib_pool; - while (entry != &dev->fib_list) { - /* - * Extract the fibctx - */ - fibctx = list_entry(entry, struct aac_fib_context, next); - /* - * Check if the queue is getting - * backlogged - */ - if (fibctx->count > 20) - { - /* - * It's *not* jiffies folks, - * but jiffies / HZ so do not - * panic ... - */ - time_last = fibctx->jiffies; - /* - * Has it been > 2 minutes - * since the last read off - * the queue? - */ - if ((time_now - time_last) > aif_timeout) { - entry = entry->next; - aac_close_fib_context(dev, fibctx); - continue; - } - } - /* - * Warning: no sleep allowed while - * holding spinlock - */ - if (hw_fib_p < &hw_fib_pool[num]) { - hw_newfib = *hw_fib_p; - *(hw_fib_p++) = NULL; - newfib = *fib_p; - *(fib_p++) = NULL; - /* - * Make the copy of the FIB - */ - memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib)); - memcpy(newfib, fib, sizeof(struct fib)); - newfib->hw_fib_va = hw_newfib; - /* - * Put the FIB onto the - * fibctx's fibs - */ - list_add_tail(&newfib->fiblink, &fibctx->fib_list); - fibctx->count++; - /* - * Set the event to wake up the - * thread that is waiting. - */ - up(&fibctx->wait_sem); - } else { - printk(KERN_WARNING "aifd: didn't allocate NewFib.\n"); - } - entry = entry->next; - } - /* - * Set the status of this FIB - */ - *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); - aac_fib_adapter_complete(fib, sizeof(u32)); - spin_unlock_irqrestore(&dev->fib_lock, flagv); - /* Free up the remaining resources */ - hw_fib_p = hw_fib_pool; - fib_p = fib_pool; - while (hw_fib_p < &hw_fib_pool[num]) { - kfree(*hw_fib_p); - kfree(*fib_p); - ++fib_p; - ++hw_fib_p; - } - kfree(hw_fib_pool); - kfree(fib_pool); - } - kfree(fib); - spin_lock_irqsave(dev->queues->queue[HostNormCmdQueue].lock, flags); - } - /* - * There are no more AIF's - */ - spin_unlock_irqrestore(dev->queues->queue[HostNormCmdQueue].lock, flags); - - /* - * Background activity - */ - if ((time_before(next_check_jiffies,next_jiffies)) - && ((difference = next_check_jiffies - jiffies) <= 0)) { - next_check_jiffies = next_jiffies; - if (aac_check_health(dev) == 0) { - difference = ((long)(unsigned)check_interval) - * HZ; - next_check_jiffies = jiffies + difference; - } else if (!dev->queues) - break; - } - if (!time_before(next_check_jiffies,next_jiffies) - && ((difference = next_jiffies - jiffies) <= 0)) { - struct timeval now; - int ret; - - /* Don't even try to talk to adapter if its sick */ - ret = aac_check_health(dev); - if (!ret && !dev->queues) - break; - next_check_jiffies = jiffies - + ((long)(unsigned)check_interval) - * HZ; - do_gettimeofday(&now); - - /* Synchronize our watches */ - if (((1000000 - (1000000 / HZ)) > now.tv_usec) - && (now.tv_usec > (1000000 / HZ))) - difference = (((1000000 - now.tv_usec) * HZ) - + 500000) / 1000000; - else if (ret == 0) { - struct fib *fibptr; - - if ((fibptr = aac_fib_alloc(dev))) { - int status; - __le32 *info; - - aac_fib_init(fibptr); - - info = (__le32 *) fib_data(fibptr); - if (now.tv_usec > 500000) - ++now.tv_sec; - - *info = cpu_to_le32(now.tv_sec); - - status = aac_fib_send(SendHostTime, - fibptr, - sizeof(*info), - FsaNormal, - 1, 1, - NULL, - NULL); - /* Do not set XferState to zero unless - * receives a response from F/W */ - if (status >= 0) - aac_fib_complete(fibptr); - /* FIB should be freed only after - * getting the response from the F/W */ - if (status != -ERESTARTSYS) - aac_fib_free(fibptr); - } - difference = (long)(unsigned)update_interval*HZ; - } else { - /* retry shortly */ - difference = 10 * HZ; - } - next_jiffies = jiffies + difference; - if (time_before(next_check_jiffies,next_jiffies)) - difference = next_check_jiffies - jiffies; - } - if (difference <= 0) - difference = 1; - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(difference); - - if (kthread_should_stop()) - break; - } - if (dev->queues) - remove_wait_queue(&dev->queues->queue[HostNormCmdQueue].cmdready, &wait); - dev->aif_thread = 0; - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/dpcsup.c b/ANDROID_3.4.5/drivers/scsi/aacraid/dpcsup.c deleted file mode 100644 index f0c66a80..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/dpcsup.c +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * dpcsup.c - * - * Abstract: All DPC processing routines for the cyclone board occur here. - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aacraid.h" - -/** - * aac_response_normal - Handle command replies - * @q: Queue to read from - * - * This DPC routine will be run when the adapter interrupts us to let us - * know there is a response on our normal priority queue. We will pull off - * all QE there are and wake up all the waiters before exiting. We will - * take a spinlock out on the queue before operating on it. - */ - -unsigned int aac_response_normal(struct aac_queue * q) -{ - struct aac_dev * dev = q->dev; - struct aac_entry *entry; - struct hw_fib * hwfib; - struct fib * fib; - int consumed = 0; - unsigned long flags, mflags; - - spin_lock_irqsave(q->lock, flags); - /* - * Keep pulling response QEs off the response queue and waking - * up the waiters until there are no more QEs. We then return - * back to the system. If no response was requesed we just - * deallocate the Fib here and continue. - */ - while(aac_consumer_get(dev, q, &entry)) - { - int fast; - u32 index = le32_to_cpu(entry->addr); - fast = index & 0x01; - fib = &dev->fibs[index >> 2]; - hwfib = fib->hw_fib_va; - - aac_consumer_free(dev, q, HostNormRespQueue); - /* - * Remove this fib from the Outstanding I/O queue. - * But only if it has not already been timed out. - * - * If the fib has been timed out already, then just - * continue. The caller has already been notified that - * the fib timed out. - */ - dev->queues->queue[AdapNormCmdQueue].numpending--; - - if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { - spin_unlock_irqrestore(q->lock, flags); - aac_fib_complete(fib); - aac_fib_free(fib); - spin_lock_irqsave(q->lock, flags); - continue; - } - spin_unlock_irqrestore(q->lock, flags); - - if (fast) { - /* - * Doctor the fib - */ - *(__le32 *)hwfib->data = cpu_to_le32(ST_OK); - hwfib->header.XferState |= cpu_to_le32(AdapterProcessed); - } - - FIB_COUNTER_INCREMENT(aac_config.FibRecved); - - if (hwfib->header.Command == cpu_to_le16(NuFileSystem)) - { - __le32 *pstatus = (__le32 *)hwfib->data; - if (*pstatus & cpu_to_le32(0xffff0000)) - *pstatus = cpu_to_le32(ST_OK); - } - if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) - { - if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected)) - FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved); - else - FIB_COUNTER_INCREMENT(aac_config.AsyncRecved); - /* - * NOTE: we cannot touch the fib after this - * call, because it may have been deallocated. - */ - fib->flags = 0; - fib->callback(fib->callback_data, fib); - } else { - unsigned long flagv; - spin_lock_irqsave(&fib->event_lock, flagv); - if (!fib->done) { - fib->done = 1; - up(&fib->event_wait); - } - spin_unlock_irqrestore(&fib->event_lock, flagv); - - spin_lock_irqsave(&dev->manage_lock, mflags); - dev->management_fib_count--; - spin_unlock_irqrestore(&dev->manage_lock, mflags); - - FIB_COUNTER_INCREMENT(aac_config.NormalRecved); - if (fib->done == 2) { - spin_lock_irqsave(&fib->event_lock, flagv); - fib->done = 0; - spin_unlock_irqrestore(&fib->event_lock, flagv); - aac_fib_complete(fib); - aac_fib_free(fib); - } - } - consumed++; - spin_lock_irqsave(q->lock, flags); - } - - if (consumed > aac_config.peak_fibs) - aac_config.peak_fibs = consumed; - if (consumed == 0) - aac_config.zero_fibs++; - - spin_unlock_irqrestore(q->lock, flags); - return 0; -} - - -/** - * aac_command_normal - handle commands - * @q: queue to process - * - * This DPC routine will be queued when the adapter interrupts us to - * let us know there is a command on our normal priority queue. We will - * pull off all QE there are and wake up all the waiters before exiting. - * We will take a spinlock out on the queue before operating on it. - */ - -unsigned int aac_command_normal(struct aac_queue *q) -{ - struct aac_dev * dev = q->dev; - struct aac_entry *entry; - unsigned long flags; - - spin_lock_irqsave(q->lock, flags); - - /* - * Keep pulling response QEs off the response queue and waking - * up the waiters until there are no more QEs. We then return - * back to the system. - */ - while(aac_consumer_get(dev, q, &entry)) - { - struct fib fibctx; - struct hw_fib * hw_fib; - u32 index; - struct fib *fib = &fibctx; - - index = le32_to_cpu(entry->addr) / sizeof(struct hw_fib); - hw_fib = &dev->aif_base_va[index]; - - /* - * Allocate a FIB at all costs. For non queued stuff - * we can just use the stack so we are happy. We need - * a fib object in order to manage the linked lists - */ - if (dev->aif_thread) - if((fib = kmalloc(sizeof(struct fib), GFP_ATOMIC)) == NULL) - fib = &fibctx; - - memset(fib, 0, sizeof(struct fib)); - INIT_LIST_HEAD(&fib->fiblink); - fib->type = FSAFS_NTC_FIB_CONTEXT; - fib->size = sizeof(struct fib); - fib->hw_fib_va = hw_fib; - fib->data = hw_fib->data; - fib->dev = dev; - - - if (dev->aif_thread && fib != &fibctx) { - list_add_tail(&fib->fiblink, &q->cmdq); - aac_consumer_free(dev, q, HostNormCmdQueue); - wake_up_interruptible(&q->cmdready); - } else { - aac_consumer_free(dev, q, HostNormCmdQueue); - spin_unlock_irqrestore(q->lock, flags); - /* - * Set the status of this FIB - */ - *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); - aac_fib_adapter_complete(fib, sizeof(u32)); - spin_lock_irqsave(q->lock, flags); - } - } - spin_unlock_irqrestore(q->lock, flags); - return 0; -} - -/* - * - * aac_aif_callback - * @context: the context set in the fib - here it is scsi cmd - * @fibptr: pointer to the fib - * - * Handles the AIFs - new method (SRC) - * - */ - -static void aac_aif_callback(void *context, struct fib * fibptr) -{ - struct fib *fibctx; - struct aac_dev *dev; - struct aac_aifcmd *cmd; - int status; - - fibctx = (struct fib *)context; - BUG_ON(fibptr == NULL); - dev = fibptr->dev; - - if (fibptr->hw_fib_va->header.XferState & - cpu_to_le32(NoMoreAifDataAvailable)) { - aac_fib_complete(fibptr); - aac_fib_free(fibptr); - return; - } - - aac_intr_normal(dev, 0, 1, 0, fibptr->hw_fib_va); - - aac_fib_init(fibctx); - cmd = (struct aac_aifcmd *) fib_data(fibctx); - cmd->command = cpu_to_le32(AifReqEvent); - - status = aac_fib_send(AifRequest, - fibctx, - sizeof(struct hw_fib)-sizeof(struct aac_fibhdr), - FsaNormal, - 0, 1, - (fib_callback)aac_aif_callback, fibctx); -} - - -/** - * aac_intr_normal - Handle command replies - * @dev: Device - * @index: completion reference - * - * This DPC routine will be run when the adapter interrupts us to let us - * know there is a response on our normal priority queue. We will pull off - * all QE there are and wake up all the waiters before exiting. - */ -unsigned int aac_intr_normal(struct aac_dev *dev, u32 index, - int isAif, int isFastResponse, struct hw_fib *aif_fib) -{ - unsigned long mflags; - dprintk((KERN_INFO "aac_intr_normal(%p,%x)\n", dev, index)); - if (isAif == 1) { /* AIF - common */ - struct hw_fib * hw_fib; - struct fib * fib; - struct aac_queue *q = &dev->queues->queue[HostNormCmdQueue]; - unsigned long flags; - - /* - * Allocate a FIB. For non queued stuff we can just use - * the stack so we are happy. We need a fib object in order to - * manage the linked lists. - */ - if ((!dev->aif_thread) - || (!(fib = kzalloc(sizeof(struct fib),GFP_ATOMIC)))) - return 1; - if (!(hw_fib = kzalloc(sizeof(struct hw_fib),GFP_ATOMIC))) { - kfree (fib); - return 1; - } - if (aif_fib != NULL) { - memcpy(hw_fib, aif_fib, sizeof(struct hw_fib)); - } else { - memcpy(hw_fib, - (struct hw_fib *)(((uintptr_t)(dev->regs.sa)) + - index), sizeof(struct hw_fib)); - } - INIT_LIST_HEAD(&fib->fiblink); - fib->type = FSAFS_NTC_FIB_CONTEXT; - fib->size = sizeof(struct fib); - fib->hw_fib_va = hw_fib; - fib->data = hw_fib->data; - fib->dev = dev; - - spin_lock_irqsave(q->lock, flags); - list_add_tail(&fib->fiblink, &q->cmdq); - wake_up_interruptible(&q->cmdready); - spin_unlock_irqrestore(q->lock, flags); - return 1; - } else if (isAif == 2) { /* AIF - new (SRC) */ - struct fib *fibctx; - struct aac_aifcmd *cmd; - - fibctx = aac_fib_alloc(dev); - if (!fibctx) - return 1; - aac_fib_init(fibctx); - - cmd = (struct aac_aifcmd *) fib_data(fibctx); - cmd->command = cpu_to_le32(AifReqEvent); - - return aac_fib_send(AifRequest, - fibctx, - sizeof(struct hw_fib)-sizeof(struct aac_fibhdr), - FsaNormal, - 0, 1, - (fib_callback)aac_aif_callback, fibctx); - } else { - struct fib *fib = &dev->fibs[index]; - struct hw_fib * hwfib = fib->hw_fib_va; - - /* - * Remove this fib from the Outstanding I/O queue. - * But only if it has not already been timed out. - * - * If the fib has been timed out already, then just - * continue. The caller has already been notified that - * the fib timed out. - */ - dev->queues->queue[AdapNormCmdQueue].numpending--; - - if (unlikely(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { - aac_fib_complete(fib); - aac_fib_free(fib); - return 0; - } - - if (isFastResponse) { - /* - * Doctor the fib - */ - *(__le32 *)hwfib->data = cpu_to_le32(ST_OK); - hwfib->header.XferState |= cpu_to_le32(AdapterProcessed); - } - - FIB_COUNTER_INCREMENT(aac_config.FibRecved); - - if (hwfib->header.Command == cpu_to_le16(NuFileSystem)) - { - __le32 *pstatus = (__le32 *)hwfib->data; - if (*pstatus & cpu_to_le32(0xffff0000)) - *pstatus = cpu_to_le32(ST_OK); - } - if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) - { - if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected)) - FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved); - else - FIB_COUNTER_INCREMENT(aac_config.AsyncRecved); - /* - * NOTE: we cannot touch the fib after this - * call, because it may have been deallocated. - */ - fib->flags = 0; - fib->callback(fib->callback_data, fib); - } else { - unsigned long flagv; - dprintk((KERN_INFO "event_wait up\n")); - spin_lock_irqsave(&fib->event_lock, flagv); - if (!fib->done) { - fib->done = 1; - up(&fib->event_wait); - } - spin_unlock_irqrestore(&fib->event_lock, flagv); - - spin_lock_irqsave(&dev->manage_lock, mflags); - dev->management_fib_count--; - spin_unlock_irqrestore(&dev->manage_lock, mflags); - - FIB_COUNTER_INCREMENT(aac_config.NormalRecved); - if (fib->done == 2) { - spin_lock_irqsave(&fib->event_lock, flagv); - fib->done = 0; - spin_unlock_irqrestore(&fib->event_lock, flagv); - aac_fib_complete(fib); - aac_fib_free(fib); - } - - } - return 0; - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/linit.c b/ANDROID_3.4.5/drivers/scsi/aacraid/linit.c deleted file mode 100644 index 0d279c44..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/linit.c +++ /dev/null @@ -1,1366 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * linit.c - * - * Abstract: Linux Driver entry module for Adaptec RAID Array Controller - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "aacraid.h" - -#define AAC_DRIVER_VERSION "1.2-0" -#ifndef AAC_DRIVER_BRANCH -#define AAC_DRIVER_BRANCH "" -#endif -#define AAC_DRIVERNAME "aacraid" - -#ifdef AAC_DRIVER_BUILD -#define _str(x) #x -#define str(x) _str(x) -#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION "[" str(AAC_DRIVER_BUILD) "]" AAC_DRIVER_BRANCH -#else -#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION AAC_DRIVER_BRANCH -#endif - -MODULE_AUTHOR("Red Hat Inc and Adaptec"); -MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, " - "Adaptec Advanced Raid Products, " - "HP NetRAID-4M, IBM ServeRAID & ICP SCSI driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(AAC_DRIVER_FULL_VERSION); - -static DEFINE_MUTEX(aac_mutex); -static LIST_HEAD(aac_devices); -static int aac_cfg_major = -1; -char aac_driver_version[] = AAC_DRIVER_FULL_VERSION; - -/* - * Because of the way Linux names scsi devices, the order in this table has - * become important. Check for on-board Raid first, add-in cards second. - * - * Note: The last field is used to index into aac_drivers below. - */ -#ifdef DECLARE_PCI_DEVICE_TABLE -static DECLARE_PCI_DEVICE_TABLE(aac_pci_tbl) = { -#elif defined(__devinitconst) -static const struct pci_device_id aac_pci_tbl[] __devinitconst = { -#else -static const struct pci_device_id aac_pci_tbl[] __devinitdata = { -#endif - { 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */ - { 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */ - { 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si (SlimFast/PERC3Si */ - { 0x1028, 0x0004, 0x1028, 0x00d0, 0, 0, 3 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ - { 0x1028, 0x0002, 0x1028, 0x00d1, 0, 0, 4 }, /* PERC 3/Di (Viper/PERC3DiV) */ - { 0x1028, 0x0002, 0x1028, 0x00d9, 0, 0, 5 }, /* PERC 3/Di (Lexus/PERC3DiL) */ - { 0x1028, 0x000a, 0x1028, 0x0106, 0, 0, 6 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ - { 0x1028, 0x000a, 0x1028, 0x011b, 0, 0, 7 }, /* PERC 3/Di (Dagger/PERC3DiD) */ - { 0x1028, 0x000a, 0x1028, 0x0121, 0, 0, 8 }, /* PERC 3/Di (Boxster/PERC3DiB) */ - { 0x9005, 0x0283, 0x9005, 0x0283, 0, 0, 9 }, /* catapult */ - { 0x9005, 0x0284, 0x9005, 0x0284, 0, 0, 10 }, /* tomcat */ - { 0x9005, 0x0285, 0x9005, 0x0286, 0, 0, 11 }, /* Adaptec 2120S (Crusader) */ - { 0x9005, 0x0285, 0x9005, 0x0285, 0, 0, 12 }, /* Adaptec 2200S (Vulcan) */ - { 0x9005, 0x0285, 0x9005, 0x0287, 0, 0, 13 }, /* Adaptec 2200S (Vulcan-2m) */ - { 0x9005, 0x0285, 0x17aa, 0x0286, 0, 0, 14 }, /* Legend S220 (Legend Crusader) */ - { 0x9005, 0x0285, 0x17aa, 0x0287, 0, 0, 15 }, /* Legend S230 (Legend Vulcan) */ - - { 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier) */ - { 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado) */ - { 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */ - { 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */ - { 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 20 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ - { 0x9005, 0x0286, 0x9005, 0x028d, 0, 0, 21 }, /* ASR-2130S (Lancer) */ - { 0x9005, 0x0286, 0x9005, 0x029b, 0, 0, 22 }, /* AAR-2820SA (Intruder) */ - { 0x9005, 0x0286, 0x9005, 0x029c, 0, 0, 23 }, /* AAR-2620SA (Intruder) */ - { 0x9005, 0x0286, 0x9005, 0x029d, 0, 0, 24 }, /* AAR-2420SA (Intruder) */ - { 0x9005, 0x0286, 0x9005, 0x029e, 0, 0, 25 }, /* ICP9024RO (Lancer) */ - { 0x9005, 0x0286, 0x9005, 0x029f, 0, 0, 26 }, /* ICP9014RO (Lancer) */ - { 0x9005, 0x0286, 0x9005, 0x02a0, 0, 0, 27 }, /* ICP9047MA (Lancer) */ - { 0x9005, 0x0286, 0x9005, 0x02a1, 0, 0, 28 }, /* ICP9087MA (Lancer) */ - { 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5445AU (Hurricane44) */ - { 0x9005, 0x0285, 0x9005, 0x02a4, 0, 0, 30 }, /* ICP9085LI (Marauder-X) */ - { 0x9005, 0x0285, 0x9005, 0x02a5, 0, 0, 31 }, /* ICP5085BR (Marauder-E) */ - { 0x9005, 0x0286, 0x9005, 0x02a6, 0, 0, 32 }, /* ICP9067MA (Intruder-6) */ - { 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 33 }, /* Themisto Jupiter Platform */ - { 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 33 }, /* Themisto Jupiter Platform */ - { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 34 }, /* Callisto Jupiter Platform */ - { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 35 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ - { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 36 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ - { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 37 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ - { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 38 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ - { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 39 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ - { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 40 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ - { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */ - { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */ - { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005 */ - { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */ - { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */ - { 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */ - { 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */ - { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000 (BlackBird) */ - { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */ - { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */ - { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-3800 (Hurricane44) */ - - { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/ - { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 54 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 55 }, /* Dell PERC2/QC */ - { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 56 }, /* HP NetRAID-4M */ - - { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 57 }, /* Dell Catchall */ - { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 58 }, /* Legend Catchall */ - { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */ - { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */ - { 0x9005, 0x0288, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 61 }, /* Adaptec NEMER/ARK Catch All */ - { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Series 6 (Tupelo) */ - { 0x9005, 0x028c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 63 }, /* Adaptec PMC Series 7 (Denali) */ - { 0x9005, 0x028d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 64 }, /* Adaptec PMC Series 8 */ - { 0x9005, 0x028f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 65 }, /* Adaptec PMC Series 9 */ - { 0,} -}; -MODULE_DEVICE_TABLE(pci, aac_pci_tbl); - -/* - * dmb - For now we add the number of channels to this structure. - * In the future we should add a fib that reports the number of channels - * for the card. At that time we can remove the channels from here - */ -static struct aac_driver_ident aac_drivers[] = { - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 2/Si (Iguana/PERC2Si) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Opal/PERC3Di) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Si (SlimFast/PERC3Si */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Viper/PERC3DiV) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Lexus/PERC3DiL) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Dagger/PERC3DiD) */ - { aac_rx_init, "percraid", "DELL ", "PERCRAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* PERC 3/Di (Boxster/PERC3DiB) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "catapult ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* catapult */ - { aac_rx_init, "aacraid", "ADAPTEC ", "tomcat ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* tomcat */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2120S ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 2200S ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Adaptec 2200S (Vulcan-2m) */ - { aac_rx_init, "aacraid", "Legend ", "Legend S220 ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S220 (Legend Crusader) */ - { aac_rx_init, "aacraid", "Legend ", "Legend S230 ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend S230 (Legend Vulcan) */ - - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3230S ", 2 }, /* Adaptec 3230S (Harrier) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "Adaptec 3240S ", 2 }, /* Adaptec 3240S (Tornado) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020ZCR ", 2 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025ZCR ", 2 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-2130S PCI-X ", 1 }, /* ASR-2130S (Lancer) */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2820SA ", 1 }, /* AAR-2820SA (Intruder) */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2620SA ", 1 }, /* AAR-2620SA (Intruder) */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "AAR-2420SA ", 1 }, /* AAR-2420SA (Intruder) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9024RO ", 2 }, /* ICP9024RO (Lancer) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9014RO ", 1 }, /* ICP9014RO (Lancer) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9047MA ", 1 }, /* ICP9047MA (Lancer) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9087MA ", 1 }, /* ICP9087MA (Lancer) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP5445AU ", 1 }, /* ICP5445AU (Hurricane44) */ - { aac_rx_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */ - { aac_rx_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9067MA ", 1 }, /* ICP9067MA (Intruder-6) */ - { NULL , "aacraid", "ADAPTEC ", "Themisto ", 0, AAC_QUIRK_SLAVE }, /* Jupiter Platform */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2025SA ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2410SA SATA ", 1, AAC_QUIRK_17SG }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ - { aac_rx_init, "aacraid", "DELL ", "CERC SR2 ", 1, AAC_QUIRK_17SG }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2810SA SATA ", 1, AAC_QUIRK_17SG }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-21610SA SATA", 1, AAC_QUIRK_17SG }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2026ZCR ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "AAR-2610SA ", 1 }, /* SATA 6Ch (Bearcat) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005 ", 1 }, /* ASR-4005 */ - { aac_rx_init, "ServeRAID","IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */ - { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */ - { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000 ", 1 }, /* ASR-4000 (BlackBird & AvonPark) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-3800 ", 1 }, /* ASR-3800 (Hurricane44) */ - - { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/ - { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ - { aac_sa_init, "aacraid", "ADAPTEC ", "AAC-364 ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ - { aac_sa_init, "percraid", "DELL ", "PERCRAID ", 4, AAC_QUIRK_34SG }, /* Dell PERC2/QC */ - { aac_sa_init, "hpnraid", "HP ", "NetRAID ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */ - - { aac_rx_init, "aacraid", "DELL ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Dell Catchall */ - { aac_rx_init, "aacraid", "Legend ", "RAID ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG | AAC_QUIRK_SCSI_32 }, /* Legend Catchall */ - { aac_rx_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Catch All */ - { aac_rkt_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec Rocket Catch All */ - { aac_nark_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec NEMER/ARK Catch All */ - { aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 6 (Tupelo) */ - { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 7 (Denali) */ - { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 }, /* Adaptec PMC Series 8 */ - { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2 } /* Adaptec PMC Series 9 */ -}; - -/** - * aac_queuecommand - queue a SCSI command - * @cmd: SCSI command to queue - * @done: Function to call on command completion - * - * Queues a command for execution by the associated Host Adapter. - * - * TODO: unify with aac_scsi_cmd(). - */ - -static int aac_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct Scsi_Host *host = cmd->device->host; - struct aac_dev *dev = (struct aac_dev *)host->hostdata; - u32 count = 0; - cmd->scsi_done = done; - for (; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct fib * fib = &dev->fibs[count]; - struct scsi_cmnd * command; - if (fib->hw_fib_va->header.XferState && - ((command = fib->callback_data)) && - (command == cmd) && - (cmd->SCp.phase == AAC_OWNER_FIRMWARE)) - return 0; /* Already owned by Adapter */ - } - cmd->SCp.phase = AAC_OWNER_LOWLEVEL; - return (aac_scsi_cmd(cmd) ? FAILED : 0); -} - -static DEF_SCSI_QCMD(aac_queuecommand) - -/** - * aac_info - Returns the host adapter name - * @shost: Scsi host to report on - * - * Returns a static string describing the device in question - */ - -static const char *aac_info(struct Scsi_Host *shost) -{ - struct aac_dev *dev = (struct aac_dev *)shost->hostdata; - return aac_drivers[dev->cardtype].name; -} - -/** - * aac_get_driver_ident - * @devtype: index into lookup table - * - * Returns a pointer to the entry in the driver lookup table. - */ - -struct aac_driver_ident* aac_get_driver_ident(int devtype) -{ - return &aac_drivers[devtype]; -} - -/** - * aac_biosparm - return BIOS parameters for disk - * @sdev: The scsi device corresponding to the disk - * @bdev: the block device corresponding to the disk - * @capacity: the sector capacity of the disk - * @geom: geometry block to fill in - * - * Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk. - * The default disk geometry is 64 heads, 32 sectors, and the appropriate - * number of cylinders so as not to exceed drive capacity. In order for - * disks equal to or larger than 1 GB to be addressable by the BIOS - * without exceeding the BIOS limitation of 1024 cylinders, Extended - * Translation should be enabled. With Extended Translation enabled, - * drives between 1 GB inclusive and 2 GB exclusive are given a disk - * geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive - * are given a disk geometry of 255 heads and 63 sectors. However, if - * the BIOS detects that the Extended Translation setting does not match - * the geometry in the partition table, then the translation inferred - * from the partition table will be used by the BIOS, and a warning may - * be displayed. - */ - -static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int *geom) -{ - struct diskparm *param = (struct diskparm *)geom; - unsigned char *buf; - - dprintk((KERN_DEBUG "aac_biosparm.\n")); - - /* - * Assuming extended translation is enabled - #REVISIT# - */ - if (capacity >= 2 * 1024 * 1024) { /* 1 GB in 512 byte sectors */ - if(capacity >= 4 * 1024 * 1024) { /* 2 GB in 512 byte sectors */ - param->heads = 255; - param->sectors = 63; - } else { - param->heads = 128; - param->sectors = 32; - } - } else { - param->heads = 64; - param->sectors = 32; - } - - param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors); - - /* - * Read the first 1024 bytes from the disk device, if the boot - * sector partition table is valid, search for a partition table - * entry whose end_head matches one of the standard geometry - * translations ( 64/32, 128/32, 255/63 ). - */ - buf = scsi_bios_ptable(bdev); - if (!buf) - return 0; - if(*(__le16 *)(buf + 0x40) == cpu_to_le16(0xaa55)) { - struct partition *first = (struct partition * )buf; - struct partition *entry = first; - int saved_cylinders = param->cylinders; - int num; - unsigned char end_head, end_sec; - - for(num = 0; num < 4; num++) { - end_head = entry->end_head; - end_sec = entry->end_sector & 0x3f; - - if(end_head == 63) { - param->heads = 64; - param->sectors = 32; - break; - } else if(end_head == 127) { - param->heads = 128; - param->sectors = 32; - break; - } else if(end_head == 254) { - param->heads = 255; - param->sectors = 63; - break; - } - entry++; - } - - if (num == 4) { - end_head = first->end_head; - end_sec = first->end_sector & 0x3f; - } - - param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors); - if (num < 4 && end_sec == param->sectors) { - if (param->cylinders != saved_cylinders) - dprintk((KERN_DEBUG "Adopting geometry: heads=%d, sectors=%d from partition table %d.\n", - param->heads, param->sectors, num)); - } else if (end_head > 0 || end_sec > 0) { - dprintk((KERN_DEBUG "Strange geometry: heads=%d, sectors=%d in partition table %d.\n", - end_head + 1, end_sec, num)); - dprintk((KERN_DEBUG "Using geometry: heads=%d, sectors=%d.\n", - param->heads, param->sectors)); - } - } - kfree(buf); - return 0; -} - -/** - * aac_slave_configure - compute queue depths - * @sdev: SCSI device we are considering - * - * Selects queue depths for each target device based on the host adapter's - * total capacity and the queue depth supported by the target device. - * A queue depth of one automatically disables tagged queueing. - */ - -static int aac_slave_configure(struct scsi_device *sdev) -{ - struct aac_dev *aac = (struct aac_dev *)sdev->host->hostdata; - if (aac->jbod && (sdev->type == TYPE_DISK)) - sdev->removable = 1; - if ((sdev->type == TYPE_DISK) && - (sdev_channel(sdev) != CONTAINER_CHANNEL) && - (!aac->jbod || sdev->inq_periph_qual) && - (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2))) { - if (expose_physicals == 0) - return -ENXIO; - if (expose_physicals < 0) - sdev->no_uld_attach = 1; - } - if (sdev->tagged_supported && (sdev->type == TYPE_DISK) && - (!aac->raid_scsi_mode || (sdev_channel(sdev) != 2)) && - !sdev->no_uld_attach) { - struct scsi_device * dev; - struct Scsi_Host *host = sdev->host; - unsigned num_lsu = 0; - unsigned num_one = 0; - unsigned depth; - unsigned cid; - - /* - * Firmware has an individual device recovery time typically - * of 35 seconds, give us a margin. - */ - if (sdev->request_queue->rq_timeout < (45 * HZ)) - blk_queue_rq_timeout(sdev->request_queue, 45*HZ); - for (cid = 0; cid < aac->maximum_num_containers; ++cid) - if (aac->fsa_dev[cid].valid) - ++num_lsu; - __shost_for_each_device(dev, host) { - if (dev->tagged_supported && (dev->type == TYPE_DISK) && - (!aac->raid_scsi_mode || - (sdev_channel(sdev) != 2)) && - !dev->no_uld_attach) { - if ((sdev_channel(dev) != CONTAINER_CHANNEL) - || !aac->fsa_dev[sdev_id(dev)].valid) - ++num_lsu; - } else - ++num_one; - } - if (num_lsu == 0) - ++num_lsu; - depth = (host->can_queue - num_one) / num_lsu; - if (depth > 256) - depth = 256; - else if (depth < 2) - depth = 2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth); - } else - scsi_adjust_queue_depth(sdev, 0, 1); - - return 0; -} - -/** - * aac_change_queue_depth - alter queue depths - * @sdev: SCSI device we are considering - * @depth: desired queue depth - * - * Alters queue depths for target device based on the host adapter's - * total capacity and the queue depth supported by the target device. - */ - -static int aac_change_queue_depth(struct scsi_device *sdev, int depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (sdev->tagged_supported && (sdev->type == TYPE_DISK) && - (sdev_channel(sdev) == CONTAINER_CHANNEL)) { - struct scsi_device * dev; - struct Scsi_Host *host = sdev->host; - unsigned num = 0; - - __shost_for_each_device(dev, host) { - if (dev->tagged_supported && (dev->type == TYPE_DISK) && - (sdev_channel(dev) == CONTAINER_CHANNEL)) - ++num; - ++num; - } - if (num >= host->can_queue) - num = host->can_queue - 1; - if (depth > (host->can_queue - num)) - depth = host->can_queue - num; - if (depth > 256) - depth = 256; - else if (depth < 2) - depth = 2; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth); - } else - scsi_adjust_queue_depth(sdev, 0, 1); - return sdev->queue_depth; -} - -static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct aac_dev *aac = (struct aac_dev *)(sdev->host->hostdata); - if (sdev_channel(sdev) != CONTAINER_CHANNEL) - return snprintf(buf, PAGE_SIZE, sdev->no_uld_attach - ? "Hidden\n" : - ((aac->jbod && (sdev->type == TYPE_DISK)) ? "JBOD\n" : "")); - return snprintf(buf, PAGE_SIZE, "%s\n", - get_container_type(aac->fsa_dev[sdev_id(sdev)].type)); -} - -static struct device_attribute aac_raid_level_attr = { - .attr = { - .name = "level", - .mode = S_IRUGO, - }, - .show = aac_show_raid_level -}; - -static struct device_attribute *aac_dev_attrs[] = { - &aac_raid_level_attr, - NULL, -}; - -static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg) -{ - struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - return aac_do_ioctl(dev, cmd, arg); -} - -static int aac_eh_abort(struct scsi_cmnd* cmd) -{ - struct scsi_device * dev = cmd->device; - struct Scsi_Host * host = dev->host; - struct aac_dev * aac = (struct aac_dev *)host->hostdata; - int count; - int ret = FAILED; - - printk(KERN_ERR "%s: Host adapter abort request (%d,%d,%d,%d)\n", - AAC_DRIVERNAME, - host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun); - switch (cmd->cmnd[0]) { - case SERVICE_ACTION_IN: - if (!(aac->raw_io_interface) || - !(aac->raw_io_64) || - ((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16)) - break; - case INQUIRY: - case READ_CAPACITY: - /* Mark associated FIB to not complete, eh handler does this */ - for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct fib * fib = &aac->fibs[count]; - if (fib->hw_fib_va->header.XferState && - (fib->flags & FIB_CONTEXT_FLAG) && - (fib->callback_data == cmd)) { - fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; - cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; - ret = SUCCESS; - } - } - break; - case TEST_UNIT_READY: - /* Mark associated FIB to not complete, eh handler does this */ - for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct scsi_cmnd * command; - struct fib * fib = &aac->fibs[count]; - if ((fib->hw_fib_va->header.XferState & cpu_to_le32(Async | NoResponseExpected)) && - (fib->flags & FIB_CONTEXT_FLAG) && - ((command = fib->callback_data)) && - (command->device == cmd->device)) { - fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; - command->SCp.phase = AAC_OWNER_ERROR_HANDLER; - if (command == cmd) - ret = SUCCESS; - } - } - } - return ret; -} - -/* - * aac_eh_reset - Reset command handling - * @scsi_cmd: SCSI command block causing the reset - * - */ -static int aac_eh_reset(struct scsi_cmnd* cmd) -{ - struct scsi_device * dev = cmd->device; - struct Scsi_Host * host = dev->host; - struct scsi_cmnd * command; - int count; - struct aac_dev * aac = (struct aac_dev *)host->hostdata; - unsigned long flags; - - /* Mark the associated FIB to not complete, eh handler does this */ - for (count = 0; count < (host->can_queue + AAC_NUM_MGT_FIB); ++count) { - struct fib * fib = &aac->fibs[count]; - if (fib->hw_fib_va->header.XferState && - (fib->flags & FIB_CONTEXT_FLAG) && - (fib->callback_data == cmd)) { - fib->flags |= FIB_CONTEXT_FLAG_TIMED_OUT; - cmd->SCp.phase = AAC_OWNER_ERROR_HANDLER; - } - } - printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", - AAC_DRIVERNAME); - - if ((count = aac_check_health(aac))) - return count; - /* - * Wait for all commands to complete to this specific - * target (block maximum 60 seconds). - */ - for (count = 60; count; --count) { - int active = aac->in_reset; - - if (active == 0) - __shost_for_each_device(dev, host) { - spin_lock_irqsave(&dev->list_lock, flags); - list_for_each_entry(command, &dev->cmd_list, list) { - if ((command != cmd) && - (command->SCp.phase == AAC_OWNER_FIRMWARE)) { - active++; - break; - } - } - spin_unlock_irqrestore(&dev->list_lock, flags); - if (active) - break; - - } - /* - * We can exit If all the commands are complete - */ - if (active == 0) - return SUCCESS; - ssleep(1); - } - printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME); - /* - * This adapter needs a blind reset, only do so for Adapters that - * support a register, instead of a commanded, reset. - */ - if (((aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_MU_RESET) || - (aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_DOORBELL_RESET)) && - aac_check_reset && - ((aac_check_reset != 1) || - !(aac->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_IGNORE_RESET))) - aac_reset_adapter(aac, 2); /* Bypass wait for command quiesce */ - return SUCCESS; /* Cause an immediate retry of the command with a ten second delay after successful tur */ -} - -/** - * aac_cfg_open - open a configuration file - * @inode: inode being opened - * @file: file handle attached - * - * Called when the configuration device is opened. Does the needed - * set up on the handle and then returns - * - * Bugs: This needs extending to check a given adapter is present - * so we can support hot plugging, and to ref count adapters. - */ - -static int aac_cfg_open(struct inode *inode, struct file *file) -{ - struct aac_dev *aac; - unsigned minor_number = iminor(inode); - int err = -ENODEV; - - mutex_lock(&aac_mutex); /* BKL pushdown: nothing else protects this list */ - list_for_each_entry(aac, &aac_devices, entry) { - if (aac->id == minor_number) { - file->private_data = aac; - err = 0; - break; - } - } - mutex_unlock(&aac_mutex); - - return err; -} - -/** - * aac_cfg_ioctl - AAC configuration request - * @inode: inode of device - * @file: file handle - * @cmd: ioctl command code - * @arg: argument - * - * Handles a configuration ioctl. Currently this involves wrapping it - * up and feeding it into the nasty windowsalike glue layer. - * - * Bugs: Needs locking against parallel ioctls lower down - * Bugs: Needs to handle hot plugging - */ - -static long aac_cfg_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - int ret; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - mutex_lock(&aac_mutex); - ret = aac_do_ioctl(file->private_data, cmd, (void __user *)arg); - mutex_unlock(&aac_mutex); - - return ret; -} - -#ifdef CONFIG_COMPAT -static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg) -{ - long ret; - mutex_lock(&aac_mutex); - switch (cmd) { - case FSACTL_MINIPORT_REV_CHECK: - case FSACTL_SENDFIB: - case FSACTL_OPEN_GET_ADAPTER_FIB: - case FSACTL_CLOSE_GET_ADAPTER_FIB: - case FSACTL_SEND_RAW_SRB: - case FSACTL_GET_PCI_INFO: - case FSACTL_QUERY_DISK: - case FSACTL_DELETE_DISK: - case FSACTL_FORCE_DELETE_DISK: - case FSACTL_GET_CONTAINERS: - case FSACTL_SEND_LARGE_FIB: - ret = aac_do_ioctl(dev, cmd, (void __user *)arg); - break; - - case FSACTL_GET_NEXT_ADAPTER_FIB: { - struct fib_ioctl __user *f; - - f = compat_alloc_user_space(sizeof(*f)); - ret = 0; - if (clear_user(f, sizeof(*f))) - ret = -EFAULT; - if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32))) - ret = -EFAULT; - if (!ret) - ret = aac_do_ioctl(dev, cmd, f); - break; - } - - default: - ret = -ENOIOCTLCMD; - break; - } - mutex_unlock(&aac_mutex); - return ret; -} - -static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) -{ - struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; - return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg); -} - -static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg) -{ - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - return aac_compat_do_ioctl(file->private_data, cmd, arg); -} -#endif - -static ssize_t aac_show_model(struct device *device, - struct device_attribute *attr, char *buf) -{ - struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; - int len; - - if (dev->supplement_adapter_info.AdapterTypeText[0]) { - char * cp = dev->supplement_adapter_info.AdapterTypeText; - while (*cp && *cp != ' ') - ++cp; - while (*cp == ' ') - ++cp; - len = snprintf(buf, PAGE_SIZE, "%s\n", cp); - } else - len = snprintf(buf, PAGE_SIZE, "%s\n", - aac_drivers[dev->cardtype].model); - return len; -} - -static ssize_t aac_show_vendor(struct device *device, - struct device_attribute *attr, char *buf) -{ - struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; - int len; - - if (dev->supplement_adapter_info.AdapterTypeText[0]) { - char * cp = dev->supplement_adapter_info.AdapterTypeText; - while (*cp && *cp != ' ') - ++cp; - len = snprintf(buf, PAGE_SIZE, "%.*s\n", - (int)(cp - (char *)dev->supplement_adapter_info.AdapterTypeText), - dev->supplement_adapter_info.AdapterTypeText); - } else - len = snprintf(buf, PAGE_SIZE, "%s\n", - aac_drivers[dev->cardtype].vname); - return len; -} - -static ssize_t aac_show_flags(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - int len = 0; - struct aac_dev *dev = (struct aac_dev*)class_to_shost(cdev)->hostdata; - - if (nblank(dprintk(x))) - len = snprintf(buf, PAGE_SIZE, "dprintk\n"); -#ifdef AAC_DETAILED_STATUS_INFO - len += snprintf(buf + len, PAGE_SIZE - len, - "AAC_DETAILED_STATUS_INFO\n"); -#endif - if (dev->raw_io_interface && dev->raw_io_64) - len += snprintf(buf + len, PAGE_SIZE - len, - "SAI_READ_CAPACITY_16\n"); - if (dev->jbod) - len += snprintf(buf + len, PAGE_SIZE - len, "SUPPORTED_JBOD\n"); - if (dev->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_POWER_MANAGEMENT) - len += snprintf(buf + len, PAGE_SIZE - len, - "SUPPORTED_POWER_MANAGEMENT\n"); - if (dev->msi) - len += snprintf(buf + len, PAGE_SIZE - len, "PCI_HAS_MSI\n"); - return len; -} - -static ssize_t aac_show_kernel_version(struct device *device, - struct device_attribute *attr, - char *buf) -{ - struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; - int len, tmp; - - tmp = le32_to_cpu(dev->adapter_info.kernelrev); - len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", - tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff, - le32_to_cpu(dev->adapter_info.kernelbuild)); - return len; -} - -static ssize_t aac_show_monitor_version(struct device *device, - struct device_attribute *attr, - char *buf) -{ - struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; - int len, tmp; - - tmp = le32_to_cpu(dev->adapter_info.monitorrev); - len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", - tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff, - le32_to_cpu(dev->adapter_info.monitorbuild)); - return len; -} - -static ssize_t aac_show_bios_version(struct device *device, - struct device_attribute *attr, - char *buf) -{ - struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; - int len, tmp; - - tmp = le32_to_cpu(dev->adapter_info.biosrev); - len = snprintf(buf, PAGE_SIZE, "%d.%d-%d[%d]\n", - tmp >> 24, (tmp >> 16) & 0xff, tmp & 0xff, - le32_to_cpu(dev->adapter_info.biosbuild)); - return len; -} - -static ssize_t aac_show_serial_number(struct device *device, - struct device_attribute *attr, char *buf) -{ - struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; - int len = 0; - - if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0) - len = snprintf(buf, 16, "%06X\n", - le32_to_cpu(dev->adapter_info.serial[0])); - if (len && - !memcmp(&dev->supplement_adapter_info.MfgPcbaSerialNo[ - sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo)-len], - buf, len-1)) - len = snprintf(buf, 16, "%.*s\n", - (int)sizeof(dev->supplement_adapter_info.MfgPcbaSerialNo), - dev->supplement_adapter_info.MfgPcbaSerialNo); - - return min(len, 16); -} - -static ssize_t aac_show_max_channel(struct device *device, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - class_to_shost(device)->max_channel); -} - -static ssize_t aac_show_max_id(struct device *device, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", - class_to_shost(device)->max_id); -} - -static ssize_t aac_store_reset_adapter(struct device *device, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int retval = -EACCES; - - if (!capable(CAP_SYS_ADMIN)) - return retval; - retval = aac_reset_adapter((struct aac_dev*)class_to_shost(device)->hostdata, buf[0] == '!'); - if (retval >= 0) - retval = count; - return retval; -} - -static ssize_t aac_show_reset_adapter(struct device *device, - struct device_attribute *attr, - char *buf) -{ - struct aac_dev *dev = (struct aac_dev*)class_to_shost(device)->hostdata; - int len, tmp; - - tmp = aac_adapter_check_health(dev); - if ((tmp == 0) && dev->in_reset) - tmp = -EBUSY; - len = snprintf(buf, PAGE_SIZE, "0x%x\n", tmp); - return len; -} - -static struct device_attribute aac_model = { - .attr = { - .name = "model", - .mode = S_IRUGO, - }, - .show = aac_show_model, -}; -static struct device_attribute aac_vendor = { - .attr = { - .name = "vendor", - .mode = S_IRUGO, - }, - .show = aac_show_vendor, -}; -static struct device_attribute aac_flags = { - .attr = { - .name = "flags", - .mode = S_IRUGO, - }, - .show = aac_show_flags, -}; -static struct device_attribute aac_kernel_version = { - .attr = { - .name = "hba_kernel_version", - .mode = S_IRUGO, - }, - .show = aac_show_kernel_version, -}; -static struct device_attribute aac_monitor_version = { - .attr = { - .name = "hba_monitor_version", - .mode = S_IRUGO, - }, - .show = aac_show_monitor_version, -}; -static struct device_attribute aac_bios_version = { - .attr = { - .name = "hba_bios_version", - .mode = S_IRUGO, - }, - .show = aac_show_bios_version, -}; -static struct device_attribute aac_serial_number = { - .attr = { - .name = "serial_number", - .mode = S_IRUGO, - }, - .show = aac_show_serial_number, -}; -static struct device_attribute aac_max_channel = { - .attr = { - .name = "max_channel", - .mode = S_IRUGO, - }, - .show = aac_show_max_channel, -}; -static struct device_attribute aac_max_id = { - .attr = { - .name = "max_id", - .mode = S_IRUGO, - }, - .show = aac_show_max_id, -}; -static struct device_attribute aac_reset = { - .attr = { - .name = "reset_host", - .mode = S_IWUSR|S_IRUGO, - }, - .store = aac_store_reset_adapter, - .show = aac_show_reset_adapter, -}; - -static struct device_attribute *aac_attrs[] = { - &aac_model, - &aac_vendor, - &aac_flags, - &aac_kernel_version, - &aac_monitor_version, - &aac_bios_version, - &aac_serial_number, - &aac_max_channel, - &aac_max_id, - &aac_reset, - NULL -}; - -ssize_t aac_get_serial_number(struct device *device, char *buf) -{ - return aac_show_serial_number(device, &aac_serial_number, buf); -} - -static const struct file_operations aac_cfg_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = aac_cfg_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = aac_compat_cfg_ioctl, -#endif - .open = aac_cfg_open, - .llseek = noop_llseek, -}; - -static struct scsi_host_template aac_driver_template = { - .module = THIS_MODULE, - .name = "AAC", - .proc_name = AAC_DRIVERNAME, - .info = aac_info, - .ioctl = aac_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = aac_compat_ioctl, -#endif - .queuecommand = aac_queuecommand, - .bios_param = aac_biosparm, - .shost_attrs = aac_attrs, - .slave_configure = aac_slave_configure, - .change_queue_depth = aac_change_queue_depth, - .sdev_attrs = aac_dev_attrs, - .eh_abort_handler = aac_eh_abort, - .eh_host_reset_handler = aac_eh_reset, - .can_queue = AAC_NUM_IO_FIB, - .this_id = MAXIMUM_NUM_CONTAINERS, - .sg_tablesize = 16, - .max_sectors = 128, -#if (AAC_NUM_IO_FIB > 256) - .cmd_per_lun = 256, -#else - .cmd_per_lun = AAC_NUM_IO_FIB, -#endif - .use_clustering = ENABLE_CLUSTERING, - .emulated = 1, -}; - -static void __aac_shutdown(struct aac_dev * aac) -{ - if (aac->aif_thread) - kthread_stop(aac->thread); - aac_send_shutdown(aac); - aac_adapter_disable_int(aac); - free_irq(aac->pdev->irq, aac); - if (aac->msi) - pci_disable_msi(aac->pdev); -} - -static int __devinit aac_probe_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - unsigned index = id->driver_data; - struct Scsi_Host *shost; - struct aac_dev *aac; - struct list_head *insert = &aac_devices; - int error = -ENODEV; - int unique_id = 0; - u64 dmamask; - extern int aac_sync_mode; - - list_for_each_entry(aac, &aac_devices, entry) { - if (aac->id > unique_id) - break; - insert = &aac->entry; - unique_id++; - } - - pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 | - PCIE_LINK_STATE_CLKPM); - - error = pci_enable_device(pdev); - if (error) - goto out; - error = -ENODEV; - - /* - * If the quirk31 bit is set, the adapter needs adapter - * to driver communication memory to be allocated below 2gig - */ - if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) - dmamask = DMA_BIT_MASK(31); - else - dmamask = DMA_BIT_MASK(32); - - if (pci_set_dma_mask(pdev, dmamask) || - pci_set_consistent_dma_mask(pdev, dmamask)) - goto out_disable_pdev; - - pci_set_master(pdev); - - shost = scsi_host_alloc(&aac_driver_template, sizeof(struct aac_dev)); - if (!shost) - goto out_disable_pdev; - - shost->irq = pdev->irq; - shost->base = pci_resource_start(pdev, 0); - shost->unique_id = unique_id; - shost->max_cmd_len = 16; - - aac = (struct aac_dev *)shost->hostdata; - aac->scsi_host_ptr = shost; - aac->pdev = pdev; - aac->name = aac_driver_template.name; - aac->id = shost->unique_id; - aac->cardtype = index; - INIT_LIST_HEAD(&aac->entry); - - aac->fibs = kmalloc(sizeof(struct fib) * (shost->can_queue + AAC_NUM_MGT_FIB), GFP_KERNEL); - if (!aac->fibs) - goto out_free_host; - spin_lock_init(&aac->fib_lock); - - /* - * Map in the registers from the adapter. - */ - aac->base_size = AAC_MIN_FOOTPRINT_SIZE; - if ((*aac_drivers[index].init)(aac)) - goto out_unmap; - - if (aac->sync_mode) { - if (aac_sync_mode) - printk(KERN_INFO "%s%d: Sync. mode enforced " - "by driver parameter. This will cause " - "a significant performance decrease!\n", - aac->name, - aac->id); - else - printk(KERN_INFO "%s%d: Async. mode not supported " - "by current driver, sync. mode enforced." - "\nPlease update driver to get full performance.\n", - aac->name, - aac->id); - } - - /* - * Start any kernel threads needed - */ - aac->thread = kthread_run(aac_command_thread, aac, AAC_DRIVERNAME); - if (IS_ERR(aac->thread)) { - printk(KERN_ERR "aacraid: Unable to create command thread.\n"); - error = PTR_ERR(aac->thread); - goto out_deinit; - } - - /* - * If we had set a smaller DMA mask earlier, set it to 4gig - * now since the adapter can dma data to at least a 4gig - * address space. - */ - if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) - goto out_deinit; - - aac->maximum_num_channels = aac_drivers[index].channels; - error = aac_get_adapter_info(aac); - if (error < 0) - goto out_deinit; - - /* - * Lets override negotiations and drop the maximum SG limit to 34 - */ - if ((aac_drivers[index].quirks & AAC_QUIRK_34SG) && - (shost->sg_tablesize > 34)) { - shost->sg_tablesize = 34; - shost->max_sectors = (shost->sg_tablesize * 8) + 112; - } - - if ((aac_drivers[index].quirks & AAC_QUIRK_17SG) && - (shost->sg_tablesize > 17)) { - shost->sg_tablesize = 17; - shost->max_sectors = (shost->sg_tablesize * 8) + 112; - } - - error = pci_set_dma_max_seg_size(pdev, - (aac->adapter_info.options & AAC_OPT_NEW_COMM) ? - (shost->max_sectors << 9) : 65536); - if (error) - goto out_deinit; - - /* - * Firmware printf works only with older firmware. - */ - if (aac_drivers[index].quirks & AAC_QUIRK_34SG) - aac->printf_enabled = 1; - else - aac->printf_enabled = 0; - - /* - * max channel will be the physical channels plus 1 virtual channel - * all containers are on the virtual channel 0 (CONTAINER_CHANNEL) - * physical channels are address by their actual physical number+1 - */ - if (aac->nondasd_support || expose_physicals || aac->jbod) - shost->max_channel = aac->maximum_num_channels; - else - shost->max_channel = 0; - - aac_get_config_status(aac, 0); - aac_get_containers(aac); - list_add(&aac->entry, insert); - - shost->max_id = aac->maximum_num_containers; - if (shost->max_id < aac->maximum_num_physicals) - shost->max_id = aac->maximum_num_physicals; - if (shost->max_id < MAXIMUM_NUM_CONTAINERS) - shost->max_id = MAXIMUM_NUM_CONTAINERS; - else - shost->this_id = shost->max_id; - - /* - * dmb - we may need to move the setting of these parms somewhere else once - * we get a fib that can report the actual numbers - */ - shost->max_lun = AAC_MAX_LUN; - - pci_set_drvdata(pdev, shost); - - error = scsi_add_host(shost, &pdev->dev); - if (error) - goto out_deinit; - scsi_scan_host(shost); - - return 0; - - out_deinit: - __aac_shutdown(aac); - out_unmap: - aac_fib_map_free(aac); - if (aac->comm_addr) - pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, - aac->comm_phys); - kfree(aac->queues); - aac_adapter_ioremap(aac, 0); - kfree(aac->fibs); - kfree(aac->fsa_dev); - out_free_host: - scsi_host_put(shost); - out_disable_pdev: - pci_disable_device(pdev); - out: - return error; -} - -static void aac_shutdown(struct pci_dev *dev) -{ - struct Scsi_Host *shost = pci_get_drvdata(dev); - scsi_block_requests(shost); - __aac_shutdown((struct aac_dev *)shost->hostdata); -} - -static void __devexit aac_remove_one(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct aac_dev *aac = (struct aac_dev *)shost->hostdata; - - scsi_remove_host(shost); - - __aac_shutdown(aac); - aac_fib_map_free(aac); - pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, - aac->comm_phys); - kfree(aac->queues); - - aac_adapter_ioremap(aac, 0); - - kfree(aac->fibs); - kfree(aac->fsa_dev); - - list_del(&aac->entry); - scsi_host_put(shost); - pci_disable_device(pdev); - if (list_empty(&aac_devices)) { - unregister_chrdev(aac_cfg_major, "aac"); - aac_cfg_major = -1; - } -} - -static struct pci_driver aac_pci_driver = { - .name = AAC_DRIVERNAME, - .id_table = aac_pci_tbl, - .probe = aac_probe_one, - .remove = __devexit_p(aac_remove_one), - .shutdown = aac_shutdown, -}; - -static int __init aac_init(void) -{ - int error; - - printk(KERN_INFO "Adaptec %s driver %s\n", - AAC_DRIVERNAME, aac_driver_version); - - error = pci_register_driver(&aac_pci_driver); - if (error < 0) - return error; - - aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops); - if (aac_cfg_major < 0) { - printk(KERN_WARNING - "aacraid: unable to register \"aac\" device.\n"); - } - - return 0; -} - -static void __exit aac_exit(void) -{ - if (aac_cfg_major > -1) - unregister_chrdev(aac_cfg_major, "aac"); - pci_unregister_driver(&aac_pci_driver); -} - -module_init(aac_init); -module_exit(aac_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/nark.c b/ANDROID_3.4.5/drivers/scsi/aacraid/nark.c deleted file mode 100644 index f397d21a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/nark.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * nark.c - * - * Abstract: Hardware Device Interface for NEMER/ARK - * - */ - -#include -#include - -#include - -#include "aacraid.h" - -/** - * aac_nark_ioremap - * @size: mapping resize request - * - */ -static int aac_nark_ioremap(struct aac_dev * dev, u32 size) -{ - if (!size) { - iounmap(dev->regs.rx); - dev->regs.rx = NULL; - iounmap(dev->base); - dev->base = NULL; - return 0; - } - dev->scsi_host_ptr->base = pci_resource_start(dev->pdev, 2); - dev->regs.rx = ioremap((u64)pci_resource_start(dev->pdev, 0) | - ((u64)pci_resource_start(dev->pdev, 1) << 32), - sizeof(struct rx_registers) - sizeof(struct rx_inbound)); - dev->base = NULL; - if (dev->regs.rx == NULL) - return -1; - dev->base = ioremap(dev->scsi_host_ptr->base, size); - if (dev->base == NULL) { - iounmap(dev->regs.rx); - dev->regs.rx = NULL; - return -1; - } - dev->IndexRegs = &((struct rx_registers __iomem *)dev->base)->IndexRegs; - return 0; -} - -/** - * aac_nark_init - initialize an NEMER/ARK Split Bar card - * @dev: device to configure - * - */ - -int aac_nark_init(struct aac_dev * dev) -{ - /* - * Fill in the function dispatch table. - */ - dev->a_ops.adapter_ioremap = aac_nark_ioremap; - dev->a_ops.adapter_comm = aac_rx_select_comm; - - return _aac_rx_init(dev); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/rkt.c b/ANDROID_3.4.5/drivers/scsi/aacraid/rkt.c deleted file mode 100644 index be44de92..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/rkt.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * rkt.c - * - * Abstract: Hardware miniport for Drawbridge specific hardware functions. - * - */ - -#include - -#include - -#include "aacraid.h" - -#define AAC_NUM_IO_FIB_RKT (246 - AAC_NUM_MGT_FIB) - -/** - * aac_rkt_select_comm - Select communications method - * @dev: Adapter - * @comm: communications method - */ - -static int aac_rkt_select_comm(struct aac_dev *dev, int comm) -{ - int retval; - retval = aac_rx_select_comm(dev, comm); - if (comm == AAC_COMM_MESSAGE) { - /* - * FIB Setup has already been done, but we can minimize the - * damage by at least ensuring the OS never issues more - * commands than we can handle. The Rocket adapters currently - * can only handle 246 commands and 8 AIFs at the same time, - * and in fact do notify us accordingly if we negotiate the - * FIB size. The problem that causes us to add this check is - * to ensure that we do not overdo it with the adapter when a - * hard coded FIB override is being utilized. This special - * case warrants this half baked, but convenient, check here. - */ - if (dev->scsi_host_ptr->can_queue > AAC_NUM_IO_FIB_RKT) { - dev->init->MaxIoCommands = - cpu_to_le32(AAC_NUM_IO_FIB_RKT + AAC_NUM_MGT_FIB); - dev->scsi_host_ptr->can_queue = AAC_NUM_IO_FIB_RKT; - } - } - return retval; -} - -/** - * aac_rkt_ioremap - * @size: mapping resize request - * - */ -static int aac_rkt_ioremap(struct aac_dev * dev, u32 size) -{ - if (!size) { - iounmap(dev->regs.rkt); - return 0; - } - dev->base = dev->regs.rkt = ioremap(dev->scsi_host_ptr->base, size); - if (dev->base == NULL) - return -1; - dev->IndexRegs = &dev->regs.rkt->IndexRegs; - return 0; -} - -/** - * aac_rkt_init - initialize an i960 based AAC card - * @dev: device to configure - * - * Allocate and set up resources for the i960 based AAC variants. The - * device_interface in the commregion will be allocated and linked - * to the comm region. - */ - -int aac_rkt_init(struct aac_dev *dev) -{ - /* - * Fill in the function dispatch table. - */ - dev->a_ops.adapter_ioremap = aac_rkt_ioremap; - dev->a_ops.adapter_comm = aac_rkt_select_comm; - - return _aac_rx_init(dev); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/rx.c b/ANDROID_3.4.5/drivers/scsi/aacraid/rx.c deleted file mode 100644 index b029c7cc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/rx.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * rx.c - * - * Abstract: Hardware miniport for Drawbridge specific hardware functions. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "aacraid.h" - -static irqreturn_t aac_rx_intr_producer(int irq, void *dev_id) -{ - struct aac_dev *dev = dev_id; - unsigned long bellbits; - u8 intstat = rx_readb(dev, MUnit.OISR); - - /* - * Read mask and invert because drawbridge is reversed. - * This allows us to only service interrupts that have - * been enabled. - * Check to see if this is our interrupt. If it isn't just return - */ - if (likely(intstat & ~(dev->OIMR))) { - bellbits = rx_readl(dev, OutboundDoorbellReg); - if (unlikely(bellbits & DoorBellPrintfReady)) { - aac_printf(dev, readl (&dev->IndexRegs->Mailbox[5])); - rx_writel(dev, MUnit.ODR,DoorBellPrintfReady); - rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone); - } - else if (unlikely(bellbits & DoorBellAdapterNormCmdReady)) { - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady); - aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); - } - else if (likely(bellbits & DoorBellAdapterNormRespReady)) { - rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady); - aac_response_normal(&dev->queues->queue[HostNormRespQueue]); - } - else if (unlikely(bellbits & DoorBellAdapterNormCmdNotFull)) { - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); - } - else if (unlikely(bellbits & DoorBellAdapterNormRespNotFull)) { - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull); - rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull); - } - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -static irqreturn_t aac_rx_intr_message(int irq, void *dev_id) -{ - int isAif, isFastResponse, isSpecial; - struct aac_dev *dev = dev_id; - u32 Index = rx_readl(dev, MUnit.OutboundQueue); - if (unlikely(Index == 0xFFFFFFFFL)) - Index = rx_readl(dev, MUnit.OutboundQueue); - if (likely(Index != 0xFFFFFFFFL)) { - do { - isAif = isFastResponse = isSpecial = 0; - if (Index & 0x00000002L) { - isAif = 1; - if (Index == 0xFFFFFFFEL) - isSpecial = 1; - Index &= ~0x00000002L; - } else { - if (Index & 0x00000001L) - isFastResponse = 1; - Index >>= 2; - } - if (!isSpecial) { - if (unlikely(aac_intr_normal(dev, - Index, isAif, - isFastResponse, NULL))) { - rx_writel(dev, - MUnit.OutboundQueue, - Index); - rx_writel(dev, - MUnit.ODR, - DoorBellAdapterNormRespReady); - } - } - Index = rx_readl(dev, MUnit.OutboundQueue); - } while (Index != 0xFFFFFFFFL); - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -/** - * aac_rx_disable_interrupt - Disable interrupts - * @dev: Adapter - */ - -static void aac_rx_disable_interrupt(struct aac_dev *dev) -{ - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); -} - -/** - * aac_rx_enable_interrupt_producer - Enable interrupts - * @dev: Adapter - */ - -static void aac_rx_enable_interrupt_producer(struct aac_dev *dev) -{ - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); -} - -/** - * aac_rx_enable_interrupt_message - Enable interrupts - * @dev: Adapter - */ - -static void aac_rx_enable_interrupt_message(struct aac_dev *dev) -{ - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xf7); -} - -/** - * rx_sync_cmd - send a command and wait - * @dev: Adapter - * @command: Command to execute - * @p1: first parameter - * @ret: adapter status - * - * This routine will send a synchronous command to the adapter and wait - * for its completion. - */ - -static int rx_sync_cmd(struct aac_dev *dev, u32 command, - u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, - u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) -{ - unsigned long start; - int ok; - /* - * Write the command into Mailbox 0 - */ - writel(command, &dev->IndexRegs->Mailbox[0]); - /* - * Write the parameters into Mailboxes 1 - 6 - */ - writel(p1, &dev->IndexRegs->Mailbox[1]); - writel(p2, &dev->IndexRegs->Mailbox[2]); - writel(p3, &dev->IndexRegs->Mailbox[3]); - writel(p4, &dev->IndexRegs->Mailbox[4]); - /* - * Clear the synch command doorbell to start on a clean slate. - */ - rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); - /* - * Disable doorbell interrupts - */ - rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); - /* - * Force the completion of the mask register write before issuing - * the interrupt. - */ - rx_readb (dev, MUnit.OIMR); - /* - * Signal that there is a new synch command - */ - rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0); - - ok = 0; - start = jiffies; - - /* - * Wait up to 30 seconds - */ - while (time_before(jiffies, start+30*HZ)) - { - udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ - /* - * Mon960 will set doorbell0 bit when it has completed the command. - */ - if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { - /* - * Clear the doorbell. - */ - rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); - ok = 1; - break; - } - /* - * Yield the processor in case we are slow - */ - msleep(1); - } - if (unlikely(ok != 1)) { - /* - * Restore interrupt mask even though we timed out - */ - aac_adapter_enable_int(dev); - return -ETIMEDOUT; - } - /* - * Pull the synch status from Mailbox 0. - */ - if (status) - *status = readl(&dev->IndexRegs->Mailbox[0]); - if (r1) - *r1 = readl(&dev->IndexRegs->Mailbox[1]); - if (r2) - *r2 = readl(&dev->IndexRegs->Mailbox[2]); - if (r3) - *r3 = readl(&dev->IndexRegs->Mailbox[3]); - if (r4) - *r4 = readl(&dev->IndexRegs->Mailbox[4]); - /* - * Clear the synch command doorbell. - */ - rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); - /* - * Restore interrupt mask - */ - aac_adapter_enable_int(dev); - return 0; - -} - -/** - * aac_rx_interrupt_adapter - interrupt adapter - * @dev: Adapter - * - * Send an interrupt to the i960 and breakpoint it. - */ - -static void aac_rx_interrupt_adapter(struct aac_dev *dev) -{ - rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); -} - -/** - * aac_rx_notify_adapter - send an event to the adapter - * @dev: Adapter - * @event: Event to send - * - * Notify the i960 that something it probably cares about has - * happened. - */ - -static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event) -{ - switch (event) { - - case AdapNormCmdQue: - rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1); - break; - case HostNormRespNotFull: - rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4); - break; - case AdapNormRespQue: - rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2); - break; - case HostNormCmdNotFull: - rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3); - break; - case HostShutdown: - break; - case FastIo: - rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6); - break; - case AdapPrintfDone: - rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5); - break; - default: - BUG(); - break; - } -} - -/** - * aac_rx_start_adapter - activate adapter - * @dev: Adapter - * - * Start up processing on an i960 based AAC adapter - */ - -static void aac_rx_start_adapter(struct aac_dev *dev) -{ - struct aac_init *init; - - init = dev->init; - init->HostElapsedSeconds = cpu_to_le32(get_seconds()); - // We can only use a 32 bit address here - rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, - 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); -} - -/** - * aac_rx_check_health - * @dev: device to check if healthy - * - * Will attempt to determine if the specified adapter is alive and - * capable of handling requests, returning 0 if alive. - */ -static int aac_rx_check_health(struct aac_dev *dev) -{ - u32 status = rx_readl(dev, MUnit.OMRx[0]); - - /* - * Check to see if the board failed any self tests. - */ - if (unlikely(status & SELF_TEST_FAILED)) - return -1; - /* - * Check to see if the board panic'd. - */ - if (unlikely(status & KERNEL_PANIC)) { - char * buffer; - struct POSTSTATUS { - __le32 Post_Command; - __le32 Post_Address; - } * post; - dma_addr_t paddr, baddr; - int ret; - - if (likely((status & 0xFF000000L) == 0xBC000000L)) - return (status >> 16) & 0xFF; - buffer = pci_alloc_consistent(dev->pdev, 512, &baddr); - ret = -2; - if (unlikely(buffer == NULL)) - return ret; - post = pci_alloc_consistent(dev->pdev, - sizeof(struct POSTSTATUS), &paddr); - if (unlikely(post == NULL)) { - pci_free_consistent(dev->pdev, 512, buffer, baddr); - return ret; - } - memset(buffer, 0, 512); - post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS); - post->Post_Address = cpu_to_le32(baddr); - rx_writel(dev, MUnit.IMRx[0], paddr); - rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, 0, 0, 0, 0, 0, - NULL, NULL, NULL, NULL, NULL); - pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS), - post, paddr); - if (likely((buffer[0] == '0') && ((buffer[1] == 'x') || (buffer[1] == 'X')))) { - ret = (hex_to_bin(buffer[2]) << 4) + - hex_to_bin(buffer[3]); - } - pci_free_consistent(dev->pdev, 512, buffer, baddr); - return ret; - } - /* - * Wait for the adapter to be up and running. - */ - if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) - return -3; - /* - * Everything is OK - */ - return 0; -} - -/** - * aac_rx_deliver_producer - * @fib: fib to issue - * - * Will send a fib, returning 0 if successful. - */ -int aac_rx_deliver_producer(struct fib * fib) -{ - struct aac_dev *dev = fib->dev; - struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; - unsigned long qflags; - u32 Index; - unsigned long nointr = 0; - - spin_lock_irqsave(q->lock, qflags); - aac_queue_get( dev, &Index, AdapNormCmdQueue, fib->hw_fib_va, 1, fib, &nointr); - - q->numpending++; - *(q->headers.producer) = cpu_to_le32(Index + 1); - spin_unlock_irqrestore(q->lock, qflags); - if (!(nointr & aac_config.irq_mod)) - aac_adapter_notify(dev, AdapNormCmdQueue); - - return 0; -} - -/** - * aac_rx_deliver_message - * @fib: fib to issue - * - * Will send a fib, returning 0 if successful. - */ -static int aac_rx_deliver_message(struct fib * fib) -{ - struct aac_dev *dev = fib->dev; - struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; - unsigned long qflags; - u32 Index; - u64 addr; - volatile void __iomem *device; - - unsigned long count = 10000000L; /* 50 seconds */ - spin_lock_irqsave(q->lock, qflags); - q->numpending++; - spin_unlock_irqrestore(q->lock, qflags); - for(;;) { - Index = rx_readl(dev, MUnit.InboundQueue); - if (unlikely(Index == 0xFFFFFFFFL)) - Index = rx_readl(dev, MUnit.InboundQueue); - if (likely(Index != 0xFFFFFFFFL)) - break; - if (--count == 0) { - spin_lock_irqsave(q->lock, qflags); - q->numpending--; - spin_unlock_irqrestore(q->lock, qflags); - return -ETIMEDOUT; - } - udelay(5); - } - device = dev->base + Index; - addr = fib->hw_fib_pa; - writel((u32)(addr & 0xffffffff), device); - device += sizeof(u32); - writel((u32)(addr >> 32), device); - device += sizeof(u32); - writel(le16_to_cpu(fib->hw_fib_va->header.Size), device); - rx_writel(dev, MUnit.InboundQueue, Index); - return 0; -} - -/** - * aac_rx_ioremap - * @size: mapping resize request - * - */ -static int aac_rx_ioremap(struct aac_dev * dev, u32 size) -{ - if (!size) { - iounmap(dev->regs.rx); - return 0; - } - dev->base = dev->regs.rx = ioremap(dev->scsi_host_ptr->base, size); - if (dev->base == NULL) - return -1; - dev->IndexRegs = &dev->regs.rx->IndexRegs; - return 0; -} - -static int aac_rx_restart_adapter(struct aac_dev *dev, int bled) -{ - u32 var; - - if (!(dev->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_MU_RESET) || (bled >= 0) || (bled == -2)) { - if (bled) - printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", - dev->name, dev->id, bled); - else { - bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, - 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); - if (!bled && (var != 0x00000001) && (var != 0x3803000F)) - bled = -EINVAL; - } - if (bled && (bled != -ETIMEDOUT)) - bled = aac_adapter_sync_cmd(dev, IOP_RESET, - 0, 0, 0, 0, 0, 0, &var, NULL, NULL, NULL, NULL); - - if (bled && (bled != -ETIMEDOUT)) - return -EINVAL; - } - if (bled || (var == 0x3803000F)) { /* USE_OTHER_METHOD */ - rx_writel(dev, MUnit.reserved2, 3); - msleep(5000); /* Delay 5 seconds */ - var = 0x00000001; - } - if (var != 0x00000001) - return -EINVAL; - if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) - return -ENODEV; - if (startup_timeout < 300) - startup_timeout = 300; - return 0; -} - -/** - * aac_rx_select_comm - Select communications method - * @dev: Adapter - * @comm: communications method - */ - -int aac_rx_select_comm(struct aac_dev *dev, int comm) -{ - switch (comm) { - case AAC_COMM_PRODUCER: - dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_producer; - dev->a_ops.adapter_intr = aac_rx_intr_producer; - dev->a_ops.adapter_deliver = aac_rx_deliver_producer; - break; - case AAC_COMM_MESSAGE: - dev->a_ops.adapter_enable_int = aac_rx_enable_interrupt_message; - dev->a_ops.adapter_intr = aac_rx_intr_message; - dev->a_ops.adapter_deliver = aac_rx_deliver_message; - break; - default: - return 1; - } - return 0; -} - -/** - * aac_rx_init - initialize an i960 based AAC card - * @dev: device to configure - * - * Allocate and set up resources for the i960 based AAC variants. The - * device_interface in the commregion will be allocated and linked - * to the comm region. - */ - -int _aac_rx_init(struct aac_dev *dev) -{ - unsigned long start; - unsigned long status; - int restart = 0; - int instance = dev->id; - const char * name = dev->name; - - if (aac_adapter_ioremap(dev, dev->base_size)) { - printk(KERN_WARNING "%s: unable to map adapter.\n", name); - goto error_iounmap; - } - - /* Failure to reset here is an option ... */ - dev->a_ops.adapter_sync_cmd = rx_sync_cmd; - dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt; - dev->OIMR = status = rx_readb (dev, MUnit.OIMR); - if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) && - !aac_rx_restart_adapter(dev, 0)) - /* Make sure the Hardware FIFO is empty */ - while ((++restart < 512) && - (rx_readl(dev, MUnit.OutboundQueue) != 0xFFFFFFFFL)); - /* - * Check to see if the board panic'd while booting. - */ - status = rx_readl(dev, MUnit.OMRx[0]); - if (status & KERNEL_PANIC) { - if (aac_rx_restart_adapter(dev, aac_rx_check_health(dev))) - goto error_iounmap; - ++restart; - } - /* - * Check to see if the board failed any self tests. - */ - status = rx_readl(dev, MUnit.OMRx[0]); - if (status & SELF_TEST_FAILED) { - printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); - goto error_iounmap; - } - /* - * Check to see if the monitor panic'd while booting. - */ - if (status & MONITOR_PANIC) { - printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); - goto error_iounmap; - } - start = jiffies; - /* - * Wait for the adapter to be up and running. Wait up to 3 minutes - */ - while (!((status = rx_readl(dev, MUnit.OMRx[0])) & KERNEL_UP_AND_RUNNING)) - { - if ((restart && - (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || - time_after(jiffies, start+HZ*startup_timeout)) { - printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", - dev->name, instance, status); - goto error_iounmap; - } - if (!restart && - ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || - time_after(jiffies, start + HZ * - ((startup_timeout > 60) - ? (startup_timeout - 60) - : (startup_timeout / 2))))) { - if (likely(!aac_rx_restart_adapter(dev, aac_rx_check_health(dev)))) - start = jiffies; - ++restart; - } - msleep(1); - } - if (restart && aac_commit) - aac_commit = 1; - /* - * Fill in the common function dispatch table. - */ - dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; - dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; - dev->a_ops.adapter_notify = aac_rx_notify_adapter; - dev->a_ops.adapter_sync_cmd = rx_sync_cmd; - dev->a_ops.adapter_check_health = aac_rx_check_health; - dev->a_ops.adapter_restart = aac_rx_restart_adapter; - - /* - * First clear out all interrupts. Then enable the one's that we - * can handle. - */ - aac_adapter_comm(dev, AAC_COMM_PRODUCER); - aac_adapter_disable_int(dev); - rx_writel(dev, MUnit.ODR, 0xffffffff); - aac_adapter_enable_int(dev); - - if (aac_init_adapter(dev) == NULL) - goto error_iounmap; - aac_adapter_comm(dev, dev->comm_interface); - dev->sync_mode = 0; /* sync. mode not supported */ - dev->msi = aac_msi && !pci_enable_msi(dev->pdev); - if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, - IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { - if (dev->msi) - pci_disable_msi(dev->pdev); - printk(KERN_ERR "%s%d: Interrupt unavailable.\n", - name, instance); - goto error_iounmap; - } - dev->dbg_base = dev->scsi_host_ptr->base; - dev->dbg_base_mapped = dev->base; - dev->dbg_size = dev->base_size; - - aac_adapter_enable_int(dev); - /* - * Tell the adapter that all is configured, and it can - * start accepting requests - */ - aac_rx_start_adapter(dev); - - return 0; - -error_iounmap: - - return -1; -} - -int aac_rx_init(struct aac_dev *dev) -{ - /* - * Fill in the function dispatch table. - */ - dev->a_ops.adapter_ioremap = aac_rx_ioremap; - dev->a_ops.adapter_comm = aac_rx_select_comm; - - return _aac_rx_init(dev); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/sa.c b/ANDROID_3.4.5/drivers/scsi/aacraid/sa.c deleted file mode 100644 index beb53363..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/sa.c +++ /dev/null @@ -1,417 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * sa.c - * - * Abstract: Drawbridge specific support functions - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "aacraid.h" - -static irqreturn_t aac_sa_intr(int irq, void *dev_id) -{ - struct aac_dev *dev = dev_id; - unsigned short intstat, mask; - - intstat = sa_readw(dev, DoorbellReg_p); - /* - * Read mask and invert because drawbridge is reversed. - * This allows us to only service interrupts that have been enabled. - */ - mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK)); - - /* Check to see if this is our interrupt. If it isn't just return */ - - if (intstat & mask) { - if (intstat & PrintfReady) { - aac_printf(dev, sa_readl(dev, Mailbox5)); - sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */ - sa_writew(dev, DoorbellReg_s, PrintfDone); - } else if (intstat & DOORBELL_1) { // dev -> Host Normal Command Ready - sa_writew(dev, DoorbellClrReg_p, DOORBELL_1); - aac_command_normal(&dev->queues->queue[HostNormCmdQueue]); - } else if (intstat & DOORBELL_2) { // dev -> Host Normal Response Ready - sa_writew(dev, DoorbellClrReg_p, DOORBELL_2); - aac_response_normal(&dev->queues->queue[HostNormRespQueue]); - } else if (intstat & DOORBELL_3) { // dev -> Host Normal Command Not Full - sa_writew(dev, DoorbellClrReg_p, DOORBELL_3); - } else if (intstat & DOORBELL_4) { // dev -> Host Normal Response Not Full - sa_writew(dev, DoorbellClrReg_p, DOORBELL_4); - } - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -/** - * aac_sa_disable_interrupt - disable interrupt - * @dev: Which adapter to enable. - */ - -static void aac_sa_disable_interrupt (struct aac_dev *dev) -{ - sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); -} - -/** - * aac_sa_enable_interrupt - enable interrupt - * @dev: Which adapter to enable. - */ - -static void aac_sa_enable_interrupt (struct aac_dev *dev) -{ - sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | - DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); -} - -/** - * aac_sa_notify_adapter - handle adapter notification - * @dev: Adapter that notification is for - * @event: Event to notidy - * - * Notify the adapter of an event - */ - -static void aac_sa_notify_adapter(struct aac_dev *dev, u32 event) -{ - switch (event) { - - case AdapNormCmdQue: - sa_writew(dev, DoorbellReg_s,DOORBELL_1); - break; - case HostNormRespNotFull: - sa_writew(dev, DoorbellReg_s,DOORBELL_4); - break; - case AdapNormRespQue: - sa_writew(dev, DoorbellReg_s,DOORBELL_2); - break; - case HostNormCmdNotFull: - sa_writew(dev, DoorbellReg_s,DOORBELL_3); - break; - case HostShutdown: - /* - sa_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, 0, 0, - NULL, NULL, NULL, NULL, NULL); - */ - break; - case FastIo: - sa_writew(dev, DoorbellReg_s,DOORBELL_6); - break; - case AdapPrintfDone: - sa_writew(dev, DoorbellReg_s,DOORBELL_5); - break; - default: - BUG(); - break; - } -} - - -/** - * sa_sync_cmd - send a command and wait - * @dev: Adapter - * @command: Command to execute - * @p1: first parameter - * @ret: adapter status - * - * This routine will send a synchronous command to the adapter and wait - * for its completion. - */ - -static int sa_sync_cmd(struct aac_dev *dev, u32 command, - u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, - u32 *ret, u32 *r1, u32 *r2, u32 *r3, u32 *r4) -{ - unsigned long start; - int ok; - /* - * Write the Command into Mailbox 0 - */ - sa_writel(dev, Mailbox0, command); - /* - * Write the parameters into Mailboxes 1 - 4 - */ - sa_writel(dev, Mailbox1, p1); - sa_writel(dev, Mailbox2, p2); - sa_writel(dev, Mailbox3, p3); - sa_writel(dev, Mailbox4, p4); - - /* - * Clear the synch command doorbell to start on a clean slate. - */ - sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); - /* - * Signal that there is a new synch command - */ - sa_writew(dev, DoorbellReg_s, DOORBELL_0); - - ok = 0; - start = jiffies; - - while(time_before(jiffies, start+30*HZ)) - { - /* - * Delay 5uS so that the monitor gets access - */ - udelay(5); - /* - * Mon110 will set doorbell0 bit when it has - * completed the command. - */ - if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0) { - ok = 1; - break; - } - msleep(1); - } - - if (ok != 1) - return -ETIMEDOUT; - /* - * Clear the synch command doorbell. - */ - sa_writew(dev, DoorbellClrReg_p, DOORBELL_0); - /* - * Pull the synch status from Mailbox 0. - */ - if (ret) - *ret = sa_readl(dev, Mailbox0); - if (r1) - *r1 = sa_readl(dev, Mailbox1); - if (r2) - *r2 = sa_readl(dev, Mailbox2); - if (r3) - *r3 = sa_readl(dev, Mailbox3); - if (r4) - *r4 = sa_readl(dev, Mailbox4); - return 0; -} - -/** - * aac_sa_interrupt_adapter - interrupt an adapter - * @dev: Which adapter to enable. - * - * Breakpoint an adapter. - */ - -static void aac_sa_interrupt_adapter (struct aac_dev *dev) -{ - sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, - NULL, NULL, NULL, NULL, NULL); -} - -/** - * aac_sa_start_adapter - activate adapter - * @dev: Adapter - * - * Start up processing on an ARM based AAC adapter - */ - -static void aac_sa_start_adapter(struct aac_dev *dev) -{ - struct aac_init *init; - /* - * Fill in the remaining pieces of the init. - */ - init = dev->init; - init->HostElapsedSeconds = cpu_to_le32(get_seconds()); - /* We can only use a 32 bit address here */ - sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, - (u32)(ulong)dev->init_pa, 0, 0, 0, 0, 0, - NULL, NULL, NULL, NULL, NULL); -} - -static int aac_sa_restart_adapter(struct aac_dev *dev, int bled) -{ - return -EINVAL; -} - -/** - * aac_sa_check_health - * @dev: device to check if healthy - * - * Will attempt to determine if the specified adapter is alive and - * capable of handling requests, returning 0 if alive. - */ -static int aac_sa_check_health(struct aac_dev *dev) -{ - long status = sa_readl(dev, Mailbox7); - - /* - * Check to see if the board failed any self tests. - */ - if (status & SELF_TEST_FAILED) - return -1; - /* - * Check to see if the board panic'd while booting. - */ - if (status & KERNEL_PANIC) - return -2; - /* - * Wait for the adapter to be up and running. Wait up to 3 minutes - */ - if (!(status & KERNEL_UP_AND_RUNNING)) - return -3; - /* - * Everything is OK - */ - return 0; -} - -/** - * aac_sa_ioremap - * @size: mapping resize request - * - */ -static int aac_sa_ioremap(struct aac_dev * dev, u32 size) -{ - if (!size) { - iounmap(dev->regs.sa); - return 0; - } - dev->base = dev->regs.sa = ioremap(dev->scsi_host_ptr->base, size); - return (dev->base == NULL) ? -1 : 0; -} - -/** - * aac_sa_init - initialize an ARM based AAC card - * @dev: device to configure - * - * Allocate and set up resources for the ARM based AAC variants. The - * device_interface in the commregion will be allocated and linked - * to the comm region. - */ - -int aac_sa_init(struct aac_dev *dev) -{ - unsigned long start; - unsigned long status; - int instance; - const char *name; - - instance = dev->id; - name = dev->name; - - if (aac_sa_ioremap(dev, dev->base_size)) { - printk(KERN_WARNING "%s: unable to map adapter.\n", name); - goto error_iounmap; - } - - /* - * Check to see if the board failed any self tests. - */ - if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) { - printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance); - goto error_iounmap; - } - /* - * Check to see if the board panic'd while booting. - */ - if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) { - printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance); - goto error_iounmap; - } - start = jiffies; - /* - * Wait for the adapter to be up and running. Wait up to 3 minutes. - */ - while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) { - if (time_after(jiffies, start+startup_timeout*HZ)) { - status = sa_readl(dev, Mailbox7); - printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n", - name, instance, status); - goto error_iounmap; - } - msleep(1); - } - - /* - * Fill in the function dispatch table. - */ - - dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; - dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; - dev->a_ops.adapter_enable_int = aac_sa_enable_interrupt; - dev->a_ops.adapter_notify = aac_sa_notify_adapter; - dev->a_ops.adapter_sync_cmd = sa_sync_cmd; - dev->a_ops.adapter_check_health = aac_sa_check_health; - dev->a_ops.adapter_restart = aac_sa_restart_adapter; - dev->a_ops.adapter_intr = aac_sa_intr; - dev->a_ops.adapter_deliver = aac_rx_deliver_producer; - dev->a_ops.adapter_ioremap = aac_sa_ioremap; - - /* - * First clear out all interrupts. Then enable the one's that - * we can handle. - */ - aac_adapter_disable_int(dev); - aac_adapter_enable_int(dev); - - if(aac_init_adapter(dev) == NULL) - goto error_irq; - dev->sync_mode = 0; /* sync. mode not supported */ - if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, - IRQF_SHARED|IRQF_DISABLED, - "aacraid", (void *)dev ) < 0) { - printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", - name, instance); - goto error_iounmap; - } - dev->dbg_base = dev->scsi_host_ptr->base; - dev->dbg_base_mapped = dev->base; - dev->dbg_size = dev->base_size; - - aac_adapter_enable_int(dev); - - /* - * Tell the adapter that all is configure, and it can start - * accepting requests - */ - aac_sa_start_adapter(dev); - return 0; - -error_irq: - aac_sa_disable_interrupt(dev); - free_irq(dev->pdev->irq, (void *)dev); - -error_iounmap: - - return -1; -} - diff --git a/ANDROID_3.4.5/drivers/scsi/aacraid/src.c b/ANDROID_3.4.5/drivers/scsi/aacraid/src.c deleted file mode 100644 index 2bee5150..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aacraid/src.c +++ /dev/null @@ -1,784 +0,0 @@ -/* - * Adaptec AAC series RAID controller driver - * (c) Copyright 2001 Red Hat Inc. - * - * based on the old aacraid driver that is.. - * Adaptec aacraid device driver for Linux. - * - * Copyright (c) 2000-2010 Adaptec, Inc. - * 2010 PMC-Sierra, Inc. (aacraid@pmc-sierra.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Module Name: - * src.c - * - * Abstract: Hardware Device Interface for PMC SRC based controllers - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "aacraid.h" - -static irqreturn_t aac_src_intr_message(int irq, void *dev_id) -{ - struct aac_dev *dev = dev_id; - unsigned long bellbits, bellbits_shifted; - int our_interrupt = 0; - int isFastResponse; - u32 index, handle; - - bellbits = src_readl(dev, MUnit.ODR_R); - if (bellbits & PmDoorBellResponseSent) { - bellbits = PmDoorBellResponseSent; - /* handle async. status */ - our_interrupt = 1; - index = dev->host_rrq_idx; - if (dev->host_rrq[index] == 0) { - u32 old_index = index; - /* adjust index */ - do { - index++; - if (index == dev->scsi_host_ptr->can_queue + - AAC_NUM_MGT_FIB) - index = 0; - if (dev->host_rrq[index] != 0) - break; - } while (index != old_index); - dev->host_rrq_idx = index; - } - for (;;) { - isFastResponse = 0; - /* remove toggle bit (31) */ - handle = (dev->host_rrq[index] & 0x7fffffff); - /* check fast response bit (30) */ - if (handle & 0x40000000) - isFastResponse = 1; - handle &= 0x0000ffff; - if (handle == 0) - break; - - aac_intr_normal(dev, handle-1, 0, isFastResponse, NULL); - - dev->host_rrq[index++] = 0; - if (index == dev->scsi_host_ptr->can_queue + - AAC_NUM_MGT_FIB) - index = 0; - dev->host_rrq_idx = index; - } - } else { - bellbits_shifted = (bellbits >> SRC_ODR_SHIFT); - if (bellbits_shifted & DoorBellAifPending) { - our_interrupt = 1; - /* handle AIF */ - aac_intr_normal(dev, 0, 2, 0, NULL); - } else if (bellbits_shifted & OUTBOUNDDOORBELL_0) { - unsigned long sflags; - struct list_head *entry; - int send_it = 0; - - if (dev->sync_fib) { - our_interrupt = 1; - if (dev->sync_fib->callback) - dev->sync_fib->callback(dev->sync_fib->callback_data, - dev->sync_fib); - spin_lock_irqsave(&dev->sync_fib->event_lock, sflags); - if (dev->sync_fib->flags & FIB_CONTEXT_FLAG_WAIT) { - dev->management_fib_count--; - up(&dev->sync_fib->event_wait); - } - spin_unlock_irqrestore(&dev->sync_fib->event_lock, sflags); - spin_lock_irqsave(&dev->sync_lock, sflags); - if (!list_empty(&dev->sync_fib_list)) { - entry = dev->sync_fib_list.next; - dev->sync_fib = list_entry(entry, struct fib, fiblink); - list_del(entry); - send_it = 1; - } else { - dev->sync_fib = NULL; - } - spin_unlock_irqrestore(&dev->sync_lock, sflags); - if (send_it) { - aac_adapter_sync_cmd(dev, SEND_SYNCHRONOUS_FIB, - (u32)dev->sync_fib->hw_fib_pa, 0, 0, 0, 0, 0, - NULL, NULL, NULL, NULL, NULL); - } - } - } - } - - if (our_interrupt) { - src_writel(dev, MUnit.ODR_C, bellbits); - return IRQ_HANDLED; - } - return IRQ_NONE; -} - -/** - * aac_src_disable_interrupt - Disable interrupts - * @dev: Adapter - */ - -static void aac_src_disable_interrupt(struct aac_dev *dev) -{ - src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); -} - -/** - * aac_src_enable_interrupt_message - Enable interrupts - * @dev: Adapter - */ - -static void aac_src_enable_interrupt_message(struct aac_dev *dev) -{ - src_writel(dev, MUnit.OIMR, dev->OIMR = 0xfffffff8); -} - -/** - * src_sync_cmd - send a command and wait - * @dev: Adapter - * @command: Command to execute - * @p1: first parameter - * @ret: adapter status - * - * This routine will send a synchronous command to the adapter and wait - * for its completion. - */ - -static int src_sync_cmd(struct aac_dev *dev, u32 command, - u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, - u32 *status, u32 * r1, u32 * r2, u32 * r3, u32 * r4) -{ - unsigned long start; - int ok; - - /* - * Write the command into Mailbox 0 - */ - writel(command, &dev->IndexRegs->Mailbox[0]); - /* - * Write the parameters into Mailboxes 1 - 6 - */ - writel(p1, &dev->IndexRegs->Mailbox[1]); - writel(p2, &dev->IndexRegs->Mailbox[2]); - writel(p3, &dev->IndexRegs->Mailbox[3]); - writel(p4, &dev->IndexRegs->Mailbox[4]); - - /* - * Clear the synch command doorbell to start on a clean slate. - */ - src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); - - /* - * Disable doorbell interrupts - */ - src_writel(dev, MUnit.OIMR, dev->OIMR = 0xffffffff); - - /* - * Force the completion of the mask register write before issuing - * the interrupt. - */ - src_readl(dev, MUnit.OIMR); - - /* - * Signal that there is a new synch command - */ - src_writel(dev, MUnit.IDR, INBOUNDDOORBELL_0 << SRC_IDR_SHIFT); - - if (!dev->sync_mode || command != SEND_SYNCHRONOUS_FIB) { - ok = 0; - start = jiffies; - - /* - * Wait up to 5 minutes - */ - while (time_before(jiffies, start+300*HZ)) { - udelay(5); /* Delay 5 microseconds to let Mon960 get info. */ - /* - * Mon960 will set doorbell0 bit when it has completed the command. - */ - if ((src_readl(dev, MUnit.ODR_R) >> SRC_ODR_SHIFT) & OUTBOUNDDOORBELL_0) { - /* - * Clear the doorbell. - */ - src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); - ok = 1; - break; - } - /* - * Yield the processor in case we are slow - */ - msleep(1); - } - if (unlikely(ok != 1)) { - /* - * Restore interrupt mask even though we timed out - */ - aac_adapter_enable_int(dev); - return -ETIMEDOUT; - } - /* - * Pull the synch status from Mailbox 0. - */ - if (status) - *status = readl(&dev->IndexRegs->Mailbox[0]); - if (r1) - *r1 = readl(&dev->IndexRegs->Mailbox[1]); - if (r2) - *r2 = readl(&dev->IndexRegs->Mailbox[2]); - if (r3) - *r3 = readl(&dev->IndexRegs->Mailbox[3]); - if (r4) - *r4 = readl(&dev->IndexRegs->Mailbox[4]); - - /* - * Clear the synch command doorbell. - */ - src_writel(dev, MUnit.ODR_C, OUTBOUNDDOORBELL_0 << SRC_ODR_SHIFT); - } - - /* - * Restore interrupt mask - */ - aac_adapter_enable_int(dev); - return 0; -} - -/** - * aac_src_interrupt_adapter - interrupt adapter - * @dev: Adapter - * - * Send an interrupt to the i960 and breakpoint it. - */ - -static void aac_src_interrupt_adapter(struct aac_dev *dev) -{ - src_sync_cmd(dev, BREAKPOINT_REQUEST, - 0, 0, 0, 0, 0, 0, - NULL, NULL, NULL, NULL, NULL); -} - -/** - * aac_src_notify_adapter - send an event to the adapter - * @dev: Adapter - * @event: Event to send - * - * Notify the i960 that something it probably cares about has - * happened. - */ - -static void aac_src_notify_adapter(struct aac_dev *dev, u32 event) -{ - switch (event) { - - case AdapNormCmdQue: - src_writel(dev, MUnit.ODR_C, - INBOUNDDOORBELL_1 << SRC_ODR_SHIFT); - break; - case HostNormRespNotFull: - src_writel(dev, MUnit.ODR_C, - INBOUNDDOORBELL_4 << SRC_ODR_SHIFT); - break; - case AdapNormRespQue: - src_writel(dev, MUnit.ODR_C, - INBOUNDDOORBELL_2 << SRC_ODR_SHIFT); - break; - case HostNormCmdNotFull: - src_writel(dev, MUnit.ODR_C, - INBOUNDDOORBELL_3 << SRC_ODR_SHIFT); - break; - case FastIo: - src_writel(dev, MUnit.ODR_C, - INBOUNDDOORBELL_6 << SRC_ODR_SHIFT); - break; - case AdapPrintfDone: - src_writel(dev, MUnit.ODR_C, - INBOUNDDOORBELL_5 << SRC_ODR_SHIFT); - break; - default: - BUG(); - break; - } -} - -/** - * aac_src_start_adapter - activate adapter - * @dev: Adapter - * - * Start up processing on an i960 based AAC adapter - */ - -static void aac_src_start_adapter(struct aac_dev *dev) -{ - struct aac_init *init; - - init = dev->init; - init->HostElapsedSeconds = cpu_to_le32(get_seconds()); - - /* We can only use a 32 bit address here */ - src_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, - 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); -} - -/** - * aac_src_check_health - * @dev: device to check if healthy - * - * Will attempt to determine if the specified adapter is alive and - * capable of handling requests, returning 0 if alive. - */ -static int aac_src_check_health(struct aac_dev *dev) -{ - u32 status = src_readl(dev, MUnit.OMR); - - /* - * Check to see if the board failed any self tests. - */ - if (unlikely(status & SELF_TEST_FAILED)) - return -1; - - /* - * Check to see if the board panic'd. - */ - if (unlikely(status & KERNEL_PANIC)) - return (status >> 16) & 0xFF; - /* - * Wait for the adapter to be up and running. - */ - if (unlikely(!(status & KERNEL_UP_AND_RUNNING))) - return -3; - /* - * Everything is OK - */ - return 0; -} - -/** - * aac_src_deliver_message - * @fib: fib to issue - * - * Will send a fib, returning 0 if successful. - */ -static int aac_src_deliver_message(struct fib *fib) -{ - struct aac_dev *dev = fib->dev; - struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; - unsigned long qflags; - u32 fibsize; - u64 address; - struct aac_fib_xporthdr *pFibX; - - spin_lock_irqsave(q->lock, qflags); - q->numpending++; - spin_unlock_irqrestore(q->lock, qflags); - - /* Calculate the amount to the fibsize bits */ - fibsize = (sizeof(struct aac_fib_xporthdr) + - fib->hw_fib_va->header.Size + 127) / 128 - 1; - if (fibsize > (ALIGN32 - 1)) - fibsize = ALIGN32 - 1; - - /* Fill XPORT header */ - pFibX = (struct aac_fib_xporthdr *) - ((unsigned char *)fib->hw_fib_va - - sizeof(struct aac_fib_xporthdr)); - pFibX->Handle = fib->hw_fib_va->header.SenderData + 1; - pFibX->HostAddress = fib->hw_fib_pa; - pFibX->Size = fib->hw_fib_va->header.Size; - address = fib->hw_fib_pa - (u64)sizeof(struct aac_fib_xporthdr); - - src_writel(dev, MUnit.IQ_H, (u32)(address >> 32)); - src_writel(dev, MUnit.IQ_L, (u32)(address & 0xffffffff) + fibsize); - return 0; -} - -/** - * aac_src_ioremap - * @size: mapping resize request - * - */ -static int aac_src_ioremap(struct aac_dev *dev, u32 size) -{ - if (!size) { - iounmap(dev->regs.src.bar0); - dev->base = dev->regs.src.bar0 = NULL; - return 0; - } - dev->regs.src.bar1 = ioremap(pci_resource_start(dev->pdev, 2), - AAC_MIN_SRC_BAR1_SIZE); - dev->base = NULL; - if (dev->regs.src.bar1 == NULL) - return -1; - dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base, - size); - if (dev->base == NULL) { - iounmap(dev->regs.src.bar1); - dev->regs.src.bar1 = NULL; - return -1; - } - dev->IndexRegs = &((struct src_registers __iomem *) - dev->base)->u.tupelo.IndexRegs; - return 0; -} - -/** - * aac_srcv_ioremap - * @size: mapping resize request - * - */ -static int aac_srcv_ioremap(struct aac_dev *dev, u32 size) -{ - if (!size) { - iounmap(dev->regs.src.bar0); - dev->base = dev->regs.src.bar0 = NULL; - return 0; - } - dev->base = dev->regs.src.bar0 = ioremap(dev->scsi_host_ptr->base, size); - if (dev->base == NULL) - return -1; - dev->IndexRegs = &((struct src_registers __iomem *) - dev->base)->u.denali.IndexRegs; - return 0; -} - -static int aac_src_restart_adapter(struct aac_dev *dev, int bled) -{ - u32 var, reset_mask; - - if (bled >= 0) { - if (bled) - printk(KERN_ERR "%s%d: adapter kernel panic'd %x.\n", - dev->name, dev->id, bled); - bled = aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, - 0, 0, 0, 0, 0, 0, &var, &reset_mask, NULL, NULL, NULL); - if (bled || (var != 0x00000001)) - return -EINVAL; - if (dev->supplement_adapter_info.SupportedOptions2 & - AAC_OPTION_DOORBELL_RESET) { - src_writel(dev, MUnit.IDR, reset_mask); - msleep(5000); /* Delay 5 seconds */ - } - } - - if (src_readl(dev, MUnit.OMR) & KERNEL_PANIC) - return -ENODEV; - - if (startup_timeout < 300) - startup_timeout = 300; - - return 0; -} - -/** - * aac_src_select_comm - Select communications method - * @dev: Adapter - * @comm: communications method - */ -int aac_src_select_comm(struct aac_dev *dev, int comm) -{ - switch (comm) { - case AAC_COMM_MESSAGE: - dev->a_ops.adapter_enable_int = aac_src_enable_interrupt_message; - dev->a_ops.adapter_intr = aac_src_intr_message; - dev->a_ops.adapter_deliver = aac_src_deliver_message; - break; - default: - return 1; - } - return 0; -} - -/** - * aac_src_init - initialize an Cardinal Frey Bar card - * @dev: device to configure - * - */ - -int aac_src_init(struct aac_dev *dev) -{ - unsigned long start; - unsigned long status; - int restart = 0; - int instance = dev->id; - const char *name = dev->name; - - dev->a_ops.adapter_ioremap = aac_src_ioremap; - dev->a_ops.adapter_comm = aac_src_select_comm; - - dev->base_size = AAC_MIN_SRC_BAR0_SIZE; - if (aac_adapter_ioremap(dev, dev->base_size)) { - printk(KERN_WARNING "%s: unable to map adapter.\n", name); - goto error_iounmap; - } - - /* Failure to reset here is an option ... */ - dev->a_ops.adapter_sync_cmd = src_sync_cmd; - dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; - if ((aac_reset_devices || reset_devices) && - !aac_src_restart_adapter(dev, 0)) - ++restart; - /* - * Check to see if the board panic'd while booting. - */ - status = src_readl(dev, MUnit.OMR); - if (status & KERNEL_PANIC) { - if (aac_src_restart_adapter(dev, aac_src_check_health(dev))) - goto error_iounmap; - ++restart; - } - /* - * Check to see if the board failed any self tests. - */ - status = src_readl(dev, MUnit.OMR); - if (status & SELF_TEST_FAILED) { - printk(KERN_ERR "%s%d: adapter self-test failed.\n", - dev->name, instance); - goto error_iounmap; - } - /* - * Check to see if the monitor panic'd while booting. - */ - if (status & MONITOR_PANIC) { - printk(KERN_ERR "%s%d: adapter monitor panic.\n", - dev->name, instance); - goto error_iounmap; - } - start = jiffies; - /* - * Wait for the adapter to be up and running. Wait up to 3 minutes - */ - while (!((status = src_readl(dev, MUnit.OMR)) & - KERNEL_UP_AND_RUNNING)) { - if ((restart && - (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || - time_after(jiffies, start+HZ*startup_timeout)) { - printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", - dev->name, instance, status); - goto error_iounmap; - } - if (!restart && - ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || - time_after(jiffies, start + HZ * - ((startup_timeout > 60) - ? (startup_timeout - 60) - : (startup_timeout / 2))))) { - if (likely(!aac_src_restart_adapter(dev, - aac_src_check_health(dev)))) - start = jiffies; - ++restart; - } - msleep(1); - } - if (restart && aac_commit) - aac_commit = 1; - /* - * Fill in the common function dispatch table. - */ - dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; - dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; - dev->a_ops.adapter_notify = aac_src_notify_adapter; - dev->a_ops.adapter_sync_cmd = src_sync_cmd; - dev->a_ops.adapter_check_health = aac_src_check_health; - dev->a_ops.adapter_restart = aac_src_restart_adapter; - - /* - * First clear out all interrupts. Then enable the one's that we - * can handle. - */ - aac_adapter_comm(dev, AAC_COMM_MESSAGE); - aac_adapter_disable_int(dev); - src_writel(dev, MUnit.ODR_C, 0xffffffff); - aac_adapter_enable_int(dev); - - if (aac_init_adapter(dev) == NULL) - goto error_iounmap; - if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) - goto error_iounmap; - - dev->msi = aac_msi && !pci_enable_msi(dev->pdev); - - if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, - IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { - - if (dev->msi) - pci_disable_msi(dev->pdev); - - printk(KERN_ERR "%s%d: Interrupt unavailable.\n", - name, instance); - goto error_iounmap; - } - dev->dbg_base = pci_resource_start(dev->pdev, 2); - dev->dbg_base_mapped = dev->regs.src.bar1; - dev->dbg_size = AAC_MIN_SRC_BAR1_SIZE; - - aac_adapter_enable_int(dev); - - if (!dev->sync_mode) { - /* - * Tell the adapter that all is configured, and it can - * start accepting requests - */ - aac_src_start_adapter(dev); - } - return 0; - -error_iounmap: - - return -1; -} - -/** - * aac_srcv_init - initialize an SRCv card - * @dev: device to configure - * - */ - -int aac_srcv_init(struct aac_dev *dev) -{ - unsigned long start; - unsigned long status; - int restart = 0; - int instance = dev->id; - const char *name = dev->name; - - dev->a_ops.adapter_ioremap = aac_srcv_ioremap; - dev->a_ops.adapter_comm = aac_src_select_comm; - - dev->base_size = AAC_MIN_SRCV_BAR0_SIZE; - if (aac_adapter_ioremap(dev, dev->base_size)) { - printk(KERN_WARNING "%s: unable to map adapter.\n", name); - goto error_iounmap; - } - - /* Failure to reset here is an option ... */ - dev->a_ops.adapter_sync_cmd = src_sync_cmd; - dev->a_ops.adapter_enable_int = aac_src_disable_interrupt; - if ((aac_reset_devices || reset_devices) && - !aac_src_restart_adapter(dev, 0)) - ++restart; - /* - * Check to see if the board panic'd while booting. - */ - status = src_readl(dev, MUnit.OMR); - if (status & KERNEL_PANIC) { - if (aac_src_restart_adapter(dev, aac_src_check_health(dev))) - goto error_iounmap; - ++restart; - } - /* - * Check to see if the board failed any self tests. - */ - status = src_readl(dev, MUnit.OMR); - if (status & SELF_TEST_FAILED) { - printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance); - goto error_iounmap; - } - /* - * Check to see if the monitor panic'd while booting. - */ - if (status & MONITOR_PANIC) { - printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance); - goto error_iounmap; - } - start = jiffies; - /* - * Wait for the adapter to be up and running. Wait up to 3 minutes - */ - while (!((status = src_readl(dev, MUnit.OMR)) & KERNEL_UP_AND_RUNNING)) { - if ((restart && - (status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC))) || - time_after(jiffies, start+HZ*startup_timeout)) { - printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", - dev->name, instance, status); - goto error_iounmap; - } - if (!restart && - ((status & (KERNEL_PANIC|SELF_TEST_FAILED|MONITOR_PANIC)) || - time_after(jiffies, start + HZ * - ((startup_timeout > 60) - ? (startup_timeout - 60) - : (startup_timeout / 2))))) { - if (likely(!aac_src_restart_adapter(dev, aac_src_check_health(dev)))) - start = jiffies; - ++restart; - } - msleep(1); - } - if (restart && aac_commit) - aac_commit = 1; - /* - * Fill in the common function dispatch table. - */ - dev->a_ops.adapter_interrupt = aac_src_interrupt_adapter; - dev->a_ops.adapter_disable_int = aac_src_disable_interrupt; - dev->a_ops.adapter_notify = aac_src_notify_adapter; - dev->a_ops.adapter_sync_cmd = src_sync_cmd; - dev->a_ops.adapter_check_health = aac_src_check_health; - dev->a_ops.adapter_restart = aac_src_restart_adapter; - - /* - * First clear out all interrupts. Then enable the one's that we - * can handle. - */ - aac_adapter_comm(dev, AAC_COMM_MESSAGE); - aac_adapter_disable_int(dev); - src_writel(dev, MUnit.ODR_C, 0xffffffff); - aac_adapter_enable_int(dev); - - if (aac_init_adapter(dev) == NULL) - goto error_iounmap; - if (dev->comm_interface != AAC_COMM_MESSAGE_TYPE1) - goto error_iounmap; - dev->msi = aac_msi && !pci_enable_msi(dev->pdev); - if (request_irq(dev->pdev->irq, dev->a_ops.adapter_intr, - IRQF_SHARED|IRQF_DISABLED, "aacraid", dev) < 0) { - if (dev->msi) - pci_disable_msi(dev->pdev); - printk(KERN_ERR "%s%d: Interrupt unavailable.\n", - name, instance); - goto error_iounmap; - } - dev->dbg_base = dev->scsi_host_ptr->base; - dev->dbg_base_mapped = dev->base; - dev->dbg_size = dev->base_size; - - aac_adapter_enable_int(dev); - - if (!dev->sync_mode) { - /* - * Tell the adapter that all is configured, and it can - * start accepting requests - */ - aac_src_start_adapter(dev); - } - return 0; - -error_iounmap: - - return -1; -} - diff --git a/ANDROID_3.4.5/drivers/scsi/advansys.c b/ANDROID_3.4.5/drivers/scsi/advansys.c deleted file mode 100644 index 374c4edf..00000000 --- a/ANDROID_3.4.5/drivers/scsi/advansys.c +++ /dev/null @@ -1,12857 +0,0 @@ -#define DRV_NAME "advansys" -#define ASC_VERSION "3.4" /* AdvanSys Driver Version */ - -/* - * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters - * - * Copyright (c) 1995-2000 Advanced System Products, Inc. - * Copyright (c) 2000-2001 ConnectCom Solutions, Inc. - * Copyright (c) 2007 Matthew Wilcox - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -/* - * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys) - * changed its name to ConnectCom Solutions, Inc. - * On June 18, 2001 Initio Corp. acquired ConnectCom's SCSI assets - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -/* FIXME: - * - * 1. Although all of the necessary command mapping places have the - * appropriate dma_map.. APIs, the driver still processes its internal - * queue using bus_to_virt() and virt_to_bus() which are illegal under - * the API. The entire queue processing structure will need to be - * altered to fix this. - * 2. Need to add memory mapping workaround. Test the memory mapping. - * If it doesn't work revert to I/O port access. Can a test be done - * safely? - * 3. Handle an interrupt not working. Keep an interrupt counter in - * the interrupt handler. In the timeout function if the interrupt - * has not occurred then print a message and run in polled mode. - * 4. Need to add support for target mode commands, cf. CAM XPT. - * 5. check DMA mapping functions for failure - * 6. Use scsi_transport_spi - * 7. advansys_info is not safe against multiple simultaneous callers - * 8. Add module_param to override ISA/VLB ioport array - */ -#warning this driver is still not properly converted to the DMA API - -/* Enable driver /proc statistics. */ -#define ADVANSYS_STATS - -/* Enable driver tracing. */ -#undef ADVANSYS_DEBUG - -/* - * Portable Data Types - * - * Any instance where a 32-bit long or pointer type is assumed - * for precision or HW defined structures, the following define - * types must be used. In Linux the char, short, and int types - * are all consistent at 8, 16, and 32 bits respectively. Pointers - * and long types are 64 bits on Alpha and UltraSPARC. - */ -#define ASC_PADDR __u32 /* Physical/Bus address data type. */ -#define ASC_VADDR __u32 /* Virtual address data type. */ -#define ASC_DCNT __u32 /* Unsigned Data count type. */ -#define ASC_SDCNT __s32 /* Signed Data count type. */ - -typedef unsigned char uchar; - -#ifndef TRUE -#define TRUE (1) -#endif -#ifndef FALSE -#define FALSE (0) -#endif - -#define ERR (-1) -#define UW_ERR (uint)(0xFFFF) -#define isodd_word(val) ((((uint)val) & (uint)0x0001) != 0) - -#define PCI_VENDOR_ID_ASP 0x10cd -#define PCI_DEVICE_ID_ASP_1200A 0x1100 -#define PCI_DEVICE_ID_ASP_ABP940 0x1200 -#define PCI_DEVICE_ID_ASP_ABP940U 0x1300 -#define PCI_DEVICE_ID_ASP_ABP940UW 0x2300 -#define PCI_DEVICE_ID_38C0800_REV1 0x2500 -#define PCI_DEVICE_ID_38C1600_REV1 0x2700 - -/* - * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists. - * The SRB structure will have to be changed and the ASC_SRB2SCSIQ() - * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the - * SRB structure. - */ -#define CC_VERY_LONG_SG_LIST 0 -#define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr) - -#define PortAddr unsigned int /* port address size */ -#define inp(port) inb(port) -#define outp(port, byte) outb((byte), (port)) - -#define inpw(port) inw(port) -#define outpw(port, word) outw((word), (port)) - -#define ASC_MAX_SG_QUEUE 7 -#define ASC_MAX_SG_LIST 255 - -#define ASC_CS_TYPE unsigned short - -#define ASC_IS_ISA (0x0001) -#define ASC_IS_ISAPNP (0x0081) -#define ASC_IS_EISA (0x0002) -#define ASC_IS_PCI (0x0004) -#define ASC_IS_PCI_ULTRA (0x0104) -#define ASC_IS_PCMCIA (0x0008) -#define ASC_IS_MCA (0x0020) -#define ASC_IS_VL (0x0040) -#define ASC_IS_WIDESCSI_16 (0x0100) -#define ASC_IS_WIDESCSI_32 (0x0200) -#define ASC_IS_BIG_ENDIAN (0x8000) - -#define ASC_CHIP_MIN_VER_VL (0x01) -#define ASC_CHIP_MAX_VER_VL (0x07) -#define ASC_CHIP_MIN_VER_PCI (0x09) -#define ASC_CHIP_MAX_VER_PCI (0x0F) -#define ASC_CHIP_VER_PCI_BIT (0x08) -#define ASC_CHIP_MIN_VER_ISA (0x11) -#define ASC_CHIP_MIN_VER_ISA_PNP (0x21) -#define ASC_CHIP_MAX_VER_ISA (0x27) -#define ASC_CHIP_VER_ISA_BIT (0x30) -#define ASC_CHIP_VER_ISAPNP_BIT (0x20) -#define ASC_CHIP_VER_ASYN_BUG (0x21) -#define ASC_CHIP_VER_PCI 0x08 -#define ASC_CHIP_VER_PCI_ULTRA_3150 (ASC_CHIP_VER_PCI | 0x02) -#define ASC_CHIP_VER_PCI_ULTRA_3050 (ASC_CHIP_VER_PCI | 0x03) -#define ASC_CHIP_MIN_VER_EISA (0x41) -#define ASC_CHIP_MAX_VER_EISA (0x47) -#define ASC_CHIP_VER_EISA_BIT (0x40) -#define ASC_CHIP_LATEST_VER_EISA ((ASC_CHIP_MIN_VER_EISA - 1) + 3) -#define ASC_MAX_VL_DMA_COUNT (0x07FFFFFFL) -#define ASC_MAX_PCI_DMA_COUNT (0xFFFFFFFFL) -#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL) - -#define ASC_SCSI_ID_BITS 3 -#define ASC_SCSI_TIX_TYPE uchar -#define ASC_ALL_DEVICE_BIT_SET 0xFF -#define ASC_SCSI_BIT_ID_TYPE uchar -#define ASC_MAX_TID 7 -#define ASC_MAX_LUN 7 -#define ASC_SCSI_WIDTH_BIT_SET 0xFF -#define ASC_MAX_SENSE_LEN 32 -#define ASC_MIN_SENSE_LEN 14 -#define ASC_SCSI_RESET_HOLD_TIME_US 60 - -/* - * Narrow boards only support 12-byte commands, while wide boards - * extend to 16-byte commands. - */ -#define ASC_MAX_CDB_LEN 12 -#define ADV_MAX_CDB_LEN 16 - -#define MS_SDTR_LEN 0x03 -#define MS_WDTR_LEN 0x02 - -#define ASC_SG_LIST_PER_Q 7 -#define QS_FREE 0x00 -#define QS_READY 0x01 -#define QS_DISC1 0x02 -#define QS_DISC2 0x04 -#define QS_BUSY 0x08 -#define QS_ABORTED 0x40 -#define QS_DONE 0x80 -#define QC_NO_CALLBACK 0x01 -#define QC_SG_SWAP_QUEUE 0x02 -#define QC_SG_HEAD 0x04 -#define QC_DATA_IN 0x08 -#define QC_DATA_OUT 0x10 -#define QC_URGENT 0x20 -#define QC_MSG_OUT 0x40 -#define QC_REQ_SENSE 0x80 -#define QCSG_SG_XFER_LIST 0x02 -#define QCSG_SG_XFER_MORE 0x04 -#define QCSG_SG_XFER_END 0x08 -#define QD_IN_PROGRESS 0x00 -#define QD_NO_ERROR 0x01 -#define QD_ABORTED_BY_HOST 0x02 -#define QD_WITH_ERROR 0x04 -#define QD_INVALID_REQUEST 0x80 -#define QD_INVALID_HOST_NUM 0x81 -#define QD_INVALID_DEVICE 0x82 -#define QD_ERR_INTERNAL 0xFF -#define QHSTA_NO_ERROR 0x00 -#define QHSTA_M_SEL_TIMEOUT 0x11 -#define QHSTA_M_DATA_OVER_RUN 0x12 -#define QHSTA_M_DATA_UNDER_RUN 0x12 -#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13 -#define QHSTA_M_BAD_BUS_PHASE_SEQ 0x14 -#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21 -#define QHSTA_D_ASC_DVC_ERROR_CODE_SET 0x22 -#define QHSTA_D_HOST_ABORT_FAILED 0x23 -#define QHSTA_D_EXE_SCSI_Q_FAILED 0x24 -#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25 -#define QHSTA_D_ASPI_NO_BUF_POOL 0x26 -#define QHSTA_M_WTM_TIMEOUT 0x41 -#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42 -#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43 -#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44 -#define QHSTA_M_TARGET_STATUS_BUSY 0x45 -#define QHSTA_M_BAD_TAG_CODE 0x46 -#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY 0x47 -#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48 -#define QHSTA_D_LRAM_CMP_ERROR 0x81 -#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1 -#define ASC_FLAG_SCSIQ_REQ 0x01 -#define ASC_FLAG_BIOS_SCSIQ_REQ 0x02 -#define ASC_FLAG_BIOS_ASYNC_IO 0x04 -#define ASC_FLAG_SRB_LINEAR_ADDR 0x08 -#define ASC_FLAG_WIN16 0x10 -#define ASC_FLAG_WIN32 0x20 -#define ASC_FLAG_ISA_OVER_16MB 0x40 -#define ASC_FLAG_DOS_VM_CALLBACK 0x80 -#define ASC_TAG_FLAG_EXTRA_BYTES 0x10 -#define ASC_TAG_FLAG_DISABLE_DISCONNECT 0x04 -#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX 0x08 -#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40 -#define ASC_SCSIQ_CPY_BEG 4 -#define ASC_SCSIQ_SGHD_CPY_BEG 2 -#define ASC_SCSIQ_B_FWD 0 -#define ASC_SCSIQ_B_BWD 1 -#define ASC_SCSIQ_B_STATUS 2 -#define ASC_SCSIQ_B_QNO 3 -#define ASC_SCSIQ_B_CNTL 4 -#define ASC_SCSIQ_B_SG_QUEUE_CNT 5 -#define ASC_SCSIQ_D_DATA_ADDR 8 -#define ASC_SCSIQ_D_DATA_CNT 12 -#define ASC_SCSIQ_B_SENSE_LEN 20 -#define ASC_SCSIQ_DONE_INFO_BEG 22 -#define ASC_SCSIQ_D_SRBPTR 22 -#define ASC_SCSIQ_B_TARGET_IX 26 -#define ASC_SCSIQ_B_CDB_LEN 28 -#define ASC_SCSIQ_B_TAG_CODE 29 -#define ASC_SCSIQ_W_VM_ID 30 -#define ASC_SCSIQ_DONE_STATUS 32 -#define ASC_SCSIQ_HOST_STATUS 33 -#define ASC_SCSIQ_SCSI_STATUS 34 -#define ASC_SCSIQ_CDB_BEG 36 -#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56 -#define ASC_SCSIQ_DW_REMAIN_XFER_CNT 60 -#define ASC_SCSIQ_B_FIRST_SG_WK_QP 48 -#define ASC_SCSIQ_B_SG_WK_QP 49 -#define ASC_SCSIQ_B_SG_WK_IX 50 -#define ASC_SCSIQ_W_ALT_DC1 52 -#define ASC_SCSIQ_B_LIST_CNT 6 -#define ASC_SCSIQ_B_CUR_LIST_CNT 7 -#define ASC_SGQ_B_SG_CNTL 4 -#define ASC_SGQ_B_SG_HEAD_QP 5 -#define ASC_SGQ_B_SG_LIST_CNT 6 -#define ASC_SGQ_B_SG_CUR_LIST_CNT 7 -#define ASC_SGQ_LIST_BEG 8 -#define ASC_DEF_SCSI1_QNG 4 -#define ASC_MAX_SCSI1_QNG 4 -#define ASC_DEF_SCSI2_QNG 16 -#define ASC_MAX_SCSI2_QNG 32 -#define ASC_TAG_CODE_MASK 0x23 -#define ASC_STOP_REQ_RISC_STOP 0x01 -#define ASC_STOP_ACK_RISC_STOP 0x03 -#define ASC_STOP_CLEAN_UP_BUSY_Q 0x10 -#define ASC_STOP_CLEAN_UP_DISC_Q 0x20 -#define ASC_STOP_HOST_REQ_RISC_HALT 0x40 -#define ASC_TIDLUN_TO_IX(tid, lun) (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<> ASC_SCSI_ID_BITS) & ASC_MAX_LUN) -#define ASC_QNO_TO_QADDR(q_no) ((ASC_QADR_BEG)+((int)(q_no) << 6)) - -typedef struct asc_scsiq_1 { - uchar status; - uchar q_no; - uchar cntl; - uchar sg_queue_cnt; - uchar target_id; - uchar target_lun; - ASC_PADDR data_addr; - ASC_DCNT data_cnt; - ASC_PADDR sense_addr; - uchar sense_len; - uchar extra_bytes; -} ASC_SCSIQ_1; - -typedef struct asc_scsiq_2 { - ASC_VADDR srb_ptr; - uchar target_ix; - uchar flag; - uchar cdb_len; - uchar tag_code; - ushort vm_id; -} ASC_SCSIQ_2; - -typedef struct asc_scsiq_3 { - uchar done_stat; - uchar host_stat; - uchar scsi_stat; - uchar scsi_msg; -} ASC_SCSIQ_3; - -typedef struct asc_scsiq_4 { - uchar cdb[ASC_MAX_CDB_LEN]; - uchar y_first_sg_list_qp; - uchar y_working_sg_qp; - uchar y_working_sg_ix; - uchar y_res; - ushort x_req_count; - ushort x_reconnect_rtn; - ASC_PADDR x_saved_data_addr; - ASC_DCNT x_saved_data_cnt; -} ASC_SCSIQ_4; - -typedef struct asc_q_done_info { - ASC_SCSIQ_2 d2; - ASC_SCSIQ_3 d3; - uchar q_status; - uchar q_no; - uchar cntl; - uchar sense_len; - uchar extra_bytes; - uchar res; - ASC_DCNT remain_bytes; -} ASC_QDONE_INFO; - -typedef struct asc_sg_list { - ASC_PADDR addr; - ASC_DCNT bytes; -} ASC_SG_LIST; - -typedef struct asc_sg_head { - ushort entry_cnt; - ushort queue_cnt; - ushort entry_to_copy; - ushort res; - ASC_SG_LIST sg_list[0]; -} ASC_SG_HEAD; - -typedef struct asc_scsi_q { - ASC_SCSIQ_1 q1; - ASC_SCSIQ_2 q2; - uchar *cdbptr; - ASC_SG_HEAD *sg_head; - ushort remain_sg_entry_cnt; - ushort next_sg_index; -} ASC_SCSI_Q; - -typedef struct asc_scsi_req_q { - ASC_SCSIQ_1 r1; - ASC_SCSIQ_2 r2; - uchar *cdbptr; - ASC_SG_HEAD *sg_head; - uchar *sense_ptr; - ASC_SCSIQ_3 r3; - uchar cdb[ASC_MAX_CDB_LEN]; - uchar sense[ASC_MIN_SENSE_LEN]; -} ASC_SCSI_REQ_Q; - -typedef struct asc_scsi_bios_req_q { - ASC_SCSIQ_1 r1; - ASC_SCSIQ_2 r2; - uchar *cdbptr; - ASC_SG_HEAD *sg_head; - uchar *sense_ptr; - ASC_SCSIQ_3 r3; - uchar cdb[ASC_MAX_CDB_LEN]; - uchar sense[ASC_MIN_SENSE_LEN]; -} ASC_SCSI_BIOS_REQ_Q; - -typedef struct asc_risc_q { - uchar fwd; - uchar bwd; - ASC_SCSIQ_1 i1; - ASC_SCSIQ_2 i2; - ASC_SCSIQ_3 i3; - ASC_SCSIQ_4 i4; -} ASC_RISC_Q; - -typedef struct asc_sg_list_q { - uchar seq_no; - uchar q_no; - uchar cntl; - uchar sg_head_qp; - uchar sg_list_cnt; - uchar sg_cur_list_cnt; -} ASC_SG_LIST_Q; - -typedef struct asc_risc_sg_list_q { - uchar fwd; - uchar bwd; - ASC_SG_LIST_Q sg; - ASC_SG_LIST sg_list[7]; -} ASC_RISC_SG_LIST_Q; - -#define ASCQ_ERR_Q_STATUS 0x0D -#define ASCQ_ERR_CUR_QNG 0x17 -#define ASCQ_ERR_SG_Q_LINKS 0x18 -#define ASCQ_ERR_ISR_RE_ENTRY 0x1A -#define ASCQ_ERR_CRITICAL_RE_ENTRY 0x1B -#define ASCQ_ERR_ISR_ON_CRITICAL 0x1C - -/* - * Warning code values are set in ASC_DVC_VAR 'warn_code'. - */ -#define ASC_WARN_NO_ERROR 0x0000 -#define ASC_WARN_IO_PORT_ROTATE 0x0001 -#define ASC_WARN_EEPROM_CHKSUM 0x0002 -#define ASC_WARN_IRQ_MODIFIED 0x0004 -#define ASC_WARN_AUTO_CONFIG 0x0008 -#define ASC_WARN_CMD_QNG_CONFLICT 0x0010 -#define ASC_WARN_EEPROM_RECOVER 0x0020 -#define ASC_WARN_CFG_MSW_RECOVER 0x0040 - -/* - * Error code values are set in {ASC/ADV}_DVC_VAR 'err_code'. - */ -#define ASC_IERR_NO_CARRIER 0x0001 /* No more carrier memory */ -#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */ -#define ASC_IERR_SET_PC_ADDR 0x0004 -#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */ -#define ASC_IERR_ILLEGAL_CONNECTION 0x0010 /* Illegal cable connection */ -#define ASC_IERR_SINGLE_END_DEVICE 0x0020 /* SE device on DIFF bus */ -#define ASC_IERR_REVERSED_CABLE 0x0040 /* Narrow flat cable reversed */ -#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */ -#define ASC_IERR_HVD_DEVICE 0x0100 /* HVD device on LVD port */ -#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */ -#define ASC_IERR_NO_BUS_TYPE 0x0400 -#define ASC_IERR_BIST_PRE_TEST 0x0800 /* BIST pre-test error */ -#define ASC_IERR_BIST_RAM_TEST 0x1000 /* BIST RAM test error */ -#define ASC_IERR_BAD_CHIPTYPE 0x2000 /* Invalid chip_type setting */ - -#define ASC_DEF_MAX_TOTAL_QNG (0xF0) -#define ASC_MIN_TAG_Q_PER_DVC (0x04) -#define ASC_MIN_FREE_Q (0x02) -#define ASC_MIN_TOTAL_QNG ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q)) -#define ASC_MAX_TOTAL_QNG 240 -#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16 -#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG 8 -#define ASC_MAX_PCI_INRAM_TOTAL_QNG 20 -#define ASC_MAX_INRAM_TAG_QNG 16 -#define ASC_IOADR_GAP 0x10 -#define ASC_SYN_MAX_OFFSET 0x0F -#define ASC_DEF_SDTR_OFFSET 0x0F -#define ASC_SDTR_ULTRA_PCI_10MB_INDEX 0x02 -#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41 - -/* The narrow chip only supports a limited selection of transfer rates. - * These are encoded in the range 0..7 or 0..15 depending whether the chip - * is Ultra-capable or not. These tables let us convert from one to the other. - */ -static const unsigned char asc_syn_xfer_period[8] = { - 25, 30, 35, 40, 50, 60, 70, 85 -}; - -static const unsigned char asc_syn_ultra_xfer_period[16] = { - 12, 19, 25, 32, 38, 44, 50, 57, 63, 69, 75, 82, 88, 94, 100, 107 -}; - -typedef struct ext_msg { - uchar msg_type; - uchar msg_len; - uchar msg_req; - union { - struct { - uchar sdtr_xfer_period; - uchar sdtr_req_ack_offset; - } sdtr; - struct { - uchar wdtr_width; - } wdtr; - struct { - uchar mdp_b3; - uchar mdp_b2; - uchar mdp_b1; - uchar mdp_b0; - } mdp; - } u_ext_msg; - uchar res; -} EXT_MSG; - -#define xfer_period u_ext_msg.sdtr.sdtr_xfer_period -#define req_ack_offset u_ext_msg.sdtr.sdtr_req_ack_offset -#define wdtr_width u_ext_msg.wdtr.wdtr_width -#define mdp_b3 u_ext_msg.mdp_b3 -#define mdp_b2 u_ext_msg.mdp_b2 -#define mdp_b1 u_ext_msg.mdp_b1 -#define mdp_b0 u_ext_msg.mdp_b0 - -typedef struct asc_dvc_cfg { - ASC_SCSI_BIT_ID_TYPE can_tagged_qng; - ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled; - ASC_SCSI_BIT_ID_TYPE disc_enable; - ASC_SCSI_BIT_ID_TYPE sdtr_enable; - uchar chip_scsi_id; - uchar isa_dma_speed; - uchar isa_dma_channel; - uchar chip_version; - ushort mcode_date; - ushort mcode_version; - uchar max_tag_qng[ASC_MAX_TID + 1]; - uchar sdtr_period_offset[ASC_MAX_TID + 1]; - uchar adapter_info[6]; -} ASC_DVC_CFG; - -#define ASC_DEF_DVC_CNTL 0xFFFF -#define ASC_DEF_CHIP_SCSI_ID 7 -#define ASC_DEF_ISA_DMA_SPEED 4 -#define ASC_INIT_STATE_BEG_GET_CFG 0x0001 -#define ASC_INIT_STATE_END_GET_CFG 0x0002 -#define ASC_INIT_STATE_BEG_SET_CFG 0x0004 -#define ASC_INIT_STATE_END_SET_CFG 0x0008 -#define ASC_INIT_STATE_BEG_LOAD_MC 0x0010 -#define ASC_INIT_STATE_END_LOAD_MC 0x0020 -#define ASC_INIT_STATE_BEG_INQUIRY 0x0040 -#define ASC_INIT_STATE_END_INQUIRY 0x0080 -#define ASC_INIT_RESET_SCSI_DONE 0x0100 -#define ASC_INIT_STATE_WITHOUT_EEP 0x8000 -#define ASC_BUG_FIX_IF_NOT_DWB 0x0001 -#define ASC_BUG_FIX_ASYN_USE_SYN 0x0002 -#define ASC_MIN_TAGGED_CMD 7 -#define ASC_MAX_SCSI_RESET_WAIT 30 -#define ASC_OVERRUN_BSIZE 64 - -struct asc_dvc_var; /* Forward Declaration. */ - -typedef struct asc_dvc_var { - PortAddr iop_base; - ushort err_code; - ushort dvc_cntl; - ushort bug_fix_cntl; - ushort bus_type; - ASC_SCSI_BIT_ID_TYPE init_sdtr; - ASC_SCSI_BIT_ID_TYPE sdtr_done; - ASC_SCSI_BIT_ID_TYPE use_tagged_qng; - ASC_SCSI_BIT_ID_TYPE unit_not_ready; - ASC_SCSI_BIT_ID_TYPE queue_full_or_busy; - ASC_SCSI_BIT_ID_TYPE start_motor; - uchar *overrun_buf; - dma_addr_t overrun_dma; - uchar scsi_reset_wait; - uchar chip_no; - char is_in_int; - uchar max_total_qng; - uchar cur_total_qng; - uchar in_critical_cnt; - uchar last_q_shortage; - ushort init_state; - uchar cur_dvc_qng[ASC_MAX_TID + 1]; - uchar max_dvc_qng[ASC_MAX_TID + 1]; - ASC_SCSI_Q *scsiq_busy_head[ASC_MAX_TID + 1]; - ASC_SCSI_Q *scsiq_busy_tail[ASC_MAX_TID + 1]; - const uchar *sdtr_period_tbl; - ASC_DVC_CFG *cfg; - ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always; - char redo_scam; - ushort res2; - uchar dos_int13_table[ASC_MAX_TID + 1]; - ASC_DCNT max_dma_count; - ASC_SCSI_BIT_ID_TYPE no_scam; - ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer; - uchar min_sdtr_index; - uchar max_sdtr_index; - struct asc_board *drv_ptr; - int ptr_map_count; - void **ptr_map; - ASC_DCNT uc_break; -} ASC_DVC_VAR; - -typedef struct asc_dvc_inq_info { - uchar type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1]; -} ASC_DVC_INQ_INFO; - -typedef struct asc_cap_info { - ASC_DCNT lba; - ASC_DCNT blk_size; -} ASC_CAP_INFO; - -typedef struct asc_cap_info_array { - ASC_CAP_INFO cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1]; -} ASC_CAP_INFO_ARRAY; - -#define ASC_MCNTL_NO_SEL_TIMEOUT (ushort)0x0001 -#define ASC_MCNTL_NULL_TARGET (ushort)0x0002 -#define ASC_CNTL_INITIATOR (ushort)0x0001 -#define ASC_CNTL_BIOS_GT_1GB (ushort)0x0002 -#define ASC_CNTL_BIOS_GT_2_DISK (ushort)0x0004 -#define ASC_CNTL_BIOS_REMOVABLE (ushort)0x0008 -#define ASC_CNTL_NO_SCAM (ushort)0x0010 -#define ASC_CNTL_INT_MULTI_Q (ushort)0x0080 -#define ASC_CNTL_NO_LUN_SUPPORT (ushort)0x0040 -#define ASC_CNTL_NO_VERIFY_COPY (ushort)0x0100 -#define ASC_CNTL_RESET_SCSI (ushort)0x0200 -#define ASC_CNTL_INIT_INQUIRY (ushort)0x0400 -#define ASC_CNTL_INIT_VERBOSE (ushort)0x0800 -#define ASC_CNTL_SCSI_PARITY (ushort)0x1000 -#define ASC_CNTL_BURST_MODE (ushort)0x2000 -#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000 -#define ASC_EEP_DVC_CFG_BEG_VL 2 -#define ASC_EEP_MAX_DVC_ADDR_VL 15 -#define ASC_EEP_DVC_CFG_BEG 32 -#define ASC_EEP_MAX_DVC_ADDR 45 -#define ASC_EEP_MAX_RETRY 20 - -/* - * These macros keep the chip SCSI id and ISA DMA speed - * bitfields in board order. C bitfields aren't portable - * between big and little-endian platforms so they are - * not used. - */ - -#define ASC_EEP_GET_CHIP_ID(cfg) ((cfg)->id_speed & 0x0f) -#define ASC_EEP_GET_DMA_SPD(cfg) (((cfg)->id_speed & 0xf0) >> 4) -#define ASC_EEP_SET_CHIP_ID(cfg, sid) \ - ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID)) -#define ASC_EEP_SET_DMA_SPD(cfg, spd) \ - ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4) - -typedef struct asceep_config { - ushort cfg_lsw; - ushort cfg_msw; - uchar init_sdtr; - uchar disc_enable; - uchar use_cmd_qng; - uchar start_motor; - uchar max_total_qng; - uchar max_tag_qng; - uchar bios_scan; - uchar power_up_wait; - uchar no_scam; - uchar id_speed; /* low order 4 bits is chip scsi id */ - /* high order 4 bits is isa dma speed */ - uchar dos_int13_table[ASC_MAX_TID + 1]; - uchar adapter_info[6]; - ushort cntl; - ushort chksum; -} ASCEEP_CONFIG; - -#define ASC_EEP_CMD_READ 0x80 -#define ASC_EEP_CMD_WRITE 0x40 -#define ASC_EEP_CMD_WRITE_ABLE 0x30 -#define ASC_EEP_CMD_WRITE_DISABLE 0x00 -#define ASCV_MSGOUT_BEG 0x0000 -#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3) -#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4) -#define ASCV_BREAK_SAVED_CODE (ushort)0x0006 -#define ASCV_MSGIN_BEG (ASCV_MSGOUT_BEG+8) -#define ASCV_MSGIN_SDTR_PERIOD (ASCV_MSGIN_BEG+3) -#define ASCV_MSGIN_SDTR_OFFSET (ASCV_MSGIN_BEG+4) -#define ASCV_SDTR_DATA_BEG (ASCV_MSGIN_BEG+8) -#define ASCV_SDTR_DONE_BEG (ASCV_SDTR_DATA_BEG+8) -#define ASCV_MAX_DVC_QNG_BEG (ushort)0x0020 -#define ASCV_BREAK_ADDR (ushort)0x0028 -#define ASCV_BREAK_NOTIFY_COUNT (ushort)0x002A -#define ASCV_BREAK_CONTROL (ushort)0x002C -#define ASCV_BREAK_HIT_COUNT (ushort)0x002E - -#define ASCV_ASCDVC_ERR_CODE_W (ushort)0x0030 -#define ASCV_MCODE_CHKSUM_W (ushort)0x0032 -#define ASCV_MCODE_SIZE_W (ushort)0x0034 -#define ASCV_STOP_CODE_B (ushort)0x0036 -#define ASCV_DVC_ERR_CODE_B (ushort)0x0037 -#define ASCV_OVERRUN_PADDR_D (ushort)0x0038 -#define ASCV_OVERRUN_BSIZE_D (ushort)0x003C -#define ASCV_HALTCODE_W (ushort)0x0040 -#define ASCV_CHKSUM_W (ushort)0x0042 -#define ASCV_MC_DATE_W (ushort)0x0044 -#define ASCV_MC_VER_W (ushort)0x0046 -#define ASCV_NEXTRDY_B (ushort)0x0048 -#define ASCV_DONENEXT_B (ushort)0x0049 -#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A -#define ASCV_SCSIBUSY_B (ushort)0x004B -#define ASCV_Q_DONE_IN_PROGRESS_B (ushort)0x004C -#define ASCV_CURCDB_B (ushort)0x004D -#define ASCV_RCLUN_B (ushort)0x004E -#define ASCV_BUSY_QHEAD_B (ushort)0x004F -#define ASCV_DISC1_QHEAD_B (ushort)0x0050 -#define ASCV_DISC_ENABLE_B (ushort)0x0052 -#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053 -#define ASCV_HOSTSCSI_ID_B (ushort)0x0055 -#define ASCV_MCODE_CNTL_B (ushort)0x0056 -#define ASCV_NULL_TARGET_B (ushort)0x0057 -#define ASCV_FREE_Q_HEAD_W (ushort)0x0058 -#define ASCV_DONE_Q_TAIL_W (ushort)0x005A -#define ASCV_FREE_Q_HEAD_B (ushort)(ASCV_FREE_Q_HEAD_W+1) -#define ASCV_DONE_Q_TAIL_B (ushort)(ASCV_DONE_Q_TAIL_W+1) -#define ASCV_HOST_FLAG_B (ushort)0x005D -#define ASCV_TOTAL_READY_Q_B (ushort)0x0064 -#define ASCV_VER_SERIAL_B (ushort)0x0065 -#define ASCV_HALTCODE_SAVED_W (ushort)0x0066 -#define ASCV_WTM_FLAG_B (ushort)0x0068 -#define ASCV_RISC_FLAG_B (ushort)0x006A -#define ASCV_REQ_SG_LIST_QP (ushort)0x006B -#define ASC_HOST_FLAG_IN_ISR 0x01 -#define ASC_HOST_FLAG_ACK_INT 0x02 -#define ASC_RISC_FLAG_GEN_INT 0x01 -#define ASC_RISC_FLAG_REQ_SG_LIST 0x02 -#define IOP_CTRL (0x0F) -#define IOP_STATUS (0x0E) -#define IOP_INT_ACK IOP_STATUS -#define IOP_REG_IFC (0x0D) -#define IOP_SYN_OFFSET (0x0B) -#define IOP_EXTRA_CONTROL (0x0D) -#define IOP_REG_PC (0x0C) -#define IOP_RAM_ADDR (0x0A) -#define IOP_RAM_DATA (0x08) -#define IOP_EEP_DATA (0x06) -#define IOP_EEP_CMD (0x07) -#define IOP_VERSION (0x03) -#define IOP_CONFIG_HIGH (0x04) -#define IOP_CONFIG_LOW (0x02) -#define IOP_SIG_BYTE (0x01) -#define IOP_SIG_WORD (0x00) -#define IOP_REG_DC1 (0x0E) -#define IOP_REG_DC0 (0x0C) -#define IOP_REG_SB (0x0B) -#define IOP_REG_DA1 (0x0A) -#define IOP_REG_DA0 (0x08) -#define IOP_REG_SC (0x09) -#define IOP_DMA_SPEED (0x07) -#define IOP_REG_FLAG (0x07) -#define IOP_FIFO_H (0x06) -#define IOP_FIFO_L (0x04) -#define IOP_REG_ID (0x05) -#define IOP_REG_QP (0x03) -#define IOP_REG_IH (0x02) -#define IOP_REG_IX (0x01) -#define IOP_REG_AX (0x00) -#define IFC_REG_LOCK (0x00) -#define IFC_REG_UNLOCK (0x09) -#define IFC_WR_EN_FILTER (0x10) -#define IFC_RD_NO_EEPROM (0x10) -#define IFC_SLEW_RATE (0x20) -#define IFC_ACT_NEG (0x40) -#define IFC_INP_FILTER (0x80) -#define IFC_INIT_DEFAULT (IFC_ACT_NEG | IFC_REG_UNLOCK) -#define SC_SEL (uchar)(0x80) -#define SC_BSY (uchar)(0x40) -#define SC_ACK (uchar)(0x20) -#define SC_REQ (uchar)(0x10) -#define SC_ATN (uchar)(0x08) -#define SC_IO (uchar)(0x04) -#define SC_CD (uchar)(0x02) -#define SC_MSG (uchar)(0x01) -#define SEC_SCSI_CTL (uchar)(0x80) -#define SEC_ACTIVE_NEGATE (uchar)(0x40) -#define SEC_SLEW_RATE (uchar)(0x20) -#define SEC_ENABLE_FILTER (uchar)(0x10) -#define ASC_HALT_EXTMSG_IN (ushort)0x8000 -#define ASC_HALT_CHK_CONDITION (ushort)0x8100 -#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200 -#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX (ushort)0x8300 -#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX (ushort)0x8400 -#define ASC_HALT_SDTR_REJECTED (ushort)0x4000 -#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000 -#define ASC_MAX_QNO 0xF8 -#define ASC_DATA_SEC_BEG (ushort)0x0080 -#define ASC_DATA_SEC_END (ushort)0x0080 -#define ASC_CODE_SEC_BEG (ushort)0x0080 -#define ASC_CODE_SEC_END (ushort)0x0080 -#define ASC_QADR_BEG (0x4000) -#define ASC_QADR_USED (ushort)(ASC_MAX_QNO * 64) -#define ASC_QADR_END (ushort)0x7FFF -#define ASC_QLAST_ADR (ushort)0x7FC0 -#define ASC_QBLK_SIZE 0x40 -#define ASC_BIOS_DATA_QBEG 0xF8 -#define ASC_MIN_ACTIVE_QNO 0x01 -#define ASC_QLINK_END 0xFF -#define ASC_EEPROM_WORDS 0x10 -#define ASC_MAX_MGS_LEN 0x10 -#define ASC_BIOS_ADDR_DEF 0xDC00 -#define ASC_BIOS_SIZE 0x3800 -#define ASC_BIOS_RAM_OFF 0x3800 -#define ASC_BIOS_RAM_SIZE 0x800 -#define ASC_BIOS_MIN_ADDR 0xC000 -#define ASC_BIOS_MAX_ADDR 0xEC00 -#define ASC_BIOS_BANK_SIZE 0x0400 -#define ASC_MCODE_START_ADDR 0x0080 -#define ASC_CFG0_HOST_INT_ON 0x0020 -#define ASC_CFG0_BIOS_ON 0x0040 -#define ASC_CFG0_VERA_BURST_ON 0x0080 -#define ASC_CFG0_SCSI_PARITY_ON 0x0800 -#define ASC_CFG1_SCSI_TARGET_ON 0x0080 -#define ASC_CFG1_LRAM_8BITS_ON 0x0800 -#define ASC_CFG_MSW_CLR_MASK 0x3080 -#define CSW_TEST1 (ASC_CS_TYPE)0x8000 -#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000 -#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000 -#define CSW_IRQ_WRITTEN (ASC_CS_TYPE)0x1000 -#define CSW_33MHZ_SELECTED (ASC_CS_TYPE)0x0800 -#define CSW_TEST2 (ASC_CS_TYPE)0x0400 -#define CSW_TEST3 (ASC_CS_TYPE)0x0200 -#define CSW_RESERVED2 (ASC_CS_TYPE)0x0100 -#define CSW_DMA_DONE (ASC_CS_TYPE)0x0080 -#define CSW_FIFO_RDY (ASC_CS_TYPE)0x0040 -#define CSW_EEP_READ_DONE (ASC_CS_TYPE)0x0020 -#define CSW_HALTED (ASC_CS_TYPE)0x0010 -#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008 -#define CSW_PARITY_ERR (ASC_CS_TYPE)0x0004 -#define CSW_SCSI_RESET_LATCH (ASC_CS_TYPE)0x0002 -#define CSW_INT_PENDING (ASC_CS_TYPE)0x0001 -#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000 -#define CIW_INT_ACK (ASC_CS_TYPE)0x0100 -#define CIW_TEST1 (ASC_CS_TYPE)0x0200 -#define CIW_TEST2 (ASC_CS_TYPE)0x0400 -#define CIW_SEL_33MHZ (ASC_CS_TYPE)0x0800 -#define CIW_IRQ_ACT (ASC_CS_TYPE)0x1000 -#define CC_CHIP_RESET (uchar)0x80 -#define CC_SCSI_RESET (uchar)0x40 -#define CC_HALT (uchar)0x20 -#define CC_SINGLE_STEP (uchar)0x10 -#define CC_DMA_ABLE (uchar)0x08 -#define CC_TEST (uchar)0x04 -#define CC_BANK_ONE (uchar)0x02 -#define CC_DIAG (uchar)0x01 -#define ASC_1000_ID0W 0x04C1 -#define ASC_1000_ID0W_FIX 0x00C1 -#define ASC_1000_ID1B 0x25 -#define ASC_EISA_REV_IOP_MASK (0x0C83) -#define ASC_EISA_CFG_IOP_MASK (0x0C86) -#define ASC_GET_EISA_SLOT(iop) (PortAddr)((iop) & 0xF000) -#define INS_HALTINT (ushort)0x6281 -#define INS_HALT (ushort)0x6280 -#define INS_SINT (ushort)0x6200 -#define INS_RFLAG_WTM (ushort)0x7380 -#define ASC_MC_SAVE_CODE_WSIZE 0x500 -#define ASC_MC_SAVE_DATA_WSIZE 0x40 - -typedef struct asc_mc_saved { - ushort data[ASC_MC_SAVE_DATA_WSIZE]; - ushort code[ASC_MC_SAVE_CODE_WSIZE]; -} ASC_MC_SAVED; - -#define AscGetQDoneInProgress(port) AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B) -#define AscPutQDoneInProgress(port, val) AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val) -#define AscGetVarFreeQHead(port) AscReadLramWord((port), ASCV_FREE_Q_HEAD_W) -#define AscGetVarDoneQTail(port) AscReadLramWord((port), ASCV_DONE_Q_TAIL_W) -#define AscPutVarFreeQHead(port, val) AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val) -#define AscPutVarDoneQTail(port, val) AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val) -#define AscGetRiscVarFreeQHead(port) AscReadLramByte((port), ASCV_NEXTRDY_B) -#define AscGetRiscVarDoneQTail(port) AscReadLramByte((port), ASCV_DONENEXT_B) -#define AscPutRiscVarFreeQHead(port, val) AscWriteLramByte((port), ASCV_NEXTRDY_B, val) -#define AscPutRiscVarDoneQTail(port, val) AscWriteLramByte((port), ASCV_DONENEXT_B, val) -#define AscPutMCodeSDTRDoneAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data)) -#define AscGetMCodeSDTRDoneAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id)) -#define AscPutMCodeInitSDTRAtID(port, id, data) AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data) -#define AscGetMCodeInitSDTRAtID(port, id) AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id)) -#define AscGetChipSignatureByte(port) (uchar)inp((port)+IOP_SIG_BYTE) -#define AscGetChipSignatureWord(port) (ushort)inpw((port)+IOP_SIG_WORD) -#define AscGetChipVerNo(port) (uchar)inp((port)+IOP_VERSION) -#define AscGetChipCfgLsw(port) (ushort)inpw((port)+IOP_CONFIG_LOW) -#define AscGetChipCfgMsw(port) (ushort)inpw((port)+IOP_CONFIG_HIGH) -#define AscSetChipCfgLsw(port, data) outpw((port)+IOP_CONFIG_LOW, data) -#define AscSetChipCfgMsw(port, data) outpw((port)+IOP_CONFIG_HIGH, data) -#define AscGetChipEEPCmd(port) (uchar)inp((port)+IOP_EEP_CMD) -#define AscSetChipEEPCmd(port, data) outp((port)+IOP_EEP_CMD, data) -#define AscGetChipEEPData(port) (ushort)inpw((port)+IOP_EEP_DATA) -#define AscSetChipEEPData(port, data) outpw((port)+IOP_EEP_DATA, data) -#define AscGetChipLramAddr(port) (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR)) -#define AscSetChipLramAddr(port, addr) outpw((PortAddr)((port)+IOP_RAM_ADDR), addr) -#define AscGetChipLramData(port) (ushort)inpw((port)+IOP_RAM_DATA) -#define AscSetChipLramData(port, data) outpw((port)+IOP_RAM_DATA, data) -#define AscGetChipIFC(port) (uchar)inp((port)+IOP_REG_IFC) -#define AscSetChipIFC(port, data) outp((port)+IOP_REG_IFC, data) -#define AscGetChipStatus(port) (ASC_CS_TYPE)inpw((port)+IOP_STATUS) -#define AscSetChipStatus(port, cs_val) outpw((port)+IOP_STATUS, cs_val) -#define AscGetChipControl(port) (uchar)inp((port)+IOP_CTRL) -#define AscSetChipControl(port, cc_val) outp((port)+IOP_CTRL, cc_val) -#define AscGetChipSyn(port) (uchar)inp((port)+IOP_SYN_OFFSET) -#define AscSetChipSyn(port, data) outp((port)+IOP_SYN_OFFSET, data) -#define AscSetPCAddr(port, data) outpw((port)+IOP_REG_PC, data) -#define AscGetPCAddr(port) (ushort)inpw((port)+IOP_REG_PC) -#define AscIsIntPending(port) (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH)) -#define AscGetChipScsiID(port) ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID) -#define AscGetExtraControl(port) (uchar)inp((port)+IOP_EXTRA_CONTROL) -#define AscSetExtraControl(port, data) outp((port)+IOP_EXTRA_CONTROL, data) -#define AscReadChipAX(port) (ushort)inpw((port)+IOP_REG_AX) -#define AscWriteChipAX(port, data) outpw((port)+IOP_REG_AX, data) -#define AscReadChipIX(port) (uchar)inp((port)+IOP_REG_IX) -#define AscWriteChipIX(port, data) outp((port)+IOP_REG_IX, data) -#define AscReadChipIH(port) (ushort)inpw((port)+IOP_REG_IH) -#define AscWriteChipIH(port, data) outpw((port)+IOP_REG_IH, data) -#define AscReadChipQP(port) (uchar)inp((port)+IOP_REG_QP) -#define AscWriteChipQP(port, data) outp((port)+IOP_REG_QP, data) -#define AscReadChipFIFO_L(port) (ushort)inpw((port)+IOP_REG_FIFO_L) -#define AscWriteChipFIFO_L(port, data) outpw((port)+IOP_REG_FIFO_L, data) -#define AscReadChipFIFO_H(port) (ushort)inpw((port)+IOP_REG_FIFO_H) -#define AscWriteChipFIFO_H(port, data) outpw((port)+IOP_REG_FIFO_H, data) -#define AscReadChipDmaSpeed(port) (uchar)inp((port)+IOP_DMA_SPEED) -#define AscWriteChipDmaSpeed(port, data) outp((port)+IOP_DMA_SPEED, data) -#define AscReadChipDA0(port) (ushort)inpw((port)+IOP_REG_DA0) -#define AscWriteChipDA0(port) outpw((port)+IOP_REG_DA0, data) -#define AscReadChipDA1(port) (ushort)inpw((port)+IOP_REG_DA1) -#define AscWriteChipDA1(port) outpw((port)+IOP_REG_DA1, data) -#define AscReadChipDC0(port) (ushort)inpw((port)+IOP_REG_DC0) -#define AscWriteChipDC0(port) outpw((port)+IOP_REG_DC0, data) -#define AscReadChipDC1(port) (ushort)inpw((port)+IOP_REG_DC1) -#define AscWriteChipDC1(port) outpw((port)+IOP_REG_DC1, data) -#define AscReadChipDvcID(port) (uchar)inp((port)+IOP_REG_ID) -#define AscWriteChipDvcID(port, data) outp((port)+IOP_REG_ID, data) - -/* - * Portable Data Types - * - * Any instance where a 32-bit long or pointer type is assumed - * for precision or HW defined structures, the following define - * types must be used. In Linux the char, short, and int types - * are all consistent at 8, 16, and 32 bits respectively. Pointers - * and long types are 64 bits on Alpha and UltraSPARC. - */ -#define ADV_PADDR __u32 /* Physical address data type. */ -#define ADV_VADDR __u32 /* Virtual address data type. */ -#define ADV_DCNT __u32 /* Unsigned Data count type. */ -#define ADV_SDCNT __s32 /* Signed Data count type. */ - -/* - * These macros are used to convert a virtual address to a - * 32-bit value. This currently can be used on Linux Alpha - * which uses 64-bit virtual address but a 32-bit bus address. - * This is likely to break in the future, but doing this now - * will give us time to change the HW and FW to handle 64-bit - * addresses. - */ -#define ADV_VADDR_TO_U32 virt_to_bus -#define ADV_U32_TO_VADDR bus_to_virt - -#define AdvPortAddr void __iomem * /* Virtual memory address size */ - -/* - * Define Adv Library required memory access macros. - */ -#define ADV_MEM_READB(addr) readb(addr) -#define ADV_MEM_READW(addr) readw(addr) -#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr) -#define ADV_MEM_WRITEW(addr, word) writew(word, addr) -#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr) - -#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15) - -/* - * Define total number of simultaneous maximum element scatter-gather - * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the - * maximum number of outstanding commands per wide host adapter. Each - * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather - * elements. Allow each command to have at least one ADV_SG_BLOCK structure. - * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK - * structures or 255 scatter-gather elements. - */ -#define ADV_TOT_SG_BLOCK ASC_DEF_MAX_HOST_QNG - -/* - * Define maximum number of scatter-gather elements per request. - */ -#define ADV_MAX_SG_LIST 255 -#define NO_OF_SG_PER_BLOCK 15 - -#define ADV_EEP_DVC_CFG_BEGIN (0x00) -#define ADV_EEP_DVC_CFG_END (0x15) -#define ADV_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */ -#define ADV_EEP_MAX_WORD_ADDR (0x1E) - -#define ADV_EEP_DELAY_MS 100 - -#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */ -#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */ -/* - * For the ASC3550 Bit 13 is Termination Polarity control bit. - * For later ICs Bit 13 controls whether the CIS (Card Information - * Service Section) is loaded from EEPROM. - */ -#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */ -#define ADV_EEPROM_CIS_LD 0x2000 /* EEPROM Bit 13 */ -/* - * ASC38C1600 Bit 11 - * - * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify - * INT A in the PCI Configuration Space Int Pin field. If it is 1, then - * Function 0 will specify INT B. - * - * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify - * INT B in the PCI Configuration Space Int Pin field. If it is 1, then - * Function 1 will specify INT A. - */ -#define ADV_EEPROM_INTAB 0x0800 /* EEPROM Bit 11 */ - -typedef struct adveep_3550_config { - /* Word Offset, Description */ - - ushort cfg_lsw; /* 00 power up initialization */ - /* bit 13 set - Term Polarity Control */ - /* bit 14 set - BIOS Enable */ - /* bit 15 set - Big Endian Mode */ - ushort cfg_msw; /* 01 unused */ - ushort disc_enable; /* 02 disconnect enable */ - ushort wdtr_able; /* 03 Wide DTR able */ - ushort sdtr_able; /* 04 Synchronous DTR able */ - ushort start_motor; /* 05 send start up motor */ - ushort tagqng_able; /* 06 tag queuing able */ - ushort bios_scan; /* 07 BIOS device control */ - ushort scam_tolerant; /* 08 no scam */ - - uchar adapter_scsi_id; /* 09 Host Adapter ID */ - uchar bios_boot_delay; /* power up wait */ - - uchar scsi_reset_delay; /* 10 reset delay */ - uchar bios_id_lun; /* first boot device scsi id & lun */ - /* high nibble is lun */ - /* low nibble is scsi id */ - - uchar termination; /* 11 0 - automatic */ - /* 1 - low off / high off */ - /* 2 - low off / high on */ - /* 3 - low on / high on */ - /* There is no low on / high off */ - - uchar reserved1; /* reserved byte (not used) */ - - ushort bios_ctrl; /* 12 BIOS control bits */ - /* bit 0 BIOS don't act as initiator. */ - /* bit 1 BIOS > 1 GB support */ - /* bit 2 BIOS > 2 Disk Support */ - /* bit 3 BIOS don't support removables */ - /* bit 4 BIOS support bootable CD */ - /* bit 5 BIOS scan enabled */ - /* bit 6 BIOS support multiple LUNs */ - /* bit 7 BIOS display of message */ - /* bit 8 SCAM disabled */ - /* bit 9 Reset SCSI bus during init. */ - /* bit 10 */ - /* bit 11 No verbose initialization. */ - /* bit 12 SCSI parity enabled */ - /* bit 13 */ - /* bit 14 */ - /* bit 15 */ - ushort ultra_able; /* 13 ULTRA speed able */ - ushort reserved2; /* 14 reserved */ - uchar max_host_qng; /* 15 maximum host queuing */ - uchar max_dvc_qng; /* maximum per device queuing */ - ushort dvc_cntl; /* 16 control bit for driver */ - ushort bug_fix; /* 17 control bit for bug fix */ - ushort serial_number_word1; /* 18 Board serial number word 1 */ - ushort serial_number_word2; /* 19 Board serial number word 2 */ - ushort serial_number_word3; /* 20 Board serial number word 3 */ - ushort check_sum; /* 21 EEP check sum */ - uchar oem_name[16]; /* 22 OEM name */ - ushort dvc_err_code; /* 30 last device driver error code */ - ushort adv_err_code; /* 31 last uc and Adv Lib error code */ - ushort adv_err_addr; /* 32 last uc error address */ - ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ - ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ - ushort saved_adv_err_addr; /* 35 saved last uc error address */ - ushort num_of_err; /* 36 number of error */ -} ADVEEP_3550_CONFIG; - -typedef struct adveep_38C0800_config { - /* Word Offset, Description */ - - ushort cfg_lsw; /* 00 power up initialization */ - /* bit 13 set - Load CIS */ - /* bit 14 set - BIOS Enable */ - /* bit 15 set - Big Endian Mode */ - ushort cfg_msw; /* 01 unused */ - ushort disc_enable; /* 02 disconnect enable */ - ushort wdtr_able; /* 03 Wide DTR able */ - ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */ - ushort start_motor; /* 05 send start up motor */ - ushort tagqng_able; /* 06 tag queuing able */ - ushort bios_scan; /* 07 BIOS device control */ - ushort scam_tolerant; /* 08 no scam */ - - uchar adapter_scsi_id; /* 09 Host Adapter ID */ - uchar bios_boot_delay; /* power up wait */ - - uchar scsi_reset_delay; /* 10 reset delay */ - uchar bios_id_lun; /* first boot device scsi id & lun */ - /* high nibble is lun */ - /* low nibble is scsi id */ - - uchar termination_se; /* 11 0 - automatic */ - /* 1 - low off / high off */ - /* 2 - low off / high on */ - /* 3 - low on / high on */ - /* There is no low on / high off */ - - uchar termination_lvd; /* 11 0 - automatic */ - /* 1 - low off / high off */ - /* 2 - low off / high on */ - /* 3 - low on / high on */ - /* There is no low on / high off */ - - ushort bios_ctrl; /* 12 BIOS control bits */ - /* bit 0 BIOS don't act as initiator. */ - /* bit 1 BIOS > 1 GB support */ - /* bit 2 BIOS > 2 Disk Support */ - /* bit 3 BIOS don't support removables */ - /* bit 4 BIOS support bootable CD */ - /* bit 5 BIOS scan enabled */ - /* bit 6 BIOS support multiple LUNs */ - /* bit 7 BIOS display of message */ - /* bit 8 SCAM disabled */ - /* bit 9 Reset SCSI bus during init. */ - /* bit 10 */ - /* bit 11 No verbose initialization. */ - /* bit 12 SCSI parity enabled */ - /* bit 13 */ - /* bit 14 */ - /* bit 15 */ - ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */ - ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */ - uchar max_host_qng; /* 15 maximum host queueing */ - uchar max_dvc_qng; /* maximum per device queuing */ - ushort dvc_cntl; /* 16 control bit for driver */ - ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */ - ushort serial_number_word1; /* 18 Board serial number word 1 */ - ushort serial_number_word2; /* 19 Board serial number word 2 */ - ushort serial_number_word3; /* 20 Board serial number word 3 */ - ushort check_sum; /* 21 EEP check sum */ - uchar oem_name[16]; /* 22 OEM name */ - ushort dvc_err_code; /* 30 last device driver error code */ - ushort adv_err_code; /* 31 last uc and Adv Lib error code */ - ushort adv_err_addr; /* 32 last uc error address */ - ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ - ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ - ushort saved_adv_err_addr; /* 35 saved last uc error address */ - ushort reserved36; /* 36 reserved */ - ushort reserved37; /* 37 reserved */ - ushort reserved38; /* 38 reserved */ - ushort reserved39; /* 39 reserved */ - ushort reserved40; /* 40 reserved */ - ushort reserved41; /* 41 reserved */ - ushort reserved42; /* 42 reserved */ - ushort reserved43; /* 43 reserved */ - ushort reserved44; /* 44 reserved */ - ushort reserved45; /* 45 reserved */ - ushort reserved46; /* 46 reserved */ - ushort reserved47; /* 47 reserved */ - ushort reserved48; /* 48 reserved */ - ushort reserved49; /* 49 reserved */ - ushort reserved50; /* 50 reserved */ - ushort reserved51; /* 51 reserved */ - ushort reserved52; /* 52 reserved */ - ushort reserved53; /* 53 reserved */ - ushort reserved54; /* 54 reserved */ - ushort reserved55; /* 55 reserved */ - ushort cisptr_lsw; /* 56 CIS PTR LSW */ - ushort cisprt_msw; /* 57 CIS PTR MSW */ - ushort subsysvid; /* 58 SubSystem Vendor ID */ - ushort subsysid; /* 59 SubSystem ID */ - ushort reserved60; /* 60 reserved */ - ushort reserved61; /* 61 reserved */ - ushort reserved62; /* 62 reserved */ - ushort reserved63; /* 63 reserved */ -} ADVEEP_38C0800_CONFIG; - -typedef struct adveep_38C1600_config { - /* Word Offset, Description */ - - ushort cfg_lsw; /* 00 power up initialization */ - /* bit 11 set - Func. 0 INTB, Func. 1 INTA */ - /* clear - Func. 0 INTA, Func. 1 INTB */ - /* bit 13 set - Load CIS */ - /* bit 14 set - BIOS Enable */ - /* bit 15 set - Big Endian Mode */ - ushort cfg_msw; /* 01 unused */ - ushort disc_enable; /* 02 disconnect enable */ - ushort wdtr_able; /* 03 Wide DTR able */ - ushort sdtr_speed1; /* 04 SDTR Speed TID 0-3 */ - ushort start_motor; /* 05 send start up motor */ - ushort tagqng_able; /* 06 tag queuing able */ - ushort bios_scan; /* 07 BIOS device control */ - ushort scam_tolerant; /* 08 no scam */ - - uchar adapter_scsi_id; /* 09 Host Adapter ID */ - uchar bios_boot_delay; /* power up wait */ - - uchar scsi_reset_delay; /* 10 reset delay */ - uchar bios_id_lun; /* first boot device scsi id & lun */ - /* high nibble is lun */ - /* low nibble is scsi id */ - - uchar termination_se; /* 11 0 - automatic */ - /* 1 - low off / high off */ - /* 2 - low off / high on */ - /* 3 - low on / high on */ - /* There is no low on / high off */ - - uchar termination_lvd; /* 11 0 - automatic */ - /* 1 - low off / high off */ - /* 2 - low off / high on */ - /* 3 - low on / high on */ - /* There is no low on / high off */ - - ushort bios_ctrl; /* 12 BIOS control bits */ - /* bit 0 BIOS don't act as initiator. */ - /* bit 1 BIOS > 1 GB support */ - /* bit 2 BIOS > 2 Disk Support */ - /* bit 3 BIOS don't support removables */ - /* bit 4 BIOS support bootable CD */ - /* bit 5 BIOS scan enabled */ - /* bit 6 BIOS support multiple LUNs */ - /* bit 7 BIOS display of message */ - /* bit 8 SCAM disabled */ - /* bit 9 Reset SCSI bus during init. */ - /* bit 10 Basic Integrity Checking disabled */ - /* bit 11 No verbose initialization. */ - /* bit 12 SCSI parity enabled */ - /* bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */ - /* bit 14 */ - /* bit 15 */ - ushort sdtr_speed2; /* 13 SDTR speed TID 4-7 */ - ushort sdtr_speed3; /* 14 SDTR speed TID 8-11 */ - uchar max_host_qng; /* 15 maximum host queueing */ - uchar max_dvc_qng; /* maximum per device queuing */ - ushort dvc_cntl; /* 16 control bit for driver */ - ushort sdtr_speed4; /* 17 SDTR speed 4 TID 12-15 */ - ushort serial_number_word1; /* 18 Board serial number word 1 */ - ushort serial_number_word2; /* 19 Board serial number word 2 */ - ushort serial_number_word3; /* 20 Board serial number word 3 */ - ushort check_sum; /* 21 EEP check sum */ - uchar oem_name[16]; /* 22 OEM name */ - ushort dvc_err_code; /* 30 last device driver error code */ - ushort adv_err_code; /* 31 last uc and Adv Lib error code */ - ushort adv_err_addr; /* 32 last uc error address */ - ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */ - ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */ - ushort saved_adv_err_addr; /* 35 saved last uc error address */ - ushort reserved36; /* 36 reserved */ - ushort reserved37; /* 37 reserved */ - ushort reserved38; /* 38 reserved */ - ushort reserved39; /* 39 reserved */ - ushort reserved40; /* 40 reserved */ - ushort reserved41; /* 41 reserved */ - ushort reserved42; /* 42 reserved */ - ushort reserved43; /* 43 reserved */ - ushort reserved44; /* 44 reserved */ - ushort reserved45; /* 45 reserved */ - ushort reserved46; /* 46 reserved */ - ushort reserved47; /* 47 reserved */ - ushort reserved48; /* 48 reserved */ - ushort reserved49; /* 49 reserved */ - ushort reserved50; /* 50 reserved */ - ushort reserved51; /* 51 reserved */ - ushort reserved52; /* 52 reserved */ - ushort reserved53; /* 53 reserved */ - ushort reserved54; /* 54 reserved */ - ushort reserved55; /* 55 reserved */ - ushort cisptr_lsw; /* 56 CIS PTR LSW */ - ushort cisprt_msw; /* 57 CIS PTR MSW */ - ushort subsysvid; /* 58 SubSystem Vendor ID */ - ushort subsysid; /* 59 SubSystem ID */ - ushort reserved60; /* 60 reserved */ - ushort reserved61; /* 61 reserved */ - ushort reserved62; /* 62 reserved */ - ushort reserved63; /* 63 reserved */ -} ADVEEP_38C1600_CONFIG; - -/* - * EEPROM Commands - */ -#define ASC_EEP_CMD_DONE 0x0200 - -/* bios_ctrl */ -#define BIOS_CTRL_BIOS 0x0001 -#define BIOS_CTRL_EXTENDED_XLAT 0x0002 -#define BIOS_CTRL_GT_2_DISK 0x0004 -#define BIOS_CTRL_BIOS_REMOVABLE 0x0008 -#define BIOS_CTRL_BOOTABLE_CD 0x0010 -#define BIOS_CTRL_MULTIPLE_LUN 0x0040 -#define BIOS_CTRL_DISPLAY_MSG 0x0080 -#define BIOS_CTRL_NO_SCAM 0x0100 -#define BIOS_CTRL_RESET_SCSI_BUS 0x0200 -#define BIOS_CTRL_INIT_VERBOSE 0x0800 -#define BIOS_CTRL_SCSI_PARITY 0x1000 -#define BIOS_CTRL_AIPP_DIS 0x2000 - -#define ADV_3550_MEMSIZE 0x2000 /* 8 KB Internal Memory */ - -#define ADV_38C0800_MEMSIZE 0x4000 /* 16 KB Internal Memory */ - -/* - * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is - * a special 16K Adv Library and Microcode version. After the issue is - * resolved, should restore 32K support. - * - * #define ADV_38C1600_MEMSIZE 0x8000L * 32 KB Internal Memory * - */ -#define ADV_38C1600_MEMSIZE 0x4000 /* 16 KB Internal Memory */ - -/* - * Byte I/O register address from base of 'iop_base'. - */ -#define IOPB_INTR_STATUS_REG 0x00 -#define IOPB_CHIP_ID_1 0x01 -#define IOPB_INTR_ENABLES 0x02 -#define IOPB_CHIP_TYPE_REV 0x03 -#define IOPB_RES_ADDR_4 0x04 -#define IOPB_RES_ADDR_5 0x05 -#define IOPB_RAM_DATA 0x06 -#define IOPB_RES_ADDR_7 0x07 -#define IOPB_FLAG_REG 0x08 -#define IOPB_RES_ADDR_9 0x09 -#define IOPB_RISC_CSR 0x0A -#define IOPB_RES_ADDR_B 0x0B -#define IOPB_RES_ADDR_C 0x0C -#define IOPB_RES_ADDR_D 0x0D -#define IOPB_SOFT_OVER_WR 0x0E -#define IOPB_RES_ADDR_F 0x0F -#define IOPB_MEM_CFG 0x10 -#define IOPB_RES_ADDR_11 0x11 -#define IOPB_GPIO_DATA 0x12 -#define IOPB_RES_ADDR_13 0x13 -#define IOPB_FLASH_PAGE 0x14 -#define IOPB_RES_ADDR_15 0x15 -#define IOPB_GPIO_CNTL 0x16 -#define IOPB_RES_ADDR_17 0x17 -#define IOPB_FLASH_DATA 0x18 -#define IOPB_RES_ADDR_19 0x19 -#define IOPB_RES_ADDR_1A 0x1A -#define IOPB_RES_ADDR_1B 0x1B -#define IOPB_RES_ADDR_1C 0x1C -#define IOPB_RES_ADDR_1D 0x1D -#define IOPB_RES_ADDR_1E 0x1E -#define IOPB_RES_ADDR_1F 0x1F -#define IOPB_DMA_CFG0 0x20 -#define IOPB_DMA_CFG1 0x21 -#define IOPB_TICKLE 0x22 -#define IOPB_DMA_REG_WR 0x23 -#define IOPB_SDMA_STATUS 0x24 -#define IOPB_SCSI_BYTE_CNT 0x25 -#define IOPB_HOST_BYTE_CNT 0x26 -#define IOPB_BYTE_LEFT_TO_XFER 0x27 -#define IOPB_BYTE_TO_XFER_0 0x28 -#define IOPB_BYTE_TO_XFER_1 0x29 -#define IOPB_BYTE_TO_XFER_2 0x2A -#define IOPB_BYTE_TO_XFER_3 0x2B -#define IOPB_ACC_GRP 0x2C -#define IOPB_RES_ADDR_2D 0x2D -#define IOPB_DEV_ID 0x2E -#define IOPB_RES_ADDR_2F 0x2F -#define IOPB_SCSI_DATA 0x30 -#define IOPB_RES_ADDR_31 0x31 -#define IOPB_RES_ADDR_32 0x32 -#define IOPB_SCSI_DATA_HSHK 0x33 -#define IOPB_SCSI_CTRL 0x34 -#define IOPB_RES_ADDR_35 0x35 -#define IOPB_RES_ADDR_36 0x36 -#define IOPB_RES_ADDR_37 0x37 -#define IOPB_RAM_BIST 0x38 -#define IOPB_PLL_TEST 0x39 -#define IOPB_PCI_INT_CFG 0x3A -#define IOPB_RES_ADDR_3B 0x3B -#define IOPB_RFIFO_CNT 0x3C -#define IOPB_RES_ADDR_3D 0x3D -#define IOPB_RES_ADDR_3E 0x3E -#define IOPB_RES_ADDR_3F 0x3F - -/* - * Word I/O register address from base of 'iop_base'. - */ -#define IOPW_CHIP_ID_0 0x00 /* CID0 */ -#define IOPW_CTRL_REG 0x02 /* CC */ -#define IOPW_RAM_ADDR 0x04 /* LA */ -#define IOPW_RAM_DATA 0x06 /* LD */ -#define IOPW_RES_ADDR_08 0x08 -#define IOPW_RISC_CSR 0x0A /* CSR */ -#define IOPW_SCSI_CFG0 0x0C /* CFG0 */ -#define IOPW_SCSI_CFG1 0x0E /* CFG1 */ -#define IOPW_RES_ADDR_10 0x10 -#define IOPW_SEL_MASK 0x12 /* SM */ -#define IOPW_RES_ADDR_14 0x14 -#define IOPW_FLASH_ADDR 0x16 /* FA */ -#define IOPW_RES_ADDR_18 0x18 -#define IOPW_EE_CMD 0x1A /* EC */ -#define IOPW_EE_DATA 0x1C /* ED */ -#define IOPW_SFIFO_CNT 0x1E /* SFC */ -#define IOPW_RES_ADDR_20 0x20 -#define IOPW_Q_BASE 0x22 /* QB */ -#define IOPW_QP 0x24 /* QP */ -#define IOPW_IX 0x26 /* IX */ -#define IOPW_SP 0x28 /* SP */ -#define IOPW_PC 0x2A /* PC */ -#define IOPW_RES_ADDR_2C 0x2C -#define IOPW_RES_ADDR_2E 0x2E -#define IOPW_SCSI_DATA 0x30 /* SD */ -#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */ -#define IOPW_SCSI_CTRL 0x34 /* SC */ -#define IOPW_HSHK_CFG 0x36 /* HCFG */ -#define IOPW_SXFR_STATUS 0x36 /* SXS */ -#define IOPW_SXFR_CNTL 0x38 /* SXL */ -#define IOPW_SXFR_CNTH 0x3A /* SXH */ -#define IOPW_RES_ADDR_3C 0x3C -#define IOPW_RFIFO_DATA 0x3E /* RFD */ - -/* - * Doubleword I/O register address from base of 'iop_base'. - */ -#define IOPDW_RES_ADDR_0 0x00 -#define IOPDW_RAM_DATA 0x04 -#define IOPDW_RES_ADDR_8 0x08 -#define IOPDW_RES_ADDR_C 0x0C -#define IOPDW_RES_ADDR_10 0x10 -#define IOPDW_COMMA 0x14 -#define IOPDW_COMMB 0x18 -#define IOPDW_RES_ADDR_1C 0x1C -#define IOPDW_SDMA_ADDR0 0x20 -#define IOPDW_SDMA_ADDR1 0x24 -#define IOPDW_SDMA_COUNT 0x28 -#define IOPDW_SDMA_ERROR 0x2C -#define IOPDW_RDMA_ADDR0 0x30 -#define IOPDW_RDMA_ADDR1 0x34 -#define IOPDW_RDMA_COUNT 0x38 -#define IOPDW_RDMA_ERROR 0x3C - -#define ADV_CHIP_ID_BYTE 0x25 -#define ADV_CHIP_ID_WORD 0x04C1 - -#define ADV_INTR_ENABLE_HOST_INTR 0x01 -#define ADV_INTR_ENABLE_SEL_INTR 0x02 -#define ADV_INTR_ENABLE_DPR_INTR 0x04 -#define ADV_INTR_ENABLE_RTA_INTR 0x08 -#define ADV_INTR_ENABLE_RMA_INTR 0x10 -#define ADV_INTR_ENABLE_RST_INTR 0x20 -#define ADV_INTR_ENABLE_DPE_INTR 0x40 -#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80 - -#define ADV_INTR_STATUS_INTRA 0x01 -#define ADV_INTR_STATUS_INTRB 0x02 -#define ADV_INTR_STATUS_INTRC 0x04 - -#define ADV_RISC_CSR_STOP (0x0000) -#define ADV_RISC_TEST_COND (0x2000) -#define ADV_RISC_CSR_RUN (0x4000) -#define ADV_RISC_CSR_SINGLE_STEP (0x8000) - -#define ADV_CTRL_REG_HOST_INTR 0x0100 -#define ADV_CTRL_REG_SEL_INTR 0x0200 -#define ADV_CTRL_REG_DPR_INTR 0x0400 -#define ADV_CTRL_REG_RTA_INTR 0x0800 -#define ADV_CTRL_REG_RMA_INTR 0x1000 -#define ADV_CTRL_REG_RES_BIT14 0x2000 -#define ADV_CTRL_REG_DPE_INTR 0x4000 -#define ADV_CTRL_REG_POWER_DONE 0x8000 -#define ADV_CTRL_REG_ANY_INTR 0xFF00 - -#define ADV_CTRL_REG_CMD_RESET 0x00C6 -#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5 -#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4 -#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3 -#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2 - -#define ADV_TICKLE_NOP 0x00 -#define ADV_TICKLE_A 0x01 -#define ADV_TICKLE_B 0x02 -#define ADV_TICKLE_C 0x03 - -#define AdvIsIntPending(port) \ - (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR) - -/* - * SCSI_CFG0 Register bit definitions - */ -#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */ -#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */ -#define EVEN_PARITY 0x1000 /* Select Even Parity */ -#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */ -#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */ -#define PRIM_MODE 0x0100 /* Primitive SCSI mode */ -#define SCAM_EN 0x0080 /* Enable SCAM selection */ -#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */ -#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */ -#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */ -#define OUR_ID 0x000F /* SCSI ID */ - -/* - * SCSI_CFG1 Register bit definitions - */ -#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */ -#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */ -#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */ -#define FILTER_SEL 0x0C00 /* Filter Period Selection */ -#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */ -#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */ -#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */ -#define ACTIVE_DBL 0x0200 /* Disable Active Negation */ -#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */ -#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */ -#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */ -#define TERM_CTL 0x0030 /* External SCSI Termination Bits */ -#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */ -#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */ -#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */ - -/* - * Addendum for ASC-38C0800 Chip - * - * The ASC-38C1600 Chip uses the same definitions except that the - * bus mode override bits [12:10] have been moved to byte register - * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in - * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV) - * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only. - * Also each ASC-38C1600 function or channel uses only cable bits [5:4] - * and [1:0]. Bits [14], [7:6], [3:2] are unused. - */ -#define DIS_TERM_DRV 0x4000 /* 1: Read c_det[3:0], 0: cannot read */ -#define HVD_LVD_SE 0x1C00 /* Device Detect Bits */ -#define HVD 0x1000 /* HVD Device Detect */ -#define LVD 0x0800 /* LVD Device Detect */ -#define SE 0x0400 /* SE Device Detect */ -#define TERM_LVD 0x00C0 /* LVD Termination Bits */ -#define TERM_LVD_HI 0x0080 /* Enable LVD Upper Termination */ -#define TERM_LVD_LO 0x0040 /* Enable LVD Lower Termination */ -#define TERM_SE 0x0030 /* SE Termination Bits */ -#define TERM_SE_HI 0x0020 /* Enable SE Upper Termination */ -#define TERM_SE_LO 0x0010 /* Enable SE Lower Termination */ -#define C_DET_LVD 0x000C /* LVD Cable Detect Bits */ -#define C_DET3 0x0008 /* Cable Detect for LVD External Wide */ -#define C_DET2 0x0004 /* Cable Detect for LVD Internal Wide */ -#define C_DET_SE 0x0003 /* SE Cable Detect Bits */ -#define C_DET1 0x0002 /* Cable Detect for SE Internal Wide */ -#define C_DET0 0x0001 /* Cable Detect for SE Internal Narrow */ - -#define CABLE_ILLEGAL_A 0x7 - /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */ - -#define CABLE_ILLEGAL_B 0xB - /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */ - -/* - * MEM_CFG Register bit definitions - */ -#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */ -#define FAST_EE_CLK 0x20 /* Diagnostic Bit */ -#define RAM_SZ 0x1C /* Specify size of RAM to RISC */ -#define RAM_SZ_2KB 0x00 /* 2 KB */ -#define RAM_SZ_4KB 0x04 /* 4 KB */ -#define RAM_SZ_8KB 0x08 /* 8 KB */ -#define RAM_SZ_16KB 0x0C /* 16 KB */ -#define RAM_SZ_32KB 0x10 /* 32 KB */ -#define RAM_SZ_64KB 0x14 /* 64 KB */ - -/* - * DMA_CFG0 Register bit definitions - * - * This register is only accessible to the host. - */ -#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */ -#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */ -#define FIFO_THRESH_16B 0x00 /* 16 bytes */ -#define FIFO_THRESH_32B 0x20 /* 32 bytes */ -#define FIFO_THRESH_48B 0x30 /* 48 bytes */ -#define FIFO_THRESH_64B 0x40 /* 64 bytes */ -#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */ -#define FIFO_THRESH_96B 0x60 /* 96 bytes */ -#define FIFO_THRESH_112B 0x70 /* 112 bytes */ -#define START_CTL 0x0C /* DMA start conditions */ -#define START_CTL_TH 0x00 /* Wait threshold level (default) */ -#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */ -#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */ -#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */ -#define READ_CMD 0x03 /* Memory Read Method */ -#define READ_CMD_MR 0x00 /* Memory Read */ -#define READ_CMD_MRL 0x02 /* Memory Read Long */ -#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */ - -/* - * ASC-38C0800 RAM BIST Register bit definitions - */ -#define RAM_TEST_MODE 0x80 -#define PRE_TEST_MODE 0x40 -#define NORMAL_MODE 0x00 -#define RAM_TEST_DONE 0x10 -#define RAM_TEST_STATUS 0x0F -#define RAM_TEST_HOST_ERROR 0x08 -#define RAM_TEST_INTRAM_ERROR 0x04 -#define RAM_TEST_RISC_ERROR 0x02 -#define RAM_TEST_SCSI_ERROR 0x01 -#define RAM_TEST_SUCCESS 0x00 -#define PRE_TEST_VALUE 0x05 -#define NORMAL_VALUE 0x00 - -/* - * ASC38C1600 Definitions - * - * IOPB_PCI_INT_CFG Bit Field Definitions - */ - -#define INTAB_LD 0x80 /* Value loaded from EEPROM Bit 11. */ - -/* - * Bit 1 can be set to change the interrupt for the Function to operate in - * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in - * Open Drain mode. Both functions of the ASC38C1600 must be set to the same - * mode, otherwise the operating mode is undefined. - */ -#define TOTEMPOLE 0x02 - -/* - * Bit 0 can be used to change the Int Pin for the Function. The value is - * 0 by default for both Functions with Function 0 using INT A and Function - * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set, - * INT A is used. - * - * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin - * value specified in the PCI Configuration Space. - */ -#define INTAB 0x01 - -/* - * Adv Library Status Definitions - */ -#define ADV_TRUE 1 -#define ADV_FALSE 0 -#define ADV_SUCCESS 1 -#define ADV_BUSY 0 -#define ADV_ERROR (-1) - -/* - * ADV_DVC_VAR 'warn_code' values - */ -#define ASC_WARN_BUSRESET_ERROR 0x0001 /* SCSI Bus Reset error */ -#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */ -#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */ -#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */ - -#define ADV_MAX_TID 15 /* max. target identifier */ -#define ADV_MAX_LUN 7 /* max. logical unit number */ - -/* - * Fixed locations of microcode operating variables. - */ -#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */ -#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */ -#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */ -#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */ -#define ASC_MC_VERSION_NUM 0x003A /* microcode number */ -#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */ -#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */ -#define ASC_MC_BIOS_SIGNATURE 0x0058 /* BIOS Signature 0x55AA */ -#define ASC_MC_BIOS_VERSION 0x005A /* BIOS Version (2 bytes) */ -#define ASC_MC_SDTR_SPEED1 0x0090 /* SDTR Speed for TID 0-3 */ -#define ASC_MC_SDTR_SPEED2 0x0092 /* SDTR Speed for TID 4-7 */ -#define ASC_MC_SDTR_SPEED3 0x0094 /* SDTR Speed for TID 8-11 */ -#define ASC_MC_SDTR_SPEED4 0x0096 /* SDTR Speed for TID 12-15 */ -#define ASC_MC_CHIP_TYPE 0x009A -#define ASC_MC_INTRB_CODE 0x009B -#define ASC_MC_WDTR_ABLE 0x009C -#define ASC_MC_SDTR_ABLE 0x009E -#define ASC_MC_TAGQNG_ABLE 0x00A0 -#define ASC_MC_DISC_ENABLE 0x00A2 -#define ASC_MC_IDLE_CMD_STATUS 0x00A4 -#define ASC_MC_IDLE_CMD 0x00A6 -#define ASC_MC_IDLE_CMD_PARAMETER 0x00A8 -#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC -#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE -#define ASC_MC_DEFAULT_MEM_CFG 0x00B0 -#define ASC_MC_DEFAULT_SEL_MASK 0x00B2 -#define ASC_MC_SDTR_DONE 0x00B6 -#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0 -#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0 -#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100 -#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */ -#define ASC_MC_WDTR_DONE 0x0124 -#define ASC_MC_CAM_MODE_MASK 0x015E /* CAM mode TID bitmask. */ -#define ASC_MC_ICQ 0x0160 -#define ASC_MC_IRQ 0x0164 -#define ASC_MC_PPR_ABLE 0x017A - -/* - * BIOS LRAM variable absolute offsets. - */ -#define BIOS_CODESEG 0x54 -#define BIOS_CODELEN 0x56 -#define BIOS_SIGNATURE 0x58 -#define BIOS_VERSION 0x5A - -/* - * Microcode Control Flags - * - * Flags set by the Adv Library in RISC variable 'control_flag' (0x122) - * and handled by the microcode. - */ -#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */ -#define CONTROL_FLAG_ENABLE_AIPP 0x0002 /* Enabled AIPP checking. */ - -/* - * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format - */ -#define HSHK_CFG_WIDE_XFR 0x8000 -#define HSHK_CFG_RATE 0x0F00 -#define HSHK_CFG_OFFSET 0x001F - -#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */ -#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */ -#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */ -#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */ - -#define ASC_QC_DATA_CHECK 0x01 /* Require ASC_QC_DATA_OUT set or clear. */ -#define ASC_QC_DATA_OUT 0x02 /* Data out DMA transfer. */ -#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */ -#define ASC_QC_NO_OVERRUN 0x08 /* Don't report overrun. */ -#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */ - -#define ASC_QSC_NO_DISC 0x01 /* Don't allow disconnect for request. */ -#define ASC_QSC_NO_TAGMSG 0x02 /* Don't allow tag queuing for request. */ -#define ASC_QSC_NO_SYNC 0x04 /* Don't use Synch. transfer on request. */ -#define ASC_QSC_NO_WIDE 0x08 /* Don't use Wide transfer on request. */ -#define ASC_QSC_REDO_DTR 0x10 /* Renegotiate WDTR/SDTR before request. */ -/* - * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or - * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used. - */ -#define ASC_QSC_HEAD_TAG 0x40 /* Use Head Tag Message (0x21). */ -#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */ - -/* - * All fields here are accessed by the board microcode and need to be - * little-endian. - */ -typedef struct adv_carr_t { - ADV_VADDR carr_va; /* Carrier Virtual Address */ - ADV_PADDR carr_pa; /* Carrier Physical Address */ - ADV_VADDR areq_vpa; /* ASC_SCSI_REQ_Q Virtual or Physical Address */ - /* - * next_vpa [31:4] Carrier Virtual or Physical Next Pointer - * - * next_vpa [3:1] Reserved Bits - * next_vpa [0] Done Flag set in Response Queue. - */ - ADV_VADDR next_vpa; -} ADV_CARR_T; - -/* - * Mask used to eliminate low 4 bits of carrier 'next_vpa' field. - */ -#define ASC_NEXT_VPA_MASK 0xFFFFFFF0 - -#define ASC_RQ_DONE 0x00000001 -#define ASC_RQ_GOOD 0x00000002 -#define ASC_CQ_STOPPER 0x00000000 - -#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK) - -#define ADV_CARRIER_NUM_PAGE_CROSSING \ - (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + (PAGE_SIZE - 1))/PAGE_SIZE) - -#define ADV_CARRIER_BUFSIZE \ - ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T)) - -/* - * ASC_SCSI_REQ_Q 'a_flag' definitions - * - * The Adv Library should limit use to the lower nibble (4 bits) of - * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag. - */ -#define ADV_POLL_REQUEST 0x01 /* poll for request completion */ -#define ADV_SCSIQ_DONE 0x02 /* request done */ -#define ADV_DONT_RETRY 0x08 /* don't do retry */ - -#define ADV_CHIP_ASC3550 0x01 /* Ultra-Wide IC */ -#define ADV_CHIP_ASC38C0800 0x02 /* Ultra2-Wide/LVD IC */ -#define ADV_CHIP_ASC38C1600 0x03 /* Ultra3-Wide/LVD2 IC */ - -/* - * Adapter temporary configuration structure - * - * This structure can be discarded after initialization. Don't add - * fields here needed after initialization. - * - * Field naming convention: - * - * *_enable indicates the field enables or disables a feature. The - * value of the field is never reset. - */ -typedef struct adv_dvc_cfg { - ushort disc_enable; /* enable disconnection */ - uchar chip_version; /* chip version */ - uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */ - ushort control_flag; /* Microcode Control Flag */ - ushort mcode_date; /* Microcode date */ - ushort mcode_version; /* Microcode version */ - ushort serial1; /* EEPROM serial number word 1 */ - ushort serial2; /* EEPROM serial number word 2 */ - ushort serial3; /* EEPROM serial number word 3 */ -} ADV_DVC_CFG; - -struct adv_dvc_var; -struct adv_scsi_req_q; - -typedef struct asc_sg_block { - uchar reserved1; - uchar reserved2; - uchar reserved3; - uchar sg_cnt; /* Valid entries in block. */ - ADV_PADDR sg_ptr; /* Pointer to next sg block. */ - struct { - ADV_PADDR sg_addr; /* SG element address. */ - ADV_DCNT sg_count; /* SG element count. */ - } sg_list[NO_OF_SG_PER_BLOCK]; -} ADV_SG_BLOCK; - -/* - * ADV_SCSI_REQ_Q - microcode request structure - * - * All fields in this structure up to byte 60 are used by the microcode. - * The microcode makes assumptions about the size and ordering of fields - * in this structure. Do not change the structure definition here without - * coordinating the change with the microcode. - * - * All fields accessed by microcode must be maintained in little_endian - * order. - */ -typedef struct adv_scsi_req_q { - uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */ - uchar target_cmd; - uchar target_id; /* Device target identifier. */ - uchar target_lun; /* Device target logical unit number. */ - ADV_PADDR data_addr; /* Data buffer physical address. */ - ADV_DCNT data_cnt; /* Data count. Ucode sets to residual. */ - ADV_PADDR sense_addr; - ADV_PADDR carr_pa; - uchar mflag; - uchar sense_len; - uchar cdb_len; /* SCSI CDB length. Must <= 16 bytes. */ - uchar scsi_cntl; - uchar done_status; /* Completion status. */ - uchar scsi_status; /* SCSI status byte. */ - uchar host_status; /* Ucode host status. */ - uchar sg_working_ix; - uchar cdb[12]; /* SCSI CDB bytes 0-11. */ - ADV_PADDR sg_real_addr; /* SG list physical address. */ - ADV_PADDR scsiq_rptr; - uchar cdb16[4]; /* SCSI CDB bytes 12-15. */ - ADV_VADDR scsiq_ptr; - ADV_VADDR carr_va; - /* - * End of microcode structure - 60 bytes. The rest of the structure - * is used by the Adv Library and ignored by the microcode. - */ - ADV_VADDR srb_ptr; - ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */ - char *vdata_addr; /* Data buffer virtual address. */ - uchar a_flag; - uchar pad[2]; /* Pad out to a word boundary. */ -} ADV_SCSI_REQ_Q; - -/* - * The following two structures are used to process Wide Board requests. - * - * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library - * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the - * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the - * Mid-Level SCSI request structure. - * - * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each - * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux - * up to 255 scatter-gather elements may be used per request or - * ADV_SCSI_REQ_Q. - * - * Both structures must be 32 byte aligned. - */ -typedef struct adv_sgblk { - ADV_SG_BLOCK sg_block; /* Sgblock structure. */ - uchar align[32]; /* Sgblock structure padding. */ - struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */ -} adv_sgblk_t; - -typedef struct adv_req { - ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */ - uchar align[32]; /* Request structure padding. */ - struct scsi_cmnd *cmndp; /* Mid-Level SCSI command pointer. */ - adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */ - struct adv_req *next_reqp; /* Next Request Structure. */ -} adv_req_t; - -/* - * Adapter operation variable structure. - * - * One structure is required per host adapter. - * - * Field naming convention: - * - * *_able indicates both whether a feature should be enabled or disabled - * and whether a device isi capable of the feature. At initialization - * this field may be set, but later if a device is found to be incapable - * of the feature, the field is cleared. - */ -typedef struct adv_dvc_var { - AdvPortAddr iop_base; /* I/O port address */ - ushort err_code; /* fatal error code */ - ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */ - ushort wdtr_able; /* try WDTR for a device */ - ushort sdtr_able; /* try SDTR for a device */ - ushort ultra_able; /* try SDTR Ultra speed for a device */ - ushort sdtr_speed1; /* EEPROM SDTR Speed for TID 0-3 */ - ushort sdtr_speed2; /* EEPROM SDTR Speed for TID 4-7 */ - ushort sdtr_speed3; /* EEPROM SDTR Speed for TID 8-11 */ - ushort sdtr_speed4; /* EEPROM SDTR Speed for TID 12-15 */ - ushort tagqng_able; /* try tagged queuing with a device */ - ushort ppr_able; /* PPR message capable per TID bitmask. */ - uchar max_dvc_qng; /* maximum number of tagged commands per device */ - ushort start_motor; /* start motor command allowed */ - uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */ - uchar chip_no; /* should be assigned by caller */ - uchar max_host_qng; /* maximum number of Q'ed command allowed */ - ushort no_scam; /* scam_tolerant of EEPROM */ - struct asc_board *drv_ptr; /* driver pointer to private structure */ - uchar chip_scsi_id; /* chip SCSI target ID */ - uchar chip_type; - uchar bist_err_code; - ADV_CARR_T *carrier_buf; - ADV_CARR_T *carr_freelist; /* Carrier free list. */ - ADV_CARR_T *icq_sp; /* Initiator command queue stopper pointer. */ - ADV_CARR_T *irq_sp; /* Initiator response queue stopper pointer. */ - ushort carr_pending_cnt; /* Count of pending carriers. */ - struct adv_req *orig_reqp; /* adv_req_t memory block. */ - /* - * Note: The following fields will not be used after initialization. The - * driver may discard the buffer after initialization is done. - */ - ADV_DVC_CFG *cfg; /* temporary configuration structure */ -} ADV_DVC_VAR; - -/* - * Microcode idle loop commands - */ -#define IDLE_CMD_COMPLETED 0 -#define IDLE_CMD_STOP_CHIP 0x0001 -#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002 -#define IDLE_CMD_SEND_INT 0x0004 -#define IDLE_CMD_ABORT 0x0008 -#define IDLE_CMD_DEVICE_RESET 0x0010 -#define IDLE_CMD_SCSI_RESET_START 0x0020 /* Assert SCSI Bus Reset */ -#define IDLE_CMD_SCSI_RESET_END 0x0040 /* Deassert SCSI Bus Reset */ -#define IDLE_CMD_SCSIREQ 0x0080 - -#define IDLE_CMD_STATUS_SUCCESS 0x0001 -#define IDLE_CMD_STATUS_FAILURE 0x0002 - -/* - * AdvSendIdleCmd() flag definitions. - */ -#define ADV_NOWAIT 0x01 - -/* - * Wait loop time out values. - */ -#define SCSI_WAIT_100_MSEC 100UL /* 100 milliseconds */ -#define SCSI_US_PER_MSEC 1000 /* microseconds per millisecond */ -#define SCSI_MAX_RETRY 10 /* retry count */ - -#define ADV_ASYNC_RDMA_FAILURE 0x01 /* Fatal RDMA failure. */ -#define ADV_ASYNC_SCSI_BUS_RESET_DET 0x02 /* Detected SCSI Bus Reset. */ -#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */ -#define ADV_RDMA_IN_CARR_AND_Q_INVALID 0x04 /* RDMAed-in data invalid. */ - -#define ADV_HOST_SCSI_BUS_RESET 0x80 /* Host Initiated SCSI Bus Reset. */ - -/* Read byte from a register. */ -#define AdvReadByteRegister(iop_base, reg_off) \ - (ADV_MEM_READB((iop_base) + (reg_off))) - -/* Write byte to a register. */ -#define AdvWriteByteRegister(iop_base, reg_off, byte) \ - (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte))) - -/* Read word (2 bytes) from a register. */ -#define AdvReadWordRegister(iop_base, reg_off) \ - (ADV_MEM_READW((iop_base) + (reg_off))) - -/* Write word (2 bytes) to a register. */ -#define AdvWriteWordRegister(iop_base, reg_off, word) \ - (ADV_MEM_WRITEW((iop_base) + (reg_off), (word))) - -/* Write dword (4 bytes) to a register. */ -#define AdvWriteDWordRegister(iop_base, reg_off, dword) \ - (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword))) - -/* Read byte from LRAM. */ -#define AdvReadByteLram(iop_base, addr, byte) \ -do { \ - ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \ - (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \ -} while (0) - -/* Write byte to LRAM. */ -#define AdvWriteByteLram(iop_base, addr, byte) \ - (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ - ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte))) - -/* Read word (2 bytes) from LRAM. */ -#define AdvReadWordLram(iop_base, addr, word) \ -do { \ - ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \ - (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \ -} while (0) - -/* Write word (2 bytes) to LRAM. */ -#define AdvWriteWordLram(iop_base, addr, word) \ - (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ - ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) - -/* Write little-endian double word (4 bytes) to LRAM */ -/* Because of unspecified C language ordering don't use auto-increment. */ -#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \ - ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \ - ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \ - cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \ - (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \ - ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \ - cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF))))) - -/* Read word (2 bytes) from LRAM assuming that the address is already set. */ -#define AdvReadWordAutoIncLram(iop_base) \ - (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)) - -/* Write word (2 bytes) to LRAM assuming that the address is already set. */ -#define AdvWriteWordAutoIncLram(iop_base, word) \ - (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word))) - -/* - * Define macro to check for Condor signature. - * - * Evaluate to ADV_TRUE if a Condor chip is found the specified port - * address 'iop_base'. Otherwise evalue to ADV_FALSE. - */ -#define AdvFindSignature(iop_base) \ - (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \ - ADV_CHIP_ID_BYTE) && \ - (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \ - ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE) - -/* - * Define macro to Return the version number of the chip at 'iop_base'. - * - * The second parameter 'bus_type' is currently unused. - */ -#define AdvGetChipVersion(iop_base, bus_type) \ - AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV) - -/* - * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must - * match the ASC_SCSI_REQ_Q 'srb_ptr' field. - * - * If the request has not yet been sent to the device it will simply be - * aborted from RISC memory. If the request is disconnected it will be - * aborted on reselection by sending an Abort Message to the target ID. - * - * Return value: - * ADV_TRUE(1) - Queue was successfully aborted. - * ADV_FALSE(0) - Queue was not found on the active queue list. - */ -#define AdvAbortQueue(asc_dvc, scsiq) \ - AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \ - (ADV_DCNT) (scsiq)) - -/* - * Send a Bus Device Reset Message to the specified target ID. - * - * All outstanding commands will be purged if sending the - * Bus Device Reset Message is successful. - * - * Return Value: - * ADV_TRUE(1) - All requests on the target are purged. - * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests - * are not purged. - */ -#define AdvResetDevice(asc_dvc, target_id) \ - AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \ - (ADV_DCNT) (target_id)) - -/* - * SCSI Wide Type definition. - */ -#define ADV_SCSI_BIT_ID_TYPE ushort - -/* - * AdvInitScsiTarget() 'cntl_flag' options. - */ -#define ADV_SCAN_LUN 0x01 -#define ADV_CAPINFO_NOLUN 0x02 - -/* - * Convert target id to target id bit mask. - */ -#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID)) - -/* - * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values. - */ - -#define QD_NO_STATUS 0x00 /* Request not completed yet. */ -#define QD_NO_ERROR 0x01 -#define QD_ABORTED_BY_HOST 0x02 -#define QD_WITH_ERROR 0x04 - -#define QHSTA_NO_ERROR 0x00 -#define QHSTA_M_SEL_TIMEOUT 0x11 -#define QHSTA_M_DATA_OVER_RUN 0x12 -#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13 -#define QHSTA_M_QUEUE_ABORTED 0x15 -#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */ -#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */ -#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */ -#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */ -#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */ -#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */ -#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */ -/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */ -#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */ -#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */ -#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */ -#define QHSTA_M_SCSI_BUS_RESET 0x30 /* Request aborted from SBR */ -#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */ -#define QHSTA_M_BUS_DEVICE_RESET 0x32 /* Request aborted from BDR */ -#define QHSTA_M_DIRECTION_ERR 0x35 /* Data Phase mismatch */ -#define QHSTA_M_DIRECTION_ERR_HUNG 0x36 /* Data Phase mismatch and bus hang */ -#define QHSTA_M_WTM_TIMEOUT 0x41 -#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42 -#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43 -#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44 -#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */ -#define QHSTA_M_FROZEN_TIDQ 0x46 /* TID Queue frozen. */ -#define QHSTA_M_SGBACKUP_ERROR 0x47 /* Scatter-Gather backup error */ - -/* Return the address that is aligned at the next doubleword >= to 'addr'. */ -#define ADV_8BALIGN(addr) (((ulong) (addr) + 0x7) & ~0x7) -#define ADV_16BALIGN(addr) (((ulong) (addr) + 0xF) & ~0xF) -#define ADV_32BALIGN(addr) (((ulong) (addr) + 0x1F) & ~0x1F) - -/* - * Total contiguous memory needed for driver SG blocks. - * - * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum - * number of scatter-gather elements the driver supports in a - * single request. - */ - -#define ADV_SG_LIST_MAX_BYTE_SIZE \ - (sizeof(ADV_SG_BLOCK) * \ - ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)) - -/* struct asc_board flags */ -#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */ - -#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0) - -#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */ - -#define ASC_INFO_SIZE 128 /* advansys_info() line size */ - -#ifdef CONFIG_PROC_FS -/* /proc/scsi/advansys/[0...] related definitions */ -#define ASC_PRTBUF_SIZE 2048 -#define ASC_PRTLINE_SIZE 160 - -#define ASC_PRT_NEXT() \ - if (cp) { \ - totlen += len; \ - leftlen -= len; \ - if (leftlen == 0) { \ - return totlen; \ - } \ - cp += len; \ - } -#endif /* CONFIG_PROC_FS */ - -/* Asc Library return codes */ -#define ASC_TRUE 1 -#define ASC_FALSE 0 -#define ASC_NOERROR 1 -#define ASC_BUSY 0 -#define ASC_ERROR (-1) - -/* struct scsi_cmnd function return codes */ -#define STATUS_BYTE(byte) (byte) -#define MSG_BYTE(byte) ((byte) << 8) -#define HOST_BYTE(byte) ((byte) << 16) -#define DRIVER_BYTE(byte) ((byte) << 24) - -#define ASC_STATS(shost, counter) ASC_STATS_ADD(shost, counter, 1) -#ifndef ADVANSYS_STATS -#define ASC_STATS_ADD(shost, counter, count) -#else /* ADVANSYS_STATS */ -#define ASC_STATS_ADD(shost, counter, count) \ - (((struct asc_board *) shost_priv(shost))->asc_stats.counter += (count)) -#endif /* ADVANSYS_STATS */ - -/* If the result wraps when calculating tenths, return 0. */ -#define ASC_TENTHS(num, den) \ - (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \ - 0 : ((((num) * 10)/(den)) - (10 * ((num)/(den))))) - -/* - * Display a message to the console. - */ -#define ASC_PRINT(s) \ - { \ - printk("advansys: "); \ - printk(s); \ - } - -#define ASC_PRINT1(s, a1) \ - { \ - printk("advansys: "); \ - printk((s), (a1)); \ - } - -#define ASC_PRINT2(s, a1, a2) \ - { \ - printk("advansys: "); \ - printk((s), (a1), (a2)); \ - } - -#define ASC_PRINT3(s, a1, a2, a3) \ - { \ - printk("advansys: "); \ - printk((s), (a1), (a2), (a3)); \ - } - -#define ASC_PRINT4(s, a1, a2, a3, a4) \ - { \ - printk("advansys: "); \ - printk((s), (a1), (a2), (a3), (a4)); \ - } - -#ifndef ADVANSYS_DEBUG - -#define ASC_DBG(lvl, s...) -#define ASC_DBG_PRT_SCSI_HOST(lvl, s) -#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) -#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) -#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) -#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) -#define ASC_DBG_PRT_HEX(lvl, name, start, length) -#define ASC_DBG_PRT_CDB(lvl, cdb, len) -#define ASC_DBG_PRT_SENSE(lvl, sense, len) -#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) - -#else /* ADVANSYS_DEBUG */ - -/* - * Debugging Message Levels: - * 0: Errors Only - * 1: High-Level Tracing - * 2-N: Verbose Tracing - */ - -#define ASC_DBG(lvl, format, arg...) { \ - if (asc_dbglvl >= (lvl)) \ - printk(KERN_DEBUG "%s: %s: " format, DRV_NAME, \ - __func__ , ## arg); \ -} - -#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_scsi_host(s); \ - } \ - } - -#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_asc_scsi_q(scsiqp); \ - } \ - } - -#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_asc_qdone_info(qdone); \ - } \ - } - -#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_adv_scsi_req_q(scsiqp); \ - } \ - } - -#define ASC_DBG_PRT_HEX(lvl, name, start, length) \ - { \ - if (asc_dbglvl >= (lvl)) { \ - asc_prt_hex((name), (start), (length)); \ - } \ - } - -#define ASC_DBG_PRT_CDB(lvl, cdb, len) \ - ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len)); - -#define ASC_DBG_PRT_SENSE(lvl, sense, len) \ - ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len)); - -#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \ - ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len)); -#endif /* ADVANSYS_DEBUG */ - -#ifdef ADVANSYS_STATS - -/* Per board statistics structure */ -struct asc_stats { - /* Driver Entrypoint Statistics */ - ADV_DCNT queuecommand; /* # calls to advansys_queuecommand() */ - ADV_DCNT reset; /* # calls to advansys_eh_bus_reset() */ - ADV_DCNT biosparam; /* # calls to advansys_biosparam() */ - ADV_DCNT interrupt; /* # advansys_interrupt() calls */ - ADV_DCNT callback; /* # calls to asc/adv_isr_callback() */ - ADV_DCNT done; /* # calls to request's scsi_done function */ - ADV_DCNT build_error; /* # asc/adv_build_req() ASC_ERROR returns. */ - ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */ - ADV_DCNT adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */ - /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */ - ADV_DCNT exe_noerror; /* # ASC_NOERROR returns. */ - ADV_DCNT exe_busy; /* # ASC_BUSY returns. */ - ADV_DCNT exe_error; /* # ASC_ERROR returns. */ - ADV_DCNT exe_unknown; /* # unknown returns. */ - /* Data Transfer Statistics */ - ADV_DCNT xfer_cnt; /* # I/O requests received */ - ADV_DCNT xfer_elem; /* # scatter-gather elements */ - ADV_DCNT xfer_sect; /* # 512-byte blocks */ -}; -#endif /* ADVANSYS_STATS */ - -/* - * Structure allocated for each board. - * - * This structure is allocated by scsi_host_alloc() at the end - * of the 'Scsi_Host' structure starting at the 'hostdata' - * field. It is guaranteed to be allocated from DMA-able memory. - */ -struct asc_board { - struct device *dev; - uint flags; /* Board flags */ - unsigned int irq; - union { - ASC_DVC_VAR asc_dvc_var; /* Narrow board */ - ADV_DVC_VAR adv_dvc_var; /* Wide board */ - } dvc_var; - union { - ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */ - ADV_DVC_CFG adv_dvc_cfg; /* Wide board */ - } dvc_cfg; - ushort asc_n_io_port; /* Number I/O ports. */ - ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */ - ushort reqcnt[ADV_MAX_TID + 1]; /* Starvation request count */ - ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */ - ushort queue_full_cnt[ADV_MAX_TID + 1]; /* Queue full count */ - union { - ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */ - ADVEEP_3550_CONFIG adv_3550_eep; /* 3550 EEPROM config. */ - ADVEEP_38C0800_CONFIG adv_38C0800_eep; /* 38C0800 EEPROM config. */ - ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */ - } eep_config; - ulong last_reset; /* Saved last reset time */ - /* /proc/scsi/advansys/[0...] */ - char *prtbuf; /* /proc print buffer */ -#ifdef ADVANSYS_STATS - struct asc_stats asc_stats; /* Board statistics */ -#endif /* ADVANSYS_STATS */ - /* - * The following fields are used only for Narrow Boards. - */ - uchar sdtr_data[ASC_MAX_TID + 1]; /* SDTR information */ - /* - * The following fields are used only for Wide Boards. - */ - void __iomem *ioremap_addr; /* I/O Memory remap address. */ - ushort ioport; /* I/O Port address. */ - adv_req_t *adv_reqp; /* Request structures. */ - adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */ - ushort bios_signature; /* BIOS Signature. */ - ushort bios_version; /* BIOS Version. */ - ushort bios_codeseg; /* BIOS Code Segment. */ - ushort bios_codelen; /* BIOS Code Segment Length. */ -}; - -#define asc_dvc_to_board(asc_dvc) container_of(asc_dvc, struct asc_board, \ - dvc_var.asc_dvc_var) -#define adv_dvc_to_board(adv_dvc) container_of(adv_dvc, struct asc_board, \ - dvc_var.adv_dvc_var) -#define adv_dvc_to_pdev(adv_dvc) to_pci_dev(adv_dvc_to_board(adv_dvc)->dev) - -#ifdef ADVANSYS_DEBUG -static int asc_dbglvl = 3; - -/* - * asc_prt_asc_dvc_var() - */ -static void asc_prt_asc_dvc_var(ASC_DVC_VAR *h) -{ - printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong)h); - - printk(" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl " - "%d,\n", h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl); - - printk(" bus_type %d, init_sdtr 0x%x,\n", h->bus_type, - (unsigned)h->init_sdtr); - - printk(" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, " - "chip_no 0x%x,\n", (unsigned)h->sdtr_done, - (unsigned)h->use_tagged_qng, (unsigned)h->unit_not_ready, - (unsigned)h->chip_no); - - printk(" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait " - "%u,\n", (unsigned)h->queue_full_or_busy, - (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait); - - printk(" is_in_int %u, max_total_qng %u, cur_total_qng %u, " - "in_critical_cnt %u,\n", (unsigned)h->is_in_int, - (unsigned)h->max_total_qng, (unsigned)h->cur_total_qng, - (unsigned)h->in_critical_cnt); - - printk(" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, " - "pci_fix_asyn_xfer 0x%x,\n", (unsigned)h->last_q_shortage, - (unsigned)h->init_state, (unsigned)h->no_scam, - (unsigned)h->pci_fix_asyn_xfer); - - printk(" cfg 0x%lx\n", (ulong)h->cfg); -} - -/* - * asc_prt_asc_dvc_cfg() - */ -static void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h) -{ - printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong)h); - - printk(" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n", - h->can_tagged_qng, h->cmd_qng_enabled); - printk(" disc_enable 0x%x, sdtr_enable 0x%x,\n", - h->disc_enable, h->sdtr_enable); - - printk(" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, " - "chip_version %d,\n", h->chip_scsi_id, h->isa_dma_speed, - h->isa_dma_channel, h->chip_version); - - printk(" mcode_date 0x%x, mcode_version %d\n", - h->mcode_date, h->mcode_version); -} - -/* - * asc_prt_adv_dvc_var() - * - * Display an ADV_DVC_VAR structure. - */ -static void asc_prt_adv_dvc_var(ADV_DVC_VAR *h) -{ - printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong)h); - - printk(" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n", - (ulong)h->iop_base, h->err_code, (unsigned)h->ultra_able); - - printk(" sdtr_able 0x%x, wdtr_able 0x%x\n", - (unsigned)h->sdtr_able, (unsigned)h->wdtr_able); - - printk(" start_motor 0x%x, scsi_reset_wait 0x%x\n", - (unsigned)h->start_motor, (unsigned)h->scsi_reset_wait); - - printk(" max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n", - (unsigned)h->max_host_qng, (unsigned)h->max_dvc_qng, - (ulong)h->carr_freelist); - - printk(" icq_sp 0x%lx, irq_sp 0x%lx\n", - (ulong)h->icq_sp, (ulong)h->irq_sp); - - printk(" no_scam 0x%x, tagqng_able 0x%x\n", - (unsigned)h->no_scam, (unsigned)h->tagqng_able); - - printk(" chip_scsi_id 0x%x, cfg 0x%lx\n", - (unsigned)h->chip_scsi_id, (ulong)h->cfg); -} - -/* - * asc_prt_adv_dvc_cfg() - * - * Display an ADV_DVC_CFG structure. - */ -static void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h) -{ - printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong)h); - - printk(" disc_enable 0x%x, termination 0x%x\n", - h->disc_enable, h->termination); - - printk(" chip_version 0x%x, mcode_date 0x%x\n", - h->chip_version, h->mcode_date); - - printk(" mcode_version 0x%x, control_flag 0x%x\n", - h->mcode_version, h->control_flag); -} - -/* - * asc_prt_scsi_host() - */ -static void asc_prt_scsi_host(struct Scsi_Host *s) -{ - struct asc_board *boardp = shost_priv(s); - - printk("Scsi_Host at addr 0x%p, device %s\n", s, dev_name(boardp->dev)); - printk(" host_busy %u, host_no %d, last_reset %d,\n", - s->host_busy, s->host_no, (unsigned)s->last_reset); - - printk(" base 0x%lx, io_port 0x%lx, irq %d,\n", - (ulong)s->base, (ulong)s->io_port, boardp->irq); - - printk(" dma_channel %d, this_id %d, can_queue %d,\n", - s->dma_channel, s->this_id, s->can_queue); - - printk(" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n", - s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma); - - if (ASC_NARROW_BOARD(boardp)) { - asc_prt_asc_dvc_var(&boardp->dvc_var.asc_dvc_var); - asc_prt_asc_dvc_cfg(&boardp->dvc_cfg.asc_dvc_cfg); - } else { - asc_prt_adv_dvc_var(&boardp->dvc_var.adv_dvc_var); - asc_prt_adv_dvc_cfg(&boardp->dvc_cfg.adv_dvc_cfg); - } -} - -/* - * asc_prt_hex() - * - * Print hexadecimal output in 4 byte groupings 32 bytes - * or 8 double-words per line. - */ -static void asc_prt_hex(char *f, uchar *s, int l) -{ - int i; - int j; - int k; - int m; - - printk("%s: (%d bytes)\n", f, l); - - for (i = 0; i < l; i += 32) { - - /* Display a maximum of 8 double-words per line. */ - if ((k = (l - i) / 4) >= 8) { - k = 8; - m = 0; - } else { - m = (l - i) % 4; - } - - for (j = 0; j < k; j++) { - printk(" %2.2X%2.2X%2.2X%2.2X", - (unsigned)s[i + (j * 4)], - (unsigned)s[i + (j * 4) + 1], - (unsigned)s[i + (j * 4) + 2], - (unsigned)s[i + (j * 4) + 3]); - } - - switch (m) { - case 0: - default: - break; - case 1: - printk(" %2.2X", (unsigned)s[i + (j * 4)]); - break; - case 2: - printk(" %2.2X%2.2X", - (unsigned)s[i + (j * 4)], - (unsigned)s[i + (j * 4) + 1]); - break; - case 3: - printk(" %2.2X%2.2X%2.2X", - (unsigned)s[i + (j * 4) + 1], - (unsigned)s[i + (j * 4) + 2], - (unsigned)s[i + (j * 4) + 3]); - break; - } - - printk("\n"); - } -} - -/* - * asc_prt_asc_scsi_q() - */ -static void asc_prt_asc_scsi_q(ASC_SCSI_Q *q) -{ - ASC_SG_HEAD *sgp; - int i; - - printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong)q); - - printk - (" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n", - q->q2.target_ix, q->q1.target_lun, (ulong)q->q2.srb_ptr, - q->q2.tag_code); - - printk - (" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", - (ulong)le32_to_cpu(q->q1.data_addr), - (ulong)le32_to_cpu(q->q1.data_cnt), - (ulong)le32_to_cpu(q->q1.sense_addr), q->q1.sense_len); - - printk(" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n", - (ulong)q->cdbptr, q->q2.cdb_len, - (ulong)q->sg_head, q->q1.sg_queue_cnt); - - if (q->sg_head) { - sgp = q->sg_head; - printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong)sgp); - printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, - sgp->queue_cnt); - for (i = 0; i < sgp->entry_cnt; i++) { - printk(" [%u]: addr 0x%lx, bytes %lu\n", - i, (ulong)le32_to_cpu(sgp->sg_list[i].addr), - (ulong)le32_to_cpu(sgp->sg_list[i].bytes)); - } - - } -} - -/* - * asc_prt_asc_qdone_info() - */ -static void asc_prt_asc_qdone_info(ASC_QDONE_INFO *q) -{ - printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong)q); - printk(" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n", - (ulong)q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len, - q->d2.tag_code); - printk - (" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n", - q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg); -} - -/* - * asc_prt_adv_sgblock() - * - * Display an ADV_SG_BLOCK structure. - */ -static void asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b) -{ - int i; - - printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n", - (ulong)b, sgblockno); - printk(" sg_cnt %u, sg_ptr 0x%lx\n", - b->sg_cnt, (ulong)le32_to_cpu(b->sg_ptr)); - BUG_ON(b->sg_cnt > NO_OF_SG_PER_BLOCK); - if (b->sg_ptr != 0) - BUG_ON(b->sg_cnt != NO_OF_SG_PER_BLOCK); - for (i = 0; i < b->sg_cnt; i++) { - printk(" [%u]: sg_addr 0x%lx, sg_count 0x%lx\n", - i, (ulong)b->sg_list[i].sg_addr, - (ulong)b->sg_list[i].sg_count); - } -} - -/* - * asc_prt_adv_scsi_req_q() - * - * Display an ADV_SCSI_REQ_Q structure. - */ -static void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q) -{ - int sg_blk_cnt; - struct asc_sg_block *sg_ptr; - - printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong)q); - - printk(" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n", - q->target_id, q->target_lun, (ulong)q->srb_ptr, q->a_flag); - - printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n", - q->cntl, (ulong)le32_to_cpu(q->data_addr), (ulong)q->vdata_addr); - - printk(" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n", - (ulong)le32_to_cpu(q->data_cnt), - (ulong)le32_to_cpu(q->sense_addr), q->sense_len); - - printk - (" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n", - q->cdb_len, q->done_status, q->host_status, q->scsi_status); - - printk(" sg_working_ix 0x%x, target_cmd %u\n", - q->sg_working_ix, q->target_cmd); - - printk(" scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n", - (ulong)le32_to_cpu(q->scsiq_rptr), - (ulong)le32_to_cpu(q->sg_real_addr), (ulong)q->sg_list_ptr); - - /* Display the request's ADV_SG_BLOCK structures. */ - if (q->sg_list_ptr != NULL) { - sg_blk_cnt = 0; - while (1) { - /* - * 'sg_ptr' is a physical address. Convert it to a virtual - * address by indexing 'sg_blk_cnt' into the virtual address - * array 'sg_list_ptr'. - * - * XXX - Assumes all SG physical blocks are virtually contiguous. - */ - sg_ptr = - &(((ADV_SG_BLOCK *)(q->sg_list_ptr))[sg_blk_cnt]); - asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr); - if (sg_ptr->sg_ptr == 0) { - break; - } - sg_blk_cnt++; - } - } -} -#endif /* ADVANSYS_DEBUG */ - -/* - * The advansys chip/microcode contains a 32-bit identifier for each command - * known as the 'srb'. I don't know what it stands for. The driver used - * to encode the scsi_cmnd pointer by calling virt_to_bus and retrieve it - * with bus_to_virt. Now the driver keeps a per-host map of integers to - * pointers. It auto-expands when full, unless it can't allocate memory. - * Note that an srb of 0 is treated specially by the chip/firmware, hence - * the return of i+1 in this routine, and the corresponding subtraction in - * the inverse routine. - */ -#define BAD_SRB 0 -static u32 advansys_ptr_to_srb(struct asc_dvc_var *asc_dvc, void *ptr) -{ - int i; - void **new_ptr; - - for (i = 0; i < asc_dvc->ptr_map_count; i++) { - if (!asc_dvc->ptr_map[i]) - goto out; - } - - if (asc_dvc->ptr_map_count == 0) - asc_dvc->ptr_map_count = 1; - else - asc_dvc->ptr_map_count *= 2; - - new_ptr = krealloc(asc_dvc->ptr_map, - asc_dvc->ptr_map_count * sizeof(void *), GFP_ATOMIC); - if (!new_ptr) - return BAD_SRB; - asc_dvc->ptr_map = new_ptr; - out: - ASC_DBG(3, "Putting ptr %p into array offset %d\n", ptr, i); - asc_dvc->ptr_map[i] = ptr; - return i + 1; -} - -static void * advansys_srb_to_ptr(struct asc_dvc_var *asc_dvc, u32 srb) -{ - void *ptr; - - srb--; - if (srb >= asc_dvc->ptr_map_count) { - printk("advansys: bad SRB %u, max %u\n", srb, - asc_dvc->ptr_map_count); - return NULL; - } - ptr = asc_dvc->ptr_map[srb]; - asc_dvc->ptr_map[srb] = NULL; - ASC_DBG(3, "Returning ptr %p from array offset %d\n", ptr, srb); - return ptr; -} - -/* - * advansys_info() - * - * Return suitable for printing on the console with the argument - * adapter's configuration information. - * - * Note: The information line should not exceed ASC_INFO_SIZE bytes, - * otherwise the static 'info' array will be overrun. - */ -static const char *advansys_info(struct Scsi_Host *shost) -{ - static char info[ASC_INFO_SIZE]; - struct asc_board *boardp = shost_priv(shost); - ASC_DVC_VAR *asc_dvc_varp; - ADV_DVC_VAR *adv_dvc_varp; - char *busname; - char *widename = NULL; - - if (ASC_NARROW_BOARD(boardp)) { - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; - ASC_DBG(1, "begin\n"); - if (asc_dvc_varp->bus_type & ASC_IS_ISA) { - if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == - ASC_IS_ISAPNP) { - busname = "ISA PnP"; - } else { - busname = "ISA"; - } - sprintf(info, - "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X", - ASC_VERSION, busname, - (ulong)shost->io_port, - (ulong)shost->io_port + ASC_IOADR_GAP - 1, - boardp->irq, shost->dma_channel); - } else { - if (asc_dvc_varp->bus_type & ASC_IS_VL) { - busname = "VL"; - } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) { - busname = "EISA"; - } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) { - if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA) - == ASC_IS_PCI_ULTRA) { - busname = "PCI Ultra"; - } else { - busname = "PCI"; - } - } else { - busname = "?"; - shost_printk(KERN_ERR, shost, "unknown bus " - "type %d\n", asc_dvc_varp->bus_type); - } - sprintf(info, - "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X", - ASC_VERSION, busname, (ulong)shost->io_port, - (ulong)shost->io_port + ASC_IOADR_GAP - 1, - boardp->irq); - } - } else { - /* - * Wide Adapter Information - * - * Memory-mapped I/O is used instead of I/O space to access - * the adapter, but display the I/O Port range. The Memory - * I/O address is displayed through the driver /proc file. - */ - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - widename = "Ultra-Wide"; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - widename = "Ultra2-Wide"; - } else { - widename = "Ultra3-Wide"; - } - sprintf(info, - "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X", - ASC_VERSION, widename, (ulong)adv_dvc_varp->iop_base, - (ulong)adv_dvc_varp->iop_base + boardp->asc_n_io_port - 1, boardp->irq); - } - BUG_ON(strlen(info) >= ASC_INFO_SIZE); - ASC_DBG(1, "end\n"); - return info; -} - -#ifdef CONFIG_PROC_FS -/* - * asc_prt_line() - * - * If 'cp' is NULL print to the console, otherwise print to a buffer. - * - * Return 0 if printing to the console, otherwise return the number of - * bytes written to the buffer. - * - * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack - * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes. - */ -static int asc_prt_line(char *buf, int buflen, char *fmt, ...) -{ - va_list args; - int ret; - char s[ASC_PRTLINE_SIZE]; - - va_start(args, fmt); - ret = vsprintf(s, fmt, args); - BUG_ON(ret >= ASC_PRTLINE_SIZE); - if (buf == NULL) { - (void)printk(s); - ret = 0; - } else { - ret = min(buflen, ret); - memcpy(buf, s, ret); - } - va_end(args); - return ret; -} - -/* - * asc_prt_board_devices() - * - * Print driver information for devices attached to the board. - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). - * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. - */ -static int asc_prt_board_devices(struct Scsi_Host *shost, char *cp, int cplen) -{ - struct asc_board *boardp = shost_priv(shost); - int leftlen; - int totlen; - int len; - int chip_scsi_id; - int i; - - leftlen = cplen; - totlen = len = 0; - - len = asc_prt_line(cp, leftlen, - "\nDevice Information for AdvanSys SCSI Host %d:\n", - shost->host_no); - ASC_PRT_NEXT(); - - if (ASC_NARROW_BOARD(boardp)) { - chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; - } else { - chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; - } - - len = asc_prt_line(cp, leftlen, "Target IDs Detected:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) { - len = asc_prt_line(cp, leftlen, " %X,", i); - ASC_PRT_NEXT(); - } - } - len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id); - ASC_PRT_NEXT(); - - return totlen; -} - -/* - * Display Wide Board BIOS Information. - */ -static int asc_prt_adv_bios(struct Scsi_Host *shost, char *cp, int cplen) -{ - struct asc_board *boardp = shost_priv(shost); - int leftlen; - int totlen; - int len; - ushort major, minor, letter; - - leftlen = cplen; - totlen = len = 0; - - len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: "); - ASC_PRT_NEXT(); - - /* - * If the BIOS saved a valid signature, then fill in - * the BIOS code segment base address. - */ - if (boardp->bios_signature != 0x55AA) { - len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n"); - ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, - "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n"); - ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, - "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n"); - ASC_PRT_NEXT(); - } else { - major = (boardp->bios_version >> 12) & 0xF; - minor = (boardp->bios_version >> 8) & 0xF; - letter = (boardp->bios_version & 0xFF); - - len = asc_prt_line(cp, leftlen, "%d.%d%c\n", - major, minor, - letter >= 26 ? '?' : letter + 'A'); - ASC_PRT_NEXT(); - - /* - * Current available ROM BIOS release is 3.1I for UW - * and 3.2I for U2W. This code doesn't differentiate - * UW and U2W boards. - */ - if (major < 3 || (major <= 3 && minor < 1) || - (major <= 3 && minor <= 1 && letter < ('I' - 'A'))) { - len = asc_prt_line(cp, leftlen, - "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n"); - ASC_PRT_NEXT(); - len = asc_prt_line(cp, leftlen, - "ftp://ftp.connectcom.net/pub\n"); - ASC_PRT_NEXT(); - } - } - - return totlen; -} - -/* - * Add serial number to information bar if signature AAh - * is found in at bit 15-9 (7 bits) of word 1. - * - * Serial Number consists fo 12 alpha-numeric digits. - * - * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits) - * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits) - * 3-4 - Product ID (0-99) Word0: 9-0 (10 bits) - * 5 - Product revision (A-J) Word0: " " - * - * Signature Word1: 15-9 (7 bits) - * 6 - Year (0-9) Word1: 8-6 (3 bits) & Word2: 15 (1 bit) - * 7-8 - Week of the year (1-52) Word1: 5-0 (6 bits) - * - * 9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits) - * - * Note 1: Only production cards will have a serial number. - * - * Note 2: Signature is most significant 7 bits (0xFE). - * - * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE. - */ -static int asc_get_eeprom_string(ushort *serialnum, uchar *cp) -{ - ushort w, num; - - if ((serialnum[1] & 0xFE00) != ((ushort)0xAA << 8)) { - return ASC_FALSE; - } else { - /* - * First word - 6 digits. - */ - w = serialnum[0]; - - /* Product type - 1st digit. */ - if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') { - /* Product type is P=Prototype */ - *cp += 0x8; - } - cp++; - - /* Manufacturing location - 2nd digit. */ - *cp++ = 'A' + ((w & 0x1C00) >> 10); - - /* Product ID - 3rd, 4th digits. */ - num = w & 0x3FF; - *cp++ = '0' + (num / 100); - num %= 100; - *cp++ = '0' + (num / 10); - - /* Product revision - 5th digit. */ - *cp++ = 'A' + (num % 10); - - /* - * Second word - */ - w = serialnum[1]; - - /* - * Year - 6th digit. - * - * If bit 15 of third word is set, then the - * last digit of the year is greater than 7. - */ - if (serialnum[2] & 0x8000) { - *cp++ = '8' + ((w & 0x1C0) >> 6); - } else { - *cp++ = '0' + ((w & 0x1C0) >> 6); - } - - /* Week of year - 7th, 8th digits. */ - num = w & 0x003F; - *cp++ = '0' + num / 10; - num %= 10; - *cp++ = '0' + num; - - /* - * Third word - */ - w = serialnum[2] & 0x7FFF; - - /* Serial number - 9th digit. */ - *cp++ = 'A' + (w / 1000); - - /* 10th, 11th, 12th digits. */ - num = w % 1000; - *cp++ = '0' + num / 100; - num %= 100; - *cp++ = '0' + num / 10; - num %= 10; - *cp++ = '0' + num; - - *cp = '\0'; /* Null Terminate the string. */ - return ASC_TRUE; - } -} - -/* - * asc_prt_asc_board_eeprom() - * - * Print board EEPROM configuration. - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). - * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. - */ -static int asc_prt_asc_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen) -{ - struct asc_board *boardp = shost_priv(shost); - ASC_DVC_VAR *asc_dvc_varp; - int leftlen; - int totlen; - int len; - ASCEEP_CONFIG *ep; - int i; -#ifdef CONFIG_ISA - int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 }; -#endif /* CONFIG_ISA */ - uchar serialstr[13]; - - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; - ep = &boardp->eep_config.asc_eep; - - leftlen = cplen; - totlen = len = 0; - - len = asc_prt_line(cp, leftlen, - "\nEEPROM Settings for AdvanSys SCSI Host %d:\n", - shost->host_no); - ASC_PRT_NEXT(); - - if (asc_get_eeprom_string((ushort *)&ep->adapter_info[0], serialstr) - == ASC_TRUE) { - len = - asc_prt_line(cp, leftlen, " Serial Number: %s\n", - serialstr); - ASC_PRT_NEXT(); - } else { - if (ep->adapter_info[5] == 0xBB) { - len = asc_prt_line(cp, leftlen, - " Default Settings Used for EEPROM-less Adapter.\n"); - ASC_PRT_NEXT(); - } else { - len = asc_prt_line(cp, leftlen, - " Serial Number Signature Not Present.\n"); - ASC_PRT_NEXT(); - } - } - - len = asc_prt_line(cp, leftlen, - " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", - ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng, - ep->max_tag_qng); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Target ID: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %d", i); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Disconnects: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (ep-> - disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : - 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Command Queuing: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (ep-> - use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : - 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Start Motor: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (ep-> - start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : - 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Synchronous Transfer:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (ep-> - init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : - 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - -#ifdef CONFIG_ISA - if (asc_dvc_varp->bus_type & ASC_IS_ISA) { - len = asc_prt_line(cp, leftlen, - " Host ISA DMA speed: %d MB/S\n", - isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]); - ASC_PRT_NEXT(); - } -#endif /* CONFIG_ISA */ - - return totlen; -} - -/* - * asc_prt_adv_board_eeprom() - * - * Print board EEPROM configuration. - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). - * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. - */ -static int asc_prt_adv_board_eeprom(struct Scsi_Host *shost, char *cp, int cplen) -{ - struct asc_board *boardp = shost_priv(shost); - ADV_DVC_VAR *adv_dvc_varp; - int leftlen; - int totlen; - int len; - int i; - char *termstr; - uchar serialstr[13]; - ADVEEP_3550_CONFIG *ep_3550 = NULL; - ADVEEP_38C0800_CONFIG *ep_38C0800 = NULL; - ADVEEP_38C1600_CONFIG *ep_38C1600 = NULL; - ushort word; - ushort *wordp; - ushort sdtr_speed = 0; - - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - ep_3550 = &boardp->eep_config.adv_3550_eep; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - ep_38C0800 = &boardp->eep_config.adv_38C0800_eep; - } else { - ep_38C1600 = &boardp->eep_config.adv_38C1600_eep; - } - - leftlen = cplen; - totlen = len = 0; - - len = asc_prt_line(cp, leftlen, - "\nEEPROM Settings for AdvanSys SCSI Host %d:\n", - shost->host_no); - ASC_PRT_NEXT(); - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - wordp = &ep_3550->serial_number_word1; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - wordp = &ep_38C0800->serial_number_word1; - } else { - wordp = &ep_38C1600->serial_number_word1; - } - - if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) { - len = - asc_prt_line(cp, leftlen, " Serial Number: %s\n", - serialstr); - ASC_PRT_NEXT(); - } else { - len = asc_prt_line(cp, leftlen, - " Serial Number Signature Not Present.\n"); - ASC_PRT_NEXT(); - } - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - len = asc_prt_line(cp, leftlen, - " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", - ep_3550->adapter_scsi_id, - ep_3550->max_host_qng, ep_3550->max_dvc_qng); - ASC_PRT_NEXT(); - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - len = asc_prt_line(cp, leftlen, - " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", - ep_38C0800->adapter_scsi_id, - ep_38C0800->max_host_qng, - ep_38C0800->max_dvc_qng); - ASC_PRT_NEXT(); - } else { - len = asc_prt_line(cp, leftlen, - " Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n", - ep_38C1600->adapter_scsi_id, - ep_38C1600->max_host_qng, - ep_38C1600->max_dvc_qng); - ASC_PRT_NEXT(); - } - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - word = ep_3550->termination; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - word = ep_38C0800->termination_lvd; - } else { - word = ep_38C1600->termination_lvd; - } - switch (word) { - case 1: - termstr = "Low Off/High Off"; - break; - case 2: - termstr = "Low Off/High On"; - break; - case 3: - termstr = "Low On/High On"; - break; - default: - case 0: - termstr = "Automatic"; - break; - } - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - len = asc_prt_line(cp, leftlen, - " termination: %u (%s), bios_ctrl: 0x%x\n", - ep_3550->termination, termstr, - ep_3550->bios_ctrl); - ASC_PRT_NEXT(); - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - len = asc_prt_line(cp, leftlen, - " termination: %u (%s), bios_ctrl: 0x%x\n", - ep_38C0800->termination_lvd, termstr, - ep_38C0800->bios_ctrl); - ASC_PRT_NEXT(); - } else { - len = asc_prt_line(cp, leftlen, - " termination: %u (%s), bios_ctrl: 0x%x\n", - ep_38C1600->termination_lvd, termstr, - ep_38C1600->bios_ctrl); - ASC_PRT_NEXT(); - } - - len = asc_prt_line(cp, leftlen, " Target ID: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %X", i); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - word = ep_3550->disc_enable; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - word = ep_38C0800->disc_enable; - } else { - word = ep_38C1600->disc_enable; - } - len = asc_prt_line(cp, leftlen, " Disconnects: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - word = ep_3550->tagqng_able; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - word = ep_38C0800->tagqng_able; - } else { - word = ep_38C1600->tagqng_able; - } - len = asc_prt_line(cp, leftlen, " Command Queuing: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - word = ep_3550->start_motor; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - word = ep_38C0800->start_motor; - } else { - word = ep_38C1600->start_motor; - } - len = asc_prt_line(cp, leftlen, " Start Motor: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - len = asc_prt_line(cp, leftlen, " Synchronous Transfer:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (ep_3550-> - sdtr_able & ADV_TID_TO_TIDMASK(i)) ? - 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - } - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - len = asc_prt_line(cp, leftlen, " Ultra Transfer: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (ep_3550-> - ultra_able & ADV_TID_TO_TIDMASK(i)) - ? 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - } - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - word = ep_3550->wdtr_able; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - word = ep_38C0800->wdtr_able; - } else { - word = ep_38C1600->wdtr_able; - } - len = asc_prt_line(cp, leftlen, " Wide Transfer: "); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - len = asc_prt_line(cp, leftlen, " %c", - (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 || - adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) { - len = asc_prt_line(cp, leftlen, - " Synchronous Transfer Speed (Mhz):\n "); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - char *speed_str; - - if (i == 0) { - sdtr_speed = adv_dvc_varp->sdtr_speed1; - } else if (i == 4) { - sdtr_speed = adv_dvc_varp->sdtr_speed2; - } else if (i == 8) { - sdtr_speed = adv_dvc_varp->sdtr_speed3; - } else if (i == 12) { - sdtr_speed = adv_dvc_varp->sdtr_speed4; - } - switch (sdtr_speed & ADV_MAX_TID) { - case 0: - speed_str = "Off"; - break; - case 1: - speed_str = " 5"; - break; - case 2: - speed_str = " 10"; - break; - case 3: - speed_str = " 20"; - break; - case 4: - speed_str = " 40"; - break; - case 5: - speed_str = " 80"; - break; - default: - speed_str = "Unk"; - break; - } - len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str); - ASC_PRT_NEXT(); - if (i == 7) { - len = asc_prt_line(cp, leftlen, "\n "); - ASC_PRT_NEXT(); - } - sdtr_speed >>= 4; - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - } - - return totlen; -} - -/* - * asc_prt_driver_conf() - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). - * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. - */ -static int asc_prt_driver_conf(struct Scsi_Host *shost, char *cp, int cplen) -{ - struct asc_board *boardp = shost_priv(shost); - int leftlen; - int totlen; - int len; - int chip_scsi_id; - - leftlen = cplen; - totlen = len = 0; - - len = asc_prt_line(cp, leftlen, - "\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n", - shost->host_no); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n", - shost->host_busy, shost->last_reset, shost->max_id, - shost->max_lun, shost->max_channel); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n", - shost->unique_id, shost->can_queue, shost->this_id, - shost->sg_tablesize, shost->cmd_per_lun); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " unchecked_isa_dma %d, use_clustering %d\n", - shost->unchecked_isa_dma, shost->use_clustering); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n", - boardp->flags, boardp->last_reset, jiffies, - boardp->asc_n_io_port); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " io_port 0x%x\n", shost->io_port); - ASC_PRT_NEXT(); - - if (ASC_NARROW_BOARD(boardp)) { - chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id; - } else { - chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id; - } - - return totlen; -} - -/* - * asc_prt_asc_board_info() - * - * Print dynamic board configuration information. - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). - * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. - */ -static int asc_prt_asc_board_info(struct Scsi_Host *shost, char *cp, int cplen) -{ - struct asc_board *boardp = shost_priv(shost); - int chip_scsi_id; - int leftlen; - int totlen; - int len; - ASC_DVC_VAR *v; - ASC_DVC_CFG *c; - int i; - int renegotiate = 0; - - v = &boardp->dvc_var.asc_dvc_var; - c = &boardp->dvc_cfg.asc_dvc_cfg; - chip_scsi_id = c->chip_scsi_id; - - leftlen = cplen; - totlen = len = 0; - - len = asc_prt_line(cp, leftlen, - "\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n", - shost->host_no); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, " - "mcode_version 0x%x, err_code %u\n", - c->chip_version, c->mcode_date, c->mcode_version, - v->err_code); - ASC_PRT_NEXT(); - - /* Current number of commands waiting for the host. */ - len = asc_prt_line(cp, leftlen, - " Total Command Pending: %d\n", v->cur_total_qng); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Command Queuing:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - len = asc_prt_line(cp, leftlen, " %X:%c", - i, - (v-> - use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? - 'Y' : 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - /* Current number of commands waiting for a device. */ - len = asc_prt_line(cp, leftlen, " Command Queue Pending:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - /* Current limit on number of commands that can be sent to a device. */ - len = asc_prt_line(cp, leftlen, " Command Queue Limit:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - /* Indicate whether the device has returned queue full status. */ - len = asc_prt_line(cp, leftlen, " Command Queue Full:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) { - len = asc_prt_line(cp, leftlen, " %X:Y-%d", - i, boardp->queue_full_cnt[i]); - } else { - len = asc_prt_line(cp, leftlen, " %X:N", i); - } - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Synchronous Transfer:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ASC_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - len = asc_prt_line(cp, leftlen, " %X:%c", - i, - (v-> - sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : - 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - for (i = 0; i <= ASC_MAX_TID; i++) { - uchar syn_period_ix; - - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) || - ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - - len = asc_prt_line(cp, leftlen, " %X:", i); - ASC_PRT_NEXT(); - - if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) { - len = asc_prt_line(cp, leftlen, " Asynchronous"); - ASC_PRT_NEXT(); - } else { - syn_period_ix = - (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - - 1); - - len = asc_prt_line(cp, leftlen, - " Transfer Period Factor: %d (%d.%d Mhz),", - v->sdtr_period_tbl[syn_period_ix], - 250 / - v->sdtr_period_tbl[syn_period_ix], - ASC_TENTHS(250, - v-> - sdtr_period_tbl - [syn_period_ix])); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d", - boardp-> - sdtr_data[i] & ASC_SYN_MAX_OFFSET); - ASC_PRT_NEXT(); - } - - if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { - len = asc_prt_line(cp, leftlen, "*\n"); - renegotiate = 1; - } else { - len = asc_prt_line(cp, leftlen, "\n"); - } - ASC_PRT_NEXT(); - } - - if (renegotiate) { - len = asc_prt_line(cp, leftlen, - " * = Re-negotiation pending before next command.\n"); - ASC_PRT_NEXT(); - } - - return totlen; -} - -/* - * asc_prt_adv_board_info() - * - * Print dynamic board configuration information. - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). - * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. - */ -static int asc_prt_adv_board_info(struct Scsi_Host *shost, char *cp, int cplen) -{ - struct asc_board *boardp = shost_priv(shost); - int leftlen; - int totlen; - int len; - int i; - ADV_DVC_VAR *v; - ADV_DVC_CFG *c; - AdvPortAddr iop_base; - ushort chip_scsi_id; - ushort lramword; - uchar lrambyte; - ushort tagqng_able; - ushort sdtr_able, wdtr_able; - ushort wdtr_done, sdtr_done; - ushort period = 0; - int renegotiate = 0; - - v = &boardp->dvc_var.adv_dvc_var; - c = &boardp->dvc_cfg.adv_dvc_cfg; - iop_base = v->iop_base; - chip_scsi_id = v->chip_scsi_id; - - leftlen = cplen; - totlen = len = 0; - - len = asc_prt_line(cp, leftlen, - "\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n", - shost->host_no); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " iop_base 0x%lx, cable_detect: %X, err_code %u\n", - v->iop_base, - AdvReadWordRegister(iop_base, - IOPW_SCSI_CFG1) & CABLE_DETECT, - v->err_code); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " chip_version %u, mcode_date 0x%x, " - "mcode_version 0x%x\n", c->chip_version, - c->mcode_date, c->mcode_version); - ASC_PRT_NEXT(); - - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - len = asc_prt_line(cp, leftlen, " Queuing Enabled:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - - len = asc_prt_line(cp, leftlen, " %X:%c", - i, - (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : - 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Queue Limit:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, - lrambyte); - - len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, " Command Pending:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, - lrambyte); - - len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - len = asc_prt_line(cp, leftlen, " Wide Enabled:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - - len = asc_prt_line(cp, leftlen, " %X:%c", - i, - (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : - 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done); - len = asc_prt_line(cp, leftlen, " Transfer Bit Width:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - - AdvReadWordLram(iop_base, - ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i), - lramword); - - len = asc_prt_line(cp, leftlen, " %X:%d", - i, (lramword & 0x8000) ? 16 : 8); - ASC_PRT_NEXT(); - - if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) && - (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { - len = asc_prt_line(cp, leftlen, "*"); - ASC_PRT_NEXT(); - renegotiate = 1; - } - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - len = asc_prt_line(cp, leftlen, " Synchronous Enabled:"); - ASC_PRT_NEXT(); - for (i = 0; i <= ADV_MAX_TID; i++) { - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - - len = asc_prt_line(cp, leftlen, " %X:%c", - i, - (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : - 'N'); - ASC_PRT_NEXT(); - } - len = asc_prt_line(cp, leftlen, "\n"); - ASC_PRT_NEXT(); - - AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done); - for (i = 0; i <= ADV_MAX_TID; i++) { - - AdvReadWordLram(iop_base, - ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i), - lramword); - lramword &= ~0x8000; - - if ((chip_scsi_id == i) || - ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) || - ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) { - continue; - } - - len = asc_prt_line(cp, leftlen, " %X:", i); - ASC_PRT_NEXT(); - - if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */ - len = asc_prt_line(cp, leftlen, " Asynchronous"); - ASC_PRT_NEXT(); - } else { - len = - asc_prt_line(cp, leftlen, - " Transfer Period Factor: "); - ASC_PRT_NEXT(); - - if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */ - len = - asc_prt_line(cp, leftlen, "9 (80.0 Mhz),"); - ASC_PRT_NEXT(); - } else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */ - len = - asc_prt_line(cp, leftlen, "10 (40.0 Mhz),"); - ASC_PRT_NEXT(); - } else { /* 20 Mhz or below. */ - - period = (((lramword >> 8) * 25) + 50) / 4; - - if (period == 0) { /* Should never happen. */ - len = - asc_prt_line(cp, leftlen, - "%d (? Mhz), "); - ASC_PRT_NEXT(); - } else { - len = asc_prt_line(cp, leftlen, - "%d (%d.%d Mhz),", - period, 250 / period, - ASC_TENTHS(250, - period)); - ASC_PRT_NEXT(); - } - } - - len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d", - lramword & 0x1F); - ASC_PRT_NEXT(); - } - - if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) { - len = asc_prt_line(cp, leftlen, "*\n"); - renegotiate = 1; - } else { - len = asc_prt_line(cp, leftlen, "\n"); - } - ASC_PRT_NEXT(); - } - - if (renegotiate) { - len = asc_prt_line(cp, leftlen, - " * = Re-negotiation pending before next command.\n"); - ASC_PRT_NEXT(); - } - - return totlen; -} - -/* - * asc_proc_copy() - * - * Copy proc information to a read buffer taking into account the current - * read offset in the file and the remaining space in the read buffer. - */ -static int -asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen, - char *cp, int cplen) -{ - int cnt = 0; - - ASC_DBG(2, "offset %d, advoffset %d, cplen %d\n", - (unsigned)offset, (unsigned)advoffset, cplen); - if (offset <= advoffset) { - /* Read offset below current offset, copy everything. */ - cnt = min(cplen, leftlen); - ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n", - (ulong)curbuf, (ulong)cp, cnt); - memcpy(curbuf, cp, cnt); - } else if (offset < advoffset + cplen) { - /* Read offset within current range, partial copy. */ - cnt = (advoffset + cplen) - offset; - cp = (cp + cplen) - cnt; - cnt = min(cnt, leftlen); - ASC_DBG(2, "curbuf 0x%lx, cp 0x%lx, cnt %d\n", - (ulong)curbuf, (ulong)cp, cnt); - memcpy(curbuf, cp, cnt); - } - return cnt; -} - -#ifdef ADVANSYS_STATS -/* - * asc_prt_board_stats() - * - * Note: no single line should be greater than ASC_PRTLINE_SIZE, - * cf. asc_prt_line(). - * - * Return the number of characters copied into 'cp'. No more than - * 'cplen' characters will be copied to 'cp'. - */ -static int asc_prt_board_stats(struct Scsi_Host *shost, char *cp, int cplen) -{ - struct asc_board *boardp = shost_priv(shost); - struct asc_stats *s = &boardp->asc_stats; - - int leftlen = cplen; - int len, totlen = 0; - - len = asc_prt_line(cp, leftlen, - "\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", - shost->host_no); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n", - s->queuecommand, s->reset, s->biosparam, - s->interrupt); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n", - s->callback, s->done, s->build_error, - s->adv_build_noreq, s->adv_build_nosg); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, - " exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n", - s->exe_noerror, s->exe_busy, s->exe_error, - s->exe_unknown); - ASC_PRT_NEXT(); - - /* - * Display data transfer statistics. - */ - if (s->xfer_cnt > 0) { - len = asc_prt_line(cp, leftlen, " xfer_cnt %lu, xfer_elem %lu, ", - s->xfer_cnt, s->xfer_elem); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, "xfer_bytes %lu.%01lu kb\n", - s->xfer_sect / 2, ASC_TENTHS(s->xfer_sect, 2)); - ASC_PRT_NEXT(); - - /* Scatter gather transfer statistics */ - len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ", - s->xfer_elem / s->xfer_cnt, - ASC_TENTHS(s->xfer_elem, s->xfer_cnt)); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ", - (s->xfer_sect / 2) / s->xfer_elem, - ASC_TENTHS((s->xfer_sect / 2), s->xfer_elem)); - ASC_PRT_NEXT(); - - len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n", - (s->xfer_sect / 2) / s->xfer_cnt, - ASC_TENTHS((s->xfer_sect / 2), s->xfer_cnt)); - ASC_PRT_NEXT(); - } - - return totlen; -} -#endif /* ADVANSYS_STATS */ - -/* - * advansys_proc_info() - /proc/scsi/advansys/{0,1,2,3,...} - * - * *buffer: I/O buffer - * **start: if inout == FALSE pointer into buffer where user read should start - * offset: current offset into a /proc/scsi/advansys/[0...] file - * length: length of buffer - * hostno: Scsi_Host host_no - * inout: TRUE - user is writing; FALSE - user is reading - * - * Return the number of bytes read from or written to a - * /proc/scsi/advansys/[0...] file. - * - * Note: This function uses the per board buffer 'prtbuf' which is - * allocated when the board is initialized in advansys_detect(). The - * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is - * used to write to the buffer. The way asc_proc_copy() is written - * if 'prtbuf' is too small it will not be overwritten. Instead the - * user just won't get all the available statistics. - */ -static int -advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start, - off_t offset, int length, int inout) -{ - struct asc_board *boardp = shost_priv(shost); - char *cp; - int cplen; - int cnt; - int totcnt; - int leftlen; - char *curbuf; - off_t advoffset; - - ASC_DBG(1, "begin\n"); - - /* - * User write not supported. - */ - if (inout == TRUE) - return -ENOSYS; - - /* - * User read of /proc/scsi/advansys/[0...] file. - */ - - /* Copy read data starting at the beginning of the buffer. */ - *start = buffer; - curbuf = buffer; - advoffset = 0; - totcnt = 0; - leftlen = length; - - /* - * Get board configuration information. - * - * advansys_info() returns the board string from its own static buffer. - */ - cp = (char *)advansys_info(shost); - strcat(cp, "\n"); - cplen = strlen(cp); - /* Copy board information. */ - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG(1, "totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - - /* - * Display Wide Board BIOS Information. - */ - if (!ASC_NARROW_BOARD(boardp)) { - cp = boardp->prtbuf; - cplen = asc_prt_adv_bios(shost, cp, ASC_PRTBUF_SIZE); - BUG_ON(cplen >= ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, - cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG(1, "totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - } - - /* - * Display driver information for each device attached to the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_board_devices(shost, cp, ASC_PRTBUF_SIZE); - BUG_ON(cplen >= ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG(1, "totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - - /* - * Display EEPROM configuration for the board. - */ - cp = boardp->prtbuf; - if (ASC_NARROW_BOARD(boardp)) { - cplen = asc_prt_asc_board_eeprom(shost, cp, ASC_PRTBUF_SIZE); - } else { - cplen = asc_prt_adv_board_eeprom(shost, cp, ASC_PRTBUF_SIZE); - } - BUG_ON(cplen >= ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG(1, "totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - - /* - * Display driver configuration and information for the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_driver_conf(shost, cp, ASC_PRTBUF_SIZE); - BUG_ON(cplen >= ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG(1, "totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - -#ifdef ADVANSYS_STATS - /* - * Display driver statistics for the board. - */ - cp = boardp->prtbuf; - cplen = asc_prt_board_stats(shost, cp, ASC_PRTBUF_SIZE); - BUG_ON(cplen >= ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG(1, "totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; -#endif /* ADVANSYS_STATS */ - - /* - * Display Asc Library dynamic configuration information - * for the board. - */ - cp = boardp->prtbuf; - if (ASC_NARROW_BOARD(boardp)) { - cplen = asc_prt_asc_board_info(shost, cp, ASC_PRTBUF_SIZE); - } else { - cplen = asc_prt_adv_board_info(shost, cp, ASC_PRTBUF_SIZE); - } - BUG_ON(cplen >= ASC_PRTBUF_SIZE); - cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen); - totcnt += cnt; - leftlen -= cnt; - if (leftlen == 0) { - ASC_DBG(1, "totcnt %d\n", totcnt); - return totcnt; - } - advoffset += cplen; - curbuf += cnt; - - ASC_DBG(1, "totcnt %d\n", totcnt); - - return totcnt; -} -#endif /* CONFIG_PROC_FS */ - -static void asc_scsi_done(struct scsi_cmnd *scp) -{ - scsi_dma_unmap(scp); - ASC_STATS(scp->device->host, done); - scp->scsi_done(scp); -} - -static void AscSetBank(PortAddr iop_base, uchar bank) -{ - uchar val; - - val = AscGetChipControl(iop_base) & - (~ - (CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | - CC_CHIP_RESET)); - if (bank == 1) { - val |= CC_BANK_ONE; - } else if (bank == 2) { - val |= CC_DIAG | CC_BANK_ONE; - } else { - val &= ~CC_BANK_ONE; - } - AscSetChipControl(iop_base, val); -} - -static void AscSetChipIH(PortAddr iop_base, ushort ins_code) -{ - AscSetBank(iop_base, 1); - AscWriteChipIH(iop_base, ins_code); - AscSetBank(iop_base, 0); -} - -static int AscStartChip(PortAddr iop_base) -{ - AscSetChipControl(iop_base, 0); - if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { - return (0); - } - return (1); -} - -static int AscStopChip(PortAddr iop_base) -{ - uchar cc_val; - - cc_val = - AscGetChipControl(iop_base) & - (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG)); - AscSetChipControl(iop_base, (uchar)(cc_val | CC_HALT)); - AscSetChipIH(iop_base, INS_HALT); - AscSetChipIH(iop_base, INS_RFLAG_WTM); - if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) { - return (0); - } - return (1); -} - -static int AscIsChipHalted(PortAddr iop_base) -{ - if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) { - if ((AscGetChipControl(iop_base) & CC_HALT) != 0) { - return (1); - } - } - return (0); -} - -static int AscResetChipAndScsiBus(ASC_DVC_VAR *asc_dvc) -{ - PortAddr iop_base; - int i = 10; - - iop_base = asc_dvc->iop_base; - while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) - && (i-- > 0)) { - mdelay(100); - } - AscStopChip(iop_base); - AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT); - udelay(60); - AscSetChipIH(iop_base, INS_RFLAG_WTM); - AscSetChipIH(iop_base, INS_HALT); - AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT); - AscSetChipControl(iop_base, CC_HALT); - mdelay(200); - AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); - AscSetChipStatus(iop_base, 0); - return (AscIsChipHalted(iop_base)); -} - -static int AscFindSignature(PortAddr iop_base) -{ - ushort sig_word; - - ASC_DBG(1, "AscGetChipSignatureByte(0x%x) 0x%x\n", - iop_base, AscGetChipSignatureByte(iop_base)); - if (AscGetChipSignatureByte(iop_base) == (uchar)ASC_1000_ID1B) { - ASC_DBG(1, "AscGetChipSignatureWord(0x%x) 0x%x\n", - iop_base, AscGetChipSignatureWord(iop_base)); - sig_word = AscGetChipSignatureWord(iop_base); - if ((sig_word == (ushort)ASC_1000_ID0W) || - (sig_word == (ushort)ASC_1000_ID0W_FIX)) { - return (1); - } - } - return (0); -} - -static void AscEnableInterrupt(PortAddr iop_base) -{ - ushort cfg; - - cfg = AscGetChipCfgLsw(iop_base); - AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON); -} - -static void AscDisableInterrupt(PortAddr iop_base) -{ - ushort cfg; - - cfg = AscGetChipCfgLsw(iop_base); - AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON)); -} - -static uchar AscReadLramByte(PortAddr iop_base, ushort addr) -{ - unsigned char byte_data; - unsigned short word_data; - - if (isodd_word(addr)) { - AscSetChipLramAddr(iop_base, addr - 1); - word_data = AscGetChipLramData(iop_base); - byte_data = (word_data >> 8) & 0xFF; - } else { - AscSetChipLramAddr(iop_base, addr); - word_data = AscGetChipLramData(iop_base); - byte_data = word_data & 0xFF; - } - return byte_data; -} - -static ushort AscReadLramWord(PortAddr iop_base, ushort addr) -{ - ushort word_data; - - AscSetChipLramAddr(iop_base, addr); - word_data = AscGetChipLramData(iop_base); - return (word_data); -} - -#if CC_VERY_LONG_SG_LIST -static ASC_DCNT AscReadLramDWord(PortAddr iop_base, ushort addr) -{ - ushort val_low, val_high; - ASC_DCNT dword_data; - - AscSetChipLramAddr(iop_base, addr); - val_low = AscGetChipLramData(iop_base); - val_high = AscGetChipLramData(iop_base); - dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low; - return (dword_data); -} -#endif /* CC_VERY_LONG_SG_LIST */ - -static void -AscMemWordSetLram(PortAddr iop_base, ushort s_addr, ushort set_wval, int words) -{ - int i; - - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < words; i++) { - AscSetChipLramData(iop_base, set_wval); - } -} - -static void AscWriteLramWord(PortAddr iop_base, ushort addr, ushort word_val) -{ - AscSetChipLramAddr(iop_base, addr); - AscSetChipLramData(iop_base, word_val); -} - -static void AscWriteLramByte(PortAddr iop_base, ushort addr, uchar byte_val) -{ - ushort word_data; - - if (isodd_word(addr)) { - addr--; - word_data = AscReadLramWord(iop_base, addr); - word_data &= 0x00FF; - word_data |= (((ushort)byte_val << 8) & 0xFF00); - } else { - word_data = AscReadLramWord(iop_base, addr); - word_data &= 0xFF00; - word_data |= ((ushort)byte_val & 0x00FF); - } - AscWriteLramWord(iop_base, addr, word_data); -} - -/* - * Copy 2 bytes to LRAM. - * - * The source data is assumed to be in little-endian order in memory - * and is maintained in little-endian order when written to LRAM. - */ -static void -AscMemWordCopyPtrToLram(PortAddr iop_base, ushort s_addr, - const uchar *s_buffer, int words) -{ - int i; - - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < 2 * words; i += 2) { - /* - * On a little-endian system the second argument below - * produces a little-endian ushort which is written to - * LRAM in little-endian order. On a big-endian system - * the second argument produces a big-endian ushort which - * is "transparently" byte-swapped by outpw() and written - * in little-endian order to LRAM. - */ - outpw(iop_base + IOP_RAM_DATA, - ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); - } -} - -/* - * Copy 4 bytes to LRAM. - * - * The source data is assumed to be in little-endian order in memory - * and is maintained in little-endian order when written to LRAM. - */ -static void -AscMemDWordCopyPtrToLram(PortAddr iop_base, - ushort s_addr, uchar *s_buffer, int dwords) -{ - int i; - - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < 4 * dwords; i += 4) { - outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */ - outpw(iop_base + IOP_RAM_DATA, ((ushort)s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */ - } -} - -/* - * Copy 2 bytes from LRAM. - * - * The source data is assumed to be in little-endian order in LRAM - * and is maintained in little-endian order when written to memory. - */ -static void -AscMemWordCopyPtrFromLram(PortAddr iop_base, - ushort s_addr, uchar *d_buffer, int words) -{ - int i; - ushort word; - - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < 2 * words; i += 2) { - word = inpw(iop_base + IOP_RAM_DATA); - d_buffer[i] = word & 0xff; - d_buffer[i + 1] = (word >> 8) & 0xff; - } -} - -static ASC_DCNT AscMemSumLramWord(PortAddr iop_base, ushort s_addr, int words) -{ - ASC_DCNT sum; - int i; - - sum = 0L; - for (i = 0; i < words; i++, s_addr += 2) { - sum += AscReadLramWord(iop_base, s_addr); - } - return (sum); -} - -static ushort AscInitLram(ASC_DVC_VAR *asc_dvc) -{ - uchar i; - ushort s_addr; - PortAddr iop_base; - ushort warn_code; - - iop_base = asc_dvc->iop_base; - warn_code = 0; - AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0, - (ushort)(((int)(asc_dvc->max_total_qng + 2 + 1) * - 64) >> 1)); - i = ASC_MIN_ACTIVE_QNO; - s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE; - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), - (uchar)(i + 1)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), - (uchar)(asc_dvc->max_total_qng)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), - (uchar)i); - i++; - s_addr += ASC_QBLK_SIZE; - for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) { - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), - (uchar)(i + 1)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), - (uchar)(i - 1)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), - (uchar)i); - } - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_FWD), - (uchar)ASC_QLINK_END); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_BWD), - (uchar)(asc_dvc->max_total_qng - 1)); - AscWriteLramByte(iop_base, (ushort)(s_addr + ASC_SCSIQ_B_QNO), - (uchar)asc_dvc->max_total_qng); - i++; - s_addr += ASC_QBLK_SIZE; - for (; i <= (uchar)(asc_dvc->max_total_qng + 3); - i++, s_addr += ASC_QBLK_SIZE) { - AscWriteLramByte(iop_base, - (ushort)(s_addr + (ushort)ASC_SCSIQ_B_FWD), i); - AscWriteLramByte(iop_base, - (ushort)(s_addr + (ushort)ASC_SCSIQ_B_BWD), i); - AscWriteLramByte(iop_base, - (ushort)(s_addr + (ushort)ASC_SCSIQ_B_QNO), i); - } - return warn_code; -} - -static ASC_DCNT -AscLoadMicroCode(PortAddr iop_base, ushort s_addr, - const uchar *mcode_buf, ushort mcode_size) -{ - ASC_DCNT chksum; - ushort mcode_word_size; - ushort mcode_chksum; - - /* Write the microcode buffer starting at LRAM address 0. */ - mcode_word_size = (ushort)(mcode_size >> 1); - AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size); - AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size); - - chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size); - ASC_DBG(1, "chksum 0x%lx\n", (ulong)chksum); - mcode_chksum = (ushort)AscMemSumLramWord(iop_base, - (ushort)ASC_CODE_SEC_BEG, - (ushort)((mcode_size - - s_addr - (ushort) - ASC_CODE_SEC_BEG) / - 2)); - ASC_DBG(1, "mcode_chksum 0x%lx\n", (ulong)mcode_chksum); - AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum); - AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size); - return chksum; -} - -static void AscInitQLinkVar(ASC_DVC_VAR *asc_dvc) -{ - PortAddr iop_base; - int i; - ushort lram_addr; - - iop_base = asc_dvc->iop_base; - AscPutRiscVarFreeQHead(iop_base, 1); - AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng); - AscPutVarFreeQHead(iop_base, 1); - AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng); - AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B, - (uchar)((int)asc_dvc->max_total_qng + 1)); - AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B, - (uchar)((int)asc_dvc->max_total_qng + 2)); - AscWriteLramByte(iop_base, (ushort)ASCV_TOTAL_READY_Q_B, - asc_dvc->max_total_qng); - AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0); - AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0); - AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0); - AscPutQDoneInProgress(iop_base, 0); - lram_addr = ASC_QADR_BEG; - for (i = 0; i < 32; i++, lram_addr += 2) { - AscWriteLramWord(iop_base, lram_addr, 0); - } -} - -static ushort AscInitMicroCodeVar(ASC_DVC_VAR *asc_dvc) -{ - int i; - ushort warn_code; - PortAddr iop_base; - ASC_PADDR phy_addr; - ASC_DCNT phy_size; - struct asc_board *board = asc_dvc_to_board(asc_dvc); - - iop_base = asc_dvc->iop_base; - warn_code = 0; - for (i = 0; i <= ASC_MAX_TID; i++) { - AscPutMCodeInitSDTRAtID(iop_base, i, - asc_dvc->cfg->sdtr_period_offset[i]); - } - - AscInitQLinkVar(asc_dvc); - AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B, - asc_dvc->cfg->disc_enable); - AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B, - ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id)); - - /* Ensure overrun buffer is aligned on an 8 byte boundary. */ - BUG_ON((unsigned long)asc_dvc->overrun_buf & 7); - asc_dvc->overrun_dma = dma_map_single(board->dev, asc_dvc->overrun_buf, - ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(board->dev, asc_dvc->overrun_dma)) { - warn_code = -ENOMEM; - goto err_dma_map; - } - phy_addr = cpu_to_le32(asc_dvc->overrun_dma); - AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D, - (uchar *)&phy_addr, 1); - phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE); - AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D, - (uchar *)&phy_size, 1); - - asc_dvc->cfg->mcode_date = - AscReadLramWord(iop_base, (ushort)ASCV_MC_DATE_W); - asc_dvc->cfg->mcode_version = - AscReadLramWord(iop_base, (ushort)ASCV_MC_VER_W); - - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; - warn_code = UW_ERR; - goto err_mcode_start; - } - if (AscStartChip(iop_base) != 1) { - asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; - warn_code = UW_ERR; - goto err_mcode_start; - } - - return warn_code; - -err_mcode_start: - dma_unmap_single(board->dev, asc_dvc->overrun_dma, - ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); -err_dma_map: - asc_dvc->overrun_dma = 0; - return warn_code; -} - -static ushort AscInitAsc1000Driver(ASC_DVC_VAR *asc_dvc) -{ - const struct firmware *fw; - const char fwname[] = "advansys/mcode.bin"; - int err; - unsigned long chksum; - ushort warn_code; - PortAddr iop_base; - - iop_base = asc_dvc->iop_base; - warn_code = 0; - if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) && - !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) { - AscResetChipAndScsiBus(asc_dvc); - mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */ - } - asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC; - if (asc_dvc->err_code != 0) - return UW_ERR; - if (!AscFindSignature(asc_dvc->iop_base)) { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - return warn_code; - } - AscDisableInterrupt(iop_base); - warn_code |= AscInitLram(asc_dvc); - if (asc_dvc->err_code != 0) - return UW_ERR; - - err = request_firmware(&fw, fwname, asc_dvc->drv_ptr->dev); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fwname, err); - asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; - return err; - } - if (fw->size < 4) { - printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", - fw->size, fwname); - release_firmware(fw); - asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; - return -EINVAL; - } - chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | - (fw->data[1] << 8) | fw->data[0]; - ASC_DBG(1, "_asc_mcode_chksum 0x%lx\n", (ulong)chksum); - if (AscLoadMicroCode(iop_base, 0, &fw->data[4], - fw->size - 4) != chksum) { - asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM; - release_firmware(fw); - return warn_code; - } - release_firmware(fw); - warn_code |= AscInitMicroCodeVar(asc_dvc); - if (!asc_dvc->overrun_dma) - return warn_code; - asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC; - AscEnableInterrupt(iop_base); - return warn_code; -} - -/* - * Load the Microcode - * - * Write the microcode image to RISC memory starting at address 0. - * - * The microcode is stored compressed in the following format: - * - * 254 word (508 byte) table indexed by byte code followed - * by the following byte codes: - * - * 1-Byte Code: - * 00: Emit word 0 in table. - * 01: Emit word 1 in table. - * . - * FD: Emit word 253 in table. - * - * Multi-Byte Code: - * FE WW WW: (3 byte code) Word to emit is the next word WW WW. - * FF BB WW WW: (4 byte code) Emit BB count times next word WW WW. - * - * Returns 0 or an error if the checksum doesn't match - */ -static int AdvLoadMicrocode(AdvPortAddr iop_base, const unsigned char *buf, - int size, int memsize, int chksum) -{ - int i, j, end, len = 0; - ADV_DCNT sum; - - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - - for (i = 253 * 2; i < size; i++) { - if (buf[i] == 0xff) { - unsigned short word = (buf[i + 3] << 8) | buf[i + 2]; - for (j = 0; j < buf[i + 1]; j++) { - AdvWriteWordAutoIncLram(iop_base, word); - len += 2; - } - i += 3; - } else if (buf[i] == 0xfe) { - unsigned short word = (buf[i + 2] << 8) | buf[i + 1]; - AdvWriteWordAutoIncLram(iop_base, word); - i += 2; - len += 2; - } else { - unsigned int off = buf[i] * 2; - unsigned short word = (buf[off + 1] << 8) | buf[off]; - AdvWriteWordAutoIncLram(iop_base, word); - len += 2; - } - } - - end = len; - - while (len < memsize) { - AdvWriteWordAutoIncLram(iop_base, 0); - len += 2; - } - - /* Verify the microcode checksum. */ - sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0); - - for (len = 0; len < end; len += 2) { - sum += AdvReadWordAutoIncLram(iop_base); - } - - if (sum != chksum) - return ASC_IERR_MCODE_CHKSUM; - - return 0; -} - -static void AdvBuildCarrierFreelist(struct adv_dvc_var *asc_dvc) -{ - ADV_CARR_T *carrp; - ADV_SDCNT buf_size; - ADV_PADDR carr_paddr; - - carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf); - asc_dvc->carr_freelist = NULL; - if (carrp == asc_dvc->carrier_buf) { - buf_size = ADV_CARRIER_BUFSIZE; - } else { - buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T); - } - - do { - /* Get physical address of the carrier 'carrp'. */ - carr_paddr = cpu_to_le32(virt_to_bus(carrp)); - - buf_size -= sizeof(ADV_CARR_T); - - carrp->carr_pa = carr_paddr; - carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp)); - - /* - * Insert the carrier at the beginning of the freelist. - */ - carrp->next_vpa = - cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); - asc_dvc->carr_freelist = carrp; - - carrp++; - } while (buf_size > 0); -} - -/* - * Send an idle command to the chip and wait for completion. - * - * Command completion is polled for once per microsecond. - * - * The function can be called from anywhere including an interrupt handler. - * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical() - * functions to prevent reentrancy. - * - * Return Values: - * ADV_TRUE - command completed successfully - * ADV_FALSE - command failed - * ADV_ERROR - command timed out - */ -static int -AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc, - ushort idle_cmd, ADV_DCNT idle_cmd_parameter) -{ - int result; - ADV_DCNT i, j; - AdvPortAddr iop_base; - - iop_base = asc_dvc->iop_base; - - /* - * Clear the idle command status which is set by the microcode - * to a non-zero value to indicate when the command is completed. - * The non-zero result is one of the IDLE_CMD_STATUS_* values - */ - AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort)0); - - /* - * Write the idle command value after the idle command parameter - * has been written to avoid a race condition. If the order is not - * followed, the microcode may process the idle command before the - * parameters have been written to LRAM. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER, - cpu_to_le32(idle_cmd_parameter)); - AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd); - - /* - * Tickle the RISC to tell it to process the idle command. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { - /* - * Clear the tickle value. In the ASC-3550 the RISC flag - * command 'clr_tickle_b' does not work unless the host - * value is cleared. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP); - } - - /* Wait for up to 100 millisecond for the idle command to timeout. */ - for (i = 0; i < SCSI_WAIT_100_MSEC; i++) { - /* Poll once each microsecond for command completion. */ - for (j = 0; j < SCSI_US_PER_MSEC; j++) { - AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, - result); - if (result != 0) - return result; - udelay(1); - } - } - - BUG(); /* The idle command should never timeout. */ - return ADV_ERROR; -} - -/* - * Reset SCSI Bus and purge all outstanding requests. - * - * Return Value: - * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset. - * ADV_FALSE(0) - Microcode command failed. - * ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC - * may be hung which requires driver recovery. - */ -static int AdvResetSB(ADV_DVC_VAR *asc_dvc) -{ - int status; - - /* - * Send the SCSI Bus Reset idle start idle command which asserts - * the SCSI Bus Reset signal. - */ - status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_START, 0L); - if (status != ADV_TRUE) { - return status; - } - - /* - * Delay for the specified SCSI Bus Reset hold time. - * - * The hold time delay is done on the host because the RISC has no - * microsecond accurate timer. - */ - udelay(ASC_SCSI_RESET_HOLD_TIME_US); - - /* - * Send the SCSI Bus Reset end idle command which de-asserts - * the SCSI Bus Reset signal and purges any pending requests. - */ - status = AdvSendIdleCmd(asc_dvc, (ushort)IDLE_CMD_SCSI_RESET_END, 0L); - if (status != ADV_TRUE) { - return status; - } - - mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */ - - return status; -} - -/* - * Initialize the ASC-3550. - * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - * - * Needed after initialization for error recovery. - */ -static int AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc) -{ - const struct firmware *fw; - const char fwname[] = "advansys/3550.bin"; - AdvPortAddr iop_base; - ushort warn_code; - int begin_addr; - int end_addr; - ushort code_sum; - int word; - int i; - int err; - unsigned long chksum; - ushort scsi_cfg1; - uchar tid; - ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ - ushort wdtr_able = 0, sdtr_able, tagqng_able; - uchar max_cmd[ADV_MAX_TID + 1]; - - /* If there is already an error, don't continue. */ - if (asc_dvc->err_code != 0) - return ADV_ERROR; - - /* - * The caller must set 'chip_type' to ADV_CHIP_ASC3550. - */ - if (asc_dvc->chip_type != ADV_CHIP_ASC3550) { - asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; - return ADV_ERROR; - } - - warn_code = 0; - iop_base = asc_dvc->iop_base; - - /* - * Save the RISC memory BIOS region before writing the microcode. - * The BIOS may already be loaded and using its RISC LRAM region - * so its region must be saved and restored. - * - * Note: This code makes the assumption, which is currently true, - * that a chip reset does not clear RISC LRAM. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Save current per TID negotiated values. - */ - if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == 0x55AA) { - ushort bios_version, major, minor; - - bios_version = - bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM) / 2]; - major = (bios_version >> 12) & 0xF; - minor = (bios_version >> 8) & 0xF; - if (major < 3 || (major == 3 && minor == 1)) { - /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */ - AdvReadWordLram(iop_base, 0x120, wdtr_able); - } else { - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - } - } - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - - err = request_firmware(&fw, fwname, asc_dvc->drv_ptr->dev); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fwname, err); - asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; - return err; - } - if (fw->size < 4) { - printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", - fw->size, fwname); - release_firmware(fw); - asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; - return -EINVAL; - } - chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | - (fw->data[1] << 8) | fw->data[0]; - asc_dvc->err_code = AdvLoadMicrocode(iop_base, &fw->data[4], - fw->size - 4, ADV_3550_MEMSIZE, - chksum); - release_firmware(fw); - if (asc_dvc->err_code) - return ADV_ERROR; - - /* - * Restore the RISC memory BIOS region. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Calculate and write the microcode code checksum to the microcode - * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). - */ - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); - AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); - code_sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); - for (word = begin_addr; word < end_addr; word += 2) { - code_sum += AdvReadWordAutoIncLram(iop_base); - } - AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - - /* - * Read and save microcode version and date. - */ - AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, - asc_dvc->cfg->mcode_date); - AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, - asc_dvc->cfg->mcode_version); - - /* - * Set the chip type to indicate the ASC3550. - */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550); - - /* - * If the PCI Configuration Command Register "Parity Error Response - * Control" Bit was clear (0), then set the microcode variable - * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode - * to ignore DMA parity errors. - */ - if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - word |= CONTROL_FLAG_IGNORE_PERR; - AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - } - - /* - * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO - * threshold of 128 bytes. This register is only accessible to the host. - */ - AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - START_CTL_EMFU | READ_CMD_MRM); - - /* - * Microcode operating variables for WDTR, SDTR, and command tag - * queuing will be set in slave_configure() based on what a - * device reports it is capable of in Inquiry byte 7. - * - * If SCSI Bus Resets have been disabled, then directly set - * SDTR and WDTR from the EEPROM configuration. This will allow - * the BIOS and warm boot to work without a SCSI bus hang on - * the Inquiry caused by host and target mismatched DTR values. - * Without the SCSI Bus Reset, before an Inquiry a device can't - * be assumed to be in Asynchronous, Narrow mode. - */ - if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, - asc_dvc->wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, - asc_dvc->sdtr_able); - } - - /* - * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID - * bitmask. These values determine the maximum SDTR speed negotiated - * with a device. - * - * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them - * without determining here whether the device supports SDTR. - * - * 4-bit speed SDTR speed name - * =========== =============== - * 0000b (0x0) SDTR disabled - * 0001b (0x1) 5 Mhz - * 0010b (0x2) 10 Mhz - * 0011b (0x3) 20 Mhz (Ultra) - * 0100b (0x4) 40 Mhz (LVD/Ultra2) - * 0101b (0x5) 80 Mhz (LVD2/Ultra3) - * 0110b (0x6) Undefined - * . - * 1111b (0xF) Undefined - */ - word = 0; - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able) { - /* Set Ultra speed for TID 'tid'. */ - word |= (0x3 << (4 * (tid % 4))); - } else { - /* Set Fast speed for TID 'tid'. */ - word |= (0x2 << (4 * (tid % 4))); - } - if (tid == 3) { /* Check if done with sdtr_speed1. */ - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word); - word = 0; - } else if (tid == 7) { /* Check if done with sdtr_speed2. */ - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word); - word = 0; - } else if (tid == 11) { /* Check if done with sdtr_speed3. */ - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word); - word = 0; - } else if (tid == 15) { /* Check if done with sdtr_speed4. */ - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word); - /* End of loop. */ - } - } - - /* - * Set microcode operating variable for the disconnect per TID bitmask. - */ - AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, - asc_dvc->cfg->disc_enable); - - /* - * Set SCSI_CFG0 Microcode Default Value. - * - * The microcode will set the SCSI_CFG0 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | - asc_dvc->chip_scsi_id); - - /* - * Determine SCSI_CFG1 Microcode Default Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - - /* Read current SCSI_CFG1 Register value. */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - - /* - * If all three connectors are in use, return an error. - */ - if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 || - (scsi_cfg1 & CABLE_ILLEGAL_B) == 0) { - asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION; - return ADV_ERROR; - } - - /* - * If the internal narrow cable is reversed all of the SCSI_CTRL - * register signals will be set. Check for and return an error if - * this condition is found. - */ - if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { - asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; - return ADV_ERROR; - } - - /* - * If this is a differential board and a single-ended device - * is attached to one of the connectors, return an error. - */ - if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0) { - asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE; - return ADV_ERROR; - } - - /* - * If automatic termination control is enabled, then set the - * termination value based on a table listed in a_condor.h. - * - * If manual termination was specified with an EEPROM setting - * then 'termination' was set-up in AdvInitFrom3550EEPROM() and - * is ready to be 'ored' into SCSI_CFG1. - */ - if (asc_dvc->cfg->termination == 0) { - /* - * The software always controls termination by setting TERM_CTL_SEL. - * If TERM_CTL_SEL were set to 0, the hardware would set termination. - */ - asc_dvc->cfg->termination |= TERM_CTL_SEL; - - switch (scsi_cfg1 & CABLE_DETECT) { - /* TERM_CTL_H: on, TERM_CTL_L: on */ - case 0x3: - case 0x7: - case 0xB: - case 0xD: - case 0xE: - case 0xF: - asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L); - break; - - /* TERM_CTL_H: on, TERM_CTL_L: off */ - case 0x1: - case 0x5: - case 0x9: - case 0xA: - case 0xC: - asc_dvc->cfg->termination |= TERM_CTL_H; - break; - - /* TERM_CTL_H: off, TERM_CTL_L: off */ - case 0x2: - case 0x6: - break; - } - } - - /* - * Clear any set TERM_CTL_H and TERM_CTL_L bits. - */ - scsi_cfg1 &= ~TERM_CTL; - - /* - * Invert the TERM_CTL_H and TERM_CTL_L bits and then - * set 'scsi_cfg1'. The TERM_POL bit does not need to be - * referenced, because the hardware internally inverts - * the Termination High and Low bits if TERM_POL is set. - */ - scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL)); - - /* - * Set SCSI_CFG1 Microcode Default Value - * - * Set filter value and possibly modified termination control - * bits in the Microcode SCSI_CFG1 Register Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, - FLTR_DISABLE | scsi_cfg1); - - /* - * Set MEM_CFG Microcode Default Value - * - * The microcode will set the MEM_CFG register using this value - * after it is started below. - * - * MEM_CFG may be accessed as a word or byte, but only bits 0-7 - * are defined. - * - * ASC-3550 has 8KB internal memory. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_8KB); - - /* - * Set SEL_MASK Microcode Default Value - * - * The microcode will set the SEL_MASK register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, - ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); - - AdvBuildCarrierFreelist(asc_dvc); - - /* - * Set-up the Host->RISC Initiator Command Queue (ICQ). - */ - - if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); - - /* - * The first command issued will be placed in the stopper carrier. - */ - asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC ICQ physical address start value. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); - - /* - * Set-up the RISC->Host Initiator Response Queue (IRQ). - */ - if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); - - /* - * The first command completed by the RISC will be placed in - * the stopper. - * - * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is - * completed the RISC will set the ASC_RQ_STOPPER bit. - */ - asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC IRQ physical address start value. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); - asc_dvc->carr_pending_cnt = 0; - - AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, - (ADV_INTR_ENABLE_HOST_INTR | - ADV_INTR_ENABLE_GLOBAL_INTR)); - - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); - AdvWriteWordRegister(iop_base, IOPW_PC, word); - - /* finally, finally, gentlemen, start your engine */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); - - /* - * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus - * Resets should be performed. The RISC has to be running - * to issue a SCSI Bus Reset. - */ - if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { - /* - * If the BIOS Signature is present in memory, restore the - * BIOS Handshake Configuration Table and do not perform - * a SCSI Bus Reset. - */ - if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == - 0x55AA) { - /* - * Restore per TID negotiated values. - */ - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, - tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvWriteByteLram(iop_base, - ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - } else { - if (AdvResetSB(asc_dvc) != ADV_TRUE) { - warn_code = ASC_WARN_BUSRESET_ERROR; - } - } - } - - return warn_code; -} - -/* - * Initialize the ASC-38C0800. - * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - * - * Needed after initialization for error recovery. - */ -static int AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc) -{ - const struct firmware *fw; - const char fwname[] = "advansys/38C0800.bin"; - AdvPortAddr iop_base; - ushort warn_code; - int begin_addr; - int end_addr; - ushort code_sum; - int word; - int i; - int err; - unsigned long chksum; - ushort scsi_cfg1; - uchar byte; - uchar tid; - ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ - ushort wdtr_able, sdtr_able, tagqng_able; - uchar max_cmd[ADV_MAX_TID + 1]; - - /* If there is already an error, don't continue. */ - if (asc_dvc->err_code != 0) - return ADV_ERROR; - - /* - * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800. - */ - if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800) { - asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; - return ADV_ERROR; - } - - warn_code = 0; - iop_base = asc_dvc->iop_base; - - /* - * Save the RISC memory BIOS region before writing the microcode. - * The BIOS may already be loaded and using its RISC LRAM region - * so its region must be saved and restored. - * - * Note: This code makes the assumption, which is currently true, - * that a chip reset does not clear RISC LRAM. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Save current per TID negotiated values. - */ - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - - /* - * RAM BIST (RAM Built-In Self Test) - * - * Address : I/O base + offset 0x38h register (byte). - * Function: Bit 7-6(RW) : RAM mode - * Normal Mode : 0x00 - * Pre-test Mode : 0x40 - * RAM Test Mode : 0x80 - * Bit 5 : unused - * Bit 4(RO) : Done bit - * Bit 3-0(RO) : Status - * Host Error : 0x08 - * Int_RAM Error : 0x04 - * RISC Error : 0x02 - * SCSI Error : 0x01 - * No Error : 0x00 - * - * Note: RAM BIST code should be put right here, before loading the - * microcode and after saving the RISC memory BIOS region. - */ - - /* - * LRAM Pre-test - * - * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. - * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return - * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset - * to NORMAL_MODE, return an error too. - */ - for (i = 0; i < 2; i++) { - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); - mdelay(10); /* Wait for 10ms before reading back. */ - byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); - if ((byte & RAM_TEST_DONE) == 0 - || (byte & 0x0F) != PRE_TEST_VALUE) { - asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; - return ADV_ERROR; - } - - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - mdelay(10); /* Wait for 10ms before reading back. */ - if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) - != NORMAL_VALUE) { - asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; - return ADV_ERROR; - } - } - - /* - * LRAM Test - It takes about 1.5 ms to run through the test. - * - * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. - * If Done bit not set or Status not 0, save register byte, set the - * err_code, and return an error. - */ - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); - mdelay(10); /* Wait for 10ms before checking status. */ - - byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); - if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) { - /* Get here if Done bit not set or Status not 0. */ - asc_dvc->bist_err_code = byte; /* for BIOS display message */ - asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST; - return ADV_ERROR; - } - - /* We need to reset back to normal mode after LRAM test passes. */ - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - - err = request_firmware(&fw, fwname, asc_dvc->drv_ptr->dev); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fwname, err); - asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; - return err; - } - if (fw->size < 4) { - printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", - fw->size, fwname); - release_firmware(fw); - asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; - return -EINVAL; - } - chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | - (fw->data[1] << 8) | fw->data[0]; - asc_dvc->err_code = AdvLoadMicrocode(iop_base, &fw->data[4], - fw->size - 4, ADV_38C0800_MEMSIZE, - chksum); - release_firmware(fw); - if (asc_dvc->err_code) - return ADV_ERROR; - - /* - * Restore the RISC memory BIOS region. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Calculate and write the microcode code checksum to the microcode - * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). - */ - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); - AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); - code_sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); - for (word = begin_addr; word < end_addr; word += 2) { - code_sum += AdvReadWordAutoIncLram(iop_base); - } - AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - - /* - * Read microcode version and date. - */ - AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, - asc_dvc->cfg->mcode_date); - AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, - asc_dvc->cfg->mcode_version); - - /* - * Set the chip type to indicate the ASC38C0800. - */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800); - - /* - * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. - * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current - * cable detection and then we are able to read C_DET[3:0]. - * - * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 - * Microcode Default Value' section below. - */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, - scsi_cfg1 | DIS_TERM_DRV); - - /* - * If the PCI Configuration Command Register "Parity Error Response - * Control" Bit was clear (0), then set the microcode variable - * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode - * to ignore DMA parity errors. - */ - if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - word |= CONTROL_FLAG_IGNORE_PERR; - AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - } - - /* - * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2] - * bits for the default FIFO threshold. - * - * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes. - * - * For DMA Errata #4 set the BC_THRESH_ENB bit. - */ - AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | - READ_CMD_MRM); - - /* - * Microcode operating variables for WDTR, SDTR, and command tag - * queuing will be set in slave_configure() based on what a - * device reports it is capable of in Inquiry byte 7. - * - * If SCSI Bus Resets have been disabled, then directly set - * SDTR and WDTR from the EEPROM configuration. This will allow - * the BIOS and warm boot to work without a SCSI bus hang on - * the Inquiry caused by host and target mismatched DTR values. - * Without the SCSI Bus Reset, before an Inquiry a device can't - * be assumed to be in Asynchronous, Narrow mode. - */ - if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, - asc_dvc->wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, - asc_dvc->sdtr_able); - } - - /* - * Set microcode operating variables for DISC and SDTR_SPEED1, - * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM - * configuration values. - * - * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them - * without determining here whether the device supports SDTR. - */ - AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, - asc_dvc->cfg->disc_enable); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); - - /* - * Set SCSI_CFG0 Microcode Default Value. - * - * The microcode will set the SCSI_CFG0 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | - asc_dvc->chip_scsi_id); - - /* - * Determine SCSI_CFG1 Microcode Default Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - - /* Read current SCSI_CFG1 Register value. */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - - /* - * If the internal narrow cable is reversed all of the SCSI_CTRL - * register signals will be set. Check for and return an error if - * this condition is found. - */ - if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { - asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; - return ADV_ERROR; - } - - /* - * All kind of combinations of devices attached to one of four - * connectors are acceptable except HVD device attached. For example, - * LVD device can be attached to SE connector while SE device attached - * to LVD connector. If LVD device attached to SE connector, it only - * runs up to Ultra speed. - * - * If an HVD device is attached to one of LVD connectors, return an - * error. However, there is no way to detect HVD device attached to - * SE connectors. - */ - if (scsi_cfg1 & HVD) { - asc_dvc->err_code = ASC_IERR_HVD_DEVICE; - return ADV_ERROR; - } - - /* - * If either SE or LVD automatic termination control is enabled, then - * set the termination value based on a table listed in a_condor.h. - * - * If manual termination was specified with an EEPROM setting then - * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready - * to be 'ored' into SCSI_CFG1. - */ - if ((asc_dvc->cfg->termination & TERM_SE) == 0) { - /* SE automatic termination control is enabled. */ - switch (scsi_cfg1 & C_DET_SE) { - /* TERM_SE_HI: on, TERM_SE_LO: on */ - case 0x1: - case 0x2: - case 0x3: - asc_dvc->cfg->termination |= TERM_SE; - break; - - /* TERM_SE_HI: on, TERM_SE_LO: off */ - case 0x0: - asc_dvc->cfg->termination |= TERM_SE_HI; - break; - } - } - - if ((asc_dvc->cfg->termination & TERM_LVD) == 0) { - /* LVD automatic termination control is enabled. */ - switch (scsi_cfg1 & C_DET_LVD) { - /* TERM_LVD_HI: on, TERM_LVD_LO: on */ - case 0x4: - case 0x8: - case 0xC: - asc_dvc->cfg->termination |= TERM_LVD; - break; - - /* TERM_LVD_HI: off, TERM_LVD_LO: off */ - case 0x0: - break; - } - } - - /* - * Clear any set TERM_SE and TERM_LVD bits. - */ - scsi_cfg1 &= (~TERM_SE & ~TERM_LVD); - - /* - * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'. - */ - scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0); - - /* - * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE - * bits and set possibly modified termination control bits in the - * Microcode SCSI_CFG1 Register Value. - */ - scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE); - - /* - * Set SCSI_CFG1 Microcode Default Value - * - * Set possibly modified termination control and reset DIS_TERM_DRV - * bits in the Microcode SCSI_CFG1 Register Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); - - /* - * Set MEM_CFG Microcode Default Value - * - * The microcode will set the MEM_CFG register using this value - * after it is started below. - * - * MEM_CFG may be accessed as a word or byte, but only bits 0-7 - * are defined. - * - * ASC-38C0800 has 16KB internal memory. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_16KB); - - /* - * Set SEL_MASK Microcode Default Value - * - * The microcode will set the SEL_MASK register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, - ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); - - AdvBuildCarrierFreelist(asc_dvc); - - /* - * Set-up the Host->RISC Initiator Command Queue (ICQ). - */ - - if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); - - /* - * The first command issued will be placed in the stopper carrier. - */ - asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC ICQ physical address start value. - * carr_pa is LE, must be native before write - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); - - /* - * Set-up the RISC->Host Initiator Response Queue (IRQ). - */ - if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); - - /* - * The first command completed by the RISC will be placed in - * the stopper. - * - * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is - * completed the RISC will set the ASC_RQ_STOPPER bit. - */ - asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC IRQ physical address start value. - * - * carr_pa is LE, must be native before write * - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); - asc_dvc->carr_pending_cnt = 0; - - AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, - (ADV_INTR_ENABLE_HOST_INTR | - ADV_INTR_ENABLE_GLOBAL_INTR)); - - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); - AdvWriteWordRegister(iop_base, IOPW_PC, word); - - /* finally, finally, gentlemen, start your engine */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); - - /* - * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus - * Resets should be performed. The RISC has to be running - * to issue a SCSI Bus Reset. - */ - if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { - /* - * If the BIOS Signature is present in memory, restore the - * BIOS Handshake Configuration Table and do not perform - * a SCSI Bus Reset. - */ - if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == - 0x55AA) { - /* - * Restore per TID negotiated values. - */ - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, - tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvWriteByteLram(iop_base, - ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - } else { - if (AdvResetSB(asc_dvc) != ADV_TRUE) { - warn_code = ASC_WARN_BUSRESET_ERROR; - } - } - } - - return warn_code; -} - -/* - * Initialize the ASC-38C1600. - * - * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - * - * Needed after initialization for error recovery. - */ -static int AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc) -{ - const struct firmware *fw; - const char fwname[] = "advansys/38C1600.bin"; - AdvPortAddr iop_base; - ushort warn_code; - int begin_addr; - int end_addr; - ushort code_sum; - long word; - int i; - int err; - unsigned long chksum; - ushort scsi_cfg1; - uchar byte; - uchar tid; - ushort bios_mem[ASC_MC_BIOSLEN / 2]; /* BIOS RISC Memory 0x40-0x8F. */ - ushort wdtr_able, sdtr_able, ppr_able, tagqng_able; - uchar max_cmd[ASC_MAX_TID + 1]; - - /* If there is already an error, don't continue. */ - if (asc_dvc->err_code != 0) { - return ADV_ERROR; - } - - /* - * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600. - */ - if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { - asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE; - return ADV_ERROR; - } - - warn_code = 0; - iop_base = asc_dvc->iop_base; - - /* - * Save the RISC memory BIOS region before writing the microcode. - * The BIOS may already be loaded and using its RISC LRAM region - * so its region must be saved and restored. - * - * Note: This code makes the assumption, which is currently true, - * that a chip reset does not clear RISC LRAM. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Save current per TID negotiated values. - */ - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ASC_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - - /* - * RAM BIST (Built-In Self Test) - * - * Address : I/O base + offset 0x38h register (byte). - * Function: Bit 7-6(RW) : RAM mode - * Normal Mode : 0x00 - * Pre-test Mode : 0x40 - * RAM Test Mode : 0x80 - * Bit 5 : unused - * Bit 4(RO) : Done bit - * Bit 3-0(RO) : Status - * Host Error : 0x08 - * Int_RAM Error : 0x04 - * RISC Error : 0x02 - * SCSI Error : 0x01 - * No Error : 0x00 - * - * Note: RAM BIST code should be put right here, before loading the - * microcode and after saving the RISC memory BIOS region. - */ - - /* - * LRAM Pre-test - * - * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds. - * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return - * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset - * to NORMAL_MODE, return an error too. - */ - for (i = 0; i < 2; i++) { - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE); - mdelay(10); /* Wait for 10ms before reading back. */ - byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); - if ((byte & RAM_TEST_DONE) == 0 - || (byte & 0x0F) != PRE_TEST_VALUE) { - asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; - return ADV_ERROR; - } - - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - mdelay(10); /* Wait for 10ms before reading back. */ - if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST) - != NORMAL_VALUE) { - asc_dvc->err_code = ASC_IERR_BIST_PRE_TEST; - return ADV_ERROR; - } - } - - /* - * LRAM Test - It takes about 1.5 ms to run through the test. - * - * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds. - * If Done bit not set or Status not 0, save register byte, set the - * err_code, and return an error. - */ - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE); - mdelay(10); /* Wait for 10ms before checking status. */ - - byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST); - if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0) { - /* Get here if Done bit not set or Status not 0. */ - asc_dvc->bist_err_code = byte; /* for BIOS display message */ - asc_dvc->err_code = ASC_IERR_BIST_RAM_TEST; - return ADV_ERROR; - } - - /* We need to reset back to normal mode after LRAM test passes. */ - AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE); - - err = request_firmware(&fw, fwname, asc_dvc->drv_ptr->dev); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fwname, err); - asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; - return err; - } - if (fw->size < 4) { - printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", - fw->size, fwname); - release_firmware(fw); - asc_dvc->err_code = ASC_IERR_MCODE_CHKSUM; - return -EINVAL; - } - chksum = (fw->data[3] << 24) | (fw->data[2] << 16) | - (fw->data[1] << 8) | fw->data[0]; - asc_dvc->err_code = AdvLoadMicrocode(iop_base, &fw->data[4], - fw->size - 4, ADV_38C1600_MEMSIZE, - chksum); - release_firmware(fw); - if (asc_dvc->err_code) - return ADV_ERROR; - - /* - * Restore the RISC memory BIOS region. - */ - for (i = 0; i < ASC_MC_BIOSLEN / 2; i++) { - AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), - bios_mem[i]); - } - - /* - * Calculate and write the microcode code checksum to the microcode - * code checksum location ASC_MC_CODE_CHK_SUM (0x2C). - */ - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr); - AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr); - code_sum = 0; - AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr); - for (word = begin_addr; word < end_addr; word += 2) { - code_sum += AdvReadWordAutoIncLram(iop_base); - } - AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum); - - /* - * Read microcode version and date. - */ - AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, - asc_dvc->cfg->mcode_date); - AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, - asc_dvc->cfg->mcode_version); - - /* - * Set the chip type to indicate the ASC38C1600. - */ - AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600); - - /* - * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register. - * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current - * cable detection and then we are able to read C_DET[3:0]. - * - * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1 - * Microcode Default Value' section below. - */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, - scsi_cfg1 | DIS_TERM_DRV); - - /* - * If the PCI Configuration Command Register "Parity Error Response - * Control" Bit was clear (0), then set the microcode variable - * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode - * to ignore DMA parity errors. - */ - if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR) { - AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - word |= CONTROL_FLAG_IGNORE_PERR; - AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - } - - /* - * If the BIOS control flag AIPP (Asynchronous Information - * Phase Protection) disable bit is not set, then set the firmware - * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable - * AIPP checking and encoding. - */ - if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0) { - AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - word |= CONTROL_FLAG_ENABLE_AIPP; - AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word); - } - - /* - * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4], - * and START_CTL_TH [3:2]. - */ - AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0, - FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM); - - /* - * Microcode operating variables for WDTR, SDTR, and command tag - * queuing will be set in slave_configure() based on what a - * device reports it is capable of in Inquiry byte 7. - * - * If SCSI Bus Resets have been disabled, then directly set - * SDTR and WDTR from the EEPROM configuration. This will allow - * the BIOS and warm boot to work without a SCSI bus hang on - * the Inquiry caused by host and target mismatched DTR values. - * Without the SCSI Bus Reset, before an Inquiry a device can't - * be assumed to be in Asynchronous, Narrow mode. - */ - if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0) { - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, - asc_dvc->wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, - asc_dvc->sdtr_able); - } - - /* - * Set microcode operating variables for DISC and SDTR_SPEED1, - * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM - * configuration values. - * - * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2, - * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them - * without determining here whether the device supports SDTR. - */ - AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, - asc_dvc->cfg->disc_enable); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4); - - /* - * Set SCSI_CFG0 Microcode Default Value. - * - * The microcode will set the SCSI_CFG0 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0, - PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN | - asc_dvc->chip_scsi_id); - - /* - * Calculate SCSI_CFG1 Microcode Default Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - * - * Each ASC-38C1600 function has only two cable detect bits. - * The bus mode override bits are in IOPB_SOFT_OVER_WR. - */ - scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1); - - /* - * If the cable is reversed all of the SCSI_CTRL register signals - * will be set. Check for and return an error if this condition is - * found. - */ - if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07) { - asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE; - return ADV_ERROR; - } - - /* - * Each ASC-38C1600 function has two connectors. Only an HVD device - * can not be connected to either connector. An LVD device or SE device - * may be connected to either connecor. If an SE device is connected, - * then at most Ultra speed (20 Mhz) can be used on both connectors. - * - * If an HVD device is attached, return an error. - */ - if (scsi_cfg1 & HVD) { - asc_dvc->err_code |= ASC_IERR_HVD_DEVICE; - return ADV_ERROR; - } - - /* - * Each function in the ASC-38C1600 uses only the SE cable detect and - * termination because there are two connectors for each function. Each - * function may use either LVD or SE mode. Corresponding the SE automatic - * termination control EEPROM bits are used for each function. Each - * function has its own EEPROM. If SE automatic control is enabled for - * the function, then set the termination value based on a table listed - * in a_condor.h. - * - * If manual termination is specified in the EEPROM for the function, - * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is - * ready to be 'ored' into SCSI_CFG1. - */ - if ((asc_dvc->cfg->termination & TERM_SE) == 0) { - struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc); - /* SE automatic termination control is enabled. */ - switch (scsi_cfg1 & C_DET_SE) { - /* TERM_SE_HI: on, TERM_SE_LO: on */ - case 0x1: - case 0x2: - case 0x3: - asc_dvc->cfg->termination |= TERM_SE; - break; - - case 0x0: - if (PCI_FUNC(pdev->devfn) == 0) { - /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */ - } else { - /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */ - asc_dvc->cfg->termination |= TERM_SE_HI; - } - break; - } - } - - /* - * Clear any set TERM_SE bits. - */ - scsi_cfg1 &= ~TERM_SE; - - /* - * Invert the TERM_SE bits and then set 'scsi_cfg1'. - */ - scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE); - - /* - * Clear Big Endian and Terminator Polarity bits and set possibly - * modified termination control bits in the Microcode SCSI_CFG1 - * Register Value. - * - * Big Endian bit is not used even on big endian machines. - */ - scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL); - - /* - * Set SCSI_CFG1 Microcode Default Value - * - * Set possibly modified termination control bits in the Microcode - * SCSI_CFG1 Register Value. - * - * The microcode will set the SCSI_CFG1 register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1); - - /* - * Set MEM_CFG Microcode Default Value - * - * The microcode will set the MEM_CFG register using this value - * after it is started below. - * - * MEM_CFG may be accessed as a word or byte, but only bits 0-7 - * are defined. - * - * ASC-38C1600 has 32KB internal memory. - * - * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come - * out a special 16K Adv Library and Microcode version. After the issue - * resolved, we should turn back to the 32K support. Both a_condor.h and - * mcode.sas files also need to be updated. - * - * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - * BIOS_EN | RAM_SZ_32KB); - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, - BIOS_EN | RAM_SZ_16KB); - - /* - * Set SEL_MASK Microcode Default Value - * - * The microcode will set the SEL_MASK register using this value - * after it is started below. - */ - AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK, - ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id)); - - AdvBuildCarrierFreelist(asc_dvc); - - /* - * Set-up the Host->RISC Initiator Command Queue (ICQ). - */ - if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa)); - - /* - * The first command issued will be placed in the stopper carrier. - */ - asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC ICQ physical address start value. Initialize the - * COMMA register to the same value otherwise the RISC will - * prematurely detect a command is available. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa); - AdvWriteDWordRegister(iop_base, IOPDW_COMMA, - le32_to_cpu(asc_dvc->icq_sp->carr_pa)); - - /* - * Set-up the RISC->Host Initiator Response Queue (IRQ). - */ - if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL) { - asc_dvc->err_code |= ASC_IERR_NO_CARRIER; - return ADV_ERROR; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa)); - - /* - * The first command completed by the RISC will be placed in - * the stopper. - * - * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is - * completed the RISC will set the ASC_RQ_STOPPER bit. - */ - asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Set RISC IRQ physical address start value. - */ - AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa); - asc_dvc->carr_pending_cnt = 0; - - AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES, - (ADV_INTR_ENABLE_HOST_INTR | - ADV_INTR_ENABLE_GLOBAL_INTR)); - AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word); - AdvWriteWordRegister(iop_base, IOPW_PC, word); - - /* finally, finally, gentlemen, start your engine */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN); - - /* - * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus - * Resets should be performed. The RISC has to be running - * to issue a SCSI Bus Reset. - */ - if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) { - /* - * If the BIOS Signature is present in memory, restore the - * per TID microcode operating variables. - */ - if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM) / 2] == - 0x55AA) { - /* - * Restore per TID negotiated values. - */ - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, - tagqng_able); - for (tid = 0; tid <= ASC_MAX_TID; tid++) { - AdvWriteByteLram(iop_base, - ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - } else { - if (AdvResetSB(asc_dvc) != ADV_TRUE) { - warn_code = ASC_WARN_BUSRESET_ERROR; - } - } - } - - return warn_code; -} - -/* - * Reset chip and SCSI Bus. - * - * Return Value: - * ADV_TRUE(1) - Chip re-initialization and SCSI Bus Reset successful. - * ADV_FALSE(0) - Chip re-initialization and SCSI Bus Reset failure. - */ -static int AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc) -{ - int status; - ushort wdtr_able, sdtr_able, tagqng_able; - ushort ppr_able = 0; - uchar tid, max_cmd[ADV_MAX_TID + 1]; - AdvPortAddr iop_base; - ushort bios_sig; - - iop_base = asc_dvc->iop_base; - - /* - * Save current per TID negotiated values. - */ - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); - } - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - - /* - * Force the AdvInitAsc3550/38C0800Driver() function to - * perform a SCSI Bus Reset by clearing the BIOS signature word. - * The initialization functions assumes a SCSI Bus Reset is not - * needed if the BIOS signature word is present. - */ - AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig); - AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0); - - /* - * Stop chip and reset it. - */ - AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP); - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET); - mdelay(100); - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, - ADV_CTRL_REG_CMD_WR_IO_REG); - - /* - * Reset Adv Library error code, if any, and try - * re-initializing the chip. - */ - asc_dvc->err_code = 0; - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - status = AdvInitAsc38C1600Driver(asc_dvc); - } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - status = AdvInitAsc38C0800Driver(asc_dvc); - } else { - status = AdvInitAsc3550Driver(asc_dvc); - } - - /* Translate initialization return value to status value. */ - if (status == 0) { - status = ADV_TRUE; - } else { - status = ADV_FALSE; - } - - /* - * Restore the BIOS signature word. - */ - AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig); - - /* - * Restore per TID negotiated values. - */ - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able); - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able); - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able); - } - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able); - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid, - max_cmd[tid]); - } - - return status; -} - -/* - * adv_async_callback() - Adv Library asynchronous event callback function. - */ -static void adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code) -{ - switch (code) { - case ADV_ASYNC_SCSI_BUS_RESET_DET: - /* - * The firmware detected a SCSI Bus reset. - */ - ASC_DBG(0, "ADV_ASYNC_SCSI_BUS_RESET_DET\n"); - break; - - case ADV_ASYNC_RDMA_FAILURE: - /* - * Handle RDMA failure by resetting the SCSI Bus and - * possibly the chip if it is unresponsive. Log the error - * with a unique code. - */ - ASC_DBG(0, "ADV_ASYNC_RDMA_FAILURE\n"); - AdvResetChipAndSB(adv_dvc_varp); - break; - - case ADV_HOST_SCSI_BUS_RESET: - /* - * Host generated SCSI bus reset occurred. - */ - ASC_DBG(0, "ADV_HOST_SCSI_BUS_RESET\n"); - break; - - default: - ASC_DBG(0, "unknown code 0x%x\n", code); - break; - } -} - -/* - * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR(). - * - * Callback function for the Wide SCSI Adv Library. - */ -static void adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp) -{ - struct asc_board *boardp; - adv_req_t *reqp; - adv_sgblk_t *sgblkp; - struct scsi_cmnd *scp; - struct Scsi_Host *shost; - ADV_DCNT resid_cnt; - - ASC_DBG(1, "adv_dvc_varp 0x%lx, scsiqp 0x%lx\n", - (ulong)adv_dvc_varp, (ulong)scsiqp); - ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); - - /* - * Get the adv_req_t structure for the command that has been - * completed. The adv_req_t structure actually contains the - * completed ADV_SCSI_REQ_Q structure. - */ - reqp = (adv_req_t *)ADV_U32_TO_VADDR(scsiqp->srb_ptr); - ASC_DBG(1, "reqp 0x%lx\n", (ulong)reqp); - if (reqp == NULL) { - ASC_PRINT("adv_isr_callback: reqp is NULL\n"); - return; - } - - /* - * Get the struct scsi_cmnd structure and Scsi_Host structure for the - * command that has been completed. - * - * Note: The adv_req_t request structure and adv_sgblk_t structure, - * if any, are dropped, because a board structure pointer can not be - * determined. - */ - scp = reqp->cmndp; - ASC_DBG(1, "scp 0x%p\n", scp); - if (scp == NULL) { - ASC_PRINT - ("adv_isr_callback: scp is NULL; adv_req_t dropped.\n"); - return; - } - ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); - - shost = scp->device->host; - ASC_STATS(shost, callback); - ASC_DBG(1, "shost 0x%p\n", shost); - - boardp = shost_priv(shost); - BUG_ON(adv_dvc_varp != &boardp->dvc_var.adv_dvc_var); - - /* - * 'done_status' contains the command's ending status. - */ - switch (scsiqp->done_status) { - case QD_NO_ERROR: - ASC_DBG(2, "QD_NO_ERROR\n"); - scp->result = 0; - - /* - * Check for an underrun condition. - * - * If there was no error and an underrun condition, then - * then return the number of underrun bytes. - */ - resid_cnt = le32_to_cpu(scsiqp->data_cnt); - if (scsi_bufflen(scp) != 0 && resid_cnt != 0 && - resid_cnt <= scsi_bufflen(scp)) { - ASC_DBG(1, "underrun condition %lu bytes\n", - (ulong)resid_cnt); - scsi_set_resid(scp, resid_cnt); - } - break; - - case QD_WITH_ERROR: - ASC_DBG(2, "QD_WITH_ERROR\n"); - switch (scsiqp->host_status) { - case QHSTA_NO_ERROR: - if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) { - ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n"); - ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - SCSI_SENSE_BUFFERSIZE); - /* - * Note: The 'status_byte()' macro used by - * target drivers defined in scsi.h shifts the - * status byte returned by host drivers right - * by 1 bit. This is why target drivers also - * use right shifted status byte definitions. - * For instance target drivers use - * CHECK_CONDITION, defined to 0x1, instead of - * the SCSI defined check condition value of - * 0x2. Host drivers are supposed to return - * the status byte as it is defined by SCSI. - */ - scp->result = DRIVER_BYTE(DRIVER_SENSE) | - STATUS_BYTE(scsiqp->scsi_status); - } else { - scp->result = STATUS_BYTE(scsiqp->scsi_status); - } - break; - - default: - /* Some other QHSTA error occurred. */ - ASC_DBG(1, "host_status 0x%x\n", scsiqp->host_status); - scp->result = HOST_BYTE(DID_BAD_TARGET); - break; - } - break; - - case QD_ABORTED_BY_HOST: - ASC_DBG(1, "QD_ABORTED_BY_HOST\n"); - scp->result = - HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status); - break; - - default: - ASC_DBG(1, "done_status 0x%x\n", scsiqp->done_status); - scp->result = - HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status); - break; - } - - /* - * If the 'init_tidmask' bit isn't already set for the target and the - * current request finished normally, then set the bit for the target - * to indicate that a device is present. - */ - if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 && - scsiqp->done_status == QD_NO_ERROR && - scsiqp->host_status == QHSTA_NO_ERROR) { - boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id); - } - - asc_scsi_done(scp); - - /* - * Free all 'adv_sgblk_t' structures allocated for the request. - */ - while ((sgblkp = reqp->sgblkp) != NULL) { - /* Remove 'sgblkp' from the request list. */ - reqp->sgblkp = sgblkp->next_sgblkp; - - /* Add 'sgblkp' to the board free list. */ - sgblkp->next_sgblkp = boardp->adv_sgblkp; - boardp->adv_sgblkp = sgblkp; - } - - /* - * Free the adv_req_t structure used with the command by adding - * it back to the board free list. - */ - reqp->next_reqp = boardp->adv_reqp; - boardp->adv_reqp = reqp; - - ASC_DBG(1, "done\n"); -} - -/* - * Adv Library Interrupt Service Routine - * - * This function is called by a driver's interrupt service routine. - * The function disables and re-enables interrupts. - * - * When a microcode idle command is completed, the ADV_DVC_VAR - * 'idle_cmd_done' field is set to ADV_TRUE. - * - * Note: AdvISR() can be called when interrupts are disabled or even - * when there is no hardware interrupt condition present. It will - * always check for completed idle commands and microcode requests. - * This is an important feature that shouldn't be changed because it - * allows commands to be completed from polling mode loops. - * - * Return: - * ADV_TRUE(1) - interrupt was pending - * ADV_FALSE(0) - no interrupt was pending - */ -static int AdvISR(ADV_DVC_VAR *asc_dvc) -{ - AdvPortAddr iop_base; - uchar int_stat; - ushort target_bit; - ADV_CARR_T *free_carrp; - ADV_VADDR irq_next_vpa; - ADV_SCSI_REQ_Q *scsiq; - - iop_base = asc_dvc->iop_base; - - /* Reading the register clears the interrupt. */ - int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG); - - if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB | - ADV_INTR_STATUS_INTRC)) == 0) { - return ADV_FALSE; - } - - /* - * Notify the driver of an asynchronous microcode condition by - * calling the adv_async_callback function. The function - * is passed the microcode ASC_MC_INTRB_CODE byte value. - */ - if (int_stat & ADV_INTR_STATUS_INTRB) { - uchar intrb_code; - - AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code); - - if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || - asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE && - asc_dvc->carr_pending_cnt != 0) { - AdvWriteByteRegister(iop_base, IOPB_TICKLE, - ADV_TICKLE_A); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { - AdvWriteByteRegister(iop_base, - IOPB_TICKLE, - ADV_TICKLE_NOP); - } - } - } - - adv_async_callback(asc_dvc, intrb_code); - } - - /* - * Check if the IRQ stopper carrier contains a completed request. - */ - while (((irq_next_vpa = - le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0) { - /* - * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure. - * The RISC will have set 'areq_vpa' to a virtual address. - * - * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr - * field to the carrier ADV_CARR_T.areq_vpa field. The conversion - * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr' - * in AdvExeScsiQueue(). - */ - scsiq = (ADV_SCSI_REQ_Q *) - ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa)); - - /* - * Request finished with good status and the queue was not - * DMAed to host memory by the firmware. Set all status fields - * to indicate good status. - */ - if ((irq_next_vpa & ASC_RQ_GOOD) != 0) { - scsiq->done_status = QD_NO_ERROR; - scsiq->host_status = scsiq->scsi_status = 0; - scsiq->data_cnt = 0L; - } - - /* - * Advance the stopper pointer to the next carrier - * ignoring the lower four bits. Free the previous - * stopper carrier. - */ - free_carrp = asc_dvc->irq_sp; - asc_dvc->irq_sp = (ADV_CARR_T *) - ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa)); - - free_carrp->next_vpa = - cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist)); - asc_dvc->carr_freelist = free_carrp; - asc_dvc->carr_pending_cnt--; - - target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id); - - /* - * Clear request microcode control flag. - */ - scsiq->cntl = 0; - - /* - * Notify the driver of the completed request by passing - * the ADV_SCSI_REQ_Q pointer to its callback function. - */ - scsiq->a_flag |= ADV_SCSIQ_DONE; - adv_isr_callback(asc_dvc, scsiq); - /* - * Note: After the driver callback function is called, 'scsiq' - * can no longer be referenced. - * - * Fall through and continue processing other completed - * requests... - */ - } - return ADV_TRUE; -} - -static int AscSetLibErrorCode(ASC_DVC_VAR *asc_dvc, ushort err_code) -{ - if (asc_dvc->err_code == 0) { - asc_dvc->err_code = err_code; - AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W, - err_code); - } - return err_code; -} - -static void AscAckInterrupt(PortAddr iop_base) -{ - uchar host_flag; - uchar risc_flag; - ushort loop; - - loop = 0; - do { - risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B); - if (loop++ > 0x7FFF) { - break; - } - } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0); - host_flag = - AscReadLramByte(iop_base, - ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT); - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, - (uchar)(host_flag | ASC_HOST_FLAG_ACK_INT)); - AscSetChipStatus(iop_base, CIW_INT_ACK); - loop = 0; - while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) { - AscSetChipStatus(iop_base, CIW_INT_ACK); - if (loop++ > 3) { - break; - } - } - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); -} - -static uchar AscGetSynPeriodIndex(ASC_DVC_VAR *asc_dvc, uchar syn_time) -{ - const uchar *period_table; - int max_index; - int min_index; - int i; - - period_table = asc_dvc->sdtr_period_tbl; - max_index = (int)asc_dvc->max_sdtr_index; - min_index = (int)asc_dvc->min_sdtr_index; - if ((syn_time <= period_table[max_index])) { - for (i = min_index; i < (max_index - 1); i++) { - if (syn_time <= period_table[i]) { - return (uchar)i; - } - } - return (uchar)max_index; - } else { - return (uchar)(max_index + 1); - } -} - -static uchar -AscMsgOutSDTR(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar sdtr_offset) -{ - EXT_MSG sdtr_buf; - uchar sdtr_period_index; - PortAddr iop_base; - - iop_base = asc_dvc->iop_base; - sdtr_buf.msg_type = EXTENDED_MESSAGE; - sdtr_buf.msg_len = MS_SDTR_LEN; - sdtr_buf.msg_req = EXTENDED_SDTR; - sdtr_buf.xfer_period = sdtr_period; - sdtr_offset &= ASC_SYN_MAX_OFFSET; - sdtr_buf.req_ack_offset = sdtr_offset; - sdtr_period_index = AscGetSynPeriodIndex(asc_dvc, sdtr_period); - if (sdtr_period_index <= asc_dvc->max_sdtr_index) { - AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (uchar *)&sdtr_buf, - sizeof(EXT_MSG) >> 1); - return ((sdtr_period_index << 4) | sdtr_offset); - } else { - sdtr_buf.req_ack_offset = 0; - AscMemWordCopyPtrToLram(iop_base, ASCV_MSGOUT_BEG, - (uchar *)&sdtr_buf, - sizeof(EXT_MSG) >> 1); - return 0; - } -} - -static uchar -AscCalSDTRData(ASC_DVC_VAR *asc_dvc, uchar sdtr_period, uchar syn_offset) -{ - uchar byte; - uchar sdtr_period_ix; - - sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period); - if (sdtr_period_ix > asc_dvc->max_sdtr_index) - return 0xFF; - byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET); - return byte; -} - -static int AscSetChipSynRegAtID(PortAddr iop_base, uchar id, uchar sdtr_data) -{ - ASC_SCSI_BIT_ID_TYPE org_id; - int i; - int sta = TRUE; - - AscSetBank(iop_base, 1); - org_id = AscReadChipDvcID(iop_base); - for (i = 0; i <= ASC_MAX_TID; i++) { - if (org_id == (0x01 << i)) - break; - } - org_id = (ASC_SCSI_BIT_ID_TYPE) i; - AscWriteChipDvcID(iop_base, id); - if (AscReadChipDvcID(iop_base) == (0x01 << id)) { - AscSetBank(iop_base, 0); - AscSetChipSyn(iop_base, sdtr_data); - if (AscGetChipSyn(iop_base) != sdtr_data) { - sta = FALSE; - } - } else { - sta = FALSE; - } - AscSetBank(iop_base, 1); - AscWriteChipDvcID(iop_base, org_id); - AscSetBank(iop_base, 0); - return (sta); -} - -static void AscSetChipSDTR(PortAddr iop_base, uchar sdtr_data, uchar tid_no) -{ - AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data); -} - -static int AscIsrChipHalted(ASC_DVC_VAR *asc_dvc) -{ - EXT_MSG ext_msg; - EXT_MSG out_msg; - ushort halt_q_addr; - int sdtr_accept; - ushort int_halt_code; - ASC_SCSI_BIT_ID_TYPE scsi_busy; - ASC_SCSI_BIT_ID_TYPE target_id; - PortAddr iop_base; - uchar tag_code; - uchar q_status; - uchar halt_qp; - uchar sdtr_data; - uchar target_ix; - uchar q_cntl, tid_no; - uchar cur_dvc_qng; - uchar asyn_sdtr; - uchar scsi_status; - struct asc_board *boardp; - - BUG_ON(!asc_dvc->drv_ptr); - boardp = asc_dvc->drv_ptr; - - iop_base = asc_dvc->iop_base; - int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W); - - halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B); - halt_q_addr = ASC_QNO_TO_QADDR(halt_qp); - target_ix = AscReadLramByte(iop_base, - (ushort)(halt_q_addr + - (ushort)ASC_SCSIQ_B_TARGET_IX)); - q_cntl = AscReadLramByte(iop_base, - (ushort)(halt_q_addr + (ushort)ASC_SCSIQ_B_CNTL)); - tid_no = ASC_TIX_TO_TID(target_ix); - target_id = (uchar)ASC_TID_TO_TARGET_ID(tid_no); - if (asc_dvc->pci_fix_asyn_xfer & target_id) { - asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB; - } else { - asyn_sdtr = 0; - } - if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) { - if (asc_dvc->pci_fix_asyn_xfer & target_id) { - AscSetChipSDTR(iop_base, 0, tid_no); - boardp->sdtr_data[tid_no] = 0; - } - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) { - if (asc_dvc->pci_fix_asyn_xfer & target_id) { - AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - boardp->sdtr_data[tid_no] = asyn_sdtr; - } - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (int_halt_code == ASC_HALT_EXTMSG_IN) { - AscMemWordCopyPtrFromLram(iop_base, - ASCV_MSGIN_BEG, - (uchar *)&ext_msg, - sizeof(EXT_MSG) >> 1); - - if (ext_msg.msg_type == EXTENDED_MESSAGE && - ext_msg.msg_req == EXTENDED_SDTR && - ext_msg.msg_len == MS_SDTR_LEN) { - sdtr_accept = TRUE; - if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) { - - sdtr_accept = FALSE; - ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET; - } - if ((ext_msg.xfer_period < - asc_dvc->sdtr_period_tbl[asc_dvc->min_sdtr_index]) - || (ext_msg.xfer_period > - asc_dvc->sdtr_period_tbl[asc_dvc-> - max_sdtr_index])) { - sdtr_accept = FALSE; - ext_msg.xfer_period = - asc_dvc->sdtr_period_tbl[asc_dvc-> - min_sdtr_index]; - } - if (sdtr_accept) { - sdtr_data = - AscCalSDTRData(asc_dvc, ext_msg.xfer_period, - ext_msg.req_ack_offset); - if ((sdtr_data == 0xFF)) { - - q_cntl |= QC_MSG_OUT; - asc_dvc->init_sdtr &= ~target_id; - asc_dvc->sdtr_done &= ~target_id; - AscSetChipSDTR(iop_base, asyn_sdtr, - tid_no); - boardp->sdtr_data[tid_no] = asyn_sdtr; - } - } - if (ext_msg.req_ack_offset == 0) { - - q_cntl &= ~QC_MSG_OUT; - asc_dvc->init_sdtr &= ~target_id; - asc_dvc->sdtr_done &= ~target_id; - AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - } else { - if (sdtr_accept && (q_cntl & QC_MSG_OUT)) { - q_cntl &= ~QC_MSG_OUT; - asc_dvc->sdtr_done |= target_id; - asc_dvc->init_sdtr |= target_id; - asc_dvc->pci_fix_asyn_xfer &= - ~target_id; - sdtr_data = - AscCalSDTRData(asc_dvc, - ext_msg.xfer_period, - ext_msg. - req_ack_offset); - AscSetChipSDTR(iop_base, sdtr_data, - tid_no); - boardp->sdtr_data[tid_no] = sdtr_data; - } else { - q_cntl |= QC_MSG_OUT; - AscMsgOutSDTR(asc_dvc, - ext_msg.xfer_period, - ext_msg.req_ack_offset); - asc_dvc->pci_fix_asyn_xfer &= - ~target_id; - sdtr_data = - AscCalSDTRData(asc_dvc, - ext_msg.xfer_period, - ext_msg. - req_ack_offset); - AscSetChipSDTR(iop_base, sdtr_data, - tid_no); - boardp->sdtr_data[tid_no] = sdtr_data; - asc_dvc->sdtr_done |= target_id; - asc_dvc->init_sdtr |= target_id; - } - } - - AscWriteLramByte(iop_base, - (ushort)(halt_q_addr + - (ushort)ASC_SCSIQ_B_CNTL), - q_cntl); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (ext_msg.msg_type == EXTENDED_MESSAGE && - ext_msg.msg_req == EXTENDED_WDTR && - ext_msg.msg_len == MS_WDTR_LEN) { - - ext_msg.wdtr_width = 0; - AscMemWordCopyPtrToLram(iop_base, - ASCV_MSGOUT_BEG, - (uchar *)&ext_msg, - sizeof(EXT_MSG) >> 1); - q_cntl |= QC_MSG_OUT; - AscWriteLramByte(iop_base, - (ushort)(halt_q_addr + - (ushort)ASC_SCSIQ_B_CNTL), - q_cntl); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else { - - ext_msg.msg_type = MESSAGE_REJECT; - AscMemWordCopyPtrToLram(iop_base, - ASCV_MSGOUT_BEG, - (uchar *)&ext_msg, - sizeof(EXT_MSG) >> 1); - q_cntl |= QC_MSG_OUT; - AscWriteLramByte(iop_base, - (ushort)(halt_q_addr + - (ushort)ASC_SCSIQ_B_CNTL), - q_cntl); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } - } else if (int_halt_code == ASC_HALT_CHK_CONDITION) { - - q_cntl |= QC_REQ_SENSE; - - if ((asc_dvc->init_sdtr & target_id) != 0) { - - asc_dvc->sdtr_done &= ~target_id; - - sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); - q_cntl |= QC_MSG_OUT; - AscMsgOutSDTR(asc_dvc, - asc_dvc-> - sdtr_period_tbl[(sdtr_data >> 4) & - (uchar)(asc_dvc-> - max_sdtr_index - - 1)], - (uchar)(sdtr_data & (uchar) - ASC_SYN_MAX_OFFSET)); - } - - AscWriteLramByte(iop_base, - (ushort)(halt_q_addr + - (ushort)ASC_SCSIQ_B_CNTL), q_cntl); - - tag_code = AscReadLramByte(iop_base, - (ushort)(halt_q_addr + (ushort) - ASC_SCSIQ_B_TAG_CODE)); - tag_code &= 0xDC; - if ((asc_dvc->pci_fix_asyn_xfer & target_id) - && !(asc_dvc->pci_fix_asyn_xfer_always & target_id) - ) { - - tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT - | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX); - - } - AscWriteLramByte(iop_base, - (ushort)(halt_q_addr + - (ushort)ASC_SCSIQ_B_TAG_CODE), - tag_code); - - q_status = AscReadLramByte(iop_base, - (ushort)(halt_q_addr + (ushort) - ASC_SCSIQ_B_STATUS)); - q_status |= (QS_READY | QS_BUSY); - AscWriteLramByte(iop_base, - (ushort)(halt_q_addr + - (ushort)ASC_SCSIQ_B_STATUS), - q_status); - - scsi_busy = AscReadLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B); - scsi_busy &= ~target_id; - AscWriteLramByte(iop_base, (ushort)ASCV_SCSIBUSY_B, scsi_busy); - - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) { - - AscMemWordCopyPtrFromLram(iop_base, - ASCV_MSGOUT_BEG, - (uchar *)&out_msg, - sizeof(EXT_MSG) >> 1); - - if ((out_msg.msg_type == EXTENDED_MESSAGE) && - (out_msg.msg_len == MS_SDTR_LEN) && - (out_msg.msg_req == EXTENDED_SDTR)) { - - asc_dvc->init_sdtr &= ~target_id; - asc_dvc->sdtr_done &= ~target_id; - AscSetChipSDTR(iop_base, asyn_sdtr, tid_no); - boardp->sdtr_data[tid_no] = asyn_sdtr; - } - q_cntl &= ~QC_MSG_OUT; - AscWriteLramByte(iop_base, - (ushort)(halt_q_addr + - (ushort)ASC_SCSIQ_B_CNTL), q_cntl); - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) { - - scsi_status = AscReadLramByte(iop_base, - (ushort)((ushort)halt_q_addr + - (ushort) - ASC_SCSIQ_SCSI_STATUS)); - cur_dvc_qng = - AscReadLramByte(iop_base, - (ushort)((ushort)ASC_QADR_BEG + - (ushort)target_ix)); - if ((cur_dvc_qng > 0) && (asc_dvc->cur_dvc_qng[tid_no] > 0)) { - - scsi_busy = AscReadLramByte(iop_base, - (ushort)ASCV_SCSIBUSY_B); - scsi_busy |= target_id; - AscWriteLramByte(iop_base, - (ushort)ASCV_SCSIBUSY_B, scsi_busy); - asc_dvc->queue_full_or_busy |= target_id; - - if (scsi_status == SAM_STAT_TASK_SET_FULL) { - if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) { - cur_dvc_qng -= 1; - asc_dvc->max_dvc_qng[tid_no] = - cur_dvc_qng; - - AscWriteLramByte(iop_base, - (ushort)((ushort) - ASCV_MAX_DVC_QNG_BEG - + (ushort) - tid_no), - cur_dvc_qng); - - /* - * Set the device queue depth to the - * number of active requests when the - * QUEUE FULL condition was encountered. - */ - boardp->queue_full |= target_id; - boardp->queue_full_cnt[tid_no] = - cur_dvc_qng; - } - } - } - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } -#if CC_VERY_LONG_SG_LIST - else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC) { - uchar q_no; - ushort q_addr; - uchar sg_wk_q_no; - uchar first_sg_wk_q_no; - ASC_SCSI_Q *scsiq; /* Ptr to driver request. */ - ASC_SG_HEAD *sg_head; /* Ptr to driver SG request. */ - ASC_SG_LIST_Q scsi_sg_q; /* Structure written to queue. */ - ushort sg_list_dwords; - ushort sg_entry_cnt; - uchar next_qp; - int i; - - q_no = AscReadLramByte(iop_base, (ushort)ASCV_REQ_SG_LIST_QP); - if (q_no == ASC_QLINK_END) - return 0; - - q_addr = ASC_QNO_TO_QADDR(q_no); - - /* - * Convert the request's SRB pointer to a host ASC_SCSI_REQ - * structure pointer using a macro provided by the driver. - * The ASC_SCSI_REQ pointer provides a pointer to the - * host ASC_SG_HEAD structure. - */ - /* Read request's SRB pointer. */ - scsiq = (ASC_SCSI_Q *) - ASC_SRB2SCSIQ(ASC_U32_TO_VADDR(AscReadLramDWord(iop_base, - (ushort) - (q_addr + - ASC_SCSIQ_D_SRBPTR)))); - - /* - * Get request's first and working SG queue. - */ - sg_wk_q_no = AscReadLramByte(iop_base, - (ushort)(q_addr + - ASC_SCSIQ_B_SG_WK_QP)); - - first_sg_wk_q_no = AscReadLramByte(iop_base, - (ushort)(q_addr + - ASC_SCSIQ_B_FIRST_SG_WK_QP)); - - /* - * Reset request's working SG queue back to the - * first SG queue. - */ - AscWriteLramByte(iop_base, - (ushort)(q_addr + - (ushort)ASC_SCSIQ_B_SG_WK_QP), - first_sg_wk_q_no); - - sg_head = scsiq->sg_head; - - /* - * Set sg_entry_cnt to the number of SG elements - * that will be completed on this interrupt. - * - * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1 - * SG elements. The data_cnt and data_addr fields which - * add 1 to the SG element capacity are not used when - * restarting SG handling after a halt. - */ - if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1)) { - sg_entry_cnt = ASC_MAX_SG_LIST - 1; - - /* - * Keep track of remaining number of SG elements that - * will need to be handled on the next interrupt. - */ - scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1); - } else { - sg_entry_cnt = scsiq->remain_sg_entry_cnt; - scsiq->remain_sg_entry_cnt = 0; - } - - /* - * Copy SG elements into the list of allocated SG queues. - * - * Last index completed is saved in scsiq->next_sg_index. - */ - next_qp = first_sg_wk_q_no; - q_addr = ASC_QNO_TO_QADDR(next_qp); - scsi_sg_q.sg_head_qp = q_no; - scsi_sg_q.cntl = QCSG_SG_XFER_LIST; - for (i = 0; i < sg_head->queue_cnt; i++) { - scsi_sg_q.seq_no = i + 1; - if (sg_entry_cnt > ASC_SG_LIST_PER_Q) { - sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2); - sg_entry_cnt -= ASC_SG_LIST_PER_Q; - /* - * After very first SG queue RISC FW uses next - * SG queue first element then checks sg_list_cnt - * against zero and then decrements, so set - * sg_list_cnt 1 less than number of SG elements - * in each SG queue. - */ - scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1; - scsi_sg_q.sg_cur_list_cnt = - ASC_SG_LIST_PER_Q - 1; - } else { - /* - * This is the last SG queue in the list of - * allocated SG queues. If there are more - * SG elements than will fit in the allocated - * queues, then set the QCSG_SG_XFER_MORE flag. - */ - if (scsiq->remain_sg_entry_cnt != 0) { - scsi_sg_q.cntl |= QCSG_SG_XFER_MORE; - } else { - scsi_sg_q.cntl |= QCSG_SG_XFER_END; - } - /* equals sg_entry_cnt * 2 */ - sg_list_dwords = sg_entry_cnt << 1; - scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1; - scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1; - sg_entry_cnt = 0; - } - - scsi_sg_q.q_no = next_qp; - AscMemWordCopyPtrToLram(iop_base, - q_addr + ASC_SCSIQ_SGHD_CPY_BEG, - (uchar *)&scsi_sg_q, - sizeof(ASC_SG_LIST_Q) >> 1); - - AscMemDWordCopyPtrToLram(iop_base, - q_addr + ASC_SGQ_LIST_BEG, - (uchar *)&sg_head-> - sg_list[scsiq->next_sg_index], - sg_list_dwords); - - scsiq->next_sg_index += ASC_SG_LIST_PER_Q; - - /* - * If the just completed SG queue contained the - * last SG element, then no more SG queues need - * to be written. - */ - if (scsi_sg_q.cntl & QCSG_SG_XFER_END) { - break; - } - - next_qp = AscReadLramByte(iop_base, - (ushort)(q_addr + - ASC_SCSIQ_B_FWD)); - q_addr = ASC_QNO_TO_QADDR(next_qp); - } - - /* - * Clear the halt condition so the RISC will be restarted - * after the return. - */ - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0); - return (0); - } -#endif /* CC_VERY_LONG_SG_LIST */ - return (0); -} - -/* - * void - * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) - * - * Calling/Exit State: - * none - * - * Description: - * Input an ASC_QDONE_INFO structure from the chip - */ -static void -DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words) -{ - int i; - ushort word; - - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < 2 * words; i += 2) { - if (i == 10) { - continue; - } - word = inpw(iop_base + IOP_RAM_DATA); - inbuf[i] = word & 0xff; - inbuf[i + 1] = (word >> 8) & 0xff; - } - ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words); -} - -static uchar -_AscCopyLramScsiDoneQ(PortAddr iop_base, - ushort q_addr, - ASC_QDONE_INFO *scsiq, ASC_DCNT max_dma_count) -{ - ushort _val; - uchar sg_queue_cnt; - - DvcGetQinfo(iop_base, - q_addr + ASC_SCSIQ_DONE_INFO_BEG, - (uchar *)scsiq, - (sizeof(ASC_SCSIQ_2) + sizeof(ASC_SCSIQ_3)) / 2); - - _val = AscReadLramWord(iop_base, - (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS)); - scsiq->q_status = (uchar)_val; - scsiq->q_no = (uchar)(_val >> 8); - _val = AscReadLramWord(iop_base, - (ushort)(q_addr + (ushort)ASC_SCSIQ_B_CNTL)); - scsiq->cntl = (uchar)_val; - sg_queue_cnt = (uchar)(_val >> 8); - _val = AscReadLramWord(iop_base, - (ushort)(q_addr + - (ushort)ASC_SCSIQ_B_SENSE_LEN)); - scsiq->sense_len = (uchar)_val; - scsiq->extra_bytes = (uchar)(_val >> 8); - - /* - * Read high word of remain bytes from alternate location. - */ - scsiq->remain_bytes = (((ADV_DCNT)AscReadLramWord(iop_base, - (ushort)(q_addr + - (ushort) - ASC_SCSIQ_W_ALT_DC1))) - << 16); - /* - * Read low word of remain bytes from original location. - */ - scsiq->remain_bytes += AscReadLramWord(iop_base, - (ushort)(q_addr + (ushort) - ASC_SCSIQ_DW_REMAIN_XFER_CNT)); - - scsiq->remain_bytes &= max_dma_count; - return sg_queue_cnt; -} - -/* - * asc_isr_callback() - Second Level Interrupt Handler called by AscISR(). - * - * Interrupt callback function for the Narrow SCSI Asc Library. - */ -static void asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep) -{ - struct asc_board *boardp; - struct scsi_cmnd *scp; - struct Scsi_Host *shost; - - ASC_DBG(1, "asc_dvc_varp 0x%p, qdonep 0x%p\n", asc_dvc_varp, qdonep); - ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep); - - scp = advansys_srb_to_ptr(asc_dvc_varp, qdonep->d2.srb_ptr); - if (!scp) - return; - - ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len); - - shost = scp->device->host; - ASC_STATS(shost, callback); - ASC_DBG(1, "shost 0x%p\n", shost); - - boardp = shost_priv(shost); - BUG_ON(asc_dvc_varp != &boardp->dvc_var.asc_dvc_var); - - dma_unmap_single(boardp->dev, scp->SCp.dma_handle, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - /* - * 'qdonep' contains the command's ending status. - */ - switch (qdonep->d3.done_stat) { - case QD_NO_ERROR: - ASC_DBG(2, "QD_NO_ERROR\n"); - scp->result = 0; - - /* - * Check for an underrun condition. - * - * If there was no error and an underrun condition, then - * return the number of underrun bytes. - */ - if (scsi_bufflen(scp) != 0 && qdonep->remain_bytes != 0 && - qdonep->remain_bytes <= scsi_bufflen(scp)) { - ASC_DBG(1, "underrun condition %u bytes\n", - (unsigned)qdonep->remain_bytes); - scsi_set_resid(scp, qdonep->remain_bytes); - } - break; - - case QD_WITH_ERROR: - ASC_DBG(2, "QD_WITH_ERROR\n"); - switch (qdonep->d3.host_stat) { - case QHSTA_NO_ERROR: - if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) { - ASC_DBG(2, "SAM_STAT_CHECK_CONDITION\n"); - ASC_DBG_PRT_SENSE(2, scp->sense_buffer, - SCSI_SENSE_BUFFERSIZE); - /* - * Note: The 'status_byte()' macro used by - * target drivers defined in scsi.h shifts the - * status byte returned by host drivers right - * by 1 bit. This is why target drivers also - * use right shifted status byte definitions. - * For instance target drivers use - * CHECK_CONDITION, defined to 0x1, instead of - * the SCSI defined check condition value of - * 0x2. Host drivers are supposed to return - * the status byte as it is defined by SCSI. - */ - scp->result = DRIVER_BYTE(DRIVER_SENSE) | - STATUS_BYTE(qdonep->d3.scsi_stat); - } else { - scp->result = STATUS_BYTE(qdonep->d3.scsi_stat); - } - break; - - default: - /* QHSTA error occurred */ - ASC_DBG(1, "host_stat 0x%x\n", qdonep->d3.host_stat); - scp->result = HOST_BYTE(DID_BAD_TARGET); - break; - } - break; - - case QD_ABORTED_BY_HOST: - ASC_DBG(1, "QD_ABORTED_BY_HOST\n"); - scp->result = - HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3. - scsi_msg) | - STATUS_BYTE(qdonep->d3.scsi_stat); - break; - - default: - ASC_DBG(1, "done_stat 0x%x\n", qdonep->d3.done_stat); - scp->result = - HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3. - scsi_msg) | - STATUS_BYTE(qdonep->d3.scsi_stat); - break; - } - - /* - * If the 'init_tidmask' bit isn't already set for the target and the - * current request finished normally, then set the bit for the target - * to indicate that a device is present. - */ - if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 && - qdonep->d3.done_stat == QD_NO_ERROR && - qdonep->d3.host_stat == QHSTA_NO_ERROR) { - boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id); - } - - asc_scsi_done(scp); -} - -static int AscIsrQDone(ASC_DVC_VAR *asc_dvc) -{ - uchar next_qp; - uchar n_q_used; - uchar sg_list_qp; - uchar sg_queue_cnt; - uchar q_cnt; - uchar done_q_tail; - uchar tid_no; - ASC_SCSI_BIT_ID_TYPE scsi_busy; - ASC_SCSI_BIT_ID_TYPE target_id; - PortAddr iop_base; - ushort q_addr; - ushort sg_q_addr; - uchar cur_target_qng; - ASC_QDONE_INFO scsiq_buf; - ASC_QDONE_INFO *scsiq; - int false_overrun; - - iop_base = asc_dvc->iop_base; - n_q_used = 1; - scsiq = (ASC_QDONE_INFO *)&scsiq_buf; - done_q_tail = (uchar)AscGetVarDoneQTail(iop_base); - q_addr = ASC_QNO_TO_QADDR(done_q_tail); - next_qp = AscReadLramByte(iop_base, - (ushort)(q_addr + (ushort)ASC_SCSIQ_B_FWD)); - if (next_qp != ASC_QLINK_END) { - AscPutVarDoneQTail(iop_base, next_qp); - q_addr = ASC_QNO_TO_QADDR(next_qp); - sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq, - asc_dvc->max_dma_count); - AscWriteLramByte(iop_base, - (ushort)(q_addr + - (ushort)ASC_SCSIQ_B_STATUS), - (uchar)(scsiq-> - q_status & (uchar)~(QS_READY | - QS_ABORTED))); - tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix); - target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix); - if ((scsiq->cntl & QC_SG_HEAD) != 0) { - sg_q_addr = q_addr; - sg_list_qp = next_qp; - for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) { - sg_list_qp = AscReadLramByte(iop_base, - (ushort)(sg_q_addr - + (ushort) - ASC_SCSIQ_B_FWD)); - sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp); - if (sg_list_qp == ASC_QLINK_END) { - AscSetLibErrorCode(asc_dvc, - ASCQ_ERR_SG_Q_LINKS); - scsiq->d3.done_stat = QD_WITH_ERROR; - scsiq->d3.host_stat = - QHSTA_D_QDONE_SG_LIST_CORRUPTED; - goto FATAL_ERR_QDONE; - } - AscWriteLramByte(iop_base, - (ushort)(sg_q_addr + (ushort) - ASC_SCSIQ_B_STATUS), - QS_FREE); - } - n_q_used = sg_queue_cnt + 1; - AscPutVarDoneQTail(iop_base, sg_list_qp); - } - if (asc_dvc->queue_full_or_busy & target_id) { - cur_target_qng = AscReadLramByte(iop_base, - (ushort)((ushort) - ASC_QADR_BEG - + (ushort) - scsiq->d2. - target_ix)); - if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) { - scsi_busy = AscReadLramByte(iop_base, (ushort) - ASCV_SCSIBUSY_B); - scsi_busy &= ~target_id; - AscWriteLramByte(iop_base, - (ushort)ASCV_SCSIBUSY_B, - scsi_busy); - asc_dvc->queue_full_or_busy &= ~target_id; - } - } - if (asc_dvc->cur_total_qng >= n_q_used) { - asc_dvc->cur_total_qng -= n_q_used; - if (asc_dvc->cur_dvc_qng[tid_no] != 0) { - asc_dvc->cur_dvc_qng[tid_no]--; - } - } else { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG); - scsiq->d3.done_stat = QD_WITH_ERROR; - goto FATAL_ERR_QDONE; - } - if ((scsiq->d2.srb_ptr == 0UL) || - ((scsiq->q_status & QS_ABORTED) != 0)) { - return (0x11); - } else if (scsiq->q_status == QS_DONE) { - false_overrun = FALSE; - if (scsiq->extra_bytes != 0) { - scsiq->remain_bytes += - (ADV_DCNT)scsiq->extra_bytes; - } - if (scsiq->d3.done_stat == QD_WITH_ERROR) { - if (scsiq->d3.host_stat == - QHSTA_M_DATA_OVER_RUN) { - if ((scsiq-> - cntl & (QC_DATA_IN | QC_DATA_OUT)) - == 0) { - scsiq->d3.done_stat = - QD_NO_ERROR; - scsiq->d3.host_stat = - QHSTA_NO_ERROR; - } else if (false_overrun) { - scsiq->d3.done_stat = - QD_NO_ERROR; - scsiq->d3.host_stat = - QHSTA_NO_ERROR; - } - } else if (scsiq->d3.host_stat == - QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) { - AscStopChip(iop_base); - AscSetChipControl(iop_base, - (uchar)(CC_SCSI_RESET - | CC_HALT)); - udelay(60); - AscSetChipControl(iop_base, CC_HALT); - AscSetChipStatus(iop_base, - CIW_CLR_SCSI_RESET_INT); - AscSetChipStatus(iop_base, 0); - AscSetChipControl(iop_base, 0); - } - } - if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { - asc_isr_callback(asc_dvc, scsiq); - } else { - if ((AscReadLramByte(iop_base, - (ushort)(q_addr + (ushort) - ASC_SCSIQ_CDB_BEG)) - == START_STOP)) { - asc_dvc->unit_not_ready &= ~target_id; - if (scsiq->d3.done_stat != QD_NO_ERROR) { - asc_dvc->start_motor &= - ~target_id; - } - } - } - return (1); - } else { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS); - FATAL_ERR_QDONE: - if ((scsiq->cntl & QC_NO_CALLBACK) == 0) { - asc_isr_callback(asc_dvc, scsiq); - } - return (0x80); - } - } - return (0); -} - -static int AscISR(ASC_DVC_VAR *asc_dvc) -{ - ASC_CS_TYPE chipstat; - PortAddr iop_base; - ushort saved_ram_addr; - uchar ctrl_reg; - uchar saved_ctrl_reg; - int int_pending; - int status; - uchar host_flag; - - iop_base = asc_dvc->iop_base; - int_pending = FALSE; - - if (AscIsIntPending(iop_base) == 0) - return int_pending; - - if ((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0) { - return ERR; - } - if (asc_dvc->in_critical_cnt != 0) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL); - return ERR; - } - if (asc_dvc->is_in_int) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY); - return ERR; - } - asc_dvc->is_in_int = TRUE; - ctrl_reg = AscGetChipControl(iop_base); - saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET | - CC_SINGLE_STEP | CC_DIAG | CC_TEST)); - chipstat = AscGetChipStatus(iop_base); - if (chipstat & CSW_SCSI_RESET_LATCH) { - if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) { - int i = 10; - int_pending = TRUE; - asc_dvc->sdtr_done = 0; - saved_ctrl_reg &= (uchar)(~CC_HALT); - while ((AscGetChipStatus(iop_base) & - CSW_SCSI_RESET_ACTIVE) && (i-- > 0)) { - mdelay(100); - } - AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT)); - AscSetChipControl(iop_base, CC_HALT); - AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT); - AscSetChipStatus(iop_base, 0); - chipstat = AscGetChipStatus(iop_base); - } - } - saved_ram_addr = AscGetChipLramAddr(iop_base); - host_flag = AscReadLramByte(iop_base, - ASCV_HOST_FLAG_B) & - (uchar)(~ASC_HOST_FLAG_IN_ISR); - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, - (uchar)(host_flag | (uchar)ASC_HOST_FLAG_IN_ISR)); - if ((chipstat & CSW_INT_PENDING) || (int_pending)) { - AscAckInterrupt(iop_base); - int_pending = TRUE; - if ((chipstat & CSW_HALTED) && (ctrl_reg & CC_SINGLE_STEP)) { - if (AscIsrChipHalted(asc_dvc) == ERR) { - goto ISR_REPORT_QDONE_FATAL_ERROR; - } else { - saved_ctrl_reg &= (uchar)(~CC_HALT); - } - } else { - ISR_REPORT_QDONE_FATAL_ERROR: - if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) { - while (((status = - AscIsrQDone(asc_dvc)) & 0x01) != 0) { - } - } else { - do { - if ((status = - AscIsrQDone(asc_dvc)) == 1) { - break; - } - } while (status == 0x11); - } - if ((status & 0x80) != 0) - int_pending = ERR; - } - } - AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag); - AscSetChipLramAddr(iop_base, saved_ram_addr); - AscSetChipControl(iop_base, saved_ctrl_reg); - asc_dvc->is_in_int = FALSE; - return int_pending; -} - -/* - * advansys_reset() - * - * Reset the bus associated with the command 'scp'. - * - * This function runs its own thread. Interrupts must be blocked but - * sleeping is allowed and no locking other than for host structures is - * required. Returns SUCCESS or FAILED. - */ -static int advansys_reset(struct scsi_cmnd *scp) -{ - struct Scsi_Host *shost = scp->device->host; - struct asc_board *boardp = shost_priv(shost); - unsigned long flags; - int status; - int ret = SUCCESS; - - ASC_DBG(1, "0x%p\n", scp); - - ASC_STATS(shost, reset); - - scmd_printk(KERN_INFO, scp, "SCSI bus reset started...\n"); - - if (ASC_NARROW_BOARD(boardp)) { - ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var; - - /* Reset the chip and SCSI bus. */ - ASC_DBG(1, "before AscInitAsc1000Driver()\n"); - status = AscInitAsc1000Driver(asc_dvc); - - /* Refer to ASC_IERR_* definitions for meaning of 'err_code'. */ - if (asc_dvc->err_code || !asc_dvc->overrun_dma) { - scmd_printk(KERN_INFO, scp, "SCSI bus reset error: " - "0x%x, status: 0x%x\n", asc_dvc->err_code, - status); - ret = FAILED; - } else if (status) { - scmd_printk(KERN_INFO, scp, "SCSI bus reset warning: " - "0x%x\n", status); - } else { - scmd_printk(KERN_INFO, scp, "SCSI bus reset " - "successful\n"); - } - - ASC_DBG(1, "after AscInitAsc1000Driver()\n"); - spin_lock_irqsave(shost->host_lock, flags); - } else { - /* - * If the suggest reset bus flags are set, then reset the bus. - * Otherwise only reset the device. - */ - ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var; - - /* - * Reset the target's SCSI bus. - */ - ASC_DBG(1, "before AdvResetChipAndSB()\n"); - switch (AdvResetChipAndSB(adv_dvc)) { - case ASC_TRUE: - scmd_printk(KERN_INFO, scp, "SCSI bus reset " - "successful\n"); - break; - case ASC_FALSE: - default: - scmd_printk(KERN_INFO, scp, "SCSI bus reset error\n"); - ret = FAILED; - break; - } - spin_lock_irqsave(shost->host_lock, flags); - AdvISR(adv_dvc); - } - - /* Save the time of the most recently completed reset. */ - boardp->last_reset = jiffies; - spin_unlock_irqrestore(shost->host_lock, flags); - - ASC_DBG(1, "ret %d\n", ret); - - return ret; -} - -/* - * advansys_biosparam() - * - * Translate disk drive geometry if the "BIOS greater than 1 GB" - * support is enabled for a drive. - * - * ip (information pointer) is an int array with the following definition: - * ip[0]: heads - * ip[1]: sectors - * ip[2]: cylinders - */ -static int -advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int ip[]) -{ - struct asc_board *boardp = shost_priv(sdev->host); - - ASC_DBG(1, "begin\n"); - ASC_STATS(sdev->host, biosparam); - if (ASC_NARROW_BOARD(boardp)) { - if ((boardp->dvc_var.asc_dvc_var.dvc_cntl & - ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) { - ip[0] = 255; - ip[1] = 63; - } else { - ip[0] = 64; - ip[1] = 32; - } - } else { - if ((boardp->dvc_var.adv_dvc_var.bios_ctrl & - BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) { - ip[0] = 255; - ip[1] = 63; - } else { - ip[0] = 64; - ip[1] = 32; - } - } - ip[2] = (unsigned long)capacity / (ip[0] * ip[1]); - ASC_DBG(1, "end\n"); - return 0; -} - -/* - * First-level interrupt handler. - * - * 'dev_id' is a pointer to the interrupting adapter's Scsi_Host. - */ -static irqreturn_t advansys_interrupt(int irq, void *dev_id) -{ - struct Scsi_Host *shost = dev_id; - struct asc_board *boardp = shost_priv(shost); - irqreturn_t result = IRQ_NONE; - - ASC_DBG(2, "boardp 0x%p\n", boardp); - spin_lock(shost->host_lock); - if (ASC_NARROW_BOARD(boardp)) { - if (AscIsIntPending(shost->io_port)) { - result = IRQ_HANDLED; - ASC_STATS(shost, interrupt); - ASC_DBG(1, "before AscISR()\n"); - AscISR(&boardp->dvc_var.asc_dvc_var); - } - } else { - ASC_DBG(1, "before AdvISR()\n"); - if (AdvISR(&boardp->dvc_var.adv_dvc_var)) { - result = IRQ_HANDLED; - ASC_STATS(shost, interrupt); - } - } - spin_unlock(shost->host_lock); - - ASC_DBG(1, "end\n"); - return result; -} - -static int AscHostReqRiscHalt(PortAddr iop_base) -{ - int count = 0; - int sta = 0; - uchar saved_stop_code; - - if (AscIsChipHalted(iop_base)) - return (1); - saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP); - do { - if (AscIsChipHalted(iop_base)) { - sta = 1; - break; - } - mdelay(100); - } while (count++ < 20); - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code); - return (sta); -} - -static int -AscSetRunChipSynRegAtID(PortAddr iop_base, uchar tid_no, uchar sdtr_data) -{ - int sta = FALSE; - - if (AscHostReqRiscHalt(iop_base)) { - sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data); - AscStartChip(iop_base); - } - return sta; -} - -static void AscAsyncFix(ASC_DVC_VAR *asc_dvc, struct scsi_device *sdev) -{ - char type = sdev->type; - ASC_SCSI_BIT_ID_TYPE tid_bits = 1 << sdev->id; - - if (!(asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)) - return; - if (asc_dvc->init_sdtr & tid_bits) - return; - - if ((type == TYPE_ROM) && (strncmp(sdev->vendor, "HP ", 3) == 0)) - asc_dvc->pci_fix_asyn_xfer_always |= tid_bits; - - asc_dvc->pci_fix_asyn_xfer |= tid_bits; - if ((type == TYPE_PROCESSOR) || (type == TYPE_SCANNER) || - (type == TYPE_ROM) || (type == TYPE_TAPE)) - asc_dvc->pci_fix_asyn_xfer &= ~tid_bits; - - if (asc_dvc->pci_fix_asyn_xfer & tid_bits) - AscSetRunChipSynRegAtID(asc_dvc->iop_base, sdev->id, - ASYN_SDTR_DATA_FIX_PCI_REV_AB); -} - -static void -advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc) -{ - ASC_SCSI_BIT_ID_TYPE tid_bit = 1 << sdev->id; - ASC_SCSI_BIT_ID_TYPE orig_use_tagged_qng = asc_dvc->use_tagged_qng; - - if (sdev->lun == 0) { - ASC_SCSI_BIT_ID_TYPE orig_init_sdtr = asc_dvc->init_sdtr; - if ((asc_dvc->cfg->sdtr_enable & tid_bit) && sdev->sdtr) { - asc_dvc->init_sdtr |= tid_bit; - } else { - asc_dvc->init_sdtr &= ~tid_bit; - } - - if (orig_init_sdtr != asc_dvc->init_sdtr) - AscAsyncFix(asc_dvc, sdev); - } - - if (sdev->tagged_supported) { - if (asc_dvc->cfg->cmd_qng_enabled & tid_bit) { - if (sdev->lun == 0) { - asc_dvc->cfg->can_tagged_qng |= tid_bit; - asc_dvc->use_tagged_qng |= tid_bit; - } - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, - asc_dvc->max_dvc_qng[sdev->id]); - } - } else { - if (sdev->lun == 0) { - asc_dvc->cfg->can_tagged_qng &= ~tid_bit; - asc_dvc->use_tagged_qng &= ~tid_bit; - } - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); - } - - if ((sdev->lun == 0) && - (orig_use_tagged_qng != asc_dvc->use_tagged_qng)) { - AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B, - asc_dvc->cfg->disc_enable); - AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B, - asc_dvc->use_tagged_qng); - AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B, - asc_dvc->cfg->can_tagged_qng); - - asc_dvc->max_dvc_qng[sdev->id] = - asc_dvc->cfg->max_tag_qng[sdev->id]; - AscWriteLramByte(asc_dvc->iop_base, - (ushort)(ASCV_MAX_DVC_QNG_BEG + sdev->id), - asc_dvc->max_dvc_qng[sdev->id]); - } -} - -/* - * Wide Transfers - * - * If the EEPROM enabled WDTR for the device and the device supports wide - * bus (16 bit) transfers, then turn on the device's 'wdtr_able' bit and - * write the new value to the microcode. - */ -static void -advansys_wide_enable_wdtr(AdvPortAddr iop_base, unsigned short tidmask) -{ - unsigned short cfg_word; - AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); - if ((cfg_word & tidmask) != 0) - return; - - cfg_word |= tidmask; - AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word); - - /* - * Clear the microcode SDTR and WDTR negotiation done indicators for - * the target to cause it to negotiate with the new setting set above. - * WDTR when accepted causes the target to enter asynchronous mode, so - * SDTR must be negotiated. - */ - AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); - cfg_word &= ~tidmask; - AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); - AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); - cfg_word &= ~tidmask; - AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word); -} - -/* - * Synchronous Transfers - * - * If the EEPROM enabled SDTR for the device and the device - * supports synchronous transfers, then turn on the device's - * 'sdtr_able' bit. Write the new value to the microcode. - */ -static void -advansys_wide_enable_sdtr(AdvPortAddr iop_base, unsigned short tidmask) -{ - unsigned short cfg_word; - AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); - if ((cfg_word & tidmask) != 0) - return; - - cfg_word |= tidmask; - AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word); - - /* - * Clear the microcode "SDTR negotiation" done indicator for the - * target to cause it to negotiate with the new setting set above. - */ - AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); - cfg_word &= ~tidmask; - AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word); -} - -/* - * PPR (Parallel Protocol Request) Capable - * - * If the device supports DT mode, then it must be PPR capable. - * The PPR message will be used in place of the SDTR and WDTR - * messages to negotiate synchronous speed and offset, transfer - * width, and protocol options. - */ -static void advansys_wide_enable_ppr(ADV_DVC_VAR *adv_dvc, - AdvPortAddr iop_base, unsigned short tidmask) -{ - AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able); - adv_dvc->ppr_able |= tidmask; - AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, adv_dvc->ppr_able); -} - -static void -advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc) -{ - AdvPortAddr iop_base = adv_dvc->iop_base; - unsigned short tidmask = 1 << sdev->id; - - if (sdev->lun == 0) { - /* - * Handle WDTR, SDTR, and Tag Queuing. If the feature - * is enabled in the EEPROM and the device supports the - * feature, then enable it in the microcode. - */ - - if ((adv_dvc->wdtr_able & tidmask) && sdev->wdtr) - advansys_wide_enable_wdtr(iop_base, tidmask); - if ((adv_dvc->sdtr_able & tidmask) && sdev->sdtr) - advansys_wide_enable_sdtr(iop_base, tidmask); - if (adv_dvc->chip_type == ADV_CHIP_ASC38C1600 && sdev->ppr) - advansys_wide_enable_ppr(adv_dvc, iop_base, tidmask); - - /* - * Tag Queuing is disabled for the BIOS which runs in polled - * mode and would see no benefit from Tag Queuing. Also by - * disabling Tag Queuing in the BIOS devices with Tag Queuing - * bugs will at least work with the BIOS. - */ - if ((adv_dvc->tagqng_able & tidmask) && - sdev->tagged_supported) { - unsigned short cfg_word; - AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word); - cfg_word |= tidmask; - AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, - cfg_word); - AdvWriteByteLram(iop_base, - ASC_MC_NUMBER_OF_MAX_CMD + sdev->id, - adv_dvc->max_dvc_qng); - } - } - - if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) { - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, - adv_dvc->max_dvc_qng); - } else { - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); - } -} - -/* - * Set the number of commands to queue per device for the - * specified host adapter. - */ -static int advansys_slave_configure(struct scsi_device *sdev) -{ - struct asc_board *boardp = shost_priv(sdev->host); - - if (ASC_NARROW_BOARD(boardp)) - advansys_narrow_slave_configure(sdev, - &boardp->dvc_var.asc_dvc_var); - else - advansys_wide_slave_configure(sdev, - &boardp->dvc_var.adv_dvc_var); - - return 0; -} - -static __le32 advansys_get_sense_buffer_dma(struct scsi_cmnd *scp) -{ - struct asc_board *board = shost_priv(scp->device->host); - scp->SCp.dma_handle = dma_map_single(board->dev, scp->sense_buffer, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - dma_cache_sync(board->dev, scp->sense_buffer, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - return cpu_to_le32(scp->SCp.dma_handle); -} - -static int asc_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, - struct asc_scsi_q *asc_scsi_q) -{ - struct asc_dvc_var *asc_dvc = &boardp->dvc_var.asc_dvc_var; - int use_sg; - - memset(asc_scsi_q, 0, sizeof(*asc_scsi_q)); - - /* - * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'. - */ - asc_scsi_q->q2.srb_ptr = advansys_ptr_to_srb(asc_dvc, scp); - if (asc_scsi_q->q2.srb_ptr == BAD_SRB) { - scp->result = HOST_BYTE(DID_SOFT_ERROR); - return ASC_ERROR; - } - - /* - * Build the ASC_SCSI_Q request. - */ - asc_scsi_q->cdbptr = &scp->cmnd[0]; - asc_scsi_q->q2.cdb_len = scp->cmd_len; - asc_scsi_q->q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id); - asc_scsi_q->q1.target_lun = scp->device->lun; - asc_scsi_q->q2.target_ix = - ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun); - asc_scsi_q->q1.sense_addr = advansys_get_sense_buffer_dma(scp); - asc_scsi_q->q1.sense_len = SCSI_SENSE_BUFFERSIZE; - - /* - * If there are any outstanding requests for the current target, - * then every 255th request send an ORDERED request. This heuristic - * tries to retain the benefit of request sorting while preventing - * request starvation. 255 is the max number of tags or pending commands - * a device may have outstanding. - * - * The request count is incremented below for every successfully - * started request. - * - */ - if ((asc_dvc->cur_dvc_qng[scp->device->id] > 0) && - (boardp->reqcnt[scp->device->id] % 255) == 0) { - asc_scsi_q->q2.tag_code = MSG_ORDERED_TAG; - } else { - asc_scsi_q->q2.tag_code = MSG_SIMPLE_TAG; - } - - /* Build ASC_SCSI_Q */ - use_sg = scsi_dma_map(scp); - if (use_sg != 0) { - int sgcnt; - struct scatterlist *slp; - struct asc_sg_head *asc_sg_head; - - if (use_sg > scp->device->host->sg_tablesize) { - scmd_printk(KERN_ERR, scp, "use_sg %d > " - "sg_tablesize %d\n", use_sg, - scp->device->host->sg_tablesize); - scsi_dma_unmap(scp); - scp->result = HOST_BYTE(DID_ERROR); - return ASC_ERROR; - } - - asc_sg_head = kzalloc(sizeof(asc_scsi_q->sg_head) + - use_sg * sizeof(struct asc_sg_list), GFP_ATOMIC); - if (!asc_sg_head) { - scsi_dma_unmap(scp); - scp->result = HOST_BYTE(DID_SOFT_ERROR); - return ASC_ERROR; - } - - asc_scsi_q->q1.cntl |= QC_SG_HEAD; - asc_scsi_q->sg_head = asc_sg_head; - asc_scsi_q->q1.data_cnt = 0; - asc_scsi_q->q1.data_addr = 0; - /* This is a byte value, otherwise it would need to be swapped. */ - asc_sg_head->entry_cnt = asc_scsi_q->q1.sg_queue_cnt = use_sg; - ASC_STATS_ADD(scp->device->host, xfer_elem, - asc_sg_head->entry_cnt); - - /* - * Convert scatter-gather list into ASC_SG_HEAD list. - */ - scsi_for_each_sg(scp, slp, use_sg, sgcnt) { - asc_sg_head->sg_list[sgcnt].addr = - cpu_to_le32(sg_dma_address(slp)); - asc_sg_head->sg_list[sgcnt].bytes = - cpu_to_le32(sg_dma_len(slp)); - ASC_STATS_ADD(scp->device->host, xfer_sect, - DIV_ROUND_UP(sg_dma_len(slp), 512)); - } - } - - ASC_STATS(scp->device->host, xfer_cnt); - - ASC_DBG_PRT_ASC_SCSI_Q(2, asc_scsi_q); - ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); - - return ASC_NOERROR; -} - -/* - * Build scatter-gather list for Adv Library (Wide Board). - * - * Additional ADV_SG_BLOCK structures will need to be allocated - * if the total number of scatter-gather elements exceeds - * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are - * assumed to be physically contiguous. - * - * Return: - * ADV_SUCCESS(1) - SG List successfully created - * ADV_ERROR(-1) - SG List creation failed - */ -static int -adv_get_sglist(struct asc_board *boardp, adv_req_t *reqp, struct scsi_cmnd *scp, - int use_sg) -{ - adv_sgblk_t *sgblkp; - ADV_SCSI_REQ_Q *scsiqp; - struct scatterlist *slp; - int sg_elem_cnt; - ADV_SG_BLOCK *sg_block, *prev_sg_block; - ADV_PADDR sg_block_paddr; - int i; - - scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q); - slp = scsi_sglist(scp); - sg_elem_cnt = use_sg; - prev_sg_block = NULL; - reqp->sgblkp = NULL; - - for (;;) { - /* - * Allocate a 'adv_sgblk_t' structure from the board free - * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK - * (15) scatter-gather elements. - */ - if ((sgblkp = boardp->adv_sgblkp) == NULL) { - ASC_DBG(1, "no free adv_sgblk_t\n"); - ASC_STATS(scp->device->host, adv_build_nosg); - - /* - * Allocation failed. Free 'adv_sgblk_t' structures - * already allocated for the request. - */ - while ((sgblkp = reqp->sgblkp) != NULL) { - /* Remove 'sgblkp' from the request list. */ - reqp->sgblkp = sgblkp->next_sgblkp; - - /* Add 'sgblkp' to the board free list. */ - sgblkp->next_sgblkp = boardp->adv_sgblkp; - boardp->adv_sgblkp = sgblkp; - } - return ASC_BUSY; - } - - /* Complete 'adv_sgblk_t' board allocation. */ - boardp->adv_sgblkp = sgblkp->next_sgblkp; - sgblkp->next_sgblkp = NULL; - - /* - * Get 8 byte aligned virtual and physical addresses - * for the allocated ADV_SG_BLOCK structure. - */ - sg_block = (ADV_SG_BLOCK *)ADV_8BALIGN(&sgblkp->sg_block); - sg_block_paddr = virt_to_bus(sg_block); - - /* - * Check if this is the first 'adv_sgblk_t' for the - * request. - */ - if (reqp->sgblkp == NULL) { - /* Request's first scatter-gather block. */ - reqp->sgblkp = sgblkp; - - /* - * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical - * address pointers. - */ - scsiqp->sg_list_ptr = sg_block; - scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr); - } else { - /* Request's second or later scatter-gather block. */ - sgblkp->next_sgblkp = reqp->sgblkp; - reqp->sgblkp = sgblkp; - - /* - * Point the previous ADV_SG_BLOCK structure to - * the newly allocated ADV_SG_BLOCK structure. - */ - prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr); - } - - for (i = 0; i < NO_OF_SG_PER_BLOCK; i++) { - sg_block->sg_list[i].sg_addr = - cpu_to_le32(sg_dma_address(slp)); - sg_block->sg_list[i].sg_count = - cpu_to_le32(sg_dma_len(slp)); - ASC_STATS_ADD(scp->device->host, xfer_sect, - DIV_ROUND_UP(sg_dma_len(slp), 512)); - - if (--sg_elem_cnt == 0) { /* Last ADV_SG_BLOCK and scatter-gather entry. */ - sg_block->sg_cnt = i + 1; - sg_block->sg_ptr = 0L; /* Last ADV_SG_BLOCK in list. */ - return ADV_SUCCESS; - } - slp++; - } - sg_block->sg_cnt = NO_OF_SG_PER_BLOCK; - prev_sg_block = sg_block; - } -} - -/* - * Build a request structure for the Adv Library (Wide Board). - * - * If an adv_req_t can not be allocated to issue the request, - * then return ASC_BUSY. If an error occurs, then return ASC_ERROR. - * - * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the - * microcode for DMA addresses or math operations are byte swapped - * to little-endian order. - */ -static int -adv_build_req(struct asc_board *boardp, struct scsi_cmnd *scp, - ADV_SCSI_REQ_Q **adv_scsiqpp) -{ - adv_req_t *reqp; - ADV_SCSI_REQ_Q *scsiqp; - int i; - int ret; - int use_sg; - - /* - * Allocate an adv_req_t structure from the board to execute - * the command. - */ - if (boardp->adv_reqp == NULL) { - ASC_DBG(1, "no free adv_req_t\n"); - ASC_STATS(scp->device->host, adv_build_noreq); - return ASC_BUSY; - } else { - reqp = boardp->adv_reqp; - boardp->adv_reqp = reqp->next_reqp; - reqp->next_reqp = NULL; - } - - /* - * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers. - */ - scsiqp = (ADV_SCSI_REQ_Q *)ADV_32BALIGN(&reqp->scsi_req_q); - - /* - * Initialize the structure. - */ - scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0; - - /* - * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure. - */ - scsiqp->srb_ptr = ADV_VADDR_TO_U32(reqp); - - /* - * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure. - */ - reqp->cmndp = scp; - - /* - * Build the ADV_SCSI_REQ_Q request. - */ - - /* Set CDB length and copy it to the request structure. */ - scsiqp->cdb_len = scp->cmd_len; - /* Copy first 12 CDB bytes to cdb[]. */ - for (i = 0; i < scp->cmd_len && i < 12; i++) { - scsiqp->cdb[i] = scp->cmnd[i]; - } - /* Copy last 4 CDB bytes, if present, to cdb16[]. */ - for (; i < scp->cmd_len; i++) { - scsiqp->cdb16[i - 12] = scp->cmnd[i]; - } - - scsiqp->target_id = scp->device->id; - scsiqp->target_lun = scp->device->lun; - - scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0])); - scsiqp->sense_len = SCSI_SENSE_BUFFERSIZE; - - /* Build ADV_SCSI_REQ_Q */ - - use_sg = scsi_dma_map(scp); - if (use_sg == 0) { - /* Zero-length transfer */ - reqp->sgblkp = NULL; - scsiqp->data_cnt = 0; - scsiqp->vdata_addr = NULL; - - scsiqp->data_addr = 0; - scsiqp->sg_list_ptr = NULL; - scsiqp->sg_real_addr = 0; - } else { - if (use_sg > ADV_MAX_SG_LIST) { - scmd_printk(KERN_ERR, scp, "use_sg %d > " - "ADV_MAX_SG_LIST %d\n", use_sg, - scp->device->host->sg_tablesize); - scsi_dma_unmap(scp); - scp->result = HOST_BYTE(DID_ERROR); - - /* - * Free the 'adv_req_t' structure by adding it back - * to the board free list. - */ - reqp->next_reqp = boardp->adv_reqp; - boardp->adv_reqp = reqp; - - return ASC_ERROR; - } - - scsiqp->data_cnt = cpu_to_le32(scsi_bufflen(scp)); - - ret = adv_get_sglist(boardp, reqp, scp, use_sg); - if (ret != ADV_SUCCESS) { - /* - * Free the adv_req_t structure by adding it back to - * the board free list. - */ - reqp->next_reqp = boardp->adv_reqp; - boardp->adv_reqp = reqp; - - return ret; - } - - ASC_STATS_ADD(scp->device->host, xfer_elem, use_sg); - } - - ASC_STATS(scp->device->host, xfer_cnt); - - ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp); - ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len); - - *adv_scsiqpp = scsiqp; - - return ASC_NOERROR; -} - -static int AscSgListToQueue(int sg_list) -{ - int n_sg_list_qs; - - n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q); - if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0) - n_sg_list_qs++; - return n_sg_list_qs + 1; -} - -static uint -AscGetNumOfFreeQueue(ASC_DVC_VAR *asc_dvc, uchar target_ix, uchar n_qs) -{ - uint cur_used_qs; - uint cur_free_qs; - ASC_SCSI_BIT_ID_TYPE target_id; - uchar tid_no; - - target_id = ASC_TIX_TO_TARGET_ID(target_ix); - tid_no = ASC_TIX_TO_TID(target_ix); - if ((asc_dvc->unit_not_ready & target_id) || - (asc_dvc->queue_full_or_busy & target_id)) { - return 0; - } - if (n_qs == 1) { - cur_used_qs = (uint) asc_dvc->cur_total_qng + - (uint) asc_dvc->last_q_shortage + (uint) ASC_MIN_FREE_Q; - } else { - cur_used_qs = (uint) asc_dvc->cur_total_qng + - (uint) ASC_MIN_FREE_Q; - } - if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) { - cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs; - if (asc_dvc->cur_dvc_qng[tid_no] >= - asc_dvc->max_dvc_qng[tid_no]) { - return 0; - } - return cur_free_qs; - } - if (n_qs > 1) { - if ((n_qs > asc_dvc->last_q_shortage) - && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) { - asc_dvc->last_q_shortage = n_qs; - } - } - return 0; -} - -static uchar AscAllocFreeQueue(PortAddr iop_base, uchar free_q_head) -{ - ushort q_addr; - uchar next_qp; - uchar q_status; - - q_addr = ASC_QNO_TO_QADDR(free_q_head); - q_status = (uchar)AscReadLramByte(iop_base, - (ushort)(q_addr + - ASC_SCSIQ_B_STATUS)); - next_qp = AscReadLramByte(iop_base, (ushort)(q_addr + ASC_SCSIQ_B_FWD)); - if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) - return next_qp; - return ASC_QLINK_END; -} - -static uchar -AscAllocMultipleFreeQueue(PortAddr iop_base, uchar free_q_head, uchar n_free_q) -{ - uchar i; - - for (i = 0; i < n_free_q; i++) { - free_q_head = AscAllocFreeQueue(iop_base, free_q_head); - if (free_q_head == ASC_QLINK_END) - break; - } - return free_q_head; -} - -/* - * void - * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) - * - * Calling/Exit State: - * none - * - * Description: - * Output an ASC_SCSI_Q structure to the chip - */ -static void -DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words) -{ - int i; - - ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words); - AscSetChipLramAddr(iop_base, s_addr); - for (i = 0; i < 2 * words; i += 2) { - if (i == 4 || i == 20) { - continue; - } - outpw(iop_base + IOP_RAM_DATA, - ((ushort)outbuf[i + 1] << 8) | outbuf[i]); - } -} - -static int AscPutReadyQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no) -{ - ushort q_addr; - uchar tid_no; - uchar sdtr_data; - uchar syn_period_ix; - uchar syn_offset; - PortAddr iop_base; - - iop_base = asc_dvc->iop_base; - if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) && - ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) { - tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix); - sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); - syn_period_ix = - (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1); - syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET; - AscMsgOutSDTR(asc_dvc, - asc_dvc->sdtr_period_tbl[syn_period_ix], - syn_offset); - scsiq->q1.cntl |= QC_MSG_OUT; - } - q_addr = ASC_QNO_TO_QADDR(q_no); - if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) { - scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG; - } - scsiq->q1.status = QS_FREE; - AscMemWordCopyPtrToLram(iop_base, - q_addr + ASC_SCSIQ_CDB_BEG, - (uchar *)scsiq->cdbptr, scsiq->q2.cdb_len >> 1); - - DvcPutScsiQ(iop_base, - q_addr + ASC_SCSIQ_CPY_BEG, - (uchar *)&scsiq->q1.cntl, - ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1); - AscWriteLramWord(iop_base, - (ushort)(q_addr + (ushort)ASC_SCSIQ_B_STATUS), - (ushort)(((ushort)scsiq->q1. - q_no << 8) | (ushort)QS_READY)); - return 1; -} - -static int -AscPutReadySgListQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar q_no) -{ - int sta; - int i; - ASC_SG_HEAD *sg_head; - ASC_SG_LIST_Q scsi_sg_q; - ASC_DCNT saved_data_addr; - ASC_DCNT saved_data_cnt; - PortAddr iop_base; - ushort sg_list_dwords; - ushort sg_index; - ushort sg_entry_cnt; - ushort q_addr; - uchar next_qp; - - iop_base = asc_dvc->iop_base; - sg_head = scsiq->sg_head; - saved_data_addr = scsiq->q1.data_addr; - saved_data_cnt = scsiq->q1.data_cnt; - scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr; - scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes; -#if CC_VERY_LONG_SG_LIST - /* - * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST - * then not all SG elements will fit in the allocated queues. - * The rest of the SG elements will be copied when the RISC - * completes the SG elements that fit and halts. - */ - if (sg_head->entry_cnt > ASC_MAX_SG_LIST) { - /* - * Set sg_entry_cnt to be the number of SG elements that - * will fit in the allocated SG queues. It is minus 1, because - * the first SG element is handled above. ASC_MAX_SG_LIST is - * already inflated by 1 to account for this. For example it - * may be 50 which is 1 + 7 queues * 7 SG elements. - */ - sg_entry_cnt = ASC_MAX_SG_LIST - 1; - - /* - * Keep track of remaining number of SG elements that will - * need to be handled from a_isr.c. - */ - scsiq->remain_sg_entry_cnt = - sg_head->entry_cnt - ASC_MAX_SG_LIST; - } else { -#endif /* CC_VERY_LONG_SG_LIST */ - /* - * Set sg_entry_cnt to be the number of SG elements that - * will fit in the allocated SG queues. It is minus 1, because - * the first SG element is handled above. - */ - sg_entry_cnt = sg_head->entry_cnt - 1; -#if CC_VERY_LONG_SG_LIST - } -#endif /* CC_VERY_LONG_SG_LIST */ - if (sg_entry_cnt != 0) { - scsiq->q1.cntl |= QC_SG_HEAD; - q_addr = ASC_QNO_TO_QADDR(q_no); - sg_index = 1; - scsiq->q1.sg_queue_cnt = sg_head->queue_cnt; - scsi_sg_q.sg_head_qp = q_no; - scsi_sg_q.cntl = QCSG_SG_XFER_LIST; - for (i = 0; i < sg_head->queue_cnt; i++) { - scsi_sg_q.seq_no = i + 1; - if (sg_entry_cnt > ASC_SG_LIST_PER_Q) { - sg_list_dwords = (uchar)(ASC_SG_LIST_PER_Q * 2); - sg_entry_cnt -= ASC_SG_LIST_PER_Q; - if (i == 0) { - scsi_sg_q.sg_list_cnt = - ASC_SG_LIST_PER_Q; - scsi_sg_q.sg_cur_list_cnt = - ASC_SG_LIST_PER_Q; - } else { - scsi_sg_q.sg_list_cnt = - ASC_SG_LIST_PER_Q - 1; - scsi_sg_q.sg_cur_list_cnt = - ASC_SG_LIST_PER_Q - 1; - } - } else { -#if CC_VERY_LONG_SG_LIST - /* - * This is the last SG queue in the list of - * allocated SG queues. If there are more - * SG elements than will fit in the allocated - * queues, then set the QCSG_SG_XFER_MORE flag. - */ - if (sg_head->entry_cnt > ASC_MAX_SG_LIST) { - scsi_sg_q.cntl |= QCSG_SG_XFER_MORE; - } else { -#endif /* CC_VERY_LONG_SG_LIST */ - scsi_sg_q.cntl |= QCSG_SG_XFER_END; -#if CC_VERY_LONG_SG_LIST - } -#endif /* CC_VERY_LONG_SG_LIST */ - sg_list_dwords = sg_entry_cnt << 1; - if (i == 0) { - scsi_sg_q.sg_list_cnt = sg_entry_cnt; - scsi_sg_q.sg_cur_list_cnt = - sg_entry_cnt; - } else { - scsi_sg_q.sg_list_cnt = - sg_entry_cnt - 1; - scsi_sg_q.sg_cur_list_cnt = - sg_entry_cnt - 1; - } - sg_entry_cnt = 0; - } - next_qp = AscReadLramByte(iop_base, - (ushort)(q_addr + - ASC_SCSIQ_B_FWD)); - scsi_sg_q.q_no = next_qp; - q_addr = ASC_QNO_TO_QADDR(next_qp); - AscMemWordCopyPtrToLram(iop_base, - q_addr + ASC_SCSIQ_SGHD_CPY_BEG, - (uchar *)&scsi_sg_q, - sizeof(ASC_SG_LIST_Q) >> 1); - AscMemDWordCopyPtrToLram(iop_base, - q_addr + ASC_SGQ_LIST_BEG, - (uchar *)&sg_head-> - sg_list[sg_index], - sg_list_dwords); - sg_index += ASC_SG_LIST_PER_Q; - scsiq->next_sg_index = sg_index; - } - } else { - scsiq->q1.cntl &= ~QC_SG_HEAD; - } - sta = AscPutReadyQueue(asc_dvc, scsiq, q_no); - scsiq->q1.data_addr = saved_data_addr; - scsiq->q1.data_cnt = saved_data_cnt; - return (sta); -} - -static int -AscSendScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq, uchar n_q_required) -{ - PortAddr iop_base; - uchar free_q_head; - uchar next_qp; - uchar tid_no; - uchar target_ix; - int sta; - - iop_base = asc_dvc->iop_base; - target_ix = scsiq->q2.target_ix; - tid_no = ASC_TIX_TO_TID(target_ix); - sta = 0; - free_q_head = (uchar)AscGetVarFreeQHead(iop_base); - if (n_q_required > 1) { - next_qp = AscAllocMultipleFreeQueue(iop_base, free_q_head, - (uchar)n_q_required); - if (next_qp != ASC_QLINK_END) { - asc_dvc->last_q_shortage = 0; - scsiq->sg_head->queue_cnt = n_q_required - 1; - scsiq->q1.q_no = free_q_head; - sta = AscPutReadySgListQueue(asc_dvc, scsiq, - free_q_head); - } - } else if (n_q_required == 1) { - next_qp = AscAllocFreeQueue(iop_base, free_q_head); - if (next_qp != ASC_QLINK_END) { - scsiq->q1.q_no = free_q_head; - sta = AscPutReadyQueue(asc_dvc, scsiq, free_q_head); - } - } - if (sta == 1) { - AscPutVarFreeQHead(iop_base, next_qp); - asc_dvc->cur_total_qng += n_q_required; - asc_dvc->cur_dvc_qng[tid_no]++; - } - return sta; -} - -#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16 -static uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] = { - INQUIRY, - REQUEST_SENSE, - READ_CAPACITY, - READ_TOC, - MODE_SELECT, - MODE_SENSE, - MODE_SELECT_10, - MODE_SENSE_10, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF, - 0xFF -}; - -static int AscExeScsiQueue(ASC_DVC_VAR *asc_dvc, ASC_SCSI_Q *scsiq) -{ - PortAddr iop_base; - int sta; - int n_q_required; - int disable_syn_offset_one_fix; - int i; - ASC_PADDR addr; - ushort sg_entry_cnt = 0; - ushort sg_entry_cnt_minus_one = 0; - uchar target_ix; - uchar tid_no; - uchar sdtr_data; - uchar extra_bytes; - uchar scsi_cmd; - uchar disable_cmd; - ASC_SG_HEAD *sg_head; - ASC_DCNT data_cnt; - - iop_base = asc_dvc->iop_base; - sg_head = scsiq->sg_head; - if (asc_dvc->err_code != 0) - return (ERR); - scsiq->q1.q_no = 0; - if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) { - scsiq->q1.extra_bytes = 0; - } - sta = 0; - target_ix = scsiq->q2.target_ix; - tid_no = ASC_TIX_TO_TID(target_ix); - n_q_required = 1; - if (scsiq->cdbptr[0] == REQUEST_SENSE) { - if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) { - asc_dvc->sdtr_done &= ~scsiq->q1.target_id; - sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no); - AscMsgOutSDTR(asc_dvc, - asc_dvc-> - sdtr_period_tbl[(sdtr_data >> 4) & - (uchar)(asc_dvc-> - max_sdtr_index - - 1)], - (uchar)(sdtr_data & (uchar) - ASC_SYN_MAX_OFFSET)); - scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT); - } - } - if (asc_dvc->in_critical_cnt != 0) { - AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY); - return (ERR); - } - asc_dvc->in_critical_cnt++; - if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { - if ((sg_entry_cnt = sg_head->entry_cnt) == 0) { - asc_dvc->in_critical_cnt--; - return (ERR); - } -#if !CC_VERY_LONG_SG_LIST - if (sg_entry_cnt > ASC_MAX_SG_LIST) { - asc_dvc->in_critical_cnt--; - return (ERR); - } -#endif /* !CC_VERY_LONG_SG_LIST */ - if (sg_entry_cnt == 1) { - scsiq->q1.data_addr = - (ADV_PADDR)sg_head->sg_list[0].addr; - scsiq->q1.data_cnt = - (ADV_DCNT)sg_head->sg_list[0].bytes; - scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE); - } - sg_entry_cnt_minus_one = sg_entry_cnt - 1; - } - scsi_cmd = scsiq->cdbptr[0]; - disable_syn_offset_one_fix = FALSE; - if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) && - !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) { - if (scsiq->q1.cntl & QC_SG_HEAD) { - data_cnt = 0; - for (i = 0; i < sg_entry_cnt; i++) { - data_cnt += - (ADV_DCNT)le32_to_cpu(sg_head->sg_list[i]. - bytes); - } - } else { - data_cnt = le32_to_cpu(scsiq->q1.data_cnt); - } - if (data_cnt != 0UL) { - if (data_cnt < 512UL) { - disable_syn_offset_one_fix = TRUE; - } else { - for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; - i++) { - disable_cmd = - _syn_offset_one_disable_cmd[i]; - if (disable_cmd == 0xFF) { - break; - } - if (scsi_cmd == disable_cmd) { - disable_syn_offset_one_fix = - TRUE; - break; - } - } - } - } - } - if (disable_syn_offset_one_fix) { - scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG; - scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX | - ASC_TAG_FLAG_DISABLE_DISCONNECT); - } else { - scsiq->q2.tag_code &= 0x27; - } - if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) { - if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { - if ((scsi_cmd == READ_6) || - (scsi_cmd == READ_10)) { - addr = - (ADV_PADDR)le32_to_cpu(sg_head-> - sg_list - [sg_entry_cnt_minus_one]. - addr) + - (ADV_DCNT)le32_to_cpu(sg_head-> - sg_list - [sg_entry_cnt_minus_one]. - bytes); - extra_bytes = - (uchar)((ushort)addr & 0x0003); - if ((extra_bytes != 0) - && - ((scsiq->q2. - tag_code & - ASC_TAG_FLAG_EXTRA_BYTES) - == 0)) { - scsiq->q2.tag_code |= - ASC_TAG_FLAG_EXTRA_BYTES; - scsiq->q1.extra_bytes = - extra_bytes; - data_cnt = - le32_to_cpu(sg_head-> - sg_list - [sg_entry_cnt_minus_one]. - bytes); - data_cnt -= - (ASC_DCNT) extra_bytes; - sg_head-> - sg_list - [sg_entry_cnt_minus_one]. - bytes = - cpu_to_le32(data_cnt); - } - } - } - } - sg_head->entry_to_copy = sg_head->entry_cnt; -#if CC_VERY_LONG_SG_LIST - /* - * Set the sg_entry_cnt to the maximum possible. The rest of - * the SG elements will be copied when the RISC completes the - * SG elements that fit and halts. - */ - if (sg_entry_cnt > ASC_MAX_SG_LIST) { - sg_entry_cnt = ASC_MAX_SG_LIST; - } -#endif /* CC_VERY_LONG_SG_LIST */ - n_q_required = AscSgListToQueue(sg_entry_cnt); - if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >= - (uint) n_q_required) - || ((scsiq->q1.cntl & QC_URGENT) != 0)) { - if ((sta = - AscSendScsiQueue(asc_dvc, scsiq, - n_q_required)) == 1) { - asc_dvc->in_critical_cnt--; - return (sta); - } - } - } else { - if (asc_dvc->bug_fix_cntl) { - if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) { - if ((scsi_cmd == READ_6) || - (scsi_cmd == READ_10)) { - addr = - le32_to_cpu(scsiq->q1.data_addr) + - le32_to_cpu(scsiq->q1.data_cnt); - extra_bytes = - (uchar)((ushort)addr & 0x0003); - if ((extra_bytes != 0) - && - ((scsiq->q2. - tag_code & - ASC_TAG_FLAG_EXTRA_BYTES) - == 0)) { - data_cnt = - le32_to_cpu(scsiq->q1. - data_cnt); - if (((ushort)data_cnt & 0x01FF) - == 0) { - scsiq->q2.tag_code |= - ASC_TAG_FLAG_EXTRA_BYTES; - data_cnt -= (ASC_DCNT) - extra_bytes; - scsiq->q1.data_cnt = - cpu_to_le32 - (data_cnt); - scsiq->q1.extra_bytes = - extra_bytes; - } - } - } - } - } - n_q_required = 1; - if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) || - ((scsiq->q1.cntl & QC_URGENT) != 0)) { - if ((sta = AscSendScsiQueue(asc_dvc, scsiq, - n_q_required)) == 1) { - asc_dvc->in_critical_cnt--; - return (sta); - } - } - } - asc_dvc->in_critical_cnt--; - return (sta); -} - -/* - * AdvExeScsiQueue() - Send a request to the RISC microcode program. - * - * Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q, - * add the carrier to the ICQ (Initiator Command Queue), and tickle the - * RISC to notify it a new command is ready to be executed. - * - * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be - * set to SCSI_MAX_RETRY. - * - * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode - * for DMA addresses or math operations are byte swapped to little-endian - * order. - * - * Return: - * ADV_SUCCESS(1) - The request was successfully queued. - * ADV_BUSY(0) - Resource unavailable; Retry again after pending - * request completes. - * ADV_ERROR(-1) - Invalid ADV_SCSI_REQ_Q request structure - * host IC error. - */ -static int AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq) -{ - AdvPortAddr iop_base; - ADV_PADDR req_paddr; - ADV_CARR_T *new_carrp; - - /* - * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID. - */ - if (scsiq->target_id > ADV_MAX_TID) { - scsiq->host_status = QHSTA_M_INVALID_DEVICE; - scsiq->done_status = QD_WITH_ERROR; - return ADV_ERROR; - } - - iop_base = asc_dvc->iop_base; - - /* - * Allocate a carrier ensuring at least one carrier always - * remains on the freelist and initialize fields. - */ - if ((new_carrp = asc_dvc->carr_freelist) == NULL) { - return ADV_BUSY; - } - asc_dvc->carr_freelist = (ADV_CARR_T *) - ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa)); - asc_dvc->carr_pending_cnt++; - - /* - * Set the carrier to be a stopper by setting 'next_vpa' - * to the stopper value. The current stopper will be changed - * below to point to the new stopper. - */ - new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER); - - /* - * Clear the ADV_SCSI_REQ_Q done flag. - */ - scsiq->a_flag &= ~ADV_SCSIQ_DONE; - - req_paddr = virt_to_bus(scsiq); - BUG_ON(req_paddr & 31); - /* Wait for assertion before making little-endian */ - req_paddr = cpu_to_le32(req_paddr); - - /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */ - scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq)); - scsiq->scsiq_rptr = req_paddr; - - scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp)); - /* - * Every ADV_CARR_T.carr_pa is byte swapped to little-endian - * order during initialization. - */ - scsiq->carr_pa = asc_dvc->icq_sp->carr_pa; - - /* - * Use the current stopper to send the ADV_SCSI_REQ_Q command to - * the microcode. The newly allocated stopper will become the new - * stopper. - */ - asc_dvc->icq_sp->areq_vpa = req_paddr; - - /* - * Set the 'next_vpa' pointer for the old stopper to be the - * physical address of the new stopper. The RISC can only - * follow physical addresses. - */ - asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa; - - /* - * Set the host adapter stopper pointer to point to the new carrier. - */ - asc_dvc->icq_sp = new_carrp; - - if (asc_dvc->chip_type == ADV_CHIP_ASC3550 || - asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - /* - * Tickle the RISC to tell it to read its Command Queue Head pointer. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A); - if (asc_dvc->chip_type == ADV_CHIP_ASC3550) { - /* - * Clear the tickle value. In the ASC-3550 the RISC flag - * command 'clr_tickle_a' does not work unless the host - * value is cleared. - */ - AdvWriteByteRegister(iop_base, IOPB_TICKLE, - ADV_TICKLE_NOP); - } - } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - /* - * Notify the RISC a carrier is ready by writing the physical - * address of the new carrier stopper to the COMMA register. - */ - AdvWriteDWordRegister(iop_base, IOPDW_COMMA, - le32_to_cpu(new_carrp->carr_pa)); - } - - return ADV_SUCCESS; -} - -/* - * Execute a single 'Scsi_Cmnd'. - */ -static int asc_execute_scsi_cmnd(struct scsi_cmnd *scp) -{ - int ret, err_code; - struct asc_board *boardp = shost_priv(scp->device->host); - - ASC_DBG(1, "scp 0x%p\n", scp); - - if (ASC_NARROW_BOARD(boardp)) { - ASC_DVC_VAR *asc_dvc = &boardp->dvc_var.asc_dvc_var; - struct asc_scsi_q asc_scsi_q; - - /* asc_build_req() can not return ASC_BUSY. */ - ret = asc_build_req(boardp, scp, &asc_scsi_q); - if (ret == ASC_ERROR) { - ASC_STATS(scp->device->host, build_error); - return ASC_ERROR; - } - - ret = AscExeScsiQueue(asc_dvc, &asc_scsi_q); - kfree(asc_scsi_q.sg_head); - err_code = asc_dvc->err_code; - } else { - ADV_DVC_VAR *adv_dvc = &boardp->dvc_var.adv_dvc_var; - ADV_SCSI_REQ_Q *adv_scsiqp; - - switch (adv_build_req(boardp, scp, &adv_scsiqp)) { - case ASC_NOERROR: - ASC_DBG(3, "adv_build_req ASC_NOERROR\n"); - break; - case ASC_BUSY: - ASC_DBG(1, "adv_build_req ASC_BUSY\n"); - /* - * The asc_stats fields 'adv_build_noreq' and - * 'adv_build_nosg' count wide board busy conditions. - * They are updated in adv_build_req and - * adv_get_sglist, respectively. - */ - return ASC_BUSY; - case ASC_ERROR: - default: - ASC_DBG(1, "adv_build_req ASC_ERROR\n"); - ASC_STATS(scp->device->host, build_error); - return ASC_ERROR; - } - - ret = AdvExeScsiQueue(adv_dvc, adv_scsiqp); - err_code = adv_dvc->err_code; - } - - switch (ret) { - case ASC_NOERROR: - ASC_STATS(scp->device->host, exe_noerror); - /* - * Increment monotonically increasing per device - * successful request counter. Wrapping doesn't matter. - */ - boardp->reqcnt[scp->device->id]++; - ASC_DBG(1, "ExeScsiQueue() ASC_NOERROR\n"); - break; - case ASC_BUSY: - ASC_STATS(scp->device->host, exe_busy); - break; - case ASC_ERROR: - scmd_printk(KERN_ERR, scp, "ExeScsiQueue() ASC_ERROR, " - "err_code 0x%x\n", err_code); - ASC_STATS(scp->device->host, exe_error); - scp->result = HOST_BYTE(DID_ERROR); - break; - default: - scmd_printk(KERN_ERR, scp, "ExeScsiQueue() unknown, " - "err_code 0x%x\n", err_code); - ASC_STATS(scp->device->host, exe_unknown); - scp->result = HOST_BYTE(DID_ERROR); - break; - } - - ASC_DBG(1, "end\n"); - return ret; -} - -/* - * advansys_queuecommand() - interrupt-driven I/O entrypoint. - * - * This function always returns 0. Command return status is saved - * in the 'scp' result field. - */ -static int -advansys_queuecommand_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *)) -{ - struct Scsi_Host *shost = scp->device->host; - int asc_res, result = 0; - - ASC_STATS(shost, queuecommand); - scp->scsi_done = done; - - asc_res = asc_execute_scsi_cmnd(scp); - - switch (asc_res) { - case ASC_NOERROR: - break; - case ASC_BUSY: - result = SCSI_MLQUEUE_HOST_BUSY; - break; - case ASC_ERROR: - default: - asc_scsi_done(scp); - break; - } - - return result; -} - -static DEF_SCSI_QCMD(advansys_queuecommand) - -static ushort __devinit AscGetEisaChipCfg(PortAddr iop_base) -{ - PortAddr eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | - (PortAddr) (ASC_EISA_CFG_IOP_MASK); - return inpw(eisa_cfg_iop); -} - -/* - * Return the BIOS address of the adapter at the specified - * I/O port and with the specified bus type. - */ -static unsigned short __devinit -AscGetChipBiosAddress(PortAddr iop_base, unsigned short bus_type) -{ - unsigned short cfg_lsw; - unsigned short bios_addr; - - /* - * The PCI BIOS is re-located by the motherboard BIOS. Because - * of this the driver can not determine where a PCI BIOS is - * loaded and executes. - */ - if (bus_type & ASC_IS_PCI) - return 0; - - if ((bus_type & ASC_IS_EISA) != 0) { - cfg_lsw = AscGetEisaChipCfg(iop_base); - cfg_lsw &= 0x000F; - bios_addr = ASC_BIOS_MIN_ADDR + cfg_lsw * ASC_BIOS_BANK_SIZE; - return bios_addr; - } - - cfg_lsw = AscGetChipCfgLsw(iop_base); - - /* - * ISA PnP uses the top bit as the 32K BIOS flag - */ - if (bus_type == ASC_IS_ISAPNP) - cfg_lsw &= 0x7FFF; - bios_addr = ASC_BIOS_MIN_ADDR + (cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE; - return bios_addr; -} - -static uchar __devinit AscSetChipScsiID(PortAddr iop_base, uchar new_host_id) -{ - ushort cfg_lsw; - - if (AscGetChipScsiID(iop_base) == new_host_id) { - return (new_host_id); - } - cfg_lsw = AscGetChipCfgLsw(iop_base); - cfg_lsw &= 0xF8FF; - cfg_lsw |= (ushort)((new_host_id & ASC_MAX_TID) << 8); - AscSetChipCfgLsw(iop_base, cfg_lsw); - return (AscGetChipScsiID(iop_base)); -} - -static unsigned char __devinit AscGetChipScsiCtrl(PortAddr iop_base) -{ - unsigned char sc; - - AscSetBank(iop_base, 1); - sc = inp(iop_base + IOP_REG_SC); - AscSetBank(iop_base, 0); - return sc; -} - -static unsigned char __devinit -AscGetChipVersion(PortAddr iop_base, unsigned short bus_type) -{ - if (bus_type & ASC_IS_EISA) { - PortAddr eisa_iop; - unsigned char revision; - eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) | - (PortAddr) ASC_EISA_REV_IOP_MASK; - revision = inp(eisa_iop); - return ASC_CHIP_MIN_VER_EISA - 1 + revision; - } - return AscGetChipVerNo(iop_base); -} - -#ifdef CONFIG_ISA -static void __devinit AscEnableIsaDma(uchar dma_channel) -{ - if (dma_channel < 4) { - outp(0x000B, (ushort)(0xC0 | dma_channel)); - outp(0x000A, dma_channel); - } else if (dma_channel < 8) { - outp(0x00D6, (ushort)(0xC0 | (dma_channel - 4))); - outp(0x00D4, (ushort)(dma_channel - 4)); - } -} -#endif /* CONFIG_ISA */ - -static int AscStopQueueExe(PortAddr iop_base) -{ - int count = 0; - - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) { - AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, - ASC_STOP_REQ_RISC_STOP); - do { - if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) & - ASC_STOP_ACK_RISC_STOP) { - return (1); - } - mdelay(100); - } while (count++ < 20); - } - return (0); -} - -static ASC_DCNT __devinit AscGetMaxDmaCount(ushort bus_type) -{ - if (bus_type & ASC_IS_ISA) - return ASC_MAX_ISA_DMA_COUNT; - else if (bus_type & (ASC_IS_EISA | ASC_IS_VL)) - return ASC_MAX_VL_DMA_COUNT; - return ASC_MAX_PCI_DMA_COUNT; -} - -#ifdef CONFIG_ISA -static ushort __devinit AscGetIsaDmaChannel(PortAddr iop_base) -{ - ushort channel; - - channel = AscGetChipCfgLsw(iop_base) & 0x0003; - if (channel == 0x03) - return (0); - else if (channel == 0x00) - return (7); - return (channel + 4); -} - -static ushort __devinit AscSetIsaDmaChannel(PortAddr iop_base, ushort dma_channel) -{ - ushort cfg_lsw; - uchar value; - - if ((dma_channel >= 5) && (dma_channel <= 7)) { - if (dma_channel == 7) - value = 0x00; - else - value = dma_channel - 4; - cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC; - cfg_lsw |= value; - AscSetChipCfgLsw(iop_base, cfg_lsw); - return (AscGetIsaDmaChannel(iop_base)); - } - return 0; -} - -static uchar __devinit AscGetIsaDmaSpeed(PortAddr iop_base) -{ - uchar speed_value; - - AscSetBank(iop_base, 1); - speed_value = AscReadChipDmaSpeed(iop_base); - speed_value &= 0x07; - AscSetBank(iop_base, 0); - return speed_value; -} - -static uchar __devinit AscSetIsaDmaSpeed(PortAddr iop_base, uchar speed_value) -{ - speed_value &= 0x07; - AscSetBank(iop_base, 1); - AscWriteChipDmaSpeed(iop_base, speed_value); - AscSetBank(iop_base, 0); - return AscGetIsaDmaSpeed(iop_base); -} -#endif /* CONFIG_ISA */ - -static ushort __devinit AscInitAscDvcVar(ASC_DVC_VAR *asc_dvc) -{ - int i; - PortAddr iop_base; - ushort warn_code; - uchar chip_version; - - iop_base = asc_dvc->iop_base; - warn_code = 0; - asc_dvc->err_code = 0; - if ((asc_dvc->bus_type & - (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) { - asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE; - } - AscSetChipControl(iop_base, CC_HALT); - AscSetChipStatus(iop_base, 0); - asc_dvc->bug_fix_cntl = 0; - asc_dvc->pci_fix_asyn_xfer = 0; - asc_dvc->pci_fix_asyn_xfer_always = 0; - /* asc_dvc->init_state initialized in AscInitGetConfig(). */ - asc_dvc->sdtr_done = 0; - asc_dvc->cur_total_qng = 0; - asc_dvc->is_in_int = 0; - asc_dvc->in_critical_cnt = 0; - asc_dvc->last_q_shortage = 0; - asc_dvc->use_tagged_qng = 0; - asc_dvc->no_scam = 0; - asc_dvc->unit_not_ready = 0; - asc_dvc->queue_full_or_busy = 0; - asc_dvc->redo_scam = 0; - asc_dvc->res2 = 0; - asc_dvc->min_sdtr_index = 0; - asc_dvc->cfg->can_tagged_qng = 0; - asc_dvc->cfg->cmd_qng_enabled = 0; - asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL; - asc_dvc->init_sdtr = 0; - asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG; - asc_dvc->scsi_reset_wait = 3; - asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type); - asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET; - asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID; - chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type); - asc_dvc->cfg->chip_version = chip_version; - asc_dvc->sdtr_period_tbl = asc_syn_xfer_period; - asc_dvc->max_sdtr_index = 7; - if ((asc_dvc->bus_type & ASC_IS_PCI) && - (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) { - asc_dvc->bus_type = ASC_IS_PCI_ULTRA; - asc_dvc->sdtr_period_tbl = asc_syn_ultra_xfer_period; - asc_dvc->max_sdtr_index = 15; - if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150) { - AscSetExtraControl(iop_base, - (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE)); - } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) { - AscSetExtraControl(iop_base, - (SEC_ACTIVE_NEGATE | - SEC_ENABLE_FILTER)); - } - } - if (asc_dvc->bus_type == ASC_IS_PCI) { - AscSetExtraControl(iop_base, - (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE)); - } - - asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED; -#ifdef CONFIG_ISA - if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) { - if (chip_version >= ASC_CHIP_MIN_VER_ISA_PNP) { - AscSetChipIFC(iop_base, IFC_INIT_DEFAULT); - asc_dvc->bus_type = ASC_IS_ISAPNP; - } - asc_dvc->cfg->isa_dma_channel = - (uchar)AscGetIsaDmaChannel(iop_base); - } -#endif /* CONFIG_ISA */ - for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->cur_dvc_qng[i] = 0; - asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG; - asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *)0L; - asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *)0L; - asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG; - } - return warn_code; -} - -static int __devinit AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg) -{ - int retry; - - for (retry = 0; retry < ASC_EEP_MAX_RETRY; retry++) { - unsigned char read_back; - AscSetChipEEPCmd(iop_base, cmd_reg); - mdelay(1); - read_back = AscGetChipEEPCmd(iop_base); - if (read_back == cmd_reg) - return 1; - } - return 0; -} - -static void __devinit AscWaitEEPRead(void) -{ - mdelay(1); -} - -static ushort __devinit AscReadEEPWord(PortAddr iop_base, uchar addr) -{ - ushort read_wval; - uchar cmd_reg; - - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); - AscWaitEEPRead(); - cmd_reg = addr | ASC_EEP_CMD_READ; - AscWriteEEPCmdReg(iop_base, cmd_reg); - AscWaitEEPRead(); - read_wval = AscGetChipEEPData(iop_base); - AscWaitEEPRead(); - return read_wval; -} - -static ushort __devinit -AscGetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) -{ - ushort wval; - ushort sum; - ushort *wbuf; - int cfg_beg; - int cfg_end; - int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2; - int s_addr; - - wbuf = (ushort *)cfg_buf; - sum = 0; - /* Read two config words; Byte-swapping done by AscReadEEPWord(). */ - for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { - *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr); - sum += *wbuf; - } - if (bus_type & ASC_IS_VL) { - cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; - cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; - } else { - cfg_beg = ASC_EEP_DVC_CFG_BEG; - cfg_end = ASC_EEP_MAX_DVC_ADDR; - } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { - wval = AscReadEEPWord(iop_base, (uchar)s_addr); - if (s_addr <= uchar_end_in_config) { - /* - * Swap all char fields - must unswap bytes already swapped - * by AscReadEEPWord(). - */ - *wbuf = le16_to_cpu(wval); - } else { - /* Don't swap word field at the end - cntl field. */ - *wbuf = wval; - } - sum += wval; /* Checksum treats all EEPROM data as words. */ - } - /* - * Read the checksum word which will be compared against 'sum' - * by the caller. Word field already swapped. - */ - *wbuf = AscReadEEPWord(iop_base, (uchar)s_addr); - return sum; -} - -static int __devinit AscTestExternalLram(ASC_DVC_VAR *asc_dvc) -{ - PortAddr iop_base; - ushort q_addr; - ushort saved_word; - int sta; - - iop_base = asc_dvc->iop_base; - sta = 0; - q_addr = ASC_QNO_TO_QADDR(241); - saved_word = AscReadLramWord(iop_base, q_addr); - AscSetChipLramAddr(iop_base, q_addr); - AscSetChipLramData(iop_base, 0x55AA); - mdelay(10); - AscSetChipLramAddr(iop_base, q_addr); - if (AscGetChipLramData(iop_base) == 0x55AA) { - sta = 1; - AscWriteLramWord(iop_base, q_addr, saved_word); - } - return (sta); -} - -static void __devinit AscWaitEEPWrite(void) -{ - mdelay(20); -} - -static int __devinit AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg) -{ - ushort read_back; - int retry; - - retry = 0; - while (TRUE) { - AscSetChipEEPData(iop_base, data_reg); - mdelay(1); - read_back = AscGetChipEEPData(iop_base); - if (read_back == data_reg) { - return (1); - } - if (retry++ > ASC_EEP_MAX_RETRY) { - return (0); - } - } -} - -static ushort __devinit -AscWriteEEPWord(PortAddr iop_base, uchar addr, ushort word_val) -{ - ushort read_wval; - - read_wval = AscReadEEPWord(iop_base, addr); - if (read_wval != word_val) { - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE); - AscWaitEEPRead(); - AscWriteEEPDataReg(iop_base, word_val); - AscWaitEEPRead(); - AscWriteEEPCmdReg(iop_base, - (uchar)((uchar)ASC_EEP_CMD_WRITE | addr)); - AscWaitEEPWrite(); - AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE); - AscWaitEEPRead(); - return (AscReadEEPWord(iop_base, addr)); - } - return (read_wval); -} - -static int __devinit -AscSetEEPConfigOnce(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) -{ - int n_error; - ushort *wbuf; - ushort word; - ushort sum; - int s_addr; - int cfg_beg; - int cfg_end; - int uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2; - - wbuf = (ushort *)cfg_buf; - n_error = 0; - sum = 0; - /* Write two config words; AscWriteEEPWord() will swap bytes. */ - for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { - sum += *wbuf; - if (*wbuf != AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) { - n_error++; - } - } - if (bus_type & ASC_IS_VL) { - cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; - cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; - } else { - cfg_beg = ASC_EEP_DVC_CFG_BEG; - cfg_end = ASC_EEP_MAX_DVC_ADDR; - } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { - if (s_addr <= uchar_end_in_config) { - /* - * This is a char field. Swap char fields before they are - * swapped again by AscWriteEEPWord(). - */ - word = cpu_to_le16(*wbuf); - if (word != - AscWriteEEPWord(iop_base, (uchar)s_addr, word)) { - n_error++; - } - } else { - /* Don't swap word field at the end - cntl field. */ - if (*wbuf != - AscWriteEEPWord(iop_base, (uchar)s_addr, *wbuf)) { - n_error++; - } - } - sum += *wbuf; /* Checksum calculated from word values. */ - } - /* Write checksum word. It will be swapped by AscWriteEEPWord(). */ - *wbuf = sum; - if (sum != AscWriteEEPWord(iop_base, (uchar)s_addr, sum)) { - n_error++; - } - - /* Read EEPROM back again. */ - wbuf = (ushort *)cfg_buf; - /* - * Read two config words; Byte-swapping done by AscReadEEPWord(). - */ - for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) { - if (*wbuf != AscReadEEPWord(iop_base, (uchar)s_addr)) { - n_error++; - } - } - if (bus_type & ASC_IS_VL) { - cfg_beg = ASC_EEP_DVC_CFG_BEG_VL; - cfg_end = ASC_EEP_MAX_DVC_ADDR_VL; - } else { - cfg_beg = ASC_EEP_DVC_CFG_BEG; - cfg_end = ASC_EEP_MAX_DVC_ADDR; - } - for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) { - if (s_addr <= uchar_end_in_config) { - /* - * Swap all char fields. Must unswap bytes already swapped - * by AscReadEEPWord(). - */ - word = - le16_to_cpu(AscReadEEPWord - (iop_base, (uchar)s_addr)); - } else { - /* Don't swap word field at the end - cntl field. */ - word = AscReadEEPWord(iop_base, (uchar)s_addr); - } - if (*wbuf != word) { - n_error++; - } - } - /* Read checksum; Byte swapping not needed. */ - if (AscReadEEPWord(iop_base, (uchar)s_addr) != sum) { - n_error++; - } - return n_error; -} - -static int __devinit -AscSetEEPConfig(PortAddr iop_base, ASCEEP_CONFIG *cfg_buf, ushort bus_type) -{ - int retry; - int n_error; - - retry = 0; - while (TRUE) { - if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf, - bus_type)) == 0) { - break; - } - if (++retry > ASC_EEP_MAX_RETRY) { - break; - } - } - return n_error; -} - -static ushort __devinit AscInitFromEEP(ASC_DVC_VAR *asc_dvc) -{ - ASCEEP_CONFIG eep_config_buf; - ASCEEP_CONFIG *eep_config; - PortAddr iop_base; - ushort chksum; - ushort warn_code; - ushort cfg_msw, cfg_lsw; - int i; - int write_eep = 0; - - iop_base = asc_dvc->iop_base; - warn_code = 0; - AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE); - AscStopQueueExe(iop_base); - if ((AscStopChip(iop_base) == FALSE) || - (AscGetChipScsiCtrl(iop_base) != 0)) { - asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE; - AscResetChipAndScsiBus(asc_dvc); - mdelay(asc_dvc->scsi_reset_wait * 1000); /* XXX: msleep? */ - } - if (AscIsChipHalted(iop_base) == FALSE) { - asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP; - return (warn_code); - } - AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR); - if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) { - asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR; - return (warn_code); - } - eep_config = (ASCEEP_CONFIG *)&eep_config_buf; - cfg_msw = AscGetChipCfgMsw(iop_base); - cfg_lsw = AscGetChipCfgLsw(iop_base); - if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { - cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; - warn_code |= ASC_WARN_CFG_MSW_RECOVER; - AscSetChipCfgMsw(iop_base, cfg_msw); - } - chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type); - ASC_DBG(1, "chksum 0x%x\n", chksum); - if (chksum == 0) { - chksum = 0xaa55; - } - if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { - warn_code |= ASC_WARN_AUTO_CONFIG; - if (asc_dvc->cfg->chip_version == 3) { - if (eep_config->cfg_lsw != cfg_lsw) { - warn_code |= ASC_WARN_EEPROM_RECOVER; - eep_config->cfg_lsw = - AscGetChipCfgLsw(iop_base); - } - if (eep_config->cfg_msw != cfg_msw) { - warn_code |= ASC_WARN_EEPROM_RECOVER; - eep_config->cfg_msw = - AscGetChipCfgMsw(iop_base); - } - } - } - eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; - eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON; - ASC_DBG(1, "eep_config->chksum 0x%x\n", eep_config->chksum); - if (chksum != eep_config->chksum) { - if (AscGetChipVersion(iop_base, asc_dvc->bus_type) == - ASC_CHIP_VER_PCI_ULTRA_3050) { - ASC_DBG(1, "chksum error ignored; EEPROM-less board\n"); - eep_config->init_sdtr = 0xFF; - eep_config->disc_enable = 0xFF; - eep_config->start_motor = 0xFF; - eep_config->use_cmd_qng = 0; - eep_config->max_total_qng = 0xF0; - eep_config->max_tag_qng = 0x20; - eep_config->cntl = 0xBFFF; - ASC_EEP_SET_CHIP_ID(eep_config, 7); - eep_config->no_scam = 0; - eep_config->adapter_info[0] = 0; - eep_config->adapter_info[1] = 0; - eep_config->adapter_info[2] = 0; - eep_config->adapter_info[3] = 0; - eep_config->adapter_info[4] = 0; - /* Indicate EEPROM-less board. */ - eep_config->adapter_info[5] = 0xBB; - } else { - ASC_PRINT - ("AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n"); - write_eep = 1; - warn_code |= ASC_WARN_EEPROM_CHKSUM; - } - } - asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr; - asc_dvc->cfg->disc_enable = eep_config->disc_enable; - asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng; - asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config); - asc_dvc->start_motor = eep_config->start_motor; - asc_dvc->dvc_cntl = eep_config->cntl; - asc_dvc->no_scam = eep_config->no_scam; - asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0]; - asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1]; - asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2]; - asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3]; - asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4]; - asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5]; - if (!AscTestExternalLram(asc_dvc)) { - if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == - ASC_IS_PCI_ULTRA)) { - eep_config->max_total_qng = - ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG; - eep_config->max_tag_qng = - ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG; - } else { - eep_config->cfg_msw |= 0x0800; - cfg_msw |= 0x0800; - AscSetChipCfgMsw(iop_base, cfg_msw); - eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG; - eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG; - } - } else { - } - if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) { - eep_config->max_total_qng = ASC_MIN_TOTAL_QNG; - } - if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) { - eep_config->max_total_qng = ASC_MAX_TOTAL_QNG; - } - if (eep_config->max_tag_qng > eep_config->max_total_qng) { - eep_config->max_tag_qng = eep_config->max_total_qng; - } - if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) { - eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC; - } - asc_dvc->max_total_qng = eep_config->max_total_qng; - if ((eep_config->use_cmd_qng & eep_config->disc_enable) != - eep_config->use_cmd_qng) { - eep_config->disc_enable = eep_config->use_cmd_qng; - warn_code |= ASC_WARN_CMD_QNG_CONFLICT; - } - ASC_EEP_SET_CHIP_ID(eep_config, - ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID); - asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config); - if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) && - !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) { - asc_dvc->min_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX; - } - - for (i = 0; i <= ASC_MAX_TID; i++) { - asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i]; - asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng; - asc_dvc->cfg->sdtr_period_offset[i] = - (uchar)(ASC_DEF_SDTR_OFFSET | - (asc_dvc->min_sdtr_index << 4)); - } - eep_config->cfg_msw = AscGetChipCfgMsw(iop_base); - if (write_eep) { - if ((i = AscSetEEPConfig(iop_base, eep_config, - asc_dvc->bus_type)) != 0) { - ASC_PRINT1 - ("AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", - i); - } else { - ASC_PRINT - ("AscInitFromEEP: Successfully re-wrote EEPROM.\n"); - } - } - return (warn_code); -} - -static int __devinit AscInitGetConfig(struct Scsi_Host *shost) -{ - struct asc_board *board = shost_priv(shost); - ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var; - unsigned short warn_code = 0; - - asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG; - if (asc_dvc->err_code != 0) - return asc_dvc->err_code; - - if (AscFindSignature(asc_dvc->iop_base)) { - warn_code |= AscInitAscDvcVar(asc_dvc); - warn_code |= AscInitFromEEP(asc_dvc); - asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG; - if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) - asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT; - } else { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - } - - switch (warn_code) { - case 0: /* No error */ - break; - case ASC_WARN_IO_PORT_ROTATE: - shost_printk(KERN_WARNING, shost, "I/O port address " - "modified\n"); - break; - case ASC_WARN_AUTO_CONFIG: - shost_printk(KERN_WARNING, shost, "I/O port increment switch " - "enabled\n"); - break; - case ASC_WARN_EEPROM_CHKSUM: - shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n"); - break; - case ASC_WARN_IRQ_MODIFIED: - shost_printk(KERN_WARNING, shost, "IRQ modified\n"); - break; - case ASC_WARN_CMD_QNG_CONFLICT: - shost_printk(KERN_WARNING, shost, "tag queuing enabled w/o " - "disconnects\n"); - break; - default: - shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n", - warn_code); - break; - } - - if (asc_dvc->err_code != 0) - shost_printk(KERN_ERR, shost, "error 0x%x at init_state " - "0x%x\n", asc_dvc->err_code, asc_dvc->init_state); - - return asc_dvc->err_code; -} - -static int __devinit AscInitSetConfig(struct pci_dev *pdev, struct Scsi_Host *shost) -{ - struct asc_board *board = shost_priv(shost); - ASC_DVC_VAR *asc_dvc = &board->dvc_var.asc_dvc_var; - PortAddr iop_base = asc_dvc->iop_base; - unsigned short cfg_msw; - unsigned short warn_code = 0; - - asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG; - if (asc_dvc->err_code != 0) - return asc_dvc->err_code; - if (!AscFindSignature(asc_dvc->iop_base)) { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - return asc_dvc->err_code; - } - - cfg_msw = AscGetChipCfgMsw(iop_base); - if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) { - cfg_msw &= ~ASC_CFG_MSW_CLR_MASK; - warn_code |= ASC_WARN_CFG_MSW_RECOVER; - AscSetChipCfgMsw(iop_base, cfg_msw); - } - if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) != - asc_dvc->cfg->cmd_qng_enabled) { - asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled; - warn_code |= ASC_WARN_CMD_QNG_CONFLICT; - } - if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) { - warn_code |= ASC_WARN_AUTO_CONFIG; - } -#ifdef CONFIG_PCI - if (asc_dvc->bus_type & ASC_IS_PCI) { - cfg_msw &= 0xFFC0; - AscSetChipCfgMsw(iop_base, cfg_msw); - if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) { - } else { - if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) || - (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB; - asc_dvc->bug_fix_cntl |= - ASC_BUG_FIX_ASYN_USE_SYN; - } - } - } else -#endif /* CONFIG_PCI */ - if (asc_dvc->bus_type == ASC_IS_ISAPNP) { - if (AscGetChipVersion(iop_base, asc_dvc->bus_type) - == ASC_CHIP_VER_ASYN_BUG) { - asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN; - } - } - if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) != - asc_dvc->cfg->chip_scsi_id) { - asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID; - } -#ifdef CONFIG_ISA - if (asc_dvc->bus_type & ASC_IS_ISA) { - AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel); - AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed); - } -#endif /* CONFIG_ISA */ - - asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG; - - switch (warn_code) { - case 0: /* No error. */ - break; - case ASC_WARN_IO_PORT_ROTATE: - shost_printk(KERN_WARNING, shost, "I/O port address " - "modified\n"); - break; - case ASC_WARN_AUTO_CONFIG: - shost_printk(KERN_WARNING, shost, "I/O port increment switch " - "enabled\n"); - break; - case ASC_WARN_EEPROM_CHKSUM: - shost_printk(KERN_WARNING, shost, "EEPROM checksum error\n"); - break; - case ASC_WARN_IRQ_MODIFIED: - shost_printk(KERN_WARNING, shost, "IRQ modified\n"); - break; - case ASC_WARN_CMD_QNG_CONFLICT: - shost_printk(KERN_WARNING, shost, "tag queuing w/o " - "disconnects\n"); - break; - default: - shost_printk(KERN_WARNING, shost, "unknown warning: 0x%x\n", - warn_code); - break; - } - - if (asc_dvc->err_code != 0) - shost_printk(KERN_ERR, shost, "error 0x%x at init_state " - "0x%x\n", asc_dvc->err_code, asc_dvc->init_state); - - return asc_dvc->err_code; -} - -/* - * EEPROM Configuration. - * - * All drivers should use this structure to set the default EEPROM - * configuration. The BIOS now uses this structure when it is built. - * Additional structure information can be found in a_condor.h where - * the structure is defined. - * - * The *_Field_IsChar structs are needed to correct for endianness. - * These values are read from the board 16 bits at a time directly - * into the structs. Because some fields are char, the values will be - * in the wrong order. The *_Field_IsChar tells when to flip the - * bytes. Data read and written to PCI memory is automatically swapped - * on big-endian platforms so char fields read as words are actually being - * unswapped on big-endian platforms. - */ -static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config __devinitdata = { - ADV_EEPROM_BIOS_ENABLE, /* cfg_lsw */ - 0x0000, /* cfg_msw */ - 0xFFFF, /* disc_enable */ - 0xFFFF, /* wdtr_able */ - 0xFFFF, /* sdtr_able */ - 0xFFFF, /* start_motor */ - 0xFFFF, /* tagqng_able */ - 0xFFFF, /* bios_scan */ - 0, /* scam_tolerant */ - 7, /* adapter_scsi_id */ - 0, /* bios_boot_delay */ - 3, /* scsi_reset_delay */ - 0, /* bios_id_lun */ - 0, /* termination */ - 0, /* reserved1 */ - 0xFFE7, /* bios_ctrl */ - 0xFFFF, /* ultra_able */ - 0, /* reserved2 */ - ASC_DEF_MAX_HOST_QNG, /* max_host_qng */ - ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */ - 0, /* dvc_cntl */ - 0, /* bug_fix */ - 0, /* serial_number_word1 */ - 0, /* serial_number_word2 */ - 0, /* serial_number_word3 */ - 0, /* check_sum */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - , /* oem_name[16] */ - 0, /* dvc_err_code */ - 0, /* adv_err_code */ - 0, /* adv_err_addr */ - 0, /* saved_dvc_err_code */ - 0, /* saved_adv_err_code */ - 0, /* saved_adv_err_addr */ - 0 /* num_of_err */ -}; - -static ADVEEP_3550_CONFIG ADVEEP_3550_Config_Field_IsChar __devinitdata = { - 0, /* cfg_lsw */ - 0, /* cfg_msw */ - 0, /* -disc_enable */ - 0, /* wdtr_able */ - 0, /* sdtr_able */ - 0, /* start_motor */ - 0, /* tagqng_able */ - 0, /* bios_scan */ - 0, /* scam_tolerant */ - 1, /* adapter_scsi_id */ - 1, /* bios_boot_delay */ - 1, /* scsi_reset_delay */ - 1, /* bios_id_lun */ - 1, /* termination */ - 1, /* reserved1 */ - 0, /* bios_ctrl */ - 0, /* ultra_able */ - 0, /* reserved2 */ - 1, /* max_host_qng */ - 1, /* max_dvc_qng */ - 0, /* dvc_cntl */ - 0, /* bug_fix */ - 0, /* serial_number_word1 */ - 0, /* serial_number_word2 */ - 0, /* serial_number_word3 */ - 0, /* check_sum */ - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - , /* oem_name[16] */ - 0, /* dvc_err_code */ - 0, /* adv_err_code */ - 0, /* adv_err_addr */ - 0, /* saved_dvc_err_code */ - 0, /* saved_adv_err_code */ - 0, /* saved_adv_err_addr */ - 0 /* num_of_err */ -}; - -static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config __devinitdata = { - ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ - 0x0000, /* 01 cfg_msw */ - 0xFFFF, /* 02 disc_enable */ - 0xFFFF, /* 03 wdtr_able */ - 0x4444, /* 04 sdtr_speed1 */ - 0xFFFF, /* 05 start_motor */ - 0xFFFF, /* 06 tagqng_able */ - 0xFFFF, /* 07 bios_scan */ - 0, /* 08 scam_tolerant */ - 7, /* 09 adapter_scsi_id */ - 0, /* bios_boot_delay */ - 3, /* 10 scsi_reset_delay */ - 0, /* bios_id_lun */ - 0, /* 11 termination_se */ - 0, /* termination_lvd */ - 0xFFE7, /* 12 bios_ctrl */ - 0x4444, /* 13 sdtr_speed2 */ - 0x4444, /* 14 sdtr_speed3 */ - ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */ - ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */ - 0, /* 16 dvc_cntl */ - 0x4444, /* 17 sdtr_speed4 */ - 0, /* 18 serial_number_word1 */ - 0, /* 19 serial_number_word2 */ - 0, /* 20 serial_number_word3 */ - 0, /* 21 check_sum */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - , /* 22-29 oem_name[16] */ - 0, /* 30 dvc_err_code */ - 0, /* 31 adv_err_code */ - 0, /* 32 adv_err_addr */ - 0, /* 33 saved_dvc_err_code */ - 0, /* 34 saved_adv_err_code */ - 0, /* 35 saved_adv_err_addr */ - 0, /* 36 reserved */ - 0, /* 37 reserved */ - 0, /* 38 reserved */ - 0, /* 39 reserved */ - 0, /* 40 reserved */ - 0, /* 41 reserved */ - 0, /* 42 reserved */ - 0, /* 43 reserved */ - 0, /* 44 reserved */ - 0, /* 45 reserved */ - 0, /* 46 reserved */ - 0, /* 47 reserved */ - 0, /* 48 reserved */ - 0, /* 49 reserved */ - 0, /* 50 reserved */ - 0, /* 51 reserved */ - 0, /* 52 reserved */ - 0, /* 53 reserved */ - 0, /* 54 reserved */ - 0, /* 55 reserved */ - 0, /* 56 cisptr_lsw */ - 0, /* 57 cisprt_msw */ - PCI_VENDOR_ID_ASP, /* 58 subsysvid */ - PCI_DEVICE_ID_38C0800_REV1, /* 59 subsysid */ - 0, /* 60 reserved */ - 0, /* 61 reserved */ - 0, /* 62 reserved */ - 0 /* 63 reserved */ -}; - -static ADVEEP_38C0800_CONFIG ADVEEP_38C0800_Config_Field_IsChar __devinitdata = { - 0, /* 00 cfg_lsw */ - 0, /* 01 cfg_msw */ - 0, /* 02 disc_enable */ - 0, /* 03 wdtr_able */ - 0, /* 04 sdtr_speed1 */ - 0, /* 05 start_motor */ - 0, /* 06 tagqng_able */ - 0, /* 07 bios_scan */ - 0, /* 08 scam_tolerant */ - 1, /* 09 adapter_scsi_id */ - 1, /* bios_boot_delay */ - 1, /* 10 scsi_reset_delay */ - 1, /* bios_id_lun */ - 1, /* 11 termination_se */ - 1, /* termination_lvd */ - 0, /* 12 bios_ctrl */ - 0, /* 13 sdtr_speed2 */ - 0, /* 14 sdtr_speed3 */ - 1, /* 15 max_host_qng */ - 1, /* max_dvc_qng */ - 0, /* 16 dvc_cntl */ - 0, /* 17 sdtr_speed4 */ - 0, /* 18 serial_number_word1 */ - 0, /* 19 serial_number_word2 */ - 0, /* 20 serial_number_word3 */ - 0, /* 21 check_sum */ - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - , /* 22-29 oem_name[16] */ - 0, /* 30 dvc_err_code */ - 0, /* 31 adv_err_code */ - 0, /* 32 adv_err_addr */ - 0, /* 33 saved_dvc_err_code */ - 0, /* 34 saved_adv_err_code */ - 0, /* 35 saved_adv_err_addr */ - 0, /* 36 reserved */ - 0, /* 37 reserved */ - 0, /* 38 reserved */ - 0, /* 39 reserved */ - 0, /* 40 reserved */ - 0, /* 41 reserved */ - 0, /* 42 reserved */ - 0, /* 43 reserved */ - 0, /* 44 reserved */ - 0, /* 45 reserved */ - 0, /* 46 reserved */ - 0, /* 47 reserved */ - 0, /* 48 reserved */ - 0, /* 49 reserved */ - 0, /* 50 reserved */ - 0, /* 51 reserved */ - 0, /* 52 reserved */ - 0, /* 53 reserved */ - 0, /* 54 reserved */ - 0, /* 55 reserved */ - 0, /* 56 cisptr_lsw */ - 0, /* 57 cisprt_msw */ - 0, /* 58 subsysvid */ - 0, /* 59 subsysid */ - 0, /* 60 reserved */ - 0, /* 61 reserved */ - 0, /* 62 reserved */ - 0 /* 63 reserved */ -}; - -static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config __devinitdata = { - ADV_EEPROM_BIOS_ENABLE, /* 00 cfg_lsw */ - 0x0000, /* 01 cfg_msw */ - 0xFFFF, /* 02 disc_enable */ - 0xFFFF, /* 03 wdtr_able */ - 0x5555, /* 04 sdtr_speed1 */ - 0xFFFF, /* 05 start_motor */ - 0xFFFF, /* 06 tagqng_able */ - 0xFFFF, /* 07 bios_scan */ - 0, /* 08 scam_tolerant */ - 7, /* 09 adapter_scsi_id */ - 0, /* bios_boot_delay */ - 3, /* 10 scsi_reset_delay */ - 0, /* bios_id_lun */ - 0, /* 11 termination_se */ - 0, /* termination_lvd */ - 0xFFE7, /* 12 bios_ctrl */ - 0x5555, /* 13 sdtr_speed2 */ - 0x5555, /* 14 sdtr_speed3 */ - ASC_DEF_MAX_HOST_QNG, /* 15 max_host_qng */ - ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */ - 0, /* 16 dvc_cntl */ - 0x5555, /* 17 sdtr_speed4 */ - 0, /* 18 serial_number_word1 */ - 0, /* 19 serial_number_word2 */ - 0, /* 20 serial_number_word3 */ - 0, /* 21 check_sum */ - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - , /* 22-29 oem_name[16] */ - 0, /* 30 dvc_err_code */ - 0, /* 31 adv_err_code */ - 0, /* 32 adv_err_addr */ - 0, /* 33 saved_dvc_err_code */ - 0, /* 34 saved_adv_err_code */ - 0, /* 35 saved_adv_err_addr */ - 0, /* 36 reserved */ - 0, /* 37 reserved */ - 0, /* 38 reserved */ - 0, /* 39 reserved */ - 0, /* 40 reserved */ - 0, /* 41 reserved */ - 0, /* 42 reserved */ - 0, /* 43 reserved */ - 0, /* 44 reserved */ - 0, /* 45 reserved */ - 0, /* 46 reserved */ - 0, /* 47 reserved */ - 0, /* 48 reserved */ - 0, /* 49 reserved */ - 0, /* 50 reserved */ - 0, /* 51 reserved */ - 0, /* 52 reserved */ - 0, /* 53 reserved */ - 0, /* 54 reserved */ - 0, /* 55 reserved */ - 0, /* 56 cisptr_lsw */ - 0, /* 57 cisprt_msw */ - PCI_VENDOR_ID_ASP, /* 58 subsysvid */ - PCI_DEVICE_ID_38C1600_REV1, /* 59 subsysid */ - 0, /* 60 reserved */ - 0, /* 61 reserved */ - 0, /* 62 reserved */ - 0 /* 63 reserved */ -}; - -static ADVEEP_38C1600_CONFIG ADVEEP_38C1600_Config_Field_IsChar __devinitdata = { - 0, /* 00 cfg_lsw */ - 0, /* 01 cfg_msw */ - 0, /* 02 disc_enable */ - 0, /* 03 wdtr_able */ - 0, /* 04 sdtr_speed1 */ - 0, /* 05 start_motor */ - 0, /* 06 tagqng_able */ - 0, /* 07 bios_scan */ - 0, /* 08 scam_tolerant */ - 1, /* 09 adapter_scsi_id */ - 1, /* bios_boot_delay */ - 1, /* 10 scsi_reset_delay */ - 1, /* bios_id_lun */ - 1, /* 11 termination_se */ - 1, /* termination_lvd */ - 0, /* 12 bios_ctrl */ - 0, /* 13 sdtr_speed2 */ - 0, /* 14 sdtr_speed3 */ - 1, /* 15 max_host_qng */ - 1, /* max_dvc_qng */ - 0, /* 16 dvc_cntl */ - 0, /* 17 sdtr_speed4 */ - 0, /* 18 serial_number_word1 */ - 0, /* 19 serial_number_word2 */ - 0, /* 20 serial_number_word3 */ - 0, /* 21 check_sum */ - {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} - , /* 22-29 oem_name[16] */ - 0, /* 30 dvc_err_code */ - 0, /* 31 adv_err_code */ - 0, /* 32 adv_err_addr */ - 0, /* 33 saved_dvc_err_code */ - 0, /* 34 saved_adv_err_code */ - 0, /* 35 saved_adv_err_addr */ - 0, /* 36 reserved */ - 0, /* 37 reserved */ - 0, /* 38 reserved */ - 0, /* 39 reserved */ - 0, /* 40 reserved */ - 0, /* 41 reserved */ - 0, /* 42 reserved */ - 0, /* 43 reserved */ - 0, /* 44 reserved */ - 0, /* 45 reserved */ - 0, /* 46 reserved */ - 0, /* 47 reserved */ - 0, /* 48 reserved */ - 0, /* 49 reserved */ - 0, /* 50 reserved */ - 0, /* 51 reserved */ - 0, /* 52 reserved */ - 0, /* 53 reserved */ - 0, /* 54 reserved */ - 0, /* 55 reserved */ - 0, /* 56 cisptr_lsw */ - 0, /* 57 cisprt_msw */ - 0, /* 58 subsysvid */ - 0, /* 59 subsysid */ - 0, /* 60 reserved */ - 0, /* 61 reserved */ - 0, /* 62 reserved */ - 0 /* 63 reserved */ -}; - -#ifdef CONFIG_PCI -/* - * Wait for EEPROM command to complete - */ -static void __devinit AdvWaitEEPCmd(AdvPortAddr iop_base) -{ - int eep_delay_ms; - - for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++) { - if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & - ASC_EEP_CMD_DONE) { - break; - } - mdelay(1); - } - if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == - 0) - BUG(); -} - -/* - * Read the EEPROM from specified location - */ -static ushort __devinit AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr) -{ - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_READ | eep_word_addr); - AdvWaitEEPCmd(iop_base); - return AdvReadWordRegister(iop_base, IOPW_EE_DATA); -} - -/* - * Write the EEPROM from 'cfg_buf'. - */ -static void __devinit -AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) -{ - ushort *wbuf; - ushort addr, chksum; - ushort *charfields; - - wbuf = (ushort *)cfg_buf; - charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar; - chksum = 0; - - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); - AdvWaitEEPCmd(iop_base); - - /* - * Write EEPROM from word 0 to word 20. - */ - for (addr = ADV_EEP_DVC_CFG_BEGIN; - addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - chksum += *wbuf; /* Checksum is calculated from word values. */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - mdelay(ADV_EEP_DELAY_MS); - } - - /* - * Write EEPROM checksum at word 21. - */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - wbuf++; - charfields++; - - /* - * Write EEPROM OEM name at words 22 to 29. - */ - for (addr = ADV_EEP_DVC_CTL_BEGIN; - addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - } - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); - AdvWaitEEPCmd(iop_base); -} - -/* - * Write the EEPROM from 'cfg_buf'. - */ -static void __devinit -AdvSet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) -{ - ushort *wbuf; - ushort *charfields; - ushort addr, chksum; - - wbuf = (ushort *)cfg_buf; - charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar; - chksum = 0; - - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); - AdvWaitEEPCmd(iop_base); - - /* - * Write EEPROM from word 0 to word 20. - */ - for (addr = ADV_EEP_DVC_CFG_BEGIN; - addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - chksum += *wbuf; /* Checksum is calculated from word values. */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - mdelay(ADV_EEP_DELAY_MS); - } - - /* - * Write EEPROM checksum at word 21. - */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - wbuf++; - charfields++; - - /* - * Write EEPROM OEM name at words 22 to 29. - */ - for (addr = ADV_EEP_DVC_CTL_BEGIN; - addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - } - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); - AdvWaitEEPCmd(iop_base); -} - -/* - * Write the EEPROM from 'cfg_buf'. - */ -static void __devinit -AdvSet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) -{ - ushort *wbuf; - ushort *charfields; - ushort addr, chksum; - - wbuf = (ushort *)cfg_buf; - charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar; - chksum = 0; - - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE); - AdvWaitEEPCmd(iop_base); - - /* - * Write EEPROM from word 0 to word 20. - */ - for (addr = ADV_EEP_DVC_CFG_BEGIN; - addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - chksum += *wbuf; /* Checksum is calculated from word values. */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - mdelay(ADV_EEP_DELAY_MS); - } - - /* - * Write EEPROM checksum at word 21. - */ - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - wbuf++; - charfields++; - - /* - * Write EEPROM OEM name at words 22 to 29. - */ - for (addr = ADV_EEP_DVC_CTL_BEGIN; - addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++) { - ushort word; - - if (*charfields++) { - word = cpu_to_le16(*wbuf); - } else { - word = *wbuf; - } - AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word); - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, - ASC_EEP_CMD_WRITE | addr); - AdvWaitEEPCmd(iop_base); - } - AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE); - AdvWaitEEPCmd(iop_base); -} - -/* - * Read EEPROM configuration into the specified buffer. - * - * Return a checksum based on the EEPROM configuration read. - */ -static ushort __devinit -AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf) -{ - ushort wval, chksum; - ushort *wbuf; - int eep_addr; - ushort *charfields; - - charfields = (ushort *)&ADVEEP_3550_Config_Field_IsChar; - wbuf = (ushort *)cfg_buf; - chksum = 0; - - for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; - eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { - wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; /* Checksum is calculated from word values. */ - if (*charfields++) { - *wbuf = le16_to_cpu(wval); - } else { - *wbuf = wval; - } - } - /* Read checksum word. */ - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - charfields++; - - /* Read rest of EEPROM not covered by the checksum. */ - for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; - eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - if (*charfields++) { - *wbuf = le16_to_cpu(*wbuf); - } - } - return chksum; -} - -/* - * Read EEPROM configuration into the specified buffer. - * - * Return a checksum based on the EEPROM configuration read. - */ -static ushort __devinit -AdvGet38C0800EEPConfig(AdvPortAddr iop_base, ADVEEP_38C0800_CONFIG *cfg_buf) -{ - ushort wval, chksum; - ushort *wbuf; - int eep_addr; - ushort *charfields; - - charfields = (ushort *)&ADVEEP_38C0800_Config_Field_IsChar; - wbuf = (ushort *)cfg_buf; - chksum = 0; - - for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; - eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { - wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; /* Checksum is calculated from word values. */ - if (*charfields++) { - *wbuf = le16_to_cpu(wval); - } else { - *wbuf = wval; - } - } - /* Read checksum word. */ - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - charfields++; - - /* Read rest of EEPROM not covered by the checksum. */ - for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; - eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - if (*charfields++) { - *wbuf = le16_to_cpu(*wbuf); - } - } - return chksum; -} - -/* - * Read EEPROM configuration into the specified buffer. - * - * Return a checksum based on the EEPROM configuration read. - */ -static ushort __devinit -AdvGet38C1600EEPConfig(AdvPortAddr iop_base, ADVEEP_38C1600_CONFIG *cfg_buf) -{ - ushort wval, chksum; - ushort *wbuf; - int eep_addr; - ushort *charfields; - - charfields = (ushort *)&ADVEEP_38C1600_Config_Field_IsChar; - wbuf = (ushort *)cfg_buf; - chksum = 0; - - for (eep_addr = ADV_EEP_DVC_CFG_BEGIN; - eep_addr < ADV_EEP_DVC_CFG_END; eep_addr++, wbuf++) { - wval = AdvReadEEPWord(iop_base, eep_addr); - chksum += wval; /* Checksum is calculated from word values. */ - if (*charfields++) { - *wbuf = le16_to_cpu(wval); - } else { - *wbuf = wval; - } - } - /* Read checksum word. */ - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - wbuf++; - charfields++; - - /* Read rest of EEPROM not covered by the checksum. */ - for (eep_addr = ADV_EEP_DVC_CTL_BEGIN; - eep_addr < ADV_EEP_MAX_WORD_ADDR; eep_addr++, wbuf++) { - *wbuf = AdvReadEEPWord(iop_base, eep_addr); - if (*charfields++) { - *wbuf = le16_to_cpu(*wbuf); - } - } - return chksum; -} - -/* - * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and - * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while - * all of this is done. - * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - * - * Note: Chip is stopped on entry. - */ -static int __devinit AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc) -{ - AdvPortAddr iop_base; - ushort warn_code; - ADVEEP_3550_CONFIG eep_config; - - iop_base = asc_dvc->iop_base; - - warn_code = 0; - - /* - * Read the board's EEPROM configuration. - * - * Set default values if a bad checksum is found. - */ - if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum) { - warn_code |= ASC_WARN_EEPROM_CHKSUM; - - /* - * Set EEPROM default values. - */ - memcpy(&eep_config, &Default_3550_EEPROM_Config, - sizeof(ADVEEP_3550_CONFIG)); - - /* - * Assume the 6 byte board serial number that was read from - * EEPROM is correct even if the EEPROM checksum failed. - */ - eep_config.serial_number_word3 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); - - eep_config.serial_number_word2 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); - - eep_config.serial_number_word1 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); - - AdvSet3550EEPConfig(iop_base, &eep_config); - } - /* - * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the - * EEPROM configuration that was read. - * - * This is the mapping of EEPROM fields to Adv Library fields. - */ - asc_dvc->wdtr_able = eep_config.wdtr_able; - asc_dvc->sdtr_able = eep_config.sdtr_able; - asc_dvc->ultra_able = eep_config.ultra_able; - asc_dvc->tagqng_able = eep_config.tagqng_able; - asc_dvc->cfg->disc_enable = eep_config.disc_enable; - asc_dvc->max_host_qng = eep_config.max_host_qng; - asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); - asc_dvc->start_motor = eep_config.start_motor; - asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; - asc_dvc->bios_ctrl = eep_config.bios_ctrl; - asc_dvc->no_scam = eep_config.scam_tolerant; - asc_dvc->cfg->serial1 = eep_config.serial_number_word1; - asc_dvc->cfg->serial2 = eep_config.serial_number_word2; - asc_dvc->cfg->serial3 = eep_config.serial_number_word3; - - /* - * Set the host maximum queuing (max. 253, min. 16) and the per device - * maximum queuing (max. 63, min. 4). - */ - if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) { - eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; - } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) { - /* If the value is zero, assume it is uninitialized. */ - if (eep_config.max_host_qng == 0) { - eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; - } else { - eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG; - } - } - - if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) { - eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; - } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) { - /* If the value is zero, assume it is uninitialized. */ - if (eep_config.max_dvc_qng == 0) { - eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; - } else { - eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG; - } - } - - /* - * If 'max_dvc_qng' is greater than 'max_host_qng', then - * set 'max_dvc_qng' to 'max_host_qng'. - */ - if (eep_config.max_dvc_qng > eep_config.max_host_qng) { - eep_config.max_dvc_qng = eep_config.max_host_qng; - } - - /* - * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' - * values based on possibly adjusted EEPROM values. - */ - asc_dvc->max_host_qng = eep_config.max_host_qng; - asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - - /* - * If the EEPROM 'termination' field is set to automatic (0), then set - * the ADV_DVC_CFG 'termination' field to automatic also. - * - * If the termination is specified with a non-zero 'termination' - * value check that a legal value is set and set the ADV_DVC_CFG - * 'termination' field appropriately. - */ - if (eep_config.termination == 0) { - asc_dvc->cfg->termination = 0; /* auto termination */ - } else { - /* Enable manual control with low off / high off. */ - if (eep_config.termination == 1) { - asc_dvc->cfg->termination = TERM_CTL_SEL; - - /* Enable manual control with low off / high on. */ - } else if (eep_config.termination == 2) { - asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H; - - /* Enable manual control with low on / high on. */ - } else if (eep_config.termination == 3) { - asc_dvc->cfg->termination = - TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L; - } else { - /* - * The EEPROM 'termination' field contains a bad value. Use - * automatic termination instead. - */ - asc_dvc->cfg->termination = 0; - warn_code |= ASC_WARN_EEPROM_TERMINATION; - } - } - - return warn_code; -} - -/* - * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and - * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while - * all of this is done. - * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - * - * Note: Chip is stopped on entry. - */ -static int __devinit AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc) -{ - AdvPortAddr iop_base; - ushort warn_code; - ADVEEP_38C0800_CONFIG eep_config; - uchar tid, termination; - ushort sdtr_speed = 0; - - iop_base = asc_dvc->iop_base; - - warn_code = 0; - - /* - * Read the board's EEPROM configuration. - * - * Set default values if a bad checksum is found. - */ - if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != - eep_config.check_sum) { - warn_code |= ASC_WARN_EEPROM_CHKSUM; - - /* - * Set EEPROM default values. - */ - memcpy(&eep_config, &Default_38C0800_EEPROM_Config, - sizeof(ADVEEP_38C0800_CONFIG)); - - /* - * Assume the 6 byte board serial number that was read from - * EEPROM is correct even if the EEPROM checksum failed. - */ - eep_config.serial_number_word3 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); - - eep_config.serial_number_word2 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); - - eep_config.serial_number_word1 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); - - AdvSet38C0800EEPConfig(iop_base, &eep_config); - } - /* - * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the - * EEPROM configuration that was read. - * - * This is the mapping of EEPROM fields to Adv Library fields. - */ - asc_dvc->wdtr_able = eep_config.wdtr_able; - asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1; - asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2; - asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3; - asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4; - asc_dvc->tagqng_able = eep_config.tagqng_able; - asc_dvc->cfg->disc_enable = eep_config.disc_enable; - asc_dvc->max_host_qng = eep_config.max_host_qng; - asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID); - asc_dvc->start_motor = eep_config.start_motor; - asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; - asc_dvc->bios_ctrl = eep_config.bios_ctrl; - asc_dvc->no_scam = eep_config.scam_tolerant; - asc_dvc->cfg->serial1 = eep_config.serial_number_word1; - asc_dvc->cfg->serial2 = eep_config.serial_number_word2; - asc_dvc->cfg->serial3 = eep_config.serial_number_word3; - - /* - * For every Target ID if any of its 'sdtr_speed[1234]' bits - * are set, then set an 'sdtr_able' bit for it. - */ - asc_dvc->sdtr_able = 0; - for (tid = 0; tid <= ADV_MAX_TID; tid++) { - if (tid == 0) { - sdtr_speed = asc_dvc->sdtr_speed1; - } else if (tid == 4) { - sdtr_speed = asc_dvc->sdtr_speed2; - } else if (tid == 8) { - sdtr_speed = asc_dvc->sdtr_speed3; - } else if (tid == 12) { - sdtr_speed = asc_dvc->sdtr_speed4; - } - if (sdtr_speed & ADV_MAX_TID) { - asc_dvc->sdtr_able |= (1 << tid); - } - sdtr_speed >>= 4; - } - - /* - * Set the host maximum queuing (max. 253, min. 16) and the per device - * maximum queuing (max. 63, min. 4). - */ - if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) { - eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; - } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) { - /* If the value is zero, assume it is uninitialized. */ - if (eep_config.max_host_qng == 0) { - eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; - } else { - eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG; - } - } - - if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) { - eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; - } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) { - /* If the value is zero, assume it is uninitialized. */ - if (eep_config.max_dvc_qng == 0) { - eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; - } else { - eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG; - } - } - - /* - * If 'max_dvc_qng' is greater than 'max_host_qng', then - * set 'max_dvc_qng' to 'max_host_qng'. - */ - if (eep_config.max_dvc_qng > eep_config.max_host_qng) { - eep_config.max_dvc_qng = eep_config.max_host_qng; - } - - /* - * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng' - * values based on possibly adjusted EEPROM values. - */ - asc_dvc->max_host_qng = eep_config.max_host_qng; - asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - - /* - * If the EEPROM 'termination' field is set to automatic (0), then set - * the ADV_DVC_CFG 'termination' field to automatic also. - * - * If the termination is specified with a non-zero 'termination' - * value check that a legal value is set and set the ADV_DVC_CFG - * 'termination' field appropriately. - */ - if (eep_config.termination_se == 0) { - termination = 0; /* auto termination for SE */ - } else { - /* Enable manual control with low off / high off. */ - if (eep_config.termination_se == 1) { - termination = 0; - - /* Enable manual control with low off / high on. */ - } else if (eep_config.termination_se == 2) { - termination = TERM_SE_HI; - - /* Enable manual control with low on / high on. */ - } else if (eep_config.termination_se == 3) { - termination = TERM_SE; - } else { - /* - * The EEPROM 'termination_se' field contains a bad value. - * Use automatic termination instead. - */ - termination = 0; - warn_code |= ASC_WARN_EEPROM_TERMINATION; - } - } - - if (eep_config.termination_lvd == 0) { - asc_dvc->cfg->termination = termination; /* auto termination for LVD */ - } else { - /* Enable manual control with low off / high off. */ - if (eep_config.termination_lvd == 1) { - asc_dvc->cfg->termination = termination; - - /* Enable manual control with low off / high on. */ - } else if (eep_config.termination_lvd == 2) { - asc_dvc->cfg->termination = termination | TERM_LVD_HI; - - /* Enable manual control with low on / high on. */ - } else if (eep_config.termination_lvd == 3) { - asc_dvc->cfg->termination = termination | TERM_LVD; - } else { - /* - * The EEPROM 'termination_lvd' field contains a bad value. - * Use automatic termination instead. - */ - asc_dvc->cfg->termination = termination; - warn_code |= ASC_WARN_EEPROM_TERMINATION; - } - } - - return warn_code; -} - -/* - * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and - * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while - * all of this is done. - * - * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - * - * Note: Chip is stopped on entry. - */ -static int __devinit AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc) -{ - AdvPortAddr iop_base; - ushort warn_code; - ADVEEP_38C1600_CONFIG eep_config; - uchar tid, termination; - ushort sdtr_speed = 0; - - iop_base = asc_dvc->iop_base; - - warn_code = 0; - - /* - * Read the board's EEPROM configuration. - * - * Set default values if a bad checksum is found. - */ - if (AdvGet38C1600EEPConfig(iop_base, &eep_config) != - eep_config.check_sum) { - struct pci_dev *pdev = adv_dvc_to_pdev(asc_dvc); - warn_code |= ASC_WARN_EEPROM_CHKSUM; - - /* - * Set EEPROM default values. - */ - memcpy(&eep_config, &Default_38C1600_EEPROM_Config, - sizeof(ADVEEP_38C1600_CONFIG)); - - if (PCI_FUNC(pdev->devfn) != 0) { - u8 ints; - /* - * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 - * and old Mac system booting problem. The Expansion - * ROM must be disabled in Function 1 for these systems - */ - eep_config.cfg_lsw &= ~ADV_EEPROM_BIOS_ENABLE; - /* - * Clear the INTAB (bit 11) if the GPIO 0 input - * indicates the Function 1 interrupt line is wired - * to INTB. - * - * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input: - * 1 - Function 1 interrupt line wired to INT A. - * 0 - Function 1 interrupt line wired to INT B. - * - * Note: Function 0 is always wired to INTA. - * Put all 5 GPIO bits in input mode and then read - * their input values. - */ - AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0); - ints = AdvReadByteRegister(iop_base, IOPB_GPIO_DATA); - if ((ints & 0x01) == 0) - eep_config.cfg_lsw &= ~ADV_EEPROM_INTAB; - } - - /* - * Assume the 6 byte board serial number that was read from - * EEPROM is correct even if the EEPROM checksum failed. - */ - eep_config.serial_number_word3 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1); - eep_config.serial_number_word2 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2); - eep_config.serial_number_word1 = - AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3); - - AdvSet38C1600EEPConfig(iop_base, &eep_config); - } - - /* - * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the - * EEPROM configuration that was read. - * - * This is the mapping of EEPROM fields to Adv Library fields. - */ - asc_dvc->wdtr_able = eep_config.wdtr_able; - asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1; - asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2; - asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3; - asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4; - asc_dvc->ppr_able = 0; - asc_dvc->tagqng_able = eep_config.tagqng_able; - asc_dvc->cfg->disc_enable = eep_config.disc_enable; - asc_dvc->max_host_qng = eep_config.max_host_qng; - asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID); - asc_dvc->start_motor = eep_config.start_motor; - asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay; - asc_dvc->bios_ctrl = eep_config.bios_ctrl; - asc_dvc->no_scam = eep_config.scam_tolerant; - - /* - * For every Target ID if any of its 'sdtr_speed[1234]' bits - * are set, then set an 'sdtr_able' bit for it. - */ - asc_dvc->sdtr_able = 0; - for (tid = 0; tid <= ASC_MAX_TID; tid++) { - if (tid == 0) { - sdtr_speed = asc_dvc->sdtr_speed1; - } else if (tid == 4) { - sdtr_speed = asc_dvc->sdtr_speed2; - } else if (tid == 8) { - sdtr_speed = asc_dvc->sdtr_speed3; - } else if (tid == 12) { - sdtr_speed = asc_dvc->sdtr_speed4; - } - if (sdtr_speed & ASC_MAX_TID) { - asc_dvc->sdtr_able |= (1 << tid); - } - sdtr_speed >>= 4; - } - - /* - * Set the host maximum queuing (max. 253, min. 16) and the per device - * maximum queuing (max. 63, min. 4). - */ - if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG) { - eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; - } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG) { - /* If the value is zero, assume it is uninitialized. */ - if (eep_config.max_host_qng == 0) { - eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG; - } else { - eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG; - } - } - - if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG) { - eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; - } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG) { - /* If the value is zero, assume it is uninitialized. */ - if (eep_config.max_dvc_qng == 0) { - eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG; - } else { - eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG; - } - } - - /* - * If 'max_dvc_qng' is greater than 'max_host_qng', then - * set 'max_dvc_qng' to 'max_host_qng'. - */ - if (eep_config.max_dvc_qng > eep_config.max_host_qng) { - eep_config.max_dvc_qng = eep_config.max_host_qng; - } - - /* - * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng' - * values based on possibly adjusted EEPROM values. - */ - asc_dvc->max_host_qng = eep_config.max_host_qng; - asc_dvc->max_dvc_qng = eep_config.max_dvc_qng; - - /* - * If the EEPROM 'termination' field is set to automatic (0), then set - * the ASC_DVC_CFG 'termination' field to automatic also. - * - * If the termination is specified with a non-zero 'termination' - * value check that a legal value is set and set the ASC_DVC_CFG - * 'termination' field appropriately. - */ - if (eep_config.termination_se == 0) { - termination = 0; /* auto termination for SE */ - } else { - /* Enable manual control with low off / high off. */ - if (eep_config.termination_se == 1) { - termination = 0; - - /* Enable manual control with low off / high on. */ - } else if (eep_config.termination_se == 2) { - termination = TERM_SE_HI; - - /* Enable manual control with low on / high on. */ - } else if (eep_config.termination_se == 3) { - termination = TERM_SE; - } else { - /* - * The EEPROM 'termination_se' field contains a bad value. - * Use automatic termination instead. - */ - termination = 0; - warn_code |= ASC_WARN_EEPROM_TERMINATION; - } - } - - if (eep_config.termination_lvd == 0) { - asc_dvc->cfg->termination = termination; /* auto termination for LVD */ - } else { - /* Enable manual control with low off / high off. */ - if (eep_config.termination_lvd == 1) { - asc_dvc->cfg->termination = termination; - - /* Enable manual control with low off / high on. */ - } else if (eep_config.termination_lvd == 2) { - asc_dvc->cfg->termination = termination | TERM_LVD_HI; - - /* Enable manual control with low on / high on. */ - } else if (eep_config.termination_lvd == 3) { - asc_dvc->cfg->termination = termination | TERM_LVD; - } else { - /* - * The EEPROM 'termination_lvd' field contains a bad value. - * Use automatic termination instead. - */ - asc_dvc->cfg->termination = termination; - warn_code |= ASC_WARN_EEPROM_TERMINATION; - } - } - - return warn_code; -} - -/* - * Initialize the ADV_DVC_VAR structure. - * - * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR. - * - * For a non-fatal error return a warning code. If there are no warnings - * then 0 is returned. - */ -static int __devinit -AdvInitGetConfig(struct pci_dev *pdev, struct Scsi_Host *shost) -{ - struct asc_board *board = shost_priv(shost); - ADV_DVC_VAR *asc_dvc = &board->dvc_var.adv_dvc_var; - unsigned short warn_code = 0; - AdvPortAddr iop_base = asc_dvc->iop_base; - u16 cmd; - int status; - - asc_dvc->err_code = 0; - - /* - * Save the state of the PCI Configuration Command Register - * "Parity Error Response Control" Bit. If the bit is clear (0), - * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore - * DMA parity errors. - */ - asc_dvc->cfg->control_flag = 0; - pci_read_config_word(pdev, PCI_COMMAND, &cmd); - if ((cmd & PCI_COMMAND_PARITY) == 0) - asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR; - - asc_dvc->cfg->chip_version = - AdvGetChipVersion(iop_base, asc_dvc->bus_type); - - ASC_DBG(1, "iopb_chip_id_1: 0x%x 0x%x\n", - (ushort)AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1), - (ushort)ADV_CHIP_ID_BYTE); - - ASC_DBG(1, "iopw_chip_id_0: 0x%x 0x%x\n", - (ushort)AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0), - (ushort)ADV_CHIP_ID_WORD); - - /* - * Reset the chip to start and allow register writes. - */ - if (AdvFindSignature(iop_base) == 0) { - asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE; - return ADV_ERROR; - } else { - /* - * The caller must set 'chip_type' to a valid setting. - */ - if (asc_dvc->chip_type != ADV_CHIP_ASC3550 && - asc_dvc->chip_type != ADV_CHIP_ASC38C0800 && - asc_dvc->chip_type != ADV_CHIP_ASC38C1600) { - asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE; - return ADV_ERROR; - } - - /* - * Reset Chip. - */ - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, - ADV_CTRL_REG_CMD_RESET); - mdelay(100); - AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, - ADV_CTRL_REG_CMD_WR_IO_REG); - - if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600) { - status = AdvInitFrom38C1600EEP(asc_dvc); - } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800) { - status = AdvInitFrom38C0800EEP(asc_dvc); - } else { - status = AdvInitFrom3550EEP(asc_dvc); - } - warn_code |= status; - } - - if (warn_code != 0) - shost_printk(KERN_WARNING, shost, "warning: 0x%x\n", warn_code); - - if (asc_dvc->err_code) - shost_printk(KERN_ERR, shost, "error code 0x%x\n", - asc_dvc->err_code); - - return asc_dvc->err_code; -} -#endif - -static struct scsi_host_template advansys_template = { - .proc_name = DRV_NAME, -#ifdef CONFIG_PROC_FS - .proc_info = advansys_proc_info, -#endif - .name = DRV_NAME, - .info = advansys_info, - .queuecommand = advansys_queuecommand, - .eh_bus_reset_handler = advansys_reset, - .bios_param = advansys_biosparam, - .slave_configure = advansys_slave_configure, - /* - * Because the driver may control an ISA adapter 'unchecked_isa_dma' - * must be set. The flag will be cleared in advansys_board_found - * for non-ISA adapters. - */ - .unchecked_isa_dma = 1, - /* - * All adapters controlled by this driver are capable of large - * scatter-gather lists. According to the mid-level SCSI documentation - * this obviates any performance gain provided by setting - * 'use_clustering'. But empirically while CPU utilization is increased - * by enabling clustering, I/O throughput increases as well. - */ - .use_clustering = ENABLE_CLUSTERING, -}; - -static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost) -{ - struct asc_board *board = shost_priv(shost); - struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var; - int req_cnt = 0; - adv_req_t *reqp = NULL; - int sg_cnt = 0; - adv_sgblk_t *sgp; - int warn_code, err_code; - - /* - * Allocate buffer carrier structures. The total size - * is about 4 KB, so allocate all at once. - */ - adv_dvc->carrier_buf = kmalloc(ADV_CARRIER_BUFSIZE, GFP_KERNEL); - ASC_DBG(1, "carrier_buf 0x%p\n", adv_dvc->carrier_buf); - - if (!adv_dvc->carrier_buf) - goto kmalloc_failed; - - /* - * Allocate up to 'max_host_qng' request structures for the Wide - * board. The total size is about 16 KB, so allocate all at once. - * If the allocation fails decrement and try again. - */ - for (req_cnt = adv_dvc->max_host_qng; req_cnt > 0; req_cnt--) { - reqp = kmalloc(sizeof(adv_req_t) * req_cnt, GFP_KERNEL); - - ASC_DBG(1, "reqp 0x%p, req_cnt %d, bytes %lu\n", reqp, req_cnt, - (ulong)sizeof(adv_req_t) * req_cnt); - - if (reqp) - break; - } - - if (!reqp) - goto kmalloc_failed; - - adv_dvc->orig_reqp = reqp; - - /* - * Allocate up to ADV_TOT_SG_BLOCK request structures for - * the Wide board. Each structure is about 136 bytes. - */ - board->adv_sgblkp = NULL; - for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) { - sgp = kmalloc(sizeof(adv_sgblk_t), GFP_KERNEL); - - if (!sgp) - break; - - sgp->next_sgblkp = board->adv_sgblkp; - board->adv_sgblkp = sgp; - - } - - ASC_DBG(1, "sg_cnt %d * %lu = %lu bytes\n", sg_cnt, sizeof(adv_sgblk_t), - sizeof(adv_sgblk_t) * sg_cnt); - - if (!board->adv_sgblkp) - goto kmalloc_failed; - - /* - * Point 'adv_reqp' to the request structures and - * link them together. - */ - req_cnt--; - reqp[req_cnt].next_reqp = NULL; - for (; req_cnt > 0; req_cnt--) { - reqp[req_cnt - 1].next_reqp = &reqp[req_cnt]; - } - board->adv_reqp = &reqp[0]; - - if (adv_dvc->chip_type == ADV_CHIP_ASC3550) { - ASC_DBG(2, "AdvInitAsc3550Driver()\n"); - warn_code = AdvInitAsc3550Driver(adv_dvc); - } else if (adv_dvc->chip_type == ADV_CHIP_ASC38C0800) { - ASC_DBG(2, "AdvInitAsc38C0800Driver()\n"); - warn_code = AdvInitAsc38C0800Driver(adv_dvc); - } else { - ASC_DBG(2, "AdvInitAsc38C1600Driver()\n"); - warn_code = AdvInitAsc38C1600Driver(adv_dvc); - } - err_code = adv_dvc->err_code; - - if (warn_code || err_code) { - shost_printk(KERN_WARNING, shost, "error: warn 0x%x, error " - "0x%x\n", warn_code, err_code); - } - - goto exit; - - kmalloc_failed: - shost_printk(KERN_ERR, shost, "error: kmalloc() failed\n"); - err_code = ADV_ERROR; - exit: - return err_code; -} - -static void advansys_wide_free_mem(struct asc_board *board) -{ - struct adv_dvc_var *adv_dvc = &board->dvc_var.adv_dvc_var; - kfree(adv_dvc->carrier_buf); - adv_dvc->carrier_buf = NULL; - kfree(adv_dvc->orig_reqp); - adv_dvc->orig_reqp = board->adv_reqp = NULL; - while (board->adv_sgblkp) { - adv_sgblk_t *sgp = board->adv_sgblkp; - board->adv_sgblkp = sgp->next_sgblkp; - kfree(sgp); - } -} - -static int __devinit advansys_board_found(struct Scsi_Host *shost, - unsigned int iop, int bus_type) -{ - struct pci_dev *pdev; - struct asc_board *boardp = shost_priv(shost); - ASC_DVC_VAR *asc_dvc_varp = NULL; - ADV_DVC_VAR *adv_dvc_varp = NULL; - int share_irq, warn_code, ret; - - pdev = (bus_type == ASC_IS_PCI) ? to_pci_dev(boardp->dev) : NULL; - - if (ASC_NARROW_BOARD(boardp)) { - ASC_DBG(1, "narrow board\n"); - asc_dvc_varp = &boardp->dvc_var.asc_dvc_var; - asc_dvc_varp->bus_type = bus_type; - asc_dvc_varp->drv_ptr = boardp; - asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg; - asc_dvc_varp->iop_base = iop; - } else { -#ifdef CONFIG_PCI - adv_dvc_varp = &boardp->dvc_var.adv_dvc_var; - adv_dvc_varp->drv_ptr = boardp; - adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg; - if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW) { - ASC_DBG(1, "wide board ASC-3550\n"); - adv_dvc_varp->chip_type = ADV_CHIP_ASC3550; - } else if (pdev->device == PCI_DEVICE_ID_38C0800_REV1) { - ASC_DBG(1, "wide board ASC-38C0800\n"); - adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800; - } else { - ASC_DBG(1, "wide board ASC-38C1600\n"); - adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600; - } - - boardp->asc_n_io_port = pci_resource_len(pdev, 1); - boardp->ioremap_addr = pci_ioremap_bar(pdev, 1); - if (!boardp->ioremap_addr) { - shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) " - "returned NULL\n", - (long)pci_resource_start(pdev, 1), - boardp->asc_n_io_port); - ret = -ENODEV; - goto err_shost; - } - adv_dvc_varp->iop_base = (AdvPortAddr)boardp->ioremap_addr; - ASC_DBG(1, "iop_base: 0x%p\n", adv_dvc_varp->iop_base); - - /* - * Even though it isn't used to access wide boards, other - * than for the debug line below, save I/O Port address so - * that it can be reported. - */ - boardp->ioport = iop; - - ASC_DBG(1, "iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n", - (ushort)inp(iop + 1), (ushort)inpw(iop)); -#endif /* CONFIG_PCI */ - } - -#ifdef CONFIG_PROC_FS - /* - * Allocate buffer for printing information from - * /proc/scsi/advansys/[0...]. - */ - boardp->prtbuf = kmalloc(ASC_PRTBUF_SIZE, GFP_KERNEL); - if (!boardp->prtbuf) { - shost_printk(KERN_ERR, shost, "kmalloc(%d) returned NULL\n", - ASC_PRTBUF_SIZE); - ret = -ENOMEM; - goto err_unmap; - } -#endif /* CONFIG_PROC_FS */ - - if (ASC_NARROW_BOARD(boardp)) { - /* - * Set the board bus type and PCI IRQ before - * calling AscInitGetConfig(). - */ - switch (asc_dvc_varp->bus_type) { -#ifdef CONFIG_ISA - case ASC_IS_ISA: - shost->unchecked_isa_dma = TRUE; - share_irq = 0; - break; - case ASC_IS_VL: - shost->unchecked_isa_dma = FALSE; - share_irq = 0; - break; - case ASC_IS_EISA: - shost->unchecked_isa_dma = FALSE; - share_irq = IRQF_SHARED; - break; -#endif /* CONFIG_ISA */ -#ifdef CONFIG_PCI - case ASC_IS_PCI: - shost->unchecked_isa_dma = FALSE; - share_irq = IRQF_SHARED; - break; -#endif /* CONFIG_PCI */ - default: - shost_printk(KERN_ERR, shost, "unknown adapter type: " - "%d\n", asc_dvc_varp->bus_type); - shost->unchecked_isa_dma = TRUE; - share_irq = 0; - break; - } - - /* - * NOTE: AscInitGetConfig() may change the board's - * bus_type value. The bus_type value should no - * longer be used. If the bus_type field must be - * referenced only use the bit-wise AND operator "&". - */ - ASC_DBG(2, "AscInitGetConfig()\n"); - ret = AscInitGetConfig(shost) ? -ENODEV : 0; - } else { -#ifdef CONFIG_PCI - /* - * For Wide boards set PCI information before calling - * AdvInitGetConfig(). - */ - shost->unchecked_isa_dma = FALSE; - share_irq = IRQF_SHARED; - ASC_DBG(2, "AdvInitGetConfig()\n"); - - ret = AdvInitGetConfig(pdev, shost) ? -ENODEV : 0; -#endif /* CONFIG_PCI */ - } - - if (ret) - goto err_free_proc; - - /* - * Save the EEPROM configuration so that it can be displayed - * from /proc/scsi/advansys/[0...]. - */ - if (ASC_NARROW_BOARD(boardp)) { - - ASCEEP_CONFIG *ep; - - /* - * Set the adapter's target id bit in the 'init_tidmask' field. - */ - boardp->init_tidmask |= - ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id); - - /* - * Save EEPROM settings for the board. - */ - ep = &boardp->eep_config.asc_eep; - - ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable; - ep->disc_enable = asc_dvc_varp->cfg->disc_enable; - ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled; - ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed); - ep->start_motor = asc_dvc_varp->start_motor; - ep->cntl = asc_dvc_varp->dvc_cntl; - ep->no_scam = asc_dvc_varp->no_scam; - ep->max_total_qng = asc_dvc_varp->max_total_qng; - ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id); - /* 'max_tag_qng' is set to the same value for every device. */ - ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0]; - ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0]; - ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1]; - ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2]; - ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3]; - ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4]; - ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5]; - - /* - * Modify board configuration. - */ - ASC_DBG(2, "AscInitSetConfig()\n"); - ret = AscInitSetConfig(pdev, shost) ? -ENODEV : 0; - if (ret) - goto err_free_proc; - } else { - ADVEEP_3550_CONFIG *ep_3550; - ADVEEP_38C0800_CONFIG *ep_38C0800; - ADVEEP_38C1600_CONFIG *ep_38C1600; - - /* - * Save Wide EEP Configuration Information. - */ - if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) { - ep_3550 = &boardp->eep_config.adv_3550_eep; - - ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id; - ep_3550->max_host_qng = adv_dvc_varp->max_host_qng; - ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng; - ep_3550->termination = adv_dvc_varp->cfg->termination; - ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable; - ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl; - ep_3550->wdtr_able = adv_dvc_varp->wdtr_able; - ep_3550->sdtr_able = adv_dvc_varp->sdtr_able; - ep_3550->ultra_able = adv_dvc_varp->ultra_able; - ep_3550->tagqng_able = adv_dvc_varp->tagqng_able; - ep_3550->start_motor = adv_dvc_varp->start_motor; - ep_3550->scsi_reset_delay = - adv_dvc_varp->scsi_reset_wait; - ep_3550->serial_number_word1 = - adv_dvc_varp->cfg->serial1; - ep_3550->serial_number_word2 = - adv_dvc_varp->cfg->serial2; - ep_3550->serial_number_word3 = - adv_dvc_varp->cfg->serial3; - } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) { - ep_38C0800 = &boardp->eep_config.adv_38C0800_eep; - - ep_38C0800->adapter_scsi_id = - adv_dvc_varp->chip_scsi_id; - ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng; - ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng; - ep_38C0800->termination_lvd = - adv_dvc_varp->cfg->termination; - ep_38C0800->disc_enable = - adv_dvc_varp->cfg->disc_enable; - ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl; - ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able; - ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able; - ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1; - ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2; - ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3; - ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4; - ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able; - ep_38C0800->start_motor = adv_dvc_varp->start_motor; - ep_38C0800->scsi_reset_delay = - adv_dvc_varp->scsi_reset_wait; - ep_38C0800->serial_number_word1 = - adv_dvc_varp->cfg->serial1; - ep_38C0800->serial_number_word2 = - adv_dvc_varp->cfg->serial2; - ep_38C0800->serial_number_word3 = - adv_dvc_varp->cfg->serial3; - } else { - ep_38C1600 = &boardp->eep_config.adv_38C1600_eep; - - ep_38C1600->adapter_scsi_id = - adv_dvc_varp->chip_scsi_id; - ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng; - ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng; - ep_38C1600->termination_lvd = - adv_dvc_varp->cfg->termination; - ep_38C1600->disc_enable = - adv_dvc_varp->cfg->disc_enable; - ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl; - ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able; - ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able; - ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1; - ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2; - ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3; - ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4; - ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able; - ep_38C1600->start_motor = adv_dvc_varp->start_motor; - ep_38C1600->scsi_reset_delay = - adv_dvc_varp->scsi_reset_wait; - ep_38C1600->serial_number_word1 = - adv_dvc_varp->cfg->serial1; - ep_38C1600->serial_number_word2 = - adv_dvc_varp->cfg->serial2; - ep_38C1600->serial_number_word3 = - adv_dvc_varp->cfg->serial3; - } - - /* - * Set the adapter's target id bit in the 'init_tidmask' field. - */ - boardp->init_tidmask |= - ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id); - } - - /* - * Channels are numbered beginning with 0. For AdvanSys one host - * structure supports one channel. Multi-channel boards have a - * separate host structure for each channel. - */ - shost->max_channel = 0; - if (ASC_NARROW_BOARD(boardp)) { - shost->max_id = ASC_MAX_TID + 1; - shost->max_lun = ASC_MAX_LUN + 1; - shost->max_cmd_len = ASC_MAX_CDB_LEN; - - shost->io_port = asc_dvc_varp->iop_base; - boardp->asc_n_io_port = ASC_IOADR_GAP; - shost->this_id = asc_dvc_varp->cfg->chip_scsi_id; - - /* Set maximum number of queues the adapter can handle. */ - shost->can_queue = asc_dvc_varp->max_total_qng; - } else { - shost->max_id = ADV_MAX_TID + 1; - shost->max_lun = ADV_MAX_LUN + 1; - shost->max_cmd_len = ADV_MAX_CDB_LEN; - - /* - * Save the I/O Port address and length even though - * I/O ports are not used to access Wide boards. - * Instead the Wide boards are accessed with - * PCI Memory Mapped I/O. - */ - shost->io_port = iop; - - shost->this_id = adv_dvc_varp->chip_scsi_id; - - /* Set maximum number of queues the adapter can handle. */ - shost->can_queue = adv_dvc_varp->max_host_qng; - } - - /* - * Following v1.3.89, 'cmd_per_lun' is no longer needed - * and should be set to zero. - * - * But because of a bug introduced in v1.3.89 if the driver is - * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level - * SCSI function 'allocate_device' will panic. To allow the driver - * to work as a module in these kernels set 'cmd_per_lun' to 1. - * - * Note: This is wrong. cmd_per_lun should be set to the depth - * you want on untagged devices always. - #ifdef MODULE - */ - shost->cmd_per_lun = 1; -/* #else - shost->cmd_per_lun = 0; -#endif */ - - /* - * Set the maximum number of scatter-gather elements the - * adapter can handle. - */ - if (ASC_NARROW_BOARD(boardp)) { - /* - * Allow two commands with 'sg_tablesize' scatter-gather - * elements to be executed simultaneously. This value is - * the theoretical hardware limit. It may be decreased - * below. - */ - shost->sg_tablesize = - (((asc_dvc_varp->max_total_qng - 2) / 2) * - ASC_SG_LIST_PER_Q) + 1; - } else { - shost->sg_tablesize = ADV_MAX_SG_LIST; - } - - /* - * The value of 'sg_tablesize' can not exceed the SCSI - * mid-level driver definition of SG_ALL. SG_ALL also - * must not be exceeded, because it is used to define the - * size of the scatter-gather table in 'struct asc_sg_head'. - */ - if (shost->sg_tablesize > SG_ALL) { - shost->sg_tablesize = SG_ALL; - } - - ASC_DBG(1, "sg_tablesize: %d\n", shost->sg_tablesize); - - /* BIOS start address. */ - if (ASC_NARROW_BOARD(boardp)) { - shost->base = AscGetChipBiosAddress(asc_dvc_varp->iop_base, - asc_dvc_varp->bus_type); - } else { - /* - * Fill-in BIOS board variables. The Wide BIOS saves - * information in LRAM that is used by the driver. - */ - AdvReadWordLram(adv_dvc_varp->iop_base, - BIOS_SIGNATURE, boardp->bios_signature); - AdvReadWordLram(adv_dvc_varp->iop_base, - BIOS_VERSION, boardp->bios_version); - AdvReadWordLram(adv_dvc_varp->iop_base, - BIOS_CODESEG, boardp->bios_codeseg); - AdvReadWordLram(adv_dvc_varp->iop_base, - BIOS_CODELEN, boardp->bios_codelen); - - ASC_DBG(1, "bios_signature 0x%x, bios_version 0x%x\n", - boardp->bios_signature, boardp->bios_version); - - ASC_DBG(1, "bios_codeseg 0x%x, bios_codelen 0x%x\n", - boardp->bios_codeseg, boardp->bios_codelen); - - /* - * If the BIOS saved a valid signature, then fill in - * the BIOS code segment base address. - */ - if (boardp->bios_signature == 0x55AA) { - /* - * Convert x86 realmode code segment to a linear - * address by shifting left 4. - */ - shost->base = ((ulong)boardp->bios_codeseg << 4); - } else { - shost->base = 0; - } - } - - /* - * Register Board Resources - I/O Port, DMA, IRQ - */ - - /* Register DMA Channel for Narrow boards. */ - shost->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */ -#ifdef CONFIG_ISA - if (ASC_NARROW_BOARD(boardp)) { - /* Register DMA channel for ISA bus. */ - if (asc_dvc_varp->bus_type & ASC_IS_ISA) { - shost->dma_channel = asc_dvc_varp->cfg->isa_dma_channel; - ret = request_dma(shost->dma_channel, DRV_NAME); - if (ret) { - shost_printk(KERN_ERR, shost, "request_dma() " - "%d failed %d\n", - shost->dma_channel, ret); - goto err_free_proc; - } - AscEnableIsaDma(shost->dma_channel); - } - } -#endif /* CONFIG_ISA */ - - /* Register IRQ Number. */ - ASC_DBG(2, "request_irq(%d, %p)\n", boardp->irq, shost); - - ret = request_irq(boardp->irq, advansys_interrupt, share_irq, - DRV_NAME, shost); - - if (ret) { - if (ret == -EBUSY) { - shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x " - "already in use\n", boardp->irq); - } else if (ret == -EINVAL) { - shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x " - "not valid\n", boardp->irq); - } else { - shost_printk(KERN_ERR, shost, "request_irq(): IRQ 0x%x " - "failed with %d\n", boardp->irq, ret); - } - goto err_free_dma; - } - - /* - * Initialize board RISC chip and enable interrupts. - */ - if (ASC_NARROW_BOARD(boardp)) { - ASC_DBG(2, "AscInitAsc1000Driver()\n"); - - asc_dvc_varp->overrun_buf = kzalloc(ASC_OVERRUN_BSIZE, GFP_KERNEL); - if (!asc_dvc_varp->overrun_buf) { - ret = -ENOMEM; - goto err_free_irq; - } - warn_code = AscInitAsc1000Driver(asc_dvc_varp); - - if (warn_code || asc_dvc_varp->err_code) { - shost_printk(KERN_ERR, shost, "error: init_state 0x%x, " - "warn 0x%x, error 0x%x\n", - asc_dvc_varp->init_state, warn_code, - asc_dvc_varp->err_code); - if (!asc_dvc_varp->overrun_dma) { - ret = -ENODEV; - goto err_free_mem; - } - } - } else { - if (advansys_wide_init_chip(shost)) { - ret = -ENODEV; - goto err_free_mem; - } - } - - ASC_DBG_PRT_SCSI_HOST(2, shost); - - ret = scsi_add_host(shost, boardp->dev); - if (ret) - goto err_free_mem; - - scsi_scan_host(shost); - return 0; - - err_free_mem: - if (ASC_NARROW_BOARD(boardp)) { - if (asc_dvc_varp->overrun_dma) - dma_unmap_single(boardp->dev, asc_dvc_varp->overrun_dma, - ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); - kfree(asc_dvc_varp->overrun_buf); - } else - advansys_wide_free_mem(boardp); - err_free_irq: - free_irq(boardp->irq, shost); - err_free_dma: -#ifdef CONFIG_ISA - if (shost->dma_channel != NO_ISA_DMA) - free_dma(shost->dma_channel); -#endif - err_free_proc: - kfree(boardp->prtbuf); - err_unmap: - if (boardp->ioremap_addr) - iounmap(boardp->ioremap_addr); - err_shost: - return ret; -} - -/* - * advansys_release() - * - * Release resources allocated for a single AdvanSys adapter. - */ -static int advansys_release(struct Scsi_Host *shost) -{ - struct asc_board *board = shost_priv(shost); - ASC_DBG(1, "begin\n"); - scsi_remove_host(shost); - free_irq(board->irq, shost); -#ifdef CONFIG_ISA - if (shost->dma_channel != NO_ISA_DMA) { - ASC_DBG(1, "free_dma()\n"); - free_dma(shost->dma_channel); - } -#endif - if (ASC_NARROW_BOARD(board)) { - dma_unmap_single(board->dev, - board->dvc_var.asc_dvc_var.overrun_dma, - ASC_OVERRUN_BSIZE, DMA_FROM_DEVICE); - kfree(board->dvc_var.asc_dvc_var.overrun_buf); - } else { - iounmap(board->ioremap_addr); - advansys_wide_free_mem(board); - } - kfree(board->prtbuf); - scsi_host_put(shost); - ASC_DBG(1, "end\n"); - return 0; -} - -#define ASC_IOADR_TABLE_MAX_IX 11 - -static PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] = { - 0x100, 0x0110, 0x120, 0x0130, 0x140, 0x0150, 0x0190, - 0x0210, 0x0230, 0x0250, 0x0330 -}; - -/* - * The ISA IRQ number is found in bits 2 and 3 of the CfgLsw. It decodes as: - * 00: 10 - * 01: 11 - * 10: 12 - * 11: 15 - */ -static unsigned int __devinit advansys_isa_irq_no(PortAddr iop_base) -{ - unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base); - unsigned int chip_irq = ((cfg_lsw >> 2) & 0x03) + 10; - if (chip_irq == 13) - chip_irq = 15; - return chip_irq; -} - -static int __devinit advansys_isa_probe(struct device *dev, unsigned int id) -{ - int err = -ENODEV; - PortAddr iop_base = _asc_def_iop_base[id]; - struct Scsi_Host *shost; - struct asc_board *board; - - if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) { - ASC_DBG(1, "I/O port 0x%x busy\n", iop_base); - return -ENODEV; - } - ASC_DBG(1, "probing I/O port 0x%x\n", iop_base); - if (!AscFindSignature(iop_base)) - goto release_region; - if (!(AscGetChipVersion(iop_base, ASC_IS_ISA) & ASC_CHIP_VER_ISA_BIT)) - goto release_region; - - err = -ENOMEM; - shost = scsi_host_alloc(&advansys_template, sizeof(*board)); - if (!shost) - goto release_region; - - board = shost_priv(shost); - board->irq = advansys_isa_irq_no(iop_base); - board->dev = dev; - - err = advansys_board_found(shost, iop_base, ASC_IS_ISA); - if (err) - goto free_host; - - dev_set_drvdata(dev, shost); - return 0; - - free_host: - scsi_host_put(shost); - release_region: - release_region(iop_base, ASC_IOADR_GAP); - return err; -} - -static int __devexit advansys_isa_remove(struct device *dev, unsigned int id) -{ - int ioport = _asc_def_iop_base[id]; - advansys_release(dev_get_drvdata(dev)); - release_region(ioport, ASC_IOADR_GAP); - return 0; -} - -static struct isa_driver advansys_isa_driver = { - .probe = advansys_isa_probe, - .remove = __devexit_p(advansys_isa_remove), - .driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - }, -}; - -/* - * The VLB IRQ number is found in bits 2 to 4 of the CfgLsw. It decodes as: - * 000: invalid - * 001: 10 - * 010: 11 - * 011: 12 - * 100: invalid - * 101: 14 - * 110: 15 - * 111: invalid - */ -static unsigned int __devinit advansys_vlb_irq_no(PortAddr iop_base) -{ - unsigned short cfg_lsw = AscGetChipCfgLsw(iop_base); - unsigned int chip_irq = ((cfg_lsw >> 2) & 0x07) + 9; - if ((chip_irq < 10) || (chip_irq == 13) || (chip_irq > 15)) - return 0; - return chip_irq; -} - -static int __devinit advansys_vlb_probe(struct device *dev, unsigned int id) -{ - int err = -ENODEV; - PortAddr iop_base = _asc_def_iop_base[id]; - struct Scsi_Host *shost; - struct asc_board *board; - - if (!request_region(iop_base, ASC_IOADR_GAP, DRV_NAME)) { - ASC_DBG(1, "I/O port 0x%x busy\n", iop_base); - return -ENODEV; - } - ASC_DBG(1, "probing I/O port 0x%x\n", iop_base); - if (!AscFindSignature(iop_base)) - goto release_region; - /* - * I don't think this condition can actually happen, but the old - * driver did it, and the chances of finding a VLB setup in 2007 - * to do testing with is slight to none. - */ - if (AscGetChipVersion(iop_base, ASC_IS_VL) > ASC_CHIP_MAX_VER_VL) - goto release_region; - - err = -ENOMEM; - shost = scsi_host_alloc(&advansys_template, sizeof(*board)); - if (!shost) - goto release_region; - - board = shost_priv(shost); - board->irq = advansys_vlb_irq_no(iop_base); - board->dev = dev; - - err = advansys_board_found(shost, iop_base, ASC_IS_VL); - if (err) - goto free_host; - - dev_set_drvdata(dev, shost); - return 0; - - free_host: - scsi_host_put(shost); - release_region: - release_region(iop_base, ASC_IOADR_GAP); - return -ENODEV; -} - -static struct isa_driver advansys_vlb_driver = { - .probe = advansys_vlb_probe, - .remove = __devexit_p(advansys_isa_remove), - .driver = { - .owner = THIS_MODULE, - .name = "advansys_vlb", - }, -}; - -static struct eisa_device_id advansys_eisa_table[] __devinitdata = { - { "ABP7401" }, - { "ABP7501" }, - { "" } -}; - -MODULE_DEVICE_TABLE(eisa, advansys_eisa_table); - -/* - * EISA is a little more tricky than PCI; each EISA device may have two - * channels, and this driver is written to make each channel its own Scsi_Host - */ -struct eisa_scsi_data { - struct Scsi_Host *host[2]; -}; - -/* - * The EISA IRQ number is found in bits 8 to 10 of the CfgLsw. It decodes as: - * 000: 10 - * 001: 11 - * 010: 12 - * 011: invalid - * 100: 14 - * 101: 15 - * 110: invalid - * 111: invalid - */ -static unsigned int __devinit advansys_eisa_irq_no(struct eisa_device *edev) -{ - unsigned short cfg_lsw = inw(edev->base_addr + 0xc86); - unsigned int chip_irq = ((cfg_lsw >> 8) & 0x07) + 10; - if ((chip_irq == 13) || (chip_irq > 15)) - return 0; - return chip_irq; -} - -static int __devinit advansys_eisa_probe(struct device *dev) -{ - int i, ioport, irq = 0; - int err; - struct eisa_device *edev = to_eisa_device(dev); - struct eisa_scsi_data *data; - - err = -ENOMEM; - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - goto fail; - ioport = edev->base_addr + 0xc30; - - err = -ENODEV; - for (i = 0; i < 2; i++, ioport += 0x20) { - struct asc_board *board; - struct Scsi_Host *shost; - if (!request_region(ioport, ASC_IOADR_GAP, DRV_NAME)) { - printk(KERN_WARNING "Region %x-%x busy\n", ioport, - ioport + ASC_IOADR_GAP - 1); - continue; - } - if (!AscFindSignature(ioport)) { - release_region(ioport, ASC_IOADR_GAP); - continue; - } - - /* - * I don't know why we need to do this for EISA chips, but - * not for any others. It looks to be equivalent to - * AscGetChipCfgMsw, but I may have overlooked something, - * so I'm not converting it until I get an EISA board to - * test with. - */ - inw(ioport + 4); - - if (!irq) - irq = advansys_eisa_irq_no(edev); - - err = -ENOMEM; - shost = scsi_host_alloc(&advansys_template, sizeof(*board)); - if (!shost) - goto release_region; - - board = shost_priv(shost); - board->irq = irq; - board->dev = dev; - - err = advansys_board_found(shost, ioport, ASC_IS_EISA); - if (!err) { - data->host[i] = shost; - continue; - } - - scsi_host_put(shost); - release_region: - release_region(ioport, ASC_IOADR_GAP); - break; - } - - if (err) - goto free_data; - dev_set_drvdata(dev, data); - return 0; - - free_data: - kfree(data->host[0]); - kfree(data->host[1]); - kfree(data); - fail: - return err; -} - -static __devexit int advansys_eisa_remove(struct device *dev) -{ - int i; - struct eisa_scsi_data *data = dev_get_drvdata(dev); - - for (i = 0; i < 2; i++) { - int ioport; - struct Scsi_Host *shost = data->host[i]; - if (!shost) - continue; - ioport = shost->io_port; - advansys_release(shost); - release_region(ioport, ASC_IOADR_GAP); - } - - kfree(data); - return 0; -} - -static struct eisa_driver advansys_eisa_driver = { - .id_table = advansys_eisa_table, - .driver = { - .name = DRV_NAME, - .probe = advansys_eisa_probe, - .remove = __devexit_p(advansys_eisa_remove), - } -}; - -/* PCI Devices supported by this driver */ -static struct pci_device_id advansys_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_1200A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940U, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_ASP_ABP940UW, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C0800_REV1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_ASP, PCI_DEVICE_ID_38C1600_REV1, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {} -}; - -MODULE_DEVICE_TABLE(pci, advansys_pci_tbl); - -static void __devinit advansys_set_latency(struct pci_dev *pdev) -{ - if ((pdev->device == PCI_DEVICE_ID_ASP_1200A) || - (pdev->device == PCI_DEVICE_ID_ASP_ABP940)) { - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0); - } else { - u8 latency; - pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &latency); - if (latency < 0x20) - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x20); - } -} - -static int __devinit -advansys_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - int err, ioport; - struct Scsi_Host *shost; - struct asc_board *board; - - err = pci_enable_device(pdev); - if (err) - goto fail; - err = pci_request_regions(pdev, DRV_NAME); - if (err) - goto disable_device; - pci_set_master(pdev); - advansys_set_latency(pdev); - - err = -ENODEV; - if (pci_resource_len(pdev, 0) == 0) - goto release_region; - - ioport = pci_resource_start(pdev, 0); - - err = -ENOMEM; - shost = scsi_host_alloc(&advansys_template, sizeof(*board)); - if (!shost) - goto release_region; - - board = shost_priv(shost); - board->irq = pdev->irq; - board->dev = &pdev->dev; - - if (pdev->device == PCI_DEVICE_ID_ASP_ABP940UW || - pdev->device == PCI_DEVICE_ID_38C0800_REV1 || - pdev->device == PCI_DEVICE_ID_38C1600_REV1) { - board->flags |= ASC_IS_WIDE_BOARD; - } - - err = advansys_board_found(shost, ioport, ASC_IS_PCI); - if (err) - goto free_host; - - pci_set_drvdata(pdev, shost); - return 0; - - free_host: - scsi_host_put(shost); - release_region: - pci_release_regions(pdev); - disable_device: - pci_disable_device(pdev); - fail: - return err; -} - -static void __devexit advansys_pci_remove(struct pci_dev *pdev) -{ - advansys_release(pci_get_drvdata(pdev)); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static struct pci_driver advansys_pci_driver = { - .name = DRV_NAME, - .id_table = advansys_pci_tbl, - .probe = advansys_pci_probe, - .remove = __devexit_p(advansys_pci_remove), -}; - -static int __init advansys_init(void) -{ - int error; - - error = isa_register_driver(&advansys_isa_driver, - ASC_IOADR_TABLE_MAX_IX); - if (error) - goto fail; - - error = isa_register_driver(&advansys_vlb_driver, - ASC_IOADR_TABLE_MAX_IX); - if (error) - goto unregister_isa; - - error = eisa_driver_register(&advansys_eisa_driver); - if (error) - goto unregister_vlb; - - error = pci_register_driver(&advansys_pci_driver); - if (error) - goto unregister_eisa; - - return 0; - - unregister_eisa: - eisa_driver_unregister(&advansys_eisa_driver); - unregister_vlb: - isa_unregister_driver(&advansys_vlb_driver); - unregister_isa: - isa_unregister_driver(&advansys_isa_driver); - fail: - return error; -} - -static void __exit advansys_exit(void) -{ - pci_unregister_driver(&advansys_pci_driver); - eisa_driver_unregister(&advansys_eisa_driver); - isa_unregister_driver(&advansys_vlb_driver); - isa_unregister_driver(&advansys_isa_driver); -} - -module_init(advansys_init); -module_exit(advansys_exit); - -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("advansys/mcode.bin"); -MODULE_FIRMWARE("advansys/3550.bin"); -MODULE_FIRMWARE("advansys/38C0800.bin"); -MODULE_FIRMWARE("advansys/38C1600.bin"); diff --git a/ANDROID_3.4.5/drivers/scsi/aha152x.c b/ANDROID_3.4.5/drivers/scsi/aha152x.c deleted file mode 100644 index 19a36945..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aha152x.c +++ /dev/null @@ -1,3984 +0,0 @@ -/* aha152x.c -- Adaptec AHA-152x driver - * Author: Jürgen E. Fischer, fischer@norbit.de - * Copyright 1993-2004 Jürgen E. Fischer - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * - * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $ - * - * $Log: aha152x.c,v $ - * Revision 2.7 2004/01/24 11:42:59 fischer - * - gather code that is not used by PCMCIA at the end - * - move request_region for !PCMCIA case to detection - * - migration to new scsi host api (remove legacy code) - * - free host scribble before scsi_done - * - fix error handling - * - one isapnp device added to id_table - * - * Revision 2.6 2003/10/30 20:52:47 fischer - * - interfaces changes for kernel 2.6 - * - aha152x_probe_one introduced for pcmcia stub - * - fixed pnpdev handling - * - instead of allocation a new one, reuse command for request sense after check condition and reset - * - fixes race in is_complete - * - * Revision 2.5 2002/04/14 11:24:53 fischer - * - isapnp support - * - abort fixed - * - 2.5 support - * - * Revision 2.4 2000/12/16 12:53:56 fischer - * - allow REQUEST SENSE to be queued - * - handle shared PCI interrupts - * - * Revision 2.3 2000/11/04 16:40:26 fischer - * - handle data overruns - * - extend timeout for data phases - * - * Revision 2.2 2000/08/08 19:54:53 fischer - * - minor changes - * - * Revision 2.1 2000/05/17 16:23:17 fischer - * - signature update - * - fix for data out w/o scatter gather - * - * Revision 2.0 1999/12/25 15:07:32 fischer - * - interrupt routine completly reworked - * - basic support for new eh code - * - * Revision 1.21 1999/11/10 23:46:36 fischer - * - default to synchronous operation - * - synchronous negotiation fixed - * - added timeout to loops - * - debugging output can be controlled through procfs - * - * Revision 1.20 1999/11/07 18:37:31 fischer - * - synchronous operation works - * - resid support for sg driver - * - * Revision 1.19 1999/11/02 22:39:59 fischer - * - moved leading comments to README.aha152x - * - new additional module parameters - * - updates for 2.3 - * - support for the Tripace TC1550 controller - * - interrupt handling changed - * - * Revision 1.18 1996/09/07 20:10:40 fischer - * - fixed can_queue handling (multiple outstanding commands working again) - * - * Revision 1.17 1996/08/17 16:05:14 fischer - * - biosparam improved - * - interrupt verification - * - updated documentation - * - cleanups - * - * Revision 1.16 1996/06/09 00:04:56 root - * - added configuration symbols for insmod (aha152x/aha152x1) - * - * Revision 1.15 1996/04/30 14:52:06 fischer - * - proc info fixed - * - support for extended translation for >1GB disks - * - * Revision 1.14 1996/01/17 15:11:20 fischer - * - fixed lockup in MESSAGE IN phase after reconnection - * - * Revision 1.13 1996/01/09 02:15:53 fischer - * - some cleanups - * - moved request_irq behind controller initialization - * (to avoid spurious interrupts) - * - * Revision 1.12 1995/12/16 12:26:07 fischer - * - barrier()s added - * - configurable RESET delay added - * - * Revision 1.11 1995/12/06 21:18:35 fischer - * - some minor updates - * - * Revision 1.10 1995/07/22 19:18:45 fischer - * - support for 2 controllers - * - started synchronous data transfers (not working yet) - * - * Revision 1.9 1995/03/18 09:20:24 root - * - patches for PCMCIA and modules - * - * Revision 1.8 1995/01/21 22:07:19 root - * - snarf_region => request_region - * - aha152x_intr interface change - * - * Revision 1.7 1995/01/02 23:19:36 root - * - updated COMMAND_SIZE to cmd_len - * - changed sti() to restore_flags() - * - fixed some #ifdef which generated warnings - * - * Revision 1.6 1994/11/24 20:35:27 root - * - problem with odd number of bytes in fifo fixed - * - * Revision 1.5 1994/10/30 14:39:56 root - * - abort code fixed - * - debugging improved - * - * Revision 1.4 1994/09/12 11:33:01 root - * - irqaction to request_irq - * - abortion updated - * - * Revision 1.3 1994/08/04 13:53:05 root - * - updates for mid-level-driver changes - * - accept unexpected BUSFREE phase as error condition - * - parity check now configurable - * - * Revision 1.2 1994/07/03 12:56:36 root - * - cleaned up debugging code - * - more tweaking on reset delays - * - updated abort/reset code (pretty untested...) - * - * Revision 1.1 1994/05/28 21:18:49 root - * - update for mid-level interface change (abort-reset) - * - delays after resets adjusted for some slow devices - * - * Revision 1.0 1994/03/25 12:52:00 root - * - Fixed "more data than expected" problem - * - added new BIOS signatures - * - * Revision 0.102 1994/01/31 20:44:12 root - * - minor changes in insw/outsw handling - * - * Revision 0.101 1993/12/13 01:16:27 root - * - fixed STATUS phase (non-GOOD stati were dropped sometimes; - * fixes problems with CD-ROM sector size detection & media change) - * - * Revision 0.100 1993/12/10 16:58:47 root - * - fix for unsuccessful selections in case of non-continuous id assignments - * on the scsi bus. - * - * Revision 0.99 1993/10/24 16:19:59 root - * - fixed DATA IN (rare read errors gone) - * - * Revision 0.98 1993/10/17 12:54:44 root - * - fixed some recent fixes (shame on me) - * - moved initialization of scratch area to aha152x_queue - * - * Revision 0.97 1993/10/09 18:53:53 root - * - DATA IN fixed. Rarely left data in the fifo. - * - * Revision 0.96 1993/10/03 00:53:59 root - * - minor changes on DATA IN - * - * Revision 0.95 1993/09/24 10:36:01 root - * - change handling of MSGI after reselection - * - fixed sti/cli - * - minor changes - * - * Revision 0.94 1993/09/18 14:08:22 root - * - fixed bug in multiple outstanding command code - * - changed detection - * - support for kernel command line configuration - * - reset corrected - * - changed message handling - * - * Revision 0.93 1993/09/15 20:41:19 root - * - fixed bugs with multiple outstanding commands - * - * Revision 0.92 1993/09/13 02:46:33 root - * - multiple outstanding commands work (no problems with IBM drive) - * - * Revision 0.91 1993/09/12 20:51:46 root - * added multiple outstanding commands - * (some problem with this $%&? IBM device remain) - * - * Revision 0.9 1993/09/12 11:11:22 root - * - corrected auto-configuration - * - changed the auto-configuration (added some '#define's) - * - added support for dis-/reconnection - * - * Revision 0.8 1993/09/06 23:09:39 root - * - added support for the drive activity light - * - minor changes - * - * Revision 0.7 1993/09/05 14:30:15 root - * - improved phase detection - * - now using the new snarf_region code of 0.99pl13 - * - * Revision 0.6 1993/09/02 11:01:38 root - * first public release; added some signatures and biosparam() - * - * Revision 0.5 1993/08/30 10:23:30 root - * fixed timing problems with my IBM drive - * - * Revision 0.4 1993/08/29 14:06:52 root - * fixed some problems with timeouts due incomplete commands - * - * Revision 0.3 1993/08/28 15:55:03 root - * writing data works too. mounted and worked on a dos partition - * - * Revision 0.2 1993/08/27 22:42:07 root - * reading data works. Mounted a msdos partition. - * - * Revision 0.1 1993/08/25 13:38:30 root - * first "damn thing doesn't work" version - * - * Revision 0.0 1993/08/14 19:54:25 root - * empty function bodies; detect() works. - * - * - ************************************************************************** - - see Documentation/scsi/aha152x.txt for configuration details - - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include -#include -#include -#include "aha152x.h" - -static LIST_HEAD(aha152x_host_list); - - -/* DEFINES */ - -/* For PCMCIA cards, always use AUTOCONF */ -#if defined(PCMCIA) || defined(MODULE) -#if !defined(AUTOCONF) -#define AUTOCONF -#endif -#endif - -#if !defined(AUTOCONF) && !defined(SETUP0) -#error define AUTOCONF or SETUP0 -#endif - -#if defined(AHA152X_DEBUG) -#define DEBUG_DEFAULT debug_eh - -#define DPRINTK(when,msgs...) \ - do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0) - -#define DO_LOCK(flags) \ - do { \ - if(spin_is_locked(&QLOCK)) { \ - DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \ - } \ - DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \ - spin_lock_irqsave(&QLOCK,flags); \ - DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \ - QLOCKER=__func__; \ - QLOCKERL=__LINE__; \ - } while(0) - -#define DO_UNLOCK(flags) \ - do { \ - DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \ - spin_unlock_irqrestore(&QLOCK,flags); \ - DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \ - QLOCKER="(not locked)"; \ - QLOCKERL=0; \ - } while(0) - -#else -#define DPRINTK(when,msgs...) -#define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags) -#define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags) -#endif - -#define LEAD "(scsi%d:%d:%d) " -#define WARN_LEAD KERN_WARNING LEAD -#define INFO_LEAD KERN_INFO LEAD -#define NOTE_LEAD KERN_NOTICE LEAD -#define ERR_LEAD KERN_ERR LEAD -#define DEBUG_LEAD KERN_DEBUG LEAD -#define CMDINFO(cmd) \ - (cmd) ? ((cmd)->device->host->host_no) : -1, \ - (cmd) ? ((cmd)->device->id & 0x0f) : -1, \ - (cmd) ? ((cmd)->device->lun & 0x07) : -1 - -static inline void -CMD_INC_RESID(struct scsi_cmnd *cmd, int inc) -{ - scsi_set_resid(cmd, scsi_get_resid(cmd) + inc); -} - -#define DELAY_DEFAULT 1000 - -#if defined(PCMCIA) -#define IRQ_MIN 0 -#define IRQ_MAX 16 -#else -#define IRQ_MIN 9 -#if defined(__PPC) -#define IRQ_MAX (nr_irqs-1) -#else -#define IRQ_MAX 12 -#endif -#endif - -enum { - not_issued = 0x0001, /* command not yet issued */ - selecting = 0x0002, /* target is beeing selected */ - identified = 0x0004, /* IDENTIFY was sent */ - disconnected = 0x0008, /* target disconnected */ - completed = 0x0010, /* target sent COMMAND COMPLETE */ - aborted = 0x0020, /* ABORT was sent */ - resetted = 0x0040, /* BUS DEVICE RESET was sent */ - spiordy = 0x0080, /* waiting for SPIORDY to raise */ - syncneg = 0x0100, /* synchronous negotiation in progress */ - aborting = 0x0200, /* ABORT is pending */ - resetting = 0x0400, /* BUS DEVICE RESET is pending */ - check_condition = 0x0800, /* requesting sense after CHECK CONDITION */ -}; - -MODULE_AUTHOR("Jürgen Fischer"); -MODULE_DESCRIPTION(AHA152X_REVID); -MODULE_LICENSE("GPL"); - -#if !defined(PCMCIA) -#if defined(MODULE) -static int io[] = {0, 0}; -module_param_array(io, int, NULL, 0); -MODULE_PARM_DESC(io,"base io address of controller"); - -static int irq[] = {0, 0}; -module_param_array(irq, int, NULL, 0); -MODULE_PARM_DESC(irq,"interrupt for controller"); - -static int scsiid[] = {7, 7}; -module_param_array(scsiid, int, NULL, 0); -MODULE_PARM_DESC(scsiid,"scsi id of controller"); - -static int reconnect[] = {1, 1}; -module_param_array(reconnect, int, NULL, 0); -MODULE_PARM_DESC(reconnect,"allow targets to disconnect"); - -static int parity[] = {1, 1}; -module_param_array(parity, int, NULL, 0); -MODULE_PARM_DESC(parity,"use scsi parity"); - -static int sync[] = {1, 1}; -module_param_array(sync, int, NULL, 0); -MODULE_PARM_DESC(sync,"use synchronous transfers"); - -static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT}; -module_param_array(delay, int, NULL, 0); -MODULE_PARM_DESC(delay,"scsi reset delay"); - -static int exttrans[] = {0, 0}; -module_param_array(exttrans, int, NULL, 0); -MODULE_PARM_DESC(exttrans,"use extended translation"); - -#if !defined(AHA152X_DEBUG) -static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; -module_param_array(aha152x, int, NULL, 0); -MODULE_PARM_DESC(aha152x, "parameters for first controller"); - -static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0}; -module_param_array(aha152x1, int, NULL, 0); -MODULE_PARM_DESC(aha152x1, "parameters for second controller"); -#else -static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT}; -module_param_array(debug, int, NULL, 0); -MODULE_PARM_DESC(debug, "flags for driver debugging"); - -static int aha152x[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; -module_param_array(aha152x, int, NULL, 0); -MODULE_PARM_DESC(aha152x, "parameters for first controller"); - -static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT}; -module_param_array(aha152x1, int, NULL, 0); -MODULE_PARM_DESC(aha152x1, "parameters for second controller"); -#endif /* !defined(AHA152X_DEBUG) */ -#endif /* MODULE */ - -#ifdef __ISAPNP__ -static struct isapnp_device_id id_table[] __devinitdata = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1502), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1505), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1510), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1515), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1520), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2015), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1522), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x2215), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1530), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3015), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1532), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x3215), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x6360), 0 }, - { ISAPNP_DEVICE_SINGLE_END, } -}; -MODULE_DEVICE_TABLE(isapnp, id_table); -#endif /* ISAPNP */ - -#endif /* !PCMCIA */ - -static struct scsi_host_template aha152x_driver_template; - -/* - * internal states of the host - * - */ -enum aha152x_state { - idle=0, - unknown, - seldo, - seldi, - selto, - busfree, - msgo, - cmd, - msgi, - status, - datai, - datao, - parerr, - rsti, - maxstate -}; - -/* - * current state information of the host - * - */ -struct aha152x_hostdata { - Scsi_Cmnd *issue_SC; - /* pending commands to issue */ - - Scsi_Cmnd *current_SC; - /* current command on the bus */ - - Scsi_Cmnd *disconnected_SC; - /* commands that disconnected */ - - Scsi_Cmnd *done_SC; - /* command that was completed */ - - spinlock_t lock; - /* host lock */ - -#if defined(AHA152X_DEBUG) - const char *locker; - /* which function has the lock */ - int lockerl; /* where did it get it */ - - int debug; /* current debugging setting */ -#endif - -#if defined(AHA152X_STAT) - int total_commands; - int disconnections; - int busfree_without_any_action; - int busfree_without_old_command; - int busfree_without_new_command; - int busfree_without_done_command; - int busfree_with_check_condition; - int count[maxstate]; - int count_trans[maxstate]; - unsigned long time[maxstate]; -#endif - - int commands; /* current number of commands */ - - int reconnect; /* disconnection allowed */ - int parity; /* parity checking enabled */ - int synchronous; /* synchronous transferes enabled */ - int delay; /* reset out delay */ - int ext_trans; /* extended translation enabled */ - - int swint; /* software-interrupt was fired during detect() */ - int service; /* bh needs to be run */ - int in_intr; /* bh is running */ - - /* current state, - previous state, - last state different from current state */ - enum aha152x_state state, prevstate, laststate; - - int target; - /* reconnecting target */ - - unsigned char syncrate[8]; - /* current synchronous transfer agreements */ - - unsigned char syncneg[8]; - /* 0: no negotiation; - * 1: negotiation in progress; - * 2: negotiation completed - */ - - int cmd_i; - /* number of sent bytes of current command */ - - int msgi_len; - /* number of received message bytes */ - unsigned char msgi[256]; - /* received message bytes */ - - int msgo_i, msgo_len; - /* number of sent bytes and length of current messages */ - unsigned char msgo[256]; - /* pending messages */ - - int data_len; - /* number of sent/received bytes in dataphase */ - - unsigned long io_port0; - unsigned long io_port1; - -#ifdef __ISAPNP__ - struct pnp_dev *pnpdev; -#endif - struct list_head host_list; -}; - - -/* - * host specific command extension - * - */ -struct aha152x_scdata { - Scsi_Cmnd *next; /* next sc in queue */ - struct completion *done;/* semaphore to block on */ - struct scsi_eh_save ses; -}; - -/* access macros for hostdata */ - -#define HOSTDATA(shpnt) ((struct aha152x_hostdata *) &shpnt->hostdata) - -#define HOSTNO ((shpnt)->host_no) - -#define CURRENT_SC (HOSTDATA(shpnt)->current_SC) -#define DONE_SC (HOSTDATA(shpnt)->done_SC) -#define ISSUE_SC (HOSTDATA(shpnt)->issue_SC) -#define DISCONNECTED_SC (HOSTDATA(shpnt)->disconnected_SC) -#define QLOCK (HOSTDATA(shpnt)->lock) -#define QLOCKER (HOSTDATA(shpnt)->locker) -#define QLOCKERL (HOSTDATA(shpnt)->lockerl) - -#define STATE (HOSTDATA(shpnt)->state) -#define PREVSTATE (HOSTDATA(shpnt)->prevstate) -#define LASTSTATE (HOSTDATA(shpnt)->laststate) - -#define RECONN_TARGET (HOSTDATA(shpnt)->target) - -#define CMD_I (HOSTDATA(shpnt)->cmd_i) - -#define MSGO(i) (HOSTDATA(shpnt)->msgo[i]) -#define MSGO_I (HOSTDATA(shpnt)->msgo_i) -#define MSGOLEN (HOSTDATA(shpnt)->msgo_len) -#define ADDMSGO(x) (MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow")) - -#define MSGI(i) (HOSTDATA(shpnt)->msgi[i]) -#define MSGILEN (HOSTDATA(shpnt)->msgi_len) -#define ADDMSGI(x) (MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow")) - -#define DATA_LEN (HOSTDATA(shpnt)->data_len) - -#define SYNCRATE (HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id]) -#define SYNCNEG (HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id]) - -#define DELAY (HOSTDATA(shpnt)->delay) -#define EXT_TRANS (HOSTDATA(shpnt)->ext_trans) -#define TC1550 (HOSTDATA(shpnt)->tc1550) -#define RECONNECT (HOSTDATA(shpnt)->reconnect) -#define PARITY (HOSTDATA(shpnt)->parity) -#define SYNCHRONOUS (HOSTDATA(shpnt)->synchronous) - -#define HOSTIOPORT0 (HOSTDATA(shpnt)->io_port0) -#define HOSTIOPORT1 (HOSTDATA(shpnt)->io_port1) - -#define SCDATA(SCpnt) ((struct aha152x_scdata *) (SCpnt)->host_scribble) -#define SCNEXT(SCpnt) SCDATA(SCpnt)->next -#define SCSEM(SCpnt) SCDATA(SCpnt)->done - -#define SG_ADDRESS(buffer) ((char *) sg_virt((buffer))) - -/* state handling */ -static void seldi_run(struct Scsi_Host *shpnt); -static void seldo_run(struct Scsi_Host *shpnt); -static void selto_run(struct Scsi_Host *shpnt); -static void busfree_run(struct Scsi_Host *shpnt); - -static void msgo_init(struct Scsi_Host *shpnt); -static void msgo_run(struct Scsi_Host *shpnt); -static void msgo_end(struct Scsi_Host *shpnt); - -static void cmd_init(struct Scsi_Host *shpnt); -static void cmd_run(struct Scsi_Host *shpnt); -static void cmd_end(struct Scsi_Host *shpnt); - -static void datai_init(struct Scsi_Host *shpnt); -static void datai_run(struct Scsi_Host *shpnt); -static void datai_end(struct Scsi_Host *shpnt); - -static void datao_init(struct Scsi_Host *shpnt); -static void datao_run(struct Scsi_Host *shpnt); -static void datao_end(struct Scsi_Host *shpnt); - -static void status_run(struct Scsi_Host *shpnt); - -static void msgi_run(struct Scsi_Host *shpnt); -static void msgi_end(struct Scsi_Host *shpnt); - -static void parerr_run(struct Scsi_Host *shpnt); -static void rsti_run(struct Scsi_Host *shpnt); - -static void is_complete(struct Scsi_Host *shpnt); - -/* - * driver states - * - */ -static struct { - char *name; - void (*init)(struct Scsi_Host *); - void (*run)(struct Scsi_Host *); - void (*end)(struct Scsi_Host *); - int spio; -} states[] = { - { "idle", NULL, NULL, NULL, 0}, - { "unknown", NULL, NULL, NULL, 0}, - { "seldo", NULL, seldo_run, NULL, 0}, - { "seldi", NULL, seldi_run, NULL, 0}, - { "selto", NULL, selto_run, NULL, 0}, - { "busfree", NULL, busfree_run, NULL, 0}, - { "msgo", msgo_init, msgo_run, msgo_end, 1}, - { "cmd", cmd_init, cmd_run, cmd_end, 1}, - { "msgi", NULL, msgi_run, msgi_end, 1}, - { "status", NULL, status_run, NULL, 1}, - { "datai", datai_init, datai_run, datai_end, 0}, - { "datao", datao_init, datao_run, datao_end, 0}, - { "parerr", NULL, parerr_run, NULL, 0}, - { "rsti", NULL, rsti_run, NULL, 0}, -}; - -/* setup & interrupt */ -static irqreturn_t intr(int irq, void *dev_id); -static void reset_ports(struct Scsi_Host *shpnt); -static void aha152x_error(struct Scsi_Host *shpnt, char *msg); -static void done(struct Scsi_Host *shpnt, int error); - -/* diagnostics */ -static void disp_ports(struct Scsi_Host *shpnt); -static void show_command(Scsi_Cmnd * ptr); -static void show_queues(struct Scsi_Host *shpnt); -static void disp_enintr(struct Scsi_Host *shpnt); - - -/* - * queue services: - * - */ -static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC) -{ - Scsi_Cmnd *end; - - SCNEXT(new_SC) = NULL; - if (!*SC) - *SC = new_SC; - else { - for (end = *SC; SCNEXT(end); end = SCNEXT(end)) - ; - SCNEXT(end) = new_SC; - } -} - -static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC) -{ - Scsi_Cmnd *ptr; - - ptr = *SC; - if (ptr) { - *SC = SCNEXT(*SC); - SCNEXT(ptr)=NULL; - } - return ptr; -} - -static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun) -{ - Scsi_Cmnd *ptr, *prev; - - for (ptr = *SC, prev = NULL; - ptr && ((ptr->device->id != target) || (ptr->device->lun != lun)); - prev = ptr, ptr = SCNEXT(ptr)) - ; - - if (ptr) { - if (prev) - SCNEXT(prev) = SCNEXT(ptr); - else - *SC = SCNEXT(ptr); - - SCNEXT(ptr)=NULL; - } - - return ptr; -} - -static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp) -{ - Scsi_Cmnd *ptr, *prev; - - for (ptr = *SC, prev = NULL; - ptr && SCp!=ptr; - prev = ptr, ptr = SCNEXT(ptr)) - ; - - if (ptr) { - if (prev) - SCNEXT(prev) = SCNEXT(ptr); - else - *SC = SCNEXT(ptr); - - SCNEXT(ptr)=NULL; - } - - return ptr; -} - -static irqreturn_t swintr(int irqno, void *dev_id) -{ - struct Scsi_Host *shpnt = dev_id; - - HOSTDATA(shpnt)->swint++; - - SETPORT(DMACNTRL0, INTEN); - return IRQ_HANDLED; -} - -struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup) -{ - struct Scsi_Host *shpnt; - - shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata)); - if (!shpnt) { - printk(KERN_ERR "aha152x: scsi_host_alloc failed\n"); - return NULL; - } - - memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt)); - INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list); - - /* need to have host registered before triggering any interrupt */ - list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list); - - shpnt->io_port = setup->io_port; - shpnt->n_io_port = IO_RANGE; - shpnt->irq = setup->irq; - - if (!setup->tc1550) { - HOSTIOPORT0 = setup->io_port; - HOSTIOPORT1 = setup->io_port; - } else { - HOSTIOPORT0 = setup->io_port+0x10; - HOSTIOPORT1 = setup->io_port-0x10; - } - - spin_lock_init(&QLOCK); - RECONNECT = setup->reconnect; - SYNCHRONOUS = setup->synchronous; - PARITY = setup->parity; - DELAY = setup->delay; - EXT_TRANS = setup->ext_trans; - -#if defined(AHA152X_DEBUG) - HOSTDATA(shpnt)->debug = setup->debug; -#endif - - SETPORT(SCSIID, setup->scsiid << 4); - shpnt->this_id = setup->scsiid; - - if (setup->reconnect) - shpnt->can_queue = AHA152X_MAXQUEUE; - - /* RESET OUT */ - printk("aha152x: resetting bus...\n"); - SETPORT(SCSISEQ, SCSIRSTO); - mdelay(256); - SETPORT(SCSISEQ, 0); - mdelay(DELAY); - - reset_ports(shpnt); - - printk(KERN_INFO - "aha152x%d%s: " - "vital data: rev=%x, " - "io=0x%03lx (0x%03lx/0x%03lx), " - "irq=%d, " - "scsiid=%d, " - "reconnect=%s, " - "parity=%s, " - "synchronous=%s, " - "delay=%d, " - "extended translation=%s\n", - shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "", - GETPORT(REV) & 0x7, - shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1, - shpnt->irq, - shpnt->this_id, - RECONNECT ? "enabled" : "disabled", - PARITY ? "enabled" : "disabled", - SYNCHRONOUS ? "enabled" : "disabled", - DELAY, - EXT_TRANS ? "enabled" : "disabled"); - - /* not expecting any interrupts */ - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, 0); - - if( request_irq(shpnt->irq, swintr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) { - printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq); - goto out_host_put; - } - - HOSTDATA(shpnt)->swint = 0; - - printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no); - - mb(); - SETPORT(DMACNTRL0, SWINT|INTEN); - mdelay(1000); - free_irq(shpnt->irq, shpnt); - - if (!HOSTDATA(shpnt)->swint) { - if (TESTHI(DMASTAT, INTSTAT)) { - printk("lost.\n"); - } else { - printk("failed.\n"); - } - - SETPORT(DMACNTRL0, INTEN); - - printk(KERN_ERR "aha152x%d: irq %d possibly wrong. " - "Please verify.\n", shpnt->host_no, shpnt->irq); - goto out_host_put; - } - printk("ok.\n"); - - - /* clear interrupts */ - SETPORT(SSTAT0, 0x7f); - SETPORT(SSTAT1, 0xef); - - if ( request_irq(shpnt->irq, intr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) { - printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq); - goto out_host_put; - } - - if( scsi_add_host(shpnt, NULL) ) { - free_irq(shpnt->irq, shpnt); - printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no); - goto out_host_put; - } - - scsi_scan_host(shpnt); - - return shpnt; - -out_host_put: - list_del(&HOSTDATA(shpnt)->host_list); - scsi_host_put(shpnt); - - return NULL; -} - -void aha152x_release(struct Scsi_Host *shpnt) -{ - if (!shpnt) - return; - - scsi_remove_host(shpnt); - if (shpnt->irq) - free_irq(shpnt->irq, shpnt); - -#if !defined(PCMCIA) - if (shpnt->io_port) - release_region(shpnt->io_port, IO_RANGE); -#endif - -#ifdef __ISAPNP__ - if (HOSTDATA(shpnt)->pnpdev) - pnp_device_detach(HOSTDATA(shpnt)->pnpdev); -#endif - - list_del(&HOSTDATA(shpnt)->host_list); - scsi_host_put(shpnt); -} - - -/* - * setup controller to generate interrupts depending - * on current state (lock has to be acquired) - * - */ -static int setup_expected_interrupts(struct Scsi_Host *shpnt) -{ - if(CURRENT_SC) { - CURRENT_SC->SCp.phase |= 1 << 16; - - if(CURRENT_SC->SCp.phase & selecting) { - DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC)); - SETPORT(SSTAT1, SELTO); - SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0)); - SETPORT(SIMODE1, ENSELTIMO); - } else { - DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : ""); - SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0); - SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); - } - } else if(STATE==seldi) { - DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC)); - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); - } else { - DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n", - CMDINFO(CURRENT_SC), - DISCONNECTED_SC ? "(reselection)" : "", - ISSUE_SC ? "(busfree)" : ""); - SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0); - SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0)); - } - - if(!HOSTDATA(shpnt)->in_intr) - SETBITS(DMACNTRL0, INTEN); - - return TESTHI(DMASTAT, INTSTAT); -} - - -/* - * Queue a command and setup interrupts for a free bus. - */ -static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete, - int phase, void (*done)(Scsi_Cmnd *)) -{ - struct Scsi_Host *shpnt = SCpnt->device->host; - unsigned long flags; - -#if defined(AHA152X_DEBUG) - if (HOSTDATA(shpnt)->debug & debug_queue) { - printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=", - CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, - scsi_sg_count(SCpnt), scsi_bufflen(SCpnt)); - __scsi_print_command(SCpnt->cmnd); - } -#endif - - SCpnt->scsi_done = done; - SCpnt->SCp.phase = not_issued | phase; - SCpnt->SCp.Status = 0x1; /* Ilegal status by SCSI standard */ - SCpnt->SCp.Message = 0; - SCpnt->SCp.have_data_in = 0; - SCpnt->SCp.sent_command = 0; - - if(SCpnt->SCp.phase & (resetting|check_condition)) { - if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) { - printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt)); - return FAILED; - } - } else { - SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC); - if(!SCpnt->host_scribble) { - printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt)); - return FAILED; - } - } - - SCNEXT(SCpnt) = NULL; - SCSEM(SCpnt) = complete; - - /* setup scratch area - SCp.ptr : buffer pointer - SCp.this_residual : buffer length - SCp.buffer : next buffer - SCp.buffers_residual : left buffers in list - SCp.phase : current state of the command */ - - if ((phase & resetting) || !scsi_sglist(SCpnt)) { - SCpnt->SCp.ptr = NULL; - SCpnt->SCp.this_residual = 0; - scsi_set_resid(SCpnt, 0); - SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; - } else { - scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); - SCpnt->SCp.buffer = scsi_sglist(SCpnt); - SCpnt->SCp.ptr = SG_ADDRESS(SCpnt->SCp.buffer); - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; - } - - DO_LOCK(flags); - -#if defined(AHA152X_STAT) - HOSTDATA(shpnt)->total_commands++; -#endif - - /* Turn led on, when this is the first command. */ - HOSTDATA(shpnt)->commands++; - if (HOSTDATA(shpnt)->commands==1) - SETPORT(PORTA, 1); - - append_SC(&ISSUE_SC, SCpnt); - - if(!HOSTDATA(shpnt)->in_intr) - setup_expected_interrupts(shpnt); - - DO_UNLOCK(flags); - - return 0; -} - -/* - * queue a command - * - */ -static int aha152x_queue_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) -{ -#if 0 - if(*SCpnt->cmnd == REQUEST_SENSE) { - SCpnt->result = 0; - done(SCpnt); - - return 0; - } -#endif - - return aha152x_internal_queue(SCpnt, NULL, 0, done); -} - -static DEF_SCSI_QCMD(aha152x_queue) - - -/* - * - * - */ -static void reset_done(Scsi_Cmnd *SCpnt) -{ -#if 0 - struct Scsi_Host *shpnt = SCpnt->host; - DPRINTK(debug_eh, INFO_LEAD "reset_done called\n", CMDINFO(SCpnt)); -#endif - if(SCSEM(SCpnt)) { - complete(SCSEM(SCpnt)); - } else { - printk(KERN_ERR "aha152x: reset_done w/o completion\n"); - } -} - -/* - * Abort a command - * - */ -static int aha152x_abort(Scsi_Cmnd *SCpnt) -{ - struct Scsi_Host *shpnt = SCpnt->device->host; - Scsi_Cmnd *ptr; - unsigned long flags; - -#if defined(AHA152X_DEBUG) - if(HOSTDATA(shpnt)->debug & debug_eh) { - printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt); - show_queues(shpnt); - } -#endif - - DO_LOCK(flags); - - ptr=remove_SC(&ISSUE_SC, SCpnt); - - if(ptr) { - DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt)); - - HOSTDATA(shpnt)->commands--; - if (!HOSTDATA(shpnt)->commands) - SETPORT(PORTA, 0); - DO_UNLOCK(flags); - - kfree(SCpnt->host_scribble); - SCpnt->host_scribble=NULL; - - return SUCCESS; - } - - DO_UNLOCK(flags); - - /* - * FIXME: - * for current command: queue ABORT for message out and raise ATN - * for disconnected command: pseudo SC with ABORT message or ABORT on reselection? - * - */ - - printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt)); - - return FAILED; -} - -/* - * Reset a device - * - */ -static int aha152x_device_reset(Scsi_Cmnd * SCpnt) -{ - struct Scsi_Host *shpnt = SCpnt->device->host; - DECLARE_COMPLETION(done); - int ret, issued, disconnected; - unsigned char old_cmd_len = SCpnt->cmd_len; - unsigned long flags; - unsigned long timeleft; - -#if defined(AHA152X_DEBUG) - if(HOSTDATA(shpnt)->debug & debug_eh) { - printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt); - show_queues(shpnt); - } -#endif - - if(CURRENT_SC==SCpnt) { - printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt)); - return FAILED; - } - - DO_LOCK(flags); - issued = remove_SC(&ISSUE_SC, SCpnt) == NULL; - disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt); - DO_UNLOCK(flags); - - SCpnt->cmd_len = 0; - - aha152x_internal_queue(SCpnt, &done, resetting, reset_done); - - timeleft = wait_for_completion_timeout(&done, 100*HZ); - if (!timeleft) { - /* remove command from issue queue */ - DO_LOCK(flags); - remove_SC(&ISSUE_SC, SCpnt); - DO_UNLOCK(flags); - } - - SCpnt->cmd_len = old_cmd_len; - - DO_LOCK(flags); - - if(SCpnt->SCp.phase & resetted) { - HOSTDATA(shpnt)->commands--; - if (!HOSTDATA(shpnt)->commands) - SETPORT(PORTA, 0); - kfree(SCpnt->host_scribble); - SCpnt->host_scribble=NULL; - - ret = SUCCESS; - } else { - /* requeue */ - if(!issued) { - append_SC(&ISSUE_SC, SCpnt); - } else if(disconnected) { - append_SC(&DISCONNECTED_SC, SCpnt); - } - - ret = FAILED; - } - - DO_UNLOCK(flags); - return ret; -} - -static void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs) -{ - Scsi_Cmnd *ptr; - - ptr=*SCs; - while(ptr) { - Scsi_Cmnd *next; - - if(SCDATA(ptr)) { - next = SCNEXT(ptr); - } else { - printk(DEBUG_LEAD "queue corrupted at %p\n", CMDINFO(ptr), ptr); - next = NULL; - } - - if (!ptr->device->soft_reset) { - DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr); - remove_SC(SCs, ptr); - HOSTDATA(shpnt)->commands--; - kfree(ptr->host_scribble); - ptr->host_scribble=NULL; - } - - ptr = next; - } -} - -/* - * Reset the bus - * - */ -static int aha152x_bus_reset_host(struct Scsi_Host *shpnt) -{ - unsigned long flags; - - DO_LOCK(flags); - -#if defined(AHA152X_DEBUG) - if(HOSTDATA(shpnt)->debug & debug_eh) { - printk(KERN_DEBUG "scsi%d: bus reset", shpnt->host_no); - show_queues(shpnt); - } -#endif - - free_hard_reset_SCs(shpnt, &ISSUE_SC); - free_hard_reset_SCs(shpnt, &DISCONNECTED_SC); - - DPRINTK(debug_eh, KERN_DEBUG "scsi%d: resetting bus\n", shpnt->host_no); - - SETPORT(SCSISEQ, SCSIRSTO); - mdelay(256); - SETPORT(SCSISEQ, 0); - mdelay(DELAY); - - DPRINTK(debug_eh, KERN_DEBUG "scsi%d: bus resetted\n", shpnt->host_no); - - setup_expected_interrupts(shpnt); - if(HOSTDATA(shpnt)->commands==0) - SETPORT(PORTA, 0); - - DO_UNLOCK(flags); - - return SUCCESS; -} - -/* - * Reset the bus - * - */ -static int aha152x_bus_reset(Scsi_Cmnd *SCpnt) -{ - return aha152x_bus_reset_host(SCpnt->device->host); -} - -/* - * Restore default values to the AIC-6260 registers and reset the fifos - * - */ -static void reset_ports(struct Scsi_Host *shpnt) -{ - unsigned long flags; - - /* disable interrupts */ - SETPORT(DMACNTRL0, RSTFIFO); - - SETPORT(SCSISEQ, 0); - - SETPORT(SXFRCTL1, 0); - SETPORT(SCSISIG, 0); - SETRATE(0); - - /* clear all interrupt conditions */ - SETPORT(SSTAT0, 0x7f); - SETPORT(SSTAT1, 0xef); - - SETPORT(SSTAT4, SYNCERR | FWERR | FRERR); - - SETPORT(DMACNTRL0, 0); - SETPORT(DMACNTRL1, 0); - - SETPORT(BRSTCNTRL, 0xf1); - - /* clear SCSI fifos and transfer count */ - SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); - SETPORT(SXFRCTL0, CH1); - - DO_LOCK(flags); - setup_expected_interrupts(shpnt); - DO_UNLOCK(flags); -} - -/* - * Reset the host (bus and controller) - * - */ -int aha152x_host_reset_host(struct Scsi_Host *shpnt) -{ - DPRINTK(debug_eh, KERN_DEBUG "scsi%d: host reset\n", shpnt->host_no); - - aha152x_bus_reset_host(shpnt); - - DPRINTK(debug_eh, KERN_DEBUG "scsi%d: resetting ports\n", shpnt->host_no); - reset_ports(shpnt); - - return SUCCESS; -} - -/* - * Reset the host (bus and controller) - * - */ -static int aha152x_host_reset(Scsi_Cmnd *SCpnt) -{ - return aha152x_host_reset_host(SCpnt->device->host); -} - -/* - * Return the "logical geometry" - * - */ -static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int *info_array) -{ - struct Scsi_Host *shpnt = sdev->host; - - /* try default translation */ - info_array[0] = 64; - info_array[1] = 32; - info_array[2] = (unsigned long)capacity / (64 * 32); - - /* for disks >1GB do some guessing */ - if (info_array[2] >= 1024) { - int info[3]; - - /* try to figure out the geometry from the partition table */ - if (scsicam_bios_param(bdev, capacity, info) < 0 || - !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { - if (EXT_TRANS) { - printk(KERN_NOTICE - "aha152x: unable to verify geometry for disk with >1GB.\n" - " using extended translation.\n"); - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = (unsigned long)capacity / (255 * 63); - } else { - printk(KERN_NOTICE - "aha152x: unable to verify geometry for disk with >1GB.\n" - " Using default translation. Please verify yourself.\n" - " Perhaps you need to enable extended translation in the driver.\n" - " See Documentation/scsi/aha152x.txt for details.\n"); - } - } else { - info_array[0] = info[0]; - info_array[1] = info[1]; - info_array[2] = info[2]; - - if (info[0] == 255 && !EXT_TRANS) { - printk(KERN_NOTICE - "aha152x: current partition table is using extended translation.\n" - " using it also, although it's not explicitly enabled.\n"); - } - } - } - - return 0; -} - -/* - * Internal done function - * - */ -static void done(struct Scsi_Host *shpnt, int error) -{ - if (CURRENT_SC) { - if(DONE_SC) - printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC); - - DONE_SC = CURRENT_SC; - CURRENT_SC = NULL; - DONE_SC->result = error; - } else - printk(KERN_ERR "aha152x: done() called outside of command\n"); -} - -static struct work_struct aha152x_tq; - -/* - * Run service completions on the card with interrupts enabled. - * - */ -static void run(struct work_struct *work) -{ - struct aha152x_hostdata *hd; - - list_for_each_entry(hd, &aha152x_host_list, host_list) { - struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata); - - is_complete(shost); - } -} - -/* - * Interrupt handler - * - */ -static irqreturn_t intr(int irqno, void *dev_id) -{ - struct Scsi_Host *shpnt = dev_id; - unsigned long flags; - unsigned char rev, dmacntrl0; - - /* - * Read a couple of registers that are known to not be all 1's. If - * we read all 1's (-1), that means that either: - * - * a. The host adapter chip has gone bad, and we cannot control it, - * OR - * b. The host adapter is a PCMCIA card that has been ejected - * - * In either case, we cannot do anything with the host adapter at - * this point in time. So just ignore the interrupt and return. - * In the latter case, the interrupt might actually be meant for - * someone else sharing this IRQ, and that driver will handle it. - */ - rev = GETPORT(REV); - dmacntrl0 = GETPORT(DMACNTRL0); - if ((rev == 0xFF) && (dmacntrl0 == 0xFF)) - return IRQ_NONE; - - if( TESTLO(DMASTAT, INTSTAT) ) - return IRQ_NONE; - - /* no more interrupts from the controller, while we're busy. - INTEN is restored by the BH handler */ - CLRBITS(DMACNTRL0, INTEN); - - DO_LOCK(flags); - if( HOSTDATA(shpnt)->service==0 ) { - HOSTDATA(shpnt)->service=1; - - /* Poke the BH handler */ - INIT_WORK(&aha152x_tq, run); - schedule_work(&aha152x_tq); - } - DO_UNLOCK(flags); - - return IRQ_HANDLED; -} - -/* - * busfree phase - * - handle completition/disconnection/error of current command - * - start selection for next command (if any) - */ -static void busfree_run(struct Scsi_Host *shpnt) -{ - unsigned long flags; -#if defined(AHA152X_STAT) - int action=0; -#endif - - SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); - SETPORT(SXFRCTL0, CH1); - - SETPORT(SSTAT1, CLRBUSFREE); - - if(CURRENT_SC) { -#if defined(AHA152X_STAT) - action++; -#endif - CURRENT_SC->SCp.phase &= ~syncneg; - - if(CURRENT_SC->SCp.phase & completed) { - /* target sent COMMAND COMPLETE */ - done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16)); - - } else if(CURRENT_SC->SCp.phase & aborted) { - DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC)); - done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16)); - - } else if(CURRENT_SC->SCp.phase & resetted) { - DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC)); - done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16)); - - } else if(CURRENT_SC->SCp.phase & disconnected) { - /* target sent DISCONNECT */ - DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n", - CMDINFO(CURRENT_SC), - scsi_get_resid(CURRENT_SC), - scsi_bufflen(CURRENT_SC)); -#if defined(AHA152X_STAT) - HOSTDATA(shpnt)->disconnections++; -#endif - append_SC(&DISCONNECTED_SC, CURRENT_SC); - CURRENT_SC->SCp.phase |= 1 << 16; - CURRENT_SC = NULL; - - } else { - done(shpnt, DID_ERROR << 16); - } -#if defined(AHA152X_STAT) - } else { - HOSTDATA(shpnt)->busfree_without_old_command++; -#endif - } - - DO_LOCK(flags); - - if(DONE_SC) { -#if defined(AHA152X_STAT) - action++; -#endif - - if(DONE_SC->SCp.phase & check_condition) { - struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC; - struct aha152x_scdata *sc = SCDATA(cmd); - -#if 0 - if(HOSTDATA(shpnt)->debug & debug_eh) { - printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC)); - scsi_print_sense("bh", DONE_SC); - } -#endif - - scsi_eh_restore_cmnd(cmd, &sc->ses); - - cmd->SCp.Status = SAM_STAT_CHECK_CONDITION; - - HOSTDATA(shpnt)->commands--; - if (!HOSTDATA(shpnt)->commands) - SETPORT(PORTA, 0); /* turn led off */ - } else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) { -#if defined(AHA152X_STAT) - HOSTDATA(shpnt)->busfree_with_check_condition++; -#endif -#if 0 - DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC)); -#endif - - if(!(DONE_SC->SCp.phase & not_issued)) { - struct aha152x_scdata *sc; - Scsi_Cmnd *ptr = DONE_SC; - DONE_SC=NULL; -#if 0 - DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr)); -#endif - - sc = SCDATA(ptr); - /* It was allocated in aha152x_internal_queue? */ - BUG_ON(!sc); - scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0); - - DO_UNLOCK(flags); - aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done); - DO_LOCK(flags); -#if 0 - } else { - DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC)); -#endif - } - } - - if(DONE_SC && DONE_SC->scsi_done) { -#if defined(AHA152X_DEBUG) - int hostno=DONE_SC->device->host->host_no; - int id=DONE_SC->device->id & 0xf; - int lun=DONE_SC->device->lun & 0x7; -#endif - Scsi_Cmnd *ptr = DONE_SC; - DONE_SC=NULL; - - /* turn led off, when no commands are in the driver */ - HOSTDATA(shpnt)->commands--; - if (!HOSTDATA(shpnt)->commands) - SETPORT(PORTA, 0); /* turn led off */ - - if(ptr->scsi_done != reset_done) { - kfree(ptr->host_scribble); - ptr->host_scribble=NULL; - } - - DO_UNLOCK(flags); - DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", hostno, id, lun, ptr); - ptr->scsi_done(ptr); - DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", hostno, id, lun, ptr); - DO_LOCK(flags); - } - - DONE_SC=NULL; -#if defined(AHA152X_STAT) - } else { - HOSTDATA(shpnt)->busfree_without_done_command++; -#endif - } - - if(ISSUE_SC) - CURRENT_SC = remove_first_SC(&ISSUE_SC); - - DO_UNLOCK(flags); - - if(CURRENT_SC) { -#if defined(AHA152X_STAT) - action++; -#endif - CURRENT_SC->SCp.phase |= selecting; - - DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC)); - - /* clear selection timeout */ - SETPORT(SSTAT1, SELTO); - - SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id); - SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER); - SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0)); - } else { -#if defined(AHA152X_STAT) - HOSTDATA(shpnt)->busfree_without_new_command++; -#endif - SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0); - } - -#if defined(AHA152X_STAT) - if(!action) - HOSTDATA(shpnt)->busfree_without_any_action++; -#endif -} - -/* - * Selection done (OUT) - * - queue IDENTIFY message and SDTR to selected target for message out - * (ATN asserted automagically via ENAUTOATNO in busfree()) - */ -static void seldo_run(struct Scsi_Host *shpnt) -{ - SETPORT(SCSISIG, 0); - SETPORT(SSTAT1, CLRBUSFREE); - SETPORT(SSTAT1, CLRPHASECHG); - - CURRENT_SC->SCp.phase &= ~(selecting|not_issued); - - SETPORT(SCSISEQ, 0); - - if (TESTLO(SSTAT0, SELDO)) { - printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC)); - done(shpnt, DID_NO_CONNECT << 16); - return; - } - - SETPORT(SSTAT0, CLRSELDO); - - ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); - - if (CURRENT_SC->SCp.phase & aborting) { - ADDMSGO(ABORT); - } else if (CURRENT_SC->SCp.phase & resetting) { - ADDMSGO(BUS_DEVICE_RESET); - } else if (SYNCNEG==0 && SYNCHRONOUS) { - CURRENT_SC->SCp.phase |= syncneg; - MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8); - SYNCNEG=1; /* negotiation in progress */ - } - - SETRATE(SYNCRATE); -} - -/* - * Selection timeout - * - return command to mid-level with failure cause - * - */ -static void selto_run(struct Scsi_Host *shpnt) -{ - SETPORT(SCSISEQ, 0); - SETPORT(SSTAT1, CLRSELTIMO); - - DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC)); - - if(!CURRENT_SC) { - DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC)); - return; - } - - CURRENT_SC->SCp.phase &= ~selecting; - - if (CURRENT_SC->SCp.phase & aborted) { - DPRINTK(debug_selection, DEBUG_LEAD "aborted\n", CMDINFO(CURRENT_SC)); - done(shpnt, DID_ABORT << 16); - } else if (TESTLO(SSTAT0, SELINGO)) { - DPRINTK(debug_selection, DEBUG_LEAD "arbitration not won\n", CMDINFO(CURRENT_SC)); - done(shpnt, DID_BUS_BUSY << 16); - } else { - /* ARBITRATION won, but SELECTION failed */ - DPRINTK(debug_selection, DEBUG_LEAD "selection failed\n", CMDINFO(CURRENT_SC)); - done(shpnt, DID_NO_CONNECT << 16); - } -} - -/* - * Selection in done - * - put current command back to issue queue - * (reconnection of a disconnected nexus instead - * of successful selection out) - * - */ -static void seldi_run(struct Scsi_Host *shpnt) -{ - int selid; - int target; - unsigned long flags; - - SETPORT(SCSISIG, 0); - SETPORT(SSTAT0, CLRSELDI); - SETPORT(SSTAT1, CLRBUSFREE); - SETPORT(SSTAT1, CLRPHASECHG); - - if(CURRENT_SC) { - if(!(CURRENT_SC->SCp.phase & not_issued)) - printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC)); - - DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC)); - - DO_LOCK(flags); - append_SC(&ISSUE_SC, CURRENT_SC); - DO_UNLOCK(flags); - - CURRENT_SC = NULL; - } - - if(!DISCONNECTED_SC) { - DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC)); - return; - } - - RECONN_TARGET=-1; - - selid = GETPORT(SELID) & ~(1 << shpnt->this_id); - - if (selid==0) { - printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid); - return; - } - - for(target=7; !(selid & (1 << target)); target--) - ; - - if(selid & ~(1 << target)) { - printk("aha152x%d: multiple targets reconnected (%02x)\n", - HOSTNO, selid); - } - - - SETPORT(SCSIID, (shpnt->this_id << OID_) | target); - SETPORT(SCSISEQ, 0); - - SETRATE(HOSTDATA(shpnt)->syncrate[target]); - - RECONN_TARGET=target; - DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid); -} - -/* - * message in phase - * - handle initial message after reconnection to identify - * reconnecting nexus - * - queue command on DISCONNECTED_SC on DISCONNECT message - * - set completed flag on COMMAND COMPLETE - * (other completition code moved to busfree_run) - * - handle response to SDTR - * - clear synchronous transfer agreements on BUS RESET - * - * FIXME: what about SAVE POINTERS, RESTORE POINTERS? - * - */ -static void msgi_run(struct Scsi_Host *shpnt) -{ - for(;;) { - int sstat1 = GETPORT(SSTAT1); - - if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT)) - return; - - if(TESTLO(SSTAT0,SPIORDY)) { - DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); - return; - } - - ADDMSGI(GETPORT(SCSIDAT)); - -#if defined(AHA152X_DEBUG) - if (HOSTDATA(shpnt)->debug & debug_msgi) { - printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0)); - spi_print_msg(&MSGI(0)); - printk("\n"); - } -#endif - - if(!CURRENT_SC) { - if(LASTSTATE!=seldi) { - printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO); - } - - /* - * Handle reselection - */ - if(!(MSGI(0) & IDENTIFY_BASE)) { - printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO); - continue; - } - - CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f); - - if (!CURRENT_SC) { - show_queues(shpnt); - printk(KERN_ERR "aha152x%d: no disconnected command for target %d/%d\n", HOSTNO, RECONN_TARGET, MSGI(0) & 0x3f); - continue; - } - - DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC)); - - CURRENT_SC->SCp.Message = MSGI(0); - CURRENT_SC->SCp.phase &= ~disconnected; - - MSGILEN=0; - - /* next message if any */ - continue; - } - - CURRENT_SC->SCp.Message = MSGI(0); - - switch (MSGI(0)) { - case DISCONNECT: - if (!RECONNECT) - printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC)); - - CURRENT_SC->SCp.phase |= disconnected; - break; - - case COMMAND_COMPLETE: - if(CURRENT_SC->SCp.phase & completed) - DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC)); - - CURRENT_SC->SCp.phase |= completed; - break; - - case MESSAGE_REJECT: - if (SYNCNEG==1) { - printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC)); - SYNCNEG=2; /* negotiation completed */ - } else - printk(INFO_LEAD "inbound message (MESSAGE REJECT)\n", CMDINFO(CURRENT_SC)); - break; - - case SAVE_POINTERS: - break; - - case RESTORE_POINTERS: - break; - - case EXTENDED_MESSAGE: - if(MSGILEN<2 || MSGILENsynchronous) - break; - - printk(INFO_LEAD, CMDINFO(CURRENT_SC)); - spi_print_msg(&MSGI(0)); - printk("\n"); - - ticks = (MSGI(3) * 4 + 49) / 50; - - if (syncneg) { - /* negotiation in progress */ - if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) { - ADDMSGO(MESSAGE_REJECT); - printk(INFO_LEAD "received Synchronous Data Transfer Request invalid - rejected\n", CMDINFO(CURRENT_SC)); - break; - } - - SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); - } else if (ticks <= 9 && MSGI(4) >= 1) { - ADDMSGO(EXTENDED_MESSAGE); - ADDMSGO(3); - ADDMSGO(EXTENDED_SDTR); - if (ticks < 4) { - ticks = 4; - ADDMSGO(50); - } else - ADDMSGO(MSGI(3)); - - if (MSGI(4) > 8) - MSGI(4) = 8; - - ADDMSGO(MSGI(4)); - - SYNCRATE |= ((ticks - 2) << 4) + MSGI(4); - } else { - /* requested SDTR is too slow, do it asynchronously */ - printk(INFO_LEAD "Synchronous Data Transfer Request too slow - Rejecting\n", CMDINFO(CURRENT_SC)); - ADDMSGO(MESSAGE_REJECT); - } - - SYNCNEG=2; /* negotiation completed */ - SETRATE(SYNCRATE); - } - break; - - case BUS_DEVICE_RESET: - { - int i; - - for(i=0; i<8; i++) { - HOSTDATA(shpnt)->syncrate[i]=0; - HOSTDATA(shpnt)->syncneg[i]=0; - } - - } - break; - - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - case EXTENDED_WDTR: - default: - ADDMSGO(MESSAGE_REJECT); - break; - } - break; - } - - MSGILEN=0; - } -} - -static void msgi_end(struct Scsi_Host *shpnt) -{ - if(MSGILEN>0) - printk(WARN_LEAD "target left before message completed (%d)\n", CMDINFO(CURRENT_SC), MSGILEN); - - if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) { - DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC)); - SETPORT(SCSISIG, P_MSGI | SIG_ATNO); - } -} - -/* - * message out phase - * - */ -static void msgo_init(struct Scsi_Host *shpnt) -{ - if(MSGOLEN==0) { - if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) { - ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun)); - } else { - printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC)); - ADDMSGO(MESSAGE_REJECT); - } - } - -#if defined(AHA152X_DEBUG) - if(HOSTDATA(shpnt)->debug & debug_msgo) { - int i; - - printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC)); - for (i=0; iSCp.phase |= identified; - - if (MSGO(MSGO_I)==ABORT) - CURRENT_SC->SCp.phase |= aborted; - - if (MSGO(MSGO_I)==BUS_DEVICE_RESET) - CURRENT_SC->SCp.phase |= resetted; - - SETPORT(SCSIDAT, MSGO(MSGO_I++)); - } -} - -static void msgo_end(struct Scsi_Host *shpnt) -{ - if(MSGO_ISCp.sent_command) { - printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC)); - done(shpnt, DID_ERROR << 16); - return; - } - -#if defined(AHA152X_DEBUG) - if (HOSTDATA(shpnt)->debug & debug_cmd) { - printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC)); - __scsi_print_command(CURRENT_SC->cmnd); - } -#endif - - CMD_I=0; -} - -/* - * command phase - * - */ -static void cmd_run(struct Scsi_Host *shpnt) -{ - if(CMD_I==CURRENT_SC->cmd_len) { - DPRINTK(debug_cmd, DEBUG_LEAD "command already completely sent (%d/%d)", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len); - disp_ports(shpnt); - } - - while(CMD_Icmd_len) { - DPRINTK(debug_cmd, DEBUG_LEAD "command byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), CURRENT_SC->cmnd[CMD_I], CMD_I, CURRENT_SC->cmd_len); - - if(TESTLO(SSTAT0, SPIORDY)) { - DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); - return; - } - - SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]); - } -} - -static void cmd_end(struct Scsi_Host *shpnt) -{ - if(CMD_Icmd_len) - printk(ERR_LEAD "command sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len); - else - CURRENT_SC->SCp.sent_command++; -} - -/* - * status phase - * - */ -static void status_run(struct Scsi_Host *shpnt) -{ - if(TESTLO(SSTAT0,SPIORDY)) { - DPRINTK(debug_status, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC)); - return; - } - - CURRENT_SC->SCp.Status = GETPORT(SCSIDAT); - -#if defined(AHA152X_DEBUG) - if (HOSTDATA(shpnt)->debug & debug_status) { - printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status); - scsi_print_status(CURRENT_SC->SCp.Status); - printk("\n"); - } -#endif -} - -/* - * data in phase - * - */ -static void datai_init(struct Scsi_Host *shpnt) -{ - SETPORT(DMACNTRL0, RSTFIFO); - SETPORT(DMACNTRL0, RSTFIFO|ENDMA); - - SETPORT(SXFRCTL0, CH1|CLRSTCNT); - SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); - - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE); - - DATA_LEN=0; - DPRINTK(debug_datai, - DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n", - CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC), - scsi_get_resid(CURRENT_SC)); -} - -static void datai_run(struct Scsi_Host *shpnt) -{ - unsigned long the_time; - int fifodata, data_count; - - /* - * loop while the phase persists or the fifos are not empty - * - */ - while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) { - /* FIXME: maybe this should be done by setting up - * STCNT to trigger ENSWRAP interrupt, instead of - * polling for DFIFOFULL - */ - the_time=jiffies + 100*HZ; - while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time)) - barrier(); - - if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) { - printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC)); - disp_ports(shpnt); - break; - } - - if(TESTHI(DMASTAT, DFIFOFULL)) { - fifodata = 128; - } else { - the_time=jiffies + 100*HZ; - while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time)) - barrier(); - - if(TESTLO(SSTAT2, SEMPTY)) { - printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC)); - disp_ports(shpnt); - break; - } - - fifodata = GETPORT(FIFOSTAT); - } - - if(CURRENT_SC->SCp.this_residual>0) { - while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) { - data_count = fifodata>CURRENT_SC->SCp.this_residual ? - CURRENT_SC->SCp.this_residual : - fifodata; - fifodata -= data_count; - - if(data_count & 1) { - DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC)); - SETPORT(DMACNTRL0, ENDMA|_8BIT); - *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT); - CURRENT_SC->SCp.this_residual--; - DATA_LEN++; - SETPORT(DMACNTRL0, ENDMA); - } - - if(data_count > 1) { - DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count); - data_count >>= 1; - insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - DATA_LEN += 2 * data_count; - } - - if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; - } - } - } else if(fifodata>0) { - printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT)); - SETPORT(DMACNTRL0, ENDMA|_8BIT); - while(fifodata>0) { - int data; - data=GETPORT(DATAPORT); - DPRINTK(debug_datai, DEBUG_LEAD "data=%02x\n", CMDINFO(CURRENT_SC), data); - fifodata--; - DATA_LEN++; - } - SETPORT(DMACNTRL0, ENDMA|_8BIT); - } - } - - if(TESTLO(DMASTAT, INTSTAT) || - TESTLO(DMASTAT, DFIFOEMP) || - TESTLO(SSTAT2, SEMPTY) || - GETPORT(FIFOSTAT)>0) { - /* - * something went wrong, if there's something left in the fifos - * or the phase didn't change - */ - printk(ERR_LEAD "fifos should be empty and phase should have changed\n", CMDINFO(CURRENT_SC)); - disp_ports(shpnt); - } - - if(DATA_LEN!=GETSTCNT()) { - printk(ERR_LEAD - "manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d)", - CMDINFO(CURRENT_SC), DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, GETPORT(FIFOSTAT)); - disp_ports(shpnt); - mdelay(10000); - } -} - -static void datai_end(struct Scsi_Host *shpnt) -{ - CMD_INC_RESID(CURRENT_SC, -GETSTCNT()); - - DPRINTK(debug_datai, - DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n", - CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC), - scsi_get_resid(CURRENT_SC), GETSTCNT()); - - SETPORT(SXFRCTL0, CH1|CLRSTCNT); - SETPORT(DMACNTRL0, 0); -} - -/* - * data out phase - * - */ -static void datao_init(struct Scsi_Host *shpnt) -{ - SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO); - SETPORT(DMACNTRL0, WRITE_READ | ENDMA); - - SETPORT(SXFRCTL0, CH1|CLRSTCNT); - SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN); - - SETPORT(SIMODE0, 0); - SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE ); - - DATA_LEN = scsi_get_resid(CURRENT_SC); - - DPRINTK(debug_datao, - DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n", - CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC), - scsi_get_resid(CURRENT_SC)); -} - -static void datao_run(struct Scsi_Host *shpnt) -{ - unsigned long the_time; - int data_count; - - /* until phase changes or all data sent */ - while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) { - data_count = 128; - if(data_count > CURRENT_SC->SCp.this_residual) - data_count=CURRENT_SC->SCp.this_residual; - - if(TESTLO(DMASTAT, DFIFOEMP)) { - printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT)); - disp_ports(shpnt); - break; - } - - if(data_count & 1) { - SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT); - SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++); - CURRENT_SC->SCp.this_residual--; - CMD_INC_RESID(CURRENT_SC, -1); - SETPORT(DMACNTRL0,WRITE_READ|ENDMA); - } - - if(data_count > 1) { - data_count >>= 1; - outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count); - CURRENT_SC->SCp.ptr += 2 * data_count; - CURRENT_SC->SCp.this_residual -= 2 * data_count; - CMD_INC_RESID(CURRENT_SC, -2 * data_count); - } - - if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) { - /* advance to next buffer */ - CURRENT_SC->SCp.buffers_residual--; - CURRENT_SC->SCp.buffer++; - CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer); - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length; - } - - the_time=jiffies + 100*HZ; - while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time)) - barrier(); - - if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) { - printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC)); - disp_ports(shpnt); - break; - } - } -} - -static void datao_end(struct Scsi_Host *shpnt) -{ - if(TESTLO(DMASTAT, DFIFOEMP)) { - int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) - - GETSTCNT(); - - DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n", - CMDINFO(CURRENT_SC), - data_count, - DATA_LEN - scsi_get_resid(CURRENT_SC), - GETSTCNT()); - - CMD_INC_RESID(CURRENT_SC, data_count); - - data_count -= CURRENT_SC->SCp.ptr - - SG_ADDRESS(CURRENT_SC->SCp.buffer); - while(data_count>0) { - CURRENT_SC->SCp.buffer--; - CURRENT_SC->SCp.buffers_residual++; - data_count -= CURRENT_SC->SCp.buffer->length; - } - CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) - - data_count; - CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + - data_count; - } - - DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n", - CMDINFO(CURRENT_SC), - scsi_bufflen(CURRENT_SC), - scsi_get_resid(CURRENT_SC), - GETSTCNT()); - - SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT); - SETPORT(SXFRCTL0, CH1); - - SETPORT(DMACNTRL0, 0); -} - -/* - * figure out what state we're in - * - */ -static int update_state(struct Scsi_Host *shpnt) -{ - int dataphase=0; - unsigned int stat0 = GETPORT(SSTAT0); - unsigned int stat1 = GETPORT(SSTAT1); - - PREVSTATE = STATE; - STATE=unknown; - - if(stat1 & SCSIRSTI) { - STATE=rsti; - SETPORT(SCSISEQ,0); - SETPORT(SSTAT1,SCSIRSTI); - } else if(stat0 & SELDI && PREVSTATE==busfree) { - STATE=seldi; - } else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) { - STATE=seldo; - } else if(stat1 & SELTO) { - STATE=selto; - } else if(stat1 & BUSFREE) { - STATE=busfree; - SETPORT(SSTAT1,BUSFREE); - } else if(stat1 & SCSIPERR) { - STATE=parerr; - SETPORT(SSTAT1,SCSIPERR); - } else if(stat1 & REQINIT) { - switch(GETPORT(SCSISIG) & P_MASK) { - case P_MSGI: STATE=msgi; break; - case P_MSGO: STATE=msgo; break; - case P_DATAO: STATE=datao; break; - case P_DATAI: STATE=datai; break; - case P_STATUS: STATE=status; break; - case P_CMD: STATE=cmd; break; - } - dataphase=1; - } - - if((stat0 & SELDI) && STATE!=seldi && !dataphase) { - printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC)); - disp_ports(shpnt); - } - - if(STATE!=PREVSTATE) { - LASTSTATE=PREVSTATE; - } - - return dataphase; -} - -/* - * handle parity error - * - * FIXME: in which phase? - * - */ -static void parerr_run(struct Scsi_Host *shpnt) -{ - printk(ERR_LEAD "parity error\n", CMDINFO(CURRENT_SC)); - done(shpnt, DID_PARITY << 16); -} - -/* - * handle reset in - * - */ -static void rsti_run(struct Scsi_Host *shpnt) -{ - Scsi_Cmnd *ptr; - - printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO); - - ptr=DISCONNECTED_SC; - while(ptr) { - Scsi_Cmnd *next = SCNEXT(ptr); - - if (!ptr->device->soft_reset) { - remove_SC(&DISCONNECTED_SC, ptr); - - kfree(ptr->host_scribble); - ptr->host_scribble=NULL; - - ptr->result = DID_RESET << 16; - ptr->scsi_done(ptr); - } - - ptr = next; - } - - if(CURRENT_SC && !CURRENT_SC->device->soft_reset) - done(shpnt, DID_RESET << 16 ); -} - - -/* - * bottom-half handler - * - */ -static void is_complete(struct Scsi_Host *shpnt) -{ - int dataphase; - unsigned long flags; - int pending; - - if(!shpnt) - return; - - DO_LOCK(flags); - - if( HOSTDATA(shpnt)->service==0 ) { - DO_UNLOCK(flags); - return; - } - - HOSTDATA(shpnt)->service = 0; - - if(HOSTDATA(shpnt)->in_intr) { - DO_UNLOCK(flags); - /* aha152x_error never returns.. */ - aha152x_error(shpnt, "bottom-half already running!?"); - } - HOSTDATA(shpnt)->in_intr++; - - /* - * loop while there are interrupt conditions pending - * - */ - do { - unsigned long start = jiffies; - DO_UNLOCK(flags); - - dataphase=update_state(shpnt); - - DPRINTK(debug_phases, LEAD "start %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name); - - /* - * end previous state - * - */ - if(PREVSTATE!=STATE && states[PREVSTATE].end) - states[PREVSTATE].end(shpnt); - - /* - * disable SPIO mode if previous phase used it - * and this one doesn't - * - */ - if(states[PREVSTATE].spio && !states[STATE].spio) { - SETPORT(SXFRCTL0, CH1); - SETPORT(DMACNTRL0, 0); - if(CURRENT_SC) - CURRENT_SC->SCp.phase &= ~spiordy; - } - - /* - * accept current dataphase phase - * - */ - if(dataphase) { - SETPORT(SSTAT0, REQINIT); - SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK); - SETPORT(SSTAT1, PHASECHG); - } - - /* - * enable SPIO mode if previous didn't use it - * and this one does - * - */ - if(!states[PREVSTATE].spio && states[STATE].spio) { - SETPORT(DMACNTRL0, 0); - SETPORT(SXFRCTL0, CH1|SPIOEN); - if(CURRENT_SC) - CURRENT_SC->SCp.phase |= spiordy; - } - - /* - * initialize for new state - * - */ - if(PREVSTATE!=STATE && states[STATE].init) - states[STATE].init(shpnt); - - /* - * handle current state - * - */ - if(states[STATE].run) - states[STATE].run(shpnt); - else - printk(ERR_LEAD "unexpected state (%x)\n", CMDINFO(CURRENT_SC), STATE); - - /* - * setup controller to interrupt on - * the next expected condition and - * loop if it's already there - * - */ - DO_LOCK(flags); - pending=setup_expected_interrupts(shpnt); -#if defined(AHA152X_STAT) - HOSTDATA(shpnt)->count[STATE]++; - if(PREVSTATE!=STATE) - HOSTDATA(shpnt)->count_trans[STATE]++; - HOSTDATA(shpnt)->time[STATE] += jiffies-start; -#endif - - DPRINTK(debug_phases, LEAD "end %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name); - } while(pending); - - /* - * enable interrupts and leave bottom-half - * - */ - HOSTDATA(shpnt)->in_intr--; - SETBITS(DMACNTRL0, INTEN); - DO_UNLOCK(flags); -} - - -/* - * Dump the current driver status and panic - */ -static void aha152x_error(struct Scsi_Host *shpnt, char *msg) -{ - printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg); - show_queues(shpnt); - panic("aha152x panic\n"); -} - -/* - * Display registers of AIC-6260 - */ -static void disp_ports(struct Scsi_Host *shpnt) -{ -#if defined(AHA152X_DEBUG) - int s; - - printk("\n%s: %s(%s) ", - CURRENT_SC ? "busy" : "waiting", - states[STATE].name, - states[PREVSTATE].name); - - s = GETPORT(SCSISEQ); - printk("SCSISEQ( "); - if (s & TEMODEO) - printk("TARGET MODE "); - if (s & ENSELO) - printk("SELO "); - if (s & ENSELI) - printk("SELI "); - if (s & ENRESELI) - printk("RESELI "); - if (s & ENAUTOATNO) - printk("AUTOATNO "); - if (s & ENAUTOATNI) - printk("AUTOATNI "); - if (s & ENAUTOATNP) - printk("AUTOATNP "); - if (s & SCSIRSTO) - printk("SCSIRSTO "); - printk(");"); - - printk(" SCSISIG("); - s = GETPORT(SCSISIG); - switch (s & P_MASK) { - case P_DATAO: - printk("DATA OUT"); - break; - case P_DATAI: - printk("DATA IN"); - break; - case P_CMD: - printk("COMMAND"); - break; - case P_STATUS: - printk("STATUS"); - break; - case P_MSGO: - printk("MESSAGE OUT"); - break; - case P_MSGI: - printk("MESSAGE IN"); - break; - default: - printk("*invalid*"); - break; - } - - printk("); "); - - printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - - printk("SSTAT( "); - s = GETPORT(SSTAT0); - if (s & TARGET) - printk("TARGET "); - if (s & SELDO) - printk("SELDO "); - if (s & SELDI) - printk("SELDI "); - if (s & SELINGO) - printk("SELINGO "); - if (s & SWRAP) - printk("SWRAP "); - if (s & SDONE) - printk("SDONE "); - if (s & SPIORDY) - printk("SPIORDY "); - if (s & DMADONE) - printk("DMADONE "); - - s = GETPORT(SSTAT1); - if (s & SELTO) - printk("SELTO "); - if (s & ATNTARG) - printk("ATNTARG "); - if (s & SCSIRSTI) - printk("SCSIRSTI "); - if (s & PHASEMIS) - printk("PHASEMIS "); - if (s & BUSFREE) - printk("BUSFREE "); - if (s & SCSIPERR) - printk("SCSIPERR "); - if (s & PHASECHG) - printk("PHASECHG "); - if (s & REQINIT) - printk("REQINIT "); - printk("); "); - - - printk("SSTAT( "); - - s = GETPORT(SSTAT0) & GETPORT(SIMODE0); - - if (s & TARGET) - printk("TARGET "); - if (s & SELDO) - printk("SELDO "); - if (s & SELDI) - printk("SELDI "); - if (s & SELINGO) - printk("SELINGO "); - if (s & SWRAP) - printk("SWRAP "); - if (s & SDONE) - printk("SDONE "); - if (s & SPIORDY) - printk("SPIORDY "); - if (s & DMADONE) - printk("DMADONE "); - - s = GETPORT(SSTAT1) & GETPORT(SIMODE1); - - if (s & SELTO) - printk("SELTO "); - if (s & ATNTARG) - printk("ATNTARG "); - if (s & SCSIRSTI) - printk("SCSIRSTI "); - if (s & PHASEMIS) - printk("PHASEMIS "); - if (s & BUSFREE) - printk("BUSFREE "); - if (s & SCSIPERR) - printk("SCSIPERR "); - if (s & PHASECHG) - printk("PHASECHG "); - if (s & REQINIT) - printk("REQINIT "); - printk("); "); - - printk("SXFRCTL0( "); - - s = GETPORT(SXFRCTL0); - if (s & SCSIEN) - printk("SCSIEN "); - if (s & DMAEN) - printk("DMAEN "); - if (s & CH1) - printk("CH1 "); - if (s & CLRSTCNT) - printk("CLRSTCNT "); - if (s & SPIOEN) - printk("SPIOEN "); - if (s & CLRCH1) - printk("CLRCH1 "); - printk("); "); - - printk("SIGNAL( "); - - s = GETPORT(SCSISIG); - if (s & SIG_ATNI) - printk("ATNI "); - if (s & SIG_SELI) - printk("SELI "); - if (s & SIG_BSYI) - printk("BSYI "); - if (s & SIG_REQI) - printk("REQI "); - if (s & SIG_ACKI) - printk("ACKI "); - printk("); "); - - printk("SELID (%02x), ", GETPORT(SELID)); - - printk("STCNT (%d), ", GETSTCNT()); - - printk("SSTAT2( "); - - s = GETPORT(SSTAT2); - if (s & SOFFSET) - printk("SOFFSET "); - if (s & SEMPTY) - printk("SEMPTY "); - if (s & SFULL) - printk("SFULL "); - printk("); SFCNT (%d); ", s & (SFULL | SFCNT)); - - s = GETPORT(SSTAT3); - printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); - - printk("SSTAT4( "); - s = GETPORT(SSTAT4); - if (s & SYNCERR) - printk("SYNCERR "); - if (s & FWERR) - printk("FWERR "); - if (s & FRERR) - printk("FRERR "); - printk("); "); - - printk("DMACNTRL0( "); - s = GETPORT(DMACNTRL0); - printk("%s ", s & _8BIT ? "8BIT" : "16BIT"); - printk("%s ", s & DMA ? "DMA" : "PIO"); - printk("%s ", s & WRITE_READ ? "WRITE" : "READ"); - if (s & ENDMA) - printk("ENDMA "); - if (s & INTEN) - printk("INTEN "); - if (s & RSTFIFO) - printk("RSTFIFO "); - if (s & SWINT) - printk("SWINT "); - printk("); "); - - printk("DMASTAT( "); - s = GETPORT(DMASTAT); - if (s & ATDONE) - printk("ATDONE "); - if (s & WORDRDY) - printk("WORDRDY "); - if (s & DFIFOFULL) - printk("DFIFOFULL "); - if (s & DFIFOEMP) - printk("DFIFOEMP "); - printk(")\n"); -#endif -} - -/* - * display enabled interrupts - */ -static void disp_enintr(struct Scsi_Host *shpnt) -{ - int s; - - printk(KERN_DEBUG "enabled interrupts ( "); - - s = GETPORT(SIMODE0); - if (s & ENSELDO) - printk("ENSELDO "); - if (s & ENSELDI) - printk("ENSELDI "); - if (s & ENSELINGO) - printk("ENSELINGO "); - if (s & ENSWRAP) - printk("ENSWRAP "); - if (s & ENSDONE) - printk("ENSDONE "); - if (s & ENSPIORDY) - printk("ENSPIORDY "); - if (s & ENDMADONE) - printk("ENDMADONE "); - - s = GETPORT(SIMODE1); - if (s & ENSELTIMO) - printk("ENSELTIMO "); - if (s & ENATNTARG) - printk("ENATNTARG "); - if (s & ENPHASEMIS) - printk("ENPHASEMIS "); - if (s & ENBUSFREE) - printk("ENBUSFREE "); - if (s & ENSCSIPERR) - printk("ENSCSIPERR "); - if (s & ENPHASECHG) - printk("ENPHASECHG "); - if (s & ENREQINIT) - printk("ENREQINIT "); - printk(")\n"); -} - -/* - * Show the command data of a command - */ -static void show_command(Scsi_Cmnd *ptr) -{ - scmd_printk(KERN_DEBUG, ptr, "%p: cmnd=(", ptr); - - __scsi_print_command(ptr->cmnd); - - printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |", - scsi_bufflen(ptr), scsi_get_resid(ptr)); - - if (ptr->SCp.phase & not_issued) - printk("not issued|"); - if (ptr->SCp.phase & selecting) - printk("selecting|"); - if (ptr->SCp.phase & identified) - printk("identified|"); - if (ptr->SCp.phase & disconnected) - printk("disconnected|"); - if (ptr->SCp.phase & completed) - printk("completed|"); - if (ptr->SCp.phase & spiordy) - printk("spiordy|"); - if (ptr->SCp.phase & syncneg) - printk("syncneg|"); - if (ptr->SCp.phase & aborted) - printk("aborted|"); - if (ptr->SCp.phase & resetted) - printk("resetted|"); - if( SCDATA(ptr) ) { - printk("; next=0x%p\n", SCNEXT(ptr)); - } else { - printk("; next=(host scribble NULL)\n"); - } -} - -/* - * Dump the queued data - */ -static void show_queues(struct Scsi_Host *shpnt) -{ - Scsi_Cmnd *ptr; - unsigned long flags; - - DO_LOCK(flags); - printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n"); - for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) - show_command(ptr); - DO_UNLOCK(flags); - - printk(KERN_DEBUG "current_SC:\n"); - if (CURRENT_SC) - show_command(CURRENT_SC); - else - printk(KERN_DEBUG "none\n"); - - printk(KERN_DEBUG "disconnected_SC:\n"); - for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL) - show_command(ptr); - - disp_ports(shpnt); - disp_enintr(shpnt); -} - -#undef SPRINTF -#define SPRINTF(args...) pos += sprintf(pos, ## args) - -static int get_command(char *pos, Scsi_Cmnd * ptr) -{ - char *start = pos; - int i; - - SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ", - (unsigned int) ptr, ptr->device->id, ptr->device->lun); - - for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++) - SPRINTF("0x%02x ", ptr->cmnd[i]); - - SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |", - scsi_get_resid(ptr), ptr->SCp.this_residual, - ptr->SCp.buffers_residual); - - if (ptr->SCp.phase & not_issued) - SPRINTF("not issued|"); - if (ptr->SCp.phase & selecting) - SPRINTF("selecting|"); - if (ptr->SCp.phase & disconnected) - SPRINTF("disconnected|"); - if (ptr->SCp.phase & aborted) - SPRINTF("aborted|"); - if (ptr->SCp.phase & identified) - SPRINTF("identified|"); - if (ptr->SCp.phase & completed) - SPRINTF("completed|"); - if (ptr->SCp.phase & spiordy) - SPRINTF("spiordy|"); - if (ptr->SCp.phase & syncneg) - SPRINTF("syncneg|"); - SPRINTF("; next=0x%p\n", SCNEXT(ptr)); - - return (pos - start); -} - -static int get_ports(struct Scsi_Host *shpnt, char *pos) -{ - char *start = pos; - int s; - - SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name); - - s = GETPORT(SCSISEQ); - SPRINTF("SCSISEQ( "); - if (s & TEMODEO) - SPRINTF("TARGET MODE "); - if (s & ENSELO) - SPRINTF("SELO "); - if (s & ENSELI) - SPRINTF("SELI "); - if (s & ENRESELI) - SPRINTF("RESELI "); - if (s & ENAUTOATNO) - SPRINTF("AUTOATNO "); - if (s & ENAUTOATNI) - SPRINTF("AUTOATNI "); - if (s & ENAUTOATNP) - SPRINTF("AUTOATNP "); - if (s & SCSIRSTO) - SPRINTF("SCSIRSTO "); - SPRINTF(");"); - - SPRINTF(" SCSISIG("); - s = GETPORT(SCSISIG); - switch (s & P_MASK) { - case P_DATAO: - SPRINTF("DATA OUT"); - break; - case P_DATAI: - SPRINTF("DATA IN"); - break; - case P_CMD: - SPRINTF("COMMAND"); - break; - case P_STATUS: - SPRINTF("STATUS"); - break; - case P_MSGO: - SPRINTF("MESSAGE OUT"); - break; - case P_MSGI: - SPRINTF("MESSAGE IN"); - break; - default: - SPRINTF("*invalid*"); - break; - } - - SPRINTF("); "); - - SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo"); - - SPRINTF("SSTAT( "); - s = GETPORT(SSTAT0); - if (s & TARGET) - SPRINTF("TARGET "); - if (s & SELDO) - SPRINTF("SELDO "); - if (s & SELDI) - SPRINTF("SELDI "); - if (s & SELINGO) - SPRINTF("SELINGO "); - if (s & SWRAP) - SPRINTF("SWRAP "); - if (s & SDONE) - SPRINTF("SDONE "); - if (s & SPIORDY) - SPRINTF("SPIORDY "); - if (s & DMADONE) - SPRINTF("DMADONE "); - - s = GETPORT(SSTAT1); - if (s & SELTO) - SPRINTF("SELTO "); - if (s & ATNTARG) - SPRINTF("ATNTARG "); - if (s & SCSIRSTI) - SPRINTF("SCSIRSTI "); - if (s & PHASEMIS) - SPRINTF("PHASEMIS "); - if (s & BUSFREE) - SPRINTF("BUSFREE "); - if (s & SCSIPERR) - SPRINTF("SCSIPERR "); - if (s & PHASECHG) - SPRINTF("PHASECHG "); - if (s & REQINIT) - SPRINTF("REQINIT "); - SPRINTF("); "); - - - SPRINTF("SSTAT( "); - - s = GETPORT(SSTAT0) & GETPORT(SIMODE0); - - if (s & TARGET) - SPRINTF("TARGET "); - if (s & SELDO) - SPRINTF("SELDO "); - if (s & SELDI) - SPRINTF("SELDI "); - if (s & SELINGO) - SPRINTF("SELINGO "); - if (s & SWRAP) - SPRINTF("SWRAP "); - if (s & SDONE) - SPRINTF("SDONE "); - if (s & SPIORDY) - SPRINTF("SPIORDY "); - if (s & DMADONE) - SPRINTF("DMADONE "); - - s = GETPORT(SSTAT1) & GETPORT(SIMODE1); - - if (s & SELTO) - SPRINTF("SELTO "); - if (s & ATNTARG) - SPRINTF("ATNTARG "); - if (s & SCSIRSTI) - SPRINTF("SCSIRSTI "); - if (s & PHASEMIS) - SPRINTF("PHASEMIS "); - if (s & BUSFREE) - SPRINTF("BUSFREE "); - if (s & SCSIPERR) - SPRINTF("SCSIPERR "); - if (s & PHASECHG) - SPRINTF("PHASECHG "); - if (s & REQINIT) - SPRINTF("REQINIT "); - SPRINTF("); "); - - SPRINTF("SXFRCTL0( "); - - s = GETPORT(SXFRCTL0); - if (s & SCSIEN) - SPRINTF("SCSIEN "); - if (s & DMAEN) - SPRINTF("DMAEN "); - if (s & CH1) - SPRINTF("CH1 "); - if (s & CLRSTCNT) - SPRINTF("CLRSTCNT "); - if (s & SPIOEN) - SPRINTF("SPIOEN "); - if (s & CLRCH1) - SPRINTF("CLRCH1 "); - SPRINTF("); "); - - SPRINTF("SIGNAL( "); - - s = GETPORT(SCSISIG); - if (s & SIG_ATNI) - SPRINTF("ATNI "); - if (s & SIG_SELI) - SPRINTF("SELI "); - if (s & SIG_BSYI) - SPRINTF("BSYI "); - if (s & SIG_REQI) - SPRINTF("REQI "); - if (s & SIG_ACKI) - SPRINTF("ACKI "); - SPRINTF("); "); - - SPRINTF("SELID(%02x), ", GETPORT(SELID)); - - SPRINTF("STCNT(%d), ", GETSTCNT()); - - SPRINTF("SSTAT2( "); - - s = GETPORT(SSTAT2); - if (s & SOFFSET) - SPRINTF("SOFFSET "); - if (s & SEMPTY) - SPRINTF("SEMPTY "); - if (s & SFULL) - SPRINTF("SFULL "); - SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT)); - - s = GETPORT(SSTAT3); - SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f); - - SPRINTF("SSTAT4( "); - s = GETPORT(SSTAT4); - if (s & SYNCERR) - SPRINTF("SYNCERR "); - if (s & FWERR) - SPRINTF("FWERR "); - if (s & FRERR) - SPRINTF("FRERR "); - SPRINTF("); "); - - SPRINTF("DMACNTRL0( "); - s = GETPORT(DMACNTRL0); - SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT"); - SPRINTF("%s ", s & DMA ? "DMA" : "PIO"); - SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ"); - if (s & ENDMA) - SPRINTF("ENDMA "); - if (s & INTEN) - SPRINTF("INTEN "); - if (s & RSTFIFO) - SPRINTF("RSTFIFO "); - if (s & SWINT) - SPRINTF("SWINT "); - SPRINTF("); "); - - SPRINTF("DMASTAT( "); - s = GETPORT(DMASTAT); - if (s & ATDONE) - SPRINTF("ATDONE "); - if (s & WORDRDY) - SPRINTF("WORDRDY "); - if (s & DFIFOFULL) - SPRINTF("DFIFOFULL "); - if (s & DFIFOEMP) - SPRINTF("DFIFOEMP "); - SPRINTF(")\n"); - - SPRINTF("enabled interrupts( "); - - s = GETPORT(SIMODE0); - if (s & ENSELDO) - SPRINTF("ENSELDO "); - if (s & ENSELDI) - SPRINTF("ENSELDI "); - if (s & ENSELINGO) - SPRINTF("ENSELINGO "); - if (s & ENSWRAP) - SPRINTF("ENSWRAP "); - if (s & ENSDONE) - SPRINTF("ENSDONE "); - if (s & ENSPIORDY) - SPRINTF("ENSPIORDY "); - if (s & ENDMADONE) - SPRINTF("ENDMADONE "); - - s = GETPORT(SIMODE1); - if (s & ENSELTIMO) - SPRINTF("ENSELTIMO "); - if (s & ENATNTARG) - SPRINTF("ENATNTARG "); - if (s & ENPHASEMIS) - SPRINTF("ENPHASEMIS "); - if (s & ENBUSFREE) - SPRINTF("ENBUSFREE "); - if (s & ENSCSIPERR) - SPRINTF("ENSCSIPERR "); - if (s & ENPHASECHG) - SPRINTF("ENPHASECHG "); - if (s & ENREQINIT) - SPRINTF("ENREQINIT "); - SPRINTF(")\n"); - - return (pos - start); -} - -static int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt) -{ - if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0) - return -EINVAL; - -#if defined(AHA152X_DEBUG) - if(length>14 && strncmp("debug ", buffer+8, 6)==0) { - int debug = HOSTDATA(shpnt)->debug; - - HOSTDATA(shpnt)->debug = simple_strtoul(buffer+14, NULL, 0); - - printk(KERN_INFO "aha152x%d: debugging options set to 0x%04x (were 0x%04x)\n", HOSTNO, HOSTDATA(shpnt)->debug, debug); - } else -#endif -#if defined(AHA152X_STAT) - if(length>13 && strncmp("reset", buffer+8, 5)==0) { - int i; - - HOSTDATA(shpnt)->total_commands=0; - HOSTDATA(shpnt)->disconnections=0; - HOSTDATA(shpnt)->busfree_without_any_action=0; - HOSTDATA(shpnt)->busfree_without_old_command=0; - HOSTDATA(shpnt)->busfree_without_new_command=0; - HOSTDATA(shpnt)->busfree_without_done_command=0; - HOSTDATA(shpnt)->busfree_with_check_condition=0; - for (i = idle; icount[i]=0; - HOSTDATA(shpnt)->count_trans[i]=0; - HOSTDATA(shpnt)->time[i]=0; - } - - printk(KERN_INFO "aha152x%d: stats reseted.\n", HOSTNO); - - } else -#endif - { - return -EINVAL; - } - - - return length; -} - -#undef SPRINTF -#define SPRINTF(args...) \ - do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) - -static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, - off_t offset, int length, int inout) -{ - int i; - char *pos = buffer; - Scsi_Cmnd *ptr; - unsigned long flags; - int thislength; - - DPRINTK(debug_procinfo, - KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n", - buffer, offset, length, shpnt->host_no, inout); - - - if (inout) - return aha152x_set_info(buffer, length, shpnt); - - SPRINTF(AHA152X_REVID "\n"); - - SPRINTF("ioports 0x%04lx to 0x%04lx\n", - shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1); - SPRINTF("interrupt 0x%02x\n", shpnt->irq); - SPRINTF("disconnection/reconnection %s\n", - RECONNECT ? "enabled" : "disabled"); - SPRINTF("parity checking %s\n", - PARITY ? "enabled" : "disabled"); - SPRINTF("synchronous transfers %s\n", - SYNCHRONOUS ? "enabled" : "disabled"); - SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands); - - if(SYNCHRONOUS) { - SPRINTF("synchronously operating targets (tick=50 ns):\n"); - for (i = 0; i < 8; i++) - if (HOSTDATA(shpnt)->syncrate[i] & 0x7f) - SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n", - i, - (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2), - (((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50, - HOSTDATA(shpnt)->syncrate[i] & 0x0f); - } -#if defined(AHA152X_DEBUG) -#define PDEBUG(flags,txt) \ - if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt); - - SPRINTF("enabled debugging options: "); - - PDEBUG(debug_procinfo, "procinfo"); - PDEBUG(debug_queue, "queue"); - PDEBUG(debug_intr, "interrupt"); - PDEBUG(debug_selection, "selection"); - PDEBUG(debug_msgo, "message out"); - PDEBUG(debug_msgi, "message in"); - PDEBUG(debug_status, "status"); - PDEBUG(debug_cmd, "command"); - PDEBUG(debug_datai, "data in"); - PDEBUG(debug_datao, "data out"); - PDEBUG(debug_eh, "eh"); - PDEBUG(debug_locking, "locks"); - PDEBUG(debug_phases, "phases"); - - SPRINTF("\n"); -#endif - - SPRINTF("\nqueue status:\n"); - DO_LOCK(flags); - if (ISSUE_SC) { - SPRINTF("not yet issued commands:\n"); - for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr)) - pos += get_command(pos, ptr); - } else - SPRINTF("no not yet issued commands\n"); - DO_UNLOCK(flags); - - if (CURRENT_SC) { - SPRINTF("current command:\n"); - pos += get_command(pos, CURRENT_SC); - } else - SPRINTF("no current command\n"); - - if (DISCONNECTED_SC) { - SPRINTF("disconnected commands:\n"); - for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr)) - pos += get_command(pos, ptr); - } else - SPRINTF("no disconnected commands\n"); - - pos += get_ports(shpnt, pos); - -#if defined(AHA152X_STAT) - SPRINTF("statistics:\n" - "total commands: %d\n" - "disconnections: %d\n" - "busfree with check condition: %d\n" - "busfree without old command: %d\n" - "busfree without new command: %d\n" - "busfree without done command: %d\n" - "busfree without any action: %d\n" - "state " - "transitions " - "count " - "time\n", - HOSTDATA(shpnt)->total_commands, - HOSTDATA(shpnt)->disconnections, - HOSTDATA(shpnt)->busfree_with_check_condition, - HOSTDATA(shpnt)->busfree_without_old_command, - HOSTDATA(shpnt)->busfree_without_new_command, - HOSTDATA(shpnt)->busfree_without_done_command, - HOSTDATA(shpnt)->busfree_without_any_action); - for(i=0; icount_trans[i], - HOSTDATA(shpnt)->count[i], - HOSTDATA(shpnt)->time[i]); - } -#endif - - DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: pos=%p\n", pos); - - thislength = pos - (buffer + offset); - DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: length=%d thislength=%d\n", length, thislength); - - if(thislength<0) { - DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: output too short\n"); - *start = NULL; - return 0; - } - - thislength = thislengthrequest_queue, BLK_BOUNCE_HIGH); - return 0; -} - -static struct scsi_host_template aha152x_driver_template = { - .module = THIS_MODULE, - .name = AHA152X_REVID, - .proc_name = "aha152x", - .proc_info = aha152x_proc_info, - .queuecommand = aha152x_queue, - .eh_abort_handler = aha152x_abort, - .eh_device_reset_handler = aha152x_device_reset, - .eh_bus_reset_handler = aha152x_bus_reset, - .eh_host_reset_handler = aha152x_host_reset, - .bios_param = aha152x_biosparam, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, - .slave_alloc = aha152x_adjust_queue, -}; - -#if !defined(PCMCIA) -static int setup_count; -static struct aha152x_setup setup[2]; - -/* possible i/o addresses for the AIC-6260; default first */ -static unsigned short ports[] = { 0x340, 0x140 }; - -#if !defined(SKIP_BIOSTEST) -/* possible locations for the Adaptec BIOS; defaults first */ -static unsigned int addresses[] = -{ - 0xdc000, /* default first */ - 0xc8000, - 0xcc000, - 0xd0000, - 0xd4000, - 0xd8000, - 0xe0000, - 0xeb800, /* VTech Platinum SMP */ - 0xf0000, -}; - -/* signatures for various AIC-6[23]60 based controllers. - The point in detecting signatures is to avoid useless and maybe - harmful probes on ports. I'm not sure that all listed boards pass - auto-configuration. For those which fail the BIOS signature is - obsolete, because user intervention to supply the configuration is - needed anyway. May be an information whether or not the BIOS supports - extended translation could be also useful here. */ -static struct signature { - unsigned char *signature; - int sig_offset; - int sig_length; -} signatures[] = -{ - { "Adaptec AHA-1520 BIOS", 0x102e, 21 }, - /* Adaptec 152x */ - { "Adaptec AHA-1520B", 0x000b, 17 }, - /* Adaptec 152x rev B */ - { "Adaptec AHA-1520B", 0x0026, 17 }, - /* Iomega Jaz Jet ISA (AIC6370Q) */ - { "Adaptec ASW-B626 BIOS", 0x1029, 21 }, - /* on-board controller */ - { "Adaptec BIOS: ASW-B626", 0x000f, 22 }, - /* on-board controller */ - { "Adaptec ASW-B626 S2", 0x2e6c, 19 }, - /* on-board controller */ - { "Adaptec BIOS:AIC-6360", 0x000c, 21 }, - /* on-board controller */ - { "ScsiPro SP-360 BIOS", 0x2873, 19 }, - /* ScsiPro-Controller */ - { "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 }, - /* Gigabyte Local-Bus-SCSI */ - { "Adaptec BIOS:AVA-282X", 0x000c, 21 }, - /* Adaptec 282x */ - { "Adaptec IBM Dock II SCSI", 0x2edd, 24 }, - /* IBM Thinkpad Dock II */ - { "Adaptec BIOS:AHA-1532P", 0x001c, 22 }, - /* IBM Thinkpad Dock II SCSI */ - { "DTC3520A Host Adapter BIOS", 0x318a, 26 }, - /* DTC 3520A ISA SCSI */ -}; -#endif /* !SKIP_BIOSTEST */ - -/* - * Test, if port_base is valid. - * - */ -static int aha152x_porttest(int io_port) -{ - int i; - - SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ - for (i = 0; i < 16; i++) - SETPORT(io_port + O_STACK, i); - - SETPORT(io_port + O_DMACNTRL1, 0); /* reset stack pointer */ - for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++) - ; - - return (i == 16); -} - -static int tc1550_porttest(int io_port) -{ - int i; - - SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ - for (i = 0; i < 16; i++) - SETPORT(io_port + O_STACK, i); - - SETPORT(io_port + O_TC_DMACNTRL1, 0); /* reset stack pointer */ - for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++) - ; - - return (i == 16); -} - - -static int checksetup(struct aha152x_setup *setup) -{ - int i; - for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++) - ; - - if (i == ARRAY_SIZE(ports)) - return 0; - - if (!request_region(setup->io_port, IO_RANGE, "aha152x")) { - printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port); - return 0; - } - - if( aha152x_porttest(setup->io_port) ) { - setup->tc1550=0; - } else if( tc1550_porttest(setup->io_port) ) { - setup->tc1550=1; - } else { - release_region(setup->io_port, IO_RANGE); - return 0; - } - - release_region(setup->io_port, IO_RANGE); - - if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX)) - return 0; - - if ((setup->scsiid < 0) || (setup->scsiid > 7)) - return 0; - - if ((setup->reconnect < 0) || (setup->reconnect > 1)) - return 0; - - if ((setup->parity < 0) || (setup->parity > 1)) - return 0; - - if ((setup->synchronous < 0) || (setup->synchronous > 1)) - return 0; - - if ((setup->ext_trans < 0) || (setup->ext_trans > 1)) - return 0; - - - return 1; -} - - -static int __init aha152x_init(void) -{ - int i, j, ok; -#if defined(AUTOCONF) - aha152x_config conf; -#endif -#ifdef __ISAPNP__ - struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL}; -#endif - - if ( setup_count ) { - printk(KERN_INFO "aha152x: processing commandline: "); - - for (i = 0; ipnpdev=pnpdev[i]; - pnpdev[i]=NULL; -#endif - } - } else { - printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port); - } - -#if defined(__ISAPNP__) - if( pnpdev[i] ) - pnp_device_detach(pnpdev[i]); -#endif - } - - return 0; -} - -static void __exit aha152x_exit(void) -{ - struct aha152x_hostdata *hd, *tmp; - - list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) { - struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata); - - aha152x_release(shost); - } -} - -module_init(aha152x_init); -module_exit(aha152x_exit); - -#if !defined(MODULE) -static int __init aha152x_setup(char *str) -{ -#if defined(AHA152X_DEBUG) - int ints[11]; -#else - int ints[10]; -#endif - get_options(str, ARRAY_SIZE(ints), ints); - - if(setup_count>=ARRAY_SIZE(setup)) { - printk(KERN_ERR "aha152x: you can only configure up to two controllers\n"); - return 1; - } - - setup[setup_count].conf = str; - setup[setup_count].io_port = ints[0] >= 1 ? ints[1] : 0x340; - setup[setup_count].irq = ints[0] >= 2 ? ints[2] : 11; - setup[setup_count].scsiid = ints[0] >= 3 ? ints[3] : 7; - setup[setup_count].reconnect = ints[0] >= 4 ? ints[4] : 1; - setup[setup_count].parity = ints[0] >= 5 ? ints[5] : 1; - setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1; - setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT; - setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0; -#if defined(AHA152X_DEBUG) - setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT; - if (ints[0] > 9) { - printk(KERN_NOTICE "aha152x: usage: aha152x=[,[," - "[,[,[,[,[,[,]]]]]]]]\n"); -#else - if (ints[0] > 8) { /*}*/ - printk(KERN_NOTICE "aha152x: usage: aha152x=[,[," - "[,[,[,[,[,]]]]]]]\n"); -#endif - } else { - setup_count++; - return 0; - } - - return 1; -} -__setup("aha152x=", aha152x_setup); -#endif - -#endif /* !PCMCIA */ diff --git a/ANDROID_3.4.5/drivers/scsi/aha152x.h b/ANDROID_3.4.5/drivers/scsi/aha152x.h deleted file mode 100644 index ac4bfa43..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aha152x.h +++ /dev/null @@ -1,337 +0,0 @@ -#ifndef _AHA152X_H -#define _AHA152X_H - -/* - * $Id: aha152x.h,v 2.7 2004/01/24 11:39:03 fischer Exp $ - */ - -/* number of queueable commands - (unless we support more than 1 cmd_per_lun this should do) */ -#define AHA152X_MAXQUEUE 7 - -#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.7 $" - -/* port addresses */ -#define SCSISEQ (HOSTIOPORT0+0x00) /* SCSI sequence control */ -#define SXFRCTL0 (HOSTIOPORT0+0x01) /* SCSI transfer control 0 */ -#define SXFRCTL1 (HOSTIOPORT0+0x02) /* SCSI transfer control 1 */ -#define SCSISIG (HOSTIOPORT0+0x03) /* SCSI signal in/out */ -#define SCSIRATE (HOSTIOPORT0+0x04) /* SCSI rate control */ -#define SELID (HOSTIOPORT0+0x05) /* selection/reselection ID */ -#define SCSIID SELID /* SCSI ID */ -#define SCSIDAT (HOSTIOPORT0+0x06) /* SCSI latched data */ -#define SCSIBUS (HOSTIOPORT0+0x07) /* SCSI data bus */ -#define STCNT0 (HOSTIOPORT0+0x08) /* SCSI transfer count 0 */ -#define STCNT1 (HOSTIOPORT0+0x09) /* SCSI transfer count 1 */ -#define STCNT2 (HOSTIOPORT0+0x0a) /* SCSI transfer count 2 */ -#define SSTAT0 (HOSTIOPORT0+0x0b) /* SCSI interrupt status 0 */ -#define SSTAT1 (HOSTIOPORT0+0x0c) /* SCSI interrupt status 1 */ -#define SSTAT2 (HOSTIOPORT0+0x0d) /* SCSI interrupt status 2 */ -#define SCSITEST (HOSTIOPORT0+0x0e) /* SCSI test control */ -#define SSTAT3 SCSITEST /* SCSI interrupt status 3 */ -#define SSTAT4 (HOSTIOPORT0+0x0f) /* SCSI status 4 */ -#define SIMODE0 (HOSTIOPORT1+0x10) /* SCSI interrupt mode 0 */ -#define SIMODE1 (HOSTIOPORT1+0x11) /* SCSI interrupt mode 1 */ -#define DMACNTRL0 (HOSTIOPORT1+0x12) /* DMA control 0 */ -#define DMACNTRL1 (HOSTIOPORT1+0x13) /* DMA control 1 */ -#define DMASTAT (HOSTIOPORT1+0x14) /* DMA status */ -#define FIFOSTAT (HOSTIOPORT1+0x15) /* FIFO status */ -#define DATAPORT (HOSTIOPORT1+0x16) /* DATA port */ -#define BRSTCNTRL (HOSTIOPORT1+0x18) /* burst control */ -#define PORTA (HOSTIOPORT1+0x1a) /* PORT A */ -#define PORTB (HOSTIOPORT1+0x1b) /* PORT B */ -#define REV (HOSTIOPORT1+0x1c) /* revision */ -#define STACK (HOSTIOPORT1+0x1d) /* stack */ -#define TEST (HOSTIOPORT1+0x1e) /* test register */ - -#define IO_RANGE 0x20 - -/* used in aha152x_porttest */ -#define O_PORTA 0x1a /* PORT A */ -#define O_PORTB 0x1b /* PORT B */ -#define O_DMACNTRL1 0x13 /* DMA control 1 */ -#define O_STACK 0x1d /* stack */ - -/* used in tc1550_porttest */ -#define O_TC_PORTA 0x0a /* PORT A */ -#define O_TC_PORTB 0x0b /* PORT B */ -#define O_TC_DMACNTRL1 0x03 /* DMA control 1 */ -#define O_TC_STACK 0x0d /* stack */ - -/* bits and bitmasks to ports */ - -/* SCSI sequence control */ -#define TEMODEO 0x80 -#define ENSELO 0x40 -#define ENSELI 0x20 -#define ENRESELI 0x10 -#define ENAUTOATNO 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNP 0x02 -#define SCSIRSTO 0x01 - -/* SCSI transfer control 0 */ -#define SCSIEN 0x80 -#define DMAEN 0x40 -#define CH1 0x20 -#define CLRSTCNT 0x10 -#define SPIOEN 0x08 -#define CLRCH1 0x02 - -/* SCSI transfer control 1 */ -#define BITBUCKET 0x80 -#define SWRAPEN 0x40 -#define ENSPCHK 0x20 -#define STIMESEL 0x18 /* mask */ -#define STIMESEL_ 3 -#define ENSTIMER 0x04 -#define BYTEALIGN 0x02 - -/* SCSI signal IN */ -#define SIG_CDI 0x80 -#define SIG_IOI 0x40 -#define SIG_MSGI 0x20 -#define SIG_ATNI 0x10 -#define SIG_SELI 0x08 -#define SIG_BSYI 0x04 -#define SIG_REQI 0x02 -#define SIG_ACKI 0x01 - -/* SCSI Phases */ -#define P_MASK (SIG_MSGI|SIG_CDI|SIG_IOI) -#define P_DATAO (0) -#define P_DATAI (SIG_IOI) -#define P_CMD (SIG_CDI) -#define P_STATUS (SIG_CDI|SIG_IOI) -#define P_MSGO (SIG_MSGI|SIG_CDI) -#define P_MSGI (SIG_MSGI|SIG_CDI|SIG_IOI) - -/* SCSI signal OUT */ -#define SIG_CDO 0x80 -#define SIG_IOO 0x40 -#define SIG_MSGO 0x20 -#define SIG_ATNO 0x10 -#define SIG_SELO 0x08 -#define SIG_BSYO 0x04 -#define SIG_REQO 0x02 -#define SIG_ACKO 0x01 - -/* SCSI rate control */ -#define SXFR 0x70 /* mask */ -#define SXFR_ 4 -#define SOFS 0x0f /* mask */ - -/* SCSI ID */ -#define OID 0x70 -#define OID_ 4 -#define TID 0x07 - -/* SCSI transfer count */ -#define GETSTCNT() ( (GETPORT(STCNT2)<<16) \ - + (GETPORT(STCNT1)<< 8) \ - + GETPORT(STCNT0) ) - -#define SETSTCNT(X) { SETPORT(STCNT2, ((X) & 0xFF0000) >> 16); \ - SETPORT(STCNT1, ((X) & 0x00FF00) >> 8); \ - SETPORT(STCNT0, ((X) & 0x0000FF) ); } - -/* SCSI interrupt status */ -#define TARGET 0x80 -#define SELDO 0x40 -#define SELDI 0x20 -#define SELINGO 0x10 -#define SWRAP 0x08 -#define SDONE 0x04 -#define SPIORDY 0x02 -#define DMADONE 0x01 - -#define SETSDONE 0x80 -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRSWRAP 0x08 -#define CLRSDONE 0x04 -#define CLRSPIORDY 0x02 -#define CLRDMADONE 0x01 - -/* SCSI status 1 */ -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define PHASECHG 0x02 -#define REQINIT 0x01 - -#define CLRSELTIMO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRPHASECHG 0x02 -#define CLRREQINIT 0x01 - -/* SCSI status 2 */ -#define SOFFSET 0x20 -#define SEMPTY 0x10 -#define SFULL 0x08 -#define SFCNT 0x07 /* mask */ - -/* SCSI status 3 */ -#define SCSICNT 0xf0 /* mask */ -#define SCSICNT_ 4 -#define OFFCNT 0x0f /* mask */ - -/* SCSI TEST control */ -#define SCTESTU 0x08 -#define SCTESTD 0x04 -#define STCTEST 0x01 - -/* SCSI status 4 */ -#define SYNCERR 0x04 -#define FWERR 0x02 -#define FRERR 0x01 - -#define CLRSYNCERR 0x04 -#define CLRFWERR 0x02 -#define CLRFRERR 0x01 - -/* SCSI interrupt mode 0 */ -#define ENSELDO 0x40 -#define ENSELDI 0x20 -#define ENSELINGO 0x10 -#define ENSWRAP 0x08 -#define ENSDONE 0x04 -#define ENSPIORDY 0x02 -#define ENDMADONE 0x01 - -/* SCSI interrupt mode 1 */ -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENPHASECHG 0x02 -#define ENREQINIT 0x01 - -/* DMA control 0 */ -#define ENDMA 0x80 -#define _8BIT 0x40 -#define DMA 0x20 -#define WRITE_READ 0x08 -#define INTEN 0x04 -#define RSTFIFO 0x02 -#define SWINT 0x01 - -/* DMA control 1 */ -#define PWRDWN 0x80 -#define STK 0x07 /* mask */ - -/* DMA status */ -#define ATDONE 0x80 -#define WORDRDY 0x40 -#define INTSTAT 0x20 -#define DFIFOFULL 0x10 -#define DFIFOEMP 0x08 - -/* BURST control */ -#define BON 0xf0 -#define BOFF 0x0f - -/* TEST REGISTER */ -#define BOFFTMR 0x40 -#define BONTMR 0x20 -#define STCNTH 0x10 -#define STCNTM 0x08 -#define STCNTL 0x04 -#define SCSIBLK 0x02 -#define DMABLK 0x01 - -/* On the AHA-152x board PORTA and PORTB contain - some information about the board's configuration. */ -typedef union { - struct { - unsigned reserved:2; /* reserved */ - unsigned tardisc:1; /* Target disconnect: 0=disabled, 1=enabled */ - unsigned syncneg:1; /* Initial sync neg: 0=disabled, 1=enabled */ - unsigned msgclasses:2; /* Message classes - 0=#4 - 1=#0, #1, #2, #3, #4 - 2=#0, #3, #4 - 3=#0, #4 - */ - unsigned boot:1; /* boot: 0=disabled, 1=enabled */ - unsigned dma:1; /* Transfer mode: 0=PIO; 1=DMA */ - unsigned id:3; /* SCSI-id */ - unsigned irq:2; /* IRQ-Channel: 0,3=12, 1=10, 2=11 */ - unsigned dmachan:2; /* DMA-Channel: 0=0, 1=5, 2=6, 3=7 */ - unsigned parity:1; /* SCSI-parity: 1=enabled 0=disabled */ - } fields; - unsigned short port; -} aha152x_config ; - -#define cf_parity fields.parity -#define cf_dmachan fields.dmachan -#define cf_irq fields.irq -#define cf_id fields.id -#define cf_dma fields.dma -#define cf_boot fields.boot -#define cf_msgclasses fields.msgclasses -#define cf_syncneg fields.syncneg -#define cf_tardisc fields.tardisc -#define cf_port port - -/* Some macros to manipulate ports and their bits */ - -#define SETPORT(PORT, VAL) outb( (VAL), (PORT) ) -#define GETPORT(PORT) inb( PORT ) -#define SETBITS(PORT, BITS) outb( (inb(PORT) | (BITS)), (PORT) ) -#define CLRBITS(PORT, BITS) outb( (inb(PORT) & ~(BITS)), (PORT) ) -#define TESTHI(PORT, BITS) ((inb(PORT) & (BITS)) == (BITS)) -#define TESTLO(PORT, BITS) ((inb(PORT) & (BITS)) == 0) - -#define SETRATE(RATE) SETPORT(SCSIRATE,(RATE) & 0x7f) - -#if defined(AHA152X_DEBUG) -enum { - debug_procinfo = 0x0001, - debug_queue = 0x0002, - debug_locking = 0x0004, - debug_intr = 0x0008, - debug_selection = 0x0010, - debug_msgo = 0x0020, - debug_msgi = 0x0040, - debug_status = 0x0080, - debug_cmd = 0x0100, - debug_datai = 0x0200, - debug_datao = 0x0400, - debug_eh = 0x0800, - debug_done = 0x1000, - debug_phases = 0x2000, -}; -#endif - -/* for the pcmcia stub */ -struct aha152x_setup { - int io_port; - int irq; - int scsiid; - int reconnect; - int parity; - int synchronous; - int delay; - int ext_trans; - int tc1550; -#if defined(AHA152X_DEBUG) - int debug; -#endif - char *conf; -}; - -struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *); -void aha152x_release(struct Scsi_Host *); -int aha152x_host_reset_host(struct Scsi_Host *); - -#endif /* _AHA152X_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/aha1542.c b/ANDROID_3.4.5/drivers/scsi/aha1542.c deleted file mode 100644 index ede91f37..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aha1542.c +++ /dev/null @@ -1,1744 +0,0 @@ -/* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $ - * linux/kernel/aha1542.c - * - * Copyright (C) 1992 Tommy Thorn - * Copyright (C) 1993, 1994, 1995 Eric Youngdale - * - * Modified by Eric Youngdale - * Use request_irq and request_dma to help prevent unexpected conflicts - * Set up on-board DMA controller, such that we do not have to - * have the bios enabled to use the aha1542. - * Modified by David Gentzel - * Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus - * controller). - * Modified by Matti Aarnio - * Accept parameters from LILO cmd-line. -- 1-Oct-94 - * Modified by Mike McLagan - * Recognise extended mode on AHA1542CP, different bit than 1542CF - * 1-Jan-97 - * Modified by Bjorn L. Thordarson and Einar Thor Einarsson - * Recognize that DMA0 is valid DMA channel -- 13-Jul-98 - * Modified by Chris Faulhaber - * Added module command-line options - * 19-Jul-99 - * Modified by Adam Fritzler - * Added proper detection of the AHA-1640 (MCA version of AHA-1540) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "scsi.h" -#include -#include "aha1542.h" - -#define SCSI_BUF_PA(address) isa_virt_to_bus(address) -#define SCSI_SG_PA(sgent) (isa_page_to_bus(sg_page((sgent))) + (sgent)->offset) - -#include - -#ifdef DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - -/* - static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $"; - */ - -/* The adaptec can be configured for quite a number of addresses, but - I generally do not want the card poking around at random. We allow - two addresses - this allows people to use the Adaptec with a Midi - card, which also used 0x330 -- can be overridden with LILO! */ - -#define MAXBOARDS 4 /* Increase this and the sizes of the - arrays below, if you need more.. */ - -/* Boards 3,4 slots are reserved for ISAPnP/MCA scans */ - -static unsigned int bases[MAXBOARDS] __initdata = {0x330, 0x334, 0, 0}; - -/* set by aha1542_setup according to the command line; they also may - be marked __initdata, but require zero initializers then */ - -static int setup_called[MAXBOARDS]; -static int setup_buson[MAXBOARDS]; -static int setup_busoff[MAXBOARDS]; -static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 }; - -/* - * LILO/Module params: aha1542=[,,[,]] - * - * Where: is any of the valid AHA addresses: - * 0x130, 0x134, 0x230, 0x234, 0x330, 0x334 - * is the time (in microsecs) that AHA spends on the AT-bus - * when transferring data. 1542A power-on default is 11us, - * valid values are in range: 2..15 (decimal) - * is the time that AHA spends OFF THE BUS after while - * it is transferring data (not to monopolize the bus). - * Power-on default is 4us, valid range: 1..64 microseconds. - * Default is jumper selected (1542A: on the J1), - * but experimenter can alter it with this. - * Valid values: 5, 6, 7, 8, 10 (MB/s) - * Factory default is 5 MB/s. - */ - -#if defined(MODULE) -static bool isapnp = 0; -static int aha1542[] = {0x330, 11, 4, -1}; -module_param_array(aha1542, int, NULL, 0); -module_param(isapnp, bool, 0); - -static struct isapnp_device_id id_table[] __initdata = { - { - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1542), - 0 - }, - {0} -}; - -MODULE_DEVICE_TABLE(isapnp, id_table); - -#else -static int isapnp = 1; -#endif - -#define BIOS_TRANSLATION_1632 0 /* Used by some old 1542A boards */ -#define BIOS_TRANSLATION_6432 1 /* Default case these days */ -#define BIOS_TRANSLATION_25563 2 /* Big disk case */ - -struct aha1542_hostdata { - /* This will effectively start both of them at the first mailbox */ - int bios_translation; /* Mapping bios uses - for compatibility */ - int aha1542_last_mbi_used; - int aha1542_last_mbo_used; - Scsi_Cmnd *SCint[AHA1542_MAILBOXES]; - struct mailbox mb[2 * AHA1542_MAILBOXES]; - struct ccb ccb[AHA1542_MAILBOXES]; -}; - -#define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata) - -static DEFINE_SPINLOCK(aha1542_lock); - - - -#define WAITnexttimeout 3000000 - -static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt); -static int aha1542_restart(struct Scsi_Host *shost); -static void aha1542_intr_handle(struct Scsi_Host *shost); - -#define aha1542_intr_reset(base) outb(IRST, CONTROL(base)) - -#define WAIT(port, mask, allof, noneof) \ - { register int WAITbits; \ - register int WAITtimeout = WAITnexttimeout; \ - while (1) { \ - WAITbits = inb(port) & (mask); \ - if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ - break; \ - if (--WAITtimeout == 0) goto fail; \ - } \ - } - -/* Similar to WAIT, except we use the udelay call to regulate the - amount of time we wait. */ -#define WAITd(port, mask, allof, noneof, timeout) \ - { register int WAITbits; \ - register int WAITtimeout = timeout; \ - while (1) { \ - WAITbits = inb(port) & (mask); \ - if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ - break; \ - mdelay(1); \ - if (--WAITtimeout == 0) goto fail; \ - } \ - } - -static void aha1542_stat(void) -{ -/* int s = inb(STATUS), i = inb(INTRFLAGS); - printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */ -} - -/* This is a bit complicated, but we need to make sure that an interrupt - routine does not send something out while we are in the middle of this. - Fortunately, it is only at boot time that multi-byte messages - are ever sent. */ -static int aha1542_out(unsigned int base, unchar * cmdp, int len) -{ - unsigned long flags = 0; - int got_lock; - - if (len == 1) { - got_lock = 0; - while (1 == 1) { - WAIT(STATUS(base), CDF, 0, CDF); - spin_lock_irqsave(&aha1542_lock, flags); - if (inb(STATUS(base)) & CDF) { - spin_unlock_irqrestore(&aha1542_lock, flags); - continue; - } - outb(*cmdp, DATA(base)); - spin_unlock_irqrestore(&aha1542_lock, flags); - return 0; - } - } else { - spin_lock_irqsave(&aha1542_lock, flags); - got_lock = 1; - while (len--) { - WAIT(STATUS(base), CDF, 0, CDF); - outb(*cmdp++, DATA(base)); - } - spin_unlock_irqrestore(&aha1542_lock, flags); - } - return 0; -fail: - if (got_lock) - spin_unlock_irqrestore(&aha1542_lock, flags); - printk(KERN_ERR "aha1542_out failed(%d): ", len + 1); - aha1542_stat(); - return 1; -} - -/* Only used at boot time, so we do not need to worry about latency as much - here */ - -static int __init aha1542_in(unsigned int base, unchar * cmdp, int len) -{ - unsigned long flags; - - spin_lock_irqsave(&aha1542_lock, flags); - while (len--) { - WAIT(STATUS(base), DF, DF, 0); - *cmdp++ = inb(DATA(base)); - } - spin_unlock_irqrestore(&aha1542_lock, flags); - return 0; -fail: - spin_unlock_irqrestore(&aha1542_lock, flags); - printk(KERN_ERR "aha1542_in failed(%d): ", len + 1); - aha1542_stat(); - return 1; -} - -/* Similar to aha1542_in, except that we wait a very short period of time. - We use this if we know the board is alive and awake, but we are not sure - if the board will respond to the command we are about to send or not */ -static int __init aha1542_in1(unsigned int base, unchar * cmdp, int len) -{ - unsigned long flags; - - spin_lock_irqsave(&aha1542_lock, flags); - while (len--) { - WAITd(STATUS(base), DF, DF, 0, 100); - *cmdp++ = inb(DATA(base)); - } - spin_unlock_irqrestore(&aha1542_lock, flags); - return 0; -fail: - spin_unlock_irqrestore(&aha1542_lock, flags); - return 1; -} - -static int makecode(unsigned hosterr, unsigned scsierr) -{ - switch (hosterr) { - case 0x0: - case 0xa: /* Linked command complete without error and linked normally */ - case 0xb: /* Linked command complete without error, interrupt generated */ - hosterr = 0; - break; - - case 0x11: /* Selection time out-The initiator selection or target - reselection was not complete within the SCSI Time out period */ - hosterr = DID_TIME_OUT; - break; - - case 0x12: /* Data overrun/underrun-The target attempted to transfer more data - than was allocated by the Data Length field or the sum of the - Scatter / Gather Data Length fields. */ - - case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ - - case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was - invalid. This usually indicates a software failure. */ - - case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. - This usually indicates a software failure. */ - - case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set - of linked CCB's does not specify the same logical unit number as - the first. */ - case 0x18: /* Invalid Target Direction received from Host-The direction of a - Target Mode CCB was invalid. */ - - case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was - received to service data transfer between the same target LUN - and initiator SCSI ID in the same direction. */ - - case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero - length segment or invalid segment list boundaries was received. - A CCB parameter was invalid. */ - DEB(printk("Aha1542: %x %x\n", hosterr, scsierr)); - hosterr = DID_ERROR; /* Couldn't find any better */ - break; - - case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus - phase sequence was requested by the target. The host adapter - will generate a SCSI Reset Condition, notifying the host with - a SCRD interrupt */ - hosterr = DID_RESET; - break; - default: - printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr); - break; - } - return scsierr | (hosterr << 16); -} - -static int __init aha1542_test_port(int bse, struct Scsi_Host *shpnt) -{ - unchar inquiry_cmd[] = {CMD_INQUIRY}; - unchar inquiry_result[4]; - unchar *cmdp; - int len; - volatile int debug = 0; - - /* Quick and dirty test for presence of the card. */ - if (inb(STATUS(bse)) == 0xff) - return 0; - - /* Reset the adapter. I ought to make a hard reset, but it's not really necessary */ - - /* DEB(printk("aha1542_test_port called \n")); */ - - /* In case some other card was probing here, reset interrupts */ - aha1542_intr_reset(bse); /* reset interrupts, so they don't block */ - - outb(SRST | IRST /*|SCRST */ , CONTROL(bse)); - - mdelay(20); /* Wait a little bit for things to settle down. */ - - debug = 1; - /* Expect INIT and IDLE, any of the others are bad */ - WAIT(STATUS(bse), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); - - debug = 2; - /* Shouldn't have generated any interrupts during reset */ - if (inb(INTRFLAGS(bse)) & INTRMASK) - goto fail; - - - /* Perform a host adapter inquiry instead so we do not need to set - up the mailboxes ahead of time */ - - aha1542_out(bse, inquiry_cmd, 1); - - debug = 3; - len = 4; - cmdp = &inquiry_result[0]; - - while (len--) { - WAIT(STATUS(bse), DF, DF, 0); - *cmdp++ = inb(DATA(bse)); - } - - debug = 8; - /* Reading port should reset DF */ - if (inb(STATUS(bse)) & DF) - goto fail; - - debug = 9; - /* When HACC, command is completed, and we're though testing */ - WAIT(INTRFLAGS(bse), HACC, HACC, 0); - /* now initialize adapter */ - - debug = 10; - /* Clear interrupts */ - outb(IRST, CONTROL(bse)); - - debug = 11; - - return debug; /* 1 = ok */ -fail: - return 0; /* 0 = not ok */ -} - -/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */ -static irqreturn_t do_aha1542_intr_handle(int dummy, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *shost = dev_id; - - spin_lock_irqsave(shost->host_lock, flags); - aha1542_intr_handle(shost); - spin_unlock_irqrestore(shost->host_lock, flags); - return IRQ_HANDLED; -} - -/* A "high" level interrupt handler */ -static void aha1542_intr_handle(struct Scsi_Host *shost) -{ - void (*my_done) (Scsi_Cmnd *) = NULL; - int errstatus, mbi, mbo, mbistatus; - int number_serviced; - unsigned long flags; - Scsi_Cmnd *SCtmp; - int flag; - int needs_restart; - struct mailbox *mb; - struct ccb *ccb; - - mb = HOSTDATA(shost)->mb; - ccb = HOSTDATA(shost)->ccb; - -#ifdef DEBUG - { - flag = inb(INTRFLAGS(shost->io_port)); - printk(KERN_DEBUG "aha1542_intr_handle: "); - if (!(flag & ANYINTR)) - printk("no interrupt?"); - if (flag & MBIF) - printk("MBIF "); - if (flag & MBOA) - printk("MBOF "); - if (flag & HACC) - printk("HACC "); - if (flag & SCRD) - printk("SCRD "); - printk("status %02x\n", inb(STATUS(shost->io_port))); - }; -#endif - number_serviced = 0; - needs_restart = 0; - - while (1 == 1) { - flag = inb(INTRFLAGS(shost->io_port)); - - /* Check for unusual interrupts. If any of these happen, we should - probably do something special, but for now just printing a message - is sufficient. A SCSI reset detected is something that we really - need to deal with in some way. */ - if (flag & ~MBIF) { - if (flag & MBOA) - printk("MBOF "); - if (flag & HACC) - printk("HACC "); - if (flag & SCRD) { - needs_restart = 1; - printk("SCRD "); - } - } - aha1542_intr_reset(shost->io_port); - - spin_lock_irqsave(&aha1542_lock, flags); - mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1; - if (mbi >= 2 * AHA1542_MAILBOXES) - mbi = AHA1542_MAILBOXES; - - do { - if (mb[mbi].status != 0) - break; - mbi++; - if (mbi >= 2 * AHA1542_MAILBOXES) - mbi = AHA1542_MAILBOXES; - } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used); - - if (mb[mbi].status == 0) { - spin_unlock_irqrestore(&aha1542_lock, flags); - /* Hmm, no mail. Must have read it the last time around */ - if (!number_serviced && !needs_restart) - printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n"); - /* We detected a reset. Restart all pending commands for - devices that use the hard reset option */ - if (needs_restart) - aha1542_restart(shost); - return; - }; - - mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_BUF_PA(&ccb[0]))) / sizeof(struct ccb); - mbistatus = mb[mbi].status; - mb[mbi].status = 0; - HOSTDATA(shost)->aha1542_last_mbi_used = mbi; - spin_unlock_irqrestore(&aha1542_lock, flags); - -#ifdef DEBUG - { - if (ccb[mbo].tarstat | ccb[mbo].hastat) - printk(KERN_DEBUG "aha1542_command: returning %x (status %d)\n", - ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); - }; -#endif - - if (mbistatus == 3) - continue; /* Aborted command not found */ - -#ifdef DEBUG - printk(KERN_DEBUG "...done %d %d\n", mbo, mbi); -#endif - - SCtmp = HOSTDATA(shost)->SCint[mbo]; - - if (!SCtmp || !SCtmp->scsi_done) { - printk(KERN_WARNING "aha1542_intr_handle: Unexpected interrupt\n"); - printk(KERN_WARNING "tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat, - ccb[mbo].hastat, ccb[mbo].idlun, mbo); - return; - } - my_done = SCtmp->scsi_done; - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - /* Fetch the sense data, and tuck it away, in the required slot. The - Adaptec automatically fetches it, and there is no guarantee that - we will still have it in the cdb when we come back */ - if (ccb[mbo].tarstat == 2) - memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], - SCSI_SENSE_BUFFERSIZE); - - - /* is there mail :-) */ - - /* more error checking left out here */ - if (mbistatus != 1) - /* This is surely wrong, but I don't know what's right */ - errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); - else - errstatus = 0; - -#ifdef DEBUG - if (errstatus) - printk(KERN_DEBUG "(aha1542 error:%x %x %x) ", errstatus, - ccb[mbo].hastat, ccb[mbo].tarstat); -#endif - - if (ccb[mbo].tarstat == 2) { -#ifdef DEBUG - int i; -#endif - DEB(printk("aha1542_intr_handle: sense:")); -#ifdef DEBUG - for (i = 0; i < 12; i++) - printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]); - printk("\n"); -#endif - /* - DEB(printk("aha1542_intr_handle: buf:")); - for (i = 0; i < bufflen; i++) - printk("%02x ", ((unchar *)buff)[i]); - printk("\n"); - */ - } - DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus)); - SCtmp->result = errstatus; - HOSTDATA(shost)->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as - far as queuecommand is concerned */ - my_done(SCtmp); - number_serviced++; - }; -} - -static int aha1542_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) -{ - unchar ahacmd = CMD_START_SCSI; - unchar direction; - unchar *cmd = (unchar *) SCpnt->cmnd; - unchar target = SCpnt->device->id; - unchar lun = SCpnt->device->lun; - unsigned long flags; - int bufflen = scsi_bufflen(SCpnt); - int mbo; - struct mailbox *mb; - struct ccb *ccb; - - DEB(int i); - - mb = HOSTDATA(SCpnt->device->host)->mb; - ccb = HOSTDATA(SCpnt->device->host)->ccb; - - DEB(if (target > 1) { - SCpnt->result = DID_TIME_OUT << 16; - done(SCpnt); return 0; - } - ); - - if (*cmd == REQUEST_SENSE) { - /* Don't do the command - we have the sense data already */ -#if 0 - /* scsi_request_sense() provides a buffer of size 256, - so there is no reason to expect equality */ - if (bufflen != SCSI_SENSE_BUFFERSIZE) - printk(KERN_CRIT "aha1542: Wrong buffer length supplied " - "for request sense (%d)\n", bufflen); -#endif - SCpnt->result = 0; - done(SCpnt); - return 0; - } -#ifdef DEBUG - if (*cmd == READ_10 || *cmd == WRITE_10) - i = xscsi2int(cmd + 2); - else if (*cmd == READ_6 || *cmd == WRITE_6) - i = scsi2int(cmd + 2); - else - i = -1; - if (done) - printk(KERN_DEBUG "aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); - else - printk(KERN_DEBUG "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); - aha1542_stat(); - printk(KERN_DEBUG "aha1542_queuecommand: dumping scsi cmd:"); - for (i = 0; i < SCpnt->cmd_len; i++) - printk("%02x ", cmd[i]); - printk("\n"); - if (*cmd == WRITE_10 || *cmd == WRITE_6) - return 0; /* we are still testing, so *don't* write */ -#endif - /* Use the outgoing mailboxes in a round-robin fashion, because this - is how the host adapter will scan for them */ - - spin_lock_irqsave(&aha1542_lock, flags); - mbo = HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used + 1; - if (mbo >= AHA1542_MAILBOXES) - mbo = 0; - - do { - if (mb[mbo].status == 0 && HOSTDATA(SCpnt->device->host)->SCint[mbo] == NULL) - break; - mbo++; - if (mbo >= AHA1542_MAILBOXES) - mbo = 0; - } while (mbo != HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used); - - if (mb[mbo].status || HOSTDATA(SCpnt->device->host)->SCint[mbo]) - panic("Unable to find empty mailbox for aha1542.\n"); - - HOSTDATA(SCpnt->device->host)->SCint[mbo] = SCpnt; /* This will effectively prevent someone else from - screwing with this cdb. */ - - HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used = mbo; - spin_unlock_irqrestore(&aha1542_lock, flags); - -#ifdef DEBUG - printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done); -#endif - - any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo])); /* This gets trashed for some reason */ - - memset(&ccb[mbo], 0, sizeof(struct ccb)); - - ccb[mbo].cdblen = SCpnt->cmd_len; - - direction = 0; - if (*cmd == READ_10 || *cmd == READ_6) - direction = 8; - else if (*cmd == WRITE_10 || *cmd == WRITE_6) - direction = 16; - - memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); - - if (bufflen) { - struct scatterlist *sg; - struct chain *cptr; -#ifdef DEBUG - unsigned char *ptr; -#endif - int i, sg_count = scsi_sg_count(SCpnt); - ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather */ - SCpnt->host_scribble = kmalloc(sizeof(*cptr)*sg_count, - GFP_KERNEL | GFP_DMA); - cptr = (struct chain *) SCpnt->host_scribble; - if (cptr == NULL) { - /* free the claimed mailbox slot */ - HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL; - return SCSI_MLQUEUE_HOST_BUSY; - } - scsi_for_each_sg(SCpnt, sg, sg_count, i) { - any2scsi(cptr[i].dataptr, SCSI_SG_PA(sg)); - any2scsi(cptr[i].datalen, sg->length); - }; - any2scsi(ccb[mbo].datalen, sg_count * sizeof(struct chain)); - any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr)); -#ifdef DEBUG - printk("cptr %x: ", cptr); - ptr = (unsigned char *) cptr; - for (i = 0; i < 18; i++) - printk("%02x ", ptr[i]); -#endif - } else { - ccb[mbo].op = 0; /* SCSI Initiator Command */ - SCpnt->host_scribble = NULL; - any2scsi(ccb[mbo].datalen, 0); - any2scsi(ccb[mbo].dataptr, 0); - }; - ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7); /*SCSI Target Id */ - ccb[mbo].rsalen = 16; - ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; - ccb[mbo].commlinkid = 0; - -#ifdef DEBUG - { - int i; - printk(KERN_DEBUG "aha1542_command: sending.. "); - for (i = 0; i < sizeof(ccb[mbo]) - 10; i++) - printk("%02x ", ((unchar *) & ccb[mbo])[i]); - }; -#endif - - if (done) { - DEB(printk("aha1542_queuecommand: now waiting for interrupt "); - aha1542_stat()); - SCpnt->scsi_done = done; - mb[mbo].status = 1; - aha1542_out(SCpnt->device->host->io_port, &ahacmd, 1); /* start scsi command */ - DEB(aha1542_stat()); - } else - printk("aha1542_queuecommand: done can't be NULL\n"); - - return 0; -} - -static DEF_SCSI_QCMD(aha1542_queuecommand) - -/* Initialize mailboxes */ -static void setup_mailboxes(int bse, struct Scsi_Host *shpnt) -{ - int i; - struct mailbox *mb; - struct ccb *ccb; - - unchar cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0}; - - mb = HOSTDATA(shpnt)->mb; - ccb = HOSTDATA(shpnt)->ccb; - - for (i = 0; i < AHA1542_MAILBOXES; i++) { - mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0; - any2scsi(mb[i].ccbptr, SCSI_BUF_PA(&ccb[i])); - }; - aha1542_intr_reset(bse); /* reset interrupts, so they don't block */ - any2scsi((cmd + 2), SCSI_BUF_PA(mb)); - aha1542_out(bse, cmd, 5); - WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0); - while (0) { -fail: - printk(KERN_ERR "aha1542_detect: failed setting up mailboxes\n"); - } - aha1542_intr_reset(bse); -} - -static int __init aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id) -{ - unchar inquiry_cmd[] = {CMD_RETCONF}; - unchar inquiry_result[3]; - int i; - i = inb(STATUS(base_io)); - if (i & DF) { - i = inb(DATA(base_io)); - }; - aha1542_out(base_io, inquiry_cmd, 1); - aha1542_in(base_io, inquiry_result, 3); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - while (0) { -fail: - printk(KERN_ERR "aha1542_detect: query board settings\n"); - } - aha1542_intr_reset(base_io); - switch (inquiry_result[0]) { - case 0x80: - *dma_chan = 7; - break; - case 0x40: - *dma_chan = 6; - break; - case 0x20: - *dma_chan = 5; - break; - case 0x01: - *dma_chan = 0; - break; - case 0: - /* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel. - Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */ - *dma_chan = 0xFF; - break; - default: - printk(KERN_ERR "Unable to determine Adaptec DMA priority. Disabling board\n"); - return -1; - }; - switch (inquiry_result[1]) { - case 0x40: - *irq_level = 15; - break; - case 0x20: - *irq_level = 14; - break; - case 0x8: - *irq_level = 12; - break; - case 0x4: - *irq_level = 11; - break; - case 0x2: - *irq_level = 10; - break; - case 0x1: - *irq_level = 9; - break; - default: - printk(KERN_ERR "Unable to determine Adaptec IRQ level. Disabling board\n"); - return -1; - }; - *scsi_id = inquiry_result[2] & 7; - return 0; -} - -/* This function should only be called for 1542C boards - we can detect - the special firmware settings and unlock the board */ - -static int __init aha1542_mbenable(int base) -{ - static unchar mbenable_cmd[3]; - static unchar mbenable_result[2]; - int retval; - - retval = BIOS_TRANSLATION_6432; - - mbenable_cmd[0] = CMD_EXTBIOS; - aha1542_out(base, mbenable_cmd, 1); - if (aha1542_in1(base, mbenable_result, 2)) - return retval; - WAITd(INTRFLAGS(base), INTRMASK, HACC, 0, 100); - aha1542_intr_reset(base); - - if ((mbenable_result[0] & 0x08) || mbenable_result[1]) { - mbenable_cmd[0] = CMD_MBENABLE; - mbenable_cmd[1] = 0; - mbenable_cmd[2] = mbenable_result[1]; - - if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03)) - retval = BIOS_TRANSLATION_25563; - - aha1542_out(base, mbenable_cmd, 3); - WAIT(INTRFLAGS(base), INTRMASK, HACC, 0); - }; - while (0) { -fail: - printk(KERN_ERR "aha1542_mbenable: Mailbox init failed\n"); - } - aha1542_intr_reset(base); - return retval; -} - -/* Query the board to find out if it is a 1542 or a 1740, or whatever. */ -static int __init aha1542_query(int base_io, int *transl) -{ - unchar inquiry_cmd[] = {CMD_INQUIRY}; - unchar inquiry_result[4]; - int i; - i = inb(STATUS(base_io)); - if (i & DF) { - i = inb(DATA(base_io)); - }; - aha1542_out(base_io, inquiry_cmd, 1); - aha1542_in(base_io, inquiry_result, 4); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - while (0) { -fail: - printk(KERN_ERR "aha1542_detect: query card type\n"); - } - aha1542_intr_reset(base_io); - - *transl = BIOS_TRANSLATION_6432; /* Default case */ - - /* For an AHA1740 series board, we ignore the board since there is a - hardware bug which can lead to wrong blocks being returned if the board - is operating in the 1542 emulation mode. Since there is an extended mode - driver, we simply ignore the board and let the 1740 driver pick it up. - */ - - if (inquiry_result[0] == 0x43) { - printk(KERN_INFO "aha1542.c: Emulation mode not supported for AHA 174N hardware.\n"); - return 1; - }; - - /* Always call this - boards that do not support extended bios translation - will ignore the command, and we will set the proper default */ - - *transl = aha1542_mbenable(base_io); - - return 0; -} - -#ifndef MODULE -static char *setup_str[MAXBOARDS] __initdata; -static int setup_idx = 0; - -static void __init aha1542_setup(char *str, int *ints) -{ - const char *ahausage = "aha1542: usage: aha1542=[,,[,]]\n"; - int setup_portbase; - - if (setup_idx >= MAXBOARDS) { - printk(KERN_ERR "aha1542: aha1542_setup called too many times! Bad LILO params ?\n"); - printk(KERN_ERR " Entryline 1: %s\n", setup_str[0]); - printk(KERN_ERR " Entryline 2: %s\n", setup_str[1]); - printk(KERN_ERR " This line: %s\n", str); - return; - } - if (ints[0] < 1 || ints[0] > 4) { - printk(KERN_ERR "aha1542: %s\n", str); - printk(ahausage); - printk(KERN_ERR "aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n"); - } - setup_called[setup_idx] = ints[0]; - setup_str[setup_idx] = str; - - setup_portbase = ints[0] >= 1 ? ints[1] : 0; /* Preserve the default value.. */ - setup_buson[setup_idx] = ints[0] >= 2 ? ints[2] : 7; - setup_busoff[setup_idx] = ints[0] >= 3 ? ints[3] : 5; - if (ints[0] >= 4) - { - int atbt = -1; - switch (ints[4]) { - case 5: - atbt = 0x00; - break; - case 6: - atbt = 0x04; - break; - case 7: - atbt = 0x01; - break; - case 8: - atbt = 0x02; - break; - case 10: - atbt = 0x03; - break; - default: - printk(KERN_ERR "aha1542: %s\n", str); - printk(ahausage); - printk(KERN_ERR "aha1542: Valid values for DMASPEED are 5-8, 10 MB/s. Using jumper defaults.\n"); - break; - } - setup_dmaspeed[setup_idx] = atbt; - } - if (setup_portbase != 0) - bases[setup_idx] = setup_portbase; - - ++setup_idx; -} - -static int __init do_setup(char *str) -{ - int ints[5]; - - int count=setup_idx; - - get_options(str, ARRAY_SIZE(ints), ints); - aha1542_setup(str,ints); - - return countproc_name = "aha1542"; - -#ifdef MODULE - bases[0] = aha1542[0]; - setup_buson[0] = aha1542[1]; - setup_busoff[0] = aha1542[2]; - { - int atbt = -1; - switch (aha1542[3]) { - case 5: - atbt = 0x00; - break; - case 6: - atbt = 0x04; - break; - case 7: - atbt = 0x01; - break; - case 8: - atbt = 0x02; - break; - case 10: - atbt = 0x03; - break; - }; - setup_dmaspeed[0] = atbt; - } -#endif - - /* - * Find MicroChannel cards (AHA1640) - */ -#ifdef CONFIG_MCA_LEGACY - if(MCA_bus) { - int slot = 0; - int pos = 0; - - for (indx = 0; (slot != MCA_NOTFOUND) && (indx < ARRAY_SIZE(bases)); indx++) { - - if (bases[indx]) - continue; - - /* Detect only AHA-1640 cards -- MCA ID 0F1F */ - slot = mca_find_unused_adapter(0x0f1f, slot); - if (slot == MCA_NOTFOUND) - break; - - /* Found one */ - pos = mca_read_stored_pos(slot, 3); - - /* Decode address */ - if (pos & 0x80) { - if (pos & 0x02) { - if (pos & 0x01) - bases[indx] = 0x334; - else - bases[indx] = 0x234; - } else { - if (pos & 0x01) - bases[indx] = 0x134; - } - } else { - if (pos & 0x02) { - if (pos & 0x01) - bases[indx] = 0x330; - else - bases[indx] = 0x230; - } else { - if (pos & 0x01) - bases[indx] = 0x130; - } - } - - /* No need to decode IRQ and Arb level -- those are - * read off the card later. - */ - printk(KERN_INFO "Found an AHA-1640 in MCA slot %d, I/O 0x%04x\n", slot, bases[indx]); - - mca_set_adapter_name(slot, "Adapter AHA-1640"); - mca_set_adapter_procfn(slot, NULL, NULL); - mca_mark_as_used(slot); - - /* Go on */ - slot++; - } - - } -#endif - - /* - * Hunt for ISA Plug'n'Pray Adaptecs (AHA1535) - */ - - if(isapnp) - { - struct pnp_dev *pdev = NULL; - for(indx = 0; indx < ARRAY_SIZE(bases); indx++) { - if(bases[indx]) - continue; - pdev = pnp_find_dev(NULL, ISAPNP_VENDOR('A', 'D', 'P'), - ISAPNP_FUNCTION(0x1542), pdev); - if(pdev==NULL) - break; - /* - * Activate the PnP card - */ - - if(pnp_device_attach(pdev)<0) - continue; - - if(pnp_activate_dev(pdev)<0) { - pnp_device_detach(pdev); - continue; - } - - if(!pnp_port_valid(pdev, 0)) { - pnp_device_detach(pdev); - continue; - } - - bases[indx] = pnp_port_start(pdev, 0); - - /* The card can be queried for its DMA, we have - the DMA set up that is enough */ - - printk(KERN_INFO "ISAPnP found an AHA1535 at I/O 0x%03X\n", bases[indx]); - } - } - for (indx = 0; indx < ARRAY_SIZE(bases); indx++) - if (bases[indx] != 0 && request_region(bases[indx], 4, "aha1542")) { - shpnt = scsi_register(tpnt, - sizeof(struct aha1542_hostdata)); - - if(shpnt==NULL) { - release_region(bases[indx], 4); - continue; - } - if (!aha1542_test_port(bases[indx], shpnt)) - goto unregister; - - base_io = bases[indx]; - - /* Set the Bus on/off-times as not to ruin floppy performance */ - { - unchar oncmd[] = {CMD_BUSON_TIME, 7}; - unchar offcmd[] = {CMD_BUSOFF_TIME, 5}; - - if (setup_called[indx]) { - oncmd[1] = setup_buson[indx]; - offcmd[1] = setup_busoff[indx]; - } - aha1542_intr_reset(base_io); - aha1542_out(base_io, oncmd, 2); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - aha1542_intr_reset(base_io); - aha1542_out(base_io, offcmd, 2); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - if (setup_dmaspeed[indx] >= 0) { - unchar dmacmd[] = {CMD_DMASPEED, 0}; - dmacmd[1] = setup_dmaspeed[indx]; - aha1542_intr_reset(base_io); - aha1542_out(base_io, dmacmd, 2); - WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0); - } - while (0) { -fail: - printk(KERN_ERR "aha1542_detect: setting bus on/off-time failed\n"); - } - aha1542_intr_reset(base_io); - } - if (aha1542_query(base_io, &trans)) - goto unregister; - - if (aha1542_getconfig(base_io, &irq_level, &dma_chan, &scsi_id) == -1) - goto unregister; - - printk(KERN_INFO "Configuring Adaptec (SCSI-ID %d) at IO:%x, IRQ %d", scsi_id, base_io, irq_level); - if (dma_chan != 0xFF) - printk(", DMA priority %d", dma_chan); - printk("\n"); - - DEB(aha1542_stat()); - setup_mailboxes(base_io, shpnt); - - DEB(aha1542_stat()); - - DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level)); - spin_lock_irqsave(&aha1542_lock, flags); - if (request_irq(irq_level, do_aha1542_intr_handle, 0, - "aha1542", shpnt)) { - printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n"); - spin_unlock_irqrestore(&aha1542_lock, flags); - goto unregister; - } - if (dma_chan != 0xFF) { - if (request_dma(dma_chan, "aha1542")) { - printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n"); - free_irq(irq_level, shpnt); - spin_unlock_irqrestore(&aha1542_lock, flags); - goto unregister; - } - if (dma_chan == 0 || dma_chan >= 5) { - set_dma_mode(dma_chan, DMA_MODE_CASCADE); - enable_dma(dma_chan); - } - } - - shpnt->this_id = scsi_id; - shpnt->unique_id = base_io; - shpnt->io_port = base_io; - shpnt->n_io_port = 4; /* Number of bytes of I/O space used */ - shpnt->dma_channel = dma_chan; - shpnt->irq = irq_level; - HOSTDATA(shpnt)->bios_translation = trans; - if (trans == BIOS_TRANSLATION_25563) - printk(KERN_INFO "aha1542.c: Using extended bios translation\n"); - HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1); - HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1); - memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint)); - spin_unlock_irqrestore(&aha1542_lock, flags); -#if 0 - DEB(printk(" *** READ CAPACITY ***\n")); - - { - unchar buf[8]; - static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - int i; - - for (i = 0; i < sizeof(buf); ++i) - buf[i] = 0x87; - for (i = 0; i < 2; ++i) - if (!aha1542_command(i, cmd, buf, sizeof(buf))) { - printk(KERN_DEBUG "aha_detect: LU %d sector_size %d device_size %d\n", - i, xscsi2int(buf + 4), xscsi2int(buf)); - } - } - - DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n")); - - for (i = 0; i < 4; ++i) { - unsigned char cmd[10]; - static buffer[512]; - - cmd[0] = READ_10; - cmd[1] = 0; - xany2scsi(cmd + 2, i); - cmd[6] = 0; - cmd[7] = 0; - cmd[8] = 1; - cmd[9] = 0; - aha1542_command(0, cmd, buffer, 512); - } -#endif - count++; - continue; -unregister: - release_region(bases[indx], 4); - scsi_unregister(shpnt); - continue; - - }; - - return count; -} - -static int aha1542_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, shost); - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -static int aha1542_restart(struct Scsi_Host *shost) -{ - int i; - int count = 0; -#if 0 - unchar ahacmd = CMD_START_SCSI; -#endif - - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(shost)->SCint[i] && - !(HOSTDATA(shost)->SCint[i]->device->soft_reset)) { -#if 0 - HOSTDATA(shost)->mb[i].status = 1; /* Indicate ready to restart... */ -#endif - count++; - } - printk(KERN_DEBUG "Potential to restart %d stalled commands...\n", count); -#if 0 - /* start scsi command */ - if (count) - aha1542_out(shost->io_port, &ahacmd, 1); -#endif - return 0; -} - -/* - * This is a device reset. This is handled by sending a special command - * to the device. - */ -static int aha1542_dev_reset(Scsi_Cmnd * SCpnt) -{ - unsigned long flags; - struct mailbox *mb; - unchar target = SCpnt->device->id; - unchar lun = SCpnt->device->lun; - int mbo; - struct ccb *ccb; - unchar ahacmd = CMD_START_SCSI; - - ccb = HOSTDATA(SCpnt->device->host)->ccb; - mb = HOSTDATA(SCpnt->device->host)->mb; - - spin_lock_irqsave(&aha1542_lock, flags); - mbo = HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used + 1; - if (mbo >= AHA1542_MAILBOXES) - mbo = 0; - - do { - if (mb[mbo].status == 0 && HOSTDATA(SCpnt->device->host)->SCint[mbo] == NULL) - break; - mbo++; - if (mbo >= AHA1542_MAILBOXES) - mbo = 0; - } while (mbo != HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used); - - if (mb[mbo].status || HOSTDATA(SCpnt->device->host)->SCint[mbo]) - panic("Unable to find empty mailbox for aha1542.\n"); - - HOSTDATA(SCpnt->device->host)->SCint[mbo] = SCpnt; /* This will effectively - prevent someone else from - screwing with this cdb. */ - - HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used = mbo; - spin_unlock_irqrestore(&aha1542_lock, flags); - - any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo])); /* This gets trashed for some reason */ - - memset(&ccb[mbo], 0, sizeof(struct ccb)); - - ccb[mbo].op = 0x81; /* BUS DEVICE RESET */ - - ccb[mbo].idlun = (target & 7) << 5 | (lun & 7); /*SCSI Target Id */ - - ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; - ccb[mbo].commlinkid = 0; - - /* - * Now tell the 1542 to flush all pending commands for this - * target - */ - aha1542_out(SCpnt->device->host->io_port, &ahacmd, 1); - - scmd_printk(KERN_WARNING, SCpnt, - "Trying device reset for target\n"); - - return SUCCESS; - - -#ifdef ERIC_neverdef - /* - * With the 1542 we apparently never get an interrupt to - * acknowledge a device reset being sent. Then again, Leonard - * says we are doing this wrong in the first place... - * - * Take a wait and see attitude. If we get spurious interrupts, - * then the device reset is doing something sane and useful, and - * we will wait for the interrupt to post completion. - */ - printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target); - - /* - * Free the command block for all commands running on this - * target... - */ - for (i = 0; i < AHA1542_MAILBOXES; i++) { - if (HOSTDATA(SCpnt->host)->SCint[i] && - HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - HOSTDATA(SCpnt->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->host)->mb[i].status = 0; - } - } - return SUCCESS; - - return FAILED; -#endif /* ERIC_neverdef */ -} - -static int aha1542_bus_reset(Scsi_Cmnd * SCpnt) -{ - int i; - - /* - * This does a scsi reset for all devices on the bus. - * In principle, we could also reset the 1542 - should - * we do this? Try this first, and we can add that later - * if it turns out to be useful. - */ - outb(SCRST, CONTROL(SCpnt->device->host->io_port)); - - /* - * Wait for the thing to settle down a bit. Unfortunately - * this is going to basically lock up the machine while we - * wait for this to complete. To be 100% correct, we need to - * check for timeout, and if we are doing something like this - * we are pretty desperate anyways. - */ - ssleep(4); - - spin_lock_irq(SCpnt->device->host->host_lock); - - WAIT(STATUS(SCpnt->device->host->io_port), - STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); - - /* - * Now try to pick up the pieces. For all pending commands, - * free any internal data structures, and basically clear things - * out. We do not try and restart any commands or anything - - * the strategy handler takes care of that crap. - */ - printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no); - - for (i = 0; i < AHA1542_MAILBOXES; i++) { - if (HOSTDATA(SCpnt->device->host)->SCint[i] != NULL) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->device->host)->SCint[i]; - - - if (SCtmp->device->soft_reset) { - /* - * If this device implements the soft reset option, - * then it is still holding onto the command, and - * may yet complete it. In this case, we don't - * flush the data. - */ - continue; - } - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - HOSTDATA(SCpnt->device->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->device->host)->mb[i].status = 0; - } - } - - spin_unlock_irq(SCpnt->device->host->host_lock); - return SUCCESS; - -fail: - spin_unlock_irq(SCpnt->device->host->host_lock); - return FAILED; -} - -static int aha1542_host_reset(Scsi_Cmnd * SCpnt) -{ - int i; - - /* - * This does a scsi reset for all devices on the bus. - * In principle, we could also reset the 1542 - should - * we do this? Try this first, and we can add that later - * if it turns out to be useful. - */ - outb(HRST | SCRST, CONTROL(SCpnt->device->host->io_port)); - - /* - * Wait for the thing to settle down a bit. Unfortunately - * this is going to basically lock up the machine while we - * wait for this to complete. To be 100% correct, we need to - * check for timeout, and if we are doing something like this - * we are pretty desperate anyways. - */ - ssleep(4); - spin_lock_irq(SCpnt->device->host->host_lock); - - WAIT(STATUS(SCpnt->device->host->io_port), - STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); - - /* - * We need to do this too before the 1542 can interact with - * us again. - */ - setup_mailboxes(SCpnt->device->host->io_port, SCpnt->device->host); - - /* - * Now try to pick up the pieces. For all pending commands, - * free any internal data structures, and basically clear things - * out. We do not try and restart any commands or anything - - * the strategy handler takes care of that crap. - */ - printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no); - - for (i = 0; i < AHA1542_MAILBOXES; i++) { - if (HOSTDATA(SCpnt->device->host)->SCint[i] != NULL) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->device->host)->SCint[i]; - - if (SCtmp->device->soft_reset) { - /* - * If this device implements the soft reset option, - * then it is still holding onto the command, and - * may yet complete it. In this case, we don't - * flush the data. - */ - continue; - } - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - HOSTDATA(SCpnt->device->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->device->host)->mb[i].status = 0; - } - } - - spin_unlock_irq(SCpnt->device->host->host_lock); - return SUCCESS; - -fail: - spin_unlock_irq(SCpnt->device->host->host_lock); - return FAILED; -} - -#if 0 -/* - * These are the old error handling routines. They are only temporarily - * here while we play with the new error handling code. - */ -static int aha1542_old_abort(Scsi_Cmnd * SCpnt) -{ -#if 0 - unchar ahacmd = CMD_START_SCSI; - unsigned long flags; - struct mailbox *mb; - int mbi, mbo, i; - - printk(KERN_DEBUG "In aha1542_abort: %x %x\n", - inb(STATUS(SCpnt->host->io_port)), - inb(INTRFLAGS(SCpnt->host->io_port))); - - spin_lock_irqsave(&aha1542_lock, flags); - mb = HOSTDATA(SCpnt->host)->mb; - mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1; - if (mbi >= 2 * AHA1542_MAILBOXES) - mbi = AHA1542_MAILBOXES; - - do { - if (mb[mbi].status != 0) - break; - mbi++; - if (mbi >= 2 * AHA1542_MAILBOXES) - mbi = AHA1542_MAILBOXES; - } while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used); - spin_unlock_irqrestore(&aha1542_lock, flags); - - if (mb[mbi].status) { - printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n", - SCpnt->host->irq); - aha1542_intr_handle(SCpnt->host, NULL); - return 0; - } - /* OK, no lost interrupt. Try looking to see how many pending commands - we think we have. */ - - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(SCpnt->host)->SCint[i]) { - if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) { - printk(KERN_ERR "Timed out command pending for %s\n", - SCpnt->request->rq_disk ? - SCpnt->request->rq_disk->disk_name : "?" - ); - if (HOSTDATA(SCpnt->host)->mb[i].status) { - printk(KERN_ERR "OGMB still full - restarting\n"); - aha1542_out(SCpnt->host->io_port, &ahacmd, 1); - }; - } else - printk(KERN_ERR "Other pending command %s\n", - SCpnt->request->rq_disk ? - SCpnt->request->rq_disk->disk_name : "?" - ); - } -#endif - - DEB(printk("aha1542_abort\n")); -#if 0 - spin_lock_irqsave(&aha1542_lock, flags); - for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) { - if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) { - mb[mbo].status = 2; /* Abort command */ - aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */ - spin_unlock_irqrestore(&aha1542_lock, flags); - break; - } - } - if (AHA1542_MAILBOXES == mbo) - spin_unlock_irqrestore(&aha1542_lock, flags); -#endif - return SCSI_ABORT_SNOOZE; -} - -/* We do not implement a reset function here, but the upper level code - assumes that it will get some kind of response for the command in - SCpnt. We must oblige, or the command will hang the scsi system. - For a first go, we assume that the 1542 notifies us with all of the - pending commands (it does implement soft reset, after all). */ - -static int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) -{ - unchar ahacmd = CMD_START_SCSI; - int i; - - /* - * See if a bus reset was suggested. - */ - if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) { - /* - * This does a scsi reset for all devices on the bus. - * In principle, we could also reset the 1542 - should - * we do this? Try this first, and we can add that later - * if it turns out to be useful. - */ - outb(HRST | SCRST, CONTROL(SCpnt->host->io_port)); - - /* - * Wait for the thing to settle down a bit. Unfortunately - * this is going to basically lock up the machine while we - * wait for this to complete. To be 100% correct, we need to - * check for timeout, and if we are doing something like this - * we are pretty desperate anyways. - */ - WAIT(STATUS(SCpnt->host->io_port), - STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF); - - /* - * We need to do this too before the 1542 can interact with - * us again. - */ - setup_mailboxes(SCpnt->host->io_port, SCpnt->host); - - /* - * Now try to pick up the pieces. Restart all commands - * that are currently active on the bus, and reset all of - * the datastructures. We have some time to kill while - * things settle down, so print a nice message. - */ - printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no); - - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; - SCtmp->result = DID_RESET << 16; - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target); - SCtmp->scsi_done(SCpnt); - - HOSTDATA(SCpnt->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->host)->mb[i].status = 0; - } - /* - * Now tell the mid-level code what we did here. Since - * we have restarted all of the outstanding commands, - * then report SUCCESS. - */ - return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET); -fail: - printk(KERN_CRIT "aha1542.c: Unable to perform hard reset.\n"); - printk(KERN_CRIT "Power cycle machine to reset\n"); - return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET); - - - } else { - /* This does a selective reset of just the one device */ - /* First locate the ccb for this command */ - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) { - HOSTDATA(SCpnt->host)->ccb[i].op = 0x81; /* BUS DEVICE RESET */ - /* Now tell the 1542 to flush all pending commands for this target */ - aha1542_out(SCpnt->host->io_port, &ahacmd, 1); - - /* Here is the tricky part. What to do next. Do we get an interrupt - for the commands that we aborted with the specified target, or - do we generate this on our own? Try it without first and see - what happens */ - printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target); - - /* If the first does not work, then try the second. I think the - first option is more likely to be correct. Free the command - block for all commands running on this target... */ - for (i = 0; i < AHA1542_MAILBOXES; i++) - if (HOSTDATA(SCpnt->host)->SCint[i] && - HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) { - Scsi_Cmnd *SCtmp; - SCtmp = HOSTDATA(SCpnt->host)->SCint[i]; - SCtmp->result = DID_RESET << 16; - kfree(SCtmp->host_scribble); - SCtmp->host_scribble = NULL; - printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target); - SCtmp->scsi_done(SCpnt); - - HOSTDATA(SCpnt->host)->SCint[i] = NULL; - HOSTDATA(SCpnt->host)->mb[i].status = 0; - } - return SCSI_RESET_SUCCESS; - } - } - /* No active command at this time, so this means that each time we got - some kind of response the last time through. Tell the mid-level code - to request sense information in order to decide what to do next. */ - return SCSI_RESET_PUNT; -} -#endif /* end of big comment block around old_abort + old_reset */ - -static int aha1542_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *ip) -{ - int translation_algorithm; - int size = capacity; - - translation_algorithm = HOSTDATA(sdev->host)->bios_translation; - - if ((size >> 11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) { - /* Please verify that this is the same as what DOS returns */ - ip[0] = 255; - ip[1] = 63; - ip[2] = size / 255 / 63; - } else { - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - } - - return 0; -} -MODULE_LICENSE("GPL"); - - -static struct scsi_host_template driver_template = { - .proc_name = "aha1542", - .name = "Adaptec 1542", - .detect = aha1542_detect, - .release = aha1542_release, - .queuecommand = aha1542_queuecommand, - .eh_device_reset_handler= aha1542_dev_reset, - .eh_bus_reset_handler = aha1542_bus_reset, - .eh_host_reset_handler = aha1542_host_reset, - .bios_param = aha1542_biosparam, - .can_queue = AHA1542_MAILBOXES, - .this_id = 7, - .sg_tablesize = AHA1542_SCATTER, - .cmd_per_lun = AHA1542_CMDLUN, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/aha1542.h b/ANDROID_3.4.5/drivers/scsi/aha1542.h deleted file mode 100644 index b871d2b5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aha1542.h +++ /dev/null @@ -1,150 +0,0 @@ -#ifndef _AHA1542_H - -/* $Id: aha1542.h,v 1.1 1992/07/24 06:27:38 root Exp root $ - * - * Header file for the adaptec 1542 driver for Linux - * - * $Log: aha1542.h,v $ - * Revision 1.1 1992/07/24 06:27:38 root - * Initial revision - * - * Revision 1.2 1992/07/04 18:41:49 root - * Replaced distribution with current drivers - * - * Revision 1.3 1992/06/23 23:58:20 root - * Fixes. - * - * Revision 1.2 1992/05/26 22:13:23 root - * Changed bug that prevented DMA above first 2 mbytes. - * - * Revision 1.1 1992/05/22 21:00:29 root - * Initial revision - * - * Revision 1.1 1992/04/24 18:01:50 root - * Initial revision - * - * Revision 1.1 1992/04/02 03:23:13 drew - * Initial revision - * - * Revision 1.3 1992/01/27 14:46:29 tthorn - * *** empty log message *** - * - */ - -#include - -/* I/O Port interface 4.2 */ -/* READ */ -#define STATUS(base) base -#define STST 0x80 /* Self Test in Progress */ -#define DIAGF 0x40 /* Internal Diagnostic Failure */ -#define INIT 0x20 /* Mailbox Initialization Required */ -#define IDLE 0x10 /* SCSI Host Adapter Idle */ -#define CDF 0x08 /* Command/Data Out Port Full */ -#define DF 0x04 /* Data In Port Full */ -#define INVDCMD 0x01 /* Invalid H A Command */ -#define STATMASK 0xfd /* 0x02 is reserved */ - -#define INTRFLAGS(base) (STATUS(base)+2) -#define ANYINTR 0x80 /* Any Interrupt */ -#define SCRD 0x08 /* SCSI Reset Detected */ -#define HACC 0x04 /* HA Command Complete */ -#define MBOA 0x02 /* MBO Empty */ -#define MBIF 0x01 /* MBI Full */ -#define INTRMASK 0x8f - -/* WRITE */ -#define CONTROL(base) STATUS(base) -#define HRST 0x80 /* Hard Reset */ -#define SRST 0x40 /* Soft Reset */ -#define IRST 0x20 /* Interrupt Reset */ -#define SCRST 0x10 /* SCSI Bus Reset */ - -/* READ/WRITE */ -#define DATA(base) (STATUS(base)+1) -#define CMD_NOP 0x00 /* No Operation */ -#define CMD_MBINIT 0x01 /* Mailbox Initialization */ -#define CMD_START_SCSI 0x02 /* Start SCSI Command */ -#define CMD_INQUIRY 0x04 /* Adapter Inquiry */ -#define CMD_EMBOI 0x05 /* Enable MailBox Out Interrupt */ -#define CMD_BUSON_TIME 0x07 /* Set Bus-On Time */ -#define CMD_BUSOFF_TIME 0x08 /* Set Bus-Off Time */ -#define CMD_DMASPEED 0x09 /* Set AT Bus Transfer Speed */ -#define CMD_RETDEVS 0x0a /* Return Installed Devices */ -#define CMD_RETCONF 0x0b /* Return Configuration Data */ -#define CMD_RETSETUP 0x0d /* Return Setup Data */ -#define CMD_ECHO 0x1f /* ECHO Command Data */ - -#define CMD_EXTBIOS 0x28 /* Return extend bios information only 1542C */ -#define CMD_MBENABLE 0x29 /* Set Mailbox Interface enable only 1542C */ - -/* Mailbox Definition 5.2.1 and 5.2.2 */ -struct mailbox { - unchar status; /* Command/Status */ - unchar ccbptr[3]; /* msb, .., lsb */ -}; - -/* This is used with scatter-gather */ -struct chain { - unchar datalen[3]; /* Size of this part of chain */ - unchar dataptr[3]; /* Location of data */ -}; - -/* These belong in scsi.h also */ -static inline void any2scsi(u8 *p, u32 v) -{ - p[0] = v >> 16; - p[1] = v >> 8; - p[2] = v; -} - -#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) ) - -#define xany2scsi(up, p) \ -(up)[0] = ((long)(p)) >> 24; \ -(up)[1] = ((long)(p)) >> 16; \ -(up)[2] = ((long)(p)) >> 8; \ -(up)[3] = ((long)(p)); - -#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \ - + (((long)(up)[2]) << 8) + ((long)(up)[3]) ) - -#define MAX_CDB 12 -#define MAX_SENSE 14 - -struct ccb { /* Command Control Block 5.3 */ - unchar op; /* Command Control Block Operation Code */ - unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */ - /* Outbound data transfer, length is checked*/ - /* Inbound data transfer, length is checked */ - /* Logical Unit Number */ - unchar cdblen; /* SCSI Command Length */ - unchar rsalen; /* Request Sense Allocation Length/Disable */ - unchar datalen[3]; /* Data Length (msb, .., lsb) */ - unchar dataptr[3]; /* Data Pointer */ - unchar linkptr[3]; /* Link Pointer */ - unchar commlinkid; /* Command Linking Identifier */ - unchar hastat; /* Host Adapter Status (HASTAT) */ - unchar tarstat; /* Target Device Status */ - unchar reserved[2]; - unchar cdb[MAX_CDB+MAX_SENSE];/* SCSI Command Descriptor Block */ - /* REQUEST SENSE */ -}; - -static int aha1542_detect(struct scsi_host_template *); -static int aha1542_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static int aha1542_bus_reset(Scsi_Cmnd * SCpnt); -static int aha1542_dev_reset(Scsi_Cmnd * SCpnt); -static int aha1542_host_reset(Scsi_Cmnd * SCpnt); -#if 0 -static int aha1542_old_abort(Scsi_Cmnd * SCpnt); -static int aha1542_old_reset(Scsi_Cmnd *, unsigned int); -#endif -static int aha1542_biosparam(struct scsi_device *, struct block_device *, - sector_t, int *); - -#define AHA1542_MAILBOXES 8 -#define AHA1542_SCATTER 16 -#define AHA1542_CMDLUN 1 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aha1740.c b/ANDROID_3.4.5/drivers/scsi/aha1740.c deleted file mode 100644 index a3e6ed35..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aha1740.c +++ /dev/null @@ -1,697 +0,0 @@ -/* $Id$ - * 1993/03/31 - * linux/kernel/aha1740.c - * - * Based loosely on aha1542.c which is - * Copyright (C) 1992 Tommy Thorn and - * Modified by Eric Youngdale - * - * This file is aha1740.c, written and - * Copyright (C) 1992,1993 Brad McLean - * brad@saturn.gaylord.com or brad@bradpc.gaylord.com. - * - * Modifications to makecode and queuecommand - * for proper handling of multiple devices courteously - * provided by Michael Weller, March, 1993 - * - * Multiple adapter support, extended translation detection, - * update to current scsi subsystem changes, proc fs support, - * working (!) module support based on patches from Andreas Arens, - * by Andreas Degert , 2/1997 - * - * aha1740_makecode may still need even more work - * if it doesn't work for your devices, take a look. - * - * Reworked for new_eh and new locking by Alan Cox - * - * Converted to EISA and generic DMA APIs by Marc Zyngier - * , 4/2003. - * - * Shared interrupt support added by Rask Ingemann Lambertsen - * , 10/2003 - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open non patent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "scsi.h" -#include -#include "aha1740.h" - -/* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH - IT WORK, THEN: -#define DEBUG -*/ -#ifdef DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - -struct aha1740_hostdata { - struct eisa_device *edev; - unsigned int translation; - unsigned int last_ecb_used; - dma_addr_t ecb_dma_addr; - struct ecb ecb[AHA1740_ECBS]; -}; - -struct aha1740_sg { - struct aha1740_chain sg_chain[AHA1740_SCATTER]; - dma_addr_t sg_dma_addr; - dma_addr_t buf_dma_addr; -}; - -#define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata) - -static inline struct ecb *ecb_dma_to_cpu (struct Scsi_Host *host, - dma_addr_t dma) -{ - struct aha1740_hostdata *hdata = HOSTDATA (host); - dma_addr_t offset; - - offset = dma - hdata->ecb_dma_addr; - - return (struct ecb *)(((char *) hdata->ecb) + (unsigned int) offset); -} - -static inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu) -{ - struct aha1740_hostdata *hdata = HOSTDATA (host); - dma_addr_t offset; - - offset = (char *) cpu - (char *) hdata->ecb; - - return hdata->ecb_dma_addr + offset; -} - -static int aha1740_proc_info(struct Scsi_Host *shpnt, char *buffer, - char **start, off_t offset, - int length, int inout) -{ - int len; - struct aha1740_hostdata *host; - - if (inout) - return-ENOSYS; - - host = HOSTDATA(shpnt); - - len = sprintf(buffer, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n" - "Extended translation %sabled.\n", - shpnt->io_port, shpnt->irq, host->edev->slot, - host->translation ? "en" : "dis"); - - if (offset > len) { - *start = buffer; - return 0; - } - - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - return len; -} - -static int aha1740_makecode(unchar *sense, unchar *status) -{ - struct statusword - { - ushort don:1, /* Command Done - No Error */ - du:1, /* Data underrun */ - :1, qf:1, /* Queue full */ - sc:1, /* Specification Check */ - dor:1, /* Data overrun */ - ch:1, /* Chaining Halted */ - intr:1, /* Interrupt issued */ - asa:1, /* Additional Status Available */ - sns:1, /* Sense information Stored */ - :1, ini:1, /* Initialization Required */ - me:1, /* Major error or exception */ - :1, eca:1, /* Extended Contingent alliance */ - :1; - } status_word; - int retval = DID_OK; - - status_word = * (struct statusword *) status; -#ifdef DEBUG - printk("makecode from %x,%x,%x,%x %x,%x,%x,%x", - status[0], status[1], status[2], status[3], - sense[0], sense[1], sense[2], sense[3]); -#endif - if (!status_word.don) { /* Anything abnormal was detected */ - if ( (status[1]&0x18) || status_word.sc ) { - /*Additional info available*/ - /* Use the supplied info for further diagnostics */ - switch ( status[2] ) { - case 0x12: - if ( status_word.dor ) - retval=DID_ERROR; /* It's an Overrun */ - /* If not overrun, assume underrun and - * ignore it! */ - case 0x00: /* No info, assume no error, should - * not occur */ - break; - case 0x11: - case 0x21: - retval=DID_TIME_OUT; - break; - case 0x0a: - retval=DID_BAD_TARGET; - break; - case 0x04: - case 0x05: - retval=DID_ABORT; - /* Either by this driver or the - * AHA1740 itself */ - break; - default: - retval=DID_ERROR; /* No further - * diagnostics - * possible */ - } - } else { - /* Michael suggests, and Brad concurs: */ - if ( status_word.qf ) { - retval = DID_TIME_OUT; /* forces a redo */ - /* I think this specific one should - * not happen -Brad */ - printk("aha1740.c: WARNING: AHA1740 queue overflow!\n"); - } else - if ( status[0]&0x60 ) { - /* Didn't find a better error */ - retval = DID_ERROR; - } - /* In any other case return DID_OK so for example - CONDITION_CHECKS make it through to the appropriate - device driver */ - } - } - /* Under all circumstances supply the target status -Michael */ - return status[3] | retval << 16; -} - -static int aha1740_test_port(unsigned int base) -{ - if ( inb(PORTADR(base)) & PORTADDR_ENH ) - return 1; /* Okay, we're all set */ - - printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n"); - return 0; -} - -/* A "high" level interrupt handler */ -static irqreturn_t aha1740_intr_handle(int irq, void *dev_id) -{ - struct Scsi_Host *host = (struct Scsi_Host *) dev_id; - void (*my_done)(Scsi_Cmnd *); - int errstatus, adapstat; - int number_serviced; - struct ecb *ecbptr; - Scsi_Cmnd *SCtmp; - unsigned int base; - unsigned long flags; - int handled = 0; - struct aha1740_sg *sgptr; - struct eisa_device *edev; - - if (!host) - panic("aha1740.c: Irq from unknown host!\n"); - spin_lock_irqsave(host->host_lock, flags); - base = host->io_port; - number_serviced = 0; - edev = HOSTDATA(host)->edev; - - while(inb(G2STAT(base)) & G2STAT_INTPEND) { - handled = 1; - DEB(printk("aha1740_intr top of loop.\n")); - adapstat = inb(G2INTST(base)); - ecbptr = ecb_dma_to_cpu (host, inl(MBOXIN0(base))); - outb(G2CNTRL_IRST,G2CNTRL(base)); /* interrupt reset */ - - switch ( adapstat & G2INTST_MASK ) { - case G2INTST_CCBRETRY: - case G2INTST_CCBERROR: - case G2INTST_CCBGOOD: - /* Host Ready -> Mailbox in complete */ - outb(G2CNTRL_HRDY,G2CNTRL(base)); - if (!ecbptr) { - printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n", - inb(G2STAT(base)),adapstat, - inb(G2INTST(base)), number_serviced++); - continue; - } - SCtmp = ecbptr->SCpnt; - if (!SCtmp) { - printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n", - inb(G2STAT(base)),adapstat, - inb(G2INTST(base)), number_serviced++); - continue; - } - sgptr = (struct aha1740_sg *) SCtmp->host_scribble; - scsi_dma_unmap(SCtmp); - - /* Free the sg block */ - dma_free_coherent (&edev->dev, - sizeof (struct aha1740_sg), - SCtmp->host_scribble, - sgptr->sg_dma_addr); - - /* Fetch the sense data, and tuck it away, in - the required slot. The Adaptec - automatically fetches it, and there is no - guarantee that we will still have it in the - cdb when we come back */ - if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) { - memcpy(SCtmp->sense_buffer, ecbptr->sense, - SCSI_SENSE_BUFFERSIZE); - errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status); - } else - errstatus = 0; - DEB(if (errstatus) - printk("aha1740_intr_handle: returning %6x\n", - errstatus)); - SCtmp->result = errstatus; - my_done = ecbptr->done; - memset(ecbptr,0,sizeof(struct ecb)); - if ( my_done ) - my_done(SCtmp); - break; - - case G2INTST_HARDFAIL: - printk(KERN_ALERT "aha1740 hardware failure!\n"); - panic("aha1740.c"); /* Goodbye */ - - case G2INTST_ASNEVENT: - printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n", - adapstat, - inb(MBOXIN0(base)), - inb(MBOXIN1(base)), - inb(MBOXIN2(base)), - inb(MBOXIN3(base))); /* Say What? */ - /* Host Ready -> Mailbox in complete */ - outb(G2CNTRL_HRDY,G2CNTRL(base)); - break; - - case G2INTST_CMDGOOD: - /* set immediate command success flag here: */ - break; - - case G2INTST_CMDERROR: - /* Set immediate command failure flag here: */ - break; - } - number_serviced++; - } - - spin_unlock_irqrestore(host->host_lock, flags); - return IRQ_RETVAL(handled); -} - -static int aha1740_queuecommand_lck(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) -{ - unchar direction; - unchar *cmd = (unchar *) SCpnt->cmnd; - unchar target = scmd_id(SCpnt); - struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host); - unsigned long flags; - dma_addr_t sg_dma; - struct aha1740_sg *sgptr; - int ecbno, nseg; - DEB(int i); - - if(*cmd == REQUEST_SENSE) { - SCpnt->result = 0; - done(SCpnt); - return 0; - } - -#ifdef DEBUG - if (*cmd == READ_10 || *cmd == WRITE_10) - i = xscsi2int(cmd+2); - else if (*cmd == READ_6 || *cmd == WRITE_6) - i = scsi2int(cmd+2); - else - i = -1; - printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", - target, *cmd, i, bufflen); - printk("scsi cmd:"); - for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]); - printk("\n"); -#endif - - /* locate an available ecb */ - spin_lock_irqsave(SCpnt->device->host->host_lock, flags); - ecbno = host->last_ecb_used + 1; /* An optimization */ - if (ecbno >= AHA1740_ECBS) - ecbno = 0; - do { - if (!host->ecb[ecbno].cmdw) - break; - ecbno++; - if (ecbno >= AHA1740_ECBS) - ecbno = 0; - } while (ecbno != host->last_ecb_used); - - if (host->ecb[ecbno].cmdw) - panic("Unable to find empty ecb for aha1740.\n"); - - host->ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command - doubles as reserved flag */ - - host->last_ecb_used = ecbno; - spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); - -#ifdef DEBUG - printk("Sending command (%d %x)...", ecbno, done); -#endif - - host->ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command - * Descriptor Block - * Length */ - - direction = 0; - if (*cmd == READ_10 || *cmd == READ_6) - direction = 1; - else if (*cmd == WRITE_10 || *cmd == WRITE_6) - direction = 0; - - memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len); - - SCpnt->host_scribble = dma_alloc_coherent (&host->edev->dev, - sizeof (struct aha1740_sg), - &sg_dma, GFP_ATOMIC); - if(SCpnt->host_scribble == NULL) { - printk(KERN_WARNING "aha1740: out of memory in queuecommand!\n"); - return 1; - } - sgptr = (struct aha1740_sg *) SCpnt->host_scribble; - sgptr->sg_dma_addr = sg_dma; - - nseg = scsi_dma_map(SCpnt); - BUG_ON(nseg < 0); - if (nseg) { - struct scatterlist *sg; - struct aha1740_chain * cptr; - int i; - DEB(unsigned char * ptr); - - host->ecb[ecbno].sg = 1; /* SCSI Initiator Command - * w/scatter-gather*/ - cptr = sgptr->sg_chain; - scsi_for_each_sg(SCpnt, sg, nseg, i) { - cptr[i].datalen = sg_dma_len (sg); - cptr[i].dataptr = sg_dma_address (sg); - } - host->ecb[ecbno].datalen = nseg * sizeof(struct aha1740_chain); - host->ecb[ecbno].dataptr = sg_dma; -#ifdef DEBUG - printk("cptr %x: ",cptr); - ptr = (unsigned char *) cptr; - for(i=0;i<24;i++) printk("%02x ", ptr[i]); -#endif - } else { - host->ecb[ecbno].datalen = 0; - host->ecb[ecbno].dataptr = 0; - } - host->ecb[ecbno].lun = SCpnt->device->lun; - host->ecb[ecbno].ses = 1; /* Suppress underrun errors */ - host->ecb[ecbno].dir = direction; - host->ecb[ecbno].ars = 1; /* Yes, get the sense on an error */ - host->ecb[ecbno].senselen = 12; - host->ecb[ecbno].senseptr = ecb_cpu_to_dma (SCpnt->device->host, - host->ecb[ecbno].sense); - host->ecb[ecbno].statusptr = ecb_cpu_to_dma (SCpnt->device->host, - host->ecb[ecbno].status); - host->ecb[ecbno].done = done; - host->ecb[ecbno].SCpnt = SCpnt; -#ifdef DEBUG - { - int i; - printk("aha1740_command: sending.. "); - for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++) - printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]); - } - printk("\n"); -#endif - if (done) { - /* The Adaptec Spec says the card is so fast that the loops - will only be executed once in the code below. Even if this - was true with the fastest processors when the spec was - written, it doesn't seem to be true with today's fast - processors. We print a warning if the code is executed more - often than LOOPCNT_WARN. If this happens, it should be - investigated. If the count reaches LOOPCNT_MAX, we assume - something is broken; since there is no way to return an - error (the return value is ignored by the mid-level scsi - layer) we have to panic (and maybe that's the best thing we - can do then anyhow). */ - -#define LOOPCNT_WARN 10 /* excessive mbxout wait -> syslog-msg */ -#define LOOPCNT_MAX 1000000 /* mbxout deadlock -> panic() after ~ 2 sec. */ - int loopcnt; - unsigned int base = SCpnt->device->host->io_port; - DEB(printk("aha1740[%d] critical section\n",ecbno)); - - spin_lock_irqsave(SCpnt->device->host->host_lock, flags); - for (loopcnt = 0; ; loopcnt++) { - if (inb(G2STAT(base)) & G2STAT_MBXOUT) break; - if (loopcnt == LOOPCNT_WARN) { - printk("aha1740[%d]_mbxout wait!\n",ecbno); - } - if (loopcnt == LOOPCNT_MAX) - panic("aha1740.c: mbxout busy!\n"); - } - outl (ecb_cpu_to_dma (SCpnt->device->host, host->ecb + ecbno), - MBOXOUT0(base)); - for (loopcnt = 0; ; loopcnt++) { - if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break; - if (loopcnt == LOOPCNT_WARN) { - printk("aha1740[%d]_attn wait!\n",ecbno); - } - if (loopcnt == LOOPCNT_MAX) - panic("aha1740.c: attn wait failed!\n"); - } - outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */ - spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags); - DEB(printk("aha1740[%d] request queued.\n",ecbno)); - } else - printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n"); - return 0; -} - -static DEF_SCSI_QCMD(aha1740_queuecommand) - -/* Query the board for its irq_level and irq_type. Nothing else matters - in enhanced mode on an EISA bus. */ - -static void aha1740_getconfig(unsigned int base, unsigned int *irq_level, - unsigned int *irq_type, - unsigned int *translation) -{ - static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 }; - - *irq_level = intab[inb(INTDEF(base)) & 0x7]; - *irq_type = (inb(INTDEF(base)) & 0x8) >> 3; - *translation = inb(RESV1(base)) & 0x1; - outb(inb(INTDEF(base)) | 0x10, INTDEF(base)); -} - -static int aha1740_biosparam(struct scsi_device *sdev, - struct block_device *dev, - sector_t capacity, int* ip) -{ - int size = capacity; - int extended = HOSTDATA(sdev->host)->translation; - - DEB(printk("aha1740_biosparam\n")); - if (extended && (ip[2] > 1024)) { - ip[0] = 255; - ip[1] = 63; - ip[2] = size / (255 * 63); - } else { - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - } - return 0; -} - -static int aha1740_eh_abort_handler (Scsi_Cmnd *dummy) -{ -/* - * From Alan Cox : - * The AHA1740 has firmware handled abort/reset handling. The "head in - * sand" kernel code is correct for once 8) - * - * So we define a dummy handler just to keep the kernel SCSI code as - * quiet as possible... - */ - - return 0; -} - -static struct scsi_host_template aha1740_template = { - .module = THIS_MODULE, - .proc_name = "aha1740", - .proc_info = aha1740_proc_info, - .name = "Adaptec 174x (EISA)", - .queuecommand = aha1740_queuecommand, - .bios_param = aha1740_biosparam, - .can_queue = AHA1740_ECBS, - .this_id = 7, - .sg_tablesize = AHA1740_SCATTER, - .cmd_per_lun = AHA1740_CMDLUN, - .use_clustering = ENABLE_CLUSTERING, - .eh_abort_handler = aha1740_eh_abort_handler, -}; - -static int aha1740_probe (struct device *dev) -{ - int slotbase, rc; - unsigned int irq_level, irq_type, translation; - struct Scsi_Host *shpnt; - struct aha1740_hostdata *host; - struct eisa_device *edev = to_eisa_device (dev); - - DEB(printk("aha1740_probe: \n")); - - slotbase = edev->base_addr + EISA_VENDOR_ID_OFFSET; - if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */ - return -EBUSY; - if (!aha1740_test_port(slotbase)) - goto err_release_region; - aha1740_getconfig(slotbase,&irq_level,&irq_type,&translation); - if ((inb(G2STAT(slotbase)) & - (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) { - /* If the card isn't ready, hard reset it */ - outb(G2CNTRL_HRST, G2CNTRL(slotbase)); - outb(0, G2CNTRL(slotbase)); - } - printk(KERN_INFO "Configuring slot %d at IO:%x, IRQ %u (%s)\n", - edev->slot, slotbase, irq_level, irq_type ? "edge" : "level"); - printk(KERN_INFO "aha174x: Extended translation %sabled.\n", - translation ? "en" : "dis"); - shpnt = scsi_host_alloc(&aha1740_template, - sizeof(struct aha1740_hostdata)); - if(shpnt == NULL) - goto err_release_region; - - shpnt->base = 0; - shpnt->io_port = slotbase; - shpnt->n_io_port = SLOTSIZE; - shpnt->irq = irq_level; - shpnt->dma_channel = 0xff; - host = HOSTDATA(shpnt); - host->edev = edev; - host->translation = translation; - host->ecb_dma_addr = dma_map_single (&edev->dev, host->ecb, - sizeof (host->ecb), - DMA_BIDIRECTIONAL); - if (!host->ecb_dma_addr) { - printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n"); - scsi_unregister (shpnt); - goto err_host_put; - } - - DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level)); - if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : IRQF_SHARED, - "aha1740",shpnt)) { - printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n", - irq_level); - goto err_unmap; - } - - eisa_set_drvdata (edev, shpnt); - - rc = scsi_add_host (shpnt, dev); - if (rc) - goto err_irq; - - scsi_scan_host (shpnt); - return 0; - - err_irq: - free_irq(irq_level, shpnt); - err_unmap: - dma_unmap_single (&edev->dev, host->ecb_dma_addr, - sizeof (host->ecb), DMA_BIDIRECTIONAL); - err_host_put: - scsi_host_put (shpnt); - err_release_region: - release_region(slotbase, SLOTSIZE); - - return -ENODEV; -} - -static __devexit int aha1740_remove (struct device *dev) -{ - struct Scsi_Host *shpnt = dev_get_drvdata(dev); - struct aha1740_hostdata *host = HOSTDATA (shpnt); - - scsi_remove_host(shpnt); - - free_irq (shpnt->irq, shpnt); - dma_unmap_single (dev, host->ecb_dma_addr, - sizeof (host->ecb), DMA_BIDIRECTIONAL); - release_region (shpnt->io_port, SLOTSIZE); - - scsi_host_put (shpnt); - - return 0; -} - -static struct eisa_device_id aha1740_ids[] = { - { "ADP0000" }, /* 1740 */ - { "ADP0001" }, /* 1740A */ - { "ADP0002" }, /* 1742A */ - { "ADP0400" }, /* 1744 */ - { "" } -}; -MODULE_DEVICE_TABLE(eisa, aha1740_ids); - -static struct eisa_driver aha1740_driver = { - .id_table = aha1740_ids, - .driver = { - .name = "aha1740", - .probe = aha1740_probe, - .remove = __devexit_p (aha1740_remove), - }, -}; - -static __init int aha1740_init (void) -{ - return eisa_driver_register (&aha1740_driver); -} - -static __exit void aha1740_exit (void) -{ - eisa_driver_unregister (&aha1740_driver); -} - -module_init (aha1740_init); -module_exit (aha1740_exit); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/aha1740.h b/ANDROID_3.4.5/drivers/scsi/aha1740.h deleted file mode 100644 index af23fd6b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aha1740.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef _AHA1740_H - -/* $Id$ - * - * Header file for the adaptec 1740 driver for Linux - * - * With minor revisions 3/31/93 - * Written and (C) 1992,1993 Brad McLean. See aha1740.c - * for more info - * - */ - -#include - -#define SLOTSIZE 0x5c - -/* EISA configuration registers & values */ -#define HID0(base) (base + 0x0) -#define HID1(base) (base + 0x1) -#define HID2(base) (base + 0x2) -#define HID3(base) (base + 0x3) -#define EBCNTRL(base) (base + 0x4) -#define PORTADR(base) (base + 0x40) -#define BIOSADR(base) (base + 0x41) -#define INTDEF(base) (base + 0x42) -#define SCSIDEF(base) (base + 0x43) -#define BUSDEF(base) (base + 0x44) -#define RESV0(base) (base + 0x45) -#define RESV1(base) (base + 0x46) -#define RESV2(base) (base + 0x47) - -#define HID_MFG "ADP" -#define HID_PRD 0 -#define HID_REV 2 -#define EBCNTRL_VALUE 1 -#define PORTADDR_ENH 0x80 -/* READ */ -#define G2INTST(base) (base + 0x56) -#define G2STAT(base) (base + 0x57) -#define MBOXIN0(base) (base + 0x58) -#define MBOXIN1(base) (base + 0x59) -#define MBOXIN2(base) (base + 0x5a) -#define MBOXIN3(base) (base + 0x5b) -#define G2STAT2(base) (base + 0x5c) - -#define G2INTST_MASK 0xf0 /* isolate the status */ -#define G2INTST_CCBGOOD 0x10 /* CCB Completed */ -#define G2INTST_CCBRETRY 0x50 /* CCB Completed with a retry */ -#define G2INTST_HARDFAIL 0x70 /* Adapter Hardware Failure */ -#define G2INTST_CMDGOOD 0xa0 /* Immediate command success */ -#define G2INTST_CCBERROR 0xc0 /* CCB Completed with error */ -#define G2INTST_ASNEVENT 0xd0 /* Asynchronous Event Notification */ -#define G2INTST_CMDERROR 0xe0 /* Immediate command error */ - -#define G2STAT_MBXOUT 4 /* Mailbox Out Empty Bit */ -#define G2STAT_INTPEND 2 /* Interrupt Pending Bit */ -#define G2STAT_BUSY 1 /* Busy Bit (attention pending) */ - -#define G2STAT2_READY 0 /* Host Ready Bit */ - -/* WRITE (and ReadBack) */ -#define MBOXOUT0(base) (base + 0x50) -#define MBOXOUT1(base) (base + 0x51) -#define MBOXOUT2(base) (base + 0x52) -#define MBOXOUT3(base) (base + 0x53) -#define ATTN(base) (base + 0x54) -#define G2CNTRL(base) (base + 0x55) - -#define ATTN_IMMED 0x10 /* Immediate Command */ -#define ATTN_START 0x40 /* Start CCB */ -#define ATTN_ABORT 0x50 /* Abort CCB */ - -#define G2CNTRL_HRST 0x80 /* Hard Reset */ -#define G2CNTRL_IRST 0x40 /* Clear EISA Interrupt */ -#define G2CNTRL_HRDY 0x20 /* Sets HOST ready */ - -/* This is used with scatter-gather */ -struct aha1740_chain { - u32 dataptr; /* Location of data */ - u32 datalen; /* Size of this part of chain */ -}; - -/* These belong in scsi.h */ -#define any2scsi(up, p) \ -(up)[0] = (((unsigned long)(p)) >> 16) ; \ -(up)[1] = (((unsigned long)(p)) >> 8); \ -(up)[2] = ((unsigned long)(p)); - -#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) ) - -#define xany2scsi(up, p) \ -(up)[0] = ((long)(p)) >> 24; \ -(up)[1] = ((long)(p)) >> 16; \ -(up)[2] = ((long)(p)) >> 8; \ -(up)[3] = ((long)(p)); - -#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \ - + (((long)(up)[2]) << 8) + ((long)(up)[3]) ) - -#define MAX_CDB 12 -#define MAX_SENSE 14 -#define MAX_STATUS 32 - -struct ecb { /* Enhanced Control Block 6.1 */ - u16 cmdw; /* Command Word */ - /* Flag Word 1 */ - u16 cne:1, /* Control Block Chaining */ - :6, di:1, /* Disable Interrupt */ - :2, ses:1, /* Suppress Underrun error */ - :1, sg:1, /* Scatter/Gather */ - :1, dsb:1, /* Disable Status Block */ - ars:1; /* Automatic Request Sense */ - /* Flag Word 2 */ - u16 lun:3, /* Logical Unit */ - tag:1, /* Tagged Queuing */ - tt:2, /* Tag Type */ - nd:1, /* No Disconnect */ - :1, dat:1, /* Data transfer - check direction */ - dir:1, /* Direction of transfer 1 = datain */ - st:1, /* Suppress Transfer */ - chk:1, /* Calculate Checksum */ - :2, rec:1,:1; /* Error Recovery */ - u16 nil0; /* nothing */ - u32 dataptr; /* Data or Scatter List ptr */ - u32 datalen; /* Data or Scatter List len */ - u32 statusptr; /* Status Block ptr */ - u32 linkptr; /* Chain Address */ - u32 nil1; /* nothing */ - u32 senseptr; /* Sense Info Pointer */ - u8 senselen; /* Sense Length */ - u8 cdblen; /* CDB Length */ - u16 datacheck; /* Data checksum */ - u8 cdb[MAX_CDB]; /* CDB area */ -/* Hardware defined portion ends here, rest is driver defined */ - u8 sense[MAX_SENSE]; /* Sense area */ - u8 status[MAX_STATUS]; /* Status area */ - Scsi_Cmnd *SCpnt; /* Link to the SCSI Command Block */ - void (*done) (Scsi_Cmnd *); /* Completion Function */ -}; - -#define AHA1740CMD_NOP 0x00 /* No OP */ -#define AHA1740CMD_INIT 0x01 /* Initiator SCSI Command */ -#define AHA1740CMD_DIAG 0x05 /* Run Diagnostic Command */ -#define AHA1740CMD_SCSI 0x06 /* Initialize SCSI */ -#define AHA1740CMD_SENSE 0x08 /* Read Sense Information */ -#define AHA1740CMD_DOWN 0x09 /* Download Firmware (yeah, I bet!) */ -#define AHA1740CMD_RINQ 0x0a /* Read Host Adapter Inquiry Data */ -#define AHA1740CMD_TARG 0x10 /* Target SCSI Command */ - -#define AHA1740_ECBS 32 -#define AHA1740_SCATTER 16 -#define AHA1740_CMDLUN 1 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic79xx b/ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic79xx deleted file mode 100644 index 67390694..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ /dev/null @@ -1,85 +0,0 @@ -# -# AIC79XX 2.5.X Kernel configuration File. -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#4 $ -# -config SCSI_AIC79XX - tristate "Adaptec AIC79xx U320 support" - depends on PCI && SCSI - select SCSI_SPI_ATTRS - help - This driver supports all of Adaptec's Ultra 320 PCI-X - based SCSI controllers. - -config AIC79XX_CMDS_PER_DEVICE - int "Maximum number of TCQ commands per device" - depends on SCSI_AIC79XX - default "32" - ---help--- - Specify the number of commands you would like to allocate per SCSI - device when Tagged Command Queueing (TCQ) is enabled on that device. - - This is an upper bound value for the number of tagged transactions - to be used for any device. The aic7xxx driver will automatically - vary this number based on device behavior. For devices with a - fixed maximum, the driver will eventually lock to this maximum - and display a console message indicating this value. - - Due to resource allocation issues in the Linux SCSI mid-layer, using - a high number of commands per device may result in memory allocation - failures when many devices are attached to the system. For this reason, - the default is set to 32. Higher values may result in higher performance - on some devices. The upper bound is 253. 0 disables tagged queueing. - - Per device tag depth can be controlled via the kernel command line - "tag_info" option. See Documentation/scsi/aic79xx.txt for details. - -config AIC79XX_RESET_DELAY_MS - int "Initial bus reset delay in milli-seconds" - depends on SCSI_AIC79XX - default "5000" - ---help--- - The number of milliseconds to delay after an initial bus reset. - The bus settle delay following all error recovery actions is - dictated by the SCSI layer and is not affected by this value. - - Default: 5000 (5 seconds) - -config AIC79XX_BUILD_FIRMWARE - bool "Build Adapter Firmware with Kernel Build" - depends on SCSI_AIC79XX && !PREVENT_FIRMWARE_BUILD - help - This option should only be enabled if you are modifying the firmware - source to the aic79xx driver and wish to have the generated firmware - include files updated during a normal kernel build. The assembler - for the firmware requires lex and yacc or their equivalents, as well - as the db v1 library. You may have to install additional packages - or modify the assembler Makefile or the files it includes if your - build environment is different than that of the author. - -config AIC79XX_DEBUG_ENABLE - bool "Compile in Debugging Code" - depends on SCSI_AIC79XX - default y - help - Compile in aic79xx debugging code that can be useful in diagnosing - driver errors. - -config AIC79XX_DEBUG_MASK - int "Debug code enable mask (16383 for all debugging)" - depends on SCSI_AIC79XX - default "0" - help - Bit mask of debug options that is only valid if the - CONFIG_AIC79XX_DEBUG_ENBLE option is enabled. The bits in this mask - are defined in the drivers/scsi/aic7xxx/aic79xx.h - search for the - variable ahd_debug in that file to find them. - -config AIC79XX_REG_PRETTY_PRINT - bool "Decode registers during diagnostics" - depends on SCSI_AIC79XX - default y - help - Compile in register value tables for the output of expanded register - contents in diagnostics. This make it much easier to understand debug - output without having to refer to a data book and/or the aic7xxx.reg - file. diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic7xxx deleted file mode 100644 index 55ac55ee..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ /dev/null @@ -1,90 +0,0 @@ -# -# AIC7XXX and AIC79XX 2.5.X Kernel configuration File. -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#7 $ -# -config SCSI_AIC7XXX - tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)" - depends on (PCI || EISA) && SCSI - select SCSI_SPI_ATTRS - ---help--- - This driver supports all of Adaptec's Fast through Ultra 160 PCI - based SCSI controllers as well as the aic7770 based EISA and VLB - SCSI controllers (the 274x and 284x series). For AAA and ARO based - configurations, only SCSI functionality is provided. - - To compile this driver as a module, choose M here: the - module will be called aic7xxx. - -config AIC7XXX_CMDS_PER_DEVICE - int "Maximum number of TCQ commands per device" - depends on SCSI_AIC7XXX - default "32" - ---help--- - Specify the number of commands you would like to allocate per SCSI - device when Tagged Command Queueing (TCQ) is enabled on that device. - - This is an upper bound value for the number of tagged transactions - to be used for any device. The aic7xxx driver will automatically - vary this number based on device behavior. For devices with a - fixed maximum, the driver will eventually lock to this maximum - and display a console message indicating this value. - - Due to resource allocation issues in the Linux SCSI mid-layer, using - a high number of commands per device may result in memory allocation - failures when many devices are attached to the system. For this reason, - the default is set to 32. Higher values may result in higher performance - on some devices. The upper bound is 253. 0 disables tagged queueing. - - Per device tag depth can be controlled via the kernel command line - "tag_info" option. See Documentation/scsi/aic7xxx.txt for details. - -config AIC7XXX_RESET_DELAY_MS - int "Initial bus reset delay in milli-seconds" - depends on SCSI_AIC7XXX - default "5000" - ---help--- - The number of milliseconds to delay after an initial bus reset. - The bus settle delay following all error recovery actions is - dictated by the SCSI layer and is not affected by this value. - - Default: 5000 (5 seconds) - -config AIC7XXX_BUILD_FIRMWARE - bool "Build Adapter Firmware with Kernel Build" - depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD - help - This option should only be enabled if you are modifying the firmware - source to the aic7xxx driver and wish to have the generated firmware - include files updated during a normal kernel build. The assembler - for the firmware requires lex and yacc or their equivalents, as well - as the db v1 library. You may have to install additional packages - or modify the assembler Makefile or the files it includes if your - build environment is different than that of the author. - -config AIC7XXX_DEBUG_ENABLE - bool "Compile in Debugging Code" - depends on SCSI_AIC7XXX - default y - help - Compile in aic7xxx debugging code that can be useful in diagnosing - driver errors. - -config AIC7XXX_DEBUG_MASK - int "Debug code enable mask (2047 for all debugging)" - depends on SCSI_AIC7XXX - default "0" - help - Bit mask of debug options that is only valid if the - CONFIG_AIC7XXX_DEBUG_ENABLE option is enabled. The bits in this mask - are defined in the drivers/scsi/aic7xxx/aic7xxx.h - search for the - variable ahc_debug in that file to find them. - -config AIC7XXX_REG_PRETTY_PRINT - bool "Decode registers during diagnostics" - depends on SCSI_AIC7XXX - default y - help - Compile in register value tables for the output of expanded register - contents in diagnostics. This make it much easier to understand debug - output without having to refer to a data book and/or the aic7xxx.reg - file. diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/Makefile b/ANDROID_3.4.5/drivers/scsi/aic7xxx/Makefile deleted file mode 100644 index 741d8186..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/Makefile +++ /dev/null @@ -1,85 +0,0 @@ -# -# Makefile for the Linux aic7xxx SCSI driver. -# -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Makefile#8 $ -# - -# Let kbuild descend into aicasm when cleaning -subdir- += aicasm - -obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o -obj-$(CONFIG_SCSI_AIC79XX) += aic79xx.o - -# Core Fast -> U160 files -aic7xxx-y += aic7xxx_core.o \ - aic7xxx_93cx6.o -aic7xxx-$(CONFIG_EISA) += aic7770.o -aic7xxx-$(CONFIG_PCI) += aic7xxx_pci.o -aic7xxx-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) += aic7xxx_reg_print.o - -# Platform Specific Fast -> U160 Files -aic7xxx-y += aic7xxx_osm.o \ - aic7xxx_proc.o -aic7xxx-$(CONFIG_EISA) += aic7770_osm.o -aic7xxx-$(CONFIG_PCI) += aic7xxx_osm_pci.o - -# Core U320 files -aic79xx-y += aic79xx_core.o \ - aic79xx_pci.o -aic79xx-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) += aic79xx_reg_print.o - -# Platform Specific U320 Files -aic79xx-y += aic79xx_osm.o \ - aic79xx_proc.o \ - aic79xx_osm_pci.o - -ccflags-y += -Idrivers/scsi -ifdef WARNINGS_BECOME_ERRORS -ccflags-y += -Werror -endif - -# Files generated that shall be removed upon make clean -clean-files := aic7xxx_seq.h aic7xxx_reg.h aic7xxx_reg_print.c -clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c - -# Dependencies for generated files need to be listed explicitly - -$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_seq.h $(obj)/aic7xxx_reg.h -$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_seq.h $(obj)/aic79xx_reg.h - -aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE) := $(obj)/aic7xxx_reg.h -aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) += $(obj)/aic7xxx_reg_print.c - -aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \ - -p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h - -ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y) -$(obj)/aic7xxx_seq.h: $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm - $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \ - $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \ - $(src)/aic7xxx.seq - -$(aic7xxx-gen-y): $(obj)/aic7xxx_seq.h -else -$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped -endif - -aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE) := $(obj)/aic79xx_reg.h -aic79xx-gen-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) += $(obj)/aic79xx_reg_print.c - -aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \ - -p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h - -ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y) -$(obj)/aic79xx_seq.h: $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm - $(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \ - $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \ - $(src)/aic79xx.seq - -$(aic79xx-gen-y): $(obj)/aic79xx_seq.h -else -$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped -endif - -$(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl] - $(MAKE) -C $(src)/aicasm diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770.c deleted file mode 100644 index 5000bd69..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * Product specific probe and attach routines for: - * 27/284X and aic7770 motherboard SCSI controllers - * - * Copyright (c) 1994-1998, 2000, 2001 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#32 $ - * - * $FreeBSD$ - */ - -#ifdef __linux__ -#include "aic7xxx_osm.h" -#include "aic7xxx_inline.h" -#include "aic7xxx_93cx6.h" -#else -#include -#include -#include -#endif - -#define ID_AIC7770 0x04907770 -#define ID_AHA_274x 0x04907771 -#define ID_AHA_284xB 0x04907756 /* BIOS enabled */ -#define ID_AHA_284x 0x04907757 /* BIOS disabled*/ -#define ID_OLV_274x 0x04907782 /* Olivetti OEM */ -#define ID_OLV_274xD 0x04907783 /* Olivetti OEM (Differential) */ - -static int aic7770_chip_init(struct ahc_softc *ahc); -static int aha2840_load_seeprom(struct ahc_softc *ahc); -static ahc_device_setup_t ahc_aic7770_VL_setup; -static ahc_device_setup_t ahc_aic7770_EISA_setup; -static ahc_device_setup_t ahc_aic7770_setup; - -struct aic7770_identity aic7770_ident_table[] = -{ - { - ID_AHA_274x, - 0xFFFFFFFF, - "Adaptec 274X SCSI adapter", - ahc_aic7770_EISA_setup - }, - { - ID_AHA_284xB, - 0xFFFFFFFE, - "Adaptec 284X SCSI adapter", - ahc_aic7770_VL_setup - }, - { - ID_AHA_284x, - 0xFFFFFFFE, - "Adaptec 284X SCSI adapter (BIOS Disabled)", - ahc_aic7770_VL_setup - }, - { - ID_OLV_274x, - 0xFFFFFFFF, - "Adaptec (Olivetti OEM) 274X SCSI adapter", - ahc_aic7770_EISA_setup - }, - { - ID_OLV_274xD, - 0xFFFFFFFF, - "Adaptec (Olivetti OEM) 274X Differential SCSI adapter", - ahc_aic7770_EISA_setup - }, - /* Generic chip probes for devices we don't know 'exactly' */ - { - ID_AIC7770, - 0xFFFFFFFF, - "Adaptec aic7770 SCSI adapter", - ahc_aic7770_EISA_setup - } -}; -const int ahc_num_aic7770_devs = ARRAY_SIZE(aic7770_ident_table); - -struct aic7770_identity * -aic7770_find_device(uint32_t id) -{ - struct aic7770_identity *entry; - int i; - - for (i = 0; i < ahc_num_aic7770_devs; i++) { - entry = &aic7770_ident_table[i]; - if (entry->full_id == (id & entry->id_mask)) - return (entry); - } - return (NULL); -} - -int -aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) -{ - int error; - int have_seeprom; - u_int hostconf; - u_int irq; - u_int intdef; - - error = entry->setup(ahc); - have_seeprom = 0; - if (error != 0) - return (error); - - error = aic7770_map_registers(ahc, io); - if (error != 0) - return (error); - - /* - * Before we continue probing the card, ensure that - * its interrupts are *disabled*. We don't want - * a misstep to hang the machine in an interrupt - * storm. - */ - ahc_intr_enable(ahc, FALSE); - - ahc->description = entry->name; - error = ahc_softc_init(ahc); - if (error != 0) - return (error); - - ahc->bus_chip_init = aic7770_chip_init; - - error = ahc_reset(ahc, /*reinit*/FALSE); - if (error != 0) - return (error); - - /* Make sure we have a valid interrupt vector */ - intdef = ahc_inb(ahc, INTDEF); - irq = intdef & VECTOR; - switch (irq) { - case 9: - case 10: - case 11: - case 12: - case 14: - case 15: - break; - default: - printk("aic7770_config: invalid irq setting %d\n", intdef); - return (ENXIO); - } - - if ((intdef & EDGE_TRIG) != 0) - ahc->flags |= AHC_EDGE_INTERRUPT; - - switch (ahc->chip & (AHC_EISA|AHC_VL)) { - case AHC_EISA: - { - u_int biosctrl; - u_int scsiconf; - u_int scsiconf1; - - biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL); - scsiconf = ahc_inb(ahc, SCSICONF); - scsiconf1 = ahc_inb(ahc, SCSICONF + 1); - - /* Get the primary channel information */ - if ((biosctrl & CHANNEL_B_PRIMARY) != 0) - ahc->flags |= 1; - - if ((biosctrl & BIOSMODE) == BIOSDISABLED) { - ahc->flags |= AHC_USEDEFAULTS; - } else { - if ((ahc->features & AHC_WIDE) != 0) { - ahc->our_id = scsiconf1 & HWSCSIID; - if (scsiconf & TERM_ENB) - ahc->flags |= AHC_TERM_ENB_A; - } else { - ahc->our_id = scsiconf & HSCSIID; - ahc->our_id_b = scsiconf1 & HSCSIID; - if (scsiconf & TERM_ENB) - ahc->flags |= AHC_TERM_ENB_A; - if (scsiconf1 & TERM_ENB) - ahc->flags |= AHC_TERM_ENB_B; - } - } - if ((ahc_inb(ahc, HA_274_BIOSGLOBAL) & HA_274_EXTENDED_TRANS)) - ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B; - break; - } - case AHC_VL: - { - have_seeprom = aha2840_load_seeprom(ahc); - break; - } - default: - break; - } - if (have_seeprom == 0) { - kfree(ahc->seep_config); - ahc->seep_config = NULL; - } - - /* - * Ensure autoflush is enabled - */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS); - - /* Setup the FIFO threshold and the bus off time */ - hostconf = ahc_inb(ahc, HOSTCONF); - ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH); - ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF); - - ahc->bus_softc.aic7770_softc.busspd = hostconf & DFTHRSH; - ahc->bus_softc.aic7770_softc.bustime = (hostconf << 2) & BOFF; - - /* - * Generic aic7xxx initialization. - */ - error = ahc_init(ahc); - if (error != 0) - return (error); - - error = aic7770_map_int(ahc, irq); - if (error != 0) - return (error); - - ahc->init_level++; - - /* - * Enable the board's BUS drivers - */ - ahc_outb(ahc, BCTL, ENABLE); - return (0); -} - -static int -aic7770_chip_init(struct ahc_softc *ahc) -{ - ahc_outb(ahc, BUSSPD, ahc->bus_softc.aic7770_softc.busspd); - ahc_outb(ahc, BUSTIME, ahc->bus_softc.aic7770_softc.bustime); - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS); - ahc_outb(ahc, BCTL, ENABLE); - return (ahc_chip_init(ahc)); -} - -/* - * Read the 284x SEEPROM. - */ -static int -aha2840_load_seeprom(struct ahc_softc *ahc) -{ - struct seeprom_descriptor sd; - struct seeprom_config *sc; - int have_seeprom; - uint8_t scsi_conf; - - sd.sd_ahc = ahc; - sd.sd_control_offset = SEECTL_2840; - sd.sd_status_offset = STATUS_2840; - sd.sd_dataout_offset = STATUS_2840; - sd.sd_chip = C46; - sd.sd_MS = 0; - sd.sd_RDY = EEPROM_TF; - sd.sd_CS = CS_2840; - sd.sd_CK = CK_2840; - sd.sd_DO = DO_2840; - sd.sd_DI = DI_2840; - sc = ahc->seep_config; - - if (bootverbose) - printk("%s: Reading SEEPROM...", ahc_name(ahc)); - have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc, - /*start_addr*/0, sizeof(*sc)/2); - - if (have_seeprom) { - - if (ahc_verify_cksum(sc) == 0) { - if(bootverbose) - printk ("checksum error\n"); - have_seeprom = 0; - } else if (bootverbose) { - printk("done.\n"); - } - } - - if (!have_seeprom) { - if (bootverbose) - printk("%s: No SEEPROM available\n", ahc_name(ahc)); - ahc->flags |= AHC_USEDEFAULTS; - } else { - /* - * Put the data we've collected down into SRAM - * where ahc_init will find it. - */ - int i; - int max_targ; - uint16_t discenable; - - max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8; - discenable = 0; - for (i = 0; i < max_targ; i++){ - uint8_t target_settings; - - target_settings = (sc->device_flags[i] & CFXFER) << 4; - if (sc->device_flags[i] & CFSYNCH) - target_settings |= SOFS; - if (sc->device_flags[i] & CFWIDEB) - target_settings |= WIDEXFER; - if (sc->device_flags[i] & CFDISC) - discenable |= (0x01 << i); - ahc_outb(ahc, TARG_SCSIRATE + i, target_settings); - } - ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); - ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); - - ahc->our_id = sc->brtime_id & CFSCSIID; - - scsi_conf = (ahc->our_id & 0x7); - if (sc->adapter_control & CFSPARITY) - scsi_conf |= ENSPCHK; - if (sc->adapter_control & CFRESETB) - scsi_conf |= RESET_SCSI; - - if (sc->bios_control & CF284XEXTEND) - ahc->flags |= AHC_EXTENDED_TRANS_A; - /* Set SCSICONF info */ - ahc_outb(ahc, SCSICONF, scsi_conf); - - if (sc->adapter_control & CF284XSTERM) - ahc->flags |= AHC_TERM_ENB_A; - } - return (have_seeprom); -} - -static int -ahc_aic7770_VL_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7770_setup(ahc); - ahc->chip |= AHC_VL; - return (error); -} - -static int -ahc_aic7770_EISA_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7770_setup(ahc); - ahc->chip |= AHC_EISA; - return (error); -} - -static int -ahc_aic7770_setup(struct ahc_softc *ahc) -{ - ahc->channel = 'A'; - ahc->channel_b = 'B'; - ahc->chip = AHC_AIC7770; - ahc->features = AHC_AIC7770_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG; - ahc->flags |= AHC_PAGESCBS; - ahc->instruction_ram_size = 448; - return (0); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770_osm.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770_osm.c deleted file mode 100644 index 0cb8ef64..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7770_osm.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Linux driver attachment glue for aic7770 based controllers. - * - * Copyright (c) 2000-2003 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#14 $ - */ - -#include "aic7xxx_osm.h" - -#include -#include - -int -aic7770_map_registers(struct ahc_softc *ahc, u_int port) -{ - /* - * Lock out other contenders for our i/o space. - */ - if (!request_region(port, AHC_EISA_IOSIZE, "aic7xxx")) - return (ENOMEM); - ahc->tag = BUS_SPACE_PIO; - ahc->bsh.ioport = port; - return (0); -} - -int -aic7770_map_int(struct ahc_softc *ahc, u_int irq) -{ - int error; - int shared; - - shared = 0; - if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0) - shared = IRQF_SHARED; - - error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc); - if (error == 0) - ahc->platform_data->irq = irq; - - return (-error); -} - -static int -aic7770_probe(struct device *dev) -{ - struct eisa_device *edev = to_eisa_device(dev); - u_int eisaBase = edev->base_addr+AHC_EISA_SLOT_OFFSET; - struct ahc_softc *ahc; - char buf[80]; - char *name; - int error; - - sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); - name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); - if (name == NULL) - return (ENOMEM); - strcpy(name, buf); - ahc = ahc_alloc(&aic7xxx_driver_template, name); - if (ahc == NULL) - return (ENOMEM); - error = aic7770_config(ahc, aic7770_ident_table + edev->id.driver_data, - eisaBase); - if (error != 0) { - ahc->bsh.ioport = 0; - ahc_free(ahc); - return (error); - } - - dev_set_drvdata(dev, ahc); - - error = ahc_linux_register_host(ahc, &aic7xxx_driver_template); - return (error); -} - -static int -aic7770_remove(struct device *dev) -{ - struct ahc_softc *ahc = dev_get_drvdata(dev); - u_long s; - - if (ahc->platform_data && ahc->platform_data->host) - scsi_remove_host(ahc->platform_data->host); - - ahc_lock(ahc, &s); - ahc_intr_enable(ahc, FALSE); - ahc_unlock(ahc, &s); - - ahc_free(ahc); - return 0; -} - -static struct eisa_device_id aic7770_ids[] = { - { "ADP7771", 0 }, /* AHA 274x */ - { "ADP7756", 1 }, /* AHA 284x BIOS enabled */ - { "ADP7757", 2 }, /* AHA 284x BIOS disabled */ - { "ADP7782", 3 }, /* AHA 274x Olivetti OEM */ - { "ADP7783", 4 }, /* AHA 274x Olivetti OEM (Differential) */ - { "ADP7770", 5 }, /* AIC7770 generic */ - { "" } -}; -MODULE_DEVICE_TABLE(eisa, aic7770_ids); - -static struct eisa_driver aic7770_driver = { - .id_table = aic7770_ids, - .driver = { - .name = "aic7xxx", - .probe = aic7770_probe, - .remove = aic7770_remove, - } -}; - -int -ahc_linux_eisa_init(void) -{ - return eisa_driver_register(&aic7770_driver); -} - -void -ahc_linux_eisa_exit(void) -{ - eisa_driver_unregister(&aic7770_driver); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.h deleted file mode 100644 index 9b059422..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.h +++ /dev/null @@ -1,1478 +0,0 @@ -/* - * Core definitions and data structures shareable across OS platforms. - * - * Copyright (c) 1994-2002 Justin T. Gibbs. - * Copyright (c) 2000-2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#109 $ - * - * $FreeBSD$ - */ - -#ifndef _AIC79XX_H_ -#define _AIC79XX_H_ - -/* Register Definitions */ -#include "aic79xx_reg.h" - -/************************* Forward Declarations *******************************/ -struct ahd_platform_data; -struct scb_platform_data; - -/****************************** Useful Macros *********************************/ -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define ALL_CHANNELS '\0' -#define ALL_TARGETS_MASK 0xFFFF -#define INITIATOR_WILDCARD (~0) -#define SCB_LIST_NULL 0xFF00 -#define SCB_LIST_NULL_LE (ahd_htole16(SCB_LIST_NULL)) -#define QOUTFIFO_ENTRY_VALID 0x80 -#define SCBID_IS_NULL(scbid) (((scbid) & 0xFF00 ) == SCB_LIST_NULL) - -#define SCSIID_TARGET(ahd, scsiid) \ - (((scsiid) & TID) >> TID_SHIFT) -#define SCSIID_OUR_ID(scsiid) \ - ((scsiid) & OID) -#define SCSIID_CHANNEL(ahd, scsiid) ('A') -#define SCB_IS_SCSIBUS_B(ahd, scb) (0) -#define SCB_GET_OUR_ID(scb) \ - SCSIID_OUR_ID((scb)->hscb->scsiid) -#define SCB_GET_TARGET(ahd, scb) \ - SCSIID_TARGET((ahd), (scb)->hscb->scsiid) -#define SCB_GET_CHANNEL(ahd, scb) \ - SCSIID_CHANNEL(ahd, (scb)->hscb->scsiid) -#define SCB_GET_LUN(scb) \ - ((scb)->hscb->lun) -#define SCB_GET_TARGET_OFFSET(ahd, scb) \ - SCB_GET_TARGET(ahd, scb) -#define SCB_GET_TARGET_MASK(ahd, scb) \ - (0x01 << (SCB_GET_TARGET_OFFSET(ahd, scb))) -#ifdef AHD_DEBUG -#define SCB_IS_SILENT(scb) \ - ((ahd_debug & AHD_SHOW_MASKED_ERRORS) == 0 \ - && (((scb)->flags & SCB_SILENT) != 0)) -#else -#define SCB_IS_SILENT(scb) \ - (((scb)->flags & SCB_SILENT) != 0) -#endif -/* - * TCLs have the following format: TTTTLLLLLLLL - */ -#define TCL_TARGET_OFFSET(tcl) \ - ((((tcl) >> 4) & TID) >> 4) -#define TCL_LUN(tcl) \ - (tcl & (AHD_NUM_LUNS - 1)) -#define BUILD_TCL(scsiid, lun) \ - ((lun) | (((scsiid) & TID) << 4)) -#define BUILD_TCL_RAW(target, channel, lun) \ - ((lun) | ((target) << 8)) - -#define SCB_GET_TAG(scb) \ - ahd_le16toh(scb->hscb->tag) - -#ifndef AHD_TARGET_MODE -#undef AHD_TMODE_ENABLE -#define AHD_TMODE_ENABLE 0 -#endif - -#define AHD_BUILD_COL_IDX(target, lun) \ - (((lun) << 4) | target) - -#define AHD_GET_SCB_COL_IDX(ahd, scb) \ - ((SCB_GET_LUN(scb) << 4) | SCB_GET_TARGET(ahd, scb)) - -#define AHD_SET_SCB_COL_IDX(scb, col_idx) \ -do { \ - (scb)->hscb->scsiid = ((col_idx) << TID_SHIFT) & TID; \ - (scb)->hscb->lun = ((col_idx) >> 4) & (AHD_NUM_LUNS_NONPKT-1); \ -} while (0) - -#define AHD_COPY_SCB_COL_IDX(dst, src) \ -do { \ - dst->hscb->scsiid = src->hscb->scsiid; \ - dst->hscb->lun = src->hscb->lun; \ -} while (0) - -#define AHD_NEVER_COL_IDX 0xFFFF - -/**************************** Driver Constants ********************************/ -/* - * The maximum number of supported targets. - */ -#define AHD_NUM_TARGETS 16 - -/* - * The maximum number of supported luns. - * The identify message only supports 64 luns in non-packetized transfers. - * You can have 2^64 luns when information unit transfers are enabled, - * but until we see a need to support that many, we support 256. - */ -#define AHD_NUM_LUNS_NONPKT 64 -#define AHD_NUM_LUNS 256 - -/* - * The maximum transfer per S/G segment. - */ -#define AHD_MAXTRANSFER_SIZE 0x00ffffff /* limited by 24bit counter */ - -/* - * The maximum amount of SCB storage in hardware on a controller. - * This value represents an upper bound. Due to software design, - * we may not be able to use this number. - */ -#define AHD_SCB_MAX 512 - -/* - * The maximum number of concurrent transactions supported per driver instance. - * Sequencer Control Blocks (SCBs) store per-transaction information. - */ -#define AHD_MAX_QUEUE AHD_SCB_MAX - -/* - * Define the size of our QIN and QOUT FIFOs. They must be a power of 2 - * in size and accommodate as many transactions as can be queued concurrently. - */ -#define AHD_QIN_SIZE AHD_MAX_QUEUE -#define AHD_QOUT_SIZE AHD_MAX_QUEUE - -#define AHD_QIN_WRAP(x) ((x) & (AHD_QIN_SIZE-1)) -/* - * The maximum amount of SCB storage we allocate in host memory. - */ -#define AHD_SCB_MAX_ALLOC AHD_MAX_QUEUE - -/* - * Ring Buffer of incoming target commands. - * We allocate 256 to simplify the logic in the sequencer - * by using the natural wrap point of an 8bit counter. - */ -#define AHD_TMODE_CMDS 256 - -/* Reset line assertion time in us */ -#define AHD_BUSRESET_DELAY 25 - -/******************* Chip Characteristics/Operating Settings *****************/ -/* - * Chip Type - * The chip order is from least sophisticated to most sophisticated. - */ -typedef enum { - AHD_NONE = 0x0000, - AHD_CHIPID_MASK = 0x00FF, - AHD_AIC7901 = 0x0001, - AHD_AIC7902 = 0x0002, - AHD_AIC7901A = 0x0003, - AHD_PCI = 0x0100, /* Bus type PCI */ - AHD_PCIX = 0x0200, /* Bus type PCIX */ - AHD_BUS_MASK = 0x0F00 -} ahd_chip; - -/* - * Features available in each chip type. - */ -typedef enum { - AHD_FENONE = 0x00000, - AHD_WIDE = 0x00001,/* Wide Channel */ - AHD_AIC79XXB_SLOWCRC = 0x00002,/* SLOWCRC bit should be set */ - AHD_MULTI_FUNC = 0x00100,/* Multi-Function/Channel Device */ - AHD_TARGETMODE = 0x01000,/* Has tested target mode support */ - AHD_MULTIROLE = 0x02000,/* Space for two roles at a time */ - AHD_RTI = 0x04000,/* Retained Training Support */ - AHD_NEW_IOCELL_OPTS = 0x08000,/* More Signal knobs in the IOCELL */ - AHD_NEW_DFCNTRL_OPTS = 0x10000,/* SCSIENWRDIS bit */ - AHD_FAST_CDB_DELIVERY = 0x20000,/* CDB acks released to Output Sync */ - AHD_REMOVABLE = 0x00000,/* Hot-Swap supported - None so far*/ - AHD_AIC7901_FE = AHD_FENONE, - AHD_AIC7901A_FE = AHD_FENONE, - AHD_AIC7902_FE = AHD_MULTI_FUNC -} ahd_feature; - -/* - * Bugs in the silicon that we work around in software. - */ -typedef enum { - AHD_BUGNONE = 0x0000, - /* - * Rev A hardware fails to update LAST/CURR/NEXTSCB - * correctly in certain packetized selection cases. - */ - AHD_SENT_SCB_UPDATE_BUG = 0x0001, - /* The wrong SCB is accessed to check the abort pending bit. */ - AHD_ABORT_LQI_BUG = 0x0002, - /* Packetized bitbucket crosses packet boundaries. */ - AHD_PKT_BITBUCKET_BUG = 0x0004, - /* The selection timer runs twice as long as its setting. */ - AHD_LONG_SETIMO_BUG = 0x0008, - /* The Non-LQ CRC error status is delayed until phase change. */ - AHD_NLQICRC_DELAYED_BUG = 0x0010, - /* The chip must be reset for all outgoing bus resets. */ - AHD_SCSIRST_BUG = 0x0020, - /* Some PCIX fields must be saved and restored across chip reset. */ - AHD_PCIX_CHIPRST_BUG = 0x0040, - /* MMAPIO is not functional in PCI-X mode. */ - AHD_PCIX_MMAPIO_BUG = 0x0080, - /* Reads to SCBRAM fail to reset the discard timer. */ - AHD_PCIX_SCBRAM_RD_BUG = 0x0100, - /* Bug workarounds that can be disabled on non-PCIX busses. */ - AHD_PCIX_BUG_MASK = AHD_PCIX_CHIPRST_BUG - | AHD_PCIX_MMAPIO_BUG - | AHD_PCIX_SCBRAM_RD_BUG, - /* - * LQOSTOP0 status set even for forced selections with ATN - * to perform non-packetized message delivery. - */ - AHD_LQO_ATNO_BUG = 0x0200, - /* FIFO auto-flush does not always trigger. */ - AHD_AUTOFLUSH_BUG = 0x0400, - /* The CLRLQO registers are not self-clearing. */ - AHD_CLRLQO_AUTOCLR_BUG = 0x0800, - /* The PACKETIZED status bit refers to the previous connection. */ - AHD_PKTIZED_STATUS_BUG = 0x1000, - /* "Short Luns" are not placed into outgoing LQ packets correctly. */ - AHD_PKT_LUN_BUG = 0x2000, - /* - * Only the FIFO allocated to the non-packetized connection may - * be in use during a non-packetzied connection. - */ - AHD_NONPACKFIFO_BUG = 0x4000, - /* - * Writing to a DFF SCBPTR register may fail if concurent with - * a hardware write to the other DFF SCBPTR register. This is - * not currently a concern in our sequencer since all chips with - * this bug have the AHD_NONPACKFIFO_BUG and all writes of concern - * occur in non-packetized connections. - */ - AHD_MDFF_WSCBPTR_BUG = 0x8000, - /* SGHADDR updates are slow. */ - AHD_REG_SLOW_SETTLE_BUG = 0x10000, - /* - * Changing the MODE_PTR coincident with an interrupt that - * switches to a different mode will cause the interrupt to - * be in the mode written outside of interrupt context. - */ - AHD_SET_MODE_BUG = 0x20000, - /* Non-packetized busfree revision does not work. */ - AHD_BUSFREEREV_BUG = 0x40000, - /* - * Paced transfers are indicated with a non-standard PPR - * option bit in the neg table, 160MHz is indicated by - * sync factor 0x7, and the offset if off by a factor of 2. - */ - AHD_PACED_NEGTABLE_BUG = 0x80000, - /* LQOOVERRUN false positives. */ - AHD_LQOOVERRUN_BUG = 0x100000, - /* - * Controller write to INTSTAT will lose to a host - * write to CLRINT. - */ - AHD_INTCOLLISION_BUG = 0x200000, - /* - * The GEM318 violates the SCSI spec by not waiting - * the mandated bus settle delay between phase changes - * in some situations. Some aic79xx chip revs. are more - * strict in this regard and will treat REQ assertions - * that fall within the bus settle delay window as - * glitches. This flag tells the firmware to tolerate - * early REQ assertions. - */ - AHD_EARLY_REQ_BUG = 0x400000, - /* - * The LED does not stay on long enough in packetized modes. - */ - AHD_FAINT_LED_BUG = 0x800000 -} ahd_bug; - -/* - * Configuration specific settings. - * The driver determines these settings by probing the - * chip/controller's configuration. - */ -typedef enum { - AHD_FNONE = 0x00000, - AHD_BOOT_CHANNEL = 0x00001,/* We were set as the boot channel. */ - AHD_USEDEFAULTS = 0x00004,/* - * For cards without an seeprom - * or a BIOS to initialize the chip's - * SRAM, we use the default target - * settings. - */ - AHD_SEQUENCER_DEBUG = 0x00008, - AHD_RESET_BUS_A = 0x00010, - AHD_EXTENDED_TRANS_A = 0x00020, - AHD_TERM_ENB_A = 0x00040, - AHD_SPCHK_ENB_A = 0x00080, - AHD_STPWLEVEL_A = 0x00100, - AHD_INITIATORROLE = 0x00200,/* - * Allow initiator operations on - * this controller. - */ - AHD_TARGETROLE = 0x00400,/* - * Allow target operations on this - * controller. - */ - AHD_RESOURCE_SHORTAGE = 0x00800, - AHD_TQINFIFO_BLOCKED = 0x01000,/* Blocked waiting for ATIOs */ - AHD_INT50_SPEEDFLEX = 0x02000,/* - * Internal 50pin connector - * sits behind an aic3860 - */ - AHD_BIOS_ENABLED = 0x04000, - AHD_ALL_INTERRUPTS = 0x08000, - AHD_39BIT_ADDRESSING = 0x10000,/* Use 39 bit addressing scheme. */ - AHD_64BIT_ADDRESSING = 0x20000,/* Use 64 bit addressing scheme. */ - AHD_CURRENT_SENSING = 0x40000, - AHD_SCB_CONFIG_USED = 0x80000,/* No SEEPROM but SCB had info. */ - AHD_HP_BOARD = 0x100000, - AHD_BUS_RESET_ACTIVE = 0x200000, - AHD_UPDATE_PEND_CMDS = 0x400000, - AHD_RUNNING_QOUTFIFO = 0x800000, - AHD_HAD_FIRST_SEL = 0x1000000 -} ahd_flag; - -/************************* Hardware SCB Definition ***************************/ - -/* - * The driver keeps up to MAX_SCB scb structures per card in memory. The SCB - * consists of a "hardware SCB" mirroring the fields available on the card - * and additional information the kernel stores for each transaction. - * - * To minimize space utilization, a portion of the hardware scb stores - * different data during different portions of a SCSI transaction. - * As initialized by the host driver for the initiator role, this area - * contains the SCSI cdb (or a pointer to the cdb) to be executed. After - * the cdb has been presented to the target, this area serves to store - * residual transfer information and the SCSI status byte. - * For the target role, the contents of this area do not change, but - * still serve a different purpose than for the initiator role. See - * struct target_data for details. - */ - -/* - * Status information embedded in the shared poriton of - * an SCB after passing the cdb to the target. The kernel - * driver will only read this data for transactions that - * complete abnormally. - */ -struct initiator_status { - uint32_t residual_datacnt; /* Residual in the current S/G seg */ - uint32_t residual_sgptr; /* The next S/G for this transfer */ - uint8_t scsi_status; /* Standard SCSI status byte */ -}; - -struct target_status { - uint32_t residual_datacnt; /* Residual in the current S/G seg */ - uint32_t residual_sgptr; /* The next S/G for this transfer */ - uint8_t scsi_status; /* SCSI status to give to initiator */ - uint8_t target_phases; /* Bitmap of phases to execute */ - uint8_t data_phase; /* Data-In or Data-Out */ - uint8_t initiator_tag; /* Initiator's transaction tag */ -}; - -/* - * Initiator mode SCB shared data area. - * If the embedded CDB is 12 bytes or less, we embed - * the sense buffer address in the SCB. This allows - * us to retrieve sense information without interrupting - * the host in packetized mode. - */ -typedef uint32_t sense_addr_t; -#define MAX_CDB_LEN 16 -#define MAX_CDB_LEN_WITH_SENSE_ADDR (MAX_CDB_LEN - sizeof(sense_addr_t)) -union initiator_data { - struct { - uint64_t cdbptr; - uint8_t cdblen; - } cdb_from_host; - uint8_t cdb[MAX_CDB_LEN]; - struct { - uint8_t cdb[MAX_CDB_LEN_WITH_SENSE_ADDR]; - sense_addr_t sense_addr; - } cdb_plus_saddr; -}; - -/* - * Target mode version of the shared data SCB segment. - */ -struct target_data { - uint32_t spare[2]; - uint8_t scsi_status; /* SCSI status to give to initiator */ - uint8_t target_phases; /* Bitmap of phases to execute */ - uint8_t data_phase; /* Data-In or Data-Out */ - uint8_t initiator_tag; /* Initiator's transaction tag */ -}; - -struct hardware_scb { -/*0*/ union { - union initiator_data idata; - struct target_data tdata; - struct initiator_status istatus; - struct target_status tstatus; - } shared_data; -/* - * A word about residuals. - * The scb is presented to the sequencer with the dataptr and datacnt - * fields initialized to the contents of the first S/G element to - * transfer. The sgptr field is initialized to the bus address for - * the S/G element that follows the first in the in core S/G array - * or'ed with the SG_FULL_RESID flag. Sgptr may point to an invalid - * S/G entry for this transfer (single S/G element transfer with the - * first elements address and length preloaded in the dataptr/datacnt - * fields). If no transfer is to occur, sgptr is set to SG_LIST_NULL. - * The SG_FULL_RESID flag ensures that the residual will be correctly - * noted even if no data transfers occur. Once the data phase is entered, - * the residual sgptr and datacnt are loaded from the sgptr and the - * datacnt fields. After each S/G element's dataptr and length are - * loaded into the hardware, the residual sgptr is advanced. After - * each S/G element is expired, its datacnt field is checked to see - * if the LAST_SEG flag is set. If so, SG_LIST_NULL is set in the - * residual sg ptr and the transfer is considered complete. If the - * sequencer determines that there is a residual in the tranfer, or - * there is non-zero status, it will set the SG_STATUS_VALID flag in - * sgptr and dma the scb back into host memory. To sumarize: - * - * Sequencer: - * o A residual has occurred if SG_FULL_RESID is set in sgptr, - * or residual_sgptr does not have SG_LIST_NULL set. - * - * o We are transferring the last segment if residual_datacnt has - * the SG_LAST_SEG flag set. - * - * Host: - * o A residual can only have occurred if a completed scb has the - * SG_STATUS_VALID flag set. Inspection of the SCSI status field, - * the residual_datacnt, and the residual_sgptr field will tell - * for sure. - * - * o residual_sgptr and sgptr refer to the "next" sg entry - * and so may point beyond the last valid sg entry for the - * transfer. - */ -#define SG_PTR_MASK 0xFFFFFFF8 -/*16*/ uint16_t tag; /* Reused by Sequencer. */ -/*18*/ uint8_t control; /* See SCB_CONTROL in aic79xx.reg for details */ -/*19*/ uint8_t scsiid; /* - * Selection out Id - * Our Id (bits 0-3) Their ID (bits 4-7) - */ -/*20*/ uint8_t lun; -/*21*/ uint8_t task_attribute; -/*22*/ uint8_t cdb_len; -/*23*/ uint8_t task_management; -/*24*/ uint64_t dataptr; -/*32*/ uint32_t datacnt; /* Byte 3 is spare. */ -/*36*/ uint32_t sgptr; -/*40*/ uint32_t hscb_busaddr; -/*44*/ uint32_t next_hscb_busaddr; -/********** Long lun field only downloaded for full 8 byte lun support ********/ -/*48*/ uint8_t pkt_long_lun[8]; -/******* Fields below are not Downloaded (Sequencer may use for scratch) ******/ -/*56*/ uint8_t spare[8]; -}; - -/************************ Kernel SCB Definitions ******************************/ -/* - * Some fields of the SCB are OS dependent. Here we collect the - * definitions for elements that all OS platforms need to include - * in there SCB definition. - */ - -/* - * Definition of a scatter/gather element as transferred to the controller. - * The aic7xxx chips only support a 24bit length. We use the top byte of - * the length to store additional address bits and a flag to indicate - * that a given segment terminates the transfer. This gives us an - * addressable range of 512GB on machines with 64bit PCI or with chips - * that can support dual address cycles on 32bit PCI busses. - */ -struct ahd_dma_seg { - uint32_t addr; - uint32_t len; -#define AHD_DMA_LAST_SEG 0x80000000 -#define AHD_SG_HIGH_ADDR_MASK 0x7F000000 -#define AHD_SG_LEN_MASK 0x00FFFFFF -}; - -struct ahd_dma64_seg { - uint64_t addr; - uint32_t len; - uint32_t pad; -}; - -struct map_node { - bus_dmamap_t dmamap; - dma_addr_t physaddr; - uint8_t *vaddr; - SLIST_ENTRY(map_node) links; -}; - -/* - * The current state of this SCB. - */ -typedef enum { - SCB_FLAG_NONE = 0x00000, - SCB_TRANSMISSION_ERROR = 0x00001,/* - * We detected a parity or CRC - * error that has effected the - * payload of the command. This - * flag is checked when normal - * status is returned to catch - * the case of a target not - * responding to our attempt - * to report the error. - */ - SCB_OTHERTCL_TIMEOUT = 0x00002,/* - * Another device was active - * during the first timeout for - * this SCB so we gave ourselves - * an additional timeout period - * in case it was hogging the - * bus. - */ - SCB_DEVICE_RESET = 0x00004, - SCB_SENSE = 0x00008, - SCB_CDB32_PTR = 0x00010, - SCB_RECOVERY_SCB = 0x00020, - SCB_AUTO_NEGOTIATE = 0x00040,/* Negotiate to achieve goal. */ - SCB_NEGOTIATE = 0x00080,/* Negotiation forced for command. */ - SCB_ABORT = 0x00100, - SCB_ACTIVE = 0x00200, - SCB_TARGET_IMMEDIATE = 0x00400, - SCB_PACKETIZED = 0x00800, - SCB_EXPECT_PPR_BUSFREE = 0x01000, - SCB_PKT_SENSE = 0x02000, - SCB_EXTERNAL_RESET = 0x04000,/* Device was reset externally */ - SCB_ON_COL_LIST = 0x08000, - SCB_SILENT = 0x10000 /* - * Be quiet about transmission type - * errors. They are expected and we - * don't want to upset the user. This - * flag is typically used during DV. - */ -} scb_flag; - -struct scb { - struct hardware_scb *hscb; - union { - SLIST_ENTRY(scb) sle; - LIST_ENTRY(scb) le; - TAILQ_ENTRY(scb) tqe; - } links; - union { - SLIST_ENTRY(scb) sle; - LIST_ENTRY(scb) le; - TAILQ_ENTRY(scb) tqe; - } links2; -#define pending_links links2.le -#define collision_links links2.le - struct scb *col_scb; - ahd_io_ctx_t io_ctx; - struct ahd_softc *ahd_softc; - scb_flag flags; -#ifndef __linux__ - bus_dmamap_t dmamap; -#endif - struct scb_platform_data *platform_data; - struct map_node *hscb_map; - struct map_node *sg_map; - struct map_node *sense_map; - void *sg_list; - uint8_t *sense_data; - dma_addr_t sg_list_busaddr; - dma_addr_t sense_busaddr; - u_int sg_count;/* How full ahd_dma_seg is */ -#define AHD_MAX_LQ_CRC_ERRORS 5 - u_int crc_retry_count; -}; - -TAILQ_HEAD(scb_tailq, scb); -LIST_HEAD(scb_list, scb); - -struct scb_data { - /* - * TAILQ of lists of free SCBs grouped by device - * collision domains. - */ - struct scb_tailq free_scbs; - - /* - * Per-device lists of SCBs whose tag ID would collide - * with an already active tag on the device. - */ - struct scb_list free_scb_lists[AHD_NUM_TARGETS * AHD_NUM_LUNS_NONPKT]; - - /* - * SCBs that will not collide with any active device. - */ - struct scb_list any_dev_free_scb_list; - - /* - * Mapping from tag to SCB. - */ - struct scb *scbindex[AHD_SCB_MAX]; - - /* - * "Bus" addresses of our data structures. - */ - bus_dma_tag_t hscb_dmat; /* dmat for our hardware SCB array */ - bus_dma_tag_t sg_dmat; /* dmat for our sg segments */ - bus_dma_tag_t sense_dmat; /* dmat for our sense buffers */ - SLIST_HEAD(, map_node) hscb_maps; - SLIST_HEAD(, map_node) sg_maps; - SLIST_HEAD(, map_node) sense_maps; - int scbs_left; /* unallocated scbs in head map_node */ - int sgs_left; /* unallocated sgs in head map_node */ - int sense_left; /* unallocated sense in head map_node */ - uint16_t numscbs; - uint16_t maxhscbs; /* Number of SCBs on the card */ - uint8_t init_level; /* - * How far we've initialized - * this structure. - */ -}; - -/************************ Target Mode Definitions *****************************/ - -/* - * Connection descriptor for select-in requests in target mode. - */ -struct target_cmd { - uint8_t scsiid; /* Our ID and the initiator's ID */ - uint8_t identify; /* Identify message */ - uint8_t bytes[22]; /* - * Bytes contains any additional message - * bytes terminated by 0xFF. The remainder - * is the cdb to execute. - */ - uint8_t cmd_valid; /* - * When a command is complete, the firmware - * will set cmd_valid to all bits set. - * After the host has seen the command, - * the bits are cleared. This allows us - * to just peek at host memory to determine - * if more work is complete. cmd_valid is on - * an 8 byte boundary to simplify setting - * it on aic7880 hardware which only has - * limited direct access to the DMA FIFO. - */ - uint8_t pad[7]; -}; - -/* - * Number of events we can buffer up if we run out - * of immediate notify ccbs. - */ -#define AHD_TMODE_EVENT_BUFFER_SIZE 8 -struct ahd_tmode_event { - uint8_t initiator_id; - uint8_t event_type; /* MSG type or EVENT_TYPE_BUS_RESET */ -#define EVENT_TYPE_BUS_RESET 0xFF - uint8_t event_arg; -}; - -/* - * Per enabled lun target mode state. - * As this state is directly influenced by the host OS'es target mode - * environment, we let the OS module define it. Forward declare the - * structure here so we can store arrays of them, etc. in OS neutral - * data structures. - */ -#ifdef AHD_TARGET_MODE -struct ahd_tmode_lstate { - struct cam_path *path; - struct ccb_hdr_slist accept_tios; - struct ccb_hdr_slist immed_notifies; - struct ahd_tmode_event event_buffer[AHD_TMODE_EVENT_BUFFER_SIZE]; - uint8_t event_r_idx; - uint8_t event_w_idx; -}; -#else -struct ahd_tmode_lstate; -#endif - -/******************** Transfer Negotiation Datastructures *********************/ -#define AHD_TRANS_CUR 0x01 /* Modify current neogtiation status */ -#define AHD_TRANS_ACTIVE 0x03 /* Assume this target is on the bus */ -#define AHD_TRANS_GOAL 0x04 /* Modify negotiation goal */ -#define AHD_TRANS_USER 0x08 /* Modify user negotiation settings */ -#define AHD_PERIOD_10MHz 0x19 - -#define AHD_WIDTH_UNKNOWN 0xFF -#define AHD_PERIOD_UNKNOWN 0xFF -#define AHD_OFFSET_UNKNOWN 0xFF -#define AHD_PPR_OPTS_UNKNOWN 0xFF - -/* - * Transfer Negotiation Information. - */ -struct ahd_transinfo { - uint8_t protocol_version; /* SCSI Revision level */ - uint8_t transport_version; /* SPI Revision level */ - uint8_t width; /* Bus width */ - uint8_t period; /* Sync rate factor */ - uint8_t offset; /* Sync offset */ - uint8_t ppr_options; /* Parallel Protocol Request options */ -}; - -/* - * Per-initiator current, goal and user transfer negotiation information. */ -struct ahd_initiator_tinfo { - struct ahd_transinfo curr; - struct ahd_transinfo goal; - struct ahd_transinfo user; -}; - -/* - * Per enabled target ID state. - * Pointers to lun target state as well as sync/wide negotiation information - * for each initiator<->target mapping. For the initiator role we pretend - * that we are the target and the targets are the initiators since the - * negotiation is the same regardless of role. - */ -struct ahd_tmode_tstate { - struct ahd_tmode_lstate* enabled_luns[AHD_NUM_LUNS]; - struct ahd_initiator_tinfo transinfo[AHD_NUM_TARGETS]; - - /* - * Per initiator state bitmasks. - */ - uint16_t auto_negotiate;/* Auto Negotiation Required */ - uint16_t discenable; /* Disconnection allowed */ - uint16_t tagenable; /* Tagged Queuing allowed */ -}; - -/* - * Points of interest along the negotiated transfer scale. - */ -#define AHD_SYNCRATE_160 0x8 -#define AHD_SYNCRATE_PACED 0x8 -#define AHD_SYNCRATE_DT 0x9 -#define AHD_SYNCRATE_ULTRA2 0xa -#define AHD_SYNCRATE_ULTRA 0xc -#define AHD_SYNCRATE_FAST 0x19 -#define AHD_SYNCRATE_MIN_DT AHD_SYNCRATE_FAST -#define AHD_SYNCRATE_SYNC 0x32 -#define AHD_SYNCRATE_MIN 0x60 -#define AHD_SYNCRATE_ASYNC 0xFF -#define AHD_SYNCRATE_MAX AHD_SYNCRATE_160 - -/* Safe and valid period for async negotiations. */ -#define AHD_ASYNC_XFER_PERIOD 0x44 - -/* - * In RevA, the synctable uses a 120MHz rate for the period - * factor 8 and 160MHz for the period factor 7. The 120MHz - * rate never made it into the official SCSI spec, so we must - * compensate when setting the negotiation table for Rev A - * parts. - */ -#define AHD_SYNCRATE_REVA_120 0x8 -#define AHD_SYNCRATE_REVA_160 0x7 - -/***************************** Lookup Tables **********************************/ -/* - * Phase -> name and message out response - * to parity errors in each phase table. - */ -struct ahd_phase_table_entry { - uint8_t phase; - uint8_t mesg_out; /* Message response to parity errors */ - const char *phasemsg; -}; - -/************************** Serial EEPROM Format ******************************/ - -struct seeprom_config { -/* - * Per SCSI ID Configuration Flags - */ - uint16_t device_flags[16]; /* words 0-15 */ -#define CFXFER 0x003F /* synchronous transfer rate */ -#define CFXFER_ASYNC 0x3F -#define CFQAS 0x0040 /* Negotiate QAS */ -#define CFPACKETIZED 0x0080 /* Negotiate Packetized Transfers */ -#define CFSTART 0x0100 /* send start unit SCSI command */ -#define CFINCBIOS 0x0200 /* include in BIOS scan */ -#define CFDISC 0x0400 /* enable disconnection */ -#define CFMULTILUNDEV 0x0800 /* Probe multiple luns in BIOS scan */ -#define CFWIDEB 0x1000 /* wide bus device */ -#define CFHOSTMANAGED 0x8000 /* Managed by a RAID controller */ - -/* - * BIOS Control Bits - */ - uint16_t bios_control; /* word 16 */ -#define CFSUPREM 0x0001 /* support all removeable drives */ -#define CFSUPREMB 0x0002 /* support removeable boot drives */ -#define CFBIOSSTATE 0x000C /* BIOS Action State */ -#define CFBS_DISABLED 0x00 -#define CFBS_ENABLED 0x04 -#define CFBS_DISABLED_SCAN 0x08 -#define CFENABLEDV 0x0010 /* Perform Domain Validation */ -#define CFCTRL_A 0x0020 /* BIOS displays Ctrl-A message */ -#define CFSPARITY 0x0040 /* SCSI parity */ -#define CFEXTEND 0x0080 /* extended translation enabled */ -#define CFBOOTCD 0x0100 /* Support Bootable CD-ROM */ -#define CFMSG_LEVEL 0x0600 /* BIOS Message Level */ -#define CFMSG_VERBOSE 0x0000 -#define CFMSG_SILENT 0x0200 -#define CFMSG_DIAG 0x0400 -#define CFRESETB 0x0800 /* reset SCSI bus at boot */ -/* UNUSED 0xf000 */ - -/* - * Host Adapter Control Bits - */ - uint16_t adapter_control; /* word 17 */ -#define CFAUTOTERM 0x0001 /* Perform Auto termination */ -#define CFSTERM 0x0002 /* SCSI low byte termination */ -#define CFWSTERM 0x0004 /* SCSI high byte termination */ -#define CFSEAUTOTERM 0x0008 /* Ultra2 Perform secondary Auto Term*/ -#define CFSELOWTERM 0x0010 /* Ultra2 secondary low term */ -#define CFSEHIGHTERM 0x0020 /* Ultra2 secondary high term */ -#define CFSTPWLEVEL 0x0040 /* Termination level control */ -#define CFBIOSAUTOTERM 0x0080 /* Perform Auto termination */ -#define CFTERM_MENU 0x0100 /* BIOS displays termination menu */ -#define CFCLUSTERENB 0x8000 /* Cluster Enable */ - -/* - * Bus Release Time, Host Adapter ID - */ - uint16_t brtime_id; /* word 18 */ -#define CFSCSIID 0x000f /* host adapter SCSI ID */ -/* UNUSED 0x00f0 */ -#define CFBRTIME 0xff00 /* bus release time/PCI Latency Time */ - -/* - * Maximum targets - */ - uint16_t max_targets; /* word 19 */ -#define CFMAXTARG 0x00ff /* maximum targets */ -#define CFBOOTLUN 0x0f00 /* Lun to boot from */ -#define CFBOOTID 0xf000 /* Target to boot from */ - uint16_t res_1[10]; /* words 20-29 */ - uint16_t signature; /* BIOS Signature */ -#define CFSIGNATURE 0x400 - uint16_t checksum; /* word 31 */ -}; - -/* - * Vital Product Data used during POST and by the BIOS. - */ -struct vpd_config { - uint8_t bios_flags; -#define VPDMASTERBIOS 0x0001 -#define VPDBOOTHOST 0x0002 - uint8_t reserved_1[21]; - uint8_t resource_type; - uint8_t resource_len[2]; - uint8_t resource_data[8]; - uint8_t vpd_tag; - uint16_t vpd_len; - uint8_t vpd_keyword[2]; - uint8_t length; - uint8_t revision; - uint8_t device_flags; - uint8_t termnation_menus[2]; - uint8_t fifo_threshold; - uint8_t end_tag; - uint8_t vpd_checksum; - uint16_t default_target_flags; - uint16_t default_bios_flags; - uint16_t default_ctrl_flags; - uint8_t default_irq; - uint8_t pci_lattime; - uint8_t max_target; - uint8_t boot_lun; - uint16_t signature; - uint8_t reserved_2; - uint8_t checksum; - uint8_t reserved_3[4]; -}; - -/****************************** Flexport Logic ********************************/ -#define FLXADDR_TERMCTL 0x0 -#define FLX_TERMCTL_ENSECHIGH 0x8 -#define FLX_TERMCTL_ENSECLOW 0x4 -#define FLX_TERMCTL_ENPRIHIGH 0x2 -#define FLX_TERMCTL_ENPRILOW 0x1 -#define FLXADDR_ROMSTAT_CURSENSECTL 0x1 -#define FLX_ROMSTAT_SEECFG 0xF0 -#define FLX_ROMSTAT_EECFG 0x0F -#define FLX_ROMSTAT_SEE_93C66 0x00 -#define FLX_ROMSTAT_SEE_NONE 0xF0 -#define FLX_ROMSTAT_EE_512x8 0x0 -#define FLX_ROMSTAT_EE_1MBx8 0x1 -#define FLX_ROMSTAT_EE_2MBx8 0x2 -#define FLX_ROMSTAT_EE_4MBx8 0x3 -#define FLX_ROMSTAT_EE_16MBx8 0x4 -#define CURSENSE_ENB 0x1 -#define FLXADDR_FLEXSTAT 0x2 -#define FLX_FSTAT_BUSY 0x1 -#define FLXADDR_CURRENT_STAT 0x4 -#define FLX_CSTAT_SEC_HIGH 0xC0 -#define FLX_CSTAT_SEC_LOW 0x30 -#define FLX_CSTAT_PRI_HIGH 0x0C -#define FLX_CSTAT_PRI_LOW 0x03 -#define FLX_CSTAT_MASK 0x03 -#define FLX_CSTAT_SHIFT 2 -#define FLX_CSTAT_OKAY 0x0 -#define FLX_CSTAT_OVER 0x1 -#define FLX_CSTAT_UNDER 0x2 -#define FLX_CSTAT_INVALID 0x3 - -int ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf, - u_int start_addr, u_int count, int bstream); - -int ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf, - u_int start_addr, u_int count); -int ahd_verify_cksum(struct seeprom_config *sc); -int ahd_acquire_seeprom(struct ahd_softc *ahd); -void ahd_release_seeprom(struct ahd_softc *ahd); - -/**************************** Message Buffer *********************************/ -typedef enum { - MSG_FLAG_NONE = 0x00, - MSG_FLAG_EXPECT_PPR_BUSFREE = 0x01, - MSG_FLAG_IU_REQ_CHANGED = 0x02, - MSG_FLAG_EXPECT_IDE_BUSFREE = 0x04, - MSG_FLAG_EXPECT_QASREJ_BUSFREE = 0x08, - MSG_FLAG_PACKETIZED = 0x10 -} ahd_msg_flags; - -typedef enum { - MSG_TYPE_NONE = 0x00, - MSG_TYPE_INITIATOR_MSGOUT = 0x01, - MSG_TYPE_INITIATOR_MSGIN = 0x02, - MSG_TYPE_TARGET_MSGOUT = 0x03, - MSG_TYPE_TARGET_MSGIN = 0x04 -} ahd_msg_type; - -typedef enum { - MSGLOOP_IN_PROG, - MSGLOOP_MSGCOMPLETE, - MSGLOOP_TERMINATED -} msg_loop_stat; - -/*********************** Software Configuration Structure *********************/ -struct ahd_suspend_channel_state { - uint8_t scsiseq; - uint8_t sxfrctl0; - uint8_t sxfrctl1; - uint8_t simode0; - uint8_t simode1; - uint8_t seltimer; - uint8_t seqctl; -}; - -struct ahd_suspend_pci_state { - uint32_t devconfig; - uint8_t command; - uint8_t csize_lattime; -}; - -struct ahd_suspend_state { - struct ahd_suspend_channel_state channel[2]; - struct ahd_suspend_pci_state pci_state; - uint8_t optionmode; - uint8_t dscommand0; - uint8_t dspcistatus; - /* hsmailbox */ - uint8_t crccontrol1; - uint8_t scbbaddr; - /* Host and sequencer SCB counts */ - uint8_t dff_thrsh; - uint8_t *scratch_ram; - uint8_t *btt; -}; - -typedef void (*ahd_bus_intr_t)(struct ahd_softc *); - -typedef enum { - AHD_MODE_DFF0, - AHD_MODE_DFF1, - AHD_MODE_CCHAN, - AHD_MODE_SCSI, - AHD_MODE_CFG, - AHD_MODE_UNKNOWN -} ahd_mode; - -#define AHD_MK_MSK(x) (0x01 << (x)) -#define AHD_MODE_DFF0_MSK AHD_MK_MSK(AHD_MODE_DFF0) -#define AHD_MODE_DFF1_MSK AHD_MK_MSK(AHD_MODE_DFF1) -#define AHD_MODE_CCHAN_MSK AHD_MK_MSK(AHD_MODE_CCHAN) -#define AHD_MODE_SCSI_MSK AHD_MK_MSK(AHD_MODE_SCSI) -#define AHD_MODE_CFG_MSK AHD_MK_MSK(AHD_MODE_CFG) -#define AHD_MODE_UNKNOWN_MSK AHD_MK_MSK(AHD_MODE_UNKNOWN) -#define AHD_MODE_ANY_MSK (~0) - -typedef uint8_t ahd_mode_state; - -typedef void ahd_callback_t (void *); - -struct ahd_completion -{ - uint16_t tag; - uint8_t sg_status; - uint8_t valid_tag; -}; - -struct ahd_softc { - bus_space_tag_t tags[2]; - bus_space_handle_t bshs[2]; -#ifndef __linux__ - bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */ -#endif - struct scb_data scb_data; - - struct hardware_scb *next_queued_hscb; - struct map_node *next_queued_hscb_map; - - /* - * SCBs that have been sent to the controller - */ - LIST_HEAD(, scb) pending_scbs; - - /* - * Current register window mode information. - */ - ahd_mode dst_mode; - ahd_mode src_mode; - - /* - * Saved register window mode information - * used for restore on next unpause. - */ - ahd_mode saved_dst_mode; - ahd_mode saved_src_mode; - - /* - * Platform specific data. - */ - struct ahd_platform_data *platform_data; - - /* - * Platform specific device information. - */ - ahd_dev_softc_t dev_softc; - - /* - * Bus specific device information. - */ - ahd_bus_intr_t bus_intr; - - /* - * Target mode related state kept on a per enabled lun basis. - * Targets that are not enabled will have null entries. - * As an initiator, we keep one target entry for our initiator - * ID to store our sync/wide transfer settings. - */ - struct ahd_tmode_tstate *enabled_targets[AHD_NUM_TARGETS]; - - /* - * The black hole device responsible for handling requests for - * disabled luns on enabled targets. - */ - struct ahd_tmode_lstate *black_hole; - - /* - * Device instance currently on the bus awaiting a continue TIO - * for a command that was not given the disconnect priveledge. - */ - struct ahd_tmode_lstate *pending_device; - - /* - * Timer handles for timer driven callbacks. - */ - ahd_timer_t reset_timer; - ahd_timer_t stat_timer; - - /* - * Statistics. - */ -#define AHD_STAT_UPDATE_US 250000 /* 250ms */ -#define AHD_STAT_BUCKETS 4 - u_int cmdcmplt_bucket; - uint32_t cmdcmplt_counts[AHD_STAT_BUCKETS]; - uint32_t cmdcmplt_total; - - /* - * Card characteristics - */ - ahd_chip chip; - ahd_feature features; - ahd_bug bugs; - ahd_flag flags; - struct seeprom_config *seep_config; - - /* Command Queues */ - struct ahd_completion *qoutfifo; - uint16_t qoutfifonext; - uint16_t qoutfifonext_valid_tag; - uint16_t qinfifonext; - uint16_t qinfifo[AHD_SCB_MAX]; - - /* - * Our qfreeze count. The sequencer compares - * this value with its own counter to determine - * whether to allow selections to occur. - */ - uint16_t qfreeze_cnt; - - /* Values to store in the SEQCTL register for pause and unpause */ - uint8_t unpause; - uint8_t pause; - - /* Critical Section Data */ - struct cs *critical_sections; - u_int num_critical_sections; - - /* Buffer for handling packetized bitbucket. */ - uint8_t *overrun_buf; - - /* Links for chaining softcs */ - TAILQ_ENTRY(ahd_softc) links; - - /* Channel Names ('A', 'B', etc.) */ - char channel; - - /* Initiator Bus ID */ - uint8_t our_id; - - /* - * Target incoming command FIFO. - */ - struct target_cmd *targetcmds; - uint8_t tqinfifonext; - - /* - * Cached verson of the hs_mailbox so we can avoid - * pausing the sequencer during mailbox updates. - */ - uint8_t hs_mailbox; - - /* - * Incoming and outgoing message handling. - */ - uint8_t send_msg_perror; - ahd_msg_flags msg_flags; - ahd_msg_type msg_type; - uint8_t msgout_buf[12];/* Message we are sending */ - uint8_t msgin_buf[12];/* Message we are receiving */ - u_int msgout_len; /* Length of message to send */ - u_int msgout_index; /* Current index in msgout */ - u_int msgin_index; /* Current index in msgin */ - - /* - * Mapping information for data structures shared - * between the sequencer and kernel. - */ - bus_dma_tag_t parent_dmat; - bus_dma_tag_t shared_data_dmat; - struct map_node shared_data_map; - - /* Information saved through suspend/resume cycles */ - struct ahd_suspend_state suspend_state; - - /* Number of enabled target mode device on this card */ - u_int enabled_luns; - - /* Initialization level of this data structure */ - u_int init_level; - - /* PCI cacheline size. */ - u_int pci_cachesize; - - /* IO Cell Parameters */ - uint8_t iocell_opts[AHD_NUM_PER_DEV_ANNEXCOLS]; - - u_int stack_size; - uint16_t *saved_stack; - - /* Per-Unit descriptive information */ - const char *description; - const char *bus_description; - char *name; - int unit; - - /* Selection Timer settings */ - int seltime; - - /* - * Interrupt coalescing settings. - */ -#define AHD_INT_COALESCING_TIMER_DEFAULT 250 /*us*/ -#define AHD_INT_COALESCING_MAXCMDS_DEFAULT 10 -#define AHD_INT_COALESCING_MAXCMDS_MAX 127 -#define AHD_INT_COALESCING_MINCMDS_DEFAULT 5 -#define AHD_INT_COALESCING_MINCMDS_MAX 127 -#define AHD_INT_COALESCING_THRESHOLD_DEFAULT 2000 -#define AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT 1000 - u_int int_coalescing_timer; - u_int int_coalescing_maxcmds; - u_int int_coalescing_mincmds; - u_int int_coalescing_threshold; - u_int int_coalescing_stop_threshold; - - uint16_t user_discenable;/* Disconnection allowed */ - uint16_t user_tagenable;/* Tagged Queuing allowed */ -}; - -/*************************** IO Cell Configuration ****************************/ -#define AHD_PRECOMP_SLEW_INDEX \ - (AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0) - -#define AHD_AMPLITUDE_INDEX \ - (AHD_ANNEXCOL_AMPLITUDE - AHD_ANNEXCOL_PER_DEV0) - -#define AHD_SET_SLEWRATE(ahd, new_slew) \ -do { \ - (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_SLEWRATE_MASK; \ - (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] |= \ - (((new_slew) << AHD_SLEWRATE_SHIFT) & AHD_SLEWRATE_MASK); \ -} while (0) - -#define AHD_SET_PRECOMP(ahd, new_pcomp) \ -do { \ - (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK; \ - (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] |= \ - (((new_pcomp) << AHD_PRECOMP_SHIFT) & AHD_PRECOMP_MASK); \ -} while (0) - -#define AHD_SET_AMPLITUDE(ahd, new_amp) \ -do { \ - (ahd)->iocell_opts[AHD_AMPLITUDE_INDEX] &= ~AHD_AMPLITUDE_MASK; \ - (ahd)->iocell_opts[AHD_AMPLITUDE_INDEX] |= \ - (((new_amp) << AHD_AMPLITUDE_SHIFT) & AHD_AMPLITUDE_MASK); \ -} while (0) - -/************************ Active Device Information ***************************/ -typedef enum { - ROLE_UNKNOWN, - ROLE_INITIATOR, - ROLE_TARGET -} role_t; - -struct ahd_devinfo { - int our_scsiid; - int target_offset; - uint16_t target_mask; - u_int target; - u_int lun; - char channel; - role_t role; /* - * Only guaranteed to be correct if not - * in the busfree state. - */ -}; - -/****************************** PCI Structures ********************************/ -#define AHD_PCI_IOADDR0 PCIR_BAR(0) /* I/O BAR*/ -#define AHD_PCI_MEMADDR PCIR_BAR(1) /* Memory BAR */ -#define AHD_PCI_IOADDR1 PCIR_BAR(3) /* Second I/O BAR */ - -typedef int (ahd_device_setup_t)(struct ahd_softc *); - -struct ahd_pci_identity { - uint64_t full_id; - uint64_t id_mask; - const char *name; - ahd_device_setup_t *setup; -}; - -/***************************** VL/EISA Declarations ***************************/ -struct aic7770_identity { - uint32_t full_id; - uint32_t id_mask; - const char *name; - ahd_device_setup_t *setup; -}; -extern struct aic7770_identity aic7770_ident_table []; -extern const int ahd_num_aic7770_devs; - -#define AHD_EISA_SLOT_OFFSET 0xc00 -#define AHD_EISA_IOSIZE 0x100 - -/*************************** Function Declarations ****************************/ -/******************************************************************************/ - -/***************************** PCI Front End *********************************/ -const struct ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t); -int ahd_pci_config(struct ahd_softc *, - const struct ahd_pci_identity *); -int ahd_pci_test_register_access(struct ahd_softc *); -#ifdef CONFIG_PM -void ahd_pci_suspend(struct ahd_softc *); -void ahd_pci_resume(struct ahd_softc *); -#endif - -/************************** SCB and SCB queue management **********************/ -void ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, - struct scb *scb); - -/****************************** Initialization ********************************/ -struct ahd_softc *ahd_alloc(void *platform_arg, char *name); -int ahd_softc_init(struct ahd_softc *); -void ahd_controller_info(struct ahd_softc *ahd, char *buf); -int ahd_init(struct ahd_softc *ahd); -#ifdef CONFIG_PM -int ahd_suspend(struct ahd_softc *ahd); -void ahd_resume(struct ahd_softc *ahd); -#endif -int ahd_default_config(struct ahd_softc *ahd); -int ahd_parse_vpddata(struct ahd_softc *ahd, - struct vpd_config *vpd); -int ahd_parse_cfgdata(struct ahd_softc *ahd, - struct seeprom_config *sc); -void ahd_intr_enable(struct ahd_softc *ahd, int enable); -void ahd_pause_and_flushwork(struct ahd_softc *ahd); -void ahd_set_unit(struct ahd_softc *, int); -void ahd_set_name(struct ahd_softc *, char *); -struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx); -void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb); -void ahd_free(struct ahd_softc *ahd); -int ahd_reset(struct ahd_softc *ahd, int reinit); -int ahd_write_flexport(struct ahd_softc *ahd, - u_int addr, u_int value); -int ahd_read_flexport(struct ahd_softc *ahd, u_int addr, - uint8_t *value); - -/***************************** Error Recovery *********************************/ -typedef enum { - SEARCH_COMPLETE, - SEARCH_COUNT, - SEARCH_REMOVE, - SEARCH_PRINT -} ahd_search_action; -int ahd_search_qinfifo(struct ahd_softc *ahd, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status, - ahd_search_action action); -int ahd_search_disc_list(struct ahd_softc *ahd, int target, - char channel, int lun, u_int tag, - int stop_on_first, int remove, - int save_state); -int ahd_reset_channel(struct ahd_softc *ahd, char channel, - int initiate_reset); -/*************************** Utility Functions ********************************/ -void ahd_compile_devinfo(struct ahd_devinfo *devinfo, - u_int our_id, u_int target, - u_int lun, char channel, - role_t role); -/************************** Transfer Negotiation ******************************/ -void ahd_find_syncrate(struct ahd_softc *ahd, u_int *period, - u_int *ppr_options, u_int maxsync); -/* - * Negotiation types. These are used to qualify if we should renegotiate - * even if our goal and current transport parameters are identical. - */ -typedef enum { - AHD_NEG_TO_GOAL, /* Renegotiate only if goal and curr differ. */ - AHD_NEG_IF_NON_ASYNC, /* Renegotiate so long as goal is non-async. */ - AHD_NEG_ALWAYS /* Renegotiat even if goal is async. */ -} ahd_neg_type; -int ahd_update_neg_request(struct ahd_softc*, - struct ahd_devinfo*, - struct ahd_tmode_tstate*, - struct ahd_initiator_tinfo*, - ahd_neg_type); -void ahd_set_width(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - u_int width, u_int type, int paused); -void ahd_set_syncrate(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - u_int period, u_int offset, - u_int ppr_options, - u_int type, int paused); -typedef enum { - AHD_QUEUE_NONE, - AHD_QUEUE_BASIC, - AHD_QUEUE_TAGGED -} ahd_queue_alg; - -/**************************** Target Mode *************************************/ -#ifdef AHD_TARGET_MODE -void ahd_send_lstate_events(struct ahd_softc *, - struct ahd_tmode_lstate *); -void ahd_handle_en_lun(struct ahd_softc *ahd, - struct cam_sim *sim, union ccb *ccb); -cam_status ahd_find_tmode_devs(struct ahd_softc *ahd, - struct cam_sim *sim, union ccb *ccb, - struct ahd_tmode_tstate **tstate, - struct ahd_tmode_lstate **lstate, - int notfound_failure); -#ifndef AHD_TMODE_ENABLE -#define AHD_TMODE_ENABLE 0 -#endif -#endif -/******************************* Debug ***************************************/ -#ifdef AHD_DEBUG -extern uint32_t ahd_debug; -#define AHD_SHOW_MISC 0x00001 -#define AHD_SHOW_SENSE 0x00002 -#define AHD_SHOW_RECOVERY 0x00004 -#define AHD_DUMP_SEEPROM 0x00008 -#define AHD_SHOW_TERMCTL 0x00010 -#define AHD_SHOW_MEMORY 0x00020 -#define AHD_SHOW_MESSAGES 0x00040 -#define AHD_SHOW_MODEPTR 0x00080 -#define AHD_SHOW_SELTO 0x00100 -#define AHD_SHOW_FIFOS 0x00200 -#define AHD_SHOW_QFULL 0x00400 -#define AHD_SHOW_DV 0x00800 -#define AHD_SHOW_MASKED_ERRORS 0x01000 -#define AHD_SHOW_QUEUE 0x02000 -#define AHD_SHOW_TQIN 0x04000 -#define AHD_SHOW_SG 0x08000 -#define AHD_SHOW_INT_COALESCING 0x10000 -#define AHD_DEBUG_SEQUENCER 0x20000 -#endif -void ahd_print_devinfo(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -void ahd_dump_card_state(struct ahd_softc *ahd); -int ahd_print_register(const ahd_reg_parse_entry_t *table, - u_int num_entries, - const char *name, - u_int address, - u_int value, - u_int *cur_column, - u_int wrap_point); -#endif /* _AIC79XX_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.reg b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.reg deleted file mode 100644 index 7e12c31c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.reg +++ /dev/null @@ -1,4281 +0,0 @@ -/* - * Aic79xx register and scratch ram definitions. - * - * Copyright (c) 1994-2001, 2004 Justin T. Gibbs. - * Copyright (c) 2000-2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $FreeBSD$ - */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $" - -/* - * This file is processed by the aic7xxx_asm utility for use in assembling - * firmware for the aic79xx family of SCSI host adapters as well as to generate - * a C header file for use in the kernel portion of the Aic79xx driver. - */ - -/* Register window Modes */ -#define M_DFF0 0 -#define M_DFF1 1 -#define M_CCHAN 2 -#define M_SCSI 3 -#define M_CFG 4 -#define M_DST_SHIFT 4 - -#define MK_MODE(src, dst) ((src) | ((dst) << M_DST_SHIFT)) -#define SET_MODE(src, dst) \ - SET_SRC_MODE src; \ - SET_DST_MODE dst; \ - if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \ - mvi MK_MODE(src, dst) call set_mode_work_around; \ - } else { \ - mvi MODE_PTR, MK_MODE(src, dst); \ - } - -#define RESTORE_MODE(mode) \ - if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { \ - mov mode call set_mode_work_around; \ - } else { \ - mov MODE_PTR, mode; \ - } - -#define SET_SEQINTCODE(code) \ - if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { \ - mvi code call set_seqint_work_around; \ - } else { \ - mvi SEQINTCODE, code; \ - } - -/* - * Registers marked "dont_generate_debug_code" are not (yet) referenced - * from the driver code, and this keyword inhibit generation - * of debug code for them. - * - * REG_PRETTY_PRINT config will complain if dont_generate_debug_code - * is added to the register which is referenced in the driver. - * Unreferenced register with no dont_generate_debug_code will result - * in dead code. No warning is issued. - */ - -/* - * Mode Pointer - * Controls which of the 5, 512byte, address spaces should be used - * as the source and destination of any register accesses in our - * register window. - */ -register MODE_PTR { - address 0x000 - access_mode RW - field DST_MODE 0x70 - field SRC_MODE 0x07 - mode_pointer - dont_generate_debug_code -} - -const SRC_MODE_SHIFT 0 -const DST_MODE_SHIFT 4 - -/* - * Host Interrupt Status - */ -register INTSTAT { - address 0x001 - access_mode RW - field HWERRINT 0x80 - field BRKADRINT 0x40 - field SWTMINT 0x20 - field PCIINT 0x10 - field SCSIINT 0x08 - field SEQINT 0x04 - field CMDCMPLT 0x02 - field SPLTINT 0x01 - mask INT_PEND 0xFF -} - -/* - * Sequencer Interrupt Code - */ -register SEQINTCODE { - address 0x002 - access_mode RW - field { - NO_SEQINT, /* No seqint pending. */ - BAD_PHASE, /* unknown scsi bus phase */ - SEND_REJECT, /* sending a message reject */ - PROTO_VIOLATION, /* Protocol Violation */ - NO_MATCH, /* no cmd match for reconnect */ - IGN_WIDE_RES, /* Complex IGN Wide Res Msg */ - PDATA_REINIT, /* - * Returned to data phase - * that requires data - * transfer pointers to be - * recalculated from the - * transfer residual. - */ - HOST_MSG_LOOP, /* - * The bus is ready for the - * host to perform another - * message transaction. This - * mechanism is used for things - * like sync/wide negotiation - * that require a kernel based - * message state engine. - */ - BAD_STATUS, /* Bad status from target */ - DATA_OVERRUN, /* - * Target attempted to write - * beyond the bounds of its - * command. - */ - MKMSG_FAILED, /* - * Target completed command - * without honoring our ATN - * request to issue a message. - */ - MISSED_BUSFREE, /* - * The sequencer never saw - * the bus go free after - * either a command complete - * or disconnect message. - */ - DUMP_CARD_STATE, - ILLEGAL_PHASE, - INVALID_SEQINT, - CFG4ISTAT_INTR, - STATUS_OVERRUN, - CFG4OVERRUN, - ENTERING_NONPACK, - TASKMGMT_FUNC_COMPLETE, /* - * Task management function - * request completed with - * an expected busfree. - */ - TASKMGMT_CMD_CMPLT_OKAY, /* - * A command with a non-zero - * task management function - * has completed via the normal - * command completion method - * for commands with a zero - * task management function. - * This happens when an attempt - * to abort a command loses - * the race for the command to - * complete normally. - */ - TRACEPOINT0, - TRACEPOINT1, - TRACEPOINT2, - TRACEPOINT3, - SAW_HWERR, - BAD_SCB_STATUS - } - dont_generate_debug_code -} - -/* - * Clear Host Interrupt - */ -register CLRINT { - address 0x003 - access_mode WO - count 19 - field CLRHWERRINT 0x80 /* Rev B or greater */ - field CLRBRKADRINT 0x40 - field CLRSWTMINT 0x20 - field CLRPCIINT 0x10 - field CLRSCSIINT 0x08 - field CLRSEQINT 0x04 - field CLRCMDINT 0x02 - field CLRSPLTINT 0x01 - dont_generate_debug_code -} - -/* - * Error Register - */ -register ERROR { - address 0x004 - access_mode RO - field CIOPARERR 0x80 - field CIOACCESFAIL 0x40 /* Rev B or greater */ - field MPARERR 0x20 - field DPARERR 0x10 - field SQPARERR 0x08 - field ILLOPCODE 0x04 - field DSCTMOUT 0x02 - dont_generate_debug_code -} - -/* - * Clear Error - */ -register CLRERR { - address 0x004 - access_mode WO - field CLRCIOPARERR 0x80 - field CLRCIOACCESFAIL 0x40 /* Rev B or greater */ - field CLRMPARERR 0x20 - field CLRDPARERR 0x10 - field CLRSQPARERR 0x08 - field CLRILLOPCODE 0x04 - field CLRDSCTMOUT 0x02 -} - -/* - * Host Control Register - * Overall host control of the device. - */ -register HCNTRL { - address 0x005 - access_mode RW - count 12 - field SEQ_RESET 0x80 /* Rev B or greater */ - field POWRDN 0x40 - field SWINT 0x10 - field SWTIMER_START_B 0x08 /* Rev B or greater */ - field PAUSE 0x04 - field INTEN 0x02 - field CHIPRST 0x01 - field CHIPRSTACK 0x01 - dont_generate_debug_code -} - -/* - * Host New SCB Queue Offset - */ -register HNSCB_QOFF { - address 0x006 - access_mode RW - size 2 - count 2 - dont_generate_debug_code -} - -/* - * Host Empty SCB Queue Offset - */ -register HESCB_QOFF { - address 0x008 - access_mode RW - count 2 - dont_generate_debug_code -} - -/* - * Host Mailbox - */ -register HS_MAILBOX { - address 0x00B - access_mode RW - mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */ - mask ENINT_COALESCE 0x40 /* Perform interrupt coalescing */ -} - -/* - * Sequencer Interrupt Status - */ -register SEQINTSTAT { - address 0x00C - count 1 - access_mode RO - field SEQ_SWTMRTO 0x10 - field SEQ_SEQINT 0x08 - field SEQ_SCSIINT 0x04 - field SEQ_PCIINT 0x02 - field SEQ_SPLTINT 0x01 -} - -/* - * Clear SEQ Interrupt - */ -register CLRSEQINTSTAT { - address 0x00C - access_mode WO - field CLRSEQ_SWTMRTO 0x10 - field CLRSEQ_SEQINT 0x08 - field CLRSEQ_SCSIINT 0x04 - field CLRSEQ_PCIINT 0x02 - field CLRSEQ_SPLTINT 0x01 - dont_generate_debug_code -} - -/* - * Software Timer - */ -register SWTIMER { - address 0x00E - access_mode RW - size 2 - dont_generate_debug_code -} - -/* - * SEQ New SCB Queue Offset - */ -register SNSCB_QOFF { - address 0x010 - access_mode RW - size 2 - modes M_CCHAN - dont_generate_debug_code -} - -/* - * SEQ Empty SCB Queue Offset - */ -register SESCB_QOFF { - address 0x012 - count 2 - access_mode RW - modes M_CCHAN - dont_generate_debug_code -} - -/* - * SEQ Done SCB Queue Offset - */ -register SDSCB_QOFF { - address 0x014 - access_mode RW - modes M_CCHAN - size 2 - dont_generate_debug_code -} - -/* - * Queue Offset Control & Status - */ -register QOFF_CTLSTA { - address 0x016 - access_mode RW - modes M_CCHAN - field EMPTY_SCB_AVAIL 0x80 - field NEW_SCB_AVAIL 0x40 - field SDSCB_ROLLOVR 0x20 - field HS_MAILBOX_ACT 0x10 - field SCB_QSIZE 0x0F { - SCB_QSIZE_4, - SCB_QSIZE_8, - SCB_QSIZE_16, - SCB_QSIZE_32, - SCB_QSIZE_64, - SCB_QSIZE_128, - SCB_QSIZE_256, - SCB_QSIZE_512, - SCB_QSIZE_1024, - SCB_QSIZE_2048, - SCB_QSIZE_4096, - SCB_QSIZE_8192, - SCB_QSIZE_16384 - } - dont_generate_debug_code -} - -/* - * Interrupt Control - */ -register INTCTL { - address 0x018 - access_mode RW - field SWTMINTMASK 0x80 - field SWTMINTEN 0x40 - field SWTIMER_START 0x20 - field AUTOCLRCMDINT 0x10 - field PCIINTEN 0x08 - field SCSIINTEN 0x04 - field SEQINTEN 0x02 - field SPLTINTEN 0x01 -} - -/* - * Data FIFO Control - */ -register DFCNTRL { - address 0x019 - access_mode RW - modes M_DFF0, M_DFF1 - count 11 - field PRELOADEN 0x80 - field SCSIENWRDIS 0x40 /* Rev B only. */ - field SCSIEN 0x20 - field SCSIENACK 0x20 - field HDMAEN 0x08 - field HDMAENACK 0x08 - field DIRECTION 0x04 - field DIRECTIONACK 0x04 - field FIFOFLUSH 0x02 - field FIFOFLUSHACK 0x02 - field DIRECTIONEN 0x01 -} - -/* - * Device Space Command 0 - */ -register DSCOMMAND0 { - address 0x019 - count 1 - access_mode RW - modes M_CFG - field CACHETHEN 0x80 /* Cache Threshold enable */ - field DPARCKEN 0x40 /* Data Parity Check Enable */ - field MPARCKEN 0x20 /* Memory Parity Check Enable */ - field EXTREQLCK 0x10 /* External Request Lock */ - field DISABLE_TWATE 0x02 /* Rev B or greater */ - field CIOPARCKEN 0x01 /* Internal bus parity error enable */ - dont_generate_debug_code -} - -/* - * Data FIFO Status - */ -register DFSTATUS { - address 0x01A - access_mode RO - modes M_DFF0, M_DFF1 - field PRELOAD_AVAIL 0x80 - field PKT_PRELOAD_AVAIL 0x40 - field MREQPEND 0x10 - field HDONE 0x08 - field DFTHRESH 0x04 - field FIFOFULL 0x02 - field FIFOEMP 0x01 -} - -/* - * S/G Cache Pointer - */ -register SG_CACHE_PRE { - address 0x01B - access_mode WO - modes M_DFF0, M_DFF1 - field SG_ADDR_MASK 0xf8 - field ODD_SEG 0x04 - field LAST_SEG 0x02 - dont_generate_debug_code -} - -register SG_CACHE_SHADOW { - address 0x01B - access_mode RO - modes M_DFF0, M_DFF1 - field SG_ADDR_MASK 0xf8 - field ODD_SEG 0x04 - field LAST_SEG 0x02 - field LAST_SEG_DONE 0x01 -} - -/* - * Arbiter Control - */ -register ARBCTL { - address 0x01B - access_mode RW - modes M_CFG - field RESET_HARB 0x80 - field RETRY_SWEN 0x08 - field USE_TIME 0x07 -} - -/* - * Data Channel Host Address - */ -register HADDR { - address 0x070 - access_mode RW - size 8 - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * Host Overlay DMA Address - */ -register HODMAADR { - address 0x070 - access_mode RW - size 8 - modes M_SCSI -} - -/* - * PCI PLL Delay. - */ -register PLLDELAY { - address 0x070 - access_mode RW - size 1 - modes M_CFG - field SPLIT_DROP_REQ 0x80 -} - -/* - * Data Channel Host Count - */ -register HCNT { - address 0x078 - access_mode RW - size 3 - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * Host Overlay DMA Count - */ -register HODMACNT { - address 0x078 - access_mode RW - size 2 - modes M_SCSI -} - -/* - * Host Overlay DMA Enable - */ -register HODMAEN { - address 0x07A - access_mode RW - modes M_SCSI -} - -/* - * Scatter/Gather Host Address - */ -register SGHADDR { - address 0x07C - access_mode RW - size 8 - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * SCB Host Address - */ -register SCBHADDR { - address 0x07C - access_mode RW - size 8 - modes M_CCHAN - dont_generate_debug_code -} - -/* - * Scatter/Gather Host Count - */ -register SGHCNT { - address 0x084 - access_mode RW - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * SCB Host Count - */ -register SCBHCNT { - address 0x084 - access_mode RW - modes M_CCHAN - dont_generate_debug_code -} - -/* - * Data FIFO Threshold - */ -register DFF_THRSH { - address 0x088 - access_mode RW - modes M_CFG - count 1 - field WR_DFTHRSH 0x70 { - WR_DFTHRSH_MIN, - WR_DFTHRSH_25, - WR_DFTHRSH_50, - WR_DFTHRSH_63, - WR_DFTHRSH_75, - WR_DFTHRSH_85, - WR_DFTHRSH_90, - WR_DFTHRSH_MAX - } - field RD_DFTHRSH 0x07 { - RD_DFTHRSH_MIN, - RD_DFTHRSH_25, - RD_DFTHRSH_50, - RD_DFTHRSH_63, - RD_DFTHRSH_75, - RD_DFTHRSH_85, - RD_DFTHRSH_90, - RD_DFTHRSH_MAX - } - dont_generate_debug_code -} - -/* - * ROM Address - */ -register ROMADDR { - address 0x08A - access_mode RW - size 3 -} - -/* - * ROM Control - */ -register ROMCNTRL { - address 0x08D - access_mode RW - field ROMOP 0xE0 - field ROMSPD 0x18 - field REPEAT 0x02 - field RDY 0x01 -} - -/* - * ROM Data - */ -register ROMDATA { - address 0x08E - access_mode RW -} - -/* - * Data Channel Receive Message 0 - */ -register DCHRXMSG0 { - address 0x090 - access_mode RO - modes M_DFF0, M_DFF1 - field CDNUM 0xF8 - field CFNUM 0x07 -} - -/* - * CMC Receive Message 0 - */ -register CMCRXMSG0 { - address 0x090 - access_mode RO - modes M_CCHAN - field CDNUM 0xF8 - field CFNUM 0x07 -} - -/* - * Overlay Receive Message 0 - */ -register OVLYRXMSG0 { - address 0x090 - access_mode RO - modes M_SCSI - field CDNUM 0xF8 - field CFNUM 0x07 -} - -/* - * Relaxed Order Enable - */ -register ROENABLE { - address 0x090 - access_mode RW - modes M_CFG - field MSIROEN 0x20 - field OVLYROEN 0x10 - field CMCROEN 0x08 - field SGROEN 0x04 - field DCH1ROEN 0x02 - field DCH0ROEN 0x01 -} - -/* - * Data Channel Receive Message 1 - */ -register DCHRXMSG1 { - address 0x091 - access_mode RO - modes M_DFF0, M_DFF1 - field CBNUM 0xFF -} - -/* - * CMC Receive Message 1 - */ -register CMCRXMSG1 { - address 0x091 - access_mode RO - modes M_CCHAN - field CBNUM 0xFF -} - -/* - * Overlay Receive Message 1 - */ -register OVLYRXMSG1 { - address 0x091 - access_mode RO - modes M_SCSI - field CBNUM 0xFF -} - -/* - * No Snoop Enable - */ -register NSENABLE { - address 0x091 - access_mode RW - modes M_CFG - field MSINSEN 0x20 - field OVLYNSEN 0x10 - field CMCNSEN 0x08 - field SGNSEN 0x04 - field DCH1NSEN 0x02 - field DCH0NSEN 0x01 -} - -/* - * Data Channel Receive Message 2 - */ -register DCHRXMSG2 { - address 0x092 - access_mode RO - modes M_DFF0, M_DFF1 - field MINDEX 0xFF -} - -/* - * CMC Receive Message 2 - */ -register CMCRXMSG2 { - address 0x092 - access_mode RO - modes M_CCHAN - field MINDEX 0xFF -} - -/* - * Overlay Receive Message 2 - */ -register OVLYRXMSG2 { - address 0x092 - access_mode RO - modes M_SCSI - field MINDEX 0xFF -} - -/* - * Outstanding Split Transactions - */ -register OST { - address 0x092 - access_mode RW - modes M_CFG -} - -/* - * Data Channel Receive Message 3 - */ -register DCHRXMSG3 { - address 0x093 - access_mode RO - modes M_DFF0, M_DFF1 - field MCLASS 0x0F -} - -/* - * CMC Receive Message 3 - */ -register CMCRXMSG3 { - address 0x093 - access_mode RO - modes M_CCHAN - field MCLASS 0x0F -} - -/* - * Overlay Receive Message 3 - */ -register OVLYRXMSG3 { - address 0x093 - access_mode RO - modes M_SCSI - field MCLASS 0x0F -} - -/* - * PCI-X Control - */ -register PCIXCTL { - address 0x093 - access_mode RW - modes M_CFG - count 1 - field SERRPULSE 0x80 - field UNEXPSCIEN 0x20 - field SPLTSMADIS 0x10 - field SPLTSTADIS 0x08 - field SRSPDPEEN 0x04 - field TSCSERREN 0x02 - field CMPABCDIS 0x01 - dont_generate_debug_code -} - -/* - * CMC Sequencer Byte Count - */ -register CMCSEQBCNT { - address 0x094 - access_mode RO - modes M_CCHAN -} - -/* - * Overlay Sequencer Byte Count - */ -register OVLYSEQBCNT { - address 0x094 - access_mode RO - modes M_SCSI -} - -/* - * Data Channel Sequencer Byte Count - */ -register DCHSEQBCNT { - address 0x094 - access_mode RO - size 2 - modes M_DFF0, M_DFF1 -} - -/* - * Data Channel Split Status 0 - */ -register DCHSPLTSTAT0 { - address 0x096 - access_mode RW - modes M_DFF0, M_DFF1 - count 2 - field STAETERM 0x80 - field SCBCERR 0x40 - field SCADERR 0x20 - field SCDATBUCKET 0x10 - field CNTNOTCMPLT 0x08 - field RXOVRUN 0x04 - field RXSCEMSG 0x02 - field RXSPLTRSP 0x01 - dont_generate_debug_code -} - -/* - * CMC Split Status 0 - */ -register CMCSPLTSTAT0 { - address 0x096 - access_mode RW - modes M_CCHAN - field STAETERM 0x80 - field SCBCERR 0x40 - field SCADERR 0x20 - field SCDATBUCKET 0x10 - field CNTNOTCMPLT 0x08 - field RXOVRUN 0x04 - field RXSCEMSG 0x02 - field RXSPLTRSP 0x01 -} - -/* - * Overlay Split Status 0 - */ -register OVLYSPLTSTAT0 { - address 0x096 - access_mode RW - modes M_SCSI - field STAETERM 0x80 - field SCBCERR 0x40 - field SCADERR 0x20 - field SCDATBUCKET 0x10 - field CNTNOTCMPLT 0x08 - field RXOVRUN 0x04 - field RXSCEMSG 0x02 - field RXSPLTRSP 0x01 -} - -/* - * Data Channel Split Status 1 - */ -register DCHSPLTSTAT1 { - address 0x097 - access_mode RW - modes M_DFF0, M_DFF1 - count 2 - field RXDATABUCKET 0x01 - dont_generate_debug_code -} - -/* - * CMC Split Status 1 - */ -register CMCSPLTSTAT1 { - address 0x097 - access_mode RW - modes M_CCHAN - field RXDATABUCKET 0x01 -} - -/* - * Overlay Split Status 1 - */ -register OVLYSPLTSTAT1 { - address 0x097 - access_mode RW - modes M_SCSI - field RXDATABUCKET 0x01 -} - -/* - * S/G Receive Message 0 - */ -register SGRXMSG0 { - address 0x098 - access_mode RO - modes M_DFF0, M_DFF1 - field CDNUM 0xF8 - field CFNUM 0x07 -} - -/* - * S/G Receive Message 1 - */ -register SGRXMSG1 { - address 0x099 - access_mode RO - modes M_DFF0, M_DFF1 - field CBNUM 0xFF -} - -/* - * S/G Receive Message 2 - */ -register SGRXMSG2 { - address 0x09A - access_mode RO - modes M_DFF0, M_DFF1 - field MINDEX 0xFF -} - -/* - * S/G Receive Message 3 - */ -register SGRXMSG3 { - address 0x09B - access_mode RO - modes M_DFF0, M_DFF1 - field MCLASS 0x0F -} - -/* - * Slave Split Out Address 0 - */ -register SLVSPLTOUTADR0 { - address 0x098 - access_mode RO - modes M_SCSI - field LOWER_ADDR 0x7F -} - -/* - * Slave Split Out Address 1 - */ -register SLVSPLTOUTADR1 { - address 0x099 - access_mode RO - modes M_SCSI - field REQ_DNUM 0xF8 - field REQ_FNUM 0x07 -} - -/* - * Slave Split Out Address 2 - */ -register SLVSPLTOUTADR2 { - address 0x09A - access_mode RO - modes M_SCSI - field REQ_BNUM 0xFF -} - -/* - * Slave Split Out Address 3 - */ -register SLVSPLTOUTADR3 { - address 0x09B - access_mode RO - modes M_SCSI - field RLXORD 020 - field TAG_NUM 0x1F -} - -/* - * SG Sequencer Byte Count - */ -register SGSEQBCNT { - address 0x09C - access_mode RO - modes M_DFF0, M_DFF1 -} - -/* - * Slave Split Out Attribute 0 - */ -register SLVSPLTOUTATTR0 { - address 0x09C - access_mode RO - modes M_SCSI - field LOWER_BCNT 0xFF -} - -/* - * Slave Split Out Attribute 1 - */ -register SLVSPLTOUTATTR1 { - address 0x09D - access_mode RO - modes M_SCSI - field CMPLT_DNUM 0xF8 - field CMPLT_FNUM 0x07 -} - -/* - * Slave Split Out Attribute 2 - */ -register SLVSPLTOUTATTR2 { - address 0x09E - access_mode RO - size 2 - modes M_SCSI - field CMPLT_BNUM 0xFF -} -/* - * S/G Split Status 0 - */ -register SGSPLTSTAT0 { - address 0x09E - access_mode RW - modes M_DFF0, M_DFF1 - count 2 - field STAETERM 0x80 - field SCBCERR 0x40 - field SCADERR 0x20 - field SCDATBUCKET 0x10 - field CNTNOTCMPLT 0x08 - field RXOVRUN 0x04 - field RXSCEMSG 0x02 - field RXSPLTRSP 0x01 - dont_generate_debug_code -} - -/* - * S/G Split Status 1 - */ -register SGSPLTSTAT1 { - address 0x09F - access_mode RW - modes M_DFF0, M_DFF1 - count 2 - field RXDATABUCKET 0x01 - dont_generate_debug_code -} - -/* - * Special Function - */ -register SFUNCT { - address 0x09f - access_mode RW - modes M_CFG - field TEST_GROUP 0xF0 - field TEST_NUM 0x0F - dont_generate_debug_code -} - -/* - * Data FIFO 0 PCI Status - */ -register DF0PCISTAT { - address 0x0A0 - access_mode RW - modes M_CFG - count 1 - field DPE 0x80 - field SSE 0x40 - field RMA 0x20 - field RTA 0x10 - field SCAAPERR 0x08 - field RDPERR 0x04 - field TWATERR 0x02 - field DPR 0x01 - dont_generate_debug_code -} - -/* - * Data FIFO 1 PCI Status - */ -register DF1PCISTAT { - address 0x0A1 - access_mode RW - modes M_CFG - field DPE 0x80 - field SSE 0x40 - field RMA 0x20 - field RTA 0x10 - field SCAAPERR 0x08 - field RDPERR 0x04 - field TWATERR 0x02 - field DPR 0x01 -} - -/* - * S/G PCI Status - */ -register SGPCISTAT { - address 0x0A2 - access_mode RW - modes M_CFG - field DPE 0x80 - field SSE 0x40 - field RMA 0x20 - field RTA 0x10 - field SCAAPERR 0x08 - field RDPERR 0x04 - field DPR 0x01 -} - -/* - * CMC PCI Status - */ -register CMCPCISTAT { - address 0x0A3 - access_mode RW - modes M_CFG - field DPE 0x80 - field SSE 0x40 - field RMA 0x20 - field RTA 0x10 - field SCAAPERR 0x08 - field RDPERR 0x04 - field TWATERR 0x02 - field DPR 0x01 -} - -/* - * Overlay PCI Status - */ -register OVLYPCISTAT { - address 0x0A4 - access_mode RW - modes M_CFG - field DPE 0x80 - field SSE 0x40 - field RMA 0x20 - field RTA 0x10 - field SCAAPERR 0x08 - field RDPERR 0x04 - field DPR 0x01 -} - -/* - * PCI Status for MSI Master DMA Transfer - */ -register MSIPCISTAT { - address 0x0A6 - access_mode RW - modes M_CFG - field SSE 0x40 - field RMA 0x20 - field RTA 0x10 - field CLRPENDMSI 0x08 - field TWATERR 0x02 - field DPR 0x01 -} - -/* - * PCI Status for Target - */ -register TARGPCISTAT { - address 0x0A7 - access_mode RW - modes M_CFG - count 5 - field DPE 0x80 - field SSE 0x40 - field STA 0x08 - field TWATERR 0x02 - dont_generate_debug_code -} - -/* - * LQ Packet In - * The last LQ Packet received - */ -register LQIN { - address 0x020 - access_mode RW - size 20 - count 2 - modes M_DFF0, M_DFF1, M_SCSI - dont_generate_debug_code -} - -/* - * SCB Type Pointer - * SCB offset for Target Mode SCB type information - */ -register TYPEPTR { - address 0x020 - access_mode RW - modes M_CFG -} - -/* - * Queue Tag Pointer - * SCB offset to the Two Byte tag identifier used for target mode. - */ -register TAGPTR { - address 0x021 - access_mode RW - modes M_CFG -} - -/* - * Logical Unit Number Pointer - * SCB offset to the LSB (little endian) of the lun field. - */ -register LUNPTR { - address 0x022 - access_mode RW - modes M_CFG - count 2 - dont_generate_debug_code -} - -/* - * Data Length Pointer - * SCB offset for the 4 byte data length field in target mode. - */ -register DATALENPTR { - address 0x023 - access_mode RW - modes M_CFG -} - -/* - * Status Length Pointer - * SCB offset to the two byte status field in target SCBs. - */ -register STATLENPTR { - address 0x024 - access_mode RW - modes M_CFG -} - -/* - * Command Length Pointer - * Scb offset for the CDB length field in initiator SCBs. - */ -register CMDLENPTR { - address 0x025 - access_mode RW - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Task Attribute Pointer - * Scb offset for the byte field specifying the attribute byte - * to be used in command packets. - */ -register ATTRPTR { - address 0x026 - access_mode RW - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Task Management Flags Pointer - * Scb offset for the byte field specifying the attribute flags - * byte to be used in command packets. - */ -register FLAGPTR { - address 0x027 - access_mode RW - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Command Pointer - * Scb offset for the first byte in the CDB for initiator SCBs. - */ -register CMDPTR { - address 0x028 - access_mode RW - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Queue Next Pointer - * Scb offset for the 2 byte "next scb link". - */ -register QNEXTPTR { - address 0x029 - access_mode RW - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * SCSI ID Pointer - * Scb offset to the value to place in the SCSIID register - * during target mode connections. - */ -register IDPTR { - address 0x02A - access_mode RW - modes M_CFG -} - -/* - * Command Aborted Byte Pointer - * Offset to the SCB flags field that includes the - * "SCB aborted" status bit. - */ -register ABRTBYTEPTR { - address 0x02B - access_mode RW - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Command Aborted Bit Pointer - * Bit offset in the SCB flags field for "SCB aborted" status. - */ -register ABRTBITPTR { - address 0x02C - access_mode RW - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Rev B or greater. - */ -register MAXCMDBYTES { - address 0x02D - access_mode RW - modes M_CFG -} - -/* - * Rev B or greater. - */ -register MAXCMD2RCV { - address 0x02E - access_mode RW - modes M_CFG -} - -/* - * Rev B or greater. - */ -register SHORTTHRESH { - address 0x02F - access_mode RW - modes M_CFG -} - -/* - * Logical Unit Number Length - * The length, in bytes, of the SCB lun field. - */ -register LUNLEN { - address 0x030 - access_mode RW - modes M_CFG - count 2 - mask ILUNLEN 0x0F - mask TLUNLEN 0xF0 - dont_generate_debug_code -} -const LUNLEN_SINGLE_LEVEL_LUN 0xF - -/* - * CDB Limit - * The size, in bytes, of the embedded CDB field in initator SCBs. - */ -register CDBLIMIT { - address 0x031 - access_mode RW - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Maximum Commands - * The maximum number of commands to issue during a - * single packetized connection. - */ -register MAXCMD { - address 0x032 - access_mode RW - modes M_CFG - count 9 - dont_generate_debug_code -} - -/* - * Maximum Command Counter - * The number of commands already sent during this connection - */ -register MAXCMDCNT { - address 0x033 - access_mode RW - modes M_CFG - dont_generate_debug_code -} - -/* - * LQ Packet Reserved Bytes - * The bytes to be sent in the currently reserved fileds - * of all LQ packets. - */ -register LQRSVD01 { - address 0x034 - access_mode RW - modes M_SCSI -} -register LQRSVD16 { - address 0x035 - access_mode RW - modes M_SCSI -} -register LQRSVD17 { - address 0x036 - access_mode RW - modes M_SCSI -} - -/* - * Command Reserved 0 - * The byte to be sent for the reserved byte 0 of - * outgoing command packets. - */ -register CMDRSVD0 { - address 0x037 - access_mode RW - modes M_CFG -} - -/* - * LQ Manager Control 0 - */ -register LQCTL0 { - address 0x038 - access_mode RW - modes M_CFG - field LQITARGCLT 0xC0 - field LQIINITGCLT 0x30 - field LQ0TARGCLT 0x0C - field LQ0INITGCLT 0x03 -} - -/* - * LQ Manager Control 1 - */ -register LQCTL1 { - address 0x038 - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - count 2 - field PCI2PCI 0x04 - field SINGLECMD 0x02 - field ABORTPENDING 0x01 - dont_generate_debug_code -} - -/* - * LQ Manager Control 2 - */ -register LQCTL2 { - address 0x039 - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - count 5 - field LQIRETRY 0x80 - field LQICONTINUE 0x40 - field LQITOIDLE 0x20 - field LQIPAUSE 0x10 - field LQORETRY 0x08 - field LQOCONTINUE 0x04 - field LQOTOIDLE 0x02 - field LQOPAUSE 0x01 - dont_generate_debug_code -} - -/* - * SCSI RAM BIST0 - */ -register SCSBIST0 { - address 0x039 - access_mode RW - modes M_CFG - field GSBISTERR 0x40 - field GSBISTDONE 0x20 - field GSBISTRUN 0x10 - field OSBISTERR 0x04 - field OSBISTDONE 0x02 - field OSBISTRUN 0x01 -} - -/* - * SCSI Sequence Control0 - */ -register SCSISEQ0 { - address 0x03A - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - field TEMODEO 0x80 - field ENSELO 0x40 - field ENARBO 0x20 - field FORCEBUSFREE 0x10 - field SCSIRSTO 0x01 -} - -/* - * SCSI RAM BIST 1 - */ -register SCSBIST1 { - address 0x03A - access_mode RW - modes M_CFG - field NTBISTERR 0x04 - field NTBISTDONE 0x02 - field NTBISTRUN 0x01 -} - -/* - * SCSI Sequence Control 1 - */ -register SCSISEQ1 { - address 0x03B - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - count 8 - field MANUALCTL 0x40 - field ENSELI 0x20 - field ENRSELI 0x10 - field MANUALP 0x0C - field ENAUTOATNP 0x02 - field ALTSTIM 0x01 -} - -/* - * SCSI Transfer Control 0 - */ -register SXFRCTL0 { - address 0x03C - access_mode RW - modes M_SCSI - field DFON 0x80 - field DFPEXP 0x40 - field BIOSCANCELEN 0x10 - field SPIOEN 0x08 - dont_generate_debug_code -} - -/* - * SCSI Transfer Control 1 - */ -register SXFRCTL1 { - address 0x03D - access_mode RW - modes M_SCSI - field BITBUCKET 0x80 - field ENSACHK 0x40 - field ENSPCHK 0x20 - field STIMESEL 0x18 - field ENSTIMER 0x04 - field ACTNEGEN 0x02 - field STPWEN 0x01 - dont_generate_debug_code -} - -/* - * SCSI Transfer Control 2 - */ -register SXFRCTL2 { - address 0x03E - access_mode RW - modes M_SCSI - field AUTORSTDIS 0x10 - field CMDDMAEN 0x08 - field ASU 0x07 -} - -/* - * SCSI Bus Initiator IDs - * Bitmask of observed initiators on the bus. - */ -register BUSINITID { - address 0x03C - access_mode RW - modes M_CFG - size 2 -} - -/* - * Data Length Counters - * Packet byte counter. - */ -register DLCOUNT { - address 0x03C - access_mode RW - modes M_DFF0, M_DFF1 - size 3 -} - -/* - * Data FIFO Status - */ -register DFFSTAT { - address 0x03F - access_mode RW - modes M_SCSI - field FIFO1FREE 0x20 - field FIFO0FREE 0x10 - /* - * On the B, this enum only works - * in the read direction. For writes, - * you must use the B version of the - * CURRFIFO_0 definition which is defined - * as a constant outside of this register - * definition to avoid confusing the - * register pretty printing code. - */ - enum CURRFIFO 0x03 { - CURRFIFO_0, - CURRFIFO_1, - CURRFIFO_NONE 0x3 - } -} - -const B_CURRFIFO_0 0x2 - -/* - * SCSI Bus Target IDs - * Bitmask of observed targets on the bus. - */ -register BUSTARGID { - address 0x03E - access_mode RW - modes M_CFG - size 2 -} - -/* - * SCSI Control Signal Out - */ -register SCSISIGO { - address 0x040 - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - field CDO 0x80 - field IOO 0x40 - field MSGO 0x20 - field ATNO 0x10 - field SELO 0x08 - field BSYO 0x04 - field REQO 0x02 - field ACKO 0x01 -/* - * Possible phases to write into SCSISIG0 - */ - enum PHASE_MASK CDO|IOO|MSGO { - P_DATAOUT 0x0, - P_DATAIN IOO, - P_DATAOUT_DT P_DATAOUT|MSGO, - P_DATAIN_DT P_DATAIN|MSGO, - P_COMMAND CDO, - P_MESGOUT CDO|MSGO, - P_STATUS CDO|IOO, - P_MESGIN CDO|IOO|MSGO - } - dont_generate_debug_code -} - -/* - * SCSI Control Signal In - */ -register SCSISIGI { - address 0x041 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - field CDI 0x80 - field IOI 0x40 - field MSGI 0x20 - field ATNI 0x10 - field SELI 0x08 - field BSYI 0x04 - field REQI 0x02 - field ACKI 0x01 -/* - * Possible phases in SCSISIGI - */ - enum PHASE_MASK CDO|IOO|MSGO { - P_DATAOUT 0x0, - P_DATAIN IOO, - P_DATAOUT_DT P_DATAOUT|MSGO, - P_DATAIN_DT P_DATAIN|MSGO, - P_COMMAND CDO, - P_MESGOUT CDO|MSGO, - P_STATUS CDO|IOO, - P_MESGIN CDO|IOO|MSGO - } -} - -/* - * Multiple Target IDs - * Bitmask of ids to respond as a target. - */ -register MULTARGID { - address 0x040 - access_mode RW - modes M_CFG - size 2 - count 2 - dont_generate_debug_code -} - -/* - * SCSI Phase - */ -register SCSIPHASE { - address 0x042 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - field STATUS_PHASE 0x20 - field COMMAND_PHASE 0x10 - field MSG_IN_PHASE 0x08 - field MSG_OUT_PHASE 0x04 - field DATA_PHASE_MASK 0x03 { - DATA_OUT_PHASE 0x01, - DATA_IN_PHASE 0x02 - } -} - -/* - * SCSI Data 0 Image - */ -register SCSIDAT0_IMG { - address 0x043 - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI -} - -/* - * SCSI Latched Data - */ -register SCSIDAT { - address 0x044 - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - size 2 - dont_generate_debug_code -} - -/* - * SCSI Data Bus - */ -register SCSIBUS { - address 0x046 - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - size 2 -} - -/* - * Target ID In - */ -register TARGIDIN { - address 0x048 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - count 2 - field CLKOUT 0x80 - field TARGID 0x0F - dont_generate_debug_code -} - -/* - * Selection/Reselection ID - * Upper four bits are the device id. The ONEBIT is set when the re/selecting - * device did not set its own ID. - */ -register SELID { - address 0x049 - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - field SELID_MASK 0xf0 - field ONEBIT 0x08 -} - -/* - * SCSI Block Control - * Controls Bus type and channel selection. SELWIDE allows for the - * coexistence of 8bit and 16bit devices on a wide bus. - */ -register SBLKCTL { - address 0x04A - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - field DIAGLEDEN 0x80 - field DIAGLEDON 0x40 - field ENAB40 0x08 /* LVD transceiver active */ - field ENAB20 0x04 /* SE/HVD transceiver active */ - field SELWIDE 0x02 - dont_generate_debug_code -} - -/* - * Option Mode - */ -register OPTIONMODE { - address 0x04A - access_mode RW - modes M_CFG - count 4 - field BIOSCANCTL 0x80 - field AUTOACKEN 0x40 - field BIASCANCTL 0x20 - field BUSFREEREV 0x10 - field ENDGFORMCHK 0x04 - field AUTO_MSGOUT_DE 0x02 - mask OPTIONMODE_DEFAULTS AUTO_MSGOUT_DE - dont_generate_debug_code -} - -/* - * SCSI Status 0 - */ -register SSTAT0 { - address 0x04B - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - field TARGET 0x80 /* Board acting as target */ - field SELDO 0x40 /* Selection Done */ - field SELDI 0x20 /* Board has been selected */ - field SELINGO 0x10 /* Selection In Progress */ - field IOERR 0x08 /* LVD Tranceiver mode changed */ - field OVERRUN 0x04 /* SCSI Offset overrun detected */ - field SPIORDY 0x02 /* SCSI PIO Ready */ - field ARBDO 0x01 /* Arbitration Done Out */ -} - -/* - * Clear SCSI Interrupt 0 - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0. - */ -register CLRSINT0 { - address 0x04B - access_mode WO - modes M_DFF0, M_DFF1, M_SCSI - field CLRSELDO 0x40 - field CLRSELDI 0x20 - field CLRSELINGO 0x10 - field CLRIOERR 0x08 - field CLROVERRUN 0x04 - field CLRSPIORDY 0x02 - field CLRARBDO 0x01 - dont_generate_debug_code -} - -/* - * SCSI Interrupt Mode 0 - * Setting any bit will enable the corresponding function - * in SIMODE0 to interrupt via the IRQ pin. - */ -register SIMODE0 { - address 0x04B - access_mode RW - modes M_CFG - count 8 - field ENSELDO 0x40 - field ENSELDI 0x20 - field ENSELINGO 0x10 - field ENIOERR 0x08 - field ENOVERRUN 0x04 - field ENSPIORDY 0x02 - field ENARBDO 0x01 -} - -/* - * SCSI Status 1 - */ -register SSTAT1 { - address 0x04C - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - field SELTO 0x80 - field ATNTARG 0x40 - field SCSIRSTI 0x20 - field PHASEMIS 0x10 - field BUSFREE 0x08 - field SCSIPERR 0x04 - field STRB2FAST 0x02 - field REQINIT 0x01 -} - -/* - * Clear SCSI Interrupt 1 - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. - */ -register CLRSINT1 { - address 0x04C - access_mode WO - modes M_DFF0, M_DFF1, M_SCSI - field CLRSELTIMEO 0x80 - field CLRATNO 0x40 - field CLRSCSIRSTI 0x20 - field CLRBUSFREE 0x08 - field CLRSCSIPERR 0x04 - field CLRSTRB2FAST 0x02 - field CLRREQINIT 0x01 - dont_generate_debug_code -} - -/* - * SCSI Status 2 - */ -register SSTAT2 { - address 0x04d - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - field BUSFREETIME 0xc0 { - BUSFREE_LQO 0x40, - BUSFREE_DFF0 0x80, - BUSFREE_DFF1 0xC0 - } - field NONPACKREQ 0x20 - field EXP_ACTIVE 0x10 /* SCSI Expander Active */ - field BSYX 0x08 /* Busy Expander */ - field WIDE_RES 0x04 /* Modes 0 and 1 only */ - field SDONE 0x02 /* Modes 0 and 1 only */ - field DMADONE 0x01 /* Modes 0 and 1 only */ -} - -/* - * Clear SCSI Interrupt 2 - */ -register CLRSINT2 { - address 0x04D - access_mode WO - modes M_DFF0, M_DFF1, M_SCSI - field CLRNONPACKREQ 0x20 - field CLRWIDE_RES 0x04 /* Modes 0 and 1 only */ - field CLRSDONE 0x02 /* Modes 0 and 1 only */ - field CLRDMADONE 0x01 /* Modes 0 and 1 only */ - dont_generate_debug_code -} - -/* - * SCSI Interrupt Mode 2 - */ -register SIMODE2 { - address 0x04D - access_mode RW - modes M_CFG - field ENWIDE_RES 0x04 - field ENSDONE 0x02 - field ENDMADONE 0x01 -} - -/* - * Physical Error Diagnosis - */ -register PERRDIAG { - address 0x04E - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - count 3 - field HIZERO 0x80 - field HIPERR 0x40 - field PREVPHASE 0x20 - field PARITYERR 0x10 - field AIPERR 0x08 - field CRCERR 0x04 - field DGFORMERR 0x02 - field DTERR 0x01 -} - -/* - * LQI Manager Current State - */ -register LQISTATE { - address 0x04E - access_mode RO - modes M_CFG - count 6 - dont_generate_debug_code -} - -/* - * SCSI Offset Count - */ -register SOFFCNT { - address 0x04F - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - count 1 -} - -/* - * LQO Manager Current State - */ -register LQOSTATE { - address 0x04F - access_mode RO - modes M_CFG - count 2 - dont_generate_debug_code -} - -/* - * LQI Manager Status - */ -register LQISTAT0 { - address 0x050 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - count 2 - field LQIATNQAS 0x20 - field LQICRCT1 0x10 - field LQICRCT2 0x08 - field LQIBADLQT 0x04 - field LQIATNLQ 0x02 - field LQIATNCMD 0x01 -} - -/* - * Clear LQI Interrupts 0 - */ -register CLRLQIINT0 { - address 0x050 - access_mode WO - modes M_DFF0, M_DFF1, M_SCSI - count 1 - field CLRLQIATNQAS 0x20 - field CLRLQICRCT1 0x10 - field CLRLQICRCT2 0x08 - field CLRLQIBADLQT 0x04 - field CLRLQIATNLQ 0x02 - field CLRLQIATNCMD 0x01 - dont_generate_debug_code -} - -/* - * LQI Manager Interrupt Mode 0 - */ -register LQIMODE0 { - address 0x050 - access_mode RW - modes M_CFG - count 3 - field ENLQIATNQASK 0x20 - field ENLQICRCT1 0x10 - field ENLQICRCT2 0x08 - field ENLQIBADLQT 0x04 - field ENLQIATNLQ 0x02 - field ENLQIATNCMD 0x01 - dont_generate_debug_code -} - -/* - * LQI Manager Status 1 - */ -register LQISTAT1 { - address 0x051 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - count 3 - field LQIPHASE_LQ 0x80 - field LQIPHASE_NLQ 0x40 - field LQIABORT 0x20 - field LQICRCI_LQ 0x10 - field LQICRCI_NLQ 0x08 - field LQIBADLQI 0x04 - field LQIOVERI_LQ 0x02 - field LQIOVERI_NLQ 0x01 -} - -/* - * Clear LQI Manager Interrupts1 - */ -register CLRLQIINT1 { - address 0x051 - access_mode WO - modes M_DFF0, M_DFF1, M_SCSI - count 4 - field CLRLQIPHASE_LQ 0x80 - field CLRLQIPHASE_NLQ 0x40 - field CLRLIQABORT 0x20 - field CLRLQICRCI_LQ 0x10 - field CLRLQICRCI_NLQ 0x08 - field CLRLQIBADLQI 0x04 - field CLRLQIOVERI_LQ 0x02 - field CLRLQIOVERI_NLQ 0x01 - dont_generate_debug_code -} - -/* - * LQI Manager Interrupt Mode 1 - */ -register LQIMODE1 { - address 0x051 - access_mode RW - modes M_CFG - count 4 - field ENLQIPHASE_LQ 0x80 /* LQIPHASE1 */ - field ENLQIPHASE_NLQ 0x40 /* LQIPHASE2 */ - field ENLIQABORT 0x20 - field ENLQICRCI_LQ 0x10 /* LQICRCI1 */ - field ENLQICRCI_NLQ 0x08 /* LQICRCI2 */ - field ENLQIBADLQI 0x04 - field ENLQIOVERI_LQ 0x02 /* LQIOVERI1 */ - field ENLQIOVERI_NLQ 0x01 /* LQIOVERI2 */ - dont_generate_debug_code -} - -/* - * LQI Manager Status 2 - */ -register LQISTAT2 { - address 0x052 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - field PACKETIZED 0x80 - field LQIPHASE_OUTPKT 0x40 - field LQIWORKONLQ 0x20 - field LQIWAITFIFO 0x10 - field LQISTOPPKT 0x08 - field LQISTOPLQ 0x04 - field LQISTOPCMD 0x02 - field LQIGSAVAIL 0x01 -} - -/* - * SCSI Status 3 - */ -register SSTAT3 { - address 0x053 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - count 3 - field NTRAMPERR 0x02 - field OSRAMPERR 0x01 -} - -/* - * Clear SCSI Status 3 - */ -register CLRSINT3 { - address 0x053 - access_mode WO - modes M_DFF0, M_DFF1, M_SCSI - count 3 - field CLRNTRAMPERR 0x02 - field CLROSRAMPERR 0x01 - dont_generate_debug_code -} - -/* - * SCSI Interrupt Mode 3 - */ -register SIMODE3 { - address 0x053 - access_mode RW - modes M_CFG - count 4 - field ENNTRAMPERR 0x02 - field ENOSRAMPERR 0x01 - dont_generate_debug_code -} - -/* - * LQO Manager Status 0 - */ -register LQOSTAT0 { - address 0x054 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - count 2 - field LQOTARGSCBPERR 0x10 - field LQOSTOPT2 0x08 - field LQOATNLQ 0x04 - field LQOATNPKT 0x02 - field LQOTCRC 0x01 -} - -/* - * Clear LQO Manager interrupt 0 - */ -register CLRLQOINT0 { - address 0x054 - access_mode WO - modes M_DFF0, M_DFF1, M_SCSI - count 3 - field CLRLQOTARGSCBPERR 0x10 - field CLRLQOSTOPT2 0x08 - field CLRLQOATNLQ 0x04 - field CLRLQOATNPKT 0x02 - field CLRLQOTCRC 0x01 - dont_generate_debug_code -} - -/* - * LQO Manager Interrupt Mode 0 - */ -register LQOMODE0 { - address 0x054 - access_mode RW - modes M_CFG - count 4 - field ENLQOTARGSCBPERR 0x10 - field ENLQOSTOPT2 0x08 - field ENLQOATNLQ 0x04 - field ENLQOATNPKT 0x02 - field ENLQOTCRC 0x01 - dont_generate_debug_code -} - -/* - * LQO Manager Status 1 - */ -register LQOSTAT1 { - address 0x055 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - field LQOINITSCBPERR 0x10 - field LQOSTOPI2 0x08 - field LQOBADQAS 0x04 - field LQOBUSFREE 0x02 - field LQOPHACHGINPKT 0x01 -} - -/* - * Clear LOQ Interrupt 1 - */ -register CLRLQOINT1 { - address 0x055 - access_mode WO - modes M_DFF0, M_DFF1, M_SCSI - count 7 - field CLRLQOINITSCBPERR 0x10 - field CLRLQOSTOPI2 0x08 - field CLRLQOBADQAS 0x04 - field CLRLQOBUSFREE 0x02 - field CLRLQOPHACHGINPKT 0x01 - dont_generate_debug_code -} - -/* - * LQO Manager Interrupt Mode 1 - */ -register LQOMODE1 { - address 0x055 - access_mode RW - modes M_CFG - count 4 - field ENLQOINITSCBPERR 0x10 - field ENLQOSTOPI2 0x08 - field ENLQOBADQAS 0x04 - field ENLQOBUSFREE 0x02 - field ENLQOPHACHGINPKT 0x01 - dont_generate_debug_code -} - -/* - * LQO Manager Status 2 - */ -register LQOSTAT2 { - address 0x056 - access_mode RO - modes M_DFF0, M_DFF1, M_SCSI - field LQOPKT 0xE0 - field LQOWAITFIFO 0x10 - field LQOPHACHGOUTPKT 0x02 /* outside of packet boundaries. */ - field LQOSTOP0 0x01 /* Stopped after sending all packets */ -} - -/* - * Output Synchronizer Space Count - */ -register OS_SPACE_CNT { - address 0x056 - access_mode RO - modes M_CFG - count 2 - dont_generate_debug_code -} - -/* - * SCSI Interrupt Mode 1 - * Setting any bit will enable the corresponding function - * in SIMODE1 to interrupt via the IRQ pin. - */ -register SIMODE1 { - address 0x057 - access_mode RW - modes M_DFF0, M_DFF1, M_SCSI - field ENSELTIMO 0x80 - field ENATNTARG 0x40 - field ENSCSIRST 0x20 - field ENPHASEMIS 0x10 - field ENBUSFREE 0x08 - field ENSCSIPERR 0x04 - field ENSTRB2FAST 0x02 - field ENREQINIT 0x01 -} - -/* - * Good Status FIFO - */ -register GSFIFO { - address 0x058 - access_mode RO - size 2 - modes M_DFF0, M_DFF1, M_SCSI - dont_generate_debug_code -} - -/* - * Data FIFO SCSI Transfer Control - */ -register DFFSXFRCTL { - address 0x05A - access_mode RW - modes M_DFF0, M_DFF1 - field DFFBITBUCKET 0x08 - field CLRSHCNT 0x04 - field CLRCHN 0x02 - field RSTCHN 0x01 -} - -/* - * Next SCSI Control Block - */ -register NEXTSCB { - address 0x05A - access_mode RW - size 2 - modes M_SCSI - dont_generate_debug_code -} - -/* - * LQO SCSI Control - * (Rev B only.) - */ -register LQOSCSCTL { - address 0x05A - access_mode RW - size 1 - modes M_CFG - count 1 - field LQOH2A_VERSION 0x80 - field LQOBUSETDLY 0x40 - field LQONOHOLDLACK 0x02 - field LQONOCHKOVER 0x01 - dont_generate_debug_code -} - -/* - * SEQ Interrupts - */ -register SEQINTSRC { - address 0x05B - access_mode RO - modes M_DFF0, M_DFF1 - field CTXTDONE 0x40 - field SAVEPTRS 0x20 - field CFG4DATA 0x10 - field CFG4ISTAT 0x08 - field CFG4TSTAT 0x04 - field CFG4ICMD 0x02 - field CFG4TCMD 0x01 -} - -/* - * Clear Arp Interrupts - */ -register CLRSEQINTSRC { - address 0x05B - access_mode WO - modes M_DFF0, M_DFF1 - field CLRCTXTDONE 0x40 - field CLRSAVEPTRS 0x20 - field CLRCFG4DATA 0x10 - field CLRCFG4ISTAT 0x08 - field CLRCFG4TSTAT 0x04 - field CLRCFG4ICMD 0x02 - field CLRCFG4TCMD 0x01 - dont_generate_debug_code -} - -/* - * SEQ Interrupt Enabled (Shared) - */ -register SEQIMODE { - address 0x05C - access_mode RW - modes M_DFF0, M_DFF1 - field ENCTXTDONE 0x40 - field ENSAVEPTRS 0x20 - field ENCFG4DATA 0x10 - field ENCFG4ISTAT 0x08 - field ENCFG4TSTAT 0x04 - field ENCFG4ICMD 0x02 - field ENCFG4TCMD 0x01 -} - -/* - * Current SCSI Control Block - */ -register CURRSCB { - address 0x05C - access_mode RW - size 2 - modes M_SCSI - dont_generate_debug_code -} - -/* - * Data FIFO Status - */ -register MDFFSTAT { - address 0x05D - access_mode RO - modes M_DFF0, M_DFF1 - field SHCNTNEGATIVE 0x40 /* Rev B or higher */ - field SHCNTMINUS1 0x20 /* Rev B or higher */ - field LASTSDONE 0x10 - field SHVALID 0x08 - field DLZERO 0x04 /* FIFO data ends on packet boundary. */ - field DATAINFIFO 0x02 - field FIFOFREE 0x01 -} - -/* - * CRC Control - */ -register CRCCONTROL { - address 0x05d - access_mode RW - modes M_CFG - field CRCVALCHKEN 0x40 -} - -/* - * SCSI Test Control - */ -register SCSITEST { - address 0x05E - access_mode RW - modes M_CFG - field CNTRTEST 0x08 - field SEL_TXPLL_DEBUG 0x04 -} - -/* - * Data FIFO Queue Tag - */ -register DFFTAG { - address 0x05E - access_mode RW - size 2 - modes M_DFF0, M_DFF1 -} - -/* - * Last SCSI Control Block - */ -register LASTSCB { - address 0x05E - access_mode RW - size 2 - modes M_SCSI - dont_generate_debug_code -} - -/* - * SCSI I/O Cell Power-down Control - */ -register IOPDNCTL { - address 0x05F - access_mode RW - modes M_CFG - field DISABLE_OE 0x80 - field PDN_IDIST 0x04 - field PDN_DIFFSENSE 0x01 -} - -/* - * Shadow Host Address. - */ -register SHADDR { - address 0x060 - access_mode RO - size 8 - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * Data Group CRC Interval. - */ -register DGRPCRCI { - address 0x060 - access_mode RW - size 2 - modes M_CFG -} - -/* - * Data Transfer Negotiation Address - */ -register NEGOADDR { - address 0x060 - access_mode RW - modes M_SCSI - dont_generate_debug_code -} - -/* - * Data Transfer Negotiation Data - Period Byte - */ -register NEGPERIOD { - address 0x061 - access_mode RW - modes M_SCSI - count 1 - dont_generate_debug_code -} - -/* - * Packetized CRC Interval - */ -register PACKCRCI { - address 0x062 - access_mode RW - size 2 - modes M_CFG -} - -/* - * Data Transfer Negotiation Data - Offset Byte - */ -register NEGOFFSET { - address 0x062 - access_mode RW - modes M_SCSI - count 1 - dont_generate_debug_code -} - -/* - * Data Transfer Negotiation Data - PPR Options - */ -register NEGPPROPTS { - address 0x063 - access_mode RW - modes M_SCSI - count 1 - field PPROPT_PACE 0x08 - field PPROPT_QAS 0x04 - field PPROPT_DT 0x02 - field PPROPT_IUT 0x01 - dont_generate_debug_code -} - -/* - * Data Transfer Negotiation Data - Connection Options - */ -register NEGCONOPTS { - address 0x064 - access_mode RW - modes M_SCSI - field ENSNAPSHOT 0x40 - field RTI_WRTDIS 0x20 - field RTI_OVRDTRN 0x10 - field ENSLOWCRC 0x08 - field ENAUTOATNI 0x04 - field ENAUTOATNO 0x02 - field WIDEXFER 0x01 - dont_generate_debug_code -} - -/* - * Negotiation Table Annex Column Index. - */ -register ANNEXCOL { - address 0x065 - access_mode RW - modes M_SCSI - count 7 - dont_generate_debug_code -} - -/* - * SCSI Check - * (Rev. B only) - */ -register SCSCHKN { - address 0x066 - access_mode RW - modes M_CFG - count 1 - field BIDICHKDIS 0x80 - field STSELSKIDDIS 0x40 - field CURRFIFODEF 0x20 - field WIDERESEN 0x10 - field SDONEMSKDIS 0x08 - field DFFACTCLR 0x04 - field SHVALIDSTDIS 0x02 - field LSTSGCLRDIS 0x01 - dont_generate_debug_code -} - -const AHD_ANNEXCOL_PER_DEV0 4 -const AHD_NUM_PER_DEV_ANNEXCOLS 4 -const AHD_ANNEXCOL_PRECOMP_SLEW 4 -const AHD_PRECOMP_MASK 0x07 -const AHD_PRECOMP_SHIFT 0 -const AHD_PRECOMP_CUTBACK_17 0x04 -const AHD_PRECOMP_CUTBACK_29 0x06 -const AHD_PRECOMP_CUTBACK_37 0x07 -const AHD_SLEWRATE_MASK 0x78 -const AHD_SLEWRATE_SHIFT 3 -/* - * Rev A has only a single bit (high bit of field) of slew adjustment. - * Rev B has 4 bits. The current default happens to be the same for both. - */ -const AHD_SLEWRATE_DEF_REVA 0x08 -const AHD_SLEWRATE_DEF_REVB 0x08 - -/* Rev A does not have any amplitude setting. */ -const AHD_ANNEXCOL_AMPLITUDE 6 -const AHD_AMPLITUDE_MASK 0x7 -const AHD_AMPLITUDE_SHIFT 0 -const AHD_AMPLITUDE_DEF 0x7 - -/* - * Negotiation Table Annex Data Port. - */ -register ANNEXDAT { - address 0x066 - access_mode RW - modes M_SCSI - count 3 - dont_generate_debug_code -} - -/* - * Initiator's Own Id. - * The SCSI ID to use for Selection Out and seen during a reselection.. - */ -register IOWNID { - address 0x067 - access_mode RW - modes M_SCSI - dont_generate_debug_code -} - -/* - * 960MHz Phase-Locked Loop Control 0 - */ -register PLL960CTL0 { - address 0x068 - access_mode RW - modes M_CFG - field PLL_VCOSEL 0x80 - field PLL_PWDN 0x40 - field PLL_NS 0x30 - field PLL_ENLUD 0x08 - field PLL_ENLPF 0x04 - field PLL_DLPF 0x02 - field PLL_ENFBM 0x01 -} - -/* - * Target Own Id - */ -register TOWNID { - address 0x069 - access_mode RW - modes M_SCSI - count 2 - dont_generate_debug_code -} - -/* - * 960MHz Phase-Locked Loop Control 1 - */ -register PLL960CTL1 { - address 0x069 - access_mode RW - modes M_CFG - field PLL_CNTEN 0x80 - field PLL_CNTCLR 0x40 - field PLL_RST 0x01 -} - -/* - * Expander Signature - */ -register XSIG { - address 0x06A - access_mode RW - modes M_SCSI -} - -/* - * Shadow Byte Count - */ -register SHCNT { - address 0x068 - access_mode RW - size 3 - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * Selection Out ID - */ -register SELOID { - address 0x06B - access_mode RW - modes M_SCSI -} - -/* - * 960-MHz Phase-Locked Loop Test Count - */ -register PLL960CNT0 { - address 0x06A - access_mode RO - size 2 - modes M_CFG -} - -/* - * 400-MHz Phase-Locked Loop Control 0 - */ -register PLL400CTL0 { - address 0x06C - access_mode RW - modes M_CFG - field PLL_VCOSEL 0x80 - field PLL_PWDN 0x40 - field PLL_NS 0x30 - field PLL_ENLUD 0x08 - field PLL_ENLPF 0x04 - field PLL_DLPF 0x02 - field PLL_ENFBM 0x01 -} - -/* - * Arbitration Fairness - */ -register FAIRNESS { - address 0x06C - access_mode RW - size 2 - modes M_SCSI -} - -/* - * 400-MHz Phase-Locked Loop Control 1 - */ -register PLL400CTL1 { - address 0x06D - access_mode RW - modes M_CFG - field PLL_CNTEN 0x80 - field PLL_CNTCLR 0x40 - field PLL_RST 0x01 -} - -/* - * Arbitration Unfairness - */ -register UNFAIRNESS { - address 0x06E - access_mode RW - size 2 - modes M_SCSI -} - -/* - * 400-MHz Phase-Locked Loop Test Count - */ -register PLL400CNT0 { - address 0x06E - access_mode RO - size 2 - modes M_CFG -} - -/* - * SCB Page Pointer - */ -register SCBPTR { - address 0x0A8 - access_mode RW - size 2 - modes M_DFF0, M_DFF1, M_CCHAN, M_SCSI - dont_generate_debug_code -} - -/* - * CMC SCB Array Count - * Number of bytes to transfer between CMC SCB memory and SCBRAM. - * Transfers must be 8byte aligned and sized. - */ -register CCSCBACNT { - address 0x0AB - access_mode RW - modes M_CCHAN -} - -/* - * SCB Autopointer - * SCB-Next Address Snooping logic. When an SCB is transferred to - * the card, the next SCB address to be used by the CMC array can - * be autoloaded from that transfer. - */ -register SCBAUTOPTR { - address 0x0AB - access_mode RW - modes M_CFG - count 1 - field AUSCBPTR_EN 0x80 - field SCBPTR_ADDR 0x38 - field SCBPTR_OFF 0x07 - dont_generate_debug_code -} - -/* - * CMC SG Ram Address Pointer - */ -register CCSGADDR { - address 0x0AC - access_mode RW - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * CMC SCB RAM Address Pointer - */ -register CCSCBADDR { - address 0x0AC - access_mode RW - modes M_CCHAN - dont_generate_debug_code -} - -/* - * CMC SCB Ram Back-up Address Pointer - * Indicates the true stop location of transfers halted prior - * to SCBHCNT going to 0. - */ -register CCSCBADR_BK { - address 0x0AC - access_mode RO - modes M_CFG -} - -/* - * CMC SG Control - */ -register CCSGCTL { - address 0x0AD - access_mode RW - modes M_DFF0, M_DFF1 - field CCSGDONE 0x80 - field SG_CACHE_AVAIL 0x10 - field CCSGENACK 0x08 - mask CCSGEN 0x0C - field SG_FETCH_REQ 0x02 - field CCSGRESET 0x01 -} - -/* - * CMD SCB Control - */ -register CCSCBCTL { - address 0x0AD - access_mode RW - modes M_CCHAN - field CCSCBDONE 0x80 - field ARRDONE 0x40 - field CCARREN 0x10 - field CCSCBEN 0x08 - field CCSCBDIR 0x04 - field CCSCBRESET 0x01 -} - -/* - * CMC Ram BIST - */ -register CMC_RAMBIST { - address 0x0AD - access_mode RW - modes M_CFG - field SG_ELEMENT_SIZE 0x80 - field SCBRAMBIST_FAIL 0x40 - field SG_BIST_FAIL 0x20 - field SG_BIST_EN 0x10 - field CMC_BUFFER_BIST_FAIL 0x02 - field CMC_BUFFER_BIST_EN 0x01 -} - -/* - * CMC SG RAM Data Port - */ -register CCSGRAM { - address 0x0B0 - access_mode RW - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * CMC SCB RAM Data Port - */ -register CCSCBRAM { - address 0x0B0 - access_mode RW - modes M_CCHAN - dont_generate_debug_code -} - -/* - * Flex DMA Address. - */ -register FLEXADR { - address 0x0B0 - access_mode RW - size 3 - modes M_SCSI -} - -/* - * Flex DMA Byte Count - */ -register FLEXCNT { - address 0x0B3 - access_mode RW - size 2 - modes M_SCSI -} - -/* - * Flex DMA Status - */ -register FLEXDMASTAT { - address 0x0B5 - access_mode RW - modes M_SCSI - field FLEXDMAERR 0x02 - field FLEXDMADONE 0x01 -} - -/* - * Flex DMA Data Port - */ -register FLEXDATA { - address 0x0B6 - access_mode RW - modes M_SCSI -} - -/* - * Board Data - */ -register BRDDAT { - address 0x0B8 - access_mode RW - modes M_SCSI - count 2 - dont_generate_debug_code -} - -/* - * Board Control - */ -register BRDCTL { - address 0x0B9 - access_mode RW - modes M_SCSI - count 7 - field FLXARBACK 0x80 - field FLXARBREQ 0x40 - field BRDADDR 0x38 - field BRDEN 0x04 - field BRDRW 0x02 - field BRDSTB 0x01 - dont_generate_debug_code -} - -/* - * Serial EEPROM Address - */ -register SEEADR { - address 0x0BA - access_mode RW - modes M_SCSI - count 4 - dont_generate_debug_code -} - -/* - * Serial EEPROM Data - */ -register SEEDAT { - address 0x0BC - access_mode RW - size 2 - modes M_SCSI - count 4 - dont_generate_debug_code -} - -/* - * Serial EEPROM Status - */ -register SEESTAT { - address 0x0BE - access_mode RO - modes M_SCSI - count 1 - field INIT_DONE 0x80 - field SEEOPCODE 0x70 - field LDALTID_L 0x08 - field SEEARBACK 0x04 - field SEEBUSY 0x02 - field SEESTART 0x01 - dont_generate_debug_code -} - -/* - * Serial EEPROM Control - */ -register SEECTL { - address 0x0BE - access_mode RW - modes M_SCSI - count 4 - field SEEOPCODE 0x70 { - SEEOP_ERASE 0x70, - SEEOP_READ 0x60, - SEEOP_WRITE 0x50, - /* - * The following four commands use special - * addresses for differentiation. - */ - SEEOP_ERAL 0x40 - } - mask SEEOP_EWEN 0x40 - mask SEEOP_WALL 0x40 - mask SEEOP_EWDS 0x40 - field SEERST 0x02 - field SEESTART 0x01 - dont_generate_debug_code -} - -const SEEOP_ERAL_ADDR 0x80 -const SEEOP_EWEN_ADDR 0xC0 -const SEEOP_WRAL_ADDR 0x40 -const SEEOP_EWDS_ADDR 0x00 - -/* - * SCB Counter - */ -register SCBCNT { - address 0x0BF - access_mode RW - modes M_SCSI - dont_generate_debug_code -} - -/* - * Data FIFO Write Address - * Pointer to the next QWD location to be written to the data FIFO. - */ -register DFWADDR { - address 0x0C0 - access_mode RW - size 2 - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * DSP Filter Control - */ -register DSPFLTRCTL { - address 0x0C0 - access_mode RW - modes M_CFG - field FLTRDISABLE 0x20 - field EDGESENSE 0x10 - field DSPFCNTSEL 0x0F -} - -/* - * DSP Data Channel Control - */ -register DSPDATACTL { - address 0x0C1 - access_mode RW - modes M_CFG - count 3 - field BYPASSENAB 0x80 - field DESQDIS 0x10 - field RCVROFFSTDIS 0x04 - field XMITOFFSTDIS 0x02 - dont_generate_debug_code -} - -/* - * Data FIFO Read Address - * Pointer to the next QWD location to be read from the data FIFO. - */ -register DFRADDR { - address 0x0C2 - access_mode RW - size 2 - modes M_DFF0, M_DFF1 -} - -/* - * DSP REQ Control - */ -register DSPREQCTL { - address 0x0C2 - access_mode RW - modes M_CFG - field MANREQCTL 0xC0 - field MANREQDLY 0x3F -} - -/* - * DSP ACK Control - */ -register DSPACKCTL { - address 0x0C3 - access_mode RW - modes M_CFG - field MANACKCTL 0xC0 - field MANACKDLY 0x3F -} - -/* - * Data FIFO Data - * Read/Write byte port into the data FIFO. The read and write - * FIFO pointers increment with each read and write respectively - * to this port. - */ -register DFDAT { - address 0x0C4 - access_mode RW - modes M_DFF0, M_DFF1 - dont_generate_debug_code -} - -/* - * DSP Channel Select - */ -register DSPSELECT { - address 0x0C4 - access_mode RW - modes M_CFG - count 1 - field AUTOINCEN 0x80 - field DSPSEL 0x1F - dont_generate_debug_code -} - -const NUMDSPS 0x14 - -/* - * Write Bias Control - */ -register WRTBIASCTL { - address 0x0C5 - access_mode WO - modes M_CFG - count 3 - field AUTOXBCDIS 0x80 - field XMITMANVAL 0x3F - dont_generate_debug_code -} - -/* - * Currently the WRTBIASCTL is the same as the default. - */ -const WRTBIASCTL_HP_DEFAULT 0x0 - -/* - * Receiver Bias Control - */ -register RCVRBIOSCTL { - address 0x0C6 - access_mode WO - modes M_CFG - field AUTORBCDIS 0x80 - field RCVRMANVAL 0x3F -} - -/* - * Write Bias Calculator - */ -register WRTBIASCALC { - address 0x0C7 - access_mode RO - modes M_CFG -} - -/* - * Data FIFO Pointers - * Contains the byte offset from DFWADDR and DWRADDR to the current - * FIFO write/read locations. - */ -register DFPTRS { - address 0x0C8 - access_mode RW - modes M_DFF0, M_DFF1 -} - -/* - * Receiver Bias Calculator - */ -register RCVRBIASCALC { - address 0x0C8 - access_mode RO - modes M_CFG -} - -/* - * Data FIFO Backup Read Pointer - * Contains the data FIFO address to be restored if the last - * data accessed from the data FIFO was not transferred successfully. - */ -register DFBKPTR { - address 0x0C9 - access_mode RW - size 2 - modes M_DFF0, M_DFF1 -} - -/* - * Skew Calculator - */ -register SKEWCALC { - address 0x0C9 - access_mode RO - modes M_CFG -} - -/* - * Data FIFO Debug Control - */ -register DFDBCTL { - address 0x0CB - access_mode RW - modes M_DFF0, M_DFF1 - field DFF_CIO_WR_RDY 0x20 - field DFF_CIO_RD_RDY 0x10 - field DFF_DIR_ERR 0x08 - field DFF_RAMBIST_FAIL 0x04 - field DFF_RAMBIST_DONE 0x02 - field DFF_RAMBIST_EN 0x01 -} - -/* - * Data FIFO Space Count - * Number of FIFO locations that are free. - */ -register DFSCNT { - address 0x0CC - access_mode RO - size 2 - modes M_DFF0, M_DFF1 -} - -/* - * Data FIFO Byte Count - * Number of filled FIFO locations. - */ -register DFBCNT { - address 0x0CE - access_mode RO - size 2 - modes M_DFF0, M_DFF1 -} - -/* - * Sequencer Program Overlay Address. - * Low address must be written prior to high address. - */ -register OVLYADDR { - address 0x0D4 - modes M_SCSI - size 2 - access_mode RW -} - -/* - * Sequencer Control 0 - * Error detection mode, speed configuration, - * single step, breakpoints and program load. - */ -register SEQCTL0 { - address 0x0D6 - access_mode RW - count 11 - field PERRORDIS 0x80 - field PAUSEDIS 0x40 - field FAILDIS 0x20 - field FASTMODE 0x10 - field BRKADRINTEN 0x08 - field STEP 0x04 - field SEQRESET 0x02 - field LOADRAM 0x01 -} - -/* - * Sequencer Control 1 - * Instruction RAM Diagnostics - */ -register SEQCTL1 { - address 0x0D7 - access_mode RW - field OVRLAY_DATA_CHK 0x08 - field RAMBIST_DONE 0x04 - field RAMBIST_FAIL 0x02 - field RAMBIST_EN 0x01 -} - -/* - * Sequencer Flags - * Zero and Carry state of the ALU. - */ -register FLAGS { - address 0x0D8 - access_mode RO - count 23 - field ZERO 0x02 - field CARRY 0x01 - dont_generate_debug_code -} - -/* - * Sequencer Interrupt Control - */ -register SEQINTCTL { - address 0x0D9 - access_mode RW - field INTVEC1DSL 0x80 - field INT1_CONTEXT 0x20 - field SCS_SEQ_INT1M1 0x10 - field SCS_SEQ_INT1M0 0x08 - field INTMASK2 0x04 - field INTMASK1 0x02 - field IRET 0x01 -} - -/* - * Sequencer RAM Data Port - * Single byte window into the Sequencer Instruction Ram area starting - * at the address specified by OVLYADDR. To write a full instruction word, - * simply write four bytes in succession. OVLYADDR will increment after the - * most significant instrution byte (the byte with the parity bit) is written. - */ -register SEQRAM { - address 0x0DA - access_mode RW - count 2 - dont_generate_debug_code -} - -/* - * Sequencer Program Counter - * Low byte must be written prior to high byte. - */ -register PRGMCNT { - address 0x0DE - access_mode RW - size 2 - count 5 - dont_generate_debug_code -} - -/* - * Accumulator - */ -register ACCUM { - address 0x0E0 - access_mode RW - accumulator - dont_generate_debug_code -} - -/* - * Source Index Register - * Incrementing index for reads of SINDIR and the destination (low byte only) - * for any immediate operands passed in jmp, jc, jnc, call instructions. - * Example: - * mvi 0xFF call some_routine; - * - * Will set SINDEX[0] to 0xFF and call the routine "some_routine. - */ -register SINDEX { - address 0x0E2 - access_mode RW - size 2 - sindex - dont_generate_debug_code -} - -/* - * Destination Index Register - * Incrementing index for writes to DINDIR. Can be used as a scratch register. - */ -register DINDEX { - address 0x0E4 - access_mode RW - size 2 - dont_generate_debug_code -} - -/* - * Break Address - * Sequencer instruction breakpoint address address. - */ -register BRKADDR0 { - address 0x0E6 - access_mode RW -} - -register BRKADDR1 { - address 0x0E6 - access_mode RW - field BRKDIS 0x80 /* Disable Breakpoint */ -} - -/* - * All Ones - * All reads to this register return the value 0xFF. - */ -register ALLONES { - address 0x0E8 - access_mode RO - allones - dont_generate_debug_code -} - -/* - * All Zeros - * All reads to this register return the value 0. - */ -register ALLZEROS { - address 0x0EA - access_mode RO - allzeros - dont_generate_debug_code -} - -/* - * No Destination - * Writes to this register have no effect. - */ -register NONE { - address 0x0EA - access_mode WO - none - dont_generate_debug_code -} - -/* - * Source Index Indirect - * Reading this register is equivalent to reading (register_base + SINDEX) and - * incrementing SINDEX by 1. - */ -register SINDIR { - address 0x0EC - access_mode RO - dont_generate_debug_code -} - -/* - * Destination Index Indirect - * Writing this register is equivalent to writing to (register_base + DINDEX) - * and incrementing DINDEX by 1. - */ -register DINDIR { - address 0x0ED - access_mode WO - dont_generate_debug_code -} - -/* - * Function One - * 2's complement to bit value conversion. Write the 2's complement value - * (0-7 only) to the top nibble and retrieve the bit indexed by that value - * on the next read of this register. - * Example: - * Write 0x60 - * Read 0x40 - */ -register FUNCTION1 { - address 0x0F0 - access_mode RW -} - -/* - * Stack - * Window into the stack. Each stack location is 10 bits wide reported - * low byte followed by high byte. There are 8 stack locations. - */ -register STACK { - address 0x0F2 - access_mode RW - dont_generate_debug_code -} - -/* - * Interrupt Vector 1 Address - * Interrupt branch address for SCS SEQ_INT1 mode 0 and 1 interrupts. - */ -register INTVEC1_ADDR { - address 0x0F4 - access_mode RW - size 2 - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Current Address - * Address of the SEQRAM instruction currently executing instruction. - */ -register CURADDR { - address 0x0F4 - access_mode RW - size 2 - modes M_SCSI - count 2 - dont_generate_debug_code -} - -/* - * Interrupt Vector 2 Address - * Interrupt branch address for HST_SEQ_INT2 interrupts. - */ -register INTVEC2_ADDR { - address 0x0F6 - access_mode RW - size 2 - modes M_CFG - count 1 - dont_generate_debug_code -} - -/* - * Last Address - * Address of the SEQRAM instruction executed prior to the current instruction. - */ -register LASTADDR { - address 0x0F6 - access_mode RW - size 2 - modes M_SCSI -} - -register AHD_PCI_CONFIG_BASE { - address 0x100 - access_mode RW - size 256 - modes M_CFG -} - -/* ---------------------- Scratch RAM Offsets ------------------------- */ -scratch_ram { - /* Mode Specific */ - address 0x0A0 - size 8 - modes 0, 1, 2, 3 - REG0 { - size 2 - dont_generate_debug_code - } - REG1 { - size 2 - } - REG_ISR { - size 2 - dont_generate_debug_code - } - SG_STATE { - size 1 - field SEGS_AVAIL 0x01 - field LOADING_NEEDED 0x02 - field FETCH_INPROG 0x04 - } - /* - * Track whether the transfer byte count for - * the current data phase is odd. - */ - DATA_COUNT_ODD { - size 1 - } -} - -scratch_ram { - /* Mode Specific */ - address 0x0F8 - size 8 - modes 0, 1, 2, 3 - LONGJMP_ADDR { - size 2 - dont_generate_debug_code - } - ACCUM_SAVE { - size 1 - dont_generate_debug_code - } -} - - -scratch_ram { - address 0x100 - size 128 - modes 0, 1, 2, 3 - /* - * Per "other-id" execution queues. We use an array of - * tail pointers into lists of SCBs sorted by "other-id". - * The execution head pointer threads the head SCBs for - * each list. - */ - WAITING_SCB_TAILS { - size 32 - dont_generate_debug_code - } - WAITING_TID_HEAD { - size 2 - dont_generate_debug_code - } - WAITING_TID_TAIL { - size 2 - dont_generate_debug_code - } - /* - * SCBID of the next SCB in the new SCB queue. - */ - NEXT_QUEUED_SCB_ADDR { - size 4 - dont_generate_debug_code - } - /* - * head of list of SCBs that have - * completed but have not been - * put into the qoutfifo. - */ - COMPLETE_SCB_HEAD { - size 2 - dont_generate_debug_code - } - /* - * The list of completed SCBs in - * the active DMA. - */ - COMPLETE_SCB_DMAINPROG_HEAD { - size 2 - dont_generate_debug_code - } - /* - * head of list of SCBs that have - * completed but need to be uploaded - * to the host prior to being completed. - */ - COMPLETE_DMA_SCB_HEAD { - size 2 - dont_generate_debug_code - } - /* - * tail of list of SCBs that have - * completed but need to be uploaded - * to the host prior to being completed. - */ - COMPLETE_DMA_SCB_TAIL { - size 2 - dont_generate_debug_code - } - /* - * head of list of SCBs that have - * been uploaded to the host, but cannot - * be completed until the QFREEZE is in - * full effect (i.e. no selections pending). - */ - COMPLETE_ON_QFREEZE_HEAD { - size 2 - dont_generate_debug_code - } - /* - * Counting semaphore to prevent new select-outs - * The queue is frozen so long as the sequencer - * and kernel freeze counts differ. - */ - QFREEZE_COUNT { - size 2 - } - KERNEL_QFREEZE_COUNT { - size 2 - } - /* - * Mode to restore on legacy idle loop exit. - */ - SAVED_MODE { - size 1 - } - /* - * Single byte buffer used to designate the type or message - * to send to a target. - */ - MSG_OUT { - size 1 - dont_generate_debug_code - } - /* Parameters for DMA Logic */ - DMAPARAMS { - size 1 - count 8 - field PRELOADEN 0x80 - field WIDEODD 0x40 - field SCSIEN 0x20 - field SDMAEN 0x10 - field SDMAENACK 0x10 - field HDMAEN 0x08 - field HDMAENACK 0x08 - field DIRECTION 0x04 /* Set indicates PCI->SCSI */ - field FIFOFLUSH 0x02 - field FIFORESET 0x01 - dont_generate_debug_code - } - SEQ_FLAGS { - size 1 - field NOT_IDENTIFIED 0x80 - field NO_CDB_SENT 0x40 - field TARGET_CMD_IS_TAGGED 0x40 - field DPHASE 0x20 - /* Target flags */ - field TARG_CMD_PENDING 0x10 - field CMDPHASE_PENDING 0x08 - field DPHASE_PENDING 0x04 - field SPHASE_PENDING 0x02 - field NO_DISCONNECT 0x01 - } - /* - * Temporary storage for the - * target/channel/lun of a - * reconnecting target - */ - SAVED_SCSIID { - size 1 - dont_generate_debug_code - } - SAVED_LUN { - size 1 - dont_generate_debug_code - } - /* - * The last bus phase as seen by the sequencer. - */ - LASTPHASE { - size 1 - field CDI 0x80 - field IOI 0x40 - field MSGI 0x20 - field P_BUSFREE 0x01 - enum PHASE_MASK CDO|IOO|MSGO { - P_DATAOUT 0x0, - P_DATAIN IOO, - P_DATAOUT_DT P_DATAOUT|MSGO, - P_DATAIN_DT P_DATAIN|MSGO, - P_COMMAND CDO, - P_MESGOUT CDO|MSGO, - P_STATUS CDO|IOO, - P_MESGIN CDO|IOO|MSGO - } - } - /* - * Value to "or" into the SCBPTR[1] value to - * indicate that an entry in the QINFIFO is valid. - */ - QOUTFIFO_ENTRY_VALID_TAG { - size 1 - dont_generate_debug_code - } - /* - * Kernel and sequencer offsets into the queue of - * incoming target mode command descriptors. The - * queue is full when the KERNEL_TQINPOS == TQINPOS. - */ - KERNEL_TQINPOS { - size 1 - count 1 - dont_generate_debug_code - } - TQINPOS { - size 1 - count 8 - dont_generate_debug_code - } - /* - * Base address of our shared data with the kernel driver in host - * memory. This includes the qoutfifo and target mode - * incoming command queue. - */ - SHARED_DATA_ADDR { - size 4 - dont_generate_debug_code - } - /* - * Pointer to location in host memory for next - * position in the qoutfifo. - */ - QOUTFIFO_NEXT_ADDR { - size 4 - dont_generate_debug_code - } - ARG_1 { - size 1 - mask SEND_MSG 0x80 - mask SEND_SENSE 0x40 - mask SEND_REJ 0x20 - mask MSGOUT_PHASEMIS 0x10 - mask EXIT_MSG_LOOP 0x08 - mask CONT_MSG_LOOP_WRITE 0x04 - mask CONT_MSG_LOOP_READ 0x03 - mask CONT_MSG_LOOP_TARG 0x02 - alias RETURN_1 - dont_generate_debug_code - } - ARG_2 { - size 1 - count 1 - alias RETURN_2 - dont_generate_debug_code - } - - /* - * Snapshot of MSG_OUT taken after each message is sent. - */ - LAST_MSG { - size 1 - dont_generate_debug_code - } - - /* - * Sequences the kernel driver has okayed for us. This allows - * the driver to do things like prevent initiator or target - * operations. - */ - SCSISEQ_TEMPLATE { - size 1 - count 7 - field MANUALCTL 0x40 - field ENSELI 0x20 - field ENRSELI 0x10 - field MANUALP 0x0C - field ENAUTOATNP 0x02 - field ALTSTIM 0x01 - dont_generate_debug_code - } - - /* - * The initiator specified tag for this target mode transaction. - */ - INITIATOR_TAG { - size 1 - count 1 - dont_generate_debug_code - } - - SEQ_FLAGS2 { - size 1 - field PENDING_MK_MESSAGE 0x01 - field TARGET_MSG_PENDING 0x02 - field SELECTOUT_QFROZEN 0x04 - } - - ALLOCFIFO_SCBPTR { - size 2 - dont_generate_debug_code - } - - /* - * The maximum amount of time to wait, when interrupt coalescing - * is enabled, before issuing a CMDCMPLT interrupt for a completed - * command. - */ - INT_COALESCING_TIMER { - size 2 - dont_generate_debug_code - } - - /* - * The maximum number of commands to coalesce into a single interrupt. - * Actually the 2's complement of that value to simplify sequencer - * code. - */ - INT_COALESCING_MAXCMDS { - size 1 - dont_generate_debug_code - } - - /* - * The minimum number of commands still outstanding required - * to continue coalescing (2's complement of value). - */ - INT_COALESCING_MINCMDS { - size 1 - dont_generate_debug_code - } - - /* - * Number of commands "in-flight". - */ - CMDS_PENDING { - size 2 - dont_generate_debug_code - } - - /* - * The count of commands that have been coalesced. - */ - INT_COALESCING_CMDCOUNT { - size 1 - dont_generate_debug_code - } - - /* - * Since the HS_MAIBOX is self clearing, copy its contents to - * this position in scratch ram every time it changes. - */ - LOCAL_HS_MAILBOX { - size 1 - dont_generate_debug_code - } - /* - * Target-mode CDB type to CDB length table used - * in non-packetized operation. - */ - CMDSIZE_TABLE { - size 8 - count 8 - dont_generate_debug_code - } - /* - * When an SCB with the MK_MESSAGE flag is - * queued to the controller, it cannot enter - * the waiting for selection list until the - * selections for any previously queued - * commands to that target complete. During - * the wait, the MK_MESSAGE SCB is queued - * here. - */ - MK_MESSAGE_SCB { - size 2 - } - /* - * Saved SCSIID of MK_MESSAGE_SCB to avoid - * an extra SCBPTR operation when deciding - * if the MK_MESSAGE_SCB can be run. - */ - MK_MESSAGE_SCSIID { - size 1 - } -} - -/************************* Hardware SCB Definition ****************************/ -scb { - address 0x180 - size 64 - modes 0, 1, 2, 3 - SCB_RESIDUAL_DATACNT { - size 4 - alias SCB_CDB_STORE - alias SCB_HOST_CDB_PTR - dont_generate_debug_code - } - SCB_RESIDUAL_SGPTR { - size 4 - field SG_ADDR_MASK 0xf8 /* In the last byte */ - field SG_OVERRUN_RESID 0x02 /* In the first byte */ - field SG_LIST_NULL 0x01 /* In the first byte */ - dont_generate_debug_code - } - SCB_SCSI_STATUS { - size 1 - alias SCB_HOST_CDB_LEN - dont_generate_debug_code - } - SCB_TARGET_PHASES { - size 1 - dont_generate_debug_code - } - SCB_TARGET_DATA_DIR { - size 1 - dont_generate_debug_code - } - SCB_TARGET_ITAG { - size 1 - dont_generate_debug_code - } - SCB_SENSE_BUSADDR { - /* - * Only valid if CDB length is less than 13 bytes or - * we are using a CDB pointer. Otherwise contains - * the last 4 bytes of embedded cdb information. - */ - size 4 - alias SCB_NEXT_COMPLETE - dont_generate_debug_code - } - SCB_TAG { - alias SCB_FIFO_USE_COUNT - size 2 - dont_generate_debug_code - } - SCB_CONTROL { - size 1 - field TARGET_SCB 0x80 - field DISCENB 0x40 - field TAG_ENB 0x20 - field MK_MESSAGE 0x10 - field STATUS_RCVD 0x08 - field DISCONNECTED 0x04 - field SCB_TAG_TYPE 0x03 - } - SCB_SCSIID { - size 1 - field TID 0xF0 - field OID 0x0F - } - SCB_LUN { - size 1 - field LID 0xff - dont_generate_debug_code - } - SCB_TASK_ATTRIBUTE { - size 1 - /* - * Overloaded field for non-packetized - * ignore wide residue message handling. - */ - field SCB_XFERLEN_ODD 0x01 - dont_generate_debug_code - } - SCB_CDB_LEN { - size 1 - field SCB_CDB_LEN_PTR 0x80 /* CDB in host memory */ - dont_generate_debug_code - } - SCB_TASK_MANAGEMENT { - size 1 - dont_generate_debug_code - } - SCB_DATAPTR { - size 8 - dont_generate_debug_code - } - SCB_DATACNT { - /* - * The last byte is really the high address bits for - * the data address. - */ - size 4 - field SG_LAST_SEG 0x80 /* In the fourth byte */ - field SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ - dont_generate_debug_code - } - SCB_SGPTR { - size 4 - field SG_STATUS_VALID 0x04 /* In the first byte */ - field SG_FULL_RESID 0x02 /* In the first byte */ - field SG_LIST_NULL 0x01 /* In the first byte */ - dont_generate_debug_code - } - SCB_BUSADDR { - size 4 - dont_generate_debug_code - } - SCB_NEXT { - alias SCB_NEXT_SCB_BUSADDR - size 2 - dont_generate_debug_code - } - SCB_NEXT2 { - size 2 - dont_generate_debug_code - } - SCB_SPARE { - size 8 - alias SCB_PKT_LUN - } - SCB_DISCONNECTED_LISTS { - size 8 - dont_generate_debug_code - } -} - -/*********************************** Constants ********************************/ -const MK_MESSAGE_BIT_OFFSET 4 -const TID_SHIFT 4 -const TARGET_CMD_CMPLT 0xfe -const INVALID_ADDR 0x80 -#define SCB_LIST_NULL 0xff -#define QOUTFIFO_ENTRY_VALID_TOGGLE 0x80 - -const CCSGADDR_MAX 0x80 -const CCSCBADDR_MAX 0x80 -const CCSGRAM_MAXSEGS 16 - -/* Selection Timeout Timer Constants */ -const STIMESEL_SHIFT 3 -const STIMESEL_MIN 0x18 -const STIMESEL_BUG_ADJ 0x8 - -/* WDTR Message values */ -const BUS_8_BIT 0x00 -const BUS_16_BIT 0x01 -const BUS_32_BIT 0x02 - -/* Offset maximums */ -const MAX_OFFSET 0xfe -const MAX_OFFSET_PACED 0xfe -const MAX_OFFSET_PACED_BUG 0x7f -/* - * Some 160 devices incorrectly accept 0xfe as a - * sync offset, but will overrun this value. Limit - * to 0x7f for speed lower than U320 which will - * avoid the persistent sync offset overruns. - */ -const MAX_OFFSET_NON_PACED 0x7f -const HOST_MSG 0xff - -/* - * The size of our sense buffers. - * Sense buffer mapping can be handled in either of two ways. - * The first is to allocate a dmamap for each transaction. - * Depending on the architecture, dmamaps can be costly. The - * alternative is to statically map the buffers in much the same - * way we handle our scatter gather lists. The driver implements - * the later. - */ -const AHD_SENSE_BUFSIZE 256 - -/* Target mode command processing constants */ -const CMD_GROUP_CODE_SHIFT 0x05 - -const STATUS_BUSY 0x08 -const STATUS_QUEUE_FULL 0x28 -const STATUS_PKT_SENSE 0xFF -const TARGET_DATA_IN 1 - -const SCB_TRANSFER_SIZE_FULL_LUN 56 -const SCB_TRANSFER_SIZE_1BYTE_LUN 48 -/* PKT_OVERRUN_BUFSIZE must be a multiple of 256 less than 64K */ -const PKT_OVERRUN_BUFSIZE 512 - -/* - * Timer parameters. - */ -const AHD_TIMER_US_PER_TICK 25 -const AHD_TIMER_MAX_TICKS 0xFFFF -const AHD_TIMER_MAX_US (AHD_TIMER_MAX_TICKS * AHD_TIMER_US_PER_TICK) - -/* - * Downloaded (kernel inserted) constants - */ -const SG_PREFETCH_CNT download -const SG_PREFETCH_CNT_LIMIT download -const SG_PREFETCH_ALIGN_MASK download -const SG_PREFETCH_ADDR_MASK download -const SG_SIZEOF download -const PKT_OVERRUN_BUFOFFSET download -const SCB_TRANSFER_SIZE download -const CACHELINE_MASK download - -/* - * BIOS SCB offsets - */ -const NVRAM_SCB_OFFSET 0x2C diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.seq b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.seq deleted file mode 100644 index 3a36d936..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx.seq +++ /dev/null @@ -1,2290 +0,0 @@ -/* - * Adaptec U320 device driver firmware for Linux and FreeBSD. - * - * Copyright (c) 1994-2001, 2004 Justin T. Gibbs. - * Copyright (c) 2000-2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $FreeBSD$ - */ - -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $" -PATCH_ARG_LIST = "struct ahd_softc *ahd" -PREFIX = "ahd_" - -#include "aic79xx.reg" -#include "scsi_message.h" - -restart: -if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { - test SEQINTCODE, 0xFF jz idle_loop; - SET_SEQINTCODE(NO_SEQINT) -} - -idle_loop: - - if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { - /* - * Convert ERROR status into a sequencer - * interrupt to handle the case of an - * interrupt collision on the hardware - * setting of HWERR. - */ - test ERROR, 0xFF jz no_error_set; - SET_SEQINTCODE(SAW_HWERR) -no_error_set: - } - SET_MODE(M_SCSI, M_SCSI) - test SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus; - test SEQ_FLAGS2, SELECTOUT_QFROZEN jz check_waiting_list; - /* - * If the kernel has caught up with us, thaw the queue. - */ - mov A, KERNEL_QFREEZE_COUNT; - cmp QFREEZE_COUNT, A jne check_frozen_completions; - mov A, KERNEL_QFREEZE_COUNT[1]; - cmp QFREEZE_COUNT[1], A jne check_frozen_completions; - and SEQ_FLAGS2, ~SELECTOUT_QFROZEN; - jmp check_waiting_list; -check_frozen_completions: - test SSTAT0, SELDO|SELINGO jnz idle_loop_checkbus; -BEGIN_CRITICAL; - /* - * If we have completions stalled waiting for the qfreeze - * to take effect, move them over to the complete_scb list - * now that no selections are pending. - */ - cmp COMPLETE_ON_QFREEZE_HEAD[1],SCB_LIST_NULL je idle_loop_checkbus; - /* - * Find the end of the qfreeze list. The first element has - * to be treated specially. - */ - bmov SCBPTR, COMPLETE_ON_QFREEZE_HEAD, 2; - cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je join_lists; - /* - * Now the normal loop. - */ - bmov SCBPTR, SCB_NEXT_COMPLETE, 2; - cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL jne . - 1; -join_lists: - bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; - bmov COMPLETE_SCB_HEAD, COMPLETE_ON_QFREEZE_HEAD, 2; - mvi COMPLETE_ON_QFREEZE_HEAD[1], SCB_LIST_NULL; - jmp idle_loop_checkbus; -check_waiting_list: - cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je idle_loop_checkbus; - /* - * ENSELO is cleared by a SELDO, so we must test for SELDO - * one last time. - */ - test SSTAT0, SELDO jnz select_out; - call start_selection; -idle_loop_checkbus: - test SSTAT0, SELDO jnz select_out; -END_CRITICAL; - test SSTAT0, SELDI jnz select_in; - test SCSIPHASE, ~DATA_PHASE_MASK jz idle_loop_check_nonpackreq; - test SCSISIGO, ATNO jz idle_loop_check_nonpackreq; - call unexpected_nonpkt_phase_find_ctxt; -idle_loop_check_nonpackreq: - test SSTAT2, NONPACKREQ jz . + 2; - call unexpected_nonpkt_phase_find_ctxt; - if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { - /* - * On Rev A. hardware, the busy LED is only - * turned on automaically during selections - * and re-selections. Make the LED status - * more useful by forcing it to be on so - * long as one of our data FIFOs is active. - */ - and A, FIFO0FREE|FIFO1FREE, DFFSTAT; - cmp A, FIFO0FREE|FIFO1FREE jne . + 3; - and SBLKCTL, ~DIAGLEDEN|DIAGLEDON; - jmp . + 2; - or SBLKCTL, DIAGLEDEN|DIAGLEDON; - } - call idle_loop_gsfifo_in_scsi_mode; - call idle_loop_service_fifos; - call idle_loop_cchan; - jmp idle_loop; - -idle_loop_gsfifo: - SET_MODE(M_SCSI, M_SCSI) -BEGIN_CRITICAL; -idle_loop_gsfifo_in_scsi_mode: - test LQISTAT2, LQIGSAVAIL jz return; - /* - * We have received good status for this transaction. There may - * still be data in our FIFOs draining to the host. Complete - * the SCB only if all data has transferred to the host. - */ -good_status_IU_done: - bmov SCBPTR, GSFIFO, 2; - clr SCB_SCSI_STATUS; - /* - * If a command completed before an attempted task management - * function completed, notify the host after disabling any - * pending select-outs. - */ - test SCB_TASK_MANAGEMENT, 0xFF jz gsfifo_complete_normally; - test SSTAT0, SELDO|SELINGO jnz . + 2; - and SCSISEQ0, ~ENSELO; - SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY) -gsfifo_complete_normally: - or SCB_CONTROL, STATUS_RCVD; - - /* - * Since this status did not consume a FIFO, we have to - * be a bit more dilligent in how we check for FIFOs pertaining - * to this transaction. There are two states that a FIFO still - * transferring data may be in. - * - * 1) Configured and draining to the host, with a FIFO handler. - * 2) Pending cfg4data, fifo not empty. - * - * Case 1 can be detected by noticing a non-zero FIFO active - * count in the SCB. In this case, we allow the routine servicing - * the FIFO to complete the SCB. - * - * Case 2 implies either a pending or yet to occur save data - * pointers for this same context in the other FIFO. So, if - * we detect case 1, we will properly defer the post of the SCB - * and achieve the desired result. The pending cfg4data will - * notice that status has been received and complete the SCB. - */ - test SCB_FIFO_USE_COUNT, 0xFF jnz idle_loop_gsfifo_in_scsi_mode; - call complete; -END_CRITICAL; - jmp idle_loop_gsfifo_in_scsi_mode; - -idle_loop_service_fifos: - SET_MODE(M_DFF0, M_DFF0) -BEGIN_CRITICAL; - test LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo; - call longjmp; -END_CRITICAL; -idle_loop_next_fifo: - SET_MODE(M_DFF1, M_DFF1) -BEGIN_CRITICAL; - test LONGJMP_ADDR[1], INVALID_ADDR jz longjmp; -END_CRITICAL; -return: - ret; - -idle_loop_cchan: - SET_MODE(M_CCHAN, M_CCHAN) - test QOFF_CTLSTA, HS_MAILBOX_ACT jz hs_mailbox_empty; - or QOFF_CTLSTA, HS_MAILBOX_ACT; - mov LOCAL_HS_MAILBOX, HS_MAILBOX; -hs_mailbox_empty: -BEGIN_CRITICAL; - test CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle; - test CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog; - test CCSCBCTL, CCSCBDONE jz return; - /* FALLTHROUGH */ -scbdma_tohost_done: - test CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone; - /* - * An SCB has been successfully uploaded to the host. - * If the SCB was uploaded for some reason other than - * bad SCSI status (currently only for underruns), we - * queue the SCB for normal completion. Otherwise, we - * wait until any select-out activity has halted, and - * then queue the completion. - */ - and CCSCBCTL, ~(CCARREN|CCSCBEN); - bmov COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2; - cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL jne . + 2; - mvi COMPLETE_DMA_SCB_TAIL[1], SCB_LIST_NULL; - test SCB_SCSI_STATUS, 0xff jz scbdma_queue_completion; - bmov SCB_NEXT_COMPLETE, COMPLETE_ON_QFREEZE_HEAD, 2; - bmov COMPLETE_ON_QFREEZE_HEAD, SCBPTR, 2 ret; -scbdma_queue_completion: - bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; - bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret; -fill_qoutfifo_dmadone: - and CCSCBCTL, ~(CCARREN|CCSCBEN); - call qoutfifo_updated; - mvi COMPLETE_SCB_DMAINPROG_HEAD[1], SCB_LIST_NULL; - bmov QOUTFIFO_NEXT_ADDR, SCBHADDR, 4; - test QOFF_CTLSTA, SDSCB_ROLLOVR jz return; - bmov QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4; - xor QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret; -END_CRITICAL; - -qoutfifo_updated: - /* - * If there are more commands waiting to be dma'ed - * to the host, always coalesce. Otherwise honor the - * host's wishes. - */ - cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; - cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; - test LOCAL_HS_MAILBOX, ENINT_COALESCE jz issue_cmdcmplt; - - /* - * If we have relatively few commands outstanding, don't - * bother waiting for another command to complete. - */ - test CMDS_PENDING[1], 0xFF jnz coalesce_by_count; - /* Add -1 so that jnc means <= not just < */ - add A, -1, INT_COALESCING_MINCMDS; - add NONE, A, CMDS_PENDING; - jnc issue_cmdcmplt; - - /* - * If coalescing, only coalesce up to the limit - * provided by the host driver. - */ -coalesce_by_count: - mov A, INT_COALESCING_MAXCMDS; - add NONE, A, INT_COALESCING_CMDCOUNT; - jc issue_cmdcmplt; - /* - * If the timer is not currently active, - * fire it up. - */ - test INTCTL, SWTMINTMASK jz return; - bmov SWTIMER, INT_COALESCING_TIMER, 2; - mvi CLRSEQINTSTAT, CLRSEQ_SWTMRTO; - or INTCTL, SWTMINTEN|SWTIMER_START; - and INTCTL, ~SWTMINTMASK ret; - -issue_cmdcmplt: - mvi INTSTAT, CMDCMPLT; - clr INT_COALESCING_CMDCOUNT; - or INTCTL, SWTMINTMASK ret; - -BEGIN_CRITICAL; -fetch_new_scb_inprog: - test CCSCBCTL, ARRDONE jz return; -fetch_new_scb_done: - and CCSCBCTL, ~(CCARREN|CCSCBEN); - clr A; - add CMDS_PENDING, 1; - adc CMDS_PENDING[1], A; - if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { - /* - * "Short Luns" are not placed into outgoing LQ - * packets in the correct byte order. Use a full - * sized lun field instead and fill it with the - * one byte of lun information we support. - */ - mov SCB_PKT_LUN[6], SCB_LUN; - } - /* - * The FIFO use count field is shared with the - * tag set by the host so that our SCB dma engine - * knows the correct location to store the SCB. - * Set it to zero before processing the SCB. - */ - clr SCB_FIFO_USE_COUNT; - /* Update the next SCB address to download. */ - bmov NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4; - /* - * NULL out the SCB links since these fields - * occupy the same location as SCB_NEXT_SCB_BUSADDR. - */ - mvi SCB_NEXT[1], SCB_LIST_NULL; - mvi SCB_NEXT2[1], SCB_LIST_NULL; - /* Increment our position in the QINFIFO. */ - mov NONE, SNSCB_QOFF; - - /* - * Save SCBID of this SCB in REG0 since - * SCBPTR will be clobbered during target - * list updates. We also record the SCB's - * flags so that we can refer to them even - * after SCBPTR has been changed. - */ - bmov REG0, SCBPTR, 2; - mov A, SCB_CONTROL; - - /* - * Find the tail SCB of the execution queue - * for this target. - */ - shr SINDEX, 3, SCB_SCSIID; - and SINDEX, ~0x1; - mvi SINDEX[1], (WAITING_SCB_TAILS >> 8); - bmov DINDEX, SINDEX, 2; - bmov SCBPTR, SINDIR, 2; - - /* - * Update the tail to point to the new SCB. - */ - bmov DINDIR, REG0, 2; - - /* - * If the queue was empty, queue this SCB as - * the first for this target. - */ - cmp SCBPTR[1], SCB_LIST_NULL je first_new_target_scb; - - /* - * SCBs that want to send messages must always be - * at the head of their per-target queue so that - * ATN can be asserted even if the current - * negotiation agreement is packetized. If the - * target queue is empty, the SCB can be queued - * immediately. If the queue is not empty, we must - * wait for it to empty before entering this SCB - * into the waiting for selection queue. Otherwise - * our batching and round-robin selection scheme - * could allow commands to be queued out of order. - * To simplify the implementation, we stop pulling - * new commands from the host until the MK_MESSAGE - * SCB can be queued to the waiting for selection - * list. - */ - test A, MK_MESSAGE jz batch_scb; - - /* - * If the last SCB is also a MK_MESSAGE SCB, then - * order is preserved even if we batch. - */ - test SCB_CONTROL, MK_MESSAGE jz batch_scb; - - /* - * Defer this SCB and stop fetching new SCBs until - * it can be queued. Since the SCB_SCSIID of the - * tail SCB must be the same as that of the newly - * queued SCB, there is no need to restore the SCBID - * here. - */ - or SEQ_FLAGS2, PENDING_MK_MESSAGE; - bmov MK_MESSAGE_SCB, REG0, 2; - mov MK_MESSAGE_SCSIID, SCB_SCSIID ret; - -batch_scb: - /* - * Otherwise just update the previous tail SCB to - * point to the new tail. - */ - bmov SCB_NEXT, REG0, 2 ret; - -first_new_target_scb: - /* - * Append SCB to the tail of the waiting for - * selection list. - */ - cmp WAITING_TID_HEAD[1], SCB_LIST_NULL je first_new_scb; - bmov SCBPTR, WAITING_TID_TAIL, 2; - bmov SCB_NEXT2, REG0, 2; - bmov WAITING_TID_TAIL, REG0, 2 ret; -first_new_scb: - /* - * Whole list is empty, so the head of - * the list must be initialized too. - */ - bmov WAITING_TID_HEAD, REG0, 2; - bmov WAITING_TID_TAIL, REG0, 2 ret; -END_CRITICAL; - -scbdma_idle: - /* - * Don't bother downloading new SCBs to execute - * if select-outs are currently frozen or we have - * a MK_MESSAGE SCB waiting to enter the queue. - */ - test SEQ_FLAGS2, SELECTOUT_QFROZEN|PENDING_MK_MESSAGE - jnz scbdma_no_new_scbs; -BEGIN_CRITICAL; - test QOFF_CTLSTA, NEW_SCB_AVAIL jnz fetch_new_scb; -scbdma_no_new_scbs: - cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne dma_complete_scb; - cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL je return; - /* FALLTHROUGH */ -fill_qoutfifo: - /* - * Keep track of the SCBs we are dmaing just - * in case the DMA fails or is aborted. - */ - bmov COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2; - mvi CCSCBCTL, CCSCBRESET; - bmov SCBHADDR, QOUTFIFO_NEXT_ADDR, 4; - mov A, QOUTFIFO_NEXT_ADDR; - bmov SCBPTR, COMPLETE_SCB_HEAD, 2; -fill_qoutfifo_loop: - bmov CCSCBRAM, SCBPTR, 2; - mov CCSCBRAM, SCB_SGPTR[0]; - mov CCSCBRAM, QOUTFIFO_ENTRY_VALID_TAG; - mov NONE, SDSCB_QOFF; - inc INT_COALESCING_CMDCOUNT; - add CMDS_PENDING, -1; - adc CMDS_PENDING[1], -1; - cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done; - cmp CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done; - test QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done; - /* - * Don't cross an ADB or Cachline boundary when DMA'ing - * completion entries. In PCI mode, at least in 32/33 - * configurations, the SCB DMA engine may lose its place - * in the data-stream should the target force a retry on - * something other than an 8byte aligned boundary. In - * PCI-X mode, we do this to avoid split transactions since - * many chipsets seem to be unable to format proper split - * completions to continue the data transfer. - */ - add SINDEX, A, CCSCBADDR; - test SINDEX, CACHELINE_MASK jz fill_qoutfifo_done; - bmov SCBPTR, SCB_NEXT_COMPLETE, 2; - jmp fill_qoutfifo_loop; -fill_qoutfifo_done: - mov SCBHCNT, CCSCBADDR; - mvi CCSCBCTL, CCSCBEN|CCSCBRESET; - bmov COMPLETE_SCB_HEAD, SCB_NEXT_COMPLETE, 2; - mvi SCB_NEXT_COMPLETE[1], SCB_LIST_NULL ret; - -fetch_new_scb: - bmov SCBHADDR, NEXT_QUEUED_SCB_ADDR, 4; - mvi CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET jmp dma_scb; -dma_complete_scb: - bmov SCBPTR, COMPLETE_DMA_SCB_HEAD, 2; - bmov SCBHADDR, SCB_BUSADDR, 4; - mvi CCARREN|CCSCBEN|CCSCBRESET jmp dma_scb; - -/* - * Either post or fetch an SCB from host memory. The caller - * is responsible for polling for transfer completion. - * - * Prerequisits: Mode == M_CCHAN - * SINDEX contains CCSCBCTL flags - * SCBHADDR set to Host SCB address - * SCBPTR set to SCB src location on "push" operations - */ -SET_SRC_MODE M_CCHAN; -SET_DST_MODE M_CCHAN; -dma_scb: - mvi SCBHCNT, SCB_TRANSFER_SIZE; - mov CCSCBCTL, SINDEX ret; - -setjmp: - /* - * At least on the A, a return in the same - * instruction as the bmov results in a return - * to the caller, not to the new address at the - * top of the stack. Since we want the latter - * (we use setjmp to register a handler from an - * interrupt context but not invoke that handler - * until we return to our idle loop), use a - * separate ret instruction. - */ - bmov LONGJMP_ADDR, STACK, 2; - ret; -setjmp_inline: - bmov LONGJMP_ADDR, STACK, 2; -longjmp: - bmov STACK, LONGJMP_ADDR, 2 ret; -END_CRITICAL; - -/*************************** Chip Bug Work Arounds ****************************/ -/* - * Must disable interrupts when setting the mode pointer - * register as an interrupt occurring mid update will - * fail to store the new mode value for restoration on - * an iret. - */ -if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { -set_mode_work_around: - mvi SEQINTCTL, INTVEC1DSL; - mov MODE_PTR, SINDEX; - clr SEQINTCTL ret; -} - - -if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { -set_seqint_work_around: - mov SEQINTCODE, SINDEX; - mvi SEQINTCODE, NO_SEQINT ret; -} - -/************************ Packetized LongJmp Routines *************************/ -SET_SRC_MODE M_SCSI; -SET_DST_MODE M_SCSI; -start_selection: -BEGIN_CRITICAL; - if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { - /* - * Razor #494 - * Rev A hardware fails to update LAST/CURR/NEXTSCB - * correctly after a packetized selection in several - * situations: - * - * 1) If only one command existed in the queue, the - * LAST/CURR/NEXTSCB are unchanged. - * - * 2) In a non QAS, protocol allowed phase change, - * the queue is shifted 1 too far. LASTSCB is - * the last SCB that was correctly processed. - * - * 3) In the QAS case, if the full list of commands - * was successfully sent, NEXTSCB is NULL and neither - * CURRSCB nor LASTSCB can be trusted. We must - * manually walk the list counting MAXCMDCNT elements - * to find the last SCB that was sent correctly. - * - * To simplify the workaround for this bug in SELDO - * handling, we initialize LASTSCB prior to enabling - * selection so we can rely on it even for case #1 above. - */ - bmov LASTSCB, WAITING_TID_HEAD, 2; - } - bmov CURRSCB, WAITING_TID_HEAD, 2; - bmov SCBPTR, WAITING_TID_HEAD, 2; - shr SELOID, 4, SCB_SCSIID; - /* - * If we want to send a message to the device, ensure - * we are selecting with atn regardless of our packetized - * agreement. Since SPI4 only allows target reset or PPR - * messages if this is a packetized connection, the change - * to our negotiation table entry for this selection will - * be cleared when the message is acted on. - */ - test SCB_CONTROL, MK_MESSAGE jz . + 3; - mov NEGOADDR, SELOID; - or NEGCONOPTS, ENAUTOATNO; - or SCSISEQ0, ENSELO ret; -END_CRITICAL; - -/* - * Allocate a FIFO for a non-packetized transaction. - * In RevA hardware, both FIFOs must be free before we - * can allocate a FIFO for a non-packetized transaction. - */ -allocate_fifo_loop: - /* - * Do whatever work is required to free a FIFO. - */ - call idle_loop_service_fifos; - SET_MODE(M_SCSI, M_SCSI) -allocate_fifo: - if ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0) { - and A, FIFO0FREE|FIFO1FREE, DFFSTAT; - cmp A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop; - } else { - test DFFSTAT, FIFO1FREE jnz allocate_fifo1; - test DFFSTAT, FIFO0FREE jz allocate_fifo_loop; - mvi DFFSTAT, B_CURRFIFO_0; - SET_MODE(M_DFF0, M_DFF0) - bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret; - } -SET_SRC_MODE M_SCSI; -SET_DST_MODE M_SCSI; -allocate_fifo1: - mvi DFFSTAT, CURRFIFO_1; - SET_MODE(M_DFF1, M_DFF1) - bmov SCBPTR, ALLOCFIFO_SCBPTR, 2 ret; - -/* - * We have been reselected as an initiator - * or selected as a target. - */ -SET_SRC_MODE M_SCSI; -SET_DST_MODE M_SCSI; -select_in: - if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { - /* - * On Rev A. hardware, the busy LED is only - * turned on automaically during selections - * and re-selections. Make the LED status - * more useful by forcing it to be on from - * the point of selection until our idle - * loop determines that neither of our FIFOs - * are busy. This handles the non-packetized - * case nicely as we will not return to the - * idle loop until the busfree at the end of - * each transaction. - */ - or SBLKCTL, DIAGLEDEN|DIAGLEDON; - } - if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { - /* - * Test to ensure that the bus has not - * already gone free prior to clearing - * any stale busfree status. This avoids - * a window whereby a busfree just after - * a selection could be missed. - */ - test SCSISIGI, BSYI jz . + 2; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; - } - or SXFRCTL0, SPIOEN; - and SAVED_SCSIID, SELID_MASK, SELID; - and A, OID, IOWNID; - or SAVED_SCSIID, A; - mvi CLRSINT0, CLRSELDI; - jmp ITloop; - -/* - * We have successfully selected out. - * - * Clear SELDO. - * Dequeue all SCBs sent from the waiting queue - * Requeue all SCBs *not* sent to the tail of the waiting queue - * Take Razor #494 into account for above. - * - * In Packetized Mode: - * Return to the idle loop. Our interrupt handler will take - * care of any incoming L_Qs. - * - * In Non-Packetize Mode: - * Continue to our normal state machine. - */ -SET_SRC_MODE M_SCSI; -SET_DST_MODE M_SCSI; -select_out: -BEGIN_CRITICAL; - if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) { - /* - * On Rev A. hardware, the busy LED is only - * turned on automaically during selections - * and re-selections. Make the LED status - * more useful by forcing it to be on from - * the point of re-selection until our idle - * loop determines that neither of our FIFOs - * are busy. This handles the non-packetized - * case nicely as we will not return to the - * idle loop until the busfree at the end of - * each transaction. - */ - or SBLKCTL, DIAGLEDEN|DIAGLEDON; - } - /* Clear out all SCBs that have been successfully sent. */ - if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) { - /* - * For packetized, the LQO manager clears ENSELO on - * the assertion of SELDO. If we are non-packetized, - * LASTSCB and CURRSCB are accurate. - */ - test SCSISEQ0, ENSELO jnz use_lastscb; - - /* - * The update is correct for LQOSTAT1 errors. All - * but LQOBUSFREE are handled by kernel interrupts. - * If we see LQOBUSFREE, return to the idle loop. - * Once we are out of the select_out critical section, - * the kernel will cleanup the LQOBUSFREE and we will - * eventually restart the selection if appropriate. - */ - test LQOSTAT1, LQOBUSFREE jnz idle_loop; - - /* - * On a phase change oustside of packet boundaries, - * LASTSCB points to the currently active SCB context - * on the bus. - */ - test LQOSTAT2, LQOPHACHGOUTPKT jnz use_lastscb; - - /* - * If the hardware has traversed the whole list, NEXTSCB - * will be NULL, CURRSCB and LASTSCB cannot be trusted, - * but MAXCMDCNT is accurate. If we stop part way through - * the list or only had one command to issue, NEXTSCB[1] is - * not NULL and LASTSCB is the last command to go out. - */ - cmp NEXTSCB[1], SCB_LIST_NULL jne use_lastscb; - - /* - * Brute force walk. - */ - bmov SCBPTR, WAITING_TID_HEAD, 2; - mvi SEQINTCTL, INTVEC1DSL; - mvi MODE_PTR, MK_MODE(M_CFG, M_CFG); - mov A, MAXCMDCNT; - mvi MODE_PTR, MK_MODE(M_SCSI, M_SCSI); - clr SEQINTCTL; -find_lastscb_loop: - dec A; - test A, 0xFF jz found_last_sent_scb; - bmov SCBPTR, SCB_NEXT, 2; - jmp find_lastscb_loop; -use_lastscb: - bmov SCBPTR, LASTSCB, 2; -found_last_sent_scb: - bmov CURRSCB, SCBPTR, 2; -curscb_ww_done: - } else { - bmov SCBPTR, CURRSCB, 2; - } - - /* - * The whole list made it. Clear our tail pointer to indicate - * that the per-target selection queue is now empty. - */ - cmp SCB_NEXT[1], SCB_LIST_NULL je select_out_clear_tail; - - /* - * Requeue any SCBs not sent, to the tail of the waiting Q. - * We know that neither the per-TID list nor the list of - * TIDs is empty. Use this knowledge to our advantage and - * queue the remainder to the tail of the global execution - * queue. - */ - bmov REG0, SCB_NEXT, 2; -select_out_queue_remainder: - bmov SCBPTR, WAITING_TID_TAIL, 2; - bmov SCB_NEXT2, REG0, 2; - bmov WAITING_TID_TAIL, REG0, 2; - jmp select_out_inc_tid_q; - -select_out_clear_tail: - /* - * Queue any pending MK_MESSAGE SCB for this target now - * that the queue is empty. - */ - test SEQ_FLAGS2, PENDING_MK_MESSAGE jz select_out_no_mk_message_scb; - mov A, MK_MESSAGE_SCSIID; - cmp SCB_SCSIID, A jne select_out_no_mk_message_scb; - and SEQ_FLAGS2, ~PENDING_MK_MESSAGE; - bmov REG0, MK_MESSAGE_SCB, 2; - jmp select_out_queue_remainder; - -select_out_no_mk_message_scb: - /* - * Clear this target's execution tail and increment the queue. - */ - shr DINDEX, 3, SCB_SCSIID; - or DINDEX, 1; /* Want only the second byte */ - mvi DINDEX[1], ((WAITING_SCB_TAILS) >> 8); - mvi DINDIR, SCB_LIST_NULL; -select_out_inc_tid_q: - bmov SCBPTR, WAITING_TID_HEAD, 2; - bmov WAITING_TID_HEAD, SCB_NEXT2, 2; - cmp WAITING_TID_HEAD[1], SCB_LIST_NULL jne . + 2; - mvi WAITING_TID_TAIL[1], SCB_LIST_NULL; - bmov SCBPTR, CURRSCB, 2; - mvi CLRSINT0, CLRSELDO; - test LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_mode_cleared; - test LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_mode_cleared; - - /* - * If this is a packetized connection, return to our - * idle_loop and let our interrupt handler deal with - * any connection setup/teardown issues. The only - * exceptions are the case of MK_MESSAGE and task management - * SCBs. - */ - if ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0) { - /* - * In the A, the LQO manager transitions to LQOSTOP0 even if - * we have selected out with ATN asserted and the target - * REQs in a non-packet phase. - */ - test SCB_CONTROL, MK_MESSAGE jz select_out_no_message; - test SCSISIGO, ATNO jnz select_out_non_packetized; -select_out_no_message: - } - test LQOSTAT2, LQOSTOP0 jz select_out_non_packetized; - test SCB_TASK_MANAGEMENT, 0xFF jz idle_loop; - SET_SEQINTCODE(TASKMGMT_FUNC_COMPLETE) - jmp idle_loop; - -select_out_non_packetized: - /* Non packetized request. */ - and SCSISEQ0, ~ENSELO; - if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { - /* - * Test to ensure that the bus has not - * already gone free prior to clearing - * any stale busfree status. This avoids - * a window whereby a busfree just after - * a selection could be missed. - */ - test SCSISIGI, BSYI jz . + 2; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; - } - mov SAVED_SCSIID, SCB_SCSIID; - mov SAVED_LUN, SCB_LUN; - mvi SEQ_FLAGS, NO_CDB_SENT; -END_CRITICAL; - or SXFRCTL0, SPIOEN; - - /* - * As soon as we get a successful selection, the target - * should go into the message out phase since we have ATN - * asserted. - */ - mvi MSG_OUT, MSG_IDENTIFYFLAG; - - /* - * Main loop for information transfer phases. Wait for the - * target to assert REQ before checking MSG, C/D and I/O for - * the bus phase. - */ -mesgin_phasemis: -ITloop: - call phase_lock; - - mov A, LASTPHASE; - - test A, ~P_DATAIN_DT jz p_data; - cmp A,P_COMMAND je p_command; - cmp A,P_MESGOUT je p_mesgout; - cmp A,P_STATUS je p_status; - cmp A,P_MESGIN je p_mesgin; - - SET_SEQINTCODE(BAD_PHASE) - jmp ITloop; /* Try reading the bus again. */ - -/* - * Command phase. Set up the DMA registers and let 'er rip. - */ -p_command: - test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay; - SET_SEQINTCODE(PROTO_VIOLATION) -p_command_okay: - test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) - jnz p_command_allocate_fifo; - /* - * Command retry. Free our current FIFO and - * re-allocate a FIFO so transfer state is - * reset. - */ -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; - mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; - SET_MODE(M_SCSI, M_SCSI) -p_command_allocate_fifo: - bmov ALLOCFIFO_SCBPTR, SCBPTR, 2; - call allocate_fifo; -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; - add NONE, -17, SCB_CDB_LEN; - jnc p_command_embedded; -p_command_from_host: - bmov HADDR[0], SCB_HOST_CDB_PTR, 9; - mvi SG_CACHE_PRE, LAST_SEG; - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); - jmp p_command_xfer; -p_command_embedded: - bmov SHCNT[0], SCB_CDB_LEN, 1; - bmov DFDAT, SCB_CDB_STORE, 16; - mvi DFCNTRL, SCSIEN; -p_command_xfer: - and SEQ_FLAGS, ~NO_CDB_SENT; - if ((ahd->features & AHD_FAST_CDB_DELIVERY) != 0) { - /* - * To speed up CDB delivery in Rev B, all CDB acks - * are "released" to the output sync as soon as the - * command phase starts. There is only one problem - * with this approach. If the target changes phase - * before all data are sent, we have left over acks - * that can go out on the bus in a data phase. Due - * to other chip contraints, this only happens if - * the target goes to data-in, but if the acks go - * out before we can test SDONE, we'll think that - * the transfer has completed successfully. Work - * around this by taking advantage of the 400ns or - * 800ns dead time between command phase and the REQ - * of the new phase. If the transfer has completed - * successfully, SCSIEN should fall *long* before we - * see a phase change. We thus treat any phasemiss - * that occurs before SCSIEN falls as an incomplete - * transfer. - */ - test SSTAT1, PHASEMIS jnz p_command_xfer_failed; - test DFCNTRL, SCSIEN jnz . - 1; - } else { - test DFCNTRL, SCSIEN jnz .; - } - /* - * DMA Channel automatically disabled. - * Don't allow a data phase if the command - * was not fully transferred. - */ - test SSTAT2, SDONE jnz ITloop; -p_command_xfer_failed: - or SEQ_FLAGS, NO_CDB_SENT; - jmp ITloop; - - -/* - * Status phase. Wait for the data byte to appear, then read it - * and store it into the SCB. - */ -SET_SRC_MODE M_SCSI; -SET_DST_MODE M_SCSI; -p_status: - test SEQ_FLAGS,NOT_IDENTIFIED jnz mesgin_proto_violation; -p_status_okay: - mov SCB_SCSI_STATUS, SCSIDAT; - or SCB_CONTROL, STATUS_RCVD; - jmp ITloop; - -/* - * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full - * indentify message sequence and send it to the target. The host may - * override this behavior by setting the MK_MESSAGE bit in the SCB - * control byte. This will cause us to interrupt the host and allow - * it to handle the message phase completely on its own. If the bit - * associated with this target is set, we will also interrupt the host, - * thereby allowing it to send a message on the next selection regardless - * of the transaction being sent. - * - * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. - * This is done to allow the host to send messages outside of an identify - * sequence while protecting the seqencer from testing the MK_MESSAGE bit - * on an SCB that might not be for the current nexus. (For example, a - * BDR message in response to a bad reselection would leave us pointed to - * an SCB that doesn't have anything to do with the current target). - * - * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, - * bus device reset). - * - * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, - * in case the target decides to put us in this phase for some strange - * reason. - */ -p_mesgout_retry: - /* Turn on ATN for the retry */ - mvi SCSISIGO, ATNO; -p_mesgout: - mov SINDEX, MSG_OUT; - cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; - test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; -p_mesgout_identify: - or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; - test SCB_CONTROL, DISCENB jnz . + 2; - and SINDEX, ~DISCENB; -/* - * Send a tag message if TAG_ENB is set in the SCB control block. - * Use SCB_NONPACKET_TAG as the tag value. - */ -p_mesgout_tag: - test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; - mov SCSIDAT, SINDEX; /* Send the identify message */ - call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - and SCSIDAT,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; - call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - mov SCBPTR jmp p_mesgout_onebyte; -/* - * Interrupt the driver, and allow it to handle this message - * phase and any required retries. - */ -p_mesgout_from_host: - cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; - jmp host_message_loop; - -p_mesgout_onebyte: - mvi CLRSINT1, CLRATNO; - mov SCSIDAT, SINDEX; - -/* - * If the next bus phase after ATN drops is message out, it means - * that the target is requesting that the last message(s) be resent. - */ - call phase_lock; - cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; - -p_mesgout_done: - mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ - mov LAST_MSG, MSG_OUT; - mvi MSG_OUT, MSG_NOOP; /* No message left */ - jmp ITloop; - -/* - * Message in phase. Bytes are read using Automatic PIO mode. - */ -p_mesgin: - /* read the 1st message byte */ - mvi ACCUM call inb_first; - - test A,MSG_IDENTIFYFLAG jnz mesgin_identify; - cmp A,MSG_DISCONNECT je mesgin_disconnect; - cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; - cmp ALLZEROS,A je mesgin_complete; - cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; - cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; - cmp A,MSG_NOOP je mesgin_done; - -/* - * Pushed message loop to allow the kernel to - * run it's own message state engine. To avoid an - * extra nop instruction after signaling the kernel, - * we perform the phase_lock before checking to see - * if we should exit the loop and skip the phase_lock - * in the ITloop. Performing back to back phase_locks - * shouldn't hurt, but why do it twice... - */ -host_message_loop: - call phase_lock; /* Benign the first time through. */ - SET_SEQINTCODE(HOST_MSG_LOOP) - cmp RETURN_1, EXIT_MSG_LOOP je ITloop; - cmp RETURN_1, CONT_MSG_LOOP_WRITE jne . + 3; - mov SCSIDAT, RETURN_2; - jmp host_message_loop; - /* Must be CONT_MSG_LOOP_READ */ - mov NONE, SCSIDAT; /* ACK Byte */ - jmp host_message_loop; - -mesgin_ign_wide_residue: - mov SAVED_MODE, MODE_PTR; - SET_MODE(M_SCSI, M_SCSI) - shr NEGOADDR, 4, SAVED_SCSIID; - mov A, NEGCONOPTS; - RESTORE_MODE(SAVED_MODE) - test A, WIDEXFER jz mesgin_reject; - /* Pull the residue byte */ - mvi REG0 call inb_next; - cmp REG0, 0x01 jne mesgin_reject; - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; - test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jnz mesgin_done; - SET_SEQINTCODE(IGN_WIDE_RES) - jmp mesgin_done; - -mesgin_proto_violation: - SET_SEQINTCODE(PROTO_VIOLATION) - jmp mesgin_done; -mesgin_reject: - mvi MSG_MESSAGE_REJECT call mk_mesg; -mesgin_done: - mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ - jmp ITloop; - -#define INDEX_DISC_LIST(scsiid, lun) \ - and A, 0xC0, scsiid; \ - or SCBPTR, A, lun; \ - clr SCBPTR[1]; \ - and SINDEX, 0x30, scsiid; \ - shr SINDEX, 3; /* Multiply by 2 */ \ - add SINDEX, (SCB_DISCONNECTED_LISTS & 0xFF); \ - mvi SINDEX[1], ((SCB_DISCONNECTED_LISTS >> 8) & 0xFF) - -mesgin_identify: - /* - * Determine whether a target is using tagged or non-tagged - * transactions by first looking at the transaction stored in - * the per-device, disconnected array. If there is no untagged - * transaction for this target, this must be a tagged transaction. - */ - and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; - INDEX_DISC_LIST(SAVED_SCSIID, SAVED_LUN); - bmov DINDEX, SINDEX, 2; - bmov REG0, SINDIR, 2; - cmp REG0[1], SCB_LIST_NULL je snoop_tag; - /* Untagged. Clear the busy table entry and setup the SCB. */ - bmov DINDIR, ALLONES, 2; - bmov SCBPTR, REG0, 2; - jmp setup_SCB; - -/* - * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. - * If we get one, we use the tag returned to find the proper - * SCB. After receiving the tag, look for the SCB at SCB locations tag and - * tag + 256. - */ -snoop_tag: - if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x80; - } - mov NONE, SCSIDAT; /* ACK Identify MSG */ - call phase_lock; - if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x1; - } - cmp LASTPHASE, P_MESGIN jne not_found_ITloop; - if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x2; - } - cmp SCSIBUS, MSG_SIMPLE_Q_TAG jne not_found; -get_tag: - clr SCBPTR[1]; - mvi SCBPTR call inb_next; /* tag value */ -verify_scb: - test SCB_CONTROL,DISCONNECTED jz verify_other_scb; - mov A, SAVED_SCSIID; - cmp SCB_SCSIID, A jne verify_other_scb; - mov A, SAVED_LUN; - cmp SCB_LUN, A je setup_SCB_disconnected; -verify_other_scb: - xor SCBPTR[1], 1; - test SCBPTR[1], 0xFF jnz verify_scb; - jmp not_found; - -/* - * Ensure that the SCB the tag points to is for - * an SCB transaction to the reconnecting target. - */ -setup_SCB: - if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x10; - } - test SCB_CONTROL,DISCONNECTED jz not_found; -setup_SCB_disconnected: - and SCB_CONTROL,~DISCONNECTED; - clr SEQ_FLAGS; /* make note of IDENTIFY */ - test SCB_SGPTR, SG_LIST_NULL jnz . + 3; - bmov ALLOCFIFO_SCBPTR, SCBPTR, 2; - call allocate_fifo; - /* See if the host wants to send a message upon reconnection */ - test SCB_CONTROL, MK_MESSAGE jz mesgin_done; - mvi HOST_MSG call mk_mesg; - jmp mesgin_done; - -not_found: - SET_SEQINTCODE(NO_MATCH) - jmp mesgin_done; - -not_found_ITloop: - SET_SEQINTCODE(NO_MATCH) - jmp ITloop; - -/* - * We received a "command complete" message. Put the SCB on the complete - * queue and trigger a completion interrupt via the idle loop. Before doing - * so, check to see if there is a residual or the status byte is something - * other than STATUS_GOOD (0). In either of these conditions, we upload the - * SCB back to the host so it can process this information. - */ -mesgin_complete: - - /* - * If ATN is raised, we still want to give the target a message. - * Perhaps there was a parity error on this last message byte. - * Either way, the target should take us to message out phase - * and then attempt to complete the command again. We should use a - * critical section here to guard against a timeout triggering - * for this command and setting ATN while we are still processing - * the completion. - test SCSISIGI, ATNI jnz mesgin_done; - */ - - /* - * If we are identified and have successfully sent the CDB, - * any status will do. Optimize this fast path. - */ - test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation; - test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; - - /* - * If the target never sent an identify message but instead went - * to mesgin to give an invalid message, let the host abort us. - */ - test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; - - /* - * If we recevied good status but never successfully sent the - * cdb, abort the command. - */ - test SCB_SCSI_STATUS,0xff jnz complete_accepted; - test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation; -complete_accepted: - - /* - * See if we attempted to deliver a message but the target ingnored us. - */ - test SCB_CONTROL, MK_MESSAGE jz complete_nomsg; - SET_SEQINTCODE(MKMSG_FAILED) -complete_nomsg: - call queue_scb_completion; - jmp await_busfree; - -BEGIN_CRITICAL; -freeze_queue: - /* Cancel any pending select-out. */ - test SSTAT0, SELDO|SELINGO jnz . + 2; - and SCSISEQ0, ~ENSELO; - mov ACCUM_SAVE, A; - clr A; - add QFREEZE_COUNT, 1; - adc QFREEZE_COUNT[1], A; - or SEQ_FLAGS2, SELECTOUT_QFROZEN; - mov A, ACCUM_SAVE ret; -END_CRITICAL; - -/* - * Complete the current FIFO's SCB if data for this same - * SCB is not transferring in the other FIFO. - */ -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; -pkt_complete_scb_if_fifos_idle: - bmov ARG_1, SCBPTR, 2; - mvi DFFSXFRCTL, CLRCHN; - SET_MODE(M_SCSI, M_SCSI) - bmov SCBPTR, ARG_1, 2; - test SCB_FIFO_USE_COUNT, 0xFF jnz return; -queue_scb_completion: - test SCB_SCSI_STATUS,0xff jnz bad_status; - /* - * Check for residuals - */ - test SCB_SGPTR, SG_LIST_NULL jnz complete; /* No xfer */ - test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ - test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; -complete: -BEGIN_CRITICAL; - bmov SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2; - bmov COMPLETE_SCB_HEAD, SCBPTR, 2 ret; -END_CRITICAL; -bad_status: - cmp SCB_SCSI_STATUS, STATUS_PKT_SENSE je upload_scb; - call freeze_queue; -upload_scb: - /* - * Restore SCB TAG since we reuse this field - * in the sequencer. We don't want to corrupt - * it on the host. - */ - bmov SCB_TAG, SCBPTR, 2; -BEGIN_CRITICAL; - or SCB_SGPTR, SG_STATUS_VALID; - mvi SCB_NEXT_COMPLETE[1], SCB_LIST_NULL; - cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne add_dma_scb_tail; - bmov COMPLETE_DMA_SCB_HEAD, SCBPTR, 2; - bmov COMPLETE_DMA_SCB_TAIL, SCBPTR, 2 ret; -add_dma_scb_tail: - bmov REG0, SCBPTR, 2; - bmov SCBPTR, COMPLETE_DMA_SCB_TAIL, 2; - bmov SCB_NEXT_COMPLETE, REG0, 2; - bmov COMPLETE_DMA_SCB_TAIL, REG0, 2 ret; -END_CRITICAL; - -/* - * Is it a disconnect message? Set a flag in the SCB to remind us - * and await the bus going free. If this is an untagged transaction - * store the SCB id for it in our untagged target table for lookup on - * a reselection. - */ -mesgin_disconnect: - /* - * If ATN is raised, we still want to give the target a message. - * Perhaps there was a parity error on this last message byte - * or we want to abort this command. Either way, the target - * should take us to message out phase and then attempt to - * disconnect again. - * XXX - Wait for more testing. - test SCSISIGI, ATNI jnz mesgin_done; - */ - test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT - jnz mesgin_proto_violation; - or SCB_CONTROL,DISCONNECTED; - test SCB_CONTROL, TAG_ENB jnz await_busfree; -queue_disc_scb: - bmov REG0, SCBPTR, 2; - INDEX_DISC_LIST(SAVED_SCSIID, SAVED_LUN); - bmov DINDEX, SINDEX, 2; - bmov DINDIR, REG0, 2; - bmov SCBPTR, REG0, 2; - /* FALLTHROUGH */ -await_busfree: - and SIMODE1, ~ENBUSFREE; - if ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0) { - /* - * In the BUSFREEREV_BUG case, the - * busfree status was cleared at the - * beginning of the connection. - */ - mvi CLRSINT1,CLRBUSFREE; - } - mov NONE, SCSIDAT; /* Ack the last byte */ - test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) - jnz await_busfree_not_m_dff; -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; -await_busfree_clrchn: - mvi DFFSXFRCTL, CLRCHN; -await_busfree_not_m_dff: - /* clear target specific flags */ - mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT; - test SSTAT1,REQINIT|BUSFREE jz .; - /* - * We only set BUSFREE status once either a new - * phase has been detected or we are really - * BUSFREE. This allows the driver to know - * that we are active on the bus even though - * no identified transaction exists should a - * timeout occur while awaiting busfree. - */ - mvi LASTPHASE, P_BUSFREE; - test SSTAT1, BUSFREE jnz idle_loop; - SET_SEQINTCODE(MISSED_BUSFREE) - - -/* - * Save data pointers message: - * Copying RAM values back to SCB, for Save Data Pointers message, but - * only if we've actually been into a data phase to change them. This - * protects against bogus data in scratch ram and the residual counts - * since they are only initialized when we go into data_in or data_out. - * Ack the message as soon as possible. - */ -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; -mesgin_sdptrs: - mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ - test SEQ_FLAGS, DPHASE jz ITloop; - call save_pointers; - jmp ITloop; - -save_pointers: - /* - * If we are asked to save our position at the end of the - * transfer, just mark us at the end rather than perform a - * full save. - */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz save_pointers_full; - or SCB_SGPTR, SG_LIST_NULL ret; - -save_pointers_full: - /* - * The SCB_DATAPTR becomes the current SHADDR. - * All other information comes directly from our residual - * state. - */ - bmov SCB_DATAPTR, SHADDR, 8; - bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8 ret; - -/* - * Restore pointers message? Data pointers are recopied from the - * SCB anytime we enter a data phase for the first time, so all - * we need to do is clear the DPHASE flag and let the data phase - * code do the rest. We also reset/reallocate the FIFO to make - * sure we have a clean start for the next data or command phase. - */ -mesgin_rdptrs: - and SEQ_FLAGS, ~DPHASE; - test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz msgin_rdptrs_get_fifo; - mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; - SET_MODE(M_SCSI, M_SCSI) -msgin_rdptrs_get_fifo: - call allocate_fifo; - jmp mesgin_done; - -phase_lock: - if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) { - /* - * Don't ignore persistent REQ assertions just because - * they were asserted within the bus settle delay window. - * This allows us to tolerate devices like the GEM318 - * that violate the SCSI spec. We are careful not to - * count REQ while we are waiting for it to fall during - * an async phase due to our asserted ACK. Each - * sequencer instruction takes ~25ns, so the REQ must - * last at least 100ns in order to be counted as a true - * REQ. - */ - test SCSIPHASE, 0xFF jnz phase_locked; - test SCSISIGI, ACKI jnz phase_lock; - test SCSISIGI, REQI jz phase_lock; - test SCSIPHASE, 0xFF jnz phase_locked; - test SCSISIGI, ACKI jnz phase_lock; - test SCSISIGI, REQI jz phase_lock; -phase_locked: - } else { - test SCSIPHASE, 0xFF jz .; - } - test SSTAT1, SCSIPERR jnz phase_lock; -phase_lock_latch_phase: - and LASTPHASE, PHASE_MASK, SCSISIGI ret; - -/* - * Functions to read data in Automatic PIO mode. - * - * An ACK is not sent on input from the target until SCSIDATL is read from. - * So we wait until SCSIDATL is latched (the usual way), then read the data - * byte directly off the bus using SCSIBUSL. When we have pulled the ATN - * line, or we just want to acknowledge the byte, then we do a dummy read - * from SCISDATL. The SCSI spec guarantees that the target will hold the - * data byte on the bus until we send our ACK. - * - * The assumption here is that these are called in a particular sequence, - * and that REQ is already set when inb_first is called. inb_{first,next} - * use the same calling convention as inb. - */ -inb_next: - mov NONE,SCSIDAT; /*dummy read from latch to ACK*/ -inb_next_wait: - /* - * If there is a parity error, wait for the kernel to - * see the interrupt and prepare our message response - * before continuing. - */ - test SCSIPHASE, 0xFF jz .; - test SSTAT1, SCSIPERR jnz inb_next_wait; -inb_next_check_phase: - and LASTPHASE, PHASE_MASK, SCSISIGI; - cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; -inb_first: - clr DINDEX[1]; - mov DINDEX,SINDEX; - mov DINDIR,SCSIBUS ret; /*read byte directly from bus*/ -inb_last: - mov NONE,SCSIDAT ret; /*dummy read from latch to ACK*/ - -mk_mesg: - mvi SCSISIGO, ATNO; - mov MSG_OUT,SINDEX ret; - -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; -disable_ccsgen: - test SG_STATE, FETCH_INPROG jz disable_ccsgen_fetch_done; - clr CCSGCTL; -disable_ccsgen_fetch_done: - clr SG_STATE ret; - -service_fifo: - /* - * Do we have any prefetch left??? - */ - test SG_STATE, SEGS_AVAIL jnz idle_sg_avail; - - /* - * Can this FIFO have access to the S/G cache yet? - */ - test CCSGCTL, SG_CACHE_AVAIL jz return; - - /* Did we just finish fetching segs? */ - test CCSGCTL, CCSGDONE jnz idle_sgfetch_complete; - - /* Are we actively fetching segments? */ - test CCSGCTL, CCSGENACK jnz return; - - /* - * Should the other FIFO get the S/G cache first? If - * both FIFOs have been allocated since we last checked - * any FIFO, it is important that we service a FIFO - * that is not actively on the bus first. This guarantees - * that a FIFO will be freed to handle snapshot requests for - * any FIFO that is still on the bus. Chips with RTI do not - * perform snapshots, so don't bother with this test there. - */ - if ((ahd->features & AHD_RTI) == 0) { - /* - * If we're not still receiving SCSI data, - * it is safe to allocate the S/G cache to - * this FIFO. - */ - test DFCNTRL, SCSIEN jz idle_sgfetch_start; - - /* - * Switch to the other FIFO. Non-RTI chips - * also have the "set mode" bug, so we must - * disable interrupts during the switch. - */ - mvi SEQINTCTL, INTVEC1DSL; - xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); - - /* - * If the other FIFO needs loading, then it - * must not have claimed the S/G cache yet - * (SG_CACHE_AVAIL would have been cleared in - * the original FIFO mode and we test this above). - * Return to the idle loop so we can process the - * FIFO not currently on the bus first. - */ - test SG_STATE, LOADING_NEEDED jz idle_sgfetch_okay; - clr SEQINTCTL ret; -idle_sgfetch_okay: - xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); - clr SEQINTCTL; - } - -idle_sgfetch_start: - /* - * We fetch a "cacheline aligned" and sized amount of data - * so we don't end up referencing a non-existent page. - * Cacheline aligned is in quotes because the kernel will - * set the prefetch amount to a reasonable level if the - * cacheline size is unknown. - */ - bmov SGHADDR, SCB_RESIDUAL_SGPTR, 4; - mvi SGHCNT, SG_PREFETCH_CNT; - if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) { - /* - * Need two instructions between "touches" of SGHADDR. - */ - nop; - } - and SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; - mvi CCSGCTL, CCSGEN|CCSGRESET; - or SG_STATE, FETCH_INPROG ret; -idle_sgfetch_complete: - /* - * Guard against SG_CACHE_AVAIL activating during sg fetch - * request in the other FIFO. - */ - test SG_STATE, FETCH_INPROG jz return; - clr CCSGCTL; - and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; - mvi SG_STATE, SEGS_AVAIL|LOADING_NEEDED; -idle_sg_avail: - /* Does the hardware have space for another SG entry? */ - test DFSTATUS, PRELOAD_AVAIL jz return; - /* - * On the A, preloading a segment before HDMAENACK - * comes true can clobber the shadow address of the - * first segment in the S/G FIFO. Wait until it is - * safe to proceed. - */ - if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0) { - test DFCNTRL, HDMAENACK jz return; - } - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { - bmov HADDR, CCSGRAM, 8; - } else { - bmov HADDR, CCSGRAM, 4; - } - bmov HCNT, CCSGRAM, 3; - bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; - if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { - and HADDR[4], SG_HIGH_ADDR_BITS, SCB_RESIDUAL_DATACNT[3]; - } - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { - /* Skip 4 bytes of pad. */ - add CCSGADDR, 4; - } -sg_advance: - clr A; /* add sizeof(struct scatter) */ - add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; - adc SCB_RESIDUAL_SGPTR[1],A; - adc SCB_RESIDUAL_SGPTR[2],A; - adc SCB_RESIDUAL_SGPTR[3],A; - mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 3; - or SINDEX, LAST_SEG; - clr SG_STATE; - mov SG_CACHE_PRE, SINDEX; - if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) { - /* - * Use SCSIENWRDIS so that SCSIEN is never - * modified by this operation. - */ - or DFCNTRL, PRELOADEN|HDMAEN|SCSIENWRDIS; - } else { - or DFCNTRL, PRELOADEN|HDMAEN; - } - /* - * Do we have another segment in the cache? - */ - add NONE, SG_PREFETCH_CNT_LIMIT, CCSGADDR; - jnc return; - and SG_STATE, ~SEGS_AVAIL ret; - -/* - * Initialize the DMA address and counter from the SCB. - */ -load_first_seg: - bmov HADDR, SCB_DATAPTR, 11; - and REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0]; - test SCB_DATACNT[3], SG_LAST_SEG jz . + 2; - or REG_ISR, LAST_SEG; - mov SG_CACHE_PRE, REG_ISR; - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); - /* - * Since we've are entering a data phase, we will - * rely on the SCB_RESID* fields. Initialize the - * residual and clear the full residual flag. - */ - and SCB_SGPTR[0], ~SG_FULL_RESID; - bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; - /* If we need more S/G elements, tell the idle loop */ - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz . + 2; - mvi SG_STATE, LOADING_NEEDED ret; - clr SG_STATE ret; - -p_data_handle_xfer: - call setjmp; - test SG_STATE, LOADING_NEEDED jnz service_fifo; -p_data_clear_handler: - or LONGJMP_ADDR[1], INVALID_ADDR ret; - -p_data: - test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed; - SET_SEQINTCODE(PROTO_VIOLATION) -p_data_allowed: - - test SEQ_FLAGS, DPHASE jz data_phase_initialize; - - /* - * If we re-enter the data phase after going through another - * phase, our transfer location has almost certainly been - * corrupted by the interveining, non-data, transfers. Ask - * the host driver to fix us up based on the transfer residual - * unless we already know that we should be bitbucketing. - */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket; - SET_SEQINTCODE(PDATA_REINIT) - jmp data_phase_inbounds; - -p_data_bitbucket: - /* - * Turn on `Bit Bucket' mode, wait until the target takes - * us to another phase, and then notify the host. - */ - mov SAVED_MODE, MODE_PTR; - test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) - jnz bitbucket_not_m_dff; - /* - * Ensure that any FIFO contents are cleared out and the - * FIFO free'd prior to starting the BITBUCKET. BITBUCKET - * doesn't discard data already in the FIFO. - */ - mvi DFFSXFRCTL, RSTCHN|CLRSHCNT; - SET_MODE(M_SCSI, M_SCSI) -bitbucket_not_m_dff: - or SXFRCTL1,BITBUCKET; - /* Wait for non-data phase. */ - test SCSIPHASE, ~DATA_PHASE_MASK jz .; - and SXFRCTL1, ~BITBUCKET; - RESTORE_MODE(SAVED_MODE) -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; - SET_SEQINTCODE(DATA_OVERRUN) - jmp ITloop; - -data_phase_initialize: - test SCB_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket; - call load_first_seg; -data_phase_inbounds: - /* We have seen a data phase at least once. */ - or SEQ_FLAGS, DPHASE; - mov SAVED_MODE, MODE_PTR; - test SG_STATE, LOADING_NEEDED jz data_group_dma_loop; - call p_data_handle_xfer; -data_group_dma_loop: - /* - * The transfer is complete if either the last segment - * completes or the target changes phase. Both conditions - * will clear SCSIEN. - */ - call idle_loop_service_fifos; - call idle_loop_cchan; - call idle_loop_gsfifo; - RESTORE_MODE(SAVED_MODE) - test DFCNTRL, SCSIEN jnz data_group_dma_loop; - -data_group_dmafinish: - /* - * The transfer has terminated either due to a phase - * change, and/or the completion of the last segment. - * We have two goals here. Do as much other work - * as possible while the data fifo drains on a read - * and respond as quickly as possible to the standard - * messages (save data pointers/disconnect and command - * complete) that usually follow a data phase. - */ - call calc_residual; - - /* - * Go ahead and shut down the DMA engine now. - */ - test DFCNTRL, DIRECTION jnz data_phase_finish; -data_group_fifoflush: - if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { - or DFCNTRL, FIFOFLUSH; - } - /* - * We have enabled the auto-ack feature. This means - * that the controller may have already transferred - * some overrun bytes into the data FIFO and acked them - * on the bus. The only way to detect this situation is - * to wait for LAST_SEG_DONE to come true on a completed - * transfer and then test to see if the data FIFO is - * non-empty. We know there is more data yet to transfer - * if SG_LIST_NULL is not yet set, thus there cannot be - * an overrun. - */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_finish; - test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; - test DFSTATUS, FIFOEMP jnz data_phase_finish; - /* Overrun */ - jmp p_data; -data_phase_finish: - /* - * If the target has left us in data phase, loop through - * the dma code again. We will only loop if there is a - * data overrun. - */ - if ((ahd->flags & AHD_TARGETROLE) != 0) { - test SSTAT0, TARGET jnz data_phase_done; - } - if ((ahd->flags & AHD_INITIATORROLE) != 0) { - test SSTAT1, REQINIT jz .; - test SCSIPHASE, DATA_PHASE_MASK jnz p_data; - } - -data_phase_done: - /* Kill off any pending prefetch */ - call disable_ccsgen; - or LONGJMP_ADDR[1], INVALID_ADDR; - - if ((ahd->flags & AHD_TARGETROLE) != 0) { - test SEQ_FLAGS, DPHASE_PENDING jz ITloop; - /* - and SEQ_FLAGS, ~DPHASE_PENDING; - * For data-in phases, wait for any pending acks from the - * initiator before changing phase. We only need to - * send Ignore Wide Residue messages for data-in phases. - test DFCNTRL, DIRECTION jz target_ITloop; - test SSTAT1, REQINIT jnz .; - test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jz target_ITloop; - SET_MODE(M_SCSI, M_SCSI) - test NEGCONOPTS, WIDEXFER jz target_ITloop; - */ - /* - * Issue an Ignore Wide Residue Message. - mvi P_MESGIN|BSYO call change_phase; - mvi MSG_IGN_WIDE_RESIDUE call target_outb; - mvi 1 call target_outb; - jmp target_ITloop; - */ - } else { - jmp ITloop; - } - -/* - * We assume that, even though data may still be - * transferring to the host, that the SCSI side of - * the DMA engine is now in a static state. This - * allows us to update our notion of where we are - * in this transfer. - * - * If, by chance, we stopped before being able - * to fetch additional segments for this transfer, - * yet the last S/G was completely exhausted, - * call our idle loop until it is able to load - * another segment. This will allow us to immediately - * pickup on the next segment on the next data phase. - * - * If we happened to stop on the last segment, then - * our residual information is still correct from - * the idle loop and there is no need to perform - * any fixups. - */ -residual_before_last_seg: - test MDFFSTAT, SHVALID jnz sgptr_fixup; - /* - * Can never happen from an interrupt as the packetized - * hardware will only interrupt us once SHVALID or - * LAST_SEG_DONE. - */ - call idle_loop_service_fifos; - RESTORE_MODE(SAVED_MODE) - /* FALLTHROUGH */ -calc_residual: - test SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg; - /* Record if we've consumed all S/G entries */ - test MDFFSTAT, SHVALID jz . + 2; - bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; - or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret; - -sgptr_fixup: - /* - * Fixup the residual next S/G pointer. The S/G preload - * feature of the chip allows us to load two elements - * in addition to the currently active element. We - * store the bottom byte of the next S/G pointer in - * the SG_CACHE_PTR register so we can restore the - * correct value when the DMA completes. If the next - * sg ptr value has advanced to the point where higher - * bytes in the address have been affected, fix them - * too. - */ - test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; - test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; - add SCB_RESIDUAL_SGPTR[1], -1; - adc SCB_RESIDUAL_SGPTR[2], -1; - adc SCB_RESIDUAL_SGPTR[3], -1; -sgptr_fixup_done: - and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; - clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ - bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; - -export timer_isr: - call issue_cmdcmplt; - mvi CLRSEQINTSTAT, CLRSEQ_SWTMRTO; - if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) { - /* - * In H2A4, the mode pointer is not saved - * for intvec2, but is restored on iret. - * This can lead to the restoration of a - * bogus mode ptr. Manually clear the - * intmask bits and do a normal return - * to compensate. - */ - and SEQINTCTL, ~(INTMASK2|INTMASK1) ret; - } else { - or SEQINTCTL, IRET ret; - } - -export seq_isr: - if ((ahd->features & AHD_RTI) == 0) { - /* - * On RevA Silicon, if the target returns us to data-out - * after we have already trained for data-out, it is - * possible for us to transition the free running clock to - * data-valid before the required 100ns P1 setup time (8 P1 - * assertions in fast-160 mode). This will only happen if - * this L-Q is a continuation of a data transfer for which - * we have already prefetched data into our FIFO (LQ/Data - * followed by LQ/Data for the same write transaction). - * This can cause some target implementations to miss the - * first few data transfers on the bus. We detect this - * situation by noticing that this is the first data transfer - * after an LQ (LQIWORKONLQ true), that the data transfer is - * a continuation of a transfer already setup in our FIFO - * (SAVEPTRS interrupt), and that the transaction is a write - * (DIRECTION set in DFCNTRL). The delay is performed by - * disabling SCSIEN until we see the first REQ from the - * target. - * - * First instruction in an ISR cannot be a branch on - * Rev A. Snapshot LQISTAT2 so the status is not missed - * and deffer the test by one instruction. - */ - mov REG_ISR, LQISTAT2; - test REG_ISR, LQIWORKONLQ jz main_isr; - test SEQINTSRC, SAVEPTRS jz main_isr; - test LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo; - /* - * Switch to the active FIFO after clearing the snapshot - * savepointer in the current FIFO. We do this so that - * a pending CTXTDONE or SAVEPTR is visible in the active - * FIFO. This status is the only way we can detect if we - * have lost the race (e.g. host paused us) and our attempts - * to disable the channel occurred after all REQs were - * already seen and acked (REQINIT never comes true). - */ - mvi DFFSXFRCTL, CLRCHN; - xor MODE_PTR, MK_MODE(M_DFF1, M_DFF1); - test DFCNTRL, DIRECTION jz interrupt_return; - and DFCNTRL, ~SCSIEN; -snapshot_wait_data_valid: - test SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz interrupt_return; - test SSTAT1, REQINIT jz snapshot_wait_data_valid; -snapshot_data_valid: - or DFCNTRL, SCSIEN; - or SEQINTCTL, IRET ret; -snapshot_saveptr: - mvi DFFSXFRCTL, CLRCHN; - or SEQINTCTL, IRET ret; -main_isr: - } - test SEQINTSRC, CFG4DATA jnz cfg4data_intr; - test SEQINTSRC, CFG4ISTAT jnz cfg4istat_intr; - test SEQINTSRC, SAVEPTRS jnz saveptr_intr; - test SEQINTSRC, CFG4ICMD jnz cfg4icmd_intr; - SET_SEQINTCODE(INVALID_SEQINT) - -/* - * There are two types of save pointers interrupts: - * The first is a snapshot save pointers where the current FIFO is not - * active and contains a snapshot of the current poniter information. - * This happens between packets in a stream for a single L_Q. Since we - * are not performing a pointer save, we can safely clear the channel - * so it can be used for other transactions. On RTI capable controllers, - * where snapshots can, and are, disabled, the code to handle this type - * of snapshot is not active. - * - * The second case is a save pointers on an active FIFO which occurs - * if the target changes to a new L_Q or busfrees/QASes and the transfer - * has a residual. This should occur coincident with a ctxtdone. We - * disable the interrupt and allow our active routine to handle the - * save. - */ -saveptr_intr: - if ((ahd->features & AHD_RTI) == 0) { - test LONGJMP_ADDR[1], INVALID_ADDR jnz snapshot_saveptr; - } -saveptr_active_fifo: - and SEQIMODE, ~ENSAVEPTRS; - or SEQINTCTL, IRET ret; - -cfg4data_intr: - test SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun_inc_use_count; - call load_first_seg; - call pkt_handle_xfer; - inc SCB_FIFO_USE_COUNT; -interrupt_return: - or SEQINTCTL, IRET ret; - -cfg4istat_intr: - call freeze_queue; - add NONE, -13, SCB_CDB_LEN; - jnc cfg4istat_have_sense_addr; - test SCB_CDB_LEN, SCB_CDB_LEN_PTR jnz cfg4istat_have_sense_addr; - /* - * Host sets up address/count and enables transfer. - */ - SET_SEQINTCODE(CFG4ISTAT_INTR) - jmp cfg4istat_setup_handler; -cfg4istat_have_sense_addr: - bmov HADDR, SCB_SENSE_BUSADDR, 4; - mvi HCNT[1], (AHD_SENSE_BUFSIZE >> 8); - mvi SG_CACHE_PRE, LAST_SEG; - mvi DFCNTRL, PRELOADEN|SCSIEN|HDMAEN; -cfg4istat_setup_handler: - /* - * Status pkt is transferring to host. - * Wait in idle loop for transfer to complete. - * If a command completed before an attempted - * task management function completed, notify the host. - */ - test SCB_TASK_MANAGEMENT, 0xFF jz cfg4istat_no_taskmgmt_func; - SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY) -cfg4istat_no_taskmgmt_func: - call pkt_handle_status; - or SEQINTCTL, IRET ret; - -cfg4icmd_intr: - /* - * In the case of DMAing a CDB from the host, the normal - * CDB buffer is formatted with an 8 byte address followed - * by a 1 byte count. - */ - bmov HADDR[0], SCB_HOST_CDB_PTR, 9; - mvi SG_CACHE_PRE, LAST_SEG; - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); - call pkt_handle_cdb; - or SEQINTCTL, IRET ret; - -/* - * See if the target has gone on in this context creating an - * overrun condition. For the write case, the hardware cannot - * ack bytes until data are provided. So, if the target begins - * another packet without changing contexts, implying we are - * not sitting on a packet boundary, we are in an overrun - * situation. For the read case, the hardware will continue to - * ack bytes into the FIFO, and may even ack the last overrun packet - * into the FIFO. If the FIFO should become non-empty, we are in - * a read overrun case. - */ -#define check_overrun \ - /* Not on a packet boundary. */ \ - test MDFFSTAT, DLZERO jz pkt_handle_overrun; \ - test DFSTATUS, FIFOEMP jz pkt_handle_overrun - -pkt_handle_xfer: - test SG_STATE, LOADING_NEEDED jz pkt_last_seg; - call setjmp; - test SEQINTSRC, SAVEPTRS jnz pkt_saveptrs; - test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; - test SCSISIGO, ATNO jnz . + 2; - test SSTAT2, NONPACKREQ jz pkt_service_fifo; - /* - * Defer handling of this NONPACKREQ until we - * can be sure it pertains to this FIFO. SAVEPTRS - * will not be asserted if the NONPACKREQ is for us, - * so we must simulate it if shadow is valid. If - * shadow is not valid, keep running this FIFO until we - * have satisfied the transfer by loading segments and - * waiting for either shadow valid or last_seg_done. - */ - test MDFFSTAT, SHVALID jnz pkt_saveptrs; -pkt_service_fifo: - test SG_STATE, LOADING_NEEDED jnz service_fifo; -pkt_last_seg: - call setjmp; - test SEQINTSRC, SAVEPTRS jnz pkt_saveptrs; - test SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_last_seg_done; - test SCSIPHASE, ~DATA_PHASE_MASK jz . + 2; - test SCSISIGO, ATNO jnz . + 2; - test SSTAT2, NONPACKREQ jz return; - test MDFFSTAT, SHVALID jz return; - /* FALLTHROUGH */ - -/* - * Either a SAVEPTRS interrupt condition is pending for this FIFO - * or we have a pending NONPACKREQ for this FIFO. We differentiate - * between the two by capturing the state of the SAVEPTRS interrupt - * prior to clearing this status and executing the common code for - * these two cases. - */ -pkt_saveptrs: -BEGIN_CRITICAL; - if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { - or DFCNTRL, FIFOFLUSH; - } - mov REG0, SEQINTSRC; - call calc_residual; - call save_pointers; - mvi CLRSEQINTSRC, CLRSAVEPTRS; - call disable_ccsgen; - or SEQIMODE, ENSAVEPTRS; - test DFCNTRL, DIRECTION jnz pkt_saveptrs_check_status; - test DFSTATUS, FIFOEMP jnz pkt_saveptrs_check_status; - /* - * Keep a handler around for this FIFO until it drains - * to the host to guarantee that we don't complete the - * command to the host before the data arrives. - */ -pkt_saveptrs_wait_fifoemp: - call setjmp; - test DFSTATUS, FIFOEMP jz return; -pkt_saveptrs_check_status: - or LONGJMP_ADDR[1], INVALID_ADDR; - test REG0, SAVEPTRS jz unexpected_nonpkt_phase; - dec SCB_FIFO_USE_COUNT; - test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; - mvi DFFSXFRCTL, CLRCHN ret; - -/* - * LAST_SEG_DONE status has been seen in the current FIFO. - * This indicates that all of the allowed data for this - * command has transferred across the SCSI and host buses. - * Check for overrun and see if we can complete this command. - */ -pkt_last_seg_done: - /* - * Mark transfer as completed. - */ - or SCB_SGPTR, SG_LIST_NULL; - - /* - * Wait for the current context to finish to verify that - * no overrun condition has occurred. - */ - test SEQINTSRC, CTXTDONE jnz pkt_ctxt_done; - call setjmp; -pkt_wait_ctxt_done_loop: - test SEQINTSRC, CTXTDONE jnz pkt_ctxt_done; - /* - * A sufficiently large overrun or a NONPACKREQ may - * prevent CTXTDONE from ever asserting, so we must - * poll for these statuses too. - */ - check_overrun; - test SSTAT2, NONPACKREQ jz return; - test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase; - /* FALLTHROUGH */ - -pkt_ctxt_done: - check_overrun; - or LONGJMP_ADDR[1], INVALID_ADDR; - /* - * If status has been received, it is safe to skip - * the check to see if another FIFO is active because - * LAST_SEG_DONE has been observed. However, we check - * the FIFO anyway since it costs us only one extra - * instruction to leverage common code to perform the - * SCB completion. - */ - dec SCB_FIFO_USE_COUNT; - test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; - mvi DFFSXFRCTL, CLRCHN ret; -END_CRITICAL; - -/* - * Must wait until CDB xfer is over before issuing the - * clear channel. - */ -pkt_handle_cdb: - call setjmp; - test SG_CACHE_SHADOW, LAST_SEG_DONE jz return; - or LONGJMP_ADDR[1], INVALID_ADDR; - mvi DFFSXFRCTL, CLRCHN ret; - -/* - * Watch over the status transfer. Our host sense buffer is - * large enough to take the maximum allowed status packet. - * None-the-less, we must still catch and report overruns to - * the host. Additionally, properly catch unexpected non-packet - * phases that are typically caused by CRC errors in status packet - * transmission. - */ -pkt_handle_status: - call setjmp; - test SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun; - test SEQINTSRC, CTXTDONE jz pkt_status_check_nonpackreq; - test SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun; -pkt_status_IU_done: - if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) { - or DFCNTRL, FIFOFLUSH; - } - test DFSTATUS, FIFOEMP jz return; -BEGIN_CRITICAL; - or LONGJMP_ADDR[1], INVALID_ADDR; - mvi SCB_SCSI_STATUS, STATUS_PKT_SENSE; - or SCB_CONTROL, STATUS_RCVD; - jmp pkt_complete_scb_if_fifos_idle; -END_CRITICAL; -pkt_status_check_overrun: - /* - * Status PKT overruns are uncerimoniously recovered with a - * bus reset. If we've overrun, let the host know so that - * recovery can be performed. - * - * LAST_SEG_DONE has been observed. If either CTXTDONE or - * a NONPACKREQ phase change have occurred and the FIFO is - * empty, there is no overrun. - */ - test DFSTATUS, FIFOEMP jz pkt_status_report_overrun; - test SEQINTSRC, CTXTDONE jz . + 2; - test DFSTATUS, FIFOEMP jnz pkt_status_IU_done; - test SCSIPHASE, ~DATA_PHASE_MASK jz return; - test DFSTATUS, FIFOEMP jnz pkt_status_check_nonpackreq; -pkt_status_report_overrun: - SET_SEQINTCODE(STATUS_OVERRUN) - /* SEQUENCER RESTARTED */ -pkt_status_check_nonpackreq: - /* - * CTXTDONE may be held off if a NONPACKREQ is associated with - * the current context. If a NONPACKREQ is observed, decide - * if it is for the current context. If it is for the current - * context, we must defer NONPACKREQ processing until all data - * has transferred to the host. - */ - test SCSIPHASE, ~DATA_PHASE_MASK jz return; - test SCSISIGO, ATNO jnz . + 2; - test SSTAT2, NONPACKREQ jz return; - test SEQINTSRC, CTXTDONE jnz pkt_status_IU_done; - test DFSTATUS, FIFOEMP jz return; - /* - * The unexpected nonpkt phase handler assumes that any - * data channel use will have a FIFO reference count. It - * turns out that the status handler doesn't need a references - * count since the status received flag, and thus completion - * processing, cannot be set until the handler is finished. - * We increment the count here to make the nonpkt handler - * happy. - */ - inc SCB_FIFO_USE_COUNT; - /* FALLTHROUGH */ - -/* - * Nonpackreq is a polled status. It can come true in three situations: - * we have received an L_Q, we have sent one or more L_Qs, or there is no - * L_Q context associated with this REQ (REQ occurs immediately after a - * (re)selection). Routines that know that the context responsible for this - * nonpackreq call directly into unexpected_nonpkt_phase. In the case of the - * top level idle loop, we exhaust all active contexts prior to determining that - * we simply do not have the full I_T_L_Q for this phase. - */ -unexpected_nonpkt_phase_find_ctxt: - /* - * This nonpackreq is most likely associated with one of the tags - * in a FIFO or an outgoing LQ. Only treat it as an I_T only - * nonpackreq if we've cleared out the FIFOs and handled any - * pending SELDO. - */ -SET_SRC_MODE M_SCSI; -SET_DST_MODE M_SCSI; - and A, FIFO1FREE|FIFO0FREE, DFFSTAT; - cmp A, FIFO1FREE|FIFO0FREE jne return; - test SSTAT0, SELDO jnz return; - mvi SCBPTR[1], SCB_LIST_NULL; -unexpected_nonpkt_phase: - test MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) - jnz unexpected_nonpkt_mode_cleared; -SET_SRC_MODE M_DFF0; -SET_DST_MODE M_DFF0; - or LONGJMP_ADDR[1], INVALID_ADDR; - dec SCB_FIFO_USE_COUNT; - mvi DFFSXFRCTL, CLRCHN; -unexpected_nonpkt_mode_cleared: - mvi CLRSINT2, CLRNONPACKREQ; - if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { - /* - * Test to ensure that the bus has not - * already gone free prior to clearing - * any stale busfree status. This avoids - * a window whereby a busfree just after - * a selection could be missed. - */ - test SCSISIGI, BSYI jz . + 2; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; - } - test SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase; - SET_SEQINTCODE(ENTERING_NONPACK) - jmp ITloop; - -illegal_phase: - SET_SEQINTCODE(ILLEGAL_PHASE) - jmp ITloop; - -/* - * We have entered an overrun situation. If we have working - * BITBUCKET, flip that on and let the hardware eat any overrun - * data. Otherwise use an overrun buffer in the host to simulate - * BITBUCKET. - */ -pkt_handle_overrun_inc_use_count: - inc SCB_FIFO_USE_COUNT; -pkt_handle_overrun: - SET_SEQINTCODE(CFG4OVERRUN) - call freeze_queue; - if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) { - or DFFSXFRCTL, DFFBITBUCKET; -SET_SRC_MODE M_DFF1; -SET_DST_MODE M_DFF1; - } else { - call load_overrun_buf; - mvi DFCNTRL, (HDMAEN|SCSIEN|PRELOADEN); - } - call setjmp; - if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { - test DFSTATUS, PRELOAD_AVAIL jz overrun_load_done; - call load_overrun_buf; - or DFCNTRL, PRELOADEN; -overrun_load_done: - test SEQINTSRC, CTXTDONE jnz pkt_overrun_end; - } else { - test DFFSXFRCTL, DFFBITBUCKET jz pkt_overrun_end; - } - test SSTAT2, NONPACKREQ jz return; -pkt_overrun_end: - or SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID; - test SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase; - dec SCB_FIFO_USE_COUNT; - or LONGJMP_ADDR[1], INVALID_ADDR; - test SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle; - mvi DFFSXFRCTL, CLRCHN ret; - -if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { -load_overrun_buf: - /* - * Load a dummy segment if preload space is available. - */ - mov HADDR[0], SHARED_DATA_ADDR; - add HADDR[1], PKT_OVERRUN_BUFOFFSET, SHARED_DATA_ADDR[1]; - mov ACCUM_SAVE, A; - clr A; - adc HADDR[2], A, SHARED_DATA_ADDR[2]; - adc HADDR[3], A, SHARED_DATA_ADDR[3]; - mov A, ACCUM_SAVE; - bmov HADDR[4], ALLZEROS, 4; - /* PKT_OVERRUN_BUFSIZE is a multiple of 256 */ - clr HCNT[0]; - mvi HCNT[1], ((PKT_OVERRUN_BUFSIZE >> 8) & 0xFF); - clr HCNT[2] ret; -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_core.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_core.c deleted file mode 100644 index 25417d0e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_core.c +++ /dev/null @@ -1,10823 +0,0 @@ -/* - * Core routines and tables shareable across OS platforms. - * - * Copyright (c) 1994-2002 Justin T. Gibbs. - * Copyright (c) 2000-2003 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#250 $ - */ - -#ifdef __linux__ -#include "aic79xx_osm.h" -#include "aic79xx_inline.h" -#include "aicasm/aicasm_insformat.h" -#else -#include -#include -#include -#endif - - -/***************************** Lookup Tables **********************************/ -static const char *const ahd_chip_names[] = -{ - "NONE", - "aic7901", - "aic7902", - "aic7901A" -}; -static const u_int num_chip_names = ARRAY_SIZE(ahd_chip_names); - -/* - * Hardware error codes. - */ -struct ahd_hard_error_entry { - uint8_t errno; - const char *errmesg; -}; - -static const struct ahd_hard_error_entry ahd_hard_errors[] = { - { DSCTMOUT, "Discard Timer has timed out" }, - { ILLOPCODE, "Illegal Opcode in sequencer program" }, - { SQPARERR, "Sequencer Parity Error" }, - { DPARERR, "Data-path Parity Error" }, - { MPARERR, "Scratch or SCB Memory Parity Error" }, - { CIOPARERR, "CIOBUS Parity Error" }, -}; -static const u_int num_errors = ARRAY_SIZE(ahd_hard_errors); - -static const struct ahd_phase_table_entry ahd_phase_table[] = -{ - { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, - { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, - { P_DATAOUT_DT, MSG_NOOP, "in DT Data-out phase" }, - { P_DATAIN_DT, MSG_INITIATOR_DET_ERR, "in DT Data-in phase" }, - { P_COMMAND, MSG_NOOP, "in Command phase" }, - { P_MESGOUT, MSG_NOOP, "in Message-out phase" }, - { P_STATUS, MSG_INITIATOR_DET_ERR, "in Status phase" }, - { P_MESGIN, MSG_PARITY_ERROR, "in Message-in phase" }, - { P_BUSFREE, MSG_NOOP, "while idle" }, - { 0, MSG_NOOP, "in unknown phase" } -}; - -/* - * In most cases we only wish to itterate over real phases, so - * exclude the last element from the count. - */ -static const u_int num_phases = ARRAY_SIZE(ahd_phase_table) - 1; - -/* Our Sequencer Program */ -#include "aic79xx_seq.h" - -/**************************** Function Declarations ***************************/ -static void ahd_handle_transmission_error(struct ahd_softc *ahd); -static void ahd_handle_lqiphase_error(struct ahd_softc *ahd, - u_int lqistat1); -static int ahd_handle_pkt_busfree(struct ahd_softc *ahd, - u_int busfreetime); -static int ahd_handle_nonpkt_busfree(struct ahd_softc *ahd); -static void ahd_handle_proto_violation(struct ahd_softc *ahd); -static void ahd_force_renegotiation(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); - -static struct ahd_tmode_tstate* - ahd_alloc_tstate(struct ahd_softc *ahd, - u_int scsi_id, char channel); -#ifdef AHD_TARGET_MODE -static void ahd_free_tstate(struct ahd_softc *ahd, - u_int scsi_id, char channel, int force); -#endif -static void ahd_devlimited_syncrate(struct ahd_softc *ahd, - struct ahd_initiator_tinfo *, - u_int *period, - u_int *ppr_options, - role_t role); -static void ahd_update_neg_table(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - struct ahd_transinfo *tinfo); -static void ahd_update_pending_scbs(struct ahd_softc *ahd); -static void ahd_fetch_devinfo(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_scb_devinfo(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - struct scb *scb); -static void ahd_setup_initiator_msgout(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - struct scb *scb); -static void ahd_build_transfer_msg(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_construct_sdtr(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - u_int period, u_int offset); -static void ahd_construct_wdtr(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - u_int bus_width); -static void ahd_construct_ppr(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - u_int period, u_int offset, - u_int bus_width, u_int ppr_options); -static void ahd_clear_msg_state(struct ahd_softc *ahd); -static void ahd_handle_message_phase(struct ahd_softc *ahd); -typedef enum { - AHDMSG_1B, - AHDMSG_2B, - AHDMSG_EXT -} ahd_msgtype; -static int ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type, - u_int msgval, int full); -static int ahd_parse_msg(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static int ahd_handle_msg_reject(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_handle_ign_wide_residue(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_reinitialize_dataptrs(struct ahd_softc *ahd); -static void ahd_handle_devreset(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - u_int lun, cam_status status, - char *message, int verbose_level); -#ifdef AHD_TARGET_MODE -static void ahd_setup_target_msgin(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo, - struct scb *scb); -#endif - -static u_int ahd_sglist_size(struct ahd_softc *ahd); -static u_int ahd_sglist_allocsize(struct ahd_softc *ahd); -static bus_dmamap_callback_t - ahd_dmamap_cb; -static void ahd_initialize_hscbs(struct ahd_softc *ahd); -static int ahd_init_scbdata(struct ahd_softc *ahd); -static void ahd_fini_scbdata(struct ahd_softc *ahd); -static void ahd_setup_iocell_workaround(struct ahd_softc *ahd); -static void ahd_iocell_first_selection(struct ahd_softc *ahd); -static void ahd_add_col_list(struct ahd_softc *ahd, - struct scb *scb, u_int col_idx); -static void ahd_rem_col_list(struct ahd_softc *ahd, - struct scb *scb); -static void ahd_chip_init(struct ahd_softc *ahd); -static void ahd_qinfifo_requeue(struct ahd_softc *ahd, - struct scb *prev_scb, - struct scb *scb); -static int ahd_qinfifo_count(struct ahd_softc *ahd); -static int ahd_search_scb_list(struct ahd_softc *ahd, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status, - ahd_search_action action, - u_int *list_head, u_int *list_tail, - u_int tid); -static void ahd_stitch_tid_list(struct ahd_softc *ahd, - u_int tid_prev, u_int tid_cur, - u_int tid_next); -static void ahd_add_scb_to_free_list(struct ahd_softc *ahd, - u_int scbid); -static u_int ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, - u_int prev, u_int next, u_int tid); -static void ahd_reset_current_bus(struct ahd_softc *ahd); -static ahd_callback_t ahd_stat_timer; -#ifdef AHD_DUMP_SEQ -static void ahd_dumpseq(struct ahd_softc *ahd); -#endif -static void ahd_loadseq(struct ahd_softc *ahd); -static int ahd_check_patch(struct ahd_softc *ahd, - const struct patch **start_patch, - u_int start_instr, u_int *skip_addr); -static u_int ahd_resolve_seqaddr(struct ahd_softc *ahd, - u_int address); -static void ahd_download_instr(struct ahd_softc *ahd, - u_int instrptr, uint8_t *dconsts); -static int ahd_probe_stack_size(struct ahd_softc *ahd); -static int ahd_scb_active_in_fifo(struct ahd_softc *ahd, - struct scb *scb); -static void ahd_run_data_fifo(struct ahd_softc *ahd, - struct scb *scb); - -#ifdef AHD_TARGET_MODE -static void ahd_queue_lstate_event(struct ahd_softc *ahd, - struct ahd_tmode_lstate *lstate, - u_int initiator_id, - u_int event_type, - u_int event_arg); -static void ahd_update_scsiid(struct ahd_softc *ahd, - u_int targid_mask); -static int ahd_handle_target_cmd(struct ahd_softc *ahd, - struct target_cmd *cmd); -#endif - -static int ahd_abort_scbs(struct ahd_softc *ahd, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status); -static void ahd_alloc_scbs(struct ahd_softc *ahd); -static void ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, - u_int scbid); -static void ahd_calc_residual(struct ahd_softc *ahd, - struct scb *scb); -static void ahd_clear_critical_section(struct ahd_softc *ahd); -static void ahd_clear_intstat(struct ahd_softc *ahd); -static void ahd_enable_coalescing(struct ahd_softc *ahd, - int enable); -static u_int ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl); -static void ahd_freeze_devq(struct ahd_softc *ahd, - struct scb *scb); -static void ahd_handle_scb_status(struct ahd_softc *ahd, - struct scb *scb); -static const struct ahd_phase_table_entry* ahd_lookup_phase_entry(int phase); -static void ahd_shutdown(void *arg); -static void ahd_update_coalescing_values(struct ahd_softc *ahd, - u_int timer, - u_int maxcmds, - u_int mincmds); -static int ahd_verify_vpd_cksum(struct vpd_config *vpd); -static int ahd_wait_seeprom(struct ahd_softc *ahd); -static int ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, - int target, char channel, int lun, - u_int tag, role_t role); - -static void ahd_reset_cmds_pending(struct ahd_softc *ahd); - -/*************************** Interrupt Services *******************************/ -static void ahd_run_qoutfifo(struct ahd_softc *ahd); -#ifdef AHD_TARGET_MODE -static void ahd_run_tqinfifo(struct ahd_softc *ahd, int paused); -#endif -static void ahd_handle_hwerrint(struct ahd_softc *ahd); -static void ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat); -static void ahd_handle_scsiint(struct ahd_softc *ahd, - u_int intstat); - -/************************ Sequencer Execution Control *************************/ -void -ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) -{ - if (ahd->src_mode == src && ahd->dst_mode == dst) - return; -#ifdef AHD_DEBUG - if (ahd->src_mode == AHD_MODE_UNKNOWN - || ahd->dst_mode == AHD_MODE_UNKNOWN) - panic("Setting mode prior to saving it.\n"); - if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) - printk("%s: Setting mode 0x%x\n", ahd_name(ahd), - ahd_build_mode_state(ahd, src, dst)); -#endif - ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst)); - ahd->src_mode = src; - ahd->dst_mode = dst; -} - -static void -ahd_update_modes(struct ahd_softc *ahd) -{ - ahd_mode_state mode_ptr; - ahd_mode src; - ahd_mode dst; - - mode_ptr = ahd_inb(ahd, MODE_PTR); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MODEPTR) != 0) - printk("Reading mode 0x%x\n", mode_ptr); -#endif - ahd_extract_mode_state(ahd, mode_ptr, &src, &dst); - ahd_known_modes(ahd, src, dst); -} - -static void -ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode, - ahd_mode dstmode, const char *file, int line) -{ -#ifdef AHD_DEBUG - if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0 - || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) { - panic("%s:%s:%d: Mode assertion failed.\n", - ahd_name(ahd), file, line); - } -#endif -} - -#define AHD_ASSERT_MODES(ahd, source, dest) \ - ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__); - -ahd_mode_state -ahd_save_modes(struct ahd_softc *ahd) -{ - if (ahd->src_mode == AHD_MODE_UNKNOWN - || ahd->dst_mode == AHD_MODE_UNKNOWN) - ahd_update_modes(ahd); - - return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode)); -} - -void -ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state) -{ - ahd_mode src; - ahd_mode dst; - - ahd_extract_mode_state(ahd, state, &src, &dst); - ahd_set_modes(ahd, src, dst); -} - -/* - * Determine whether the sequencer has halted code execution. - * Returns non-zero status if the sequencer is stopped. - */ -int -ahd_is_paused(struct ahd_softc *ahd) -{ - return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0); -} - -/* - * Request that the sequencer stop and wait, indefinitely, for it - * to stop. The sequencer will only acknowledge that it is paused - * once it has reached an instruction boundary and PAUSEDIS is - * cleared in the SEQCTL register. The sequencer may use PAUSEDIS - * for critical sections. - */ -void -ahd_pause(struct ahd_softc *ahd) -{ - ahd_outb(ahd, HCNTRL, ahd->pause); - - /* - * Since the sequencer can disable pausing in a critical section, we - * must loop until it actually stops. - */ - while (ahd_is_paused(ahd) == 0) - ; -} - -/* - * Allow the sequencer to continue program execution. - * We check here to ensure that no additional interrupt - * sources that would cause the sequencer to halt have been - * asserted. If, for example, a SCSI bus reset is detected - * while we are fielding a different, pausing, interrupt type, - * we don't want to release the sequencer before going back - * into our interrupt handler and dealing with this new - * condition. - */ -void -ahd_unpause(struct ahd_softc *ahd) -{ - /* - * Automatically restore our modes to those saved - * prior to the first change of the mode. - */ - if (ahd->saved_src_mode != AHD_MODE_UNKNOWN - && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) { - if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0) - ahd_reset_cmds_pending(ahd); - ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); - } - - if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0) - ahd_outb(ahd, HCNTRL, ahd->unpause); - - ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN); -} - -/*********************** Scatter Gather List Handling *************************/ -void * -ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, - void *sgptr, dma_addr_t addr, bus_size_t len, int last) -{ - scb->sg_count++; - if (sizeof(dma_addr_t) > 4 - && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) { - struct ahd_dma64_seg *sg; - - sg = (struct ahd_dma64_seg *)sgptr; - sg->addr = ahd_htole64(addr); - sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0)); - return (sg + 1); - } else { - struct ahd_dma_seg *sg; - - sg = (struct ahd_dma_seg *)sgptr; - sg->addr = ahd_htole32(addr & 0xFFFFFFFF); - sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000) - | (last ? AHD_DMA_LAST_SEG : 0)); - return (sg + 1); - } -} - -static void -ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb) -{ - /* XXX Handle target mode SCBs. */ - scb->crc_retry_count = 0; - if ((scb->flags & SCB_PACKETIZED) != 0) { - /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ - scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE; - } else { - if (ahd_get_transfer_length(scb) & 0x01) - scb->hscb->task_attribute = SCB_XFERLEN_ODD; - else - scb->hscb->task_attribute = 0; - } - - if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR - || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0) - scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr = - ahd_htole32(scb->sense_busaddr); -} - -static void -ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb) -{ - /* - * Copy the first SG into the "current" data ponter area. - */ - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { - struct ahd_dma64_seg *sg; - - sg = (struct ahd_dma64_seg *)scb->sg_list; - scb->hscb->dataptr = sg->addr; - scb->hscb->datacnt = sg->len; - } else { - struct ahd_dma_seg *sg; - uint32_t *dataptr_words; - - sg = (struct ahd_dma_seg *)scb->sg_list; - dataptr_words = (uint32_t*)&scb->hscb->dataptr; - dataptr_words[0] = sg->addr; - dataptr_words[1] = 0; - if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { - uint64_t high_addr; - - high_addr = ahd_le32toh(sg->len) & 0x7F000000; - scb->hscb->dataptr |= ahd_htole64(high_addr << 8); - } - scb->hscb->datacnt = sg->len; - } - /* - * Note where to find the SG entries in bus space. - * We also set the full residual flag which the - * sequencer will clear as soon as a data transfer - * occurs. - */ - scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID); -} - -static void -ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb) -{ - scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL); - scb->hscb->dataptr = 0; - scb->hscb->datacnt = 0; -} - -/************************** Memory mapping routines ***************************/ -static void * -ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr) -{ - dma_addr_t sg_offset; - - /* sg_list_phys points to entry 1, not 0 */ - sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd)); - return ((uint8_t *)scb->sg_list + sg_offset); -} - -static uint32_t -ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg) -{ - dma_addr_t sg_offset; - - /* sg_list_phys points to entry 1, not 0 */ - sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list) - - ahd_sg_size(ahd); - - return (scb->sg_list_busaddr + sg_offset); -} - -static void -ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op) -{ - ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat, - scb->hscb_map->dmamap, - /*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr, - /*len*/sizeof(*scb->hscb), op); -} - -void -ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op) -{ - if (scb->sg_count == 0) - return; - - ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat, - scb->sg_map->dmamap, - /*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd), - /*len*/ahd_sg_size(ahd) * scb->sg_count, op); -} - -static void -ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op) -{ - ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat, - scb->sense_map->dmamap, - /*offset*/scb->sense_busaddr, - /*len*/AHD_SENSE_BUFSIZE, op); -} - -#ifdef AHD_TARGET_MODE -static uint32_t -ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index) -{ - return (((uint8_t *)&ahd->targetcmds[index]) - - (uint8_t *)ahd->qoutfifo); -} -#endif - -/*********************** Miscellaneous Support Functions ***********************/ -/* - * Return pointers to the transfer negotiation information - * for the specified our_id/remote_id pair. - */ -struct ahd_initiator_tinfo * -ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id, - u_int remote_id, struct ahd_tmode_tstate **tstate) -{ - /* - * Transfer data structures are stored from the perspective - * of the target role. Since the parameters for a connection - * in the initiator role to a given target are the same as - * when the roles are reversed, we pretend we are the target. - */ - if (channel == 'B') - our_id += 8; - *tstate = ahd->enabled_targets[our_id]; - return (&(*tstate)->transinfo[remote_id]); -} - -uint16_t -ahd_inw(struct ahd_softc *ahd, u_int port) -{ - /* - * Read high byte first as some registers increment - * or have other side effects when the low byte is - * read. - */ - uint16_t r = ahd_inb(ahd, port+1) << 8; - return r | ahd_inb(ahd, port); -} - -void -ahd_outw(struct ahd_softc *ahd, u_int port, u_int value) -{ - /* - * Write low byte first to accommodate registers - * such as PRGMCNT where the order maters. - */ - ahd_outb(ahd, port, value & 0xFF); - ahd_outb(ahd, port+1, (value >> 8) & 0xFF); -} - -uint32_t -ahd_inl(struct ahd_softc *ahd, u_int port) -{ - return ((ahd_inb(ahd, port)) - | (ahd_inb(ahd, port+1) << 8) - | (ahd_inb(ahd, port+2) << 16) - | (ahd_inb(ahd, port+3) << 24)); -} - -void -ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value) -{ - ahd_outb(ahd, port, (value) & 0xFF); - ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF); - ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF); - ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF); -} - -uint64_t -ahd_inq(struct ahd_softc *ahd, u_int port) -{ - return ((ahd_inb(ahd, port)) - | (ahd_inb(ahd, port+1) << 8) - | (ahd_inb(ahd, port+2) << 16) - | (ahd_inb(ahd, port+3) << 24) - | (((uint64_t)ahd_inb(ahd, port+4)) << 32) - | (((uint64_t)ahd_inb(ahd, port+5)) << 40) - | (((uint64_t)ahd_inb(ahd, port+6)) << 48) - | (((uint64_t)ahd_inb(ahd, port+7)) << 56)); -} - -void -ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value) -{ - ahd_outb(ahd, port, value & 0xFF); - ahd_outb(ahd, port+1, (value >> 8) & 0xFF); - ahd_outb(ahd, port+2, (value >> 16) & 0xFF); - ahd_outb(ahd, port+3, (value >> 24) & 0xFF); - ahd_outb(ahd, port+4, (value >> 32) & 0xFF); - ahd_outb(ahd, port+5, (value >> 40) & 0xFF); - ahd_outb(ahd, port+6, (value >> 48) & 0xFF); - ahd_outb(ahd, port+7, (value >> 56) & 0xFF); -} - -u_int -ahd_get_scbptr(struct ahd_softc *ahd) -{ - AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), - ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); - return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8)); -} - -void -ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr) -{ - AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), - ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); - ahd_outb(ahd, SCBPTR, scbptr & 0xFF); - ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF); -} - -#if 0 /* unused */ -static u_int -ahd_get_hnscb_qoff(struct ahd_softc *ahd) -{ - return (ahd_inw_atomic(ahd, HNSCB_QOFF)); -} -#endif - -static void -ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value) -{ - ahd_outw_atomic(ahd, HNSCB_QOFF, value); -} - -#if 0 /* unused */ -static u_int -ahd_get_hescb_qoff(struct ahd_softc *ahd) -{ - return (ahd_inb(ahd, HESCB_QOFF)); -} -#endif - -static void -ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value) -{ - ahd_outb(ahd, HESCB_QOFF, value); -} - -static u_int -ahd_get_snscb_qoff(struct ahd_softc *ahd) -{ - u_int oldvalue; - - AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); - oldvalue = ahd_inw(ahd, SNSCB_QOFF); - ahd_outw(ahd, SNSCB_QOFF, oldvalue); - return (oldvalue); -} - -static void -ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value) -{ - AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); - ahd_outw(ahd, SNSCB_QOFF, value); -} - -#if 0 /* unused */ -static u_int -ahd_get_sescb_qoff(struct ahd_softc *ahd) -{ - AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); - return (ahd_inb(ahd, SESCB_QOFF)); -} -#endif - -static void -ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value) -{ - AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); - ahd_outb(ahd, SESCB_QOFF, value); -} - -#if 0 /* unused */ -static u_int -ahd_get_sdscb_qoff(struct ahd_softc *ahd) -{ - AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); - return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8)); -} -#endif - -static void -ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value) -{ - AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); - ahd_outb(ahd, SDSCB_QOFF, value & 0xFF); - ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF); -} - -u_int -ahd_inb_scbram(struct ahd_softc *ahd, u_int offset) -{ - u_int value; - - /* - * Workaround PCI-X Rev A. hardware bug. - * After a host read of SCB memory, the chip - * may become confused into thinking prefetch - * was required. This starts the discard timer - * running and can cause an unexpected discard - * timer interrupt. The work around is to read - * a normal register prior to the exhaustion of - * the discard timer. The mode pointer register - * has no side effects and so serves well for - * this purpose. - * - * Razor #528 - */ - value = ahd_inb(ahd, offset); - if ((ahd->bugs & AHD_PCIX_SCBRAM_RD_BUG) != 0) - ahd_inb(ahd, MODE_PTR); - return (value); -} - -u_int -ahd_inw_scbram(struct ahd_softc *ahd, u_int offset) -{ - return (ahd_inb_scbram(ahd, offset) - | (ahd_inb_scbram(ahd, offset+1) << 8)); -} - -static uint32_t -ahd_inl_scbram(struct ahd_softc *ahd, u_int offset) -{ - return (ahd_inw_scbram(ahd, offset) - | (ahd_inw_scbram(ahd, offset+2) << 16)); -} - -static uint64_t -ahd_inq_scbram(struct ahd_softc *ahd, u_int offset) -{ - return (ahd_inl_scbram(ahd, offset) - | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32); -} - -struct scb * -ahd_lookup_scb(struct ahd_softc *ahd, u_int tag) -{ - struct scb* scb; - - if (tag >= AHD_SCB_MAX) - return (NULL); - scb = ahd->scb_data.scbindex[tag]; - if (scb != NULL) - ahd_sync_scb(ahd, scb, - BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - return (scb); -} - -static void -ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb) -{ - struct hardware_scb *q_hscb; - struct map_node *q_hscb_map; - uint32_t saved_hscb_busaddr; - - /* - * Our queuing method is a bit tricky. The card - * knows in advance which HSCB (by address) to download, - * and we can't disappoint it. To achieve this, the next - * HSCB to download is saved off in ahd->next_queued_hscb. - * When we are called to queue "an arbitrary scb", - * we copy the contents of the incoming HSCB to the one - * the sequencer knows about, swap HSCB pointers and - * finally assign the SCB to the tag indexed location - * in the scb_array. This makes sure that we can still - * locate the correct SCB by SCB_TAG. - */ - q_hscb = ahd->next_queued_hscb; - q_hscb_map = ahd->next_queued_hscb_map; - saved_hscb_busaddr = q_hscb->hscb_busaddr; - memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); - q_hscb->hscb_busaddr = saved_hscb_busaddr; - q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; - - /* Now swap HSCB pointers. */ - ahd->next_queued_hscb = scb->hscb; - ahd->next_queued_hscb_map = scb->hscb_map; - scb->hscb = q_hscb; - scb->hscb_map = q_hscb_map; - - /* Now define the mapping from tag to SCB in the scbindex */ - ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb; -} - -/* - * Tell the sequencer about a new transaction to execute. - */ -void -ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb) -{ - ahd_swap_with_next_hscb(ahd, scb); - - if (SCBID_IS_NULL(SCB_GET_TAG(scb))) - panic("Attempt to queue invalid SCB tag %x\n", - SCB_GET_TAG(scb)); - - /* - * Keep a history of SCBs we've downloaded in the qinfifo. - */ - ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); - ahd->qinfifonext++; - - if (scb->sg_count != 0) - ahd_setup_data_scb(ahd, scb); - else - ahd_setup_noxfer_scb(ahd, scb); - ahd_setup_scb_common(ahd, scb); - - /* - * Make sure our data is consistent from the - * perspective of the adapter. - */ - ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_QUEUE) != 0) { - uint64_t host_dataptr; - - host_dataptr = ahd_le64toh(scb->hscb->dataptr); - printk("%s: Queueing SCB %d:0x%x bus addr 0x%x - 0x%x%x/0x%x\n", - ahd_name(ahd), - SCB_GET_TAG(scb), scb->hscb->scsiid, - ahd_le32toh(scb->hscb->hscb_busaddr), - (u_int)((host_dataptr >> 32) & 0xFFFFFFFF), - (u_int)(host_dataptr & 0xFFFFFFFF), - ahd_le32toh(scb->hscb->datacnt)); - } -#endif - /* Tell the adapter about the newly queued SCB */ - ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); -} - -/************************** Interrupt Processing ******************************/ -static void -ahd_sync_qoutfifo(struct ahd_softc *ahd, int op) -{ - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, - /*offset*/0, - /*len*/AHD_SCB_MAX * sizeof(struct ahd_completion), op); -} - -static void -ahd_sync_tqinfifo(struct ahd_softc *ahd, int op) -{ -#ifdef AHD_TARGET_MODE - if ((ahd->flags & AHD_TARGETROLE) != 0) { - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, - ahd->shared_data_map.dmamap, - ahd_targetcmd_offset(ahd, 0), - sizeof(struct target_cmd) * AHD_TMODE_CMDS, - op); - } -#endif -} - -/* - * See if the firmware has posted any completed commands - * into our in-core command complete fifos. - */ -#define AHD_RUN_QOUTFIFO 0x1 -#define AHD_RUN_TQINFIFO 0x2 -static u_int -ahd_check_cmdcmpltqueues(struct ahd_softc *ahd) -{ - u_int retval; - - retval = 0; - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, - /*offset*/ahd->qoutfifonext * sizeof(*ahd->qoutfifo), - /*len*/sizeof(*ahd->qoutfifo), BUS_DMASYNC_POSTREAD); - if (ahd->qoutfifo[ahd->qoutfifonext].valid_tag - == ahd->qoutfifonext_valid_tag) - retval |= AHD_RUN_QOUTFIFO; -#ifdef AHD_TARGET_MODE - if ((ahd->flags & AHD_TARGETROLE) != 0 - && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) { - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, - ahd->shared_data_map.dmamap, - ahd_targetcmd_offset(ahd, ahd->tqinfifofnext), - /*len*/sizeof(struct target_cmd), - BUS_DMASYNC_POSTREAD); - if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0) - retval |= AHD_RUN_TQINFIFO; - } -#endif - return (retval); -} - -/* - * Catch an interrupt from the adapter - */ -int -ahd_intr(struct ahd_softc *ahd) -{ - u_int intstat; - - if ((ahd->pause & INTEN) == 0) { - /* - * Our interrupt is not enabled on the chip - * and may be disabled for re-entrancy reasons, - * so just return. This is likely just a shared - * interrupt. - */ - return (0); - } - - /* - * Instead of directly reading the interrupt status register, - * infer the cause of the interrupt by checking our in-core - * completion queues. This avoids a costly PCI bus read in - * most cases. - */ - if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0 - && (ahd_check_cmdcmpltqueues(ahd) != 0)) - intstat = CMDCMPLT; - else - intstat = ahd_inb(ahd, INTSTAT); - - if ((intstat & INT_PEND) == 0) - return (0); - - if (intstat & CMDCMPLT) { - ahd_outb(ahd, CLRINT, CLRCMDINT); - - /* - * Ensure that the chip sees that we've cleared - * this interrupt before we walk the output fifo. - * Otherwise, we may, due to posted bus writes, - * clear the interrupt after we finish the scan, - * and after the sequencer has added new entries - * and asserted the interrupt again. - */ - if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { - if (ahd_is_paused(ahd)) { - /* - * Potentially lost SEQINT. - * If SEQINTCODE is non-zero, - * simulate the SEQINT. - */ - if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT) - intstat |= SEQINT; - } - } else { - ahd_flush_device_writes(ahd); - } - ahd_run_qoutfifo(ahd); - ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++; - ahd->cmdcmplt_total++; -#ifdef AHD_TARGET_MODE - if ((ahd->flags & AHD_TARGETROLE) != 0) - ahd_run_tqinfifo(ahd, /*paused*/FALSE); -#endif - } - - /* - * Handle statuses that may invalidate our cached - * copy of INTSTAT separately. - */ - if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) { - /* Hot eject. Do nothing */ - } else if (intstat & HWERRINT) { - ahd_handle_hwerrint(ahd); - } else if ((intstat & (PCIINT|SPLTINT)) != 0) { - ahd->bus_intr(ahd); - } else { - - if ((intstat & SEQINT) != 0) - ahd_handle_seqint(ahd, intstat); - - if ((intstat & SCSIINT) != 0) - ahd_handle_scsiint(ahd, intstat); - } - return (1); -} - -/******************************** Private Inlines *****************************/ -static inline void -ahd_assert_atn(struct ahd_softc *ahd) -{ - ahd_outb(ahd, SCSISIGO, ATNO); -} - -/* - * Determine if the current connection has a packetized - * agreement. This does not necessarily mean that we - * are currently in a packetized transfer. We could - * just as easily be sending or receiving a message. - */ -static int -ahd_currently_packetized(struct ahd_softc *ahd) -{ - ahd_mode_state saved_modes; - int packetized; - - saved_modes = ahd_save_modes(ahd); - if ((ahd->bugs & AHD_PKTIZED_STATUS_BUG) != 0) { - /* - * The packetized bit refers to the last - * connection, not the current one. Check - * for non-zero LQISTATE instead. - */ - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - packetized = ahd_inb(ahd, LQISTATE) != 0; - } else { - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - packetized = ahd_inb(ahd, LQISTAT2) & PACKETIZED; - } - ahd_restore_modes(ahd, saved_modes); - return (packetized); -} - -static inline int -ahd_set_active_fifo(struct ahd_softc *ahd) -{ - u_int active_fifo; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - active_fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO; - switch (active_fifo) { - case 0: - case 1: - ahd_set_modes(ahd, active_fifo, active_fifo); - return (1); - default: - return (0); - } -} - -static inline void -ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl) -{ - ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL); -} - -/* - * Determine whether the sequencer reported a residual - * for this SCB/transaction. - */ -static inline void -ahd_update_residual(struct ahd_softc *ahd, struct scb *scb) -{ - uint32_t sgptr; - - sgptr = ahd_le32toh(scb->hscb->sgptr); - if ((sgptr & SG_STATUS_VALID) != 0) - ahd_calc_residual(ahd, scb); -} - -static inline void -ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb) -{ - uint32_t sgptr; - - sgptr = ahd_le32toh(scb->hscb->sgptr); - if ((sgptr & SG_STATUS_VALID) != 0) - ahd_handle_scb_status(ahd, scb); - else - ahd_done(ahd, scb); -} - - -/************************* Sequencer Execution Control ************************/ -/* - * Restart the sequencer program from address zero - */ -static void -ahd_restart(struct ahd_softc *ahd) -{ - - ahd_pause(ahd); - - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - - /* No more pending messages */ - ahd_clear_msg_state(ahd); - ahd_outb(ahd, SCSISIGO, 0); /* De-assert BSY */ - ahd_outb(ahd, MSG_OUT, MSG_NOOP); /* No message to send */ - ahd_outb(ahd, SXFRCTL1, ahd_inb(ahd, SXFRCTL1) & ~BITBUCKET); - ahd_outb(ahd, SEQINTCTL, 0); - ahd_outb(ahd, LASTPHASE, P_BUSFREE); - ahd_outb(ahd, SEQ_FLAGS, 0); - ahd_outb(ahd, SAVED_SCSIID, 0xFF); - ahd_outb(ahd, SAVED_LUN, 0xFF); - - /* - * Ensure that the sequencer's idea of TQINPOS - * matches our own. The sequencer increments TQINPOS - * only after it sees a DMA complete and a reset could - * occur before the increment leaving the kernel to believe - * the command arrived but the sequencer to not. - */ - ahd_outb(ahd, TQINPOS, ahd->tqinfifonext); - - /* Always allow reselection */ - ahd_outb(ahd, SCSISEQ1, - ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); - ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); - - /* - * Clear any pending sequencer interrupt. It is no - * longer relevant since we're resetting the Program - * Counter. - */ - ahd_outb(ahd, CLRINT, CLRSEQINT); - - ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET); - ahd_unpause(ahd); -} - -static void -ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo) -{ - ahd_mode_state saved_modes; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_FIFOS) != 0) - printk("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo); -#endif - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, fifo, fifo); - ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT); - if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) - ahd_outb(ahd, CCSGCTL, CCSGRESET); - ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); - ahd_outb(ahd, SG_STATE, 0); - ahd_restore_modes(ahd, saved_modes); -} - -/************************* Input/Output Queues ********************************/ -/* - * Flush and completed commands that are sitting in the command - * complete queues down on the chip but have yet to be dma'ed back up. - */ -static void -ahd_flush_qoutfifo(struct ahd_softc *ahd) -{ - struct scb *scb; - ahd_mode_state saved_modes; - u_int saved_scbptr; - u_int ccscbctl; - u_int scbid; - u_int next_scbid; - - saved_modes = ahd_save_modes(ahd); - - /* - * Flush the good status FIFO for completed packetized commands. - */ - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - saved_scbptr = ahd_get_scbptr(ahd); - while ((ahd_inb(ahd, LQISTAT2) & LQIGSAVAIL) != 0) { - u_int fifo_mode; - u_int i; - - scbid = ahd_inw(ahd, GSFIFO); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("%s: Warning - GSFIFO SCB %d invalid\n", - ahd_name(ahd), scbid); - continue; - } - /* - * Determine if this transaction is still active in - * any FIFO. If it is, we must flush that FIFO to - * the host before completing the command. - */ - fifo_mode = 0; -rescan_fifos: - for (i = 0; i < 2; i++) { - /* Toggle to the other mode. */ - fifo_mode ^= 1; - ahd_set_modes(ahd, fifo_mode, fifo_mode); - - if (ahd_scb_active_in_fifo(ahd, scb) == 0) - continue; - - ahd_run_data_fifo(ahd, scb); - - /* - * Running this FIFO may cause a CFG4DATA for - * this same transaction to assert in the other - * FIFO or a new snapshot SAVEPTRS interrupt - * in this FIFO. Even running a FIFO may not - * clear the transaction if we are still waiting - * for data to drain to the host. We must loop - * until the transaction is not active in either - * FIFO just to be sure. Reset our loop counter - * so we will visit both FIFOs again before - * declaring this transaction finished. We - * also delay a bit so that status has a chance - * to change before we look at this FIFO again. - */ - ahd_delay(200); - goto rescan_fifos; - } - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_set_scbptr(ahd, scbid); - if ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_LIST_NULL) == 0 - && ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_FULL_RESID) != 0 - || (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR) - & SG_LIST_NULL) != 0)) { - u_int comp_head; - - /* - * The transfer completed with a residual. - * Place this SCB on the complete DMA list - * so that we update our in-core copy of the - * SCB before completing the command. - */ - ahd_outb(ahd, SCB_SCSI_STATUS, 0); - ahd_outb(ahd, SCB_SGPTR, - ahd_inb_scbram(ahd, SCB_SGPTR) - | SG_STATUS_VALID); - ahd_outw(ahd, SCB_TAG, scbid); - ahd_outw(ahd, SCB_NEXT_COMPLETE, SCB_LIST_NULL); - comp_head = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); - if (SCBID_IS_NULL(comp_head)) { - ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, scbid); - ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid); - } else { - u_int tail; - - tail = ahd_inw(ahd, COMPLETE_DMA_SCB_TAIL); - ahd_set_scbptr(ahd, tail); - ahd_outw(ahd, SCB_NEXT_COMPLETE, scbid); - ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, scbid); - ahd_set_scbptr(ahd, scbid); - } - } else - ahd_complete_scb(ahd, scb); - } - ahd_set_scbptr(ahd, saved_scbptr); - - /* - * Setup for command channel portion of flush. - */ - ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); - - /* - * Wait for any inprogress DMA to complete and clear DMA state - * if this if for an SCB in the qinfifo. - */ - while (((ccscbctl = ahd_inb(ahd, CCSCBCTL)) & (CCARREN|CCSCBEN)) != 0) { - - if ((ccscbctl & (CCSCBDIR|CCARREN)) == (CCSCBDIR|CCARREN)) { - if ((ccscbctl & ARRDONE) != 0) - break; - } else if ((ccscbctl & CCSCBDONE) != 0) - break; - ahd_delay(200); - } - /* - * We leave the sequencer to cleanup in the case of DMA's to - * update the qoutfifo. In all other cases (DMA's to the - * chip or a push of an SCB from the COMPLETE_DMA_SCB list), - * we disable the DMA engine so that the sequencer will not - * attempt to handle the DMA completion. - */ - if ((ccscbctl & CCSCBDIR) != 0 || (ccscbctl & ARRDONE) != 0) - ahd_outb(ahd, CCSCBCTL, ccscbctl & ~(CCARREN|CCSCBEN)); - - /* - * Complete any SCBs that just finished - * being DMA'ed into the qoutfifo. - */ - ahd_run_qoutfifo(ahd); - - saved_scbptr = ahd_get_scbptr(ahd); - /* - * Manually update/complete any completed SCBs that are waiting to be - * DMA'ed back up to the host. - */ - scbid = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); - while (!SCBID_IS_NULL(scbid)) { - uint8_t *hscb_ptr; - u_int i; - - ahd_set_scbptr(ahd, scbid); - next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("%s: Warning - DMA-up and complete " - "SCB %d invalid\n", ahd_name(ahd), scbid); - continue; - } - hscb_ptr = (uint8_t *)scb->hscb; - for (i = 0; i < sizeof(struct hardware_scb); i++) - *hscb_ptr++ = ahd_inb_scbram(ahd, SCB_BASE + i); - - ahd_complete_scb(ahd, scb); - scbid = next_scbid; - } - ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL); - ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL); - - scbid = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD); - while (!SCBID_IS_NULL(scbid)) { - - ahd_set_scbptr(ahd, scbid); - next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("%s: Warning - Complete Qfrz SCB %d invalid\n", - ahd_name(ahd), scbid); - continue; - } - - ahd_complete_scb(ahd, scb); - scbid = next_scbid; - } - ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL); - - scbid = ahd_inw(ahd, COMPLETE_SCB_HEAD); - while (!SCBID_IS_NULL(scbid)) { - - ahd_set_scbptr(ahd, scbid); - next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("%s: Warning - Complete SCB %d invalid\n", - ahd_name(ahd), scbid); - continue; - } - - ahd_complete_scb(ahd, scb); - scbid = next_scbid; - } - ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL); - - /* - * Restore state. - */ - ahd_set_scbptr(ahd, saved_scbptr); - ahd_restore_modes(ahd, saved_modes); - ahd->flags |= AHD_UPDATE_PEND_CMDS; -} - -/* - * Determine if an SCB for a packetized transaction - * is active in a FIFO. - */ -static int -ahd_scb_active_in_fifo(struct ahd_softc *ahd, struct scb *scb) -{ - - /* - * The FIFO is only active for our transaction if - * the SCBPTR matches the SCB's ID and the firmware - * has installed a handler for the FIFO or we have - * a pending SAVEPTRS or CFG4DATA interrupt. - */ - if (ahd_get_scbptr(ahd) != SCB_GET_TAG(scb) - || ((ahd_inb(ahd, LONGJMP_ADDR+1) & INVALID_ADDR) != 0 - && (ahd_inb(ahd, SEQINTSRC) & (CFG4DATA|SAVEPTRS)) == 0)) - return (0); - - return (1); -} - -/* - * Run a data fifo to completion for a transaction we know - * has completed across the SCSI bus (good status has been - * received). We are already set to the correct FIFO mode - * on entry to this routine. - * - * This function attempts to operate exactly as the firmware - * would when running this FIFO. Care must be taken to update - * this routine any time the firmware's FIFO algorithm is - * changed. - */ -static void -ahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb) -{ - u_int seqintsrc; - - seqintsrc = ahd_inb(ahd, SEQINTSRC); - if ((seqintsrc & CFG4DATA) != 0) { - uint32_t datacnt; - uint32_t sgptr; - - /* - * Clear full residual flag. - */ - sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID; - ahd_outb(ahd, SCB_SGPTR, sgptr); - - /* - * Load datacnt and address. - */ - datacnt = ahd_inl_scbram(ahd, SCB_DATACNT); - if ((datacnt & AHD_DMA_LAST_SEG) != 0) { - sgptr |= LAST_SEG; - ahd_outb(ahd, SG_STATE, 0); - } else - ahd_outb(ahd, SG_STATE, LOADING_NEEDED); - ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR)); - ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK); - ahd_outb(ahd, SG_CACHE_PRE, sgptr); - ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN); - - /* - * Initialize Residual Fields. - */ - ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24); - ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK); - - /* - * Mark the SCB as having a FIFO in use. - */ - ahd_outb(ahd, SCB_FIFO_USE_COUNT, - ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1); - - /* - * Install a "fake" handler for this FIFO. - */ - ahd_outw(ahd, LONGJMP_ADDR, 0); - - /* - * Notify the hardware that we have satisfied - * this sequencer interrupt. - */ - ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA); - } else if ((seqintsrc & SAVEPTRS) != 0) { - uint32_t sgptr; - uint32_t resid; - - if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) { - /* - * Snapshot Save Pointers. All that - * is necessary to clear the snapshot - * is a CLRCHN. - */ - goto clrchn; - } - - /* - * Disable S/G fetch so the DMA engine - * is available to future users. - */ - if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) - ahd_outb(ahd, CCSGCTL, 0); - ahd_outb(ahd, SG_STATE, 0); - - /* - * Flush the data FIFO. Strickly only - * necessary for Rev A parts. - */ - ahd_outb(ahd, DFCNTRL, ahd_inb(ahd, DFCNTRL) | FIFOFLUSH); - - /* - * Calculate residual. - */ - sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); - resid = ahd_inl(ahd, SHCNT); - resid |= ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24; - ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid); - if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) { - /* - * Must back up to the correct S/G element. - * Typically this just means resetting our - * low byte to the offset in the SG_CACHE, - * but if we wrapped, we have to correct - * the other bytes of the sgptr too. - */ - if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0 - && (sgptr & 0x80) == 0) - sgptr -= 0x100; - sgptr &= ~0xFF; - sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW) - & SG_ADDR_MASK; - ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); - ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0); - } else if ((resid & AHD_SG_LEN_MASK) == 0) { - ahd_outb(ahd, SCB_RESIDUAL_SGPTR, - sgptr | SG_LIST_NULL); - } - /* - * Save Pointers. - */ - ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR)); - ahd_outl(ahd, SCB_DATACNT, resid); - ahd_outl(ahd, SCB_SGPTR, sgptr); - ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS); - ahd_outb(ahd, SEQIMODE, - ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS); - /* - * If the data is to the SCSI bus, we are - * done, otherwise wait for FIFOEMP. - */ - if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0) - goto clrchn; - } else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) { - uint32_t sgptr; - uint64_t data_addr; - uint32_t data_len; - u_int dfcntrl; - - /* - * Disable S/G fetch so the DMA engine - * is available to future users. We won't - * be using the DMA engine to load segments. - */ - if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) { - ahd_outb(ahd, CCSGCTL, 0); - ahd_outb(ahd, SG_STATE, LOADING_NEEDED); - } - - /* - * Wait for the DMA engine to notice that the - * host transfer is enabled and that there is - * space in the S/G FIFO for new segments before - * loading more segments. - */ - if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) != 0 - && (ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) { - - /* - * Determine the offset of the next S/G - * element to load. - */ - sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); - sgptr &= SG_PTR_MASK; - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { - struct ahd_dma64_seg *sg; - - sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); - data_addr = sg->addr; - data_len = sg->len; - sgptr += sizeof(*sg); - } else { - struct ahd_dma_seg *sg; - - sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); - data_addr = sg->len & AHD_SG_HIGH_ADDR_MASK; - data_addr <<= 8; - data_addr |= sg->addr; - data_len = sg->len; - sgptr += sizeof(*sg); - } - - /* - * Update residual information. - */ - ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, data_len >> 24); - ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); - - /* - * Load the S/G. - */ - if (data_len & AHD_DMA_LAST_SEG) { - sgptr |= LAST_SEG; - ahd_outb(ahd, SG_STATE, 0); - } - ahd_outq(ahd, HADDR, data_addr); - ahd_outl(ahd, HCNT, data_len & AHD_SG_LEN_MASK); - ahd_outb(ahd, SG_CACHE_PRE, sgptr & 0xFF); - - /* - * Advertise the segment to the hardware. - */ - dfcntrl = ahd_inb(ahd, DFCNTRL)|PRELOADEN|HDMAEN; - if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) { - /* - * Use SCSIENWRDIS so that SCSIEN - * is never modified by this - * operation. - */ - dfcntrl |= SCSIENWRDIS; - } - ahd_outb(ahd, DFCNTRL, dfcntrl); - } - } else if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG_DONE) != 0) { - - /* - * Transfer completed to the end of SG list - * and has flushed to the host. - */ - ahd_outb(ahd, SCB_SGPTR, - ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL); - goto clrchn; - } else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) { -clrchn: - /* - * Clear any handler for this FIFO, decrement - * the FIFO use count for the SCB, and release - * the FIFO. - */ - ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); - ahd_outb(ahd, SCB_FIFO_USE_COUNT, - ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1); - ahd_outb(ahd, DFFSXFRCTL, CLRCHN); - } -} - -/* - * Look for entries in the QoutFIFO that have completed. - * The valid_tag completion field indicates the validity - * of the entry - the valid value toggles each time through - * the queue. We use the sg_status field in the completion - * entry to avoid referencing the hscb if the completion - * occurred with no errors and no residual. sg_status is - * a copy of the first byte (little endian) of the sgptr - * hscb field. - */ -static void -ahd_run_qoutfifo(struct ahd_softc *ahd) -{ - struct ahd_completion *completion; - struct scb *scb; - u_int scb_index; - - if ((ahd->flags & AHD_RUNNING_QOUTFIFO) != 0) - panic("ahd_run_qoutfifo recursion"); - ahd->flags |= AHD_RUNNING_QOUTFIFO; - ahd_sync_qoutfifo(ahd, BUS_DMASYNC_POSTREAD); - for (;;) { - completion = &ahd->qoutfifo[ahd->qoutfifonext]; - - if (completion->valid_tag != ahd->qoutfifonext_valid_tag) - break; - - scb_index = ahd_le16toh(completion->tag); - scb = ahd_lookup_scb(ahd, scb_index); - if (scb == NULL) { - printk("%s: WARNING no command for scb %d " - "(cmdcmplt)\nQOUTPOS = %d\n", - ahd_name(ahd), scb_index, - ahd->qoutfifonext); - ahd_dump_card_state(ahd); - } else if ((completion->sg_status & SG_STATUS_VALID) != 0) { - ahd_handle_scb_status(ahd, scb); - } else { - ahd_done(ahd, scb); - } - - ahd->qoutfifonext = (ahd->qoutfifonext+1) & (AHD_QOUT_SIZE-1); - if (ahd->qoutfifonext == 0) - ahd->qoutfifonext_valid_tag ^= QOUTFIFO_ENTRY_VALID; - } - ahd->flags &= ~AHD_RUNNING_QOUTFIFO; -} - -/************************* Interrupt Handling *********************************/ -static void -ahd_handle_hwerrint(struct ahd_softc *ahd) -{ - /* - * Some catastrophic hardware error has occurred. - * Print it for the user and disable the controller. - */ - int i; - int error; - - error = ahd_inb(ahd, ERROR); - for (i = 0; i < num_errors; i++) { - if ((error & ahd_hard_errors[i].errno) != 0) - printk("%s: hwerrint, %s\n", - ahd_name(ahd), ahd_hard_errors[i].errmesg); - } - - ahd_dump_card_state(ahd); - panic("BRKADRINT"); - - /* Tell everyone that this HBA is no longer available */ - ahd_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, - CAM_NO_HBA); - - /* Tell the system that this controller has gone away. */ - ahd_free(ahd); -} - -#ifdef AHD_DEBUG -static void -ahd_dump_sglist(struct scb *scb) -{ - int i; - - if (scb->sg_count > 0) { - if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) { - struct ahd_dma64_seg *sg_list; - - sg_list = (struct ahd_dma64_seg*)scb->sg_list; - for (i = 0; i < scb->sg_count; i++) { - uint64_t addr; - uint32_t len; - - addr = ahd_le64toh(sg_list[i].addr); - len = ahd_le32toh(sg_list[i].len); - printk("sg[%d] - Addr 0x%x%x : Length %d%s\n", - i, - (uint32_t)((addr >> 32) & 0xFFFFFFFF), - (uint32_t)(addr & 0xFFFFFFFF), - sg_list[i].len & AHD_SG_LEN_MASK, - (sg_list[i].len & AHD_DMA_LAST_SEG) - ? " Last" : ""); - } - } else { - struct ahd_dma_seg *sg_list; - - sg_list = (struct ahd_dma_seg*)scb->sg_list; - for (i = 0; i < scb->sg_count; i++) { - uint32_t len; - - len = ahd_le32toh(sg_list[i].len); - printk("sg[%d] - Addr 0x%x%x : Length %d%s\n", - i, - (len & AHD_SG_HIGH_ADDR_MASK) >> 24, - ahd_le32toh(sg_list[i].addr), - len & AHD_SG_LEN_MASK, - len & AHD_DMA_LAST_SEG ? " Last" : ""); - } - } - } -} -#endif /* AHD_DEBUG */ - -static void -ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat) -{ - u_int seqintcode; - - /* - * Save the sequencer interrupt code and clear the SEQINT - * bit. We will unpause the sequencer, if appropriate, - * after servicing the request. - */ - seqintcode = ahd_inb(ahd, SEQINTCODE); - ahd_outb(ahd, CLRINT, CLRSEQINT); - if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) { - /* - * Unpause the sequencer and let it clear - * SEQINT by writing NO_SEQINT to it. This - * will cause the sequencer to be paused again, - * which is the expected state of this routine. - */ - ahd_unpause(ahd); - while (!ahd_is_paused(ahd)) - ; - ahd_outb(ahd, CLRINT, CLRSEQINT); - } - ahd_update_modes(ahd); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) - printk("%s: Handle Seqint Called for code %d\n", - ahd_name(ahd), seqintcode); -#endif - switch (seqintcode) { - case ENTERING_NONPACK: - { - struct scb *scb; - u_int scbid; - - AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), - ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - /* - * Somehow need to know if this - * is from a selection or reselection. - * From that, we can determine target - * ID so we at least have an I_T nexus. - */ - } else { - ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); - ahd_outb(ahd, SAVED_LUN, scb->hscb->lun); - ahd_outb(ahd, SEQ_FLAGS, 0x0); - } - if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0 - && (ahd_inb(ahd, SCSISIGO) & ATNO) != 0) { - /* - * Phase change after read stream with - * CRC error with P0 asserted on last - * packet. - */ -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printk("%s: Assuming LQIPHASE_NLQ with " - "P0 assertion\n", ahd_name(ahd)); -#endif - } -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printk("%s: Entering NONPACK\n", ahd_name(ahd)); -#endif - break; - } - case INVALID_SEQINT: - printk("%s: Invalid Sequencer interrupt occurred, " - "resetting channel.\n", - ahd_name(ahd)); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - ahd_dump_card_state(ahd); -#endif - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - break; - case STATUS_OVERRUN: - { - struct scb *scb; - u_int scbid; - - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb != NULL) - ahd_print_path(ahd, scb); - else - printk("%s: ", ahd_name(ahd)); - printk("SCB %d Packetized Status Overrun", scbid); - ahd_dump_card_state(ahd); - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - break; - } - case CFG4ISTAT_INTR: - { - struct scb *scb; - u_int scbid; - - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - ahd_dump_card_state(ahd); - printk("CFG4ISTAT: Free SCB %d referenced", scbid); - panic("For safety"); - } - ahd_outq(ahd, HADDR, scb->sense_busaddr); - ahd_outw(ahd, HCNT, AHD_SENSE_BUFSIZE); - ahd_outb(ahd, HCNT + 2, 0); - ahd_outb(ahd, SG_CACHE_PRE, SG_LAST_SEG); - ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN); - break; - } - case ILLEGAL_PHASE: - { - u_int bus_phase; - - bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; - printk("%s: ILLEGAL_PHASE 0x%x\n", - ahd_name(ahd), bus_phase); - - switch (bus_phase) { - case P_DATAOUT: - case P_DATAIN: - case P_DATAOUT_DT: - case P_DATAIN_DT: - case P_MESGOUT: - case P_STATUS: - case P_MESGIN: - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - printk("%s: Issued Bus Reset.\n", ahd_name(ahd)); - break; - case P_COMMAND: - { - struct ahd_devinfo devinfo; - struct scb *scb; - struct ahd_initiator_tinfo *targ_info; - struct ahd_tmode_tstate *tstate; - struct ahd_transinfo *tinfo; - u_int scbid; - - /* - * If a target takes us into the command phase - * assume that it has been externally reset and - * has thus lost our previous packetized negotiation - * agreement. Since we have not sent an identify - * message and may not have fully qualified the - * connection, we change our command to TUR, assert - * ATN and ABORT the task when we go to message in - * phase. The OSM will see the REQUEUE_REQUEST - * status and retry the command. - */ - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("Invalid phase with no valid SCB. " - "Resetting bus.\n"); - ahd_reset_channel(ahd, 'A', - /*Initiate Reset*/TRUE); - break; - } - ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb), - SCB_GET_TARGET(ahd, scb), - SCB_GET_LUN(scb), - SCB_GET_CHANNEL(ahd, scb), - ROLE_INITIATOR); - targ_info = ahd_fetch_transinfo(ahd, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, - &tstate); - tinfo = &targ_info->curr; - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_ACTIVE, /*paused*/TRUE); - ahd_set_syncrate(ahd, &devinfo, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHD_TRANS_ACTIVE, /*paused*/TRUE); - /* Hand-craft TUR command */ - ahd_outb(ahd, SCB_CDB_STORE, 0); - ahd_outb(ahd, SCB_CDB_STORE+1, 0); - ahd_outb(ahd, SCB_CDB_STORE+2, 0); - ahd_outb(ahd, SCB_CDB_STORE+3, 0); - ahd_outb(ahd, SCB_CDB_STORE+4, 0); - ahd_outb(ahd, SCB_CDB_STORE+5, 0); - ahd_outb(ahd, SCB_CDB_LEN, 6); - scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE); - scb->hscb->control |= MK_MESSAGE; - ahd_outb(ahd, SCB_CONTROL, scb->hscb->control); - ahd_outb(ahd, MSG_OUT, HOST_MSG); - ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid); - /* - * The lun is 0, regardless of the SCB's lun - * as we have not sent an identify message. - */ - ahd_outb(ahd, SAVED_LUN, 0); - ahd_outb(ahd, SEQ_FLAGS, 0); - ahd_assert_atn(ahd); - scb->flags &= ~SCB_PACKETIZED; - scb->flags |= SCB_ABORT|SCB_EXTERNAL_RESET; - ahd_freeze_devq(ahd, scb); - ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahd_freeze_scb(scb); - - /* Notify XPT */ - ahd_send_async(ahd, devinfo.channel, devinfo.target, - CAM_LUN_WILDCARD, AC_SENT_BDR); - - /* - * Allow the sequencer to continue with - * non-pack processing. - */ - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_outb(ahd, CLRLQOINT1, CLRLQOPHACHGINPKT); - if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { - ahd_outb(ahd, CLRLQOINT1, 0); - } -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { - ahd_print_path(ahd, scb); - printk("Unexpected command phase from " - "packetized target\n"); - } -#endif - break; - } - } - break; - } - case CFG4OVERRUN: - { - struct scb *scb; - u_int scb_index; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { - printk("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd), - ahd_inb(ahd, MODE_PTR)); - } -#endif - scb_index = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scb_index); - if (scb == NULL) { - /* - * Attempt to transfer to an SCB that is - * not outstanding. - */ - ahd_assert_atn(ahd); - ahd_outb(ahd, MSG_OUT, HOST_MSG); - ahd->msgout_buf[0] = MSG_ABORT_TASK; - ahd->msgout_len = 1; - ahd->msgout_index = 0; - ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - /* - * Clear status received flag to prevent any - * attempt to complete this bogus SCB. - */ - ahd_outb(ahd, SCB_CONTROL, - ahd_inb_scbram(ahd, SCB_CONTROL) - & ~STATUS_RCVD); - } - break; - } - case DUMP_CARD_STATE: - { - ahd_dump_card_state(ahd); - break; - } - case PDATA_REINIT: - { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { - printk("%s: PDATA_REINIT - DFCNTRL = 0x%x " - "SG_CACHE_SHADOW = 0x%x\n", - ahd_name(ahd), ahd_inb(ahd, DFCNTRL), - ahd_inb(ahd, SG_CACHE_SHADOW)); - } -#endif - ahd_reinitialize_dataptrs(ahd); - break; - } - case HOST_MSG_LOOP: - { - struct ahd_devinfo devinfo; - - /* - * The sequencer has encountered a message phase - * that requires host assistance for completion. - * While handling the message phase(s), we will be - * notified by the sequencer after each byte is - * transferred so we can track bus phase changes. - * - * If this is the first time we've seen a HOST_MSG_LOOP - * interrupt, initialize the state of the host message - * loop. - */ - ahd_fetch_devinfo(ahd, &devinfo); - if (ahd->msg_type == MSG_TYPE_NONE) { - struct scb *scb; - u_int scb_index; - u_int bus_phase; - - bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; - if (bus_phase != P_MESGIN - && bus_phase != P_MESGOUT) { - printk("ahd_intr: HOST_MSG_LOOP bad " - "phase 0x%x\n", bus_phase); - /* - * Probably transitioned to bus free before - * we got here. Just punt the message. - */ - ahd_dump_card_state(ahd); - ahd_clear_intstat(ahd); - ahd_restart(ahd); - return; - } - - scb_index = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scb_index); - if (devinfo.role == ROLE_INITIATOR) { - if (bus_phase == P_MESGOUT) - ahd_setup_initiator_msgout(ahd, - &devinfo, - scb); - else { - ahd->msg_type = - MSG_TYPE_INITIATOR_MSGIN; - ahd->msgin_index = 0; - } - } -#ifdef AHD_TARGET_MODE - else { - if (bus_phase == P_MESGOUT) { - ahd->msg_type = - MSG_TYPE_TARGET_MSGOUT; - ahd->msgin_index = 0; - } - else - ahd_setup_target_msgin(ahd, - &devinfo, - scb); - } -#endif - } - - ahd_handle_message_phase(ahd); - break; - } - case NO_MATCH: - { - /* Ensure we don't leave the selection hardware on */ - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); - - printk("%s:%c:%d: no active SCB for reconnecting " - "target - issuing BUS DEVICE RESET\n", - ahd_name(ahd), 'A', ahd_inb(ahd, SELID) >> 4); - printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " - "REG0 == 0x%x ACCUM = 0x%x\n", - ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN), - ahd_inw(ahd, REG0), ahd_inb(ahd, ACCUM)); - printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " - "SINDEX == 0x%x\n", - ahd_inb(ahd, SEQ_FLAGS), ahd_get_scbptr(ahd), - ahd_find_busy_tcl(ahd, - BUILD_TCL(ahd_inb(ahd, SAVED_SCSIID), - ahd_inb(ahd, SAVED_LUN))), - ahd_inw(ahd, SINDEX)); - printk("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " - "SCB_CONTROL == 0x%x\n", - ahd_inb(ahd, SELID), ahd_inb_scbram(ahd, SCB_SCSIID), - ahd_inb_scbram(ahd, SCB_LUN), - ahd_inb_scbram(ahd, SCB_CONTROL)); - printk("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n", - ahd_inb(ahd, SCSIBUS), ahd_inb(ahd, SCSISIGI)); - printk("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0)); - printk("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0)); - ahd_dump_card_state(ahd); - ahd->msgout_buf[0] = MSG_BUS_DEV_RESET; - ahd->msgout_len = 1; - ahd->msgout_index = 0; - ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - ahd_outb(ahd, MSG_OUT, HOST_MSG); - ahd_assert_atn(ahd); - break; - } - case PROTO_VIOLATION: - { - ahd_handle_proto_violation(ahd); - break; - } - case IGN_WIDE_RES: - { - struct ahd_devinfo devinfo; - - ahd_fetch_devinfo(ahd, &devinfo); - ahd_handle_ign_wide_residue(ahd, &devinfo); - break; - } - case BAD_PHASE: - { - u_int lastphase; - - lastphase = ahd_inb(ahd, LASTPHASE); - printk("%s:%c:%d: unknown scsi bus phase %x, " - "lastphase = 0x%x. Attempting to continue\n", - ahd_name(ahd), 'A', - SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)), - lastphase, ahd_inb(ahd, SCSISIGI)); - break; - } - case MISSED_BUSFREE: - { - u_int lastphase; - - lastphase = ahd_inb(ahd, LASTPHASE); - printk("%s:%c:%d: Missed busfree. " - "Lastphase = 0x%x, Curphase = 0x%x\n", - ahd_name(ahd), 'A', - SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)), - lastphase, ahd_inb(ahd, SCSISIGI)); - ahd_restart(ahd); - return; - } - case DATA_OVERRUN: - { - /* - * When the sequencer detects an overrun, it - * places the controller in "BITBUCKET" mode - * and allows the target to complete its transfer. - * Unfortunately, none of the counters get updated - * when the controller is in this mode, so we have - * no way of knowing how large the overrun was. - */ - struct scb *scb; - u_int scbindex; -#ifdef AHD_DEBUG - u_int lastphase; -#endif - - scbindex = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbindex); -#ifdef AHD_DEBUG - lastphase = ahd_inb(ahd, LASTPHASE); - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { - ahd_print_path(ahd, scb); - printk("data overrun detected %s. Tag == 0x%x.\n", - ahd_lookup_phase_entry(lastphase)->phasemsg, - SCB_GET_TAG(scb)); - ahd_print_path(ahd, scb); - printk("%s seen Data Phase. Length = %ld. " - "NumSGs = %d.\n", - ahd_inb(ahd, SEQ_FLAGS) & DPHASE - ? "Have" : "Haven't", - ahd_get_transfer_length(scb), scb->sg_count); - ahd_dump_sglist(scb); - } -#endif - - /* - * Set this and it will take effect when the - * target does a command complete. - */ - ahd_freeze_devq(ahd, scb); - ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); - ahd_freeze_scb(scb); - break; - } - case MKMSG_FAILED: - { - struct ahd_devinfo devinfo; - struct scb *scb; - u_int scbid; - - ahd_fetch_devinfo(ahd, &devinfo); - printk("%s:%c:%d:%d: Attempt to issue message failed\n", - ahd_name(ahd), devinfo.channel, devinfo.target, - devinfo.lun); - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb != NULL - && (scb->flags & SCB_RECOVERY_SCB) != 0) - /* - * Ensure that we didn't put a second instance of this - * SCB into the QINFIFO. - */ - ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), - SCB_GET_CHANNEL(ahd, scb), - SCB_GET_LUN(scb), SCB_GET_TAG(scb), - ROLE_INITIATOR, /*status*/0, - SEARCH_REMOVE); - ahd_outb(ahd, SCB_CONTROL, - ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE); - break; - } - case TASKMGMT_FUNC_COMPLETE: - { - u_int scbid; - struct scb *scb; - - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb != NULL) { - u_int lun; - u_int tag; - cam_status error; - - ahd_print_path(ahd, scb); - printk("Task Management Func 0x%x Complete\n", - scb->hscb->task_management); - lun = CAM_LUN_WILDCARD; - tag = SCB_LIST_NULL; - - switch (scb->hscb->task_management) { - case SIU_TASKMGMT_ABORT_TASK: - tag = SCB_GET_TAG(scb); - case SIU_TASKMGMT_ABORT_TASK_SET: - case SIU_TASKMGMT_CLEAR_TASK_SET: - lun = scb->hscb->lun; - error = CAM_REQ_ABORTED; - ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), - 'A', lun, tag, ROLE_INITIATOR, - error); - break; - case SIU_TASKMGMT_LUN_RESET: - lun = scb->hscb->lun; - case SIU_TASKMGMT_TARGET_RESET: - { - struct ahd_devinfo devinfo; - - ahd_scb_devinfo(ahd, &devinfo, scb); - error = CAM_BDR_SENT; - ahd_handle_devreset(ahd, &devinfo, lun, - CAM_BDR_SENT, - lun != CAM_LUN_WILDCARD - ? "Lun Reset" - : "Target Reset", - /*verbose_level*/0); - break; - } - default: - panic("Unexpected TaskMgmt Func\n"); - break; - } - } - break; - } - case TASKMGMT_CMD_CMPLT_OKAY: - { - u_int scbid; - struct scb *scb; - - /* - * An ABORT TASK TMF failed to be delivered before - * the targeted command completed normally. - */ - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb != NULL) { - /* - * Remove the second instance of this SCB from - * the QINFIFO if it is still there. - */ - ahd_print_path(ahd, scb); - printk("SCB completes before TMF\n"); - /* - * Handle losing the race. Wait until any - * current selection completes. We will then - * set the TMF back to zero in this SCB so that - * the sequencer doesn't bother to issue another - * sequencer interrupt for its completion. - */ - while ((ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0 - && (ahd_inb(ahd, SSTAT0) & SELDO) == 0 - && (ahd_inb(ahd, SSTAT1) & SELTO) == 0) - ; - ahd_outb(ahd, SCB_TASK_MANAGEMENT, 0); - ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), - SCB_GET_CHANNEL(ahd, scb), - SCB_GET_LUN(scb), SCB_GET_TAG(scb), - ROLE_INITIATOR, /*status*/0, - SEARCH_REMOVE); - } - break; - } - case TRACEPOINT0: - case TRACEPOINT1: - case TRACEPOINT2: - case TRACEPOINT3: - printk("%s: Tracepoint %d\n", ahd_name(ahd), - seqintcode - TRACEPOINT0); - break; - case NO_SEQINT: - break; - case SAW_HWERR: - ahd_handle_hwerrint(ahd); - break; - default: - printk("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd), - seqintcode); - break; - } - /* - * The sequencer is paused immediately on - * a SEQINT, so we should restart it when - * we're done. - */ - ahd_unpause(ahd); -} - -static void -ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat) -{ - struct scb *scb; - u_int status0; - u_int status3; - u_int status; - u_int lqistat1; - u_int lqostat0; - u_int scbid; - u_int busfreetime; - - ahd_update_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - - status3 = ahd_inb(ahd, SSTAT3) & (NTRAMPERR|OSRAMPERR); - status0 = ahd_inb(ahd, SSTAT0) & (IOERR|OVERRUN|SELDI|SELDO); - status = ahd_inb(ahd, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); - lqistat1 = ahd_inb(ahd, LQISTAT1); - lqostat0 = ahd_inb(ahd, LQOSTAT0); - busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; - - /* - * Ignore external resets after a bus reset. - */ - if (((status & SCSIRSTI) != 0) && (ahd->flags & AHD_BUS_RESET_ACTIVE)) { - ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); - return; - } - - /* - * Clear bus reset flag - */ - ahd->flags &= ~AHD_BUS_RESET_ACTIVE; - - if ((status0 & (SELDI|SELDO)) != 0) { - u_int simode0; - - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - simode0 = ahd_inb(ahd, SIMODE0); - status0 &= simode0 & (IOERR|OVERRUN|SELDI|SELDO); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - } - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb != NULL - && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0) - scb = NULL; - - if ((status0 & IOERR) != 0) { - u_int now_lvd; - - now_lvd = ahd_inb(ahd, SBLKCTL) & ENAB40; - printk("%s: Transceiver State Has Changed to %s mode\n", - ahd_name(ahd), now_lvd ? "LVD" : "SE"); - ahd_outb(ahd, CLRSINT0, CLRIOERR); - /* - * A change in I/O mode is equivalent to a bus reset. - */ - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - ahd_pause(ahd); - ahd_setup_iocell_workaround(ahd); - ahd_unpause(ahd); - } else if ((status0 & OVERRUN) != 0) { - - printk("%s: SCSI offset overrun detected. Resetting bus.\n", - ahd_name(ahd)); - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - } else if ((status & SCSIRSTI) != 0) { - - printk("%s: Someone reset channel A\n", ahd_name(ahd)); - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE); - } else if ((status & SCSIPERR) != 0) { - - /* Make sure the sequencer is in a safe location. */ - ahd_clear_critical_section(ahd); - - ahd_handle_transmission_error(ahd); - } else if (lqostat0 != 0) { - - printk("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0); - ahd_outb(ahd, CLRLQOINT0, lqostat0); - if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) - ahd_outb(ahd, CLRLQOINT1, 0); - } else if ((status & SELTO) != 0) { - /* Stop the selection */ - ahd_outb(ahd, SCSISEQ0, 0); - - /* Make sure the sequencer is in a safe location. */ - ahd_clear_critical_section(ahd); - - /* No more pending messages */ - ahd_clear_msg_state(ahd); - - /* Clear interrupt state */ - ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); - - /* - * Although the driver does not care about the - * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a successful - * selection, so we must manually clear it to insure - * the LED turns off just incase no future successful - * selections occur (e.g. no devices on the bus). - */ - ahd_outb(ahd, CLRSINT0, CLRSELINGO); - - scbid = ahd_inw(ahd, WAITING_TID_HEAD); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("%s: ahd_intr - referenced scb not " - "valid during SELTO scb(0x%x)\n", - ahd_name(ahd), scbid); - ahd_dump_card_state(ahd); - } else { - struct ahd_devinfo devinfo; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_SELTO) != 0) { - ahd_print_path(ahd, scb); - printk("Saw Selection Timeout for SCB 0x%x\n", - scbid); - } -#endif - ahd_scb_devinfo(ahd, &devinfo, scb); - ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT); - ahd_freeze_devq(ahd, scb); - - /* - * Cancel any pending transactions on the device - * now that it seems to be missing. This will - * also revert us to async/narrow transfers until - * we can renegotiate with the device. - */ - ahd_handle_devreset(ahd, &devinfo, - CAM_LUN_WILDCARD, - CAM_SEL_TIMEOUT, - "Selection Timeout", - /*verbose_level*/1); - } - ahd_outb(ahd, CLRINT, CLRSCSIINT); - ahd_iocell_first_selection(ahd); - ahd_unpause(ahd); - } else if ((status0 & (SELDI|SELDO)) != 0) { - - ahd_iocell_first_selection(ahd); - ahd_unpause(ahd); - } else if (status3 != 0) { - printk("%s: SCSI Cell parity error SSTAT3 == 0x%x\n", - ahd_name(ahd), status3); - ahd_outb(ahd, CLRSINT3, status3); - } else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) { - - /* Make sure the sequencer is in a safe location. */ - ahd_clear_critical_section(ahd); - - ahd_handle_lqiphase_error(ahd, lqistat1); - } else if ((lqistat1 & LQICRCI_NLQ) != 0) { - /* - * This status can be delayed during some - * streaming operations. The SCSIPHASE - * handler has already dealt with this case - * so just clear the error. - */ - ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ); - } else if ((status & BUSFREE) != 0 - || (lqistat1 & LQOBUSFREE) != 0) { - u_int lqostat1; - int restart; - int clear_fifo; - int packetized; - u_int mode; - - /* - * Clear our selection hardware as soon as possible. - * We may have an entry in the waiting Q for this target, - * that is affected by this busfree and we don't want to - * go about selecting the target while we handle the event. - */ - ahd_outb(ahd, SCSISEQ0, 0); - - /* Make sure the sequencer is in a safe location. */ - ahd_clear_critical_section(ahd); - - /* - * Determine what we were up to at the time of - * the busfree. - */ - mode = AHD_MODE_SCSI; - busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME; - lqostat1 = ahd_inb(ahd, LQOSTAT1); - switch (busfreetime) { - case BUSFREE_DFF0: - case BUSFREE_DFF1: - { - mode = busfreetime == BUSFREE_DFF0 - ? AHD_MODE_DFF0 : AHD_MODE_DFF1; - ahd_set_modes(ahd, mode, mode); - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("%s: Invalid SCB %d in DFF%d " - "during unexpected busfree\n", - ahd_name(ahd), scbid, mode); - packetized = 0; - } else - packetized = (scb->flags & SCB_PACKETIZED) != 0; - clear_fifo = 1; - break; - } - case BUSFREE_LQO: - clear_fifo = 0; - packetized = 1; - break; - default: - clear_fifo = 0; - packetized = (lqostat1 & LQOBUSFREE) != 0; - if (!packetized - && ahd_inb(ahd, LASTPHASE) == P_BUSFREE - && (ahd_inb(ahd, SSTAT0) & SELDI) == 0 - && ((ahd_inb(ahd, SSTAT0) & SELDO) == 0 - || (ahd_inb(ahd, SCSISEQ0) & ENSELO) == 0)) - /* - * Assume packetized if we are not - * on the bus in a non-packetized - * capacity and any pending selection - * was a packetized selection. - */ - packetized = 1; - break; - } - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) - printk("Saw Busfree. Busfreetime = 0x%x.\n", - busfreetime); -#endif - /* - * Busfrees that occur in non-packetized phases are - * handled by the nonpkt_busfree handler. - */ - if (packetized && ahd_inb(ahd, LASTPHASE) == P_BUSFREE) { - restart = ahd_handle_pkt_busfree(ahd, busfreetime); - } else { - packetized = 0; - restart = ahd_handle_nonpkt_busfree(ahd); - } - /* - * Clear the busfree interrupt status. The setting of - * the interrupt is a pulse, so in a perfect world, we - * would not need to muck with the ENBUSFREE logic. This - * would ensure that if the bus moves on to another - * connection, busfree protection is still in force. If - * BUSFREEREV is broken, however, we must manually clear - * the ENBUSFREE if the busfree occurred during a non-pack - * connection so that we don't get false positives during - * future, packetized, connections. - */ - ahd_outb(ahd, CLRSINT1, CLRBUSFREE); - if (packetized == 0 - && (ahd->bugs & AHD_BUSFREEREV_BUG) != 0) - ahd_outb(ahd, SIMODE1, - ahd_inb(ahd, SIMODE1) & ~ENBUSFREE); - - if (clear_fifo) - ahd_clear_fifo(ahd, mode); - - ahd_clear_msg_state(ahd); - ahd_outb(ahd, CLRINT, CLRSCSIINT); - if (restart) { - ahd_restart(ahd); - } else { - ahd_unpause(ahd); - } - } else { - printk("%s: Missing case in ahd_handle_scsiint. status = %x\n", - ahd_name(ahd), status); - ahd_dump_card_state(ahd); - ahd_clear_intstat(ahd); - ahd_unpause(ahd); - } -} - -static void -ahd_handle_transmission_error(struct ahd_softc *ahd) -{ - struct scb *scb; - u_int scbid; - u_int lqistat1; - u_int lqistat2; - u_int msg_out; - u_int curphase; - u_int lastphase; - u_int perrdiag; - u_int cur_col; - int silent; - - scb = NULL; - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ); - lqistat2 = ahd_inb(ahd, LQISTAT2); - if ((lqistat1 & (LQICRCI_NLQ|LQICRCI_LQ)) == 0 - && (ahd->bugs & AHD_NLQICRC_DELAYED_BUG) != 0) { - u_int lqistate; - - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - lqistate = ahd_inb(ahd, LQISTATE); - if ((lqistate >= 0x1E && lqistate <= 0x24) - || (lqistate == 0x29)) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) { - printk("%s: NLQCRC found via LQISTATE\n", - ahd_name(ahd)); - } -#endif - lqistat1 |= LQICRCI_NLQ; - } - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - } - - ahd_outb(ahd, CLRLQIINT1, lqistat1); - lastphase = ahd_inb(ahd, LASTPHASE); - curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; - perrdiag = ahd_inb(ahd, PERRDIAG); - msg_out = MSG_INITIATOR_DET_ERR; - ahd_outb(ahd, CLRSINT1, CLRSCSIPERR); - - /* - * Try to find the SCB associated with this error. - */ - silent = FALSE; - if (lqistat1 == 0 - || (lqistat1 & LQICRCI_NLQ) != 0) { - if ((lqistat1 & (LQICRCI_NLQ|LQIOVERI_NLQ)) != 0) - ahd_set_active_fifo(ahd); - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb != NULL && SCB_IS_SILENT(scb)) - silent = TRUE; - } - - cur_col = 0; - if (silent == FALSE) { - printk("%s: Transmission error detected\n", ahd_name(ahd)); - ahd_lqistat1_print(lqistat1, &cur_col, 50); - ahd_lastphase_print(lastphase, &cur_col, 50); - ahd_scsisigi_print(curphase, &cur_col, 50); - ahd_perrdiag_print(perrdiag, &cur_col, 50); - printk("\n"); - ahd_dump_card_state(ahd); - } - - if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) { - if (silent == FALSE) { - printk("%s: Gross protocol error during incoming " - "packet. lqistat1 == 0x%x. Resetting bus.\n", - ahd_name(ahd), lqistat1); - } - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - return; - } else if ((lqistat1 & LQICRCI_LQ) != 0) { - /* - * A CRC error has been detected on an incoming LQ. - * The bus is currently hung on the last ACK. - * Hit LQIRETRY to release the last ack, and - * wait for the sequencer to determine that ATNO - * is asserted while in message out to take us - * to our host message loop. No NONPACKREQ or - * LQIPHASE type errors will occur in this - * scenario. After this first LQIRETRY, the LQI - * manager will be in ISELO where it will - * happily sit until another packet phase begins. - * Unexpected bus free detection is enabled - * through any phases that occur after we release - * this last ack until the LQI manager sees a - * packet phase. This implies we may have to - * ignore a perfectly valid "unexected busfree" - * after our "initiator detected error" message is - * sent. A busfree is the expected response after - * we tell the target that it's L_Q was corrupted. - * (SPI4R09 10.7.3.3.3) - */ - ahd_outb(ahd, LQCTL2, LQIRETRY); - printk("LQIRetry for LQICRCI_LQ to release ACK\n"); - } else if ((lqistat1 & LQICRCI_NLQ) != 0) { - /* - * We detected a CRC error in a NON-LQ packet. - * The hardware has varying behavior in this situation - * depending on whether this packet was part of a - * stream or not. - * - * PKT by PKT mode: - * The hardware has already acked the complete packet. - * If the target honors our outstanding ATN condition, - * we should be (or soon will be) in MSGOUT phase. - * This will trigger the LQIPHASE_LQ status bit as the - * hardware was expecting another LQ. Unexpected - * busfree detection is enabled. Once LQIPHASE_LQ is - * true (first entry into host message loop is much - * the same), we must clear LQIPHASE_LQ and hit - * LQIRETRY so the hardware is ready to handle - * a future LQ. NONPACKREQ will not be asserted again - * once we hit LQIRETRY until another packet is - * processed. The target may either go busfree - * or start another packet in response to our message. - * - * Read Streaming P0 asserted: - * If we raise ATN and the target completes the entire - * stream (P0 asserted during the last packet), the - * hardware will ack all data and return to the ISTART - * state. When the target reponds to our ATN condition, - * LQIPHASE_LQ will be asserted. We should respond to - * this with an LQIRETRY to prepare for any future - * packets. NONPACKREQ will not be asserted again - * once we hit LQIRETRY until another packet is - * processed. The target may either go busfree or - * start another packet in response to our message. - * Busfree detection is enabled. - * - * Read Streaming P0 not asserted: - * If we raise ATN and the target transitions to - * MSGOUT in or after a packet where P0 is not - * asserted, the hardware will assert LQIPHASE_NLQ. - * We should respond to the LQIPHASE_NLQ with an - * LQIRETRY. Should the target stay in a non-pkt - * phase after we send our message, the hardware - * will assert LQIPHASE_LQ. Recovery is then just as - * listed above for the read streaming with P0 asserted. - * Busfree detection is enabled. - */ - if (silent == FALSE) - printk("LQICRC_NLQ\n"); - if (scb == NULL) { - printk("%s: No SCB valid for LQICRC_NLQ. " - "Resetting bus\n", ahd_name(ahd)); - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - return; - } - } else if ((lqistat1 & LQIBADLQI) != 0) { - printk("Need to handle BADLQI!\n"); - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - return; - } else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) { - if ((curphase & ~P_DATAIN_DT) != 0) { - /* Ack the byte. So we can continue. */ - if (silent == FALSE) - printk("Acking %s to clear perror\n", - ahd_lookup_phase_entry(curphase)->phasemsg); - ahd_inb(ahd, SCSIDAT); - } - - if (curphase == P_MESGIN) - msg_out = MSG_PARITY_ERROR; - } - - /* - * We've set the hardware to assert ATN if we - * get a parity error on "in" phases, so all we - * need to do is stuff the message buffer with - * the appropriate message. "In" phases have set - * mesg_out to something other than MSG_NOP. - */ - ahd->send_msg_perror = msg_out; - if (scb != NULL && msg_out == MSG_INITIATOR_DET_ERR) - scb->flags |= SCB_TRANSMISSION_ERROR; - ahd_outb(ahd, MSG_OUT, HOST_MSG); - ahd_outb(ahd, CLRINT, CLRSCSIINT); - ahd_unpause(ahd); -} - -static void -ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1) -{ - /* - * Clear the sources of the interrupts. - */ - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_outb(ahd, CLRLQIINT1, lqistat1); - - /* - * If the "illegal" phase changes were in response - * to our ATN to flag a CRC error, AND we ended up - * on packet boundaries, clear the error, restart the - * LQI manager as appropriate, and go on our merry - * way toward sending the message. Otherwise, reset - * the bus to clear the error. - */ - ahd_set_active_fifo(ahd); - if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0 - && (ahd_inb(ahd, MDFFSTAT) & DLZERO) != 0) { - if ((lqistat1 & LQIPHASE_LQ) != 0) { - printk("LQIRETRY for LQIPHASE_LQ\n"); - ahd_outb(ahd, LQCTL2, LQIRETRY); - } else if ((lqistat1 & LQIPHASE_NLQ) != 0) { - printk("LQIRETRY for LQIPHASE_NLQ\n"); - ahd_outb(ahd, LQCTL2, LQIRETRY); - } else - panic("ahd_handle_lqiphase_error: No phase errors\n"); - ahd_dump_card_state(ahd); - ahd_outb(ahd, CLRINT, CLRSCSIINT); - ahd_unpause(ahd); - } else { - printk("Reseting Channel for LQI Phase error\n"); - ahd_dump_card_state(ahd); - ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE); - } -} - -/* - * Packetized unexpected or expected busfree. - * Entered in mode based on busfreetime. - */ -static int -ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime) -{ - u_int lqostat1; - - AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), - ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); - lqostat1 = ahd_inb(ahd, LQOSTAT1); - if ((lqostat1 & LQOBUSFREE) != 0) { - struct scb *scb; - u_int scbid; - u_int saved_scbptr; - u_int waiting_h; - u_int waiting_t; - u_int next; - - /* - * The LQO manager detected an unexpected busfree - * either: - * - * 1) During an outgoing LQ. - * 2) After an outgoing LQ but before the first - * REQ of the command packet. - * 3) During an outgoing command packet. - * - * In all cases, CURRSCB is pointing to the - * SCB that encountered the failure. Clean - * up the queue, clear SELDO and LQOBUSFREE, - * and allow the sequencer to restart the select - * out at its lesure. - */ - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - scbid = ahd_inw(ahd, CURRSCB); - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) - panic("SCB not valid during LQOBUSFREE"); - /* - * Clear the status. - */ - ahd_outb(ahd, CLRLQOINT1, CLRLQOBUSFREE); - if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) - ahd_outb(ahd, CLRLQOINT1, 0); - ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); - ahd_flush_device_writes(ahd); - ahd_outb(ahd, CLRSINT0, CLRSELDO); - - /* - * Return the LQO manager to its idle loop. It will - * not do this automatically if the busfree occurs - * after the first REQ of either the LQ or command - * packet or between the LQ and command packet. - */ - ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE); - - /* - * Update the waiting for selection queue so - * we restart on the correct SCB. - */ - waiting_h = ahd_inw(ahd, WAITING_TID_HEAD); - saved_scbptr = ahd_get_scbptr(ahd); - if (waiting_h != scbid) { - - ahd_outw(ahd, WAITING_TID_HEAD, scbid); - waiting_t = ahd_inw(ahd, WAITING_TID_TAIL); - if (waiting_t == waiting_h) { - ahd_outw(ahd, WAITING_TID_TAIL, scbid); - next = SCB_LIST_NULL; - } else { - ahd_set_scbptr(ahd, waiting_h); - next = ahd_inw_scbram(ahd, SCB_NEXT2); - } - ahd_set_scbptr(ahd, scbid); - ahd_outw(ahd, SCB_NEXT2, next); - } - ahd_set_scbptr(ahd, saved_scbptr); - if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) { - if (SCB_IS_SILENT(scb) == FALSE) { - ahd_print_path(ahd, scb); - printk("Probable outgoing LQ CRC error. " - "Retrying command\n"); - } - scb->crc_retry_count++; - } else { - ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); - ahd_freeze_scb(scb); - ahd_freeze_devq(ahd, scb); - } - /* Return unpausing the sequencer. */ - return (0); - } else if ((ahd_inb(ahd, PERRDIAG) & PARITYERR) != 0) { - /* - * Ignore what are really parity errors that - * occur on the last REQ of a free running - * clock prior to going busfree. Some drives - * do not properly active negate just before - * going busfree resulting in a parity glitch. - */ - ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0) - printk("%s: Parity on last REQ detected " - "during busfree phase.\n", - ahd_name(ahd)); -#endif - /* Return unpausing the sequencer. */ - return (0); - } - if (ahd->src_mode != AHD_MODE_SCSI) { - u_int scbid; - struct scb *scb; - - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - ahd_print_path(ahd, scb); - printk("Unexpected PKT busfree condition\n"); - ahd_dump_card_state(ahd); - ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A', - SCB_GET_LUN(scb), SCB_GET_TAG(scb), - ROLE_INITIATOR, CAM_UNEXP_BUSFREE); - - /* Return restarting the sequencer. */ - return (1); - } - printk("%s: Unexpected PKT busfree condition\n", ahd_name(ahd)); - ahd_dump_card_state(ahd); - /* Restart the sequencer. */ - return (1); -} - -/* - * Non-packetized unexpected or expected busfree. - */ -static int -ahd_handle_nonpkt_busfree(struct ahd_softc *ahd) -{ - struct ahd_devinfo devinfo; - struct scb *scb; - u_int lastphase; - u_int saved_scsiid; - u_int saved_lun; - u_int target; - u_int initiator_role_id; - u_int scbid; - u_int ppr_busfree; - int printerror; - - /* - * Look at what phase we were last in. If its message out, - * chances are pretty good that the busfree was in response - * to one of our abort requests. - */ - lastphase = ahd_inb(ahd, LASTPHASE); - saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); - saved_lun = ahd_inb(ahd, SAVED_LUN); - target = SCSIID_TARGET(ahd, saved_scsiid); - initiator_role_id = SCSIID_OUR_ID(saved_scsiid); - ahd_compile_devinfo(&devinfo, initiator_role_id, - target, saved_lun, 'A', ROLE_INITIATOR); - printerror = 1; - - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - if (scb != NULL - && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0) - scb = NULL; - - ppr_busfree = (ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0; - if (lastphase == P_MESGOUT) { - u_int tag; - - tag = SCB_LIST_NULL; - if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_ABORT_TAG, TRUE) - || ahd_sent_msg(ahd, AHDMSG_1B, MSG_ABORT, TRUE)) { - int found; - int sent_msg; - - if (scb == NULL) { - ahd_print_devinfo(ahd, &devinfo); - printk("Abort for unidentified " - "connection completed.\n"); - /* restart the sequencer. */ - return (1); - } - sent_msg = ahd->msgout_buf[ahd->msgout_index - 1]; - ahd_print_path(ahd, scb); - printk("SCB %d - Abort%s Completed.\n", - SCB_GET_TAG(scb), - sent_msg == MSG_ABORT_TAG ? "" : " Tag"); - - if (sent_msg == MSG_ABORT_TAG) - tag = SCB_GET_TAG(scb); - - if ((scb->flags & SCB_EXTERNAL_RESET) != 0) { - /* - * This abort is in response to an - * unexpected switch to command phase - * for a packetized connection. Since - * the identify message was never sent, - * "saved lun" is 0. We really want to - * abort only the SCB that encountered - * this error, which could have a different - * lun. The SCB will be retried so the OS - * will see the UA after renegotiating to - * packetized. - */ - tag = SCB_GET_TAG(scb); - saved_lun = scb->hscb->lun; - } - found = ahd_abort_scbs(ahd, target, 'A', saved_lun, - tag, ROLE_INITIATOR, - CAM_REQ_ABORTED); - printk("found == 0x%x\n", found); - printerror = 0; - } else if (ahd_sent_msg(ahd, AHDMSG_1B, - MSG_BUS_DEV_RESET, TRUE)) { -#ifdef __FreeBSD__ - /* - * Don't mark the user's request for this BDR - * as completing with CAM_BDR_SENT. CAM3 - * specifies CAM_REQ_CMP. - */ - if (scb != NULL - && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV - && ahd_match_scb(ahd, scb, target, 'A', - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_INITIATOR)) - ahd_set_transaction_status(scb, CAM_REQ_CMP); -#endif - ahd_handle_devreset(ahd, &devinfo, CAM_LUN_WILDCARD, - CAM_BDR_SENT, "Bus Device Reset", - /*verbose_level*/0); - printerror = 0; - } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, FALSE) - && ppr_busfree == 0) { - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - - /* - * PPR Rejected. - * - * If the previous negotiation was packetized, - * this could be because the device has been - * reset without our knowledge. Force our - * current negotiation to async and retry the - * negotiation. Otherwise retry the command - * with non-ppr negotiation. - */ -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("PPR negotiation rejected busfree.\n"); -#endif - tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, - devinfo.our_scsiid, - devinfo.target, &tstate); - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ)!=0) { - ahd_set_width(ahd, &devinfo, - MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_CUR, - /*paused*/TRUE); - ahd_set_syncrate(ahd, &devinfo, - /*period*/0, /*offset*/0, - /*ppr_options*/0, - AHD_TRANS_CUR, - /*paused*/TRUE); - /* - * The expect PPR busfree handler below - * will effect the retry and necessary - * abort. - */ - } else { - tinfo->curr.transport_version = 2; - tinfo->goal.transport_version = 2; - tinfo->goal.ppr_options = 0; - if (scb != NULL) { - /* - * Remove any SCBs in the waiting - * for selection queue that may - * also be for this target so that - * command ordering is preserved. - */ - ahd_freeze_devq(ahd, scb); - ahd_qinfifo_requeue_tail(ahd, scb); - } - printerror = 0; - } - } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) - && ppr_busfree == 0) { - /* - * Negotiation Rejected. Go-narrow and - * retry command. - */ -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("WDTR negotiation rejected busfree.\n"); -#endif - ahd_set_width(ahd, &devinfo, - MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_CUR|AHD_TRANS_GOAL, - /*paused*/TRUE); - if (scb != NULL) { - /* - * Remove any SCBs in the waiting for - * selection queue that may also be for - * this target so that command ordering - * is preserved. - */ - ahd_freeze_devq(ahd, scb); - ahd_qinfifo_requeue_tail(ahd, scb); - } - printerror = 0; - } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE) - && ppr_busfree == 0) { - /* - * Negotiation Rejected. Go-async and - * retry command. - */ -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("SDTR negotiation rejected busfree.\n"); -#endif - ahd_set_syncrate(ahd, &devinfo, - /*period*/0, /*offset*/0, - /*ppr_options*/0, - AHD_TRANS_CUR|AHD_TRANS_GOAL, - /*paused*/TRUE); - if (scb != NULL) { - /* - * Remove any SCBs in the waiting for - * selection queue that may also be for - * this target so that command ordering - * is preserved. - */ - ahd_freeze_devq(ahd, scb); - ahd_qinfifo_requeue_tail(ahd, scb); - } - printerror = 0; - } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_IDE_BUSFREE) != 0 - && ahd_sent_msg(ahd, AHDMSG_1B, - MSG_INITIATOR_DET_ERR, TRUE)) { - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("Expected IDE Busfree\n"); -#endif - printerror = 0; - } else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE) - && ahd_sent_msg(ahd, AHDMSG_1B, - MSG_MESSAGE_REJECT, TRUE)) { - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("Expected QAS Reject Busfree\n"); -#endif - printerror = 0; - } - } - - /* - * The busfree required flag is honored at the end of - * the message phases. We check it last in case we - * had to send some other message that caused a busfree. - */ - if (scb != NULL && printerror != 0 - && (lastphase == P_MESGIN || lastphase == P_MESGOUT) - && ((ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0)) { - - ahd_freeze_devq(ahd, scb); - ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahd_freeze_scb(scb); - if ((ahd->msg_flags & MSG_FLAG_IU_REQ_CHANGED) != 0) { - ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), - SCB_GET_CHANNEL(ahd, scb), - SCB_GET_LUN(scb), SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQ_ABORTED); - } else { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("PPR Negotiation Busfree.\n"); -#endif - ahd_done(ahd, scb); - } - printerror = 0; - } - if (printerror != 0) { - int aborted; - - aborted = 0; - if (scb != NULL) { - u_int tag; - - if ((scb->hscb->control & TAG_ENB) != 0) - tag = SCB_GET_TAG(scb); - else - tag = SCB_LIST_NULL; - ahd_print_path(ahd, scb); - aborted = ahd_abort_scbs(ahd, target, 'A', - SCB_GET_LUN(scb), tag, - ROLE_INITIATOR, - CAM_UNEXP_BUSFREE); - } else { - /* - * We had not fully identified this connection, - * so we cannot abort anything. - */ - printk("%s: ", ahd_name(ahd)); - } - printk("Unexpected busfree %s, %d SCBs aborted, " - "PRGMCNT == 0x%x\n", - ahd_lookup_phase_entry(lastphase)->phasemsg, - aborted, - ahd_inw(ahd, PRGMCNT)); - ahd_dump_card_state(ahd); - if (lastphase != P_BUSFREE) - ahd_force_renegotiation(ahd, &devinfo); - } - /* Always restart the sequencer. */ - return (1); -} - -static void -ahd_handle_proto_violation(struct ahd_softc *ahd) -{ - struct ahd_devinfo devinfo; - struct scb *scb; - u_int scbid; - u_int seq_flags; - u_int curphase; - u_int lastphase; - int found; - - ahd_fetch_devinfo(ahd, &devinfo); - scbid = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scbid); - seq_flags = ahd_inb(ahd, SEQ_FLAGS); - curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK; - lastphase = ahd_inb(ahd, LASTPHASE); - if ((seq_flags & NOT_IDENTIFIED) != 0) { - - /* - * The reconnecting target either did not send an - * identify message, or did, but we didn't find an SCB - * to match. - */ - ahd_print_devinfo(ahd, &devinfo); - printk("Target did not send an IDENTIFY message. " - "LASTPHASE = 0x%x.\n", lastphase); - scb = NULL; - } else if (scb == NULL) { - /* - * We don't seem to have an SCB active for this - * transaction. Print an error and reset the bus. - */ - ahd_print_devinfo(ahd, &devinfo); - printk("No SCB found during protocol violation\n"); - goto proto_violation_reset; - } else { - ahd_set_transaction_status(scb, CAM_SEQUENCE_FAIL); - if ((seq_flags & NO_CDB_SENT) != 0) { - ahd_print_path(ahd, scb); - printk("No or incomplete CDB sent to device.\n"); - } else if ((ahd_inb_scbram(ahd, SCB_CONTROL) - & STATUS_RCVD) == 0) { - /* - * The target never bothered to provide status to - * us prior to completing the command. Since we don't - * know the disposition of this command, we must attempt - * to abort it. Assert ATN and prepare to send an abort - * message. - */ - ahd_print_path(ahd, scb); - printk("Completed command without status.\n"); - } else { - ahd_print_path(ahd, scb); - printk("Unknown protocol violation.\n"); - ahd_dump_card_state(ahd); - } - } - if ((lastphase & ~P_DATAIN_DT) == 0 - || lastphase == P_COMMAND) { -proto_violation_reset: - /* - * Target either went directly to data - * phase or didn't respond to our ATN. - * The only safe thing to do is to blow - * it away with a bus reset. - */ - found = ahd_reset_channel(ahd, 'A', TRUE); - printk("%s: Issued Channel %c Bus Reset. " - "%d SCBs aborted\n", ahd_name(ahd), 'A', found); - } else { - /* - * Leave the selection hardware off in case - * this abort attempt will affect yet to - * be sent commands. - */ - ahd_outb(ahd, SCSISEQ0, - ahd_inb(ahd, SCSISEQ0) & ~ENSELO); - ahd_assert_atn(ahd); - ahd_outb(ahd, MSG_OUT, HOST_MSG); - if (scb == NULL) { - ahd_print_devinfo(ahd, &devinfo); - ahd->msgout_buf[0] = MSG_ABORT_TASK; - ahd->msgout_len = 1; - ahd->msgout_index = 0; - ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - } else { - ahd_print_path(ahd, scb); - scb->flags |= SCB_ABORT; - } - printk("Protocol violation %s. Attempting to abort.\n", - ahd_lookup_phase_entry(curphase)->phasemsg); - } -} - -/* - * Force renegotiation to occur the next time we initiate - * a command to the current device. - */ -static void -ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - struct ahd_initiator_tinfo *targ_info; - struct ahd_tmode_tstate *tstate; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - ahd_print_devinfo(ahd, devinfo); - printk("Forcing renegotiation\n"); - } -#endif - targ_info = ahd_fetch_transinfo(ahd, - devinfo->channel, - devinfo->our_scsiid, - devinfo->target, - &tstate); - ahd_update_neg_request(ahd, devinfo, tstate, - targ_info, AHD_NEG_IF_NON_ASYNC); -} - -#define AHD_MAX_STEPS 2000 -static void -ahd_clear_critical_section(struct ahd_softc *ahd) -{ - ahd_mode_state saved_modes; - int stepping; - int steps; - int first_instr; - u_int simode0; - u_int simode1; - u_int simode3; - u_int lqimode0; - u_int lqimode1; - u_int lqomode0; - u_int lqomode1; - - if (ahd->num_critical_sections == 0) - return; - - stepping = FALSE; - steps = 0; - first_instr = 0; - simode0 = 0; - simode1 = 0; - simode3 = 0; - lqimode0 = 0; - lqimode1 = 0; - lqomode0 = 0; - lqomode1 = 0; - saved_modes = ahd_save_modes(ahd); - for (;;) { - struct cs *cs; - u_int seqaddr; - u_int i; - - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - seqaddr = ahd_inw(ahd, CURADDR); - - cs = ahd->critical_sections; - for (i = 0; i < ahd->num_critical_sections; i++, cs++) { - - if (cs->begin < seqaddr && cs->end >= seqaddr) - break; - } - - if (i == ahd->num_critical_sections) - break; - - if (steps > AHD_MAX_STEPS) { - printk("%s: Infinite loop in critical section\n" - "%s: First Instruction 0x%x now 0x%x\n", - ahd_name(ahd), ahd_name(ahd), first_instr, - seqaddr); - ahd_dump_card_state(ahd); - panic("critical section loop"); - } - - steps++; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) - printk("%s: Single stepping at 0x%x\n", ahd_name(ahd), - seqaddr); -#endif - if (stepping == FALSE) { - - first_instr = seqaddr; - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - simode0 = ahd_inb(ahd, SIMODE0); - simode3 = ahd_inb(ahd, SIMODE3); - lqimode0 = ahd_inb(ahd, LQIMODE0); - lqimode1 = ahd_inb(ahd, LQIMODE1); - lqomode0 = ahd_inb(ahd, LQOMODE0); - lqomode1 = ahd_inb(ahd, LQOMODE1); - ahd_outb(ahd, SIMODE0, 0); - ahd_outb(ahd, SIMODE3, 0); - ahd_outb(ahd, LQIMODE0, 0); - ahd_outb(ahd, LQIMODE1, 0); - ahd_outb(ahd, LQOMODE0, 0); - ahd_outb(ahd, LQOMODE1, 0); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - simode1 = ahd_inb(ahd, SIMODE1); - /* - * We don't clear ENBUSFREE. Unfortunately - * we cannot re-enable busfree detection within - * the current connection, so we must leave it - * on while single stepping. - */ - ahd_outb(ahd, SIMODE1, simode1 & ENBUSFREE); - ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) | STEP); - stepping = TRUE; - } - ahd_outb(ahd, CLRSINT1, CLRBUSFREE); - ahd_outb(ahd, CLRINT, CLRSCSIINT); - ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); - ahd_outb(ahd, HCNTRL, ahd->unpause); - while (!ahd_is_paused(ahd)) - ahd_delay(200); - ahd_update_modes(ahd); - } - if (stepping) { - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - ahd_outb(ahd, SIMODE0, simode0); - ahd_outb(ahd, SIMODE3, simode3); - ahd_outb(ahd, LQIMODE0, lqimode0); - ahd_outb(ahd, LQIMODE1, lqimode1); - ahd_outb(ahd, LQOMODE0, lqomode0); - ahd_outb(ahd, LQOMODE1, lqomode1); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) & ~STEP); - ahd_outb(ahd, SIMODE1, simode1); - /* - * SCSIINT seems to glitch occasionally when - * the interrupt masks are restored. Clear SCSIINT - * one more time so that only persistent errors - * are seen as a real interrupt. - */ - ahd_outb(ahd, CLRINT, CLRSCSIINT); - } - ahd_restore_modes(ahd, saved_modes); -} - -/* - * Clear any pending interrupt status. - */ -static void -ahd_clear_intstat(struct ahd_softc *ahd) -{ - AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), - ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); - /* Clear any interrupt conditions this may have caused */ - ahd_outb(ahd, CLRLQIINT0, CLRLQIATNQAS|CLRLQICRCT1|CLRLQICRCT2 - |CLRLQIBADLQT|CLRLQIATNLQ|CLRLQIATNCMD); - ahd_outb(ahd, CLRLQIINT1, CLRLQIPHASE_LQ|CLRLQIPHASE_NLQ|CLRLIQABORT - |CLRLQICRCI_LQ|CLRLQICRCI_NLQ|CLRLQIBADLQI - |CLRLQIOVERI_LQ|CLRLQIOVERI_NLQ|CLRNONPACKREQ); - ahd_outb(ahd, CLRLQOINT0, CLRLQOTARGSCBPERR|CLRLQOSTOPT2|CLRLQOATNLQ - |CLRLQOATNPKT|CLRLQOTCRC); - ahd_outb(ahd, CLRLQOINT1, CLRLQOINITSCBPERR|CLRLQOSTOPI2|CLRLQOBADQAS - |CLRLQOBUSFREE|CLRLQOPHACHGINPKT); - if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) { - ahd_outb(ahd, CLRLQOINT0, 0); - ahd_outb(ahd, CLRLQOINT1, 0); - } - ahd_outb(ahd, CLRSINT3, CLRNTRAMPERR|CLROSRAMPERR); - ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI - |CLRBUSFREE|CLRSCSIPERR|CLRREQINIT); - ahd_outb(ahd, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO - |CLRIOERR|CLROVERRUN); - ahd_outb(ahd, CLRINT, CLRSCSIINT); -} - -/**************************** Debugging Routines ******************************/ -#ifdef AHD_DEBUG -uint32_t ahd_debug = AHD_DEBUG_OPTS; -#endif - -#if 0 -void -ahd_print_scb(struct scb *scb) -{ - struct hardware_scb *hscb; - int i; - - hscb = scb->hscb; - printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", - (void *)scb, - hscb->control, - hscb->scsiid, - hscb->lun, - hscb->cdb_len); - printk("Shared Data: "); - for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++) - printk("%#02x", hscb->shared_data.idata.cdb[i]); - printk(" dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n", - (uint32_t)((ahd_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF), - (uint32_t)(ahd_le64toh(hscb->dataptr) & 0xFFFFFFFF), - ahd_le32toh(hscb->datacnt), - ahd_le32toh(hscb->sgptr), - SCB_GET_TAG(scb)); - ahd_dump_sglist(scb); -} -#endif /* 0 */ - -/************************* Transfer Negotiation *******************************/ -/* - * Allocate per target mode instance (ID we respond to as a target) - * transfer negotiation data structures. - */ -static struct ahd_tmode_tstate * -ahd_alloc_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel) -{ - struct ahd_tmode_tstate *master_tstate; - struct ahd_tmode_tstate *tstate; - int i; - - master_tstate = ahd->enabled_targets[ahd->our_id]; - if (ahd->enabled_targets[scsi_id] != NULL - && ahd->enabled_targets[scsi_id] != master_tstate) - panic("%s: ahd_alloc_tstate - Target already allocated", - ahd_name(ahd)); - tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC); - if (tstate == NULL) - return (NULL); - - /* - * If we have allocated a master tstate, copy user settings from - * the master tstate (taken from SRAM or the EEPROM) for this - * channel, but reset our current and goal settings to async/narrow - * until an initiator talks to us. - */ - if (master_tstate != NULL) { - memcpy(tstate, master_tstate, sizeof(*tstate)); - memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); - for (i = 0; i < 16; i++) { - memset(&tstate->transinfo[i].curr, 0, - sizeof(tstate->transinfo[i].curr)); - memset(&tstate->transinfo[i].goal, 0, - sizeof(tstate->transinfo[i].goal)); - } - } else - memset(tstate, 0, sizeof(*tstate)); - ahd->enabled_targets[scsi_id] = tstate; - return (tstate); -} - -#ifdef AHD_TARGET_MODE -/* - * Free per target mode instance (ID we respond to as a target) - * transfer negotiation data structures. - */ -static void -ahd_free_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel, int force) -{ - struct ahd_tmode_tstate *tstate; - - /* - * Don't clean up our "master" tstate. - * It has our default user settings. - */ - if (scsi_id == ahd->our_id - && force == FALSE) - return; - - tstate = ahd->enabled_targets[scsi_id]; - if (tstate != NULL) - kfree(tstate); - ahd->enabled_targets[scsi_id] = NULL; -} -#endif - -/* - * Called when we have an active connection to a target on the bus, - * this function finds the nearest period to the input period limited - * by the capabilities of the bus connectivity of and sync settings for - * the target. - */ -static void -ahd_devlimited_syncrate(struct ahd_softc *ahd, - struct ahd_initiator_tinfo *tinfo, - u_int *period, u_int *ppr_options, role_t role) -{ - struct ahd_transinfo *transinfo; - u_int maxsync; - - if ((ahd_inb(ahd, SBLKCTL) & ENAB40) != 0 - && (ahd_inb(ahd, SSTAT2) & EXP_ACTIVE) == 0) { - maxsync = AHD_SYNCRATE_PACED; - } else { - maxsync = AHD_SYNCRATE_ULTRA; - /* Can't do DT related options on an SE bus */ - *ppr_options &= MSG_EXT_PPR_QAS_REQ; - } - /* - * Never allow a value higher than our current goal - * period otherwise we may allow a target initiated - * negotiation to go above the limit as set by the - * user. In the case of an initiator initiated - * sync negotiation, we limit based on the user - * setting. This allows the system to still accept - * incoming negotiations even if target initiated - * negotiation is not performed. - */ - if (role == ROLE_TARGET) - transinfo = &tinfo->user; - else - transinfo = &tinfo->goal; - *ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN); - if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) { - maxsync = max(maxsync, (u_int)AHD_SYNCRATE_ULTRA2); - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - } - if (transinfo->period == 0) { - *period = 0; - *ppr_options = 0; - } else { - *period = max(*period, (u_int)transinfo->period); - ahd_find_syncrate(ahd, period, ppr_options, maxsync); - } -} - -/* - * Look up the valid period to SCSIRATE conversion in our table. - * Return the period and offset that should be sent to the target - * if this was the beginning of an SDTR. - */ -void -ahd_find_syncrate(struct ahd_softc *ahd, u_int *period, - u_int *ppr_options, u_int maxsync) -{ - if (*period < maxsync) - *period = maxsync; - - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) != 0 - && *period > AHD_SYNCRATE_MIN_DT) - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - - if (*period > AHD_SYNCRATE_MIN) - *period = 0; - - /* Honor PPR option conformance rules. */ - if (*period > AHD_SYNCRATE_PACED) - *ppr_options &= ~MSG_EXT_PPR_RTI; - - if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0) - *ppr_options &= (MSG_EXT_PPR_DT_REQ|MSG_EXT_PPR_QAS_REQ); - - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0) - *ppr_options &= MSG_EXT_PPR_QAS_REQ; - - /* Skip all PACED only entries if IU is not available */ - if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0 - && *period < AHD_SYNCRATE_DT) - *period = AHD_SYNCRATE_DT; - - /* Skip all DT only entries if DT is not available */ - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && *period < AHD_SYNCRATE_ULTRA2) - *period = AHD_SYNCRATE_ULTRA2; -} - -/* - * Truncate the given synchronous offset to a value the - * current adapter type and syncrate are capable of. - */ -static void -ahd_validate_offset(struct ahd_softc *ahd, - struct ahd_initiator_tinfo *tinfo, - u_int period, u_int *offset, int wide, - role_t role) -{ - u_int maxoffset; - - /* Limit offset to what we can do */ - if (period == 0) - maxoffset = 0; - else if (period <= AHD_SYNCRATE_PACED) { - if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) - maxoffset = MAX_OFFSET_PACED_BUG; - else - maxoffset = MAX_OFFSET_PACED; - } else - maxoffset = MAX_OFFSET_NON_PACED; - *offset = min(*offset, maxoffset); - if (tinfo != NULL) { - if (role == ROLE_TARGET) - *offset = min(*offset, (u_int)tinfo->user.offset); - else - *offset = min(*offset, (u_int)tinfo->goal.offset); - } -} - -/* - * Truncate the given transfer width parameter to a value the - * current adapter type is capable of. - */ -static void -ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo, - u_int *bus_width, role_t role) -{ - switch (*bus_width) { - default: - if (ahd->features & AHD_WIDE) { - /* Respond Wide */ - *bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - /* FALLTHROUGH */ - case MSG_EXT_WDTR_BUS_8_BIT: - *bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - if (tinfo != NULL) { - if (role == ROLE_TARGET) - *bus_width = min((u_int)tinfo->user.width, *bus_width); - else - *bus_width = min((u_int)tinfo->goal.width, *bus_width); - } -} - -/* - * Update the bitmask of targets for which the controller should - * negotiate with at the next convenient opportunity. This currently - * means the next time we send the initial identify messages for - * a new transaction. - */ -int -ahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - struct ahd_tmode_tstate *tstate, - struct ahd_initiator_tinfo *tinfo, ahd_neg_type neg_type) -{ - u_int auto_negotiate_orig; - - auto_negotiate_orig = tstate->auto_negotiate; - if (neg_type == AHD_NEG_ALWAYS) { - /* - * Force our "current" settings to be - * unknown so that unless a bus reset - * occurs the need to renegotiate is - * recorded persistently. - */ - if ((ahd->features & AHD_WIDE) != 0) - tinfo->curr.width = AHD_WIDTH_UNKNOWN; - tinfo->curr.period = AHD_PERIOD_UNKNOWN; - tinfo->curr.offset = AHD_OFFSET_UNKNOWN; - } - if (tinfo->curr.period != tinfo->goal.period - || tinfo->curr.width != tinfo->goal.width - || tinfo->curr.offset != tinfo->goal.offset - || tinfo->curr.ppr_options != tinfo->goal.ppr_options - || (neg_type == AHD_NEG_IF_NON_ASYNC - && (tinfo->goal.offset != 0 - || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT - || tinfo->goal.ppr_options != 0))) - tstate->auto_negotiate |= devinfo->target_mask; - else - tstate->auto_negotiate &= ~devinfo->target_mask; - - return (auto_negotiate_orig != tstate->auto_negotiate); -} - -/* - * Update the user/goal/curr tables of synchronous negotiation - * parameters as well as, in the case of a current or active update, - * any data structures on the host controller. In the case of an - * active update, the specified target is currently talking to us on - * the bus, so the transfer parameter update must take effect - * immediately. - */ -void -ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - u_int period, u_int offset, u_int ppr_options, - u_int type, int paused) -{ - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - u_int old_period; - u_int old_offset; - u_int old_ppr; - int active; - int update_needed; - - active = (type & AHD_TRANS_ACTIVE) == AHD_TRANS_ACTIVE; - update_needed = 0; - - if (period == 0 || offset == 0) { - period = 0; - offset = 0; - } - - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - if ((type & AHD_TRANS_USER) != 0) { - tinfo->user.period = period; - tinfo->user.offset = offset; - tinfo->user.ppr_options = ppr_options; - } - - if ((type & AHD_TRANS_GOAL) != 0) { - tinfo->goal.period = period; - tinfo->goal.offset = offset; - tinfo->goal.ppr_options = ppr_options; - } - - old_period = tinfo->curr.period; - old_offset = tinfo->curr.offset; - old_ppr = tinfo->curr.ppr_options; - - if ((type & AHD_TRANS_CUR) != 0 - && (old_period != period - || old_offset != offset - || old_ppr != ppr_options)) { - - update_needed++; - - tinfo->curr.period = period; - tinfo->curr.offset = offset; - tinfo->curr.ppr_options = ppr_options; - - ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); - if (bootverbose) { - if (offset != 0) { - int options; - - printk("%s: target %d synchronous with " - "period = 0x%x, offset = 0x%x", - ahd_name(ahd), devinfo->target, - period, offset); - options = 0; - if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { - printk("(RDSTRM"); - options++; - } - if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { - printk("%s", options ? "|DT" : "(DT"); - options++; - } - if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - printk("%s", options ? "|IU" : "(IU"); - options++; - } - if ((ppr_options & MSG_EXT_PPR_RTI) != 0) { - printk("%s", options ? "|RTI" : "(RTI"); - options++; - } - if ((ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) { - printk("%s", options ? "|QAS" : "(QAS"); - options++; - } - if (options != 0) - printk(")\n"); - else - printk("\n"); - } else { - printk("%s: target %d using " - "asynchronous transfers%s\n", - ahd_name(ahd), devinfo->target, - (ppr_options & MSG_EXT_PPR_QAS_REQ) != 0 - ? "(QAS)" : ""); - } - } - } - /* - * Always refresh the neg-table to handle the case of the - * sequencer setting the ENATNO bit for a MK_MESSAGE request. - * We will always renegotiate in that case if this is a - * packetized request. Also manage the busfree expected flag - * from this common routine so that we catch changes due to - * WDTR or SDTR messages. - */ - if ((type & AHD_TRANS_CUR) != 0) { - if (!paused) - ahd_pause(ahd); - ahd_update_neg_table(ahd, devinfo, &tinfo->curr); - if (!paused) - ahd_unpause(ahd); - if (ahd->msg_type != MSG_TYPE_NONE) { - if ((old_ppr & MSG_EXT_PPR_IU_REQ) - != (ppr_options & MSG_EXT_PPR_IU_REQ)) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - ahd_print_devinfo(ahd, devinfo); - printk("Expecting IU Change busfree\n"); - } -#endif - ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE - | MSG_FLAG_IU_REQ_CHANGED; - } - if ((old_ppr & MSG_EXT_PPR_IU_REQ) != 0) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("PPR with IU_REQ outstanding\n"); -#endif - ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE; - } - } - } - - update_needed += ahd_update_neg_request(ahd, devinfo, tstate, - tinfo, AHD_NEG_TO_GOAL); - - if (update_needed && active) - ahd_update_pending_scbs(ahd); -} - -/* - * Update the user/goal/curr tables of wide negotiation - * parameters as well as, in the case of a current or active update, - * any data structures on the host controller. In the case of an - * active update, the specified target is currently talking to us on - * the bus, so the transfer parameter update must take effect - * immediately. - */ -void -ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - u_int width, u_int type, int paused) -{ - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - u_int oldwidth; - int active; - int update_needed; - - active = (type & AHD_TRANS_ACTIVE) == AHD_TRANS_ACTIVE; - update_needed = 0; - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - if ((type & AHD_TRANS_USER) != 0) - tinfo->user.width = width; - - if ((type & AHD_TRANS_GOAL) != 0) - tinfo->goal.width = width; - - oldwidth = tinfo->curr.width; - if ((type & AHD_TRANS_CUR) != 0 && oldwidth != width) { - - update_needed++; - - tinfo->curr.width = width; - ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); - if (bootverbose) { - printk("%s: target %d using %dbit transfers\n", - ahd_name(ahd), devinfo->target, - 8 * (0x01 << width)); - } - } - - if ((type & AHD_TRANS_CUR) != 0) { - if (!paused) - ahd_pause(ahd); - ahd_update_neg_table(ahd, devinfo, &tinfo->curr); - if (!paused) - ahd_unpause(ahd); - } - - update_needed += ahd_update_neg_request(ahd, devinfo, tstate, - tinfo, AHD_NEG_TO_GOAL); - if (update_needed && active) - ahd_update_pending_scbs(ahd); - -} - -/* - * Update the current state of tagged queuing for a given target. - */ -static void -ahd_set_tags(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, ahd_queue_alg alg) -{ - struct scsi_device *sdev = cmd->device; - - ahd_platform_set_tags(ahd, sdev, devinfo, alg); - ahd_send_async(ahd, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG); -} - -static void -ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - struct ahd_transinfo *tinfo) -{ - ahd_mode_state saved_modes; - u_int period; - u_int ppr_opts; - u_int con_opts; - u_int offset; - u_int saved_negoaddr; - uint8_t iocell_opts[sizeof(ahd->iocell_opts)]; - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - - saved_negoaddr = ahd_inb(ahd, NEGOADDR); - ahd_outb(ahd, NEGOADDR, devinfo->target); - period = tinfo->period; - offset = tinfo->offset; - memcpy(iocell_opts, ahd->iocell_opts, sizeof(ahd->iocell_opts)); - ppr_opts = tinfo->ppr_options & (MSG_EXT_PPR_QAS_REQ|MSG_EXT_PPR_DT_REQ - |MSG_EXT_PPR_IU_REQ|MSG_EXT_PPR_RTI); - con_opts = 0; - if (period == 0) - period = AHD_SYNCRATE_ASYNC; - if (period == AHD_SYNCRATE_160) { - - if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) { - /* - * When the SPI4 spec was finalized, PACE transfers - * was not made a configurable option in the PPR - * message. Instead it is assumed to be enabled for - * any syncrate faster than 80MHz. Nevertheless, - * Harpoon2A4 allows this to be configurable. - * - * Harpoon2A4 also assumes at most 2 data bytes per - * negotiated REQ/ACK offset. Paced transfers take - * 4, so we must adjust our offset. - */ - ppr_opts |= PPROPT_PACE; - offset *= 2; - - /* - * Harpoon2A assumed that there would be a - * fallback rate between 160MHz and 80MHz, - * so 7 is used as the period factor rather - * than 8 for 160MHz. - */ - period = AHD_SYNCRATE_REVA_160; - } - if ((tinfo->ppr_options & MSG_EXT_PPR_PCOMP_EN) == 0) - iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= - ~AHD_PRECOMP_MASK; - } else { - /* - * Precomp should be disabled for non-paced transfers. - */ - iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK; - - if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0 - && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0 - && (ppr_opts & MSG_EXT_PPR_IU_REQ) == 0) { - /* - * Slow down our CRC interval to be - * compatible with non-packetized - * U160 devices that can't handle a - * CRC at full speed. - */ - con_opts |= ENSLOWCRC; - } - - if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) { - /* - * On H2A4, revert to a slower slewrate - * on non-paced transfers. - */ - iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= - ~AHD_SLEWRATE_MASK; - } - } - - ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW); - ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_PRECOMP_SLEW_INDEX]); - ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_AMPLITUDE); - ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_AMPLITUDE_INDEX]); - - ahd_outb(ahd, NEGPERIOD, period); - ahd_outb(ahd, NEGPPROPTS, ppr_opts); - ahd_outb(ahd, NEGOFFSET, offset); - - if (tinfo->width == MSG_EXT_WDTR_BUS_16_BIT) - con_opts |= WIDEXFER; - - /* - * Slow down our CRC interval to be - * compatible with packetized U320 devices - * that can't handle a CRC at full speed - */ - if (ahd->features & AHD_AIC79XXB_SLOWCRC) { - con_opts |= ENSLOWCRC; - } - - /* - * During packetized transfers, the target will - * give us the opportunity to send command packets - * without us asserting attention. - */ - if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) == 0) - con_opts |= ENAUTOATNO; - ahd_outb(ahd, NEGCONOPTS, con_opts); - ahd_outb(ahd, NEGOADDR, saved_negoaddr); - ahd_restore_modes(ahd, saved_modes); -} - -/* - * When the transfer settings for a connection change, setup for - * negotiation in pending SCBs to effect the change as quickly as - * possible. We also cancel any negotiations that are scheduled - * for inflight SCBs that have not been started yet. - */ -static void -ahd_update_pending_scbs(struct ahd_softc *ahd) -{ - struct scb *pending_scb; - int pending_scb_count; - int paused; - u_int saved_scbptr; - ahd_mode_state saved_modes; - - /* - * Traverse the pending SCB list and ensure that all of the - * SCBs there have the proper settings. We can only safely - * clear the negotiation required flag (setting requires the - * execution queue to be modified) and this is only possible - * if we are not already attempting to select out for this - * SCB. For this reason, all callers only call this routine - * if we are changing the negotiation settings for the currently - * active transaction on the bus. - */ - pending_scb_count = 0; - LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - - ahd_scb_devinfo(ahd, &devinfo, pending_scb); - tinfo = ahd_fetch_transinfo(ahd, devinfo.channel, - devinfo.our_scsiid, - devinfo.target, &tstate); - if ((tstate->auto_negotiate & devinfo.target_mask) == 0 - && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { - pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; - pending_scb->hscb->control &= ~MK_MESSAGE; - } - ahd_sync_scb(ahd, pending_scb, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - pending_scb_count++; - } - - if (pending_scb_count == 0) - return; - - if (ahd_is_paused(ahd)) { - paused = 1; - } else { - paused = 0; - ahd_pause(ahd); - } - - /* - * Force the sequencer to reinitialize the selection for - * the command at the head of the execution queue if it - * has already been setup. The negotiation changes may - * effect whether we select-out with ATN. It is only - * safe to clear ENSELO when the bus is not free and no - * selection is in progres or completed. - */ - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - if ((ahd_inb(ahd, SCSISIGI) & BSYI) != 0 - && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0) - ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO); - saved_scbptr = ahd_get_scbptr(ahd); - /* Ensure that the hscbs down on the card match the new information */ - LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { - u_int scb_tag; - u_int control; - - scb_tag = SCB_GET_TAG(pending_scb); - ahd_set_scbptr(ahd, scb_tag); - control = ahd_inb_scbram(ahd, SCB_CONTROL); - control &= ~MK_MESSAGE; - control |= pending_scb->hscb->control & MK_MESSAGE; - ahd_outb(ahd, SCB_CONTROL, control); - } - ahd_set_scbptr(ahd, saved_scbptr); - ahd_restore_modes(ahd, saved_modes); - - if (paused == 0) - ahd_unpause(ahd); -} - -/**************************** Pathing Information *****************************/ -static void -ahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - ahd_mode_state saved_modes; - u_int saved_scsiid; - role_t role; - int our_id; - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - - if (ahd_inb(ahd, SSTAT0) & TARGET) - role = ROLE_TARGET; - else - role = ROLE_INITIATOR; - - if (role == ROLE_TARGET - && (ahd_inb(ahd, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) { - /* We were selected, so pull our id from TARGIDIN */ - our_id = ahd_inb(ahd, TARGIDIN) & OID; - } else if (role == ROLE_TARGET) - our_id = ahd_inb(ahd, TOWNID); - else - our_id = ahd_inb(ahd, IOWNID); - - saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); - ahd_compile_devinfo(devinfo, - our_id, - SCSIID_TARGET(ahd, saved_scsiid), - ahd_inb(ahd, SAVED_LUN), - SCSIID_CHANNEL(ahd, saved_scsiid), - role); - ahd_restore_modes(ahd, saved_modes); -} - -void -ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - printk("%s:%c:%d:%d: ", ahd_name(ahd), 'A', - devinfo->target, devinfo->lun); -} - -static const struct ahd_phase_table_entry* -ahd_lookup_phase_entry(int phase) -{ - const struct ahd_phase_table_entry *entry; - const struct ahd_phase_table_entry *last_entry; - - /* - * num_phases doesn't include the default entry which - * will be returned if the phase doesn't match. - */ - last_entry = &ahd_phase_table[num_phases]; - for (entry = ahd_phase_table; entry < last_entry; entry++) { - if (phase == entry->phase) - break; - } - return (entry); -} - -void -ahd_compile_devinfo(struct ahd_devinfo *devinfo, u_int our_id, u_int target, - u_int lun, char channel, role_t role) -{ - devinfo->our_scsiid = our_id; - devinfo->target = target; - devinfo->lun = lun; - devinfo->target_offset = target; - devinfo->channel = channel; - devinfo->role = role; - if (channel == 'B') - devinfo->target_offset += 8; - devinfo->target_mask = (0x01 << devinfo->target_offset); -} - -static void -ahd_scb_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - struct scb *scb) -{ - role_t role; - int our_id; - - our_id = SCSIID_OUR_ID(scb->hscb->scsiid); - role = ROLE_INITIATOR; - if ((scb->hscb->control & TARGET_SCB) != 0) - role = ROLE_TARGET; - ahd_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahd, scb), - SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahd, scb), role); -} - - -/************************ Message Phase Processing ****************************/ -/* - * When an initiator transaction with the MK_MESSAGE flag either reconnects - * or enters the initial message out phase, we are interrupted. Fill our - * outgoing message buffer with the appropriate message and beging handing - * the message phase(s) manually. - */ -static void -ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - struct scb *scb) -{ - /* - * To facilitate adding multiple messages together, - * each routine should increment the index and len - * variables instead of setting them explicitly. - */ - ahd->msgout_index = 0; - ahd->msgout_len = 0; - - if (ahd_currently_packetized(ahd)) - ahd->msg_flags |= MSG_FLAG_PACKETIZED; - - if (ahd->send_msg_perror - && ahd_inb(ahd, MSG_OUT) == HOST_MSG) { - ahd->msgout_buf[ahd->msgout_index++] = ahd->send_msg_perror; - ahd->msgout_len++; - ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("Setting up for Parity Error delivery\n"); -#endif - return; - } else if (scb == NULL) { - printk("%s: WARNING. No pending message for " - "I_T msgin. Issuing NO-OP\n", ahd_name(ahd)); - ahd->msgout_buf[ahd->msgout_index++] = MSG_NOOP; - ahd->msgout_len++; - ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - return; - } - - if ((scb->flags & SCB_DEVICE_RESET) == 0 - && (scb->flags & SCB_PACKETIZED) == 0 - && ahd_inb(ahd, MSG_OUT) == MSG_IDENTIFYFLAG) { - u_int identify_msg; - - identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb); - if ((scb->hscb->control & DISCENB) != 0) - identify_msg |= MSG_IDENTIFY_DISCFLAG; - ahd->msgout_buf[ahd->msgout_index++] = identify_msg; - ahd->msgout_len++; - - if ((scb->hscb->control & TAG_ENB) != 0) { - ahd->msgout_buf[ahd->msgout_index++] = - scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE); - ahd->msgout_buf[ahd->msgout_index++] = SCB_GET_TAG(scb); - ahd->msgout_len += 2; - } - } - - if (scb->flags & SCB_DEVICE_RESET) { - ahd->msgout_buf[ahd->msgout_index++] = MSG_BUS_DEV_RESET; - ahd->msgout_len++; - ahd_print_path(ahd, scb); - printk("Bus Device Reset Message Sent\n"); - /* - * Clear our selection hardware in advance of - * the busfree. We may have an entry in the waiting - * Q for this target, and we don't want to go about - * selecting while we handle the busfree and blow it - * away. - */ - ahd_outb(ahd, SCSISEQ0, 0); - } else if ((scb->flags & SCB_ABORT) != 0) { - - if ((scb->hscb->control & TAG_ENB) != 0) { - ahd->msgout_buf[ahd->msgout_index++] = MSG_ABORT_TAG; - } else { - ahd->msgout_buf[ahd->msgout_index++] = MSG_ABORT; - } - ahd->msgout_len++; - ahd_print_path(ahd, scb); - printk("Abort%s Message Sent\n", - (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); - /* - * Clear our selection hardware in advance of - * the busfree. We may have an entry in the waiting - * Q for this target, and we don't want to go about - * selecting while we handle the busfree and blow it - * away. - */ - ahd_outb(ahd, SCSISEQ0, 0); - } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { - ahd_build_transfer_msg(ahd, devinfo); - /* - * Clear our selection hardware in advance of potential - * PPR IU status change busfree. We may have an entry in - * the waiting Q for this target, and we don't want to go - * about selecting while we handle the busfree and blow - * it away. - */ - ahd_outb(ahd, SCSISEQ0, 0); - } else { - printk("ahd_intr: AWAITING_MSG for an SCB that " - "does not have a waiting message\n"); - printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, - devinfo->target_mask); - panic("SCB = %d, SCB Control = %x:%x, MSG_OUT = %x " - "SCB flags = %x", SCB_GET_TAG(scb), scb->hscb->control, - ahd_inb_scbram(ahd, SCB_CONTROL), ahd_inb(ahd, MSG_OUT), - scb->flags); - } - - /* - * Clear the MK_MESSAGE flag from the SCB so we aren't - * asked to send this message again. - */ - ahd_outb(ahd, SCB_CONTROL, - ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE); - scb->hscb->control &= ~MK_MESSAGE; - ahd->msgout_index = 0; - ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; -} - -/* - * Build an appropriate transfer negotiation message for the - * currently active target. - */ -static void -ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - /* - * We need to initiate transfer negotiations. - * If our current and goal settings are identical, - * we want to renegotiate due to a check condition. - */ - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - int dowide; - int dosync; - int doppr; - u_int period; - u_int ppr_options; - u_int offset; - - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - /* - * Filter our period based on the current connection. - * If we can't perform DT transfers on this segment (not in LVD - * mode for instance), then our decision to issue a PPR message - * may change. - */ - period = tinfo->goal.period; - offset = tinfo->goal.offset; - ppr_options = tinfo->goal.ppr_options; - /* Target initiated PPR is not allowed in the SCSI spec */ - if (devinfo->role == ROLE_TARGET) - ppr_options = 0; - ahd_devlimited_syncrate(ahd, tinfo, &period, - &ppr_options, devinfo->role); - dowide = tinfo->curr.width != tinfo->goal.width; - dosync = tinfo->curr.offset != offset || tinfo->curr.period != period; - /* - * Only use PPR if we have options that need it, even if the device - * claims to support it. There might be an expander in the way - * that doesn't. - */ - doppr = ppr_options != 0; - - if (!dowide && !dosync && !doppr) { - dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; - dosync = tinfo->goal.offset != 0; - } - - if (!dowide && !dosync && !doppr) { - /* - * Force async with a WDTR message if we have a wide bus, - * or just issue an SDTR with a 0 offset. - */ - if ((ahd->features & AHD_WIDE) != 0) - dowide = 1; - else - dosync = 1; - - if (bootverbose) { - ahd_print_devinfo(ahd, devinfo); - printk("Ensuring async\n"); - } - } - /* Target initiated PPR is not allowed in the SCSI spec */ - if (devinfo->role == ROLE_TARGET) - doppr = 0; - - /* - * Both the PPR message and SDTR message require the - * goal syncrate to be limited to what the target device - * is capable of handling (based on whether an LVD->SE - * expander is on the bus), so combine these two cases. - * Regardless, guarantee that if we are using WDTR and SDTR - * messages that WDTR comes first. - */ - if (doppr || (dosync && !dowide)) { - - offset = tinfo->goal.offset; - ahd_validate_offset(ahd, tinfo, period, &offset, - doppr ? tinfo->goal.width - : tinfo->curr.width, - devinfo->role); - if (doppr) { - ahd_construct_ppr(ahd, devinfo, period, offset, - tinfo->goal.width, ppr_options); - } else { - ahd_construct_sdtr(ahd, devinfo, period, offset); - } - } else { - ahd_construct_wdtr(ahd, devinfo, tinfo->goal.width); - } -} - -/* - * Build a synchronous negotiation message in our message - * buffer based on the input parameters. - */ -static void -ahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - u_int period, u_int offset) -{ - if (offset == 0) - period = AHD_ASYNC_XFER_PERIOD; - ahd->msgout_index += spi_populate_sync_msg( - ahd->msgout_buf + ahd->msgout_index, period, offset); - ahd->msgout_len += 5; - if (bootverbose) { - printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", - ahd_name(ahd), devinfo->channel, devinfo->target, - devinfo->lun, period, offset); - } -} - -/* - * Build a wide negotiateion message in our message - * buffer based on the input parameters. - */ -static void -ahd_construct_wdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - u_int bus_width) -{ - ahd->msgout_index += spi_populate_width_msg( - ahd->msgout_buf + ahd->msgout_index, bus_width); - ahd->msgout_len += 4; - if (bootverbose) { - printk("(%s:%c:%d:%d): Sending WDTR %x\n", - ahd_name(ahd), devinfo->channel, devinfo->target, - devinfo->lun, bus_width); - } -} - -/* - * Build a parallel protocol request message in our message - * buffer based on the input parameters. - */ -static void -ahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - u_int period, u_int offset, u_int bus_width, - u_int ppr_options) -{ - /* - * Always request precompensation from - * the other target if we are running - * at paced syncrates. - */ - if (period <= AHD_SYNCRATE_PACED) - ppr_options |= MSG_EXT_PPR_PCOMP_EN; - if (offset == 0) - period = AHD_ASYNC_XFER_PERIOD; - ahd->msgout_index += spi_populate_ppr_msg( - ahd->msgout_buf + ahd->msgout_index, period, offset, - bus_width, ppr_options); - ahd->msgout_len += 8; - if (bootverbose) { - printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " - "offset %x, ppr_options %x\n", ahd_name(ahd), - devinfo->channel, devinfo->target, devinfo->lun, - bus_width, period, offset, ppr_options); - } -} - -/* - * Clear any active message state. - */ -static void -ahd_clear_msg_state(struct ahd_softc *ahd) -{ - ahd_mode_state saved_modes; - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd->send_msg_perror = 0; - ahd->msg_flags = MSG_FLAG_NONE; - ahd->msgout_len = 0; - ahd->msgin_index = 0; - ahd->msg_type = MSG_TYPE_NONE; - if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0) { - /* - * The target didn't care to respond to our - * message request, so clear ATN. - */ - ahd_outb(ahd, CLRSINT1, CLRATNO); - } - ahd_outb(ahd, MSG_OUT, MSG_NOOP); - ahd_outb(ahd, SEQ_FLAGS2, - ahd_inb(ahd, SEQ_FLAGS2) & ~TARGET_MSG_PENDING); - ahd_restore_modes(ahd, saved_modes); -} - -/* - * Manual message loop handler. - */ -static void -ahd_handle_message_phase(struct ahd_softc *ahd) -{ - struct ahd_devinfo devinfo; - u_int bus_phase; - int end_session; - - ahd_fetch_devinfo(ahd, &devinfo); - end_session = FALSE; - bus_phase = ahd_inb(ahd, LASTPHASE); - - if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0) { - printk("LQIRETRY for LQIPHASE_OUTPKT\n"); - ahd_outb(ahd, LQCTL2, LQIRETRY); - } -reswitch: - switch (ahd->msg_type) { - case MSG_TYPE_INITIATOR_MSGOUT: - { - int lastbyte; - int phasemis; - int msgdone; - - if (ahd->msgout_len == 0 && ahd->send_msg_perror == 0) - panic("HOST_MSG_LOOP interrupt with no active message"); - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - ahd_print_devinfo(ahd, &devinfo); - printk("INITIATOR_MSG_OUT"); - } -#endif - phasemis = bus_phase != P_MESGOUT; - if (phasemis) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - printk(" PHASEMIS %s\n", - ahd_lookup_phase_entry(bus_phase) - ->phasemsg); - } -#endif - if (bus_phase == P_MESGIN) { - /* - * Change gears and see if - * this messages is of interest to - * us or should be passed back to - * the sequencer. - */ - ahd_outb(ahd, CLRSINT1, CLRATNO); - ahd->send_msg_perror = 0; - ahd->msg_type = MSG_TYPE_INITIATOR_MSGIN; - ahd->msgin_index = 0; - goto reswitch; - } - end_session = TRUE; - break; - } - - if (ahd->send_msg_perror) { - ahd_outb(ahd, CLRSINT1, CLRATNO); - ahd_outb(ahd, CLRSINT1, CLRREQINIT); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk(" byte 0x%x\n", ahd->send_msg_perror); -#endif - /* - * If we are notifying the target of a CRC error - * during packetized operations, the target is - * within its rights to acknowledge our message - * with a busfree. - */ - if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0 - && ahd->send_msg_perror == MSG_INITIATOR_DET_ERR) - ahd->msg_flags |= MSG_FLAG_EXPECT_IDE_BUSFREE; - - ahd_outb(ahd, RETURN_2, ahd->send_msg_perror); - ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_WRITE); - break; - } - - msgdone = ahd->msgout_index == ahd->msgout_len; - if (msgdone) { - /* - * The target has requested a retry. - * Re-assert ATN, reset our message index to - * 0, and try again. - */ - ahd->msgout_index = 0; - ahd_assert_atn(ahd); - } - - lastbyte = ahd->msgout_index == (ahd->msgout_len - 1); - if (lastbyte) { - /* Last byte is signified by dropping ATN */ - ahd_outb(ahd, CLRSINT1, CLRATNO); - } - - /* - * Clear our interrupt status and present - * the next byte on the bus. - */ - ahd_outb(ahd, CLRSINT1, CLRREQINIT); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk(" byte 0x%x\n", - ahd->msgout_buf[ahd->msgout_index]); -#endif - ahd_outb(ahd, RETURN_2, ahd->msgout_buf[ahd->msgout_index++]); - ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_WRITE); - break; - } - case MSG_TYPE_INITIATOR_MSGIN: - { - int phasemis; - int message_done; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - ahd_print_devinfo(ahd, &devinfo); - printk("INITIATOR_MSG_IN"); - } -#endif - phasemis = bus_phase != P_MESGIN; - if (phasemis) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - printk(" PHASEMIS %s\n", - ahd_lookup_phase_entry(bus_phase) - ->phasemsg); - } -#endif - ahd->msgin_index = 0; - if (bus_phase == P_MESGOUT - && (ahd->send_msg_perror != 0 - || (ahd->msgout_len != 0 - && ahd->msgout_index == 0))) { - ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - goto reswitch; - } - end_session = TRUE; - break; - } - - /* Pull the byte in without acking it */ - ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIBUS); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk(" byte 0x%x\n", - ahd->msgin_buf[ahd->msgin_index]); -#endif - - message_done = ahd_parse_msg(ahd, &devinfo); - - if (message_done) { - /* - * Clear our incoming message buffer in case there - * is another message following this one. - */ - ahd->msgin_index = 0; - - /* - * If this message illicited a response, - * assert ATN so the target takes us to the - * message out phase. - */ - if (ahd->msgout_len != 0) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) { - ahd_print_devinfo(ahd, &devinfo); - printk("Asserting ATN for response\n"); - } -#endif - ahd_assert_atn(ahd); - } - } else - ahd->msgin_index++; - - if (message_done == MSGLOOP_TERMINATED) { - end_session = TRUE; - } else { - /* Ack the byte */ - ahd_outb(ahd, CLRSINT1, CLRREQINIT); - ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_READ); - } - break; - } - case MSG_TYPE_TARGET_MSGIN: - { - int msgdone; - int msgout_request; - - /* - * By default, the message loop will continue. - */ - ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); - - if (ahd->msgout_len == 0) - panic("Target MSGIN with no active message"); - - /* - * If we interrupted a mesgout session, the initiator - * will not know this until our first REQ. So, we - * only honor mesgout requests after we've sent our - * first byte. - */ - if ((ahd_inb(ahd, SCSISIGI) & ATNI) != 0 - && ahd->msgout_index > 0) - msgout_request = TRUE; - else - msgout_request = FALSE; - - if (msgout_request) { - - /* - * Change gears and see if - * this messages is of interest to - * us or should be passed back to - * the sequencer. - */ - ahd->msg_type = MSG_TYPE_TARGET_MSGOUT; - ahd_outb(ahd, SCSISIGO, P_MESGOUT | BSYO); - ahd->msgin_index = 0; - /* Dummy read to REQ for first byte */ - ahd_inb(ahd, SCSIDAT); - ahd_outb(ahd, SXFRCTL0, - ahd_inb(ahd, SXFRCTL0) | SPIOEN); - break; - } - - msgdone = ahd->msgout_index == ahd->msgout_len; - if (msgdone) { - ahd_outb(ahd, SXFRCTL0, - ahd_inb(ahd, SXFRCTL0) & ~SPIOEN); - end_session = TRUE; - break; - } - - /* - * Present the next byte on the bus. - */ - ahd_outb(ahd, SXFRCTL0, ahd_inb(ahd, SXFRCTL0) | SPIOEN); - ahd_outb(ahd, SCSIDAT, ahd->msgout_buf[ahd->msgout_index++]); - break; - } - case MSG_TYPE_TARGET_MSGOUT: - { - int lastbyte; - int msgdone; - - /* - * By default, the message loop will continue. - */ - ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG); - - /* - * The initiator signals that this is - * the last byte by dropping ATN. - */ - lastbyte = (ahd_inb(ahd, SCSISIGI) & ATNI) == 0; - - /* - * Read the latched byte, but turn off SPIOEN first - * so that we don't inadvertently cause a REQ for the - * next byte. - */ - ahd_outb(ahd, SXFRCTL0, ahd_inb(ahd, SXFRCTL0) & ~SPIOEN); - ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIDAT); - msgdone = ahd_parse_msg(ahd, &devinfo); - if (msgdone == MSGLOOP_TERMINATED) { - /* - * The message is *really* done in that it caused - * us to go to bus free. The sequencer has already - * been reset at this point, so pull the ejection - * handle. - */ - return; - } - - ahd->msgin_index++; - - /* - * XXX Read spec about initiator dropping ATN too soon - * and use msgdone to detect it. - */ - if (msgdone == MSGLOOP_MSGCOMPLETE) { - ahd->msgin_index = 0; - - /* - * If this message illicited a response, transition - * to the Message in phase and send it. - */ - if (ahd->msgout_len != 0) { - ahd_outb(ahd, SCSISIGO, P_MESGIN | BSYO); - ahd_outb(ahd, SXFRCTL0, - ahd_inb(ahd, SXFRCTL0) | SPIOEN); - ahd->msg_type = MSG_TYPE_TARGET_MSGIN; - ahd->msgin_index = 0; - break; - } - } - - if (lastbyte) - end_session = TRUE; - else { - /* Ask for the next byte. */ - ahd_outb(ahd, SXFRCTL0, - ahd_inb(ahd, SXFRCTL0) | SPIOEN); - } - - break; - } - default: - panic("Unknown REQINIT message type"); - } - - if (end_session) { - if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0) { - printk("%s: Returning to Idle Loop\n", - ahd_name(ahd)); - ahd_clear_msg_state(ahd); - - /* - * Perform the equivalent of a clear_target_state. - */ - ahd_outb(ahd, LASTPHASE, P_BUSFREE); - ahd_outb(ahd, SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT); - ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET); - } else { - ahd_clear_msg_state(ahd); - ahd_outb(ahd, RETURN_1, EXIT_MSG_LOOP); - } - } -} - -/* - * See if we sent a particular extended message to the target. - * If "full" is true, return true only if the target saw the full - * message. If "full" is false, return true if the target saw at - * least the first byte of the message. - */ -static int -ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type, u_int msgval, int full) -{ - int found; - u_int index; - - found = FALSE; - index = 0; - - while (index < ahd->msgout_len) { - if (ahd->msgout_buf[index] == MSG_EXTENDED) { - u_int end_index; - - end_index = index + 1 + ahd->msgout_buf[index + 1]; - if (ahd->msgout_buf[index+2] == msgval - && type == AHDMSG_EXT) { - - if (full) { - if (ahd->msgout_index > end_index) - found = TRUE; - } else if (ahd->msgout_index > index) - found = TRUE; - } - index = end_index; - } else if (ahd->msgout_buf[index] >= MSG_SIMPLE_TASK - && ahd->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { - - /* Skip tag type and tag id or residue param*/ - index += 2; - } else { - /* Single byte message */ - if (type == AHDMSG_1B - && ahd->msgout_index > index - && (ahd->msgout_buf[index] == msgval - || ((ahd->msgout_buf[index] & MSG_IDENTIFYFLAG) != 0 - && msgval == MSG_IDENTIFYFLAG))) - found = TRUE; - index++; - } - - if (found) - break; - } - return (found); -} - -/* - * Wait for a complete incoming message, parse it, and respond accordingly. - */ -static int -ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - int reject; - int done; - int response; - - done = MSGLOOP_IN_PROG; - response = FALSE; - reject = FALSE; - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - /* - * Parse as much of the message as is available, - * rejecting it if we don't support it. When - * the entire message is available and has been - * handled, return MSGLOOP_MSGCOMPLETE, indicating - * that we have parsed an entire message. - * - * In the case of extended messages, we accept the length - * byte outright and perform more checking once we know the - * extended message type. - */ - switch (ahd->msgin_buf[0]) { - case MSG_DISCONNECT: - case MSG_SAVEDATAPOINTER: - case MSG_CMDCOMPLETE: - case MSG_RESTOREPOINTERS: - case MSG_IGN_WIDE_RESIDUE: - /* - * End our message loop as these are messages - * the sequencer handles on its own. - */ - done = MSGLOOP_TERMINATED; - break; - case MSG_MESSAGE_REJECT: - response = ahd_handle_msg_reject(ahd, devinfo); - /* FALLTHROUGH */ - case MSG_NOOP: - done = MSGLOOP_MSGCOMPLETE; - break; - case MSG_EXTENDED: - { - /* Wait for enough of the message to begin validation */ - if (ahd->msgin_index < 2) - break; - switch (ahd->msgin_buf[2]) { - case MSG_EXT_SDTR: - { - u_int period; - u_int ppr_options; - u_int offset; - u_int saved_offset; - - if (ahd->msgin_buf[1] != MSG_EXT_SDTR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have both args before validating - * and acting on this message. - * - * Add one to MSG_EXT_SDTR_LEN to account for - * the extended message preamble. - */ - if (ahd->msgin_index < (MSG_EXT_SDTR_LEN + 1)) - break; - - period = ahd->msgin_buf[3]; - ppr_options = 0; - saved_offset = offset = ahd->msgin_buf[4]; - ahd_devlimited_syncrate(ahd, tinfo, &period, - &ppr_options, devinfo->role); - ahd_validate_offset(ahd, tinfo, period, &offset, - tinfo->curr.width, devinfo->role); - if (bootverbose) { - printk("(%s:%c:%d:%d): Received " - "SDTR period %x, offset %x\n\t" - "Filtered to period %x, offset %x\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun, - ahd->msgin_buf[3], saved_offset, - period, offset); - } - ahd_set_syncrate(ahd, devinfo, period, - offset, ppr_options, - AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, - /*paused*/TRUE); - - /* - * See if we initiated Sync Negotiation - * and didn't have to fall down to async - * transfers. - */ - if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, TRUE)) { - /* We started it */ - if (saved_offset != offset) { - /* Went too low - force async */ - reject = TRUE; - } - } else { - /* - * Send our own SDTR in reply - */ - if (bootverbose - && devinfo->role == ROLE_INITIATOR) { - printk("(%s:%c:%d:%d): Target " - "Initiated SDTR\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun); - } - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_construct_sdtr(ahd, devinfo, - period, offset); - ahd->msgout_index = 0; - response = TRUE; - } - done = MSGLOOP_MSGCOMPLETE; - break; - } - case MSG_EXT_WDTR: - { - u_int bus_width; - u_int saved_width; - u_int sending_reply; - - sending_reply = FALSE; - if (ahd->msgin_buf[1] != MSG_EXT_WDTR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have our arg before validating - * and acting on this message. - * - * Add one to MSG_EXT_WDTR_LEN to account for - * the extended message preamble. - */ - if (ahd->msgin_index < (MSG_EXT_WDTR_LEN + 1)) - break; - - bus_width = ahd->msgin_buf[3]; - saved_width = bus_width; - ahd_validate_width(ahd, tinfo, &bus_width, - devinfo->role); - if (bootverbose) { - printk("(%s:%c:%d:%d): Received WDTR " - "%x filtered to %x\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun, - saved_width, bus_width); - } - - if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, TRUE)) { - /* - * Don't send a WDTR back to the - * target, since we asked first. - * If the width went higher than our - * request, reject it. - */ - if (saved_width > bus_width) { - reject = TRUE; - printk("(%s:%c:%d:%d): requested %dBit " - "transfers. Rejecting...\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun, - 8 * (0x01 << bus_width)); - bus_width = 0; - } - } else { - /* - * Send our own WDTR in reply - */ - if (bootverbose - && devinfo->role == ROLE_INITIATOR) { - printk("(%s:%c:%d:%d): Target " - "Initiated WDTR\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun); - } - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_construct_wdtr(ahd, devinfo, bus_width); - ahd->msgout_index = 0; - response = TRUE; - sending_reply = TRUE; - } - /* - * After a wide message, we are async, but - * some devices don't seem to honor this portion - * of the spec. Force a renegotiation of the - * sync component of our transfer agreement even - * if our goal is async. By updating our width - * after forcing the negotiation, we avoid - * renegotiating for width. - */ - ahd_update_neg_request(ahd, devinfo, tstate, - tinfo, AHD_NEG_ALWAYS); - ahd_set_width(ahd, devinfo, bus_width, - AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, - /*paused*/TRUE); - if (sending_reply == FALSE && reject == FALSE) { - - /* - * We will always have an SDTR to send. - */ - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_build_transfer_msg(ahd, devinfo); - ahd->msgout_index = 0; - response = TRUE; - } - done = MSGLOOP_MSGCOMPLETE; - break; - } - case MSG_EXT_PPR: - { - u_int period; - u_int offset; - u_int bus_width; - u_int ppr_options; - u_int saved_width; - u_int saved_offset; - u_int saved_ppr_options; - - if (ahd->msgin_buf[1] != MSG_EXT_PPR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have all args before validating - * and acting on this message. - * - * Add one to MSG_EXT_PPR_LEN to account for - * the extended message preamble. - */ - if (ahd->msgin_index < (MSG_EXT_PPR_LEN + 1)) - break; - - period = ahd->msgin_buf[3]; - offset = ahd->msgin_buf[5]; - bus_width = ahd->msgin_buf[6]; - saved_width = bus_width; - ppr_options = ahd->msgin_buf[7]; - /* - * According to the spec, a DT only - * period factor with no DT option - * set implies async. - */ - if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && period <= 9) - offset = 0; - saved_ppr_options = ppr_options; - saved_offset = offset; - - /* - * Transfer options are only available if we - * are negotiating wide. - */ - if (bus_width == 0) - ppr_options &= MSG_EXT_PPR_QAS_REQ; - - ahd_validate_width(ahd, tinfo, &bus_width, - devinfo->role); - ahd_devlimited_syncrate(ahd, tinfo, &period, - &ppr_options, devinfo->role); - ahd_validate_offset(ahd, tinfo, period, &offset, - bus_width, devinfo->role); - - if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, TRUE)) { - /* - * If we are unable to do any of the - * requested options (we went too low), - * then we'll have to reject the message. - */ - if (saved_width > bus_width - || saved_offset != offset - || saved_ppr_options != ppr_options) { - reject = TRUE; - period = 0; - offset = 0; - bus_width = 0; - ppr_options = 0; - } - } else { - if (devinfo->role != ROLE_TARGET) - printk("(%s:%c:%d:%d): Target " - "Initiated PPR\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun); - else - printk("(%s:%c:%d:%d): Initiator " - "Initiated PPR\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun); - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_construct_ppr(ahd, devinfo, period, offset, - bus_width, ppr_options); - ahd->msgout_index = 0; - response = TRUE; - } - if (bootverbose) { - printk("(%s:%c:%d:%d): Received PPR width %x, " - "period %x, offset %x,options %x\n" - "\tFiltered to width %x, period %x, " - "offset %x, options %x\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun, - saved_width, ahd->msgin_buf[3], - saved_offset, saved_ppr_options, - bus_width, period, offset, ppr_options); - } - ahd_set_width(ahd, devinfo, bus_width, - AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, - /*paused*/TRUE); - ahd_set_syncrate(ahd, devinfo, period, - offset, ppr_options, - AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, - /*paused*/TRUE); - - done = MSGLOOP_MSGCOMPLETE; - break; - } - default: - /* Unknown extended message. Reject it. */ - reject = TRUE; - break; - } - break; - } -#ifdef AHD_TARGET_MODE - case MSG_BUS_DEV_RESET: - ahd_handle_devreset(ahd, devinfo, CAM_LUN_WILDCARD, - CAM_BDR_SENT, - "Bus Device Reset Received", - /*verbose_level*/0); - ahd_restart(ahd); - done = MSGLOOP_TERMINATED; - break; - case MSG_ABORT_TAG: - case MSG_ABORT: - case MSG_CLEAR_QUEUE: - { - int tag; - - /* Target mode messages */ - if (devinfo->role != ROLE_TARGET) { - reject = TRUE; - break; - } - tag = SCB_LIST_NULL; - if (ahd->msgin_buf[0] == MSG_ABORT_TAG) - tag = ahd_inb(ahd, INITIATOR_TAG); - ahd_abort_scbs(ahd, devinfo->target, devinfo->channel, - devinfo->lun, tag, ROLE_TARGET, - CAM_REQ_ABORTED); - - tstate = ahd->enabled_targets[devinfo->our_scsiid]; - if (tstate != NULL) { - struct ahd_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[devinfo->lun]; - if (lstate != NULL) { - ahd_queue_lstate_event(ahd, lstate, - devinfo->our_scsiid, - ahd->msgin_buf[0], - /*arg*/tag); - ahd_send_lstate_events(ahd, lstate); - } - } - ahd_restart(ahd); - done = MSGLOOP_TERMINATED; - break; - } -#endif - case MSG_QAS_REQUEST: -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printk("%s: QAS request. SCSISIGI == 0x%x\n", - ahd_name(ahd), ahd_inb(ahd, SCSISIGI)); -#endif - ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE; - /* FALLTHROUGH */ - case MSG_TERM_IO_PROC: - default: - reject = TRUE; - break; - } - - if (reject) { - /* - * Setup to reject the message. - */ - ahd->msgout_index = 0; - ahd->msgout_len = 1; - ahd->msgout_buf[0] = MSG_MESSAGE_REJECT; - done = MSGLOOP_MSGCOMPLETE; - response = TRUE; - } - - if (done != MSGLOOP_IN_PROG && !response) - /* Clear the outgoing message buffer */ - ahd->msgout_len = 0; - - return (done); -} - -/* - * Process a message reject message. - */ -static int -ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - /* - * What we care about here is if we had an - * outstanding SDTR or WDTR message for this - * target. If we did, this is a signal that - * the target is refusing negotiation. - */ - struct scb *scb; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - u_int scb_index; - u_int last_msg; - int response = 0; - - scb_index = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scb_index); - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, - devinfo->our_scsiid, - devinfo->target, &tstate); - /* Might be necessary */ - last_msg = ahd_inb(ahd, LAST_MSG); - - if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) { - if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/TRUE) - && tinfo->goal.period <= AHD_SYNCRATE_PACED) { - /* - * Target may not like our SPI-4 PPR Options. - * Attempt to negotiate 80MHz which will turn - * off these options. - */ - if (bootverbose) { - printk("(%s:%c:%d:%d): PPR Rejected. " - "Trying simple U160 PPR\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun); - } - tinfo->goal.period = AHD_SYNCRATE_DT; - tinfo->goal.ppr_options &= MSG_EXT_PPR_IU_REQ - | MSG_EXT_PPR_QAS_REQ - | MSG_EXT_PPR_DT_REQ; - } else { - /* - * Target does not support the PPR message. - * Attempt to negotiate SPI-2 style. - */ - if (bootverbose) { - printk("(%s:%c:%d:%d): PPR Rejected. " - "Trying WDTR/SDTR\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun); - } - tinfo->goal.ppr_options = 0; - tinfo->curr.transport_version = 2; - tinfo->goal.transport_version = 2; - } - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_build_transfer_msg(ahd, devinfo); - ahd->msgout_index = 0; - response = 1; - } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { - - /* note 8bit xfers */ - printk("(%s:%c:%d:%d): refuses WIDE negotiation. Using " - "8bit transfers\n", ahd_name(ahd), - devinfo->channel, devinfo->target, devinfo->lun); - ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, - /*paused*/TRUE); - /* - * No need to clear the sync rate. If the target - * did not accept the command, our syncrate is - * unaffected. If the target started the negotiation, - * but rejected our response, we already cleared the - * sync rate before sending our WDTR. - */ - if (tinfo->goal.offset != tinfo->curr.offset) { - - /* Start the sync negotiation */ - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_build_transfer_msg(ahd, devinfo); - ahd->msgout_index = 0; - response = 1; - } - } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) { - /* note asynch xfers and clear flag */ - ahd_set_syncrate(ahd, devinfo, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, - /*paused*/TRUE); - printk("(%s:%c:%d:%d): refuses synchronous negotiation. " - "Using asynchronous transfers\n", - ahd_name(ahd), devinfo->channel, - devinfo->target, devinfo->lun); - } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { - int tag_type; - int mask; - - tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); - - if (tag_type == MSG_SIMPLE_TASK) { - printk("(%s:%c:%d:%d): refuses tagged commands. " - "Performing non-tagged I/O\n", ahd_name(ahd), - devinfo->channel, devinfo->target, devinfo->lun); - ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_NONE); - mask = ~0x23; - } else { - printk("(%s:%c:%d:%d): refuses %s tagged commands. " - "Performing simple queue tagged I/O only\n", - ahd_name(ahd), devinfo->channel, devinfo->target, - devinfo->lun, tag_type == MSG_ORDERED_TASK - ? "ordered" : "head of queue"); - ahd_set_tags(ahd, scb->io_ctx, devinfo, AHD_QUEUE_BASIC); - mask = ~0x03; - } - - /* - * Resend the identify for this CCB as the target - * may believe that the selection is invalid otherwise. - */ - ahd_outb(ahd, SCB_CONTROL, - ahd_inb_scbram(ahd, SCB_CONTROL) & mask); - scb->hscb->control &= mask; - ahd_set_transaction_tag(scb, /*enabled*/FALSE, - /*type*/MSG_SIMPLE_TASK); - ahd_outb(ahd, MSG_OUT, MSG_IDENTIFYFLAG); - ahd_assert_atn(ahd); - ahd_busy_tcl(ahd, BUILD_TCL(scb->hscb->scsiid, devinfo->lun), - SCB_GET_TAG(scb)); - - /* - * Requeue all tagged commands for this target - * currently in our possession so they can be - * converted to untagged commands. - */ - ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb), - SCB_GET_CHANNEL(ahd, scb), - SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ, - SEARCH_COMPLETE); - } else if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_IDENTIFYFLAG, TRUE)) { - /* - * Most likely the device believes that we had - * previously negotiated packetized. - */ - ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE - | MSG_FLAG_IU_REQ_CHANGED; - - ahd_force_renegotiation(ahd, devinfo); - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_build_transfer_msg(ahd, devinfo); - ahd->msgout_index = 0; - response = 1; - } else { - /* - * Otherwise, we ignore it. - */ - printk("%s:%c:%d: Message reject for %x -- ignored\n", - ahd_name(ahd), devinfo->channel, devinfo->target, - last_msg); - } - return (response); -} - -/* - * Process an ingnore wide residue message. - */ -static void -ahd_handle_ign_wide_residue(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - u_int scb_index; - struct scb *scb; - - scb_index = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scb_index); - /* - * XXX Actually check data direction in the sequencer? - * Perhaps add datadir to some spare bits in the hscb? - */ - if ((ahd_inb(ahd, SEQ_FLAGS) & DPHASE) == 0 - || ahd_get_transfer_dir(scb) != CAM_DIR_IN) { - /* - * Ignore the message if we haven't - * seen an appropriate data phase yet. - */ - } else { - /* - * If the residual occurred on the last - * transfer and the transfer request was - * expected to end on an odd count, do - * nothing. Otherwise, subtract a byte - * and update the residual count accordingly. - */ - uint32_t sgptr; - - sgptr = ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR); - if ((sgptr & SG_LIST_NULL) != 0 - && (ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE) - & SCB_XFERLEN_ODD) != 0) { - /* - * If the residual occurred on the last - * transfer and the transfer request was - * expected to end on an odd count, do - * nothing. - */ - } else { - uint32_t data_cnt; - uint64_t data_addr; - uint32_t sglen; - - /* Pull in the rest of the sgptr */ - sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); - data_cnt = ahd_inl_scbram(ahd, SCB_RESIDUAL_DATACNT); - if ((sgptr & SG_LIST_NULL) != 0) { - /* - * The residual data count is not updated - * for the command run to completion case. - * Explicitly zero the count. - */ - data_cnt &= ~AHD_SG_LEN_MASK; - } - data_addr = ahd_inq(ahd, SHADDR); - data_cnt += 1; - data_addr -= 1; - sgptr &= SG_PTR_MASK; - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { - struct ahd_dma64_seg *sg; - - sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); - - /* - * The residual sg ptr points to the next S/G - * to load so we must go back one. - */ - sg--; - sglen = ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; - if (sg != scb->sg_list - && sglen < (data_cnt & AHD_SG_LEN_MASK)) { - - sg--; - sglen = ahd_le32toh(sg->len); - /* - * Preserve High Address and SG_LIST - * bits while setting the count to 1. - */ - data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK)); - data_addr = ahd_le64toh(sg->addr) - + (sglen & AHD_SG_LEN_MASK) - - 1; - - /* - * Increment sg so it points to the - * "next" sg. - */ - sg++; - sgptr = ahd_sg_virt_to_bus(ahd, scb, - sg); - } - } else { - struct ahd_dma_seg *sg; - - sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); - - /* - * The residual sg ptr points to the next S/G - * to load so we must go back one. - */ - sg--; - sglen = ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; - if (sg != scb->sg_list - && sglen < (data_cnt & AHD_SG_LEN_MASK)) { - - sg--; - sglen = ahd_le32toh(sg->len); - /* - * Preserve High Address and SG_LIST - * bits while setting the count to 1. - */ - data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK)); - data_addr = ahd_le32toh(sg->addr) - + (sglen & AHD_SG_LEN_MASK) - - 1; - - /* - * Increment sg so it points to the - * "next" sg. - */ - sg++; - sgptr = ahd_sg_virt_to_bus(ahd, scb, - sg); - } - } - /* - * Toggle the "oddness" of the transfer length - * to handle this mid-transfer ignore wide - * residue. This ensures that the oddness is - * correct for subsequent data transfers. - */ - ahd_outb(ahd, SCB_TASK_ATTRIBUTE, - ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE) - ^ SCB_XFERLEN_ODD); - - ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); - ahd_outl(ahd, SCB_RESIDUAL_DATACNT, data_cnt); - /* - * The FIFO's pointers will be updated if/when the - * sequencer re-enters a data phase. - */ - } - } -} - - -/* - * Reinitialize the data pointers for the active transfer - * based on its current residual. - */ -static void -ahd_reinitialize_dataptrs(struct ahd_softc *ahd) -{ - struct scb *scb; - ahd_mode_state saved_modes; - u_int scb_index; - u_int wait; - uint32_t sgptr; - uint32_t resid; - uint64_t dataptr; - - AHD_ASSERT_MODES(ahd, AHD_MODE_DFF0_MSK|AHD_MODE_DFF1_MSK, - AHD_MODE_DFF0_MSK|AHD_MODE_DFF1_MSK); - - scb_index = ahd_get_scbptr(ahd); - scb = ahd_lookup_scb(ahd, scb_index); - - /* - * Release and reacquire the FIFO so we - * have a clean slate. - */ - ahd_outb(ahd, DFFSXFRCTL, CLRCHN); - wait = 1000; - while (--wait && !(ahd_inb(ahd, MDFFSTAT) & FIFOFREE)) - ahd_delay(100); - if (wait == 0) { - ahd_print_path(ahd, scb); - printk("ahd_reinitialize_dataptrs: Forcing FIFO free.\n"); - ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT); - } - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_outb(ahd, DFFSTAT, - ahd_inb(ahd, DFFSTAT) - | (saved_modes == 0x11 ? CURRFIFO_1 : CURRFIFO_0)); - - /* - * Determine initial values for data_addr and data_cnt - * for resuming the data phase. - */ - sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); - sgptr &= SG_PTR_MASK; - - resid = (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 2) << 16) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 1) << 8) - | ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT); - - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { - struct ahd_dma64_seg *sg; - - sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); - - /* The residual sg_ptr always points to the next sg */ - sg--; - - dataptr = ahd_le64toh(sg->addr) - + (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK) - - resid; - ahd_outl(ahd, HADDR + 4, dataptr >> 32); - } else { - struct ahd_dma_seg *sg; - - sg = ahd_sg_bus_to_virt(ahd, scb, sgptr); - - /* The residual sg_ptr always points to the next sg */ - sg--; - - dataptr = ahd_le32toh(sg->addr) - + (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK) - - resid; - ahd_outb(ahd, HADDR + 4, - (ahd_le32toh(sg->len) & ~AHD_SG_LEN_MASK) >> 24); - } - ahd_outl(ahd, HADDR, dataptr); - ahd_outb(ahd, HCNT + 2, resid >> 16); - ahd_outb(ahd, HCNT + 1, resid >> 8); - ahd_outb(ahd, HCNT, resid); -} - -/* - * Handle the effects of issuing a bus device reset message. - */ -static void -ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - u_int lun, cam_status status, char *message, - int verbose_level) -{ -#ifdef AHD_TARGET_MODE - struct ahd_tmode_tstate* tstate; -#endif - int found; - - found = ahd_abort_scbs(ahd, devinfo->target, devinfo->channel, - lun, SCB_LIST_NULL, devinfo->role, - status); - -#ifdef AHD_TARGET_MODE - /* - * Send an immediate notify ccb to all target mord peripheral - * drivers affected by this action. - */ - tstate = ahd->enabled_targets[devinfo->our_scsiid]; - if (tstate != NULL) { - u_int cur_lun; - u_int max_lun; - - if (lun != CAM_LUN_WILDCARD) { - cur_lun = 0; - max_lun = AHD_NUM_LUNS - 1; - } else { - cur_lun = lun; - max_lun = lun; - } - for (;cur_lun <= max_lun; cur_lun++) { - struct ahd_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[cur_lun]; - if (lstate == NULL) - continue; - - ahd_queue_lstate_event(ahd, lstate, devinfo->our_scsiid, - MSG_BUS_DEV_RESET, /*arg*/0); - ahd_send_lstate_events(ahd, lstate); - } - } -#endif - - /* - * Go back to async/narrow transfers and renegotiate. - */ - ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_CUR, /*paused*/TRUE); - ahd_set_syncrate(ahd, devinfo, /*period*/0, /*offset*/0, - /*ppr_options*/0, AHD_TRANS_CUR, - /*paused*/TRUE); - - if (status != CAM_SEL_TIMEOUT) - ahd_send_async(ahd, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR); - - if (message != NULL && bootverbose) - printk("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd), - message, devinfo->channel, devinfo->target, found); -} - -#ifdef AHD_TARGET_MODE -static void -ahd_setup_target_msgin(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, - struct scb *scb) -{ - - /* - * To facilitate adding multiple messages together, - * each routine should increment the index and len - * variables instead of setting them explicitly. - */ - ahd->msgout_index = 0; - ahd->msgout_len = 0; - - if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) - ahd_build_transfer_msg(ahd, devinfo); - else - panic("ahd_intr: AWAITING target message with no message"); - - ahd->msgout_index = 0; - ahd->msg_type = MSG_TYPE_TARGET_MSGIN; -} -#endif -/**************************** Initialization **********************************/ -static u_int -ahd_sglist_size(struct ahd_softc *ahd) -{ - bus_size_t list_size; - - list_size = sizeof(struct ahd_dma_seg) * AHD_NSEG; - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) - list_size = sizeof(struct ahd_dma64_seg) * AHD_NSEG; - return (list_size); -} - -/* - * Calculate the optimum S/G List allocation size. S/G elements used - * for a given transaction must be physically contiguous. Assume the - * OS will allocate full pages to us, so it doesn't make sense to request - * less than a page. - */ -static u_int -ahd_sglist_allocsize(struct ahd_softc *ahd) -{ - bus_size_t sg_list_increment; - bus_size_t sg_list_size; - bus_size_t max_list_size; - bus_size_t best_list_size; - - /* Start out with the minimum required for AHD_NSEG. */ - sg_list_increment = ahd_sglist_size(ahd); - sg_list_size = sg_list_increment; - - /* Get us as close as possible to a page in size. */ - while ((sg_list_size + sg_list_increment) <= PAGE_SIZE) - sg_list_size += sg_list_increment; - - /* - * Try to reduce the amount of wastage by allocating - * multiple pages. - */ - best_list_size = sg_list_size; - max_list_size = roundup(sg_list_increment, PAGE_SIZE); - if (max_list_size < 4 * PAGE_SIZE) - max_list_size = 4 * PAGE_SIZE; - if (max_list_size > (AHD_SCB_MAX_ALLOC * sg_list_increment)) - max_list_size = (AHD_SCB_MAX_ALLOC * sg_list_increment); - while ((sg_list_size + sg_list_increment) <= max_list_size - && (sg_list_size % PAGE_SIZE) != 0) { - bus_size_t new_mod; - bus_size_t best_mod; - - sg_list_size += sg_list_increment; - new_mod = sg_list_size % PAGE_SIZE; - best_mod = best_list_size % PAGE_SIZE; - if (new_mod > best_mod || new_mod == 0) { - best_list_size = sg_list_size; - } - } - return (best_list_size); -} - -/* - * Allocate a controller structure for a new device - * and perform initial initializion. - */ -struct ahd_softc * -ahd_alloc(void *platform_arg, char *name) -{ - struct ahd_softc *ahd; - -#ifndef __FreeBSD__ - ahd = kmalloc(sizeof(*ahd), GFP_ATOMIC); - if (!ahd) { - printk("aic7xxx: cannot malloc softc!\n"); - kfree(name); - return NULL; - } -#else - ahd = device_get_softc((device_t)platform_arg); -#endif - memset(ahd, 0, sizeof(*ahd)); - ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC); - if (ahd->seep_config == NULL) { -#ifndef __FreeBSD__ - kfree(ahd); -#endif - kfree(name); - return (NULL); - } - LIST_INIT(&ahd->pending_scbs); - /* We don't know our unit number until the OSM sets it */ - ahd->name = name; - ahd->unit = -1; - ahd->description = NULL; - ahd->bus_description = NULL; - ahd->channel = 'A'; - ahd->chip = AHD_NONE; - ahd->features = AHD_FENONE; - ahd->bugs = AHD_BUGNONE; - ahd->flags = AHD_SPCHK_ENB_A|AHD_RESET_BUS_A|AHD_TERM_ENB_A - | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A; - ahd_timer_init(&ahd->reset_timer); - ahd_timer_init(&ahd->stat_timer); - ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT; - ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT; - ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT; - ahd->int_coalescing_threshold = AHD_INT_COALESCING_THRESHOLD_DEFAULT; - ahd->int_coalescing_stop_threshold = - AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT; - - if (ahd_platform_alloc(ahd, platform_arg) != 0) { - ahd_free(ahd); - ahd = NULL; - } -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MEMORY) != 0) { - printk("%s: scb size = 0x%x, hscb size = 0x%x\n", - ahd_name(ahd), (u_int)sizeof(struct scb), - (u_int)sizeof(struct hardware_scb)); - } -#endif - return (ahd); -} - -int -ahd_softc_init(struct ahd_softc *ahd) -{ - - ahd->unpause = 0; - ahd->pause = PAUSE; - return (0); -} - -void -ahd_set_unit(struct ahd_softc *ahd, int unit) -{ - ahd->unit = unit; -} - -void -ahd_set_name(struct ahd_softc *ahd, char *name) -{ - if (ahd->name != NULL) - kfree(ahd->name); - ahd->name = name; -} - -void -ahd_free(struct ahd_softc *ahd) -{ - int i; - - switch (ahd->init_level) { - default: - case 5: - ahd_shutdown(ahd); - /* FALLTHROUGH */ - case 4: - ahd_dmamap_unload(ahd, ahd->shared_data_dmat, - ahd->shared_data_map.dmamap); - /* FALLTHROUGH */ - case 3: - ahd_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo, - ahd->shared_data_map.dmamap); - ahd_dmamap_destroy(ahd, ahd->shared_data_dmat, - ahd->shared_data_map.dmamap); - /* FALLTHROUGH */ - case 2: - ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat); - case 1: -#ifndef __linux__ - ahd_dma_tag_destroy(ahd, ahd->buffer_dmat); -#endif - break; - case 0: - break; - } - -#ifndef __linux__ - ahd_dma_tag_destroy(ahd, ahd->parent_dmat); -#endif - ahd_platform_free(ahd); - ahd_fini_scbdata(ahd); - for (i = 0; i < AHD_NUM_TARGETS; i++) { - struct ahd_tmode_tstate *tstate; - - tstate = ahd->enabled_targets[i]; - if (tstate != NULL) { -#ifdef AHD_TARGET_MODE - int j; - - for (j = 0; j < AHD_NUM_LUNS; j++) { - struct ahd_tmode_lstate *lstate; - - lstate = tstate->enabled_luns[j]; - if (lstate != NULL) { - xpt_free_path(lstate->path); - kfree(lstate); - } - } -#endif - kfree(tstate); - } - } -#ifdef AHD_TARGET_MODE - if (ahd->black_hole != NULL) { - xpt_free_path(ahd->black_hole->path); - kfree(ahd->black_hole); - } -#endif - if (ahd->name != NULL) - kfree(ahd->name); - if (ahd->seep_config != NULL) - kfree(ahd->seep_config); - if (ahd->saved_stack != NULL) - kfree(ahd->saved_stack); -#ifndef __FreeBSD__ - kfree(ahd); -#endif - return; -} - -static void -ahd_shutdown(void *arg) -{ - struct ahd_softc *ahd; - - ahd = (struct ahd_softc *)arg; - - /* - * Stop periodic timer callbacks. - */ - ahd_timer_stop(&ahd->reset_timer); - ahd_timer_stop(&ahd->stat_timer); - - /* This will reset most registers to 0, but not all */ - ahd_reset(ahd, /*reinit*/FALSE); -} - -/* - * Reset the controller and record some information about it - * that is only available just after a reset. If "reinit" is - * non-zero, this reset occurred after initial configuration - * and the caller requests that the chip be fully reinitialized - * to a runable state. Chip interrupts are *not* enabled after - * a reinitialization. The caller must enable interrupts via - * ahd_intr_enable(). - */ -int -ahd_reset(struct ahd_softc *ahd, int reinit) -{ - u_int sxfrctl1; - int wait; - uint32_t cmd; - - /* - * Preserve the value of the SXFRCTL1 register for all channels. - * It contains settings that affect termination and we don't want - * to disturb the integrity of the bus. - */ - ahd_pause(ahd); - ahd_update_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - sxfrctl1 = ahd_inb(ahd, SXFRCTL1); - - cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); - if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) { - uint32_t mod_cmd; - - /* - * A4 Razor #632 - * During the assertion of CHIPRST, the chip - * does not disable its parity logic prior to - * the start of the reset. This may cause a - * parity error to be detected and thus a - * spurious SERR or PERR assertion. Disble - * PERR and SERR responses during the CHIPRST. - */ - mod_cmd = cmd & ~(PCIM_CMD_PERRESPEN|PCIM_CMD_SERRESPEN); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, - mod_cmd, /*bytes*/2); - } - ahd_outb(ahd, HCNTRL, CHIPRST | ahd->pause); - - /* - * Ensure that the reset has finished. We delay 1000us - * prior to reading the register to make sure the chip - * has sufficiently completed its reset to handle register - * accesses. - */ - wait = 1000; - do { - ahd_delay(1000); - } while (--wait && !(ahd_inb(ahd, HCNTRL) & CHIPRSTACK)); - - if (wait == 0) { - printk("%s: WARNING - Failed chip reset! " - "Trying to initialize anyway.\n", ahd_name(ahd)); - } - ahd_outb(ahd, HCNTRL, ahd->pause); - - if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) { - /* - * Clear any latched PCI error status and restore - * previous SERR and PERR response enables. - */ - ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, - 0xFF, /*bytes*/1); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, - cmd, /*bytes*/2); - } - - /* - * Mode should be SCSI after a chip reset, but lets - * set it just to be safe. We touch the MODE_PTR - * register directly so as to bypass the lazy update - * code in ahd_set_modes(). - */ - ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_outb(ahd, MODE_PTR, - ahd_build_mode_state(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI)); - - /* - * Restore SXFRCTL1. - * - * We must always initialize STPWEN to 1 before we - * restore the saved values. STPWEN is initialized - * to a tri-state condition which can only be cleared - * by turning it on. - */ - ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN); - ahd_outb(ahd, SXFRCTL1, sxfrctl1); - - /* Determine chip configuration */ - ahd->features &= ~AHD_WIDE; - if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0) - ahd->features |= AHD_WIDE; - - /* - * If a recovery action has forced a chip reset, - * re-initialize the chip to our liking. - */ - if (reinit != 0) - ahd_chip_init(ahd); - - return (0); -} - -/* - * Determine the number of SCBs available on the controller - */ -static int -ahd_probe_scbs(struct ahd_softc *ahd) { - int i; - - AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK), - ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK)); - for (i = 0; i < AHD_SCB_MAX; i++) { - int j; - - ahd_set_scbptr(ahd, i); - ahd_outw(ahd, SCB_BASE, i); - for (j = 2; j < 64; j++) - ahd_outb(ahd, SCB_BASE+j, 0); - /* Start out life as unallocated (needing an abort) */ - ahd_outb(ahd, SCB_CONTROL, MK_MESSAGE); - if (ahd_inw_scbram(ahd, SCB_BASE) != i) - break; - ahd_set_scbptr(ahd, 0); - if (ahd_inw_scbram(ahd, SCB_BASE) != 0) - break; - } - return (i); -} - -static void -ahd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - dma_addr_t *baddr; - - baddr = (dma_addr_t *)arg; - *baddr = segs->ds_addr; -} - -static void -ahd_initialize_hscbs(struct ahd_softc *ahd) -{ - int i; - - for (i = 0; i < ahd->scb_data.maxhscbs; i++) { - ahd_set_scbptr(ahd, i); - - /* Clear the control byte. */ - ahd_outb(ahd, SCB_CONTROL, 0); - - /* Set the next pointer */ - ahd_outw(ahd, SCB_NEXT, SCB_LIST_NULL); - } -} - -static int -ahd_init_scbdata(struct ahd_softc *ahd) -{ - struct scb_data *scb_data; - int i; - - scb_data = &ahd->scb_data; - TAILQ_INIT(&scb_data->free_scbs); - for (i = 0; i < AHD_NUM_TARGETS * AHD_NUM_LUNS_NONPKT; i++) - LIST_INIT(&scb_data->free_scb_lists[i]); - LIST_INIT(&scb_data->any_dev_free_scb_list); - SLIST_INIT(&scb_data->hscb_maps); - SLIST_INIT(&scb_data->sg_maps); - SLIST_INIT(&scb_data->sense_maps); - - /* Determine the number of hardware SCBs and initialize them */ - scb_data->maxhscbs = ahd_probe_scbs(ahd); - if (scb_data->maxhscbs == 0) { - printk("%s: No SCB space found\n", ahd_name(ahd)); - return (ENXIO); - } - - ahd_initialize_hscbs(ahd); - - /* - * Create our DMA tags. These tags define the kinds of device - * accessible memory allocations and memory mappings we will - * need to perform during normal operation. - * - * Unless we need to further restrict the allocation, we rely - * on the restrictions of the parent dmat, hence the common - * use of MAXADDR and MAXSIZE. - */ - - /* DMA tag for our hardware scb structures */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - PAGE_SIZE, /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->hscb_dmat) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* DMA tag for our S/G structures. */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - ahd_sglist_allocsize(ahd), /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->sg_dmat) != 0) { - goto error_exit; - } -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MEMORY) != 0) - printk("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd), - ahd_sglist_allocsize(ahd)); -#endif - - scb_data->init_level++; - - /* DMA tag for our sense buffers. We allocate in page sized chunks */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - PAGE_SIZE, /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->sense_dmat) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* Perform initial CCB allocation */ - ahd_alloc_scbs(ahd); - - if (scb_data->numscbs == 0) { - printk("%s: ahd_init_scbdata - " - "Unable to allocate initial scbs\n", - ahd_name(ahd)); - goto error_exit; - } - - /* - * Note that we were successful - */ - return (0); - -error_exit: - - return (ENOMEM); -} - -static struct scb * -ahd_find_scb_by_tag(struct ahd_softc *ahd, u_int tag) -{ - struct scb *scb; - - /* - * Look on the pending list. - */ - LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { - if (SCB_GET_TAG(scb) == tag) - return (scb); - } - - /* - * Then on all of the collision free lists. - */ - TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { - struct scb *list_scb; - - list_scb = scb; - do { - if (SCB_GET_TAG(list_scb) == tag) - return (list_scb); - list_scb = LIST_NEXT(list_scb, collision_links); - } while (list_scb); - } - - /* - * And finally on the generic free list. - */ - LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) { - if (SCB_GET_TAG(scb) == tag) - return (scb); - } - - return (NULL); -} - -static void -ahd_fini_scbdata(struct ahd_softc *ahd) -{ - struct scb_data *scb_data; - - scb_data = &ahd->scb_data; - if (scb_data == NULL) - return; - - switch (scb_data->init_level) { - default: - case 7: - { - struct map_node *sns_map; - - while ((sns_map = SLIST_FIRST(&scb_data->sense_maps)) != NULL) { - SLIST_REMOVE_HEAD(&scb_data->sense_maps, links); - ahd_dmamap_unload(ahd, scb_data->sense_dmat, - sns_map->dmamap); - ahd_dmamem_free(ahd, scb_data->sense_dmat, - sns_map->vaddr, sns_map->dmamap); - kfree(sns_map); - } - ahd_dma_tag_destroy(ahd, scb_data->sense_dmat); - /* FALLTHROUGH */ - } - case 6: - { - struct map_node *sg_map; - - while ((sg_map = SLIST_FIRST(&scb_data->sg_maps)) != NULL) { - SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); - ahd_dmamap_unload(ahd, scb_data->sg_dmat, - sg_map->dmamap); - ahd_dmamem_free(ahd, scb_data->sg_dmat, - sg_map->vaddr, sg_map->dmamap); - kfree(sg_map); - } - ahd_dma_tag_destroy(ahd, scb_data->sg_dmat); - /* FALLTHROUGH */ - } - case 5: - { - struct map_node *hscb_map; - - while ((hscb_map = SLIST_FIRST(&scb_data->hscb_maps)) != NULL) { - SLIST_REMOVE_HEAD(&scb_data->hscb_maps, links); - ahd_dmamap_unload(ahd, scb_data->hscb_dmat, - hscb_map->dmamap); - ahd_dmamem_free(ahd, scb_data->hscb_dmat, - hscb_map->vaddr, hscb_map->dmamap); - kfree(hscb_map); - } - ahd_dma_tag_destroy(ahd, scb_data->hscb_dmat); - /* FALLTHROUGH */ - } - case 4: - case 3: - case 2: - case 1: - case 0: - break; - } -} - -/* - * DSP filter Bypass must be enabled until the first selection - * after a change in bus mode (Razor #491 and #493). - */ -static void -ahd_setup_iocell_workaround(struct ahd_softc *ahd) -{ - ahd_mode_state saved_modes; - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - ahd_outb(ahd, DSPDATACTL, ahd_inb(ahd, DSPDATACTL) - | BYPASSENAB | RCVROFFSTDIS | XMITOFFSTDIS); - ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI)); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) - printk("%s: Setting up iocell workaround\n", ahd_name(ahd)); -#endif - ahd_restore_modes(ahd, saved_modes); - ahd->flags &= ~AHD_HAD_FIRST_SEL; -} - -static void -ahd_iocell_first_selection(struct ahd_softc *ahd) -{ - ahd_mode_state saved_modes; - u_int sblkctl; - - if ((ahd->flags & AHD_HAD_FIRST_SEL) != 0) - return; - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - sblkctl = ahd_inb(ahd, SBLKCTL); - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) - printk("%s: iocell first selection\n", ahd_name(ahd)); -#endif - if ((sblkctl & ENAB40) != 0) { - ahd_outb(ahd, DSPDATACTL, - ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) - printk("%s: BYPASS now disabled\n", ahd_name(ahd)); -#endif - } - ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI)); - ahd_outb(ahd, CLRINT, CLRSCSIINT); - ahd_restore_modes(ahd, saved_modes); - ahd->flags |= AHD_HAD_FIRST_SEL; -} - -/*************************** SCB Management ***********************************/ -static void -ahd_add_col_list(struct ahd_softc *ahd, struct scb *scb, u_int col_idx) -{ - struct scb_list *free_list; - struct scb_tailq *free_tailq; - struct scb *first_scb; - - scb->flags |= SCB_ON_COL_LIST; - AHD_SET_SCB_COL_IDX(scb, col_idx); - free_list = &ahd->scb_data.free_scb_lists[col_idx]; - free_tailq = &ahd->scb_data.free_scbs; - first_scb = LIST_FIRST(free_list); - if (first_scb != NULL) { - LIST_INSERT_AFTER(first_scb, scb, collision_links); - } else { - LIST_INSERT_HEAD(free_list, scb, collision_links); - TAILQ_INSERT_TAIL(free_tailq, scb, links.tqe); - } -} - -static void -ahd_rem_col_list(struct ahd_softc *ahd, struct scb *scb) -{ - struct scb_list *free_list; - struct scb_tailq *free_tailq; - struct scb *first_scb; - u_int col_idx; - - scb->flags &= ~SCB_ON_COL_LIST; - col_idx = AHD_GET_SCB_COL_IDX(ahd, scb); - free_list = &ahd->scb_data.free_scb_lists[col_idx]; - free_tailq = &ahd->scb_data.free_scbs; - first_scb = LIST_FIRST(free_list); - if (first_scb == scb) { - struct scb *next_scb; - - /* - * Maintain order in the collision free - * lists for fairness if this device has - * other colliding tags active. - */ - next_scb = LIST_NEXT(scb, collision_links); - if (next_scb != NULL) { - TAILQ_INSERT_AFTER(free_tailq, scb, - next_scb, links.tqe); - } - TAILQ_REMOVE(free_tailq, scb, links.tqe); - } - LIST_REMOVE(scb, collision_links); -} - -/* - * Get a free scb. If there are none, see if we can allocate a new SCB. - */ -struct scb * -ahd_get_scb(struct ahd_softc *ahd, u_int col_idx) -{ - struct scb *scb; - int tries; - - tries = 0; -look_again: - TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { - if (AHD_GET_SCB_COL_IDX(ahd, scb) != col_idx) { - ahd_rem_col_list(ahd, scb); - goto found; - } - } - if ((scb = LIST_FIRST(&ahd->scb_data.any_dev_free_scb_list)) == NULL) { - - if (tries++ != 0) - return (NULL); - ahd_alloc_scbs(ahd); - goto look_again; - } - LIST_REMOVE(scb, links.le); - if (col_idx != AHD_NEVER_COL_IDX - && (scb->col_scb != NULL) - && (scb->col_scb->flags & SCB_ACTIVE) == 0) { - LIST_REMOVE(scb->col_scb, links.le); - ahd_add_col_list(ahd, scb->col_scb, col_idx); - } -found: - scb->flags |= SCB_ACTIVE; - return (scb); -} - -/* - * Return an SCB resource to the free list. - */ -void -ahd_free_scb(struct ahd_softc *ahd, struct scb *scb) -{ - /* Clean up for the next user */ - scb->flags = SCB_FLAG_NONE; - scb->hscb->control = 0; - ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL; - - if (scb->col_scb == NULL) { - - /* - * No collision possible. Just free normally. - */ - LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, - scb, links.le); - } else if ((scb->col_scb->flags & SCB_ON_COL_LIST) != 0) { - - /* - * The SCB we might have collided with is on - * a free collision list. Put both SCBs on - * the generic list. - */ - ahd_rem_col_list(ahd, scb->col_scb); - LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, - scb, links.le); - LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, - scb->col_scb, links.le); - } else if ((scb->col_scb->flags - & (SCB_PACKETIZED|SCB_ACTIVE)) == SCB_ACTIVE - && (scb->col_scb->hscb->control & TAG_ENB) != 0) { - - /* - * The SCB we might collide with on the next allocation - * is still active in a non-packetized, tagged, context. - * Put us on the SCB collision list. - */ - ahd_add_col_list(ahd, scb, - AHD_GET_SCB_COL_IDX(ahd, scb->col_scb)); - } else { - /* - * The SCB we might collide with on the next allocation - * is either active in a packetized context, or free. - * Since we can't collide, put this SCB on the generic - * free list. - */ - LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list, - scb, links.le); - } - - ahd_platform_scb_free(ahd, scb); -} - -static void -ahd_alloc_scbs(struct ahd_softc *ahd) -{ - struct scb_data *scb_data; - struct scb *next_scb; - struct hardware_scb *hscb; - struct map_node *hscb_map; - struct map_node *sg_map; - struct map_node *sense_map; - uint8_t *segs; - uint8_t *sense_data; - dma_addr_t hscb_busaddr; - dma_addr_t sg_busaddr; - dma_addr_t sense_busaddr; - int newcount; - int i; - - scb_data = &ahd->scb_data; - if (scb_data->numscbs >= AHD_SCB_MAX_ALLOC) - /* Can't allocate any more */ - return; - - if (scb_data->scbs_left != 0) { - int offset; - - offset = (PAGE_SIZE / sizeof(*hscb)) - scb_data->scbs_left; - hscb_map = SLIST_FIRST(&scb_data->hscb_maps); - hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset]; - hscb_busaddr = hscb_map->physaddr + (offset * sizeof(*hscb)); - } else { - hscb_map = kmalloc(sizeof(*hscb_map), GFP_ATOMIC); - - if (hscb_map == NULL) - return; - - /* Allocate the next batch of hardware SCBs */ - if (ahd_dmamem_alloc(ahd, scb_data->hscb_dmat, - (void **)&hscb_map->vaddr, - BUS_DMA_NOWAIT, &hscb_map->dmamap) != 0) { - kfree(hscb_map); - return; - } - - SLIST_INSERT_HEAD(&scb_data->hscb_maps, hscb_map, links); - - ahd_dmamap_load(ahd, scb_data->hscb_dmat, hscb_map->dmamap, - hscb_map->vaddr, PAGE_SIZE, ahd_dmamap_cb, - &hscb_map->physaddr, /*flags*/0); - - hscb = (struct hardware_scb *)hscb_map->vaddr; - hscb_busaddr = hscb_map->physaddr; - scb_data->scbs_left = PAGE_SIZE / sizeof(*hscb); - } - - if (scb_data->sgs_left != 0) { - int offset; - - offset = ((ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd)) - - scb_data->sgs_left) * ahd_sglist_size(ahd); - sg_map = SLIST_FIRST(&scb_data->sg_maps); - segs = sg_map->vaddr + offset; - sg_busaddr = sg_map->physaddr + offset; - } else { - sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC); - - if (sg_map == NULL) - return; - - /* Allocate the next batch of S/G lists */ - if (ahd_dmamem_alloc(ahd, scb_data->sg_dmat, - (void **)&sg_map->vaddr, - BUS_DMA_NOWAIT, &sg_map->dmamap) != 0) { - kfree(sg_map); - return; - } - - SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); - - ahd_dmamap_load(ahd, scb_data->sg_dmat, sg_map->dmamap, - sg_map->vaddr, ahd_sglist_allocsize(ahd), - ahd_dmamap_cb, &sg_map->physaddr, /*flags*/0); - - segs = sg_map->vaddr; - sg_busaddr = sg_map->physaddr; - scb_data->sgs_left = - ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_MEMORY) - printk("Mapped SG data\n"); -#endif - } - - if (scb_data->sense_left != 0) { - int offset; - - offset = PAGE_SIZE - (AHD_SENSE_BUFSIZE * scb_data->sense_left); - sense_map = SLIST_FIRST(&scb_data->sense_maps); - sense_data = sense_map->vaddr + offset; - sense_busaddr = sense_map->physaddr + offset; - } else { - sense_map = kmalloc(sizeof(*sense_map), GFP_ATOMIC); - - if (sense_map == NULL) - return; - - /* Allocate the next batch of sense buffers */ - if (ahd_dmamem_alloc(ahd, scb_data->sense_dmat, - (void **)&sense_map->vaddr, - BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) { - kfree(sense_map); - return; - } - - SLIST_INSERT_HEAD(&scb_data->sense_maps, sense_map, links); - - ahd_dmamap_load(ahd, scb_data->sense_dmat, sense_map->dmamap, - sense_map->vaddr, PAGE_SIZE, ahd_dmamap_cb, - &sense_map->physaddr, /*flags*/0); - - sense_data = sense_map->vaddr; - sense_busaddr = sense_map->physaddr; - scb_data->sense_left = PAGE_SIZE / AHD_SENSE_BUFSIZE; -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_MEMORY) - printk("Mapped sense data\n"); -#endif - } - - newcount = min(scb_data->sense_left, scb_data->scbs_left); - newcount = min(newcount, scb_data->sgs_left); - newcount = min(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs)); - for (i = 0; i < newcount; i++) { - struct scb_platform_data *pdata; - u_int col_tag; -#ifndef __linux__ - int error; -#endif - - next_scb = kmalloc(sizeof(*next_scb), GFP_ATOMIC); - if (next_scb == NULL) - break; - - pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC); - if (pdata == NULL) { - kfree(next_scb); - break; - } - next_scb->platform_data = pdata; - next_scb->hscb_map = hscb_map; - next_scb->sg_map = sg_map; - next_scb->sense_map = sense_map; - next_scb->sg_list = segs; - next_scb->sense_data = sense_data; - next_scb->sense_busaddr = sense_busaddr; - memset(hscb, 0, sizeof(*hscb)); - next_scb->hscb = hscb; - hscb->hscb_busaddr = ahd_htole32(hscb_busaddr); - - /* - * The sequencer always starts with the second entry. - * The first entry is embedded in the scb. - */ - next_scb->sg_list_busaddr = sg_busaddr; - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) - next_scb->sg_list_busaddr - += sizeof(struct ahd_dma64_seg); - else - next_scb->sg_list_busaddr += sizeof(struct ahd_dma_seg); - next_scb->ahd_softc = ahd; - next_scb->flags = SCB_FLAG_NONE; -#ifndef __linux__ - error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0, - &next_scb->dmamap); - if (error != 0) { - kfree(next_scb); - kfree(pdata); - break; - } -#endif - next_scb->hscb->tag = ahd_htole16(scb_data->numscbs); - col_tag = scb_data->numscbs ^ 0x100; - next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag); - if (next_scb->col_scb != NULL) - next_scb->col_scb->col_scb = next_scb; - ahd_free_scb(ahd, next_scb); - hscb++; - hscb_busaddr += sizeof(*hscb); - segs += ahd_sglist_size(ahd); - sg_busaddr += ahd_sglist_size(ahd); - sense_data += AHD_SENSE_BUFSIZE; - sense_busaddr += AHD_SENSE_BUFSIZE; - scb_data->numscbs++; - scb_data->sense_left--; - scb_data->scbs_left--; - scb_data->sgs_left--; - } -} - -void -ahd_controller_info(struct ahd_softc *ahd, char *buf) -{ - const char *speed; - const char *type; - int len; - - len = sprintf(buf, "%s: ", ahd_chip_names[ahd->chip & AHD_CHIPID_MASK]); - buf += len; - - speed = "Ultra320 "; - if ((ahd->features & AHD_WIDE) != 0) { - type = "Wide "; - } else { - type = "Single "; - } - len = sprintf(buf, "%s%sChannel %c, SCSI Id=%d, ", - speed, type, ahd->channel, ahd->our_id); - buf += len; - - sprintf(buf, "%s, %d SCBs", ahd->bus_description, - ahd->scb_data.maxhscbs); -} - -static const char *channel_strings[] = { - "Primary Low", - "Primary High", - "Secondary Low", - "Secondary High" -}; - -static const char *termstat_strings[] = { - "Terminated Correctly", - "Over Terminated", - "Under Terminated", - "Not Configured" -}; - -/***************************** Timer Facilities *******************************/ -#define ahd_timer_init init_timer -#define ahd_timer_stop del_timer_sync -typedef void ahd_linux_callback_t (u_long); - -static void -ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg) -{ - struct ahd_softc *ahd; - - ahd = (struct ahd_softc *)arg; - del_timer(timer); - timer->data = (u_long)arg; - timer->expires = jiffies + (usec * HZ)/1000000; - timer->function = (ahd_linux_callback_t*)func; - add_timer(timer); -} - -/* - * Start the board, ready for normal operation - */ -int -ahd_init(struct ahd_softc *ahd) -{ - uint8_t *next_vaddr; - dma_addr_t next_baddr; - size_t driver_data_size; - int i; - int error; - u_int warn_user; - uint8_t current_sensing; - uint8_t fstat; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - - ahd->stack_size = ahd_probe_stack_size(ahd); - ahd->saved_stack = kmalloc(ahd->stack_size * sizeof(uint16_t), GFP_ATOMIC); - if (ahd->saved_stack == NULL) - return (ENOMEM); - - /* - * Verify that the compiler hasn't over-aggressively - * padded important structures. - */ - if (sizeof(struct hardware_scb) != 64) - panic("Hardware SCB size is incorrect"); - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_DEBUG_SEQUENCER) != 0) - ahd->flags |= AHD_SEQUENCER_DEBUG; -#endif - - /* - * Default to allowing initiator operations. - */ - ahd->flags |= AHD_INITIATORROLE; - - /* - * Only allow target mode features if this unit has them enabled. - */ - if ((AHD_TMODE_ENABLE & (0x1 << ahd->unit)) == 0) - ahd->features &= ~AHD_TARGETMODE; - -#ifndef __linux__ - /* DMA tag for mapping buffers into device visible space. */ - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING - ? (dma_addr_t)0x7FFFFFFFFFULL - : BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE, - /*nsegments*/AHD_NSEG, - /*maxsegsz*/AHD_MAXTRANSFER_SIZE, - /*flags*/BUS_DMA_ALLOCNOW, - &ahd->buffer_dmat) != 0) { - return (ENOMEM); - } -#endif - - ahd->init_level++; - - /* - * DMA tag for our command fifos and other data in system memory - * the card's sequencer must be able to access. For initiator - * roles, we need to allocate space for the qoutfifo. When providing - * for the target mode role, we must additionally provide space for - * the incoming target command fifo. - */ - driver_data_size = AHD_SCB_MAX * sizeof(*ahd->qoutfifo) - + sizeof(struct hardware_scb); - if ((ahd->features & AHD_TARGETMODE) != 0) - driver_data_size += AHD_TMODE_CMDS * sizeof(struct target_cmd); - if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) - driver_data_size += PKT_OVERRUN_BUFSIZE; - if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - driver_data_size, - /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &ahd->shared_data_dmat) != 0) { - return (ENOMEM); - } - - ahd->init_level++; - - /* Allocation of driver data */ - if (ahd_dmamem_alloc(ahd, ahd->shared_data_dmat, - (void **)&ahd->shared_data_map.vaddr, - BUS_DMA_NOWAIT, - &ahd->shared_data_map.dmamap) != 0) { - return (ENOMEM); - } - - ahd->init_level++; - - /* And permanently map it in */ - ahd_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_map.dmamap, - ahd->shared_data_map.vaddr, driver_data_size, - ahd_dmamap_cb, &ahd->shared_data_map.physaddr, - /*flags*/0); - ahd->qoutfifo = (struct ahd_completion *)ahd->shared_data_map.vaddr; - next_vaddr = (uint8_t *)&ahd->qoutfifo[AHD_QOUT_SIZE]; - next_baddr = ahd->shared_data_map.physaddr - + AHD_QOUT_SIZE*sizeof(struct ahd_completion); - if ((ahd->features & AHD_TARGETMODE) != 0) { - ahd->targetcmds = (struct target_cmd *)next_vaddr; - next_vaddr += AHD_TMODE_CMDS * sizeof(struct target_cmd); - next_baddr += AHD_TMODE_CMDS * sizeof(struct target_cmd); - } - - if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) { - ahd->overrun_buf = next_vaddr; - next_vaddr += PKT_OVERRUN_BUFSIZE; - next_baddr += PKT_OVERRUN_BUFSIZE; - } - - /* - * We need one SCB to serve as the "next SCB". Since the - * tag identifier in this SCB will never be used, there is - * no point in using a valid HSCB tag from an SCB pulled from - * the standard free pool. So, we allocate this "sentinel" - * specially from the DMA safe memory chunk used for the QOUTFIFO. - */ - ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr; - ahd->next_queued_hscb_map = &ahd->shared_data_map; - ahd->next_queued_hscb->hscb_busaddr = ahd_htole32(next_baddr); - - ahd->init_level++; - - /* Allocate SCB data now that buffer_dmat is initialized */ - if (ahd_init_scbdata(ahd) != 0) - return (ENOMEM); - - if ((ahd->flags & AHD_INITIATORROLE) == 0) - ahd->flags &= ~AHD_RESET_BUS_A; - - /* - * Before committing these settings to the chip, give - * the OSM one last chance to modify our configuration. - */ - ahd_platform_init(ahd); - - /* Bring up the chip. */ - ahd_chip_init(ahd); - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - - if ((ahd->flags & AHD_CURRENT_SENSING) == 0) - goto init_done; - - /* - * Verify termination based on current draw and - * warn user if the bus is over/under terminated. - */ - error = ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, - CURSENSE_ENB); - if (error != 0) { - printk("%s: current sensing timeout 1\n", ahd_name(ahd)); - goto init_done; - } - for (i = 20, fstat = FLX_FSTAT_BUSY; - (fstat & FLX_FSTAT_BUSY) != 0 && i; i--) { - error = ahd_read_flexport(ahd, FLXADDR_FLEXSTAT, &fstat); - if (error != 0) { - printk("%s: current sensing timeout 2\n", - ahd_name(ahd)); - goto init_done; - } - } - if (i == 0) { - printk("%s: Timedout during current-sensing test\n", - ahd_name(ahd)); - goto init_done; - } - - /* Latch Current Sensing status. */ - error = ahd_read_flexport(ahd, FLXADDR_CURRENT_STAT, ¤t_sensing); - if (error != 0) { - printk("%s: current sensing timeout 3\n", ahd_name(ahd)); - goto init_done; - } - - /* Diable current sensing. */ - ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0); - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_TERMCTL) != 0) { - printk("%s: current_sensing == 0x%x\n", - ahd_name(ahd), current_sensing); - } -#endif - warn_user = 0; - for (i = 0; i < 4; i++, current_sensing >>= FLX_CSTAT_SHIFT) { - u_int term_stat; - - term_stat = (current_sensing & FLX_CSTAT_MASK); - switch (term_stat) { - case FLX_CSTAT_OVER: - case FLX_CSTAT_UNDER: - warn_user++; - case FLX_CSTAT_INVALID: - case FLX_CSTAT_OKAY: - if (warn_user == 0 && bootverbose == 0) - break; - printk("%s: %s Channel %s\n", ahd_name(ahd), - channel_strings[i], termstat_strings[term_stat]); - break; - } - } - if (warn_user) { - printk("%s: WARNING. Termination is not configured correctly.\n" - "%s: WARNING. SCSI bus operations may FAIL.\n", - ahd_name(ahd), ahd_name(ahd)); - } -init_done: - ahd_restart(ahd); - ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, - ahd_stat_timer, ahd); - return (0); -} - -/* - * (Re)initialize chip state after a chip reset. - */ -static void -ahd_chip_init(struct ahd_softc *ahd) -{ - uint32_t busaddr; - u_int sxfrctl1; - u_int scsiseq_template; - u_int wait; - u_int i; - u_int target; - - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - /* - * Take the LED out of diagnostic mode - */ - ahd_outb(ahd, SBLKCTL, ahd_inb(ahd, SBLKCTL) & ~(DIAGLEDEN|DIAGLEDON)); - - /* - * Return HS_MAILBOX to its default value. - */ - ahd->hs_mailbox = 0; - ahd_outb(ahd, HS_MAILBOX, 0); - - /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1. */ - ahd_outb(ahd, IOWNID, ahd->our_id); - ahd_outb(ahd, TOWNID, ahd->our_id); - sxfrctl1 = (ahd->flags & AHD_TERM_ENB_A) != 0 ? STPWEN : 0; - sxfrctl1 |= (ahd->flags & AHD_SPCHK_ENB_A) != 0 ? ENSPCHK : 0; - if ((ahd->bugs & AHD_LONG_SETIMO_BUG) - && (ahd->seltime != STIMESEL_MIN)) { - /* - * The selection timer duration is twice as long - * as it should be. Halve it by adding "1" to - * the user specified setting. - */ - sxfrctl1 |= ahd->seltime + STIMESEL_BUG_ADJ; - } else { - sxfrctl1 |= ahd->seltime; - } - - ahd_outb(ahd, SXFRCTL0, DFON); - ahd_outb(ahd, SXFRCTL1, sxfrctl1|ahd->seltime|ENSTIMER|ACTNEGEN); - ahd_outb(ahd, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - - /* - * Now that termination is set, wait for up - * to 500ms for our transceivers to settle. If - * the adapter does not have a cable attached, - * the transceivers may never settle, so don't - * complain if we fail here. - */ - for (wait = 10000; - (ahd_inb(ahd, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; - wait--) - ahd_delay(100); - - /* Clear any false bus resets due to the transceivers settling */ - ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); - ahd_outb(ahd, CLRINT, CLRSCSIINT); - - /* Initialize mode specific S/G state. */ - for (i = 0; i < 2; i++) { - ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i); - ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR); - ahd_outb(ahd, SG_STATE, 0); - ahd_outb(ahd, CLRSEQINTSRC, 0xFF); - ahd_outb(ahd, SEQIMODE, - ENSAVEPTRS|ENCFG4DATA|ENCFG4ISTAT - |ENCFG4TSTAT|ENCFG4ICMD|ENCFG4TCMD); - } - - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - ahd_outb(ahd, DSCOMMAND0, ahd_inb(ahd, DSCOMMAND0)|MPARCKEN|CACHETHEN); - ahd_outb(ahd, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75); - ahd_outb(ahd, SIMODE0, ENIOERR|ENOVERRUN); - ahd_outb(ahd, SIMODE3, ENNTRAMPERR|ENOSRAMPERR); - if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) { - ahd_outb(ahd, OPTIONMODE, AUTOACKEN|AUTO_MSGOUT_DE); - } else { - ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE); - } - ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN|SHVALIDSTDIS); - if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX) - /* - * Do not issue a target abort when a split completion - * error occurs. Let our PCIX interrupt handler deal - * with it instead. H2A4 Razor #625 - */ - ahd_outb(ahd, PCIXCTL, ahd_inb(ahd, PCIXCTL) | SPLTSTADIS); - - if ((ahd->bugs & AHD_LQOOVERRUN_BUG) != 0) - ahd_outb(ahd, LQOSCSCTL, LQONOCHKOVER); - - /* - * Tweak IOCELL settings. - */ - if ((ahd->flags & AHD_HP_BOARD) != 0) { - for (i = 0; i < NUMDSPS; i++) { - ahd_outb(ahd, DSPSELECT, i); - ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_HP_DEFAULT); - } -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) - printk("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd), - WRTBIASCTL_HP_DEFAULT); -#endif - } - ahd_setup_iocell_workaround(ahd); - - /* - * Enable LQI Manager interrupts. - */ - ahd_outb(ahd, LQIMODE1, ENLQIPHASE_LQ|ENLQIPHASE_NLQ|ENLIQABORT - | ENLQICRCI_LQ|ENLQICRCI_NLQ|ENLQIBADLQI - | ENLQIOVERI_LQ|ENLQIOVERI_NLQ); - ahd_outb(ahd, LQOMODE0, ENLQOATNLQ|ENLQOATNPKT|ENLQOTCRC); - /* - * We choose to have the sequencer catch LQOPHCHGINPKT errors - * manually for the command phase at the start of a packetized - * selection case. ENLQOBUSFREE should be made redundant by - * the BUSFREE interrupt, but it seems that some LQOBUSFREE - * events fail to assert the BUSFREE interrupt so we must - * also enable LQOBUSFREE interrupts. - */ - ahd_outb(ahd, LQOMODE1, ENLQOBUSFREE); - - /* - * Setup sequencer interrupt handlers. - */ - ahd_outw(ahd, INTVEC1_ADDR, ahd_resolve_seqaddr(ahd, LABEL_seq_isr)); - ahd_outw(ahd, INTVEC2_ADDR, ahd_resolve_seqaddr(ahd, LABEL_timer_isr)); - - /* - * Setup SCB Offset registers. - */ - if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { - ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, - pkt_long_lun)); - } else { - ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, lun)); - } - ahd_outb(ahd, CMDLENPTR, offsetof(struct hardware_scb, cdb_len)); - ahd_outb(ahd, ATTRPTR, offsetof(struct hardware_scb, task_attribute)); - ahd_outb(ahd, FLAGPTR, offsetof(struct hardware_scb, task_management)); - ahd_outb(ahd, CMDPTR, offsetof(struct hardware_scb, - shared_data.idata.cdb)); - ahd_outb(ahd, QNEXTPTR, - offsetof(struct hardware_scb, next_hscb_busaddr)); - ahd_outb(ahd, ABRTBITPTR, MK_MESSAGE_BIT_OFFSET); - ahd_outb(ahd, ABRTBYTEPTR, offsetof(struct hardware_scb, control)); - if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { - ahd_outb(ahd, LUNLEN, - sizeof(ahd->next_queued_hscb->pkt_long_lun) - 1); - } else { - ahd_outb(ahd, LUNLEN, LUNLEN_SINGLE_LEVEL_LUN); - } - ahd_outb(ahd, CDBLIMIT, SCB_CDB_LEN_PTR - 1); - ahd_outb(ahd, MAXCMD, 0xFF); - ahd_outb(ahd, SCBAUTOPTR, - AUSCBPTR_EN | offsetof(struct hardware_scb, tag)); - - /* We haven't been enabled for target mode yet. */ - ahd_outb(ahd, MULTARGID, 0); - ahd_outb(ahd, MULTARGID + 1, 0); - - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - /* Initialize the negotiation table. */ - if ((ahd->features & AHD_NEW_IOCELL_OPTS) == 0) { - /* - * Clear the spare bytes in the neg table to avoid - * spurious parity errors. - */ - for (target = 0; target < AHD_NUM_TARGETS; target++) { - ahd_outb(ahd, NEGOADDR, target); - ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PER_DEV0); - for (i = 0; i < AHD_NUM_PER_DEV_ANNEXCOLS; i++) - ahd_outb(ahd, ANNEXDAT, 0); - } - } - for (target = 0; target < AHD_NUM_TARGETS; target++) { - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - target, &tstate); - ahd_compile_devinfo(&devinfo, ahd->our_id, - target, CAM_LUN_WILDCARD, - 'A', ROLE_INITIATOR); - ahd_update_neg_table(ahd, &devinfo, &tinfo->curr); - } - - ahd_outb(ahd, CLRSINT3, NTRAMPERR|OSRAMPERR); - ahd_outb(ahd, CLRINT, CLRSCSIINT); - -#ifdef NEEDS_MORE_TESTING - /* - * Always enable abort on incoming L_Qs if this feature is - * supported. We use this to catch invalid SCB references. - */ - if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0) - ahd_outb(ahd, LQCTL1, ABORTPENDING); - else -#endif - ahd_outb(ahd, LQCTL1, 0); - - /* All of our queues are empty */ - ahd->qoutfifonext = 0; - ahd->qoutfifonext_valid_tag = QOUTFIFO_ENTRY_VALID; - ahd_outb(ahd, QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID); - for (i = 0; i < AHD_QOUT_SIZE; i++) - ahd->qoutfifo[i].valid_tag = 0; - ahd_sync_qoutfifo(ahd, BUS_DMASYNC_PREREAD); - - ahd->qinfifonext = 0; - for (i = 0; i < AHD_QIN_SIZE; i++) - ahd->qinfifo[i] = SCB_LIST_NULL; - - if ((ahd->features & AHD_TARGETMODE) != 0) { - /* All target command blocks start out invalid. */ - for (i = 0; i < AHD_TMODE_CMDS; i++) - ahd->targetcmds[i].cmd_valid = 0; - ahd_sync_tqinfifo(ahd, BUS_DMASYNC_PREREAD); - ahd->tqinfifonext = 1; - ahd_outb(ahd, KERNEL_TQINPOS, ahd->tqinfifonext - 1); - ahd_outb(ahd, TQINPOS, ahd->tqinfifonext); - } - - /* Initialize Scratch Ram. */ - ahd_outb(ahd, SEQ_FLAGS, 0); - ahd_outb(ahd, SEQ_FLAGS2, 0); - - /* We don't have any waiting selections */ - ahd_outw(ahd, WAITING_TID_HEAD, SCB_LIST_NULL); - ahd_outw(ahd, WAITING_TID_TAIL, SCB_LIST_NULL); - ahd_outw(ahd, MK_MESSAGE_SCB, SCB_LIST_NULL); - ahd_outw(ahd, MK_MESSAGE_SCSIID, 0xFF); - for (i = 0; i < AHD_NUM_TARGETS; i++) - ahd_outw(ahd, WAITING_SCB_TAILS + (2 * i), SCB_LIST_NULL); - - /* - * Nobody is waiting to be DMAed into the QOUTFIFO. - */ - ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL); - ahd_outw(ahd, COMPLETE_SCB_DMAINPROG_HEAD, SCB_LIST_NULL); - ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL); - ahd_outw(ahd, COMPLETE_DMA_SCB_TAIL, SCB_LIST_NULL); - ahd_outw(ahd, COMPLETE_ON_QFREEZE_HEAD, SCB_LIST_NULL); - - /* - * The Freeze Count is 0. - */ - ahd->qfreeze_cnt = 0; - ahd_outw(ahd, QFREEZE_COUNT, 0); - ahd_outw(ahd, KERNEL_QFREEZE_COUNT, 0); - - /* - * Tell the sequencer where it can find our arrays in memory. - */ - busaddr = ahd->shared_data_map.physaddr; - ahd_outl(ahd, SHARED_DATA_ADDR, busaddr); - ahd_outl(ahd, QOUTFIFO_NEXT_ADDR, busaddr); - - /* - * Setup the allowed SCSI Sequences based on operational mode. - * If we are a target, we'll enable select in operations once - * we've had a lun enabled. - */ - scsiseq_template = ENAUTOATNP; - if ((ahd->flags & AHD_INITIATORROLE) != 0) - scsiseq_template |= ENRSELI; - ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq_template); - - /* There are no busy SCBs yet. */ - for (target = 0; target < AHD_NUM_TARGETS; target++) { - int lun; - - for (lun = 0; lun < AHD_NUM_LUNS_NONPKT; lun++) - ahd_unbusy_tcl(ahd, BUILD_TCL_RAW(target, 'A', lun)); - } - - /* - * Initialize the group code to command length table. - * Vendor Unique codes are set to 0 so we only capture - * the first byte of the cdb. These can be overridden - * when target mode is enabled. - */ - ahd_outb(ahd, CMDSIZE_TABLE, 5); - ahd_outb(ahd, CMDSIZE_TABLE + 1, 9); - ahd_outb(ahd, CMDSIZE_TABLE + 2, 9); - ahd_outb(ahd, CMDSIZE_TABLE + 3, 0); - ahd_outb(ahd, CMDSIZE_TABLE + 4, 15); - ahd_outb(ahd, CMDSIZE_TABLE + 5, 11); - ahd_outb(ahd, CMDSIZE_TABLE + 6, 0); - ahd_outb(ahd, CMDSIZE_TABLE + 7, 0); - - /* Tell the sequencer of our initial queue positions */ - ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); - ahd_outb(ahd, QOFF_CTLSTA, SCB_QSIZE_512); - ahd->qinfifonext = 0; - ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); - ahd_set_hescb_qoff(ahd, 0); - ahd_set_snscb_qoff(ahd, 0); - ahd_set_sescb_qoff(ahd, 0); - ahd_set_sdscb_qoff(ahd, 0); - - /* - * Tell the sequencer which SCB will be the next one it receives. - */ - busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr); - ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); - - /* - * Default to coalescing disabled. - */ - ahd_outw(ahd, INT_COALESCING_CMDCOUNT, 0); - ahd_outw(ahd, CMDS_PENDING, 0); - ahd_update_coalescing_values(ahd, ahd->int_coalescing_timer, - ahd->int_coalescing_maxcmds, - ahd->int_coalescing_mincmds); - ahd_enable_coalescing(ahd, FALSE); - - ahd_loadseq(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - - if (ahd->features & AHD_AIC79XXB_SLOWCRC) { - u_int negodat3 = ahd_inb(ahd, NEGCONOPTS); - - negodat3 |= ENSLOWCRC; - ahd_outb(ahd, NEGCONOPTS, negodat3); - negodat3 = ahd_inb(ahd, NEGCONOPTS); - if (!(negodat3 & ENSLOWCRC)) - printk("aic79xx: failed to set the SLOWCRC bit\n"); - else - printk("aic79xx: SLOWCRC bit set\n"); - } -} - -/* - * Setup default device and controller settings. - * This should only be called if our probe has - * determined that no configuration data is available. - */ -int -ahd_default_config(struct ahd_softc *ahd) -{ - int targ; - - ahd->our_id = 7; - - /* - * Allocate a tstate to house information for our - * initiator presence on the bus as well as the user - * data for any target mode initiator. - */ - if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) { - printk("%s: unable to allocate ahd_tmode_tstate. " - "Failing attach\n", ahd_name(ahd)); - return (ENOMEM); - } - - for (targ = 0; targ < AHD_NUM_TARGETS; targ++) { - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - uint16_t target_mask; - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - targ, &tstate); - /* - * We support SPC2 and SPI4. - */ - tinfo->user.protocol_version = 4; - tinfo->user.transport_version = 4; - - target_mask = 0x01 << targ; - ahd->user_discenable |= target_mask; - tstate->discenable |= target_mask; - ahd->user_tagenable |= target_mask; -#ifdef AHD_FORCE_160 - tinfo->user.period = AHD_SYNCRATE_DT; -#else - tinfo->user.period = AHD_SYNCRATE_160; -#endif - tinfo->user.offset = MAX_OFFSET; - tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM - | MSG_EXT_PPR_WR_FLOW - | MSG_EXT_PPR_HOLD_MCS - | MSG_EXT_PPR_IU_REQ - | MSG_EXT_PPR_QAS_REQ - | MSG_EXT_PPR_DT_REQ; - if ((ahd->features & AHD_RTI) != 0) - tinfo->user.ppr_options |= MSG_EXT_PPR_RTI; - - tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; - - /* - * Start out Async/Narrow/Untagged and with - * conservative protocol support. - */ - tinfo->goal.protocol_version = 2; - tinfo->goal.transport_version = 2; - tinfo->curr.protocol_version = 2; - tinfo->curr.transport_version = 2; - ahd_compile_devinfo(&devinfo, ahd->our_id, - targ, CAM_LUN_WILDCARD, - 'A', ROLE_INITIATOR); - tstate->tagenable &= ~target_mask; - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); - ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, - /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL, - /*paused*/TRUE); - } - return (0); -} - -/* - * Parse device configuration information. - */ -int -ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc) -{ - int targ; - int max_targ; - - max_targ = sc->max_targets & CFMAXTARG; - ahd->our_id = sc->brtime_id & CFSCSIID; - - /* - * Allocate a tstate to house information for our - * initiator presence on the bus as well as the user - * data for any target mode initiator. - */ - if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) { - printk("%s: unable to allocate ahd_tmode_tstate. " - "Failing attach\n", ahd_name(ahd)); - return (ENOMEM); - } - - for (targ = 0; targ < max_targ; targ++) { - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_transinfo *user_tinfo; - struct ahd_tmode_tstate *tstate; - uint16_t target_mask; - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - targ, &tstate); - user_tinfo = &tinfo->user; - - /* - * We support SPC2 and SPI4. - */ - tinfo->user.protocol_version = 4; - tinfo->user.transport_version = 4; - - target_mask = 0x01 << targ; - ahd->user_discenable &= ~target_mask; - tstate->discenable &= ~target_mask; - ahd->user_tagenable &= ~target_mask; - if (sc->device_flags[targ] & CFDISC) { - tstate->discenable |= target_mask; - ahd->user_discenable |= target_mask; - ahd->user_tagenable |= target_mask; - } else { - /* - * Cannot be packetized without disconnection. - */ - sc->device_flags[targ] &= ~CFPACKETIZED; - } - - user_tinfo->ppr_options = 0; - user_tinfo->period = (sc->device_flags[targ] & CFXFER); - if (user_tinfo->period < CFXFER_ASYNC) { - if (user_tinfo->period <= AHD_PERIOD_10MHz) - user_tinfo->ppr_options |= MSG_EXT_PPR_DT_REQ; - user_tinfo->offset = MAX_OFFSET; - } else { - user_tinfo->offset = 0; - user_tinfo->period = AHD_ASYNC_XFER_PERIOD; - } -#ifdef AHD_FORCE_160 - if (user_tinfo->period <= AHD_SYNCRATE_160) - user_tinfo->period = AHD_SYNCRATE_DT; -#endif - - if ((sc->device_flags[targ] & CFPACKETIZED) != 0) { - user_tinfo->ppr_options |= MSG_EXT_PPR_RD_STRM - | MSG_EXT_PPR_WR_FLOW - | MSG_EXT_PPR_HOLD_MCS - | MSG_EXT_PPR_IU_REQ; - if ((ahd->features & AHD_RTI) != 0) - user_tinfo->ppr_options |= MSG_EXT_PPR_RTI; - } - - if ((sc->device_flags[targ] & CFQAS) != 0) - user_tinfo->ppr_options |= MSG_EXT_PPR_QAS_REQ; - - if ((sc->device_flags[targ] & CFWIDEB) != 0) - user_tinfo->width = MSG_EXT_WDTR_BUS_16_BIT; - else - user_tinfo->width = MSG_EXT_WDTR_BUS_8_BIT; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) - printk("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width, - user_tinfo->period, user_tinfo->offset, - user_tinfo->ppr_options); -#endif - /* - * Start out Async/Narrow/Untagged and with - * conservative protocol support. - */ - tstate->tagenable &= ~target_mask; - tinfo->goal.protocol_version = 2; - tinfo->goal.transport_version = 2; - tinfo->curr.protocol_version = 2; - tinfo->curr.transport_version = 2; - ahd_compile_devinfo(&devinfo, ahd->our_id, - targ, CAM_LUN_WILDCARD, - 'A', ROLE_INITIATOR); - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); - ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, - /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL, - /*paused*/TRUE); - } - - ahd->flags &= ~AHD_SPCHK_ENB_A; - if (sc->bios_control & CFSPARITY) - ahd->flags |= AHD_SPCHK_ENB_A; - - ahd->flags &= ~AHD_RESET_BUS_A; - if (sc->bios_control & CFRESETB) - ahd->flags |= AHD_RESET_BUS_A; - - ahd->flags &= ~AHD_EXTENDED_TRANS_A; - if (sc->bios_control & CFEXTEND) - ahd->flags |= AHD_EXTENDED_TRANS_A; - - ahd->flags &= ~AHD_BIOS_ENABLED; - if ((sc->bios_control & CFBIOSSTATE) == CFBS_ENABLED) - ahd->flags |= AHD_BIOS_ENABLED; - - ahd->flags &= ~AHD_STPWLEVEL_A; - if ((sc->adapter_control & CFSTPWLEVEL) != 0) - ahd->flags |= AHD_STPWLEVEL_A; - - return (0); -} - -/* - * Parse device configuration information. - */ -int -ahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd) -{ - int error; - - error = ahd_verify_vpd_cksum(vpd); - if (error == 0) - return (EINVAL); - if ((vpd->bios_flags & VPDBOOTHOST) != 0) - ahd->flags |= AHD_BOOT_CHANNEL; - return (0); -} - -void -ahd_intr_enable(struct ahd_softc *ahd, int enable) -{ - u_int hcntrl; - - hcntrl = ahd_inb(ahd, HCNTRL); - hcntrl &= ~INTEN; - ahd->pause &= ~INTEN; - ahd->unpause &= ~INTEN; - if (enable) { - hcntrl |= INTEN; - ahd->pause |= INTEN; - ahd->unpause |= INTEN; - } - ahd_outb(ahd, HCNTRL, hcntrl); -} - -static void -ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, - u_int mincmds) -{ - if (timer > AHD_TIMER_MAX_US) - timer = AHD_TIMER_MAX_US; - ahd->int_coalescing_timer = timer; - - if (maxcmds > AHD_INT_COALESCING_MAXCMDS_MAX) - maxcmds = AHD_INT_COALESCING_MAXCMDS_MAX; - if (mincmds > AHD_INT_COALESCING_MINCMDS_MAX) - mincmds = AHD_INT_COALESCING_MINCMDS_MAX; - ahd->int_coalescing_maxcmds = maxcmds; - ahd_outw(ahd, INT_COALESCING_TIMER, timer / AHD_TIMER_US_PER_TICK); - ahd_outb(ahd, INT_COALESCING_MAXCMDS, -maxcmds); - ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds); -} - -static void -ahd_enable_coalescing(struct ahd_softc *ahd, int enable) -{ - - ahd->hs_mailbox &= ~ENINT_COALESCE; - if (enable) - ahd->hs_mailbox |= ENINT_COALESCE; - ahd_outb(ahd, HS_MAILBOX, ahd->hs_mailbox); - ahd_flush_device_writes(ahd); - ahd_run_qoutfifo(ahd); -} - -/* - * Ensure that the card is paused in a location - * outside of all critical sections and that all - * pending work is completed prior to returning. - * This routine should only be called from outside - * an interrupt context. - */ -void -ahd_pause_and_flushwork(struct ahd_softc *ahd) -{ - u_int intstat; - u_int maxloops; - - maxloops = 1000; - ahd->flags |= AHD_ALL_INTERRUPTS; - ahd_pause(ahd); - /* - * Freeze the outgoing selections. We do this only - * until we are safely paused without further selections - * pending. - */ - ahd->qfreeze_cnt--; - ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); - ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN); - do { - - ahd_unpause(ahd); - /* - * Give the sequencer some time to service - * any active selections. - */ - ahd_delay(500); - - ahd_intr(ahd); - ahd_pause(ahd); - intstat = ahd_inb(ahd, INTSTAT); - if ((intstat & INT_PEND) == 0) { - ahd_clear_critical_section(ahd); - intstat = ahd_inb(ahd, INTSTAT); - } - } while (--maxloops - && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0) - && ((intstat & INT_PEND) != 0 - || (ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0 - || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)); - - if (maxloops == 0) { - printk("Infinite interrupt loop, INTSTAT = %x", - ahd_inb(ahd, INTSTAT)); - } - ahd->qfreeze_cnt++; - ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); - - ahd_flush_qoutfifo(ahd); - - ahd->flags &= ~AHD_ALL_INTERRUPTS; -} - -#ifdef CONFIG_PM -int -ahd_suspend(struct ahd_softc *ahd) -{ - - ahd_pause_and_flushwork(ahd); - - if (LIST_FIRST(&ahd->pending_scbs) != NULL) { - ahd_unpause(ahd); - return (EBUSY); - } - ahd_shutdown(ahd); - return (0); -} - -void -ahd_resume(struct ahd_softc *ahd) -{ - - ahd_reset(ahd, /*reinit*/TRUE); - ahd_intr_enable(ahd, TRUE); - ahd_restart(ahd); -} -#endif - -/************************** Busy Target Table *********************************/ -/* - * Set SCBPTR to the SCB that contains the busy - * table entry for TCL. Return the offset into - * the SCB that contains the entry for TCL. - * saved_scbid is dereferenced and set to the - * scbid that should be restored once manipualtion - * of the TCL entry is complete. - */ -static inline u_int -ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl) -{ - /* - * Index to the SCB that contains the busy entry. - */ - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - *saved_scbid = ahd_get_scbptr(ahd); - ahd_set_scbptr(ahd, TCL_LUN(tcl) - | ((TCL_TARGET_OFFSET(tcl) & 0xC) << 4)); - - /* - * And now calculate the SCB offset to the entry. - * Each entry is 2 bytes wide, hence the - * multiplication by 2. - */ - return (((TCL_TARGET_OFFSET(tcl) & 0x3) << 1) + SCB_DISCONNECTED_LISTS); -} - -/* - * Return the untagged transaction id for a given target/channel lun. - */ -static u_int -ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl) -{ - u_int scbid; - u_int scb_offset; - u_int saved_scbptr; - - scb_offset = ahd_index_busy_tcl(ahd, &saved_scbptr, tcl); - scbid = ahd_inw_scbram(ahd, scb_offset); - ahd_set_scbptr(ahd, saved_scbptr); - return (scbid); -} - -static void -ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid) -{ - u_int scb_offset; - u_int saved_scbptr; - - scb_offset = ahd_index_busy_tcl(ahd, &saved_scbptr, tcl); - ahd_outw(ahd, scb_offset, scbid); - ahd_set_scbptr(ahd, saved_scbptr); -} - -/************************** SCB and SCB queue management **********************/ -static int -ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target, - char channel, int lun, u_int tag, role_t role) -{ - int targ = SCB_GET_TARGET(ahd, scb); - char chan = SCB_GET_CHANNEL(ahd, scb); - int slun = SCB_GET_LUN(scb); - int match; - - match = ((chan == channel) || (channel == ALL_CHANNELS)); - if (match != 0) - match = ((targ == target) || (target == CAM_TARGET_WILDCARD)); - if (match != 0) - match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); - if (match != 0) { -#ifdef AHD_TARGET_MODE - int group; - - group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); - if (role == ROLE_INITIATOR) { - match = (group != XPT_FC_GROUP_TMODE) - && ((tag == SCB_GET_TAG(scb)) - || (tag == SCB_LIST_NULL)); - } else if (role == ROLE_TARGET) { - match = (group == XPT_FC_GROUP_TMODE) - && ((tag == scb->io_ctx->csio.tag_id) - || (tag == SCB_LIST_NULL)); - } -#else /* !AHD_TARGET_MODE */ - match = ((tag == SCB_GET_TAG(scb)) || (tag == SCB_LIST_NULL)); -#endif /* AHD_TARGET_MODE */ - } - - return match; -} - -static void -ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb) -{ - int target; - char channel; - int lun; - - target = SCB_GET_TARGET(ahd, scb); - lun = SCB_GET_LUN(scb); - channel = SCB_GET_CHANNEL(ahd, scb); - - ahd_search_qinfifo(ahd, target, channel, lun, - /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN, - CAM_REQUEUE_REQ, SEARCH_COMPLETE); - - ahd_platform_freeze_devq(ahd, scb); -} - -void -ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb) -{ - struct scb *prev_scb; - ahd_mode_state saved_modes; - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); - prev_scb = NULL; - if (ahd_qinfifo_count(ahd) != 0) { - u_int prev_tag; - u_int prev_pos; - - prev_pos = AHD_QIN_WRAP(ahd->qinfifonext - 1); - prev_tag = ahd->qinfifo[prev_pos]; - prev_scb = ahd_lookup_scb(ahd, prev_tag); - } - ahd_qinfifo_requeue(ahd, prev_scb, scb); - ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); - ahd_restore_modes(ahd, saved_modes); -} - -static void -ahd_qinfifo_requeue(struct ahd_softc *ahd, struct scb *prev_scb, - struct scb *scb) -{ - if (prev_scb == NULL) { - uint32_t busaddr; - - busaddr = ahd_le32toh(scb->hscb->hscb_busaddr); - ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); - } else { - prev_scb->hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr; - ahd_sync_scb(ahd, prev_scb, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - } - ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb); - ahd->qinfifonext++; - scb->hscb->next_hscb_busaddr = ahd->next_queued_hscb->hscb_busaddr; - ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); -} - -static int -ahd_qinfifo_count(struct ahd_softc *ahd) -{ - u_int qinpos; - u_int wrap_qinpos; - u_int wrap_qinfifonext; - - AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK); - qinpos = ahd_get_snscb_qoff(ahd); - wrap_qinpos = AHD_QIN_WRAP(qinpos); - wrap_qinfifonext = AHD_QIN_WRAP(ahd->qinfifonext); - if (wrap_qinfifonext >= wrap_qinpos) - return (wrap_qinfifonext - wrap_qinpos); - else - return (wrap_qinfifonext - + ARRAY_SIZE(ahd->qinfifo) - wrap_qinpos); -} - -static void -ahd_reset_cmds_pending(struct ahd_softc *ahd) -{ - struct scb *scb; - ahd_mode_state saved_modes; - u_int pending_cmds; - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); - - /* - * Don't count any commands as outstanding that the - * sequencer has already marked for completion. - */ - ahd_flush_qoutfifo(ahd); - - pending_cmds = 0; - LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { - pending_cmds++; - } - ahd_outw(ahd, CMDS_PENDING, pending_cmds - ahd_qinfifo_count(ahd)); - ahd_restore_modes(ahd, saved_modes); - ahd->flags &= ~AHD_UPDATE_PEND_CMDS; -} - -static void -ahd_done_with_status(struct ahd_softc *ahd, struct scb *scb, uint32_t status) -{ - cam_status ostat; - cam_status cstat; - - ostat = ahd_get_transaction_status(scb); - if (ostat == CAM_REQ_INPROG) - ahd_set_transaction_status(scb, status); - cstat = ahd_get_transaction_status(scb); - if (cstat != CAM_REQ_CMP) - ahd_freeze_scb(scb); - ahd_done(ahd, scb); -} - -int -ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status, - ahd_search_action action) -{ - struct scb *scb; - struct scb *mk_msg_scb; - struct scb *prev_scb; - ahd_mode_state saved_modes; - u_int qinstart; - u_int qinpos; - u_int qintail; - u_int tid_next; - u_int tid_prev; - u_int scbid; - u_int seq_flags2; - u_int savedscbptr; - uint32_t busaddr; - int found; - int targets; - - /* Must be in CCHAN mode */ - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); - - /* - * Halt any pending SCB DMA. The sequencer will reinitiate - * this dma if the qinfifo is not empty once we unpause. - */ - if ((ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN|CCSCBDIR)) - == (CCARREN|CCSCBEN|CCSCBDIR)) { - ahd_outb(ahd, CCSCBCTL, - ahd_inb(ahd, CCSCBCTL) & ~(CCARREN|CCSCBEN)); - while ((ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN)) != 0) - ; - } - /* Determine sequencer's position in the qinfifo. */ - qintail = AHD_QIN_WRAP(ahd->qinfifonext); - qinstart = ahd_get_snscb_qoff(ahd); - qinpos = AHD_QIN_WRAP(qinstart); - found = 0; - prev_scb = NULL; - - if (action == SEARCH_PRINT) { - printk("qinstart = %d qinfifonext = %d\nQINFIFO:", - qinstart, ahd->qinfifonext); - } - - /* - * Start with an empty queue. Entries that are not chosen - * for removal will be re-added to the queue as we go. - */ - ahd->qinfifonext = qinstart; - busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr); - ahd_outl(ahd, NEXT_QUEUED_SCB_ADDR, busaddr); - - while (qinpos != qintail) { - scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]); - if (scb == NULL) { - printk("qinpos = %d, SCB index = %d\n", - qinpos, ahd->qinfifo[qinpos]); - panic("Loop 1\n"); - } - - if (ahd_match_scb(ahd, scb, target, channel, lun, tag, role)) { - /* - * We found an scb that needs to be acted on. - */ - found++; - switch (action) { - case SEARCH_COMPLETE: - if ((scb->flags & SCB_ACTIVE) == 0) - printk("Inactive SCB in qinfifo\n"); - ahd_done_with_status(ahd, scb, status); - /* FALLTHROUGH */ - case SEARCH_REMOVE: - break; - case SEARCH_PRINT: - printk(" 0x%x", ahd->qinfifo[qinpos]); - /* FALLTHROUGH */ - case SEARCH_COUNT: - ahd_qinfifo_requeue(ahd, prev_scb, scb); - prev_scb = scb; - break; - } - } else { - ahd_qinfifo_requeue(ahd, prev_scb, scb); - prev_scb = scb; - } - qinpos = AHD_QIN_WRAP(qinpos+1); - } - - ahd_set_hnscb_qoff(ahd, ahd->qinfifonext); - - if (action == SEARCH_PRINT) - printk("\nWAITING_TID_QUEUES:\n"); - - /* - * Search waiting for selection lists. We traverse the - * list of "their ids" waiting for selection and, if - * appropriate, traverse the SCBs of each "their id" - * looking for matches. - */ - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - seq_flags2 = ahd_inb(ahd, SEQ_FLAGS2); - if ((seq_flags2 & PENDING_MK_MESSAGE) != 0) { - scbid = ahd_inw(ahd, MK_MESSAGE_SCB); - mk_msg_scb = ahd_lookup_scb(ahd, scbid); - } else - mk_msg_scb = NULL; - savedscbptr = ahd_get_scbptr(ahd); - tid_next = ahd_inw(ahd, WAITING_TID_HEAD); - tid_prev = SCB_LIST_NULL; - targets = 0; - for (scbid = tid_next; !SCBID_IS_NULL(scbid); scbid = tid_next) { - u_int tid_head; - u_int tid_tail; - - targets++; - if (targets > AHD_NUM_TARGETS) - panic("TID LIST LOOP"); - - if (scbid >= ahd->scb_data.numscbs) { - printk("%s: Waiting TID List inconsistency. " - "SCB index == 0x%x, yet numscbs == 0x%x.", - ahd_name(ahd), scbid, ahd->scb_data.numscbs); - ahd_dump_card_state(ahd); - panic("for safety"); - } - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("%s: SCB = 0x%x Not Active!\n", - ahd_name(ahd), scbid); - panic("Waiting TID List traversal\n"); - } - ahd_set_scbptr(ahd, scbid); - tid_next = ahd_inw_scbram(ahd, SCB_NEXT2); - if (ahd_match_scb(ahd, scb, target, channel, CAM_LUN_WILDCARD, - SCB_LIST_NULL, ROLE_UNKNOWN) == 0) { - tid_prev = scbid; - continue; - } - - /* - * We found a list of scbs that needs to be searched. - */ - if (action == SEARCH_PRINT) - printk(" %d ( ", SCB_GET_TARGET(ahd, scb)); - tid_head = scbid; - found += ahd_search_scb_list(ahd, target, channel, - lun, tag, role, status, - action, &tid_head, &tid_tail, - SCB_GET_TARGET(ahd, scb)); - /* - * Check any MK_MESSAGE SCB that is still waiting to - * enter this target's waiting for selection queue. - */ - if (mk_msg_scb != NULL - && ahd_match_scb(ahd, mk_msg_scb, target, channel, - lun, tag, role)) { - - /* - * We found an scb that needs to be acted on. - */ - found++; - switch (action) { - case SEARCH_COMPLETE: - if ((mk_msg_scb->flags & SCB_ACTIVE) == 0) - printk("Inactive SCB pending MK_MSG\n"); - ahd_done_with_status(ahd, mk_msg_scb, status); - /* FALLTHROUGH */ - case SEARCH_REMOVE: - { - u_int tail_offset; - - printk("Removing MK_MSG scb\n"); - - /* - * Reset our tail to the tail of the - * main per-target list. - */ - tail_offset = WAITING_SCB_TAILS - + (2 * SCB_GET_TARGET(ahd, mk_msg_scb)); - ahd_outw(ahd, tail_offset, tid_tail); - - seq_flags2 &= ~PENDING_MK_MESSAGE; - ahd_outb(ahd, SEQ_FLAGS2, seq_flags2); - ahd_outw(ahd, CMDS_PENDING, - ahd_inw(ahd, CMDS_PENDING)-1); - mk_msg_scb = NULL; - break; - } - case SEARCH_PRINT: - printk(" 0x%x", SCB_GET_TAG(scb)); - /* FALLTHROUGH */ - case SEARCH_COUNT: - break; - } - } - - if (mk_msg_scb != NULL - && SCBID_IS_NULL(tid_head) - && ahd_match_scb(ahd, scb, target, channel, CAM_LUN_WILDCARD, - SCB_LIST_NULL, ROLE_UNKNOWN)) { - - /* - * When removing the last SCB for a target - * queue with a pending MK_MESSAGE scb, we - * must queue the MK_MESSAGE scb. - */ - printk("Queueing mk_msg_scb\n"); - tid_head = ahd_inw(ahd, MK_MESSAGE_SCB); - seq_flags2 &= ~PENDING_MK_MESSAGE; - ahd_outb(ahd, SEQ_FLAGS2, seq_flags2); - mk_msg_scb = NULL; - } - if (tid_head != scbid) - ahd_stitch_tid_list(ahd, tid_prev, tid_head, tid_next); - if (!SCBID_IS_NULL(tid_head)) - tid_prev = tid_head; - if (action == SEARCH_PRINT) - printk(")\n"); - } - - /* Restore saved state. */ - ahd_set_scbptr(ahd, savedscbptr); - ahd_restore_modes(ahd, saved_modes); - return (found); -} - -static int -ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status, - ahd_search_action action, u_int *list_head, - u_int *list_tail, u_int tid) -{ - struct scb *scb; - u_int scbid; - u_int next; - u_int prev; - int found; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - found = 0; - prev = SCB_LIST_NULL; - next = *list_head; - *list_tail = SCB_LIST_NULL; - for (scbid = next; !SCBID_IS_NULL(scbid); scbid = next) { - if (scbid >= ahd->scb_data.numscbs) { - printk("%s:SCB List inconsistency. " - "SCB == 0x%x, yet numscbs == 0x%x.", - ahd_name(ahd), scbid, ahd->scb_data.numscbs); - ahd_dump_card_state(ahd); - panic("for safety"); - } - scb = ahd_lookup_scb(ahd, scbid); - if (scb == NULL) { - printk("%s: SCB = %d Not Active!\n", - ahd_name(ahd), scbid); - panic("Waiting List traversal\n"); - } - ahd_set_scbptr(ahd, scbid); - *list_tail = scbid; - next = ahd_inw_scbram(ahd, SCB_NEXT); - if (ahd_match_scb(ahd, scb, target, channel, - lun, SCB_LIST_NULL, role) == 0) { - prev = scbid; - continue; - } - found++; - switch (action) { - case SEARCH_COMPLETE: - if ((scb->flags & SCB_ACTIVE) == 0) - printk("Inactive SCB in Waiting List\n"); - ahd_done_with_status(ahd, scb, status); - /* FALLTHROUGH */ - case SEARCH_REMOVE: - ahd_rem_wscb(ahd, scbid, prev, next, tid); - *list_tail = prev; - if (SCBID_IS_NULL(prev)) - *list_head = next; - break; - case SEARCH_PRINT: - printk("0x%x ", scbid); - case SEARCH_COUNT: - prev = scbid; - break; - } - if (found > AHD_SCB_MAX) - panic("SCB LIST LOOP"); - } - if (action == SEARCH_COMPLETE - || action == SEARCH_REMOVE) - ahd_outw(ahd, CMDS_PENDING, ahd_inw(ahd, CMDS_PENDING) - found); - return (found); -} - -static void -ahd_stitch_tid_list(struct ahd_softc *ahd, u_int tid_prev, - u_int tid_cur, u_int tid_next) -{ - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - - if (SCBID_IS_NULL(tid_cur)) { - - /* Bypass current TID list */ - if (SCBID_IS_NULL(tid_prev)) { - ahd_outw(ahd, WAITING_TID_HEAD, tid_next); - } else { - ahd_set_scbptr(ahd, tid_prev); - ahd_outw(ahd, SCB_NEXT2, tid_next); - } - if (SCBID_IS_NULL(tid_next)) - ahd_outw(ahd, WAITING_TID_TAIL, tid_prev); - } else { - - /* Stitch through tid_cur */ - if (SCBID_IS_NULL(tid_prev)) { - ahd_outw(ahd, WAITING_TID_HEAD, tid_cur); - } else { - ahd_set_scbptr(ahd, tid_prev); - ahd_outw(ahd, SCB_NEXT2, tid_cur); - } - ahd_set_scbptr(ahd, tid_cur); - ahd_outw(ahd, SCB_NEXT2, tid_next); - - if (SCBID_IS_NULL(tid_next)) - ahd_outw(ahd, WAITING_TID_TAIL, tid_cur); - } -} - -/* - * Manipulate the waiting for selection list and return the - * scb that follows the one that we remove. - */ -static u_int -ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid, - u_int prev, u_int next, u_int tid) -{ - u_int tail_offset; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - if (!SCBID_IS_NULL(prev)) { - ahd_set_scbptr(ahd, prev); - ahd_outw(ahd, SCB_NEXT, next); - } - - /* - * SCBs that have MK_MESSAGE set in them may - * cause the tail pointer to be updated without - * setting the next pointer of the previous tail. - * Only clear the tail if the removed SCB was - * the tail. - */ - tail_offset = WAITING_SCB_TAILS + (2 * tid); - if (SCBID_IS_NULL(next) - && ahd_inw(ahd, tail_offset) == scbid) - ahd_outw(ahd, tail_offset, prev); - - ahd_add_scb_to_free_list(ahd, scbid); - return (next); -} - -/* - * Add the SCB as selected by SCBPTR onto the on chip list of - * free hardware SCBs. This list is empty/unused if we are not - * performing SCB paging. - */ -static void -ahd_add_scb_to_free_list(struct ahd_softc *ahd, u_int scbid) -{ -/* XXX Need some other mechanism to designate "free". */ - /* - * Invalidate the tag so that our abort - * routines don't think it's active. - ahd_outb(ahd, SCB_TAG, SCB_LIST_NULL); - */ -} - -/******************************** Error Handling ******************************/ -/* - * Abort all SCBs that match the given description (target/channel/lun/tag), - * setting their status to the passed in status if the status has not already - * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer - * is paused before it is called. - */ -static int -ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status) -{ - struct scb *scbp; - struct scb *scbp_next; - u_int i, j; - u_int maxtarget; - u_int minlun; - u_int maxlun; - int found; - ahd_mode_state saved_modes; - - /* restore this when we're done */ - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - - found = ahd_search_qinfifo(ahd, target, channel, lun, SCB_LIST_NULL, - role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); - - /* - * Clean out the busy target table for any untagged commands. - */ - i = 0; - maxtarget = 16; - if (target != CAM_TARGET_WILDCARD) { - i = target; - if (channel == 'B') - i += 8; - maxtarget = i + 1; - } - - if (lun == CAM_LUN_WILDCARD) { - minlun = 0; - maxlun = AHD_NUM_LUNS_NONPKT; - } else if (lun >= AHD_NUM_LUNS_NONPKT) { - minlun = maxlun = 0; - } else { - minlun = lun; - maxlun = lun + 1; - } - - if (role != ROLE_TARGET) { - for (;i < maxtarget; i++) { - for (j = minlun;j < maxlun; j++) { - u_int scbid; - u_int tcl; - - tcl = BUILD_TCL_RAW(i, 'A', j); - scbid = ahd_find_busy_tcl(ahd, tcl); - scbp = ahd_lookup_scb(ahd, scbid); - if (scbp == NULL - || ahd_match_scb(ahd, scbp, target, channel, - lun, tag, role) == 0) - continue; - ahd_unbusy_tcl(ahd, BUILD_TCL_RAW(i, 'A', j)); - } - } - } - - /* - * Don't abort commands that have already completed, - * but haven't quite made it up to the host yet. - */ - ahd_flush_qoutfifo(ahd); - - /* - * Go through the pending CCB list and look for - * commands for this target that are still active. - * These are other tagged commands that were - * disconnected when the reset occurred. - */ - scbp_next = LIST_FIRST(&ahd->pending_scbs); - while (scbp_next != NULL) { - scbp = scbp_next; - scbp_next = LIST_NEXT(scbp, pending_links); - if (ahd_match_scb(ahd, scbp, target, channel, lun, tag, role)) { - cam_status ostat; - - ostat = ahd_get_transaction_status(scbp); - if (ostat == CAM_REQ_INPROG) - ahd_set_transaction_status(scbp, status); - if (ahd_get_transaction_status(scbp) != CAM_REQ_CMP) - ahd_freeze_scb(scbp); - if ((scbp->flags & SCB_ACTIVE) == 0) - printk("Inactive SCB on pending list\n"); - ahd_done(ahd, scbp); - found++; - } - } - ahd_restore_modes(ahd, saved_modes); - ahd_platform_abort_scbs(ahd, target, channel, lun, tag, role, status); - ahd->flags |= AHD_UPDATE_PEND_CMDS; - return found; -} - -static void -ahd_reset_current_bus(struct ahd_softc *ahd) -{ - uint8_t scsiseq; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) & ~ENSCSIRST); - scsiseq = ahd_inb(ahd, SCSISEQ0) & ~(ENSELO|ENARBO|SCSIRSTO); - ahd_outb(ahd, SCSISEQ0, scsiseq | SCSIRSTO); - ahd_flush_device_writes(ahd); - ahd_delay(AHD_BUSRESET_DELAY); - /* Turn off the bus reset */ - ahd_outb(ahd, SCSISEQ0, scsiseq); - ahd_flush_device_writes(ahd); - ahd_delay(AHD_BUSRESET_DELAY); - if ((ahd->bugs & AHD_SCSIRST_BUG) != 0) { - /* - * 2A Razor #474 - * Certain chip state is not cleared for - * SCSI bus resets that we initiate, so - * we must reset the chip. - */ - ahd_reset(ahd, /*reinit*/TRUE); - ahd_intr_enable(ahd, /*enable*/TRUE); - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - } - - ahd_clear_intstat(ahd); -} - -int -ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) -{ - struct ahd_devinfo caminfo; - u_int initiator; - u_int target; - u_int max_scsiid; - int found; - u_int fifo; - u_int next_fifo; - uint8_t scsiseq; - - /* - * Check if the last bus reset is cleared - */ - if (ahd->flags & AHD_BUS_RESET_ACTIVE) { - printk("%s: bus reset still active\n", - ahd_name(ahd)); - return 0; - } - ahd->flags |= AHD_BUS_RESET_ACTIVE; - - ahd->pending_device = NULL; - - ahd_compile_devinfo(&caminfo, - CAM_TARGET_WILDCARD, - CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, - channel, ROLE_UNKNOWN); - ahd_pause(ahd); - - /* Make sure the sequencer is in a safe location. */ - ahd_clear_critical_section(ahd); - - /* - * Run our command complete fifos to ensure that we perform - * completion processing on any commands that 'completed' - * before the reset occurred. - */ - ahd_run_qoutfifo(ahd); -#ifdef AHD_TARGET_MODE - if ((ahd->flags & AHD_TARGETROLE) != 0) { - ahd_run_tqinfifo(ahd, /*paused*/TRUE); - } -#endif - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - - /* - * Disable selections so no automatic hardware - * functions will modify chip state. - */ - ahd_outb(ahd, SCSISEQ0, 0); - ahd_outb(ahd, SCSISEQ1, 0); - - /* - * Safely shut down our DMA engines. Always start with - * the FIFO that is not currently active (if any are - * actively connected). - */ - next_fifo = fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO; - if (next_fifo > CURRFIFO_1) - /* If disconneced, arbitrarily start with FIFO1. */ - next_fifo = fifo = 0; - do { - next_fifo ^= CURRFIFO_1; - ahd_set_modes(ahd, next_fifo, next_fifo); - ahd_outb(ahd, DFCNTRL, - ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN)); - while ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0) - ahd_delay(10); - /* - * Set CURRFIFO to the now inactive channel. - */ - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_outb(ahd, DFFSTAT, next_fifo); - } while (next_fifo != fifo); - - /* - * Reset the bus if we are initiating this reset - */ - ahd_clear_msg_state(ahd); - ahd_outb(ahd, SIMODE1, - ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST)); - - if (initiate_reset) - ahd_reset_current_bus(ahd); - - ahd_clear_intstat(ahd); - - /* - * Clean up all the state information for the - * pending transactions on this bus. - */ - found = ahd_abort_scbs(ahd, CAM_TARGET_WILDCARD, channel, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_UNKNOWN, CAM_SCSI_BUS_RESET); - - /* - * Cleanup anything left in the FIFOs. - */ - ahd_clear_fifo(ahd, 0); - ahd_clear_fifo(ahd, 1); - - /* - * Clear SCSI interrupt status - */ - ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI); - - /* - * Reenable selections - */ - ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST); - scsiseq = ahd_inb(ahd, SCSISEQ_TEMPLATE); - ahd_outb(ahd, SCSISEQ1, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); - - max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7; -#ifdef AHD_TARGET_MODE - /* - * Send an immediate notify ccb to all target more peripheral - * drivers affected by this action. - */ - for (target = 0; target <= max_scsiid; target++) { - struct ahd_tmode_tstate* tstate; - u_int lun; - - tstate = ahd->enabled_targets[target]; - if (tstate == NULL) - continue; - for (lun = 0; lun < AHD_NUM_LUNS; lun++) { - struct ahd_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[lun]; - if (lstate == NULL) - continue; - - ahd_queue_lstate_event(ahd, lstate, CAM_TARGET_WILDCARD, - EVENT_TYPE_BUS_RESET, /*arg*/0); - ahd_send_lstate_events(ahd, lstate); - } - } -#endif - /* - * Revert to async/narrow transfers until we renegotiate. - */ - for (target = 0; target <= max_scsiid; target++) { - - if (ahd->enabled_targets[target] == NULL) - continue; - for (initiator = 0; initiator <= max_scsiid; initiator++) { - struct ahd_devinfo devinfo; - - ahd_compile_devinfo(&devinfo, target, initiator, - CAM_LUN_WILDCARD, - 'A', ROLE_UNKNOWN); - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_CUR, /*paused*/TRUE); - ahd_set_syncrate(ahd, &devinfo, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHD_TRANS_CUR, /*paused*/TRUE); - } - } - - /* Notify the XPT that a bus reset occurred */ - ahd_send_async(ahd, caminfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET); - - ahd_restart(ahd); - - return (found); -} - -/**************************** Statistics Processing ***************************/ -static void -ahd_stat_timer(void *arg) -{ - struct ahd_softc *ahd = arg; - u_long s; - int enint_coal; - - ahd_lock(ahd, &s); - - enint_coal = ahd->hs_mailbox & ENINT_COALESCE; - if (ahd->cmdcmplt_total > ahd->int_coalescing_threshold) - enint_coal |= ENINT_COALESCE; - else if (ahd->cmdcmplt_total < ahd->int_coalescing_stop_threshold) - enint_coal &= ~ENINT_COALESCE; - - if (enint_coal != (ahd->hs_mailbox & ENINT_COALESCE)) { - ahd_enable_coalescing(ahd, enint_coal); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0) - printk("%s: Interrupt coalescing " - "now %sabled. Cmds %d\n", - ahd_name(ahd), - (enint_coal & ENINT_COALESCE) ? "en" : "dis", - ahd->cmdcmplt_total); -#endif - } - - ahd->cmdcmplt_bucket = (ahd->cmdcmplt_bucket+1) & (AHD_STAT_BUCKETS-1); - ahd->cmdcmplt_total -= ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]; - ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket] = 0; - ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, - ahd_stat_timer, ahd); - ahd_unlock(ahd, &s); -} - -/****************************** Status Processing *****************************/ - -static void -ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb) -{ - struct hardware_scb *hscb; - int paused; - - /* - * The sequencer freezes its select-out queue - * anytime a SCSI status error occurs. We must - * handle the error and increment our qfreeze count - * to allow the sequencer to continue. We don't - * bother clearing critical sections here since all - * operations are on data structures that the sequencer - * is not touching once the queue is frozen. - */ - hscb = scb->hscb; - - if (ahd_is_paused(ahd)) { - paused = 1; - } else { - paused = 0; - ahd_pause(ahd); - } - - /* Freeze the queue until the client sees the error. */ - ahd_freeze_devq(ahd, scb); - ahd_freeze_scb(scb); - ahd->qfreeze_cnt++; - ahd_outw(ahd, KERNEL_QFREEZE_COUNT, ahd->qfreeze_cnt); - - if (paused == 0) - ahd_unpause(ahd); - - /* Don't want to clobber the original sense code */ - if ((scb->flags & SCB_SENSE) != 0) { - /* - * Clear the SCB_SENSE Flag and perform - * a normal command completion. - */ - scb->flags &= ~SCB_SENSE; - ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); - ahd_done(ahd, scb); - return; - } - ahd_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); - ahd_set_scsi_status(scb, hscb->shared_data.istatus.scsi_status); - switch (hscb->shared_data.istatus.scsi_status) { - case STATUS_PKT_SENSE: - { - struct scsi_status_iu_header *siu; - - ahd_sync_sense(ahd, scb, BUS_DMASYNC_POSTREAD); - siu = (struct scsi_status_iu_header *)scb->sense_data; - ahd_set_scsi_status(scb, siu->status); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_SENSE) != 0) { - ahd_print_path(ahd, scb); - printk("SCB 0x%x Received PKT Status of 0x%x\n", - SCB_GET_TAG(scb), siu->status); - printk("\tflags = 0x%x, sense len = 0x%x, " - "pktfail = 0x%x\n", - siu->flags, scsi_4btoul(siu->sense_length), - scsi_4btoul(siu->pkt_failures_length)); - } -#endif - if ((siu->flags & SIU_RSPVALID) != 0) { - ahd_print_path(ahd, scb); - if (scsi_4btoul(siu->pkt_failures_length) < 4) { - printk("Unable to parse pkt_failures\n"); - } else { - - switch (SIU_PKTFAIL_CODE(siu)) { - case SIU_PFC_NONE: - printk("No packet failure found\n"); - break; - case SIU_PFC_CIU_FIELDS_INVALID: - printk("Invalid Command IU Field\n"); - break; - case SIU_PFC_TMF_NOT_SUPPORTED: - printk("TMF not supported\n"); - break; - case SIU_PFC_TMF_FAILED: - printk("TMF failed\n"); - break; - case SIU_PFC_INVALID_TYPE_CODE: - printk("Invalid L_Q Type code\n"); - break; - case SIU_PFC_ILLEGAL_REQUEST: - printk("Illegal request\n"); - default: - break; - } - } - if (siu->status == SCSI_STATUS_OK) - ahd_set_transaction_status(scb, - CAM_REQ_CMP_ERR); - } - if ((siu->flags & SIU_SNSVALID) != 0) { - scb->flags |= SCB_PKT_SENSE; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_SENSE) != 0) - printk("Sense data available\n"); -#endif - } - ahd_done(ahd, scb); - break; - } - case SCSI_STATUS_CMD_TERMINATED: - case SCSI_STATUS_CHECK_COND: - { - struct ahd_devinfo devinfo; - struct ahd_dma_seg *sg; - struct scsi_sense *sc; - struct ahd_initiator_tinfo *targ_info; - struct ahd_tmode_tstate *tstate; - struct ahd_transinfo *tinfo; -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_SENSE) { - ahd_print_path(ahd, scb); - printk("SCB %d: requests Check Status\n", - SCB_GET_TAG(scb)); - } -#endif - - if (ahd_perform_autosense(scb) == 0) - break; - - ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb), - SCB_GET_TARGET(ahd, scb), - SCB_GET_LUN(scb), - SCB_GET_CHANNEL(ahd, scb), - ROLE_INITIATOR); - targ_info = ahd_fetch_transinfo(ahd, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, - &tstate); - tinfo = &targ_info->curr; - sg = scb->sg_list; - sc = (struct scsi_sense *)hscb->shared_data.idata.cdb; - /* - * Save off the residual if there is one. - */ - ahd_update_residual(ahd, scb); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_SENSE) { - ahd_print_path(ahd, scb); - printk("Sending Sense\n"); - } -#endif - scb->sg_count = 0; - sg = ahd_sg_setup(ahd, scb, sg, ahd_get_sense_bufaddr(ahd, scb), - ahd_get_sense_bufsize(ahd, scb), - /*last*/TRUE); - sc->opcode = REQUEST_SENSE; - sc->byte2 = 0; - if (tinfo->protocol_version <= SCSI_REV_2 - && SCB_GET_LUN(scb) < 8) - sc->byte2 = SCB_GET_LUN(scb) << 5; - sc->unused[0] = 0; - sc->unused[1] = 0; - sc->length = ahd_get_sense_bufsize(ahd, scb); - sc->control = 0; - - /* - * We can't allow the target to disconnect. - * This will be an untagged transaction and - * having the target disconnect will make this - * transaction indestinguishable from outstanding - * tagged transactions. - */ - hscb->control = 0; - - /* - * This request sense could be because the - * the device lost power or in some other - * way has lost our transfer negotiations. - * Renegotiate if appropriate. Unit attention - * errors will be reported before any data - * phases occur. - */ - if (ahd_get_residual(scb) == ahd_get_transfer_length(scb)) { - ahd_update_neg_request(ahd, &devinfo, - tstate, targ_info, - AHD_NEG_IF_NON_ASYNC); - } - if (tstate->auto_negotiate & devinfo.target_mask) { - hscb->control |= MK_MESSAGE; - scb->flags &= - ~(SCB_NEGOTIATE|SCB_ABORT|SCB_DEVICE_RESET); - scb->flags |= SCB_AUTO_NEGOTIATE; - } - hscb->cdb_len = sizeof(*sc); - ahd_setup_data_scb(ahd, scb); - scb->flags |= SCB_SENSE; - ahd_queue_scb(ahd, scb); - break; - } - case SCSI_STATUS_OK: - printk("%s: Interrupted for status of 0???\n", - ahd_name(ahd)); - /* FALLTHROUGH */ - default: - ahd_done(ahd, scb); - break; - } -} - -static void -ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb) -{ - if (scb->hscb->shared_data.istatus.scsi_status != 0) { - ahd_handle_scsi_status(ahd, scb); - } else { - ahd_calc_residual(ahd, scb); - ahd_done(ahd, scb); - } -} - -/* - * Calculate the residual for a just completed SCB. - */ -static void -ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb) -{ - struct hardware_scb *hscb; - struct initiator_status *spkt; - uint32_t sgptr; - uint32_t resid_sgptr; - uint32_t resid; - - /* - * 5 cases. - * 1) No residual. - * SG_STATUS_VALID clear in sgptr. - * 2) Transferless command - * 3) Never performed any transfers. - * sgptr has SG_FULL_RESID set. - * 4) No residual but target did not - * save data pointers after the - * last transfer, so sgptr was - * never updated. - * 5) We have a partial residual. - * Use residual_sgptr to determine - * where we are. - */ - - hscb = scb->hscb; - sgptr = ahd_le32toh(hscb->sgptr); - if ((sgptr & SG_STATUS_VALID) == 0) - /* Case 1 */ - return; - sgptr &= ~SG_STATUS_VALID; - - if ((sgptr & SG_LIST_NULL) != 0) - /* Case 2 */ - return; - - /* - * Residual fields are the same in both - * target and initiator status packets, - * so we can always use the initiator fields - * regardless of the role for this SCB. - */ - spkt = &hscb->shared_data.istatus; - resid_sgptr = ahd_le32toh(spkt->residual_sgptr); - if ((sgptr & SG_FULL_RESID) != 0) { - /* Case 3 */ - resid = ahd_get_transfer_length(scb); - } else if ((resid_sgptr & SG_LIST_NULL) != 0) { - /* Case 4 */ - return; - } else if ((resid_sgptr & SG_OVERRUN_RESID) != 0) { - ahd_print_path(ahd, scb); - printk("data overrun detected Tag == 0x%x.\n", - SCB_GET_TAG(scb)); - ahd_freeze_devq(ahd, scb); - ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); - ahd_freeze_scb(scb); - return; - } else if ((resid_sgptr & ~SG_PTR_MASK) != 0) { - panic("Bogus resid sgptr value 0x%x\n", resid_sgptr); - /* NOTREACHED */ - } else { - struct ahd_dma_seg *sg; - - /* - * Remainder of the SG where the transfer - * stopped. - */ - resid = ahd_le32toh(spkt->residual_datacnt) & AHD_SG_LEN_MASK; - sg = ahd_sg_bus_to_virt(ahd, scb, resid_sgptr & SG_PTR_MASK); - - /* The residual sg_ptr always points to the next sg */ - sg--; - - /* - * Add up the contents of all residual - * SG segments that are after the SG where - * the transfer stopped. - */ - while ((ahd_le32toh(sg->len) & AHD_DMA_LAST_SEG) == 0) { - sg++; - resid += ahd_le32toh(sg->len) & AHD_SG_LEN_MASK; - } - } - if ((scb->flags & SCB_SENSE) == 0) - ahd_set_residual(scb, resid); - else - ahd_set_sense_residual(scb, resid); - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) { - ahd_print_path(ahd, scb); - printk("Handled %sResidual of %d bytes\n", - (scb->flags & SCB_SENSE) ? "Sense " : "", resid); - } -#endif -} - -/******************************* Target Mode **********************************/ -#ifdef AHD_TARGET_MODE -/* - * Add a target mode event to this lun's queue - */ -static void -ahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate, - u_int initiator_id, u_int event_type, u_int event_arg) -{ - struct ahd_tmode_event *event; - int pending; - - xpt_freeze_devq(lstate->path, /*count*/1); - if (lstate->event_w_idx >= lstate->event_r_idx) - pending = lstate->event_w_idx - lstate->event_r_idx; - else - pending = AHD_TMODE_EVENT_BUFFER_SIZE + 1 - - (lstate->event_r_idx - lstate->event_w_idx); - - if (event_type == EVENT_TYPE_BUS_RESET - || event_type == MSG_BUS_DEV_RESET) { - /* - * Any earlier events are irrelevant, so reset our buffer. - * This has the effect of allowing us to deal with reset - * floods (an external device holding down the reset line) - * without losing the event that is really interesting. - */ - lstate->event_r_idx = 0; - lstate->event_w_idx = 0; - xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE); - } - - if (pending == AHD_TMODE_EVENT_BUFFER_SIZE) { - xpt_print_path(lstate->path); - printk("immediate event %x:%x lost\n", - lstate->event_buffer[lstate->event_r_idx].event_type, - lstate->event_buffer[lstate->event_r_idx].event_arg); - lstate->event_r_idx++; - if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE) - lstate->event_r_idx = 0; - xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE); - } - - event = &lstate->event_buffer[lstate->event_w_idx]; - event->initiator_id = initiator_id; - event->event_type = event_type; - event->event_arg = event_arg; - lstate->event_w_idx++; - if (lstate->event_w_idx == AHD_TMODE_EVENT_BUFFER_SIZE) - lstate->event_w_idx = 0; -} - -/* - * Send any target mode events queued up waiting - * for immediate notify resources. - */ -void -ahd_send_lstate_events(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate) -{ - struct ccb_hdr *ccbh; - struct ccb_immed_notify *inot; - - while (lstate->event_r_idx != lstate->event_w_idx - && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { - struct ahd_tmode_event *event; - - event = &lstate->event_buffer[lstate->event_r_idx]; - SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); - inot = (struct ccb_immed_notify *)ccbh; - switch (event->event_type) { - case EVENT_TYPE_BUS_RESET: - ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; - break; - default: - ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; - inot->message_args[0] = event->event_type; - inot->message_args[1] = event->event_arg; - break; - } - inot->initiator_id = event->initiator_id; - inot->sense_len = 0; - xpt_done((union ccb *)inot); - lstate->event_r_idx++; - if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE) - lstate->event_r_idx = 0; - } -} -#endif - -/******************** Sequencer Program Patching/Download *********************/ - -#ifdef AHD_DUMP_SEQ -void -ahd_dumpseq(struct ahd_softc* ahd) -{ - int i; - int max_prog; - - max_prog = 2048; - - ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); - ahd_outw(ahd, PRGMCNT, 0); - for (i = 0; i < max_prog; i++) { - uint8_t ins_bytes[4]; - - ahd_insb(ahd, SEQRAM, ins_bytes, 4); - printk("0x%08x\n", ins_bytes[0] << 24 - | ins_bytes[1] << 16 - | ins_bytes[2] << 8 - | ins_bytes[3]); - } -} -#endif - -static void -ahd_loadseq(struct ahd_softc *ahd) -{ - struct cs cs_table[num_critical_sections]; - u_int begin_set[num_critical_sections]; - u_int end_set[num_critical_sections]; - const struct patch *cur_patch; - u_int cs_count; - u_int cur_cs; - u_int i; - int downloaded; - u_int skip_addr; - u_int sg_prefetch_cnt; - u_int sg_prefetch_cnt_limit; - u_int sg_prefetch_align; - u_int sg_size; - u_int cacheline_mask; - uint8_t download_consts[DOWNLOAD_CONST_COUNT]; - - if (bootverbose) - printk("%s: Downloading Sequencer Program...", - ahd_name(ahd)); - -#if DOWNLOAD_CONST_COUNT != 8 -#error "Download Const Mismatch" -#endif - /* - * Start out with 0 critical sections - * that apply to this firmware load. - */ - cs_count = 0; - cur_cs = 0; - memset(begin_set, 0, sizeof(begin_set)); - memset(end_set, 0, sizeof(end_set)); - - /* - * Setup downloadable constant table. - * - * The computation for the S/G prefetch variables is - * a bit complicated. We would like to always fetch - * in terms of cachelined sized increments. However, - * if the cacheline is not an even multiple of the - * SG element size or is larger than our SG RAM, using - * just the cache size might leave us with only a portion - * of an SG element at the tail of a prefetch. If the - * cacheline is larger than our S/G prefetch buffer less - * the size of an SG element, we may round down to a cacheline - * that doesn't contain any or all of the S/G of interest - * within the bounds of our S/G ram. Provide variables to - * the sequencer that will allow it to handle these edge - * cases. - */ - /* Start by aligning to the nearest cacheline. */ - sg_prefetch_align = ahd->pci_cachesize; - if (sg_prefetch_align == 0) - sg_prefetch_align = 8; - /* Round down to the nearest power of 2. */ - while (powerof2(sg_prefetch_align) == 0) - sg_prefetch_align--; - - cacheline_mask = sg_prefetch_align - 1; - - /* - * If the cacheline boundary is greater than half our prefetch RAM - * we risk not being able to fetch even a single complete S/G - * segment if we align to that boundary. - */ - if (sg_prefetch_align > CCSGADDR_MAX/2) - sg_prefetch_align = CCSGADDR_MAX/2; - /* Start by fetching a single cacheline. */ - sg_prefetch_cnt = sg_prefetch_align; - /* - * Increment the prefetch count by cachelines until - * at least one S/G element will fit. - */ - sg_size = sizeof(struct ahd_dma_seg); - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) - sg_size = sizeof(struct ahd_dma64_seg); - while (sg_prefetch_cnt < sg_size) - sg_prefetch_cnt += sg_prefetch_align; - /* - * If the cacheline is not an even multiple of - * the S/G size, we may only get a partial S/G when - * we align. Add a cacheline if this is the case. - */ - if ((sg_prefetch_align % sg_size) != 0 - && (sg_prefetch_cnt < CCSGADDR_MAX)) - sg_prefetch_cnt += sg_prefetch_align; - /* - * Lastly, compute a value that the sequencer can use - * to determine if the remainder of the CCSGRAM buffer - * has a full S/G element in it. - */ - sg_prefetch_cnt_limit = -(sg_prefetch_cnt - sg_size + 1); - download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt; - download_consts[SG_PREFETCH_CNT_LIMIT] = sg_prefetch_cnt_limit; - download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_align - 1); - download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_align - 1); - download_consts[SG_SIZEOF] = sg_size; - download_consts[PKT_OVERRUN_BUFOFFSET] = - (ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256; - download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN; - download_consts[CACHELINE_MASK] = cacheline_mask; - cur_patch = patches; - downloaded = 0; - skip_addr = 0; - ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); - ahd_outw(ahd, PRGMCNT, 0); - - for (i = 0; i < sizeof(seqprog)/4; i++) { - if (ahd_check_patch(ahd, &cur_patch, i, &skip_addr) == 0) { - /* - * Don't download this instruction as it - * is in a patch that was removed. - */ - continue; - } - /* - * Move through the CS table until we find a CS - * that might apply to this instruction. - */ - for (; cur_cs < num_critical_sections; cur_cs++) { - if (critical_sections[cur_cs].end <= i) { - if (begin_set[cs_count] == TRUE - && end_set[cs_count] == FALSE) { - cs_table[cs_count].end = downloaded; - end_set[cs_count] = TRUE; - cs_count++; - } - continue; - } - if (critical_sections[cur_cs].begin <= i - && begin_set[cs_count] == FALSE) { - cs_table[cs_count].begin = downloaded; - begin_set[cs_count] = TRUE; - } - break; - } - ahd_download_instr(ahd, i, download_consts); - downloaded++; - } - - ahd->num_critical_sections = cs_count; - if (cs_count != 0) { - - cs_count *= sizeof(struct cs); - ahd->critical_sections = kmalloc(cs_count, GFP_ATOMIC); - if (ahd->critical_sections == NULL) - panic("ahd_loadseq: Could not malloc"); - memcpy(ahd->critical_sections, cs_table, cs_count); - } - ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE); - - if (bootverbose) { - printk(" %d instructions downloaded\n", downloaded); - printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", - ahd_name(ahd), ahd->features, ahd->bugs, ahd->flags); - } -} - -static int -ahd_check_patch(struct ahd_softc *ahd, const struct patch **start_patch, - u_int start_instr, u_int *skip_addr) -{ - const struct patch *cur_patch; - const struct patch *last_patch; - u_int num_patches; - - num_patches = ARRAY_SIZE(patches); - last_patch = &patches[num_patches]; - cur_patch = *start_patch; - - while (cur_patch < last_patch && start_instr == cur_patch->begin) { - - if (cur_patch->patch_func(ahd) == 0) { - - /* Start rejecting code */ - *skip_addr = start_instr + cur_patch->skip_instr; - cur_patch += cur_patch->skip_patch; - } else { - /* Accepted this patch. Advance to the next - * one and wait for our intruction pointer to - * hit this point. - */ - cur_patch++; - } - } - - *start_patch = cur_patch; - if (start_instr < *skip_addr) - /* Still skipping */ - return (0); - - return (1); -} - -static u_int -ahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address) -{ - const struct patch *cur_patch; - int address_offset; - u_int skip_addr; - u_int i; - - address_offset = 0; - cur_patch = patches; - skip_addr = 0; - - for (i = 0; i < address;) { - - ahd_check_patch(ahd, &cur_patch, i, &skip_addr); - - if (skip_addr > i) { - int end_addr; - - end_addr = min(address, skip_addr); - address_offset += end_addr - i; - i = skip_addr; - } else { - i++; - } - } - return (address - address_offset); -} - -static void -ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts) -{ - union ins_formats instr; - struct ins_format1 *fmt1_ins; - struct ins_format3 *fmt3_ins; - u_int opcode; - - /* - * The firmware is always compiled into a little endian format. - */ - instr.integer = ahd_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); - - fmt1_ins = &instr.format1; - fmt3_ins = NULL; - - /* Pull the opcode */ - opcode = instr.format1.opcode; - switch (opcode) { - case AIC_OP_JMP: - case AIC_OP_JC: - case AIC_OP_JNC: - case AIC_OP_CALL: - case AIC_OP_JNE: - case AIC_OP_JNZ: - case AIC_OP_JE: - case AIC_OP_JZ: - { - fmt3_ins = &instr.format3; - fmt3_ins->address = ahd_resolve_seqaddr(ahd, fmt3_ins->address); - /* FALLTHROUGH */ - } - case AIC_OP_OR: - case AIC_OP_AND: - case AIC_OP_XOR: - case AIC_OP_ADD: - case AIC_OP_ADC: - case AIC_OP_BMOV: - if (fmt1_ins->parity != 0) { - fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; - } - fmt1_ins->parity = 0; - /* FALLTHROUGH */ - case AIC_OP_ROL: - { - int i, count; - - /* Calculate odd parity for the instruction */ - for (i = 0, count = 0; i < 31; i++) { - uint32_t mask; - - mask = 0x01 << i; - if ((instr.integer & mask) != 0) - count++; - } - if ((count & 0x01) == 0) - instr.format1.parity = 1; - - /* The sequencer is a little endian cpu */ - instr.integer = ahd_htole32(instr.integer); - ahd_outsb(ahd, SEQRAM, instr.bytes, 4); - break; - } - default: - panic("Unknown opcode encountered in seq program"); - break; - } -} - -static int -ahd_probe_stack_size(struct ahd_softc *ahd) -{ - int last_probe; - - last_probe = 0; - while (1) { - int i; - - /* - * We avoid using 0 as a pattern to avoid - * confusion if the stack implementation - * "back-fills" with zeros when "poping' - * entries. - */ - for (i = 1; i <= last_probe+1; i++) { - ahd_outb(ahd, STACK, i & 0xFF); - ahd_outb(ahd, STACK, (i >> 8) & 0xFF); - } - - /* Verify */ - for (i = last_probe+1; i > 0; i--) { - u_int stack_entry; - - stack_entry = ahd_inb(ahd, STACK) - |(ahd_inb(ahd, STACK) << 8); - if (stack_entry != i) - goto sized; - } - last_probe++; - } -sized: - return (last_probe); -} - -int -ahd_print_register(const ahd_reg_parse_entry_t *table, u_int num_entries, - const char *name, u_int address, u_int value, - u_int *cur_column, u_int wrap_point) -{ - int printed; - u_int printed_mask; - - if (cur_column != NULL && *cur_column >= wrap_point) { - printk("\n"); - *cur_column = 0; - } - printed = printk("%s[0x%x]", name, value); - if (table == NULL) { - printed += printk(" "); - *cur_column += printed; - return (printed); - } - printed_mask = 0; - while (printed_mask != 0xFF) { - int entry; - - for (entry = 0; entry < num_entries; entry++) { - if (((value & table[entry].mask) - != table[entry].value) - || ((printed_mask & table[entry].mask) - == table[entry].mask)) - continue; - - printed += printk("%s%s", - printed_mask == 0 ? ":(" : "|", - table[entry].name); - printed_mask |= table[entry].mask; - - break; - } - if (entry >= num_entries) - break; - } - if (printed_mask != 0) - printed += printk(") "); - else - printed += printk(" "); - if (cur_column != NULL) - *cur_column += printed; - return (printed); -} - -void -ahd_dump_card_state(struct ahd_softc *ahd) -{ - struct scb *scb; - ahd_mode_state saved_modes; - u_int dffstat; - int paused; - u_int scb_index; - u_int saved_scb_index; - u_int cur_col; - int i; - - if (ahd_is_paused(ahd)) { - paused = 1; - } else { - paused = 0; - ahd_pause(ahd); - } - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" - "%s: Dumping Card State at program address 0x%x Mode 0x%x\n", - ahd_name(ahd), - ahd_inw(ahd, CURADDR), - ahd_build_mode_state(ahd, ahd->saved_src_mode, - ahd->saved_dst_mode)); - if (paused) - printk("Card was paused\n"); - - if (ahd_check_cmdcmpltqueues(ahd)) - printk("Completions are pending\n"); - - /* - * Mode independent registers. - */ - cur_col = 0; - ahd_intstat_print(ahd_inb(ahd, INTSTAT), &cur_col, 50); - ahd_seloid_print(ahd_inb(ahd, SELOID), &cur_col, 50); - ahd_selid_print(ahd_inb(ahd, SELID), &cur_col, 50); - ahd_hs_mailbox_print(ahd_inb(ahd, LOCAL_HS_MAILBOX), &cur_col, 50); - ahd_intctl_print(ahd_inb(ahd, INTCTL), &cur_col, 50); - ahd_seqintstat_print(ahd_inb(ahd, SEQINTSTAT), &cur_col, 50); - ahd_saved_mode_print(ahd_inb(ahd, SAVED_MODE), &cur_col, 50); - ahd_dffstat_print(ahd_inb(ahd, DFFSTAT), &cur_col, 50); - ahd_scsisigi_print(ahd_inb(ahd, SCSISIGI), &cur_col, 50); - ahd_scsiphase_print(ahd_inb(ahd, SCSIPHASE), &cur_col, 50); - ahd_scsibus_print(ahd_inb(ahd, SCSIBUS), &cur_col, 50); - ahd_lastphase_print(ahd_inb(ahd, LASTPHASE), &cur_col, 50); - ahd_scsiseq0_print(ahd_inb(ahd, SCSISEQ0), &cur_col, 50); - ahd_scsiseq1_print(ahd_inb(ahd, SCSISEQ1), &cur_col, 50); - ahd_seqctl0_print(ahd_inb(ahd, SEQCTL0), &cur_col, 50); - ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50); - ahd_seq_flags_print(ahd_inb(ahd, SEQ_FLAGS), &cur_col, 50); - ahd_seq_flags2_print(ahd_inb(ahd, SEQ_FLAGS2), &cur_col, 50); - ahd_qfreeze_count_print(ahd_inw(ahd, QFREEZE_COUNT), &cur_col, 50); - ahd_kernel_qfreeze_count_print(ahd_inw(ahd, KERNEL_QFREEZE_COUNT), - &cur_col, 50); - ahd_mk_message_scb_print(ahd_inw(ahd, MK_MESSAGE_SCB), &cur_col, 50); - ahd_mk_message_scsiid_print(ahd_inb(ahd, MK_MESSAGE_SCSIID), - &cur_col, 50); - ahd_sstat0_print(ahd_inb(ahd, SSTAT0), &cur_col, 50); - ahd_sstat1_print(ahd_inb(ahd, SSTAT1), &cur_col, 50); - ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50); - ahd_sstat3_print(ahd_inb(ahd, SSTAT3), &cur_col, 50); - ahd_perrdiag_print(ahd_inb(ahd, PERRDIAG), &cur_col, 50); - ahd_simode1_print(ahd_inb(ahd, SIMODE1), &cur_col, 50); - ahd_lqistat0_print(ahd_inb(ahd, LQISTAT0), &cur_col, 50); - ahd_lqistat1_print(ahd_inb(ahd, LQISTAT1), &cur_col, 50); - ahd_lqistat2_print(ahd_inb(ahd, LQISTAT2), &cur_col, 50); - ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50); - ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50); - ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50); - printk("\n"); - printk("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x " - "CURRSCB 0x%x NEXTSCB 0x%x\n", - ahd->scb_data.numscbs, ahd_inw(ahd, CMDS_PENDING), - ahd_inw(ahd, LASTSCB), ahd_inw(ahd, CURRSCB), - ahd_inw(ahd, NEXTSCB)); - cur_col = 0; - /* QINFIFO */ - ahd_search_qinfifo(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT); - saved_scb_index = ahd_get_scbptr(ahd); - printk("Pending list:"); - i = 0; - LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { - if (i++ > AHD_SCB_MAX) - break; - cur_col = printk("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb), - ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT)); - ahd_set_scbptr(ahd, SCB_GET_TAG(scb)); - ahd_scb_control_print(ahd_inb_scbram(ahd, SCB_CONTROL), - &cur_col, 60); - ahd_scb_scsiid_print(ahd_inb_scbram(ahd, SCB_SCSIID), - &cur_col, 60); - } - printk("\nTotal %d\n", i); - - printk("Kernel Free SCB list: "); - i = 0; - TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) { - struct scb *list_scb; - - list_scb = scb; - do { - printk("%d ", SCB_GET_TAG(list_scb)); - list_scb = LIST_NEXT(list_scb, collision_links); - } while (list_scb && i++ < AHD_SCB_MAX); - } - - LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) { - if (i++ > AHD_SCB_MAX) - break; - printk("%d ", SCB_GET_TAG(scb)); - } - printk("\n"); - - printk("Sequencer Complete DMA-inprog list: "); - scb_index = ahd_inw(ahd, COMPLETE_SCB_DMAINPROG_HEAD); - i = 0; - while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { - ahd_set_scbptr(ahd, scb_index); - printk("%d ", scb_index); - scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); - } - printk("\n"); - - printk("Sequencer Complete list: "); - scb_index = ahd_inw(ahd, COMPLETE_SCB_HEAD); - i = 0; - while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { - ahd_set_scbptr(ahd, scb_index); - printk("%d ", scb_index); - scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); - } - printk("\n"); - - - printk("Sequencer DMA-Up and Complete list: "); - scb_index = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD); - i = 0; - while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { - ahd_set_scbptr(ahd, scb_index); - printk("%d ", scb_index); - scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); - } - printk("\n"); - printk("Sequencer On QFreeze and Complete list: "); - scb_index = ahd_inw(ahd, COMPLETE_ON_QFREEZE_HEAD); - i = 0; - while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) { - ahd_set_scbptr(ahd, scb_index); - printk("%d ", scb_index); - scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE); - } - printk("\n"); - ahd_set_scbptr(ahd, saved_scb_index); - dffstat = ahd_inb(ahd, DFFSTAT); - for (i = 0; i < 2; i++) { -#ifdef AHD_DEBUG - struct scb *fifo_scb; -#endif - u_int fifo_scbptr; - - ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i); - fifo_scbptr = ahd_get_scbptr(ahd); - printk("\n\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n", - ahd_name(ahd), i, - (dffstat & (FIFO0FREE << i)) ? "Free" : "Active", - ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr); - cur_col = 0; - ahd_seqimode_print(ahd_inb(ahd, SEQIMODE), &cur_col, 50); - ahd_seqintsrc_print(ahd_inb(ahd, SEQINTSRC), &cur_col, 50); - ahd_dfcntrl_print(ahd_inb(ahd, DFCNTRL), &cur_col, 50); - ahd_dfstatus_print(ahd_inb(ahd, DFSTATUS), &cur_col, 50); - ahd_sg_cache_shadow_print(ahd_inb(ahd, SG_CACHE_SHADOW), - &cur_col, 50); - ahd_sg_state_print(ahd_inb(ahd, SG_STATE), &cur_col, 50); - ahd_dffsxfrctl_print(ahd_inb(ahd, DFFSXFRCTL), &cur_col, 50); - ahd_soffcnt_print(ahd_inb(ahd, SOFFCNT), &cur_col, 50); - ahd_mdffstat_print(ahd_inb(ahd, MDFFSTAT), &cur_col, 50); - if (cur_col > 50) { - printk("\n"); - cur_col = 0; - } - cur_col += printk("SHADDR = 0x%x%x, SHCNT = 0x%x ", - ahd_inl(ahd, SHADDR+4), - ahd_inl(ahd, SHADDR), - (ahd_inb(ahd, SHCNT) - | (ahd_inb(ahd, SHCNT + 1) << 8) - | (ahd_inb(ahd, SHCNT + 2) << 16))); - if (cur_col > 50) { - printk("\n"); - cur_col = 0; - } - cur_col += printk("HADDR = 0x%x%x, HCNT = 0x%x ", - ahd_inl(ahd, HADDR+4), - ahd_inl(ahd, HADDR), - (ahd_inb(ahd, HCNT) - | (ahd_inb(ahd, HCNT + 1) << 8) - | (ahd_inb(ahd, HCNT + 2) << 16))); - ahd_ccsgctl_print(ahd_inb(ahd, CCSGCTL), &cur_col, 50); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_SG) != 0) { - fifo_scb = ahd_lookup_scb(ahd, fifo_scbptr); - if (fifo_scb != NULL) - ahd_dump_sglist(fifo_scb); - } -#endif - } - printk("\nLQIN: "); - for (i = 0; i < 20; i++) - printk("0x%x ", ahd_inb(ahd, LQIN + i)); - printk("\n"); - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - printk("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n", - ahd_name(ahd), ahd_inb(ahd, LQISTATE), ahd_inb(ahd, LQOSTATE), - ahd_inb(ahd, OPTIONMODE)); - printk("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n", - ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT), - ahd_inb(ahd, MAXCMDCNT)); - printk("%s: SAVED_SCSIID = 0x%x SAVED_LUN = 0x%x\n", - ahd_name(ahd), ahd_inb(ahd, SAVED_SCSIID), - ahd_inb(ahd, SAVED_LUN)); - ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50); - printk("\n"); - ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN); - cur_col = 0; - ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50); - printk("\n"); - ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode); - printk("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n", - ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX), - ahd_inw(ahd, DINDEX)); - printk("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n", - ahd_name(ahd), ahd_get_scbptr(ahd), - ahd_inw_scbram(ahd, SCB_NEXT), - ahd_inw_scbram(ahd, SCB_NEXT2)); - printk("CDB %x %x %x %x %x %x\n", - ahd_inb_scbram(ahd, SCB_CDB_STORE), - ahd_inb_scbram(ahd, SCB_CDB_STORE+1), - ahd_inb_scbram(ahd, SCB_CDB_STORE+2), - ahd_inb_scbram(ahd, SCB_CDB_STORE+3), - ahd_inb_scbram(ahd, SCB_CDB_STORE+4), - ahd_inb_scbram(ahd, SCB_CDB_STORE+5)); - printk("STACK:"); - for (i = 0; i < ahd->stack_size; i++) { - ahd->saved_stack[i] = - ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8); - printk(" 0x%x", ahd->saved_stack[i]); - } - for (i = ahd->stack_size-1; i >= 0; i--) { - ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF); - ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF); - } - printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); - ahd_restore_modes(ahd, saved_modes); - if (paused == 0) - ahd_unpause(ahd); -} - -#if 0 -void -ahd_dump_scbs(struct ahd_softc *ahd) -{ - ahd_mode_state saved_modes; - u_int saved_scb_index; - int i; - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - saved_scb_index = ahd_get_scbptr(ahd); - for (i = 0; i < AHD_SCB_MAX; i++) { - ahd_set_scbptr(ahd, i); - printk("%3d", i); - printk("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n", - ahd_inb_scbram(ahd, SCB_CONTROL), - ahd_inb_scbram(ahd, SCB_SCSIID), - ahd_inw_scbram(ahd, SCB_NEXT), - ahd_inw_scbram(ahd, SCB_NEXT2), - ahd_inl_scbram(ahd, SCB_SGPTR), - ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR)); - } - printk("\n"); - ahd_set_scbptr(ahd, saved_scb_index); - ahd_restore_modes(ahd, saved_modes); -} -#endif /* 0 */ - -/**************************** Flexport Logic **********************************/ -/* - * Read count 16bit words from 16bit word address start_addr from the - * SEEPROM attached to the controller, into buf, using the controller's - * SEEPROM reading state machine. Optionally treat the data as a byte - * stream in terms of byte order. - */ -int -ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf, - u_int start_addr, u_int count, int bytestream) -{ - u_int cur_addr; - u_int end_addr; - int error; - - /* - * If we never make it through the loop even once, - * we were passed invalid arguments. - */ - error = EINVAL; - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - end_addr = start_addr + count; - for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) { - - ahd_outb(ahd, SEEADR, cur_addr); - ahd_outb(ahd, SEECTL, SEEOP_READ | SEESTART); - - error = ahd_wait_seeprom(ahd); - if (error) - break; - if (bytestream != 0) { - uint8_t *bytestream_ptr; - - bytestream_ptr = (uint8_t *)buf; - *bytestream_ptr++ = ahd_inb(ahd, SEEDAT); - *bytestream_ptr = ahd_inb(ahd, SEEDAT+1); - } else { - /* - * ahd_inw() already handles machine byte order. - */ - *buf = ahd_inw(ahd, SEEDAT); - } - buf++; - } - return (error); -} - -/* - * Write count 16bit words from buf, into SEEPROM attache to the - * controller starting at 16bit word address start_addr, using the - * controller's SEEPROM writing state machine. - */ -int -ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf, - u_int start_addr, u_int count) -{ - u_int cur_addr; - u_int end_addr; - int error; - int retval; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - error = ENOENT; - - /* Place the chip into write-enable mode */ - ahd_outb(ahd, SEEADR, SEEOP_EWEN_ADDR); - ahd_outb(ahd, SEECTL, SEEOP_EWEN | SEESTART); - error = ahd_wait_seeprom(ahd); - if (error) - return (error); - - /* - * Write the data. If we don't get through the loop at - * least once, the arguments were invalid. - */ - retval = EINVAL; - end_addr = start_addr + count; - for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) { - ahd_outw(ahd, SEEDAT, *buf++); - ahd_outb(ahd, SEEADR, cur_addr); - ahd_outb(ahd, SEECTL, SEEOP_WRITE | SEESTART); - - retval = ahd_wait_seeprom(ahd); - if (retval) - break; - } - - /* - * Disable writes. - */ - ahd_outb(ahd, SEEADR, SEEOP_EWDS_ADDR); - ahd_outb(ahd, SEECTL, SEEOP_EWDS | SEESTART); - error = ahd_wait_seeprom(ahd); - if (error) - return (error); - return (retval); -} - -/* - * Wait ~100us for the serial eeprom to satisfy our request. - */ -static int -ahd_wait_seeprom(struct ahd_softc *ahd) -{ - int cnt; - - cnt = 5000; - while ((ahd_inb(ahd, SEESTAT) & (SEEARBACK|SEEBUSY)) != 0 && --cnt) - ahd_delay(5); - - if (cnt == 0) - return (ETIMEDOUT); - return (0); -} - -/* - * Validate the two checksums in the per_channel - * vital product data struct. - */ -static int -ahd_verify_vpd_cksum(struct vpd_config *vpd) -{ - int i; - int maxaddr; - uint32_t checksum; - uint8_t *vpdarray; - - vpdarray = (uint8_t *)vpd; - maxaddr = offsetof(struct vpd_config, vpd_checksum); - checksum = 0; - for (i = offsetof(struct vpd_config, resource_type); i < maxaddr; i++) - checksum = checksum + vpdarray[i]; - if (checksum == 0 - || (-checksum & 0xFF) != vpd->vpd_checksum) - return (0); - - checksum = 0; - maxaddr = offsetof(struct vpd_config, checksum); - for (i = offsetof(struct vpd_config, default_target_flags); - i < maxaddr; i++) - checksum = checksum + vpdarray[i]; - if (checksum == 0 - || (-checksum & 0xFF) != vpd->checksum) - return (0); - return (1); -} - -int -ahd_verify_cksum(struct seeprom_config *sc) -{ - int i; - int maxaddr; - uint32_t checksum; - uint16_t *scarray; - - maxaddr = (sizeof(*sc)/2) - 1; - checksum = 0; - scarray = (uint16_t *)sc; - - for (i = 0; i < maxaddr; i++) - checksum = checksum + scarray[i]; - if (checksum == 0 - || (checksum & 0xFFFF) != sc->checksum) { - return (0); - } else { - return (1); - } -} - -int -ahd_acquire_seeprom(struct ahd_softc *ahd) -{ - /* - * We should be able to determine the SEEPROM type - * from the flexport logic, but unfortunately not - * all implementations have this logic and there is - * no programatic method for determining if the logic - * is present. - */ - return (1); -#if 0 - uint8_t seetype; - int error; - - error = ahd_read_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, &seetype); - if (error != 0 - || ((seetype & FLX_ROMSTAT_SEECFG) == FLX_ROMSTAT_SEE_NONE)) - return (0); - return (1); -#endif -} - -void -ahd_release_seeprom(struct ahd_softc *ahd) -{ - /* Currently a no-op */ -} - -/* - * Wait at most 2 seconds for flexport arbitration to succeed. - */ -static int -ahd_wait_flexport(struct ahd_softc *ahd) -{ - int cnt; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - cnt = 1000000 * 2 / 5; - while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt) - ahd_delay(5); - - if (cnt == 0) - return (ETIMEDOUT); - return (0); -} - -int -ahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value) -{ - int error; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - if (addr > 7) - panic("ahd_write_flexport: address out of range"); - ahd_outb(ahd, BRDCTL, BRDEN|(addr << 3)); - error = ahd_wait_flexport(ahd); - if (error != 0) - return (error); - ahd_outb(ahd, BRDDAT, value); - ahd_flush_device_writes(ahd); - ahd_outb(ahd, BRDCTL, BRDSTB|BRDEN|(addr << 3)); - ahd_flush_device_writes(ahd); - ahd_outb(ahd, BRDCTL, BRDEN|(addr << 3)); - ahd_flush_device_writes(ahd); - ahd_outb(ahd, BRDCTL, 0); - ahd_flush_device_writes(ahd); - return (0); -} - -int -ahd_read_flexport(struct ahd_softc *ahd, u_int addr, uint8_t *value) -{ - int error; - - AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); - if (addr > 7) - panic("ahd_read_flexport: address out of range"); - ahd_outb(ahd, BRDCTL, BRDRW|BRDEN|(addr << 3)); - error = ahd_wait_flexport(ahd); - if (error != 0) - return (error); - *value = ahd_inb(ahd, BRDDAT); - ahd_outb(ahd, BRDCTL, 0); - ahd_flush_device_writes(ahd); - return (0); -} - -/************************* Target Mode ****************************************/ -#ifdef AHD_TARGET_MODE -cam_status -ahd_find_tmode_devs(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb, - struct ahd_tmode_tstate **tstate, - struct ahd_tmode_lstate **lstate, - int notfound_failure) -{ - - if ((ahd->features & AHD_TARGETMODE) == 0) - return (CAM_REQ_INVALID); - - /* - * Handle the 'black hole' device that sucks up - * requests to unattached luns on enabled targets. - */ - if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD - && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { - *tstate = NULL; - *lstate = ahd->black_hole; - } else { - u_int max_id; - - max_id = (ahd->features & AHD_WIDE) ? 16 : 8; - if (ccb->ccb_h.target_id >= max_id) - return (CAM_TID_INVALID); - - if (ccb->ccb_h.target_lun >= AHD_NUM_LUNS) - return (CAM_LUN_INVALID); - - *tstate = ahd->enabled_targets[ccb->ccb_h.target_id]; - *lstate = NULL; - if (*tstate != NULL) - *lstate = - (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; - } - - if (notfound_failure != 0 && *lstate == NULL) - return (CAM_PATH_INVALID); - - return (CAM_REQ_CMP); -} - -void -ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb) -{ -#if NOT_YET - struct ahd_tmode_tstate *tstate; - struct ahd_tmode_lstate *lstate; - struct ccb_en_lun *cel; - cam_status status; - u_int target; - u_int lun; - u_int target_mask; - u_long s; - char channel; - - status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, &lstate, - /*notfound_failure*/FALSE); - - if (status != CAM_REQ_CMP) { - ccb->ccb_h.status = status; - return; - } - - if ((ahd->features & AHD_MULTIROLE) != 0) { - u_int our_id; - - our_id = ahd->our_id; - if (ccb->ccb_h.target_id != our_id) { - if ((ahd->features & AHD_MULTI_TID) != 0 - && (ahd->flags & AHD_INITIATORROLE) != 0) { - /* - * Only allow additional targets if - * the initiator role is disabled. - * The hardware cannot handle a re-select-in - * on the initiator id during a re-select-out - * on a different target id. - */ - status = CAM_TID_INVALID; - } else if ((ahd->flags & AHD_INITIATORROLE) != 0 - || ahd->enabled_luns > 0) { - /* - * Only allow our target id to change - * if the initiator role is not configured - * and there are no enabled luns which - * are attached to the currently registered - * scsi id. - */ - status = CAM_TID_INVALID; - } - } - } - - if (status != CAM_REQ_CMP) { - ccb->ccb_h.status = status; - return; - } - - /* - * We now have an id that is valid. - * If we aren't in target mode, switch modes. - */ - if ((ahd->flags & AHD_TARGETROLE) == 0 - && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { - u_long s; - - printk("Configuring Target Mode\n"); - ahd_lock(ahd, &s); - if (LIST_FIRST(&ahd->pending_scbs) != NULL) { - ccb->ccb_h.status = CAM_BUSY; - ahd_unlock(ahd, &s); - return; - } - ahd->flags |= AHD_TARGETROLE; - if ((ahd->features & AHD_MULTIROLE) == 0) - ahd->flags &= ~AHD_INITIATORROLE; - ahd_pause(ahd); - ahd_loadseq(ahd); - ahd_restart(ahd); - ahd_unlock(ahd, &s); - } - cel = &ccb->cel; - target = ccb->ccb_h.target_id; - lun = ccb->ccb_h.target_lun; - channel = SIM_CHANNEL(ahd, sim); - target_mask = 0x01 << target; - if (channel == 'B') - target_mask <<= 8; - - if (cel->enable != 0) { - u_int scsiseq1; - - /* Are we already enabled?? */ - if (lstate != NULL) { - xpt_print_path(ccb->ccb_h.path); - printk("Lun already enabled\n"); - ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; - return; - } - - if (cel->grp6_len != 0 - || cel->grp7_len != 0) { - /* - * Don't (yet?) support vendor - * specific commands. - */ - ccb->ccb_h.status = CAM_REQ_INVALID; - printk("Non-zero Group Codes\n"); - return; - } - - /* - * Seems to be okay. - * Setup our data structures. - */ - if (target != CAM_TARGET_WILDCARD && tstate == NULL) { - tstate = ahd_alloc_tstate(ahd, target, channel); - if (tstate == NULL) { - xpt_print_path(ccb->ccb_h.path); - printk("Couldn't allocate tstate\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - } - lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC); - if (lstate == NULL) { - xpt_print_path(ccb->ccb_h.path); - printk("Couldn't allocate lstate\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - memset(lstate, 0, sizeof(*lstate)); - status = xpt_create_path(&lstate->path, /*periph*/NULL, - xpt_path_path_id(ccb->ccb_h.path), - xpt_path_target_id(ccb->ccb_h.path), - xpt_path_lun_id(ccb->ccb_h.path)); - if (status != CAM_REQ_CMP) { - kfree(lstate); - xpt_print_path(ccb->ccb_h.path); - printk("Couldn't allocate path\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - SLIST_INIT(&lstate->accept_tios); - SLIST_INIT(&lstate->immed_notifies); - ahd_lock(ahd, &s); - ahd_pause(ahd); - if (target != CAM_TARGET_WILDCARD) { - tstate->enabled_luns[lun] = lstate; - ahd->enabled_luns++; - - if ((ahd->features & AHD_MULTI_TID) != 0) { - u_int targid_mask; - - targid_mask = ahd_inw(ahd, TARGID); - targid_mask |= target_mask; - ahd_outw(ahd, TARGID, targid_mask); - ahd_update_scsiid(ahd, targid_mask); - } else { - u_int our_id; - char channel; - - channel = SIM_CHANNEL(ahd, sim); - our_id = SIM_SCSI_ID(ahd, sim); - - /* - * This can only happen if selections - * are not enabled - */ - if (target != our_id) { - u_int sblkctl; - char cur_channel; - int swap; - - sblkctl = ahd_inb(ahd, SBLKCTL); - cur_channel = (sblkctl & SELBUSB) - ? 'B' : 'A'; - if ((ahd->features & AHD_TWIN) == 0) - cur_channel = 'A'; - swap = cur_channel != channel; - ahd->our_id = target; - - if (swap) - ahd_outb(ahd, SBLKCTL, - sblkctl ^ SELBUSB); - - ahd_outb(ahd, SCSIID, target); - - if (swap) - ahd_outb(ahd, SBLKCTL, sblkctl); - } - } - } else - ahd->black_hole = lstate; - /* Allow select-in operations */ - if (ahd->black_hole != NULL && ahd->enabled_luns > 0) { - scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); - scsiseq1 |= ENSELI; - ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1); - scsiseq1 = ahd_inb(ahd, SCSISEQ1); - scsiseq1 |= ENSELI; - ahd_outb(ahd, SCSISEQ1, scsiseq1); - } - ahd_unpause(ahd); - ahd_unlock(ahd, &s); - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_print_path(ccb->ccb_h.path); - printk("Lun now enabled for target mode\n"); - } else { - struct scb *scb; - int i, empty; - - if (lstate == NULL) { - ccb->ccb_h.status = CAM_LUN_INVALID; - return; - } - - ahd_lock(ahd, &s); - - ccb->ccb_h.status = CAM_REQ_CMP; - LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) { - struct ccb_hdr *ccbh; - - ccbh = &scb->io_ctx->ccb_h; - if (ccbh->func_code == XPT_CONT_TARGET_IO - && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ - printk("CTIO pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - ahd_unlock(ahd, &s); - return; - } - } - - if (SLIST_FIRST(&lstate->accept_tios) != NULL) { - printk("ATIOs pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - } - - if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { - printk("INOTs pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - } - - if (ccb->ccb_h.status != CAM_REQ_CMP) { - ahd_unlock(ahd, &s); - return; - } - - xpt_print_path(ccb->ccb_h.path); - printk("Target mode disabled\n"); - xpt_free_path(lstate->path); - kfree(lstate); - - ahd_pause(ahd); - /* Can we clean up the target too? */ - if (target != CAM_TARGET_WILDCARD) { - tstate->enabled_luns[lun] = NULL; - ahd->enabled_luns--; - for (empty = 1, i = 0; i < 8; i++) - if (tstate->enabled_luns[i] != NULL) { - empty = 0; - break; - } - - if (empty) { - ahd_free_tstate(ahd, target, channel, - /*force*/FALSE); - if (ahd->features & AHD_MULTI_TID) { - u_int targid_mask; - - targid_mask = ahd_inw(ahd, TARGID); - targid_mask &= ~target_mask; - ahd_outw(ahd, TARGID, targid_mask); - ahd_update_scsiid(ahd, targid_mask); - } - } - } else { - - ahd->black_hole = NULL; - - /* - * We can't allow selections without - * our black hole device. - */ - empty = TRUE; - } - if (ahd->enabled_luns == 0) { - /* Disallow select-in */ - u_int scsiseq1; - - scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE); - scsiseq1 &= ~ENSELI; - ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1); - scsiseq1 = ahd_inb(ahd, SCSISEQ1); - scsiseq1 &= ~ENSELI; - ahd_outb(ahd, SCSISEQ1, scsiseq1); - - if ((ahd->features & AHD_MULTIROLE) == 0) { - printk("Configuring Initiator Mode\n"); - ahd->flags &= ~AHD_TARGETROLE; - ahd->flags |= AHD_INITIATORROLE; - ahd_pause(ahd); - ahd_loadseq(ahd); - ahd_restart(ahd); - /* - * Unpaused. The extra unpause - * that follows is harmless. - */ - } - } - ahd_unpause(ahd); - ahd_unlock(ahd, &s); - } -#endif -} - -static void -ahd_update_scsiid(struct ahd_softc *ahd, u_int targid_mask) -{ -#if NOT_YET - u_int scsiid_mask; - u_int scsiid; - - if ((ahd->features & AHD_MULTI_TID) == 0) - panic("ahd_update_scsiid called on non-multitid unit\n"); - - /* - * Since we will rely on the TARGID mask - * for selection enables, ensure that OID - * in SCSIID is not set to some other ID - * that we don't want to allow selections on. - */ - if ((ahd->features & AHD_ULTRA2) != 0) - scsiid = ahd_inb(ahd, SCSIID_ULTRA2); - else - scsiid = ahd_inb(ahd, SCSIID); - scsiid_mask = 0x1 << (scsiid & OID); - if ((targid_mask & scsiid_mask) == 0) { - u_int our_id; - - /* ffs counts from 1 */ - our_id = ffs(targid_mask); - if (our_id == 0) - our_id = ahd->our_id; - else - our_id--; - scsiid &= TID; - scsiid |= our_id; - } - if ((ahd->features & AHD_ULTRA2) != 0) - ahd_outb(ahd, SCSIID_ULTRA2, scsiid); - else - ahd_outb(ahd, SCSIID, scsiid); -#endif -} - -static void -ahd_run_tqinfifo(struct ahd_softc *ahd, int paused) -{ - struct target_cmd *cmd; - - ahd_sync_tqinfifo(ahd, BUS_DMASYNC_POSTREAD); - while ((cmd = &ahd->targetcmds[ahd->tqinfifonext])->cmd_valid != 0) { - - /* - * Only advance through the queue if we - * have the resources to process the command. - */ - if (ahd_handle_target_cmd(ahd, cmd) != 0) - break; - - cmd->cmd_valid = 0; - ahd_dmamap_sync(ahd, ahd->shared_data_dmat, - ahd->shared_data_map.dmamap, - ahd_targetcmd_offset(ahd, ahd->tqinfifonext), - sizeof(struct target_cmd), - BUS_DMASYNC_PREREAD); - ahd->tqinfifonext++; - - /* - * Lazily update our position in the target mode incoming - * command queue as seen by the sequencer. - */ - if ((ahd->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { - u_int hs_mailbox; - - hs_mailbox = ahd_inb(ahd, HS_MAILBOX); - hs_mailbox &= ~HOST_TQINPOS; - hs_mailbox |= ahd->tqinfifonext & HOST_TQINPOS; - ahd_outb(ahd, HS_MAILBOX, hs_mailbox); - } - } -} - -static int -ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd) -{ - struct ahd_tmode_tstate *tstate; - struct ahd_tmode_lstate *lstate; - struct ccb_accept_tio *atio; - uint8_t *byte; - int initiator; - int target; - int lun; - - initiator = SCSIID_TARGET(ahd, cmd->scsiid); - target = SCSIID_OUR_ID(cmd->scsiid); - lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); - - byte = cmd->bytes; - tstate = ahd->enabled_targets[target]; - lstate = NULL; - if (tstate != NULL) - lstate = tstate->enabled_luns[lun]; - - /* - * Commands for disabled luns go to the black hole driver. - */ - if (lstate == NULL) - lstate = ahd->black_hole; - - atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); - if (atio == NULL) { - ahd->flags |= AHD_TQINFIFO_BLOCKED; - /* - * Wait for more ATIOs from the peripheral driver for this lun. - */ - return (1); - } else - ahd->flags &= ~AHD_TQINFIFO_BLOCKED; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_TQIN) != 0) - printk("Incoming command from %d for %d:%d%s\n", - initiator, target, lun, - lstate == ahd->black_hole ? "(Black Holed)" : ""); -#endif - SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); - - if (lstate == ahd->black_hole) { - /* Fill in the wildcards */ - atio->ccb_h.target_id = target; - atio->ccb_h.target_lun = lun; - } - - /* - * Package it up and send it off to - * whomever has this lun enabled. - */ - atio->sense_len = 0; - atio->init_id = initiator; - if (byte[0] != 0xFF) { - /* Tag was included */ - atio->tag_action = *byte++; - atio->tag_id = *byte++; - atio->ccb_h.flags = CAM_TAG_ACTION_VALID; - } else { - atio->ccb_h.flags = 0; - } - byte++; - - /* Okay. Now determine the cdb size based on the command code */ - switch (*byte >> CMD_GROUP_CODE_SHIFT) { - case 0: - atio->cdb_len = 6; - break; - case 1: - case 2: - atio->cdb_len = 10; - break; - case 4: - atio->cdb_len = 16; - break; - case 5: - atio->cdb_len = 12; - break; - case 3: - default: - /* Only copy the opcode. */ - atio->cdb_len = 1; - printk("Reserved or VU command code type encountered\n"); - break; - } - - memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len); - - atio->ccb_h.status |= CAM_CDB_RECVD; - - if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) { - /* - * We weren't allowed to disconnect. - * We're hanging on the bus until a - * continue target I/O comes in response - * to this accept tio. - */ -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_TQIN) != 0) - printk("Received Immediate Command %d:%d:%d - %p\n", - initiator, target, lun, ahd->pending_device); -#endif - ahd->pending_device = lstate; - ahd_freeze_ccb((union ccb *)atio); - atio->ccb_h.flags |= CAM_DIS_DISCONNECT; - } - xpt_done((union ccb*)atio); - return (0); -} - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_inline.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_inline.h deleted file mode 100644 index 09335a3c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_inline.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Inline routines shareable across OS platforms. - * - * Copyright (c) 1994-2001 Justin T. Gibbs. - * Copyright (c) 2000-2003 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#59 $ - * - * $FreeBSD$ - */ - -#ifndef _AIC79XX_INLINE_H_ -#define _AIC79XX_INLINE_H_ - -/******************************** Debugging ***********************************/ -static inline char *ahd_name(struct ahd_softc *ahd); - -static inline char *ahd_name(struct ahd_softc *ahd) -{ - return (ahd->name); -} - -/************************ Sequencer Execution Control *************************/ -static inline void ahd_known_modes(struct ahd_softc *ahd, - ahd_mode src, ahd_mode dst); -static inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd, - ahd_mode src, - ahd_mode dst); -static inline void ahd_extract_mode_state(struct ahd_softc *ahd, - ahd_mode_state state, - ahd_mode *src, ahd_mode *dst); - -void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, - ahd_mode dst); -ahd_mode_state ahd_save_modes(struct ahd_softc *ahd); -void ahd_restore_modes(struct ahd_softc *ahd, - ahd_mode_state state); -int ahd_is_paused(struct ahd_softc *ahd); -void ahd_pause(struct ahd_softc *ahd); -void ahd_unpause(struct ahd_softc *ahd); - -static inline void -ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) -{ - ahd->src_mode = src; - ahd->dst_mode = dst; - ahd->saved_src_mode = src; - ahd->saved_dst_mode = dst; -} - -static inline ahd_mode_state -ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst) -{ - return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT)); -} - -static inline void -ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state, - ahd_mode *src, ahd_mode *dst) -{ - *src = (state & SRC_MODE) >> SRC_MODE_SHIFT; - *dst = (state & DST_MODE) >> DST_MODE_SHIFT; -} - -/*********************** Scatter Gather List Handling *************************/ -void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb, - void *sgptr, dma_addr_t addr, - bus_size_t len, int last); - -/************************** Memory mapping routines ***************************/ -static inline size_t ahd_sg_size(struct ahd_softc *ahd); - -void ahd_sync_sglist(struct ahd_softc *ahd, - struct scb *scb, int op); - -static inline size_t ahd_sg_size(struct ahd_softc *ahd) -{ - if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) - return (sizeof(struct ahd_dma64_seg)); - return (sizeof(struct ahd_dma_seg)); -} - -/*********************** Miscellaneous Support Functions ***********************/ -struct ahd_initiator_tinfo * - ahd_fetch_transinfo(struct ahd_softc *ahd, - char channel, u_int our_id, - u_int remote_id, - struct ahd_tmode_tstate **tstate); -uint16_t - ahd_inw(struct ahd_softc *ahd, u_int port); -void ahd_outw(struct ahd_softc *ahd, u_int port, - u_int value); -uint32_t - ahd_inl(struct ahd_softc *ahd, u_int port); -void ahd_outl(struct ahd_softc *ahd, u_int port, - uint32_t value); -uint64_t - ahd_inq(struct ahd_softc *ahd, u_int port); -void ahd_outq(struct ahd_softc *ahd, u_int port, - uint64_t value); -u_int ahd_get_scbptr(struct ahd_softc *ahd); -void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr); -u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset); -u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset); -struct scb * - ahd_lookup_scb(struct ahd_softc *ahd, u_int tag); -void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb); - -static inline uint8_t *ahd_get_sense_buf(struct ahd_softc *ahd, - struct scb *scb); -static inline uint32_t ahd_get_sense_bufaddr(struct ahd_softc *ahd, - struct scb *scb); - -#if 0 /* unused */ - -#define AHD_COPY_COL_IDX(dst, src) \ -do { \ - dst->hscb->scsiid = src->hscb->scsiid; \ - dst->hscb->lun = src->hscb->lun; \ -} while (0) - -#endif - -static inline uint8_t * -ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb) -{ - return (scb->sense_data); -} - -static inline uint32_t -ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb) -{ - return (scb->sense_busaddr); -} - -/************************** Interrupt Processing ******************************/ -int ahd_intr(struct ahd_softc *ahd); - -#endif /* _AIC79XX_INLINE_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.c deleted file mode 100644 index 93281218..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.c +++ /dev/null @@ -1,2903 +0,0 @@ -/* - * Adaptec AIC79xx device driver for Linux. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#171 $ - * - * -------------------------------------------------------------------------- - * Copyright (c) 1994-2000 Justin T. Gibbs. - * Copyright (c) 1997-1999 Doug Ledford - * Copyright (c) 2000-2003 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#include "aic79xx_osm.h" -#include "aic79xx_inline.h" -#include - -static struct scsi_transport_template *ahd_linux_transport_template = NULL; - -#include /* __setup */ -#include /* For fetching system memory size */ -#include /* For block_size() */ -#include /* For ssleep/msleep */ -#include -#include - -/* - * Bucket size for counting good commands in between bad ones. - */ -#define AHD_LINUX_ERR_THRESH 1000 - -/* - * Set this to the delay in seconds after SCSI bus reset. - * Note, we honor this only for the initial bus reset. - * The scsi error recovery code performs its own bus settle - * delay handling for error recovery actions. - */ -#ifdef CONFIG_AIC79XX_RESET_DELAY_MS -#define AIC79XX_RESET_DELAY CONFIG_AIC79XX_RESET_DELAY_MS -#else -#define AIC79XX_RESET_DELAY 5000 -#endif - -/* - * To change the default number of tagged transactions allowed per-device, - * add a line to the lilo.conf file like: - * append="aic79xx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}" - * which will result in the first four devices on the first two - * controllers being set to a tagged queue depth of 32. - * - * The tag_commands is an array of 16 to allow for wide and twin adapters. - * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15 - * for channel 1. - */ -typedef struct { - uint16_t tag_commands[16]; /* Allow for wide/twin adapters. */ -} adapter_tag_info_t; - -/* - * Modify this as you see fit for your system. - * - * 0 tagged queuing disabled - * 1 <= n <= 253 n == max tags ever dispatched. - * - * The driver will throttle the number of commands dispatched to a - * device if it returns queue full. For devices with a fixed maximum - * queue depth, the driver will eventually determine this depth and - * lock it in (a console message is printed to indicate that a lock - * has occurred). On some devices, queue full is returned for a temporary - * resource shortage. These devices will return queue full at varying - * depths. The driver will throttle back when the queue fulls occur and - * attempt to slowly increase the depth over time as the device recovers - * from the resource shortage. - * - * In this example, the first line will disable tagged queueing for all - * the devices on the first probed aic79xx adapter. - * - * The second line enables tagged queueing with 4 commands/LUN for IDs - * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the - * driver to attempt to use up to 64 tags for ID 1. - * - * The third line is the same as the first line. - * - * The fourth line disables tagged queueing for devices 0 and 3. It - * enables tagged queueing for the other IDs, with 16 commands/LUN - * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for - * IDs 2, 5-7, and 9-15. - */ - -/* - * NOTE: The below structure is for reference only, the actual structure - * to modify in order to change things is just below this comment block. -adapter_tag_info_t aic79xx_tag_info[] = -{ - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, - {{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, - {{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} -}; -*/ - -#ifdef CONFIG_AIC79XX_CMDS_PER_DEVICE -#define AIC79XX_CMDS_PER_DEVICE CONFIG_AIC79XX_CMDS_PER_DEVICE -#else -#define AIC79XX_CMDS_PER_DEVICE AHD_MAX_QUEUE -#endif - -#define AIC79XX_CONFIGED_TAG_COMMANDS { \ - AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE, \ - AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE, \ - AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE, \ - AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE, \ - AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE, \ - AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE, \ - AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE, \ - AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE \ -} - -/* - * By default, use the number of commands specified by - * the users kernel configuration. - */ -static adapter_tag_info_t aic79xx_tag_info[] = -{ - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS}, - {AIC79XX_CONFIGED_TAG_COMMANDS} -}; - -/* - * The I/O cell on the chip is very configurable in respect to its analog - * characteristics. Set the defaults here; they can be overriden with - * the proper insmod parameters. - */ -struct ahd_linux_iocell_opts -{ - uint8_t precomp; - uint8_t slewrate; - uint8_t amplitude; -}; -#define AIC79XX_DEFAULT_PRECOMP 0xFF -#define AIC79XX_DEFAULT_SLEWRATE 0xFF -#define AIC79XX_DEFAULT_AMPLITUDE 0xFF -#define AIC79XX_DEFAULT_IOOPTS \ -{ \ - AIC79XX_DEFAULT_PRECOMP, \ - AIC79XX_DEFAULT_SLEWRATE, \ - AIC79XX_DEFAULT_AMPLITUDE \ -} -#define AIC79XX_PRECOMP_INDEX 0 -#define AIC79XX_SLEWRATE_INDEX 1 -#define AIC79XX_AMPLITUDE_INDEX 2 -static const struct ahd_linux_iocell_opts aic79xx_iocell_info[] = -{ - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS, - AIC79XX_DEFAULT_IOOPTS -}; - -/* - * There should be a specific return value for this in scsi.h, but - * it seems that most drivers ignore it. - */ -#define DID_UNDERFLOW DID_ERROR - -void -ahd_print_path(struct ahd_softc *ahd, struct scb *scb) -{ - printk("(scsi%d:%c:%d:%d): ", - ahd->platform_data->host->host_no, - scb != NULL ? SCB_GET_CHANNEL(ahd, scb) : 'X', - scb != NULL ? SCB_GET_TARGET(ahd, scb) : -1, - scb != NULL ? SCB_GET_LUN(scb) : -1); -} - -/* - * XXX - these options apply unilaterally to _all_ adapters - * cards in the system. This should be fixed. Exceptions to this - * rule are noted in the comments. - */ - -/* - * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This - * has no effect on any later resets that might occur due to things like - * SCSI bus timeouts. - */ -static uint32_t aic79xx_no_reset; - -/* - * Should we force EXTENDED translation on a controller. - * 0 == Use whatever is in the SEEPROM or default to off - * 1 == Use whatever is in the SEEPROM or default to on - */ -static uint32_t aic79xx_extended; - -/* - * PCI bus parity checking of the Adaptec controllers. This is somewhat - * dubious at best. To my knowledge, this option has never actually - * solved a PCI parity problem, but on certain machines with broken PCI - * chipset configurations, it can generate tons of false error messages. - * It's included in the driver for completeness. - * 0 = Shut off PCI parity check - * non-0 = Enable PCI parity check - * - * NOTE: you can't actually pass -1 on the lilo prompt. So, to set this - * variable to -1 you would actually want to simply pass the variable - * name without a number. That will invert the 0 which will result in - * -1. - */ -static uint32_t aic79xx_pci_parity = ~0; - -/* - * There are lots of broken chipsets in the world. Some of them will - * violate the PCI spec when we issue byte sized memory writes to our - * controller. I/O mapped register access, if allowed by the given - * platform, will work in almost all cases. - */ -uint32_t aic79xx_allow_memio = ~0; - -/* - * So that we can set how long each device is given as a selection timeout. - * The table of values goes like this: - * 0 - 256ms - * 1 - 128ms - * 2 - 64ms - * 3 - 32ms - * We default to 256ms because some older devices need a longer time - * to respond to initial selection. - */ -static uint32_t aic79xx_seltime; - -/* - * Certain devices do not perform any aging on commands. Should the - * device be saturated by commands in one portion of the disk, it is - * possible for transactions on far away sectors to never be serviced. - * To handle these devices, we can periodically send an ordered tag to - * force all outstanding transactions to be serviced prior to a new - * transaction. - */ -static uint32_t aic79xx_periodic_otag; - -/* Some storage boxes are using an LSI chip which has a bug making it - * impossible to use aic79xx Rev B chip in 320 speeds. The following - * storage boxes have been reported to be buggy: - * EonStor 3U 16-Bay: U16U-G3A3 - * EonStor 2U 12-Bay: U12U-G3A3 - * SentinelRAID: 2500F R5 / R6 - * SentinelRAID: 2500F R1 - * SentinelRAID: 2500F/1500F - * SentinelRAID: 150F - * - * To get around this LSI bug, you can set your board to 160 mode - * or you can enable the SLOWCRC bit. - */ -uint32_t aic79xx_slowcrc; - -/* - * Module information and settable options. - */ -static char *aic79xx = NULL; - -MODULE_AUTHOR("Maintainer: Hannes Reinecke "); -MODULE_DESCRIPTION("Adaptec AIC790X U320 SCSI Host Bus Adapter driver"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(AIC79XX_DRIVER_VERSION); -module_param(aic79xx, charp, 0444); -MODULE_PARM_DESC(aic79xx, -"period-delimited options string:\n" -" verbose Enable verbose/diagnostic logging\n" -" allow_memio Allow device registers to be memory mapped\n" -" debug Bitmask of debug values to enable\n" -" no_reset Suppress initial bus resets\n" -" extended Enable extended geometry on all controllers\n" -" periodic_otag Send an ordered tagged transaction\n" -" periodically to prevent tag starvation.\n" -" This may be required by some older disk\n" -" or drives/RAID arrays.\n" -" tag_info: Set per-target tag depth\n" -" global_tag_depth: Global tag depth for all targets on all buses\n" -" slewrate:Set the signal slew rate (0-15).\n" -" precomp: Set the signal precompensation (0-7).\n" -" amplitude: Set the signal amplitude (0-7).\n" -" seltime: Selection Timeout:\n" -" (0/256ms,1/128ms,2/64ms,3/32ms)\n" -" slowcrc Turn on the SLOWCRC bit (Rev B only)\n" -"\n" -" Sample modprobe configuration file:\n" -" # Enable verbose logging\n" -" # Set tag depth on Controller 2/Target 2 to 10 tags\n" -" # Shorten the selection timeout to 128ms\n" -"\n" -" options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n" -); - -static void ahd_linux_handle_scsi_status(struct ahd_softc *, - struct scsi_device *, - struct scb *); -static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, - struct scsi_cmnd *cmd); -static int ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd); -static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); -static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_linux_device_queue_depth(struct scsi_device *); -static int ahd_linux_run_command(struct ahd_softc*, - struct ahd_linux_device *, - struct scsi_cmnd *); -static void ahd_linux_setup_tag_info_global(char *p); -static int aic79xx_setup(char *c); -static void ahd_freeze_simq(struct ahd_softc *ahd); -static void ahd_release_simq(struct ahd_softc *ahd); - -static int ahd_linux_unit; - - -/************************** OS Utility Wrappers *******************************/ -void ahd_delay(long); -void -ahd_delay(long usec) -{ - /* - * udelay on Linux can have problems for - * multi-millisecond waits. Wait at most - * 1024us per call. - */ - while (usec > 0) { - udelay(usec % 1024); - usec -= 1024; - } -} - - -/***************************** Low Level I/O **********************************/ -uint8_t ahd_inb(struct ahd_softc * ahd, long port); -void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val); -void ahd_outw_atomic(struct ahd_softc * ahd, - long port, uint16_t val); -void ahd_outsb(struct ahd_softc * ahd, long port, - uint8_t *, int count); -void ahd_insb(struct ahd_softc * ahd, long port, - uint8_t *, int count); - -uint8_t -ahd_inb(struct ahd_softc * ahd, long port) -{ - uint8_t x; - - if (ahd->tags[0] == BUS_SPACE_MEMIO) { - x = readb(ahd->bshs[0].maddr + port); - } else { - x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF)); - } - mb(); - return (x); -} - -#if 0 /* unused */ -static uint16_t -ahd_inw_atomic(struct ahd_softc * ahd, long port) -{ - uint8_t x; - - if (ahd->tags[0] == BUS_SPACE_MEMIO) { - x = readw(ahd->bshs[0].maddr + port); - } else { - x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF)); - } - mb(); - return (x); -} -#endif - -void -ahd_outb(struct ahd_softc * ahd, long port, uint8_t val) -{ - if (ahd->tags[0] == BUS_SPACE_MEMIO) { - writeb(val, ahd->bshs[0].maddr + port); - } else { - outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF)); - } - mb(); -} - -void -ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val) -{ - if (ahd->tags[0] == BUS_SPACE_MEMIO) { - writew(val, ahd->bshs[0].maddr + port); - } else { - outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF)); - } - mb(); -} - -void -ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count) -{ - int i; - - /* - * There is probably a more efficient way to do this on Linux - * but we don't use this for anything speed critical and this - * should work. - */ - for (i = 0; i < count; i++) - ahd_outb(ahd, port, *array++); -} - -void -ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count) -{ - int i; - - /* - * There is probably a more efficient way to do this on Linux - * but we don't use this for anything speed critical and this - * should work. - */ - for (i = 0; i < count; i++) - *array++ = ahd_inb(ahd, port); -} - -/******************************* PCI Routines *********************************/ -uint32_t -ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width) -{ - switch (width) { - case 1: - { - uint8_t retval; - - pci_read_config_byte(pci, reg, &retval); - return (retval); - } - case 2: - { - uint16_t retval; - pci_read_config_word(pci, reg, &retval); - return (retval); - } - case 4: - { - uint32_t retval; - pci_read_config_dword(pci, reg, &retval); - return (retval); - } - default: - panic("ahd_pci_read_config: Read size too big"); - /* NOTREACHED */ - return (0); - } -} - -void -ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width) -{ - switch (width) { - case 1: - pci_write_config_byte(pci, reg, value); - break; - case 2: - pci_write_config_word(pci, reg, value); - break; - case 4: - pci_write_config_dword(pci, reg, value); - break; - default: - panic("ahd_pci_write_config: Write size too big"); - /* NOTREACHED */ - } -} - -/****************************** Inlines ***************************************/ -static void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*); - -static void -ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) -{ - struct scsi_cmnd *cmd; - - cmd = scb->io_ctx; - ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE); - scsi_dma_unmap(cmd); -} - -/******************************** Macros **************************************/ -#define BUILD_SCSIID(ahd, cmd) \ - (((scmd_id(cmd) << TID_SHIFT) & TID) | (ahd)->our_id) - -/* - * Return a string describing the driver. - */ -static const char * -ahd_linux_info(struct Scsi_Host *host) -{ - static char buffer[512]; - char ahd_info[256]; - char *bp; - struct ahd_softc *ahd; - - bp = &buffer[0]; - ahd = *(struct ahd_softc **)host->hostdata; - memset(bp, 0, sizeof(buffer)); - strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev " AIC79XX_DRIVER_VERSION "\n" - " <"); - strcat(bp, ahd->description); - strcat(bp, ">\n" - " "); - ahd_controller_info(ahd, ahd_info); - strcat(bp, ahd_info); - - return (bp); -} - -/* - * Queue an SCB to the controller. - */ -static int -ahd_linux_queue_lck(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) -{ - struct ahd_softc *ahd; - struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); - int rtn = SCSI_MLQUEUE_HOST_BUSY; - - ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - - cmd->scsi_done = scsi_done; - cmd->result = CAM_REQ_INPROG << 16; - rtn = ahd_linux_run_command(ahd, dev, cmd); - - return rtn; -} - -static DEF_SCSI_QCMD(ahd_linux_queue) - -static struct scsi_target ** -ahd_linux_target_in_softc(struct scsi_target *starget) -{ - struct ahd_softc *ahd = - *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); - unsigned int target_offset; - - target_offset = starget->id; - if (starget->channel != 0) - target_offset += 8; - - return &ahd->platform_data->starget[target_offset]; -} - -static int -ahd_linux_target_alloc(struct scsi_target *starget) -{ - struct ahd_softc *ahd = - *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); - struct seeprom_config *sc = ahd->seep_config; - unsigned long flags; - struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - char channel = starget->channel + 'A'; - - ahd_lock(ahd, &flags); - - BUG_ON(*ahd_targp != NULL); - - *ahd_targp = starget; - - if (sc) { - int flags = sc->device_flags[starget->id]; - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - starget->id, &tstate); - - if ((flags & CFPACKETIZED) == 0) { - /* don't negotiate packetized (IU) transfers */ - spi_max_iu(starget) = 0; - } else { - if ((ahd->features & AHD_RTI) == 0) - spi_rti(starget) = 0; - } - - if ((flags & CFQAS) == 0) - spi_max_qas(starget) = 0; - - /* Transinfo values have been set to BIOS settings */ - spi_max_width(starget) = (flags & CFWIDEB) ? 1 : 0; - spi_min_period(starget) = tinfo->user.period; - spi_max_offset(starget) = tinfo->user.offset; - } - - tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, - starget->id, &tstate); - ahd_compile_devinfo(&devinfo, ahd->our_id, starget->id, - CAM_LUN_WILDCARD, channel, - ROLE_INITIATOR); - ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_unlock(ahd, &flags); - - return 0; -} - -static void -ahd_linux_target_destroy(struct scsi_target *starget) -{ - struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); - - *ahd_targp = NULL; -} - -static int -ahd_linux_slave_alloc(struct scsi_device *sdev) -{ - struct ahd_softc *ahd = - *((struct ahd_softc **)sdev->host->hostdata); - struct ahd_linux_device *dev; - - if (bootverbose) - printk("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id); - - dev = scsi_transport_device_data(sdev); - memset(dev, 0, sizeof(*dev)); - - /* - * We start out life using untagged - * transactions of which we allow one. - */ - dev->openings = 1; - - /* - * Set maxtags to 0. This will be changed if we - * later determine that we are dealing with - * a tagged queuing capable device. - */ - dev->maxtags = 0; - - return (0); -} - -static int -ahd_linux_slave_configure(struct scsi_device *sdev) -{ - struct ahd_softc *ahd; - - ahd = *((struct ahd_softc **)sdev->host->hostdata); - if (bootverbose) - sdev_printk(KERN_INFO, sdev, "Slave Configure\n"); - - ahd_linux_device_queue_depth(sdev); - - /* Initial Domain Validation */ - if (!spi_initial_dv(sdev->sdev_target)) - spi_dv_device(sdev); - - return 0; -} - -#if defined(__i386__) -/* - * Return the disk geometry for the given SCSI device. - */ -static int -ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - uint8_t *bh; - int heads; - int sectors; - int cylinders; - int ret; - int extended; - struct ahd_softc *ahd; - - ahd = *((struct ahd_softc **)sdev->host->hostdata); - - bh = scsi_bios_ptable(bdev); - if (bh) { - ret = scsi_partsize(bh, capacity, - &geom[2], &geom[0], &geom[1]); - kfree(bh); - if (ret != -1) - return (ret); - } - heads = 64; - sectors = 32; - cylinders = aic_sector_div(capacity, heads, sectors); - - if (aic79xx_extended != 0) - extended = 1; - else - extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 0; - if (extended && cylinders >= 1024) { - heads = 255; - sectors = 63; - cylinders = aic_sector_div(capacity, heads, sectors); - } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - return (0); -} -#endif - -/* - * Abort the current SCSI command(s). - */ -static int -ahd_linux_abort(struct scsi_cmnd *cmd) -{ - int error; - - error = ahd_linux_queue_abort_cmd(cmd); - - return error; -} - -/* - * Attempt to send a target reset message to the device that timed out. - */ -static int -ahd_linux_dev_reset(struct scsi_cmnd *cmd) -{ - struct ahd_softc *ahd; - struct ahd_linux_device *dev; - struct scb *reset_scb; - u_int cdb_byte; - int retval = SUCCESS; - int paused; - int wait; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - unsigned long flags; - DECLARE_COMPLETION_ONSTACK(done); - - reset_scb = NULL; - paused = FALSE; - wait = FALSE; - ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - - scmd_printk(KERN_INFO, cmd, - "Attempting to queue a TARGET RESET message:"); - - printk("CDB:"); - for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printk(" 0x%x", cmd->cmnd[cdb_byte]); - printk("\n"); - - /* - * Determine if we currently own this command. - */ - dev = scsi_transport_device_data(cmd->device); - - if (dev == NULL) { - /* - * No target device for this command exists, - * so we must not still own the command. - */ - scmd_printk(KERN_INFO, cmd, "Is not an active device\n"); - return SUCCESS; - } - - /* - * Generate us a new SCB - */ - reset_scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX); - if (!reset_scb) { - scmd_printk(KERN_INFO, cmd, "No SCB available\n"); - return FAILED; - } - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - cmd->device->id, &tstate); - reset_scb->io_ctx = cmd; - reset_scb->platform_data->dev = dev; - reset_scb->sg_count = 0; - ahd_set_residual(reset_scb, 0); - ahd_set_sense_residual(reset_scb, 0); - reset_scb->platform_data->xfer_len = 0; - reset_scb->hscb->control = 0; - reset_scb->hscb->scsiid = BUILD_SCSIID(ahd,cmd); - reset_scb->hscb->lun = cmd->device->lun; - reset_scb->hscb->cdb_len = 0; - reset_scb->hscb->task_management = SIU_TASKMGMT_LUN_RESET; - reset_scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE; - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - reset_scb->flags |= SCB_PACKETIZED; - } else { - reset_scb->hscb->control |= MK_MESSAGE; - } - dev->openings--; - dev->active++; - dev->commands_issued++; - - ahd_lock(ahd, &flags); - - LIST_INSERT_HEAD(&ahd->pending_scbs, reset_scb, pending_links); - ahd_queue_scb(ahd, reset_scb); - - ahd->platform_data->eh_done = &done; - ahd_unlock(ahd, &flags); - - printk("%s: Device reset code sleeping\n", ahd_name(ahd)); - if (!wait_for_completion_timeout(&done, 5 * HZ)) { - ahd_lock(ahd, &flags); - ahd->platform_data->eh_done = NULL; - ahd_unlock(ahd, &flags); - printk("%s: Device reset timer expired (active %d)\n", - ahd_name(ahd), dev->active); - retval = FAILED; - } - printk("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); - - return (retval); -} - -/* - * Reset the SCSI bus. - */ -static int -ahd_linux_bus_reset(struct scsi_cmnd *cmd) -{ - struct ahd_softc *ahd; - int found; - unsigned long flags; - - ahd = *(struct ahd_softc **)cmd->device->host->hostdata; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printk("%s: Bus reset called for cmd %p\n", - ahd_name(ahd), cmd); -#endif - ahd_lock(ahd, &flags); - - found = ahd_reset_channel(ahd, scmd_channel(cmd) + 'A', - /*initiate reset*/TRUE); - ahd_unlock(ahd, &flags); - - if (bootverbose) - printk("%s: SCSI bus reset delivered. " - "%d SCBs aborted.\n", ahd_name(ahd), found); - - return (SUCCESS); -} - -struct scsi_host_template aic79xx_driver_template = { - .module = THIS_MODULE, - .name = "aic79xx", - .proc_name = "aic79xx", - .proc_info = ahd_linux_proc_info, - .info = ahd_linux_info, - .queuecommand = ahd_linux_queue, - .eh_abort_handler = ahd_linux_abort, - .eh_device_reset_handler = ahd_linux_dev_reset, - .eh_bus_reset_handler = ahd_linux_bus_reset, -#if defined(__i386__) - .bios_param = ahd_linux_biosparam, -#endif - .can_queue = AHD_MAX_QUEUE, - .this_id = -1, - .max_sectors = 8192, - .cmd_per_lun = 2, - .use_clustering = ENABLE_CLUSTERING, - .slave_alloc = ahd_linux_slave_alloc, - .slave_configure = ahd_linux_slave_configure, - .target_alloc = ahd_linux_target_alloc, - .target_destroy = ahd_linux_target_destroy, -}; - -/******************************** Bus DMA *************************************/ -int -ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, - bus_size_t alignment, bus_size_t boundary, - dma_addr_t lowaddr, dma_addr_t highaddr, - bus_dma_filter_t *filter, void *filterarg, - bus_size_t maxsize, int nsegments, - bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) -{ - bus_dma_tag_t dmat; - - dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC); - if (dmat == NULL) - return (ENOMEM); - - /* - * Linux is very simplistic about DMA memory. For now don't - * maintain all specification information. Once Linux supplies - * better facilities for doing these operations, or the - * needs of this particular driver change, we might need to do - * more here. - */ - dmat->alignment = alignment; - dmat->boundary = boundary; - dmat->maxsize = maxsize; - *ret_tag = dmat; - return (0); -} - -void -ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat) -{ - kfree(dmat); -} - -int -ahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr, - int flags, bus_dmamap_t *mapp) -{ - *vaddr = pci_alloc_consistent(ahd->dev_softc, - dmat->maxsize, mapp); - if (*vaddr == NULL) - return (ENOMEM); - return(0); -} - -void -ahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat, - void* vaddr, bus_dmamap_t map) -{ - pci_free_consistent(ahd->dev_softc, dmat->maxsize, - vaddr, map); -} - -int -ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map, - void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, - void *cb_arg, int flags) -{ - /* - * Assume for now that this will only be used during - * initialization and not for per-transaction buffer mapping. - */ - bus_dma_segment_t stack_sg; - - stack_sg.ds_addr = map; - stack_sg.ds_len = dmat->maxsize; - cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); - return (0); -} - -void -ahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) -{ -} - -int -ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) -{ - /* Nothing to do */ - return (0); -} - -/********************* Platform Dependent Functions ***************************/ -static void -ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value) -{ - - if ((instance >= 0) - && (instance < ARRAY_SIZE(aic79xx_iocell_info))) { - uint8_t *iocell_info; - - iocell_info = (uint8_t*)&aic79xx_iocell_info[instance]; - iocell_info[index] = value & 0xFFFF; - if (bootverbose) - printk("iocell[%d:%ld] = %d\n", instance, index, value); - } -} - -static void -ahd_linux_setup_tag_info_global(char *p) -{ - int tags, i, j; - - tags = simple_strtoul(p + 1, NULL, 0) & 0xff; - printk("Setting Global Tags= %d\n", tags); - - for (i = 0; i < ARRAY_SIZE(aic79xx_tag_info); i++) { - for (j = 0; j < AHD_NUM_TARGETS; j++) { - aic79xx_tag_info[i].tag_commands[j] = tags; - } - } -} - -static void -ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) -{ - - if ((instance >= 0) && (targ >= 0) - && (instance < ARRAY_SIZE(aic79xx_tag_info)) - && (targ < AHD_NUM_TARGETS)) { - aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF; - if (bootverbose) - printk("tag_info[%d:%d] = %d\n", instance, targ, value); - } -} - -static char * -ahd_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, - void (*callback)(u_long, int, int, int32_t), - u_long callback_arg) -{ - char *tok_end; - char *tok_end2; - int i; - int instance; - int targ; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - /* All options use a ':' name/arg separator */ - if (*opt_arg != ':') - return (opt_arg); - opt_arg++; - instance = -1; - targ = -1; - done = FALSE; - /* - * Restore separator that may be in - * the middle of our option argument. - */ - tok_end = strchr(opt_arg, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*opt_arg) { - case '{': - if (instance == -1) { - instance = 0; - } else { - if (depth > 1) { - if (targ == -1) - targ = 0; - } else { - printk("Malformed Option %s\n", - opt_name); - done = TRUE; - } - } - opt_arg++; - break; - case '}': - if (targ != -1) - targ = -1; - else if (instance != -1) - instance = -1; - opt_arg++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (targ >= 0) - targ++; - else if (instance >= 0) - instance++; - opt_arg++; - break; - case '\0': - done = TRUE; - break; - default: - tok_end = end; - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(opt_arg, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) - tok_end = tok_end2; - } - callback(callback_arg, instance, targ, - simple_strtol(opt_arg, NULL, 0)); - opt_arg = tok_end; - break; - } - } - return (opt_arg); -} - -/* - * Handle Linux boot parameters. This routine allows for assigning a value - * to a parameter with a ':' between the parameter and the value. - * ie. aic79xx=stpwlev:1,extended - */ -static int -aic79xx_setup(char *s) -{ - int i, n; - char *p; - char *end; - - static const struct { - const char *name; - uint32_t *flag; - } options[] = { - { "extended", &aic79xx_extended }, - { "no_reset", &aic79xx_no_reset }, - { "verbose", &aic79xx_verbose }, - { "allow_memio", &aic79xx_allow_memio}, -#ifdef AHD_DEBUG - { "debug", &ahd_debug }, -#endif - { "periodic_otag", &aic79xx_periodic_otag }, - { "pci_parity", &aic79xx_pci_parity }, - { "seltime", &aic79xx_seltime }, - { "tag_info", NULL }, - { "global_tag_depth", NULL}, - { "slewrate", NULL }, - { "precomp", NULL }, - { "amplitude", NULL }, - { "slowcrc", &aic79xx_slowcrc }, - }; - - end = strchr(s, '\0'); - - /* - * XXX ia64 gcc isn't smart enough to know that ARRAY_SIZE - * will never be 0 in this case. - */ - n = 0; - - while ((p = strsep(&s, ",.")) != NULL) { - if (*p == '\0') - continue; - for (i = 0; i < ARRAY_SIZE(options); i++) { - - n = strlen(options[i].name); - if (strncmp(options[i].name, p, n) == 0) - break; - } - if (i == ARRAY_SIZE(options)) - continue; - - if (strncmp(p, "global_tag_depth", n) == 0) { - ahd_linux_setup_tag_info_global(p + n); - } else if (strncmp(p, "tag_info", n) == 0) { - s = ahd_parse_brace_option("tag_info", p + n, end, - 2, ahd_linux_setup_tag_info, 0); - } else if (strncmp(p, "slewrate", n) == 0) { - s = ahd_parse_brace_option("slewrate", - p + n, end, 1, ahd_linux_setup_iocell_info, - AIC79XX_SLEWRATE_INDEX); - } else if (strncmp(p, "precomp", n) == 0) { - s = ahd_parse_brace_option("precomp", - p + n, end, 1, ahd_linux_setup_iocell_info, - AIC79XX_PRECOMP_INDEX); - } else if (strncmp(p, "amplitude", n) == 0) { - s = ahd_parse_brace_option("amplitude", - p + n, end, 1, ahd_linux_setup_iocell_info, - AIC79XX_AMPLITUDE_INDEX); - } else if (p[n] == ':') { - *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); - } else if (!strncmp(p, "verbose", n)) { - *(options[i].flag) = 1; - } else { - *(options[i].flag) ^= 0xFFFFFFFF; - } - } - return 1; -} - -__setup("aic79xx=", aic79xx_setup); - -uint32_t aic79xx_verbose; - -int -ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *template) -{ - char buf[80]; - struct Scsi_Host *host; - char *new_name; - u_long s; - int retval; - - template->name = ahd->description; - host = scsi_host_alloc(template, sizeof(struct ahd_softc *)); - if (host == NULL) - return (ENOMEM); - - *((struct ahd_softc **)host->hostdata) = ahd; - ahd->platform_data->host = host; - host->can_queue = AHD_MAX_QUEUE; - host->cmd_per_lun = 2; - host->sg_tablesize = AHD_NSEG; - host->this_id = ahd->our_id; - host->irq = ahd->platform_data->irq; - host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8; - host->max_lun = AHD_NUM_LUNS; - host->max_channel = 0; - host->sg_tablesize = AHD_NSEG; - ahd_lock(ahd, &s); - ahd_set_unit(ahd, ahd_linux_unit++); - ahd_unlock(ahd, &s); - sprintf(buf, "scsi%d", host->host_no); - new_name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); - if (new_name != NULL) { - strcpy(new_name, buf); - ahd_set_name(ahd, new_name); - } - host->unique_id = ahd->unit; - ahd_linux_initialize_scsi_bus(ahd); - ahd_intr_enable(ahd, TRUE); - - host->transportt = ahd_linux_transport_template; - - retval = scsi_add_host(host, &ahd->dev_softc->dev); - if (retval) { - printk(KERN_WARNING "aic79xx: scsi_add_host failed\n"); - scsi_host_put(host); - return retval; - } - - scsi_scan_host(host); - return 0; -} - -/* - * Place the SCSI bus into a known state by either resetting it, - * or forcing transfer negotiations on the next command to any - * target. - */ -static void -ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd) -{ - u_int target_id; - u_int numtarg; - unsigned long s; - - target_id = 0; - numtarg = 0; - - if (aic79xx_no_reset != 0) - ahd->flags &= ~AHD_RESET_BUS_A; - - if ((ahd->flags & AHD_RESET_BUS_A) != 0) - ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE); - else - numtarg = (ahd->features & AHD_WIDE) ? 16 : 8; - - ahd_lock(ahd, &s); - - /* - * Force negotiation to async for all targets that - * will not see an initial bus reset. - */ - for (; target_id < numtarg; target_id++) { - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - target_id, &tstate); - ahd_compile_devinfo(&devinfo, ahd->our_id, target_id, - CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR); - ahd_update_neg_request(ahd, &devinfo, tstate, - tinfo, AHD_NEG_ALWAYS); - } - ahd_unlock(ahd, &s); - /* Give the bus some time to recover */ - if ((ahd->flags & AHD_RESET_BUS_A) != 0) { - ahd_freeze_simq(ahd); - msleep(AIC79XX_RESET_DELAY); - ahd_release_simq(ahd); - } -} - -int -ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) -{ - ahd->platform_data = - kmalloc(sizeof(struct ahd_platform_data), GFP_ATOMIC); - if (ahd->platform_data == NULL) - return (ENOMEM); - memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); - ahd->platform_data->irq = AHD_LINUX_NOIRQ; - ahd_lockinit(ahd); - ahd->seltime = (aic79xx_seltime & 0x3) << 4; - return (0); -} - -void -ahd_platform_free(struct ahd_softc *ahd) -{ - struct scsi_target *starget; - int i; - - if (ahd->platform_data != NULL) { - /* destroy all of the device and target objects */ - for (i = 0; i < AHD_NUM_TARGETS; i++) { - starget = ahd->platform_data->starget[i]; - if (starget != NULL) { - ahd->platform_data->starget[i] = NULL; - } - } - - if (ahd->platform_data->irq != AHD_LINUX_NOIRQ) - free_irq(ahd->platform_data->irq, ahd); - if (ahd->tags[0] == BUS_SPACE_PIO - && ahd->bshs[0].ioport != 0) - release_region(ahd->bshs[0].ioport, 256); - if (ahd->tags[1] == BUS_SPACE_PIO - && ahd->bshs[1].ioport != 0) - release_region(ahd->bshs[1].ioport, 256); - if (ahd->tags[0] == BUS_SPACE_MEMIO - && ahd->bshs[0].maddr != NULL) { - iounmap(ahd->bshs[0].maddr); - release_mem_region(ahd->platform_data->mem_busaddr, - 0x1000); - } - if (ahd->platform_data->host) - scsi_host_put(ahd->platform_data->host); - - kfree(ahd->platform_data); - } -} - -void -ahd_platform_init(struct ahd_softc *ahd) -{ - /* - * Lookup and commit any modified IO Cell options. - */ - if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) { - const struct ahd_linux_iocell_opts *iocell_opts; - - iocell_opts = &aic79xx_iocell_info[ahd->unit]; - if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP) - AHD_SET_PRECOMP(ahd, iocell_opts->precomp); - if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE) - AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate); - if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE) - AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude); - } - -} - -void -ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb) -{ - ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), - SCB_GET_CHANNEL(ahd, scb), - SCB_GET_LUN(scb), SCB_LIST_NULL, - ROLE_UNKNOWN, CAM_REQUEUE_REQ); -} - -void -ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, - struct ahd_devinfo *devinfo, ahd_queue_alg alg) -{ - struct ahd_linux_device *dev; - int was_queuing; - int now_queuing; - - if (sdev == NULL) - return; - - dev = scsi_transport_device_data(sdev); - - if (dev == NULL) - return; - was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED); - switch (alg) { - default: - case AHD_QUEUE_NONE: - now_queuing = 0; - break; - case AHD_QUEUE_BASIC: - now_queuing = AHD_DEV_Q_BASIC; - break; - case AHD_QUEUE_TAGGED: - now_queuing = AHD_DEV_Q_TAGGED; - break; - } - if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0 - && (was_queuing != now_queuing) - && (dev->active != 0)) { - dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen++; - } - - dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG); - if (now_queuing) { - u_int usertags; - - usertags = ahd_linux_user_tagdepth(ahd, devinfo); - if (!was_queuing) { - /* - * Start out aggressively and allow our - * dynamic queue depth algorithm to take - * care of the rest. - */ - dev->maxtags = usertags; - dev->openings = dev->maxtags - dev->active; - } - if (dev->maxtags == 0) { - /* - * Queueing is disabled by the user. - */ - dev->openings = 1; - } else if (alg == AHD_QUEUE_TAGGED) { - dev->flags |= AHD_DEV_Q_TAGGED; - if (aic79xx_periodic_otag != 0) - dev->flags |= AHD_DEV_PERIODIC_OTAG; - } else - dev->flags |= AHD_DEV_Q_BASIC; - } else { - /* We can only have one opening. */ - dev->maxtags = 0; - dev->openings = 1 - dev->active; - } - - switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { - case AHD_DEV_Q_BASIC: - scsi_set_tag_type(sdev, MSG_SIMPLE_TASK); - scsi_activate_tcq(sdev, dev->openings + dev->active); - break; - case AHD_DEV_Q_TAGGED: - scsi_set_tag_type(sdev, MSG_ORDERED_TASK); - scsi_activate_tcq(sdev, dev->openings + dev->active); - break; - default: - /* - * We allow the OS to queue 2 untagged transactions to - * us at any time even though we can only execute them - * serially on the controller/device. This should - * remove some latency. - */ - scsi_deactivate_tcq(sdev, 1); - break; - } -} - -int -ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status) -{ - return 0; -} - -static u_int -ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - static int warned_user; - u_int tags; - - tags = 0; - if ((ahd->user_discenable & devinfo->target_mask) != 0) { - if (ahd->unit >= ARRAY_SIZE(aic79xx_tag_info)) { - - if (warned_user == 0) { - printk(KERN_WARNING -"aic79xx: WARNING: Insufficient tag_info instances\n" -"aic79xx: for installed controllers. Using defaults\n" -"aic79xx: Please update the aic79xx_tag_info array in\n" -"aic79xx: the aic79xx_osm.c source file.\n"); - warned_user++; - } - tags = AHD_MAX_QUEUE; - } else { - adapter_tag_info_t *tag_info; - - tag_info = &aic79xx_tag_info[ahd->unit]; - tags = tag_info->tag_commands[devinfo->target_offset]; - if (tags > AHD_MAX_QUEUE) - tags = AHD_MAX_QUEUE; - } - } - return (tags); -} - -/* - * Determines the queue depth for a given device. - */ -static void -ahd_linux_device_queue_depth(struct scsi_device *sdev) -{ - struct ahd_devinfo devinfo; - u_int tags; - struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata); - - ahd_compile_devinfo(&devinfo, - ahd->our_id, - sdev->sdev_target->id, sdev->lun, - sdev->sdev_target->channel == 0 ? 'A' : 'B', - ROLE_INITIATOR); - tags = ahd_linux_user_tagdepth(ahd, &devinfo); - if (tags != 0 && sdev->tagged_supported != 0) { - - ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_TAGGED); - ahd_send_async(ahd, devinfo.channel, devinfo.target, - devinfo.lun, AC_TRANSFER_NEG); - ahd_print_devinfo(ahd, &devinfo); - printk("Tagged Queuing enabled. Depth %d\n", tags); - } else { - ahd_platform_set_tags(ahd, sdev, &devinfo, AHD_QUEUE_NONE); - ahd_send_async(ahd, devinfo.channel, devinfo.target, - devinfo.lun, AC_TRANSFER_NEG); - } -} - -static int -ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, - struct scsi_cmnd *cmd) -{ - struct scb *scb; - struct hardware_scb *hscb; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - u_int col_idx; - uint16_t mask; - unsigned long flags; - int nseg; - - nseg = scsi_dma_map(cmd); - if (nseg < 0) - return SCSI_MLQUEUE_HOST_BUSY; - - ahd_lock(ahd, &flags); - - /* - * Get an scb to use. - */ - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - cmd->device->id, &tstate); - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0 - || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - col_idx = AHD_NEVER_COL_IDX; - } else { - col_idx = AHD_BUILD_COL_IDX(cmd->device->id, - cmd->device->lun); - } - if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { - ahd->flags |= AHD_RESOURCE_SHORTAGE; - ahd_unlock(ahd, &flags); - scsi_dma_unmap(cmd); - return SCSI_MLQUEUE_HOST_BUSY; - } - - scb->io_ctx = cmd; - scb->platform_data->dev = dev; - hscb = scb->hscb; - cmd->host_scribble = (char *)scb; - - /* - * Fill out basics of the HSCB. - */ - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahd, cmd); - hscb->lun = cmd->device->lun; - scb->hscb->task_management = 0; - mask = SCB_GET_TARGET_MASK(ahd, scb); - - if ((ahd->user_discenable & mask) != 0) - hscb->control |= DISCENB; - - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) - scb->flags |= SCB_PACKETIZED; - - if ((tstate->auto_negotiate & mask) != 0) { - scb->flags |= SCB_AUTO_NEGOTIATE; - scb->hscb->control |= MK_MESSAGE; - } - - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { - int msg_bytes; - uint8_t tag_msgs[2]; - - msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); - if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { - hscb->control |= tag_msgs[0]; - if (tag_msgs[0] == MSG_ORDERED_TASK) - dev->commands_since_idle_or_otag = 0; - } else - if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH - && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { - hscb->control |= MSG_ORDERED_TASK; - dev->commands_since_idle_or_otag = 0; - } else { - hscb->control |= MSG_SIMPLE_TASK; - } - } - - hscb->cdb_len = cmd->cmd_len; - memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); - - scb->platform_data->xfer_len = 0; - ahd_set_residual(scb, 0); - ahd_set_sense_residual(scb, 0); - scb->sg_count = 0; - - if (nseg > 0) { - void *sg = scb->sg_list; - struct scatterlist *cur_seg; - int i; - - scb->platform_data->xfer_len = 0; - - scsi_for_each_sg(cmd, cur_seg, nseg, i) { - dma_addr_t addr; - bus_size_t len; - - addr = sg_dma_address(cur_seg); - len = sg_dma_len(cur_seg); - scb->platform_data->xfer_len += len; - sg = ahd_sg_setup(ahd, scb, sg, addr, len, - i == (nseg - 1)); - } - } - - LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); - dev->openings--; - dev->active++; - dev->commands_issued++; - - if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) - dev->commands_since_idle_or_otag++; - scb->flags |= SCB_ACTIVE; - ahd_queue_scb(ahd, scb); - - ahd_unlock(ahd, &flags); - - return 0; -} - -/* - * SCSI controller interrupt handler. - */ -irqreturn_t -ahd_linux_isr(int irq, void *dev_id) -{ - struct ahd_softc *ahd; - u_long flags; - int ours; - - ahd = (struct ahd_softc *) dev_id; - ahd_lock(ahd, &flags); - ours = ahd_intr(ahd); - ahd_unlock(ahd, &flags); - return IRQ_RETVAL(ours); -} - -void -ahd_send_async(struct ahd_softc *ahd, char channel, - u_int target, u_int lun, ac_code code) -{ - switch (code) { - case AC_TRANSFER_NEG: - { - char buf[80]; - struct scsi_target *starget; - struct info_str info; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - unsigned int target_ppr_options; - - BUG_ON(target == CAM_TARGET_WILDCARD); - - info.buffer = buf; - info.length = sizeof(buf); - info.offset = 0; - info.pos = 0; - tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, - target, &tstate); - - /* - * Don't bother reporting results while - * negotiations are still pending. - */ - if (tinfo->curr.period != tinfo->goal.period - || tinfo->curr.width != tinfo->goal.width - || tinfo->curr.offset != tinfo->goal.offset - || tinfo->curr.ppr_options != tinfo->goal.ppr_options) - if (bootverbose == 0) - break; - - /* - * Don't bother reporting results that - * are identical to those last reported. - */ - starget = ahd->platform_data->starget[target]; - if (starget == NULL) - break; - - target_ppr_options = - (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) - + (spi_qas(starget) ? MSG_EXT_PPR_QAS_REQ : 0) - + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0) - + (spi_rd_strm(starget) ? MSG_EXT_PPR_RD_STRM : 0) - + (spi_pcomp_en(starget) ? MSG_EXT_PPR_PCOMP_EN : 0) - + (spi_rti(starget) ? MSG_EXT_PPR_RTI : 0) - + (spi_wr_flow(starget) ? MSG_EXT_PPR_WR_FLOW : 0) - + (spi_hold_mcs(starget) ? MSG_EXT_PPR_HOLD_MCS : 0); - - if (tinfo->curr.period == spi_period(starget) - && tinfo->curr.width == spi_width(starget) - && tinfo->curr.offset == spi_offset(starget) - && tinfo->curr.ppr_options == target_ppr_options) - if (bootverbose == 0) - break; - - spi_period(starget) = tinfo->curr.period; - spi_width(starget) = tinfo->curr.width; - spi_offset(starget) = tinfo->curr.offset; - spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0; - spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0; - spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0; - spi_rd_strm(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RD_STRM ? 1 : 0; - spi_pcomp_en(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_PCOMP_EN ? 1 : 0; - spi_rti(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RTI ? 1 : 0; - spi_wr_flow(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_WR_FLOW ? 1 : 0; - spi_hold_mcs(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_HOLD_MCS ? 1 : 0; - spi_display_xfer_agreement(starget); - break; - } - case AC_SENT_BDR: - { - WARN_ON(lun != CAM_LUN_WILDCARD); - scsi_report_device_reset(ahd->platform_data->host, - channel - 'A', target); - break; - } - case AC_BUS_RESET: - if (ahd->platform_data->host != NULL) { - scsi_report_bus_reset(ahd->platform_data->host, - channel - 'A'); - } - break; - default: - panic("ahd_send_async: Unexpected async event"); - } -} - -/* - * Calls the higher level scsi done function and frees the scb. - */ -void -ahd_done(struct ahd_softc *ahd, struct scb *scb) -{ - struct scsi_cmnd *cmd; - struct ahd_linux_device *dev; - - if ((scb->flags & SCB_ACTIVE) == 0) { - printk("SCB %d done'd twice\n", SCB_GET_TAG(scb)); - ahd_dump_card_state(ahd); - panic("Stopping for safety"); - } - LIST_REMOVE(scb, pending_links); - cmd = scb->io_ctx; - dev = scb->platform_data->dev; - dev->active--; - dev->openings++; - if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) { - cmd->result &= ~(CAM_DEV_QFRZN << 16); - dev->qfrozen--; - } - ahd_linux_unmap_scb(ahd, scb); - - /* - * Guard against stale sense data. - * The Linux mid-layer assumes that sense - * was retrieved anytime the first byte of - * the sense buffer looks "sane". - */ - cmd->sense_buffer[0] = 0; - if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) { - uint32_t amount_xferred; - - amount_xferred = - ahd_get_transfer_length(scb) - ahd_get_residual(scb); - if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MISC) != 0) { - ahd_print_path(ahd, scb); - printk("Set CAM_UNCOR_PARITY\n"); - } -#endif - ahd_set_transaction_status(scb, CAM_UNCOR_PARITY); -#ifdef AHD_REPORT_UNDERFLOWS - /* - * This code is disabled by default as some - * clients of the SCSI system do not properly - * initialize the underflow parameter. This - * results in spurious termination of commands - * that complete as expected (e.g. underflow is - * allowed as command can return variable amounts - * of data. - */ - } else if (amount_xferred < scb->io_ctx->underflow) { - u_int i; - - ahd_print_path(ahd, scb); - printk("CDB:"); - for (i = 0; i < scb->io_ctx->cmd_len; i++) - printk(" 0x%x", scb->io_ctx->cmnd[i]); - printk("\n"); - ahd_print_path(ahd, scb); - printk("Saw underflow (%ld of %ld bytes). " - "Treated as error\n", - ahd_get_residual(scb), - ahd_get_transfer_length(scb)); - ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR); -#endif - } else { - ahd_set_transaction_status(scb, CAM_REQ_CMP); - } - } else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { - ahd_linux_handle_scsi_status(ahd, cmd->device, scb); - } - - if (dev->openings == 1 - && ahd_get_transaction_status(scb) == CAM_REQ_CMP - && ahd_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) - dev->tag_success_count++; - /* - * Some devices deal with temporary internal resource - * shortages by returning queue full. When the queue - * full occurrs, we throttle back. Slowly try to get - * back to our previous queue depth. - */ - if ((dev->openings + dev->active) < dev->maxtags - && dev->tag_success_count > AHD_TAG_SUCCESS_INTERVAL) { - dev->tag_success_count = 0; - dev->openings++; - } - - if (dev->active == 0) - dev->commands_since_idle_or_otag = 0; - - if ((scb->flags & SCB_RECOVERY_SCB) != 0) { - printk("Recovery SCB completes\n"); - if (ahd_get_transaction_status(scb) == CAM_BDR_SENT - || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) - ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); - - if (ahd->platform_data->eh_done) - complete(ahd->platform_data->eh_done); - } - - ahd_free_scb(ahd, scb); - ahd_linux_queue_cmd_complete(ahd, cmd); -} - -static void -ahd_linux_handle_scsi_status(struct ahd_softc *ahd, - struct scsi_device *sdev, struct scb *scb) -{ - struct ahd_devinfo devinfo; - struct ahd_linux_device *dev = scsi_transport_device_data(sdev); - - ahd_compile_devinfo(&devinfo, - ahd->our_id, - sdev->sdev_target->id, sdev->lun, - sdev->sdev_target->channel == 0 ? 'A' : 'B', - ROLE_INITIATOR); - - /* - * We don't currently trust the mid-layer to - * properly deal with queue full or busy. So, - * when one occurs, we tell the mid-layer to - * unconditionally requeue the command to us - * so that we can retry it ourselves. We also - * implement our own throttling mechanism so - * we don't clobber the device with too many - * commands. - */ - switch (ahd_get_scsi_status(scb)) { - default: - break; - case SCSI_STATUS_CHECK_COND: - case SCSI_STATUS_CMD_TERMINATED: - { - struct scsi_cmnd *cmd; - - /* - * Copy sense information to the OS's cmd - * structure if it is available. - */ - cmd = scb->io_ctx; - if ((scb->flags & (SCB_SENSE|SCB_PKT_SENSE)) != 0) { - struct scsi_status_iu_header *siu; - u_int sense_size; - u_int sense_offset; - - if (scb->flags & SCB_SENSE) { - sense_size = min(sizeof(struct scsi_sense_data) - - ahd_get_sense_residual(scb), - (u_long)SCSI_SENSE_BUFFERSIZE); - sense_offset = 0; - } else { - /* - * Copy only the sense data into the provided - * buffer. - */ - siu = (struct scsi_status_iu_header *) - scb->sense_data; - sense_size = min_t(size_t, - scsi_4btoul(siu->sense_length), - SCSI_SENSE_BUFFERSIZE); - sense_offset = SIU_SENSE_OFFSET(siu); - } - - memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - memcpy(cmd->sense_buffer, - ahd_get_sense_buf(ahd, scb) - + sense_offset, sense_size); - cmd->result |= (DRIVER_SENSE << 24); - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_SENSE) { - int i; - - printk("Copied %d bytes of sense data at %d:", - sense_size, sense_offset); - for (i = 0; i < sense_size; i++) { - if ((i & 0xF) == 0) - printk("\n"); - printk("0x%x ", cmd->sense_buffer[i]); - } - printk("\n"); - } -#endif - } - break; - } - case SCSI_STATUS_QUEUE_FULL: - /* - * By the time the core driver has returned this - * command, all other commands that were queued - * to us but not the device have been returned. - * This ensures that dev->active is equal to - * the number of commands actually queued to - * the device. - */ - dev->tag_success_count = 0; - if (dev->active != 0) { - /* - * Drop our opening count to the number - * of commands currently outstanding. - */ - dev->openings = 0; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_QFULL) != 0) { - ahd_print_path(ahd, scb); - printk("Dropping tag count to %d\n", - dev->active); - } -#endif - if (dev->active == dev->tags_on_last_queuefull) { - - dev->last_queuefull_same_count++; - /* - * If we repeatedly see a queue full - * at the same queue depth, this - * device has a fixed number of tag - * slots. Lock in this tag depth - * so we stop seeing queue fulls from - * this device. - */ - if (dev->last_queuefull_same_count - == AHD_LOCK_TAGS_COUNT) { - dev->maxtags = dev->active; - ahd_print_path(ahd, scb); - printk("Locking max tag count at %d\n", - dev->active); - } - } else { - dev->tags_on_last_queuefull = dev->active; - dev->last_queuefull_same_count = 0; - } - ahd_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahd_set_scsi_status(scb, SCSI_STATUS_OK); - ahd_platform_set_tags(ahd, sdev, &devinfo, - (dev->flags & AHD_DEV_Q_BASIC) - ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); - break; - } - /* - * Drop down to a single opening, and treat this - * as if the target returned BUSY SCSI status. - */ - dev->openings = 1; - ahd_platform_set_tags(ahd, sdev, &devinfo, - (dev->flags & AHD_DEV_Q_BASIC) - ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); - ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); - } -} - -static void -ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) -{ - int status; - int new_status = DID_OK; - int do_fallback = 0; - int scsi_status; - - /* - * Map CAM error codes into Linux Error codes. We - * avoid the conversion so that the DV code has the - * full error information available when making - * state change decisions. - */ - - status = ahd_cmd_get_transaction_status(cmd); - switch (status) { - case CAM_REQ_INPROG: - case CAM_REQ_CMP: - new_status = DID_OK; - break; - case CAM_AUTOSENSE_FAIL: - new_status = DID_ERROR; - /* Fallthrough */ - case CAM_SCSI_STATUS_ERROR: - scsi_status = ahd_cmd_get_scsi_status(cmd); - - switch(scsi_status) { - case SCSI_STATUS_CMD_TERMINATED: - case SCSI_STATUS_CHECK_COND: - if ((cmd->result >> 24) != DRIVER_SENSE) { - do_fallback = 1; - } else { - struct scsi_sense_data *sense; - - sense = (struct scsi_sense_data *) - cmd->sense_buffer; - if (sense->extra_len >= 5 && - (sense->add_sense_code == 0x47 - || sense->add_sense_code == 0x48)) - do_fallback = 1; - } - break; - default: - break; - } - break; - case CAM_REQ_ABORTED: - new_status = DID_ABORT; - break; - case CAM_BUSY: - new_status = DID_BUS_BUSY; - break; - case CAM_REQ_INVALID: - case CAM_PATH_INVALID: - new_status = DID_BAD_TARGET; - break; - case CAM_SEL_TIMEOUT: - new_status = DID_NO_CONNECT; - break; - case CAM_SCSI_BUS_RESET: - case CAM_BDR_SENT: - new_status = DID_RESET; - break; - case CAM_UNCOR_PARITY: - new_status = DID_PARITY; - do_fallback = 1; - break; - case CAM_CMD_TIMEOUT: - new_status = DID_TIME_OUT; - do_fallback = 1; - break; - case CAM_REQ_CMP_ERR: - case CAM_UNEXP_BUSFREE: - case CAM_DATA_RUN_ERR: - new_status = DID_ERROR; - do_fallback = 1; - break; - case CAM_UA_ABORT: - case CAM_NO_HBA: - case CAM_SEQUENCE_FAIL: - case CAM_CCB_LEN_ERR: - case CAM_PROVIDE_FAIL: - case CAM_REQ_TERMIO: - case CAM_UNREC_HBA_ERROR: - case CAM_REQ_TOO_BIG: - new_status = DID_ERROR; - break; - case CAM_REQUEUE_REQ: - new_status = DID_REQUEUE; - break; - default: - /* We should never get here */ - new_status = DID_ERROR; - break; - } - - if (do_fallback) { - printk("%s: device overrun (status %x) on %d:%d:%d\n", - ahd_name(ahd), status, cmd->device->channel, - cmd->device->id, cmd->device->lun); - } - - ahd_cmd_set_transaction_status(cmd, new_status); - - cmd->scsi_done(cmd); -} - -static void -ahd_freeze_simq(struct ahd_softc *ahd) -{ - scsi_block_requests(ahd->platform_data->host); -} - -static void -ahd_release_simq(struct ahd_softc *ahd) -{ - scsi_unblock_requests(ahd->platform_data->host); -} - -static int -ahd_linux_queue_abort_cmd(struct scsi_cmnd *cmd) -{ - struct ahd_softc *ahd; - struct ahd_linux_device *dev; - struct scb *pending_scb; - u_int saved_scbptr; - u_int active_scbptr; - u_int last_phase; - u_int saved_scsiid; - u_int cdb_byte; - int retval; - int was_paused; - int paused; - int wait; - int disconnected; - ahd_mode_state saved_modes; - unsigned long flags; - - pending_scb = NULL; - paused = FALSE; - wait = FALSE; - ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - - scmd_printk(KERN_INFO, cmd, - "Attempting to queue an ABORT message:"); - - printk("CDB:"); - for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printk(" 0x%x", cmd->cmnd[cdb_byte]); - printk("\n"); - - ahd_lock(ahd, &flags); - - /* - * First determine if we currently own this command. - * Start by searching the device queue. If not found - * there, check the pending_scb list. If not found - * at all, and the system wanted us to just abort the - * command, return success. - */ - dev = scsi_transport_device_data(cmd->device); - - if (dev == NULL) { - /* - * No target device for this command exists, - * so we must not still own the command. - */ - scmd_printk(KERN_INFO, cmd, "Is not an active device\n"); - retval = SUCCESS; - goto no_cmd; - } - - /* - * See if we can find a matching cmd in the pending list. - */ - LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { - if (pending_scb->io_ctx == cmd) - break; - } - - if (pending_scb == NULL) { - scmd_printk(KERN_INFO, cmd, "Command not found\n"); - goto no_cmd; - } - - if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { - /* - * We can't queue two recovery actions using the same SCB - */ - retval = FAILED; - goto done; - } - - /* - * Ensure that the card doesn't do anything - * behind our back. Also make sure that we - * didn't "just" miss an interrupt that would - * affect this cmd. - */ - was_paused = ahd_is_paused(ahd); - ahd_pause_and_flushwork(ahd); - paused = TRUE; - - if ((pending_scb->flags & SCB_ACTIVE) == 0) { - scmd_printk(KERN_INFO, cmd, "Command already completed\n"); - goto no_cmd; - } - - printk("%s: At time of recovery, card was %spaused\n", - ahd_name(ahd), was_paused ? "" : "not "); - ahd_dump_card_state(ahd); - - disconnected = TRUE; - if (ahd_search_qinfifo(ahd, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, - pending_scb->hscb->tag, - ROLE_INITIATOR, CAM_REQ_ABORTED, - SEARCH_COMPLETE) > 0) { - printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", - ahd_name(ahd), cmd->device->channel, - cmd->device->id, cmd->device->lun); - retval = SUCCESS; - goto done; - } - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - last_phase = ahd_inb(ahd, LASTPHASE); - saved_scbptr = ahd_get_scbptr(ahd); - active_scbptr = saved_scbptr; - if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) { - struct scb *bus_scb; - - bus_scb = ahd_lookup_scb(ahd, active_scbptr); - if (bus_scb == pending_scb) - disconnected = FALSE; - } - - /* - * At this point, pending_scb is the scb associated with the - * passed in command. That command is currently active on the - * bus or is in the disconnected state. - */ - saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); - if (last_phase != P_BUSFREE - && SCB_GET_TAG(pending_scb) == active_scbptr) { - - /* - * We're active on the bus, so assert ATN - * and hope that the target responds. - */ - pending_scb = ahd_lookup_scb(ahd, active_scbptr); - pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; - ahd_outb(ahd, MSG_OUT, HOST_MSG); - ahd_outb(ahd, SCSISIGO, last_phase|ATNO); - scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n"); - wait = TRUE; - } else if (disconnected) { - - /* - * Actually re-queue this SCB in an attempt - * to select the device before it reconnects. - */ - pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; - ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); - pending_scb->hscb->cdb_len = 0; - pending_scb->hscb->task_attribute = 0; - pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK; - - if ((pending_scb->flags & SCB_PACKETIZED) != 0) { - /* - * Mark the SCB has having an outstanding - * task management function. Should the command - * complete normally before the task management - * function can be sent, the host will be notified - * to abort our requeued SCB. - */ - ahd_outb(ahd, SCB_TASK_MANAGEMENT, - pending_scb->hscb->task_management); - } else { - /* - * If non-packetized, set the MK_MESSAGE control - * bit indicating that we desire to send a message. - * We also set the disconnected flag since there is - * no guarantee that our SCB control byte matches - * the version on the card. We don't want the - * sequencer to abort the command thinking an - * unsolicited reselection occurred. - */ - pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; - - /* - * The sequencer will never re-reference the - * in-core SCB. To make sure we are notified - * during reselection, set the MK_MESSAGE flag in - * the card's copy of the SCB. - */ - ahd_outb(ahd, SCB_CONTROL, - ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); - } - - /* - * Clear out any entries in the QINFIFO first - * so we are the next SCB for this target - * to run. - */ - ahd_search_qinfifo(ahd, cmd->device->id, - cmd->device->channel + 'A', cmd->device->lun, - SCB_LIST_NULL, ROLE_INITIATOR, - CAM_REQUEUE_REQ, SEARCH_COMPLETE); - ahd_qinfifo_requeue_tail(ahd, pending_scb); - ahd_set_scbptr(ahd, saved_scbptr); - ahd_print_path(ahd, pending_scb); - printk("Device is disconnected, re-queuing SCB\n"); - wait = TRUE; - } else { - scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n"); - retval = FAILED; - goto done; - } - -no_cmd: - /* - * Our assumption is that if we don't have the command, no - * recovery action was required, so we return success. Again, - * the semantics of the mid-layer recovery engine are not - * well defined, so this may change in time. - */ - retval = SUCCESS; -done: - if (paused) - ahd_unpause(ahd); - if (wait) { - DECLARE_COMPLETION_ONSTACK(done); - - ahd->platform_data->eh_done = &done; - ahd_unlock(ahd, &flags); - - printk("%s: Recovery code sleeping\n", ahd_name(ahd)); - if (!wait_for_completion_timeout(&done, 5 * HZ)) { - ahd_lock(ahd, &flags); - ahd->platform_data->eh_done = NULL; - ahd_unlock(ahd, &flags); - printk("%s: Timer Expired (active %d)\n", - ahd_name(ahd), dev->active); - retval = FAILED; - } - printk("Recovery code awake\n"); - } else - ahd_unlock(ahd, &flags); - - if (retval != SUCCESS) - printk("%s: Command abort returning 0x%x\n", - ahd_name(ahd), retval); - - return retval; -} - -static void ahd_linux_set_width(struct scsi_target *starget, int width) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_devinfo devinfo; - unsigned long flags; - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_lock(ahd, &flags); - ahd_set_width(ahd, &devinfo, width, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_period(struct scsi_target *starget, int period) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options; - unsigned int dt; - unsigned long flags; - unsigned long offset = tinfo->goal.offset; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: set period to %d\n", ahd_name(ahd), period); -#endif - if (offset == 0) - offset = MAX_OFFSET; - - if (period < 8) - period = 8; - if (period < 10) { - if (spi_max_width(starget)) { - ppr_options |= MSG_EXT_PPR_DT_REQ; - if (period == 8) - ppr_options |= MSG_EXT_PPR_IU_REQ; - } else - period = 10; - } - - dt = ppr_options & MSG_EXT_PPR_DT_REQ; - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - - /* all PPR requests apart from QAS require wide transfers */ - if (ppr_options & ~MSG_EXT_PPR_QAS_REQ) { - if (spi_width(starget) == 0) - ppr_options &= MSG_EXT_PPR_QAS_REQ; - } - - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_offset(struct scsi_target *starget, int offset) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = 0; - unsigned int period = 0; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; - unsigned long flags; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: set offset to %d\n", ahd_name(ahd), offset); -#endif - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - if (offset != 0) { - period = tinfo->goal.period; - ppr_options = tinfo->goal.ppr_options; - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - } - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, - AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_dt(struct scsi_target *starget, int dt) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_DT_REQ; - unsigned int period = tinfo->goal.period; - unsigned int width = tinfo->goal.width; - unsigned long flags; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: %s DT\n", ahd_name(ahd), - dt ? "enabling" : "disabling"); -#endif - if (dt && spi_max_width(starget)) { - ppr_options |= MSG_EXT_PPR_DT_REQ; - if (!width) - ahd_linux_set_width(starget, 1); - } else { - if (period <= 9) - period = 10; /* If resetting DT, period must be >= 25ns */ - /* IU is invalid without DT set */ - ppr_options &= ~MSG_EXT_PPR_IU_REQ; - } - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_qas(struct scsi_target *starget, int qas) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_QAS_REQ; - unsigned int period = tinfo->goal.period; - unsigned int dt; - unsigned long flags; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: %s QAS\n", ahd_name(ahd), - qas ? "enabling" : "disabling"); -#endif - - if (qas) { - ppr_options |= MSG_EXT_PPR_QAS_REQ; - } - - dt = ppr_options & MSG_EXT_PPR_DT_REQ; - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_iu(struct scsi_target *starget, int iu) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_IU_REQ; - unsigned int period = tinfo->goal.period; - unsigned int dt; - unsigned long flags; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: %s IU\n", ahd_name(ahd), - iu ? "enabling" : "disabling"); -#endif - - if (iu && spi_max_width(starget)) { - ppr_options |= MSG_EXT_PPR_IU_REQ; - ppr_options |= MSG_EXT_PPR_DT_REQ; /* IU requires DT */ - } - - dt = ppr_options & MSG_EXT_PPR_DT_REQ; - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_RD_STRM; - unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; - unsigned long flags; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: %s Read Streaming\n", ahd_name(ahd), - rdstrm ? "enabling" : "disabling"); -#endif - - if (rdstrm && spi_max_width(starget)) - ppr_options |= MSG_EXT_PPR_RD_STRM; - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_WR_FLOW; - unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; - unsigned long flags; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: %s Write Flow Control\n", ahd_name(ahd), - wrflow ? "enabling" : "disabling"); -#endif - - if (wrflow && spi_max_width(starget)) - ppr_options |= MSG_EXT_PPR_WR_FLOW; - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_rti(struct scsi_target *starget, int rti) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_RTI; - unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; - unsigned long flags; - - if ((ahd->features & AHD_RTI) == 0) { -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: RTI not available\n", ahd_name(ahd)); -#endif - return; - } - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: %s RTI\n", ahd_name(ahd), - rti ? "enabling" : "disabling"); -#endif - - if (rti && spi_max_width(starget)) - ppr_options |= MSG_EXT_PPR_RTI; - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_PCOMP_EN; - unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; - unsigned long flags; - -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_DV) != 0) - printk("%s: %s Precompensation\n", ahd_name(ahd), - pcomp ? "Enable" : "Disable"); -#endif - - if (pcomp && spi_max_width(starget)) { - uint8_t precomp; - - if (ahd->unit < ARRAY_SIZE(aic79xx_iocell_info)) { - const struct ahd_linux_iocell_opts *iocell_opts; - - iocell_opts = &aic79xx_iocell_info[ahd->unit]; - precomp = iocell_opts->precomp; - } else { - precomp = AIC79XX_DEFAULT_PRECOMP; - } - ppr_options |= MSG_EXT_PPR_PCOMP_EN; - AHD_SET_PRECOMP(ahd, precomp); - } else { - AHD_SET_PRECOMP(ahd, 0); - } - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_set_hold_mcs(struct scsi_target *starget, int hold) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); - struct ahd_tmode_tstate *tstate; - struct ahd_initiator_tinfo *tinfo - = ahd_fetch_transinfo(ahd, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahd_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_HOLD_MCS; - unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; - unsigned long flags; - - if (hold && spi_max_width(starget)) - ppr_options |= MSG_EXT_PPR_HOLD_MCS; - - ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahd_find_syncrate(ahd, &period, &ppr_options, - dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - - ahd_lock(ahd, &flags); - ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - ahd_unlock(ahd, &flags); -} - -static void ahd_linux_get_signalling(struct Scsi_Host *shost) -{ - struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata; - unsigned long flags; - u8 mode; - - ahd_lock(ahd, &flags); - ahd_pause(ahd); - mode = ahd_inb(ahd, SBLKCTL); - ahd_unpause(ahd); - ahd_unlock(ahd, &flags); - - if (mode & ENAB40) - spi_signalling(shost) = SPI_SIGNAL_LVD; - else if (mode & ENAB20) - spi_signalling(shost) = SPI_SIGNAL_SE; - else - spi_signalling(shost) = SPI_SIGNAL_UNKNOWN; -} - -static struct spi_function_template ahd_linux_transport_functions = { - .set_offset = ahd_linux_set_offset, - .show_offset = 1, - .set_period = ahd_linux_set_period, - .show_period = 1, - .set_width = ahd_linux_set_width, - .show_width = 1, - .set_dt = ahd_linux_set_dt, - .show_dt = 1, - .set_iu = ahd_linux_set_iu, - .show_iu = 1, - .set_qas = ahd_linux_set_qas, - .show_qas = 1, - .set_rd_strm = ahd_linux_set_rd_strm, - .show_rd_strm = 1, - .set_wr_flow = ahd_linux_set_wr_flow, - .show_wr_flow = 1, - .set_rti = ahd_linux_set_rti, - .show_rti = 1, - .set_pcomp_en = ahd_linux_set_pcomp_en, - .show_pcomp_en = 1, - .set_hold_mcs = ahd_linux_set_hold_mcs, - .show_hold_mcs = 1, - .get_signalling = ahd_linux_get_signalling, -}; - -static int __init -ahd_linux_init(void) -{ - int error = 0; - - /* - * If we've been passed any parameters, process them now. - */ - if (aic79xx) - aic79xx_setup(aic79xx); - - ahd_linux_transport_template = - spi_attach_transport(&ahd_linux_transport_functions); - if (!ahd_linux_transport_template) - return -ENODEV; - - scsi_transport_reserve_device(ahd_linux_transport_template, - sizeof(struct ahd_linux_device)); - - error = ahd_linux_pci_init(); - if (error) - spi_release_transport(ahd_linux_transport_template); - return error; -} - -static void __exit -ahd_linux_exit(void) -{ - ahd_linux_pci_exit(); - spi_release_transport(ahd_linux_transport_template); -} - -module_init(ahd_linux_init); -module_exit(ahd_linux_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.h deleted file mode 100644 index 28e43498..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm.h +++ /dev/null @@ -1,703 +0,0 @@ -/* - * Adaptec AIC79xx device driver for Linux. - * - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#166 $ - * - */ -#ifndef _AIC79XX_LINUX_H_ -#define _AIC79XX_LINUX_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Core SCSI definitions */ -#define AIC_LIB_PREFIX ahd - -/* Name space conflict with BSD queue macros */ -#ifdef LIST_HEAD -#undef LIST_HEAD -#endif - -#include "cam.h" -#include "queue.h" -#include "scsi_message.h" -#include "scsi_iu.h" -#include "aiclib.h" - -/*********************************** Debugging ********************************/ -#ifdef CONFIG_AIC79XX_DEBUG_ENABLE -#ifdef CONFIG_AIC79XX_DEBUG_MASK -#define AHD_DEBUG 1 -#define AHD_DEBUG_OPTS CONFIG_AIC79XX_DEBUG_MASK -#else -/* - * Compile in debugging code, but do not enable any printfs. - */ -#define AHD_DEBUG 1 -#define AHD_DEBUG_OPTS 0 -#endif -/* No debugging code. */ -#endif - -/********************************** Misc Macros *******************************/ -#define powerof2(x) ((((x)-1)&(x))==0) - -/************************* Forward Declarations *******************************/ -struct ahd_softc; -typedef struct pci_dev *ahd_dev_softc_t; -typedef struct scsi_cmnd *ahd_io_ctx_t; - -/******************************* Byte Order ***********************************/ -#define ahd_htobe16(x) cpu_to_be16(x) -#define ahd_htobe32(x) cpu_to_be32(x) -#define ahd_htobe64(x) cpu_to_be64(x) -#define ahd_htole16(x) cpu_to_le16(x) -#define ahd_htole32(x) cpu_to_le32(x) -#define ahd_htole64(x) cpu_to_le64(x) - -#define ahd_be16toh(x) be16_to_cpu(x) -#define ahd_be32toh(x) be32_to_cpu(x) -#define ahd_be64toh(x) be64_to_cpu(x) -#define ahd_le16toh(x) le16_to_cpu(x) -#define ahd_le32toh(x) le32_to_cpu(x) -#define ahd_le64toh(x) le64_to_cpu(x) - -/************************* Configuration Data *********************************/ -extern uint32_t aic79xx_allow_memio; -extern struct scsi_host_template aic79xx_driver_template; - -/***************************** Bus Space/DMA **********************************/ - -typedef uint32_t bus_size_t; - -typedef enum { - BUS_SPACE_MEMIO, - BUS_SPACE_PIO -} bus_space_tag_t; - -typedef union { - u_long ioport; - volatile uint8_t __iomem *maddr; -} bus_space_handle_t; - -typedef struct bus_dma_segment -{ - dma_addr_t ds_addr; - bus_size_t ds_len; -} bus_dma_segment_t; - -struct ahd_linux_dma_tag -{ - bus_size_t alignment; - bus_size_t boundary; - bus_size_t maxsize; -}; -typedef struct ahd_linux_dma_tag* bus_dma_tag_t; - -typedef dma_addr_t bus_dmamap_t; - -typedef int bus_dma_filter_t(void*, dma_addr_t); -typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); - -#define BUS_DMA_WAITOK 0x0 -#define BUS_DMA_NOWAIT 0x1 -#define BUS_DMA_ALLOCNOW 0x2 -#define BUS_DMA_LOAD_SEGS 0x4 /* - * Argument is an S/G list not - * a single buffer. - */ - -#define BUS_SPACE_MAXADDR 0xFFFFFFFF -#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF -#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF - -int ahd_dma_tag_create(struct ahd_softc *, bus_dma_tag_t /*parent*/, - bus_size_t /*alignment*/, bus_size_t /*boundary*/, - dma_addr_t /*lowaddr*/, dma_addr_t /*highaddr*/, - bus_dma_filter_t*/*filter*/, void */*filterarg*/, - bus_size_t /*maxsize*/, int /*nsegments*/, - bus_size_t /*maxsegsz*/, int /*flags*/, - bus_dma_tag_t */*dma_tagp*/); - -void ahd_dma_tag_destroy(struct ahd_softc *, bus_dma_tag_t /*tag*/); - -int ahd_dmamem_alloc(struct ahd_softc *, bus_dma_tag_t /*dmat*/, - void** /*vaddr*/, int /*flags*/, - bus_dmamap_t* /*mapp*/); - -void ahd_dmamem_free(struct ahd_softc *, bus_dma_tag_t /*dmat*/, - void* /*vaddr*/, bus_dmamap_t /*map*/); - -void ahd_dmamap_destroy(struct ahd_softc *, bus_dma_tag_t /*tag*/, - bus_dmamap_t /*map*/); - -int ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t /*dmat*/, - bus_dmamap_t /*map*/, void * /*buf*/, - bus_size_t /*buflen*/, bus_dmamap_callback_t *, - void */*callback_arg*/, int /*flags*/); - -int ahd_dmamap_unload(struct ahd_softc *, bus_dma_tag_t, bus_dmamap_t); - -/* - * Operations performed by ahd_dmamap_sync(). - */ -#define BUS_DMASYNC_PREREAD 0x01 /* pre-read synchronization */ -#define BUS_DMASYNC_POSTREAD 0x02 /* post-read synchronization */ -#define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */ -#define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */ - -/* - * XXX - * ahd_dmamap_sync is only used on buffers allocated with - * the pci_alloc_consistent() API. Although I'm not sure how - * this works on architectures with a write buffer, Linux does - * not have an API to sync "coherent" memory. Perhaps we need - * to do an mb()? - */ -#define ahd_dmamap_sync(ahd, dma_tag, dmamap, offset, len, op) - -/************************** Timer DataStructures ******************************/ -typedef struct timer_list ahd_timer_t; - -/********************************** Includes **********************************/ -#ifdef CONFIG_AIC79XX_REG_PRETTY_PRINT -#define AIC_DEBUG_REGISTERS 1 -#else -#define AIC_DEBUG_REGISTERS 0 -#endif -#include "aic79xx.h" - -/***************************** Timer Facilities *******************************/ -#define ahd_timer_init init_timer -#define ahd_timer_stop del_timer_sync - -/***************************** SMP support ************************************/ -#include - -#define AIC79XX_DRIVER_VERSION "3.0" - -/*************************** Device Data Structures ***************************/ -/* - * A per probed device structure used to deal with some error recovery - * scenarios that the Linux mid-layer code just doesn't know how to - * handle. The structure allocated for a device only becomes persistent - * after a successfully completed inquiry command to the target when - * that inquiry data indicates a lun is present. - */ - -typedef enum { - AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ - AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ - AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ - AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ -} ahd_linux_dev_flags; - -struct ahd_linux_device { - TAILQ_ENTRY(ahd_linux_device) links; - - /* - * The number of transactions currently - * queued to the device. - */ - int active; - - /* - * The currently allowed number of - * transactions that can be queued to - * the device. Must be signed for - * conversion from tagged to untagged - * mode where the device may have more - * than one outstanding active transaction. - */ - int openings; - - /* - * A positive count indicates that this - * device's queue is halted. - */ - u_int qfrozen; - - /* - * Cumulative command counter. - */ - u_long commands_issued; - - /* - * The number of tagged transactions when - * running at our current opening level - * that have been successfully received by - * this device since the last QUEUE FULL. - */ - u_int tag_success_count; -#define AHD_TAG_SUCCESS_INTERVAL 50 - - ahd_linux_dev_flags flags; - - /* - * Per device timer. - */ - struct timer_list timer; - - /* - * The high limit for the tags variable. - */ - u_int maxtags; - - /* - * The computed number of tags outstanding - * at the time of the last QUEUE FULL event. - */ - u_int tags_on_last_queuefull; - - /* - * How many times we have seen a queue full - * with the same number of tags. This is used - * to stop our adaptive queue depth algorithm - * on devices with a fixed number of tags. - */ - u_int last_queuefull_same_count; -#define AHD_LOCK_TAGS_COUNT 50 - - /* - * How many transactions have been queued - * without the device going idle. We use - * this statistic to determine when to issue - * an ordered tag to prevent transaction - * starvation. This statistic is only updated - * if the AHD_DEV_PERIODIC_OTAG flag is set - * on this device. - */ - u_int commands_since_idle_or_otag; -#define AHD_OTAG_THRESH 500 -}; - -/********************* Definitions Required by the Core ***********************/ -/* - * Number of SG segments we require. So long as the S/G segments for - * a particular transaction are allocated in a physically contiguous - * manner and are allocated below 4GB, the number of S/G segments is - * unrestricted. - */ -#define AHD_NSEG 128 - -/* - * Per-SCB OSM storage. - */ -struct scb_platform_data { - struct ahd_linux_device *dev; - dma_addr_t buf_busaddr; - uint32_t xfer_len; - uint32_t sense_resid; /* Auto-Sense residual */ -}; - -/* - * Define a structure used for each host adapter. All members are - * aligned on a boundary >= the size of the member to honor the - * alignment restrictions of the various platforms supported by - * this driver. - */ -struct ahd_platform_data { - /* - * Fields accessed from interrupt context. - */ - struct scsi_target *starget[AHD_NUM_TARGETS]; - - spinlock_t spin_lock; - struct completion *eh_done; - struct Scsi_Host *host; /* pointer to scsi host */ -#define AHD_LINUX_NOIRQ ((uint32_t)~0) - uint32_t irq; /* IRQ for this adapter */ - uint32_t bios_address; - resource_size_t mem_busaddr; /* Mem Base Addr */ -}; - -void ahd_delay(long); - -/***************************** Low Level I/O **********************************/ -uint8_t ahd_inb(struct ahd_softc * ahd, long port); -void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val); -void ahd_outw_atomic(struct ahd_softc * ahd, - long port, uint16_t val); -void ahd_outsb(struct ahd_softc * ahd, long port, - uint8_t *, int count); -void ahd_insb(struct ahd_softc * ahd, long port, - uint8_t *, int count); - -/**************************** Initialization **********************************/ -int ahd_linux_register_host(struct ahd_softc *, - struct scsi_host_template *); - -/*************************** Pretty Printing **********************************/ -struct info_str { - char *buffer; - int length; - off_t offset; - int pos; -}; - -/******************************** Locking *************************************/ -static inline void -ahd_lockinit(struct ahd_softc *ahd) -{ - spin_lock_init(&ahd->platform_data->spin_lock); -} - -static inline void -ahd_lock(struct ahd_softc *ahd, unsigned long *flags) -{ - spin_lock_irqsave(&ahd->platform_data->spin_lock, *flags); -} - -static inline void -ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) -{ - spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags); -} - -/******************************* PCI Definitions ******************************/ -/* - * PCIM_xxx: mask to locate subfield in register - * PCIR_xxx: config register offset - * PCIC_xxx: device class - * PCIS_xxx: device subclass - * PCIP_xxx: device programming interface - * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) - * PCID_xxx: device ID - */ -#define PCIR_DEVVENDOR 0x00 -#define PCIR_VENDOR 0x00 -#define PCIR_DEVICE 0x02 -#define PCIR_COMMAND 0x04 -#define PCIM_CMD_PORTEN 0x0001 -#define PCIM_CMD_MEMEN 0x0002 -#define PCIM_CMD_BUSMASTEREN 0x0004 -#define PCIM_CMD_MWRICEN 0x0010 -#define PCIM_CMD_PERRESPEN 0x0040 -#define PCIM_CMD_SERRESPEN 0x0100 -#define PCIR_STATUS 0x06 -#define PCIR_REVID 0x08 -#define PCIR_PROGIF 0x09 -#define PCIR_SUBCLASS 0x0a -#define PCIR_CLASS 0x0b -#define PCIR_CACHELNSZ 0x0c -#define PCIR_LATTIMER 0x0d -#define PCIR_HEADERTYPE 0x0e -#define PCIM_MFDEV 0x80 -#define PCIR_BIST 0x0f -#define PCIR_CAP_PTR 0x34 - -/* config registers for header type 0 devices */ -#define PCIR_MAPS 0x10 -#define PCIR_SUBVEND_0 0x2c -#define PCIR_SUBDEV_0 0x2e - -/****************************** PCI-X definitions *****************************/ -#define PCIXR_COMMAND 0x96 -#define PCIXR_DEVADDR 0x98 -#define PCIXM_DEVADDR_FNUM 0x0003 /* Function Number */ -#define PCIXM_DEVADDR_DNUM 0x00F8 /* Device Number */ -#define PCIXM_DEVADDR_BNUM 0xFF00 /* Bus Number */ -#define PCIXR_STATUS 0x9A -#define PCIXM_STATUS_64BIT 0x0001 /* Active 64bit connection to device. */ -#define PCIXM_STATUS_133CAP 0x0002 /* Device is 133MHz capable */ -#define PCIXM_STATUS_SCDISC 0x0004 /* Split Completion Discarded */ -#define PCIXM_STATUS_UNEXPSC 0x0008 /* Unexpected Split Completion */ -#define PCIXM_STATUS_CMPLEXDEV 0x0010 /* Device Complexity (set == bridge) */ -#define PCIXM_STATUS_MAXMRDBC 0x0060 /* Maximum Burst Read Count */ -#define PCIXM_STATUS_MAXSPLITS 0x0380 /* Maximum Split Transactions */ -#define PCIXM_STATUS_MAXCRDS 0x1C00 /* Maximum Cumulative Read Size */ -#define PCIXM_STATUS_RCVDSCEM 0x2000 /* Received a Split Comp w/Error msg */ - -typedef enum -{ - AHD_POWER_STATE_D0, - AHD_POWER_STATE_D1, - AHD_POWER_STATE_D2, - AHD_POWER_STATE_D3 -} ahd_power_state; - -void ahd_power_state_change(struct ahd_softc *ahd, - ahd_power_state new_state); - -/******************************* PCI Routines *********************************/ -int ahd_linux_pci_init(void); -void ahd_linux_pci_exit(void); -int ahd_pci_map_registers(struct ahd_softc *ahd); -int ahd_pci_map_int(struct ahd_softc *ahd); - -uint32_t ahd_pci_read_config(ahd_dev_softc_t pci, - int reg, int width); -void ahd_pci_write_config(ahd_dev_softc_t pci, - int reg, uint32_t value, - int width); - -static inline int ahd_get_pci_function(ahd_dev_softc_t); -static inline int -ahd_get_pci_function(ahd_dev_softc_t pci) -{ - return (PCI_FUNC(pci->devfn)); -} - -static inline int ahd_get_pci_slot(ahd_dev_softc_t); -static inline int -ahd_get_pci_slot(ahd_dev_softc_t pci) -{ - return (PCI_SLOT(pci->devfn)); -} - -static inline int ahd_get_pci_bus(ahd_dev_softc_t); -static inline int -ahd_get_pci_bus(ahd_dev_softc_t pci) -{ - return (pci->bus->number); -} - -static inline void ahd_flush_device_writes(struct ahd_softc *); -static inline void -ahd_flush_device_writes(struct ahd_softc *ahd) -{ - /* XXX Is this sufficient for all architectures??? */ - ahd_inb(ahd, INTSTAT); -} - -/**************************** Proc FS Support *********************************/ -int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, - off_t, int, int); - -/*********************** Transaction Access Wrappers **************************/ -static inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); -static inline void ahd_set_transaction_status(struct scb *, uint32_t); -static inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); -static inline void ahd_set_scsi_status(struct scb *, uint32_t); -static inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd); -static inline uint32_t ahd_get_transaction_status(struct scb *); -static inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd); -static inline uint32_t ahd_get_scsi_status(struct scb *); -static inline void ahd_set_transaction_tag(struct scb *, int, u_int); -static inline u_long ahd_get_transfer_length(struct scb *); -static inline int ahd_get_transfer_dir(struct scb *); -static inline void ahd_set_residual(struct scb *, u_long); -static inline void ahd_set_sense_residual(struct scb *scb, u_long resid); -static inline u_long ahd_get_residual(struct scb *); -static inline u_long ahd_get_sense_residual(struct scb *); -static inline int ahd_perform_autosense(struct scb *); -static inline uint32_t ahd_get_sense_bufsize(struct ahd_softc *, - struct scb *); -static inline void ahd_notify_xfer_settings_change(struct ahd_softc *, - struct ahd_devinfo *); -static inline void ahd_platform_scb_free(struct ahd_softc *ahd, - struct scb *scb); -static inline void ahd_freeze_scb(struct scb *scb); - -static inline -void ahd_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) -{ - cmd->result &= ~(CAM_STATUS_MASK << 16); - cmd->result |= status << 16; -} - -static inline -void ahd_set_transaction_status(struct scb *scb, uint32_t status) -{ - ahd_cmd_set_transaction_status(scb->io_ctx,status); -} - -static inline -void ahd_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) -{ - cmd->result &= ~0xFFFF; - cmd->result |= status; -} - -static inline -void ahd_set_scsi_status(struct scb *scb, uint32_t status) -{ - ahd_cmd_set_scsi_status(scb->io_ctx, status); -} - -static inline -uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd) -{ - return ((cmd->result >> 16) & CAM_STATUS_MASK); -} - -static inline -uint32_t ahd_get_transaction_status(struct scb *scb) -{ - return (ahd_cmd_get_transaction_status(scb->io_ctx)); -} - -static inline -uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd) -{ - return (cmd->result & 0xFFFF); -} - -static inline -uint32_t ahd_get_scsi_status(struct scb *scb) -{ - return (ahd_cmd_get_scsi_status(scb->io_ctx)); -} - -static inline -void ahd_set_transaction_tag(struct scb *scb, int enabled, u_int type) -{ - /* - * Nothing to do for linux as the incoming transaction - * has no concept of tag/non tagged, etc. - */ -} - -static inline -u_long ahd_get_transfer_length(struct scb *scb) -{ - return (scb->platform_data->xfer_len); -} - -static inline -int ahd_get_transfer_dir(struct scb *scb) -{ - return (scb->io_ctx->sc_data_direction); -} - -static inline -void ahd_set_residual(struct scb *scb, u_long resid) -{ - scsi_set_resid(scb->io_ctx, resid); -} - -static inline -void ahd_set_sense_residual(struct scb *scb, u_long resid) -{ - scb->platform_data->sense_resid = resid; -} - -static inline -u_long ahd_get_residual(struct scb *scb) -{ - return scsi_get_resid(scb->io_ctx); -} - -static inline -u_long ahd_get_sense_residual(struct scb *scb) -{ - return (scb->platform_data->sense_resid); -} - -static inline -int ahd_perform_autosense(struct scb *scb) -{ - /* - * We always perform autosense in Linux. - * On other platforms this is set on a - * per-transaction basis. - */ - return (1); -} - -static inline uint32_t -ahd_get_sense_bufsize(struct ahd_softc *ahd, struct scb *scb) -{ - return (sizeof(struct scsi_sense_data)); -} - -static inline void -ahd_notify_xfer_settings_change(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo) -{ - /* Nothing to do here for linux */ -} - -static inline void -ahd_platform_scb_free(struct ahd_softc *ahd, struct scb *scb) -{ - ahd->flags &= ~AHD_RESOURCE_SHORTAGE; -} - -int ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg); -void ahd_platform_free(struct ahd_softc *ahd); -void ahd_platform_init(struct ahd_softc *ahd); -void ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb); - -static inline void -ahd_freeze_scb(struct scb *scb) -{ - if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { - scb->io_ctx->result |= CAM_DEV_QFRZN << 16; - scb->platform_data->dev->qfrozen++; - } -} - -void ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev, - struct ahd_devinfo *devinfo, ahd_queue_alg); -int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status); -irqreturn_t - ahd_linux_isr(int irq, void *dev_id); -void ahd_done(struct ahd_softc*, struct scb*); -void ahd_send_async(struct ahd_softc *, char channel, - u_int target, u_int lun, ac_code); -void ahd_print_path(struct ahd_softc *, struct scb *); - -#ifdef CONFIG_PCI -#define AHD_PCI_CONFIG 1 -#else -#define AHD_PCI_CONFIG 0 -#endif -#define bootverbose aic79xx_verbose -extern uint32_t aic79xx_verbose; - -#endif /* _AIC79XX_LINUX_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm_pci.c deleted file mode 100644 index 3c85873b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Linux driver attachment glue for PCI based U320 controllers. - * - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#25 $ - */ - -#include "aic79xx_osm.h" -#include "aic79xx_inline.h" -#include "aic79xx_pci.h" - -/* Define the macro locally since it's different for different class of chips. - */ -#define ID(x) \ - ID2C(x), \ - ID2C(IDIROC(x)) - -static const struct pci_device_id ahd_linux_pci_id_table[] = { - /* aic7901 based controllers */ - ID(ID_AHA_29320A), - ID(ID_AHA_29320ALP), - ID(ID_AHA_29320LPE), - /* aic7902 based controllers */ - ID(ID_AHA_29320), - ID(ID_AHA_29320B), - ID(ID_AHA_29320LP), - ID(ID_AHA_39320), - ID(ID_AHA_39320_B), - ID(ID_AHA_39320A), - ID(ID_AHA_39320D), - ID(ID_AHA_39320D_HP), - ID(ID_AHA_39320D_B), - ID(ID_AHA_39320D_B_HP), - /* Generic chip probes for devices we don't know exactly. */ - ID16(ID_AIC7901 & ID_9005_GENERIC_MASK), - ID(ID_AIC7901A & ID_DEV_VENDOR_MASK), - ID16(ID_AIC7902 & ID_9005_GENERIC_MASK), - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table); - -#ifdef CONFIG_PM -static int -ahd_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) -{ - struct ahd_softc *ahd = pci_get_drvdata(pdev); - int rc; - - if ((rc = ahd_suspend(ahd))) - return rc; - - ahd_pci_suspend(ahd); - - pci_save_state(pdev); - pci_disable_device(pdev); - - if (mesg.event & PM_EVENT_SLEEP) - pci_set_power_state(pdev, PCI_D3hot); - - return rc; -} - -static int -ahd_linux_pci_dev_resume(struct pci_dev *pdev) -{ - struct ahd_softc *ahd = pci_get_drvdata(pdev); - int rc; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - if ((rc = pci_enable_device(pdev))) { - dev_printk(KERN_ERR, &pdev->dev, - "failed to enable device after resume (%d)\n", rc); - return rc; - } - - pci_set_master(pdev); - - ahd_pci_resume(ahd); - - ahd_resume(ahd); - - return rc; -} -#endif - -static void -ahd_linux_pci_dev_remove(struct pci_dev *pdev) -{ - struct ahd_softc *ahd = pci_get_drvdata(pdev); - u_long s; - - if (ahd->platform_data && ahd->platform_data->host) - scsi_remove_host(ahd->platform_data->host); - - ahd_lock(ahd, &s); - ahd_intr_enable(ahd, FALSE); - ahd_unlock(ahd, &s); - ahd_free(ahd); -} - -static void -ahd_linux_pci_inherit_flags(struct ahd_softc *ahd) -{ - struct pci_dev *pdev = ahd->dev_softc, *master_pdev; - unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); - - master_pdev = pci_get_slot(pdev->bus, master_devfn); - if (master_pdev) { - struct ahd_softc *master = pci_get_drvdata(master_pdev); - if (master) { - ahd->flags &= ~AHD_BIOS_ENABLED; - ahd->flags |= master->flags & AHD_BIOS_ENABLED; - } else - printk(KERN_ERR "aic79xx: no multichannel peer found!\n"); - pci_dev_put(master_pdev); - } -} - -static int -ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - char buf[80]; - struct ahd_softc *ahd; - ahd_dev_softc_t pci; - const struct ahd_pci_identity *entry; - char *name; - int error; - struct device *dev = &pdev->dev; - - pci = pdev; - entry = ahd_find_pci_device(pci); - if (entry == NULL) - return (-ENODEV); - - /* - * Allocate a softc for this card and - * set it up for attachment by our - * common detect routine. - */ - sprintf(buf, "ahd_pci:%d:%d:%d", - ahd_get_pci_bus(pci), - ahd_get_pci_slot(pci), - ahd_get_pci_function(pci)); - name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); - if (name == NULL) - return (-ENOMEM); - strcpy(name, buf); - ahd = ahd_alloc(NULL, name); - if (ahd == NULL) - return (-ENOMEM); - if (pci_enable_device(pdev)) { - ahd_free(ahd); - return (-ENODEV); - } - pci_set_master(pdev); - - if (sizeof(dma_addr_t) > 4) { - const u64 required_mask = dma_get_required_mask(dev); - - if (required_mask > DMA_BIT_MASK(39) && - dma_set_mask(dev, DMA_BIT_MASK(64)) == 0) - ahd->flags |= AHD_64BIT_ADDRESSING; - else if (required_mask > DMA_BIT_MASK(32) && - dma_set_mask(dev, DMA_BIT_MASK(39)) == 0) - ahd->flags |= AHD_39BIT_ADDRESSING; - else - dma_set_mask(dev, DMA_BIT_MASK(32)); - } else { - dma_set_mask(dev, DMA_BIT_MASK(32)); - } - ahd->dev_softc = pci; - error = ahd_pci_config(ahd, entry); - if (error != 0) { - ahd_free(ahd); - return (-error); - } - - /* - * Second Function PCI devices need to inherit some - * * settings from function 0. - */ - if ((ahd->features & AHD_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0) - ahd_linux_pci_inherit_flags(ahd); - - pci_set_drvdata(pdev, ahd); - - ahd_linux_register_host(ahd, &aic79xx_driver_template); - return (0); -} - -static struct pci_driver aic79xx_pci_driver = { - .name = "aic79xx", - .probe = ahd_linux_pci_dev_probe, -#ifdef CONFIG_PM - .suspend = ahd_linux_pci_dev_suspend, - .resume = ahd_linux_pci_dev_resume, -#endif - .remove = ahd_linux_pci_dev_remove, - .id_table = ahd_linux_pci_id_table -}; - -int -ahd_linux_pci_init(void) -{ - return pci_register_driver(&aic79xx_pci_driver); -} - -void -ahd_linux_pci_exit(void) -{ - pci_unregister_driver(&aic79xx_pci_driver); -} - -static int -ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, resource_size_t *base, - resource_size_t *base2) -{ - *base = pci_resource_start(ahd->dev_softc, 0); - /* - * This is really the 3rd bar and should be at index 2, - * but the Linux PCI code doesn't know how to "count" 64bit - * bars. - */ - *base2 = pci_resource_start(ahd->dev_softc, 3); - if (*base == 0 || *base2 == 0) - return (ENOMEM); - if (!request_region(*base, 256, "aic79xx")) - return (ENOMEM); - if (!request_region(*base2, 256, "aic79xx")) { - release_region(*base, 256); - return (ENOMEM); - } - return (0); -} - -static int -ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd, - resource_size_t *bus_addr, - uint8_t __iomem **maddr) -{ - resource_size_t start; - resource_size_t base_page; - u_long base_offset; - int error = 0; - - if (aic79xx_allow_memio == 0) - return (ENOMEM); - - if ((ahd->bugs & AHD_PCIX_MMAPIO_BUG) != 0) - return (ENOMEM); - - start = pci_resource_start(ahd->dev_softc, 1); - base_page = start & PAGE_MASK; - base_offset = start - base_page; - if (start != 0) { - *bus_addr = start; - if (!request_mem_region(start, 0x1000, "aic79xx")) - error = ENOMEM; - if (!error) { - *maddr = ioremap_nocache(base_page, base_offset + 512); - if (*maddr == NULL) { - error = ENOMEM; - release_mem_region(start, 0x1000); - } else - *maddr += base_offset; - } - } else - error = ENOMEM; - return (error); -} - -int -ahd_pci_map_registers(struct ahd_softc *ahd) -{ - uint32_t command; - resource_size_t base; - uint8_t __iomem *maddr; - int error; - - /* - * If its allowed, we prefer memory mapped access. - */ - command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4); - command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN); - base = 0; - maddr = NULL; - error = ahd_linux_pci_reserve_mem_region(ahd, &base, &maddr); - if (error == 0) { - ahd->platform_data->mem_busaddr = base; - ahd->tags[0] = BUS_SPACE_MEMIO; - ahd->bshs[0].maddr = maddr; - ahd->tags[1] = BUS_SPACE_MEMIO; - ahd->bshs[1].maddr = maddr + 0x100; - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, - command | PCIM_CMD_MEMEN, 4); - - if (ahd_pci_test_register_access(ahd) != 0) { - - printk("aic79xx: PCI Device %d:%d:%d " - "failed memory mapped test. Using PIO.\n", - ahd_get_pci_bus(ahd->dev_softc), - ahd_get_pci_slot(ahd->dev_softc), - ahd_get_pci_function(ahd->dev_softc)); - iounmap(maddr); - release_mem_region(ahd->platform_data->mem_busaddr, - 0x1000); - ahd->bshs[0].maddr = NULL; - maddr = NULL; - } else - command |= PCIM_CMD_MEMEN; - } else if (bootverbose) { - printk("aic79xx: PCI%d:%d:%d MEM region 0x%llx " - "unavailable. Cannot memory map device.\n", - ahd_get_pci_bus(ahd->dev_softc), - ahd_get_pci_slot(ahd->dev_softc), - ahd_get_pci_function(ahd->dev_softc), - (unsigned long long)base); - } - - if (maddr == NULL) { - resource_size_t base2; - - error = ahd_linux_pci_reserve_io_regions(ahd, &base, &base2); - if (error == 0) { - ahd->tags[0] = BUS_SPACE_PIO; - ahd->tags[1] = BUS_SPACE_PIO; - ahd->bshs[0].ioport = (u_long)base; - ahd->bshs[1].ioport = (u_long)base2; - command |= PCIM_CMD_PORTEN; - } else { - printk("aic79xx: PCI%d:%d:%d IO regions 0x%llx and " - "0x%llx unavailable. Cannot map device.\n", - ahd_get_pci_bus(ahd->dev_softc), - ahd_get_pci_slot(ahd->dev_softc), - ahd_get_pci_function(ahd->dev_softc), - (unsigned long long)base, - (unsigned long long)base2); - } - } - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4); - return (error); -} - -int -ahd_pci_map_int(struct ahd_softc *ahd) -{ - int error; - - error = request_irq(ahd->dev_softc->irq, ahd_linux_isr, - IRQF_SHARED, "aic79xx", ahd); - if (!error) - ahd->platform_data->irq = ahd->dev_softc->irq; - - return (-error); -} - -void -ahd_power_state_change(struct ahd_softc *ahd, ahd_power_state new_state) -{ - pci_set_power_state(ahd->dev_softc, new_state); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.c deleted file mode 100644 index 14b5f8d0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.c +++ /dev/null @@ -1,1022 +0,0 @@ -/* - * Product specific probe and attach routines for: - * aic7901 and aic7902 SCSI controllers - * - * Copyright (c) 1994-2001 Justin T. Gibbs. - * Copyright (c) 2000-2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#92 $ - */ - -#ifdef __linux__ -#include "aic79xx_osm.h" -#include "aic79xx_inline.h" -#else -#include -#include -#endif - -#include "aic79xx_pci.h" - -static inline uint64_t -ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) -{ - uint64_t id; - - id = subvendor - | (subdevice << 16) - | ((uint64_t)vendor << 32) - | ((uint64_t)device << 48); - - return (id); -} - -#define ID_AIC7902_PCI_REV_A4 0x3 -#define ID_AIC7902_PCI_REV_B0 0x10 -#define SUBID_HP 0x0E11 - -#define DEVID_9005_HOSTRAID(id) ((id) & 0x80) - -#define DEVID_9005_TYPE(id) ((id) & 0xF) -#define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */ -#define DEVID_9005_TYPE_HBA_2EXT 0x1 /* 2 External Ports */ -#define DEVID_9005_TYPE_IROC 0x8 /* Raid(0,1,10) Card */ -#define DEVID_9005_TYPE_MB 0xF /* On Motherboard */ - -#define DEVID_9005_MFUNC(id) ((id) & 0x10) - -#define DEVID_9005_PACKETIZED(id) ((id) & 0x8000) - -#define SUBID_9005_TYPE(id) ((id) & 0xF) -#define SUBID_9005_TYPE_HBA 0x0 /* Standard Card */ -#define SUBID_9005_TYPE_MB 0xF /* On Motherboard */ - -#define SUBID_9005_AUTOTERM(id) (((id) & 0x10) == 0) - -#define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20) - -#define SUBID_9005_SEEPTYPE(id) (((id) & 0x0C0) >> 6) -#define SUBID_9005_SEEPTYPE_NONE 0x0 -#define SUBID_9005_SEEPTYPE_4K 0x1 - -static ahd_device_setup_t ahd_aic7901_setup; -static ahd_device_setup_t ahd_aic7901A_setup; -static ahd_device_setup_t ahd_aic7902_setup; -static ahd_device_setup_t ahd_aic790X_setup; - -static const struct ahd_pci_identity ahd_pci_ident_table[] = -{ - /* aic7901 based controllers */ - { - ID_AHA_29320A, - ID_ALL_MASK, - "Adaptec 29320A Ultra320 SCSI adapter", - ahd_aic7901_setup - }, - { - ID_AHA_29320ALP, - ID_ALL_MASK, - "Adaptec 29320ALP PCIx Ultra320 SCSI adapter", - ahd_aic7901_setup - }, - { - ID_AHA_29320LPE, - ID_ALL_MASK, - "Adaptec 29320LPE PCIe Ultra320 SCSI adapter", - ahd_aic7901_setup - }, - /* aic7901A based controllers */ - { - ID_AHA_29320LP, - ID_ALL_MASK, - "Adaptec 29320LP Ultra320 SCSI adapter", - ahd_aic7901A_setup - }, - /* aic7902 based controllers */ - { - ID_AHA_29320, - ID_ALL_MASK, - "Adaptec 29320 Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_29320B, - ID_ALL_MASK, - "Adaptec 29320B Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_39320, - ID_ALL_MASK, - "Adaptec 39320 Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_39320_B, - ID_ALL_MASK, - "Adaptec 39320 Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_39320_B_DELL, - ID_ALL_MASK, - "Adaptec (Dell OEM) 39320 Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_39320A, - ID_ALL_MASK, - "Adaptec 39320A Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_39320D, - ID_ALL_MASK, - "Adaptec 39320D Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_39320D_HP, - ID_ALL_MASK, - "Adaptec (HP OEM) 39320D Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_39320D_B, - ID_ALL_MASK, - "Adaptec 39320D Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - { - ID_AHA_39320D_B_HP, - ID_ALL_MASK, - "Adaptec (HP OEM) 39320D Ultra320 SCSI adapter", - ahd_aic7902_setup - }, - /* Generic chip probes for devices we don't know 'exactly' */ - { - ID_AIC7901 & ID_9005_GENERIC_MASK, - ID_9005_GENERIC_MASK, - "Adaptec AIC7901 Ultra320 SCSI adapter", - ahd_aic7901_setup - }, - { - ID_AIC7901A & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec AIC7901A Ultra320 SCSI adapter", - ahd_aic7901A_setup - }, - { - ID_AIC7902 & ID_9005_GENERIC_MASK, - ID_9005_GENERIC_MASK, - "Adaptec AIC7902 Ultra320 SCSI adapter", - ahd_aic7902_setup - } -}; - -static const u_int ahd_num_pci_devs = ARRAY_SIZE(ahd_pci_ident_table); - -#define DEVCONFIG 0x40 -#define PCIXINITPAT 0x0000E000ul -#define PCIXINIT_PCI33_66 0x0000E000ul -#define PCIXINIT_PCIX50_66 0x0000C000ul -#define PCIXINIT_PCIX66_100 0x0000A000ul -#define PCIXINIT_PCIX100_133 0x00008000ul -#define PCI_BUS_MODES_INDEX(devconfig) \ - (((devconfig) & PCIXINITPAT) >> 13) -static const char *pci_bus_modes[] = -{ - "PCI bus mode unknown", - "PCI bus mode unknown", - "PCI bus mode unknown", - "PCI bus mode unknown", - "PCI-X 101-133MHz", - "PCI-X 67-100MHz", - "PCI-X 50-66MHz", - "PCI 33 or 66MHz" -}; - -#define TESTMODE 0x00000800ul -#define IRDY_RST 0x00000200ul -#define FRAME_RST 0x00000100ul -#define PCI64BIT 0x00000080ul -#define MRDCEN 0x00000040ul -#define ENDIANSEL 0x00000020ul -#define MIXQWENDIANEN 0x00000008ul -#define DACEN 0x00000004ul -#define STPWLEVEL 0x00000002ul -#define QWENDIANSEL 0x00000001ul - -#define DEVCONFIG1 0x44 -#define PREQDIS 0x01 - -#define CSIZE_LATTIME 0x0c -#define CACHESIZE 0x000000fful -#define LATTIME 0x0000ff00ul - -static int ahd_check_extport(struct ahd_softc *ahd); -static void ahd_configure_termination(struct ahd_softc *ahd, - u_int adapter_control); -static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat); -static void ahd_pci_intr(struct ahd_softc *ahd); - -const struct ahd_pci_identity * -ahd_find_pci_device(ahd_dev_softc_t pci) -{ - uint64_t full_id; - uint16_t device; - uint16_t vendor; - uint16_t subdevice; - uint16_t subvendor; - const struct ahd_pci_identity *entry; - u_int i; - - vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); - device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); - subvendor = ahd_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); - subdevice = ahd_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); - full_id = ahd_compose_id(device, - vendor, - subdevice, - subvendor); - - /* - * Controllers, mask out the IROC/HostRAID bit - */ - - full_id &= ID_ALL_IROC_MASK; - - for (i = 0; i < ahd_num_pci_devs; i++) { - entry = &ahd_pci_ident_table[i]; - if (entry->full_id == (full_id & entry->id_mask)) { - /* Honor exclusion entries. */ - if (entry->name == NULL) - return (NULL); - return (entry); - } - } - return (NULL); -} - -int -ahd_pci_config(struct ahd_softc *ahd, const struct ahd_pci_identity *entry) -{ - struct scb_data *shared_scb_data; - u_int command; - uint32_t devconfig; - uint16_t subvendor; - int error; - - shared_scb_data = NULL; - ahd->description = entry->name; - /* - * Record if this is an HP board. - */ - subvendor = ahd_pci_read_config(ahd->dev_softc, - PCIR_SUBVEND_0, /*bytes*/2); - if (subvendor == SUBID_HP) - ahd->flags |= AHD_HP_BOARD; - - error = entry->setup(ahd); - if (error != 0) - return (error); - - devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); - if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) { - ahd->chip |= AHD_PCI; - /* Disable PCIX workarounds when running in PCI mode. */ - ahd->bugs &= ~AHD_PCIX_BUG_MASK; - } else { - ahd->chip |= AHD_PCIX; - } - ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)]; - - ahd_power_state_change(ahd, AHD_POWER_STATE_D0); - - error = ahd_pci_map_registers(ahd); - if (error != 0) - return (error); - - /* - * If we need to support high memory, enable dual - * address cycles. This bit must be set to enable - * high address bit generation even if we are on a - * 64bit bus (PCI64BIT set in devconfig). - */ - if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) { - if (bootverbose) - printk("%s: Enabling 39Bit Addressing\n", - ahd_name(ahd)); - devconfig = ahd_pci_read_config(ahd->dev_softc, - DEVCONFIG, /*bytes*/4); - devconfig |= DACEN; - ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, - devconfig, /*bytes*/4); - } - - /* Ensure busmastering is enabled */ - command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); - command |= PCIM_CMD_BUSMASTEREN; - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2); - - error = ahd_softc_init(ahd); - if (error != 0) - return (error); - - ahd->bus_intr = ahd_pci_intr; - - error = ahd_reset(ahd, /*reinit*/FALSE); - if (error != 0) - return (ENXIO); - - ahd->pci_cachesize = - ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME, - /*bytes*/1) & CACHESIZE; - ahd->pci_cachesize *= 4; - - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - /* See if we have a SEEPROM and perform auto-term */ - error = ahd_check_extport(ahd); - if (error != 0) - return (error); - - /* Core initialization */ - error = ahd_init(ahd); - if (error != 0) - return (error); - ahd->init_level++; - - /* - * Allow interrupts now that we are completely setup. - */ - return ahd_pci_map_int(ahd); -} - -#ifdef CONFIG_PM -void -ahd_pci_suspend(struct ahd_softc *ahd) -{ - /* - * Save chip register configuration data for chip resets - * that occur during runtime and resume events. - */ - ahd->suspend_state.pci_state.devconfig = - ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); - ahd->suspend_state.pci_state.command = - ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1); - ahd->suspend_state.pci_state.csize_lattime = - ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME, /*bytes*/1); - -} - -void -ahd_pci_resume(struct ahd_softc *ahd) -{ - ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, - ahd->suspend_state.pci_state.devconfig, /*bytes*/4); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, - ahd->suspend_state.pci_state.command, /*bytes*/1); - ahd_pci_write_config(ahd->dev_softc, CSIZE_LATTIME, - ahd->suspend_state.pci_state.csize_lattime, /*bytes*/1); -} -#endif - -/* - * Perform some simple tests that should catch situations where - * our registers are invalidly mapped. - */ -int -ahd_pci_test_register_access(struct ahd_softc *ahd) -{ - uint32_t cmd; - u_int targpcistat; - u_int pci_status1; - int error; - uint8_t hcntrl; - - error = EIO; - - /* - * Enable PCI error interrupt status, but suppress NMIs - * generated by SERR raised due to target aborts. - */ - cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, - cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2); - - /* - * First a simple test to see if any - * registers can be read. Reading - * HCNTRL has no side effects and has - * at least one bit that is guaranteed to - * be zero so it is a good register to - * use for this test. - */ - hcntrl = ahd_inb(ahd, HCNTRL); - if (hcntrl == 0xFF) - goto fail; - - /* - * Next create a situation where write combining - * or read prefetching could be initiated by the - * CPU or host bridge. Our device does not support - * either, so look for data corruption and/or flaged - * PCI errors. First pause without causing another - * chip reset. - */ - hcntrl &= ~CHIPRST; - ahd_outb(ahd, HCNTRL, hcntrl|PAUSE); - while (ahd_is_paused(ahd) == 0) - ; - - /* Clear any PCI errors that occurred before our driver attached. */ - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - targpcistat = ahd_inb(ahd, TARGPCISTAT); - ahd_outb(ahd, TARGPCISTAT, targpcistat); - pci_status1 = ahd_pci_read_config(ahd->dev_softc, - PCIR_STATUS + 1, /*bytes*/1); - ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, - pci_status1, /*bytes*/1); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - ahd_outb(ahd, CLRINT, CLRPCIINT); - - ahd_outb(ahd, SEQCTL0, PERRORDIS); - ahd_outl(ahd, SRAM_BASE, 0x5aa555aa); - if (ahd_inl(ahd, SRAM_BASE) != 0x5aa555aa) - goto fail; - - if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) { - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - targpcistat = ahd_inb(ahd, TARGPCISTAT); - if ((targpcistat & STA) != 0) - goto fail; - } - - error = 0; - -fail: - if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) { - - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - targpcistat = ahd_inb(ahd, TARGPCISTAT); - - /* Silently clear any latched errors. */ - ahd_outb(ahd, TARGPCISTAT, targpcistat); - pci_status1 = ahd_pci_read_config(ahd->dev_softc, - PCIR_STATUS + 1, /*bytes*/1); - ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, - pci_status1, /*bytes*/1); - ahd_outb(ahd, CLRINT, CLRPCIINT); - } - ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS); - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); - return (error); -} - -/* - * Check the external port logic for a serial eeprom - * and termination/cable detection contrls. - */ -static int -ahd_check_extport(struct ahd_softc *ahd) -{ - struct vpd_config vpd; - struct seeprom_config *sc; - u_int adapter_control; - int have_seeprom; - int error; - - sc = ahd->seep_config; - have_seeprom = ahd_acquire_seeprom(ahd); - if (have_seeprom) { - u_int start_addr; - - /* - * Fetch VPD for this function and parse it. - */ - if (bootverbose) - printk("%s: Reading VPD from SEEPROM...", - ahd_name(ahd)); - - /* Address is always in units of 16bit words */ - start_addr = ((2 * sizeof(*sc)) - + (sizeof(vpd) * (ahd->channel - 'A'))) / 2; - - error = ahd_read_seeprom(ahd, (uint16_t *)&vpd, - start_addr, sizeof(vpd)/2, - /*bytestream*/TRUE); - if (error == 0) - error = ahd_parse_vpddata(ahd, &vpd); - if (bootverbose) - printk("%s: VPD parsing %s\n", - ahd_name(ahd), - error == 0 ? "successful" : "failed"); - - if (bootverbose) - printk("%s: Reading SEEPROM...", ahd_name(ahd)); - - /* Address is always in units of 16bit words */ - start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A'); - - error = ahd_read_seeprom(ahd, (uint16_t *)sc, - start_addr, sizeof(*sc)/2, - /*bytestream*/FALSE); - - if (error != 0) { - printk("Unable to read SEEPROM\n"); - have_seeprom = 0; - } else { - have_seeprom = ahd_verify_cksum(sc); - - if (bootverbose) { - if (have_seeprom == 0) - printk ("checksum error\n"); - else - printk ("done.\n"); - } - } - ahd_release_seeprom(ahd); - } - - if (!have_seeprom) { - u_int nvram_scb; - - /* - * Pull scratch ram settings and treat them as - * if they are the contents of an seeprom if - * the 'ADPT', 'BIOS', or 'ASPI' signature is found - * in SCB 0xFF. We manually compose the data as 16bit - * values to avoid endian issues. - */ - ahd_set_scbptr(ahd, 0xFF); - nvram_scb = ahd_inb_scbram(ahd, SCB_BASE + NVRAM_SCB_OFFSET); - if (nvram_scb != 0xFF - && ((ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A' - && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'D' - && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P' - && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'T') - || (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'B' - && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'I' - && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'O' - && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'S') - || (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A' - && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'S' - && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P' - && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'I'))) { - uint16_t *sc_data; - int i; - - ahd_set_scbptr(ahd, nvram_scb); - sc_data = (uint16_t *)sc; - for (i = 0; i < 64; i += 2) - *sc_data++ = ahd_inw_scbram(ahd, SCB_BASE+i); - have_seeprom = ahd_verify_cksum(sc); - if (have_seeprom) - ahd->flags |= AHD_SCB_CONFIG_USED; - } - } - -#ifdef AHD_DEBUG - if (have_seeprom != 0 - && (ahd_debug & AHD_DUMP_SEEPROM) != 0) { - uint16_t *sc_data; - int i; - - printk("%s: Seeprom Contents:", ahd_name(ahd)); - sc_data = (uint16_t *)sc; - for (i = 0; i < (sizeof(*sc)); i += 2) - printk("\n\t0x%.4x", sc_data[i]); - printk("\n"); - } -#endif - - if (!have_seeprom) { - if (bootverbose) - printk("%s: No SEEPROM available.\n", ahd_name(ahd)); - ahd->flags |= AHD_USEDEFAULTS; - error = ahd_default_config(ahd); - adapter_control = CFAUTOTERM|CFSEAUTOTERM; - kfree(ahd->seep_config); - ahd->seep_config = NULL; - } else { - error = ahd_parse_cfgdata(ahd, sc); - adapter_control = sc->adapter_control; - } - if (error != 0) - return (error); - - ahd_configure_termination(ahd, adapter_control); - - return (0); -} - -static void -ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control) -{ - int error; - u_int sxfrctl1; - uint8_t termctl; - uint32_t devconfig; - - devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4); - devconfig &= ~STPWLEVEL; - if ((ahd->flags & AHD_STPWLEVEL_A) != 0) - devconfig |= STPWLEVEL; - if (bootverbose) - printk("%s: STPWLEVEL is %s\n", - ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off"); - ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); - - /* Make sure current sensing is off. */ - if ((ahd->flags & AHD_CURRENT_SENSING) != 0) { - (void)ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0); - } - - /* - * Read to sense. Write to set. - */ - error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl); - if ((adapter_control & CFAUTOTERM) == 0) { - if (bootverbose) - printk("%s: Manual Primary Termination\n", - ahd_name(ahd)); - termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH); - if ((adapter_control & CFSTERM) != 0) - termctl |= FLX_TERMCTL_ENPRILOW; - if ((adapter_control & CFWSTERM) != 0) - termctl |= FLX_TERMCTL_ENPRIHIGH; - } else if (error != 0) { - printk("%s: Primary Auto-Term Sensing failed! " - "Using Defaults.\n", ahd_name(ahd)); - termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH; - } - - if ((adapter_control & CFSEAUTOTERM) == 0) { - if (bootverbose) - printk("%s: Manual Secondary Termination\n", - ahd_name(ahd)); - termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH); - if ((adapter_control & CFSELOWTERM) != 0) - termctl |= FLX_TERMCTL_ENSECLOW; - if ((adapter_control & CFSEHIGHTERM) != 0) - termctl |= FLX_TERMCTL_ENSECHIGH; - } else if (error != 0) { - printk("%s: Secondary Auto-Term Sensing failed! " - "Using Defaults.\n", ahd_name(ahd)); - termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH; - } - - /* - * Now set the termination based on what we found. - */ - sxfrctl1 = ahd_inb(ahd, SXFRCTL1) & ~STPWEN; - ahd->flags &= ~AHD_TERM_ENB_A; - if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) { - ahd->flags |= AHD_TERM_ENB_A; - sxfrctl1 |= STPWEN; - } - /* Must set the latch once in order to be effective. */ - ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN); - ahd_outb(ahd, SXFRCTL1, sxfrctl1); - - error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl); - if (error != 0) { - printk("%s: Unable to set termination settings!\n", - ahd_name(ahd)); - } else if (bootverbose) { - printk("%s: Primary High byte termination %sabled\n", - ahd_name(ahd), - (termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis"); - - printk("%s: Primary Low byte termination %sabled\n", - ahd_name(ahd), - (termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis"); - - printk("%s: Secondary High byte termination %sabled\n", - ahd_name(ahd), - (termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis"); - - printk("%s: Secondary Low byte termination %sabled\n", - ahd_name(ahd), - (termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis"); - } - return; -} - -#define DPE 0x80 -#define SSE 0x40 -#define RMA 0x20 -#define RTA 0x10 -#define STA 0x08 -#define DPR 0x01 - -static const char *split_status_source[] = -{ - "DFF0", - "DFF1", - "OVLY", - "CMC", -}; - -static const char *pci_status_source[] = -{ - "DFF0", - "DFF1", - "SG", - "CMC", - "OVLY", - "NONE", - "MSI", - "TARG" -}; - -static const char *split_status_strings[] = -{ - "%s: Received split response in %s.\n", - "%s: Received split completion error message in %s\n", - "%s: Receive overrun in %s\n", - "%s: Count not complete in %s\n", - "%s: Split completion data bucket in %s\n", - "%s: Split completion address error in %s\n", - "%s: Split completion byte count error in %s\n", - "%s: Signaled Target-abort to early terminate a split in %s\n" -}; - -static const char *pci_status_strings[] = -{ - "%s: Data Parity Error has been reported via PERR# in %s\n", - "%s: Target initial wait state error in %s\n", - "%s: Split completion read data parity error in %s\n", - "%s: Split completion address attribute parity error in %s\n", - "%s: Received a Target Abort in %s\n", - "%s: Received a Master Abort in %s\n", - "%s: Signal System Error Detected in %s\n", - "%s: Address or Write Phase Parity Error Detected in %s.\n" -}; - -static void -ahd_pci_intr(struct ahd_softc *ahd) -{ - uint8_t pci_status[8]; - ahd_mode_state saved_modes; - u_int pci_status1; - u_int intstat; - u_int i; - u_int reg; - - intstat = ahd_inb(ahd, INTSTAT); - - if ((intstat & SPLTINT) != 0) - ahd_pci_split_intr(ahd, intstat); - - if ((intstat & PCIINT) == 0) - return; - - printk("%s: PCI error Interrupt\n", ahd_name(ahd)); - saved_modes = ahd_save_modes(ahd); - ahd_dump_card_state(ahd); - ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); - for (i = 0, reg = DF0PCISTAT; i < 8; i++, reg++) { - - if (i == 5) - continue; - pci_status[i] = ahd_inb(ahd, reg); - /* Clear latched errors. So our interrupt deasserts. */ - ahd_outb(ahd, reg, pci_status[i]); - } - - for (i = 0; i < 8; i++) { - u_int bit; - - if (i == 5) - continue; - - for (bit = 0; bit < 8; bit++) { - - if ((pci_status[i] & (0x1 << bit)) != 0) { - static const char *s; - - s = pci_status_strings[bit]; - if (i == 7/*TARG*/ && bit == 3) - s = "%s: Signaled Target Abort\n"; - printk(s, ahd_name(ahd), pci_status_source[i]); - } - } - } - pci_status1 = ahd_pci_read_config(ahd->dev_softc, - PCIR_STATUS + 1, /*bytes*/1); - ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, - pci_status1, /*bytes*/1); - ahd_restore_modes(ahd, saved_modes); - ahd_outb(ahd, CLRINT, CLRPCIINT); - ahd_unpause(ahd); -} - -static void -ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat) -{ - uint8_t split_status[4]; - uint8_t split_status1[4]; - uint8_t sg_split_status[2]; - uint8_t sg_split_status1[2]; - ahd_mode_state saved_modes; - u_int i; - uint16_t pcix_status; - - /* - * Check for splits in all modes. Modes 0 and 1 - * additionally have SG engine splits to look at. - */ - pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS, - /*bytes*/2); - printk("%s: PCI Split Interrupt - PCI-X status = 0x%x\n", - ahd_name(ahd), pcix_status); - saved_modes = ahd_save_modes(ahd); - for (i = 0; i < 4; i++) { - ahd_set_modes(ahd, i, i); - - split_status[i] = ahd_inb(ahd, DCHSPLTSTAT0); - split_status1[i] = ahd_inb(ahd, DCHSPLTSTAT1); - /* Clear latched errors. So our interrupt deasserts. */ - ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]); - ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]); - if (i > 1) - continue; - sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0); - sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1); - /* Clear latched errors. So our interrupt deasserts. */ - ahd_outb(ahd, SGSPLTSTAT0, sg_split_status[i]); - ahd_outb(ahd, SGSPLTSTAT1, sg_split_status1[i]); - } - - for (i = 0; i < 4; i++) { - u_int bit; - - for (bit = 0; bit < 8; bit++) { - - if ((split_status[i] & (0x1 << bit)) != 0) { - static const char *s; - - s = split_status_strings[bit]; - printk(s, ahd_name(ahd), - split_status_source[i]); - } - - if (i > 1) - continue; - - if ((sg_split_status[i] & (0x1 << bit)) != 0) { - static const char *s; - - s = split_status_strings[bit]; - printk(s, ahd_name(ahd), "SG"); - } - } - } - /* - * Clear PCI-X status bits. - */ - ahd_pci_write_config(ahd->dev_softc, PCIXR_STATUS, - pcix_status, /*bytes*/2); - ahd_outb(ahd, CLRINT, CLRSPLTINT); - ahd_restore_modes(ahd, saved_modes); -} - -static int -ahd_aic7901_setup(struct ahd_softc *ahd) -{ - - ahd->chip = AHD_AIC7901; - ahd->features = AHD_AIC7901_FE; - return (ahd_aic790X_setup(ahd)); -} - -static int -ahd_aic7901A_setup(struct ahd_softc *ahd) -{ - - ahd->chip = AHD_AIC7901A; - ahd->features = AHD_AIC7901A_FE; - return (ahd_aic790X_setup(ahd)); -} - -static int -ahd_aic7902_setup(struct ahd_softc *ahd) -{ - ahd->chip = AHD_AIC7902; - ahd->features = AHD_AIC7902_FE; - return (ahd_aic790X_setup(ahd)); -} - -static int -ahd_aic790X_setup(struct ahd_softc *ahd) -{ - ahd_dev_softc_t pci; - u_int rev; - - pci = ahd->dev_softc; - rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1); - if (rev < ID_AIC7902_PCI_REV_A4) { - printk("%s: Unable to attach to unsupported chip revision %d\n", - ahd_name(ahd), rev); - ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2); - return (ENXIO); - } - ahd->channel = ahd_get_pci_function(pci) + 'A'; - if (rev < ID_AIC7902_PCI_REV_B0) { - /* - * Enable A series workarounds. - */ - ahd->bugs |= AHD_SENT_SCB_UPDATE_BUG|AHD_ABORT_LQI_BUG - | AHD_PKT_BITBUCKET_BUG|AHD_LONG_SETIMO_BUG - | AHD_NLQICRC_DELAYED_BUG|AHD_SCSIRST_BUG - | AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG - | AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG - | AHD_PCIX_CHIPRST_BUG|AHD_PCIX_SCBRAM_RD_BUG - | AHD_PKTIZED_STATUS_BUG|AHD_PKT_LUN_BUG - | AHD_MDFF_WSCBPTR_BUG|AHD_REG_SLOW_SETTLE_BUG - | AHD_SET_MODE_BUG|AHD_BUSFREEREV_BUG - | AHD_NONPACKFIFO_BUG|AHD_PACED_NEGTABLE_BUG - | AHD_FAINT_LED_BUG; - - /* - * IO Cell parameter setup. - */ - AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29); - - if ((ahd->flags & AHD_HP_BOARD) == 0) - AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVA); - } else { - /* This is revision B and newer. */ - extern uint32_t aic79xx_slowcrc; - u_int devconfig1; - - ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS - | AHD_NEW_DFCNTRL_OPTS|AHD_FAST_CDB_DELIVERY - | AHD_BUSFREEREV_BUG; - ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG; - - /* If the user requested that the SLOWCRC bit to be set. */ - if (aic79xx_slowcrc) - ahd->features |= AHD_AIC79XXB_SLOWCRC; - - /* - * Some issues have been resolved in the 7901B. - */ - if ((ahd->features & AHD_MULTI_FUNC) != 0) - ahd->bugs |= AHD_INTCOLLISION_BUG|AHD_ABORT_LQI_BUG; - - /* - * IO Cell parameter setup. - */ - AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29); - AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVB); - AHD_SET_AMPLITUDE(ahd, AHD_AMPLITUDE_DEF); - - /* - * Set the PREQDIS bit for H2B which disables some workaround - * that doesn't work on regular PCI busses. - * XXX - Find out exactly what this does from the hardware - * folks! - */ - devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1); - ahd_pci_write_config(pci, DEVCONFIG1, - devconfig1|PREQDIS, /*bytes*/1); - devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1); - } - - return (0); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.h deleted file mode 100644 index 16b7c70a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_pci.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Adaptec AIC79xx device driver for Linux. - * - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id$ - * - */ -#ifndef _AIC79XX_PCI_H_ -#define _AIC79XX_PCI_H_ - -#define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull -#define ID_ALL_IROC_MASK 0xFF7FFFFFFFFFFFFFull -#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull -#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull -#define ID_9005_GENERIC_IROC_MASK 0xFF70FFFF00000000ull - -#define ID_AIC7901 0x800F9005FFFF9005ull -#define ID_AHA_29320A 0x8000900500609005ull -#define ID_AHA_29320ALP 0x8017900500449005ull -#define ID_AHA_29320LPE 0x8017900500459005ull - -#define ID_AIC7901A 0x801E9005FFFF9005ull -#define ID_AHA_29320LP 0x8014900500449005ull - -#define ID_AIC7902 0x801F9005FFFF9005ull -#define ID_AIC7902_B 0x801D9005FFFF9005ull -#define ID_AHA_39320 0x8010900500409005ull -#define ID_AHA_29320 0x8012900500429005ull -#define ID_AHA_29320B 0x8013900500439005ull -#define ID_AHA_39320_B 0x8015900500409005ull -#define ID_AHA_39320_B_DELL 0x8015900501681028ull -#define ID_AHA_39320A 0x8016900500409005ull -#define ID_AHA_39320D 0x8011900500419005ull -#define ID_AHA_39320D_B 0x801C900500419005ull -#define ID_AHA_39320D_HP 0x8011900500AC0E11ull -#define ID_AHA_39320D_B_HP 0x801C900500AC0E11ull - -#endif /* _AIC79XX_PCI_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_proc.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_proc.c deleted file mode 100644 index 59c85d5a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_proc.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * String handling code courtesy of Gerard Roudier's - * sym driver. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#19 $ - */ -#include "aic79xx_osm.h" -#include "aic79xx_inline.h" - -static void copy_mem_info(struct info_str *info, char *data, int len); -static int copy_info(struct info_str *info, char *fmt, ...); -static void ahd_dump_target_state(struct ahd_softc *ahd, - struct info_str *info, - u_int our_id, char channel, - u_int target_id); -static void ahd_dump_device_state(struct info_str *info, - struct scsi_device *sdev); -static int ahd_proc_write_seeprom(struct ahd_softc *ahd, - char *buffer, int length); - -/* - * Table of syncrates that don't follow the "divisible by 4" - * rule. This table will be expanded in future SCSI specs. - */ -static const struct { - u_int period_factor; - u_int period; /* in 100ths of ns */ -} scsi_syncrates[] = { - { 0x08, 625 }, /* FAST-160 */ - { 0x09, 1250 }, /* FAST-80 */ - { 0x0a, 2500 }, /* FAST-40 40MHz */ - { 0x0b, 3030 }, /* FAST-40 33MHz */ - { 0x0c, 5000 } /* FAST-20 */ -}; - -/* - * Return the frequency in kHz corresponding to the given - * sync period factor. - */ -static u_int -ahd_calc_syncsrate(u_int period_factor) -{ - int i; - - /* See if the period is in the "exception" table */ - for (i = 0; i < ARRAY_SIZE(scsi_syncrates); i++) { - - if (period_factor == scsi_syncrates[i].period_factor) { - /* Period in kHz */ - return (100000000 / scsi_syncrates[i].period); - } - } - - /* - * Wasn't in the table, so use the standard - * 4 times conversion. - */ - return (10000000 / (period_factor * 4 * 10)); -} - - -static void -copy_mem_info(struct info_str *info, char *data, int len) -{ - if (info->pos + len > info->offset + info->length) - len = info->offset + info->length - info->pos; - - if (info->pos + len < info->offset) { - info->pos += len; - return; - } - - if (info->pos < info->offset) { - off_t partial; - - partial = info->offset - info->pos; - data += partial; - info->pos += partial; - len -= partial; - } - - if (len > 0) { - memcpy(info->buffer, data, len); - info->pos += len; - info->buffer += len; - } -} - -static int -copy_info(struct info_str *info, char *fmt, ...) -{ - va_list args; - char buf[256]; - int len; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - copy_mem_info(info, buf, len); - return (len); -} - -static void -ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) -{ - u_int speed; - u_int freq; - u_int mb; - - if (tinfo->period == AHD_PERIOD_UNKNOWN) { - copy_info(info, "Renegotiation Pending\n"); - return; - } - speed = 3300; - freq = 0; - if (tinfo->offset != 0) { - freq = ahd_calc_syncsrate(tinfo->period); - speed = freq; - } - speed *= (0x01 << tinfo->width); - mb = speed / 1000; - if (mb > 0) - copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000); - else - copy_info(info, "%dKB/s transfers", speed); - - if (freq != 0) { - int printed_options; - - printed_options = 0; - copy_info(info, " (%d.%03dMHz", freq / 1000, freq % 1000); - if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) { - copy_info(info, " RDSTRM"); - printed_options++; - } - if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { - copy_info(info, "%s", printed_options ? "|DT" : " DT"); - printed_options++; - } - if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - copy_info(info, "%s", printed_options ? "|IU" : " IU"); - printed_options++; - } - if ((tinfo->ppr_options & MSG_EXT_PPR_RTI) != 0) { - copy_info(info, "%s", - printed_options ? "|RTI" : " RTI"); - printed_options++; - } - if ((tinfo->ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) { - copy_info(info, "%s", - printed_options ? "|QAS" : " QAS"); - printed_options++; - } - } - - if (tinfo->width > 0) { - if (freq != 0) { - copy_info(info, ", "); - } else { - copy_info(info, " ("); - } - copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width)); - } else if (freq != 0) { - copy_info(info, ")"); - } - copy_info(info, "\n"); -} - -static void -ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, - u_int our_id, char channel, u_int target_id) -{ - struct scsi_target *starget; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - int lun; - - tinfo = ahd_fetch_transinfo(ahd, channel, our_id, - target_id, &tstate); - copy_info(info, "Target %d Negotiation Settings\n", target_id); - copy_info(info, "\tUser: "); - ahd_format_transinfo(info, &tinfo->user); - starget = ahd->platform_data->starget[target_id]; - if (starget == NULL) - return; - - copy_info(info, "\tGoal: "); - ahd_format_transinfo(info, &tinfo->goal); - copy_info(info, "\tCurr: "); - ahd_format_transinfo(info, &tinfo->curr); - - for (lun = 0; lun < AHD_NUM_LUNS; lun++) { - struct scsi_device *dev; - - dev = scsi_device_lookup_by_target(starget, lun); - - if (dev == NULL) - continue; - - ahd_dump_device_state(info, dev); - } -} - -static void -ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev) -{ - struct ahd_linux_device *dev = scsi_transport_device_data(sdev); - - copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", - sdev->sdev_target->channel + 'A', - sdev->sdev_target->id, sdev->lun); - - copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); - copy_info(info, "\t\tCommands Active %d\n", dev->active); - copy_info(info, "\t\tCommand Openings %d\n", dev->openings); - copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags); - copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen); -} - -static int -ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length) -{ - ahd_mode_state saved_modes; - int have_seeprom; - u_long s; - int paused; - int written; - - /* Default to failure. */ - written = -EINVAL; - ahd_lock(ahd, &s); - paused = ahd_is_paused(ahd); - if (!paused) - ahd_pause(ahd); - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - if (length != sizeof(struct seeprom_config)) { - printk("ahd_proc_write_seeprom: incorrect buffer size\n"); - goto done; - } - - have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer); - if (have_seeprom == 0) { - printk("ahd_proc_write_seeprom: cksum verification failed\n"); - goto done; - } - - have_seeprom = ahd_acquire_seeprom(ahd); - if (!have_seeprom) { - printk("ahd_proc_write_seeprom: No Serial EEPROM\n"); - goto done; - } else { - u_int start_addr; - - if (ahd->seep_config == NULL) { - ahd->seep_config = kmalloc(sizeof(*ahd->seep_config), GFP_ATOMIC); - if (ahd->seep_config == NULL) { - printk("aic79xx: Unable to allocate serial " - "eeprom buffer. Write failing\n"); - goto done; - } - } - printk("aic79xx: Writing Serial EEPROM\n"); - start_addr = 32 * (ahd->channel - 'A'); - ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr, - sizeof(struct seeprom_config)/2); - ahd_read_seeprom(ahd, (uint16_t *)ahd->seep_config, - start_addr, sizeof(struct seeprom_config)/2, - /*ByteStream*/FALSE); - ahd_release_seeprom(ahd); - written = length; - } - -done: - ahd_restore_modes(ahd, saved_modes); - if (!paused) - ahd_unpause(ahd); - ahd_unlock(ahd, &s); - return (written); -} -/* - * Return information to handle /proc support for the driver. - */ -int -ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, - off_t offset, int length, int inout) -{ - struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata; - struct info_str info; - char ahd_info[256]; - u_int max_targ; - u_int i; - int retval; - - /* Has data been written to the file? */ - if (inout == TRUE) { - retval = ahd_proc_write_seeprom(ahd, buffer, length); - goto done; - } - - if (start) - *start = buffer; - - info.buffer = buffer; - info.length = length; - info.offset = offset; - info.pos = 0; - - copy_info(&info, "Adaptec AIC79xx driver version: %s\n", - AIC79XX_DRIVER_VERSION); - copy_info(&info, "%s\n", ahd->description); - ahd_controller_info(ahd, ahd_info); - copy_info(&info, "%s\n", ahd_info); - copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n", - ahd->scb_data.numscbs, AHD_NSEG); - - max_targ = 16; - - if (ahd->seep_config == NULL) - copy_info(&info, "No Serial EEPROM\n"); - else { - copy_info(&info, "Serial EEPROM:\n"); - for (i = 0; i < sizeof(*ahd->seep_config)/2; i++) { - if (((i % 8) == 0) && (i != 0)) { - copy_info(&info, "\n"); - } - copy_info(&info, "0x%.4x ", - ((uint16_t*)ahd->seep_config)[i]); - } - copy_info(&info, "\n"); - } - copy_info(&info, "\n"); - - if ((ahd->features & AHD_WIDE) == 0) - max_targ = 8; - - for (i = 0; i < max_targ; i++) { - - ahd_dump_target_state(ahd, &info, ahd->our_id, 'A', - /*target_id*/i); - } - retval = info.pos > info.offset ? info.pos - info.offset : 0; -done: - return (retval); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped deleted file mode 100644 index cdcead07..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped +++ /dev/null @@ -1,2685 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated - * from the following source files: - * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $ - */ -typedef int (ahd_reg_print_t)(u_int, u_int *, u_int); -typedef struct ahd_reg_parse_entry { - char *name; - uint8_t value; - uint8_t mask; -} ahd_reg_parse_entry_t; - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_mode_ptr_print; -#else -#define ahd_mode_ptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "MODE_PTR", 0x00, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_intstat_print; -#else -#define ahd_intstat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INTSTAT", 0x01, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seqintcode_print; -#else -#define ahd_seqintcode_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEQINTCODE", 0x02, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_error_print; -#else -#define ahd_error_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "ERROR", 0x04, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_hescb_qoff_print; -#else -#define ahd_hescb_qoff_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "HESCB_QOFF", 0x08, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_hs_mailbox_print; -#else -#define ahd_hs_mailbox_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "HS_MAILBOX", 0x0b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seqintstat_print; -#else -#define ahd_seqintstat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEQINTSTAT", 0x0c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_clrseqintstat_print; -#else -#define ahd_clrseqintstat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CLRSEQINTSTAT", 0x0c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_swtimer_print; -#else -#define ahd_swtimer_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SWTIMER", 0x0e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sescb_qoff_print; -#else -#define ahd_sescb_qoff_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SESCB_QOFF", 0x12, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_intctl_print; -#else -#define ahd_intctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INTCTL", 0x18, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_dfcntrl_print; -#else -#define ahd_dfcntrl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DFCNTRL", 0x19, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_dfstatus_print; -#else -#define ahd_dfstatus_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DFSTATUS", 0x1a, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sg_cache_shadow_print; -#else -#define ahd_sg_cache_shadow_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SG_CACHE_SHADOW", 0x1b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqin_print; -#else -#define ahd_lqin_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQIN", 0x20, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lunptr_print; -#else -#define ahd_lunptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LUNPTR", 0x22, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_cmdlenptr_print; -#else -#define ahd_cmdlenptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CMDLENPTR", 0x25, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_attrptr_print; -#else -#define ahd_attrptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "ATTRPTR", 0x26, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_flagptr_print; -#else -#define ahd_flagptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "FLAGPTR", 0x27, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_cmdptr_print; -#else -#define ahd_cmdptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CMDPTR", 0x28, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_qnextptr_print; -#else -#define ahd_qnextptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "QNEXTPTR", 0x29, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_abrtbyteptr_print; -#else -#define ahd_abrtbyteptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "ABRTBYTEPTR", 0x2b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_abrtbitptr_print; -#else -#define ahd_abrtbitptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "ABRTBITPTR", 0x2c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lunlen_print; -#else -#define ahd_lunlen_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LUNLEN", 0x30, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_cdblimit_print; -#else -#define ahd_cdblimit_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CDBLIMIT", 0x31, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_maxcmd_print; -#else -#define ahd_maxcmd_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "MAXCMD", 0x32, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_maxcmdcnt_print; -#else -#define ahd_maxcmdcnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "MAXCMDCNT", 0x33, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqctl1_print; -#else -#define ahd_lqctl1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQCTL1", 0x38, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqctl2_print; -#else -#define ahd_lqctl2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQCTL2", 0x39, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scsiseq0_print; -#else -#define ahd_scsiseq0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCSISEQ0", 0x3a, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scsiseq1_print; -#else -#define ahd_scsiseq1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCSISEQ1", 0x3b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sxfrctl0_print; -#else -#define ahd_sxfrctl0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SXFRCTL0", 0x3c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_dffstat_print; -#else -#define ahd_dffstat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DFFSTAT", 0x3f, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_multargid_print; -#else -#define ahd_multargid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "MULTARGID", 0x40, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scsisigi_print; -#else -#define ahd_scsisigi_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCSISIGI", 0x41, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scsiphase_print; -#else -#define ahd_scsiphase_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCSIPHASE", 0x42, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scsidat_print; -#else -#define ahd_scsidat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCSIDAT", 0x44, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scsibus_print; -#else -#define ahd_scsibus_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCSIBUS", 0x46, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_targidin_print; -#else -#define ahd_targidin_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "TARGIDIN", 0x48, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_selid_print; -#else -#define ahd_selid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SELID", 0x49, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sblkctl_print; -#else -#define ahd_sblkctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SBLKCTL", 0x4a, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sstat0_print; -#else -#define ahd_sstat0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SSTAT0", 0x4b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_simode0_print; -#else -#define ahd_simode0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SIMODE0", 0x4b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sstat1_print; -#else -#define ahd_sstat1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SSTAT1", 0x4c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sstat2_print; -#else -#define ahd_sstat2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SSTAT2", 0x4d, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_clrsint2_print; -#else -#define ahd_clrsint2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CLRSINT2", 0x4d, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_perrdiag_print; -#else -#define ahd_perrdiag_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "PERRDIAG", 0x4e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqistate_print; -#else -#define ahd_lqistate_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQISTATE", 0x4e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_soffcnt_print; -#else -#define ahd_soffcnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SOFFCNT", 0x4f, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqostate_print; -#else -#define ahd_lqostate_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQOSTATE", 0x4f, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqistat0_print; -#else -#define ahd_lqistat0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQISTAT0", 0x50, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_clrlqiint0_print; -#else -#define ahd_clrlqiint0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CLRLQIINT0", 0x50, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqimode0_print; -#else -#define ahd_lqimode0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQIMODE0", 0x50, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqimode1_print; -#else -#define ahd_lqimode1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQIMODE1", 0x51, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqistat1_print; -#else -#define ahd_lqistat1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQISTAT1", 0x51, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_clrlqiint1_print; -#else -#define ahd_clrlqiint1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CLRLQIINT1", 0x51, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqistat2_print; -#else -#define ahd_lqistat2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQISTAT2", 0x52, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sstat3_print; -#else -#define ahd_sstat3_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SSTAT3", 0x53, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_simode3_print; -#else -#define ahd_simode3_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SIMODE3", 0x53, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_clrsint3_print; -#else -#define ahd_clrsint3_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CLRSINT3", 0x53, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqostat0_print; -#else -#define ahd_lqostat0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQOSTAT0", 0x54, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_clrlqoint0_print; -#else -#define ahd_clrlqoint0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CLRLQOINT0", 0x54, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqomode0_print; -#else -#define ahd_lqomode0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQOMODE0", 0x54, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqomode1_print; -#else -#define ahd_lqomode1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQOMODE1", 0x55, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqostat1_print; -#else -#define ahd_lqostat1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQOSTAT1", 0x55, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_clrlqoint1_print; -#else -#define ahd_clrlqoint1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CLRLQOINT1", 0x55, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqostat2_print; -#else -#define ahd_lqostat2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQOSTAT2", 0x56, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_os_space_cnt_print; -#else -#define ahd_os_space_cnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "OS_SPACE_CNT", 0x56, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_simode1_print; -#else -#define ahd_simode1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SIMODE1", 0x57, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_gsfifo_print; -#else -#define ahd_gsfifo_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "GSFIFO", 0x58, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_dffsxfrctl_print; -#else -#define ahd_dffsxfrctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DFFSXFRCTL", 0x5a, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lqoscsctl_print; -#else -#define ahd_lqoscsctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LQOSCSCTL", 0x5a, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_nextscb_print; -#else -#define ahd_nextscb_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "NEXTSCB", 0x5a, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_clrseqintsrc_print; -#else -#define ahd_clrseqintsrc_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CLRSEQINTSRC", 0x5b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seqintsrc_print; -#else -#define ahd_seqintsrc_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEQINTSRC", 0x5b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_currscb_print; -#else -#define ahd_currscb_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CURRSCB", 0x5c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seqimode_print; -#else -#define ahd_seqimode_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEQIMODE", 0x5c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_mdffstat_print; -#else -#define ahd_mdffstat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "MDFFSTAT", 0x5d, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lastscb_print; -#else -#define ahd_lastscb_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LASTSCB", 0x5e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_negoaddr_print; -#else -#define ahd_negoaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "NEGOADDR", 0x60, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_negperiod_print; -#else -#define ahd_negperiod_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "NEGPERIOD", 0x61, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_negoffset_print; -#else -#define ahd_negoffset_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "NEGOFFSET", 0x62, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_negppropts_print; -#else -#define ahd_negppropts_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "NEGPPROPTS", 0x63, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_negconopts_print; -#else -#define ahd_negconopts_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "NEGCONOPTS", 0x64, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_annexcol_print; -#else -#define ahd_annexcol_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "ANNEXCOL", 0x65, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_annexdat_print; -#else -#define ahd_annexdat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "ANNEXDAT", 0x66, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scschkn_print; -#else -#define ahd_scschkn_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCSCHKN", 0x66, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_iownid_print; -#else -#define ahd_iownid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "IOWNID", 0x67, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_shcnt_print; -#else -#define ahd_shcnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SHCNT", 0x68, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_townid_print; -#else -#define ahd_townid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "TOWNID", 0x69, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seloid_print; -#else -#define ahd_seloid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SELOID", 0x6b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scbhaddr_print; -#else -#define ahd_scbhaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCBHADDR", 0x7c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sghaddr_print; -#else -#define ahd_sghaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SGHADDR", 0x7c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scbhcnt_print; -#else -#define ahd_scbhcnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCBHCNT", 0x84, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sghcnt_print; -#else -#define ahd_sghcnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SGHCNT", 0x84, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_pcixctl_print; -#else -#define ahd_pcixctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "PCIXCTL", 0x93, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_dchspltstat0_print; -#else -#define ahd_dchspltstat0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DCHSPLTSTAT0", 0x96, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_dchspltstat1_print; -#else -#define ahd_dchspltstat1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DCHSPLTSTAT1", 0x97, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sgspltstat0_print; -#else -#define ahd_sgspltstat0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SGSPLTSTAT0", 0x9e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sgspltstat1_print; -#else -#define ahd_sgspltstat1_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SGSPLTSTAT1", 0x9f, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_df0pcistat_print; -#else -#define ahd_df0pcistat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DF0PCISTAT", 0xa0, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_reg0_print; -#else -#define ahd_reg0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "REG0", 0xa0, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_reg_isr_print; -#else -#define ahd_reg_isr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "REG_ISR", 0xa4, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sg_state_print; -#else -#define ahd_sg_state_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SG_STATE", 0xa6, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_targpcistat_print; -#else -#define ahd_targpcistat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "TARGPCISTAT", 0xa7, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scbautoptr_print; -#else -#define ahd_scbautoptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCBAUTOPTR", 0xab, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_ccscbaddr_print; -#else -#define ahd_ccscbaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CCSCBADDR", 0xac, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_ccscbctl_print; -#else -#define ahd_ccscbctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CCSCBCTL", 0xad, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_ccsgctl_print; -#else -#define ahd_ccsgctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CCSGCTL", 0xad, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_ccscbram_print; -#else -#define ahd_ccscbram_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CCSCBRAM", 0xb0, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_brddat_print; -#else -#define ahd_brddat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "BRDDAT", 0xb8, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seeadr_print; -#else -#define ahd_seeadr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEEADR", 0xba, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seedat_print; -#else -#define ahd_seedat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEEDAT", 0xbc, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seectl_print; -#else -#define ahd_seectl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEECTL", 0xbe, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seestat_print; -#else -#define ahd_seestat_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEESTAT", 0xbe, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_dspdatactl_print; -#else -#define ahd_dspdatactl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DSPDATACTL", 0xc1, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_dspselect_print; -#else -#define ahd_dspselect_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "DSPSELECT", 0xc4, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_wrtbiasctl_print; -#else -#define ahd_wrtbiasctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "WRTBIASCTL", 0xc5, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seqctl0_print; -#else -#define ahd_seqctl0_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEQCTL0", 0xd6, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seqintctl_print; -#else -#define ahd_seqintctl_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEQINTCTL", 0xd9, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_prgmcnt_print; -#else -#define ahd_prgmcnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "PRGMCNT", 0xde, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_none_print; -#else -#define ahd_none_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "NONE", 0xea, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_intvec1_addr_print; -#else -#define ahd_intvec1_addr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INTVEC1_ADDR", 0xf4, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_curaddr_print; -#else -#define ahd_curaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CURADDR", 0xf4, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_intvec2_addr_print; -#else -#define ahd_intvec2_addr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INTVEC2_ADDR", 0xf6, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_longjmp_addr_print; -#else -#define ahd_longjmp_addr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LONGJMP_ADDR", 0xf8, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_accum_save_print; -#else -#define ahd_accum_save_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "ACCUM_SAVE", 0xfa, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_waiting_scb_tails_print; -#else -#define ahd_waiting_scb_tails_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "WAITING_SCB_TAILS", 0x100, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_sram_base_print; -#else -#define ahd_sram_base_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SRAM_BASE", 0x100, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_waiting_tid_head_print; -#else -#define ahd_waiting_tid_head_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "WAITING_TID_HEAD", 0x120, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_waiting_tid_tail_print; -#else -#define ahd_waiting_tid_tail_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "WAITING_TID_TAIL", 0x122, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_next_queued_scb_addr_print; -#else -#define ahd_next_queued_scb_addr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "NEXT_QUEUED_SCB_ADDR", 0x124, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_complete_scb_head_print; -#else -#define ahd_complete_scb_head_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "COMPLETE_SCB_HEAD", 0x128, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_complete_scb_dmainprog_head_print; -#else -#define ahd_complete_scb_dmainprog_head_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "COMPLETE_SCB_DMAINPROG_HEAD", 0x12a, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_complete_dma_scb_head_print; -#else -#define ahd_complete_dma_scb_head_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_HEAD", 0x12c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_complete_dma_scb_tail_print; -#else -#define ahd_complete_dma_scb_tail_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_TAIL", 0x12e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_complete_on_qfreeze_head_print; -#else -#define ahd_complete_on_qfreeze_head_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "COMPLETE_ON_QFREEZE_HEAD", 0x130, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_qfreeze_count_print; -#else -#define ahd_qfreeze_count_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "QFREEZE_COUNT", 0x132, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_kernel_qfreeze_count_print; -#else -#define ahd_kernel_qfreeze_count_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "KERNEL_QFREEZE_COUNT", 0x134, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_saved_mode_print; -#else -#define ahd_saved_mode_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SAVED_MODE", 0x136, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_msg_out_print; -#else -#define ahd_msg_out_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "MSG_OUT", 0x137, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seq_flags_print; -#else -#define ahd_seq_flags_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEQ_FLAGS", 0x139, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_lastphase_print; -#else -#define ahd_lastphase_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LASTPHASE", 0x13c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_qoutfifo_entry_valid_tag_print; -#else -#define ahd_qoutfifo_entry_valid_tag_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG", 0x13d, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_kernel_tqinpos_print; -#else -#define ahd_kernel_tqinpos_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "KERNEL_TQINPOS", 0x13e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_qoutfifo_next_addr_print; -#else -#define ahd_qoutfifo_next_addr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR", 0x144, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_last_msg_print; -#else -#define ahd_last_msg_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LAST_MSG", 0x14a, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scsiseq_template_print; -#else -#define ahd_scsiseq_template_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCSISEQ_TEMPLATE", 0x14b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_initiator_tag_print; -#else -#define ahd_initiator_tag_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INITIATOR_TAG", 0x14c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_seq_flags2_print; -#else -#define ahd_seq_flags2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SEQ_FLAGS2", 0x14d, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_allocfifo_scbptr_print; -#else -#define ahd_allocfifo_scbptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR", 0x14e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalescing_timer_print; -#else -#define ahd_int_coalescing_timer_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x150, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalescing_maxcmds_print; -#else -#define ahd_int_coalescing_maxcmds_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x152, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalescing_mincmds_print; -#else -#define ahd_int_coalescing_mincmds_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x153, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_cmds_pending_print; -#else -#define ahd_cmds_pending_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CMDS_PENDING", 0x154, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalescing_cmdcount_print; -#else -#define ahd_int_coalescing_cmdcount_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x156, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_local_hs_mailbox_print; -#else -#define ahd_local_hs_mailbox_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX", 0x157, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_cmdsize_table_print; -#else -#define ahd_cmdsize_table_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "CMDSIZE_TABLE", 0x158, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_mk_message_scb_print; -#else -#define ahd_mk_message_scb_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "MK_MESSAGE_SCB", 0x160, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_mk_message_scsiid_print; -#else -#define ahd_mk_message_scsiid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "MK_MESSAGE_SCSIID", 0x162, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_base_print; -#else -#define ahd_scb_base_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_BASE", 0x180, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_residual_datacnt_print; -#else -#define ahd_scb_residual_datacnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_RESIDUAL_DATACNT", 0x180, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_sense_busaddr_print; -#else -#define ahd_scb_sense_busaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_SENSE_BUSADDR", 0x18c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_tag_print; -#else -#define ahd_scb_tag_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TAG", 0x190, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_control_print; -#else -#define ahd_scb_control_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_CONTROL", 0x192, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_scsiid_print; -#else -#define ahd_scb_scsiid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_SCSIID", 0x193, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_lun_print; -#else -#define ahd_scb_lun_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_LUN", 0x194, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_task_attribute_print; -#else -#define ahd_scb_task_attribute_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TASK_ATTRIBUTE", 0x195, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_task_management_print; -#else -#define ahd_scb_task_management_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", 0x197, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_dataptr_print; -#else -#define ahd_scb_dataptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_DATAPTR", 0x198, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_datacnt_print; -#else -#define ahd_scb_datacnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_DATACNT", 0x1a0, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_sgptr_print; -#else -#define ahd_scb_sgptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_SGPTR", 0x1a4, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_busaddr_print; -#else -#define ahd_scb_busaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_BUSADDR", 0x1a8, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_next2_print; -#else -#define ahd_scb_next2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1ae, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_disconnected_lists_print; -#else -#define ahd_scb_disconnected_lists_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_DISCONNECTED_LISTS", 0x1b8, regvalue, cur_col, wrap) -#endif - - -#define MODE_PTR 0x00 -#define DST_MODE 0x70 -#define SRC_MODE 0x07 - -#define INTSTAT 0x01 -#define INT_PEND 0xff -#define HWERRINT 0x80 -#define BRKADRINT 0x40 -#define SWTMINT 0x20 -#define PCIINT 0x10 -#define SCSIINT 0x08 -#define SEQINT 0x04 -#define CMDCMPLT 0x02 -#define SPLTINT 0x01 - -#define SEQINTCODE 0x02 -#define BAD_SCB_STATUS 0x1a -#define SAW_HWERR 0x19 -#define TRACEPOINT3 0x18 -#define TRACEPOINT2 0x17 -#define TRACEPOINT1 0x16 -#define TRACEPOINT0 0x15 -#define TASKMGMT_CMD_CMPLT_OKAY 0x14 -#define TASKMGMT_FUNC_COMPLETE 0x13 -#define ENTERING_NONPACK 0x12 -#define CFG4OVERRUN 0x11 -#define STATUS_OVERRUN 0x10 -#define CFG4ISTAT_INTR 0x0f -#define INVALID_SEQINT 0x0e -#define ILLEGAL_PHASE 0x0d -#define DUMP_CARD_STATE 0x0c -#define MISSED_BUSFREE 0x0b -#define MKMSG_FAILED 0x0a -#define DATA_OVERRUN 0x09 -#define BAD_STATUS 0x08 -#define HOST_MSG_LOOP 0x07 -#define PDATA_REINIT 0x06 -#define IGN_WIDE_RES 0x05 -#define NO_MATCH 0x04 -#define PROTO_VIOLATION 0x03 -#define SEND_REJECT 0x02 -#define BAD_PHASE 0x01 -#define NO_SEQINT 0x00 - -#define CLRINT 0x03 -#define CLRHWERRINT 0x80 -#define CLRBRKADRINT 0x40 -#define CLRSWTMINT 0x20 -#define CLRPCIINT 0x10 -#define CLRSCSIINT 0x08 -#define CLRSEQINT 0x04 -#define CLRCMDINT 0x02 -#define CLRSPLTINT 0x01 - -#define ERROR 0x04 -#define CIOPARERR 0x80 -#define CIOACCESFAIL 0x40 -#define MPARERR 0x20 -#define DPARERR 0x10 -#define SQPARERR 0x08 -#define ILLOPCODE 0x04 -#define DSCTMOUT 0x02 - -#define CLRERR 0x04 -#define CLRCIOPARERR 0x80 -#define CLRCIOACCESFAIL 0x40 -#define CLRMPARERR 0x20 -#define CLRDPARERR 0x10 -#define CLRSQPARERR 0x08 -#define CLRILLOPCODE 0x04 -#define CLRDSCTMOUT 0x02 - -#define HCNTRL 0x05 -#define SEQ_RESET 0x80 -#define POWRDN 0x40 -#define SWINT 0x10 -#define SWTIMER_START_B 0x08 -#define PAUSE 0x04 -#define INTEN 0x02 -#define CHIPRST 0x01 -#define CHIPRSTACK 0x01 - -#define HNSCB_QOFF 0x06 - -#define HESCB_QOFF 0x08 - -#define HS_MAILBOX 0x0b -#define HOST_TQINPOS 0x80 -#define ENINT_COALESCE 0x40 - -#define SEQINTSTAT 0x0c -#define SEQ_SWTMRTO 0x10 -#define SEQ_SEQINT 0x08 -#define SEQ_SCSIINT 0x04 -#define SEQ_PCIINT 0x02 -#define SEQ_SPLTINT 0x01 - -#define CLRSEQINTSTAT 0x0c -#define CLRSEQ_SWTMRTO 0x10 -#define CLRSEQ_SEQINT 0x08 -#define CLRSEQ_SCSIINT 0x04 -#define CLRSEQ_PCIINT 0x02 -#define CLRSEQ_SPLTINT 0x01 - -#define SWTIMER 0x0e - -#define SNSCB_QOFF 0x10 - -#define SESCB_QOFF 0x12 - -#define SDSCB_QOFF 0x14 - -#define QOFF_CTLSTA 0x16 -#define EMPTY_SCB_AVAIL 0x80 -#define NEW_SCB_AVAIL 0x40 -#define SDSCB_ROLLOVR 0x20 -#define HS_MAILBOX_ACT 0x10 -#define SCB_QSIZE 0x0f -#define SCB_QSIZE_16384 0x0c -#define SCB_QSIZE_8192 0x0b -#define SCB_QSIZE_4096 0x0a -#define SCB_QSIZE_2048 0x09 -#define SCB_QSIZE_1024 0x08 -#define SCB_QSIZE_512 0x07 -#define SCB_QSIZE_256 0x06 -#define SCB_QSIZE_128 0x05 -#define SCB_QSIZE_64 0x04 -#define SCB_QSIZE_32 0x03 -#define SCB_QSIZE_16 0x02 -#define SCB_QSIZE_8 0x01 -#define SCB_QSIZE_4 0x00 - -#define INTCTL 0x18 -#define SWTMINTMASK 0x80 -#define SWTMINTEN 0x40 -#define SWTIMER_START 0x20 -#define AUTOCLRCMDINT 0x10 -#define PCIINTEN 0x08 -#define SCSIINTEN 0x04 -#define SEQINTEN 0x02 -#define SPLTINTEN 0x01 - -#define DFCNTRL 0x19 -#define SCSIENWRDIS 0x40 -#define SCSIENACK 0x20 -#define DIRECTIONACK 0x04 -#define FIFOFLUSHACK 0x02 -#define DIRECTIONEN 0x01 - -#define DSCOMMAND0 0x19 -#define CACHETHEN 0x80 -#define DPARCKEN 0x40 -#define MPARCKEN 0x20 -#define EXTREQLCK 0x10 -#define DISABLE_TWATE 0x02 -#define CIOPARCKEN 0x01 - -#define DFSTATUS 0x1a -#define PRELOAD_AVAIL 0x80 -#define PKT_PRELOAD_AVAIL 0x40 -#define MREQPEND 0x10 -#define HDONE 0x08 -#define DFTHRESH 0x04 -#define FIFOFULL 0x02 -#define FIFOEMP 0x01 - -#define SG_CACHE_SHADOW 0x1b -#define ODD_SEG 0x04 -#define LAST_SEG 0x02 -#define LAST_SEG_DONE 0x01 - -#define ARBCTL 0x1b -#define RESET_HARB 0x80 -#define RETRY_SWEN 0x08 -#define USE_TIME 0x07 - -#define SG_CACHE_PRE 0x1b - -#define LQIN 0x20 - -#define TYPEPTR 0x20 - -#define TAGPTR 0x21 - -#define LUNPTR 0x22 - -#define DATALENPTR 0x23 - -#define STATLENPTR 0x24 - -#define CMDLENPTR 0x25 - -#define ATTRPTR 0x26 - -#define FLAGPTR 0x27 - -#define CMDPTR 0x28 - -#define QNEXTPTR 0x29 - -#define IDPTR 0x2a - -#define ABRTBYTEPTR 0x2b - -#define ABRTBITPTR 0x2c - -#define MAXCMDBYTES 0x2d - -#define MAXCMD2RCV 0x2e - -#define SHORTTHRESH 0x2f - -#define LUNLEN 0x30 -#define TLUNLEN 0xf0 -#define ILUNLEN 0x0f - -#define CDBLIMIT 0x31 - -#define MAXCMD 0x32 - -#define MAXCMDCNT 0x33 - -#define LQRSVD01 0x34 - -#define LQRSVD16 0x35 - -#define LQRSVD17 0x36 - -#define CMDRSVD0 0x37 - -#define LQCTL0 0x38 -#define LQITARGCLT 0xc0 -#define LQIINITGCLT 0x30 -#define LQ0TARGCLT 0x0c -#define LQ0INITGCLT 0x03 - -#define LQCTL1 0x38 -#define PCI2PCI 0x04 -#define SINGLECMD 0x02 -#define ABORTPENDING 0x01 - -#define SCSBIST0 0x39 -#define GSBISTERR 0x40 -#define GSBISTDONE 0x20 -#define GSBISTRUN 0x10 -#define OSBISTERR 0x04 -#define OSBISTDONE 0x02 -#define OSBISTRUN 0x01 - -#define LQCTL2 0x39 -#define LQIRETRY 0x80 -#define LQICONTINUE 0x40 -#define LQITOIDLE 0x20 -#define LQIPAUSE 0x10 -#define LQORETRY 0x08 -#define LQOCONTINUE 0x04 -#define LQOTOIDLE 0x02 -#define LQOPAUSE 0x01 - -#define SCSBIST1 0x3a -#define NTBISTERR 0x04 -#define NTBISTDONE 0x02 -#define NTBISTRUN 0x01 - -#define SCSISEQ0 0x3a -#define TEMODEO 0x80 -#define ENSELO 0x40 -#define ENARBO 0x20 -#define FORCEBUSFREE 0x10 -#define SCSIRSTO 0x01 - -#define SCSISEQ1 0x3b - -#define SXFRCTL0 0x3c -#define DFON 0x80 -#define DFPEXP 0x40 -#define BIOSCANCELEN 0x10 -#define SPIOEN 0x08 - -#define DLCOUNT 0x3c - -#define BUSINITID 0x3c - -#define SXFRCTL1 0x3d -#define BITBUCKET 0x80 -#define ENSACHK 0x40 -#define ENSPCHK 0x20 -#define STIMESEL 0x18 -#define ENSTIMER 0x04 -#define ACTNEGEN 0x02 -#define STPWEN 0x01 - -#define BUSTARGID 0x3e - -#define SXFRCTL2 0x3e -#define AUTORSTDIS 0x10 -#define CMDDMAEN 0x08 -#define ASU 0x07 - -#define DFFSTAT 0x3f -#define CURRFIFO 0x03 -#define FIFO1FREE 0x20 -#define FIFO0FREE 0x10 -#define CURRFIFO_NONE 0x03 -#define CURRFIFO_1 0x01 -#define CURRFIFO_0 0x00 - -#define SCSISIGO 0x40 -#define CDO 0x80 -#define IOO 0x40 -#define MSGO 0x20 -#define ATNO 0x10 -#define SELO 0x08 -#define BSYO 0x04 -#define REQO 0x02 -#define ACKO 0x01 - -#define MULTARGID 0x40 - -#define SCSISIGI 0x41 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 - -#define SCSIPHASE 0x42 -#define STATUS_PHASE 0x20 -#define COMMAND_PHASE 0x10 -#define MSG_IN_PHASE 0x08 -#define MSG_OUT_PHASE 0x04 -#define DATA_PHASE_MASK 0x03 -#define DATA_IN_PHASE 0x02 -#define DATA_OUT_PHASE 0x01 - -#define SCSIDAT0_IMG 0x43 - -#define SCSIDAT 0x44 - -#define SCSIBUS 0x46 - -#define TARGIDIN 0x48 -#define CLKOUT 0x80 -#define TARGID 0x0f - -#define SELID 0x49 -#define SELID_MASK 0xf0 -#define ONEBIT 0x08 - -#define OPTIONMODE 0x4a -#define OPTIONMODE_DEFAULTS 0x02 -#define BIOSCANCTL 0x80 -#define AUTOACKEN 0x40 -#define BIASCANCTL 0x20 -#define BUSFREEREV 0x10 -#define ENDGFORMCHK 0x04 -#define AUTO_MSGOUT_DE 0x02 - -#define SBLKCTL 0x4a -#define DIAGLEDEN 0x80 -#define DIAGLEDON 0x40 -#define ENAB40 0x08 -#define ENAB20 0x04 -#define SELWIDE 0x02 - -#define CLRSINT0 0x4b -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRIOERR 0x08 -#define CLROVERRUN 0x04 -#define CLRSPIORDY 0x02 -#define CLRARBDO 0x01 - -#define SSTAT0 0x4b -#define TARGET 0x80 -#define SELDO 0x40 -#define SELDI 0x20 -#define SELINGO 0x10 -#define IOERR 0x08 -#define OVERRUN 0x04 -#define SPIORDY 0x02 -#define ARBDO 0x01 - -#define SIMODE0 0x4b -#define ENSELDO 0x40 -#define ENSELDI 0x20 -#define ENSELINGO 0x10 -#define ENIOERR 0x08 -#define ENOVERRUN 0x04 -#define ENSPIORDY 0x02 -#define ENARBDO 0x01 - -#define CLRSINT1 0x4c -#define CLRSELTIMEO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRSTRB2FAST 0x02 -#define CLRREQINIT 0x01 - -#define SSTAT1 0x4c -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define STRB2FAST 0x02 -#define REQINIT 0x01 - -#define SSTAT2 0x4d -#define BUSFREETIME 0xc0 -#define NONPACKREQ 0x20 -#define EXP_ACTIVE 0x10 -#define BSYX 0x08 -#define WIDE_RES 0x04 -#define SDONE 0x02 -#define DMADONE 0x01 -#define BUSFREE_DFF1 0xc0 -#define BUSFREE_DFF0 0x80 -#define BUSFREE_LQO 0x40 - -#define SIMODE2 0x4d -#define ENWIDE_RES 0x04 -#define ENSDONE 0x02 -#define ENDMADONE 0x01 - -#define CLRSINT2 0x4d -#define CLRNONPACKREQ 0x20 -#define CLRWIDE_RES 0x04 -#define CLRSDONE 0x02 -#define CLRDMADONE 0x01 - -#define PERRDIAG 0x4e -#define HIZERO 0x80 -#define HIPERR 0x40 -#define PREVPHASE 0x20 -#define PARITYERR 0x10 -#define AIPERR 0x08 -#define CRCERR 0x04 -#define DGFORMERR 0x02 -#define DTERR 0x01 - -#define LQISTATE 0x4e - -#define SOFFCNT 0x4f - -#define LQOSTATE 0x4f - -#define LQISTAT0 0x50 -#define LQIATNQAS 0x20 -#define LQICRCT1 0x10 -#define LQICRCT2 0x08 -#define LQIBADLQT 0x04 -#define LQIATNLQ 0x02 -#define LQIATNCMD 0x01 - -#define CLRLQIINT0 0x50 -#define CLRLQIATNQAS 0x20 -#define CLRLQICRCT1 0x10 -#define CLRLQICRCT2 0x08 -#define CLRLQIBADLQT 0x04 -#define CLRLQIATNLQ 0x02 -#define CLRLQIATNCMD 0x01 - -#define LQIMODE0 0x50 -#define ENLQIATNQASK 0x20 -#define ENLQICRCT1 0x10 -#define ENLQICRCT2 0x08 -#define ENLQIBADLQT 0x04 -#define ENLQIATNLQ 0x02 -#define ENLQIATNCMD 0x01 - -#define LQIMODE1 0x51 -#define ENLQIPHASE_LQ 0x80 -#define ENLQIPHASE_NLQ 0x40 -#define ENLIQABORT 0x20 -#define ENLQICRCI_LQ 0x10 -#define ENLQICRCI_NLQ 0x08 -#define ENLQIBADLQI 0x04 -#define ENLQIOVERI_LQ 0x02 -#define ENLQIOVERI_NLQ 0x01 - -#define LQISTAT1 0x51 -#define LQIPHASE_LQ 0x80 -#define LQIPHASE_NLQ 0x40 -#define LQIABORT 0x20 -#define LQICRCI_LQ 0x10 -#define LQICRCI_NLQ 0x08 -#define LQIBADLQI 0x04 -#define LQIOVERI_LQ 0x02 -#define LQIOVERI_NLQ 0x01 - -#define CLRLQIINT1 0x51 -#define CLRLQIPHASE_LQ 0x80 -#define CLRLQIPHASE_NLQ 0x40 -#define CLRLIQABORT 0x20 -#define CLRLQICRCI_LQ 0x10 -#define CLRLQICRCI_NLQ 0x08 -#define CLRLQIBADLQI 0x04 -#define CLRLQIOVERI_LQ 0x02 -#define CLRLQIOVERI_NLQ 0x01 - -#define LQISTAT2 0x52 -#define PACKETIZED 0x80 -#define LQIPHASE_OUTPKT 0x40 -#define LQIWORKONLQ 0x20 -#define LQIWAITFIFO 0x10 -#define LQISTOPPKT 0x08 -#define LQISTOPLQ 0x04 -#define LQISTOPCMD 0x02 -#define LQIGSAVAIL 0x01 - -#define SSTAT3 0x53 -#define NTRAMPERR 0x02 -#define OSRAMPERR 0x01 - -#define SIMODE3 0x53 -#define ENNTRAMPERR 0x02 -#define ENOSRAMPERR 0x01 - -#define CLRSINT3 0x53 -#define CLRNTRAMPERR 0x02 -#define CLROSRAMPERR 0x01 - -#define LQOSTAT0 0x54 -#define LQOTARGSCBPERR 0x10 -#define LQOSTOPT2 0x08 -#define LQOATNLQ 0x04 -#define LQOATNPKT 0x02 -#define LQOTCRC 0x01 - -#define CLRLQOINT0 0x54 -#define CLRLQOTARGSCBPERR 0x10 -#define CLRLQOSTOPT2 0x08 -#define CLRLQOATNLQ 0x04 -#define CLRLQOATNPKT 0x02 -#define CLRLQOTCRC 0x01 - -#define LQOMODE0 0x54 -#define ENLQOTARGSCBPERR 0x10 -#define ENLQOSTOPT2 0x08 -#define ENLQOATNLQ 0x04 -#define ENLQOATNPKT 0x02 -#define ENLQOTCRC 0x01 - -#define LQOMODE1 0x55 -#define ENLQOINITSCBPERR 0x10 -#define ENLQOSTOPI2 0x08 -#define ENLQOBADQAS 0x04 -#define ENLQOBUSFREE 0x02 -#define ENLQOPHACHGINPKT 0x01 - -#define LQOSTAT1 0x55 -#define LQOINITSCBPERR 0x10 -#define LQOSTOPI2 0x08 -#define LQOBADQAS 0x04 -#define LQOBUSFREE 0x02 -#define LQOPHACHGINPKT 0x01 - -#define CLRLQOINT1 0x55 -#define CLRLQOINITSCBPERR 0x10 -#define CLRLQOSTOPI2 0x08 -#define CLRLQOBADQAS 0x04 -#define CLRLQOBUSFREE 0x02 -#define CLRLQOPHACHGINPKT 0x01 - -#define LQOSTAT2 0x56 -#define LQOPKT 0xe0 -#define LQOWAITFIFO 0x10 -#define LQOPHACHGOUTPKT 0x02 -#define LQOSTOP0 0x01 - -#define OS_SPACE_CNT 0x56 - -#define SIMODE1 0x57 -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENSTRB2FAST 0x02 -#define ENREQINIT 0x01 - -#define GSFIFO 0x58 - -#define DFFSXFRCTL 0x5a -#define DFFBITBUCKET 0x08 -#define CLRSHCNT 0x04 -#define CLRCHN 0x02 -#define RSTCHN 0x01 - -#define LQOSCSCTL 0x5a -#define LQOH2A_VERSION 0x80 -#define LQOBUSETDLY 0x40 -#define LQONOHOLDLACK 0x02 -#define LQONOCHKOVER 0x01 - -#define NEXTSCB 0x5a - -#define CLRSEQINTSRC 0x5b -#define CLRCTXTDONE 0x40 -#define CLRSAVEPTRS 0x20 -#define CLRCFG4DATA 0x10 -#define CLRCFG4ISTAT 0x08 -#define CLRCFG4TSTAT 0x04 -#define CLRCFG4ICMD 0x02 -#define CLRCFG4TCMD 0x01 - -#define SEQINTSRC 0x5b -#define CTXTDONE 0x40 -#define SAVEPTRS 0x20 -#define CFG4DATA 0x10 -#define CFG4ISTAT 0x08 -#define CFG4TSTAT 0x04 -#define CFG4ICMD 0x02 -#define CFG4TCMD 0x01 - -#define CURRSCB 0x5c - -#define SEQIMODE 0x5c -#define ENCTXTDONE 0x40 -#define ENSAVEPTRS 0x20 -#define ENCFG4DATA 0x10 -#define ENCFG4ISTAT 0x08 -#define ENCFG4TSTAT 0x04 -#define ENCFG4ICMD 0x02 -#define ENCFG4TCMD 0x01 - -#define MDFFSTAT 0x5d -#define SHCNTNEGATIVE 0x40 -#define SHCNTMINUS1 0x20 -#define LASTSDONE 0x10 -#define SHVALID 0x08 -#define DLZERO 0x04 -#define DATAINFIFO 0x02 -#define FIFOFREE 0x01 - -#define CRCCONTROL 0x5d -#define CRCVALCHKEN 0x40 - -#define DFFTAG 0x5e - -#define LASTSCB 0x5e - -#define SCSITEST 0x5e -#define CNTRTEST 0x08 -#define SEL_TXPLL_DEBUG 0x04 - -#define IOPDNCTL 0x5f -#define DISABLE_OE 0x80 -#define PDN_IDIST 0x04 -#define PDN_DIFFSENSE 0x01 - -#define SHADDR 0x60 - -#define NEGOADDR 0x60 - -#define DGRPCRCI 0x60 - -#define NEGPERIOD 0x61 - -#define PACKCRCI 0x62 - -#define NEGOFFSET 0x62 - -#define NEGPPROPTS 0x63 -#define PPROPT_PACE 0x08 -#define PPROPT_QAS 0x04 -#define PPROPT_DT 0x02 -#define PPROPT_IUT 0x01 - -#define NEGCONOPTS 0x64 -#define ENSNAPSHOT 0x40 -#define RTI_WRTDIS 0x20 -#define RTI_OVRDTRN 0x10 -#define ENSLOWCRC 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNO 0x02 -#define WIDEXFER 0x01 - -#define ANNEXCOL 0x65 - -#define ANNEXDAT 0x66 - -#define SCSCHKN 0x66 -#define BIDICHKDIS 0x80 -#define STSELSKIDDIS 0x40 -#define CURRFIFODEF 0x20 -#define WIDERESEN 0x10 -#define SDONEMSKDIS 0x08 -#define DFFACTCLR 0x04 -#define SHVALIDSTDIS 0x02 -#define LSTSGCLRDIS 0x01 - -#define IOWNID 0x67 - -#define PLL960CTL0 0x68 - -#define SHCNT 0x68 - -#define TOWNID 0x69 - -#define PLL960CTL1 0x69 - -#define PLL960CNT0 0x6a - -#define XSIG 0x6a - -#define SELOID 0x6b - -#define PLL400CTL0 0x6c -#define PLL_VCOSEL 0x80 -#define PLL_PWDN 0x40 -#define PLL_NS 0x30 -#define PLL_ENLUD 0x08 -#define PLL_ENLPF 0x04 -#define PLL_DLPF 0x02 -#define PLL_ENFBM 0x01 - -#define FAIRNESS 0x6c - -#define PLL400CTL1 0x6d -#define PLL_CNTEN 0x80 -#define PLL_CNTCLR 0x40 -#define PLL_RST 0x01 - -#define UNFAIRNESS 0x6e - -#define PLL400CNT0 0x6e - -#define HADDR 0x70 - -#define PLLDELAY 0x70 -#define SPLIT_DROP_REQ 0x80 - -#define HODMAADR 0x70 - -#define HODMACNT 0x78 - -#define HCNT 0x78 - -#define HODMAEN 0x7a - -#define SCBHADDR 0x7c - -#define SGHADDR 0x7c - -#define SCBHCNT 0x84 - -#define SGHCNT 0x84 - -#define DFF_THRSH 0x88 -#define WR_DFTHRSH 0x70 -#define RD_DFTHRSH 0x07 -#define WR_DFTHRSH_MAX 0x70 -#define WR_DFTHRSH_90 0x60 -#define WR_DFTHRSH_85 0x50 -#define WR_DFTHRSH_75 0x40 -#define WR_DFTHRSH_63 0x30 -#define WR_DFTHRSH_50 0x20 -#define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 -#define RD_DFTHRSH_90 0x06 -#define RD_DFTHRSH_85 0x05 -#define RD_DFTHRSH_75 0x04 -#define RD_DFTHRSH_63 0x03 -#define RD_DFTHRSH_50 0x02 -#define RD_DFTHRSH_25 0x01 -#define RD_DFTHRSH_MIN 0x00 -#define WR_DFTHRSH_MIN 0x00 - -#define ROMADDR 0x8a - -#define ROMCNTRL 0x8d -#define ROMOP 0xe0 -#define ROMSPD 0x18 -#define REPEAT 0x02 -#define RDY 0x01 - -#define ROMDATA 0x8e - -#define CMCRXMSG0 0x90 - -#define ROENABLE 0x90 -#define MSIROEN 0x20 -#define OVLYROEN 0x10 -#define CMCROEN 0x08 -#define SGROEN 0x04 -#define DCH1ROEN 0x02 -#define DCH0ROEN 0x01 - -#define OVLYRXMSG0 0x90 - -#define DCHRXMSG0 0x90 - -#define OVLYRXMSG1 0x91 - -#define NSENABLE 0x91 -#define MSINSEN 0x20 -#define OVLYNSEN 0x10 -#define CMCNSEN 0x08 -#define SGNSEN 0x04 -#define DCH1NSEN 0x02 -#define DCH0NSEN 0x01 - -#define CMCRXMSG1 0x91 - -#define DCHRXMSG1 0x91 - -#define DCHRXMSG2 0x92 - -#define CMCRXMSG2 0x92 - -#define OST 0x92 - -#define OVLYRXMSG2 0x92 - -#define DCHRXMSG3 0x93 - -#define OVLYRXMSG3 0x93 - -#define CMCRXMSG3 0x93 - -#define PCIXCTL 0x93 -#define SERRPULSE 0x80 -#define UNEXPSCIEN 0x20 -#define SPLTSMADIS 0x10 -#define SPLTSTADIS 0x08 -#define SRSPDPEEN 0x04 -#define TSCSERREN 0x02 -#define CMPABCDIS 0x01 - -#define OVLYSEQBCNT 0x94 - -#define DCHSEQBCNT 0x94 - -#define CMCSEQBCNT 0x94 - -#define CMCSPLTSTAT0 0x96 - -#define DCHSPLTSTAT0 0x96 - -#define OVLYSPLTSTAT0 0x96 - -#define CMCSPLTSTAT1 0x97 - -#define OVLYSPLTSTAT1 0x97 - -#define DCHSPLTSTAT1 0x97 - -#define SGRXMSG0 0x98 -#define CDNUM 0xf8 -#define CFNUM 0x07 - -#define SLVSPLTOUTADR0 0x98 -#define LOWER_ADDR 0x7f - -#define SGRXMSG1 0x99 -#define CBNUM 0xff - -#define SLVSPLTOUTADR1 0x99 -#define REQ_DNUM 0xf8 -#define REQ_FNUM 0x07 - -#define SGRXMSG2 0x9a -#define MINDEX 0xff - -#define SLVSPLTOUTADR2 0x9a -#define REQ_BNUM 0xff - -#define SGRXMSG3 0x9b -#define MCLASS 0x0f - -#define SLVSPLTOUTADR3 0x9b -#define TAG_NUM 0x1f -#define RLXORD 0x10 - -#define SGSEQBCNT 0x9c - -#define SLVSPLTOUTATTR0 0x9c -#define LOWER_BCNT 0xff - -#define SLVSPLTOUTATTR1 0x9d -#define CMPLT_DNUM 0xf8 -#define CMPLT_FNUM 0x07 - -#define SLVSPLTOUTATTR2 0x9e -#define CMPLT_BNUM 0xff - -#define SGSPLTSTAT0 0x9e -#define STAETERM 0x80 -#define SCBCERR 0x40 -#define SCADERR 0x20 -#define SCDATBUCKET 0x10 -#define CNTNOTCMPLT 0x08 -#define RXOVRUN 0x04 -#define RXSCEMSG 0x02 -#define RXSPLTRSP 0x01 - -#define SGSPLTSTAT1 0x9f -#define RXDATABUCKET 0x01 - -#define SFUNCT 0x9f -#define TEST_GROUP 0xf0 -#define TEST_NUM 0x0f - -#define DF0PCISTAT 0xa0 - -#define REG0 0xa0 - -#define DF1PCISTAT 0xa1 - -#define SGPCISTAT 0xa2 - -#define REG1 0xa2 - -#define CMCPCISTAT 0xa3 - -#define OVLYPCISTAT 0xa4 -#define SCAAPERR 0x08 -#define RDPERR 0x04 - -#define REG_ISR 0xa4 - -#define SG_STATE 0xa6 -#define FETCH_INPROG 0x04 -#define LOADING_NEEDED 0x02 -#define SEGS_AVAIL 0x01 - -#define MSIPCISTAT 0xa6 -#define RMA 0x20 -#define RTA 0x10 -#define CLRPENDMSI 0x08 -#define DPR 0x01 - -#define TARGPCISTAT 0xa7 -#define DPE 0x80 -#define SSE 0x40 -#define STA 0x08 -#define TWATERR 0x02 - -#define DATA_COUNT_ODD 0xa7 - -#define SCBPTR 0xa8 - -#define CCSCBACNT 0xab - -#define SCBAUTOPTR 0xab -#define AUSCBPTR_EN 0x80 -#define SCBPTR_ADDR 0x38 -#define SCBPTR_OFF 0x07 - -#define CCSGADDR 0xac - -#define CCSCBADR_BK 0xac - -#define CCSCBADDR 0xac - -#define CMC_RAMBIST 0xad -#define SG_ELEMENT_SIZE 0x80 -#define SCBRAMBIST_FAIL 0x40 -#define SG_BIST_FAIL 0x20 -#define SG_BIST_EN 0x10 -#define CMC_BUFFER_BIST_FAIL 0x02 -#define CMC_BUFFER_BIST_EN 0x01 - -#define CCSCBCTL 0xad -#define CCSCBDONE 0x80 -#define ARRDONE 0x40 -#define CCARREN 0x10 -#define CCSCBEN 0x08 -#define CCSCBDIR 0x04 -#define CCSCBRESET 0x01 - -#define CCSGCTL 0xad -#define CCSGEN 0x0c -#define CCSGDONE 0x80 -#define SG_CACHE_AVAIL 0x10 -#define CCSGENACK 0x08 -#define SG_FETCH_REQ 0x02 -#define CCSGRESET 0x01 - -#define CCSGRAM 0xb0 - -#define FLEXADR 0xb0 - -#define CCSCBRAM 0xb0 - -#define FLEXCNT 0xb3 - -#define FLEXDMASTAT 0xb5 -#define FLEXDMAERR 0x02 -#define FLEXDMADONE 0x01 - -#define FLEXDATA 0xb6 - -#define BRDDAT 0xb8 - -#define BRDCTL 0xb9 -#define FLXARBACK 0x80 -#define FLXARBREQ 0x40 -#define BRDADDR 0x38 -#define BRDEN 0x04 -#define BRDRW 0x02 -#define BRDSTB 0x01 - -#define SEEADR 0xba - -#define SEEDAT 0xbc - -#define SEECTL 0xbe -#define SEEOP_WALL 0x40 -#define SEEOP_EWEN 0x40 -#define SEEOP_EWDS 0x40 -#define SEEOPCODE 0x70 -#define SEERST 0x02 -#define SEESTART 0x01 -#define SEEOP_ERASE 0x70 -#define SEEOP_READ 0x60 -#define SEEOP_WRITE 0x50 -#define SEEOP_ERAL 0x40 - -#define SEESTAT 0xbe -#define INIT_DONE 0x80 -#define LDALTID_L 0x08 -#define SEEARBACK 0x04 -#define SEEBUSY 0x02 - -#define SCBCNT 0xbf - -#define DFWADDR 0xc0 - -#define DSPFLTRCTL 0xc0 -#define FLTRDISABLE 0x20 -#define EDGESENSE 0x10 -#define DSPFCNTSEL 0x0f - -#define DSPDATACTL 0xc1 -#define BYPASSENAB 0x80 -#define DESQDIS 0x10 -#define RCVROFFSTDIS 0x04 -#define XMITOFFSTDIS 0x02 - -#define DFRADDR 0xc2 - -#define DSPREQCTL 0xc2 -#define MANREQCTL 0xc0 -#define MANREQDLY 0x3f - -#define DSPACKCTL 0xc3 -#define MANACKCTL 0xc0 -#define MANACKDLY 0x3f - -#define DFDAT 0xc4 - -#define DSPSELECT 0xc4 -#define AUTOINCEN 0x80 -#define DSPSEL 0x1f - -#define WRTBIASCTL 0xc5 -#define AUTOXBCDIS 0x80 -#define XMITMANVAL 0x3f - -#define RCVRBIOSCTL 0xc6 -#define AUTORBCDIS 0x80 -#define RCVRMANVAL 0x3f - -#define WRTBIASCALC 0xc7 - -#define RCVRBIASCALC 0xc8 - -#define DFPTRS 0xc8 - -#define SKEWCALC 0xc9 - -#define DFBKPTR 0xc9 - -#define DFDBCTL 0xcb -#define DFF_CIO_WR_RDY 0x20 -#define DFF_CIO_RD_RDY 0x10 -#define DFF_DIR_ERR 0x08 -#define DFF_RAMBIST_FAIL 0x04 -#define DFF_RAMBIST_DONE 0x02 -#define DFF_RAMBIST_EN 0x01 - -#define DFSCNT 0xcc - -#define DFBCNT 0xce - -#define OVLYADDR 0xd4 - -#define SEQCTL0 0xd6 -#define PERRORDIS 0x80 -#define PAUSEDIS 0x40 -#define FAILDIS 0x20 -#define FASTMODE 0x10 -#define BRKADRINTEN 0x08 -#define STEP 0x04 -#define SEQRESET 0x02 -#define LOADRAM 0x01 - -#define SEQCTL1 0xd7 -#define OVRLAY_DATA_CHK 0x08 -#define RAMBIST_DONE 0x04 -#define RAMBIST_FAIL 0x02 -#define RAMBIST_EN 0x01 - -#define FLAGS 0xd8 -#define ZERO 0x02 -#define CARRY 0x01 - -#define SEQINTCTL 0xd9 -#define INTVEC1DSL 0x80 -#define INT1_CONTEXT 0x20 -#define SCS_SEQ_INT1M1 0x10 -#define SCS_SEQ_INT1M0 0x08 -#define INTMASK2 0x04 -#define INTMASK1 0x02 -#define IRET 0x01 - -#define SEQRAM 0xda - -#define PRGMCNT 0xde - -#define ACCUM 0xe0 - -#define SINDEX 0xe2 - -#define DINDEX 0xe4 - -#define BRKADDR0 0xe6 - -#define BRKADDR1 0xe6 -#define BRKDIS 0x80 - -#define ALLONES 0xe8 - -#define ALLZEROS 0xea - -#define NONE 0xea - -#define SINDIR 0xec - -#define DINDIR 0xed - -#define FUNCTION1 0xf0 - -#define STACK 0xf2 - -#define INTVEC1_ADDR 0xf4 - -#define CURADDR 0xf4 - -#define LASTADDR 0xf6 - -#define INTVEC2_ADDR 0xf6 - -#define LONGJMP_ADDR 0xf8 - -#define ACCUM_SAVE 0xfa - -#define WAITING_SCB_TAILS 0x100 - -#define AHD_PCI_CONFIG_BASE 0x100 - -#define SRAM_BASE 0x100 - -#define WAITING_TID_HEAD 0x120 - -#define WAITING_TID_TAIL 0x122 - -#define NEXT_QUEUED_SCB_ADDR 0x124 - -#define COMPLETE_SCB_HEAD 0x128 - -#define COMPLETE_SCB_DMAINPROG_HEAD 0x12a - -#define COMPLETE_DMA_SCB_HEAD 0x12c - -#define COMPLETE_DMA_SCB_TAIL 0x12e - -#define COMPLETE_ON_QFREEZE_HEAD 0x130 - -#define QFREEZE_COUNT 0x132 - -#define KERNEL_QFREEZE_COUNT 0x134 - -#define SAVED_MODE 0x136 - -#define MSG_OUT 0x137 - -#define DMAPARAMS 0x138 -#define PRELOADEN 0x80 -#define WIDEODD 0x40 -#define SCSIEN 0x20 -#define SDMAEN 0x10 -#define SDMAENACK 0x10 -#define HDMAEN 0x08 -#define HDMAENACK 0x08 -#define DIRECTION 0x04 -#define FIFOFLUSH 0x02 -#define FIFORESET 0x01 - -#define SEQ_FLAGS 0x139 -#define NOT_IDENTIFIED 0x80 -#define NO_CDB_SENT 0x40 -#define TARGET_CMD_IS_TAGGED 0x40 -#define DPHASE 0x20 -#define TARG_CMD_PENDING 0x10 -#define CMDPHASE_PENDING 0x08 -#define DPHASE_PENDING 0x04 -#define SPHASE_PENDING 0x02 -#define NO_DISCONNECT 0x01 - -#define SAVED_SCSIID 0x13a - -#define SAVED_LUN 0x13b - -#define LASTPHASE 0x13c -#define PHASE_MASK 0xe0 -#define CDI 0x80 -#define IOI 0x40 -#define MSGI 0x20 -#define P_BUSFREE 0x01 -#define P_MESGIN 0xe0 -#define P_STATUS 0xc0 -#define P_MESGOUT 0xa0 -#define P_COMMAND 0x80 -#define P_DATAIN_DT 0x60 -#define P_DATAIN 0x40 -#define P_DATAOUT_DT 0x20 -#define P_DATAOUT 0x00 - -#define QOUTFIFO_ENTRY_VALID_TAG 0x13d - -#define KERNEL_TQINPOS 0x13e - -#define TQINPOS 0x13f - -#define SHARED_DATA_ADDR 0x140 - -#define QOUTFIFO_NEXT_ADDR 0x144 - -#define ARG_1 0x148 -#define RETURN_1 0x148 -#define SEND_MSG 0x80 -#define SEND_SENSE 0x40 -#define SEND_REJ 0x20 -#define MSGOUT_PHASEMIS 0x10 -#define EXIT_MSG_LOOP 0x08 -#define CONT_MSG_LOOP_WRITE 0x04 -#define CONT_MSG_LOOP_READ 0x03 -#define CONT_MSG_LOOP_TARG 0x02 - -#define ARG_2 0x149 -#define RETURN_2 0x149 - -#define LAST_MSG 0x14a - -#define SCSISEQ_TEMPLATE 0x14b -#define MANUALCTL 0x40 -#define ENSELI 0x20 -#define ENRSELI 0x10 -#define MANUALP 0x0c -#define ENAUTOATNP 0x02 -#define ALTSTIM 0x01 - -#define INITIATOR_TAG 0x14c - -#define SEQ_FLAGS2 0x14d -#define SELECTOUT_QFROZEN 0x04 -#define TARGET_MSG_PENDING 0x02 -#define PENDING_MK_MESSAGE 0x01 - -#define ALLOCFIFO_SCBPTR 0x14e - -#define INT_COALESCING_TIMER 0x150 - -#define INT_COALESCING_MAXCMDS 0x152 - -#define INT_COALESCING_MINCMDS 0x153 - -#define CMDS_PENDING 0x154 - -#define INT_COALESCING_CMDCOUNT 0x156 - -#define LOCAL_HS_MAILBOX 0x157 - -#define CMDSIZE_TABLE 0x158 - -#define MK_MESSAGE_SCB 0x160 - -#define MK_MESSAGE_SCSIID 0x162 - -#define SCB_BASE 0x180 - -#define SCB_RESIDUAL_DATACNT 0x180 -#define SCB_CDB_STORE 0x180 -#define SCB_HOST_CDB_PTR 0x180 - -#define SCB_RESIDUAL_SGPTR 0x184 -#define SG_ADDR_MASK 0xf8 -#define SG_OVERRUN_RESID 0x02 - -#define SCB_SCSI_STATUS 0x188 -#define SCB_HOST_CDB_LEN 0x188 - -#define SCB_TARGET_PHASES 0x189 - -#define SCB_TARGET_DATA_DIR 0x18a - -#define SCB_TARGET_ITAG 0x18b - -#define SCB_SENSE_BUSADDR 0x18c -#define SCB_NEXT_COMPLETE 0x18c - -#define SCB_TAG 0x190 -#define SCB_FIFO_USE_COUNT 0x190 - -#define SCB_CONTROL 0x192 -#define TARGET_SCB 0x80 -#define DISCENB 0x40 -#define TAG_ENB 0x20 -#define MK_MESSAGE 0x10 -#define STATUS_RCVD 0x08 -#define DISCONNECTED 0x04 -#define SCB_TAG_TYPE 0x03 - -#define SCB_SCSIID 0x193 -#define TID 0xf0 -#define OID 0x0f - -#define SCB_LUN 0x194 -#define LID 0xff - -#define SCB_TASK_ATTRIBUTE 0x195 -#define SCB_XFERLEN_ODD 0x01 - -#define SCB_CDB_LEN 0x196 -#define SCB_CDB_LEN_PTR 0x80 - -#define SCB_TASK_MANAGEMENT 0x197 - -#define SCB_DATAPTR 0x198 - -#define SCB_DATACNT 0x1a0 -#define SG_LAST_SEG 0x80 -#define SG_HIGH_ADDR_BITS 0x7f - -#define SCB_SGPTR 0x1a4 -#define SG_STATUS_VALID 0x04 -#define SG_FULL_RESID 0x02 -#define SG_LIST_NULL 0x01 - -#define SCB_BUSADDR 0x1a8 - -#define SCB_NEXT 0x1ac -#define SCB_NEXT_SCB_BUSADDR 0x1ac - -#define SCB_NEXT2 0x1ae - -#define SCB_SPARE 0x1b0 -#define SCB_PKT_LUN 0x1b0 - -#define SCB_DISCONNECTED_LISTS 0x1b8 - - -#define AHD_TIMER_MAX_US 0x18ffe7 -#define AHD_TIMER_MAX_TICKS 0xffff -#define AHD_SENSE_BUFSIZE 0x100 -#define BUS_8_BIT 0x00 -#define TARGET_CMD_CMPLT 0xfe -#define SEEOP_WRAL_ADDR 0x40 -#define AHD_AMPLITUDE_DEF 0x07 -#define AHD_PRECOMP_CUTBACK_37 0x07 -#define AHD_PRECOMP_SHIFT 0x00 -#define AHD_ANNEXCOL_PRECOMP_SLEW 0x04 -#define AHD_TIMER_US_PER_TICK 0x19 -#define SCB_TRANSFER_SIZE_FULL_LUN 0x38 -#define STATUS_QUEUE_FULL 0x28 -#define STATUS_BUSY 0x08 -#define MAX_OFFSET_NON_PACED 0x7f -#define MAX_OFFSET_PACED 0xfe -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 -#define TID_SHIFT 0x04 -#define MK_MESSAGE_BIT_OFFSET 0x04 -#define WRTBIASCTL_HP_DEFAULT 0x00 -#define SEEOP_EWDS_ADDR 0x00 -#define AHD_AMPLITUDE_SHIFT 0x00 -#define AHD_AMPLITUDE_MASK 0x07 -#define AHD_ANNEXCOL_AMPLITUDE 0x06 -#define AHD_SLEWRATE_DEF_REVA 0x08 -#define AHD_SLEWRATE_SHIFT 0x03 -#define AHD_SLEWRATE_MASK 0x78 -#define AHD_PRECOMP_CUTBACK_29 0x06 -#define AHD_NUM_PER_DEV_ANNEXCOLS 0x04 -#define B_CURRFIFO_0 0x02 -#define LUNLEN_SINGLE_LEVEL_LUN 0x0f -#define NVRAM_SCB_OFFSET 0x2c -#define STATUS_PKT_SENSE 0xff -#define CMD_GROUP_CODE_SHIFT 0x05 -#define MAX_OFFSET_PACED_BUG 0x7f -#define STIMESEL_BUG_ADJ 0x08 -#define STIMESEL_MIN 0x18 -#define STIMESEL_SHIFT 0x03 -#define CCSGRAM_MAXSEGS 0x10 -#define INVALID_ADDR 0x80 -#define SEEOP_ERAL_ADDR 0x80 -#define AHD_SLEWRATE_DEF_REVB 0x08 -#define AHD_PRECOMP_CUTBACK_17 0x04 -#define AHD_PRECOMP_MASK 0x07 -#define SRC_MODE_SHIFT 0x00 -#define PKT_OVERRUN_BUFSIZE 0x200 -#define SCB_TRANSFER_SIZE_1BYTE_LUN 0x30 -#define TARGET_DATA_IN 0x01 -#define HOST_MSG 0xff -#define MAX_OFFSET 0xfe -#define BUS_16_BIT 0x01 -#define CCSCBADDR_MAX 0x80 -#define NUMDSPS 0x14 -#define SEEOP_EWEN_ADDR 0xc0 -#define AHD_ANNEXCOL_PER_DEV0 0x04 -#define DST_MODE_SHIFT 0x04 - - -/* Downloaded Constant Definitions */ -#define CACHELINE_MASK 0x07 -#define SCB_TRANSFER_SIZE 0x06 -#define PKT_OVERRUN_BUFOFFSET 0x05 -#define SG_SIZEOF 0x04 -#define SG_PREFETCH_ADDR_MASK 0x03 -#define SG_PREFETCH_ALIGN_MASK 0x02 -#define SG_PREFETCH_CNT_LIMIT 0x01 -#define SG_PREFETCH_CNT 0x00 -#define DOWNLOAD_CONST_COUNT 0x08 - - -/* Exported Labels */ -#define LABEL_seq_isr 0x28f -#define LABEL_timer_isr 0x28b diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped deleted file mode 100644 index f5ea715d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped +++ /dev/null @@ -1,745 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated - * from the following source files: - * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $ - */ - -#include "aic79xx_osm.h" - -static const ahd_reg_parse_entry_t INTSTAT_parse_table[] = { - { "SPLTINT", 0x01, 0x01 }, - { "CMDCMPLT", 0x02, 0x02 }, - { "SEQINT", 0x04, 0x04 }, - { "SCSIINT", 0x08, 0x08 }, - { "PCIINT", 0x10, 0x10 }, - { "SWTMINT", 0x20, 0x20 }, - { "BRKADRINT", 0x40, 0x40 }, - { "HWERRINT", 0x80, 0x80 }, - { "INT_PEND", 0xff, 0xff } -}; - -int -ahd_intstat_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(INTSTAT_parse_table, 9, "INTSTAT", - 0x01, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t HS_MAILBOX_parse_table[] = { - { "ENINT_COALESCE", 0x40, 0x40 }, - { "HOST_TQINPOS", 0x80, 0x80 } -}; - -int -ahd_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(HS_MAILBOX_parse_table, 2, "HS_MAILBOX", - 0x0b, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SEQINTSTAT_parse_table[] = { - { "SEQ_SPLTINT", 0x01, 0x01 }, - { "SEQ_PCIINT", 0x02, 0x02 }, - { "SEQ_SCSIINT", 0x04, 0x04 }, - { "SEQ_SEQINT", 0x08, 0x08 }, - { "SEQ_SWTMRTO", 0x10, 0x10 } -}; - -int -ahd_seqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SEQINTSTAT_parse_table, 5, "SEQINTSTAT", - 0x0c, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t INTCTL_parse_table[] = { - { "SPLTINTEN", 0x01, 0x01 }, - { "SEQINTEN", 0x02, 0x02 }, - { "SCSIINTEN", 0x04, 0x04 }, - { "PCIINTEN", 0x08, 0x08 }, - { "AUTOCLRCMDINT", 0x10, 0x10 }, - { "SWTIMER_START", 0x20, 0x20 }, - { "SWTMINTEN", 0x40, 0x40 }, - { "SWTMINTMASK", 0x80, 0x80 } -}; - -int -ahd_intctl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(INTCTL_parse_table, 8, "INTCTL", - 0x18, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t DFCNTRL_parse_table[] = { - { "DIRECTIONEN", 0x01, 0x01 }, - { "FIFOFLUSH", 0x02, 0x02 }, - { "FIFOFLUSHACK", 0x02, 0x02 }, - { "DIRECTION", 0x04, 0x04 }, - { "DIRECTIONACK", 0x04, 0x04 }, - { "HDMAEN", 0x08, 0x08 }, - { "HDMAENACK", 0x08, 0x08 }, - { "SCSIEN", 0x20, 0x20 }, - { "SCSIENACK", 0x20, 0x20 }, - { "SCSIENWRDIS", 0x40, 0x40 }, - { "PRELOADEN", 0x80, 0x80 } -}; - -int -ahd_dfcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(DFCNTRL_parse_table, 11, "DFCNTRL", - 0x19, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t DFSTATUS_parse_table[] = { - { "FIFOEMP", 0x01, 0x01 }, - { "FIFOFULL", 0x02, 0x02 }, - { "DFTHRESH", 0x04, 0x04 }, - { "HDONE", 0x08, 0x08 }, - { "MREQPEND", 0x10, 0x10 }, - { "PKT_PRELOAD_AVAIL", 0x40, 0x40 }, - { "PRELOAD_AVAIL", 0x80, 0x80 } -}; - -int -ahd_dfstatus_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(DFSTATUS_parse_table, 7, "DFSTATUS", - 0x1a, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = { - { "LAST_SEG_DONE", 0x01, 0x01 }, - { "LAST_SEG", 0x02, 0x02 }, - { "ODD_SEG", 0x04, 0x04 }, - { "SG_ADDR_MASK", 0xf8, 0xf8 } -}; - -int -ahd_sg_cache_shadow_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SG_CACHE_SHADOW_parse_table, 4, "SG_CACHE_SHADOW", - 0x1b, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SCSISEQ0_parse_table[] = { - { "SCSIRSTO", 0x01, 0x01 }, - { "FORCEBUSFREE", 0x10, 0x10 }, - { "ENARBO", 0x20, 0x20 }, - { "ENSELO", 0x40, 0x40 }, - { "TEMODEO", 0x80, 0x80 } -}; - -int -ahd_scsiseq0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCSISEQ0_parse_table, 5, "SCSISEQ0", - 0x3a, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SCSISEQ1_parse_table[] = { - { "ALTSTIM", 0x01, 0x01 }, - { "ENAUTOATNP", 0x02, 0x02 }, - { "MANUALP", 0x0c, 0x0c }, - { "ENRSELI", 0x10, 0x10 }, - { "ENSELI", 0x20, 0x20 }, - { "MANUALCTL", 0x40, 0x40 } -}; - -int -ahd_scsiseq1_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCSISEQ1_parse_table, 6, "SCSISEQ1", - 0x3b, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t DFFSTAT_parse_table[] = { - { "CURRFIFO_0", 0x00, 0x03 }, - { "CURRFIFO_1", 0x01, 0x03 }, - { "CURRFIFO_NONE", 0x03, 0x03 }, - { "FIFO0FREE", 0x10, 0x10 }, - { "FIFO1FREE", 0x20, 0x20 }, - { "CURRFIFO", 0x03, 0x03 } -}; - -int -ahd_dffstat_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(DFFSTAT_parse_table, 6, "DFFSTAT", - 0x3f, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SCSISIGI_parse_table[] = { - { "P_DATAOUT", 0x00, 0xe0 }, - { "P_DATAOUT_DT", 0x20, 0xe0 }, - { "P_DATAIN", 0x40, 0xe0 }, - { "P_DATAIN_DT", 0x60, 0xe0 }, - { "P_COMMAND", 0x80, 0xe0 }, - { "P_MESGOUT", 0xa0, 0xe0 }, - { "P_STATUS", 0xc0, 0xe0 }, - { "P_MESGIN", 0xe0, 0xe0 }, - { "ACKI", 0x01, 0x01 }, - { "REQI", 0x02, 0x02 }, - { "BSYI", 0x04, 0x04 }, - { "SELI", 0x08, 0x08 }, - { "ATNI", 0x10, 0x10 }, - { "MSGI", 0x20, 0x20 }, - { "IOI", 0x40, 0x40 }, - { "CDI", 0x80, 0x80 }, - { "PHASE_MASK", 0xe0, 0xe0 } -}; - -int -ahd_scsisigi_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCSISIGI_parse_table, 17, "SCSISIGI", - 0x41, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SCSIPHASE_parse_table[] = { - { "DATA_OUT_PHASE", 0x01, 0x03 }, - { "DATA_IN_PHASE", 0x02, 0x03 }, - { "DATA_PHASE_MASK", 0x03, 0x03 }, - { "MSG_OUT_PHASE", 0x04, 0x04 }, - { "MSG_IN_PHASE", 0x08, 0x08 }, - { "COMMAND_PHASE", 0x10, 0x10 }, - { "STATUS_PHASE", 0x20, 0x20 } -}; - -int -ahd_scsiphase_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCSIPHASE_parse_table, 7, "SCSIPHASE", - 0x42, regvalue, cur_col, wrap)); -} - -int -ahd_scsibus_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SCSIBUS", - 0x46, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SELID_parse_table[] = { - { "ONEBIT", 0x08, 0x08 }, - { "SELID_MASK", 0xf0, 0xf0 } -}; - -int -ahd_selid_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SELID_parse_table, 2, "SELID", - 0x49, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SSTAT0_parse_table[] = { - { "ARBDO", 0x01, 0x01 }, - { "SPIORDY", 0x02, 0x02 }, - { "OVERRUN", 0x04, 0x04 }, - { "IOERR", 0x08, 0x08 }, - { "SELINGO", 0x10, 0x10 }, - { "SELDI", 0x20, 0x20 }, - { "SELDO", 0x40, 0x40 }, - { "TARGET", 0x80, 0x80 } -}; - -int -ahd_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SSTAT0_parse_table, 8, "SSTAT0", - 0x4b, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SIMODE0_parse_table[] = { - { "ENARBDO", 0x01, 0x01 }, - { "ENSPIORDY", 0x02, 0x02 }, - { "ENOVERRUN", 0x04, 0x04 }, - { "ENIOERR", 0x08, 0x08 }, - { "ENSELINGO", 0x10, 0x10 }, - { "ENSELDI", 0x20, 0x20 }, - { "ENSELDO", 0x40, 0x40 } -}; - -int -ahd_simode0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SIMODE0_parse_table, 7, "SIMODE0", - 0x4b, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SSTAT1_parse_table[] = { - { "REQINIT", 0x01, 0x01 }, - { "STRB2FAST", 0x02, 0x02 }, - { "SCSIPERR", 0x04, 0x04 }, - { "BUSFREE", 0x08, 0x08 }, - { "PHASEMIS", 0x10, 0x10 }, - { "SCSIRSTI", 0x20, 0x20 }, - { "ATNTARG", 0x40, 0x40 }, - { "SELTO", 0x80, 0x80 } -}; - -int -ahd_sstat1_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SSTAT1_parse_table, 8, "SSTAT1", - 0x4c, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SSTAT2_parse_table[] = { - { "BUSFREE_LQO", 0x40, 0xc0 }, - { "BUSFREE_DFF0", 0x80, 0xc0 }, - { "BUSFREE_DFF1", 0xc0, 0xc0 }, - { "DMADONE", 0x01, 0x01 }, - { "SDONE", 0x02, 0x02 }, - { "WIDE_RES", 0x04, 0x04 }, - { "BSYX", 0x08, 0x08 }, - { "EXP_ACTIVE", 0x10, 0x10 }, - { "NONPACKREQ", 0x20, 0x20 }, - { "BUSFREETIME", 0xc0, 0xc0 } -}; - -int -ahd_sstat2_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SSTAT2_parse_table, 10, "SSTAT2", - 0x4d, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t PERRDIAG_parse_table[] = { - { "DTERR", 0x01, 0x01 }, - { "DGFORMERR", 0x02, 0x02 }, - { "CRCERR", 0x04, 0x04 }, - { "AIPERR", 0x08, 0x08 }, - { "PARITYERR", 0x10, 0x10 }, - { "PREVPHASE", 0x20, 0x20 }, - { "HIPERR", 0x40, 0x40 }, - { "HIZERO", 0x80, 0x80 } -}; - -int -ahd_perrdiag_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(PERRDIAG_parse_table, 8, "PERRDIAG", - 0x4e, regvalue, cur_col, wrap)); -} - -int -ahd_soffcnt_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SOFFCNT", - 0x4f, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t LQISTAT0_parse_table[] = { - { "LQIATNCMD", 0x01, 0x01 }, - { "LQIATNLQ", 0x02, 0x02 }, - { "LQIBADLQT", 0x04, 0x04 }, - { "LQICRCT2", 0x08, 0x08 }, - { "LQICRCT1", 0x10, 0x10 }, - { "LQIATNQAS", 0x20, 0x20 } -}; - -int -ahd_lqistat0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(LQISTAT0_parse_table, 6, "LQISTAT0", - 0x50, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t LQISTAT1_parse_table[] = { - { "LQIOVERI_NLQ", 0x01, 0x01 }, - { "LQIOVERI_LQ", 0x02, 0x02 }, - { "LQIBADLQI", 0x04, 0x04 }, - { "LQICRCI_NLQ", 0x08, 0x08 }, - { "LQICRCI_LQ", 0x10, 0x10 }, - { "LQIABORT", 0x20, 0x20 }, - { "LQIPHASE_NLQ", 0x40, 0x40 }, - { "LQIPHASE_LQ", 0x80, 0x80 } -}; - -int -ahd_lqistat1_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(LQISTAT1_parse_table, 8, "LQISTAT1", - 0x51, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t LQISTAT2_parse_table[] = { - { "LQIGSAVAIL", 0x01, 0x01 }, - { "LQISTOPCMD", 0x02, 0x02 }, - { "LQISTOPLQ", 0x04, 0x04 }, - { "LQISTOPPKT", 0x08, 0x08 }, - { "LQIWAITFIFO", 0x10, 0x10 }, - { "LQIWORKONLQ", 0x20, 0x20 }, - { "LQIPHASE_OUTPKT", 0x40, 0x40 }, - { "PACKETIZED", 0x80, 0x80 } -}; - -int -ahd_lqistat2_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(LQISTAT2_parse_table, 8, "LQISTAT2", - 0x52, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SSTAT3_parse_table[] = { - { "OSRAMPERR", 0x01, 0x01 }, - { "NTRAMPERR", 0x02, 0x02 } -}; - -int -ahd_sstat3_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SSTAT3_parse_table, 2, "SSTAT3", - 0x53, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t LQOSTAT0_parse_table[] = { - { "LQOTCRC", 0x01, 0x01 }, - { "LQOATNPKT", 0x02, 0x02 }, - { "LQOATNLQ", 0x04, 0x04 }, - { "LQOSTOPT2", 0x08, 0x08 }, - { "LQOTARGSCBPERR", 0x10, 0x10 } -}; - -int -ahd_lqostat0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(LQOSTAT0_parse_table, 5, "LQOSTAT0", - 0x54, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t LQOSTAT1_parse_table[] = { - { "LQOPHACHGINPKT", 0x01, 0x01 }, - { "LQOBUSFREE", 0x02, 0x02 }, - { "LQOBADQAS", 0x04, 0x04 }, - { "LQOSTOPI2", 0x08, 0x08 }, - { "LQOINITSCBPERR", 0x10, 0x10 } -}; - -int -ahd_lqostat1_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(LQOSTAT1_parse_table, 5, "LQOSTAT1", - 0x55, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t LQOSTAT2_parse_table[] = { - { "LQOSTOP0", 0x01, 0x01 }, - { "LQOPHACHGOUTPKT", 0x02, 0x02 }, - { "LQOWAITFIFO", 0x10, 0x10 }, - { "LQOPKT", 0xe0, 0xe0 } -}; - -int -ahd_lqostat2_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(LQOSTAT2_parse_table, 4, "LQOSTAT2", - 0x56, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SIMODE1_parse_table[] = { - { "ENREQINIT", 0x01, 0x01 }, - { "ENSTRB2FAST", 0x02, 0x02 }, - { "ENSCSIPERR", 0x04, 0x04 }, - { "ENBUSFREE", 0x08, 0x08 }, - { "ENPHASEMIS", 0x10, 0x10 }, - { "ENSCSIRST", 0x20, 0x20 }, - { "ENATNTARG", 0x40, 0x40 }, - { "ENSELTIMO", 0x80, 0x80 } -}; - -int -ahd_simode1_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SIMODE1_parse_table, 8, "SIMODE1", - 0x57, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t DFFSXFRCTL_parse_table[] = { - { "RSTCHN", 0x01, 0x01 }, - { "CLRCHN", 0x02, 0x02 }, - { "CLRSHCNT", 0x04, 0x04 }, - { "DFFBITBUCKET", 0x08, 0x08 } -}; - -int -ahd_dffsxfrctl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(DFFSXFRCTL_parse_table, 4, "DFFSXFRCTL", - 0x5a, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SEQINTSRC_parse_table[] = { - { "CFG4TCMD", 0x01, 0x01 }, - { "CFG4ICMD", 0x02, 0x02 }, - { "CFG4TSTAT", 0x04, 0x04 }, - { "CFG4ISTAT", 0x08, 0x08 }, - { "CFG4DATA", 0x10, 0x10 }, - { "SAVEPTRS", 0x20, 0x20 }, - { "CTXTDONE", 0x40, 0x40 } -}; - -int -ahd_seqintsrc_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SEQINTSRC_parse_table, 7, "SEQINTSRC", - 0x5b, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SEQIMODE_parse_table[] = { - { "ENCFG4TCMD", 0x01, 0x01 }, - { "ENCFG4ICMD", 0x02, 0x02 }, - { "ENCFG4TSTAT", 0x04, 0x04 }, - { "ENCFG4ISTAT", 0x08, 0x08 }, - { "ENCFG4DATA", 0x10, 0x10 }, - { "ENSAVEPTRS", 0x20, 0x20 }, - { "ENCTXTDONE", 0x40, 0x40 } -}; - -int -ahd_seqimode_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SEQIMODE_parse_table, 7, "SEQIMODE", - 0x5c, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t MDFFSTAT_parse_table[] = { - { "FIFOFREE", 0x01, 0x01 }, - { "DATAINFIFO", 0x02, 0x02 }, - { "DLZERO", 0x04, 0x04 }, - { "SHVALID", 0x08, 0x08 }, - { "LASTSDONE", 0x10, 0x10 }, - { "SHCNTMINUS1", 0x20, 0x20 }, - { "SHCNTNEGATIVE", 0x40, 0x40 } -}; - -int -ahd_mdffstat_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(MDFFSTAT_parse_table, 7, "MDFFSTAT", - 0x5d, regvalue, cur_col, wrap)); -} - -int -ahd_seloid_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SELOID", - 0x6b, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SG_STATE_parse_table[] = { - { "SEGS_AVAIL", 0x01, 0x01 }, - { "LOADING_NEEDED", 0x02, 0x02 }, - { "FETCH_INPROG", 0x04, 0x04 } -}; - -int -ahd_sg_state_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SG_STATE_parse_table, 3, "SG_STATE", - 0xa6, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t CCSCBCTL_parse_table[] = { - { "CCSCBRESET", 0x01, 0x01 }, - { "CCSCBDIR", 0x04, 0x04 }, - { "CCSCBEN", 0x08, 0x08 }, - { "CCARREN", 0x10, 0x10 }, - { "ARRDONE", 0x40, 0x40 }, - { "CCSCBDONE", 0x80, 0x80 } -}; - -int -ahd_ccscbctl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(CCSCBCTL_parse_table, 6, "CCSCBCTL", - 0xad, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t CCSGCTL_parse_table[] = { - { "CCSGRESET", 0x01, 0x01 }, - { "SG_FETCH_REQ", 0x02, 0x02 }, - { "CCSGENACK", 0x08, 0x08 }, - { "SG_CACHE_AVAIL", 0x10, 0x10 }, - { "CCSGDONE", 0x80, 0x80 }, - { "CCSGEN", 0x0c, 0x0c } -}; - -int -ahd_ccsgctl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(CCSGCTL_parse_table, 6, "CCSGCTL", - 0xad, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SEQCTL0_parse_table[] = { - { "LOADRAM", 0x01, 0x01 }, - { "SEQRESET", 0x02, 0x02 }, - { "STEP", 0x04, 0x04 }, - { "BRKADRINTEN", 0x08, 0x08 }, - { "FASTMODE", 0x10, 0x10 }, - { "FAILDIS", 0x20, 0x20 }, - { "PAUSEDIS", 0x40, 0x40 }, - { "PERRORDIS", 0x80, 0x80 } -}; - -int -ahd_seqctl0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SEQCTL0_parse_table, 8, "SEQCTL0", - 0xd6, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SEQINTCTL_parse_table[] = { - { "IRET", 0x01, 0x01 }, - { "INTMASK1", 0x02, 0x02 }, - { "INTMASK2", 0x04, 0x04 }, - { "SCS_SEQ_INT1M0", 0x08, 0x08 }, - { "SCS_SEQ_INT1M1", 0x10, 0x10 }, - { "INT1_CONTEXT", 0x20, 0x20 }, - { "INTVEC1DSL", 0x80, 0x80 } -}; - -int -ahd_seqintctl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SEQINTCTL_parse_table, 7, "SEQINTCTL", - 0xd9, regvalue, cur_col, wrap)); -} - -int -ahd_sram_base_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SRAM_BASE", - 0x100, regvalue, cur_col, wrap)); -} - -int -ahd_qfreeze_count_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "QFREEZE_COUNT", - 0x132, regvalue, cur_col, wrap)); -} - -int -ahd_kernel_qfreeze_count_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "KERNEL_QFREEZE_COUNT", - 0x134, regvalue, cur_col, wrap)); -} - -int -ahd_saved_mode_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SAVED_MODE", - 0x136, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SEQ_FLAGS_parse_table[] = { - { "NO_DISCONNECT", 0x01, 0x01 }, - { "SPHASE_PENDING", 0x02, 0x02 }, - { "DPHASE_PENDING", 0x04, 0x04 }, - { "CMDPHASE_PENDING", 0x08, 0x08 }, - { "TARG_CMD_PENDING", 0x10, 0x10 }, - { "DPHASE", 0x20, 0x20 }, - { "NO_CDB_SENT", 0x40, 0x40 }, - { "TARGET_CMD_IS_TAGGED",0x40, 0x40 }, - { "NOT_IDENTIFIED", 0x80, 0x80 } -}; - -int -ahd_seq_flags_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SEQ_FLAGS_parse_table, 9, "SEQ_FLAGS", - 0x139, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t LASTPHASE_parse_table[] = { - { "P_DATAOUT", 0x00, 0xe0 }, - { "P_DATAOUT_DT", 0x20, 0xe0 }, - { "P_DATAIN", 0x40, 0xe0 }, - { "P_DATAIN_DT", 0x60, 0xe0 }, - { "P_COMMAND", 0x80, 0xe0 }, - { "P_MESGOUT", 0xa0, 0xe0 }, - { "P_STATUS", 0xc0, 0xe0 }, - { "P_MESGIN", 0xe0, 0xe0 }, - { "P_BUSFREE", 0x01, 0x01 }, - { "MSGI", 0x20, 0x20 }, - { "IOI", 0x40, 0x40 }, - { "CDI", 0x80, 0x80 }, - { "PHASE_MASK", 0xe0, 0xe0 } -}; - -int -ahd_lastphase_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(LASTPHASE_parse_table, 13, "LASTPHASE", - 0x13c, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = { - { "PENDING_MK_MESSAGE", 0x01, 0x01 }, - { "TARGET_MSG_PENDING", 0x02, 0x02 }, - { "SELECTOUT_QFROZEN", 0x04, 0x04 } -}; - -int -ahd_seq_flags2_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SEQ_FLAGS2_parse_table, 3, "SEQ_FLAGS2", - 0x14d, regvalue, cur_col, wrap)); -} - -int -ahd_mk_message_scb_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "MK_MESSAGE_SCB", - 0x160, regvalue, cur_col, wrap)); -} - -int -ahd_mk_message_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "MK_MESSAGE_SCSIID", - 0x162, regvalue, cur_col, wrap)); -} - -int -ahd_scb_base_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SCB_BASE", - 0x180, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SCB_CONTROL_parse_table[] = { - { "SCB_TAG_TYPE", 0x03, 0x03 }, - { "DISCONNECTED", 0x04, 0x04 }, - { "STATUS_RCVD", 0x08, 0x08 }, - { "MK_MESSAGE", 0x10, 0x10 }, - { "TAG_ENB", 0x20, 0x20 }, - { "DISCENB", 0x40, 0x40 }, - { "TARGET_SCB", 0x80, 0x80 } -}; - -int -ahd_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCB_CONTROL_parse_table, 7, "SCB_CONTROL", - 0x192, regvalue, cur_col, wrap)); -} - -static const ahd_reg_parse_entry_t SCB_SCSIID_parse_table[] = { - { "OID", 0x0f, 0x0f }, - { "TID", 0xf0, 0xf0 } -}; - -int -ahd_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCB_SCSIID_parse_table, 2, "SCB_SCSIID", - 0x193, regvalue, cur_col, wrap)); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped deleted file mode 100644 index 4b51e232..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped +++ /dev/null @@ -1,1190 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated - * from the following source files: - * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#120 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#77 $ - */ -static const uint8_t seqprog[] = { - 0xff, 0x02, 0x06, 0x78, - 0x00, 0xea, 0x6e, 0x59, - 0x01, 0xea, 0x04, 0x30, - 0xff, 0x04, 0x0c, 0x78, - 0x19, 0xea, 0x6e, 0x59, - 0x19, 0xea, 0x04, 0x00, - 0x33, 0xea, 0x68, 0x59, - 0x33, 0xea, 0x00, 0x00, - 0x60, 0x3a, 0x3a, 0x68, - 0x04, 0x4d, 0x35, 0x78, - 0x01, 0x34, 0xc1, 0x31, - 0x00, 0x32, 0x21, 0x60, - 0x01, 0x35, 0xc1, 0x31, - 0x00, 0x33, 0x21, 0x60, - 0xfb, 0x4d, 0x9b, 0x0a, - 0x00, 0xe2, 0x34, 0x40, - 0x50, 0x4b, 0x3a, 0x68, - 0xff, 0x31, 0x3b, 0x70, - 0x02, 0x30, 0x51, 0x31, - 0xff, 0x8d, 0x2d, 0x70, - 0x02, 0x8c, 0x51, 0x31, - 0xff, 0x8d, 0x29, 0x60, - 0x02, 0x28, 0x19, 0x33, - 0x02, 0x30, 0x51, 0x32, - 0xff, 0xea, 0x62, 0x02, - 0x00, 0xe2, 0x3a, 0x40, - 0xff, 0x21, 0x3b, 0x70, - 0x40, 0x4b, 0xb4, 0x69, - 0x00, 0xe2, 0x72, 0x59, - 0x40, 0x4b, 0xb4, 0x69, - 0x20, 0x4b, 0xa0, 0x69, - 0xfc, 0x42, 0x44, 0x78, - 0x10, 0x40, 0x44, 0x78, - 0x00, 0xe2, 0x10, 0x5e, - 0x20, 0x4d, 0x48, 0x78, - 0x00, 0xe2, 0x10, 0x5e, - 0x30, 0x3f, 0xc0, 0x09, - 0x30, 0xe0, 0x50, 0x60, - 0x7f, 0x4a, 0x94, 0x08, - 0x00, 0xe2, 0x52, 0x40, - 0xc0, 0x4a, 0x94, 0x00, - 0x00, 0xe2, 0x5e, 0x58, - 0x00, 0xe2, 0x76, 0x58, - 0x00, 0xe2, 0x86, 0x58, - 0x00, 0xe2, 0x06, 0x40, - 0x33, 0xea, 0x68, 0x59, - 0x33, 0xea, 0x00, 0x00, - 0x01, 0x52, 0x84, 0x78, - 0x02, 0x58, 0x50, 0x31, - 0xff, 0xea, 0x10, 0x0b, - 0xff, 0x97, 0x6f, 0x78, - 0x50, 0x4b, 0x6a, 0x68, - 0xbf, 0x3a, 0x74, 0x08, - 0x14, 0xea, 0x6e, 0x59, - 0x14, 0xea, 0x04, 0x00, - 0x08, 0x92, 0x25, 0x03, - 0xff, 0x90, 0x5f, 0x68, - 0x00, 0xe2, 0x8a, 0x5b, - 0x00, 0xe2, 0x5e, 0x40, - 0x00, 0xea, 0x68, 0x59, - 0x01, 0xea, 0x00, 0x30, - 0x80, 0xf9, 0x7e, 0x68, - 0x00, 0xe2, 0x66, 0x59, - 0x11, 0xea, 0x68, 0x59, - 0x11, 0xea, 0x00, 0x00, - 0x80, 0xf9, 0x66, 0x79, - 0xff, 0xea, 0xd4, 0x0d, - 0x22, 0xea, 0x68, 0x59, - 0x22, 0xea, 0x00, 0x00, - 0x10, 0x16, 0x90, 0x78, - 0x10, 0x16, 0x2c, 0x00, - 0x01, 0x0b, 0xae, 0x32, - 0x18, 0xad, 0x1c, 0x79, - 0x04, 0xad, 0xdc, 0x68, - 0x80, 0xad, 0x84, 0x78, - 0x10, 0xad, 0xaa, 0x78, - 0xe7, 0xad, 0x5a, 0x09, - 0x02, 0x8c, 0x59, 0x32, - 0xff, 0x8d, 0xa1, 0x60, - 0xff, 0xea, 0x5e, 0x02, - 0xff, 0x88, 0xa7, 0x78, - 0x02, 0x30, 0x19, 0x33, - 0x02, 0xa8, 0x60, 0x36, - 0x02, 0x28, 0x19, 0x33, - 0x02, 0xa8, 0x50, 0x36, - 0xe7, 0xad, 0x5a, 0x09, - 0x00, 0xe2, 0xb8, 0x58, - 0xff, 0xea, 0x56, 0x02, - 0x04, 0x7c, 0x88, 0x32, - 0x20, 0x16, 0x84, 0x78, - 0x04, 0x40, 0x89, 0x32, - 0x80, 0x3d, 0x7b, 0x16, - 0xff, 0x2d, 0xc7, 0x60, - 0xff, 0x29, 0xc7, 0x60, - 0x40, 0x57, 0xd7, 0x78, - 0xff, 0x55, 0xc7, 0x68, - 0xff, 0x53, 0xc1, 0x19, - 0x00, 0x54, 0xd5, 0x19, - 0x00, 0xe2, 0xd6, 0x50, - 0x01, 0x52, 0xc1, 0x31, - 0x00, 0x56, 0xd5, 0x19, - 0x00, 0xe2, 0xd6, 0x48, - 0x80, 0x18, 0x84, 0x78, - 0x02, 0x50, 0x1d, 0x30, - 0x10, 0xea, 0x18, 0x00, - 0x60, 0x18, 0x30, 0x00, - 0x7f, 0x18, 0x30, 0x0c, - 0x02, 0xea, 0x02, 0x00, - 0xff, 0xea, 0xac, 0x0a, - 0x80, 0x18, 0x30, 0x04, - 0x40, 0xad, 0x84, 0x78, - 0xe7, 0xad, 0x5a, 0x09, - 0xff, 0xea, 0xc0, 0x09, - 0x01, 0x54, 0xa9, 0x1a, - 0x00, 0x55, 0xab, 0x22, - 0x01, 0x94, 0x6d, 0x33, - 0xff, 0xea, 0x20, 0x0b, - 0x04, 0xac, 0x49, 0x32, - 0xff, 0xea, 0x5a, 0x03, - 0xff, 0xea, 0x5e, 0x03, - 0x01, 0x10, 0xd4, 0x31, - 0x02, 0xa8, 0x40, 0x31, - 0x01, 0x92, 0xc1, 0x31, - 0x3d, 0x93, 0xc5, 0x29, - 0xfe, 0xe2, 0xc4, 0x09, - 0x01, 0xea, 0xc6, 0x01, - 0x02, 0xe2, 0xc8, 0x31, - 0x02, 0xec, 0x50, 0x31, - 0x02, 0xa0, 0xda, 0x31, - 0xff, 0xa9, 0x10, 0x71, - 0x10, 0xe0, 0x0e, 0x79, - 0x10, 0x92, 0x0f, 0x79, - 0x01, 0x4d, 0x9b, 0x02, - 0x02, 0xa0, 0xc0, 0x32, - 0x01, 0x93, 0xc5, 0x36, - 0x02, 0xa0, 0x58, 0x37, - 0xff, 0x21, 0x19, 0x71, - 0x02, 0x22, 0x51, 0x31, - 0x02, 0xa0, 0x5c, 0x33, - 0x02, 0xa0, 0x44, 0x36, - 0x02, 0xa0, 0x40, 0x32, - 0x02, 0xa0, 0x44, 0x36, - 0x05, 0x4d, 0x21, 0x69, - 0x40, 0x16, 0x52, 0x69, - 0xff, 0x2d, 0x57, 0x61, - 0xff, 0x29, 0x85, 0x70, - 0x02, 0x28, 0x55, 0x32, - 0x01, 0xea, 0x5a, 0x01, - 0x04, 0x44, 0xf9, 0x30, - 0x01, 0x44, 0xc1, 0x31, - 0x02, 0x28, 0x51, 0x31, - 0x02, 0xa8, 0x60, 0x31, - 0x01, 0xa4, 0x61, 0x31, - 0x01, 0x3d, 0x61, 0x31, - 0x01, 0x14, 0xd4, 0x31, - 0x01, 0x56, 0xad, 0x1a, - 0xff, 0x54, 0xa9, 0x1a, - 0xff, 0x55, 0xab, 0x22, - 0xff, 0x8d, 0x4b, 0x71, - 0x80, 0xac, 0x4a, 0x71, - 0x20, 0x16, 0x4a, 0x69, - 0x00, 0xac, 0xc4, 0x19, - 0x07, 0xe2, 0x4a, 0xf9, - 0x02, 0x8c, 0x51, 0x31, - 0x00, 0xe2, 0x2e, 0x41, - 0x01, 0xac, 0x08, 0x31, - 0x09, 0xea, 0x5a, 0x01, - 0x02, 0x8c, 0x51, 0x32, - 0xff, 0xea, 0x1a, 0x07, - 0x04, 0x24, 0xf9, 0x30, - 0x1d, 0xea, 0x5c, 0x41, - 0x02, 0x2c, 0x51, 0x31, - 0x04, 0xa8, 0xf9, 0x30, - 0x19, 0xea, 0x5c, 0x41, - 0x06, 0xea, 0x08, 0x81, - 0x01, 0xe2, 0x5a, 0x35, - 0x02, 0xf2, 0xf0, 0x31, - 0xff, 0xea, 0xd4, 0x0d, - 0x02, 0xf2, 0xf0, 0x31, - 0x02, 0xf8, 0xe4, 0x35, - 0x80, 0xea, 0xb2, 0x01, - 0x01, 0xe2, 0x00, 0x30, - 0xff, 0xea, 0xb2, 0x0d, - 0x01, 0xe2, 0x04, 0x30, - 0x01, 0xea, 0x04, 0x34, - 0x02, 0x20, 0xbd, 0x30, - 0x02, 0x20, 0xb9, 0x30, - 0x02, 0x20, 0x51, 0x31, - 0x4c, 0x93, 0xd7, 0x28, - 0x10, 0x92, 0x81, 0x79, - 0x01, 0x6b, 0xc0, 0x30, - 0x02, 0x64, 0xc8, 0x00, - 0x40, 0x3a, 0x74, 0x04, - 0x00, 0xe2, 0x76, 0x58, - 0x33, 0xea, 0x68, 0x59, - 0x33, 0xea, 0x00, 0x00, - 0x30, 0x3f, 0xc0, 0x09, - 0x30, 0xe0, 0x82, 0x61, - 0x20, 0x3f, 0x98, 0x69, - 0x10, 0x3f, 0x82, 0x79, - 0x02, 0xea, 0x7e, 0x00, - 0x00, 0xea, 0x68, 0x59, - 0x01, 0xea, 0x00, 0x30, - 0x02, 0x4e, 0x51, 0x35, - 0x01, 0xea, 0x7e, 0x00, - 0x11, 0xea, 0x68, 0x59, - 0x11, 0xea, 0x00, 0x00, - 0x02, 0x4e, 0x51, 0x35, - 0xc0, 0x4a, 0x94, 0x00, - 0x04, 0x41, 0xa6, 0x79, - 0x08, 0xea, 0x98, 0x00, - 0x08, 0x57, 0xae, 0x00, - 0x08, 0x3c, 0x78, 0x00, - 0xf0, 0x49, 0x74, 0x0a, - 0x0f, 0x67, 0xc0, 0x09, - 0x00, 0x3a, 0x75, 0x02, - 0x20, 0xea, 0x96, 0x00, - 0x00, 0xe2, 0x28, 0x42, - 0xc0, 0x4a, 0x94, 0x00, - 0x40, 0x3a, 0xd2, 0x69, - 0x02, 0x55, 0x06, 0x68, - 0x02, 0x56, 0xd2, 0x69, - 0xff, 0x5b, 0xd2, 0x61, - 0x02, 0x20, 0x51, 0x31, - 0x80, 0xea, 0xb2, 0x01, - 0x44, 0xea, 0x00, 0x00, - 0x01, 0x33, 0xc0, 0x31, - 0x33, 0xea, 0x00, 0x00, - 0xff, 0xea, 0xb2, 0x09, - 0xff, 0xe0, 0xc0, 0x19, - 0xff, 0xe0, 0xd4, 0x79, - 0x02, 0xac, 0x51, 0x31, - 0x00, 0xe2, 0xca, 0x41, - 0x02, 0x5e, 0x50, 0x31, - 0x02, 0xa8, 0xb8, 0x30, - 0x02, 0x5c, 0x50, 0x31, - 0xff, 0xad, 0xe5, 0x71, - 0x02, 0xac, 0x41, 0x31, - 0x02, 0x22, 0x51, 0x31, - 0x02, 0xa0, 0x5c, 0x33, - 0x02, 0xa0, 0x44, 0x32, - 0x00, 0xe2, 0xf8, 0x41, - 0x01, 0x4d, 0xf1, 0x79, - 0x01, 0x62, 0xc1, 0x31, - 0x00, 0x93, 0xf1, 0x61, - 0xfe, 0x4d, 0x9b, 0x0a, - 0x02, 0x60, 0x41, 0x31, - 0x00, 0xe2, 0xdc, 0x41, - 0x3d, 0x93, 0xc9, 0x29, - 0x01, 0xe4, 0xc8, 0x01, - 0x01, 0xea, 0xca, 0x01, - 0xff, 0xea, 0xda, 0x01, - 0x02, 0x20, 0x51, 0x31, - 0x02, 0xae, 0x41, 0x32, - 0xff, 0x21, 0x01, 0x62, - 0xff, 0xea, 0x46, 0x02, - 0x02, 0x5c, 0x50, 0x31, - 0x40, 0xea, 0x96, 0x00, - 0x02, 0x56, 0x20, 0x6e, - 0x01, 0x55, 0x20, 0x6e, - 0x10, 0x92, 0x0d, 0x7a, - 0x10, 0x40, 0x16, 0x6a, - 0x01, 0x56, 0x16, 0x7a, - 0xff, 0x97, 0x07, 0x78, - 0x13, 0xea, 0x6e, 0x59, - 0x13, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x06, 0x40, - 0xbf, 0x3a, 0x74, 0x08, - 0x04, 0x41, 0x1c, 0x7a, - 0x08, 0xea, 0x98, 0x00, - 0x08, 0x57, 0xae, 0x00, - 0x01, 0x93, 0x75, 0x32, - 0x01, 0x94, 0x77, 0x32, - 0x40, 0xea, 0x72, 0x02, - 0x08, 0x3c, 0x78, 0x00, - 0x80, 0xea, 0x6e, 0x02, - 0x00, 0xe2, 0xf6, 0x5b, - 0x01, 0x3c, 0xc1, 0x31, - 0x9f, 0xe0, 0x98, 0x7c, - 0x80, 0xe0, 0x3c, 0x72, - 0xa0, 0xe0, 0x78, 0x72, - 0xc0, 0xe0, 0x6e, 0x72, - 0xe0, 0xe0, 0xa8, 0x72, - 0x01, 0xea, 0x6e, 0x59, - 0x01, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x28, 0x42, - 0x80, 0x39, 0x43, 0x7a, - 0x03, 0xea, 0x6e, 0x59, - 0x03, 0xea, 0x04, 0x00, - 0xee, 0x00, 0x4a, 0x6a, - 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x68, 0x59, - 0x33, 0xea, 0x00, 0x00, - 0x02, 0xa8, 0x9c, 0x32, - 0x00, 0xe2, 0x88, 0x59, - 0xef, 0x96, 0xd5, 0x19, - 0x00, 0xe2, 0x5a, 0x52, - 0x09, 0x80, 0xe1, 0x30, - 0x02, 0xea, 0x36, 0x00, - 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x60, 0x42, - 0x01, 0x96, 0xd1, 0x30, - 0x10, 0x80, 0x89, 0x31, - 0x20, 0xea, 0x32, 0x00, - 0xbf, 0x39, 0x73, 0x0a, - 0x10, 0x4c, 0x6a, 0x6a, - 0x20, 0x19, 0x62, 0x6a, - 0x20, 0x19, 0x66, 0x6a, - 0x02, 0x4d, 0x28, 0x6a, - 0x40, 0x39, 0x73, 0x02, - 0x00, 0xe2, 0x28, 0x42, - 0x80, 0x39, 0xe9, 0x6a, - 0x01, 0x44, 0x10, 0x33, - 0x08, 0x92, 0x25, 0x03, - 0x00, 0xe2, 0x28, 0x42, - 0x10, 0xea, 0x80, 0x00, - 0x01, 0x37, 0xc5, 0x31, - 0x80, 0xe2, 0x94, 0x62, - 0x10, 0x92, 0xb9, 0x6a, - 0xc0, 0x94, 0xc5, 0x01, - 0x40, 0x92, 0x85, 0x6a, - 0xbf, 0xe2, 0xc4, 0x09, - 0x20, 0x92, 0x99, 0x7a, - 0x01, 0xe2, 0x88, 0x30, - 0x00, 0xe2, 0xf6, 0x5b, - 0xa0, 0x3c, 0xa1, 0x62, - 0x23, 0x92, 0x89, 0x08, - 0x00, 0xe2, 0xf6, 0x5b, - 0xa0, 0x3c, 0xa1, 0x62, - 0x00, 0xa8, 0x98, 0x42, - 0xff, 0xe2, 0x98, 0x62, - 0x00, 0xe2, 0xb8, 0x42, - 0x40, 0xea, 0x98, 0x00, - 0x01, 0xe2, 0x88, 0x30, - 0x00, 0xe2, 0xf6, 0x5b, - 0xa0, 0x3c, 0x77, 0x72, - 0x40, 0xea, 0x98, 0x00, - 0x01, 0x37, 0x95, 0x32, - 0x08, 0xea, 0x6e, 0x02, - 0x00, 0xe2, 0x28, 0x42, - 0xe0, 0xea, 0x12, 0x5c, - 0x80, 0xe0, 0xf4, 0x6a, - 0x04, 0xe0, 0xa6, 0x73, - 0x02, 0xe0, 0xd8, 0x73, - 0x00, 0xea, 0x52, 0x73, - 0x03, 0xe0, 0xe8, 0x73, - 0x23, 0xe0, 0xca, 0x72, - 0x08, 0xe0, 0xf0, 0x72, - 0x00, 0xe2, 0xf6, 0x5b, - 0x07, 0xea, 0x6e, 0x59, - 0x07, 0xea, 0x04, 0x00, - 0x08, 0x48, 0x29, 0x72, - 0x04, 0x48, 0xc7, 0x62, - 0x01, 0x49, 0x89, 0x30, - 0x00, 0xe2, 0xb8, 0x42, - 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xb8, 0x42, - 0x01, 0x00, 0x6c, 0x32, - 0x33, 0xea, 0x68, 0x59, - 0x33, 0xea, 0x00, 0x00, - 0x4c, 0x3a, 0xc1, 0x28, - 0x01, 0x64, 0xc0, 0x31, - 0x00, 0x36, 0x69, 0x59, - 0x01, 0x36, 0x01, 0x30, - 0x01, 0xe0, 0xee, 0x7a, - 0xa0, 0xea, 0x08, 0x5c, - 0x01, 0xa0, 0xee, 0x62, - 0x01, 0x84, 0xe3, 0x7a, - 0x01, 0x95, 0xf1, 0x6a, - 0x05, 0xea, 0x6e, 0x59, - 0x05, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf0, 0x42, - 0x03, 0xea, 0x6e, 0x59, - 0x03, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf0, 0x42, - 0x07, 0xea, 0x1a, 0x5c, - 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0x28, 0x42, - 0x3f, 0xe0, 0x76, 0x0a, - 0xc0, 0x3a, 0xc1, 0x09, - 0x00, 0x3b, 0x51, 0x01, - 0xff, 0xea, 0x52, 0x09, - 0x30, 0x3a, 0xc5, 0x09, - 0x3d, 0xe2, 0xc4, 0x29, - 0xb8, 0xe2, 0xc4, 0x19, - 0x01, 0xea, 0xc6, 0x01, - 0x02, 0xe2, 0xc8, 0x31, - 0x02, 0xec, 0x40, 0x31, - 0xff, 0xa1, 0x10, 0x73, - 0x02, 0xe8, 0xda, 0x31, - 0x02, 0xa0, 0x50, 0x31, - 0x00, 0xe2, 0x32, 0x43, - 0x80, 0x39, 0x73, 0x02, - 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xf6, 0x5b, - 0x01, 0x39, 0x73, 0x02, - 0xe0, 0x3c, 0x4d, 0x63, - 0x02, 0x39, 0x73, 0x02, - 0x20, 0x46, 0x46, 0x63, - 0xff, 0xea, 0x52, 0x09, - 0xa8, 0xea, 0x08, 0x5c, - 0x04, 0x92, 0x2d, 0x7b, - 0x01, 0x3a, 0xc1, 0x31, - 0x00, 0x93, 0x2d, 0x63, - 0x01, 0x3b, 0xc1, 0x31, - 0x00, 0x94, 0x37, 0x73, - 0x01, 0xa9, 0x52, 0x11, - 0xff, 0xa9, 0x22, 0x6b, - 0x00, 0xe2, 0x46, 0x43, - 0x10, 0x39, 0x73, 0x02, - 0x04, 0x92, 0x47, 0x7b, - 0xfb, 0x92, 0x25, 0x0b, - 0xff, 0xea, 0x72, 0x0a, - 0x01, 0xa4, 0x41, 0x6b, - 0x02, 0xa8, 0x9c, 0x32, - 0x00, 0xe2, 0x88, 0x59, - 0x10, 0x92, 0xf1, 0x7a, - 0xff, 0xea, 0x1a, 0x5c, - 0x00, 0xe2, 0xf0, 0x42, - 0x04, 0xea, 0x6e, 0x59, - 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf0, 0x42, - 0x04, 0xea, 0x6e, 0x59, - 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x28, 0x42, - 0x08, 0x92, 0xe9, 0x7a, - 0xc0, 0x39, 0x5d, 0x7b, - 0x80, 0x39, 0xe9, 0x6a, - 0xff, 0x88, 0x5d, 0x6b, - 0x40, 0x39, 0xe9, 0x6a, - 0x10, 0x92, 0x63, 0x7b, - 0x0a, 0xea, 0x6e, 0x59, - 0x0a, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x82, 0x5b, - 0x00, 0xe2, 0xc2, 0x43, - 0x50, 0x4b, 0x6a, 0x6b, - 0xbf, 0x3a, 0x74, 0x08, - 0x01, 0xe0, 0xf4, 0x31, - 0xff, 0xea, 0xc0, 0x09, - 0x01, 0x32, 0x65, 0x1a, - 0x00, 0x33, 0x67, 0x22, - 0x04, 0x4d, 0x9b, 0x02, - 0x01, 0xfa, 0xc0, 0x35, - 0x02, 0xa8, 0x90, 0x32, - 0x02, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x68, 0x59, - 0x33, 0xea, 0x00, 0x00, - 0x02, 0x48, 0x51, 0x31, - 0xff, 0x90, 0x85, 0x68, - 0xff, 0x88, 0x8f, 0x6b, - 0x01, 0xa4, 0x8b, 0x6b, - 0x02, 0xa4, 0x93, 0x6b, - 0x01, 0x84, 0x93, 0x7b, - 0x02, 0x28, 0x19, 0x33, - 0x02, 0xa8, 0x50, 0x36, - 0xff, 0x88, 0x93, 0x73, - 0x00, 0xe2, 0x66, 0x5b, - 0x02, 0xa8, 0x20, 0x33, - 0x04, 0xa4, 0x49, 0x03, - 0xff, 0xea, 0x1a, 0x03, - 0xff, 0x2d, 0x9f, 0x63, - 0x02, 0xa8, 0x58, 0x32, - 0x02, 0xa8, 0x5c, 0x36, - 0x02, 0xa8, 0x40, 0x31, - 0x02, 0x2e, 0x51, 0x31, - 0x02, 0xa0, 0x18, 0x33, - 0x02, 0xa0, 0x5c, 0x36, - 0xc0, 0x39, 0xe9, 0x6a, - 0x04, 0x92, 0x25, 0x03, - 0x20, 0x92, 0xc3, 0x6b, - 0x02, 0xa8, 0x40, 0x31, - 0xc0, 0x3a, 0xc1, 0x09, - 0x00, 0x3b, 0x51, 0x01, - 0xff, 0xea, 0x52, 0x09, - 0x30, 0x3a, 0xc5, 0x09, - 0x3d, 0xe2, 0xc4, 0x29, - 0xb8, 0xe2, 0xc4, 0x19, - 0x01, 0xea, 0xc6, 0x01, - 0x02, 0xe2, 0xc8, 0x31, - 0x02, 0xa0, 0xda, 0x31, - 0x02, 0xa0, 0x50, 0x31, - 0xf7, 0x57, 0xae, 0x08, - 0x08, 0xea, 0x98, 0x00, - 0x01, 0x44, 0xd4, 0x31, - 0xee, 0x00, 0xcc, 0x6b, - 0x02, 0xea, 0xb4, 0x00, - 0xc0, 0xea, 0x72, 0x02, - 0x09, 0x4c, 0xce, 0x7b, - 0x01, 0xea, 0x78, 0x02, - 0x08, 0x4c, 0x06, 0x68, - 0x0b, 0xea, 0x6e, 0x59, - 0x0b, 0xea, 0x04, 0x00, - 0x01, 0x44, 0xd4, 0x31, - 0x20, 0x39, 0x29, 0x7a, - 0x00, 0xe2, 0xe0, 0x5b, - 0x00, 0xe2, 0x28, 0x42, - 0x01, 0x84, 0xe5, 0x7b, - 0x01, 0xa4, 0x49, 0x07, - 0x08, 0x60, 0x30, 0x33, - 0x08, 0x80, 0x41, 0x37, - 0xdf, 0x39, 0x73, 0x0a, - 0xee, 0x00, 0xf2, 0x6b, - 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x68, 0x59, - 0x33, 0xea, 0x00, 0x00, - 0x00, 0xe2, 0x88, 0x59, - 0x00, 0xe2, 0xf0, 0x42, - 0xff, 0x42, 0x02, 0x6c, - 0x01, 0x41, 0xf6, 0x6b, - 0x02, 0x41, 0xf6, 0x7b, - 0xff, 0x42, 0x02, 0x6c, - 0x01, 0x41, 0xf6, 0x6b, - 0x02, 0x41, 0xf6, 0x7b, - 0xff, 0x42, 0x02, 0x7c, - 0x04, 0x4c, 0xf6, 0x6b, - 0xe0, 0x41, 0x78, 0x0e, - 0x01, 0x44, 0xd4, 0x31, - 0xff, 0x42, 0x0a, 0x7c, - 0x04, 0x4c, 0x0a, 0x6c, - 0xe0, 0x41, 0x78, 0x0a, - 0xe0, 0x3c, 0x29, 0x62, - 0xff, 0xea, 0xca, 0x09, - 0x01, 0xe2, 0xc8, 0x31, - 0x01, 0x46, 0xda, 0x35, - 0x01, 0x44, 0xd4, 0x35, - 0x10, 0xea, 0x80, 0x00, - 0x01, 0xe2, 0x6e, 0x36, - 0x04, 0xa6, 0x22, 0x7c, - 0xff, 0xea, 0x5a, 0x09, - 0xff, 0xea, 0x4c, 0x0d, - 0x01, 0xa6, 0x4e, 0x6c, - 0x10, 0xad, 0x84, 0x78, - 0x80, 0xad, 0x46, 0x6c, - 0x08, 0xad, 0x84, 0x68, - 0x20, 0x19, 0x3a, 0x7c, - 0x80, 0xea, 0xb2, 0x01, - 0x11, 0x00, 0x00, 0x10, - 0x02, 0xa6, 0x36, 0x7c, - 0xff, 0xea, 0xb2, 0x0d, - 0x11, 0x00, 0x00, 0x10, - 0xff, 0xea, 0xb2, 0x09, - 0x04, 0x84, 0xf9, 0x30, - 0x00, 0xea, 0x08, 0x81, - 0xff, 0xea, 0xd4, 0x09, - 0x02, 0x84, 0xf9, 0x88, - 0x0d, 0xea, 0x5a, 0x01, - 0x04, 0xa6, 0x4c, 0x05, - 0x04, 0xa6, 0x84, 0x78, - 0xff, 0xea, 0x5a, 0x09, - 0x03, 0x84, 0x59, 0x89, - 0x03, 0xea, 0x4c, 0x01, - 0x80, 0x1a, 0x84, 0x78, - 0x08, 0x19, 0x84, 0x78, - 0x08, 0xb0, 0xe0, 0x30, - 0x04, 0xb0, 0xe0, 0x30, - 0x03, 0xb0, 0xf0, 0x30, - 0x01, 0xb0, 0x06, 0x33, - 0x7f, 0x83, 0xe9, 0x08, - 0x04, 0xac, 0x58, 0x19, - 0xff, 0xea, 0xc0, 0x09, - 0x04, 0x84, 0x09, 0x9b, - 0x00, 0x85, 0x0b, 0x23, - 0x00, 0x86, 0x0d, 0x23, - 0x00, 0x87, 0x0f, 0x23, - 0x01, 0x84, 0xc5, 0x31, - 0x80, 0x83, 0x71, 0x7c, - 0x02, 0xe2, 0xc4, 0x01, - 0xff, 0xea, 0x4c, 0x09, - 0x01, 0xe2, 0x36, 0x30, - 0xc8, 0x19, 0x32, 0x00, - 0x88, 0x19, 0x32, 0x00, - 0x01, 0xac, 0xd4, 0x99, - 0x00, 0xe2, 0x84, 0x50, - 0xfe, 0xa6, 0x4c, 0x0d, - 0x0b, 0x98, 0xe1, 0x30, - 0xfd, 0xa4, 0x49, 0x09, - 0x80, 0xa3, 0x85, 0x7c, - 0x02, 0xa4, 0x48, 0x01, - 0x01, 0xa4, 0x36, 0x30, - 0xa8, 0xea, 0x32, 0x00, - 0xfd, 0xa4, 0x49, 0x0b, - 0x05, 0xa3, 0x07, 0x33, - 0x80, 0x83, 0x91, 0x6c, - 0x02, 0xea, 0x4c, 0x05, - 0xff, 0xea, 0x4c, 0x0d, - 0x00, 0xe2, 0x60, 0x59, - 0x02, 0xa6, 0x24, 0x6c, - 0x80, 0xf9, 0xf2, 0x05, - 0xc0, 0x39, 0x9f, 0x7c, - 0x03, 0xea, 0x6e, 0x59, - 0x03, 0xea, 0x04, 0x00, - 0x20, 0x39, 0xc3, 0x7c, - 0x01, 0x84, 0xa9, 0x6c, - 0x06, 0xea, 0x6e, 0x59, - 0x06, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xc6, 0x44, - 0x01, 0x00, 0x6c, 0x32, - 0xee, 0x00, 0xb2, 0x6c, - 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x68, 0x59, - 0x33, 0xea, 0x00, 0x00, - 0x80, 0x3d, 0x7a, 0x00, - 0xfc, 0x42, 0xb4, 0x7c, - 0x7f, 0x3d, 0x7a, 0x08, - 0x00, 0x36, 0x69, 0x59, - 0x01, 0x36, 0x01, 0x30, - 0x09, 0xea, 0x6e, 0x59, - 0x09, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x28, 0x42, - 0x01, 0xa4, 0xa9, 0x6c, - 0x00, 0xe2, 0x7c, 0x5c, - 0x20, 0x39, 0x73, 0x02, - 0x01, 0x00, 0x6c, 0x32, - 0x02, 0xa6, 0xce, 0x7c, - 0x00, 0xe2, 0x92, 0x5c, - 0x00, 0xe2, 0x76, 0x58, - 0x00, 0xe2, 0x86, 0x58, - 0x00, 0xe2, 0x5a, 0x58, - 0x00, 0x36, 0x69, 0x59, - 0x01, 0x36, 0x01, 0x30, - 0x20, 0x19, 0xce, 0x6c, - 0x00, 0xe2, 0xfe, 0x5c, - 0x04, 0x19, 0xe8, 0x6c, - 0x02, 0x19, 0x32, 0x00, - 0x01, 0x84, 0xe9, 0x7c, - 0x01, 0x1b, 0xe2, 0x7c, - 0x01, 0x1a, 0xe8, 0x6c, - 0x00, 0xe2, 0x98, 0x44, - 0x80, 0x4b, 0xee, 0x6c, - 0x01, 0x4c, 0xea, 0x7c, - 0x03, 0x42, 0x98, 0x6c, - 0x00, 0xe2, 0x1e, 0x5c, - 0x80, 0xf9, 0xf2, 0x01, - 0x04, 0x39, 0x29, 0x7a, - 0x00, 0xe2, 0x28, 0x42, - 0x08, 0x5d, 0x06, 0x6d, - 0x00, 0xe2, 0x76, 0x58, - 0x00, 0x36, 0x69, 0x59, - 0x01, 0x36, 0x01, 0x30, - 0x02, 0x1b, 0xf6, 0x7c, - 0x08, 0x5d, 0x04, 0x7d, - 0x03, 0x68, 0x00, 0x37, - 0x01, 0x84, 0x09, 0x07, - 0x80, 0x1b, 0x10, 0x7d, - 0x80, 0x84, 0x11, 0x6d, - 0xff, 0x85, 0x0b, 0x1b, - 0xff, 0x86, 0x0d, 0x23, - 0xff, 0x87, 0x0f, 0x23, - 0xf8, 0x1b, 0x08, 0x0b, - 0xff, 0xea, 0x06, 0x0b, - 0x03, 0x68, 0x00, 0x37, - 0x00, 0xe2, 0xd6, 0x58, - 0x10, 0xea, 0x18, 0x00, - 0xf9, 0xd9, 0xb2, 0x0d, - 0x01, 0xd9, 0xb2, 0x05, - 0x01, 0x52, 0x48, 0x31, - 0x20, 0xa4, 0x3a, 0x7d, - 0x20, 0x5b, 0x3a, 0x7d, - 0x80, 0xf9, 0x48, 0x7d, - 0x02, 0xea, 0xb4, 0x00, - 0x11, 0x00, 0x00, 0x10, - 0x04, 0x19, 0x54, 0x7d, - 0xdf, 0x19, 0x32, 0x08, - 0x60, 0x5b, 0x54, 0x6d, - 0x01, 0x4c, 0x2e, 0x7d, - 0x20, 0x19, 0x32, 0x00, - 0x01, 0xd9, 0xb2, 0x05, - 0x02, 0xea, 0xb4, 0x00, - 0x01, 0xd9, 0xb2, 0x05, - 0x10, 0x5b, 0x4c, 0x6d, - 0x08, 0x5b, 0x56, 0x6d, - 0x20, 0x5b, 0x46, 0x6d, - 0x02, 0x5b, 0x76, 0x6d, - 0x0e, 0xea, 0x6e, 0x59, - 0x0e, 0xea, 0x04, 0x00, - 0x80, 0xf9, 0x36, 0x6d, - 0xdf, 0x5c, 0xb8, 0x08, - 0x01, 0xd9, 0xb2, 0x05, - 0x01, 0xa4, 0x37, 0x6e, - 0x00, 0xe2, 0x7c, 0x5c, - 0x00, 0xe2, 0x80, 0x5d, - 0x01, 0x90, 0x21, 0x1b, - 0x01, 0xd9, 0xb2, 0x05, - 0x00, 0xe2, 0x66, 0x5b, - 0xf3, 0x96, 0xd5, 0x19, - 0x00, 0xe2, 0x64, 0x55, - 0x80, 0x96, 0x65, 0x6d, - 0x0f, 0xea, 0x6e, 0x59, - 0x0f, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x6c, 0x45, - 0x04, 0x8c, 0xe1, 0x30, - 0x01, 0xea, 0xf2, 0x00, - 0x02, 0xea, 0x36, 0x00, - 0xa8, 0xea, 0x32, 0x00, - 0xff, 0x97, 0x73, 0x7d, - 0x14, 0xea, 0x6e, 0x59, - 0x14, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xe2, 0x5d, - 0x01, 0xd9, 0xb2, 0x05, - 0x09, 0x80, 0xe1, 0x30, - 0x02, 0xea, 0x36, 0x00, - 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0xda, 0x5d, - 0x01, 0xd9, 0xb2, 0x05, - 0x02, 0xa6, 0x90, 0x7d, - 0x00, 0xe2, 0x60, 0x59, - 0x20, 0x5b, 0x9e, 0x6d, - 0xfc, 0x42, 0x8a, 0x7d, - 0x10, 0x40, 0x8c, 0x6d, - 0x20, 0x4d, 0x8e, 0x7d, - 0x08, 0x5d, 0x9e, 0x6d, - 0x02, 0xa6, 0x24, 0x6c, - 0x00, 0xe2, 0x60, 0x59, - 0x20, 0x5b, 0x9e, 0x6d, - 0x01, 0x1b, 0xbe, 0x6d, - 0xfc, 0x42, 0x9a, 0x7d, - 0x10, 0x40, 0x9c, 0x6d, - 0x20, 0x4d, 0x84, 0x78, - 0x08, 0x5d, 0x84, 0x78, - 0x02, 0x19, 0x32, 0x00, - 0x01, 0x5b, 0x40, 0x31, - 0x00, 0xe2, 0xfe, 0x5c, - 0x00, 0xe2, 0xe0, 0x5b, - 0x20, 0xea, 0xb6, 0x00, - 0x00, 0xe2, 0x1e, 0x5c, - 0x20, 0x5c, 0xb8, 0x00, - 0x04, 0x19, 0xb4, 0x6d, - 0x01, 0x1a, 0xb4, 0x6d, - 0x00, 0xe2, 0x60, 0x59, - 0x01, 0x1a, 0x84, 0x78, - 0x80, 0xf9, 0xf2, 0x01, - 0x20, 0xa0, 0x18, 0x7e, - 0xff, 0x90, 0x21, 0x1b, - 0x08, 0x92, 0x77, 0x6b, - 0x02, 0xea, 0xb4, 0x04, - 0x01, 0xa4, 0x49, 0x03, - 0x40, 0x5b, 0xce, 0x6d, - 0x00, 0xe2, 0x60, 0x59, - 0x40, 0x5b, 0xce, 0x6d, - 0x04, 0x5d, 0x38, 0x7e, - 0x01, 0x1a, 0x38, 0x7e, - 0x20, 0x4d, 0x84, 0x78, - 0x40, 0x5b, 0x18, 0x7e, - 0x04, 0x5d, 0x38, 0x7e, - 0x01, 0x1a, 0x38, 0x7e, - 0x80, 0xf9, 0xf2, 0x01, - 0xff, 0x90, 0x21, 0x1b, - 0x08, 0x92, 0x77, 0x6b, - 0x02, 0xea, 0xb4, 0x04, - 0x00, 0xe2, 0x60, 0x59, - 0x01, 0x1b, 0x84, 0x78, - 0x80, 0xf9, 0xf2, 0x01, - 0x02, 0xea, 0xb4, 0x04, - 0x00, 0xe2, 0x60, 0x59, - 0x01, 0x1b, 0xf6, 0x6d, - 0x40, 0x5b, 0x04, 0x7e, - 0x01, 0x1b, 0xf6, 0x6d, - 0x02, 0x19, 0x32, 0x00, - 0x01, 0x1a, 0x84, 0x78, - 0x80, 0xf9, 0xf2, 0x01, - 0xff, 0xea, 0x10, 0x03, - 0x08, 0x92, 0x25, 0x03, - 0x00, 0xe2, 0x76, 0x43, - 0x01, 0x1a, 0x00, 0x7e, - 0x40, 0x5b, 0xfc, 0x7d, - 0x01, 0x1a, 0xea, 0x6d, - 0xfc, 0x42, 0x84, 0x78, - 0x01, 0x1a, 0x04, 0x6e, - 0x10, 0xea, 0x6e, 0x59, - 0x10, 0xea, 0x04, 0x00, - 0xfc, 0x42, 0x84, 0x78, - 0x10, 0x40, 0x0a, 0x6e, - 0x20, 0x4d, 0x84, 0x78, - 0x40, 0x5b, 0xea, 0x6d, - 0x01, 0x1a, 0x84, 0x78, - 0x01, 0x90, 0x21, 0x1b, - 0x30, 0x3f, 0xc0, 0x09, - 0x30, 0xe0, 0x84, 0x60, - 0x40, 0x4b, 0x84, 0x68, - 0xff, 0xea, 0x52, 0x01, - 0xee, 0x00, 0x20, 0x6e, - 0x80, 0xf9, 0xf2, 0x01, - 0xff, 0x90, 0x21, 0x1b, - 0x02, 0xea, 0xb4, 0x00, - 0x20, 0xea, 0x9a, 0x00, - 0x04, 0x41, 0x26, 0x7e, - 0x08, 0xea, 0x98, 0x00, - 0x08, 0x57, 0xae, 0x00, - 0xf3, 0x42, 0x30, 0x6e, - 0x12, 0xea, 0x6e, 0x59, - 0x12, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x28, 0x42, - 0x0d, 0xea, 0x6e, 0x59, - 0x0d, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x28, 0x42, - 0x01, 0x90, 0x21, 0x1b, - 0x11, 0xea, 0x6e, 0x59, - 0x11, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x66, 0x5b, - 0x08, 0x5a, 0xb4, 0x00, - 0x00, 0xe2, 0x5e, 0x5e, - 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x60, 0x59, - 0x80, 0x1a, 0x4c, 0x7e, - 0x00, 0xe2, 0x5e, 0x5e, - 0x80, 0x19, 0x32, 0x00, - 0x40, 0x5b, 0x52, 0x6e, - 0x08, 0x5a, 0x52, 0x7e, - 0x20, 0x4d, 0x84, 0x78, - 0x02, 0x84, 0x09, 0x03, - 0x40, 0x5b, 0x18, 0x7e, - 0xff, 0x90, 0x21, 0x1b, - 0x80, 0xf9, 0xf2, 0x01, - 0x08, 0x92, 0x77, 0x6b, - 0x02, 0xea, 0xb4, 0x04, - 0x01, 0x40, 0xe1, 0x30, - 0x05, 0x41, 0xe3, 0x98, - 0x01, 0xe0, 0xf4, 0x31, - 0xff, 0xea, 0xc0, 0x09, - 0x00, 0x42, 0xe5, 0x20, - 0x00, 0x43, 0xe7, 0x20, - 0x01, 0xfa, 0xc0, 0x31, - 0x04, 0xea, 0xe8, 0x30, - 0xff, 0xea, 0xf0, 0x08, - 0x02, 0xea, 0xf2, 0x00, - 0xff, 0xea, 0xf4, 0x0c -}; - -typedef int ahd_patch_func_t (struct ahd_softc *ahd); -static ahd_patch_func_t ahd_patch23_func; - -static int -ahd_patch23_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch22_func; - -static int -ahd_patch22_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); -} - -static ahd_patch_func_t ahd_patch21_func; - -static int -ahd_patch21_func(struct ahd_softc *ahd) -{ - return ((ahd->flags & AHD_INITIATORROLE) != 0); -} - -static ahd_patch_func_t ahd_patch20_func; - -static int -ahd_patch20_func(struct ahd_softc *ahd) -{ - return ((ahd->flags & AHD_TARGETROLE) != 0); -} - -static ahd_patch_func_t ahd_patch19_func; - -static int -ahd_patch19_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch18_func; - -static int -ahd_patch18_func(struct ahd_softc *ahd) -{ - return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); -} - -static ahd_patch_func_t ahd_patch17_func; - -static int -ahd_patch17_func(struct ahd_softc *ahd) -{ - return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); -} - -static ahd_patch_func_t ahd_patch16_func; - -static int -ahd_patch16_func(struct ahd_softc *ahd) -{ - return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); -} - -static ahd_patch_func_t ahd_patch15_func; - -static int -ahd_patch15_func(struct ahd_softc *ahd) -{ - return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); -} - -static ahd_patch_func_t ahd_patch14_func; - -static int -ahd_patch14_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch13_func; - -static int -ahd_patch13_func(struct ahd_softc *ahd) -{ - return ((ahd->features & AHD_RTI) == 0); -} - -static ahd_patch_func_t ahd_patch12_func; - -static int -ahd_patch12_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch11_func; - -static int -ahd_patch11_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0); -} - -static ahd_patch_func_t ahd_patch10_func; - -static int -ahd_patch10_func(struct ahd_softc *ahd) -{ - return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); -} - -static ahd_patch_func_t ahd_patch9_func; - -static int -ahd_patch9_func(struct ahd_softc *ahd) -{ - return ((ahd->features & AHD_FAST_CDB_DELIVERY) != 0); -} - -static ahd_patch_func_t ahd_patch8_func; - -static int -ahd_patch8_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch7_func; - -static int -ahd_patch7_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch6_func; - -static int -ahd_patch6_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch5_func; - -static int -ahd_patch5_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch4_func; - -static int -ahd_patch4_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_PKT_LUN_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch3_func; - -static int -ahd_patch3_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_FAINT_LED_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch2_func; - -static int -ahd_patch2_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_SET_MODE_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch1_func; - -static int -ahd_patch1_func(struct ahd_softc *ahd) -{ - return ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0); -} - -static ahd_patch_func_t ahd_patch0_func; - -static int -ahd_patch0_func(struct ahd_softc *ahd) -{ - return (0); -} - -static const struct patch { - ahd_patch_func_t *patch_func; - uint32_t begin :10, - skip_instr :10, - skip_patch :12; -} patches[] = { - { ahd_patch1_func, 0, 3, 3 }, - { ahd_patch1_func, 1, 1, 2 }, - { ahd_patch0_func, 2, 1, 1 }, - { ahd_patch1_func, 3, 3, 3 }, - { ahd_patch1_func, 4, 1, 2 }, - { ahd_patch0_func, 5, 1, 1 }, - { ahd_patch2_func, 6, 1, 2 }, - { ahd_patch0_func, 7, 1, 1 }, - { ahd_patch3_func, 36, 5, 1 }, - { ahd_patch2_func, 45, 1, 2 }, - { ahd_patch0_func, 46, 1, 1 }, - { ahd_patch1_func, 53, 1, 2 }, - { ahd_patch0_func, 54, 1, 1 }, - { ahd_patch2_func, 59, 1, 2 }, - { ahd_patch0_func, 60, 1, 1 }, - { ahd_patch2_func, 63, 1, 2 }, - { ahd_patch0_func, 64, 1, 1 }, - { ahd_patch2_func, 67, 1, 2 }, - { ahd_patch0_func, 68, 1, 1 }, - { ahd_patch4_func, 115, 1, 1 }, - { ahd_patch2_func, 180, 3, 1 }, - { ahd_patch1_func, 183, 2, 1 }, - { ahd_patch5_func, 185, 1, 1 }, - { ahd_patch2_func, 194, 1, 2 }, - { ahd_patch0_func, 195, 1, 1 }, - { ahd_patch6_func, 196, 2, 2 }, - { ahd_patch0_func, 198, 6, 3 }, - { ahd_patch2_func, 201, 1, 2 }, - { ahd_patch0_func, 202, 1, 1 }, - { ahd_patch2_func, 205, 1, 2 }, - { ahd_patch0_func, 206, 1, 1 }, - { ahd_patch3_func, 208, 1, 1 }, - { ahd_patch7_func, 209, 3, 1 }, - { ahd_patch3_func, 218, 1, 1 }, - { ahd_patch5_func, 219, 16, 2 }, - { ahd_patch0_func, 235, 1, 1 }, - { ahd_patch8_func, 260, 2, 1 }, - { ahd_patch1_func, 264, 1, 2 }, - { ahd_patch0_func, 265, 1, 1 }, - { ahd_patch7_func, 268, 3, 1 }, - { ahd_patch1_func, 283, 1, 2 }, - { ahd_patch0_func, 284, 1, 1 }, - { ahd_patch1_func, 287, 1, 2 }, - { ahd_patch0_func, 288, 1, 1 }, - { ahd_patch2_func, 291, 1, 2 }, - { ahd_patch0_func, 292, 1, 1 }, - { ahd_patch9_func, 305, 2, 2 }, - { ahd_patch0_func, 307, 1, 1 }, - { ahd_patch1_func, 349, 1, 2 }, - { ahd_patch0_func, 350, 1, 1 }, - { ahd_patch2_func, 358, 1, 2 }, - { ahd_patch0_func, 359, 1, 1 }, - { ahd_patch2_func, 362, 1, 2 }, - { ahd_patch0_func, 363, 1, 1 }, - { ahd_patch1_func, 369, 1, 2 }, - { ahd_patch0_func, 370, 1, 1 }, - { ahd_patch1_func, 372, 1, 2 }, - { ahd_patch0_func, 373, 1, 1 }, - { ahd_patch10_func, 392, 1, 1 }, - { ahd_patch10_func, 395, 1, 1 }, - { ahd_patch10_func, 397, 1, 1 }, - { ahd_patch10_func, 409, 1, 1 }, - { ahd_patch1_func, 419, 1, 2 }, - { ahd_patch0_func, 420, 1, 1 }, - { ahd_patch1_func, 422, 1, 2 }, - { ahd_patch0_func, 423, 1, 1 }, - { ahd_patch1_func, 431, 1, 2 }, - { ahd_patch0_func, 432, 1, 1 }, - { ahd_patch2_func, 445, 1, 2 }, - { ahd_patch0_func, 446, 1, 1 }, - { ahd_patch11_func, 482, 1, 1 }, - { ahd_patch1_func, 490, 1, 2 }, - { ahd_patch0_func, 491, 1, 1 }, - { ahd_patch2_func, 503, 1, 2 }, - { ahd_patch0_func, 504, 1, 1 }, - { ahd_patch12_func, 507, 6, 2 }, - { ahd_patch0_func, 513, 1, 1 }, - { ahd_patch13_func, 534, 7, 1 }, - { ahd_patch14_func, 543, 1, 1 }, - { ahd_patch15_func, 552, 1, 1 }, - { ahd_patch16_func, 553, 1, 2 }, - { ahd_patch0_func, 554, 1, 1 }, - { ahd_patch17_func, 557, 1, 1 }, - { ahd_patch16_func, 558, 1, 1 }, - { ahd_patch18_func, 569, 1, 2 }, - { ahd_patch0_func, 570, 1, 1 }, - { ahd_patch1_func, 589, 1, 2 }, - { ahd_patch0_func, 590, 1, 1 }, - { ahd_patch1_func, 593, 1, 2 }, - { ahd_patch0_func, 594, 1, 1 }, - { ahd_patch2_func, 599, 1, 2 }, - { ahd_patch0_func, 600, 1, 1 }, - { ahd_patch2_func, 604, 1, 2 }, - { ahd_patch0_func, 605, 1, 1 }, - { ahd_patch1_func, 606, 1, 2 }, - { ahd_patch0_func, 607, 1, 1 }, - { ahd_patch2_func, 618, 1, 2 }, - { ahd_patch0_func, 619, 1, 1 }, - { ahd_patch19_func, 623, 1, 1 }, - { ahd_patch20_func, 628, 1, 1 }, - { ahd_patch21_func, 629, 2, 1 }, - { ahd_patch20_func, 633, 1, 2 }, - { ahd_patch0_func, 634, 1, 1 }, - { ahd_patch2_func, 637, 1, 2 }, - { ahd_patch0_func, 638, 1, 1 }, - { ahd_patch2_func, 653, 1, 2 }, - { ahd_patch0_func, 654, 1, 1 }, - { ahd_patch13_func, 655, 14, 1 }, - { ahd_patch1_func, 673, 1, 2 }, - { ahd_patch0_func, 674, 1, 1 }, - { ahd_patch13_func, 675, 1, 1 }, - { ahd_patch1_func, 687, 1, 2 }, - { ahd_patch0_func, 688, 1, 1 }, - { ahd_patch1_func, 695, 1, 2 }, - { ahd_patch0_func, 696, 1, 1 }, - { ahd_patch19_func, 719, 1, 1 }, - { ahd_patch19_func, 757, 1, 1 }, - { ahd_patch1_func, 768, 1, 2 }, - { ahd_patch0_func, 769, 1, 1 }, - { ahd_patch7_func, 785, 3, 1 }, - { ahd_patch1_func, 789, 1, 2 }, - { ahd_patch0_func, 790, 1, 1 }, - { ahd_patch1_func, 792, 1, 2 }, - { ahd_patch0_func, 793, 1, 1 }, - { ahd_patch1_func, 796, 1, 2 }, - { ahd_patch0_func, 797, 1, 1 }, - { ahd_patch22_func, 799, 1, 2 }, - { ahd_patch0_func, 800, 2, 1 }, - { ahd_patch23_func, 803, 4, 2 }, - { ahd_patch0_func, 807, 1, 1 }, - { ahd_patch23_func, 815, 11, 1 } -}; - -static const struct cs { - uint16_t begin; - uint16_t end; -} critical_sections[] = { - { 17, 30 }, - { 47, 58 }, - { 61, 63 }, - { 65, 66 }, - { 72, 92 }, - { 110, 142 }, - { 143, 180 }, - { 185, 193 }, - { 218, 274 }, - { 435, 443 }, - { 453, 455 }, - { 458, 467 }, - { 719, 749 }, - { 759, 763 } -}; - -static const int num_critical_sections = sizeof(critical_sections) - / sizeof(*critical_sections); diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.h deleted file mode 100644 index f6957746..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.h +++ /dev/null @@ -1,1284 +0,0 @@ -/* - * Core definitions and data structures shareable across OS platforms. - * - * Copyright (c) 1994-2001 Justin T. Gibbs. - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#85 $ - * - * $FreeBSD$ - */ - -#ifndef _AIC7XXX_H_ -#define _AIC7XXX_H_ - -/* Register Definitions */ -#include "aic7xxx_reg.h" - -/************************* Forward Declarations *******************************/ -struct ahc_platform_data; -struct scb_platform_data; -struct seeprom_descriptor; - -/****************************** Useful Macros *********************************/ -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define ALL_CHANNELS '\0' -#define ALL_TARGETS_MASK 0xFFFF -#define INITIATOR_WILDCARD (~0) - -#define SCSIID_TARGET(ahc, scsiid) \ - (((scsiid) & ((((ahc)->features & AHC_TWIN) != 0) ? TWIN_TID : TID)) \ - >> TID_SHIFT) -#define SCSIID_OUR_ID(scsiid) \ - ((scsiid) & OID) -#define SCSIID_CHANNEL(ahc, scsiid) \ - ((((ahc)->features & AHC_TWIN) != 0) \ - ? ((((scsiid) & TWIN_CHNLB) != 0) ? 'B' : 'A') \ - : 'A') -#define SCB_IS_SCSIBUS_B(ahc, scb) \ - (SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) == 'B') -#define SCB_GET_OUR_ID(scb) \ - SCSIID_OUR_ID((scb)->hscb->scsiid) -#define SCB_GET_TARGET(ahc, scb) \ - SCSIID_TARGET((ahc), (scb)->hscb->scsiid) -#define SCB_GET_CHANNEL(ahc, scb) \ - SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) -#define SCB_GET_LUN(scb) \ - ((scb)->hscb->lun & LID) -#define SCB_GET_TARGET_OFFSET(ahc, scb) \ - (SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0)) -#define SCB_GET_TARGET_MASK(ahc, scb) \ - (0x01 << (SCB_GET_TARGET_OFFSET(ahc, scb))) -#ifdef AHC_DEBUG -#define SCB_IS_SILENT(scb) \ - ((ahc_debug & AHC_SHOW_MASKED_ERRORS) == 0 \ - && (((scb)->flags & SCB_SILENT) != 0)) -#else -#define SCB_IS_SILENT(scb) \ - (((scb)->flags & SCB_SILENT) != 0) -#endif -#define TCL_TARGET_OFFSET(tcl) \ - ((((tcl) >> 4) & TID) >> 4) -#define TCL_LUN(tcl) \ - (tcl & (AHC_NUM_LUNS - 1)) -#define BUILD_TCL(scsiid, lun) \ - ((lun) | (((scsiid) & TID) << 4)) - -#ifndef AHC_TARGET_MODE -#undef AHC_TMODE_ENABLE -#define AHC_TMODE_ENABLE 0 -#endif - -/**************************** Driver Constants ********************************/ -/* - * The maximum number of supported targets. - */ -#define AHC_NUM_TARGETS 16 - -/* - * The maximum number of supported luns. - * The identify message only supports 64 luns in SPI3. - * You can have 2^64 luns when information unit transfers are enabled, - * but it is doubtful this driver will ever support IUTs. - */ -#define AHC_NUM_LUNS 64 - -/* - * The maximum transfer per S/G segment. - */ -#define AHC_MAXTRANSFER_SIZE 0x00ffffff /* limited by 24bit counter */ - -/* - * The maximum amount of SCB storage in hardware on a controller. - * This value represents an upper bound. Controllers vary in the number - * they actually support. - */ -#define AHC_SCB_MAX 255 - -/* - * The maximum number of concurrent transactions supported per driver instance. - * Sequencer Control Blocks (SCBs) store per-transaction information. Although - * the space for SCBs on the host adapter varies by model, the driver will - * page the SCBs between host and controller memory as needed. We are limited - * to 253 because: - * 1) The 8bit nature of the RISC engine holds us to an 8bit value. - * 2) We reserve one value, 255, to represent the invalid element. - * 3) Our input queue scheme requires one SCB to always be reserved - * in advance of queuing any SCBs. This takes us down to 254. - * 4) To handle our output queue correctly on machines that only - * support 32bit stores, we must clear the array 4 bytes at a - * time. To avoid colliding with a DMA write from the sequencer, - * we must be sure that 4 slots are empty when we write to clear - * the queue. This reduces us to 253 SCBs: 1 that just completed - * and the known three additional empty slots in the queue that - * precede it. - */ -#define AHC_MAX_QUEUE 253 - -/* - * The maximum amount of SCB storage we allocate in host memory. This - * number should reflect the 1 additional SCB we require to handle our - * qinfifo mechanism. - */ -#define AHC_SCB_MAX_ALLOC (AHC_MAX_QUEUE+1) - -/* - * Ring Buffer of incoming target commands. - * We allocate 256 to simplify the logic in the sequencer - * by using the natural wrap point of an 8bit counter. - */ -#define AHC_TMODE_CMDS 256 - -/* Reset line assertion time in us */ -#define AHC_BUSRESET_DELAY 25 - -/******************* Chip Characteristics/Operating Settings *****************/ -/* - * Chip Type - * The chip order is from least sophisticated to most sophisticated. - */ -typedef enum { - AHC_NONE = 0x0000, - AHC_CHIPID_MASK = 0x00FF, - AHC_AIC7770 = 0x0001, - AHC_AIC7850 = 0x0002, - AHC_AIC7855 = 0x0003, - AHC_AIC7859 = 0x0004, - AHC_AIC7860 = 0x0005, - AHC_AIC7870 = 0x0006, - AHC_AIC7880 = 0x0007, - AHC_AIC7895 = 0x0008, - AHC_AIC7895C = 0x0009, - AHC_AIC7890 = 0x000a, - AHC_AIC7896 = 0x000b, - AHC_AIC7892 = 0x000c, - AHC_AIC7899 = 0x000d, - AHC_VL = 0x0100, /* Bus type VL */ - AHC_EISA = 0x0200, /* Bus type EISA */ - AHC_PCI = 0x0400, /* Bus type PCI */ - AHC_BUS_MASK = 0x0F00 -} ahc_chip; - -/* - * Features available in each chip type. - */ -typedef enum { - AHC_FENONE = 0x00000, - AHC_ULTRA = 0x00001, /* Supports 20MHz Transfers */ - AHC_ULTRA2 = 0x00002, /* Supports 40MHz Transfers */ - AHC_WIDE = 0x00004, /* Wide Channel */ - AHC_TWIN = 0x00008, /* Twin Channel */ - AHC_MORE_SRAM = 0x00010, /* 80 bytes instead of 64 */ - AHC_CMD_CHAN = 0x00020, /* Has a Command DMA Channel */ - AHC_QUEUE_REGS = 0x00040, /* Has Queue management registers */ - AHC_SG_PRELOAD = 0x00080, /* Can perform auto-SG preload */ - AHC_SPIOCAP = 0x00100, /* Has a Serial Port I/O Cap Register */ - AHC_MULTI_TID = 0x00200, /* Has bitmask of TIDs for select-in */ - AHC_HS_MAILBOX = 0x00400, /* Has HS_MAILBOX register */ - AHC_DT = 0x00800, /* Double Transition transfers */ - AHC_NEW_TERMCTL = 0x01000, /* Newer termination scheme */ - AHC_MULTI_FUNC = 0x02000, /* Multi-Function Twin Channel Device */ - AHC_LARGE_SCBS = 0x04000, /* 64byte SCBs */ - AHC_AUTORATE = 0x08000, /* Automatic update of SCSIRATE/OFFSET*/ - AHC_AUTOPAUSE = 0x10000, /* Automatic pause on register access */ - AHC_TARGETMODE = 0x20000, /* Has tested target mode support */ - AHC_MULTIROLE = 0x40000, /* Space for two roles at a time */ - AHC_REMOVABLE = 0x80000, /* Hot-Swap supported */ - AHC_HVD = 0x100000, /* HVD rather than SE */ - AHC_AIC7770_FE = AHC_FENONE, - /* - * The real 7850 does not support Ultra modes, but there are - * several cards that use the generic 7850 PCI ID even though - * they are using an Ultra capable chip (7859/7860). We start - * out with the AHC_ULTRA feature set and then check the DEVSTATUS - * register to determine if the capability is really present. - */ - AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, - AHC_AIC7860_FE = AHC_AIC7850_FE, - AHC_AIC7870_FE = AHC_TARGETMODE|AHC_AUTOPAUSE, - AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, - /* - * Although we have space for both the initiator and - * target roles on ULTRA2 chips, we currently disable - * the initiator role to allow multi-scsi-id target mode - * configurations. We can only respond on the same SCSI - * ID as our initiator role if we allow initiator operation. - * At some point, we should add a configuration knob to - * allow both roles to be loaded. - */ - AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2 - |AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_MULTI_TID - |AHC_HS_MAILBOX|AHC_NEW_TERMCTL|AHC_LARGE_SCBS - |AHC_TARGETMODE, - AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_DT|AHC_AUTORATE|AHC_AUTOPAUSE, - AHC_AIC7895_FE = AHC_AIC7880_FE|AHC_MORE_SRAM|AHC_AUTOPAUSE - |AHC_CMD_CHAN|AHC_MULTI_FUNC|AHC_LARGE_SCBS, - AHC_AIC7895C_FE = AHC_AIC7895_FE|AHC_MULTI_TID, - AHC_AIC7896_FE = AHC_AIC7890_FE|AHC_MULTI_FUNC, - AHC_AIC7899_FE = AHC_AIC7892_FE|AHC_MULTI_FUNC -} ahc_feature; - -/* - * Bugs in the silicon that we work around in software. - */ -typedef enum { - AHC_BUGNONE = 0x00, - /* - * On all chips prior to the U2 product line, - * the WIDEODD S/G segment feature does not - * work during scsi->HostBus transfers. - */ - AHC_TMODE_WIDEODD_BUG = 0x01, - /* - * On the aic7890/91 Rev 0 chips, the autoflush - * feature does not work. A manual flush of - * the DMA FIFO is required. - */ - AHC_AUTOFLUSH_BUG = 0x02, - /* - * On many chips, cacheline streaming does not work. - */ - AHC_CACHETHEN_BUG = 0x04, - /* - * On the aic7896/97 chips, cacheline - * streaming must be enabled. - */ - AHC_CACHETHEN_DIS_BUG = 0x08, - /* - * PCI 2.1 Retry failure on non-empty data fifo. - */ - AHC_PCI_2_1_RETRY_BUG = 0x10, - /* - * Controller does not handle cacheline residuals - * properly on S/G segments if PCI MWI instructions - * are allowed. - */ - AHC_PCI_MWI_BUG = 0x20, - /* - * An SCB upload using the SCB channel's - * auto array entry copy feature may - * corrupt data. This appears to only - * occur on 66MHz systems. - */ - AHC_SCBCHAN_UPLOAD_BUG = 0x40 -} ahc_bug; - -/* - * Configuration specific settings. - * The driver determines these settings by probing the - * chip/controller's configuration. - */ -typedef enum { - AHC_FNONE = 0x000, - AHC_PRIMARY_CHANNEL = 0x003, /* - * The channel that should - * be probed first. - */ - AHC_USEDEFAULTS = 0x004, /* - * For cards without an seeprom - * or a BIOS to initialize the chip's - * SRAM, we use the default target - * settings. - */ - AHC_SEQUENCER_DEBUG = 0x008, - AHC_SHARED_SRAM = 0x010, - AHC_LARGE_SEEPROM = 0x020, /* Uses C56_66 not C46 */ - AHC_RESET_BUS_A = 0x040, - AHC_RESET_BUS_B = 0x080, - AHC_EXTENDED_TRANS_A = 0x100, - AHC_EXTENDED_TRANS_B = 0x200, - AHC_TERM_ENB_A = 0x400, - AHC_TERM_ENB_B = 0x800, - AHC_INITIATORROLE = 0x1000, /* - * Allow initiator operations on - * this controller. - */ - AHC_TARGETROLE = 0x2000, /* - * Allow target operations on this - * controller. - */ - AHC_NEWEEPROM_FMT = 0x4000, - AHC_TQINFIFO_BLOCKED = 0x10000, /* Blocked waiting for ATIOs */ - AHC_INT50_SPEEDFLEX = 0x20000, /* - * Internal 50pin connector - * sits behind an aic3860 - */ - AHC_SCB_BTT = 0x40000, /* - * The busy targets table is - * stored in SCB space rather - * than SRAM. - */ - AHC_BIOS_ENABLED = 0x80000, - AHC_ALL_INTERRUPTS = 0x100000, - AHC_PAGESCBS = 0x400000, /* Enable SCB paging */ - AHC_EDGE_INTERRUPT = 0x800000, /* Device uses edge triggered ints */ - AHC_39BIT_ADDRESSING = 0x1000000, /* Use 39 bit addressing scheme. */ - AHC_LSCBS_ENABLED = 0x2000000, /* 64Byte SCBs enabled */ - AHC_SCB_CONFIG_USED = 0x4000000, /* No SEEPROM but SCB2 had info. */ - AHC_NO_BIOS_INIT = 0x8000000, /* No BIOS left over settings. */ - AHC_DISABLE_PCI_PERR = 0x10000000, - AHC_HAS_TERM_LOGIC = 0x20000000 -} ahc_flag; - -/************************* Hardware SCB Definition ***************************/ - -/* - * The driver keeps up to MAX_SCB scb structures per card in memory. The SCB - * consists of a "hardware SCB" mirroring the fields available on the card - * and additional information the kernel stores for each transaction. - * - * To minimize space utilization, a portion of the hardware scb stores - * different data during different portions of a SCSI transaction. - * As initialized by the host driver for the initiator role, this area - * contains the SCSI cdb (or a pointer to the cdb) to be executed. After - * the cdb has been presented to the target, this area serves to store - * residual transfer information and the SCSI status byte. - * For the target role, the contents of this area do not change, but - * still serve a different purpose than for the initiator role. See - * struct target_data for details. - */ - -/* - * Status information embedded in the shared poriton of - * an SCB after passing the cdb to the target. The kernel - * driver will only read this data for transactions that - * complete abnormally (non-zero status byte). - */ -struct status_pkt { - uint32_t residual_datacnt; /* Residual in the current S/G seg */ - uint32_t residual_sg_ptr; /* The next S/G for this transfer */ - uint8_t scsi_status; /* Standard SCSI status byte */ -}; - -/* - * Target mode version of the shared data SCB segment. - */ -struct target_data { - uint32_t residual_datacnt; /* Residual in the current S/G seg */ - uint32_t residual_sg_ptr; /* The next S/G for this transfer */ - uint8_t scsi_status; /* SCSI status to give to initiator */ - uint8_t target_phases; /* Bitmap of phases to execute */ - uint8_t data_phase; /* Data-In or Data-Out */ - uint8_t initiator_tag; /* Initiator's transaction tag */ -}; - -struct hardware_scb { -/*0*/ union { - /* - * If the cdb is 12 bytes or less, we embed it directly - * in the SCB. For longer cdbs, we embed the address - * of the cdb payload as seen by the chip and a DMA - * is used to pull it in. - */ - uint8_t cdb[12]; - uint32_t cdb_ptr; - struct status_pkt status; - struct target_data tdata; - } shared_data; -/* - * A word about residuals. - * The scb is presented to the sequencer with the dataptr and datacnt - * fields initialized to the contents of the first S/G element to - * transfer. The sgptr field is initialized to the bus address for - * the S/G element that follows the first in the in core S/G array - * or'ed with the SG_FULL_RESID flag. Sgptr may point to an invalid - * S/G entry for this transfer (single S/G element transfer with the - * first elements address and length preloaded in the dataptr/datacnt - * fields). If no transfer is to occur, sgptr is set to SG_LIST_NULL. - * The SG_FULL_RESID flag ensures that the residual will be correctly - * noted even if no data transfers occur. Once the data phase is entered, - * the residual sgptr and datacnt are loaded from the sgptr and the - * datacnt fields. After each S/G element's dataptr and length are - * loaded into the hardware, the residual sgptr is advanced. After - * each S/G element is expired, its datacnt field is checked to see - * if the LAST_SEG flag is set. If so, SG_LIST_NULL is set in the - * residual sg ptr and the transfer is considered complete. If the - * sequencer determines that there is a residual in the tranfer, it - * will set the SG_RESID_VALID flag in sgptr and dma the scb back into - * host memory. To sumarize: - * - * Sequencer: - * o A residual has occurred if SG_FULL_RESID is set in sgptr, - * or residual_sgptr does not have SG_LIST_NULL set. - * - * o We are transferring the last segment if residual_datacnt has - * the SG_LAST_SEG flag set. - * - * Host: - * o A residual has occurred if a completed scb has the - * SG_RESID_VALID flag set. - * - * o residual_sgptr and sgptr refer to the "next" sg entry - * and so may point beyond the last valid sg entry for the - * transfer. - */ -/*12*/ uint32_t dataptr; -/*16*/ uint32_t datacnt; /* - * Byte 3 (numbered from 0) of - * the datacnt is really the - * 4th byte in that data address. - */ -/*20*/ uint32_t sgptr; -#define SG_PTR_MASK 0xFFFFFFF8 -/*24*/ uint8_t control; /* See SCB_CONTROL in aic7xxx.reg for details */ -/*25*/ uint8_t scsiid; /* what to load in the SCSIID register */ -/*26*/ uint8_t lun; -/*27*/ uint8_t tag; /* - * Index into our kernel SCB array. - * Also used as the tag for tagged I/O - */ -/*28*/ uint8_t cdb_len; -/*29*/ uint8_t scsirate; /* Value for SCSIRATE register */ -/*30*/ uint8_t scsioffset; /* Value for SCSIOFFSET register */ -/*31*/ uint8_t next; /* - * Used for threading SCBs in the - * "Waiting for Selection" and - * "Disconnected SCB" lists down - * in the sequencer. - */ -/*32*/ uint8_t cdb32[32]; /* - * CDB storage for cdbs of size - * 13->32. We store them here - * because hardware scbs are - * allocated from DMA safe - * memory so we are guaranteed - * the controller can access - * this data. - */ -}; - -/************************ Kernel SCB Definitions ******************************/ -/* - * Some fields of the SCB are OS dependent. Here we collect the - * definitions for elements that all OS platforms need to include - * in there SCB definition. - */ - -/* - * Definition of a scatter/gather element as transferred to the controller. - * The aic7xxx chips only support a 24bit length. We use the top byte of - * the length to store additional address bits and a flag to indicate - * that a given segment terminates the transfer. This gives us an - * addressable range of 512GB on machines with 64bit PCI or with chips - * that can support dual address cycles on 32bit PCI busses. - */ -struct ahc_dma_seg { - uint32_t addr; - uint32_t len; -#define AHC_DMA_LAST_SEG 0x80000000 -#define AHC_SG_HIGH_ADDR_MASK 0x7F000000 -#define AHC_SG_LEN_MASK 0x00FFFFFF -}; - -struct sg_map_node { - bus_dmamap_t sg_dmamap; - dma_addr_t sg_physaddr; - struct ahc_dma_seg* sg_vaddr; - SLIST_ENTRY(sg_map_node) links; -}; - -/* - * The current state of this SCB. - */ -typedef enum { - SCB_FREE = 0x0000, - SCB_OTHERTCL_TIMEOUT = 0x0002,/* - * Another device was active - * during the first timeout for - * this SCB so we gave ourselves - * an additional timeout period - * in case it was hogging the - * bus. - */ - SCB_DEVICE_RESET = 0x0004, - SCB_SENSE = 0x0008, - SCB_CDB32_PTR = 0x0010, - SCB_RECOVERY_SCB = 0x0020, - SCB_AUTO_NEGOTIATE = 0x0040,/* Negotiate to achieve goal. */ - SCB_NEGOTIATE = 0x0080,/* Negotiation forced for command. */ - SCB_ABORT = 0x0100, - SCB_UNTAGGEDQ = 0x0200, - SCB_ACTIVE = 0x0400, - SCB_TARGET_IMMEDIATE = 0x0800, - SCB_TRANSMISSION_ERROR = 0x1000,/* - * We detected a parity or CRC - * error that has effected the - * payload of the command. This - * flag is checked when normal - * status is returned to catch - * the case of a target not - * responding to our attempt - * to report the error. - */ - SCB_TARGET_SCB = 0x2000, - SCB_SILENT = 0x4000 /* - * Be quiet about transmission type - * errors. They are expected and we - * don't want to upset the user. This - * flag is typically used during DV. - */ -} scb_flag; - -struct scb { - struct hardware_scb *hscb; - union { - SLIST_ENTRY(scb) sle; - TAILQ_ENTRY(scb) tqe; - } links; - LIST_ENTRY(scb) pending_links; - ahc_io_ctx_t io_ctx; - struct ahc_softc *ahc_softc; - scb_flag flags; -#ifndef __linux__ - bus_dmamap_t dmamap; -#endif - struct scb_platform_data *platform_data; - struct sg_map_node *sg_map; - struct ahc_dma_seg *sg_list; - dma_addr_t sg_list_phys; - u_int sg_count;/* How full ahc_dma_seg is */ -}; - -struct scb_data { - SLIST_HEAD(, scb) free_scbs; /* - * Pool of SCBs ready to be assigned - * commands to execute. - */ - struct scb *scbindex[256]; /* - * Mapping from tag to SCB. - * As tag identifiers are an - * 8bit value, we provide space - * for all possible tag values. - * Any lookups to entries at or - * above AHC_SCB_MAX_ALLOC will - * always fail. - */ - struct hardware_scb *hscbs; /* Array of hardware SCBs */ - struct scb *scbarray; /* Array of kernel SCBs */ - struct scsi_sense_data *sense; /* Per SCB sense data */ - - /* - * "Bus" addresses of our data structures. - */ - bus_dma_tag_t hscb_dmat; /* dmat for our hardware SCB array */ - bus_dmamap_t hscb_dmamap; - dma_addr_t hscb_busaddr; - bus_dma_tag_t sense_dmat; - bus_dmamap_t sense_dmamap; - dma_addr_t sense_busaddr; - bus_dma_tag_t sg_dmat; /* dmat for our sg segments */ - SLIST_HEAD(, sg_map_node) sg_maps; - uint8_t numscbs; - uint8_t maxhscbs; /* Number of SCBs on the card */ - uint8_t init_level; /* - * How far we've initialized - * this structure. - */ -}; - -/************************ Target Mode Definitions *****************************/ - -/* - * Connection descriptor for select-in requests in target mode. - */ -struct target_cmd { - uint8_t scsiid; /* Our ID and the initiator's ID */ - uint8_t identify; /* Identify message */ - uint8_t bytes[22]; /* - * Bytes contains any additional message - * bytes terminated by 0xFF. The remainder - * is the cdb to execute. - */ - uint8_t cmd_valid; /* - * When a command is complete, the firmware - * will set cmd_valid to all bits set. - * After the host has seen the command, - * the bits are cleared. This allows us - * to just peek at host memory to determine - * if more work is complete. cmd_valid is on - * an 8 byte boundary to simplify setting - * it on aic7880 hardware which only has - * limited direct access to the DMA FIFO. - */ - uint8_t pad[7]; -}; - -/* - * Number of events we can buffer up if we run out - * of immediate notify ccbs. - */ -#define AHC_TMODE_EVENT_BUFFER_SIZE 8 -struct ahc_tmode_event { - uint8_t initiator_id; - uint8_t event_type; /* MSG type or EVENT_TYPE_BUS_RESET */ -#define EVENT_TYPE_BUS_RESET 0xFF - uint8_t event_arg; -}; - -/* - * Per enabled lun target mode state. - * As this state is directly influenced by the host OS'es target mode - * environment, we let the OS module define it. Forward declare the - * structure here so we can store arrays of them, etc. in OS neutral - * data structures. - */ -#ifdef AHC_TARGET_MODE -struct ahc_tmode_lstate { - struct cam_path *path; - struct ccb_hdr_slist accept_tios; - struct ccb_hdr_slist immed_notifies; - struct ahc_tmode_event event_buffer[AHC_TMODE_EVENT_BUFFER_SIZE]; - uint8_t event_r_idx; - uint8_t event_w_idx; -}; -#else -struct ahc_tmode_lstate; -#endif - -/******************** Transfer Negotiation Datastructures *********************/ -#define AHC_TRANS_CUR 0x01 /* Modify current neogtiation status */ -#define AHC_TRANS_ACTIVE 0x03 /* Assume this target is on the bus */ -#define AHC_TRANS_GOAL 0x04 /* Modify negotiation goal */ -#define AHC_TRANS_USER 0x08 /* Modify user negotiation settings */ - -#define AHC_WIDTH_UNKNOWN 0xFF -#define AHC_PERIOD_UNKNOWN 0xFF -#define AHC_OFFSET_UNKNOWN 0xFF -#define AHC_PPR_OPTS_UNKNOWN 0xFF - -/* - * Transfer Negotiation Information. - */ -struct ahc_transinfo { - uint8_t protocol_version; /* SCSI Revision level */ - uint8_t transport_version; /* SPI Revision level */ - uint8_t width; /* Bus width */ - uint8_t period; /* Sync rate factor */ - uint8_t offset; /* Sync offset */ - uint8_t ppr_options; /* Parallel Protocol Request options */ -}; - -/* - * Per-initiator current, goal and user transfer negotiation information. */ -struct ahc_initiator_tinfo { - uint8_t scsirate; /* Computed value for SCSIRATE reg */ - struct ahc_transinfo curr; - struct ahc_transinfo goal; - struct ahc_transinfo user; -}; - -/* - * Per enabled target ID state. - * Pointers to lun target state as well as sync/wide negotiation information - * for each initiator<->target mapping. For the initiator role we pretend - * that we are the target and the targets are the initiators since the - * negotiation is the same regardless of role. - */ -struct ahc_tmode_tstate { - struct ahc_tmode_lstate* enabled_luns[AHC_NUM_LUNS]; - struct ahc_initiator_tinfo transinfo[AHC_NUM_TARGETS]; - - /* - * Per initiator state bitmasks. - */ - uint16_t auto_negotiate;/* Auto Negotiation Required */ - uint16_t ultraenb; /* Using ultra sync rate */ - uint16_t discenable; /* Disconnection allowed */ - uint16_t tagenable; /* Tagged Queuing allowed */ -}; - -/* - * Data structure for our table of allowed synchronous transfer rates. - */ -struct ahc_syncrate { - u_int sxfr_u2; /* Value of the SXFR parameter for Ultra2+ Chips */ - u_int sxfr; /* Value of the SXFR parameter for <= Ultra Chips */ -#define ULTRA_SXFR 0x100 /* Rate Requires Ultra Mode set */ -#define ST_SXFR 0x010 /* Rate Single Transition Only */ -#define DT_SXFR 0x040 /* Rate Double Transition Only */ - uint8_t period; /* Period to send to SCSI target */ - const char *rate; -}; - -/* Safe and valid period for async negotiations. */ -#define AHC_ASYNC_XFER_PERIOD 0x45 -#define AHC_ULTRA2_XFER_PERIOD 0x0a - -/* - * Indexes into our table of syncronous transfer rates. - */ -#define AHC_SYNCRATE_DT 0 -#define AHC_SYNCRATE_ULTRA2 1 -#define AHC_SYNCRATE_ULTRA 3 -#define AHC_SYNCRATE_FAST 6 -#define AHC_SYNCRATE_MAX AHC_SYNCRATE_DT -#define AHC_SYNCRATE_MIN 13 - -/***************************** Lookup Tables **********************************/ -/* - * Phase -> name and message out response - * to parity errors in each phase table. - */ -struct ahc_phase_table_entry { - uint8_t phase; - uint8_t mesg_out; /* Message response to parity errors */ - char *phasemsg; -}; - -/************************** Serial EEPROM Format ******************************/ - -struct seeprom_config { -/* - * Per SCSI ID Configuration Flags - */ - uint16_t device_flags[16]; /* words 0-15 */ -#define CFXFER 0x0007 /* synchronous transfer rate */ -#define CFSYNCH 0x0008 /* enable synchronous transfer */ -#define CFDISC 0x0010 /* enable disconnection */ -#define CFWIDEB 0x0020 /* wide bus device */ -#define CFSYNCHISULTRA 0x0040 /* CFSYNCH is an ultra offset (2940AU)*/ -#define CFSYNCSINGLE 0x0080 /* Single-Transition signalling */ -#define CFSTART 0x0100 /* send start unit SCSI command */ -#define CFINCBIOS 0x0200 /* include in BIOS scan */ -#define CFRNFOUND 0x0400 /* report even if not found */ -#define CFMULTILUNDEV 0x0800 /* Probe multiple luns in BIOS scan */ -#define CFWBCACHEENB 0x4000 /* Enable W-Behind Cache on disks */ -#define CFWBCACHENOP 0xc000 /* Don't touch W-Behind Cache */ - -/* - * BIOS Control Bits - */ - uint16_t bios_control; /* word 16 */ -#define CFSUPREM 0x0001 /* support all removeable drives */ -#define CFSUPREMB 0x0002 /* support removeable boot drives */ -#define CFBIOSEN 0x0004 /* BIOS enabled */ -#define CFBIOS_BUSSCAN 0x0008 /* Have the BIOS Scan the Bus */ -#define CFSM2DRV 0x0010 /* support more than two drives */ -#define CFSTPWLEVEL 0x0010 /* Termination level control */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ -#define CFCTRL_A 0x0020 /* BIOS displays Ctrl-A message */ -#define CFTERM_MENU 0x0040 /* BIOS displays termination menu */ -#define CFEXTEND 0x0080 /* extended translation enabled */ -#define CFSCAMEN 0x0100 /* SCAM enable */ -#define CFMSG_LEVEL 0x0600 /* BIOS Message Level */ -#define CFMSG_VERBOSE 0x0000 -#define CFMSG_SILENT 0x0200 -#define CFMSG_DIAG 0x0400 -#define CFBOOTCD 0x0800 /* Support Bootable CD-ROM */ -/* UNUSED 0xff00 */ - -/* - * Host Adapter Control Bits - */ - uint16_t adapter_control; /* word 17 */ -#define CFAUTOTERM 0x0001 /* Perform Auto termination */ -#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable */ -#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */ -#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */ -#define CFSTERM 0x0004 /* SCSI low byte termination */ -#define CFWSTERM 0x0008 /* SCSI high byte termination */ -#define CFSPARITY 0x0010 /* SCSI parity */ -#define CF284XSTERM 0x0020 /* SCSI low byte term (284x cards) */ -#define CFMULTILUN 0x0020 -#define CFRESETB 0x0040 /* reset SCSI bus at boot */ -#define CFCLUSTERENB 0x0080 /* Cluster Enable */ -#define CFBOOTCHAN 0x0300 /* probe this channel first */ -#define CFBOOTCHANSHIFT 8 -#define CFSEAUTOTERM 0x0400 /* Ultra2 Perform secondary Auto Term*/ -#define CFSELOWTERM 0x0800 /* Ultra2 secondary low term */ -#define CFSEHIGHTERM 0x1000 /* Ultra2 secondary high term */ -#define CFENABLEDV 0x4000 /* Perform Domain Validation*/ - -/* - * Bus Release Time, Host Adapter ID - */ - uint16_t brtime_id; /* word 18 */ -#define CFSCSIID 0x000f /* host adapter SCSI ID */ -/* UNUSED 0x00f0 */ -#define CFBRTIME 0xff00 /* bus release time */ - -/* - * Maximum targets - */ - uint16_t max_targets; /* word 19 */ -#define CFMAXTARG 0x00ff /* maximum targets */ -#define CFBOOTLUN 0x0f00 /* Lun to boot from */ -#define CFBOOTID 0xf000 /* Target to boot from */ - uint16_t res_1[10]; /* words 20-29 */ - uint16_t signature; /* Signature == 0x250 */ -#define CFSIGNATURE 0x250 -#define CFSIGNATURE2 0x300 - uint16_t checksum; /* word 31 */ -}; - -/**************************** Message Buffer *********************************/ -typedef enum { - MSG_TYPE_NONE = 0x00, - MSG_TYPE_INITIATOR_MSGOUT = 0x01, - MSG_TYPE_INITIATOR_MSGIN = 0x02, - MSG_TYPE_TARGET_MSGOUT = 0x03, - MSG_TYPE_TARGET_MSGIN = 0x04 -} ahc_msg_type; - -typedef enum { - MSGLOOP_IN_PROG, - MSGLOOP_MSGCOMPLETE, - MSGLOOP_TERMINATED -} msg_loop_stat; - -/*********************** Software Configuration Structure *********************/ -TAILQ_HEAD(scb_tailq, scb); - -struct ahc_aic7770_softc { - /* - * Saved register state used for chip_init(). - */ - uint8_t busspd; - uint8_t bustime; -}; - -struct ahc_pci_softc { - /* - * Saved register state used for chip_init(). - */ - uint32_t devconfig; - uint16_t targcrccnt; - uint8_t command; - uint8_t csize_lattime; - uint8_t optionmode; - uint8_t crccontrol1; - uint8_t dscommand0; - uint8_t dspcistatus; - uint8_t scbbaddr; - uint8_t dff_thrsh; -}; - -union ahc_bus_softc { - struct ahc_aic7770_softc aic7770_softc; - struct ahc_pci_softc pci_softc; -}; - -typedef void (*ahc_bus_intr_t)(struct ahc_softc *); -typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *); -typedef int (*ahc_bus_suspend_t)(struct ahc_softc *); -typedef int (*ahc_bus_resume_t)(struct ahc_softc *); -typedef void ahc_callback_t (void *); - -struct ahc_softc { - bus_space_tag_t tag; - bus_space_handle_t bsh; -#ifndef __linux__ - bus_dma_tag_t buffer_dmat; /* dmat for buffer I/O */ -#endif - struct scb_data *scb_data; - - struct scb *next_queued_scb; - - /* - * SCBs that have been sent to the controller - */ - LIST_HEAD(, scb) pending_scbs; - - /* - * Counting lock for deferring the release of additional - * untagged transactions from the untagged_queues. When - * the lock is decremented to 0, all queues in the - * untagged_queues array are run. - */ - u_int untagged_queue_lock; - - /* - * Per-target queue of untagged-transactions. The - * transaction at the head of the queue is the - * currently pending untagged transaction for the - * target. The driver only allows a single untagged - * transaction per target. - */ - struct scb_tailq untagged_queues[AHC_NUM_TARGETS]; - - /* - * Bus attachment specific data. - */ - union ahc_bus_softc bus_softc; - - /* - * Platform specific data. - */ - struct ahc_platform_data *platform_data; - - /* - * Platform specific device information. - */ - ahc_dev_softc_t dev_softc; - - /* - * Bus specific device information. - */ - ahc_bus_intr_t bus_intr; - - /* - * Bus specific initialization required - * after a chip reset. - */ - ahc_bus_chip_init_t bus_chip_init; - - /* - * Target mode related state kept on a per enabled lun basis. - * Targets that are not enabled will have null entries. - * As an initiator, we keep one target entry for our initiator - * ID to store our sync/wide transfer settings. - */ - struct ahc_tmode_tstate *enabled_targets[AHC_NUM_TARGETS]; - - /* - * The black hole device responsible for handling requests for - * disabled luns on enabled targets. - */ - struct ahc_tmode_lstate *black_hole; - - /* - * Device instance currently on the bus awaiting a continue TIO - * for a command that was not given the disconnect priveledge. - */ - struct ahc_tmode_lstate *pending_device; - - /* - * Card characteristics - */ - ahc_chip chip; - ahc_feature features; - ahc_bug bugs; - ahc_flag flags; - struct seeprom_config *seep_config; - - /* Values to store in the SEQCTL register for pause and unpause */ - uint8_t unpause; - uint8_t pause; - - /* Command Queues */ - uint8_t qoutfifonext; - uint8_t qinfifonext; - uint8_t *qoutfifo; - uint8_t *qinfifo; - - /* Critical Section Data */ - struct cs *critical_sections; - u_int num_critical_sections; - - /* Channel Names ('A', 'B', etc.) */ - char channel; - char channel_b; - - /* Initiator Bus ID */ - uint8_t our_id; - uint8_t our_id_b; - - /* - * PCI error detection. - */ - int unsolicited_ints; - - /* - * Target incoming command FIFO. - */ - struct target_cmd *targetcmds; - uint8_t tqinfifonext; - - /* - * Cached copy of the sequencer control register. - */ - uint8_t seqctl; - - /* - * Incoming and outgoing message handling. - */ - uint8_t send_msg_perror; - ahc_msg_type msg_type; - uint8_t msgout_buf[12];/* Message we are sending */ - uint8_t msgin_buf[12];/* Message we are receiving */ - u_int msgout_len; /* Length of message to send */ - u_int msgout_index; /* Current index in msgout */ - u_int msgin_index; /* Current index in msgin */ - - /* - * Mapping information for data structures shared - * between the sequencer and kernel. - */ - bus_dma_tag_t parent_dmat; - bus_dma_tag_t shared_data_dmat; - bus_dmamap_t shared_data_dmamap; - dma_addr_t shared_data_busaddr; - - /* - * Bus address of the one byte buffer used to - * work-around a DMA bug for chips <= aic7880 - * in target mode. - */ - dma_addr_t dma_bug_buf; - - /* Number of enabled target mode device on this card */ - u_int enabled_luns; - - /* Initialization level of this data structure */ - u_int init_level; - - /* PCI cacheline size. */ - u_int pci_cachesize; - - /* - * Count of parity errors we have seen as a target. - * We auto-disable parity error checking after seeing - * AHC_PCI_TARGET_PERR_THRESH number of errors. - */ - u_int pci_target_perr_count; -#define AHC_PCI_TARGET_PERR_THRESH 10 - - /* Maximum number of sequencer instructions supported. */ - u_int instruction_ram_size; - - /* Per-Unit descriptive information */ - const char *description; - char *name; - int unit; - - /* Selection Timer settings */ - int seltime; - int seltime_b; - - uint16_t user_discenable;/* Disconnection allowed */ - uint16_t user_tagenable;/* Tagged Queuing allowed */ -}; - -/************************ Active Device Information ***************************/ -typedef enum { - ROLE_UNKNOWN, - ROLE_INITIATOR, - ROLE_TARGET -} role_t; - -struct ahc_devinfo { - int our_scsiid; - int target_offset; - uint16_t target_mask; - u_int target; - u_int lun; - char channel; - role_t role; /* - * Only guaranteed to be correct if not - * in the busfree state. - */ -}; - -/****************************** PCI Structures ********************************/ -typedef int (ahc_device_setup_t)(struct ahc_softc *); - -struct ahc_pci_identity { - uint64_t full_id; - uint64_t id_mask; - const char *name; - ahc_device_setup_t *setup; -}; - -/***************************** VL/EISA Declarations ***************************/ -struct aic7770_identity { - uint32_t full_id; - uint32_t id_mask; - const char *name; - ahc_device_setup_t *setup; -}; -extern struct aic7770_identity aic7770_ident_table[]; -extern const int ahc_num_aic7770_devs; - -#define AHC_EISA_SLOT_OFFSET 0xc00 -#define AHC_EISA_IOSIZE 0x100 - -/*************************** Function Declarations ****************************/ -/******************************************************************************/ - -/***************************** PCI Front End *********************************/ -const struct ahc_pci_identity *ahc_find_pci_device(ahc_dev_softc_t); -int ahc_pci_config(struct ahc_softc *, - const struct ahc_pci_identity *); -int ahc_pci_test_register_access(struct ahc_softc *); -#ifdef CONFIG_PM -void ahc_pci_resume(struct ahc_softc *ahc); -#endif - -/*************************** EISA/VL Front End ********************************/ -struct aic7770_identity *aic7770_find_device(uint32_t); -int aic7770_config(struct ahc_softc *ahc, - struct aic7770_identity *, - u_int port); - -/************************** SCB and SCB queue management **********************/ -int ahc_probe_scbs(struct ahc_softc *); -void ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, - struct scb *scb); -int ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, - int target, char channel, int lun, - u_int tag, role_t role); - -/****************************** Initialization ********************************/ -struct ahc_softc *ahc_alloc(void *platform_arg, char *name); -int ahc_softc_init(struct ahc_softc *); -void ahc_controller_info(struct ahc_softc *ahc, char *buf); -int ahc_chip_init(struct ahc_softc *ahc); -int ahc_init(struct ahc_softc *ahc); -void ahc_intr_enable(struct ahc_softc *ahc, int enable); -void ahc_pause_and_flushwork(struct ahc_softc *ahc); -#ifdef CONFIG_PM -int ahc_suspend(struct ahc_softc *ahc); -int ahc_resume(struct ahc_softc *ahc); -#endif -void ahc_set_unit(struct ahc_softc *, int); -void ahc_set_name(struct ahc_softc *, char *); -void ahc_free(struct ahc_softc *ahc); -int ahc_reset(struct ahc_softc *ahc, int reinit); - -/***************************** Error Recovery *********************************/ -typedef enum { - SEARCH_COMPLETE, - SEARCH_COUNT, - SEARCH_REMOVE -} ahc_search_action; -int ahc_search_qinfifo(struct ahc_softc *ahc, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status, - ahc_search_action action); -int ahc_search_untagged_queues(struct ahc_softc *ahc, - ahc_io_ctx_t ctx, - int target, char channel, - int lun, uint32_t status, - ahc_search_action action); -int ahc_search_disc_list(struct ahc_softc *ahc, int target, - char channel, int lun, u_int tag, - int stop_on_first, int remove, - int save_state); -int ahc_reset_channel(struct ahc_softc *ahc, char channel, - int initiate_reset); - -/*************************** Utility Functions ********************************/ -void ahc_compile_devinfo(struct ahc_devinfo *devinfo, - u_int our_id, u_int target, - u_int lun, char channel, - role_t role); -/************************** Transfer Negotiation ******************************/ -const struct ahc_syncrate* ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, - u_int *ppr_options, u_int maxsync); -u_int ahc_find_period(struct ahc_softc *ahc, - u_int scsirate, u_int maxsync); -/* - * Negotiation types. These are used to qualify if we should renegotiate - * even if our goal and current transport parameters are identical. - */ -typedef enum { - AHC_NEG_TO_GOAL, /* Renegotiate only if goal and curr differ. */ - AHC_NEG_IF_NON_ASYNC, /* Renegotiate so long as goal is non-async. */ - AHC_NEG_ALWAYS /* Renegotiat even if goal is async. */ -} ahc_neg_type; -int ahc_update_neg_request(struct ahc_softc*, - struct ahc_devinfo*, - struct ahc_tmode_tstate*, - struct ahc_initiator_tinfo*, - ahc_neg_type); -void ahc_set_width(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - u_int width, u_int type, int paused); -void ahc_set_syncrate(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - const struct ahc_syncrate *syncrate, - u_int period, u_int offset, - u_int ppr_options, - u_int type, int paused); -typedef enum { - AHC_QUEUE_NONE, - AHC_QUEUE_BASIC, - AHC_QUEUE_TAGGED -} ahc_queue_alg; - -/**************************** Target Mode *************************************/ -#ifdef AHC_TARGET_MODE -void ahc_send_lstate_events(struct ahc_softc *, - struct ahc_tmode_lstate *); -void ahc_handle_en_lun(struct ahc_softc *ahc, - struct cam_sim *sim, union ccb *ccb); -cam_status ahc_find_tmode_devs(struct ahc_softc *ahc, - struct cam_sim *sim, union ccb *ccb, - struct ahc_tmode_tstate **tstate, - struct ahc_tmode_lstate **lstate, - int notfound_failure); -#ifndef AHC_TMODE_ENABLE -#define AHC_TMODE_ENABLE 0 -#endif -#endif -/******************************* Debug ***************************************/ -#ifdef AHC_DEBUG -extern uint32_t ahc_debug; -#define AHC_SHOW_MISC 0x0001 -#define AHC_SHOW_SENSE 0x0002 -#define AHC_DUMP_SEEPROM 0x0004 -#define AHC_SHOW_TERMCTL 0x0008 -#define AHC_SHOW_MEMORY 0x0010 -#define AHC_SHOW_MESSAGES 0x0020 -#define AHC_SHOW_DV 0x0040 -#define AHC_SHOW_SELTO 0x0080 -#define AHC_SHOW_QFULL 0x0200 -#define AHC_SHOW_QUEUE 0x0400 -#define AHC_SHOW_TQIN 0x0800 -#define AHC_SHOW_MASKED_ERRORS 0x1000 -#define AHC_DEBUG_SEQUENCER 0x2000 -#endif -void ahc_print_devinfo(struct ahc_softc *ahc, - struct ahc_devinfo *dev); -void ahc_dump_card_state(struct ahc_softc *ahc); -int ahc_print_register(const ahc_reg_parse_entry_t *table, - u_int num_entries, - const char *name, - u_int address, - u_int value, - u_int *cur_column, - u_int wrap_point); -/******************************* SEEPROM *************************************/ -int ahc_acquire_seeprom(struct ahc_softc *ahc, - struct seeprom_descriptor *sd); -void ahc_release_seeprom(struct seeprom_descriptor *sd); -#endif /* _AIC7XXX_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.reg b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.reg deleted file mode 100644 index ba0b411d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.reg +++ /dev/null @@ -1,1761 +0,0 @@ -/* - * Aic7xxx register and scratch ram definitions. - * - * Copyright (c) 1994-2001 Justin T. Gibbs. - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $FreeBSD$ - */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $" - -/* - * This file is processed by the aic7xxx_asm utility for use in assembling - * firmware for the aic7xxx family of SCSI host adapters as well as to generate - * a C header file for use in the kernel portion of the Aic7xxx driver. - * - * All page numbers refer to the Adaptec AIC-7770 Data Book available from - * Adaptec's Technical Documents Department 1-800-934-2766 - */ - -/* - * Registers marked "dont_generate_debug_code" are not (yet) referenced - * from the driver code, and this keyword inhibit generation - * of debug code for them. - * - * REG_PRETTY_PRINT config will complain if dont_generate_debug_code - * is added to the register which is referenced in the driver. - * Unreferenced register with no dont_generate_debug_code will result - * in dead code. No warning is issued. - */ - -/* - * SCSI Sequence Control (p. 3-11). - * Each bit, when set starts a specific SCSI sequence on the bus - */ -register SCSISEQ { - address 0x000 - access_mode RW - field TEMODE 0x80 - field ENSELO 0x40 - field ENSELI 0x20 - field ENRSELI 0x10 - field ENAUTOATNO 0x08 - field ENAUTOATNI 0x04 - field ENAUTOATNP 0x02 - field SCSIRSTO 0x01 -} - -/* - * SCSI Transfer Control 0 Register (pp. 3-13). - * Controls the SCSI module data path. - */ -register SXFRCTL0 { - address 0x001 - access_mode RW - field DFON 0x80 - field DFPEXP 0x40 - field FAST20 0x20 - field CLRSTCNT 0x10 - field SPIOEN 0x08 - field SCAMEN 0x04 - field CLRCHN 0x02 -} - -/* - * SCSI Transfer Control 1 Register (pp. 3-14,15). - * Controls the SCSI module data path. - */ -register SXFRCTL1 { - address 0x002 - access_mode RW - field BITBUCKET 0x80 - field SWRAPEN 0x40 - field ENSPCHK 0x20 - mask STIMESEL 0x18 - field ENSTIMER 0x04 - field ACTNEGEN 0x02 - field STPWEN 0x01 /* Powered Termination */ - dont_generate_debug_code -} - -/* - * SCSI Control Signal Read Register (p. 3-15). - * Reads the actual state of the SCSI bus pins - */ -register SCSISIGI { - address 0x003 - access_mode RO - field CDI 0x80 - field IOI 0x40 - field MSGI 0x20 - field ATNI 0x10 - field SELI 0x08 - field BSYI 0x04 - field REQI 0x02 - field ACKI 0x01 -/* - * Possible phases in SCSISIGI - */ - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_DATAOUT_DT P_DATAOUT|MSGI - mask P_DATAIN_DT P_DATAIN|MSGI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI -} - -/* - * SCSI Control Signal Write Register (p. 3-16). - * Writing to this register modifies the control signals on the bus. Only - * those signals that are allowed in the current mode (Initiator/Target) are - * asserted. - */ -register SCSISIGO { - address 0x003 - access_mode WO - field CDO 0x80 - field IOO 0x40 - field MSGO 0x20 - field ATNO 0x10 - field SELO 0x08 - field BSYO 0x04 - field REQO 0x02 - field ACKO 0x01 -/* - * Possible phases to write into SCSISIG0 - */ - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI - dont_generate_debug_code -} - -/* - * SCSI Rate Control (p. 3-17). - * Contents of this register determine the Synchronous SCSI data transfer - * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the - * SOFS (3:0) bits disables synchronous data transfers. Any offset value - * greater than 0 enables synchronous transfers. - */ -register SCSIRATE { - address 0x004 - access_mode RW - field WIDEXFER 0x80 /* Wide transfer control */ - field ENABLE_CRC 0x40 /* CRC for D-Phases */ - field SINGLE_EDGE 0x10 /* Disable DT Transfers */ - mask SXFR 0x70 /* Sync transfer rate */ - mask SXFR_ULTRA2 0x0f /* Sync transfer rate */ - mask SOFS 0x0f /* Sync offset */ -} - -/* - * SCSI ID (p. 3-18). - * Contains the ID of the board and the current target on the - * selected channel. - */ -register SCSIID { - address 0x005 - access_mode RW - mask TID 0xf0 /* Target ID mask */ - mask TWIN_TID 0x70 - field TWIN_CHNLB 0x80 - mask OID 0x0f /* Our ID mask */ - /* - * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book) - * The aic7890/91 allow an offset of up to 127 transfers in both wide - * and narrow mode. - */ - alias SCSIOFFSET - mask SOFS_ULTRA2 0x7f /* Sync offset U2 chips */ - dont_generate_debug_code -} - -/* - * SCSI Latched Data (p. 3-19). - * Read/Write latches used to transfer data on the SCSI bus during - * Automatic or Manual PIO mode. SCSIDATH can be used for the - * upper byte of a 16bit wide asynchronouse data phase transfer. - */ -register SCSIDATL { - address 0x006 - access_mode RW - dont_generate_debug_code -} - -register SCSIDATH { - address 0x007 - access_mode RW -} - -/* - * SCSI Transfer Count (pp. 3-19,20) - * These registers count down the number of bytes transferred - * across the SCSI bus. The counter is decremented only once - * the data has been safely transferred. SDONE in SSTAT0 is - * set when STCNT goes to 0 - */ -register STCNT { - address 0x008 - size 3 - access_mode RW - dont_generate_debug_code -} - -/* ALT_MODE registers (Ultra2 and Ultra160 chips) */ -register SXFRCTL2 { - address 0x013 - access_mode RW - field AUTORSTDIS 0x10 - field CMDDMAEN 0x08 - mask ASYNC_SETUP 0x07 -} - -/* ALT_MODE register on Ultra160 chips */ -register OPTIONMODE { - address 0x008 - access_mode RW - count 2 - field AUTORATEEN 0x80 - field AUTOACKEN 0x40 - field ATNMGMNTEN 0x20 - field BUSFREEREV 0x10 - field EXPPHASEDIS 0x08 - field SCSIDATL_IMGEN 0x04 - field AUTO_MSGOUT_DE 0x02 - field DIS_MSGIN_DUALEDGE 0x01 - mask OPTIONMODE_DEFAULTS AUTO_MSGOUT_DE|DIS_MSGIN_DUALEDGE - dont_generate_debug_code -} - -/* ALT_MODE register on Ultra160 chips */ -register TARGCRCCNT { - address 0x00a - size 2 - access_mode RW - count 2 - dont_generate_debug_code -} - -/* - * Clear SCSI Interrupt 0 (p. 3-20) - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0. - */ -register CLRSINT0 { - address 0x00b - access_mode WO - field CLRSELDO 0x40 - field CLRSELDI 0x20 - field CLRSELINGO 0x10 - field CLRSWRAP 0x08 - field CLRIOERR 0x08 /* Ultra2 Only */ - field CLRSPIORDY 0x02 - dont_generate_debug_code -} - -/* - * SCSI Status 0 (p. 3-21) - * Contains one set of SCSI Interrupt codes - * These are most likely of interest to the sequencer - */ -register SSTAT0 { - address 0x00b - access_mode RO - field TARGET 0x80 /* Board acting as target */ - field SELDO 0x40 /* Selection Done */ - field SELDI 0x20 /* Board has been selected */ - field SELINGO 0x10 /* Selection In Progress */ - field SWRAP 0x08 /* 24bit counter wrap */ - field IOERR 0x08 /* LVD Tranceiver mode changed */ - field SDONE 0x04 /* STCNT = 0x000000 */ - field SPIORDY 0x02 /* SCSI PIO Ready */ - field DMADONE 0x01 /* DMA transfer completed */ -} - -/* - * Clear SCSI Interrupt 1 (p. 3-23) - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. - */ -register CLRSINT1 { - address 0x00c - access_mode WO - field CLRSELTIMEO 0x80 - field CLRATNO 0x40 - field CLRSCSIRSTI 0x20 - field CLRBUSFREE 0x08 - field CLRSCSIPERR 0x04 - field CLRPHASECHG 0x02 - field CLRREQINIT 0x01 - dont_generate_debug_code -} - -/* - * SCSI Status 1 (p. 3-24) - */ -register SSTAT1 { - address 0x00c - access_mode RO - field SELTO 0x80 - field ATNTARG 0x40 - field SCSIRSTI 0x20 - field PHASEMIS 0x10 - field BUSFREE 0x08 - field SCSIPERR 0x04 - field PHASECHG 0x02 - field REQINIT 0x01 -} - -/* - * SCSI Status 2 (pp. 3-25,26) - */ -register SSTAT2 { - address 0x00d - access_mode RO - field OVERRUN 0x80 - field SHVALID 0x40 /* Shadow Layer non-zero */ - field EXP_ACTIVE 0x10 /* SCSI Expander Active */ - field CRCVALERR 0x08 /* CRC doesn't match (U3 only) */ - field CRCENDERR 0x04 /* No terminal CRC packet (U3 only) */ - field CRCREQERR 0x02 /* Illegal CRC packet req (U3 only) */ - field DUAL_EDGE_ERR 0x01 /* Incorrect data phase (U3 only) */ - mask SFCNT 0x1f -} - -/* - * SCSI Status 3 (p. 3-26) - */ -register SSTAT3 { - address 0x00e - access_mode RO - count 2 - mask SCSICNT 0xf0 - mask OFFCNT 0x0f - mask U2OFFCNT 0x7f -} - -/* - * SCSI ID for the aic7890/91 chips - */ -register SCSIID_ULTRA2 { - address 0x00f - access_mode RW - mask TID 0xf0 /* Target ID mask */ - mask OID 0x0f /* Our ID mask */ - dont_generate_debug_code -} - -/* - * SCSI Interrupt Mode 1 (p. 3-28) - * Setting any bit will enable the corresponding function - * in SIMODE0 to interrupt via the IRQ pin. - */ -register SIMODE0 { - address 0x010 - access_mode RW - count 2 - field ENSELDO 0x40 - field ENSELDI 0x20 - field ENSELINGO 0x10 - field ENSWRAP 0x08 - field ENIOERR 0x08 /* LVD Tranceiver mode changes */ - field ENSDONE 0x04 - field ENSPIORDY 0x02 - field ENDMADONE 0x01 -} - -/* - * SCSI Interrupt Mode 1 (pp. 3-28,29) - * Setting any bit will enable the corresponding function - * in SIMODE1 to interrupt via the IRQ pin. - */ -register SIMODE1 { - address 0x011 - access_mode RW - field ENSELTIMO 0x80 - field ENATNTARG 0x40 - field ENSCSIRST 0x20 - field ENPHASEMIS 0x10 - field ENBUSFREE 0x08 - field ENSCSIPERR 0x04 - field ENPHASECHG 0x02 - field ENREQINIT 0x01 -} - -/* - * SCSI Data Bus (High) (p. 3-29) - * This register reads data on the SCSI Data bus directly. - */ -register SCSIBUSL { - address 0x012 - access_mode RW -} - -register SCSIBUSH { - address 0x013 - access_mode RW -} - -/* - * SCSI/Host Address (p. 3-30) - * These registers hold the host address for the byte about to be - * transferred on the SCSI bus. They are counted up in the same - * manner as STCNT is counted down. SHADDR should always be used - * to determine the address of the last byte transferred since HADDR - * can be skewed by write ahead. - */ -register SHADDR { - address 0x014 - size 4 - access_mode RO - dont_generate_debug_code -} - -/* - * Selection Timeout Timer (p. 3-30) - */ -register SELTIMER { - address 0x018 - access_mode RW - count 1 - field STAGE6 0x20 - field STAGE5 0x10 - field STAGE4 0x08 - field STAGE3 0x04 - field STAGE2 0x02 - field STAGE1 0x01 - alias TARGIDIN - dont_generate_debug_code -} - -/* - * Selection/Reselection ID (p. 3-31) - * Upper four bits are the device id. The ONEBIT is set when the re/selecting - * device did not set its own ID. - */ -register SELID { - address 0x019 - access_mode RW - mask SELID_MASK 0xf0 - field ONEBIT 0x08 - dont_generate_debug_code -} - -register SCAMCTL { - address 0x01a - access_mode RW - field ENSCAMSELO 0x80 - field CLRSCAMSELID 0x40 - field ALTSTIM 0x20 - field DFLTTID 0x10 - mask SCAMLVL 0x03 -} - -/* - * Target Mode Selecting in ID bitmask (aic7890/91/96/97) - */ -register TARGID { - address 0x01b - size 2 - access_mode RW - count 14 - dont_generate_debug_code -} - -/* - * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book) - * Indicates if external logic has been attached to the chip to - * perform the tasks of accessing a serial eeprom, testing termination - * strength, and performing cable detection. On the aic7860, most of - * these features are handled on chip, but on the aic7855 an attached - * aic3800 does the grunt work. - */ -register SPIOCAP { - address 0x01b - access_mode RW - count 10 - field SOFT1 0x80 - field SOFT0 0x40 - field SOFTCMDEN 0x20 - field EXT_BRDCTL 0x10 /* External Board control */ - field SEEPROM 0x08 /* External serial eeprom logic */ - field EEPROM 0x04 /* Writable external BIOS ROM */ - field ROM 0x02 /* Logic for accessing external ROM */ - field SSPIOCPS 0x01 /* Termination and cable detection */ - dont_generate_debug_code -} - -register BRDCTL { - address 0x01d - count 11 - field BRDDAT7 0x80 - field BRDDAT6 0x40 - field BRDDAT5 0x20 - field BRDSTB 0x10 - field BRDCS 0x08 - field BRDRW 0x04 - field BRDCTL1 0x02 - field BRDCTL0 0x01 - /* 7890 Definitions */ - field BRDDAT4 0x10 - field BRDDAT3 0x08 - field BRDDAT2 0x04 - field BRDRW_ULTRA2 0x02 - field BRDSTB_ULTRA2 0x01 - dont_generate_debug_code -} - -/* - * Serial EEPROM Control (p. 4-92 in 7870 Databook) - * Controls the reading and writing of an external serial 1-bit - * EEPROM Device. In order to access the serial EEPROM, you must - * first set the SEEMS bit that generates a request to the memory - * port for access to the serial EEPROM device. When the memory - * port is not busy servicing another request, it reconfigures - * to allow access to the serial EEPROM. When this happens, SEERDY - * gets set high to verify that the memory port access has been - * granted. - * - * After successful arbitration for the memory port, the SEECS bit of - * the SEECTL register is connected to the chip select. The SEECK, - * SEEDO, and SEEDI are connected to the clock, data out, and data in - * lines respectively. The SEERDY bit of SEECTL is useful in that it - * gives us an 800 nsec timer. After a write to the SEECTL register, - * the SEERDY goes high 800 nsec later. The one exception to this is - * when we first request access to the memory port. The SEERDY goes - * high to signify that access has been granted and, for this case, has - * no implied timing. - * - * See 93cx6.c for detailed information on the protocol necessary to - * read the serial EEPROM. - */ -register SEECTL { - address 0x01e - count 11 - field EXTARBACK 0x80 - field EXTARBREQ 0x40 - field SEEMS 0x20 - field SEERDY 0x10 - field SEECS 0x08 - field SEECK 0x04 - field SEEDO 0x02 - field SEEDI 0x01 - dont_generate_debug_code -} -/* - * SCSI Block Control (p. 3-32) - * Controls Bus type and channel selection. In a twin channel configuration - * addresses 0x00-0x1e are gated to the appropriate channel based on this - * register. SELWIDE allows for the coexistence of 8bit and 16bit devices - * on a wide bus. - */ -register SBLKCTL { - address 0x01f - access_mode RW - field DIAGLEDEN 0x80 /* Aic78X0 only */ - field DIAGLEDON 0x40 /* Aic78X0 only */ - field AUTOFLUSHDIS 0x20 - field SELBUSB 0x08 - field ENAB40 0x08 /* LVD transceiver active */ - field ENAB20 0x04 /* SE/HVD transceiver active */ - field SELWIDE 0x02 - field XCVR 0x01 /* External transceiver active */ -} - -/* - * Sequencer Control (p. 3-33) - * Error detection mode and speed configuration - */ -register SEQCTL { - address 0x060 - access_mode RW - count 15 - field PERRORDIS 0x80 - field PAUSEDIS 0x40 - field FAILDIS 0x20 - field FASTMODE 0x10 - field BRKADRINTEN 0x08 - field STEP 0x04 - field SEQRESET 0x02 - field LOADRAM 0x01 -} - -/* - * Sequencer RAM Data (p. 3-34) - * Single byte window into the Scratch Ram area starting at the address - * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write - * four bytes in succession. The SEQADDRs will increment after the most - * significant byte is written - */ -register SEQRAM { - address 0x061 - access_mode RW - count 2 - dont_generate_debug_code -} - -/* - * Sequencer Address Registers (p. 3-35) - * Only the first bit of SEQADDR1 holds addressing information - */ -register SEQADDR0 { - address 0x062 - access_mode RW - dont_generate_debug_code -} - -register SEQADDR1 { - address 0x063 - access_mode RW - count 8 - mask SEQADDR1_MASK 0x01 - dont_generate_debug_code -} - -/* - * Accumulator - * We cheat by passing arguments in the Accumulator up to the kernel driver - */ -register ACCUM { - address 0x064 - access_mode RW - accumulator - dont_generate_debug_code -} - -register SINDEX { - address 0x065 - access_mode RW - sindex - dont_generate_debug_code -} - -register DINDEX { - address 0x066 - access_mode RW - dont_generate_debug_code -} - -register ALLONES { - address 0x069 - access_mode RO - allones - dont_generate_debug_code -} - -register ALLZEROS { - address 0x06a - access_mode RO - allzeros - dont_generate_debug_code -} - -register NONE { - address 0x06a - access_mode WO - none - dont_generate_debug_code -} - -register FLAGS { - address 0x06b - access_mode RO - count 18 - field ZERO 0x02 - field CARRY 0x01 - dont_generate_debug_code -} - -register SINDIR { - address 0x06c - access_mode RO - dont_generate_debug_code -} - -register DINDIR { - address 0x06d - access_mode WO - dont_generate_debug_code -} - -register FUNCTION1 { - address 0x06e - access_mode RW -} - -register STACK { - address 0x06f - access_mode RO - count 5 - dont_generate_debug_code -} - -const STACK_SIZE 4 - -/* - * Board Control (p. 3-43) - */ -register BCTL { - address 0x084 - access_mode RW - field ACE 0x08 - field ENABLE 0x01 -} - -/* - * On the aic78X0 chips, Board Control is replaced by the DSCommand - * register (p. 4-64) - */ -register DSCOMMAND0 { - address 0x084 - access_mode RW - count 7 - field CACHETHEN 0x80 /* Cache Threshold enable */ - field DPARCKEN 0x40 /* Data Parity Check Enable */ - field MPARCKEN 0x20 /* Memory Parity Check Enable */ - field EXTREQLCK 0x10 /* External Request Lock */ - /* aic7890/91/96/97 only */ - field INTSCBRAMSEL 0x08 /* Internal SCB RAM Select */ - field RAMPS 0x04 /* External SCB RAM Present */ - field USCBSIZE32 0x02 /* Use 32byte SCB Page Size */ - field CIOPARCKEN 0x01 /* Internal bus parity error enable */ - dont_generate_debug_code -} - -register DSCOMMAND1 { - address 0x085 - access_mode RW - mask DSLATT 0xfc /* PCI latency timer (non-ultra2) */ - field HADDLDSEL1 0x02 /* Host Address Load Select Bits */ - field HADDLDSEL0 0x01 - dont_generate_debug_code -} - -/* - * Bus On/Off Time (p. 3-44) aic7770 only - */ -register BUSTIME { - address 0x085 - access_mode RW - count 2 - mask BOFF 0xf0 - mask BON 0x0f - dont_generate_debug_code -} - -/* - * Bus Speed (p. 3-45) aic7770 only - */ -register BUSSPD { - address 0x086 - access_mode RW - count 2 - mask DFTHRSH 0xc0 - mask STBOFF 0x38 - mask STBON 0x07 - mask DFTHRSH_100 0xc0 - mask DFTHRSH_75 0x80 - dont_generate_debug_code -} - -/* aic7850/55/60/70/80/95 only */ -register DSPCISTATUS { - address 0x086 - count 4 - mask DFTHRSH_100 0xc0 - dont_generate_debug_code -} - -/* aic7890/91/96/97 only */ -register HS_MAILBOX { - address 0x086 - mask HOST_MAILBOX 0xF0 - mask SEQ_MAILBOX 0x0F - mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */ - dont_generate_debug_code -} - -const HOST_MAILBOX_SHIFT 4 -const SEQ_MAILBOX_SHIFT 0 - -/* - * Host Control (p. 3-47) R/W - * Overall host control of the device. - */ -register HCNTRL { - address 0x087 - access_mode RW - count 14 - field POWRDN 0x40 - field SWINT 0x10 - field IRQMS 0x08 - field PAUSE 0x04 - field INTEN 0x02 - field CHIPRST 0x01 - field CHIPRSTACK 0x01 - dont_generate_debug_code -} - -/* - * Host Address (p. 3-48) - * This register contains the address of the byte about - * to be transferred across the host bus. - */ -register HADDR { - address 0x088 - size 4 - access_mode RW - dont_generate_debug_code -} - -register HCNT { - address 0x08c - size 3 - access_mode RW - dont_generate_debug_code -} - -/* - * SCB Pointer (p. 3-49) - * Gate one of the SCBs into the SCBARRAY window. - */ -register SCBPTR { - address 0x090 - access_mode RW - dont_generate_debug_code -} - -/* - * Interrupt Status (p. 3-50) - * Status for system interrupts - */ -register INTSTAT { - address 0x091 - access_mode RW - field BRKADRINT 0x08 - field SCSIINT 0x04 - field CMDCMPLT 0x02 - field SEQINT 0x01 - mask BAD_PHASE SEQINT /* unknown scsi bus phase */ - mask SEND_REJECT 0x10|SEQINT /* sending a message reject */ - mask PROTO_VIOLATION 0x20|SEQINT /* SCSI protocol violation */ - mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */ - mask IGN_WIDE_RES 0x40|SEQINT /* Complex IGN Wide Res Msg */ - mask PDATA_REINIT 0x50|SEQINT /* - * Returned to data phase - * that requires data - * transfer pointers to be - * recalculated from the - * transfer residual. - */ - mask HOST_MSG_LOOP 0x60|SEQINT /* - * The bus is ready for the - * host to perform another - * message transaction. This - * mechanism is used for things - * like sync/wide negotiation - * that require a kernel based - * message state engine. - */ - mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ - mask PERR_DETECTED 0x80|SEQINT /* - * Either the phase_lock - * or inb_next routine has - * noticed a parity error. - */ - mask DATA_OVERRUN 0x90|SEQINT /* - * Target attempted to write - * beyond the bounds of its - * command. - */ - mask MKMSG_FAILED 0xa0|SEQINT /* - * Target completed command - * without honoring our ATN - * request to issue a message. - */ - mask MISSED_BUSFREE 0xb0|SEQINT /* - * The sequencer never saw - * the bus go free after - * either a command complete - * or disconnect message. - */ - mask SCB_MISMATCH 0xc0|SEQINT /* - * Downloaded SCB's tag does - * not match the entry we - * intended to download. - */ - mask NO_FREE_SCB 0xd0|SEQINT /* - * get_free_or_disc_scb failed. - */ - mask OUT_OF_RANGE 0xe0|SEQINT - - mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */ - mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT) - dont_generate_debug_code -} - -/* - * Hard Error (p. 3-53) - * Reporting of catastrophic errors. You usually cannot recover from - * these without a full board reset. - */ -register ERROR { - address 0x092 - access_mode RO - count 26 - field CIOPARERR 0x80 /* Ultra2 only */ - field PCIERRSTAT 0x40 /* PCI only */ - field MPARERR 0x20 /* PCI only */ - field DPARERR 0x10 /* PCI only */ - field SQPARERR 0x08 - field ILLOPCODE 0x04 - field ILLSADDR 0x02 - field ILLHADDR 0x01 -} - -/* - * Clear Interrupt Status (p. 3-52) - */ -register CLRINT { - address 0x092 - access_mode WO - count 24 - field CLRPARERR 0x10 /* PCI only */ - field CLRBRKADRINT 0x08 - field CLRSCSIINT 0x04 - field CLRCMDINT 0x02 - field CLRSEQINT 0x01 - dont_generate_debug_code -} - -register DFCNTRL { - address 0x093 - access_mode RW - field PRELOADEN 0x80 /* aic7890 only */ - field WIDEODD 0x40 - field SCSIEN 0x20 - field SDMAEN 0x10 - field SDMAENACK 0x10 - field HDMAEN 0x08 - field HDMAENACK 0x08 - field DIRECTION 0x04 - field FIFOFLUSH 0x02 - field FIFORESET 0x01 -} - -register DFSTATUS { - address 0x094 - access_mode RO - field PRELOAD_AVAIL 0x80 - field DFCACHETH 0x40 - field FIFOQWDEMP 0x20 - field MREQPEND 0x10 - field HDONE 0x08 - field DFTHRESH 0x04 - field FIFOFULL 0x02 - field FIFOEMP 0x01 -} - -register DFWADDR { - address 0x95 - access_mode RW - dont_generate_debug_code -} - -register DFRADDR { - address 0x97 - access_mode RW -} - -register DFDAT { - address 0x099 - access_mode RW - dont_generate_debug_code -} - -/* - * SCB Auto Increment (p. 3-59) - * Byte offset into the SCB Array and an optional bit to allow auto - * incrementing of the address during download and upload operations - */ -register SCBCNT { - address 0x09a - access_mode RW - count 1 - field SCBAUTO 0x80 - mask SCBCNT_MASK 0x1f - dont_generate_debug_code -} - -/* - * Queue In FIFO (p. 3-60) - * Input queue for queued SCBs (commands that the seqencer has yet to start) - */ -register QINFIFO { - address 0x09b - access_mode RW - count 12 - dont_generate_debug_code -} - -/* - * Queue In Count (p. 3-60) - * Number of queued SCBs - */ -register QINCNT { - address 0x09c - access_mode RO -} - -/* - * Queue Out FIFO (p. 3-61) - * Queue of SCBs that have completed and await the host - */ -register QOUTFIFO { - address 0x09d - access_mode WO - count 7 - dont_generate_debug_code -} - -register CRCCONTROL1 { - address 0x09d - access_mode RW - count 3 - field CRCONSEEN 0x80 - field CRCVALCHKEN 0x40 - field CRCENDCHKEN 0x20 - field CRCREQCHKEN 0x10 - field TARGCRCENDEN 0x08 - field TARGCRCCNTEN 0x04 - dont_generate_debug_code -} - - -/* - * Queue Out Count (p. 3-61) - * Number of queued SCBs in the Out FIFO - */ -register QOUTCNT { - address 0x09e - access_mode RO -} - -register SCSIPHASE { - address 0x09e - access_mode RO - field STATUS_PHASE 0x20 - field COMMAND_PHASE 0x10 - field MSG_IN_PHASE 0x08 - field MSG_OUT_PHASE 0x04 - field DATA_IN_PHASE 0x02 - field DATA_OUT_PHASE 0x01 - mask DATA_PHASE_MASK 0x03 -} - -/* - * Special Function - */ -register SFUNCT { - address 0x09f - access_mode RW - count 4 - field ALT_MODE 0x80 - dont_generate_debug_code -} - -/* - * SCB Definition (p. 5-4) - */ -scb { - address 0x0a0 - size 64 - - SCB_CDB_PTR { - size 4 - alias SCB_RESIDUAL_DATACNT - alias SCB_CDB_STORE - dont_generate_debug_code - } - SCB_RESIDUAL_SGPTR { - size 4 - dont_generate_debug_code - } - SCB_SCSI_STATUS { - size 1 - dont_generate_debug_code - } - SCB_TARGET_PHASES { - size 1 - dont_generate_debug_code - } - SCB_TARGET_DATA_DIR { - size 1 - dont_generate_debug_code - } - SCB_TARGET_ITAG { - size 1 - dont_generate_debug_code - } - SCB_DATAPTR { - size 4 - dont_generate_debug_code - } - SCB_DATACNT { - /* - * The last byte is really the high address bits for - * the data address. - */ - size 4 - field SG_LAST_SEG 0x80 /* In the fourth byte */ - mask SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ - dont_generate_debug_code - } - SCB_SGPTR { - size 4 - field SG_RESID_VALID 0x04 /* In the first byte */ - field SG_FULL_RESID 0x02 /* In the first byte */ - field SG_LIST_NULL 0x01 /* In the first byte */ - dont_generate_debug_code - } - SCB_CONTROL { - size 1 - field TARGET_SCB 0x80 - field STATUS_RCVD 0x80 - field DISCENB 0x40 - field TAG_ENB 0x20 - field MK_MESSAGE 0x10 - field ULTRAENB 0x08 - field DISCONNECTED 0x04 - mask SCB_TAG_TYPE 0x03 - } - SCB_SCSIID { - size 1 - field TWIN_CHNLB 0x80 - mask TWIN_TID 0x70 - mask TID 0xf0 - mask OID 0x0f - } - SCB_LUN { - field SCB_XFERLEN_ODD 0x80 - mask LID 0x3f - size 1 - } - SCB_TAG { - size 1 - } - SCB_CDB_LEN { - size 1 - dont_generate_debug_code - } - SCB_SCSIRATE { - size 1 - dont_generate_debug_code - } - SCB_SCSIOFFSET { - size 1 - count 1 - dont_generate_debug_code - } - SCB_NEXT { - size 1 - dont_generate_debug_code - } - SCB_64_SPARE { - size 16 - } - SCB_64_BTT { - size 16 - dont_generate_debug_code - } -} - -const SCB_UPLOAD_SIZE 32 -const SCB_DOWNLOAD_SIZE 32 -const SCB_DOWNLOAD_SIZE_64 48 - -const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ - -/* --------------------- AHA-2840-only definitions -------------------- */ - -register SEECTL_2840 { - address 0x0c0 - access_mode RW - count 2 - field CS_2840 0x04 - field CK_2840 0x02 - field DO_2840 0x01 - dont_generate_debug_code -} - -register STATUS_2840 { - address 0x0c1 - access_mode RW - count 4 - field EEPROM_TF 0x80 - mask BIOS_SEL 0x60 - mask ADSEL 0x1e - field DI_2840 0x01 - dont_generate_debug_code -} - -/* --------------------- AIC-7870-only definitions -------------------- */ - -register CCHADDR { - address 0x0E0 - size 8 - dont_generate_debug_code -} - -register CCHCNT { - address 0x0E8 - dont_generate_debug_code -} - -register CCSGRAM { - address 0x0E9 - dont_generate_debug_code -} - -register CCSGADDR { - address 0x0EA - dont_generate_debug_code -} - -register CCSGCTL { - address 0x0EB - field CCSGDONE 0x80 - field CCSGEN 0x08 - field SG_FETCH_NEEDED 0x02 /* Bit used for software state */ - field CCSGRESET 0x01 - dont_generate_debug_code -} - -register CCSCBCNT { - address 0xEF - count 1 - dont_generate_debug_code -} - -register CCSCBCTL { - address 0x0EE - field CCSCBDONE 0x80 - field ARRDONE 0x40 /* SCB Array prefetch done */ - field CCARREN 0x10 - field CCSCBEN 0x08 - field CCSCBDIR 0x04 - field CCSCBRESET 0x01 - dont_generate_debug_code -} - -register CCSCBADDR { - address 0x0ED - dont_generate_debug_code -} - -register CCSCBRAM { - address 0xEC - dont_generate_debug_code -} - -/* - * SCB bank address (7895/7896/97 only) - */ -register SCBBADDR { - address 0x0F0 - access_mode RW - count 3 - dont_generate_debug_code -} - -register CCSCBPTR { - address 0x0F1 - dont_generate_debug_code -} - -register HNSCB_QOFF { - address 0x0F4 - count 4 - dont_generate_debug_code -} - -register SNSCB_QOFF { - address 0x0F6 - dont_generate_debug_code -} - -register SDSCB_QOFF { - address 0x0F8 - dont_generate_debug_code -} - -register QOFF_CTLSTA { - address 0x0FA - field SCB_AVAIL 0x40 - field SNSCB_ROLLOVER 0x20 - field SDSCB_ROLLOVER 0x10 - mask SCB_QSIZE 0x07 - mask SCB_QSIZE_256 0x06 - dont_generate_debug_code -} - -register DFF_THRSH { - address 0x0FB - mask WR_DFTHRSH 0x70 - mask RD_DFTHRSH 0x07 - mask RD_DFTHRSH_MIN 0x00 - mask RD_DFTHRSH_25 0x01 - mask RD_DFTHRSH_50 0x02 - mask RD_DFTHRSH_63 0x03 - mask RD_DFTHRSH_75 0x04 - mask RD_DFTHRSH_85 0x05 - mask RD_DFTHRSH_90 0x06 - mask RD_DFTHRSH_MAX 0x07 - mask WR_DFTHRSH_MIN 0x00 - mask WR_DFTHRSH_25 0x10 - mask WR_DFTHRSH_50 0x20 - mask WR_DFTHRSH_63 0x30 - mask WR_DFTHRSH_75 0x40 - mask WR_DFTHRSH_85 0x50 - mask WR_DFTHRSH_90 0x60 - mask WR_DFTHRSH_MAX 0x70 - count 4 - dont_generate_debug_code -} - -register SG_CACHE_PRE { - access_mode WO - address 0x0fc - mask SG_ADDR_MASK 0xf8 - field LAST_SEG 0x02 - field LAST_SEG_DONE 0x01 - dont_generate_debug_code -} - -register SG_CACHE_SHADOW { - access_mode RO - address 0x0fc - mask SG_ADDR_MASK 0xf8 - field LAST_SEG 0x02 - field LAST_SEG_DONE 0x01 - dont_generate_debug_code -} -/* ---------------------- Scratch RAM Offsets ------------------------- */ -/* These offsets are either to values that are initialized by the board's - * BIOS or are specified by the sequencer code. - * - * The host adapter card (at least the BIOS) uses 20-2f for SCSI - * device information, 32-33 and 5a-5f as well. As it turns out, the - * BIOS trashes 20-2f, writing the synchronous negotiation results - * on top of the BIOS values, so we re-use those for our per-target - * scratchspace (actually a value that can be copied directly into - * SCSIRATE). The kernel driver will enable synchronous negotiation - * for all targets that have a value other than 0 in the lower four - * bits of the target scratch space. This should work regardless of - * whether the bios has been installed. - */ - -scratch_ram { - address 0x020 - size 58 - - /* - * 1 byte per target starting at this address for configuration values - */ - BUSY_TARGETS { - alias TARG_SCSIRATE - size 16 - dont_generate_debug_code - } - /* - * Bit vector of targets that have ULTRA enabled as set by - * the BIOS. The Sequencer relies on a per-SCB field to - * control whether to enable Ultra transfers or not. During - * initialization, we read this field and reuse it for 2 - * entries in the busy target table. - */ - ULTRA_ENB { - alias CMDSIZE_TABLE - size 2 - count 2 - dont_generate_debug_code - } - /* - * Bit vector of targets that have disconnection disabled as set by - * the BIOS. The Sequencer relies in a per-SCB field to control the - * disconnect priveldge. During initialization, we read this field - * and reuse it for 2 entries in the busy target table. - */ - DISC_DSB { - size 2 - count 6 - dont_generate_debug_code - } - CMDSIZE_TABLE_TAIL { - size 4 - } - /* - * Partial transfer past cacheline end to be - * transferred using an extra S/G. - */ - MWI_RESIDUAL { - size 1 - dont_generate_debug_code - } - /* - * SCBID of the next SCB to be started by the controller. - */ - NEXT_QUEUED_SCB { - size 1 - dont_generate_debug_code - } - /* - * Single byte buffer used to designate the type or message - * to send to a target. - */ - MSG_OUT { - size 1 - dont_generate_debug_code - } - /* Parameters for DMA Logic */ - DMAPARAMS { - size 1 - count 12 - field PRELOADEN 0x80 - field WIDEODD 0x40 - field SCSIEN 0x20 - field SDMAEN 0x10 - field SDMAENACK 0x10 - field HDMAEN 0x08 - field HDMAENACK 0x08 - field DIRECTION 0x04 /* Set indicates PCI->SCSI */ - field FIFOFLUSH 0x02 - field FIFORESET 0x01 - dont_generate_debug_code - } - SEQ_FLAGS { - size 1 - field NOT_IDENTIFIED 0x80 - field NO_CDB_SENT 0x40 - field TARGET_CMD_IS_TAGGED 0x40 - field DPHASE 0x20 - /* Target flags */ - field TARG_CMD_PENDING 0x10 - field CMDPHASE_PENDING 0x08 - field DPHASE_PENDING 0x04 - field SPHASE_PENDING 0x02 - field NO_DISCONNECT 0x01 - } - /* - * Temporary storage for the - * target/channel/lun of a - * reconnecting target - */ - SAVED_SCSIID { - size 1 - dont_generate_debug_code - } - SAVED_LUN { - size 1 - dont_generate_debug_code - } - /* - * The last bus phase as seen by the sequencer. - */ - LASTPHASE { - size 1 - field CDI 0x80 - field IOI 0x40 - field MSGI 0x20 - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI - mask P_BUSFREE 0x01 - } - /* - * head of list of SCBs awaiting - * selection - */ - WAITING_SCBH { - size 1 - dont_generate_debug_code - } - /* - * head of list of SCBs that are - * disconnected. Used for SCB - * paging. - */ - DISCONNECTED_SCBH { - size 1 - dont_generate_debug_code - } - /* - * head of list of SCBs that are - * not in use. Used for SCB paging. - */ - FREE_SCBH { - size 1 - dont_generate_debug_code - } - /* - * head of list of SCBs that have - * completed but have not been - * put into the qoutfifo. - */ - COMPLETE_SCBH { - size 1 - } - /* - * Address of the hardware scb array in the host. - */ - HSCB_ADDR { - size 4 - dont_generate_debug_code - } - /* - * Base address of our shared data with the kernel driver in host - * memory. This includes the qoutfifo and target mode - * incoming command queue. - */ - SHARED_DATA_ADDR { - size 4 - dont_generate_debug_code - } - KERNEL_QINPOS { - size 1 - dont_generate_debug_code - } - QINPOS { - size 1 - dont_generate_debug_code - } - QOUTPOS { - size 1 - dont_generate_debug_code - } - /* - * Kernel and sequencer offsets into the queue of - * incoming target mode command descriptors. The - * queue is full when the KERNEL_TQINPOS == TQINPOS. - */ - KERNEL_TQINPOS { - size 1 - dont_generate_debug_code - } - TQINPOS { - size 1 - dont_generate_debug_code - } - ARG_1 { - size 1 - count 1 - mask SEND_MSG 0x80 - mask SEND_SENSE 0x40 - mask SEND_REJ 0x20 - mask MSGOUT_PHASEMIS 0x10 - mask EXIT_MSG_LOOP 0x08 - mask CONT_MSG_LOOP 0x04 - mask CONT_TARG_SESSION 0x02 - alias RETURN_1 - dont_generate_debug_code - } - ARG_2 { - size 1 - alias RETURN_2 - dont_generate_debug_code - } - - /* - * Snapshot of MSG_OUT taken after each message is sent. - */ - LAST_MSG { - size 1 - alias TARG_IMMEDIATE_SCB - dont_generate_debug_code - } - - /* - * Sequences the kernel driver has okayed for us. This allows - * the driver to do things like prevent initiator or target - * operations. - */ - SCSISEQ_TEMPLATE { - size 1 - field ENSELO 0x40 - field ENSELI 0x20 - field ENRSELI 0x10 - field ENAUTOATNO 0x08 - field ENAUTOATNI 0x04 - field ENAUTOATNP 0x02 - dont_generate_debug_code - } -} - -scratch_ram { - address 0x056 - size 4 - /* - * These scratch ram locations are initialized by the 274X BIOS. - * We reuse them after capturing the BIOS settings during - * initialization. - */ - - /* - * The initiator specified tag for this target mode transaction. - */ - HA_274_BIOSGLOBAL { - size 1 - field HA_274_EXTENDED_TRANS 0x01 - alias INITIATOR_TAG - count 1 - dont_generate_debug_code - } - - SEQ_FLAGS2 { - size 1 - field SCB_DMA 0x01 - field TARGET_MSG_PENDING 0x02 - dont_generate_debug_code - } -} - -scratch_ram { - address 0x05a - size 6 - /* - * These are reserved registers in the card's scratch ram on the 2742. - * The EISA configuraiton chip is mapped here. On Rev E. of the - * aic7770, the sequencer can use this area for scratch, but the - * host cannot directly access these registers. On later chips, this - * area can be read and written by both the host and the sequencer. - * Even on later chips, many of these locations are initialized by - * the BIOS. - */ - SCSICONF { - size 1 - count 12 - field TERM_ENB 0x80 - field RESET_SCSI 0x40 - field ENSPCHK 0x20 - mask HSCSIID 0x07 /* our SCSI ID */ - mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ - dont_generate_debug_code - } - INTDEF { - address 0x05c - size 1 - count 1 - field EDGE_TRIG 0x80 - mask VECTOR 0x0f - dont_generate_debug_code - } - HOSTCONF { - address 0x05d - size 1 - count 1 - dont_generate_debug_code - } - HA_274_BIOSCTRL { - address 0x05f - size 1 - count 1 - mask BIOSMODE 0x30 - mask BIOSDISABLED 0x30 - field CHANNEL_B_PRIMARY 0x08 - dont_generate_debug_code - } -} - -scratch_ram { - address 0x070 - size 16 - - /* - * Per target SCSI offset values for Ultra2 controllers. - */ - TARG_OFFSET { - size 16 - count 1 - dont_generate_debug_code - } -} - -const TID_SHIFT 4 -const SCB_LIST_NULL 0xff -const TARGET_CMD_CMPLT 0xfe - -const CCSGADDR_MAX 0x80 -const CCSGRAM_MAXSEGS 16 - -/* WDTR Message values */ -const BUS_8_BIT 0x00 -const BUS_16_BIT 0x01 -const BUS_32_BIT 0x02 - -/* Offset maximums */ -const MAX_OFFSET_8BIT 0x0f -const MAX_OFFSET_16BIT 0x08 -const MAX_OFFSET_ULTRA2 0x7f -const MAX_OFFSET 0x7f -const HOST_MSG 0xff - -/* Target mode command processing constants */ -const CMD_GROUP_CODE_SHIFT 0x05 - -const STATUS_BUSY 0x08 -const STATUS_QUEUE_FULL 0x28 -const TARGET_DATA_IN 1 - -/* - * Downloaded (kernel inserted) constants - */ -/* Offsets into the SCBID array where different data is stored */ -const QOUTFIFO_OFFSET download -const QINFIFO_OFFSET download -const CACHESIZE_MASK download -const INVERTED_CACHESIZE_MASK download -const SG_PREFETCH_CNT download -const SG_PREFETCH_ALIGN_MASK download -const SG_PREFETCH_ADDR_MASK download diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.seq b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.seq deleted file mode 100644 index e60041e8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx.seq +++ /dev/null @@ -1,2399 +0,0 @@ -/* - * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. - * - * Copyright (c) 1994-2001 Justin T. Gibbs. - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $FreeBSD$ - */ - -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $" -PATCH_ARG_LIST = "struct ahc_softc *ahc" -PREFIX = "ahc_" - -#include "aic7xxx.reg" -#include "scsi_message.h" - -/* - * A few words on the waiting SCB list: - * After starting the selection hardware, we check for reconnecting targets - * as well as for our selection to complete just in case the reselection wins - * bus arbitration. The problem with this is that we must keep track of the - * SCB that we've already pulled from the QINFIFO and started the selection - * on just in case the reselection wins so that we can retry the selection at - * a later time. This problem cannot be resolved by holding a single entry - * in scratch ram since a reconnecting target can request sense and this will - * create yet another SCB waiting for selection. The solution used here is to - * use byte 27 of the SCB as a pseudo-next pointer and to thread a list - * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, - * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to - * this list every time a request sense occurs or after completing a non-tagged - * command for which a second SCB has been queued. The sequencer will - * automatically consume the entries. - */ - -bus_free_sel: - /* - * Turn off the selection hardware. We need to reset the - * selection request in order to perform a new selection. - */ - and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP; - and SIMODE1, ~ENBUSFREE; -poll_for_work: - call clear_target_state; - and SXFRCTL0, ~SPIOEN; - if ((ahc->features & AHC_ULTRA2) != 0) { - clr SCSIBUSL; - } - test SCSISEQ, ENSELO jnz poll_for_selection; - if ((ahc->features & AHC_TWIN) != 0) { - xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ - test SCSISEQ, ENSELO jnz poll_for_selection; - } - cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; -poll_for_work_loop: - if ((ahc->features & AHC_TWIN) != 0) { - xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ - } - test SSTAT0, SELDO|SELDI jnz selection; -test_queue: - /* Has the driver posted any work for us? */ -BEGIN_CRITICAL; - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; - } else { - mov A, QINPOS; - cmp KERNEL_QINPOS, A je poll_for_work_loop; - } - mov ARG_1, NEXT_QUEUED_SCB; - - /* - * We have at least one queued SCB now and we don't have any - * SCBs in the list of SCBs awaiting selection. Allocate a - * card SCB for the host's SCB and get to work on it. - */ - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov ALLZEROS call get_free_or_disc_scb; - } else { - /* In the non-paging case, the SCBID == hardware SCB index */ - mov SCBPTR, ARG_1; - } - or SEQ_FLAGS2, SCB_DMA; -END_CRITICAL; -dma_queued_scb: - /* - * DMA the SCB from host ram into the current SCB location. - */ - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov ARG_1 call dma_scb; - /* - * Check one last time to see if this SCB was canceled - * before we completed the DMA operation. If it was, - * the QINFIFO next pointer will not match our saved - * value. - */ - mov A, ARG_1; -BEGIN_CRITICAL; - cmp NEXT_QUEUED_SCB, A jne abort_qinscb; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - cmp SCB_TAG, A je . + 2; - mvi SCB_MISMATCH call set_seqint; - } - mov NEXT_QUEUED_SCB, SCB_NEXT; - mov SCB_NEXT,WAITING_SCBH; - mov WAITING_SCBH, SCBPTR; - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - mov NONE, SNSCB_QOFF; - } else { - inc QINPOS; - } - and SEQ_FLAGS2, ~SCB_DMA; -END_CRITICAL; -start_waiting: - /* - * Start the first entry on the waiting SCB list. - */ - mov SCBPTR, WAITING_SCBH; - call start_selection; - -poll_for_selection: - /* - * Twin channel devices cannot handle things like SELTO - * interrupts on the "background" channel. So, while - * selecting, keep polling the current channel until - * either a selection or reselection occurs. - */ - test SSTAT0, SELDO|SELDI jz poll_for_selection; - -selection: - /* - * We aren't expecting a bus free, so interrupt - * the kernel driver if it happens. - */ - mvi CLRSINT1,CLRBUSFREE; - if ((ahc->features & AHC_DT) == 0) { - or SIMODE1, ENBUSFREE; - } - - /* - * Guard against a bus free after (re)selection - * but prior to enabling the busfree interrupt. SELDI - * and SELDO will be cleared in that case. - */ - test SSTAT0, SELDI|SELDO jz bus_free_sel; - test SSTAT0,SELDO jnz select_out; -select_in: - if ((ahc->flags & AHC_TARGETROLE) != 0) { - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT0, TARGET jz initiator_reselect; - } - mvi CLRSINT0, CLRSELDI; - - /* - * We've just been selected. Assert BSY and - * setup the phase for receiving messages - * from the target. - */ - mvi SCSISIGO, P_MESGOUT|BSYO; - - /* - * Setup the DMA for sending the identify and - * command information. - */ - mvi SEQ_FLAGS, CMDPHASE_PENDING; - - mov A, TQINPOS; - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi SHARED_DATA_ADDR call set_32byte_addr; - mvi CCSCBCTL, CCSCBRESET; - } else { - mvi DINDEX, HADDR; - mvi SHARED_DATA_ADDR call set_32byte_addr; - mvi DFCNTRL, FIFORESET; - } - - /* Initiator that selected us */ - and SAVED_SCSIID, SELID_MASK, SELID; - /* The Target ID we were selected at */ - if ((ahc->features & AHC_MULTI_TID) != 0) { - and A, OID, TARGIDIN; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - and A, OID, SCSIID_ULTRA2; - } else { - and A, OID, SCSIID; - } - or SAVED_SCSIID, A; - if ((ahc->features & AHC_TWIN) != 0) { - test SBLKCTL, SELBUSB jz . + 2; - or SAVED_SCSIID, TWIN_CHNLB; - } - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mov CCSCBRAM, SAVED_SCSIID; - } else { - mov DFDAT, SAVED_SCSIID; - } - - /* - * If ATN isn't asserted, the target isn't interested - * in talking to us. Go directly to bus free. - * XXX SCSI-1 may require us to assume lun 0 if - * ATN is false. - */ - test SCSISIGI, ATNI jz target_busfree; - - /* - * Watch ATN closely now as we pull in messages from the - * initiator. We follow the guidlines from section 6.5 - * of the SCSI-2 spec for what messages are allowed when. - */ - call target_inb; - - /* - * Our first message must be one of IDENTIFY, ABORT, or - * BUS_DEVICE_RESET. - */ - test DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop; - /* Store for host */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mov CCSCBRAM, DINDEX; - } else { - mov DFDAT, DINDEX; - } - and SAVED_LUN, MSG_IDENTIFY_LUNMASK, DINDEX; - - /* Remember for disconnection decision */ - test DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2; - /* XXX Honor per target settings too */ - or SEQ_FLAGS, NO_DISCONNECT; - - test SCSISIGI, ATNI jz ident_messages_done; - call target_inb; - /* - * If this is a tagged request, the tagged message must - * immediately follow the identify. We test for a valid - * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and - * < MSG_IGN_WIDE_RESIDUE. - */ - add A, -MSG_SIMPLE_Q_TAG, DINDEX; - jnc ident_messages_done_msg_pending; - add A, -MSG_IGN_WIDE_RESIDUE, DINDEX; - jc ident_messages_done_msg_pending; - - /* Store for host */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mov CCSCBRAM, DINDEX; - } else { - mov DFDAT, DINDEX; - } - - /* - * If the initiator doesn't feel like providing a tag number, - * we've got a failed selection and must transition to bus - * free. - */ - test SCSISIGI, ATNI jz target_busfree; - - /* - * Store the tag for the host. - */ - call target_inb; - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mov CCSCBRAM, DINDEX; - } else { - mov DFDAT, DINDEX; - } - mov INITIATOR_TAG, DINDEX; - or SEQ_FLAGS, TARGET_CMD_IS_TAGGED; - -ident_messages_done: - /* Terminate the ident list */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mvi CCSCBRAM, SCB_LIST_NULL; - } else { - mvi DFDAT, SCB_LIST_NULL; - } - or SEQ_FLAGS, TARG_CMD_PENDING; - test SEQ_FLAGS2, TARGET_MSG_PENDING - jnz target_mesgout_pending; - test SCSISIGI, ATNI jnz target_mesgout_continue; - jmp target_ITloop; - - -ident_messages_done_msg_pending: - or SEQ_FLAGS2, TARGET_MSG_PENDING; - jmp ident_messages_done; - - /* - * Pushed message loop to allow the kernel to - * run it's own target mode message state engine. - */ -host_target_message_loop: - mvi HOST_MSG_LOOP call set_seqint; - cmp RETURN_1, EXIT_MSG_LOOP je target_ITloop; - test SSTAT0, SPIORDY jz .; - jmp host_target_message_loop; - } - -if ((ahc->flags & AHC_INITIATORROLE) != 0) { -/* - * Reselection has been initiated by a target. Make a note that we've been - * reselected, but haven't seen an IDENTIFY message from the target yet. - */ -initiator_reselect: - /* XXX test for and handle ONE BIT condition */ - or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; - and SAVED_SCSIID, SELID_MASK, SELID; - if ((ahc->features & AHC_ULTRA2) != 0) { - and A, OID, SCSIID_ULTRA2; - } else { - and A, OID, SCSIID; - } - or SAVED_SCSIID, A; - if ((ahc->features & AHC_TWIN) != 0) { - test SBLKCTL, SELBUSB jz . + 2; - or SAVED_SCSIID, TWIN_CHNLB; - } - mvi CLRSINT0, CLRSELDI; - jmp ITloop; -} - -abort_qinscb: - call add_scb_to_free_list; - jmp poll_for_work_loop; - -start_selection: - /* - * If bus reset interrupts have been disabled (from a previous - * reset), re-enable them now. Resets are only of interest - * when we have outstanding transactions, so we can safely - * defer re-enabling the interrupt until, as an initiator, - * we start sending out transactions again. - */ - test SIMODE1, ENSCSIRST jnz . + 3; - mvi CLRSINT1, CLRSCSIRSTI; - or SIMODE1, ENSCSIRST; - if ((ahc->features & AHC_TWIN) != 0) { - and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ - test SCB_SCSIID, TWIN_CHNLB jz . + 2; - or SINDEX, SELBUSB; - mov SBLKCTL,SINDEX; /* select channel */ - } -initialize_scsiid: - if ((ahc->features & AHC_ULTRA2) != 0) { - mov SCSIID_ULTRA2, SCB_SCSIID; - } else if ((ahc->features & AHC_TWIN) != 0) { - and SCSIID, TWIN_TID|OID, SCB_SCSIID; - } else { - mov SCSIID, SCB_SCSIID; - } - if ((ahc->flags & AHC_TARGETROLE) != 0) { - mov SINDEX, SCSISEQ_TEMPLATE; - test SCB_CONTROL, TARGET_SCB jz . + 2; - or SINDEX, TEMODE; - mov SCSISEQ, SINDEX ret; - } else { - mov SCSISEQ, SCSISEQ_TEMPLATE ret; - } - -/* - * Initialize transfer settings with SCB provided settings. - */ -set_transfer_settings: - if ((ahc->features & AHC_ULTRA) != 0) { - test SCB_CONTROL, ULTRAENB jz . + 2; - or SXFRCTL0, FAST20; - } - /* - * Initialize SCSIRATE with the appropriate value for this target. - */ - if ((ahc->features & AHC_ULTRA2) != 0) { - bmov SCSIRATE, SCB_SCSIRATE, 2 ret; - } else { - mov SCSIRATE, SCB_SCSIRATE ret; - } - -if ((ahc->flags & AHC_TARGETROLE) != 0) { -/* - * We carefully toggle SPIOEN to allow us to return the - * message byte we receive so it can be checked prior to - * driving REQ on the bus for the next byte. - */ -target_inb: - /* - * Drive REQ on the bus by enabling SCSI PIO. - */ - or SXFRCTL0, SPIOEN; - /* Wait for the byte */ - test SSTAT0, SPIORDY jz .; - /* Prevent our read from triggering another REQ */ - and SXFRCTL0, ~SPIOEN; - /* Save latched contents */ - mov DINDEX, SCSIDATL ret; -} - -/* - * After the selection, remove this SCB from the "waiting SCB" - * list. This is achieved by simply moving our "next" pointer into - * WAITING_SCBH. Our next pointer will be set to null the next time this - * SCB is used, so don't bother with it now. - */ -select_out: - /* Turn off the selection hardware */ - and SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ; - mov SCBPTR, WAITING_SCBH; - mov WAITING_SCBH,SCB_NEXT; - mov SAVED_SCSIID, SCB_SCSIID; - and SAVED_LUN, LID, SCB_LUN; - call set_transfer_settings; - if ((ahc->flags & AHC_TARGETROLE) != 0) { - test SSTAT0, TARGET jz initiator_select; - - or SXFRCTL0, CLRSTCNT|CLRCHN; - - /* - * Put tag in connonical location since not - * all connections have an SCB. - */ - mov INITIATOR_TAG, SCB_TARGET_ITAG; - - /* - * We've just re-selected an initiator. - * Assert BSY and setup the phase for - * sending our identify messages. - */ - mvi P_MESGIN|BSYO call change_phase; - mvi CLRSINT0, CLRSELDO; - - /* - * Start out with a simple identify message. - */ - or SAVED_LUN, MSG_IDENTIFYFLAG call target_outb; - - /* - * If we are the result of a tagged command, send - * a simple Q tag and the tag id. - */ - test SCB_CONTROL, TAG_ENB jz . + 3; - mvi MSG_SIMPLE_Q_TAG call target_outb; - mov SCB_TARGET_ITAG call target_outb; -target_synccmd: - /* - * Now determine what phases the host wants us - * to go through. - */ - mov SEQ_FLAGS, SCB_TARGET_PHASES; - - test SCB_CONTROL, MK_MESSAGE jz target_ITloop; - mvi P_MESGIN|BSYO call change_phase; - jmp host_target_message_loop; -target_ITloop: - /* - * Start honoring ATN signals now that - * we properly identified ourselves. - */ - test SCSISIGI, ATNI jnz target_mesgout; - test SEQ_FLAGS, CMDPHASE_PENDING jnz target_cmdphase; - test SEQ_FLAGS, DPHASE_PENDING jnz target_dphase; - test SEQ_FLAGS, SPHASE_PENDING jnz target_sphase; - - /* - * No more work to do. Either disconnect or not depending - * on the state of NO_DISCONNECT. - */ - test SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; - mvi TARG_IMMEDIATE_SCB, SCB_LIST_NULL; - call complete_target_cmd; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov ALLZEROS call get_free_or_disc_scb; - } - cmp TARG_IMMEDIATE_SCB, SCB_LIST_NULL je .; - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov TARG_IMMEDIATE_SCB call dma_scb; - call set_transfer_settings; - or SXFRCTL0, CLRSTCNT|CLRCHN; - jmp target_synccmd; - -target_mesgout: - mvi SCSISIGO, P_MESGOUT|BSYO; -target_mesgout_continue: - call target_inb; -target_mesgout_pending: - and SEQ_FLAGS2, ~TARGET_MSG_PENDING; - /* Local Processing goes here... */ - jmp host_target_message_loop; - -target_disconnect: - mvi P_MESGIN|BSYO call change_phase; - test SEQ_FLAGS, DPHASE jz . + 2; - mvi MSG_SAVEDATAPOINTER call target_outb; - mvi MSG_DISCONNECT call target_outb; - -target_busfree_wait: - /* Wait for preceding I/O session to complete. */ - test SCSISIGI, ACKI jnz .; -target_busfree: - and SIMODE1, ~ENBUSFREE; - if ((ahc->features & AHC_ULTRA2) != 0) { - clr SCSIBUSL; - } - clr SCSISIGO; - mvi LASTPHASE, P_BUSFREE; - call complete_target_cmd; - jmp poll_for_work; - -target_cmdphase: - /* - * The target has dropped ATN (doesn't want to abort or BDR) - * and we believe this selection to be valid. If the ring - * buffer for new commands is full, return busy or queue full. - */ - if ((ahc->features & AHC_HS_MAILBOX) != 0) { - and A, HOST_TQINPOS, HS_MAILBOX; - } else { - mov A, KERNEL_TQINPOS; - } - cmp TQINPOS, A jne tqinfifo_has_space; - mvi P_STATUS|BSYO call change_phase; - test SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3; - mvi STATUS_QUEUE_FULL call target_outb; - jmp target_busfree_wait; - mvi STATUS_BUSY call target_outb; - jmp target_busfree_wait; -tqinfifo_has_space: - mvi P_COMMAND|BSYO call change_phase; - call target_inb; - mov A, DINDEX; - /* Store for host */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mov CCSCBRAM, A; - } else { - mov DFDAT, A; - } - - /* - * Determine the number of bytes to read - * based on the command group code via table lookup. - * We reuse the first 8 bytes of the TARG_SCSIRATE - * BIOS array for this table. Count is one less than - * the total for the command since we've already fetched - * the first byte. - */ - shr A, CMD_GROUP_CODE_SHIFT; - add SINDEX, CMDSIZE_TABLE, A; - mov A, SINDIR; - - test A, 0xFF jz command_phase_done; - or SXFRCTL0, SPIOEN; -command_loop: - test SSTAT0, SPIORDY jz .; - cmp A, 1 jne . + 2; - and SXFRCTL0, ~SPIOEN; /* Last Byte */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mov CCSCBRAM, SCSIDATL; - } else { - mov DFDAT, SCSIDATL; - } - dec A; - test A, 0xFF jnz command_loop; - -command_phase_done: - and SEQ_FLAGS, ~CMDPHASE_PENDING; - jmp target_ITloop; - -target_dphase: - /* - * Data phases on the bus are from the - * perspective of the initiator. The dma - * code looks at LASTPHASE to determine the - * data direction of the DMA. Toggle it for - * target transfers. - */ - xor LASTPHASE, IOI, SCB_TARGET_DATA_DIR; - or SCB_TARGET_DATA_DIR, BSYO call change_phase; - jmp p_data; - -target_sphase: - mvi P_STATUS|BSYO call change_phase; - mvi LASTPHASE, P_STATUS; - mov SCB_SCSI_STATUS call target_outb; - /* XXX Watch for ATN or parity errors??? */ - mvi SCSISIGO, P_MESGIN|BSYO; - /* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */ - mov ALLZEROS call target_outb; - jmp target_busfree_wait; - -complete_target_cmd: - test SEQ_FLAGS, TARG_CMD_PENDING jnz . + 2; - mov SCB_TAG jmp complete_post; - if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* Set the valid byte */ - mvi CCSCBADDR, 24; - mov CCSCBRAM, ALLONES; - mvi CCHCNT, 28; - or CCSCBCTL, CCSCBEN|CCSCBRESET; - test CCSCBCTL, CCSCBDONE jz .; - clr CCSCBCTL; - } else { - /* Set the valid byte */ - or DFCNTRL, FIFORESET; - mvi DFWADDR, 3; /* Third 64bit word or byte 24 */ - mov DFDAT, ALLONES; - mvi 28 call set_hcnt; - or DFCNTRL, HDMAEN|FIFOFLUSH; - call dma_finish; - } - inc TQINPOS; - mvi INTSTAT,CMDCMPLT ret; - } - -if ((ahc->flags & AHC_INITIATORROLE) != 0) { -initiator_select: - or SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN; - /* - * As soon as we get a successful selection, the target - * should go into the message out phase since we have ATN - * asserted. - */ - mvi MSG_OUT, MSG_IDENTIFYFLAG; - mvi SEQ_FLAGS, NO_CDB_SENT; - mvi CLRSINT0, CLRSELDO; - - /* - * Main loop for information transfer phases. Wait for the - * target to assert REQ before checking MSG, C/D and I/O for - * the bus phase. - */ -mesgin_phasemis: -ITloop: - call phase_lock; - - mov A, LASTPHASE; - - test A, ~P_DATAIN jz p_data; - cmp A,P_COMMAND je p_command; - cmp A,P_MESGOUT je p_mesgout; - cmp A,P_STATUS je p_status; - cmp A,P_MESGIN je p_mesgin; - - mvi BAD_PHASE call set_seqint; - jmp ITloop; /* Try reading the bus again. */ - -await_busfree: - and SIMODE1, ~ENBUSFREE; - mov NONE, SCSIDATL; /* Ack the last byte */ - if ((ahc->features & AHC_ULTRA2) != 0) { - clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ - } - and SXFRCTL0, ~SPIOEN; - mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT; - test SSTAT1,REQINIT|BUSFREE jz .; - test SSTAT1, BUSFREE jnz poll_for_work; - mvi MISSED_BUSFREE call set_seqint; -} - -clear_target_state: - /* - * We assume that the kernel driver may reset us - * at any time, even in the middle of a DMA, so - * clear DFCNTRL too. - */ - clr DFCNTRL; - or SXFRCTL0, CLRSTCNT|CLRCHN; - - /* - * We don't know the target we will connect to, - * so default to narrow transfers to avoid - * parity problems. - */ - if ((ahc->features & AHC_ULTRA2) != 0) { - bmov SCSIRATE, ALLZEROS, 2; - } else { - clr SCSIRATE; - if ((ahc->features & AHC_ULTRA) != 0) { - and SXFRCTL0, ~(FAST20); - } - } - mvi LASTPHASE, P_BUSFREE; - /* clear target specific flags */ - mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret; - -sg_advance: - clr A; /* add sizeof(struct scatter) */ - add SCB_RESIDUAL_SGPTR[0],SG_SIZEOF; - adc SCB_RESIDUAL_SGPTR[1],A; - adc SCB_RESIDUAL_SGPTR[2],A; - adc SCB_RESIDUAL_SGPTR[3],A ret; - -if ((ahc->features & AHC_CMD_CHAN) != 0) { -disable_ccsgen: - test CCSGCTL, CCSGEN jz return; - test CCSGCTL, CCSGDONE jz .; -disable_ccsgen_fetch_done: - clr CCSGCTL; - test CCSGCTL, CCSGEN jnz .; - ret; -idle_loop: - /* - * Do we need any more segments for this transfer? - */ - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return; - - /* Did we just finish fetching segs? */ - cmp CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete; - - /* Are we actively fetching segments? */ - test CCSGCTL, CCSGEN jnz return; - - /* - * Do we have any prefetch left??? - */ - cmp CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail; - - /* - * Need to fetch segments, but we can only do that - * if the command channel is completely idle. Make - * sure we don't have an SCB prefetch going on. - */ - test CCSCBCTL, CCSCBEN jnz return; - - /* - * We fetch a "cacheline aligned" and sized amount of data - * so we don't end up referencing a non-existent page. - * Cacheline aligned is in quotes because the kernel will - * set the prefetch amount to a reasonable level if the - * cacheline size is unknown. - */ - mvi CCHCNT, SG_PREFETCH_CNT; - and CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR; - bmov CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3; - mvi CCSGCTL, CCSGEN|CCSGRESET ret; -idle_sgfetch_complete: - call disable_ccsgen_fetch_done; - and CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR; -idle_sg_avail: - if ((ahc->features & AHC_ULTRA2) != 0) { - /* Does the hardware have space for another SG entry? */ - test DFSTATUS, PRELOAD_AVAIL jz return; - bmov HADDR, CCSGRAM, 7; - bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; - } - call sg_advance; - mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; - or SINDEX, LAST_SEG; - mov SG_CACHE_PRE, SINDEX; - /* Load the segment */ - or DFCNTRL, PRELOADEN; - } - ret; -} - -if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { -/* - * Calculate the trailing portion of this S/G segment that cannot - * be transferred using memory write and invalidate PCI transactions. - * XXX Can we optimize this for PCI writes only??? - */ -calc_mwi_residual: - /* - * If the ending address is on a cacheline boundary, - * there is no need for an extra segment. - */ - mov A, HCNT[0]; - add A, A, HADDR[0]; - and A, CACHESIZE_MASK; - test A, 0xFF jz return; - - /* - * If the transfer is less than a cachline, - * there is no need for an extra segment. - */ - test HCNT[1], 0xFF jnz calc_mwi_residual_final; - test HCNT[2], 0xFF jnz calc_mwi_residual_final; - add NONE, INVERTED_CACHESIZE_MASK, HCNT[0]; - jnc return; - -calc_mwi_residual_final: - mov MWI_RESIDUAL, A; - not A; - inc A; - add HCNT[0], A; - adc HCNT[1], -1; - adc HCNT[2], -1 ret; -} - -p_data: - test SEQ_FLAGS,NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed; - mvi PROTO_VIOLATION call set_seqint; -p_data_allowed: - if ((ahc->features & AHC_ULTRA2) != 0) { - mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; - } else { - mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; - } - test LASTPHASE, IOI jnz . + 2; - or DMAPARAMS, DIRECTION; - if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* We don't have any valid S/G elements */ - mvi CCSGADDR, SG_PREFETCH_CNT; - } - test SEQ_FLAGS, DPHASE jz data_phase_initialize; - - /* - * If we re-enter the data phase after going through another - * phase, our transfer location has almost certainly been - * corrupted by the interveining, non-data, transfers. Ask - * the host driver to fix us up based on the transfer residual. - */ - mvi PDATA_REINIT call set_seqint; - jmp data_phase_loop; - -data_phase_initialize: - /* We have seen a data phase for the first time */ - or SEQ_FLAGS, DPHASE; - - /* - * Initialize the DMA address and counter from the SCB. - * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG - * flag in the highest byte of the data count. We cannot - * modify the saved values in the SCB until we see a save - * data pointers message. - */ - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - /* The lowest address byte must be loaded last. */ - mov SCB_DATACNT[3] call set_hhaddr; - } - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov HADDR, SCB_DATAPTR, 7; - bmov SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5; - } else { - mvi DINDEX, HADDR; - mvi SCB_DATAPTR call bcopy_7; - mvi DINDEX, SCB_RESIDUAL_DATACNT + 3; - mvi SCB_DATACNT + 3 call bcopy_5; - } - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) { - call calc_mwi_residual; - } - and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; - - if ((ahc->features & AHC_ULTRA2) == 0) { - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov STCNT, HCNT, 3; - } else { - call set_stcnt_from_hcnt; - } - } - -data_phase_loop: - /* Guard against overruns */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds; - - /* - * Turn on `Bit Bucket' mode, wait until the target takes - * us to another phase, and then notify the host. - */ - and DMAPARAMS, DIRECTION; - mov DFCNTRL, DMAPARAMS; - or SXFRCTL1,BITBUCKET; - if ((ahc->features & AHC_DT) == 0) { - test SSTAT1,PHASEMIS jz .; - } else { - test SCSIPHASE, DATA_PHASE_MASK jnz .; - } - and SXFRCTL1, ~BITBUCKET; - mvi DATA_OVERRUN call set_seqint; - jmp ITloop; - -data_phase_inbounds: - if ((ahc->features & AHC_ULTRA2) != 0) { - mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; - or SINDEX, LAST_SEG; - mov SG_CACHE_PRE, SINDEX; - mov DFCNTRL, DMAPARAMS; -ultra2_dma_loop: - call idle_loop; - /* - * The transfer is complete if either the last segment - * completes or the target changes phase. - */ - test SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish; - if ((ahc->features & AHC_DT) == 0) { - if ((ahc->flags & AHC_TARGETROLE) != 0) { - /* - * As a target, we control the phases, - * so ignore PHASEMIS. - */ - test SSTAT0, TARGET jnz ultra2_dma_loop; - } - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT1,PHASEMIS jz ultra2_dma_loop; - } - } else { - test DFCNTRL, SCSIEN jnz ultra2_dma_loop; - } - -ultra2_dmafinish: - /* - * The transfer has terminated either due to a phase - * change, and/or the completion of the last segment. - * We have two goals here. Do as much other work - * as possible while the data fifo drains on a read - * and respond as quickly as possible to the standard - * messages (save data pointers/disconnect and command - * complete) that usually follow a data phase. - */ - if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { - /* - * On chips with broken auto-flush, start - * the flushing process now. We'll poke - * the chip from time to time to keep the - * flush process going as we complete the - * data phase. - */ - or DFCNTRL, FIFOFLUSH; - } - /* - * We assume that, even though data may still be - * transferring to the host, that the SCSI side of - * the DMA engine is now in a static state. This - * allows us to update our notion of where we are - * in this transfer. - * - * If, by chance, we stopped before being able - * to fetch additional segments for this transfer, - * yet the last S/G was completely exhausted, - * call our idle loop until it is able to load - * another segment. This will allow us to immediately - * pickup on the next segment on the next data phase. - * - * If we happened to stop on the last segment, then - * our residual information is still correct from - * the idle loop and there is no need to perform - * any fixups. - */ -ultra2_ensure_sg: - test SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid; - /* Record if we've consumed all S/G entries */ - test SSTAT2, SHVALID jnz residuals_correct; - or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; - jmp residuals_correct; - -ultra2_shvalid: - test SSTAT2, SHVALID jnz sgptr_fixup; - call idle_loop; - jmp ultra2_ensure_sg; - -sgptr_fixup: - /* - * Fixup the residual next S/G pointer. The S/G preload - * feature of the chip allows us to load two elements - * in addition to the currently active element. We - * store the bottom byte of the next S/G pointer in - * the SG_CACEPTR register so we can restore the - * correct value when the DMA completes. If the next - * sg ptr value has advanced to the point where higher - * bytes in the address have been affected, fix them - * too. - */ - test SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done; - test SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done; - add SCB_RESIDUAL_SGPTR[1], -1; - adc SCB_RESIDUAL_SGPTR[2], -1; - adc SCB_RESIDUAL_SGPTR[3], -1; -sgptr_fixup_done: - and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; - /* We are not the last seg */ - and SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG; -residuals_correct: - /* - * Go ahead and shut down the DMA engine now. - * In the future, we'll want to handle end of - * transfer messages prior to doing this, but this - * requires similar restructuring for pre-ULTRA2 - * controllers. - */ - test DMAPARAMS, DIRECTION jnz ultra2_fifoempty; -ultra2_fifoflush: - if ((ahc->features & AHC_DT) == 0) { - if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) { - /* - * On Rev A of the aic7890, the autoflush - * feature doesn't function correctly. - * Perform an explicit manual flush. During - * a manual flush, the FIFOEMP bit becomes - * true every time the PCI FIFO empties - * regardless of the state of the SCSI FIFO. - * It can take up to 4 clock cycles for the - * SCSI FIFO to get data into the PCI FIFO - * and for FIFOEMP to de-assert. Here we - * guard against this condition by making - * sure the FIFOEMP bit stays on for 5 full - * clock cycles. - */ - or DFCNTRL, FIFOFLUSH; - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - } - test DFSTATUS, FIFOEMP jz ultra2_fifoflush; - } else { - /* - * We enable the auto-ack feature on DT capable - * controllers. This means that the controller may - * have already transferred some overrun bytes into - * the data FIFO and acked them on the bus. The only - * way to detect this situation is to wait for - * LAST_SEG_DONE to come true on a completed transfer - * and then test to see if the data FIFO is non-empty. - */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL - jz ultra2_wait_fifoemp; - test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; - /* - * FIFOEMP can lag LAST_SEG_DONE. Wait a few - * clocks before calling this an overrun. - */ - test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; - test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; - test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; - /* Overrun */ - jmp data_phase_loop; -ultra2_wait_fifoemp: - test DFSTATUS, FIFOEMP jz .; - } -ultra2_fifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz ultra2_fifoempty; -ultra2_dmahalt: - and DFCNTRL, ~(SCSIEN|HDMAEN); - test DFCNTRL, SCSIEN|HDMAEN jnz .; - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - /* - * Keep HHADDR cleared for future, 32bit addressed - * only, DMA operations. - * - * Due to bayonette style S/G handling, our residual - * data must be "fixed up" once the transfer is halted. - * Here we fixup the HSHADDR stored in the high byte - * of the residual data cnt. By postponing the fixup, - * we can batch the clearing of HADDR with the fixup. - * If we halted on the last segment, the residual is - * already correct. If we are not on the last - * segment, copy the high address directly from HSHADDR. - * We don't need to worry about maintaining the - * SG_LAST_SEG flag as it will always be false in the - * case where an update is required. - */ - or DSCOMMAND1, HADDLDSEL0; - test SG_CACHE_SHADOW, LAST_SEG jnz . + 2; - mov SCB_RESIDUAL_DATACNT[3], SHADDR; - clr HADDR; - and DSCOMMAND1, ~HADDLDSEL0; - } - } else { - /* If we are the last SG block, tell the hardware. */ - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 - && ahc->pci_cachesize != 0) { - test MWI_RESIDUAL, 0xFF jnz dma_mid_sg; - } - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; - if ((ahc->flags & AHC_TARGETROLE) != 0) { - test SSTAT0, TARGET jz dma_last_sg; - if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) { - test DMAPARAMS, DIRECTION jz dma_mid_sg; - } - } -dma_last_sg: - and DMAPARAMS, ~WIDEODD; -dma_mid_sg: - /* Start DMA data transfer. */ - mov DFCNTRL, DMAPARAMS; -dma_loop: - if ((ahc->features & AHC_CMD_CHAN) != 0) { - call idle_loop; - } - test SSTAT0,DMADONE jnz dma_dmadone; - test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ -dma_phasemis: - /* - * We will be "done" DMAing when the transfer count goes to - * zero, or the target changes the phase (in light of this, - * it makes sense that the DMA circuitry doesn't ACK when - * PHASEMIS is active). If we are doing a SCSI->Host transfer, - * the data FIFO should be flushed auto-magically on STCNT=0 - * or a phase change, so just wait for FIFO empty status. - */ -dma_checkfifo: - test DFCNTRL,DIRECTION jnz dma_fifoempty; -dma_fifoflush: - test DFSTATUS,FIFOEMP jz dma_fifoflush; -dma_fifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz dma_fifoempty; - - /* - * Now shut off the DMA and make sure that the DMA - * hardware has actually stopped. Touching the DMA - * counters, etc. while a DMA is active will result - * in an ILLSADDR exception. - */ -dma_dmadone: - and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); -dma_halt: - /* - * Some revisions of the aic78XX have a problem where, if the - * data fifo is full, but the PCI input latch is not empty, - * HDMAEN cannot be cleared. The fix used here is to drain - * the prefetched but unused data from the data fifo until - * there is space for the input latch to drain. - */ - if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { - mov NONE, DFDAT; - } - test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; - - /* See if we have completed this last segment */ - test STCNT[0], 0xff jnz data_phase_finish; - test STCNT[1], 0xff jnz data_phase_finish; - test STCNT[2], 0xff jnz data_phase_finish; - - /* - * Advance the scatter-gather pointers if needed - */ - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 - && ahc->pci_cachesize != 0) { - test MWI_RESIDUAL, 0xFF jz no_mwi_resid; - /* - * Reload HADDR from SHADDR and setup the - * count to be the size of our residual. - */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov HADDR, SHADDR, 4; - mov HCNT, MWI_RESIDUAL; - bmov HCNT[1], ALLZEROS, 2; - } else { - mvi DINDEX, HADDR; - mvi SHADDR call bcopy_4; - mov MWI_RESIDUAL call set_hcnt; - } - clr MWI_RESIDUAL; - jmp sg_load_done; -no_mwi_resid: - } - test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load; - or SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL; - jmp data_phase_finish; -sg_load: - /* - * Load the next SG element's data address and length - * into the DMA engine. If we don't have hardware - * to perform a prefetch, we'll have to fetch the - * segment from host memory first. - */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* Wait for the idle loop to complete */ - test CCSGCTL, CCSGEN jz . + 3; - call idle_loop; - test CCSGCTL, CCSGEN jnz . - 1; - bmov HADDR, CCSGRAM, 7; - /* - * Workaround for flaky external SCB RAM - * on certain aic7895 setups. It seems - * unable to handle direct transfers from - * S/G ram to certain SCB locations. - */ - mov SINDEX, CCSGRAM; - mov SCB_RESIDUAL_DATACNT[3], SINDEX; - } else { - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - mov ALLZEROS call set_hhaddr; - } - mvi DINDEX, HADDR; - mvi SCB_RESIDUAL_SGPTR call bcopy_4; - - mvi SG_SIZEOF call set_hcnt; - - or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - - call dma_finish; - - mvi DINDEX, HADDR; - call dfdat_in_7; - mov SCB_RESIDUAL_DATACNT[3], DFDAT; - } - - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; - - /* - * The lowest address byte must be loaded - * last as it triggers the computation of - * some items in the PCI block. The ULTRA2 - * chips do this on PRELOAD. - */ - mov HADDR, HADDR; - } - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 - && ahc->pci_cachesize != 0) { - call calc_mwi_residual; - } - - /* Point to the new next sg in memory */ - call sg_advance; - -sg_load_done: - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov STCNT, HCNT, 3; - } else { - call set_stcnt_from_hcnt; - } - - if ((ahc->flags & AHC_TARGETROLE) != 0) { - test SSTAT0, TARGET jnz data_phase_loop; - } - } -data_phase_finish: - /* - * If the target has left us in data phase, loop through - * the dma code again. In the case of ULTRA2 adapters, - * we should only loop if there is a data overrun. For - * all other adapters, we'll loop after each S/G element - * is loaded as well as if there is an overrun. - */ - if ((ahc->flags & AHC_TARGETROLE) != 0) { - test SSTAT0, TARGET jnz data_phase_done; - } - if ((ahc->flags & AHC_INITIATORROLE) != 0) { - test SSTAT1, REQINIT jz .; - if ((ahc->features & AHC_DT) == 0) { - test SSTAT1,PHASEMIS jz data_phase_loop; - } else { - test SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop; - } - } - -data_phase_done: - /* - * After a DMA finishes, save the SG and STCNT residuals back into - * the SCB. We use STCNT instead of HCNT, since it's a reflection - * of how many bytes were transferred on the SCSI (as opposed to the - * host) bus. - */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* Kill off any pending prefetch */ - call disable_ccsgen; - } - - if ((ahc->features & AHC_ULTRA2) == 0) { - /* - * Clear the high address byte so that all other DMA - * operations, which use 32bit addressing, can assume - * HHADDR is 0. - */ - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - mov ALLZEROS call set_hhaddr; - } - } - - /* - * Update our residual information before the information is - * lost by some other type of SCSI I/O (e.g. PIO). If we have - * transferred all data, no update is needed. - * - */ - test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done; - if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 - && ahc->pci_cachesize != 0) { - if ((ahc->features & AHC_CMD_CHAN) != 0) { - test MWI_RESIDUAL, 0xFF jz bmov_resid; - } - mov A, MWI_RESIDUAL; - add SCB_RESIDUAL_DATACNT[0], A, STCNT[0]; - clr A; - adc SCB_RESIDUAL_DATACNT[1], A, STCNT[1]; - adc SCB_RESIDUAL_DATACNT[2], A, STCNT[2]; - clr MWI_RESIDUAL; - if ((ahc->features & AHC_CMD_CHAN) != 0) { - jmp . + 2; -bmov_resid: - bmov SCB_RESIDUAL_DATACNT, STCNT, 3; - } - } else if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESIDUAL_DATACNT, STCNT, 3; - } else { - mov SCB_RESIDUAL_DATACNT[0], STCNT[0]; - mov SCB_RESIDUAL_DATACNT[1], STCNT[1]; - mov SCB_RESIDUAL_DATACNT[2], STCNT[2]; - } -residual_update_done: - /* - * Since we've been through a data phase, the SCB_RESID* fields - * are now initialized. Clear the full residual flag. - */ - and SCB_SGPTR[0], ~SG_FULL_RESID; - - if ((ahc->features & AHC_ULTRA2) != 0) { - /* Clear the channel in case we return to data phase later */ - or SXFRCTL0, CLRSTCNT|CLRCHN; - or SXFRCTL0, CLRSTCNT|CLRCHN; - } - - if ((ahc->flags & AHC_TARGETROLE) != 0) { - test SEQ_FLAGS, DPHASE_PENDING jz ITloop; - and SEQ_FLAGS, ~DPHASE_PENDING; - /* - * For data-in phases, wait for any pending acks from the - * initiator before changing phase. We only need to - * send Ignore Wide Residue messages for data-in phases. - */ - test DFCNTRL, DIRECTION jz target_ITloop; - test SSTAT1, REQINIT jnz .; - test SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop; - test SCSIRATE, WIDEXFER jz target_ITloop; - /* - * Issue an Ignore Wide Residue Message. - */ - mvi P_MESGIN|BSYO call change_phase; - mvi MSG_IGN_WIDE_RESIDUE call target_outb; - mvi 1 call target_outb; - jmp target_ITloop; - } else { - jmp ITloop; - } - -if ((ahc->flags & AHC_INITIATORROLE) != 0) { -/* - * Command phase. Set up the DMA registers and let 'er rip. - */ -p_command: - test SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay; - mvi PROTO_VIOLATION call set_seqint; -p_command_okay: - - if ((ahc->features & AHC_ULTRA2) != 0) { - bmov HCNT[0], SCB_CDB_LEN, 1; - bmov HCNT[1], ALLZEROS, 2; - mvi SG_CACHE_PRE, LAST_SEG; - } else if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov STCNT[0], SCB_CDB_LEN, 1; - bmov STCNT[1], ALLZEROS, 2; - } else { - mov STCNT[0], SCB_CDB_LEN; - clr STCNT[1]; - clr STCNT[2]; - } - add NONE, -13, SCB_CDB_LEN; - mvi SCB_CDB_STORE jnc p_command_embedded; -p_command_from_host: - if ((ahc->features & AHC_ULTRA2) != 0) { - bmov HADDR[0], SCB_CDB_PTR, 4; - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); - } else { - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov HADDR[0], SCB_CDB_PTR, 4; - bmov HCNT, STCNT, 3; - } else { - mvi DINDEX, HADDR; - mvi SCB_CDB_PTR call bcopy_4; - mov SCB_CDB_LEN call set_hcnt; - } - mvi DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET); - } - jmp p_command_xfer; -p_command_embedded: - /* - * The data fifo seems to require 4 byte aligned - * transfers from the sequencer. Force this to - * be the case by clearing HADDR[0] even though - * we aren't going to touch host memory. - */ - clr HADDR[0]; - if ((ahc->features & AHC_ULTRA2) != 0) { - mvi DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION); - bmov DFDAT, SCB_CDB_STORE, 12; - } else if ((ahc->features & AHC_CMD_CHAN) != 0) { - if ((ahc->flags & AHC_SCB_BTT) != 0) { - /* - * On the 7895 the data FIFO will - * get corrupted if you try to dump - * data from external SCB memory into - * the FIFO while it is enabled. So, - * fill the fifo and then enable SCSI - * transfers. - */ - mvi DFCNTRL, (DIRECTION|FIFORESET); - } else { - mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); - } - bmov DFDAT, SCB_CDB_STORE, 12; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH); - } else { - or DFCNTRL, FIFOFLUSH; - } - } else { - mvi DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET); - call copy_to_fifo_6; - call copy_to_fifo_6; - or DFCNTRL, FIFOFLUSH; - } -p_command_xfer: - and SEQ_FLAGS, ~NO_CDB_SENT; - if ((ahc->features & AHC_DT) == 0) { - test SSTAT0, SDONE jnz . + 2; - test SSTAT1, PHASEMIS jz . - 1; - /* - * Wait for our ACK to go-away on it's own - * instead of being killed by SCSIEN getting cleared. - */ - test SCSISIGI, ACKI jnz .; - } else { - test DFCNTRL, SCSIEN jnz .; - } - test SSTAT0, SDONE jnz p_command_successful; - /* - * Don't allow a data phase if the command - * was not fully transferred. - */ - or SEQ_FLAGS, NO_CDB_SENT; -p_command_successful: - and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); - test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .; - jmp ITloop; - -/* - * Status phase. Wait for the data byte to appear, then read it - * and store it into the SCB. - */ -p_status: - test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; -p_status_okay: - mov SCB_SCSI_STATUS, SCSIDATL; - or SCB_CONTROL, STATUS_RCVD; - jmp ITloop; - -/* - * Message out phase. If MSG_OUT is MSG_IDENTIFYFLAG, build a full - * indentify message sequence and send it to the target. The host may - * override this behavior by setting the MK_MESSAGE bit in the SCB - * control byte. This will cause us to interrupt the host and allow - * it to handle the message phase completely on its own. If the bit - * associated with this target is set, we will also interrupt the host, - * thereby allowing it to send a message on the next selection regardless - * of the transaction being sent. - * - * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. - * This is done to allow the host to send messages outside of an identify - * sequence while protecting the seqencer from testing the MK_MESSAGE bit - * on an SCB that might not be for the current nexus. (For example, a - * BDR message in response to a bad reselection would leave us pointed to - * an SCB that doesn't have anything to do with the current target). - * - * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, - * bus device reset). - * - * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, - * in case the target decides to put us in this phase for some strange - * reason. - */ -p_mesgout_retry: - /* Turn on ATN for the retry */ - if ((ahc->features & AHC_DT) == 0) { - or SCSISIGO, ATNO, LASTPHASE; - } else { - mvi SCSISIGO, ATNO; - } -p_mesgout: - mov SINDEX, MSG_OUT; - cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; - test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; -p_mesgout_identify: - or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN; - test SCB_CONTROL, DISCENB jnz . + 2; - and SINDEX, ~DISCENB; -/* - * Send a tag message if TAG_ENB is set in the SCB control block. - * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. - */ -p_mesgout_tag: - test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; - mov SCSIDATL, SINDEX; /* Send the identify message */ - call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; - call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - mov SCB_TAG jmp p_mesgout_onebyte; -/* - * Interrupt the driver, and allow it to handle this message - * phase and any required retries. - */ -p_mesgout_from_host: - cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; - jmp host_message_loop; - -p_mesgout_onebyte: - mvi CLRSINT1, CLRATNO; - mov SCSIDATL, SINDEX; - -/* - * If the next bus phase after ATN drops is message out, it means - * that the target is requesting that the last message(s) be resent. - */ - call phase_lock; - cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; - -p_mesgout_done: - mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ - mov LAST_MSG, MSG_OUT; - mvi MSG_OUT, MSG_NOOP; /* No message left */ - jmp ITloop; - -/* - * Message in phase. Bytes are read using Automatic PIO mode. - */ -p_mesgin: - mvi ACCUM call inb_first; /* read the 1st message byte */ - - test A,MSG_IDENTIFYFLAG jnz mesgin_identify; - cmp A,MSG_DISCONNECT je mesgin_disconnect; - cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; - cmp ALLZEROS,A je mesgin_complete; - cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; - cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_ign_wide_residue; - cmp A,MSG_NOOP je mesgin_done; - -/* - * Pushed message loop to allow the kernel to - * run it's own message state engine. To avoid an - * extra nop instruction after signaling the kernel, - * we perform the phase_lock before checking to see - * if we should exit the loop and skip the phase_lock - * in the ITloop. Performing back to back phase_locks - * shouldn't hurt, but why do it twice... - */ -host_message_loop: - mvi HOST_MSG_LOOP call set_seqint; - call phase_lock; - cmp RETURN_1, EXIT_MSG_LOOP je ITloop + 1; - jmp host_message_loop; - -mesgin_ign_wide_residue: -if ((ahc->features & AHC_WIDE) != 0) { - test SCSIRATE, WIDEXFER jz mesgin_reject; - /* Pull the residue byte */ - mvi ARG_1 call inb_next; - cmp ARG_1, 0x01 jne mesgin_reject; - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; - test SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done; - mvi IGN_WIDE_RES call set_seqint; - jmp mesgin_done; -} - -mesgin_proto_violation: - mvi PROTO_VIOLATION call set_seqint; - jmp mesgin_done; -mesgin_reject: - mvi MSG_MESSAGE_REJECT call mk_mesg; -mesgin_done: - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - jmp ITloop; - -/* - * We received a "command complete" message. Put the SCB_TAG into the QOUTFIFO, - * and trigger a completion interrupt. Before doing so, check to see if there - * is a residual or the status byte is something other than STATUS_GOOD (0). - * In either of these conditions, we upload the SCB back to the host so it can - * process this information. In the case of a non zero status byte, we - * additionally interrupt the kernel driver synchronously, allowing it to - * decide if sense should be retrieved. If the kernel driver wishes to request - * sense, it will fill the kernel SCB with a request sense command, requeue - * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting - * RETURN_1 to SEND_SENSE. - */ -mesgin_complete: - - /* - * If ATN is raised, we still want to give the target a message. - * Perhaps there was a parity error on this last message byte. - * Either way, the target should take us to message out phase - * and then attempt to complete the command again. We should use a - * critical section here to guard against a timeout triggering - * for this command and setting ATN while we are still processing - * the completion. - test SCSISIGI, ATNI jnz mesgin_done; - */ - - /* - * If we are identified and have successfully sent the CDB, - * any status will do. Optimize this fast path. - */ - test SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation; - test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; - - /* - * If the target never sent an identify message but instead went - * to mesgin to give an invalid message, let the host abort us. - */ - test SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation; - - /* - * If we recevied good status but never successfully sent the - * cdb, abort the command. - */ - test SCB_SCSI_STATUS,0xff jnz complete_accepted; - test SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation; - -complete_accepted: - /* - * See if we attempted to deliver a message but the target ingnored us. - */ - test SCB_CONTROL, MK_MESSAGE jz . + 2; - mvi MKMSG_FAILED call set_seqint; - - /* - * Check for residuals - */ - test SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */ - test SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */ - test SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb; -check_status: - test SCB_SCSI_STATUS,0xff jz complete; /* Good Status? */ -upload_scb: - or SCB_SGPTR, SG_RESID_VALID; - mvi DMAPARAMS, FIFORESET; - mov SCB_TAG call dma_scb; - test SCB_SCSI_STATUS, 0xff jz complete; /* Just a residual? */ - mvi BAD_STATUS call set_seqint; /* let driver know */ - cmp RETURN_1, SEND_SENSE jne complete; - call add_scb_to_free_list; - jmp await_busfree; -complete: - mov SCB_TAG call complete_post; - jmp await_busfree; -} - -complete_post: - /* Post the SCBID in SINDEX and issue an interrupt */ - call add_scb_to_free_list; - mov ARG_1, SINDEX; - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - mov A, SDSCB_QOFF; - } else { - mov A, QOUTPOS; - } - mvi QOUTFIFO_OFFSET call post_byte_setup; - mov ARG_1 call post_byte; - if ((ahc->features & AHC_QUEUE_REGS) == 0) { - inc QOUTPOS; - } - mvi INTSTAT,CMDCMPLT ret; - -if ((ahc->flags & AHC_INITIATORROLE) != 0) { -/* - * Is it a disconnect message? Set a flag in the SCB to remind us - * and await the bus going free. If this is an untagged transaction - * store the SCB id for it in our untagged target table for lookup on - * a reselection. - */ -mesgin_disconnect: - /* - * If ATN is raised, we still want to give the target a message. - * Perhaps there was a parity error on this last message byte - * or we want to abort this command. Either way, the target - * should take us to message out phase and then attempt to - * disconnect again. - * XXX - Wait for more testing. - test SCSISIGI, ATNI jnz mesgin_done; - */ - test SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT - jnz mesgin_proto_violation; - or SCB_CONTROL,DISCONNECTED; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - call add_scb_to_disc_list; - } - test SCB_CONTROL, TAG_ENB jnz await_busfree; - mov ARG_1, SCB_TAG; - and SAVED_LUN, LID, SCB_LUN; - mov SCB_SCSIID call set_busy_target; - jmp await_busfree; - -/* - * Save data pointers message: - * Copying RAM values back to SCB, for Save Data Pointers message, but - * only if we've actually been into a data phase to change them. This - * protects against bogus data in scratch ram and the residual counts - * since they are only initialized when we go into data_in or data_out. - * Ack the message as soon as possible. For chips without S/G pipelining, - * we can only ack the message after SHADDR has been saved. On these - * chips, SHADDR increments with every bus transaction, even PIO. - */ -mesgin_sdptrs: - if ((ahc->features & AHC_ULTRA2) != 0) { - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - test SEQ_FLAGS, DPHASE jz ITloop; - } else { - test SEQ_FLAGS, DPHASE jz mesgin_done; - } - - /* - * If we are asked to save our position at the end of the - * transfer, just mark us at the end rather than perform a - * full save. - */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full; - or SCB_SGPTR, SG_LIST_NULL; - if ((ahc->features & AHC_ULTRA2) != 0) { - jmp ITloop; - } else { - jmp mesgin_done; - } - -mesgin_sdptrs_full: - - /* - * The SCB_SGPTR becomes the next one we'll download, - * and the SCB_DATAPTR becomes the current SHADDR. - * Use the residual number since STCNT is corrupted by - * any message transfer. - */ - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov SCB_DATAPTR, SHADDR, 4; - if ((ahc->features & AHC_ULTRA2) == 0) { - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - } - bmov SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8; - } else { - mvi DINDEX, SCB_DATAPTR; - mvi SHADDR call bcopy_4; - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - mvi SCB_RESIDUAL_DATACNT call bcopy_8; - } - jmp ITloop; - -/* - * Restore pointers message? Data pointers are recopied from the - * SCB anytime we enter a data phase for the first time, so all - * we need to do is clear the DPHASE flag and let the data phase - * code do the rest. We also reset/reallocate the FIFO to make - * sure we have a clean start for the next data or command phase. - */ -mesgin_rdptrs: - and SEQ_FLAGS, ~DPHASE; /* - * We'll reload them - * the next time through - * the dataphase. - */ - or SXFRCTL0, CLRSTCNT|CLRCHN; - jmp mesgin_done; - -/* - * Index into our Busy Target table. SINDEX and DINDEX are modified - * upon return. SCBPTR may be modified by this action. - */ -set_busy_target: - shr DINDEX, 4, SINDEX; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mov SCBPTR, SAVED_LUN; - add DINDEX, SCB_64_BTT; - } else { - add DINDEX, BUSY_TARGETS; - } - mov DINDIR, ARG_1 ret; - -/* - * Identify message? For a reconnecting target, this tells us the lun - * that the reconnection is for - find the correct SCB and switch to it, - * clearing the "disconnected" bit so we don't "find" it by accident later. - */ -mesgin_identify: - /* - * Determine whether a target is using tagged or non-tagged - * transactions by first looking at the transaction stored in - * the busy target array. If there is no untagged transaction - * for this target or the transaction is for a different lun, then - * this must be a tagged transaction. - */ - shr SINDEX, 4, SAVED_SCSIID; - and SAVED_LUN, MSG_IDENTIFY_LUNMASK, A; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - add SINDEX, SCB_64_BTT; - mov SCBPTR, SAVED_LUN; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - add NONE, -SCB_64_BTT, SINDEX; - jc . + 2; - mvi INTSTAT, OUT_OF_RANGE; - nop; - add NONE, -(SCB_64_BTT + 16), SINDEX; - jnc . + 2; - mvi INTSTAT, OUT_OF_RANGE; - nop; - } - } else { - add SINDEX, BUSY_TARGETS; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - add NONE, -BUSY_TARGETS, SINDEX; - jc . + 2; - mvi INTSTAT, OUT_OF_RANGE; - nop; - add NONE, -(BUSY_TARGETS + 16), SINDEX; - jnc . + 2; - mvi INTSTAT, OUT_OF_RANGE; - nop; - } - } - mov ARG_1, SINDIR; - cmp ARG_1, SCB_LIST_NULL je snoop_tag; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mov ARG_1 call findSCB; - } else { - mov SCBPTR, ARG_1; - } - if ((ahc->flags & AHC_SCB_BTT) != 0) { - jmp setup_SCB_id_lun_okay; - } else { - /* - * We only allow one untagged command per-target - * at a time. So, if the lun doesn't match, look - * for a tag message. - */ - and A, LID, SCB_LUN; - cmp SAVED_LUN, A je setup_SCB_id_lun_okay; - if ((ahc->flags & AHC_PAGESCBS) != 0) { - /* - * findSCB removes the SCB from the - * disconnected list, so we must replace - * it there should this SCB be for another - * lun. - */ - call cleanup_scb; - } - } - -/* - * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. - * If we get one, we use the tag returned to find the proper - * SCB. With SCB paging, we must search for non-tagged - * transactions since the SCB may exist in any slot. If we're not - * using SCB paging, we can use the tag as the direct index to the - * SCB. - */ -snoop_tag: - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x80; - } - mov NONE,SCSIDATL; /* ACK Identify MSG */ - call phase_lock; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x1; - } - cmp LASTPHASE, P_MESGIN jne not_found; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x2; - } - cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; -get_tag: - if ((ahc->flags & AHC_PAGESCBS) != 0) { - mvi ARG_1 call inb_next; /* tag value */ - mov ARG_1 call findSCB; - } else { - mvi ARG_1 call inb_next; /* tag value */ - mov SCBPTR, ARG_1; - } - -/* - * Ensure that the SCB the tag points to is for - * an SCB transaction to the reconnecting target. - */ -setup_SCB: - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x4; - } - mov A, SCB_SCSIID; - cmp SAVED_SCSIID, A jne not_found_cleanup_scb; - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x8; - } -setup_SCB_id_okay: - and A, LID, SCB_LUN; - cmp SAVED_LUN, A jne not_found_cleanup_scb; -setup_SCB_id_lun_okay: - if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { - or SEQ_FLAGS, 0x10; - } - test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; - and SCB_CONTROL,~DISCONNECTED; - test SCB_CONTROL, TAG_ENB jnz setup_SCB_tagged; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mov A, SCBPTR; - } - mvi ARG_1, SCB_LIST_NULL; - mov SAVED_SCSIID call set_busy_target; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mov SCBPTR, A; - } -setup_SCB_tagged: - clr SEQ_FLAGS; /* make note of IDENTIFY */ - call set_transfer_settings; - /* See if the host wants to send a message upon reconnection */ - test SCB_CONTROL, MK_MESSAGE jz mesgin_done; - mvi HOST_MSG call mk_mesg; - jmp mesgin_done; - -not_found_cleanup_scb: - if ((ahc->flags & AHC_PAGESCBS) != 0) { - call cleanup_scb; - } -not_found: - mvi NO_MATCH call set_seqint; - jmp mesgin_done; - -mk_mesg: - if ((ahc->features & AHC_DT) == 0) { - or SCSISIGO, ATNO, LASTPHASE; - } else { - mvi SCSISIGO, ATNO; - } - mov MSG_OUT,SINDEX ret; - -/* - * Functions to read data in Automatic PIO mode. - * - * According to Adaptec's documentation, an ACK is not sent on input from - * the target until SCSIDATL is read from. So we wait until SCSIDATL is - * latched (the usual way), then read the data byte directly off the bus - * using SCSIBUSL. When we have pulled the ATN line, or we just want to - * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI - * spec guarantees that the target will hold the data byte on the bus until - * we send our ACK. - * - * The assumption here is that these are called in a particular sequence, - * and that REQ is already set when inb_first is called. inb_{first,next} - * use the same calling convention as inb. - */ -inb_next_wait_perr: - mvi PERR_DETECTED call set_seqint; - jmp inb_next_wait; -inb_next: - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ -inb_next_wait: - /* - * If there is a parity error, wait for the kernel to - * see the interrupt and prepare our message response - * before continuing. - */ - test SSTAT1, REQINIT jz inb_next_wait; - test SSTAT1, SCSIPERR jnz inb_next_wait_perr; -inb_next_check_phase: - and LASTPHASE, PHASE_MASK, SCSISIGI; - cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; -inb_first: - mov DINDEX,SINDEX; - mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ -inb_last: - mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ -} - -if ((ahc->flags & AHC_TARGETROLE) != 0) { -/* - * Change to a new phase. If we are changing the state of the I/O signal, - * from out to in, wait an additional data release delay before continuing. - */ -change_phase: - /* Wait for preceding I/O session to complete. */ - test SCSISIGI, ACKI jnz .; - - /* Change the phase */ - and DINDEX, IOI, SCSISIGI; - mov SCSISIGO, SINDEX; - and A, IOI, SINDEX; - - /* - * If the data direction has changed, from - * out (initiator driving) to in (target driving), - * we must wait at least a data release delay plus - * the normal bus settle delay. [SCSI III SPI 10.11.0] - */ - cmp DINDEX, A je change_phase_wait; - test SINDEX, IOI jz change_phase_wait; - call change_phase_wait; -change_phase_wait: - nop; - nop; - nop; - nop ret; - -/* - * Send a byte to an initiator in Automatic PIO mode. - */ -target_outb: - or SXFRCTL0, SPIOEN; - test SSTAT0, SPIORDY jz .; - mov SCSIDATL, SINDEX; - test SSTAT0, SPIORDY jz .; - and SXFRCTL0, ~SPIOEN ret; -} - -/* - * Locate a disconnected SCB by SCBID. Upon return, SCBPTR and SINDEX will - * be set to the position of the SCB. If the SCB cannot be found locally, - * it will be paged in from host memory. RETURN_2 stores the address of the - * preceding SCB in the disconnected list which can be used to speed up - * removal of the found SCB from the disconnected list. - */ -if ((ahc->flags & AHC_PAGESCBS) != 0) { -BEGIN_CRITICAL; -findSCB: - mov A, SINDEX; /* Tag passed in SINDEX */ - cmp DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound; - mov SCBPTR, DISCONNECTED_SCBH; /* Initialize SCBPTR */ - mvi ARG_2, SCB_LIST_NULL; /* Head of list */ - jmp findSCB_loop; -findSCB_next: - cmp SCB_NEXT, SCB_LIST_NULL je findSCB_notFound; - mov ARG_2, SCBPTR; - mov SCBPTR,SCB_NEXT; -findSCB_loop: - cmp SCB_TAG, A jne findSCB_next; -rem_scb_from_disc_list: - cmp ARG_2, SCB_LIST_NULL je rHead; - mov DINDEX, SCB_NEXT; - mov SINDEX, SCBPTR; - mov SCBPTR, ARG_2; - mov SCB_NEXT, DINDEX; - mov SCBPTR, SINDEX ret; -rHead: - mov DISCONNECTED_SCBH,SCB_NEXT ret; -END_CRITICAL; -findSCB_notFound: - /* - * We didn't find it. Page in the SCB. - */ - mov ARG_1, A; /* Save tag */ - mov ALLZEROS call get_free_or_disc_scb; - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov ARG_1 jmp dma_scb; -} - -/* - * Prepare the hardware to post a byte to host memory given an - * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR. - */ -post_byte_setup: - mov ARG_2, SINDEX; - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi SHARED_DATA_ADDR call set_1byte_addr; - mvi CCHCNT, 1; - mvi CCSCBCTL, CCSCBRESET ret; - } else { - mvi DINDEX, HADDR; - mvi SHARED_DATA_ADDR call set_1byte_addr; - mvi 1 call set_hcnt; - mvi DFCNTRL, FIFORESET ret; - } - -post_byte: - if ((ahc->features & AHC_CMD_CHAN) != 0) { - bmov CCSCBRAM, SINDEX, 1; - or CCSCBCTL, CCSCBEN|CCSCBRESET; - test CCSCBCTL, CCSCBDONE jz .; - clr CCSCBCTL ret; - } else { - mov DFDAT, SINDEX; - or DFCNTRL, HDMAEN|FIFOFLUSH; - jmp dma_finish; - } - -phase_lock_perr: - mvi PERR_DETECTED call set_seqint; -phase_lock: - /* - * If there is a parity error, wait for the kernel to - * see the interrupt and prepare our message response - * before continuing. - */ - test SSTAT1, REQINIT jz phase_lock; - test SSTAT1, SCSIPERR jnz phase_lock_perr; -phase_lock_latch_phase: - if ((ahc->features & AHC_DT) == 0) { - and SCSISIGO, PHASE_MASK, SCSISIGI; - } - and LASTPHASE, PHASE_MASK, SCSISIGI ret; - -if ((ahc->features & AHC_CMD_CHAN) == 0) { -set_hcnt: - mov HCNT[0], SINDEX; -clear_hcnt: - clr HCNT[1]; - clr HCNT[2] ret; - -set_stcnt_from_hcnt: - mov STCNT[0], HCNT[0]; - mov STCNT[1], HCNT[1]; - mov STCNT[2], HCNT[2] ret; - -bcopy_8: - mov DINDIR, SINDIR; -bcopy_7: - mov DINDIR, SINDIR; - mov DINDIR, SINDIR; -bcopy_5: - mov DINDIR, SINDIR; -bcopy_4: - mov DINDIR, SINDIR; -bcopy_3: - mov DINDIR, SINDIR; - mov DINDIR, SINDIR; - mov DINDIR, SINDIR ret; -} - -if ((ahc->flags & AHC_TARGETROLE) != 0) { -/* - * Setup addr assuming that A is an index into - * an array of 32byte objects, SINDEX contains - * the base address of that array, and DINDEX - * contains the base address of the location - * to store the indexed address. - */ -set_32byte_addr: - shr ARG_2, 3, A; - shl A, 5; - jmp set_1byte_addr; -} - -/* - * Setup addr assuming that A is an index into - * an array of 64byte objects, SINDEX contains - * the base address of that array, and DINDEX - * contains the base address of the location - * to store the indexed address. - */ -set_64byte_addr: - shr ARG_2, 2, A; - shl A, 6; - -/* - * Setup addr assuming that A + (ARG_2 * 256) is an - * index into an array of 1byte objects, SINDEX contains - * the base address of that array, and DINDEX contains - * the base address of the location to store the computed - * address. - */ -set_1byte_addr: - add DINDIR, A, SINDIR; - mov A, ARG_2; - adc DINDIR, A, SINDIR; - clr A; - adc DINDIR, A, SINDIR; - adc DINDIR, A, SINDIR ret; - -/* - * Either post or fetch an SCB from host memory based on the - * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. - */ -dma_scb: - mov A, SINDEX; - if ((ahc->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi HSCB_ADDR call set_64byte_addr; - mov CCSCBPTR, SCBPTR; - test DMAPARAMS, DIRECTION jz dma_scb_tohost; - if ((ahc->flags & AHC_SCB_BTT) != 0) { - mvi CCHCNT, SCB_DOWNLOAD_SIZE_64; - } else { - mvi CCHCNT, SCB_DOWNLOAD_SIZE; - } - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; - jmp dma_scb_finish; -dma_scb_tohost: - mvi CCHCNT, SCB_UPLOAD_SIZE; - if ((ahc->features & AHC_ULTRA2) == 0) { - mvi CCSCBCTL, CCSCBRESET; - bmov CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE; - or CCSCBCTL, CCSCBEN|CCSCBRESET; - test CCSCBCTL, CCSCBDONE jz .; - } else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) { - mvi CCSCBCTL, CCARREN|CCSCBRESET; - cmp CCSCBCTL, ARRDONE|CCARREN jne .; - mvi CCHCNT, SCB_UPLOAD_SIZE; - mvi CCSCBCTL, CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; - } else { - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; - } -dma_scb_finish: - clr CCSCBCTL; - test CCSCBCTL, CCARREN|CCSCBEN jnz .; - ret; - } else { - mvi DINDEX, HADDR; - mvi HSCB_ADDR call set_64byte_addr; - mvi SCB_DOWNLOAD_SIZE call set_hcnt; - mov DFCNTRL, DMAPARAMS; - test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; - /* Fill it with the SCB data */ -copy_scb_tofifo: - mvi SINDEX, SCB_BASE; - add A, SCB_DOWNLOAD_SIZE, SINDEX; -copy_scb_tofifo_loop: - call copy_to_fifo_8; - cmp SINDEX, A jne copy_scb_tofifo_loop; - or DFCNTRL, HDMAEN|FIFOFLUSH; - jmp dma_finish; -dma_scb_fromhost: - mvi DINDEX, SCB_BASE; - if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) { - /* - * The PCI module will only issue a PCI - * retry if the data FIFO is empty. If the - * host disconnects in the middle of a - * transfer, we must empty the fifo of all - * available data to force the chip to - * continue the transfer. This does not - * happen for SCSI transfers as the SCSI module - * will drain the FIFO as data are made available. - * When the hang occurs, we know that a multiple - * of 8 bytes is in the FIFO because the PCI - * module has an 8 byte input latch that only - * dumps to the FIFO when HCNT == 0 or the - * latch is full. - */ - clr A; - /* Wait for at least 8 bytes of data to arrive. */ -dma_scb_hang_fifo: - test DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo; -dma_scb_hang_wait: - test DFSTATUS, MREQPEND jnz dma_scb_hang_wait; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - /* - * The PCI module no longer intends to perform - * a PCI transaction. Drain the fifo. - */ -dma_scb_hang_dma_drain_fifo: - not A, HCNT; - add A, SCB_DOWNLOAD_SIZE+SCB_BASE+1; - and A, ~0x7; - mov DINDIR,DFDAT; - cmp DINDEX, A jne . - 1; - cmp DINDEX, SCB_DOWNLOAD_SIZE+SCB_BASE - je dma_finish_nowait; - /* Restore A as the lines left to transfer. */ - add A, -SCB_BASE, DINDEX; - shr A, 3; - jmp dma_scb_hang_fifo; -dma_scb_hang_dma_done: - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - add SEQADDR0, A; - } else { - call dma_finish; - } - call dfdat_in_8; - call dfdat_in_8; - call dfdat_in_8; -dfdat_in_8: - mov DINDIR,DFDAT; -dfdat_in_7: - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; -dfdat_in_2: - mov DINDIR,DFDAT; - mov DINDIR,DFDAT ret; - } - -copy_to_fifo_8: - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; -copy_to_fifo_6: - mov DFDAT,SINDIR; -copy_to_fifo_5: - mov DFDAT,SINDIR; -copy_to_fifo_4: - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR ret; - -/* - * Wait for DMA from host memory to data FIFO to complete, then disable - * DMA and wait for it to acknowledge that it's off. - */ -dma_finish: - test DFSTATUS,HDONE jz dma_finish; -dma_finish_nowait: - /* Turn off DMA */ - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - ret; - -/* - * Restore an SCB that failed to match an incoming reselection - * to the correct/safe state. If the SCB is for a disconnected - * transaction, it must be returned to the disconnected list. - * If it is not in the disconnected state, it must be free. - */ -cleanup_scb: - if ((ahc->flags & AHC_PAGESCBS) != 0) { - test SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list; - } -add_scb_to_free_list: - if ((ahc->flags & AHC_PAGESCBS) != 0) { -BEGIN_CRITICAL; - mov SCB_NEXT, FREE_SCBH; - mvi SCB_TAG, SCB_LIST_NULL; - mov FREE_SCBH, SCBPTR ret; -END_CRITICAL; - } else { - mvi SCB_TAG, SCB_LIST_NULL ret; - } - -if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { -set_hhaddr: - or DSCOMMAND1, HADDLDSEL0; - and HADDR, SG_HIGH_ADDR_BITS, SINDEX; - and DSCOMMAND1, ~HADDLDSEL0 ret; -} - -if ((ahc->flags & AHC_PAGESCBS) != 0) { -get_free_or_disc_scb: -BEGIN_CRITICAL; - cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; - cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; -return_error: - mvi NO_FREE_SCB call set_seqint; - mvi SINDEX, SCB_LIST_NULL ret; -dequeue_disc_scb: - mov SCBPTR, DISCONNECTED_SCBH; - mov DISCONNECTED_SCBH, SCB_NEXT; -END_CRITICAL; - mvi DMAPARAMS, FIFORESET; - mov SCB_TAG jmp dma_scb; -BEGIN_CRITICAL; -dequeue_free_scb: - mov SCBPTR, FREE_SCBH; - mov FREE_SCBH, SCB_NEXT ret; -END_CRITICAL; - -add_scb_to_disc_list: -/* - * Link this SCB into the DISCONNECTED list. This list holds the - * candidates for paging out an SCB if one is needed for a new command. - * Modifying the disconnected list is a critical(pause dissabled) section. - */ -BEGIN_CRITICAL; - mov SCB_NEXT, DISCONNECTED_SCBH; - mov DISCONNECTED_SCBH, SCBPTR ret; -END_CRITICAL; -} -set_seqint: - mov INTSTAT, SINDEX; - nop; -return: - ret; diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c deleted file mode 100644 index 9e85a7ef..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Interface for the 93C66/56/46/26/06 serial eeprom parts. - * - * Copyright (c) 1995, 1996 Daniel M. Eischen - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL"). - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#19 $ - */ - -/* - * The instruction set of the 93C66/56/46/26/06 chips are as follows: - * - * Start OP * - * Function Bit Code Address** Data Description - * ------------------------------------------------------------------- - * READ 1 10 A5 - A0 Reads data stored in memory, - * starting at specified address - * EWEN 1 00 11XXXX Write enable must precede - * all programming modes - * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 - * WRITE 1 01 A5 - A0 D15 - D0 Writes register - * ERAL 1 00 10XXXX Erase all registers - * WRAL 1 00 01XXXX D15 - D0 Writes to all registers - * EWDS 1 00 00XXXX Disables all programming - * instructions - * *Note: A value of X for address is a don't care condition. - * **Note: There are 8 address bits for the 93C56/66 chips unlike - * the 93C46/26/06 chips which have 6 address bits. - * - * The 93C46 has a four wire interface: clock, chip select, data in, and - * data out. In order to perform one of the above functions, you need - * to enable the chip select for a clock period (typically a minimum of - * 1 usec, with the clock high and low a minimum of 750 and 250 nsec - * respectively). While the chip select remains high, you can clock in - * the instructions (above) starting with the start bit, followed by the - * OP code, Address, and Data (if needed). For the READ instruction, the - * requested 16-bit register contents is read from the data out line but - * is preceded by an initial zero (leading 0, followed by 16-bits, MSB - * first). The clock cycling from low to high initiates the next data - * bit to be sent from the chip. - */ - -#ifdef __linux__ -#include "aic7xxx_osm.h" -#include "aic7xxx_inline.h" -#include "aic7xxx_93cx6.h" -#else -#include -#include -#include -#endif - -/* - * Right now, we only have to read the SEEPROM. But we make it easier to - * add other 93Cx6 functions. - */ -struct seeprom_cmd { - uint8_t len; - uint8_t bits[11]; -}; - -/* Short opcodes for the c46 */ -static const struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; -static const struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; - -/* Long opcodes for the C56/C66 */ -static const struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; -static const struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; - -/* Common opcodes */ -static const struct seeprom_cmd seeprom_write = {3, {1, 0, 1}}; -static const struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; - -/* - * Wait for the SEERDY to go high; about 800 ns. - */ -#define CLOCK_PULSE(sd, rdy) \ - while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) { \ - ; /* Do nothing */ \ - } \ - (void)SEEPROM_INB(sd); /* Clear clock */ - -/* - * Send a START condition and the given command - */ -static void -send_seeprom_cmd(struct seeprom_descriptor *sd, const struct seeprom_cmd *cmd) -{ - uint8_t temp; - int i = 0; - - /* Send chip select for one clock cycle. */ - temp = sd->sd_MS ^ sd->sd_CS; - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - - for (i = 0; i < cmd->len; i++) { - if (cmd->bits[i] != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if (cmd->bits[i] != 0) - temp ^= sd->sd_DO; - } -} - -/* - * Clear CS put the chip in the reset state, where it can wait for new commands. - */ -static void -reset_seeprom(struct seeprom_descriptor *sd) -{ - uint8_t temp; - - temp = sd->sd_MS; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); -} - -/* - * Read the serial EEPROM and returns 1 if successful and 0 if - * not successful. - */ -int -ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, - u_int start_addr, u_int count) -{ - int i = 0; - u_int k = 0; - uint16_t v; - uint8_t temp; - - /* - * Read the requested registers of the seeprom. The loop - * will range from 0 to count-1. - */ - for (k = start_addr; k < count + start_addr; k++) { - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - send_seeprom_cmd(sd, &seeprom_read); - - /* Send the 6 or 8 bit address (MSB first, LSB last). */ - temp = sd->sd_MS ^ sd->sd_CS; - for (i = (sd->sd_chip - 1); i >= 0; i--) { - if ((k & (1 << i)) != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if ((k & (1 << i)) != 0) - temp ^= sd->sd_DO; - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - v = 0; - for (i = 16; i >= 0; i--) { - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - v <<= 1; - if (SEEPROM_DATA_INB(sd) & sd->sd_DI) - v |= 1; - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - } - - buf[k - start_addr] = v; - - /* Reset the chip select for the next command cycle. */ - reset_seeprom(sd); - } -#ifdef AHC_DUMP_EEPROM - printk("\nSerial EEPROM:\n\t"); - for (k = 0; k < count; k = k + 1) { - if (((k % 8) == 0) && (k != 0)) { - printk(KERN_CONT "\n\t"); - } - printk(KERN_CONT " 0x%x", buf[k]); - } - printk(KERN_CONT "\n"); -#endif - return (1); -} - -/* - * Write the serial EEPROM and return 1 if successful and 0 if - * not successful. - */ -int -ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, - u_int start_addr, u_int count) -{ - const struct seeprom_cmd *ewen, *ewds; - uint16_t v; - uint8_t temp; - int i, k; - - /* Place the chip into write-enable mode */ - if (sd->sd_chip == C46) { - ewen = &seeprom_ewen; - ewds = &seeprom_ewds; - } else if (sd->sd_chip == C56_66) { - ewen = &seeprom_long_ewen; - ewds = &seeprom_long_ewds; - } else { - printk("ahc_write_seeprom: unsupported seeprom type %d\n", - sd->sd_chip); - return (0); - } - - send_seeprom_cmd(sd, ewen); - reset_seeprom(sd); - - /* Write all requested data out to the seeprom. */ - temp = sd->sd_MS ^ sd->sd_CS; - for (k = start_addr; k < count + start_addr; k++) { - /* Send the write command */ - send_seeprom_cmd(sd, &seeprom_write); - - /* Send the 6 or 8 bit address (MSB first). */ - for (i = (sd->sd_chip - 1); i >= 0; i--) { - if ((k & (1 << i)) != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if ((k & (1 << i)) != 0) - temp ^= sd->sd_DO; - } - - /* Write the 16 bit value, MSB first */ - v = buf[k - start_addr]; - for (i = 15; i >= 0; i--) { - if ((v & (1 << i)) != 0) - temp ^= sd->sd_DO; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - if ((v & (1 << i)) != 0) - temp ^= sd->sd_DO; - } - - /* Wait for the chip to complete the write */ - temp = sd->sd_MS; - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - temp = sd->sd_MS ^ sd->sd_CS; - do { - SEEPROM_OUTB(sd, temp); - CLOCK_PULSE(sd, sd->sd_RDY); - SEEPROM_OUTB(sd, temp ^ sd->sd_CK); - CLOCK_PULSE(sd, sd->sd_RDY); - } while ((SEEPROM_DATA_INB(sd) & sd->sd_DI) == 0); - - reset_seeprom(sd); - } - - /* Put the chip back into write-protect mode */ - send_seeprom_cmd(sd, ewds); - reset_seeprom(sd); - - return (1); -} - -int -ahc_verify_cksum(struct seeprom_config *sc) -{ - int i; - int maxaddr; - uint32_t checksum; - uint16_t *scarray; - - maxaddr = (sizeof(*sc)/2) - 1; - checksum = 0; - scarray = (uint16_t *)sc; - - for (i = 0; i < maxaddr; i++) - checksum = checksum + scarray[i]; - if (checksum == 0 - || (checksum & 0xFFFF) != sc->checksum) { - return (0); - } else { - return(1); - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h deleted file mode 100644 index 859c43cc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_93cx6.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Interface to the 93C46/56 serial EEPROM that is used to store BIOS - * settings for the aic7xxx based adaptec SCSI controllers. It can - * also be used for 93C26 and 93C06 serial EEPROMS. - * - * Copyright (c) 1994, 1995, 2000 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.h#12 $ - * - * $FreeBSD$ - */ -#ifndef _AIC7XXX_93CX6_H_ -#define _AIC7XXX_93CX6_H_ - -typedef enum { - C46 = 6, - C56_66 = 8 -} seeprom_chip_t; - -struct seeprom_descriptor { - struct ahc_softc *sd_ahc; - u_int sd_control_offset; - u_int sd_status_offset; - u_int sd_dataout_offset; - seeprom_chip_t sd_chip; - uint16_t sd_MS; - uint16_t sd_RDY; - uint16_t sd_CS; - uint16_t sd_CK; - uint16_t sd_DO; - uint16_t sd_DI; -}; - -/* - * This function will read count 16-bit words from the serial EEPROM and - * return their value in buf. The port address of the aic7xxx serial EEPROM - * control register is passed in as offset. The following parameters are - * also passed in: - * - * CS - Chip select - * CK - Clock - * DO - Data out - * DI - Data in - * RDY - SEEPROM ready - * MS - Memory port mode select - * - * A failed read attempt returns 0, and a successful read returns 1. - */ - -#define SEEPROM_INB(sd) \ - ahc_inb(sd->sd_ahc, sd->sd_control_offset) -#define SEEPROM_OUTB(sd, value) \ -do { \ - ahc_outb(sd->sd_ahc, sd->sd_control_offset, value); \ - ahc_flush_device_writes(sd->sd_ahc); \ -} while(0) - -#define SEEPROM_STATUS_INB(sd) \ - ahc_inb(sd->sd_ahc, sd->sd_status_offset) -#define SEEPROM_DATA_INB(sd) \ - ahc_inb(sd->sd_ahc, sd->sd_dataout_offset) - -int ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, - u_int start_addr, u_int count); -int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, - u_int start_addr, u_int count); -int ahc_verify_cksum(struct seeprom_config *sc); - -#endif /* _AIC7XXX_93CX6_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_core.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_core.c deleted file mode 100644 index 10172a3a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_core.c +++ /dev/null @@ -1,7973 +0,0 @@ -/* - * Core routines and tables shareable across OS platforms. - * - * Copyright (c) 1994-2002 Justin T. Gibbs. - * Copyright (c) 2000-2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $ - */ - -#ifdef __linux__ -#include "aic7xxx_osm.h" -#include "aic7xxx_inline.h" -#include "aicasm/aicasm_insformat.h" -#else -#include -#include -#include -#endif - -/***************************** Lookup Tables **********************************/ -static const char *const ahc_chip_names[] = { - "NONE", - "aic7770", - "aic7850", - "aic7855", - "aic7859", - "aic7860", - "aic7870", - "aic7880", - "aic7895", - "aic7895C", - "aic7890/91", - "aic7896/97", - "aic7892", - "aic7899" -}; -static const u_int num_chip_names = ARRAY_SIZE(ahc_chip_names); - -/* - * Hardware error codes. - */ -struct ahc_hard_error_entry { - uint8_t errno; - const char *errmesg; -}; - -static const struct ahc_hard_error_entry ahc_hard_errors[] = { - { ILLHADDR, "Illegal Host Access" }, - { ILLSADDR, "Illegal Sequencer Address referrenced" }, - { ILLOPCODE, "Illegal Opcode in sequencer program" }, - { SQPARERR, "Sequencer Parity Error" }, - { DPARERR, "Data-path Parity Error" }, - { MPARERR, "Scratch or SCB Memory Parity Error" }, - { PCIERRSTAT, "PCI Error detected" }, - { CIOPARERR, "CIOBUS Parity Error" }, -}; -static const u_int num_errors = ARRAY_SIZE(ahc_hard_errors); - -static const struct ahc_phase_table_entry ahc_phase_table[] = -{ - { P_DATAOUT, MSG_NOOP, "in Data-out phase" }, - { P_DATAIN, MSG_INITIATOR_DET_ERR, "in Data-in phase" }, - { P_DATAOUT_DT, MSG_NOOP, "in DT Data-out phase" }, - { P_DATAIN_DT, MSG_INITIATOR_DET_ERR, "in DT Data-in phase" }, - { P_COMMAND, MSG_NOOP, "in Command phase" }, - { P_MESGOUT, MSG_NOOP, "in Message-out phase" }, - { P_STATUS, MSG_INITIATOR_DET_ERR, "in Status phase" }, - { P_MESGIN, MSG_PARITY_ERROR, "in Message-in phase" }, - { P_BUSFREE, MSG_NOOP, "while idle" }, - { 0, MSG_NOOP, "in unknown phase" } -}; - -/* - * In most cases we only wish to itterate over real phases, so - * exclude the last element from the count. - */ -static const u_int num_phases = ARRAY_SIZE(ahc_phase_table) - 1; - -/* - * Valid SCSIRATE values. (p. 3-17) - * Provides a mapping of tranfer periods in ns to the proper value to - * stick in the scsixfer reg. - */ -static const struct ahc_syncrate ahc_syncrates[] = -{ - /* ultra2 fast/ultra period rate */ - { 0x42, 0x000, 9, "80.0" }, - { 0x03, 0x000, 10, "40.0" }, - { 0x04, 0x000, 11, "33.0" }, - { 0x05, 0x100, 12, "20.0" }, - { 0x06, 0x110, 15, "16.0" }, - { 0x07, 0x120, 18, "13.4" }, - { 0x08, 0x000, 25, "10.0" }, - { 0x19, 0x010, 31, "8.0" }, - { 0x1a, 0x020, 37, "6.67" }, - { 0x1b, 0x030, 43, "5.7" }, - { 0x1c, 0x040, 50, "5.0" }, - { 0x00, 0x050, 56, "4.4" }, - { 0x00, 0x060, 62, "4.0" }, - { 0x00, 0x070, 68, "3.6" }, - { 0x00, 0x000, 0, NULL } -}; - -/* Our Sequencer Program */ -#include "aic7xxx_seq.h" - -/**************************** Function Declarations ***************************/ -static void ahc_force_renegotiation(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static struct ahc_tmode_tstate* - ahc_alloc_tstate(struct ahc_softc *ahc, - u_int scsi_id, char channel); -#ifdef AHC_TARGET_MODE -static void ahc_free_tstate(struct ahc_softc *ahc, - u_int scsi_id, char channel, int force); -#endif -static const struct ahc_syncrate* - ahc_devlimited_syncrate(struct ahc_softc *ahc, - struct ahc_initiator_tinfo *, - u_int *period, - u_int *ppr_options, - role_t role); -static void ahc_update_pending_scbs(struct ahc_softc *ahc); -static void ahc_fetch_devinfo(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_scb_devinfo(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct scb *scb); -static void ahc_assert_atn(struct ahc_softc *ahc); -static void ahc_setup_initiator_msgout(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct scb *scb); -static void ahc_build_transfer_msg(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_construct_sdtr(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - u_int period, u_int offset); -static void ahc_construct_wdtr(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - u_int bus_width); -static void ahc_construct_ppr(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - u_int period, u_int offset, - u_int bus_width, u_int ppr_options); -static void ahc_clear_msg_state(struct ahc_softc *ahc); -static void ahc_handle_proto_violation(struct ahc_softc *ahc); -static void ahc_handle_message_phase(struct ahc_softc *ahc); -typedef enum { - AHCMSG_1B, - AHCMSG_2B, - AHCMSG_EXT -} ahc_msgtype; -static int ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, - u_int msgval, int full); -static int ahc_parse_msg(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static int ahc_handle_msg_reject(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_handle_ign_wide_residue(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_reinitialize_dataptrs(struct ahc_softc *ahc); -static void ahc_handle_devreset(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - cam_status status, char *message, - int verbose_level); -#ifdef AHC_TARGET_MODE -static void ahc_setup_target_msgin(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo, - struct scb *scb); -#endif - -static bus_dmamap_callback_t ahc_dmamap_cb; -static void ahc_build_free_scb_list(struct ahc_softc *ahc); -static int ahc_init_scbdata(struct ahc_softc *ahc); -static void ahc_fini_scbdata(struct ahc_softc *ahc); -static void ahc_qinfifo_requeue(struct ahc_softc *ahc, - struct scb *prev_scb, - struct scb *scb); -static int ahc_qinfifo_count(struct ahc_softc *ahc); -static u_int ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, - u_int prev, u_int scbptr); -static void ahc_add_curscb_to_free_list(struct ahc_softc *ahc); -static u_int ahc_rem_wscb(struct ahc_softc *ahc, - u_int scbpos, u_int prev); -static void ahc_reset_current_bus(struct ahc_softc *ahc); -#ifdef AHC_DUMP_SEQ -static void ahc_dumpseq(struct ahc_softc *ahc); -#endif -static int ahc_loadseq(struct ahc_softc *ahc); -static int ahc_check_patch(struct ahc_softc *ahc, - const struct patch **start_patch, - u_int start_instr, u_int *skip_addr); -static void ahc_download_instr(struct ahc_softc *ahc, - u_int instrptr, uint8_t *dconsts); -#ifdef AHC_TARGET_MODE -static void ahc_queue_lstate_event(struct ahc_softc *ahc, - struct ahc_tmode_lstate *lstate, - u_int initiator_id, - u_int event_type, - u_int event_arg); -static void ahc_update_scsiid(struct ahc_softc *ahc, - u_int targid_mask); -static int ahc_handle_target_cmd(struct ahc_softc *ahc, - struct target_cmd *cmd); -#endif - -static u_int ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl); -static void ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl); -static void ahc_busy_tcl(struct ahc_softc *ahc, - u_int tcl, u_int busyid); - -/************************** SCB and SCB queue management **********************/ -static void ahc_run_untagged_queues(struct ahc_softc *ahc); -static void ahc_run_untagged_queue(struct ahc_softc *ahc, - struct scb_tailq *queue); - -/****************************** Initialization ********************************/ -static void ahc_alloc_scbs(struct ahc_softc *ahc); -static void ahc_shutdown(void *arg); - -/*************************** Interrupt Services *******************************/ -static void ahc_clear_intstat(struct ahc_softc *ahc); -static void ahc_run_qoutfifo(struct ahc_softc *ahc); -#ifdef AHC_TARGET_MODE -static void ahc_run_tqinfifo(struct ahc_softc *ahc, int paused); -#endif -static void ahc_handle_brkadrint(struct ahc_softc *ahc); -static void ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat); -static void ahc_handle_scsiint(struct ahc_softc *ahc, - u_int intstat); -static void ahc_clear_critical_section(struct ahc_softc *ahc); - -/***************************** Error Recovery *********************************/ -static void ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb); -static int ahc_abort_scbs(struct ahc_softc *ahc, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status); -static void ahc_calc_residual(struct ahc_softc *ahc, - struct scb *scb); - -/*********************** Untagged Transaction Routines ************************/ -static inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc); -static inline void ahc_release_untagged_queues(struct ahc_softc *ahc); - -/* - * Block our completion routine from starting the next untagged - * transaction for this target or target lun. - */ -static inline void -ahc_freeze_untagged_queues(struct ahc_softc *ahc) -{ - if ((ahc->flags & AHC_SCB_BTT) == 0) - ahc->untagged_queue_lock++; -} - -/* - * Allow the next untagged transaction for this target or target lun - * to be executed. We use a counting semaphore to allow the lock - * to be acquired recursively. Once the count drops to zero, the - * transaction queues will be run. - */ -static inline void -ahc_release_untagged_queues(struct ahc_softc *ahc) -{ - if ((ahc->flags & AHC_SCB_BTT) == 0) { - ahc->untagged_queue_lock--; - if (ahc->untagged_queue_lock == 0) - ahc_run_untagged_queues(ahc); - } -} - -/************************* Sequencer Execution Control ************************/ -/* - * Work around any chip bugs related to halting sequencer execution. - * On Ultra2 controllers, we must clear the CIOBUS stretch signal by - * reading a register that will set this signal and deassert it. - * Without this workaround, if the chip is paused, by an interrupt or - * manual pause while accessing scb ram, accesses to certain registers - * will hang the system (infinite pci retries). - */ -static void -ahc_pause_bug_fix(struct ahc_softc *ahc) -{ - if ((ahc->features & AHC_ULTRA2) != 0) - (void)ahc_inb(ahc, CCSCBCTL); -} - -/* - * Determine whether the sequencer has halted code execution. - * Returns non-zero status if the sequencer is stopped. - */ -int -ahc_is_paused(struct ahc_softc *ahc) -{ - return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0); -} - -/* - * Request that the sequencer stop and wait, indefinitely, for it - * to stop. The sequencer will only acknowledge that it is paused - * once it has reached an instruction boundary and PAUSEDIS is - * cleared in the SEQCTL register. The sequencer may use PAUSEDIS - * for critical sections. - */ -void -ahc_pause(struct ahc_softc *ahc) -{ - ahc_outb(ahc, HCNTRL, ahc->pause); - - /* - * Since the sequencer can disable pausing in a critical section, we - * must loop until it actually stops. - */ - while (ahc_is_paused(ahc) == 0) - ; - - ahc_pause_bug_fix(ahc); -} - -/* - * Allow the sequencer to continue program execution. - * We check here to ensure that no additional interrupt - * sources that would cause the sequencer to halt have been - * asserted. If, for example, a SCSI bus reset is detected - * while we are fielding a different, pausing, interrupt type, - * we don't want to release the sequencer before going back - * into our interrupt handler and dealing with this new - * condition. - */ -void -ahc_unpause(struct ahc_softc *ahc) -{ - if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0) - ahc_outb(ahc, HCNTRL, ahc->unpause); -} - -/************************** Memory mapping routines ***************************/ -static struct ahc_dma_seg * -ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr) -{ - int sg_index; - - sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg); - /* sg_list_phys points to entry 1, not 0 */ - sg_index++; - - return (&scb->sg_list[sg_index]); -} - -static uint32_t -ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg) -{ - int sg_index; - - /* sg_list_phys points to entry 1, not 0 */ - sg_index = sg - &scb->sg_list[1]; - - return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list))); -} - -static uint32_t -ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index) -{ - return (ahc->scb_data->hscb_busaddr - + (sizeof(struct hardware_scb) * index)); -} - -static void -ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op) -{ - ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat, - ahc->scb_data->hscb_dmamap, - /*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb), - /*len*/sizeof(*scb->hscb), op); -} - -void -ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op) -{ - if (scb->sg_count == 0) - return; - - ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap, - /*offset*/(scb->sg_list - scb->sg_map->sg_vaddr) - * sizeof(struct ahc_dma_seg), - /*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op); -} - -#ifdef AHC_TARGET_MODE -static uint32_t -ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index) -{ - return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo); -} -#endif - -/*********************** Miscellaneous Support Functions ***********************/ -/* - * Determine whether the sequencer reported a residual - * for this SCB/transaction. - */ -static void -ahc_update_residual(struct ahc_softc *ahc, struct scb *scb) -{ - uint32_t sgptr; - - sgptr = ahc_le32toh(scb->hscb->sgptr); - if ((sgptr & SG_RESID_VALID) != 0) - ahc_calc_residual(ahc, scb); -} - -/* - * Return pointers to the transfer negotiation information - * for the specified our_id/remote_id pair. - */ -struct ahc_initiator_tinfo * -ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id, - u_int remote_id, struct ahc_tmode_tstate **tstate) -{ - /* - * Transfer data structures are stored from the perspective - * of the target role. Since the parameters for a connection - * in the initiator role to a given target are the same as - * when the roles are reversed, we pretend we are the target. - */ - if (channel == 'B') - our_id += 8; - *tstate = ahc->enabled_targets[our_id]; - return (&(*tstate)->transinfo[remote_id]); -} - -uint16_t -ahc_inw(struct ahc_softc *ahc, u_int port) -{ - uint16_t r = ahc_inb(ahc, port+1) << 8; - return r | ahc_inb(ahc, port); -} - -void -ahc_outw(struct ahc_softc *ahc, u_int port, u_int value) -{ - ahc_outb(ahc, port, value & 0xFF); - ahc_outb(ahc, port+1, (value >> 8) & 0xFF); -} - -uint32_t -ahc_inl(struct ahc_softc *ahc, u_int port) -{ - return ((ahc_inb(ahc, port)) - | (ahc_inb(ahc, port+1) << 8) - | (ahc_inb(ahc, port+2) << 16) - | (ahc_inb(ahc, port+3) << 24)); -} - -void -ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value) -{ - ahc_outb(ahc, port, (value) & 0xFF); - ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF); - ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF); - ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF); -} - -uint64_t -ahc_inq(struct ahc_softc *ahc, u_int port) -{ - return ((ahc_inb(ahc, port)) - | (ahc_inb(ahc, port+1) << 8) - | (ahc_inb(ahc, port+2) << 16) - | (ahc_inb(ahc, port+3) << 24) - | (((uint64_t)ahc_inb(ahc, port+4)) << 32) - | (((uint64_t)ahc_inb(ahc, port+5)) << 40) - | (((uint64_t)ahc_inb(ahc, port+6)) << 48) - | (((uint64_t)ahc_inb(ahc, port+7)) << 56)); -} - -void -ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value) -{ - ahc_outb(ahc, port, value & 0xFF); - ahc_outb(ahc, port+1, (value >> 8) & 0xFF); - ahc_outb(ahc, port+2, (value >> 16) & 0xFF); - ahc_outb(ahc, port+3, (value >> 24) & 0xFF); - ahc_outb(ahc, port+4, (value >> 32) & 0xFF); - ahc_outb(ahc, port+5, (value >> 40) & 0xFF); - ahc_outb(ahc, port+6, (value >> 48) & 0xFF); - ahc_outb(ahc, port+7, (value >> 56) & 0xFF); -} - -/* - * Get a free scb. If there are none, see if we can allocate a new SCB. - */ -struct scb * -ahc_get_scb(struct ahc_softc *ahc) -{ - struct scb *scb; - - if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) { - ahc_alloc_scbs(ahc); - scb = SLIST_FIRST(&ahc->scb_data->free_scbs); - if (scb == NULL) - return (NULL); - } - SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle); - return (scb); -} - -/* - * Return an SCB resource to the free list. - */ -void -ahc_free_scb(struct ahc_softc *ahc, struct scb *scb) -{ - struct hardware_scb *hscb; - - hscb = scb->hscb; - /* Clean up for the next user */ - ahc->scb_data->scbindex[hscb->tag] = NULL; - scb->flags = SCB_FREE; - hscb->control = 0; - - SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle); - - /* Notify the OSM that a resource is now available. */ - ahc_platform_scb_free(ahc, scb); -} - -struct scb * -ahc_lookup_scb(struct ahc_softc *ahc, u_int tag) -{ - struct scb* scb; - - scb = ahc->scb_data->scbindex[tag]; - if (scb != NULL) - ahc_sync_scb(ahc, scb, - BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE); - return (scb); -} - -static void -ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb) -{ - struct hardware_scb *q_hscb; - u_int saved_tag; - - /* - * Our queuing method is a bit tricky. The card - * knows in advance which HSCB to download, and we - * can't disappoint it. To achieve this, the next - * SCB to download is saved off in ahc->next_queued_scb. - * When we are called to queue "an arbitrary scb", - * we copy the contents of the incoming HSCB to the one - * the sequencer knows about, swap HSCB pointers and - * finally assign the SCB to the tag indexed location - * in the scb_array. This makes sure that we can still - * locate the correct SCB by SCB_TAG. - */ - q_hscb = ahc->next_queued_scb->hscb; - saved_tag = q_hscb->tag; - memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb)); - if ((scb->flags & SCB_CDB32_PTR) != 0) { - q_hscb->shared_data.cdb_ptr = - ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag) - + offsetof(struct hardware_scb, cdb32)); - } - q_hscb->tag = saved_tag; - q_hscb->next = scb->hscb->tag; - - /* Now swap HSCB pointers. */ - ahc->next_queued_scb->hscb = scb->hscb; - scb->hscb = q_hscb; - - /* Now define the mapping from tag to SCB in the scbindex */ - ahc->scb_data->scbindex[scb->hscb->tag] = scb; -} - -/* - * Tell the sequencer about a new transaction to execute. - */ -void -ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb) -{ - ahc_swap_with_next_hscb(ahc, scb); - - if (scb->hscb->tag == SCB_LIST_NULL - || scb->hscb->next == SCB_LIST_NULL) - panic("Attempt to queue invalid SCB tag %x:%x\n", - scb->hscb->tag, scb->hscb->next); - - /* - * Setup data "oddness". - */ - scb->hscb->lun &= LID; - if (ahc_get_transfer_length(scb) & 0x1) - scb->hscb->lun |= SCB_XFERLEN_ODD; - - /* - * Keep a history of SCBs we've downloaded in the qinfifo. - */ - ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; - - /* - * Make sure our data is consistent from the - * perspective of the adapter. - */ - ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - - /* Tell the adapter about the newly queued SCB */ - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); - } else { - if ((ahc->features & AHC_AUTOPAUSE) == 0) - ahc_pause(ahc); - ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); - if ((ahc->features & AHC_AUTOPAUSE) == 0) - ahc_unpause(ahc); - } -} - -struct scsi_sense_data * -ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb) -{ - int offset; - - offset = scb - ahc->scb_data->scbarray; - return (&ahc->scb_data->sense[offset]); -} - -static uint32_t -ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb) -{ - int offset; - - offset = scb - ahc->scb_data->scbarray; - return (ahc->scb_data->sense_busaddr - + (offset * sizeof(struct scsi_sense_data))); -} - -/************************** Interrupt Processing ******************************/ -static void -ahc_sync_qoutfifo(struct ahc_softc *ahc, int op) -{ - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, - /*offset*/0, /*len*/256, op); -} - -static void -ahc_sync_tqinfifo(struct ahc_softc *ahc, int op) -{ -#ifdef AHC_TARGET_MODE - if ((ahc->flags & AHC_TARGETROLE) != 0) { - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap, - ahc_targetcmd_offset(ahc, 0), - sizeof(struct target_cmd) * AHC_TMODE_CMDS, - op); - } -#endif -} - -/* - * See if the firmware has posted any completed commands - * into our in-core command complete fifos. - */ -#define AHC_RUN_QOUTFIFO 0x1 -#define AHC_RUN_TQINFIFO 0x2 -static u_int -ahc_check_cmdcmpltqueues(struct ahc_softc *ahc) -{ - u_int retval; - - retval = 0; - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, - /*offset*/ahc->qoutfifonext, /*len*/1, - BUS_DMASYNC_POSTREAD); - if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) - retval |= AHC_RUN_QOUTFIFO; -#ifdef AHC_TARGET_MODE - if ((ahc->flags & AHC_TARGETROLE) != 0 - && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) { - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap, - ahc_targetcmd_offset(ahc, ahc->tqinfifofnext), - /*len*/sizeof(struct target_cmd), - BUS_DMASYNC_POSTREAD); - if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0) - retval |= AHC_RUN_TQINFIFO; - } -#endif - return (retval); -} - -/* - * Catch an interrupt from the adapter - */ -int -ahc_intr(struct ahc_softc *ahc) -{ - u_int intstat; - - if ((ahc->pause & INTEN) == 0) { - /* - * Our interrupt is not enabled on the chip - * and may be disabled for re-entrancy reasons, - * so just return. This is likely just a shared - * interrupt. - */ - return (0); - } - /* - * Instead of directly reading the interrupt status register, - * infer the cause of the interrupt by checking our in-core - * completion queues. This avoids a costly PCI bus read in - * most cases. - */ - if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0 - && (ahc_check_cmdcmpltqueues(ahc) != 0)) - intstat = CMDCMPLT; - else { - intstat = ahc_inb(ahc, INTSTAT); - } - - if ((intstat & INT_PEND) == 0) { -#if AHC_PCI_CONFIG > 0 - if (ahc->unsolicited_ints > 500) { - ahc->unsolicited_ints = 0; - if ((ahc->chip & AHC_PCI) != 0 - && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0) - ahc->bus_intr(ahc); - } -#endif - ahc->unsolicited_ints++; - return (0); - } - ahc->unsolicited_ints = 0; - - if (intstat & CMDCMPLT) { - ahc_outb(ahc, CLRINT, CLRCMDINT); - - /* - * Ensure that the chip sees that we've cleared - * this interrupt before we walk the output fifo. - * Otherwise, we may, due to posted bus writes, - * clear the interrupt after we finish the scan, - * and after the sequencer has added new entries - * and asserted the interrupt again. - */ - ahc_flush_device_writes(ahc); - ahc_run_qoutfifo(ahc); -#ifdef AHC_TARGET_MODE - if ((ahc->flags & AHC_TARGETROLE) != 0) - ahc_run_tqinfifo(ahc, /*paused*/FALSE); -#endif - } - - /* - * Handle statuses that may invalidate our cached - * copy of INTSTAT separately. - */ - if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) { - /* Hot eject. Do nothing */ - } else if (intstat & BRKADRINT) { - ahc_handle_brkadrint(ahc); - } else if ((intstat & (SEQINT|SCSIINT)) != 0) { - - ahc_pause_bug_fix(ahc); - - if ((intstat & SEQINT) != 0) - ahc_handle_seqint(ahc, intstat); - - if ((intstat & SCSIINT) != 0) - ahc_handle_scsiint(ahc, intstat); - } - return (1); -} - -/************************* Sequencer Execution Control ************************/ -/* - * Restart the sequencer program from address zero - */ -static void -ahc_restart(struct ahc_softc *ahc) -{ - uint8_t sblkctl; - - ahc_pause(ahc); - - /* No more pending messages. */ - ahc_clear_msg_state(ahc); - - ahc_outb(ahc, SCSISIGO, 0); /* De-assert BSY */ - ahc_outb(ahc, MSG_OUT, MSG_NOOP); /* No message to send */ - ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); - ahc_outb(ahc, LASTPHASE, P_BUSFREE); - ahc_outb(ahc, SAVED_SCSIID, 0xFF); - ahc_outb(ahc, SAVED_LUN, 0xFF); - - /* - * Ensure that the sequencer's idea of TQINPOS - * matches our own. The sequencer increments TQINPOS - * only after it sees a DMA complete and a reset could - * occur before the increment leaving the kernel to believe - * the command arrived but the sequencer to not. - */ - ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); - - /* Always allow reselection */ - ahc_outb(ahc, SCSISEQ, - ahc_inb(ahc, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP)); - if ((ahc->features & AHC_CMD_CHAN) != 0) { - /* Ensure that no DMA operations are in progress */ - ahc_outb(ahc, CCSCBCNT, 0); - ahc_outb(ahc, CCSGCTL, 0); - ahc_outb(ahc, CCSCBCTL, 0); - } - /* - * If we were in the process of DMA'ing SCB data into - * an SCB, replace that SCB on the free list. This prevents - * an SCB leak. - */ - if ((ahc_inb(ahc, SEQ_FLAGS2) & SCB_DMA) != 0) { - ahc_add_curscb_to_free_list(ahc); - ahc_outb(ahc, SEQ_FLAGS2, - ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); - } - - /* - * Clear any pending sequencer interrupt. It is no - * longer relevant since we're resetting the Program - * Counter. - */ - ahc_outb(ahc, CLRINT, CLRSEQINT); - - ahc_outb(ahc, MWI_RESIDUAL, 0); - ahc_outb(ahc, SEQCTL, ahc->seqctl); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - - /* - * Take the LED out of diagnostic mode on PM resume, too - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON))); - - ahc_unpause(ahc); -} - -/************************* Input/Output Queues ********************************/ -static void -ahc_run_qoutfifo(struct ahc_softc *ahc) -{ - struct scb *scb; - u_int scb_index; - - ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD); - while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) { - - scb_index = ahc->qoutfifo[ahc->qoutfifonext]; - if ((ahc->qoutfifonext & 0x03) == 0x03) { - u_int modnext; - - /* - * Clear 32bits of QOUTFIFO at a time - * so that we don't clobber an incoming - * byte DMA to the array on architectures - * that only support 32bit load and store - * operations. - */ - modnext = ahc->qoutfifonext & ~0x3; - *((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL; - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap, - /*offset*/modnext, /*len*/4, - BUS_DMASYNC_PREREAD); - } - ahc->qoutfifonext++; - - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printk("%s: WARNING no command for scb %d " - "(cmdcmplt)\nQOUTPOS = %d\n", - ahc_name(ahc), scb_index, - (ahc->qoutfifonext - 1) & 0xFF); - continue; - } - - /* - * Save off the residual - * if there is one. - */ - ahc_update_residual(ahc, scb); - ahc_done(ahc, scb); - } -} - -static void -ahc_run_untagged_queues(struct ahc_softc *ahc) -{ - int i; - - for (i = 0; i < 16; i++) - ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]); -} - -static void -ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue) -{ - struct scb *scb; - - if (ahc->untagged_queue_lock != 0) - return; - - if ((scb = TAILQ_FIRST(queue)) != NULL - && (scb->flags & SCB_ACTIVE) == 0) { - scb->flags |= SCB_ACTIVE; - ahc_queue_scb(ahc, scb); - } -} - -/************************* Interrupt Handling *********************************/ -static void -ahc_handle_brkadrint(struct ahc_softc *ahc) -{ - /* - * We upset the sequencer :-( - * Lookup the error message - */ - int i; - int error; - - error = ahc_inb(ahc, ERROR); - for (i = 0; error != 1 && i < num_errors; i++) - error >>= 1; - printk("%s: brkadrint, %s at seqaddr = 0x%x\n", - ahc_name(ahc), ahc_hard_errors[i].errmesg, - ahc_inb(ahc, SEQADDR0) | - (ahc_inb(ahc, SEQADDR1) << 8)); - - ahc_dump_card_state(ahc); - - /* Tell everyone that this HBA is no longer available */ - ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN, - CAM_NO_HBA); - - /* Disable all interrupt sources by resetting the controller */ - ahc_shutdown(ahc); -} - -static void -ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat) -{ - struct scb *scb; - struct ahc_devinfo devinfo; - - ahc_fetch_devinfo(ahc, &devinfo); - - /* - * Clear the upper byte that holds SEQINT status - * codes and clear the SEQINT bit. We will unpause - * the sequencer, if appropriate, after servicing - * the request. - */ - ahc_outb(ahc, CLRINT, CLRSEQINT); - switch (intstat & SEQINT_MASK) { - case BAD_STATUS: - { - u_int scb_index; - struct hardware_scb *hscb; - - /* - * Set the default return value to 0 (don't - * send sense). The sense code will change - * this if needed. - */ - ahc_outb(ahc, RETURN_1, 0); - - /* - * The sequencer will notify us when a command - * has an error that would be of interest to - * the kernel. This allows us to leave the sequencer - * running in the common case of command completes - * without error. The sequencer will already have - * dma'd the SCB back up to us, so we can reference - * the in kernel copy directly. - */ - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - ahc_print_devinfo(ahc, &devinfo); - printk("ahc_intr - referenced scb " - "not valid during seqint 0x%x scb(%d)\n", - intstat, scb_index); - ahc_dump_card_state(ahc); - panic("for safety"); - goto unpause; - } - - hscb = scb->hscb; - - /* Don't want to clobber the original sense code */ - if ((scb->flags & SCB_SENSE) != 0) { - /* - * Clear the SCB_SENSE Flag and have - * the sequencer do a normal command - * complete. - */ - scb->flags &= ~SCB_SENSE; - ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); - break; - } - ahc_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR); - /* Freeze the queue until the client sees the error. */ - ahc_freeze_devq(ahc, scb); - ahc_freeze_scb(scb); - ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status); - switch (hscb->shared_data.status.scsi_status) { - case SCSI_STATUS_OK: - printk("%s: Interrupted for status of 0???\n", - ahc_name(ahc)); - break; - case SCSI_STATUS_CMD_TERMINATED: - case SCSI_STATUS_CHECK_COND: - { - struct ahc_dma_seg *sg; - struct scsi_sense *sc; - struct ahc_initiator_tinfo *targ_info; - struct ahc_tmode_tstate *tstate; - struct ahc_transinfo *tinfo; -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOW_SENSE) { - ahc_print_path(ahc, scb); - printk("SCB %d: requests Check Status\n", - scb->hscb->tag); - } -#endif - - if (ahc_perform_autosense(scb) == 0) - break; - - targ_info = ahc_fetch_transinfo(ahc, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, - &tstate); - tinfo = &targ_info->curr; - sg = scb->sg_list; - sc = (struct scsi_sense *)(&hscb->shared_data.cdb); - /* - * Save off the residual if there is one. - */ - ahc_update_residual(ahc, scb); -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOW_SENSE) { - ahc_print_path(ahc, scb); - printk("Sending Sense\n"); - } -#endif - sg->addr = ahc_get_sense_bufaddr(ahc, scb); - sg->len = ahc_get_sense_bufsize(ahc, scb); - sg->len |= AHC_DMA_LAST_SEG; - - /* Fixup byte order */ - sg->addr = ahc_htole32(sg->addr); - sg->len = ahc_htole32(sg->len); - - sc->opcode = REQUEST_SENSE; - sc->byte2 = 0; - if (tinfo->protocol_version <= SCSI_REV_2 - && SCB_GET_LUN(scb) < 8) - sc->byte2 = SCB_GET_LUN(scb) << 5; - sc->unused[0] = 0; - sc->unused[1] = 0; - sc->length = sg->len; - sc->control = 0; - - /* - * We can't allow the target to disconnect. - * This will be an untagged transaction and - * having the target disconnect will make this - * transaction indestinguishable from outstanding - * tagged transactions. - */ - hscb->control = 0; - - /* - * This request sense could be because the - * the device lost power or in some other - * way has lost our transfer negotiations. - * Renegotiate if appropriate. Unit attention - * errors will be reported before any data - * phases occur. - */ - if (ahc_get_residual(scb) - == ahc_get_transfer_length(scb)) { - ahc_update_neg_request(ahc, &devinfo, - tstate, targ_info, - AHC_NEG_IF_NON_ASYNC); - } - if (tstate->auto_negotiate & devinfo.target_mask) { - hscb->control |= MK_MESSAGE; - scb->flags &= ~SCB_NEGOTIATE; - scb->flags |= SCB_AUTO_NEGOTIATE; - } - hscb->cdb_len = sizeof(*sc); - hscb->dataptr = sg->addr; - hscb->datacnt = sg->len; - hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID; - hscb->sgptr = ahc_htole32(hscb->sgptr); - scb->sg_count = 1; - scb->flags |= SCB_SENSE; - ahc_qinfifo_requeue_tail(ahc, scb); - ahc_outb(ahc, RETURN_1, SEND_SENSE); - /* - * Ensure we have enough time to actually - * retrieve the sense. - */ - ahc_scb_timer_reset(scb, 5 * 1000000); - break; - } - default: - break; - } - break; - } - case NO_MATCH: - { - /* Ensure we don't leave the selection hardware on */ - ahc_outb(ahc, SCSISEQ, - ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); - - printk("%s:%c:%d: no active SCB for reconnecting " - "target - issuing BUS DEVICE RESET\n", - ahc_name(ahc), devinfo.channel, devinfo.target); - printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " - "ARG_1 == 0x%x ACCUM = 0x%x\n", - ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), - ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); - printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " - "SINDEX == 0x%x\n", - ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), - ahc_index_busy_tcl(ahc, - BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), - ahc_inb(ahc, SAVED_LUN))), - ahc_inb(ahc, SINDEX)); - printk("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " - "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", - ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), - ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), - ahc_inb(ahc, SCB_CONTROL)); - printk("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", - ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); - printk("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0)); - printk("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL)); - ahc_dump_card_state(ahc); - ahc->msgout_buf[0] = MSG_BUS_DEV_RESET; - ahc->msgout_len = 1; - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_assert_atn(ahc); - break; - } - case SEND_REJECT: - { - u_int rejbyte = ahc_inb(ahc, ACCUM); - printk("%s:%c:%d: Warning - unknown message received from " - "target (0x%x). Rejecting\n", - ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte); - break; - } - case PROTO_VIOLATION: - { - ahc_handle_proto_violation(ahc); - break; - } - case IGN_WIDE_RES: - ahc_handle_ign_wide_residue(ahc, &devinfo); - break; - case PDATA_REINIT: - ahc_reinitialize_dataptrs(ahc); - break; - case BAD_PHASE: - { - u_int lastphase; - - lastphase = ahc_inb(ahc, LASTPHASE); - printk("%s:%c:%d: unknown scsi bus phase %x, " - "lastphase = 0x%x. Attempting to continue\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - lastphase, ahc_inb(ahc, SCSISIGI)); - break; - } - case MISSED_BUSFREE: - { - u_int lastphase; - - lastphase = ahc_inb(ahc, LASTPHASE); - printk("%s:%c:%d: Missed busfree. " - "Lastphase = 0x%x, Curphase = 0x%x\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - lastphase, ahc_inb(ahc, SCSISIGI)); - ahc_restart(ahc); - return; - } - case HOST_MSG_LOOP: - { - /* - * The sequencer has encountered a message phase - * that requires host assistance for completion. - * While handling the message phase(s), we will be - * notified by the sequencer after each byte is - * transferred so we can track bus phase changes. - * - * If this is the first time we've seen a HOST_MSG_LOOP - * interrupt, initialize the state of the host message - * loop. - */ - if (ahc->msg_type == MSG_TYPE_NONE) { - struct scb *scb; - u_int scb_index; - u_int bus_phase; - - bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - if (bus_phase != P_MESGIN - && bus_phase != P_MESGOUT) { - printk("ahc_intr: HOST_MSG_LOOP bad " - "phase 0x%x\n", - bus_phase); - /* - * Probably transitioned to bus free before - * we got here. Just punt the message. - */ - ahc_clear_intstat(ahc); - ahc_restart(ahc); - return; - } - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (devinfo.role == ROLE_INITIATOR) { - if (bus_phase == P_MESGOUT) { - if (scb == NULL) - panic("HOST_MSG_LOOP with " - "invalid SCB %x\n", - scb_index); - - ahc_setup_initiator_msgout(ahc, - &devinfo, - scb); - } else { - ahc->msg_type = - MSG_TYPE_INITIATOR_MSGIN; - ahc->msgin_index = 0; - } - } -#ifdef AHC_TARGET_MODE - else { - if (bus_phase == P_MESGOUT) { - ahc->msg_type = - MSG_TYPE_TARGET_MSGOUT; - ahc->msgin_index = 0; - } - else - ahc_setup_target_msgin(ahc, - &devinfo, - scb); - } -#endif - } - - ahc_handle_message_phase(ahc); - break; - } - case PERR_DETECTED: - { - /* - * If we've cleared the parity error interrupt - * but the sequencer still believes that SCSIPERR - * is true, it must be that the parity error is - * for the currently presented byte on the bus, - * and we are not in a phase (data-in) where we will - * eventually ack this byte. Ack the byte and - * throw it away in the hope that the target will - * take us to message out to deliver the appropriate - * error message. - */ - if ((intstat & SCSIINT) == 0 - && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) { - - if ((ahc->features & AHC_DT) == 0) { - u_int curphase; - - /* - * The hardware will only let you ack bytes - * if the expected phase in SCSISIGO matches - * the current phase. Make sure this is - * currently the case. - */ - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - ahc_outb(ahc, LASTPHASE, curphase); - ahc_outb(ahc, SCSISIGO, curphase); - } - if ((ahc_inb(ahc, SCSISIGI) & (CDI|MSGI)) == 0) { - int wait; - - /* - * In a data phase. Faster to bitbucket - * the data than to individually ack each - * byte. This is also the only strategy - * that will work with AUTOACK enabled. - */ - ahc_outb(ahc, SXFRCTL1, - ahc_inb(ahc, SXFRCTL1) | BITBUCKET); - wait = 5000; - while (--wait != 0) { - if ((ahc_inb(ahc, SCSISIGI) - & (CDI|MSGI)) != 0) - break; - ahc_delay(100); - } - ahc_outb(ahc, SXFRCTL1, - ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET); - if (wait == 0) { - struct scb *scb; - u_int scb_index; - - ahc_print_devinfo(ahc, &devinfo); - printk("Unable to clear parity error. " - "Resetting bus.\n"); - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb != NULL) - ahc_set_transaction_status(scb, - CAM_UNCOR_PARITY); - ahc_reset_channel(ahc, devinfo.channel, - /*init reset*/TRUE); - } - } else { - ahc_inb(ahc, SCSIDATL); - } - } - break; - } - case DATA_OVERRUN: - { - /* - * When the sequencer detects an overrun, it - * places the controller in "BITBUCKET" mode - * and allows the target to complete its transfer. - * Unfortunately, none of the counters get updated - * when the controller is in this mode, so we have - * no way of knowing how large the overrun was. - */ - u_int scbindex = ahc_inb(ahc, SCB_TAG); - u_int lastphase = ahc_inb(ahc, LASTPHASE); - u_int i; - - scb = ahc_lookup_scb(ahc, scbindex); - for (i = 0; i < num_phases; i++) { - if (lastphase == ahc_phase_table[i].phase) - break; - } - ahc_print_path(ahc, scb); - printk("data overrun detected %s." - " Tag == 0x%x.\n", - ahc_phase_table[i].phasemsg, - scb->hscb->tag); - ahc_print_path(ahc, scb); - printk("%s seen Data Phase. Length = %ld. NumSGs = %d.\n", - ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't", - ahc_get_transfer_length(scb), scb->sg_count); - if (scb->sg_count > 0) { - for (i = 0; i < scb->sg_count; i++) { - - printk("sg[%d] - Addr 0x%x%x : Length %d\n", - i, - (ahc_le32toh(scb->sg_list[i].len) >> 24 - & SG_HIGH_ADDR_BITS), - ahc_le32toh(scb->sg_list[i].addr), - ahc_le32toh(scb->sg_list[i].len) - & AHC_SG_LEN_MASK); - } - } - /* - * Set this and it will take effect when the - * target does a command complete. - */ - ahc_freeze_devq(ahc, scb); - if ((scb->flags & SCB_SENSE) == 0) { - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); - } else { - scb->flags &= ~SCB_SENSE; - ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); - } - ahc_freeze_scb(scb); - - if ((ahc->features & AHC_ULTRA2) != 0) { - /* - * Clear the channel in case we return - * to data phase later. - */ - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN); - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN); - } - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - u_int dscommand1; - - /* Ensure HHADDR is 0 for future DMA operations. */ - dscommand1 = ahc_inb(ahc, DSCOMMAND1); - ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0); - ahc_outb(ahc, HADDR, 0); - ahc_outb(ahc, DSCOMMAND1, dscommand1); - } - break; - } - case MKMSG_FAILED: - { - u_int scbindex; - - printk("%s:%c:%d:%d: Attempt to issue message failed\n", - ahc_name(ahc), devinfo.channel, devinfo.target, - devinfo.lun); - scbindex = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scbindex); - if (scb != NULL - && (scb->flags & SCB_RECOVERY_SCB) != 0) - /* - * Ensure that we didn't put a second instance of this - * SCB into the QINFIFO. - */ - ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), - SCB_GET_CHANNEL(ahc, scb), - SCB_GET_LUN(scb), scb->hscb->tag, - ROLE_INITIATOR, /*status*/0, - SEARCH_REMOVE); - break; - } - case NO_FREE_SCB: - { - printk("%s: No free or disconnected SCBs\n", ahc_name(ahc)); - ahc_dump_card_state(ahc); - panic("for safety"); - break; - } - case SCB_MISMATCH: - { - u_int scbptr; - - scbptr = ahc_inb(ahc, SCBPTR); - printk("Bogus TAG after DMA. SCBPTR %d, tag %d, our tag %d\n", - scbptr, ahc_inb(ahc, ARG_1), - ahc->scb_data->hscbs[scbptr].tag); - ahc_dump_card_state(ahc); - panic("for safety"); - break; - } - case OUT_OF_RANGE: - { - printk("%s: BTT calculation out of range\n", ahc_name(ahc)); - printk("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, " - "ARG_1 == 0x%x ACCUM = 0x%x\n", - ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN), - ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM)); - printk("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, " - "SINDEX == 0x%x\n, A == 0x%x\n", - ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR), - ahc_index_busy_tcl(ahc, - BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID), - ahc_inb(ahc, SAVED_LUN))), - ahc_inb(ahc, SINDEX), - ahc_inb(ahc, ACCUM)); - printk("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, " - "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n", - ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID), - ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG), - ahc_inb(ahc, SCB_CONTROL)); - printk("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n", - ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI)); - ahc_dump_card_state(ahc); - panic("for safety"); - break; - } - default: - printk("ahc_intr: seqint, " - "intstat == 0x%x, scsisigi = 0x%x\n", - intstat, ahc_inb(ahc, SCSISIGI)); - break; - } -unpause: - /* - * The sequencer is paused immediately on - * a SEQINT, so we should restart it when - * we're done. - */ - ahc_unpause(ahc); -} - -static void -ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) -{ - u_int scb_index; - u_int status0; - u_int status; - struct scb *scb; - char cur_channel; - char intr_channel; - - if ((ahc->features & AHC_TWIN) != 0 - && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0)) - cur_channel = 'B'; - else - cur_channel = 'A'; - intr_channel = cur_channel; - - if ((ahc->features & AHC_ULTRA2) != 0) - status0 = ahc_inb(ahc, SSTAT0) & IOERR; - else - status0 = 0; - status = ahc_inb(ahc, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); - if (status == 0 && status0 == 0) { - if ((ahc->features & AHC_TWIN) != 0) { - /* Try the other channel */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); - status = ahc_inb(ahc, SSTAT1) - & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR); - intr_channel = (cur_channel == 'A') ? 'B' : 'A'; - } - if (status == 0) { - printk("%s: Spurious SCSI interrupt\n", ahc_name(ahc)); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_unpause(ahc); - return; - } - } - - /* Make sure the sequencer is in a safe location. */ - ahc_clear_critical_section(ahc); - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - if (scb != NULL - && (ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) != 0) - scb = NULL; - - if ((ahc->features & AHC_ULTRA2) != 0 - && (status0 & IOERR) != 0) { - int now_lvd; - - now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40; - printk("%s: Transceiver State Has Changed to %s mode\n", - ahc_name(ahc), now_lvd ? "LVD" : "SE"); - ahc_outb(ahc, CLRSINT0, CLRIOERR); - /* - * When transitioning to SE mode, the reset line - * glitches, triggering an arbitration bug in some - * Ultra2 controllers. This bug is cleared when we - * assert the reset line. Since a reset glitch has - * already occurred with this transition and a - * transceiver state change is handled just like - * a bus reset anyway, asserting the reset line - * ourselves is safe. - */ - ahc_reset_channel(ahc, intr_channel, - /*Initiate Reset*/now_lvd == 0); - } else if ((status & SCSIRSTI) != 0) { - printk("%s: Someone reset channel %c\n", - ahc_name(ahc), intr_channel); - if (intr_channel != cur_channel) - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB); - ahc_reset_channel(ahc, intr_channel, /*Initiate Reset*/FALSE); - } else if ((status & SCSIPERR) != 0) { - /* - * Determine the bus phase and queue an appropriate message. - * SCSIPERR is latched true as soon as a parity error - * occurs. If the sequencer acked the transfer that - * caused the parity error and the currently presented - * transfer on the bus has correct parity, SCSIPERR will - * be cleared by CLRSCSIPERR. Use this to determine if - * we should look at the last phase the sequencer recorded, - * or the current phase presented on the bus. - */ - struct ahc_devinfo devinfo; - u_int mesg_out; - u_int curphase; - u_int errorphase; - u_int lastphase; - u_int scsirate; - u_int i; - u_int sstat2; - int silent; - - lastphase = ahc_inb(ahc, LASTPHASE); - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - sstat2 = ahc_inb(ahc, SSTAT2); - ahc_outb(ahc, CLRSINT1, CLRSCSIPERR); - /* - * For all phases save DATA, the sequencer won't - * automatically ack a byte that has a parity error - * in it. So the only way that the current phase - * could be 'data-in' is if the parity error is for - * an already acked byte in the data phase. During - * synchronous data-in transfers, we may actually - * ack bytes before latching the current phase in - * LASTPHASE, leading to the discrepancy between - * curphase and lastphase. - */ - if ((ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0 - || curphase == P_DATAIN || curphase == P_DATAIN_DT) - errorphase = curphase; - else - errorphase = lastphase; - - for (i = 0; i < num_phases; i++) { - if (errorphase == ahc_phase_table[i].phase) - break; - } - mesg_out = ahc_phase_table[i].mesg_out; - silent = FALSE; - if (scb != NULL) { - if (SCB_IS_SILENT(scb)) - silent = TRUE; - else - ahc_print_path(ahc, scb); - scb->flags |= SCB_TRANSMISSION_ERROR; - } else - printk("%s:%c:%d: ", ahc_name(ahc), intr_channel, - SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID))); - scsirate = ahc_inb(ahc, SCSIRATE); - if (silent == FALSE) { - printk("parity error detected %s. " - "SEQADDR(0x%x) SCSIRATE(0x%x)\n", - ahc_phase_table[i].phasemsg, - ahc_inw(ahc, SEQADDR0), - scsirate); - if ((ahc->features & AHC_DT) != 0) { - if ((sstat2 & CRCVALERR) != 0) - printk("\tCRC Value Mismatch\n"); - if ((sstat2 & CRCENDERR) != 0) - printk("\tNo terminal CRC packet " - "recevied\n"); - if ((sstat2 & CRCREQERR) != 0) - printk("\tIllegal CRC packet " - "request\n"); - if ((sstat2 & DUAL_EDGE_ERR) != 0) - printk("\tUnexpected %sDT Data Phase\n", - (scsirate & SINGLE_EDGE) - ? "" : "non-"); - } - } - - if ((ahc->features & AHC_DT) != 0 - && (sstat2 & DUAL_EDGE_ERR) != 0) { - /* - * This error applies regardless of - * data direction, so ignore the value - * in the phase table. - */ - mesg_out = MSG_INITIATOR_DET_ERR; - } - - /* - * We've set the hardware to assert ATN if we - * get a parity error on "in" phases, so all we - * need to do is stuff the message buffer with - * the appropriate message. "In" phases have set - * mesg_out to something other than MSG_NOP. - */ - if (mesg_out != MSG_NOOP) { - if (ahc->msg_type != MSG_TYPE_NONE) - ahc->send_msg_perror = TRUE; - else - ahc_outb(ahc, MSG_OUT, mesg_out); - } - /* - * Force a renegotiation with this target just in - * case we are out of sync for some external reason - * unknown (or unreported) by the target. - */ - ahc_fetch_devinfo(ahc, &devinfo); - ahc_force_renegotiation(ahc, &devinfo); - - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_unpause(ahc); - } else if ((status & SELTO) != 0) { - u_int scbptr; - - /* Stop the selection */ - ahc_outb(ahc, SCSISEQ, 0); - - /* No more pending messages */ - ahc_clear_msg_state(ahc); - - /* Clear interrupt state */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR); - - /* - * Although the driver does not care about the - * 'Selection in Progress' status bit, the busy - * LED does. SELINGO is only cleared by a successful - * selection, so we must manually clear it to insure - * the LED turns off just incase no future successful - * selections occur (e.g. no devices on the bus). - */ - ahc_outb(ahc, CLRSINT0, CLRSELINGO); - - scbptr = ahc_inb(ahc, WAITING_SCBH); - ahc_outb(ahc, SCBPTR, scbptr); - scb_index = ahc_inb(ahc, SCB_TAG); - - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printk("%s: ahc_intr - referenced scb not " - "valid during SELTO scb(%d, %d)\n", - ahc_name(ahc), scbptr, scb_index); - ahc_dump_card_state(ahc); - } else { - struct ahc_devinfo devinfo; -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_SELTO) != 0) { - ahc_print_path(ahc, scb); - printk("Saw Selection Timeout for SCB 0x%x\n", - scb_index); - } -#endif - ahc_scb_devinfo(ahc, &devinfo, scb); - ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); - ahc_freeze_devq(ahc, scb); - - /* - * Cancel any pending transactions on the device - * now that it seems to be missing. This will - * also revert us to async/narrow transfers until - * we can renegotiate with the device. - */ - ahc_handle_devreset(ahc, &devinfo, - CAM_SEL_TIMEOUT, - "Selection Timeout", - /*verbose_level*/1); - } - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_restart(ahc); - } else if ((status & BUSFREE) != 0 - && (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) { - struct ahc_devinfo devinfo; - u_int lastphase; - u_int saved_scsiid; - u_int saved_lun; - u_int target; - u_int initiator_role_id; - char channel; - int printerror; - - /* - * Clear our selection hardware as soon as possible. - * We may have an entry in the waiting Q for this target, - * that is affected by this busfree and we don't want to - * go about selecting the target while we handle the event. - */ - ahc_outb(ahc, SCSISEQ, - ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP)); - - /* - * Disable busfree interrupts and clear the busfree - * interrupt status. We do this here so that several - * bus transactions occur prior to clearing the SCSIINT - * latch. It can take a bit for the clearing to take effect. - */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE); - ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR); - - /* - * Look at what phase we were last in. - * If its message out, chances are pretty good - * that the busfree was in response to one of - * our abort requests. - */ - lastphase = ahc_inb(ahc, LASTPHASE); - saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); - saved_lun = ahc_inb(ahc, SAVED_LUN); - target = SCSIID_TARGET(ahc, saved_scsiid); - initiator_role_id = SCSIID_OUR_ID(saved_scsiid); - channel = SCSIID_CHANNEL(ahc, saved_scsiid); - ahc_compile_devinfo(&devinfo, initiator_role_id, - target, saved_lun, channel, ROLE_INITIATOR); - printerror = 1; - - if (lastphase == P_MESGOUT) { - u_int tag; - - tag = SCB_LIST_NULL; - if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE) - || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) { - if (ahc->msgout_buf[ahc->msgout_index - 1] - == MSG_ABORT_TAG) - tag = scb->hscb->tag; - ahc_print_path(ahc, scb); - printk("SCB %d - Abort%s Completed.\n", - scb->hscb->tag, tag == SCB_LIST_NULL ? - "" : " Tag"); - ahc_abort_scbs(ahc, target, channel, - saved_lun, tag, - ROLE_INITIATOR, - CAM_REQ_ABORTED); - printerror = 0; - } else if (ahc_sent_msg(ahc, AHCMSG_1B, - MSG_BUS_DEV_RESET, TRUE)) { -#ifdef __FreeBSD__ - /* - * Don't mark the user's request for this BDR - * as completing with CAM_BDR_SENT. CAM3 - * specifies CAM_REQ_CMP. - */ - if (scb != NULL - && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV - && ahc_match_scb(ahc, scb, target, channel, - CAM_LUN_WILDCARD, - SCB_LIST_NULL, - ROLE_INITIATOR)) { - ahc_set_transaction_status(scb, CAM_REQ_CMP); - } -#endif - ahc_compile_devinfo(&devinfo, - initiator_role_id, - target, - CAM_LUN_WILDCARD, - channel, - ROLE_INITIATOR); - ahc_handle_devreset(ahc, &devinfo, - CAM_BDR_SENT, - "Bus Device Reset", - /*verbose_level*/0); - printerror = 0; - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_PPR, FALSE)) { - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - - /* - * PPR Rejected. Try non-ppr negotiation - * and retry command. - */ - tinfo = ahc_fetch_transinfo(ahc, - devinfo.channel, - devinfo.our_scsiid, - devinfo.target, - &tstate); - tinfo->curr.transport_version = 2; - tinfo->goal.transport_version = 2; - tinfo->goal.ppr_options = 0; - ahc_qinfifo_requeue_tail(ahc, scb); - printerror = 0; - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_WDTR, FALSE)) { - /* - * Negotiation Rejected. Go-narrow and - * retry command. - */ - ahc_set_width(ahc, &devinfo, - MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_CUR|AHC_TRANS_GOAL, - /*paused*/TRUE); - ahc_qinfifo_requeue_tail(ahc, scb); - printerror = 0; - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_SDTR, FALSE)) { - /* - * Negotiation Rejected. Go-async and - * retry command. - */ - ahc_set_syncrate(ahc, &devinfo, - /*syncrate*/NULL, - /*period*/0, /*offset*/0, - /*ppr_options*/0, - AHC_TRANS_CUR|AHC_TRANS_GOAL, - /*paused*/TRUE); - ahc_qinfifo_requeue_tail(ahc, scb); - printerror = 0; - } - } - if (printerror != 0) { - u_int i; - - if (scb != NULL) { - u_int tag; - - if ((scb->hscb->control & TAG_ENB) != 0) - tag = scb->hscb->tag; - else - tag = SCB_LIST_NULL; - ahc_print_path(ahc, scb); - ahc_abort_scbs(ahc, target, channel, - SCB_GET_LUN(scb), tag, - ROLE_INITIATOR, - CAM_UNEXP_BUSFREE); - } else { - /* - * We had not fully identified this connection, - * so we cannot abort anything. - */ - printk("%s: ", ahc_name(ahc)); - } - for (i = 0; i < num_phases; i++) { - if (lastphase == ahc_phase_table[i].phase) - break; - } - if (lastphase != P_BUSFREE) { - /* - * Renegotiate with this device at the - * next opportunity just in case this busfree - * is due to a negotiation mismatch with the - * device. - */ - ahc_force_renegotiation(ahc, &devinfo); - } - printk("Unexpected busfree %s\n" - "SEQADDR == 0x%x\n", - ahc_phase_table[i].phasemsg, - ahc_inb(ahc, SEQADDR0) - | (ahc_inb(ahc, SEQADDR1) << 8)); - } - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_restart(ahc); - } else { - printk("%s: Missing case in ahc_handle_scsiint. status = %x\n", - ahc_name(ahc), status); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - } -} - -/* - * Force renegotiation to occur the next time we initiate - * a command to the current device. - */ -static void -ahc_force_renegotiation(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - struct ahc_initiator_tinfo *targ_info; - struct ahc_tmode_tstate *tstate; - - targ_info = ahc_fetch_transinfo(ahc, - devinfo->channel, - devinfo->our_scsiid, - devinfo->target, - &tstate); - ahc_update_neg_request(ahc, devinfo, tstate, - targ_info, AHC_NEG_IF_NON_ASYNC); -} - -#define AHC_MAX_STEPS 2000 -static void -ahc_clear_critical_section(struct ahc_softc *ahc) -{ - int stepping; - int steps; - u_int simode0; - u_int simode1; - - if (ahc->num_critical_sections == 0) - return; - - stepping = FALSE; - steps = 0; - simode0 = 0; - simode1 = 0; - for (;;) { - struct cs *cs; - u_int seqaddr; - u_int i; - - seqaddr = ahc_inb(ahc, SEQADDR0) - | (ahc_inb(ahc, SEQADDR1) << 8); - - /* - * Seqaddr represents the next instruction to execute, - * so we are really executing the instruction just - * before it. - */ - if (seqaddr != 0) - seqaddr -= 1; - cs = ahc->critical_sections; - for (i = 0; i < ahc->num_critical_sections; i++, cs++) { - - if (cs->begin < seqaddr && cs->end >= seqaddr) - break; - } - - if (i == ahc->num_critical_sections) - break; - - if (steps > AHC_MAX_STEPS) { - printk("%s: Infinite loop in critical section\n", - ahc_name(ahc)); - ahc_dump_card_state(ahc); - panic("critical section loop"); - } - - steps++; - if (stepping == FALSE) { - - /* - * Disable all interrupt sources so that the - * sequencer will not be stuck by a pausing - * interrupt condition while we attempt to - * leave a critical section. - */ - simode0 = ahc_inb(ahc, SIMODE0); - ahc_outb(ahc, SIMODE0, 0); - simode1 = ahc_inb(ahc, SIMODE1); - if ((ahc->features & AHC_DT) != 0) - /* - * On DT class controllers, we - * use the enhanced busfree logic. - * Unfortunately we cannot re-enable - * busfree detection within the - * current connection, so we must - * leave it on while single stepping. - */ - ahc_outb(ahc, SIMODE1, simode1 & ENBUSFREE); - else - ahc_outb(ahc, SIMODE1, 0); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_outb(ahc, SEQCTL, ahc->seqctl | STEP); - stepping = TRUE; - } - if ((ahc->features & AHC_DT) != 0) { - ahc_outb(ahc, CLRSINT1, CLRBUSFREE); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - } - ahc_outb(ahc, HCNTRL, ahc->unpause); - while (!ahc_is_paused(ahc)) - ahc_delay(200); - } - if (stepping) { - ahc_outb(ahc, SIMODE0, simode0); - ahc_outb(ahc, SIMODE1, simode1); - ahc_outb(ahc, SEQCTL, ahc->seqctl); - } -} - -/* - * Clear any pending interrupt status. - */ -static void -ahc_clear_intstat(struct ahc_softc *ahc) -{ - /* Clear any interrupt conditions this may have caused */ - ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI - |CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG| - CLRREQINIT); - ahc_flush_device_writes(ahc); - ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO); - ahc_flush_device_writes(ahc); - ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_flush_device_writes(ahc); -} - -/**************************** Debugging Routines ******************************/ -#ifdef AHC_DEBUG -uint32_t ahc_debug = AHC_DEBUG_OPTS; -#endif - -#if 0 /* unused */ -static void -ahc_print_scb(struct scb *scb) -{ - int i; - - struct hardware_scb *hscb = scb->hscb; - - printk("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n", - (void *)scb, - hscb->control, - hscb->scsiid, - hscb->lun, - hscb->cdb_len); - printk("Shared Data: "); - for (i = 0; i < sizeof(hscb->shared_data.cdb); i++) - printk("%#02x", hscb->shared_data.cdb[i]); - printk(" dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n", - ahc_le32toh(hscb->dataptr), - ahc_le32toh(hscb->datacnt), - ahc_le32toh(hscb->sgptr), - hscb->tag); - if (scb->sg_count > 0) { - for (i = 0; i < scb->sg_count; i++) { - printk("sg[%d] - Addr 0x%x%x : Length %d\n", - i, - (ahc_le32toh(scb->sg_list[i].len) >> 24 - & SG_HIGH_ADDR_BITS), - ahc_le32toh(scb->sg_list[i].addr), - ahc_le32toh(scb->sg_list[i].len)); - } - } -} -#endif - -/************************* Transfer Negotiation *******************************/ -/* - * Allocate per target mode instance (ID we respond to as a target) - * transfer negotiation data structures. - */ -static struct ahc_tmode_tstate * -ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel) -{ - struct ahc_tmode_tstate *master_tstate; - struct ahc_tmode_tstate *tstate; - int i; - - master_tstate = ahc->enabled_targets[ahc->our_id]; - if (channel == 'B') { - scsi_id += 8; - master_tstate = ahc->enabled_targets[ahc->our_id_b + 8]; - } - if (ahc->enabled_targets[scsi_id] != NULL - && ahc->enabled_targets[scsi_id] != master_tstate) - panic("%s: ahc_alloc_tstate - Target already allocated", - ahc_name(ahc)); - tstate = kmalloc(sizeof(*tstate), GFP_ATOMIC); - if (tstate == NULL) - return (NULL); - - /* - * If we have allocated a master tstate, copy user settings from - * the master tstate (taken from SRAM or the EEPROM) for this - * channel, but reset our current and goal settings to async/narrow - * until an initiator talks to us. - */ - if (master_tstate != NULL) { - memcpy(tstate, master_tstate, sizeof(*tstate)); - memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns)); - tstate->ultraenb = 0; - for (i = 0; i < AHC_NUM_TARGETS; i++) { - memset(&tstate->transinfo[i].curr, 0, - sizeof(tstate->transinfo[i].curr)); - memset(&tstate->transinfo[i].goal, 0, - sizeof(tstate->transinfo[i].goal)); - } - } else - memset(tstate, 0, sizeof(*tstate)); - ahc->enabled_targets[scsi_id] = tstate; - return (tstate); -} - -#ifdef AHC_TARGET_MODE -/* - * Free per target mode instance (ID we respond to as a target) - * transfer negotiation data structures. - */ -static void -ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force) -{ - struct ahc_tmode_tstate *tstate; - - /* - * Don't clean up our "master" tstate. - * It has our default user settings. - */ - if (((channel == 'B' && scsi_id == ahc->our_id_b) - || (channel == 'A' && scsi_id == ahc->our_id)) - && force == FALSE) - return; - - if (channel == 'B') - scsi_id += 8; - tstate = ahc->enabled_targets[scsi_id]; - if (tstate != NULL) - kfree(tstate); - ahc->enabled_targets[scsi_id] = NULL; -} -#endif - -/* - * Called when we have an active connection to a target on the bus, - * this function finds the nearest syncrate to the input period limited - * by the capabilities of the bus connectivity of and sync settings for - * the target. - */ -const struct ahc_syncrate * -ahc_devlimited_syncrate(struct ahc_softc *ahc, - struct ahc_initiator_tinfo *tinfo, - u_int *period, u_int *ppr_options, role_t role) -{ - struct ahc_transinfo *transinfo; - u_int maxsync; - - if ((ahc->features & AHC_ULTRA2) != 0) { - if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0 - && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) { - maxsync = AHC_SYNCRATE_DT; - } else { - maxsync = AHC_SYNCRATE_ULTRA; - /* Can't do DT on an SE bus */ - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - } - } else if ((ahc->features & AHC_ULTRA) != 0) { - maxsync = AHC_SYNCRATE_ULTRA; - } else { - maxsync = AHC_SYNCRATE_FAST; - } - /* - * Never allow a value higher than our current goal - * period otherwise we may allow a target initiated - * negotiation to go above the limit as set by the - * user. In the case of an initiator initiated - * sync negotiation, we limit based on the user - * setting. This allows the system to still accept - * incoming negotiations even if target initiated - * negotiation is not performed. - */ - if (role == ROLE_TARGET) - transinfo = &tinfo->user; - else - transinfo = &tinfo->goal; - *ppr_options &= transinfo->ppr_options; - if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) { - maxsync = max(maxsync, (u_int)AHC_SYNCRATE_ULTRA2); - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - } - if (transinfo->period == 0) { - *period = 0; - *ppr_options = 0; - return (NULL); - } - *period = max(*period, (u_int)transinfo->period); - return (ahc_find_syncrate(ahc, period, ppr_options, maxsync)); -} - -/* - * Look up the valid period to SCSIRATE conversion in our table. - * Return the period and offset that should be sent to the target - * if this was the beginning of an SDTR. - */ -const struct ahc_syncrate * -ahc_find_syncrate(struct ahc_softc *ahc, u_int *period, - u_int *ppr_options, u_int maxsync) -{ - const struct ahc_syncrate *syncrate; - - if ((ahc->features & AHC_DT) == 0) - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - - /* Skip all DT only entries if DT is not available */ - if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && maxsync < AHC_SYNCRATE_ULTRA2) - maxsync = AHC_SYNCRATE_ULTRA2; - - /* Now set the maxsync based on the card capabilities - * DT is already done above */ - if ((ahc->features & (AHC_DT | AHC_ULTRA2)) == 0 - && maxsync < AHC_SYNCRATE_ULTRA) - maxsync = AHC_SYNCRATE_ULTRA; - if ((ahc->features & (AHC_DT | AHC_ULTRA2 | AHC_ULTRA)) == 0 - && maxsync < AHC_SYNCRATE_FAST) - maxsync = AHC_SYNCRATE_FAST; - - for (syncrate = &ahc_syncrates[maxsync]; - syncrate->rate != NULL; - syncrate++) { - - /* - * The Ultra2 table doesn't go as low - * as for the Fast/Ultra cards. - */ - if ((ahc->features & AHC_ULTRA2) != 0 - && (syncrate->sxfr_u2 == 0)) - break; - - if (*period <= syncrate->period) { - /* - * When responding to a target that requests - * sync, the requested rate may fall between - * two rates that we can output, but still be - * a rate that we can receive. Because of this, - * we want to respond to the target with - * the same rate that it sent to us even - * if the period we use to send data to it - * is lower. Only lower the response period - * if we must. - */ - if (syncrate == &ahc_syncrates[maxsync]) - *period = syncrate->period; - - /* - * At some speeds, we only support - * ST transfers. - */ - if ((syncrate->sxfr_u2 & ST_SXFR) != 0) - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - break; - } - } - - if ((*period == 0) - || (syncrate->rate == NULL) - || ((ahc->features & AHC_ULTRA2) != 0 - && (syncrate->sxfr_u2 == 0))) { - /* Use asynchronous transfers. */ - *period = 0; - syncrate = NULL; - *ppr_options &= ~MSG_EXT_PPR_DT_REQ; - } - return (syncrate); -} - -/* - * Convert from an entry in our syncrate table to the SCSI equivalent - * sync "period" factor. - */ -u_int -ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync) -{ - const struct ahc_syncrate *syncrate; - - if ((ahc->features & AHC_ULTRA2) != 0) - scsirate &= SXFR_ULTRA2; - else - scsirate &= SXFR; - - /* now set maxsync based on card capabilities */ - if ((ahc->features & AHC_DT) == 0 && maxsync < AHC_SYNCRATE_ULTRA2) - maxsync = AHC_SYNCRATE_ULTRA2; - if ((ahc->features & (AHC_DT | AHC_ULTRA2)) == 0 - && maxsync < AHC_SYNCRATE_ULTRA) - maxsync = AHC_SYNCRATE_ULTRA; - if ((ahc->features & (AHC_DT | AHC_ULTRA2 | AHC_ULTRA)) == 0 - && maxsync < AHC_SYNCRATE_FAST) - maxsync = AHC_SYNCRATE_FAST; - - - syncrate = &ahc_syncrates[maxsync]; - while (syncrate->rate != NULL) { - - if ((ahc->features & AHC_ULTRA2) != 0) { - if (syncrate->sxfr_u2 == 0) - break; - else if (scsirate == (syncrate->sxfr_u2 & SXFR_ULTRA2)) - return (syncrate->period); - } else if (scsirate == (syncrate->sxfr & SXFR)) { - return (syncrate->period); - } - syncrate++; - } - return (0); /* async */ -} - -/* - * Truncate the given synchronous offset to a value the - * current adapter type and syncrate are capable of. - */ -static void -ahc_validate_offset(struct ahc_softc *ahc, - struct ahc_initiator_tinfo *tinfo, - const struct ahc_syncrate *syncrate, - u_int *offset, int wide, role_t role) -{ - u_int maxoffset; - - /* Limit offset to what we can do */ - if (syncrate == NULL) { - maxoffset = 0; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - maxoffset = MAX_OFFSET_ULTRA2; - } else { - if (wide) - maxoffset = MAX_OFFSET_16BIT; - else - maxoffset = MAX_OFFSET_8BIT; - } - *offset = min(*offset, maxoffset); - if (tinfo != NULL) { - if (role == ROLE_TARGET) - *offset = min(*offset, (u_int)tinfo->user.offset); - else - *offset = min(*offset, (u_int)tinfo->goal.offset); - } -} - -/* - * Truncate the given transfer width parameter to a value the - * current adapter type is capable of. - */ -static void -ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo, - u_int *bus_width, role_t role) -{ - switch (*bus_width) { - default: - if (ahc->features & AHC_WIDE) { - /* Respond Wide */ - *bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - /* FALLTHROUGH */ - case MSG_EXT_WDTR_BUS_8_BIT: - *bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - if (tinfo != NULL) { - if (role == ROLE_TARGET) - *bus_width = min((u_int)tinfo->user.width, *bus_width); - else - *bus_width = min((u_int)tinfo->goal.width, *bus_width); - } -} - -/* - * Update the bitmask of targets for which the controller should - * negotiate with at the next convenient opportunity. This currently - * means the next time we send the initial identify messages for - * a new transaction. - */ -int -ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct ahc_tmode_tstate *tstate, - struct ahc_initiator_tinfo *tinfo, ahc_neg_type neg_type) -{ - u_int auto_negotiate_orig; - - auto_negotiate_orig = tstate->auto_negotiate; - if (neg_type == AHC_NEG_ALWAYS) { - /* - * Force our "current" settings to be - * unknown so that unless a bus reset - * occurs the need to renegotiate is - * recorded persistently. - */ - if ((ahc->features & AHC_WIDE) != 0) - tinfo->curr.width = AHC_WIDTH_UNKNOWN; - tinfo->curr.period = AHC_PERIOD_UNKNOWN; - tinfo->curr.offset = AHC_OFFSET_UNKNOWN; - } - if (tinfo->curr.period != tinfo->goal.period - || tinfo->curr.width != tinfo->goal.width - || tinfo->curr.offset != tinfo->goal.offset - || tinfo->curr.ppr_options != tinfo->goal.ppr_options - || (neg_type == AHC_NEG_IF_NON_ASYNC - && (tinfo->goal.offset != 0 - || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT - || tinfo->goal.ppr_options != 0))) - tstate->auto_negotiate |= devinfo->target_mask; - else - tstate->auto_negotiate &= ~devinfo->target_mask; - - return (auto_negotiate_orig != tstate->auto_negotiate); -} - -/* - * Update the user/goal/curr tables of synchronous negotiation - * parameters as well as, in the case of a current or active update, - * any data structures on the host controller. In the case of an - * active update, the specified target is currently talking to us on - * the bus, so the transfer parameter update must take effect - * immediately. - */ -void -ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - const struct ahc_syncrate *syncrate, u_int period, - u_int offset, u_int ppr_options, u_int type, int paused) -{ - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int old_period; - u_int old_offset; - u_int old_ppr; - int active; - int update_needed; - - active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; - update_needed = 0; - - if (syncrate == NULL) { - period = 0; - offset = 0; - } - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - if ((type & AHC_TRANS_USER) != 0) { - tinfo->user.period = period; - tinfo->user.offset = offset; - tinfo->user.ppr_options = ppr_options; - } - - if ((type & AHC_TRANS_GOAL) != 0) { - tinfo->goal.period = period; - tinfo->goal.offset = offset; - tinfo->goal.ppr_options = ppr_options; - } - - old_period = tinfo->curr.period; - old_offset = tinfo->curr.offset; - old_ppr = tinfo->curr.ppr_options; - - if ((type & AHC_TRANS_CUR) != 0 - && (old_period != period - || old_offset != offset - || old_ppr != ppr_options)) { - u_int scsirate; - - update_needed++; - scsirate = tinfo->scsirate; - if ((ahc->features & AHC_ULTRA2) != 0) { - - scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC); - if (syncrate != NULL) { - scsirate |= syncrate->sxfr_u2; - if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) - scsirate |= ENABLE_CRC; - else - scsirate |= SINGLE_EDGE; - } - } else { - - scsirate &= ~(SXFR|SOFS); - /* - * Ensure Ultra mode is set properly for - * this target. - */ - tstate->ultraenb &= ~devinfo->target_mask; - if (syncrate != NULL) { - if (syncrate->sxfr & ULTRA_SXFR) { - tstate->ultraenb |= - devinfo->target_mask; - } - scsirate |= syncrate->sxfr & SXFR; - scsirate |= offset & SOFS; - } - if (active) { - u_int sxfrctl0; - - sxfrctl0 = ahc_inb(ahc, SXFRCTL0); - sxfrctl0 &= ~FAST20; - if (tstate->ultraenb & devinfo->target_mask) - sxfrctl0 |= FAST20; - ahc_outb(ahc, SXFRCTL0, sxfrctl0); - } - } - if (active) { - ahc_outb(ahc, SCSIRATE, scsirate); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIOFFSET, offset); - } - - tinfo->scsirate = scsirate; - tinfo->curr.period = period; - tinfo->curr.offset = offset; - tinfo->curr.ppr_options = ppr_options; - - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); - if (bootverbose) { - if (offset != 0) { - printk("%s: target %d synchronous at %sMHz%s, " - "offset = 0x%x\n", ahc_name(ahc), - devinfo->target, syncrate->rate, - (ppr_options & MSG_EXT_PPR_DT_REQ) - ? " DT" : "", offset); - } else { - printk("%s: target %d using " - "asynchronous transfers\n", - ahc_name(ahc), devinfo->target); - } - } - } - - update_needed += ahc_update_neg_request(ahc, devinfo, tstate, - tinfo, AHC_NEG_TO_GOAL); - - if (update_needed) - ahc_update_pending_scbs(ahc); -} - -/* - * Update the user/goal/curr tables of wide negotiation - * parameters as well as, in the case of a current or active update, - * any data structures on the host controller. In the case of an - * active update, the specified target is currently talking to us on - * the bus, so the transfer parameter update must take effect - * immediately. - */ -void -ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - u_int width, u_int type, int paused) -{ - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int oldwidth; - int active; - int update_needed; - - active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE; - update_needed = 0; - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - - if ((type & AHC_TRANS_USER) != 0) - tinfo->user.width = width; - - if ((type & AHC_TRANS_GOAL) != 0) - tinfo->goal.width = width; - - oldwidth = tinfo->curr.width; - if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) { - u_int scsirate; - - update_needed++; - scsirate = tinfo->scsirate; - scsirate &= ~WIDEXFER; - if (width == MSG_EXT_WDTR_BUS_16_BIT) - scsirate |= WIDEXFER; - - tinfo->scsirate = scsirate; - - if (active) - ahc_outb(ahc, SCSIRATE, scsirate); - - tinfo->curr.width = width; - - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_TRANSFER_NEG); - if (bootverbose) { - printk("%s: target %d using %dbit transfers\n", - ahc_name(ahc), devinfo->target, - 8 * (0x01 << width)); - } - } - - update_needed += ahc_update_neg_request(ahc, devinfo, tstate, - tinfo, AHC_NEG_TO_GOAL); - if (update_needed) - ahc_update_pending_scbs(ahc); -} - -/* - * Update the current state of tagged queuing for a given target. - */ -static void -ahc_set_tags(struct ahc_softc *ahc, struct scsi_cmnd *cmd, - struct ahc_devinfo *devinfo, ahc_queue_alg alg) -{ - struct scsi_device *sdev = cmd->device; - - ahc_platform_set_tags(ahc, sdev, devinfo, alg); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - devinfo->lun, AC_TRANSFER_NEG); -} - -/* - * When the transfer settings for a connection change, update any - * in-transit SCBs to contain the new data so the hardware will - * be set correctly during future (re)selections. - */ -static void -ahc_update_pending_scbs(struct ahc_softc *ahc) -{ - struct scb *pending_scb; - int pending_scb_count; - int i; - int paused; - u_int saved_scbptr; - - /* - * Traverse the pending SCB list and ensure that all of the - * SCBs there have the proper settings. - */ - pending_scb_count = 0; - LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { - struct ahc_devinfo devinfo; - struct hardware_scb *pending_hscb; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - - ahc_scb_devinfo(ahc, &devinfo, pending_scb); - tinfo = ahc_fetch_transinfo(ahc, devinfo.channel, - devinfo.our_scsiid, - devinfo.target, &tstate); - pending_hscb = pending_scb->hscb; - pending_hscb->control &= ~ULTRAENB; - if ((tstate->ultraenb & devinfo.target_mask) != 0) - pending_hscb->control |= ULTRAENB; - pending_hscb->scsirate = tinfo->scsirate; - pending_hscb->scsioffset = tinfo->curr.offset; - if ((tstate->auto_negotiate & devinfo.target_mask) == 0 - && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) { - pending_scb->flags &= ~SCB_AUTO_NEGOTIATE; - pending_hscb->control &= ~MK_MESSAGE; - } - ahc_sync_scb(ahc, pending_scb, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - pending_scb_count++; - } - - if (pending_scb_count == 0) - return; - - if (ahc_is_paused(ahc)) { - paused = 1; - } else { - paused = 0; - ahc_pause(ahc); - } - - saved_scbptr = ahc_inb(ahc, SCBPTR); - /* Ensure that the hscbs down on the card match the new information */ - for (i = 0; i < ahc->scb_data->maxhscbs; i++) { - struct hardware_scb *pending_hscb; - u_int control; - u_int scb_tag; - - ahc_outb(ahc, SCBPTR, i); - scb_tag = ahc_inb(ahc, SCB_TAG); - pending_scb = ahc_lookup_scb(ahc, scb_tag); - if (pending_scb == NULL) - continue; - - pending_hscb = pending_scb->hscb; - control = ahc_inb(ahc, SCB_CONTROL); - control &= ~(ULTRAENB|MK_MESSAGE); - control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE); - ahc_outb(ahc, SCB_CONTROL, control); - ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate); - ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset); - } - ahc_outb(ahc, SCBPTR, saved_scbptr); - - if (paused == 0) - ahc_unpause(ahc); -} - -/**************************** Pathing Information *****************************/ -static void -ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - u_int saved_scsiid; - role_t role; - int our_id; - - if (ahc_inb(ahc, SSTAT0) & TARGET) - role = ROLE_TARGET; - else - role = ROLE_INITIATOR; - - if (role == ROLE_TARGET - && (ahc->features & AHC_MULTI_TID) != 0 - && (ahc_inb(ahc, SEQ_FLAGS) - & (CMDPHASE_PENDING|TARG_CMD_PENDING|NO_DISCONNECT)) != 0) { - /* We were selected, so pull our id from TARGIDIN */ - our_id = ahc_inb(ahc, TARGIDIN) & OID; - } else if ((ahc->features & AHC_ULTRA2) != 0) - our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; - else - our_id = ahc_inb(ahc, SCSIID) & OID; - - saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); - ahc_compile_devinfo(devinfo, - our_id, - SCSIID_TARGET(ahc, saved_scsiid), - ahc_inb(ahc, SAVED_LUN), - SCSIID_CHANNEL(ahc, saved_scsiid), - role); -} - -static const struct ahc_phase_table_entry* -ahc_lookup_phase_entry(int phase) -{ - const struct ahc_phase_table_entry *entry; - const struct ahc_phase_table_entry *last_entry; - - /* - * num_phases doesn't include the default entry which - * will be returned if the phase doesn't match. - */ - last_entry = &ahc_phase_table[num_phases]; - for (entry = ahc_phase_table; entry < last_entry; entry++) { - if (phase == entry->phase) - break; - } - return (entry); -} - -void -ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target, - u_int lun, char channel, role_t role) -{ - devinfo->our_scsiid = our_id; - devinfo->target = target; - devinfo->lun = lun; - devinfo->target_offset = target; - devinfo->channel = channel; - devinfo->role = role; - if (channel == 'B') - devinfo->target_offset += 8; - devinfo->target_mask = (0x01 << devinfo->target_offset); -} - -void -ahc_print_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - printk("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); -} - -static void -ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct scb *scb) -{ - role_t role; - int our_id; - - our_id = SCSIID_OUR_ID(scb->hscb->scsiid); - role = ROLE_INITIATOR; - if ((scb->flags & SCB_TARGET_SCB) != 0) - role = ROLE_TARGET; - ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb), - SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role); -} - - -/************************ Message Phase Processing ****************************/ -static void -ahc_assert_atn(struct ahc_softc *ahc) -{ - u_int scsisigo; - - scsisigo = ATNO; - if ((ahc->features & AHC_DT) == 0) - scsisigo |= ahc_inb(ahc, SCSISIGI); - ahc_outb(ahc, SCSISIGO, scsisigo); -} - -/* - * When an initiator transaction with the MK_MESSAGE flag either reconnects - * or enters the initial message out phase, we are interrupted. Fill our - * outgoing message buffer with the appropriate message and beging handing - * the message phase(s) manually. - */ -static void -ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct scb *scb) -{ - /* - * To facilitate adding multiple messages together, - * each routine should increment the index and len - * variables instead of setting them explicitly. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - - if ((scb->flags & SCB_DEVICE_RESET) == 0 - && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) { - u_int identify_msg; - - identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb); - if ((scb->hscb->control & DISCENB) != 0) - identify_msg |= MSG_IDENTIFY_DISCFLAG; - ahc->msgout_buf[ahc->msgout_index++] = identify_msg; - ahc->msgout_len++; - - if ((scb->hscb->control & TAG_ENB) != 0) { - ahc->msgout_buf[ahc->msgout_index++] = - scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE); - ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag; - ahc->msgout_len += 2; - } - } - - if (scb->flags & SCB_DEVICE_RESET) { - ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET; - ahc->msgout_len++; - ahc_print_path(ahc, scb); - printk("Bus Device Reset Message Sent\n"); - /* - * Clear our selection hardware in advance of - * the busfree. We may have an entry in the waiting - * Q for this target, and we don't want to go about - * selecting while we handle the busfree and blow it - * away. - */ - ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else if ((scb->flags & SCB_ABORT) != 0) { - if ((scb->hscb->control & TAG_ENB) != 0) - ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG; - else - ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT; - ahc->msgout_len++; - ahc_print_path(ahc, scb); - printk("Abort%s Message Sent\n", - (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : ""); - /* - * Clear our selection hardware in advance of - * the busfree. We may have an entry in the waiting - * Q for this target, and we don't want to go about - * selecting while we handle the busfree and blow it - * away. - */ - ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) { - ahc_build_transfer_msg(ahc, devinfo); - } else { - printk("ahc_intr: AWAITING_MSG for an SCB that " - "does not have a waiting message\n"); - printk("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid, - devinfo->target_mask); - panic("SCB = %d, SCB Control = %x, MSG_OUT = %x " - "SCB flags = %x", scb->hscb->tag, scb->hscb->control, - ahc_inb(ahc, MSG_OUT), scb->flags); - } - - /* - * Clear the MK_MESSAGE flag from the SCB so we aren't - * asked to send this message again. - */ - ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE); - scb->hscb->control &= ~MK_MESSAGE; - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; -} - -/* - * Build an appropriate transfer negotiation message for the - * currently active target. - */ -static void -ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - /* - * We need to initiate transfer negotiations. - * If our current and goal settings are identical, - * we want to renegotiate due to a check condition. - */ - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - const struct ahc_syncrate *rate; - int dowide; - int dosync; - int doppr; - u_int period; - u_int ppr_options; - u_int offset; - - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - /* - * Filter our period based on the current connection. - * If we can't perform DT transfers on this segment (not in LVD - * mode for instance), then our decision to issue a PPR message - * may change. - */ - period = tinfo->goal.period; - offset = tinfo->goal.offset; - ppr_options = tinfo->goal.ppr_options; - /* Target initiated PPR is not allowed in the SCSI spec */ - if (devinfo->role == ROLE_TARGET) - ppr_options = 0; - rate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, devinfo->role); - dowide = tinfo->curr.width != tinfo->goal.width; - dosync = tinfo->curr.offset != offset || tinfo->curr.period != period; - /* - * Only use PPR if we have options that need it, even if the device - * claims to support it. There might be an expander in the way - * that doesn't. - */ - doppr = ppr_options != 0; - - if (!dowide && !dosync && !doppr) { - dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; - dosync = tinfo->goal.offset != 0; - } - - if (!dowide && !dosync && !doppr) { - /* - * Force async with a WDTR message if we have a wide bus, - * or just issue an SDTR with a 0 offset. - */ - if ((ahc->features & AHC_WIDE) != 0) - dowide = 1; - else - dosync = 1; - - if (bootverbose) { - ahc_print_devinfo(ahc, devinfo); - printk("Ensuring async\n"); - } - } - - /* Target initiated PPR is not allowed in the SCSI spec */ - if (devinfo->role == ROLE_TARGET) - doppr = 0; - - /* - * Both the PPR message and SDTR message require the - * goal syncrate to be limited to what the target device - * is capable of handling (based on whether an LVD->SE - * expander is on the bus), so combine these two cases. - * Regardless, guarantee that if we are using WDTR and SDTR - * messages that WDTR comes first. - */ - if (doppr || (dosync && !dowide)) { - - offset = tinfo->goal.offset; - ahc_validate_offset(ahc, tinfo, rate, &offset, - doppr ? tinfo->goal.width - : tinfo->curr.width, - devinfo->role); - if (doppr) { - ahc_construct_ppr(ahc, devinfo, period, offset, - tinfo->goal.width, ppr_options); - } else { - ahc_construct_sdtr(ahc, devinfo, period, offset); - } - } else { - ahc_construct_wdtr(ahc, devinfo, tinfo->goal.width); - } -} - -/* - * Build a synchronous negotiation message in our message - * buffer based on the input parameters. - */ -static void -ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - u_int period, u_int offset) -{ - if (offset == 0) - period = AHC_ASYNC_XFER_PERIOD; - ahc->msgout_index += spi_populate_sync_msg( - ahc->msgout_buf + ahc->msgout_index, period, offset); - ahc->msgout_len += 5; - if (bootverbose) { - printk("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - devinfo->lun, period, offset); - } -} - -/* - * Build a wide negotiation message in our message - * buffer based on the input parameters. - */ -static void -ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - u_int bus_width) -{ - ahc->msgout_index += spi_populate_width_msg( - ahc->msgout_buf + ahc->msgout_index, bus_width); - ahc->msgout_len += 4; - if (bootverbose) { - printk("(%s:%c:%d:%d): Sending WDTR %x\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - devinfo->lun, bus_width); - } -} - -/* - * Build a parallel protocol request message in our message - * buffer based on the input parameters. - */ -static void -ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - u_int period, u_int offset, u_int bus_width, - u_int ppr_options) -{ - if (offset == 0) - period = AHC_ASYNC_XFER_PERIOD; - ahc->msgout_index += spi_populate_ppr_msg( - ahc->msgout_buf + ahc->msgout_index, period, offset, - bus_width, ppr_options); - ahc->msgout_len += 8; - if (bootverbose) { - printk("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, " - "offset %x, ppr_options %x\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun, - bus_width, period, offset, ppr_options); - } -} - -/* - * Clear any active message state. - */ -static void -ahc_clear_msg_state(struct ahc_softc *ahc) -{ - ahc->msgout_len = 0; - ahc->msgin_index = 0; - ahc->msg_type = MSG_TYPE_NONE; - if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) { - /* - * The target didn't care to respond to our - * message request, so clear ATN. - */ - ahc_outb(ahc, CLRSINT1, CLRATNO); - } - ahc_outb(ahc, MSG_OUT, MSG_NOOP); - ahc_outb(ahc, SEQ_FLAGS2, - ahc_inb(ahc, SEQ_FLAGS2) & ~TARGET_MSG_PENDING); -} - -static void -ahc_handle_proto_violation(struct ahc_softc *ahc) -{ - struct ahc_devinfo devinfo; - struct scb *scb; - u_int scbid; - u_int seq_flags; - u_int curphase; - u_int lastphase; - int found; - - ahc_fetch_devinfo(ahc, &devinfo); - scbid = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scbid); - seq_flags = ahc_inb(ahc, SEQ_FLAGS); - curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - lastphase = ahc_inb(ahc, LASTPHASE); - if ((seq_flags & NOT_IDENTIFIED) != 0) { - - /* - * The reconnecting target either did not send an - * identify message, or did, but we didn't find an SCB - * to match. - */ - ahc_print_devinfo(ahc, &devinfo); - printk("Target did not send an IDENTIFY message. " - "LASTPHASE = 0x%x.\n", lastphase); - scb = NULL; - } else if (scb == NULL) { - /* - * We don't seem to have an SCB active for this - * transaction. Print an error and reset the bus. - */ - ahc_print_devinfo(ahc, &devinfo); - printk("No SCB found during protocol violation\n"); - goto proto_violation_reset; - } else { - ahc_set_transaction_status(scb, CAM_SEQUENCE_FAIL); - if ((seq_flags & NO_CDB_SENT) != 0) { - ahc_print_path(ahc, scb); - printk("No or incomplete CDB sent to device.\n"); - } else if ((ahc_inb(ahc, SCB_CONTROL) & STATUS_RCVD) == 0) { - /* - * The target never bothered to provide status to - * us prior to completing the command. Since we don't - * know the disposition of this command, we must attempt - * to abort it. Assert ATN and prepare to send an abort - * message. - */ - ahc_print_path(ahc, scb); - printk("Completed command without status.\n"); - } else { - ahc_print_path(ahc, scb); - printk("Unknown protocol violation.\n"); - ahc_dump_card_state(ahc); - } - } - if ((lastphase & ~P_DATAIN_DT) == 0 - || lastphase == P_COMMAND) { -proto_violation_reset: - /* - * Target either went directly to data/command - * phase or didn't respond to our ATN. - * The only safe thing to do is to blow - * it away with a bus reset. - */ - found = ahc_reset_channel(ahc, 'A', TRUE); - printk("%s: Issued Channel %c Bus Reset. " - "%d SCBs aborted\n", ahc_name(ahc), 'A', found); - } else { - /* - * Leave the selection hardware off in case - * this abort attempt will affect yet to - * be sent commands. - */ - ahc_outb(ahc, SCSISEQ, - ahc_inb(ahc, SCSISEQ) & ~ENSELO); - ahc_assert_atn(ahc); - ahc_outb(ahc, MSG_OUT, HOST_MSG); - if (scb == NULL) { - ahc_print_devinfo(ahc, &devinfo); - ahc->msgout_buf[0] = MSG_ABORT_TASK; - ahc->msgout_len = 1; - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - } else { - ahc_print_path(ahc, scb); - scb->flags |= SCB_ABORT; - } - printk("Protocol violation %s. Attempting to abort.\n", - ahc_lookup_phase_entry(curphase)->phasemsg); - } -} - -/* - * Manual message loop handler. - */ -static void -ahc_handle_message_phase(struct ahc_softc *ahc) -{ - struct ahc_devinfo devinfo; - u_int bus_phase; - int end_session; - - ahc_fetch_devinfo(ahc, &devinfo); - end_session = FALSE; - bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK; - -reswitch: - switch (ahc->msg_type) { - case MSG_TYPE_INITIATOR_MSGOUT: - { - int lastbyte; - int phasemis; - int msgdone; - - if (ahc->msgout_len == 0) - panic("HOST_MSG_LOOP interrupt with no active message"); - -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { - ahc_print_devinfo(ahc, &devinfo); - printk("INITIATOR_MSG_OUT"); - } -#endif - phasemis = bus_phase != P_MESGOUT; - if (phasemis) { -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { - printk(" PHASEMIS %s\n", - ahc_lookup_phase_entry(bus_phase) - ->phasemsg); - } -#endif - if (bus_phase == P_MESGIN) { - /* - * Change gears and see if - * this messages is of interest to - * us or should be passed back to - * the sequencer. - */ - ahc_outb(ahc, CLRSINT1, CLRATNO); - ahc->send_msg_perror = FALSE; - ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN; - ahc->msgin_index = 0; - goto reswitch; - } - end_session = TRUE; - break; - } - - if (ahc->send_msg_perror) { - ahc_outb(ahc, CLRSINT1, CLRATNO); - ahc_outb(ahc, CLRSINT1, CLRREQINIT); -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) - printk(" byte 0x%x\n", ahc->send_msg_perror); -#endif - ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR); - break; - } - - msgdone = ahc->msgout_index == ahc->msgout_len; - if (msgdone) { - /* - * The target has requested a retry. - * Re-assert ATN, reset our message index to - * 0, and try again. - */ - ahc->msgout_index = 0; - ahc_assert_atn(ahc); - } - - lastbyte = ahc->msgout_index == (ahc->msgout_len - 1); - if (lastbyte) { - /* Last byte is signified by dropping ATN */ - ahc_outb(ahc, CLRSINT1, CLRATNO); - } - - /* - * Clear our interrupt status and present - * the next byte on the bus. - */ - ahc_outb(ahc, CLRSINT1, CLRREQINIT); -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) - printk(" byte 0x%x\n", - ahc->msgout_buf[ahc->msgout_index]); -#endif - ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); - break; - } - case MSG_TYPE_INITIATOR_MSGIN: - { - int phasemis; - int message_done; - -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { - ahc_print_devinfo(ahc, &devinfo); - printk("INITIATOR_MSG_IN"); - } -#endif - phasemis = bus_phase != P_MESGIN; - if (phasemis) { -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { - printk(" PHASEMIS %s\n", - ahc_lookup_phase_entry(bus_phase) - ->phasemsg); - } -#endif - ahc->msgin_index = 0; - if (bus_phase == P_MESGOUT - && (ahc->send_msg_perror == TRUE - || (ahc->msgout_len != 0 - && ahc->msgout_index == 0))) { - ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - goto reswitch; - } - end_session = TRUE; - break; - } - - /* Pull the byte in without acking it */ - ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL); -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) - printk(" byte 0x%x\n", - ahc->msgin_buf[ahc->msgin_index]); -#endif - - message_done = ahc_parse_msg(ahc, &devinfo); - - if (message_done) { - /* - * Clear our incoming message buffer in case there - * is another message following this one. - */ - ahc->msgin_index = 0; - - /* - * If this message illicited a response, - * assert ATN so the target takes us to the - * message out phase. - */ - if (ahc->msgout_len != 0) { -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) { - ahc_print_devinfo(ahc, &devinfo); - printk("Asserting ATN for response\n"); - } -#endif - ahc_assert_atn(ahc); - } - } else - ahc->msgin_index++; - - if (message_done == MSGLOOP_TERMINATED) { - end_session = TRUE; - } else { - /* Ack the byte */ - ahc_outb(ahc, CLRSINT1, CLRREQINIT); - ahc_inb(ahc, SCSIDATL); - } - break; - } - case MSG_TYPE_TARGET_MSGIN: - { - int msgdone; - int msgout_request; - - if (ahc->msgout_len == 0) - panic("Target MSGIN with no active message"); - - /* - * If we interrupted a mesgout session, the initiator - * will not know this until our first REQ. So, we - * only honor mesgout requests after we've sent our - * first byte. - */ - if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0 - && ahc->msgout_index > 0) - msgout_request = TRUE; - else - msgout_request = FALSE; - - if (msgout_request) { - - /* - * Change gears and see if - * this messages is of interest to - * us or should be passed back to - * the sequencer. - */ - ahc->msg_type = MSG_TYPE_TARGET_MSGOUT; - ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO); - ahc->msgin_index = 0; - /* Dummy read to REQ for first byte */ - ahc_inb(ahc, SCSIDATL); - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - break; - } - - msgdone = ahc->msgout_index == ahc->msgout_len; - if (msgdone) { - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); - end_session = TRUE; - break; - } - - /* - * Present the next byte on the bus. - */ - ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN); - ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]); - break; - } - case MSG_TYPE_TARGET_MSGOUT: - { - int lastbyte; - int msgdone; - - /* - * The initiator signals that this is - * the last byte by dropping ATN. - */ - lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0; - - /* - * Read the latched byte, but turn off SPIOEN first - * so that we don't inadvertently cause a REQ for the - * next byte. - */ - ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN); - ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL); - msgdone = ahc_parse_msg(ahc, &devinfo); - if (msgdone == MSGLOOP_TERMINATED) { - /* - * The message is *really* done in that it caused - * us to go to bus free. The sequencer has already - * been reset at this point, so pull the ejection - * handle. - */ - return; - } - - ahc->msgin_index++; - - /* - * XXX Read spec about initiator dropping ATN too soon - * and use msgdone to detect it. - */ - if (msgdone == MSGLOOP_MSGCOMPLETE) { - ahc->msgin_index = 0; - - /* - * If this message illicited a response, transition - * to the Message in phase and send it. - */ - if (ahc->msgout_len != 0) { - ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO); - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - ahc->msg_type = MSG_TYPE_TARGET_MSGIN; - ahc->msgin_index = 0; - break; - } - } - - if (lastbyte) - end_session = TRUE; - else { - /* Ask for the next byte. */ - ahc_outb(ahc, SXFRCTL0, - ahc_inb(ahc, SXFRCTL0) | SPIOEN); - } - - break; - } - default: - panic("Unknown REQINIT message type"); - } - - if (end_session) { - ahc_clear_msg_state(ahc); - ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP); - } else - ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP); -} - -/* - * See if we sent a particular extended message to the target. - * If "full" is true, return true only if the target saw the full - * message. If "full" is false, return true if the target saw at - * least the first byte of the message. - */ -static int -ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full) -{ - int found; - u_int index; - - found = FALSE; - index = 0; - - while (index < ahc->msgout_len) { - if (ahc->msgout_buf[index] == MSG_EXTENDED) { - u_int end_index; - - end_index = index + 1 + ahc->msgout_buf[index + 1]; - if (ahc->msgout_buf[index+2] == msgval - && type == AHCMSG_EXT) { - - if (full) { - if (ahc->msgout_index > end_index) - found = TRUE; - } else if (ahc->msgout_index > index) - found = TRUE; - } - index = end_index; - } else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK - && ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) { - - /* Skip tag type and tag id or residue param*/ - index += 2; - } else { - /* Single byte message */ - if (type == AHCMSG_1B - && ahc->msgout_buf[index] == msgval - && ahc->msgout_index > index) - found = TRUE; - index++; - } - - if (found) - break; - } - return (found); -} - -/* - * Wait for a complete incoming message, parse it, and respond accordingly. - */ -static int -ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - int reject; - int done; - int response; - u_int targ_scsirate; - - done = MSGLOOP_IN_PROG; - response = FALSE; - reject = FALSE; - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid, - devinfo->target, &tstate); - targ_scsirate = tinfo->scsirate; - - /* - * Parse as much of the message as is available, - * rejecting it if we don't support it. When - * the entire message is available and has been - * handled, return MSGLOOP_MSGCOMPLETE, indicating - * that we have parsed an entire message. - * - * In the case of extended messages, we accept the length - * byte outright and perform more checking once we know the - * extended message type. - */ - switch (ahc->msgin_buf[0]) { - case MSG_DISCONNECT: - case MSG_SAVEDATAPOINTER: - case MSG_CMDCOMPLETE: - case MSG_RESTOREPOINTERS: - case MSG_IGN_WIDE_RESIDUE: - /* - * End our message loop as these are messages - * the sequencer handles on its own. - */ - done = MSGLOOP_TERMINATED; - break; - case MSG_MESSAGE_REJECT: - response = ahc_handle_msg_reject(ahc, devinfo); - /* FALLTHROUGH */ - case MSG_NOOP: - done = MSGLOOP_MSGCOMPLETE; - break; - case MSG_EXTENDED: - { - /* Wait for enough of the message to begin validation */ - if (ahc->msgin_index < 2) - break; - switch (ahc->msgin_buf[2]) { - case MSG_EXT_SDTR: - { - const struct ahc_syncrate *syncrate; - u_int period; - u_int ppr_options; - u_int offset; - u_int saved_offset; - - if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have both args before validating - * and acting on this message. - * - * Add one to MSG_EXT_SDTR_LEN to account for - * the extended message preamble. - */ - if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1)) - break; - - period = ahc->msgin_buf[3]; - ppr_options = 0; - saved_offset = offset = ahc->msgin_buf[4]; - syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, - devinfo->role); - ahc_validate_offset(ahc, tinfo, syncrate, &offset, - targ_scsirate & WIDEXFER, - devinfo->role); - if (bootverbose) { - printk("(%s:%c:%d:%d): Received " - "SDTR period %x, offset %x\n\t" - "Filtered to period %x, offset %x\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun, - ahc->msgin_buf[3], saved_offset, - period, offset); - } - ahc_set_syncrate(ahc, devinfo, - syncrate, period, - offset, ppr_options, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - - /* - * See if we initiated Sync Negotiation - * and didn't have to fall down to async - * transfers. - */ - if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, TRUE)) { - /* We started it */ - if (saved_offset != offset) { - /* Went too low - force async */ - reject = TRUE; - } - } else { - /* - * Send our own SDTR in reply - */ - if (bootverbose - && devinfo->role == ROLE_INITIATOR) { - printk("(%s:%c:%d:%d): Target " - "Initiated SDTR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - } - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_sdtr(ahc, devinfo, - period, offset); - ahc->msgout_index = 0; - response = TRUE; - } - done = MSGLOOP_MSGCOMPLETE; - break; - } - case MSG_EXT_WDTR: - { - u_int bus_width; - u_int saved_width; - u_int sending_reply; - - sending_reply = FALSE; - if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have our arg before validating - * and acting on this message. - * - * Add one to MSG_EXT_WDTR_LEN to account for - * the extended message preamble. - */ - if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1)) - break; - - bus_width = ahc->msgin_buf[3]; - saved_width = bus_width; - ahc_validate_width(ahc, tinfo, &bus_width, - devinfo->role); - if (bootverbose) { - printk("(%s:%c:%d:%d): Received WDTR " - "%x filtered to %x\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun, - saved_width, bus_width); - } - - if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, TRUE)) { - /* - * Don't send a WDTR back to the - * target, since we asked first. - * If the width went higher than our - * request, reject it. - */ - if (saved_width > bus_width) { - reject = TRUE; - printk("(%s:%c:%d:%d): requested %dBit " - "transfers. Rejecting...\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun, - 8 * (0x01 << bus_width)); - bus_width = 0; - } - } else { - /* - * Send our own WDTR in reply - */ - if (bootverbose - && devinfo->role == ROLE_INITIATOR) { - printk("(%s:%c:%d:%d): Target " - "Initiated WDTR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - } - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_wdtr(ahc, devinfo, bus_width); - ahc->msgout_index = 0; - response = TRUE; - sending_reply = TRUE; - } - /* - * After a wide message, we are async, but - * some devices don't seem to honor this portion - * of the spec. Force a renegotiation of the - * sync component of our transfer agreement even - * if our goal is async. By updating our width - * after forcing the negotiation, we avoid - * renegotiating for width. - */ - ahc_update_neg_request(ahc, devinfo, tstate, - tinfo, AHC_NEG_ALWAYS); - ahc_set_width(ahc, devinfo, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - if (sending_reply == FALSE && reject == FALSE) { - - /* - * We will always have an SDTR to send. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_build_transfer_msg(ahc, devinfo); - ahc->msgout_index = 0; - response = TRUE; - } - done = MSGLOOP_MSGCOMPLETE; - break; - } - case MSG_EXT_PPR: - { - const struct ahc_syncrate *syncrate; - u_int period; - u_int offset; - u_int bus_width; - u_int ppr_options; - u_int saved_width; - u_int saved_offset; - u_int saved_ppr_options; - - if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) { - reject = TRUE; - break; - } - - /* - * Wait until we have all args before validating - * and acting on this message. - * - * Add one to MSG_EXT_PPR_LEN to account for - * the extended message preamble. - */ - if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1)) - break; - - period = ahc->msgin_buf[3]; - offset = ahc->msgin_buf[5]; - bus_width = ahc->msgin_buf[6]; - saved_width = bus_width; - ppr_options = ahc->msgin_buf[7]; - /* - * According to the spec, a DT only - * period factor with no DT option - * set implies async. - */ - if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0 - && period == 9) - offset = 0; - saved_ppr_options = ppr_options; - saved_offset = offset; - - /* - * Mask out any options we don't support - * on any controller. Transfer options are - * only available if we are negotiating wide. - */ - ppr_options &= MSG_EXT_PPR_DT_REQ; - if (bus_width == 0) - ppr_options = 0; - - ahc_validate_width(ahc, tinfo, &bus_width, - devinfo->role); - syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period, - &ppr_options, - devinfo->role); - ahc_validate_offset(ahc, tinfo, syncrate, - &offset, bus_width, - devinfo->role); - - if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, TRUE)) { - /* - * If we are unable to do any of the - * requested options (we went too low), - * then we'll have to reject the message. - */ - if (saved_width > bus_width - || saved_offset != offset - || saved_ppr_options != ppr_options) { - reject = TRUE; - period = 0; - offset = 0; - bus_width = 0; - ppr_options = 0; - syncrate = NULL; - } - } else { - if (devinfo->role != ROLE_TARGET) - printk("(%s:%c:%d:%d): Target " - "Initiated PPR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - else - printk("(%s:%c:%d:%d): Initiator " - "Initiated PPR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_construct_ppr(ahc, devinfo, period, offset, - bus_width, ppr_options); - ahc->msgout_index = 0; - response = TRUE; - } - if (bootverbose) { - printk("(%s:%c:%d:%d): Received PPR width %x, " - "period %x, offset %x,options %x\n" - "\tFiltered to width %x, period %x, " - "offset %x, options %x\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun, - saved_width, ahc->msgin_buf[3], - saved_offset, saved_ppr_options, - bus_width, period, offset, ppr_options); - } - ahc_set_width(ahc, devinfo, bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - ahc_set_syncrate(ahc, devinfo, - syncrate, period, - offset, ppr_options, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - done = MSGLOOP_MSGCOMPLETE; - break; - } - default: - /* Unknown extended message. Reject it. */ - reject = TRUE; - break; - } - break; - } -#ifdef AHC_TARGET_MODE - case MSG_BUS_DEV_RESET: - ahc_handle_devreset(ahc, devinfo, - CAM_BDR_SENT, - "Bus Device Reset Received", - /*verbose_level*/0); - ahc_restart(ahc); - done = MSGLOOP_TERMINATED; - break; - case MSG_ABORT_TAG: - case MSG_ABORT: - case MSG_CLEAR_QUEUE: - { - int tag; - - /* Target mode messages */ - if (devinfo->role != ROLE_TARGET) { - reject = TRUE; - break; - } - tag = SCB_LIST_NULL; - if (ahc->msgin_buf[0] == MSG_ABORT_TAG) - tag = ahc_inb(ahc, INITIATOR_TAG); - ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, - devinfo->lun, tag, ROLE_TARGET, - CAM_REQ_ABORTED); - - tstate = ahc->enabled_targets[devinfo->our_scsiid]; - if (tstate != NULL) { - struct ahc_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[devinfo->lun]; - if (lstate != NULL) { - ahc_queue_lstate_event(ahc, lstate, - devinfo->our_scsiid, - ahc->msgin_buf[0], - /*arg*/tag); - ahc_send_lstate_events(ahc, lstate); - } - } - ahc_restart(ahc); - done = MSGLOOP_TERMINATED; - break; - } -#endif - case MSG_TERM_IO_PROC: - default: - reject = TRUE; - break; - } - - if (reject) { - /* - * Setup to reject the message. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 1; - ahc->msgout_buf[0] = MSG_MESSAGE_REJECT; - done = MSGLOOP_MSGCOMPLETE; - response = TRUE; - } - - if (done != MSGLOOP_IN_PROG && !response) - /* Clear the outgoing message buffer */ - ahc->msgout_len = 0; - - return (done); -} - -/* - * Process a message reject message. - */ -static int -ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - /* - * What we care about here is if we had an - * outstanding SDTR or WDTR message for this - * target. If we did, this is a signal that - * the target is refusing negotiation. - */ - struct scb *scb; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int scb_index; - u_int last_msg; - int response = 0; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, - devinfo->our_scsiid, - devinfo->target, &tstate); - /* Might be necessary */ - last_msg = ahc_inb(ahc, LAST_MSG); - - if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) { - /* - * Target does not support the PPR message. - * Attempt to negotiate SPI-2 style. - */ - if (bootverbose) { - printk("(%s:%c:%d:%d): PPR Rejected. " - "Trying WDTR/SDTR\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - } - tinfo->goal.ppr_options = 0; - tinfo->curr.transport_version = 2; - tinfo->goal.transport_version = 2; - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_build_transfer_msg(ahc, devinfo); - ahc->msgout_index = 0; - response = 1; - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) { - - /* note 8bit xfers */ - printk("(%s:%c:%d:%d): refuses WIDE negotiation. Using " - "8bit transfers\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - /* - * No need to clear the sync rate. If the target - * did not accept the command, our syncrate is - * unaffected. If the target started the negotiation, - * but rejected our response, we already cleared the - * sync rate before sending our WDTR. - */ - if (tinfo->goal.offset != tinfo->curr.offset) { - - /* Start the sync negotiation */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_build_transfer_msg(ahc, devinfo); - ahc->msgout_index = 0; - response = 1; - } - } else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) { - /* note asynch xfers and clear flag */ - ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, - /*paused*/TRUE); - printk("(%s:%c:%d:%d): refuses synchronous negotiation. " - "Using asynchronous transfers\n", - ahc_name(ahc), devinfo->channel, - devinfo->target, devinfo->lun); - } else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) { - int tag_type; - int mask; - - tag_type = (scb->hscb->control & MSG_SIMPLE_TASK); - - if (tag_type == MSG_SIMPLE_TASK) { - printk("(%s:%c:%d:%d): refuses tagged commands. " - "Performing non-tagged I/O\n", ahc_name(ahc), - devinfo->channel, devinfo->target, devinfo->lun); - ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_NONE); - mask = ~0x23; - } else { - printk("(%s:%c:%d:%d): refuses %s tagged commands. " - "Performing simple queue tagged I/O only\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - devinfo->lun, tag_type == MSG_ORDERED_TASK - ? "ordered" : "head of queue"); - ahc_set_tags(ahc, scb->io_ctx, devinfo, AHC_QUEUE_BASIC); - mask = ~0x03; - } - - /* - * Resend the identify for this CCB as the target - * may believe that the selection is invalid otherwise. - */ - ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL) & mask); - scb->hscb->control &= mask; - ahc_set_transaction_tag(scb, /*enabled*/FALSE, - /*type*/MSG_SIMPLE_TASK); - ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG); - ahc_assert_atn(ahc); - - /* - * This transaction is now at the head of - * the untagged queue for this target. - */ - if ((ahc->flags & AHC_SCB_BTT) == 0) { - struct scb_tailq *untagged_q; - - untagged_q = - &(ahc->untagged_queues[devinfo->target_offset]); - TAILQ_INSERT_HEAD(untagged_q, scb, links.tqe); - scb->flags |= SCB_UNTAGGEDQ; - } - ahc_busy_tcl(ahc, BUILD_TCL(scb->hscb->scsiid, devinfo->lun), - scb->hscb->tag); - - /* - * Requeue all tagged commands for this target - * currently in our possession so they can be - * converted to untagged commands. - */ - ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb), - SCB_GET_CHANNEL(ahc, scb), - SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ, - SEARCH_COMPLETE); - } else { - /* - * Otherwise, we ignore it. - */ - printk("%s:%c:%d: Message reject for %x -- ignored\n", - ahc_name(ahc), devinfo->channel, devinfo->target, - last_msg); - } - return (response); -} - -/* - * Process an ingnore wide residue message. - */ -static void -ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - u_int scb_index; - struct scb *scb; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - /* - * XXX Actually check data direction in the sequencer? - * Perhaps add datadir to some spare bits in the hscb? - */ - if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0 - || ahc_get_transfer_dir(scb) != CAM_DIR_IN) { - /* - * Ignore the message if we haven't - * seen an appropriate data phase yet. - */ - } else { - /* - * If the residual occurred on the last - * transfer and the transfer request was - * expected to end on an odd count, do - * nothing. Otherwise, subtract a byte - * and update the residual count accordingly. - */ - uint32_t sgptr; - - sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR); - if ((sgptr & SG_LIST_NULL) != 0 - && (ahc_inb(ahc, SCB_LUN) & SCB_XFERLEN_ODD) != 0) { - /* - * If the residual occurred on the last - * transfer and the transfer request was - * expected to end on an odd count, do - * nothing. - */ - } else { - struct ahc_dma_seg *sg; - uint32_t data_cnt; - uint32_t data_addr; - uint32_t sglen; - - /* Pull in all of the sgptr */ - sgptr = ahc_inl(ahc, SCB_RESIDUAL_SGPTR); - data_cnt = ahc_inl(ahc, SCB_RESIDUAL_DATACNT); - - if ((sgptr & SG_LIST_NULL) != 0) { - /* - * The residual data count is not updated - * for the command run to completion case. - * Explicitly zero the count. - */ - data_cnt &= ~AHC_SG_LEN_MASK; - } - - data_addr = ahc_inl(ahc, SHADDR); - - data_cnt += 1; - data_addr -= 1; - sgptr &= SG_PTR_MASK; - - sg = ahc_sg_bus_to_virt(scb, sgptr); - - /* - * The residual sg ptr points to the next S/G - * to load so we must go back one. - */ - sg--; - sglen = ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; - if (sg != scb->sg_list - && sglen < (data_cnt & AHC_SG_LEN_MASK)) { - - sg--; - sglen = ahc_le32toh(sg->len); - /* - * Preserve High Address and SG_LIST bits - * while setting the count to 1. - */ - data_cnt = 1 | (sglen & (~AHC_SG_LEN_MASK)); - data_addr = ahc_le32toh(sg->addr) - + (sglen & AHC_SG_LEN_MASK) - 1; - - /* - * Increment sg so it points to the - * "next" sg. - */ - sg++; - sgptr = ahc_sg_virt_to_bus(scb, sg); - } - ahc_outl(ahc, SCB_RESIDUAL_SGPTR, sgptr); - ahc_outl(ahc, SCB_RESIDUAL_DATACNT, data_cnt); - /* - * Toggle the "oddness" of the transfer length - * to handle this mid-transfer ignore wide - * residue. This ensures that the oddness is - * correct for subsequent data transfers. - */ - ahc_outb(ahc, SCB_LUN, - ahc_inb(ahc, SCB_LUN) ^ SCB_XFERLEN_ODD); - } - } -} - - -/* - * Reinitialize the data pointers for the active transfer - * based on its current residual. - */ -static void -ahc_reinitialize_dataptrs(struct ahc_softc *ahc) -{ - struct scb *scb; - struct ahc_dma_seg *sg; - u_int scb_index; - uint32_t sgptr; - uint32_t resid; - uint32_t dataptr; - - scb_index = ahc_inb(ahc, SCB_TAG); - scb = ahc_lookup_scb(ahc, scb_index); - sgptr = (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8) - | ahc_inb(ahc, SCB_RESIDUAL_SGPTR); - - sgptr &= SG_PTR_MASK; - sg = ahc_sg_bus_to_virt(scb, sgptr); - - /* The residual sg_ptr always points to the next sg */ - sg--; - - resid = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 1) << 8) - | ahc_inb(ahc, SCB_RESIDUAL_DATACNT); - - dataptr = ahc_le32toh(sg->addr) - + (ahc_le32toh(sg->len) & AHC_SG_LEN_MASK) - - resid; - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - u_int dscommand1; - - dscommand1 = ahc_inb(ahc, DSCOMMAND1); - ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0); - ahc_outb(ahc, HADDR, - (ahc_le32toh(sg->len) >> 24) & SG_HIGH_ADDR_BITS); - ahc_outb(ahc, DSCOMMAND1, dscommand1); - } - ahc_outb(ahc, HADDR + 3, dataptr >> 24); - ahc_outb(ahc, HADDR + 2, dataptr >> 16); - ahc_outb(ahc, HADDR + 1, dataptr >> 8); - ahc_outb(ahc, HADDR, dataptr); - ahc_outb(ahc, HCNT + 2, resid >> 16); - ahc_outb(ahc, HCNT + 1, resid >> 8); - ahc_outb(ahc, HCNT, resid); - if ((ahc->features & AHC_ULTRA2) == 0) { - ahc_outb(ahc, STCNT + 2, resid >> 16); - ahc_outb(ahc, STCNT + 1, resid >> 8); - ahc_outb(ahc, STCNT, resid); - } -} - -/* - * Handle the effects of issuing a bus device reset message. - */ -static void -ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - cam_status status, char *message, int verbose_level) -{ -#ifdef AHC_TARGET_MODE - struct ahc_tmode_tstate* tstate; - u_int lun; -#endif - int found; - - found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel, - CAM_LUN_WILDCARD, SCB_LIST_NULL, devinfo->role, - status); - -#ifdef AHC_TARGET_MODE - /* - * Send an immediate notify ccb to all target mord peripheral - * drivers affected by this action. - */ - tstate = ahc->enabled_targets[devinfo->our_scsiid]; - if (tstate != NULL) { - for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct ahc_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[lun]; - if (lstate == NULL) - continue; - - ahc_queue_lstate_event(ahc, lstate, devinfo->our_scsiid, - MSG_BUS_DEV_RESET, /*arg*/0); - ahc_send_lstate_events(ahc, lstate); - } - } -#endif - - /* - * Go back to async/narrow transfers and renegotiate. - */ - ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_CUR, /*paused*/TRUE); - ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, - /*period*/0, /*offset*/0, /*ppr_options*/0, - AHC_TRANS_CUR, /*paused*/TRUE); - - if (status != CAM_SEL_TIMEOUT) - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR); - - if (message != NULL - && (verbose_level <= bootverbose)) - printk("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc), - message, devinfo->channel, devinfo->target, found); -} - -#ifdef AHC_TARGET_MODE -static void -ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, - struct scb *scb) -{ - - /* - * To facilitate adding multiple messages together, - * each routine should increment the index and len - * variables instead of setting them explicitly. - */ - ahc->msgout_index = 0; - ahc->msgout_len = 0; - - if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0) - ahc_build_transfer_msg(ahc, devinfo); - else - panic("ahc_intr: AWAITING target message with no message"); - - ahc->msgout_index = 0; - ahc->msg_type = MSG_TYPE_TARGET_MSGIN; -} -#endif -/**************************** Initialization **********************************/ -/* - * Allocate a controller structure for a new device - * and perform initial initializion. - */ -struct ahc_softc * -ahc_alloc(void *platform_arg, char *name) -{ - struct ahc_softc *ahc; - int i; - -#ifndef __FreeBSD__ - ahc = kmalloc(sizeof(*ahc), GFP_ATOMIC); - if (!ahc) { - printk("aic7xxx: cannot malloc softc!\n"); - kfree(name); - return NULL; - } -#else - ahc = device_get_softc((device_t)platform_arg); -#endif - memset(ahc, 0, sizeof(*ahc)); - ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC); - if (ahc->seep_config == NULL) { -#ifndef __FreeBSD__ - kfree(ahc); -#endif - kfree(name); - return (NULL); - } - LIST_INIT(&ahc->pending_scbs); - /* We don't know our unit number until the OSM sets it */ - ahc->name = name; - ahc->unit = -1; - ahc->description = NULL; - ahc->channel = 'A'; - ahc->channel_b = 'B'; - ahc->chip = AHC_NONE; - ahc->features = AHC_FENONE; - ahc->bugs = AHC_BUGNONE; - ahc->flags = AHC_FNONE; - /* - * Default to all error reporting enabled with the - * sequencer operating at its fastest speed. - * The bus attach code may modify this. - */ - ahc->seqctl = FASTMODE; - - for (i = 0; i < AHC_NUM_TARGETS; i++) - TAILQ_INIT(&ahc->untagged_queues[i]); - if (ahc_platform_alloc(ahc, platform_arg) != 0) { - ahc_free(ahc); - ahc = NULL; - } - return (ahc); -} - -int -ahc_softc_init(struct ahc_softc *ahc) -{ - - /* The IRQMS bit is only valid on VL and EISA chips */ - if ((ahc->chip & AHC_PCI) == 0) - ahc->unpause = ahc_inb(ahc, HCNTRL) & IRQMS; - else - ahc->unpause = 0; - ahc->pause = ahc->unpause | PAUSE; - /* XXX The shared scb data stuff should be deprecated */ - if (ahc->scb_data == NULL) { - ahc->scb_data = kmalloc(sizeof(*ahc->scb_data), GFP_ATOMIC); - if (ahc->scb_data == NULL) - return (ENOMEM); - memset(ahc->scb_data, 0, sizeof(*ahc->scb_data)); - } - - return (0); -} - -void -ahc_set_unit(struct ahc_softc *ahc, int unit) -{ - ahc->unit = unit; -} - -void -ahc_set_name(struct ahc_softc *ahc, char *name) -{ - if (ahc->name != NULL) - kfree(ahc->name); - ahc->name = name; -} - -void -ahc_free(struct ahc_softc *ahc) -{ - int i; - - switch (ahc->init_level) { - default: - case 5: - ahc_shutdown(ahc); - /* FALLTHROUGH */ - case 4: - ahc_dmamap_unload(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap); - /* FALLTHROUGH */ - case 3: - ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo, - ahc->shared_data_dmamap); - ahc_dmamap_destroy(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap); - /* FALLTHROUGH */ - case 2: - ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat); - case 1: -#ifndef __linux__ - ahc_dma_tag_destroy(ahc, ahc->buffer_dmat); -#endif - break; - case 0: - break; - } - -#ifndef __linux__ - ahc_dma_tag_destroy(ahc, ahc->parent_dmat); -#endif - ahc_platform_free(ahc); - ahc_fini_scbdata(ahc); - for (i = 0; i < AHC_NUM_TARGETS; i++) { - struct ahc_tmode_tstate *tstate; - - tstate = ahc->enabled_targets[i]; - if (tstate != NULL) { -#ifdef AHC_TARGET_MODE - int j; - - for (j = 0; j < AHC_NUM_LUNS; j++) { - struct ahc_tmode_lstate *lstate; - - lstate = tstate->enabled_luns[j]; - if (lstate != NULL) { - xpt_free_path(lstate->path); - kfree(lstate); - } - } -#endif - kfree(tstate); - } - } -#ifdef AHC_TARGET_MODE - if (ahc->black_hole != NULL) { - xpt_free_path(ahc->black_hole->path); - kfree(ahc->black_hole); - } -#endif - if (ahc->name != NULL) - kfree(ahc->name); - if (ahc->seep_config != NULL) - kfree(ahc->seep_config); -#ifndef __FreeBSD__ - kfree(ahc); -#endif - return; -} - -static void -ahc_shutdown(void *arg) -{ - struct ahc_softc *ahc; - int i; - - ahc = (struct ahc_softc *)arg; - - /* This will reset most registers to 0, but not all */ - ahc_reset(ahc, /*reinit*/FALSE); - ahc_outb(ahc, SCSISEQ, 0); - ahc_outb(ahc, SXFRCTL0, 0); - ahc_outb(ahc, DSPCISTATUS, 0); - - for (i = TARG_SCSIRATE; i < SCSICONF; i++) - ahc_outb(ahc, i, 0); -} - -/* - * Reset the controller and record some information about it - * that is only available just after a reset. If "reinit" is - * non-zero, this reset occurred after initial configuration - * and the caller requests that the chip be fully reinitialized - * to a runable state. Chip interrupts are *not* enabled after - * a reinitialization. The caller must enable interrupts via - * ahc_intr_enable(). - */ -int -ahc_reset(struct ahc_softc *ahc, int reinit) -{ - u_int sblkctl; - u_int sxfrctl1_a, sxfrctl1_b; - int error; - int wait; - - /* - * Preserve the value of the SXFRCTL1 register for all channels. - * It contains settings that affect termination and we don't want - * to disturb the integrity of the bus. - */ - ahc_pause(ahc); - sxfrctl1_b = 0; - if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { - u_int sblkctl; - - /* - * Save channel B's settings in case this chip - * is setup for TWIN channel operation. - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB); - sxfrctl1_b = ahc_inb(ahc, SXFRCTL1); - ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB); - } - sxfrctl1_a = ahc_inb(ahc, SXFRCTL1); - - ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause); - - /* - * Ensure that the reset has finished. We delay 1000us - * prior to reading the register to make sure the chip - * has sufficiently completed its reset to handle register - * accesses. - */ - wait = 1000; - do { - ahc_delay(1000); - } while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK)); - - if (wait == 0) { - printk("%s: WARNING - Failed chip reset! " - "Trying to initialize anyway.\n", ahc_name(ahc)); - } - ahc_outb(ahc, HCNTRL, ahc->pause); - - /* Determine channel configuration */ - sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE); - /* No Twin Channel PCI cards */ - if ((ahc->chip & AHC_PCI) != 0) - sblkctl &= ~SELBUSB; - switch (sblkctl) { - case 0: - /* Single Narrow Channel */ - break; - case 2: - /* Wide Channel */ - ahc->features |= AHC_WIDE; - break; - case 8: - /* Twin Channel */ - ahc->features |= AHC_TWIN; - break; - default: - printk(" Unsupported adapter type. Ignoring\n"); - return(-1); - } - - /* - * Reload sxfrctl1. - * - * We must always initialize STPWEN to 1 before we - * restore the saved values. STPWEN is initialized - * to a tri-state condition which can only be cleared - * by turning it on. - */ - if ((ahc->features & AHC_TWIN) != 0) { - u_int sblkctl; - - sblkctl = ahc_inb(ahc, SBLKCTL); - ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB); - ahc_outb(ahc, SXFRCTL1, sxfrctl1_b); - ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB); - } - ahc_outb(ahc, SXFRCTL1, sxfrctl1_a); - - error = 0; - if (reinit != 0) - /* - * If a recovery action has forced a chip reset, - * re-initialize the chip to our liking. - */ - error = ahc->bus_chip_init(ahc); -#ifdef AHC_DUMP_SEQ - else - ahc_dumpseq(ahc); -#endif - - return (error); -} - -/* - * Determine the number of SCBs available on the controller - */ -int -ahc_probe_scbs(struct ahc_softc *ahc) { - int i; - - for (i = 0; i < AHC_SCB_MAX; i++) { - - ahc_outb(ahc, SCBPTR, i); - ahc_outb(ahc, SCB_BASE, i); - if (ahc_inb(ahc, SCB_BASE) != i) - break; - ahc_outb(ahc, SCBPTR, 0); - if (ahc_inb(ahc, SCB_BASE) != 0) - break; - } - return (i); -} - -static void -ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) -{ - dma_addr_t *baddr; - - baddr = (dma_addr_t *)arg; - *baddr = segs->ds_addr; -} - -static void -ahc_build_free_scb_list(struct ahc_softc *ahc) -{ - int scbsize; - int i; - - scbsize = 32; - if ((ahc->flags & AHC_LSCBS_ENABLED) != 0) - scbsize = 64; - - for (i = 0; i < ahc->scb_data->maxhscbs; i++) { - int j; - - ahc_outb(ahc, SCBPTR, i); - - /* - * Touch all SCB bytes to avoid parity errors - * should one of our debugging routines read - * an otherwise uninitiatlized byte. - */ - for (j = 0; j < scbsize; j++) - ahc_outb(ahc, SCB_BASE+j, 0xFF); - - /* Clear the control byte. */ - ahc_outb(ahc, SCB_CONTROL, 0); - - /* Set the next pointer */ - if ((ahc->flags & AHC_PAGESCBS) != 0) - ahc_outb(ahc, SCB_NEXT, i+1); - else - ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); - - /* Make the tag number, SCSIID, and lun invalid */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - ahc_outb(ahc, SCB_SCSIID, 0xFF); - ahc_outb(ahc, SCB_LUN, 0xFF); - } - - if ((ahc->flags & AHC_PAGESCBS) != 0) { - /* SCB 0 heads the free list. */ - ahc_outb(ahc, FREE_SCBH, 0); - } else { - /* No free list. */ - ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL); - } - - /* Make sure that the last SCB terminates the free list */ - ahc_outb(ahc, SCBPTR, i-1); - ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL); -} - -static int -ahc_init_scbdata(struct ahc_softc *ahc) -{ - struct scb_data *scb_data; - - scb_data = ahc->scb_data; - SLIST_INIT(&scb_data->free_scbs); - SLIST_INIT(&scb_data->sg_maps); - - /* Allocate SCB resources */ - scb_data->scbarray = kmalloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC, GFP_ATOMIC); - if (scb_data->scbarray == NULL) - return (ENOMEM); - memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC); - - /* Determine the number of hardware SCBs and initialize them */ - - scb_data->maxhscbs = ahc_probe_scbs(ahc); - if (ahc->scb_data->maxhscbs == 0) { - printk("%s: No SCB space found\n", ahc_name(ahc)); - return (ENXIO); - } - - /* - * Create our DMA tags. These tags define the kinds of device - * accessible memory allocations and memory mappings we will - * need to perform during normal operation. - * - * Unless we need to further restrict the allocation, we rely - * on the restrictions of the parent dmat, hence the common - * use of MAXADDR and MAXSIZE. - */ - - /* DMA tag for our hardware scb structures */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), - /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->hscb_dmat) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* Allocation for our hscbs */ - if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat, - (void **)&scb_data->hscbs, - BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* And permanently map them */ - ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap, - scb_data->hscbs, - AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb), - ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0); - - scb_data->init_level++; - - /* DMA tag for our sense buffers */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), - /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->sense_dmat) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* Allocate them */ - if (ahc_dmamem_alloc(ahc, scb_data->sense_dmat, - (void **)&scb_data->sense, - BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* And permanently map them */ - ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap, - scb_data->sense, - AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data), - ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0); - - scb_data->init_level++; - - /* DMA tag for our S/G structures. We allocate in page sized chunks */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/8, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - PAGE_SIZE, /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &scb_data->sg_dmat) != 0) { - goto error_exit; - } - - scb_data->init_level++; - - /* Perform initial CCB allocation */ - memset(scb_data->hscbs, 0, - AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb)); - ahc_alloc_scbs(ahc); - - if (scb_data->numscbs == 0) { - printk("%s: ahc_init_scbdata - " - "Unable to allocate initial scbs\n", - ahc_name(ahc)); - goto error_exit; - } - - /* - * Reserve the next queued SCB. - */ - ahc->next_queued_scb = ahc_get_scb(ahc); - - /* - * Note that we were successful - */ - return (0); - -error_exit: - - return (ENOMEM); -} - -static void -ahc_fini_scbdata(struct ahc_softc *ahc) -{ - struct scb_data *scb_data; - - scb_data = ahc->scb_data; - if (scb_data == NULL) - return; - - switch (scb_data->init_level) { - default: - case 7: - { - struct sg_map_node *sg_map; - - while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) { - SLIST_REMOVE_HEAD(&scb_data->sg_maps, links); - ahc_dmamap_unload(ahc, scb_data->sg_dmat, - sg_map->sg_dmamap); - ahc_dmamem_free(ahc, scb_data->sg_dmat, - sg_map->sg_vaddr, - sg_map->sg_dmamap); - kfree(sg_map); - } - ahc_dma_tag_destroy(ahc, scb_data->sg_dmat); - } - case 6: - ahc_dmamap_unload(ahc, scb_data->sense_dmat, - scb_data->sense_dmamap); - case 5: - ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense, - scb_data->sense_dmamap); - ahc_dmamap_destroy(ahc, scb_data->sense_dmat, - scb_data->sense_dmamap); - case 4: - ahc_dma_tag_destroy(ahc, scb_data->sense_dmat); - case 3: - ahc_dmamap_unload(ahc, scb_data->hscb_dmat, - scb_data->hscb_dmamap); - case 2: - ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs, - scb_data->hscb_dmamap); - ahc_dmamap_destroy(ahc, scb_data->hscb_dmat, - scb_data->hscb_dmamap); - case 1: - ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat); - break; - case 0: - break; - } - if (scb_data->scbarray != NULL) - kfree(scb_data->scbarray); -} - -static void -ahc_alloc_scbs(struct ahc_softc *ahc) -{ - struct scb_data *scb_data; - struct scb *next_scb; - struct sg_map_node *sg_map; - dma_addr_t physaddr; - struct ahc_dma_seg *segs; - int newcount; - int i; - - scb_data = ahc->scb_data; - if (scb_data->numscbs >= AHC_SCB_MAX_ALLOC) - /* Can't allocate any more */ - return; - - next_scb = &scb_data->scbarray[scb_data->numscbs]; - - sg_map = kmalloc(sizeof(*sg_map), GFP_ATOMIC); - - if (sg_map == NULL) - return; - - /* Allocate S/G space for the next batch of SCBS */ - if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat, - (void **)&sg_map->sg_vaddr, - BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) { - kfree(sg_map); - return; - } - - SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links); - - ahc_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap, - sg_map->sg_vaddr, PAGE_SIZE, ahc_dmamap_cb, - &sg_map->sg_physaddr, /*flags*/0); - - segs = sg_map->sg_vaddr; - physaddr = sg_map->sg_physaddr; - - newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg))); - newcount = min(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs)); - for (i = 0; i < newcount; i++) { - struct scb_platform_data *pdata; -#ifndef __linux__ - int error; -#endif - pdata = kmalloc(sizeof(*pdata), GFP_ATOMIC); - if (pdata == NULL) - break; - next_scb->platform_data = pdata; - next_scb->sg_map = sg_map; - next_scb->sg_list = segs; - /* - * The sequencer always starts with the second entry. - * The first entry is embedded in the scb. - */ - next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg); - next_scb->ahc_softc = ahc; - next_scb->flags = SCB_FREE; -#ifndef __linux__ - error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0, - &next_scb->dmamap); - if (error != 0) - break; -#endif - next_scb->hscb = &scb_data->hscbs[scb_data->numscbs]; - next_scb->hscb->tag = ahc->scb_data->numscbs; - SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, - next_scb, links.sle); - segs += AHC_NSEG; - physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg)); - next_scb++; - ahc->scb_data->numscbs++; - } -} - -void -ahc_controller_info(struct ahc_softc *ahc, char *buf) -{ - int len; - - len = sprintf(buf, "%s: ", ahc_chip_names[ahc->chip & AHC_CHIPID_MASK]); - buf += len; - if ((ahc->features & AHC_TWIN) != 0) - len = sprintf(buf, "Twin Channel, A SCSI Id=%d, " - "B SCSI Id=%d, primary %c, ", - ahc->our_id, ahc->our_id_b, - (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A'); - else { - const char *speed; - const char *type; - - speed = ""; - if ((ahc->features & AHC_ULTRA) != 0) { - speed = "Ultra "; - } else if ((ahc->features & AHC_DT) != 0) { - speed = "Ultra160 "; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - speed = "Ultra2 "; - } - if ((ahc->features & AHC_WIDE) != 0) { - type = "Wide"; - } else { - type = "Single"; - } - len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ", - speed, type, ahc->channel, ahc->our_id); - } - buf += len; - - if ((ahc->flags & AHC_PAGESCBS) != 0) - sprintf(buf, "%d/%d SCBs", - ahc->scb_data->maxhscbs, AHC_MAX_QUEUE); - else - sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs); -} - -int -ahc_chip_init(struct ahc_softc *ahc) -{ - int term; - int error; - u_int i; - u_int scsi_conf; - u_int scsiseq_template; - uint32_t physaddr; - - ahc_outb(ahc, SEQ_FLAGS, 0); - ahc_outb(ahc, SEQ_FLAGS2, 0); - - /* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/ - if (ahc->features & AHC_TWIN) { - - /* - * Setup Channel B first. - */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB); - term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0; - ahc_outb(ahc, SCSIID, ahc->our_id_b); - scsi_conf = ahc_inb(ahc, SCSICONF + 1); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |term|ahc->seltime_b|ENSTIMER|ACTNEGEN); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - - /* Select Channel A */ - ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB); - } - term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0; - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id); - else - ahc_outb(ahc, SCSIID, ahc->our_id); - scsi_conf = ahc_inb(ahc, SCSICONF); - ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL)) - |term|ahc->seltime - |ENSTIMER|ACTNEGEN); - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR); - ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR); - ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN); - - /* There are no untagged SCBs active yet. */ - for (i = 0; i < 16; i++) { - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0)); - if ((ahc->flags & AHC_SCB_BTT) != 0) { - int lun; - - /* - * The SCB based BTT allows an entry per - * target and lun pair. - */ - for (lun = 1; lun < AHC_NUM_LUNS; lun++) - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun)); - } - } - - /* All of our queues are empty */ - for (i = 0; i < 256; i++) - ahc->qoutfifo[i] = SCB_LIST_NULL; - ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD); - - for (i = 0; i < 256; i++) - ahc->qinfifo[i] = SCB_LIST_NULL; - - if ((ahc->features & AHC_MULTI_TID) != 0) { - ahc_outb(ahc, TARGID, 0); - ahc_outb(ahc, TARGID + 1, 0); - } - - /* - * Tell the sequencer where it can find our arrays in memory. - */ - physaddr = ahc->scb_data->hscb_busaddr; - ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF); - - physaddr = ahc->shared_data_busaddr; - ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF); - ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF); - - /* - * Initialize the group code to command length table. - * This overrides the values in TARG_SCSIRATE, so only - * setup the table after we have processed that information. - */ - ahc_outb(ahc, CMDSIZE_TABLE, 5); - ahc_outb(ahc, CMDSIZE_TABLE + 1, 9); - ahc_outb(ahc, CMDSIZE_TABLE + 2, 9); - ahc_outb(ahc, CMDSIZE_TABLE + 3, 0); - ahc_outb(ahc, CMDSIZE_TABLE + 4, 15); - ahc_outb(ahc, CMDSIZE_TABLE + 5, 11); - ahc_outb(ahc, CMDSIZE_TABLE + 6, 0); - ahc_outb(ahc, CMDSIZE_TABLE + 7, 0); - - if ((ahc->features & AHC_HS_MAILBOX) != 0) - ahc_outb(ahc, HS_MAILBOX, 0); - - /* Tell the sequencer of our initial queue positions */ - if ((ahc->features & AHC_TARGETMODE) != 0) { - ahc->tqinfifonext = 1; - ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1); - ahc_outb(ahc, TQINPOS, ahc->tqinfifonext); - } - ahc->qinfifonext = 0; - ahc->qoutfifonext = 0; - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256); - ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); - ahc_outb(ahc, SNSCB_QOFF, ahc->qinfifonext); - ahc_outb(ahc, SDSCB_QOFF, 0); - } else { - ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); - ahc_outb(ahc, QINPOS, ahc->qinfifonext); - ahc_outb(ahc, QOUTPOS, ahc->qoutfifonext); - } - - /* We don't have any waiting selections */ - ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL); - - /* Our disconnection list is empty too */ - ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL); - - /* Message out buffer starts empty */ - ahc_outb(ahc, MSG_OUT, MSG_NOOP); - - /* - * Setup the allowed SCSI Sequences based on operational mode. - * If we are a target, we'll enable select in operations once - * we've had a lun enabled. - */ - scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP; - if ((ahc->flags & AHC_INITIATORROLE) != 0) - scsiseq_template |= ENRSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template); - - /* Initialize our list of free SCBs. */ - ahc_build_free_scb_list(ahc); - - /* - * Tell the sequencer which SCB will be the next one it receives. - */ - ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); - - /* - * Load the Sequencer program and Enable the adapter - * in "fast" mode. - */ - if (bootverbose) - printk("%s: Downloading Sequencer Program...", - ahc_name(ahc)); - - error = ahc_loadseq(ahc); - if (error != 0) - return (error); - - if ((ahc->features & AHC_ULTRA2) != 0) { - int wait; - - /* - * Wait for up to 500ms for our transceivers - * to settle. If the adapter does not have - * a cable attached, the transceivers may - * never settle, so don't complain if we - * fail here. - */ - for (wait = 5000; - (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; - wait--) - ahc_delay(100); - } - ahc_restart(ahc); - return (0); -} - -/* - * Start the board, ready for normal operation - */ -int -ahc_init(struct ahc_softc *ahc) -{ - int max_targ; - u_int i; - u_int scsi_conf; - u_int ultraenb; - u_int discenable; - u_int tagenable; - size_t driver_data_size; - -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_DEBUG_SEQUENCER) != 0) - ahc->flags |= AHC_SEQUENCER_DEBUG; -#endif - -#ifdef AHC_PRINT_SRAM - printk("Scratch Ram:"); - for (i = 0x20; i < 0x5f; i++) { - if (((i % 8) == 0) && (i != 0)) { - printk ("\n "); - } - printk (" 0x%x", ahc_inb(ahc, i)); - } - if ((ahc->features & AHC_MORE_SRAM) != 0) { - for (i = 0x70; i < 0x7f; i++) { - if (((i % 8) == 0) && (i != 0)) { - printk ("\n "); - } - printk (" 0x%x", ahc_inb(ahc, i)); - } - } - printk ("\n"); - /* - * Reading uninitialized scratch ram may - * generate parity errors. - */ - ahc_outb(ahc, CLRINT, CLRPARERR); - ahc_outb(ahc, CLRINT, CLRBRKADRINT); -#endif - max_targ = 15; - - /* - * Assume we have a board at this stage and it has been reset. - */ - if ((ahc->flags & AHC_USEDEFAULTS) != 0) - ahc->our_id = ahc->our_id_b = 7; - - /* - * Default to allowing initiator operations. - */ - ahc->flags |= AHC_INITIATORROLE; - - /* - * Only allow target mode features if this unit has them enabled. - */ - if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0) - ahc->features &= ~AHC_TARGETMODE; - -#ifndef __linux__ - /* DMA tag for mapping buffers into device visible space. */ - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/ahc->flags & AHC_39BIT_ADDRESSING - ? (dma_addr_t)0x7FFFFFFFFFULL - : BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - /*maxsize*/(AHC_NSEG - 1) * PAGE_SIZE, - /*nsegments*/AHC_NSEG, - /*maxsegsz*/AHC_MAXTRANSFER_SIZE, - /*flags*/BUS_DMA_ALLOCNOW, - &ahc->buffer_dmat) != 0) { - return (ENOMEM); - } -#endif - - ahc->init_level++; - - /* - * DMA tag for our command fifos and other data in system memory - * the card's sequencer must be able to access. For initiator - * roles, we need to allocate space for the qinfifo and qoutfifo. - * The qinfifo and qoutfifo are composed of 256 1 byte elements. - * When providing for the target mode role, we must additionally - * provide space for the incoming target command fifo and an extra - * byte to deal with a dma bug in some chip versions. - */ - driver_data_size = 2 * 256 * sizeof(uint8_t); - if ((ahc->features & AHC_TARGETMODE) != 0) - driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd) - + /*DMA WideOdd Bug Buffer*/1; - if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1, - /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1, - /*lowaddr*/BUS_SPACE_MAXADDR_32BIT, - /*highaddr*/BUS_SPACE_MAXADDR, - /*filter*/NULL, /*filterarg*/NULL, - driver_data_size, - /*nsegments*/1, - /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT, - /*flags*/0, &ahc->shared_data_dmat) != 0) { - return (ENOMEM); - } - - ahc->init_level++; - - /* Allocation of driver data */ - if (ahc_dmamem_alloc(ahc, ahc->shared_data_dmat, - (void **)&ahc->qoutfifo, - BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) { - return (ENOMEM); - } - - ahc->init_level++; - - /* And permanently map it in */ - ahc_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap, - ahc->qoutfifo, driver_data_size, ahc_dmamap_cb, - &ahc->shared_data_busaddr, /*flags*/0); - - if ((ahc->features & AHC_TARGETMODE) != 0) { - ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo; - ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[AHC_TMODE_CMDS]; - ahc->dma_bug_buf = ahc->shared_data_busaddr - + driver_data_size - 1; - /* All target command blocks start out invalid. */ - for (i = 0; i < AHC_TMODE_CMDS; i++) - ahc->targetcmds[i].cmd_valid = 0; - ahc_sync_tqinfifo(ahc, BUS_DMASYNC_PREREAD); - ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256]; - } - ahc->qinfifo = &ahc->qoutfifo[256]; - - ahc->init_level++; - - /* Allocate SCB data now that buffer_dmat is initialized */ - if (ahc->scb_data->maxhscbs == 0) - if (ahc_init_scbdata(ahc) != 0) - return (ENOMEM); - - /* - * Allocate a tstate to house information for our - * initiator presence on the bus as well as the user - * data for any target mode initiator. - */ - if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) { - printk("%s: unable to allocate ahc_tmode_tstate. " - "Failing attach\n", ahc_name(ahc)); - return (ENOMEM); - } - - if ((ahc->features & AHC_TWIN) != 0) { - if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) { - printk("%s: unable to allocate ahc_tmode_tstate. " - "Failing attach\n", ahc_name(ahc)); - return (ENOMEM); - } - } - - if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) { - ahc->flags |= AHC_PAGESCBS; - } else { - ahc->flags &= ~AHC_PAGESCBS; - } - -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOW_MISC) { - printk("%s: hardware scb %u bytes; kernel scb %u bytes; " - "ahc_dma %u bytes\n", - ahc_name(ahc), - (u_int)sizeof(struct hardware_scb), - (u_int)sizeof(struct scb), - (u_int)sizeof(struct ahc_dma_seg)); - } -#endif /* AHC_DEBUG */ - - /* - * Look at the information that board initialization or - * the board bios has left us. - */ - if (ahc->features & AHC_TWIN) { - scsi_conf = ahc_inb(ahc, SCSICONF + 1); - if ((scsi_conf & RESET_SCSI) != 0 - && (ahc->flags & AHC_INITIATORROLE) != 0) - ahc->flags |= AHC_RESET_BUS_B; - } - - scsi_conf = ahc_inb(ahc, SCSICONF); - if ((scsi_conf & RESET_SCSI) != 0 - && (ahc->flags & AHC_INITIATORROLE) != 0) - ahc->flags |= AHC_RESET_BUS_A; - - ultraenb = 0; - tagenable = ALL_TARGETS_MASK; - - /* Grab the disconnection disable table and invert it for our needs */ - if ((ahc->flags & AHC_USEDEFAULTS) != 0) { - printk("%s: Host Adapter Bios disabled. Using default SCSI " - "device parameters\n", ahc_name(ahc)); - ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B| - AHC_TERM_ENB_A|AHC_TERM_ENB_B; - discenable = ALL_TARGETS_MASK; - if ((ahc->features & AHC_ULTRA) != 0) - ultraenb = ALL_TARGETS_MASK; - } else { - discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8) - | ahc_inb(ahc, DISC_DSB)); - if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0) - ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8) - | ahc_inb(ahc, ULTRA_ENB); - } - - if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) - max_targ = 7; - - for (i = 0; i <= max_targ; i++) { - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int our_id; - u_int target_id; - char channel; - - channel = 'A'; - our_id = ahc->our_id; - target_id = i; - if (i > 7 && (ahc->features & AHC_TWIN) != 0) { - channel = 'B'; - our_id = ahc->our_id_b; - target_id = i % 8; - } - tinfo = ahc_fetch_transinfo(ahc, channel, our_id, - target_id, &tstate); - /* Default to async narrow across the board */ - memset(tinfo, 0, sizeof(*tinfo)); - if (ahc->flags & AHC_USEDEFAULTS) { - if ((ahc->features & AHC_WIDE) != 0) - tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; - - /* - * These will be truncated when we determine the - * connection type we have with the target. - */ - tinfo->user.period = ahc_syncrates->period; - tinfo->user.offset = MAX_OFFSET; - } else { - u_int scsirate; - uint16_t mask; - - /* Take the settings leftover in scratch RAM. */ - scsirate = ahc_inb(ahc, TARG_SCSIRATE + i); - mask = (0x01 << i); - if ((ahc->features & AHC_ULTRA2) != 0) { - u_int offset; - u_int maxsync; - - if ((scsirate & SOFS) == 0x0F) { - /* - * Haven't negotiated yet, - * so the format is different. - */ - scsirate = (scsirate & SXFR) >> 4 - | (ultraenb & mask) - ? 0x08 : 0x0 - | (scsirate & WIDEXFER); - offset = MAX_OFFSET_ULTRA2; - } else - offset = ahc_inb(ahc, TARG_OFFSET + i); - if ((scsirate & ~WIDEXFER) == 0 && offset != 0) - /* Set to the lowest sync rate, 5MHz */ - scsirate |= 0x1c; - maxsync = AHC_SYNCRATE_ULTRA2; - if ((ahc->features & AHC_DT) != 0) - maxsync = AHC_SYNCRATE_DT; - tinfo->user.period = - ahc_find_period(ahc, scsirate, maxsync); - if (offset == 0) - tinfo->user.period = 0; - else - tinfo->user.offset = MAX_OFFSET; - if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/ - && (ahc->features & AHC_DT) != 0) - tinfo->user.ppr_options = - MSG_EXT_PPR_DT_REQ; - } else if ((scsirate & SOFS) != 0) { - if ((scsirate & SXFR) == 0x40 - && (ultraenb & mask) != 0) { - /* Treat 10MHz as a non-ultra speed */ - scsirate &= ~SXFR; - ultraenb &= ~mask; - } - tinfo->user.period = - ahc_find_period(ahc, scsirate, - (ultraenb & mask) - ? AHC_SYNCRATE_ULTRA - : AHC_SYNCRATE_FAST); - if (tinfo->user.period != 0) - tinfo->user.offset = MAX_OFFSET; - } - if (tinfo->user.period == 0) - tinfo->user.offset = 0; - if ((scsirate & WIDEXFER) != 0 - && (ahc->features & AHC_WIDE) != 0) - tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT; - tinfo->user.protocol_version = 4; - if ((ahc->features & AHC_DT) != 0) - tinfo->user.transport_version = 3; - else - tinfo->user.transport_version = 2; - tinfo->goal.protocol_version = 2; - tinfo->goal.transport_version = 2; - tinfo->curr.protocol_version = 2; - tinfo->curr.transport_version = 2; - } - tstate->ultraenb = 0; - } - ahc->user_discenable = discenable; - ahc->user_tagenable = tagenable; - - return (ahc->bus_chip_init(ahc)); -} - -void -ahc_intr_enable(struct ahc_softc *ahc, int enable) -{ - u_int hcntrl; - - hcntrl = ahc_inb(ahc, HCNTRL); - hcntrl &= ~INTEN; - ahc->pause &= ~INTEN; - ahc->unpause &= ~INTEN; - if (enable) { - hcntrl |= INTEN; - ahc->pause |= INTEN; - ahc->unpause |= INTEN; - } - ahc_outb(ahc, HCNTRL, hcntrl); -} - -/* - * Ensure that the card is paused in a location - * outside of all critical sections and that all - * pending work is completed prior to returning. - * This routine should only be called from outside - * an interrupt context. - */ -void -ahc_pause_and_flushwork(struct ahc_softc *ahc) -{ - int intstat; - int maxloops; - int paused; - - maxloops = 1000; - ahc->flags |= AHC_ALL_INTERRUPTS; - paused = FALSE; - do { - if (paused) { - ahc_unpause(ahc); - /* - * Give the sequencer some time to service - * any active selections. - */ - ahc_delay(500); - } - ahc_intr(ahc); - ahc_pause(ahc); - paused = TRUE; - ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO); - intstat = ahc_inb(ahc, INTSTAT); - if ((intstat & INT_PEND) == 0) { - ahc_clear_critical_section(ahc); - intstat = ahc_inb(ahc, INTSTAT); - } - } while (--maxloops - && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0) - && ((intstat & INT_PEND) != 0 - || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)) != 0)); - if (maxloops == 0) { - printk("Infinite interrupt loop, INTSTAT = %x", - ahc_inb(ahc, INTSTAT)); - } - ahc_platform_flushwork(ahc); - ahc->flags &= ~AHC_ALL_INTERRUPTS; -} - -#ifdef CONFIG_PM -int -ahc_suspend(struct ahc_softc *ahc) -{ - - ahc_pause_and_flushwork(ahc); - - if (LIST_FIRST(&ahc->pending_scbs) != NULL) { - ahc_unpause(ahc); - return (EBUSY); - } - -#ifdef AHC_TARGET_MODE - /* - * XXX What about ATIOs that have not yet been serviced? - * Perhaps we should just refuse to be suspended if we - * are acting in a target role. - */ - if (ahc->pending_device != NULL) { - ahc_unpause(ahc); - return (EBUSY); - } -#endif - ahc_shutdown(ahc); - return (0); -} - -int -ahc_resume(struct ahc_softc *ahc) -{ - - ahc_reset(ahc, /*reinit*/TRUE); - ahc_intr_enable(ahc, TRUE); - ahc_restart(ahc); - return (0); -} -#endif -/************************** Busy Target Table *********************************/ -/* - * Return the untagged transaction id for a given target/channel lun. - * Optionally, clear the entry. - */ -static u_int -ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl) -{ - u_int scbid; - u_int target_offset; - - if ((ahc->flags & AHC_SCB_BTT) != 0) { - u_int saved_scbptr; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); - scbid = ahc_inb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl)); - ahc_outb(ahc, SCBPTR, saved_scbptr); - } else { - target_offset = TCL_TARGET_OFFSET(tcl); - scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset); - } - - return (scbid); -} - -static void -ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl) -{ - u_int target_offset; - - if ((ahc->flags & AHC_SCB_BTT) != 0) { - u_int saved_scbptr; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); - ahc_outb(ahc, SCB_64_BTT+TCL_TARGET_OFFSET(tcl), SCB_LIST_NULL); - ahc_outb(ahc, SCBPTR, saved_scbptr); - } else { - target_offset = TCL_TARGET_OFFSET(tcl); - ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL); - } -} - -static void -ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid) -{ - u_int target_offset; - - if ((ahc->flags & AHC_SCB_BTT) != 0) { - u_int saved_scbptr; - - saved_scbptr = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, TCL_LUN(tcl)); - ahc_outb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl), scbid); - ahc_outb(ahc, SCBPTR, saved_scbptr); - } else { - target_offset = TCL_TARGET_OFFSET(tcl); - ahc_outb(ahc, BUSY_TARGETS + target_offset, scbid); - } -} - -/************************** SCB and SCB queue management **********************/ -int -ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target, - char channel, int lun, u_int tag, role_t role) -{ - int targ = SCB_GET_TARGET(ahc, scb); - char chan = SCB_GET_CHANNEL(ahc, scb); - int slun = SCB_GET_LUN(scb); - int match; - - match = ((chan == channel) || (channel == ALL_CHANNELS)); - if (match != 0) - match = ((targ == target) || (target == CAM_TARGET_WILDCARD)); - if (match != 0) - match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); - if (match != 0) { -#ifdef AHC_TARGET_MODE - int group; - - group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); - if (role == ROLE_INITIATOR) { - match = (group != XPT_FC_GROUP_TMODE) - && ((tag == scb->hscb->tag) - || (tag == SCB_LIST_NULL)); - } else if (role == ROLE_TARGET) { - match = (group == XPT_FC_GROUP_TMODE) - && ((tag == scb->io_ctx->csio.tag_id) - || (tag == SCB_LIST_NULL)); - } -#else /* !AHC_TARGET_MODE */ - match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); -#endif /* AHC_TARGET_MODE */ - } - - return match; -} - -static void -ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb) -{ - int target; - char channel; - int lun; - - target = SCB_GET_TARGET(ahc, scb); - lun = SCB_GET_LUN(scb); - channel = SCB_GET_CHANNEL(ahc, scb); - - ahc_search_qinfifo(ahc, target, channel, lun, - /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN, - CAM_REQUEUE_REQ, SEARCH_COMPLETE); - - ahc_platform_freeze_devq(ahc, scb); -} - -void -ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, struct scb *scb) -{ - struct scb *prev_scb; - - prev_scb = NULL; - if (ahc_qinfifo_count(ahc) != 0) { - u_int prev_tag; - uint8_t prev_pos; - - prev_pos = ahc->qinfifonext - 1; - prev_tag = ahc->qinfifo[prev_pos]; - prev_scb = ahc_lookup_scb(ahc, prev_tag); - } - ahc_qinfifo_requeue(ahc, prev_scb, scb); - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); - } else { - ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); - } -} - -static void -ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb, - struct scb *scb) -{ - if (prev_scb == NULL) { - ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag); - } else { - prev_scb->hscb->next = scb->hscb->tag; - ahc_sync_scb(ahc, prev_scb, - BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); - } - ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; - scb->hscb->next = ahc->next_queued_scb->hscb->tag; - ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE); -} - -static int -ahc_qinfifo_count(struct ahc_softc *ahc) -{ - uint8_t qinpos; - uint8_t diff; - - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - qinpos = ahc_inb(ahc, SNSCB_QOFF); - ahc_outb(ahc, SNSCB_QOFF, qinpos); - } else - qinpos = ahc_inb(ahc, QINPOS); - diff = ahc->qinfifonext - qinpos; - return (diff); -} - -int -ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status, - ahc_search_action action) -{ - struct scb *scb; - struct scb *prev_scb; - uint8_t qinstart; - uint8_t qinpos; - uint8_t qintail; - uint8_t next; - uint8_t prev; - uint8_t curscbptr; - int found; - int have_qregs; - - qintail = ahc->qinfifonext; - have_qregs = (ahc->features & AHC_QUEUE_REGS) != 0; - if (have_qregs) { - qinstart = ahc_inb(ahc, SNSCB_QOFF); - ahc_outb(ahc, SNSCB_QOFF, qinstart); - } else - qinstart = ahc_inb(ahc, QINPOS); - qinpos = qinstart; - found = 0; - prev_scb = NULL; - - if (action == SEARCH_COMPLETE) { - /* - * Don't attempt to run any queued untagged transactions - * until we are done with the abort process. - */ - ahc_freeze_untagged_queues(ahc); - } - - /* - * Start with an empty queue. Entries that are not chosen - * for removal will be re-added to the queue as we go. - */ - ahc->qinfifonext = qinpos; - ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag); - - while (qinpos != qintail) { - scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]); - if (scb == NULL) { - printk("qinpos = %d, SCB index = %d\n", - qinpos, ahc->qinfifo[qinpos]); - panic("Loop 1\n"); - } - - if (ahc_match_scb(ahc, scb, target, channel, lun, tag, role)) { - /* - * We found an scb that needs to be acted on. - */ - found++; - switch (action) { - case SEARCH_COMPLETE: - { - cam_status ostat; - cam_status cstat; - - ostat = ahc_get_transaction_status(scb); - if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, status); - cstat = ahc_get_transaction_status(scb); - if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); - if ((scb->flags & SCB_ACTIVE) == 0) - printk("Inactive SCB in qinfifo\n"); - ahc_done(ahc, scb); - - /* FALLTHROUGH */ - } - case SEARCH_REMOVE: - break; - case SEARCH_COUNT: - ahc_qinfifo_requeue(ahc, prev_scb, scb); - prev_scb = scb; - break; - } - } else { - ahc_qinfifo_requeue(ahc, prev_scb, scb); - prev_scb = scb; - } - qinpos++; - } - - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext); - } else { - ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext); - } - - if (action != SEARCH_COUNT - && (found != 0) - && (qinstart != ahc->qinfifonext)) { - /* - * The sequencer may be in the process of dmaing - * down the SCB at the beginning of the queue. - * This could be problematic if either the first, - * or the second SCB is removed from the queue - * (the first SCB includes a pointer to the "next" - * SCB to dma). If we have removed any entries, swap - * the first element in the queue with the next HSCB - * so the sequencer will notice that NEXT_QUEUED_SCB - * has changed during its dma attempt and will retry - * the DMA. - */ - scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]); - - if (scb == NULL) { - printk("found = %d, qinstart = %d, qinfifionext = %d\n", - found, qinstart, ahc->qinfifonext); - panic("First/Second Qinfifo fixup\n"); - } - /* - * ahc_swap_with_next_hscb forces our next pointer to - * point to the reserved SCB for future commands. Save - * and restore our original next pointer to maintain - * queue integrity. - */ - next = scb->hscb->next; - ahc->scb_data->scbindex[scb->hscb->tag] = NULL; - ahc_swap_with_next_hscb(ahc, scb); - scb->hscb->next = next; - ahc->qinfifo[qinstart] = scb->hscb->tag; - - /* Tell the card about the new head of the qinfifo. */ - ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag); - - /* Fixup the tail "next" pointer. */ - qintail = ahc->qinfifonext - 1; - scb = ahc_lookup_scb(ahc, ahc->qinfifo[qintail]); - scb->hscb->next = ahc->next_queued_scb->hscb->tag; - } - - /* - * Search waiting for selection list. - */ - curscbptr = ahc_inb(ahc, SCBPTR); - next = ahc_inb(ahc, WAITING_SCBH); /* Start at head of list. */ - prev = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - uint8_t scb_index; - - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - printk("Waiting List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - ahc_dump_card_state(ahc); - panic("for safety"); - } - scb = ahc_lookup_scb(ahc, scb_index); - if (scb == NULL) { - printk("scb_index = %d, next = %d\n", - scb_index, next); - panic("Waiting List traversal\n"); - } - if (ahc_match_scb(ahc, scb, target, channel, - lun, SCB_LIST_NULL, role)) { - /* - * We found an scb that needs to be acted on. - */ - found++; - switch (action) { - case SEARCH_COMPLETE: - { - cam_status ostat; - cam_status cstat; - - ostat = ahc_get_transaction_status(scb); - if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, - status); - cstat = ahc_get_transaction_status(scb); - if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); - if ((scb->flags & SCB_ACTIVE) == 0) - printk("Inactive SCB in Waiting List\n"); - ahc_done(ahc, scb); - /* FALLTHROUGH */ - } - case SEARCH_REMOVE: - next = ahc_rem_wscb(ahc, next, prev); - break; - case SEARCH_COUNT: - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - break; - } - } else { - - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } - ahc_outb(ahc, SCBPTR, curscbptr); - - found += ahc_search_untagged_queues(ahc, /*ahc_io_ctx_t*/NULL, target, - channel, lun, status, action); - - if (action == SEARCH_COMPLETE) - ahc_release_untagged_queues(ahc); - return (found); -} - -int -ahc_search_untagged_queues(struct ahc_softc *ahc, ahc_io_ctx_t ctx, - int target, char channel, int lun, uint32_t status, - ahc_search_action action) -{ - struct scb *scb; - int maxtarget; - int found; - int i; - - if (action == SEARCH_COMPLETE) { - /* - * Don't attempt to run any queued untagged transactions - * until we are done with the abort process. - */ - ahc_freeze_untagged_queues(ahc); - } - - found = 0; - i = 0; - if ((ahc->flags & AHC_SCB_BTT) == 0) { - - maxtarget = 16; - if (target != CAM_TARGET_WILDCARD) { - - i = target; - if (channel == 'B') - i += 8; - maxtarget = i + 1; - } - } else { - maxtarget = 0; - } - - for (; i < maxtarget; i++) { - struct scb_tailq *untagged_q; - struct scb *next_scb; - - untagged_q = &(ahc->untagged_queues[i]); - next_scb = TAILQ_FIRST(untagged_q); - while (next_scb != NULL) { - - scb = next_scb; - next_scb = TAILQ_NEXT(scb, links.tqe); - - /* - * The head of the list may be the currently - * active untagged command for a device. - * We're only searching for commands that - * have not been started. A transaction - * marked active but still in the qinfifo - * is removed by the qinfifo scanning code - * above. - */ - if ((scb->flags & SCB_ACTIVE) != 0) - continue; - - if (ahc_match_scb(ahc, scb, target, channel, lun, - SCB_LIST_NULL, ROLE_INITIATOR) == 0 - || (ctx != NULL && ctx != scb->io_ctx)) - continue; - - /* - * We found an scb that needs to be acted on. - */ - found++; - switch (action) { - case SEARCH_COMPLETE: - { - cam_status ostat; - cam_status cstat; - - ostat = ahc_get_transaction_status(scb); - if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scb, status); - cstat = ahc_get_transaction_status(scb); - if (cstat != CAM_REQ_CMP) - ahc_freeze_scb(scb); - if ((scb->flags & SCB_ACTIVE) == 0) - printk("Inactive SCB in untaggedQ\n"); - ahc_done(ahc, scb); - break; - } - case SEARCH_REMOVE: - scb->flags &= ~SCB_UNTAGGEDQ; - TAILQ_REMOVE(untagged_q, scb, links.tqe); - break; - case SEARCH_COUNT: - break; - } - } - } - - if (action == SEARCH_COMPLETE) - ahc_release_untagged_queues(ahc); - return (found); -} - -int -ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, int stop_on_first, int remove, - int save_state) -{ - struct scb *scbp; - u_int next; - u_int prev; - u_int count; - u_int active_scb; - - count = 0; - next = ahc_inb(ahc, DISCONNECTED_SCBH); - prev = SCB_LIST_NULL; - - if (save_state) { - /* restore this when we're done */ - active_scb = ahc_inb(ahc, SCBPTR); - } else - /* Silence compiler */ - active_scb = SCB_LIST_NULL; - - while (next != SCB_LIST_NULL) { - u_int scb_index; - - ahc_outb(ahc, SCBPTR, next); - scb_index = ahc_inb(ahc, SCB_TAG); - if (scb_index >= ahc->scb_data->numscbs) { - printk("Disconnected List inconsistency. " - "SCB index == %d, yet numscbs == %d.", - scb_index, ahc->scb_data->numscbs); - ahc_dump_card_state(ahc); - panic("for safety"); - } - - if (next == prev) { - panic("Disconnected List Loop. " - "cur SCBPTR == %x, prev SCBPTR == %x.", - next, prev); - } - scbp = ahc_lookup_scb(ahc, scb_index); - if (ahc_match_scb(ahc, scbp, target, channel, lun, - tag, ROLE_INITIATOR)) { - count++; - if (remove) { - next = - ahc_rem_scb_from_disc_list(ahc, prev, next); - } else { - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - if (stop_on_first) - break; - } else { - prev = next; - next = ahc_inb(ahc, SCB_NEXT); - } - } - if (save_state) - ahc_outb(ahc, SCBPTR, active_scb); - return (count); -} - -/* - * Remove an SCB from the on chip list of disconnected transactions. - * This is empty/unused if we are not performing SCB paging. - */ -static u_int -ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr) -{ - u_int next; - - ahc_outb(ahc, SCBPTR, scbptr); - next = ahc_inb(ahc, SCB_NEXT); - - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc_add_curscb_to_free_list(ahc); - - if (prev != SCB_LIST_NULL) { - ahc_outb(ahc, SCBPTR, prev); - ahc_outb(ahc, SCB_NEXT, next); - } else - ahc_outb(ahc, DISCONNECTED_SCBH, next); - - return (next); -} - -/* - * Add the SCB as selected by SCBPTR onto the on chip list of - * free hardware SCBs. This list is empty/unused if we are not - * performing SCB paging. - */ -static void -ahc_add_curscb_to_free_list(struct ahc_softc *ahc) -{ - /* - * Invalidate the tag so that our abort - * routines don't think it's active. - */ - ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL); - - if ((ahc->flags & AHC_PAGESCBS) != 0) { - ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH)); - ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR)); - } -} - -/* - * Manipulate the waiting for selection list and return the - * scb that follows the one that we remove. - */ -static u_int -ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev) -{ - u_int curscb, next; - - /* - * Select the SCB we want to abort and - * pull the next pointer out of it. - */ - curscb = ahc_inb(ahc, SCBPTR); - ahc_outb(ahc, SCBPTR, scbpos); - next = ahc_inb(ahc, SCB_NEXT); - - /* Clear the necessary fields */ - ahc_outb(ahc, SCB_CONTROL, 0); - - ahc_add_curscb_to_free_list(ahc); - - /* update the waiting list */ - if (prev == SCB_LIST_NULL) { - /* First in the list */ - ahc_outb(ahc, WAITING_SCBH, next); - - /* - * Ensure we aren't attempting to perform - * selection for this entry. - */ - ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO)); - } else { - /* - * Select the scb that pointed to us - * and update its next pointer. - */ - ahc_outb(ahc, SCBPTR, prev); - ahc_outb(ahc, SCB_NEXT, next); - } - - /* - * Point us back at the original scb position. - */ - ahc_outb(ahc, SCBPTR, curscb); - return next; -} - -/******************************** Error Handling ******************************/ -/* - * Abort all SCBs that match the given description (target/channel/lun/tag), - * setting their status to the passed in status if the status has not already - * been modified from CAM_REQ_INPROG. This routine assumes that the sequencer - * is paused before it is called. - */ -static int -ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status) -{ - struct scb *scbp; - struct scb *scbp_next; - u_int active_scb; - int i, j; - int maxtarget; - int minlun; - int maxlun; - - int found; - - /* - * Don't attempt to run any queued untagged transactions - * until we are done with the abort process. - */ - ahc_freeze_untagged_queues(ahc); - - /* restore this when we're done */ - active_scb = ahc_inb(ahc, SCBPTR); - - found = ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL, - role, CAM_REQUEUE_REQ, SEARCH_COMPLETE); - - /* - * Clean out the busy target table for any untagged commands. - */ - i = 0; - maxtarget = 16; - if (target != CAM_TARGET_WILDCARD) { - i = target; - if (channel == 'B') - i += 8; - maxtarget = i + 1; - } - - if (lun == CAM_LUN_WILDCARD) { - - /* - * Unless we are using an SCB based - * busy targets table, there is only - * one table entry for all luns of - * a target. - */ - minlun = 0; - maxlun = 1; - if ((ahc->flags & AHC_SCB_BTT) != 0) - maxlun = AHC_NUM_LUNS; - } else { - minlun = lun; - maxlun = lun + 1; - } - - if (role != ROLE_TARGET) { - for (;i < maxtarget; i++) { - for (j = minlun;j < maxlun; j++) { - u_int scbid; - u_int tcl; - - tcl = BUILD_TCL(i << 4, j); - scbid = ahc_index_busy_tcl(ahc, tcl); - scbp = ahc_lookup_scb(ahc, scbid); - if (scbp == NULL - || ahc_match_scb(ahc, scbp, target, channel, - lun, tag, role) == 0) - continue; - ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j)); - } - } - - /* - * Go through the disconnected list and remove any entries we - * have queued for completion, 0'ing their control byte too. - * We save the active SCB and restore it ourselves, so there - * is no reason for this search to restore it too. - */ - ahc_search_disc_list(ahc, target, channel, lun, tag, - /*stop_on_first*/FALSE, /*remove*/TRUE, - /*save_state*/FALSE); - } - - /* - * Go through the hardware SCB array looking for commands that - * were active but not on any list. In some cases, these remnants - * might not still have mappings in the scbindex array (e.g. unexpected - * bus free with the same scb queued for an abort). Don't hold this - * against them. - */ - for (i = 0; i < ahc->scb_data->maxhscbs; i++) { - u_int scbid; - - ahc_outb(ahc, SCBPTR, i); - scbid = ahc_inb(ahc, SCB_TAG); - scbp = ahc_lookup_scb(ahc, scbid); - if ((scbp == NULL && scbid != SCB_LIST_NULL) - || (scbp != NULL - && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role))) - ahc_add_curscb_to_free_list(ahc); - } - - /* - * Go through the pending CCB list and look for - * commands for this target that are still active. - * These are other tagged commands that were - * disconnected when the reset occurred. - */ - scbp_next = LIST_FIRST(&ahc->pending_scbs); - while (scbp_next != NULL) { - scbp = scbp_next; - scbp_next = LIST_NEXT(scbp, pending_links); - if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) { - cam_status ostat; - - ostat = ahc_get_transaction_status(scbp); - if (ostat == CAM_REQ_INPROG) - ahc_set_transaction_status(scbp, status); - if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP) - ahc_freeze_scb(scbp); - if ((scbp->flags & SCB_ACTIVE) == 0) - printk("Inactive SCB on pending list\n"); - ahc_done(ahc, scbp); - found++; - } - } - ahc_outb(ahc, SCBPTR, active_scb); - ahc_platform_abort_scbs(ahc, target, channel, lun, tag, role, status); - ahc_release_untagged_queues(ahc); - return found; -} - -static void -ahc_reset_current_bus(struct ahc_softc *ahc) -{ - uint8_t scsiseq; - - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST); - scsiseq = ahc_inb(ahc, SCSISEQ); - ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO); - ahc_flush_device_writes(ahc); - ahc_delay(AHC_BUSRESET_DELAY); - /* Turn off the bus reset */ - ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO); - - ahc_clear_intstat(ahc); - - /* Re-enable reset interrupts */ - ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST); -} - -int -ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset) -{ - struct ahc_devinfo devinfo; - u_int initiator, target, max_scsiid; - u_int sblkctl; - u_int scsiseq; - u_int simode1; - int found; - int restart_needed; - char cur_channel; - - ahc->pending_device = NULL; - - ahc_compile_devinfo(&devinfo, - CAM_TARGET_WILDCARD, - CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, - channel, ROLE_UNKNOWN); - ahc_pause(ahc); - - /* Make sure the sequencer is in a safe location. */ - ahc_clear_critical_section(ahc); - - /* - * Run our command complete fifos to ensure that we perform - * completion processing on any commands that 'completed' - * before the reset occurred. - */ - ahc_run_qoutfifo(ahc); -#ifdef AHC_TARGET_MODE - /* - * XXX - In Twin mode, the tqinfifo may have commands - * for an unaffected channel in it. However, if - * we have run out of ATIO resources to drain that - * queue, we may not get them all out here. Further, - * the blocked transactions for the reset channel - * should just be killed off, irrespecitve of whether - * we are blocked on ATIO resources. Write a routine - * to compact the tqinfifo appropriately. - */ - if ((ahc->flags & AHC_TARGETROLE) != 0) { - ahc_run_tqinfifo(ahc, /*paused*/TRUE); - } -#endif - - /* - * Reset the bus if we are initiating this reset - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - cur_channel = 'A'; - if ((ahc->features & AHC_TWIN) != 0 - && ((sblkctl & SELBUSB) != 0)) - cur_channel = 'B'; - scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); - if (cur_channel != channel) { - /* Case 1: Command for another bus is active - * Stealthily reset the other bus without - * upsetting the current bus. - */ - ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); - simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); -#ifdef AHC_TARGET_MODE - /* - * Bus resets clear ENSELI, so we cannot - * defer re-enabling bus reset interrupts - * if we are in target mode. - */ - if ((ahc->flags & AHC_TARGETROLE) != 0) - simode1 |= ENSCSIRST; -#endif - ahc_outb(ahc, SIMODE1, simode1); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_clear_intstat(ahc); - ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); - ahc_outb(ahc, SBLKCTL, sblkctl); - restart_needed = FALSE; - } else { - /* Case 2: A command from this bus is active or we're idle */ - simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); -#ifdef AHC_TARGET_MODE - /* - * Bus resets clear ENSELI, so we cannot - * defer re-enabling bus reset interrupts - * if we are in target mode. - */ - if ((ahc->flags & AHC_TARGETROLE) != 0) - simode1 |= ENSCSIRST; -#endif - ahc_outb(ahc, SIMODE1, simode1); - if (initiate_reset) - ahc_reset_current_bus(ahc); - ahc_clear_intstat(ahc); - ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP)); - restart_needed = TRUE; - } - - /* - * Clean up all the state information for the - * pending transactions on this bus. - */ - found = ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, channel, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_UNKNOWN, CAM_SCSI_BUS_RESET); - - max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7; - -#ifdef AHC_TARGET_MODE - /* - * Send an immediate notify ccb to all target more peripheral - * drivers affected by this action. - */ - for (target = 0; target <= max_scsiid; target++) { - struct ahc_tmode_tstate* tstate; - u_int lun; - - tstate = ahc->enabled_targets[target]; - if (tstate == NULL) - continue; - for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct ahc_tmode_lstate* lstate; - - lstate = tstate->enabled_luns[lun]; - if (lstate == NULL) - continue; - - ahc_queue_lstate_event(ahc, lstate, CAM_TARGET_WILDCARD, - EVENT_TYPE_BUS_RESET, /*arg*/0); - ahc_send_lstate_events(ahc, lstate); - } - } -#endif - /* Notify the XPT that a bus reset occurred */ - ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD, - CAM_LUN_WILDCARD, AC_BUS_RESET); - - /* - * Revert to async/narrow transfers until we renegotiate. - */ - for (target = 0; target <= max_scsiid; target++) { - - if (ahc->enabled_targets[target] == NULL) - continue; - for (initiator = 0; initiator <= max_scsiid; initiator++) { - struct ahc_devinfo devinfo; - - ahc_compile_devinfo(&devinfo, target, initiator, - CAM_LUN_WILDCARD, - channel, ROLE_UNKNOWN); - ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_CUR, /*paused*/TRUE); - ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL, - /*period*/0, /*offset*/0, - /*ppr_options*/0, AHC_TRANS_CUR, - /*paused*/TRUE); - } - } - - if (restart_needed) - ahc_restart(ahc); - else - ahc_unpause(ahc); - return found; -} - - -/***************************** Residual Processing ****************************/ -/* - * Calculate the residual for a just completed SCB. - */ -static void -ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb) -{ - struct hardware_scb *hscb; - struct status_pkt *spkt; - uint32_t sgptr; - uint32_t resid_sgptr; - uint32_t resid; - - /* - * 5 cases. - * 1) No residual. - * SG_RESID_VALID clear in sgptr. - * 2) Transferless command - * 3) Never performed any transfers. - * sgptr has SG_FULL_RESID set. - * 4) No residual but target did not - * save data pointers after the - * last transfer, so sgptr was - * never updated. - * 5) We have a partial residual. - * Use residual_sgptr to determine - * where we are. - */ - - hscb = scb->hscb; - sgptr = ahc_le32toh(hscb->sgptr); - if ((sgptr & SG_RESID_VALID) == 0) - /* Case 1 */ - return; - sgptr &= ~SG_RESID_VALID; - - if ((sgptr & SG_LIST_NULL) != 0) - /* Case 2 */ - return; - - spkt = &hscb->shared_data.status; - resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr); - if ((sgptr & SG_FULL_RESID) != 0) { - /* Case 3 */ - resid = ahc_get_transfer_length(scb); - } else if ((resid_sgptr & SG_LIST_NULL) != 0) { - /* Case 4 */ - return; - } else if ((resid_sgptr & ~SG_PTR_MASK) != 0) { - panic("Bogus resid sgptr value 0x%x\n", resid_sgptr); - } else { - struct ahc_dma_seg *sg; - - /* - * Remainder of the SG where the transfer - * stopped. - */ - resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK; - sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK); - - /* The residual sg_ptr always points to the next sg */ - sg--; - - /* - * Add up the contents of all residual - * SG segments that are after the SG where - * the transfer stopped. - */ - while ((ahc_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) { - sg++; - resid += ahc_le32toh(sg->len) & AHC_SG_LEN_MASK; - } - } - if ((scb->flags & SCB_SENSE) == 0) - ahc_set_residual(scb, resid); - else - ahc_set_sense_residual(scb, resid); - -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MISC) != 0) { - ahc_print_path(ahc, scb); - printk("Handled %sResidual of %d bytes\n", - (scb->flags & SCB_SENSE) ? "Sense " : "", resid); - } -#endif -} - -/******************************* Target Mode **********************************/ -#ifdef AHC_TARGET_MODE -/* - * Add a target mode event to this lun's queue - */ -static void -ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate, - u_int initiator_id, u_int event_type, u_int event_arg) -{ - struct ahc_tmode_event *event; - int pending; - - xpt_freeze_devq(lstate->path, /*count*/1); - if (lstate->event_w_idx >= lstate->event_r_idx) - pending = lstate->event_w_idx - lstate->event_r_idx; - else - pending = AHC_TMODE_EVENT_BUFFER_SIZE + 1 - - (lstate->event_r_idx - lstate->event_w_idx); - - if (event_type == EVENT_TYPE_BUS_RESET - || event_type == MSG_BUS_DEV_RESET) { - /* - * Any earlier events are irrelevant, so reset our buffer. - * This has the effect of allowing us to deal with reset - * floods (an external device holding down the reset line) - * without losing the event that is really interesting. - */ - lstate->event_r_idx = 0; - lstate->event_w_idx = 0; - xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE); - } - - if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) { - xpt_print_path(lstate->path); - printk("immediate event %x:%x lost\n", - lstate->event_buffer[lstate->event_r_idx].event_type, - lstate->event_buffer[lstate->event_r_idx].event_arg); - lstate->event_r_idx++; - if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) - lstate->event_r_idx = 0; - xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE); - } - - event = &lstate->event_buffer[lstate->event_w_idx]; - event->initiator_id = initiator_id; - event->event_type = event_type; - event->event_arg = event_arg; - lstate->event_w_idx++; - if (lstate->event_w_idx == AHC_TMODE_EVENT_BUFFER_SIZE) - lstate->event_w_idx = 0; -} - -/* - * Send any target mode events queued up waiting - * for immediate notify resources. - */ -void -ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate) -{ - struct ccb_hdr *ccbh; - struct ccb_immed_notify *inot; - - while (lstate->event_r_idx != lstate->event_w_idx - && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) { - struct ahc_tmode_event *event; - - event = &lstate->event_buffer[lstate->event_r_idx]; - SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle); - inot = (struct ccb_immed_notify *)ccbh; - switch (event->event_type) { - case EVENT_TYPE_BUS_RESET: - ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN; - break; - default: - ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN; - inot->message_args[0] = event->event_type; - inot->message_args[1] = event->event_arg; - break; - } - inot->initiator_id = event->initiator_id; - inot->sense_len = 0; - xpt_done((union ccb *)inot); - lstate->event_r_idx++; - if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE) - lstate->event_r_idx = 0; - } -} -#endif - -/******************** Sequencer Program Patching/Download *********************/ - -#ifdef AHC_DUMP_SEQ -void -ahc_dumpseq(struct ahc_softc* ahc) -{ - int i; - - ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - for (i = 0; i < ahc->instruction_ram_size; i++) { - uint8_t ins_bytes[4]; - - ahc_insb(ahc, SEQRAM, ins_bytes, 4); - printk("0x%08x\n", ins_bytes[0] << 24 - | ins_bytes[1] << 16 - | ins_bytes[2] << 8 - | ins_bytes[3]); - } -} -#endif - -static int -ahc_loadseq(struct ahc_softc *ahc) -{ - struct cs cs_table[num_critical_sections]; - u_int begin_set[num_critical_sections]; - u_int end_set[num_critical_sections]; - const struct patch *cur_patch; - u_int cs_count; - u_int cur_cs; - u_int i; - u_int skip_addr; - u_int sg_prefetch_cnt; - int downloaded; - uint8_t download_consts[7]; - - /* - * Start out with 0 critical sections - * that apply to this firmware load. - */ - cs_count = 0; - cur_cs = 0; - memset(begin_set, 0, sizeof(begin_set)); - memset(end_set, 0, sizeof(end_set)); - - /* Setup downloadable constant table */ - download_consts[QOUTFIFO_OFFSET] = 0; - if (ahc->targetcmds != NULL) - download_consts[QOUTFIFO_OFFSET] += 32; - download_consts[QINFIFO_OFFSET] = download_consts[QOUTFIFO_OFFSET] + 1; - download_consts[CACHESIZE_MASK] = ahc->pci_cachesize - 1; - download_consts[INVERTED_CACHESIZE_MASK] = ~(ahc->pci_cachesize - 1); - sg_prefetch_cnt = ahc->pci_cachesize; - if (sg_prefetch_cnt < (2 * sizeof(struct ahc_dma_seg))) - sg_prefetch_cnt = 2 * sizeof(struct ahc_dma_seg); - download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt; - download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_cnt - 1); - download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_cnt - 1); - - cur_patch = patches; - downloaded = 0; - skip_addr = 0; - ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM); - ahc_outb(ahc, SEQADDR0, 0); - ahc_outb(ahc, SEQADDR1, 0); - - for (i = 0; i < sizeof(seqprog)/4; i++) { - if (ahc_check_patch(ahc, &cur_patch, i, &skip_addr) == 0) { - /* - * Don't download this instruction as it - * is in a patch that was removed. - */ - continue; - } - - if (downloaded == ahc->instruction_ram_size) { - /* - * We're about to exceed the instruction - * storage capacity for this chip. Fail - * the load. - */ - printk("\n%s: Program too large for instruction memory " - "size of %d!\n", ahc_name(ahc), - ahc->instruction_ram_size); - return (ENOMEM); - } - - /* - * Move through the CS table until we find a CS - * that might apply to this instruction. - */ - for (; cur_cs < num_critical_sections; cur_cs++) { - if (critical_sections[cur_cs].end <= i) { - if (begin_set[cs_count] == TRUE - && end_set[cs_count] == FALSE) { - cs_table[cs_count].end = downloaded; - end_set[cs_count] = TRUE; - cs_count++; - } - continue; - } - if (critical_sections[cur_cs].begin <= i - && begin_set[cs_count] == FALSE) { - cs_table[cs_count].begin = downloaded; - begin_set[cs_count] = TRUE; - } - break; - } - ahc_download_instr(ahc, i, download_consts); - downloaded++; - } - - ahc->num_critical_sections = cs_count; - if (cs_count != 0) { - - cs_count *= sizeof(struct cs); - ahc->critical_sections = kmalloc(cs_count, GFP_ATOMIC); - if (ahc->critical_sections == NULL) - panic("ahc_loadseq: Could not malloc"); - memcpy(ahc->critical_sections, cs_table, cs_count); - } - ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); - - if (bootverbose) { - printk(" %d instructions downloaded\n", downloaded); - printk("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n", - ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags); - } - return (0); -} - -static int -ahc_check_patch(struct ahc_softc *ahc, const struct patch **start_patch, - u_int start_instr, u_int *skip_addr) -{ - const struct patch *cur_patch; - const struct patch *last_patch; - u_int num_patches; - - num_patches = ARRAY_SIZE(patches); - last_patch = &patches[num_patches]; - cur_patch = *start_patch; - - while (cur_patch < last_patch && start_instr == cur_patch->begin) { - - if (cur_patch->patch_func(ahc) == 0) { - - /* Start rejecting code */ - *skip_addr = start_instr + cur_patch->skip_instr; - cur_patch += cur_patch->skip_patch; - } else { - /* Accepted this patch. Advance to the next - * one and wait for our intruction pointer to - * hit this point. - */ - cur_patch++; - } - } - - *start_patch = cur_patch; - if (start_instr < *skip_addr) - /* Still skipping */ - return (0); - - return (1); -} - -static void -ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts) -{ - union ins_formats instr; - struct ins_format1 *fmt1_ins; - struct ins_format3 *fmt3_ins; - u_int opcode; - - /* - * The firmware is always compiled into a little endian format. - */ - instr.integer = ahc_le32toh(*(uint32_t*)&seqprog[instrptr * 4]); - - fmt1_ins = &instr.format1; - fmt3_ins = NULL; - - /* Pull the opcode */ - opcode = instr.format1.opcode; - switch (opcode) { - case AIC_OP_JMP: - case AIC_OP_JC: - case AIC_OP_JNC: - case AIC_OP_CALL: - case AIC_OP_JNE: - case AIC_OP_JNZ: - case AIC_OP_JE: - case AIC_OP_JZ: - { - const struct patch *cur_patch; - int address_offset; - u_int address; - u_int skip_addr; - u_int i; - - fmt3_ins = &instr.format3; - address_offset = 0; - address = fmt3_ins->address; - cur_patch = patches; - skip_addr = 0; - - for (i = 0; i < address;) { - - ahc_check_patch(ahc, &cur_patch, i, &skip_addr); - - if (skip_addr > i) { - int end_addr; - - end_addr = min(address, skip_addr); - address_offset += end_addr - i; - i = skip_addr; - } else { - i++; - } - } - address -= address_offset; - fmt3_ins->address = address; - /* FALLTHROUGH */ - } - case AIC_OP_OR: - case AIC_OP_AND: - case AIC_OP_XOR: - case AIC_OP_ADD: - case AIC_OP_ADC: - case AIC_OP_BMOV: - if (fmt1_ins->parity != 0) { - fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; - } - fmt1_ins->parity = 0; - if ((ahc->features & AHC_CMD_CHAN) == 0 - && opcode == AIC_OP_BMOV) { - /* - * Block move was added at the same time - * as the command channel. Verify that - * this is only a move of a single element - * and convert the BMOV to a MOV - * (AND with an immediate of FF). - */ - if (fmt1_ins->immediate != 1) - panic("%s: BMOV not supported\n", - ahc_name(ahc)); - fmt1_ins->opcode = AIC_OP_AND; - fmt1_ins->immediate = 0xff; - } - /* FALLTHROUGH */ - case AIC_OP_ROL: - if ((ahc->features & AHC_ULTRA2) != 0) { - int i, count; - - /* Calculate odd parity for the instruction */ - for (i = 0, count = 0; i < 31; i++) { - uint32_t mask; - - mask = 0x01 << i; - if ((instr.integer & mask) != 0) - count++; - } - if ((count & 0x01) == 0) - instr.format1.parity = 1; - } else { - /* Compress the instruction for older sequencers */ - if (fmt3_ins != NULL) { - instr.integer = - fmt3_ins->immediate - | (fmt3_ins->source << 8) - | (fmt3_ins->address << 16) - | (fmt3_ins->opcode << 25); - } else { - instr.integer = - fmt1_ins->immediate - | (fmt1_ins->source << 8) - | (fmt1_ins->destination << 16) - | (fmt1_ins->ret << 24) - | (fmt1_ins->opcode << 25); - } - } - /* The sequencer is a little endian cpu */ - instr.integer = ahc_htole32(instr.integer); - ahc_outsb(ahc, SEQRAM, instr.bytes, 4); - break; - default: - panic("Unknown opcode encountered in seq program"); - break; - } -} - -int -ahc_print_register(const ahc_reg_parse_entry_t *table, u_int num_entries, - const char *name, u_int address, u_int value, - u_int *cur_column, u_int wrap_point) -{ - int printed; - u_int printed_mask; - - if (cur_column != NULL && *cur_column >= wrap_point) { - printk("\n"); - *cur_column = 0; - } - printed = printk("%s[0x%x]", name, value); - if (table == NULL) { - printed += printk(" "); - *cur_column += printed; - return (printed); - } - printed_mask = 0; - while (printed_mask != 0xFF) { - int entry; - - for (entry = 0; entry < num_entries; entry++) { - if (((value & table[entry].mask) - != table[entry].value) - || ((printed_mask & table[entry].mask) - == table[entry].mask)) - continue; - - printed += printk("%s%s", - printed_mask == 0 ? ":(" : "|", - table[entry].name); - printed_mask |= table[entry].mask; - - break; - } - if (entry >= num_entries) - break; - } - if (printed_mask != 0) - printed += printk(") "); - else - printed += printk(" "); - if (cur_column != NULL) - *cur_column += printed; - return (printed); -} - -void -ahc_dump_card_state(struct ahc_softc *ahc) -{ - struct scb *scb; - struct scb_tailq *untagged_q; - u_int cur_col; - int paused; - int target; - int maxtarget; - int i; - uint8_t last_phase; - uint8_t qinpos; - uint8_t qintail; - uint8_t qoutpos; - uint8_t scb_index; - uint8_t saved_scbptr; - - if (ahc_is_paused(ahc)) { - paused = 1; - } else { - paused = 0; - ahc_pause(ahc); - } - - saved_scbptr = ahc_inb(ahc, SCBPTR); - last_phase = ahc_inb(ahc, LASTPHASE); - printk(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n" - "%s: Dumping Card State %s, at SEQADDR 0x%x\n", - ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg, - ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - if (paused) - printk("Card was paused\n"); - printk("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n", - ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX), - ahc_inb(ahc, ARG_2)); - printk("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT), - ahc_inb(ahc, SCBPTR)); - cur_col = 0; - if ((ahc->features & AHC_DT) != 0) - ahc_scsiphase_print(ahc_inb(ahc, SCSIPHASE), &cur_col, 50); - ahc_scsisigi_print(ahc_inb(ahc, SCSISIGI), &cur_col, 50); - ahc_error_print(ahc_inb(ahc, ERROR), &cur_col, 50); - ahc_scsibusl_print(ahc_inb(ahc, SCSIBUSL), &cur_col, 50); - ahc_lastphase_print(ahc_inb(ahc, LASTPHASE), &cur_col, 50); - ahc_scsiseq_print(ahc_inb(ahc, SCSISEQ), &cur_col, 50); - ahc_sblkctl_print(ahc_inb(ahc, SBLKCTL), &cur_col, 50); - ahc_scsirate_print(ahc_inb(ahc, SCSIRATE), &cur_col, 50); - ahc_seqctl_print(ahc_inb(ahc, SEQCTL), &cur_col, 50); - ahc_seq_flags_print(ahc_inb(ahc, SEQ_FLAGS), &cur_col, 50); - ahc_sstat0_print(ahc_inb(ahc, SSTAT0), &cur_col, 50); - ahc_sstat1_print(ahc_inb(ahc, SSTAT1), &cur_col, 50); - ahc_sstat2_print(ahc_inb(ahc, SSTAT2), &cur_col, 50); - ahc_sstat3_print(ahc_inb(ahc, SSTAT3), &cur_col, 50); - ahc_simode0_print(ahc_inb(ahc, SIMODE0), &cur_col, 50); - ahc_simode1_print(ahc_inb(ahc, SIMODE1), &cur_col, 50); - ahc_sxfrctl0_print(ahc_inb(ahc, SXFRCTL0), &cur_col, 50); - ahc_dfcntrl_print(ahc_inb(ahc, DFCNTRL), &cur_col, 50); - ahc_dfstatus_print(ahc_inb(ahc, DFSTATUS), &cur_col, 50); - if (cur_col != 0) - printk("\n"); - printk("STACK:"); - for (i = 0; i < STACK_SIZE; i++) - printk(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8)); - printk("\nSCB count = %d\n", ahc->scb_data->numscbs); - printk("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag); - printk("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB)); - /* QINFIFO */ - printk("QINFIFO entries: "); - if ((ahc->features & AHC_QUEUE_REGS) != 0) { - qinpos = ahc_inb(ahc, SNSCB_QOFF); - ahc_outb(ahc, SNSCB_QOFF, qinpos); - } else - qinpos = ahc_inb(ahc, QINPOS); - qintail = ahc->qinfifonext; - while (qinpos != qintail) { - printk("%d ", ahc->qinfifo[qinpos]); - qinpos++; - } - printk("\n"); - - printk("Waiting Queue entries: "); - scb_index = ahc_inb(ahc, WAITING_SCBH); - i = 0; - while (scb_index != SCB_LIST_NULL && i++ < 256) { - ahc_outb(ahc, SCBPTR, scb_index); - printk("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); - scb_index = ahc_inb(ahc, SCB_NEXT); - } - printk("\n"); - - printk("Disconnected Queue entries: "); - scb_index = ahc_inb(ahc, DISCONNECTED_SCBH); - i = 0; - while (scb_index != SCB_LIST_NULL && i++ < 256) { - ahc_outb(ahc, SCBPTR, scb_index); - printk("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG)); - scb_index = ahc_inb(ahc, SCB_NEXT); - } - printk("\n"); - - ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD); - printk("QOUTFIFO entries: "); - qoutpos = ahc->qoutfifonext; - i = 0; - while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) { - printk("%d ", ahc->qoutfifo[qoutpos]); - qoutpos++; - } - printk("\n"); - - printk("Sequencer Free SCB List: "); - scb_index = ahc_inb(ahc, FREE_SCBH); - i = 0; - while (scb_index != SCB_LIST_NULL && i++ < 256) { - ahc_outb(ahc, SCBPTR, scb_index); - printk("%d ", scb_index); - scb_index = ahc_inb(ahc, SCB_NEXT); - } - printk("\n"); - - printk("Sequencer SCB Info: "); - for (i = 0; i < ahc->scb_data->maxhscbs; i++) { - ahc_outb(ahc, SCBPTR, i); - cur_col = printk("\n%3d ", i); - - ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), &cur_col, 60); - ahc_scb_scsiid_print(ahc_inb(ahc, SCB_SCSIID), &cur_col, 60); - ahc_scb_lun_print(ahc_inb(ahc, SCB_LUN), &cur_col, 60); - ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60); - } - printk("\n"); - - printk("Pending list: "); - i = 0; - LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { - if (i++ > 256) - break; - cur_col = printk("\n%3d ", scb->hscb->tag); - ahc_scb_control_print(scb->hscb->control, &cur_col, 60); - ahc_scb_scsiid_print(scb->hscb->scsiid, &cur_col, 60); - ahc_scb_lun_print(scb->hscb->lun, &cur_col, 60); - if ((ahc->flags & AHC_PAGESCBS) == 0) { - ahc_outb(ahc, SCBPTR, scb->hscb->tag); - printk("("); - ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), - &cur_col, 60); - ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60); - printk(")"); - } - } - printk("\n"); - - printk("Kernel Free SCB list: "); - i = 0; - SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) { - if (i++ > 256) - break; - printk("%d ", scb->hscb->tag); - } - printk("\n"); - - maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7; - for (target = 0; target <= maxtarget; target++) { - untagged_q = &ahc->untagged_queues[target]; - if (TAILQ_FIRST(untagged_q) == NULL) - continue; - printk("Untagged Q(%d): ", target); - i = 0; - TAILQ_FOREACH(scb, untagged_q, links.tqe) { - if (i++ > 256) - break; - printk("%d ", scb->hscb->tag); - } - printk("\n"); - } - - ahc_platform_dump_card_state(ahc); - printk("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); - ahc_outb(ahc, SCBPTR, saved_scbptr); - if (paused == 0) - ahc_unpause(ahc); -} - -/************************* Target Mode ****************************************/ -#ifdef AHC_TARGET_MODE -cam_status -ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb, - struct ahc_tmode_tstate **tstate, - struct ahc_tmode_lstate **lstate, - int notfound_failure) -{ - - if ((ahc->features & AHC_TARGETMODE) == 0) - return (CAM_REQ_INVALID); - - /* - * Handle the 'black hole' device that sucks up - * requests to unattached luns on enabled targets. - */ - if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD - && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) { - *tstate = NULL; - *lstate = ahc->black_hole; - } else { - u_int max_id; - - max_id = (ahc->features & AHC_WIDE) ? 16 : 8; - if (ccb->ccb_h.target_id >= max_id) - return (CAM_TID_INVALID); - - if (ccb->ccb_h.target_lun >= AHC_NUM_LUNS) - return (CAM_LUN_INVALID); - - *tstate = ahc->enabled_targets[ccb->ccb_h.target_id]; - *lstate = NULL; - if (*tstate != NULL) - *lstate = - (*tstate)->enabled_luns[ccb->ccb_h.target_lun]; - } - - if (notfound_failure != 0 && *lstate == NULL) - return (CAM_PATH_INVALID); - - return (CAM_REQ_CMP); -} - -void -ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb) -{ - struct ahc_tmode_tstate *tstate; - struct ahc_tmode_lstate *lstate; - struct ccb_en_lun *cel; - cam_status status; - u_long s; - u_int target; - u_int lun; - u_int target_mask; - u_int our_id; - int error; - char channel; - - status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate, - /*notfound_failure*/FALSE); - - if (status != CAM_REQ_CMP) { - ccb->ccb_h.status = status; - return; - } - - if (cam_sim_bus(sim) == 0) - our_id = ahc->our_id; - else - our_id = ahc->our_id_b; - - if (ccb->ccb_h.target_id != our_id) { - /* - * our_id represents our initiator ID, or - * the ID of the first target to have an - * enabled lun in target mode. There are - * two cases that may preclude enabling a - * target id other than our_id. - * - * o our_id is for an active initiator role. - * Since the hardware does not support - * reselections to the initiator role at - * anything other than our_id, and our_id - * is used by the hardware to indicate the - * ID to use for both select-out and - * reselect-out operations, the only target - * ID we can support in this mode is our_id. - * - * o The MULTARGID feature is not available and - * a previous target mode ID has been enabled. - */ - if ((ahc->features & AHC_MULTIROLE) != 0) { - - if ((ahc->features & AHC_MULTI_TID) != 0 - && (ahc->flags & AHC_INITIATORROLE) != 0) { - /* - * Only allow additional targets if - * the initiator role is disabled. - * The hardware cannot handle a re-select-in - * on the initiator id during a re-select-out - * on a different target id. - */ - status = CAM_TID_INVALID; - } else if ((ahc->flags & AHC_INITIATORROLE) != 0 - || ahc->enabled_luns > 0) { - /* - * Only allow our target id to change - * if the initiator role is not configured - * and there are no enabled luns which - * are attached to the currently registered - * scsi id. - */ - status = CAM_TID_INVALID; - } - } else if ((ahc->features & AHC_MULTI_TID) == 0 - && ahc->enabled_luns > 0) { - - status = CAM_TID_INVALID; - } - } - - if (status != CAM_REQ_CMP) { - ccb->ccb_h.status = status; - return; - } - - /* - * We now have an id that is valid. - * If we aren't in target mode, switch modes. - */ - if ((ahc->flags & AHC_TARGETROLE) == 0 - && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) { - u_long s; - ahc_flag saved_flags; - - printk("Configuring Target Mode\n"); - ahc_lock(ahc, &s); - if (LIST_FIRST(&ahc->pending_scbs) != NULL) { - ccb->ccb_h.status = CAM_BUSY; - ahc_unlock(ahc, &s); - return; - } - saved_flags = ahc->flags; - ahc->flags |= AHC_TARGETROLE; - if ((ahc->features & AHC_MULTIROLE) == 0) - ahc->flags &= ~AHC_INITIATORROLE; - ahc_pause(ahc); - error = ahc_loadseq(ahc); - if (error != 0) { - /* - * Restore original configuration and notify - * the caller that we cannot support target mode. - * Since the adapter started out in this - * configuration, the firmware load will succeed, - * so there is no point in checking ahc_loadseq's - * return value. - */ - ahc->flags = saved_flags; - (void)ahc_loadseq(ahc); - ahc_restart(ahc); - ahc_unlock(ahc, &s); - ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; - return; - } - ahc_restart(ahc); - ahc_unlock(ahc, &s); - } - cel = &ccb->cel; - target = ccb->ccb_h.target_id; - lun = ccb->ccb_h.target_lun; - channel = SIM_CHANNEL(ahc, sim); - target_mask = 0x01 << target; - if (channel == 'B') - target_mask <<= 8; - - if (cel->enable != 0) { - u_int scsiseq; - - /* Are we already enabled?? */ - if (lstate != NULL) { - xpt_print_path(ccb->ccb_h.path); - printk("Lun already enabled\n"); - ccb->ccb_h.status = CAM_LUN_ALRDY_ENA; - return; - } - - if (cel->grp6_len != 0 - || cel->grp7_len != 0) { - /* - * Don't (yet?) support vendor - * specific commands. - */ - ccb->ccb_h.status = CAM_REQ_INVALID; - printk("Non-zero Group Codes\n"); - return; - } - - /* - * Seems to be okay. - * Setup our data structures. - */ - if (target != CAM_TARGET_WILDCARD && tstate == NULL) { - tstate = ahc_alloc_tstate(ahc, target, channel); - if (tstate == NULL) { - xpt_print_path(ccb->ccb_h.path); - printk("Couldn't allocate tstate\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - } - lstate = kmalloc(sizeof(*lstate), GFP_ATOMIC); - if (lstate == NULL) { - xpt_print_path(ccb->ccb_h.path); - printk("Couldn't allocate lstate\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - memset(lstate, 0, sizeof(*lstate)); - status = xpt_create_path(&lstate->path, /*periph*/NULL, - xpt_path_path_id(ccb->ccb_h.path), - xpt_path_target_id(ccb->ccb_h.path), - xpt_path_lun_id(ccb->ccb_h.path)); - if (status != CAM_REQ_CMP) { - kfree(lstate); - xpt_print_path(ccb->ccb_h.path); - printk("Couldn't allocate path\n"); - ccb->ccb_h.status = CAM_RESRC_UNAVAIL; - return; - } - SLIST_INIT(&lstate->accept_tios); - SLIST_INIT(&lstate->immed_notifies); - ahc_lock(ahc, &s); - ahc_pause(ahc); - if (target != CAM_TARGET_WILDCARD) { - tstate->enabled_luns[lun] = lstate; - ahc->enabled_luns++; - - if ((ahc->features & AHC_MULTI_TID) != 0) { - u_int targid_mask; - - targid_mask = ahc_inb(ahc, TARGID) - | (ahc_inb(ahc, TARGID + 1) << 8); - - targid_mask |= target_mask; - ahc_outb(ahc, TARGID, targid_mask); - ahc_outb(ahc, TARGID+1, (targid_mask >> 8)); - - ahc_update_scsiid(ahc, targid_mask); - } else { - u_int our_id; - char channel; - - channel = SIM_CHANNEL(ahc, sim); - our_id = SIM_SCSI_ID(ahc, sim); - - /* - * This can only happen if selections - * are not enabled - */ - if (target != our_id) { - u_int sblkctl; - char cur_channel; - int swap; - - sblkctl = ahc_inb(ahc, SBLKCTL); - cur_channel = (sblkctl & SELBUSB) - ? 'B' : 'A'; - if ((ahc->features & AHC_TWIN) == 0) - cur_channel = 'A'; - swap = cur_channel != channel; - if (channel == 'A') - ahc->our_id = target; - else - ahc->our_id_b = target; - - if (swap) - ahc_outb(ahc, SBLKCTL, - sblkctl ^ SELBUSB); - - ahc_outb(ahc, SCSIID, target); - - if (swap) - ahc_outb(ahc, SBLKCTL, sblkctl); - } - } - } else - ahc->black_hole = lstate; - /* Allow select-in operations */ - if (ahc->black_hole != NULL && ahc->enabled_luns > 0) { - scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); - scsiseq |= ENSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); - scsiseq = ahc_inb(ahc, SCSISEQ); - scsiseq |= ENSELI; - ahc_outb(ahc, SCSISEQ, scsiseq); - } - ahc_unpause(ahc); - ahc_unlock(ahc, &s); - ccb->ccb_h.status = CAM_REQ_CMP; - xpt_print_path(ccb->ccb_h.path); - printk("Lun now enabled for target mode\n"); - } else { - struct scb *scb; - int i, empty; - - if (lstate == NULL) { - ccb->ccb_h.status = CAM_LUN_INVALID; - return; - } - - ahc_lock(ahc, &s); - - ccb->ccb_h.status = CAM_REQ_CMP; - LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) { - struct ccb_hdr *ccbh; - - ccbh = &scb->io_ctx->ccb_h; - if (ccbh->func_code == XPT_CONT_TARGET_IO - && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){ - printk("CTIO pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - ahc_unlock(ahc, &s); - return; - } - } - - if (SLIST_FIRST(&lstate->accept_tios) != NULL) { - printk("ATIOs pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - } - - if (SLIST_FIRST(&lstate->immed_notifies) != NULL) { - printk("INOTs pending\n"); - ccb->ccb_h.status = CAM_REQ_INVALID; - } - - if (ccb->ccb_h.status != CAM_REQ_CMP) { - ahc_unlock(ahc, &s); - return; - } - - xpt_print_path(ccb->ccb_h.path); - printk("Target mode disabled\n"); - xpt_free_path(lstate->path); - kfree(lstate); - - ahc_pause(ahc); - /* Can we clean up the target too? */ - if (target != CAM_TARGET_WILDCARD) { - tstate->enabled_luns[lun] = NULL; - ahc->enabled_luns--; - for (empty = 1, i = 0; i < 8; i++) - if (tstate->enabled_luns[i] != NULL) { - empty = 0; - break; - } - - if (empty) { - ahc_free_tstate(ahc, target, channel, - /*force*/FALSE); - if (ahc->features & AHC_MULTI_TID) { - u_int targid_mask; - - targid_mask = ahc_inb(ahc, TARGID) - | (ahc_inb(ahc, TARGID + 1) - << 8); - - targid_mask &= ~target_mask; - ahc_outb(ahc, TARGID, targid_mask); - ahc_outb(ahc, TARGID+1, - (targid_mask >> 8)); - ahc_update_scsiid(ahc, targid_mask); - } - } - } else { - - ahc->black_hole = NULL; - - /* - * We can't allow selections without - * our black hole device. - */ - empty = TRUE; - } - if (ahc->enabled_luns == 0) { - /* Disallow select-in */ - u_int scsiseq; - - scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE); - scsiseq &= ~ENSELI; - ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq); - scsiseq = ahc_inb(ahc, SCSISEQ); - scsiseq &= ~ENSELI; - ahc_outb(ahc, SCSISEQ, scsiseq); - - if ((ahc->features & AHC_MULTIROLE) == 0) { - printk("Configuring Initiator Mode\n"); - ahc->flags &= ~AHC_TARGETROLE; - ahc->flags |= AHC_INITIATORROLE; - /* - * Returning to a configuration that - * fit previously will always succeed. - */ - (void)ahc_loadseq(ahc); - ahc_restart(ahc); - /* - * Unpaused. The extra unpause - * that follows is harmless. - */ - } - } - ahc_unpause(ahc); - ahc_unlock(ahc, &s); - } -} - -static void -ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask) -{ - u_int scsiid_mask; - u_int scsiid; - - if ((ahc->features & AHC_MULTI_TID) == 0) - panic("ahc_update_scsiid called on non-multitid unit\n"); - - /* - * Since we will rely on the TARGID mask - * for selection enables, ensure that OID - * in SCSIID is not set to some other ID - * that we don't want to allow selections on. - */ - if ((ahc->features & AHC_ULTRA2) != 0) - scsiid = ahc_inb(ahc, SCSIID_ULTRA2); - else - scsiid = ahc_inb(ahc, SCSIID); - scsiid_mask = 0x1 << (scsiid & OID); - if ((targid_mask & scsiid_mask) == 0) { - u_int our_id; - - /* ffs counts from 1 */ - our_id = ffs(targid_mask); - if (our_id == 0) - our_id = ahc->our_id; - else - our_id--; - scsiid &= TID; - scsiid |= our_id; - } - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, SCSIID_ULTRA2, scsiid); - else - ahc_outb(ahc, SCSIID, scsiid); -} - -static void -ahc_run_tqinfifo(struct ahc_softc *ahc, int paused) -{ - struct target_cmd *cmd; - - /* - * If the card supports auto-access pause, - * we can access the card directly regardless - * of whether it is paused or not. - */ - if ((ahc->features & AHC_AUTOPAUSE) != 0) - paused = TRUE; - - ahc_sync_tqinfifo(ahc, BUS_DMASYNC_POSTREAD); - while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) { - - /* - * Only advance through the queue if we - * have the resources to process the command. - */ - if (ahc_handle_target_cmd(ahc, cmd) != 0) - break; - - cmd->cmd_valid = 0; - ahc_dmamap_sync(ahc, ahc->shared_data_dmat, - ahc->shared_data_dmamap, - ahc_targetcmd_offset(ahc, ahc->tqinfifonext), - sizeof(struct target_cmd), - BUS_DMASYNC_PREREAD); - ahc->tqinfifonext++; - - /* - * Lazily update our position in the target mode incoming - * command queue as seen by the sequencer. - */ - if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) { - if ((ahc->features & AHC_HS_MAILBOX) != 0) { - u_int hs_mailbox; - - hs_mailbox = ahc_inb(ahc, HS_MAILBOX); - hs_mailbox &= ~HOST_TQINPOS; - hs_mailbox |= ahc->tqinfifonext & HOST_TQINPOS; - ahc_outb(ahc, HS_MAILBOX, hs_mailbox); - } else { - if (!paused) - ahc_pause(ahc); - ahc_outb(ahc, KERNEL_TQINPOS, - ahc->tqinfifonext & HOST_TQINPOS); - if (!paused) - ahc_unpause(ahc); - } - } - } -} - -static int -ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd) -{ - struct ahc_tmode_tstate *tstate; - struct ahc_tmode_lstate *lstate; - struct ccb_accept_tio *atio; - uint8_t *byte; - int initiator; - int target; - int lun; - - initiator = SCSIID_TARGET(ahc, cmd->scsiid); - target = SCSIID_OUR_ID(cmd->scsiid); - lun = (cmd->identify & MSG_IDENTIFY_LUNMASK); - - byte = cmd->bytes; - tstate = ahc->enabled_targets[target]; - lstate = NULL; - if (tstate != NULL) - lstate = tstate->enabled_luns[lun]; - - /* - * Commands for disabled luns go to the black hole driver. - */ - if (lstate == NULL) - lstate = ahc->black_hole; - - atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios); - if (atio == NULL) { - ahc->flags |= AHC_TQINFIFO_BLOCKED; - /* - * Wait for more ATIOs from the peripheral driver for this lun. - */ - if (bootverbose) - printk("%s: ATIOs exhausted\n", ahc_name(ahc)); - return (1); - } else - ahc->flags &= ~AHC_TQINFIFO_BLOCKED; -#if 0 - printk("Incoming command from %d for %d:%d%s\n", - initiator, target, lun, - lstate == ahc->black_hole ? "(Black Holed)" : ""); -#endif - SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle); - - if (lstate == ahc->black_hole) { - /* Fill in the wildcards */ - atio->ccb_h.target_id = target; - atio->ccb_h.target_lun = lun; - } - - /* - * Package it up and send it off to - * whomever has this lun enabled. - */ - atio->sense_len = 0; - atio->init_id = initiator; - if (byte[0] != 0xFF) { - /* Tag was included */ - atio->tag_action = *byte++; - atio->tag_id = *byte++; - atio->ccb_h.flags = CAM_TAG_ACTION_VALID; - } else { - atio->ccb_h.flags = 0; - } - byte++; - - /* Okay. Now determine the cdb size based on the command code */ - switch (*byte >> CMD_GROUP_CODE_SHIFT) { - case 0: - atio->cdb_len = 6; - break; - case 1: - case 2: - atio->cdb_len = 10; - break; - case 4: - atio->cdb_len = 16; - break; - case 5: - atio->cdb_len = 12; - break; - case 3: - default: - /* Only copy the opcode. */ - atio->cdb_len = 1; - printk("Reserved or VU command code type encountered\n"); - break; - } - - memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len); - - atio->ccb_h.status |= CAM_CDB_RECVD; - - if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) { - /* - * We weren't allowed to disconnect. - * We're hanging on the bus until a - * continue target I/O comes in response - * to this accept tio. - */ -#if 0 - printk("Received Immediate Command %d:%d:%d - %p\n", - initiator, target, lun, ahc->pending_device); -#endif - ahc->pending_device = lstate; - ahc_freeze_ccb((union ccb *)atio); - atio->ccb_h.flags |= CAM_DIS_DISCONNECT; - } - xpt_done((union ccb*)atio); - return (0); -} - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_inline.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_inline.h deleted file mode 100644 index 0b57b783..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_inline.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Inline routines shareable across OS platforms. - * - * Copyright (c) 1994-2001 Justin T. Gibbs. - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#43 $ - * - * $FreeBSD$ - */ - -#ifndef _AIC7XXX_INLINE_H_ -#define _AIC7XXX_INLINE_H_ - -/************************* Sequencer Execution Control ************************/ -int ahc_is_paused(struct ahc_softc *ahc); -void ahc_pause(struct ahc_softc *ahc); -void ahc_unpause(struct ahc_softc *ahc); - -/************************** Memory mapping routines ***************************/ -void ahc_sync_sglist(struct ahc_softc *ahc, - struct scb *scb, int op); - -/******************************** Debugging ***********************************/ -static inline char *ahc_name(struct ahc_softc *ahc); - -static inline char *ahc_name(struct ahc_softc *ahc) -{ - return (ahc->name); -} - -/*********************** Miscellaneous Support Functions ***********************/ - -struct ahc_initiator_tinfo * - ahc_fetch_transinfo(struct ahc_softc *ahc, - char channel, u_int our_id, - u_int remote_id, - struct ahc_tmode_tstate **tstate); -uint16_t - ahc_inw(struct ahc_softc *ahc, u_int port); -void ahc_outw(struct ahc_softc *ahc, u_int port, - u_int value); -uint32_t - ahc_inl(struct ahc_softc *ahc, u_int port); -void ahc_outl(struct ahc_softc *ahc, u_int port, - uint32_t value); -uint64_t - ahc_inq(struct ahc_softc *ahc, u_int port); -void ahc_outq(struct ahc_softc *ahc, u_int port, - uint64_t value); -struct scb* - ahc_get_scb(struct ahc_softc *ahc); -void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb); -struct scb * - ahc_lookup_scb(struct ahc_softc *ahc, u_int tag); -void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb); -struct scsi_sense_data * - ahc_get_sense_buf(struct ahc_softc *ahc, - struct scb *scb); - -/************************** Interrupt Processing ******************************/ -int ahc_intr(struct ahc_softc *ahc); - -#endif /* _AIC7XXX_INLINE_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.c deleted file mode 100644 index 5a477cdc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ /dev/null @@ -1,2624 +0,0 @@ -/* - * Adaptec AIC7xxx device driver for Linux. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#235 $ - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F - * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA - * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide, - * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux, - * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file - * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual, - * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the - * ANSI SCSI-2 specification (draft 10c), ... - * - * -------------------------------------------------------------------------- - * - * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org): - * - * Substantially modified to include support for wide and twin bus - * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, - * SCB paging, and other rework of the code. - * - * -------------------------------------------------------------------------- - * Copyright (c) 1994-2000 Justin T. Gibbs. - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - *--------------------------------------------------------------------------- - * - * Thanks also go to (in alphabetical order) the following: - * - * Rory Bolt - Sequencer bug fixes - * Jay Estabrook - Initial DEC Alpha support - * Doug Ledford - Much needed abort/reset bug fixes - * Kai Makisara - DMAing of SCBs - * - * A Boot time option was also added for not resetting the scsi bus. - * - * Form: aic7xxx=extended - * aic7xxx=no_reset - * aic7xxx=verbose - * - * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97 - * - * Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp - */ - -/* - * Further driver modifications made by Doug Ledford - * - * Copyright (c) 1997-1999 Doug Ledford - * - * These changes are released under the same licensing terms as the FreeBSD - * driver written by Justin Gibbs. Please see his Copyright notice above - * for the exact terms and conditions covering my changes as well as the - * warranty statement. - * - * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include - * but are not limited to: - * - * 1: Import of the latest FreeBSD sequencer code for this driver - * 2: Modification of kernel code to accommodate different sequencer semantics - * 3: Extensive changes throughout kernel portion of driver to improve - * abort/reset processing and error hanndling - * 4: Other work contributed by various people on the Internet - * 5: Changes to printk information and verbosity selection code - * 6: General reliability related changes, especially in IRQ management - * 7: Modifications to the default probe/attach order for supported cards - * 8: SMP friendliness has been improved - * - */ - -#include "aic7xxx_osm.h" -#include "aic7xxx_inline.h" -#include - -static struct scsi_transport_template *ahc_linux_transport_template = NULL; - -#include /* __setup */ -#include /* For fetching system memory size */ -#include /* For block_size() */ -#include /* For ssleep/msleep */ -#include - - -/* - * Set this to the delay in seconds after SCSI bus reset. - * Note, we honor this only for the initial bus reset. - * The scsi error recovery code performs its own bus settle - * delay handling for error recovery actions. - */ -#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS -#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS -#else -#define AIC7XXX_RESET_DELAY 5000 -#endif - -/* - * Control collection of SCSI transfer statistics for the /proc filesystem. - * - * NOTE: Do NOT enable this when running on kernels version 1.2.x and below. - * NOTE: This does affect performance since it has to maintain statistics. - */ -#ifdef CONFIG_AIC7XXX_PROC_STATS -#define AIC7XXX_PROC_STATS -#endif - -/* - * To change the default number of tagged transactions allowed per-device, - * add a line to the lilo.conf file like: - * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}" - * which will result in the first four devices on the first two - * controllers being set to a tagged queue depth of 32. - * - * The tag_commands is an array of 16 to allow for wide and twin adapters. - * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15 - * for channel 1. - */ -typedef struct { - uint8_t tag_commands[16]; /* Allow for wide/twin adapters. */ -} adapter_tag_info_t; - -/* - * Modify this as you see fit for your system. - * - * 0 tagged queuing disabled - * 1 <= n <= 253 n == max tags ever dispatched. - * - * The driver will throttle the number of commands dispatched to a - * device if it returns queue full. For devices with a fixed maximum - * queue depth, the driver will eventually determine this depth and - * lock it in (a console message is printed to indicate that a lock - * has occurred). On some devices, queue full is returned for a temporary - * resource shortage. These devices will return queue full at varying - * depths. The driver will throttle back when the queue fulls occur and - * attempt to slowly increase the depth over time as the device recovers - * from the resource shortage. - * - * In this example, the first line will disable tagged queueing for all - * the devices on the first probed aic7xxx adapter. - * - * The second line enables tagged queueing with 4 commands/LUN for IDs - * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the - * driver to attempt to use up to 64 tags for ID 1. - * - * The third line is the same as the first line. - * - * The fourth line disables tagged queueing for devices 0 and 3. It - * enables tagged queueing for the other IDs, with 16 commands/LUN - * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for - * IDs 2, 5-7, and 9-15. - */ - -/* - * NOTE: The below structure is for reference only, the actual structure - * to modify in order to change things is just below this comment block. -adapter_tag_info_t aic7xxx_tag_info[] = -{ - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, - {{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}}, - {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, - {{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} -}; -*/ - -#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE -#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE -#else -#define AIC7XXX_CMDS_PER_DEVICE AHC_MAX_QUEUE -#endif - -#define AIC7XXX_CONFIGED_TAG_COMMANDS { \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE, \ - AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE \ -} - -/* - * By default, use the number of commands specified by - * the users kernel configuration. - */ -static adapter_tag_info_t aic7xxx_tag_info[] = -{ - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS}, - {AIC7XXX_CONFIGED_TAG_COMMANDS} -}; - -/* - * There should be a specific return value for this in scsi.h, but - * it seems that most drivers ignore it. - */ -#define DID_UNDERFLOW DID_ERROR - -void -ahc_print_path(struct ahc_softc *ahc, struct scb *scb) -{ - printk("(scsi%d:%c:%d:%d): ", - ahc->platform_data->host->host_no, - scb != NULL ? SCB_GET_CHANNEL(ahc, scb) : 'X', - scb != NULL ? SCB_GET_TARGET(ahc, scb) : -1, - scb != NULL ? SCB_GET_LUN(scb) : -1); -} - -/* - * XXX - these options apply unilaterally to _all_ 274x/284x/294x - * cards in the system. This should be fixed. Exceptions to this - * rule are noted in the comments. - */ - -/* - * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This - * has no effect on any later resets that might occur due to things like - * SCSI bus timeouts. - */ -static uint32_t aic7xxx_no_reset; - -/* - * Should we force EXTENDED translation on a controller. - * 0 == Use whatever is in the SEEPROM or default to off - * 1 == Use whatever is in the SEEPROM or default to on - */ -static uint32_t aic7xxx_extended; - -/* - * PCI bus parity checking of the Adaptec controllers. This is somewhat - * dubious at best. To my knowledge, this option has never actually - * solved a PCI parity problem, but on certain machines with broken PCI - * chipset configurations where stray PCI transactions with bad parity are - * the norm rather than the exception, the error messages can be overwhelming. - * It's included in the driver for completeness. - * 0 = Shut off PCI parity check - * non-0 = reverse polarity pci parity checking - */ -static uint32_t aic7xxx_pci_parity = ~0; - -/* - * There are lots of broken chipsets in the world. Some of them will - * violate the PCI spec when we issue byte sized memory writes to our - * controller. I/O mapped register access, if allowed by the given - * platform, will work in almost all cases. - */ -uint32_t aic7xxx_allow_memio = ~0; - -/* - * So that we can set how long each device is given as a selection timeout. - * The table of values goes like this: - * 0 - 256ms - * 1 - 128ms - * 2 - 64ms - * 3 - 32ms - * We default to 256ms because some older devices need a longer time - * to respond to initial selection. - */ -static uint32_t aic7xxx_seltime; - -/* - * Certain devices do not perform any aging on commands. Should the - * device be saturated by commands in one portion of the disk, it is - * possible for transactions on far away sectors to never be serviced. - * To handle these devices, we can periodically send an ordered tag to - * force all outstanding transactions to be serviced prior to a new - * transaction. - */ -static uint32_t aic7xxx_periodic_otag; - -/* - * Module information and settable options. - */ -static char *aic7xxx = NULL; - -MODULE_AUTHOR("Maintainer: Hannes Reinecke "); -MODULE_DESCRIPTION("Adaptec AIC77XX/78XX SCSI Host Bus Adapter driver"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(AIC7XXX_DRIVER_VERSION); -module_param(aic7xxx, charp, 0444); -MODULE_PARM_DESC(aic7xxx, -"period-delimited options string:\n" -" verbose Enable verbose/diagnostic logging\n" -" allow_memio Allow device registers to be memory mapped\n" -" debug Bitmask of debug values to enable\n" -" no_probe Toggle EISA/VLB controller probing\n" -" probe_eisa_vl Toggle EISA/VLB controller probing\n" -" no_reset Suppress initial bus resets\n" -" extended Enable extended geometry on all controllers\n" -" periodic_otag Send an ordered tagged transaction\n" -" periodically to prevent tag starvation.\n" -" This may be required by some older disk\n" -" drives or RAID arrays.\n" -" tag_info: Set per-target tag depth\n" -" global_tag_depth: Global tag depth for every target\n" -" on every bus\n" -" seltime: Selection Timeout\n" -" (0/256ms,1/128ms,2/64ms,3/32ms)\n" -"\n" -" Sample modprobe configuration file:\n" -" # Toggle EISA/VLB probing\n" -" # Set tag depth on Controller 1/Target 1 to 10 tags\n" -" # Shorten the selection timeout to 128ms\n" -"\n" -" options aic7xxx 'aic7xxx=probe_eisa_vl.tag_info:{{}.{.10}}.seltime:1'\n" -); - -static void ahc_linux_handle_scsi_status(struct ahc_softc *, - struct scsi_device *, - struct scb *); -static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, - struct scsi_cmnd *cmd); -static void ahc_linux_freeze_simq(struct ahc_softc *ahc); -static void ahc_linux_release_simq(struct ahc_softc *ahc); -static int ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); -static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc); -static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo); -static void ahc_linux_device_queue_depth(struct scsi_device *); -static int ahc_linux_run_command(struct ahc_softc*, - struct ahc_linux_device *, - struct scsi_cmnd *); -static void ahc_linux_setup_tag_info_global(char *p); -static int aic7xxx_setup(char *s); - -static int ahc_linux_unit; - - -/************************** OS Utility Wrappers *******************************/ -void -ahc_delay(long usec) -{ - /* - * udelay on Linux can have problems for - * multi-millisecond waits. Wait at most - * 1024us per call. - */ - while (usec > 0) { - udelay(usec % 1024); - usec -= 1024; - } -} - -/***************************** Low Level I/O **********************************/ -uint8_t -ahc_inb(struct ahc_softc * ahc, long port) -{ - uint8_t x; - - if (ahc->tag == BUS_SPACE_MEMIO) { - x = readb(ahc->bsh.maddr + port); - } else { - x = inb(ahc->bsh.ioport + port); - } - mb(); - return (x); -} - -void -ahc_outb(struct ahc_softc * ahc, long port, uint8_t val) -{ - if (ahc->tag == BUS_SPACE_MEMIO) { - writeb(val, ahc->bsh.maddr + port); - } else { - outb(val, ahc->bsh.ioport + port); - } - mb(); -} - -void -ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count) -{ - int i; - - /* - * There is probably a more efficient way to do this on Linux - * but we don't use this for anything speed critical and this - * should work. - */ - for (i = 0; i < count; i++) - ahc_outb(ahc, port, *array++); -} - -void -ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count) -{ - int i; - - /* - * There is probably a more efficient way to do this on Linux - * but we don't use this for anything speed critical and this - * should work. - */ - for (i = 0; i < count; i++) - *array++ = ahc_inb(ahc, port); -} - -/********************************* Inlines ************************************/ -static void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*); - -static int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, - struct ahc_dma_seg *sg, - dma_addr_t addr, bus_size_t len); - -static void -ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb) -{ - struct scsi_cmnd *cmd; - - cmd = scb->io_ctx; - ahc_sync_sglist(ahc, scb, BUS_DMASYNC_POSTWRITE); - - scsi_dma_unmap(cmd); -} - -static int -ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb, - struct ahc_dma_seg *sg, dma_addr_t addr, bus_size_t len) -{ - int consumed; - - if ((scb->sg_count + 1) > AHC_NSEG) - panic("Too few segs for dma mapping. " - "Increase AHC_NSEG\n"); - - consumed = 1; - sg->addr = ahc_htole32(addr & 0xFFFFFFFF); - scb->platform_data->xfer_len += len; - - if (sizeof(dma_addr_t) > 4 - && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) - len |= (addr >> 8) & AHC_SG_HIGH_ADDR_MASK; - - sg->len = ahc_htole32(len); - return (consumed); -} - -/* - * Return a string describing the driver. - */ -static const char * -ahc_linux_info(struct Scsi_Host *host) -{ - static char buffer[512]; - char ahc_info[256]; - char *bp; - struct ahc_softc *ahc; - - bp = &buffer[0]; - ahc = *(struct ahc_softc **)host->hostdata; - memset(bp, 0, sizeof(buffer)); - strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev " AIC7XXX_DRIVER_VERSION "\n" - " <"); - strcat(bp, ahc->description); - strcat(bp, ">\n" - " "); - ahc_controller_info(ahc, ahc_info); - strcat(bp, ahc_info); - strcat(bp, "\n"); - - return (bp); -} - -/* - * Queue an SCB to the controller. - */ -static int -ahc_linux_queue_lck(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) -{ - struct ahc_softc *ahc; - struct ahc_linux_device *dev = scsi_transport_device_data(cmd->device); - int rtn = SCSI_MLQUEUE_HOST_BUSY; - unsigned long flags; - - ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - - ahc_lock(ahc, &flags); - if (ahc->platform_data->qfrozen == 0) { - cmd->scsi_done = scsi_done; - cmd->result = CAM_REQ_INPROG << 16; - rtn = ahc_linux_run_command(ahc, dev, cmd); - } - ahc_unlock(ahc, &flags); - - return rtn; -} - -static DEF_SCSI_QCMD(ahc_linux_queue) - -static inline struct scsi_target ** -ahc_linux_target_in_softc(struct scsi_target *starget) -{ - struct ahc_softc *ahc = - *((struct ahc_softc **)dev_to_shost(&starget->dev)->hostdata); - unsigned int target_offset; - - target_offset = starget->id; - if (starget->channel != 0) - target_offset += 8; - - return &ahc->platform_data->starget[target_offset]; -} - -static int -ahc_linux_target_alloc(struct scsi_target *starget) -{ - struct ahc_softc *ahc = - *((struct ahc_softc **)dev_to_shost(&starget->dev)->hostdata); - struct seeprom_config *sc = ahc->seep_config; - unsigned long flags; - struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget); - unsigned short scsirate; - struct ahc_devinfo devinfo; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - char channel = starget->channel + 'A'; - unsigned int our_id = ahc->our_id; - unsigned int target_offset; - - target_offset = starget->id; - if (starget->channel != 0) - target_offset += 8; - - if (starget->channel) - our_id = ahc->our_id_b; - - ahc_lock(ahc, &flags); - - BUG_ON(*ahc_targp != NULL); - - *ahc_targp = starget; - - if (sc) { - int maxsync = AHC_SYNCRATE_DT; - int ultra = 0; - int flags = sc->device_flags[target_offset]; - - if (ahc->flags & AHC_NEWEEPROM_FMT) { - if (flags & CFSYNCHISULTRA) - ultra = 1; - } else if (flags & CFULTRAEN) - ultra = 1; - /* AIC nutcase; 10MHz appears as ultra = 1, CFXFER = 0x04 - * change it to ultra=0, CFXFER = 0 */ - if(ultra && (flags & CFXFER) == 0x04) { - ultra = 0; - flags &= ~CFXFER; - } - - if ((ahc->features & AHC_ULTRA2) != 0) { - scsirate = (flags & CFXFER) | (ultra ? 0x8 : 0); - } else { - scsirate = (flags & CFXFER) << 4; - maxsync = ultra ? AHC_SYNCRATE_ULTRA : - AHC_SYNCRATE_FAST; - } - spi_max_width(starget) = (flags & CFWIDEB) ? 1 : 0; - if (!(flags & CFSYNCH)) - spi_max_offset(starget) = 0; - spi_min_period(starget) = - ahc_find_period(ahc, scsirate, maxsync); - - tinfo = ahc_fetch_transinfo(ahc, channel, ahc->our_id, - starget->id, &tstate); - } - ahc_compile_devinfo(&devinfo, our_id, starget->id, - CAM_LUN_WILDCARD, channel, - ROLE_INITIATOR); - ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0, - AHC_TRANS_GOAL, /*paused*/FALSE); - ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHC_TRANS_GOAL, /*paused*/FALSE); - ahc_unlock(ahc, &flags); - - return 0; -} - -static void -ahc_linux_target_destroy(struct scsi_target *starget) -{ - struct scsi_target **ahc_targp = ahc_linux_target_in_softc(starget); - - *ahc_targp = NULL; -} - -static int -ahc_linux_slave_alloc(struct scsi_device *sdev) -{ - struct ahc_softc *ahc = - *((struct ahc_softc **)sdev->host->hostdata); - struct scsi_target *starget = sdev->sdev_target; - struct ahc_linux_device *dev; - - if (bootverbose) - printk("%s: Slave Alloc %d\n", ahc_name(ahc), sdev->id); - - dev = scsi_transport_device_data(sdev); - memset(dev, 0, sizeof(*dev)); - - /* - * We start out life using untagged - * transactions of which we allow one. - */ - dev->openings = 1; - - /* - * Set maxtags to 0. This will be changed if we - * later determine that we are dealing with - * a tagged queuing capable device. - */ - dev->maxtags = 0; - - spi_period(starget) = 0; - - return 0; -} - -static int -ahc_linux_slave_configure(struct scsi_device *sdev) -{ - struct ahc_softc *ahc; - - ahc = *((struct ahc_softc **)sdev->host->hostdata); - - if (bootverbose) - sdev_printk(KERN_INFO, sdev, "Slave Configure\n"); - - ahc_linux_device_queue_depth(sdev); - - /* Initial Domain Validation */ - if (!spi_initial_dv(sdev->sdev_target)) - spi_dv_device(sdev); - - return 0; -} - -#if defined(__i386__) -/* - * Return the disk geometry for the given SCSI device. - */ -static int -ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - uint8_t *bh; - int heads; - int sectors; - int cylinders; - int ret; - int extended; - struct ahc_softc *ahc; - u_int channel; - - ahc = *((struct ahc_softc **)sdev->host->hostdata); - channel = sdev_channel(sdev); - - bh = scsi_bios_ptable(bdev); - if (bh) { - ret = scsi_partsize(bh, capacity, - &geom[2], &geom[0], &geom[1]); - kfree(bh); - if (ret != -1) - return (ret); - } - heads = 64; - sectors = 32; - cylinders = aic_sector_div(capacity, heads, sectors); - - if (aic7xxx_extended != 0) - extended = 1; - else if (channel == 0) - extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0; - else - extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0; - if (extended && cylinders >= 1024) { - heads = 255; - sectors = 63; - cylinders = aic_sector_div(capacity, heads, sectors); - } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - return (0); -} -#endif - -/* - * Abort the current SCSI command(s). - */ -static int -ahc_linux_abort(struct scsi_cmnd *cmd) -{ - int error; - - error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT); - if (error != 0) - printk("aic7xxx_abort returns 0x%x\n", error); - return (error); -} - -/* - * Attempt to send a target reset message to the device that timed out. - */ -static int -ahc_linux_dev_reset(struct scsi_cmnd *cmd) -{ - int error; - - error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); - if (error != 0) - printk("aic7xxx_dev_reset returns 0x%x\n", error); - return (error); -} - -/* - * Reset the SCSI bus. - */ -static int -ahc_linux_bus_reset(struct scsi_cmnd *cmd) -{ - struct ahc_softc *ahc; - int found; - unsigned long flags; - - ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - - ahc_lock(ahc, &flags); - found = ahc_reset_channel(ahc, scmd_channel(cmd) + 'A', - /*initiate reset*/TRUE); - ahc_unlock(ahc, &flags); - - if (bootverbose) - printk("%s: SCSI bus reset delivered. " - "%d SCBs aborted.\n", ahc_name(ahc), found); - - return SUCCESS; -} - -struct scsi_host_template aic7xxx_driver_template = { - .module = THIS_MODULE, - .name = "aic7xxx", - .proc_name = "aic7xxx", - .proc_info = ahc_linux_proc_info, - .info = ahc_linux_info, - .queuecommand = ahc_linux_queue, - .eh_abort_handler = ahc_linux_abort, - .eh_device_reset_handler = ahc_linux_dev_reset, - .eh_bus_reset_handler = ahc_linux_bus_reset, -#if defined(__i386__) - .bios_param = ahc_linux_biosparam, -#endif - .can_queue = AHC_MAX_QUEUE, - .this_id = -1, - .max_sectors = 8192, - .cmd_per_lun = 2, - .use_clustering = ENABLE_CLUSTERING, - .slave_alloc = ahc_linux_slave_alloc, - .slave_configure = ahc_linux_slave_configure, - .target_alloc = ahc_linux_target_alloc, - .target_destroy = ahc_linux_target_destroy, -}; - -/**************************** Tasklet Handler *********************************/ - -/******************************** Macros **************************************/ -#define BUILD_SCSIID(ahc, cmd) \ - ((((cmd)->device->id << TID_SHIFT) & TID) \ - | (((cmd)->device->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \ - | (((cmd)->device->channel == 0) ? 0 : TWIN_CHNLB)) - -/******************************** Bus DMA *************************************/ -int -ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent, - bus_size_t alignment, bus_size_t boundary, - dma_addr_t lowaddr, dma_addr_t highaddr, - bus_dma_filter_t *filter, void *filterarg, - bus_size_t maxsize, int nsegments, - bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag) -{ - bus_dma_tag_t dmat; - - dmat = kmalloc(sizeof(*dmat), GFP_ATOMIC); - if (dmat == NULL) - return (ENOMEM); - - /* - * Linux is very simplistic about DMA memory. For now don't - * maintain all specification information. Once Linux supplies - * better facilities for doing these operations, or the - * needs of this particular driver change, we might need to do - * more here. - */ - dmat->alignment = alignment; - dmat->boundary = boundary; - dmat->maxsize = maxsize; - *ret_tag = dmat; - return (0); -} - -void -ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat) -{ - kfree(dmat); -} - -int -ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr, - int flags, bus_dmamap_t *mapp) -{ - *vaddr = pci_alloc_consistent(ahc->dev_softc, - dmat->maxsize, mapp); - if (*vaddr == NULL) - return ENOMEM; - return 0; -} - -void -ahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat, - void* vaddr, bus_dmamap_t map) -{ - pci_free_consistent(ahc->dev_softc, dmat->maxsize, - vaddr, map); -} - -int -ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map, - void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb, - void *cb_arg, int flags) -{ - /* - * Assume for now that this will only be used during - * initialization and not for per-transaction buffer mapping. - */ - bus_dma_segment_t stack_sg; - - stack_sg.ds_addr = map; - stack_sg.ds_len = dmat->maxsize; - cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); - return (0); -} - -void -ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) -{ -} - -int -ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map) -{ - /* Nothing to do */ - return (0); -} - -static void -ahc_linux_setup_tag_info_global(char *p) -{ - int tags, i, j; - - tags = simple_strtoul(p + 1, NULL, 0) & 0xff; - printk("Setting Global Tags= %d\n", tags); - - for (i = 0; i < ARRAY_SIZE(aic7xxx_tag_info); i++) { - for (j = 0; j < AHC_NUM_TARGETS; j++) { - aic7xxx_tag_info[i].tag_commands[j] = tags; - } - } -} - -static void -ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) -{ - - if ((instance >= 0) && (targ >= 0) - && (instance < ARRAY_SIZE(aic7xxx_tag_info)) - && (targ < AHC_NUM_TARGETS)) { - aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff; - if (bootverbose) - printk("tag_info[%d:%d] = %d\n", instance, targ, value); - } -} - -static char * -ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, - void (*callback)(u_long, int, int, int32_t), - u_long callback_arg) -{ - char *tok_end; - char *tok_end2; - int i; - int instance; - int targ; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - /* All options use a ':' name/arg separator */ - if (*opt_arg != ':') - return (opt_arg); - opt_arg++; - instance = -1; - targ = -1; - done = FALSE; - /* - * Restore separator that may be in - * the middle of our option argument. - */ - tok_end = strchr(opt_arg, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*opt_arg) { - case '{': - if (instance == -1) { - instance = 0; - } else { - if (depth > 1) { - if (targ == -1) - targ = 0; - } else { - printk("Malformed Option %s\n", - opt_name); - done = TRUE; - } - } - opt_arg++; - break; - case '}': - if (targ != -1) - targ = -1; - else if (instance != -1) - instance = -1; - opt_arg++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (targ >= 0) - targ++; - else if (instance >= 0) - instance++; - opt_arg++; - break; - case '\0': - done = TRUE; - break; - default: - tok_end = end; - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(opt_arg, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) - tok_end = tok_end2; - } - callback(callback_arg, instance, targ, - simple_strtol(opt_arg, NULL, 0)); - opt_arg = tok_end; - break; - } - } - return (opt_arg); -} - -/* - * Handle Linux boot parameters. This routine allows for assigning a value - * to a parameter with a ':' between the parameter and the value. - * ie. aic7xxx=stpwlev:1,extended - */ -static int -aic7xxx_setup(char *s) -{ - int i, n; - char *p; - char *end; - - static const struct { - const char *name; - uint32_t *flag; - } options[] = { - { "extended", &aic7xxx_extended }, - { "no_reset", &aic7xxx_no_reset }, - { "verbose", &aic7xxx_verbose }, - { "allow_memio", &aic7xxx_allow_memio}, -#ifdef AHC_DEBUG - { "debug", &ahc_debug }, -#endif - { "periodic_otag", &aic7xxx_periodic_otag }, - { "pci_parity", &aic7xxx_pci_parity }, - { "seltime", &aic7xxx_seltime }, - { "tag_info", NULL }, - { "global_tag_depth", NULL }, - { "dv", NULL } - }; - - end = strchr(s, '\0'); - - /* - * XXX ia64 gcc isn't smart enough to know that ARRAY_SIZE - * will never be 0 in this case. - */ - n = 0; - - while ((p = strsep(&s, ",.")) != NULL) { - if (*p == '\0') - continue; - for (i = 0; i < ARRAY_SIZE(options); i++) { - - n = strlen(options[i].name); - if (strncmp(options[i].name, p, n) == 0) - break; - } - if (i == ARRAY_SIZE(options)) - continue; - - if (strncmp(p, "global_tag_depth", n) == 0) { - ahc_linux_setup_tag_info_global(p + n); - } else if (strncmp(p, "tag_info", n) == 0) { - s = ahc_parse_brace_option("tag_info", p + n, end, - 2, ahc_linux_setup_tag_info, 0); - } else if (p[n] == ':') { - *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); - } else if (strncmp(p, "verbose", n) == 0) { - *(options[i].flag) = 1; - } else { - *(options[i].flag) ^= 0xFFFFFFFF; - } - } - return 1; -} - -__setup("aic7xxx=", aic7xxx_setup); - -uint32_t aic7xxx_verbose; - -int -ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *template) -{ - char buf[80]; - struct Scsi_Host *host; - char *new_name; - u_long s; - int retval; - - template->name = ahc->description; - host = scsi_host_alloc(template, sizeof(struct ahc_softc *)); - if (host == NULL) - return (ENOMEM); - - *((struct ahc_softc **)host->hostdata) = ahc; - ahc->platform_data->host = host; - host->can_queue = AHC_MAX_QUEUE; - host->cmd_per_lun = 2; - /* XXX No way to communicate the ID for multiple channels */ - host->this_id = ahc->our_id; - host->irq = ahc->platform_data->irq; - host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8; - host->max_lun = AHC_NUM_LUNS; - host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0; - host->sg_tablesize = AHC_NSEG; - ahc_lock(ahc, &s); - ahc_set_unit(ahc, ahc_linux_unit++); - ahc_unlock(ahc, &s); - sprintf(buf, "scsi%d", host->host_no); - new_name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); - if (new_name != NULL) { - strcpy(new_name, buf); - ahc_set_name(ahc, new_name); - } - host->unique_id = ahc->unit; - ahc_linux_initialize_scsi_bus(ahc); - ahc_intr_enable(ahc, TRUE); - - host->transportt = ahc_linux_transport_template; - - retval = scsi_add_host(host, - (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); - if (retval) { - printk(KERN_WARNING "aic7xxx: scsi_add_host failed\n"); - scsi_host_put(host); - return retval; - } - - scsi_scan_host(host); - return 0; -} - -/* - * Place the SCSI bus into a known state by either resetting it, - * or forcing transfer negotiations on the next command to any - * target. - */ -void -ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc) -{ - int i; - int numtarg; - unsigned long s; - - i = 0; - numtarg = 0; - - ahc_lock(ahc, &s); - - if (aic7xxx_no_reset != 0) - ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B); - - if ((ahc->flags & AHC_RESET_BUS_A) != 0) - ahc_reset_channel(ahc, 'A', /*initiate_reset*/TRUE); - else - numtarg = (ahc->features & AHC_WIDE) ? 16 : 8; - - if ((ahc->features & AHC_TWIN) != 0) { - - if ((ahc->flags & AHC_RESET_BUS_B) != 0) { - ahc_reset_channel(ahc, 'B', /*initiate_reset*/TRUE); - } else { - if (numtarg == 0) - i = 8; - numtarg += 8; - } - } - - /* - * Force negotiation to async for all targets that - * will not see an initial bus reset. - */ - for (; i < numtarg; i++) { - struct ahc_devinfo devinfo; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - u_int our_id; - u_int target_id; - char channel; - - channel = 'A'; - our_id = ahc->our_id; - target_id = i; - if (i > 7 && (ahc->features & AHC_TWIN) != 0) { - channel = 'B'; - our_id = ahc->our_id_b; - target_id = i % 8; - } - tinfo = ahc_fetch_transinfo(ahc, channel, our_id, - target_id, &tstate); - ahc_compile_devinfo(&devinfo, our_id, target_id, - CAM_LUN_WILDCARD, channel, ROLE_INITIATOR); - ahc_update_neg_request(ahc, &devinfo, tstate, - tinfo, AHC_NEG_ALWAYS); - } - ahc_unlock(ahc, &s); - /* Give the bus some time to recover */ - if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) { - ahc_linux_freeze_simq(ahc); - msleep(AIC7XXX_RESET_DELAY); - ahc_linux_release_simq(ahc); - } -} - -int -ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg) -{ - - ahc->platform_data = - kmalloc(sizeof(struct ahc_platform_data), GFP_ATOMIC); - if (ahc->platform_data == NULL) - return (ENOMEM); - memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data)); - ahc->platform_data->irq = AHC_LINUX_NOIRQ; - ahc_lockinit(ahc); - ahc->seltime = (aic7xxx_seltime & 0x3) << 4; - ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4; - if (aic7xxx_pci_parity == 0) - ahc->flags |= AHC_DISABLE_PCI_PERR; - - return (0); -} - -void -ahc_platform_free(struct ahc_softc *ahc) -{ - struct scsi_target *starget; - int i; - - if (ahc->platform_data != NULL) { - /* destroy all of the device and target objects */ - for (i = 0; i < AHC_NUM_TARGETS; i++) { - starget = ahc->platform_data->starget[i]; - if (starget != NULL) { - ahc->platform_data->starget[i] = NULL; - } - } - - if (ahc->platform_data->irq != AHC_LINUX_NOIRQ) - free_irq(ahc->platform_data->irq, ahc); - if (ahc->tag == BUS_SPACE_PIO - && ahc->bsh.ioport != 0) - release_region(ahc->bsh.ioport, 256); - if (ahc->tag == BUS_SPACE_MEMIO - && ahc->bsh.maddr != NULL) { - iounmap(ahc->bsh.maddr); - release_mem_region(ahc->platform_data->mem_busaddr, - 0x1000); - } - - if (ahc->platform_data->host) - scsi_host_put(ahc->platform_data->host); - - kfree(ahc->platform_data); - } -} - -void -ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb) -{ - ahc_platform_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb), - SCB_GET_CHANNEL(ahc, scb), - SCB_GET_LUN(scb), SCB_LIST_NULL, - ROLE_UNKNOWN, CAM_REQUEUE_REQ); -} - -void -ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, - struct ahc_devinfo *devinfo, ahc_queue_alg alg) -{ - struct ahc_linux_device *dev; - int was_queuing; - int now_queuing; - - if (sdev == NULL) - return; - dev = scsi_transport_device_data(sdev); - - was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED); - switch (alg) { - default: - case AHC_QUEUE_NONE: - now_queuing = 0; - break; - case AHC_QUEUE_BASIC: - now_queuing = AHC_DEV_Q_BASIC; - break; - case AHC_QUEUE_TAGGED: - now_queuing = AHC_DEV_Q_TAGGED; - break; - } - if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0 - && (was_queuing != now_queuing) - && (dev->active != 0)) { - dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen++; - } - - dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED|AHC_DEV_PERIODIC_OTAG); - if (now_queuing) { - u_int usertags; - - usertags = ahc_linux_user_tagdepth(ahc, devinfo); - if (!was_queuing) { - /* - * Start out aggressively and allow our - * dynamic queue depth algorithm to take - * care of the rest. - */ - dev->maxtags = usertags; - dev->openings = dev->maxtags - dev->active; - } - if (dev->maxtags == 0) { - /* - * Queueing is disabled by the user. - */ - dev->openings = 1; - } else if (alg == AHC_QUEUE_TAGGED) { - dev->flags |= AHC_DEV_Q_TAGGED; - if (aic7xxx_periodic_otag != 0) - dev->flags |= AHC_DEV_PERIODIC_OTAG; - } else - dev->flags |= AHC_DEV_Q_BASIC; - } else { - /* We can only have one opening. */ - dev->maxtags = 0; - dev->openings = 1 - dev->active; - } - switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) { - case AHC_DEV_Q_BASIC: - scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); - scsi_activate_tcq(sdev, dev->openings + dev->active); - break; - case AHC_DEV_Q_TAGGED: - scsi_set_tag_type(sdev, MSG_ORDERED_TAG); - scsi_activate_tcq(sdev, dev->openings + dev->active); - break; - default: - /* - * We allow the OS to queue 2 untagged transactions to - * us at any time even though we can only execute them - * serially on the controller/device. This should - * remove some latency. - */ - scsi_deactivate_tcq(sdev, 2); - break; - } -} - -int -ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, - int lun, u_int tag, role_t role, uint32_t status) -{ - return 0; -} - -static u_int -ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo) -{ - static int warned_user; - u_int tags; - - tags = 0; - if ((ahc->user_discenable & devinfo->target_mask) != 0) { - if (ahc->unit >= ARRAY_SIZE(aic7xxx_tag_info)) { - if (warned_user == 0) { - - printk(KERN_WARNING -"aic7xxx: WARNING: Insufficient tag_info instances\n" -"aic7xxx: for installed controllers. Using defaults\n" -"aic7xxx: Please update the aic7xxx_tag_info array in\n" -"aic7xxx: the aic7xxx_osm..c source file.\n"); - warned_user++; - } - tags = AHC_MAX_QUEUE; - } else { - adapter_tag_info_t *tag_info; - - tag_info = &aic7xxx_tag_info[ahc->unit]; - tags = tag_info->tag_commands[devinfo->target_offset]; - if (tags > AHC_MAX_QUEUE) - tags = AHC_MAX_QUEUE; - } - } - return (tags); -} - -/* - * Determines the queue depth for a given device. - */ -static void -ahc_linux_device_queue_depth(struct scsi_device *sdev) -{ - struct ahc_devinfo devinfo; - u_int tags; - struct ahc_softc *ahc = *((struct ahc_softc **)sdev->host->hostdata); - - ahc_compile_devinfo(&devinfo, - sdev->sdev_target->channel == 0 - ? ahc->our_id : ahc->our_id_b, - sdev->sdev_target->id, sdev->lun, - sdev->sdev_target->channel == 0 ? 'A' : 'B', - ROLE_INITIATOR); - tags = ahc_linux_user_tagdepth(ahc, &devinfo); - if (tags != 0 && sdev->tagged_supported != 0) { - - ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_TAGGED); - ahc_send_async(ahc, devinfo.channel, devinfo.target, - devinfo.lun, AC_TRANSFER_NEG); - ahc_print_devinfo(ahc, &devinfo); - printk("Tagged Queuing enabled. Depth %d\n", tags); - } else { - ahc_platform_set_tags(ahc, sdev, &devinfo, AHC_QUEUE_NONE); - ahc_send_async(ahc, devinfo.channel, devinfo.target, - devinfo.lun, AC_TRANSFER_NEG); - } -} - -static int -ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev, - struct scsi_cmnd *cmd) -{ - struct scb *scb; - struct hardware_scb *hscb; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - uint16_t mask; - struct scb_tailq *untagged_q = NULL; - int nseg; - - /* - * Schedule us to run later. The only reason we are not - * running is because the whole controller Q is frozen. - */ - if (ahc->platform_data->qfrozen != 0) - return SCSI_MLQUEUE_HOST_BUSY; - - /* - * We only allow one untagged transaction - * per target in the initiator role unless - * we are storing a full busy target *lun* - * table in SCB space. - */ - if (!blk_rq_tagged(cmd->request) - && (ahc->features & AHC_SCB_BTT) == 0) { - int target_offset; - - target_offset = cmd->device->id + cmd->device->channel * 8; - untagged_q = &(ahc->untagged_queues[target_offset]); - if (!TAILQ_EMPTY(untagged_q)) - /* if we're already executing an untagged command - * we're busy to another */ - return SCSI_MLQUEUE_DEVICE_BUSY; - } - - nseg = scsi_dma_map(cmd); - if (nseg < 0) - return SCSI_MLQUEUE_HOST_BUSY; - - /* - * Get an scb to use. - */ - scb = ahc_get_scb(ahc); - if (!scb) { - scsi_dma_unmap(cmd); - return SCSI_MLQUEUE_HOST_BUSY; - } - - scb->io_ctx = cmd; - scb->platform_data->dev = dev; - hscb = scb->hscb; - cmd->host_scribble = (char *)scb; - - /* - * Fill out basics of the HSCB. - */ - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahc, cmd); - hscb->lun = cmd->device->lun; - mask = SCB_GET_TARGET_MASK(ahc, scb); - tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb), - SCB_GET_OUR_ID(scb), - SCB_GET_TARGET(ahc, scb), &tstate); - hscb->scsirate = tinfo->scsirate; - hscb->scsioffset = tinfo->curr.offset; - if ((tstate->ultraenb & mask) != 0) - hscb->control |= ULTRAENB; - - if ((ahc->user_discenable & mask) != 0) - hscb->control |= DISCENB; - - if ((tstate->auto_negotiate & mask) != 0) { - scb->flags |= SCB_AUTO_NEGOTIATE; - scb->hscb->control |= MK_MESSAGE; - } - - if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) { - int msg_bytes; - uint8_t tag_msgs[2]; - - msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); - if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { - hscb->control |= tag_msgs[0]; - if (tag_msgs[0] == MSG_ORDERED_TASK) - dev->commands_since_idle_or_otag = 0; - } else if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH - && (dev->flags & AHC_DEV_Q_TAGGED) != 0) { - hscb->control |= MSG_ORDERED_TASK; - dev->commands_since_idle_or_otag = 0; - } else { - hscb->control |= MSG_SIMPLE_TASK; - } - } - - hscb->cdb_len = cmd->cmd_len; - if (hscb->cdb_len <= 12) { - memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len); - } else { - memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len); - scb->flags |= SCB_CDB32_PTR; - } - - scb->platform_data->xfer_len = 0; - ahc_set_residual(scb, 0); - ahc_set_sense_residual(scb, 0); - scb->sg_count = 0; - - if (nseg > 0) { - struct ahc_dma_seg *sg; - struct scatterlist *cur_seg; - int i; - - /* Copy the segments into the SG list. */ - sg = scb->sg_list; - /* - * The sg_count may be larger than nseg if - * a transfer crosses a 32bit page. - */ - scsi_for_each_sg(cmd, cur_seg, nseg, i) { - dma_addr_t addr; - bus_size_t len; - int consumed; - - addr = sg_dma_address(cur_seg); - len = sg_dma_len(cur_seg); - consumed = ahc_linux_map_seg(ahc, scb, - sg, addr, len); - sg += consumed; - scb->sg_count += consumed; - } - sg--; - sg->len |= ahc_htole32(AHC_DMA_LAST_SEG); - - /* - * Reset the sg list pointer. - */ - scb->hscb->sgptr = - ahc_htole32(scb->sg_list_phys | SG_FULL_RESID); - - /* - * Copy the first SG into the "current" - * data pointer area. - */ - scb->hscb->dataptr = scb->sg_list->addr; - scb->hscb->datacnt = scb->sg_list->len; - } else { - scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL); - scb->hscb->dataptr = 0; - scb->hscb->datacnt = 0; - scb->sg_count = 0; - } - - LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links); - dev->openings--; - dev->active++; - dev->commands_issued++; - if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0) - dev->commands_since_idle_or_otag++; - - scb->flags |= SCB_ACTIVE; - if (untagged_q) { - TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe); - scb->flags |= SCB_UNTAGGEDQ; - } - ahc_queue_scb(ahc, scb); - return 0; -} - -/* - * SCSI controller interrupt handler. - */ -irqreturn_t -ahc_linux_isr(int irq, void *dev_id) -{ - struct ahc_softc *ahc; - u_long flags; - int ours; - - ahc = (struct ahc_softc *) dev_id; - ahc_lock(ahc, &flags); - ours = ahc_intr(ahc); - ahc_unlock(ahc, &flags); - return IRQ_RETVAL(ours); -} - -void -ahc_platform_flushwork(struct ahc_softc *ahc) -{ - -} - -void -ahc_send_async(struct ahc_softc *ahc, char channel, - u_int target, u_int lun, ac_code code) -{ - switch (code) { - case AC_TRANSFER_NEG: - { - char buf[80]; - struct scsi_target *starget; - struct ahc_linux_target *targ; - struct info_str info; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - int target_offset; - unsigned int target_ppr_options; - - BUG_ON(target == CAM_TARGET_WILDCARD); - - info.buffer = buf; - info.length = sizeof(buf); - info.offset = 0; - info.pos = 0; - tinfo = ahc_fetch_transinfo(ahc, channel, - channel == 'A' ? ahc->our_id - : ahc->our_id_b, - target, &tstate); - - /* - * Don't bother reporting results while - * negotiations are still pending. - */ - if (tinfo->curr.period != tinfo->goal.period - || tinfo->curr.width != tinfo->goal.width - || tinfo->curr.offset != tinfo->goal.offset - || tinfo->curr.ppr_options != tinfo->goal.ppr_options) - if (bootverbose == 0) - break; - - /* - * Don't bother reporting results that - * are identical to those last reported. - */ - target_offset = target; - if (channel == 'B') - target_offset += 8; - starget = ahc->platform_data->starget[target_offset]; - if (starget == NULL) - break; - targ = scsi_transport_target_data(starget); - - target_ppr_options = - (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) - + (spi_qas(starget) ? MSG_EXT_PPR_QAS_REQ : 0) - + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0); - - if (tinfo->curr.period == spi_period(starget) - && tinfo->curr.width == spi_width(starget) - && tinfo->curr.offset == spi_offset(starget) - && tinfo->curr.ppr_options == target_ppr_options) - if (bootverbose == 0) - break; - - spi_period(starget) = tinfo->curr.period; - spi_width(starget) = tinfo->curr.width; - spi_offset(starget) = tinfo->curr.offset; - spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0; - spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0; - spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0; - spi_display_xfer_agreement(starget); - break; - } - case AC_SENT_BDR: - { - WARN_ON(lun != CAM_LUN_WILDCARD); - scsi_report_device_reset(ahc->platform_data->host, - channel - 'A', target); - break; - } - case AC_BUS_RESET: - if (ahc->platform_data->host != NULL) { - scsi_report_bus_reset(ahc->platform_data->host, - channel - 'A'); - } - break; - default: - panic("ahc_send_async: Unexpected async event"); - } -} - -/* - * Calls the higher level scsi done function and frees the scb. - */ -void -ahc_done(struct ahc_softc *ahc, struct scb *scb) -{ - struct scsi_cmnd *cmd; - struct ahc_linux_device *dev; - - LIST_REMOVE(scb, pending_links); - if ((scb->flags & SCB_UNTAGGEDQ) != 0) { - struct scb_tailq *untagged_q; - int target_offset; - - target_offset = SCB_GET_TARGET_OFFSET(ahc, scb); - untagged_q = &(ahc->untagged_queues[target_offset]); - TAILQ_REMOVE(untagged_q, scb, links.tqe); - BUG_ON(!TAILQ_EMPTY(untagged_q)); - } else if ((scb->flags & SCB_ACTIVE) == 0) { - /* - * Transactions aborted from the untagged queue may - * not have been dispatched to the controller, so - * only check the SCB_ACTIVE flag for tagged transactions. - */ - printk("SCB %d done'd twice\n", scb->hscb->tag); - ahc_dump_card_state(ahc); - panic("Stopping for safety"); - } - cmd = scb->io_ctx; - dev = scb->platform_data->dev; - dev->active--; - dev->openings++; - if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) { - cmd->result &= ~(CAM_DEV_QFRZN << 16); - dev->qfrozen--; - } - ahc_linux_unmap_scb(ahc, scb); - - /* - * Guard against stale sense data. - * The Linux mid-layer assumes that sense - * was retrieved anytime the first byte of - * the sense buffer looks "sane". - */ - cmd->sense_buffer[0] = 0; - if (ahc_get_transaction_status(scb) == CAM_REQ_INPROG) { - uint32_t amount_xferred; - - amount_xferred = - ahc_get_transfer_length(scb) - ahc_get_residual(scb); - if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) { -#ifdef AHC_DEBUG - if ((ahc_debug & AHC_SHOW_MISC) != 0) { - ahc_print_path(ahc, scb); - printk("Set CAM_UNCOR_PARITY\n"); - } -#endif - ahc_set_transaction_status(scb, CAM_UNCOR_PARITY); -#ifdef AHC_REPORT_UNDERFLOWS - /* - * This code is disabled by default as some - * clients of the SCSI system do not properly - * initialize the underflow parameter. This - * results in spurious termination of commands - * that complete as expected (e.g. underflow is - * allowed as command can return variable amounts - * of data. - */ - } else if (amount_xferred < scb->io_ctx->underflow) { - u_int i; - - ahc_print_path(ahc, scb); - printk("CDB:"); - for (i = 0; i < scb->io_ctx->cmd_len; i++) - printk(" 0x%x", scb->io_ctx->cmnd[i]); - printk("\n"); - ahc_print_path(ahc, scb); - printk("Saw underflow (%ld of %ld bytes). " - "Treated as error\n", - ahc_get_residual(scb), - ahc_get_transfer_length(scb)); - ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR); -#endif - } else { - ahc_set_transaction_status(scb, CAM_REQ_CMP); - } - } else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { - ahc_linux_handle_scsi_status(ahc, cmd->device, scb); - } - - if (dev->openings == 1 - && ahc_get_transaction_status(scb) == CAM_REQ_CMP - && ahc_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL) - dev->tag_success_count++; - /* - * Some devices deal with temporary internal resource - * shortages by returning queue full. When the queue - * full occurrs, we throttle back. Slowly try to get - * back to our previous queue depth. - */ - if ((dev->openings + dev->active) < dev->maxtags - && dev->tag_success_count > AHC_TAG_SUCCESS_INTERVAL) { - dev->tag_success_count = 0; - dev->openings++; - } - - if (dev->active == 0) - dev->commands_since_idle_or_otag = 0; - - if ((scb->flags & SCB_RECOVERY_SCB) != 0) { - printk("Recovery SCB completes\n"); - if (ahc_get_transaction_status(scb) == CAM_BDR_SENT - || ahc_get_transaction_status(scb) == CAM_REQ_ABORTED) - ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT); - - if (ahc->platform_data->eh_done) - complete(ahc->platform_data->eh_done); - } - - ahc_free_scb(ahc, scb); - ahc_linux_queue_cmd_complete(ahc, cmd); -} - -static void -ahc_linux_handle_scsi_status(struct ahc_softc *ahc, - struct scsi_device *sdev, struct scb *scb) -{ - struct ahc_devinfo devinfo; - struct ahc_linux_device *dev = scsi_transport_device_data(sdev); - - ahc_compile_devinfo(&devinfo, - ahc->our_id, - sdev->sdev_target->id, sdev->lun, - sdev->sdev_target->channel == 0 ? 'A' : 'B', - ROLE_INITIATOR); - - /* - * We don't currently trust the mid-layer to - * properly deal with queue full or busy. So, - * when one occurs, we tell the mid-layer to - * unconditionally requeue the command to us - * so that we can retry it ourselves. We also - * implement our own throttling mechanism so - * we don't clobber the device with too many - * commands. - */ - switch (ahc_get_scsi_status(scb)) { - default: - break; - case SCSI_STATUS_CHECK_COND: - case SCSI_STATUS_CMD_TERMINATED: - { - struct scsi_cmnd *cmd; - - /* - * Copy sense information to the OS's cmd - * structure if it is available. - */ - cmd = scb->io_ctx; - if (scb->flags & SCB_SENSE) { - u_int sense_size; - - sense_size = min(sizeof(struct scsi_sense_data) - - ahc_get_sense_residual(scb), - (u_long)SCSI_SENSE_BUFFERSIZE); - memcpy(cmd->sense_buffer, - ahc_get_sense_buf(ahc, scb), sense_size); - if (sense_size < SCSI_SENSE_BUFFERSIZE) - memset(&cmd->sense_buffer[sense_size], 0, - SCSI_SENSE_BUFFERSIZE - sense_size); - cmd->result |= (DRIVER_SENSE << 24); -#ifdef AHC_DEBUG - if (ahc_debug & AHC_SHOW_SENSE) { - int i; - - printk("Copied %d bytes of sense data:", - sense_size); - for (i = 0; i < sense_size; i++) { - if ((i & 0xF) == 0) - printk("\n"); - printk("0x%x ", cmd->sense_buffer[i]); - } - printk("\n"); - } -#endif - } - break; - } - case SCSI_STATUS_QUEUE_FULL: - { - /* - * By the time the core driver has returned this - * command, all other commands that were queued - * to us but not the device have been returned. - * This ensures that dev->active is equal to - * the number of commands actually queued to - * the device. - */ - dev->tag_success_count = 0; - if (dev->active != 0) { - /* - * Drop our opening count to the number - * of commands currently outstanding. - */ - dev->openings = 0; -/* - ahc_print_path(ahc, scb); - printk("Dropping tag count to %d\n", dev->active); - */ - if (dev->active == dev->tags_on_last_queuefull) { - - dev->last_queuefull_same_count++; - /* - * If we repeatedly see a queue full - * at the same queue depth, this - * device has a fixed number of tag - * slots. Lock in this tag depth - * so we stop seeing queue fulls from - * this device. - */ - if (dev->last_queuefull_same_count - == AHC_LOCK_TAGS_COUNT) { - dev->maxtags = dev->active; - ahc_print_path(ahc, scb); - printk("Locking max tag count at %d\n", - dev->active); - } - } else { - dev->tags_on_last_queuefull = dev->active; - dev->last_queuefull_same_count = 0; - } - ahc_set_transaction_status(scb, CAM_REQUEUE_REQ); - ahc_set_scsi_status(scb, SCSI_STATUS_OK); - ahc_platform_set_tags(ahc, sdev, &devinfo, - (dev->flags & AHC_DEV_Q_BASIC) - ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); - break; - } - /* - * Drop down to a single opening, and treat this - * as if the target returned BUSY SCSI status. - */ - dev->openings = 1; - ahc_set_scsi_status(scb, SCSI_STATUS_BUSY); - ahc_platform_set_tags(ahc, sdev, &devinfo, - (dev->flags & AHC_DEV_Q_BASIC) - ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED); - break; - } - } -} - -static void -ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, struct scsi_cmnd *cmd) -{ - /* - * Map CAM error codes into Linux Error codes. We - * avoid the conversion so that the DV code has the - * full error information available when making - * state change decisions. - */ - { - u_int new_status; - - switch (ahc_cmd_get_transaction_status(cmd)) { - case CAM_REQ_INPROG: - case CAM_REQ_CMP: - case CAM_SCSI_STATUS_ERROR: - new_status = DID_OK; - break; - case CAM_REQ_ABORTED: - new_status = DID_ABORT; - break; - case CAM_BUSY: - new_status = DID_BUS_BUSY; - break; - case CAM_REQ_INVALID: - case CAM_PATH_INVALID: - new_status = DID_BAD_TARGET; - break; - case CAM_SEL_TIMEOUT: - new_status = DID_NO_CONNECT; - break; - case CAM_SCSI_BUS_RESET: - case CAM_BDR_SENT: - new_status = DID_RESET; - break; - case CAM_UNCOR_PARITY: - new_status = DID_PARITY; - break; - case CAM_CMD_TIMEOUT: - new_status = DID_TIME_OUT; - break; - case CAM_UA_ABORT: - case CAM_REQ_CMP_ERR: - case CAM_AUTOSENSE_FAIL: - case CAM_NO_HBA: - case CAM_DATA_RUN_ERR: - case CAM_UNEXP_BUSFREE: - case CAM_SEQUENCE_FAIL: - case CAM_CCB_LEN_ERR: - case CAM_PROVIDE_FAIL: - case CAM_REQ_TERMIO: - case CAM_UNREC_HBA_ERROR: - case CAM_REQ_TOO_BIG: - new_status = DID_ERROR; - break; - case CAM_REQUEUE_REQ: - new_status = DID_REQUEUE; - break; - default: - /* We should never get here */ - new_status = DID_ERROR; - break; - } - - ahc_cmd_set_transaction_status(cmd, new_status); - } - - cmd->scsi_done(cmd); -} - -static void -ahc_linux_freeze_simq(struct ahc_softc *ahc) -{ - unsigned long s; - - ahc_lock(ahc, &s); - ahc->platform_data->qfrozen++; - if (ahc->platform_data->qfrozen == 1) { - scsi_block_requests(ahc->platform_data->host); - - /* XXX What about Twin channels? */ - ahc_platform_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS, - CAM_LUN_WILDCARD, SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ); - } - ahc_unlock(ahc, &s); -} - -static void -ahc_linux_release_simq(struct ahc_softc *ahc) -{ - u_long s; - int unblock_reqs; - - unblock_reqs = 0; - ahc_lock(ahc, &s); - if (ahc->platform_data->qfrozen > 0) - ahc->platform_data->qfrozen--; - if (ahc->platform_data->qfrozen == 0) - unblock_reqs = 1; - ahc_unlock(ahc, &s); - /* - * There is still a race here. The mid-layer - * should keep its own freeze count and use - * a bottom half handler to run the queues - * so we can unblock with our own lock held. - */ - if (unblock_reqs) - scsi_unblock_requests(ahc->platform_data->host); -} - -static int -ahc_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) -{ - struct ahc_softc *ahc; - struct ahc_linux_device *dev; - struct scb *pending_scb; - u_int saved_scbptr; - u_int active_scb_index; - u_int last_phase; - u_int saved_scsiid; - u_int cdb_byte; - int retval; - int was_paused; - int paused; - int wait; - int disconnected; - unsigned long flags; - - pending_scb = NULL; - paused = FALSE; - wait = FALSE; - ahc = *(struct ahc_softc **)cmd->device->host->hostdata; - - scmd_printk(KERN_INFO, cmd, "Attempting to queue a%s message\n", - flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); - - printk("CDB:"); - for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printk(" 0x%x", cmd->cmnd[cdb_byte]); - printk("\n"); - - ahc_lock(ahc, &flags); - - /* - * First determine if we currently own this command. - * Start by searching the device queue. If not found - * there, check the pending_scb list. If not found - * at all, and the system wanted us to just abort the - * command, return success. - */ - dev = scsi_transport_device_data(cmd->device); - - if (dev == NULL) { - /* - * No target device for this command exists, - * so we must not still own the command. - */ - printk("%s:%d:%d:%d: Is not an active device\n", - ahc_name(ahc), cmd->device->channel, cmd->device->id, - cmd->device->lun); - retval = SUCCESS; - goto no_cmd; - } - - if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0 - && ahc_search_untagged_queues(ahc, cmd, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, - CAM_REQ_ABORTED, SEARCH_COMPLETE) != 0) { - printk("%s:%d:%d:%d: Command found on untagged queue\n", - ahc_name(ahc), cmd->device->channel, cmd->device->id, - cmd->device->lun); - retval = SUCCESS; - goto done; - } - - /* - * See if we can find a matching cmd in the pending list. - */ - LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { - if (pending_scb->io_ctx == cmd) - break; - } - - if (pending_scb == NULL && flag == SCB_DEVICE_RESET) { - - /* Any SCB for this device will do for a target reset */ - LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) { - if (ahc_match_scb(ahc, pending_scb, scmd_id(cmd), - scmd_channel(cmd) + 'A', - CAM_LUN_WILDCARD, - SCB_LIST_NULL, ROLE_INITIATOR)) - break; - } - } - - if (pending_scb == NULL) { - scmd_printk(KERN_INFO, cmd, "Command not found\n"); - goto no_cmd; - } - - if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { - /* - * We can't queue two recovery actions using the same SCB - */ - retval = FAILED; - goto done; - } - - /* - * Ensure that the card doesn't do anything - * behind our back and that we didn't "just" miss - * an interrupt that would affect this cmd. - */ - was_paused = ahc_is_paused(ahc); - ahc_pause_and_flushwork(ahc); - paused = TRUE; - - if ((pending_scb->flags & SCB_ACTIVE) == 0) { - scmd_printk(KERN_INFO, cmd, "Command already completed\n"); - goto no_cmd; - } - - printk("%s: At time of recovery, card was %spaused\n", - ahc_name(ahc), was_paused ? "" : "not "); - ahc_dump_card_state(ahc); - - disconnected = TRUE; - if (flag == SCB_ABORT) { - if (ahc_search_qinfifo(ahc, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, - pending_scb->hscb->tag, - ROLE_INITIATOR, CAM_REQ_ABORTED, - SEARCH_COMPLETE) > 0) { - printk("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", - ahc_name(ahc), cmd->device->channel, - cmd->device->id, cmd->device->lun); - retval = SUCCESS; - goto done; - } - } else if (ahc_search_qinfifo(ahc, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, pending_scb->hscb->tag, - ROLE_INITIATOR, /*status*/0, - SEARCH_COUNT) > 0) { - disconnected = FALSE; - } - - if (disconnected && (ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) { - struct scb *bus_scb; - - bus_scb = ahc_lookup_scb(ahc, ahc_inb(ahc, SCB_TAG)); - if (bus_scb == pending_scb) - disconnected = FALSE; - else if (flag != SCB_ABORT - && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid - && ahc_inb(ahc, SAVED_LUN) == SCB_GET_LUN(pending_scb)) - disconnected = FALSE; - } - - /* - * At this point, pending_scb is the scb associated with the - * passed in command. That command is currently active on the - * bus, is in the disconnected state, or we're hoping to find - * a command for the same target active on the bus to abuse to - * send a BDR. Queue the appropriate message based on which of - * these states we are in. - */ - last_phase = ahc_inb(ahc, LASTPHASE); - saved_scbptr = ahc_inb(ahc, SCBPTR); - active_scb_index = ahc_inb(ahc, SCB_TAG); - saved_scsiid = ahc_inb(ahc, SAVED_SCSIID); - if (last_phase != P_BUSFREE - && (pending_scb->hscb->tag == active_scb_index - || (flag == SCB_DEVICE_RESET - && SCSIID_TARGET(ahc, saved_scsiid) == scmd_id(cmd)))) { - - /* - * We're active on the bus, so assert ATN - * and hope that the target responds. - */ - pending_scb = ahc_lookup_scb(ahc, active_scb_index); - pending_scb->flags |= SCB_RECOVERY_SCB|flag; - ahc_outb(ahc, MSG_OUT, HOST_MSG); - ahc_outb(ahc, SCSISIGO, last_phase|ATNO); - scmd_printk(KERN_INFO, cmd, "Device is active, asserting ATN\n"); - wait = TRUE; - } else if (disconnected) { - - /* - * Actually re-queue this SCB in an attempt - * to select the device before it reconnects. - * In either case (selection or reselection), - * we will now issue the approprate message - * to the timed-out device. - * - * Set the MK_MESSAGE control bit indicating - * that we desire to send a message. We - * also set the disconnected flag since - * in the paging case there is no guarantee - * that our SCB control byte matches the - * version on the card. We don't want the - * sequencer to abort the command thinking - * an unsolicited reselection occurred. - */ - pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; - pending_scb->flags |= SCB_RECOVERY_SCB|flag; - - /* - * Remove any cached copy of this SCB in the - * disconnected list in preparation for the - * queuing of our abort SCB. We use the - * same element in the SCB, SCB_NEXT, for - * both the qinfifo and the disconnected list. - */ - ahc_search_disc_list(ahc, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, pending_scb->hscb->tag, - /*stop_on_first*/TRUE, - /*remove*/TRUE, - /*save_state*/FALSE); - - /* - * In the non-paging case, the sequencer will - * never re-reference the in-core SCB. - * To make sure we are notified during - * reselection, set the MK_MESSAGE flag in - * the card's copy of the SCB. - */ - if ((ahc->flags & AHC_PAGESCBS) == 0) { - ahc_outb(ahc, SCBPTR, pending_scb->hscb->tag); - ahc_outb(ahc, SCB_CONTROL, - ahc_inb(ahc, SCB_CONTROL)|MK_MESSAGE); - } - - /* - * Clear out any entries in the QINFIFO first - * so we are the next SCB for this target - * to run. - */ - ahc_search_qinfifo(ahc, cmd->device->id, - cmd->device->channel + 'A', - cmd->device->lun, SCB_LIST_NULL, - ROLE_INITIATOR, CAM_REQUEUE_REQ, - SEARCH_COMPLETE); - ahc_qinfifo_requeue_tail(ahc, pending_scb); - ahc_outb(ahc, SCBPTR, saved_scbptr); - ahc_print_path(ahc, pending_scb); - printk("Device is disconnected, re-queuing SCB\n"); - wait = TRUE; - } else { - scmd_printk(KERN_INFO, cmd, "Unable to deliver message\n"); - retval = FAILED; - goto done; - } - -no_cmd: - /* - * Our assumption is that if we don't have the command, no - * recovery action was required, so we return success. Again, - * the semantics of the mid-layer recovery engine are not - * well defined, so this may change in time. - */ - retval = SUCCESS; -done: - if (paused) - ahc_unpause(ahc); - if (wait) { - DECLARE_COMPLETION_ONSTACK(done); - - ahc->platform_data->eh_done = &done; - ahc_unlock(ahc, &flags); - - printk("Recovery code sleeping\n"); - if (!wait_for_completion_timeout(&done, 5 * HZ)) { - ahc_lock(ahc, &flags); - ahc->platform_data->eh_done = NULL; - ahc_unlock(ahc, &flags); - - printk("Timer Expired\n"); - retval = FAILED; - } - printk("Recovery code awake\n"); - } else - ahc_unlock(ahc, &flags); - return (retval); -} - -void -ahc_platform_dump_card_state(struct ahc_softc *ahc) -{ -} - -static void ahc_linux_set_width(struct scsi_target *starget, int width) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); - struct ahc_devinfo devinfo; - unsigned long flags; - - ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - ahc_lock(ahc, &flags); - ahc_set_width(ahc, &devinfo, width, AHC_TRANS_GOAL, FALSE); - ahc_unlock(ahc, &flags); -} - -static void ahc_linux_set_period(struct scsi_target *starget, int period) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); - struct ahc_tmode_tstate *tstate; - struct ahc_initiator_tinfo *tinfo - = ahc_fetch_transinfo(ahc, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahc_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options; - unsigned long flags; - unsigned long offset = tinfo->goal.offset; - const struct ahc_syncrate *syncrate; - - if (offset == 0) - offset = MAX_OFFSET; - - if (period < 9) - period = 9; /* 12.5ns is our minimum */ - if (period == 9) { - if (spi_max_width(starget)) - ppr_options |= MSG_EXT_PPR_DT_REQ; - else - /* need wide for DT and need DT for 12.5 ns */ - period = 10; - } - - ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - - /* all PPR requests apart from QAS require wide transfers */ - if (ppr_options & ~MSG_EXT_PPR_QAS_REQ) { - if (spi_width(starget) == 0) - ppr_options &= MSG_EXT_PPR_QAS_REQ; - } - - syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT); - ahc_lock(ahc, &flags); - ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset, - ppr_options, AHC_TRANS_GOAL, FALSE); - ahc_unlock(ahc, &flags); -} - -static void ahc_linux_set_offset(struct scsi_target *starget, int offset) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); - struct ahc_tmode_tstate *tstate; - struct ahc_initiator_tinfo *tinfo - = ahc_fetch_transinfo(ahc, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahc_devinfo devinfo; - unsigned int ppr_options = 0; - unsigned int period = 0; - unsigned long flags; - const struct ahc_syncrate *syncrate = NULL; - - ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - if (offset != 0) { - syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT); - period = tinfo->goal.period; - ppr_options = tinfo->goal.ppr_options; - } - ahc_lock(ahc, &flags); - ahc_set_syncrate(ahc, &devinfo, syncrate, period, offset, - ppr_options, AHC_TRANS_GOAL, FALSE); - ahc_unlock(ahc, &flags); -} - -static void ahc_linux_set_dt(struct scsi_target *starget, int dt) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); - struct ahc_tmode_tstate *tstate; - struct ahc_initiator_tinfo *tinfo - = ahc_fetch_transinfo(ahc, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahc_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_DT_REQ; - unsigned int period = tinfo->goal.period; - unsigned int width = tinfo->goal.width; - unsigned long flags; - const struct ahc_syncrate *syncrate; - - if (dt && spi_max_width(starget)) { - ppr_options |= MSG_EXT_PPR_DT_REQ; - if (!width) - ahc_linux_set_width(starget, 1); - } else if (period == 9) - period = 10; /* if resetting DT, period must be >= 25ns */ - - ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,AHC_SYNCRATE_DT); - ahc_lock(ahc, &flags); - ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->goal.offset, - ppr_options, AHC_TRANS_GOAL, FALSE); - ahc_unlock(ahc, &flags); -} - -#if 0 -/* FIXME: This code claims to support IU and QAS. However, the actual - * sequencer code and aic7xxx_core have no support for these parameters and - * will get into a bad state if they're negotiated. Do not enable this - * unless you know what you're doing */ -static void ahc_linux_set_qas(struct scsi_target *starget, int qas) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); - struct ahc_tmode_tstate *tstate; - struct ahc_initiator_tinfo *tinfo - = ahc_fetch_transinfo(ahc, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahc_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_QAS_REQ; - unsigned int period = tinfo->goal.period; - unsigned long flags; - struct ahc_syncrate *syncrate; - - if (qas) - ppr_options |= MSG_EXT_PPR_QAS_REQ; - - ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT); - ahc_lock(ahc, &flags); - ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->goal.offset, - ppr_options, AHC_TRANS_GOAL, FALSE); - ahc_unlock(ahc, &flags); -} - -static void ahc_linux_set_iu(struct scsi_target *starget, int iu) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ahc_softc *ahc = *((struct ahc_softc **)shost->hostdata); - struct ahc_tmode_tstate *tstate; - struct ahc_initiator_tinfo *tinfo - = ahc_fetch_transinfo(ahc, - starget->channel + 'A', - shost->this_id, starget->id, &tstate); - struct ahc_devinfo devinfo; - unsigned int ppr_options = tinfo->goal.ppr_options - & ~MSG_EXT_PPR_IU_REQ; - unsigned int period = tinfo->goal.period; - unsigned long flags; - struct ahc_syncrate *syncrate; - - if (iu) - ppr_options |= MSG_EXT_PPR_IU_REQ; - - ahc_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, - starget->channel + 'A', ROLE_INITIATOR); - syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, AHC_SYNCRATE_DT); - ahc_lock(ahc, &flags); - ahc_set_syncrate(ahc, &devinfo, syncrate, period, tinfo->goal.offset, - ppr_options, AHC_TRANS_GOAL, FALSE); - ahc_unlock(ahc, &flags); -} -#endif - -static void ahc_linux_get_signalling(struct Scsi_Host *shost) -{ - struct ahc_softc *ahc = *(struct ahc_softc **)shost->hostdata; - unsigned long flags; - u8 mode; - - if (!(ahc->features & AHC_ULTRA2)) { - /* non-LVD chipset, may not have SBLKCTL reg */ - spi_signalling(shost) = - ahc->features & AHC_HVD ? - SPI_SIGNAL_HVD : - SPI_SIGNAL_SE; - return; - } - - ahc_lock(ahc, &flags); - ahc_pause(ahc); - mode = ahc_inb(ahc, SBLKCTL); - ahc_unpause(ahc); - ahc_unlock(ahc, &flags); - - if (mode & ENAB40) - spi_signalling(shost) = SPI_SIGNAL_LVD; - else if (mode & ENAB20) - spi_signalling(shost) = SPI_SIGNAL_SE; - else - spi_signalling(shost) = SPI_SIGNAL_UNKNOWN; -} - -static struct spi_function_template ahc_linux_transport_functions = { - .set_offset = ahc_linux_set_offset, - .show_offset = 1, - .set_period = ahc_linux_set_period, - .show_period = 1, - .set_width = ahc_linux_set_width, - .show_width = 1, - .set_dt = ahc_linux_set_dt, - .show_dt = 1, -#if 0 - .set_iu = ahc_linux_set_iu, - .show_iu = 1, - .set_qas = ahc_linux_set_qas, - .show_qas = 1, -#endif - .get_signalling = ahc_linux_get_signalling, -}; - - - -static int __init -ahc_linux_init(void) -{ - /* - * If we've been passed any parameters, process them now. - */ - if (aic7xxx) - aic7xxx_setup(aic7xxx); - - ahc_linux_transport_template = - spi_attach_transport(&ahc_linux_transport_functions); - if (!ahc_linux_transport_template) - return -ENODEV; - - scsi_transport_reserve_device(ahc_linux_transport_template, - sizeof(struct ahc_linux_device)); - - ahc_linux_pci_init(); - ahc_linux_eisa_init(); - return 0; -} - -static void -ahc_linux_exit(void) -{ - ahc_linux_pci_exit(); - ahc_linux_eisa_exit(); - spi_release_transport(ahc_linux_transport_template); -} - -module_init(ahc_linux_init); -module_exit(ahc_linux_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.h deleted file mode 100644 index bca0fb83..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ /dev/null @@ -1,713 +0,0 @@ -/* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Copyright (c) 2000-2003 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#151 $ - * - */ -#ifndef _AIC7XXX_LINUX_H_ -#define _AIC7XXX_LINUX_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Core SCSI definitions */ -#define AIC_LIB_PREFIX ahc - -/* Name space conflict with BSD queue macros */ -#ifdef LIST_HEAD -#undef LIST_HEAD -#endif - -#include "cam.h" -#include "queue.h" -#include "scsi_message.h" -#include "aiclib.h" - -/*********************************** Debugging ********************************/ -#ifdef CONFIG_AIC7XXX_DEBUG_ENABLE -#ifdef CONFIG_AIC7XXX_DEBUG_MASK -#define AHC_DEBUG 1 -#define AHC_DEBUG_OPTS CONFIG_AIC7XXX_DEBUG_MASK -#else -/* - * Compile in debugging code, but do not enable any printfs. - */ -#define AHC_DEBUG 1 -#endif -/* No debugging code. */ -#endif - -/************************* Forward Declarations *******************************/ -struct ahc_softc; -typedef struct pci_dev *ahc_dev_softc_t; -typedef struct scsi_cmnd *ahc_io_ctx_t; - -/******************************* Byte Order ***********************************/ -#define ahc_htobe16(x) cpu_to_be16(x) -#define ahc_htobe32(x) cpu_to_be32(x) -#define ahc_htobe64(x) cpu_to_be64(x) -#define ahc_htole16(x) cpu_to_le16(x) -#define ahc_htole32(x) cpu_to_le32(x) -#define ahc_htole64(x) cpu_to_le64(x) - -#define ahc_be16toh(x) be16_to_cpu(x) -#define ahc_be32toh(x) be32_to_cpu(x) -#define ahc_be64toh(x) be64_to_cpu(x) -#define ahc_le16toh(x) le16_to_cpu(x) -#define ahc_le32toh(x) le32_to_cpu(x) -#define ahc_le64toh(x) le64_to_cpu(x) - -/************************* Configuration Data *********************************/ -extern u_int aic7xxx_no_probe; -extern u_int aic7xxx_allow_memio; -extern struct scsi_host_template aic7xxx_driver_template; - -/***************************** Bus Space/DMA **********************************/ - -typedef uint32_t bus_size_t; - -typedef enum { - BUS_SPACE_MEMIO, - BUS_SPACE_PIO -} bus_space_tag_t; - -typedef union { - u_long ioport; - volatile uint8_t __iomem *maddr; -} bus_space_handle_t; - -typedef struct bus_dma_segment -{ - dma_addr_t ds_addr; - bus_size_t ds_len; -} bus_dma_segment_t; - -struct ahc_linux_dma_tag -{ - bus_size_t alignment; - bus_size_t boundary; - bus_size_t maxsize; -}; -typedef struct ahc_linux_dma_tag* bus_dma_tag_t; - -typedef dma_addr_t bus_dmamap_t; - -typedef int bus_dma_filter_t(void*, dma_addr_t); -typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); - -#define BUS_DMA_WAITOK 0x0 -#define BUS_DMA_NOWAIT 0x1 -#define BUS_DMA_ALLOCNOW 0x2 -#define BUS_DMA_LOAD_SEGS 0x4 /* - * Argument is an S/G list not - * a single buffer. - */ - -#define BUS_SPACE_MAXADDR 0xFFFFFFFF -#define BUS_SPACE_MAXADDR_32BIT 0xFFFFFFFF -#define BUS_SPACE_MAXSIZE_32BIT 0xFFFFFFFF - -int ahc_dma_tag_create(struct ahc_softc *, bus_dma_tag_t /*parent*/, - bus_size_t /*alignment*/, bus_size_t /*boundary*/, - dma_addr_t /*lowaddr*/, dma_addr_t /*highaddr*/, - bus_dma_filter_t*/*filter*/, void */*filterarg*/, - bus_size_t /*maxsize*/, int /*nsegments*/, - bus_size_t /*maxsegsz*/, int /*flags*/, - bus_dma_tag_t */*dma_tagp*/); - -void ahc_dma_tag_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/); - -int ahc_dmamem_alloc(struct ahc_softc *, bus_dma_tag_t /*dmat*/, - void** /*vaddr*/, int /*flags*/, - bus_dmamap_t* /*mapp*/); - -void ahc_dmamem_free(struct ahc_softc *, bus_dma_tag_t /*dmat*/, - void* /*vaddr*/, bus_dmamap_t /*map*/); - -void ahc_dmamap_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/, - bus_dmamap_t /*map*/); - -int ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t /*dmat*/, - bus_dmamap_t /*map*/, void * /*buf*/, - bus_size_t /*buflen*/, bus_dmamap_callback_t *, - void */*callback_arg*/, int /*flags*/); - -int ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t); - -/* - * Operations performed by ahc_dmamap_sync(). - */ -#define BUS_DMASYNC_PREREAD 0x01 /* pre-read synchronization */ -#define BUS_DMASYNC_POSTREAD 0x02 /* post-read synchronization */ -#define BUS_DMASYNC_PREWRITE 0x04 /* pre-write synchronization */ -#define BUS_DMASYNC_POSTWRITE 0x08 /* post-write synchronization */ - -/* - * XXX - * ahc_dmamap_sync is only used on buffers allocated with - * the pci_alloc_consistent() API. Although I'm not sure how - * this works on architectures with a write buffer, Linux does - * not have an API to sync "coherent" memory. Perhaps we need - * to do an mb()? - */ -#define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op) - -/********************************** Includes **********************************/ -#ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT -#define AIC_DEBUG_REGISTERS 1 -#else -#define AIC_DEBUG_REGISTERS 0 -#endif -#include "aic7xxx.h" - -/***************************** Timer Facilities *******************************/ -static inline void -ahc_scb_timer_reset(struct scb *scb, u_int usec) -{ -} - -/***************************** SMP support ************************************/ -#include - -#define AIC7XXX_DRIVER_VERSION "7.0" - -/*************************** Device Data Structures ***************************/ -/* - * A per probed device structure used to deal with some error recovery - * scenarios that the Linux mid-layer code just doesn't know how to - * handle. The structure allocated for a device only becomes persistent - * after a successfully completed inquiry command to the target when - * that inquiry data indicates a lun is present. - */ -typedef enum { - AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ - AHC_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ - AHC_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ - AHC_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ -} ahc_linux_dev_flags; - -struct ahc_linux_device { - /* - * The number of transactions currently - * queued to the device. - */ - int active; - - /* - * The currently allowed number of - * transactions that can be queued to - * the device. Must be signed for - * conversion from tagged to untagged - * mode where the device may have more - * than one outstanding active transaction. - */ - int openings; - - /* - * A positive count indicates that this - * device's queue is halted. - */ - u_int qfrozen; - - /* - * Cumulative command counter. - */ - u_long commands_issued; - - /* - * The number of tagged transactions when - * running at our current opening level - * that have been successfully received by - * this device since the last QUEUE FULL. - */ - u_int tag_success_count; -#define AHC_TAG_SUCCESS_INTERVAL 50 - - ahc_linux_dev_flags flags; - - /* - * The high limit for the tags variable. - */ - u_int maxtags; - - /* - * The computed number of tags outstanding - * at the time of the last QUEUE FULL event. - */ - u_int tags_on_last_queuefull; - - /* - * How many times we have seen a queue full - * with the same number of tags. This is used - * to stop our adaptive queue depth algorithm - * on devices with a fixed number of tags. - */ - u_int last_queuefull_same_count; -#define AHC_LOCK_TAGS_COUNT 50 - - /* - * How many transactions have been queued - * without the device going idle. We use - * this statistic to determine when to issue - * an ordered tag to prevent transaction - * starvation. This statistic is only updated - * if the AHC_DEV_PERIODIC_OTAG flag is set - * on this device. - */ - u_int commands_since_idle_or_otag; -#define AHC_OTAG_THRESH 500 -}; - -/********************* Definitions Required by the Core ***********************/ -/* - * Number of SG segments we require. So long as the S/G segments for - * a particular transaction are allocated in a physically contiguous - * manner and are allocated below 4GB, the number of S/G segments is - * unrestricted. - */ -#define AHC_NSEG 128 - -/* - * Per-SCB OSM storage. - */ -struct scb_platform_data { - struct ahc_linux_device *dev; - dma_addr_t buf_busaddr; - uint32_t xfer_len; - uint32_t sense_resid; /* Auto-Sense residual */ -}; - -/* - * Define a structure used for each host adapter. All members are - * aligned on a boundary >= the size of the member to honor the - * alignment restrictions of the various platforms supported by - * this driver. - */ -struct ahc_platform_data { - /* - * Fields accessed from interrupt context. - */ - struct scsi_target *starget[AHC_NUM_TARGETS]; - - spinlock_t spin_lock; - u_int qfrozen; - struct completion *eh_done; - struct Scsi_Host *host; /* pointer to scsi host */ -#define AHC_LINUX_NOIRQ ((uint32_t)~0) - uint32_t irq; /* IRQ for this adapter */ - uint32_t bios_address; - resource_size_t mem_busaddr; /* Mem Base Addr */ -}; - -void ahc_delay(long); - - -/***************************** Low Level I/O **********************************/ -uint8_t ahc_inb(struct ahc_softc * ahc, long port); -void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val); -void ahc_outsb(struct ahc_softc * ahc, long port, - uint8_t *, int count); -void ahc_insb(struct ahc_softc * ahc, long port, - uint8_t *, int count); - -/**************************** Initialization **********************************/ -int ahc_linux_register_host(struct ahc_softc *, - struct scsi_host_template *); - -/*************************** Pretty Printing **********************************/ -struct info_str { - char *buffer; - int length; - off_t offset; - int pos; -}; - -/******************************** Locking *************************************/ -/* Lock protecting internal data structures */ - -static inline void -ahc_lockinit(struct ahc_softc *ahc) -{ - spin_lock_init(&ahc->platform_data->spin_lock); -} - -static inline void -ahc_lock(struct ahc_softc *ahc, unsigned long *flags) -{ - spin_lock_irqsave(&ahc->platform_data->spin_lock, *flags); -} - -static inline void -ahc_unlock(struct ahc_softc *ahc, unsigned long *flags) -{ - spin_unlock_irqrestore(&ahc->platform_data->spin_lock, *flags); -} - -/******************************* PCI Definitions ******************************/ -/* - * PCIM_xxx: mask to locate subfield in register - * PCIR_xxx: config register offset - * PCIC_xxx: device class - * PCIS_xxx: device subclass - * PCIP_xxx: device programming interface - * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices) - * PCID_xxx: device ID - */ -#define PCIR_DEVVENDOR 0x00 -#define PCIR_VENDOR 0x00 -#define PCIR_DEVICE 0x02 -#define PCIR_COMMAND 0x04 -#define PCIM_CMD_PORTEN 0x0001 -#define PCIM_CMD_MEMEN 0x0002 -#define PCIM_CMD_BUSMASTEREN 0x0004 -#define PCIM_CMD_MWRICEN 0x0010 -#define PCIM_CMD_PERRESPEN 0x0040 -#define PCIM_CMD_SERRESPEN 0x0100 -#define PCIR_STATUS 0x06 -#define PCIR_REVID 0x08 -#define PCIR_PROGIF 0x09 -#define PCIR_SUBCLASS 0x0a -#define PCIR_CLASS 0x0b -#define PCIR_CACHELNSZ 0x0c -#define PCIR_LATTIMER 0x0d -#define PCIR_HEADERTYPE 0x0e -#define PCIM_MFDEV 0x80 -#define PCIR_BIST 0x0f -#define PCIR_CAP_PTR 0x34 - -/* config registers for header type 0 devices */ -#define PCIR_MAPS 0x10 -#define PCIR_SUBVEND_0 0x2c -#define PCIR_SUBDEV_0 0x2e - -typedef enum -{ - AHC_POWER_STATE_D0, - AHC_POWER_STATE_D1, - AHC_POWER_STATE_D2, - AHC_POWER_STATE_D3 -} ahc_power_state; - -/**************************** VL/EISA Routines ********************************/ -#ifdef CONFIG_EISA -int ahc_linux_eisa_init(void); -void ahc_linux_eisa_exit(void); -int aic7770_map_registers(struct ahc_softc *ahc, - u_int port); -int aic7770_map_int(struct ahc_softc *ahc, u_int irq); -#else -static inline int ahc_linux_eisa_init(void) { - return -ENODEV; -} -static inline void ahc_linux_eisa_exit(void) { -} -#endif - -/******************************* PCI Routines *********************************/ -#ifdef CONFIG_PCI -int ahc_linux_pci_init(void); -void ahc_linux_pci_exit(void); -int ahc_pci_map_registers(struct ahc_softc *ahc); -int ahc_pci_map_int(struct ahc_softc *ahc); - -uint32_t ahc_pci_read_config(ahc_dev_softc_t pci, - int reg, int width); - -void ahc_pci_write_config(ahc_dev_softc_t pci, - int reg, uint32_t value, - int width); - -static inline int ahc_get_pci_function(ahc_dev_softc_t); -static inline int -ahc_get_pci_function(ahc_dev_softc_t pci) -{ - return (PCI_FUNC(pci->devfn)); -} - -static inline int ahc_get_pci_slot(ahc_dev_softc_t); -static inline int -ahc_get_pci_slot(ahc_dev_softc_t pci) -{ - return (PCI_SLOT(pci->devfn)); -} - -static inline int ahc_get_pci_bus(ahc_dev_softc_t); -static inline int -ahc_get_pci_bus(ahc_dev_softc_t pci) -{ - return (pci->bus->number); -} -#else -static inline int ahc_linux_pci_init(void) { - return 0; -} -static inline void ahc_linux_pci_exit(void) { -} -#endif - -static inline void ahc_flush_device_writes(struct ahc_softc *); -static inline void -ahc_flush_device_writes(struct ahc_softc *ahc) -{ - /* XXX Is this sufficient for all architectures??? */ - ahc_inb(ahc, INTSTAT); -} - -/**************************** Proc FS Support *********************************/ -int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, - off_t, int, int); - -/*************************** Domain Validation ********************************/ -/*********************** Transaction Access Wrappers *************************/ -static inline void ahc_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); -static inline void ahc_set_transaction_status(struct scb *, uint32_t); -static inline void ahc_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); -static inline void ahc_set_scsi_status(struct scb *, uint32_t); -static inline uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd); -static inline uint32_t ahc_get_transaction_status(struct scb *); -static inline uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd); -static inline uint32_t ahc_get_scsi_status(struct scb *); -static inline void ahc_set_transaction_tag(struct scb *, int, u_int); -static inline u_long ahc_get_transfer_length(struct scb *); -static inline int ahc_get_transfer_dir(struct scb *); -static inline void ahc_set_residual(struct scb *, u_long); -static inline void ahc_set_sense_residual(struct scb *scb, u_long resid); -static inline u_long ahc_get_residual(struct scb *); -static inline u_long ahc_get_sense_residual(struct scb *); -static inline int ahc_perform_autosense(struct scb *); -static inline uint32_t ahc_get_sense_bufsize(struct ahc_softc *, - struct scb *); -static inline void ahc_notify_xfer_settings_change(struct ahc_softc *, - struct ahc_devinfo *); -static inline void ahc_platform_scb_free(struct ahc_softc *ahc, - struct scb *scb); -static inline void ahc_freeze_scb(struct scb *scb); - -static inline -void ahc_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) -{ - cmd->result &= ~(CAM_STATUS_MASK << 16); - cmd->result |= status << 16; -} - -static inline -void ahc_set_transaction_status(struct scb *scb, uint32_t status) -{ - ahc_cmd_set_transaction_status(scb->io_ctx,status); -} - -static inline -void ahc_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) -{ - cmd->result &= ~0xFFFF; - cmd->result |= status; -} - -static inline -void ahc_set_scsi_status(struct scb *scb, uint32_t status) -{ - ahc_cmd_set_scsi_status(scb->io_ctx, status); -} - -static inline -uint32_t ahc_cmd_get_transaction_status(struct scsi_cmnd *cmd) -{ - return ((cmd->result >> 16) & CAM_STATUS_MASK); -} - -static inline -uint32_t ahc_get_transaction_status(struct scb *scb) -{ - return (ahc_cmd_get_transaction_status(scb->io_ctx)); -} - -static inline -uint32_t ahc_cmd_get_scsi_status(struct scsi_cmnd *cmd) -{ - return (cmd->result & 0xFFFF); -} - -static inline -uint32_t ahc_get_scsi_status(struct scb *scb) -{ - return (ahc_cmd_get_scsi_status(scb->io_ctx)); -} - -static inline -void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type) -{ - /* - * Nothing to do for linux as the incoming transaction - * has no concept of tag/non tagged, etc. - */ -} - -static inline -u_long ahc_get_transfer_length(struct scb *scb) -{ - return (scb->platform_data->xfer_len); -} - -static inline -int ahc_get_transfer_dir(struct scb *scb) -{ - return (scb->io_ctx->sc_data_direction); -} - -static inline -void ahc_set_residual(struct scb *scb, u_long resid) -{ - scsi_set_resid(scb->io_ctx, resid); -} - -static inline -void ahc_set_sense_residual(struct scb *scb, u_long resid) -{ - scb->platform_data->sense_resid = resid; -} - -static inline -u_long ahc_get_residual(struct scb *scb) -{ - return scsi_get_resid(scb->io_ctx); -} - -static inline -u_long ahc_get_sense_residual(struct scb *scb) -{ - return (scb->platform_data->sense_resid); -} - -static inline -int ahc_perform_autosense(struct scb *scb) -{ - /* - * We always perform autosense in Linux. - * On other platforms this is set on a - * per-transaction basis. - */ - return (1); -} - -static inline uint32_t -ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb) -{ - return (sizeof(struct scsi_sense_data)); -} - -static inline void -ahc_notify_xfer_settings_change(struct ahc_softc *ahc, - struct ahc_devinfo *devinfo) -{ - /* Nothing to do here for linux */ -} - -static inline void -ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb) -{ -} - -int ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg); -void ahc_platform_free(struct ahc_softc *ahc); -void ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb); - -static inline void -ahc_freeze_scb(struct scb *scb) -{ - if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) { - scb->io_ctx->result |= CAM_DEV_QFRZN << 16; - scb->platform_data->dev->qfrozen++; - } -} - -void ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev, - struct ahc_devinfo *devinfo, ahc_queue_alg); -int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, - char channel, int lun, u_int tag, - role_t role, uint32_t status); -irqreturn_t - ahc_linux_isr(int irq, void *dev_id); -void ahc_platform_flushwork(struct ahc_softc *ahc); -void ahc_done(struct ahc_softc*, struct scb*); -void ahc_send_async(struct ahc_softc *, char channel, - u_int target, u_int lun, ac_code); -void ahc_print_path(struct ahc_softc *, struct scb *); -void ahc_platform_dump_card_state(struct ahc_softc *ahc); - -#ifdef CONFIG_PCI -#define AHC_PCI_CONFIG 1 -#else -#define AHC_PCI_CONFIG 0 -#endif -#define bootverbose aic7xxx_verbose -extern u_int aic7xxx_verbose; -#endif /* _AIC7XXX_LINUX_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c deleted file mode 100644 index ee05e841..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Linux driver attachment glue for PCI based controllers. - * - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#47 $ - */ - -#include "aic7xxx_osm.h" -#include "aic7xxx_pci.h" - -/* Define the macro locally since it's different for different class of chips. -*/ -#define ID(x) ID_C(x, PCI_CLASS_STORAGE_SCSI) - -static const struct pci_device_id ahc_linux_pci_id_table[] = { - /* aic7850 based controllers */ - ID(ID_AHA_2902_04_10_15_20C_30C), - /* aic7860 based controllers */ - ID(ID_AHA_2930CU), - ID(ID_AHA_1480A & ID_DEV_VENDOR_MASK), - ID(ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK), - ID(ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK), - ID(ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK), - /* aic7870 based controllers */ - ID(ID_AHA_2940), - ID(ID_AHA_3940), - ID(ID_AHA_398X), - ID(ID_AHA_2944), - ID(ID_AHA_3944), - ID(ID_AHA_4944), - /* aic7880 based controllers */ - ID(ID_AHA_2940U & ID_DEV_VENDOR_MASK), - ID(ID_AHA_3940U & ID_DEV_VENDOR_MASK), - ID(ID_AHA_2944U & ID_DEV_VENDOR_MASK), - ID(ID_AHA_3944U & ID_DEV_VENDOR_MASK), - ID(ID_AHA_398XU & ID_DEV_VENDOR_MASK), - ID(ID_AHA_4944U & ID_DEV_VENDOR_MASK), - ID(ID_AHA_2930U & ID_DEV_VENDOR_MASK), - ID(ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK), - ID(ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK), - /* aic7890 based controllers */ - ID(ID_AHA_2930U2), - ID(ID_AHA_2940U2B), - ID(ID_AHA_2940U2_OEM), - ID(ID_AHA_2940U2), - ID(ID_AHA_2950U2B), - ID16(ID_AIC7890_ARO & ID_AIC7895_ARO_MASK), - ID(ID_AAA_131U2), - /* aic7890 based controllers */ - ID(ID_AHA_29160), - ID(ID_AHA_29160_CPQ), - ID(ID_AHA_29160N), - ID(ID_AHA_29160C), - ID(ID_AHA_29160B), - ID(ID_AHA_19160B), - ID(ID_AIC7892_ARO), - /* aic7892 based controllers */ - ID(ID_AHA_2940U_DUAL), - ID(ID_AHA_3940AU), - ID(ID_AHA_3944AU), - ID(ID_AIC7895_ARO), - ID(ID_AHA_3950U2B_0), - ID(ID_AHA_3950U2B_1), - ID(ID_AHA_3950U2D_0), - ID(ID_AHA_3950U2D_1), - ID(ID_AIC7896_ARO), - /* aic7899 based controllers */ - ID(ID_AHA_3960D), - ID(ID_AHA_3960D_CPQ), - ID(ID_AIC7899_ARO), - /* Generic chip probes for devices we don't know exactly. */ - ID(ID_AIC7850 & ID_DEV_VENDOR_MASK), - ID(ID_AIC7855 & ID_DEV_VENDOR_MASK), - ID(ID_AIC7859 & ID_DEV_VENDOR_MASK), - ID(ID_AIC7860 & ID_DEV_VENDOR_MASK), - ID(ID_AIC7870 & ID_DEV_VENDOR_MASK), - ID(ID_AIC7880 & ID_DEV_VENDOR_MASK), - ID16(ID_AIC7890 & ID_9005_GENERIC_MASK), - ID16(ID_AIC7892 & ID_9005_GENERIC_MASK), - ID(ID_AIC7895 & ID_DEV_VENDOR_MASK), - ID16(ID_AIC7896 & ID_9005_GENERIC_MASK), - ID16(ID_AIC7899 & ID_9005_GENERIC_MASK), - ID(ID_AIC7810 & ID_DEV_VENDOR_MASK), - ID(ID_AIC7815 & ID_DEV_VENDOR_MASK), - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table); - -#ifdef CONFIG_PM -static int -ahc_linux_pci_dev_suspend(struct pci_dev *pdev, pm_message_t mesg) -{ - struct ahc_softc *ahc = pci_get_drvdata(pdev); - int rc; - - if ((rc = ahc_suspend(ahc))) - return rc; - - pci_save_state(pdev); - pci_disable_device(pdev); - - if (mesg.event & PM_EVENT_SLEEP) - pci_set_power_state(pdev, PCI_D3hot); - - return rc; -} - -static int -ahc_linux_pci_dev_resume(struct pci_dev *pdev) -{ - struct ahc_softc *ahc = pci_get_drvdata(pdev); - int rc; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - if ((rc = pci_enable_device(pdev))) { - dev_printk(KERN_ERR, &pdev->dev, - "failed to enable device after resume (%d)\n", rc); - return rc; - } - - pci_set_master(pdev); - - ahc_pci_resume(ahc); - - return (ahc_resume(ahc)); -} -#endif - -static void -ahc_linux_pci_dev_remove(struct pci_dev *pdev) -{ - struct ahc_softc *ahc = pci_get_drvdata(pdev); - u_long s; - - if (ahc->platform_data && ahc->platform_data->host) - scsi_remove_host(ahc->platform_data->host); - - ahc_lock(ahc, &s); - ahc_intr_enable(ahc, FALSE); - ahc_unlock(ahc, &s); - ahc_free(ahc); -} - -static void -ahc_linux_pci_inherit_flags(struct ahc_softc *ahc) -{ - struct pci_dev *pdev = ahc->dev_softc, *master_pdev; - unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); - - master_pdev = pci_get_slot(pdev->bus, master_devfn); - if (master_pdev) { - struct ahc_softc *master = pci_get_drvdata(master_pdev); - if (master) { - ahc->flags &= ~AHC_BIOS_ENABLED; - ahc->flags |= master->flags & AHC_BIOS_ENABLED; - - ahc->flags &= ~AHC_PRIMARY_CHANNEL; - ahc->flags |= master->flags & AHC_PRIMARY_CHANNEL; - } else - printk(KERN_ERR "aic7xxx: no multichannel peer found!\n"); - pci_dev_put(master_pdev); - } -} - -static int -ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - char buf[80]; - const uint64_t mask_39bit = 0x7FFFFFFFFFULL; - struct ahc_softc *ahc; - ahc_dev_softc_t pci; - const struct ahc_pci_identity *entry; - char *name; - int error; - struct device *dev = &pdev->dev; - - pci = pdev; - entry = ahc_find_pci_device(pci); - if (entry == NULL) - return (-ENODEV); - - /* - * Allocate a softc for this card and - * set it up for attachment by our - * common detect routine. - */ - sprintf(buf, "ahc_pci:%d:%d:%d", - ahc_get_pci_bus(pci), - ahc_get_pci_slot(pci), - ahc_get_pci_function(pci)); - name = kmalloc(strlen(buf) + 1, GFP_ATOMIC); - if (name == NULL) - return (-ENOMEM); - strcpy(name, buf); - ahc = ahc_alloc(NULL, name); - if (ahc == NULL) - return (-ENOMEM); - if (pci_enable_device(pdev)) { - ahc_free(ahc); - return (-ENODEV); - } - pci_set_master(pdev); - - if (sizeof(dma_addr_t) > 4 - && ahc->features & AHC_LARGE_SCBS - && dma_set_mask(dev, mask_39bit) == 0 - && dma_get_required_mask(dev) > DMA_BIT_MASK(32)) { - ahc->flags |= AHC_39BIT_ADDRESSING; - } else { - if (dma_set_mask(dev, DMA_BIT_MASK(32))) { - ahc_free(ahc); - printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n"); - return (-ENODEV); - } - } - ahc->dev_softc = pci; - error = ahc_pci_config(ahc, entry); - if (error != 0) { - ahc_free(ahc); - return (-error); - } - - /* - * Second Function PCI devices need to inherit some - * settings from function 0. - */ - if ((ahc->features & AHC_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0) - ahc_linux_pci_inherit_flags(ahc); - - pci_set_drvdata(pdev, ahc); - ahc_linux_register_host(ahc, &aic7xxx_driver_template); - return (0); -} - -/******************************* PCI Routines *********************************/ -uint32_t -ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width) -{ - switch (width) { - case 1: - { - uint8_t retval; - - pci_read_config_byte(pci, reg, &retval); - return (retval); - } - case 2: - { - uint16_t retval; - pci_read_config_word(pci, reg, &retval); - return (retval); - } - case 4: - { - uint32_t retval; - pci_read_config_dword(pci, reg, &retval); - return (retval); - } - default: - panic("ahc_pci_read_config: Read size too big"); - /* NOTREACHED */ - return (0); - } -} - -void -ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width) -{ - switch (width) { - case 1: - pci_write_config_byte(pci, reg, value); - break; - case 2: - pci_write_config_word(pci, reg, value); - break; - case 4: - pci_write_config_dword(pci, reg, value); - break; - default: - panic("ahc_pci_write_config: Write size too big"); - /* NOTREACHED */ - } -} - - -static struct pci_driver aic7xxx_pci_driver = { - .name = "aic7xxx", - .probe = ahc_linux_pci_dev_probe, -#ifdef CONFIG_PM - .suspend = ahc_linux_pci_dev_suspend, - .resume = ahc_linux_pci_dev_resume, -#endif - .remove = ahc_linux_pci_dev_remove, - .id_table = ahc_linux_pci_id_table -}; - -int -ahc_linux_pci_init(void) -{ - return pci_register_driver(&aic7xxx_pci_driver); -} - -void -ahc_linux_pci_exit(void) -{ - pci_unregister_driver(&aic7xxx_pci_driver); -} - -static int -ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, resource_size_t *base) -{ - if (aic7xxx_allow_memio == 0) - return (ENOMEM); - - *base = pci_resource_start(ahc->dev_softc, 0); - if (*base == 0) - return (ENOMEM); - if (!request_region(*base, 256, "aic7xxx")) - return (ENOMEM); - return (0); -} - -static int -ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc, - resource_size_t *bus_addr, - uint8_t __iomem **maddr) -{ - resource_size_t start; - int error; - - error = 0; - start = pci_resource_start(ahc->dev_softc, 1); - if (start != 0) { - *bus_addr = start; - if (!request_mem_region(start, 0x1000, "aic7xxx")) - error = ENOMEM; - if (error == 0) { - *maddr = ioremap_nocache(start, 256); - if (*maddr == NULL) { - error = ENOMEM; - release_mem_region(start, 0x1000); - } - } - } else - error = ENOMEM; - return (error); -} - -int -ahc_pci_map_registers(struct ahc_softc *ahc) -{ - uint32_t command; - resource_size_t base; - uint8_t __iomem *maddr; - int error; - - /* - * If its allowed, we prefer memory mapped access. - */ - command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4); - command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN); - base = 0; - maddr = NULL; - error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr); - if (error == 0) { - ahc->platform_data->mem_busaddr = base; - ahc->tag = BUS_SPACE_MEMIO; - ahc->bsh.maddr = maddr; - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, - command | PCIM_CMD_MEMEN, 4); - - /* - * Do a quick test to see if memory mapped - * I/O is functioning correctly. - */ - if (ahc_pci_test_register_access(ahc) != 0) { - - printk("aic7xxx: PCI Device %d:%d:%d " - "failed memory mapped test. Using PIO.\n", - ahc_get_pci_bus(ahc->dev_softc), - ahc_get_pci_slot(ahc->dev_softc), - ahc_get_pci_function(ahc->dev_softc)); - iounmap(maddr); - release_mem_region(ahc->platform_data->mem_busaddr, - 0x1000); - ahc->bsh.maddr = NULL; - maddr = NULL; - } else - command |= PCIM_CMD_MEMEN; - } else { - printk("aic7xxx: PCI%d:%d:%d MEM region 0x%llx " - "unavailable. Cannot memory map device.\n", - ahc_get_pci_bus(ahc->dev_softc), - ahc_get_pci_slot(ahc->dev_softc), - ahc_get_pci_function(ahc->dev_softc), - (unsigned long long)base); - } - - /* - * We always prefer memory mapped access. - */ - if (maddr == NULL) { - - error = ahc_linux_pci_reserve_io_region(ahc, &base); - if (error == 0) { - ahc->tag = BUS_SPACE_PIO; - ahc->bsh.ioport = (u_long)base; - command |= PCIM_CMD_PORTEN; - } else { - printk("aic7xxx: PCI%d:%d:%d IO region 0x%llx[0..255] " - "unavailable. Cannot map device.\n", - ahc_get_pci_bus(ahc->dev_softc), - ahc_get_pci_slot(ahc->dev_softc), - ahc_get_pci_function(ahc->dev_softc), - (unsigned long long)base); - } - } - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4); - return (error); -} - -int -ahc_pci_map_int(struct ahc_softc *ahc) -{ - int error; - - error = request_irq(ahc->dev_softc->irq, ahc_linux_isr, - IRQF_SHARED, "aic7xxx", ahc); - if (error == 0) - ahc->platform_data->irq = ahc->dev_softc->irq; - - return (-error); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.c deleted file mode 100644 index 6917b4f5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.c +++ /dev/null @@ -1,2469 +0,0 @@ -/* - * Product specific probe and attach routines for: - * 3940, 2940, aic7895, aic7890, aic7880, - * aic7870, aic7860 and aic7850 SCSI controllers - * - * Copyright (c) 1994-2001 Justin T. Gibbs. - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#79 $ - */ - -#ifdef __linux__ -#include "aic7xxx_osm.h" -#include "aic7xxx_inline.h" -#include "aic7xxx_93cx6.h" -#else -#include -#include -#include -#endif - -#include "aic7xxx_pci.h" - -static inline uint64_t -ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor) -{ - uint64_t id; - - id = subvendor - | (subdevice << 16) - | ((uint64_t)vendor << 32) - | ((uint64_t)device << 48); - - return (id); -} - -#define AHC_PCI_IOADDR PCIR_MAPS /* I/O Address */ -#define AHC_PCI_MEMADDR (PCIR_MAPS + 4) /* Mem I/O Address */ - -#define DEVID_9005_TYPE(id) ((id) & 0xF) -#define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */ -#define DEVID_9005_TYPE_AAA 0x3 /* RAID Card */ -#define DEVID_9005_TYPE_SISL 0x5 /* Container ROMB */ -#define DEVID_9005_TYPE_MB 0xF /* On Motherboard */ - -#define DEVID_9005_MAXRATE(id) (((id) & 0x30) >> 4) -#define DEVID_9005_MAXRATE_U160 0x0 -#define DEVID_9005_MAXRATE_ULTRA2 0x1 -#define DEVID_9005_MAXRATE_ULTRA 0x2 -#define DEVID_9005_MAXRATE_FAST 0x3 - -#define DEVID_9005_MFUNC(id) (((id) & 0x40) >> 6) - -#define DEVID_9005_CLASS(id) (((id) & 0xFF00) >> 8) -#define DEVID_9005_CLASS_SPI 0x0 /* Parallel SCSI */ - -#define SUBID_9005_TYPE(id) ((id) & 0xF) -#define SUBID_9005_TYPE_MB 0xF /* On Motherboard */ -#define SUBID_9005_TYPE_CARD 0x0 /* Standard Card */ -#define SUBID_9005_TYPE_LCCARD 0x1 /* Low Cost Card */ -#define SUBID_9005_TYPE_RAID 0x3 /* Combined with Raid */ - -#define SUBID_9005_TYPE_KNOWN(id) \ - ((((id) & 0xF) == SUBID_9005_TYPE_MB) \ - || (((id) & 0xF) == SUBID_9005_TYPE_CARD) \ - || (((id) & 0xF) == SUBID_9005_TYPE_LCCARD) \ - || (((id) & 0xF) == SUBID_9005_TYPE_RAID)) - -#define SUBID_9005_MAXRATE(id) (((id) & 0x30) >> 4) -#define SUBID_9005_MAXRATE_ULTRA2 0x0 -#define SUBID_9005_MAXRATE_ULTRA 0x1 -#define SUBID_9005_MAXRATE_U160 0x2 -#define SUBID_9005_MAXRATE_RESERVED 0x3 - -#define SUBID_9005_SEEPTYPE(id) \ - ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ - ? ((id) & 0xC0) >> 6 \ - : ((id) & 0x300) >> 8) -#define SUBID_9005_SEEPTYPE_NONE 0x0 -#define SUBID_9005_SEEPTYPE_1K 0x1 -#define SUBID_9005_SEEPTYPE_2K_4K 0x2 -#define SUBID_9005_SEEPTYPE_RESERVED 0x3 -#define SUBID_9005_AUTOTERM(id) \ - ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ - ? (((id) & 0x400) >> 10) == 0 \ - : (((id) & 0x40) >> 6) == 0) - -#define SUBID_9005_NUMCHAN(id) \ - ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ - ? ((id) & 0x300) >> 8 \ - : ((id) & 0xC00) >> 10) - -#define SUBID_9005_LEGACYCONN(id) \ - ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ - ? 0 \ - : ((id) & 0x80) >> 7) - -#define SUBID_9005_MFUNCENB(id) \ - ((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB) \ - ? ((id) & 0x800) >> 11 \ - : ((id) & 0x1000) >> 12) -/* - * Informational only. Should use chip register to be - * certain, but may be use in identification strings. - */ -#define SUBID_9005_CARD_SCSIWIDTH_MASK 0x2000 -#define SUBID_9005_CARD_PCIWIDTH_MASK 0x4000 -#define SUBID_9005_CARD_SEDIFF_MASK 0x8000 - -static ahc_device_setup_t ahc_aic785X_setup; -static ahc_device_setup_t ahc_aic7860_setup; -static ahc_device_setup_t ahc_apa1480_setup; -static ahc_device_setup_t ahc_aic7870_setup; -static ahc_device_setup_t ahc_aic7870h_setup; -static ahc_device_setup_t ahc_aha394X_setup; -static ahc_device_setup_t ahc_aha394Xh_setup; -static ahc_device_setup_t ahc_aha494X_setup; -static ahc_device_setup_t ahc_aha494Xh_setup; -static ahc_device_setup_t ahc_aha398X_setup; -static ahc_device_setup_t ahc_aic7880_setup; -static ahc_device_setup_t ahc_aic7880h_setup; -static ahc_device_setup_t ahc_aha2940Pro_setup; -static ahc_device_setup_t ahc_aha394XU_setup; -static ahc_device_setup_t ahc_aha394XUh_setup; -static ahc_device_setup_t ahc_aha398XU_setup; -static ahc_device_setup_t ahc_aic7890_setup; -static ahc_device_setup_t ahc_aic7892_setup; -static ahc_device_setup_t ahc_aic7895_setup; -static ahc_device_setup_t ahc_aic7895h_setup; -static ahc_device_setup_t ahc_aic7896_setup; -static ahc_device_setup_t ahc_aic7899_setup; -static ahc_device_setup_t ahc_aha29160C_setup; -static ahc_device_setup_t ahc_raid_setup; -static ahc_device_setup_t ahc_aha394XX_setup; -static ahc_device_setup_t ahc_aha494XX_setup; -static ahc_device_setup_t ahc_aha398XX_setup; - -static const struct ahc_pci_identity ahc_pci_ident_table[] = { - /* aic7850 based controllers */ - { - ID_AHA_2902_04_10_15_20C_30C, - ID_ALL_MASK, - "Adaptec 2902/04/10/15/20C/30C SCSI adapter", - ahc_aic785X_setup - }, - /* aic7860 based controllers */ - { - ID_AHA_2930CU, - ID_ALL_MASK, - "Adaptec 2930CU SCSI adapter", - ahc_aic7860_setup - }, - { - ID_AHA_1480A & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 1480A Ultra SCSI adapter", - ahc_apa1480_setup - }, - { - ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 2940A Ultra SCSI adapter", - ahc_aic7860_setup - }, - { - ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 2940A/CN Ultra SCSI adapter", - ahc_aic7860_setup - }, - { - ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 2930C Ultra SCSI adapter (VAR)", - ahc_aic7860_setup - }, - /* aic7870 based controllers */ - { - ID_AHA_2940, - ID_ALL_MASK, - "Adaptec 2940 SCSI adapter", - ahc_aic7870_setup - }, - { - ID_AHA_3940, - ID_ALL_MASK, - "Adaptec 3940 SCSI adapter", - ahc_aha394X_setup - }, - { - ID_AHA_398X, - ID_ALL_MASK, - "Adaptec 398X SCSI RAID adapter", - ahc_aha398X_setup - }, - { - ID_AHA_2944, - ID_ALL_MASK, - "Adaptec 2944 SCSI adapter", - ahc_aic7870h_setup - }, - { - ID_AHA_3944, - ID_ALL_MASK, - "Adaptec 3944 SCSI adapter", - ahc_aha394Xh_setup - }, - { - ID_AHA_4944, - ID_ALL_MASK, - "Adaptec 4944 SCSI adapter", - ahc_aha494Xh_setup - }, - /* aic7880 based controllers */ - { - ID_AHA_2940U & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 2940 Ultra SCSI adapter", - ahc_aic7880_setup - }, - { - ID_AHA_3940U & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 3940 Ultra SCSI adapter", - ahc_aha394XU_setup - }, - { - ID_AHA_2944U & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 2944 Ultra SCSI adapter", - ahc_aic7880h_setup - }, - { - ID_AHA_3944U & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 3944 Ultra SCSI adapter", - ahc_aha394XUh_setup - }, - { - ID_AHA_398XU & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 398X Ultra SCSI RAID adapter", - ahc_aha398XU_setup - }, - { - /* - * XXX Don't know the slot numbers - * so we can't identify channels - */ - ID_AHA_4944U & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 4944 Ultra SCSI adapter", - ahc_aic7880h_setup - }, - { - ID_AHA_2930U & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 2930 Ultra SCSI adapter", - ahc_aic7880_setup - }, - { - ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 2940 Pro Ultra SCSI adapter", - ahc_aha2940Pro_setup - }, - { - ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec 2940/CN Ultra SCSI adapter", - ahc_aic7880_setup - }, - /* Ignore all SISL (AAC on MB) based controllers. */ - { - ID_9005_SISL_ID, - ID_9005_SISL_MASK, - NULL, - NULL - }, - /* aic7890 based controllers */ - { - ID_AHA_2930U2, - ID_ALL_MASK, - "Adaptec 2930 Ultra2 SCSI adapter", - ahc_aic7890_setup - }, - { - ID_AHA_2940U2B, - ID_ALL_MASK, - "Adaptec 2940B Ultra2 SCSI adapter", - ahc_aic7890_setup - }, - { - ID_AHA_2940U2_OEM, - ID_ALL_MASK, - "Adaptec 2940 Ultra2 SCSI adapter (OEM)", - ahc_aic7890_setup - }, - { - ID_AHA_2940U2, - ID_ALL_MASK, - "Adaptec 2940 Ultra2 SCSI adapter", - ahc_aic7890_setup - }, - { - ID_AHA_2950U2B, - ID_ALL_MASK, - "Adaptec 2950 Ultra2 SCSI adapter", - ahc_aic7890_setup - }, - { - ID_AIC7890_ARO, - ID_ALL_MASK, - "Adaptec aic7890/91 Ultra2 SCSI adapter (ARO)", - ahc_aic7890_setup - }, - { - ID_AAA_131U2, - ID_ALL_MASK, - "Adaptec AAA-131 Ultra2 RAID adapter", - ahc_aic7890_setup - }, - /* aic7892 based controllers */ - { - ID_AHA_29160, - ID_ALL_MASK, - "Adaptec 29160 Ultra160 SCSI adapter", - ahc_aic7892_setup - }, - { - ID_AHA_29160_CPQ, - ID_ALL_MASK, - "Adaptec (Compaq OEM) 29160 Ultra160 SCSI adapter", - ahc_aic7892_setup - }, - { - ID_AHA_29160N, - ID_ALL_MASK, - "Adaptec 29160N Ultra160 SCSI adapter", - ahc_aic7892_setup - }, - { - ID_AHA_29160C, - ID_ALL_MASK, - "Adaptec 29160C Ultra160 SCSI adapter", - ahc_aha29160C_setup - }, - { - ID_AHA_29160B, - ID_ALL_MASK, - "Adaptec 29160B Ultra160 SCSI adapter", - ahc_aic7892_setup - }, - { - ID_AHA_19160B, - ID_ALL_MASK, - "Adaptec 19160B Ultra160 SCSI adapter", - ahc_aic7892_setup - }, - { - ID_AIC7892_ARO, - ID_ALL_MASK, - "Adaptec aic7892 Ultra160 SCSI adapter (ARO)", - ahc_aic7892_setup - }, - { - ID_AHA_2915_30LP, - ID_ALL_MASK, - "Adaptec 2915/30LP Ultra160 SCSI adapter", - ahc_aic7892_setup - }, - /* aic7895 based controllers */ - { - ID_AHA_2940U_DUAL, - ID_ALL_MASK, - "Adaptec 2940/DUAL Ultra SCSI adapter", - ahc_aic7895_setup - }, - { - ID_AHA_3940AU, - ID_ALL_MASK, - "Adaptec 3940A Ultra SCSI adapter", - ahc_aic7895_setup - }, - { - ID_AHA_3944AU, - ID_ALL_MASK, - "Adaptec 3944A Ultra SCSI adapter", - ahc_aic7895h_setup - }, - { - ID_AIC7895_ARO, - ID_AIC7895_ARO_MASK, - "Adaptec aic7895 Ultra SCSI adapter (ARO)", - ahc_aic7895_setup - }, - /* aic7896/97 based controllers */ - { - ID_AHA_3950U2B_0, - ID_ALL_MASK, - "Adaptec 3950B Ultra2 SCSI adapter", - ahc_aic7896_setup - }, - { - ID_AHA_3950U2B_1, - ID_ALL_MASK, - "Adaptec 3950B Ultra2 SCSI adapter", - ahc_aic7896_setup - }, - { - ID_AHA_3950U2D_0, - ID_ALL_MASK, - "Adaptec 3950D Ultra2 SCSI adapter", - ahc_aic7896_setup - }, - { - ID_AHA_3950U2D_1, - ID_ALL_MASK, - "Adaptec 3950D Ultra2 SCSI adapter", - ahc_aic7896_setup - }, - { - ID_AIC7896_ARO, - ID_ALL_MASK, - "Adaptec aic7896/97 Ultra2 SCSI adapter (ARO)", - ahc_aic7896_setup - }, - /* aic7899 based controllers */ - { - ID_AHA_3960D, - ID_ALL_MASK, - "Adaptec 3960D Ultra160 SCSI adapter", - ahc_aic7899_setup - }, - { - ID_AHA_3960D_CPQ, - ID_ALL_MASK, - "Adaptec (Compaq OEM) 3960D Ultra160 SCSI adapter", - ahc_aic7899_setup - }, - { - ID_AIC7899_ARO, - ID_ALL_MASK, - "Adaptec aic7899 Ultra160 SCSI adapter (ARO)", - ahc_aic7899_setup - }, - /* Generic chip probes for devices we don't know 'exactly' */ - { - ID_AIC7850 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7850 SCSI adapter", - ahc_aic785X_setup - }, - { - ID_AIC7855 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7855 SCSI adapter", - ahc_aic785X_setup - }, - { - ID_AIC7859 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7859 SCSI adapter", - ahc_aic7860_setup - }, - { - ID_AIC7860 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7860 Ultra SCSI adapter", - ahc_aic7860_setup - }, - { - ID_AIC7870 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7870 SCSI adapter", - ahc_aic7870_setup - }, - { - ID_AIC7880 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7880 Ultra SCSI adapter", - ahc_aic7880_setup - }, - { - ID_AIC7890 & ID_9005_GENERIC_MASK, - ID_9005_GENERIC_MASK, - "Adaptec aic7890/91 Ultra2 SCSI adapter", - ahc_aic7890_setup - }, - { - ID_AIC7892 & ID_9005_GENERIC_MASK, - ID_9005_GENERIC_MASK, - "Adaptec aic7892 Ultra160 SCSI adapter", - ahc_aic7892_setup - }, - { - ID_AIC7895 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7895 Ultra SCSI adapter", - ahc_aic7895_setup - }, - { - ID_AIC7896 & ID_9005_GENERIC_MASK, - ID_9005_GENERIC_MASK, - "Adaptec aic7896/97 Ultra2 SCSI adapter", - ahc_aic7896_setup - }, - { - ID_AIC7899 & ID_9005_GENERIC_MASK, - ID_9005_GENERIC_MASK, - "Adaptec aic7899 Ultra160 SCSI adapter", - ahc_aic7899_setup - }, - { - ID_AIC7810 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7810 RAID memory controller", - ahc_raid_setup - }, - { - ID_AIC7815 & ID_DEV_VENDOR_MASK, - ID_DEV_VENDOR_MASK, - "Adaptec aic7815 RAID memory controller", - ahc_raid_setup - } -}; - -static const u_int ahc_num_pci_devs = ARRAY_SIZE(ahc_pci_ident_table); - -#define AHC_394X_SLOT_CHANNEL_A 4 -#define AHC_394X_SLOT_CHANNEL_B 5 - -#define AHC_398X_SLOT_CHANNEL_A 4 -#define AHC_398X_SLOT_CHANNEL_B 8 -#define AHC_398X_SLOT_CHANNEL_C 12 - -#define AHC_494X_SLOT_CHANNEL_A 4 -#define AHC_494X_SLOT_CHANNEL_B 5 -#define AHC_494X_SLOT_CHANNEL_C 6 -#define AHC_494X_SLOT_CHANNEL_D 7 - -#define DEVCONFIG 0x40 -#define PCIERRGENDIS 0x80000000ul -#define SCBSIZE32 0x00010000ul /* aic789X only */ -#define REXTVALID 0x00001000ul /* ultra cards only */ -#define MPORTMODE 0x00000400ul /* aic7870+ only */ -#define RAMPSM 0x00000200ul /* aic7870+ only */ -#define VOLSENSE 0x00000100ul -#define PCI64BIT 0x00000080ul /* 64Bit PCI bus (Ultra2 Only)*/ -#define SCBRAMSEL 0x00000080ul -#define MRDCEN 0x00000040ul -#define EXTSCBTIME 0x00000020ul /* aic7870 only */ -#define EXTSCBPEN 0x00000010ul /* aic7870 only */ -#define BERREN 0x00000008ul -#define DACEN 0x00000004ul -#define STPWLEVEL 0x00000002ul -#define DIFACTNEGEN 0x00000001ul /* aic7870 only */ - -#define CSIZE_LATTIME 0x0c -#define CACHESIZE 0x0000003ful /* only 5 bits */ -#define LATTIME 0x0000ff00ul - -/* PCI STATUS definitions */ -#define DPE 0x80 -#define SSE 0x40 -#define RMA 0x20 -#define RTA 0x10 -#define STA 0x08 -#define DPR 0x01 - -static int ahc_9005_subdevinfo_valid(uint16_t vendor, uint16_t device, - uint16_t subvendor, uint16_t subdevice); -static int ahc_ext_scbram_present(struct ahc_softc *ahc); -static void ahc_scbram_config(struct ahc_softc *ahc, int enable, - int pcheck, int fast, int large); -static void ahc_probe_ext_scbram(struct ahc_softc *ahc); -static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1); -static void ahc_parse_pci_eeprom(struct ahc_softc *ahc, - struct seeprom_config *sc); -static void configure_termination(struct ahc_softc *ahc, - struct seeprom_descriptor *sd, - u_int adapter_control, - u_int *sxfrctl1); - -static void ahc_new_term_detect(struct ahc_softc *ahc, - int *enableSEC_low, - int *enableSEC_high, - int *enablePRI_low, - int *enablePRI_high, - int *eeprom_present); -static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present, - int *internal68_present, - int *externalcable_present, - int *eeprom_present); -static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, - int *externalcable_present, - int *eeprom_present); -static void write_brdctl(struct ahc_softc *ahc, uint8_t value); -static uint8_t read_brdctl(struct ahc_softc *ahc); -static void ahc_pci_intr(struct ahc_softc *ahc); -static int ahc_pci_chip_init(struct ahc_softc *ahc); - -static int -ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor, - uint16_t subdevice, uint16_t subvendor) -{ - int result; - - /* Default to invalid. */ - result = 0; - if (vendor == 0x9005 - && subvendor == 0x9005 - && subdevice != device - && SUBID_9005_TYPE_KNOWN(subdevice) != 0) { - - switch (SUBID_9005_TYPE(subdevice)) { - case SUBID_9005_TYPE_MB: - break; - case SUBID_9005_TYPE_CARD: - case SUBID_9005_TYPE_LCCARD: - /* - * Currently only trust Adaptec cards to - * get the sub device info correct. - */ - if (DEVID_9005_TYPE(device) == DEVID_9005_TYPE_HBA) - result = 1; - break; - case SUBID_9005_TYPE_RAID: - break; - default: - break; - } - } - return (result); -} - -const struct ahc_pci_identity * -ahc_find_pci_device(ahc_dev_softc_t pci) -{ - uint64_t full_id; - uint16_t device; - uint16_t vendor; - uint16_t subdevice; - uint16_t subvendor; - const struct ahc_pci_identity *entry; - u_int i; - - vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2); - device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2); - subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2); - subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2); - full_id = ahc_compose_id(device, vendor, subdevice, subvendor); - - /* - * If the second function is not hooked up, ignore it. - * Unfortunately, not all MB vendors implement the - * subdevice ID as per the Adaptec spec, so do our best - * to sanity check it prior to accepting the subdevice - * ID as valid. - */ - if (ahc_get_pci_function(pci) > 0 - && ahc_9005_subdevinfo_valid(vendor, device, subvendor, subdevice) - && SUBID_9005_MFUNCENB(subdevice) == 0) - return (NULL); - - for (i = 0; i < ahc_num_pci_devs; i++) { - entry = &ahc_pci_ident_table[i]; - if (entry->full_id == (full_id & entry->id_mask)) { - /* Honor exclusion entries. */ - if (entry->name == NULL) - return (NULL); - return (entry); - } - } - return (NULL); -} - -int -ahc_pci_config(struct ahc_softc *ahc, const struct ahc_pci_identity *entry) -{ - u_int command; - u_int our_id; - u_int sxfrctl1; - u_int scsiseq; - u_int dscommand0; - uint32_t devconfig; - int error; - uint8_t sblkctl; - - our_id = 0; - error = entry->setup(ahc); - if (error != 0) - return (error); - ahc->chip |= AHC_PCI; - ahc->description = entry->name; - - pci_set_power_state(ahc->dev_softc, AHC_POWER_STATE_D0); - - error = ahc_pci_map_registers(ahc); - if (error != 0) - return (error); - - /* - * Before we continue probing the card, ensure that - * its interrupts are *disabled*. We don't want - * a misstep to hang the machine in an interrupt - * storm. - */ - ahc_intr_enable(ahc, FALSE); - - devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); - - /* - * If we need to support high memory, enable dual - * address cycles. This bit must be set to enable - * high address bit generation even if we are on a - * 64bit bus (PCI64BIT set in devconfig). - */ - if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - - if (bootverbose) - printk("%s: Enabling 39Bit Addressing\n", - ahc_name(ahc)); - devconfig |= DACEN; - } - - /* Ensure that pci error generation, a test feature, is disabled. */ - devconfig |= PCIERRGENDIS; - - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); - - /* Ensure busmastering is enabled */ - command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); - command |= PCIM_CMD_BUSMASTEREN; - - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2); - - /* On all PCI adapters, we allow SCB paging */ - ahc->flags |= AHC_PAGESCBS; - - error = ahc_softc_init(ahc); - if (error != 0) - return (error); - - /* - * Disable PCI parity error checking. Users typically - * do this to work around broken PCI chipsets that get - * the parity timing wrong and thus generate lots of spurious - * errors. The chip only allows us to disable *all* parity - * error reporting when doing this, so CIO bus, scb ram, and - * scratch ram parity errors will be ignored too. - */ - if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) - ahc->seqctl |= FAILDIS; - - ahc->bus_intr = ahc_pci_intr; - ahc->bus_chip_init = ahc_pci_chip_init; - - /* Remember how the card was setup in case there is no SEEPROM */ - if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) { - ahc_pause(ahc); - if ((ahc->features & AHC_ULTRA2) != 0) - our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID; - else - our_id = ahc_inb(ahc, SCSIID) & OID; - sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN; - scsiseq = ahc_inb(ahc, SCSISEQ); - } else { - sxfrctl1 = STPWEN; - our_id = 7; - scsiseq = 0; - } - - error = ahc_reset(ahc, /*reinit*/FALSE); - if (error != 0) - return (ENXIO); - - if ((ahc->features & AHC_DT) != 0) { - u_int sfunct; - - /* Perform ALT-Mode Setup */ - sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; - ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc_outb(ahc, OPTIONMODE, - OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS); - ahc_outb(ahc, SFUNCT, sfunct); - - /* Normal mode setup */ - ahc_outb(ahc, CRCCONTROL1, CRCVALCHKEN|CRCENDCHKEN|CRCREQCHKEN - |TARGCRCENDEN); - } - - dscommand0 = ahc_inb(ahc, DSCOMMAND0); - dscommand0 |= MPARCKEN|CACHETHEN; - if ((ahc->features & AHC_ULTRA2) != 0) { - - /* - * DPARCKEN doesn't work correctly on - * some MBs so don't use it. - */ - dscommand0 &= ~DPARCKEN; - } - - /* - * Handle chips that must have cache line - * streaming (dis/en)abled. - */ - if ((ahc->bugs & AHC_CACHETHEN_DIS_BUG) != 0) - dscommand0 |= CACHETHEN; - - if ((ahc->bugs & AHC_CACHETHEN_BUG) != 0) - dscommand0 &= ~CACHETHEN; - - ahc_outb(ahc, DSCOMMAND0, dscommand0); - - ahc->pci_cachesize = - ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, - /*bytes*/1) & CACHESIZE; - ahc->pci_cachesize *= 4; - - if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0 - && ahc->pci_cachesize == 4) { - - ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, - 0, /*bytes*/1); - ahc->pci_cachesize = 0; - } - - /* - * We cannot perform ULTRA speeds without the presence - * of the external precision resistor. - */ - if ((ahc->features & AHC_ULTRA) != 0) { - uint32_t devconfig; - - devconfig = ahc_pci_read_config(ahc->dev_softc, - DEVCONFIG, /*bytes*/4); - if ((devconfig & REXTVALID) == 0) - ahc->features &= ~AHC_ULTRA; - } - - /* See if we have a SEEPROM and perform auto-term */ - check_extport(ahc, &sxfrctl1); - - /* - * Take the LED out of diagnostic mode - */ - sblkctl = ahc_inb(ahc, SBLKCTL); - ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON))); - - if ((ahc->features & AHC_ULTRA2) != 0) { - ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_MAX|WR_DFTHRSH_MAX); - } else { - ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100); - } - - if (ahc->flags & AHC_USEDEFAULTS) { - /* - * PCI Adapter default setup - * Should only be used if the adapter does not have - * a SEEPROM. - */ - /* See if someone else set us up already */ - if ((ahc->flags & AHC_NO_BIOS_INIT) == 0 - && scsiseq != 0) { - printk("%s: Using left over BIOS settings\n", - ahc_name(ahc)); - ahc->flags &= ~AHC_USEDEFAULTS; - ahc->flags |= AHC_BIOS_ENABLED; - } else { - /* - * Assume only one connector and always turn - * on termination. - */ - our_id = 0x07; - sxfrctl1 = STPWEN; - } - ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI); - - ahc->our_id = our_id; - } - - /* - * Take a look to see if we have external SRAM. - * We currently do not attempt to use SRAM that is - * shared among multiple controllers. - */ - ahc_probe_ext_scbram(ahc); - - /* - * Record our termination setting for the - * generic initialization routine. - */ - if ((sxfrctl1 & STPWEN) != 0) - ahc->flags |= AHC_TERM_ENB_A; - - /* - * Save chip register configuration data for chip resets - * that occur during runtime and resume events. - */ - ahc->bus_softc.pci_softc.devconfig = - ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); - ahc->bus_softc.pci_softc.command = - ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); - ahc->bus_softc.pci_softc.csize_lattime = - ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1); - ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0); - ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS); - if ((ahc->features & AHC_DT) != 0) { - u_int sfunct; - - sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; - ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE); - ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT); - ahc_outb(ahc, SFUNCT, sfunct); - ahc->bus_softc.pci_softc.crccontrol1 = - ahc_inb(ahc, CRCCONTROL1); - } - if ((ahc->features & AHC_MULTI_FUNC) != 0) - ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR); - - if ((ahc->features & AHC_ULTRA2) != 0) - ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH); - - /* Core initialization */ - error = ahc_init(ahc); - if (error != 0) - return (error); - ahc->init_level++; - - /* - * Allow interrupts now that we are completely setup. - */ - return ahc_pci_map_int(ahc); -} - -/* - * Test for the presence of external sram in an - * "unshared" configuration. - */ -static int -ahc_ext_scbram_present(struct ahc_softc *ahc) -{ - u_int chip; - int ramps; - int single_user; - uint32_t devconfig; - - chip = ahc->chip & AHC_CHIPID_MASK; - devconfig = ahc_pci_read_config(ahc->dev_softc, - DEVCONFIG, /*bytes*/4); - single_user = (devconfig & MPORTMODE) != 0; - - if ((ahc->features & AHC_ULTRA2) != 0) - ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0; - else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C) - /* - * External SCBRAM arbitration is flakey - * on these chips. Unfortunately this means - * we don't use the extra SCB ram space on the - * 3940AUW. - */ - ramps = 0; - else if (chip >= AHC_AIC7870) - ramps = (devconfig & RAMPSM) != 0; - else - ramps = 0; - - if (ramps && single_user) - return (1); - return (0); -} - -/* - * Enable external scbram. - */ -static void -ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck, - int fast, int large) -{ - uint32_t devconfig; - - if (ahc->features & AHC_MULTI_FUNC) { - /* - * Set the SCB Base addr (highest address bit) - * depending on which channel we are. - */ - ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc)); - } - - ahc->flags &= ~AHC_LSCBS_ENABLED; - if (large) - ahc->flags |= AHC_LSCBS_ENABLED; - devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4); - if ((ahc->features & AHC_ULTRA2) != 0) { - u_int dscommand0; - - dscommand0 = ahc_inb(ahc, DSCOMMAND0); - if (enable) - dscommand0 &= ~INTSCBRAMSEL; - else - dscommand0 |= INTSCBRAMSEL; - if (large) - dscommand0 &= ~USCBSIZE32; - else - dscommand0 |= USCBSIZE32; - ahc_outb(ahc, DSCOMMAND0, dscommand0); - } else { - if (fast) - devconfig &= ~EXTSCBTIME; - else - devconfig |= EXTSCBTIME; - if (enable) - devconfig &= ~SCBRAMSEL; - else - devconfig |= SCBRAMSEL; - if (large) - devconfig &= ~SCBSIZE32; - else - devconfig |= SCBSIZE32; - } - if (pcheck) - devconfig |= EXTSCBPEN; - else - devconfig &= ~EXTSCBPEN; - - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); -} - -/* - * Take a look to see if we have external SRAM. - * We currently do not attempt to use SRAM that is - * shared among multiple controllers. - */ -static void -ahc_probe_ext_scbram(struct ahc_softc *ahc) -{ - int num_scbs; - int test_num_scbs; - int enable; - int pcheck; - int fast; - int large; - - enable = FALSE; - pcheck = FALSE; - fast = FALSE; - large = FALSE; - num_scbs = 0; - - if (ahc_ext_scbram_present(ahc) == 0) - goto done; - - /* - * Probe for the best parameters to use. - */ - ahc_scbram_config(ahc, /*enable*/TRUE, pcheck, fast, large); - num_scbs = ahc_probe_scbs(ahc); - if (num_scbs == 0) { - /* The SRAM wasn't really present. */ - goto done; - } - enable = TRUE; - - /* - * Clear any outstanding parity error - * and ensure that parity error reporting - * is enabled. - */ - ahc_outb(ahc, SEQCTL, 0); - ahc_outb(ahc, CLRINT, CLRPARERR); - ahc_outb(ahc, CLRINT, CLRBRKADRINT); - - /* Now see if we can do parity */ - ahc_scbram_config(ahc, enable, /*pcheck*/TRUE, fast, large); - num_scbs = ahc_probe_scbs(ahc); - if ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0 - || (ahc_inb(ahc, ERROR) & MPARERR) == 0) - pcheck = TRUE; - - /* Clear any resulting parity error */ - ahc_outb(ahc, CLRINT, CLRPARERR); - ahc_outb(ahc, CLRINT, CLRBRKADRINT); - - /* Now see if we can do fast timing */ - ahc_scbram_config(ahc, enable, pcheck, /*fast*/TRUE, large); - test_num_scbs = ahc_probe_scbs(ahc); - if (test_num_scbs == num_scbs - && ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0 - || (ahc_inb(ahc, ERROR) & MPARERR) == 0)) - fast = TRUE; - - /* - * See if we can use large SCBs and still maintain - * the same overall count of SCBs. - */ - if ((ahc->features & AHC_LARGE_SCBS) != 0) { - ahc_scbram_config(ahc, enable, pcheck, fast, /*large*/TRUE); - test_num_scbs = ahc_probe_scbs(ahc); - if (test_num_scbs >= num_scbs) { - large = TRUE; - num_scbs = test_num_scbs; - if (num_scbs >= 64) { - /* - * We have enough space to move the - * "busy targets table" into SCB space - * and make it qualify all the way to the - * lun level. - */ - ahc->flags |= AHC_SCB_BTT; - } - } - } -done: - /* - * Disable parity error reporting until we - * can load instruction ram. - */ - ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); - /* Clear any latched parity error */ - ahc_outb(ahc, CLRINT, CLRPARERR); - ahc_outb(ahc, CLRINT, CLRBRKADRINT); - if (bootverbose && enable) { - printk("%s: External SRAM, %s access%s, %dbytes/SCB\n", - ahc_name(ahc), fast ? "fast" : "slow", - pcheck ? ", parity checking enabled" : "", - large ? 64 : 32); - } - ahc_scbram_config(ahc, enable, pcheck, fast, large); -} - -/* - * Perform some simple tests that should catch situations where - * our registers are invalidly mapped. - */ -int -ahc_pci_test_register_access(struct ahc_softc *ahc) -{ - int error; - u_int status1; - uint32_t cmd; - uint8_t hcntrl; - - error = EIO; - - /* - * Enable PCI error interrupt status, but suppress NMIs - * generated by SERR raised due to target aborts. - */ - cmd = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, - cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2); - - /* - * First a simple test to see if any - * registers can be read. Reading - * HCNTRL has no side effects and has - * at least one bit that is guaranteed to - * be zero so it is a good register to - * use for this test. - */ - hcntrl = ahc_inb(ahc, HCNTRL); - - if (hcntrl == 0xFF) - goto fail; - - if ((hcntrl & CHIPRST) != 0) { - /* - * The chip has not been initialized since - * PCI/EISA/VLB bus reset. Don't trust - * "left over BIOS data". - */ - ahc->flags |= AHC_NO_BIOS_INIT; - } - - /* - * Next create a situation where write combining - * or read prefetching could be initiated by the - * CPU or host bridge. Our device does not support - * either, so look for data corruption and/or flagged - * PCI errors. First pause without causing another - * chip reset. - */ - hcntrl &= ~CHIPRST; - ahc_outb(ahc, HCNTRL, hcntrl|PAUSE); - while (ahc_is_paused(ahc) == 0) - ; - - /* Clear any PCI errors that occurred before our driver attached. */ - status1 = ahc_pci_read_config(ahc->dev_softc, - PCIR_STATUS + 1, /*bytes*/1); - ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, - status1, /*bytes*/1); - ahc_outb(ahc, CLRINT, CLRPARERR); - - ahc_outb(ahc, SEQCTL, PERRORDIS); - ahc_outb(ahc, SCBPTR, 0); - ahc_outl(ahc, SCB_BASE, 0x5aa555aa); - if (ahc_inl(ahc, SCB_BASE) != 0x5aa555aa) - goto fail; - - status1 = ahc_pci_read_config(ahc->dev_softc, - PCIR_STATUS + 1, /*bytes*/1); - if ((status1 & STA) != 0) - goto fail; - - error = 0; - -fail: - /* Silently clear any latched errors. */ - status1 = ahc_pci_read_config(ahc->dev_softc, - PCIR_STATUS + 1, /*bytes*/1); - ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, - status1, /*bytes*/1); - ahc_outb(ahc, CLRINT, CLRPARERR); - ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS); - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); - return (error); -} - -/* - * Check the external port logic for a serial eeprom - * and termination/cable detection contrls. - */ -static void -check_extport(struct ahc_softc *ahc, u_int *sxfrctl1) -{ - struct seeprom_descriptor sd; - struct seeprom_config *sc; - int have_seeprom; - int have_autoterm; - - sd.sd_ahc = ahc; - sd.sd_control_offset = SEECTL; - sd.sd_status_offset = SEECTL; - sd.sd_dataout_offset = SEECTL; - sc = ahc->seep_config; - - /* - * For some multi-channel devices, the c46 is simply too - * small to work. For the other controller types, we can - * get our information from either SEEPROM type. Set the - * type to start our probe with accordingly. - */ - if (ahc->flags & AHC_LARGE_SEEPROM) - sd.sd_chip = C56_66; - else - sd.sd_chip = C46; - - sd.sd_MS = SEEMS; - sd.sd_RDY = SEERDY; - sd.sd_CS = SEECS; - sd.sd_CK = SEECK; - sd.sd_DO = SEEDO; - sd.sd_DI = SEEDI; - - have_seeprom = ahc_acquire_seeprom(ahc, &sd); - if (have_seeprom) { - - if (bootverbose) - printk("%s: Reading SEEPROM...", ahc_name(ahc)); - - for (;;) { - u_int start_addr; - - start_addr = 32 * (ahc->channel - 'A'); - - have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc, - start_addr, - sizeof(*sc)/2); - - if (have_seeprom) - have_seeprom = ahc_verify_cksum(sc); - - if (have_seeprom != 0 || sd.sd_chip == C56_66) { - if (bootverbose) { - if (have_seeprom == 0) - printk ("checksum error\n"); - else - printk ("done.\n"); - } - break; - } - sd.sd_chip = C56_66; - } - ahc_release_seeprom(&sd); - - /* Remember the SEEPROM type for later */ - if (sd.sd_chip == C56_66) - ahc->flags |= AHC_LARGE_SEEPROM; - } - - if (!have_seeprom) { - /* - * Pull scratch ram settings and treat them as - * if they are the contents of an seeprom if - * the 'ADPT' signature is found in SCB2. - * We manually compose the data as 16bit values - * to avoid endian issues. - */ - ahc_outb(ahc, SCBPTR, 2); - if (ahc_inb(ahc, SCB_BASE) == 'A' - && ahc_inb(ahc, SCB_BASE + 1) == 'D' - && ahc_inb(ahc, SCB_BASE + 2) == 'P' - && ahc_inb(ahc, SCB_BASE + 3) == 'T') { - uint16_t *sc_data; - int i; - - sc_data = (uint16_t *)sc; - for (i = 0; i < 32; i++, sc_data++) { - int j; - - j = i * 2; - *sc_data = ahc_inb(ahc, SRAM_BASE + j) - | ahc_inb(ahc, SRAM_BASE + j + 1) << 8; - } - have_seeprom = ahc_verify_cksum(sc); - if (have_seeprom) - ahc->flags |= AHC_SCB_CONFIG_USED; - } - /* - * Clear any SCB parity errors in case this data and - * its associated parity was not initialized by the BIOS - */ - ahc_outb(ahc, CLRINT, CLRPARERR); - ahc_outb(ahc, CLRINT, CLRBRKADRINT); - } - - if (!have_seeprom) { - if (bootverbose) - printk("%s: No SEEPROM available.\n", ahc_name(ahc)); - ahc->flags |= AHC_USEDEFAULTS; - kfree(ahc->seep_config); - ahc->seep_config = NULL; - sc = NULL; - } else { - ahc_parse_pci_eeprom(ahc, sc); - } - - /* - * Cards that have the external logic necessary to talk to - * a SEEPROM, are almost certain to have the remaining logic - * necessary for auto-termination control. This assumption - * hasn't failed yet... - */ - have_autoterm = have_seeprom; - - /* - * Some low-cost chips have SEEPROM and auto-term control built - * in, instead of using a GAL. They can tell us directly - * if the termination logic is enabled. - */ - if ((ahc->features & AHC_SPIOCAP) != 0) { - if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0) - have_autoterm = FALSE; - } - - if (have_autoterm) { - ahc->flags |= AHC_HAS_TERM_LOGIC; - ahc_acquire_seeprom(ahc, &sd); - configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1); - ahc_release_seeprom(&sd); - } else if (have_seeprom) { - *sxfrctl1 &= ~STPWEN; - if ((sc->adapter_control & CFSTERM) != 0) - *sxfrctl1 |= STPWEN; - if (bootverbose) - printk("%s: Low byte termination %sabled\n", - ahc_name(ahc), - (*sxfrctl1 & STPWEN) ? "en" : "dis"); - } -} - -static void -ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc) -{ - /* - * Put the data we've collected down into SRAM - * where ahc_init will find it. - */ - int i; - int max_targ = sc->max_targets & CFMAXTARG; - u_int scsi_conf; - uint16_t discenable; - uint16_t ultraenb; - - discenable = 0; - ultraenb = 0; - if ((sc->adapter_control & CFULTRAEN) != 0) { - /* - * Determine if this adapter has a "newstyle" - * SEEPROM format. - */ - for (i = 0; i < max_targ; i++) { - if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) { - ahc->flags |= AHC_NEWEEPROM_FMT; - break; - } - } - } - - for (i = 0; i < max_targ; i++) { - u_int scsirate; - uint16_t target_mask; - - target_mask = 0x01 << i; - if (sc->device_flags[i] & CFDISC) - discenable |= target_mask; - if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) { - if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) - ultraenb |= target_mask; - } else if ((sc->adapter_control & CFULTRAEN) != 0) { - ultraenb |= target_mask; - } - if ((sc->device_flags[i] & CFXFER) == 0x04 - && (ultraenb & target_mask) != 0) { - /* Treat 10MHz as a non-ultra speed */ - sc->device_flags[i] &= ~CFXFER; - ultraenb &= ~target_mask; - } - if ((ahc->features & AHC_ULTRA2) != 0) { - u_int offset; - - if (sc->device_flags[i] & CFSYNCH) - offset = MAX_OFFSET_ULTRA2; - else - offset = 0; - ahc_outb(ahc, TARG_OFFSET + i, offset); - - /* - * The ultra enable bits contain the - * high bit of the ultra2 sync rate - * field. - */ - scsirate = (sc->device_flags[i] & CFXFER) - | ((ultraenb & target_mask) ? 0x8 : 0x0); - if (sc->device_flags[i] & CFWIDEB) - scsirate |= WIDEXFER; - } else { - scsirate = (sc->device_flags[i] & CFXFER) << 4; - if (sc->device_flags[i] & CFSYNCH) - scsirate |= SOFS; - if (sc->device_flags[i] & CFWIDEB) - scsirate |= WIDEXFER; - } - ahc_outb(ahc, TARG_SCSIRATE + i, scsirate); - } - ahc->our_id = sc->brtime_id & CFSCSIID; - - scsi_conf = (ahc->our_id & 0x7); - if (sc->adapter_control & CFSPARITY) - scsi_conf |= ENSPCHK; - if (sc->adapter_control & CFRESETB) - scsi_conf |= RESET_SCSI; - - ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT; - - if (sc->bios_control & CFEXTEND) - ahc->flags |= AHC_EXTENDED_TRANS_A; - - if (sc->bios_control & CFBIOSEN) - ahc->flags |= AHC_BIOS_ENABLED; - if (ahc->features & AHC_ULTRA - && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) { - /* Should we enable Ultra mode? */ - if (!(sc->adapter_control & CFULTRAEN)) - /* Treat us as a non-ultra card */ - ultraenb = 0; - } - - if (sc->signature == CFSIGNATURE - || sc->signature == CFSIGNATURE2) { - uint32_t devconfig; - - /* Honor the STPWLEVEL settings */ - devconfig = ahc_pci_read_config(ahc->dev_softc, - DEVCONFIG, /*bytes*/4); - devconfig &= ~STPWLEVEL; - if ((sc->bios_control & CFSTPWLEVEL) != 0) - devconfig |= STPWLEVEL; - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, - devconfig, /*bytes*/4); - } - /* Set SCSICONF info */ - ahc_outb(ahc, SCSICONF, scsi_conf); - ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff)); - ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff)); - ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff); - ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff); -} - -static void -configure_termination(struct ahc_softc *ahc, - struct seeprom_descriptor *sd, - u_int adapter_control, - u_int *sxfrctl1) -{ - uint8_t brddat; - - brddat = 0; - - /* - * Update the settings in sxfrctl1 to match the - * termination settings - */ - *sxfrctl1 = 0; - - /* - * SEECS must be on for the GALS to latch - * the data properly. Be sure to leave MS - * on or we will release the seeprom. - */ - SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS); - if ((adapter_control & CFAUTOTERM) != 0 - || (ahc->features & AHC_NEW_TERMCTL) != 0) { - int internal50_present; - int internal68_present; - int externalcable_present; - int eeprom_present; - int enableSEC_low; - int enableSEC_high; - int enablePRI_low; - int enablePRI_high; - int sum; - - enableSEC_low = 0; - enableSEC_high = 0; - enablePRI_low = 0; - enablePRI_high = 0; - if ((ahc->features & AHC_NEW_TERMCTL) != 0) { - ahc_new_term_detect(ahc, &enableSEC_low, - &enableSEC_high, - &enablePRI_low, - &enablePRI_high, - &eeprom_present); - if ((adapter_control & CFSEAUTOTERM) == 0) { - if (bootverbose) - printk("%s: Manual SE Termination\n", - ahc_name(ahc)); - enableSEC_low = (adapter_control & CFSELOWTERM); - enableSEC_high = - (adapter_control & CFSEHIGHTERM); - } - if ((adapter_control & CFAUTOTERM) == 0) { - if (bootverbose) - printk("%s: Manual LVD Termination\n", - ahc_name(ahc)); - enablePRI_low = (adapter_control & CFSTERM); - enablePRI_high = (adapter_control & CFWSTERM); - } - /* Make the table calculations below happy */ - internal50_present = 0; - internal68_present = 1; - externalcable_present = 1; - } else if ((ahc->features & AHC_SPIOCAP) != 0) { - aic785X_cable_detect(ahc, &internal50_present, - &externalcable_present, - &eeprom_present); - /* Can never support a wide connector. */ - internal68_present = 0; - } else { - aic787X_cable_detect(ahc, &internal50_present, - &internal68_present, - &externalcable_present, - &eeprom_present); - } - - if ((ahc->features & AHC_WIDE) == 0) - internal68_present = 0; - - if (bootverbose - && (ahc->features & AHC_ULTRA2) == 0) { - printk("%s: internal 50 cable %s present", - ahc_name(ahc), - internal50_present ? "is":"not"); - - if ((ahc->features & AHC_WIDE) != 0) - printk(", internal 68 cable %s present", - internal68_present ? "is":"not"); - printk("\n%s: external cable %s present\n", - ahc_name(ahc), - externalcable_present ? "is":"not"); - } - if (bootverbose) - printk("%s: BIOS eeprom %s present\n", - ahc_name(ahc), eeprom_present ? "is" : "not"); - - if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) { - /* - * The 50 pin connector is a separate bus, - * so force it to always be terminated. - * In the future, perform current sensing - * to determine if we are in the middle of - * a properly terminated bus. - */ - internal50_present = 0; - } - - /* - * Now set the termination based on what - * we found. - * Flash Enable = BRDDAT7 - * Secondary High Term Enable = BRDDAT6 - * Secondary Low Term Enable = BRDDAT5 (7890) - * Primary High Term Enable = BRDDAT4 (7890) - */ - if ((ahc->features & AHC_ULTRA2) == 0 - && (internal50_present != 0) - && (internal68_present != 0) - && (externalcable_present != 0)) { - printk("%s: Illegal cable configuration!!. " - "Only two connectors on the " - "adapter may be used at a " - "time!\n", ahc_name(ahc)); - - /* - * Pretend there are no cables in the hope - * that having all of the termination on - * gives us a more stable bus. - */ - internal50_present = 0; - internal68_present = 0; - externalcable_present = 0; - } - - if ((ahc->features & AHC_WIDE) != 0 - && ((externalcable_present == 0) - || (internal68_present == 0) - || (enableSEC_high != 0))) { - brddat |= BRDDAT6; - if (bootverbose) { - if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) - printk("%s: 68 pin termination " - "Enabled\n", ahc_name(ahc)); - else - printk("%s: %sHigh byte termination " - "Enabled\n", ahc_name(ahc), - enableSEC_high ? "Secondary " - : ""); - } - } - - sum = internal50_present + internal68_present - + externalcable_present; - if (sum < 2 || (enableSEC_low != 0)) { - if ((ahc->features & AHC_ULTRA2) != 0) - brddat |= BRDDAT5; - else - *sxfrctl1 |= STPWEN; - if (bootverbose) { - if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) - printk("%s: 50 pin termination " - "Enabled\n", ahc_name(ahc)); - else - printk("%s: %sLow byte termination " - "Enabled\n", ahc_name(ahc), - enableSEC_low ? "Secondary " - : ""); - } - } - - if (enablePRI_low != 0) { - *sxfrctl1 |= STPWEN; - if (bootverbose) - printk("%s: Primary Low Byte termination " - "Enabled\n", ahc_name(ahc)); - } - - /* - * Setup STPWEN before setting up the rest of - * the termination per the tech note on the U160 cards. - */ - ahc_outb(ahc, SXFRCTL1, *sxfrctl1); - - if (enablePRI_high != 0) { - brddat |= BRDDAT4; - if (bootverbose) - printk("%s: Primary High Byte " - "termination Enabled\n", - ahc_name(ahc)); - } - - write_brdctl(ahc, brddat); - - } else { - if ((adapter_control & CFSTERM) != 0) { - *sxfrctl1 |= STPWEN; - - if (bootverbose) - printk("%s: %sLow byte termination Enabled\n", - ahc_name(ahc), - (ahc->features & AHC_ULTRA2) ? "Primary " - : ""); - } - - if ((adapter_control & CFWSTERM) != 0 - && (ahc->features & AHC_WIDE) != 0) { - brddat |= BRDDAT6; - if (bootverbose) - printk("%s: %sHigh byte termination Enabled\n", - ahc_name(ahc), - (ahc->features & AHC_ULTRA2) - ? "Secondary " : ""); - } - - /* - * Setup STPWEN before setting up the rest of - * the termination per the tech note on the U160 cards. - */ - ahc_outb(ahc, SXFRCTL1, *sxfrctl1); - - if ((ahc->features & AHC_WIDE) != 0) - write_brdctl(ahc, brddat); - } - SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */ -} - -static void -ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low, - int *enableSEC_high, int *enablePRI_low, - int *enablePRI_high, int *eeprom_present) -{ - uint8_t brdctl; - - /* - * BRDDAT7 = Eeprom - * BRDDAT6 = Enable Secondary High Byte termination - * BRDDAT5 = Enable Secondary Low Byte termination - * BRDDAT4 = Enable Primary high byte termination - * BRDDAT3 = Enable Primary low byte termination - */ - brdctl = read_brdctl(ahc); - *eeprom_present = brdctl & BRDDAT7; - *enableSEC_high = (brdctl & BRDDAT6); - *enableSEC_low = (brdctl & BRDDAT5); - *enablePRI_high = (brdctl & BRDDAT4); - *enablePRI_low = (brdctl & BRDDAT3); -} - -static void -aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present, - int *internal68_present, int *externalcable_present, - int *eeprom_present) -{ - uint8_t brdctl; - - /* - * First read the status of our cables. - * Set the rom bank to 0 since the - * bank setting serves as a multiplexor - * for the cable detection logic. - * BRDDAT5 controls the bank switch. - */ - write_brdctl(ahc, 0); - - /* - * Now read the state of the internal - * connectors. BRDDAT6 is INT50 and - * BRDDAT7 is INT68. - */ - brdctl = read_brdctl(ahc); - *internal50_present = (brdctl & BRDDAT6) ? 0 : 1; - *internal68_present = (brdctl & BRDDAT7) ? 0 : 1; - - /* - * Set the rom bank to 1 and determine - * the other signals. - */ - write_brdctl(ahc, BRDDAT5); - - /* - * Now read the state of the external - * connectors. BRDDAT6 is EXT68 and - * BRDDAT7 is EPROMPS. - */ - brdctl = read_brdctl(ahc); - *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; - *eeprom_present = (brdctl & BRDDAT7) ? 1 : 0; -} - -static void -aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present, - int *externalcable_present, int *eeprom_present) -{ - uint8_t brdctl; - uint8_t spiocap; - - spiocap = ahc_inb(ahc, SPIOCAP); - spiocap &= ~SOFTCMDEN; - spiocap |= EXT_BRDCTL; - ahc_outb(ahc, SPIOCAP, spiocap); - ahc_outb(ahc, BRDCTL, BRDRW|BRDCS); - ahc_flush_device_writes(ahc); - ahc_delay(500); - ahc_outb(ahc, BRDCTL, 0); - ahc_flush_device_writes(ahc); - ahc_delay(500); - brdctl = ahc_inb(ahc, BRDCTL); - *internal50_present = (brdctl & BRDDAT5) ? 0 : 1; - *externalcable_present = (brdctl & BRDDAT6) ? 0 : 1; - *eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0; -} - -int -ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd) -{ - int wait; - - if ((ahc->features & AHC_SPIOCAP) != 0 - && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0) - return (0); - - /* - * Request access of the memory port. When access is - * granted, SEERDY will go high. We use a 1 second - * timeout which should be near 1 second more than - * is needed. Reason: after the chip reset, there - * should be no contention. - */ - SEEPROM_OUTB(sd, sd->sd_MS); - wait = 1000; /* 1 second timeout in msec */ - while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) { - ahc_delay(1000); /* delay 1 msec */ - } - if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) { - SEEPROM_OUTB(sd, 0); - return (0); - } - return(1); -} - -void -ahc_release_seeprom(struct seeprom_descriptor *sd) -{ - /* Release access to the memory port and the serial EEPROM. */ - SEEPROM_OUTB(sd, 0); -} - -static void -write_brdctl(struct ahc_softc *ahc, uint8_t value) -{ - uint8_t brdctl; - - if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - brdctl = BRDSTB; - if (ahc->channel == 'B') - brdctl |= BRDCS; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - brdctl = 0; - } else { - brdctl = BRDSTB|BRDCS; - } - ahc_outb(ahc, BRDCTL, brdctl); - ahc_flush_device_writes(ahc); - brdctl |= value; - ahc_outb(ahc, BRDCTL, brdctl); - ahc_flush_device_writes(ahc); - if ((ahc->features & AHC_ULTRA2) != 0) - brdctl |= BRDSTB_ULTRA2; - else - brdctl &= ~BRDSTB; - ahc_outb(ahc, BRDCTL, brdctl); - ahc_flush_device_writes(ahc); - if ((ahc->features & AHC_ULTRA2) != 0) - brdctl = 0; - else - brdctl &= ~BRDCS; - ahc_outb(ahc, BRDCTL, brdctl); -} - -static uint8_t -read_brdctl(struct ahc_softc *ahc) -{ - uint8_t brdctl; - uint8_t value; - - if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - brdctl = BRDRW; - if (ahc->channel == 'B') - brdctl |= BRDCS; - } else if ((ahc->features & AHC_ULTRA2) != 0) { - brdctl = BRDRW_ULTRA2; - } else { - brdctl = BRDRW|BRDCS; - } - ahc_outb(ahc, BRDCTL, brdctl); - ahc_flush_device_writes(ahc); - value = ahc_inb(ahc, BRDCTL); - ahc_outb(ahc, BRDCTL, 0); - return (value); -} - -static void -ahc_pci_intr(struct ahc_softc *ahc) -{ - u_int error; - u_int status1; - - error = ahc_inb(ahc, ERROR); - if ((error & PCIERRSTAT) == 0) - return; - - status1 = ahc_pci_read_config(ahc->dev_softc, - PCIR_STATUS + 1, /*bytes*/1); - - printk("%s: PCI error Interrupt at seqaddr = 0x%x\n", - ahc_name(ahc), - ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8)); - - if (status1 & DPE) { - ahc->pci_target_perr_count++; - printk("%s: Data Parity Error Detected during address " - "or write data phase\n", ahc_name(ahc)); - } - if (status1 & SSE) { - printk("%s: Signal System Error Detected\n", ahc_name(ahc)); - } - if (status1 & RMA) { - printk("%s: Received a Master Abort\n", ahc_name(ahc)); - } - if (status1 & RTA) { - printk("%s: Received a Target Abort\n", ahc_name(ahc)); - } - if (status1 & STA) { - printk("%s: Signaled a Target Abort\n", ahc_name(ahc)); - } - if (status1 & DPR) { - printk("%s: Data Parity Error has been reported via PERR#\n", - ahc_name(ahc)); - } - - /* Clear latched errors. */ - ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, - status1, /*bytes*/1); - - if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) { - printk("%s: Latched PCIERR interrupt with " - "no status bits set\n", ahc_name(ahc)); - } else { - ahc_outb(ahc, CLRINT, CLRPARERR); - } - - if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) { - printk( -"%s: WARNING WARNING WARNING WARNING\n" -"%s: Too many PCI parity errors observed as a target.\n" -"%s: Some device on this bus is generating bad parity.\n" -"%s: This is an error *observed by*, not *generated by*, this controller.\n" -"%s: PCI parity error checking has been disabled.\n" -"%s: WARNING WARNING WARNING WARNING\n", - ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), - ahc_name(ahc), ahc_name(ahc), ahc_name(ahc)); - ahc->seqctl |= FAILDIS; - ahc_outb(ahc, SEQCTL, ahc->seqctl); - } - ahc_unpause(ahc); -} - -static int -ahc_pci_chip_init(struct ahc_softc *ahc) -{ - ahc_outb(ahc, DSCOMMAND0, ahc->bus_softc.pci_softc.dscommand0); - ahc_outb(ahc, DSPCISTATUS, ahc->bus_softc.pci_softc.dspcistatus); - if ((ahc->features & AHC_DT) != 0) { - u_int sfunct; - - sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE; - ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE); - ahc_outb(ahc, OPTIONMODE, ahc->bus_softc.pci_softc.optionmode); - ahc_outw(ahc, TARGCRCCNT, ahc->bus_softc.pci_softc.targcrccnt); - ahc_outb(ahc, SFUNCT, sfunct); - ahc_outb(ahc, CRCCONTROL1, - ahc->bus_softc.pci_softc.crccontrol1); - } - if ((ahc->features & AHC_MULTI_FUNC) != 0) - ahc_outb(ahc, SCBBADDR, ahc->bus_softc.pci_softc.scbbaddr); - - if ((ahc->features & AHC_ULTRA2) != 0) - ahc_outb(ahc, DFF_THRSH, ahc->bus_softc.pci_softc.dff_thrsh); - - return (ahc_chip_init(ahc)); -} - -#ifdef CONFIG_PM -void -ahc_pci_resume(struct ahc_softc *ahc) -{ - /* - * We assume that the OS has restored our register - * mappings, etc. Just update the config space registers - * that the OS doesn't know about and rely on our chip - * reset handler to handle the rest. - */ - ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, - ahc->bus_softc.pci_softc.devconfig, /*bytes*/4); - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, - ahc->bus_softc.pci_softc.command, /*bytes*/1); - ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, - ahc->bus_softc.pci_softc.csize_lattime, /*bytes*/1); - if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) { - struct seeprom_descriptor sd; - u_int sxfrctl1; - - sd.sd_ahc = ahc; - sd.sd_control_offset = SEECTL; - sd.sd_status_offset = SEECTL; - sd.sd_dataout_offset = SEECTL; - - ahc_acquire_seeprom(ahc, &sd); - configure_termination(ahc, &sd, - ahc->seep_config->adapter_control, - &sxfrctl1); - ahc_release_seeprom(&sd); - } -} -#endif - -static int -ahc_aic785X_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - uint8_t rev; - - pci = ahc->dev_softc; - ahc->channel = 'A'; - ahc->chip = AHC_AIC7850; - ahc->features = AHC_AIC7850_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); - if (rev >= 1) - ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; - ahc->instruction_ram_size = 512; - return (0); -} - -static int -ahc_aic7860_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - uint8_t rev; - - pci = ahc->dev_softc; - ahc->channel = 'A'; - ahc->chip = AHC_AIC7860; - ahc->features = AHC_AIC7860_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); - if (rev >= 1) - ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; - ahc->instruction_ram_size = 512; - return (0); -} - -static int -ahc_apa1480_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7860_setup(ahc); - if (error != 0) - return (error); - ahc->features |= AHC_REMOVABLE; - return (0); -} - -static int -ahc_aic7870_setup(struct ahc_softc *ahc) -{ - - ahc->channel = 'A'; - ahc->chip = AHC_AIC7870; - ahc->features = AHC_AIC7870_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - ahc->instruction_ram_size = 512; - return (0); -} - -static int -ahc_aic7870h_setup(struct ahc_softc *ahc) -{ - int error = ahc_aic7870_setup(ahc); - - ahc->features |= AHC_HVD; - - return error; -} - -static int -ahc_aha394X_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7870_setup(ahc); - if (error == 0) - error = ahc_aha394XX_setup(ahc); - return (error); -} - -static int -ahc_aha394Xh_setup(struct ahc_softc *ahc) -{ - int error = ahc_aha394X_setup(ahc); - - ahc->features |= AHC_HVD; - - return error; -} - -static int -ahc_aha398X_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7870_setup(ahc); - if (error == 0) - error = ahc_aha398XX_setup(ahc); - return (error); -} - -static int -ahc_aha494X_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7870_setup(ahc); - if (error == 0) - error = ahc_aha494XX_setup(ahc); - return (error); -} - -static int -ahc_aha494Xh_setup(struct ahc_softc *ahc) -{ - int error = ahc_aha494X_setup(ahc); - - ahc->features |= AHC_HVD; - - return error; -} - -static int -ahc_aic7880_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - uint8_t rev; - - pci = ahc->dev_softc; - ahc->channel = 'A'; - ahc->chip = AHC_AIC7880; - ahc->features = AHC_AIC7880_FE; - ahc->bugs |= AHC_TMODE_WIDEODD_BUG; - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); - if (rev >= 1) { - ahc->bugs |= AHC_PCI_2_1_RETRY_BUG; - } else { - ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG; - } - ahc->instruction_ram_size = 512; - return (0); -} - -static int -ahc_aic7880h_setup(struct ahc_softc *ahc) -{ - int error = ahc_aic7880_setup(ahc); - - ahc->features |= AHC_HVD; - - return error; -} - - -static int -ahc_aha2940Pro_setup(struct ahc_softc *ahc) -{ - - ahc->flags |= AHC_INT50_SPEEDFLEX; - return (ahc_aic7880_setup(ahc)); -} - -static int -ahc_aha394XU_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7880_setup(ahc); - if (error == 0) - error = ahc_aha394XX_setup(ahc); - return (error); -} - -static int -ahc_aha394XUh_setup(struct ahc_softc *ahc) -{ - int error = ahc_aha394XU_setup(ahc); - - ahc->features |= AHC_HVD; - - return error; -} - -static int -ahc_aha398XU_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7880_setup(ahc); - if (error == 0) - error = ahc_aha398XX_setup(ahc); - return (error); -} - -static int -ahc_aic7890_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - uint8_t rev; - - pci = ahc->dev_softc; - ahc->channel = 'A'; - ahc->chip = AHC_AIC7890; - ahc->features = AHC_AIC7890_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); - if (rev == 0) - ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG; - ahc->instruction_ram_size = 768; - return (0); -} - -static int -ahc_aic7892_setup(struct ahc_softc *ahc) -{ - - ahc->channel = 'A'; - ahc->chip = AHC_AIC7892; - ahc->features = AHC_AIC7892_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG; - ahc->instruction_ram_size = 1024; - return (0); -} - -static int -ahc_aic7895_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - uint8_t rev; - - pci = ahc->dev_softc; - ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; - /* - * The 'C' revision of the aic7895 has a few additional features. - */ - rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1); - if (rev >= 4) { - ahc->chip = AHC_AIC7895C; - ahc->features = AHC_AIC7895C_FE; - } else { - u_int command; - - ahc->chip = AHC_AIC7895; - ahc->features = AHC_AIC7895_FE; - - /* - * The BIOS disables the use of MWI transactions - * since it does not have the MWI bug work around - * we have. Disabling MWI reduces performance, so - * turn it on again. - */ - command = ahc_pci_read_config(pci, PCIR_COMMAND, /*bytes*/1); - command |= PCIM_CMD_MWRICEN; - ahc_pci_write_config(pci, PCIR_COMMAND, command, /*bytes*/1); - ahc->bugs |= AHC_PCI_MWI_BUG; - } - /* - * XXX Does CACHETHEN really not work??? What about PCI retry? - * on C level chips. Need to test, but for now, play it safe. - */ - ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG - | AHC_CACHETHEN_BUG; - -#if 0 - uint32_t devconfig; - - /* - * Cachesize must also be zero due to stray DAC - * problem when sitting behind some bridges. - */ - ahc_pci_write_config(pci, CSIZE_LATTIME, 0, /*bytes*/1); - devconfig = ahc_pci_read_config(pci, DEVCONFIG, /*bytes*/1); - devconfig |= MRDCEN; - ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1); -#endif - ahc->flags |= AHC_NEWEEPROM_FMT; - ahc->instruction_ram_size = 512; - return (0); -} - -static int -ahc_aic7895h_setup(struct ahc_softc *ahc) -{ - int error = ahc_aic7895_setup(ahc); - - ahc->features |= AHC_HVD; - - return error; -} - -static int -ahc_aic7896_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - - pci = ahc->dev_softc; - ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; - ahc->chip = AHC_AIC7896; - ahc->features = AHC_AIC7896_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - ahc->bugs |= AHC_CACHETHEN_DIS_BUG; - ahc->instruction_ram_size = 768; - return (0); -} - -static int -ahc_aic7899_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - - pci = ahc->dev_softc; - ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A'; - ahc->chip = AHC_AIC7899; - ahc->features = AHC_AIC7899_FE; - ahc->flags |= AHC_NEWEEPROM_FMT; - ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG; - ahc->instruction_ram_size = 1024; - return (0); -} - -static int -ahc_aha29160C_setup(struct ahc_softc *ahc) -{ - int error; - - error = ahc_aic7899_setup(ahc); - if (error != 0) - return (error); - ahc->features |= AHC_REMOVABLE; - return (0); -} - -static int -ahc_raid_setup(struct ahc_softc *ahc) -{ - printk("RAID functionality unsupported\n"); - return (ENXIO); -} - -static int -ahc_aha394XX_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - - pci = ahc->dev_softc; - switch (ahc_get_pci_slot(pci)) { - case AHC_394X_SLOT_CHANNEL_A: - ahc->channel = 'A'; - break; - case AHC_394X_SLOT_CHANNEL_B: - ahc->channel = 'B'; - break; - default: - printk("adapter at unexpected slot %d\n" - "unable to map to a channel\n", - ahc_get_pci_slot(pci)); - ahc->channel = 'A'; - } - return (0); -} - -static int -ahc_aha398XX_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - - pci = ahc->dev_softc; - switch (ahc_get_pci_slot(pci)) { - case AHC_398X_SLOT_CHANNEL_A: - ahc->channel = 'A'; - break; - case AHC_398X_SLOT_CHANNEL_B: - ahc->channel = 'B'; - break; - case AHC_398X_SLOT_CHANNEL_C: - ahc->channel = 'C'; - break; - default: - printk("adapter at unexpected slot %d\n" - "unable to map to a channel\n", - ahc_get_pci_slot(pci)); - ahc->channel = 'A'; - break; - } - ahc->flags |= AHC_LARGE_SEEPROM; - return (0); -} - -static int -ahc_aha494XX_setup(struct ahc_softc *ahc) -{ - ahc_dev_softc_t pci; - - pci = ahc->dev_softc; - switch (ahc_get_pci_slot(pci)) { - case AHC_494X_SLOT_CHANNEL_A: - ahc->channel = 'A'; - break; - case AHC_494X_SLOT_CHANNEL_B: - ahc->channel = 'B'; - break; - case AHC_494X_SLOT_CHANNEL_C: - ahc->channel = 'C'; - break; - case AHC_494X_SLOT_CHANNEL_D: - ahc->channel = 'D'; - break; - default: - printk("adapter at unexpected slot %d\n" - "unable to map to a channel\n", - ahc_get_pci_slot(pci)); - ahc->channel = 'A'; - } - ahc->flags |= AHC_LARGE_SEEPROM; - return (0); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.h deleted file mode 100644 index 263f85da..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_pci.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id$ - * - */ -#ifndef _AIC7XXX_PCI_H_ -#define _AIC7XXX_PCI_H_ - -#define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull -#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull -#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull -#define ID_9005_SISL_MASK 0x000FFFFF00000000ull -#define ID_9005_SISL_ID 0x0005900500000000ull -#define ID_AIC7850 0x5078900400000000ull -#define ID_AHA_2902_04_10_15_20C_30C 0x5078900478509004ull -#define ID_AIC7855 0x5578900400000000ull -#define ID_AIC7859 0x3860900400000000ull -#define ID_AHA_2930CU 0x3860900438699004ull -#define ID_AIC7860 0x6078900400000000ull -#define ID_AIC7860C 0x6078900478609004ull -#define ID_AHA_1480A 0x6075900400000000ull -#define ID_AHA_2940AU_0 0x6178900400000000ull -#define ID_AHA_2940AU_1 0x6178900478619004ull -#define ID_AHA_2940AU_CN 0x2178900478219004ull -#define ID_AHA_2930C_VAR 0x6038900438689004ull - -#define ID_AIC7870 0x7078900400000000ull -#define ID_AHA_2940 0x7178900400000000ull -#define ID_AHA_3940 0x7278900400000000ull -#define ID_AHA_398X 0x7378900400000000ull -#define ID_AHA_2944 0x7478900400000000ull -#define ID_AHA_3944 0x7578900400000000ull -#define ID_AHA_4944 0x7678900400000000ull - -#define ID_AIC7880 0x8078900400000000ull -#define ID_AIC7880_B 0x8078900478809004ull -#define ID_AHA_2940U 0x8178900400000000ull -#define ID_AHA_3940U 0x8278900400000000ull -#define ID_AHA_2944U 0x8478900400000000ull -#define ID_AHA_3944U 0x8578900400000000ull -#define ID_AHA_398XU 0x8378900400000000ull -#define ID_AHA_4944U 0x8678900400000000ull -#define ID_AHA_2940UB 0x8178900478819004ull -#define ID_AHA_2930U 0x8878900478889004ull -#define ID_AHA_2940U_PRO 0x8778900478879004ull -#define ID_AHA_2940U_CN 0x0078900478009004ull - -#define ID_AIC7895 0x7895900478959004ull -#define ID_AIC7895_ARO 0x7890900478939004ull -#define ID_AIC7895_ARO_MASK 0xFFF0FFFFFFFFFFFFull -#define ID_AHA_2940U_DUAL 0x7895900478919004ull -#define ID_AHA_3940AU 0x7895900478929004ull -#define ID_AHA_3944AU 0x7895900478949004ull - -#define ID_AIC7890 0x001F9005000F9005ull -#define ID_AIC7890_ARO 0x00139005000F9005ull -#define ID_AAA_131U2 0x0013900500039005ull -#define ID_AHA_2930U2 0x0011900501819005ull -#define ID_AHA_2940U2B 0x00109005A1009005ull -#define ID_AHA_2940U2_OEM 0x0010900521809005ull -#define ID_AHA_2940U2 0x00109005A1809005ull -#define ID_AHA_2950U2B 0x00109005E1009005ull - -#define ID_AIC7892 0x008F9005FFFF9005ull -#define ID_AIC7892_ARO 0x00839005FFFF9005ull -#define ID_AHA_29160 0x00809005E2A09005ull -#define ID_AHA_29160_CPQ 0x00809005E2A00E11ull -#define ID_AHA_29160N 0x0080900562A09005ull -#define ID_AHA_29160C 0x0080900562209005ull -#define ID_AHA_29160B 0x00809005E2209005ull -#define ID_AHA_19160B 0x0081900562A19005ull -#define ID_AHA_2915_30LP 0x0082900502109005ull - -#define ID_AIC7896 0x005F9005FFFF9005ull -#define ID_AIC7896_ARO 0x00539005FFFF9005ull -#define ID_AHA_3950U2B_0 0x00509005FFFF9005ull -#define ID_AHA_3950U2B_1 0x00509005F5009005ull -#define ID_AHA_3950U2D_0 0x00519005FFFF9005ull -#define ID_AHA_3950U2D_1 0x00519005B5009005ull - -#define ID_AIC7899 0x00CF9005FFFF9005ull -#define ID_AIC7899_ARO 0x00C39005FFFF9005ull -#define ID_AHA_3960D 0x00C09005F6209005ull -#define ID_AHA_3960D_CPQ 0x00C09005F6200E11ull - -#define ID_AIC7810 0x1078900400000000ull -#define ID_AIC7815 0x7815900400000000ull - -#endif /* _AIC7XXX_PCI_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_proc.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_proc.c deleted file mode 100644 index f2525f8e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Copyright (c) 2000-2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * String handling code courtesy of Gerard Roudier's - * sym driver. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#29 $ - */ -#include "aic7xxx_osm.h" -#include "aic7xxx_inline.h" -#include "aic7xxx_93cx6.h" - -static void copy_mem_info(struct info_str *info, char *data, int len); -static int copy_info(struct info_str *info, char *fmt, ...); -static void ahc_dump_target_state(struct ahc_softc *ahc, - struct info_str *info, - u_int our_id, char channel, - u_int target_id, u_int target_offset); -static void ahc_dump_device_state(struct info_str *info, - struct scsi_device *dev); -static int ahc_proc_write_seeprom(struct ahc_softc *ahc, - char *buffer, int length); - -/* - * Table of syncrates that don't follow the "divisible by 4" - * rule. This table will be expanded in future SCSI specs. - */ -static const struct { - u_int period_factor; - u_int period; /* in 100ths of ns */ -} scsi_syncrates[] = { - { 0x08, 625 }, /* FAST-160 */ - { 0x09, 1250 }, /* FAST-80 */ - { 0x0a, 2500 }, /* FAST-40 40MHz */ - { 0x0b, 3030 }, /* FAST-40 33MHz */ - { 0x0c, 5000 } /* FAST-20 */ -}; - -/* - * Return the frequency in kHz corresponding to the given - * sync period factor. - */ -static u_int -ahc_calc_syncsrate(u_int period_factor) -{ - int i; - - /* See if the period is in the "exception" table */ - for (i = 0; i < ARRAY_SIZE(scsi_syncrates); i++) { - - if (period_factor == scsi_syncrates[i].period_factor) { - /* Period in kHz */ - return (100000000 / scsi_syncrates[i].period); - } - } - - /* - * Wasn't in the table, so use the standard - * 4 times conversion. - */ - return (10000000 / (period_factor * 4 * 10)); -} - - -static void -copy_mem_info(struct info_str *info, char *data, int len) -{ - if (info->pos + len > info->offset + info->length) - len = info->offset + info->length - info->pos; - - if (info->pos + len < info->offset) { - info->pos += len; - return; - } - - if (info->pos < info->offset) { - off_t partial; - - partial = info->offset - info->pos; - data += partial; - info->pos += partial; - len -= partial; - } - - if (len > 0) { - memcpy(info->buffer, data, len); - info->pos += len; - info->buffer += len; - } -} - -static int -copy_info(struct info_str *info, char *fmt, ...) -{ - va_list args; - char buf[256]; - int len; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - copy_mem_info(info, buf, len); - return (len); -} - -static void -ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo) -{ - u_int speed; - u_int freq; - u_int mb; - - speed = 3300; - freq = 0; - if (tinfo->offset != 0) { - freq = ahc_calc_syncsrate(tinfo->period); - speed = freq; - } - speed *= (0x01 << tinfo->width); - mb = speed / 1000; - if (mb > 0) - copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000); - else - copy_info(info, "%dKB/s transfers", speed); - - if (freq != 0) { - copy_info(info, " (%d.%03dMHz%s, offset %d", - freq / 1000, freq % 1000, - (tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0 - ? " DT" : "", tinfo->offset); - } - - if (tinfo->width > 0) { - if (freq != 0) { - copy_info(info, ", "); - } else { - copy_info(info, " ("); - } - copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width)); - } else if (freq != 0) { - copy_info(info, ")"); - } - copy_info(info, "\n"); -} - -static void -ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info, - u_int our_id, char channel, u_int target_id, - u_int target_offset) -{ - struct scsi_target *starget; - struct ahc_initiator_tinfo *tinfo; - struct ahc_tmode_tstate *tstate; - int lun; - - tinfo = ahc_fetch_transinfo(ahc, channel, our_id, - target_id, &tstate); - if ((ahc->features & AHC_TWIN) != 0) - copy_info(info, "Channel %c ", channel); - copy_info(info, "Target %d Negotiation Settings\n", target_id); - copy_info(info, "\tUser: "); - ahc_format_transinfo(info, &tinfo->user); - starget = ahc->platform_data->starget[target_offset]; - if (!starget) - return; - - copy_info(info, "\tGoal: "); - ahc_format_transinfo(info, &tinfo->goal); - copy_info(info, "\tCurr: "); - ahc_format_transinfo(info, &tinfo->curr); - - for (lun = 0; lun < AHC_NUM_LUNS; lun++) { - struct scsi_device *sdev; - - sdev = scsi_device_lookup_by_target(starget, lun); - - if (sdev == NULL) - continue; - - ahc_dump_device_state(info, sdev); - } -} - -static void -ahc_dump_device_state(struct info_str *info, struct scsi_device *sdev) -{ - struct ahc_linux_device *dev = scsi_transport_device_data(sdev); - - copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", - sdev->sdev_target->channel + 'A', - sdev->sdev_target->id, sdev->lun); - - copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); - copy_info(info, "\t\tCommands Active %d\n", dev->active); - copy_info(info, "\t\tCommand Openings %d\n", dev->openings); - copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags); - copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen); -} - -static int -ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length) -{ - struct seeprom_descriptor sd; - int have_seeprom; - u_long s; - int paused; - int written; - - /* Default to failure. */ - written = -EINVAL; - ahc_lock(ahc, &s); - paused = ahc_is_paused(ahc); - if (!paused) - ahc_pause(ahc); - - if (length != sizeof(struct seeprom_config)) { - printk("ahc_proc_write_seeprom: incorrect buffer size\n"); - goto done; - } - - have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer); - if (have_seeprom == 0) { - printk("ahc_proc_write_seeprom: cksum verification failed\n"); - goto done; - } - - sd.sd_ahc = ahc; -#if AHC_PCI_CONFIG > 0 - if ((ahc->chip & AHC_PCI) != 0) { - sd.sd_control_offset = SEECTL; - sd.sd_status_offset = SEECTL; - sd.sd_dataout_offset = SEECTL; - if (ahc->flags & AHC_LARGE_SEEPROM) - sd.sd_chip = C56_66; - else - sd.sd_chip = C46; - sd.sd_MS = SEEMS; - sd.sd_RDY = SEERDY; - sd.sd_CS = SEECS; - sd.sd_CK = SEECK; - sd.sd_DO = SEEDO; - sd.sd_DI = SEEDI; - have_seeprom = ahc_acquire_seeprom(ahc, &sd); - } else -#endif - if ((ahc->chip & AHC_VL) != 0) { - sd.sd_control_offset = SEECTL_2840; - sd.sd_status_offset = STATUS_2840; - sd.sd_dataout_offset = STATUS_2840; - sd.sd_chip = C46; - sd.sd_MS = 0; - sd.sd_RDY = EEPROM_TF; - sd.sd_CS = CS_2840; - sd.sd_CK = CK_2840; - sd.sd_DO = DO_2840; - sd.sd_DI = DI_2840; - have_seeprom = TRUE; - } else { - printk("ahc_proc_write_seeprom: unsupported adapter type\n"); - goto done; - } - - if (!have_seeprom) { - printk("ahc_proc_write_seeprom: No Serial EEPROM\n"); - goto done; - } else { - u_int start_addr; - - if (ahc->seep_config == NULL) { - ahc->seep_config = kmalloc(sizeof(*ahc->seep_config), GFP_ATOMIC); - if (ahc->seep_config == NULL) { - printk("aic7xxx: Unable to allocate serial " - "eeprom buffer. Write failing\n"); - goto done; - } - } - printk("aic7xxx: Writing Serial EEPROM\n"); - start_addr = 32 * (ahc->channel - 'A'); - ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr, - sizeof(struct seeprom_config)/2); - ahc_read_seeprom(&sd, (uint16_t *)ahc->seep_config, - start_addr, sizeof(struct seeprom_config)/2); -#if AHC_PCI_CONFIG > 0 - if ((ahc->chip & AHC_VL) == 0) - ahc_release_seeprom(&sd); -#endif - written = length; - } - -done: - if (!paused) - ahc_unpause(ahc); - ahc_unlock(ahc, &s); - return (written); -} - -/* - * Return information to handle /proc support for the driver. - */ -int -ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, - off_t offset, int length, int inout) -{ - struct ahc_softc *ahc = *(struct ahc_softc **)shost->hostdata; - struct info_str info; - char ahc_info[256]; - u_int max_targ; - u_int i; - int retval; - - /* Has data been written to the file? */ - if (inout == TRUE) { - retval = ahc_proc_write_seeprom(ahc, buffer, length); - goto done; - } - - if (start) - *start = buffer; - - info.buffer = buffer; - info.length = length; - info.offset = offset; - info.pos = 0; - - copy_info(&info, "Adaptec AIC7xxx driver version: %s\n", - AIC7XXX_DRIVER_VERSION); - copy_info(&info, "%s\n", ahc->description); - ahc_controller_info(ahc, ahc_info); - copy_info(&info, "%s\n", ahc_info); - copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n", - ahc->scb_data->numscbs, AHC_NSEG); - - - if (ahc->seep_config == NULL) - copy_info(&info, "No Serial EEPROM\n"); - else { - copy_info(&info, "Serial EEPROM:\n"); - for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) { - if (((i % 8) == 0) && (i != 0)) { - copy_info(&info, "\n"); - } - copy_info(&info, "0x%.4x ", - ((uint16_t*)ahc->seep_config)[i]); - } - copy_info(&info, "\n"); - } - copy_info(&info, "\n"); - - max_targ = 16; - if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0) - max_targ = 8; - - for (i = 0; i < max_targ; i++) { - u_int our_id; - u_int target_id; - char channel; - - channel = 'A'; - our_id = ahc->our_id; - target_id = i; - if (i > 7 && (ahc->features & AHC_TWIN) != 0) { - channel = 'B'; - our_id = ahc->our_id_b; - target_id = i % 8; - } - - ahc_dump_target_state(ahc, &info, our_id, - channel, target_id, i); - } - retval = info.pos > info.offset ? info.pos - info.offset : 0; -done: - return (retval); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped deleted file mode 100644 index e821082a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped +++ /dev/null @@ -1,912 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated - * from the following source files: - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ - */ -typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); -typedef struct ahc_reg_parse_entry { - char *name; - uint8_t value; - uint8_t mask; -} ahc_reg_parse_entry_t; - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scsiseq_print; -#else -#define ahc_scsiseq_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCSISEQ", 0x00, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_sxfrctl0_print; -#else -#define ahc_sxfrctl0_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SXFRCTL0", 0x01, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scsisigi_print; -#else -#define ahc_scsisigi_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCSISIGI", 0x03, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scsirate_print; -#else -#define ahc_scsirate_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCSIRATE", 0x04, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_sstat0_print; -#else -#define ahc_sstat0_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SSTAT0", 0x0b, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_sstat1_print; -#else -#define ahc_sstat1_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SSTAT1", 0x0c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_sstat2_print; -#else -#define ahc_sstat2_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SSTAT2", 0x0d, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_sstat3_print; -#else -#define ahc_sstat3_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SSTAT3", 0x0e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_simode0_print; -#else -#define ahc_simode0_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SIMODE0", 0x10, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_simode1_print; -#else -#define ahc_simode1_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SIMODE1", 0x11, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scsibusl_print; -#else -#define ahc_scsibusl_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCSIBUSL", 0x12, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_sblkctl_print; -#else -#define ahc_sblkctl_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SBLKCTL", 0x1f, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_seq_flags_print; -#else -#define ahc_seq_flags_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SEQ_FLAGS", 0x3c, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_lastphase_print; -#else -#define ahc_lastphase_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "LASTPHASE", 0x3f, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_seqctl_print; -#else -#define ahc_seqctl_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SEQCTL", 0x60, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_sram_base_print; -#else -#define ahc_sram_base_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SRAM_BASE", 0x70, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_error_print; -#else -#define ahc_error_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "ERROR", 0x92, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_dfcntrl_print; -#else -#define ahc_dfcntrl_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "DFCNTRL", 0x93, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_dfstatus_print; -#else -#define ahc_dfstatus_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "DFSTATUS", 0x94, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scsiphase_print; -#else -#define ahc_scsiphase_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCSIPHASE", 0x9e, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scb_base_print; -#else -#define ahc_scb_base_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCB_BASE", 0xa0, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scb_control_print; -#else -#define ahc_scb_control_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCB_CONTROL", 0xb8, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scb_scsiid_print; -#else -#define ahc_scb_scsiid_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCB_SCSIID", 0xb9, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scb_lun_print; -#else -#define ahc_scb_lun_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCB_LUN", 0xba, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_scb_tag_print; -#else -#define ahc_scb_tag_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "SCB_TAG", 0xbb, regvalue, cur_col, wrap) -#endif - - -#define SCSISEQ 0x00 -#define TEMODE 0x80 -#define SCSIRSTO 0x01 - -#define SXFRCTL0 0x01 -#define DFON 0x80 -#define DFPEXP 0x40 -#define FAST20 0x20 -#define CLRSTCNT 0x10 -#define SPIOEN 0x08 -#define SCAMEN 0x04 -#define CLRCHN 0x02 - -#define SXFRCTL1 0x02 -#define STIMESEL 0x18 -#define BITBUCKET 0x80 -#define SWRAPEN 0x40 -#define ENSTIMER 0x04 -#define ACTNEGEN 0x02 -#define STPWEN 0x01 - -#define SCSISIGO 0x03 -#define CDO 0x80 -#define IOO 0x40 -#define MSGO 0x20 -#define ATNO 0x10 -#define SELO 0x08 -#define BSYO 0x04 -#define REQO 0x02 -#define ACKO 0x01 - -#define SCSISIGI 0x03 -#define P_DATAIN_DT 0x60 -#define P_DATAOUT_DT 0x20 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 - -#define SCSIRATE 0x04 -#define SXFR 0x70 -#define SOFS 0x0f -#define SXFR_ULTRA2 0x0f -#define WIDEXFER 0x80 -#define ENABLE_CRC 0x40 -#define SINGLE_EDGE 0x10 - -#define SCSIID 0x05 -#define SCSIOFFSET 0x05 -#define SOFS_ULTRA2 0x7f - -#define SCSIDATL 0x06 - -#define SCSIDATH 0x07 - -#define STCNT 0x08 - -#define OPTIONMODE 0x08 -#define OPTIONMODE_DEFAULTS 0x03 -#define AUTORATEEN 0x80 -#define AUTOACKEN 0x40 -#define ATNMGMNTEN 0x20 -#define BUSFREEREV 0x10 -#define EXPPHASEDIS 0x08 -#define SCSIDATL_IMGEN 0x04 -#define AUTO_MSGOUT_DE 0x02 -#define DIS_MSGIN_DUALEDGE 0x01 - -#define TARGCRCCNT 0x0a - -#define CLRSINT0 0x0b -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRIOERR 0x08 -#define CLRSWRAP 0x08 -#define CLRSPIORDY 0x02 - -#define SSTAT0 0x0b -#define TARGET 0x80 -#define SELDO 0x40 -#define SELDI 0x20 -#define SELINGO 0x10 -#define SWRAP 0x08 -#define IOERR 0x08 -#define SDONE 0x04 -#define SPIORDY 0x02 -#define DMADONE 0x01 - -#define CLRSINT1 0x0c -#define CLRSELTIMEO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRPHASECHG 0x02 -#define CLRREQINIT 0x01 - -#define SSTAT1 0x0c -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define PHASECHG 0x02 -#define REQINIT 0x01 - -#define SSTAT2 0x0d -#define SFCNT 0x1f -#define OVERRUN 0x80 -#define SHVALID 0x40 -#define EXP_ACTIVE 0x10 -#define CRCVALERR 0x08 -#define CRCENDERR 0x04 -#define CRCREQERR 0x02 -#define DUAL_EDGE_ERR 0x01 - -#define SSTAT3 0x0e -#define SCSICNT 0xf0 -#define U2OFFCNT 0x7f -#define OFFCNT 0x0f - -#define SCSIID_ULTRA2 0x0f - -#define SIMODE0 0x10 -#define ENSELDO 0x40 -#define ENSELDI 0x20 -#define ENSELINGO 0x10 -#define ENIOERR 0x08 -#define ENSWRAP 0x08 -#define ENSDONE 0x04 -#define ENSPIORDY 0x02 -#define ENDMADONE 0x01 - -#define SIMODE1 0x11 -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENPHASECHG 0x02 -#define ENREQINIT 0x01 - -#define SCSIBUSL 0x12 - -#define SCSIBUSH 0x13 - -#define SXFRCTL2 0x13 -#define ASYNC_SETUP 0x07 -#define AUTORSTDIS 0x10 -#define CMDDMAEN 0x08 - -#define SHADDR 0x14 - -#define SELTIMER 0x18 -#define TARGIDIN 0x18 -#define STAGE6 0x20 -#define STAGE5 0x10 -#define STAGE4 0x08 -#define STAGE3 0x04 -#define STAGE2 0x02 -#define STAGE1 0x01 - -#define SELID 0x19 -#define SELID_MASK 0xf0 -#define ONEBIT 0x08 - -#define SCAMCTL 0x1a -#define SCAMLVL 0x03 -#define ENSCAMSELO 0x80 -#define CLRSCAMSELID 0x40 -#define ALTSTIM 0x20 -#define DFLTTID 0x10 - -#define TARGID 0x1b - -#define SPIOCAP 0x1b -#define SOFT1 0x80 -#define SOFT0 0x40 -#define SOFTCMDEN 0x20 -#define EXT_BRDCTL 0x10 -#define SEEPROM 0x08 -#define EEPROM 0x04 -#define ROM 0x02 -#define SSPIOCPS 0x01 - -#define BRDCTL 0x1d -#define BRDDAT7 0x80 -#define BRDDAT6 0x40 -#define BRDDAT5 0x20 -#define BRDDAT4 0x10 -#define BRDSTB 0x10 -#define BRDDAT3 0x08 -#define BRDCS 0x08 -#define BRDDAT2 0x04 -#define BRDRW 0x04 -#define BRDRW_ULTRA2 0x02 -#define BRDCTL1 0x02 -#define BRDCTL0 0x01 -#define BRDSTB_ULTRA2 0x01 - -#define SEECTL 0x1e -#define EXTARBACK 0x80 -#define EXTARBREQ 0x40 -#define SEEMS 0x20 -#define SEERDY 0x10 -#define SEECS 0x08 -#define SEECK 0x04 -#define SEEDO 0x02 -#define SEEDI 0x01 - -#define SBLKCTL 0x1f -#define DIAGLEDEN 0x80 -#define DIAGLEDON 0x40 -#define AUTOFLUSHDIS 0x20 -#define ENAB40 0x08 -#define SELBUSB 0x08 -#define ENAB20 0x04 -#define SELWIDE 0x02 -#define XCVR 0x01 - -#define BUSY_TARGETS 0x20 -#define TARG_SCSIRATE 0x20 - -#define ULTRA_ENB 0x30 -#define CMDSIZE_TABLE 0x30 - -#define DISC_DSB 0x32 - -#define CMDSIZE_TABLE_TAIL 0x34 - -#define MWI_RESIDUAL 0x38 - -#define NEXT_QUEUED_SCB 0x39 - -#define MSG_OUT 0x3a - -#define DMAPARAMS 0x3b -#define PRELOADEN 0x80 -#define WIDEODD 0x40 -#define SCSIEN 0x20 -#define SDMAEN 0x10 -#define SDMAENACK 0x10 -#define HDMAEN 0x08 -#define HDMAENACK 0x08 -#define DIRECTION 0x04 -#define FIFOFLUSH 0x02 -#define FIFORESET 0x01 - -#define SEQ_FLAGS 0x3c -#define NOT_IDENTIFIED 0x80 -#define NO_CDB_SENT 0x40 -#define TARGET_CMD_IS_TAGGED 0x40 -#define DPHASE 0x20 -#define TARG_CMD_PENDING 0x10 -#define CMDPHASE_PENDING 0x08 -#define DPHASE_PENDING 0x04 -#define SPHASE_PENDING 0x02 -#define NO_DISCONNECT 0x01 - -#define SAVED_SCSIID 0x3d - -#define SAVED_LUN 0x3e - -#define LASTPHASE 0x3f -#define P_MESGIN 0xe0 -#define PHASE_MASK 0xe0 -#define P_STATUS 0xc0 -#define P_MESGOUT 0xa0 -#define P_COMMAND 0x80 -#define P_DATAIN 0x40 -#define P_BUSFREE 0x01 -#define P_DATAOUT 0x00 -#define CDI 0x80 -#define IOI 0x40 -#define MSGI 0x20 - -#define WAITING_SCBH 0x40 - -#define DISCONNECTED_SCBH 0x41 - -#define FREE_SCBH 0x42 - -#define COMPLETE_SCBH 0x43 - -#define HSCB_ADDR 0x44 - -#define SHARED_DATA_ADDR 0x48 - -#define KERNEL_QINPOS 0x4c - -#define QINPOS 0x4d - -#define QOUTPOS 0x4e - -#define KERNEL_TQINPOS 0x4f - -#define TQINPOS 0x50 - -#define ARG_1 0x51 -#define RETURN_1 0x51 -#define SEND_MSG 0x80 -#define SEND_SENSE 0x40 -#define SEND_REJ 0x20 -#define MSGOUT_PHASEMIS 0x10 -#define EXIT_MSG_LOOP 0x08 -#define CONT_MSG_LOOP 0x04 -#define CONT_TARG_SESSION 0x02 - -#define ARG_2 0x52 -#define RETURN_2 0x52 - -#define LAST_MSG 0x53 -#define TARG_IMMEDIATE_SCB 0x53 - -#define SCSISEQ_TEMPLATE 0x54 -#define ENSELO 0x40 -#define ENSELI 0x20 -#define ENRSELI 0x10 -#define ENAUTOATNO 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNP 0x02 - -#define HA_274_BIOSGLOBAL 0x56 -#define INITIATOR_TAG 0x56 -#define HA_274_EXTENDED_TRANS 0x01 - -#define SEQ_FLAGS2 0x57 -#define TARGET_MSG_PENDING 0x02 -#define SCB_DMA 0x01 - -#define SCSICONF 0x5a -#define HWSCSIID 0x0f -#define HSCSIID 0x07 -#define TERM_ENB 0x80 -#define RESET_SCSI 0x40 -#define ENSPCHK 0x20 - -#define INTDEF 0x5c -#define VECTOR 0x0f -#define EDGE_TRIG 0x80 - -#define HOSTCONF 0x5d - -#define HA_274_BIOSCTRL 0x5f -#define BIOSDISABLED 0x30 -#define BIOSMODE 0x30 -#define CHANNEL_B_PRIMARY 0x08 - -#define SEQCTL 0x60 -#define PERRORDIS 0x80 -#define PAUSEDIS 0x40 -#define FAILDIS 0x20 -#define FASTMODE 0x10 -#define BRKADRINTEN 0x08 -#define STEP 0x04 -#define SEQRESET 0x02 -#define LOADRAM 0x01 - -#define SEQRAM 0x61 - -#define SEQADDR0 0x62 - -#define SEQADDR1 0x63 -#define SEQADDR1_MASK 0x01 - -#define ACCUM 0x64 - -#define SINDEX 0x65 - -#define DINDEX 0x66 - -#define ALLONES 0x69 - -#define ALLZEROS 0x6a - -#define NONE 0x6a - -#define FLAGS 0x6b -#define ZERO 0x02 -#define CARRY 0x01 - -#define SINDIR 0x6c - -#define DINDIR 0x6d - -#define FUNCTION1 0x6e - -#define STACK 0x6f - -#define TARG_OFFSET 0x70 - -#define SRAM_BASE 0x70 - -#define BCTL 0x84 -#define ACE 0x08 -#define ENABLE 0x01 - -#define DSCOMMAND0 0x84 -#define CACHETHEN 0x80 -#define DPARCKEN 0x40 -#define MPARCKEN 0x20 -#define EXTREQLCK 0x10 -#define INTSCBRAMSEL 0x08 -#define RAMPS 0x04 -#define USCBSIZE32 0x02 -#define CIOPARCKEN 0x01 - -#define BUSTIME 0x85 -#define BOFF 0xf0 -#define BON 0x0f - -#define DSCOMMAND1 0x85 -#define DSLATT 0xfc -#define HADDLDSEL1 0x02 -#define HADDLDSEL0 0x01 - -#define BUSSPD 0x86 -#define DFTHRSH 0xc0 -#define DFTHRSH_75 0x80 -#define STBOFF 0x38 -#define STBON 0x07 - -#define HS_MAILBOX 0x86 -#define HOST_MAILBOX 0xf0 -#define HOST_TQINPOS 0x80 -#define SEQ_MAILBOX 0x0f - -#define DSPCISTATUS 0x86 -#define DFTHRSH_100 0xc0 - -#define HCNTRL 0x87 -#define POWRDN 0x40 -#define SWINT 0x10 -#define IRQMS 0x08 -#define PAUSE 0x04 -#define INTEN 0x02 -#define CHIPRST 0x01 -#define CHIPRSTACK 0x01 - -#define HADDR 0x88 - -#define HCNT 0x8c - -#define SCBPTR 0x90 - -#define INTSTAT 0x91 -#define SEQINT_MASK 0xf1 -#define OUT_OF_RANGE 0xe1 -#define NO_FREE_SCB 0xd1 -#define SCB_MISMATCH 0xc1 -#define MISSED_BUSFREE 0xb1 -#define MKMSG_FAILED 0xa1 -#define DATA_OVERRUN 0x91 -#define PERR_DETECTED 0x81 -#define BAD_STATUS 0x71 -#define HOST_MSG_LOOP 0x61 -#define PDATA_REINIT 0x51 -#define IGN_WIDE_RES 0x41 -#define NO_MATCH 0x31 -#define PROTO_VIOLATION 0x21 -#define SEND_REJECT 0x11 -#define INT_PEND 0x0f -#define BAD_PHASE 0x01 -#define BRKADRINT 0x08 -#define SCSIINT 0x04 -#define CMDCMPLT 0x02 -#define SEQINT 0x01 - -#define CLRINT 0x92 -#define CLRPARERR 0x10 -#define CLRBRKADRINT 0x08 -#define CLRSCSIINT 0x04 -#define CLRCMDINT 0x02 -#define CLRSEQINT 0x01 - -#define ERROR 0x92 -#define CIOPARERR 0x80 -#define PCIERRSTAT 0x40 -#define MPARERR 0x20 -#define DPARERR 0x10 -#define SQPARERR 0x08 -#define ILLOPCODE 0x04 -#define ILLSADDR 0x02 -#define ILLHADDR 0x01 - -#define DFCNTRL 0x93 - -#define DFSTATUS 0x94 -#define PRELOAD_AVAIL 0x80 -#define DFCACHETH 0x40 -#define FIFOQWDEMP 0x20 -#define MREQPEND 0x10 -#define HDONE 0x08 -#define DFTHRESH 0x04 -#define FIFOFULL 0x02 -#define FIFOEMP 0x01 - -#define DFWADDR 0x95 - -#define DFRADDR 0x97 - -#define DFDAT 0x99 - -#define SCBCNT 0x9a -#define SCBCNT_MASK 0x1f -#define SCBAUTO 0x80 - -#define QINFIFO 0x9b - -#define QINCNT 0x9c - -#define QOUTFIFO 0x9d - -#define CRCCONTROL1 0x9d -#define CRCONSEEN 0x80 -#define CRCVALCHKEN 0x40 -#define CRCENDCHKEN 0x20 -#define CRCREQCHKEN 0x10 -#define TARGCRCENDEN 0x08 -#define TARGCRCCNTEN 0x04 - -#define QOUTCNT 0x9e - -#define SCSIPHASE 0x9e -#define DATA_PHASE_MASK 0x03 -#define STATUS_PHASE 0x20 -#define COMMAND_PHASE 0x10 -#define MSG_IN_PHASE 0x08 -#define MSG_OUT_PHASE 0x04 -#define DATA_IN_PHASE 0x02 -#define DATA_OUT_PHASE 0x01 - -#define SFUNCT 0x9f -#define ALT_MODE 0x80 - -#define SCB_BASE 0xa0 - -#define SCB_CDB_PTR 0xa0 -#define SCB_RESIDUAL_DATACNT 0xa0 -#define SCB_CDB_STORE 0xa0 - -#define SCB_RESIDUAL_SGPTR 0xa4 - -#define SCB_SCSI_STATUS 0xa8 - -#define SCB_TARGET_PHASES 0xa9 - -#define SCB_TARGET_DATA_DIR 0xaa - -#define SCB_TARGET_ITAG 0xab - -#define SCB_DATAPTR 0xac - -#define SCB_DATACNT 0xb0 -#define SG_HIGH_ADDR_BITS 0x7f -#define SG_LAST_SEG 0x80 - -#define SCB_SGPTR 0xb4 -#define SG_RESID_VALID 0x04 -#define SG_FULL_RESID 0x02 -#define SG_LIST_NULL 0x01 - -#define SCB_CONTROL 0xb8 -#define SCB_TAG_TYPE 0x03 -#define STATUS_RCVD 0x80 -#define TARGET_SCB 0x80 -#define DISCENB 0x40 -#define TAG_ENB 0x20 -#define MK_MESSAGE 0x10 -#define ULTRAENB 0x08 -#define DISCONNECTED 0x04 - -#define SCB_SCSIID 0xb9 -#define TID 0xf0 -#define TWIN_TID 0x70 -#define OID 0x0f -#define TWIN_CHNLB 0x80 - -#define SCB_LUN 0xba -#define LID 0x3f -#define SCB_XFERLEN_ODD 0x80 - -#define SCB_TAG 0xbb - -#define SCB_CDB_LEN 0xbc - -#define SCB_SCSIRATE 0xbd - -#define SCB_SCSIOFFSET 0xbe - -#define SCB_NEXT 0xbf - -#define SCB_64_SPARE 0xc0 - -#define SEECTL_2840 0xc0 -#define CS_2840 0x04 -#define CK_2840 0x02 -#define DO_2840 0x01 - -#define STATUS_2840 0xc1 -#define BIOS_SEL 0x60 -#define ADSEL 0x1e -#define EEPROM_TF 0x80 -#define DI_2840 0x01 - -#define SCB_64_BTT 0xd0 - -#define CCHADDR 0xe0 - -#define CCHCNT 0xe8 - -#define CCSGRAM 0xe9 - -#define CCSGADDR 0xea - -#define CCSGCTL 0xeb -#define CCSGDONE 0x80 -#define CCSGEN 0x08 -#define SG_FETCH_NEEDED 0x02 -#define CCSGRESET 0x01 - -#define CCSCBRAM 0xec - -#define CCSCBADDR 0xed - -#define CCSCBCTL 0xee -#define CCSCBDONE 0x80 -#define ARRDONE 0x40 -#define CCARREN 0x10 -#define CCSCBEN 0x08 -#define CCSCBDIR 0x04 -#define CCSCBRESET 0x01 - -#define CCSCBCNT 0xef - -#define SCBBADDR 0xf0 - -#define CCSCBPTR 0xf1 - -#define HNSCB_QOFF 0xf4 - -#define SNSCB_QOFF 0xf6 - -#define SDSCB_QOFF 0xf8 - -#define QOFF_CTLSTA 0xfa -#define SCB_QSIZE 0x07 -#define SCB_QSIZE_256 0x06 -#define SCB_AVAIL 0x40 -#define SNSCB_ROLLOVER 0x20 -#define SDSCB_ROLLOVER 0x10 - -#define DFF_THRSH 0xfb -#define WR_DFTHRSH 0x70 -#define WR_DFTHRSH_MAX 0x70 -#define WR_DFTHRSH_90 0x60 -#define WR_DFTHRSH_85 0x50 -#define WR_DFTHRSH_75 0x40 -#define WR_DFTHRSH_63 0x30 -#define WR_DFTHRSH_50 0x20 -#define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH 0x07 -#define RD_DFTHRSH_MAX 0x07 -#define RD_DFTHRSH_90 0x06 -#define RD_DFTHRSH_85 0x05 -#define RD_DFTHRSH_75 0x04 -#define RD_DFTHRSH_63 0x03 -#define RD_DFTHRSH_50 0x02 -#define RD_DFTHRSH_25 0x01 -#define RD_DFTHRSH_MIN 0x00 -#define WR_DFTHRSH_MIN 0x00 - -#define SG_CACHE_SHADOW 0xfc -#define SG_ADDR_MASK 0xf8 -#define LAST_SEG 0x02 -#define LAST_SEG_DONE 0x01 - -#define SG_CACHE_PRE 0xfc - - -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define BUS_8_BIT 0x00 -#define TARGET_CMD_CMPLT 0xfe -#define STATUS_QUEUE_FULL 0x28 -#define STATUS_BUSY 0x08 -#define MAX_OFFSET_8BIT 0x0f -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 -#define TID_SHIFT 0x04 -#define SCB_DOWNLOAD_SIZE_64 0x30 -#define HOST_MAILBOX_SHIFT 0x04 -#define CMD_GROUP_CODE_SHIFT 0x05 -#define CCSGRAM_MAXSEGS 0x10 -#define SCB_LIST_NULL 0xff -#define SG_SIZEOF 0x08 -#define SCB_DOWNLOAD_SIZE 0x20 -#define SEQ_MAILBOX_SHIFT 0x00 -#define TARGET_DATA_IN 0x01 -#define HOST_MSG 0xff -#define MAX_OFFSET 0x7f -#define BUS_16_BIT 0x01 -#define SCB_UPLOAD_SIZE 0x20 -#define STACK_SIZE 0x04 - - -/* Downloaded Constant Definitions */ -#define INVERTED_CACHESIZE_MASK 0x03 -#define SG_PREFETCH_ADDR_MASK 0x06 -#define SG_PREFETCH_ALIGN_MASK 0x05 -#define QOUTFIFO_OFFSET 0x00 -#define SG_PREFETCH_CNT 0x04 -#define CACHESIZE_MASK 0x02 -#define QINFIFO_OFFSET 0x01 -#define DOWNLOAD_CONST_COUNT 0x07 - - -/* Exported Labels */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped deleted file mode 100644 index 9f9b8804..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped +++ /dev/null @@ -1,413 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated - * from the following source files: - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ - */ - -#include "aic7xxx_osm.h" - -static const ahc_reg_parse_entry_t SCSISEQ_parse_table[] = { - { "SCSIRSTO", 0x01, 0x01 }, - { "ENAUTOATNP", 0x02, 0x02 }, - { "ENAUTOATNI", 0x04, 0x04 }, - { "ENAUTOATNO", 0x08, 0x08 }, - { "ENRSELI", 0x10, 0x10 }, - { "ENSELI", 0x20, 0x20 }, - { "ENSELO", 0x40, 0x40 }, - { "TEMODE", 0x80, 0x80 } -}; - -int -ahc_scsiseq_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SCSISEQ_parse_table, 8, "SCSISEQ", - 0x00, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SXFRCTL0_parse_table[] = { - { "CLRCHN", 0x02, 0x02 }, - { "SCAMEN", 0x04, 0x04 }, - { "SPIOEN", 0x08, 0x08 }, - { "CLRSTCNT", 0x10, 0x10 }, - { "FAST20", 0x20, 0x20 }, - { "DFPEXP", 0x40, 0x40 }, - { "DFON", 0x80, 0x80 } -}; - -int -ahc_sxfrctl0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SXFRCTL0_parse_table, 7, "SXFRCTL0", - 0x01, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SCSISIGI_parse_table[] = { - { "ACKI", 0x01, 0x01 }, - { "REQI", 0x02, 0x02 }, - { "BSYI", 0x04, 0x04 }, - { "SELI", 0x08, 0x08 }, - { "ATNI", 0x10, 0x10 }, - { "MSGI", 0x20, 0x20 }, - { "IOI", 0x40, 0x40 }, - { "CDI", 0x80, 0x80 }, - { "P_DATAOUT", 0x00, 0x00 }, - { "P_DATAOUT_DT", 0x20, 0x20 }, - { "P_DATAIN", 0x40, 0x40 }, - { "P_DATAIN_DT", 0x60, 0x60 }, - { "P_COMMAND", 0x80, 0x80 }, - { "P_MESGOUT", 0xa0, 0xa0 }, - { "P_STATUS", 0xc0, 0xc0 }, - { "PHASE_MASK", 0xe0, 0xe0 }, - { "P_MESGIN", 0xe0, 0xe0 } -}; - -int -ahc_scsisigi_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SCSISIGI_parse_table, 17, "SCSISIGI", - 0x03, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SCSIRATE_parse_table[] = { - { "SINGLE_EDGE", 0x10, 0x10 }, - { "ENABLE_CRC", 0x40, 0x40 }, - { "WIDEXFER", 0x80, 0x80 }, - { "SXFR_ULTRA2", 0x0f, 0x0f }, - { "SOFS", 0x0f, 0x0f }, - { "SXFR", 0x70, 0x70 } -}; - -int -ahc_scsirate_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SCSIRATE_parse_table, 6, "SCSIRATE", - 0x04, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SSTAT0_parse_table[] = { - { "DMADONE", 0x01, 0x01 }, - { "SPIORDY", 0x02, 0x02 }, - { "SDONE", 0x04, 0x04 }, - { "SWRAP", 0x08, 0x08 }, - { "IOERR", 0x08, 0x08 }, - { "SELINGO", 0x10, 0x10 }, - { "SELDI", 0x20, 0x20 }, - { "SELDO", 0x40, 0x40 }, - { "TARGET", 0x80, 0x80 } -}; - -int -ahc_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SSTAT0_parse_table, 9, "SSTAT0", - 0x0b, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SSTAT1_parse_table[] = { - { "REQINIT", 0x01, 0x01 }, - { "PHASECHG", 0x02, 0x02 }, - { "SCSIPERR", 0x04, 0x04 }, - { "BUSFREE", 0x08, 0x08 }, - { "PHASEMIS", 0x10, 0x10 }, - { "SCSIRSTI", 0x20, 0x20 }, - { "ATNTARG", 0x40, 0x40 }, - { "SELTO", 0x80, 0x80 } -}; - -int -ahc_sstat1_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SSTAT1_parse_table, 8, "SSTAT1", - 0x0c, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SSTAT2_parse_table[] = { - { "DUAL_EDGE_ERR", 0x01, 0x01 }, - { "CRCREQERR", 0x02, 0x02 }, - { "CRCENDERR", 0x04, 0x04 }, - { "CRCVALERR", 0x08, 0x08 }, - { "EXP_ACTIVE", 0x10, 0x10 }, - { "SHVALID", 0x40, 0x40 }, - { "OVERRUN", 0x80, 0x80 }, - { "SFCNT", 0x1f, 0x1f } -}; - -int -ahc_sstat2_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SSTAT2_parse_table, 8, "SSTAT2", - 0x0d, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SSTAT3_parse_table[] = { - { "OFFCNT", 0x0f, 0x0f }, - { "U2OFFCNT", 0x7f, 0x7f }, - { "SCSICNT", 0xf0, 0xf0 } -}; - -int -ahc_sstat3_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SSTAT3_parse_table, 3, "SSTAT3", - 0x0e, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SIMODE0_parse_table[] = { - { "ENDMADONE", 0x01, 0x01 }, - { "ENSPIORDY", 0x02, 0x02 }, - { "ENSDONE", 0x04, 0x04 }, - { "ENSWRAP", 0x08, 0x08 }, - { "ENIOERR", 0x08, 0x08 }, - { "ENSELINGO", 0x10, 0x10 }, - { "ENSELDI", 0x20, 0x20 }, - { "ENSELDO", 0x40, 0x40 } -}; - -int -ahc_simode0_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SIMODE0_parse_table, 8, "SIMODE0", - 0x10, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SIMODE1_parse_table[] = { - { "ENREQINIT", 0x01, 0x01 }, - { "ENPHASECHG", 0x02, 0x02 }, - { "ENSCSIPERR", 0x04, 0x04 }, - { "ENBUSFREE", 0x08, 0x08 }, - { "ENPHASEMIS", 0x10, 0x10 }, - { "ENSCSIRST", 0x20, 0x20 }, - { "ENATNTARG", 0x40, 0x40 }, - { "ENSELTIMO", 0x80, 0x80 } -}; - -int -ahc_simode1_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SIMODE1_parse_table, 8, "SIMODE1", - 0x11, regvalue, cur_col, wrap)); -} - -int -ahc_scsibusl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(NULL, 0, "SCSIBUSL", - 0x12, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SBLKCTL_parse_table[] = { - { "XCVR", 0x01, 0x01 }, - { "SELWIDE", 0x02, 0x02 }, - { "ENAB20", 0x04, 0x04 }, - { "SELBUSB", 0x08, 0x08 }, - { "ENAB40", 0x08, 0x08 }, - { "AUTOFLUSHDIS", 0x20, 0x20 }, - { "DIAGLEDON", 0x40, 0x40 }, - { "DIAGLEDEN", 0x80, 0x80 } -}; - -int -ahc_sblkctl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SBLKCTL_parse_table, 8, "SBLKCTL", - 0x1f, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SEQ_FLAGS_parse_table[] = { - { "NO_DISCONNECT", 0x01, 0x01 }, - { "SPHASE_PENDING", 0x02, 0x02 }, - { "DPHASE_PENDING", 0x04, 0x04 }, - { "CMDPHASE_PENDING", 0x08, 0x08 }, - { "TARG_CMD_PENDING", 0x10, 0x10 }, - { "DPHASE", 0x20, 0x20 }, - { "NO_CDB_SENT", 0x40, 0x40 }, - { "TARGET_CMD_IS_TAGGED",0x40, 0x40 }, - { "NOT_IDENTIFIED", 0x80, 0x80 } -}; - -int -ahc_seq_flags_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SEQ_FLAGS_parse_table, 9, "SEQ_FLAGS", - 0x3c, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t LASTPHASE_parse_table[] = { - { "MSGI", 0x20, 0x20 }, - { "IOI", 0x40, 0x40 }, - { "CDI", 0x80, 0x80 }, - { "P_DATAOUT", 0x00, 0x00 }, - { "P_BUSFREE", 0x01, 0x01 }, - { "P_DATAIN", 0x40, 0x40 }, - { "P_COMMAND", 0x80, 0x80 }, - { "P_MESGOUT", 0xa0, 0xa0 }, - { "P_STATUS", 0xc0, 0xc0 }, - { "PHASE_MASK", 0xe0, 0xe0 }, - { "P_MESGIN", 0xe0, 0xe0 } -}; - -int -ahc_lastphase_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(LASTPHASE_parse_table, 11, "LASTPHASE", - 0x3f, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SEQCTL_parse_table[] = { - { "LOADRAM", 0x01, 0x01 }, - { "SEQRESET", 0x02, 0x02 }, - { "STEP", 0x04, 0x04 }, - { "BRKADRINTEN", 0x08, 0x08 }, - { "FASTMODE", 0x10, 0x10 }, - { "FAILDIS", 0x20, 0x20 }, - { "PAUSEDIS", 0x40, 0x40 }, - { "PERRORDIS", 0x80, 0x80 } -}; - -int -ahc_seqctl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SEQCTL_parse_table, 8, "SEQCTL", - 0x60, regvalue, cur_col, wrap)); -} - -int -ahc_sram_base_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(NULL, 0, "SRAM_BASE", - 0x70, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t ERROR_parse_table[] = { - { "ILLHADDR", 0x01, 0x01 }, - { "ILLSADDR", 0x02, 0x02 }, - { "ILLOPCODE", 0x04, 0x04 }, - { "SQPARERR", 0x08, 0x08 }, - { "DPARERR", 0x10, 0x10 }, - { "MPARERR", 0x20, 0x20 }, - { "PCIERRSTAT", 0x40, 0x40 }, - { "CIOPARERR", 0x80, 0x80 } -}; - -int -ahc_error_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(ERROR_parse_table, 8, "ERROR", - 0x92, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t DFCNTRL_parse_table[] = { - { "FIFORESET", 0x01, 0x01 }, - { "FIFOFLUSH", 0x02, 0x02 }, - { "DIRECTION", 0x04, 0x04 }, - { "HDMAEN", 0x08, 0x08 }, - { "HDMAENACK", 0x08, 0x08 }, - { "SDMAEN", 0x10, 0x10 }, - { "SDMAENACK", 0x10, 0x10 }, - { "SCSIEN", 0x20, 0x20 }, - { "WIDEODD", 0x40, 0x40 }, - { "PRELOADEN", 0x80, 0x80 } -}; - -int -ahc_dfcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(DFCNTRL_parse_table, 10, "DFCNTRL", - 0x93, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t DFSTATUS_parse_table[] = { - { "FIFOEMP", 0x01, 0x01 }, - { "FIFOFULL", 0x02, 0x02 }, - { "DFTHRESH", 0x04, 0x04 }, - { "HDONE", 0x08, 0x08 }, - { "MREQPEND", 0x10, 0x10 }, - { "FIFOQWDEMP", 0x20, 0x20 }, - { "DFCACHETH", 0x40, 0x40 }, - { "PRELOAD_AVAIL", 0x80, 0x80 } -}; - -int -ahc_dfstatus_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(DFSTATUS_parse_table, 8, "DFSTATUS", - 0x94, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SCSIPHASE_parse_table[] = { - { "DATA_OUT_PHASE", 0x01, 0x01 }, - { "DATA_IN_PHASE", 0x02, 0x02 }, - { "MSG_OUT_PHASE", 0x04, 0x04 }, - { "MSG_IN_PHASE", 0x08, 0x08 }, - { "COMMAND_PHASE", 0x10, 0x10 }, - { "STATUS_PHASE", 0x20, 0x20 }, - { "DATA_PHASE_MASK", 0x03, 0x03 } -}; - -int -ahc_scsiphase_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SCSIPHASE_parse_table, 7, "SCSIPHASE", - 0x9e, regvalue, cur_col, wrap)); -} - -int -ahc_scb_base_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(NULL, 0, "SCB_BASE", - 0xa0, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SCB_CONTROL_parse_table[] = { - { "DISCONNECTED", 0x04, 0x04 }, - { "ULTRAENB", 0x08, 0x08 }, - { "MK_MESSAGE", 0x10, 0x10 }, - { "TAG_ENB", 0x20, 0x20 }, - { "DISCENB", 0x40, 0x40 }, - { "TARGET_SCB", 0x80, 0x80 }, - { "STATUS_RCVD", 0x80, 0x80 }, - { "SCB_TAG_TYPE", 0x03, 0x03 } -}; - -int -ahc_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SCB_CONTROL_parse_table, 8, "SCB_CONTROL", - 0xb8, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SCB_SCSIID_parse_table[] = { - { "TWIN_CHNLB", 0x80, 0x80 }, - { "OID", 0x0f, 0x0f }, - { "TWIN_TID", 0x70, 0x70 }, - { "TID", 0xf0, 0xf0 } -}; - -int -ahc_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SCB_SCSIID_parse_table, 4, "SCB_SCSIID", - 0xb9, regvalue, cur_col, wrap)); -} - -static const ahc_reg_parse_entry_t SCB_LUN_parse_table[] = { - { "SCB_XFERLEN_ODD", 0x80, 0x80 }, - { "LID", 0x3f, 0x3f } -}; - -int -ahc_scb_lun_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(SCB_LUN_parse_table, 2, "SCB_LUN", - 0xba, regvalue, cur_col, wrap)); -} - -int -ahc_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(NULL, 0, "SCB_TAG", - 0xbb, regvalue, cur_col, wrap)); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped deleted file mode 100644 index 07e93fba..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped +++ /dev/null @@ -1,1308 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated - * from the following source files: - * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ - */ -static const uint8_t seqprog[] = { - 0xb2, 0x00, 0x00, 0x08, - 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xee, 0x59, - 0xf7, 0x01, 0x02, 0x08, - 0xff, 0x6a, 0x24, 0x08, - 0x40, 0x00, 0x40, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0x40, 0x00, 0x40, 0x68, - 0xff, 0x40, 0x3c, 0x60, - 0x08, 0x1f, 0x3e, 0x10, - 0x60, 0x0b, 0x42, 0x68, - 0x40, 0xfa, 0x12, 0x78, - 0x01, 0x4d, 0xc8, 0x30, - 0x00, 0x4c, 0x12, 0x70, - 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0xc2, 0x5e, - 0x01, 0x51, 0x20, 0x31, - 0x01, 0x57, 0xae, 0x00, - 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x14, 0x5e, - 0x01, 0x51, 0xc8, 0x30, - 0x00, 0x39, 0xc8, 0x60, - 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0xda, 0x5e, - 0x01, 0xbf, 0x72, 0x30, - 0x01, 0x40, 0x7e, 0x31, - 0x01, 0x90, 0x80, 0x30, - 0x01, 0xf6, 0xd4, 0x30, - 0x01, 0x4d, 0x9a, 0x18, - 0xfe, 0x57, 0xae, 0x08, - 0x01, 0x40, 0x20, 0x31, - 0x00, 0x65, 0xcc, 0x58, - 0x60, 0x0b, 0x40, 0x78, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x60, 0x0b, 0x00, 0x78, - 0x40, 0x0b, 0xfa, 0x68, - 0x80, 0x0b, 0xb6, 0x78, - 0x20, 0x6a, 0x16, 0x00, - 0xa4, 0x6a, 0x06, 0x00, - 0x08, 0x6a, 0x78, 0x00, - 0x01, 0x50, 0xc8, 0x30, - 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xfe, 0x5d, - 0x01, 0x6a, 0xdc, 0x01, - 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xfe, 0x5d, - 0x01, 0x6a, 0x26, 0x01, - 0xf0, 0x19, 0x7a, 0x08, - 0x0f, 0x18, 0xc8, 0x08, - 0x0f, 0x0f, 0xc8, 0x08, - 0x0f, 0x05, 0xc8, 0x08, - 0x00, 0x3d, 0x7a, 0x00, - 0x08, 0x1f, 0x6e, 0x78, - 0x80, 0x3d, 0x7a, 0x00, - 0x01, 0x3d, 0xd8, 0x31, - 0x01, 0x3d, 0x32, 0x31, - 0x10, 0x03, 0x4e, 0x79, - 0x00, 0x65, 0xf2, 0x58, - 0x80, 0x66, 0xae, 0x78, - 0x01, 0x66, 0xd8, 0x31, - 0x01, 0x66, 0x32, 0x31, - 0x3f, 0x66, 0x7c, 0x08, - 0x40, 0x66, 0x82, 0x68, - 0x01, 0x3c, 0x78, 0x00, - 0x10, 0x03, 0x9e, 0x78, - 0x00, 0x65, 0xf2, 0x58, - 0xe0, 0x66, 0xc8, 0x18, - 0x00, 0x65, 0xaa, 0x50, - 0xdd, 0x66, 0xc8, 0x18, - 0x00, 0x65, 0xaa, 0x48, - 0x01, 0x66, 0xd8, 0x31, - 0x01, 0x66, 0x32, 0x31, - 0x10, 0x03, 0x4e, 0x79, - 0x00, 0x65, 0xf2, 0x58, - 0x01, 0x66, 0xd8, 0x31, - 0x01, 0x66, 0x32, 0x31, - 0x01, 0x66, 0xac, 0x30, - 0x40, 0x3c, 0x78, 0x00, - 0xff, 0x6a, 0xd8, 0x01, - 0xff, 0x6a, 0x32, 0x01, - 0x10, 0x3c, 0x78, 0x00, - 0x02, 0x57, 0x40, 0x69, - 0x10, 0x03, 0x3e, 0x69, - 0x00, 0x65, 0x20, 0x41, - 0x02, 0x57, 0xae, 0x00, - 0x00, 0x65, 0x9e, 0x40, - 0x61, 0x6a, 0xda, 0x5e, - 0x08, 0x51, 0x20, 0x71, - 0x02, 0x0b, 0xb2, 0x78, - 0x00, 0x65, 0xae, 0x40, - 0x1a, 0x01, 0x02, 0x00, - 0xf0, 0x19, 0x7a, 0x08, - 0x0f, 0x0f, 0xc8, 0x08, - 0x0f, 0x05, 0xc8, 0x08, - 0x00, 0x3d, 0x7a, 0x00, - 0x08, 0x1f, 0xc4, 0x78, - 0x80, 0x3d, 0x7a, 0x00, - 0x20, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0xb4, 0x5e, - 0x00, 0x65, 0x12, 0x40, - 0x20, 0x11, 0xd2, 0x68, - 0x20, 0x6a, 0x18, 0x00, - 0x20, 0x11, 0x22, 0x00, - 0xf7, 0x1f, 0xca, 0x08, - 0x80, 0xb9, 0xd8, 0x78, - 0x08, 0x65, 0xca, 0x00, - 0x01, 0x65, 0x3e, 0x30, - 0x01, 0xb9, 0x1e, 0x30, - 0x7f, 0xb9, 0x0a, 0x08, - 0x01, 0xb9, 0x0a, 0x30, - 0x01, 0x54, 0xca, 0x30, - 0x80, 0xb8, 0xe6, 0x78, - 0x80, 0x65, 0xca, 0x00, - 0x01, 0x65, 0x00, 0x34, - 0x01, 0x54, 0x00, 0x34, - 0x08, 0xb8, 0xee, 0x78, - 0x20, 0x01, 0x02, 0x00, - 0x02, 0xbd, 0x08, 0x34, - 0x01, 0xbd, 0x08, 0x34, - 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0xf4, 0x78, - 0xf7, 0x01, 0x02, 0x08, - 0x01, 0x06, 0xcc, 0x34, - 0xb2, 0x00, 0x00, 0x08, - 0x01, 0x40, 0x20, 0x31, - 0x01, 0xbf, 0x80, 0x30, - 0x01, 0xb9, 0x7a, 0x30, - 0x3f, 0xba, 0x7c, 0x08, - 0x00, 0x65, 0xea, 0x58, - 0x80, 0x0b, 0xc4, 0x79, - 0x12, 0x01, 0x02, 0x00, - 0x01, 0xab, 0xac, 0x30, - 0xe4, 0x6a, 0x70, 0x5d, - 0x40, 0x6a, 0x16, 0x00, - 0x80, 0x3e, 0x86, 0x5d, - 0x20, 0xb8, 0x18, 0x79, - 0x20, 0x6a, 0x86, 0x5d, - 0x00, 0xab, 0x86, 0x5d, - 0x01, 0xa9, 0x78, 0x30, - 0x10, 0xb8, 0x20, 0x79, - 0xe4, 0x6a, 0x70, 0x5d, - 0x00, 0x65, 0xae, 0x40, - 0x10, 0x03, 0x3c, 0x69, - 0x08, 0x3c, 0x5a, 0x69, - 0x04, 0x3c, 0x92, 0x69, - 0x02, 0x3c, 0x98, 0x69, - 0x01, 0x3c, 0x44, 0x79, - 0xff, 0x6a, 0xa6, 0x00, - 0x00, 0x65, 0xa4, 0x59, - 0x00, 0x6a, 0xc2, 0x5e, - 0xff, 0x53, 0x30, 0x71, - 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x53, 0x14, 0x5e, - 0x00, 0x65, 0xea, 0x58, - 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0x18, 0x41, - 0xa4, 0x6a, 0x06, 0x00, - 0x00, 0x65, 0xf2, 0x58, - 0xfd, 0x57, 0xae, 0x08, - 0x00, 0x65, 0xae, 0x40, - 0xe4, 0x6a, 0x70, 0x5d, - 0x20, 0x3c, 0x4a, 0x79, - 0x02, 0x6a, 0x86, 0x5d, - 0x04, 0x6a, 0x86, 0x5d, - 0x01, 0x03, 0x4c, 0x69, - 0xf7, 0x11, 0x22, 0x08, - 0xff, 0x6a, 0x24, 0x08, - 0xff, 0x6a, 0x06, 0x08, - 0x01, 0x6a, 0x7e, 0x00, - 0x00, 0x65, 0xa4, 0x59, - 0x00, 0x65, 0x04, 0x40, - 0x80, 0x86, 0xc8, 0x08, - 0x01, 0x4f, 0xc8, 0x30, - 0x00, 0x50, 0x6c, 0x61, - 0xc4, 0x6a, 0x70, 0x5d, - 0x40, 0x3c, 0x68, 0x79, - 0x28, 0x6a, 0x86, 0x5d, - 0x00, 0x65, 0x4c, 0x41, - 0x08, 0x6a, 0x86, 0x5d, - 0x00, 0x65, 0x4c, 0x41, - 0x84, 0x6a, 0x70, 0x5d, - 0x00, 0x65, 0xf2, 0x58, - 0x01, 0x66, 0xc8, 0x30, - 0x01, 0x64, 0xd8, 0x31, - 0x01, 0x64, 0x32, 0x31, - 0x5b, 0x64, 0xc8, 0x28, - 0x30, 0x64, 0xca, 0x18, - 0x01, 0x6c, 0xc8, 0x30, - 0xff, 0x64, 0x8e, 0x79, - 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x80, 0x79, - 0x01, 0x64, 0x86, 0x61, - 0xf7, 0x01, 0x02, 0x08, - 0x01, 0x06, 0xd8, 0x31, - 0x01, 0x06, 0x32, 0x31, - 0xff, 0x64, 0xc8, 0x18, - 0xff, 0x64, 0x80, 0x69, - 0xf7, 0x3c, 0x78, 0x08, - 0x00, 0x65, 0x20, 0x41, - 0x40, 0xaa, 0x7e, 0x10, - 0x04, 0xaa, 0x70, 0x5d, - 0x00, 0x65, 0x58, 0x42, - 0xc4, 0x6a, 0x70, 0x5d, - 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa8, 0x86, 0x5d, - 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x86, 0x5d, - 0x00, 0x65, 0x4c, 0x41, - 0x10, 0x3c, 0xa8, 0x69, - 0x00, 0xbb, 0x8c, 0x44, - 0x18, 0x6a, 0xda, 0x01, - 0x01, 0x69, 0xd8, 0x31, - 0x1c, 0x6a, 0xd0, 0x01, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xb0, 0x79, - 0xff, 0x6a, 0xdc, 0x09, - 0x01, 0x93, 0x26, 0x01, - 0x03, 0x6a, 0x2a, 0x01, - 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xe2, 0x5d, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xaa, 0x5e, - 0x01, 0x50, 0xa0, 0x18, - 0x02, 0x6a, 0x22, 0x05, - 0x1a, 0x01, 0x02, 0x00, - 0x80, 0x6a, 0x74, 0x00, - 0x40, 0x6a, 0x78, 0x00, - 0x40, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xda, 0x5d, - 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x58, 0x7a, - 0x80, 0x64, 0xa0, 0x73, - 0xa0, 0x64, 0x02, 0x74, - 0xc0, 0x64, 0xf6, 0x73, - 0xe0, 0x64, 0x32, 0x74, - 0x01, 0x6a, 0xda, 0x5e, - 0x00, 0x65, 0xcc, 0x41, - 0xf7, 0x11, 0x22, 0x08, - 0x01, 0x06, 0xd4, 0x30, - 0xff, 0x6a, 0x24, 0x08, - 0xf7, 0x01, 0x02, 0x08, - 0xc0, 0x6a, 0x78, 0x00, - 0x09, 0x0c, 0xe8, 0x79, - 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0xda, 0x5e, - 0xff, 0x6a, 0x26, 0x09, - 0x12, 0x01, 0x02, 0x00, - 0x02, 0x6a, 0x08, 0x30, - 0xff, 0x6a, 0x08, 0x08, - 0xdf, 0x01, 0x02, 0x08, - 0x01, 0x6a, 0x7e, 0x00, - 0xc0, 0x6a, 0x78, 0x04, - 0xff, 0x6a, 0xc8, 0x08, - 0x08, 0xa4, 0x48, 0x19, - 0x00, 0xa5, 0x4a, 0x21, - 0x00, 0xa6, 0x4c, 0x21, - 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0xde, 0x7e, - 0x80, 0xeb, 0x08, 0x7a, - 0xff, 0x6a, 0xd6, 0x09, - 0x08, 0xeb, 0x0c, 0x6a, - 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0xa3, 0xde, 0x6e, - 0x88, 0xeb, 0x22, 0x72, - 0x08, 0xeb, 0xde, 0x6e, - 0x04, 0xea, 0x26, 0xe2, - 0x08, 0xee, 0xde, 0x6e, - 0x04, 0x6a, 0xd0, 0x81, - 0x05, 0xa4, 0xc0, 0x89, - 0x03, 0xa5, 0xc2, 0x31, - 0x09, 0x6a, 0xd6, 0x05, - 0x00, 0x65, 0x0a, 0x5a, - 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0xde, 0x7e, - 0x07, 0xe9, 0x10, 0x31, - 0x01, 0xe9, 0x46, 0x31, - 0x00, 0xa3, 0xbc, 0x5e, - 0x00, 0x65, 0xfc, 0x59, - 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x36, 0x7a, - 0x02, 0x65, 0xca, 0x00, - 0x01, 0x65, 0xf8, 0x31, - 0x80, 0x93, 0x26, 0x01, - 0xff, 0x6a, 0xd4, 0x0c, - 0x01, 0x8c, 0xc8, 0x30, - 0x00, 0x88, 0xc8, 0x18, - 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0xde, 0x7e, - 0xff, 0x8d, 0x4c, 0x6a, - 0xff, 0x8e, 0x4c, 0x6a, - 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0xde, 0x56, - 0x01, 0x64, 0x70, 0x30, - 0xff, 0x64, 0xc8, 0x10, - 0x01, 0x64, 0xc8, 0x18, - 0x00, 0x8c, 0x18, 0x19, - 0xff, 0x8d, 0x1a, 0x21, - 0xff, 0x8e, 0x1c, 0x25, - 0xc0, 0x3c, 0x5c, 0x7a, - 0x21, 0x6a, 0xda, 0x5e, - 0xa8, 0x6a, 0x76, 0x00, - 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x64, 0x6a, - 0x04, 0x3b, 0x76, 0x00, - 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x6c, 0x7a, - 0x51, 0x6a, 0xda, 0x5e, - 0x00, 0x65, 0x84, 0x42, - 0x20, 0x3c, 0x78, 0x00, - 0x00, 0xb3, 0xbc, 0x5e, - 0x07, 0xac, 0x10, 0x31, - 0x05, 0xb3, 0x46, 0x31, - 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xf0, 0x5d, - 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0xf4, 0x5d, - 0x00, 0x65, 0x3c, 0x5a, - 0xfd, 0xa4, 0x48, 0x09, - 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xe8, 0x5d, - 0x01, 0xa4, 0x96, 0x7a, - 0x04, 0x3b, 0x76, 0x08, - 0x01, 0x3b, 0x26, 0x31, - 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x8c, 0x7a, - 0x03, 0x9e, 0x8e, 0x6a, - 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0xda, 0x5e, - 0x00, 0x65, 0xcc, 0x41, - 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x9c, 0x7a, - 0x02, 0x65, 0xca, 0x00, - 0x01, 0x65, 0xf8, 0x31, - 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x10, 0x5a, - 0x01, 0xfc, 0xaa, 0x6a, - 0x80, 0x0b, 0xa0, 0x6a, - 0x10, 0x0c, 0xa0, 0x7a, - 0x20, 0x93, 0xa0, 0x6a, - 0x02, 0x93, 0x26, 0x01, - 0x02, 0xfc, 0xb4, 0x7a, - 0x40, 0x0d, 0xc8, 0x6a, - 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0xc8, 0x42, - 0x40, 0x0d, 0xba, 0x6a, - 0x00, 0x65, 0x10, 0x5a, - 0x00, 0x65, 0xac, 0x42, - 0x80, 0xfc, 0xc4, 0x7a, - 0x80, 0xa4, 0xc4, 0x6a, - 0xff, 0xa5, 0x4a, 0x19, - 0xff, 0xa6, 0x4c, 0x21, - 0xff, 0xa7, 0x4e, 0x21, - 0xf8, 0xfc, 0x48, 0x09, - 0x7f, 0xa3, 0x46, 0x09, - 0x04, 0x3b, 0xe4, 0x6a, - 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xca, 0x7a, - 0x01, 0x94, 0xca, 0x7a, - 0x01, 0x94, 0xca, 0x7a, - 0x01, 0x94, 0xca, 0x7a, - 0x01, 0x94, 0xca, 0x7a, - 0x01, 0xa4, 0xe2, 0x7a, - 0x01, 0xfc, 0xd8, 0x7a, - 0x01, 0x94, 0xe4, 0x6a, - 0x01, 0x94, 0xe4, 0x6a, - 0x01, 0x94, 0xe4, 0x6a, - 0x00, 0x65, 0x84, 0x42, - 0x01, 0x94, 0xe2, 0x7a, - 0x10, 0x94, 0xe4, 0x6a, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xe8, 0x6a, - 0x01, 0x85, 0x0a, 0x01, - 0x02, 0xfc, 0xf0, 0x6a, - 0x01, 0x14, 0x46, 0x31, - 0xff, 0x6a, 0x10, 0x09, - 0xfe, 0x85, 0x0a, 0x09, - 0xff, 0x38, 0xfe, 0x6a, - 0x80, 0xa3, 0xfe, 0x7a, - 0x80, 0x0b, 0xfc, 0x7a, - 0x04, 0x3b, 0xfe, 0x7a, - 0xbf, 0x3b, 0x76, 0x08, - 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x10, 0x5a, - 0x01, 0x0b, 0x0c, 0x6b, - 0x10, 0x0c, 0x00, 0x7b, - 0x04, 0x93, 0x0a, 0x6b, - 0x01, 0x94, 0x08, 0x7b, - 0x10, 0x94, 0x0a, 0x6b, - 0xc7, 0x93, 0x26, 0x09, - 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x0e, 0x6b, - 0xff, 0x08, 0x5c, 0x6b, - 0xff, 0x09, 0x5c, 0x6b, - 0xff, 0x0a, 0x5c, 0x6b, - 0xff, 0x38, 0x2a, 0x7b, - 0x04, 0x14, 0x10, 0x31, - 0x01, 0x38, 0x18, 0x31, - 0x02, 0x6a, 0x1a, 0x31, - 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xf6, 0x5d, - 0x00, 0x38, 0xe2, 0x5d, - 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x56, 0x43, - 0x80, 0xa3, 0x30, 0x7b, - 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x5c, 0x43, - 0x08, 0xeb, 0x36, 0x7b, - 0x00, 0x65, 0x10, 0x5a, - 0x08, 0xeb, 0x32, 0x6b, - 0x07, 0xe9, 0x10, 0x31, - 0x01, 0xe9, 0xca, 0x30, - 0x01, 0x65, 0x46, 0x31, - 0x00, 0x6a, 0xbc, 0x5e, - 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0xf6, 0x5d, - 0x08, 0x6a, 0xe2, 0x5d, - 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xaa, 0x5e, - 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x8c, 0x5e, - 0x01, 0x99, 0x46, 0x31, - 0x00, 0xa3, 0xbc, 0x5e, - 0x01, 0x88, 0x10, 0x31, - 0x00, 0x65, 0x3c, 0x5a, - 0x00, 0x65, 0xfc, 0x59, - 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xe8, 0x5d, - 0x80, 0x0b, 0x84, 0x6a, - 0x80, 0x0b, 0x64, 0x6b, - 0x01, 0x0c, 0x5e, 0x7b, - 0x10, 0x0c, 0x84, 0x7a, - 0x03, 0x9e, 0x84, 0x6a, - 0x00, 0x65, 0x06, 0x5a, - 0x00, 0x6a, 0xbc, 0x5e, - 0x01, 0xa4, 0x84, 0x6b, - 0xff, 0x38, 0x7a, 0x7b, - 0x01, 0x38, 0xc8, 0x30, - 0x00, 0x08, 0x40, 0x19, - 0xff, 0x6a, 0xc8, 0x08, - 0x00, 0x09, 0x42, 0x21, - 0x00, 0x0a, 0x44, 0x21, - 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x7c, 0x43, - 0x03, 0x08, 0x40, 0x31, - 0x03, 0x08, 0x40, 0x31, - 0x01, 0x08, 0x40, 0x31, - 0x01, 0x09, 0x42, 0x31, - 0x01, 0x0a, 0x44, 0x31, - 0xfd, 0xb4, 0x68, 0x09, - 0x12, 0x01, 0x02, 0x00, - 0x12, 0x01, 0x02, 0x00, - 0x04, 0x3c, 0xcc, 0x79, - 0xfb, 0x3c, 0x78, 0x08, - 0x04, 0x93, 0x20, 0x79, - 0x01, 0x0c, 0x90, 0x6b, - 0x80, 0xba, 0x20, 0x79, - 0x80, 0x04, 0x20, 0x79, - 0xe4, 0x6a, 0x70, 0x5d, - 0x23, 0x6a, 0x86, 0x5d, - 0x01, 0x6a, 0x86, 0x5d, - 0x00, 0x65, 0x20, 0x41, - 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0xa4, 0x7b, - 0x21, 0x6a, 0xda, 0x5e, - 0x01, 0xbc, 0x18, 0x31, - 0x02, 0x6a, 0x1a, 0x31, - 0x02, 0x6a, 0xf8, 0x01, - 0x01, 0xbc, 0x10, 0x30, - 0x02, 0x6a, 0x12, 0x30, - 0x01, 0xbc, 0x10, 0x30, - 0xff, 0x6a, 0x12, 0x08, - 0xff, 0x6a, 0x14, 0x08, - 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xca, 0x53, - 0x04, 0xa0, 0x10, 0x31, - 0xac, 0x6a, 0x26, 0x01, - 0x04, 0xa0, 0x10, 0x31, - 0x03, 0x08, 0x18, 0x31, - 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xf6, 0x5d, - 0x00, 0xbc, 0xe2, 0x5d, - 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xe2, 0x43, - 0xff, 0x6a, 0x10, 0x09, - 0xa4, 0x6a, 0x26, 0x01, - 0x0c, 0xa0, 0x32, 0x31, - 0x05, 0x6a, 0x26, 0x01, - 0x35, 0x6a, 0x26, 0x01, - 0x0c, 0xa0, 0x32, 0x31, - 0x36, 0x6a, 0x26, 0x01, - 0x02, 0x93, 0x26, 0x01, - 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x9e, 0x5e, - 0x00, 0x65, 0x9e, 0x5e, - 0x02, 0x93, 0x26, 0x01, - 0xbf, 0x3c, 0x78, 0x08, - 0x04, 0x0b, 0xe8, 0x6b, - 0x10, 0x0c, 0xe4, 0x7b, - 0x01, 0x03, 0xe8, 0x6b, - 0x20, 0x93, 0xea, 0x6b, - 0x04, 0x0b, 0xf0, 0x6b, - 0x40, 0x3c, 0x78, 0x00, - 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0xf2, 0x6b, - 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0x58, 0x6c, - 0x01, 0x06, 0x50, 0x31, - 0x80, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0xcc, 0x41, - 0x10, 0x3f, 0x06, 0x00, - 0x10, 0x6a, 0x06, 0x00, - 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x1e, 0x64, - 0x10, 0xb8, 0x42, 0x6c, - 0xc0, 0x3e, 0xca, 0x00, - 0x40, 0xb8, 0x0e, 0x6c, - 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x22, 0x7c, - 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xda, 0x5d, - 0xa0, 0x3f, 0x2a, 0x64, - 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xda, 0x5d, - 0xa0, 0x3f, 0x2a, 0x64, - 0x00, 0xbb, 0x22, 0x44, - 0xff, 0x65, 0x22, 0x64, - 0x00, 0x65, 0x42, 0x44, - 0x40, 0x6a, 0x18, 0x00, - 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xda, 0x5d, - 0xa0, 0x3f, 0xfe, 0x73, - 0x40, 0x6a, 0x18, 0x00, - 0x01, 0x3a, 0xa6, 0x30, - 0x08, 0x6a, 0x74, 0x00, - 0x00, 0x65, 0xcc, 0x41, - 0x64, 0x6a, 0x6a, 0x5d, - 0x80, 0x64, 0xda, 0x6c, - 0x04, 0x64, 0x9c, 0x74, - 0x02, 0x64, 0xac, 0x74, - 0x00, 0x6a, 0x62, 0x74, - 0x03, 0x64, 0xca, 0x74, - 0x23, 0x64, 0x4a, 0x74, - 0x08, 0x64, 0x5e, 0x74, - 0x61, 0x6a, 0xda, 0x5e, - 0x00, 0x65, 0xda, 0x5d, - 0x08, 0x51, 0xce, 0x71, - 0x00, 0x65, 0x42, 0x44, - 0x80, 0x04, 0x5c, 0x7c, - 0x51, 0x6a, 0x60, 0x5d, - 0x01, 0x51, 0x5c, 0x64, - 0x01, 0xa4, 0x54, 0x7c, - 0x80, 0xba, 0x5e, 0x6c, - 0x41, 0x6a, 0xda, 0x5e, - 0x00, 0x65, 0x5e, 0x44, - 0x21, 0x6a, 0xda, 0x5e, - 0x00, 0x65, 0x5e, 0x44, - 0x07, 0x6a, 0x56, 0x5d, - 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xcc, 0x41, - 0x80, 0xb8, 0x58, 0x7c, - 0xc0, 0x3c, 0x6c, 0x7c, - 0x80, 0x3c, 0x58, 0x6c, - 0xff, 0xa8, 0x6c, 0x6c, - 0x40, 0x3c, 0x58, 0x6c, - 0x10, 0xb8, 0x70, 0x7c, - 0xa1, 0x6a, 0xda, 0x5e, - 0x01, 0xb4, 0x76, 0x6c, - 0x02, 0xb4, 0x78, 0x6c, - 0x01, 0xa4, 0x78, 0x7c, - 0xff, 0xa8, 0x88, 0x7c, - 0x04, 0xb4, 0x68, 0x01, - 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x14, 0x5e, - 0xff, 0xa8, 0x88, 0x7c, - 0x71, 0x6a, 0xda, 0x5e, - 0x40, 0x51, 0x88, 0x64, - 0x00, 0x65, 0xb4, 0x5e, - 0x00, 0x65, 0xde, 0x41, - 0x00, 0xbb, 0x8c, 0x5c, - 0x00, 0x65, 0xde, 0x41, - 0x00, 0x65, 0xb4, 0x5e, - 0x01, 0x65, 0xa2, 0x30, - 0x01, 0xf8, 0xc8, 0x30, - 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0xb8, 0xdd, - 0x00, 0x51, 0xca, 0x5d, - 0x01, 0x4e, 0x9c, 0x18, - 0x02, 0x6a, 0x22, 0x05, - 0xc0, 0x3c, 0x58, 0x6c, - 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0xd6, 0x5e, - 0x20, 0xb8, 0xde, 0x69, - 0x01, 0xbb, 0xa2, 0x30, - 0x3f, 0xba, 0x7c, 0x08, - 0x00, 0xb9, 0xd0, 0x5c, - 0x00, 0x65, 0xde, 0x41, - 0x01, 0x06, 0xd4, 0x30, - 0x20, 0x3c, 0xcc, 0x79, - 0x20, 0x3c, 0x5e, 0x7c, - 0x01, 0xa4, 0xba, 0x7c, - 0x01, 0xb4, 0x68, 0x01, - 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0x5e, 0x44, - 0x04, 0x14, 0x58, 0x31, - 0x01, 0x06, 0xd4, 0x30, - 0x08, 0xa0, 0x60, 0x31, - 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xf6, 0x5d, - 0x01, 0x06, 0xd4, 0x30, - 0xa0, 0x6a, 0xee, 0x5d, - 0x00, 0x65, 0xcc, 0x41, - 0xdf, 0x3c, 0x78, 0x08, - 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0x5e, 0x44, - 0x4c, 0x65, 0xcc, 0x28, - 0x01, 0x3e, 0x20, 0x31, - 0xd0, 0x66, 0xcc, 0x18, - 0x20, 0x66, 0xcc, 0x18, - 0x01, 0x51, 0xda, 0x34, - 0x4c, 0x3d, 0xca, 0x28, - 0x3f, 0x64, 0x7c, 0x08, - 0xd0, 0x65, 0xca, 0x18, - 0x01, 0x3e, 0x20, 0x31, - 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xe8, 0x4c, - 0xe1, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xf0, 0x54, - 0xe1, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x20, 0x65, 0xca, 0x18, - 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xfa, 0x4c, - 0xe1, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x02, 0x55, - 0xe1, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0x14, 0x75, - 0x00, 0x51, 0x90, 0x5d, - 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0x36, 0x45, - 0x3f, 0xba, 0xc8, 0x08, - 0x00, 0x3e, 0x36, 0x75, - 0x00, 0x65, 0xb2, 0x5e, - 0x80, 0x3c, 0x78, 0x00, - 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xda, 0x5d, - 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x52, 0x65, - 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x52, 0x65, - 0x51, 0x6a, 0x60, 0x5d, - 0x00, 0x51, 0x90, 0x5d, - 0x51, 0x6a, 0x60, 0x5d, - 0x01, 0x51, 0x20, 0x31, - 0x04, 0x3c, 0x78, 0x00, - 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x50, 0x65, - 0x08, 0x3c, 0x78, 0x00, - 0x3f, 0xba, 0xc8, 0x08, - 0x00, 0x3e, 0x50, 0x65, - 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x50, 0x7d, - 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x46, 0x6d, - 0x01, 0x90, 0xc8, 0x30, - 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0xd0, 0x5c, - 0x01, 0x64, 0x20, 0x31, - 0xff, 0x6a, 0x78, 0x08, - 0x00, 0x65, 0xea, 0x58, - 0x10, 0xb8, 0x5e, 0x7c, - 0xff, 0x6a, 0x56, 0x5d, - 0x00, 0x65, 0x5e, 0x44, - 0x00, 0x65, 0xb2, 0x5e, - 0x31, 0x6a, 0xda, 0x5e, - 0x00, 0x65, 0x5e, 0x44, - 0x10, 0x3f, 0x06, 0x00, - 0x10, 0x6a, 0x06, 0x00, - 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0xda, 0x5e, - 0x00, 0x65, 0x62, 0x45, - 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x62, 0x7d, - 0x04, 0x0c, 0x5c, 0x6d, - 0xe0, 0x03, 0x7e, 0x08, - 0xe0, 0x3f, 0xcc, 0x61, - 0x01, 0x65, 0xcc, 0x30, - 0x01, 0x12, 0xda, 0x34, - 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x70, 0x6d, - 0x40, 0x03, 0xcc, 0x08, - 0x01, 0x65, 0x06, 0x30, - 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x7e, 0x75, - 0x40, 0x65, 0x7e, 0x7d, - 0x00, 0x65, 0x7e, 0x5d, - 0xff, 0x6a, 0xd4, 0x08, - 0xff, 0x6a, 0xd4, 0x08, - 0xff, 0x6a, 0xd4, 0x08, - 0xff, 0x6a, 0xd4, 0x0c, - 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x88, 0x7d, - 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x8c, 0x7d, - 0xf7, 0x01, 0x02, 0x0c, - 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0xb0, 0x75, - 0x01, 0x41, 0x20, 0x31, - 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0xa0, 0x45, - 0xff, 0xbf, 0xb0, 0x75, - 0x01, 0x90, 0xa4, 0x30, - 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0x9a, 0x65, - 0xff, 0x52, 0xae, 0x75, - 0x01, 0xbf, 0xcc, 0x30, - 0x01, 0x90, 0xca, 0x30, - 0x01, 0x52, 0x20, 0x31, - 0x01, 0x66, 0x7e, 0x31, - 0x01, 0x65, 0x20, 0x35, - 0x01, 0xbf, 0x82, 0x34, - 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0xc2, 0x5e, - 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x14, 0x46, - 0x01, 0x65, 0xa4, 0x30, - 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x08, 0x5e, - 0x01, 0x6a, 0xd0, 0x01, - 0x01, 0x6a, 0xdc, 0x05, - 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x08, 0x5e, - 0x01, 0x6a, 0xe2, 0x5d, - 0x01, 0x6a, 0x26, 0x05, - 0x01, 0x65, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xce, 0x7d, - 0xff, 0x6a, 0xdc, 0x0d, - 0x01, 0x65, 0x32, 0x31, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xaa, 0x46, - 0x81, 0x6a, 0xda, 0x5e, - 0x01, 0x0c, 0xda, 0x7d, - 0x04, 0x0c, 0xd8, 0x6d, - 0xe0, 0x03, 0x06, 0x08, - 0xe0, 0x03, 0x7e, 0x0c, - 0x01, 0x65, 0x18, 0x31, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x0d, - 0x01, 0x8c, 0x10, 0x30, - 0x01, 0x8d, 0x12, 0x30, - 0x01, 0x8e, 0x14, 0x34, - 0x01, 0x6c, 0xda, 0x30, - 0x01, 0x6c, 0xda, 0x30, - 0x01, 0x6c, 0xda, 0x30, - 0x01, 0x6c, 0xda, 0x30, - 0x01, 0x6c, 0xda, 0x30, - 0x01, 0x6c, 0xda, 0x30, - 0x01, 0x6c, 0xda, 0x30, - 0x01, 0x6c, 0xda, 0x34, - 0x3d, 0x64, 0xa4, 0x28, - 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x08, 0x46, - 0x2e, 0x64, 0xa4, 0x28, - 0x66, 0x64, 0xc8, 0x28, - 0x00, 0x6c, 0xda, 0x18, - 0x01, 0x52, 0xc8, 0x30, - 0x00, 0x6c, 0xda, 0x20, - 0xff, 0x6a, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0x00, 0x6c, 0xda, 0x24, - 0x01, 0x65, 0xc8, 0x30, - 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x04, 0x5e, - 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0x28, 0x7e, - 0x30, 0x6a, 0xd0, 0x01, - 0x20, 0x6a, 0xd0, 0x01, - 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0x24, 0x66, - 0x00, 0x65, 0x40, 0x46, - 0x20, 0x6a, 0xd0, 0x01, - 0x01, 0x6a, 0xdc, 0x01, - 0x20, 0xa0, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x30, 0x7e, - 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0x34, 0x66, - 0x20, 0x6a, 0xd0, 0x01, - 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x3a, 0x66, - 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x3e, 0x66, - 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x42, 0x6e, - 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x04, 0x5e, - 0x20, 0x6a, 0xe2, 0x5d, - 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x5c, 0x6e, - 0xa0, 0x6a, 0xca, 0x00, - 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x9a, 0x5e, - 0x00, 0x65, 0x54, 0x66, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xaa, 0x46, - 0xa0, 0x6a, 0xcc, 0x00, - 0xff, 0x6a, 0xc8, 0x08, - 0x20, 0x94, 0x60, 0x6e, - 0x10, 0x94, 0x62, 0x6e, - 0x08, 0x94, 0x7c, 0x6e, - 0x08, 0x94, 0x7c, 0x6e, - 0x08, 0x94, 0x7c, 0x6e, - 0xff, 0x8c, 0xc8, 0x10, - 0xc1, 0x64, 0xc8, 0x18, - 0xf8, 0x64, 0xc8, 0x08, - 0x01, 0x99, 0xda, 0x30, - 0x00, 0x66, 0x70, 0x66, - 0xc0, 0x66, 0xac, 0x76, - 0x60, 0x66, 0xc8, 0x18, - 0x3d, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x60, 0x46, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x7e, 0x6e, - 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0xaa, 0x5e, - 0x00, 0x65, 0x8a, 0x5e, - 0x00, 0x65, 0x8a, 0x5e, - 0x00, 0x65, 0x8a, 0x5e, - 0x01, 0x99, 0xda, 0x30, - 0x01, 0x99, 0xda, 0x30, - 0x01, 0x99, 0xda, 0x30, - 0x01, 0x99, 0xda, 0x30, - 0x01, 0x99, 0xda, 0x30, - 0x01, 0x99, 0xda, 0x30, - 0x01, 0x99, 0xda, 0x30, - 0x01, 0x99, 0xda, 0x34, - 0x01, 0x6c, 0x32, 0x31, - 0x01, 0x6c, 0x32, 0x31, - 0x01, 0x6c, 0x32, 0x31, - 0x01, 0x6c, 0x32, 0x31, - 0x01, 0x6c, 0x32, 0x31, - 0x01, 0x6c, 0x32, 0x31, - 0x01, 0x6c, 0x32, 0x31, - 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0xaa, 0x7e, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xae, 0x6e, - 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0xd6, 0x6e, - 0x01, 0x42, 0x7e, 0x31, - 0xff, 0x6a, 0x76, 0x01, - 0x01, 0x90, 0x84, 0x34, - 0xff, 0x6a, 0x76, 0x05, - 0x01, 0x85, 0x0a, 0x01, - 0x7f, 0x65, 0x10, 0x09, - 0xfe, 0x85, 0x0a, 0x0d, - 0xff, 0x42, 0xd2, 0x66, - 0xff, 0x41, 0xca, 0x66, - 0xd1, 0x6a, 0xda, 0x5e, - 0xff, 0x6a, 0xca, 0x04, - 0x01, 0x41, 0x20, 0x31, - 0x01, 0xbf, 0x82, 0x30, - 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x14, 0x46, - 0x01, 0x42, 0x20, 0x31, - 0x01, 0xbf, 0x84, 0x34, - 0x01, 0x41, 0x7e, 0x31, - 0x01, 0x90, 0x82, 0x34, - 0x01, 0x65, 0x22, 0x31, - 0xff, 0x6a, 0xd4, 0x08, - 0xff, 0x6a, 0xd4, 0x0c -}; - -typedef int ahc_patch_func_t (struct ahc_softc *ahc); -static ahc_patch_func_t ahc_patch23_func; - -static int -ahc_patch23_func(struct ahc_softc *ahc) -{ - return ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0); -} - -static ahc_patch_func_t ahc_patch22_func; - -static int -ahc_patch22_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_CMD_CHAN) == 0); -} - -static ahc_patch_func_t ahc_patch21_func; - -static int -ahc_patch21_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_QUEUE_REGS) == 0); -} - -static ahc_patch_func_t ahc_patch20_func; - -static int -ahc_patch20_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_WIDE) != 0); -} - -static ahc_patch_func_t ahc_patch19_func; - -static int -ahc_patch19_func(struct ahc_softc *ahc) -{ - return ((ahc->flags & AHC_SCB_BTT) != 0); -} - -static ahc_patch_func_t ahc_patch18_func; - -static int -ahc_patch18_func(struct ahc_softc *ahc) -{ - return ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0); -} - -static ahc_patch_func_t ahc_patch17_func; - -static int -ahc_patch17_func(struct ahc_softc *ahc) -{ - return ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0); -} - -static ahc_patch_func_t ahc_patch16_func; - -static int -ahc_patch16_func(struct ahc_softc *ahc) -{ - return ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0); -} - -static ahc_patch_func_t ahc_patch15_func; - -static int -ahc_patch15_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_ULTRA2) == 0); -} - -static ahc_patch_func_t ahc_patch14_func; - -static int -ahc_patch14_func(struct ahc_softc *ahc) -{ - return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0); -} - -static ahc_patch_func_t ahc_patch13_func; - -static int -ahc_patch13_func(struct ahc_softc *ahc) -{ - return ((ahc->flags & AHC_39BIT_ADDRESSING) != 0); -} - -static ahc_patch_func_t ahc_patch12_func; - -static int -ahc_patch12_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_HS_MAILBOX) != 0); -} - -static ahc_patch_func_t ahc_patch11_func; - -static int -ahc_patch11_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_ULTRA) != 0); -} - -static ahc_patch_func_t ahc_patch10_func; - -static int -ahc_patch10_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_MULTI_TID) != 0); -} - -static ahc_patch_func_t ahc_patch9_func; - -static int -ahc_patch9_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_CMD_CHAN) != 0); -} - -static ahc_patch_func_t ahc_patch8_func; - -static int -ahc_patch8_func(struct ahc_softc *ahc) -{ - return ((ahc->flags & AHC_INITIATORROLE) != 0); -} - -static ahc_patch_func_t ahc_patch7_func; - -static int -ahc_patch7_func(struct ahc_softc *ahc) -{ - return ((ahc->flags & AHC_TARGETROLE) != 0); -} - -static ahc_patch_func_t ahc_patch6_func; - -static int -ahc_patch6_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_DT) == 0); -} - -static ahc_patch_func_t ahc_patch5_func; - -static int -ahc_patch5_func(struct ahc_softc *ahc) -{ - return ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0); -} - -static ahc_patch_func_t ahc_patch4_func; - -static int -ahc_patch4_func(struct ahc_softc *ahc) -{ - return ((ahc->flags & AHC_PAGESCBS) != 0); -} - -static ahc_patch_func_t ahc_patch3_func; - -static int -ahc_patch3_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_QUEUE_REGS) != 0); -} - -static ahc_patch_func_t ahc_patch2_func; - -static int -ahc_patch2_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_TWIN) != 0); -} - -static ahc_patch_func_t ahc_patch1_func; - -static int -ahc_patch1_func(struct ahc_softc *ahc) -{ - return ((ahc->features & AHC_ULTRA2) != 0); -} - -static ahc_patch_func_t ahc_patch0_func; - -static int -ahc_patch0_func(struct ahc_softc *ahc) -{ - return (0); -} - -static const struct patch { - ahc_patch_func_t *patch_func; - uint32_t begin :10, - skip_instr :10, - skip_patch :12; -} patches[] = { - { ahc_patch1_func, 4, 1, 1 }, - { ahc_patch2_func, 6, 2, 1 }, - { ahc_patch2_func, 9, 1, 1 }, - { ahc_patch3_func, 11, 1, 2 }, - { ahc_patch0_func, 12, 2, 1 }, - { ahc_patch4_func, 15, 1, 2 }, - { ahc_patch0_func, 16, 1, 1 }, - { ahc_patch5_func, 22, 2, 1 }, - { ahc_patch3_func, 27, 1, 2 }, - { ahc_patch0_func, 28, 1, 1 }, - { ahc_patch6_func, 34, 1, 1 }, - { ahc_patch7_func, 37, 54, 19 }, - { ahc_patch8_func, 37, 1, 1 }, - { ahc_patch9_func, 42, 3, 2 }, - { ahc_patch0_func, 45, 3, 1 }, - { ahc_patch10_func, 49, 1, 2 }, - { ahc_patch0_func, 50, 2, 3 }, - { ahc_patch1_func, 50, 1, 2 }, - { ahc_patch0_func, 51, 1, 1 }, - { ahc_patch2_func, 53, 2, 1 }, - { ahc_patch9_func, 55, 1, 2 }, - { ahc_patch0_func, 56, 1, 1 }, - { ahc_patch9_func, 60, 1, 2 }, - { ahc_patch0_func, 61, 1, 1 }, - { ahc_patch9_func, 71, 1, 2 }, - { ahc_patch0_func, 72, 1, 1 }, - { ahc_patch9_func, 75, 1, 2 }, - { ahc_patch0_func, 76, 1, 1 }, - { ahc_patch9_func, 79, 1, 2 }, - { ahc_patch0_func, 80, 1, 1 }, - { ahc_patch8_func, 91, 9, 4 }, - { ahc_patch1_func, 93, 1, 2 }, - { ahc_patch0_func, 94, 1, 1 }, - { ahc_patch2_func, 96, 2, 1 }, - { ahc_patch2_func, 105, 4, 1 }, - { ahc_patch1_func, 109, 1, 2 }, - { ahc_patch0_func, 110, 2, 3 }, - { ahc_patch2_func, 110, 1, 2 }, - { ahc_patch0_func, 111, 1, 1 }, - { ahc_patch7_func, 112, 4, 2 }, - { ahc_patch0_func, 116, 1, 1 }, - { ahc_patch11_func, 117, 2, 1 }, - { ahc_patch1_func, 119, 1, 2 }, - { ahc_patch0_func, 120, 1, 1 }, - { ahc_patch7_func, 121, 4, 1 }, - { ahc_patch7_func, 131, 95, 11 }, - { ahc_patch4_func, 151, 1, 1 }, - { ahc_patch1_func, 168, 1, 1 }, - { ahc_patch12_func, 173, 1, 2 }, - { ahc_patch0_func, 174, 1, 1 }, - { ahc_patch9_func, 185, 1, 2 }, - { ahc_patch0_func, 186, 1, 1 }, - { ahc_patch9_func, 195, 1, 2 }, - { ahc_patch0_func, 196, 1, 1 }, - { ahc_patch9_func, 212, 6, 2 }, - { ahc_patch0_func, 218, 6, 1 }, - { ahc_patch8_func, 226, 21, 2 }, - { ahc_patch1_func, 241, 1, 1 }, - { ahc_patch1_func, 249, 1, 2 }, - { ahc_patch0_func, 250, 2, 2 }, - { ahc_patch11_func, 251, 1, 1 }, - { ahc_patch9_func, 259, 27, 3 }, - { ahc_patch1_func, 275, 10, 2 }, - { ahc_patch13_func, 278, 1, 1 }, - { ahc_patch14_func, 286, 14, 1 }, - { ahc_patch1_func, 302, 1, 2 }, - { ahc_patch0_func, 303, 1, 1 }, - { ahc_patch9_func, 306, 1, 1 }, - { ahc_patch13_func, 311, 1, 1 }, - { ahc_patch9_func, 312, 2, 2 }, - { ahc_patch0_func, 314, 4, 1 }, - { ahc_patch14_func, 318, 1, 1 }, - { ahc_patch15_func, 320, 2, 3 }, - { ahc_patch9_func, 320, 1, 2 }, - { ahc_patch0_func, 321, 1, 1 }, - { ahc_patch6_func, 326, 1, 2 }, - { ahc_patch0_func, 327, 1, 1 }, - { ahc_patch1_func, 331, 47, 11 }, - { ahc_patch6_func, 338, 2, 4 }, - { ahc_patch7_func, 338, 1, 1 }, - { ahc_patch8_func, 339, 1, 1 }, - { ahc_patch0_func, 340, 1, 1 }, - { ahc_patch16_func, 341, 1, 1 }, - { ahc_patch6_func, 357, 6, 3 }, - { ahc_patch16_func, 357, 5, 1 }, - { ahc_patch0_func, 363, 7, 1 }, - { ahc_patch13_func, 373, 5, 1 }, - { ahc_patch0_func, 378, 52, 17 }, - { ahc_patch14_func, 378, 1, 1 }, - { ahc_patch7_func, 380, 2, 2 }, - { ahc_patch17_func, 381, 1, 1 }, - { ahc_patch9_func, 384, 1, 1 }, - { ahc_patch18_func, 391, 1, 1 }, - { ahc_patch14_func, 396, 9, 3 }, - { ahc_patch9_func, 397, 3, 2 }, - { ahc_patch0_func, 400, 3, 1 }, - { ahc_patch9_func, 408, 6, 2 }, - { ahc_patch0_func, 414, 9, 2 }, - { ahc_patch13_func, 414, 1, 1 }, - { ahc_patch13_func, 423, 2, 1 }, - { ahc_patch14_func, 425, 1, 1 }, - { ahc_patch9_func, 427, 1, 2 }, - { ahc_patch0_func, 428, 1, 1 }, - { ahc_patch7_func, 429, 1, 1 }, - { ahc_patch7_func, 430, 1, 1 }, - { ahc_patch8_func, 431, 3, 3 }, - { ahc_patch6_func, 432, 1, 2 }, - { ahc_patch0_func, 433, 1, 1 }, - { ahc_patch9_func, 434, 1, 1 }, - { ahc_patch15_func, 435, 1, 2 }, - { ahc_patch13_func, 435, 1, 1 }, - { ahc_patch14_func, 437, 9, 4 }, - { ahc_patch9_func, 437, 1, 1 }, - { ahc_patch9_func, 444, 2, 1 }, - { ahc_patch0_func, 446, 4, 3 }, - { ahc_patch9_func, 446, 1, 2 }, - { ahc_patch0_func, 447, 3, 1 }, - { ahc_patch1_func, 451, 2, 1 }, - { ahc_patch7_func, 453, 10, 2 }, - { ahc_patch0_func, 463, 1, 1 }, - { ahc_patch8_func, 464, 118, 22 }, - { ahc_patch1_func, 466, 3, 2 }, - { ahc_patch0_func, 469, 5, 3 }, - { ahc_patch9_func, 469, 2, 2 }, - { ahc_patch0_func, 471, 3, 1 }, - { ahc_patch1_func, 476, 2, 2 }, - { ahc_patch0_func, 478, 6, 3 }, - { ahc_patch9_func, 478, 2, 2 }, - { ahc_patch0_func, 480, 3, 1 }, - { ahc_patch1_func, 486, 2, 2 }, - { ahc_patch0_func, 488, 9, 7 }, - { ahc_patch9_func, 488, 5, 6 }, - { ahc_patch19_func, 488, 1, 2 }, - { ahc_patch0_func, 489, 1, 1 }, - { ahc_patch19_func, 491, 1, 2 }, - { ahc_patch0_func, 492, 1, 1 }, - { ahc_patch0_func, 493, 4, 1 }, - { ahc_patch6_func, 498, 3, 2 }, - { ahc_patch0_func, 501, 1, 1 }, - { ahc_patch6_func, 511, 1, 2 }, - { ahc_patch0_func, 512, 1, 1 }, - { ahc_patch20_func, 549, 7, 1 }, - { ahc_patch3_func, 584, 1, 2 }, - { ahc_patch0_func, 585, 1, 1 }, - { ahc_patch21_func, 588, 1, 1 }, - { ahc_patch8_func, 590, 106, 33 }, - { ahc_patch4_func, 592, 1, 1 }, - { ahc_patch1_func, 598, 2, 2 }, - { ahc_patch0_func, 600, 1, 1 }, - { ahc_patch1_func, 603, 1, 2 }, - { ahc_patch0_func, 604, 1, 1 }, - { ahc_patch9_func, 605, 3, 3 }, - { ahc_patch15_func, 606, 1, 1 }, - { ahc_patch0_func, 608, 4, 1 }, - { ahc_patch19_func, 617, 2, 2 }, - { ahc_patch0_func, 619, 1, 1 }, - { ahc_patch19_func, 623, 10, 3 }, - { ahc_patch5_func, 625, 8, 1 }, - { ahc_patch0_func, 633, 9, 2 }, - { ahc_patch5_func, 634, 8, 1 }, - { ahc_patch4_func, 644, 1, 2 }, - { ahc_patch0_func, 645, 1, 1 }, - { ahc_patch19_func, 646, 1, 2 }, - { ahc_patch0_func, 647, 3, 2 }, - { ahc_patch4_func, 649, 1, 1 }, - { ahc_patch5_func, 650, 1, 1 }, - { ahc_patch5_func, 653, 1, 1 }, - { ahc_patch5_func, 655, 1, 1 }, - { ahc_patch4_func, 657, 2, 2 }, - { ahc_patch0_func, 659, 2, 1 }, - { ahc_patch5_func, 661, 1, 1 }, - { ahc_patch5_func, 664, 1, 1 }, - { ahc_patch5_func, 667, 1, 1 }, - { ahc_patch19_func, 671, 1, 1 }, - { ahc_patch19_func, 674, 1, 1 }, - { ahc_patch4_func, 680, 1, 1 }, - { ahc_patch6_func, 683, 1, 2 }, - { ahc_patch0_func, 684, 1, 1 }, - { ahc_patch7_func, 696, 16, 1 }, - { ahc_patch4_func, 712, 20, 1 }, - { ahc_patch9_func, 733, 4, 2 }, - { ahc_patch0_func, 737, 4, 1 }, - { ahc_patch9_func, 741, 4, 2 }, - { ahc_patch0_func, 745, 3, 1 }, - { ahc_patch6_func, 751, 1, 1 }, - { ahc_patch22_func, 753, 14, 1 }, - { ahc_patch7_func, 767, 3, 1 }, - { ahc_patch9_func, 779, 24, 8 }, - { ahc_patch19_func, 783, 1, 2 }, - { ahc_patch0_func, 784, 1, 1 }, - { ahc_patch15_func, 789, 4, 2 }, - { ahc_patch0_func, 793, 7, 3 }, - { ahc_patch23_func, 793, 5, 2 }, - { ahc_patch0_func, 798, 2, 1 }, - { ahc_patch0_func, 803, 42, 3 }, - { ahc_patch18_func, 815, 18, 2 }, - { ahc_patch0_func, 833, 1, 1 }, - { ahc_patch4_func, 857, 1, 1 }, - { ahc_patch4_func, 858, 3, 2 }, - { ahc_patch0_func, 861, 1, 1 }, - { ahc_patch13_func, 862, 3, 1 }, - { ahc_patch4_func, 865, 12, 1 } -}; - -static const struct cs { - uint16_t begin; - uint16_t end; -} critical_sections[] = { - { 11, 18 }, - { 21, 30 }, - { 712, 728 }, - { 858, 861 }, - { 865, 871 }, - { 873, 875 }, - { 875, 877 } -}; - -static const int num_critical_sections = sizeof(critical_sections) - / sizeof(*critical_sections); diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/Makefile b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/Makefile deleted file mode 100644 index b98c5c10..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/Makefile +++ /dev/null @@ -1,80 +0,0 @@ -PROG= aicasm - -.SUFFIXES= .l .y .c .h - -CSRCS= aicasm.c aicasm_symbol.c -YSRCS= aicasm_gram.y aicasm_macro_gram.y -LSRCS= aicasm_scan.l aicasm_macro_scan.l - -GENHDRS= aicdb.h $(YSRCS:.y=.h) -GENSRCS= $(YSRCS:.y=.c) $(LSRCS:.l=.c) - -SRCS= ${CSRCS} ${GENSRCS} -LIBS= -ldb -clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG) -# Override default kernel CFLAGS. This is a userland app. -AICASM_CFLAGS:= -I/usr/include -I. -LEX= flex -YACC= bison -YFLAGS= -d - -NOMAN= noman - -ifneq ($(HOSTCC),) -AICASM_CC= $(HOSTCC) -else -AICASM_CC= $(CC) -endif - -ifdef DEBUG -CFLAGS+= -DDEBUG -g -YFLAGS+= -t -v -LFLAGS= -d -endif - -$(PROG): ${GENHDRS} $(SRCS) - $(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) $(LIBS) - -aicdb.h: - @if [ -e "/usr/include/db4/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ - elif [ -e "/usr/include/db3/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ - elif [ -e "/usr/include/db2/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ - elif [ -e "/usr/include/db1/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ - elif [ -e "/usr/include/db/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ - elif [ -e "/usr/include/db_185.h" ]; then \ - echo "#include " > aicdb.h; \ - else \ - echo "*** Install db development libraries"; \ - fi - -clean: - rm -f $(clean-files) - -# Create a dependency chain in generated files -# to avoid concurrent invocations of the single -# rule that builds them all. -aicasm_gram.c: aicasm_gram.h -aicasm_gram.c aicasm_gram.h: aicasm_gram.y - $(YACC) $(YFLAGS) -b $(<:.y=) $< - mv $(<:.y=).tab.c $(<:.y=.c) - mv $(<:.y=).tab.h $(<:.y=.h) - -# Create a dependency chain in generated files -# to avoid concurrent invocations of the single -# rule that builds them all. -aicasm_macro_gram.c: aicasm_macro_gram.h -aicasm_macro_gram.c aicasm_macro_gram.h: aicasm_macro_gram.y - $(YACC) $(YFLAGS) -b $(<:.y=) -p mm $< - mv $(<:.y=).tab.c $(<:.y=.c) - mv $(<:.y=).tab.h $(<:.y=.h) - -aicasm_scan.c: aicasm_scan.l - $(LEX) $(LFLAGS) -o$@ $< - -aicasm_macro_scan.c: aicasm_macro_scan.l - $(LEX) $(LFLAGS) -Pmm -o$@ $< diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.c deleted file mode 100644 index 2e3117aa..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * Aic7xxx SCSI host adapter firmware assembler - * - * Copyright (c) 1997, 1998, 2000, 2001 Justin T. Gibbs. - * Copyright (c) 2001, 2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#23 $ - * - * $FreeBSD$ - */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#if linux -#include -#else -#include -#endif - -#include "aicasm.h" -#include "aicasm_symbol.h" -#include "aicasm_insformat.h" - -typedef struct patch { - STAILQ_ENTRY(patch) links; - int patch_func; - u_int begin; - u_int skip_instr; - u_int skip_patch; -} patch_t; - -STAILQ_HEAD(patch_list, patch) patches; - -static void usage(void); -static void back_patch(void); -static void output_code(void); -static void output_listing(char *ifilename); -static void dump_scope(scope_t *scope); -static void emit_patch(scope_t *scope, int patch); -static int check_patch(patch_t **start_patch, int start_instr, - int *skip_addr, int *func_vals); - -struct path_list search_path; -int includes_search_curdir; -char *appname; -char *stock_include_file; -FILE *ofile; -char *ofilename; -char *regfilename; -FILE *regfile; -char *listfilename; -FILE *listfile; -char *regdiagfilename; -FILE *regdiagfile; -int src_mode; -int dst_mode; - -static STAILQ_HEAD(,instruction) seq_program; -struct cs_tailq cs_tailq; -struct scope_list scope_stack; -symlist_t patch_functions; - -#if DEBUG -extern int yy_flex_debug; -extern int mm_flex_debug; -extern int yydebug; -extern int mmdebug; -#endif -extern FILE *yyin; -extern int yyparse(void); - -int main(int argc, char *argv[]); - -int -main(int argc, char *argv[]) -{ - extern char *optarg; - extern int optind; - int ch; - int retval; - char *inputfilename; - scope_t *sentinal; - - STAILQ_INIT(&patches); - SLIST_INIT(&search_path); - STAILQ_INIT(&seq_program); - TAILQ_INIT(&cs_tailq); - SLIST_INIT(&scope_stack); - - /* Set Sentinal scope node */ - sentinal = scope_alloc(); - sentinal->type = SCOPE_ROOT; - - includes_search_curdir = 1; - appname = *argv; - regfile = NULL; - listfile = NULL; -#if DEBUG - yy_flex_debug = 0; - mm_flex_debug = 0; - yydebug = 0; - mmdebug = 0; -#endif - while ((ch = getopt(argc, argv, "d:i:l:n:o:p:r:I:")) != -1) { - switch(ch) { - case 'd': -#if DEBUG - if (strcmp(optarg, "s") == 0) { - yy_flex_debug = 1; - mm_flex_debug = 1; - } else if (strcmp(optarg, "p") == 0) { - yydebug = 1; - mmdebug = 1; - } else { - fprintf(stderr, "%s: -d Requires either an " - "'s' or 'p' argument\n", appname); - usage(); - } -#else - stop("-d: Assembler not built with debugging " - "information", EX_SOFTWARE); -#endif - break; - case 'i': - stock_include_file = optarg; - break; - case 'l': - /* Create a program listing */ - if ((listfile = fopen(optarg, "w")) == NULL) { - perror(optarg); - stop(NULL, EX_CANTCREAT); - } - listfilename = optarg; - break; - case 'n': - /* Don't complain about the -nostdinc directrive */ - if (strcmp(optarg, "ostdinc")) { - fprintf(stderr, "%s: Unknown option -%c%s\n", - appname, ch, optarg); - usage(); - /* NOTREACHED */ - } - break; - case 'o': - if ((ofile = fopen(optarg, "w")) == NULL) { - perror(optarg); - stop(NULL, EX_CANTCREAT); - } - ofilename = optarg; - break; - case 'p': - /* Create Register Diagnostic "printing" Functions */ - if ((regdiagfile = fopen(optarg, "w")) == NULL) { - perror(optarg); - stop(NULL, EX_CANTCREAT); - } - regdiagfilename = optarg; - break; - case 'r': - if ((regfile = fopen(optarg, "w")) == NULL) { - perror(optarg); - stop(NULL, EX_CANTCREAT); - } - regfilename = optarg; - break; - case 'I': - { - path_entry_t include_dir; - - if (strcmp(optarg, "-") == 0) { - if (includes_search_curdir == 0) { - fprintf(stderr, "%s: Warning - '-I-' " - "specified multiple " - "times\n", appname); - } - includes_search_curdir = 0; - for (include_dir = SLIST_FIRST(&search_path); - include_dir != NULL; - include_dir = SLIST_NEXT(include_dir, - links)) - /* - * All entries before a '-I-' only - * apply to includes specified with - * quotes instead of "<>". - */ - include_dir->quoted_includes_only = 1; - } else { - include_dir = - (path_entry_t)malloc(sizeof(*include_dir)); - if (include_dir == NULL) { - perror(optarg); - stop(NULL, EX_OSERR); - } - include_dir->directory = strdup(optarg); - if (include_dir->directory == NULL) { - perror(optarg); - stop(NULL, EX_OSERR); - } - include_dir->quoted_includes_only = 0; - SLIST_INSERT_HEAD(&search_path, include_dir, - links); - } - break; - } - case '?': - default: - usage(); - /* NOTREACHED */ - } - } - argc -= optind; - argv += optind; - - if (argc != 1) { - fprintf(stderr, "%s: No input file specifiled\n", appname); - usage(); - /* NOTREACHED */ - } - - if (regdiagfile != NULL - && (regfile == NULL || stock_include_file == NULL)) { - fprintf(stderr, - "%s: The -p option requires the -r and -i options.\n", - appname); - usage(); - /* NOTREACHED */ - } - symtable_open(); - inputfilename = *argv; - include_file(*argv, SOURCE_FILE); - retval = yyparse(); - if (retval == 0) { - if (SLIST_FIRST(&scope_stack) == NULL - || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) { - stop("Unterminated conditional expression", EX_DATAERR); - /* NOTREACHED */ - } - - /* Process outmost scope */ - process_scope(SLIST_FIRST(&scope_stack)); - /* - * Decend the tree of scopes and insert/emit - * patches as appropriate. We perform a depth first - * tranversal, recursively handling each scope. - */ - /* start at the root scope */ - dump_scope(SLIST_FIRST(&scope_stack)); - - /* Patch up forward jump addresses */ - back_patch(); - - if (ofile != NULL) - output_code(); - if (regfile != NULL) - symtable_dump(regfile, regdiagfile); - if (listfile != NULL) - output_listing(inputfilename); - } - - stop(NULL, 0); - /* NOTREACHED */ - return (0); -} - -static void -usage() -{ - - (void)fprintf(stderr, -"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]\n" -" [-r register_output_file [-p register_diag_file -i includefile]]\n" -" [-l program_list_file]\n" -" input_file\n", appname); - exit(EX_USAGE); -} - -static void -back_patch() -{ - struct instruction *cur_instr; - - for (cur_instr = STAILQ_FIRST(&seq_program); - cur_instr != NULL; - cur_instr = STAILQ_NEXT(cur_instr, links)) { - if (cur_instr->patch_label != NULL) { - struct ins_format3 *f3_instr; - u_int address; - - if (cur_instr->patch_label->type != LABEL) { - char buf[255]; - - snprintf(buf, sizeof(buf), - "Undefined label %s", - cur_instr->patch_label->name); - stop(buf, EX_DATAERR); - /* NOTREACHED */ - } - f3_instr = &cur_instr->format.format3; - address = f3_instr->address; - address += cur_instr->patch_label->info.linfo->address; - f3_instr->address = address; - } - } -} - -static void -output_code() -{ - struct instruction *cur_instr; - patch_t *cur_patch; - critical_section_t *cs; - symbol_node_t *cur_node; - int instrcount; - - instrcount = 0; - fprintf(ofile, -"/*\n" -" * DO NOT EDIT - This file is automatically generated\n" -" * from the following source files:\n" -" *\n" -"%s */\n", versions); - - fprintf(ofile, "static const uint8_t seqprog[] = {\n"); - for (cur_instr = STAILQ_FIRST(&seq_program); - cur_instr != NULL; - cur_instr = STAILQ_NEXT(cur_instr, links)) { - - fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x", - cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n", -#ifdef __LITTLE_ENDIAN - cur_instr->format.bytes[0], - cur_instr->format.bytes[1], - cur_instr->format.bytes[2], - cur_instr->format.bytes[3]); -#else - cur_instr->format.bytes[3], - cur_instr->format.bytes[2], - cur_instr->format.bytes[1], - cur_instr->format.bytes[0]); -#endif - instrcount++; - } - fprintf(ofile, "\n};\n\n"); - - if (patch_arg_list == NULL) - stop("Patch argument list not defined", - EX_DATAERR); - - /* - * Output patch information. Patch functions first. - */ - fprintf(ofile, -"typedef int %spatch_func_t (%s);\n", prefix, patch_arg_list); - - for (cur_node = SLIST_FIRST(&patch_functions); - cur_node != NULL; - cur_node = SLIST_NEXT(cur_node,links)) { - fprintf(ofile, -"static %spatch_func_t %spatch%d_func;\n" -"\n" -"static int\n" -"%spatch%d_func(%s)\n" -"{\n" -" return (%s);\n" -"}\n\n", - prefix, - prefix, - cur_node->symbol->info.condinfo->func_num, - prefix, - cur_node->symbol->info.condinfo->func_num, - patch_arg_list, - cur_node->symbol->name); - } - - fprintf(ofile, -"static const struct patch {\n" -" %spatch_func_t *patch_func;\n" -" uint32_t begin :10,\n" -" skip_instr :10,\n" -" skip_patch :12;\n" -"} patches[] = {\n", prefix); - - for (cur_patch = STAILQ_FIRST(&patches); - cur_patch != NULL; - cur_patch = STAILQ_NEXT(cur_patch,links)) { - fprintf(ofile, "%s\t{ %spatch%d_func, %d, %d, %d }", - cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n", - prefix, - cur_patch->patch_func, cur_patch->begin, - cur_patch->skip_instr, cur_patch->skip_patch); - } - - fprintf(ofile, "\n};\n\n"); - - fprintf(ofile, -"static const struct cs {\n" -" uint16_t begin;\n" -" uint16_t end;\n" -"} critical_sections[] = {\n"); - - for (cs = TAILQ_FIRST(&cs_tailq); - cs != NULL; - cs = TAILQ_NEXT(cs, links)) { - fprintf(ofile, "%s\t{ %d, %d }", - cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n", - cs->begin_addr, cs->end_addr); - } - - fprintf(ofile, "\n};\n\n"); - - fprintf(ofile, -"static const int num_critical_sections = sizeof(critical_sections)\n" -" / sizeof(*critical_sections);\n"); - - fprintf(stderr, "%s: %d instructions used\n", appname, instrcount); -} - -static void -dump_scope(scope_t *scope) -{ - scope_t *cur_scope; - - /* - * Emit the first patch for this scope - */ - emit_patch(scope, 0); - - /* - * Dump each scope within this one. - */ - cur_scope = TAILQ_FIRST(&scope->inner_scope); - - while (cur_scope != NULL) { - - dump_scope(cur_scope); - - cur_scope = TAILQ_NEXT(cur_scope, scope_links); - } - - /* - * Emit the second, closing, patch for this scope - */ - emit_patch(scope, 1); -} - -void -emit_patch(scope_t *scope, int patch) -{ - patch_info_t *pinfo; - patch_t *new_patch; - - pinfo = &scope->patches[patch]; - - if (pinfo->skip_instr == 0) - /* No-Op patch */ - return; - - new_patch = (patch_t *)malloc(sizeof(*new_patch)); - - if (new_patch == NULL) - stop("Could not malloc patch structure", EX_OSERR); - - memset(new_patch, 0, sizeof(*new_patch)); - - if (patch == 0) { - new_patch->patch_func = scope->func_num; - new_patch->begin = scope->begin_addr; - } else { - new_patch->patch_func = 0; - new_patch->begin = scope->end_addr; - } - new_patch->skip_instr = pinfo->skip_instr; - new_patch->skip_patch = pinfo->skip_patch; - STAILQ_INSERT_TAIL(&patches, new_patch, links); -} - -void -output_listing(char *ifilename) -{ - char buf[1024]; - FILE *ifile; - struct instruction *cur_instr; - patch_t *cur_patch; - symbol_node_t *cur_func; - int *func_values; - int instrcount; - int instrptr; - int line; - int func_count; - int skip_addr; - - instrcount = 0; - instrptr = 0; - line = 1; - skip_addr = 0; - if ((ifile = fopen(ifilename, "r")) == NULL) { - perror(ifilename); - stop(NULL, EX_DATAERR); - } - - /* - * Determine which options to apply to this listing. - */ - for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions); - cur_func != NULL; - cur_func = SLIST_NEXT(cur_func, links)) - func_count++; - - func_values = NULL; - if (func_count != 0) { - func_values = (int *)malloc(func_count * sizeof(int)); - - if (func_values == NULL) - stop("Could not malloc", EX_OSERR); - - func_values[0] = 0; /* FALSE func */ - func_count--; - - /* - * Ask the user to fill in the return values for - * the rest of the functions. - */ - - - for (cur_func = SLIST_FIRST(&patch_functions); - cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL; - cur_func = SLIST_NEXT(cur_func, links), func_count--) { - int input; - - fprintf(stdout, "\n(%s)\n", cur_func->symbol->name); - fprintf(stdout, - "Enter the return value for " - "this expression[T/F]:"); - - while (1) { - - input = getchar(); - input = toupper(input); - - if (input == 'T') { - func_values[func_count] = 1; - break; - } else if (input == 'F') { - func_values[func_count] = 0; - break; - } - } - if (isatty(fileno(stdin)) == 0) - putchar(input); - } - fprintf(stdout, "\nThanks!\n"); - } - - /* Now output the listing */ - cur_patch = STAILQ_FIRST(&patches); - for (cur_instr = STAILQ_FIRST(&seq_program); - cur_instr != NULL; - cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) { - - if (check_patch(&cur_patch, instrcount, - &skip_addr, func_values) == 0) { - /* Don't count this instruction as it is in a patch - * that was removed. - */ - continue; - } - - while (line < cur_instr->srcline) { - fgets(buf, sizeof(buf), ifile); - fprintf(listfile, " \t%s", buf); - line++; - } - fprintf(listfile, "%04x %02x%02x%02x%02x", instrptr, -#ifdef __LITTLE_ENDIAN - cur_instr->format.bytes[0], - cur_instr->format.bytes[1], - cur_instr->format.bytes[2], - cur_instr->format.bytes[3]); -#else - cur_instr->format.bytes[3], - cur_instr->format.bytes[2], - cur_instr->format.bytes[1], - cur_instr->format.bytes[0]); -#endif - /* - * Macro expansions can cause several instructions - * to be output for a single source line. Only - * advance the line once in these cases. - */ - if (line == cur_instr->srcline) { - fgets(buf, sizeof(buf), ifile); - fprintf(listfile, "\t%s", buf); - line++; - } else { - fprintf(listfile, "\n"); - } - instrptr++; - } - /* Dump the remainder of the file */ - while(fgets(buf, sizeof(buf), ifile) != NULL) - fprintf(listfile, " %s", buf); - - fclose(ifile); -} - -static int -check_patch(patch_t **start_patch, int start_instr, - int *skip_addr, int *func_vals) -{ - patch_t *cur_patch; - - cur_patch = *start_patch; - - while (cur_patch != NULL && start_instr == cur_patch->begin) { - if (func_vals[cur_patch->patch_func] == 0) { - int skip; - - /* Start rejecting code */ - *skip_addr = start_instr + cur_patch->skip_instr; - for (skip = cur_patch->skip_patch; - skip > 0 && cur_patch != NULL; - skip--) - cur_patch = STAILQ_NEXT(cur_patch, links); - } else { - /* Accepted this patch. Advance to the next - * one and wait for our intruction pointer to - * hit this point. - */ - cur_patch = STAILQ_NEXT(cur_patch, links); - } - } - - *start_patch = cur_patch; - if (start_instr < *skip_addr) - /* Still skipping */ - return (0); - - return (1); -} - -/* - * Print out error information if appropriate, and clean up before - * terminating the program. - */ -void -stop(const char *string, int err_code) -{ - if (string != NULL) { - fprintf(stderr, "%s: ", appname); - if (yyfilename != NULL) { - fprintf(stderr, "Stopped at file %s, line %d - ", - yyfilename, yylineno); - } - fprintf(stderr, "%s\n", string); - } - - if (ofile != NULL) { - fclose(ofile); - if (err_code != 0) { - fprintf(stderr, "%s: Removing %s due to error\n", - appname, ofilename); - unlink(ofilename); - } - } - - if (regfile != NULL) { - fclose(regfile); - if (err_code != 0) { - fprintf(stderr, "%s: Removing %s due to error\n", - appname, regfilename); - unlink(regfilename); - } - } - - if (listfile != NULL) { - fclose(listfile); - if (err_code != 0) { - fprintf(stderr, "%s: Removing %s due to error\n", - appname, listfilename); - unlink(listfilename); - } - } - - symlist_free(&patch_functions); - symtable_close(); - - exit(err_code); -} - -struct instruction * -seq_alloc() -{ - struct instruction *new_instr; - - new_instr = (struct instruction *)malloc(sizeof(struct instruction)); - if (new_instr == NULL) - stop("Unable to malloc instruction object", EX_SOFTWARE); - memset(new_instr, 0, sizeof(*new_instr)); - STAILQ_INSERT_TAIL(&seq_program, new_instr, links); - new_instr->srcline = yylineno; - return new_instr; -} - -critical_section_t * -cs_alloc() -{ - critical_section_t *new_cs; - - new_cs= (critical_section_t *)malloc(sizeof(critical_section_t)); - if (new_cs == NULL) - stop("Unable to malloc critical_section object", EX_SOFTWARE); - memset(new_cs, 0, sizeof(*new_cs)); - - TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links); - return new_cs; -} - -scope_t * -scope_alloc() -{ - scope_t *new_scope; - - new_scope = (scope_t *)malloc(sizeof(scope_t)); - if (new_scope == NULL) - stop("Unable to malloc scope object", EX_SOFTWARE); - memset(new_scope, 0, sizeof(*new_scope)); - TAILQ_INIT(&new_scope->inner_scope); - - if (SLIST_FIRST(&scope_stack) != NULL) { - TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope, - new_scope, scope_links); - } - /* This patch is now the current scope */ - SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links); - return new_scope; -} - -void -process_scope(scope_t *scope) -{ - /* - * We are "leaving" this scope. We should now have - * enough information to process the lists of scopes - * we encapsulate. - */ - scope_t *cur_scope; - u_int skip_patch_count; - u_int skip_instr_count; - - cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq); - skip_patch_count = 0; - skip_instr_count = 0; - while (cur_scope != NULL) { - u_int patch0_patch_skip; - - patch0_patch_skip = 0; - switch (cur_scope->type) { - case SCOPE_IF: - case SCOPE_ELSE_IF: - if (skip_instr_count != 0) { - /* Create a tail patch */ - patch0_patch_skip++; - cur_scope->patches[1].skip_patch = - skip_patch_count + 1; - cur_scope->patches[1].skip_instr = - skip_instr_count; - } - - /* Count Head patch */ - patch0_patch_skip++; - - /* Count any patches contained in our inner scope */ - patch0_patch_skip += cur_scope->inner_scope_patches; - - cur_scope->patches[0].skip_patch = patch0_patch_skip; - cur_scope->patches[0].skip_instr = - cur_scope->end_addr - cur_scope->begin_addr; - - skip_instr_count += cur_scope->patches[0].skip_instr; - - skip_patch_count += patch0_patch_skip; - if (cur_scope->type == SCOPE_IF) { - scope->inner_scope_patches += skip_patch_count; - skip_patch_count = 0; - skip_instr_count = 0; - } - break; - case SCOPE_ELSE: - /* Count any patches contained in our innter scope */ - skip_patch_count += cur_scope->inner_scope_patches; - - skip_instr_count += cur_scope->end_addr - - cur_scope->begin_addr; - break; - case SCOPE_ROOT: - stop("Unexpected scope type encountered", EX_SOFTWARE); - /* NOTREACHED */ - } - - cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links); - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.h deleted file mode 100644 index 51678dd4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters - * - * Copyright (c) 1997 Justin T. Gibbs. - * Copyright (c) 2001, 2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.h#14 $ - * - * $FreeBSD$ - */ - -#ifdef __linux__ -#include "../queue.h" -#else -#include -#endif - -#ifndef TRUE -#define TRUE 1 -#endif - -#ifndef FALSE -#define FALSE 0 -#endif - -typedef struct path_entry { - char *directory; - int quoted_includes_only; - SLIST_ENTRY(path_entry) links; -} *path_entry_t; - -typedef enum { - QUOTED_INCLUDE, - BRACKETED_INCLUDE, - SOURCE_FILE -} include_type; - -SLIST_HEAD(path_list, path_entry); - -extern struct path_list search_path; -extern struct cs_tailq cs_tailq; -extern struct scope_list scope_stack; -extern struct symlist patch_functions; -extern int includes_search_curdir; /* False if we've seen -I- */ -extern char *appname; -extern char *stock_include_file; -extern int yylineno; -extern char *yyfilename; -extern char *prefix; -extern char *patch_arg_list; -extern char *versions; -extern int src_mode; -extern int dst_mode; -struct symbol; - -void stop(const char *errstring, int err_code); -void include_file(char *file_name, include_type type); -void expand_macro(struct symbol *macro_symbol); -struct instruction *seq_alloc(void); -struct critical_section *cs_alloc(void); -struct scope *scope_alloc(void); -void process_scope(struct scope *); diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y deleted file mode 100644 index f1586a43..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y +++ /dev/null @@ -1,2004 +0,0 @@ -%{ -/* - * Parser for the Aic7xxx SCSI Host adapter sequencer assembler. - * - * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. - * Copyright (c) 2001, 2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#30 $ - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include "../queue.h" -#else -#include -#endif - -#include "aicasm.h" -#include "aicasm_symbol.h" -#include "aicasm_insformat.h" - -int yylineno; -char *yyfilename; -char stock_prefix[] = "aic_"; -char *prefix = stock_prefix; -char *patch_arg_list; -char *versions; -static char errbuf[255]; -static char regex_pattern[255]; -static symbol_t *cur_symbol; -static symbol_t *field_symbol; -static symbol_t *scb_or_sram_symbol; -static symtype cur_symtype; -static symbol_ref_t accumulator; -static symbol_ref_t mode_ptr; -static symbol_ref_t allones; -static symbol_ref_t allzeros; -static symbol_ref_t none; -static symbol_ref_t sindex; -static int instruction_ptr; -static int num_srams; -static int sram_or_scb_offset; -static int download_constant_count; -static int in_critical_section; -static u_int enum_increment; -static u_int enum_next_value; - -static void process_field(int field_type, symbol_t *sym, int mask); -static void initialize_symbol(symbol_t *symbol); -static void add_macro_arg(const char *argtext, int position); -static void add_macro_body(const char *bodytext); -static void process_register(symbol_t **p_symbol); -static void format_1_instr(int opcode, symbol_ref_t *dest, - expression_t *immed, symbol_ref_t *src, int ret); -static void format_2_instr(int opcode, symbol_ref_t *dest, - expression_t *places, symbol_ref_t *src, int ret); -static void format_3_instr(int opcode, symbol_ref_t *src, - expression_t *immed, symbol_ref_t *address); -static void test_readable_symbol(symbol_t *symbol); -static void test_writable_symbol(symbol_t *symbol); -static void type_check(symbol_ref_t *sym, expression_t *expression, int and_op); -static void make_expression(expression_t *immed, int value); -static void add_conditional(symbol_t *symbol); -static void add_version(const char *verstring); -static int is_download_const(expression_t *immed); -static int is_location_address(symbol_t *symbol); -void yyerror(const char *string); - -#define SRAM_SYMNAME "SRAM_BASE" -#define SCB_SYMNAME "SCB_BASE" -%} - -%union { - u_int value; - char *str; - symbol_t *sym; - symbol_ref_t sym_ref; - expression_t expression; -} - -%token T_REGISTER - -%token T_CONST - -%token T_EXPORT - -%token T_DOWNLOAD - -%token T_SCB - -%token T_SRAM - -%token T_ALIAS - -%token T_SIZE - -%token T_EXPR_LSHIFT - -%token T_EXPR_RSHIFT - -%token T_ADDRESS - -%token T_COUNT - -%token T_ACCESS_MODE - -%token T_DONT_GENERATE_DEBUG_CODE - -%token T_MODES - -%token T_DEFINE - -%token T_SET_SRC_MODE - -%token T_SET_DST_MODE - -%token T_MODE - -%token T_BEGIN_CS - -%token T_END_CS - -%token T_PAD_PAGE - -%token T_FIELD - -%token T_ENUM - -%token T_MASK - -%token T_NUMBER - -%token T_PATH T_STRING T_ARG T_MACROBODY - -%token T_CEXPR - -%token T_EOF T_INCLUDE T_VERSION T_PREFIX T_PATCH_ARG_LIST - -%token T_SHR T_SHL T_ROR T_ROL - -%token T_MVI T_MOV T_CLR T_BMOV - -%token T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL - -%token T_ADD T_ADC - -%token T_INC T_DEC - -%token T_STC T_CLC - -%token T_CMP T_NOT T_XOR - -%token T_TEST T_AND - -%token T_OR - -/* 16 bit extensions, not implemented - * %token T_OR16 T_AND16 T_XOR16 T_ADD16 - * %token T_ADC16 T_MVI16 T_TEST16 T_CMP16 T_CMPXCHG - */ -%token T_RET - -%token T_NOP - -%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX T_MODE_PTR - -%token T_A - -%token T_SYMBOL - -%token T_NL - -%token T_IF T_ELSE T_ELSE_IF T_ENDIF - -%type reg_symbol address destination source opt_source - -%type expression immediate immediate_or_a - -%type export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne - -%type mode_value mode_list macro_arglist - -%left '|' -%left '&' -%left T_EXPR_LSHIFT T_EXPR_RSHIFT -%left '+' '-' -%left '*' '/' -%right '~' -%nonassoc UMINUS -%% - -program: - include -| program include -| prefix -| program prefix -| patch_arg_list -| program patch_arg_list -| version -| program version -| register -| program register -| constant -| program constant -| macrodefn -| program macrodefn -| scratch_ram -| program scratch_ram -| scb -| program scb -| label -| program label -| set_src_mode -| program set_src_mode -| set_dst_mode -| program set_dst_mode -| critical_section_start -| program critical_section_start -| critical_section_end -| program critical_section_end -| conditional -| program conditional -| code -| program code -; - -include: - T_INCLUDE '<' T_PATH '>' - { - include_file($3, BRACKETED_INCLUDE); - } -| T_INCLUDE '"' T_PATH '"' - { - include_file($3, QUOTED_INCLUDE); - } -; - -prefix: - T_PREFIX '=' T_STRING - { - if (prefix != stock_prefix) - stop("Prefix multiply defined", - EX_DATAERR); - prefix = strdup($3); - if (prefix == NULL) - stop("Unable to record prefix", EX_SOFTWARE); - } -; - -patch_arg_list: - T_PATCH_ARG_LIST '=' T_STRING - { - if (patch_arg_list != NULL) - stop("Patch argument list multiply defined", - EX_DATAERR); - patch_arg_list = strdup($3); - if (patch_arg_list == NULL) - stop("Unable to record patch arg list", EX_SOFTWARE); - } -; - -version: - T_VERSION '=' T_STRING - { add_version($3); } -; - -register: - T_REGISTER { cur_symtype = REGISTER; } reg_definition -; - -reg_definition: - T_SYMBOL '{' - { - if ($1->type != UNINITIALIZED) { - stop("Register multiply defined", EX_DATAERR); - /* NOTREACHED */ - } - cur_symbol = $1; - cur_symbol->type = cur_symtype; - initialize_symbol(cur_symbol); - } - reg_attribute_list - '}' - { - /* - * Default to allowing everything in for registers - * with no bit or mask definitions. - */ - if (cur_symbol->info.rinfo->valid_bitmask == 0) - cur_symbol->info.rinfo->valid_bitmask = 0xFF; - - if (cur_symbol->info.rinfo->size == 0) - cur_symbol->info.rinfo->size = 1; - - /* - * This might be useful for registers too. - */ - if (cur_symbol->type != REGISTER) { - if (cur_symbol->info.rinfo->address == 0) - cur_symbol->info.rinfo->address = - sram_or_scb_offset; - sram_or_scb_offset += - cur_symbol->info.rinfo->size; - } - cur_symbol = NULL; - } -; - -reg_attribute_list: - reg_attribute -| reg_attribute_list reg_attribute -; - -reg_attribute: - reg_address -| size -| count -| access_mode -| dont_generate_debug_code -| modes -| field_defn -| enum_defn -| mask_defn -| alias -| accumulator -| mode_pointer -| allones -| allzeros -| none -| sindex -; - -reg_address: - T_ADDRESS T_NUMBER - { - cur_symbol->info.rinfo->address = $2; - } -; - -size: - T_SIZE T_NUMBER - { - cur_symbol->info.rinfo->size = $2; - if (scb_or_sram_symbol != NULL) { - u_int max_addr; - u_int sym_max_addr; - - max_addr = scb_or_sram_symbol->info.rinfo->address - + scb_or_sram_symbol->info.rinfo->size; - sym_max_addr = cur_symbol->info.rinfo->address - + cur_symbol->info.rinfo->size; - - if (sym_max_addr > max_addr) - stop("SCB or SRAM space exhausted", EX_DATAERR); - } - } -; - -count: - T_COUNT T_NUMBER - { - cur_symbol->count += $2; - } -; - -access_mode: - T_ACCESS_MODE T_MODE - { - cur_symbol->info.rinfo->mode = $2; - } -; - -dont_generate_debug_code: - T_DONT_GENERATE_DEBUG_CODE - { - cur_symbol->dont_generate_debug_code = 1; - } -; - -modes: - T_MODES mode_list - { - cur_symbol->info.rinfo->modes = $2; - } -; - -mode_list: - mode_value - { - $$ = $1; - } -| mode_list ',' mode_value - { - $$ = $1 | $3; - } -; - -mode_value: - T_NUMBER - { - if ($1 > 4) { - stop("Valid register modes range between 0 and 4.", - EX_DATAERR); - /* NOTREACHED */ - } - - $$ = (0x1 << $1); - } -| T_SYMBOL - { - symbol_t *symbol; - - symbol = $1; - if (symbol->type != CONST) { - stop("Only \"const\" symbols allowed in " - "mode definitions.", EX_DATAERR); - /* NOTREACHED */ - } - if (symbol->info.cinfo->value > 4) { - stop("Valid register modes range between 0 and 4.", - EX_DATAERR); - /* NOTREACHED */ - } - $$ = (0x1 << symbol->info.cinfo->value); - } -; - -field_defn: - T_FIELD - { - field_symbol = NULL; - enum_next_value = 0; - enum_increment = 1; - } - '{' enum_entry_list '}' -| T_FIELD T_SYMBOL expression - { - process_field(FIELD, $2, $3.value); - field_symbol = $2; - enum_next_value = 0; - enum_increment = 0x01 << (ffs($3.value) - 1); - } - '{' enum_entry_list '}' -| T_FIELD T_SYMBOL expression - { - process_field(FIELD, $2, $3.value); - } -; - -enum_defn: - T_ENUM - { - field_symbol = NULL; - enum_next_value = 0; - enum_increment = 1; - } - '{' enum_entry_list '}' -| T_ENUM T_SYMBOL expression - { - process_field(ENUM, $2, $3.value); - field_symbol = $2; - enum_next_value = 0; - enum_increment = 0x01 << (ffs($3.value) - 1); - } - '{' enum_entry_list '}' -; - -enum_entry_list: - enum_entry -| enum_entry_list ',' enum_entry -; - -enum_entry: - T_SYMBOL - { - process_field(ENUM_ENTRY, $1, enum_next_value); - enum_next_value += enum_increment; - } -| T_SYMBOL expression - { - process_field(ENUM_ENTRY, $1, $2.value); - enum_next_value = $2.value + enum_increment; - } -; - -mask_defn: - T_MASK T_SYMBOL expression - { - process_field(MASK, $2, $3.value); - } -; - -alias: - T_ALIAS T_SYMBOL - { - if ($2->type != UNINITIALIZED) { - stop("Re-definition of register alias", - EX_DATAERR); - /* NOTREACHED */ - } - $2->type = ALIAS; - initialize_symbol($2); - $2->info.ainfo->parent = cur_symbol; - } -; - -accumulator: - T_ACCUM - { - if (accumulator.symbol != NULL) { - stop("Only one accumulator definition allowed", - EX_DATAERR); - /* NOTREACHED */ - } - accumulator.symbol = cur_symbol; - } -; - -mode_pointer: - T_MODE_PTR - { - if (mode_ptr.symbol != NULL) { - stop("Only one mode pointer definition allowed", - EX_DATAERR); - /* NOTREACHED */ - } - mode_ptr.symbol = cur_symbol; - } -; - -allones: - T_ALLONES - { - if (allones.symbol != NULL) { - stop("Only one definition of allones allowed", - EX_DATAERR); - /* NOTREACHED */ - } - allones.symbol = cur_symbol; - } -; - -allzeros: - T_ALLZEROS - { - if (allzeros.symbol != NULL) { - stop("Only one definition of allzeros allowed", - EX_DATAERR); - /* NOTREACHED */ - } - allzeros.symbol = cur_symbol; - } -; - -none: - T_NONE - { - if (none.symbol != NULL) { - stop("Only one definition of none allowed", - EX_DATAERR); - /* NOTREACHED */ - } - none.symbol = cur_symbol; - } -; - -sindex: - T_SINDEX - { - if (sindex.symbol != NULL) { - stop("Only one definition of sindex allowed", - EX_DATAERR); - /* NOTREACHED */ - } - sindex.symbol = cur_symbol; - } -; - -expression: - expression '|' expression - { - $$.value = $1.value | $3.value; - symlist_merge(&$$.referenced_syms, - &$1.referenced_syms, - &$3.referenced_syms); - } -| expression '&' expression - { - $$.value = $1.value & $3.value; - symlist_merge(&$$.referenced_syms, - &$1.referenced_syms, - &$3.referenced_syms); - } -| expression '+' expression - { - $$.value = $1.value + $3.value; - symlist_merge(&$$.referenced_syms, - &$1.referenced_syms, - &$3.referenced_syms); - } -| expression '-' expression - { - $$.value = $1.value - $3.value; - symlist_merge(&($$.referenced_syms), - &($1.referenced_syms), - &($3.referenced_syms)); - } -| expression '*' expression - { - $$.value = $1.value * $3.value; - symlist_merge(&($$.referenced_syms), - &($1.referenced_syms), - &($3.referenced_syms)); - } -| expression '/' expression - { - $$.value = $1.value / $3.value; - symlist_merge(&($$.referenced_syms), - &($1.referenced_syms), - &($3.referenced_syms)); - } -| expression T_EXPR_LSHIFT expression - { - $$.value = $1.value << $3.value; - symlist_merge(&$$.referenced_syms, - &$1.referenced_syms, - &$3.referenced_syms); - } -| expression T_EXPR_RSHIFT expression - { - $$.value = $1.value >> $3.value; - symlist_merge(&$$.referenced_syms, - &$1.referenced_syms, - &$3.referenced_syms); - } -| '(' expression ')' - { - $$ = $2; - } -| '~' expression - { - $$ = $2; - $$.value = (~$$.value) & 0xFF; - } -| '-' expression %prec UMINUS - { - $$ = $2; - $$.value = -$$.value; - } -| T_NUMBER - { - $$.value = $1; - SLIST_INIT(&$$.referenced_syms); - } -| T_SYMBOL - { - symbol_t *symbol; - - symbol = $1; - switch (symbol->type) { - case ALIAS: - symbol = $1->info.ainfo->parent; - case REGISTER: - case SCBLOC: - case SRAMLOC: - $$.value = symbol->info.rinfo->address; - break; - case MASK: - case FIELD: - case ENUM: - case ENUM_ENTRY: - $$.value = symbol->info.finfo->value; - break; - case DOWNLOAD_CONST: - case CONST: - $$.value = symbol->info.cinfo->value; - break; - case UNINITIALIZED: - default: - { - snprintf(errbuf, sizeof(errbuf), - "Undefined symbol %s referenced", - symbol->name); - stop(errbuf, EX_DATAERR); - /* NOTREACHED */ - break; - } - } - SLIST_INIT(&$$.referenced_syms); - symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD); - } -; - -constant: - T_CONST T_SYMBOL expression - { - if ($2->type != UNINITIALIZED) { - stop("Re-definition of symbol as a constant", - EX_DATAERR); - /* NOTREACHED */ - } - $2->type = CONST; - initialize_symbol($2); - $2->info.cinfo->value = $3.value; - } -| T_CONST T_SYMBOL T_DOWNLOAD - { - if ($1) { - stop("Invalid downloaded constant declaration", - EX_DATAERR); - /* NOTREACHED */ - } - if ($2->type != UNINITIALIZED) { - stop("Re-definition of symbol as a downloaded constant", - EX_DATAERR); - /* NOTREACHED */ - } - $2->type = DOWNLOAD_CONST; - initialize_symbol($2); - $2->info.cinfo->value = download_constant_count++; - } -; - -macrodefn_prologue: - T_DEFINE T_SYMBOL - { - if ($2->type != UNINITIALIZED) { - stop("Re-definition of symbol as a macro", - EX_DATAERR); - /* NOTREACHED */ - } - cur_symbol = $2; - cur_symbol->type = MACRO; - initialize_symbol(cur_symbol); - } -; - -macrodefn: - macrodefn_prologue T_MACROBODY - { - add_macro_body($2); - } -| macrodefn_prologue '(' macro_arglist ')' T_MACROBODY - { - add_macro_body($5); - cur_symbol->info.macroinfo->narg = $3; - } -; - -macro_arglist: - { - /* Macros can take no arguments */ - $$ = 0; - } -| T_ARG - { - $$ = 1; - add_macro_arg($1, 0); - } -| macro_arglist ',' T_ARG - { - if ($1 == 0) { - stop("Comma without preceding argument in arg list", - EX_DATAERR); - /* NOTREACHED */ - } - $$ = $1 + 1; - add_macro_arg($3, $1); - } -; - -scratch_ram: - T_SRAM '{' - { - snprintf(errbuf, sizeof(errbuf), "%s%d", SRAM_SYMNAME, - num_srams); - cur_symbol = symtable_get(SRAM_SYMNAME); - cur_symtype = SRAMLOC; - cur_symbol->type = SRAMLOC; - initialize_symbol(cur_symbol); - cur_symbol->count += 1; - } - reg_address - { - sram_or_scb_offset = cur_symbol->info.rinfo->address; - } - size - { - scb_or_sram_symbol = cur_symbol; - } - scb_or_sram_attributes - '}' - { - cur_symbol = NULL; - scb_or_sram_symbol = NULL; - } -; - -scb: - T_SCB '{' - { - cur_symbol = symtable_get(SCB_SYMNAME); - cur_symtype = SCBLOC; - if (cur_symbol->type != UNINITIALIZED) { - stop("Only one SRAM definition allowed", - EX_SOFTWARE); - /* NOTREACHED */ - } - cur_symbol->type = SCBLOC; - initialize_symbol(cur_symbol); - /* 64 bytes of SCB space */ - cur_symbol->info.rinfo->size = 64; - cur_symbol->count += 1; - } - reg_address - { - sram_or_scb_offset = cur_symbol->info.rinfo->address; - } - size - { - scb_or_sram_symbol = cur_symbol; - } - scb_or_sram_attributes - '}' - { - cur_symbol = NULL; - scb_or_sram_symbol = NULL; - } -; - -scb_or_sram_attributes: - /* NULL definition is okay */ -| modes -| scb_or_sram_reg_list -| modes scb_or_sram_reg_list -; - -scb_or_sram_reg_list: - reg_definition -| scb_or_sram_reg_list reg_definition -; - -reg_symbol: - T_SYMBOL - { - process_register(&$1); - $$.symbol = $1; - $$.offset = 0; - } -| T_SYMBOL '[' T_SYMBOL ']' - { - process_register(&$1); - if ($3->type != CONST) { - stop("register offset must be a constant", EX_DATAERR); - /* NOTREACHED */ - } - if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) { - stop("Accessing offset beyond range of register", - EX_DATAERR); - /* NOTREACHED */ - } - $$.symbol = $1; - $$.offset = $3->info.cinfo->value; - } -| T_SYMBOL '[' T_NUMBER ']' - { - process_register(&$1); - if (($3 + 1) > $1->info.rinfo->size) { - stop("Accessing offset beyond range of register", - EX_DATAERR); - /* NOTREACHED */ - } - $$.symbol = $1; - $$.offset = $3; - } -| T_A - { - if (accumulator.symbol == NULL) { - stop("No accumulator has been defined", EX_DATAERR); - /* NOTREACHED */ - } - $$.symbol = accumulator.symbol; - $$.offset = 0; - } -; - -destination: - reg_symbol - { - test_writable_symbol($1.symbol); - $$ = $1; - } -; - -immediate: - expression - { $$ = $1; } -; - -immediate_or_a: - expression - { - if ($1.value == 0 && is_download_const(&$1) == 0) { - snprintf(errbuf, sizeof(errbuf), - "\nExpression evaluates to 0 and thus " - "references the accumulator.\n " - "If this is the desired effect, use 'A' " - "instead.\n"); - stop(errbuf, EX_DATAERR); - } - $$ = $1; - } -| T_A - { - SLIST_INIT(&$$.referenced_syms); - symlist_add(&$$.referenced_syms, accumulator.symbol, - SYMLIST_INSERT_HEAD); - $$.value = 0; - } -; - -source: - reg_symbol - { - test_readable_symbol($1.symbol); - $$ = $1; - } -; - -opt_source: - { - $$.symbol = NULL; - $$.offset = 0; - } -| ',' source - { $$ = $2; } -; - -ret: - { $$ = 0; } -| T_RET - { $$ = 1; } -; - -set_src_mode: - T_SET_SRC_MODE T_NUMBER ';' - { - src_mode = $2; - } -; - -set_dst_mode: - T_SET_DST_MODE T_NUMBER ';' - { - dst_mode = $2; - } -; - -critical_section_start: - T_BEGIN_CS ';' - { - critical_section_t *cs; - - if (in_critical_section != FALSE) { - stop("Critical Section within Critical Section", - EX_DATAERR); - /* NOTREACHED */ - } - cs = cs_alloc(); - cs->begin_addr = instruction_ptr; - in_critical_section = TRUE; - } -; - -critical_section_end: - T_END_CS ';' - { - critical_section_t *cs; - - if (in_critical_section == FALSE) { - stop("Unballanced 'end_cs'", EX_DATAERR); - /* NOTREACHED */ - } - cs = TAILQ_LAST(&cs_tailq, cs_tailq); - cs->end_addr = instruction_ptr; - in_critical_section = FALSE; - } -; - -export: - { $$ = 0; } -| T_EXPORT - { $$ = 1; } -; - -label: - export T_SYMBOL ':' - { - if ($2->type != UNINITIALIZED) { - stop("Program label multiply defined", EX_DATAERR); - /* NOTREACHED */ - } - $2->type = LABEL; - initialize_symbol($2); - $2->info.linfo->address = instruction_ptr; - $2->info.linfo->exported = $1; - } -; - -address: - T_SYMBOL - { - $$.symbol = $1; - $$.offset = 0; - } -| T_SYMBOL '+' T_NUMBER - { - $$.symbol = $1; - $$.offset = $3; - } -| T_SYMBOL '-' T_NUMBER - { - $$.symbol = $1; - $$.offset = -$3; - } -| '.' - { - $$.symbol = NULL; - $$.offset = 0; - } -| '.' '+' T_NUMBER - { - $$.symbol = NULL; - $$.offset = $3; - } -| '.' '-' T_NUMBER - { - $$.symbol = NULL; - $$.offset = -$3; - } -; - -conditional: - T_IF T_CEXPR '{' - { - scope_t *new_scope; - - add_conditional($2); - new_scope = scope_alloc(); - new_scope->type = SCOPE_IF; - new_scope->begin_addr = instruction_ptr; - new_scope->func_num = $2->info.condinfo->func_num; - } -| T_ELSE T_IF T_CEXPR '{' - { - scope_t *new_scope; - scope_t *scope_context; - scope_t *last_scope; - - /* - * Ensure that the previous scope is either an - * if or and else if. - */ - scope_context = SLIST_FIRST(&scope_stack); - last_scope = TAILQ_LAST(&scope_context->inner_scope, - scope_tailq); - if (last_scope == NULL - || last_scope->type == T_ELSE) { - - stop("'else if' without leading 'if'", EX_DATAERR); - /* NOTREACHED */ - } - add_conditional($3); - new_scope = scope_alloc(); - new_scope->type = SCOPE_ELSE_IF; - new_scope->begin_addr = instruction_ptr; - new_scope->func_num = $3->info.condinfo->func_num; - } -| T_ELSE '{' - { - scope_t *new_scope; - scope_t *scope_context; - scope_t *last_scope; - - /* - * Ensure that the previous scope is either an - * if or and else if. - */ - scope_context = SLIST_FIRST(&scope_stack); - last_scope = TAILQ_LAST(&scope_context->inner_scope, - scope_tailq); - if (last_scope == NULL - || last_scope->type == SCOPE_ELSE) { - - stop("'else' without leading 'if'", EX_DATAERR); - /* NOTREACHED */ - } - new_scope = scope_alloc(); - new_scope->type = SCOPE_ELSE; - new_scope->begin_addr = instruction_ptr; - } -; - -conditional: - '}' - { - scope_t *scope_context; - - scope_context = SLIST_FIRST(&scope_stack); - if (scope_context->type == SCOPE_ROOT) { - stop("Unexpected '}' encountered", EX_DATAERR); - /* NOTREACHED */ - } - - scope_context->end_addr = instruction_ptr; - - /* Pop the scope */ - SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links); - - process_scope(scope_context); - - if (SLIST_FIRST(&scope_stack) == NULL) { - stop("Unexpected '}' encountered", EX_DATAERR); - /* NOTREACHED */ - } - } -; - -f1_opcode: - T_AND { $$ = AIC_OP_AND; } -| T_XOR { $$ = AIC_OP_XOR; } -| T_ADD { $$ = AIC_OP_ADD; } -| T_ADC { $$ = AIC_OP_ADC; } -; - -code: - f1_opcode destination ',' immediate_or_a opt_source ret ';' - { - format_1_instr($1, &$2, &$4, &$5, $6); - } -; - -code: - T_OR reg_symbol ',' immediate_or_a opt_source ret ';' - { - format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6); - } -; - -code: - T_INC destination opt_source ret ';' - { - expression_t immed; - - make_expression(&immed, 1); - format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); - } -; - -code: - T_DEC destination opt_source ret ';' - { - expression_t immed; - - make_expression(&immed, -1); - format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4); - } -; - -code: - T_CLC ret ';' - { - expression_t immed; - - make_expression(&immed, -1); - format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2); - } -| T_CLC T_MVI destination ',' immediate_or_a ret ';' - { - format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6); - } -; - -code: - T_STC ret ';' - { - expression_t immed; - - make_expression(&immed, 1); - format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2); - } -| T_STC destination ret ';' - { - expression_t immed; - - make_expression(&immed, 1); - format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3); - } -; - -code: - T_BMOV destination ',' source ',' immediate ret ';' - { - format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7); - } -; - -code: - T_MOV destination ',' source ret ';' - { - expression_t immed; - - make_expression(&immed, 1); - format_1_instr(AIC_OP_BMOV, &$2, &immed, &$4, $5); - } -; - -code: - T_MVI destination ',' immediate ret ';' - { - if ($4.value == 0 - && is_download_const(&$4) == 0) { - expression_t immed; - - /* - * Allow move immediates of 0 so that macros, - * that can't know the immediate's value and - * otherwise compensate, still work. - */ - make_expression(&immed, 1); - format_1_instr(AIC_OP_BMOV, &$2, &immed, &allzeros, $5); - } else { - format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5); - } - } -; - -code: - T_NOT destination opt_source ret ';' - { - expression_t immed; - - make_expression(&immed, 0xff); - format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4); - } -; - -code: - T_CLR destination ret ';' - { - expression_t immed; - - make_expression(&immed, 0xff); - format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3); - } -; - -code: - T_NOP ret ';' - { - expression_t immed; - - make_expression(&immed, 0xff); - format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2); - } -; - -code: - T_RET ';' - { - expression_t immed; - - make_expression(&immed, 0xff); - format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE); - } -; - - /* - * This grammar differs from the one in the aic7xxx - * reference manual since the grammar listed there is - * ambiguous and causes a shift/reduce conflict. - * It also seems more logical as the "immediate" - * argument is listed as the second arg like the - * other formats. - */ - -f2_opcode: - T_SHL { $$ = AIC_OP_SHL; } -| T_SHR { $$ = AIC_OP_SHR; } -| T_ROL { $$ = AIC_OP_ROL; } -| T_ROR { $$ = AIC_OP_ROR; } -; - -/* - * 16bit opcodes, not used - * - *f4_opcode: - * T_OR16 { $$ = AIC_OP_OR16; } - *| T_AND16 { $$ = AIC_OP_AND16; } - *| T_XOR16 { $$ = AIC_OP_XOR16; } - *| T_ADD16 { $$ = AIC_OP_ADD16; } - *| T_ADC16 { $$ = AIC_OP_ADC16; } - *| T_MVI16 { $$ = AIC_OP_MVI16; } - *; - */ - -code: - f2_opcode destination ',' expression opt_source ret ';' - { - format_2_instr($1, &$2, &$4, &$5, $6); - } -; - -jmp_jc_jnc_call: - T_JMP { $$ = AIC_OP_JMP; } -| T_JC { $$ = AIC_OP_JC; } -| T_JNC { $$ = AIC_OP_JNC; } -| T_CALL { $$ = AIC_OP_CALL; } -; - -jz_jnz: - T_JZ { $$ = AIC_OP_JZ; } -| T_JNZ { $$ = AIC_OP_JNZ; } -; - -je_jne: - T_JE { $$ = AIC_OP_JE; } -| T_JNE { $$ = AIC_OP_JNE; } -; - -code: - jmp_jc_jnc_call address ';' - { - expression_t immed; - - make_expression(&immed, 0); - format_3_instr($1, &sindex, &immed, &$2); - } -; - -code: - T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';' - { - type_check(&$2, &$4, AIC_OP_OR); - format_3_instr($5, &$2, &$4, &$6); - } -; - -code: - T_TEST source ',' immediate_or_a jz_jnz address ';' - { - format_3_instr($5, &$2, &$4, &$6); - } -; - -code: - T_CMP source ',' immediate_or_a je_jne address ';' - { - format_3_instr($5, &$2, &$4, &$6); - } -; - -code: - T_MOV source jmp_jc_jnc_call address ';' - { - expression_t immed; - - make_expression(&immed, 0); - format_3_instr($3, &$2, &immed, &$4); - } -; - -code: - T_MVI immediate jmp_jc_jnc_call address ';' - { - format_3_instr($3, &allzeros, &$2, &$4); - } -; - -%% - -static void -process_field(int field_type, symbol_t *sym, int value) -{ - /* - * Add the current register to its - * symbol list, if it already exists, - * warn if we are setting it to a - * different value, or in the bit to - * the "allowed bits" of this register. - */ - if (sym->type == UNINITIALIZED) { - sym->type = field_type; - initialize_symbol(sym); - sym->info.finfo->value = value; - if (field_type != ENUM_ENTRY) { - if (field_type != MASK && value == 0) { - stop("Empty Field, or Enum", EX_DATAERR); - /* NOTREACHED */ - } - sym->info.finfo->value = value; - sym->info.finfo->mask = value; - } else if (field_symbol != NULL) { - sym->info.finfo->mask = field_symbol->info.finfo->value; - } else { - sym->info.finfo->mask = 0xFF; - } - } else if (sym->type != field_type) { - stop("Field definition mirrors a definition of the same " - " name, but a different type", EX_DATAERR); - /* NOTREACHED */ - } else if (value != sym->info.finfo->value) { - stop("Field redefined with a conflicting value", EX_DATAERR); - /* NOTREACHED */ - } - /* Fail if this symbol is already listed */ - if (symlist_search(&(sym->info.finfo->symrefs), - cur_symbol->name) != NULL) { - stop("Field defined multiple times for register", EX_DATAERR); - /* NOTREACHED */ - } - symlist_add(&(sym->info.finfo->symrefs), cur_symbol, - SYMLIST_INSERT_HEAD); - cur_symbol->info.rinfo->valid_bitmask |= sym->info.finfo->mask; - cur_symbol->info.rinfo->typecheck_masks = TRUE; - symlist_add(&(cur_symbol->info.rinfo->fields), sym, SYMLIST_SORT); -} - -static void -initialize_symbol(symbol_t *symbol) -{ - switch (symbol->type) { - case UNINITIALIZED: - stop("Call to initialize_symbol with type field unset", - EX_SOFTWARE); - /* NOTREACHED */ - break; - case REGISTER: - case SRAMLOC: - case SCBLOC: - symbol->info.rinfo = - (struct reg_info *)malloc(sizeof(struct reg_info)); - if (symbol->info.rinfo == NULL) { - stop("Can't create register info", EX_SOFTWARE); - /* NOTREACHED */ - } - memset(symbol->info.rinfo, 0, - sizeof(struct reg_info)); - SLIST_INIT(&(symbol->info.rinfo->fields)); - /* - * Default to allowing access in all register modes - * or to the mode specified by the SCB or SRAM space - * we are in. - */ - if (scb_or_sram_symbol != NULL) - symbol->info.rinfo->modes = - scb_or_sram_symbol->info.rinfo->modes; - else - symbol->info.rinfo->modes = ~0; - break; - case ALIAS: - symbol->info.ainfo = - (struct alias_info *)malloc(sizeof(struct alias_info)); - if (symbol->info.ainfo == NULL) { - stop("Can't create alias info", EX_SOFTWARE); - /* NOTREACHED */ - } - memset(symbol->info.ainfo, 0, - sizeof(struct alias_info)); - break; - case MASK: - case FIELD: - case ENUM: - case ENUM_ENTRY: - symbol->info.finfo = - (struct field_info *)malloc(sizeof(struct field_info)); - if (symbol->info.finfo == NULL) { - stop("Can't create field info", EX_SOFTWARE); - /* NOTREACHED */ - } - memset(symbol->info.finfo, 0, sizeof(struct field_info)); - SLIST_INIT(&(symbol->info.finfo->symrefs)); - break; - case CONST: - case DOWNLOAD_CONST: - symbol->info.cinfo = - (struct const_info *)malloc(sizeof(struct const_info)); - if (symbol->info.cinfo == NULL) { - stop("Can't create alias info", EX_SOFTWARE); - /* NOTREACHED */ - } - memset(symbol->info.cinfo, 0, - sizeof(struct const_info)); - break; - case LABEL: - symbol->info.linfo = - (struct label_info *)malloc(sizeof(struct label_info)); - if (symbol->info.linfo == NULL) { - stop("Can't create label info", EX_SOFTWARE); - /* NOTREACHED */ - } - memset(symbol->info.linfo, 0, - sizeof(struct label_info)); - break; - case CONDITIONAL: - symbol->info.condinfo = - (struct cond_info *)malloc(sizeof(struct cond_info)); - if (symbol->info.condinfo == NULL) { - stop("Can't create conditional info", EX_SOFTWARE); - /* NOTREACHED */ - } - memset(symbol->info.condinfo, 0, - sizeof(struct cond_info)); - break; - case MACRO: - symbol->info.macroinfo = - (struct macro_info *)malloc(sizeof(struct macro_info)); - if (symbol->info.macroinfo == NULL) { - stop("Can't create macro info", EX_SOFTWARE); - /* NOTREACHED */ - } - memset(symbol->info.macroinfo, 0, - sizeof(struct macro_info)); - STAILQ_INIT(&symbol->info.macroinfo->args); - break; - default: - stop("Call to initialize_symbol with invalid symbol type", - EX_SOFTWARE); - /* NOTREACHED */ - break; - } -} - -static void -add_macro_arg(const char *argtext, int argnum) -{ - struct macro_arg *marg; - int i; - int retval; - - if (cur_symbol == NULL || cur_symbol->type != MACRO) { - stop("Invalid current symbol for adding macro arg", - EX_SOFTWARE); - /* NOTREACHED */ - } - - marg = (struct macro_arg *)malloc(sizeof(*marg)); - if (marg == NULL) { - stop("Can't create macro_arg structure", EX_SOFTWARE); - /* NOTREACHED */ - } - marg->replacement_text = NULL; - retval = snprintf(regex_pattern, sizeof(regex_pattern), - "[^-/A-Za-z0-9_](%s)([^-/A-Za-z0-9_]|$)", - argtext); - if (retval >= sizeof(regex_pattern)) { - stop("Regex text buffer too small for arg", - EX_SOFTWARE); - /* NOTREACHED */ - } - retval = regcomp(&marg->arg_regex, regex_pattern, REG_EXTENDED); - if (retval != 0) { - stop("Regex compilation failed", EX_SOFTWARE); - /* NOTREACHED */ - } - STAILQ_INSERT_TAIL(&cur_symbol->info.macroinfo->args, marg, links); -} - -static void -add_macro_body(const char *bodytext) -{ - if (cur_symbol == NULL || cur_symbol->type != MACRO) { - stop("Invalid current symbol for adding macro arg", - EX_SOFTWARE); - /* NOTREACHED */ - } - cur_symbol->info.macroinfo->body = strdup(bodytext); - if (cur_symbol->info.macroinfo->body == NULL) { - stop("Can't duplicate macro body text", EX_SOFTWARE); - /* NOTREACHED */ - } -} - -static void -process_register(symbol_t **p_symbol) -{ - symbol_t *symbol = *p_symbol; - - if (symbol->type == UNINITIALIZED) { - snprintf(errbuf, sizeof(errbuf), "Undefined register %s", - symbol->name); - stop(errbuf, EX_DATAERR); - /* NOTREACHED */ - } else if (symbol->type == ALIAS) { - *p_symbol = symbol->info.ainfo->parent; - } else if ((symbol->type != REGISTER) - && (symbol->type != SCBLOC) - && (symbol->type != SRAMLOC)) { - snprintf(errbuf, sizeof(errbuf), - "Specified symbol %s is not a register", - symbol->name); - stop(errbuf, EX_DATAERR); - } -} - -static void -format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed, - symbol_ref_t *src, int ret) -{ - struct instruction *instr; - struct ins_format1 *f1_instr; - - if (src->symbol == NULL) - src = dest; - - /* Test register permissions */ - test_writable_symbol(dest->symbol); - test_readable_symbol(src->symbol); - - if (!is_location_address(dest->symbol)) { - /* Ensure that immediate makes sense for this destination */ - type_check(dest, immed, opcode); - } - - /* Allocate sequencer space for the instruction and fill it out */ - instr = seq_alloc(); - f1_instr = &instr->format.format1; - f1_instr->ret = ret ? 1 : 0; - f1_instr->opcode = opcode; - f1_instr->destination = dest->symbol->info.rinfo->address - + dest->offset; - f1_instr->source = src->symbol->info.rinfo->address - + src->offset; - f1_instr->immediate = immed->value; - - if (is_download_const(immed)) - f1_instr->parity = 1; - else if (dest->symbol == mode_ptr.symbol) { - u_int src_value; - u_int dst_value; - - /* - * Attempt to update mode information if - * we are operating on the mode register. - */ - if (src->symbol == allones.symbol) - src_value = 0xFF; - else if (src->symbol == allzeros.symbol) - src_value = 0; - else if (src->symbol == mode_ptr.symbol) - src_value = (dst_mode << 4) | src_mode; - else - goto cant_update; - - switch (opcode) { - case AIC_OP_AND: - dst_value = src_value & immed->value; - break; - case AIC_OP_XOR: - dst_value = src_value ^ immed->value; - break; - case AIC_OP_ADD: - dst_value = (src_value + immed->value) & 0xFF; - break; - case AIC_OP_OR: - dst_value = src_value | immed->value; - break; - case AIC_OP_BMOV: - dst_value = src_value; - break; - default: - goto cant_update; - } - src_mode = dst_value & 0xF; - dst_mode = (dst_value >> 4) & 0xF; - } - -cant_update: - symlist_free(&immed->referenced_syms); - instruction_ptr++; -} - -static void -format_2_instr(int opcode, symbol_ref_t *dest, expression_t *places, - symbol_ref_t *src, int ret) -{ - struct instruction *instr; - struct ins_format2 *f2_instr; - uint8_t shift_control; - - if (src->symbol == NULL) - src = dest; - - /* Test register permissions */ - test_writable_symbol(dest->symbol); - test_readable_symbol(src->symbol); - - /* Allocate sequencer space for the instruction and fill it out */ - instr = seq_alloc(); - f2_instr = &instr->format.format2; - f2_instr->ret = ret ? 1 : 0; - f2_instr->opcode = AIC_OP_ROL; - f2_instr->destination = dest->symbol->info.rinfo->address - + dest->offset; - f2_instr->source = src->symbol->info.rinfo->address - + src->offset; - if (places->value > 8 || places->value <= 0) { - stop("illegal shift value", EX_DATAERR); - /* NOTREACHED */ - } - switch (opcode) { - case AIC_OP_SHL: - if (places->value == 8) - shift_control = 0xf0; - else - shift_control = (places->value << 4) | places->value; - break; - case AIC_OP_SHR: - if (places->value == 8) { - shift_control = 0xf8; - } else { - shift_control = (places->value << 4) - | (8 - places->value) - | 0x08; - } - break; - case AIC_OP_ROL: - shift_control = places->value & 0x7; - break; - case AIC_OP_ROR: - shift_control = (8 - places->value) | 0x08; - break; - default: - shift_control = 0; /* Quiet Compiler */ - stop("Invalid shift operation specified", EX_SOFTWARE); - /* NOTREACHED */ - break; - }; - f2_instr->shift_control = shift_control; - symlist_free(&places->referenced_syms); - instruction_ptr++; -} - -static void -format_3_instr(int opcode, symbol_ref_t *src, - expression_t *immed, symbol_ref_t *address) -{ - struct instruction *instr; - struct ins_format3 *f3_instr; - int addr; - - /* Test register permissions */ - test_readable_symbol(src->symbol); - - /* Allocate sequencer space for the instruction and fill it out */ - instr = seq_alloc(); - f3_instr = &instr->format.format3; - if (address->symbol == NULL) { - /* 'dot' reference. Use the current instruction pointer */ - addr = instruction_ptr + address->offset; - } else if (address->symbol->type == UNINITIALIZED) { - /* forward reference */ - addr = address->offset; - instr->patch_label = address->symbol; - } else - addr = address->symbol->info.linfo->address + address->offset; - f3_instr->opcode = opcode; - f3_instr->address = addr; - f3_instr->source = src->symbol->info.rinfo->address - + src->offset; - f3_instr->immediate = immed->value; - - if (is_download_const(immed)) - f3_instr->parity = 1; - - symlist_free(&immed->referenced_syms); - instruction_ptr++; -} - -static void -test_readable_symbol(symbol_t *symbol) -{ - if ((symbol->info.rinfo->modes & (0x1 << src_mode)) == 0) { - snprintf(errbuf, sizeof(errbuf), - "Register %s unavailable in source reg mode %d", - symbol->name, src_mode); - stop(errbuf, EX_DATAERR); - } - - if (symbol->info.rinfo->mode == WO) { - stop("Write Only register specified as source", - EX_DATAERR); - /* NOTREACHED */ - } -} - -static void -test_writable_symbol(symbol_t *symbol) -{ - if ((symbol->info.rinfo->modes & (0x1 << dst_mode)) == 0) { - snprintf(errbuf, sizeof(errbuf), - "Register %s unavailable in destination reg mode %d", - symbol->name, dst_mode); - stop(errbuf, EX_DATAERR); - } - - if (symbol->info.rinfo->mode == RO) { - stop("Read Only register specified as destination", - EX_DATAERR); - /* NOTREACHED */ - } -} - -static void -type_check(symbol_ref_t *sym, expression_t *expression, int opcode) -{ - symbol_t *symbol = sym->symbol; - symbol_node_t *node; - int and_op; - int8_t value, mask; - - and_op = FALSE; - /* - * Make sure that we aren't attempting to write something - * that hasn't been defined. If this is an and operation, - * this is a mask, so "undefined" bits are okay. - */ - if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || - opcode == AIC_OP_JZ || opcode == AIC_OP_JNE || - opcode == AIC_OP_BMOV) - and_op = TRUE; - - /* - * Defaulting to 8 bit logic - */ - mask = (int8_t)~symbol->info.rinfo->valid_bitmask; - value = (int8_t)expression->value; - - if (and_op == FALSE && (mask & value) != 0 ) { - snprintf(errbuf, sizeof(errbuf), - "Invalid bit(s) 0x%x in immediate written to %s", - (mask & value), - symbol->name); - stop(errbuf, EX_DATAERR); - /* NOTREACHED */ - } - - /* - * Now make sure that all of the symbols referenced by the - * expression are defined for this register. - */ - if (symbol->info.rinfo->typecheck_masks != FALSE) { - for(node = expression->referenced_syms.slh_first; - node != NULL; - node = node->links.sle_next) { - if ((node->symbol->type == MASK - || node->symbol->type == FIELD - || node->symbol->type == ENUM - || node->symbol->type == ENUM_ENTRY) - && symlist_search(&node->symbol->info.finfo->symrefs, - symbol->name) == NULL) { - snprintf(errbuf, sizeof(errbuf), - "Invalid field or mask %s " - "for register %s", - node->symbol->name, symbol->name); - stop(errbuf, EX_DATAERR); - /* NOTREACHED */ - } - } - } -} - -static void -make_expression(expression_t *immed, int value) -{ - SLIST_INIT(&immed->referenced_syms); - immed->value = value & 0xff; -} - -static void -add_conditional(symbol_t *symbol) -{ - static int numfuncs; - - if (numfuncs == 0) { - /* add a special conditional, "0" */ - symbol_t *false_func; - - false_func = symtable_get("0"); - if (false_func->type != UNINITIALIZED) { - stop("Conditional expression '0' " - "conflicts with a symbol", EX_DATAERR); - /* NOTREACHED */ - } - false_func->type = CONDITIONAL; - initialize_symbol(false_func); - false_func->info.condinfo->func_num = numfuncs++; - symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD); - } - - /* This condition has occurred before */ - if (symbol->type == CONDITIONAL) - return; - - if (symbol->type != UNINITIALIZED) { - stop("Conditional expression conflicts with a symbol", - EX_DATAERR); - /* NOTREACHED */ - } - - symbol->type = CONDITIONAL; - initialize_symbol(symbol); - symbol->info.condinfo->func_num = numfuncs++; - symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD); -} - -static void -add_version(const char *verstring) -{ - const char prefix[] = " * "; - int newlen; - int oldlen; - - newlen = strlen(verstring) + strlen(prefix); - oldlen = 0; - if (versions != NULL) - oldlen = strlen(versions); - versions = realloc(versions, newlen + oldlen + 2); - if (versions == NULL) - stop("Can't allocate version string", EX_SOFTWARE); - strcpy(&versions[oldlen], prefix); - strcpy(&versions[oldlen + strlen(prefix)], verstring); - versions[newlen + oldlen] = '\n'; - versions[newlen + oldlen + 1] = '\0'; -} - -void -yyerror(const char *string) -{ - stop(string, EX_DATAERR); -} - -static int -is_download_const(expression_t *immed) -{ - if ((immed->referenced_syms.slh_first != NULL) - && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST)) - return (TRUE); - - return (FALSE); -} - -static int -is_location_address(symbol_t *sym) -{ - if (sym->type == SCBLOC || - sym->type == SRAMLOC) - return (TRUE); - return (FALSE); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h deleted file mode 100644 index 9df9e2ce..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h +++ /dev/null @@ -1,219 +0,0 @@ -/* - * Instruction formats for the sequencer program downloaded to - * Aic7xxx SCSI host adapters - * - * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#12 $ - * - * $FreeBSD$ - */ - -#include - -/* 8bit ALU logic operations */ -struct ins_format1 { -#ifdef __LITTLE_ENDIAN - uint32_t immediate : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -#else - uint32_t parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - immediate : 8; -#endif -}; - -/* 8bit ALU shift/rotate operations */ -struct ins_format2 { -#ifdef __LITTLE_ENDIAN - uint32_t shift_control : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -#else - uint32_t parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - shift_control : 8; -#endif -}; - -/* 8bit branch control operations */ -struct ins_format3 { -#ifdef __LITTLE_ENDIAN - uint32_t immediate : 8, - source : 9, - address : 10, - opcode : 4, - parity : 1; -#else - uint32_t parity : 1, - opcode : 4, - address : 10, - source : 9, - immediate : 8; -#endif -}; - -/* 16bit ALU logic operations */ -struct ins_format4 { -#ifdef __LITTLE_ENDIAN - uint32_t opcode_ext : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -#else - uint32_t parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - opcode_ext : 8; -#endif -}; - -/* 16bit branch control operations */ -struct ins_format5 { -#ifdef __LITTLE_ENDIAN - uint32_t opcode_ext : 8, - source : 9, - address : 10, - opcode : 4, - parity : 1; -#else - uint32_t parity : 1, - opcode : 4, - address : 10, - source : 9, - opcode_ext : 8; -#endif -}; - -/* Far branch operations */ -struct ins_format6 { -#ifdef __LITTLE_ENDIAN - uint32_t page : 3, - opcode_ext : 5, - source : 9, - address : 10, - opcode : 4, - parity : 1; -#else - uint32_t parity : 1, - opcode : 4, - address : 10, - source : 9, - opcode_ext : 5, - page : 3; -#endif -}; - -union ins_formats { - struct ins_format1 format1; - struct ins_format2 format2; - struct ins_format3 format3; - struct ins_format4 format4; - struct ins_format5 format5; - struct ins_format6 format6; - uint8_t bytes[4]; - uint32_t integer; -}; -struct instruction { - union ins_formats format; - u_int srcline; - struct symbol *patch_label; - STAILQ_ENTRY(instruction) links; -}; - -#define AIC_OP_OR 0x0 -#define AIC_OP_AND 0x1 -#define AIC_OP_XOR 0x2 -#define AIC_OP_ADD 0x3 -#define AIC_OP_ADC 0x4 -#define AIC_OP_ROL 0x5 -#define AIC_OP_BMOV 0x6 - -#define AIC_OP_MVI16 0x7 - -#define AIC_OP_JMP 0x8 -#define AIC_OP_JC 0x9 -#define AIC_OP_JNC 0xa -#define AIC_OP_CALL 0xb -#define AIC_OP_JNE 0xc -#define AIC_OP_JNZ 0xd -#define AIC_OP_JE 0xe -#define AIC_OP_JZ 0xf - -/* Pseudo Ops */ -#define AIC_OP_SHL 0x10 -#define AIC_OP_SHR 0x20 -#define AIC_OP_ROR 0x30 - -/* 16bit Ops. Low byte main opcode. High byte extended opcode. */ -#define AIC_OP_OR16 0x8005 -#define AIC_OP_AND16 0x8105 -#define AIC_OP_XOR16 0x8205 -#define AIC_OP_ADD16 0x8305 -#define AIC_OP_ADC16 0x8405 -#define AIC_OP_JNE16 0x8805 -#define AIC_OP_JNZ16 0x8905 -#define AIC_OP_JE16 0x8C05 -#define AIC_OP_JZ16 0x8B05 -#define AIC_OP_JMP16 0x9005 -#define AIC_OP_JC16 0x9105 -#define AIC_OP_JNC16 0x9205 -#define AIC_OP_CALL16 0x9305 -#define AIC_OP_CALL16 0x9305 - -/* Page extension is low three bits of second opcode byte. */ -#define AIC_OP_JMPF 0xA005 -#define AIC_OP_CALLF 0xB005 -#define AIC_OP_JCF 0xC005 -#define AIC_OP_JNCF 0xD005 -#define AIC_OP_CMPXCHG 0xE005 diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y deleted file mode 100644 index 708326df..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y +++ /dev/null @@ -1,165 +0,0 @@ -%{ -/* - * Sub-parser for macro invocation in the Aic7xxx SCSI - * Host adapter sequencer assembler. - * - * Copyright (c) 2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_macro_gram.y#5 $ - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include -#include -#include - -#ifdef __linux__ -#include "../queue.h" -#else -#include -#endif - -#include "aicasm.h" -#include "aicasm_symbol.h" -#include "aicasm_insformat.h" - -static symbol_t *macro_symbol; - -static void add_macro_arg(const char *argtext, int position); -void mmerror(const char *string); - -%} - -%union { - int value; - char *str; - symbol_t *sym; -} - - -%token T_ARG - -%token T_SYMBOL - -%type macro_arglist - -%% - -macrocall: - T_SYMBOL '(' - { - macro_symbol = $1; - } - macro_arglist ')' - { - if (macro_symbol->info.macroinfo->narg != $4) { - printf("Narg == %d", macro_symbol->info.macroinfo->narg); - stop("Too few arguments for macro invocation", - EX_DATAERR); - /* NOTREACHED */ - } - macro_symbol = NULL; - YYACCEPT; - } -; - -macro_arglist: - { - /* Macros can take 0 arguments */ - $$ = 0; - } -| T_ARG - { - $$ = 1; - add_macro_arg($1, 1); - } -| macro_arglist ',' T_ARG - { - if ($1 == 0) { - stop("Comma without preceding argument in arg list", - EX_DATAERR); - /* NOTREACHED */ - } - $$ = $1 + 1; - add_macro_arg($3, $$); - } -; - -%% - -static void -add_macro_arg(const char *argtext, int argnum) -{ - struct macro_arg *marg; - int i; - - if (macro_symbol == NULL || macro_symbol->type != MACRO) { - stop("Invalid current symbol for adding macro arg", - EX_SOFTWARE); - /* NOTREACHED */ - } - /* - * Macro Invocation. Find the appropriate argument and fill - * in the replace ment text for this call. - */ - i = 0; - STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { - i++; - if (i == argnum) - break; - } - if (marg == NULL) { - stop("Too many arguments for macro invocation", EX_DATAERR); - /* NOTREACHED */ - } - marg->replacement_text = strdup(argtext); - if (marg->replacement_text == NULL) { - stop("Unable to replicate replacement text", EX_SOFTWARE); - /* NOTREACHED */ - } -} - -void -mmerror(const char *string) -{ - stop(string, EX_DATAERR); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l deleted file mode 100644 index c0457b8c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l +++ /dev/null @@ -1,157 +0,0 @@ -%{ -/* - * Sub-Lexical Analyzer for macro invokation in - * the Aic7xxx SCSI Host adapter sequencer assembler. - * - * Copyright (c) 2001 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_macro_scan.l#8 $ - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include -#include -#include -#ifdef __linux__ -#include "../queue.h" -#else -#include -#endif - -#include "aicasm.h" -#include "aicasm_symbol.h" -#include "aicasm_macro_gram.h" - -#define MAX_STR_CONST 4096 -static char string_buf[MAX_STR_CONST]; -static char *string_buf_ptr; -static int parren_count; -static char buf[255]; -int mmlineno; -%} - -WORD [A-Za-z_][-A-Za-z_0-9]* -SPACE [ \t]+ -MCARG [^(), \t]+ - -%x ARGLIST - -%% -\n { - ++mmlineno; - } -\r ; -{SPACE} ; -\( { - parren_count++; - if (parren_count == 1) { - string_buf_ptr = string_buf; - return ('('); - } - *string_buf_ptr++ = '('; - } -\) { - if (parren_count == 1) { - if (string_buf_ptr != string_buf) { - /* - * Return an argument and - * rescan this parren so we - * can return it as well. - */ - *string_buf_ptr = '\0'; - mmlval.str = string_buf; - string_buf_ptr = string_buf; - unput(')'); - return T_ARG; - } - BEGIN INITIAL; - return (')'); - } - parren_count--; - *string_buf_ptr++ = ')'; - } -{MCARG} { - char *yptr; - - yptr = mmtext; - while (*yptr) - *string_buf_ptr++ = *yptr++; - } -\, { - if (string_buf_ptr != string_buf) { - /* - * Return an argument and - * rescan this comma so we - * can return it as well. - */ - *string_buf_ptr = '\0'; - mmlval.str = string_buf; - string_buf_ptr = string_buf; - unput(','); - return T_ARG; - } - return ','; - } -{WORD}[(] { - /* May be a symbol or a macro invocation. */ - mmlval.sym = symtable_get(mmtext); - if (mmlval.sym->type != MACRO) { - stop("Expecting Macro Name", - EX_DATAERR); - } - unput('('); - parren_count = 0; - BEGIN ARGLIST; - return T_SYMBOL; - } -. { - snprintf(buf, sizeof(buf), "Invalid character " - "'%c'", mmtext[0]); - stop(buf, EX_DATAERR); - } -%% - -int -mmwrap() -{ - stop("EOF encountered in macro call", EX_DATAERR); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l deleted file mode 100644 index 93c8667c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l +++ /dev/null @@ -1,622 +0,0 @@ -%{ -/* - * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler. - * - * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs. - * Copyright (c) 2001, 2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#20 $ - * - * $FreeBSD$ - */ - -#include - -#include -#include -#include -#include -#include -#include -#ifdef __linux__ -#include "../queue.h" -#else -#include -#endif - -#include "aicasm.h" -#include "aicasm_symbol.h" -#include "aicasm_gram.h" - -/* This is used for macro body capture too, so err on the large size. */ -#define MAX_STR_CONST 4096 -static char string_buf[MAX_STR_CONST]; -static char *string_buf_ptr; -static int parren_count; -static int quote_count; -static char buf[255]; -%} - -PATH ([/]*[-A-Za-z0-9_.])+ -WORD [A-Za-z_][-A-Za-z_0-9]* -SPACE [ \t]+ -MCARG [^(), \t]+ -MBODY ((\\[^\n])*[^\n\\]*)+ - -%x COMMENT -%x CEXPR -%x INCLUDE -%x STRING -%x MACRODEF -%x MACROARGLIST -%x MACROCALLARGS -%x MACROBODY - -%% -\n { ++yylineno; } -\r ; -"/*" { BEGIN COMMENT; /* Enter comment eating state */ } -"/*" { fprintf(stderr, "Warning! Comment within comment."); } -\n { ++yylineno; } -[^*/\n]* ; -"*"+[^*/\n]* ; -"/"+[^*/\n]* ; -"*"+"/" { BEGIN INITIAL; } -if[ \t]*\( { - string_buf_ptr = string_buf; - parren_count = 1; - BEGIN CEXPR; - return T_IF; - } -\( { *string_buf_ptr++ = '('; parren_count++; } -\) { - parren_count--; - if (parren_count == 0) { - /* All done */ - BEGIN INITIAL; - *string_buf_ptr = '\0'; - yylval.sym = symtable_get(string_buf); - return T_CEXPR; - } else { - *string_buf_ptr++ = ')'; - } - } -\n { ++yylineno; } -\r ; -[^()\n]+ { - char *yptr; - - yptr = yytext; - while (*yptr != '\0') { - /* Remove duplicate spaces */ - if (*yptr == '\t') - *yptr = ' '; - if (*yptr == ' ' - && string_buf_ptr != string_buf - && string_buf_ptr[-1] == ' ') - yptr++; - else - *string_buf_ptr++ = *yptr++; - } - } -else { return T_ELSE; } -VERSION { return T_VERSION; } -PREFIX { return T_PREFIX; } -PATCH_ARG_LIST { return T_PATCH_ARG_LIST; } -\" { - string_buf_ptr = string_buf; - BEGIN STRING; - } -[^"]+ { - char *yptr; - - yptr = yytext; - while (*yptr) - *string_buf_ptr++ = *yptr++; - } -\" { - /* All done */ - BEGIN INITIAL; - *string_buf_ptr = '\0'; - yylval.str = string_buf; - return T_STRING; - } -{SPACE} ; - - /* Register/SCB/SRAM definition keywords */ -export { return T_EXPORT; } -register { return T_REGISTER; } -const { yylval.value = FALSE; return T_CONST; } -download { return T_DOWNLOAD; } -address { return T_ADDRESS; } -count { return T_COUNT; } -access_mode { return T_ACCESS_MODE; } -dont_generate_debug_code { return T_DONT_GENERATE_DEBUG_CODE; } -modes { return T_MODES; } -RW|RO|WO { - if (strcmp(yytext, "RW") == 0) - yylval.value = RW; - else if (strcmp(yytext, "RO") == 0) - yylval.value = RO; - else - yylval.value = WO; - return T_MODE; - } -field { return T_FIELD; } -enum { return T_ENUM; } -mask { return T_MASK; } -alias { return T_ALIAS; } -size { return T_SIZE; } -scb { return T_SCB; } -scratch_ram { return T_SRAM; } -accumulator { return T_ACCUM; } -mode_pointer { return T_MODE_PTR; } -allones { return T_ALLONES; } -allzeros { return T_ALLZEROS; } -none { return T_NONE; } -sindex { return T_SINDEX; } -A { return T_A; } - - /* Instruction Formatting */ -PAD_PAGE { return T_PAD_PAGE; } -BEGIN_CRITICAL { return T_BEGIN_CS; } -END_CRITICAL { return T_END_CS; } -SET_SRC_MODE { return T_SET_SRC_MODE; } -SET_DST_MODE { return T_SET_DST_MODE; } - - /* Opcodes */ -shl { return T_SHL; } -shr { return T_SHR; } -ror { return T_ROR; } -rol { return T_ROL; } -mvi { return T_MVI; } -mov { return T_MOV; } -clr { return T_CLR; } -jmp { return T_JMP; } -jc { return T_JC; } -jnc { return T_JNC; } -je { return T_JE; } -jne { return T_JNE; } -jz { return T_JZ; } -jnz { return T_JNZ; } -call { return T_CALL; } -add { return T_ADD; } -adc { return T_ADC; } -bmov { return T_BMOV; } -inc { return T_INC; } -dec { return T_DEC; } -stc { return T_STC; } -clc { return T_CLC; } -cmp { return T_CMP; } -not { return T_NOT; } -xor { return T_XOR; } -test { return T_TEST;} -and { return T_AND; } -or { return T_OR; } -ret { return T_RET; } -nop { return T_NOP; } - - /* ARP2 16bit extensions */ - /* or16 { return T_OR16; } */ - /* and16 { return T_AND16; }*/ - /* xor16 { return T_XOR16; }*/ - /* add16 { return T_ADD16; }*/ - /* adc16 { return T_ADC16; }*/ - /* mvi16 { return T_MVI16; }*/ - /* test16 { return T_TEST16; }*/ - /* cmp16 { return T_CMP16; }*/ - /* cmpxchg { return T_CMPXCHG; }*/ - - /* Allowed Symbols */ -\<\< { return T_EXPR_LSHIFT; } -\>\> { return T_EXPR_RSHIFT; } -[-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; } - - /* Number processing */ -0[0-7]* { - yylval.value = strtol(yytext, NULL, 8); - return T_NUMBER; - } - -0[xX][0-9a-fA-F]+ { - yylval.value = strtoul(yytext + 2, NULL, 16); - return T_NUMBER; - } - -[1-9][0-9]* { - yylval.value = strtol(yytext, NULL, 10); - return T_NUMBER; - } - /* Include Files */ -#include{SPACE} { - BEGIN INCLUDE; - quote_count = 0; - return T_INCLUDE; - } -[<] { return yytext[0]; } -[>] { BEGIN INITIAL; return yytext[0]; } -[\"] { - if (quote_count != 0) - BEGIN INITIAL; - quote_count++; - return yytext[0]; - } -{PATH} { - char *yptr; - - yptr = yytext; - string_buf_ptr = string_buf; - while (*yptr) - *string_buf_ptr++ = *yptr++; - yylval.str = string_buf; - *string_buf_ptr = '\0'; - return T_PATH; - } -. { stop("Invalid include line", EX_DATAERR); } -#define{SPACE} { - BEGIN MACRODEF; - return T_DEFINE; - } -{WORD}{SPACE} { - char *yptr; - - /* Strip space and return as a normal symbol */ - yptr = yytext; - while (*yptr != ' ' && *yptr != '\t') - yptr++; - *yptr = '\0'; - yylval.sym = symtable_get(yytext); - string_buf_ptr = string_buf; - BEGIN MACROBODY; - return T_SYMBOL; - } -{WORD}\( { - /* - * We store the symbol with its opening - * parren so we can differentiate macros - * that take args from macros with the - * same name that do not take args as - * is allowed in C. - */ - BEGIN MACROARGLIST; - yylval.sym = symtable_get(yytext); - unput('('); - return T_SYMBOL; - } -{WORD} { - yylval.str = yytext; - return T_ARG; - } -{SPACE} ; -[(,] { - return yytext[0]; - } -[)] { - string_buf_ptr = string_buf; - BEGIN MACROBODY; - return ')'; - } -. { - snprintf(buf, sizeof(buf), "Invalid character " - "'%c' in macro argument list", - yytext[0]); - stop(buf, EX_DATAERR); - } -{SPACE} ; -\( { - parren_count++; - if (parren_count == 1) - return ('('); - *string_buf_ptr++ = '('; - } -\) { - parren_count--; - if (parren_count == 0) { - BEGIN INITIAL; - return (')'); - } - *string_buf_ptr++ = ')'; - } -{MCARG} { - char *yptr; - - yptr = yytext; - while (*yptr) - *string_buf_ptr++ = *yptr++; - } -\, { - if (string_buf_ptr != string_buf) { - /* - * Return an argument and - * rescan this comma so we - * can return it as well. - */ - *string_buf_ptr = '\0'; - yylval.str = string_buf; - string_buf_ptr = string_buf; - unput(','); - return T_ARG; - } - return ','; - } -\\\n { - /* Eat escaped newlines. */ - ++yylineno; - } -\r ; -\n { - /* Macros end on the first unescaped newline. */ - BEGIN INITIAL; - *string_buf_ptr = '\0'; - yylval.str = string_buf; - ++yylineno; - return T_MACROBODY; - } -{MBODY} { - char *yptr; - char c; - - yptr = yytext; - while (c = *yptr++) { - /* - * Strip carriage returns. - */ - if (c == '\r') - continue; - *string_buf_ptr++ = c; - } - } -{WORD}\( { - char *yptr; - char *ycopy; - - /* May be a symbol or a macro invocation. */ - yylval.sym = symtable_get(yytext); - if (yylval.sym->type == MACRO) { - YY_BUFFER_STATE old_state; - YY_BUFFER_STATE temp_state; - - ycopy = strdup(yytext); - yptr = ycopy + yyleng; - while (yptr > ycopy) - unput(*--yptr); - old_state = YY_CURRENT_BUFFER; - temp_state = - yy_create_buffer(stdin, - YY_BUF_SIZE); - yy_switch_to_buffer(temp_state); - mm_switch_to_buffer(old_state); - mmparse(); - mm_switch_to_buffer(temp_state); - yy_switch_to_buffer(old_state); - mm_delete_buffer(temp_state); - expand_macro(yylval.sym); - } else { - if (yylval.sym->type == UNINITIALIZED) { - /* Try without the '(' */ - symbol_delete(yylval.sym); - yytext[yyleng-1] = '\0'; - yylval.sym = - symtable_get(yytext); - } - unput('('); - return T_SYMBOL; - } - } -{WORD} { - yylval.sym = symtable_get(yytext); - if (yylval.sym->type == MACRO) { - expand_macro(yylval.sym); - } else { - return T_SYMBOL; - } - } -. { - snprintf(buf, sizeof(buf), "Invalid character " - "'%c'", yytext[0]); - stop(buf, EX_DATAERR); - } -%% - -typedef struct include { - YY_BUFFER_STATE buffer; - int lineno; - char *filename; - SLIST_ENTRY(include) links; -}include_t; - -SLIST_HEAD(, include) include_stack; - -void -include_file(char *file_name, include_type type) -{ - FILE *newfile; - include_t *include; - - newfile = NULL; - /* Try the current directory first */ - if (includes_search_curdir != 0 || type == SOURCE_FILE) - newfile = fopen(file_name, "r"); - - if (newfile == NULL && type != SOURCE_FILE) { - path_entry_t include_dir; - for (include_dir = search_path.slh_first; - include_dir != NULL; - include_dir = include_dir->links.sle_next) { - char fullname[PATH_MAX]; - - if ((include_dir->quoted_includes_only == TRUE) - && (type != QUOTED_INCLUDE)) - continue; - - snprintf(fullname, sizeof(fullname), - "%s/%s", include_dir->directory, file_name); - - if ((newfile = fopen(fullname, "r")) != NULL) - break; - } - } - - if (newfile == NULL) { - perror(file_name); - stop("Unable to open input file", EX_SOFTWARE); - /* NOTREACHED */ - } - - if (type != SOURCE_FILE) { - include = (include_t *)malloc(sizeof(include_t)); - if (include == NULL) { - stop("Unable to allocate include stack entry", - EX_SOFTWARE); - /* NOTREACHED */ - } - include->buffer = YY_CURRENT_BUFFER; - include->lineno = yylineno; - include->filename = yyfilename; - SLIST_INSERT_HEAD(&include_stack, include, links); - } - yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE)); - yylineno = 1; - yyfilename = strdup(file_name); -} - -static void next_substitution(struct symbol *mac_symbol, const char *body_pos, - const char **next_match, - struct macro_arg **match_marg, regmatch_t *match); - -void -expand_macro(struct symbol *macro_symbol) -{ - struct macro_arg *marg; - struct macro_arg *match_marg; - const char *body_head; - const char *body_pos; - const char *next_match; - - /* - * Due to the nature of unput, we must work - * backwards through the macro body performing - * any expansions. - */ - body_head = macro_symbol->info.macroinfo->body; - body_pos = body_head + strlen(body_head); - while (body_pos > body_head) { - regmatch_t match; - - next_match = body_head; - match_marg = NULL; - next_substitution(macro_symbol, body_pos, &next_match, - &match_marg, &match); - - /* Put back everything up until the replacement. */ - while (body_pos > next_match) - unput(*--body_pos); - - /* Perform the replacement. */ - if (match_marg != NULL) { - const char *strp; - - next_match = match_marg->replacement_text; - strp = next_match + strlen(next_match); - while (strp > next_match) - unput(*--strp); - - /* Skip past the unexpanded macro arg. */ - body_pos -= match.rm_eo - match.rm_so; - } - } - - /* Cleanup replacement text. */ - STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) { - free(marg->replacement_text); - } -} - -/* - * Find the next substitution in the macro working backwards from - * body_pos until the beginning of the macro buffer. next_match - * should be initialized to the beginning of the macro buffer prior - * to calling this routine. - */ -static void -next_substitution(struct symbol *mac_symbol, const char *body_pos, - const char **next_match, struct macro_arg **match_marg, - regmatch_t *match) -{ - regmatch_t matches[2]; - struct macro_arg *marg; - const char *search_pos; - int retval; - - do { - search_pos = *next_match; - - STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) { - - retval = regexec(&marg->arg_regex, search_pos, 2, - matches, 0); - if (retval == 0 - && (matches[1].rm_eo + search_pos) <= body_pos - && (matches[1].rm_eo + search_pos) > *next_match) { - *match = matches[1]; - *next_match = match->rm_eo + search_pos; - *match_marg = marg; - } - } - } while (search_pos != *next_match); -} - -int -yywrap() -{ - include_t *include; - - yy_delete_buffer(YY_CURRENT_BUFFER); - (void)fclose(yyin); - if (yyfilename != NULL) - free(yyfilename); - yyfilename = NULL; - include = include_stack.slh_first; - if (include != NULL) { - yy_switch_to_buffer(include->buffer); - yylineno = include->lineno; - yyfilename = include->filename; - SLIST_REMOVE_HEAD(&include_stack, links); - free(include); - return (0); - } - return (1); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c deleted file mode 100644 index 232aff1f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c +++ /dev/null @@ -1,693 +0,0 @@ -/* - * Aic7xxx SCSI host adapter firmware assembler symbol table implementation - * - * Copyright (c) 1997 Justin T. Gibbs. - * Copyright (c) 2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#24 $ - * - * $FreeBSD$ - */ - -#include - -#ifdef __linux__ -#include "aicdb.h" -#else -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -#include "aicasm_symbol.h" -#include "aicasm.h" - -static DB *symtable; - -symbol_t * -symbol_create(char *name) -{ - symbol_t *new_symbol; - - new_symbol = (symbol_t *)malloc(sizeof(symbol_t)); - if (new_symbol == NULL) { - perror("Unable to create new symbol"); - exit(EX_SOFTWARE); - } - memset(new_symbol, 0, sizeof(*new_symbol)); - new_symbol->name = strdup(name); - if (new_symbol->name == NULL) - stop("Unable to strdup symbol name", EX_SOFTWARE); - new_symbol->type = UNINITIALIZED; - new_symbol->count = 1; - return (new_symbol); -} - -void -symbol_delete(symbol_t *symbol) -{ - if (symtable != NULL) { - DBT key; - - key.data = symbol->name; - key.size = strlen(symbol->name); - symtable->del(symtable, &key, /*flags*/0); - } - switch(symbol->type) { - case SCBLOC: - case SRAMLOC: - case REGISTER: - if (symbol->info.rinfo != NULL) - free(symbol->info.rinfo); - break; - case ALIAS: - if (symbol->info.ainfo != NULL) - free(symbol->info.ainfo); - break; - case MASK: - case FIELD: - case ENUM: - case ENUM_ENTRY: - if (symbol->info.finfo != NULL) { - symlist_free(&symbol->info.finfo->symrefs); - free(symbol->info.finfo); - } - break; - case DOWNLOAD_CONST: - case CONST: - if (symbol->info.cinfo != NULL) - free(symbol->info.cinfo); - break; - case LABEL: - if (symbol->info.linfo != NULL) - free(symbol->info.linfo); - break; - case UNINITIALIZED: - default: - break; - } - free(symbol->name); - free(symbol); -} - -void -symtable_open() -{ - symtable = dbopen(/*filename*/NULL, - O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH, - /*openinfo*/NULL); - - if (symtable == NULL) { - perror("Symbol table creation failed"); - exit(EX_SOFTWARE); - /* NOTREACHED */ - } -} - -void -symtable_close() -{ - if (symtable != NULL) { - DBT key; - DBT data; - - while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) { - symbol_t *stored_ptr; - - memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); - symbol_delete(stored_ptr); - } - symtable->close(symtable); - } -} - -/* - * The semantics of get is to return an uninitialized symbol entry - * if a lookup fails. - */ -symbol_t * -symtable_get(char *name) -{ - symbol_t *stored_ptr; - DBT key; - DBT data; - int retval; - - key.data = (void *)name; - key.size = strlen(name); - - if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) { - if (retval == -1) { - perror("Symbol table get operation failed"); - exit(EX_SOFTWARE); - /* NOTREACHED */ - } else if (retval == 1) { - /* Symbol wasn't found, so create a new one */ - symbol_t *new_symbol; - - new_symbol = symbol_create(name); - data.data = &new_symbol; - data.size = sizeof(new_symbol); - if (symtable->put(symtable, &key, &data, - /*flags*/0) !=0) { - perror("Symtable put failed"); - exit(EX_SOFTWARE); - } - return (new_symbol); - } else { - perror("Unexpected return value from db get routine"); - exit(EX_SOFTWARE); - /* NOTREACHED */ - } - } - memcpy(&stored_ptr, data.data, sizeof(stored_ptr)); - stored_ptr->count++; - data.data = &stored_ptr; - if (symtable->put(symtable, &key, &data, /*flags*/0) !=0) { - perror("Symtable put failed"); - exit(EX_SOFTWARE); - } - return (stored_ptr); -} - -symbol_node_t * -symlist_search(symlist_t *symlist, char *symname) -{ - symbol_node_t *curnode; - - curnode = SLIST_FIRST(symlist); - while(curnode != NULL) { - if (strcmp(symname, curnode->symbol->name) == 0) - break; - curnode = SLIST_NEXT(curnode, links); - } - return (curnode); -} - -void -symlist_add(symlist_t *symlist, symbol_t *symbol, int how) -{ - symbol_node_t *newnode; - - newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t)); - if (newnode == NULL) { - stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE); - /* NOTREACHED */ - } - newnode->symbol = symbol; - if (how == SYMLIST_SORT) { - symbol_node_t *curnode; - int field; - - field = FALSE; - switch(symbol->type) { - case REGISTER: - case SCBLOC: - case SRAMLOC: - break; - case FIELD: - case MASK: - case ENUM: - case ENUM_ENTRY: - field = TRUE; - break; - default: - stop("symlist_add: Invalid symbol type for sorting", - EX_SOFTWARE); - /* NOTREACHED */ - } - - curnode = SLIST_FIRST(symlist); - if (curnode == NULL - || (field - && (curnode->symbol->type > newnode->symbol->type - || (curnode->symbol->type == newnode->symbol->type - && (curnode->symbol->info.finfo->value > - newnode->symbol->info.finfo->value)))) - || (!field && (curnode->symbol->info.rinfo->address > - newnode->symbol->info.rinfo->address))) { - SLIST_INSERT_HEAD(symlist, newnode, links); - return; - } - - while (1) { - if (SLIST_NEXT(curnode, links) == NULL) { - SLIST_INSERT_AFTER(curnode, newnode, - links); - break; - } else { - symbol_t *cursymbol; - - cursymbol = SLIST_NEXT(curnode, links)->symbol; - if ((field - && (cursymbol->type > symbol->type - || (cursymbol->type == symbol->type - && (cursymbol->info.finfo->value > - symbol->info.finfo->value)))) - || (!field - && (cursymbol->info.rinfo->address > - symbol->info.rinfo->address))) { - SLIST_INSERT_AFTER(curnode, newnode, - links); - break; - } - } - curnode = SLIST_NEXT(curnode, links); - } - } else { - SLIST_INSERT_HEAD(symlist, newnode, links); - } -} - -void -symlist_free(symlist_t *symlist) -{ - symbol_node_t *node1, *node2; - - node1 = SLIST_FIRST(symlist); - while (node1 != NULL) { - node2 = SLIST_NEXT(node1, links); - free(node1); - node1 = node2; - } - SLIST_INIT(symlist); -} - -void -symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1, - symlist_t *symlist_src2) -{ - symbol_node_t *node; - - *symlist_dest = *symlist_src1; - while((node = SLIST_FIRST(symlist_src2)) != NULL) { - SLIST_REMOVE_HEAD(symlist_src2, links); - SLIST_INSERT_HEAD(symlist_dest, node, links); - } - - /* These are now empty */ - SLIST_INIT(symlist_src1); - SLIST_INIT(symlist_src2); -} - -void -aic_print_file_prologue(FILE *ofile) -{ - - if (ofile == NULL) - return; - - fprintf(ofile, -"/*\n" -" * DO NOT EDIT - This file is automatically generated\n" -" * from the following source files:\n" -" *\n" -"%s */\n", - versions); -} - -void -aic_print_include(FILE *dfile, char *include_file) -{ - - if (dfile == NULL) - return; - fprintf(dfile, "\n#include \"%s\"\n\n", include_file); -} - -void -aic_print_reg_dump_types(FILE *ofile) -{ - if (ofile == NULL) - return; - - fprintf(ofile, -"typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n" -"typedef struct %sreg_parse_entry {\n" -" char *name;\n" -" uint8_t value;\n" -" uint8_t mask;\n" -"} %sreg_parse_entry_t;\n" -"\n", - prefix, prefix, prefix); -} - -static void -aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode) -{ - if (dfile == NULL) - return; - - fprintf(dfile, -"static const %sreg_parse_entry_t %s_parse_table[] = {\n", - prefix, - regnode->symbol->name); -} - -static void -aic_print_reg_dump_end(FILE *ofile, FILE *dfile, - symbol_node_t *regnode, u_int num_entries) -{ - char *lower_name; - char *letter; - - lower_name = strdup(regnode->symbol->name); - if (lower_name == NULL) - stop("Unable to strdup symbol name", EX_SOFTWARE); - - for (letter = lower_name; *letter != '\0'; letter++) - *letter = tolower(*letter); - - if (dfile != NULL) { - if (num_entries != 0) - fprintf(dfile, -"\n" -"};\n" -"\n"); - - fprintf(dfile, -"int\n" -"%s%s_print(u_int regvalue, u_int *cur_col, u_int wrap)\n" -"{\n" -" return (%sprint_register(%s%s, %d, \"%s\",\n" -" 0x%02x, regvalue, cur_col, wrap));\n" -"}\n" -"\n", - prefix, - lower_name, - prefix, - num_entries != 0 ? regnode->symbol->name : "NULL", - num_entries != 0 ? "_parse_table" : "", - num_entries, - regnode->symbol->name, - regnode->symbol->info.rinfo->address); - } - - fprintf(ofile, -"#if AIC_DEBUG_REGISTERS\n" -"%sreg_print_t %s%s_print;\n" -"#else\n" -"#define %s%s_print(regvalue, cur_col, wrap) \\\n" -" %sprint_register(NULL, 0, \"%s\", 0x%02x, regvalue, cur_col, wrap)\n" -"#endif\n" -"\n", - prefix, - prefix, - lower_name, - prefix, - lower_name, - prefix, - regnode->symbol->name, - regnode->symbol->info.rinfo->address); -} - -static void -aic_print_reg_dump_entry(FILE *dfile, symbol_node_t *curnode) -{ - int num_tabs; - - if (dfile == NULL) - return; - - fprintf(dfile, -" { \"%s\",", - curnode->symbol->name); - - num_tabs = 3 - (strlen(curnode->symbol->name) + 5) / 8; - - while (num_tabs-- > 0) - fputc('\t', dfile); - fprintf(dfile, "0x%02x, 0x%02x }", - curnode->symbol->info.finfo->value, - curnode->symbol->info.finfo->mask); -} - -void -symtable_dump(FILE *ofile, FILE *dfile) -{ - /* - * Sort the registers by address with a simple insertion sort. - * Put bitmasks next to the first register that defines them. - * Put constants at the end. - */ - symlist_t registers; - symlist_t masks; - symlist_t constants; - symlist_t download_constants; - symlist_t aliases; - symlist_t exported_labels; - symbol_node_t *curnode; - symbol_node_t *regnode; - DBT key; - DBT data; - int flag; - int reg_count = 0, reg_used = 0; - u_int i; - - if (symtable == NULL) - return; - - SLIST_INIT(®isters); - SLIST_INIT(&masks); - SLIST_INIT(&constants); - SLIST_INIT(&download_constants); - SLIST_INIT(&aliases); - SLIST_INIT(&exported_labels); - flag = R_FIRST; - while (symtable->seq(symtable, &key, &data, flag) == 0) { - symbol_t *cursym; - - memcpy(&cursym, data.data, sizeof(cursym)); - switch(cursym->type) { - case REGISTER: - case SCBLOC: - case SRAMLOC: - symlist_add(®isters, cursym, SYMLIST_SORT); - break; - case MASK: - case FIELD: - case ENUM: - case ENUM_ENTRY: - symlist_add(&masks, cursym, SYMLIST_SORT); - break; - case CONST: - symlist_add(&constants, cursym, - SYMLIST_INSERT_HEAD); - break; - case DOWNLOAD_CONST: - symlist_add(&download_constants, cursym, - SYMLIST_INSERT_HEAD); - break; - case ALIAS: - symlist_add(&aliases, cursym, - SYMLIST_INSERT_HEAD); - break; - case LABEL: - if (cursym->info.linfo->exported == 0) - break; - symlist_add(&exported_labels, cursym, - SYMLIST_INSERT_HEAD); - break; - default: - break; - } - flag = R_NEXT; - } - - /* Register dianostic functions/declarations first. */ - aic_print_file_prologue(ofile); - aic_print_reg_dump_types(ofile); - aic_print_file_prologue(dfile); - aic_print_include(dfile, stock_include_file); - SLIST_FOREACH(curnode, ®isters, links) { - - if (curnode->symbol->dont_generate_debug_code) - continue; - - switch(curnode->symbol->type) { - case REGISTER: - case SCBLOC: - case SRAMLOC: - { - symlist_t *fields; - symbol_node_t *fieldnode; - int num_entries; - - num_entries = 0; - reg_count++; - if (curnode->symbol->count == 1) - break; - fields = &curnode->symbol->info.rinfo->fields; - SLIST_FOREACH(fieldnode, fields, links) { - if (num_entries == 0) - aic_print_reg_dump_start(dfile, - curnode); - else if (dfile != NULL) - fputs(",\n", dfile); - num_entries++; - aic_print_reg_dump_entry(dfile, fieldnode); - } - aic_print_reg_dump_end(ofile, dfile, - curnode, num_entries); - reg_used++; - } - default: - break; - } - } - fprintf(stderr, "%s: %d of %d register definitions used\n", appname, - reg_used, reg_count); - - /* Fold in the masks and bits */ - while (SLIST_FIRST(&masks) != NULL) { - char *regname; - - curnode = SLIST_FIRST(&masks); - SLIST_REMOVE_HEAD(&masks, links); - - regnode = SLIST_FIRST(&curnode->symbol->info.finfo->symrefs); - regname = regnode->symbol->name; - regnode = symlist_search(®isters, regname); - SLIST_INSERT_AFTER(regnode, curnode, links); - } - - /* Add the aliases */ - while (SLIST_FIRST(&aliases) != NULL) { - char *regname; - - curnode = SLIST_FIRST(&aliases); - SLIST_REMOVE_HEAD(&aliases, links); - - regname = curnode->symbol->info.ainfo->parent->name; - regnode = symlist_search(®isters, regname); - SLIST_INSERT_AFTER(regnode, curnode, links); - } - - /* Output generated #defines. */ - while (SLIST_FIRST(®isters) != NULL) { - symbol_node_t *curnode; - u_int value; - char *tab_str; - char *tab_str2; - - curnode = SLIST_FIRST(®isters); - SLIST_REMOVE_HEAD(®isters, links); - switch(curnode->symbol->type) { - case REGISTER: - case SCBLOC: - case SRAMLOC: - fprintf(ofile, "\n"); - value = curnode->symbol->info.rinfo->address; - tab_str = "\t"; - tab_str2 = "\t\t"; - break; - case ALIAS: - { - symbol_t *parent; - - parent = curnode->symbol->info.ainfo->parent; - value = parent->info.rinfo->address; - tab_str = "\t"; - tab_str2 = "\t\t"; - break; - } - case MASK: - case FIELD: - case ENUM: - case ENUM_ENTRY: - value = curnode->symbol->info.finfo->value; - tab_str = "\t\t"; - tab_str2 = "\t"; - break; - default: - value = 0; /* Quiet compiler */ - tab_str = NULL; - tab_str2 = NULL; - stop("symtable_dump: Invalid symbol type " - "encountered", EX_SOFTWARE); - break; - } - fprintf(ofile, "#define%s%-16s%s0x%02x\n", - tab_str, curnode->symbol->name, tab_str2, - value); - free(curnode); - } - fprintf(ofile, "\n\n"); - - while (SLIST_FIRST(&constants) != NULL) { - symbol_node_t *curnode; - - curnode = SLIST_FIRST(&constants); - SLIST_REMOVE_HEAD(&constants, links); - fprintf(ofile, "#define\t%-8s\t0x%02x\n", - curnode->symbol->name, - curnode->symbol->info.cinfo->value); - free(curnode); - } - - fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n"); - - for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) { - symbol_node_t *curnode; - - curnode = SLIST_FIRST(&download_constants); - SLIST_REMOVE_HEAD(&download_constants, links); - fprintf(ofile, "#define\t%-8s\t0x%02x\n", - curnode->symbol->name, - curnode->symbol->info.cinfo->value); - free(curnode); - } - fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i); - - fprintf(ofile, "\n\n/* Exported Labels */\n"); - - while (SLIST_FIRST(&exported_labels) != NULL) { - symbol_node_t *curnode; - - curnode = SLIST_FIRST(&exported_labels); - SLIST_REMOVE_HEAD(&exported_labels, links); - fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n", - curnode->symbol->name, - curnode->symbol->info.linfo->address); - free(curnode); - } -} - diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h deleted file mode 100644 index 34bbcad7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Aic7xxx SCSI host adapter firmware assembler symbol table definitions - * - * Copyright (c) 1997 Justin T. Gibbs. - * Copyright (c) 2002 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.h#17 $ - * - * $FreeBSD$ - */ - -#ifdef __linux__ -#include "../queue.h" -#else -#include -#endif - -typedef enum { - UNINITIALIZED, - REGISTER, - ALIAS, - SCBLOC, - SRAMLOC, - ENUM_ENTRY, - FIELD, - MASK, - ENUM, - CONST, - DOWNLOAD_CONST, - LABEL, - CONDITIONAL, - MACRO -} symtype; - -typedef enum { - RO = 0x01, - WO = 0x02, - RW = 0x03 -}amode_t; - -typedef SLIST_HEAD(symlist, symbol_node) symlist_t; - -struct reg_info { - u_int address; - int size; - amode_t mode; - symlist_t fields; - uint8_t valid_bitmask; - uint8_t modes; - int typecheck_masks; -}; - -struct field_info { - symlist_t symrefs; - uint8_t value; - uint8_t mask; -}; - -struct const_info { - u_int value; - int define; -}; - -struct alias_info { - struct symbol *parent; -}; - -struct label_info { - int address; - int exported; -}; - -struct cond_info { - int func_num; -}; - -struct macro_arg { - STAILQ_ENTRY(macro_arg) links; - regex_t arg_regex; - char *replacement_text; -}; -STAILQ_HEAD(macro_arg_list, macro_arg) args; - -struct macro_info { - struct macro_arg_list args; - int narg; - const char* body; -}; - -typedef struct expression_info { - symlist_t referenced_syms; - int value; -} expression_t; - -typedef struct symbol { - char *name; - symtype type; - int count; - union { - struct reg_info *rinfo; - struct field_info *finfo; - struct const_info *cinfo; - struct alias_info *ainfo; - struct label_info *linfo; - struct cond_info *condinfo; - struct macro_info *macroinfo; - } info; - int dont_generate_debug_code; -} symbol_t; - -typedef struct symbol_ref { - symbol_t *symbol; - int offset; -} symbol_ref_t; - -typedef struct symbol_node { - SLIST_ENTRY(symbol_node) links; - symbol_t *symbol; -} symbol_node_t; - -typedef struct critical_section { - TAILQ_ENTRY(critical_section) links; - int begin_addr; - int end_addr; -} critical_section_t; - -typedef enum { - SCOPE_ROOT, - SCOPE_IF, - SCOPE_ELSE_IF, - SCOPE_ELSE -} scope_type; - -typedef struct patch_info { - int skip_patch; - int skip_instr; -} patch_info_t; - -typedef struct scope { - SLIST_ENTRY(scope) scope_stack_links; - TAILQ_ENTRY(scope) scope_links; - TAILQ_HEAD(, scope) inner_scope; - scope_type type; - int inner_scope_patches; - int begin_addr; - int end_addr; - patch_info_t patches[2]; - int func_num; -} scope_t; - -TAILQ_HEAD(cs_tailq, critical_section); -SLIST_HEAD(scope_list, scope); -TAILQ_HEAD(scope_tailq, scope); - -void symbol_delete(symbol_t *symbol); - -void symtable_open(void); - -void symtable_close(void); - -symbol_t * - symtable_get(char *name); - -symbol_node_t * - symlist_search(symlist_t *symlist, char *symname); - -void - symlist_add(symlist_t *symlist, symbol_t *symbol, int how); -#define SYMLIST_INSERT_HEAD 0x00 -#define SYMLIST_SORT 0x01 - -void symlist_free(symlist_t *symlist); - -void symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1, - symlist_t *symlist_src2); -void symtable_dump(FILE *ofile, FILE *dfile); diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.c deleted file mode 100644 index 828ae3d9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.c +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Implementation of Utility functions for all SCSI device types. - * - * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs. - * Copyright (c) 1997, 1998 Kenneth D. Merry. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $ - * $Id$ - */ - -#include "aiclib.h" - diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.h deleted file mode 100644 index f8fd198a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/aiclib.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Largely written by Julian Elischer (julian@tfs.com) - * for TRW Financial Systems. - * - * TRW Financial Systems, in accordance with their agreement with Carnegie - * Mellon University, makes this software available to CMU to distribute - * or use in any manner that they see fit as long as this message is kept with - * the software. For this reason TFS also grants any other persons or - * organisations permission to use or modify this software. - * - * TFS supplies this software to be publicly redistributed - * on the understanding that TFS is not responsible for the correct - * functioning of this software in any circumstances. - * - * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992 - * - * $FreeBSD: src/sys/cam/scsi/scsi_all.h,v 1.21 2002/10/08 17:12:44 ken Exp $ - * - * Copyright (c) 2003 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - * $Id$ - */ - -#ifndef _AICLIB_H -#define _AICLIB_H - -struct scsi_sense -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -#define SCSI_REV_0 0 -#define SCSI_REV_CCS 1 -#define SCSI_REV_2 2 -#define SCSI_REV_SPC 3 -#define SCSI_REV_SPC2 4 - -struct scsi_sense_data -{ - uint8_t error_code; -#define SSD_ERRCODE 0x7F -#define SSD_CURRENT_ERROR 0x70 -#define SSD_DEFERRED_ERROR 0x71 -#define SSD_ERRCODE_VALID 0x80 - uint8_t segment; - uint8_t flags; -#define SSD_KEY 0x0F -#define SSD_KEY_NO_SENSE 0x00 -#define SSD_KEY_RECOVERED_ERROR 0x01 -#define SSD_KEY_NOT_READY 0x02 -#define SSD_KEY_MEDIUM_ERROR 0x03 -#define SSD_KEY_HARDWARE_ERROR 0x04 -#define SSD_KEY_ILLEGAL_REQUEST 0x05 -#define SSD_KEY_UNIT_ATTENTION 0x06 -#define SSD_KEY_DATA_PROTECT 0x07 -#define SSD_KEY_BLANK_CHECK 0x08 -#define SSD_KEY_Vendor_Specific 0x09 -#define SSD_KEY_COPY_ABORTED 0x0a -#define SSD_KEY_ABORTED_COMMAND 0x0b -#define SSD_KEY_EQUAL 0x0c -#define SSD_KEY_VOLUME_OVERFLOW 0x0d -#define SSD_KEY_MISCOMPARE 0x0e -#define SSD_KEY_RESERVED 0x0f -#define SSD_ILI 0x20 -#define SSD_EOM 0x40 -#define SSD_FILEMARK 0x80 - uint8_t info[4]; - uint8_t extra_len; - uint8_t cmd_spec_info[4]; - uint8_t add_sense_code; - uint8_t add_sense_code_qual; - uint8_t fru; - uint8_t sense_key_spec[3]; -#define SSD_SCS_VALID 0x80 -#define SSD_FIELDPTR_CMD 0x40 -#define SSD_BITPTR_VALID 0x08 -#define SSD_BITPTR_VALUE 0x07 -#define SSD_MIN_SIZE 18 - uint8_t extra_bytes[14]; -#define SSD_FULL_SIZE sizeof(struct scsi_sense_data) -}; - -/* - * Status Byte - */ -#define SCSI_STATUS_OK 0x00 -#define SCSI_STATUS_CHECK_COND 0x02 -#define SCSI_STATUS_COND_MET 0x04 -#define SCSI_STATUS_BUSY 0x08 -#define SCSI_STATUS_INTERMED 0x10 -#define SCSI_STATUS_INTERMED_COND_MET 0x14 -#define SCSI_STATUS_RESERV_CONFLICT 0x18 -#define SCSI_STATUS_CMD_TERMINATED 0x22 /* Obsolete in SAM-2 */ -#define SCSI_STATUS_QUEUE_FULL 0x28 -#define SCSI_STATUS_ACA_ACTIVE 0x30 -#define SCSI_STATUS_TASK_ABORTED 0x40 - -/************************* Large Disk Handling ********************************/ -static inline int -aic_sector_div(sector_t capacity, int heads, int sectors) -{ - /* ugly, ugly sector_div calling convention.. */ - sector_div(capacity, (heads * sectors)); - return (int)capacity; -} - -static inline uint32_t -scsi_4btoul(uint8_t *bytes) -{ - uint32_t rv; - - rv = (bytes[0] << 24) | - (bytes[1] << 16) | - (bytes[2] << 8) | - bytes[3]; - return (rv); -} - -/* Macros for generating the elements of the PCI ID tables. */ - -#define GETID(v, s) (unsigned)(((v) >> (s)) & 0xFFFF ?: PCI_ANY_ID) - -#define ID_C(x, c) \ -{ \ - GETID(x,32), GETID(x,48), GETID(x,0), GETID(x,16), \ - (c) << 8, 0xFFFF00, 0 \ -} - -#define ID2C(x) \ - ID_C(x, PCI_CLASS_STORAGE_SCSI), \ - ID_C(x, PCI_CLASS_STORAGE_RAID) - -#define IDIROC(x) ((x) | ~ID_ALL_IROC_MASK) - -/* Generate IDs for all 16 possibilites. - * The argument has already masked out - * the 4 least significant bits of the device id. - * (e.g., mask: ID_9005_GENERIC_MASK). - */ -#define ID16(x) \ - ID(x), \ - ID((x) | 0x0001000000000000ull), \ - ID((x) | 0x0002000000000000ull), \ - ID((x) | 0x0003000000000000ull), \ - ID((x) | 0x0004000000000000ull), \ - ID((x) | 0x0005000000000000ull), \ - ID((x) | 0x0006000000000000ull), \ - ID((x) | 0x0007000000000000ull), \ - ID((x) | 0x0008000000000000ull), \ - ID((x) | 0x0009000000000000ull), \ - ID((x) | 0x000A000000000000ull), \ - ID((x) | 0x000B000000000000ull), \ - ID((x) | 0x000C000000000000ull), \ - ID((x) | 0x000D000000000000ull), \ - ID((x) | 0x000E000000000000ull), \ - ID((x) | 0x000F000000000000ull) - -#endif /*_AICLIB_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/cam.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/cam.h deleted file mode 100644 index 687aef6e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/cam.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Data structures and definitions for the CAM system. - * - * Copyright (c) 1997 Justin T. Gibbs. - * Copyright (c) 2000 Adaptec Inc. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL"). - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/cam.h#15 $ - */ - -#ifndef _AIC7XXX_CAM_H -#define _AIC7XXX_CAM_H 1 - -#include - -#define CAM_BUS_WILDCARD ((u_int)~0) -#define CAM_TARGET_WILDCARD ((u_int)~0) -#define CAM_LUN_WILDCARD ((u_int)~0) - -/* CAM Status field values */ -typedef enum { - CAM_REQ_INPROG, /* CCB request is in progress */ - CAM_REQ_CMP, /* CCB request completed without error */ - CAM_REQ_ABORTED, /* CCB request aborted by the host */ - CAM_UA_ABORT, /* Unable to abort CCB request */ - CAM_REQ_CMP_ERR, /* CCB request completed with an error */ - CAM_BUSY, /* CAM subsystem is busy */ - CAM_REQ_INVALID, /* CCB request was invalid */ - CAM_PATH_INVALID, /* Supplied Path ID is invalid */ - CAM_SEL_TIMEOUT, /* Target Selection Timeout */ - CAM_CMD_TIMEOUT, /* Command timeout */ - CAM_SCSI_STATUS_ERROR, /* SCSI error, look at error code in CCB */ - CAM_SCSI_BUS_RESET, /* SCSI Bus Reset Sent/Received */ - CAM_UNCOR_PARITY, /* Uncorrectable parity error occurred */ - CAM_AUTOSENSE_FAIL, /* Autosense: request sense cmd fail */ - CAM_NO_HBA, /* No HBA Detected Error */ - CAM_DATA_RUN_ERR, /* Data Overrun error */ - CAM_UNEXP_BUSFREE, /* Unexpected Bus Free */ - CAM_SEQUENCE_FAIL, /* Protocol Violation */ - CAM_CCB_LEN_ERR, /* CCB length supplied is inadequate */ - CAM_PROVIDE_FAIL, /* Unable to provide requested capability */ - CAM_BDR_SENT, /* A SCSI BDR msg was sent to target */ - CAM_REQ_TERMIO, /* CCB request terminated by the host */ - CAM_UNREC_HBA_ERROR, /* Unrecoverable Host Bus Adapter Error */ - CAM_REQ_TOO_BIG, /* The request was too large for this host */ - CAM_UA_TERMIO, /* Unable to terminate I/O CCB request */ - CAM_MSG_REJECT_REC, /* Message Reject Received */ - CAM_DEV_NOT_THERE, /* SCSI Device Not Installed/there */ - CAM_RESRC_UNAVAIL, /* Resource Unavailable */ - /* - * This request should be requeued to preserve - * transaction ordering. This typically occurs - * when the SIM recognizes an error that should - * freeze the queue and must place additional - * requests for the target at the sim level - * back into the XPT queue. - */ - CAM_REQUEUE_REQ, - CAM_DEV_QFRZN = 0x40, - - CAM_STATUS_MASK = 0x3F -} cam_status; - -/* - * Definitions for the asynchronous callback CCB fields. - */ -typedef enum { - AC_GETDEV_CHANGED = 0x800,/* Getdev info might have changed */ - AC_INQ_CHANGED = 0x400,/* Inquiry info might have changed */ - AC_TRANSFER_NEG = 0x200,/* New transfer settings in effect */ - AC_LOST_DEVICE = 0x100,/* A device went away */ - AC_FOUND_DEVICE = 0x080,/* A new device was found */ - AC_PATH_DEREGISTERED = 0x040,/* A path has de-registered */ - AC_PATH_REGISTERED = 0x020,/* A new path has been registered */ - AC_SENT_BDR = 0x010,/* A BDR message was sent to target */ - AC_SCSI_AEN = 0x008,/* A SCSI AEN has been received */ - AC_UNSOL_RESEL = 0x002,/* Unsolicited reselection occurred */ - AC_BUS_RESET = 0x001 /* A SCSI bus reset occurred */ -} ac_code; - -typedef enum { - CAM_DIR_IN = DMA_FROM_DEVICE, - CAM_DIR_OUT = DMA_TO_DEVICE, - CAM_DIR_NONE = DMA_NONE, -} ccb_flags; - -#endif /* _AIC7XXX_CAM_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/queue.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/queue.h deleted file mode 100644 index 8adf8003..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/queue.h +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)queue.h 8.5 (Berkeley) 8/20/94 - * $FreeBSD: src/sys/sys/queue.h,v 1.38 2000/05/26 02:06:56 jake Exp $ - */ - -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * This file defines five types of data structures: singly-linked lists, - * singly-linked tail queues, lists, tail queues, and circular queues. - * - * A singly-linked list is headed by a single forward pointer. The elements - * are singly linked for minimum space and pointer manipulation overhead at - * the expense of O(n) removal for arbitrary elements. New elements can be - * added to the list after an existing element or at the head of the list. - * Elements being removed from the head of the list should use the explicit - * macro for this purpose for optimum efficiency. A singly-linked list may - * only be traversed in the forward direction. Singly-linked lists are ideal - * for applications with large datasets and few or no removals or for - * implementing a LIFO queue. - * - * A singly-linked tail queue is headed by a pair of pointers, one to the - * head of the list and the other to the tail of the list. The elements are - * singly linked for minimum space and pointer manipulation overhead at the - * expense of O(n) removal for arbitrary elements. New elements can be added - * to the list after an existing element, at the head of the list, or at the - * end of the list. Elements being removed from the head of the tail queue - * should use the explicit macro for this purpose for optimum efficiency. - * A singly-linked tail queue may only be traversed in the forward direction. - * Singly-linked tail queues are ideal for applications with large datasets - * and few or no removals or for implementing a FIFO queue. - * - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * A tail queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or - * after an existing element, at the head of the list, or at the end of - * the list. A tail queue may be traversed in either direction. - * - * A circle queue is headed by a pair of pointers, one to the head of the - * list and the other to the tail of the list. The elements are doubly - * linked so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before or after - * an existing element, at the head of the list, or at the end of the list. - * A circle queue may be traversed in either direction, but has a more - * complex end of list detection. - * - * For details on the use of these macros, see the queue(3) manual page. - * - * - * SLIST LIST STAILQ TAILQ CIRCLEQ - * _HEAD + + + + + - * _HEAD_INITIALIZER + + + + + - * _ENTRY + + + + + - * _INIT + + + + + - * _EMPTY + + + + + - * _FIRST + + + + + - * _NEXT + + + + + - * _PREV - - - + + - * _LAST - - + + + - * _FOREACH + + + + + - * _FOREACH_REVERSE - - - + + - * _INSERT_HEAD + + + + + - * _INSERT_BEFORE - + - + + - * _INSERT_AFTER + + + + + - * _INSERT_TAIL - - + + + - * _REMOVE_HEAD + - + - - - * _REMOVE + + + + + - * - */ - -/* - * Singly-linked List declarations. - */ -#define SLIST_HEAD(name, type) \ -struct name { \ - struct type *slh_first; /* first element */ \ -} - -#define SLIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define SLIST_ENTRY(type) \ -struct { \ - struct type *sle_next; /* next element */ \ -} - -/* - * Singly-linked List functions. - */ -#define SLIST_EMPTY(head) ((head)->slh_first == NULL) - -#define SLIST_FIRST(head) ((head)->slh_first) - -#define SLIST_FOREACH(var, head, field) \ - for ((var) = SLIST_FIRST((head)); \ - (var); \ - (var) = SLIST_NEXT((var), field)) - -#define SLIST_INIT(head) do { \ - SLIST_FIRST((head)) = NULL; \ -} while (0) - -#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ - SLIST_NEXT((slistelm), field) = (elm); \ -} while (0) - -#define SLIST_INSERT_HEAD(head, elm, field) do { \ - SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ - SLIST_FIRST((head)) = (elm); \ -} while (0) - -#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) - -#define SLIST_REMOVE(head, elm, type, field) do { \ - if (SLIST_FIRST((head)) == (elm)) { \ - SLIST_REMOVE_HEAD((head), field); \ - } \ - else { \ - struct type *curelm = SLIST_FIRST((head)); \ - while (SLIST_NEXT(curelm, field) != (elm)) \ - curelm = SLIST_NEXT(curelm, field); \ - SLIST_NEXT(curelm, field) = \ - SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ - } \ -} while (0) - -#define SLIST_REMOVE_HEAD(head, field) do { \ - SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ -} while (0) - -/* - * Singly-linked Tail queue declarations. - */ -#define STAILQ_HEAD(name, type) \ -struct name { \ - struct type *stqh_first;/* first element */ \ - struct type **stqh_last;/* addr of last next element */ \ -} - -#define STAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).stqh_first } - -#define STAILQ_ENTRY(type) \ -struct { \ - struct type *stqe_next; /* next element */ \ -} - -/* - * Singly-linked Tail queue functions. - */ -#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) - -#define STAILQ_FIRST(head) ((head)->stqh_first) - -#define STAILQ_FOREACH(var, head, field) \ - for((var) = STAILQ_FIRST((head)); \ - (var); \ - (var) = STAILQ_NEXT((var), field)) - -#define STAILQ_INIT(head) do { \ - STAILQ_FIRST((head)) = NULL; \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_NEXT((tqelm), field) = (elm); \ -} while (0) - -#define STAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ - STAILQ_FIRST((head)) = (elm); \ -} while (0) - -#define STAILQ_INSERT_TAIL(head, elm, field) do { \ - STAILQ_NEXT((elm), field) = NULL; \ - STAILQ_LAST((head)) = (elm); \ - (head)->stqh_last = &STAILQ_NEXT((elm), field); \ -} while (0) - -#define STAILQ_LAST(head) (*(head)->stqh_last) - -#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) - -#define STAILQ_REMOVE(head, elm, type, field) do { \ - if (STAILQ_FIRST((head)) == (elm)) { \ - STAILQ_REMOVE_HEAD(head, field); \ - } \ - else { \ - struct type *curelm = STAILQ_FIRST((head)); \ - while (STAILQ_NEXT(curelm, field) != (elm)) \ - curelm = STAILQ_NEXT(curelm, field); \ - if ((STAILQ_NEXT(curelm, field) = \ - STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ - (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ - } \ -} while (0) - -#define STAILQ_REMOVE_HEAD(head, field) do { \ - if ((STAILQ_FIRST((head)) = \ - STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ - if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ - (head)->stqh_last = &STAILQ_FIRST((head)); \ -} while (0) - -/* - * List declarations. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_INIT(head) do { \ - LIST_FIRST((head)) = NULL; \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ -} while (0) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_REMOVE(elm, field) do { \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ -} while (0) - -/* - * Tail queue declarations. - */ -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} - -#define TAILQ_HEAD_INITIALIZER(head) \ - { NULL, &(head).tqh_first } - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -/* - * Tail queue functions. - */ -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ - for ((var) = TAILQ_LAST((head), headname); \ - (var); \ - (var) = TAILQ_PREV((var), headname, field)) - -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ -} while (0) - -#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ - if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_NEXT((listelm), field) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ -} while (0) - -#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ - TAILQ_NEXT((elm), field) = (listelm); \ - *(listelm)->field.tqe_prev = (elm); \ - (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ -} while (0) - -#define TAILQ_LAST(head, headname) \ - (*(((struct headname *)((head)->tqh_last))->tqh_last)) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_PREV(elm, headname, field) \ - (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) - -#define TAILQ_REMOVE(head, elm, field) do { \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ -} while (0) - -/* - * Circular queue declarations. - */ -#define CIRCLEQ_HEAD(name, type) \ -struct name { \ - struct type *cqh_first; /* first element */ \ - struct type *cqh_last; /* last element */ \ -} - -#define CIRCLEQ_HEAD_INITIALIZER(head) \ - { (void *)&(head), (void *)&(head) } - -#define CIRCLEQ_ENTRY(type) \ -struct { \ - struct type *cqe_next; /* next element */ \ - struct type *cqe_prev; /* previous element */ \ -} - -/* - * Circular queue functions. - */ -#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) - -#define CIRCLEQ_FIRST(head) ((head)->cqh_first) - -#define CIRCLEQ_FOREACH(var, head, field) \ - for ((var) = CIRCLEQ_FIRST((head)); \ - (var) != (void *)(head); \ - (var) = CIRCLEQ_NEXT((var), field)) - -#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ - for ((var) = CIRCLEQ_LAST((head)); \ - (var) != (void *)(head); \ - (var) = CIRCLEQ_PREV((var), field)) - -#define CIRCLEQ_INIT(head) do { \ - CIRCLEQ_FIRST((head)) = (void *)(head); \ - CIRCLEQ_LAST((head)) = (void *)(head); \ -} while (0) - -#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ - CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \ - CIRCLEQ_PREV((elm), field) = (listelm); \ - if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \ - CIRCLEQ_LAST((head)) = (elm); \ - else \ - CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\ - CIRCLEQ_NEXT((listelm), field) = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ - CIRCLEQ_NEXT((elm), field) = (listelm); \ - CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \ - if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \ - CIRCLEQ_FIRST((head)) = (elm); \ - else \ - CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\ - CIRCLEQ_PREV((listelm), field) = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ - CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \ - CIRCLEQ_PREV((elm), field) = (void *)(head); \ - if (CIRCLEQ_LAST((head)) == (void *)(head)) \ - CIRCLEQ_LAST((head)) = (elm); \ - else \ - CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \ - CIRCLEQ_FIRST((head)) = (elm); \ -} while (0) - -#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ - CIRCLEQ_NEXT((elm), field) = (void *)(head); \ - CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \ - if (CIRCLEQ_FIRST((head)) == (void *)(head)) \ - CIRCLEQ_FIRST((head)) = (elm); \ - else \ - CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \ - CIRCLEQ_LAST((head)) = (elm); \ -} while (0) - -#define CIRCLEQ_LAST(head) ((head)->cqh_last) - -#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next) - -#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev) - -#define CIRCLEQ_REMOVE(head, elm, field) do { \ - if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \ - CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \ - else \ - CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \ - CIRCLEQ_PREV((elm), field); \ - if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \ - CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \ - else \ - CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \ - CIRCLEQ_NEXT((elm), field); \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_iu.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_iu.h deleted file mode 100644 index 0eafd3c1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_iu.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * This file is in the public domain. - */ -#ifndef _SCSI_SCSI_IU_H -#define _SCSI_SCSI_IU_H 1 - -struct scsi_status_iu_header -{ - u_int8_t reserved[2]; - u_int8_t flags; -#define SIU_SNSVALID 0x2 -#define SIU_RSPVALID 0x1 - u_int8_t status; - u_int8_t sense_length[4]; - u_int8_t pkt_failures_length[4]; - u_int8_t pkt_failures[1]; -}; - -#define SIU_PKTFAIL_OFFSET(siu) 12 -#define SIU_PKTFAIL_CODE(siu) (scsi_4btoul((siu)->pkt_failures) & 0xFF) -#define SIU_PFC_NONE 0 -#define SIU_PFC_CIU_FIELDS_INVALID 2 -#define SIU_PFC_TMF_NOT_SUPPORTED 4 -#define SIU_PFC_TMF_FAILED 5 -#define SIU_PFC_INVALID_TYPE_CODE 6 -#define SIU_PFC_ILLEGAL_REQUEST 7 -#define SIU_SENSE_OFFSET(siu) \ - (12 + (((siu)->flags & SIU_RSPVALID) \ - ? scsi_4btoul((siu)->pkt_failures_length) \ - : 0)) - -#define SIU_TASKMGMT_NONE 0x00 -#define SIU_TASKMGMT_ABORT_TASK 0x01 -#define SIU_TASKMGMT_ABORT_TASK_SET 0x02 -#define SIU_TASKMGMT_CLEAR_TASK_SET 0x04 -#define SIU_TASKMGMT_LUN_RESET 0x08 -#define SIU_TASKMGMT_TARGET_RESET 0x20 -#define SIU_TASKMGMT_CLEAR_ACA 0x40 -#endif /*_SCSI_SCSI_IU_H*/ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_message.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_message.h deleted file mode 100644 index 75811e24..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx/scsi_message.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is in the public domain. - * $FreeBSD: src/sys/cam/scsi/scsi_message.h,v 1.2 2000/05/01 20:21:29 peter Exp $ - */ - -/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */ -#define MSG_CMDCOMPLETE 0x00 /* M/M */ -#define MSG_TASK_COMPLETE 0x00 /* M/M */ /* SPI3 Terminology */ -#define MSG_EXTENDED 0x01 /* O/O */ -#define MSG_SAVEDATAPOINTER 0x02 /* O/O */ -#define MSG_RESTOREPOINTERS 0x03 /* O/O */ -#define MSG_DISCONNECT 0x04 /* O/O */ -#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */ -#define MSG_ABORT 0x06 /* O/M */ -#define MSG_ABORT_TASK_SET 0x06 /* O/M */ /* SPI3 Terminology */ -#define MSG_MESSAGE_REJECT 0x07 /* M/M */ -#define MSG_NOOP 0x08 /* M/M */ -#define MSG_PARITY_ERROR 0x09 /* M/M */ -#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */ -#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */ -#define MSG_BUS_DEV_RESET 0x0c /* O/M */ -#define MSG_TARGET_RESET 0x0c /* O/M */ /* SPI3 Terminology */ -#define MSG_ABORT_TAG 0x0d /* O/O */ -#define MSG_ABORT_TASK 0x0d /* O/O */ /* SPI3 Terminology */ -#define MSG_CLEAR_QUEUE 0x0e /* O/O */ -#define MSG_CLEAR_TASK_SET 0x0e /* O/O */ /* SPI3 Terminology */ -#define MSG_INIT_RECOVERY 0x0f /* O/O */ /* Deprecated in SPI3 */ -#define MSG_REL_RECOVERY 0x10 /* O/O */ /* Deprecated in SPI3 */ -#define MSG_TERM_IO_PROC 0x11 /* O/O */ /* Deprecated in SPI3 */ -#define MSG_CLEAR_ACA 0x16 /* O/O */ /* SPI3 */ -#define MSG_LOGICAL_UNIT_RESET 0x17 /* O/O */ /* SPI3 */ -#define MSG_QAS_REQUEST 0x55 /* O/O */ /* SPI3 */ - -/* Messages (2 byte) */ -#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ -#define MSG_SIMPLE_TASK 0x20 /* O/O */ /* SPI3 Terminology */ -#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */ -#define MSG_HEAD_OF_QUEUE_TASK 0x21 /* O/O */ /* SPI3 Terminology */ -#define MSG_ORDERED_Q_TAG 0x22 /* O/O */ -#define MSG_ORDERED_TASK 0x22 /* O/O */ /* SPI3 Terminology */ -#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */ -#define MSG_ACA_TASK 0x24 /* 0/0 */ /* SPI3 */ - -/* Identify message */ /* M/M */ -#define MSG_IDENTIFYFLAG 0x80 -#define MSG_IDENTIFY_DISCFLAG 0x40 -#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun)) -#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG) -#define MSG_IDENTIFY_LUNMASK 0x3F - -/* Extended messages (opcode and length) */ -#define MSG_EXT_SDTR 0x01 -#define MSG_EXT_SDTR_LEN 0x03 - -#define MSG_EXT_WDTR 0x03 -#define MSG_EXT_WDTR_LEN 0x02 -#define MSG_EXT_WDTR_BUS_8_BIT 0x00 -#define MSG_EXT_WDTR_BUS_16_BIT 0x01 -#define MSG_EXT_WDTR_BUS_32_BIT 0x02 /* Deprecated in SPI3 */ - -#define MSG_EXT_PPR 0x04 /* SPI3 */ -#define MSG_EXT_PPR_LEN 0x06 -#define MSG_EXT_PPR_PCOMP_EN 0x80 -#define MSG_EXT_PPR_RTI 0x40 -#define MSG_EXT_PPR_RD_STRM 0x20 -#define MSG_EXT_PPR_WR_FLOW 0x10 -#define MSG_EXT_PPR_HOLD_MCS 0x08 -#define MSG_EXT_PPR_QAS_REQ 0x04 -#define MSG_EXT_PPR_DT_REQ 0x02 -#define MSG_EXT_PPR_IU_REQ 0x01 diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old.c deleted file mode 100644 index 5b212f0d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old.c +++ /dev/null @@ -1,11149 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F - * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA - * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide, - * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux, - * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file - * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual, - * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the - * ANSI SCSI-2 specification (draft 10c), ... - * - * -------------------------------------------------------------------------- - * - * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org): - * - * Substantially modified to include support for wide and twin bus - * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes, - * SCB paging, and other rework of the code. - * - * Parts of this driver were also based on the FreeBSD driver by - * Justin T. Gibbs. His copyright follows: - * - * -------------------------------------------------------------------------- - * Copyright (c) 1994-1997 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $ - *--------------------------------------------------------------------------- - * - * Thanks also go to (in alphabetical order) the following: - * - * Rory Bolt - Sequencer bug fixes - * Jay Estabrook - Initial DEC Alpha support - * Doug Ledford - Much needed abort/reset bug fixes - * Kai Makisara - DMAing of SCBs - * - * A Boot time option was also added for not resetting the scsi bus. - * - * Form: aic7xxx=extended - * aic7xxx=no_reset - * aic7xxx=ultra - * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level - * aic7xxx=verbose - * - * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97 - * - * $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $ - *-M*************************************************************************/ - -/*+M************************************************************************** - * - * Further driver modifications made by Doug Ledford - * - * Copyright (c) 1997-1999 Doug Ledford - * - * These changes are released under the same licensing terms as the FreeBSD - * driver written by Justin Gibbs. Please see his Copyright notice above - * for the exact terms and conditions covering my changes as well as the - * warranty statement. - * - * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include - * but are not limited to: - * - * 1: Import of the latest FreeBSD sequencer code for this driver - * 2: Modification of kernel code to accommodate different sequencer semantics - * 3: Extensive changes throughout kernel portion of driver to improve - * abort/reset processing and error hanndling - * 4: Other work contributed by various people on the Internet - * 5: Changes to printk information and verbosity selection code - * 6: General reliability related changes, especially in IRQ management - * 7: Modifications to the default probe/attach order for supported cards - * 8: SMP friendliness has been improved - * - * Overall, this driver represents a significant departure from the official - * aic7xxx driver released by Dan Eischen in two ways. First, in the code - * itself. A diff between the two version of the driver is now a several - * thousand line diff. Second, in approach to solving the same problem. The - * problem is importing the FreeBSD aic7xxx driver code to linux can be a - * difficult and time consuming process, that also can be error prone. Dan - * Eischen's official driver uses the approach that the linux and FreeBSD - * drivers should be as identical as possible. To that end, his next version - * of this driver will be using a mid-layer code library that he is developing - * to moderate communications between the linux mid-level SCSI code and the - * low level FreeBSD driver. He intends to be able to essentially drop the - * FreeBSD driver into the linux kernel with only a few minor tweaks to some - * include files and the like and get things working, making for fast easy - * imports of the FreeBSD code into linux. - * - * I disagree with Dan's approach. Not that I don't think his way of doing - * things would be nice, easy to maintain, and create a more uniform driver - * between FreeBSD and Linux. I have no objection to those issues. My - * disagreement is on the needed functionality. There simply are certain - * things that are done differently in FreeBSD than linux that will cause - * problems for this driver regardless of any middle ware Dan implements. - * The biggest example of this at the moment is interrupt semantics. Linux - * doesn't provide the same protection techniques as FreeBSD does, nor can - * they be easily implemented in any middle ware code since they would truly - * belong in the kernel proper and would effect all drivers. For the time - * being, I see issues such as these as major stumbling blocks to the - * reliability of code based upon such middle ware. Therefore, I choose to - * use a different approach to importing the FreeBSD code that doesn't - * involve any middle ware type code. My approach is to import the sequencer - * code from FreeBSD wholesale. Then, to only make changes in the kernel - * portion of the driver as they are needed for the new sequencer semantics. - * In this way, the portion of the driver that speaks to the rest of the - * linux kernel is fairly static and can be changed/modified to solve - * any problems one might encounter without concern for the FreeBSD driver. - * - * Note: If time and experience should prove me wrong that the middle ware - * code Dan writes is reliable in its operation, then I'll retract my above - * statements. But, for those that don't know, I'm from Missouri (in the US) - * and our state motto is "The Show-Me State". Well, before I will put - * faith into it, you'll have to show me that it works :) - * - *_M*************************************************************************/ - -/* - * The next three defines are user configurable. These should be the only - * defines a user might need to get in here and change. There are other - * defines buried deeper in the code, but those really shouldn't need touched - * under normal conditions. - */ - -/* - * AIC7XXX_STRICT_PCI_SETUP - * Should we assume the PCI config options on our controllers are set with - * sane and proper values, or should we be anal about our PCI config - * registers and force them to what we want? The main advantage to - * defining this option is on non-Intel hardware where the BIOS may not - * have been run to set things up, or if you have one of the BIOSless - * Adaptec controllers, such as a 2910, that don't get set up by the - * BIOS. However, keep in mind that we really do set the most important - * items in the driver regardless of this setting, this only controls some - * of the more esoteric PCI options on these cards. In that sense, I - * would default to leaving this off. However, if people wish to try - * things both ways, that would also help me to know if there are some - * machines where it works one way but not another. - * - * -- July 7, 17:09 - * OK...I need this on my machine for testing, so the default is to - * leave it defined. - * - * -- July 7, 18:49 - * I needed it for testing, but it didn't make any difference, so back - * off she goes. - * - * -- July 16, 23:04 - * I turned it back on to try and compensate for the 2.1.x PCI code - * which no longer relies solely on the BIOS and now tries to set - * things itself. - */ - -#define AIC7XXX_STRICT_PCI_SETUP - -/* - * AIC7XXX_VERBOSE_DEBUGGING - * This option enables a lot of extra printk();s in the code, surrounded - * by if (aic7xxx_verbose ...) statements. Executing all of those if - * statements and the extra checks can get to where it actually does have - * an impact on CPU usage and such, as well as code size. Disabling this - * define will keep some of those from becoming part of the code. - * - * NOTE: Currently, this option has no real effect, I will be adding the - * various #ifdef's in the code later when I've decided a section is - * complete and no longer needs debugging. OK...a lot of things are now - * surrounded by this define, so turning this off does have an impact. - */ - -/* - * #define AIC7XXX_VERBOSE_DEBUGGING - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "scsi.h" -#include -#include "aic7xxx_old/aic7xxx.h" - -#include "aic7xxx_old/sequencer.h" -#include "aic7xxx_old/scsi_message.h" -#include "aic7xxx_old/aic7xxx_reg.h" -#include - -#include -#include /* for kmalloc() */ - -#define AIC7XXX_C_VERSION "5.2.6" - -#define ALL_TARGETS -1 -#define ALL_CHANNELS -1 -#define ALL_LUNS -1 -#define MAX_TARGETS 16 -#define MAX_LUNS 8 -#ifndef TRUE -# define TRUE 1 -#endif -#ifndef FALSE -# define FALSE 0 -#endif - -#if defined(__powerpc__) || defined(__i386__) || defined(__x86_64__) -# define MMAPIO -#endif - -/* - * You can try raising me for better performance or lowering me if you have - * flaky devices that go off the scsi bus when hit with too many tagged - * commands (like some IBM SCSI-3 LVD drives). - */ -#define AIC7XXX_CMDS_PER_DEVICE 32 - -typedef struct -{ - unsigned char tag_commands[16]; /* Allow for wide/twin adapters. */ -} adapter_tag_info_t; - -/* - * Make a define that will tell the driver not to the default tag depth - * everywhere. - */ -#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\ - 0, 0, 0, 0, 0, 0, 0, 0} - -/* - * Modify this as you see fit for your system. By setting tag_commands - * to 0, the driver will use it's own algorithm for determining the - * number of commands to use (see above). When 255, the driver will - * not enable tagged queueing for that particular device. When positive - * (> 0) and (< 255) the values in the array are used for the queue_depth. - * Note that the maximum value for an entry is 254, but you're insane if - * you try to use that many commands on one device. - * - * In this example, the first line will disable tagged queueing for all - * the devices on the first probed aic7xxx adapter. - * - * The second line enables tagged queueing with 4 commands/LUN for IDs - * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the - * driver to use its own algorithm for ID 1. - * - * The third line is the same as the first line. - * - * The fourth line disables tagged queueing for devices 0 and 3. It - * enables tagged queueing for the other IDs, with 16 commands/LUN - * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for - * IDs 2, 5-7, and 9-15. - */ - -/* - * NOTE: The below structure is for reference only, the actual structure - * to modify in order to change things is found after this fake one. - * -adapter_tag_info_t aic7xxx_tag_info[] = -{ - {DEFAULT_TAG_COMMANDS}, - {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}}, - {DEFAULT_TAG_COMMANDS}, - {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}} -}; -*/ - -static adapter_tag_info_t aic7xxx_tag_info[] = -{ - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS}, - {DEFAULT_TAG_COMMANDS} -}; - - -/* - * Define an array of board names that can be indexed by aha_type. - * Don't forget to change this when changing the types! - */ -static const char *board_names[] = { - "AIC-7xxx Unknown", /* AIC_NONE */ - "Adaptec AIC-7810 Hardware RAID Controller", /* AIC_7810 */ - "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */ - "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */ - "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */ - "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */ - "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */ - "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */ - "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */ - "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */ - "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */ - "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */ - "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */ - "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */ - "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */ - "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */ - "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */ - "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */ - "Adaptec AHA-2944 Ultra SCSI host adapter", /* AIC_7884 */ - "Adaptec AHA-2940UW Pro Ultra SCSI host adapter", /* AIC_7887 */ - "Adaptec AIC-7895 Ultra SCSI host adapter", /* AIC_7895 */ - "Adaptec AIC-7890/1 Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AHA-293X Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AHA-294X Ultra2 SCSI host adapter", /* AIC_7890 */ - "Adaptec AIC-7896/7 Ultra2 SCSI host adapter", /* AIC_7896 */ - "Adaptec AHA-394X Ultra2 SCSI host adapter", /* AIC_7897 */ - "Adaptec AHA-395X Ultra2 SCSI host adapter", /* AIC_7897 */ - "Adaptec PCMCIA SCSI controller", /* card bus stuff */ - "Adaptec AIC-7892 Ultra 160/m SCSI host adapter", /* AIC_7892 */ - "Adaptec AIC-7899 Ultra 160/m SCSI host adapter", /* AIC_7899 */ -}; - -/* - * There should be a specific return value for this in scsi.h, but - * it seems that most drivers ignore it. - */ -#define DID_UNDERFLOW DID_ERROR - -/* - * What we want to do is have the higher level scsi driver requeue - * the command to us. There is no specific driver status for this - * condition, but the higher level scsi driver will requeue the - * command on a DID_BUS_BUSY error. - * - * Upon further inspection and testing, it seems that DID_BUS_BUSY - * will *always* retry the command. We can get into an infinite loop - * if this happens when we really want some sort of counter that - * will automatically abort/reset the command after so many retries. - * Using DID_ERROR will do just that. (Made by a suggestion by - * Doug Ledford 8/1/96) - */ -#define DID_RETRY_COMMAND DID_ERROR - -#define HSCSIID 0x07 -#define SCSI_RESET 0x040 - -/* - * EISA/VL-bus stuff - */ -#define MINSLOT 1 -#define MAXSLOT 15 -#define SLOTBASE(x) ((x) << 12) -#define BASE_TO_SLOT(x) ((x) >> 12) - -/* - * Standard EISA Host ID regs (Offset from slot base) - */ -#define AHC_HID0 0x80 /* 0,1: msb of ID2, 2-7: ID1 */ -#define AHC_HID1 0x81 /* 0-4: ID3, 5-7: LSB ID2 */ -#define AHC_HID2 0x82 /* product */ -#define AHC_HID3 0x83 /* firmware revision */ - -/* - * AIC-7770 I/O range to reserve for a card - */ -#define MINREG 0xC00 -#define MAXREG 0xCFF - -#define INTDEF 0x5C /* Interrupt Definition Register */ - -/* - * AIC-78X0 PCI registers - */ -#define CLASS_PROGIF_REVID 0x08 -#define DEVREVID 0x000000FFul -#define PROGINFC 0x0000FF00ul -#define SUBCLASS 0x00FF0000ul -#define BASECLASS 0xFF000000ul - -#define CSIZE_LATTIME 0x0C -#define CACHESIZE 0x0000003Ful /* only 5 bits */ -#define LATTIME 0x0000FF00ul - -#define DEVCONFIG 0x40 -#define SCBSIZE32 0x00010000ul /* aic789X only */ -#define MPORTMODE 0x00000400ul /* aic7870 only */ -#define RAMPSM 0x00000200ul /* aic7870 only */ -#define RAMPSM_ULTRA2 0x00000004 -#define VOLSENSE 0x00000100ul -#define SCBRAMSEL 0x00000080ul -#define SCBRAMSEL_ULTRA2 0x00000008 -#define MRDCEN 0x00000040ul -#define EXTSCBTIME 0x00000020ul /* aic7870 only */ -#define EXTSCBPEN 0x00000010ul /* aic7870 only */ -#define BERREN 0x00000008ul -#define DACEN 0x00000004ul -#define STPWLEVEL 0x00000002ul -#define DIFACTNEGEN 0x00000001ul /* aic7870 only */ - -#define SCAMCTL 0x1a /* Ultra2 only */ -#define CCSCBBADDR 0xf0 /* aic7895/6/7 */ - -/* - * Define the different types of SEEPROMs on aic7xxx adapters - * and make it also represent the address size used in accessing - * its registers. The 93C46 chips have 1024 bits organized into - * 64 16-bit words, while the 93C56 chips have 2048 bits organized - * into 128 16-bit words. The C46 chips use 6 bits to address - * each word, while the C56 and C66 (4096 bits) use 8 bits to - * address each word. - */ -typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type; - -/* - * - * Define the format of the SEEPROM registers (16 bits). - * - */ -struct seeprom_config { - -/* - * SCSI ID Configuration Flags - */ -#define CFXFER 0x0007 /* synchronous transfer rate */ -#define CFSYNCH 0x0008 /* enable synchronous transfer */ -#define CFDISC 0x0010 /* enable disconnection */ -#define CFWIDEB 0x0020 /* wide bus device (wide card) */ -#define CFSYNCHISULTRA 0x0040 /* CFSYNC is an ultra offset */ -#define CFNEWULTRAFORMAT 0x0080 /* Use the Ultra2 SEEPROM format */ -#define CFSTART 0x0100 /* send start unit SCSI command */ -#define CFINCBIOS 0x0200 /* include in BIOS scan */ -#define CFRNFOUND 0x0400 /* report even if not found */ -#define CFMULTILUN 0x0800 /* probe mult luns in BIOS scan */ -#define CFWBCACHEYES 0x4000 /* Enable W-Behind Cache on drive */ -#define CFWBCACHENC 0xc000 /* Don't change W-Behind Cache */ -/* UNUSED 0x3000 */ - unsigned short device_flags[16]; /* words 0-15 */ - -/* - * BIOS Control Bits - */ -#define CFSUPREM 0x0001 /* support all removable drives */ -#define CFSUPREMB 0x0002 /* support removable drives for boot only */ -#define CFBIOSEN 0x0004 /* BIOS enabled */ -/* UNUSED 0x0008 */ -#define CFSM2DRV 0x0010 /* support more than two drives */ -#define CF284XEXTEND 0x0020 /* extended translation (284x cards) */ -/* UNUSED 0x0040 */ -#define CFEXTEND 0x0080 /* extended translation enabled */ -/* UNUSED 0xFF00 */ - unsigned short bios_control; /* word 16 */ - -/* - * Host Adapter Control Bits - */ -#define CFAUTOTERM 0x0001 /* Perform Auto termination */ -#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */ -#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */ -#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */ -#define CFSTERM 0x0004 /* SCSI low byte termination */ -#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */ -#define CFSPARITY 0x0010 /* SCSI parity */ -#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */ -#define CFRESETB 0x0040 /* reset SCSI bus at boot */ -#define CFBPRIMARY 0x0100 /* Channel B primary on 7895 chipsets */ -#define CFSEAUTOTERM 0x0400 /* aic7890 Perform SE Auto Term */ -#define CFLVDSTERM 0x0800 /* aic7890 LVD Termination */ -/* UNUSED 0xF280 */ - unsigned short adapter_control; /* word 17 */ - -/* - * Bus Release, Host Adapter ID - */ -#define CFSCSIID 0x000F /* host adapter SCSI ID */ -/* UNUSED 0x00F0 */ -#define CFBRTIME 0xFF00 /* bus release time */ - unsigned short brtime_id; /* word 18 */ - -/* - * Maximum targets - */ -#define CFMAXTARG 0x00FF /* maximum targets */ -/* UNUSED 0xFF00 */ - unsigned short max_targets; /* word 19 */ - - unsigned short res_1[11]; /* words 20-30 */ - unsigned short checksum; /* word 31 */ -}; - -#define SELBUS_MASK 0x0a -#define SELNARROW 0x00 -#define SELBUSB 0x08 -#define SINGLE_BUS 0x00 - -#define SCB_TARGET(scb) \ - (((scb)->hscb->target_channel_lun & TID) >> 4) -#define SCB_LUN(scb) \ - ((scb)->hscb->target_channel_lun & LID) -#define SCB_IS_SCSIBUS_B(scb) \ - (((scb)->hscb->target_channel_lun & SELBUSB) != 0) - -/* - * If an error occurs during a data transfer phase, run the command - * to completion - it's easier that way - making a note of the error - * condition in this location. This then will modify a DID_OK status - * into an appropriate error for the higher-level SCSI code. - */ -#define aic7xxx_error(cmd) ((cmd)->SCp.Status) - -/* - * Keep track of the targets returned status. - */ -#define aic7xxx_status(cmd) ((cmd)->SCp.sent_command) - -/* - * The position of the SCSI commands scb within the scb array. - */ -#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in) - -/* - * The stored DMA mapping for single-buffer data transfers. - */ -#define aic7xxx_mapping(cmd) ((cmd)->SCp.phase) - -/* - * Get out private data area from a scsi cmd pointer - */ -#define AIC_DEV(cmd) ((struct aic_dev_data *)(cmd)->device->hostdata) - -/* - * So we can keep track of our host structs - */ -static struct aic7xxx_host *first_aic7xxx = NULL; - -/* - * As of Linux 2.1, the mid-level SCSI code uses virtual addresses - * in the scatter-gather lists. We need to convert the virtual - * addresses to physical addresses. - */ -struct hw_scatterlist { - unsigned int address; - unsigned int length; -}; - -/* - * Maximum number of SG segments these cards can support. - */ -#define AIC7XXX_MAX_SG 128 - -/* - * The maximum number of SCBs we could have for ANY type - * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE - * SEQUENCER CODE IF THIS IS MODIFIED! - */ -#define AIC7XXX_MAXSCB 255 - - -struct aic7xxx_hwscb { -/* ------------ Begin hardware supported fields ---------------- */ -/* 0*/ unsigned char control; -/* 1*/ unsigned char target_channel_lun; /* 4/1/3 bits */ -/* 2*/ unsigned char target_status; -/* 3*/ unsigned char SG_segment_count; -/* 4*/ unsigned int SG_list_pointer; -/* 8*/ unsigned char residual_SG_segment_count; -/* 9*/ unsigned char residual_data_count[3]; -/*12*/ unsigned int data_pointer; -/*16*/ unsigned int data_count; -/*20*/ unsigned int SCSI_cmd_pointer; -/*24*/ unsigned char SCSI_cmd_length; -/*25*/ unsigned char tag; /* Index into our kernel SCB array. - * Also used as the tag for tagged I/O - */ -#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download - * via PIO to initialize a transaction. - */ -/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection - * or disconnected down in the sequencer. - */ -/*27*/ unsigned char prev; -/*28*/ unsigned int pad; /* - * Unused by the kernel, but we require - * the padding so that the array of - * hardware SCBs is aligned on 32 byte - * boundaries so the sequencer can index - */ -}; - -typedef enum { - SCB_FREE = 0x0000, - SCB_DTR_SCB = 0x0001, - SCB_WAITINGQ = 0x0002, - SCB_ACTIVE = 0x0004, - SCB_SENSE = 0x0008, - SCB_ABORT = 0x0010, - SCB_DEVICE_RESET = 0x0020, - SCB_RESET = 0x0040, - SCB_RECOVERY_SCB = 0x0080, - SCB_MSGOUT_PPR = 0x0100, - SCB_MSGOUT_SENT = 0x0200, - SCB_MSGOUT_SDTR = 0x0400, - SCB_MSGOUT_WDTR = 0x0800, - SCB_MSGOUT_BITS = SCB_MSGOUT_PPR | - SCB_MSGOUT_SENT | - SCB_MSGOUT_SDTR | - SCB_MSGOUT_WDTR, - SCB_QUEUED_ABORT = 0x1000, - SCB_QUEUED_FOR_DONE = 0x2000, - SCB_WAS_BUSY = 0x4000, - SCB_QUEUE_FULL = 0x8000 -} scb_flag_type; - -typedef enum { - AHC_FNONE = 0x00000000, - AHC_PAGESCBS = 0x00000001, - AHC_CHANNEL_B_PRIMARY = 0x00000002, - AHC_USEDEFAULTS = 0x00000004, - AHC_INDIRECT_PAGING = 0x00000008, - AHC_CHNLB = 0x00000020, - AHC_CHNLC = 0x00000040, - AHC_EXTEND_TRANS_A = 0x00000100, - AHC_EXTEND_TRANS_B = 0x00000200, - AHC_TERM_ENB_A = 0x00000400, - AHC_TERM_ENB_SE_LOW = 0x00000400, - AHC_TERM_ENB_B = 0x00000800, - AHC_TERM_ENB_SE_HIGH = 0x00000800, - AHC_HANDLING_REQINITS = 0x00001000, - AHC_TARGETMODE = 0x00002000, - AHC_NEWEEPROM_FMT = 0x00004000, - /* - * Here ends the FreeBSD defined flags and here begins the linux defined - * flags. NOTE: I did not preserve the old flag name during this change - * specifically to force me to evaluate what flags were being used properly - * and what flags weren't. This way, I could clean up the flag usage on - * a use by use basis. Doug Ledford - */ - AHC_MOTHERBOARD = 0x00020000, - AHC_NO_STPWEN = 0x00040000, - AHC_RESET_DELAY = 0x00080000, - AHC_A_SCANNED = 0x00100000, - AHC_B_SCANNED = 0x00200000, - AHC_MULTI_CHANNEL = 0x00400000, - AHC_BIOS_ENABLED = 0x00800000, - AHC_SEEPROM_FOUND = 0x01000000, - AHC_TERM_ENB_LVD = 0x02000000, - AHC_ABORT_PENDING = 0x04000000, - AHC_RESET_PENDING = 0x08000000, -#define AHC_IN_ISR_BIT 28 - AHC_IN_ISR = 0x10000000, - AHC_IN_ABORT = 0x20000000, - AHC_IN_RESET = 0x40000000, - AHC_EXTERNAL_SRAM = 0x80000000 -} ahc_flag_type; - -typedef enum { - AHC_NONE = 0x0000, - AHC_CHIPID_MASK = 0x00ff, - AHC_AIC7770 = 0x0001, - AHC_AIC7850 = 0x0002, - AHC_AIC7860 = 0x0003, - AHC_AIC7870 = 0x0004, - AHC_AIC7880 = 0x0005, - AHC_AIC7890 = 0x0006, - AHC_AIC7895 = 0x0007, - AHC_AIC7896 = 0x0008, - AHC_AIC7892 = 0x0009, - AHC_AIC7899 = 0x000a, - AHC_VL = 0x0100, - AHC_EISA = 0x0200, - AHC_PCI = 0x0400, -} ahc_chip; - -typedef enum { - AHC_FENONE = 0x0000, - AHC_ULTRA = 0x0001, - AHC_ULTRA2 = 0x0002, - AHC_WIDE = 0x0004, - AHC_TWIN = 0x0008, - AHC_MORE_SRAM = 0x0010, - AHC_CMD_CHAN = 0x0020, - AHC_QUEUE_REGS = 0x0040, - AHC_SG_PRELOAD = 0x0080, - AHC_SPIOCAP = 0x0100, - AHC_ULTRA3 = 0x0200, - AHC_NEW_AUTOTERM = 0x0400, - AHC_AIC7770_FE = AHC_FENONE, - AHC_AIC7850_FE = AHC_SPIOCAP, - AHC_AIC7860_FE = AHC_ULTRA|AHC_SPIOCAP, - AHC_AIC7870_FE = AHC_FENONE, - AHC_AIC7880_FE = AHC_ULTRA, - AHC_AIC7890_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2| - AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM, - AHC_AIC7895_FE = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA, - AHC_AIC7896_FE = AHC_AIC7890_FE, - AHC_AIC7892_FE = AHC_AIC7890_FE|AHC_ULTRA3, - AHC_AIC7899_FE = AHC_AIC7890_FE|AHC_ULTRA3, -} ahc_feature; - -#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset) - -struct aic7xxx_scb_dma { - unsigned long dma_offset; /* Correction you have to add - * to virtual address to get - * dma handle in this region */ - dma_addr_t dma_address; /* DMA handle of the start, - * for unmap */ - unsigned int dma_len; /* DMA length */ -}; - -typedef enum { - AHC_BUG_NONE = 0x0000, - AHC_BUG_TMODE_WIDEODD = 0x0001, - AHC_BUG_AUTOFLUSH = 0x0002, - AHC_BUG_CACHETHEN = 0x0004, - AHC_BUG_CACHETHEN_DIS = 0x0008, - AHC_BUG_PCI_2_1_RETRY = 0x0010, - AHC_BUG_PCI_MWI = 0x0020, - AHC_BUG_SCBCHAN_UPLOAD = 0x0040, -} ahc_bugs; - -struct aic7xxx_scb { - struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */ - struct scsi_cmnd *cmd; /* scsi_cmnd for this scb */ - struct aic7xxx_scb *q_next; /* next scb in queue */ - volatile scb_flag_type flags; /* current state of scb */ - struct hw_scatterlist *sg_list; /* SG list in adapter format */ - unsigned char tag_action; - unsigned char sg_count; - unsigned char *sense_cmd; /* - * Allocate 6 characters for - * sense command. - */ - unsigned char *cmnd; - unsigned int sg_length; /* - * We init this during - * buildscb so we don't have - * to calculate anything during - * underflow/overflow/stat code - */ - void *kmalloc_ptr; - struct aic7xxx_scb_dma *scb_dma; -}; - -/* - * Define a linked list of SCBs. - */ -typedef struct { - struct aic7xxx_scb *head; - struct aic7xxx_scb *tail; -} scb_queue_type; - -static struct { - unsigned char errno; - const char *errmesg; -} hard_error[] = { - { ILLHADDR, "Illegal Host Access" }, - { ILLSADDR, "Illegal Sequencer Address referenced" }, - { ILLOPCODE, "Illegal Opcode in sequencer program" }, - { SQPARERR, "Sequencer Ram Parity Error" }, - { DPARERR, "Data-Path Ram Parity Error" }, - { MPARERR, "Scratch Ram/SCB Array Ram Parity Error" }, - { PCIERRSTAT,"PCI Error detected" }, - { CIOPARERR, "CIOBUS Parity Error" } -}; - -static unsigned char -generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 }; - -typedef struct { - scb_queue_type free_scbs; /* - * SCBs assigned to free slot on - * card (no paging required) - */ - struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; - struct aic7xxx_hwscb *hscbs; - unsigned char numscbs; /* current number of scbs */ - unsigned char maxhscbs; /* hardware scbs */ - unsigned char maxscbs; /* max scbs including pageable scbs */ - dma_addr_t hscbs_dma; /* DMA handle to hscbs */ - unsigned int hscbs_dma_len; /* length of the above DMA area */ - void *hscb_kmalloc_ptr; -} scb_data_type; - -struct target_cmd { - unsigned char mesg_bytes[4]; - unsigned char command[28]; -}; - -#define AHC_TRANS_CUR 0x0001 -#define AHC_TRANS_ACTIVE 0x0002 -#define AHC_TRANS_GOAL 0x0004 -#define AHC_TRANS_USER 0x0008 -#define AHC_TRANS_QUITE 0x0010 -typedef struct { - unsigned char width; - unsigned char period; - unsigned char offset; - unsigned char options; -} transinfo_type; - -struct aic_dev_data { - volatile scb_queue_type delayed_scbs; - volatile unsigned short temp_q_depth; - unsigned short max_q_depth; - volatile unsigned char active_cmds; - /* - * Statistics Kept: - * - * Total Xfers (count for each command that has a data xfer), - * broken down by reads && writes. - * - * Further sorted into a few bins for keeping tabs on how many commands - * we get of various sizes. - * - */ - long w_total; /* total writes */ - long r_total; /* total reads */ - long barrier_total; /* total num of REQ_BARRIER commands */ - long ordered_total; /* How many REQ_BARRIER commands we - used ordered tags to satisfy */ - long w_bins[6]; /* binned write */ - long r_bins[6]; /* binned reads */ - transinfo_type cur; - transinfo_type goal; -#define BUS_DEVICE_RESET_PENDING 0x01 -#define DEVICE_RESET_DELAY 0x02 -#define DEVICE_PRINT_DTR 0x04 -#define DEVICE_WAS_BUSY 0x08 -#define DEVICE_DTR_SCANNED 0x10 -#define DEVICE_SCSI_3 0x20 - volatile unsigned char flags; - unsigned needppr:1; - unsigned needppr_copy:1; - unsigned needsdtr:1; - unsigned needsdtr_copy:1; - unsigned needwdtr:1; - unsigned needwdtr_copy:1; - unsigned dtr_pending:1; - struct scsi_device *SDptr; - struct list_head list; -}; - -/* - * Define a structure used for each host adapter. Note, in order to avoid - * problems with architectures I can't test on (because I don't have one, - * such as the Alpha based systems) which happen to give faults for - * non-aligned memory accesses, care was taken to align this structure - * in a way that guaranteed all accesses larger than 8 bits were aligned - * on the appropriate boundary. It's also organized to try and be more - * cache line efficient. Be careful when changing this lest you might hurt - * overall performance and bring down the wrath of the masses. - */ -struct aic7xxx_host { - /* - * This is the first 64 bytes in the host struct - */ - - /* - * We are grouping things here....first, items that get either read or - * written with nearly every interrupt - */ - volatile long flags; - ahc_feature features; /* chip features */ - unsigned long base; /* card base address */ - volatile unsigned char __iomem *maddr; /* memory mapped address */ - unsigned long isr_count; /* Interrupt count */ - unsigned long spurious_int; - scb_data_type *scb_data; - struct aic7xxx_cmd_queue { - struct scsi_cmnd *head; - struct scsi_cmnd *tail; - } completeq; - - /* - * Things read/written on nearly every entry into aic7xxx_queue() - */ - volatile scb_queue_type waiting_scbs; - unsigned char unpause; /* unpause value for HCNTRL */ - unsigned char pause; /* pause value for HCNTRL */ - volatile unsigned char qoutfifonext; - volatile unsigned char activescbs; /* active scbs */ - volatile unsigned char max_activescbs; - volatile unsigned char qinfifonext; - volatile unsigned char *untagged_scbs; - volatile unsigned char *qoutfifo; - volatile unsigned char *qinfifo; - - unsigned char dev_last_queue_full[MAX_TARGETS]; - unsigned char dev_last_queue_full_count[MAX_TARGETS]; - unsigned short ultraenb; /* Gets downloaded to card as a bitmap */ - unsigned short discenable; /* Gets downloaded to card as a bitmap */ - transinfo_type user[MAX_TARGETS]; - - unsigned char msg_buf[13]; /* The message for the target */ - unsigned char msg_type; -#define MSG_TYPE_NONE 0x00 -#define MSG_TYPE_INITIATOR_MSGOUT 0x01 -#define MSG_TYPE_INITIATOR_MSGIN 0x02 - unsigned char msg_len; /* Length of message */ - unsigned char msg_index; /* Index into msg_buf array */ - - - /* - * We put the less frequently used host structure items - * after the more frequently used items to try and ease - * the burden on the cache subsystem. - * These entries are not *commonly* accessed, whereas - * the preceding entries are accessed very often. - */ - - unsigned int irq; /* IRQ for this adapter */ - int instance; /* aic7xxx instance number */ - int scsi_id; /* host adapter SCSI ID */ - int scsi_id_b; /* channel B for twin adapters */ - unsigned int bios_address; - int board_name_index; - unsigned short bios_control; /* bios control - SEEPROM */ - unsigned short adapter_control; /* adapter control - SEEPROM */ - struct pci_dev *pdev; - unsigned char pci_bus; - unsigned char pci_device_fn; - struct seeprom_config sc; - unsigned short sc_type; - unsigned short sc_size; - struct aic7xxx_host *next; /* allow for multiple IRQs */ - struct Scsi_Host *host; /* pointer to scsi host */ - struct list_head aic_devs; /* all aic_dev structs on host */ - int host_no; /* SCSI host number */ - unsigned long mbase; /* I/O memory address */ - ahc_chip chip; /* chip type */ - ahc_bugs bugs; - dma_addr_t fifo_dma; /* DMA handle for fifo arrays */ -}; - -/* - * Valid SCSIRATE values. (p. 3-17) - * Provides a mapping of transfer periods in ns/4 to the proper value to - * stick in the SCSIRATE reg to use that transfer rate. - */ -#define AHC_SYNCRATE_ULTRA3 0 -#define AHC_SYNCRATE_ULTRA2 1 -#define AHC_SYNCRATE_ULTRA 3 -#define AHC_SYNCRATE_FAST 6 -#define AHC_SYNCRATE_CRC 0x40 -#define AHC_SYNCRATE_SE 0x10 -static struct aic7xxx_syncrate { - /* Rates in Ultra mode have bit 8 of sxfr set */ -#define ULTRA_SXFR 0x100 - int sxfr_ultra2; - int sxfr; - unsigned char period; - const char *rate[2]; -} aic7xxx_syncrates[] = { - { 0x42, 0x000, 9, {"80.0", "160.0"} }, - { 0x13, 0x000, 10, {"40.0", "80.0"} }, - { 0x14, 0x000, 11, {"33.0", "66.6"} }, - { 0x15, 0x100, 12, {"20.0", "40.0"} }, - { 0x16, 0x110, 15, {"16.0", "32.0"} }, - { 0x17, 0x120, 18, {"13.4", "26.8"} }, - { 0x18, 0x000, 25, {"10.0", "20.0"} }, - { 0x19, 0x010, 31, {"8.0", "16.0"} }, - { 0x1a, 0x020, 37, {"6.67", "13.3"} }, - { 0x1b, 0x030, 43, {"5.7", "11.4"} }, - { 0x10, 0x040, 50, {"5.0", "10.0"} }, - { 0x00, 0x050, 56, {"4.4", "8.8" } }, - { 0x00, 0x060, 62, {"4.0", "8.0" } }, - { 0x00, 0x070, 68, {"3.6", "7.2" } }, - { 0x00, 0x000, 0, {NULL, NULL} }, -}; - -#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1), \ - (((scb->hscb)->target_channel_lun >> 4) & 0xf), \ - ((scb->hscb)->target_channel_lun & 0x07) - -#define CTL_OF_CMD(cmd) ((cmd->device->channel) & 0x01), \ - ((cmd->device->id) & 0x0f), \ - ((cmd->device->lun) & 0x07) - -#define TARGET_INDEX(cmd) ((cmd)->device->id | ((cmd)->device->channel << 3)) - -/* - * A nice little define to make doing our printks a little easier - */ - -#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) " -#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) " - -/* - * XXX - these options apply unilaterally to _all_ 274x/284x/294x - * cards in the system. This should be fixed. Exceptions to this - * rule are noted in the comments. - */ - -/* - * Use this as the default queue depth when setting tagged queueing on. - */ -static unsigned int aic7xxx_default_queue_depth = AIC7XXX_CMDS_PER_DEVICE; - -/* - * Skip the scsi bus reset. Non 0 make us skip the reset at startup. This - * has no effect on any later resets that might occur due to things like - * SCSI bus timeouts. - */ -static unsigned int aic7xxx_no_reset = 0; -/* - * Certain PCI motherboards will scan PCI devices from highest to lowest, - * others scan from lowest to highest, and they tend to do all kinds of - * strange things when they come into contact with PCI bridge chips. The - * net result of all this is that the PCI card that is actually used to boot - * the machine is very hard to detect. Most motherboards go from lowest - * PCI slot number to highest, and the first SCSI controller found is the - * one you boot from. The only exceptions to this are when a controller - * has its BIOS disabled. So, we by default sort all of our SCSI controllers - * from lowest PCI slot number to highest PCI slot number. We also force - * all controllers with their BIOS disabled to the end of the list. This - * works on *almost* all computers. Where it doesn't work, we have this - * option. Setting this option to non-0 will reverse the order of the sort - * to highest first, then lowest, but will still leave cards with their BIOS - * disabled at the very end. That should fix everyone up unless there are - * really strange cirumstances. - */ -static int aic7xxx_reverse_scan = 0; -/* - * Should we force EXTENDED translation on a controller. - * 0 == Use whatever is in the SEEPROM or default to off - * 1 == Use whatever is in the SEEPROM or default to on - */ -static unsigned int aic7xxx_extended = 0; -/* - * The IRQ trigger method used on EISA controllers. Does not effect PCI cards. - * -1 = Use detected settings. - * 0 = Force Edge triggered mode. - * 1 = Force Level triggered mode. - */ -static int aic7xxx_irq_trigger = -1; -/* - * This variable is used to override the termination settings on a controller. - * This should not be used under normal conditions. However, in the case - * that a controller does not have a readable SEEPROM (so that we can't - * read the SEEPROM settings directly) and that a controller has a buggered - * version of the cable detection logic, this can be used to force the - * correct termination. It is preferable to use the manual termination - * settings in the BIOS if possible, but some motherboard controllers store - * those settings in a format we can't read. In other cases, auto term - * should also work, but the chipset was put together with no auto term - * logic (common on motherboard controllers). In those cases, we have - * 32 bits here to work with. That's good for 8 controllers/channels. The - * bits are organized as 4 bits per channel, with scsi0 getting the lowest - * 4 bits in the int. A 1 in a bit position indicates the termination setting - * that corresponds to that bit should be enabled, a 0 is disabled. - * It looks something like this: - * - * 0x0f = 1111-Single Ended Low Byte Termination on/off - * ||\-Single Ended High Byte Termination on/off - * |\-LVD Low Byte Termination on/off - * \-LVD High Byte Termination on/off - * - * For non-Ultra2 controllers, the upper 2 bits are not important. So, to - * enable both high byte and low byte termination on scsi0, I would need to - * make sure that the override_term variable was set to 0x03 (bits 0011). - * To make sure that all termination is enabled on an Ultra2 controller at - * scsi2 and only high byte termination on scsi1 and high and low byte - * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011) - * - * For the most part, users should never have to use this, that's why I - * left it fairly cryptic instead of easy to understand. If you need it, - * most likely someone will be telling you what your's needs to be set to. - */ -static int aic7xxx_override_term = -1; -/* - * Certain motherboard chipset controllers tend to screw - * up the polarity of the term enable output pin. Use this variable - * to force the correct polarity for your system. This is a bitfield variable - * similar to the previous one, but this one has one bit per channel instead - * of four. - * 0 = Force the setting to active low. - * 1 = Force setting to active high. - * Most Adaptec cards are active high, several motherboards are active low. - * To force a 2940 card at SCSI 0 to active high and a motherboard 7895 - * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3 - * to active high, you would need to set stpwlev=0x9 (bits 1001). - * - * People shouldn't need to use this, but if you are experiencing lots of - * SCSI timeout problems, this may help. There is one sure way to test what - * this option needs to be. Using a boot floppy to boot the system, configure - * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and - * if needed then also pass a value to override_term to make sure that the - * driver is enabling SCSI termination, then set this variable to either 0 - * or 1. When the driver boots, make sure there are *NO* SCSI cables - * connected to your controller. If it finds and inits the controller - * without problem, then the setting you passed to stpwlev was correct. If - * the driver goes into a reset loop and hangs the system, then you need the - * other setting for this variable. If neither setting lets the machine - * boot then you have definite termination problems that may not be fixable. - */ -static int aic7xxx_stpwlev = -1; -/* - * Set this to non-0 in order to force the driver to panic the kernel - * and print out debugging info on a SCSI abort or reset cycle. - */ -static int aic7xxx_panic_on_abort = 0; -/* - * PCI bus parity checking of the Adaptec controllers. This is somewhat - * dubious at best. To my knowledge, this option has never actually - * solved a PCI parity problem, but on certain machines with broken PCI - * chipset configurations, it can generate tons of false error messages. - * It's included in the driver for completeness. - * 0 = Shut off PCI parity check - * -1 = Normal polarity pci parity checking - * 1 = reverse polarity pci parity checking - * - * NOTE: you can't actually pass -1 on the lilo prompt. So, to set this - * variable to -1 you would actually want to simply pass the variable - * name without a number. That will invert the 0 which will result in - * -1. - */ -static int aic7xxx_pci_parity = 0; -/* - * Set this to any non-0 value to cause us to dump the contents of all - * the card's registers in a hex dump format tailored to each model of - * controller. - * - * NOTE: THE CONTROLLER IS LEFT IN AN UNUSABLE STATE BY THIS OPTION. - * YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES - * ONLY - */ -static int aic7xxx_dump_card = 0; -/* - * Set this to a non-0 value to make us dump out the 32 bit instruction - * registers on the card after completing the sequencer download. This - * allows the actual sequencer download to be verified. It is possible - * to use this option and still boot up and run your system. This is - * only intended for debugging purposes. - */ -static int aic7xxx_dump_sequencer = 0; -/* - * Certain newer motherboards have put new PCI based devices into the - * IO spaces that used to typically be occupied by VLB or EISA cards. - * This overlap can cause these newer motherboards to lock up when scanned - * for older EISA and VLB devices. Setting this option to non-0 will - * cause the driver to skip scanning for any VLB or EISA controllers and - * only support the PCI controllers. NOTE: this means that if the kernel - * os compiled with PCI support disabled, then setting this to non-0 - * would result in never finding any devices :) - */ -static int aic7xxx_no_probe = 0; -/* - * On some machines, enabling the external SCB RAM isn't reliable yet. I - * haven't had time to make test patches for things like changing the - * timing mode on that external RAM either. Some of those changes may - * fix the problem. Until then though, we default to external SCB RAM - * off and give a command line option to enable it. - */ -static int aic7xxx_scbram = 0; -/* - * So that we can set how long each device is given as a selection timeout. - * The table of values goes like this: - * 0 - 256ms - * 1 - 128ms - * 2 - 64ms - * 3 - 32ms - * We default to 64ms because it's fast. Some old SCSI-I devices need a - * longer time. The final value has to be left shifted by 3, hence 0x10 - * is the final value. - */ -static int aic7xxx_seltime = 0x10; -/* - * So that insmod can find the variable and make it point to something - */ -#ifdef MODULE -static char * aic7xxx = NULL; -module_param(aic7xxx, charp, 0); -#endif - -#define VERBOSE_NORMAL 0x0000 -#define VERBOSE_NEGOTIATION 0x0001 -#define VERBOSE_SEQINT 0x0002 -#define VERBOSE_SCSIINT 0x0004 -#define VERBOSE_PROBE 0x0008 -#define VERBOSE_PROBE2 0x0010 -#define VERBOSE_NEGOTIATION2 0x0020 -#define VERBOSE_MINOR_ERROR 0x0040 -#define VERBOSE_TRACING 0x0080 -#define VERBOSE_ABORT 0x0f00 -#define VERBOSE_ABORT_MID 0x0100 -#define VERBOSE_ABORT_FIND 0x0200 -#define VERBOSE_ABORT_PROCESS 0x0400 -#define VERBOSE_ABORT_RETURN 0x0800 -#define VERBOSE_RESET 0xf000 -#define VERBOSE_RESET_MID 0x1000 -#define VERBOSE_RESET_FIND 0x2000 -#define VERBOSE_RESET_PROCESS 0x4000 -#define VERBOSE_RESET_RETURN 0x8000 -static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION | - VERBOSE_PROBE; /* verbose messages */ - - -/**************************************************************************** - * - * We're going to start putting in function declarations so that order of - * functions is no longer important. As needed, they are added here. - * - ***************************************************************************/ - -static int aic7xxx_release(struct Scsi_Host *host); -static void aic7xxx_set_syncrate(struct aic7xxx_host *p, - struct aic7xxx_syncrate *syncrate, int target, int channel, - unsigned int period, unsigned int offset, unsigned char options, - unsigned int type, struct aic_dev_data *aic_dev); -static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, - int lun, unsigned int width, unsigned int type, - struct aic_dev_data *aic_dev); -static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd); -static void aic7xxx_print_card(struct aic7xxx_host *p); -static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p); -static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded); -#ifdef AIC7XXX_VERBOSE_DEBUGGING -static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer); -#endif - -/**************************************************************************** - * - * These functions are now used. They happen to be wrapped in useless - * inb/outb port read/writes around the real reads and writes because it - * seems that certain very fast CPUs have a problem dealing with us when - * going at full speed. - * - ***************************************************************************/ - -static unsigned char -aic_inb(struct aic7xxx_host *p, long port) -{ -#ifdef MMAPIO - unsigned char x; - if(p->maddr) - { - x = readb(p->maddr + port); - } - else - { - x = inb(p->base + port); - } - return(x); -#else - return(inb(p->base + port)); -#endif -} - -static void -aic_outb(struct aic7xxx_host *p, unsigned char val, long port) -{ -#ifdef MMAPIO - if(p->maddr) - { - writeb(val, p->maddr + port); - mb(); /* locked operation in order to force CPU ordering */ - readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */ - } - else - { - outb(val, p->base + port); - mb(); /* locked operation in order to force CPU ordering */ - } -#else - outb(val, p->base + port); - mb(); /* locked operation in order to force CPU ordering */ -#endif -} - -/*+F************************************************************************* - * Function: - * aic7xxx_setup - * - * Description: - * Handle Linux boot parameters. This routine allows for assigning a value - * to a parameter with a ':' between the parameter and the value. - * ie. aic7xxx=unpause:0x0A,extended - *-F*************************************************************************/ -static int -aic7xxx_setup(char *s) -{ - int i, n; - char *p; - char *end; - - static struct { - const char *name; - unsigned int *flag; - } options[] = { - { "extended", &aic7xxx_extended }, - { "no_reset", &aic7xxx_no_reset }, - { "irq_trigger", &aic7xxx_irq_trigger }, - { "verbose", &aic7xxx_verbose }, - { "reverse_scan",&aic7xxx_reverse_scan }, - { "override_term", &aic7xxx_override_term }, - { "stpwlev", &aic7xxx_stpwlev }, - { "no_probe", &aic7xxx_no_probe }, - { "panic_on_abort", &aic7xxx_panic_on_abort }, - { "pci_parity", &aic7xxx_pci_parity }, - { "dump_card", &aic7xxx_dump_card }, - { "dump_sequencer", &aic7xxx_dump_sequencer }, - { "default_queue_depth", &aic7xxx_default_queue_depth }, - { "scbram", &aic7xxx_scbram }, - { "seltime", &aic7xxx_seltime }, - { "tag_info", NULL } - }; - - end = strchr(s, '\0'); - - while ((p = strsep(&s, ",.")) != NULL) - { - for (i = 0; i < ARRAY_SIZE(options); i++) - { - n = strlen(options[i].name); - if (!strncmp(options[i].name, p, n)) - { - if (!strncmp(p, "tag_info", n)) - { - if (p[n] == ':') - { - char *base; - char *tok, *tok_end, *tok_end2; - char tok_list[] = { '.', ',', '{', '}', '\0' }; - int i, instance = -1, device = -1; - unsigned char done = FALSE; - - base = p; - tok = base + n + 1; /* Forward us just past the ':' */ - tok_end = strchr(tok, '\0'); - if (tok_end < end) - *tok_end = ','; - while(!done) - { - switch(*tok) - { - case '{': - if (instance == -1) - instance = 0; - else if (device == -1) - device = 0; - tok++; - break; - case '}': - if (device != -1) - device = -1; - else if (instance != -1) - instance = -1; - tok++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (device >= 0) - device++; - else if (instance >= 0) - instance++; - if ( (device >= MAX_TARGETS) || - (instance >= ARRAY_SIZE(aic7xxx_tag_info)) ) - done = TRUE; - tok++; - if (!done) - { - base = tok; - } - break; - case '\0': - done = TRUE; - break; - default: - done = TRUE; - tok_end = strchr(tok, '\0'); - for(i=0; tok_list[i]; i++) - { - tok_end2 = strchr(tok, tok_list[i]); - if ( (tok_end2) && (tok_end2 < tok_end) ) - { - tok_end = tok_end2; - done = FALSE; - } - } - if ( (instance >= 0) && (device >= 0) && - (instance < ARRAY_SIZE(aic7xxx_tag_info)) && - (device < MAX_TARGETS) ) - aic7xxx_tag_info[instance].tag_commands[device] = - simple_strtoul(tok, NULL, 0) & 0xff; - tok = tok_end; - break; - } - } - while((p != base) && (p != NULL)) - p = strsep(&s, ",."); - } - } - else if (p[n] == ':') - { - *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); - if(!strncmp(p, "seltime", n)) - { - *(options[i].flag) = (*(options[i].flag) % 4) << 3; - } - } - else if (!strncmp(p, "verbose", n)) - { - *(options[i].flag) = 0xff29; - } - else - { - *(options[i].flag) = ~(*(options[i].flag)); - if(!strncmp(p, "seltime", n)) - { - *(options[i].flag) = (*(options[i].flag) % 4) << 3; - } - } - } - } - } - return 1; -} - -__setup("aic7xxx=", aic7xxx_setup); - -/*+F************************************************************************* - * Function: - * pause_sequencer - * - * Description: - * Pause the sequencer and wait for it to actually stop - this - * is important since the sequencer can disable pausing for critical - * sections. - *-F*************************************************************************/ -static void -pause_sequencer(struct aic7xxx_host *p) -{ - aic_outb(p, p->pause, HCNTRL); - while ((aic_inb(p, HCNTRL) & PAUSE) == 0) - { - ; - } - if(p->features & AHC_ULTRA2) - { - aic_inb(p, CCSCBCTL); - } -} - -/*+F************************************************************************* - * Function: - * unpause_sequencer - * - * Description: - * Unpause the sequencer. Unremarkable, yet done often enough to - * warrant an easy way to do it. - *-F*************************************************************************/ -static void -unpause_sequencer(struct aic7xxx_host *p, int unpause_always) -{ - if (unpause_always || - ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) && - !(p->flags & AHC_HANDLING_REQINITS) ) ) - { - aic_outb(p, p->unpause, HCNTRL); - } -} - -/*+F************************************************************************* - * Function: - * restart_sequencer - * - * Description: - * Restart the sequencer program from address zero. This assumes - * that the sequencer is already paused. - *-F*************************************************************************/ -static void -restart_sequencer(struct aic7xxx_host *p) -{ - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE, SEQCTL); -} - -/* - * We include the aic7xxx_seq.c file here so that the other defines have - * already been made, and so that it comes before the code that actually - * downloads the instructions (since we don't typically use function - * prototype, our code has to be ordered that way, it's a left-over from - * the original driver days.....I should fix it some time DL). - */ -#include "aic7xxx_old/aic7xxx_seq.c" - -/*+F************************************************************************* - * Function: - * aic7xxx_check_patch - * - * Description: - * See if the next patch to download should be downloaded. - *-F*************************************************************************/ -static int -aic7xxx_check_patch(struct aic7xxx_host *p, - struct sequencer_patch **start_patch, int start_instr, int *skip_addr) -{ - struct sequencer_patch *cur_patch; - struct sequencer_patch *last_patch; - int num_patches; - - num_patches = ARRAY_SIZE(sequencer_patches); - last_patch = &sequencer_patches[num_patches]; - cur_patch = *start_patch; - - while ((cur_patch < last_patch) && (start_instr == cur_patch->begin)) - { - if (cur_patch->patch_func(p) == 0) - { - /* - * Start rejecting code. - */ - *skip_addr = start_instr + cur_patch->skip_instr; - cur_patch += cur_patch->skip_patch; - } - else - { - /* - * Found an OK patch. Advance the patch pointer to the next patch - * and wait for our instruction pointer to get here. - */ - cur_patch++; - } - } - - *start_patch = cur_patch; - if (start_instr < *skip_addr) - /* - * Still skipping - */ - return (0); - return(1); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_download_instr - * - * Description: - * Find the next patch to download. - *-F*************************************************************************/ -static void -aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr, - unsigned char *dconsts) -{ - union ins_formats instr; - struct ins_format1 *fmt1_ins; - struct ins_format3 *fmt3_ins; - unsigned char opcode; - - instr = *(union ins_formats*) &seqprog[instrptr * 4]; - - instr.integer = le32_to_cpu(instr.integer); - - fmt1_ins = &instr.format1; - fmt3_ins = NULL; - - /* Pull the opcode */ - opcode = instr.format1.opcode; - switch (opcode) - { - case AIC_OP_JMP: - case AIC_OP_JC: - case AIC_OP_JNC: - case AIC_OP_CALL: - case AIC_OP_JNE: - case AIC_OP_JNZ: - case AIC_OP_JE: - case AIC_OP_JZ: - { - struct sequencer_patch *cur_patch; - int address_offset; - unsigned int address; - int skip_addr; - int i; - - fmt3_ins = &instr.format3; - address_offset = 0; - address = fmt3_ins->address; - cur_patch = sequencer_patches; - skip_addr = 0; - - for (i = 0; i < address;) - { - aic7xxx_check_patch(p, &cur_patch, i, &skip_addr); - if (skip_addr > i) - { - int end_addr; - - end_addr = min_t(int, address, skip_addr); - address_offset += end_addr - i; - i = skip_addr; - } - else - { - i++; - } - } - address -= address_offset; - fmt3_ins->address = address; - /* Fall Through to the next code section */ - } - case AIC_OP_OR: - case AIC_OP_AND: - case AIC_OP_XOR: - case AIC_OP_ADD: - case AIC_OP_ADC: - case AIC_OP_BMOV: - if (fmt1_ins->parity != 0) - { - fmt1_ins->immediate = dconsts[fmt1_ins->immediate]; - } - fmt1_ins->parity = 0; - /* Fall Through to the next code section */ - case AIC_OP_ROL: - if ((p->features & AHC_ULTRA2) != 0) - { - int i, count; - - /* Calculate odd parity for the instruction */ - for ( i=0, count=0; i < 31; i++) - { - unsigned int mask; - - mask = 0x01 << i; - if ((instr.integer & mask) != 0) - count++; - } - if (!(count & 0x01)) - instr.format1.parity = 1; - } - else - { - if (fmt3_ins != NULL) - { - instr.integer = fmt3_ins->immediate | - (fmt3_ins->source << 8) | - (fmt3_ins->address << 16) | - (fmt3_ins->opcode << 25); - } - else - { - instr.integer = fmt1_ins->immediate | - (fmt1_ins->source << 8) | - (fmt1_ins->destination << 16) | - (fmt1_ins->ret << 24) | - (fmt1_ins->opcode << 25); - } - } - aic_outb(p, (instr.integer & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM); - aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM); - udelay(10); - break; - - default: - panic("aic7xxx: Unknown opcode encountered in sequencer program."); - break; - } -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_loadseq - * - * Description: - * Load the sequencer code into the controller memory. - *-F*************************************************************************/ -static void -aic7xxx_loadseq(struct aic7xxx_host *p) -{ - struct sequencer_patch *cur_patch; - int i; - int downloaded; - int skip_addr; - unsigned char download_consts[4] = {0, 0, 0, 0}; - - if (aic7xxx_verbose & VERBOSE_PROBE) - { - printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no); - } -#if 0 - download_consts[TMODE_NUMCMDS] = p->num_targetcmds; -#endif - download_consts[TMODE_NUMCMDS] = 0; - cur_patch = &sequencer_patches[0]; - downloaded = 0; - skip_addr = 0; - - aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL); - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - - for (i = 0; i < sizeof(seqprog) / 4; i++) - { - if (aic7xxx_check_patch(p, &cur_patch, i, &skip_addr) == 0) - { - /* Skip this instruction for this configuration. */ - continue; - } - aic7xxx_download_instr(p, i, &download_consts[0]); - downloaded++; - } - - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE | FAILDIS, SEQCTL); - unpause_sequencer(p, TRUE); - mdelay(1); - pause_sequencer(p); - aic_outb(p, FASTMODE, SEQCTL); - if (aic7xxx_verbose & VERBOSE_PROBE) - { - printk(" %d instructions downloaded\n", downloaded); - } - if (aic7xxx_dump_sequencer) - aic7xxx_print_sequencer(p, downloaded); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_sequencer - * - * Description: - * Print the contents of the sequencer memory to the screen. - *-F*************************************************************************/ -static void -aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded) -{ - int i, k, temp; - - aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL); - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - - k = 0; - for (i=0; i < downloaded; i++) - { - if ( k == 0 ) - printk("%03x: ", i); - temp = aic_inb(p, SEQRAM); - temp |= (aic_inb(p, SEQRAM) << 8); - temp |= (aic_inb(p, SEQRAM) << 16); - temp |= (aic_inb(p, SEQRAM) << 24); - printk("%08x", temp); - if ( ++k == 8 ) - { - printk("\n"); - k = 0; - } - else - printk(" "); - } - aic_outb(p, 0, SEQADDR0); - aic_outb(p, 0, SEQADDR1); - aic_outb(p, FASTMODE | FAILDIS, SEQCTL); - unpause_sequencer(p, TRUE); - mdelay(1); - pause_sequencer(p); - aic_outb(p, FASTMODE, SEQCTL); - printk("\n"); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_info - * - * Description: - * Return a string describing the driver. - *-F*************************************************************************/ -static const char * -aic7xxx_info(struct Scsi_Host *dooh) -{ - static char buffer[256]; - char *bp; - struct aic7xxx_host *p; - - bp = &buffer[0]; - p = (struct aic7xxx_host *)dooh->hostdata; - memset(bp, 0, sizeof(buffer)); - strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) "); - strcat(bp, AIC7XXX_C_VERSION); - strcat(bp, "/"); - strcat(bp, AIC7XXX_H_VERSION); - strcat(bp, "\n"); - strcat(bp, " <"); - strcat(bp, board_names[p->board_name_index]); - strcat(bp, ">"); - - return(bp); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_find_syncrate - * - * Description: - * Look up the valid period to SCSIRATE conversion in our table - *-F*************************************************************************/ -static struct aic7xxx_syncrate * -aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period, - unsigned int maxsync, unsigned char *options) -{ - struct aic7xxx_syncrate *syncrate; - int done = FALSE; - - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC: - case MSG_EXT_PPR_OPTION_DT_UNITS: - if(!(p->features & AHC_ULTRA3)) - { - *options = 0; - maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); - } - break; - case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: - case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK: - if(!(p->features & AHC_ULTRA3)) - { - *options = 0; - maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); - } - else - { - /* - * we don't support the Quick Arbitration variants of dual edge - * clocking. As it turns out, we want to send back the - * same basic option, but without the QA attribute. - * We know that we are responding because we would never set - * these options ourself, we would only respond to them. - */ - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC_QUICK: - *options = MSG_EXT_PPR_OPTION_DT_CRC; - break; - case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK: - *options = MSG_EXT_PPR_OPTION_DT_UNITS; - break; - } - } - break; - default: - *options = 0; - maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2); - break; - } - syncrate = &aic7xxx_syncrates[maxsync]; - while ( (syncrate->rate[0] != NULL) && - (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) ) - { - if (*period <= syncrate->period) - { - switch(*options) - { - case MSG_EXT_PPR_OPTION_DT_CRC: - case MSG_EXT_PPR_OPTION_DT_UNITS: - if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC)) - { - done = TRUE; - /* - * oops, we went too low for the CRC/DualEdge signalling, so - * clear the options byte - */ - *options = 0; - /* - * We'll be sending a reply to this packet to set the options - * properly, so unilaterally set the period as well. - */ - *period = syncrate->period; - } - else - { - done = TRUE; - if(syncrate == &aic7xxx_syncrates[maxsync]) - { - *period = syncrate->period; - } - } - break; - default: - if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC)) - { - done = TRUE; - if(syncrate == &aic7xxx_syncrates[maxsync]) - { - *period = syncrate->period; - } - } - break; - } - if(done) - { - break; - } - } - syncrate++; - } - if ( (*period == 0) || (syncrate->rate[0] == NULL) || - ((p->features & AHC_ULTRA2) && (syncrate->sxfr_ultra2 == 0)) ) - { - /* - * Use async transfers for this target - */ - *options = 0; - *period = 255; - syncrate = NULL; - } - return (syncrate); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_find_period - * - * Description: - * Look up the valid SCSIRATE to period conversion in our table - *-F*************************************************************************/ -static unsigned int -aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate, - unsigned int maxsync) -{ - struct aic7xxx_syncrate *syncrate; - - if (p->features & AHC_ULTRA2) - { - scsirate &= SXFR_ULTRA2; - } - else - { - scsirate &= SXFR; - } - - syncrate = &aic7xxx_syncrates[maxsync]; - while (syncrate->rate[0] != NULL) - { - if (p->features & AHC_ULTRA2) - { - if (syncrate->sxfr_ultra2 == 0) - break; - else if (scsirate == syncrate->sxfr_ultra2) - return (syncrate->period); - else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC)) - return (syncrate->period); - } - else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR)) - { - return (syncrate->period); - } - syncrate++; - } - return (0); /* async */ -} - -/*+F************************************************************************* - * Function: - * aic7xxx_validate_offset - * - * Description: - * Set a valid offset value for a particular card in use and transfer - * settings in use. - *-F*************************************************************************/ -static void -aic7xxx_validate_offset(struct aic7xxx_host *p, - struct aic7xxx_syncrate *syncrate, unsigned int *offset, int wide) -{ - unsigned int maxoffset; - - /* Limit offset to what the card (and device) can do */ - if (syncrate == NULL) - { - maxoffset = 0; - } - else if (p->features & AHC_ULTRA2) - { - maxoffset = MAX_OFFSET_ULTRA2; - } - else - { - if (wide) - maxoffset = MAX_OFFSET_16BIT; - else - maxoffset = MAX_OFFSET_8BIT; - } - *offset = min(*offset, maxoffset); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_set_syncrate - * - * Description: - * Set the actual syncrate down in the card and in our host structs - *-F*************************************************************************/ -static void -aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate, - int target, int channel, unsigned int period, unsigned int offset, - unsigned char options, unsigned int type, struct aic_dev_data *aic_dev) -{ - unsigned char tindex; - unsigned short target_mask; - unsigned char lun, old_options; - unsigned int old_period, old_offset; - - tindex = target | (channel << 3); - target_mask = 0x01 << tindex; - lun = aic_inb(p, SCB_TCL) & 0x07; - - if (syncrate == NULL) - { - period = 0; - offset = 0; - } - - old_period = aic_dev->cur.period; - old_offset = aic_dev->cur.offset; - old_options = aic_dev->cur.options; - - - if (type & AHC_TRANS_CUR) - { - unsigned int scsirate; - - scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - if (p->features & AHC_ULTRA2) - { - scsirate &= ~SXFR_ULTRA2; - if (syncrate != NULL) - { - switch(options) - { - case MSG_EXT_PPR_OPTION_DT_UNITS: - /* - * mask off the CRC bit in the xfer settings - */ - scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC); - break; - default: - scsirate |= syncrate->sxfr_ultra2; - break; - } - } - if (type & AHC_TRANS_ACTIVE) - { - aic_outb(p, offset, SCSIOFFSET); - } - aic_outb(p, offset, TARG_OFFSET + tindex); - } - else /* Not an Ultra2 controller */ - { - scsirate &= ~(SXFR|SOFS); - p->ultraenb &= ~target_mask; - if (syncrate != NULL) - { - if (syncrate->sxfr & ULTRA_SXFR) - { - p->ultraenb |= target_mask; - } - scsirate |= (syncrate->sxfr & SXFR); - scsirate |= (offset & SOFS); - } - if (type & AHC_TRANS_ACTIVE) - { - unsigned char sxfrctl0; - - sxfrctl0 = aic_inb(p, SXFRCTL0); - sxfrctl0 &= ~FAST20; - if (p->ultraenb & target_mask) - sxfrctl0 |= FAST20; - aic_outb(p, sxfrctl0, SXFRCTL0); - } - aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB); - aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1 ); - } - if (type & AHC_TRANS_ACTIVE) - { - aic_outb(p, scsirate, SCSIRATE); - } - aic_outb(p, scsirate, TARG_SCSIRATE + tindex); - aic_dev->cur.period = period; - aic_dev->cur.offset = offset; - aic_dev->cur.options = options; - if ( !(type & AHC_TRANS_QUITE) && - (aic7xxx_verbose & VERBOSE_NEGOTIATION) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - if (offset) - { - int rate_mod = (scsirate & WIDEXFER) ? 1 : 0; - - printk(INFO_LEAD "Synchronous at %s Mbyte/sec, " - "offset %d.\n", p->host_no, channel, target, lun, - syncrate->rate[rate_mod], offset); - } - else - { - printk(INFO_LEAD "Using asynchronous transfers.\n", - p->host_no, channel, target, lun); - } - aic_dev->flags &= ~DEVICE_PRINT_DTR; - } - } - - if (type & AHC_TRANS_GOAL) - { - aic_dev->goal.period = period; - aic_dev->goal.offset = offset; - aic_dev->goal.options = options; - } - - if (type & AHC_TRANS_USER) - { - p->user[tindex].period = period; - p->user[tindex].offset = offset; - p->user[tindex].options = options; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_set_width - * - * Description: - * Set the actual width down in the card and in our host structs - *-F*************************************************************************/ -static void -aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun, - unsigned int width, unsigned int type, struct aic_dev_data *aic_dev) -{ - unsigned char tindex; - unsigned short target_mask; - unsigned int old_width; - - tindex = target | (channel << 3); - target_mask = 1 << tindex; - - old_width = aic_dev->cur.width; - - if (type & AHC_TRANS_CUR) - { - unsigned char scsirate; - - scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - - scsirate &= ~WIDEXFER; - if (width == MSG_EXT_WDTR_BUS_16_BIT) - scsirate |= WIDEXFER; - - aic_outb(p, scsirate, TARG_SCSIRATE + tindex); - - if (type & AHC_TRANS_ACTIVE) - aic_outb(p, scsirate, SCSIRATE); - - aic_dev->cur.width = width; - - if ( !(type & AHC_TRANS_QUITE) && - (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target, - lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" ); - } - } - - if (type & AHC_TRANS_GOAL) - aic_dev->goal.width = width; - if (type & AHC_TRANS_USER) - p->user[tindex].width = width; - - if (aic_dev->goal.offset) - { - if (p->features & AHC_ULTRA2) - { - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - } - else if (width == MSG_EXT_WDTR_BUS_16_BIT) - { - aic_dev->goal.offset = MAX_OFFSET_16BIT; - } - else - { - aic_dev->goal.offset = MAX_OFFSET_8BIT; - } - } -} - -/*+F************************************************************************* - * Function: - * scbq_init - * - * Description: - * SCB queue initialization. - * - *-F*************************************************************************/ -static void -scbq_init(volatile scb_queue_type *queue) -{ - queue->head = NULL; - queue->tail = NULL; -} - -/*+F************************************************************************* - * Function: - * scbq_insert_head - * - * Description: - * Add an SCB to the head of the list. - * - *-F*************************************************************************/ -static inline void -scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ - scb->q_next = queue->head; - queue->head = scb; - if (queue->tail == NULL) /* If list was empty, update tail. */ - queue->tail = queue->head; -} - -/*+F************************************************************************* - * Function: - * scbq_remove_head - * - * Description: - * Remove an SCB from the head of the list. - * - *-F*************************************************************************/ -static inline struct aic7xxx_scb * -scbq_remove_head(volatile scb_queue_type *queue) -{ - struct aic7xxx_scb * scbp; - - scbp = queue->head; - if (queue->head != NULL) - queue->head = queue->head->q_next; - if (queue->head == NULL) /* If list is now empty, update tail. */ - queue->tail = NULL; - return(scbp); -} - -/*+F************************************************************************* - * Function: - * scbq_remove - * - * Description: - * Removes an SCB from the list. - * - *-F*************************************************************************/ -static inline void -scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ - if (queue->head == scb) - { - /* At beginning of queue, remove from head. */ - scbq_remove_head(queue); - } - else - { - struct aic7xxx_scb *curscb = queue->head; - - /* - * Search until the next scb is the one we're looking for, or - * we run out of queue. - */ - while ((curscb != NULL) && (curscb->q_next != scb)) - { - curscb = curscb->q_next; - } - if (curscb != NULL) - { - /* Found it. */ - curscb->q_next = scb->q_next; - if (scb->q_next == NULL) - { - /* Update the tail when removing the tail. */ - queue->tail = curscb; - } - } - } -} - -/*+F************************************************************************* - * Function: - * scbq_insert_tail - * - * Description: - * Add an SCB at the tail of the list. - * - *-F*************************************************************************/ -static inline void -scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb) -{ - scb->q_next = NULL; - if (queue->tail != NULL) /* Add the scb at the end of the list. */ - queue->tail->q_next = scb; - queue->tail = scb; /* Update the tail. */ - if (queue->head == NULL) /* If list was empty, update head. */ - queue->head = queue->tail; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_match_scb - * - * Description: - * Checks to see if an scb matches the target/channel as specified. - * If target is ALL_TARGETS (-1), then we're looking for any device - * on the specified channel; this happens when a channel is going - * to be reset and all devices on that channel must be aborted. - *-F*************************************************************************/ -static int -aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, - int target, int channel, int lun, unsigned char tag) -{ - int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F; - int chan = (scb->hscb->target_channel_lun >> 3) & 0x01; - int slun = scb->hscb->target_channel_lun & 0x07; - int match; - - match = ((chan == channel) || (channel == ALL_CHANNELS)); - if (match != 0) - match = ((targ == target) || (target == ALL_TARGETS)); - if (match != 0) - match = ((lun == slun) || (lun == ALL_LUNS)); - if (match != 0) - match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL)); - - return (match); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_add_curscb_to_free_list - * - * Description: - * Adds the current scb (in SCBPTR) to the list of free SCBs. - *-F*************************************************************************/ -static void -aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p) -{ - /* - * Invalidate the tag so that aic7xxx_find_scb doesn't think - * it's active - */ - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - - aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT); - aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_rem_scb_from_disc_list - * - * Description: - * Removes the current SCB from the disconnected list and adds it - * to the free list. - *-F*************************************************************************/ -static unsigned char -aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr, - unsigned char prev) -{ - unsigned char next; - - aic_outb(p, scbptr, SCBPTR); - next = aic_inb(p, SCB_NEXT); - aic7xxx_add_curscb_to_free_list(p); - - if (prev != SCB_LIST_NULL) - { - aic_outb(p, prev, SCBPTR); - aic_outb(p, next, SCB_NEXT); - } - else - { - aic_outb(p, next, DISCONNECTED_SCBH); - } - - return next; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_busy_target - * - * Description: - * Set the specified target busy. - *-F*************************************************************************/ -static inline void -aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_index_busy_target - * - * Description: - * Returns the index of the busy target, and optionally sets the - * target inactive. - *-F*************************************************************************/ -static inline unsigned char -aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl, - int unbusy) -{ - unsigned char busy_scbid; - - busy_scbid = p->untagged_scbs[tcl]; - if (unbusy) - { - p->untagged_scbs[tcl] = SCB_LIST_NULL; - } - return (busy_scbid); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_find_scb - * - * Description: - * Look through the SCB array of the card and attempt to find the - * hardware SCB that corresponds to the passed in SCB. Return - * SCB_LIST_NULL if unsuccessful. This routine assumes that the - * card is already paused. - *-F*************************************************************************/ -static unsigned char -aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - unsigned char saved_scbptr; - unsigned char curindex; - - saved_scbptr = aic_inb(p, SCBPTR); - curindex = 0; - for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++) - { - aic_outb(p, curindex, SCBPTR); - if (aic_inb(p, SCB_TAG) == scb->hscb->tag) - { - break; - } - } - aic_outb(p, saved_scbptr, SCBPTR); - if (curindex >= p->scb_data->maxhscbs) - { - curindex = SCB_LIST_NULL; - } - - return (curindex); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_allocate_scb - * - * Description: - * Get an SCB from the free list or by allocating a new one. - *-F*************************************************************************/ -static int -aic7xxx_allocate_scb(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scbp = NULL; - int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6; - int i; - int step = PAGE_SIZE / 1024; - unsigned long scb_count = 0; - struct hw_scatterlist *hsgp; - struct aic7xxx_scb *scb_ap; - struct aic7xxx_scb_dma *scb_dma; - unsigned char *bufs; - - if (p->scb_data->numscbs < p->scb_data->maxscbs) - { - /* - * Calculate the optimal number of SCBs to allocate. - * - * NOTE: This formula works because the sizeof(sg_array) is always - * 1024. Therefore, scb_size * i would always be > PAGE_SIZE * - * (i/step). The (i-1) allows the left hand side of the equation - * to grow into the right hand side to a point of near perfect - * efficiency since scb_size * (i -1) is growing slightly faster - * than the right hand side. If the number of SG array elements - * is changed, this function may not be near so efficient any more. - * - * Since the DMA'able buffers are now allocated in a separate - * chunk this algorithm has been modified to match. The '12' - * and '6' factors in scb_size are for the DMA'able command byte - * and sensebuffers respectively. -DaveM - */ - for ( i=step;; i *= 2 ) - { - if ( (scb_size * (i-1)) >= ( (PAGE_SIZE * (i/step)) - 64 ) ) - { - i /= 2; - break; - } - } - scb_count = min( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs); - scb_ap = kmalloc(sizeof (struct aic7xxx_scb) * scb_count - + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC); - if (scb_ap == NULL) - return(0); - scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count]; - hsgp = (struct hw_scatterlist *) - pci_alloc_consistent(p->pdev, scb_size * scb_count, - &scb_dma->dma_address); - if (hsgp == NULL) - { - kfree(scb_ap); - return(0); - } - bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG]; -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - { - if (p->scb_data->numscbs == 0) - printk(INFO_LEAD "Allocating initial %ld SCB structures.\n", - p->host_no, -1, -1, -1, scb_count); - else - printk(INFO_LEAD "Allocating %ld additional SCB structures.\n", - p->host_no, -1, -1, -1, scb_count); - } -#endif - memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count); - scb_dma->dma_offset = (unsigned long)scb_dma->dma_address - - (unsigned long)hsgp; - scb_dma->dma_len = scb_size * scb_count; - for (i=0; i < scb_count; i++) - { - scbp = &scb_ap[i]; - scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs]; - scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG]; - scbp->sense_cmd = bufs; - scbp->cmnd = bufs + 6; - bufs += 12 + 6; - scbp->scb_dma = scb_dma; - memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb)); - scbp->hscb->tag = p->scb_data->numscbs; - /* - * Place in the scb array; never is removed - */ - p->scb_data->scb_array[p->scb_data->numscbs++] = scbp; - scbq_insert_tail(&p->scb_data->free_scbs, scbp); - } - scbp->kmalloc_ptr = scb_ap; - } - return(scb_count); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_queue_cmd_complete - * - * Description: - * Due to race conditions present in the SCSI subsystem, it is easier - * to queue completed commands, then call scsi_done() on them when - * we're finished. This function queues the completed commands. - *-F*************************************************************************/ -static void -aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, struct scsi_cmnd *cmd) -{ - aic7xxx_position(cmd) = SCB_LIST_NULL; - cmd->host_scribble = (char *)p->completeq.head; - p->completeq.head = cmd; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_done_cmds_complete - * - * Description: - * Process the completed command queue. - *-F*************************************************************************/ -static void aic7xxx_done_cmds_complete(struct aic7xxx_host *p) -{ - struct scsi_cmnd *cmd; - - while (p->completeq.head != NULL) { - cmd = p->completeq.head; - p->completeq.head = (struct scsi_cmnd *) cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->scsi_done(cmd); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_free_scb - * - * Description: - * Free the scb and insert into the free scb list. - *-F*************************************************************************/ -static void -aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - - scb->flags = SCB_FREE; - scb->cmd = NULL; - scb->sg_count = 0; - scb->sg_length = 0; - scb->tag_action = 0; - scb->hscb->control = 0; - scb->hscb->target_status = 0; - scb->hscb->target_channel_lun = SCB_LIST_NULL; - - scbq_insert_head(&p->scb_data->free_scbs, scb); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_done - * - * Description: - * Calls the higher level scsi done function and frees the scb. - *-F*************************************************************************/ -static void -aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - struct scsi_cmnd *cmd = scb->cmd; - struct aic_dev_data *aic_dev = cmd->device->hostdata; - int tindex = TARGET_INDEX(cmd); - struct aic7xxx_scb *scbp; - unsigned char queue_depth; - - scsi_dma_unmap(cmd); - - if (scb->flags & SCB_SENSE) - { - pci_unmap_single(p->pdev, - le32_to_cpu(scb->sg_list[0].address), - SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); - } - if (scb->flags & SCB_RECOVERY_SCB) - { - p->flags &= ~AHC_ABORT_PENDING; - } - if (scb->flags & (SCB_RESET|SCB_ABORT)) - { - cmd->result |= (DID_RESET << 16); - } - - if ((scb->flags & SCB_MSGOUT_BITS) != 0) - { - unsigned short mask; - int message_error = FALSE; - - mask = 0x01 << tindex; - - /* - * Check to see if we get an invalid message or a message error - * after failing to negotiate a wide or sync transfer message. - */ - if ((scb->flags & SCB_SENSE) && - ((scb->cmd->sense_buffer[12] == 0x43) || /* INVALID_MESSAGE */ - (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR */ - { - message_error = TRUE; - } - - if (scb->flags & SCB_MSGOUT_WDTR) - { - if (message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Wide Negotiation " - "processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no, - CTL_OF_SCB(scb)); - } - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - } - } - if (scb->flags & SCB_MSGOUT_SDTR) - { - if (message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Sync Negotiation " - "processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no, - CTL_OF_SCB(scb)); - aic_dev->flags &= ~DEVICE_PRINT_DTR; - } - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - } - } - if (scb->flags & SCB_MSGOUT_PPR) - { - if(message_error) - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - (aic_dev->flags & DEVICE_PRINT_DTR) ) - { - printk(INFO_LEAD "Device failed to complete Parallel Protocol " - "Request processing and\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "returned a sense error code for invalid message, " - "disabling future\n", p->host_no, CTL_OF_SCB(scb)); - printk(INFO_LEAD "Parallel Protocol Request negotiation to this " - "device.\n", p->host_no, CTL_OF_SCB(scb)); - } - /* - * Disable PPR negotiation and revert back to WDTR and SDTR setup - */ - aic_dev->needppr = aic_dev->needppr_copy = 0; - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - } - } - } - - queue_depth = aic_dev->temp_q_depth; - if (queue_depth >= aic_dev->active_cmds) - { - scbp = scbq_remove_head(&aic_dev->delayed_scbs); - if (scbp) - { - if (queue_depth == 1) - { - /* - * Give extra preference to untagged devices, such as CD-R devices - * This makes it more likely that a drive *won't* stuff up while - * waiting on data at a critical time, such as CD-R writing and - * audio CD ripping operations. Should also benefit tape drives. - */ - scbq_insert_head(&p->waiting_scbs, scbp); - } - else - { - scbq_insert_tail(&p->waiting_scbs, scbp); - } -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n", - p->host_no, CTL_OF_SCB(scbp)); -#endif - if (queue_depth > aic_dev->active_cmds) - { - scbp = scbq_remove_head(&aic_dev->delayed_scbs); - if (scbp) - scbq_insert_tail(&p->waiting_scbs, scbp); - } - } - } - if (!(scb->tag_action)) - { - aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun, - /* unbusy */ TRUE); - if (cmd->device->simple_tags) - { - aic_dev->temp_q_depth = aic_dev->max_q_depth; - } - } - if(scb->flags & SCB_DTR_SCB) - { - aic_dev->dtr_pending = 0; - } - aic_dev->active_cmds--; - p->activescbs--; - - if ((scb->sg_length >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK)) - { - long *ptr; - int x, i; - - - if (rq_data_dir(cmd->request) == WRITE) - { - aic_dev->w_total++; - ptr = aic_dev->w_bins; - } - else - { - aic_dev->r_total++; - ptr = aic_dev->r_bins; - } - x = scb->sg_length; - x >>= 10; - for(i=0; i<6; i++) - { - x >>= 2; - if(!x) { - ptr[i]++; - break; - } - } - if(i == 6 && x) - ptr[5]++; - } - aic7xxx_free_scb(p, scb); - aic7xxx_queue_cmd_complete(p, cmd); - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_run_done_queue - * - * Description: - * Calls the aic7xxx_done() for the scsi_cmnd of each scb in the - * aborted list, and adds each scb to the free list. If complete - * is TRUE, we also process the commands complete list. - *-F*************************************************************************/ -static void -aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete) -{ - struct aic7xxx_scb *scb; - int i, found = 0; - - for (i = 0; i < p->scb_data->numscbs; i++) - { - scb = p->scb_data->scb_array[i]; - if (scb->flags & SCB_QUEUED_FOR_DONE) - { - if (scb->flags & SCB_QUEUE_FULL) - { - scb->cmd->result = QUEUE_FULL << 1; - } - else - { - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Aborting scb %d\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag); - /* - * Clear any residual information since the normal aic7xxx_done() path - * doesn't touch the residuals. - */ - scb->hscb->residual_SG_segment_count = 0; - scb->hscb->residual_data_count[0] = 0; - scb->hscb->residual_data_count[1] = 0; - scb->hscb->residual_data_count[2] = 0; - } - found++; - aic7xxx_done(p, scb); - } - } - if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN)) - { - printk(INFO_LEAD "%d commands found and queued for " - "completion.\n", p->host_no, -1, -1, -1, found); - } - if (complete) - { - aic7xxx_done_cmds_complete(p); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_abort_waiting_scb - * - * Description: - * Manipulate the waiting for selection list and return the - * scb that follows the one that we remove. - *-F*************************************************************************/ -static unsigned char -aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb, - unsigned char scbpos, unsigned char prev) -{ - unsigned char curscb, next; - - /* - * Select the SCB we want to abort and pull the next pointer out of it. - */ - curscb = aic_inb(p, SCBPTR); - aic_outb(p, scbpos, SCBPTR); - next = aic_inb(p, SCB_NEXT); - - aic7xxx_add_curscb_to_free_list(p); - - /* - * Update the waiting list - */ - if (prev == SCB_LIST_NULL) - { - /* - * First in the list - */ - aic_outb(p, next, WAITING_SCBH); - } - else - { - /* - * Select the scb that pointed to us and update its next pointer. - */ - aic_outb(p, prev, SCBPTR); - aic_outb(p, next, SCB_NEXT); - } - /* - * Point us back at the original scb position and inform the SCSI - * system that the command has been aborted. - */ - aic_outb(p, curscb, SCBPTR); - return (next); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_search_qinfifo - * - * Description: - * Search the queue-in FIFO for matching SCBs and conditionally - * requeue. Returns the number of matching SCBs. - *-F*************************************************************************/ -static int -aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel, - int lun, unsigned char tag, int flags, int requeue, - volatile scb_queue_type *queue) -{ - int found; - unsigned char qinpos, qintail; - struct aic7xxx_scb *scbp; - - found = 0; - qinpos = aic_inb(p, QINPOS); - qintail = p->qinfifonext; - - p->qinfifonext = qinpos; - - while (qinpos != qintail) - { - scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - /* - * We found an scb that needs to be removed. - */ - if (requeue && (queue != NULL)) - { - if (scbp->flags & SCB_WAITINGQ) - { - scbq_remove(queue, scbp); - scbq_remove(&p->waiting_scbs, scbp); - scbq_remove(&AIC_DEV(scbp->cmd)->delayed_scbs, scbp); - AIC_DEV(scbp->cmd)->active_cmds++; - p->activescbs++; - } - scbq_insert_tail(queue, scbp); - AIC_DEV(scbp->cmd)->active_cmds--; - p->activescbs--; - scbp->flags |= SCB_WAITINGQ; - if ( !(scbp->tag_action & TAG_ENB) ) - { - aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - TRUE); - } - } - else if (requeue) - { - p->qinfifo[p->qinfifonext++] = scbp->hscb->tag; - } - else - { - /* - * Preserve any SCB_RECOVERY_SCB flags on this scb then set the - * flags we were called with, presumeably so aic7xxx_run_done_queue - * can find this scb - */ - scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB); - if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - FALSE) == scbp->hscb->tag) - { - aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun, - TRUE); - } - } - found++; - } - else - { - p->qinfifo[p->qinfifonext++] = scbp->hscb->tag; - } - } - /* - * Now that we've done the work, clear out any left over commands in the - * qinfifo and update the KERNEL_QINPOS down on the card. - * - * NOTE: This routine expect the sequencer to already be paused when - * it is run....make sure it's that way! - */ - qinpos = p->qinfifonext; - while(qinpos != qintail) - { - p->qinfifo[qinpos++] = SCB_LIST_NULL; - } - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - - return (found); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_scb_on_qoutfifo - * - * Description: - * Is the scb that was passed to us currently on the qoutfifo? - *-F*************************************************************************/ -static int -aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - int i=0; - - while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL) - { - if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag) - return TRUE; - else - i++; - } - return FALSE; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_device - * - * Description: - * The device at the given target/channel has been reset. Abort - * all active and queued scbs for that target/channel. This function - * need not worry about linked next pointers because if was a MSG_ABORT_TAG - * then we had a tagged command (no linked next), if it was MSG_ABORT or - * MSG_BUS_DEV_RESET then the device won't know about any commands any more - * and no busy commands will exist, and if it was a bus reset, then nothing - * knows about any linked next commands any more. In all cases, we don't - * need to worry about the linked next or busy scb, we just need to clear - * them. - *-F*************************************************************************/ -static void -aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel, - int lun, unsigned char tag) -{ - struct aic7xxx_scb *scbp, *prev_scbp; - struct scsi_device *sd; - unsigned char active_scb, tcl, scb_tag; - int i = 0, init_lists = FALSE; - struct aic_dev_data *aic_dev; - - /* - * Restore this when we're done - */ - active_scb = aic_inb(p, SCBPTR); - scb_tag = aic_inb(p, SCB_TAG); - - if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) - { - printk(INFO_LEAD "Reset device, hardware_scb %d,\n", - p->host_no, channel, target, lun, active_scb); - printk(INFO_LEAD "Current scb %d, SEQADDR 0x%x, LASTPHASE " - "0x%x\n", - p->host_no, channel, target, lun, scb_tag, - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, LASTPHASE)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", - p->host_no, channel, target, lun, - (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, - aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI)); - printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", - p->host_no, channel, target, lun, aic_inb(p, SSTAT0), - aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); - } - - /* - * Deal with the busy target and linked next issues. - */ - list_for_each_entry(aic_dev, &p->aic_devs, list) - { - if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS)) - printk(INFO_LEAD "processing aic_dev %p\n", p->host_no, channel, target, - lun, aic_dev); - sd = aic_dev->SDptr; - - if((target != ALL_TARGETS && target != sd->id) || - (channel != ALL_CHANNELS && channel != sd->channel)) - continue; - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning up status information " - "and delayed_scbs.\n", p->host_no, sd->channel, sd->id, sd->lun); - aic_dev->flags &= ~BUS_DEVICE_RESET_PENDING; - if ( tag == SCB_LIST_NULL ) - { - aic_dev->dtr_pending = 0; - aic_dev->needppr = aic_dev->needppr_copy; - aic_dev->needsdtr = aic_dev->needsdtr_copy; - aic_dev->needwdtr = aic_dev->needwdtr_copy; - aic_dev->flags = DEVICE_PRINT_DTR; - aic_dev->temp_q_depth = aic_dev->max_q_depth; - } - tcl = (sd->id << 4) | (sd->channel << 3) | sd->lun; - if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) || - (tag == SCB_LIST_NULL) ) - aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE); - prev_scbp = NULL; - scbp = aic_dev->delayed_scbs.head; - while (scbp != NULL) - { - prev_scbp = scbp; - scbp = scbp->q_next; - if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) - { - scbq_remove(&aic_dev->delayed_scbs, prev_scbp); - if (prev_scbp->flags & SCB_WAITINGQ) - { - aic_dev->active_cmds++; - p->activescbs++; - } - prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - } - } - } - - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun ); - aic7xxx_search_qinfifo(p, target, channel, lun, tag, - SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL); - -/* - * Search the waiting_scbs queue for matches, this catches any SCB_QUEUED - * ABORT/RESET commands. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel, - target, lun ); - { - struct aic7xxx_scb *scbp, *prev_scbp; - - prev_scbp = NULL; - scbp = p->waiting_scbs.head; - while (scbp != NULL) - { - prev_scbp = scbp; - scbp = scbp->q_next; - if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag)) - { - scbq_remove(&p->waiting_scbs, prev_scbp); - if (prev_scbp->flags & SCB_WAITINGQ) - { - AIC_DEV(prev_scbp->cmd)->active_cmds++; - p->activescbs++; - } - prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - } - } - } - - - /* - * Search waiting for selection list. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning waiting for selection " - "list.\n", p->host_no, channel, target, lun); - { - unsigned char next, prev, scb_index; - - next = aic_inb(p, WAITING_SCBH); /* Start at head of list. */ - prev = SCB_LIST_NULL; - while (next != SCB_LIST_NULL) - { - aic_outb(p, next, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index >= p->scb_data->numscbs) - { - /* - * No aic7xxx_verbose check here.....we want to see this since it - * means either the kernel driver or the sequencer screwed things up - */ - printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, " - "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, - p->scb_data->numscbs); - next = aic_inb(p, SCB_NEXT); - aic7xxx_add_curscb_to_free_list(p); - } - else - { - scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - next = aic7xxx_abort_waiting_scb(p, scbp, next, prev); - if (scbp->flags & SCB_WAITINGQ) - { - AIC_DEV(scbp->cmd)->active_cmds++; - p->activescbs++; - } - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - if (prev == SCB_LIST_NULL) - { - /* - * This is either the first scb on the waiting list, or we - * have already yanked the first and haven't left any behind. - * Either way, we need to turn off the selection hardware if - * it isn't already off. - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - } - } - else - { - prev = next; - next = aic_inb(p, SCB_NEXT); - } - } - } - } - - /* - * Go through disconnected list and remove any entries we have queued - * for completion, zeroing their control byte too. - */ - if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS)) - printk(INFO_LEAD "Cleaning disconnected scbs " - "list.\n", p->host_no, channel, target, lun); - if (p->flags & AHC_PAGESCBS) - { - unsigned char next, prev, scb_index; - - next = aic_inb(p, DISCONNECTED_SCBH); - prev = SCB_LIST_NULL; - while (next != SCB_LIST_NULL) - { - aic_outb(p, next, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, " - "numscbs=%d\n", p->host_no, channel, target, lun, scb_index, - p->scb_data->numscbs); - next = aic7xxx_rem_scb_from_disc_list(p, next, prev); - } - else - { - scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - next = aic7xxx_rem_scb_from_disc_list(p, next, prev); - if (scbp->flags & SCB_WAITINGQ) - { - AIC_DEV(scbp->cmd)->active_cmds++; - p->activescbs++; - } - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - scbp->hscb->control = 0; - } - else - { - prev = next; - next = aic_inb(p, SCB_NEXT); - } - } - } - } - - /* - * Walk the free list making sure no entries on the free list have - * a valid SCB_TAG value or SCB_CONTROL byte. - */ - if (p->flags & AHC_PAGESCBS) - { - unsigned char next; - - next = aic_inb(p, FREE_SCBH); - while (next != SCB_LIST_NULL) - { - aic_outb(p, next, SCBPTR); - if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs) - { - printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel, - target, lun); - init_lists = TRUE; - next = SCB_LIST_NULL; - } - else - { - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - next = aic_inb(p, SCB_NEXT); - } - } - } - - /* - * Go through the hardware SCB array looking for commands that - * were active but not on any list. - */ - if (init_lists) - { - aic_outb(p, SCB_LIST_NULL, FREE_SCBH); - aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); - aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH); - } - for (i = p->scb_data->maxhscbs - 1; i >= 0; i--) - { - unsigned char scbid; - - aic_outb(p, i, SCBPTR); - if (init_lists) - { - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, SCB_LIST_NULL, SCB_NEXT); - aic_outb(p, 0, SCB_CONTROL); - aic7xxx_add_curscb_to_free_list(p); - } - else - { - scbid = aic_inb(p, SCB_TAG); - if (scbid < p->scb_data->numscbs) - { - scbp = p->scb_data->scb_array[scbid]; - if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag)) - { - aic_outb(p, 0, SCB_CONTROL); - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic7xxx_add_curscb_to_free_list(p); - } - } - } - } - - /* - * Go through the entire SCB array now and look for commands for - * for this target that are stillactive. These are other (most likely - * tagged) commands that were disconnected when the reset occurred. - * Any commands we find here we know this about, it wasn't on any queue, - * it wasn't in the qinfifo, it wasn't in the disconnected or waiting - * lists, so it really must have been a paged out SCB. In that case, - * we shouldn't need to bother with updating any counters, just mark - * the correct flags and go on. - */ - for (i = 0; i < p->scb_data->numscbs; i++) - { - scbp = p->scb_data->scb_array[i]; - if ((scbp->flags & SCB_ACTIVE) && - aic7xxx_match_scb(p, scbp, target, channel, lun, tag) && - !aic7xxx_scb_on_qoutfifo(p, scbp)) - { - if (scbp->flags & SCB_WAITINGQ) - { - scbq_remove(&p->waiting_scbs, scbp); - scbq_remove(&AIC_DEV(scbp->cmd)->delayed_scbs, scbp); - AIC_DEV(scbp->cmd)->active_cmds++; - p->activescbs++; - } - scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE; - scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ); - } - } - - aic_outb(p, active_scb, SCBPTR); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_clear_intstat - * - * Description: - * Clears the interrupt status. - *-F*************************************************************************/ -static void -aic7xxx_clear_intstat(struct aic7xxx_host *p) -{ - /* Clear any interrupt conditions this may have caused. */ - aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0); - aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR | - CLRPHASECHG | CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT | CLRPARERR, CLRINT); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_current_bus - * - * Description: - * Reset the current SCSI bus. - *-F*************************************************************************/ -static void -aic7xxx_reset_current_bus(struct aic7xxx_host *p) -{ - - /* Disable reset interrupts. */ - aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1); - - /* Turn off the bus' current operations, after all, we shouldn't have any - * valid commands left to cause a RSELI and SELO once we've tossed the - * bus away with this reset, so we might as well shut down the sequencer - * until the bus is restarted as opposed to saving the current settings - * and restoring them (which makes no sense to me). */ - - /* Turn on the bus reset. */ - aic_outb(p, aic_inb(p, SCSISEQ) | SCSIRSTO, SCSISEQ); - while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0) - mdelay(5); - - /* - * Some of the new Ultra2 chipsets need a longer delay after a chip - * reset than just the init setup creates, so we have to delay here - * before we go into a reset in order to make the chips happy. - */ - if (p->features & AHC_ULTRA2) - mdelay(250); - else - mdelay(50); - - /* Turn off the bus reset. */ - aic_outb(p, 0, SCSISEQ); - mdelay(10); - - aic7xxx_clear_intstat(p); - /* Re-enable reset interrupts. */ - aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1); - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_reset_channel - * - * Description: - * Reset the channel. - *-F*************************************************************************/ -static void -aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset) -{ - unsigned long offset_min, offset_max; - unsigned char sblkctl; - int cur_channel; - - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Reset channel called, %s initiate reset.\n", - p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" ); - - - if (channel == 1) - { - offset_min = 8; - offset_max = 16; - } - else - { - if (p->features & AHC_TWIN) - { - /* Channel A */ - offset_min = 0; - offset_max = 8; - } - else - { - offset_min = 0; - if (p->features & AHC_WIDE) - { - offset_max = 16; - } - else - { - offset_max = 8; - } - } - } - - while (offset_min < offset_max) - { - /* - * Revert to async/narrow transfers until we renegotiate. - */ - aic_outb(p, 0, TARG_SCSIRATE + offset_min); - if (p->features & AHC_ULTRA2) - { - aic_outb(p, 0, TARG_OFFSET + offset_min); - } - offset_min++; - } - - /* - * Reset the bus and unpause/restart the controller - */ - sblkctl = aic_inb(p, SBLKCTL); - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - cur_channel = (sblkctl & SELBUSB) >> 3; - else - cur_channel = 0; - if ( (cur_channel != channel) && (p->features & AHC_TWIN) ) - { - /* - * Case 1: Command for another bus is active - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no, - channel, -1, -1); - /* - * Stealthily reset the other bus without upsetting the current bus. - */ - aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL); - aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1); - if (initiate_reset) - { - aic7xxx_reset_current_bus(p); - } - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ); - aic7xxx_clear_intstat(p); - aic_outb(p, sblkctl, SBLKCTL); - } - else - { - /* - * Case 2: A command from this bus is active or we're idle. - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no, - channel, -1, -1); - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), - SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - p->msg_type = MSG_TYPE_NONE; - p->msg_len = 0; - if (initiate_reset) - { - aic7xxx_reset_current_bus(p); - } - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ); - aic7xxx_clear_intstat(p); - } - if (aic7xxx_verbose & VERBOSE_RESET_RETURN) - printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1); - /* - * Clean up all the state information for the pending transactions - * on this bus. - */ - aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL); - - if ( !(p->features & AHC_TWIN) ) - { - restart_sequencer(p); - } - - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_run_waiting_queues - * - * Description: - * Scan the awaiting_scbs queue downloading and starting as many - * scbs as we can. - *-F*************************************************************************/ -static void -aic7xxx_run_waiting_queues(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scb; - struct aic_dev_data *aic_dev; - int sent; - - - if (p->waiting_scbs.head == NULL) - return; - - sent = 0; - - /* - * First handle SCBs that are waiting but have been assigned a slot. - */ - while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL) - { - aic_dev = scb->cmd->device->hostdata; - if ( !scb->tag_action ) - { - aic_dev->temp_q_depth = 1; - } - if ( aic_dev->active_cmds >= aic_dev->temp_q_depth) - { - scbq_insert_tail(&aic_dev->delayed_scbs, scb); - } - else - { - scb->flags &= ~SCB_WAITINGQ; - aic_dev->active_cmds++; - p->activescbs++; - if ( !(scb->tag_action) ) - { - aic7xxx_busy_target(p, scb); - } - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - sent++; - } - } - if (sent) - { - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - { - pause_sequencer(p); - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - unpause_sequencer(p, FALSE); - } - if (p->activescbs > p->max_activescbs) - p->max_activescbs = p->activescbs; - } -} - -#ifdef CONFIG_PCI - -#define DPE 0x80 -#define SSE 0x40 -#define RMA 0x20 -#define RTA 0x10 -#define STA 0x08 -#define DPR 0x01 - -/*+F************************************************************************* - * Function: - * aic7xxx_pci_intr - * - * Description: - * Check the scsi card for PCI errors and clear the interrupt - * - * NOTE: If you don't have this function and a 2940 card encounters - * a PCI error condition, the machine will end up locked as the - * interrupt handler gets slammed with non-stop PCI error interrupts - *-F*************************************************************************/ -static void -aic7xxx_pci_intr(struct aic7xxx_host *p) -{ - unsigned char status1; - - pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1); - - if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Data Parity Error during PCI address or PCI write" - "phase.\n", p->host_no, -1, -1, -1); - if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Signal System Error Detected\n", p->host_no, - -1, -1, -1); - if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no, - -1, -1, -1); - if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ) - printk(WARN_LEAD "Data Parity Error has been reported via PCI pin " - "PERR#\n", p->host_no, -1, -1, -1); - - pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1); - if (status1 & (DPR|RMA|RTA)) - aic_outb(p, CLRPARERR, CLRINT); - - if ( (aic7xxx_panic_on_abort) && (p->spurious_int > 500) ) - aic7xxx_panic_abort(p, NULL); - -} -#endif /* CONFIG_PCI */ - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_ppr - * - * Description: - * Build up a Parallel Protocol Request message for use with SCSI-3 - * devices. - *-F*************************************************************************/ -static void -aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_PPR; - p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.period; - p->msg_buf[p->msg_index++] = 0; - p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.offset; - p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.width; - p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.options; - p->msg_len += 8; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_sdtr - * - * Description: - * Constucts a synchronous data transfer message in the message - * buffer on the sequencer. - *-F*************************************************************************/ -static void -aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period, - unsigned char offset) -{ - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_SDTR; - p->msg_buf[p->msg_index++] = period; - p->msg_buf[p->msg_index++] = offset; - p->msg_len += 5; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_construct_wdtr - * - * Description: - * Constucts a wide data transfer message in the message buffer - * on the sequencer. - *-F*************************************************************************/ -static void -aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width) -{ - p->msg_buf[p->msg_index++] = MSG_EXTENDED; - p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN; - p->msg_buf[p->msg_index++] = MSG_EXT_WDTR; - p->msg_buf[p->msg_index++] = bus_width; - p->msg_len += 4; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_calc_residual - * - * Description: - * Calculate the residual data not yet transferred. - *-F*************************************************************************/ -static void -aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - struct aic7xxx_hwscb *hscb; - struct scsi_cmnd *cmd; - int actual, i; - - cmd = scb->cmd; - hscb = scb->hscb; - - /* - * Don't destroy valid residual information with - * residual coming from a check sense operation. - */ - if (((scb->hscb->control & DISCONNECTED) == 0) && - (scb->flags & SCB_SENSE) == 0) - { - /* - * We had an underflow. At this time, there's only - * one other driver that bothers to check for this, - * and cmd->underflow seems to be set rather half- - * heartedly in the higher-level SCSI code. - */ - actual = scb->sg_length; - for (i=1; i < hscb->residual_SG_segment_count; i++) - { - actual -= scb->sg_list[scb->sg_count - i].length; - } - actual -= (hscb->residual_data_count[2] << 16) | - (hscb->residual_data_count[1] << 8) | - hscb->residual_data_count[0]; - - if (actual < cmd->underflow) - { - if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) - { - printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG " - "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow, - (rq_data_dir(cmd->request) == WRITE) ? "wrote" : "read", actual, - hscb->residual_SG_segment_count); - printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb), - hscb->target_status); - } - /* - * In 2.4, only send back the residual information, don't flag this - * as an error. Before 2.4 we had to flag this as an error because - * the mid layer didn't check residual data counts to see if the - * command needs retried. - */ - scsi_set_resid(cmd, scb->sg_length - actual); - aic7xxx_status(cmd) = hscb->target_status; - } - } - - /* - * Clean out the residual information in the SCB for the - * next consumer. - */ - hscb->residual_data_count[2] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_SG_segment_count = 0; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_device_reset - * - * Description: - * Interrupt handler for sequencer interrupts (SEQINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel) -{ - unsigned char tindex = target; - - tindex |= ((channel & 0x01) << 3); - - /* - * Go back to async/narrow transfers and renegotiate. - */ - aic_outb(p, 0, TARG_SCSIRATE + tindex); - if (p->features & AHC_ULTRA2) - aic_outb(p, 0, TARG_OFFSET + tindex); - aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL); - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel, - target, -1); - aic7xxx_run_done_queue(p, /*complete*/ TRUE); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_seqint - * - * Description: - * Interrupt handler for sequencer interrupts (SEQINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat) -{ - struct aic7xxx_scb *scb; - struct aic_dev_data *aic_dev; - unsigned short target_mask; - unsigned char target, lun, tindex; - unsigned char queue_flag = FALSE; - char channel; - int result; - - target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f); - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - tindex = target + (channel << 3); - lun = aic_inb(p, SAVED_TCL) & 0x07; - target_mask = (0x01 << tindex); - - /* - * Go ahead and clear the SEQINT now, that avoids any interrupt race - * conditions later on in case we enable some other interrupt. - */ - aic_outb(p, CLRSEQINT, CLRINT); - switch (intstat & SEQINT_MASK) - { - case NO_MATCH: - { - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), - SCSISEQ); - printk(WARN_LEAD "No active SCB for reconnecting target - Issuing " - "BUS DEVICE RESET.\n", p->host_no, channel, target, lun); - printk(WARN_LEAD " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n", - p->host_no, channel, target, lun, - aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1), - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - } - break; - - case SEND_REJECT: - { - if (aic7xxx_verbose & VERBOSE_MINOR_ERROR) - printk(INFO_LEAD "Rejecting unknown message (0x%x) received from " - "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun, - aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS)); - } - break; - - case NO_IDENT: - { - /* - * The reconnecting target either did not send an identify - * message, or did, but we didn't find an SCB to match and - * before it could respond to our ATN/abort, it hit a dataphase. - * The only safe thing to do is to blow it away with a bus - * reset. - */ - if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID)) - printk(INFO_LEAD "Target did not send an IDENTIFY message; " - "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target, - lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL)); - - aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE); - aic7xxx_run_done_queue(p, TRUE); - - } - break; - - case BAD_PHASE: - if (aic_inb(p, LASTPHASE) == P_BUSFREE) - { - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel, - target, lun); - restart_sequencer(p); - } - else - { - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no, - channel, target, lun); - } - break; - - case EXTENDED_MSG: - { - p->msg_type = MSG_TYPE_INITIATOR_MSGIN; - p->msg_len = 0; - p->msg_index = 0; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Enabling REQINITs for MSG_IN\n", p->host_no, - channel, target, lun); -#endif - - /* - * To actually receive the message, simply turn on - * REQINIT interrupts and let our interrupt handler - * do the rest (REQINIT should already be true). - */ - p->flags |= AHC_HANDLING_REQINITS; - aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1); - - /* - * We don't want the sequencer unpaused yet so we return early - */ - return; - } - - case REJECT_MSG: - { - /* - * What we care about here is if we had an outstanding SDTR - * or WDTR message for this target. If we did, this is a - * signal that the target is refusing negotiation. - */ - unsigned char scb_index; - unsigned char last_msg; - - scb_index = aic_inb(p, SCB_TAG); - scb = p->scb_data->scb_array[scb_index]; - aic_dev = AIC_DEV(scb->cmd); - last_msg = aic_inb(p, LAST_MSG); - - if ( (last_msg == MSG_IDENTIFYFLAG) && - (scb->tag_action) && - !(scb->flags & SCB_MSGOUT_BITS) ) - { - if (scb->tag_action == MSG_ORDERED_Q_TAG) - { - /* - * OK...the device seems able to accept tagged commands, but - * not ordered tag commands, only simple tag commands. So, we - * disable ordered tag commands and go on with life just like - * normal. - */ - scsi_adjust_queue_depth(scb->cmd->device, MSG_SIMPLE_TAG, - scb->cmd->device->queue_depth); - scb->tag_action = MSG_SIMPLE_Q_TAG; - scb->hscb->control &= ~SCB_TAG_TYPE; - scb->hscb->control |= MSG_SIMPLE_Q_TAG; - aic_outb(p, scb->hscb->control, SCB_CONTROL); - /* - * OK..we set the tag type to simple tag command, now we re-assert - * ATNO and hope this will take us into the identify phase again - * so we can resend the tag type and info to the device. - */ - aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - else if (scb->tag_action == MSG_SIMPLE_Q_TAG) - { - unsigned char i; - struct aic7xxx_scb *scbp; - int old_verbose; - /* - * Hmmmm....the device is flaking out on tagged commands. - */ - scsi_adjust_queue_depth(scb->cmd->device, 0 /* untagged */, - p->host->cmd_per_lun); - aic_dev->max_q_depth = aic_dev->temp_q_depth = 1; - /* - * We set this command up as a bus device reset. However, we have - * to clear the tag type as it's causing us problems. We shouldn't - * have to worry about any other commands being active, since if - * the device is refusing tagged commands, this should be the - * first tagged command sent to the device, however, we do have - * to worry about any other tagged commands that may already be - * in the qinfifo. The easiest way to do this, is to issue a BDR, - * send all the commands back to the mid level code, then let them - * come back and get rebuilt as untagged commands. - */ - scb->tag_action = 0; - scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE); - aic_outb(p, scb->hscb->control, SCB_CONTROL); - - old_verbose = aic7xxx_verbose; - aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT); - for (i=0; i < p->scb_data->numscbs; i++) - { - scbp = p->scb_data->scb_array[i]; - if ((scbp->flags & SCB_ACTIVE) && (scbp != scb)) - { - if (aic7xxx_match_scb(p, scbp, target, channel, lun, i)) - { - aic7xxx_reset_device(p, target, channel, lun, i); - } - } - } - aic7xxx_run_done_queue(p, TRUE); - aic7xxx_verbose = old_verbose; - /* - * Wait until after the for loop to set the busy index since - * aic7xxx_reset_device will clear the busy index during its - * operation. - */ - aic7xxx_busy_target(p, scb); - printk(INFO_LEAD "Device is refusing tagged commands, using " - "untagged I/O.\n", p->host_no, channel, target, lun); - aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - } - else if (scb->flags & SCB_MSGOUT_PPR) - { - /* - * As per the draft specs, any device capable of supporting any of - * the option values other than 0 are not allowed to reject the - * PPR message. Instead, they must negotiate out what they do - * support instead of rejecting our offering or else they cause - * a parity error during msg_out phase to signal that they don't - * like our settings. - */ - aic_dev->needppr = aic_dev->needppr_copy = 0; - aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE), aic_dev); - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE, - aic_dev); - aic_dev->goal.options = aic_dev->dtr_pending = 0; - scb->flags &= ~SCB_MSGOUT_BITS; - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting PPR messages, falling " - "back.\n", p->host_no, channel, target, lun); - } - if ( aic_dev->goal.width ) - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - aic_dev->dtr_pending = 1; - scb->flags |= SCB_MSGOUT_WDTR; - } - if ( aic_dev->goal.offset ) - { - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - if( !aic_dev->dtr_pending ) - { - aic_dev->dtr_pending = 1; - scb->flags |= SCB_MSGOUT_SDTR; - } - } - if ( aic_dev->dtr_pending ) - { - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - } - else if (scb->flags & SCB_MSGOUT_WDTR) - { - /* - * note 8bit xfers and clear flag - */ - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - scb->flags &= ~SCB_MSGOUT_BITS; - aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR), aic_dev); - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE, - aic_dev); - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting WDTR messages, using " - "narrow transfers.\n", p->host_no, channel, target, lun); - } - aic_dev->needsdtr = aic_dev->needsdtr_copy; - } - else if (scb->flags & SCB_MSGOUT_SDTR) - { - /* - * note asynch xfers and clear flag - */ - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - scb->flags &= ~SCB_MSGOUT_BITS; - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL), aic_dev); - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Device is rejecting SDTR messages, using " - "async transfers.\n", p->host_no, channel, target, lun); - } - } - else if (aic7xxx_verbose & VERBOSE_SEQINT) - { - /* - * Otherwise, we ignore it. - */ - printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause. " - "Ignoring.\n", p->host_no, channel, target, lun); - } - } - break; - - case BAD_STATUS: - { - unsigned char scb_index; - struct aic7xxx_hwscb *hscb; - struct scsi_cmnd *cmd; - - /* The sequencer will notify us when a command has an error that - * would be of interest to the kernel. This allows us to leave - * the sequencer running in the common case of command completes - * without error. The sequencer will have DMA'd the SCB back - * up to us, so we can reference the drivers SCB array. - * - * Set the default return value to 0 indicating not to send - * sense. The sense code will change this if needed and this - * reduces code duplication. - */ - aic_outb(p, 0, RETURN_1); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n", - p->host_no, channel, target, lun, intstat, scb_index); - break; - } - scb = p->scb_data->scb_array[scb_index]; - hscb = scb->hscb; - - if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x," - " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat, - scb_index, scb->flags, (unsigned long) scb->cmd); - } - else - { - cmd = scb->cmd; - aic_dev = AIC_DEV(scb->cmd); - hscb->target_status = aic_inb(p, SCB_TARGET_STATUS); - aic7xxx_status(cmd) = hscb->target_status; - - cmd->result = hscb->target_status; - - switch (status_byte(hscb->target_status)) - { - case GOOD: - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Interrupted for status of GOOD???\n", - p->host_no, CTL_OF_SCB(scb)); - break; - - case COMMAND_TERMINATED: - case CHECK_CONDITION: - if ( !(scb->flags & SCB_SENSE) ) - { - /* - * Send a sense command to the requesting target. - * XXX - revisit this and get rid of the memcopys. - */ - memcpy(scb->sense_cmd, &generic_sense[0], - sizeof(generic_sense)); - - scb->sense_cmd[1] = (cmd->device->lun << 5); - scb->sense_cmd[4] = SCSI_SENSE_BUFFERSIZE; - - scb->sg_list[0].length = - cpu_to_le32(SCSI_SENSE_BUFFERSIZE); - scb->sg_list[0].address = - cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE)); - - /* - * XXX - We should allow disconnection, but can't as it - * might allow overlapped tagged commands. - */ - /* hscb->control &= DISCENB; */ - hscb->control = 0; - hscb->target_status = 0; - hscb->SG_list_pointer = - cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list)); - hscb->SCSI_cmd_pointer = - cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd)); - hscb->data_count = scb->sg_list[0].length; - hscb->data_pointer = scb->sg_list[0].address; - hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]); - hscb->residual_SG_segment_count = 0; - hscb->residual_data_count[0] = 0; - hscb->residual_data_count[1] = 0; - hscb->residual_data_count[2] = 0; - - scb->sg_count = hscb->SG_segment_count = 1; - scb->sg_length = SCSI_SENSE_BUFFERSIZE; - scb->tag_action = 0; - scb->flags |= SCB_SENSE; - /* - * Ensure the target is busy since this will be an - * an untagged request. - */ -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - if (scb->flags & SCB_MSGOUT_BITS) - printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no, - CTL_OF_SCB(scb), (scb->flags & SCB_MSGOUT_SDTR) ? - "SDTR" : "WDTR"); - else - printk(INFO_LEAD "Requesting SENSE, no MSG\n", p->host_no, - CTL_OF_SCB(scb)); - } -#endif - aic7xxx_busy_target(p, scb); - aic_outb(p, SEND_SENSE, RETURN_1); - aic7xxx_error(cmd) = DID_OK; - break; - } /* first time sense, no errors */ - printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning " - "an error.\n", p->host_no, CTL_OF_SCB(scb)); - aic7xxx_error(cmd) = DID_ERROR; - scb->flags &= ~SCB_SENSE; - break; - - case QUEUE_FULL: - queue_flag = TRUE; /* Mark that this is a QUEUE_FULL and */ - case BUSY: /* drop through to here */ - { - struct aic7xxx_scb *next_scbp, *prev_scbp; - unsigned char active_hscb, next_hscb, prev_hscb, scb_index; - /* - * We have to look three places for queued commands: - * 1: p->waiting_scbs queue - * 2: QINFIFO - * 3: WAITING_SCBS list on card (for commands that are started - * but haven't yet made it to the device) - * - * Of special note here is that commands on 2 or 3 above will - * have already been marked as active, while commands on 1 will - * not. The aic7xxx_done() function will want to unmark them - * from active, so any commands we pull off of 1 need to - * up the active count. - */ - next_scbp = p->waiting_scbs.head; - while ( next_scbp != NULL ) - { - prev_scbp = next_scbp; - next_scbp = next_scbp->q_next; - if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun, - SCB_LIST_NULL) ) - { - scbq_remove(&p->waiting_scbs, prev_scbp); - scb->flags = SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL; - p->activescbs++; - aic_dev->active_cmds++; - } - } - aic7xxx_search_qinfifo(p, target, channel, lun, - SCB_LIST_NULL, SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL, - FALSE, NULL); - next_scbp = NULL; - active_hscb = aic_inb(p, SCBPTR); - prev_hscb = next_hscb = scb_index = SCB_LIST_NULL; - next_hscb = aic_inb(p, WAITING_SCBH); - while (next_hscb != SCB_LIST_NULL) - { - aic_outb(p, next_hscb, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - if (scb_index < p->scb_data->numscbs) - { - next_scbp = p->scb_data->scb_array[scb_index]; - if (aic7xxx_match_scb(p, next_scbp, target, channel, lun, - SCB_LIST_NULL) ) - { - next_scbp->flags = SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL; - next_hscb = aic_inb(p, SCB_NEXT); - aic_outb(p, 0, SCB_CONTROL); - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic7xxx_add_curscb_to_free_list(p); - if (prev_hscb == SCB_LIST_NULL) - { - /* We were first on the list, - * so we kill the selection - * hardware. Let the sequencer - * re-init the hardware itself - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - aic_outb(p, next_hscb, WAITING_SCBH); - } - else - { - aic_outb(p, prev_hscb, SCBPTR); - aic_outb(p, next_hscb, SCB_NEXT); - } - } - else - { - prev_hscb = next_hscb; - next_hscb = aic_inb(p, SCB_NEXT); - } - } /* scb_index >= p->scb_data->numscbs */ - } - aic_outb(p, active_hscb, SCBPTR); - aic7xxx_run_done_queue(p, FALSE); - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) || - (aic7xxx_verbose > 0xffff) ) - { - if (queue_flag) - printk(INFO_LEAD "Queue full received; queue depth %d, " - "active %d\n", p->host_no, CTL_OF_SCB(scb), - aic_dev->max_q_depth, aic_dev->active_cmds); - else - printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb)); - } -#endif - if (queue_flag) - { - int diff; - result = scsi_track_queue_full(cmd->device, - aic_dev->active_cmds); - if ( result < 0 ) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - printk(INFO_LEAD "Tagged Command Queueing disabled.\n", - p->host_no, CTL_OF_SCB(scb)); - diff = aic_dev->max_q_depth - p->host->cmd_per_lun; - aic_dev->temp_q_depth = 1; - aic_dev->max_q_depth = 1; - } - else if ( result > 0 ) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no, - CTL_OF_SCB(scb), result); - diff = aic_dev->max_q_depth - result; - aic_dev->max_q_depth = result; - /* temp_q_depth could have been dropped to 1 for an untagged - * command that might be coming up */ - if(aic_dev->temp_q_depth > result) - aic_dev->temp_q_depth = result; - } - /* We should free up the no unused SCB entries. But, that's - * a difficult thing to do because we use a direct indexed - * array, so we can't just take any entries and free them, - * we *have* to free the ones at the end of the array, and - * they very well could be in use right now, which means - * in order to do this right, we have to add a delayed - * freeing mechanism tied into the scb_free() code area. - * We'll add that later. - */ - } - break; - } - - default: - if (aic7xxx_verbose & VERBOSE_SEQINT) - printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no, - CTL_OF_SCB(scb), scb->hscb->target_status); - if (!aic7xxx_error(cmd)) - { - aic7xxx_error(cmd) = DID_RETRY_COMMAND; - } - break; - } /* end switch */ - } /* end else of */ - } - break; - - case AWAITING_MSG: - { - unsigned char scb_index, msg_out; - - scb_index = aic_inb(p, SCB_TAG); - msg_out = aic_inb(p, MSG_OUT); - scb = p->scb_data->scb_array[scb_index]; - aic_dev = AIC_DEV(scb->cmd); - p->msg_index = p->msg_len = 0; - /* - * This SCB had a MK_MESSAGE set in its control byte informing - * the sequencer that we wanted to send a special message to - * this target. - */ - - if ( !(scb->flags & SCB_DEVICE_RESET) && - (msg_out == MSG_IDENTIFYFLAG) && - (scb->hscb->control & TAG_ENB) ) - { - p->msg_buf[p->msg_index++] = scb->tag_action; - p->msg_buf[p->msg_index++] = scb->hscb->tag; - p->msg_len += 2; - } - - if (scb->flags & SCB_DEVICE_RESET) - { - p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET; - p->msg_len++; - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Bus device reset mailed.\n", - p->host_no, CTL_OF_SCB(scb)); - } - else if (scb->flags & SCB_ABORT) - { - if (scb->tag_action) - { - p->msg_buf[p->msg_index++] = MSG_ABORT_TAG; - } - else - { - p->msg_buf[p->msg_index++] = MSG_ABORT; - } - p->msg_len++; - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "Abort message mailed.\n", p->host_no, - CTL_OF_SCB(scb)); - } - else if (scb->flags & SCB_MSGOUT_PPR) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n", - p->host_no, CTL_OF_SCB(scb), - aic_dev->goal.period, - aic_dev->goal.offset, - aic_dev->goal.width, - aic_dev->goal.options); - } - aic7xxx_construct_ppr(p, scb); - } - else if (scb->flags & SCB_MSGOUT_WDTR) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending WDTR message.\n", p->host_no, - CTL_OF_SCB(scb)); - } - aic7xxx_construct_wdtr(p, aic_dev->goal.width); - } - else if (scb->flags & SCB_MSGOUT_SDTR) - { - unsigned int max_sync, period; - unsigned char options = 0; - /* - * Now that the device is selected, use the bits in SBLKCTL and - * SSTAT2 to determine the max sync rate for this device. - */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - max_sync = AHC_SYNCRATE_ULTRA2; - } - else - { - max_sync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - max_sync = AHC_SYNCRATE_ULTRA; - } - else - { - max_sync = AHC_SYNCRATE_FAST; - } - period = aic_dev->goal.period; - aic7xxx_find_syncrate(p, &period, max_sync, &options); - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no, - CTL_OF_SCB(scb), period, - aic_dev->goal.offset); - } - aic7xxx_construct_sdtr(p, period, aic_dev->goal.offset); - } - else - { - panic("aic7xxx: AWAITING_MSG for an SCB that does " - "not have a waiting message.\n"); - } - /* - * We've set everything up to send our message, now to actually do - * so we need to enable reqinit interrupts and let the interrupt - * handler do the rest. We don't want to unpause the sequencer yet - * though so we'll return early. We also have to make sure that - * we clear the SEQINT *BEFORE* we set the REQINIT handler active - * or else it's possible on VLB cards to lose the first REQINIT - * interrupt. Edge triggered EISA cards could also lose this - * interrupt, although PCI and level triggered cards should not - * have this problem since they continually interrupt the kernel - * until we take care of the situation. - */ - scb->flags |= SCB_MSGOUT_SENT; - p->msg_index = 0; - p->msg_type = MSG_TYPE_INITIATOR_MSGOUT; - p->flags |= AHC_HANDLING_REQINITS; - aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1); - return; - } - break; - - case DATA_OVERRUN: - { - unsigned char scb_index = aic_inb(p, SCB_TAG); - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned int i; - - scb = (p->scb_data->scb_array[scb_index]); - /* - * XXX - What do we really want to do on an overrun? The - * mid-level SCSI code should handle this, but for now, - * we'll just indicate that the command should retried. - * If we retrieved sense info on this target, then the - * base SENSE info should have been saved prior to the - * overrun error. In that case, we return DID_OK and let - * the mid level code pick up on the sense info. Otherwise - * we return DID_ERROR so the command will get retried. - */ - if ( !(scb->flags & SCB_SENSE) ) - { - printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n", - p->host_no, CTL_OF_SCB(scb), - (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag); - printk(KERN_WARNING " %s seen Data Phase. Length=%d, NumSGs=%d.\n", - (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't", - scb->sg_length, scb->sg_count); - printk(KERN_WARNING " Raw SCSI Command: 0x"); - for (i = 0; i < scb->hscb->SCSI_cmd_length; i++) - { - printk("%02x ", scb->cmd->cmnd[i]); - } - printk("\n"); - if(aic7xxx_verbose > 0xffff) - { - for (i = 0; i < scb->sg_count; i++) - { - printk(KERN_WARNING " sg[%d] - Addr 0x%x : Length %d\n", - i, - le32_to_cpu(scb->sg_list[i].address), - le32_to_cpu(scb->sg_list[i].length) ); - } - } - aic7xxx_error(scb->cmd) = DID_ERROR; - } - else - printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n", - p->host_no, CTL_OF_SCB(scb)); - } - break; - - case WIDE_RESIDUE: - { - unsigned char resid_sgcnt, index; - unsigned char scb_index = aic_inb(p, SCB_TAG); - unsigned int cur_addr, resid_dcnt; - unsigned int native_addr, native_length, sg_addr; - int i; - - if(scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n", - p->host_no, -1, -1, -1); - /* - * XXX: Add error handling here - */ - break; - } - scb = p->scb_data->scb_array[scb_index]; - if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x " - "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb), - scb->flags, (unsigned long)scb->cmd); - break; - } - if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) - printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data " - "pointer.\n", p->host_no, CTL_OF_SCB(scb)); - - /* - * We have a valid scb to use on this WIDE_RESIDUE message, so - * we need to walk the sg list looking for this particular sg - * segment, then see if we happen to be at the very beginning of - * the segment. If we are, then we have to back things up to - * the previous segment. If not, then we simply need to remove - * one byte from this segments address and add one to the byte - * count. - */ - cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) | - (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24); - sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) | - (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24); - resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT); - resid_dcnt = aic_inb(p, SCB_RESID_DCNT) | - (aic_inb(p, SCB_RESID_DCNT + 1) << 8) | - (aic_inb(p, SCB_RESID_DCNT + 2) << 16); - index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1); - native_addr = le32_to_cpu(scb->sg_list[index].address); - native_length = le32_to_cpu(scb->sg_list[index].length); - /* - * If resid_dcnt == native_length, then we just loaded this SG - * segment and we need to back it up one... - */ - if(resid_dcnt == native_length) - { - if(index == 0) - { - /* - * Oops, this isn't right, we can't back up to before the - * beginning. This must be a bogus message, ignore it. - */ - break; - } - resid_dcnt = 1; - resid_sgcnt += 1; - native_addr = le32_to_cpu(scb->sg_list[index - 1].address); - native_length = le32_to_cpu(scb->sg_list[index - 1].length); - cur_addr = native_addr + (native_length - 1); - sg_addr -= sizeof(struct hw_scatterlist); - } - else - { - /* - * resid_dcnt != native_length, so we are in the middle of a SG - * element. Back it up one byte and leave the rest alone. - */ - resid_dcnt += 1; - cur_addr -= 1; - } - - /* - * Output the new addresses and counts to the right places on the - * card. - */ - aic_outb(p, resid_sgcnt, SG_COUNT); - aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT); - aic_outb(p, sg_addr & 0xff, SG_COUNT + 1); - aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2); - aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3); - aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4); - aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2); - - /* - * The sequencer actually wants to find the new address - * in the SHADDR register set. On the Ultra2 and later controllers - * this register set is readonly. In order to get the right number - * into the register, you actually have to enter it in HADDR and then - * use the PRELOADEN bit of DFCNTRL to drop it through from the - * HADDR register to the SHADDR register. On non-Ultra2 controllers, - * we simply write it direct. - */ - if(p->features & AHC_ULTRA2) - { - /* - * We might as well be accurate and drop both the resid_dcnt and - * cur_addr into HCNT and HADDR and have both of them drop - * through to the shadow layer together. - */ - aic_outb(p, resid_dcnt & 0xff, HCNT); - aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1); - aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2); - aic_outb(p, cur_addr & 0xff, HADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3); - aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL); - udelay(1); - aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL); - i=0; - while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000)) - { - udelay(1); - } - } - else - { - aic_outb(p, cur_addr & 0xff, SHADDR); - aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1); - aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2); - aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3); - } - } - break; - - case SEQ_SG_FIXUP: - { - unsigned char scb_index, tmp; - int sg_addr, sg_length; - - scb_index = aic_inb(p, SCB_TAG); - - if(scb_index > p->scb_data->numscbs) - { - printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n", - p->host_no, -1, -1, -1); - printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " - "0x%x\n", p->host_no, -1, -1, -1, - aic_inb(p, SCSISIGI), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", - p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR), - aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | - aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); - /* - * XXX: Add error handling here - */ - break; - } - scb = p->scb_data->scb_array[scb_index]; - if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x " - "scb->cmd:0x%p\n", p->host_no, CTL_OF_SCB(scb), - scb->flags, scb->cmd); - printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " - "0x%x\n", p->host_no, CTL_OF_SCB(scb), - aic_inb(p, SCSISIGI), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", - p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR), - aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 | - aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT)); - break; - } - if(aic7xxx_verbose & VERBOSE_MINOR_ERROR) - printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no, - CTL_OF_SCB(scb)); - /* - * Advance the SG pointer to the next element in the list - */ - tmp = aic_inb(p, SG_NEXT); - tmp += SG_SIZEOF; - aic_outb(p, tmp, SG_NEXT); - if( tmp < SG_SIZEOF ) - aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1); - tmp = aic_inb(p, SG_COUNT) - 1; - aic_outb(p, tmp, SG_COUNT); - sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address); - sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length); - /* - * Now stuff the element we just advanced past down onto the - * card so it can be stored in the residual area. - */ - aic_outb(p, sg_addr & 0xff, HADDR); - aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1); - aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2); - aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3); - aic_outb(p, sg_length & 0xff, HCNT); - aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1); - aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2); - aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR); - aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL); - while(aic_inb(p, SSTAT0) & SDONE) udelay(1); - while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL); - } - break; - -#ifdef AIC7XXX_NOT_YET - case TRACEPOINT2: - { - printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no, - channel, target, lun); - } - break; - - /* XXX Fill these in later */ - case MSG_BUFFER_BUSY: - printk("aic7xxx: Message buffer busy.\n"); - break; - case MSGIN_PHASEMIS: - printk("aic7xxx: Message-in phasemis.\n"); - break; -#endif - - default: /* unknown */ - printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n", - p->host_no, channel, target, lun, intstat, - aic_inb(p, SCSISIGI)); - break; - } - - /* - * Clear the sequencer interrupt and unpause the sequencer. - */ - unpause_sequencer(p, /* unpause always */ TRUE); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_parse_msg - * - * Description: - * Parses incoming messages into actions on behalf of - * aic7xxx_handle_reqinit - *_F*************************************************************************/ -static int -aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - int reject, reply, done; - unsigned char target_scsirate, tindex; - unsigned short target_mask; - unsigned char target, channel, lun; - unsigned char bus_width, new_bus_width; - unsigned char trans_options, new_trans_options; - unsigned int period, new_period, offset, new_offset, maxsync; - struct aic7xxx_syncrate *syncrate; - struct aic_dev_data *aic_dev; - - target = scb->cmd->device->id; - channel = scb->cmd->device->channel; - lun = scb->cmd->device->lun; - reply = reject = done = FALSE; - tindex = TARGET_INDEX(scb->cmd); - aic_dev = AIC_DEV(scb->cmd); - target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex); - target_mask = (0x01 << tindex); - - /* - * Parse as much of the message as is available, - * rejecting it if we don't support it. When - * the entire message is available and has been - * handled, return TRUE indicating that we have - * parsed an entire message. - */ - - if (p->msg_buf[0] != MSG_EXTENDED) - { - reject = TRUE; - } - - /* - * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when - * using the SDTR messages. We need the PPR messages to enable the - * higher speeds that include things like Dual Edge clocking. - */ - if (p->features & AHC_ULTRA2) - { - if ( (aic_inb(p, SBLKCTL) & ENAB40) && - !(aic_inb(p, SSTAT2) & EXP_ACTIVE) ) - { - if (p->features & AHC_ULTRA3) - maxsync = AHC_SYNCRATE_ULTRA3; - else - maxsync = AHC_SYNCRATE_ULTRA2; - } - else - { - maxsync = AHC_SYNCRATE_ULTRA; - } - } - else if (p->features & AHC_ULTRA) - { - maxsync = AHC_SYNCRATE_ULTRA; - } - else - { - maxsync = AHC_SYNCRATE_FAST; - } - - /* - * Just accept the length byte outright and perform - * more checking once we know the message type. - */ - - if ( !reject && (p->msg_len > 2) ) - { - switch(p->msg_buf[2]) - { - case MSG_EXT_SDTR: - { - - if (p->msg_buf[1] != MSG_EXT_SDTR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_SDTR_LEN + 2)) - { - break; - } - - period = new_period = p->msg_buf[3]; - offset = new_offset = p->msg_buf[4]; - trans_options = new_trans_options = 0; - bus_width = new_bus_width = target_scsirate & WIDEXFER; - - /* - * If our current max syncrate is in the Ultra3 range, bump it back - * down to Ultra2 since we can't negotiate DT transfers using SDTR - */ - if(maxsync == AHC_SYNCRATE_ULTRA3) - maxsync = AHC_SYNCRATE_ULTRA2; - - /* - * We might have a device that is starting negotiation with us - * before we can start up negotiation with it....be prepared to - * have a device ask for a higher speed then we want to give it - * in that case - */ - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) ) - { - if (!(aic_dev->flags & DEVICE_DTR_SCANNED)) - { - /* - * We shouldn't get here unless this is a narrow drive, wide - * devices should trigger this same section of code in the WDTR - * handler first instead. - */ - aic_dev->goal.width = MSG_EXT_WDTR_BUS_8_BIT; - aic_dev->goal.options = 0; - if(p->user[tindex].offset) - { - aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = max_t(unsigned char, 10,p->user[tindex].period); - if(p->features & AHC_ULTRA2) - { - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - } - else - { - aic_dev->goal.offset = MAX_OFFSET_8BIT; - } - } - else - { - aic_dev->needsdtr_copy = 0; - aic_dev->goal.period = 255; - aic_dev->goal.offset = 0; - } - aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; - } - else if (aic_dev->needsdtr_copy == 0) - { - /* - * This is a preemptive message from the target, we've already - * scanned this target and set our options for it, and we - * don't need a SDTR with this target (for whatever reason), - * so reject this incoming SDTR - */ - reject = TRUE; - break; - } - - /* The device is sending this message first and we have to reply */ - reply = TRUE; - - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive SDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - /* - * Validate the values the device passed to us against our SEEPROM - * settings. We don't have to do this if we aren't replying since - * the device isn't allowed to send values greater than the ones - * we first sent to it. - */ - new_period = max_t(unsigned int, period, aic_dev->goal.period); - new_offset = min_t(unsigned int, offset, aic_dev->goal.offset); - } - - /* - * Use our new_period, new_offset, bus_width, and card options - * to determine the actual syncrate settings - */ - syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, - &trans_options); - aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width); - - /* - * Did we drop to async? If so, send a reply regardless of whether - * or not we initiated this negotiation. - */ - if ((new_offset == 0) && (new_offset != offset)) - { - aic_dev->needsdtr_copy = 0; - reply = TRUE; - } - - /* - * Did we start this, if not, or if we went too low and had to - * go async, then send an SDTR back to the target - */ - if(reply) - { - /* when sending a reply, make sure that the goal settings are - * updated along with current and active since the code that - * will actually build the message for the sequencer uses the - * goal settings as its guidelines. - */ - aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, - new_offset, trans_options, - AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR, - aic_dev); - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_SDTR; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } - else - { - aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, - new_offset, trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev); - aic_dev->needsdtr = 0; - } - done = TRUE; - break; - } - case MSG_EXT_WDTR: - { - - if (p->msg_buf[1] != MSG_EXT_WDTR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_WDTR_LEN + 2)) - { - break; - } - - bus_width = new_bus_width = p->msg_buf[3]; - - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) == - (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) ) - { - switch(bus_width) - { - default: - { - reject = TRUE; - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((aic_dev->flags & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - aic_dev->goal.width = MSG_EXT_WDTR_BUS_8_BIT; - aic_dev->needwdtr_copy &= ~target_mask; - break; - } - case MSG_EXT_WDTR_BUS_16_BIT: - { - break; - } - } - aic_dev->needwdtr = 0; - aic7xxx_set_width(p, target, channel, lun, new_bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev); - } - else - { - if ( !(aic_dev->flags & DEVICE_DTR_SCANNED) ) - { - /* - * Well, we now know the WDTR and SYNC caps of this device since - * it contacted us first, mark it as such and copy the user stuff - * over to the goal stuff. - */ - if( (p->features & AHC_WIDE) && p->user[tindex].width ) - { - aic_dev->goal.width = MSG_EXT_WDTR_BUS_16_BIT; - aic_dev->needwdtr_copy = 1; - } - - /* - * Devices that support DT transfers don't start WDTR requests - */ - aic_dev->goal.options = 0; - - if(p->user[tindex].offset) - { - aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = max_t(unsigned char, 10, p->user[tindex].period); - if(p->features & AHC_ULTRA2) - { - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - } - else if( aic_dev->goal.width ) - { - aic_dev->goal.offset = MAX_OFFSET_16BIT; - } - else - { - aic_dev->goal.offset = MAX_OFFSET_8BIT; - } - } else { - aic_dev->needsdtr_copy = 0; - aic_dev->goal.period = 255; - aic_dev->goal.offset = 0; - } - - aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; - } - else if (aic_dev->needwdtr_copy == 0) - { - /* - * This is a preemptive message from the target, we've already - * scanned this target and set our options for it, and we - * don't need a WDTR with this target (for whatever reason), - * so reject this incoming WDTR - */ - reject = TRUE; - break; - } - - /* The device is sending this message first and we have to reply */ - reply = TRUE; - - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive WDTR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - switch(bus_width) - { - case MSG_EXT_WDTR_BUS_16_BIT: - { - if ( (p->features & AHC_WIDE) && - (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) ) - { - new_bus_width = MSG_EXT_WDTR_BUS_16_BIT; - break; - } - } /* Fall through if we aren't a wide card */ - default: - case MSG_EXT_WDTR_BUS_8_BIT: - { - aic_dev->needwdtr_copy = 0; - new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - } - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_WDTR; - aic_dev->needwdtr = 0; - if(aic_dev->dtr_pending == 0) - { - /* there is no other command with SCB_DTR_SCB already set that will - * trigger the release of the dtr_pending bit. Both set the bit - * and set scb->flags |= SCB_DTR_SCB - */ - aic_dev->dtr_pending = 1; - scb->flags |= SCB_DTR_SCB; - } - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - /* when sending a reply, make sure that the goal settings are - * updated along with current and active since the code that - * will actually build the message for the sequencer uses the - * goal settings as its guidelines. - */ - aic7xxx_set_width(p, target, channel, lun, new_bus_width, - AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR, - aic_dev); - } - - /* - * By virtue of the SCSI spec, a WDTR message negates any existing - * SDTR negotiations. So, even if needsdtr isn't marked for this - * device, we still have to do a new SDTR message if the device - * supports SDTR at all. Therefore, we check needsdtr_copy instead - * of needstr. - */ - aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE, - aic_dev); - aic_dev->needsdtr = aic_dev->needsdtr_copy; - done = TRUE; - break; - } - case MSG_EXT_PPR: - { - - if (p->msg_buf[1] != MSG_EXT_PPR_LEN) - { - reject = TRUE; - break; - } - - if (p->msg_len < (MSG_EXT_PPR_LEN + 2)) - { - break; - } - - period = new_period = p->msg_buf[3]; - offset = new_offset = p->msg_buf[5]; - bus_width = new_bus_width = p->msg_buf[6]; - trans_options = new_trans_options = p->msg_buf[7] & 0xf; - - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n", - p->host_no, CTL_OF_SCB(scb), period, offset, bus_width, - trans_options); - } - - /* - * We might have a device that is starting negotiation with us - * before we can start up negotiation with it....be prepared to - * have a device ask for a higher speed then we want to give it - * in that case - */ - if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) != - (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) ) - { - /* Have we scanned the device yet? */ - if (!(aic_dev->flags & DEVICE_DTR_SCANNED)) - { - /* The device is electing to use PPR messages, so we will too until - * we know better */ - aic_dev->needppr = aic_dev->needppr_copy = 1; - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - - /* We know the device is SCSI-3 compliant due to PPR */ - aic_dev->flags |= DEVICE_SCSI_3; - - /* - * Not only is the device starting this up, but it also hasn't - * been scanned yet, so this would likely be our TUR or our - * INQUIRY command at scan time, so we need to use the - * settings from the SEEPROM if they existed. Of course, even - * if we didn't find a SEEPROM, we stuffed default values into - * the user settings anyway, so use those in all cases. - */ - aic_dev->goal.width = p->user[tindex].width; - if(p->user[tindex].offset) - { - aic_dev->goal.period = p->user[tindex].period; - aic_dev->goal.options = p->user[tindex].options; - if(p->features & AHC_ULTRA2) - { - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - } - else if( aic_dev->goal.width && - (bus_width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE ) - { - aic_dev->goal.offset = MAX_OFFSET_16BIT; - } - else - { - aic_dev->goal.offset = MAX_OFFSET_8BIT; - } - } - else - { - aic_dev->goal.period = 255; - aic_dev->goal.offset = 0; - aic_dev->goal.options = 0; - } - aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR; - } - else if (aic_dev->needppr_copy == 0) - { - /* - * This is a preemptive message from the target, we've already - * scanned this target and set our options for it, and we - * don't need a PPR with this target (for whatever reason), - * so reject this incoming PPR - */ - reject = TRUE; - break; - } - - /* The device is sending this message first and we have to reply */ - reply = TRUE; - - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Received pre-emptive PPR message from " - "target.\n", p->host_no, CTL_OF_SCB(scb)); - } - - } - - switch(bus_width) - { - case MSG_EXT_WDTR_BUS_16_BIT: - { - if ( (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) && - p->features & AHC_WIDE) - { - break; - } - } - default: - { - if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && - ((aic_dev->flags & DEVICE_PRINT_DTR) || - (aic7xxx_verbose > 0xffff)) ) - { - reply = TRUE; - printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n", - p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width)); - } - } /* We fall through on purpose */ - case MSG_EXT_WDTR_BUS_8_BIT: - { - /* - * According to the spec, if we aren't wide, we also can't be - * Dual Edge so clear the options byte - */ - new_trans_options = 0; - new_bus_width = MSG_EXT_WDTR_BUS_8_BIT; - break; - } - } - - if(reply) - { - /* when sending a reply, make sure that the goal settings are - * updated along with current and active since the code that - * will actually build the message for the sequencer uses the - * goal settings as its guidelines. - */ - aic7xxx_set_width(p, target, channel, lun, new_bus_width, - AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR, - aic_dev); - syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, - new_offset, new_trans_options, - AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR, - aic_dev); - } - else - { - aic7xxx_set_width(p, target, channel, lun, new_bus_width, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev); - syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync, - &new_trans_options); - aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width); - aic7xxx_set_syncrate(p, syncrate, target, channel, new_period, - new_offset, new_trans_options, - AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev); - } - - /* - * As it turns out, if we don't *have* to have PPR messages, then - * configure ourselves not to use them since that makes some - * external drive chassis work (those chassis can't parse PPR - * messages and they mangle the SCSI bus until you send a WDTR - * and SDTR that they can understand). - */ - if(new_trans_options == 0) - { - aic_dev->needppr = aic_dev->needppr_copy = 0; - if(new_offset) - { - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - } - if (new_bus_width) - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - } - } - - if((new_offset == 0) && (offset != 0)) - { - /* - * Oops, the syncrate went to low for this card and we fell off - * to async (should never happen with a device that uses PPR - * messages, but have to be complete) - */ - reply = TRUE; - } - - if(reply) - { - scb->flags &= ~SCB_MSGOUT_BITS; - scb->flags |= SCB_MSGOUT_PPR; - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - } - else - { - aic_dev->needppr = 0; - } - done = TRUE; - break; - } - default: - { - reject = TRUE; - break; - } - } /* end of switch(p->msg_type) */ - } /* end of if (!reject && (p->msg_len > 2)) */ - - if (!reply && reject) - { - aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO); - done = TRUE; - } - return(done); -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_reqinit - * - * Description: - * Interrupt handler for REQINIT interrupts (used to transfer messages to - * and from devices). - *_F*************************************************************************/ -static void -aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb) -{ - unsigned char lastbyte; - unsigned char phasemis; - int done = FALSE; - - switch(p->msg_type) - { - case MSG_TYPE_INITIATOR_MSGOUT: - { - if (p->msg_len == 0) - panic("aic7xxx: REQINIT with no active message!\n"); - - lastbyte = (p->msg_index == (p->msg_len - 1)); - phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT; - - if (lastbyte || phasemis) - { - /* Time to end the message */ - p->msg_len = 0; - p->msg_type = MSG_TYPE_NONE; - /* - * NOTE-TO-MYSELF: If you clear the REQINIT after you - * disable REQINITs, then cases of REJECT_MSG stop working - * and hang the bus - */ - aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); - aic_outb(p, CLRSCSIINT, CLRINT); - p->flags &= ~AHC_HANDLING_REQINITS; - - if (phasemis == 0) - { - aic_outb(p, p->msg_buf[p->msg_index], SINDEX); - aic_outb(p, 0, RETURN_1); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Completed sending of REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); -#endif - } - else - { - aic_outb(p, MSGOUT_PHASEMIS, RETURN_1); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "PHASEMIS while sending REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); -#endif - } - unpause_sequencer(p, TRUE); - } - else - { - /* - * Present the byte on the bus (clearing REQINIT) but don't - * unpause the sequencer. - */ - aic_outb(p, CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - aic_outb(p, p->msg_buf[p->msg_index++], SCSIDATL); - } - break; - } - case MSG_TYPE_INITIATOR_MSGIN: - { - phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN; - - if (phasemis == 0) - { - p->msg_len++; - /* Pull the byte in without acking it */ - p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL); - done = aic7xxx_parse_msg(p, scb); - /* Ack the byte */ - aic_outb(p, CLRREQINIT, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - aic_inb(p, SCSIDATL); - p->msg_index++; - } - if (phasemis || done) - { -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - { - if (phasemis) - printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); - else - printk(INFO_LEAD "Completed receipt of REQINIT message.\n", - p->host_no, CTL_OF_SCB(scb)); - } -#endif - /* Time to end our message session */ - p->msg_len = 0; - p->msg_type = MSG_TYPE_NONE; - aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1); - aic_outb(p, CLRSCSIINT, CLRINT); - p->flags &= ~AHC_HANDLING_REQINITS; - unpause_sequencer(p, TRUE); - } - break; - } - default: - { - panic("aic7xxx: Unknown REQINIT message type.\n"); - break; - } - } /* End of switch(p->msg_type) */ -} - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_scsiint - * - * Description: - * Interrupt handler for SCSI interrupts (SCSIINT). - *-F*************************************************************************/ -static void -aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat) -{ - unsigned char scb_index; - unsigned char status; - struct aic7xxx_scb *scb; - struct aic_dev_data *aic_dev; - - scb_index = aic_inb(p, SCB_TAG); - status = aic_inb(p, SSTAT1); - - if (scb_index < p->scb_data->numscbs) - { - scb = p->scb_data->scb_array[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - { - scb = NULL; - } - } - else - { - scb = NULL; - } - - - if ((status & SCSIRSTI) != 0) - { - int channel; - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - - if (aic7xxx_verbose & VERBOSE_RESET) - printk(WARN_LEAD "Someone else reset the channel!!\n", - p->host_no, channel, -1, -1); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - /* - * Go through and abort all commands for the channel, but do not - * reset the channel again. - */ - aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - } - else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) ) - { - /* - * First look at what phase we were last in. If it's message-out, - * chances are pretty good that the bus free was in response to - * one of our abort requests. - */ - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned char saved_tcl = aic_inb(p, SAVED_TCL); - unsigned char target = (saved_tcl >> 4) & 0x0F; - int channel; - int printerror = TRUE; - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3; - else - channel = 0; - - aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), - SCSISEQ); - if (lastphase == P_MESGOUT) - { - unsigned char message; - - message = aic_inb(p, SINDEX); - - if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG)) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no, - CTL_OF_SCB(scb), scb->hscb->tag); - aic7xxx_reset_device(p, target, channel, ALL_LUNS, - (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag ); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - printerror = 0; - } - else if (message == MSG_BUS_DEV_RESET) - { - aic7xxx_handle_device_reset(p, target, channel); - scb = NULL; - printerror = 0; - } - } - if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) - { - /* - * Hmmm...error during a negotiation command. Either we have a - * borken bus, or the device doesn't like our negotiation message. - * Since we check the INQUIRY data of a device before sending it - * negotiation messages, assume the bus is borken for whatever - * reason. Complete the command. - */ - printerror = 0; - aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag); - aic7xxx_run_done_queue(p, TRUE); - scb = NULL; - } - if (printerror != 0) - { - if (scb != NULL) - { - unsigned char tag; - - if ((scb->hscb->control & TAG_ENB) != 0) - { - tag = scb->hscb->tag; - } - else - { - tag = SCB_LIST_NULL; - } - aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag); - aic7xxx_run_done_queue(p, TRUE); - } - else - { - aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL); - aic7xxx_run_done_queue(p, TRUE); - } - printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, " - "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase, - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - scb = NULL; - } - aic_outb(p, MSG_NOOP, MSG_OUT); - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT), - SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - aic_outb(p, CLRBUSFREE, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - restart_sequencer(p); - unpause_sequencer(p, TRUE); - } - else if ((status & SELTO) != 0) - { - unsigned char scbptr; - unsigned char nextscb; - struct scsi_cmnd *cmd; - - scbptr = aic_inb(p, WAITING_SCBH); - if (scbptr > p->scb_data->maxhscbs) - { - /* - * I'm still trying to track down exactly how this happens, but until - * I find it, this code will make sure we aren't passing bogus values - * into the SCBPTR register, even if that register will just wrap - * things around, we still don't like having out of range variables. - * - * NOTE: Don't check the aic7xxx_verbose variable, I want this message - * to always be displayed. - */ - printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.\n", - p->host_no, -1, -1, -1, scbptr); - if (p->scb_data->maxhscbs > 4) - scbptr &= (p->scb_data->maxhscbs - 1); - else - scbptr &= 0x03; - } - aic_outb(p, scbptr, SCBPTR); - scb_index = aic_inb(p, SCB_TAG); - - scb = NULL; - if (scb_index < p->scb_data->numscbs) - { - scb = p->scb_data->scb_array[scb_index]; - if ((scb->flags & SCB_ACTIVE) == 0) - { - scb = NULL; - } - } - if (scb == NULL) - { - printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n", - p->host_no, -1, -1, -1, scb_index); - printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x " - "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); - } - else - { - cmd = scb->cmd; - cmd->result = (DID_TIME_OUT << 16); - - /* - * Clear out this hardware SCB - */ - aic_outb(p, 0, SCB_CONTROL); - - /* - * Clear out a few values in the card that are in an undetermined - * state. - */ - aic_outb(p, MSG_NOOP, MSG_OUT); - - /* - * Shift the waiting for selection queue forward - */ - nextscb = aic_inb(p, SCB_NEXT); - aic_outb(p, nextscb, WAITING_SCBH); - - /* - * Put this SCB back on the free list. - */ - aic7xxx_add_curscb_to_free_list(p); -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb)); -#endif - if (scb->flags & SCB_QUEUED_ABORT) - { - /* - * We know that this particular SCB had to be the queued abort since - * the disconnected SCB would have gotten a reconnect instead. - * What we need to do then is to let the command timeout again so - * we get a reset since this abort just failed. - */ - cmd->result = 0; - scb = NULL; - } - } - /* - * Keep the sequencer from trying to restart any selections - */ - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - /* - * Make sure the data bits on the bus are released - * Don't do this on 7770 chipsets, it makes them give us - * a BRKADDRINT and kills the card. - */ - if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) - aic_outb(p, 0, SCSIBUSL); - - /* - * Delay for the selection timeout delay period then stop the selection - */ - udelay(301); - aic_outb(p, CLRSELINGO, CLRSINT0); - /* - * Clear out all the interrupt status bits - */ - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1); - p->flags &= ~AHC_HANDLING_REQINITS; - aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - /* - * Restarting the sequencer will stop the selection and make sure devices - * are allowed to reselect in. - */ - restart_sequencer(p); - unpause_sequencer(p, TRUE); - } - else if (scb == NULL) - { - printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid " - "during scsiint 0x%x scb(%d)\n" - " SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n", - p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0), - aic_inb(p, SIMODE1), aic_inb(p, SSTAT0), - (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0)); - /* - * Turn off the interrupt and set status to zero, so that it - * falls through the rest of the SCSIINT code. - */ - aic_outb(p, status, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause always */ TRUE); - scb = NULL; - } - else if (status & SCSIPERR) - { - /* - * Determine the bus phase and queue an appropriate message. - */ - char *phase; - struct scsi_cmnd *cmd; - unsigned char mesg_out = MSG_NOOP; - unsigned char lastphase = aic_inb(p, LASTPHASE); - unsigned char sstat2 = aic_inb(p, SSTAT2); - - cmd = scb->cmd; - switch (lastphase) - { - case P_DATAOUT: - phase = "Data-Out"; - break; - case P_DATAIN: - phase = "Data-In"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_COMMAND: - phase = "Command"; - break; - case P_MESGOUT: - phase = "Message-Out"; - break; - case P_STATUS: - phase = "Status"; - mesg_out = MSG_INITIATOR_DET_ERR; - break; - case P_MESGIN: - phase = "Message-In"; - mesg_out = MSG_PARITY_ERROR; - break; - default: - phase = "unknown"; - break; - } - - /* - * A parity error has occurred during a data - * transfer phase. Flag it and continue. - */ - if( (p->features & AHC_ULTRA3) && - (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) && - (lastphase == P_DATAIN) ) - { - printk(WARN_LEAD "CRC error during %s phase.\n", - p->host_no, CTL_OF_SCB(scb), phase); - if(sstat2 & CRCVALERR) - { - printk(WARN_LEAD " CRC error in intermediate CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & CRCENDERR) - { - printk(WARN_LEAD " CRC error in ending CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & CRCREQERR) - { - printk(WARN_LEAD " Target incorrectly requested a CRC packet.\n", - p->host_no, CTL_OF_SCB(scb)); - } - if(sstat2 & DUAL_EDGE_ERROR) - { - printk(WARN_LEAD " Dual Edge transmission error.\n", - p->host_no, CTL_OF_SCB(scb)); - } - } - else if( (lastphase == P_MESGOUT) && - (scb->flags & SCB_MSGOUT_PPR) ) - { - /* - * As per the draft specs, any device capable of supporting any of - * the option values other than 0 are not allowed to reject the - * PPR message. Instead, they must negotiate out what they do - * support instead of rejecting our offering or else they cause - * a parity error during msg_out phase to signal that they don't - * like our settings. - */ - aic_dev = AIC_DEV(scb->cmd); - aic_dev->needppr = aic_dev->needppr_copy = 0; - aic7xxx_set_width(p, scb->cmd->device->id, scb->cmd->device->channel, scb->cmd->device->lun, - MSG_EXT_WDTR_BUS_8_BIT, - (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE), - aic_dev); - aic7xxx_set_syncrate(p, NULL, scb->cmd->device->id, scb->cmd->device->channel, 0, 0, - 0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE, - aic_dev); - aic_dev->goal.options = 0; - scb->flags &= ~SCB_MSGOUT_BITS; - if(aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "parity error during PPR message, reverting " - "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb)); - } - if ( aic_dev->goal.width ) - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - } - if ( aic_dev->goal.offset ) - { - if( aic_dev->goal.period <= 9 ) - { - aic_dev->goal.period = 10; - } - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - } - scb = NULL; - } - - /* - * We've set the hardware to assert ATN if we get a parity - * error on "in" phases, so all we need to do is stuff the - * message buffer with the appropriate message. "In" phases - * have set mesg_out to something other than MSG_NOP. - */ - if (mesg_out != MSG_NOOP) - { - aic_outb(p, mesg_out, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - scb = NULL; - } - aic_outb(p, CLRSCSIPERR, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause_always */ TRUE); - } - else if ( (status & REQINIT) && - (p->flags & AHC_HANDLING_REQINITS) ) - { -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic7xxx_verbose > 0xffff) - printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.\n", p->host_no, - CTL_OF_SCB(scb), aic_inb(p, SSTAT1)); -#endif - aic7xxx_handle_reqinit(p, scb); - return; - } - else - { - /* - * We don't know what's going on. Turn off the - * interrupt source and try to continue. - */ - if (aic7xxx_verbose & VERBOSE_SCSIINT) - printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n", - p->host_no, -1, -1, -1, status); - aic_outb(p, status, CLRSINT1); - aic_outb(p, CLRSCSIINT, CLRINT); - unpause_sequencer(p, /* unpause always */ TRUE); - scb = NULL; - } - if (scb != NULL) - { - aic7xxx_done(p, scb); - } -} - -#ifdef AIC7XXX_VERBOSE_DEBUGGING -static void -aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer) -{ - unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp; - int i, bogus, lost; - static unsigned char scb_status[AIC7XXX_MAXSCB]; - -#define SCB_NO_LIST 0 -#define SCB_FREE_LIST 1 -#define SCB_WAITING_LIST 2 -#define SCB_DISCONNECTED_LIST 4 -#define SCB_CURRENTLY_ACTIVE 8 - - /* - * Note, these checks will fail on a regular basis once the machine moves - * beyond the bus scan phase. The problem is race conditions concerning - * the scbs and where they are linked in. When you have 30 or so commands - * outstanding on the bus, and run this twice with every interrupt, the - * chances get pretty good that you'll catch the sequencer with an SCB - * only partially linked in. Therefore, once we pass the scan phase - * of the bus, we really should disable this function. - */ - bogus = FALSE; - memset(&scb_status[0], 0, sizeof(scb_status)); - pause_sequencer(p); - saved_scbptr = aic_inb(p, SCBPTR); - if (saved_scbptr >= p->scb_data->maxhscbs) - { - printk("Bogus SCBPTR %d\n", saved_scbptr); - bogus = TRUE; - } - scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE; - free_scbh = aic_inb(p, FREE_SCBH); - if ( (free_scbh != SCB_LIST_NULL) && - (free_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus FREE_SCBH %d\n", free_scbh); - bogus = TRUE; - } - else - { - temp = free_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_FREE_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_FREE_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - dis_scbh = aic_inb(p, DISCONNECTED_SCBH); - if ( (dis_scbh != SCB_LIST_NULL) && - (dis_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus DISCONNECTED_SCBH %d\n", dis_scbh); - bogus = TRUE; - } - else - { - temp = dis_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_DISCONNECTED_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_DISCONNECTED_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - wait_scbh = aic_inb(p, WAITING_SCBH); - if ( (wait_scbh != SCB_LIST_NULL) && - (wait_scbh >= p->scb_data->maxhscbs) ) - { - printk("Bogus WAITING_SCBH %d\n", wait_scbh); - bogus = TRUE; - } - else - { - temp = wait_scbh; - while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) ) - { - if(scb_status[temp] & 0x07) - { - printk("HSCB %d on multiple lists, status 0x%02x", temp, - scb_status[temp] | SCB_WAITING_LIST); - bogus = TRUE; - } - scb_status[temp] |= SCB_WAITING_LIST; - aic_outb(p, temp, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - } - } - - lost=0; - for(i=0; i < p->scb_data->maxhscbs; i++) - { - aic_outb(p, i, SCBPTR); - temp = aic_inb(p, SCB_NEXT); - if ( ((temp != SCB_LIST_NULL) && - (temp >= p->scb_data->maxhscbs)) ) - { - printk("HSCB %d bad, SCB_NEXT invalid(%d).\n", i, temp); - bogus = TRUE; - } - if ( temp == i ) - { - printk("HSCB %d bad, SCB_NEXT points to self.\n", i); - bogus = TRUE; - } - if (scb_status[i] == 0) - lost++; - if (lost > 1) - { - printk("Too many lost scbs.\n"); - bogus=TRUE; - } - } - aic_outb(p, saved_scbptr, SCBPTR); - unpause_sequencer(p, FALSE); - if (bogus) - { - printk("Bogus parameters found in card SCB array structures.\n"); - printk("%s\n", buffer); - aic7xxx_panic_abort(p, NULL); - } - return; -} -#endif - - -/*+F************************************************************************* - * Function: - * aic7xxx_handle_command_completion_intr - * - * Description: - * SCSI command completion interrupt handler. - *-F*************************************************************************/ -static void -aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p) -{ - struct aic7xxx_scb *scb = NULL; - struct aic_dev_data *aic_dev; - struct scsi_cmnd *cmd; - unsigned char scb_index, tindex; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) ) - printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1); -#endif - - /* - * Read the INTSTAT location after clearing the CMDINT bit. This forces - * any posted PCI writes to flush to memory. Gerard Roudier suggested - * this fix to the possible race of clearing the CMDINT bit but not - * having all command bytes flushed onto the qoutfifo. - */ - aic_outb(p, CLRCMDINT, CLRINT); - aic_inb(p, INTSTAT); - /* - * The sequencer will continue running when it - * issues this interrupt. There may be >1 commands - * finished, so loop until we've processed them all. - */ - - while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL) - { - scb_index = p->qoutfifo[p->qoutfifonext]; - p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL; - if ( scb_index >= p->scb_data->numscbs ) - { - printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no, - -1, -1, -1, scb_index); - continue; - } - scb = p->scb_data->scb_array[scb_index]; - if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL)) - { - printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags " - "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags, - (unsigned long) scb->cmd); - continue; - } - tindex = TARGET_INDEX(scb->cmd); - aic_dev = AIC_DEV(scb->cmd); - if (scb->flags & SCB_QUEUED_ABORT) - { - pause_sequencer(p); - if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) && - (aic_inb(p, SCB_TAG) == scb->hscb->tag) ) - { - unpause_sequencer(p, FALSE); - continue; - } - aic7xxx_reset_device(p, scb->cmd->device->id, scb->cmd->device->channel, - scb->cmd->device->lun, scb->hscb->tag); - scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT | - SCB_QUEUED_ABORT); - unpause_sequencer(p, FALSE); - } - else if (scb->flags & SCB_ABORT) - { - /* - * We started to abort this, but it completed on us, let it - * through as successful - */ - scb->flags &= ~(SCB_ABORT|SCB_RESET); - } - else if (scb->flags & SCB_SENSE) - { - char *buffer = &scb->cmd->sense_buffer[0]; - - if (buffer[12] == 0x47 || buffer[12] == 0x54) - { - /* - * Signal that we need to re-negotiate things. - */ - aic_dev->needppr = aic_dev->needppr_copy; - aic_dev->needsdtr = aic_dev->needsdtr_copy; - aic_dev->needwdtr = aic_dev->needwdtr_copy; - } - } - cmd = scb->cmd; - if (scb->hscb->residual_SG_segment_count != 0) - { - aic7xxx_calculate_residual(p, scb); - } - cmd->result |= (aic7xxx_error(cmd) << 16); - aic7xxx_done(p, scb); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_isr - * - * Description: - * SCSI controller interrupt handler. - *-F*************************************************************************/ -static void -aic7xxx_isr(void *dev_id) -{ - struct aic7xxx_host *p; - unsigned char intstat; - - p = dev_id; - - /* - * Just a few sanity checks. Make sure that we have an int pending. - * Also, if PCI, then we are going to check for a PCI bus error status - * should we get too many spurious interrupts. - */ - if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND)) - { -#ifdef CONFIG_PCI - if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) && - !(p->flags & AHC_HANDLING_REQINITS) ) - { - if ( aic_inb(p, ERROR) & PCIERRSTAT ) - { - aic7xxx_pci_intr(p); - } - p->spurious_int = 0; - } - else if ( !(p->flags & AHC_HANDLING_REQINITS) ) - { - p->spurious_int++; - } -#endif - return; - } - - p->spurious_int = 0; - - /* - * Keep track of interrupts for /proc/scsi - */ - p->isr_count++; - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) && - (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) ) - aic7xxx_check_scbs(p, "Bogus settings at start of interrupt."); -#endif - - /* - * Handle all the interrupt sources - especially for SCSI - * interrupts, we won't get a second chance at them. - */ - if (intstat & CMDCMPLT) - { - aic7xxx_handle_command_completion_intr(p); - } - - if (intstat & BRKADRINT) - { - int i; - unsigned char errno = aic_inb(p, ERROR); - - printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno); - for (i = 0; i < ARRAY_SIZE(hard_error); i++) - { - if (errno & hard_error[i].errno) - { - printk(KERN_ERR " %s\n", hard_error[i].errmesg); - } - } - printk(KERN_ERR "(scsi%d) SEQADDR=0x%x\n", p->host_no, - (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0))); - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, NULL); -#ifdef CONFIG_PCI - if (errno & PCIERRSTAT) - aic7xxx_pci_intr(p); -#endif - if (errno & (SQPARERR | ILLOPCODE | ILLSADDR)) - { - panic("aic7xxx: unrecoverable BRKADRINT.\n"); - } - if (errno & ILLHADDR) - { - printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first " - "pausing controller!\n", p->host_no); - } -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (errno & DPARERR) - { - if (aic_inb(p, DMAPARAMS) & DIRECTION) - printk("(scsi%d) while DMAing SCB from host to card.\n", p->host_no); - else - printk("(scsi%d) while DMAing SCB from card to host.\n", p->host_no); - } -#endif - aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT); - unpause_sequencer(p, FALSE); - } - - if (intstat & SEQINT) - { - /* - * Read the CCSCBCTL register to work around a bug in the Ultra2 cards - */ - if(p->features & AHC_ULTRA2) - { - aic_inb(p, CCSCBCTL); - } - aic7xxx_handle_seqint(p, intstat); - } - - if (intstat & SCSIINT) - { - aic7xxx_handle_scsiint(p, intstat); - } - -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) && - (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) ) - aic7xxx_check_scbs(p, "Bogus settings at end of interrupt."); -#endif - -} - -/*+F************************************************************************* - * Function: - * do_aic7xxx_isr - * - * Description: - * This is a gross hack to solve a problem in linux kernels 2.1.85 and - * above. Please, children, do not try this at home, and if you ever see - * anything like it, please inform the Gross Hack Police immediately - *-F*************************************************************************/ -static irqreturn_t -do_aic7xxx_isr(int irq, void *dev_id) -{ - unsigned long cpu_flags; - struct aic7xxx_host *p; - - p = dev_id; - if(!p) - return IRQ_NONE; - spin_lock_irqsave(p->host->host_lock, cpu_flags); - p->flags |= AHC_IN_ISR; - do - { - aic7xxx_isr(dev_id); - } while ( (aic_inb(p, INTSTAT) & INT_PEND) ); - aic7xxx_done_cmds_complete(p); - aic7xxx_run_waiting_queues(p); - p->flags &= ~AHC_IN_ISR; - spin_unlock_irqrestore(p->host->host_lock, cpu_flags); - - return IRQ_HANDLED; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_init_transinfo - * - * Description: - * Set up the initial aic_dev values from the BIOS settings and from - * INQUIRY results - *-F*************************************************************************/ -static void -aic7xxx_init_transinfo(struct aic7xxx_host *p, struct aic_dev_data *aic_dev) -{ - struct scsi_device *sdpnt = aic_dev->SDptr; - unsigned char tindex; - - tindex = sdpnt->id | (sdpnt->channel << 3); - if (!(aic_dev->flags & DEVICE_DTR_SCANNED)) - { - aic_dev->flags |= DEVICE_DTR_SCANNED; - - if ( sdpnt->wdtr && (p->features & AHC_WIDE) ) - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 1; - aic_dev->goal.width = p->user[tindex].width; - } - else - { - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - pause_sequencer(p); - aic7xxx_set_width(p, sdpnt->id, sdpnt->channel, sdpnt->lun, - MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE | - AHC_TRANS_GOAL | - AHC_TRANS_CUR), aic_dev ); - unpause_sequencer(p, FALSE); - } - if ( sdpnt->sdtr && p->user[tindex].offset ) - { - aic_dev->goal.period = p->user[tindex].period; - aic_dev->goal.options = p->user[tindex].options; - if (p->features & AHC_ULTRA2) - aic_dev->goal.offset = MAX_OFFSET_ULTRA2; - else if (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) - aic_dev->goal.offset = MAX_OFFSET_16BIT; - else - aic_dev->goal.offset = MAX_OFFSET_8BIT; - if ( sdpnt->ppr && p->user[tindex].period <= 9 && - p->user[tindex].options ) - { - aic_dev->needppr = aic_dev->needppr_copy = 1; - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - aic_dev->needwdtr = aic_dev->needwdtr_copy = 0; - aic_dev->flags |= DEVICE_SCSI_3; - } - else - { - aic_dev->needsdtr = aic_dev->needsdtr_copy = 1; - aic_dev->goal.period = max_t(unsigned char, 10, aic_dev->goal.period); - aic_dev->goal.options = 0; - } - } - else - { - aic_dev->needsdtr = aic_dev->needsdtr_copy = 0; - aic_dev->goal.period = 255; - aic_dev->goal.offset = 0; - aic_dev->goal.options = 0; - } - aic_dev->flags |= DEVICE_PRINT_DTR; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_slave_alloc - * - * Description: - * Set up the initial aic_dev struct pointers - *-F*************************************************************************/ -static int -aic7xxx_slave_alloc(struct scsi_device *SDptr) -{ - struct aic7xxx_host *p = (struct aic7xxx_host *)SDptr->host->hostdata; - struct aic_dev_data *aic_dev; - - aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_KERNEL); - if(!aic_dev) - return 1; - /* - * Check to see if channel was scanned. - */ - - if (!(p->flags & AHC_A_SCANNED) && (SDptr->channel == 0)) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(INFO_LEAD "Scanning channel for devices.\n", - p->host_no, 0, -1, -1); - p->flags |= AHC_A_SCANNED; - } - else - { - if (!(p->flags & AHC_B_SCANNED) && (SDptr->channel == 1)) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(INFO_LEAD "Scanning channel for devices.\n", - p->host_no, 1, -1, -1); - p->flags |= AHC_B_SCANNED; - } - } - - memset(aic_dev, 0, sizeof(struct aic_dev_data)); - SDptr->hostdata = aic_dev; - aic_dev->SDptr = SDptr; - aic_dev->max_q_depth = 1; - aic_dev->temp_q_depth = 1; - scbq_init(&aic_dev->delayed_scbs); - INIT_LIST_HEAD(&aic_dev->list); - list_add_tail(&aic_dev->list, &p->aic_devs); - return 0; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_device_queue_depth - * - * Description: - * Determines the queue depth for a given device. There are two ways - * a queue depth can be obtained for a tagged queueing device. One - * way is the default queue depth which is determined by whether - * aic7xxx_default_queue_depth. The other is by the aic7xxx_tag_info - * array. - * - * If tagged queueing isn't supported on the device, then we set the - * depth to p->host->hostt->cmd_per_lun for internal driver queueing. - * as the default queue depth. Otherwise, we use either 4 or 8 as the - * default queue depth (dependent on the number of hardware SCBs). - * The other way we determine queue depth is through the use of the - * aic7xxx_tag_info array which is enabled by defining - * AIC7XXX_TAGGED_QUEUEING_BY_DEVICE. This array can be initialized - * with queue depths for individual devices. It also allows tagged - * queueing to be [en|dis]abled for a specific adapter. - *-F*************************************************************************/ -static void -aic7xxx_device_queue_depth(struct aic7xxx_host *p, struct scsi_device *device) -{ - int tag_enabled = FALSE; - struct aic_dev_data *aic_dev = device->hostdata; - unsigned char tindex; - - tindex = device->id | (device->channel << 3); - - if (device->simple_tags) - return; // We've already enabled this device - - if (device->tagged_supported) - { - tag_enabled = TRUE; - - if (!(p->discenable & (1 << tindex))) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - printk(INFO_LEAD "Disconnection disabled, unable to " - "enable tagged queueing.\n", - p->host_no, device->channel, device->id, device->lun); - tag_enabled = FALSE; - } - else - { - if (p->instance >= ARRAY_SIZE(aic7xxx_tag_info)) - { - static int print_warning = TRUE; - if(print_warning) - { - printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for" - " installed controllers.\n"); - printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in" - " the aic7xxx.c source file.\n"); - print_warning = FALSE; - } - aic_dev->max_q_depth = aic_dev->temp_q_depth = - aic7xxx_default_queue_depth; - } - else - { - - if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255) - { - tag_enabled = FALSE; - } - else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0) - { - aic_dev->max_q_depth = aic_dev->temp_q_depth = - aic7xxx_default_queue_depth; - } - else - { - aic_dev->max_q_depth = aic_dev->temp_q_depth = - aic7xxx_tag_info[p->instance].tag_commands[tindex]; - } - } - } - } - if (tag_enabled) - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Tagged queuing enabled, queue depth %d.\n", - p->host_no, device->channel, device->id, - device->lun, aic_dev->max_q_depth); - } - scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, aic_dev->max_q_depth); - } - else - { - if (aic7xxx_verbose & VERBOSE_NEGOTIATION2) - { - printk(INFO_LEAD "Tagged queuing disabled, queue depth %d.\n", - p->host_no, device->channel, device->id, - device->lun, device->host->cmd_per_lun); - } - scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun); - } - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_slave_destroy - * - * Description: - * prepare for this device to go away - *-F*************************************************************************/ -static void -aic7xxx_slave_destroy(struct scsi_device *SDptr) -{ - struct aic_dev_data *aic_dev = SDptr->hostdata; - - list_del(&aic_dev->list); - SDptr->hostdata = NULL; - kfree(aic_dev); - return; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_slave_configure - * - * Description: - * Configure the device we are attaching to the controller. This is - * where we get to do things like scan the INQUIRY data, set queue - * depths, allocate command structs, etc. - *-F*************************************************************************/ -static int -aic7xxx_slave_configure(struct scsi_device *SDptr) -{ - struct aic7xxx_host *p = (struct aic7xxx_host *) SDptr->host->hostdata; - struct aic_dev_data *aic_dev; - int scbnum; - - aic_dev = (struct aic_dev_data *)SDptr->hostdata; - - aic7xxx_init_transinfo(p, aic_dev); - aic7xxx_device_queue_depth(p, SDptr); - if(list_empty(&aic_dev->list)) - list_add_tail(&aic_dev->list, &p->aic_devs); - - scbnum = 0; - list_for_each_entry(aic_dev, &p->aic_devs, list) { - scbnum += aic_dev->max_q_depth; - } - while (scbnum > p->scb_data->numscbs) - { - /* - * Pre-allocate the needed SCBs to get around the possibility of having - * to allocate some when memory is more or less exhausted and we need - * the SCB in order to perform a swap operation (possible deadlock) - */ - if ( aic7xxx_allocate_scb(p) == 0 ) - break; - } - - - return(0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_probe - * - * Description: - * Probing for EISA boards: it looks like the first two bytes - * are a manufacturer code - three characters, five bits each: - * - * BYTE 0 BYTE 1 BYTE 2 BYTE 3 - * ?1111122 22233333 PPPPPPPP RRRRRRRR - * - * The characters are baselined off ASCII '@', so add that value - * to each to get the real ASCII code for it. The next two bytes - * appear to be a product and revision number, probably vendor- - * specific. This is what is being searched for at each port, - * and what should probably correspond to the ID= field in the - * ECU's .cfg file for the card - if your card is not detected, - * make sure your signature is listed in the array. - * - * The fourth byte's lowest bit seems to be an enabled/disabled - * flag (rest of the bits are reserved?). - * - * NOTE: This function is only needed on Intel and Alpha platforms, - * the other platforms we support don't have EISA/VLB busses. So, - * we #ifdef this entire function to avoid compiler warnings about - * an unused function. - *-F*************************************************************************/ -#if defined(__i386__) || defined(__alpha__) -static int -aic7xxx_probe(int slot, int base, ahc_flag_type *flags) -{ - int i; - unsigned char buf[4]; - - static struct { - int n; - unsigned char signature[sizeof(buf)]; - ahc_chip type; - int bios_disabled; - } AIC7xxx[] = { - { 4, { 0x04, 0x90, 0x77, 0x70 }, - AHC_AIC7770|AHC_EISA, FALSE }, /* mb 7770 */ - { 4, { 0x04, 0x90, 0x77, 0x71 }, - AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */ - { 4, { 0x04, 0x90, 0x77, 0x56 }, - AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */ - { 4, { 0x04, 0x90, 0x77, 0x57 }, - AHC_AIC7770|AHC_VL, TRUE } /* 284x BIOS disabled */ - }; - - /* - * The VL-bus cards need to be primed by - * writing before a signature check. - */ - for (i = 0; i < sizeof(buf); i++) - { - outb(0x80 + i, base); - buf[i] = inb(base + i); - } - - for (i = 0; i < ARRAY_SIZE(AIC7xxx); i++) - { - /* - * Signature match on enabled card? - */ - if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n)) - { - if (inb(base + 4) & 1) - { - if (AIC7xxx[i].bios_disabled) - { - *flags |= AHC_USEDEFAULTS; - } - else - { - *flags |= AHC_BIOS_ENABLED; - } - return (i); - } - - printk("aic7xxx: " - "disabled at slot %d, ignored.\n", slot); - } - } - - return (-1); -} -#endif /* (__i386__) || (__alpha__) */ - - -/*+F************************************************************************* - * Function: - * read_2840_seeprom - * - * Description: - * Reads the 2840 serial EEPROM and returns 1 if successful and 0 if - * not successful. - * - * See read_seeprom (for the 2940) for the instruction set of the 93C46 - * chip. - * - * The 2840 interface to the 93C46 serial EEPROM is through the - * STATUS_2840 and SEECTL_2840 registers. The CS_2840, CK_2840, and - * DO_2840 bits of the SEECTL_2840 register are connected to the chip - * select, clock, and data out lines respectively of the serial EEPROM. - * The DI_2840 bit of the STATUS_2840 is connected to the data in line - * of the serial EEPROM. The EEPROM_TF bit of STATUS_2840 register is - * useful in that it gives us an 800 nsec timer. After a read from the - * SEECTL_2840 register the timing flag is cleared and goes high 800 nsec - * later. - *-F*************************************************************************/ -static int -read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc) -{ - int i = 0, k = 0; - unsigned char temp; - unsigned short checksum = 0; - unsigned short *seeprom = (unsigned short *) sc; - struct seeprom_cmd { - unsigned char len; - unsigned char bits[3]; - }; - struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; - -#define CLOCK_PULSE(p) \ - while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0) \ - { \ - ; /* Do nothing */ \ - } \ - (void) aic_inb(p, SEECTL_2840); - - /* - * Read the first 32 registers of the seeprom. For the 2840, - * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers - * but only the first 32 are used by Adaptec BIOS. The loop - * will range from 0 to 31. - */ - for (k = 0; k < (sizeof(*sc) / 2); k++) - { - /* - * Send chip select for one clock cycle. - */ - aic_outb(p, CK_2840 | CS_2840, SEECTL_2840); - CLOCK_PULSE(p); - - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - for (i = 0; i < seeprom_read.len; i++) - { - temp = CS_2840 | seeprom_read.bits[i]; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - /* - * Send the 6 bit address (MSB first, LSB last). - */ - for (i = 5; i >= 0; i--) - { - temp = k; - temp = (temp >> i) & 1; /* Mask out all but lower bit. */ - temp = CS_2840 | temp; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - for (i = 0; i <= 16; i++) - { - temp = CS_2840; - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - temp = temp ^ CK_2840; - seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840); - aic_outb(p, temp, SEECTL_2840); - CLOCK_PULSE(p); - } - /* - * The serial EEPROM has a checksum in the last word. Keep a - * running checksum for all words read except for the last - * word. We'll verify the checksum after all words have been - * read. - */ - if (k < (sizeof(*sc) / 2) - 1) - { - checksum = checksum + seeprom[k]; - } - - /* - * Reset the chip select for the next command cycle. - */ - aic_outb(p, 0, SEECTL_2840); - CLOCK_PULSE(p); - aic_outb(p, CK_2840, SEECTL_2840); - CLOCK_PULSE(p); - aic_outb(p, 0, SEECTL_2840); - CLOCK_PULSE(p); - } - -#if 0 - printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum); - printk("Serial EEPROM:"); - for (k = 0; k < (sizeof(*sc) / 2); k++) - { - if (((k % 8) == 0) && (k != 0)) - { - printk("\n "); - } - printk(" 0x%x", seeprom[k]); - } - printk("\n"); -#endif - - if (checksum != sc->checksum) - { - printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n"); - return (0); - } - - return (1); -#undef CLOCK_PULSE -} - -#define CLOCK_PULSE(p) \ - do { \ - int limit = 0; \ - do { \ - mb(); \ - pause_sequencer(p); /* This is just to generate some PCI */ \ - /* traffic so the PCI read is flushed */ \ - /* it shouldn't be needed, but some */ \ - /* chipsets do indeed appear to need */ \ - /* something to force PCI reads to get */ \ - /* flushed */ \ - udelay(1); /* Do nothing */ \ - } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \ - } while(0) - -/*+F************************************************************************* - * Function: - * acquire_seeprom - * - * Description: - * Acquires access to the memory port on PCI controllers. - *-F*************************************************************************/ -static int -acquire_seeprom(struct aic7xxx_host *p) -{ - - /* - * Request access of the memory port. When access is - * granted, SEERDY will go high. We use a 1 second - * timeout which should be near 1 second more than - * is needed. Reason: after the 7870 chip reset, there - * should be no contention. - */ - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - if ((aic_inb(p, SEECTL) & SEERDY) == 0) - { - aic_outb(p, 0, SEECTL); - return (0); - } - return (1); -} - -/*+F************************************************************************* - * Function: - * release_seeprom - * - * Description: - * Releases access to the memory port on PCI controllers. - *-F*************************************************************************/ -static void -release_seeprom(struct aic7xxx_host *p) -{ - /* - * Make sure the SEEPROM is ready before we release it. - */ - CLOCK_PULSE(p); - aic_outb(p, 0, SEECTL); -} - -/*+F************************************************************************* - * Function: - * read_seeprom - * - * Description: - * Reads the serial EEPROM and returns 1 if successful and 0 if - * not successful. - * - * The instruction set of the 93C46/56/66 chips is as follows: - * - * Start OP - * Function Bit Code Address Data Description - * ------------------------------------------------------------------- - * READ 1 10 A5 - A0 Reads data stored in memory, - * starting at specified address - * EWEN 1 00 11XXXX Write enable must precede - * all programming modes - * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0 - * WRITE 1 01 A5 - A0 D15 - D0 Writes register - * ERAL 1 00 10XXXX Erase all registers - * WRAL 1 00 01XXXX D15 - D0 Writes to all registers - * EWDS 1 00 00XXXX Disables all programming - * instructions - * *Note: A value of X for address is a don't care condition. - * *Note: The 93C56 and 93C66 have 8 address bits. - * - * - * The 93C46 has a four wire interface: clock, chip select, data in, and - * data out. In order to perform one of the above functions, you need - * to enable the chip select for a clock period (typically a minimum of - * 1 usec, with the clock high and low a minimum of 750 and 250 nsec - * respectively. While the chip select remains high, you can clock in - * the instructions (above) starting with the start bit, followed by the - * OP code, Address, and Data (if needed). For the READ instruction, the - * requested 16-bit register contents is read from the data out line but - * is preceded by an initial zero (leading 0, followed by 16-bits, MSB - * first). The clock cycling from low to high initiates the next data - * bit to be sent from the chip. - * - * The 78xx interface to the 93C46 serial EEPROM is through the SEECTL - * register. After successful arbitration for the memory port, the - * SEECS bit of the SEECTL register is connected to the chip select. - * The SEECK, SEEDO, and SEEDI are connected to the clock, data out, - * and data in lines respectively. The SEERDY bit of SEECTL is useful - * in that it gives us an 800 nsec timer. After a write to the SEECTL - * register, the SEERDY goes high 800 nsec later. The one exception - * to this is when we first request access to the memory port. The - * SEERDY goes high to signify that access has been granted and, for - * this case, has no implied timing. - *-F*************************************************************************/ -static int -read_seeprom(struct aic7xxx_host *p, int offset, - unsigned short *scarray, unsigned int len, seeprom_chip_type chip) -{ - int i = 0, k; - unsigned char temp; - unsigned short checksum = 0; - struct seeprom_cmd { - unsigned char len; - unsigned char bits[3]; - }; - struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; - - /* - * Request access of the memory port. - */ - if (acquire_seeprom(p) == 0) - { - return (0); - } - - /* - * Read 'len' registers of the seeprom. For the 7870, the 93C46 - * SEEPROM is a 1024-bit device with 64 16-bit registers but only - * the first 32 are used by Adaptec BIOS. Some adapters use the - * 93C56 SEEPROM which is a 2048-bit device. The loop will range - * from 0 to 'len' - 1. - */ - for (k = 0; k < len; k++) - { - /* - * Send chip select for one clock cycle. - */ - aic_outb(p, SEEMS | SEECK | SEECS, SEECTL); - CLOCK_PULSE(p); - - /* - * Now we're ready to send the read command followed by the - * address of the 16-bit register we want to read. - */ - for (i = 0; i < seeprom_read.len; i++) - { - temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - /* - * Send the 6 or 8 bit address (MSB first, LSB last). - */ - for (i = ((int) chip - 1); i >= 0; i--) - { - temp = k + offset; - temp = (temp >> i) & 1; /* Mask out all but lower bit. */ - temp = SEEMS | SEECS | (temp << 1); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - - /* - * Now read the 16 bit register. An initial 0 precedes the - * register contents which begins with bit 15 (MSB) and ends - * with bit 0 (LSB). The initial 0 will be shifted off the - * top of our word as we let the loop run from 0 to 16. - */ - for (i = 0; i <= 16; i++) - { - temp = SEEMS | SEECS; - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - temp = temp ^ SEECK; - scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI); - aic_outb(p, temp, SEECTL); - CLOCK_PULSE(p); - } - - /* - * The serial EEPROM should have a checksum in the last word. - * Keep a running checksum for all words read except for the - * last word. We'll verify the checksum after all words have - * been read. - */ - if (k < (len - 1)) - { - checksum = checksum + scarray[k]; - } - - /* - * Reset the chip select for the next command cycle. - */ - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - aic_outb(p, SEEMS | SEECK, SEECTL); - CLOCK_PULSE(p); - aic_outb(p, SEEMS, SEECTL); - CLOCK_PULSE(p); - } - - /* - * Release access to the memory port and the serial EEPROM. - */ - release_seeprom(p); - -#if 0 - printk("Computed checksum 0x%x, checksum read 0x%x\n", - checksum, scarray[len - 1]); - printk("Serial EEPROM:"); - for (k = 0; k < len; k++) - { - if (((k % 8) == 0) && (k != 0)) - { - printk("\n "); - } - printk(" 0x%x", scarray[k]); - } - printk("\n"); -#endif - if ( (checksum != scarray[len - 1]) || (checksum == 0) ) - { - return (0); - } - - return (1); -} - -/*+F************************************************************************* - * Function: - * read_brdctl - * - * Description: - * Reads the BRDCTL register. - *-F*************************************************************************/ -static unsigned char -read_brdctl(struct aic7xxx_host *p) -{ - unsigned char brdctl, value; - - /* - * Make sure the SEEPROM is ready before we access it - */ - CLOCK_PULSE(p); - if (p->features & AHC_ULTRA2) - { - brdctl = BRDRW_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - value = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - return(value); - } - brdctl = BRDRW; - if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || - (p->flags & AHC_CHNLB) ) - { - brdctl |= BRDCS; - } - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - value = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - aic_outb(p, 0, BRDCTL); - CLOCK_PULSE(p); - return (value); -} - -/*+F************************************************************************* - * Function: - * write_brdctl - * - * Description: - * Writes a value to the BRDCTL register. - *-F*************************************************************************/ -static void -write_brdctl(struct aic7xxx_host *p, unsigned char value) -{ - unsigned char brdctl; - - /* - * Make sure the SEEPROM is ready before we access it - */ - CLOCK_PULSE(p); - if (p->features & AHC_ULTRA2) - { - brdctl = value; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl |= BRDSTB_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDSTB_ULTRA2; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - read_brdctl(p); - CLOCK_PULSE(p); - } - else - { - brdctl = BRDSTB; - if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) || - (p->flags & AHC_CHNLB) ) - { - brdctl |= BRDCS; - } - brdctl = BRDSTB | BRDCS; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl |= value; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDSTB; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - brdctl &= ~BRDCS; - aic_outb(p, brdctl, BRDCTL); - CLOCK_PULSE(p); - } -} - -/*+F************************************************************************* - * Function: - * aic785x_cable_detect - * - * Description: - * Detect the cables that are present on aic785x class controller chips - *-F*************************************************************************/ -static void -aic785x_cable_detect(struct aic7xxx_host *p, int *int_50, - int *ext_present, int *eeprom) -{ - unsigned char brdctl; - - aic_outb(p, BRDRW | BRDCS, BRDCTL); - CLOCK_PULSE(p); - aic_outb(p, 0, BRDCTL); - CLOCK_PULSE(p); - brdctl = aic_inb(p, BRDCTL); - CLOCK_PULSE(p); - *int_50 = !(brdctl & BRDDAT5); - *ext_present = !(brdctl & BRDDAT6); - *eeprom = (aic_inb(p, SPIOCAP) & EEPROM); -} - -#undef CLOCK_PULSE - -/*+F************************************************************************* - * Function: - * aic2940_uwpro_cable_detect - * - * Description: - * Detect the cables that are present on the 2940-UWPro cards - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68, - int *ext_68, int *eeprom) -{ - unsigned char brdctl; - - /* - * First read the status of our cables. Set the rom bank to - * 0 since the bank setting serves as a multiplexor for the - * cable detection logic. BRDDAT5 controls the bank switch. - */ - write_brdctl(p, 0); - - /* - * Now we read the state of the internal 68 connector. BRDDAT6 - * is don't care, BRDDAT7 is internal 68. The cable is - * present if the bit is 0 - */ - brdctl = read_brdctl(p); - *int_68 = !(brdctl & BRDDAT7); - - /* - * Set the bank bit in brdctl and then read the external cable state - * and the EEPROM status - */ - write_brdctl(p, BRDDAT5); - brdctl = read_brdctl(p); - - *ext_68 = !(brdctl & BRDDAT6); - *eeprom = !(brdctl & BRDDAT7); - - /* - * We're done, the calling function will release the SEEPROM for us - */ -} - -/*+F************************************************************************* - * Function: - * aic787x_cable_detect - * - * Description: - * Detect the cables that are present on aic787x class controller chips - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68, - int *ext_present, int *eeprom) -{ - unsigned char brdctl; - - /* - * First read the status of our cables. Set the rom bank to - * 0 since the bank setting serves as a multiplexor for the - * cable detection logic. BRDDAT5 controls the bank switch. - */ - write_brdctl(p, 0); - - /* - * Now we read the state of the two internal connectors. BRDDAT6 - * is internal 50, BRDDAT7 is internal 68. For each, the cable is - * present if the bit is 0 - */ - brdctl = read_brdctl(p); - *int_50 = !(brdctl & BRDDAT6); - *int_68 = !(brdctl & BRDDAT7); - - /* - * Set the bank bit in brdctl and then read the external cable state - * and the EEPROM status - */ - write_brdctl(p, BRDDAT5); - brdctl = read_brdctl(p); - - *ext_present = !(brdctl & BRDDAT6); - *eeprom = !(brdctl & BRDDAT7); - - /* - * We're done, the calling function will release the SEEPROM for us - */ -} - -/*+F************************************************************************* - * Function: - * aic787x_ultra2_term_detect - * - * Description: - * Detect the termination settings present on ultra2 class controllers - * - * NOTE: This function assumes the SEEPROM will have already been acquired - * prior to invocation of this function. - *-F*************************************************************************/ -static void -aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low, - int *enableSE_high, int *enableLVD_low, - int *enableLVD_high, int *eprom_present) -{ - unsigned char brdctl; - - brdctl = read_brdctl(p); - - *eprom_present = (brdctl & BRDDAT7); - *enableSE_high = (brdctl & BRDDAT6); - *enableSE_low = (brdctl & BRDDAT5); - *enableLVD_high = (brdctl & BRDDAT4); - *enableLVD_low = (brdctl & BRDDAT3); -} - -/*+F************************************************************************* - * Function: - * configure_termination - * - * Description: - * Configures the termination settings on PCI adapters that have - * SEEPROMs available. - *-F*************************************************************************/ -static void -configure_termination(struct aic7xxx_host *p) -{ - int internal50_present = 0; - int internal68_present = 0; - int external_present = 0; - int eprom_present = 0; - int enableSE_low = 0; - int enableSE_high = 0; - int enableLVD_low = 0; - int enableLVD_high = 0; - unsigned char brddat = 0; - unsigned char max_target = 0; - unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1); - - if (acquire_seeprom(p)) - { - if (p->features & (AHC_WIDE|AHC_TWIN)) - max_target = 16; - else - max_target = 8; - aic_outb(p, SEEMS | SEECS, SEECTL); - sxfrctl1 &= ~STPWEN; - /* - * The termination/cable detection logic is split into three distinct - * groups. Ultra2 and later controllers, 2940UW-Pro controllers, and - * older 7850, 7860, 7870, 7880, and 7895 controllers. Each has its - * own unique way of detecting their cables and writing the results - * back to the card. - */ - if (p->features & AHC_ULTRA2) - { - /* - * As long as user hasn't overridden term settings, always check the - * cable detection logic - */ - if (aic7xxx_override_term == -1) - { - aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high, - &enableLVD_low, &enableLVD_high, - &eprom_present); - } - - /* - * If the user is overriding settings, then they have been preserved - * to here as fake adapter_control entries. Parse them and allow - * them to override the detected settings (if we even did detection). - */ - if (!(p->adapter_control & CFSEAUTOTERM)) - { - enableSE_low = (p->adapter_control & CFSTERM); - enableSE_high = (p->adapter_control & CFWSTERM); - } - if (!(p->adapter_control & CFAUTOTERM)) - { - enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM); - } - - /* - * Now take those settings that we have and translate them into the - * values that must be written into the registers. - * - * Flash Enable = BRDDAT7 - * Secondary High Term Enable = BRDDAT6 - * Secondary Low Term Enable = BRDDAT5 - * LVD/Primary High Term Enable = BRDDAT4 - * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1 - */ - if (enableLVD_low != 0) - { - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_LVD; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination " - "Enabled\n", p->host_no); - } - - if (enableLVD_high != 0) - { - brddat |= BRDDAT4; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination " - "Enabled\n", p->host_no); - } - - if (enableSE_low != 0) - { - brddat |= BRDDAT5; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Secondary Low byte termination " - "Enabled\n", p->host_no); - } - - if (enableSE_high != 0) - { - brddat |= BRDDAT6; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Secondary High byte termination " - "Enabled\n", p->host_no); - } - } - else if (p->features & AHC_NEW_AUTOTERM) - { - /* - * The 50 pin connector termination is controlled by STPWEN in the - * SXFRCTL1 register. Since the Adaptec docs typically say the - * controller is not allowed to be in the middle of a cable and - * this is the only connection on that stub of the bus, there is - * no need to even check for narrow termination, it's simply - * always on. - */ - sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n", - p->host_no); - - if (p->adapter_control & CFAUTOTERM) - { - aic2940_uwpro_wide_cable_detect(p, &internal68_present, - &external_present, - &eprom_present); - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " - "Ext-68 %s)\n", p->host_no, - "Don't Care", - internal68_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, - eprom_present ? "is" : "is not"); - if (internal68_present && external_present) - { - brddat = 0; - p->flags &= ~AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n", - p->host_no); - } - else - { - brddat = BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", - p->host_no); - } - } - else - { - /* - * The termination of the Wide channel is done more like normal - * though, and the setting of this termination is done by writing - * either a 0 or 1 to BRDDAT6 of the BRDDAT register - */ - if (p->adapter_control & CFWSTERM) - { - brddat = BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n", - p->host_no); - } - else - { - brddat = 0; - } - } - } - else - { - if (p->adapter_control & CFAUTOTERM) - { - if (p->flags & AHC_MOTHERBOARD) - { - printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n", - p->host_no); - printk(KERN_INFO "(scsi%d) Please verify driver detected settings " - "are correct.\n", p->host_no); - printk(KERN_INFO "(scsi%d) If not, then please properly set the " - "device termination\n", p->host_no); - printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting " - "CTRL-A when prompted\n", p->host_no); - printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no); - } - /* Configure auto termination. */ - - if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 ) - { - aic787x_cable_detect(p, &internal50_present, &internal68_present, - &external_present, &eprom_present); - } - else - { - aic785x_cable_detect(p, &internal50_present, &external_present, - &eprom_present); - } - - if (max_target <= 8) - internal68_present = 0; - - if (max_target > 8) - { - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, " - "Ext-68 %s)\n", p->host_no, - internal50_present ? "YES" : "NO", - internal68_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - } - else - { - printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)\n", - p->host_no, - internal50_present ? "YES" : "NO", - external_present ? "YES" : "NO"); - } - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no, - eprom_present ? "is" : "is not"); - - /* - * Now set the termination based on what we found. BRDDAT6 - * controls wide termination enable. - * Flash Enable = BRDDAT7 - * SE High Term Enable = BRDDAT6 - */ - if (internal50_present && internal68_present && external_present) - { - printk(KERN_INFO "(scsi%d) Illegal cable configuration!! Only two\n", - p->host_no); - printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be " - "in use at a time!\n", p->host_no); - /* - * Force termination (low and high byte) on. This is safer than - * leaving it completely off, especially since this message comes - * most often from motherboard controllers that don't even have 3 - * connectors, but instead are failing the cable detection. - */ - internal50_present = external_present = 0; - enableSE_high = enableSE_low = 1; - } - - if ((max_target > 8) && - ((external_present == 0) || (internal68_present == 0)) ) - { - brddat |= BRDDAT6; - p->flags |= AHC_TERM_ENB_SE_HIGH; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", - p->host_no); - } - - if ( ((internal50_present ? 1 : 0) + - (internal68_present ? 1 : 0) + - (external_present ? 1 : 0)) <= 1 ) - { - sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", - p->host_no); - } - } - else /* p->adapter_control & CFAUTOTERM */ - { - if (p->adapter_control & CFSTERM) - { - sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n", - p->host_no); - } - - if (p->adapter_control & CFWSTERM) - { - brddat |= BRDDAT6; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n", - p->host_no); - } - } - } - - aic_outb(p, sxfrctl1, SXFRCTL1); - write_brdctl(p, brddat); - release_seeprom(p); - } -} - -/*+F************************************************************************* - * Function: - * detect_maxscb - * - * Description: - * Detects the maximum number of SCBs for the controller and returns - * the count and a mask in p (p->maxscbs, p->qcntmask). - *-F*************************************************************************/ -static void -detect_maxscb(struct aic7xxx_host *p) -{ - int i; - - /* - * It's possible that we've already done this for multichannel - * adapters. - */ - if (p->scb_data->maxhscbs == 0) - { - /* - * We haven't initialized the SCB settings yet. Walk the SCBs to - * determince how many there are. - */ - aic_outb(p, 0, FREE_SCBH); - - for (i = 0; i < AIC7XXX_MAXSCB; i++) - { - aic_outb(p, i, SCBPTR); - aic_outb(p, i, SCB_CONTROL); - if (aic_inb(p, SCB_CONTROL) != i) - break; - aic_outb(p, 0, SCBPTR); - if (aic_inb(p, SCB_CONTROL) != 0) - break; - - aic_outb(p, i, SCBPTR); - aic_outb(p, 0, SCB_CONTROL); /* Clear the control byte. */ - aic_outb(p, i + 1, SCB_NEXT); /* Set the next pointer. */ - aic_outb(p, SCB_LIST_NULL, SCB_TAG); /* Make the tag invalid. */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS); /* no busy untagged */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */ - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2); - aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3); - } - - /* Make sure the last SCB terminates the free list. */ - aic_outb(p, i - 1, SCBPTR); - aic_outb(p, SCB_LIST_NULL, SCB_NEXT); - - /* Ensure we clear the first (0) SCBs control byte. */ - aic_outb(p, 0, SCBPTR); - aic_outb(p, 0, SCB_CONTROL); - - p->scb_data->maxhscbs = i; - /* - * Use direct indexing instead for speed - */ - if ( i == AIC7XXX_MAXSCB ) - p->flags &= ~AHC_PAGESCBS; - } - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_register - * - * Description: - * Register a Adaptec aic7xxx chip SCSI controller with the kernel. - *-F*************************************************************************/ -static int -aic7xxx_register(struct scsi_host_template *template, struct aic7xxx_host *p, - int reset_delay) -{ - int i, result; - int max_targets; - int found = 1; - unsigned char term, scsi_conf; - struct Scsi_Host *host; - - host = p->host; - - p->scb_data->maxscbs = AIC7XXX_MAXSCB; - host->can_queue = AIC7XXX_MAXSCB; - host->cmd_per_lun = 3; - host->sg_tablesize = AIC7XXX_MAX_SG; - host->this_id = p->scsi_id; - host->io_port = p->base; - host->n_io_port = 0xFF; - host->base = p->mbase; - host->irq = p->irq; - if (p->features & AHC_WIDE) - { - host->max_id = 16; - } - if (p->features & AHC_TWIN) - { - host->max_channel = 1; - } - - p->host = host; - p->host_no = host->host_no; - host->unique_id = p->instance; - p->isr_count = 0; - p->next = NULL; - p->completeq.head = NULL; - p->completeq.tail = NULL; - scbq_init(&p->scb_data->free_scbs); - scbq_init(&p->waiting_scbs); - INIT_LIST_HEAD(&p->aic_devs); - - /* - * We currently have no commands of any type - */ - p->qinfifonext = 0; - p->qoutfifonext = 0; - - printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no, - board_names[p->board_name_index]); - switch(p->chip) - { - case (AHC_AIC7770|AHC_EISA): - printk("EISA slot %d\n", p->pci_device_fn); - break; - case (AHC_AIC7770|AHC_VL): - printk("VLB slot %d\n", p->pci_device_fn); - break; - default: - printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn), - PCI_FUNC(p->pci_device_fn)); - break; - } - if (p->features & AHC_TWIN) - { - printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ", - p->host_no, p->scsi_id, p->scsi_id_b); - } - else - { - char *channel; - - channel = ""; - - if ((p->flags & AHC_MULTI_CHANNEL) != 0) - { - channel = " A"; - - if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 ) - { - channel = (p->flags & AHC_CHNLB) ? " B" : " C"; - } - } - if (p->features & AHC_WIDE) - { - printk(KERN_INFO "(scsi%d) Wide ", p->host_no); - } - else - { - printk(KERN_INFO "(scsi%d) Narrow ", p->host_no); - } - printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id); - } - aic_outb(p, 0, SEQ_FLAGS); - - detect_maxscb(p); - - printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n", - p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis", - p->base, p->irq); - printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at %p\n", - p->host_no, p->mbase, p->maddr); - } - -#ifdef CONFIG_PCI - /* - * Now that we know our instance number, we can set the flags we need to - * force termination if need be. - */ - if (aic7xxx_stpwlev != -1) - { - /* - * This option only applies to PCI controllers. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) - { - unsigned char devconfig; - - pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig); - if ( (aic7xxx_stpwlev >> p->instance) & 0x01 ) - { - devconfig |= STPWLEVEL; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no); - } - else - { - devconfig &= ~STPWLEVEL; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no); - } - pci_write_config_byte(p->pdev, DEVCONFIG, devconfig); - } - } -#endif - - /* - * That took care of devconfig and stpwlev, now for the actual termination - * settings. - */ - if (aic7xxx_override_term != -1) - { - /* - * Again, this only applies to PCI controllers. We don't have problems - * with the termination on 274x controllers to the best of my knowledge. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) - { - unsigned char term_override; - - term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f); - p->adapter_control &= - ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM); - if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) ) - { - p->adapter_control |= CFLVDSTERM; - } - if (term_override & 0x02) - { - p->adapter_control |= CFWSTERM; - } - if (term_override & 0x01) - { - p->adapter_control |= CFSTERM; - } - } - } - - if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) ) - { - if (p->features & AHC_SPIOCAP) - { - if ( aic_inb(p, SPIOCAP) & SSPIOCPS ) - /* - * Update the settings in sxfrctl1 to match the termination - * settings. - */ - configure_termination(p); - } - else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870) - { - configure_termination(p); - } - } - - /* - * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels - */ - if (p->features & AHC_TWIN) - { - /* Select channel B */ - aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); - - if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) - term = (aic_inb(p, SXFRCTL1) & STPWEN); - else - term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0); - - aic_outb(p, p->scsi_id_b, SCSIID); - scsi_conf = aic_inb(p, SCSICONF + 1); - aic_outb(p, DFON | SPIOEN, SXFRCTL0); - aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | - ENSTIMER | ACTNEGEN, SXFRCTL1); - aic_outb(p, 0, SIMODE0); - aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); - aic_outb(p, 0, SCSIRATE); - - /* Select channel A */ - aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); - } - - if (p->features & AHC_ULTRA2) - { - aic_outb(p, p->scsi_id, SCSIID_ULTRA2); - } - else - { - aic_outb(p, p->scsi_id, SCSIID); - } - if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1)) - term = (aic_inb(p, SXFRCTL1) & STPWEN); - else - term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0); - scsi_conf = aic_inb(p, SCSICONF); - aic_outb(p, DFON | SPIOEN, SXFRCTL0); - aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | - ENSTIMER | ACTNEGEN, SXFRCTL1); - aic_outb(p, 0, SIMODE0); - /* - * If we are a cardbus adapter then don't enable SCSI reset detection. - * We shouldn't likely be sharing SCSI busses with someone else, and - * if we don't have a cable currently plugged into the controller then - * we won't have a power source for the SCSI termination, which means - * we'll see infinite incoming bus resets. - */ - if(p->flags & AHC_NO_STPWEN) - aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1); - else - aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1); - aic_outb(p, 0, SCSIRATE); - if ( p->features & AHC_ULTRA2) - aic_outb(p, 0, SCSIOFFSET); - - /* - * Look at the information that board initialization or the board - * BIOS has left us. In the lower four bits of each target's - * scratch space any value other than 0 indicates that we should - * initiate synchronous transfers. If it's zero, the user or the - * BIOS has decided to disable synchronous negotiation to that - * target so we don't activate the needsdtr flag. - */ - if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0) - { - max_targets = 8; - } - else - { - max_targets = 16; - } - - if (!(aic7xxx_no_reset)) - { - /* - * If we reset the bus, then clear the transfer settings, else leave - * them be. - */ - aic_outb(p, 0, ULTRA_ENB); - aic_outb(p, 0, ULTRA_ENB + 1); - p->ultraenb = 0; - } - - /* - * Allocate enough hardware scbs to handle the maximum number of - * concurrent transactions we can have. We have to make sure that - * the allocated memory is contiguous memory. The Linux kmalloc - * routine should only allocate contiguous memory, but note that - * this could be a problem if kmalloc() is changed. - */ - { - size_t array_size; - unsigned int hscb_physaddr; - - array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb); - if (p->scb_data->hscbs == NULL) - { - /* pci_alloc_consistent enforces the alignment already and - * clears the area as well. - */ - p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size, - &p->scb_data->hscbs_dma); - /* We have to use pci_free_consistent, not kfree */ - p->scb_data->hscb_kmalloc_ptr = NULL; - p->scb_data->hscbs_dma_len = array_size; - } - if (p->scb_data->hscbs == NULL) - { - printk("(scsi%d) Unable to allocate hardware SCB array; " - "failing detection.\n", p->host_no); - aic_outb(p, 0, SIMODE1); - p->irq = 0; - return(0); - } - - hscb_physaddr = p->scb_data->hscbs_dma; - aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR); - aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1); - aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2); - aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3); - - /* Set up the fifo areas at the same time */ - p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma); - if (p->untagged_scbs == NULL) - { - printk("(scsi%d) Unable to allocate hardware FIFO arrays; " - "failing detection.\n", p->host_no); - p->irq = 0; - return(0); - } - - p->qoutfifo = p->untagged_scbs + 256; - p->qinfifo = p->qoutfifo + 256; - for (i = 0; i < 256; i++) - { - p->untagged_scbs[i] = SCB_LIST_NULL; - p->qinfifo[i] = SCB_LIST_NULL; - p->qoutfifo[i] = SCB_LIST_NULL; - } - - hscb_physaddr = p->fifo_dma; - aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR); - aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1); - aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2); - aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3); - } - - /* The Q-FIFOs we just set up are all empty */ - aic_outb(p, 0, QINPOS); - aic_outb(p, 0, KERNEL_QINPOS); - aic_outb(p, 0, QOUTPOS); - - if(p->features & AHC_QUEUE_REGS) - { - aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA); - aic_outb(p, 0, SDSCB_QOFF); - aic_outb(p, 0, SNSCB_QOFF); - aic_outb(p, 0, HNSCB_QOFF); - } - - /* - * We don't have any waiting selections or disconnected SCBs. - */ - aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); - aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH); - - /* - * Message out buffer starts empty - */ - aic_outb(p, MSG_NOOP, MSG_OUT); - aic_outb(p, MSG_NOOP, LAST_MSG); - - /* - * Set all the other asundry items that haven't been set yet. - * This includes just dumping init values to a lot of registers simply - * to make sure they've been touched and are ready for use parity wise - * speaking. - */ - aic_outb(p, 0, TMODE_CMDADDR); - aic_outb(p, 0, TMODE_CMDADDR + 1); - aic_outb(p, 0, TMODE_CMDADDR + 2); - aic_outb(p, 0, TMODE_CMDADDR + 3); - aic_outb(p, 0, TMODE_CMDADDR_NEXT); - - /* - * Link us into the list of valid hosts - */ - p->next = first_aic7xxx; - first_aic7xxx = p; - - /* - * Allocate the first set of scbs for this controller. This is to stream- - * line code elsewhere in the driver. If we have to check for the existence - * of scbs in certain code sections, it slows things down. However, as - * soon as we register the IRQ for this card, we could get an interrupt that - * includes possibly the SCSI_RSTI interrupt. If we catch that interrupt - * then we are likely to segfault if we don't have at least one chunk of - * SCBs allocated or add checks all through the reset code to make sure - * that the SCBs have been allocated which is an invalid running condition - * and therefore I think it's preferable to simply pre-allocate the first - * chunk of SCBs. - */ - aic7xxx_allocate_scb(p); - - /* - * Load the sequencer program, then re-enable the board - - * resetting the AIC-7770 disables it, leaving the lights - * on with nobody home. - */ - aic7xxx_loadseq(p); - - /* - * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register - */ - aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL); - - if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 ) - { - aic_outb(p, ENABLE, BCTL); /* Enable the boards BUS drivers. */ - } - - if ( !(aic7xxx_no_reset) ) - { - if (p->features & AHC_TWIN) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no); - aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL); - aic7xxx_reset_current_bus(p); - aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL); - } - /* Reset SCSI bus A. */ - if (aic7xxx_verbose & VERBOSE_PROBE2) - { /* In case we are a 3940, 3985, or 7895, print the right channel */ - char *channel = ""; - if (p->flags & AHC_MULTI_CHANNEL) - { - channel = " A"; - if (p->flags & (AHC_CHNLB|AHC_CHNLC)) - channel = (p->flags & AHC_CHNLB) ? " B" : " C"; - } - printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel); - } - - aic7xxx_reset_current_bus(p); - - } - else - { - if (!reset_delay) - { - printk(KERN_INFO "(scsi%d) Not resetting SCSI bus. Note: Don't use " - "the no_reset\n", p->host_no); - printk(KERN_INFO "(scsi%d) option unless you have a verifiable need " - "for it.\n", p->host_no); - } - } - - /* - * Register IRQ with the kernel. Only allow sharing IRQs with - * PCI devices. - */ - if (!(p->chip & AHC_PCI)) - { - result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p)); - } - else - { - result = (request_irq(p->irq, do_aic7xxx_isr, IRQF_SHARED, - "aic7xxx", p)); - if (result < 0) - { - result = (request_irq(p->irq, do_aic7xxx_isr, IRQF_DISABLED | IRQF_SHARED, - "aic7xxx", p)); - } - } - if (result < 0) - { - printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring " - "controller.\n", p->host_no, p->irq); - aic_outb(p, 0, SIMODE1); - p->irq = 0; - return (0); - } - - if(aic_inb(p, INTSTAT) & INT_PEND) - printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n", - p->host_no, -1, -1 , -1); - aic7xxx_clear_intstat(p); - - unpause_sequencer(p, /* unpause_always */ TRUE); - - return (found); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_chip_reset - * - * Description: - * Perform a chip reset on the aic7xxx SCSI controller. The controller - * is paused upon return. - *-F*************************************************************************/ -static int -aic7xxx_chip_reset(struct aic7xxx_host *p) -{ - unsigned char sblkctl; - int wait; - - /* - * For some 274x boards, we must clear the CHIPRST bit and pause - * the sequencer. For some reason, this makes the driver work. - */ - aic_outb(p, PAUSE | CHIPRST, HCNTRL); - - /* - * In the future, we may call this function as a last resort for - * error handling. Let's be nice and not do any unnecessary delays. - */ - wait = 1000; /* 1 msec (1000 * 1 msec) */ - while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK)) - { - udelay(1); /* 1 usec */ - } - - pause_sequencer(p); - - sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE); - if (p->chip & AHC_PCI) - sblkctl &= ~SELBUSB; - switch( sblkctl ) - { - case 0: /* normal narrow card */ - break; - case 2: /* Wide card */ - p->features |= AHC_WIDE; - break; - case 8: /* Twin card */ - p->features |= AHC_TWIN; - p->flags |= AHC_MULTI_CHANNEL; - break; - default: /* hmmm...we don't know what this is */ - printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n", - aic_inb(p, SBLKCTL) & 0x0a); - return(-1); - } - return(0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_alloc - * - * Description: - * Allocate and initialize a host structure. Returns NULL upon error - * and a pointer to a aic7xxx_host struct upon success. - *-F*************************************************************************/ -static struct aic7xxx_host * -aic7xxx_alloc(struct scsi_host_template *sht, struct aic7xxx_host *temp) -{ - struct aic7xxx_host *p = NULL; - struct Scsi_Host *host; - - /* - * Allocate a storage area by registering us with the mid-level - * SCSI layer. - */ - host = scsi_register(sht, sizeof(struct aic7xxx_host)); - - if (host != NULL) - { - p = (struct aic7xxx_host *) host->hostdata; - memset(p, 0, sizeof(struct aic7xxx_host)); - *p = *temp; - p->host = host; - - p->scb_data = kzalloc(sizeof(scb_data_type), GFP_ATOMIC); - if (p->scb_data) - { - scbq_init (&p->scb_data->free_scbs); - } - else - { - /* - * For some reason we don't have enough memory. Free the - * allocated memory for the aic7xxx_host struct, and return NULL. - */ - release_region(p->base, MAXREG - MINREG); - scsi_unregister(host); - return(NULL); - } - p->host_no = host->host_no; - } - return (p); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_free - * - * Description: - * Frees and releases all resources associated with an instance of - * the driver (struct aic7xxx_host *). - *-F*************************************************************************/ -static void -aic7xxx_free(struct aic7xxx_host *p) -{ - int i; - - /* - * Free the allocated hardware SCB space. - */ - if (p->scb_data != NULL) - { - struct aic7xxx_scb_dma *scb_dma = NULL; - if (p->scb_data->hscbs != NULL) - { - pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len, - p->scb_data->hscbs, p->scb_data->hscbs_dma); - p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL; - } - /* - * Free the driver SCBs. These were allocated on an as-need - * basis. We allocated these in groups depending on how many - * we could fit into a given amount of RAM. The tail SCB for - * these allocations has a pointer to the alloced area. - */ - for (i = 0; i < p->scb_data->numscbs; i++) - { - if (p->scb_data->scb_array[i]->scb_dma != scb_dma) - { - scb_dma = p->scb_data->scb_array[i]->scb_dma; - pci_free_consistent(p->pdev, scb_dma->dma_len, - (void *)((unsigned long)scb_dma->dma_address - - scb_dma->dma_offset), - scb_dma->dma_address); - } - kfree(p->scb_data->scb_array[i]->kmalloc_ptr); - p->scb_data->scb_array[i] = NULL; - } - - /* - * Free the SCB data area. - */ - kfree(p->scb_data); - } - - pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_load_seeprom - * - * Description: - * Load the seeprom and configure adapter and target settings. - * Returns 1 if the load was successful and 0 otherwise. - *-F*************************************************************************/ -static void -aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1) -{ - int have_seeprom = 0; - int i, max_targets, mask; - unsigned char scsirate, scsi_conf; - unsigned short scarray[128]; - struct seeprom_config *sc = (struct seeprom_config *) scarray; - - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "aic7xxx: Loading serial EEPROM..."); - } - switch (p->chip) - { - case (AHC_AIC7770|AHC_EISA): /* None of these adapters have seeproms. */ - if (aic_inb(p, SCSICONF) & TERM_ENB) - p->flags |= AHC_TERM_ENB_A; - if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) ) - p->flags |= AHC_TERM_ENB_B; - break; - - case (AHC_AIC7770|AHC_VL): - have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray); - break; - - default: - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, p->sc_type); - if (!have_seeprom) - { - if(p->sc_type == C46) - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C56_66); - else - have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C46); - } - if (!have_seeprom) - { - p->sc_size = 128; - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, p->sc_type); - if (!have_seeprom) - { - if(p->sc_type == C46) - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C56_66); - else - have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)), - scarray, p->sc_size, C46); - } - } - break; - } - - if (!have_seeprom) - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("\naic7xxx: No SEEPROM available.\n"); - } - p->flags |= AHC_NEWEEPROM_FMT; - if (aic_inb(p, SCSISEQ) == 0) - { - p->flags |= AHC_USEDEFAULTS; - p->flags &= ~AHC_BIOS_ENABLED; - p->scsi_id = p->scsi_id_b = 7; - *sxfrctl1 |= STPWEN; - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Using default values.\n"); - } - } - else if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Using leftover BIOS values.\n"); - } - if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) ) - { - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - sc->adapter_control &= ~CFAUTOTERM; - sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM; - } - if (aic7xxx_extended) - p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); - else - p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B); - } - else - { - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("done\n"); - } - - /* - * Note things in our flags - */ - p->flags |= AHC_SEEPROM_FOUND; - - /* - * Update the settings in sxfrctl1 to match the termination settings. - */ - *sxfrctl1 = 0; - - /* - * Get our SCSI ID from the SEEPROM setting... - */ - p->scsi_id = (sc->brtime_id & CFSCSIID); - - /* - * First process the settings that are different between the VLB - * and PCI adapter seeproms. - */ - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770) - { - /* VLB adapter seeproms */ - if (sc->bios_control & CF284XEXTEND) - p->flags |= AHC_EXTEND_TRANS_A; - - if (sc->adapter_control & CF284XSTERM) - { - *sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - } - } - else - { - /* PCI adapter seeproms */ - if (sc->bios_control & CFEXTEND) - p->flags |= AHC_EXTEND_TRANS_A; - if (sc->bios_control & CFBIOSEN) - p->flags |= AHC_BIOS_ENABLED; - else - p->flags &= ~AHC_BIOS_ENABLED; - - if (sc->adapter_control & CFSTERM) - { - *sxfrctl1 |= STPWEN; - p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH; - } - } - memcpy(&p->sc, sc, sizeof(struct seeprom_config)); - } - - p->discenable = 0; - - /* - * Limit to 16 targets just in case. The 2842 for one is known to - * blow the max_targets setting, future cards might also. - */ - max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8); - - if (have_seeprom) - { - for (i = 0; i < max_targets; i++) - { - if( ((p->features & AHC_ULTRA) && - !(sc->adapter_control & CFULTRAEN) && - (sc->device_flags[i] & CFSYNCHISULTRA)) || - (sc->device_flags[i] & CFNEWULTRAFORMAT) ) - { - p->flags |= AHC_NEWEEPROM_FMT; - break; - } - } - } - - for (i = 0; i < max_targets; i++) - { - mask = (0x01 << i); - if (!have_seeprom) - { - if (aic_inb(p, SCSISEQ) != 0) - { - /* - * OK...the BIOS set things up and left behind the settings we need. - * Just make our sc->device_flags[i] entry match what the card has - * set for this device. - */ - p->discenable = - ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) ); - p->ultraenb = - (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) ); - sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0; - if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER) - sc->device_flags[i] |= CFWIDEB; - if (p->features & AHC_ULTRA2) - { - if (aic_inb(p, TARG_OFFSET + i)) - { - sc->device_flags[i] |= CFSYNCH; - sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07); - if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 ) - sc->device_flags[i] |= CFSYNCHISULTRA; - } - } - else - { - if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER) - { - sc->device_flags[i] |= CFSYNCH; - if (p->features & AHC_ULTRA) - sc->device_flags[i] |= ((p->ultraenb & mask) ? - CFSYNCHISULTRA : 0); - } - } - } - else - { - /* - * Assume the BIOS has NOT been run on this card and nothing between - * the card and the devices is configured yet. - */ - sc->device_flags[i] = CFDISC; - if (p->features & AHC_WIDE) - sc->device_flags[i] |= CFWIDEB; - if (p->features & AHC_ULTRA3) - sc->device_flags[i] |= 2; - else if (p->features & AHC_ULTRA2) - sc->device_flags[i] |= 3; - else if (p->features & AHC_ULTRA) - sc->device_flags[i] |= CFSYNCHISULTRA; - sc->device_flags[i] |= CFSYNCH; - aic_outb(p, 0, TARG_SCSIRATE + i); - if (p->features & AHC_ULTRA2) - aic_outb(p, 0, TARG_OFFSET + i); - } - } - if (sc->device_flags[i] & CFDISC) - { - p->discenable |= mask; - } - if (p->flags & AHC_NEWEEPROM_FMT) - { - if ( !(p->features & AHC_ULTRA2) ) - { - /* - * I know of two different Ultra BIOSes that do this differently. - * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to - * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s - * while on the IBM Netfinity 5000 they want the same thing - * to be something else, while flags[i] & CFXFER == 0x03 and - * SYNCHISULTRA false should be 40MByte/s. So, we set both to - * 40MByte/s and the lower speeds be damned. People will have - * to select around the conversely mapped lower speeds in order - * to select lower speeds on these boards. - */ - if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) && - ((sc->device_flags[i] & CFXFER) == 0x03) ) - { - sc->device_flags[i] &= ~CFXFER; - sc->device_flags[i] |= CFSYNCHISULTRA; - } - if (sc->device_flags[i] & CFSYNCHISULTRA) - { - p->ultraenb |= mask; - } - } - else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) && - (p->features & AHC_ULTRA2) && - (sc->device_flags[i] & CFSYNCHISULTRA) ) - { - p->ultraenb |= mask; - } - } - else if (sc->adapter_control & CFULTRAEN) - { - p->ultraenb |= mask; - } - if ( (sc->device_flags[i] & CFSYNCH) == 0) - { - sc->device_flags[i] &= ~CFXFER; - p->ultraenb &= ~mask; - p->user[i].offset = 0; - p->user[i].period = 0; - p->user[i].options = 0; - } - else - { - if (p->features & AHC_ULTRA3) - { - p->user[i].offset = MAX_OFFSET_ULTRA2; - if( (sc->device_flags[i] & CFXFER) < 0x03 ) - { - scsirate = (sc->device_flags[i] & CFXFER); - p->user[i].options = MSG_EXT_PPR_OPTION_DT_CRC; - } - else - { - scsirate = (sc->device_flags[i] & CFXFER) | - ((p->ultraenb & mask) ? 0x18 : 0x10); - p->user[i].options = 0; - } - p->user[i].period = aic7xxx_find_period(p, scsirate, - AHC_SYNCRATE_ULTRA3); - } - else if (p->features & AHC_ULTRA2) - { - p->user[i].offset = MAX_OFFSET_ULTRA2; - scsirate = (sc->device_flags[i] & CFXFER) | - ((p->ultraenb & mask) ? 0x18 : 0x10); - p->user[i].options = 0; - p->user[i].period = aic7xxx_find_period(p, scsirate, - AHC_SYNCRATE_ULTRA2); - } - else - { - scsirate = (sc->device_flags[i] & CFXFER) << 4; - p->user[i].options = 0; - p->user[i].offset = MAX_OFFSET_8BIT; - if (p->features & AHC_ULTRA) - { - short ultraenb; - ultraenb = aic_inb(p, ULTRA_ENB) | - (aic_inb(p, ULTRA_ENB + 1) << 8); - p->user[i].period = aic7xxx_find_period(p, scsirate, - (p->ultraenb & mask) ? - AHC_SYNCRATE_ULTRA : - AHC_SYNCRATE_FAST); - } - else - p->user[i].period = aic7xxx_find_period(p, scsirate, - AHC_SYNCRATE_FAST); - } - } - if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) ) - { - p->user[i].width = MSG_EXT_WDTR_BUS_16_BIT; - } - else - { - p->user[i].width = MSG_EXT_WDTR_BUS_8_BIT; - } - } - aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB); - aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1); - - /* - * We set the p->ultraenb from the SEEPROM to begin with, but now we make - * it match what is already down in the card. If we are doing a reset - * on the card then this will get put back to a default state anyway. - * This allows us to not have to pre-emptively negotiate when using the - * no_reset option. - */ - if (p->features & AHC_ULTRA) - p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8); - - - scsi_conf = (p->scsi_id & HSCSIID); - - if(have_seeprom) - { - p->adapter_control = sc->adapter_control; - p->bios_control = sc->bios_control; - - switch (p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - if (p->adapter_control & CFBPRIMARY) - p->flags |= AHC_CHANNEL_B_PRIMARY; - default: - break; - } - - if (sc->adapter_control & CFSPARITY) - scsi_conf |= ENSPCHK; - } - else - { - scsi_conf |= ENSPCHK | RESET_SCSI; - } - - /* - * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card. - * The 2842 and 2742 cards already have these registers set and we don't - * want to muck with them since we don't set all the bits they do. - */ - if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI ) - { - /* Set the host ID */ - aic_outb(p, scsi_conf, SCSICONF); - /* In case we are a wide card */ - aic_outb(p, p->scsi_id, SCSICONF + 1); - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_configure_bugs - * - * Description: - * Take the card passed in and set the appropriate bug flags based upon - * the card model. Also make any changes needed to device registers or - * PCI registers while we are here. - *-F*************************************************************************/ -static void -aic7xxx_configure_bugs(struct aic7xxx_host *p) -{ - unsigned short tmp_word; - - switch(p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7860: - p->bugs |= AHC_BUG_PCI_2_1_RETRY; - /* fall through */ - case AHC_AIC7850: - case AHC_AIC7870: - p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; - break; - case AHC_AIC7880: - p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | - AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; - break; - case AHC_AIC7890: - p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN; - break; - case AHC_AIC7892: - p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; - break; - case AHC_AIC7895: - p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY | - AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI; - break; - case AHC_AIC7896: - p->bugs |= AHC_BUG_CACHETHEN_DIS; - break; - case AHC_AIC7899: - p->bugs |= AHC_BUG_SCBCHAN_UPLOAD; - break; - default: - /* Nothing to do */ - break; - } - - /* - * Now handle the bugs that require PCI register or card register tweaks - */ - pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word); - if(p->bugs & AHC_BUG_PCI_MWI) - { - tmp_word &= ~PCI_COMMAND_INVALIDATE; - } - else - { - tmp_word |= PCI_COMMAND_INVALIDATE; - } - pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word); - - if(p->bugs & AHC_BUG_CACHETHEN) - { - aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0); - } - else if (p->bugs & AHC_BUG_CACHETHEN_DIS) - { - aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0); - } - - return; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_detect - * - * Description: - * Try to detect and register an Adaptec 7770 or 7870 SCSI controller. - * - * XXX - This should really be called aic7xxx_probe(). A sequence of - * probe(), attach()/detach(), and init() makes more sense than - * one do-it-all function. This may be useful when (and if) the - * mid-level SCSI code is overhauled. - *-F*************************************************************************/ -static int -aic7xxx_detect(struct scsi_host_template *template) -{ - struct aic7xxx_host *temp_p = NULL; - struct aic7xxx_host *current_p = NULL; - struct aic7xxx_host *list_p = NULL; - int found = 0; -#if defined(__i386__) || defined(__alpha__) - ahc_flag_type flags = 0; - int type; -#endif - unsigned char sxfrctl1; -#if defined(__i386__) || defined(__alpha__) - unsigned char hcntrl, hostconf; - unsigned int slot, base; -#endif - -#ifdef MODULE - /* - * If we are called as a module, the aic7xxx pointer may not be null - * and it would point to our bootup string, just like on the lilo - * command line. IF not NULL, then process this config string with - * aic7xxx_setup - */ - if(aic7xxx) - aic7xxx_setup(aic7xxx); -#endif - - template->proc_name = "aic7xxx"; - template->sg_tablesize = AIC7XXX_MAX_SG; - - -#ifdef CONFIG_PCI - /* - * PCI-bus probe. - */ - { - static struct - { - unsigned short vendor_id; - unsigned short device_id; - ahc_chip chip; - ahc_flag_type flags; - ahc_feature features; - int board_name_index; - unsigned short seeprom_size; - unsigned short seeprom_type; - } const aic_pdevs[] = { - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE, - AHC_FNONE, AHC_FENONE, 1, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850, - AHC_PAGESCBS, AHC_AIC7850_FE, 5, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850, - AHC_PAGESCBS, AHC_AIC7850_FE, 6, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7860_FE, 7, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7860_FE, 8, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7870_FE, 9, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 10, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7870_FE, 11, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7870_FE, 12, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE, 13, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD, - AHC_AIC7880_FE, 14, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 15, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7880_FE, 16, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7880_FE, 17, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880, - AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE, 18, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7895_FE, 20, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 21, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 21, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 22, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7890_FE, 23, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 24, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 25, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7896_FE, 26, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN, - AHC_AIC7860_FE, 27, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED, - AHC_AIC7892_FE, 28, - 32, C46 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899, - AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL, - AHC_AIC7899_FE, 29, - 32, C56_66 }, - }; - - unsigned short command; - unsigned int devconfig, i, oldverbose; - struct pci_dev *pdev = NULL; - - for (i = 0; i < ARRAY_SIZE(aic_pdevs); i++) - { - pdev = NULL; - while ((pdev = pci_get_device(aic_pdevs[i].vendor_id, - aic_pdevs[i].device_id, - pdev))) { - if (pci_enable_device(pdev)) - continue; - if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */ - { - if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2)) - { - printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not " - "supported by\n"); - printk(KERN_INFO " this driver, we are ignoring it.\n"); - } - } - else if ( (temp_p = kzalloc(sizeof(struct aic7xxx_host), - GFP_ATOMIC)) != NULL ) - { - temp_p->chip = aic_pdevs[i].chip | AHC_PCI; - temp_p->flags = aic_pdevs[i].flags; - temp_p->features = aic_pdevs[i].features; - temp_p->board_name_index = aic_pdevs[i].board_name_index; - temp_p->sc_size = aic_pdevs[i].seeprom_size; - temp_p->sc_type = aic_pdevs[i].seeprom_type; - - /* - * Read sundry information from PCI BIOS. - */ - temp_p->irq = pdev->irq; - temp_p->pdev = pdev; - temp_p->pci_bus = pdev->bus->number; - temp_p->pci_device_fn = pdev->devfn; - temp_p->base = pci_resource_start(pdev, 0); - temp_p->mbase = pci_resource_start(pdev, 1); - current_p = list_p; - while(current_p && temp_p) - { - if ( ((current_p->pci_bus == temp_p->pci_bus) && - (current_p->pci_device_fn == temp_p->pci_device_fn)) || - (temp_p->base && (current_p->base == temp_p->base)) || - (temp_p->mbase && (current_p->mbase == temp_p->mbase)) ) - { - /* duplicate PCI entry, skip it */ - kfree(temp_p); - temp_p = NULL; - continue; - } - current_p = current_p->next; - } - if(pci_request_regions(temp_p->pdev, "aic7xxx")) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: I/O ports already in use, ignoring.\n"); - kfree(temp_p); - continue; - } - - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at PCI %d/%d\n", - board_names[aic_pdevs[i].board_name_index], - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); - pci_read_config_word(pdev, PCI_COMMAND, &command); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n", - (int)command); - } -#ifdef AIC7XXX_STRICT_PCI_SETUP - command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY | - PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -#else - command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; -#endif - command &= ~PCI_COMMAND_INVALIDATE; - if (aic7xxx_pci_parity == 0) - command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); - pci_write_config_word(pdev, PCI_COMMAND, command); -#ifdef AIC7XXX_STRICT_PCI_SETUP - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig); - } - devconfig |= 0x80000040; - pci_write_config_dword(pdev, DEVCONFIG, devconfig); -#endif /* AIC7XXX_STRICT_PCI_SETUP */ - - temp_p->unpause = INTEN; - temp_p->pause = temp_p->unpause | PAUSE; - if ( ((temp_p->base == 0) && - (temp_p->mbase == 0)) || - (temp_p->irq == 0) ) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); - goto skip_pci_controller; - } - -#ifdef MMAPIO - if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) || - ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) && - (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) ) - { - temp_p->maddr = ioremap_nocache(temp_p->mbase, 256); - if(temp_p->maddr) - { - /* - * We need to check the I/O with the MMAPed address. Some machines - * simply fail to work with MMAPed I/O and certain controllers. - */ - if(aic_inb(temp_p, HCNTRL) == 0xff) - { - /* - * OK.....we failed our test....go back to programmed I/O - */ - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to " - "Programmed I/O.\n"); - iounmap(temp_p->maddr); - temp_p->maddr = NULL; - if(temp_p->base == 0) - { - printk("aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: Controller disabled by BIOS, ignoring.\n"); - goto skip_pci_controller; - } - } - } - } -#endif - - /* - * We HAVE to make sure the first pause_sequencer() and all other - * subsequent I/O that isn't PCI config space I/O takes place - * after the MMAPed I/O region is configured and tested. The - * problem is the PowerPC architecture that doesn't support - * programmed I/O at all, so we have to have the MMAP I/O set up - * for this pause to even work on those machines. - */ - pause_sequencer(temp_p); - - /* - * Clear out any pending PCI error status messages. Also set - * verbose to 0 so that we don't emit strange PCI error messages - * while cleaning out the current status bits. - */ - oldverbose = aic7xxx_verbose; - aic7xxx_verbose = 0; - aic7xxx_pci_intr(temp_p); - aic7xxx_verbose = oldverbose; - - temp_p->bios_address = 0; - - /* - * Remember how the card was setup in case there is no seeprom. - */ - if (temp_p->features & AHC_ULTRA2) - temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID; - else - temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID; - /* - * Get current termination setting - */ - sxfrctl1 = aic_inb(temp_p, SXFRCTL1); - - if (aic7xxx_chip_reset(temp_p) == -1) - { - goto skip_pci_controller; - } - /* - * Very quickly put the term setting back into the register since - * the chip reset may cause odd things to happen. This is to keep - * LVD busses with lots of drives from draining the power out of - * the diffsense line before we get around to running the - * configure_termination() function. Also restore the STPWLEVEL - * bit of DEVCONFIG - */ - aic_outb(temp_p, sxfrctl1, SXFRCTL1); - pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig); - sxfrctl1 &= STPWEN; - - /* - * We need to set the CHNL? assignments before loading the SEEPROM - * The 3940 and 3985 cards (original stuff, not any of the later - * stuff) are 7870 and 7880 class chips. The Ultra2 stuff falls - * under 7896 and 7897. The 7895 is in a class by itself :) - */ - switch (temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7870: /* 3840 / 3985 */ - case AHC_AIC7880: /* 3840 UW / 3985 UW */ - if(temp_p->flags & AHC_MULTI_CHANNEL) - { - switch(PCI_SLOT(temp_p->pci_device_fn)) - { - case 5: - temp_p->flags |= AHC_CHNLB; - break; - case 8: - temp_p->flags |= AHC_CHNLB; - break; - case 12: - temp_p->flags |= AHC_CHNLC; - break; - default: - break; - } - } - break; - - case AHC_AIC7895: /* 7895 */ - case AHC_AIC7896: /* 7896/7 */ - case AHC_AIC7899: /* 7899 */ - if (PCI_FUNC(pdev->devfn) != 0) - { - temp_p->flags |= AHC_CHNLB; - } - /* - * The 7895 is the only chipset that sets the SCBSIZE32 param - * in the DEVCONFIG register. The Ultra2 chipsets use - * the DSCOMMAND0 register instead. - */ - if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) - { - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - devconfig |= SCBSIZE32; - pci_write_config_dword(pdev, DEVCONFIG, devconfig); - } - break; - default: - break; - } - - /* - * Loading of the SEEPROM needs to come after we've set the flags - * to indicate possible CHNLB and CHNLC assigments. Otherwise, - * on 394x and 398x cards we'll end up reading the wrong settings - * for channels B and C - */ - switch (temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7892: - case AHC_AIC7899: - aic_outb(temp_p, 0, SCAMCTL); - /* - * Switch to the alt mode of the chip... - */ - aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT); - /* - * Set our options...the last two items set our CRC after x byte - * count in target mode... - */ - aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE); - aic_outb(temp_p, 0x00, 0x0b); - aic_outb(temp_p, 0x10, 0x0a); - /* - * switch back to normal mode... - */ - aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT); - aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN | - TARGCRCENDEN | TARGCRCCNTEN, - CRCCONTROL1); - aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 | - MPARCKEN | CIOPARCKEN | CACHETHEN) & - ~DPARCKEN), DSCOMMAND0); - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7890: - case AHC_AIC7896: - aic_outb(temp_p, 0, SCAMCTL); - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN | USCBSIZE32 | - CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0); - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7850: - case AHC_AIC7860: - /* - * Set the DSCOMMAND0 register on these cards different from - * on the 789x cards. Also, read the SEEPROM as well. - */ - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN) & ~DPARCKEN, - DSCOMMAND0); - /* FALLTHROUGH */ - default: - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - case AHC_AIC7880: - /* - * Check the rev of the chipset before we change DSCOMMAND0 - */ - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if ((devconfig & 0xff) >= 1) - { - aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) | - CACHETHEN | MPARCKEN) & ~DPARCKEN, - DSCOMMAND0); - } - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - } - - - /* - * and then we need another switch based on the type in order to - * make sure the channel B primary flag is set properly on 7895 - * controllers....Arrrgggghhh!!! We also have to catch the fact - * that when you disable the BIOS on the 7895 on the Intel DK440LX - * motherboard, and possibly others, it only sets the BIOS disabled - * bit on the A channel...I think I'm starting to lean towards - * going postal.... - */ - switch(temp_p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - current_p = list_p; - while(current_p != NULL) - { - if ( (current_p->pci_bus == temp_p->pci_bus) && - (PCI_SLOT(current_p->pci_device_fn) == - PCI_SLOT(temp_p->pci_device_fn)) ) - { - if ( PCI_FUNC(current_p->pci_device_fn) == 0 ) - { - temp_p->flags |= - (current_p->flags & AHC_CHANNEL_B_PRIMARY); - temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS); - temp_p->flags |= - (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS)); - } - else - { - current_p->flags |= - (temp_p->flags & AHC_CHANNEL_B_PRIMARY); - current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS); - current_p->flags |= - (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS)); - } - } - current_p = current_p->next; - } - break; - default: - break; - } - - /* - * We only support external SCB RAM on the 7895/6/7 chipsets. - * We could support it on the 7890/1 easy enough, but I don't - * know of any 7890/1 based cards that have it. I do know - * of 7895/6/7 cards that have it and they work properly. - */ - switch(temp_p->chip & AHC_CHIPID_MASK) - { - default: - break; - case AHC_AIC7895: - case AHC_AIC7896: - case AHC_AIC7899: - pci_read_config_dword(pdev, DEVCONFIG, &devconfig); - if (temp_p->features & AHC_ULTRA2) - { - if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) && - (aic7xxx_scbram) ) - { - aic_outb(temp_p, - aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2, - DSCOMMAND0); - temp_p->flags |= AHC_EXTERNAL_SRAM; - devconfig |= EXTSCBPEN; - } - else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) - { - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: external SCB RAM detected, " - "but not enabled\n"); - } - } - else - { - if ((devconfig & RAMPSM) && (aic7xxx_scbram)) - { - devconfig &= ~SCBRAMSEL; - devconfig |= EXTSCBPEN; - temp_p->flags |= AHC_EXTERNAL_SRAM; - } - else if (devconfig & RAMPSM) - { - printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", - board_names[aic_pdevs[i].board_name_index], - temp_p->pci_bus, - PCI_SLOT(temp_p->pci_device_fn), - PCI_FUNC(temp_p->pci_device_fn)); - printk("aic7xxx: external SCB RAM detected, " - "but not enabled\n"); - } - } - pci_write_config_dword(pdev, DEVCONFIG, devconfig); - if ( (temp_p->flags & AHC_EXTERNAL_SRAM) && - (temp_p->flags & AHC_CHNLB) ) - aic_outb(temp_p, 1, CCSCBBADDR); - break; - } - - /* - * Take the LED out of diagnostic mode - */ - aic_outb(temp_p, - (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)), - SBLKCTL); - - /* - * We don't know where this is set in the SEEPROM or by the - * BIOS, so we default to 100%. On Ultra2 controllers, use 75% - * instead. - */ - if (temp_p->features & AHC_ULTRA2) - { - aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH); - } - else - { - aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS); - } - - /* - * Call our function to fixup any bugs that exist on this chipset. - * This may muck with PCI settings and other device settings, so - * make sure it's after all the other PCI and device register - * tweaks so it can back out bad settings on specific broken cards. - */ - aic7xxx_configure_bugs(temp_p); - - /* Hold a pci device reference */ - pci_dev_get(temp_p->pdev); - - if ( list_p == NULL ) - { - list_p = current_p = temp_p; - } - else - { - current_p = list_p; - while(current_p->next != NULL) - current_p = current_p->next; - current_p->next = temp_p; - } - temp_p->next = NULL; - found++; - continue; -skip_pci_controller: -#ifdef CONFIG_PCI - pci_release_regions(temp_p->pdev); -#endif - kfree(temp_p); - } /* Found an Adaptec PCI device. */ - else /* Well, we found one, but we couldn't get any memory */ - { - printk("aic7xxx: Found <%s>\n", - board_names[aic_pdevs[i].board_name_index]); - printk(KERN_INFO "aic7xxx: Unable to allocate device memory, " - "skipping.\n"); - } - } /* while(pdev=....) */ - } /* for PCI_DEVICES */ - } -#endif /* CONFIG_PCI */ - -#if defined(__i386__) || defined(__alpha__) - /* - * EISA/VL-bus card signature probe. - */ - slot = MINSLOT; - while ( (slot <= MAXSLOT) && - !(aic7xxx_no_probe) ) - { - base = SLOTBASE(slot) + MINREG; - - if (!request_region(base, MAXREG - MINREG, "aic7xxx")) - { - /* - * Some other driver has staked a - * claim to this i/o region already. - */ - slot++; - continue; /* back to the beginning of the for loop */ - } - flags = 0; - type = aic7xxx_probe(slot, base + AHC_HID0, &flags); - if (type == -1) - { - release_region(base, MAXREG - MINREG); - slot++; - continue; - } - temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC); - if (temp_p == NULL) - { - printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n"); - release_region(base, MAXREG - MINREG); - slot++; - continue; /* back to the beginning of the while loop */ - } - - /* - * Pause the card preserving the IRQ type. Allow the operator - * to override the IRQ trigger. - */ - if (aic7xxx_irq_trigger == 1) - hcntrl = IRQMS; /* Level */ - else if (aic7xxx_irq_trigger == 0) - hcntrl = 0; /* Edge */ - else - hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */ - memset(temp_p, 0, sizeof(struct aic7xxx_host)); - temp_p->unpause = hcntrl | INTEN; - temp_p->pause = hcntrl | PAUSE | INTEN; - temp_p->base = base; - temp_p->mbase = 0; - temp_p->maddr = NULL; - temp_p->pci_bus = 0; - temp_p->pci_device_fn = slot; - aic_outb(temp_p, hcntrl | PAUSE, HCNTRL); - while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ; - if (aic7xxx_chip_reset(temp_p) == -1) - temp_p->irq = 0; - else - temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F; - temp_p->flags |= AHC_PAGESCBS; - - switch (temp_p->irq) - { - case 9: - case 10: - case 11: - case 12: - case 14: - case 15: - break; - - default: - printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ " - "level %d, ignoring.\n", temp_p->irq); - kfree(temp_p); - release_region(base, MAXREG - MINREG); - slot++; - continue; /* back to the beginning of the while loop */ - } - - /* - * We are committed now, everything has been checked and this card - * has been found, now we just set it up - */ - - /* - * Insert our new struct into the list at the end - */ - if (list_p == NULL) - { - list_p = current_p = temp_p; - } - else - { - current_p = list_p; - while (current_p->next != NULL) - current_p = current_p->next; - current_p->next = temp_p; - } - - switch (type) - { - case 0: - temp_p->board_name_index = 2; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at EISA %d\n", - board_names[2], slot); - /* FALLTHROUGH */ - case 1: - { - temp_p->chip = AHC_AIC7770 | AHC_EISA; - temp_p->features |= AHC_AIC7770_FE; - temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL); - - /* - * Get the primary channel information. Right now we don't - * do anything with this, but someday we will be able to inform - * the mid-level SCSI code which channel is primary. - */ - if (temp_p->board_name_index == 0) - { - temp_p->board_name_index = 3; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at EISA %d\n", - board_names[3], slot); - } - if (temp_p->bios_control & CHANNEL_B_PRIMARY) - { - temp_p->flags |= AHC_CHANNEL_B_PRIMARY; - } - - if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED) - { - temp_p->flags &= ~AHC_BIOS_ENABLED; - } - else - { - temp_p->flags &= ~AHC_USEDEFAULTS; - temp_p->flags |= AHC_BIOS_ENABLED; - if ( (temp_p->bios_control & 0x20) == 0 ) - { - temp_p->bios_address = 0xcc000; - temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07)); - } - else - { - temp_p->bios_address = 0xd0000; - temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06)); - } - } - temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8; - temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1); - if (temp_p->features & AHC_WIDE) - { - temp_p->scsi_id = temp_p->adapter_control & HWSCSIID; - temp_p->scsi_id_b = temp_p->scsi_id; - } - else - { - temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID; - temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID; - } - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - break; - } - - case 2: - case 3: - temp_p->chip = AHC_AIC7770 | AHC_VL; - temp_p->features |= AHC_AIC7770_FE; - if (type == 2) - temp_p->flags |= AHC_BIOS_ENABLED; - else - temp_p->flags &= ~AHC_BIOS_ENABLED; - if (aic_inb(temp_p, SCSICONF) & TERM_ENB) - sxfrctl1 = STPWEN; - aic7xxx_load_seeprom(temp_p, &sxfrctl1); - temp_p->board_name_index = 4; - if (aic7xxx_verbose & VERBOSE_PROBE2) - printk("aic7xxx: <%s> at VLB %d\n", - board_names[2], slot); - switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL ) - { - case 0x00: - temp_p->bios_address = 0xe0000; - break; - case 0x20: - temp_p->bios_address = 0xc8000; - break; - case 0x40: - temp_p->bios_address = 0xd0000; - break; - case 0x60: - temp_p->bios_address = 0xd8000; - break; - default: - break; /* can't get here */ - } - break; - - default: /* Won't get here. */ - break; - } - if (aic7xxx_verbose & VERBOSE_PROBE2) - { - printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n", - (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base, - temp_p->irq, - (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered"); - printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n", - (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis"); - } - - /* - * All the 7770 based chipsets have this bug - */ - temp_p->bugs |= AHC_BUG_TMODE_WIDEODD; - - /* - * Set the FIFO threshold and the bus off time. - */ - hostconf = aic_inb(temp_p, HOSTCONF); - aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD); - aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME); - slot++; - found++; - } - -#endif /* defined(__i386__) || defined(__alpha__) */ - - /* - * Now, we re-order the probed devices by BIOS address and BUS class. - * In general, we follow this algorithm to make the adapters show up - * in the same order under linux that the computer finds them. - * 1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS - * address, going from lowest to highest. - * 2: All PCI controllers with BIOS_ENABLED next, according to BIOS - * address, going from lowest to highest. - * 3: Remaining VLB/EISA controllers going in slot order. - * 4: Remaining PCI controllers, going in PCI device order (reversible) - */ - - { - struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL }; - struct aic7xxx_host *vlb, *pci; - struct aic7xxx_host *prev_p; - struct aic7xxx_host *p; - unsigned char left; - - prev_p = vlb = pci = NULL; - - temp_p = list_p; - while (temp_p != NULL) - { - switch(temp_p->chip & ~AHC_CHIPID_MASK) - { - case AHC_EISA: - case AHC_VL: - { - p = temp_p; - if (p->flags & AHC_BIOS_ENABLED) - vlb = sort_list[0]; - else - vlb = sort_list[2]; - - if (vlb == NULL) - { - vlb = temp_p; - temp_p = temp_p->next; - vlb->next = NULL; - } - else - { - current_p = vlb; - prev_p = NULL; - while ( (current_p != NULL) && - (current_p->bios_address < temp_p->bios_address)) - { - prev_p = current_p; - current_p = current_p->next; - } - if (prev_p != NULL) - { - prev_p->next = temp_p; - temp_p = temp_p->next; - prev_p->next->next = current_p; - } - else - { - vlb = temp_p; - temp_p = temp_p->next; - vlb->next = current_p; - } - } - - if (p->flags & AHC_BIOS_ENABLED) - sort_list[0] = vlb; - else - sort_list[2] = vlb; - - break; - } - default: /* All PCI controllers fall through to default */ - { - - p = temp_p; - if (p->flags & AHC_BIOS_ENABLED) - pci = sort_list[1]; - else - pci = sort_list[3]; - - if (pci == NULL) - { - pci = temp_p; - temp_p = temp_p->next; - pci->next = NULL; - } - else - { - current_p = pci; - prev_p = NULL; - if (!aic7xxx_reverse_scan) - { - while ( (current_p != NULL) && - ( (PCI_SLOT(current_p->pci_device_fn) | - (current_p->pci_bus << 8)) < - (PCI_SLOT(temp_p->pci_device_fn) | - (temp_p->pci_bus << 8)) ) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - else - { - while ( (current_p != NULL) && - ( (PCI_SLOT(current_p->pci_device_fn) | - (current_p->pci_bus << 8)) > - (PCI_SLOT(temp_p->pci_device_fn) | - (temp_p->pci_bus << 8)) ) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - /* - * Are we dealing with a 7895/6/7/9 where we need to sort the - * channels as well, if so, the bios_address values should - * be the same - */ - if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) && - (temp_p->pci_bus == current_p->pci_bus) && - (PCI_SLOT(temp_p->pci_device_fn) == - PCI_SLOT(current_p->pci_device_fn)) ) - { - if (temp_p->flags & AHC_CHNLB) - { - if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) ) - { - prev_p = current_p; - current_p = current_p->next; - } - } - else - { - if (temp_p->flags & AHC_CHANNEL_B_PRIMARY) - { - prev_p = current_p; - current_p = current_p->next; - } - } - } - if (prev_p != NULL) - { - prev_p->next = temp_p; - temp_p = temp_p->next; - prev_p->next->next = current_p; - } - else - { - pci = temp_p; - temp_p = temp_p->next; - pci->next = current_p; - } - } - - if (p->flags & AHC_BIOS_ENABLED) - sort_list[1] = pci; - else - sort_list[3] = pci; - - break; - } - } /* End of switch(temp_p->type) */ - } /* End of while (temp_p != NULL) */ - /* - * At this point, the cards have been broken into 4 sorted lists, now - * we run through the lists in order and register each controller - */ - { - int i; - - left = found; - for (i=0; iname = board_names[temp_p->board_name_index]; - p = aic7xxx_alloc(template, temp_p); - if (p != NULL) - { - p->instance = found - left; - if (aic7xxx_register(template, p, (--left)) == 0) - { - found--; - aic7xxx_release(p->host); - scsi_unregister(p->host); - } - else if (aic7xxx_dump_card) - { - pause_sequencer(p); - aic7xxx_print_card(p); - aic7xxx_print_scratch_ram(p); - unpause_sequencer(p, TRUE); - } - } - current_p = temp_p; - temp_p = (struct aic7xxx_host *)temp_p->next; - kfree(current_p); - } - } - } - } - return (found); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_buildscb - * - * Description: - * Build a SCB. - *-F*************************************************************************/ -static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd, - struct aic7xxx_scb *scb) -{ - unsigned short mask; - struct aic7xxx_hwscb *hscb; - struct aic_dev_data *aic_dev = cmd->device->hostdata; - struct scsi_device *sdptr = cmd->device; - unsigned char tindex = TARGET_INDEX(cmd); - int use_sg; - - mask = (0x01 << tindex); - hscb = scb->hscb; - - /* - * Setup the control byte if we need negotiation and have not - * already requested it. - */ - hscb->control = 0; - scb->tag_action = 0; - - if (p->discenable & mask) - { - hscb->control |= DISCENB; - /* We always force TEST_UNIT_READY to untagged */ - if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags) - { - hscb->control |= MSG_SIMPLE_Q_TAG; - scb->tag_action = MSG_SIMPLE_Q_TAG; - } - } - if ( !(aic_dev->dtr_pending) && - (aic_dev->needppr || aic_dev->needwdtr || aic_dev->needsdtr) && - (aic_dev->flags & DEVICE_DTR_SCANNED) ) - { - aic_dev->dtr_pending = 1; - scb->tag_action = 0; - hscb->control &= DISCENB; - hscb->control |= MK_MESSAGE; - if(aic_dev->needppr) - { - scb->flags |= SCB_MSGOUT_PPR; - } - else if(aic_dev->needwdtr) - { - scb->flags |= SCB_MSGOUT_WDTR; - } - else if(aic_dev->needsdtr) - { - scb->flags |= SCB_MSGOUT_SDTR; - } - scb->flags |= SCB_DTR_SCB; - } - hscb->target_channel_lun = ((cmd->device->id << 4) & 0xF0) | - ((cmd->device->channel & 0x01) << 3) | (cmd->device->lun & 0x07); - - /* - * The interpretation of request_buffer and request_bufflen - * changes depending on whether or not use_sg is zero; a - * non-zero use_sg indicates the number of elements in the - * scatter-gather array. - */ - - /* - * XXX - this relies on the host data being stored in a - * little-endian format. - */ - hscb->SCSI_cmd_length = cmd->cmd_len; - memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len); - hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd)); - - use_sg = scsi_dma_map(cmd); - BUG_ON(use_sg < 0); - - if (use_sg) { - struct scatterlist *sg; /* Must be mid-level SCSI code scatterlist */ - - /* - * We must build an SG list in adapter format, as the kernel's SG list - * cannot be used directly because of data field size (__alpha__) - * differences and the kernel SG list uses virtual addresses where - * we need physical addresses. - */ - int i; - - scb->sg_length = 0; - - - /* - * Copy the segments into the SG array. NOTE!!! - We used to - * have the first entry both in the data_pointer area and the first - * SG element. That has changed somewhat. We still have the first - * entry in both places, but now we download the address of - * scb->sg_list[1] instead of 0 to the sg pointer in the hscb. - */ - scsi_for_each_sg(cmd, sg, use_sg, i) { - unsigned int len = sg_dma_len(sg); - scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg)); - scb->sg_list[i].length = cpu_to_le32(len); - scb->sg_length += len; - } - /* Copy the first SG into the data pointer area. */ - hscb->data_pointer = scb->sg_list[0].address; - hscb->data_count = scb->sg_list[0].length; - scb->sg_count = i; - hscb->SG_segment_count = i; - hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1])); - } else { - scb->sg_count = 0; - scb->sg_length = 0; - hscb->SG_segment_count = 0; - hscb->SG_list_pointer = 0; - hscb->data_count = 0; - hscb->data_pointer = 0; - } -} - -/*+F************************************************************************* - * Function: - * aic7xxx_queue - * - * Description: - * Queue a SCB to the controller. - *-F*************************************************************************/ -static int aic7xxx_queue_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) -{ - struct aic7xxx_host *p; - struct aic7xxx_scb *scb; - struct aic_dev_data *aic_dev; - - p = (struct aic7xxx_host *) cmd->device->host->hostdata; - - aic_dev = cmd->device->hostdata; -#ifdef AIC7XXX_VERBOSE_DEBUGGING - if (aic_dev->active_cmds > aic_dev->max_q_depth) - { - printk(WARN_LEAD "Commands queued exceeds queue " - "depth, active=%d\n", - p->host_no, CTL_OF_CMD(cmd), - aic_dev->active_cmds); - } -#endif - - scb = scbq_remove_head(&p->scb_data->free_scbs); - if (scb == NULL) - { - aic7xxx_allocate_scb(p); - scb = scbq_remove_head(&p->scb_data->free_scbs); - if(scb == NULL) - { - printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no, - CTL_OF_CMD(cmd)); - return 1; - } - } - scb->cmd = cmd; - - /* - * Make sure the scsi_cmnd pointer is saved, the struct it points to - * is set up properly, and the parity error flag is reset, then send - * the SCB to the sequencer and watch the fun begin. - */ - aic7xxx_position(cmd) = scb->hscb->tag; - cmd->scsi_done = fn; - cmd->result = DID_OK; - aic7xxx_error(cmd) = DID_OK; - aic7xxx_status(cmd) = 0; - cmd->host_scribble = NULL; - - /* - * Construct the SCB beforehand, so the sequencer is - * paused a minimal amount of time. - */ - aic7xxx_buildscb(p, cmd, scb); - - scb->flags |= SCB_ACTIVE | SCB_WAITINGQ; - - scbq_insert_tail(&p->waiting_scbs, scb); - aic7xxx_run_waiting_queues(p); - return (0); -} - -static DEF_SCSI_QCMD(aic7xxx_queue) - -/*+F************************************************************************* - * Function: - * aic7xxx_bus_device_reset - * - * Description: - * Abort or reset the current SCSI command(s). If the scb has not - * previously been aborted, then we attempt to send a BUS_DEVICE_RESET - * message to the target. If the scb has previously been unsuccessfully - * aborted, then we will reset the channel and have all devices renegotiate. - * Returns an enumerated type that indicates the status of the operation. - *-F*************************************************************************/ -static int __aic7xxx_bus_device_reset(struct scsi_cmnd *cmd) -{ - struct aic7xxx_host *p; - struct aic7xxx_scb *scb; - struct aic7xxx_hwscb *hscb; - int channel; - unsigned char saved_scbptr, lastphase; - unsigned char hscb_index; - int disconnected; - struct aic_dev_data *aic_dev; - - if(cmd == NULL) - { - printk(KERN_ERR "aic7xxx_bus_device_reset: called with NULL cmd!\n"); - return FAILED; - } - p = (struct aic7xxx_host *)cmd->device->host->hostdata; - aic_dev = AIC_DEV(cmd); - if(aic7xxx_position(cmd) < p->scb_data->numscbs) - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - else - return FAILED; - - hscb = scb->hscb; - - aic7xxx_isr(p); - aic7xxx_done_cmds_complete(p); - /* If the command was already complete or just completed, then we didn't - * do a reset, return FAILED */ - if(!(scb->flags & SCB_ACTIVE)) - return FAILED; - - pause_sequencer(p); - lastphase = aic_inb(p, LASTPHASE); - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - { - printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ", - p->host_no, CTL_OF_SCB(scb), scb->flags); - switch (lastphase) - { - case P_DATAOUT: - printk("Data-Out phase\n"); - break; - case P_DATAIN: - printk("Data-In phase\n"); - break; - case P_COMMAND: - printk("Command phase\n"); - break; - case P_MESGOUT: - printk("Message-Out phase\n"); - break; - case P_STATUS: - printk("Status phase\n"); - break; - case P_MESGIN: - printk("Message-In phase\n"); - break; - default: - /* - * We're not in a valid phase, so assume we're idle. - */ - printk("while idle, LASTPHASE = 0x%x\n", lastphase); - break; - } - printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 " - "0x%x\n", p->host_no, CTL_OF_SCB(scb), - aic_inb(p, SCSISIGI), - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, SSTAT0), aic_inb(p, SSTAT1)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no, - CTL_OF_SCB(scb), - (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0, - aic_inb(p, SSTAT2), - aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 | - aic_inb(p, STCNT)); - } - - channel = cmd->device->channel; - - /* - * Send a Device Reset Message: - * The target that is holding up the bus may not be the same as - * the one that triggered this timeout (different commands have - * different timeout lengths). Our strategy here is to queue an - * abort message to the timed out target if it is disconnected. - * Otherwise, if we have an active target we stuff the message buffer - * with an abort message and assert ATN in the hopes that the target - * will let go of the bus and go to the mesgout phase. If this - * fails, we'll get another timeout a few seconds later which will - * attempt a bus reset. - */ - saved_scbptr = aic_inb(p, SCBPTR); - disconnected = FALSE; - - if (lastphase != P_BUSFREE) - { - if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs) - { - printk(WARN_LEAD "Invalid SCB ID %d is active, " - "SCB flags = 0x%x.\n", p->host_no, - CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags); - unpause_sequencer(p, FALSE); - return FAILED; - } - if (scb->hscb->tag == aic_inb(p, SCB_TAG)) - { - if ( (lastphase == P_MESGOUT) || (lastphase == P_MESGIN) ) - { - printk(WARN_LEAD "Device reset, Message buffer " - "in use\n", p->host_no, CTL_OF_SCB(scb)); - unpause_sequencer(p, FALSE); - return FAILED; - } - - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Device reset message in " - "message buffer\n", p->host_no, CTL_OF_SCB(scb)); - scb->flags |= SCB_RESET | SCB_DEVICE_RESET; - aic7xxx_error(cmd) = DID_RESET; - aic_dev->flags |= BUS_DEVICE_RESET_PENDING; - /* Send the abort message to the active SCB. */ - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, lastphase | ATNO, SCSISIGO); - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - ssleep(1); - spin_lock_irq(p->host->host_lock); - if(aic_dev->flags & BUS_DEVICE_RESET_PENDING) - return FAILED; - else - return SUCCESS; - } - } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */ - /* - * Simply set the MK_MESSAGE flag and the SEQINT handler will do - * the rest on a reconnect/connect. - */ - scb->hscb->control |= MK_MESSAGE; - scb->flags |= SCB_RESET | SCB_DEVICE_RESET; - aic_dev->flags |= BUS_DEVICE_RESET_PENDING; - /* - * Check to see if the command is on the qinfifo. If it is, then we will - * not need to queue the command again since the card should start it soon - */ - if (aic7xxx_search_qinfifo(p, cmd->device->channel, cmd->device->id, cmd->device->lun, hscb->tag, - 0, TRUE, NULL) == 0) - { - disconnected = TRUE; - if ((hscb_index = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL) - { - unsigned char scb_control; - - aic_outb(p, hscb_index, SCBPTR); - scb_control = aic_inb(p, SCB_CONTROL); - /* - * If the DISCONNECTED bit is not set in SCB_CONTROL, then we are - * actually on the waiting list, not disconnected, and we don't - * need to requeue the command. - */ - disconnected = (scb_control & DISCONNECTED); - aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL); - } - if (disconnected) - { - /* - * Actually requeue this SCB in case we can select the - * device before it reconnects. This can result in the command - * being on the qinfifo twice, but we don't care because it will - * all get cleaned up if/when the reset takes place. - */ - if (aic7xxx_verbose & VERBOSE_RESET_PROCESS) - printk(INFO_LEAD "Queueing device reset command.\n", p->host_no, - CTL_OF_SCB(scb)); - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - scb->flags |= SCB_QUEUED_ABORT; - } - } - aic_outb(p, saved_scbptr, SCBPTR); - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - msleep(1000/4); - spin_lock_irq(p->host->host_lock); - if(aic_dev->flags & BUS_DEVICE_RESET_PENDING) - return FAILED; - else - return SUCCESS; -} - -static int aic7xxx_bus_device_reset(struct scsi_cmnd *cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __aic7xxx_bus_device_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_panic_abort - * - * Description: - * Abort the current SCSI command(s). - *-F*************************************************************************/ -static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd) -{ - - printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION); - printk("Controller type:\n %s\n", board_names[p->board_name_index]); - printk("p->flags=0x%lx, p->chip=0x%x, p->features=0x%x, " - "sequencer %s paused\n", - p->flags, p->chip, p->features, - (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" ); - pause_sequencer(p); - disable_irq(p->irq); - aic7xxx_print_card(p); - aic7xxx_print_scratch_ram(p); - spin_unlock_irq(p->host->host_lock); - for(;;) barrier(); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_abort - * - * Description: - * Abort the current SCSI command(s). - *-F*************************************************************************/ -static int __aic7xxx_abort(struct scsi_cmnd *cmd) -{ - struct aic7xxx_scb *scb = NULL; - struct aic7xxx_host *p; - int found=0, disconnected; - unsigned char saved_hscbptr, hscbptr, scb_control; - struct aic_dev_data *aic_dev; - - if(cmd == NULL) - { - printk(KERN_ERR "aic7xxx_abort: called with NULL cmd!\n"); - return FAILED; - } - p = (struct aic7xxx_host *)cmd->device->host->hostdata; - aic_dev = AIC_DEV(cmd); - if(aic7xxx_position(cmd) < p->scb_data->numscbs) - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - else - return FAILED; - - aic7xxx_isr(p); - aic7xxx_done_cmds_complete(p); - /* If the command was already complete or just completed, then we didn't - * do a reset, return FAILED */ - if(!(scb->flags & SCB_ACTIVE)) - return FAILED; - - pause_sequencer(p); - - /* - * I added a new config option to the driver: "panic_on_abort" that will - * cause the driver to panic and the machine to stop on the first abort - * or reset call into the driver. At that point, it prints out a lot of - * useful information for me which I can then use to try and debug the - * problem. Simply enable the boot time prompt in order to activate this - * code. - */ - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, cmd); - - if (aic7xxx_verbose & VERBOSE_ABORT) - { - printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE " - "0x%x\n", - p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags, - aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8), - aic_inb(p, LASTPHASE)); - printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n", - p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ? - aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT), - aic_inb(p, SCSISIGI)); - printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n", - p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0), - aic_inb(p, SSTAT1), aic_inb(p, SSTAT2)); - } - - if (scb->flags & SCB_WAITINGQ) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB found on waiting list and " - "aborted.\n", p->host_no, CTL_OF_SCB(scb)); - scbq_remove(&p->waiting_scbs, scb); - scbq_remove(&aic_dev->delayed_scbs, scb); - aic_dev->active_cmds++; - p->activescbs++; - scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE); - scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE; - goto success; - } - -/* - * We just checked the waiting_q, now for the QINFIFO - */ - if ( ((found = aic7xxx_search_qinfifo(p, cmd->device->id, cmd->device->channel, - cmd->device->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE, - FALSE, NULL)) != 0) && - (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)) - { - printk(INFO_LEAD "SCB found in QINFIFO and aborted.\n", p->host_no, - CTL_OF_SCB(scb)); - goto success; - } - -/* - * QINFIFO, waitingq, completeq done. Next, check WAITING_SCB list in card - */ - - saved_hscbptr = aic_inb(p, SCBPTR); - if ((hscbptr = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL) - { - aic_outb(p, hscbptr, SCBPTR); - scb_control = aic_inb(p, SCB_CONTROL); - disconnected = scb_control & DISCONNECTED; - /* - * If the DISCONNECTED bit is not set in SCB_CONTROL, then we are - * either currently active or on the waiting list. - */ - if(!disconnected && aic_inb(p, LASTPHASE) == P_BUSFREE) { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB found on hardware waiting" - " list and aborted.\n", p->host_no, CTL_OF_SCB(scb)); - /* If we are the only waiting command, stop the selection engine */ - if (aic_inb(p, WAITING_SCBH) == hscbptr && aic_inb(p, SCB_NEXT) == - SCB_LIST_NULL) - { - aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ); - aic_outb(p, CLRSELTIMEO, CLRSINT1); - aic_outb(p, SCB_LIST_NULL, WAITING_SCBH); - } - else - { - unsigned char prev, next; - prev = SCB_LIST_NULL; - next = aic_inb(p, WAITING_SCBH); - while(next != SCB_LIST_NULL) - { - aic_outb(p, next, SCBPTR); - if (next == hscbptr) - { - next = aic_inb(p, SCB_NEXT); - if (prev != SCB_LIST_NULL) - { - aic_outb(p, prev, SCBPTR); - aic_outb(p, next, SCB_NEXT); - } - else - aic_outb(p, next, WAITING_SCBH); - aic_outb(p, hscbptr, SCBPTR); - next = SCB_LIST_NULL; - } - else - { - prev = next; - next = aic_inb(p, SCB_NEXT); - } - } - } - aic_outb(p, SCB_LIST_NULL, SCB_TAG); - aic_outb(p, 0, SCB_CONTROL); - aic7xxx_add_curscb_to_free_list(p); - scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE; - goto success; - } - else if (!disconnected) - { - /* - * We are the currently active command - */ - if((aic_inb(p, LASTPHASE) == P_MESGIN) || - (aic_inb(p, LASTPHASE) == P_MESGOUT)) - { - /* - * Message buffer busy, unable to abort - */ - printk(INFO_LEAD "message buffer busy, unable to abort.\n", - p->host_no, CTL_OF_SCB(scb)); - unpause_sequencer(p, FALSE); - return FAILED; - } - /* Fallthrough to below, set ATNO after we set SCB_CONTROL */ - } - aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL); - if(!disconnected) - { - aic_outb(p, HOST_MSG, MSG_OUT); - aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO); - } - aic_outb(p, saved_hscbptr, SCBPTR); - } - else - { - /* - * The scb isn't in the card at all and it is active and it isn't in - * any of the queues, so it must be disconnected and paged out. Fall - * through to the code below. - */ - disconnected = 1; - } - - p->flags |= AHC_ABORT_PENDING; - scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB; - scb->hscb->control |= MK_MESSAGE; - if(disconnected) - { - if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) - printk(INFO_LEAD "SCB disconnected. Queueing Abort" - " SCB.\n", p->host_no, CTL_OF_SCB(scb)); - p->qinfifo[p->qinfifonext++] = scb->hscb->tag; - if (p->features & AHC_QUEUE_REGS) - aic_outb(p, p->qinfifonext, HNSCB_QOFF); - else - aic_outb(p, p->qinfifonext, KERNEL_QINPOS); - } - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - msleep(1000/4); - spin_lock_irq(p->host->host_lock); - if (p->flags & AHC_ABORT_PENDING) - { - if (aic7xxx_verbose & VERBOSE_ABORT_RETURN) - printk(INFO_LEAD "Abort never delivered, returning FAILED\n", p->host_no, - CTL_OF_CMD(cmd)); - p->flags &= ~AHC_ABORT_PENDING; - return FAILED; - } - if (aic7xxx_verbose & VERBOSE_ABORT_RETURN) - printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd)); - return SUCCESS; - -success: - if (aic7xxx_verbose & VERBOSE_ABORT_RETURN) - printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd)); - aic7xxx_run_done_queue(p, TRUE); - unpause_sequencer(p, FALSE); - return SUCCESS; -} - -static int aic7xxx_abort(struct scsi_cmnd *cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __aic7xxx_abort(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_reset - * - * Description: - * Resetting the bus always succeeds - is has to, otherwise the - * kernel will panic! Try a surgical technique - sending a BUS - * DEVICE RESET message - on the offending target before pulling - * the SCSI bus reset line. - *-F*************************************************************************/ -static int aic7xxx_reset(struct scsi_cmnd *cmd) -{ - struct aic7xxx_scb *scb; - struct aic7xxx_host *p; - struct aic_dev_data *aic_dev; - - p = (struct aic7xxx_host *) cmd->device->host->hostdata; - spin_lock_irq(p->host->host_lock); - - aic_dev = AIC_DEV(cmd); - if(aic7xxx_position(cmd) < p->scb_data->numscbs) - { - scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]); - if (scb->cmd != cmd) - scb = NULL; - } - else - { - scb = NULL; - } - - /* - * I added a new config option to the driver: "panic_on_abort" that will - * cause the driver to panic and the machine to stop on the first abort - * or reset call into the driver. At that point, it prints out a lot of - * useful information for me which I can then use to try and debug the - * problem. Simply enable the boot time prompt in order to activate this - * code. - */ - if (aic7xxx_panic_on_abort) - aic7xxx_panic_abort(p, cmd); - - pause_sequencer(p); - - while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR)) - { - aic7xxx_isr(p); - pause_sequencer(p); - } - aic7xxx_done_cmds_complete(p); - - if(scb && (scb->cmd == NULL)) - { - /* - * We just completed the command when we ran the isr stuff, so we no - * longer have it. - */ - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - return SUCCESS; - } - -/* - * By this point, we want to already know what we are going to do and - * only have the following code implement our course of action. - */ - aic7xxx_reset_channel(p, cmd->device->channel, TRUE); - if (p->features & AHC_TWIN) - { - aic7xxx_reset_channel(p, cmd->device->channel ^ 0x01, TRUE); - restart_sequencer(p); - } - aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1); - aic7xxx_clear_intstat(p); - p->flags &= ~AHC_HANDLING_REQINITS; - p->msg_type = MSG_TYPE_NONE; - p->msg_index = 0; - p->msg_len = 0; - aic7xxx_run_done_queue(p, TRUE); - unpause_sequencer(p, FALSE); - spin_unlock_irq(p->host->host_lock); - ssleep(2); - return SUCCESS; -} - -/*+F************************************************************************* - * Function: - * aic7xxx_biosparam - * - * Description: - * Return the disk geometry for the given SCSI device. - * - * Note: - * This function is broken for today's really large drives and needs - * fixed. - *-F*************************************************************************/ -static int -aic7xxx_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - sector_t heads, sectors, cylinders; - int ret; - struct aic7xxx_host *p; - unsigned char *buf; - - p = (struct aic7xxx_host *) sdev->host->hostdata; - buf = scsi_bios_ptable(bdev); - - if ( buf ) - { - ret = scsi_partsize(buf, capacity, &geom[2], &geom[0], &geom[1]); - kfree(buf); - if ( ret != -1 ) - return(ret); - } - - heads = 64; - sectors = 32; - cylinders = capacity >> 11; - - if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024)) - { - heads = 255; - sectors = 63; - cylinders = capacity >> 14; - if(capacity > (65535 * heads * sectors)) - cylinders = 65535; - else - cylinders = ((unsigned int)capacity) / (unsigned int)(heads * sectors); - } - - geom[0] = (int)heads; - geom[1] = (int)sectors; - geom[2] = (int)cylinders; - - return (0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_release - * - * Description: - * Free the passed in Scsi_Host memory structures prior to unloading the - * module. - *-F*************************************************************************/ -static int -aic7xxx_release(struct Scsi_Host *host) -{ - struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata; - struct aic7xxx_host *next, *prev; - - if(p->irq) - free_irq(p->irq, p); -#ifdef MMAPIO - if(p->maddr) - { - iounmap(p->maddr); - } -#endif /* MMAPIO */ - if(!p->pdev) - release_region(p->base, MAXREG - MINREG); -#ifdef CONFIG_PCI - else { - pci_release_regions(p->pdev); - pci_dev_put(p->pdev); - } -#endif - prev = NULL; - next = first_aic7xxx; - while(next != NULL) - { - if(next == p) - { - if(prev == NULL) - first_aic7xxx = next->next; - else - prev->next = next->next; - } - else - { - prev = next; - } - next = next->next; - } - aic7xxx_free(p); - return(0); -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_card - * - * Description: - * Print out all of the control registers on the card - * - * NOTE: This function is not yet safe for use on the VLB and EISA - * controllers, so it isn't used on those controllers at all. - *-F*************************************************************************/ -static void -aic7xxx_print_card(struct aic7xxx_host *p) -{ - int i, j, k, chip; - static struct register_ranges { - int num_ranges; - int range_val[32]; - } cards_ds[] = { - { 0, {0,} }, /* none */ - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} }, - { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/ - 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/ - 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} }, - {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f, - 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc, - 0xfe, 0xff} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/ - 0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, - 0x9f, 0x9f, 0xe0, 0xf1} }, - {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f, - 0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc, - 0xfe, 0xff} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, - 0xe0, 0xf1, 0xf4, 0xfc} }, - {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/ - 0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f, - 0xe0, 0xf1, 0xf4, 0xfc} }, - }; - chip = p->chip & AHC_CHIPID_MASK; - printk("%s at ", - board_names[p->board_name_index]); - switch(p->chip & ~AHC_CHIPID_MASK) - { - case AHC_VL: - printk("VLB Slot %d.\n", p->pci_device_fn); - break; - case AHC_EISA: - printk("EISA Slot %d.\n", p->pci_device_fn); - break; - case AHC_PCI: - default: - printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn), - PCI_FUNC(p->pci_device_fn)); - break; - } - - /* - * the registers on the card.... - */ - printk("Card Dump:\n"); - k = 0; - for(i=0; ifeatures & AHC_QUEUE_REGS) - { - aic_outb(p, 0, SDSCB_QOFF); - aic_outb(p, 0, SNSCB_QOFF); - aic_outb(p, 0, HNSCB_QOFF); - } - -} - -/*+F************************************************************************* - * Function: - * aic7xxx_print_scratch_ram - * - * Description: - * Print out the scratch RAM values on the card. - *-F*************************************************************************/ -static void -aic7xxx_print_scratch_ram(struct aic7xxx_host *p) -{ - int i, k; - - k = 0; - printk("Scratch RAM:\n"); - for(i = SRAM_BASE; i < SEQCTL; i++) - { - printk("%02x:%02x ", i, aic_inb(p, i)); - if(++k == 13) - { - printk("\n"); - k=0; - } - } - if (p->features & AHC_MORE_SRAM) - { - for(i = TARG_OFFSET; i < 0x80; i++) - { - printk("%02x:%02x ", i, aic_inb(p, i)); - if(++k == 13) - { - printk("\n"); - k=0; - } - } - } - printk("\n"); -} - - -#include "aic7xxx_old/aic7xxx_proc.c" - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(AIC7XXX_H_VERSION); - - -static struct scsi_host_template driver_template = { - .proc_info = aic7xxx_proc_info, - .detect = aic7xxx_detect, - .release = aic7xxx_release, - .info = aic7xxx_info, - .queuecommand = aic7xxx_queue, - .slave_alloc = aic7xxx_slave_alloc, - .slave_configure = aic7xxx_slave_configure, - .slave_destroy = aic7xxx_slave_destroy, - .bios_param = aic7xxx_biosparam, - .eh_abort_handler = aic7xxx_abort, - .eh_device_reset_handler = aic7xxx_bus_device_reset, - .eh_host_reset_handler = aic7xxx_reset, - .can_queue = 255, - .this_id = -1, - .max_sectors = 2048, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, -}; - -#include "scsi_module.c" - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.h deleted file mode 100644 index 0116c812..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.h +++ /dev/null @@ -1,28 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver for Linux. - * - * Copyright (c) 1994 John Aycock - * The University of Calgary Department of Computer Science. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $ - *-M*************************************************************************/ -#ifndef _aic7xxx_h -#define _aic7xxx_h - -#define AIC7XXX_H_VERSION "5.2.0" - -#endif /* _aic7xxx_h */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.reg b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.reg deleted file mode 100644 index f67b4bce..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.reg +++ /dev/null @@ -1,1401 +0,0 @@ -/* - * Aic7xxx register and scratch ram definitions. - * - * Copyright (c) 1994-1998 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $ - */ - -/* - * This file is processed by the aic7xxx_asm utility for use in assembling - * firmware for the aic7xxx family of SCSI host adapters as well as to generate - * a C header file for use in the kernel portion of the Aic7xxx driver. - * - * All page numbers refer to the Adaptec AIC-7770 Data Book available from - * Adaptec's Technical Documents Department 1-800-934-2766 - */ - -/* - * SCSI Sequence Control (p. 3-11). - * Each bit, when set starts a specific SCSI sequence on the bus - */ -register SCSISEQ { - address 0x000 - access_mode RW - bit TEMODE 0x80 - bit ENSELO 0x40 - bit ENSELI 0x20 - bit ENRSELI 0x10 - bit ENAUTOATNO 0x08 - bit ENAUTOATNI 0x04 - bit ENAUTOATNP 0x02 - bit SCSIRSTO 0x01 -} - -/* - * SCSI Transfer Control 0 Register (pp. 3-13). - * Controls the SCSI module data path. - */ -register SXFRCTL0 { - address 0x001 - access_mode RW - bit DFON 0x80 - bit DFPEXP 0x40 - bit FAST20 0x20 - bit CLRSTCNT 0x10 - bit SPIOEN 0x08 - bit SCAMEN 0x04 - bit CLRCHN 0x02 -} - -/* - * SCSI Transfer Control 1 Register (pp. 3-14,15). - * Controls the SCSI module data path. - */ -register SXFRCTL1 { - address 0x002 - access_mode RW - bit BITBUCKET 0x80 - bit SWRAPEN 0x40 - bit ENSPCHK 0x20 - mask STIMESEL 0x18 - bit ENSTIMER 0x04 - bit ACTNEGEN 0x02 - bit STPWEN 0x01 /* Powered Termination */ -} - -/* - * SCSI Control Signal Read Register (p. 3-15). - * Reads the actual state of the SCSI bus pins - */ -register SCSISIGI { - address 0x003 - access_mode RO - bit CDI 0x80 - bit IOI 0x40 - bit MSGI 0x20 - bit ATNI 0x10 - bit SELI 0x08 - bit BSYI 0x04 - bit REQI 0x02 - bit ACKI 0x01 -/* - * Possible phases in SCSISIGI - */ - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI -} - -/* - * SCSI Control Signal Write Register (p. 3-16). - * Writing to this register modifies the control signals on the bus. Only - * those signals that are allowed in the current mode (Initiator/Target) are - * asserted. - */ -register SCSISIGO { - address 0x003 - access_mode WO - bit CDO 0x80 - bit IOO 0x40 - bit MSGO 0x20 - bit ATNO 0x10 - bit SELO 0x08 - bit BSYO 0x04 - bit REQO 0x02 - bit ACKO 0x01 -/* - * Possible phases to write into SCSISIG0 - */ - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI -} - -/* - * SCSI Rate Control (p. 3-17). - * Contents of this register determine the Synchronous SCSI data transfer - * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the - * SOFS (3:0) bits disables synchronous data transfers. Any offset value - * greater than 0 enables synchronous transfers. - */ -register SCSIRATE { - address 0x004 - access_mode RW - bit WIDEXFER 0x80 /* Wide transfer control */ - mask SXFR 0x70 /* Sync transfer rate */ - mask SXFR_ULTRA2 0x7f /* Sync transfer rate */ - mask SOFS 0x0f /* Sync offset */ -} - -/* - * SCSI ID (p. 3-18). - * Contains the ID of the board and the current target on the - * selected channel. - */ -register SCSIID { - address 0x005 - access_mode RW - mask TID 0xf0 /* Target ID mask */ - mask OID 0x0f /* Our ID mask */ - /* - * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book) - * The aic7890/91 allow an offset of up to 127 transfers in both wide - * and narrow mode. - */ - alias SCSIOFFSET - mask SOFS_ULTRA2 0x7f /* Sync offset U2 chips */ -} - -/* - * SCSI Latched Data (p. 3-19). - * Read/Write latches used to transfer data on the SCSI bus during - * Automatic or Manual PIO mode. SCSIDATH can be used for the - * upper byte of a 16bit wide asynchronouse data phase transfer. - */ -register SCSIDATL { - address 0x006 - access_mode RW -} - -register SCSIDATH { - address 0x007 - access_mode RW -} - -/* - * SCSI Transfer Count (pp. 3-19,20) - * These registers count down the number of bytes transferred - * across the SCSI bus. The counter is decremented only once - * the data has been safely transferred. SDONE in SSTAT0 is - * set when STCNT goes to 0 - */ -register STCNT { - address 0x008 - size 3 - access_mode RW -} - -/* - * Option Mode Register (Alternate Mode) (p. 5-198) - * This register is used to set certain options on Ultra3 based chips. - * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set) - */ -register OPTIONMODE { - address 0x008 - access_mode RW - bit AUTORATEEN 0x80 - bit AUTOACKEN 0x40 - bit ATNMGMNTEN 0x20 - bit BUSFREEREV 0x10 - bit EXPPHASEDIS 0x08 - bit SCSIDATL_IMGEN 0x04 - bit AUTO_MSGOUT_DE 0x02 - bit DIS_MSGIN_DUALEDGE 0x01 -} - - -/* - * Clear SCSI Interrupt 0 (p. 3-20) - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0. - */ -register CLRSINT0 { - address 0x00b - access_mode WO - bit CLRSELDO 0x40 - bit CLRSELDI 0x20 - bit CLRSELINGO 0x10 - bit CLRSWRAP 0x08 - bit CLRSPIORDY 0x02 -} - -/* - * SCSI Status 0 (p. 3-21) - * Contains one set of SCSI Interrupt codes - * These are most likely of interest to the sequencer - */ -register SSTAT0 { - address 0x00b - access_mode RO - bit TARGET 0x80 /* Board acting as target */ - bit SELDO 0x40 /* Selection Done */ - bit SELDI 0x20 /* Board has been selected */ - bit SELINGO 0x10 /* Selection In Progress */ - bit SWRAP 0x08 /* 24bit counter wrap */ - bit IOERR 0x08 /* LVD Tranceiver mode changed */ - bit SDONE 0x04 /* STCNT = 0x000000 */ - bit SPIORDY 0x02 /* SCSI PIO Ready */ - bit DMADONE 0x01 /* DMA transfer completed */ -} - -/* - * Clear SCSI Interrupt 1 (p. 3-23) - * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1. - */ -register CLRSINT1 { - address 0x00c - access_mode WO - bit CLRSELTIMEO 0x80 - bit CLRATNO 0x40 - bit CLRSCSIRSTI 0x20 - bit CLRBUSFREE 0x08 - bit CLRSCSIPERR 0x04 - bit CLRPHASECHG 0x02 - bit CLRREQINIT 0x01 -} - -/* - * SCSI Status 1 (p. 3-24) - */ -register SSTAT1 { - address 0x00c - access_mode RO - bit SELTO 0x80 - bit ATNTARG 0x40 - bit SCSIRSTI 0x20 - bit PHASEMIS 0x10 - bit BUSFREE 0x08 - bit SCSIPERR 0x04 - bit PHASECHG 0x02 - bit REQINIT 0x01 -} - -/* - * SCSI Status 2 (pp. 3-25,26) - */ -register SSTAT2 { - address 0x00d - access_mode RO - bit OVERRUN 0x80 - bit SHVALID 0x40 - bit WIDE_RES 0x20 - bit EXP_ACTIVE 0x10 /* SCSI Expander Active */ - bit CRCVALERR 0x08 /* CRC Value Error */ - bit CRCENDERR 0x04 /* CRC End Error */ - bit CRCREQERR 0x02 /* CRC REQ Error */ - bit DUAL_EDGE_ERROR 0x01 /* Invalid pins for Dual Edge phase */ - mask SFCNT 0x1f -} - -/* - * SCSI Status 3 (p. 3-26) - */ -register SSTAT3 { - address 0x00e - access_mode RO - mask SCSICNT 0xf0 - mask OFFCNT 0x0f -} - -/* - * SCSI ID for the aic7890/91 chips - */ -register SCSIID_ULTRA2 { - address 0x00f - access_mode RW - mask TID 0xf0 /* Target ID mask */ - mask OID 0x0f /* Our ID mask */ -} - -/* - * SCSI Interrupt Mode 1 (p. 3-28) - * Setting any bit will enable the corresponding function - * in SIMODE0 to interrupt via the IRQ pin. - */ -register SIMODE0 { - address 0x010 - access_mode RW - bit ENSELDO 0x40 - bit ENSELDI 0x20 - bit ENSELINGO 0x10 - bit ENSWRAP 0x08 - bit ENIOERR 0x08 /* LVD Tranceiver mode changes */ - bit ENSDONE 0x04 - bit ENSPIORDY 0x02 - bit ENDMADONE 0x01 -} - -/* - * SCSI Interrupt Mode 1 (pp. 3-28,29) - * Setting any bit will enable the corresponding function - * in SIMODE1 to interrupt via the IRQ pin. - */ -register SIMODE1 { - address 0x011 - access_mode RW - bit ENSELTIMO 0x80 - bit ENATNTARG 0x40 - bit ENSCSIRST 0x20 - bit ENPHASEMIS 0x10 - bit ENBUSFREE 0x08 - bit ENSCSIPERR 0x04 - bit ENPHASECHG 0x02 - bit ENREQINIT 0x01 -} - -/* - * SCSI Data Bus (High) (p. 3-29) - * This register reads data on the SCSI Data bus directly. - */ -register SCSIBUSL { - address 0x012 - access_mode RO -} - -register SCSIBUSH { - address 0x013 - access_mode RO -} - -/* - * SCSI/Host Address (p. 3-30) - * These registers hold the host address for the byte about to be - * transferred on the SCSI bus. They are counted up in the same - * manner as STCNT is counted down. SHADDR should always be used - * to determine the address of the last byte transferred since HADDR - * can be skewed by write ahead. - */ -register SHADDR { - address 0x014 - size 4 - access_mode RO -} - -/* - * Selection Timeout Timer (p. 3-30) - */ -register SELTIMER { - address 0x018 - access_mode RW - bit STAGE6 0x20 - bit STAGE5 0x10 - bit STAGE4 0x08 - bit STAGE3 0x04 - bit STAGE2 0x02 - bit STAGE1 0x01 -} - -/* - * Selection/Reselection ID (p. 3-31) - * Upper four bits are the device id. The ONEBIT is set when the re/selecting - * device did not set its own ID. - */ -register SELID { - address 0x019 - access_mode RW - mask SELID_MASK 0xf0 - bit ONEBIT 0x08 -} - -/* - * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book) - * Indicates if external logic has been attached to the chip to - * perform the tasks of accessing a serial eeprom, testing termination - * strength, and performing cable detection. On the aic7860, most of - * these features are handled on chip, but on the aic7855 an attached - * aic3800 does the grunt work. - */ -register SPIOCAP { - address 0x01b - access_mode RW - bit SOFT1 0x80 - bit SOFT0 0x40 - bit SOFTCMDEN 0x20 - bit HAS_BRDCTL 0x10 /* External Board control */ - bit SEEPROM 0x08 /* External serial eeprom logic */ - bit EEPROM 0x04 /* Writable external BIOS ROM */ - bit ROM 0x02 /* Logic for accessing external ROM */ - bit SSPIOCPS 0x01 /* Termination and cable detection */ -} - -/* - * SCSI Block Control (p. 3-32) - * Controls Bus type and channel selection. In a twin channel configuration - * addresses 0x00-0x1e are gated to the appropriate channel based on this - * register. SELWIDE allows for the coexistence of 8bit and 16bit devices - * on a wide bus. - */ -register SBLKCTL { - address 0x01f - access_mode RW - bit DIAGLEDEN 0x80 /* Aic78X0 only */ - bit DIAGLEDON 0x40 /* Aic78X0 only */ - bit AUTOFLUSHDIS 0x20 - bit SELBUSB 0x08 - bit ENAB40 0x08 /* LVD transceiver active */ - bit ENAB20 0x04 /* SE/HVD transceiver active */ - bit SELWIDE 0x02 - bit XCVR 0x01 /* External transceiver active */ -} - -/* - * Sequencer Control (p. 3-33) - * Error detection mode and speed configuration - */ -register SEQCTL { - address 0x060 - access_mode RW - bit PERRORDIS 0x80 - bit PAUSEDIS 0x40 - bit FAILDIS 0x20 - bit FASTMODE 0x10 - bit BRKADRINTEN 0x08 - bit STEP 0x04 - bit SEQRESET 0x02 - bit LOADRAM 0x01 -} - -/* - * Sequencer RAM Data (p. 3-34) - * Single byte window into the Scratch Ram area starting at the address - * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write - * four bytes in succession. The SEQADDRs will increment after the most - * significant byte is written - */ -register SEQRAM { - address 0x061 - access_mode RW -} - -/* - * Sequencer Address Registers (p. 3-35) - * Only the first bit of SEQADDR1 holds addressing information - */ -register SEQADDR0 { - address 0x062 - access_mode RW -} - -register SEQADDR1 { - address 0x063 - access_mode RW - mask SEQADDR1_MASK 0x01 -} - -/* - * Accumulator - * We cheat by passing arguments in the Accumulator up to the kernel driver - */ -register ACCUM { - address 0x064 - access_mode RW - accumulator -} - -register SINDEX { - address 0x065 - access_mode RW - sindex -} - -register DINDEX { - address 0x066 - access_mode RW -} - -register ALLONES { - address 0x069 - access_mode RO - allones -} - -register ALLZEROS { - address 0x06a - access_mode RO - allzeros -} - -register NONE { - address 0x06a - access_mode WO - none -} - -register FLAGS { - address 0x06b - access_mode RO - bit ZERO 0x02 - bit CARRY 0x01 -} - -register SINDIR { - address 0x06c - access_mode RO -} - -register DINDIR { - address 0x06d - access_mode WO -} - -register FUNCTION1 { - address 0x06e - access_mode RW -} - -register STACK { - address 0x06f - access_mode RO -} - -/* - * Board Control (p. 3-43) - */ -register BCTL { - address 0x084 - access_mode RW - bit ACE 0x08 - bit ENABLE 0x01 -} - -register DSCOMMAND0 { - address 0x084 - access_mode RW - bit CACHETHEN 0x80 - bit DPARCKEN 0x40 - bit MPARCKEN 0x20 - bit EXTREQLCK 0x10 - bit INTSCBRAMSEL 0x08 - bit RAMPS 0x04 - bit USCBSIZE32 0x02 - bit CIOPARCKEN 0x01 -} - -/* - * On the aic78X0 chips, Board Control is replaced by the DSCommand - * register (p. 4-64) - */ -register DSCOMMAND { - address 0x084 - access_mode RW - bit CACHETHEN 0x80 /* Cache Threshold enable */ - bit DPARCKEN 0x40 /* Data Parity Check Enable */ - bit MPARCKEN 0x20 /* Memory Parity Check Enable */ - bit EXTREQLCK 0x10 /* External Request Lock */ -} - -/* - * Bus On/Off Time (p. 3-44) - */ -register BUSTIME { - address 0x085 - access_mode RW - mask BOFF 0xf0 - mask BON 0x0f -} - -/* - * Bus Speed (p. 3-45) - */ -register BUSSPD { - address 0x086 - access_mode RW - mask DFTHRSH 0xc0 - mask STBOFF 0x38 - mask STBON 0x07 - mask DFTHRSH_100 0xc0 -} - -/* - * Host Control (p. 3-47) R/W - * Overall host control of the device. - */ -register HCNTRL { - address 0x087 - access_mode RW - bit POWRDN 0x40 - bit SWINT 0x10 - bit IRQMS 0x08 - bit PAUSE 0x04 - bit INTEN 0x02 - bit CHIPRST 0x01 - bit CHIPRSTACK 0x01 -} - -/* - * Host Address (p. 3-48) - * This register contains the address of the byte about - * to be transferred across the host bus. - */ -register HADDR { - address 0x088 - size 4 - access_mode RW -} - -register HCNT { - address 0x08c - size 3 - access_mode RW -} - -/* - * SCB Pointer (p. 3-49) - * Gate one of the four SCBs into the SCBARRAY window. - */ -register SCBPTR { - address 0x090 - access_mode RW -} - -/* - * Interrupt Status (p. 3-50) - * Status for system interrupts - */ -register INTSTAT { - address 0x091 - access_mode RW - bit BRKADRINT 0x08 - bit SCSIINT 0x04 - bit CMDCMPLT 0x02 - bit SEQINT 0x01 - mask BAD_PHASE SEQINT /* unknown scsi bus phase */ - mask SEND_REJECT 0x10|SEQINT /* sending a message reject */ - mask NO_IDENT 0x20|SEQINT /* no IDENTIFY after reconnect*/ - mask NO_MATCH 0x30|SEQINT /* no cmd match for reconnect */ - mask EXTENDED_MSG 0x40|SEQINT /* Extended message received */ - mask WIDE_RESIDUE 0x50|SEQINT /* need kernel to back up */ - /* the SG array for us */ - mask REJECT_MSG 0x60|SEQINT /* Reject message received */ - mask BAD_STATUS 0x70|SEQINT /* Bad status from target */ - mask RESIDUAL 0x80|SEQINT /* Residual byte count != 0 */ - mask AWAITING_MSG 0xa0|SEQINT /* - * Kernel requested to specify - * a message to this target - * (command was null), so tell - * it that it can fill the - * message buffer. - */ - mask SEQ_SG_FIXUP 0xb0|SEQINT /* need help with fixing up - * the sg array pointer after - * a phasemis with no valid - * sg elements in the shadow - * pipeline. - */ - mask TRACEPOINT2 0xc0|SEQINT - mask MSGIN_PHASEMIS 0xd0|SEQINT /* - * Target changed phase on us - * when we were expecting - * another msgin byte. - */ - mask DATA_OVERRUN 0xe0|SEQINT /* - * Target attempted to write - * beyond the bounds of its - * command. - */ - - mask SEQINT_MASK 0xf0|SEQINT /* SEQINT Status Codes */ - mask INT_PEND (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT) -} - -/* - * Hard Error (p. 3-53) - * Reporting of catastrophic errors. You usually cannot recover from - * these without a full board reset. - */ -register ERROR { - address 0x092 - access_mode RO - bit CIOPARERR 0x80 /* Ultra2 only */ - bit PCIERRSTAT 0x40 /* PCI only */ - bit MPARERR 0x20 /* PCI only */ - bit DPARERR 0x10 /* PCI only */ - bit SQPARERR 0x08 - bit ILLOPCODE 0x04 - bit ILLSADDR 0x02 - bit DSCTMOUT 0x02 /* Ultra3 only */ - bit ILLHADDR 0x01 -} - -/* - * Clear Interrupt Status (p. 3-52) - */ -register CLRINT { - address 0x092 - access_mode WO - bit CLRPARERR 0x10 /* PCI only */ - bit CLRBRKADRINT 0x08 - bit CLRSCSIINT 0x04 - bit CLRCMDINT 0x02 - bit CLRSEQINT 0x01 -} - -register DFCNTRL { - address 0x093 - access_mode RW - bit PRELOADEN 0x80 /* aic7890 only */ - bit WIDEODD 0x40 - bit SCSIEN 0x20 - bit SDMAEN 0x10 - bit SDMAENACK 0x10 - bit HDMAEN 0x08 - bit HDMAENACK 0x08 - bit DIRECTION 0x04 - bit FIFOFLUSH 0x02 - bit FIFORESET 0x01 -} - -register DFSTATUS { - address 0x094 - access_mode RO - bit PRELOAD_AVAIL 0x80 - bit DWORDEMP 0x20 - bit MREQPEND 0x10 - bit HDONE 0x08 - bit DFTHRESH 0x04 - bit FIFOFULL 0x02 - bit FIFOEMP 0x01 -} - -register DFDAT { - address 0x099 - access_mode RW -} - -/* - * SCB Auto Increment (p. 3-59) - * Byte offset into the SCB Array and an optional bit to allow auto - * incrementing of the address during download and upload operations - */ -register SCBCNT { - address 0x09a - access_mode RW - bit SCBAUTO 0x80 - mask SCBCNT_MASK 0x1f -} - -/* - * Queue In FIFO (p. 3-60) - * Input queue for queued SCBs (commands that the seqencer has yet to start) - */ -register QINFIFO { - address 0x09b - access_mode RW -} - -/* - * Queue In Count (p. 3-60) - * Number of queued SCBs - */ -register QINCNT { - address 0x09c - access_mode RO -} - -/* - * SCSIDATL IMAGE Register (p. 5-104) - * Write to this register also go to SCSIDATL but this register will preserve - * the data for later reading as long as the SCSIDATL_IMGEN bit in the - * OPTIONMODE register is set. - */ -register SCSIDATL_IMG { - address 0x09c - access_mode RW -} - -/* - * Queue Out FIFO (p. 3-61) - * Queue of SCBs that have completed and await the host - */ -register QOUTFIFO { - address 0x09d - access_mode WO -} - -/* - * CRC Control 1 Register (p. 5-105) - * Control bits for the Ultra 160/m CRC facilities - */ -register CRCCONTROL1 { - address 0x09d - access_mode RW - bit CRCONSEEN 0x80 /* CRC ON Single Edge ENable */ - bit CRCVALCHKEN 0x40 /* CRC Value Check Enable */ - bit CRCENDCHKEN 0x20 /* CRC End Check Enable */ - bit CRCREQCHKEN 0x10 - bit TARGCRCENDEN 0x08 /* Enable End CRC transfer when target */ - bit TARGCRCCNTEN 0x04 /* Enable CRC transfer when target */ -} - -/* - * Queue Out Count (p. 3-61) - * Number of queued SCBs in the Out FIFO - */ -register QOUTCNT { - address 0x09e - access_mode RO -} - -/* - * SCSI Phase Register (p. 5-106) - * Current bus phase - */ -register SCSIPHASE { - address 0x09e - access_mode RO - bit SP_STATUS 0x20 - bit SP_COMMAND 0x10 - bit SP_MSG_IN 0x08 - bit SP_MSG_OUT 0x04 - bit SP_DATA_IN 0x02 - bit SP_DATA_OUT 0x01 -} - -/* - * Special Function - */ -register SFUNCT { - address 0x09f - access_mode RW - bit ALT_MODE 0x80 -} - -/* - * SCB Definition (p. 5-4) - */ -scb { - address 0x0a0 - SCB_CONTROL { - size 1 - bit MK_MESSAGE 0x80 - bit DISCENB 0x40 - bit TAG_ENB 0x20 - bit DISCONNECTED 0x04 - mask SCB_TAG_TYPE 0x03 - } - SCB_TCL { - size 1 - bit SELBUSB 0x08 - mask TID 0xf0 - mask LID 0x07 - } - SCB_TARGET_STATUS { - size 1 - } - SCB_SGCOUNT { - size 1 - } - SCB_SGPTR { - size 4 - } - SCB_RESID_SGCNT { - size 1 - } - SCB_RESID_DCNT { - size 3 - } - SCB_DATAPTR { - size 4 - } - SCB_DATACNT { - /* - * Really only 3 bytes, but padded to make - * the kernel's job easier. - */ - size 4 - } - SCB_CMDPTR { - size 4 - } - SCB_CMDLEN { - size 1 - } - SCB_TAG { - size 1 - } - SCB_NEXT { - size 1 - } - SCB_PREV { - size 1 - } - SCB_BUSYTARGETS { - size 4 - } -} - -const SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */ - -/* --------------------- AHA-2840-only definitions -------------------- */ - -register SEECTL_2840 { - address 0x0c0 - access_mode RW - bit CS_2840 0x04 - bit CK_2840 0x02 - bit DO_2840 0x01 -} - -register STATUS_2840 { - address 0x0c1 - access_mode RW - bit EEPROM_TF 0x80 - mask BIOS_SEL 0x60 - mask ADSEL 0x1e - bit DI_2840 0x01 -} - -/* --------------------- AIC-7870-only definitions -------------------- */ - -register DSPCISTATUS { - address 0x086 - mask DFTHRSH_100 0xc0 -} - -register CCHADDR { - address 0x0E0 - size 8 -} - -register CCHCNT { - address 0x0E8 -} - -register CCSGRAM { - address 0x0E9 -} - -register CCSGADDR { - address 0x0EA -} - -register CCSGCTL { - address 0x0EB - bit CCSGDONE 0x80 - bit CCSGEN 0x08 - bit FLAG 0x02 - bit CCSGRESET 0x01 -} - -register CCSCBCNT { - address 0xEF -} - -register CCSCBCTL { - address 0x0EE - bit CCSCBDONE 0x80 - bit ARRDONE 0x40 /* SCB Array prefetch done */ - bit CCARREN 0x10 - bit CCSCBEN 0x08 - bit CCSCBDIR 0x04 - bit CCSCBRESET 0x01 -} - -register CCSCBADDR { - address 0x0ED -} - -register CCSCBRAM { - address 0xEC -} - -register CCSCBPTR { - address 0x0F1 -} - -register HNSCB_QOFF { - address 0x0F4 -} - -register HESCB_QOFF { - address 0x0F5 -} - -register SNSCB_QOFF { - address 0x0F6 -} - -register SESCB_QOFF { - address 0x0F7 -} - -register SDSCB_QOFF { - address 0x0F8 -} - -register QOFF_CTLSTA { - address 0x0FA - bit ESTABLISH_SCB_AVAIL 0x80 - bit SCB_AVAIL 0x40 - bit SNSCB_ROLLOVER 0x20 - bit SDSCB_ROLLOVER 0x10 - bit SESCB_ROLLOVER 0x08 - mask SCB_QSIZE 0x07 - mask SCB_QSIZE_256 0x06 -} - -register DFF_THRSH { - address 0x0FB - mask WR_DFTHRSH 0x70 - mask RD_DFTHRSH 0x07 - mask RD_DFTHRSH_MIN 0x00 - mask RD_DFTHRSH_25 0x01 - mask RD_DFTHRSH_50 0x02 - mask RD_DFTHRSH_63 0x03 - mask RD_DFTHRSH_75 0x04 - mask RD_DFTHRSH_85 0x05 - mask RD_DFTHRSH_90 0x06 - mask RD_DFTHRSH_MAX 0x07 - mask WR_DFTHRSH_MIN 0x00 - mask WR_DFTHRSH_25 0x10 - mask WR_DFTHRSH_50 0x20 - mask WR_DFTHRSH_63 0x30 - mask WR_DFTHRSH_75 0x40 - mask WR_DFTHRSH_85 0x50 - mask WR_DFTHRSH_90 0x60 - mask WR_DFTHRSH_MAX 0x70 -} - -register SG_CACHEPTR { - access_mode RW - address 0x0fc - mask SG_USER_DATA 0xfc - bit LAST_SEG 0x02 - bit LAST_SEG_DONE 0x01 -} - -register BRDCTL { - address 0x01d - bit BRDDAT7 0x80 - bit BRDDAT6 0x40 - bit BRDDAT5 0x20 - bit BRDSTB 0x10 - bit BRDCS 0x08 - bit BRDRW 0x04 - bit BRDCTL1 0x02 - bit BRDCTL0 0x01 - /* 7890 Definitions */ - bit BRDDAT4 0x10 - bit BRDDAT3 0x08 - bit BRDDAT2 0x04 - bit BRDRW_ULTRA2 0x02 - bit BRDSTB_ULTRA2 0x01 -} - -/* - * Serial EEPROM Control (p. 4-92 in 7870 Databook) - * Controls the reading and writing of an external serial 1-bit - * EEPROM Device. In order to access the serial EEPROM, you must - * first set the SEEMS bit that generates a request to the memory - * port for access to the serial EEPROM device. When the memory - * port is not busy servicing another request, it reconfigures - * to allow access to the serial EEPROM. When this happens, SEERDY - * gets set high to verify that the memory port access has been - * granted. - * - * After successful arbitration for the memory port, the SEECS bit of - * the SEECTL register is connected to the chip select. The SEECK, - * SEEDO, and SEEDI are connected to the clock, data out, and data in - * lines respectively. The SEERDY bit of SEECTL is useful in that it - * gives us an 800 nsec timer. After a write to the SEECTL register, - * the SEERDY goes high 800 nsec later. The one exception to this is - * when we first request access to the memory port. The SEERDY goes - * high to signify that access has been granted and, for this case, has - * no implied timing. - * - * See 93cx6.c for detailed information on the protocol necessary to - * read the serial EEPROM. - */ -register SEECTL { - address 0x01e - bit EXTARBACK 0x80 - bit EXTARBREQ 0x40 - bit SEEMS 0x20 - bit SEERDY 0x10 - bit SEECS 0x08 - bit SEECK 0x04 - bit SEEDO 0x02 - bit SEEDI 0x01 -} -/* ---------------------- Scratch RAM Offsets ------------------------- */ -/* These offsets are either to values that are initialized by the board's - * BIOS or are specified by the sequencer code. - * - * The host adapter card (at least the BIOS) uses 20-2f for SCSI - * device information, 32-33 and 5a-5f as well. As it turns out, the - * BIOS trashes 20-2f, writing the synchronous negotiation results - * on top of the BIOS values, so we re-use those for our per-target - * scratchspace (actually a value that can be copied directly into - * SCSIRATE). The kernel driver will enable synchronous negotiation - * for all targets that have a value other than 0 in the lower four - * bits of the target scratch space. This should work regardless of - * whether the bios has been installed. - */ - -scratch_ram { - address 0x020 - - /* - * 1 byte per target starting at this address for configuration values - */ - TARG_SCSIRATE { - size 16 - } - /* - * Bit vector of targets that have ULTRA enabled. - */ - ULTRA_ENB { - size 2 - } - /* - * Bit vector of targets that have disconnection disabled. - */ - DISC_DSB { - size 2 - } - /* - * Single byte buffer used to designate the type or message - * to send to a target. - */ - MSG_OUT { - size 1 - } - /* Parameters for DMA Logic */ - DMAPARAMS { - size 1 - bit PRELOADEN 0x80 - bit WIDEODD 0x40 - bit SCSIEN 0x20 - bit SDMAEN 0x10 - bit SDMAENACK 0x10 - bit HDMAEN 0x08 - bit HDMAENACK 0x08 - bit DIRECTION 0x04 - bit FIFOFLUSH 0x02 - bit FIFORESET 0x01 - } - SEQ_FLAGS { - size 1 - bit IDENTIFY_SEEN 0x80 - bit SCBPTR_VALID 0x20 - bit DPHASE 0x10 - bit AMTARGET 0x08 - bit WIDE_BUS 0x02 - bit TWIN_BUS 0x01 - } - /* - * Temporary storage for the - * target/channel/lun of a - * reconnecting target - */ - SAVED_TCL { - size 1 - } - /* Working value of the number of SG segments left */ - SG_COUNT { - size 1 - } - /* Working value of SG pointer */ - SG_NEXT { - size 4 - } - /* - * The last bus phase as seen by the sequencer. - */ - LASTPHASE { - size 1 - bit CDI 0x80 - bit IOI 0x40 - bit MSGI 0x20 - mask PHASE_MASK CDI|IOI|MSGI - mask P_DATAOUT 0x00 - mask P_DATAIN IOI - mask P_COMMAND CDI - mask P_MESGOUT CDI|MSGI - mask P_STATUS CDI|IOI - mask P_MESGIN CDI|IOI|MSGI - mask P_BUSFREE 0x01 - } - /* - * head of list of SCBs awaiting - * selection - */ - WAITING_SCBH { - size 1 - } - /* - * head of list of SCBs that are - * disconnected. Used for SCB - * paging. - */ - DISCONNECTED_SCBH { - size 1 - } - /* - * head of list of SCBs that are - * not in use. Used for SCB paging. - */ - FREE_SCBH { - size 1 - } - /* - * Address of the hardware scb array in the host. - */ - HSCB_ADDR { - size 4 - } - /* - * Address of the 256 byte array storing the SCBID of outstanding - * untagged SCBs indexed by TCL. - */ - SCBID_ADDR { - size 4 - } - /* - * Address of the array of command descriptors used to store - * information about incoming selections. - */ - TMODE_CMDADDR { - size 4 - } - KERNEL_QINPOS { - size 1 - } - QINPOS { - size 1 - } - QOUTPOS { - size 1 - } - /* - * Offset into the command descriptor array for the next - * available desciptor to use. - */ - TMODE_CMDADDR_NEXT { - size 1 - } - ARG_1 { - size 1 - mask SEND_MSG 0x80 - mask SEND_SENSE 0x40 - mask SEND_REJ 0x20 - mask MSGOUT_PHASEMIS 0x10 - alias RETURN_1 - } - ARG_2 { - size 1 - alias RETURN_2 - } - - /* - * Snapshot of MSG_OUT taken after each message is sent. - */ - LAST_MSG { - size 1 - } - - /* - * Number of times we have filled the CCSGRAM with prefetched - * SG elements. - */ - PREFETCH_CNT { - size 1 - } - - - /* - * These are reserved registers in the card's scratch ram. Some of - * the values are specified in the AHA2742 technical reference manual - * and are initialized by the BIOS at boot time. - */ - SCSICONF { - address 0x05a - size 1 - bit TERM_ENB 0x80 - bit RESET_SCSI 0x40 - mask HSCSIID 0x07 /* our SCSI ID */ - mask HWSCSIID 0x0f /* our SCSI ID if Wide Bus */ - } - HOSTCONF { - address 0x05d - size 1 - } - HA_274_BIOSCTRL { - address 0x05f - size 1 - mask BIOSMODE 0x30 - mask BIOSDISABLED 0x30 - bit CHANNEL_B_PRIMARY 0x08 - } - /* - * Per target SCSI offset values for Ultra2 controllers. - */ - TARG_OFFSET { - address 0x070 - size 16 - } -} - -const SCB_LIST_NULL 0xff - -const CCSGADDR_MAX 0x80 -const CCSGRAM_MAXSEGS 16 - -/* Offsets into the SCBID array where different data is stored */ -const UNTAGGEDSCB_OFFSET 0 -const QOUTFIFO_OFFSET 1 -const QINFIFO_OFFSET 2 - -/* WDTR Message values */ -const BUS_8_BIT 0x00 -const BUS_16_BIT 0x01 -const BUS_32_BIT 0x02 - -/* Offset maximums */ -const MAX_OFFSET_8BIT 0x0f -const MAX_OFFSET_16BIT 0x08 -const MAX_OFFSET_ULTRA2 0x7f -const HOST_MSG 0xff - -/* Target mode command processing constants */ -const CMD_GROUP_CODE_SHIFT 0x05 -const CMD_GROUP0_BYTE_DELTA -4 -const CMD_GROUP2_BYTE_DELTA -6 -const CMD_GROUP4_BYTE_DELTA 4 -const CMD_GROUP5_BYTE_DELTA 11 - -/* - * Downloaded (kernel inserted) constants - */ - -/* - * Number of command descriptors in the command descriptor array. - */ -const TMODE_NUMCMDS download diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.seq b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.seq deleted file mode 100644 index 823ff287..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx.seq +++ /dev/null @@ -1,1539 +0,0 @@ -/* - * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD. - * - * Copyright (c) 1994-1999 Justin Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License (GPL) and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $ - */ - -#include "aic7xxx.reg" -#include "scsi_message.h" - -/* - * A few words on the waiting SCB list: - * After starting the selection hardware, we check for reconnecting targets - * as well as for our selection to complete just in case the reselection wins - * bus arbitration. The problem with this is that we must keep track of the - * SCB that we've already pulled from the QINFIFO and started the selection - * on just in case the reselection wins so that we can retry the selection at - * a later time. This problem cannot be resolved by holding a single entry - * in scratch ram since a reconnecting target can request sense and this will - * create yet another SCB waiting for selection. The solution used here is to - * use byte 27 of the SCB as a pseudo-next pointer and to thread a list - * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB indexes, - * SCB_LIST_NULL is 0xff which is out of range. An entry is also added to - * this list every time a request sense occurs or after completing a non-tagged - * command for which a second SCB has been queued. The sequencer will - * automatically consume the entries. - */ - -reset: - clr SCSISIGO; /* De-assert BSY */ - and SXFRCTL1, ~BITBUCKET; - /* Always allow reselection */ - mvi SCSISEQ, ENRSELI|ENAUTOATNP; - - if ((p->features & AHC_CMD_CHAN) != 0) { - /* Ensure that no DMA operations are in progress */ - clr CCSGCTL; - clr CCSCBCTL; - } - - call clear_target_state; -poll_for_work: - and SXFRCTL0, ~SPIOEN; - if ((p->features & AHC_QUEUE_REGS) == 0) { - mov A, QINPOS; - } -poll_for_work_loop: - if ((p->features & AHC_QUEUE_REGS) == 0) { - and SEQCTL, ~PAUSEDIS; - } - test SSTAT0, SELDO|SELDI jnz selection; - test SCSISEQ, ENSELO jnz poll_for_work; - if ((p->features & AHC_TWIN) != 0) { - /* - * Twin channel devices cannot handle things like SELTO - * interrupts on the "background" channel. So, if we - * are selecting, keep polling the current channel util - * either a selection or reselection occurs. - */ - xor SBLKCTL,SELBUSB; /* Toggle to the other bus */ - test SSTAT0, SELDO|SELDI jnz selection; - test SCSISEQ, ENSELO jnz poll_for_work; - xor SBLKCTL,SELBUSB; /* Toggle back */ - } - cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting; -test_queue: - /* Has the driver posted any work for us? */ - if ((p->features & AHC_QUEUE_REGS) != 0) { - test QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop; - mov NONE, SNSCB_QOFF; - inc QINPOS; - } else { - or SEQCTL, PAUSEDIS; - cmp KERNEL_QINPOS, A je poll_for_work_loop; - inc QINPOS; - and SEQCTL, ~PAUSEDIS; - } - -/* - * We have at least one queued SCB now and we don't have any - * SCBs in the list of SCBs awaiting selection. If we have - * any SCBs available for use, pull the tag from the QINFIFO - * and get to work on it. - */ - if ((p->flags & AHC_PAGESCBS) != 0) { - mov ALLZEROS call get_free_or_disc_scb; - } - -dequeue_scb: - add A, -1, QINPOS; - mvi QINFIFO_OFFSET call fetch_byte; - - if ((p->flags & AHC_PAGESCBS) == 0) { - /* In the non-paging case, the SCBID == hardware SCB index */ - mov SCBPTR, RETURN_2; - } -dma_queued_scb: -/* - * DMA the SCB from host ram into the current SCB location. - */ - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov RETURN_2 call dma_scb; - -/* - * Preset the residual fields in case we never go through a data phase. - * This isn't done by the host so we can avoid a DMA to clear these - * fields for the normal case of I/O that completes without underrun - * or overrun conditions. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, SCB_DATACNT, 3; - } else { - mov SCB_RESID_DCNT[0],SCB_DATACNT[0]; - mov SCB_RESID_DCNT[1],SCB_DATACNT[1]; - mov SCB_RESID_DCNT[2],SCB_DATACNT[2]; - } - mov SCB_RESID_SGCNT, SCB_SGCOUNT; - -start_scb: - /* - * Place us on the waiting list in case our selection - * doesn't win during bus arbitration. - */ - mov SCB_NEXT,WAITING_SCBH; - mov WAITING_SCBH, SCBPTR; -start_waiting: - /* - * Pull the first entry off of the waiting SCB list. - */ - mov SCBPTR, WAITING_SCBH; - call start_selection; - jmp poll_for_work; - -start_selection: - if ((p->features & AHC_TWIN) != 0) { - and SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */ - and A,SELBUSB,SCB_TCL; /* Get new channel bit */ - or SINDEX,A; - mov SBLKCTL,SINDEX; /* select channel */ - } -initialize_scsiid: - if ((p->features & AHC_ULTRA2) != 0) { - and A, TID, SCB_TCL; /* Get target ID */ - and SCSIID_ULTRA2, OID; /* Clear old target */ - or SCSIID_ULTRA2, A; - } else { - and A, TID, SCB_TCL; /* Get target ID */ - and SCSIID, OID; /* Clear old target */ - or SCSIID, A; - } - mov SCSIDATL, ALLZEROS; /* clear out the latched */ - /* data register, this */ - /* fixes a bug on some */ - /* controllers where the */ - /* last byte written to */ - /* this register can leak */ - /* onto the data bus at */ - /* bad times, such as during */ - /* selection timeouts */ - mvi SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret; - -/* - * Initialize Ultra mode setting and clear the SCSI channel. - * SINDEX should contain any additional bit's the client wants - * set in SXFRCTL0. - */ -initialize_channel: - or SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX; - if ((p->features & AHC_ULTRA) != 0) { -ultra: - mvi SINDEX, ULTRA_ENB+1; - test SAVED_TCL, 0x80 jnz ultra_2; /* Target ID > 7 */ - dec SINDEX; -ultra_2: - mov FUNCTION1,SAVED_TCL; - mov A,FUNCTION1; - test SINDIR, A jz ndx_dtr; - or SXFRCTL0, FAST20; - } -/* - * Initialize SCSIRATE with the appropriate value for this target. - * The SCSIRATE settings for each target are stored in an array - * based at TARG_SCSIRATE. - */ -ndx_dtr: - shr A,4,SAVED_TCL; - if ((p->features & AHC_TWIN) != 0) { - test SBLKCTL,SELBUSB jz ndx_dtr_2; - or SAVED_TCL, SELBUSB; - or A,0x08; /* Channel B entries add 8 */ -ndx_dtr_2: - } - - if ((p->features & AHC_ULTRA2) != 0) { - add SINDEX, TARG_OFFSET, A; - mov SCSIOFFSET, SINDIR; - } - - add SINDEX,TARG_SCSIRATE,A; - mov SCSIRATE,SINDIR ret; - - -selection: - test SSTAT0,SELDO jnz select_out; -/* - * Reselection has been initiated by a target. Make a note that we've been - * reselected, but haven't seen an IDENTIFY message from the target yet. - */ -initiator_reselect: - mvi CLRSINT0, CLRSELDI; - /* XXX test for and handle ONE BIT condition */ - and SAVED_TCL, SELID_MASK, SELID; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; /* - * We aren't expecting a - * bus free, so interrupt - * the kernel driver if it - * happens. - */ - mvi SPIOEN call initialize_channel; - mvi MSG_OUT, MSG_NOOP; /* No message to send */ - jmp ITloop; - -/* - * After the selection, remove this SCB from the "waiting SCB" - * list. This is achieved by simply moving our "next" pointer into - * WAITING_SCBH. Our next pointer will be set to null the next time this - * SCB is used, so don't bother with it now. - */ -select_out: - /* Turn off the selection hardware */ - mvi SCSISEQ, ENRSELI|ENAUTOATNP; /* - * ATN on parity errors - * for "in" phases - */ - mvi CLRSINT0, CLRSELDO; - mov SCBPTR, WAITING_SCBH; - mov WAITING_SCBH,SCB_NEXT; - mov SAVED_TCL, SCB_TCL; - mvi CLRSINT1,CLRBUSFREE; - or SIMODE1, ENBUSFREE; /* - * We aren't expecting a - * bus free, so interrupt - * the kernel driver if it - * happens. - */ - mvi SPIOEN call initialize_channel; -/* - * As soon as we get a successful selection, the target should go - * into the message out phase since we have ATN asserted. - */ - mvi MSG_OUT, MSG_IDENTIFYFLAG; - or SEQ_FLAGS, IDENTIFY_SEEN; - -/* - * Main loop for information transfer phases. Wait for the target - * to assert REQ before checking MSG, C/D and I/O for the bus phase. - */ -ITloop: - call phase_lock; - - mov A, LASTPHASE; - - test A, ~P_DATAIN jz p_data; - cmp A,P_COMMAND je p_command; - cmp A,P_MESGOUT je p_mesgout; - cmp A,P_STATUS je p_status; - cmp A,P_MESGIN je p_mesgin; - - mvi INTSTAT,BAD_PHASE; /* unknown phase - signal driver */ - jmp ITloop; /* Try reading the bus again. */ - -await_busfree: - and SIMODE1, ~ENBUSFREE; - call clear_target_state; - mov NONE, SCSIDATL; /* Ack the last byte */ - and SXFRCTL0, ~SPIOEN; - test SSTAT1,REQINIT|BUSFREE jz .; - test SSTAT1, BUSFREE jnz poll_for_work; - mvi INTSTAT, BAD_PHASE; - -clear_target_state: - /* - * We assume that the kernel driver may reset us - * at any time, even in the middle of a DMA, so - * clear DFCNTRL too. - */ - clr DFCNTRL; - - /* - * We don't know the target we will connect to, - * so default to narrow transfers to avoid - * parity problems. - */ - if ((p->features & AHC_ULTRA2) != 0) { - bmov SCSIRATE, ALLZEROS, 2; - } else { - clr SCSIRATE; - and SXFRCTL0, ~(FAST20); - } - mvi LASTPHASE, P_BUSFREE; - /* clear target specific flags */ - clr SEQ_FLAGS ret; - - -data_phase_reinit: -/* - * If we re-enter the data phase after going through another phase, the - * STCNT may have been cleared, so restore it from the residual field. - * On Ultra2, we have to put it into the HCNT field because we have to - * drop the data down into the shadow layer via the preload ability. - */ - if ((p->features & AHC_ULTRA2) != 0) { - bmov HADDR, SHADDR, 4; - bmov HCNT, SCB_RESID_DCNT, 3; - } - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - bmov STCNT, SCB_RESID_DCNT, 3; - } - if ((p->features & AHC_CMD_CHAN) == 0) { - mvi DINDEX, STCNT; - mvi SCB_RESID_DCNT call bcopy_3; - } - jmp data_phase_loop; -p_data: - if ((p->features & AHC_ULTRA2) != 0) { - mvi DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN; - } else { - mvi DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET; - } - test LASTPHASE, IOI jnz . + 2; - or DMAPARAMS, DIRECTION; - call assert; /* - * Ensure entering a data - * phase is okay - seen identify, etc. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi CCSGADDR, CCSGADDR_MAX; - } - - test SEQ_FLAGS, DPHASE jnz data_phase_reinit; - or SEQ_FLAGS, DPHASE; /* we've seen a data phase */ - /* - * Initialize the DMA address and counter from the SCB. - * Also set SG_COUNT and SG_NEXT in memory since we cannot - * modify the values in the SCB itself until we see a - * save data pointers message. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov HADDR, SCB_DATAPTR, 7; - bmov SG_COUNT, SCB_SGCOUNT, 5; - if ((p->features & AHC_ULTRA2) == 0) { - bmov STCNT, HCNT, 3; - } - } else { - mvi DINDEX, HADDR; - mvi SCB_DATAPTR call bcopy_7; - call set_stcnt_from_hcnt; - mvi DINDEX, SG_COUNT; - mvi SCB_SGCOUNT call bcopy_5; - } -data_phase_loop: - /* Guard against overruns */ - test SG_COUNT, 0xff jnz data_phase_inbounds; -/* - * Turn on 'Bit Bucket' mode, set the transfer count to - * 16meg and let the target run until it changes phase. - * When the transfer completes, notify the host that we - * had an overrun. - */ - or SXFRCTL1,BITBUCKET; - and DMAPARAMS, ~(HDMAEN|SDMAEN); - if ((p->features & AHC_ULTRA2) != 0) { - bmov HCNT, ALLONES, 3; - } - if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) { - bmov STCNT, ALLONES, 3; - } - if ((p->features & AHC_CMD_CHAN) == 0) { - mvi STCNT[0], 0xFF; - mvi STCNT[1], 0xFF; - mvi STCNT[2], 0xFF; - } - -data_phase_inbounds: -/* If we are the last SG block, tell the hardware. */ - if ((p->features & AHC_ULTRA2) != 0) { - shl A, 2, SG_COUNT; - cmp SG_COUNT,0x01 jne data_phase_wideodd; - or A, LAST_SEG; - } else { - cmp SG_COUNT,0x01 jne data_phase_wideodd; - and DMAPARAMS, ~WIDEODD; - } -data_phase_wideodd: - if ((p->features & AHC_ULTRA2) != 0) { - mov SG_CACHEPTR, A; - mov DFCNTRL, DMAPARAMS; /* start the operation */ - test SXFRCTL1, BITBUCKET jnz data_phase_overrun; -u2_preload_wait: - test SSTAT1, PHASEMIS jnz u2_phasemis; - test DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait; - } else { - mov DMAPARAMS call dma; -data_phase_dma_done: -/* Go tell the host about any overruns */ - test SXFRCTL1,BITBUCKET jnz data_phase_overrun; - -/* Exit if we had an underrun. dma clears SINDEX in this case. */ - test SINDEX,0xff jz data_phase_finish; - } -/* - * Advance the scatter-gather pointers - */ -sg_advance: - if ((p->features & AHC_ULTRA2) != 0) { - cmp SG_COUNT, 0x01 je u2_data_phase_finish; - } else { - dec SG_COUNT; - test SG_COUNT, 0xff jz data_phase_finish; - } - - if ((p->features & AHC_CMD_CHAN) != 0) { - - /* - * Do we have any prefetch left??? - */ - cmp CCSGADDR, CCSGADDR_MAX jne prefetch_avail; - - /* - * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes. - */ - add A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT; - mvi A, CCSGADDR_MAX; - jc . + 2; - shl A, 3, SG_COUNT; - mov CCHCNT, A; - bmov CCHADDR, SG_NEXT, 4; - mvi CCSGCTL, CCSGEN|CCSGRESET; - test CCSGCTL, CCSGDONE jz .; - and CCSGCTL, ~CCSGEN; - test CCSGCTL, CCSGEN jnz .; - mvi CCSGCTL, CCSGRESET; -prefetch_avail: - bmov HADDR, CCSGRAM, 8; - if ((p->features & AHC_ULTRA2) == 0) { - bmov STCNT, HCNT, 3; - } else { - dec SG_COUNT; - } - } else { - mvi DINDEX, HADDR; - mvi SG_NEXT call bcopy_4; - - mvi HCNT[0],SG_SIZEOF; - clr HCNT[1]; - clr HCNT[2]; - - or DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - - call dma_finish; - -/* - * Copy data from FIFO into SCB data pointer and data count. - * This assumes that the SG segments are of the form: - * struct ahc_dma_seg { - * u_int32_t addr; four bytes, little-endian order - * u_int32_t len; four bytes, little endian order - * }; - */ - mvi DINDEX, HADDR; - call dfdat_in_7; - call set_stcnt_from_hcnt; - } -/* Advance the SG pointer */ - clr A; /* add sizeof(struct scatter) */ - add SG_NEXT[0],SG_SIZEOF; - adc SG_NEXT[1],A; - - if ((p->features & AHC_ULTRA2) != 0) { - jmp data_phase_loop; - } else { - test SSTAT1, REQINIT jz .; - test SSTAT1,PHASEMIS jz data_phase_loop; - } - - -/* - * We've loaded all of our segments into the preload layer. Now, we simply - * have to wait for it to finish or for us to get a phasemis. And, since - * we'll get a phasemis if we do finish, all we really need to do is wait - * for a phasemis then check if we did actually complete all the segments. - */ - if ((p->features & AHC_ULTRA2) != 0) { -u2_data_phase_finish: - test SSTAT1, PHASEMIS jnz u2_phasemis; - test SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish; - clr SG_COUNT; - test SSTAT1, REQINIT jz .; - test SSTAT1, PHASEMIS jz data_phase_loop; -u2_phasemis: - call ultra2_dmafinish; - test SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish; - test SSTAT2, SHVALID jnz u2_fixup_residual; - mvi INTSTAT, SEQ_SG_FIXUP; - jmp data_phase_finish; -u2_fixup_residual: - shr ARG_1, 2, SG_CACHEPTR; -u2_phasemis_loop: - and A, 0x3f, SG_COUNT; - cmp ARG_1, A je data_phase_finish; -/* - * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT - */ - clr A; - add SG_NEXT[0], -SG_SIZEOF; - adc SG_NEXT[1], 0xff; - inc SG_COUNT; - jmp u2_phasemis_loop; - } - -data_phase_finish: -/* - * After a DMA finishes, save the SG and STCNT residuals back into the SCB - * We use STCNT instead of HCNT, since it's a reflection of how many bytes - * were transferred on the SCSI (as opposed to the host) bus. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_RESID_DCNT, STCNT, 3; - mov SCB_RESID_SGCNT, SG_COUNT; - if ((p->features & AHC_ULTRA2) != 0) { - or SXFRCTL0, CLRSTCNT|CLRCHN; - } - } else { - mov SCB_RESID_DCNT[0],STCNT[0]; - mov SCB_RESID_DCNT[1],STCNT[1]; - mov SCB_RESID_DCNT[2],STCNT[2]; - mov SCB_RESID_SGCNT, SG_COUNT; - } - - jmp ITloop; - -data_phase_overrun: -/* - * Turn off BITBUCKET mode and notify the host - */ - if ((p->features & AHC_ULTRA2) != 0) { -/* - * Wait for the target to quit transferring data on the SCSI bus - */ - test SSTAT1, PHASEMIS jz .; - call ultra2_dmafinish; - } - and SXFRCTL1, ~BITBUCKET; - mvi INTSTAT,DATA_OVERRUN; - jmp ITloop; - - - - -/* - * Actually turn off the DMA hardware, save our current position into the - * proper residual variables, wait for the next REQ signal, then jump to - * the ITloop. Jumping to the ITloop ensures that if we happen to get - * brought into the data phase again (or are still in it after our last - * segment) that we will properly signal an overrun to the kernel. - */ - if ((p->features & AHC_ULTRA2) != 0) { -ultra2_dmafinish: - test DFCNTRL, DIRECTION jnz ultra2_dmahalt; - and DFCNTRL, ~SCSIEN; - test DFCNTRL, SCSIEN jnz .; - if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { - or DFCNTRL, FIFOFLUSH; - } -ultra2_dmafifoflush: - if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) { - /* - * hardware bug alert! This needless set of jumps - * works around a glitch in the silicon. When the - * PCI DMA fifo goes empty, but there is still SCSI - * data to be flushed into the PCI DMA fifo (and from - * there on into main memory), the FIFOEMP bit will - * come on between the time when the PCI DMA buffer - * went empty and the next bit of data is copied from - * the SCSI fifo into the PCI fifo. It should only - * come on when both FIFOs (meaning the entire FIFO - * chain) are empty. Since it can take up to 4 cycles - * for new data to be copied from the SCSI fifo into - * the PCI fifo, testing for FIFOEMP status for 4 - * extra times gives the needed time for any - * remaining SCSI fifo data to be put in the PCI fifo - * before we declare it *truly* empty. - */ - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - } - test DFSTATUS, FIFOEMP jz ultra2_dmafifoflush; - test DFSTATUS, MREQPEND jnz .; -ultra2_dmahalt: - and DFCNTRL, ~(HDMAEN|SCSIEN); - test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - ret; - } - -/* - * Command phase. Set up the DMA registers and let 'er rip. - */ -p_command: - call assert; - -/* - * Load HADDR and HCNT. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov HADDR, SCB_CMDPTR, 5; - bmov HCNT[1], ALLZEROS, 2; - if ((p->features & AHC_ULTRA2) == 0) { - bmov STCNT, HCNT, 3; - } - } else { - mvi DINDEX, HADDR; - mvi SCB_CMDPTR call bcopy_5; - clr HCNT[1]; - clr HCNT[2]; - call set_stcnt_from_hcnt; - } - - if ((p->features & AHC_ULTRA2) == 0) { - mvi (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma; - } else { - mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION); - test SSTAT0, SDONE jnz .; -p_command_dma_loop: - test SSTAT0, SDONE jnz p_command_ultra2_dma_done; - test SSTAT1,PHASEMIS jz p_command_dma_loop; /* ie. underrun */ -p_command_ultra2_dma_done: - test SCSISIGI, REQI jz p_command_ultra2_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz p_command_ultra2_dma_done; -p_command_ultra2_shutdown: - and DFCNTRL, ~(HDMAEN|SCSIEN); - test DFCNTRL, (HDMAEN|SCSIEN) jnz .; - or SXFRCTL0, CLRSTCNT|CLRCHN; - } - jmp ITloop; - -/* - * Status phase. Wait for the data byte to appear, then read it - * and store it into the SCB. - */ -p_status: - call assert; - - mov SCB_TARGET_STATUS, SCSIDATL; - jmp ITloop; - -/* - * Message out phase. If MSG_OUT is 0x80, build I full indentify message - * sequence and send it to the target. In addition, if the MK_MESSAGE bit - * is set in the SCB_CONTROL byte, interrupt the host and allow it to send - * it's own message. - * - * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message. - * This is done to allow the hsot to send messages outside of an identify - * sequence while protecting the seqencer from testing the MK_MESSAGE bit - * on an SCB that might not be for the current nexus. (For example, a - * BDR message in response to a bad reselection would leave us pointed to - * an SCB that doesn't have anything to do with the current target). - * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag, - * bus device reset). - * - * When there are no messages to send, MSG_OUT should be set to MSG_NOOP, - * in case the target decides to put us in this phase for some strange - * reason. - */ -p_mesgout_retry: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */ -p_mesgout: - mov SINDEX, MSG_OUT; - cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; -p_mesgout_identify: - if ((p->features & AHC_WIDE) != 0) { - and SINDEX,0xf,SCB_TCL; /* lun */ - } else { - and SINDEX,0x7,SCB_TCL; /* lun */ - } - and A,DISCENB,SCB_CONTROL; /* mask off disconnect privilege */ - or SINDEX,A; /* or in disconnect privilege */ - or SINDEX,MSG_IDENTIFYFLAG; -p_mesgout_mk_message: - test SCB_CONTROL,MK_MESSAGE jz p_mesgout_tag; - mov SCSIDATL, SINDEX; /* Send the last byte */ - jmp p_mesgout_from_host + 1;/* Skip HOST_MSG test */ -/* - * Send a tag message if TAG_ENB is set in the SCB control block. - * Use SCB_TAG (the position in the kernel's SCB array) as the tag value. - */ -p_mesgout_tag: - test SCB_CONTROL,TAG_ENB jz p_mesgout_onebyte; - mov SCSIDATL, SINDEX; /* Send the identify message */ - call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - and SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL; - call phase_lock; - cmp LASTPHASE, P_MESGOUT jne p_mesgout_done; - mov SCB_TAG jmp p_mesgout_onebyte; -/* - * Interrupt the driver, and allow it to send a message - * if it asks. - */ -p_mesgout_from_host: - cmp SINDEX, HOST_MSG jne p_mesgout_onebyte; - mvi INTSTAT,AWAITING_MSG; - nop; - /* - * Did the host detect a phase change? - */ - cmp RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done; - -p_mesgout_onebyte: - mvi CLRSINT1, CLRATNO; - mov SCSIDATL, SINDEX; - -/* - * If the next bus phase after ATN drops is a message out, it means - * that the target is requesting that the last message(s) be resent. - */ - call phase_lock; - cmp LASTPHASE, P_MESGOUT je p_mesgout_retry; - -p_mesgout_done: - mvi CLRSINT1,CLRATNO; /* Be sure to turn ATNO off */ - mov LAST_MSG, MSG_OUT; - cmp MSG_OUT, MSG_IDENTIFYFLAG jne . + 2; - and SCB_CONTROL, ~MK_MESSAGE; - mvi MSG_OUT, MSG_NOOP; /* No message left */ - jmp ITloop; - -/* - * Message in phase. Bytes are read using Automatic PIO mode. - */ -p_mesgin: - mvi ACCUM call inb_first; /* read the 1st message byte */ - - test A,MSG_IDENTIFYFLAG jnz mesgin_identify; - cmp A,MSG_DISCONNECT je mesgin_disconnect; - cmp A,MSG_SAVEDATAPOINTER je mesgin_sdptrs; - cmp ALLZEROS,A je mesgin_complete; - cmp A,MSG_RESTOREPOINTERS je mesgin_rdptrs; - cmp A,MSG_EXTENDED je mesgin_extended; - cmp A,MSG_MESSAGE_REJECT je mesgin_reject; - cmp A,MSG_NOOP je mesgin_done; - cmp A,MSG_IGN_WIDE_RESIDUE je mesgin_wide_residue; - -rej_mesgin: -/* - * We have no idea what this message in is, so we issue a message reject - * and hope for the best. In any case, rejection should be a rare - * occurrence - signal the driver when it happens. - */ - mvi INTSTAT,SEND_REJECT; /* let driver know */ - - mvi MSG_MESSAGE_REJECT call mk_mesg; - -mesgin_done: - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ - jmp ITloop; - - -mesgin_complete: -/* - * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO, - * and trigger a completion interrupt. Before doing so, check to see if there - * is a residual or the status byte is something other than STATUS_GOOD (0). - * In either of these conditions, we upload the SCB back to the host so it can - * process this information. In the case of a non zero status byte, we - * additionally interrupt the kernel driver synchronously, allowing it to - * decide if sense should be retrieved. If the kernel driver wishes to request - * sense, it will fill the kernel SCB with a request sense command and set - * RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE we redownload - * the SCB, and process it as the next command by adding it to the waiting list. - * If the kernel driver does not wish to request sense, it need only clear - * RETURN_1, and the command is allowed to complete normally. We don't bother - * to post to the QOUTFIFO in the error cases since it would require extra - * work in the kernel driver to ensure that the entry was removed before the - * command complete code tried processing it. - */ - -/* - * First check for residuals - */ - test SCB_RESID_SGCNT,0xff jnz upload_scb; - test SCB_TARGET_STATUS,0xff jz complete; /* Good Status? */ -upload_scb: - mvi DMAPARAMS, FIFORESET; - mov SCB_TAG call dma_scb; -check_status: - test SCB_TARGET_STATUS,0xff jz complete; /* Just a residual? */ - mvi INTSTAT,BAD_STATUS; /* let driver know */ - nop; - cmp RETURN_1, SEND_SENSE jne complete; - /* This SCB becomes the next to execute as it will retrieve sense */ - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - mov SCB_TAG call dma_scb; -add_to_waiting_list: - mov SCB_NEXT,WAITING_SCBH; - mov WAITING_SCBH, SCBPTR; - /* - * Prepare our selection hardware before the busfree so we have a - * high probability of winning arbitration. - */ - call start_selection; - jmp await_busfree; - -complete: - /* If we are untagged, clear our address up in host ram */ - test SCB_CONTROL, TAG_ENB jnz complete_post; - mov A, SAVED_TCL; - mvi UNTAGGEDSCB_OFFSET call post_byte_setup; - mvi SCB_LIST_NULL call post_byte; - -complete_post: - /* Post the SCB and issue an interrupt */ - if ((p->features & AHC_QUEUE_REGS) != 0) { - mov A, SDSCB_QOFF; - } else { - mov A, QOUTPOS; - } - mvi QOUTFIFO_OFFSET call post_byte_setup; - mov SCB_TAG call post_byte; - if ((p->features & AHC_QUEUE_REGS) == 0) { - inc QOUTPOS; - } - mvi INTSTAT,CMDCMPLT; - -add_to_free_list: - call add_scb_to_free_list; - jmp await_busfree; - -/* - * Is it an extended message? Copy the message to our message buffer and - * notify the host. The host will tell us whether to reject this message, - * respond to it with the message that the host placed in our message buffer, - * or simply to do nothing. - */ -mesgin_extended: - mvi INTSTAT,EXTENDED_MSG; /* let driver know */ - jmp ITloop; - -/* - * Is it a disconnect message? Set a flag in the SCB to remind us - * and await the bus going free. - */ -mesgin_disconnect: - or SCB_CONTROL,DISCONNECTED; - call add_scb_to_disc_list; - jmp await_busfree; - -/* - * Save data pointers message: - * Copying RAM values back to SCB, for Save Data Pointers message, but - * only if we've actually been into a data phase to change them. This - * protects against bogus data in scratch ram and the residual counts - * since they are only initialized when we go into data_in or data_out. - */ -mesgin_sdptrs: - test SEQ_FLAGS, DPHASE jz mesgin_done; - /* - * The SCB SGPTR becomes the next one we'll download, - * and the SCB DATAPTR becomes the current SHADDR. - * Use the residual number since STCNT is corrupted by - * any message transfer. - */ - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov SCB_SGCOUNT, SG_COUNT, 5; - bmov SCB_DATAPTR, SHADDR, 4; - bmov SCB_DATACNT, SCB_RESID_DCNT, 3; - } else { - mvi DINDEX, SCB_SGCOUNT; - mvi SG_COUNT call bcopy_5; - mvi DINDEX, SCB_DATAPTR; - mvi SHADDR call bcopy_4; - mvi SCB_RESID_DCNT call bcopy_3; - } - jmp mesgin_done; - -/* - * Restore pointers message? Data pointers are recopied from the - * SCB anytime we enter a data phase for the first time, so all - * we need to do is clear the DPHASE flag and let the data phase - * code do the rest. - */ -mesgin_rdptrs: - and SEQ_FLAGS, ~DPHASE; /* - * We'll reload them - * the next time through - * the dataphase. - */ - jmp mesgin_done; - -/* - * Identify message? For a reconnecting target, this tells us the lun - * that the reconnection is for - find the correct SCB and switch to it, - * clearing the "disconnected" bit so we don't "find" it by accident later. - */ -mesgin_identify: - - if ((p->features & AHC_WIDE) != 0) { - and A,0x0f; /* lun in lower four bits */ - } else { - and A,0x07; /* lun in lower three bits */ - } - or SAVED_TCL,A; /* SAVED_TCL should be complete now */ - - mvi ARG_2, SCB_LIST_NULL; /* SCBID of prev SCB in disc List */ - call get_untagged_SCBID; - cmp ARG_1, SCB_LIST_NULL je snoop_tag; - if ((p->flags & AHC_PAGESCBS) != 0) { - test SEQ_FLAGS, SCBPTR_VALID jz use_retrieveSCB; - } - /* - * If the SCB was found in the disconnected list (as is - * always the case in non-paging scenarios), SCBPTR is already - * set to the correct SCB. So, simply setup the SCB and get - * on with things. - */ - mov SCBPTR call rem_scb_from_disc_list; - jmp setup_SCB; -/* - * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message. - * If we get one, we use the tag returned to find the proper - * SCB. With SCB paging, this requires using search for both tagged - * and non-tagged transactions since the SCB may exist in any slot. - * If we're not using SCB paging, we can use the tag as the direct - * index to the SCB. - */ -snoop_tag: - mov NONE,SCSIDATL; /* ACK Identify MSG */ -snoop_tag_loop: - call phase_lock; - cmp LASTPHASE, P_MESGIN jne not_found; - cmp SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found; -get_tag: - mvi ARG_1 call inb_next; /* tag value */ - -use_retrieveSCB: - call retrieveSCB; -setup_SCB: - mov A, SAVED_TCL; - cmp SCB_TCL, A jne not_found_cleanup_scb; - test SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb; - and SCB_CONTROL,~DISCONNECTED; - or SEQ_FLAGS,IDENTIFY_SEEN; /* make note of IDENTIFY */ - /* See if the host wants to send a message upon reconnection */ - test SCB_CONTROL, MK_MESSAGE jz mesgin_done; - and SCB_CONTROL, ~MK_MESSAGE; - mvi HOST_MSG call mk_mesg; - jmp mesgin_done; - -not_found_cleanup_scb: - test SCB_CONTROL, DISCONNECTED jz . + 3; - call add_scb_to_disc_list; - jmp not_found; - call add_scb_to_free_list; -not_found: - mvi INTSTAT, NO_MATCH; - mvi MSG_BUS_DEV_RESET call mk_mesg; - jmp mesgin_done; - -/* - * Message reject? Let the kernel driver handle this. If we have an - * outstanding WDTR or SDTR negotiation, assume that it's a response from - * the target selecting 8bit or asynchronous transfer, otherwise just ignore - * it since we have no clue what it pertains to. - */ -mesgin_reject: - mvi INTSTAT, REJECT_MSG; - jmp mesgin_done; - -/* - * Wide Residue. We handle the simple cases, but pass of the one hard case - * to the kernel (when the residue byte happened to cause us to advance our - * sg element array, so we know have to back that advance out). - */ -mesgin_wide_residue: - mvi ARG_1 call inb_next; /* ACK the wide_residue and get */ - /* the size byte */ -/* - * In order for this to be reliable, we have to do all sorts of horrible - * magic in terms of resetting the datafifo and reloading the shadow layer - * with the correct new values (so that a subsequent save data pointers - * message will do the right thing). We let the kernel do that work. - */ - mvi INTSTAT, WIDE_RESIDUE; - jmp mesgin_done; - -/* - * [ ADD MORE MESSAGE HANDLING HERE ] - */ - -/* - * Locking the driver out, build a one-byte message passed in SINDEX - * if there is no active message already. SINDEX is returned intact. - */ -mk_mesg: - or SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */ - mov MSG_OUT,SINDEX ret; - -/* - * Functions to read data in Automatic PIO mode. - * - * According to Adaptec's documentation, an ACK is not sent on input from - * the target until SCSIDATL is read from. So we wait until SCSIDATL is - * latched (the usual way), then read the data byte directly off the bus - * using SCSIBUSL. When we have pulled the ATN line, or we just want to - * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI - * spec guarantees that the target will hold the data byte on the bus until - * we send our ACK. - * - * The assumption here is that these are called in a particular sequence, - * and that REQ is already set when inb_first is called. inb_{first,next} - * use the same calling convention as inb. - */ - -inb_next: - mov NONE,SCSIDATL; /*dummy read from latch to ACK*/ -inb_next_wait: - /* - * If there is a parity error, wait for the kernel to - * see the interrupt and prepare our message response - * before continuing. - */ - test SSTAT1, REQINIT jz inb_next_wait; - test SSTAT1, SCSIPERR jnz .; - and LASTPHASE, PHASE_MASK, SCSISIGI; - cmp LASTPHASE, P_MESGIN jne mesgin_phasemis; -inb_first: - mov DINDEX,SINDEX; - mov DINDIR,SCSIBUSL ret; /*read byte directly from bus*/ -inb_last: - mov NONE,SCSIDATL ret; /*dummy read from latch to ACK*/ - - -mesgin_phasemis: -/* - * We expected to receive another byte, but the target changed phase - */ - mvi INTSTAT, MSGIN_PHASEMIS; - jmp ITloop; - -/* - * DMA data transfer. HADDR and HCNT must be loaded first, and - * SINDEX should contain the value to load DFCNTRL with - 0x3d for - * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared - * during initialization. - */ -if ((p->features & AHC_ULTRA2) == 0) { -dma: - mov DFCNTRL,SINDEX; -dma_loop: - test SSTAT0,DMADONE jnz dma_dmadone; - test SSTAT1,PHASEMIS jz dma_loop; /* ie. underrun */ -dma_phasemis: - test SSTAT0,SDONE jnz dma_checkfifo; - mov SINDEX,ALLZEROS; /* Notify caller of phasemiss */ - -/* - * We will be "done" DMAing when the transfer count goes to zero, or - * the target changes the phase (in light of this, it makes sense that - * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are - * doing a SCSI->Host transfer, the data FIFO should be flushed auto- - * magically on STCNT=0 or a phase change, so just wait for FIFO empty - * status. - */ -dma_checkfifo: - test DFCNTRL,DIRECTION jnz dma_fifoempty; -dma_fifoflush: - test DFSTATUS,FIFOEMP jz dma_fifoflush; - -dma_fifoempty: - /* Don't clobber an inprogress host data transfer */ - test DFSTATUS, MREQPEND jnz dma_fifoempty; -/* - * Now shut the DMA enables off and make sure that the DMA enables are - * actually off first lest we get an ILLSADDR. - */ -dma_dmadone: - cmp LASTPHASE, P_COMMAND je dma_await_nreq; - test SCSIRATE, 0x0f jnz dma_shutdown; -dma_await_nreq: - test SCSISIGI, REQI jz dma_shutdown; - test SSTAT1, (PHASEMIS|REQINIT) jz dma_await_nreq; -dma_shutdown: - and DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN); -dma_halt: - /* - * Some revisions of the aic7880 have a problem where, if the - * data fifo is full, but the PCI input latch is not empty, - * HDMAEN cannot be cleared. The fix used here is to attempt - * to drain the data fifo until there is space for the input - * latch to drain and HDMAEN de-asserts. - */ - if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { - mov NONE, DFDAT; - } - test DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt; -} -return: - ret; - -/* - * Assert that if we've been reselected, then we've seen an IDENTIFY - * message. - */ -assert: - test SEQ_FLAGS,IDENTIFY_SEEN jnz return; /* seen IDENTIFY? */ - - mvi INTSTAT,NO_IDENT ret; /* no - tell the kernel */ - -/* - * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL) - * or by the SCBID ARG_1. The search begins at the SCB index passed in - * via SINDEX which is an SCB that must be on the disconnected list. If - * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR - * is set to the proper SCB. - */ -findSCB: - mov SCBPTR,SINDEX; /* Initialize SCBPTR */ - cmp ARG_1, SCB_LIST_NULL jne findSCB_by_SCBID; - mov A, SAVED_TCL; - mvi SCB_TCL jmp findSCB_loop; /* &SCB_TCL -> SINDEX */ -findSCB_by_SCBID: - mov A, ARG_1; /* Tag passed in ARG_1 */ - mvi SCB_TAG jmp findSCB_loop; /* &SCB_TAG -> SINDEX */ -findSCB_next: - mov ARG_2, SCBPTR; - cmp SCB_NEXT, SCB_LIST_NULL je notFound; - mov SCBPTR,SCB_NEXT; - dec SINDEX; /* Last comparison moved us too far */ -findSCB_loop: - cmp SINDIR, A jne findSCB_next; - mov SINDEX, SCBPTR ret; -notFound: - mvi SINDEX, SCB_LIST_NULL ret; - -/* - * Retrieve an SCB by SCBID first searching the disconnected list falling - * back to DMA'ing the SCB down from the host. This routine assumes that - * ARG_1 is the SCBID of interest and that SINDEX is the position in the - * disconnected list to start the search from. If SINDEX is SCB_LIST_NULL, - * we go directly to the host for the SCB. - */ -retrieveSCB: - test SEQ_FLAGS, SCBPTR_VALID jz retrieve_from_host; - mov SCBPTR call findSCB; /* Continue the search */ - cmp SINDEX, SCB_LIST_NULL je retrieve_from_host; - -/* - * This routine expects SINDEX to contain the index of the SCB to be - * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the - * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL - * if it is at the head. - */ -rem_scb_from_disc_list: -/* Remove this SCB from the disconnection list */ - cmp ARG_2, SCB_LIST_NULL je rHead; - mov DINDEX, SCB_NEXT; - mov SCBPTR, ARG_2; - mov SCB_NEXT, DINDEX; - mov SCBPTR, SINDEX ret; -rHead: - mov DISCONNECTED_SCBH,SCB_NEXT ret; - -retrieve_from_host: -/* - * We didn't find it. Pull an SCB and DMA down the one we want. - * We should never get here in the non-paging case. - */ - mov ALLZEROS call get_free_or_disc_scb; - mvi DMAPARAMS, HDMAEN|DIRECTION|FIFORESET; - /* Jump instead of call as we want to return anyway */ - mov ARG_1 jmp dma_scb; - -/* - * Determine whether a target is using tagged or non-tagged transactions - * by first looking for a matching transaction based on the TCL and if - * that fails, looking up this device in the host's untagged SCB array. - * The TCL to search for is assumed to be in SAVED_TCL. The value is - * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged). - * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information - * in an SCB instead of having to go to the host. - */ -get_untagged_SCBID: - cmp DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host; - mvi ARG_1, SCB_LIST_NULL; - mov DISCONNECTED_SCBH call findSCB; - cmp SINDEX, SCB_LIST_NULL je get_SCBID_from_host; - or SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */ - test SCB_CONTROL, TAG_ENB jnz . + 2; - mov ARG_1, SCB_TAG ret; - mvi ARG_1, SCB_LIST_NULL ret; - -/* - * Fetch a byte from host memory given an index of (A + (256 * SINDEX)) - * and a base address of SCBID_ADDR. The byte is returned in RETURN_2. - */ -fetch_byte: - mov ARG_2, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi CCHCNT, 1; - mvi CCSGCTL, CCSGEN|CCSGRESET; - test CCSGCTL, CCSGDONE jz .; - mvi CCSGCTL, CCSGRESET; - bmov RETURN_2, CCSGRAM, 1 ret; - } else { - mvi DINDEX, HADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi HCNT[0], 1; - clr HCNT[1]; - clr HCNT[2]; - mvi DFCNTRL, HDMAEN|DIRECTION|FIFORESET; - call dma_finish; - mov RETURN_2, DFDAT ret; - } - -/* - * Prepare the hardware to post a byte to host memory given an - * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR. - */ -post_byte_setup: - mov ARG_2, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi CCHCNT, 1; - mvi CCSCBCTL, CCSCBRESET ret; - } else { - mvi DINDEX, HADDR; - mvi SCBID_ADDR call set_1byte_addr; - mvi HCNT[0], 1; - clr HCNT[1]; - clr HCNT[2]; - mvi DFCNTRL, FIFORESET ret; - } - -post_byte: - if ((p->features & AHC_CMD_CHAN) != 0) { - bmov CCSCBRAM, SINDEX, 1; - or CCSCBCTL, CCSCBEN|CCSCBRESET; - test CCSCBCTL, CCSCBDONE jz .; - clr CCSCBCTL ret; - } else { - mov DFDAT, SINDEX; - or DFCNTRL, HDMAEN|FIFOFLUSH; - jmp dma_finish; - } - -get_SCBID_from_host: - mov A, SAVED_TCL; - mvi UNTAGGEDSCB_OFFSET call fetch_byte; - mov RETURN_1, RETURN_2 ret; - -phase_lock: - test SSTAT1, REQINIT jz phase_lock; - test SSTAT1, SCSIPERR jnz phase_lock; - and SCSISIGO, PHASE_MASK, SCSISIGI; - and LASTPHASE, PHASE_MASK, SCSISIGI ret; - -if ((p->features & AHC_CMD_CHAN) == 0) { -set_stcnt_from_hcnt: - mov STCNT[0], HCNT[0]; - mov STCNT[1], HCNT[1]; - mov STCNT[2], HCNT[2] ret; - -bcopy_7: - mov DINDIR, SINDIR; - mov DINDIR, SINDIR; -bcopy_5: - mov DINDIR, SINDIR; -bcopy_4: - mov DINDIR, SINDIR; -bcopy_3: - mov DINDIR, SINDIR; - mov DINDIR, SINDIR; - mov DINDIR, SINDIR ret; -} - -/* - * Setup addr assuming that A is an index into - * an array of 32byte objects, SINDEX contains - * the base address of that array, and DINDEX - * contains the base address of the location - * to store the indexed address. - */ -set_32byte_addr: - shr ARG_2, 3, A; - shl A, 5; -/* - * Setup addr assuming that A + (ARG_1 * 256) is an - * index into an array of 1byte objects, SINDEX contains - * the base address of that array, and DINDEX contains - * the base address of the location to store the computed - * address. - */ -set_1byte_addr: - add DINDIR, A, SINDIR; - mov A, ARG_2; - adc DINDIR, A, SINDIR; - clr A; - adc DINDIR, A, SINDIR; - adc DINDIR, A, SINDIR ret; - -/* - * Either post or fetch and SCB from host memory based on the - * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX. - */ -dma_scb: - mov A, SINDEX; - if ((p->features & AHC_CMD_CHAN) != 0) { - mvi DINDEX, CCHADDR; - mvi HSCB_ADDR call set_32byte_addr; - mov CCSCBPTR, SCBPTR; - mvi CCHCNT, 32; - test DMAPARAMS, DIRECTION jz dma_scb_tohost; - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .; - jmp dma_scb_finish; -dma_scb_tohost: - if ((p->features & AHC_ULTRA2) == 0) { - mvi CCSCBCTL, CCSCBRESET; - bmov CCSCBRAM, SCB_CONTROL, 32; - or CCSCBCTL, CCSCBEN|CCSCBRESET; - test CCSCBCTL, CCSCBDONE jz .; - } - if ((p->features & AHC_ULTRA2) != 0) { - if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) { - mvi CCSCBCTL, CCARREN|CCSCBRESET; - cmp CCSCBCTL, ARRDONE|CCARREN jne .; - mvi CCHCNT, 32; - mvi CCSCBCTL, CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|CCSCBEN jne .; - } else { - mvi CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET; - cmp CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .; - } - } -dma_scb_finish: - clr CCSCBCTL; - test CCSCBCTL, CCARREN|CCSCBEN jnz .; - ret; - } - if ((p->features & AHC_CMD_CHAN) == 0) { - mvi DINDEX, HADDR; - mvi HSCB_ADDR call set_32byte_addr; - mvi HCNT[0], 32; - clr HCNT[1]; - clr HCNT[2]; - mov DFCNTRL, DMAPARAMS; - test DMAPARAMS, DIRECTION jnz dma_scb_fromhost; - /* Fill it with the SCB data */ -copy_scb_tofifo: - mvi SINDEX, SCB_CONTROL; - add A, 32, SINDEX; -copy_scb_tofifo_loop: - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - mov DFDAT,SINDIR; - cmp SINDEX, A jne copy_scb_tofifo_loop; - or DFCNTRL, HDMAEN|FIFOFLUSH; - jmp dma_finish; -dma_scb_fromhost: - mvi DINDEX, SCB_CONTROL; - if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) { - /* - * Set the A to -24. It it hits 0, then we let - * our code fall through to dfdat_in_8 to complete - * the last of the copy. - * - * Also, things happen 8 bytes at a time in this - * case, so we may need to drain the fifo at most - * 3 times to keep things flowing - */ - mvi A, -24; -dma_scb_hang_fifo: - /* Wait for the first bit of data to hit the fifo */ - test DFSTATUS, FIFOEMP jnz .; -dma_scb_hang_wait: - /* OK, now they've started to transfer into the fifo, - * so wait for them to stop trying to transfer any - * more data. - */ - test DFSTATUS, MREQPEND jnz .; - /* - * OK, they started, then they stopped, now see if they - * managed to complete the job before stopping. Try - * it multiple times to give the chip a few cycles to - * set the flag if it did complete. - */ - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - test DFSTATUS, HDONE jnz dma_scb_hang_dma_done; - /* - * Too bad, the chip didn't complete the DMA, but there - * aren't any more memory requests pending, so that - * means it stopped part way through and hung. That's - * our bug, so now we drain what data there is in the - * fifo in order to get things going again. - */ -dma_scb_hang_empty_fifo: - call dfdat_in_8; - add A, 8; - add SINDEX, A, HCNT; - /* - * If there are another 8 bytes of data waiting in the - * fifo, then the carry bit will be set as a result - * of the above add command (unless A is non-negative, - * in which case the carry bit won't be set). - */ - jc dma_scb_hang_empty_fifo; - /* - * We've emptied the fifo now, but we wouldn't have got - * here if the memory transfer hadn't stopped part way - * through, so go back up to the beginning of the - * loop and start over. When it succeeds in getting - * all the data down, HDONE will be set and we'll - * jump to the code just below here. - */ - jmp dma_scb_hang_fifo; -dma_scb_hang_dma_done: - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - call dfdat_in_8; - add A, 8; - cmp A, 8 jne . - 2; - ret; - } else { - call dma_finish; - call dfdat_in_8; - call dfdat_in_8; - call dfdat_in_8; - } -dfdat_in_8: - mov DINDIR,DFDAT; -dfdat_in_7: - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT; - mov DINDIR,DFDAT ret; - } - - -/* - * Wait for DMA from host memory to data FIFO to complete, then disable - * DMA and wait for it to acknowledge that it's off. - */ -if ((p->features & AHC_CMD_CHAN) == 0) { -dma_finish: - test DFSTATUS,HDONE jz dma_finish; - /* Turn off DMA */ - and DFCNTRL, ~HDMAEN; - test DFCNTRL, HDMAEN jnz .; - ret; -} - -add_scb_to_free_list: - if ((p->flags & AHC_PAGESCBS) != 0) { - mov SCB_NEXT, FREE_SCBH; - mov FREE_SCBH, SCBPTR; - } - mvi SCB_TAG, SCB_LIST_NULL ret; - -if ((p->flags & AHC_PAGESCBS) != 0) { -get_free_or_disc_scb: - cmp FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb; - cmp DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb; -return_error: - mvi SINDEX, SCB_LIST_NULL ret; -dequeue_disc_scb: - mov SCBPTR, DISCONNECTED_SCBH; -dma_up_scb: - mvi DMAPARAMS, FIFORESET; - mov SCB_TAG call dma_scb; -unlink_disc_scb: - mov DISCONNECTED_SCBH, SCB_NEXT ret; -dequeue_free_scb: - mov SCBPTR, FREE_SCBH; - mov FREE_SCBH, SCB_NEXT ret; -} - -add_scb_to_disc_list: -/* - * Link this SCB into the DISCONNECTED list. This list holds the - * candidates for paging out an SCB if one is needed for a new command. - * Modifying the disconnected list is a critical(pause dissabled) section. - */ - mov SCB_NEXT, DISCONNECTED_SCBH; - mov DISCONNECTED_SCBH, SCBPTR ret; diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_proc.c deleted file mode 100644 index b07e4f04..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_proc.c +++ /dev/null @@ -1,373 +0,0 @@ -/*+M************************************************************************* - * Adaptec AIC7xxx device driver proc support for Linux. - * - * Copyright (c) 1995, 1996 Dean W. Gehnert - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * ---------------------------------------------------------------- - * o Modified from the EATA-DMA /proc support. - * o Additional support for device block statistics provided by - * Matthew Jacob. - * o Correction of overflow by Heinz Mauelshagen - * o Adittional corrections by Doug Ledford - * - * Dean W. Gehnert, deang@teleport.com, 05/01/96 - * - * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $ - *-M*************************************************************************/ - - -#define BLS (&aic7xxx_buffer[size]) -#define HDRB \ -" 0 - 4K 4 - 16K 16 - 64K 64 - 256K 256K - 1M 1M+" - -#ifdef PROC_DEBUG -extern int vsprintf(char *, const char *, va_list); - -static void -proc_debug(const char *fmt, ...) -{ - va_list ap; - char buf[256]; - - va_start(ap, fmt); - vsprintf(buf, fmt, ap); - printk(buf); - va_end(ap); -} -#else /* PROC_DEBUG */ -# define proc_debug(fmt, args...) -#endif /* PROC_DEBUG */ - -static int aic7xxx_buffer_size = 0; -static char *aic7xxx_buffer = NULL; - - -/*+F************************************************************************* - * Function: - * aic7xxx_set_info - * - * Description: - * Set parameters for the driver from the /proc filesystem. - *-F*************************************************************************/ -static int -aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) -{ - proc_debug("aic7xxx_set_info(): %s\n", buffer); - return (-ENOSYS); /* Currently this is a no-op */ -} - - -/*+F************************************************************************* - * Function: - * aic7xxx_proc_info - * - * Description: - * Return information to handle /proc support for the driver. - *-F*************************************************************************/ -int -aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length, - int inout) -{ - struct aic7xxx_host *p; - struct aic_dev_data *aic_dev; - struct scsi_device *sdptr; - int size = 0; - unsigned char i; - unsigned char tindex; - - for(p=first_aic7xxx; p && p->host != HBAptr; p=p->next) - ; - - if (!p) - { - size += sprintf(buffer, "Can't find adapter for host number %d\n", HBAptr->host_no); - if (size > length) - { - return (size); - } - else - { - return (length); - } - } - - if (inout == TRUE) /* Has data been written to the file? */ - { - return (aic7xxx_set_info(buffer, length, HBAptr)); - } - - p = (struct aic7xxx_host *) HBAptr->hostdata; - - /* - * It takes roughly 1K of space to hold all relevant card info, not - * counting any proc stats, so we start out with a 1.5k buffer size and - * if proc_stats is defined, then we sweep the stats structure to see - * how many drives we will be printing out for and add 384 bytes per - * device with active stats. - * - * Hmmmm...that 1.5k seems to keep growing as items get added so they - * can be easily viewed for debugging purposes. So, we bumped that - * 1.5k to 4k so we can quit having to bump it all the time. - */ - - size = 4096; - list_for_each_entry(aic_dev, &p->aic_devs, list) - size += 512; - if (aic7xxx_buffer_size != size) - { - if (aic7xxx_buffer != NULL) - { - kfree(aic7xxx_buffer); - aic7xxx_buffer_size = 0; - } - aic7xxx_buffer = kmalloc(size, GFP_KERNEL); - } - if (aic7xxx_buffer == NULL) - { - size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n", - __LINE__); - return size; - } - aic7xxx_buffer_size = size; - - size = 0; - size += sprintf(BLS, "Adaptec AIC7xxx driver version: "); - size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION); - size += sprintf(BLS, "%s", AIC7XXX_H_VERSION); - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Adapter Configuration:\n"); - size += sprintf(BLS, " SCSI Adapter: %s\n", - board_names[p->board_name_index]); - if (p->flags & AHC_TWIN) - size += sprintf(BLS, " Twin Channel Controller "); - else - { - char *channel = ""; - char *ultra = ""; - char *wide = "Narrow "; - if (p->flags & AHC_MULTI_CHANNEL) - { - channel = " Channel A"; - if (p->flags & (AHC_CHNLB|AHC_CHNLC)) - channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C"; - } - if (p->features & AHC_WIDE) - wide = "Wide "; - if (p->features & AHC_ULTRA3) - { - switch(p->chip & AHC_CHIPID_MASK) - { - case AHC_AIC7892: - case AHC_AIC7899: - ultra = "Ultra-160/m LVD/SE "; - break; - default: - ultra = "Ultra-3 LVD/SE "; - break; - } - } - else if (p->features & AHC_ULTRA2) - ultra = "Ultra-2 LVD/SE "; - else if (p->features & AHC_ULTRA) - ultra = "Ultra "; - size += sprintf(BLS, " %s%sController%s ", - ultra, wide, channel); - } - switch(p->chip & ~AHC_CHIPID_MASK) - { - case AHC_VL: - size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn); - break; - case AHC_EISA: - size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn); - break; - default: - size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus, - PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn)); - break; - } - if( !(p->maddr) ) - { - size += sprintf(BLS, " Programmed I/O Base: %lx\n", p->base); - } - else - { - size += sprintf(BLS, " PCI MMAPed I/O Base: 0x%lx\n", p->mbase); - } - if( (p->chip & (AHC_VL | AHC_EISA)) ) - { - size += sprintf(BLS, " BIOS Memory Address: 0x%08x\n", p->bios_address); - } - size += sprintf(BLS, " Adapter SEEPROM Config: %s\n", - (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." : - ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." : - "SEEPROM not found, using leftover BIOS values.") ); - size += sprintf(BLS, " Adaptec SCSI BIOS: %s\n", - (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled"); - size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); - size += sprintf(BLS, " SCBs: Active %d, Max Active %d,\n", - p->activescbs, p->max_activescbs); - size += sprintf(BLS, " Allocated %d, HW %d, " - "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs, - p->scb_data->maxscbs); - if (p->flags & AHC_EXTERNAL_SRAM) - size += sprintf(BLS, " Using External SCB SRAM\n"); - size += sprintf(BLS, " Interrupts: %ld", p->isr_count); - if (p->chip & AHC_EISA) - { - size += sprintf(BLS, " %s\n", - (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)"); - } - else - { - size += sprintf(BLS, "\n"); - } - size += sprintf(BLS, " BIOS Control Word: 0x%04x\n", - p->bios_control); - size += sprintf(BLS, " Adapter Control Word: 0x%04x\n", - p->adapter_control); - size += sprintf(BLS, " Extended Translation: %sabled\n", - (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis"); - size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable); - if (p->features & (AHC_ULTRA | AHC_ULTRA2)) - { - size += sprintf(BLS, " Ultra Enable Flags: 0x%04x\n", p->ultraenb); - } - size += sprintf(BLS, "Default Tag Queue Depth: %d\n", aic7xxx_default_queue_depth); - size += sprintf(BLS, " Tagged Queue By Device array for aic7xxx host " - "instance %d:\n", p->instance); - size += sprintf(BLS, " {"); - for(i=0; i < (MAX_TARGETS - 1); i++) - size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]); - size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]); - - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Statistics:\n\n"); - list_for_each_entry(aic_dev, &p->aic_devs, list) - { - sdptr = aic_dev->SDptr; - tindex = sdptr->channel << 3 | sdptr->id; - size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n", - p->host_no, sdptr->channel, sdptr->id, sdptr->lun); - size += sprintf(BLS, " Device using %s/%s", - (aic_dev->cur.width == MSG_EXT_WDTR_BUS_16_BIT) ? - "Wide" : "Narrow", - (aic_dev->cur.offset != 0) ? - "Sync transfers at " : "Async transfers.\n" ); - if (aic_dev->cur.offset != 0) - { - struct aic7xxx_syncrate *sync_rate; - unsigned char options = aic_dev->cur.options; - int period = aic_dev->cur.period; - int rate = (aic_dev->cur.width == - MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0; - - sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options); - if (sync_rate != NULL) - { - size += sprintf(BLS, "%s MByte/sec, offset %d\n", - sync_rate->rate[rate], - aic_dev->cur.offset ); - } - else - { - size += sprintf(BLS, "3.3 MByte/sec, offset %d\n", - aic_dev->cur.offset ); - } - } - size += sprintf(BLS, " Transinfo settings: "); - size += sprintf(BLS, "current(%d/%d/%d/%d), ", - aic_dev->cur.period, - aic_dev->cur.offset, - aic_dev->cur.width, - aic_dev->cur.options); - size += sprintf(BLS, "goal(%d/%d/%d/%d), ", - aic_dev->goal.period, - aic_dev->goal.offset, - aic_dev->goal.width, - aic_dev->goal.options); - size += sprintf(BLS, "user(%d/%d/%d/%d)\n", - p->user[tindex].period, - p->user[tindex].offset, - p->user[tindex].width, - p->user[tindex].options); - if(sdptr->simple_tags) - { - size += sprintf(BLS, " Tagged Command Queueing Enabled, Ordered Tags %s, Depth %d/%d\n", sdptr->ordered_tags ? "Enabled" : "Disabled", sdptr->queue_depth, aic_dev->max_q_depth); - } - if(aic_dev->barrier_total) - size += sprintf(BLS, " Total transfers %ld:\n (%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)\n", - aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total, - aic_dev->barrier_total, aic_dev->ordered_total); - else - size += sprintf(BLS, " Total transfers %ld:\n (%ld/%ld reads/writes)\n", - aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total); - size += sprintf(BLS, "%s\n", HDRB); - size += sprintf(BLS, " Reads:"); - for (i = 0; i < ARRAY_SIZE(aic_dev->r_bins); i++) - { - size += sprintf(BLS, " %10ld", aic_dev->r_bins[i]); - } - size += sprintf(BLS, "\n"); - size += sprintf(BLS, " Writes:"); - for (i = 0; i < ARRAY_SIZE(aic_dev->w_bins); i++) - { - size += sprintf(BLS, " %10ld", aic_dev->w_bins[i]); - } - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "\n\n"); - } - if (size >= aic7xxx_buffer_size) - { - printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n"); - } - - if (offset > size - 1) - { - kfree(aic7xxx_buffer); - aic7xxx_buffer = NULL; - aic7xxx_buffer_size = length = 0; - *start = NULL; - } - else - { - *start = buffer; - length = min_t(int, length, size - offset); - memcpy(buffer, &aic7xxx_buffer[offset], length); - } - - return (length); -} - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_reg.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_reg.h deleted file mode 100644 index 27f2334a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_reg.h +++ /dev/null @@ -1,629 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated. - */ - -#define SCSISEQ 0x00 -#define TEMODE 0x80 -#define ENSELO 0x40 -#define ENSELI 0x20 -#define ENRSELI 0x10 -#define ENAUTOATNO 0x08 -#define ENAUTOATNI 0x04 -#define ENAUTOATNP 0x02 -#define SCSIRSTO 0x01 - -#define SXFRCTL0 0x01 -#define DFON 0x80 -#define DFPEXP 0x40 -#define FAST20 0x20 -#define CLRSTCNT 0x10 -#define SPIOEN 0x08 -#define SCAMEN 0x04 -#define CLRCHN 0x02 - -#define SXFRCTL1 0x02 -#define BITBUCKET 0x80 -#define SWRAPEN 0x40 -#define ENSPCHK 0x20 -#define STIMESEL 0x18 -#define ENSTIMER 0x04 -#define ACTNEGEN 0x02 -#define STPWEN 0x01 - -#define SCSISIGO 0x03 -#define CDO 0x80 -#define IOO 0x40 -#define MSGO 0x20 -#define ATNO 0x10 -#define SELO 0x08 -#define BSYO 0x04 -#define REQO 0x02 -#define ACKO 0x01 - -#define SCSISIGI 0x03 -#define ATNI 0x10 -#define SELI 0x08 -#define BSYI 0x04 -#define REQI 0x02 -#define ACKI 0x01 - -#define SCSIRATE 0x04 -#define WIDEXFER 0x80 -#define SXFR_ULTRA2 0x7f -#define SXFR 0x70 -#define SOFS 0x0f - -#define SCSIID 0x05 -#define SCSIOFFSET 0x05 -#define SOFS_ULTRA2 0x7f - -#define SCSIDATL 0x06 - -#define SCSIDATH 0x07 - -#define STCNT 0x08 - -#define OPTIONMODE 0x08 -#define AUTORATEEN 0x80 -#define AUTOACKEN 0x40 -#define ATNMGMNTEN 0x20 -#define BUSFREEREV 0x10 -#define EXPPHASEDIS 0x08 -#define SCSIDATL_IMGEN 0x04 -#define AUTO_MSGOUT_DE 0x02 -#define DIS_MSGIN_DUALEDGE 0x01 - -#define CLRSINT0 0x0b -#define CLRSELDO 0x40 -#define CLRSELDI 0x20 -#define CLRSELINGO 0x10 -#define CLRSWRAP 0x08 -#define CLRSPIORDY 0x02 - -#define SSTAT0 0x0b -#define TARGET 0x80 -#define SELDO 0x40 -#define SELDI 0x20 -#define SELINGO 0x10 -#define IOERR 0x08 -#define SWRAP 0x08 -#define SDONE 0x04 -#define SPIORDY 0x02 -#define DMADONE 0x01 - -#define CLRSINT1 0x0c -#define CLRSELTIMEO 0x80 -#define CLRATNO 0x40 -#define CLRSCSIRSTI 0x20 -#define CLRBUSFREE 0x08 -#define CLRSCSIPERR 0x04 -#define CLRPHASECHG 0x02 -#define CLRREQINIT 0x01 - -#define SSTAT1 0x0c -#define SELTO 0x80 -#define ATNTARG 0x40 -#define SCSIRSTI 0x20 -#define PHASEMIS 0x10 -#define BUSFREE 0x08 -#define SCSIPERR 0x04 -#define PHASECHG 0x02 -#define REQINIT 0x01 - -#define SSTAT2 0x0d -#define OVERRUN 0x80 -#define SHVALID 0x40 -#define WIDE_RES 0x20 -#define SFCNT 0x1f -#define EXP_ACTIVE 0x10 -#define CRCVALERR 0x08 -#define CRCENDERR 0x04 -#define CRCREQERR 0x02 -#define DUAL_EDGE_ERROR 0x01 - -#define SSTAT3 0x0e -#define SCSICNT 0xf0 -#define OFFCNT 0x0f - -#define SCSIID_ULTRA2 0x0f -#define OID 0x0f - -#define SIMODE0 0x10 -#define ENSELDO 0x40 -#define ENSELDI 0x20 -#define ENSELINGO 0x10 -#define ENIOERR 0x08 -#define ENSWRAP 0x08 -#define ENSDONE 0x04 -#define ENSPIORDY 0x02 -#define ENDMADONE 0x01 - -#define SIMODE1 0x11 -#define ENSELTIMO 0x80 -#define ENATNTARG 0x40 -#define ENSCSIRST 0x20 -#define ENPHASEMIS 0x10 -#define ENBUSFREE 0x08 -#define ENSCSIPERR 0x04 -#define ENPHASECHG 0x02 -#define ENREQINIT 0x01 - -#define SCSIBUSL 0x12 - -#define SCSIBUSH 0x13 - -#define SHADDR 0x14 - -#define SELTIMER 0x18 -#define STAGE6 0x20 -#define STAGE5 0x10 -#define STAGE4 0x08 -#define STAGE3 0x04 -#define STAGE2 0x02 -#define STAGE1 0x01 - -#define SELID 0x19 -#define SELID_MASK 0xf0 -#define ONEBIT 0x08 - -#define SPIOCAP 0x1b -#define SOFT1 0x80 -#define SOFT0 0x40 -#define SOFTCMDEN 0x20 -#define HAS_BRDCTL 0x10 -#define SEEPROM 0x08 -#define EEPROM 0x04 -#define ROM 0x02 -#define SSPIOCPS 0x01 - -#define BRDCTL 0x1d -#define BRDDAT7 0x80 -#define BRDDAT6 0x40 -#define BRDDAT5 0x20 -#define BRDDAT4 0x10 -#define BRDSTB 0x10 -#define BRDCS 0x08 -#define BRDDAT3 0x08 -#define BRDDAT2 0x04 -#define BRDRW 0x04 -#define BRDRW_ULTRA2 0x02 -#define BRDCTL1 0x02 -#define BRDSTB_ULTRA2 0x01 -#define BRDCTL0 0x01 - -#define SEECTL 0x1e -#define EXTARBACK 0x80 -#define EXTARBREQ 0x40 -#define SEEMS 0x20 -#define SEERDY 0x10 -#define SEECS 0x08 -#define SEECK 0x04 -#define SEEDO 0x02 -#define SEEDI 0x01 - -#define SBLKCTL 0x1f -#define DIAGLEDEN 0x80 -#define DIAGLEDON 0x40 -#define AUTOFLUSHDIS 0x20 -#define ENAB40 0x08 -#define ENAB20 0x04 -#define SELWIDE 0x02 -#define XCVR 0x01 - -#define SRAM_BASE 0x20 - -#define TARG_SCSIRATE 0x20 - -#define ULTRA_ENB 0x30 - -#define DISC_DSB 0x32 - -#define MSG_OUT 0x34 - -#define DMAPARAMS 0x35 -#define PRELOADEN 0x80 -#define WIDEODD 0x40 -#define SCSIEN 0x20 -#define SDMAENACK 0x10 -#define SDMAEN 0x10 -#define HDMAEN 0x08 -#define HDMAENACK 0x08 -#define DIRECTION 0x04 -#define FIFOFLUSH 0x02 -#define FIFORESET 0x01 - -#define SEQ_FLAGS 0x36 -#define IDENTIFY_SEEN 0x80 -#define SCBPTR_VALID 0x20 -#define DPHASE 0x10 -#define AMTARGET 0x08 -#define WIDE_BUS 0x02 -#define TWIN_BUS 0x01 - -#define SAVED_TCL 0x37 - -#define SG_COUNT 0x38 - -#define SG_NEXT 0x39 - -#define LASTPHASE 0x3d -#define P_MESGIN 0xe0 -#define PHASE_MASK 0xe0 -#define P_STATUS 0xc0 -#define P_MESGOUT 0xa0 -#define P_COMMAND 0x80 -#define CDI 0x80 -#define IOI 0x40 -#define P_DATAIN 0x40 -#define MSGI 0x20 -#define P_BUSFREE 0x01 -#define P_DATAOUT 0x00 - -#define WAITING_SCBH 0x3e - -#define DISCONNECTED_SCBH 0x3f - -#define FREE_SCBH 0x40 - -#define HSCB_ADDR 0x41 - -#define SCBID_ADDR 0x45 - -#define TMODE_CMDADDR 0x49 - -#define KERNEL_QINPOS 0x4d - -#define QINPOS 0x4e - -#define QOUTPOS 0x4f - -#define TMODE_CMDADDR_NEXT 0x50 - -#define ARG_1 0x51 -#define RETURN_1 0x51 -#define SEND_MSG 0x80 -#define SEND_SENSE 0x40 -#define SEND_REJ 0x20 -#define MSGOUT_PHASEMIS 0x10 - -#define ARG_2 0x52 -#define RETURN_2 0x52 - -#define LAST_MSG 0x53 - -#define PREFETCH_CNT 0x54 - -#define SCSICONF 0x5a -#define TERM_ENB 0x80 -#define RESET_SCSI 0x40 -#define HWSCSIID 0x0f -#define HSCSIID 0x07 - -#define HOSTCONF 0x5d - -#define HA_274_BIOSCTRL 0x5f -#define BIOSMODE 0x30 -#define BIOSDISABLED 0x30 -#define CHANNEL_B_PRIMARY 0x08 - -#define SEQCTL 0x60 -#define PERRORDIS 0x80 -#define PAUSEDIS 0x40 -#define FAILDIS 0x20 -#define FASTMODE 0x10 -#define BRKADRINTEN 0x08 -#define STEP 0x04 -#define SEQRESET 0x02 -#define LOADRAM 0x01 - -#define SEQRAM 0x61 - -#define SEQADDR0 0x62 - -#define SEQADDR1 0x63 -#define SEQADDR1_MASK 0x01 - -#define ACCUM 0x64 - -#define SINDEX 0x65 - -#define DINDEX 0x66 - -#define ALLONES 0x69 - -#define ALLZEROS 0x6a - -#define NONE 0x6a - -#define FLAGS 0x6b -#define ZERO 0x02 -#define CARRY 0x01 - -#define SINDIR 0x6c - -#define DINDIR 0x6d - -#define FUNCTION1 0x6e - -#define STACK 0x6f - -#define TARG_OFFSET 0x70 - -#define BCTL 0x84 -#define ACE 0x08 -#define ENABLE 0x01 - -#define DSCOMMAND0 0x84 -#define INTSCBRAMSEL 0x08 -#define RAMPS 0x04 -#define USCBSIZE32 0x02 -#define CIOPARCKEN 0x01 - -#define DSCOMMAND 0x84 -#define CACHETHEN 0x80 -#define DPARCKEN 0x40 -#define MPARCKEN 0x20 -#define EXTREQLCK 0x10 - -#define BUSTIME 0x85 -#define BOFF 0xf0 -#define BON 0x0f - -#define BUSSPD 0x86 -#define DFTHRSH 0xc0 -#define STBOFF 0x38 -#define STBON 0x07 - -#define DSPCISTATUS 0x86 -#define DFTHRSH_100 0xc0 - -#define HCNTRL 0x87 -#define POWRDN 0x40 -#define SWINT 0x10 -#define IRQMS 0x08 -#define PAUSE 0x04 -#define INTEN 0x02 -#define CHIPRST 0x01 -#define CHIPRSTACK 0x01 - -#define HADDR 0x88 - -#define HCNT 0x8c - -#define SCBPTR 0x90 - -#define INTSTAT 0x91 -#define SEQINT_MASK 0xf1 -#define DATA_OVERRUN 0xe1 -#define MSGIN_PHASEMIS 0xd1 -#define TRACEPOINT2 0xc1 -#define SEQ_SG_FIXUP 0xb1 -#define AWAITING_MSG 0xa1 -#define RESIDUAL 0x81 -#define BAD_STATUS 0x71 -#define REJECT_MSG 0x61 -#define WIDE_RESIDUE 0x51 -#define EXTENDED_MSG 0x41 -#define NO_MATCH 0x31 -#define NO_IDENT 0x21 -#define SEND_REJECT 0x11 -#define INT_PEND 0x0f -#define BRKADRINT 0x08 -#define SCSIINT 0x04 -#define CMDCMPLT 0x02 -#define BAD_PHASE 0x01 -#define SEQINT 0x01 - -#define CLRINT 0x92 -#define CLRPARERR 0x10 -#define CLRBRKADRINT 0x08 -#define CLRSCSIINT 0x04 -#define CLRCMDINT 0x02 -#define CLRSEQINT 0x01 - -#define ERROR 0x92 -#define CIOPARERR 0x80 -#define PCIERRSTAT 0x40 -#define MPARERR 0x20 -#define DPARERR 0x10 -#define SQPARERR 0x08 -#define ILLOPCODE 0x04 -#define DSCTMOUT 0x02 -#define ILLSADDR 0x02 -#define ILLHADDR 0x01 - -#define DFCNTRL 0x93 - -#define DFSTATUS 0x94 -#define PRELOAD_AVAIL 0x80 -#define DWORDEMP 0x20 -#define MREQPEND 0x10 -#define HDONE 0x08 -#define DFTHRESH 0x04 -#define FIFOFULL 0x02 -#define FIFOEMP 0x01 - -#define DFDAT 0x99 - -#define SCBCNT 0x9a -#define SCBAUTO 0x80 -#define SCBCNT_MASK 0x1f - -#define QINFIFO 0x9b - -#define QINCNT 0x9c - -#define SCSIDATL_IMG 0x9c - -#define QOUTFIFO 0x9d - -#define CRCCONTROL1 0x9d -#define CRCONSEEN 0x80 -#define CRCVALCHKEN 0x40 -#define CRCENDCHKEN 0x20 -#define CRCREQCHKEN 0x10 -#define TARGCRCENDEN 0x08 -#define TARGCRCCNTEN 0x04 - -#define SCSIPHASE 0x9e -#define SP_STATUS 0x20 -#define SP_COMMAND 0x10 -#define SP_MSG_IN 0x08 -#define SP_MSG_OUT 0x04 -#define SP_DATA_IN 0x02 -#define SP_DATA_OUT 0x01 - -#define QOUTCNT 0x9e - -#define SFUNCT 0x9f -#define ALT_MODE 0x80 - -#define SCB_CONTROL 0xa0 -#define MK_MESSAGE 0x80 -#define DISCENB 0x40 -#define TAG_ENB 0x20 -#define DISCONNECTED 0x04 -#define SCB_TAG_TYPE 0x03 - -#define SCB_BASE 0xa0 - -#define SCB_TCL 0xa1 -#define TID 0xf0 -#define SELBUSB 0x08 -#define LID 0x07 - -#define SCB_TARGET_STATUS 0xa2 - -#define SCB_SGCOUNT 0xa3 - -#define SCB_SGPTR 0xa4 - -#define SCB_RESID_SGCNT 0xa8 - -#define SCB_RESID_DCNT 0xa9 - -#define SCB_DATAPTR 0xac - -#define SCB_DATACNT 0xb0 - -#define SCB_CMDPTR 0xb4 - -#define SCB_CMDLEN 0xb8 - -#define SCB_TAG 0xb9 - -#define SCB_NEXT 0xba - -#define SCB_PREV 0xbb - -#define SCB_BUSYTARGETS 0xbc - -#define SEECTL_2840 0xc0 -#define CS_2840 0x04 -#define CK_2840 0x02 -#define DO_2840 0x01 - -#define STATUS_2840 0xc1 -#define EEPROM_TF 0x80 -#define BIOS_SEL 0x60 -#define ADSEL 0x1e -#define DI_2840 0x01 - -#define CCHADDR 0xe0 - -#define CCHCNT 0xe8 - -#define CCSGRAM 0xe9 - -#define CCSGADDR 0xea - -#define CCSGCTL 0xeb -#define CCSGDONE 0x80 -#define CCSGEN 0x08 -#define FLAG 0x02 -#define CCSGRESET 0x01 - -#define CCSCBRAM 0xec - -#define CCSCBADDR 0xed - -#define CCSCBCTL 0xee -#define CCSCBDONE 0x80 -#define ARRDONE 0x40 -#define CCARREN 0x10 -#define CCSCBEN 0x08 -#define CCSCBDIR 0x04 -#define CCSCBRESET 0x01 - -#define CCSCBCNT 0xef - -#define CCSCBPTR 0xf1 - -#define HNSCB_QOFF 0xf4 - -#define HESCB_QOFF 0xf5 - -#define SNSCB_QOFF 0xf6 - -#define SESCB_QOFF 0xf7 - -#define SDSCB_QOFF 0xf8 - -#define QOFF_CTLSTA 0xfa -#define ESTABLISH_SCB_AVAIL 0x80 -#define SCB_AVAIL 0x40 -#define SNSCB_ROLLOVER 0x20 -#define SDSCB_ROLLOVER 0x10 -#define SESCB_ROLLOVER 0x08 -#define SCB_QSIZE 0x07 -#define SCB_QSIZE_256 0x06 - -#define DFF_THRSH 0xfb -#define WR_DFTHRSH 0x70 -#define WR_DFTHRSH_MAX 0x70 -#define WR_DFTHRSH_90 0x60 -#define WR_DFTHRSH_85 0x50 -#define WR_DFTHRSH_75 0x40 -#define WR_DFTHRSH_63 0x30 -#define WR_DFTHRSH_50 0x20 -#define WR_DFTHRSH_25 0x10 -#define RD_DFTHRSH_MAX 0x07 -#define RD_DFTHRSH 0x07 -#define RD_DFTHRSH_90 0x06 -#define RD_DFTHRSH_85 0x05 -#define RD_DFTHRSH_75 0x04 -#define RD_DFTHRSH_63 0x03 -#define RD_DFTHRSH_50 0x02 -#define RD_DFTHRSH_25 0x01 -#define WR_DFTHRSH_MIN 0x00 -#define RD_DFTHRSH_MIN 0x00 - -#define SG_CACHEPTR 0xfc -#define SG_USER_DATA 0xfc -#define LAST_SEG 0x02 -#define LAST_SEG_DONE 0x01 - - -#define CMD_GROUP2_BYTE_DELTA 0xfa -#define MAX_OFFSET_8BIT 0x0f -#define BUS_16_BIT 0x01 -#define QINFIFO_OFFSET 0x02 -#define CMD_GROUP5_BYTE_DELTA 0x0b -#define CMD_GROUP_CODE_SHIFT 0x05 -#define MAX_OFFSET_ULTRA2 0x7f -#define MAX_OFFSET_16BIT 0x08 -#define BUS_8_BIT 0x00 -#define QOUTFIFO_OFFSET 0x01 -#define UNTAGGEDSCB_OFFSET 0x00 -#define CCSGRAM_MAXSEGS 0x10 -#define SCB_LIST_NULL 0xff -#define SG_SIZEOF 0x08 -#define CMD_GROUP4_BYTE_DELTA 0x04 -#define CMD_GROUP0_BYTE_DELTA 0xfc -#define HOST_MSG 0xff -#define BUS_32_BIT 0x02 -#define CCSGADDR_MAX 0x80 - - -/* Downloaded Constant Definitions */ -#define TMODE_NUMCMDS 0x00 diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_seq.c b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_seq.c deleted file mode 100644 index e1bc140e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/aic7xxx_seq.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * DO NOT EDIT - This file is automatically generated. - */ -static unsigned char seqprog[] = { - 0xff, 0x6a, 0x06, 0x08, - 0x7f, 0x02, 0x04, 0x08, - 0x12, 0x6a, 0x00, 0x00, - 0xff, 0x6a, 0xd6, 0x09, - 0xff, 0x6a, 0xdc, 0x09, - 0x00, 0x65, 0xca, 0x58, - 0xf7, 0x01, 0x02, 0x08, - 0xff, 0x4e, 0xc8, 0x08, - 0xbf, 0x60, 0xc0, 0x08, - 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0c, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0x60, 0x0b, 0x86, 0x68, - 0x40, 0x00, 0x0c, 0x68, - 0x08, 0x1f, 0x3e, 0x10, - 0xff, 0x3e, 0x48, 0x60, - 0x40, 0xfa, 0x10, 0x78, - 0xff, 0xf6, 0xd4, 0x08, - 0x01, 0x4e, 0x9c, 0x18, - 0x40, 0x60, 0xc0, 0x00, - 0x00, 0x4d, 0x10, 0x70, - 0x01, 0x4e, 0x9c, 0x18, - 0xbf, 0x60, 0xc0, 0x08, - 0x00, 0x6a, 0x86, 0x5c, - 0xff, 0x4e, 0xc8, 0x18, - 0x02, 0x6a, 0x70, 0x5b, - 0xff, 0x52, 0x20, 0x09, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x52, 0xe6, 0x5b, - 0x03, 0xb0, 0x52, 0x31, - 0xff, 0xb0, 0x52, 0x09, - 0xff, 0xb1, 0x54, 0x09, - 0xff, 0xb2, 0x56, 0x09, - 0xff, 0xa3, 0x50, 0x09, - 0xff, 0x3e, 0x74, 0x09, - 0xff, 0x90, 0x7c, 0x08, - 0xff, 0x3e, 0x20, 0x09, - 0x00, 0x65, 0x4e, 0x58, - 0x00, 0x65, 0x0c, 0x40, - 0xf7, 0x1f, 0xca, 0x08, - 0x08, 0xa1, 0xc8, 0x08, - 0x00, 0x65, 0xca, 0x00, - 0xff, 0x65, 0x3e, 0x08, - 0xf0, 0xa1, 0xc8, 0x08, - 0x0f, 0x0f, 0x1e, 0x08, - 0x00, 0x0f, 0x1e, 0x00, - 0xf0, 0xa1, 0xc8, 0x08, - 0x0f, 0x05, 0x0a, 0x08, - 0x00, 0x05, 0x0a, 0x00, - 0xff, 0x6a, 0x0c, 0x08, - 0x5a, 0x6a, 0x00, 0x04, - 0x12, 0x65, 0x02, 0x00, - 0x31, 0x6a, 0xca, 0x00, - 0x80, 0x37, 0x6e, 0x68, - 0xff, 0x65, 0xca, 0x18, - 0xff, 0x37, 0xdc, 0x08, - 0xff, 0x6e, 0xc8, 0x08, - 0x00, 0x6c, 0x76, 0x78, - 0x20, 0x01, 0x02, 0x00, - 0x4c, 0x37, 0xc8, 0x28, - 0x08, 0x1f, 0x7e, 0x78, - 0x08, 0x37, 0x6e, 0x00, - 0x08, 0x64, 0xc8, 0x00, - 0x70, 0x64, 0xca, 0x18, - 0xff, 0x6c, 0x0a, 0x08, - 0x20, 0x64, 0xca, 0x18, - 0xff, 0x6c, 0x08, 0x0c, - 0x40, 0x0b, 0x96, 0x68, - 0x20, 0x6a, 0x16, 0x00, - 0xf0, 0x19, 0x6e, 0x08, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x08, 0x6a, 0x66, 0x58, - 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x12, 0x6a, 0x00, 0x00, - 0x40, 0x6a, 0x16, 0x00, - 0xff, 0x3e, 0x20, 0x09, - 0xff, 0xba, 0x7c, 0x08, - 0xff, 0xa1, 0x6e, 0x08, - 0x08, 0x6a, 0x18, 0x00, - 0x08, 0x11, 0x22, 0x00, - 0x08, 0x6a, 0x66, 0x58, - 0x80, 0x6a, 0x68, 0x00, - 0x80, 0x36, 0x6c, 0x00, - 0x00, 0x65, 0xba, 0x5b, - 0xff, 0x3d, 0xc8, 0x08, - 0xbf, 0x64, 0xe2, 0x78, - 0x80, 0x64, 0xc8, 0x71, - 0xa0, 0x64, 0xf8, 0x71, - 0xc0, 0x64, 0xf0, 0x71, - 0xe0, 0x64, 0x38, 0x72, - 0x01, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xca, 0x58, - 0xff, 0x06, 0xd4, 0x08, - 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xc4, 0x78, - 0x08, 0x0c, 0x0c, 0x68, - 0x01, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0x26, 0x09, - 0x02, 0x6a, 0x08, 0x30, - 0xff, 0x6a, 0x08, 0x08, - 0xdf, 0x01, 0x02, 0x08, - 0x01, 0x6a, 0x7a, 0x00, - 0xff, 0x6a, 0x6c, 0x0c, - 0x04, 0x14, 0x10, 0x31, - 0x03, 0xa9, 0x18, 0x31, - 0x03, 0xa9, 0x10, 0x30, - 0x08, 0x6a, 0xcc, 0x00, - 0xa9, 0x6a, 0xd0, 0x5b, - 0x00, 0x65, 0x02, 0x41, - 0xa8, 0x6a, 0x6a, 0x00, - 0x79, 0x6a, 0x6a, 0x00, - 0x40, 0x3d, 0xea, 0x68, - 0x04, 0x35, 0x6a, 0x00, - 0x00, 0x65, 0x2a, 0x5b, - 0x80, 0x6a, 0xd4, 0x01, - 0x10, 0x36, 0xd6, 0x68, - 0x10, 0x36, 0x6c, 0x00, - 0x07, 0xac, 0x10, 0x31, - 0x05, 0xa3, 0x70, 0x30, - 0x03, 0x8c, 0x10, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xc8, 0x5b, - 0x00, 0x65, 0xc2, 0x5b, - 0x38, 0x6a, 0xcc, 0x00, - 0xa3, 0x6a, 0xcc, 0x5b, - 0xff, 0x38, 0x12, 0x69, - 0x80, 0x02, 0x04, 0x00, - 0xe7, 0x35, 0x6a, 0x08, - 0x03, 0x69, 0x18, 0x31, - 0x03, 0x69, 0x10, 0x30, - 0xff, 0x6a, 0x10, 0x00, - 0xff, 0x6a, 0x12, 0x00, - 0xff, 0x6a, 0x14, 0x00, - 0x22, 0x38, 0xc8, 0x28, - 0x01, 0x38, 0x1c, 0x61, - 0x02, 0x64, 0xc8, 0x00, - 0x01, 0x38, 0x1c, 0x61, - 0xbf, 0x35, 0x6a, 0x08, - 0xff, 0x64, 0xf8, 0x09, - 0xff, 0x35, 0x26, 0x09, - 0x80, 0x02, 0xa4, 0x69, - 0x10, 0x0c, 0x7a, 0x69, - 0x80, 0x94, 0x22, 0x79, - 0x00, 0x35, 0x0a, 0x5b, - 0x80, 0x02, 0xa4, 0x69, - 0xff, 0x65, 0x94, 0x79, - 0x01, 0x38, 0x70, 0x71, - 0xff, 0x38, 0x70, 0x18, - 0xff, 0x38, 0x94, 0x79, - 0x80, 0xea, 0x4a, 0x61, - 0xef, 0x38, 0xc8, 0x18, - 0x80, 0x6a, 0xc8, 0x00, - 0x00, 0x65, 0x3c, 0x49, - 0x33, 0x38, 0xc8, 0x28, - 0xff, 0x64, 0xd0, 0x09, - 0x04, 0x39, 0xc0, 0x31, - 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x42, 0x79, - 0xf7, 0xeb, 0xd6, 0x09, - 0x08, 0xeb, 0x46, 0x69, - 0x01, 0x6a, 0xd6, 0x01, - 0x08, 0xe9, 0x10, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0xff, 0x38, 0x70, 0x18, - 0x88, 0x6a, 0xcc, 0x00, - 0x39, 0x6a, 0xce, 0x5b, - 0x08, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x78, 0x5c, - 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x6a, 0x5c, - 0x00, 0x65, 0xc2, 0x5b, - 0xff, 0x6a, 0xc8, 0x08, - 0x08, 0x39, 0x72, 0x18, - 0x00, 0x3a, 0x74, 0x20, - 0x00, 0x65, 0x02, 0x41, - 0x01, 0x0c, 0x6c, 0x79, - 0x10, 0x0c, 0x02, 0x79, - 0x10, 0x0c, 0x7a, 0x69, - 0x01, 0xfc, 0x70, 0x79, - 0xff, 0x6a, 0x70, 0x08, - 0x01, 0x0c, 0x76, 0x79, - 0x10, 0x0c, 0x02, 0x79, - 0x00, 0x65, 0xae, 0x59, - 0x01, 0xfc, 0x94, 0x69, - 0x40, 0x0d, 0x84, 0x69, - 0xb1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x94, 0x41, - 0x2e, 0xfc, 0xa2, 0x28, - 0x3f, 0x38, 0xc8, 0x08, - 0x00, 0x51, 0x94, 0x71, - 0xff, 0x6a, 0xc8, 0x08, - 0xf8, 0x39, 0x72, 0x18, - 0xff, 0x3a, 0x74, 0x20, - 0x01, 0x38, 0x70, 0x18, - 0x00, 0x65, 0x86, 0x41, - 0x03, 0x08, 0x52, 0x31, - 0xff, 0x38, 0x50, 0x09, - 0x12, 0x01, 0x02, 0x00, - 0xff, 0x08, 0x52, 0x09, - 0xff, 0x09, 0x54, 0x09, - 0xff, 0x0a, 0x56, 0x09, - 0xff, 0x38, 0x50, 0x09, - 0x00, 0x65, 0xaa, 0x40, - 0x10, 0x0c, 0xa4, 0x79, - 0x00, 0x65, 0xae, 0x59, - 0x7f, 0x02, 0x04, 0x08, - 0xe1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0x04, 0x93, 0xc2, 0x69, - 0xdf, 0x93, 0x26, 0x09, - 0x20, 0x93, 0xb2, 0x69, - 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xb6, 0x79, - 0x01, 0x94, 0xb6, 0x79, - 0x01, 0x94, 0xb6, 0x79, - 0x01, 0x94, 0xb6, 0x79, - 0x01, 0x94, 0xb6, 0x79, - 0x10, 0x94, 0xc0, 0x69, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xc4, 0x69, - 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x2a, 0x5b, - 0x05, 0xb4, 0x10, 0x31, - 0x02, 0x6a, 0x1a, 0x31, - 0x03, 0x8c, 0x10, 0x30, - 0x88, 0x6a, 0xcc, 0x00, - 0xb4, 0x6a, 0xcc, 0x5b, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x00, 0x65, 0xc2, 0x5b, - 0x3d, 0x6a, 0x0a, 0x5b, - 0xac, 0x6a, 0x26, 0x01, - 0x04, 0x0b, 0xde, 0x69, - 0x04, 0x0b, 0xe4, 0x69, - 0x10, 0x0c, 0xe0, 0x79, - 0x02, 0x03, 0xe8, 0x79, - 0x11, 0x0c, 0xe4, 0x79, - 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xea, 0x69, - 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x00, 0x65, 0x2a, 0x5b, - 0xff, 0x06, 0x44, 0x09, - 0x00, 0x65, 0xaa, 0x40, - 0x10, 0x3d, 0x06, 0x00, - 0xff, 0x34, 0xca, 0x08, - 0x80, 0x65, 0x1c, 0x62, - 0x0f, 0xa1, 0xca, 0x08, - 0x07, 0xa1, 0xca, 0x08, - 0x40, 0xa0, 0xc8, 0x08, - 0x00, 0x65, 0xca, 0x00, - 0x80, 0x65, 0xca, 0x00, - 0x80, 0xa0, 0x0c, 0x7a, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0x1e, 0x42, - 0x20, 0xa0, 0x24, 0x7a, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0xba, 0x5b, - 0xa0, 0x3d, 0x2c, 0x62, - 0x23, 0xa0, 0x0c, 0x08, - 0x00, 0x65, 0xba, 0x5b, - 0xa0, 0x3d, 0x2c, 0x62, - 0x00, 0xb9, 0x24, 0x42, - 0xff, 0x65, 0x24, 0x62, - 0xa1, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x10, 0x51, 0x2c, 0x72, - 0x40, 0x6a, 0x18, 0x00, - 0xff, 0x65, 0x0c, 0x08, - 0x00, 0x65, 0xba, 0x5b, - 0xa0, 0x3d, 0xf6, 0x71, - 0x40, 0x6a, 0x18, 0x00, - 0xff, 0x34, 0xa6, 0x08, - 0x80, 0x34, 0x34, 0x62, - 0x7f, 0xa0, 0x40, 0x09, - 0x08, 0x6a, 0x68, 0x00, - 0x00, 0x65, 0xaa, 0x40, - 0x64, 0x6a, 0x00, 0x5b, - 0x80, 0x64, 0xaa, 0x6a, - 0x04, 0x64, 0x8c, 0x72, - 0x02, 0x64, 0x92, 0x72, - 0x00, 0x6a, 0x54, 0x72, - 0x03, 0x64, 0xa6, 0x72, - 0x01, 0x64, 0x88, 0x72, - 0x07, 0x64, 0xe8, 0x72, - 0x08, 0x64, 0x50, 0x72, - 0x23, 0x64, 0xec, 0x72, - 0x11, 0x6a, 0x22, 0x01, - 0x07, 0x6a, 0xf2, 0x5a, - 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0xaa, 0x40, - 0xff, 0xa8, 0x58, 0x6a, - 0xff, 0xa2, 0x70, 0x7a, - 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xe6, 0x5b, - 0xff, 0xa2, 0x70, 0x7a, - 0x71, 0x6a, 0x22, 0x01, - 0xff, 0x6a, 0xd4, 0x08, - 0x40, 0x51, 0x70, 0x62, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xe6, 0x5b, - 0xff, 0x3e, 0x74, 0x09, - 0xff, 0x90, 0x7c, 0x08, - 0x00, 0x65, 0x4e, 0x58, - 0x00, 0x65, 0xbc, 0x40, - 0x20, 0xa0, 0x78, 0x6a, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x90, 0x5b, - 0xff, 0x6a, 0xa6, 0x5b, - 0xff, 0xf8, 0xc8, 0x08, - 0xff, 0x4f, 0xc8, 0x08, - 0x01, 0x6a, 0x90, 0x5b, - 0x00, 0xb9, 0xa6, 0x5b, - 0x01, 0x4f, 0x9e, 0x18, - 0x02, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x80, 0x5c, - 0x00, 0x65, 0xbc, 0x40, - 0x41, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0x04, 0xa0, 0x40, 0x01, - 0x00, 0x65, 0x98, 0x5c, - 0x00, 0x65, 0xbc, 0x40, - 0x10, 0x36, 0x50, 0x7a, - 0x05, 0x38, 0x46, 0x31, - 0x04, 0x14, 0x58, 0x31, - 0x03, 0xa9, 0x60, 0x31, - 0xa3, 0x6a, 0xcc, 0x00, - 0x38, 0x6a, 0xcc, 0x5b, - 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xce, 0x5b, - 0xa9, 0x6a, 0xd0, 0x5b, - 0x00, 0x65, 0x50, 0x42, - 0xef, 0x36, 0x6c, 0x08, - 0x00, 0x65, 0x50, 0x42, - 0x0f, 0x64, 0xc8, 0x08, - 0x07, 0x64, 0xc8, 0x08, - 0x00, 0x37, 0x6e, 0x00, - 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x60, 0x5b, - 0xff, 0x51, 0xbc, 0x72, - 0x20, 0x36, 0xc6, 0x7a, - 0x00, 0x90, 0x4e, 0x5b, - 0x00, 0x65, 0xc8, 0x42, - 0xff, 0x06, 0xd4, 0x08, - 0x00, 0x65, 0xba, 0x5b, - 0xe0, 0x3d, 0xe2, 0x62, - 0x20, 0x12, 0xe2, 0x62, - 0x51, 0x6a, 0xf6, 0x5a, - 0x00, 0x65, 0x48, 0x5b, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0xa1, 0xda, 0x62, - 0x04, 0xa0, 0xda, 0x7a, - 0xfb, 0xa0, 0x40, 0x09, - 0x80, 0x36, 0x6c, 0x00, - 0x80, 0xa0, 0x50, 0x7a, - 0x7f, 0xa0, 0x40, 0x09, - 0xff, 0x6a, 0xf2, 0x5a, - 0x00, 0x65, 0x50, 0x42, - 0x04, 0xa0, 0xe0, 0x7a, - 0x00, 0x65, 0x98, 0x5c, - 0x00, 0x65, 0xe2, 0x42, - 0x00, 0x65, 0x80, 0x5c, - 0x31, 0x6a, 0x22, 0x01, - 0x0c, 0x6a, 0xf2, 0x5a, - 0x00, 0x65, 0x50, 0x42, - 0x61, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x50, 0x42, - 0x51, 0x6a, 0xf6, 0x5a, - 0x51, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0x50, 0x42, - 0x10, 0x3d, 0x06, 0x00, - 0xff, 0x65, 0x68, 0x0c, - 0xff, 0x06, 0xd4, 0x08, - 0x01, 0x0c, 0xf8, 0x7a, - 0x04, 0x0c, 0xfa, 0x6a, - 0xe0, 0x03, 0x7a, 0x08, - 0xe0, 0x3d, 0x06, 0x63, - 0xff, 0x65, 0xcc, 0x08, - 0xff, 0x12, 0xda, 0x0c, - 0xff, 0x06, 0xd4, 0x0c, - 0xd1, 0x6a, 0x22, 0x01, - 0x00, 0x65, 0xaa, 0x40, - 0xff, 0x65, 0x26, 0x09, - 0x01, 0x0b, 0x1a, 0x6b, - 0x10, 0x0c, 0x0c, 0x7b, - 0x04, 0x0b, 0x14, 0x6b, - 0xff, 0x6a, 0xca, 0x08, - 0x04, 0x93, 0x18, 0x6b, - 0x01, 0x94, 0x16, 0x7b, - 0x10, 0x94, 0x18, 0x6b, - 0x80, 0x3d, 0x1e, 0x73, - 0x0f, 0x04, 0x22, 0x6b, - 0x02, 0x03, 0x22, 0x7b, - 0x11, 0x0c, 0x1e, 0x7b, - 0xc7, 0x93, 0x26, 0x09, - 0xff, 0x99, 0xd4, 0x08, - 0x38, 0x93, 0x24, 0x6b, - 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0x36, 0x28, 0x6b, - 0x21, 0x6a, 0x22, 0x05, - 0xff, 0x65, 0x20, 0x09, - 0xff, 0x51, 0x36, 0x63, - 0xff, 0x37, 0xc8, 0x08, - 0xa1, 0x6a, 0x42, 0x43, - 0xff, 0x51, 0xc8, 0x08, - 0xb9, 0x6a, 0x42, 0x43, - 0xff, 0x90, 0xa4, 0x08, - 0xff, 0xba, 0x46, 0x73, - 0xff, 0xba, 0x20, 0x09, - 0xff, 0x65, 0xca, 0x18, - 0x00, 0x6c, 0x3a, 0x63, - 0xff, 0x90, 0xca, 0x0c, - 0xff, 0x6a, 0xca, 0x04, - 0x20, 0x36, 0x5a, 0x7b, - 0x00, 0x90, 0x2e, 0x5b, - 0xff, 0x65, 0x5a, 0x73, - 0xff, 0x52, 0x58, 0x73, - 0xff, 0xba, 0xcc, 0x08, - 0xff, 0x52, 0x20, 0x09, - 0xff, 0x66, 0x74, 0x09, - 0xff, 0x65, 0x20, 0x0d, - 0xff, 0xba, 0x7e, 0x0c, - 0x00, 0x6a, 0x86, 0x5c, - 0x0d, 0x6a, 0x6a, 0x00, - 0x00, 0x51, 0xe6, 0x43, - 0xff, 0x3f, 0xb4, 0x73, - 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3f, 0x2e, 0x5b, - 0xff, 0x65, 0xb4, 0x73, - 0x20, 0x36, 0x6c, 0x00, - 0x20, 0xa0, 0x6e, 0x6b, - 0xff, 0xb9, 0xa2, 0x0c, - 0xff, 0x6a, 0xa2, 0x04, - 0xff, 0x65, 0xa4, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xda, 0x5b, - 0x01, 0x6a, 0xd0, 0x01, - 0x09, 0x6a, 0xd6, 0x01, - 0x80, 0xeb, 0x7a, 0x7b, - 0x01, 0x6a, 0xd6, 0x01, - 0x01, 0xe9, 0xa4, 0x34, - 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xda, 0x5b, - 0x01, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x0d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x78, 0x5c, - 0xff, 0x99, 0xa4, 0x0c, - 0xff, 0x65, 0xa4, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xda, 0x5b, - 0x01, 0x6a, 0xd0, 0x01, - 0x01, 0x6a, 0xdc, 0x05, - 0x88, 0x6a, 0xcc, 0x00, - 0x45, 0x6a, 0xda, 0x5b, - 0x01, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0x01, 0x6a, 0x26, 0x05, - 0x01, 0x65, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xaa, 0x7b, - 0xff, 0x6a, 0xdc, 0x0d, - 0xff, 0x65, 0x32, 0x09, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x78, 0x44, - 0xff, 0x37, 0xc8, 0x08, - 0x00, 0x6a, 0x70, 0x5b, - 0xff, 0x52, 0xa2, 0x0c, - 0x01, 0x0c, 0xba, 0x7b, - 0x04, 0x0c, 0xba, 0x6b, - 0xe0, 0x03, 0x06, 0x08, - 0xe0, 0x03, 0x7a, 0x0c, - 0xff, 0x8c, 0x10, 0x08, - 0xff, 0x8d, 0x12, 0x08, - 0xff, 0x8e, 0x14, 0x0c, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x08, - 0xff, 0x6c, 0xda, 0x0c, - 0x3d, 0x64, 0xa4, 0x28, - 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x6c, 0xda, 0x18, - 0xff, 0x52, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0xff, 0x6a, 0xc8, 0x08, - 0x00, 0x6c, 0xda, 0x20, - 0x00, 0x6c, 0xda, 0x24, - 0xff, 0x65, 0xc8, 0x08, - 0xe0, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xd6, 0x5b, - 0xff, 0x90, 0xe2, 0x09, - 0x20, 0x6a, 0xd0, 0x01, - 0x04, 0x35, 0xf8, 0x7b, - 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0xf4, 0x63, - 0x00, 0x65, 0x0e, 0x44, - 0x01, 0x6a, 0xdc, 0x01, - 0x20, 0xa0, 0xd8, 0x31, - 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xfe, 0x7b, - 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0x02, 0x64, - 0x20, 0x6a, 0xd0, 0x01, - 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x08, 0x64, - 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x0c, 0x64, - 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x10, 0x6c, - 0xff, 0x6a, 0xd4, 0x0c, - 0x88, 0x6a, 0xcc, 0x00, - 0x41, 0x6a, 0xd6, 0x5b, - 0x20, 0x6a, 0x18, 0x01, - 0xff, 0x6a, 0x1a, 0x09, - 0xff, 0x6a, 0x1c, 0x09, - 0xff, 0x35, 0x26, 0x09, - 0x04, 0x35, 0x3c, 0x6c, - 0xa0, 0x6a, 0xca, 0x00, - 0x20, 0x65, 0xc8, 0x18, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0xff, 0x6c, 0x32, 0x09, - 0x00, 0x65, 0x26, 0x64, - 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0x78, 0x44, - 0xa0, 0x6a, 0xcc, 0x00, - 0xe8, 0x6a, 0xc8, 0x00, - 0x01, 0x94, 0x40, 0x6c, - 0x10, 0x94, 0x42, 0x6c, - 0x08, 0x94, 0x54, 0x6c, - 0x08, 0x94, 0x54, 0x6c, - 0x08, 0x94, 0x54, 0x6c, - 0x00, 0x65, 0x68, 0x5c, - 0x08, 0x64, 0xc8, 0x18, - 0x00, 0x8c, 0xca, 0x18, - 0x00, 0x65, 0x4a, 0x4c, - 0x00, 0x65, 0x40, 0x44, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x56, 0x6c, - 0x00, 0x65, 0x68, 0x5c, - 0x08, 0x64, 0xc8, 0x18, - 0x08, 0x64, 0x58, 0x64, - 0xff, 0x6a, 0xd4, 0x0c, - 0x00, 0x65, 0x78, 0x5c, - 0x00, 0x65, 0x68, 0x5c, - 0x00, 0x65, 0x68, 0x5c, - 0x00, 0x65, 0x68, 0x5c, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x08, - 0xff, 0x99, 0xda, 0x0c, - 0x08, 0x94, 0x78, 0x7c, - 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x7c, 0x6c, - 0xff, 0x6a, 0xd4, 0x0c, - 0xff, 0x40, 0x74, 0x09, - 0xff, 0x90, 0x80, 0x08, - 0xff, 0x6a, 0x72, 0x05, - 0xff, 0x40, 0x94, 0x64, - 0xff, 0x3f, 0x8c, 0x64, - 0xff, 0x6a, 0xca, 0x04, - 0xff, 0x3f, 0x20, 0x09, - 0x01, 0x6a, 0x6a, 0x00, - 0x00, 0xb9, 0xe6, 0x5b, - 0xff, 0xba, 0x7e, 0x0c, - 0xff, 0x40, 0x20, 0x09, - 0xff, 0xba, 0x80, 0x0c, - 0xff, 0x3f, 0x74, 0x09, - 0xff, 0x90, 0x7e, 0x0c, -}; - -static int aic7xxx_patch15_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch15_func(struct aic7xxx_host *p) -{ - return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0); -} - -static int aic7xxx_patch14_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch14_func(struct aic7xxx_host *p) -{ - return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0); -} - -static int aic7xxx_patch13_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch13_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_WIDE) != 0); -} - -static int aic7xxx_patch12_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch12_func(struct aic7xxx_host *p) -{ - return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0); -} - -static int aic7xxx_patch11_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch11_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA2) == 0); -} - -static int aic7xxx_patch10_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch10_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_CMD_CHAN) == 0); -} - -static int aic7xxx_patch9_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch9_func(struct aic7xxx_host *p) -{ - return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895); -} - -static int aic7xxx_patch8_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch8_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA) != 0); -} - -static int aic7xxx_patch7_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch7_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_ULTRA2) != 0); -} - -static int aic7xxx_patch6_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch6_func(struct aic7xxx_host *p) -{ - return ((p->flags & AHC_PAGESCBS) == 0); -} - -static int aic7xxx_patch5_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch5_func(struct aic7xxx_host *p) -{ - return ((p->flags & AHC_PAGESCBS) != 0); -} - -static int aic7xxx_patch4_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch4_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_QUEUE_REGS) != 0); -} - -static int aic7xxx_patch3_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch3_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_TWIN) != 0); -} - -static int aic7xxx_patch2_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch2_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_QUEUE_REGS) == 0); -} - -static int aic7xxx_patch1_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch1_func(struct aic7xxx_host *p) -{ - return ((p->features & AHC_CMD_CHAN) != 0); -} - -static int aic7xxx_patch0_func(struct aic7xxx_host *p); - -static int -aic7xxx_patch0_func(struct aic7xxx_host *p) -{ - return (0); -} - -struct sequencer_patch { - int (*patch_func)(struct aic7xxx_host *); - unsigned int begin :10, - skip_instr :10, - skip_patch :12; -} sequencer_patches[] = { - { aic7xxx_patch1_func, 3, 2, 1 }, - { aic7xxx_patch2_func, 7, 1, 1 }, - { aic7xxx_patch2_func, 8, 1, 1 }, - { aic7xxx_patch3_func, 11, 4, 1 }, - { aic7xxx_patch4_func, 16, 3, 2 }, - { aic7xxx_patch0_func, 19, 4, 1 }, - { aic7xxx_patch5_func, 23, 1, 1 }, - { aic7xxx_patch6_func, 26, 1, 1 }, - { aic7xxx_patch1_func, 29, 1, 2 }, - { aic7xxx_patch0_func, 30, 3, 1 }, - { aic7xxx_patch3_func, 39, 4, 1 }, - { aic7xxx_patch7_func, 43, 3, 2 }, - { aic7xxx_patch0_func, 46, 3, 1 }, - { aic7xxx_patch8_func, 52, 7, 1 }, - { aic7xxx_patch3_func, 60, 3, 1 }, - { aic7xxx_patch7_func, 63, 2, 1 }, - { aic7xxx_patch7_func, 102, 1, 2 }, - { aic7xxx_patch0_func, 103, 2, 1 }, - { aic7xxx_patch7_func, 107, 2, 1 }, - { aic7xxx_patch9_func, 109, 1, 1 }, - { aic7xxx_patch10_func, 110, 2, 1 }, - { aic7xxx_patch7_func, 113, 1, 2 }, - { aic7xxx_patch0_func, 114, 1, 1 }, - { aic7xxx_patch1_func, 118, 1, 1 }, - { aic7xxx_patch1_func, 121, 3, 3 }, - { aic7xxx_patch11_func, 123, 1, 1 }, - { aic7xxx_patch0_func, 124, 5, 1 }, - { aic7xxx_patch7_func, 132, 1, 1 }, - { aic7xxx_patch9_func, 133, 1, 1 }, - { aic7xxx_patch10_func, 134, 3, 1 }, - { aic7xxx_patch7_func, 137, 3, 2 }, - { aic7xxx_patch0_func, 140, 2, 1 }, - { aic7xxx_patch7_func, 142, 5, 2 }, - { aic7xxx_patch0_func, 147, 3, 1 }, - { aic7xxx_patch7_func, 150, 1, 2 }, - { aic7xxx_patch0_func, 151, 2, 1 }, - { aic7xxx_patch1_func, 153, 15, 4 }, - { aic7xxx_patch11_func, 166, 1, 2 }, - { aic7xxx_patch0_func, 167, 1, 1 }, - { aic7xxx_patch0_func, 168, 10, 1 }, - { aic7xxx_patch7_func, 181, 1, 2 }, - { aic7xxx_patch0_func, 182, 2, 1 }, - { aic7xxx_patch7_func, 184, 18, 1 }, - { aic7xxx_patch1_func, 202, 3, 3 }, - { aic7xxx_patch7_func, 204, 1, 1 }, - { aic7xxx_patch0_func, 205, 4, 1 }, - { aic7xxx_patch7_func, 210, 2, 1 }, - { aic7xxx_patch7_func, 215, 13, 3 }, - { aic7xxx_patch12_func, 218, 1, 1 }, - { aic7xxx_patch12_func, 219, 4, 1 }, - { aic7xxx_patch1_func, 229, 3, 3 }, - { aic7xxx_patch11_func, 231, 1, 1 }, - { aic7xxx_patch0_func, 232, 5, 1 }, - { aic7xxx_patch11_func, 237, 1, 2 }, - { aic7xxx_patch0_func, 238, 9, 1 }, - { aic7xxx_patch13_func, 254, 1, 2 }, - { aic7xxx_patch0_func, 255, 1, 1 }, - { aic7xxx_patch4_func, 316, 1, 2 }, - { aic7xxx_patch0_func, 317, 1, 1 }, - { aic7xxx_patch2_func, 320, 1, 1 }, - { aic7xxx_patch1_func, 330, 3, 2 }, - { aic7xxx_patch0_func, 333, 5, 1 }, - { aic7xxx_patch13_func, 341, 1, 2 }, - { aic7xxx_patch0_func, 342, 1, 1 }, - { aic7xxx_patch5_func, 347, 1, 1 }, - { aic7xxx_patch11_func, 389, 15, 2 }, - { aic7xxx_patch14_func, 402, 1, 1 }, - { aic7xxx_patch1_func, 441, 7, 2 }, - { aic7xxx_patch0_func, 448, 8, 1 }, - { aic7xxx_patch1_func, 457, 4, 2 }, - { aic7xxx_patch0_func, 461, 6, 1 }, - { aic7xxx_patch1_func, 467, 4, 2 }, - { aic7xxx_patch0_func, 471, 3, 1 }, - { aic7xxx_patch10_func, 481, 10, 1 }, - { aic7xxx_patch1_func, 500, 22, 5 }, - { aic7xxx_patch11_func, 508, 4, 1 }, - { aic7xxx_patch7_func, 512, 7, 3 }, - { aic7xxx_patch15_func, 512, 5, 2 }, - { aic7xxx_patch0_func, 517, 2, 1 }, - { aic7xxx_patch10_func, 522, 50, 3 }, - { aic7xxx_patch14_func, 543, 17, 2 }, - { aic7xxx_patch0_func, 560, 4, 1 }, - { aic7xxx_patch10_func, 572, 4, 1 }, - { aic7xxx_patch5_func, 576, 2, 1 }, - { aic7xxx_patch5_func, 579, 9, 1 }, - -}; diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/scsi_message.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/scsi_message.h deleted file mode 100644 index a79f89c6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/scsi_message.h +++ /dev/null @@ -1,49 +0,0 @@ -/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */ -#define MSG_CMDCOMPLETE 0x00 /* M/M */ -#define MSG_EXTENDED 0x01 /* O/O */ -#define MSG_SAVEDATAPOINTER 0x02 /* O/O */ -#define MSG_RESTOREPOINTERS 0x03 /* O/O */ -#define MSG_DISCONNECT 0x04 /* O/O */ -#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */ -#define MSG_ABORT 0x06 /* O/M */ -#define MSG_MESSAGE_REJECT 0x07 /* M/M */ -#define MSG_NOOP 0x08 /* M/M */ -#define MSG_PARITY_ERROR 0x09 /* M/M */ -#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */ -#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */ -#define MSG_BUS_DEV_RESET 0x0c /* O/M */ -#define MSG_ABORT_TAG 0x0d /* O/O */ -#define MSG_CLEAR_QUEUE 0x0e /* O/O */ -#define MSG_INIT_RECOVERY 0x0f /* O/O */ -#define MSG_REL_RECOVERY 0x10 /* O/O */ -#define MSG_TERM_IO_PROC 0x11 /* O/O */ - -/* Messages (2 byte) */ -#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */ -#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */ -#define MSG_ORDERED_Q_TAG 0x22 /* O/O */ -#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */ - -/* Identify message */ /* M/M */ -#define MSG_IDENTIFYFLAG 0x80 -#define MSG_IDENTIFY_DISCFLAG 0x40 -#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun)) -#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG) - -/* Extended messages (opcode and length) */ -#define MSG_EXT_SDTR 0x01 -#define MSG_EXT_SDTR_LEN 0x03 - -#define MSG_EXT_WDTR 0x03 -#define MSG_EXT_WDTR_LEN 0x02 -#define MSG_EXT_WDTR_BUS_8_BIT 0x00 -#define MSG_EXT_WDTR_BUS_16_BIT 0x01 -#define MSG_EXT_WDTR_BUS_32_BIT 0x02 - -#define MSG_EXT_PPR 0x04 -#define MSG_EXT_PPR_LEN 0x06 -#define MSG_EXT_PPR_OPTION_ST 0x00 -#define MSG_EXT_PPR_OPTION_DT_CRC 0x02 -#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03 -#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04 -#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05 diff --git a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/sequencer.h b/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/sequencer.h deleted file mode 100644 index ee668552..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic7xxx_old/sequencer.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Instruction formats for the sequencer program downloaded to - * Aic7xxx SCSI host adapters - * - * Copyright (c) 1997, 1998 Justin T. Gibbs. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification, immediately at the beginning of the file. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * Where this Software is combined with software released under the terms of - * the GNU General Public License ("GPL") and the terms of the GPL would require the - * combined work to also be released under the terms of the GPL, the terms - * and conditions of this License will apply in addition to those of the - * GPL with the exception of any terms or conditions of this License that - * conflict with, or are expressly prohibited by, the GPL. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $ - */ - -#ifdef __LITTLE_ENDIAN_BITFIELD -struct ins_format1 { - unsigned int - immediate : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -}; - -struct ins_format2 { - unsigned int - shift_control : 8, - source : 9, - destination : 9, - ret : 1, - opcode : 4, - parity : 1; -}; - -struct ins_format3 { - unsigned int - immediate : 8, - source : 9, - address : 10, - opcode : 4, - parity : 1; -}; -#elif defined(__BIG_ENDIAN_BITFIELD) -struct ins_format1 { - unsigned int - parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - immediate : 8; -}; - -struct ins_format2 { - unsigned int - parity : 1, - opcode : 4, - ret : 1, - destination : 9, - source : 9, - shift_control : 8; -}; - -struct ins_format3 { - unsigned int - parity : 1, - opcode : 4, - address : 10, - source : 9, - immediate : 8; -}; -#endif - -union ins_formats { - struct ins_format1 format1; - struct ins_format2 format2; - struct ins_format3 format3; - unsigned char bytes[4]; - unsigned int integer; -}; -struct instruction { - union ins_formats format; - unsigned int srcline; - struct symbol *patch_label; - struct { - struct instruction *stqe_next; - } links; -}; - -#define AIC_OP_OR 0x0 -#define AIC_OP_AND 0x1 -#define AIC_OP_XOR 0x2 -#define AIC_OP_ADD 0x3 -#define AIC_OP_ADC 0x4 -#define AIC_OP_ROL 0x5 -#define AIC_OP_BMOV 0x6 - -#define AIC_OP_JMP 0x8 -#define AIC_OP_JC 0x9 -#define AIC_OP_JNC 0xa -#define AIC_OP_CALL 0xb -#define AIC_OP_JNE 0xc -#define AIC_OP_JNZ 0xd -#define AIC_OP_JE 0xe -#define AIC_OP_JZ 0xf - -/* Pseudo Ops */ -#define AIC_OP_SHL 0x10 -#define AIC_OP_SHR 0x20 -#define AIC_OP_ROR 0x30 diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/Kconfig b/ANDROID_3.4.5/drivers/scsi/aic94xx/Kconfig deleted file mode 100644 index c83fe751..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# Kernel configuration file for aic94xx SAS/SATA driver. -# -# Copyright (c) 2005 Adaptec, Inc. All rights reserved. -# Copyright (c) 2005 Luben Tuikov -# -# This file is licensed under GPLv2. -# -# This file is part of the aic94xx driver. -# -# The aic94xx driver is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 of the -# License. -# -# The aic94xx driver is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Aic94xx Driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# - -config SCSI_AIC94XX - tristate "Adaptec AIC94xx SAS/SATA support" - depends on PCI - select SCSI_SAS_LIBSAS - select FW_LOADER - help - This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X - AIC94xx chip based host adapters. - -config AIC94XX_DEBUG - bool "Compile in debug mode" - default y - depends on SCSI_AIC94XX - help - Compiles the aic94xx driver in debug mode. In debug mode, - the driver prints some messages to the console. diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/Makefile b/ANDROID_3.4.5/drivers/scsi/aic94xx/Makefile deleted file mode 100644 index c0a15c75..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# Makefile for Adaptec aic94xx SAS/SATA driver. -# -# Copyright (C) 2005 Adaptec, Inc. All rights reserved. -# Copyright (C) 2005 Luben Tuikov -# -# This file is licensed under GPLv2. -# -# This file is part of the aic94xx driver. -# -# The aic94xx driver is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 of the -# License. -# -# The aic94xx driver is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with the aic94xx driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -ccflags-$(CONFIG_AIC94XX_DEBUG) := -DASD_DEBUG -DASD_ENTER_EXIT - -obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o -aic94xx-y += aic94xx_init.o \ - aic94xx_hwi.o \ - aic94xx_reg.o \ - aic94xx_sds.o \ - aic94xx_seq.o \ - aic94xx_dump.o \ - aic94xx_scb.o \ - aic94xx_dev.o \ - aic94xx_tmf.o \ - aic94xx_task.o diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx.h b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx.h deleted file mode 100644 index 66cda669..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Aic94xx SAS/SATA driver header file. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * $Id: //depot/aic94xx/aic94xx.h#31 $ - */ - -#ifndef _AIC94XX_H_ -#define _AIC94XX_H_ - -#include -#include -#include - -#define ASD_DRIVER_NAME "aic94xx" -#define ASD_DRIVER_DESCRIPTION "Adaptec aic94xx SAS/SATA driver" - -#define asd_printk(fmt, ...) printk(KERN_NOTICE ASD_DRIVER_NAME ": " fmt, ## __VA_ARGS__) - -#ifdef ASD_ENTER_EXIT -#define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \ - __func__) -#define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \ - __func__) -#else -#define ENTER -#define EXIT -#endif - -#ifdef ASD_DEBUG -#define ASD_DPRINTK asd_printk -#else -#define ASD_DPRINTK(fmt, ...) -#endif - -/* 2*ITNL timeout + 1 second */ -#define AIC94XX_SCB_TIMEOUT (5*HZ) - -extern struct kmem_cache *asd_dma_token_cache; -extern struct kmem_cache *asd_ascb_cache; - -static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr) -{ - int i; - for (i = 0; i < SAS_ADDR_SIZE; i++, p += 2) - snprintf(p, 3, "%02X", sas_addr[i]); - *p = '\0'; -} - -struct asd_ha_struct; -struct asd_ascb; - -int asd_read_ocm(struct asd_ha_struct *asd_ha); -int asd_read_flash(struct asd_ha_struct *asd_ha); - -int asd_dev_found(struct domain_device *dev); -void asd_dev_gone(struct domain_device *dev); - -void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id); - -int asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags); - -void asd_set_dmamode(struct domain_device *dev); - -/* ---------- TMFs ---------- */ -int asd_abort_task(struct sas_task *); -int asd_abort_task_set(struct domain_device *, u8 *lun); -int asd_clear_aca(struct domain_device *, u8 *lun); -int asd_clear_task_set(struct domain_device *, u8 *lun); -int asd_lu_reset(struct domain_device *, u8 *lun); -int asd_I_T_nexus_reset(struct domain_device *dev); -int asd_query_task(struct sas_task *); - -/* ---------- Adapter and Port management ---------- */ -int asd_clear_nexus_port(struct asd_sas_port *port); -int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha); - -/* ---------- Phy Management ---------- */ -int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dev.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dev.c deleted file mode 100644 index 64136c56..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dev.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Aic94xx SAS/SATA DDB management - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * $Id: //depot/aic94xx/aic94xx_dev.c#21 $ - */ - -#include "aic94xx.h" -#include "aic94xx_hwi.h" -#include "aic94xx_reg.h" -#include "aic94xx_sas.h" - -#define FIND_FREE_DDB(_ha) find_first_zero_bit((_ha)->hw_prof.ddb_bitmap, \ - (_ha)->hw_prof.max_ddbs) -#define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap) -#define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap) - -static int asd_get_ddb(struct asd_ha_struct *asd_ha) -{ - int ddb, i; - - ddb = FIND_FREE_DDB(asd_ha); - if (ddb >= asd_ha->hw_prof.max_ddbs) { - ddb = -ENOMEM; - goto out; - } - SET_DDB(ddb, asd_ha); - - for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) - asd_ddbsite_write_dword(asd_ha, ddb, i, 0); -out: - return ddb; -} - -#define INIT_CONN_TAG offsetof(struct asd_ddb_ssp_smp_target_port, init_conn_tag) -#define DEST_SAS_ADDR offsetof(struct asd_ddb_ssp_smp_target_port, dest_sas_addr) -#define SEND_QUEUE_HEAD offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_head) -#define DDB_TYPE offsetof(struct asd_ddb_ssp_smp_target_port, ddb_type) -#define CONN_MASK offsetof(struct asd_ddb_ssp_smp_target_port, conn_mask) -#define DDB_TARG_FLAGS offsetof(struct asd_ddb_ssp_smp_target_port, flags) -#define DDB_TARG_FLAGS2 offsetof(struct asd_ddb_stp_sata_target_port, flags2) -#define EXEC_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, exec_queue_tail) -#define SEND_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_tail) -#define SISTER_DDB offsetof(struct asd_ddb_ssp_smp_target_port, sister_ddb) -#define MAX_CCONN offsetof(struct asd_ddb_ssp_smp_target_port, max_concurrent_conn) -#define NUM_CTX offsetof(struct asd_ddb_ssp_smp_target_port, num_contexts) -#define ATA_CMD_SCBPTR offsetof(struct asd_ddb_stp_sata_target_port, ata_cmd_scbptr) -#define SATA_TAG_ALLOC_MASK offsetof(struct asd_ddb_stp_sata_target_port, sata_tag_alloc_mask) -#define NUM_SATA_TAGS offsetof(struct asd_ddb_stp_sata_target_port, num_sata_tags) -#define SATA_STATUS offsetof(struct asd_ddb_stp_sata_target_port, sata_status) -#define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr) -#define ITNL_TIMEOUT offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout) - -static void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) -{ - if (!ddb || ddb >= 0xFFFF) - return; - asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED); - CLEAR_DDB(ddb, asd_ha); -} - -static void asd_set_ddb_type(struct domain_device *dev) -{ - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - int ddb = (int) (unsigned long) dev->lldd_dev; - - if (dev->dev_type == SATA_PM_PORT) - asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_PM_PORT); - else if (dev->tproto) - asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_TARGET); - else - asd_ddbsite_write_byte(asd_ha,ddb,DDB_TYPE,DDB_TYPE_INITIATOR); -} - -static int asd_init_sata_tag_ddb(struct domain_device *dev) -{ - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - int ddb, i; - - ddb = asd_get_ddb(asd_ha); - if (ddb < 0) - return ddb; - - for (i = 0; i < sizeof(struct asd_ddb_sata_tag); i += 2) - asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF); - - asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev, - SISTER_DDB, ddb); - return 0; -} - -void asd_set_dmamode(struct domain_device *dev) -{ - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - struct ata_device *ata_dev = sas_to_ata_dev(dev); - int ddb = (int) (unsigned long) dev->lldd_dev; - u32 qdepth = 0; - - if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) { - if (ata_id_has_ncq(ata_dev->id)) - qdepth = ata_id_queue_depth(ata_dev->id); - asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK, - (1ULL< 0) - if (asd_init_sata_tag_ddb(dev) != 0) { - unsigned long flags; - - spin_lock_irqsave(dev->sata_dev.ap->lock, flags); - ata_dev->flags |= ATA_DFLAG_NCQ_OFF; - spin_unlock_irqrestore(dev->sata_dev.ap->lock, flags); - } -} - -static int asd_init_sata(struct domain_device *dev) -{ - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - int ddb = (int) (unsigned long) dev->lldd_dev; - - asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF); - if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM || - dev->dev_type == SATA_PM_PORT) { - struct dev_to_host_fis *fis = (struct dev_to_host_fis *) - dev->frame_rcvd; - asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status); - } - asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF); - - return 0; -} - -static int asd_init_target_ddb(struct domain_device *dev) -{ - int ddb, i; - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - u8 flags = 0; - - ddb = asd_get_ddb(asd_ha); - if (ddb < 0) - return ddb; - - dev->lldd_dev = (void *) (unsigned long) ddb; - - asd_ddbsite_write_byte(asd_ha, ddb, 0, DDB_TP_CONN_TYPE); - asd_ddbsite_write_byte(asd_ha, ddb, 1, 0); - asd_ddbsite_write_word(asd_ha, ddb, INIT_CONN_TAG, 0xFFFF); - for (i = 0; i < SAS_ADDR_SIZE; i++) - asd_ddbsite_write_byte(asd_ha, ddb, DEST_SAS_ADDR+i, - dev->sas_addr[i]); - asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_HEAD, 0xFFFF); - asd_set_ddb_type(dev); - asd_ddbsite_write_byte(asd_ha, ddb, CONN_MASK, dev->port->phy_mask); - if (dev->port->oob_mode != SATA_OOB_MODE) { - flags |= OPEN_REQUIRED; - if ((dev->dev_type == SATA_DEV) || - (dev->tproto & SAS_PROTOCOL_STP)) { - struct smp_resp *rps_resp = &dev->sata_dev.rps_resp; - if (rps_resp->frame_type == SMP_RESPONSE && - rps_resp->function == SMP_REPORT_PHY_SATA && - rps_resp->result == SMP_RESP_FUNC_ACC) { - if (rps_resp->rps.affil_valid) - flags |= STP_AFFIL_POL; - if (rps_resp->rps.affil_supp) - flags |= SUPPORTS_AFFIL; - } - } else { - flags |= CONCURRENT_CONN_SUPP; - if (!dev->parent && - (dev->dev_type == EDGE_DEV || - dev->dev_type == FANOUT_DEV)) - asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN, - 4); - else - asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN, - dev->pathways); - asd_ddbsite_write_byte(asd_ha, ddb, NUM_CTX, 1); - } - } - if (dev->dev_type == SATA_PM) - flags |= SATA_MULTIPORT; - asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags); - - flags = 0; - if (dev->tproto & SAS_PROTOCOL_STP) - flags |= STP_CL_POL_NO_TX; - asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags); - - asd_ddbsite_write_word(asd_ha, ddb, EXEC_QUEUE_TAIL, 0xFFFF); - asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF); - asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF); - - if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { - i = asd_init_sata(dev); - if (i < 0) { - asd_free_ddb(asd_ha, ddb); - return i; - } - } - - if (dev->dev_type == SAS_END_DEV) { - struct sas_end_device *rdev = rphy_to_end_device(dev->rphy); - if (rdev->I_T_nexus_loss_timeout > 0) - asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT, - min(rdev->I_T_nexus_loss_timeout, - (u16)ITNL_TIMEOUT_CONST)); - else - asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT, - (u16)ITNL_TIMEOUT_CONST); - } - return 0; -} - -static int asd_init_sata_pm_table_ddb(struct domain_device *dev) -{ - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - int ddb, i; - - ddb = asd_get_ddb(asd_ha); - if (ddb < 0) - return ddb; - - for (i = 0; i < 32; i += 2) - asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF); - - asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev, - SISTER_DDB, ddb); - - return 0; -} - -#define PM_PORT_FLAGS offsetof(struct asd_ddb_sata_pm_port, pm_port_flags) -#define PARENT_DDB offsetof(struct asd_ddb_sata_pm_port, parent_ddb) - -/** - * asd_init_sata_pm_port_ddb -- SATA Port Multiplier Port - * dev: pointer to domain device - * - * For SATA Port Multiplier Ports we need to allocate one SATA Port - * Multiplier Port DDB and depending on whether the target on it - * supports SATA II NCQ, one SATA Tag DDB. - */ -static int asd_init_sata_pm_port_ddb(struct domain_device *dev) -{ - int ddb, i, parent_ddb, pmtable_ddb; - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - u8 flags; - - ddb = asd_get_ddb(asd_ha); - if (ddb < 0) - return ddb; - - asd_set_ddb_type(dev); - flags = (dev->sata_dev.port_no << 4) | PM_PORT_SET; - asd_ddbsite_write_byte(asd_ha, ddb, PM_PORT_FLAGS, flags); - asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF); - asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF); - asd_init_sata(dev); - - parent_ddb = (int) (unsigned long) dev->parent->lldd_dev; - asd_ddbsite_write_word(asd_ha, ddb, PARENT_DDB, parent_ddb); - pmtable_ddb = asd_ddbsite_read_word(asd_ha, parent_ddb, SISTER_DDB); - asd_ddbsite_write_word(asd_ha, pmtable_ddb, dev->sata_dev.port_no,ddb); - - if (asd_ddbsite_read_byte(asd_ha, ddb, NUM_SATA_TAGS) > 0) { - i = asd_init_sata_tag_ddb(dev); - if (i < 0) { - asd_free_ddb(asd_ha, ddb); - return i; - } - } - return 0; -} - -static int asd_init_initiator_ddb(struct domain_device *dev) -{ - return -ENODEV; -} - -/** - * asd_init_sata_pm_ddb -- SATA Port Multiplier - * dev: pointer to domain device - * - * For STP and direct-attached SATA Port Multipliers we need - * one target port DDB entry and one SATA PM table DDB entry. - */ -static int asd_init_sata_pm_ddb(struct domain_device *dev) -{ - int res = 0; - - res = asd_init_target_ddb(dev); - if (res) - goto out; - res = asd_init_sata_pm_table_ddb(dev); - if (res) - asd_free_ddb(dev->port->ha->lldd_ha, - (int) (unsigned long) dev->lldd_dev); -out: - return res; -} - -int asd_dev_found(struct domain_device *dev) -{ - unsigned long flags; - int res = 0; - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - - spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); - switch (dev->dev_type) { - case SATA_PM: - res = asd_init_sata_pm_ddb(dev); - break; - case SATA_PM_PORT: - res = asd_init_sata_pm_port_ddb(dev); - break; - default: - if (dev->tproto) - res = asd_init_target_ddb(dev); - else - res = asd_init_initiator_ddb(dev); - } - spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); - - return res; -} - -void asd_dev_gone(struct domain_device *dev) -{ - int ddb, sister_ddb; - unsigned long flags; - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - - spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); - ddb = (int) (unsigned long) dev->lldd_dev; - sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB); - - if (sister_ddb != 0xFFFF) - asd_free_ddb(asd_ha, sister_ddb); - asd_free_ddb(asd_ha, ddb); - dev->lldd_dev = NULL; - spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.c deleted file mode 100644 index a16a77c8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.c +++ /dev/null @@ -1,967 +0,0 @@ -/* - * Aic94xx SAS/SATA driver dump interface. - * - * Copyright (C) 2004 Adaptec, Inc. All rights reserved. - * Copyright (C) 2004 David Chaw - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * 2005/07/14/LT Complete overhaul of this file. Update pages, register - * locations, names, etc. Make use of macros. Print more information. - * Print all cseq and lseq mip and mdp. - * - */ - -#include -#include "aic94xx.h" -#include "aic94xx_reg.h" -#include "aic94xx_reg_def.h" -#include "aic94xx_sas.h" - -#include "aic94xx_dump.h" - -#ifdef ASD_DEBUG - -#define MD(x) (1 << (x)) -#define MODE_COMMON (1 << 31) -#define MODE_0_7 (0xFF) - -static const struct lseq_cio_regs { - char *name; - u32 offs; - u8 width; - u32 mode; -} LSEQmCIOREGS[] = { - {"LmMnSCBPTR", 0x20, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) }, - {"LmMnDDBPTR", 0x22, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) }, - {"LmREQMBX", 0x30, 32, MODE_COMMON }, - {"LmRSPMBX", 0x34, 32, MODE_COMMON }, - {"LmMnINT", 0x38, 32, MODE_0_7 }, - {"LmMnINTEN", 0x3C, 32, MODE_0_7 }, - {"LmXMTPRIMD", 0x40, 32, MODE_COMMON }, - {"LmXMTPRIMCS", 0x44, 8, MODE_COMMON }, - {"LmCONSTAT", 0x45, 8, MODE_COMMON }, - {"LmMnDMAERRS", 0x46, 8, MD(0)|MD(1) }, - {"LmMnSGDMAERRS", 0x47, 8, MD(0)|MD(1) }, - {"LmMnEXPHDRP", 0x48, 8, MD(0) }, - {"LmMnSASAALIGN", 0x48, 8, MD(1) }, - {"LmMnMSKHDRP", 0x49, 8, MD(0) }, - {"LmMnSTPALIGN", 0x49, 8, MD(1) }, - {"LmMnRCVHDRP", 0x4A, 8, MD(0) }, - {"LmMnXMTHDRP", 0x4A, 8, MD(1) }, - {"LmALIGNMODE", 0x4B, 8, MD(1) }, - {"LmMnEXPRCVCNT", 0x4C, 32, MD(0) }, - {"LmMnXMTCNT", 0x4C, 32, MD(1) }, - {"LmMnCURRTAG", 0x54, 16, MD(0) }, - {"LmMnPREVTAG", 0x56, 16, MD(0) }, - {"LmMnACKOFS", 0x58, 8, MD(1) }, - {"LmMnXFRLVL", 0x59, 8, MD(0)|MD(1) }, - {"LmMnSGDMACTL", 0x5A, 8, MD(0)|MD(1) }, - {"LmMnSGDMASTAT", 0x5B, 8, MD(0)|MD(1) }, - {"LmMnDDMACTL", 0x5C, 8, MD(0)|MD(1) }, - {"LmMnDDMASTAT", 0x5D, 8, MD(0)|MD(1) }, - {"LmMnDDMAMODE", 0x5E, 16, MD(0)|MD(1) }, - {"LmMnPIPECTL", 0x61, 8, MD(0)|MD(1) }, - {"LmMnACTSCB", 0x62, 16, MD(0)|MD(1) }, - {"LmMnSGBHADR", 0x64, 8, MD(0)|MD(1) }, - {"LmMnSGBADR", 0x65, 8, MD(0)|MD(1) }, - {"LmMnSGDCNT", 0x66, 8, MD(0)|MD(1) }, - {"LmMnSGDMADR", 0x68, 32, MD(0)|MD(1) }, - {"LmMnSGDMADR", 0x6C, 32, MD(0)|MD(1) }, - {"LmMnXFRCNT", 0x70, 32, MD(0)|MD(1) }, - {"LmMnXMTCRC", 0x74, 32, MD(1) }, - {"LmCURRTAG", 0x74, 16, MD(0) }, - {"LmPREVTAG", 0x76, 16, MD(0) }, - {"LmMnDPSEL", 0x7B, 8, MD(0)|MD(1) }, - {"LmDPTHSTAT", 0x7C, 8, MODE_COMMON }, - {"LmMnHOLDLVL", 0x7D, 8, MD(0) }, - {"LmMnSATAFS", 0x7E, 8, MD(1) }, - {"LmMnCMPLTSTAT", 0x7F, 8, MD(0)|MD(1) }, - {"LmPRMSTAT0", 0x80, 32, MODE_COMMON }, - {"LmPRMSTAT1", 0x84, 32, MODE_COMMON }, - {"LmGPRMINT", 0x88, 8, MODE_COMMON }, - {"LmMnCURRSCB", 0x8A, 16, MD(0) }, - {"LmPRMICODE", 0x8C, 32, MODE_COMMON }, - {"LmMnRCVCNT", 0x90, 16, MD(0) }, - {"LmMnBUFSTAT", 0x92, 16, MD(0) }, - {"LmMnXMTHDRSIZE",0x92, 8, MD(1) }, - {"LmMnXMTSIZE", 0x93, 8, MD(1) }, - {"LmMnTGTXFRCNT", 0x94, 32, MD(0) }, - {"LmMnEXPROFS", 0x98, 32, MD(0) }, - {"LmMnXMTROFS", 0x98, 32, MD(1) }, - {"LmMnRCVROFS", 0x9C, 32, MD(0) }, - {"LmCONCTL", 0xA0, 16, MODE_COMMON }, - {"LmBITLTIMER", 0xA2, 16, MODE_COMMON }, - {"LmWWNLOW", 0xA8, 32, MODE_COMMON }, - {"LmWWNHIGH", 0xAC, 32, MODE_COMMON }, - {"LmMnFRMERR", 0xB0, 32, MD(0) }, - {"LmMnFRMERREN", 0xB4, 32, MD(0) }, - {"LmAWTIMER", 0xB8, 16, MODE_COMMON }, - {"LmAWTCTL", 0xBA, 8, MODE_COMMON }, - {"LmMnHDRCMPS", 0xC0, 32, MD(0) }, - {"LmMnXMTSTAT", 0xC4, 8, MD(1) }, - {"LmHWTSTATEN", 0xC5, 8, MODE_COMMON }, - {"LmMnRRDYRC", 0xC6, 8, MD(0) }, - {"LmMnRRDYTC", 0xC6, 8, MD(1) }, - {"LmHWTSTAT", 0xC7, 8, MODE_COMMON }, - {"LmMnDATABUFADR",0xC8, 16, MD(0)|MD(1) }, - {"LmDWSSTATUS", 0xCB, 8, MODE_COMMON }, - {"LmMnACTSTAT", 0xCE, 16, MD(0)|MD(1) }, - {"LmMnREQSCB", 0xD2, 16, MD(0)|MD(1) }, - {"LmXXXPRIM", 0xD4, 32, MODE_COMMON }, - {"LmRCVASTAT", 0xD9, 8, MODE_COMMON }, - {"LmINTDIS1", 0xDA, 8, MODE_COMMON }, - {"LmPSTORESEL", 0xDB, 8, MODE_COMMON }, - {"LmPSTORE", 0xDC, 32, MODE_COMMON }, - {"LmPRIMSTAT0EN", 0xE0, 32, MODE_COMMON }, - {"LmPRIMSTAT1EN", 0xE4, 32, MODE_COMMON }, - {"LmDONETCTL", 0xF2, 16, MODE_COMMON }, - {NULL, 0, 0, 0 } -}; -/* -static struct lseq_cio_regs LSEQmOOBREGS[] = { - {"OOB_BFLTR" ,0x100, 8, MD(5)}, - {"OOB_INIT_MIN" ,0x102,16, MD(5)}, - {"OOB_INIT_MAX" ,0x104,16, MD(5)}, - {"OOB_INIT_NEG" ,0x106,16, MD(5)}, - {"OOB_SAS_MIN" ,0x108,16, MD(5)}, - {"OOB_SAS_MAX" ,0x10A,16, MD(5)}, - {"OOB_SAS_NEG" ,0x10C,16, MD(5)}, - {"OOB_WAKE_MIN" ,0x10E,16, MD(5)}, - {"OOB_WAKE_MAX" ,0x110,16, MD(5)}, - {"OOB_WAKE_NEG" ,0x112,16, MD(5)}, - {"OOB_IDLE_MAX" ,0x114,16, MD(5)}, - {"OOB_BURST_MAX" ,0x116,16, MD(5)}, - {"OOB_XMIT_BURST" ,0x118, 8, MD(5)}, - {"OOB_SEND_PAIRS" ,0x119, 8, MD(5)}, - {"OOB_INIT_IDLE" ,0x11A, 8, MD(5)}, - {"OOB_INIT_NEGO" ,0x11C, 8, MD(5)}, - {"OOB_SAS_IDLE" ,0x11E, 8, MD(5)}, - {"OOB_SAS_NEGO" ,0x120, 8, MD(5)}, - {"OOB_WAKE_IDLE" ,0x122, 8, MD(5)}, - {"OOB_WAKE_NEGO" ,0x124, 8, MD(5)}, - {"OOB_DATA_KBITS" ,0x126, 8, MD(5)}, - {"OOB_BURST_DATA" ,0x128,32, MD(5)}, - {"OOB_ALIGN_0_DATA" ,0x12C,32, MD(5)}, - {"OOB_ALIGN_1_DATA" ,0x130,32, MD(5)}, - {"OOB_SYNC_DATA" ,0x134,32, MD(5)}, - {"OOB_D10_2_DATA" ,0x138,32, MD(5)}, - {"OOB_PHY_RST_CNT" ,0x13C,32, MD(5)}, - {"OOB_SIG_GEN" ,0x140, 8, MD(5)}, - {"OOB_XMIT" ,0x141, 8, MD(5)}, - {"FUNCTION_MAKS" ,0x142, 8, MD(5)}, - {"OOB_MODE" ,0x143, 8, MD(5)}, - {"CURRENT_STATUS" ,0x144, 8, MD(5)}, - {"SPEED_MASK" ,0x145, 8, MD(5)}, - {"PRIM_COUNT" ,0x146, 8, MD(5)}, - {"OOB_SIGNALS" ,0x148, 8, MD(5)}, - {"OOB_DATA_DET" ,0x149, 8, MD(5)}, - {"OOB_TIME_OUT" ,0x14C, 8, MD(5)}, - {"OOB_TIMER_ENABLE" ,0x14D, 8, MD(5)}, - {"OOB_STATUS" ,0x14E, 8, MD(5)}, - {"HOT_PLUG_DELAY" ,0x150, 8, MD(5)}, - {"RCD_DELAY" ,0x151, 8, MD(5)}, - {"COMSAS_TIMER" ,0x152, 8, MD(5)}, - {"SNTT_DELAY" ,0x153, 8, MD(5)}, - {"SPD_CHNG_DELAY" ,0x154, 8, MD(5)}, - {"SNLT_DELAY" ,0x155, 8, MD(5)}, - {"SNWT_DELAY" ,0x156, 8, MD(5)}, - {"ALIGN_DELAY" ,0x157, 8, MD(5)}, - {"INT_ENABLE_0" ,0x158, 8, MD(5)}, - {"INT_ENABLE_1" ,0x159, 8, MD(5)}, - {"INT_ENABLE_2" ,0x15A, 8, MD(5)}, - {"INT_ENABLE_3" ,0x15B, 8, MD(5)}, - {"OOB_TEST_REG" ,0x15C, 8, MD(5)}, - {"PHY_CONTROL_0" ,0x160, 8, MD(5)}, - {"PHY_CONTROL_1" ,0x161, 8, MD(5)}, - {"PHY_CONTROL_2" ,0x162, 8, MD(5)}, - {"PHY_CONTROL_3" ,0x163, 8, MD(5)}, - {"PHY_OOB_CAL_TX" ,0x164, 8, MD(5)}, - {"PHY_OOB_CAL_RX" ,0x165, 8, MD(5)}, - {"OOB_PHY_CAL_TX" ,0x166, 8, MD(5)}, - {"OOB_PHY_CAL_RX" ,0x167, 8, MD(5)}, - {"PHY_CONTROL_4" ,0x168, 8, MD(5)}, - {"PHY_TEST" ,0x169, 8, MD(5)}, - {"PHY_PWR_CTL" ,0x16A, 8, MD(5)}, - {"PHY_PWR_DELAY" ,0x16B, 8, MD(5)}, - {"OOB_SM_CON" ,0x16C, 8, MD(5)}, - {"ADDR_TRAP_1" ,0x16D, 8, MD(5)}, - {"ADDR_NEXT_1" ,0x16E, 8, MD(5)}, - {"NEXT_ST_1" ,0x16F, 8, MD(5)}, - {"OOB_SM_STATE" ,0x170, 8, MD(5)}, - {"ADDR_TRAP_2" ,0x171, 8, MD(5)}, - {"ADDR_NEXT_2" ,0x172, 8, MD(5)}, - {"NEXT_ST_2" ,0x173, 8, MD(5)}, - {NULL, 0, 0, 0 } -}; -*/ -#define STR_8BIT " %30s[0x%04x]:0x%02x\n" -#define STR_16BIT " %30s[0x%04x]:0x%04x\n" -#define STR_32BIT " %30s[0x%04x]:0x%08x\n" -#define STR_64BIT " %30s[0x%04x]:0x%llx\n" - -#define PRINT_REG_8bit(_ha, _n, _r) asd_printk(STR_8BIT, #_n, _n, \ - asd_read_reg_byte(_ha, _r)) -#define PRINT_REG_16bit(_ha, _n, _r) asd_printk(STR_16BIT, #_n, _n, \ - asd_read_reg_word(_ha, _r)) -#define PRINT_REG_32bit(_ha, _n, _r) asd_printk(STR_32BIT, #_n, _n, \ - asd_read_reg_dword(_ha, _r)) - -#define PRINT_CREG_8bit(_ha, _n) asd_printk(STR_8BIT, #_n, _n, \ - asd_read_reg_byte(_ha, C##_n)) -#define PRINT_CREG_16bit(_ha, _n) asd_printk(STR_16BIT, #_n, _n, \ - asd_read_reg_word(_ha, C##_n)) -#define PRINT_CREG_32bit(_ha, _n) asd_printk(STR_32BIT, #_n, _n, \ - asd_read_reg_dword(_ha, C##_n)) - -#define MSTR_8BIT " Mode:%02d %30s[0x%04x]:0x%02x\n" -#define MSTR_16BIT " Mode:%02d %30s[0x%04x]:0x%04x\n" -#define MSTR_32BIT " Mode:%02d %30s[0x%04x]:0x%08x\n" - -#define PRINT_MREG_8bit(_ha, _m, _n, _r) asd_printk(MSTR_8BIT, _m, #_n, _n, \ - asd_read_reg_byte(_ha, _r)) -#define PRINT_MREG_16bit(_ha, _m, _n, _r) asd_printk(MSTR_16BIT, _m, #_n, _n, \ - asd_read_reg_word(_ha, _r)) -#define PRINT_MREG_32bit(_ha, _m, _n, _r) asd_printk(MSTR_32BIT, _m, #_n, _n, \ - asd_read_reg_dword(_ha, _r)) - -/* can also be used for MD when the register is mode aware already */ -#define PRINT_MIS_byte(_ha, _n) asd_printk(STR_8BIT, #_n,CSEQ_##_n-CMAPPEDSCR,\ - asd_read_reg_byte(_ha, CSEQ_##_n)) -#define PRINT_MIS_word(_ha, _n) asd_printk(STR_16BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\ - asd_read_reg_word(_ha, CSEQ_##_n)) -#define PRINT_MIS_dword(_ha, _n) \ - asd_printk(STR_32BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\ - asd_read_reg_dword(_ha, CSEQ_##_n)) -#define PRINT_MIS_qword(_ha, _n) \ - asd_printk(STR_64BIT, #_n,CSEQ_##_n-CMAPPEDSCR, \ - (unsigned long long)(((u64)asd_read_reg_dword(_ha, CSEQ_##_n)) \ - | (((u64)asd_read_reg_dword(_ha, (CSEQ_##_n)+4))<<32))) - -#define CMDP_REG(_n, _m) (_m*(CSEQ_PAGE_SIZE*2)+CSEQ_##_n) -#define PRINT_CMDP_word(_ha, _n) \ -asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \ - #_n, \ - asd_read_reg_word(_ha, CMDP_REG(_n, 0)), \ - asd_read_reg_word(_ha, CMDP_REG(_n, 1)), \ - asd_read_reg_word(_ha, CMDP_REG(_n, 2)), \ - asd_read_reg_word(_ha, CMDP_REG(_n, 3)), \ - asd_read_reg_word(_ha, CMDP_REG(_n, 4)), \ - asd_read_reg_word(_ha, CMDP_REG(_n, 5)), \ - asd_read_reg_word(_ha, CMDP_REG(_n, 6)), \ - asd_read_reg_word(_ha, CMDP_REG(_n, 7))) - -#define PRINT_CMDP_byte(_ha, _n) \ -asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \ - #_n, \ - asd_read_reg_byte(_ha, CMDP_REG(_n, 0)), \ - asd_read_reg_byte(_ha, CMDP_REG(_n, 1)), \ - asd_read_reg_byte(_ha, CMDP_REG(_n, 2)), \ - asd_read_reg_byte(_ha, CMDP_REG(_n, 3)), \ - asd_read_reg_byte(_ha, CMDP_REG(_n, 4)), \ - asd_read_reg_byte(_ha, CMDP_REG(_n, 5)), \ - asd_read_reg_byte(_ha, CMDP_REG(_n, 6)), \ - asd_read_reg_byte(_ha, CMDP_REG(_n, 7))) - -static void asd_dump_cseq_state(struct asd_ha_struct *asd_ha) -{ - int mode; - - asd_printk("CSEQ STATE\n"); - - asd_printk("ARP2 REGISTERS\n"); - - PRINT_CREG_32bit(asd_ha, ARP2CTL); - PRINT_CREG_32bit(asd_ha, ARP2INT); - PRINT_CREG_32bit(asd_ha, ARP2INTEN); - PRINT_CREG_8bit(asd_ha, MODEPTR); - PRINT_CREG_8bit(asd_ha, ALTMODE); - PRINT_CREG_8bit(asd_ha, FLAG); - PRINT_CREG_8bit(asd_ha, ARP2INTCTL); - PRINT_CREG_16bit(asd_ha, STACK); - PRINT_CREG_16bit(asd_ha, PRGMCNT); - PRINT_CREG_16bit(asd_ha, ACCUM); - PRINT_CREG_16bit(asd_ha, SINDEX); - PRINT_CREG_16bit(asd_ha, DINDEX); - PRINT_CREG_8bit(asd_ha, SINDIR); - PRINT_CREG_8bit(asd_ha, DINDIR); - PRINT_CREG_8bit(asd_ha, JUMLDIR); - PRINT_CREG_8bit(asd_ha, ARP2HALTCODE); - PRINT_CREG_16bit(asd_ha, CURRADDR); - PRINT_CREG_16bit(asd_ha, LASTADDR); - PRINT_CREG_16bit(asd_ha, NXTLADDR); - - asd_printk("IOP REGISTERS\n"); - - PRINT_REG_32bit(asd_ha, BISTCTL1, CBISTCTL); - PRINT_CREG_32bit(asd_ha, MAPPEDSCR); - - asd_printk("CIO REGISTERS\n"); - - for (mode = 0; mode < 9; mode++) - PRINT_MREG_16bit(asd_ha, mode, MnSCBPTR, CMnSCBPTR(mode)); - PRINT_MREG_16bit(asd_ha, 15, MnSCBPTR, CMnSCBPTR(15)); - - for (mode = 0; mode < 9; mode++) - PRINT_MREG_16bit(asd_ha, mode, MnDDBPTR, CMnDDBPTR(mode)); - PRINT_MREG_16bit(asd_ha, 15, MnDDBPTR, CMnDDBPTR(15)); - - for (mode = 0; mode < 8; mode++) - PRINT_MREG_32bit(asd_ha, mode, MnREQMBX, CMnREQMBX(mode)); - for (mode = 0; mode < 8; mode++) - PRINT_MREG_32bit(asd_ha, mode, MnRSPMBX, CMnRSPMBX(mode)); - for (mode = 0; mode < 8; mode++) - PRINT_MREG_32bit(asd_ha, mode, MnINT, CMnINT(mode)); - for (mode = 0; mode < 8; mode++) - PRINT_MREG_32bit(asd_ha, mode, MnINTEN, CMnINTEN(mode)); - - PRINT_CREG_8bit(asd_ha, SCRATCHPAGE); - for (mode = 0; mode < 8; mode++) - PRINT_MREG_8bit(asd_ha, mode, MnSCRATCHPAGE, - CMnSCRATCHPAGE(mode)); - - PRINT_REG_32bit(asd_ha, CLINKCON, CLINKCON); - PRINT_REG_8bit(asd_ha, CCONMSK, CCONMSK); - PRINT_REG_8bit(asd_ha, CCONEXIST, CCONEXIST); - PRINT_REG_16bit(asd_ha, CCONMODE, CCONMODE); - PRINT_REG_32bit(asd_ha, CTIMERCALC, CTIMERCALC); - PRINT_REG_8bit(asd_ha, CINTDIS, CINTDIS); - - asd_printk("SCRATCH MEMORY\n"); - - asd_printk("MIP 4 >>>>>\n"); - PRINT_MIS_word(asd_ha, Q_EXE_HEAD); - PRINT_MIS_word(asd_ha, Q_EXE_TAIL); - PRINT_MIS_word(asd_ha, Q_DONE_HEAD); - PRINT_MIS_word(asd_ha, Q_DONE_TAIL); - PRINT_MIS_word(asd_ha, Q_SEND_HEAD); - PRINT_MIS_word(asd_ha, Q_SEND_TAIL); - PRINT_MIS_word(asd_ha, Q_DMA2CHIM_HEAD); - PRINT_MIS_word(asd_ha, Q_DMA2CHIM_TAIL); - PRINT_MIS_word(asd_ha, Q_COPY_HEAD); - PRINT_MIS_word(asd_ha, Q_COPY_TAIL); - PRINT_MIS_word(asd_ha, REG0); - PRINT_MIS_word(asd_ha, REG1); - PRINT_MIS_dword(asd_ha, REG2); - PRINT_MIS_byte(asd_ha, LINK_CTL_Q_MAP); - PRINT_MIS_byte(asd_ha, MAX_CSEQ_MODE); - PRINT_MIS_byte(asd_ha, FREE_LIST_HACK_COUNT); - - asd_printk("MIP 5 >>>>\n"); - PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_QUEUE); - PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_COUNT); - PRINT_MIS_word(asd_ha, Q_EST_NEXUS_HEAD); - PRINT_MIS_word(asd_ha, Q_EST_NEXUS_TAIL); - PRINT_MIS_word(asd_ha, NEED_EST_NEXUS_SCB); - PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_HEAD); - PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_TAIL); - PRINT_MIS_byte(asd_ha, EST_NEXUS_SCB_OFFSET); - - asd_printk("MIP 6 >>>>\n"); - PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR0); - PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR1); - PRINT_MIS_word(asd_ha, INT_ROUT_SCBPTR); - PRINT_MIS_byte(asd_ha, INT_ROUT_MODE); - PRINT_MIS_byte(asd_ha, ISR_SCRATCH_FLAGS); - PRINT_MIS_word(asd_ha, ISR_SAVE_SINDEX); - PRINT_MIS_word(asd_ha, ISR_SAVE_DINDEX); - PRINT_MIS_word(asd_ha, Q_MONIRTT_HEAD); - PRINT_MIS_word(asd_ha, Q_MONIRTT_TAIL); - PRINT_MIS_byte(asd_ha, FREE_SCB_MASK); - PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_HEAD); - PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_TAIL); - PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_HEAD); - PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_TAIL); - - asd_printk("MIP 7 >>>>\n"); - PRINT_MIS_qword(asd_ha, EMPTY_REQ_QUEUE); - PRINT_MIS_qword(asd_ha, EMPTY_REQ_COUNT); - PRINT_MIS_word(asd_ha, Q_EMPTY_HEAD); - PRINT_MIS_word(asd_ha, Q_EMPTY_TAIL); - PRINT_MIS_word(asd_ha, NEED_EMPTY_SCB); - PRINT_MIS_byte(asd_ha, EMPTY_REQ_HEAD); - PRINT_MIS_byte(asd_ha, EMPTY_REQ_TAIL); - PRINT_MIS_byte(asd_ha, EMPTY_SCB_OFFSET); - PRINT_MIS_word(asd_ha, PRIMITIVE_DATA); - PRINT_MIS_dword(asd_ha, TIMEOUT_CONST); - - asd_printk("MDP 0 >>>>\n"); - asd_printk("%-20s %6s %6s %6s %6s %6s %6s %6s %6s\n", - "Mode: ", "0", "1", "2", "3", "4", "5", "6", "7"); - PRINT_CMDP_word(asd_ha, LRM_SAVE_SINDEX); - PRINT_CMDP_word(asd_ha, LRM_SAVE_SCBPTR); - PRINT_CMDP_word(asd_ha, Q_LINK_HEAD); - PRINT_CMDP_word(asd_ha, Q_LINK_TAIL); - PRINT_CMDP_byte(asd_ha, LRM_SAVE_SCRPAGE); - - asd_printk("MDP 0 Mode 8 >>>>\n"); - PRINT_MIS_word(asd_ha, RET_ADDR); - PRINT_MIS_word(asd_ha, RET_SCBPTR); - PRINT_MIS_word(asd_ha, SAVE_SCBPTR); - PRINT_MIS_word(asd_ha, EMPTY_TRANS_CTX); - PRINT_MIS_word(asd_ha, RESP_LEN); - PRINT_MIS_word(asd_ha, TMF_SCBPTR); - PRINT_MIS_word(asd_ha, GLOBAL_PREV_SCB); - PRINT_MIS_word(asd_ha, GLOBAL_HEAD); - PRINT_MIS_word(asd_ha, CLEAR_LU_HEAD); - PRINT_MIS_byte(asd_ha, TMF_OPCODE); - PRINT_MIS_byte(asd_ha, SCRATCH_FLAGS); - PRINT_MIS_word(asd_ha, HSB_SITE); - PRINT_MIS_word(asd_ha, FIRST_INV_SCB_SITE); - PRINT_MIS_word(asd_ha, FIRST_INV_DDB_SITE); - - asd_printk("MDP 1 Mode 8 >>>>\n"); - PRINT_MIS_qword(asd_ha, LUN_TO_CLEAR); - PRINT_MIS_qword(asd_ha, LUN_TO_CHECK); - - asd_printk("MDP 2 Mode 8 >>>>\n"); - PRINT_MIS_qword(asd_ha, HQ_NEW_POINTER); - PRINT_MIS_qword(asd_ha, HQ_DONE_BASE); - PRINT_MIS_dword(asd_ha, HQ_DONE_POINTER); - PRINT_MIS_byte(asd_ha, HQ_DONE_PASS); -} - -#define PRINT_LREG_8bit(_h, _lseq, _n) \ - asd_printk(STR_8BIT, #_n, _n, asd_read_reg_byte(_h, Lm##_n(_lseq))) -#define PRINT_LREG_16bit(_h, _lseq, _n) \ - asd_printk(STR_16BIT, #_n, _n, asd_read_reg_word(_h, Lm##_n(_lseq))) -#define PRINT_LREG_32bit(_h, _lseq, _n) \ - asd_printk(STR_32BIT, #_n, _n, asd_read_reg_dword(_h, Lm##_n(_lseq))) - -#define PRINT_LMIP_byte(_h, _lseq, _n) \ - asd_printk(STR_8BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \ - asd_read_reg_byte(_h, LmSEQ_##_n(_lseq))) -#define PRINT_LMIP_word(_h, _lseq, _n) \ - asd_printk(STR_16BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \ - asd_read_reg_word(_h, LmSEQ_##_n(_lseq))) -#define PRINT_LMIP_dword(_h, _lseq, _n) \ - asd_printk(STR_32BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \ - asd_read_reg_dword(_h, LmSEQ_##_n(_lseq))) -#define PRINT_LMIP_qword(_h, _lseq, _n) \ - asd_printk(STR_64BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \ - (unsigned long long)(((unsigned long long) \ - asd_read_reg_dword(_h, LmSEQ_##_n(_lseq))) \ - | (((unsigned long long) \ - asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)+4))<<32))) - -static void asd_print_lseq_cio_reg(struct asd_ha_struct *asd_ha, - u32 lseq_cio_addr, int i) -{ - switch (LSEQmCIOREGS[i].width) { - case 8: - asd_printk("%20s[0x%x]: 0x%02x\n", LSEQmCIOREGS[i].name, - LSEQmCIOREGS[i].offs, - asd_read_reg_byte(asd_ha, lseq_cio_addr + - LSEQmCIOREGS[i].offs)); - - break; - case 16: - asd_printk("%20s[0x%x]: 0x%04x\n", LSEQmCIOREGS[i].name, - LSEQmCIOREGS[i].offs, - asd_read_reg_word(asd_ha, lseq_cio_addr + - LSEQmCIOREGS[i].offs)); - - break; - case 32: - asd_printk("%20s[0x%x]: 0x%08x\n", LSEQmCIOREGS[i].name, - LSEQmCIOREGS[i].offs, - asd_read_reg_dword(asd_ha, lseq_cio_addr + - LSEQmCIOREGS[i].offs)); - break; - } -} - -static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq) -{ - u32 moffs; - int mode; - - asd_printk("LSEQ %d STATE\n", lseq); - - asd_printk("LSEQ%d: ARP2 REGISTERS\n", lseq); - PRINT_LREG_32bit(asd_ha, lseq, ARP2CTL); - PRINT_LREG_32bit(asd_ha, lseq, ARP2INT); - PRINT_LREG_32bit(asd_ha, lseq, ARP2INTEN); - PRINT_LREG_8bit(asd_ha, lseq, MODEPTR); - PRINT_LREG_8bit(asd_ha, lseq, ALTMODE); - PRINT_LREG_8bit(asd_ha, lseq, FLAG); - PRINT_LREG_8bit(asd_ha, lseq, ARP2INTCTL); - PRINT_LREG_16bit(asd_ha, lseq, STACK); - PRINT_LREG_16bit(asd_ha, lseq, PRGMCNT); - PRINT_LREG_16bit(asd_ha, lseq, ACCUM); - PRINT_LREG_16bit(asd_ha, lseq, SINDEX); - PRINT_LREG_16bit(asd_ha, lseq, DINDEX); - PRINT_LREG_8bit(asd_ha, lseq, SINDIR); - PRINT_LREG_8bit(asd_ha, lseq, DINDIR); - PRINT_LREG_8bit(asd_ha, lseq, JUMLDIR); - PRINT_LREG_8bit(asd_ha, lseq, ARP2HALTCODE); - PRINT_LREG_16bit(asd_ha, lseq, CURRADDR); - PRINT_LREG_16bit(asd_ha, lseq, LASTADDR); - PRINT_LREG_16bit(asd_ha, lseq, NXTLADDR); - - asd_printk("LSEQ%d: IOP REGISTERS\n", lseq); - - PRINT_LREG_32bit(asd_ha, lseq, MODECTL); - PRINT_LREG_32bit(asd_ha, lseq, DBGMODE); - PRINT_LREG_32bit(asd_ha, lseq, CONTROL); - PRINT_REG_32bit(asd_ha, BISTCTL0, LmBISTCTL0(lseq)); - PRINT_REG_32bit(asd_ha, BISTCTL1, LmBISTCTL1(lseq)); - - asd_printk("LSEQ%d: CIO REGISTERS\n", lseq); - asd_printk("Mode common:\n"); - - for (mode = 0; mode < 8; mode++) { - u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq); - int i; - - for (i = 0; LSEQmCIOREGS[i].name; i++) - if (LSEQmCIOREGS[i].mode == MODE_COMMON) - asd_print_lseq_cio_reg(asd_ha,lseq_cio_addr,i); - } - - asd_printk("Mode unique:\n"); - for (mode = 0; mode < 8; mode++) { - u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq); - int i; - - asd_printk("Mode %d\n", mode); - for (i = 0; LSEQmCIOREGS[i].name; i++) { - if (!(LSEQmCIOREGS[i].mode & (1 << mode))) - continue; - asd_print_lseq_cio_reg(asd_ha, lseq_cio_addr, i); - } - } - - asd_printk("SCRATCH MEMORY\n"); - - asd_printk("LSEQ%d MIP 0 >>>>\n", lseq); - PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_HEAD); - PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL); - PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER); - PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS); - PRINT_LMIP_dword(asd_ha, lseq, CONNECTION_STATE); - PRINT_LMIP_word(asd_ha, lseq, CONCTL); - PRINT_LMIP_byte(asd_ha, lseq, CONSTAT); - PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES); - PRINT_LMIP_word(asd_ha, lseq, REG1_ISR); - PRINT_LMIP_word(asd_ha, lseq, REG2_ISR); - PRINT_LMIP_word(asd_ha, lseq, REG3_ISR); - PRINT_LMIP_qword(asd_ha, lseq,REG0_ISR); - - asd_printk("LSEQ%d MIP 1 >>>>\n", lseq); - PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR0); - PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR1); - PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR2); - PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR3); - PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE0); - PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE1); - PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE2); - PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE3); - PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_HEAD); - PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_TAIL); - PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_BUF_AVAIL); - PRINT_LMIP_dword(asd_ha, lseq, TIMEOUT_CONST); - PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_SINDEX); - PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_DINDEX); - - asd_printk("LSEQ%d MIP 2 >>>>\n", lseq); - PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR0); - PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR1); - PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR2); - PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR3); - PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD0); - PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD1); - PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD2); - PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD3); - PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_HEAD); - PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_TAIL); - PRINT_LMIP_byte(asd_ha, lseq, EMPTY_BUFS_AVAIL); - - asd_printk("LSEQ%d MIP 3 >>>>\n", lseq); - PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TMR_TOUT_CONST); - PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMEOUT); - PRINT_LMIP_dword(asd_ha, lseq, SRST_ASSERT_TIMEOUT); - PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMEOUT); - PRINT_LMIP_dword(asd_ha, lseq, ONE_MILLISEC_TIMEOUT); - PRINT_LMIP_dword(asd_ha, lseq, TEN_MS_COMINIT_TIMEOUT); - PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMEOUT); - - for (mode = 0; mode < 3; mode++) { - asd_printk("LSEQ%d MDP 0 MODE %d >>>>\n", lseq, mode); - moffs = mode * LSEQ_MODE_SCRATCH_SIZE; - - asd_printk(STR_16BIT, "RET_ADDR", 0, - asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) - + moffs)); - asd_printk(STR_16BIT, "REG0_MODE", 2, - asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) - + moffs)); - asd_printk(STR_16BIT, "MODE_FLAGS", 4, - asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) - + moffs)); - asd_printk(STR_16BIT, "RET_ADDR2", 0x6, - asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) - + moffs)); - asd_printk(STR_16BIT, "RET_ADDR1", 0x8, - asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) - + moffs)); - asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB, - asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) - + moffs)); - asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC, - asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) - + moffs)); - } - - asd_printk("LSEQ%d MDP 0 MODE 5 >>>>\n", lseq); - moffs = LSEQ_MODE5_PAGE0_OFFSET; - asd_printk(STR_16BIT, "RET_ADDR", 0, - asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) + moffs)); - asd_printk(STR_16BIT, "REG0_MODE", 2, - asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) + moffs)); - asd_printk(STR_16BIT, "MODE_FLAGS", 4, - asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) + moffs)); - asd_printk(STR_16BIT, "RET_ADDR2", 0x6, - asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) + moffs)); - asd_printk(STR_16BIT, "RET_ADDR1", 0x8, - asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) + moffs)); - asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB, - asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) + moffs)); - asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC, - asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) + moffs)); - - asd_printk("LSEQ%d MDP 0 MODE 0 >>>>\n", lseq); - PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_DDB_SITE); - PRINT_LMIP_word(asd_ha, lseq, EMPTY_TRANS_CTX); - PRINT_LMIP_word(asd_ha, lseq, RESP_LEN); - PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_SCB_SITE); - PRINT_LMIP_dword(asd_ha, lseq, INTEN_SAVE); - PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_FRM_LEN); - PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_PROTOCOL); - PRINT_LMIP_byte(asd_ha, lseq, RESP_STATUS); - PRINT_LMIP_byte(asd_ha, lseq, LAST_LOADED_SGE); - PRINT_LMIP_byte(asd_ha, lseq, SAVE_SCBPTR); - - asd_printk("LSEQ%d MDP 0 MODE 1 >>>>\n", lseq); - PRINT_LMIP_word(asd_ha, lseq, Q_XMIT_HEAD); - PRINT_LMIP_word(asd_ha, lseq, M1_EMPTY_TRANS_CTX); - PRINT_LMIP_word(asd_ha, lseq, INI_CONN_TAG); - PRINT_LMIP_byte(asd_ha, lseq, FAILED_OPEN_STATUS); - PRINT_LMIP_byte(asd_ha, lseq, XMIT_REQUEST_TYPE); - PRINT_LMIP_byte(asd_ha, lseq, M1_RESP_STATUS); - PRINT_LMIP_byte(asd_ha, lseq, M1_LAST_LOADED_SGE); - PRINT_LMIP_word(asd_ha, lseq, M1_SAVE_SCBPTR); - - asd_printk("LSEQ%d MDP 0 MODE 2 >>>>\n", lseq); - PRINT_LMIP_word(asd_ha, lseq, PORT_COUNTER); - PRINT_LMIP_word(asd_ha, lseq, PM_TABLE_PTR); - PRINT_LMIP_word(asd_ha, lseq, SATA_INTERLOCK_TMR_SAVE); - PRINT_LMIP_word(asd_ha, lseq, IP_BITL); - PRINT_LMIP_word(asd_ha, lseq, COPY_SMP_CONN_TAG); - PRINT_LMIP_byte(asd_ha, lseq, P0M2_OFFS1AH); - - asd_printk("LSEQ%d MDP 0 MODE 4/5 >>>>\n", lseq); - PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_STATUS); - PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_MODE); - PRINT_LMIP_word(asd_ha, lseq, Q_LINK_HEAD); - PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_ERR); - PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_SIGNALS); - PRINT_LMIP_byte(asd_ha, lseq, SAS_RESET_MODE); - PRINT_LMIP_byte(asd_ha, lseq, LINK_RESET_RETRY_COUNT); - PRINT_LMIP_byte(asd_ha, lseq, NUM_LINK_RESET_RETRIES); - PRINT_LMIP_word(asd_ha, lseq, OOB_INT_ENABLES); - PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_TIMEOUT); - PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_DOWN_COUNT); - - asd_printk("LSEQ%d MDP 1 MODE 0 >>>>\n", lseq); - PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR0); - PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR1); - - asd_printk("LSEQ%d MDP 1 MODE 1 >>>>\n", lseq); - PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR0); - PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR1); - - asd_printk("LSEQ%d MDP 1 MODE 2 >>>>\n", lseq); - PRINT_LMIP_dword(asd_ha, lseq, INVALID_DWORD_COUNT); - PRINT_LMIP_dword(asd_ha, lseq, DISPARITY_ERROR_COUNT); - PRINT_LMIP_dword(asd_ha, lseq, LOSS_OF_SYNC_COUNT); - - asd_printk("LSEQ%d MDP 1 MODE 4/5 >>>>\n", lseq); - PRINT_LMIP_dword(asd_ha, lseq, FRAME_TYPE_MASK); - PRINT_LMIP_dword(asd_ha, lseq, HASHED_SRC_ADDR_MASK_PRINT); - PRINT_LMIP_byte(asd_ha, lseq, NUM_FILL_BYTES_MASK); - PRINT_LMIP_word(asd_ha, lseq, TAG_MASK); - PRINT_LMIP_word(asd_ha, lseq, TARGET_PORT_XFER_TAG); - PRINT_LMIP_dword(asd_ha, lseq, DATA_OFFSET); - - asd_printk("LSEQ%d MDP 2 MODE 0 >>>>\n", lseq); - PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMER_TERM_TS); - PRINT_LMIP_byte(asd_ha, lseq, DEVICE_BITS); - PRINT_LMIP_word(asd_ha, lseq, SDB_DDB); - PRINT_LMIP_word(asd_ha, lseq, SDB_NUM_TAGS); - PRINT_LMIP_word(asd_ha, lseq, SDB_CURR_TAG); - - asd_printk("LSEQ%d MDP 2 MODE 1 >>>>\n", lseq); - PRINT_LMIP_qword(asd_ha, lseq, TX_ID_ADDR_FRAME); - PRINT_LMIP_dword(asd_ha, lseq, OPEN_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, SRST_AS_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, LAST_LOADED_SG_EL); - - asd_printk("LSEQ%d MDP 2 MODE 2 >>>>\n", lseq); - PRINT_LMIP_dword(asd_ha, lseq, CLOSE_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, BREAK_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, DWS_RESET_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, MCTL_TIMER_TERM_TS); - - asd_printk("LSEQ%d MDP 2 MODE 4/5 >>>>\n", lseq); - PRINT_LMIP_dword(asd_ha, lseq, COMINIT_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, RCV_ID_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMER_TERM_TS); - PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TIMER_TERM_TS); -} - -#if 0 - -/** - * asd_dump_ddb_site -- dump a CSEQ DDB site - * @asd_ha: pointer to host adapter structure - * @site_no: site number of interest - */ -void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no) -{ - if (site_no >= asd_ha->hw_prof.max_ddbs) - return; - -#define DDB_FIELDB(__name) \ - asd_ddbsite_read_byte(asd_ha, site_no, \ - offsetof(struct asd_ddb_ssp_smp_target_port, __name)) -#define DDB2_FIELDB(__name) \ - asd_ddbsite_read_byte(asd_ha, site_no, \ - offsetof(struct asd_ddb_stp_sata_target_port, __name)) -#define DDB_FIELDW(__name) \ - asd_ddbsite_read_word(asd_ha, site_no, \ - offsetof(struct asd_ddb_ssp_smp_target_port, __name)) - -#define DDB_FIELDD(__name) \ - asd_ddbsite_read_dword(asd_ha, site_no, \ - offsetof(struct asd_ddb_ssp_smp_target_port, __name)) - - asd_printk("DDB: 0x%02x\n", site_no); - asd_printk("conn_type: 0x%02x\n", DDB_FIELDB(conn_type)); - asd_printk("conn_rate: 0x%02x\n", DDB_FIELDB(conn_rate)); - asd_printk("init_conn_tag: 0x%04x\n", be16_to_cpu(DDB_FIELDW(init_conn_tag))); - asd_printk("send_queue_head: 0x%04x\n", be16_to_cpu(DDB_FIELDW(send_queue_head))); - asd_printk("sq_suspended: 0x%02x\n", DDB_FIELDB(sq_suspended)); - asd_printk("DDB Type: 0x%02x\n", DDB_FIELDB(ddb_type)); - asd_printk("AWT Default: 0x%04x\n", DDB_FIELDW(awt_def)); - asd_printk("compat_features: 0x%02x\n", DDB_FIELDB(compat_features)); - asd_printk("Pathway Blocked Count: 0x%02x\n", - DDB_FIELDB(pathway_blocked_count)); - asd_printk("arb_wait_time: 0x%04x\n", DDB_FIELDW(arb_wait_time)); - asd_printk("more_compat_features: 0x%08x\n", - DDB_FIELDD(more_compat_features)); - asd_printk("Conn Mask: 0x%02x\n", DDB_FIELDB(conn_mask)); - asd_printk("flags: 0x%02x\n", DDB_FIELDB(flags)); - asd_printk("flags2: 0x%02x\n", DDB2_FIELDB(flags2)); - asd_printk("ExecQ Tail: 0x%04x\n",DDB_FIELDW(exec_queue_tail)); - asd_printk("SendQ Tail: 0x%04x\n",DDB_FIELDW(send_queue_tail)); - asd_printk("Active Task Count: 0x%04x\n", - DDB_FIELDW(active_task_count)); - asd_printk("ITNL Reason: 0x%02x\n", DDB_FIELDB(itnl_reason)); - asd_printk("ITNL Timeout Const: 0x%04x\n", DDB_FIELDW(itnl_timeout)); - asd_printk("ITNL timestamp: 0x%08x\n", DDB_FIELDD(itnl_timestamp)); -} - -void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) -{ -#define DDB0_FIELDB(__name) \ - asd_ddbsite_read_byte(asd_ha, 0, \ - offsetof(struct asd_ddb_seq_shared, __name)) -#define DDB0_FIELDW(__name) \ - asd_ddbsite_read_word(asd_ha, 0, \ - offsetof(struct asd_ddb_seq_shared, __name)) - -#define DDB0_FIELDD(__name) \ - asd_ddbsite_read_dword(asd_ha,0 , \ - offsetof(struct asd_ddb_seq_shared, __name)) - -#define DDB0_FIELDA(__name, _o) \ - asd_ddbsite_read_byte(asd_ha, 0, \ - offsetof(struct asd_ddb_seq_shared, __name)+_o) - - - asd_printk("DDB: 0\n"); - asd_printk("q_free_ddb_head:%04x\n", DDB0_FIELDW(q_free_ddb_head)); - asd_printk("q_free_ddb_tail:%04x\n", DDB0_FIELDW(q_free_ddb_tail)); - asd_printk("q_free_ddb_cnt:%04x\n", DDB0_FIELDW(q_free_ddb_cnt)); - asd_printk("q_used_ddb_head:%04x\n", DDB0_FIELDW(q_used_ddb_head)); - asd_printk("q_used_ddb_tail:%04x\n", DDB0_FIELDW(q_used_ddb_tail)); - asd_printk("shared_mem_lock:%04x\n", DDB0_FIELDW(shared_mem_lock)); - asd_printk("smp_conn_tag:%04x\n", DDB0_FIELDW(smp_conn_tag)); - asd_printk("est_nexus_buf_cnt:%04x\n", DDB0_FIELDW(est_nexus_buf_cnt)); - asd_printk("est_nexus_buf_thresh:%04x\n", - DDB0_FIELDW(est_nexus_buf_thresh)); - asd_printk("conn_not_active:%02x\n", DDB0_FIELDB(conn_not_active)); - asd_printk("phy_is_up:%02x\n", DDB0_FIELDB(phy_is_up)); - asd_printk("port_map_by_links:%02x %02x %02x %02x " - "%02x %02x %02x %02x\n", - DDB0_FIELDA(port_map_by_links, 0), - DDB0_FIELDA(port_map_by_links, 1), - DDB0_FIELDA(port_map_by_links, 2), - DDB0_FIELDA(port_map_by_links, 3), - DDB0_FIELDA(port_map_by_links, 4), - DDB0_FIELDA(port_map_by_links, 5), - DDB0_FIELDA(port_map_by_links, 6), - DDB0_FIELDA(port_map_by_links, 7)); -} - -static void asd_dump_scb_site(struct asd_ha_struct *asd_ha, u16 site_no) -{ - -#define SCB_FIELDB(__name) \ - asd_scbsite_read_byte(asd_ha, site_no, sizeof(struct scb_header) \ - + offsetof(struct initiate_ssp_task, __name)) -#define SCB_FIELDW(__name) \ - asd_scbsite_read_word(asd_ha, site_no, sizeof(struct scb_header) \ - + offsetof(struct initiate_ssp_task, __name)) -#define SCB_FIELDD(__name) \ - asd_scbsite_read_dword(asd_ha, site_no, sizeof(struct scb_header) \ - + offsetof(struct initiate_ssp_task, __name)) - - asd_printk("Total Xfer Len: 0x%08x.\n", SCB_FIELDD(total_xfer_len)); - asd_printk("Frame Type: 0x%02x.\n", SCB_FIELDB(ssp_frame.frame_type)); - asd_printk("Tag: 0x%04x.\n", SCB_FIELDW(ssp_frame.tag)); - asd_printk("Target Port Xfer Tag: 0x%04x.\n", - SCB_FIELDW(ssp_frame.tptt)); - asd_printk("Data Offset: 0x%08x.\n", SCB_FIELDW(ssp_frame.data_offs)); - asd_printk("Retry Count: 0x%02x.\n", SCB_FIELDB(retry_count)); -} - -/** - * asd_dump_scb_sites -- dump currently used CSEQ SCB sites - * @asd_ha: pointer to host adapter struct - */ -void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) -{ - u16 site_no; - - for (site_no = 0; site_no < asd_ha->hw_prof.max_scbs; site_no++) { - u8 opcode; - - if (!SCB_SITE_VALID(site_no)) - continue; - - /* We are only interested in SCB sites currently used. - */ - opcode = asd_scbsite_read_byte(asd_ha, site_no, - offsetof(struct scb_header, - opcode)); - if (opcode == 0xFF) - continue; - - asd_printk("\nSCB: 0x%x\n", site_no); - asd_dump_scb_site(asd_ha, site_no); - } -} - -#endif /* 0 */ - -/** - * ads_dump_seq_state -- dump CSEQ and LSEQ states - * @asd_ha: pointer to host adapter structure - * @lseq_mask: mask of LSEQs of interest - */ -void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask) -{ - int lseq; - - asd_dump_cseq_state(asd_ha); - - if (lseq_mask != 0) - for_each_sequencer(lseq_mask, lseq_mask, lseq) - asd_dump_lseq_state(asd_ha, lseq); -} - -void asd_dump_frame_rcvd(struct asd_phy *phy, - struct done_list_struct *dl) -{ - unsigned long flags; - int i; - - switch ((dl->status_block[1] & 0x70) >> 3) { - case SAS_PROTOCOL_STP: - ASD_DPRINTK("STP proto device-to-host FIS:\n"); - break; - default: - case SAS_PROTOCOL_SSP: - ASD_DPRINTK("SAS proto IDENTIFY:\n"); - break; - } - spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); - for (i = 0; i < phy->sas_phy.frame_rcvd_size; i+=4) - ASD_DPRINTK("%02x: %02x %02x %02x %02x\n", - i, - phy->frame_rcvd[i], - phy->frame_rcvd[i+1], - phy->frame_rcvd[i+2], - phy->frame_rcvd[i+3]); - spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); -} - -#if 0 - -static void asd_dump_scb(struct asd_ascb *ascb, int ind) -{ - asd_printk("scb%d: vaddr: 0x%p, dma_handle: 0x%llx, next: 0x%llx, " - "index:%d, opcode:0x%02x\n", - ind, ascb->dma_scb.vaddr, - (unsigned long long)ascb->dma_scb.dma_handle, - (unsigned long long) - le64_to_cpu(ascb->scb->header.next_scb), - le16_to_cpu(ascb->scb->header.index), - ascb->scb->header.opcode); -} - -void asd_dump_scb_list(struct asd_ascb *ascb, int num) -{ - int i = 0; - - asd_printk("dumping %d scbs:\n", num); - - asd_dump_scb(ascb, i++); - --num; - - if (num > 0 && !list_empty(&ascb->list)) { - struct list_head *el; - - list_for_each(el, &ascb->list) { - struct asd_ascb *s = list_entry(el, struct asd_ascb, - list); - asd_dump_scb(s, i++); - if (--num <= 0) - break; - } - } -} - -#endif /* 0 */ - -#endif /* ASD_DEBUG */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.h b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.h deleted file mode 100644 index 191a753d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_dump.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Aic94xx SAS/SATA driver dump header file. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef _AIC94XX_DUMP_H_ -#define _AIC94XX_DUMP_H_ - -#ifdef ASD_DEBUG - -void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask); -void asd_dump_frame_rcvd(struct asd_phy *phy, - struct done_list_struct *dl); -#else /* ASD_DEBUG */ - -static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha, - u8 lseq_mask) { } -static inline void asd_dump_frame_rcvd(struct asd_phy *phy, - struct done_list_struct *dl) { } -#endif /* ASD_DEBUG */ - -#endif /* _AIC94XX_DUMP_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.c deleted file mode 100644 index 81b736c7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.c +++ /dev/null @@ -1,1391 +0,0 @@ -/* - * Aic94xx SAS/SATA driver hardware interface. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include - -#include "aic94xx.h" -#include "aic94xx_reg.h" -#include "aic94xx_hwi.h" -#include "aic94xx_seq.h" -#include "aic94xx_dump.h" - -u32 MBAR0_SWB_SIZE; - -/* ---------- Initialization ---------- */ - -static int asd_get_user_sas_addr(struct asd_ha_struct *asd_ha) -{ - /* adapter came with a sas address */ - if (asd_ha->hw_prof.sas_addr[0]) - return 0; - - return sas_request_addr(asd_ha->sas_ha.core.shost, - asd_ha->hw_prof.sas_addr); -} - -static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha) -{ - int i; - - for (i = 0; i < ASD_MAX_PHYS; i++) { - if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0) - continue; - /* Set a phy's address only if it has none. - */ - ASD_DPRINTK("setting phy%d addr to %llx\n", i, - SAS_ADDR(asd_ha->hw_prof.sas_addr)); - memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, - asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE); - } -} - -/* ---------- PHY initialization ---------- */ - -static void asd_init_phy_identify(struct asd_phy *phy) -{ - phy->identify_frame = phy->id_frm_tok->vaddr; - - memset(phy->identify_frame, 0, sizeof(*phy->identify_frame)); - - phy->identify_frame->dev_type = SAS_END_DEV; - if (phy->sas_phy.role & PHY_ROLE_INITIATOR) - phy->identify_frame->initiator_bits = phy->sas_phy.iproto; - if (phy->sas_phy.role & PHY_ROLE_TARGET) - phy->identify_frame->target_bits = phy->sas_phy.tproto; - memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr, - SAS_ADDR_SIZE); - phy->identify_frame->phy_id = phy->sas_phy.id; -} - -static int asd_init_phy(struct asd_phy *phy) -{ - struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - - sas_phy->enabled = 1; - sas_phy->class = SAS; - sas_phy->iproto = SAS_PROTOCOL_ALL; - sas_phy->tproto = 0; - sas_phy->type = PHY_TYPE_PHYSICAL; - sas_phy->role = PHY_ROLE_INITIATOR; - sas_phy->oob_mode = OOB_NOT_CONNECTED; - sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; - - phy->id_frm_tok = asd_alloc_coherent(asd_ha, - sizeof(*phy->identify_frame), - GFP_KERNEL); - if (!phy->id_frm_tok) { - asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id); - return -ENOMEM; - } else - asd_init_phy_identify(phy); - - memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd)); - - return 0; -} - -static void asd_init_ports(struct asd_ha_struct *asd_ha) -{ - int i; - - spin_lock_init(&asd_ha->asd_ports_lock); - for (i = 0; i < ASD_MAX_PHYS; i++) { - struct asd_port *asd_port = &asd_ha->asd_ports[i]; - - memset(asd_port->sas_addr, 0, SAS_ADDR_SIZE); - memset(asd_port->attached_sas_addr, 0, SAS_ADDR_SIZE); - asd_port->phy_mask = 0; - asd_port->num_phys = 0; - } -} - -static int asd_init_phys(struct asd_ha_struct *asd_ha) -{ - u8 i; - u8 phy_mask = asd_ha->hw_prof.enabled_phys; - - for (i = 0; i < ASD_MAX_PHYS; i++) { - struct asd_phy *phy = &asd_ha->phys[i]; - - phy->phy_desc = &asd_ha->hw_prof.phy_desc[i]; - phy->asd_port = NULL; - - phy->sas_phy.enabled = 0; - phy->sas_phy.id = i; - phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0]; - phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0]; - phy->sas_phy.ha = &asd_ha->sas_ha; - phy->sas_phy.lldd_phy = phy; - } - - /* Now enable and initialize only the enabled phys. */ - for_each_phy(phy_mask, phy_mask, i) { - int err = asd_init_phy(&asd_ha->phys[i]); - if (err) - return err; - } - - return 0; -} - -/* ---------- Sliding windows ---------- */ - -static int asd_init_sw(struct asd_ha_struct *asd_ha) -{ - struct pci_dev *pcidev = asd_ha->pcidev; - int err; - u32 v; - - /* Unlock MBARs */ - err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v); - if (err) { - asd_printk("couldn't access conf. space of %s\n", - pci_name(pcidev)); - goto Err; - } - if (v) - err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v); - if (err) { - asd_printk("couldn't write to MBAR_KEY of %s\n", - pci_name(pcidev)); - goto Err; - } - - /* Set sliding windows A, B and C to point to proper internal - * memory regions. - */ - pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR); - pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB, - REG_BASE_ADDR_CSEQCIO); - pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI); - asd_ha->io_handle[0].swa_base = REG_BASE_ADDR; - asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO; - asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI; - MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80; - if (!asd_ha->iospace) { - /* MBAR1 will point to OCM (On Chip Memory) */ - pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR); - asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR; - } - spin_lock_init(&asd_ha->iolock); -Err: - return err; -} - -/* ---------- SCB initialization ---------- */ - -/** - * asd_init_scbs - manually allocate the first SCB. - * @asd_ha: pointer to host adapter structure - * - * This allocates the very first SCB which would be sent to the - * sequencer for execution. Its bus address is written to - * CSEQ_Q_NEW_POINTER, mode page 2, mode 8. Since the bus address of - * the _next_ scb to be DMA-ed to the host adapter is read from the last - * SCB DMA-ed to the host adapter, we have to always stay one step - * ahead of the sequencer and keep one SCB already allocated. - */ -static int asd_init_scbs(struct asd_ha_struct *asd_ha) -{ - struct asd_seq_data *seq = &asd_ha->seq; - int bitmap_bytes; - - /* allocate the index array and bitmap */ - asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs; - asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits* - sizeof(void *), GFP_KERNEL); - if (!asd_ha->seq.tc_index_array) - return -ENOMEM; - - bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8; - bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long); - asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL); - if (!asd_ha->seq.tc_index_bitmap) - return -ENOMEM; - - spin_lock_init(&seq->tc_index_lock); - - seq->next_scb.size = sizeof(struct scb); - seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL, - &seq->next_scb.dma_handle); - if (!seq->next_scb.vaddr) { - kfree(asd_ha->seq.tc_index_bitmap); - kfree(asd_ha->seq.tc_index_array); - asd_ha->seq.tc_index_bitmap = NULL; - asd_ha->seq.tc_index_array = NULL; - return -ENOMEM; - } - - seq->pending = 0; - spin_lock_init(&seq->pend_q_lock); - INIT_LIST_HEAD(&seq->pend_q); - - return 0; -} - -static void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha) -{ - asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE; - asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE; - ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n", - asd_ha->hw_prof.max_scbs, - asd_ha->hw_prof.max_ddbs); -} - -/* ---------- Done List initialization ---------- */ - -static void asd_dl_tasklet_handler(unsigned long); - -static int asd_init_dl(struct asd_ha_struct *asd_ha) -{ - asd_ha->seq.actual_dl - = asd_alloc_coherent(asd_ha, - ASD_DL_SIZE * sizeof(struct done_list_struct), - GFP_KERNEL); - if (!asd_ha->seq.actual_dl) - return -ENOMEM; - asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr; - asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE; - asd_ha->seq.dl_next = 0; - tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler, - (unsigned long) asd_ha); - - return 0; -} - -/* ---------- EDB and ESCB init ---------- */ - -static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, gfp_t gfp_flags) -{ - struct asd_seq_data *seq = &asd_ha->seq; - int i; - - seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags); - if (!seq->edb_arr) - return -ENOMEM; - - for (i = 0; i < seq->num_edbs; i++) { - seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE, - gfp_flags); - if (!seq->edb_arr[i]) - goto Err_unroll; - memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE); - } - - ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs); - - return 0; - -Err_unroll: - for (i-- ; i >= 0; i--) - asd_free_coherent(asd_ha, seq->edb_arr[i]); - kfree(seq->edb_arr); - seq->edb_arr = NULL; - - return -ENOMEM; -} - -static int asd_alloc_escbs(struct asd_ha_struct *asd_ha, - gfp_t gfp_flags) -{ - struct asd_seq_data *seq = &asd_ha->seq; - struct asd_ascb *escb; - int i, escbs; - - seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr), - gfp_flags); - if (!seq->escb_arr) - return -ENOMEM; - - escbs = seq->num_escbs; - escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags); - if (!escb) { - asd_printk("couldn't allocate list of escbs\n"); - goto Err; - } - seq->num_escbs -= escbs; /* subtract what was not allocated */ - ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs); - - for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next, - struct asd_ascb, - list)) { - seq->escb_arr[i] = escb; - escb->scb->header.opcode = EMPTY_SCB; - } - - return 0; -Err: - kfree(seq->escb_arr); - seq->escb_arr = NULL; - return -ENOMEM; - -} - -static void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha) -{ - struct asd_seq_data *seq = &asd_ha->seq; - int i, k, z = 0; - - for (i = 0; i < seq->num_escbs; i++) { - struct asd_ascb *ascb = seq->escb_arr[i]; - struct empty_scb *escb = &ascb->scb->escb; - - ascb->edb_index = z; - - escb->num_valid = ASD_EDBS_PER_SCB; - - for (k = 0; k < ASD_EDBS_PER_SCB; k++) { - struct sg_el *eb = &escb->eb[k]; - struct asd_dma_tok *edb = seq->edb_arr[z++]; - - memset(eb, 0, sizeof(*eb)); - eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle)); - eb->size = cpu_to_le32(((u32) edb->size)); - } - } -} - -/** - * asd_init_escbs -- allocate and initialize empty scbs - * @asd_ha: pointer to host adapter structure - * - * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers. - * They transport sense data, etc. - */ -static int asd_init_escbs(struct asd_ha_struct *asd_ha) -{ - struct asd_seq_data *seq = &asd_ha->seq; - int err = 0; - - /* Allocate two empty data buffers (edb) per sequencer. */ - int edbs = 2*(1+asd_ha->hw_prof.num_phys); - - seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB; - seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB; - - err = asd_alloc_edbs(asd_ha, GFP_KERNEL); - if (err) { - asd_printk("couldn't allocate edbs\n"); - return err; - } - - err = asd_alloc_escbs(asd_ha, GFP_KERNEL); - if (err) { - asd_printk("couldn't allocate escbs\n"); - return err; - } - - asd_assign_edbs2escbs(asd_ha); - /* In order to insure that normal SCBs do not overfill sequencer - * memory and leave no space for escbs (halting condition), - * we increment pending here by the number of escbs. However, - * escbs are never pending. - */ - seq->pending = seq->num_escbs; - seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2; - - return 0; -} - -/* ---------- HW initialization ---------- */ - -/** - * asd_chip_hardrst -- hard reset the chip - * @asd_ha: pointer to host adapter structure - * - * This takes 16 cycles and is synchronous to CFCLK, which runs - * at 200 MHz, so this should take at most 80 nanoseconds. - */ -int asd_chip_hardrst(struct asd_ha_struct *asd_ha) -{ - int i; - int count = 100; - u32 reg; - - for (i = 0 ; i < 4 ; i++) { - asd_write_reg_dword(asd_ha, COMBIST, HARDRST); - } - - do { - udelay(1); - reg = asd_read_reg_dword(asd_ha, CHIMINT); - if (reg & HARDRSTDET) { - asd_write_reg_dword(asd_ha, CHIMINT, - HARDRSTDET|PORRSTDET); - return 0; - } - } while (--count > 0); - - return -ENODEV; -} - -/** - * asd_init_chip -- initialize the chip - * @asd_ha: pointer to host adapter structure - * - * Hard resets the chip, disables HA interrupts, downloads the sequnecer - * microcode and starts the sequencers. The caller has to explicitly - * enable HA interrupts with asd_enable_ints(asd_ha). - */ -static int asd_init_chip(struct asd_ha_struct *asd_ha) -{ - int err; - - err = asd_chip_hardrst(asd_ha); - if (err) { - asd_printk("couldn't hard reset %s\n", - pci_name(asd_ha->pcidev)); - goto out; - } - - asd_disable_ints(asd_ha); - - err = asd_init_seqs(asd_ha); - if (err) { - asd_printk("couldn't init seqs for %s\n", - pci_name(asd_ha->pcidev)); - goto out; - } - - err = asd_start_seqs(asd_ha); - if (err) { - asd_printk("coudln't start seqs for %s\n", - pci_name(asd_ha->pcidev)); - goto out; - } -out: - return err; -} - -#define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE)) - -static int max_devs = 0; -module_param_named(max_devs, max_devs, int, S_IRUGO); -MODULE_PARM_DESC(max_devs, "\n" - "\tMaximum number of SAS devices to support (not LUs).\n" - "\tDefault: 2176, Maximum: 65663.\n"); - -static int max_cmnds = 0; -module_param_named(max_cmnds, max_cmnds, int, S_IRUGO); -MODULE_PARM_DESC(max_cmnds, "\n" - "\tMaximum number of commands queuable.\n" - "\tDefault: 512, Maximum: 66047.\n"); - -static void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha) -{ - unsigned long dma_addr = OCM_BASE_ADDR; - u32 d; - - dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE; - asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr); - d = asd_read_reg_dword(asd_ha, CTXDOMAIN); - d |= 4; - asd_write_reg_dword(asd_ha, CTXDOMAIN, d); - asd_ha->hw_prof.max_ddbs += MAX_DEVS; -} - -static int asd_extend_devctx(struct asd_ha_struct *asd_ha) -{ - dma_addr_t dma_handle; - unsigned long dma_addr; - u32 d; - int size; - - asd_extend_devctx_ocm(asd_ha); - - asd_ha->hw_prof.ddb_ext = NULL; - if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) { - max_devs = asd_ha->hw_prof.max_ddbs; - return 0; - } - - size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE; - - asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL); - if (!asd_ha->hw_prof.ddb_ext) { - asd_printk("couldn't allocate memory for %d devices\n", - max_devs); - max_devs = asd_ha->hw_prof.max_ddbs; - return -ENOMEM; - } - dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle; - dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE); - dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE; - dma_handle = (dma_addr_t) dma_addr; - asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle); - d = asd_read_reg_dword(asd_ha, CTXDOMAIN); - d &= ~4; - asd_write_reg_dword(asd_ha, CTXDOMAIN, d); - - asd_ha->hw_prof.max_ddbs = max_devs; - - return 0; -} - -static int asd_extend_cmdctx(struct asd_ha_struct *asd_ha) -{ - dma_addr_t dma_handle; - unsigned long dma_addr; - u32 d; - int size; - - asd_ha->hw_prof.scb_ext = NULL; - if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) { - max_cmnds = asd_ha->hw_prof.max_scbs; - return 0; - } - - size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE; - - asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL); - if (!asd_ha->hw_prof.scb_ext) { - asd_printk("couldn't allocate memory for %d commands\n", - max_cmnds); - max_cmnds = asd_ha->hw_prof.max_scbs; - return -ENOMEM; - } - dma_handle = asd_ha->hw_prof.scb_ext->dma_handle; - dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE); - dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE; - dma_handle = (dma_addr_t) dma_addr; - asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle); - d = asd_read_reg_dword(asd_ha, CTXDOMAIN); - d &= ~1; - asd_write_reg_dword(asd_ha, CTXDOMAIN, d); - - asd_ha->hw_prof.max_scbs = max_cmnds; - - return 0; -} - -/** - * asd_init_ctxmem -- initialize context memory - * asd_ha: pointer to host adapter structure - * - * This function sets the maximum number of SCBs and - * DDBs which can be used by the sequencer. This is normally - * 512 and 128 respectively. If support for more SCBs or more DDBs - * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are - * initialized here to extend context memory to point to host memory, - * thus allowing unlimited support for SCBs and DDBs -- only limited - * by host memory. - */ -static int asd_init_ctxmem(struct asd_ha_struct *asd_ha) -{ - int bitmap_bytes; - - asd_get_max_scb_ddb(asd_ha); - asd_extend_devctx(asd_ha); - asd_extend_cmdctx(asd_ha); - - /* The kernel wants bitmaps to be unsigned long sized. */ - bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8; - bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long); - asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL); - if (!asd_ha->hw_prof.ddb_bitmap) - return -ENOMEM; - spin_lock_init(&asd_ha->hw_prof.ddb_lock); - - return 0; -} - -int asd_init_hw(struct asd_ha_struct *asd_ha) -{ - int err; - u32 v; - - err = asd_init_sw(asd_ha); - if (err) - return err; - - err = pci_read_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, &v); - if (err) { - asd_printk("couldn't read PCIC_HSTPCIX_CNTRL of %s\n", - pci_name(asd_ha->pcidev)); - return err; - } - pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, - v | SC_TMR_DIS); - if (err) { - asd_printk("couldn't disable split completion timer of %s\n", - pci_name(asd_ha->pcidev)); - return err; - } - - err = asd_read_ocm(asd_ha); - if (err) { - asd_printk("couldn't read ocm(%d)\n", err); - /* While suspicios, it is not an error that we - * couldn't read the OCM. */ - } - - err = asd_read_flash(asd_ha); - if (err) { - asd_printk("couldn't read flash(%d)\n", err); - /* While suspicios, it is not an error that we - * couldn't read FLASH memory. - */ - } - - asd_init_ctxmem(asd_ha); - - if (asd_get_user_sas_addr(asd_ha)) { - asd_printk("No SAS Address provided for %s\n", - pci_name(asd_ha->pcidev)); - err = -ENODEV; - goto Out; - } - - asd_propagate_sas_addr(asd_ha); - - err = asd_init_phys(asd_ha); - if (err) { - asd_printk("couldn't initialize phys for %s\n", - pci_name(asd_ha->pcidev)); - goto Out; - } - - asd_init_ports(asd_ha); - - err = asd_init_scbs(asd_ha); - if (err) { - asd_printk("couldn't initialize scbs for %s\n", - pci_name(asd_ha->pcidev)); - goto Out; - } - - err = asd_init_dl(asd_ha); - if (err) { - asd_printk("couldn't initialize the done list:%d\n", - err); - goto Out; - } - - err = asd_init_escbs(asd_ha); - if (err) { - asd_printk("couldn't initialize escbs\n"); - goto Out; - } - - err = asd_init_chip(asd_ha); - if (err) { - asd_printk("couldn't init the chip\n"); - goto Out; - } -Out: - return err; -} - -/* ---------- Chip reset ---------- */ - -/** - * asd_chip_reset -- reset the host adapter, etc - * @asd_ha: pointer to host adapter structure of interest - * - * Called from the ISR. Hard reset the chip. Let everything - * timeout. This should be no different than hot-unplugging the - * host adapter. Once everything times out we'll init the chip with - * a call to asd_init_chip() and enable interrupts with asd_enable_ints(). - * XXX finish. - */ -static void asd_chip_reset(struct asd_ha_struct *asd_ha) -{ - struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; - - ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev)); - asd_chip_hardrst(asd_ha); - sas_ha->notify_ha_event(sas_ha, HAE_RESET); -} - -/* ---------- Done List Routines ---------- */ - -static void asd_dl_tasklet_handler(unsigned long data) -{ - struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data; - struct asd_seq_data *seq = &asd_ha->seq; - unsigned long flags; - - while (1) { - struct done_list_struct *dl = &seq->dl[seq->dl_next]; - struct asd_ascb *ascb; - - if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle) - break; - - /* find the aSCB */ - spin_lock_irqsave(&seq->tc_index_lock, flags); - ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index)); - spin_unlock_irqrestore(&seq->tc_index_lock, flags); - if (unlikely(!ascb)) { - ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n"); - goto next_1; - } else if (ascb->scb->header.opcode == EMPTY_SCB) { - goto out; - } else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) { - goto next_1; - } - spin_lock_irqsave(&seq->pend_q_lock, flags); - list_del_init(&ascb->list); - seq->pending--; - spin_unlock_irqrestore(&seq->pend_q_lock, flags); - out: - ascb->tasklet_complete(ascb, dl); - - next_1: - seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1); - if (!seq->dl_next) - seq->dl_toggle ^= DL_TOGGLE_MASK; - } -} - -/* ---------- Interrupt Service Routines ---------- */ - -/** - * asd_process_donelist_isr -- schedule processing of done list entries - * @asd_ha: pointer to host adapter structure - */ -static void asd_process_donelist_isr(struct asd_ha_struct *asd_ha) -{ - tasklet_schedule(&asd_ha->seq.dl_tasklet); -} - -/** - * asd_com_sas_isr -- process device communication interrupt (COMINT) - * @asd_ha: pointer to host adapter structure - */ -static void asd_com_sas_isr(struct asd_ha_struct *asd_ha) -{ - u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT); - - /* clear COMSTAT int */ - asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF); - - if (comstat & CSBUFPERR) { - asd_printk("%s: command/status buffer dma parity error\n", - pci_name(asd_ha->pcidev)); - } else if (comstat & CSERR) { - int i; - u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR); - dmaerr &= 0xFF; - asd_printk("%s: command/status dma error, DMAERR: 0x%02x, " - "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n", - pci_name(asd_ha->pcidev), - dmaerr, - asd_read_reg_dword(asd_ha, CSDMAADR), - asd_read_reg_dword(asd_ha, CSDMAADR+4)); - asd_printk("CSBUFFER:\n"); - for (i = 0; i < 8; i++) { - asd_printk("%08x %08x %08x %08x\n", - asd_read_reg_dword(asd_ha, CSBUFFER), - asd_read_reg_dword(asd_ha, CSBUFFER+4), - asd_read_reg_dword(asd_ha, CSBUFFER+8), - asd_read_reg_dword(asd_ha, CSBUFFER+12)); - } - asd_dump_seq_state(asd_ha, 0); - } else if (comstat & OVLYERR) { - u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR); - dmaerr = (dmaerr >> 8) & 0xFF; - asd_printk("%s: overlay dma error:0x%x\n", - pci_name(asd_ha->pcidev), - dmaerr); - } - asd_chip_reset(asd_ha); -} - -static void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus) -{ - static const char *halt_code[256] = { - "UNEXPECTED_INTERRUPT0", - "UNEXPECTED_INTERRUPT1", - "UNEXPECTED_INTERRUPT2", - "UNEXPECTED_INTERRUPT3", - "UNEXPECTED_INTERRUPT4", - "UNEXPECTED_INTERRUPT5", - "UNEXPECTED_INTERRUPT6", - "UNEXPECTED_INTERRUPT7", - "UNEXPECTED_INTERRUPT8", - "UNEXPECTED_INTERRUPT9", - "UNEXPECTED_INTERRUPT10", - [11 ... 19] = "unknown[11,19]", - "NO_FREE_SCB_AVAILABLE", - "INVALID_SCB_OPCODE", - "INVALID_MBX_OPCODE", - "INVALID_ATA_STATE", - "ATA_QUEUE_FULL", - "ATA_TAG_TABLE_FAULT", - "ATA_TAG_MASK_FAULT", - "BAD_LINK_QUEUE_STATE", - "DMA2CHIM_QUEUE_ERROR", - "EMPTY_SCB_LIST_FULL", - "unknown[30]", - "IN_USE_SCB_ON_FREE_LIST", - "BAD_OPEN_WAIT_STATE", - "INVALID_STP_AFFILIATION", - "unknown[34]", - "EXEC_QUEUE_ERROR", - "TOO_MANY_EMPTIES_NEEDED", - "EMPTY_REQ_QUEUE_ERROR", - "Q_MONIRTT_MGMT_ERROR", - "TARGET_MODE_FLOW_ERROR", - "DEVICE_QUEUE_NOT_FOUND", - "START_IRTT_TIMER_ERROR", - "ABORT_TASK_ILLEGAL_REQ", - [43 ... 255] = "unknown[43,255]" - }; - - if (dchstatus & CSEQINT) { - u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT); - - if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) { - asd_printk("%s: CSEQ arp2int:0x%x\n", - pci_name(asd_ha->pcidev), - arp2int); - } else if (arp2int & ARP2HALTC) - asd_printk("%s: CSEQ halted: %s\n", - pci_name(asd_ha->pcidev), - halt_code[(arp2int>>16)&0xFF]); - else - asd_printk("%s: CARP2INT:0x%x\n", - pci_name(asd_ha->pcidev), - arp2int); - } - if (dchstatus & LSEQINT_MASK) { - int lseq; - u8 lseq_mask = dchstatus & LSEQINT_MASK; - - for_each_sequencer(lseq_mask, lseq_mask, lseq) { - u32 arp2int = asd_read_reg_dword(asd_ha, - LmARP2INT(lseq)); - if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR - | ARP2CIOPERR)) { - asd_printk("%s: LSEQ%d arp2int:0x%x\n", - pci_name(asd_ha->pcidev), - lseq, arp2int); - /* XXX we should only do lseq reset */ - } else if (arp2int & ARP2HALTC) - asd_printk("%s: LSEQ%d halted: %s\n", - pci_name(asd_ha->pcidev), - lseq,halt_code[(arp2int>>16)&0xFF]); - else - asd_printk("%s: LSEQ%d ARP2INT:0x%x\n", - pci_name(asd_ha->pcidev), lseq, - arp2int); - } - } - asd_chip_reset(asd_ha); -} - -/** - * asd_dch_sas_isr -- process device channel interrupt (DEVINT) - * @asd_ha: pointer to host adapter structure - */ -static void asd_dch_sas_isr(struct asd_ha_struct *asd_ha) -{ - u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS); - - if (dchstatus & CFIFTOERR) { - asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev)); - asd_chip_reset(asd_ha); - } else - asd_arp2_err(asd_ha, dchstatus); -} - -/** - * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR) - * @asd_ha: pointer to host adapter structure - */ -static void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha) -{ - u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R); - - if (!(stat0r & ASIERR)) { - asd_printk("hmm, EXSI interrupted but no error?\n"); - return; - } - - if (stat0r & ASIFMTERR) { - asd_printk("ASI SEEPROM format error for %s\n", - pci_name(asd_ha->pcidev)); - } else if (stat0r & ASISEECHKERR) { - u32 stat1r = asd_read_reg_dword(asd_ha, ASISTAT1R); - asd_printk("ASI SEEPROM checksum 0x%x error for %s\n", - stat1r & CHECKSUM_MASK, - pci_name(asd_ha->pcidev)); - } else { - u32 statr = asd_read_reg_dword(asd_ha, ASIERRSTATR); - - if (!(statr & CPI2ASIMSTERR_MASK)) { - ASD_DPRINTK("hmm, ASIERR?\n"); - return; - } else { - u32 addr = asd_read_reg_dword(asd_ha, ASIERRADDR); - u32 data = asd_read_reg_dword(asd_ha, ASIERRDATAR); - - asd_printk("%s: CPI2 xfer err: addr: 0x%x, wdata: 0x%x, " - "count: 0x%x, byteen: 0x%x, targerr: 0x%x " - "master id: 0x%x, master err: 0x%x\n", - pci_name(asd_ha->pcidev), - addr, data, - (statr & CPI2ASIBYTECNT_MASK) >> 16, - (statr & CPI2ASIBYTEEN_MASK) >> 12, - (statr & CPI2ASITARGERR_MASK) >> 8, - (statr & CPI2ASITARGMID_MASK) >> 4, - (statr & CPI2ASIMSTERR_MASK)); - } - } - asd_chip_reset(asd_ha); -} - -/** - * asd_hst_pcix_isr -- process host interface interrupts - * @asd_ha: pointer to host adapter structure - * - * Asserted on PCIX errors: target abort, etc. - */ -static void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha) -{ - u16 status; - u32 pcix_status; - u32 ecc_status; - - pci_read_config_word(asd_ha->pcidev, PCI_STATUS, &status); - pci_read_config_dword(asd_ha->pcidev, PCIX_STATUS, &pcix_status); - pci_read_config_dword(asd_ha->pcidev, ECC_CTRL_STAT, &ecc_status); - - if (status & PCI_STATUS_DETECTED_PARITY) - asd_printk("parity error for %s\n", pci_name(asd_ha->pcidev)); - else if (status & PCI_STATUS_REC_MASTER_ABORT) - asd_printk("master abort for %s\n", pci_name(asd_ha->pcidev)); - else if (status & PCI_STATUS_REC_TARGET_ABORT) - asd_printk("target abort for %s\n", pci_name(asd_ha->pcidev)); - else if (status & PCI_STATUS_PARITY) - asd_printk("data parity for %s\n", pci_name(asd_ha->pcidev)); - else if (pcix_status & RCV_SCE) { - asd_printk("received split completion error for %s\n", - pci_name(asd_ha->pcidev)); - pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status); - /* XXX: Abort task? */ - return; - } else if (pcix_status & UNEXP_SC) { - asd_printk("unexpected split completion for %s\n", - pci_name(asd_ha->pcidev)); - pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status); - /* ignore */ - return; - } else if (pcix_status & SC_DISCARD) - asd_printk("split completion discarded for %s\n", - pci_name(asd_ha->pcidev)); - else if (ecc_status & UNCOR_ECCERR) - asd_printk("uncorrectable ECC error for %s\n", - pci_name(asd_ha->pcidev)); - asd_chip_reset(asd_ha); -} - -/** - * asd_hw_isr -- host adapter interrupt service routine - * @irq: ignored - * @dev_id: pointer to host adapter structure - * - * The ISR processes done list entries and level 3 error handling. - */ -irqreturn_t asd_hw_isr(int irq, void *dev_id) -{ - struct asd_ha_struct *asd_ha = dev_id; - u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT); - - if (!chimint) - return IRQ_NONE; - - asd_write_reg_dword(asd_ha, CHIMINT, chimint); - (void) asd_read_reg_dword(asd_ha, CHIMINT); - - if (chimint & DLAVAIL) - asd_process_donelist_isr(asd_ha); - if (chimint & COMINT) - asd_com_sas_isr(asd_ha); - if (chimint & DEVINT) - asd_dch_sas_isr(asd_ha); - if (chimint & INITERR) - asd_rbi_exsi_isr(asd_ha); - if (chimint & HOSTERR) - asd_hst_pcix_isr(asd_ha); - - return IRQ_HANDLED; -} - -/* ---------- SCB handling ---------- */ - -static struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha, - gfp_t gfp_flags) -{ - extern struct kmem_cache *asd_ascb_cache; - struct asd_seq_data *seq = &asd_ha->seq; - struct asd_ascb *ascb; - unsigned long flags; - - ascb = kmem_cache_zalloc(asd_ascb_cache, gfp_flags); - - if (ascb) { - ascb->dma_scb.size = sizeof(struct scb); - ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, - gfp_flags, - &ascb->dma_scb.dma_handle); - if (!ascb->dma_scb.vaddr) { - kmem_cache_free(asd_ascb_cache, ascb); - return NULL; - } - memset(ascb->dma_scb.vaddr, 0, sizeof(struct scb)); - asd_init_ascb(asd_ha, ascb); - - spin_lock_irqsave(&seq->tc_index_lock, flags); - ascb->tc_index = asd_tc_index_get(seq, ascb); - spin_unlock_irqrestore(&seq->tc_index_lock, flags); - if (ascb->tc_index == -1) - goto undo; - - ascb->scb->header.index = cpu_to_le16((u16)ascb->tc_index); - } - - return ascb; -undo: - dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr, - ascb->dma_scb.dma_handle); - kmem_cache_free(asd_ascb_cache, ascb); - ASD_DPRINTK("no index for ascb\n"); - return NULL; -} - -/** - * asd_ascb_alloc_list -- allocate a list of aSCBs - * @asd_ha: pointer to host adapter structure - * @num: pointer to integer number of aSCBs - * @gfp_flags: GFP_ flags. - * - * This is the only function which is used to allocate aSCBs. - * It can allocate one or many. If more than one, then they form - * a linked list in two ways: by their list field of the ascb struct - * and by the next_scb field of the scb_header. - * - * Returns NULL if no memory was available, else pointer to a list - * of ascbs. When this function returns, @num would be the number - * of SCBs which were not able to be allocated, 0 if all requested - * were able to be allocated. - */ -struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct - *asd_ha, int *num, - gfp_t gfp_flags) -{ - struct asd_ascb *first = NULL; - - for ( ; *num > 0; --*num) { - struct asd_ascb *ascb = asd_ascb_alloc(asd_ha, gfp_flags); - - if (!ascb) - break; - else if (!first) - first = ascb; - else { - struct asd_ascb *last = list_entry(first->list.prev, - struct asd_ascb, - list); - list_add_tail(&ascb->list, &first->list); - last->scb->header.next_scb = - cpu_to_le64(((u64)ascb->dma_scb.dma_handle)); - } - } - - return first; -} - -/** - * asd_swap_head_scb -- swap the head scb - * @asd_ha: pointer to host adapter structure - * @ascb: pointer to the head of an ascb list - * - * The sequencer knows the DMA address of the next SCB to be DMAed to - * the host adapter, from initialization or from the last list DMAed. - * seq->next_scb keeps the address of this SCB. The sequencer will - * DMA to the host adapter this list of SCBs. But the head (first - * element) of this list is not known to the sequencer. Here we swap - * the head of the list with the known SCB (memcpy()). - * Only one memcpy() is required per list so it is in our interest - * to keep the list of SCB as long as possible so that the ratio - * of number of memcpy calls to the number of SCB DMA-ed is as small - * as possible. - * - * LOCKING: called with the pending list lock held. - */ -static void asd_swap_head_scb(struct asd_ha_struct *asd_ha, - struct asd_ascb *ascb) -{ - struct asd_seq_data *seq = &asd_ha->seq; - struct asd_ascb *last = list_entry(ascb->list.prev, - struct asd_ascb, - list); - struct asd_dma_tok t = ascb->dma_scb; - - memcpy(seq->next_scb.vaddr, ascb->scb, sizeof(*ascb->scb)); - ascb->dma_scb = seq->next_scb; - ascb->scb = ascb->dma_scb.vaddr; - seq->next_scb = t; - last->scb->header.next_scb = - cpu_to_le64(((u64)seq->next_scb.dma_handle)); -} - -/** - * asd_start_timers -- (add and) start timers of SCBs - * @list: pointer to struct list_head of the scbs - * @to: timeout in jiffies - * - * If an SCB in the @list has no timer function, assign the default - * one, then start the timer of the SCB. This function is - * intended to be called from asd_post_ascb_list(), just prior to - * posting the SCBs to the sequencer. - */ -static void asd_start_scb_timers(struct list_head *list) -{ - struct asd_ascb *ascb; - list_for_each_entry(ascb, list, list) { - if (!ascb->uldd_timer) { - ascb->timer.data = (unsigned long) ascb; - ascb->timer.function = asd_ascb_timedout; - ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT; - add_timer(&ascb->timer); - } - } -} - -/** - * asd_post_ascb_list -- post a list of 1 or more aSCBs to the host adapter - * @asd_ha: pointer to a host adapter structure - * @ascb: pointer to the first aSCB in the list - * @num: number of aSCBs in the list (to be posted) - * - * See queueing comment in asd_post_escb_list(). - * - * Additional note on queuing: In order to minimize the ratio of memcpy() - * to the number of ascbs sent, we try to batch-send as many ascbs as possible - * in one go. - * Two cases are possible: - * A) can_queue >= num, - * B) can_queue < num. - * Case A: we can send the whole batch at once. Increment "pending" - * in the beginning of this function, when it is checked, in order to - * eliminate races when this function is called by multiple processes. - * Case B: should never happen if the managing layer considers - * lldd_queue_size. - */ -int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, - int num) -{ - unsigned long flags; - LIST_HEAD(list); - int can_queue; - - spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); - can_queue = asd_ha->hw_prof.max_scbs - asd_ha->seq.pending; - if (can_queue >= num) - asd_ha->seq.pending += num; - else - can_queue = 0; - - if (!can_queue) { - spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); - asd_printk("%s: scb queue full\n", pci_name(asd_ha->pcidev)); - return -SAS_QUEUE_FULL; - } - - asd_swap_head_scb(asd_ha, ascb); - - __list_add(&list, ascb->list.prev, &ascb->list); - - asd_start_scb_timers(&list); - - asd_ha->seq.scbpro += num; - list_splice_init(&list, asd_ha->seq.pend_q.prev); - asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro); - spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); - - return 0; -} - -/** - * asd_post_escb_list -- post a list of 1 or more empty scb - * @asd_ha: pointer to a host adapter structure - * @ascb: pointer to the first empty SCB in the list - * @num: number of aSCBs in the list (to be posted) - * - * This is essentially the same as asd_post_ascb_list, but we do not - * increment pending, add those to the pending list or get indexes. - * See asd_init_escbs() and asd_init_post_escbs(). - * - * Since sending a list of ascbs is a superset of sending a single - * ascb, this function exists to generalize this. More specifically, - * when sending a list of those, we want to do only a _single_ - * memcpy() at swap head, as opposed to for each ascb sent (in the - * case of sending them one by one). That is, we want to minimize the - * ratio of memcpy() operations to the number of ascbs sent. The same - * logic applies to asd_post_ascb_list(). - */ -int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, - int num) -{ - unsigned long flags; - - spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); - asd_swap_head_scb(asd_ha, ascb); - asd_ha->seq.scbpro += num; - asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro); - spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); - - return 0; -} - -/* ---------- LED ---------- */ - -/** - * asd_turn_led -- turn on/off an LED - * @asd_ha: pointer to host adapter structure - * @phy_id: the PHY id whose LED we want to manupulate - * @op: 1 to turn on, 0 to turn off - */ -void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op) -{ - if (phy_id < ASD_MAX_PHYS) { - u32 v = asd_read_reg_dword(asd_ha, LmCONTROL(phy_id)); - if (op) - v |= LEDPOL; - else - v &= ~LEDPOL; - asd_write_reg_dword(asd_ha, LmCONTROL(phy_id), v); - } -} - -/** - * asd_control_led -- enable/disable an LED on the board - * @asd_ha: pointer to host adapter structure - * @phy_id: integer, the phy id - * @op: integer, 1 to enable, 0 to disable the LED - * - * First we output enable the LED, then we set the source - * to be an external module. - */ -void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op) -{ - if (phy_id < ASD_MAX_PHYS) { - u32 v; - - v = asd_read_reg_dword(asd_ha, GPIOOER); - if (op) - v |= (1 << phy_id); - else - v &= ~(1 << phy_id); - asd_write_reg_dword(asd_ha, GPIOOER, v); - - v = asd_read_reg_dword(asd_ha, GPIOCNFGR); - if (op) - v |= (1 << phy_id); - else - v &= ~(1 << phy_id); - asd_write_reg_dword(asd_ha, GPIOCNFGR, v); - } -} - -/* ---------- PHY enable ---------- */ - -static int asd_enable_phy(struct asd_ha_struct *asd_ha, int phy_id) -{ - struct asd_phy *phy = &asd_ha->phys[phy_id]; - - asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, INT_ENABLE_2), 0); - asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, HOT_PLUG_DELAY), - HOTPLUG_DELAY_TIMEOUT); - - /* Get defaults from manuf. sector */ - /* XXX we need defaults for those in case MS is broken. */ - asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_0), - phy->phy_desc->phy_control_0); - asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_1), - phy->phy_desc->phy_control_1); - asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_2), - phy->phy_desc->phy_control_2); - asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_3), - phy->phy_desc->phy_control_3); - - asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(phy_id), - ASD_COMINIT_TIMEOUT); - - asd_write_reg_addr(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(phy_id), - phy->id_frm_tok->dma_handle); - - asd_control_led(asd_ha, phy_id, 1); - - return 0; -} - -int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask) -{ - u8 phy_m; - u8 i; - int num = 0, k; - struct asd_ascb *ascb; - struct asd_ascb *ascb_list; - - if (!phy_mask) { - asd_printk("%s called with phy_mask of 0!?\n", __func__); - return 0; - } - - for_each_phy(phy_mask, phy_m, i) { - num++; - asd_enable_phy(asd_ha, i); - } - - k = num; - ascb_list = asd_ascb_alloc_list(asd_ha, &k, GFP_KERNEL); - if (!ascb_list) { - asd_printk("no memory for control phy ascb list\n"); - return -ENOMEM; - } - num -= k; - - ascb = ascb_list; - for_each_phy(phy_mask, phy_m, i) { - asd_build_control_phy(ascb, i, ENABLE_PHY); - ascb = list_entry(ascb->list.next, struct asd_ascb, list); - } - ASD_DPRINTK("posting %d control phy scbs\n", num); - k = asd_post_ascb_list(asd_ha, ascb_list, num); - if (k) - asd_ascb_free_list(ascb_list); - - return k; -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.h b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.h deleted file mode 100644 index 8c1c2823..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_hwi.h +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Aic94xx SAS/SATA driver hardware interface header file. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef _AIC94XX_HWI_H_ -#define _AIC94XX_HWI_H_ - -#include -#include -#include - -#include - -#include "aic94xx.h" -#include "aic94xx_sas.h" - -/* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */ -#define ASD_MAX_PHYS 8 -#define ASD_PCBA_SN_SIZE 12 - -struct asd_ha_addrspace { - void __iomem *addr; - unsigned long start; /* pci resource start */ - unsigned long len; /* pci resource len */ - unsigned long flags; /* pci resource flags */ - - /* addresses internal to the host adapter */ - u32 swa_base; /* mmspace 1 (MBAR1) uses this only */ - u32 swb_base; - u32 swc_base; -}; - -struct bios_struct { - int present; - u8 maj; - u8 min; - u32 bld; -}; - -struct unit_element_struct { - u16 num; - u16 size; - void *area; -}; - -struct flash_struct { - u32 bar; - int present; - int wide; - u8 manuf; - u8 dev_id; - u8 sec_prot; - u8 method; - - u32 dir_offs; -}; - -struct asd_phy_desc { - /* From CTRL-A settings, then set to what is appropriate */ - u8 sas_addr[SAS_ADDR_SIZE]; - u8 max_sas_lrate; - u8 min_sas_lrate; - u8 max_sata_lrate; - u8 min_sata_lrate; - u8 flags; -#define ASD_CRC_DIS 1 -#define ASD_SATA_SPINUP_HOLD 2 - - u8 phy_control_0; /* mode 5 reg 0x160 */ - u8 phy_control_1; /* mode 5 reg 0x161 */ - u8 phy_control_2; /* mode 5 reg 0x162 */ - u8 phy_control_3; /* mode 5 reg 0x163 */ -}; - -struct asd_dma_tok { - void *vaddr; - dma_addr_t dma_handle; - size_t size; -}; - -struct hw_profile { - struct bios_struct bios; - struct unit_element_struct ue; - struct flash_struct flash; - - u8 sas_addr[SAS_ADDR_SIZE]; - char pcba_sn[ASD_PCBA_SN_SIZE+1]; - - u8 enabled_phys; /* mask of enabled phys */ - struct asd_phy_desc phy_desc[ASD_MAX_PHYS]; - u32 max_scbs; /* absolute sequencer scb queue size */ - struct asd_dma_tok *scb_ext; - u32 max_ddbs; - struct asd_dma_tok *ddb_ext; - - spinlock_t ddb_lock; - void *ddb_bitmap; - - int num_phys; /* ENABLEABLE */ - int max_phys; /* REPORTED + ENABLEABLE */ - - unsigned addr_range; /* max # of addrs; max # of possible ports */ - unsigned port_name_base; - unsigned dev_name_base; - unsigned sata_name_base; -}; - -struct asd_ascb { - struct list_head list; - struct asd_ha_struct *ha; - - struct scb *scb; /* equals dma_scb->vaddr */ - struct asd_dma_tok dma_scb; - struct asd_dma_tok *sg_arr; - - void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *); - u8 uldd_timer:1; - - /* internally generated command */ - struct timer_list timer; - struct completion *completion; - u8 tag_valid:1; - __be16 tag; /* error recovery only */ - - /* If this is an Empty SCB, index of first edb in seq->edb_arr. */ - int edb_index; - - /* Used by the timer timeout function. */ - int tc_index; - - void *uldd_task; -}; - -#define ASD_DL_SIZE_BITS 0x8 -#define ASD_DL_SIZE (1<<(2+ASD_DL_SIZE_BITS)) -#define ASD_DEF_DL_TOGGLE 0x01 - -struct asd_seq_data { - spinlock_t pend_q_lock; - u16 scbpro; - int pending; - struct list_head pend_q; - int can_queue; /* per adapter */ - struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */ - - spinlock_t tc_index_lock; - void **tc_index_array; - void *tc_index_bitmap; - int tc_index_bitmap_bits; - - struct tasklet_struct dl_tasklet; - struct done_list_struct *dl; /* array of done list entries, equals */ - struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */ - int dl_toggle; - int dl_next; - - int num_edbs; - struct asd_dma_tok **edb_arr; - int num_escbs; - struct asd_ascb **escb_arr; /* array of pointers to escbs */ -}; - -/* This is an internal port structure. These are used to get accurate - * phy_mask for updating DDB 0. - */ -struct asd_port { - u8 sas_addr[SAS_ADDR_SIZE]; - u8 attached_sas_addr[SAS_ADDR_SIZE]; - u32 phy_mask; - int num_phys; -}; - -/* This is the Host Adapter structure. It describes the hardware - * SAS adapter. - */ -struct asd_ha_struct { - struct pci_dev *pcidev; - const char *name; - - struct sas_ha_struct sas_ha; - - u8 revision_id; - - int iospace; - spinlock_t iolock; - struct asd_ha_addrspace io_handle[2]; - - struct hw_profile hw_prof; - - struct asd_phy phys[ASD_MAX_PHYS]; - spinlock_t asd_ports_lock; - struct asd_port asd_ports[ASD_MAX_PHYS]; - struct asd_sas_port ports[ASD_MAX_PHYS]; - - struct dma_pool *scb_pool; - - struct asd_seq_data seq; /* sequencer related */ - u32 bios_status; - const struct firmware *bios_image; -}; - -/* ---------- Common macros ---------- */ - -#define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle)) -#define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8) \ - ? ((u32)((__dma_handle) >> 32)) \ - : ((u32)0)) - -#define dev_to_asd_ha(__dev) pci_get_drvdata(to_pci_dev(__dev)) -#define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF \ - && ((__site_no) & 0xF0FF) > 0x001F) -/* For each bit set in __lseq_mask, set __lseq to equal the bit - * position of the set bit and execute the statement following. - * __mc is the temporary mask, used as a mask "counter". - */ -#define for_each_sequencer(__lseq_mask, __mc, __lseq) \ - for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\ - if (((__mc) & 1)) -#define for_each_phy(__lseq_mask, __mc, __lseq) \ - for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\ - if (((__mc) & 1)) - -#define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I))) - -/* ---------- DMA allocs ---------- */ - -static inline struct asd_dma_tok *asd_dmatok_alloc(gfp_t flags) -{ - return kmem_cache_alloc(asd_dma_token_cache, flags); -} - -static inline void asd_dmatok_free(struct asd_dma_tok *token) -{ - kmem_cache_free(asd_dma_token_cache, token); -} - -static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct * - asd_ha, size_t size, - gfp_t flags) -{ - struct asd_dma_tok *token = asd_dmatok_alloc(flags); - if (token) { - token->size = size; - token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev, - token->size, - &token->dma_handle, - flags); - if (!token->vaddr) { - asd_dmatok_free(token); - token = NULL; - } - } - return token; -} - -static inline void asd_free_coherent(struct asd_ha_struct *asd_ha, - struct asd_dma_tok *token) -{ - if (token) { - dma_free_coherent(&asd_ha->pcidev->dev, token->size, - token->vaddr, token->dma_handle); - asd_dmatok_free(token); - } -} - -static inline void asd_init_ascb(struct asd_ha_struct *asd_ha, - struct asd_ascb *ascb) -{ - INIT_LIST_HEAD(&ascb->list); - ascb->scb = ascb->dma_scb.vaddr; - ascb->ha = asd_ha; - ascb->timer.function = NULL; - init_timer(&ascb->timer); - ascb->tc_index = -1; -} - -/* Must be called with the tc_index_lock held! - */ -static inline void asd_tc_index_release(struct asd_seq_data *seq, int index) -{ - seq->tc_index_array[index] = NULL; - clear_bit(index, seq->tc_index_bitmap); -} - -/* Must be called with the tc_index_lock held! - */ -static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr) -{ - int index; - - index = find_first_zero_bit(seq->tc_index_bitmap, - seq->tc_index_bitmap_bits); - if (index == seq->tc_index_bitmap_bits) - return -1; - - seq->tc_index_array[index] = ptr; - set_bit(index, seq->tc_index_bitmap); - - return index; -} - -/* Must be called with the tc_index_lock held! - */ -static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index) -{ - return seq->tc_index_array[index]; -} - -/** - * asd_ascb_free -- free a single aSCB after is has completed - * @ascb: pointer to the aSCB of interest - * - * This frees an aSCB after it has been executed/completed by - * the sequencer. - */ -static inline void asd_ascb_free(struct asd_ascb *ascb) -{ - if (ascb) { - struct asd_ha_struct *asd_ha = ascb->ha; - unsigned long flags; - - BUG_ON(!list_empty(&ascb->list)); - spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags); - asd_tc_index_release(&ascb->ha->seq, ascb->tc_index); - spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags); - dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr, - ascb->dma_scb.dma_handle); - kmem_cache_free(asd_ascb_cache, ascb); - } -} - -/** - * asd_ascb_list_free -- free a list of ascbs - * @ascb_list: a list of ascbs - * - * This function will free a list of ascbs allocated by asd_ascb_alloc_list. - * It is used when say the scb queueing function returned QUEUE_FULL, - * and we do not need the ascbs any more. - */ -static inline void asd_ascb_free_list(struct asd_ascb *ascb_list) -{ - LIST_HEAD(list); - struct list_head *n, *pos; - - __list_add(&list, ascb_list->list.prev, &ascb_list->list); - list_for_each_safe(pos, n, &list) { - list_del_init(pos); - asd_ascb_free(list_entry(pos, struct asd_ascb, list)); - } -} - -/* ---------- Function declarations ---------- */ - -int asd_init_hw(struct asd_ha_struct *asd_ha); -irqreturn_t asd_hw_isr(int irq, void *dev_id); - - -struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct - *asd_ha, int *num, - gfp_t gfp_mask); - -int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, - int num); -int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, - int num); - -int asd_init_post_escbs(struct asd_ha_struct *asd_ha); -void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc); -void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op); -void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op); -int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask); - -void asd_ascb_timedout(unsigned long data); -int asd_chip_hardrst(struct asd_ha_struct *asd_ha); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_init.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_init.c deleted file mode 100644 index ff80552e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_init.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * Aic94xx SAS/SATA driver initialization. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "aic94xx.h" -#include "aic94xx_reg.h" -#include "aic94xx_hwi.h" -#include "aic94xx_seq.h" -#include "aic94xx_sds.h" - -/* The format is "version.release.patchlevel" */ -#define ASD_DRIVER_VERSION "1.0.3" - -static int use_msi = 0; -module_param_named(use_msi, use_msi, int, S_IRUGO); -MODULE_PARM_DESC(use_msi, "\n" - "\tEnable(1) or disable(0) using PCI MSI.\n" - "\tDefault: 0"); - -static int lldd_max_execute_num = 0; -module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); -MODULE_PARM_DESC(collector, "\n" - "\tIf greater than one, tells the SAS Layer to run in Task Collector\n" - "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n" - "\tThe aic94xx SAS LLDD supports both modes.\n" - "\tDefault: 0 (Direct Mode).\n"); - -static struct scsi_transport_template *aic94xx_transport_template; -static int asd_scan_finished(struct Scsi_Host *, unsigned long); -static void asd_scan_start(struct Scsi_Host *); - -static struct scsi_host_template aic94xx_sht = { - .module = THIS_MODULE, - /* .name is initialized */ - .name = "aic94xx", - .queuecommand = sas_queuecommand, - .target_alloc = sas_target_alloc, - .slave_configure = sas_slave_configure, - .scan_finished = asd_scan_finished, - .scan_start = asd_scan_start, - .change_queue_depth = sas_change_queue_depth, - .change_queue_type = sas_change_queue_type, - .bios_param = sas_bios_param, - .can_queue = 1, - .cmd_per_lun = 1, - .this_id = -1, - .sg_tablesize = SG_ALL, - .max_sectors = SCSI_DEFAULT_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .eh_device_reset_handler = sas_eh_device_reset_handler, - .eh_bus_reset_handler = sas_eh_bus_reset_handler, - .target_destroy = sas_target_destroy, - .ioctl = sas_ioctl, -}; - -static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha) -{ - int err, i; - struct asd_ha_addrspace *io_handle; - - asd_ha->iospace = 0; - for (i = 0; i < 3; i += 2) { - io_handle = &asd_ha->io_handle[i==0?0:1]; - io_handle->start = pci_resource_start(asd_ha->pcidev, i); - io_handle->len = pci_resource_len(asd_ha->pcidev, i); - io_handle->flags = pci_resource_flags(asd_ha->pcidev, i); - err = -ENODEV; - if (!io_handle->start || !io_handle->len) { - asd_printk("MBAR%d start or length for %s is 0.\n", - i==0?0:1, pci_name(asd_ha->pcidev)); - goto Err; - } - err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME); - if (err) { - asd_printk("couldn't reserve memory region for %s\n", - pci_name(asd_ha->pcidev)); - goto Err; - } - if (io_handle->flags & IORESOURCE_CACHEABLE) - io_handle->addr = ioremap(io_handle->start, - io_handle->len); - else - io_handle->addr = ioremap_nocache(io_handle->start, - io_handle->len); - if (!io_handle->addr) { - asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1, - pci_name(asd_ha->pcidev)); - goto Err_unreq; - } - } - - return 0; -Err_unreq: - pci_release_region(asd_ha->pcidev, i); -Err: - if (i > 0) { - io_handle = &asd_ha->io_handle[0]; - iounmap(io_handle->addr); - pci_release_region(asd_ha->pcidev, 0); - } - return err; -} - -static void asd_unmap_memio(struct asd_ha_struct *asd_ha) -{ - struct asd_ha_addrspace *io_handle; - - io_handle = &asd_ha->io_handle[1]; - iounmap(io_handle->addr); - pci_release_region(asd_ha->pcidev, 2); - - io_handle = &asd_ha->io_handle[0]; - iounmap(io_handle->addr); - pci_release_region(asd_ha->pcidev, 0); -} - -static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha) -{ - int i = PCI_IOBAR_OFFSET, err; - struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; - - asd_ha->iospace = 1; - io_handle->start = pci_resource_start(asd_ha->pcidev, i); - io_handle->len = pci_resource_len(asd_ha->pcidev, i); - io_handle->flags = pci_resource_flags(asd_ha->pcidev, i); - io_handle->addr = (void __iomem *) io_handle->start; - if (!io_handle->start || !io_handle->len) { - asd_printk("couldn't get IO ports for %s\n", - pci_name(asd_ha->pcidev)); - return -ENODEV; - } - err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME); - if (err) { - asd_printk("couldn't reserve io space for %s\n", - pci_name(asd_ha->pcidev)); - } - - return err; -} - -static void asd_unmap_ioport(struct asd_ha_struct *asd_ha) -{ - pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET); -} - -static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha) -{ - int err; - u16 cmd_reg; - - err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg); - if (err) { - asd_printk("couldn't read command register of %s\n", - pci_name(asd_ha->pcidev)); - goto Err; - } - - err = -ENODEV; - if (cmd_reg & PCI_COMMAND_MEMORY) { - if ((err = asd_map_memio(asd_ha))) - goto Err; - } else if (cmd_reg & PCI_COMMAND_IO) { - if ((err = asd_map_ioport(asd_ha))) - goto Err; - asd_printk("%s ioport mapped -- upgrade your hardware\n", - pci_name(asd_ha->pcidev)); - } else { - asd_printk("no proper device access to %s\n", - pci_name(asd_ha->pcidev)); - goto Err; - } - - return 0; -Err: - return err; -} - -static void asd_unmap_ha(struct asd_ha_struct *asd_ha) -{ - if (asd_ha->iospace) - asd_unmap_ioport(asd_ha); - else - asd_unmap_memio(asd_ha); -} - -static const char *asd_dev_rev[30] = { - [0] = "A0", - [1] = "A1", - [8] = "B0", -}; - -static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha) -{ - int err, i; - - asd_ha->revision_id = asd_ha->pcidev->revision; - - err = -ENODEV; - if (asd_ha->revision_id < AIC9410_DEV_REV_B0) { - asd_printk("%s is revision %s (%X), which is not supported\n", - pci_name(asd_ha->pcidev), - asd_dev_rev[asd_ha->revision_id], - asd_ha->revision_id); - goto Err; - } - /* Provide some sane default values. */ - asd_ha->hw_prof.max_scbs = 512; - asd_ha->hw_prof.max_ddbs = ASD_MAX_DDBS; - asd_ha->hw_prof.num_phys = ASD_MAX_PHYS; - /* All phys are enabled, by default. */ - asd_ha->hw_prof.enabled_phys = 0xFF; - for (i = 0; i < ASD_MAX_PHYS; i++) { - asd_ha->hw_prof.phy_desc[i].max_sas_lrate = - SAS_LINK_RATE_3_0_GBPS; - asd_ha->hw_prof.phy_desc[i].min_sas_lrate = - SAS_LINK_RATE_1_5_GBPS; - asd_ha->hw_prof.phy_desc[i].max_sata_lrate = - SAS_LINK_RATE_1_5_GBPS; - asd_ha->hw_prof.phy_desc[i].min_sata_lrate = - SAS_LINK_RATE_1_5_GBPS; - } - - return 0; -Err: - return err; -} - -static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha) -{ - int err = asd_common_setup(asd_ha); - - if (err) - return err; - - asd_ha->hw_prof.addr_range = 8; - asd_ha->hw_prof.port_name_base = 0; - asd_ha->hw_prof.dev_name_base = 8; - asd_ha->hw_prof.sata_name_base = 16; - - return 0; -} - -static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha) -{ - int err = asd_common_setup(asd_ha); - - if (err) - return err; - - asd_ha->hw_prof.addr_range = 4; - asd_ha->hw_prof.port_name_base = 0; - asd_ha->hw_prof.dev_name_base = 4; - asd_ha->hw_prof.sata_name_base = 8; - - return 0; -} - -static ssize_t asd_show_dev_rev(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", - asd_dev_rev[asd_ha->revision_id]); -} -static DEVICE_ATTR(revision, S_IRUGO, asd_show_dev_rev, NULL); - -static ssize_t asd_show_dev_bios_build(struct device *dev, - struct device_attribute *attr,char *buf) -{ - struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld); -} -static DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL); - -static ssize_t asd_show_dev_pcba_sn(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); - return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn); -} -static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL); - -#define FLASH_CMD_NONE 0x00 -#define FLASH_CMD_UPDATE 0x01 -#define FLASH_CMD_VERIFY 0x02 - -struct flash_command { - u8 command[8]; - int code; -}; - -static struct flash_command flash_command_table[] = -{ - {"verify", FLASH_CMD_VERIFY}, - {"update", FLASH_CMD_UPDATE}, - {"", FLASH_CMD_NONE} /* Last entry should be NULL. */ -}; - -struct error_bios { - char *reason; - int err_code; -}; - -static struct error_bios flash_error_table[] = -{ - {"Failed to open bios image file", FAIL_OPEN_BIOS_FILE}, - {"PCI ID mismatch", FAIL_CHECK_PCI_ID}, - {"Checksum mismatch", FAIL_CHECK_SUM}, - {"Unknown Error", FAIL_UNKNOWN}, - {"Failed to verify.", FAIL_VERIFY}, - {"Failed to reset flash chip.", FAIL_RESET_FLASH}, - {"Failed to find flash chip type.", FAIL_FIND_FLASH_ID}, - {"Failed to erash flash chip.", FAIL_ERASE_FLASH}, - {"Failed to program flash chip.", FAIL_WRITE_FLASH}, - {"Flash in progress", FLASH_IN_PROGRESS}, - {"Image file size Error", FAIL_FILE_SIZE}, - {"Input parameter error", FAIL_PARAMETERS}, - {"Out of memory", FAIL_OUT_MEMORY}, - {"OK", 0} /* Last entry err_code = 0. */ -}; - -static ssize_t asd_store_update_bios(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); - char *cmd_ptr, *filename_ptr; - struct bios_file_header header, *hdr_ptr; - int res, i; - u32 csum = 0; - int flash_command = FLASH_CMD_NONE; - int err = 0; - - cmd_ptr = kzalloc(count*2, GFP_KERNEL); - - if (!cmd_ptr) { - err = FAIL_OUT_MEMORY; - goto out; - } - - filename_ptr = cmd_ptr + count; - res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); - if (res != 2) { - err = FAIL_PARAMETERS; - goto out1; - } - - for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { - if (!memcmp(flash_command_table[i].command, - cmd_ptr, strlen(cmd_ptr))) { - flash_command = flash_command_table[i].code; - break; - } - } - if (flash_command == FLASH_CMD_NONE) { - err = FAIL_PARAMETERS; - goto out1; - } - - if (asd_ha->bios_status == FLASH_IN_PROGRESS) { - err = FLASH_IN_PROGRESS; - goto out1; - } - err = request_firmware(&asd_ha->bios_image, - filename_ptr, - &asd_ha->pcidev->dev); - if (err) { - asd_printk("Failed to load bios image file %s, error %d\n", - filename_ptr, err); - err = FAIL_OPEN_BIOS_FILE; - goto out1; - } - - hdr_ptr = (struct bios_file_header *)asd_ha->bios_image->data; - - if ((hdr_ptr->contrl_id.vendor != asd_ha->pcidev->vendor || - hdr_ptr->contrl_id.device != asd_ha->pcidev->device) && - (hdr_ptr->contrl_id.sub_vendor != asd_ha->pcidev->vendor || - hdr_ptr->contrl_id.sub_device != asd_ha->pcidev->device)) { - - ASD_DPRINTK("The PCI vendor or device id does not match\n"); - ASD_DPRINTK("vendor=%x dev=%x sub_vendor=%x sub_dev=%x" - " pci vendor=%x pci dev=%x\n", - hdr_ptr->contrl_id.vendor, - hdr_ptr->contrl_id.device, - hdr_ptr->contrl_id.sub_vendor, - hdr_ptr->contrl_id.sub_device, - asd_ha->pcidev->vendor, - asd_ha->pcidev->device); - err = FAIL_CHECK_PCI_ID; - goto out2; - } - - if (hdr_ptr->filelen != asd_ha->bios_image->size) { - err = FAIL_FILE_SIZE; - goto out2; - } - - /* calculate checksum */ - for (i = 0; i < hdr_ptr->filelen; i++) - csum += asd_ha->bios_image->data[i]; - - if ((csum & 0x0000ffff) != hdr_ptr->checksum) { - ASD_DPRINTK("BIOS file checksum mismatch\n"); - err = FAIL_CHECK_SUM; - goto out2; - } - if (flash_command == FLASH_CMD_UPDATE) { - asd_ha->bios_status = FLASH_IN_PROGRESS; - err = asd_write_flash_seg(asd_ha, - &asd_ha->bios_image->data[sizeof(*hdr_ptr)], - 0, hdr_ptr->filelen-sizeof(*hdr_ptr)); - if (!err) - err = asd_verify_flash_seg(asd_ha, - &asd_ha->bios_image->data[sizeof(*hdr_ptr)], - 0, hdr_ptr->filelen-sizeof(*hdr_ptr)); - } else { - asd_ha->bios_status = FLASH_IN_PROGRESS; - err = asd_verify_flash_seg(asd_ha, - &asd_ha->bios_image->data[sizeof(header)], - 0, hdr_ptr->filelen-sizeof(header)); - } - -out2: - release_firmware(asd_ha->bios_image); -out1: - kfree(cmd_ptr); -out: - asd_ha->bios_status = err; - - if (!err) - return count; - else - return -err; -} - -static ssize_t asd_show_update_bios(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int i; - struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); - - for (i = 0; flash_error_table[i].err_code != 0; i++) { - if (flash_error_table[i].err_code == asd_ha->bios_status) - break; - } - if (asd_ha->bios_status != FLASH_IN_PROGRESS) - asd_ha->bios_status = FLASH_OK; - - return snprintf(buf, PAGE_SIZE, "status=%x %s\n", - flash_error_table[i].err_code, - flash_error_table[i].reason); -} - -static DEVICE_ATTR(update_bios, S_IRUGO|S_IWUSR, - asd_show_update_bios, asd_store_update_bios); - -static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha) -{ - int err; - - err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision); - if (err) - return err; - - err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); - if (err) - goto err_rev; - - err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); - if (err) - goto err_biosb; - err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_update_bios); - if (err) - goto err_update_bios; - - return 0; - -err_update_bios: - device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); -err_biosb: - device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); -err_rev: - device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision); - return err; -} - -static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha) -{ - device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision); - device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); - device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); - device_remove_file(&asd_ha->pcidev->dev, &dev_attr_update_bios); -} - -/* The first entry, 0, is used for dynamic ids, the rest for devices - * we know about. - */ -static const struct asd_pcidev_struct { - const char * name; - int (*setup)(struct asd_ha_struct *asd_ha); -} asd_pcidev_data[] __devinitconst = { - /* Id 0 is used for dynamic ids. */ - { .name = "Adaptec AIC-94xx SAS/SATA Host Adapter", - .setup = asd_aic9410_setup - }, - { .name = "Adaptec AIC-9410W SAS/SATA Host Adapter", - .setup = asd_aic9410_setup - }, - { .name = "Adaptec AIC-9405W SAS/SATA Host Adapter", - .setup = asd_aic9405_setup - }, -}; - -static int asd_create_ha_caches(struct asd_ha_struct *asd_ha) -{ - asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool", - &asd_ha->pcidev->dev, - sizeof(struct scb), - 8, 0); - if (!asd_ha->scb_pool) { - asd_printk("couldn't create scb pool\n"); - return -ENOMEM; - } - - return 0; -} - -/** - * asd_free_edbs -- free empty data buffers - * asd_ha: pointer to host adapter structure - */ -static void asd_free_edbs(struct asd_ha_struct *asd_ha) -{ - struct asd_seq_data *seq = &asd_ha->seq; - int i; - - for (i = 0; i < seq->num_edbs; i++) - asd_free_coherent(asd_ha, seq->edb_arr[i]); - kfree(seq->edb_arr); - seq->edb_arr = NULL; -} - -static void asd_free_escbs(struct asd_ha_struct *asd_ha) -{ - struct asd_seq_data *seq = &asd_ha->seq; - int i; - - for (i = 0; i < seq->num_escbs; i++) { - if (!list_empty(&seq->escb_arr[i]->list)) - list_del_init(&seq->escb_arr[i]->list); - - asd_ascb_free(seq->escb_arr[i]); - } - kfree(seq->escb_arr); - seq->escb_arr = NULL; -} - -static void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha) -{ - int i; - - if (asd_ha->hw_prof.ddb_ext) - asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext); - if (asd_ha->hw_prof.scb_ext) - asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext); - - if (asd_ha->hw_prof.ddb_bitmap) - kfree(asd_ha->hw_prof.ddb_bitmap); - asd_ha->hw_prof.ddb_bitmap = NULL; - - for (i = 0; i < ASD_MAX_PHYS; i++) { - struct asd_phy *phy = &asd_ha->phys[i]; - - asd_free_coherent(asd_ha, phy->id_frm_tok); - } - if (asd_ha->seq.escb_arr) - asd_free_escbs(asd_ha); - if (asd_ha->seq.edb_arr) - asd_free_edbs(asd_ha); - if (asd_ha->hw_prof.ue.area) { - kfree(asd_ha->hw_prof.ue.area); - asd_ha->hw_prof.ue.area = NULL; - } - if (asd_ha->seq.tc_index_array) { - kfree(asd_ha->seq.tc_index_array); - kfree(asd_ha->seq.tc_index_bitmap); - asd_ha->seq.tc_index_array = NULL; - asd_ha->seq.tc_index_bitmap = NULL; - } - if (asd_ha->seq.actual_dl) { - asd_free_coherent(asd_ha, asd_ha->seq.actual_dl); - asd_ha->seq.actual_dl = NULL; - asd_ha->seq.dl = NULL; - } - if (asd_ha->seq.next_scb.vaddr) { - dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr, - asd_ha->seq.next_scb.dma_handle); - asd_ha->seq.next_scb.vaddr = NULL; - } - dma_pool_destroy(asd_ha->scb_pool); - asd_ha->scb_pool = NULL; -} - -struct kmem_cache *asd_dma_token_cache; -struct kmem_cache *asd_ascb_cache; - -static int asd_create_global_caches(void) -{ - if (!asd_dma_token_cache) { - asd_dma_token_cache - = kmem_cache_create(ASD_DRIVER_NAME "_dma_token", - sizeof(struct asd_dma_tok), - 0, - SLAB_HWCACHE_ALIGN, - NULL); - if (!asd_dma_token_cache) { - asd_printk("couldn't create dma token cache\n"); - return -ENOMEM; - } - } - - if (!asd_ascb_cache) { - asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb", - sizeof(struct asd_ascb), - 0, - SLAB_HWCACHE_ALIGN, - NULL); - if (!asd_ascb_cache) { - asd_printk("couldn't create ascb cache\n"); - goto Err; - } - } - - return 0; -Err: - kmem_cache_destroy(asd_dma_token_cache); - asd_dma_token_cache = NULL; - return -ENOMEM; -} - -static void asd_destroy_global_caches(void) -{ - if (asd_dma_token_cache) - kmem_cache_destroy(asd_dma_token_cache); - asd_dma_token_cache = NULL; - - if (asd_ascb_cache) - kmem_cache_destroy(asd_ascb_cache); - asd_ascb_cache = NULL; -} - -static int asd_register_sas_ha(struct asd_ha_struct *asd_ha) -{ - int i; - struct asd_sas_phy **sas_phys = - kcalloc(ASD_MAX_PHYS, sizeof(*sas_phys), GFP_KERNEL); - struct asd_sas_port **sas_ports = - kcalloc(ASD_MAX_PHYS, sizeof(*sas_ports), GFP_KERNEL); - - if (!sas_phys || !sas_ports) { - kfree(sas_phys); - kfree(sas_ports); - return -ENOMEM; - } - - asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name; - asd_ha->sas_ha.lldd_module = THIS_MODULE; - asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0]; - - for (i = 0; i < ASD_MAX_PHYS; i++) { - sas_phys[i] = &asd_ha->phys[i].sas_phy; - sas_ports[i] = &asd_ha->ports[i]; - } - - asd_ha->sas_ha.sas_phy = sas_phys; - asd_ha->sas_ha.sas_port= sas_ports; - asd_ha->sas_ha.num_phys= ASD_MAX_PHYS; - - asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue; - asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; - - return sas_register_ha(&asd_ha->sas_ha); -} - -static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha) -{ - int err; - - err = sas_unregister_ha(&asd_ha->sas_ha); - - sas_remove_host(asd_ha->sas_ha.core.shost); - scsi_remove_host(asd_ha->sas_ha.core.shost); - scsi_host_put(asd_ha->sas_ha.core.shost); - - kfree(asd_ha->sas_ha.sas_phy); - kfree(asd_ha->sas_ha.sas_port); - - return err; -} - -static int __devinit asd_pci_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - const struct asd_pcidev_struct *asd_dev; - unsigned asd_id = (unsigned) id->driver_data; - struct asd_ha_struct *asd_ha; - struct Scsi_Host *shost; - int err; - - if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) { - asd_printk("wrong driver_data in PCI table\n"); - return -ENODEV; - } - - if ((err = pci_enable_device(dev))) { - asd_printk("couldn't enable device %s\n", pci_name(dev)); - return err; - } - - pci_set_master(dev); - - err = -ENOMEM; - - shost = scsi_host_alloc(&aic94xx_sht, sizeof(void *)); - if (!shost) - goto Err; - - asd_dev = &asd_pcidev_data[asd_id]; - - asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL); - if (!asd_ha) { - asd_printk("out of memory\n"); - goto Err_put; - } - asd_ha->pcidev = dev; - asd_ha->sas_ha.dev = &asd_ha->pcidev->dev; - asd_ha->sas_ha.lldd_ha = asd_ha; - - asd_ha->bios_status = FLASH_OK; - asd_ha->name = asd_dev->name; - asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev)); - - SHOST_TO_SAS_HA(shost) = &asd_ha->sas_ha; - asd_ha->sas_ha.core.shost = shost; - shost->transportt = aic94xx_transport_template; - shost->max_id = ~0; - shost->max_lun = ~0; - shost->max_cmd_len = 16; - - err = scsi_add_host(shost, &dev->dev); - if (err) - goto Err_free; - - err = asd_dev->setup(asd_ha); - if (err) - goto Err_remove; - - err = -ENODEV; - if (!pci_set_dma_mask(dev, DMA_BIT_MASK(64)) - && !pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(64))) - ; - else if (!pci_set_dma_mask(dev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(dev, DMA_BIT_MASK(32))) - ; - else { - asd_printk("no suitable DMA mask for %s\n", pci_name(dev)); - goto Err_remove; - } - - pci_set_drvdata(dev, asd_ha); - - err = asd_map_ha(asd_ha); - if (err) - goto Err_remove; - - err = asd_create_ha_caches(asd_ha); - if (err) - goto Err_unmap; - - err = asd_init_hw(asd_ha); - if (err) - goto Err_free_cache; - - asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled " - "phys, flash %s, BIOS %s%d\n", - pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr), - asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys, - asd_ha->hw_prof.num_phys, - asd_ha->hw_prof.flash.present ? "present" : "not present", - asd_ha->hw_prof.bios.present ? "build " : "not present", - asd_ha->hw_prof.bios.bld); - - shost->can_queue = asd_ha->seq.can_queue; - - if (use_msi) - pci_enable_msi(asd_ha->pcidev); - - err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, IRQF_SHARED, - ASD_DRIVER_NAME, asd_ha); - if (err) { - asd_printk("couldn't get irq %d for %s\n", - asd_ha->pcidev->irq, pci_name(asd_ha->pcidev)); - goto Err_irq; - } - asd_enable_ints(asd_ha); - - err = asd_init_post_escbs(asd_ha); - if (err) { - asd_printk("couldn't post escbs for %s\n", - pci_name(asd_ha->pcidev)); - goto Err_escbs; - } - ASD_DPRINTK("escbs posted\n"); - - err = asd_create_dev_attrs(asd_ha); - if (err) - goto Err_dev_attrs; - - err = asd_register_sas_ha(asd_ha); - if (err) - goto Err_reg_sas; - - scsi_scan_host(shost); - - return 0; - -Err_reg_sas: - asd_remove_dev_attrs(asd_ha); -Err_dev_attrs: -Err_escbs: - asd_disable_ints(asd_ha); - free_irq(dev->irq, asd_ha); -Err_irq: - if (use_msi) - pci_disable_msi(dev); - asd_chip_hardrst(asd_ha); -Err_free_cache: - asd_destroy_ha_caches(asd_ha); -Err_unmap: - asd_unmap_ha(asd_ha); -Err_remove: - scsi_remove_host(shost); -Err_free: - kfree(asd_ha); -Err_put: - scsi_host_put(shost); -Err: - pci_disable_device(dev); - return err; -} - -static void asd_free_queues(struct asd_ha_struct *asd_ha) -{ - unsigned long flags; - LIST_HEAD(pending); - struct list_head *n, *pos; - - spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); - asd_ha->seq.pending = 0; - list_splice_init(&asd_ha->seq.pend_q, &pending); - spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); - - if (!list_empty(&pending)) - ASD_DPRINTK("Uh-oh! Pending is not empty!\n"); - - list_for_each_safe(pos, n, &pending) { - struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list); - /* - * Delete unexpired ascb timers. This may happen if we issue - * a CONTROL PHY scb to an adapter and rmmod before the scb - * times out. Apparently we don't wait for the CONTROL PHY - * to complete, so it doesn't matter if we kill the timer. - */ - del_timer_sync(&ascb->timer); - WARN_ON(ascb->scb->header.opcode != CONTROL_PHY); - - list_del_init(pos); - ASD_DPRINTK("freeing from pending\n"); - asd_ascb_free(ascb); - } -} - -static void asd_turn_off_leds(struct asd_ha_struct *asd_ha) -{ - u8 phy_mask = asd_ha->hw_prof.enabled_phys; - u8 i; - - for_each_phy(phy_mask, phy_mask, i) { - asd_turn_led(asd_ha, i, 0); - asd_control_led(asd_ha, i, 0); - } -} - -static void __devexit asd_pci_remove(struct pci_dev *dev) -{ - struct asd_ha_struct *asd_ha = pci_get_drvdata(dev); - - if (!asd_ha) - return; - - asd_unregister_sas_ha(asd_ha); - - asd_disable_ints(asd_ha); - - asd_remove_dev_attrs(asd_ha); - - /* XXX more here as needed */ - - free_irq(dev->irq, asd_ha); - if (use_msi) - pci_disable_msi(asd_ha->pcidev); - asd_turn_off_leds(asd_ha); - asd_chip_hardrst(asd_ha); - asd_free_queues(asd_ha); - asd_destroy_ha_caches(asd_ha); - asd_unmap_ha(asd_ha); - kfree(asd_ha); - pci_disable_device(dev); - return; -} - -static void asd_scan_start(struct Scsi_Host *shost) -{ - struct asd_ha_struct *asd_ha; - int err; - - asd_ha = SHOST_TO_SAS_HA(shost)->lldd_ha; - err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys); - if (err) - asd_printk("Couldn't enable phys, err:%d\n", err); -} - -static int asd_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - /* give the phy enabling interrupt event time to come in (1s - * is empirically about all it takes) */ - if (time < HZ) - return 0; - /* Wait for discovery to finish */ - sas_drain_work(SHOST_TO_SAS_HA(shost)); - return 1; -} - -static ssize_t asd_version_show(struct device_driver *driver, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION); -} -static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL); - -static int asd_create_driver_attrs(struct device_driver *driver) -{ - return driver_create_file(driver, &driver_attr_version); -} - -static void asd_remove_driver_attrs(struct device_driver *driver) -{ - driver_remove_file(driver, &driver_attr_version); -} - -static struct sas_domain_function_template aic94xx_transport_functions = { - .lldd_dev_found = asd_dev_found, - .lldd_dev_gone = asd_dev_gone, - - .lldd_execute_task = asd_execute_task, - - .lldd_abort_task = asd_abort_task, - .lldd_abort_task_set = asd_abort_task_set, - .lldd_clear_aca = asd_clear_aca, - .lldd_clear_task_set = asd_clear_task_set, - .lldd_I_T_nexus_reset = asd_I_T_nexus_reset, - .lldd_lu_reset = asd_lu_reset, - .lldd_query_task = asd_query_task, - - .lldd_clear_nexus_port = asd_clear_nexus_port, - .lldd_clear_nexus_ha = asd_clear_nexus_ha, - - .lldd_control_phy = asd_control_phy, - - .lldd_ata_set_dmamode = asd_set_dmamode, -}; - -static const struct pci_device_id aic94xx_pci_table[] __devinitdata = { - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x410),0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x412),0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x416),0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41E),0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x41F),0, 0, 1}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x430),0, 0, 2}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x432),0, 0, 2}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43E),0, 0, 2}, - {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x43F),0, 0, 2}, - {} -}; - -MODULE_DEVICE_TABLE(pci, aic94xx_pci_table); - -static struct pci_driver aic94xx_pci_driver = { - .name = ASD_DRIVER_NAME, - .id_table = aic94xx_pci_table, - .probe = asd_pci_probe, - .remove = __devexit_p(asd_pci_remove), -}; - -static int __init aic94xx_init(void) -{ - int err; - - - asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION, - ASD_DRIVER_VERSION); - - err = asd_create_global_caches(); - if (err) - return err; - - aic94xx_transport_template = - sas_domain_attach_transport(&aic94xx_transport_functions); - if (!aic94xx_transport_template) - goto out_destroy_caches; - - err = pci_register_driver(&aic94xx_pci_driver); - if (err) - goto out_release_transport; - - err = asd_create_driver_attrs(&aic94xx_pci_driver.driver); - if (err) - goto out_unregister_pcidrv; - - return err; - - out_unregister_pcidrv: - pci_unregister_driver(&aic94xx_pci_driver); - out_release_transport: - sas_release_transport(aic94xx_transport_template); - out_destroy_caches: - asd_destroy_global_caches(); - - return err; -} - -static void __exit aic94xx_exit(void) -{ - asd_remove_driver_attrs(&aic94xx_pci_driver.driver); - pci_unregister_driver(&aic94xx_pci_driver); - sas_release_transport(aic94xx_transport_template); - asd_release_firmware(); - asd_destroy_global_caches(); - asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION, - ASD_DRIVER_VERSION); -} - -module_init(aic94xx_init); -module_exit(aic94xx_exit); - -MODULE_AUTHOR("Luben Tuikov "); -MODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(ASD_DRIVER_VERSION); diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.c deleted file mode 100644 index 56b17c22..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Aic94xx SAS/SATA driver register access. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include "aic94xx_reg.h" -#include "aic94xx.h" - -/* Writing to device address space. - * Offset comes before value to remind that the operation of - * this function is *offs = val. - */ -static void asd_write_byte(struct asd_ha_struct *asd_ha, - unsigned long offs, u8 val) -{ - if (unlikely(asd_ha->iospace)) - outb(val, - (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF)); - else - writeb(val, asd_ha->io_handle[0].addr + offs); - wmb(); -} - -static void asd_write_word(struct asd_ha_struct *asd_ha, - unsigned long offs, u16 val) -{ - if (unlikely(asd_ha->iospace)) - outw(val, - (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF)); - else - writew(val, asd_ha->io_handle[0].addr + offs); - wmb(); -} - -static void asd_write_dword(struct asd_ha_struct *asd_ha, - unsigned long offs, u32 val) -{ - if (unlikely(asd_ha->iospace)) - outl(val, - (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF)); - else - writel(val, asd_ha->io_handle[0].addr + offs); - wmb(); -} - -/* Reading from device address space. - */ -static u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs) -{ - u8 val; - if (unlikely(asd_ha->iospace)) - val = inb((unsigned long) asd_ha->io_handle[0].addr - + (offs & 0xFF)); - else - val = readb(asd_ha->io_handle[0].addr + offs); - rmb(); - return val; -} - -static u16 asd_read_word(struct asd_ha_struct *asd_ha, - unsigned long offs) -{ - u16 val; - if (unlikely(asd_ha->iospace)) - val = inw((unsigned long)asd_ha->io_handle[0].addr - + (offs & 0xFF)); - else - val = readw(asd_ha->io_handle[0].addr + offs); - rmb(); - return val; -} - -static u32 asd_read_dword(struct asd_ha_struct *asd_ha, - unsigned long offs) -{ - u32 val; - if (unlikely(asd_ha->iospace)) - val = inl((unsigned long) asd_ha->io_handle[0].addr - + (offs & 0xFF)); - else - val = readl(asd_ha->io_handle[0].addr + offs); - rmb(); - return val; -} - -static inline u32 asd_mem_offs_swa(void) -{ - return 0; -} - -static inline u32 asd_mem_offs_swc(void) -{ - return asd_mem_offs_swa() + MBAR0_SWA_SIZE; -} - -static inline u32 asd_mem_offs_swb(void) -{ - return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20; -} - -/* We know that the register wanted is in the range - * of the sliding window. - */ -#define ASD_READ_SW(ww, type, ord) \ -static type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha, \ - u32 reg) \ -{ \ - struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ - u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\ - return asd_read_##ord(asd_ha, (unsigned long)map_offs); \ -} - -#define ASD_WRITE_SW(ww, type, ord) \ -static void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha, \ - u32 reg, type val) \ -{ \ - struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ - u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\ - asd_write_##ord(asd_ha, (unsigned long)map_offs, val); \ -} - -ASD_READ_SW(swa, u8, byte); -ASD_READ_SW(swa, u16, word); -ASD_READ_SW(swa, u32, dword); - -ASD_READ_SW(swb, u8, byte); -ASD_READ_SW(swb, u16, word); -ASD_READ_SW(swb, u32, dword); - -ASD_READ_SW(swc, u8, byte); -ASD_READ_SW(swc, u16, word); -ASD_READ_SW(swc, u32, dword); - -ASD_WRITE_SW(swa, u8, byte); -ASD_WRITE_SW(swa, u16, word); -ASD_WRITE_SW(swa, u32, dword); - -ASD_WRITE_SW(swb, u8, byte); -ASD_WRITE_SW(swb, u16, word); -ASD_WRITE_SW(swb, u32, dword); - -ASD_WRITE_SW(swc, u8, byte); -ASD_WRITE_SW(swc, u16, word); -ASD_WRITE_SW(swc, u32, dword); - -/* - * A word about sliding windows: - * MBAR0 is divided into sliding windows A, C and B, in that order. - * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes. - * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes. - * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F. - * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0. - * See asd_init_sw() in aic94xx_hwi.c - * - * We map the most common registers we'd access of the internal 4GB - * host adapter memory space. If a register/internal memory location - * is wanted which is not mapped, we slide SWB, by paging it, - * see asd_move_swb() in aic94xx_reg.c. - */ - -/** - * asd_move_swb -- move sliding window B - * @asd_ha: pointer to host adapter structure - * @reg: register desired to be within range of the new window - */ -static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg) -{ - u32 base = reg & ~(MBAR0_SWB_SIZE-1); - pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base); - asd_ha->io_handle[0].swb_base = base; -} - -static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val) -{ - struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; - BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); - if (io_handle->swa_base <= reg - && reg < io_handle->swa_base + MBAR0_SWA_SIZE) - asd_write_swa_byte (asd_ha, reg,val); - else if (io_handle->swb_base <= reg - && reg < io_handle->swb_base + MBAR0_SWB_SIZE) - asd_write_swb_byte (asd_ha, reg, val); - else if (io_handle->swc_base <= reg - && reg < io_handle->swc_base + MBAR0_SWC_SIZE) - asd_write_swc_byte (asd_ha, reg, val); - else { - /* Ok, we have to move SWB */ - asd_move_swb(asd_ha, reg); - asd_write_swb_byte (asd_ha, reg, val); - } -} - -#define ASD_WRITE_REG(type, ord) \ -void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\ -{ \ - struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \ - unsigned long flags; \ - BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \ - spin_lock_irqsave(&asd_ha->iolock, flags); \ - if (io_handle->swa_base <= reg \ - && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \ - asd_write_swa_##ord (asd_ha, reg,val); \ - else if (io_handle->swb_base <= reg \ - && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \ - asd_write_swb_##ord (asd_ha, reg, val); \ - else if (io_handle->swc_base <= reg \ - && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \ - asd_write_swc_##ord (asd_ha, reg, val); \ - else { \ - /* Ok, we have to move SWB */ \ - asd_move_swb(asd_ha, reg); \ - asd_write_swb_##ord (asd_ha, reg, val); \ - } \ - spin_unlock_irqrestore(&asd_ha->iolock, flags); \ -} - -ASD_WRITE_REG(u8, byte); -ASD_WRITE_REG(u16,word); -ASD_WRITE_REG(u32,dword); - -static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg) -{ - struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; - u8 val; - BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); - if (io_handle->swa_base <= reg - && reg < io_handle->swa_base + MBAR0_SWA_SIZE) - val = asd_read_swa_byte (asd_ha, reg); - else if (io_handle->swb_base <= reg - && reg < io_handle->swb_base + MBAR0_SWB_SIZE) - val = asd_read_swb_byte (asd_ha, reg); - else if (io_handle->swc_base <= reg - && reg < io_handle->swc_base + MBAR0_SWC_SIZE) - val = asd_read_swc_byte (asd_ha, reg); - else { - /* Ok, we have to move SWB */ - asd_move_swb(asd_ha, reg); - val = asd_read_swb_byte (asd_ha, reg); - } - return val; -} - -#define ASD_READ_REG(type, ord) \ -type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \ -{ \ - struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \ - type val; \ - unsigned long flags; \ - BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \ - spin_lock_irqsave(&asd_ha->iolock, flags); \ - if (io_handle->swa_base <= reg \ - && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \ - val = asd_read_swa_##ord (asd_ha, reg); \ - else if (io_handle->swb_base <= reg \ - && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \ - val = asd_read_swb_##ord (asd_ha, reg); \ - else if (io_handle->swc_base <= reg \ - && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \ - val = asd_read_swc_##ord (asd_ha, reg); \ - else { \ - /* Ok, we have to move SWB */ \ - asd_move_swb(asd_ha, reg); \ - val = asd_read_swb_##ord (asd_ha, reg); \ - } \ - spin_unlock_irqrestore(&asd_ha->iolock, flags); \ - return val; \ -} - -ASD_READ_REG(u8, byte); -ASD_READ_REG(u16,word); -ASD_READ_REG(u32,dword); - -/** - * asd_read_reg_string -- read a string of bytes from io space memory - * @asd_ha: pointer to host adapter structure - * @dst: pointer to a destination buffer where data will be written to - * @offs: start offset (register) to read from - * @count: number of bytes to read - */ -void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst, - u32 offs, int count) -{ - u8 *p = dst; - unsigned long flags; - - spin_lock_irqsave(&asd_ha->iolock, flags); - for ( ; count > 0; count--, offs++, p++) - *p = __asd_read_reg_byte(asd_ha, offs); - spin_unlock_irqrestore(&asd_ha->iolock, flags); -} - -/** - * asd_write_reg_string -- write a string of bytes to io space memory - * @asd_ha: pointer to host adapter structure - * @src: pointer to source buffer where data will be read from - * @offs: start offset (register) to write to - * @count: number of bytes to write - */ -void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src, - u32 offs, int count) -{ - u8 *p = src; - unsigned long flags; - - spin_lock_irqsave(&asd_ha->iolock, flags); - for ( ; count > 0; count--, offs++, p++) - __asd_write_reg_byte(asd_ha, offs, *p); - spin_unlock_irqrestore(&asd_ha->iolock, flags); -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.h b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.h deleted file mode 100644 index 2279307f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Aic94xx SAS/SATA driver hardware registers definitions. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef _AIC94XX_REG_H_ -#define _AIC94XX_REG_H_ - -#include -#include "aic94xx_hwi.h" - -/* Values */ -#define AIC9410_DEV_REV_B0 0x8 - -/* MBAR0, SWA, SWB, SWC, internal memory space addresses */ -#define REG_BASE_ADDR 0xB8000000 -#define REG_BASE_ADDR_CSEQCIO 0xB8002000 -#define REG_BASE_ADDR_EXSI 0xB8042800 - -#define MBAR0_SWA_SIZE 0x58 -extern u32 MBAR0_SWB_SIZE; -#define MBAR0_SWC_SIZE 0x8 - -/* MBAR1, points to On Chip Memory */ -#define OCM_BASE_ADDR 0xA0000000 -#define OCM_MAX_SIZE 0x20000 - -/* Smallest address possible to reference */ -#define ALL_BASE_ADDR OCM_BASE_ADDR - -/* PCI configuration space registers */ -#define PCI_IOBAR_OFFSET 4 - -#define PCI_CONF_MBAR1 0x6C -#define PCI_CONF_MBAR0_SWA 0x70 -#define PCI_CONF_MBAR0_SWB 0x74 -#define PCI_CONF_MBAR0_SWC 0x78 -#define PCI_CONF_MBAR_KEY 0x7C -#define PCI_CONF_FLSH_BAR 0xB8 - -#include "aic94xx_reg_def.h" - -u8 asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg); -u16 asd_read_reg_word(struct asd_ha_struct *asd_ha, u32 reg); -u32 asd_read_reg_dword(struct asd_ha_struct *asd_ha, u32 reg); - -void asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val); -void asd_write_reg_word(struct asd_ha_struct *asd_ha, u32 reg, u16 val); -void asd_write_reg_dword(struct asd_ha_struct *asd_ha, u32 reg, u32 val); - -void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst, - u32 offs, int count); -void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src, - u32 offs, int count); - -#define ASD_READ_OCM(type, ord, S) \ -static inline type asd_read_ocm_##ord (struct asd_ha_struct *asd_ha, \ - u32 offs) \ -{ \ - struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \ - type val = read##S (io_handle->addr + (unsigned long) offs); \ - rmb(); \ - return val; \ -} - -ASD_READ_OCM(u8, byte, b); -ASD_READ_OCM(u16,word, w); -ASD_READ_OCM(u32,dword,l); - -#define ASD_WRITE_OCM(type, ord, S) \ -static inline void asd_write_ocm_##ord (struct asd_ha_struct *asd_ha, \ - u32 offs, type val) \ -{ \ - struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \ - write##S (val, io_handle->addr + (unsigned long) offs); \ - return; \ -} - -ASD_WRITE_OCM(u8, byte, b); -ASD_WRITE_OCM(u16,word, w); -ASD_WRITE_OCM(u32,dword,l); - -#define ASD_DDBSITE_READ(type, ord) \ -static inline type asd_ddbsite_read_##ord (struct asd_ha_struct *asd_ha, \ - u16 ddb_site_no, \ - u16 offs) \ -{ \ - asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \ - asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \ - return asd_read_reg_##ord (asd_ha, CTXACCESS); \ -} - -ASD_DDBSITE_READ(u32, dword); -ASD_DDBSITE_READ(u16, word); - -static inline u8 asd_ddbsite_read_byte(struct asd_ha_struct *asd_ha, - u16 ddb_site_no, - u16 offs) -{ - if (offs & 1) - return asd_ddbsite_read_word(asd_ha, ddb_site_no, - offs & ~1) >> 8; - else - return asd_ddbsite_read_word(asd_ha, ddb_site_no, - offs) & 0xFF; -} - - -#define ASD_DDBSITE_WRITE(type, ord) \ -static inline void asd_ddbsite_write_##ord (struct asd_ha_struct *asd_ha, \ - u16 ddb_site_no, \ - u16 offs, type val) \ -{ \ - asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \ - asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \ - asd_write_reg_##ord (asd_ha, CTXACCESS, val); \ -} - -ASD_DDBSITE_WRITE(u32, dword); -ASD_DDBSITE_WRITE(u16, word); - -static inline void asd_ddbsite_write_byte(struct asd_ha_struct *asd_ha, - u16 ddb_site_no, - u16 offs, u8 val) -{ - u16 base = offs & ~1; - u16 rval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base); - if (offs & 1) - rval = (val << 8) | (rval & 0xFF); - else - rval = (rval & 0xFF00) | val; - asd_ddbsite_write_word(asd_ha, ddb_site_no, base, rval); -} - - -#define ASD_SCBSITE_READ(type, ord) \ -static inline type asd_scbsite_read_##ord (struct asd_ha_struct *asd_ha, \ - u16 scb_site_no, \ - u16 offs) \ -{ \ - asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \ - asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \ - return asd_read_reg_##ord (asd_ha, CTXACCESS); \ -} - -ASD_SCBSITE_READ(u32, dword); -ASD_SCBSITE_READ(u16, word); - -static inline u8 asd_scbsite_read_byte(struct asd_ha_struct *asd_ha, - u16 scb_site_no, - u16 offs) -{ - if (offs & 1) - return asd_scbsite_read_word(asd_ha, scb_site_no, - offs & ~1) >> 8; - else - return asd_scbsite_read_word(asd_ha, scb_site_no, - offs) & 0xFF; -} - - -#define ASD_SCBSITE_WRITE(type, ord) \ -static inline void asd_scbsite_write_##ord (struct asd_ha_struct *asd_ha, \ - u16 scb_site_no, \ - u16 offs, type val) \ -{ \ - asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \ - asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \ - asd_write_reg_##ord (asd_ha, CTXACCESS, val); \ -} - -ASD_SCBSITE_WRITE(u32, dword); -ASD_SCBSITE_WRITE(u16, word); - -static inline void asd_scbsite_write_byte(struct asd_ha_struct *asd_ha, - u16 scb_site_no, - u16 offs, u8 val) -{ - u16 base = offs & ~1; - u16 rval = asd_scbsite_read_word(asd_ha, scb_site_no, base); - if (offs & 1) - rval = (val << 8) | (rval & 0xFF); - else - rval = (rval & 0xFF00) | val; - asd_scbsite_write_word(asd_ha, scb_site_no, base, rval); -} - -/** - * asd_ddbsite_update_word -- atomically update a word in a ddb site - * @asd_ha: pointer to host adapter structure - * @ddb_site_no: the DDB site number - * @offs: the offset into the DDB - * @oldval: old value found in that offset - * @newval: the new value to replace it - * - * This function is used when the sequencers are running and we need to - * update a DDB site atomically without expensive pausing and upausing - * of the sequencers and accessing the DDB site through the CIO bus. - * - * Return 0 on success; -EFAULT on parity error; -EAGAIN if the old value - * is different than the current value at that offset. - */ -static inline int asd_ddbsite_update_word(struct asd_ha_struct *asd_ha, - u16 ddb_site_no, u16 offs, - u16 oldval, u16 newval) -{ - u8 done; - u16 oval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs); - if (oval != oldval) - return -EAGAIN; - asd_write_reg_word(asd_ha, AOLDDATA, oldval); - asd_write_reg_word(asd_ha, ANEWDATA, newval); - do { - done = asd_read_reg_byte(asd_ha, ATOMICSTATCTL); - } while (!(done & ATOMICDONE)); - if (done & ATOMICERR) - return -EFAULT; /* parity error */ - else if (done & ATOMICWIN) - return 0; /* success */ - else - return -EAGAIN; /* oldval different than current value */ -} - -static inline int asd_ddbsite_update_byte(struct asd_ha_struct *asd_ha, - u16 ddb_site_no, u16 offs, - u8 _oldval, u8 _newval) -{ - u16 base = offs & ~1; - u16 oval; - u16 nval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base); - if (offs & 1) { - if ((nval >> 8) != _oldval) - return -EAGAIN; - nval = (_newval << 8) | (nval & 0xFF); - oval = (_oldval << 8) | (nval & 0xFF); - } else { - if ((nval & 0xFF) != _oldval) - return -EAGAIN; - nval = (nval & 0xFF00) | _newval; - oval = (nval & 0xFF00) | _oldval; - } - return asd_ddbsite_update_word(asd_ha, ddb_site_no, base, oval, nval); -} - -static inline void asd_write_reg_addr(struct asd_ha_struct *asd_ha, u32 reg, - dma_addr_t dma_handle) -{ - asd_write_reg_dword(asd_ha, reg, ASD_BUSADDR_LO(dma_handle)); - asd_write_reg_dword(asd_ha, reg+4, ASD_BUSADDR_HI(dma_handle)); -} - -static inline u32 asd_get_cmdctx_size(struct asd_ha_struct *asd_ha) -{ - /* DCHREVISION returns 0, possibly broken */ - u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE; - return ctxmemsize ? 65536 : 32768; -} - -static inline u32 asd_get_devctx_size(struct asd_ha_struct *asd_ha) -{ - u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE; - return ctxmemsize ? 8192 : 4096; -} - -static inline void asd_disable_ints(struct asd_ha_struct *asd_ha) -{ - asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN); -} - -static inline void asd_enable_ints(struct asd_ha_struct *asd_ha) -{ - /* Enable COM SAS interrupt on errors, COMSTAT */ - asd_write_reg_dword(asd_ha, COMSTATEN, - EN_CSBUFPERR | EN_CSERR | EN_OVLYERR); - /* Enable DCH SAS CFIFTOERR */ - asd_write_reg_dword(asd_ha, DCHSTATUS, EN_CFIFTOERR); - /* Enable Host Device interrupts */ - asd_write_reg_dword(asd_ha, CHIMINTEN, SET_CHIMINTEN); -} - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg_def.h b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg_def.h deleted file mode 100644 index dd6cc800..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_reg_def.h +++ /dev/null @@ -1,2399 +0,0 @@ -/* - * Aic94xx SAS/SATA driver hardware registers definitions. - * - * Copyright (C) 2004 Adaptec, Inc. All rights reserved. - * Copyright (C) 2004 David Chaw - * Copyright (C) 2005 Luben Tuikov - * - * Luben Tuikov: Some register value updates to make it work with the window - * agnostic register r/w functions. Some register corrections, sizes, - * etc. - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - * $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $ - * - */ - -#ifndef _ADP94XX_REG_DEF_H_ -#define _ADP94XX_REG_DEF_H_ - -/* - * Common definitions. - */ -#define CSEQ_MODE_PAGE_SIZE 0x200 /* CSEQ mode page size */ -#define LmSEQ_MODE_PAGE_SIZE 0x200 /* LmSEQ mode page size */ -#define LmSEQ_HOST_REG_SIZE 0x4000 /* LmSEQ Host Register size */ - -/********************* COM_SAS registers definition *************************/ - -/* The base is REG_BASE_ADDR, defined in aic94xx_reg.h. - */ - -/* - * CHIM Registers, Address Range : (0x00-0xFF) - */ -#define COMBIST (REG_BASE_ADDR + 0x00) - -/* bits 31:24 */ -#define L7BLKRST 0x80000000 -#define L6BLKRST 0x40000000 -#define L5BLKRST 0x20000000 -#define L4BLKRST 0x10000000 -#define L3BLKRST 0x08000000 -#define L2BLKRST 0x04000000 -#define L1BLKRST 0x02000000 -#define L0BLKRST 0x01000000 -#define LmBLKRST 0xFF000000 -#define LmBLKRST_COMBIST(phyid) (1 << (24 + phyid)) - -#define OCMBLKRST 0x00400000 -#define CTXMEMBLKRST 0x00200000 -#define CSEQBLKRST 0x00100000 -#define EXSIBLKRST 0x00040000 -#define DPIBLKRST 0x00020000 -#define DFIFBLKRST 0x00010000 -#define HARDRST 0x00000200 -#define COMBLKRST 0x00000100 -#define FRCDFPERR 0x00000080 -#define FRCCIOPERR 0x00000020 -#define FRCBISTERR 0x00000010 -#define COMBISTEN 0x00000004 -#define COMBISTDONE 0x00000002 /* ro */ -#define COMBISTFAIL 0x00000001 /* ro */ - -#define COMSTAT (REG_BASE_ADDR + 0x04) - -#define REQMBXREAD 0x00000040 -#define RSPMBXAVAIL 0x00000020 -#define CSBUFPERR 0x00000008 -#define OVLYERR 0x00000004 -#define CSERR 0x00000002 -#define OVLYDMADONE 0x00000001 - -#define COMSTAT_MASK (REQMBXREAD | RSPMBXAVAIL | \ - CSBUFPERR | OVLYERR | CSERR |\ - OVLYDMADONE) - -#define COMSTATEN (REG_BASE_ADDR + 0x08) - -#define EN_REQMBXREAD 0x00000040 -#define EN_RSPMBXAVAIL 0x00000020 -#define EN_CSBUFPERR 0x00000008 -#define EN_OVLYERR 0x00000004 -#define EN_CSERR 0x00000002 -#define EN_OVLYDONE 0x00000001 - -#define SCBPRO (REG_BASE_ADDR + 0x0C) - -#define SCBCONS_MASK 0xFFFF0000 -#define SCBPRO_MASK 0x0000FFFF - -#define CHIMREQMBX (REG_BASE_ADDR + 0x10) - -#define CHIMRSPMBX (REG_BASE_ADDR + 0x14) - -#define CHIMINT (REG_BASE_ADDR + 0x18) - -#define EXT_INT0 0x00000800 -#define EXT_INT1 0x00000400 -#define PORRSTDET 0x00000200 -#define HARDRSTDET 0x00000100 -#define DLAVAILQ 0x00000080 /* ro */ -#define HOSTERR 0x00000040 -#define INITERR 0x00000020 -#define DEVINT 0x00000010 -#define COMINT 0x00000008 -#define DEVTIMER2 0x00000004 -#define DEVTIMER1 0x00000002 -#define DLAVAIL 0x00000001 - -#define CHIMINT_MASK (HOSTERR | INITERR | DEVINT | COMINT |\ - DEVTIMER2 | DEVTIMER1 | DLAVAIL) - -#define DEVEXCEPT_MASK (HOSTERR | INITERR | DEVINT | COMINT) - -#define CHIMINTEN (REG_BASE_ADDR + 0x1C) - -#define RST_EN_EXT_INT1 0x01000000 -#define RST_EN_EXT_INT0 0x00800000 -#define RST_EN_HOSTERR 0x00400000 -#define RST_EN_INITERR 0x00200000 -#define RST_EN_DEVINT 0x00100000 -#define RST_EN_COMINT 0x00080000 -#define RST_EN_DEVTIMER2 0x00040000 -#define RST_EN_DEVTIMER1 0x00020000 -#define RST_EN_DLAVAIL 0x00010000 -#define SET_EN_EXT_INT1 0x00000100 -#define SET_EN_EXT_INT0 0x00000080 -#define SET_EN_HOSTERR 0x00000040 -#define SET_EN_INITERR 0x00000020 -#define SET_EN_DEVINT 0x00000010 -#define SET_EN_COMINT 0x00000008 -#define SET_EN_DEVTIMER2 0x00000004 -#define SET_EN_DEVTIMER1 0x00000002 -#define SET_EN_DLAVAIL 0x00000001 - -#define RST_CHIMINTEN (RST_EN_HOSTERR | RST_EN_INITERR | \ - RST_EN_DEVINT | RST_EN_COMINT | \ - RST_EN_DEVTIMER2 | RST_EN_DEVTIMER1 |\ - RST_EN_DLAVAIL) - -#define SET_CHIMINTEN (SET_EN_HOSTERR | SET_EN_INITERR |\ - SET_EN_DEVINT | SET_EN_COMINT |\ - SET_EN_DLAVAIL) - -#define OVLYDMACTL (REG_BASE_ADDR + 0x20) - -#define OVLYADR_MASK 0x07FF0000 -#define OVLYLSEQ_MASK 0x0000FF00 -#define OVLYCSEQ 0x00000080 -#define OVLYHALTERR 0x00000040 -#define PIOCMODE 0x00000020 -#define RESETOVLYDMA 0x00000008 /* wo */ -#define STARTOVLYDMA 0x00000004 -#define STOPOVLYDMA 0x00000002 /* wo */ -#define OVLYDMAACT 0x00000001 /* ro */ - -#define OVLYDMACNT (REG_BASE_ADDR + 0x24) - -#define OVLYDOMAIN1 0x20000000 /* ro */ -#define OVLYDOMAIN0 0x10000000 -#define OVLYBUFADR_MASK 0x007F0000 -#define OVLYDMACNT_MASK 0x00003FFF - -#define OVLYDMAADR (REG_BASE_ADDR + 0x28) - -#define DMAERR (REG_BASE_ADDR + 0x30) - -#define OVLYERRSTAT_MASK 0x0000FF00 /* ro */ -#define CSERRSTAT_MASK 0x000000FF /* ro */ - -#define SPIODATA (REG_BASE_ADDR + 0x34) - -/* 0x38 - 0x3C are reserved */ - -#define T1CNTRLR (REG_BASE_ADDR + 0x40) - -#define T1DONE 0x00010000 /* ro */ -#define TIMER64 0x00000400 -#define T1ENABLE 0x00000200 -#define T1RELOAD 0x00000100 -#define T1PRESCALER_MASK 0x00000003 - -#define T1CMPR (REG_BASE_ADDR + 0x44) - -#define T1CNTR (REG_BASE_ADDR + 0x48) - -#define T2CNTRLR (REG_BASE_ADDR + 0x4C) - -#define T2DONE 0x00010000 /* ro */ -#define T2ENABLE 0x00000200 -#define T2RELOAD 0x00000100 -#define T2PRESCALER_MASK 0x00000003 - -#define T2CMPR (REG_BASE_ADDR + 0x50) - -#define T2CNTR (REG_BASE_ADDR + 0x54) - -/* 0x58h - 0xFCh are reserved */ - -/* - * DCH_SAS Registers, Address Range : (0x800-0xFFF) - */ -#define CMDCTXBASE (REG_BASE_ADDR + 0x800) - -#define DEVCTXBASE (REG_BASE_ADDR + 0x808) - -#define CTXDOMAIN (REG_BASE_ADDR + 0x810) - -#define DEVCTXDOMAIN1 0x00000008 /* ro */ -#define DEVCTXDOMAIN0 0x00000004 -#define CMDCTXDOMAIN1 0x00000002 /* ro */ -#define CMDCTXDOMAIN0 0x00000001 - -#define DCHCTL (REG_BASE_ADDR + 0x814) - -#define OCMBISTREPAIR 0x00080000 -#define OCMBISTEN 0x00040000 -#define OCMBISTDN 0x00020000 /* ro */ -#define OCMBISTFAIL 0x00010000 /* ro */ -#define DDBBISTEN 0x00004000 -#define DDBBISTDN 0x00002000 /* ro */ -#define DDBBISTFAIL 0x00001000 /* ro */ -#define SCBBISTEN 0x00000400 -#define SCBBISTDN 0x00000200 /* ro */ -#define SCBBISTFAIL 0x00000100 /* ro */ - -#define MEMSEL_MASK 0x000000E0 -#define MEMSEL_CCM_LSEQ 0x00000000 -#define MEMSEL_CCM_IOP 0x00000020 -#define MEMSEL_CCM_SASCTL 0x00000040 -#define MEMSEL_DCM_LSEQ 0x00000060 -#define MEMSEL_DCM_IOP 0x00000080 -#define MEMSEL_OCM 0x000000A0 - -#define FRCERR 0x00000010 -#define AUTORLS 0x00000001 - -#define DCHREVISION (REG_BASE_ADDR + 0x818) - -#define DCHREVISION_MASK 0x000000FF - -#define DCHSTATUS (REG_BASE_ADDR + 0x81C) - -#define EN_CFIFTOERR 0x00020000 -#define CFIFTOERR 0x00000200 -#define CSEQINT 0x00000100 /* ro */ -#define LSEQ7INT 0x00000080 /* ro */ -#define LSEQ6INT 0x00000040 /* ro */ -#define LSEQ5INT 0x00000020 /* ro */ -#define LSEQ4INT 0x00000010 /* ro */ -#define LSEQ3INT 0x00000008 /* ro */ -#define LSEQ2INT 0x00000004 /* ro */ -#define LSEQ1INT 0x00000002 /* ro */ -#define LSEQ0INT 0x00000001 /* ro */ - -#define LSEQINT_MASK (LSEQ7INT | LSEQ6INT | LSEQ5INT |\ - LSEQ4INT | LSEQ3INT | LSEQ2INT |\ - LSEQ1INT | LSEQ0INT) - -#define DCHDFIFDEBUG (REG_BASE_ADDR + 0x820) -#define ENFAIRMST 0x00FF0000 -#define DISWRMST9 0x00000200 -#define DISWRMST8 0x00000100 -#define DISRDMST 0x000000FF - -#define ATOMICSTATCTL (REG_BASE_ADDR + 0x824) -/* 8 bit wide */ -#define AUTOINC 0x80 -#define ATOMICERR 0x04 -#define ATOMICWIN 0x02 -#define ATOMICDONE 0x01 - - -#define ALTCIOADR (REG_BASE_ADDR + 0x828) -/* 16 bit; bits 8:0 define CIO addr space of CSEQ */ - -#define ASCBPTR (REG_BASE_ADDR + 0x82C) -/* 16 bit wide */ - -#define ADDBPTR (REG_BASE_ADDR + 0x82E) -/* 16 bit wide */ - -#define ANEWDATA (REG_BASE_ADDR + 0x830) -/* 16 bit */ - -#define AOLDDATA (REG_BASE_ADDR + 0x834) -/* 16 bit */ - -#define CTXACCESS (REG_BASE_ADDR + 0x838) -/* 32 bit */ - -/* 0x83Ch - 0xFFCh are reserved */ - -/* - * ARP2 External Processor Registers, Address Range : (0x00-0x1F) - */ -#define ARP2CTL 0x00 - -#define FRCSCRPERR 0x00040000 -#define FRCARP2PERR 0x00020000 -#define FRCARP2ILLOPC 0x00010000 -#define ENWAITTO 0x00008000 -#define PERRORDIS 0x00004000 -#define FAILDIS 0x00002000 -#define CIOPERRDIS 0x00001000 -#define BREAKEN3 0x00000800 -#define BREAKEN2 0x00000400 -#define BREAKEN1 0x00000200 -#define BREAKEN0 0x00000100 -#define EPAUSE 0x00000008 -#define PAUSED 0x00000004 /* ro */ -#define STEP 0x00000002 -#define ARP2RESET 0x00000001 /* wo */ - -#define ARP2INT 0x04 - -#define HALTCODE_MASK 0x00FF0000 /* ro */ -#define ARP2WAITTO 0x00000100 -#define ARP2HALTC 0x00000080 -#define ARP2ILLOPC 0x00000040 -#define ARP2PERR 0x00000020 -#define ARP2CIOPERR 0x00000010 -#define ARP2BREAK3 0x00000008 -#define ARP2BREAK2 0x00000004 -#define ARP2BREAK1 0x00000002 -#define ARP2BREAK0 0x00000001 - -#define ARP2INTEN 0x08 - -#define EN_ARP2WAITTO 0x00000100 -#define EN_ARP2HALTC 0x00000080 -#define EN_ARP2ILLOPC 0x00000040 -#define EN_ARP2PERR 0x00000020 -#define EN_ARP2CIOPERR 0x00000010 -#define EN_ARP2BREAK3 0x00000008 -#define EN_ARP2BREAK2 0x00000004 -#define EN_ARP2BREAK1 0x00000002 -#define EN_ARP2BREAK0 0x00000001 - -#define ARP2BREAKADR01 0x0C - -#define BREAKADR1_MASK 0x0FFF0000 -#define BREAKADR0_MASK 0x00000FFF - -#define ARP2BREAKADR23 0x10 - -#define BREAKADR3_MASK 0x0FFF0000 -#define BREAKADR2_MASK 0x00000FFF - -/* 0x14h - 0x1Ch are reserved */ - -/* - * ARP2 Registers, Address Range : (0x00-0x1F) - * The definitions have the same address offset for CSEQ and LmSEQ - * CIO Bus Registers. - */ -#define MODEPTR 0x00 - -#define DSTMODE 0xF0 -#define SRCMODE 0x0F - -#define ALTMODE 0x01 - -#define ALTDMODE 0xF0 -#define ALTSMODE 0x0F - -#define ATOMICXCHG 0x02 - -#define FLAG 0x04 - -#define INTCODE_MASK 0xF0 -#define ALTMODEV2 0x04 -#define CARRY_INT 0x02 -#define CARRY 0x01 - -#define ARP2INTCTL 0x05 - -#define PAUSEDIS 0x80 -#define RSTINTCTL 0x40 -#define POPALTMODE 0x08 -#define ALTMODEV 0x04 -#define INTMASK 0x02 -#define IRET 0x01 - -#define STACK 0x06 - -#define FUNCTION1 0x07 - -#define PRGMCNT 0x08 - -#define ACCUM 0x0A - -#define SINDEX 0x0C - -#define DINDEX 0x0E - -#define ALLONES 0x10 - -#define ALLZEROS 0x11 - -#define SINDIR 0x12 - -#define DINDIR 0x13 - -#define JUMLDIR 0x14 - -#define ARP2HALTCODE 0x15 - -#define CURRADDR 0x16 - -#define LASTADDR 0x18 - -#define NXTLADDR 0x1A - -#define DBGPORTPTR 0x1C - -#define DBGPORT 0x1D - -/* - * CIO Registers. - * The definitions have the same address offset for CSEQ and LmSEQ - * CIO Bus Registers. - */ -#define MnSCBPTR 0x20 - -#define MnDDBPTR 0x22 - -#define SCRATCHPAGE 0x24 - -#define MnSCRATCHPAGE 0x25 - -#define SCRATCHPAGESV 0x26 - -#define MnSCRATCHPAGESV 0x27 - -#define MnDMAERRS 0x46 - -#define MnSGDMAERRS 0x47 - -#define MnSGBUF 0x53 - -#define MnSGDMASTAT 0x5b - -#define MnDDMACTL 0x5c /* RAZOR.rspec.fm rev 1.5 is wrong */ - -#define MnDDMASTAT 0x5d /* RAZOR.rspec.fm rev 1.5 is wrong */ - -#define MnDDMAMODE 0x5e /* RAZOR.rspec.fm rev 1.5 is wrong */ - -#define MnDMAENG 0x60 - -#define MnPIPECTL 0x61 - -#define MnSGBADR 0x65 - -#define MnSCB_SITE 0x100 - -#define MnDDB_SITE 0x180 - -/* - * The common definitions below have the same address offset for both - * CSEQ and LmSEQ. - */ -#define BISTCTL0 0x4C - -#define BISTCTL1 0x50 - -#define MAPPEDSCR 0x800 - -/* - * CSEQ Host Register, Address Range : (0x000-0xFFC) - */ -#define CSEQ_HOST_REG_BASE_ADR 0xB8001000 - -#define CARP2CTL (CSEQ_HOST_REG_BASE_ADR + ARP2CTL) - -#define CARP2INT (CSEQ_HOST_REG_BASE_ADR + ARP2INT) - -#define CARP2INTEN (CSEQ_HOST_REG_BASE_ADR + ARP2INTEN) - -#define CARP2BREAKADR01 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR01) - -#define CARP2BREAKADR23 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR23) - -#define CBISTCTL (CSEQ_HOST_REG_BASE_ADR + BISTCTL1) - -#define CSEQRAMBISTEN 0x00000040 -#define CSEQRAMBISTDN 0x00000020 /* ro */ -#define CSEQRAMBISTFAIL 0x00000010 /* ro */ -#define CSEQSCRBISTEN 0x00000004 -#define CSEQSCRBISTDN 0x00000002 /* ro */ -#define CSEQSCRBISTFAIL 0x00000001 /* ro */ - -#define CMAPPEDSCR (CSEQ_HOST_REG_BASE_ADR + MAPPEDSCR) - -/* - * CSEQ CIO Bus Registers, Address Range : (0x0000-0x1FFC) - * 16 modes, each mode is 512 bytes. - * Unless specified, the register should valid for all modes. - */ -#define CSEQ_CIO_REG_BASE_ADR REG_BASE_ADDR_CSEQCIO - -#define CSEQm_CIO_REG(Mode, Reg) \ - (CSEQ_CIO_REG_BASE_ADR + \ - ((u32) (Mode) * CSEQ_MODE_PAGE_SIZE) + (u32) (Reg)) - -#define CMODEPTR (CSEQ_CIO_REG_BASE_ADR + MODEPTR) - -#define CALTMODE (CSEQ_CIO_REG_BASE_ADR + ALTMODE) - -#define CATOMICXCHG (CSEQ_CIO_REG_BASE_ADR + ATOMICXCHG) - -#define CFLAG (CSEQ_CIO_REG_BASE_ADR + FLAG) - -#define CARP2INTCTL (CSEQ_CIO_REG_BASE_ADR + ARP2INTCTL) - -#define CSTACK (CSEQ_CIO_REG_BASE_ADR + STACK) - -#define CFUNCTION1 (CSEQ_CIO_REG_BASE_ADR + FUNCTION1) - -#define CPRGMCNT (CSEQ_CIO_REG_BASE_ADR + PRGMCNT) - -#define CACCUM (CSEQ_CIO_REG_BASE_ADR + ACCUM) - -#define CSINDEX (CSEQ_CIO_REG_BASE_ADR + SINDEX) - -#define CDINDEX (CSEQ_CIO_REG_BASE_ADR + DINDEX) - -#define CALLONES (CSEQ_CIO_REG_BASE_ADR + ALLONES) - -#define CALLZEROS (CSEQ_CIO_REG_BASE_ADR + ALLZEROS) - -#define CSINDIR (CSEQ_CIO_REG_BASE_ADR + SINDIR) - -#define CDINDIR (CSEQ_CIO_REG_BASE_ADR + DINDIR) - -#define CJUMLDIR (CSEQ_CIO_REG_BASE_ADR + JUMLDIR) - -#define CARP2HALTCODE (CSEQ_CIO_REG_BASE_ADR + ARP2HALTCODE) - -#define CCURRADDR (CSEQ_CIO_REG_BASE_ADR + CURRADDR) - -#define CLASTADDR (CSEQ_CIO_REG_BASE_ADR + LASTADDR) - -#define CNXTLADDR (CSEQ_CIO_REG_BASE_ADR + NXTLADDR) - -#define CDBGPORTPTR (CSEQ_CIO_REG_BASE_ADR + DBGPORTPTR) - -#define CDBGPORT (CSEQ_CIO_REG_BASE_ADR + DBGPORT) - -#define CSCRATCHPAGE (CSEQ_CIO_REG_BASE_ADR + SCRATCHPAGE) - -#define CMnSCBPTR(Mode) CSEQm_CIO_REG(Mode, MnSCBPTR) - -#define CMnDDBPTR(Mode) CSEQm_CIO_REG(Mode, MnDDBPTR) - -#define CMnSCRATCHPAGE(Mode) CSEQm_CIO_REG(Mode, MnSCRATCHPAGE) - -#define CLINKCON (CSEQ_CIO_REG_BASE_ADR + 0x28) - -#define CCIOAACESS (CSEQ_CIO_REG_BASE_ADR + 0x2C) - -/* mode 0-7 */ -#define MnREQMBX 0x30 -#define CMnREQMBX(Mode) CSEQm_CIO_REG(Mode, 0x30) - -/* mode 8 */ -#define CSEQCON CSEQm_CIO_REG(8, 0x30) - -/* mode 0-7 */ -#define MnRSPMBX 0x34 -#define CMnRSPMBX(Mode) CSEQm_CIO_REG(Mode, 0x34) - -/* mode 8 */ -#define CSEQCOMCTL CSEQm_CIO_REG(8, 0x34) - -/* mode 8 */ -#define CSEQCOMSTAT CSEQm_CIO_REG(8, 0x35) - -/* mode 8 */ -#define CSEQCOMINTEN CSEQm_CIO_REG(8, 0x36) - -/* mode 8 */ -#define CSEQCOMDMACTL CSEQm_CIO_REG(8, 0x37) - -#define CSHALTERR 0x10 -#define RESETCSDMA 0x08 /* wo */ -#define STARTCSDMA 0x04 -#define STOPCSDMA 0x02 /* wo */ -#define CSDMAACT 0x01 /* ro */ - -/* mode 0-7 */ -#define MnINT 0x38 -#define CMnINT(Mode) CSEQm_CIO_REG(Mode, 0x38) - -#define CMnREQMBXE 0x02 -#define CMnRSPMBXF 0x01 -#define CMnINT_MASK 0x00000003 - -/* mode 8 */ -#define CSEQREQMBX CSEQm_CIO_REG(8, 0x38) - -/* mode 0-7 */ -#define MnINTEN 0x3C -#define CMnINTEN(Mode) CSEQm_CIO_REG(Mode, 0x3C) - -#define EN_CMnRSPMBXF 0x01 - -/* mode 8 */ -#define CSEQRSPMBX CSEQm_CIO_REG(8, 0x3C) - -/* mode 8 */ -#define CSDMAADR CSEQm_CIO_REG(8, 0x40) - -/* mode 8 */ -#define CSDMACNT CSEQm_CIO_REG(8, 0x48) - -/* mode 8 */ -#define CSEQDLCTL CSEQm_CIO_REG(8, 0x4D) - -#define DONELISTEND 0x10 -#define DONELISTSIZE_MASK 0x0F -#define DONELISTSIZE_8ELEM 0x01 -#define DONELISTSIZE_16ELEM 0x02 -#define DONELISTSIZE_32ELEM 0x03 -#define DONELISTSIZE_64ELEM 0x04 -#define DONELISTSIZE_128ELEM 0x05 -#define DONELISTSIZE_256ELEM 0x06 -#define DONELISTSIZE_512ELEM 0x07 -#define DONELISTSIZE_1024ELEM 0x08 -#define DONELISTSIZE_2048ELEM 0x09 -#define DONELISTSIZE_4096ELEM 0x0A -#define DONELISTSIZE_8192ELEM 0x0B -#define DONELISTSIZE_16384ELEM 0x0C - -/* mode 8 */ -#define CSEQDLOFFS CSEQm_CIO_REG(8, 0x4E) - -/* mode 11 */ -#define CM11INTVEC0 CSEQm_CIO_REG(11, 0x50) - -/* mode 11 */ -#define CM11INTVEC1 CSEQm_CIO_REG(11, 0x52) - -/* mode 11 */ -#define CM11INTVEC2 CSEQm_CIO_REG(11, 0x54) - -#define CCONMSK (CSEQ_CIO_REG_BASE_ADR + 0x60) - -#define CCONEXIST (CSEQ_CIO_REG_BASE_ADR + 0x61) - -#define CCONMODE (CSEQ_CIO_REG_BASE_ADR + 0x62) - -#define CTIMERCALC (CSEQ_CIO_REG_BASE_ADR + 0x64) - -#define CINTDIS (CSEQ_CIO_REG_BASE_ADR + 0x68) - -/* mode 8, 32x32 bits, 128 bytes of mapped buffer */ -#define CSBUFFER CSEQm_CIO_REG(8, 0x80) - -#define CSCRATCH (CSEQ_CIO_REG_BASE_ADR + 0x1C0) - -/* mode 0-8 */ -#define CMnSCRATCH(Mode) CSEQm_CIO_REG(Mode, 0x1E0) - -/* - * CSEQ Mapped Instruction RAM Page, Address Range : (0x0000-0x1FFC) - */ -#define CSEQ_RAM_REG_BASE_ADR 0xB8004000 - -/* - * The common definitions below have the same address offset for all the Link - * sequencers. - */ -#define MODECTL 0x40 - -#define DBGMODE 0x44 - -#define CONTROL 0x48 -#define LEDTIMER 0x00010000 -#define LEDTIMERS_10us 0x00000000 -#define LEDTIMERS_1ms 0x00000800 -#define LEDTIMERS_100ms 0x00001000 -#define LEDMODE_TXRX 0x00000000 -#define LEDMODE_CONNECTED 0x00000200 -#define LEDPOL 0x00000100 - -#define LSEQRAM 0x1000 - -/* - * LmSEQ Host Registers, Address Range : (0x0000-0x3FFC) - */ -#define LSEQ0_HOST_REG_BASE_ADR 0xB8020000 -#define LSEQ1_HOST_REG_BASE_ADR 0xB8024000 -#define LSEQ2_HOST_REG_BASE_ADR 0xB8028000 -#define LSEQ3_HOST_REG_BASE_ADR 0xB802C000 -#define LSEQ4_HOST_REG_BASE_ADR 0xB8030000 -#define LSEQ5_HOST_REG_BASE_ADR 0xB8034000 -#define LSEQ6_HOST_REG_BASE_ADR 0xB8038000 -#define LSEQ7_HOST_REG_BASE_ADR 0xB803C000 - -#define LmARP2CTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - ARP2CTL) - -#define LmARP2INT(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - ARP2INT) - -#define LmARP2INTEN(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - ARP2INTEN) - -#define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - DBGMODE) - -#define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - CONTROL) - -#define LmARP2BREAKADR01(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - ARP2BREAKADR01) - -#define LmARP2BREAKADR23(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - ARP2BREAKADR23) - -#define LmMODECTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - MODECTL) - -#define LmAUTODISCI 0x08000000 -#define LmDSBLBITLT 0x04000000 -#define LmDSBLANTT 0x02000000 -#define LmDSBLCRTT 0x01000000 -#define LmDSBLCONT 0x00000100 -#define LmPRIMODE 0x00000080 -#define LmDSBLHOLD 0x00000040 -#define LmDISACK 0x00000020 -#define LmBLIND48 0x00000010 -#define LmRCVMODE_MASK 0x0000000C -#define LmRCVMODE_PLD 0x00000000 -#define LmRCVMODE_HPC 0x00000004 - -#define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - DBGMODE) - -#define LmFRCPERR 0x80000000 -#define LmMEMSEL_MASK 0x30000000 -#define LmFRCRBPERR 0x00000000 -#define LmFRCTBPERR 0x10000000 -#define LmFRCSGBPERR 0x20000000 -#define LmFRCARBPERR 0x30000000 -#define LmRCVIDW 0x00080000 -#define LmINVDWERR 0x00040000 -#define LmRCVDISP 0x00004000 -#define LmDISPERR 0x00002000 -#define LmDSBLDSCR 0x00000800 -#define LmDSBLSCR 0x00000400 -#define LmFRCNAK 0x00000200 -#define LmFRCROFS 0x00000100 -#define LmFRCCRC 0x00000080 -#define LmFRMTYPE_MASK 0x00000070 -#define LmSG_DATA 0x00000000 -#define LmSG_COMMAND 0x00000010 -#define LmSG_TASK 0x00000020 -#define LmSG_TGTXFER 0x00000030 -#define LmSG_RESPONSE 0x00000040 -#define LmSG_IDENADDR 0x00000050 -#define LmSG_OPENADDR 0x00000060 -#define LmDISCRCGEN 0x00000008 -#define LmDISCRCCHK 0x00000004 -#define LmSSXMTFRM 0x00000002 -#define LmSSRCVFRM 0x00000001 - -#define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - CONTROL) - -#define LmSTEPXMTFRM 0x00000002 -#define LmSTEPRCVFRM 0x00000001 - -#define LmBISTCTL0(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ - BISTCTL0) - -#define ARBBISTEN 0x40000000 -#define ARBBISTDN 0x20000000 /* ro */ -#define ARBBISTFAIL 0x10000000 /* ro */ -#define TBBISTEN 0x00000400 -#define TBBISTDN 0x00000200 /* ro */ -#define TBBISTFAIL 0x00000100 /* ro */ -#define RBBISTEN 0x00000040 -#define RBBISTDN 0x00000020 /* ro */ -#define RBBISTFAIL 0x00000010 /* ro */ -#define SGBISTEN 0x00000004 -#define SGBISTDN 0x00000002 /* ro */ -#define SGBISTFAIL 0x00000001 /* ro */ - -#define LmBISTCTL1(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum)*LmSEQ_HOST_REG_SIZE) +\ - BISTCTL1) - -#define LmRAMPAGE1 0x00000200 -#define LmRAMPAGE0 0x00000100 -#define LmIMEMBISTEN 0x00000040 -#define LmIMEMBISTDN 0x00000020 /* ro */ -#define LmIMEMBISTFAIL 0x00000010 /* ro */ -#define LmSCRBISTEN 0x00000004 -#define LmSCRBISTDN 0x00000002 /* ro */ -#define LmSCRBISTFAIL 0x00000001 /* ro */ -#define LmRAMPAGE (LmRAMPAGE1 + LmRAMPAGE0) -#define LmRAMPAGE_LSHIFT 0x8 - -#define LmSCRATCH(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\ - MAPPEDSCR) - -#define LmSEQRAM(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ - ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\ - LSEQRAM) - -/* - * LmSEQ CIO Bus Register, Address Range : (0x0000-0xFFC) - * 8 modes, each mode is 512 bytes. - * Unless specified, the register should valid for all modes. - */ -#define LmSEQ_CIOBUS_REG_BASE 0x2000 - -#define LmSEQ_PHY_BASE(Mode, LinkNum) \ - (LSEQ0_HOST_REG_BASE_ADR + \ - (LmSEQ_HOST_REG_SIZE * (u32) (LinkNum)) + \ - LmSEQ_CIOBUS_REG_BASE + \ - ((u32) (Mode) * LmSEQ_MODE_PAGE_SIZE)) - -#define LmSEQ_PHY_REG(Mode, LinkNum, Reg) \ - (LmSEQ_PHY_BASE(Mode, LinkNum) + (u32) (Reg)) - -#define LmMODEPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, MODEPTR) - -#define LmALTMODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALTMODE) - -#define LmATOMICXCHG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ATOMICXCHG) - -#define LmFLAG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FLAG) - -#define LmARP2INTCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2INTCTL) - -#define LmSTACK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, STACK) - -#define LmFUNCTION1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FUNCTION1) - -#define LmPRGMCNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, PRGMCNT) - -#define LmACCUM(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ACCUM) - -#define LmSINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDEX) - -#define LmDINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDEX) - -#define LmALLONES(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLONES) - -#define LmALLZEROS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLZEROS) - -#define LmSINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDIR) - -#define LmDINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDIR) - -#define LmJUMLDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, JUMLDIR) - -#define LmARP2HALTCODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2HALTCODE) - -#define LmCURRADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, CURRADDR) - -#define LmLASTADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, LASTADDR) - -#define LmNXTLADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, NXTLADDR) - -#define LmDBGPORTPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORTPTR) - -#define LmDBGPORT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORT) - -#define LmSCRATCHPAGE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SCRATCHPAGE) - -#define LmMnSCRATCHPAGE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, \ - MnSCRATCHPAGE) - -#define LmTIMERCALC(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x28) - -#define LmREQMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x30) - -#define LmRSPMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x34) - -#define LmMnINT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x38) - -#define CTXMEMSIZE 0x80000000 /* ro */ -#define LmACKREQ 0x08000000 -#define LmNAKREQ 0x04000000 -#define LmMnXMTERR 0x02000000 -#define LmM5OOBSVC 0x01000000 -#define LmHWTINT 0x00800000 -#define LmMnCTXDONE 0x00100000 -#define LmM2REQMBXF 0x00080000 -#define LmM2RSPMBXE 0x00040000 -#define LmMnDMAERR 0x00020000 -#define LmRCVPRIM 0x00010000 -#define LmRCVERR 0x00008000 -#define LmADDRRCV 0x00004000 -#define LmMnHDRMISS 0x00002000 -#define LmMnWAITSCB 0x00001000 -#define LmMnRLSSCB 0x00000800 -#define LmMnSAVECTX 0x00000400 -#define LmMnFETCHSG 0x00000200 -#define LmMnLOADCTX 0x00000100 -#define LmMnCFGICL 0x00000080 -#define LmMnCFGSATA 0x00000040 -#define LmMnCFGEXPSATA 0x00000020 -#define LmMnCFGCMPLT 0x00000010 -#define LmMnCFGRBUF 0x00000008 -#define LmMnSAVETTR 0x00000004 -#define LmMnCFGRDAT 0x00000002 -#define LmMnCFGHDR 0x00000001 - -#define LmMnINTEN(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x3C) - -#define EN_LmACKREQ 0x08000000 -#define EN_LmNAKREQ 0x04000000 -#define EN_LmMnXMTERR 0x02000000 -#define EN_LmM5OOBSVC 0x01000000 -#define EN_LmHWTINT 0x00800000 -#define EN_LmMnCTXDONE 0x00100000 -#define EN_LmM2REQMBXF 0x00080000 -#define EN_LmM2RSPMBXE 0x00040000 -#define EN_LmMnDMAERR 0x00020000 -#define EN_LmRCVPRIM 0x00010000 -#define EN_LmRCVERR 0x00008000 -#define EN_LmADDRRCV 0x00004000 -#define EN_LmMnHDRMISS 0x00002000 -#define EN_LmMnWAITSCB 0x00001000 -#define EN_LmMnRLSSCB 0x00000800 -#define EN_LmMnSAVECTX 0x00000400 -#define EN_LmMnFETCHSG 0x00000200 -#define EN_LmMnLOADCTX 0x00000100 -#define EN_LmMnCFGICL 0x00000080 -#define EN_LmMnCFGSATA 0x00000040 -#define EN_LmMnCFGEXPSATA 0x00000020 -#define EN_LmMnCFGCMPLT 0x00000010 -#define EN_LmMnCFGRBUF 0x00000008 -#define EN_LmMnSAVETTR 0x00000004 -#define EN_LmMnCFGRDAT 0x00000002 -#define EN_LmMnCFGHDR 0x00000001 - -#define LmM0INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmMnCFGRBUF | \ - EN_LmMnSAVETTR | EN_LmMnCFGRDAT | \ - EN_LmMnCFGHDR | EN_LmRCVERR | \ - EN_LmADDRRCV | EN_LmMnHDRMISS | \ - EN_LmMnRLSSCB | EN_LmMnSAVECTX | \ - EN_LmMnFETCHSG | EN_LmMnLOADCTX | \ - EN_LmHWTINT | EN_LmMnCTXDONE | \ - EN_LmRCVPRIM | EN_LmMnCFGSATA | \ - EN_LmMnCFGEXPSATA | EN_LmMnDMAERR) - -#define LmM1INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmADDRRCV | \ - EN_LmMnRLSSCB | EN_LmMnSAVECTX | \ - EN_LmMnFETCHSG | EN_LmMnLOADCTX | \ - EN_LmMnXMTERR | EN_LmHWTINT | \ - EN_LmMnCTXDONE | EN_LmRCVPRIM | \ - EN_LmRCVERR | EN_LmMnDMAERR) - -#define LmM2INTEN_MASK (EN_LmADDRRCV | EN_LmHWTINT | \ - EN_LmM2REQMBXF | EN_LmRCVPRIM | \ - EN_LmRCVERR) - -#define LmM5INTEN_MASK (EN_LmADDRRCV | EN_LmM5OOBSVC | \ - EN_LmHWTINT | EN_LmRCVPRIM | \ - EN_LmRCVERR) - -#define LmXMTPRIMD(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x40) - -#define LmXMTPRIMCS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x44) - -#define LmCONSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x45) - -#define LmMnDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x46) - -#define LmMnSGDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x47) - -#define LmM0EXPHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x48) - -#define LmM1SASALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x48) -#define SAS_ALIGN_DEFAULT 0xFF - -#define LmM0MSKHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x49) - -#define LmM1STPALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x49) -#define STP_ALIGN_DEFAULT 0x1F - -#define LmM0RCVHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4A) - -#define LmM1XMTHDRP(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4A) - -#define LmM0ICLADR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4B) - -#define LmM1ALIGNMODE(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4B) - -#define LmDISALIGN 0x20 -#define LmROTSTPALIGN 0x10 -#define LmSTPALIGN 0x08 -#define LmROTNOTIFY 0x04 -#define LmDUALALIGN 0x02 -#define LmROTALIGN 0x01 - -#define LmM0EXPRCVNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4C) - -#define LmM1XMTCNT(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4C) - -#define LmMnBUFSTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x4E) - -#define LmMnBUFPERR 0x01 - -/* mode 0-1 */ -#define LmMnXFRLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x59) - -#define LmMnXFRLVL_128 0x05 -#define LmMnXFRLVL_256 0x04 -#define LmMnXFRLVL_512 0x03 -#define LmMnXFRLVL_1024 0x02 -#define LmMnXFRLVL_1536 0x01 -#define LmMnXFRLVL_2048 0x00 - - /* mode 0-1 */ -#define LmMnSGDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5A) - -#define LmMnRESETSG 0x04 -#define LmMnSTOPSG 0x02 -#define LmMnSTARTSG 0x01 - -/* mode 0-1 */ -#define LmMnSGDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5B) - -/* mode 0-1 */ -#define LmMnDDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5C) - -#define LmMnFLUSH 0x40 /* wo */ -#define LmMnRLSRTRY 0x20 /* wo */ -#define LmMnDISCARD 0x10 /* wo */ -#define LmMnRESETDAT 0x08 /* wo */ -#define LmMnSUSDAT 0x04 /* wo */ -#define LmMnSTOPDAT 0x02 /* wo */ -#define LmMnSTARTDAT 0x01 /* wo */ - -/* mode 0-1 */ -#define LmMnDDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5D) - -#define LmMnDPEMPTY 0x80 -#define LmMnFLUSHING 0x40 -#define LmMnDDMAREQ 0x20 -#define LmMnHDMAREQ 0x10 -#define LmMnDATFREE 0x08 -#define LmMnDATSUS 0x04 -#define LmMnDATACT 0x02 -#define LmMnDATEN 0x01 - -/* mode 0-1 */ -#define LmMnDDMAMODE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5E) - -#define LmMnDMATYPE_NORMAL 0x0000 -#define LmMnDMATYPE_HOST_ONLY_TX 0x0001 -#define LmMnDMATYPE_DEVICE_ONLY_TX 0x0002 -#define LmMnDMATYPE_INVALID 0x0003 -#define LmMnDMATYPE_MASK 0x0003 - -#define LmMnDMAWRAP 0x0004 -#define LmMnBITBUCKET 0x0008 -#define LmMnDISHDR 0x0010 -#define LmMnSTPCRC 0x0020 -#define LmXTEST 0x0040 -#define LmMnDISCRC 0x0080 -#define LmMnENINTLK 0x0100 -#define LmMnADDRFRM 0x0400 -#define LmMnENXMTCRC 0x0800 - -/* mode 0-1 */ -#define LmMnXFRCNT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x70) - -/* mode 0-1 */ -#define LmMnDPSEL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7B) -#define LmMnDPSEL_MASK 0x07 -#define LmMnEOLPRE 0x40 -#define LmMnEOSPRE 0x80 - -/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */ -/* Receive Mode n = 0 */ -#define LmMnHRADDR 0x00 -#define LmMnHBYTECNT 0x01 -#define LmMnHREWIND 0x02 -#define LmMnDWADDR 0x03 -#define LmMnDSPACECNT 0x04 -#define LmMnDFRMSIZE 0x05 - -/* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */ -/* Transmit Mode n = 1 */ -#define LmMnHWADDR 0x00 -#define LmMnHSPACECNT 0x01 -/* #define LmMnHREWIND 0x02 */ -#define LmMnDRADDR 0x03 -#define LmMnDBYTECNT 0x04 -/* #define LmMnDFRMSIZE 0x05 */ - -/* mode 0-1 */ -#define LmMnDPACC(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x78) -#define LmMnDPACC_MASK 0x00FFFFFF - -/* mode 0-1 */ -#define LmMnHOLDLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7D) - -#define LmPRMSTAT0(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x80) -#define LmPRMSTAT0BYTE0 0x80 -#define LmPRMSTAT0BYTE1 0x81 -#define LmPRMSTAT0BYTE2 0x82 -#define LmPRMSTAT0BYTE3 0x83 - -#define LmFRAMERCVD 0x80000000 -#define LmXFRRDYRCVD 0x40000000 -#define LmUNKNOWNP 0x20000000 -#define LmBREAK 0x10000000 -#define LmDONE 0x08000000 -#define LmOPENACPT 0x04000000 -#define LmOPENRJCT 0x02000000 -#define LmOPENRTRY 0x01000000 -#define LmCLOSERV1 0x00800000 -#define LmCLOSERV0 0x00400000 -#define LmCLOSENORM 0x00200000 -#define LmCLOSECLAF 0x00100000 -#define LmNOTIFYRV2 0x00080000 -#define LmNOTIFYRV1 0x00040000 -#define LmNOTIFYRV0 0x00020000 -#define LmNOTIFYSPIN 0x00010000 -#define LmBROADRV4 0x00008000 -#define LmBROADRV3 0x00004000 -#define LmBROADRV2 0x00002000 -#define LmBROADRV1 0x00001000 -#define LmBROADSES 0x00000800 -#define LmBROADRVCH1 0x00000400 -#define LmBROADRVCH0 0x00000200 -#define LmBROADCH 0x00000100 -#define LmAIPRVWP 0x00000080 -#define LmAIPWP 0x00000040 -#define LmAIPWD 0x00000020 -#define LmAIPWC 0x00000010 -#define LmAIPRV2 0x00000008 -#define LmAIPRV1 0x00000004 -#define LmAIPRV0 0x00000002 -#define LmAIPNRML 0x00000001 - -#define LmBROADCAST_MASK (LmBROADCH | LmBROADRVCH0 | \ - LmBROADRVCH1) - -#define LmPRMSTAT1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x84) -#define LmPRMSTAT1BYTE0 0x84 -#define LmPRMSTAT1BYTE1 0x85 -#define LmPRMSTAT1BYTE2 0x86 -#define LmPRMSTAT1BYTE3 0x87 - -#define LmFRMRCVDSTAT 0x80000000 -#define LmBREAK_DET 0x04000000 -#define LmCLOSE_DET 0x02000000 -#define LmDONE_DET 0x01000000 -#define LmXRDY 0x00040000 -#define LmSYNCSRST 0x00020000 -#define LmSYNC 0x00010000 -#define LmXHOLD 0x00008000 -#define LmRRDY 0x00004000 -#define LmHOLD 0x00002000 -#define LmROK 0x00001000 -#define LmRIP 0x00000800 -#define LmCRBLK 0x00000400 -#define LmACK 0x00000200 -#define LmNAK 0x00000100 -#define LmHARDRST 0x00000080 -#define LmERROR 0x00000040 -#define LmRERR 0x00000020 -#define LmPMREQP 0x00000010 -#define LmPMREQS 0x00000008 -#define LmPMACK 0x00000004 -#define LmPMNAK 0x00000002 -#define LmDMAT 0x00000001 - -/* mode 1 */ -#define LmMnSATAFS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7E) -#define LmMnXMTSIZE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x93) - -/* mode 0 */ -#define LmMnFRMERR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xB0) - -#define LmACRCERR 0x00000800 -#define LmPHYOVRN 0x00000400 -#define LmOBOVRN 0x00000200 -#define LmMnZERODATA 0x00000100 -#define LmSATAINTLK 0x00000080 -#define LmMnCRCERR 0x00000020 -#define LmRRDYOVRN 0x00000010 -#define LmMISSSOAF 0x00000008 -#define LmMISSSOF 0x00000004 -#define LmMISSEOAF 0x00000002 -#define LmMISSEOF 0x00000001 - -#define LmFRMERREN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xB4) - -#define EN_LmACRCERR 0x00000800 -#define EN_LmPHYOVRN 0x00000400 -#define EN_LmOBOVRN 0x00000200 -#define EN_LmMnZERODATA 0x00000100 -#define EN_LmSATAINTLK 0x00000080 -#define EN_LmFRMBAD 0x00000040 -#define EN_LmMnCRCERR 0x00000020 -#define EN_LmRRDYOVRN 0x00000010 -#define EN_LmMISSSOAF 0x00000008 -#define EN_LmMISSSOF 0x00000004 -#define EN_LmMISSEOAF 0x00000002 -#define EN_LmMISSEOF 0x00000001 - -#define LmFRMERREN_MASK (EN_LmSATAINTLK | EN_LmMnCRCERR | \ - EN_LmRRDYOVRN | EN_LmMISSSOF | \ - EN_LmMISSEOAF | EN_LmMISSEOF | \ - EN_LmACRCERR | LmPHYOVRN | \ - EN_LmOBOVRN | EN_LmMnZERODATA) - -#define LmHWTSTATEN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC5) - -#define EN_LmDONETO 0x80 -#define EN_LmINVDISP 0x40 -#define EN_LmINVDW 0x20 -#define EN_LmDWSEVENT 0x08 -#define EN_LmCRTTTO 0x04 -#define EN_LmANTTTO 0x02 -#define EN_LmBITLTTO 0x01 - -#define LmHWTSTATEN_MASK (EN_LmINVDISP | EN_LmINVDW | \ - EN_LmDWSEVENT | EN_LmCRTTTO | \ - EN_LmANTTTO | EN_LmDONETO | \ - EN_LmBITLTTO) - -#define LmHWTSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC7) - -#define LmDONETO 0x80 -#define LmINVDISP 0x40 -#define LmINVDW 0x20 -#define LmDWSEVENT 0x08 -#define LmCRTTTO 0x04 -#define LmANTTTO 0x02 -#define LmBITLTTO 0x01 - -#define LmMnDATABUFADR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xC8) -#define LmDATABUFADR_MASK 0x0FFF - -#define LmMnDATABUF(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xCA) - -#define LmPRIMSTAT0EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE0) - -#define EN_LmUNKNOWNP 0x20000000 -#define EN_LmBREAK 0x10000000 -#define EN_LmDONE 0x08000000 -#define EN_LmOPENACPT 0x04000000 -#define EN_LmOPENRJCT 0x02000000 -#define EN_LmOPENRTRY 0x01000000 -#define EN_LmCLOSERV1 0x00800000 -#define EN_LmCLOSERV0 0x00400000 -#define EN_LmCLOSENORM 0x00200000 -#define EN_LmCLOSECLAF 0x00100000 -#define EN_LmNOTIFYRV2 0x00080000 -#define EN_LmNOTIFYRV1 0x00040000 -#define EN_LmNOTIFYRV0 0x00020000 -#define EN_LmNOTIFYSPIN 0x00010000 -#define EN_LmBROADRV4 0x00008000 -#define EN_LmBROADRV3 0x00004000 -#define EN_LmBROADRV2 0x00002000 -#define EN_LmBROADRV1 0x00001000 -#define EN_LmBROADRV0 0x00000800 -#define EN_LmBROADRVCH1 0x00000400 -#define EN_LmBROADRVCH0 0x00000200 -#define EN_LmBROADCH 0x00000100 -#define EN_LmAIPRVWP 0x00000080 -#define EN_LmAIPWP 0x00000040 -#define EN_LmAIPWD 0x00000020 -#define EN_LmAIPWC 0x00000010 -#define EN_LmAIPRV2 0x00000008 -#define EN_LmAIPRV1 0x00000004 -#define EN_LmAIPRV0 0x00000002 -#define EN_LmAIPNRML 0x00000001 - -#define LmPRIMSTAT0EN_MASK (EN_LmBREAK | \ - EN_LmDONE | EN_LmOPENACPT | \ - EN_LmOPENRJCT | EN_LmOPENRTRY | \ - EN_LmCLOSERV1 | EN_LmCLOSERV0 | \ - EN_LmCLOSENORM | EN_LmCLOSECLAF | \ - EN_LmBROADRV4 | EN_LmBROADRV3 | \ - EN_LmBROADRV2 | EN_LmBROADRV1 | \ - EN_LmBROADRV0 | EN_LmBROADRVCH1 | \ - EN_LmBROADRVCH0 | EN_LmBROADCH | \ - EN_LmAIPRVWP | EN_LmAIPWP | \ - EN_LmAIPWD | EN_LmAIPWC | \ - EN_LmAIPRV2 | EN_LmAIPRV1 | \ - EN_LmAIPRV0 | EN_LmAIPNRML) - -#define LmPRIMSTAT1EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE4) - -#define EN_LmXRDY 0x00040000 -#define EN_LmSYNCSRST 0x00020000 -#define EN_LmSYNC 0x00010000 -#define EN_LmXHOLD 0x00008000 -#define EN_LmRRDY 0x00004000 -#define EN_LmHOLD 0x00002000 -#define EN_LmROK 0x00001000 -#define EN_LmRIP 0x00000800 -#define EN_LmCRBLK 0x00000400 -#define EN_LmACK 0x00000200 -#define EN_LmNAK 0x00000100 -#define EN_LmHARDRST 0x00000080 -#define EN_LmERROR 0x00000040 -#define EN_LmRERR 0x00000020 -#define EN_LmPMREQP 0x00000010 -#define EN_LmPMREQS 0x00000008 -#define EN_LmPMACK 0x00000004 -#define EN_LmPMNAK 0x00000002 -#define EN_LmDMAT 0x00000001 - -#define LmPRIMSTAT1EN_MASK (EN_LmHARDRST | \ - EN_LmSYNCSRST | \ - EN_LmPMREQP | EN_LmPMREQS | \ - EN_LmPMACK | EN_LmPMNAK) - -#define LmSMSTATE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE8) - -#define LmSMSTATEBRK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xEC) - -#define LmSMDBGCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xF0) - - -/* - * LmSEQ CIO Bus Mode 3 Register. - * Mode 3: Configuration and Setup, IOP Context SCB. - */ -#define LmM3SATATIMER(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x48) - -#define LmM3INTVEC0(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x90) - -#define LmM3INTVEC1(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x92) - -#define LmM3INTVEC2(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x94) - -#define LmM3INTVEC3(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x96) - -#define LmM3INTVEC4(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x98) - -#define LmM3INTVEC5(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9A) - -#define LmM3INTVEC6(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9C) - -#define LmM3INTVEC7(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9E) - -#define LmM3INTVEC8(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA4) - -#define LmM3INTVEC9(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA6) - -#define LmM3INTVEC10(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB0) - -#define LmM3FRMGAP(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB4) - -#define LmBITL_TIMER(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA2) - -#define LmWWN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA8) - - -/* - * LmSEQ CIO Bus Mode 5 Registers. - * Mode 5: Phy/OOB Control and Status. - */ -#define LmSEQ_OOB_REG(phy_id, reg) LmSEQ_PHY_REG(5, (phy_id), (reg)) - -#define OOB_BFLTR 0x100 - -#define BFLTR_THR_MASK 0xF0 -#define BFLTR_TC_MASK 0x0F - -#define OOB_INIT_MIN 0x102 - -#define OOB_INIT_MAX 0x104 - -#define OOB_INIT_NEG 0x106 - -#define OOB_SAS_MIN 0x108 - -#define OOB_SAS_MAX 0x10A - -#define OOB_SAS_NEG 0x10C - -#define OOB_WAKE_MIN 0x10E - -#define OOB_WAKE_MAX 0x110 - -#define OOB_WAKE_NEG 0x112 - -#define OOB_IDLE_MAX 0x114 - -#define OOB_BURST_MAX 0x116 - -#define OOB_DATA_KBITS 0x126 - -#define OOB_ALIGN_0_DATA 0x12C - -#define OOB_ALIGN_1_DATA 0x130 - -#define D10_2_DATA_k 0x00 -#define SYNC_DATA_k 0x02 -#define ALIGN_1_DATA_k 0x04 -#define ALIGN_0_DATA_k 0x08 -#define BURST_DATA_k 0x10 - -#define OOB_PHY_RESET_COUNT 0x13C - -#define OOB_SIG_GEN 0x140 - -#define START_OOB 0x80 -#define START_DWS 0x40 -#define ALIGN_CNT3 0x30 -#define ALIGN_CNT2 0x20 -#define ALIGN_CNT1 0x10 -#define ALIGN_CNT4 0x00 -#define STOP_DWS 0x08 -#define SEND_COMSAS 0x04 -#define SEND_COMINIT 0x02 -#define SEND_COMWAKE 0x01 - -#define OOB_XMIT 0x141 - -#define TX_ENABLE 0x80 -#define XMIT_OOB_BURST 0x10 -#define XMIT_D10_2 0x08 -#define XMIT_SYNC 0x04 -#define XMIT_ALIGN_1 0x02 -#define XMIT_ALIGN_0 0x01 - -#define FUNCTION_MASK 0x142 - -#define SAS_MODE_DIS 0x80 -#define SATA_MODE_DIS 0x40 -#define SPINUP_HOLD_DIS 0x20 -#define HOT_PLUG_DIS 0x10 -#define SATA_PS_DIS 0x08 -#define FUNCTION_MASK_DEFAULT (SPINUP_HOLD_DIS | SATA_PS_DIS) - -#define OOB_MODE 0x143 - -#define SAS_MODE 0x80 -#define SATA_MODE 0x40 -#define SLOW_CLK 0x20 -#define FORCE_XMIT_15 0x08 -#define PHY_SPEED_60 0x04 -#define PHY_SPEED_30 0x02 -#define PHY_SPEED_15 0x01 - -#define CURRENT_STATUS 0x144 - -#define CURRENT_OOB_DONE 0x80 -#define CURRENT_LOSS_OF_SIGNAL 0x40 -#define CURRENT_SPINUP_HOLD 0x20 -#define CURRENT_HOT_PLUG_CNCT 0x10 -#define CURRENT_GTO_TIMEOUT 0x08 -#define CURRENT_OOB_TIMEOUT 0x04 -#define CURRENT_DEVICE_PRESENT 0x02 -#define CURRENT_OOB_ERROR 0x01 - -#define CURRENT_OOB1_ERROR (CURRENT_HOT_PLUG_CNCT | \ - CURRENT_GTO_TIMEOUT) - -#define CURRENT_OOB2_ERROR (CURRENT_HOT_PLUG_CNCT | \ - CURRENT_OOB_ERROR) - -#define DEVICE_ADDED_W_CNT (CURRENT_OOB_DONE | \ - CURRENT_HOT_PLUG_CNCT | \ - CURRENT_DEVICE_PRESENT) - -#define DEVICE_ADDED_WO_CNT (CURRENT_OOB_DONE | \ - CURRENT_DEVICE_PRESENT) - -#define DEVICE_REMOVED CURRENT_LOSS_OF_SIGNAL - -#define CURRENT_PHY_MASK (CURRENT_OOB_DONE | \ - CURRENT_LOSS_OF_SIGNAL | \ - CURRENT_SPINUP_HOLD | \ - CURRENT_HOT_PLUG_CNCT | \ - CURRENT_GTO_TIMEOUT | \ - CURRENT_DEVICE_PRESENT | \ - CURRENT_OOB_ERROR ) - -#define CURRENT_ERR_MASK (CURRENT_LOSS_OF_SIGNAL | \ - CURRENT_GTO_TIMEOUT | \ - CURRENT_OOB_TIMEOUT | \ - CURRENT_OOB_ERROR ) - -#define SPEED_MASK 0x145 - -#define SATA_SPEED_30_DIS 0x10 -#define SATA_SPEED_15_DIS 0x08 -#define SAS_SPEED_60_DIS 0x04 -#define SAS_SPEED_30_DIS 0x02 -#define SAS_SPEED_15_DIS 0x01 -#define SAS_SPEED_MASK_DEFAULT 0x00 - -#define OOB_TIMER_ENABLE 0x14D - -#define HOT_PLUG_EN 0x80 -#define RCD_EN 0x40 -#define COMTIMER_EN 0x20 -#define SNTT_EN 0x10 -#define SNLT_EN 0x04 -#define SNWT_EN 0x02 -#define ALIGN_EN 0x01 - -#define OOB_STATUS 0x14E - -#define OOB_DONE 0x80 -#define LOSS_OF_SIGNAL 0x40 /* ro */ -#define SPINUP_HOLD 0x20 -#define HOT_PLUG_CNCT 0x10 /* ro */ -#define GTO_TIMEOUT 0x08 /* ro */ -#define OOB_TIMEOUT 0x04 /* ro */ -#define DEVICE_PRESENT 0x02 /* ro */ -#define OOB_ERROR 0x01 /* ro */ - -#define OOB_STATUS_ERROR_MASK (LOSS_OF_SIGNAL | GTO_TIMEOUT | \ - OOB_TIMEOUT | OOB_ERROR) - -#define OOB_STATUS_CLEAR 0x14F - -#define OOB_DONE_CLR 0x80 -#define LOSS_OF_SIGNAL_CLR 0x40 -#define SPINUP_HOLD_CLR 0x20 -#define HOT_PLUG_CNCT_CLR 0x10 -#define GTO_TIMEOUT_CLR 0x08 -#define OOB_TIMEOUT_CLR 0x04 -#define OOB_ERROR_CLR 0x01 - -#define HOT_PLUG_DELAY 0x150 -/* In 5 ms units. 20 = 100 ms. */ -#define HOTPLUG_DELAY_TIMEOUT 20 - - -#define INT_ENABLE_2 0x15A - -#define OOB_DONE_EN 0x80 -#define LOSS_OF_SIGNAL_EN 0x40 -#define SPINUP_HOLD_EN 0x20 -#define HOT_PLUG_CNCT_EN 0x10 -#define GTO_TIMEOUT_EN 0x08 -#define OOB_TIMEOUT_EN 0x04 -#define DEVICE_PRESENT_EN 0x02 -#define OOB_ERROR_EN 0x01 - -#define PHY_CONTROL_0 0x160 - -#define PHY_LOWPWREN_TX 0x80 -#define PHY_LOWPWREN_RX 0x40 -#define SPARE_REG_160_B5 0x20 -#define OFFSET_CANCEL_RX 0x10 - -/* bits 3:2 */ -#define PHY_RXCOMCENTER_60V 0x00 -#define PHY_RXCOMCENTER_70V 0x04 -#define PHY_RXCOMCENTER_80V 0x08 -#define PHY_RXCOMCENTER_90V 0x0C -#define PHY_RXCOMCENTER_MASK 0x0C - -#define PHY_RESET 0x02 -#define SAS_DEFAULT_SEL 0x01 - -#define PHY_CONTROL_1 0x161 - -/* bits 2:0 */ -#define SATA_PHY_DETLEVEL_50mv 0x00 -#define SATA_PHY_DETLEVEL_75mv 0x01 -#define SATA_PHY_DETLEVEL_100mv 0x02 -#define SATA_PHY_DETLEVEL_125mv 0x03 -#define SATA_PHY_DETLEVEL_150mv 0x04 -#define SATA_PHY_DETLEVEL_175mv 0x05 -#define SATA_PHY_DETLEVEL_200mv 0x06 -#define SATA_PHY_DETLEVEL_225mv 0x07 -#define SATA_PHY_DETLEVEL_MASK 0x07 - -/* bits 5:3 */ -#define SAS_PHY_DETLEVEL_50mv 0x00 -#define SAS_PHY_DETLEVEL_75mv 0x08 -#define SAS_PHY_DETLEVEL_100mv 0x10 -#define SAS_PHY_DETLEVEL_125mv 0x11 -#define SAS_PHY_DETLEVEL_150mv 0x20 -#define SAS_PHY_DETLEVEL_175mv 0x21 -#define SAS_PHY_DETLEVEL_200mv 0x30 -#define SAS_PHY_DETLEVEL_225mv 0x31 -#define SAS_PHY_DETLEVEL_MASK 0x38 - -#define PHY_CONTROL_2 0x162 - -/* bits 7:5 */ -#define SATA_PHY_DRV_400mv 0x00 -#define SATA_PHY_DRV_450mv 0x20 -#define SATA_PHY_DRV_500mv 0x40 -#define SATA_PHY_DRV_550mv 0x60 -#define SATA_PHY_DRV_600mv 0x80 -#define SATA_PHY_DRV_650mv 0xA0 -#define SATA_PHY_DRV_725mv 0xC0 -#define SATA_PHY_DRV_800mv 0xE0 -#define SATA_PHY_DRV_MASK 0xE0 - -/* bits 4:3 */ -#define SATA_PREEMP_0 0x00 -#define SATA_PREEMP_1 0x08 -#define SATA_PREEMP_2 0x10 -#define SATA_PREEMP_3 0x18 -#define SATA_PREEMP_MASK 0x18 - -#define SATA_CMSH1P5 0x04 - -/* bits 1:0 */ -#define SATA_SLEW_0 0x00 -#define SATA_SLEW_1 0x01 -#define SATA_SLEW_2 0x02 -#define SATA_SLEW_3 0x03 -#define SATA_SLEW_MASK 0x03 - -#define PHY_CONTROL_3 0x163 - -/* bits 7:5 */ -#define SAS_PHY_DRV_400mv 0x00 -#define SAS_PHY_DRV_450mv 0x20 -#define SAS_PHY_DRV_500mv 0x40 -#define SAS_PHY_DRV_550mv 0x60 -#define SAS_PHY_DRV_600mv 0x80 -#define SAS_PHY_DRV_650mv 0xA0 -#define SAS_PHY_DRV_725mv 0xC0 -#define SAS_PHY_DRV_800mv 0xE0 -#define SAS_PHY_DRV_MASK 0xE0 - -/* bits 4:3 */ -#define SAS_PREEMP_0 0x00 -#define SAS_PREEMP_1 0x08 -#define SAS_PREEMP_2 0x10 -#define SAS_PREEMP_3 0x18 -#define SAS_PREEMP_MASK 0x18 - -#define SAS_CMSH1P5 0x04 - -/* bits 1:0 */ -#define SAS_SLEW_0 0x00 -#define SAS_SLEW_1 0x01 -#define SAS_SLEW_2 0x02 -#define SAS_SLEW_3 0x03 -#define SAS_SLEW_MASK 0x03 - -#define PHY_CONTROL_4 0x168 - -#define PHY_DONE_CAL_TX 0x80 -#define PHY_DONE_CAL_RX 0x40 -#define RX_TERM_LOAD_DIS 0x20 -#define TX_TERM_LOAD_DIS 0x10 -#define AUTO_TERM_CAL_DIS 0x08 -#define PHY_SIGDET_FLTR_EN 0x04 -#define OSC_FREQ 0x02 -#define PHY_START_CAL 0x01 - -/* - * HST_PCIX2 Registers, Address Range: (0x00-0xFC) - */ -#define PCIX_REG_BASE_ADR 0xB8040000 - -#define PCIC_VENDOR_ID 0x00 - -#define PCIC_DEVICE_ID 0x02 - -#define PCIC_COMMAND 0x04 - -#define INT_DIS 0x0400 -#define FBB_EN 0x0200 /* ro */ -#define SERR_EN 0x0100 -#define STEP_EN 0x0080 /* ro */ -#define PERR_EN 0x0040 -#define VGA_EN 0x0020 /* ro */ -#define MWI_EN 0x0010 -#define SPC_EN 0x0008 -#define MST_EN 0x0004 -#define MEM_EN 0x0002 -#define IO_EN 0x0001 - -#define PCIC_STATUS 0x06 - -#define PERR_DET 0x8000 -#define SERR_GEN 0x4000 -#define MABT_DET 0x2000 -#define TABT_DET 0x1000 -#define TABT_GEN 0x0800 -#define DPERR_DET 0x0100 -#define CAP_LIST 0x0010 -#define INT_STAT 0x0008 - -#define PCIC_DEVREV_ID 0x08 - -#define PCIC_CLASS_CODE 0x09 - -#define PCIC_CACHELINE_SIZE 0x0C - -#define PCIC_MBAR0 0x10 - -#define PCIC_MBAR0_OFFSET 0 - -#define PCIC_MBAR1 0x18 - -#define PCIC_MBAR1_OFFSET 2 - -#define PCIC_IOBAR 0x20 - -#define PCIC_IOBAR_OFFSET 4 - -#define PCIC_SUBVENDOR_ID 0x2C - -#define PCIC_SUBSYTEM_ID 0x2E - -#define PCIX_STATUS 0x44 -#define RCV_SCE 0x20000000 -#define UNEXP_SC 0x00080000 -#define SC_DISCARD 0x00040000 - -#define ECC_CTRL_STAT 0x48 -#define UNCOR_ECCERR 0x00000008 - -#define PCIC_PM_CSR 0x5C - -#define PWR_STATE_D0 0 -#define PWR_STATE_D1 1 /* not supported */ -#define PWR_STATE_D2 2 /* not supported */ -#define PWR_STATE_D3 3 - -#define PCIC_BASE1 0x6C /* internal use only */ - -#define BASE1_RSVD 0xFFFFFFF8 - -#define PCIC_BASEA 0x70 /* internal use only */ - -#define BASEA_RSVD 0xFFFFFFC0 -#define BASEA_START 0 - -#define PCIC_BASEB 0x74 /* internal use only */ - -#define BASEB_RSVD 0xFFFFFF80 -#define BASEB_IOMAP_MASK 0x7F -#define BASEB_START 0x80 - -#define PCIC_BASEC 0x78 /* internal use only */ - -#define BASEC_RSVD 0xFFFFFFFC -#define BASEC_MASK 0x03 -#define BASEC_START 0x58 - -#define PCIC_MBAR_KEY 0x7C /* internal use only */ - -#define MBAR_KEY_MASK 0xFFFFFFFF - -#define PCIC_HSTPCIX_CNTRL 0xA0 - -#define REWIND_DIS 0x0800 -#define SC_TMR_DIS 0x04000000 - -#define PCIC_MBAR0_MASK 0xA8 -#define PCIC_MBAR0_SIZE_MASK 0x1FFFE000 -#define PCIC_MBAR0_SIZE_SHIFT 13 -#define PCIC_MBAR0_SIZE(val) \ - (((val) & PCIC_MBAR0_SIZE_MASK) >> PCIC_MBAR0_SIZE_SHIFT) - -#define PCIC_FLASH_MBAR 0xB8 - -#define PCIC_INTRPT_STAT 0xD4 - -#define PCIC_TP_CTRL 0xFC - -/* - * EXSI Registers, Address Range: (0x00-0xFC) - */ -#define EXSI_REG_BASE_ADR REG_BASE_ADDR_EXSI - -#define EXSICNFGR (EXSI_REG_BASE_ADR + 0x00) - -#define OCMINITIALIZED 0x80000000 -#define ASIEN 0x00400000 -#define HCMODE 0x00200000 -#define PCIDEF 0x00100000 -#define COMSTOCK 0x00080000 -#define SEEPROMEND 0x00040000 -#define MSTTIMEN 0x00020000 -#define XREGEX 0x00000200 -#define NVRAMW 0x00000100 -#define NVRAMEX 0x00000080 -#define SRAMW 0x00000040 -#define SRAMEX 0x00000020 -#define FLASHW 0x00000010 -#define FLASHEX 0x00000008 -#define SEEPROMCFG 0x00000004 -#define SEEPROMTYP 0x00000002 -#define SEEPROMEX 0x00000001 - - -#define EXSICNTRLR (EXSI_REG_BASE_ADR + 0x04) - -#define MODINT_EN 0x00000001 - - -#define PMSTATR (EXSI_REG_BASE_ADR + 0x10) - -#define FLASHRST 0x00000002 -#define FLASHRDY 0x00000001 - - -#define FLCNFGR (EXSI_REG_BASE_ADR + 0x14) - -#define FLWEH_MASK 0x30000000 -#define FLWESU_MASK 0x0C000000 -#define FLWEPW_MASK 0x03F00000 -#define FLOEH_MASK 0x000C0000 -#define FLOESU_MASK 0x00030000 -#define FLOEPW_MASK 0x0000FC00 -#define FLCSH_MASK 0x00000300 -#define FLCSSU_MASK 0x000000C0 -#define FLCSPW_MASK 0x0000003F - -#define SRCNFGR (EXSI_REG_BASE_ADR + 0x18) - -#define SRWEH_MASK 0x30000000 -#define SRWESU_MASK 0x0C000000 -#define SRWEPW_MASK 0x03F00000 - -#define SROEH_MASK 0x000C0000 -#define SROESU_MASK 0x00030000 -#define SROEPW_MASK 0x0000FC00 -#define SRCSH_MASK 0x00000300 -#define SRCSSU_MASK 0x000000C0 -#define SRCSPW_MASK 0x0000003F - -#define NVCNFGR (EXSI_REG_BASE_ADR + 0x1C) - -#define NVWEH_MASK 0x30000000 -#define NVWESU_MASK 0x0C000000 -#define NVWEPW_MASK 0x03F00000 -#define NVOEH_MASK 0x000C0000 -#define NVOESU_MASK 0x00030000 -#define NVOEPW_MASK 0x0000FC00 -#define NVCSH_MASK 0x00000300 -#define NVCSSU_MASK 0x000000C0 -#define NVCSPW_MASK 0x0000003F - -#define XRCNFGR (EXSI_REG_BASE_ADR + 0x20) - -#define XRWEH_MASK 0x30000000 -#define XRWESU_MASK 0x0C000000 -#define XRWEPW_MASK 0x03F00000 -#define XROEH_MASK 0x000C0000 -#define XROESU_MASK 0x00030000 -#define XROEPW_MASK 0x0000FC00 -#define XRCSH_MASK 0x00000300 -#define XRCSSU_MASK 0x000000C0 -#define XRCSPW_MASK 0x0000003F - -#define XREGADDR (EXSI_REG_BASE_ADR + 0x24) - -#define XRADDRINCEN 0x80000000 -#define XREGADD_MASK 0x007FFFFF - - -#define XREGDATAR (EXSI_REG_BASE_ADR + 0x28) - -#define XREGDATA_MASK 0x0000FFFF - -#define GPIOOER (EXSI_REG_BASE_ADR + 0x40) - -#define GPIOODENR (EXSI_REG_BASE_ADR + 0x44) - -#define GPIOINVR (EXSI_REG_BASE_ADR + 0x48) - -#define GPIODATAOR (EXSI_REG_BASE_ADR + 0x4C) - -#define GPIODATAIR (EXSI_REG_BASE_ADR + 0x50) - -#define GPIOCNFGR (EXSI_REG_BASE_ADR + 0x54) - -#define GPIO_EXTSRC 0x00000001 - -#define SCNTRLR (EXSI_REG_BASE_ADR + 0xA0) - -#define SXFERDONE 0x00000100 -#define SXFERCNT_MASK 0x000000E0 -#define SCMDTYP_MASK 0x0000001C -#define SXFERSTART 0x00000002 -#define SXFEREN 0x00000001 - -#define SRATER (EXSI_REG_BASE_ADR + 0xA4) - -#define SADDRR (EXSI_REG_BASE_ADR + 0xA8) - -#define SADDR_MASK 0x0000FFFF - -#define SDATAOR (EXSI_REG_BASE_ADR + 0xAC) - -#define SDATAOR0 (EXSI_REG_BASE_ADR + 0xAC) -#define SDATAOR1 (EXSI_REG_BASE_ADR + 0xAD) -#define SDATAOR2 (EXSI_REG_BASE_ADR + 0xAE) -#define SDATAOR3 (EXSI_REG_BASE_ADR + 0xAF) - -#define SDATAIR (EXSI_REG_BASE_ADR + 0xB0) - -#define SDATAIR0 (EXSI_REG_BASE_ADR + 0xB0) -#define SDATAIR1 (EXSI_REG_BASE_ADR + 0xB1) -#define SDATAIR2 (EXSI_REG_BASE_ADR + 0xB2) -#define SDATAIR3 (EXSI_REG_BASE_ADR + 0xB3) - -#define ASISTAT0R (EXSI_REG_BASE_ADR + 0xD0) -#define ASIFMTERR 0x00000400 -#define ASISEECHKERR 0x00000200 -#define ASIERR 0x00000100 - -#define ASISTAT1R (EXSI_REG_BASE_ADR + 0xD4) -#define CHECKSUM_MASK 0x0000FFFF - -#define ASIERRADDR (EXSI_REG_BASE_ADR + 0xD8) -#define ASIERRDATAR (EXSI_REG_BASE_ADR + 0xDC) -#define ASIERRSTATR (EXSI_REG_BASE_ADR + 0xE0) -#define CPI2ASIBYTECNT_MASK 0x00070000 -#define CPI2ASIBYTEEN_MASK 0x0000F000 -#define CPI2ASITARGERR_MASK 0x00000F00 -#define CPI2ASITARGMID_MASK 0x000000F0 -#define CPI2ASIMSTERR_MASK 0x0000000F - -/* - * XSRAM, External SRAM (DWord and any BE pattern accessible) - */ -#define XSRAM_REG_BASE_ADDR 0xB8100000 -#define XSRAM_SIZE 0x100000 - -/* - * NVRAM Registers, Address Range: (0x00000 - 0x3FFFF). - */ -#define NVRAM_REG_BASE_ADR 0xBF800000 -#define NVRAM_MAX_BASE_ADR 0x003FFFFF - -/* OCM base address */ -#define OCM_BASE_ADDR 0xA0000000 -#define OCM_MAX_SIZE 0x20000 - -/* - * Sequencers (Central and Link) Scratch RAM page definitions. - */ - -/* - * The Central Management Sequencer (CSEQ) Scratch Memory is a 1024 - * byte memory. It is dword accessible and has byte parity - * protection. The CSEQ accesses it in 32 byte windows, either as mode - * dependent or mode independent memory. Each mode has 96 bytes, - * (three 32 byte pages 0-2, not contiguous), leaving 128 bytes of - * Mode Independent memory (four 32 byte pages 3-7). Note that mode - * dependent scratch memory, Mode 8, page 0-3 overlaps mode - * independent scratch memory, pages 0-3. - * - 896 bytes of mode dependent scratch, 96 bytes per Modes 0-7, and - * 128 bytes in mode 8, - * - 259 bytes of mode independent scratch, common to modes 0-15. - * - * Sequencer scratch RAM is 1024 bytes. This scratch memory is - * divided into mode dependent and mode independent scratch with this - * memory further subdivided into pages of size 32 bytes. There are 5 - * pages (160 bytes) of mode independent scratch and 3 pages of - * dependent scratch memory for modes 0-7 (768 bytes). Mode 8 pages - * 0-2 dependent scratch overlap with pages 0-2 of mode independent - * scratch memory. - * - * The host accesses this scratch in a different manner from the - * central sequencer. The sequencer has to use CSEQ registers CSCRPAGE - * and CMnSCRPAGE to access the scratch memory. A flat mapping of the - * scratch memory is available for software convenience and to prevent - * corruption while the sequencer is running. This memory is mapped - * onto addresses 800h - BFFh, total of 400h bytes. - * - * These addresses are mapped as follows: - * - * 800h-83Fh Mode Dependent Scratch Mode 0 Pages 0-1 - * 840h-87Fh Mode Dependent Scratch Mode 1 Pages 0-1 - * 880h-8BFh Mode Dependent Scratch Mode 2 Pages 0-1 - * 8C0h-8FFh Mode Dependent Scratch Mode 3 Pages 0-1 - * 900h-93Fh Mode Dependent Scratch Mode 4 Pages 0-1 - * 940h-97Fh Mode Dependent Scratch Mode 5 Pages 0-1 - * 980h-9BFh Mode Dependent Scratch Mode 6 Pages 0-1 - * 9C0h-9FFh Mode Dependent Scratch Mode 7 Pages 0-1 - * A00h-A5Fh Mode Dependent Scratch Mode 8 Pages 0-2 - * Mode Independent Scratch Pages 0-2 - * A60h-A7Fh Mode Dependent Scratch Mode 8 Page 3 - * Mode Independent Scratch Page 3 - * A80h-AFFh Mode Independent Scratch Pages 4-7 - * B00h-B1Fh Mode Dependent Scratch Mode 0 Page 2 - * B20h-B3Fh Mode Dependent Scratch Mode 1 Page 2 - * B40h-B5Fh Mode Dependent Scratch Mode 2 Page 2 - * B60h-B7Fh Mode Dependent Scratch Mode 3 Page 2 - * B80h-B9Fh Mode Dependent Scratch Mode 4 Page 2 - * BA0h-BBFh Mode Dependent Scratch Mode 5 Page 2 - * BC0h-BDFh Mode Dependent Scratch Mode 6 Page 2 - * BE0h-BFFh Mode Dependent Scratch Mode 7 Page 2 - */ - -/* General macros */ -#define CSEQ_PAGE_SIZE 32 /* Scratch page size (in bytes) */ - -/* All macros start with offsets from base + 0x800 (CMAPPEDSCR). - * Mode dependent scratch page 0, mode 0. - * For modes 1-7 you have to do arithmetic. */ -#define CSEQ_LRM_SAVE_SINDEX (CMAPPEDSCR + 0x0000) -#define CSEQ_LRM_SAVE_SCBPTR (CMAPPEDSCR + 0x0002) -#define CSEQ_Q_LINK_HEAD (CMAPPEDSCR + 0x0004) -#define CSEQ_Q_LINK_TAIL (CMAPPEDSCR + 0x0006) -#define CSEQ_LRM_SAVE_SCRPAGE (CMAPPEDSCR + 0x0008) - -/* Mode dependent scratch page 0 mode 8 macros. */ -#define CSEQ_RET_ADDR (CMAPPEDSCR + 0x0200) -#define CSEQ_RET_SCBPTR (CMAPPEDSCR + 0x0202) -#define CSEQ_SAVE_SCBPTR (CMAPPEDSCR + 0x0204) -#define CSEQ_EMPTY_TRANS_CTX (CMAPPEDSCR + 0x0206) -#define CSEQ_RESP_LEN (CMAPPEDSCR + 0x0208) -#define CSEQ_TMF_SCBPTR (CMAPPEDSCR + 0x020A) -#define CSEQ_GLOBAL_PREV_SCB (CMAPPEDSCR + 0x020C) -#define CSEQ_GLOBAL_HEAD (CMAPPEDSCR + 0x020E) -#define CSEQ_CLEAR_LU_HEAD (CMAPPEDSCR + 0x0210) -#define CSEQ_TMF_OPCODE (CMAPPEDSCR + 0x0212) -#define CSEQ_SCRATCH_FLAGS (CMAPPEDSCR + 0x0213) -#define CSEQ_HSB_SITE (CMAPPEDSCR + 0x021A) -#define CSEQ_FIRST_INV_SCB_SITE (CMAPPEDSCR + 0x021C) -#define CSEQ_FIRST_INV_DDB_SITE (CMAPPEDSCR + 0x021E) - -/* Mode dependent scratch page 1 mode 8 macros. */ -#define CSEQ_LUN_TO_CLEAR (CMAPPEDSCR + 0x0220) -#define CSEQ_LUN_TO_CHECK (CMAPPEDSCR + 0x0228) - -/* Mode dependent scratch page 2 mode 8 macros */ -#define CSEQ_HQ_NEW_POINTER (CMAPPEDSCR + 0x0240) -#define CSEQ_HQ_DONE_BASE (CMAPPEDSCR + 0x0248) -#define CSEQ_HQ_DONE_POINTER (CMAPPEDSCR + 0x0250) -#define CSEQ_HQ_DONE_PASS (CMAPPEDSCR + 0x0254) - -/* Mode independent scratch page 4 macros. */ -#define CSEQ_Q_EXE_HEAD (CMAPPEDSCR + 0x0280) -#define CSEQ_Q_EXE_TAIL (CMAPPEDSCR + 0x0282) -#define CSEQ_Q_DONE_HEAD (CMAPPEDSCR + 0x0284) -#define CSEQ_Q_DONE_TAIL (CMAPPEDSCR + 0x0286) -#define CSEQ_Q_SEND_HEAD (CMAPPEDSCR + 0x0288) -#define CSEQ_Q_SEND_TAIL (CMAPPEDSCR + 0x028A) -#define CSEQ_Q_DMA2CHIM_HEAD (CMAPPEDSCR + 0x028C) -#define CSEQ_Q_DMA2CHIM_TAIL (CMAPPEDSCR + 0x028E) -#define CSEQ_Q_COPY_HEAD (CMAPPEDSCR + 0x0290) -#define CSEQ_Q_COPY_TAIL (CMAPPEDSCR + 0x0292) -#define CSEQ_REG0 (CMAPPEDSCR + 0x0294) -#define CSEQ_REG1 (CMAPPEDSCR + 0x0296) -#define CSEQ_REG2 (CMAPPEDSCR + 0x0298) -#define CSEQ_LINK_CTL_Q_MAP (CMAPPEDSCR + 0x029C) -#define CSEQ_MAX_CSEQ_MODE (CMAPPEDSCR + 0x029D) -#define CSEQ_FREE_LIST_HACK_COUNT (CMAPPEDSCR + 0x029E) - -/* Mode independent scratch page 5 macros. */ -#define CSEQ_EST_NEXUS_REQ_QUEUE (CMAPPEDSCR + 0x02A0) -#define CSEQ_EST_NEXUS_REQ_COUNT (CMAPPEDSCR + 0x02A8) -#define CSEQ_Q_EST_NEXUS_HEAD (CMAPPEDSCR + 0x02B0) -#define CSEQ_Q_EST_NEXUS_TAIL (CMAPPEDSCR + 0x02B2) -#define CSEQ_NEED_EST_NEXUS_SCB (CMAPPEDSCR + 0x02B4) -#define CSEQ_EST_NEXUS_REQ_HEAD (CMAPPEDSCR + 0x02B6) -#define CSEQ_EST_NEXUS_REQ_TAIL (CMAPPEDSCR + 0x02B7) -#define CSEQ_EST_NEXUS_SCB_OFFSET (CMAPPEDSCR + 0x02B8) - -/* Mode independent scratch page 6 macros. */ -#define CSEQ_INT_ROUT_RET_ADDR0 (CMAPPEDSCR + 0x02C0) -#define CSEQ_INT_ROUT_RET_ADDR1 (CMAPPEDSCR + 0x02C2) -#define CSEQ_INT_ROUT_SCBPTR (CMAPPEDSCR + 0x02C4) -#define CSEQ_INT_ROUT_MODE (CMAPPEDSCR + 0x02C6) -#define CSEQ_ISR_SCRATCH_FLAGS (CMAPPEDSCR + 0x02C7) -#define CSEQ_ISR_SAVE_SINDEX (CMAPPEDSCR + 0x02C8) -#define CSEQ_ISR_SAVE_DINDEX (CMAPPEDSCR + 0x02CA) -#define CSEQ_Q_MONIRTT_HEAD (CMAPPEDSCR + 0x02D0) -#define CSEQ_Q_MONIRTT_TAIL (CMAPPEDSCR + 0x02D2) -#define CSEQ_FREE_SCB_MASK (CMAPPEDSCR + 0x02D5) -#define CSEQ_BUILTIN_FREE_SCB_HEAD (CMAPPEDSCR + 0x02D6) -#define CSEQ_BUILTIN_FREE_SCB_TAIL (CMAPPEDSCR + 0x02D8) -#define CSEQ_EXTENDED_FREE_SCB_HEAD (CMAPPEDSCR + 0x02DA) -#define CSEQ_EXTENDED_FREE_SCB_TAIL (CMAPPEDSCR + 0x02DC) - -/* Mode independent scratch page 7 macros. */ -#define CSEQ_EMPTY_REQ_QUEUE (CMAPPEDSCR + 0x02E0) -#define CSEQ_EMPTY_REQ_COUNT (CMAPPEDSCR + 0x02E8) -#define CSEQ_Q_EMPTY_HEAD (CMAPPEDSCR + 0x02F0) -#define CSEQ_Q_EMPTY_TAIL (CMAPPEDSCR + 0x02F2) -#define CSEQ_NEED_EMPTY_SCB (CMAPPEDSCR + 0x02F4) -#define CSEQ_EMPTY_REQ_HEAD (CMAPPEDSCR + 0x02F6) -#define CSEQ_EMPTY_REQ_TAIL (CMAPPEDSCR + 0x02F7) -#define CSEQ_EMPTY_SCB_OFFSET (CMAPPEDSCR + 0x02F8) -#define CSEQ_PRIMITIVE_DATA (CMAPPEDSCR + 0x02FA) -#define CSEQ_TIMEOUT_CONST (CMAPPEDSCR + 0x02FC) - -/*************************************************************************** -* Link m Sequencer scratch RAM is 512 bytes. -* This scratch memory is divided into mode dependent and mode -* independent scratch with this memory further subdivided into -* pages of size 32 bytes. There are 4 pages (128 bytes) of -* mode independent scratch and 4 pages of dependent scratch -* memory for modes 0-2 (384 bytes). -* -* The host accesses this scratch in a different manner from the -* link sequencer. The sequencer has to use LSEQ registers -* LmSCRPAGE and LmMnSCRPAGE to access the scratch memory. A flat -* mapping of the scratch memory is available for software -* convenience and to prevent corruption while the sequencer is -* running. This memory is mapped onto addresses 800h - 9FFh. -* -* These addresses are mapped as follows: -* -* 800h-85Fh Mode Dependent Scratch Mode 0 Pages 0-2 -* 860h-87Fh Mode Dependent Scratch Mode 0 Page 3 -* Mode Dependent Scratch Mode 5 Page 0 -* 880h-8DFh Mode Dependent Scratch Mode 1 Pages 0-2 -* 8E0h-8FFh Mode Dependent Scratch Mode 1 Page 3 -* Mode Dependent Scratch Mode 5 Page 1 -* 900h-95Fh Mode Dependent Scratch Mode 2 Pages 0-2 -* 960h-97Fh Mode Dependent Scratch Mode 2 Page 3 -* Mode Dependent Scratch Mode 5 Page 2 -* 980h-9DFh Mode Independent Scratch Pages 0-3 -* 9E0h-9FFh Mode Independent Scratch Page 3 -* Mode Dependent Scratch Mode 5 Page 3 -* -****************************************************************************/ -/* General macros */ -#define LSEQ_MODE_SCRATCH_SIZE 0x80 /* Size of scratch RAM per mode */ -#define LSEQ_PAGE_SIZE 0x20 /* Scratch page size (in bytes) */ -#define LSEQ_MODE5_PAGE0_OFFSET 0x60 - -/* Common mode dependent scratch page 0 macros for modes 0,1,2, and 5 */ -/* Indexed using LSEQ_MODE_SCRATCH_SIZE * mode, for modes 0,1,2. */ -#define LmSEQ_RET_ADDR(LinkNum) (LmSCRATCH(LinkNum) + 0x0000) -#define LmSEQ_REG0_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0002) -#define LmSEQ_MODE_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0004) - -/* Mode flag macros (byte 0) */ -#define SAS_SAVECTX_OCCURRED 0x80 -#define SAS_OOBSVC_OCCURRED 0x40 -#define SAS_OOB_DEVICE_PRESENT 0x20 -#define SAS_CFGHDR_OCCURRED 0x10 -#define SAS_RCV_INTS_ARE_DISABLED 0x08 -#define SAS_OOB_HOT_PLUG_CNCT 0x04 -#define SAS_AWAIT_OPEN_CONNECTION 0x02 -#define SAS_CFGCMPLT_OCCURRED 0x01 - -/* Mode flag macros (byte 1) */ -#define SAS_RLSSCB_OCCURRED 0x80 -#define SAS_FORCED_HEADER_MISS 0x40 - -#define LmSEQ_RET_ADDR2(LinkNum) (LmSCRATCH(LinkNum) + 0x0006) -#define LmSEQ_RET_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0008) -#define LmSEQ_OPCODE_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000B) -#define LmSEQ_DATA_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000C) - -/* Mode dependent scratch page 0 macros for mode 0 (non-common) */ -/* Absolute offsets */ -#define LmSEQ_FIRST_INV_DDB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x000E) -#define LmSEQ_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0010) -#define LmSEQ_RESP_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x0012) -#define LmSEQ_FIRST_INV_SCB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x0014) -#define LmSEQ_INTEN_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0016) -#define LmSEQ_LINK_RST_FRM_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x001A) -#define LmSEQ_LINK_RST_PROTOCOL(LinkNum) (LmSCRATCH(LinkNum) + 0x001B) -#define LmSEQ_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x001C) -#define LmSEQ_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x001D) -#define LmSEQ_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x001E) - -/* Mode dependent scratch page 0 macros for mode 1 (non-common) */ -/* Absolute offsets */ -#define LmSEQ_Q_XMIT_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x008E) -#define LmSEQ_M1_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0090) -#define LmSEQ_INI_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0092) -#define LmSEQ_FAILED_OPEN_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009A) -#define LmSEQ_XMIT_REQUEST_TYPE(LinkNum) (LmSCRATCH(LinkNum) + 0x009B) -#define LmSEQ_M1_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009C) -#define LmSEQ_M1_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x009D) -#define LmSEQ_M1_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x009E) - -/* Mode dependent scratch page 0 macros for mode 2 (non-common) */ -#define LmSEQ_PORT_COUNTER(LinkNum) (LmSCRATCH(LinkNum) + 0x010E) -#define LmSEQ_PM_TABLE_PTR(LinkNum) (LmSCRATCH(LinkNum) + 0x0110) -#define LmSEQ_SATA_INTERLOCK_TMR_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0112) -#define LmSEQ_IP_BITL(LinkNum) (LmSCRATCH(LinkNum) + 0x0114) -#define LmSEQ_COPY_SMP_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0116) -#define LmSEQ_P0M2_OFFS1AH(LinkNum) (LmSCRATCH(LinkNum) + 0x011A) - -/* Mode dependent scratch page 0 macros for modes 4/5 (non-common) */ -/* Absolute offsets */ -#define LmSEQ_SAVED_OOB_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x006E) -#define LmSEQ_SAVED_OOB_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x006F) -#define LmSEQ_Q_LINK_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0070) -#define LmSEQ_LINK_RST_ERR(LinkNum) (LmSCRATCH(LinkNum) + 0x0072) -#define LmSEQ_SAVED_OOB_SIGNALS(LinkNum) (LmSCRATCH(LinkNum) + 0x0073) -#define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074) -#define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075) -#define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076) -#define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x0078) -#define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007A) -#define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C) -#define LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E) - -/* Mode dependent scratch page 1, mode 0 and mode 1 */ -#define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020) -#define LmSEQ_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0030) -#define LmSEQ_M1_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x00A0) -#define LmSEQ_M1_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x00B0) - -/* Mode dependent scratch page 1 macros for mode 2 */ -/* Absolute offsets */ -#define LmSEQ_INVALID_DWORD_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0120) -#define LmSEQ_DISPARITY_ERROR_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0124) -#define LmSEQ_LOSS_OF_SYNC_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0128) - -/* Mode dependent scratch page 1 macros for mode 4/5 */ -#define LmSEQ_FRAME_TYPE_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E0) -#define LmSEQ_HASHED_DEST_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E1) -#define LmSEQ_HASHED_SRC_ADDR_MASK_PRINT(LinkNum) (LmSCRATCH(LinkNum) + 0x00E4) -#define LmSEQ_HASHED_SRC_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E5) -#define LmSEQ_NUM_FILL_BYTES_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00EB) -#define LmSEQ_TAG_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00F0) -#define LmSEQ_TARGET_PORT_XFER_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x00F2) -#define LmSEQ_DATA_OFFSET(LinkNum) (LmSCRATCH(LinkNum) + 0x00F4) - -/* Mode dependent scratch page 2 macros for mode 0 */ -/* Absolute offsets */ -#define LmSEQ_SMP_RCV_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0040) -#define LmSEQ_DEVICE_BITS(LinkNum) (LmSCRATCH(LinkNum) + 0x005B) -#define LmSEQ_SDB_DDB(LinkNum) (LmSCRATCH(LinkNum) + 0x005C) -#define LmSEQ_SDB_NUM_TAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x005E) -#define LmSEQ_SDB_CURR_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x005F) - -/* Mode dependent scratch page 2 macros for mode 1 */ -/* Absolute offsets */ -/* byte 0 bits 1-0 are domain select. */ -#define LmSEQ_TX_ID_ADDR_FRAME(LinkNum) (LmSCRATCH(LinkNum) + 0x00C0) -#define LmSEQ_OPEN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00C8) -#define LmSEQ_SRST_AS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00CC) -#define LmSEQ_LAST_LOADED_SG_EL(LinkNum) (LmSCRATCH(LinkNum) + 0x00D4) - -/* Mode dependent scratch page 2 macros for mode 2 */ -/* Absolute offsets */ -#define LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0140) -#define LmSEQ_CLOSE_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0144) -#define LmSEQ_BREAK_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0148) -#define LmSEQ_DWS_RESET_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x014C) -#define LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(LinkNum) \ - (LmSCRATCH(LinkNum) + 0x0150) -#define LmSEQ_MCTL_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0154) - -/* Mode dependent scratch page 2 macros for mode 5 */ -#define LmSEQ_COMINIT_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0160) -#define LmSEQ_RCV_ID_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0164) -#define LmSEQ_RCV_FIS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0168) -#define LmSEQ_DEV_PRES_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x016C) - -/* Mode dependent scratch page 3 macros for modes 0 and 1 */ -/* None defined */ - -/* Mode dependent scratch page 3 macros for modes 2 and 5 */ -/* None defined */ - -/* Mode Independent Scratch page 0 macros. */ -#define LmSEQ_Q_TGTXFR_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0180) -#define LmSEQ_Q_TGTXFR_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x0182) -#define LmSEQ_LINK_NUMBER(LinkNum) (LmSCRATCH(LinkNum) + 0x0186) -#define LmSEQ_SCRATCH_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0187) -/* - * Currently only bit 0, SAS_DWSAQD, is used. - */ -#define SAS_DWSAQD 0x01 /* - * DWSSTATUS: DWSAQD - * bit las read in ISR. - */ -#define LmSEQ_CONNECTION_STATE(LinkNum) (LmSCRATCH(LinkNum) + 0x0188) -/* Connection states (byte 0) */ -#define SAS_WE_OPENED_CS 0x01 -#define SAS_DEVICE_OPENED_CS 0x02 -#define SAS_WE_SENT_DONE_CS 0x04 -#define SAS_DEVICE_SENT_DONE_CS 0x08 -#define SAS_WE_SENT_CLOSE_CS 0x10 -#define SAS_DEVICE_SENT_CLOSE_CS 0x20 -#define SAS_WE_SENT_BREAK_CS 0x40 -#define SAS_DEVICE_SENT_BREAK_CS 0x80 -/* Connection states (byte 1) */ -#define SAS_OPN_TIMEOUT_OR_OPN_RJCT_CS 0x01 -#define SAS_AIP_RECEIVED_CS 0x02 -#define SAS_CREDIT_TIMEOUT_OCCURRED_CS 0x04 -#define SAS_ACKNAK_TIMEOUT_OCCURRED_CS 0x08 -#define SAS_SMPRSP_TIMEOUT_OCCURRED_CS 0x10 -#define SAS_DONE_TIMEOUT_OCCURRED_CS 0x20 -/* Connection states (byte 2) */ -#define SAS_SMP_RESPONSE_RECEIVED_CS 0x01 -#define SAS_INTLK_TIMEOUT_OCCURRED_CS 0x02 -#define SAS_DEVICE_SENT_DMAT_CS 0x04 -#define SAS_DEVICE_SENT_SYNCSRST_CS 0x08 -#define SAS_CLEARING_AFFILIATION_CS 0x20 -#define SAS_RXTASK_ACTIVE_CS 0x40 -#define SAS_TXTASK_ACTIVE_CS 0x80 -/* Connection states (byte 3) */ -#define SAS_PHY_LOSS_OF_SIGNAL_CS 0x01 -#define SAS_DWS_TIMER_EXPIRED_CS 0x02 -#define SAS_LINK_RESET_NOT_COMPLETE_CS 0x04 -#define SAS_PHY_DISABLED_CS 0x08 -#define SAS_LINK_CTL_TASK_ACTIVE_CS 0x10 -#define SAS_PHY_EVENT_TASK_ACTIVE_CS 0x20 -#define SAS_DEVICE_SENT_ID_FRAME_CS 0x40 -#define SAS_DEVICE_SENT_REG_FIS_CS 0x40 -#define SAS_DEVICE_SENT_HARD_RESET_CS 0x80 -#define SAS_PHY_IS_DOWN_FLAGS (SAS_PHY_LOSS_OF_SIGNAL_CS|\ - SAS_DWS_TIMER_EXPIRED_CS |\ - SAS_LINK_RESET_NOT_COMPLETE_CS|\ - SAS_PHY_DISABLED_CS) - -#define SAS_LINK_CTL_PHY_EVENT_FLAGS (SAS_LINK_CTL_TASK_ACTIVE_CS |\ - SAS_PHY_EVENT_TASK_ACTIVE_CS |\ - SAS_DEVICE_SENT_ID_FRAME_CS |\ - SAS_DEVICE_SENT_HARD_RESET_CS) - -#define LmSEQ_CONCTL(LinkNum) (LmSCRATCH(LinkNum) + 0x018C) -#define LmSEQ_CONSTAT(LinkNum) (LmSCRATCH(LinkNum) + 0x018E) -#define LmSEQ_CONNECTION_MODES(LinkNum) (LmSCRATCH(LinkNum) + 0x018F) -#define LmSEQ_REG1_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0192) -#define LmSEQ_REG2_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0194) -#define LmSEQ_REG3_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0196) -#define LmSEQ_REG0_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0198) - -/* Mode independent scratch page 1 macros. */ -#define LmSEQ_EST_NEXUS_SCBPTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A0) -#define LmSEQ_EST_NEXUS_SCBPTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A2) -#define LmSEQ_EST_NEXUS_SCBPTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01A4) -#define LmSEQ_EST_NEXUS_SCBPTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01A6) -#define LmSEQ_EST_NEXUS_SCB_OPCODE0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A8) -#define LmSEQ_EST_NEXUS_SCB_OPCODE1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A9) -#define LmSEQ_EST_NEXUS_SCB_OPCODE2(LinkNum) (LmSCRATCH(LinkNum) + 0x01AA) -#define LmSEQ_EST_NEXUS_SCB_OPCODE3(LinkNum) (LmSCRATCH(LinkNum) + 0x01AB) -#define LmSEQ_EST_NEXUS_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01AC) -#define LmSEQ_EST_NEXUS_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AD) -#define LmSEQ_EST_NEXUS_BUF_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AE) -#define LmSEQ_TIMEOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01B8) -#define LmSEQ_ISR_SAVE_SINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BC) -#define LmSEQ_ISR_SAVE_DINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BE) - -/* Mode independent scratch page 2 macros. */ -#define LmSEQ_EMPTY_SCB_PTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C0) -#define LmSEQ_EMPTY_SCB_PTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C2) -#define LmSEQ_EMPTY_SCB_PTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01C4) -#define LmSEQ_EMPTY_SCB_PTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01C6) -#define LmSEQ_EMPTY_SCB_OPCD0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C8) -#define LmSEQ_EMPTY_SCB_OPCD1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C9) -#define LmSEQ_EMPTY_SCB_OPCD2(LinkNum) (LmSCRATCH(LinkNum) + 0x01CA) -#define LmSEQ_EMPTY_SCB_OPCD3(LinkNum) (LmSCRATCH(LinkNum) + 0x01CB) -#define LmSEQ_EMPTY_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01CC) -#define LmSEQ_EMPTY_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CD) -#define LmSEQ_EMPTY_BUFS_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CE) -#define LmSEQ_ATA_SCR_REGS(LinkNum) (LmSCRATCH(LinkNum) + 0x01D4) - -/* Mode independent scratch page 3 macros. */ -#define LmSEQ_DEV_PRES_TMR_TOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01E0) -#define LmSEQ_SATA_INTERLOCK_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E4) -#define LmSEQ_STP_SHUTDOWN_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E8) -#define LmSEQ_SRST_ASSERT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01EC) -#define LmSEQ_RCV_FIS_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F0) -#define LmSEQ_ONE_MILLISEC_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F4) -#define LmSEQ_TEN_MS_COMINIT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F8) -#define LmSEQ_SMP_RCV_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01FC) - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sas.h b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sas.h deleted file mode 100644 index 912e6b75..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sas.h +++ /dev/null @@ -1,787 +0,0 @@ -/* - * Aic94xx SAS/SATA driver SAS definitions and hardware interface header file. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef _AIC94XX_SAS_H_ -#define _AIC94XX_SAS_H_ - -#include - -/* ---------- DDBs ---------- */ -/* DDBs are device descriptor blocks which describe a device in the - * domain that this sequencer can maintain low-level connections for - * us. They are be 64 bytes. - */ -#define ASD_MAX_DDBS 128 - -struct asd_ddb_ssp_smp_target_port { - u8 conn_type; /* byte 0 */ -#define DDB_TP_CONN_TYPE 0x81 /* Initiator port and addr frame type 0x01 */ - - u8 conn_rate; - __be16 init_conn_tag; - u8 dest_sas_addr[8]; /* bytes 4-11 */ - - __le16 send_queue_head; - u8 sq_suspended; - u8 ddb_type; /* DDB_TYPE_TARGET */ -#define DDB_TYPE_UNUSED 0xFF -#define DDB_TYPE_TARGET 0xFE -#define DDB_TYPE_INITIATOR 0xFD -#define DDB_TYPE_PM_PORT 0xFC - - __le16 _r_a; - __be16 awt_def; - - u8 compat_features; /* byte 20 */ - u8 pathway_blocked_count; - __be16 arb_wait_time; - __be32 more_compat_features; /* byte 24 */ - - u8 conn_mask; - u8 flags; /* concurrent conn:2,2 and open:0(1) */ -#define CONCURRENT_CONN_SUPP 0x04 -#define OPEN_REQUIRED 0x01 - - u16 _r_b; - __le16 exec_queue_tail; - __le16 send_queue_tail; - __le16 sister_ddb; - - __le16 _r_c; - - u8 max_concurrent_conn; - u8 num_concurrent_conn; - u8 num_contexts; - - u8 _r_d; - - __le16 active_task_count; - - u8 _r_e[9]; - - u8 itnl_reason; /* I_T nexus loss reason */ - - __le16 _r_f; - - __le16 itnl_timeout; -#define ITNL_TIMEOUT_CONST 0x7D0 /* 2 seconds */ - - __le32 itnl_timestamp; -} __attribute__ ((packed)); - -struct asd_ddb_stp_sata_target_port { - u8 conn_type; /* byte 0 */ - u8 conn_rate; - __be16 init_conn_tag; - u8 dest_sas_addr[8]; /* bytes 4-11 */ - - __le16 send_queue_head; - u8 sq_suspended; - u8 ddb_type; /* DDB_TYPE_TARGET */ - - __le16 _r_a; - - __be16 awt_def; - u8 compat_features; /* byte 20 */ - u8 pathway_blocked_count; - __be16 arb_wait_time; - __be32 more_compat_features; /* byte 24 */ - - u8 conn_mask; - u8 flags; /* concurrent conn:2,2 and open:0(1) */ -#define SATA_MULTIPORT 0x80 -#define SUPPORTS_AFFIL 0x40 -#define STP_AFFIL_POL 0x20 - - u8 _r_b; - u8 flags2; /* STP close policy:0 */ -#define STP_CL_POL_NO_TX 0x00 -#define STP_CL_POL_BTW_CMDS 0x01 - - __le16 exec_queue_tail; - __le16 send_queue_tail; - __le16 sister_ddb; - __le16 ata_cmd_scbptr; - __le32 sata_tag_alloc_mask; - __le16 active_task_count; - __le16 _r_c; - __le32 sata_sactive; - u8 num_sata_tags; - u8 sata_status; - u8 sata_ending_status; - u8 itnl_reason; /* I_T nexus loss reason */ - __le16 ncq_data_scb_ptr; - __le16 itnl_timeout; - __le32 itnl_timestamp; -} __attribute__ ((packed)); - -/* This struct asd_ddb_init_port, describes the device descriptor block - * of an initiator port (when the sequencer is operating in target mode). - * Bytes [0,11] and [20,27] are from the OPEN address frame. - * The sequencer allocates an initiator port DDB entry. - */ -struct asd_ddb_init_port { - u8 conn_type; /* byte 0 */ - u8 conn_rate; - __be16 init_conn_tag; /* BE */ - u8 dest_sas_addr[8]; - __le16 send_queue_head; /* LE, byte 12 */ - u8 sq_suspended; - u8 ddb_type; /* DDB_TYPE_INITIATOR */ - __le16 _r_a; - __be16 awt_def; /* BE */ - u8 compat_features; - u8 pathway_blocked_count; - __be16 arb_wait_time; /* BE */ - __be32 more_compat_features; /* BE */ - u8 conn_mask; - u8 flags; /* == 5 */ - u16 _r_b; - __le16 exec_queue_tail; /* execution queue tail */ - __le16 send_queue_tail; - __le16 sister_ddb; - __le16 init_resp_timeout; /* initiator response timeout */ - __le32 _r_c; - __le16 active_tasks; /* active task count */ - __le16 init_list; /* initiator list link pointer */ - __le32 _r_d; - u8 max_conn_to[3]; /* from Conn-Disc mode page, in us, LE */ - u8 itnl_reason; /* I_T nexus loss reason */ - __le16 bus_inact_to; /* from Conn-Disc mode page, in 100 us, LE */ - __le16 itnl_to; /* from the Protocol Specific Port Ctrl MP */ - __le32 itnl_timestamp; -} __attribute__ ((packed)); - -/* This struct asd_ddb_sata_tag, describes a look-up table to be used - * by the sequencers. SATA II, IDENTIFY DEVICE data, word 76, bit 8: - * NCQ support. This table is used by the sequencers to find the - * corresponding SCB, given a SATA II tag value. - */ -struct asd_ddb_sata_tag { - __le16 scb_pointer[32]; -} __attribute__ ((packed)); - -/* This struct asd_ddb_sata_pm_table, describes a port number to - * connection handle look-up table. SATA targets attached to a port - * multiplier require a 4-bit port number value. There is one DDB - * entry of this type for each SATA port multiplier (sister DDB). - * Given a SATA PM port number, this table gives us the SATA PM Port - * DDB of the SATA port multiplier port (i.e. the SATA target - * discovered on the port). - */ -struct asd_ddb_sata_pm_table { - __le16 ddb_pointer[16]; - __le16 _r_a[16]; -} __attribute__ ((packed)); - -/* This struct asd_ddb_sata_pm_port, describes the SATA port multiplier - * port format DDB. - */ -struct asd_ddb_sata_pm_port { - u8 _r_a[15]; - u8 ddb_type; - u8 _r_b[13]; - u8 pm_port_flags; -#define PM_PORT_MASK 0xF0 -#define PM_PORT_SET 0x02 - u8 _r_c[6]; - __le16 sister_ddb; - __le16 ata_cmd_scbptr; - __le32 sata_tag_alloc_mask; - __le16 active_task_count; - __le16 parent_ddb; - __le32 sata_sactive; - u8 num_sata_tags; - u8 sata_status; - u8 sata_ending_status; - u8 _r_d[9]; -} __attribute__ ((packed)); - -/* This struct asd_ddb_seq_shared, describes a DDB shared by the - * central and link sequencers. port_map_by_links is indexed phy - * number [0,7]; each byte is a bit mask of all the phys that are in - * the same port as the indexed phy. - */ -struct asd_ddb_seq_shared { - __le16 q_free_ddb_head; - __le16 q_free_ddb_tail; - __le16 q_free_ddb_cnt; - __le16 q_used_ddb_head; - __le16 q_used_ddb_tail; - __le16 shared_mem_lock; - __le16 smp_conn_tag; - __le16 est_nexus_buf_cnt; - __le16 est_nexus_buf_thresh; - u32 _r_a; - u8 settable_max_contexts; - u8 _r_b[23]; - u8 conn_not_active; - u8 phy_is_up; - u8 _r_c[8]; - u8 port_map_by_links[8]; -} __attribute__ ((packed)); - -/* ---------- SG Element ---------- */ - -/* This struct sg_el, describes the hardware scatter gather buffer - * element. All entries are little endian. In an SCB, there are 2 of - * this, plus one more, called a link element of this indicating a - * sublist if needed. - * - * A link element has only the bus address set and the flags (DS) bit - * valid. The bus address points to the start of the sublist. - * - * If a sublist is needed, then that sublist should also include the 2 - * sg_el embedded in the SCB, in which case next_sg_offset is 32, - * since sizeof(sg_el) = 16; EOS should be 1 and EOL 0 in this case. - */ -struct sg_el { - __le64 bus_addr; - __le32 size; - __le16 _r; - u8 next_sg_offs; - u8 flags; -#define ASD_SG_EL_DS_MASK 0x30 -#define ASD_SG_EL_DS_OCM 0x10 -#define ASD_SG_EL_DS_HM 0x00 -#define ASD_SG_EL_LIST_MASK 0xC0 -#define ASD_SG_EL_LIST_EOL 0x40 -#define ASD_SG_EL_LIST_EOS 0x80 -} __attribute__ ((packed)); - -/* ---------- SCBs ---------- */ - -/* An SCB (sequencer control block) is comprised of a common header - * and a task part, for a total of 128 bytes. All fields are in LE - * order, unless otherwise noted. - */ - -/* This struct scb_header, defines the SCB header format. - */ -struct scb_header { - __le64 next_scb; - __le16 index; /* transaction context */ - u8 opcode; -} __attribute__ ((packed)); - -/* SCB opcodes: Execution queue - */ -#define INITIATE_SSP_TASK 0x00 -#define INITIATE_LONG_SSP_TASK 0x01 -#define INITIATE_BIDIR_SSP_TASK 0x02 -#define SCB_ABORT_TASK 0x03 -#define INITIATE_SSP_TMF 0x04 -#define SSP_TARG_GET_DATA 0x05 -#define SSP_TARG_GET_DATA_GOOD 0x06 -#define SSP_TARG_SEND_RESP 0x07 -#define QUERY_SSP_TASK 0x08 -#define INITIATE_ATA_TASK 0x09 -#define INITIATE_ATAPI_TASK 0x0a -#define CONTROL_ATA_DEV 0x0b -#define INITIATE_SMP_TASK 0x0c -#define SMP_TARG_SEND_RESP 0x0f - -/* SCB opcodes: Send Queue - */ -#define SSP_TARG_SEND_DATA 0x40 -#define SSP_TARG_SEND_DATA_GOOD 0x41 - -/* SCB opcodes: Link Queue - */ -#define CONTROL_PHY 0x80 -#define SEND_PRIMITIVE 0x81 -#define INITIATE_LINK_ADM_TASK 0x82 - -/* SCB opcodes: other - */ -#define EMPTY_SCB 0xc0 -#define INITIATE_SEQ_ADM_TASK 0xc1 -#define EST_ICL_TARG_WINDOW 0xc2 -#define COPY_MEM 0xc3 -#define CLEAR_NEXUS 0xc4 -#define INITIATE_DDB_ADM_TASK 0xc6 -#define ESTABLISH_NEXUS_ESCB 0xd0 - -#define LUN_SIZE 8 - -/* See SAS spec, task IU - */ -struct ssp_task_iu { - u8 lun[LUN_SIZE]; /* BE */ - u16 _r_a; - u8 tmf; - u8 _r_b; - __be16 tag; /* BE */ - u8 _r_c[14]; -} __attribute__ ((packed)); - -/* See SAS spec, command IU - */ -struct ssp_command_iu { - u8 lun[LUN_SIZE]; - u8 _r_a; - u8 efb_prio_attr; /* enable first burst, task prio & attr */ -#define EFB_MASK 0x80 -#define TASK_PRIO_MASK 0x78 -#define TASK_ATTR_MASK 0x07 - - u8 _r_b; - u8 add_cdb_len; /* in dwords, since bit 0,1 are reserved */ - union { - u8 cdb[16]; - struct { - __le64 long_cdb_addr; /* bus address, LE */ - __le32 long_cdb_size; /* LE */ - u8 _r_c[3]; - u8 eol_ds; /* eol:6,6, ds:5,4 */ - } long_cdb; /* sequencer extension */ - }; -} __attribute__ ((packed)); - -struct xfer_rdy_iu { - __be32 requested_offset; /* BE */ - __be32 write_data_len; /* BE */ - __be32 _r_a; -} __attribute__ ((packed)); - -/* ---------- SCB tasks ---------- */ - -/* This is both ssp_task and long_ssp_task - */ -struct initiate_ssp_task { - u8 proto_conn_rate; /* proto:6,4, conn_rate:3,0 */ - __le32 total_xfer_len; - struct ssp_frame_hdr ssp_frame; - struct ssp_command_iu ssp_cmd; - __le16 sister_scb; /* 0xFFFF */ - __le16 conn_handle; /* index to DDB for the intended target */ - u8 data_dir; /* :1,0 */ -#define DATA_DIR_NONE 0x00 -#define DATA_DIR_IN 0x01 -#define DATA_DIR_OUT 0x02 -#define DATA_DIR_BYRECIPIENT 0x03 - - u8 _r_a; - u8 retry_count; - u8 _r_b[5]; - struct sg_el sg_element[3]; /* 2 real and 1 link */ -} __attribute__ ((packed)); - -/* This defines both ata_task and atapi_task. - * ata: C bit of FIS should be 1, - * atapi: C bit of FIS should be 1, and command register should be 0xA0, - * to indicate a packet command. - */ -struct initiate_ata_task { - u8 proto_conn_rate; - __le32 total_xfer_len; - struct host_to_dev_fis fis; - __le32 data_offs; - u8 atapi_packet[16]; - u8 _r_a[12]; - __le16 sister_scb; - __le16 conn_handle; - u8 ata_flags; /* CSMI:6,6, DTM:4,4, QT:3,3, data dir:1,0 */ -#define CSMI_TASK 0x40 -#define DATA_XFER_MODE_DMA 0x10 -#define ATA_Q_TYPE_MASK 0x08 -#define ATA_Q_TYPE_UNTAGGED 0x00 -#define ATA_Q_TYPE_NCQ 0x08 - - u8 _r_b; - u8 retry_count; - u8 _r_c; - u8 flags; -#define STP_AFFIL_POLICY 0x20 -#define SET_AFFIL_POLICY 0x10 -#define RET_PARTIAL_SGLIST 0x02 - - u8 _r_d[3]; - struct sg_el sg_element[3]; -} __attribute__ ((packed)); - -struct initiate_smp_task { - u8 proto_conn_rate; - u8 _r_a[40]; - struct sg_el smp_req; - __le16 sister_scb; - __le16 conn_handle; - u8 _r_c[8]; - struct sg_el smp_resp; - u8 _r_d[32]; -} __attribute__ ((packed)); - -struct control_phy { - u8 phy_id; - u8 sub_func; -#define DISABLE_PHY 0x00 -#define ENABLE_PHY 0x01 -#define RELEASE_SPINUP_HOLD 0x02 -#define ENABLE_PHY_NO_SAS_OOB 0x03 -#define ENABLE_PHY_NO_SATA_OOB 0x04 -#define PHY_NO_OP 0x05 -#define EXECUTE_HARD_RESET 0x81 - - u8 func_mask; - u8 speed_mask; - u8 hot_plug_delay; - u8 port_type; - u8 flags; -#define DEV_PRES_TIMER_OVERRIDE_ENABLE 0x01 -#define DISABLE_PHY_IF_OOB_FAILS 0x02 - - __le32 timeout_override; - u8 link_reset_retries; - u8 _r_a[47]; - __le16 conn_handle; - u8 _r_b[56]; -} __attribute__ ((packed)); - -struct control_ata_dev { - u8 proto_conn_rate; - __le32 _r_a; - struct host_to_dev_fis fis; - u8 _r_b[32]; - __le16 sister_scb; - __le16 conn_handle; - u8 ata_flags; /* 0 */ - u8 _r_c[55]; -} __attribute__ ((packed)); - -struct empty_scb { - u8 num_valid; - __le32 _r_a; -#define ASD_EDBS_PER_SCB 7 -/* header+data+CRC+DMA suffix data */ -#define ASD_EDB_SIZE (24+1024+4+16) - struct sg_el eb[ASD_EDBS_PER_SCB]; -#define ELEMENT_NOT_VALID 0xC0 -} __attribute__ ((packed)); - -struct initiate_link_adm { - u8 phy_id; - u8 sub_func; -#define GET_LINK_ERROR_COUNT 0x00 -#define RESET_LINK_ERROR_COUNT 0x01 -#define ENABLE_NOTIFY_SPINUP_INTS 0x02 - - u8 _r_a[57]; - __le16 conn_handle; - u8 _r_b[56]; -} __attribute__ ((packed)); - -struct copy_memory { - u8 _r_a; - __le16 xfer_len; - __le16 _r_b; - __le64 src_busaddr; - u8 src_ds; /* See definition of sg_el */ - u8 _r_c[45]; - __le16 conn_handle; - __le64 _r_d; - __le64 dest_busaddr; - u8 dest_ds; /* See definition of sg_el */ - u8 _r_e[39]; -} __attribute__ ((packed)); - -struct abort_task { - u8 proto_conn_rate; - __le32 _r_a; - struct ssp_frame_hdr ssp_frame; - struct ssp_task_iu ssp_task; - __le16 sister_scb; - __le16 conn_handle; - u8 flags; /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */ -#define SUSPEND_DATA_TRANS 0x04 - - u8 _r_b; - u8 retry_count; - u8 _r_c[5]; - __le16 index; /* Transaction context of task to be queried */ - __le16 itnl_to; - u8 _r_d[44]; -} __attribute__ ((packed)); - -struct clear_nexus { - u8 nexus; -#define NEXUS_ADAPTER 0x00 -#define NEXUS_PORT 0x01 -#define NEXUS_I_T 0x02 -#define NEXUS_I_T_L 0x03 -#define NEXUS_TAG 0x04 -#define NEXUS_TRANS_CX 0x05 -#define NEXUS_SATA_TAG 0x06 -#define NEXUS_T_L 0x07 -#define NEXUS_L 0x08 -#define NEXUS_T_TAG 0x09 - - __le32 _r_a; - u8 flags; -#define SUSPEND_TX 0x80 -#define RESUME_TX 0x40 -#define SEND_Q 0x04 -#define EXEC_Q 0x02 -#define NOTINQ 0x01 - - u8 _r_b[3]; - u8 conn_mask; - u8 _r_c[19]; - struct ssp_task_iu ssp_task; /* LUN and TAG */ - __le16 _r_d; - __le16 conn_handle; - __le64 _r_e; - __le16 index; /* Transaction context of task to be cleared */ - __le16 context; /* Clear nexus context */ - u8 _r_f[44]; -} __attribute__ ((packed)); - -struct initiate_ssp_tmf { - u8 proto_conn_rate; - __le32 _r_a; - struct ssp_frame_hdr ssp_frame; - struct ssp_task_iu ssp_task; - __le16 sister_scb; - __le16 conn_handle; - u8 flags; /* itnl override and suspend data tx */ -#define OVERRIDE_ITNL_TIMER 8 - - u8 _r_b; - u8 retry_count; - u8 _r_c[5]; - __le16 index; /* Transaction context of task to be queried */ - __le16 itnl_to; - u8 _r_d[44]; -} __attribute__ ((packed)); - -/* Transmits an arbitrary primitive on the link. - * Used for NOTIFY and BROADCAST. - */ -struct send_prim { - u8 phy_id; - u8 wait_transmit; /* :0,0 */ - u8 xmit_flags; -#define XMTPSIZE_MASK 0xF0 -#define XMTPSIZE_SINGLE 0x10 -#define XMTPSIZE_REPEATED 0x20 -#define XMTPSIZE_CONT 0x20 -#define XMTPSIZE_TRIPLE 0x30 -#define XMTPSIZE_REDUNDANT 0x60 -#define XMTPSIZE_INF 0 - -#define XMTCONTEN 0x04 -#define XMTPFRM 0x02 /* Transmit at the next frame boundary */ -#define XMTPIMM 0x01 /* Transmit immediately */ - - __le16 _r_a; - u8 prim[4]; /* K, D0, D1, D2 */ - u8 _r_b[50]; - __le16 conn_handle; - u8 _r_c[56]; -} __attribute__ ((packed)); - -/* This describes both SSP Target Get Data and SSP Target Get Data And - * Send Good Response SCBs. Used when the sequencer is operating in - * target mode... - */ -struct ssp_targ_get_data { - u8 proto_conn_rate; - __le32 total_xfer_len; - struct ssp_frame_hdr ssp_frame; - struct xfer_rdy_iu xfer_rdy; - u8 lun[LUN_SIZE]; - __le64 _r_a; - __le16 sister_scb; - __le16 conn_handle; - u8 data_dir; /* 01b */ - u8 _r_b; - u8 retry_count; - u8 _r_c[5]; - struct sg_el sg_element[3]; -} __attribute__ ((packed)); - -/* ---------- The actual SCB struct ---------- */ - -struct scb { - struct scb_header header; - union { - struct initiate_ssp_task ssp_task; - struct initiate_ata_task ata_task; - struct initiate_smp_task smp_task; - struct control_phy control_phy; - struct control_ata_dev control_ata_dev; - struct empty_scb escb; - struct initiate_link_adm link_adm; - struct copy_memory cp_mem; - struct abort_task abort_task; - struct clear_nexus clear_nexus; - struct initiate_ssp_tmf ssp_tmf; - }; -} __attribute__ ((packed)); - -/* ---------- Done List ---------- */ -/* The done list entry opcode field is defined below. - * The mnemonic encoding and meaning is as follows: - * TC - Task Complete, status was received and acknowledged - * TF - Task Failed, indicates an error prior to receiving acknowledgment - * for the command: - * - no conn, - * - NACK or R_ERR received in response to this command, - * - credit blocked or not available, or in the case of SMP request, - * - no SMP response was received. - * In these four cases it is known that the target didn't receive the - * command. - * TI - Task Interrupted, error after the command was acknowledged. It is - * known that the command was received by the target. - * TU - Task Unacked, command was transmitted but neither ACK (R_OK) nor NAK - * (R_ERR) was received due to loss of signal, broken connection, loss of - * dword sync or other reason. The application client should send the - * appropriate task query. - * TA - Task Aborted, see TF. - * _RESP - The completion includes an empty buffer containing status. - * TO - Timeout. - */ -#define TC_NO_ERROR 0x00 -#define TC_UNDERRUN 0x01 -#define TC_OVERRUN 0x02 -#define TF_OPEN_TO 0x03 -#define TF_OPEN_REJECT 0x04 -#define TI_BREAK 0x05 -#define TI_PROTO_ERR 0x06 -#define TC_SSP_RESP 0x07 -#define TI_PHY_DOWN 0x08 -#define TF_PHY_DOWN 0x09 -#define TC_LINK_ADM_RESP 0x0a -#define TC_CSMI 0x0b -#define TC_ATA_RESP 0x0c -#define TU_PHY_DOWN 0x0d -#define TU_BREAK 0x0e -#define TI_SATA_TO 0x0f -#define TI_NAK 0x10 -#define TC_CONTROL_PHY 0x11 -#define TF_BREAK 0x12 -#define TC_RESUME 0x13 -#define TI_ACK_NAK_TO 0x14 -#define TF_SMPRSP_TO 0x15 -#define TF_SMP_XMIT_RCV_ERR 0x16 -#define TC_PARTIAL_SG_LIST 0x17 -#define TU_ACK_NAK_TO 0x18 -#define TU_SATA_TO 0x19 -#define TF_NAK_RECV 0x1a -#define TA_I_T_NEXUS_LOSS 0x1b -#define TC_ATA_R_ERR_RECV 0x1c -#define TF_TMF_NO_CTX 0x1d -#define TA_ON_REQ 0x1e -#define TF_TMF_NO_TAG 0x1f -#define TF_TMF_TAG_FREE 0x20 -#define TF_TMF_TASK_DONE 0x21 -#define TF_TMF_NO_CONN_HANDLE 0x22 -#define TC_TASK_CLEARED 0x23 -#define TI_SYNCS_RECV 0x24 -#define TU_SYNCS_RECV 0x25 -#define TF_IRTT_TO 0x26 -#define TF_NO_SMP_CONN 0x27 -#define TF_IU_SHORT 0x28 -#define TF_DATA_OFFS_ERR 0x29 -#define TF_INV_CONN_HANDLE 0x2a -#define TF_REQUESTED_N_PENDING 0x2b - -/* 0xc1 - 0xc7: empty buffer received, - 0xd1 - 0xd7: establish nexus empty buffer received -*/ -/* This is the ESCB mask */ -#define ESCB_RECVD 0xC0 - - -/* This struct done_list_struct defines the done list entry. - * All fields are LE. - */ -struct done_list_struct { - __le16 index; /* aka transaction context */ - u8 opcode; - u8 status_block[4]; - u8 toggle; /* bit 0 */ -#define DL_TOGGLE_MASK 0x01 -} __attribute__ ((packed)); - -/* ---------- PHYS ---------- */ - -struct asd_phy { - struct asd_sas_phy sas_phy; - struct asd_phy_desc *phy_desc; /* hw profile */ - - struct sas_identify_frame *identify_frame; - struct asd_dma_tok *id_frm_tok; - struct asd_port *asd_port; - - u8 frame_rcvd[ASD_EDB_SIZE]; -}; - - -#define ASD_SCB_SIZE sizeof(struct scb) -#define ASD_DDB_SIZE sizeof(struct asd_ddb_ssp_smp_target_port) - -/* Define this to 0 if you do not want NOTIFY (ENABLE SPINIP) sent. - * Default: 0x10 (it's a mask) - */ -#define ASD_NOTIFY_ENABLE_SPINUP 0x10 - -/* If enabled, set this to the interval between transmission - * of NOTIFY (ENABLE SPINUP). In units of 200 us. - */ -#define ASD_NOTIFY_TIMEOUT 2500 - -/* Initial delay after OOB, before we transmit NOTIFY (ENABLE SPINUP). - * If 0, transmit immediately. In milliseconds. - */ -#define ASD_NOTIFY_DOWN_COUNT 0 - -/* Device present timer timeout constant, 10 ms. */ -#define ASD_DEV_PRESENT_TIMEOUT 0x2710 - -#define ASD_SATA_INTERLOCK_TIMEOUT 0 - -/* How long to wait before shutting down an STP connection, unless - * an STP target sent frame(s). 50 usec. - * IGNORED by the sequencer (i.e. value 0 always). - */ -#define ASD_STP_SHUTDOWN_TIMEOUT 0x0 - -/* ATA soft reset timer timeout. 5 usec. */ -#define ASD_SRST_ASSERT_TIMEOUT 0x05 - -/* 31 sec */ -#define ASD_RCV_FIS_TIMEOUT 0x01D905C0 - -#define ASD_ONE_MILLISEC_TIMEOUT 0x03e8 - -/* COMINIT timer */ -#define ASD_TEN_MILLISEC_TIMEOUT 0x2710 -#define ASD_COMINIT_TIMEOUT ASD_TEN_MILLISEC_TIMEOUT - -/* 1 sec */ -#define ASD_SMP_RCV_TIMEOUT 0x000F4240 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_scb.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_scb.c deleted file mode 100644 index fdac7c2f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_scb.c +++ /dev/null @@ -1,937 +0,0 @@ -/* - * Aic94xx SAS/SATA driver SCB management. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include - -#include "aic94xx.h" -#include "aic94xx_reg.h" -#include "aic94xx_hwi.h" -#include "aic94xx_seq.h" - -#include "aic94xx_dump.h" - -/* ---------- EMPTY SCB ---------- */ - -#define DL_PHY_MASK 7 -#define BYTES_DMAED 0 -#define PRIMITIVE_RECVD 0x08 -#define PHY_EVENT 0x10 -#define LINK_RESET_ERROR 0x18 -#define TIMER_EVENT 0x20 -#define REQ_TASK_ABORT 0xF0 -#define REQ_DEVICE_RESET 0xF1 -#define SIGNAL_NCQ_ERROR 0xF2 -#define CLEAR_NCQ_ERROR 0xF3 - -#define PHY_EVENTS_STATUS (CURRENT_LOSS_OF_SIGNAL | CURRENT_OOB_DONE \ - | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \ - | CURRENT_OOB_ERROR) - -static void get_lrate_mode(struct asd_phy *phy, u8 oob_mode) -{ - struct sas_phy *sas_phy = phy->sas_phy.phy; - - switch (oob_mode & 7) { - case PHY_SPEED_60: - /* FIXME: sas transport class doesn't have this */ - phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS; - phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; - break; - case PHY_SPEED_30: - phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS; - phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; - break; - case PHY_SPEED_15: - phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS; - phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; - break; - } - sas_phy->negotiated_linkrate = phy->sas_phy.linkrate; - sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; - sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; - sas_phy->maximum_linkrate = phy->phy_desc->max_sas_lrate; - sas_phy->minimum_linkrate = phy->phy_desc->min_sas_lrate; - - if (oob_mode & SAS_MODE) - phy->sas_phy.oob_mode = SAS_OOB_MODE; - else if (oob_mode & SATA_MODE) - phy->sas_phy.oob_mode = SATA_OOB_MODE; -} - -static void asd_phy_event_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; - int phy_id = dl->status_block[0] & DL_PHY_MASK; - struct asd_phy *phy = &asd_ha->phys[phy_id]; - - u8 oob_status = dl->status_block[1] & PHY_EVENTS_STATUS; - u8 oob_mode = dl->status_block[2]; - - switch (oob_status) { - case CURRENT_LOSS_OF_SIGNAL: - /* directly attached device was removed */ - ASD_DPRINTK("phy%d: device unplugged\n", phy_id); - asd_turn_led(asd_ha, phy_id, 0); - sas_phy_disconnected(&phy->sas_phy); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL); - break; - case CURRENT_OOB_DONE: - /* hot plugged device */ - asd_turn_led(asd_ha, phy_id, 1); - get_lrate_mode(phy, oob_mode); - ASD_DPRINTK("phy%d device plugged: lrate:0x%x, proto:0x%x\n", - phy_id, phy->sas_phy.linkrate, phy->sas_phy.iproto); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); - break; - case CURRENT_SPINUP_HOLD: - /* hot plug SATA, no COMWAKE sent */ - asd_turn_led(asd_ha, phy_id, 1); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); - break; - case CURRENT_GTO_TIMEOUT: - case CURRENT_OOB_ERROR: - ASD_DPRINTK("phy%d error while OOB: oob status:0x%x\n", phy_id, - dl->status_block[1]); - asd_turn_led(asd_ha, phy_id, 0); - sas_phy_disconnected(&phy->sas_phy); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR); - break; - } -} - -/* If phys are enabled sparsely, this will do the right thing. */ -static unsigned ord_phy(struct asd_ha_struct *asd_ha, struct asd_phy *phy) -{ - u8 enabled_mask = asd_ha->hw_prof.enabled_phys; - int i, k = 0; - - for_each_phy(enabled_mask, enabled_mask, i) { - if (&asd_ha->phys[i] == phy) - return k; - k++; - } - return 0; -} - -/** - * asd_get_attached_sas_addr -- extract/generate attached SAS address - * phy: pointer to asd_phy - * sas_addr: pointer to buffer where the SAS address is to be written - * - * This function extracts the SAS address from an IDENTIFY frame - * received. If OOB is SATA, then a SAS address is generated from the - * HA tables. - * - * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame - * buffer. - */ -static void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr) -{ - if (phy->sas_phy.frame_rcvd[0] == 0x34 - && phy->sas_phy.oob_mode == SATA_OOB_MODE) { - struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha; - /* FIS device-to-host */ - u64 addr = be64_to_cpu(*(__be64 *)phy->phy_desc->sas_addr); - - addr += asd_ha->hw_prof.sata_name_base + ord_phy(asd_ha, phy); - *(__be64 *)sas_addr = cpu_to_be64(addr); - } else { - struct sas_identify_frame *idframe = - (void *) phy->sas_phy.frame_rcvd; - memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE); - } -} - -static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy) -{ - int i; - struct asd_port *free_port = NULL; - struct asd_port *port; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - unsigned long flags; - - spin_lock_irqsave(&asd_ha->asd_ports_lock, flags); - if (!phy->asd_port) { - for (i = 0; i < ASD_MAX_PHYS; i++) { - port = &asd_ha->asd_ports[i]; - - /* Check for wide port */ - if (port->num_phys > 0 && - memcmp(port->sas_addr, sas_phy->sas_addr, - SAS_ADDR_SIZE) == 0 && - memcmp(port->attached_sas_addr, - sas_phy->attached_sas_addr, - SAS_ADDR_SIZE) == 0) { - break; - } - - /* Find a free port */ - if (port->num_phys == 0 && free_port == NULL) { - free_port = port; - } - } - - /* Use a free port if this doesn't form a wide port */ - if (i >= ASD_MAX_PHYS) { - port = free_port; - BUG_ON(!port); - memcpy(port->sas_addr, sas_phy->sas_addr, - SAS_ADDR_SIZE); - memcpy(port->attached_sas_addr, - sas_phy->attached_sas_addr, - SAS_ADDR_SIZE); - } - port->num_phys++; - port->phy_mask |= (1U << sas_phy->id); - phy->asd_port = port; - } - ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n", - __func__, phy->asd_port->phy_mask, sas_phy->id); - asd_update_port_links(asd_ha, phy); - spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); -} - -static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy) -{ - struct asd_port *port = phy->asd_port; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - unsigned long flags; - - spin_lock_irqsave(&asd_ha->asd_ports_lock, flags); - if (port) { - port->num_phys--; - port->phy_mask &= ~(1U << sas_phy->id); - phy->asd_port = NULL; - } - spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); -} - -static void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl, - int edb_id, int phy_id) -{ - unsigned long flags; - int edb_el = edb_id + ascb->edb_index; - struct asd_dma_tok *edb = ascb->ha->seq.edb_arr[edb_el]; - struct asd_phy *phy = &ascb->ha->phys[phy_id]; - struct sas_ha_struct *sas_ha = phy->sas_phy.ha; - u16 size = ((dl->status_block[3] & 7) << 8) | dl->status_block[2]; - - size = min(size, (u16) sizeof(phy->frame_rcvd)); - - spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); - memcpy(phy->sas_phy.frame_rcvd, edb->vaddr, size); - phy->sas_phy.frame_rcvd_size = size; - asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); - spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); - asd_dump_frame_rcvd(phy, dl); - asd_form_port(ascb->ha, phy); - sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED); -} - -static void asd_link_reset_err_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl, - int phy_id) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; - struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; - struct asd_phy *phy = &asd_ha->phys[phy_id]; - u8 lr_error = dl->status_block[1]; - u8 retries_left = dl->status_block[2]; - - switch (lr_error) { - case 0: - ASD_DPRINTK("phy%d: Receive ID timer expired\n", phy_id); - break; - case 1: - ASD_DPRINTK("phy%d: Loss of signal\n", phy_id); - break; - case 2: - ASD_DPRINTK("phy%d: Loss of dword sync\n", phy_id); - break; - case 3: - ASD_DPRINTK("phy%d: Receive FIS timeout\n", phy_id); - break; - default: - ASD_DPRINTK("phy%d: unknown link reset error code: 0x%x\n", - phy_id, lr_error); - break; - } - - asd_turn_led(asd_ha, phy_id, 0); - sas_phy_disconnected(sas_phy); - asd_deform_port(asd_ha, phy); - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - - if (retries_left == 0) { - int num = 1; - struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num, - GFP_ATOMIC); - if (!cp) { - asd_printk("%s: out of memory\n", __func__); - goto out; - } - ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n", - phy_id); - asd_build_control_phy(cp, phy_id, ENABLE_PHY); - if (asd_post_ascb_list(ascb->ha, cp, 1) != 0) - asd_ascb_free(cp); - } -out: - ; -} - -static void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl, - int phy_id) -{ - unsigned long flags; - struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha; - struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; - struct asd_ha_struct *asd_ha = ascb->ha; - struct asd_phy *phy = &asd_ha->phys[phy_id]; - u8 reg = dl->status_block[1]; - u32 cont = dl->status_block[2] << ((reg & 3)*8); - - reg &= ~3; - switch (reg) { - case LmPRMSTAT0BYTE0: - switch (cont) { - case LmBROADCH: - case LmBROADRVCH0: - case LmBROADRVCH1: - case LmBROADSES: - ASD_DPRINTK("phy%d: BROADCAST change received:%d\n", - phy_id, cont); - spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); - sas_phy->sas_prim = ffs(cont); - spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); - sas_ha->notify_port_event(sas_phy,PORTE_BROADCAST_RCVD); - break; - - case LmUNKNOWNP: - ASD_DPRINTK("phy%d: unknown BREAK\n", phy_id); - break; - - default: - ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n", - phy_id, reg, cont); - break; - } - break; - case LmPRMSTAT1BYTE0: - switch (cont) { - case LmHARDRST: - ASD_DPRINTK("phy%d: HARD_RESET primitive rcvd\n", - phy_id); - /* The sequencer disables all phys on that port. - * We have to re-enable the phys ourselves. */ - asd_deform_port(asd_ha, phy); - sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); - break; - - default: - ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n", - phy_id, reg, cont); - break; - } - break; - default: - ASD_DPRINTK("unknown primitive register:0x%x\n", - dl->status_block[1]); - break; - } -} - -/** - * asd_invalidate_edb -- invalidate an EDB and if necessary post the ESCB - * @ascb: pointer to Empty SCB - * @edb_id: index [0,6] to the empty data buffer which is to be invalidated - * - * After an EDB has been invalidated, if all EDBs in this ESCB have been - * invalidated, the ESCB is posted back to the sequencer. - * Context is tasklet/IRQ. - */ -void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id) -{ - struct asd_seq_data *seq = &ascb->ha->seq; - struct empty_scb *escb = &ascb->scb->escb; - struct sg_el *eb = &escb->eb[edb_id]; - struct asd_dma_tok *edb = seq->edb_arr[ascb->edb_index + edb_id]; - - memset(edb->vaddr, 0, ASD_EDB_SIZE); - eb->flags |= ELEMENT_NOT_VALID; - escb->num_valid--; - - if (escb->num_valid == 0) { - int i; - /* ASD_DPRINTK("reposting escb: vaddr: 0x%p, " - "dma_handle: 0x%08llx, next: 0x%08llx, " - "index:%d, opcode:0x%02x\n", - ascb->dma_scb.vaddr, - (u64)ascb->dma_scb.dma_handle, - le64_to_cpu(ascb->scb->header.next_scb), - le16_to_cpu(ascb->scb->header.index), - ascb->scb->header.opcode); - */ - escb->num_valid = ASD_EDBS_PER_SCB; - for (i = 0; i < ASD_EDBS_PER_SCB; i++) - escb->eb[i].flags = 0; - if (!list_empty(&ascb->list)) - list_del_init(&ascb->list); - i = asd_post_escb_list(ascb->ha, ascb, 1); - if (i) - asd_printk("couldn't post escb, err:%d\n", i); - } -} - -static void escb_tasklet_complete(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; - int edb = (dl->opcode & DL_PHY_MASK) - 1; /* [0xc1,0xc7] -> [0,6] */ - u8 sb_opcode = dl->status_block[0]; - int phy_id = sb_opcode & DL_PHY_MASK; - struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; - struct asd_phy *phy = &asd_ha->phys[phy_id]; - - if (edb > 6 || edb < 0) { - ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", - edb, dl->opcode); - ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n", - sb_opcode, phy_id); - ASD_DPRINTK("escb: vaddr: 0x%p, " - "dma_handle: 0x%llx, next: 0x%llx, " - "index:%d, opcode:0x%02x\n", - ascb->dma_scb.vaddr, - (unsigned long long)ascb->dma_scb.dma_handle, - (unsigned long long) - le64_to_cpu(ascb->scb->header.next_scb), - le16_to_cpu(ascb->scb->header.index), - ascb->scb->header.opcode); - } - - /* Catch these before we mask off the sb_opcode bits */ - switch (sb_opcode) { - case REQ_TASK_ABORT: { - struct asd_ascb *a, *b; - u16 tc_abort; - struct domain_device *failed_dev = NULL; - - ASD_DPRINTK("%s: REQ_TASK_ABORT, reason=0x%X\n", - __func__, dl->status_block[3]); - - /* - * Find the task that caused the abort and abort it first. - * The sequencer won't put anything on the done list until - * that happens. - */ - tc_abort = *((u16*)(&dl->status_block[1])); - tc_abort = le16_to_cpu(tc_abort); - - list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { - struct sas_task *task = a->uldd_task; - - if (a->tc_index != tc_abort) - continue; - - if (task) { - failed_dev = task->dev; - sas_task_abort(task); - } else { - ASD_DPRINTK("R_T_A for non TASK scb 0x%x\n", - a->scb->header.opcode); - } - break; - } - - if (!failed_dev) { - ASD_DPRINTK("%s: Can't find task (tc=%d) to abort!\n", - __func__, tc_abort); - goto out; - } - - /* - * Now abort everything else for that device (hba?) so - * that the EH will wake up and do something. - */ - list_for_each_entry_safe(a, b, &asd_ha->seq.pend_q, list) { - struct sas_task *task = a->uldd_task; - - if (task && - task->dev == failed_dev && - a->tc_index != tc_abort) - sas_task_abort(task); - } - - goto out; - } - case REQ_DEVICE_RESET: { - struct asd_ascb *a; - u16 conn_handle; - unsigned long flags; - struct sas_task *last_dev_task = NULL; - - conn_handle = *((u16*)(&dl->status_block[1])); - conn_handle = le16_to_cpu(conn_handle); - - ASD_DPRINTK("%s: REQ_DEVICE_RESET, reason=0x%X\n", __func__, - dl->status_block[3]); - - /* Find the last pending task for the device... */ - list_for_each_entry(a, &asd_ha->seq.pend_q, list) { - u16 x; - struct domain_device *dev; - struct sas_task *task = a->uldd_task; - - if (!task) - continue; - dev = task->dev; - - x = (unsigned long)dev->lldd_dev; - if (x == conn_handle) - last_dev_task = task; - } - - if (!last_dev_task) { - ASD_DPRINTK("%s: Device reset for idle device %d?\n", - __func__, conn_handle); - goto out; - } - - /* ...and set the reset flag */ - spin_lock_irqsave(&last_dev_task->task_state_lock, flags); - last_dev_task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; - spin_unlock_irqrestore(&last_dev_task->task_state_lock, flags); - - /* Kill all pending tasks for the device */ - list_for_each_entry(a, &asd_ha->seq.pend_q, list) { - u16 x; - struct domain_device *dev; - struct sas_task *task = a->uldd_task; - - if (!task) - continue; - dev = task->dev; - - x = (unsigned long)dev->lldd_dev; - if (x == conn_handle) - sas_task_abort(task); - } - - goto out; - } - case SIGNAL_NCQ_ERROR: - ASD_DPRINTK("%s: SIGNAL_NCQ_ERROR\n", __func__); - goto out; - case CLEAR_NCQ_ERROR: - ASD_DPRINTK("%s: CLEAR_NCQ_ERROR\n", __func__); - goto out; - } - - sb_opcode &= ~DL_PHY_MASK; - - switch (sb_opcode) { - case BYTES_DMAED: - ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __func__, phy_id); - asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id); - break; - case PRIMITIVE_RECVD: - ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __func__, - phy_id); - asd_primitive_rcvd_tasklet(ascb, dl, phy_id); - break; - case PHY_EVENT: - ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __func__, phy_id); - asd_phy_event_tasklet(ascb, dl); - break; - case LINK_RESET_ERROR: - ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __func__, - phy_id); - asd_link_reset_err_tasklet(ascb, dl, phy_id); - break; - case TIMER_EVENT: - ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n", - __func__, phy_id); - asd_turn_led(asd_ha, phy_id, 0); - /* the device is gone */ - sas_phy_disconnected(sas_phy); - asd_deform_port(asd_ha, phy); - sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); - break; - default: - ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __func__, - phy_id, sb_opcode); - ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", - edb, dl->opcode); - ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n", - sb_opcode, phy_id); - ASD_DPRINTK("escb: vaddr: 0x%p, " - "dma_handle: 0x%llx, next: 0x%llx, " - "index:%d, opcode:0x%02x\n", - ascb->dma_scb.vaddr, - (unsigned long long)ascb->dma_scb.dma_handle, - (unsigned long long) - le64_to_cpu(ascb->scb->header.next_scb), - le16_to_cpu(ascb->scb->header.index), - ascb->scb->header.opcode); - - break; - } -out: - asd_invalidate_edb(ascb, edb); -} - -int asd_init_post_escbs(struct asd_ha_struct *asd_ha) -{ - struct asd_seq_data *seq = &asd_ha->seq; - int i; - - for (i = 0; i < seq->num_escbs; i++) - seq->escb_arr[i]->tasklet_complete = escb_tasklet_complete; - - ASD_DPRINTK("posting %d escbs\n", i); - return asd_post_escb_list(asd_ha, seq->escb_arr[0], seq->num_escbs); -} - -/* ---------- CONTROL PHY ---------- */ - -#define CONTROL_PHY_STATUS (CURRENT_DEVICE_PRESENT | CURRENT_OOB_DONE \ - | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \ - | CURRENT_OOB_ERROR) - -/** - * control_phy_tasklet_complete -- tasklet complete for CONTROL PHY ascb - * @ascb: pointer to an ascb - * @dl: pointer to the done list entry - * - * This function completes a CONTROL PHY scb and frees the ascb. - * A note on LEDs: - * - an LED blinks if there is IO though it, - * - if a device is connected to the LED, it is lit, - * - if no device is connected to the LED, is is dimmed (off). - */ -static void control_phy_tasklet_complete(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - struct scb *scb = ascb->scb; - struct control_phy *control_phy = &scb->control_phy; - u8 phy_id = control_phy->phy_id; - struct asd_phy *phy = &ascb->ha->phys[phy_id]; - - u8 status = dl->status_block[0]; - u8 oob_status = dl->status_block[1]; - u8 oob_mode = dl->status_block[2]; - /* u8 oob_signals= dl->status_block[3]; */ - - if (status != 0) { - ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n", - __func__, phy_id, status); - goto out; - } - - switch (control_phy->sub_func) { - case DISABLE_PHY: - asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id); - asd_turn_led(asd_ha, phy_id, 0); - asd_control_led(asd_ha, phy_id, 0); - ASD_DPRINTK("%s: disable phy%d\n", __func__, phy_id); - break; - - case ENABLE_PHY: - asd_control_led(asd_ha, phy_id, 1); - if (oob_status & CURRENT_OOB_DONE) { - asd_ha->hw_prof.enabled_phys |= (1 << phy_id); - get_lrate_mode(phy, oob_mode); - asd_turn_led(asd_ha, phy_id, 1); - ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n", - __func__, phy_id,phy->sas_phy.linkrate, - phy->sas_phy.iproto); - } else if (oob_status & CURRENT_SPINUP_HOLD) { - asd_ha->hw_prof.enabled_phys |= (1 << phy_id); - asd_turn_led(asd_ha, phy_id, 1); - ASD_DPRINTK("%s: phy%d, spinup hold\n", __func__, - phy_id); - } else if (oob_status & CURRENT_ERR_MASK) { - asd_turn_led(asd_ha, phy_id, 0); - ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n", - __func__, phy_id, oob_status); - } else if (oob_status & (CURRENT_HOT_PLUG_CNCT - | CURRENT_DEVICE_PRESENT)) { - asd_ha->hw_prof.enabled_phys |= (1 << phy_id); - asd_turn_led(asd_ha, phy_id, 1); - ASD_DPRINTK("%s: phy%d: hot plug or device present\n", - __func__, phy_id); - } else { - asd_ha->hw_prof.enabled_phys |= (1 << phy_id); - asd_turn_led(asd_ha, phy_id, 0); - ASD_DPRINTK("%s: phy%d: no device present: " - "oob_status:0x%x\n", - __func__, phy_id, oob_status); - } - break; - case RELEASE_SPINUP_HOLD: - case PHY_NO_OP: - case EXECUTE_HARD_RESET: - ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __func__, - phy_id, control_phy->sub_func); - /* XXX finish */ - break; - default: - ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __func__, - phy_id, control_phy->sub_func); - break; - } -out: - asd_ascb_free(ascb); -} - -static void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) -{ - /* disable all speeds, then enable defaults */ - *speed_mask = SAS_SPEED_60_DIS | SAS_SPEED_30_DIS | SAS_SPEED_15_DIS - | SATA_SPEED_30_DIS | SATA_SPEED_15_DIS; - - switch (pd->max_sas_lrate) { - case SAS_LINK_RATE_6_0_GBPS: - *speed_mask &= ~SAS_SPEED_60_DIS; - default: - case SAS_LINK_RATE_3_0_GBPS: - *speed_mask &= ~SAS_SPEED_30_DIS; - case SAS_LINK_RATE_1_5_GBPS: - *speed_mask &= ~SAS_SPEED_15_DIS; - } - - switch (pd->min_sas_lrate) { - case SAS_LINK_RATE_6_0_GBPS: - *speed_mask |= SAS_SPEED_30_DIS; - case SAS_LINK_RATE_3_0_GBPS: - *speed_mask |= SAS_SPEED_15_DIS; - default: - case SAS_LINK_RATE_1_5_GBPS: - /* nothing to do */ - ; - } - - switch (pd->max_sata_lrate) { - case SAS_LINK_RATE_3_0_GBPS: - *speed_mask &= ~SATA_SPEED_30_DIS; - default: - case SAS_LINK_RATE_1_5_GBPS: - *speed_mask &= ~SATA_SPEED_15_DIS; - } - - switch (pd->min_sata_lrate) { - case SAS_LINK_RATE_3_0_GBPS: - *speed_mask |= SATA_SPEED_15_DIS; - default: - case SAS_LINK_RATE_1_5_GBPS: - /* nothing to do */ - ; - } -} - -/** - * asd_build_control_phy -- build a CONTROL PHY SCB - * @ascb: pointer to an ascb - * @phy_id: phy id to control, integer - * @subfunc: subfunction, what to actually to do the phy - * - * This function builds a CONTROL PHY scb. No allocation of any kind - * is performed. @ascb is allocated with the list function. - * The caller can override the ascb->tasklet_complete to point - * to its own callback function. It must call asd_ascb_free() - * at its tasklet complete function. - * See the default implementation. - */ -void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc) -{ - struct asd_phy *phy = &ascb->ha->phys[phy_id]; - struct scb *scb = ascb->scb; - struct control_phy *control_phy = &scb->control_phy; - - scb->header.opcode = CONTROL_PHY; - control_phy->phy_id = (u8) phy_id; - control_phy->sub_func = subfunc; - - switch (subfunc) { - case EXECUTE_HARD_RESET: /* 0x81 */ - case ENABLE_PHY: /* 0x01 */ - /* decide hot plug delay */ - control_phy->hot_plug_delay = HOTPLUG_DELAY_TIMEOUT; - - /* decide speed mask */ - set_speed_mask(&control_phy->speed_mask, phy->phy_desc); - - /* initiator port settings are in the hi nibble */ - if (phy->sas_phy.role == PHY_ROLE_INITIATOR) - control_phy->port_type = SAS_PROTOCOL_ALL << 4; - else if (phy->sas_phy.role == PHY_ROLE_TARGET) - control_phy->port_type = SAS_PROTOCOL_ALL; - else - control_phy->port_type = - (SAS_PROTOCOL_ALL << 4) | SAS_PROTOCOL_ALL; - - /* link reset retries, this should be nominal */ - control_phy->link_reset_retries = 10; - - case RELEASE_SPINUP_HOLD: /* 0x02 */ - /* decide the func_mask */ - control_phy->func_mask = FUNCTION_MASK_DEFAULT; - if (phy->phy_desc->flags & ASD_SATA_SPINUP_HOLD) - control_phy->func_mask &= ~SPINUP_HOLD_DIS; - else - control_phy->func_mask |= SPINUP_HOLD_DIS; - } - - control_phy->conn_handle = cpu_to_le16(0xFFFF); - - ascb->tasklet_complete = control_phy_tasklet_complete; -} - -/* ---------- INITIATE LINK ADM TASK ---------- */ - -#if 0 - -static void link_adm_tasklet_complete(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - u8 opcode = dl->opcode; - struct initiate_link_adm *link_adm = &ascb->scb->link_adm; - u8 phy_id = link_adm->phy_id; - - if (opcode != TC_NO_ERROR) { - asd_printk("phy%d: link adm task 0x%x completed with error " - "0x%x\n", phy_id, link_adm->sub_func, opcode); - } - ASD_DPRINTK("phy%d: link adm task 0x%x: 0x%x\n", - phy_id, link_adm->sub_func, opcode); - - asd_ascb_free(ascb); -} - -void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, - u8 subfunc) -{ - struct scb *scb = ascb->scb; - struct initiate_link_adm *link_adm = &scb->link_adm; - - scb->header.opcode = INITIATE_LINK_ADM_TASK; - - link_adm->phy_id = phy_id; - link_adm->sub_func = subfunc; - link_adm->conn_handle = cpu_to_le16(0xFFFF); - - ascb->tasklet_complete = link_adm_tasklet_complete; -} - -#endif /* 0 */ - -/* ---------- SCB timer ---------- */ - -/** - * asd_ascb_timedout -- called when a pending SCB's timer has expired - * @data: unsigned long, a pointer to the ascb in question - * - * This is the default timeout function which does the most necessary. - * Upper layers can implement their own timeout function, say to free - * resources they have with this SCB, and then call this one at the - * end of their timeout function. To do this, one should initialize - * the ascb->timer.{function, data, expires} prior to calling the post - * function. The timer is started by the post function. - */ -void asd_ascb_timedout(unsigned long data) -{ - struct asd_ascb *ascb = (void *) data; - struct asd_seq_data *seq = &ascb->ha->seq; - unsigned long flags; - - ASD_DPRINTK("scb:0x%x timed out\n", ascb->scb->header.opcode); - - spin_lock_irqsave(&seq->pend_q_lock, flags); - seq->pending--; - list_del_init(&ascb->list); - spin_unlock_irqrestore(&seq->pend_q_lock, flags); - - asd_ascb_free(ascb); -} - -/* ---------- CONTROL PHY ---------- */ - -/* Given the spec value, return a driver value. */ -static const int phy_func_table[] = { - [PHY_FUNC_NOP] = PHY_NO_OP, - [PHY_FUNC_LINK_RESET] = ENABLE_PHY, - [PHY_FUNC_HARD_RESET] = EXECUTE_HARD_RESET, - [PHY_FUNC_DISABLE] = DISABLE_PHY, - [PHY_FUNC_RELEASE_SPINUP_HOLD] = RELEASE_SPINUP_HOLD, -}; - -int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func, void *arg) -{ - struct asd_ha_struct *asd_ha = phy->ha->lldd_ha; - struct asd_phy_desc *pd = asd_ha->phys[phy->id].phy_desc; - struct asd_ascb *ascb; - struct sas_phy_linkrates *rates; - int res = 1; - - switch (func) { - case PHY_FUNC_CLEAR_ERROR_LOG: - case PHY_FUNC_GET_EVENTS: - return -ENOSYS; - case PHY_FUNC_SET_LINK_RATE: - rates = arg; - if (rates->minimum_linkrate) { - pd->min_sas_lrate = rates->minimum_linkrate; - pd->min_sata_lrate = rates->minimum_linkrate; - } - if (rates->maximum_linkrate) { - pd->max_sas_lrate = rates->maximum_linkrate; - pd->max_sata_lrate = rates->maximum_linkrate; - } - func = PHY_FUNC_LINK_RESET; - break; - default: - break; - } - - ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); - if (!ascb) - return -ENOMEM; - - asd_build_control_phy(ascb, phy->id, phy_func_table[func]); - res = asd_post_ascb_list(asd_ha, ascb , 1); - if (res) - asd_ascb_free(ascb); - - return res; -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.c deleted file mode 100644 index edb43fda..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.c +++ /dev/null @@ -1,1475 +0,0 @@ -/* - * Aic94xx SAS/SATA driver access to shared data structures and memory - * maps. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include - -#include "aic94xx.h" -#include "aic94xx_reg.h" -#include "aic94xx_sds.h" - -/* ---------- OCM stuff ---------- */ - -struct asd_ocm_dir_ent { - u8 type; - u8 offs[3]; - u8 _r1; - u8 size[3]; -} __attribute__ ((packed)); - -struct asd_ocm_dir { - char sig[2]; - u8 _r1[2]; - u8 major; /* 0 */ - u8 minor; /* 0 */ - u8 _r2; - u8 num_de; - struct asd_ocm_dir_ent entry[15]; -} __attribute__ ((packed)); - -#define OCM_DE_OCM_DIR 0x00 -#define OCM_DE_WIN_DRVR 0x01 -#define OCM_DE_BIOS_CHIM 0x02 -#define OCM_DE_RAID_ENGN 0x03 -#define OCM_DE_BIOS_INTL 0x04 -#define OCM_DE_BIOS_CHIM_OSM 0x05 -#define OCM_DE_BIOS_CHIM_DYNAMIC 0x06 -#define OCM_DE_ADDC2C_RES0 0x07 -#define OCM_DE_ADDC2C_RES1 0x08 -#define OCM_DE_ADDC2C_RES2 0x09 -#define OCM_DE_ADDC2C_RES3 0x0A - -#define OCM_INIT_DIR_ENTRIES 5 -/*************************************************************************** -* OCM directory default -***************************************************************************/ -static struct asd_ocm_dir OCMDirInit = -{ - .sig = {0x4D, 0x4F}, /* signature */ - .num_de = OCM_INIT_DIR_ENTRIES, /* no. of directory entries */ -}; - -/*************************************************************************** -* OCM directory Entries default -***************************************************************************/ -static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] = -{ - { - .type = (OCM_DE_ADDC2C_RES0), /* Entry type */ - .offs = {128}, /* Offset */ - .size = {0, 4}, /* size */ - }, - { - .type = (OCM_DE_ADDC2C_RES1), /* Entry type */ - .offs = {128, 4}, /* Offset */ - .size = {0, 4}, /* size */ - }, - { - .type = (OCM_DE_ADDC2C_RES2), /* Entry type */ - .offs = {128, 8}, /* Offset */ - .size = {0, 4}, /* size */ - }, - { - .type = (OCM_DE_ADDC2C_RES3), /* Entry type */ - .offs = {128, 12}, /* Offset */ - .size = {0, 4}, /* size */ - }, - { - .type = (OCM_DE_WIN_DRVR), /* Entry type */ - .offs = {128, 16}, /* Offset */ - .size = {128, 235, 1}, /* size */ - }, -}; - -struct asd_bios_chim_struct { - char sig[4]; - u8 major; /* 1 */ - u8 minor; /* 0 */ - u8 bios_major; - u8 bios_minor; - __le32 bios_build; - u8 flags; - u8 pci_slot; - __le16 ue_num; - __le16 ue_size; - u8 _r[14]; - /* The unit element array is right here. - */ -} __attribute__ ((packed)); - -/** - * asd_read_ocm_seg - read an on chip memory (OCM) segment - * @asd_ha: pointer to the host adapter structure - * @buffer: where to write the read data - * @offs: offset into OCM where to read from - * @size: how many bytes to read - * - * Return the number of bytes not read. Return 0 on success. - */ -static int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer, - u32 offs, int size) -{ - u8 *p = buffer; - if (unlikely(asd_ha->iospace)) - asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size); - else { - for ( ; size > 0; size--, offs++, p++) - *p = asd_read_ocm_byte(asd_ha, offs); - } - return size; -} - -static int asd_read_ocm_dir(struct asd_ha_struct *asd_ha, - struct asd_ocm_dir *dir, u32 offs) -{ - int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir)); - if (err) { - ASD_DPRINTK("couldn't read ocm segment\n"); - return err; - } - - if (dir->sig[0] != 'M' || dir->sig[1] != 'O') { - ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n", - dir->sig[0], dir->sig[1]); - return -ENOENT; - } - if (dir->major != 0) { - asd_printk("unsupported major version of ocm dir:0x%x\n", - dir->major); - return -ENOENT; - } - dir->num_de &= 0xf; - return 0; -} - -/** - * asd_write_ocm_seg - write an on chip memory (OCM) segment - * @asd_ha: pointer to the host adapter structure - * @buffer: where to read the write data - * @offs: offset into OCM to write to - * @size: how many bytes to write - * - * Return the number of bytes not written. Return 0 on success. - */ -static void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer, - u32 offs, int size) -{ - u8 *p = buffer; - if (unlikely(asd_ha->iospace)) - asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size); - else { - for ( ; size > 0; size--, offs++, p++) - asd_write_ocm_byte(asd_ha, offs, *p); - } - return; -} - -#define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16)) - -static int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type, - u32 *offs, u32 *size) -{ - int i; - struct asd_ocm_dir_ent *ent; - - for (i = 0; i < dir->num_de; i++) { - if (dir->entry[i].type == type) - break; - } - if (i >= dir->num_de) - return -ENOENT; - ent = &dir->entry[i]; - *offs = (u32) THREE_TO_NUM(ent->offs); - *size = (u32) THREE_TO_NUM(ent->size); - return 0; -} - -#define OCM_BIOS_CHIM_DE 2 -#define BC_BIOS_PRESENT 1 - -static int asd_get_bios_chim(struct asd_ha_struct *asd_ha, - struct asd_ocm_dir *dir) -{ - int err; - struct asd_bios_chim_struct *bc_struct; - u32 offs, size; - - err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size); - if (err) { - ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n"); - goto out; - } - err = -ENOMEM; - bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL); - if (!bc_struct) { - asd_printk("no memory for bios_chim struct\n"); - goto out; - } - err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs, - sizeof(*bc_struct)); - if (err) { - ASD_DPRINTK("couldn't read ocm segment\n"); - goto out2; - } - if (strncmp(bc_struct->sig, "SOIB", 4) - && strncmp(bc_struct->sig, "IPSA", 4)) { - ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n", - bc_struct->sig[0], bc_struct->sig[1], - bc_struct->sig[2], bc_struct->sig[3]); - err = -ENOENT; - goto out2; - } - if (bc_struct->major != 1) { - asd_printk("BIOS_CHIM unsupported major version:0x%x\n", - bc_struct->major); - err = -ENOENT; - goto out2; - } - if (bc_struct->flags & BC_BIOS_PRESENT) { - asd_ha->hw_prof.bios.present = 1; - asd_ha->hw_prof.bios.maj = bc_struct->bios_major; - asd_ha->hw_prof.bios.min = bc_struct->bios_minor; - asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build); - ASD_DPRINTK("BIOS present (%d,%d), %d\n", - asd_ha->hw_prof.bios.maj, - asd_ha->hw_prof.bios.min, - asd_ha->hw_prof.bios.bld); - } - asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num); - asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size); - ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num, - asd_ha->hw_prof.ue.size); - size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size; - if (size > 0) { - err = -ENOMEM; - asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL); - if (!asd_ha->hw_prof.ue.area) - goto out2; - err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area, - offs + sizeof(*bc_struct), size); - if (err) { - kfree(asd_ha->hw_prof.ue.area); - asd_ha->hw_prof.ue.area = NULL; - asd_ha->hw_prof.ue.num = 0; - asd_ha->hw_prof.ue.size = 0; - ASD_DPRINTK("couldn't read ue entries(%d)\n", err); - } - } -out2: - kfree(bc_struct); -out: - return err; -} - -static void -asd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha) -{ - int i; - - /* Zero OCM */ - for (i = 0; i < OCM_MAX_SIZE; i += 4) - asd_write_ocm_dword(asd_ha, i, 0); - - /* Write Dir */ - asd_write_ocm_seg(asd_ha, &OCMDirInit, 0, - sizeof(struct asd_ocm_dir)); - - /* Write Dir Entries */ - for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++) - asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i], - sizeof(struct asd_ocm_dir) + - (i * sizeof(struct asd_ocm_dir_ent)) - , sizeof(struct asd_ocm_dir_ent)); - -} - -static int -asd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha) -{ - struct pci_dev *pcidev = asd_ha->pcidev; - u32 reg; - int err = 0; - u32 v; - - /* check if OCM has been initialized by BIOS */ - reg = asd_read_reg_dword(asd_ha, EXSICNFGR); - - if (!(reg & OCMINITIALIZED)) { - err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v); - if (err) { - asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n", - pci_name(pcidev)); - goto out; - } - - printk(KERN_INFO "OCM is not initialized by BIOS," - "reinitialize it and ignore it, current IntrptStatus" - "is 0x%x\n", v); - - if (v) - err = pci_write_config_dword(pcidev, - PCIC_INTRPT_STAT, v); - if (err) { - asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n", - pci_name(pcidev)); - goto out; - } - - asd_hwi_initialize_ocm_dir(asd_ha); - - } -out: - return err; -} - -/** - * asd_read_ocm - read on chip memory (OCM) - * @asd_ha: pointer to the host adapter structure - */ -int asd_read_ocm(struct asd_ha_struct *asd_ha) -{ - int err; - struct asd_ocm_dir *dir; - - if (asd_hwi_check_ocm_access(asd_ha)) - return -1; - - dir = kmalloc(sizeof(*dir), GFP_KERNEL); - if (!dir) { - asd_printk("no memory for ocm dir\n"); - return -ENOMEM; - } - - err = asd_read_ocm_dir(asd_ha, dir, 0); - if (err) - goto out; - - err = asd_get_bios_chim(asd_ha, dir); -out: - kfree(dir); - return err; -} - -/* ---------- FLASH stuff ---------- */ - -#define FLASH_RESET 0xF0 - -#define ASD_FLASH_SIZE 0x200000 -#define FLASH_DIR_COOKIE "*** ADAPTEC FLASH DIRECTORY *** " -#define FLASH_NEXT_ENTRY_OFFS 0x2000 -#define FLASH_MAX_DIR_ENTRIES 32 - -#define FLASH_DE_TYPE_MASK 0x3FFFFFFF -#define FLASH_DE_MS 0x120 -#define FLASH_DE_CTRL_A_USER 0xE0 - -struct asd_flash_de { - __le32 type; - __le32 offs; - __le32 pad_size; - __le32 image_size; - __le32 chksum; - u8 _r[12]; - u8 version[32]; -} __attribute__ ((packed)); - -struct asd_flash_dir { - u8 cookie[32]; - __le32 rev; /* 2 */ - __le32 chksum; - __le32 chksum_antidote; - __le32 bld; - u8 bld_id[32]; /* build id data */ - u8 ver_data[32]; /* date and time of build */ - __le32 ae_mask; - __le32 v_mask; - __le32 oc_mask; - u8 _r[20]; - struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES]; -} __attribute__ ((packed)); - -struct asd_manuf_sec { - char sig[2]; /* 'S', 'M' */ - u16 offs_next; - u8 maj; /* 0 */ - u8 min; /* 0 */ - u16 chksum; - u16 size; - u8 _r[6]; - u8 sas_addr[SAS_ADDR_SIZE]; - u8 pcba_sn[ASD_PCBA_SN_SIZE]; - /* Here start the other segments */ - u8 linked_list[0]; -} __attribute__ ((packed)); - -struct asd_manuf_phy_desc { - u8 state; /* low 4 bits */ -#define MS_PHY_STATE_ENABLED 0 -#define MS_PHY_STATE_REPORTED 1 -#define MS_PHY_STATE_HIDDEN 2 - u8 phy_id; - u16 _r; - u8 phy_control_0; /* mode 5 reg 0x160 */ - u8 phy_control_1; /* mode 5 reg 0x161 */ - u8 phy_control_2; /* mode 5 reg 0x162 */ - u8 phy_control_3; /* mode 5 reg 0x163 */ -} __attribute__ ((packed)); - -struct asd_manuf_phy_param { - char sig[2]; /* 'P', 'M' */ - u16 next; - u8 maj; /* 0 */ - u8 min; /* 2 */ - u8 num_phy_desc; /* 8 */ - u8 phy_desc_size; /* 8 */ - u8 _r[3]; - u8 usage_model_id; - u32 _r2; - struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS]; -} __attribute__ ((packed)); - -#if 0 -static const char *asd_sb_type[] = { - "unknown", - "SGPIO", - [2 ... 0x7F] = "unknown", - [0x80] = "ADPT_I2C", - [0x81 ... 0xFF] = "VENDOR_UNIQUExx" -}; -#endif - -struct asd_ms_sb_desc { - u8 type; - u8 node_desc_index; - u8 conn_desc_index; - u8 _recvd[0]; -} __attribute__ ((packed)); - -#if 0 -static const char *asd_conn_type[] = { - [0 ... 7] = "unknown", - "SFF8470", - "SFF8482", - "SFF8484", - [0x80] = "PCIX_DAUGHTER0", - [0x81] = "SAS_DAUGHTER0", - [0x82 ... 0xFF] = "VENDOR_UNIQUExx" -}; - -static const char *asd_conn_location[] = { - "unknown", - "internal", - "external", - "board_to_board", -}; -#endif - -struct asd_ms_conn_desc { - u8 type; - u8 location; - u8 num_sideband_desc; - u8 size_sideband_desc; - u32 _resvd; - u8 name[16]; - struct asd_ms_sb_desc sb_desc[0]; -} __attribute__ ((packed)); - -struct asd_nd_phy_desc { - u8 vp_attch_type; - u8 attch_specific[0]; -} __attribute__ ((packed)); - -#if 0 -static const char *asd_node_type[] = { - "IOP", - "IO_CONTROLLER", - "EXPANDER", - "PORT_MULTIPLIER", - "PORT_MULTIPLEXER", - "MULTI_DROP_I2C_BUS", -}; -#endif - -struct asd_ms_node_desc { - u8 type; - u8 num_phy_desc; - u8 size_phy_desc; - u8 _resvd; - u8 name[16]; - struct asd_nd_phy_desc phy_desc[0]; -} __attribute__ ((packed)); - -struct asd_ms_conn_map { - char sig[2]; /* 'M', 'C' */ - __le16 next; - u8 maj; /* 0 */ - u8 min; /* 0 */ - __le16 cm_size; /* size of this struct */ - u8 num_conn; - u8 conn_size; - u8 num_nodes; - u8 usage_model_id; - u32 _resvd; - struct asd_ms_conn_desc conn_desc[0]; - struct asd_ms_node_desc node_desc[0]; -} __attribute__ ((packed)); - -struct asd_ctrla_phy_entry { - u8 sas_addr[SAS_ADDR_SIZE]; - u8 sas_link_rates; /* max in hi bits, min in low bits */ - u8 flags; - u8 sata_link_rates; - u8 _r[5]; -} __attribute__ ((packed)); - -struct asd_ctrla_phy_settings { - u8 id0; /* P'h'y */ - u8 _r; - u16 next; - u8 num_phys; /* number of PHYs in the PCI function */ - u8 _r2[3]; - struct asd_ctrla_phy_entry phy_ent[ASD_MAX_PHYS]; -} __attribute__ ((packed)); - -struct asd_ll_el { - u8 id0; - u8 id1; - __le16 next; - u8 something_here[0]; -} __attribute__ ((packed)); - -static int asd_poll_flash(struct asd_ha_struct *asd_ha) -{ - int c; - u8 d; - - for (c = 5000; c > 0; c--) { - d = asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar); - d ^= asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar); - if (!d) - return 0; - udelay(5); - } - return -ENOENT; -} - -static int asd_reset_flash(struct asd_ha_struct *asd_ha) -{ - int err; - - err = asd_poll_flash(asd_ha); - if (err) - return err; - asd_write_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar, FLASH_RESET); - err = asd_poll_flash(asd_ha); - - return err; -} - -static int asd_read_flash_seg(struct asd_ha_struct *asd_ha, - void *buffer, u32 offs, int size) -{ - asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs, - size); - return 0; -} - -/** - * asd_find_flash_dir - finds and reads the flash directory - * @asd_ha: pointer to the host adapter structure - * @flash_dir: pointer to flash directory structure - * - * If found, the flash directory segment will be copied to - * @flash_dir. Return 1 if found, 0 if not. - */ -static int asd_find_flash_dir(struct asd_ha_struct *asd_ha, - struct asd_flash_dir *flash_dir) -{ - u32 v; - for (v = 0; v < ASD_FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) { - asd_read_flash_seg(asd_ha, flash_dir, v, - sizeof(FLASH_DIR_COOKIE)-1); - if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE, - sizeof(FLASH_DIR_COOKIE)-1) == 0) { - asd_ha->hw_prof.flash.dir_offs = v; - asd_read_flash_seg(asd_ha, flash_dir, v, - sizeof(*flash_dir)); - return 1; - } - } - return 0; -} - -static int asd_flash_getid(struct asd_ha_struct *asd_ha) -{ - int err = 0; - u32 reg; - - reg = asd_read_reg_dword(asd_ha, EXSICNFGR); - - if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR, - &asd_ha->hw_prof.flash.bar)) { - asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n", - pci_name(asd_ha->pcidev)); - return -ENOENT; - } - asd_ha->hw_prof.flash.present = 1; - asd_ha->hw_prof.flash.wide = reg & FLASHW ? 1 : 0; - err = asd_reset_flash(asd_ha); - if (err) { - ASD_DPRINTK("couldn't reset flash(%d)\n", err); - return err; - } - return 0; -} - -static u16 asd_calc_flash_chksum(u16 *p, int size) -{ - u16 chksum = 0; - - while (size-- > 0) - chksum += *p++; - - return chksum; -} - - -static int asd_find_flash_de(struct asd_flash_dir *flash_dir, u32 entry_type, - u32 *offs, u32 *size) -{ - int i; - struct asd_flash_de *de; - - for (i = 0; i < FLASH_MAX_DIR_ENTRIES; i++) { - u32 type = le32_to_cpu(flash_dir->dir_entry[i].type); - - type &= FLASH_DE_TYPE_MASK; - if (type == entry_type) - break; - } - if (i >= FLASH_MAX_DIR_ENTRIES) - return -ENOENT; - de = &flash_dir->dir_entry[i]; - *offs = le32_to_cpu(de->offs); - *size = le32_to_cpu(de->pad_size); - return 0; -} - -static int asd_validate_ms(struct asd_manuf_sec *ms) -{ - if (ms->sig[0] != 'S' || ms->sig[1] != 'M') { - ASD_DPRINTK("manuf sec: no valid sig(%c%c)\n", - ms->sig[0], ms->sig[1]); - return -ENOENT; - } - if (ms->maj != 0) { - asd_printk("unsupported manuf. sector. major version:%x\n", - ms->maj); - return -ENOENT; - } - ms->offs_next = le16_to_cpu((__force __le16) ms->offs_next); - ms->chksum = le16_to_cpu((__force __le16) ms->chksum); - ms->size = le16_to_cpu((__force __le16) ms->size); - - if (asd_calc_flash_chksum((u16 *)ms, ms->size/2)) { - asd_printk("failed manuf sector checksum\n"); - } - - return 0; -} - -static int asd_ms_get_sas_addr(struct asd_ha_struct *asd_ha, - struct asd_manuf_sec *ms) -{ - memcpy(asd_ha->hw_prof.sas_addr, ms->sas_addr, SAS_ADDR_SIZE); - return 0; -} - -static int asd_ms_get_pcba_sn(struct asd_ha_struct *asd_ha, - struct asd_manuf_sec *ms) -{ - memcpy(asd_ha->hw_prof.pcba_sn, ms->pcba_sn, ASD_PCBA_SN_SIZE); - asd_ha->hw_prof.pcba_sn[ASD_PCBA_SN_SIZE] = '\0'; - return 0; -} - -/** - * asd_find_ll_by_id - find a linked list entry by its id - * @start: void pointer to the first element in the linked list - * @id0: the first byte of the id (offs 0) - * @id1: the second byte of the id (offs 1) - * - * @start has to be the _base_ element start, since the - * linked list entries's offset is from this pointer. - * Some linked list entries use only the first id, in which case - * you can pass 0xFF for the second. - */ -static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1) -{ - struct asd_ll_el *el = start; - - do { - switch (id1) { - default: - if (el->id1 == id1) - case 0xFF: - if (el->id0 == id0) - return el; - } - el = start + le16_to_cpu(el->next); - } while (el != start); - - return NULL; -} - -/** - * asd_ms_get_phy_params - get phy parameters from the manufacturing sector - * @asd_ha: pointer to the host adapter structure - * @manuf_sec: pointer to the manufacturing sector - * - * The manufacturing sector contans also the linked list of sub-segments, - * since when it was read, its size was taken from the flash directory, - * not from the structure size. - * - * HIDDEN phys do not count in the total count. REPORTED phys cannot - * be enabled but are reported and counted towards the total. - * ENABLED phys are enabled by default and count towards the total. - * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys - * merely specifies the number of phys the host adapter decided to - * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN, - * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENABLED. - * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2 - * are actually enabled (enabled by default, max number of phys - * enableable in this case). - */ -static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha, - struct asd_manuf_sec *manuf_sec) -{ - int i; - int en_phys = 0; - int rep_phys = 0; - struct asd_manuf_phy_param *phy_param; - struct asd_manuf_phy_param dflt_phy_param; - - phy_param = asd_find_ll_by_id(manuf_sec, 'P', 'M'); - if (!phy_param) { - ASD_DPRINTK("ms: no phy parameters found\n"); - ASD_DPRINTK("ms: Creating default phy parameters\n"); - dflt_phy_param.sig[0] = 'P'; - dflt_phy_param.sig[1] = 'M'; - dflt_phy_param.maj = 0; - dflt_phy_param.min = 2; - dflt_phy_param.num_phy_desc = 8; - dflt_phy_param.phy_desc_size = sizeof(struct asd_manuf_phy_desc); - for (i =0; i < ASD_MAX_PHYS; i++) { - dflt_phy_param.phy_desc[i].state = 0; - dflt_phy_param.phy_desc[i].phy_id = i; - dflt_phy_param.phy_desc[i].phy_control_0 = 0xf6; - dflt_phy_param.phy_desc[i].phy_control_1 = 0x10; - dflt_phy_param.phy_desc[i].phy_control_2 = 0x43; - dflt_phy_param.phy_desc[i].phy_control_3 = 0xeb; - } - - phy_param = &dflt_phy_param; - - } - - if (phy_param->maj != 0) { - asd_printk("unsupported manuf. phy param major version:0x%x\n", - phy_param->maj); - return -ENOENT; - } - - ASD_DPRINTK("ms: num_phy_desc: %d\n", phy_param->num_phy_desc); - asd_ha->hw_prof.enabled_phys = 0; - for (i = 0; i < phy_param->num_phy_desc; i++) { - struct asd_manuf_phy_desc *pd = &phy_param->phy_desc[i]; - switch (pd->state & 0xF) { - case MS_PHY_STATE_HIDDEN: - ASD_DPRINTK("ms: phy%d: HIDDEN\n", i); - continue; - case MS_PHY_STATE_REPORTED: - ASD_DPRINTK("ms: phy%d: REPORTED\n", i); - asd_ha->hw_prof.enabled_phys &= ~(1 << i); - rep_phys++; - continue; - case MS_PHY_STATE_ENABLED: - ASD_DPRINTK("ms: phy%d: ENABLED\n", i); - asd_ha->hw_prof.enabled_phys |= (1 << i); - en_phys++; - break; - } - asd_ha->hw_prof.phy_desc[i].phy_control_0 = pd->phy_control_0; - asd_ha->hw_prof.phy_desc[i].phy_control_1 = pd->phy_control_1; - asd_ha->hw_prof.phy_desc[i].phy_control_2 = pd->phy_control_2; - asd_ha->hw_prof.phy_desc[i].phy_control_3 = pd->phy_control_3; - } - asd_ha->hw_prof.max_phys = rep_phys + en_phys; - asd_ha->hw_prof.num_phys = en_phys; - ASD_DPRINTK("ms: max_phys:0x%x, num_phys:0x%x\n", - asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys); - ASD_DPRINTK("ms: enabled_phys:0x%x\n", asd_ha->hw_prof.enabled_phys); - return 0; -} - -static int asd_ms_get_connector_map(struct asd_ha_struct *asd_ha, - struct asd_manuf_sec *manuf_sec) -{ - struct asd_ms_conn_map *cm; - - cm = asd_find_ll_by_id(manuf_sec, 'M', 'C'); - if (!cm) { - ASD_DPRINTK("ms: no connector map found\n"); - return 0; - } - - if (cm->maj != 0) { - ASD_DPRINTK("ms: unsupported: connector map major version 0x%x" - "\n", cm->maj); - return -ENOENT; - } - - /* XXX */ - - return 0; -} - - -/** - * asd_process_ms - find and extract information from the manufacturing sector - * @asd_ha: pointer to the host adapter structure - * @flash_dir: pointer to the flash directory - */ -static int asd_process_ms(struct asd_ha_struct *asd_ha, - struct asd_flash_dir *flash_dir) -{ - int err; - struct asd_manuf_sec *manuf_sec; - u32 offs, size; - - err = asd_find_flash_de(flash_dir, FLASH_DE_MS, &offs, &size); - if (err) { - ASD_DPRINTK("Couldn't find the manuf. sector\n"); - goto out; - } - - if (size == 0) - goto out; - - err = -ENOMEM; - manuf_sec = kmalloc(size, GFP_KERNEL); - if (!manuf_sec) { - ASD_DPRINTK("no mem for manuf sector\n"); - goto out; - } - - err = asd_read_flash_seg(asd_ha, (void *)manuf_sec, offs, size); - if (err) { - ASD_DPRINTK("couldn't read manuf sector at 0x%x, size 0x%x\n", - offs, size); - goto out2; - } - - err = asd_validate_ms(manuf_sec); - if (err) { - ASD_DPRINTK("couldn't validate manuf sector\n"); - goto out2; - } - - err = asd_ms_get_sas_addr(asd_ha, manuf_sec); - if (err) { - ASD_DPRINTK("couldn't read the SAS_ADDR\n"); - goto out2; - } - ASD_DPRINTK("manuf sect SAS_ADDR %llx\n", - SAS_ADDR(asd_ha->hw_prof.sas_addr)); - - err = asd_ms_get_pcba_sn(asd_ha, manuf_sec); - if (err) { - ASD_DPRINTK("couldn't read the PCBA SN\n"); - goto out2; - } - ASD_DPRINTK("manuf sect PCBA SN %s\n", asd_ha->hw_prof.pcba_sn); - - err = asd_ms_get_phy_params(asd_ha, manuf_sec); - if (err) { - ASD_DPRINTK("ms: couldn't get phy parameters\n"); - goto out2; - } - - err = asd_ms_get_connector_map(asd_ha, manuf_sec); - if (err) { - ASD_DPRINTK("ms: couldn't get connector map\n"); - goto out2; - } - -out2: - kfree(manuf_sec); -out: - return err; -} - -static int asd_process_ctrla_phy_settings(struct asd_ha_struct *asd_ha, - struct asd_ctrla_phy_settings *ps) -{ - int i; - for (i = 0; i < ps->num_phys; i++) { - struct asd_ctrla_phy_entry *pe = &ps->phy_ent[i]; - - if (!PHY_ENABLED(asd_ha, i)) - continue; - if (*(u64 *)pe->sas_addr == 0) { - asd_ha->hw_prof.enabled_phys &= ~(1 << i); - continue; - } - /* This is the SAS address which should be sent in IDENTIFY. */ - memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, pe->sas_addr, - SAS_ADDR_SIZE); - asd_ha->hw_prof.phy_desc[i].max_sas_lrate = - (pe->sas_link_rates & 0xF0) >> 4; - asd_ha->hw_prof.phy_desc[i].min_sas_lrate = - (pe->sas_link_rates & 0x0F); - asd_ha->hw_prof.phy_desc[i].max_sata_lrate = - (pe->sata_link_rates & 0xF0) >> 4; - asd_ha->hw_prof.phy_desc[i].min_sata_lrate = - (pe->sata_link_rates & 0x0F); - asd_ha->hw_prof.phy_desc[i].flags = pe->flags; - ASD_DPRINTK("ctrla: phy%d: sas_addr: %llx, sas rate:0x%x-0x%x," - " sata rate:0x%x-0x%x, flags:0x%x\n", - i, - SAS_ADDR(asd_ha->hw_prof.phy_desc[i].sas_addr), - asd_ha->hw_prof.phy_desc[i].max_sas_lrate, - asd_ha->hw_prof.phy_desc[i].min_sas_lrate, - asd_ha->hw_prof.phy_desc[i].max_sata_lrate, - asd_ha->hw_prof.phy_desc[i].min_sata_lrate, - asd_ha->hw_prof.phy_desc[i].flags); - } - - return 0; -} - -/** - * asd_process_ctrl_a_user - process CTRL-A user settings - * @asd_ha: pointer to the host adapter structure - * @flash_dir: pointer to the flash directory - */ -static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha, - struct asd_flash_dir *flash_dir) -{ - int err, i; - u32 offs, size; - struct asd_ll_el *el; - struct asd_ctrla_phy_settings *ps; - struct asd_ctrla_phy_settings dflt_ps; - - err = asd_find_flash_de(flash_dir, FLASH_DE_CTRL_A_USER, &offs, &size); - if (err) { - ASD_DPRINTK("couldn't find CTRL-A user settings section\n"); - ASD_DPRINTK("Creating default CTRL-A user settings section\n"); - - dflt_ps.id0 = 'h'; - dflt_ps.num_phys = 8; - for (i =0; i < ASD_MAX_PHYS; i++) { - memcpy(dflt_ps.phy_ent[i].sas_addr, - asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE); - dflt_ps.phy_ent[i].sas_link_rates = 0x98; - dflt_ps.phy_ent[i].flags = 0x0; - dflt_ps.phy_ent[i].sata_link_rates = 0x0; - } - - size = sizeof(struct asd_ctrla_phy_settings); - ps = &dflt_ps; - } - - if (size == 0) - goto out; - - err = -ENOMEM; - el = kmalloc(size, GFP_KERNEL); - if (!el) { - ASD_DPRINTK("no mem for ctrla user settings section\n"); - goto out; - } - - err = asd_read_flash_seg(asd_ha, (void *)el, offs, size); - if (err) { - ASD_DPRINTK("couldn't read ctrla phy settings section\n"); - goto out2; - } - - err = -ENOENT; - ps = asd_find_ll_by_id(el, 'h', 0xFF); - if (!ps) { - ASD_DPRINTK("couldn't find ctrla phy settings struct\n"); - goto out2; - } - - err = asd_process_ctrla_phy_settings(asd_ha, ps); - if (err) { - ASD_DPRINTK("couldn't process ctrla phy settings\n"); - goto out2; - } -out2: - kfree(el); -out: - return err; -} - -/** - * asd_read_flash - read flash memory - * @asd_ha: pointer to the host adapter structure - */ -int asd_read_flash(struct asd_ha_struct *asd_ha) -{ - int err; - struct asd_flash_dir *flash_dir; - - err = asd_flash_getid(asd_ha); - if (err) - return err; - - flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL); - if (!flash_dir) - return -ENOMEM; - - err = -ENOENT; - if (!asd_find_flash_dir(asd_ha, flash_dir)) { - ASD_DPRINTK("couldn't find flash directory\n"); - goto out; - } - - if (le32_to_cpu(flash_dir->rev) != 2) { - asd_printk("unsupported flash dir version:0x%x\n", - le32_to_cpu(flash_dir->rev)); - goto out; - } - - err = asd_process_ms(asd_ha, flash_dir); - if (err) { - ASD_DPRINTK("couldn't process manuf sector settings\n"); - goto out; - } - - err = asd_process_ctrl_a_user(asd_ha, flash_dir); - if (err) { - ASD_DPRINTK("couldn't process CTRL-A user settings\n"); - goto out; - } - -out: - kfree(flash_dir); - return err; -} - -/** - * asd_verify_flash_seg - verify data with flash memory - * @asd_ha: pointer to the host adapter structure - * @src: pointer to the source data to be verified - * @dest_offset: offset from flash memory - * @bytes_to_verify: total bytes to verify - */ -int asd_verify_flash_seg(struct asd_ha_struct *asd_ha, - const void *src, u32 dest_offset, u32 bytes_to_verify) -{ - const u8 *src_buf; - u8 flash_char; - int err; - u32 nv_offset, reg, i; - - reg = asd_ha->hw_prof.flash.bar; - src_buf = NULL; - - err = FLASH_OK; - nv_offset = dest_offset; - src_buf = (const u8 *)src; - for (i = 0; i < bytes_to_verify; i++) { - flash_char = asd_read_reg_byte(asd_ha, reg + nv_offset + i); - if (flash_char != src_buf[i]) { - err = FAIL_VERIFY; - break; - } - } - return err; -} - -/** - * asd_write_flash_seg - write data into flash memory - * @asd_ha: pointer to the host adapter structure - * @src: pointer to the source data to be written - * @dest_offset: offset from flash memory - * @bytes_to_write: total bytes to write - */ -int asd_write_flash_seg(struct asd_ha_struct *asd_ha, - const void *src, u32 dest_offset, u32 bytes_to_write) -{ - const u8 *src_buf; - u32 nv_offset, reg, i; - int err; - - reg = asd_ha->hw_prof.flash.bar; - src_buf = NULL; - - err = asd_check_flash_type(asd_ha); - if (err) { - ASD_DPRINTK("couldn't find the type of flash. err=%d\n", err); - return err; - } - - nv_offset = dest_offset; - err = asd_erase_nv_sector(asd_ha, nv_offset, bytes_to_write); - if (err) { - ASD_DPRINTK("Erase failed at offset:0x%x\n", - nv_offset); - return err; - } - - err = asd_reset_flash(asd_ha); - if (err) { - ASD_DPRINTK("couldn't reset flash. err=%d\n", err); - return err; - } - - src_buf = (const u8 *)src; - for (i = 0; i < bytes_to_write; i++) { - /* Setup program command sequence */ - switch (asd_ha->hw_prof.flash.method) { - case FLASH_METHOD_A: - { - asd_write_reg_byte(asd_ha, - (reg + 0xAAA), 0xAA); - asd_write_reg_byte(asd_ha, - (reg + 0x555), 0x55); - asd_write_reg_byte(asd_ha, - (reg + 0xAAA), 0xA0); - asd_write_reg_byte(asd_ha, - (reg + nv_offset + i), - (*(src_buf + i))); - break; - } - case FLASH_METHOD_B: - { - asd_write_reg_byte(asd_ha, - (reg + 0x555), 0xAA); - asd_write_reg_byte(asd_ha, - (reg + 0x2AA), 0x55); - asd_write_reg_byte(asd_ha, - (reg + 0x555), 0xA0); - asd_write_reg_byte(asd_ha, - (reg + nv_offset + i), - (*(src_buf + i))); - break; - } - default: - break; - } - if (asd_chk_write_status(asd_ha, - (nv_offset + i), 0) != 0) { - ASD_DPRINTK("aicx: Write failed at offset:0x%x\n", - reg + nv_offset + i); - return FAIL_WRITE_FLASH; - } - } - - err = asd_reset_flash(asd_ha); - if (err) { - ASD_DPRINTK("couldn't reset flash. err=%d\n", err); - return err; - } - return 0; -} - -int asd_chk_write_status(struct asd_ha_struct *asd_ha, - u32 sector_addr, u8 erase_flag) -{ - u32 reg; - u32 loop_cnt; - u8 nv_data1, nv_data2; - u8 toggle_bit1; - - /* - * Read from DQ2 requires sector address - * while it's dont care for DQ6 - */ - reg = asd_ha->hw_prof.flash.bar; - - for (loop_cnt = 0; loop_cnt < 50000; loop_cnt++) { - nv_data1 = asd_read_reg_byte(asd_ha, reg); - nv_data2 = asd_read_reg_byte(asd_ha, reg); - - toggle_bit1 = ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6) - ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6)); - - if (toggle_bit1 == 0) { - return 0; - } else { - if (nv_data2 & FLASH_STATUS_BIT_MASK_DQ5) { - nv_data1 = asd_read_reg_byte(asd_ha, - reg); - nv_data2 = asd_read_reg_byte(asd_ha, - reg); - toggle_bit1 = - ((nv_data1 & FLASH_STATUS_BIT_MASK_DQ6) - ^ (nv_data2 & FLASH_STATUS_BIT_MASK_DQ6)); - - if (toggle_bit1 == 0) - return 0; - } - } - - /* - * ERASE is a sector-by-sector operation and requires - * more time to finish while WRITE is byte-byte-byte - * operation and takes lesser time to finish. - * - * For some strange reason a reduced ERASE delay gives different - * behaviour across different spirit boards. Hence we set - * a optimum balance of 50mus for ERASE which works well - * across all boards. - */ - if (erase_flag) { - udelay(FLASH_STATUS_ERASE_DELAY_COUNT); - } else { - udelay(FLASH_STATUS_WRITE_DELAY_COUNT); - } - } - return -1; -} - -/** - * asd_hwi_erase_nv_sector - Erase the flash memory sectors. - * @asd_ha: pointer to the host adapter structure - * @flash_addr: pointer to offset from flash memory - * @size: total bytes to erase. - */ -int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, u32 flash_addr, u32 size) -{ - u32 reg; - u32 sector_addr; - - reg = asd_ha->hw_prof.flash.bar; - - /* sector staring address */ - sector_addr = flash_addr & FLASH_SECTOR_SIZE_MASK; - - /* - * Erasing an flash sector needs to be done in six consecutive - * write cyles. - */ - while (sector_addr < flash_addr+size) { - switch (asd_ha->hw_prof.flash.method) { - case FLASH_METHOD_A: - asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA); - asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55); - asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0x80); - asd_write_reg_byte(asd_ha, (reg + 0xAAA), 0xAA); - asd_write_reg_byte(asd_ha, (reg + 0x555), 0x55); - asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30); - break; - case FLASH_METHOD_B: - asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); - asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); - asd_write_reg_byte(asd_ha, (reg + 0x555), 0x80); - asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); - asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); - asd_write_reg_byte(asd_ha, (reg + sector_addr), 0x30); - break; - default: - break; - } - - if (asd_chk_write_status(asd_ha, sector_addr, 1) != 0) - return FAIL_ERASE_FLASH; - - sector_addr += FLASH_SECTOR_SIZE; - } - - return 0; -} - -int asd_check_flash_type(struct asd_ha_struct *asd_ha) -{ - u8 manuf_id; - u8 dev_id; - u8 sec_prot; - u32 inc; - u32 reg; - int err; - - /* get Flash memory base address */ - reg = asd_ha->hw_prof.flash.bar; - - /* Determine flash info */ - err = asd_reset_flash(asd_ha); - if (err) { - ASD_DPRINTK("couldn't reset flash. err=%d\n", err); - return err; - } - - asd_ha->hw_prof.flash.method = FLASH_METHOD_UNKNOWN; - asd_ha->hw_prof.flash.manuf = FLASH_MANUF_ID_UNKNOWN; - asd_ha->hw_prof.flash.dev_id = FLASH_DEV_ID_UNKNOWN; - - /* Get flash info. This would most likely be AMD Am29LV family flash. - * First try the sequence for word mode. It is the same as for - * 008B (byte mode only), 160B (word mode) and 800D (word mode). - */ - inc = asd_ha->hw_prof.flash.wide ? 2 : 1; - asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA); - asd_write_reg_byte(asd_ha, reg + 0x555, 0x55); - asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90); - manuf_id = asd_read_reg_byte(asd_ha, reg); - dev_id = asd_read_reg_byte(asd_ha, reg + inc); - sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc); - /* Get out of autoselect mode. */ - err = asd_reset_flash(asd_ha); - if (err) { - ASD_DPRINTK("couldn't reset flash. err=%d\n", err); - return err; - } - ASD_DPRINTK("Flash MethodA manuf_id(0x%x) dev_id(0x%x) " - "sec_prot(0x%x)\n", manuf_id, dev_id, sec_prot); - err = asd_reset_flash(asd_ha); - if (err != 0) - return err; - - switch (manuf_id) { - case FLASH_MANUF_ID_AMD: - switch (sec_prot) { - case FLASH_DEV_ID_AM29LV800DT: - case FLASH_DEV_ID_AM29LV640MT: - case FLASH_DEV_ID_AM29F800B: - asd_ha->hw_prof.flash.method = FLASH_METHOD_A; - break; - default: - break; - } - break; - case FLASH_MANUF_ID_ST: - switch (sec_prot) { - case FLASH_DEV_ID_STM29W800DT: - case FLASH_DEV_ID_STM29LV640: - asd_ha->hw_prof.flash.method = FLASH_METHOD_A; - break; - default: - break; - } - break; - case FLASH_MANUF_ID_FUJITSU: - switch (sec_prot) { - case FLASH_DEV_ID_MBM29LV800TE: - case FLASH_DEV_ID_MBM29DL800TA: - asd_ha->hw_prof.flash.method = FLASH_METHOD_A; - break; - } - break; - case FLASH_MANUF_ID_MACRONIX: - switch (sec_prot) { - case FLASH_DEV_ID_MX29LV800BT: - asd_ha->hw_prof.flash.method = FLASH_METHOD_A; - break; - } - break; - } - - if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) { - err = asd_reset_flash(asd_ha); - if (err) { - ASD_DPRINTK("couldn't reset flash. err=%d\n", err); - return err; - } - - /* Issue Unlock sequence for AM29LV008BT */ - asd_write_reg_byte(asd_ha, (reg + 0x555), 0xAA); - asd_write_reg_byte(asd_ha, (reg + 0x2AA), 0x55); - asd_write_reg_byte(asd_ha, (reg + 0x555), 0x90); - manuf_id = asd_read_reg_byte(asd_ha, reg); - dev_id = asd_read_reg_byte(asd_ha, reg + inc); - sec_prot = asd_read_reg_byte(asd_ha, reg + inc + inc); - - ASD_DPRINTK("Flash MethodB manuf_id(0x%x) dev_id(0x%x) sec_prot" - "(0x%x)\n", manuf_id, dev_id, sec_prot); - - err = asd_reset_flash(asd_ha); - if (err != 0) { - ASD_DPRINTK("couldn't reset flash. err=%d\n", err); - return err; - } - - switch (manuf_id) { - case FLASH_MANUF_ID_AMD: - switch (dev_id) { - case FLASH_DEV_ID_AM29LV008BT: - asd_ha->hw_prof.flash.method = FLASH_METHOD_B; - break; - default: - break; - } - break; - case FLASH_MANUF_ID_ST: - switch (dev_id) { - case FLASH_DEV_ID_STM29008: - asd_ha->hw_prof.flash.method = FLASH_METHOD_B; - break; - default: - break; - } - break; - case FLASH_MANUF_ID_FUJITSU: - switch (dev_id) { - case FLASH_DEV_ID_MBM29LV008TA: - asd_ha->hw_prof.flash.method = FLASH_METHOD_B; - break; - } - break; - case FLASH_MANUF_ID_INTEL: - switch (dev_id) { - case FLASH_DEV_ID_I28LV00TAT: - asd_ha->hw_prof.flash.method = FLASH_METHOD_B; - break; - } - break; - case FLASH_MANUF_ID_MACRONIX: - switch (dev_id) { - case FLASH_DEV_ID_I28LV00TAT: - asd_ha->hw_prof.flash.method = FLASH_METHOD_B; - break; - } - break; - default: - return FAIL_FIND_FLASH_ID; - } - } - - if (asd_ha->hw_prof.flash.method == FLASH_METHOD_UNKNOWN) - return FAIL_FIND_FLASH_ID; - - asd_ha->hw_prof.flash.manuf = manuf_id; - asd_ha->hw_prof.flash.dev_id = dev_id; - asd_ha->hw_prof.flash.sec_prot = sec_prot; - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.h b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.h deleted file mode 100644 index a06dc011..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_sds.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Aic94xx SAS/SATA driver hardware interface header file. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Gilbert Wu - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ -#ifndef _AIC94XX_SDS_H_ -#define _AIC94XX_SDS_H_ - -enum { - FLASH_METHOD_UNKNOWN, - FLASH_METHOD_A, - FLASH_METHOD_B -}; - -#define FLASH_MANUF_ID_AMD 0x01 -#define FLASH_MANUF_ID_ST 0x20 -#define FLASH_MANUF_ID_FUJITSU 0x04 -#define FLASH_MANUF_ID_MACRONIX 0xC2 -#define FLASH_MANUF_ID_INTEL 0x89 -#define FLASH_MANUF_ID_UNKNOWN 0xFF - -#define FLASH_DEV_ID_AM29LV008BT 0x3E -#define FLASH_DEV_ID_AM29LV800DT 0xDA -#define FLASH_DEV_ID_STM29W800DT 0xD7 -#define FLASH_DEV_ID_STM29LV640 0xDE -#define FLASH_DEV_ID_STM29008 0xEA -#define FLASH_DEV_ID_MBM29LV800TE 0xDA -#define FLASH_DEV_ID_MBM29DL800TA 0x4A -#define FLASH_DEV_ID_MBM29LV008TA 0x3E -#define FLASH_DEV_ID_AM29LV640MT 0x7E -#define FLASH_DEV_ID_AM29F800B 0xD6 -#define FLASH_DEV_ID_MX29LV800BT 0xDA -#define FLASH_DEV_ID_MX29LV008CT 0xDA -#define FLASH_DEV_ID_I28LV00TAT 0x3E -#define FLASH_DEV_ID_UNKNOWN 0xFF - -/* status bit mask values */ -#define FLASH_STATUS_BIT_MASK_DQ6 0x40 -#define FLASH_STATUS_BIT_MASK_DQ5 0x20 -#define FLASH_STATUS_BIT_MASK_DQ2 0x04 - -/* minimum value in micro seconds needed for checking status */ -#define FLASH_STATUS_ERASE_DELAY_COUNT 50 -#define FLASH_STATUS_WRITE_DELAY_COUNT 25 - -#define FLASH_SECTOR_SIZE 0x010000 -#define FLASH_SECTOR_SIZE_MASK 0xffff0000 - -#define FLASH_OK 0x000000 -#define FAIL_OPEN_BIOS_FILE 0x000100 -#define FAIL_CHECK_PCI_ID 0x000200 -#define FAIL_CHECK_SUM 0x000300 -#define FAIL_UNKNOWN 0x000400 -#define FAIL_VERIFY 0x000500 -#define FAIL_RESET_FLASH 0x000600 -#define FAIL_FIND_FLASH_ID 0x000700 -#define FAIL_ERASE_FLASH 0x000800 -#define FAIL_WRITE_FLASH 0x000900 -#define FAIL_FILE_SIZE 0x000a00 -#define FAIL_PARAMETERS 0x000b00 -#define FAIL_OUT_MEMORY 0x000c00 -#define FLASH_IN_PROGRESS 0x001000 - -struct controller_id { - u32 vendor; /* PCI Vendor ID */ - u32 device; /* PCI Device ID */ - u32 sub_vendor; /* PCI Subvendor ID */ - u32 sub_device; /* PCI Subdevice ID */ -}; - -struct image_info { - u32 ImageId; /* Identifies the image */ - u32 ImageOffset; /* Offset the beginning of the file */ - u32 ImageLength; /* length of the image */ - u32 ImageChecksum; /* Image checksum */ - u32 ImageVersion; /* Version of the image, could be build number */ -}; - -struct bios_file_header { - u8 signature[32]; /* Signature/Cookie to identify the file */ - u32 checksum; /*Entire file checksum with this field zero */ - u32 antidote; /* Entire file checksum with this field 0xFFFFFFFF */ - struct controller_id contrl_id; /*PCI id to identify the controller */ - u32 filelen; /*Length of the entire file*/ - u32 chunk_num; /*The chunk/part number for multiple Image files */ - u32 total_chunks; /*Total number of chunks/parts in the image file */ - u32 num_images; /* Number of images in the file */ - u32 build_num; /* Build number of this image */ - struct image_info image_header; -}; - -int asd_verify_flash_seg(struct asd_ha_struct *asd_ha, - const void *src, u32 dest_offset, u32 bytes_to_verify); -int asd_write_flash_seg(struct asd_ha_struct *asd_ha, - const void *src, u32 dest_offset, u32 bytes_to_write); -int asd_chk_write_status(struct asd_ha_struct *asd_ha, - u32 sector_addr, u8 erase_flag); -int asd_check_flash_type(struct asd_ha_struct *asd_ha); -int asd_erase_nv_sector(struct asd_ha_struct *asd_ha, - u32 flash_addr, u32 size); -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.c deleted file mode 100644 index 390168f6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.c +++ /dev/null @@ -1,1416 +0,0 @@ -/* - * Aic94xx SAS/SATA driver sequencer interface. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * Parts of this code adapted from David Chaw's adp94xx_seq.c. - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include -#include "aic94xx_reg.h" -#include "aic94xx_hwi.h" - -#include "aic94xx_seq.h" -#include "aic94xx_dump.h" - -/* It takes no more than 0.05 us for an instruction - * to complete. So waiting for 1 us should be more than - * plenty. - */ -#define PAUSE_DELAY 1 -#define PAUSE_TRIES 1000 - -static const struct firmware *sequencer_fw; -static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task, - cseq_idle_loop, lseq_idle_loop; -static const u8 *cseq_code, *lseq_code; -static u32 cseq_code_size, lseq_code_size; - -static u16 first_scb_site_no = 0xFFFF; -static u16 last_scb_site_no; - -/* ---------- Pause/Unpause CSEQ/LSEQ ---------- */ - -/** - * asd_pause_cseq - pause the central sequencer - * @asd_ha: pointer to host adapter structure - * - * Return 0 on success, negative on failure. - */ -static int asd_pause_cseq(struct asd_ha_struct *asd_ha) -{ - int count = PAUSE_TRIES; - u32 arp2ctl; - - arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); - if (arp2ctl & PAUSED) - return 0; - - asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE); - do { - arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); - if (arp2ctl & PAUSED) - return 0; - udelay(PAUSE_DELAY); - } while (--count > 0); - - ASD_DPRINTK("couldn't pause CSEQ\n"); - return -1; -} - -/** - * asd_unpause_cseq - unpause the central sequencer. - * @asd_ha: pointer to host adapter structure. - * - * Return 0 on success, negative on error. - */ -static int asd_unpause_cseq(struct asd_ha_struct *asd_ha) -{ - u32 arp2ctl; - int count = PAUSE_TRIES; - - arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); - if (!(arp2ctl & PAUSED)) - return 0; - - asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE); - do { - arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); - if (!(arp2ctl & PAUSED)) - return 0; - udelay(PAUSE_DELAY); - } while (--count > 0); - - ASD_DPRINTK("couldn't unpause the CSEQ\n"); - return -1; -} - -/** - * asd_seq_pause_lseq - pause a link sequencer - * @asd_ha: pointer to a host adapter structure - * @lseq: link sequencer of interest - * - * Return 0 on success, negative on error. - */ -static int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq) -{ - u32 arp2ctl; - int count = PAUSE_TRIES; - - arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); - if (arp2ctl & PAUSED) - return 0; - - asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE); - do { - arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); - if (arp2ctl & PAUSED) - return 0; - udelay(PAUSE_DELAY); - } while (--count > 0); - - ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq); - return -1; -} - -/** - * asd_pause_lseq - pause the link sequencer(s) - * @asd_ha: pointer to host adapter structure - * @lseq_mask: mask of link sequencers of interest - * - * Return 0 on success, negative on failure. - */ -static int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) -{ - int lseq; - int err = 0; - - for_each_sequencer(lseq_mask, lseq_mask, lseq) { - err = asd_seq_pause_lseq(asd_ha, lseq); - if (err) - return err; - } - - return err; -} - -/** - * asd_seq_unpause_lseq - unpause a link sequencer - * @asd_ha: pointer to host adapter structure - * @lseq: link sequencer of interest - * - * Return 0 on success, negative on error. - */ -static int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq) -{ - u32 arp2ctl; - int count = PAUSE_TRIES; - - arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); - if (!(arp2ctl & PAUSED)) - return 0; - - asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE); - do { - arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); - if (!(arp2ctl & PAUSED)) - return 0; - udelay(PAUSE_DELAY); - } while (--count > 0); - - ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq); - return 0; -} - - -/* ---------- Downloading CSEQ/LSEQ microcode ---------- */ - -static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog, - u32 size) -{ - u32 addr = CSEQ_RAM_REG_BASE_ADR; - const u32 *prog = (u32 *) _prog; - u32 i; - - for (i = 0; i < size; i += 4, prog++, addr += 4) { - u32 val = asd_read_reg_dword(asd_ha, addr); - - if (le32_to_cpu(*prog) != val) { - asd_printk("%s: cseq verify failed at %u " - "read:0x%x, wanted:0x%x\n", - pci_name(asd_ha->pcidev), - i, val, le32_to_cpu(*prog)); - return -1; - } - } - ASD_DPRINTK("verified %d bytes, passed\n", size); - return 0; -} - -/** - * asd_verify_lseq - verify the microcode of a link sequencer - * @asd_ha: pointer to host adapter structure - * @_prog: pointer to the microcode - * @size: size of the microcode in bytes - * @lseq: link sequencer of interest - * - * The link sequencer code is accessed in 4 KB pages, which are selected - * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register. - * The 10 KB LSEQm instruction code is mapped, page at a time, at - * LmSEQRAM address. - */ -static int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog, - u32 size, int lseq) -{ -#define LSEQ_CODEPAGE_SIZE 4096 - int pages = (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE; - u32 page; - const u32 *prog = (u32 *) _prog; - - for (page = 0; page < pages; page++) { - u32 i; - - asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq), - page << LmRAMPAGE_LSHIFT); - for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE; - i += 4, prog++, size-=4) { - - u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i); - - if (le32_to_cpu(*prog) != val) { - asd_printk("%s: LSEQ%d verify failed " - "page:%d, offs:%d\n", - pci_name(asd_ha->pcidev), - lseq, page, i); - return -1; - } - } - } - ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq, - (int)((u8 *)prog-_prog)); - return 0; -} - -/** - * asd_verify_seq -- verify CSEQ/LSEQ microcode - * @asd_ha: pointer to host adapter structure - * @prog: pointer to microcode - * @size: size of the microcode - * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest - * - * Return 0 if microcode is correct, negative on mismatch. - */ -static int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog, - u32 size, u8 lseq_mask) -{ - if (lseq_mask == 0) - return asd_verify_cseq(asd_ha, prog, size); - else { - int lseq, err; - - for_each_sequencer(lseq_mask, lseq_mask, lseq) { - err = asd_verify_lseq(asd_ha, prog, size, lseq); - if (err) - return err; - } - } - - return 0; -} -#define ASD_DMA_MODE_DOWNLOAD -#ifdef ASD_DMA_MODE_DOWNLOAD -/* This is the size of the CSEQ Mapped instruction page */ -#define MAX_DMA_OVLY_COUNT ((1U << 14)-1) -static int asd_download_seq(struct asd_ha_struct *asd_ha, - const u8 * const prog, u32 size, u8 lseq_mask) -{ - u32 comstaten; - u32 reg; - int page; - const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT; - struct asd_dma_tok *token; - int err = 0; - - if (size % 4) { - asd_printk("sequencer program not multiple of 4\n"); - return -1; - } - - asd_pause_cseq(asd_ha); - asd_pause_lseq(asd_ha, 0xFF); - - /* save, disable and clear interrupts */ - comstaten = asd_read_reg_dword(asd_ha, COMSTATEN); - asd_write_reg_dword(asd_ha, COMSTATEN, 0); - asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK); - - asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN); - asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK); - - token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL); - if (!token) { - asd_printk("out of memory for dma SEQ download\n"); - err = -ENOMEM; - goto out; - } - ASD_DPRINTK("dma-ing %d bytes\n", size); - - for (page = 0; page < pages; page++) { - int i; - u32 left = min(size-page*MAX_DMA_OVLY_COUNT, - (u32)MAX_DMA_OVLY_COUNT); - - memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left); - asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle); - asd_write_reg_dword(asd_ha, OVLYDMACNT, left); - reg = !page ? RESETOVLYDMA : 0; - reg |= (STARTOVLYDMA | OVLYHALTERR); - reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); - /* Start DMA. */ - asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); - - for (i = PAUSE_TRIES*100; i > 0; i--) { - u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL); - if (!(dmadone & OVLYDMAACT)) - break; - udelay(PAUSE_DELAY); - } - } - - reg = asd_read_reg_dword(asd_ha, COMSTAT); - if (!(reg & OVLYDMADONE) || (reg & OVLYERR) - || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){ - asd_printk("%s: error DMA-ing sequencer code\n", - pci_name(asd_ha->pcidev)); - err = -ENODEV; - } - - asd_free_coherent(asd_ha, token); - out: - asd_write_reg_dword(asd_ha, COMSTATEN, comstaten); - - return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask); -} -#else /* ASD_DMA_MODE_DOWNLOAD */ -static int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog, - u32 size, u8 lseq_mask) -{ - int i; - u32 reg = 0; - const u32 *prog = (u32 *) _prog; - - if (size % 4) { - asd_printk("sequencer program not multiple of 4\n"); - return -1; - } - - asd_pause_cseq(asd_ha); - asd_pause_lseq(asd_ha, 0xFF); - - reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); - reg |= PIOCMODE; - - asd_write_reg_dword(asd_ha, OVLYDMACNT, size); - asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); - - ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n", - lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : ""); - - for (i = 0; i < size; i += 4, prog++) - asd_write_reg_dword(asd_ha, SPIODATA, *prog); - - reg = (reg & ~PIOCMODE) | OVLYHALTERR; - asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); - - return asd_verify_seq(asd_ha, _prog, size, lseq_mask); -} -#endif /* ASD_DMA_MODE_DOWNLOAD */ - -/** - * asd_seq_download_seqs - download the sequencer microcode - * @asd_ha: pointer to host adapter structure - * - * Download the central and link sequencer microcode. - */ -static int asd_seq_download_seqs(struct asd_ha_struct *asd_ha) -{ - int err; - - if (!asd_ha->hw_prof.enabled_phys) { - asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev)); - return -ENODEV; - } - - /* Download the CSEQ */ - ASD_DPRINTK("downloading CSEQ...\n"); - err = asd_download_seq(asd_ha, cseq_code, cseq_code_size, 0); - if (err) { - asd_printk("CSEQ download failed:%d\n", err); - return err; - } - - /* Download the Link Sequencers code. All of the Link Sequencers - * microcode can be downloaded at the same time. - */ - ASD_DPRINTK("downloading LSEQs...\n"); - err = asd_download_seq(asd_ha, lseq_code, lseq_code_size, - asd_ha->hw_prof.enabled_phys); - if (err) { - /* Try it one at a time */ - u8 lseq; - u8 lseq_mask = asd_ha->hw_prof.enabled_phys; - - for_each_sequencer(lseq_mask, lseq_mask, lseq) { - err = asd_download_seq(asd_ha, lseq_code, - lseq_code_size, 1<> 8; - asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx); - } - asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD, - first_scb_site_no); - asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL, - last_scb_site_no); - asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF); - asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF); - - /* CSEQ Mode independent, page 7 setup. */ - asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0); - asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0); - asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0); - asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0); - asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF); - asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF); - asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0); - asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0); - asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0); - asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0); - asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0); - asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0); -} - -/** - * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages - * @asd_ha: pointer to host adapter structure - */ -static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha) -{ - int i; - int moffs; - - moffs = CSEQ_PAGE_SIZE * 2; - - /* CSEQ Mode dependent, modes 0-7, page 0 setup. */ - for (i = 0; i < 8; i++) { - asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0); - asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0); - asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF); - asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF); - asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0); - } - - /* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */ - - /* CSEQ Mode dependent, mode 8, page 0 setup. */ - asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF); - asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0); - asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0); - asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0); - asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0); - asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0); - asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0); - asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0); - asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0); - asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0); - asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0); - asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0); - asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE, - (u16)last_scb_site_no+1); - asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE, - (u16)asd_ha->hw_prof.max_ddbs); - - /* CSEQ Mode dependent, mode 8, page 1 setup. */ - asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0); - asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0); - asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0); - asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0); - - /* CSEQ Mode dependent, mode 8, page 2 setup. */ - /* Tell the sequencer the bus address of the first SCB. */ - asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER, - asd_ha->seq.next_scb.dma_handle); - ASD_DPRINTK("First SCB dma_handle: 0x%llx\n", - (unsigned long long)asd_ha->seq.next_scb.dma_handle); - - /* Tell the sequencer the first Done List entry address. */ - asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE, - asd_ha->seq.actual_dl->dma_handle); - - /* Initialize the Q_DONE_POINTER with the least significant - * 4 bytes of the first Done List address. */ - asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER, - ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle)); - - asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE); - - /* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */ -} - -/** - * asd_init_cseq_scratch -- setup and init CSEQ - * @asd_ha: pointer to host adapter structure - * - * Setup and initialize Central sequencers. Initialize the mode - * independent and dependent scratch page to the default settings. - */ -static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha) -{ - asd_init_cseq_mip(asd_ha); - asd_init_cseq_mdp(asd_ha); -} - -/** - * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3 - * @asd_ha: pointer to host adapter structure - */ -static void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq) -{ - int i; - - /* LSEQ Mode independent page 0 setup. */ - asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF); - asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq); - asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq), - ASD_NOTIFY_ENABLE_SPINUP); - asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000); - asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0); - - /* LSEQ Mode independent page 1 setup. */ - asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF); - asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0); - - /* LSEQ Mode Independent page 2 setup. */ - asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF); - asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0); - for (i = 0; i < 12; i += 4) - asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0); - - /* LSEQ Mode Independent page 3 setup. */ - - /* Device present timer timeout */ - asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq), - ASD_DEV_PRESENT_TIMEOUT); - - /* SATA interlock timer disabled */ - asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq), - ASD_SATA_INTERLOCK_TIMEOUT); - - /* STP shutdown timer timeout constant, IGNORED by the sequencer, - * always 0. */ - asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq), - ASD_STP_SHUTDOWN_TIMEOUT); - - asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq), - ASD_SRST_ASSERT_TIMEOUT); - - asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq), - ASD_RCV_FIS_TIMEOUT); - - asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq), - ASD_ONE_MILLISEC_TIMEOUT); - - /* COM_INIT timer */ - asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq), - ASD_TEN_MILLISEC_TIMEOUT); - - asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq), - ASD_SMP_RCV_TIMEOUT); -} - -/** - * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages. - * @asd_ha: pointer to host adapter structure - */ -static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq) -{ - int i; - u32 moffs; - u16 ret_addr[] = { - 0xFFFF, /* mode 0 */ - 0xFFFF, /* mode 1 */ - mode2_task, /* mode 2 */ - 0, - 0xFFFF, /* mode 4/5 */ - 0xFFFF, /* mode 4/5 */ - }; - - /* - * Mode 0,1,2 and 4/5 have common field on page 0 for the first - * 14 bytes. - */ - for (i = 0; i < 3; i++) { - moffs = i * LSEQ_MODE_SCRATCH_SIZE; - asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs, - ret_addr[i]); - asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0); - asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0); - asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF); - asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0); - asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0); - } - /* - * Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3. - */ - asd_write_reg_word(asd_ha, - LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET, - ret_addr[5]); - asd_write_reg_word(asd_ha, - LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); - asd_write_reg_word(asd_ha, - LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); - asd_write_reg_word(asd_ha, - LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); - asd_write_reg_word(asd_ha, - LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); - asd_write_reg_byte(asd_ha, - LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); - asd_write_reg_word(asd_ha, - LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); - - /* LSEQ Mode dependent 0, page 0 setup. */ - asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq), - (u16)asd_ha->hw_prof.max_ddbs); - asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq), - (u16)last_scb_site_no+1); - asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq), - (u16) ((LmM0INTEN_MASK & 0xFFFF0000) >> 16)); - asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2, - (u16) LmM0INTEN_MASK & 0xFFFF); - asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0); - - /* LSEQ mode dependent, mode 1, page 0 setup. */ - asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF); - asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0); - - /* LSEQ Mode dependent mode 2, page 0 setup */ - asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0); - - /* LSEQ Mode dependent, mode 4/5, page 0 setup. */ - asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF); - asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0); - /* - * Set the desired interval between transmissions of the NOTIFY - * (ENABLE SPINUP) primitive. Must be initialized to val - 1. - */ - asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq), - ASD_NOTIFY_TIMEOUT - 1); - /* No delay for the first NOTIFY to be sent to the attached target. */ - asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq), - ASD_NOTIFY_DOWN_COUNT); - asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_INITIAL_COUNT(lseq), - ASD_NOTIFY_DOWN_COUNT); - - /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */ - for (i = 0; i < 2; i++) { - int j; - /* Start from Page 1 of Mode 0 and 1. */ - moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE; - /* All the fields of page 1 can be initialized to 0. */ - for (j = 0; j < LSEQ_PAGE_SIZE; j += 4) - asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0); - } - - /* LSEQ Mode dependent, mode 2, page 1 setup. */ - asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0); - - /* LSEQ Mode dependent, mode 4/5, page 1. */ - for (i = 0; i < LSEQ_PAGE_SIZE; i+=4) - asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0); - asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF); - asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF); - asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF); - asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF); - asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF); - asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF); - asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF); - asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF); - - /* LSEQ Mode dependent, mode 0, page 2 setup. */ - asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0); - asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0); - asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0); - - /* LSEQ Mode Dependent 1, page 2 setup. */ - asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0); - asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0); - - /* LSEQ Mode Dependent 2, page 2 setup. */ - /* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer, - * i.e. always 0. */ - asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0); - asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0); - asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0); - asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0); - - /* LSEQ Mode Dependent 4/5, page 2 setup. */ - asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0); - asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq), 0); -} - -/** - * asd_init_lseq_scratch -- setup and init link sequencers - * @asd_ha: pointer to host adapter struct - */ -static void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha) -{ - u8 lseq; - u8 lseq_mask; - - lseq_mask = asd_ha->hw_prof.enabled_phys; - for_each_sequencer(lseq_mask, lseq_mask, lseq) { - asd_init_lseq_mip(asd_ha, lseq); - asd_init_lseq_mdp(asd_ha, lseq); - } -} - -/** - * asd_init_scb_sites -- initialize sequencer SCB sites (memory). - * @asd_ha: pointer to host adapter structure - * - * This should be done before initializing common CSEQ and LSEQ - * scratch since those areas depend on some computed values here, - * last_scb_site_no, etc. - */ -static void asd_init_scb_sites(struct asd_ha_struct *asd_ha) -{ - u16 site_no; - u16 max_scbs = 0; - - for (site_no = asd_ha->hw_prof.max_scbs-1; - site_no != (u16) -1; - site_no--) { - u16 i; - - /* Initialize all fields in the SCB site to 0. */ - for (i = 0; i < ASD_SCB_SIZE; i += 4) - asd_scbsite_write_dword(asd_ha, site_no, i, 0); - - /* Initialize SCB Site Opcode field to invalid. */ - asd_scbsite_write_byte(asd_ha, site_no, - offsetof(struct scb_header, opcode), - 0xFF); - - /* Initialize SCB Site Flags field to mean a response - * frame has been received. This means inadvertent - * frames received to be dropped. */ - asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); - - /* Workaround needed by SEQ to fix a SATA issue is to exclude - * certain SCB sites from the free list. */ - if (!SCB_SITE_VALID(site_no)) - continue; - - if (last_scb_site_no == 0) - last_scb_site_no = site_no; - - /* For every SCB site, we need to initialize the - * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS, - * and SG Element Flag. */ - - /* Q_NEXT field of the last SCB is invalidated. */ - asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no); - - first_scb_site_no = site_no; - max_scbs++; - } - asd_ha->hw_prof.max_scbs = max_scbs; - ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs); - ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no); - ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no); -} - -/** - * asd_init_cseq_cio - initialize CSEQ CIO registers - * @asd_ha: pointer to host adapter structure - */ -static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) -{ - int i; - - asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0); - asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS); - asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0); - asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0); - asd_ha->seq.scbpro = 0; - asd_write_reg_dword(asd_ha, SCBPRO, 0); - asd_write_reg_dword(asd_ha, CSEQCON, 0); - - /* Initialize CSEQ Mode 11 Interrupt Vectors. - * The addresses are 16 bit wide and in dword units. - * The values of their macros are in byte units. - * Thus we have to divide by 4. */ - asd_write_reg_word(asd_ha, CM11INTVEC0, cseq_vecs[0]); - asd_write_reg_word(asd_ha, CM11INTVEC1, cseq_vecs[1]); - asd_write_reg_word(asd_ha, CM11INTVEC2, cseq_vecs[2]); - - /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ - asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC); - - /* Initialize CSEQ Scratch Page to 0x04. */ - asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04); - - /* Initialize CSEQ Mode[0-8] Dependent registers. */ - /* Initialize Scratch Page to 0. */ - for (i = 0; i < 9; i++) - asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0); - - /* Reset the ARP2 Program Count. */ - asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); - - for (i = 0; i < 8; i++) { - /* Initialize Mode n Link m Interrupt Enable. */ - asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF); - /* Initialize Mode n Request Mailbox. */ - asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0); - } -} - -/** - * asd_init_lseq_cio -- initialize LmSEQ CIO registers - * @asd_ha: pointer to host adapter structure - */ -static void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq) -{ - u8 *sas_addr; - int i; - - /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ - asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC); - - asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0); - - /* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */ - for (i = 0; i < 3; i++) - asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0); - - /* Initialize Mode 5 SCRATCHPAGE to 0. */ - asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0); - - asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0); - /* Initialize Mode 0,1,2 and 5 Interrupt Enable and - * Interrupt registers. */ - asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK); - asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF); - /* Mode 1 */ - asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK); - asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF); - /* Mode 2 */ - asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK); - asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF); - /* Mode 5 */ - asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK); - asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF); - - /* Enable HW Timer status. */ - asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK); - - /* Enable Primitive Status 0 and 1. */ - asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK); - asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK); - - /* Enable Frame Error. */ - asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK); - asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50); - - /* Initialize Mode 0 Transfer Level to 512. */ - asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512); - /* Initialize Mode 1 Transfer Level to 256. */ - asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256); - - /* Initialize Program Count. */ - asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); - - /* Enable Blind SG Move. */ - asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48); - asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq), - ASD_SATA_INTERLOCK_TIMEOUT); - - (void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq)); - - /* Clear Primitive Status 0 and 1. */ - asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF); - asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF); - - /* Clear HW Timer status. */ - asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF); - - /* Clear DMA Errors for Mode 0 and 1. */ - asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF); - asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF); - - /* Clear SG DMA Errors for Mode 0 and 1. */ - asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF); - asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF); - - /* Clear Mode 0 Buffer Parity Error. */ - asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR); - - /* Clear Mode 0 Frame Error register. */ - asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF); - - /* Reset LSEQ external interrupt arbiter. */ - asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL); - - /* Set the Phy SAS for the LmSEQ WWN. */ - sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr; - for (i = 0; i < SAS_ADDR_SIZE; i++) - asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]); - - /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */ - asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0); - - /* Set the Bus Inactivity Time Limit Timer. */ - asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9); - - /* Enable SATA Port Multiplier. */ - asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80); - - /* Initialize Interrupt Vector[0-10] address in Mode 3. - * See the comment on CSEQ_INT_* */ - asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]); - asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]); - asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]); - asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]); - asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]); - asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]); - asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]); - asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]); - asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]); - asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]); - asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]); - /* - * Program the Link LED control, applicable only for - * Chip Rev. B or later. - */ - asd_write_reg_dword(asd_ha, LmCONTROL(lseq), - (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms)); - - /* Set the Align Rate for SAS and STP mode. */ - asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT); - asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT); -} - - -/** - * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox - * @asd_ha: pointer to host adapter struct - */ -static void asd_post_init_cseq(struct asd_ha_struct *asd_ha) -{ - int i; - - for (i = 0; i < 8; i++) - asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF); - for (i = 0; i < 8; i++) - asd_read_reg_dword(asd_ha, CMnRSPMBX(i)); - /* Reset the external interrupt arbiter. */ - asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL); -} - -/** - * asd_init_ddb_0 -- initialize DDB 0 - * @asd_ha: pointer to host adapter structure - * - * Initialize DDB site 0 which is used internally by the sequencer. - */ -static void asd_init_ddb_0(struct asd_ha_struct *asd_ha) -{ - int i; - - /* Zero out the DDB explicitly */ - for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4) - asd_ddbsite_write_dword(asd_ha, 0, i, 0); - - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0); - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail), - asd_ha->hw_prof.max_ddbs-1); - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0); - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF); - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF); - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0); - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0); - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0); - asd_ddbsite_write_word(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh), - asd_ha->hw_prof.num_phys * 2); - asd_ddbsite_write_byte(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0); - asd_ddbsite_write_byte(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF); - asd_ddbsite_write_byte(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00); - /* DDB 0 is reserved */ - set_bit(0, asd_ha->hw_prof.ddb_bitmap); -} - -static void asd_seq_init_ddb_sites(struct asd_ha_struct *asd_ha) -{ - unsigned int i; - unsigned int ddb_site; - - for (ddb_site = 0 ; ddb_site < ASD_MAX_DDBS; ddb_site++) - for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) - asd_ddbsite_write_dword(asd_ha, ddb_site, i, 0); -} - -/** - * asd_seq_setup_seqs -- setup and initialize central and link sequencers - * @asd_ha: pointer to host adapter structure - */ -static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha) -{ - int lseq; - u8 lseq_mask; - - /* Initialize DDB sites */ - asd_seq_init_ddb_sites(asd_ha); - - /* Initialize SCB sites. Done first to compute some values which - * the rest of the init code depends on. */ - asd_init_scb_sites(asd_ha); - - /* Initialize CSEQ Scratch RAM registers. */ - asd_init_cseq_scratch(asd_ha); - - /* Initialize LmSEQ Scratch RAM registers. */ - asd_init_lseq_scratch(asd_ha); - - /* Initialize CSEQ CIO registers. */ - asd_init_cseq_cio(asd_ha); - - asd_init_ddb_0(asd_ha); - - /* Initialize LmSEQ CIO registers. */ - lseq_mask = asd_ha->hw_prof.enabled_phys; - for_each_sequencer(lseq_mask, lseq_mask, lseq) - asd_init_lseq_cio(asd_ha, lseq); - asd_post_init_cseq(asd_ha); -} - - -/** - * asd_seq_start_cseq -- start the central sequencer, CSEQ - * @asd_ha: pointer to host adapter structure - */ -static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha) -{ - /* Reset the ARP2 instruction to location zero. */ - asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); - - /* Unpause the CSEQ */ - return asd_unpause_cseq(asd_ha); -} - -/** - * asd_seq_start_lseq -- start a link sequencer - * @asd_ha: pointer to host adapter structure - * @lseq: the link sequencer of interest - */ -static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq) -{ - /* Reset the ARP2 instruction to location zero. */ - asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); - - /* Unpause the LmSEQ */ - return asd_seq_unpause_lseq(asd_ha, lseq); -} - -int asd_release_firmware(void) -{ - if (sequencer_fw) - release_firmware(sequencer_fw); - return 0; -} - -static int asd_request_firmware(struct asd_ha_struct *asd_ha) -{ - int err, i; - struct sequencer_file_header header; - const struct sequencer_file_header *hdr_ptr; - u32 csum = 0; - u16 *ptr_cseq_vecs, *ptr_lseq_vecs; - - if (sequencer_fw) - /* already loaded */ - return 0; - - err = request_firmware(&sequencer_fw, - SAS_RAZOR_SEQUENCER_FW_FILE, - &asd_ha->pcidev->dev); - if (err) - return err; - - hdr_ptr = (const struct sequencer_file_header *)sequencer_fw->data; - - header.csum = le32_to_cpu(hdr_ptr->csum); - header.major = le32_to_cpu(hdr_ptr->major); - header.minor = le32_to_cpu(hdr_ptr->minor); - header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset); - header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size); - header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset); - header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size); - header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset); - header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size); - header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset); - header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size); - header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task); - header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop); - header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop); - - for (i = sizeof(header.csum); i < sequencer_fw->size; i++) - csum += sequencer_fw->data[i]; - - if (csum != header.csum) { - asd_printk("Firmware file checksum mismatch\n"); - return -EINVAL; - } - - if (header.cseq_table_size != CSEQ_NUM_VECS || - header.lseq_table_size != LSEQ_NUM_VECS) { - asd_printk("Firmware file table size mismatch\n"); - return -EINVAL; - } - - asd_printk("Found sequencer Firmware version %d.%d (%s)\n", - header.major, header.minor, hdr_ptr->version); - - if (header.major != SAS_RAZOR_SEQUENCER_FW_MAJOR) { - asd_printk("Firmware Major Version Mismatch;" - "driver requires version %d.X", - SAS_RAZOR_SEQUENCER_FW_MAJOR); - return -EINVAL; - } - - ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset]; - ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset]; - mode2_task = header.mode2_task; - cseq_idle_loop = header.cseq_idle_loop; - lseq_idle_loop = header.lseq_idle_loop; - - for (i = 0; i < CSEQ_NUM_VECS; i++) - cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]); - - for (i = 0; i < LSEQ_NUM_VECS; i++) - lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]); - - cseq_code = &sequencer_fw->data[header.cseq_code_offset]; - cseq_code_size = header.cseq_code_size; - lseq_code = &sequencer_fw->data[header.lseq_code_offset]; - lseq_code_size = header.lseq_code_size; - - return 0; -} - -int asd_init_seqs(struct asd_ha_struct *asd_ha) -{ - int err; - - err = asd_request_firmware(asd_ha); - - if (err) { - asd_printk("Failed to load sequencer firmware file %s, error %d\n", - SAS_RAZOR_SEQUENCER_FW_FILE, err); - return err; - } - - err = asd_seq_download_seqs(asd_ha); - if (err) { - asd_printk("couldn't download sequencers for %s\n", - pci_name(asd_ha->pcidev)); - return err; - } - - asd_seq_setup_seqs(asd_ha); - - return 0; -} - -int asd_start_seqs(struct asd_ha_struct *asd_ha) -{ - int err; - u8 lseq_mask; - int lseq; - - err = asd_seq_start_cseq(asd_ha); - if (err) { - asd_printk("couldn't start CSEQ for %s\n", - pci_name(asd_ha->pcidev)); - return err; - } - - lseq_mask = asd_ha->hw_prof.enabled_phys; - for_each_sequencer(lseq_mask, lseq_mask, lseq) { - err = asd_seq_start_lseq(asd_ha, lseq); - if (err) { - asd_printk("coudln't start LSEQ %d for %s\n", lseq, - pci_name(asd_ha->pcidev)); - return err; - } - } - - return 0; -} - -/** - * asd_update_port_links -- update port_map_by_links and phy_is_up - * @sas_phy: pointer to the phy which has been added to a port - * - * 1) When a link reset has completed and we got BYTES DMAED with a - * valid frame we call this function for that phy, to indicate that - * the phy is up, i.e. we update the phy_is_up in DDB 0. The - * sequencer checks phy_is_up when pending SCBs are to be sent, and - * when an open address frame has been received. - * - * 2) When we know of ports, we call this function to update the map - * of phys participaing in that port, i.e. we update the - * port_map_by_links in DDB 0. When a HARD_RESET primitive has been - * received, the sequencer disables all phys in that port. - * port_map_by_links is also used as the conn_mask byte in the - * initiator/target port DDB. - */ -void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy) -{ - const u8 phy_mask = (u8) phy->asd_port->phy_mask; - u8 phy_is_up; - u8 mask; - int i, err; - unsigned long flags; - - spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); - for_each_phy(phy_mask, mask, i) - asd_ddbsite_write_byte(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, - port_map_by_links)+i,phy_mask); - - for (i = 0; i < 12; i++) { - phy_is_up = asd_ddbsite_read_byte(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, phy_is_up)); - err = asd_ddbsite_update_byte(asd_ha, 0, - offsetof(struct asd_ddb_seq_shared, phy_is_up), - phy_is_up, - phy_is_up | phy_mask); - if (!err) - break; - else if (err == -EFAULT) { - asd_printk("phy_is_up: parity error in DDB 0\n"); - break; - } - } - spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); - - if (err) - asd_printk("couldn't update DDB 0:error:%d\n", err); -} - -MODULE_FIRMWARE(SAS_RAZOR_SEQUENCER_FW_FILE); diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.h b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.h deleted file mode 100644 index ad787c55..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_seq.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Aic94xx SAS/SATA driver sequencer interface header file. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#ifndef _AIC94XX_SEQ_H_ -#define _AIC94XX_SEQ_H_ - -#define CSEQ_NUM_VECS 3 -#define LSEQ_NUM_VECS 11 - -#define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw" -#define SAS_RAZOR_SEQUENCER_FW_MAJOR 1 - -/* Note: All quantites in the sequencer file are little endian */ -struct sequencer_file_header { - /* Checksum of the entire contents of the sequencer excluding - * these four bytes */ - u32 csum; - /* numeric major version */ - u32 major; - /* numeric minor version */ - u32 minor; - /* version string printed by driver */ - char version[16]; - u32 cseq_table_offset; - u32 cseq_table_size; - u32 lseq_table_offset; - u32 lseq_table_size; - u32 cseq_code_offset; - u32 cseq_code_size; - u32 lseq_code_offset; - u32 lseq_code_size; - u16 mode2_task; - u16 cseq_idle_loop; - u16 lseq_idle_loop; -} __attribute__((packed)); - -#ifdef __KERNEL__ -int asd_init_seqs(struct asd_ha_struct *asd_ha); -int asd_start_seqs(struct asd_ha_struct *asd_ha); -int asd_release_firmware(void); - -void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy); -#endif - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_task.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_task.c deleted file mode 100644 index 393e7ce8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_task.c +++ /dev/null @@ -1,643 +0,0 @@ -/* - * Aic94xx SAS/SATA Tasks - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include "aic94xx.h" -#include "aic94xx_sas.h" -#include "aic94xx_hwi.h" - -static void asd_unbuild_ata_ascb(struct asd_ascb *a); -static void asd_unbuild_smp_ascb(struct asd_ascb *a); -static void asd_unbuild_ssp_ascb(struct asd_ascb *a); - -static void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num) -{ - unsigned long flags; - - spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); - asd_ha->seq.can_queue += num; - spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); -} - -/* PCI_DMA_... to our direction translation. - */ -static const u8 data_dir_flags[] = { - [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ - [PCI_DMA_TODEVICE] = DATA_DIR_OUT, /* OUTBOUND */ - [PCI_DMA_FROMDEVICE] = DATA_DIR_IN, /* INBOUND */ - [PCI_DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ -}; - -static int asd_map_scatterlist(struct sas_task *task, - struct sg_el *sg_arr, - gfp_t gfp_flags) -{ - struct asd_ascb *ascb = task->lldd_task; - struct asd_ha_struct *asd_ha = ascb->ha; - struct scatterlist *sc; - int num_sg, res; - - if (task->data_dir == PCI_DMA_NONE) - return 0; - - if (task->num_scatter == 0) { - void *p = task->scatter; - dma_addr_t dma = pci_map_single(asd_ha->pcidev, p, - task->total_xfer_len, - task->data_dir); - sg_arr[0].bus_addr = cpu_to_le64((u64)dma); - sg_arr[0].size = cpu_to_le32(task->total_xfer_len); - sg_arr[0].flags |= ASD_SG_EL_LIST_EOL; - return 0; - } - - /* STP tasks come from libata which has already mapped - * the SG list */ - if (sas_protocol_ata(task->task_proto)) - num_sg = task->num_scatter; - else - num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, - task->num_scatter, task->data_dir); - if (num_sg == 0) - return -ENOMEM; - - if (num_sg > 3) { - int i; - - ascb->sg_arr = asd_alloc_coherent(asd_ha, - num_sg*sizeof(struct sg_el), - gfp_flags); - if (!ascb->sg_arr) { - res = -ENOMEM; - goto err_unmap; - } - for_each_sg(task->scatter, sc, num_sg, i) { - struct sg_el *sg = - &((struct sg_el *)ascb->sg_arr->vaddr)[i]; - sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc)); - sg->size = cpu_to_le32((u32)sg_dma_len(sc)); - if (i == num_sg-1) - sg->flags |= ASD_SG_EL_LIST_EOL; - } - - for_each_sg(task->scatter, sc, 2, i) { - sg_arr[i].bus_addr = - cpu_to_le64((u64)sg_dma_address(sc)); - sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc)); - } - sg_arr[1].next_sg_offs = 2 * sizeof(*sg_arr); - sg_arr[1].flags |= ASD_SG_EL_LIST_EOS; - - memset(&sg_arr[2], 0, sizeof(*sg_arr)); - sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle); - } else { - int i; - for_each_sg(task->scatter, sc, num_sg, i) { - sg_arr[i].bus_addr = - cpu_to_le64((u64)sg_dma_address(sc)); - sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc)); - } - sg_arr[i-1].flags |= ASD_SG_EL_LIST_EOL; - } - - return 0; -err_unmap: - if (sas_protocol_ata(task->task_proto)) - pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter, - task->data_dir); - return res; -} - -static void asd_unmap_scatterlist(struct asd_ascb *ascb) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - struct sas_task *task = ascb->uldd_task; - - if (task->data_dir == PCI_DMA_NONE) - return; - - if (task->num_scatter == 0) { - dma_addr_t dma = (dma_addr_t) - le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr); - pci_unmap_single(ascb->ha->pcidev, dma, task->total_xfer_len, - task->data_dir); - return; - } - - asd_free_coherent(asd_ha, ascb->sg_arr); - if (task->task_proto != SAS_PROTOCOL_STP) - pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter, - task->data_dir); -} - -/* ---------- Task complete tasklet ---------- */ - -static void asd_get_response_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - struct sas_task *task = ascb->uldd_task; - struct task_status_struct *ts = &task->task_status; - unsigned long flags; - struct tc_resp_sb_struct { - __le16 index_escb; - u8 len_lsb; - u8 flags; - } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block; - -/* int size = ((resp_sb->flags & 7) << 8) | resp_sb->len_lsb; */ - int edb_id = ((resp_sb->flags & 0x70) >> 4)-1; - struct asd_ascb *escb; - struct asd_dma_tok *edb; - void *r; - - spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags); - escb = asd_tc_index_find(&asd_ha->seq, - (int)le16_to_cpu(resp_sb->index_escb)); - spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags); - - if (!escb) { - ASD_DPRINTK("Uh-oh! No escb for this dl?!\n"); - return; - } - - ts->buf_valid_size = 0; - edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index]; - r = edb->vaddr; - if (task->task_proto == SAS_PROTOCOL_SSP) { - struct ssp_response_iu *iu = - r + 16 + sizeof(struct ssp_frame_hdr); - - ts->residual = le32_to_cpu(*(__le32 *)r); - - sas_ssp_task_response(&asd_ha->pcidev->dev, task, iu); - } else { - struct ata_task_resp *resp = (void *) &ts->buf[0]; - - ts->residual = le32_to_cpu(*(__le32 *)r); - - if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { - resp->frame_len = le16_to_cpu(*(__le16 *)(r+6)); - memcpy(&resp->ending_fis[0], r+16, ATA_RESP_FIS_SIZE); - ts->buf_valid_size = sizeof(*resp); - } - } - - asd_invalidate_edb(escb, edb_id); -} - -static void asd_task_tasklet_complete(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - struct sas_task *task = ascb->uldd_task; - struct task_status_struct *ts = &task->task_status; - unsigned long flags; - u8 opcode = dl->opcode; - - asd_can_dequeue(ascb->ha, 1); - -Again: - switch (opcode) { - case TC_NO_ERROR: - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_STAT_GOOD; - break; - case TC_UNDERRUN: - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_UNDERRUN; - ts->residual = le32_to_cpu(*(__le32 *)dl->status_block); - break; - case TC_OVERRUN: - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - ts->residual = 0; - break; - case TC_SSP_RESP: - case TC_ATA_RESP: - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_PROTO_RESPONSE; - asd_get_response_tasklet(ascb, dl); - break; - case TF_OPEN_REJECT: - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_OPEN_REJECT; - if (dl->status_block[1] & 2) - ts->open_rej_reason = 1 + dl->status_block[2]; - else if (dl->status_block[1] & 1) - ts->open_rej_reason = (dl->status_block[2] >> 4)+10; - else - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - break; - case TF_OPEN_TO: - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_OPEN_TO; - break; - case TF_PHY_DOWN: - case TU_PHY_DOWN: - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - break; - case TI_PHY_DOWN: - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_PHY_DOWN; - break; - case TI_BREAK: - case TI_PROTO_ERR: - case TI_NAK: - case TI_ACK_NAK_TO: - case TF_SMP_XMIT_RCV_ERR: - case TC_ATA_R_ERR_RECV: - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_INTERRUPTED; - break; - case TF_BREAK: - case TU_BREAK: - case TU_ACK_NAK_TO: - case TF_SMPRSP_TO: - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_DEV_NO_RESPONSE; - break; - case TF_NAK_RECV: - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_NAK_R_ERR; - break; - case TA_I_T_NEXUS_LOSS: - opcode = dl->status_block[0]; - goto Again; - break; - case TF_INV_CONN_HANDLE: - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_DEVICE_UNKNOWN; - break; - case TF_REQUESTED_N_PENDING: - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PENDING; - break; - case TC_TASK_CLEARED: - case TA_ON_REQ: - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_ABORTED_TASK; - break; - - case TF_NO_SMP_CONN: - case TF_TMF_NO_CTX: - case TF_TMF_NO_TAG: - case TF_TMF_TAG_FREE: - case TF_TMF_TASK_DONE: - case TF_TMF_NO_CONN_HANDLE: - case TF_IRTT_TO: - case TF_IU_SHORT: - case TF_DATA_OFFS_ERR: - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_DEV_NO_RESPONSE; - break; - - case TC_LINK_ADM_RESP: - case TC_CONTROL_PHY: - case TC_RESUME: - case TC_PARTIAL_SG_LIST: - default: - ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __func__, opcode); - break; - } - - switch (task->task_proto) { - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - asd_unbuild_ata_ascb(ascb); - break; - case SAS_PROTOCOL_SMP: - asd_unbuild_smp_ascb(ascb); - break; - case SAS_PROTOCOL_SSP: - asd_unbuild_ssp_ascb(ascb); - default: - break; - } - - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags &= ~SAS_TASK_STATE_PENDING; - task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - task->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { - struct completion *completion = ascb->completion; - spin_unlock_irqrestore(&task->task_state_lock, flags); - ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - task, opcode, ts->resp, ts->stat); - if (completion) - complete(completion); - } else { - spin_unlock_irqrestore(&task->task_state_lock, flags); - task->lldd_task = NULL; - asd_ascb_free(ascb); - mb(); - task->task_done(task); - } -} - -/* ---------- ATA ---------- */ - -static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task, - gfp_t gfp_flags) -{ - struct domain_device *dev = task->dev; - struct scb *scb; - u8 flags; - int res = 0; - - scb = ascb->scb; - - if (unlikely(task->ata_task.device_control_reg_update)) - scb->header.opcode = CONTROL_ATA_DEV; - else if (dev->sata_dev.command_set == ATA_COMMAND_SET) - scb->header.opcode = INITIATE_ATA_TASK; - else - scb->header.opcode = INITIATE_ATAPI_TASK; - - scb->ata_task.proto_conn_rate = (1 << 5); /* STP */ - if (dev->port->oob_mode == SAS_OOB_MODE) - scb->ata_task.proto_conn_rate |= dev->linkrate; - - scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len); - scb->ata_task.fis = task->ata_task.fis; - if (likely(!task->ata_task.device_control_reg_update)) - scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ - scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */ - if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) - memcpy(scb->ata_task.atapi_packet, task->ata_task.atapi_packet, - 16); - scb->ata_task.sister_scb = cpu_to_le16(0xFFFF); - scb->ata_task.conn_handle = cpu_to_le16( - (u16)(unsigned long)dev->lldd_dev); - - if (likely(!task->ata_task.device_control_reg_update)) { - flags = 0; - if (task->ata_task.dma_xfer) - flags |= DATA_XFER_MODE_DMA; - if (task->ata_task.use_ncq && - dev->sata_dev.command_set != ATAPI_COMMAND_SET) - flags |= ATA_Q_TYPE_NCQ; - flags |= data_dir_flags[task->data_dir]; - scb->ata_task.ata_flags = flags; - - scb->ata_task.retry_count = task->ata_task.retry_count; - - flags = 0; - if (task->ata_task.set_affil_pol) - flags |= SET_AFFIL_POLICY; - if (task->ata_task.stp_affil_pol) - flags |= STP_AFFIL_POLICY; - scb->ata_task.flags = flags; - } - ascb->tasklet_complete = asd_task_tasklet_complete; - - if (likely(!task->ata_task.device_control_reg_update)) - res = asd_map_scatterlist(task, scb->ata_task.sg_element, - gfp_flags); - - return res; -} - -static void asd_unbuild_ata_ascb(struct asd_ascb *a) -{ - asd_unmap_scatterlist(a); -} - -/* ---------- SMP ---------- */ - -static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task, - gfp_t gfp_flags) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - struct domain_device *dev = task->dev; - struct scb *scb; - - pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); - - scb = ascb->scb; - - scb->header.opcode = INITIATE_SMP_TASK; - - scb->smp_task.proto_conn_rate = dev->linkrate; - - scb->smp_task.smp_req.bus_addr = - cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req)); - scb->smp_task.smp_req.size = - cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4); - - scb->smp_task.smp_resp.bus_addr = - cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp)); - scb->smp_task.smp_resp.size = - cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4); - - scb->smp_task.sister_scb = cpu_to_le16(0xFFFF); - scb->smp_task.conn_handle = cpu_to_le16((u16) - (unsigned long)dev->lldd_dev); - - ascb->tasklet_complete = asd_task_tasklet_complete; - - return 0; -} - -static void asd_unbuild_smp_ascb(struct asd_ascb *a) -{ - struct sas_task *task = a->uldd_task; - - BUG_ON(!task); - pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); -} - -/* ---------- SSP ---------- */ - -static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task, - gfp_t gfp_flags) -{ - struct domain_device *dev = task->dev; - struct scb *scb; - int res = 0; - - scb = ascb->scb; - - scb->header.opcode = INITIATE_SSP_TASK; - - scb->ssp_task.proto_conn_rate = (1 << 4); /* SSP */ - scb->ssp_task.proto_conn_rate |= dev->linkrate; - scb->ssp_task.total_xfer_len = cpu_to_le32(task->total_xfer_len); - scb->ssp_task.ssp_frame.frame_type = SSP_DATA; - memcpy(scb->ssp_task.ssp_frame.hashed_dest_addr, dev->hashed_sas_addr, - HASHED_SAS_ADDR_SIZE); - memcpy(scb->ssp_task.ssp_frame.hashed_src_addr, - dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); - scb->ssp_task.ssp_frame.tptt = cpu_to_be16(0xFFFF); - - memcpy(scb->ssp_task.ssp_cmd.lun, task->ssp_task.LUN, 8); - if (task->ssp_task.enable_first_burst) - scb->ssp_task.ssp_cmd.efb_prio_attr |= EFB_MASK; - scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_prio << 3); - scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_attr & 7); - memcpy(scb->ssp_task.ssp_cmd.cdb, task->ssp_task.cdb, 16); - - scb->ssp_task.sister_scb = cpu_to_le16(0xFFFF); - scb->ssp_task.conn_handle = cpu_to_le16( - (u16)(unsigned long)dev->lldd_dev); - scb->ssp_task.data_dir = data_dir_flags[task->data_dir]; - scb->ssp_task.retry_count = scb->ssp_task.retry_count; - - ascb->tasklet_complete = asd_task_tasklet_complete; - - res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags); - - return res; -} - -static void asd_unbuild_ssp_ascb(struct asd_ascb *a) -{ - asd_unmap_scatterlist(a); -} - -/* ---------- Execute Task ---------- */ - -static int asd_can_queue(struct asd_ha_struct *asd_ha, int num) -{ - int res = 0; - unsigned long flags; - - spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); - if ((asd_ha->seq.can_queue - num) < 0) - res = -SAS_QUEUE_FULL; - else - asd_ha->seq.can_queue -= num; - spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); - - return res; -} - -int asd_execute_task(struct sas_task *task, const int num, - gfp_t gfp_flags) -{ - int res = 0; - LIST_HEAD(alist); - struct sas_task *t = task; - struct asd_ascb *ascb = NULL, *a; - struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; - unsigned long flags; - - res = asd_can_queue(asd_ha, num); - if (res) - return res; - - res = num; - ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags); - if (res) { - res = -ENOMEM; - goto out_err; - } - - __list_add(&alist, ascb->list.prev, &ascb->list); - list_for_each_entry(a, &alist, list) { - a->uldd_task = t; - t->lldd_task = a; - t = list_entry(t->list.next, struct sas_task, list); - } - list_for_each_entry(a, &alist, list) { - t = a->uldd_task; - a->uldd_timer = 1; - if (t->task_proto & SAS_PROTOCOL_STP) - t->task_proto = SAS_PROTOCOL_STP; - switch (t->task_proto) { - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - res = asd_build_ata_ascb(a, t, gfp_flags); - break; - case SAS_PROTOCOL_SMP: - res = asd_build_smp_ascb(a, t, gfp_flags); - break; - case SAS_PROTOCOL_SSP: - res = asd_build_ssp_ascb(a, t, gfp_flags); - break; - default: - asd_printk("unknown sas_task proto: 0x%x\n", - t->task_proto); - res = -ENOMEM; - break; - } - if (res) - goto out_err_unmap; - - spin_lock_irqsave(&t->task_state_lock, flags); - t->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock_irqrestore(&t->task_state_lock, flags); - } - list_del_init(&alist); - - res = asd_post_ascb_list(asd_ha, ascb, num); - if (unlikely(res)) { - a = NULL; - __list_add(&alist, ascb->list.prev, &ascb->list); - goto out_err_unmap; - } - - return 0; -out_err_unmap: - { - struct asd_ascb *b = a; - list_for_each_entry(a, &alist, list) { - if (a == b) - break; - t = a->uldd_task; - spin_lock_irqsave(&t->task_state_lock, flags); - t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - spin_unlock_irqrestore(&t->task_state_lock, flags); - switch (t->task_proto) { - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - asd_unbuild_ata_ascb(a); - break; - case SAS_PROTOCOL_SMP: - asd_unbuild_smp_ascb(a); - break; - case SAS_PROTOCOL_SSP: - asd_unbuild_ssp_ascb(a); - default: - break; - } - t->lldd_task = NULL; - } - } - list_del_init(&alist); -out_err: - if (ascb) - asd_ascb_free_list(ascb); - asd_can_dequeue(asd_ha, num); - return res; -} diff --git a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_tmf.c b/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_tmf.c deleted file mode 100644 index cf904093..00000000 --- a/ANDROID_3.4.5/drivers/scsi/aic94xx/aic94xx_tmf.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Aic94xx Task Management Functions - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This file is part of the aic94xx driver. - * - * The aic94xx driver is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * The aic94xx driver is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aic94xx driver; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include "aic94xx.h" -#include "aic94xx_sas.h" -#include "aic94xx_hwi.h" - -/* ---------- Internal enqueue ---------- */ - -static int asd_enqueue_internal(struct asd_ascb *ascb, - void (*tasklet_complete)(struct asd_ascb *, - struct done_list_struct *), - void (*timed_out)(unsigned long)) -{ - int res; - - ascb->tasklet_complete = tasklet_complete; - ascb->uldd_timer = 1; - - ascb->timer.data = (unsigned long) ascb; - ascb->timer.function = timed_out; - ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT; - - add_timer(&ascb->timer); - - res = asd_post_ascb_list(ascb->ha, ascb, 1); - if (unlikely(res)) - del_timer(&ascb->timer); - return res; -} - -/* ---------- CLEAR NEXUS ---------- */ - -struct tasklet_completion_status { - int dl_opcode; - int tmf_state; - u8 tag_valid:1; - __be16 tag; -}; - -#define DECLARE_TCS(tcs) \ - struct tasklet_completion_status tcs = { \ - .dl_opcode = 0, \ - .tmf_state = 0, \ - .tag_valid = 0, \ - .tag = 0, \ - } - - -static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - struct tasklet_completion_status *tcs = ascb->uldd_task; - ASD_DPRINTK("%s: here\n", __func__); - if (!del_timer(&ascb->timer)) { - ASD_DPRINTK("%s: couldn't delete timer\n", __func__); - return; - } - ASD_DPRINTK("%s: opcode: 0x%x\n", __func__, dl->opcode); - tcs->dl_opcode = dl->opcode; - complete(ascb->completion); - asd_ascb_free(ascb); -} - -static void asd_clear_nexus_timedout(unsigned long data) -{ - struct asd_ascb *ascb = (void *)data; - struct tasklet_completion_status *tcs = ascb->uldd_task; - - ASD_DPRINTK("%s: here\n", __func__); - tcs->dl_opcode = TMF_RESP_FUNC_FAILED; - complete(ascb->completion); -} - -#define CLEAR_NEXUS_PRE \ - struct asd_ascb *ascb; \ - struct scb *scb; \ - int res; \ - DECLARE_COMPLETION_ONSTACK(completion); \ - DECLARE_TCS(tcs); \ - \ - ASD_DPRINTK("%s: PRE\n", __func__); \ - res = 1; \ - ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \ - if (!ascb) \ - return -ENOMEM; \ - \ - ascb->completion = &completion; \ - ascb->uldd_task = &tcs; \ - scb = ascb->scb; \ - scb->header.opcode = CLEAR_NEXUS - -#define CLEAR_NEXUS_POST \ - ASD_DPRINTK("%s: POST\n", __func__); \ - res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \ - asd_clear_nexus_timedout); \ - if (res) \ - goto out_err; \ - ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __func__); \ - wait_for_completion(&completion); \ - res = tcs.dl_opcode; \ - if (res == TC_NO_ERROR) \ - res = TMF_RESP_FUNC_COMPLETE; \ - return res; \ -out_err: \ - asd_ascb_free(ascb); \ - return res - -int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha) -{ - struct asd_ha_struct *asd_ha = sas_ha->lldd_ha; - - CLEAR_NEXUS_PRE; - scb->clear_nexus.nexus = NEXUS_ADAPTER; - CLEAR_NEXUS_POST; -} - -int asd_clear_nexus_port(struct asd_sas_port *port) -{ - struct asd_ha_struct *asd_ha = port->ha->lldd_ha; - - CLEAR_NEXUS_PRE; - scb->clear_nexus.nexus = NEXUS_PORT; - scb->clear_nexus.conn_mask = port->phy_mask; - CLEAR_NEXUS_POST; -} - -enum clear_nexus_phase { - NEXUS_PHASE_PRE, - NEXUS_PHASE_POST, - NEXUS_PHASE_RESUME, -}; - -static int asd_clear_nexus_I_T(struct domain_device *dev, - enum clear_nexus_phase phase) -{ - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - - CLEAR_NEXUS_PRE; - scb->clear_nexus.nexus = NEXUS_I_T; - switch (phase) { - case NEXUS_PHASE_PRE: - scb->clear_nexus.flags = EXEC_Q | SUSPEND_TX; - break; - case NEXUS_PHASE_POST: - scb->clear_nexus.flags = SEND_Q | NOTINQ; - break; - case NEXUS_PHASE_RESUME: - scb->clear_nexus.flags = RESUME_TX; - } - scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) - dev->lldd_dev); - CLEAR_NEXUS_POST; -} - -int asd_I_T_nexus_reset(struct domain_device *dev) -{ - int res, tmp_res, i; - struct sas_phy *phy = sas_get_local_phy(dev); - /* Standard mandates link reset for ATA (type 0) and - * hard reset for SSP (type 1) */ - int reset_type = (dev->dev_type == SATA_DEV || - (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1; - - asd_clear_nexus_I_T(dev, NEXUS_PHASE_PRE); - /* send a hard reset */ - ASD_DPRINTK("sending %s reset to %s\n", - reset_type ? "hard" : "soft", dev_name(&phy->dev)); - res = sas_phy_reset(phy, reset_type); - if (res == TMF_RESP_FUNC_COMPLETE || res == -ENODEV) { - /* wait for the maximum settle time */ - msleep(500); - /* clear all outstanding commands (keep nexus suspended) */ - asd_clear_nexus_I_T(dev, NEXUS_PHASE_POST); - } - for (i = 0 ; i < 3; i++) { - tmp_res = asd_clear_nexus_I_T(dev, NEXUS_PHASE_RESUME); - if (tmp_res == TC_RESUME) - goto out; - msleep(500); - } - - /* This is a bit of a problem: the sequencer is still suspended - * and is refusing to resume. Hope it will resume on a bigger hammer - * or the disk is lost */ - dev_printk(KERN_ERR, &phy->dev, - "Failed to resume nexus after reset 0x%x\n", tmp_res); - - res = TMF_RESP_FUNC_FAILED; - out: - sas_put_local_phy(phy); - return res; -} - -static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun) -{ - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - - CLEAR_NEXUS_PRE; - scb->clear_nexus.nexus = NEXUS_I_T_L; - scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ; - memcpy(scb->clear_nexus.ssp_task.lun, lun, 8); - scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) - dev->lldd_dev); - CLEAR_NEXUS_POST; -} - -static int asd_clear_nexus_tag(struct sas_task *task) -{ - struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; - struct asd_ascb *tascb = task->lldd_task; - - CLEAR_NEXUS_PRE; - scb->clear_nexus.nexus = NEXUS_TAG; - memcpy(scb->clear_nexus.ssp_task.lun, task->ssp_task.LUN, 8); - scb->clear_nexus.ssp_task.tag = tascb->tag; - if (task->dev->tproto) - scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) - task->dev->lldd_dev); - CLEAR_NEXUS_POST; -} - -static int asd_clear_nexus_index(struct sas_task *task) -{ - struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; - struct asd_ascb *tascb = task->lldd_task; - - CLEAR_NEXUS_PRE; - scb->clear_nexus.nexus = NEXUS_TRANS_CX; - if (task->dev->tproto) - scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) - task->dev->lldd_dev); - scb->clear_nexus.index = cpu_to_le16(tascb->tc_index); - CLEAR_NEXUS_POST; -} - -/* ---------- TMFs ---------- */ - -static void asd_tmf_timedout(unsigned long data) -{ - struct asd_ascb *ascb = (void *) data; - struct tasklet_completion_status *tcs = ascb->uldd_task; - - ASD_DPRINTK("tmf timed out\n"); - tcs->tmf_state = TMF_RESP_FUNC_FAILED; - complete(ascb->completion); -} - -static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - struct asd_ha_struct *asd_ha = ascb->ha; - unsigned long flags; - struct tc_resp_sb_struct { - __le16 index_escb; - u8 len_lsb; - u8 flags; - } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block; - - int edb_id = ((resp_sb->flags & 0x70) >> 4)-1; - struct asd_ascb *escb; - struct asd_dma_tok *edb; - struct ssp_frame_hdr *fh; - struct ssp_response_iu *ru; - int res = TMF_RESP_FUNC_FAILED; - - ASD_DPRINTK("tmf resp tasklet\n"); - - spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags); - escb = asd_tc_index_find(&asd_ha->seq, - (int)le16_to_cpu(resp_sb->index_escb)); - spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags); - - if (!escb) { - ASD_DPRINTK("Uh-oh! No escb for this dl?!\n"); - return res; - } - - edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index]; - ascb->tag = *(__be16 *)(edb->vaddr+4); - fh = edb->vaddr + 16; - ru = edb->vaddr + 16 + sizeof(*fh); - res = ru->status; - if (ru->datapres == 1) /* Response data present */ - res = ru->resp_data[3]; -#if 0 - ascb->tag = fh->tag; -#endif - ascb->tag_valid = 1; - - asd_invalidate_edb(escb, edb_id); - return res; -} - -static void asd_tmf_tasklet_complete(struct asd_ascb *ascb, - struct done_list_struct *dl) -{ - struct tasklet_completion_status *tcs; - - if (!del_timer(&ascb->timer)) - return; - - tcs = ascb->uldd_task; - ASD_DPRINTK("tmf tasklet complete\n"); - - tcs->dl_opcode = dl->opcode; - - if (dl->opcode == TC_SSP_RESP) { - tcs->tmf_state = asd_get_tmf_resp_tasklet(ascb, dl); - tcs->tag_valid = ascb->tag_valid; - tcs->tag = ascb->tag; - } - - complete(ascb->completion); - asd_ascb_free(ascb); -} - -static int asd_clear_nexus(struct sas_task *task) -{ - int res = TMF_RESP_FUNC_FAILED; - int leftover; - struct asd_ascb *tascb = task->lldd_task; - DECLARE_COMPLETION_ONSTACK(completion); - unsigned long flags; - - tascb->completion = &completion; - - ASD_DPRINTK("task not done, clearing nexus\n"); - if (tascb->tag_valid) - res = asd_clear_nexus_tag(task); - else - res = asd_clear_nexus_index(task); - leftover = wait_for_completion_timeout(&completion, - AIC94XX_SCB_TIMEOUT); - tascb->completion = NULL; - ASD_DPRINTK("came back from clear nexus\n"); - spin_lock_irqsave(&task->task_state_lock, flags); - if (leftover < 1) - res = TMF_RESP_FUNC_FAILED; - if (task->task_state_flags & SAS_TASK_STATE_DONE) - res = TMF_RESP_FUNC_COMPLETE; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - return res; -} - -/** - * asd_abort_task -- ABORT TASK TMF - * @task: the task to be aborted - * - * Before calling ABORT TASK the task state flags should be ORed with - * SAS_TASK_STATE_ABORTED (unless SAS_TASK_STATE_DONE is set) under - * the task_state_lock IRQ spinlock, then ABORT TASK *must* be called. - * - * Implements the ABORT TASK TMF, I_T_L_Q nexus. - * Returns: SAS TMF responses (see sas_task.h), - * -ENOMEM, - * -SAS_QUEUE_FULL. - * - * When ABORT TASK returns, the caller of ABORT TASK checks first the - * task->task_state_flags, and then the return value of ABORT TASK. - * - * If the task has task state bit SAS_TASK_STATE_DONE set, then the - * task was completed successfully prior to it being aborted. The - * caller of ABORT TASK has responsibility to call task->task_done() - * xor free the task, depending on their framework. The return code - * is TMF_RESP_FUNC_FAILED in this case. - * - * Else the SAS_TASK_STATE_DONE bit is not set, - * If the return code is TMF_RESP_FUNC_COMPLETE, then - * the task was aborted successfully. The caller of - * ABORT TASK has responsibility to call task->task_done() - * to finish the task, xor free the task depending on their - * framework. - * else - * the ABORT TASK returned some kind of error. The task - * was _not_ cancelled. Nothing can be assumed. - * The caller of ABORT TASK may wish to retry. - */ -int asd_abort_task(struct sas_task *task) -{ - struct asd_ascb *tascb = task->lldd_task; - struct asd_ha_struct *asd_ha = tascb->ha; - int res = 1; - unsigned long flags; - struct asd_ascb *ascb = NULL; - struct scb *scb; - int leftover; - DECLARE_TCS(tcs); - DECLARE_COMPLETION_ONSTACK(completion); - DECLARE_COMPLETION_ONSTACK(tascb_completion); - - tascb->completion = &tascb_completion; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - res = TMF_RESP_FUNC_COMPLETE; - ASD_DPRINTK("%s: task 0x%p done\n", __func__, task); - goto out_done; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - - ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); - if (!ascb) - return -ENOMEM; - - ascb->uldd_task = &tcs; - ascb->completion = &completion; - scb = ascb->scb; - scb->header.opcode = SCB_ABORT_TASK; - - switch (task->task_proto) { - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - scb->abort_task.proto_conn_rate = (1 << 5); /* STP */ - break; - case SAS_PROTOCOL_SSP: - scb->abort_task.proto_conn_rate = (1 << 4); /* SSP */ - scb->abort_task.proto_conn_rate |= task->dev->linkrate; - break; - case SAS_PROTOCOL_SMP: - break; - default: - break; - } - - if (task->task_proto == SAS_PROTOCOL_SSP) { - scb->abort_task.ssp_frame.frame_type = SSP_TASK; - memcpy(scb->abort_task.ssp_frame.hashed_dest_addr, - task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); - memcpy(scb->abort_task.ssp_frame.hashed_src_addr, - task->dev->port->ha->hashed_sas_addr, - HASHED_SAS_ADDR_SIZE); - scb->abort_task.ssp_frame.tptt = cpu_to_be16(0xFFFF); - - memcpy(scb->abort_task.ssp_task.lun, task->ssp_task.LUN, 8); - scb->abort_task.ssp_task.tmf = TMF_ABORT_TASK; - scb->abort_task.ssp_task.tag = cpu_to_be16(0xFFFF); - } - - scb->abort_task.sister_scb = cpu_to_le16(0xFFFF); - scb->abort_task.conn_handle = cpu_to_le16( - (u16)(unsigned long)task->dev->lldd_dev); - scb->abort_task.retry_count = 1; - scb->abort_task.index = cpu_to_le16((u16)tascb->tc_index); - scb->abort_task.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST); - - res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete, - asd_tmf_timedout); - if (res) - goto out_free; - wait_for_completion(&completion); - ASD_DPRINTK("tmf came back\n"); - - tascb->tag = tcs.tag; - tascb->tag_valid = tcs.tag_valid; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - res = TMF_RESP_FUNC_COMPLETE; - ASD_DPRINTK("%s: task 0x%p done\n", __func__, task); - goto out_done; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - - if (tcs.dl_opcode == TC_SSP_RESP) { - /* The task to be aborted has been sent to the device. - * We got a Response IU for the ABORT TASK TMF. */ - if (tcs.tmf_state == TMF_RESP_FUNC_COMPLETE) - res = asd_clear_nexus(task); - else - res = tcs.tmf_state; - } else if (tcs.dl_opcode == TC_NO_ERROR && - tcs.tmf_state == TMF_RESP_FUNC_FAILED) { - /* timeout */ - res = TMF_RESP_FUNC_FAILED; - } else { - /* In the following we assume that the managing layer - * will _never_ make a mistake, when issuing ABORT - * TASK. - */ - switch (tcs.dl_opcode) { - default: - res = asd_clear_nexus(task); - /* fallthrough */ - case TC_NO_ERROR: - break; - /* The task hasn't been sent to the device xor - * we never got a (sane) Response IU for the - * ABORT TASK TMF. - */ - case TF_NAK_RECV: - res = TMF_RESP_INVALID_FRAME; - break; - case TF_TMF_TASK_DONE: /* done but not reported yet */ - res = TMF_RESP_FUNC_FAILED; - leftover = - wait_for_completion_timeout(&tascb_completion, - AIC94XX_SCB_TIMEOUT); - spin_lock_irqsave(&task->task_state_lock, flags); - if (leftover < 1) - res = TMF_RESP_FUNC_FAILED; - if (task->task_state_flags & SAS_TASK_STATE_DONE) - res = TMF_RESP_FUNC_COMPLETE; - spin_unlock_irqrestore(&task->task_state_lock, flags); - break; - case TF_TMF_NO_TAG: - case TF_TMF_TAG_FREE: /* the tag is in the free list */ - case TF_TMF_NO_CONN_HANDLE: /* no such device */ - res = TMF_RESP_FUNC_COMPLETE; - break; - case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */ - res = TMF_RESP_FUNC_ESUPP; - break; - } - } - out_done: - tascb->completion = NULL; - if (res == TMF_RESP_FUNC_COMPLETE) { - task->lldd_task = NULL; - mb(); - asd_ascb_free(tascb); - } - ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res); - return res; - - out_free: - asd_ascb_free(ascb); - ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res); - return res; -} - -/** - * asd_initiate_ssp_tmf -- send a TMF to an I_T_L or I_T_L_Q nexus - * @dev: pointer to struct domain_device of interest - * @lun: pointer to u8[8] which is the LUN - * @tmf: the TMF to be performed (see sas_task.h or the SAS spec) - * @index: the transaction context of the task to be queried if QT TMF - * - * This function is used to send ABORT TASK SET, CLEAR ACA, - * CLEAR TASK SET, LU RESET and QUERY TASK TMFs. - * - * No SCBs should be queued to the I_T_L nexus when this SCB is - * pending. - * - * Returns: TMF response code (see sas_task.h or the SAS spec) - */ -static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun, - int tmf, int index) -{ - struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; - struct asd_ascb *ascb; - int res = 1; - struct scb *scb; - DECLARE_COMPLETION_ONSTACK(completion); - DECLARE_TCS(tcs); - - if (!(dev->tproto & SAS_PROTOCOL_SSP)) - return TMF_RESP_FUNC_ESUPP; - - ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); - if (!ascb) - return -ENOMEM; - - ascb->completion = &completion; - ascb->uldd_task = &tcs; - scb = ascb->scb; - - if (tmf == TMF_QUERY_TASK) - scb->header.opcode = QUERY_SSP_TASK; - else - scb->header.opcode = INITIATE_SSP_TMF; - - scb->ssp_tmf.proto_conn_rate = (1 << 4); /* SSP */ - scb->ssp_tmf.proto_conn_rate |= dev->linkrate; - /* SSP frame header */ - scb->ssp_tmf.ssp_frame.frame_type = SSP_TASK; - memcpy(scb->ssp_tmf.ssp_frame.hashed_dest_addr, - dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); - memcpy(scb->ssp_tmf.ssp_frame.hashed_src_addr, - dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); - scb->ssp_tmf.ssp_frame.tptt = cpu_to_be16(0xFFFF); - /* SSP Task IU */ - memcpy(scb->ssp_tmf.ssp_task.lun, lun, 8); - scb->ssp_tmf.ssp_task.tmf = tmf; - - scb->ssp_tmf.sister_scb = cpu_to_le16(0xFFFF); - scb->ssp_tmf.conn_handle= cpu_to_le16((u16)(unsigned long) - dev->lldd_dev); - scb->ssp_tmf.retry_count = 1; - scb->ssp_tmf.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST); - if (tmf == TMF_QUERY_TASK) - scb->ssp_tmf.index = cpu_to_le16(index); - - res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete, - asd_tmf_timedout); - if (res) - goto out_err; - wait_for_completion(&completion); - - switch (tcs.dl_opcode) { - case TC_NO_ERROR: - res = TMF_RESP_FUNC_COMPLETE; - break; - case TF_NAK_RECV: - res = TMF_RESP_INVALID_FRAME; - break; - case TF_TMF_TASK_DONE: - res = TMF_RESP_FUNC_FAILED; - break; - case TF_TMF_NO_TAG: - case TF_TMF_TAG_FREE: /* the tag is in the free list */ - case TF_TMF_NO_CONN_HANDLE: /* no such device */ - res = TMF_RESP_FUNC_COMPLETE; - break; - case TF_TMF_NO_CTX: /* not in seq, or proto != SSP */ - res = TMF_RESP_FUNC_ESUPP; - break; - default: - /* Allow TMF response codes to propagate upwards */ - res = tcs.dl_opcode; - break; - } - return res; -out_err: - asd_ascb_free(ascb); - return res; -} - -int asd_abort_task_set(struct domain_device *dev, u8 *lun) -{ - int res = asd_initiate_ssp_tmf(dev, lun, TMF_ABORT_TASK_SET, 0); - - if (res == TMF_RESP_FUNC_COMPLETE) - asd_clear_nexus_I_T_L(dev, lun); - return res; -} - -int asd_clear_aca(struct domain_device *dev, u8 *lun) -{ - int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_ACA, 0); - - if (res == TMF_RESP_FUNC_COMPLETE) - asd_clear_nexus_I_T_L(dev, lun); - return res; -} - -int asd_clear_task_set(struct domain_device *dev, u8 *lun) -{ - int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_TASK_SET, 0); - - if (res == TMF_RESP_FUNC_COMPLETE) - asd_clear_nexus_I_T_L(dev, lun); - return res; -} - -int asd_lu_reset(struct domain_device *dev, u8 *lun) -{ - int res = asd_initiate_ssp_tmf(dev, lun, TMF_LU_RESET, 0); - - if (res == TMF_RESP_FUNC_COMPLETE) - asd_clear_nexus_I_T_L(dev, lun); - return res; -} - -/** - * asd_query_task -- send a QUERY TASK TMF to an I_T_L_Q nexus - * task: pointer to sas_task struct of interest - * - * Returns: TMF_RESP_FUNC_COMPLETE if the task is not in the task set, - * or TMF_RESP_FUNC_SUCC if the task is in the task set. - * - * Normally the management layer sets the task to aborted state, - * and then calls query task and then abort task. - */ -int asd_query_task(struct sas_task *task) -{ - struct asd_ascb *ascb = task->lldd_task; - int index; - - if (ascb) { - index = ascb->tc_index; - return asd_initiate_ssp_tmf(task->dev, task->ssp_task.LUN, - TMF_QUERY_TASK, index); - } - return TMF_RESP_FUNC_COMPLETE; -} diff --git a/ANDROID_3.4.5/drivers/scsi/arcmsr/Makefile b/ANDROID_3.4.5/drivers/scsi/arcmsr/Makefile deleted file mode 100644 index 721aced3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arcmsr/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# File: drivers/arcmsr/Makefile -# Makefile for the ARECA PCI-X PCI-EXPRESS SATA RAID controllers SCSI driver. - -arcmsr-objs := arcmsr_attr.o arcmsr_hba.o - -obj-$(CONFIG_SCSI_ARCMSR) := arcmsr.o diff --git a/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr.h b/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr.h deleted file mode 100644 index 77b26f5b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr.h +++ /dev/null @@ -1,692 +0,0 @@ -/* -******************************************************************************* -** O.S : Linux -** FILE NAME : arcmsr.h -** BY : Nick Cheng -** Description: SCSI RAID Device Driver for -** ARECA RAID Host adapter -******************************************************************************* -** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved. -** -** Web site: www.areca.com.tw -** E-mail: support@areca.com.tw -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License version 2 as -** published by the Free Software Foundation. -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -******************************************************************************* -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -**(INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -******************************************************************************* -*/ -#include -struct device_attribute; -/*The limit of outstanding scsi command that firmware can handle*/ -#define ARCMSR_MAX_OUTSTANDING_CMD 256 -#ifdef CONFIG_XEN - #define ARCMSR_MAX_FREECCB_NUM 160 -#else - #define ARCMSR_MAX_FREECCB_NUM 320 -#endif -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2010/08/05" -#define ARCMSR_SCSI_INITIATOR_ID 255 -#define ARCMSR_MAX_XFER_SECTORS 512 -#define ARCMSR_MAX_XFER_SECTORS_B 4096 -#define ARCMSR_MAX_XFER_SECTORS_C 304 -#define ARCMSR_MAX_TARGETID 17 -#define ARCMSR_MAX_TARGETLUN 8 -#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD -#define ARCMSR_MAX_QBUFFER 4096 -#define ARCMSR_DEFAULT_SG_ENTRIES 38 -#define ARCMSR_MAX_HBB_POSTQUEUE 264 -#define ARCMSR_MAX_XFER_LEN 0x26000 /* 152K */ -#define ARCMSR_CDB_SG_PAGE_LENGTH 256 -#ifndef PCI_DEVICE_ID_ARECA_1880 -#define PCI_DEVICE_ID_ARECA_1880 0x1880 - #endif -/* -********************************************************************************** -** -********************************************************************************** -*/ -#define ARC_SUCCESS 0 -#define ARC_FAILURE 1 -/* -******************************************************************************* -** split 64bits dma addressing -******************************************************************************* -*/ -#define dma_addr_hi32(addr) (uint32_t) ((addr>>16)>>16) -#define dma_addr_lo32(addr) (uint32_t) (addr & 0xffffffff) -/* -******************************************************************************* -** MESSAGE CONTROL CODE -******************************************************************************* -*/ -struct CMD_MESSAGE -{ - uint32_t HeaderLength; - uint8_t Signature[8]; - uint32_t Timeout; - uint32_t ControlCode; - uint32_t ReturnCode; - uint32_t Length; -}; -/* -******************************************************************************* -** IOP Message Transfer Data for user space -******************************************************************************* -*/ -struct CMD_MESSAGE_FIELD -{ - struct CMD_MESSAGE cmdmessage; - uint8_t messagedatabuffer[1032]; -}; -/* IOP message transfer */ -#define ARCMSR_MESSAGE_FAIL 0x0001 -/* DeviceType */ -#define ARECA_SATA_RAID 0x90000000 -/* FunctionCode */ -#define FUNCTION_READ_RQBUFFER 0x0801 -#define FUNCTION_WRITE_WQBUFFER 0x0802 -#define FUNCTION_CLEAR_RQBUFFER 0x0803 -#define FUNCTION_CLEAR_WQBUFFER 0x0804 -#define FUNCTION_CLEAR_ALLQBUFFER 0x0805 -#define FUNCTION_RETURN_CODE_3F 0x0806 -#define FUNCTION_SAY_HELLO 0x0807 -#define FUNCTION_SAY_GOODBYE 0x0808 -#define FUNCTION_FLUSH_ADAPTER_CACHE 0x0809 -#define FUNCTION_GET_FIRMWARE_STATUS 0x080A -#define FUNCTION_HARDWARE_RESET 0x080B -/* ARECA IO CONTROL CODE*/ -#define ARCMSR_MESSAGE_READ_RQBUFFER \ - ARECA_SATA_RAID | FUNCTION_READ_RQBUFFER -#define ARCMSR_MESSAGE_WRITE_WQBUFFER \ - ARECA_SATA_RAID | FUNCTION_WRITE_WQBUFFER -#define ARCMSR_MESSAGE_CLEAR_RQBUFFER \ - ARECA_SATA_RAID | FUNCTION_CLEAR_RQBUFFER -#define ARCMSR_MESSAGE_CLEAR_WQBUFFER \ - ARECA_SATA_RAID | FUNCTION_CLEAR_WQBUFFER -#define ARCMSR_MESSAGE_CLEAR_ALLQBUFFER \ - ARECA_SATA_RAID | FUNCTION_CLEAR_ALLQBUFFER -#define ARCMSR_MESSAGE_RETURN_CODE_3F \ - ARECA_SATA_RAID | FUNCTION_RETURN_CODE_3F -#define ARCMSR_MESSAGE_SAY_HELLO \ - ARECA_SATA_RAID | FUNCTION_SAY_HELLO -#define ARCMSR_MESSAGE_SAY_GOODBYE \ - ARECA_SATA_RAID | FUNCTION_SAY_GOODBYE -#define ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE \ - ARECA_SATA_RAID | FUNCTION_FLUSH_ADAPTER_CACHE -/* ARECA IOCTL ReturnCode */ -#define ARCMSR_MESSAGE_RETURNCODE_OK 0x00000001 -#define ARCMSR_MESSAGE_RETURNCODE_ERROR 0x00000006 -#define ARCMSR_MESSAGE_RETURNCODE_3F 0x0000003F -#define ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON 0x00000088 -/* -************************************************************* -** structure for holding DMA address data -************************************************************* -*/ -#define IS_DMA64 (sizeof(dma_addr_t) == 8) -#define IS_SG64_ADDR 0x01000000 /* bit24 */ -struct SG32ENTRY -{ - __le32 length; - __le32 address; -}__attribute__ ((packed)); -struct SG64ENTRY -{ - __le32 length; - __le32 address; - __le32 addresshigh; -}__attribute__ ((packed)); -/* -******************************************************************** -** Q Buffer of IOP Message Transfer -******************************************************************** -*/ -struct QBUFFER -{ - uint32_t data_len; - uint8_t data[124]; -}; -/* -******************************************************************************* -** FIRMWARE INFO for Intel IOP R 80331 processor (Type A) -******************************************************************************* -*/ -struct FIRMWARE_INFO -{ - uint32_t signature; /*0, 00-03*/ - uint32_t request_len; /*1, 04-07*/ - uint32_t numbers_queue; /*2, 08-11*/ - uint32_t sdram_size; /*3, 12-15*/ - uint32_t ide_channels; /*4, 16-19*/ - char vendor[40]; /*5, 20-59*/ - char model[8]; /*15, 60-67*/ - char firmware_ver[16]; /*17, 68-83*/ - char device_map[16]; /*21, 84-99*/ - uint32_t cfgVersion; /*25,100-103 Added for checking of new firmware capability*/ - uint8_t cfgSerial[16]; /*26,104-119*/ - uint32_t cfgPicStatus; /*30,120-123*/ -}; -/* signature of set and get firmware config */ -#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 -#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063 -/* message code of inbound message register */ -#define ARCMSR_INBOUND_MESG0_NOP 0x00000000 -#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001 -#define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002 -#define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003 -#define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004 -#define ARCMSR_INBOUND_MESG0_FLUSH_CACHE 0x00000005 -#define ARCMSR_INBOUND_MESG0_START_BGRB 0x00000006 -#define ARCMSR_INBOUND_MESG0_CHK331PENDING 0x00000007 -#define ARCMSR_INBOUND_MESG0_SYNC_TIMER 0x00000008 -/* doorbell interrupt generator */ -#define ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK 0x00000001 -#define ARCMSR_INBOUND_DRIVER_DATA_READ_OK 0x00000002 -#define ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK 0x00000001 -#define ARCMSR_OUTBOUND_IOP331_DATA_READ_OK 0x00000002 -/* ccb areca cdb flag */ -#define ARCMSR_CCBPOST_FLAG_SGL_BSIZE 0x80000000 -#define ARCMSR_CCBPOST_FLAG_IAM_BIOS 0x40000000 -#define ARCMSR_CCBREPLY_FLAG_IAM_BIOS 0x40000000 -#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE0 0x10000000 -#define ARCMSR_CCBREPLY_FLAG_ERROR_MODE1 0x00000001 -/* outbound firmware ok */ -#define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 -/* ARC-1680 Bus Reset*/ -#define ARCMSR_ARC1680_BUS_RESET 0x00000003 -/* ARC-1880 Bus Reset*/ -#define ARCMSR_ARC1880_RESET_ADAPTER 0x00000024 -#define ARCMSR_ARC1880_DiagWrite_ENABLE 0x00000080 - -/* -************************************************************************ -** SPEC. for Areca Type B adapter -************************************************************************ -*/ -/* ARECA HBB COMMAND for its FIRMWARE */ -/* window of "instruction flags" from driver to iop */ -#define ARCMSR_DRV2IOP_DOORBELL 0x00020400 -#define ARCMSR_DRV2IOP_DOORBELL_MASK 0x00020404 -/* window of "instruction flags" from iop to driver */ -#define ARCMSR_IOP2DRV_DOORBELL 0x00020408 -#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C -/* ARECA FLAG LANGUAGE */ -/* ioctl transfer */ -#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001 -/* ioctl transfer */ -#define ARCMSR_IOP2DRV_DATA_READ_OK 0x00000002 -#define ARCMSR_IOP2DRV_CDB_DONE 0x00000004 -#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE 0x00000008 - -#define ARCMSR_DOORBELL_HANDLE_INT 0x0000000F -#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN 0xFF00FFF0 -#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN 0xFF00FFF7 -/* (ARCMSR_INBOUND_MESG0_GET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ -#define ARCMSR_MESSAGE_GET_CONFIG 0x00010008 -/* (ARCMSR_INBOUND_MESG0_SET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ -#define ARCMSR_MESSAGE_SET_CONFIG 0x00020008 -/* (ARCMSR_INBOUND_MESG0_ABORT_CMD<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ -#define ARCMSR_MESSAGE_ABORT_CMD 0x00030008 -/* (ARCMSR_INBOUND_MESG0_STOP_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ -#define ARCMSR_MESSAGE_STOP_BGRB 0x00040008 -/* (ARCMSR_INBOUND_MESG0_FLUSH_CACHE<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ -#define ARCMSR_MESSAGE_FLUSH_CACHE 0x00050008 -/* (ARCMSR_INBOUND_MESG0_START_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ -#define ARCMSR_MESSAGE_START_BGRB 0x00060008 -#define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008 -#define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008 -#define ARCMSR_MESSAGE_ACTIVE_EOI_MODE 0x00100008 -/* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */ -#define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000 -/* ioctl transfer */ -#define ARCMSR_DRV2IOP_DATA_WRITE_OK 0x00000001 -/* ioctl transfer */ -#define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002 -#define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004 -#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008 -#define ARCMSR_DRV2IOP_END_OF_INTERRUPT 0x00000010 - -/* data tunnel buffer between user space program and its firmware */ -/* user space data to iop 128bytes */ -#define ARCMSR_MESSAGE_WBUFFER 0x0000fe00 -/* iop data to user space 128bytes */ -#define ARCMSR_MESSAGE_RBUFFER 0x0000ff00 -/* iop message_rwbuffer for message command */ -#define ARCMSR_MESSAGE_RWBUFFER 0x0000fa00 -/* -************************************************************************ -** SPEC. for Areca HBC adapter -************************************************************************ -*/ -#define ARCMSR_HBC_ISR_THROTTLING_LEVEL 12 -#define ARCMSR_HBC_ISR_MAX_DONE_QUEUE 20 -/* Host Interrupt Mask */ -#define ARCMSR_HBCMU_UTILITY_A_ISR_MASK 0x00000001 /* When clear, the Utility_A interrupt routes to the host.*/ -#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK 0x00000004 /* When clear, the General Outbound Doorbell interrupt routes to the host.*/ -#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK 0x00000008 /* When clear, the Outbound Post List FIFO Not Empty interrupt routes to the host.*/ -#define ARCMSR_HBCMU_ALL_INTMASKENABLE 0x0000000D /* disable all ISR */ -/* Host Interrupt Status */ -#define ARCMSR_HBCMU_UTILITY_A_ISR 0x00000001 - /* - ** Set when the Utility_A Interrupt bit is set in the Outbound Doorbell Register. - ** It clears by writing a 1 to the Utility_A bit in the Outbound Doorbell Clear Register or through automatic clearing (if enabled). - */ -#define ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR 0x00000004 - /* - ** Set if Outbound Doorbell register bits 30:1 have a non-zero - ** value. This bit clears only when Outbound Doorbell bits - ** 30:1 are ALL clear. Only a write to the Outbound Doorbell - ** Clear register clears bits in the Outbound Doorbell register. - */ -#define ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR 0x00000008 - /* - ** Set whenever the Outbound Post List Producer/Consumer - ** Register (FIFO) is not empty. It clears when the Outbound - ** Post List FIFO is empty. - */ -#define ARCMSR_HBCMU_SAS_ALL_INT 0x00000010 - /* - ** This bit indicates a SAS interrupt from a source external to - ** the PCIe core. This bit is not maskable. - */ - /* DoorBell*/ -#define ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK 0x00000002 -#define ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK 0x00000004 - /*inbound message 0 ready*/ -#define ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE 0x00000008 - /*more than 12 request completed in a time*/ -#define ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING 0x00000010 -#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK 0x00000002 - /*outbound DATA WRITE isr door bell clear*/ -#define ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_DOORBELL_CLEAR 0x00000002 -#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK 0x00000004 - /*outbound DATA READ isr door bell clear*/ -#define ARCMSR_HBCMU_IOP2DRV_DATA_READ_DOORBELL_CLEAR 0x00000004 - /*outbound message 0 ready*/ -#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE 0x00000008 - /*outbound message cmd isr door bell clear*/ -#define ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR 0x00000008 - /*ARCMSR_HBAMU_MESSAGE_FIRMWARE_OK*/ -#define ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK 0x80000000 -/* -******************************************************************************* -** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504) -******************************************************************************* -*/ -struct ARCMSR_CDB -{ - uint8_t Bus; - uint8_t TargetID; - uint8_t LUN; - uint8_t Function; - uint8_t CdbLength; - uint8_t sgcount; - uint8_t Flags; -#define ARCMSR_CDB_FLAG_SGL_BSIZE 0x01 -#define ARCMSR_CDB_FLAG_BIOS 0x02 -#define ARCMSR_CDB_FLAG_WRITE 0x04 -#define ARCMSR_CDB_FLAG_SIMPLEQ 0x00 -#define ARCMSR_CDB_FLAG_HEADQ 0x08 -#define ARCMSR_CDB_FLAG_ORDEREDQ 0x10 - - uint8_t msgPages; - uint32_t Context; - uint32_t DataLength; - uint8_t Cdb[16]; - uint8_t DeviceStatus; -#define ARCMSR_DEV_CHECK_CONDITION 0x02 -#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0 -#define ARCMSR_DEV_ABORTED 0xF1 -#define ARCMSR_DEV_INIT_FAIL 0xF2 - - uint8_t SenseData[15]; - union - { - struct SG32ENTRY sg32entry[1]; - struct SG64ENTRY sg64entry[1]; - } u; -}; -/* -******************************************************************************* -** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor -******************************************************************************* -*/ -struct MessageUnit_A -{ - uint32_t resrved0[4]; /*0000 000F*/ - uint32_t inbound_msgaddr0; /*0010 0013*/ - uint32_t inbound_msgaddr1; /*0014 0017*/ - uint32_t outbound_msgaddr0; /*0018 001B*/ - uint32_t outbound_msgaddr1; /*001C 001F*/ - uint32_t inbound_doorbell; /*0020 0023*/ - uint32_t inbound_intstatus; /*0024 0027*/ - uint32_t inbound_intmask; /*0028 002B*/ - uint32_t outbound_doorbell; /*002C 002F*/ - uint32_t outbound_intstatus; /*0030 0033*/ - uint32_t outbound_intmask; /*0034 0037*/ - uint32_t reserved1[2]; /*0038 003F*/ - uint32_t inbound_queueport; /*0040 0043*/ - uint32_t outbound_queueport; /*0044 0047*/ - uint32_t reserved2[2]; /*0048 004F*/ - uint32_t reserved3[492]; /*0050 07FF 492*/ - uint32_t reserved4[128]; /*0800 09FF 128*/ - uint32_t message_rwbuffer[256]; /*0a00 0DFF 256*/ - uint32_t message_wbuffer[32]; /*0E00 0E7F 32*/ - uint32_t reserved5[32]; /*0E80 0EFF 32*/ - uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/ - uint32_t reserved6[32]; /*0F80 0FFF 32*/ -}; - -struct MessageUnit_B -{ - uint32_t post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; - uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; - uint32_t postq_index; - uint32_t doneq_index; - uint32_t __iomem *drv2iop_doorbell; - uint32_t __iomem *drv2iop_doorbell_mask; - uint32_t __iomem *iop2drv_doorbell; - uint32_t __iomem *iop2drv_doorbell_mask; - uint32_t __iomem *message_rwbuffer; - uint32_t __iomem *message_wbuffer; - uint32_t __iomem *message_rbuffer; -}; -/* -********************************************************************* -** LSI -********************************************************************* -*/ -struct MessageUnit_C{ - uint32_t message_unit_status; /*0000 0003*/ - uint32_t slave_error_attribute; /*0004 0007*/ - uint32_t slave_error_address; /*0008 000B*/ - uint32_t posted_outbound_doorbell; /*000C 000F*/ - uint32_t master_error_attribute; /*0010 0013*/ - uint32_t master_error_address_low; /*0014 0017*/ - uint32_t master_error_address_high; /*0018 001B*/ - uint32_t hcb_size; /*001C 001F*/ - uint32_t inbound_doorbell; /*0020 0023*/ - uint32_t diagnostic_rw_data; /*0024 0027*/ - uint32_t diagnostic_rw_address_low; /*0028 002B*/ - uint32_t diagnostic_rw_address_high; /*002C 002F*/ - uint32_t host_int_status; /*0030 0033*/ - uint32_t host_int_mask; /*0034 0037*/ - uint32_t dcr_data; /*0038 003B*/ - uint32_t dcr_address; /*003C 003F*/ - uint32_t inbound_queueport; /*0040 0043*/ - uint32_t outbound_queueport; /*0044 0047*/ - uint32_t hcb_pci_address_low; /*0048 004B*/ - uint32_t hcb_pci_address_high; /*004C 004F*/ - uint32_t iop_int_status; /*0050 0053*/ - uint32_t iop_int_mask; /*0054 0057*/ - uint32_t iop_inbound_queue_port; /*0058 005B*/ - uint32_t iop_outbound_queue_port; /*005C 005F*/ - uint32_t inbound_free_list_index; /*0060 0063*/ - uint32_t inbound_post_list_index; /*0064 0067*/ - uint32_t outbound_free_list_index; /*0068 006B*/ - uint32_t outbound_post_list_index; /*006C 006F*/ - uint32_t inbound_doorbell_clear; /*0070 0073*/ - uint32_t i2o_message_unit_control; /*0074 0077*/ - uint32_t last_used_message_source_address_low; /*0078 007B*/ - uint32_t last_used_message_source_address_high; /*007C 007F*/ - uint32_t pull_mode_data_byte_count[4]; /*0080 008F*/ - uint32_t message_dest_address_index; /*0090 0093*/ - uint32_t done_queue_not_empty_int_counter_timer; /*0094 0097*/ - uint32_t utility_A_int_counter_timer; /*0098 009B*/ - uint32_t outbound_doorbell; /*009C 009F*/ - uint32_t outbound_doorbell_clear; /*00A0 00A3*/ - uint32_t message_source_address_index; /*00A4 00A7*/ - uint32_t message_done_queue_index; /*00A8 00AB*/ - uint32_t reserved0; /*00AC 00AF*/ - uint32_t inbound_msgaddr0; /*00B0 00B3*/ - uint32_t inbound_msgaddr1; /*00B4 00B7*/ - uint32_t outbound_msgaddr0; /*00B8 00BB*/ - uint32_t outbound_msgaddr1; /*00BC 00BF*/ - uint32_t inbound_queueport_low; /*00C0 00C3*/ - uint32_t inbound_queueport_high; /*00C4 00C7*/ - uint32_t outbound_queueport_low; /*00C8 00CB*/ - uint32_t outbound_queueport_high; /*00CC 00CF*/ - uint32_t iop_inbound_queue_port_low; /*00D0 00D3*/ - uint32_t iop_inbound_queue_port_high; /*00D4 00D7*/ - uint32_t iop_outbound_queue_port_low; /*00D8 00DB*/ - uint32_t iop_outbound_queue_port_high; /*00DC 00DF*/ - uint32_t message_dest_queue_port_low; /*00E0 00E3*/ - uint32_t message_dest_queue_port_high; /*00E4 00E7*/ - uint32_t last_used_message_dest_address_low; /*00E8 00EB*/ - uint32_t last_used_message_dest_address_high; /*00EC 00EF*/ - uint32_t message_done_queue_base_address_low; /*00F0 00F3*/ - uint32_t message_done_queue_base_address_high; /*00F4 00F7*/ - uint32_t host_diagnostic; /*00F8 00FB*/ - uint32_t write_sequence; /*00FC 00FF*/ - uint32_t reserved1[34]; /*0100 0187*/ - uint32_t reserved2[1950]; /*0188 1FFF*/ - uint32_t message_wbuffer[32]; /*2000 207F*/ - uint32_t reserved3[32]; /*2080 20FF*/ - uint32_t message_rbuffer[32]; /*2100 217F*/ - uint32_t reserved4[32]; /*2180 21FF*/ - uint32_t msgcode_rwbuffer[256]; /*2200 23FF*/ -}; -/* -******************************************************************************* -** Adapter Control Block -******************************************************************************* -*/ -struct AdapterControlBlock -{ - uint32_t adapter_type; /* adapter A,B..... */ - #define ACB_ADAPTER_TYPE_A 0x00000001 /* hba I IOP */ - #define ACB_ADAPTER_TYPE_B 0x00000002 /* hbb M IOP */ - #define ACB_ADAPTER_TYPE_C 0x00000004 /* hbc P IOP */ - #define ACB_ADAPTER_TYPE_D 0x00000008 /* hbd A IOP */ - struct pci_dev * pdev; - struct Scsi_Host * host; - unsigned long vir2phy_offset; - /* Offset is used in making arc cdb physical to virtual calculations */ - uint32_t outbound_int_enable; - uint32_t cdb_phyaddr_hi32; - uint32_t reg_mu_acc_handle0; - spinlock_t eh_lock; - spinlock_t ccblist_lock; - union { - struct MessageUnit_A __iomem *pmuA; - struct MessageUnit_B *pmuB; - struct MessageUnit_C __iomem *pmuC; - }; - /* message unit ATU inbound base address0 */ - void __iomem *mem_base0; - void __iomem *mem_base1; - uint32_t acb_flags; - u16 dev_id; - uint8_t adapter_index; - #define ACB_F_SCSISTOPADAPTER 0x0001 - #define ACB_F_MSG_STOP_BGRB 0x0002 - /* stop RAID background rebuild */ - #define ACB_F_MSG_START_BGRB 0x0004 - /* stop RAID background rebuild */ - #define ACB_F_IOPDATA_OVERFLOW 0x0008 - /* iop message data rqbuffer overflow */ - #define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010 - /* message clear wqbuffer */ - #define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020 - /* message clear rqbuffer */ - #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 - #define ACB_F_BUS_RESET 0x0080 - #define ACB_F_BUS_HANG_ON 0x0800/* need hardware reset bus */ - - #define ACB_F_IOP_INITED 0x0100 - /* iop init */ - #define ACB_F_ABORT 0x0200 - #define ACB_F_FIRMWARE_TRAP 0x0400 - struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; - /* used for memory free */ - struct list_head ccb_free_list; - /* head of free ccb list */ - - atomic_t ccboutstandingcount; - /*The present outstanding command number that in the IOP that - waiting for being handled by FW*/ - - void * dma_coherent; - /* dma_coherent used for memory free */ - dma_addr_t dma_coherent_handle; - /* dma_coherent_handle used for memory free */ - dma_addr_t dma_coherent_handle_hbb_mu; - unsigned int uncache_size; - uint8_t rqbuffer[ARCMSR_MAX_QBUFFER]; - /* data collection buffer for read from 80331 */ - int32_t rqbuf_firstindex; - /* first of read buffer */ - int32_t rqbuf_lastindex; - /* last of read buffer */ - uint8_t wqbuffer[ARCMSR_MAX_QBUFFER]; - /* data collection buffer for write to 80331 */ - int32_t wqbuf_firstindex; - /* first of write buffer */ - int32_t wqbuf_lastindex; - /* last of write buffer */ - uint8_t devstate[ARCMSR_MAX_TARGETID][ARCMSR_MAX_TARGETLUN]; - /* id0 ..... id15, lun0...lun7 */ -#define ARECA_RAID_GONE 0x55 -#define ARECA_RAID_GOOD 0xaa - uint32_t num_resets; - uint32_t num_aborts; - uint32_t signature; - uint32_t firm_request_len; - uint32_t firm_numbers_queue; - uint32_t firm_sdram_size; - uint32_t firm_hd_channels; - uint32_t firm_cfg_version; - char firm_model[12]; - char firm_version[20]; - char device_map[20]; /*21,84-99*/ - struct work_struct arcmsr_do_message_isr_bh; - struct timer_list eternal_timer; - unsigned short fw_flag; - #define FW_NORMAL 0x0000 - #define FW_BOG 0x0001 - #define FW_DEADLOCK 0x0010 - atomic_t rq_map_token; - atomic_t ante_token_value; -};/* HW_DEVICE_EXTENSION */ -/* -******************************************************************************* -** Command Control Block -** this CCB length must be 32 bytes boundary -******************************************************************************* -*/ -struct CommandControlBlock{ - /*x32:sizeof struct_CCB=(32+60)byte, x64:sizeof struct_CCB=(64+60)byte*/ - struct list_head list; /*x32: 8byte, x64: 16byte*/ - struct scsi_cmnd *pcmd; /*8 bytes pointer of linux scsi command */ - struct AdapterControlBlock *acb; /*x32: 4byte, x64: 8byte*/ - uint32_t cdb_phyaddr_pattern; /*x32: 4byte, x64: 4byte*/ - uint32_t arc_cdb_size; /*x32:4byte,x64:4byte*/ - uint16_t ccb_flags; /*x32: 2byte, x64: 2byte*/ - #define CCB_FLAG_READ 0x0000 - #define CCB_FLAG_WRITE 0x0001 - #define CCB_FLAG_ERROR 0x0002 - #define CCB_FLAG_FLUSHCACHE 0x0004 - #define CCB_FLAG_MASTER_ABORTED 0x0008 - uint16_t startdone; /*x32:2byte,x32:2byte*/ - #define ARCMSR_CCB_DONE 0x0000 - #define ARCMSR_CCB_START 0x55AA - #define ARCMSR_CCB_ABORTED 0xAA55 - #define ARCMSR_CCB_ILLEGAL 0xFFFF - #if BITS_PER_LONG == 64 - /* ======================512+64 bytes======================== */ - uint32_t reserved[5]; /*24 byte*/ - #else - /* ======================512+32 bytes======================== */ - uint32_t reserved; /*8 byte*/ - #endif - /* ======================================================= */ - struct ARCMSR_CDB arcmsr_cdb; -}; -/* -******************************************************************************* -** ARECA SCSI sense data -******************************************************************************* -*/ -struct SENSE_DATA -{ - uint8_t ErrorCode:7; -#define SCSI_SENSE_CURRENT_ERRORS 0x70 -#define SCSI_SENSE_DEFERRED_ERRORS 0x71 - uint8_t Valid:1; - uint8_t SegmentNumber; - uint8_t SenseKey:4; - uint8_t Reserved:1; - uint8_t IncorrectLength:1; - uint8_t EndOfMedia:1; - uint8_t FileMark:1; - uint8_t Information[4]; - uint8_t AdditionalSenseLength; - uint8_t CommandSpecificInformation[4]; - uint8_t AdditionalSenseCode; - uint8_t AdditionalSenseCodeQualifier; - uint8_t FieldReplaceableUnitCode; - uint8_t SenseKeySpecific[3]; -}; -/* -******************************************************************************* -** Outbound Interrupt Status Register - OISR -******************************************************************************* -*/ -#define ARCMSR_MU_OUTBOUND_INTERRUPT_STATUS_REG 0x30 -#define ARCMSR_MU_OUTBOUND_PCI_INT 0x10 -#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INT 0x08 -#define ARCMSR_MU_OUTBOUND_DOORBELL_INT 0x04 -#define ARCMSR_MU_OUTBOUND_MESSAGE1_INT 0x02 -#define ARCMSR_MU_OUTBOUND_MESSAGE0_INT 0x01 -#define ARCMSR_MU_OUTBOUND_HANDLE_INT \ - (ARCMSR_MU_OUTBOUND_MESSAGE0_INT \ - |ARCMSR_MU_OUTBOUND_MESSAGE1_INT \ - |ARCMSR_MU_OUTBOUND_DOORBELL_INT \ - |ARCMSR_MU_OUTBOUND_POSTQUEUE_INT \ - |ARCMSR_MU_OUTBOUND_PCI_INT) -/* -******************************************************************************* -** Outbound Interrupt Mask Register - OIMR -******************************************************************************* -*/ -#define ARCMSR_MU_OUTBOUND_INTERRUPT_MASK_REG 0x34 -#define ARCMSR_MU_OUTBOUND_PCI_INTMASKENABLE 0x10 -#define ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE 0x08 -#define ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE 0x04 -#define ARCMSR_MU_OUTBOUND_MESSAGE1_INTMASKENABLE 0x02 -#define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01 -#define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F - -extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *); -extern void arcmsr_iop_message_read(struct AdapterControlBlock *); -extern struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *); -extern struct device_attribute *arcmsr_host_attrs[]; -extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *); -void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb); diff --git a/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_attr.c b/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_attr.c deleted file mode 100644 index acdae33d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_attr.c +++ /dev/null @@ -1,402 +0,0 @@ -/* -******************************************************************************* -** O.S : Linux -** FILE NAME : arcmsr_attr.c -** BY : Nick Cheng -** Description: attributes exported to sysfs and device host -******************************************************************************* -** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved -** -** Web site: www.areca.com.tw -** E-mail: support@areca.com.tw -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License version 2 as -** published by the Free Software Foundation. -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -******************************************************************************* -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -******************************************************************************* -** For history of changes, see Documentation/scsi/ChangeLog.arcmsr -** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt -******************************************************************************* -*/ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "arcmsr.h" - -struct device_attribute *arcmsr_host_attrs[]; - -static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp, - struct kobject *kobj, - struct bin_attribute *bin, - char *buf, loff_t off, - size_t count) -{ - struct device *dev = container_of(kobj,struct device,kobj); - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - uint8_t *pQbuffer,*ptmpQbuffer; - int32_t allxfer_len = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - /* do message unit read. */ - ptmpQbuffer = (uint8_t *)buf; - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) - && (allxfer_len < 1031)) { - pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; - memcpy(ptmpQbuffer, pQbuffer, 1); - acb->rqbuf_firstindex++; - acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - ptmpQbuffer++; - allxfer_len++; - } - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - struct QBUFFER __iomem *prbuffer; - uint8_t __iomem *iop_data; - int32_t iop_len; - - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - prbuffer = arcmsr_get_iop_rqbuffer(acb); - iop_data = prbuffer->data; - iop_len = readl(&prbuffer->data_len); - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - arcmsr_iop_message_read(acb); - } - return (allxfer_len); -} - -static ssize_t arcmsr_sysfs_iop_message_write(struct file *filp, - struct kobject *kobj, - struct bin_attribute *bin, - char *buf, loff_t off, - size_t count) -{ - struct device *dev = container_of(kobj,struct device,kobj); - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; - uint8_t *pQbuffer, *ptmpuserbuffer; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (count > 1032) - return -EINVAL; - /* do message unit write. */ - ptmpuserbuffer = (uint8_t *)buf; - user_len = (int32_t)count; - wqbuf_lastindex = acb->wqbuf_lastindex; - wqbuf_firstindex = acb->wqbuf_firstindex; - if (wqbuf_lastindex != wqbuf_firstindex) { - arcmsr_post_ioctldata2iop(acb); - return 0; /*need retry*/ - } else { - my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= user_len) { - while (user_len > 0) { - pQbuffer = - &acb->wqbuffer[acb->wqbuf_lastindex]; - memcpy(pQbuffer, ptmpuserbuffer, 1); - acb->wqbuf_lastindex++; - acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - ptmpuserbuffer++; - user_len--; - } - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { - acb->acb_flags &= - ~ACB_F_MESSAGE_WQBUFFER_CLEARED; - arcmsr_post_ioctldata2iop(acb); - } - return count; - } else { - return 0; /*need retry*/ - } - } -} - -static ssize_t arcmsr_sysfs_iop_message_clear(struct file *filp, - struct kobject *kobj, - struct bin_attribute *bin, - char *buf, loff_t off, - size_t count) -{ - struct device *dev = container_of(kobj,struct device,kobj); - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - uint8_t *pQbuffer; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - arcmsr_iop_message_read(acb); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED - | ACB_F_MESSAGE_RQBUFFER_CLEARED - | ACB_F_MESSAGE_WQBUFFER_READED); - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; - pQbuffer = acb->rqbuffer; - memset(pQbuffer, 0, sizeof (struct QBUFFER)); - pQbuffer = acb->wqbuffer; - memset(pQbuffer, 0, sizeof (struct QBUFFER)); - return 1; -} - -static struct bin_attribute arcmsr_sysfs_message_read_attr = { - .attr = { - .name = "mu_read", - .mode = S_IRUSR , - }, - .size = 1032, - .read = arcmsr_sysfs_iop_message_read, -}; - -static struct bin_attribute arcmsr_sysfs_message_write_attr = { - .attr = { - .name = "mu_write", - .mode = S_IWUSR, - }, - .size = 1032, - .write = arcmsr_sysfs_iop_message_write, -}; - -static struct bin_attribute arcmsr_sysfs_message_clear_attr = { - .attr = { - .name = "mu_clear", - .mode = S_IWUSR, - }, - .size = 1, - .write = arcmsr_sysfs_iop_message_clear, -}; - -int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb) -{ - struct Scsi_Host *host = acb->host; - int error; - - error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr); - if (error) { - printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n"); - goto error_bin_file_message_read; - } - error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr); - if (error) { - printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n"); - goto error_bin_file_message_write; - } - error = sysfs_create_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_clear_attr); - if (error) { - printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n"); - goto error_bin_file_message_clear; - } - return 0; -error_bin_file_message_clear: - sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr); -error_bin_file_message_write: - sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr); -error_bin_file_message_read: - return error; -} - -void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) -{ - struct Scsi_Host *host = acb->host; - - sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_clear_attr); - sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_write_attr); - sysfs_remove_bin_file(&host->shost_dev.kobj, &arcmsr_sysfs_message_read_attr); -} - - -static ssize_t -arcmsr_attr_host_driver_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, - "%s\n", - ARCMSR_DRIVER_VERSION); -} - -static ssize_t -arcmsr_attr_host_driver_posted_cmd(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - return snprintf(buf, PAGE_SIZE, - "%4d\n", - atomic_read(&acb->ccboutstandingcount)); -} - -static ssize_t -arcmsr_attr_host_driver_reset(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - return snprintf(buf, PAGE_SIZE, - "%4d\n", - acb->num_resets); -} - -static ssize_t -arcmsr_attr_host_driver_abort(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - return snprintf(buf, PAGE_SIZE, - "%4d\n", - acb->num_aborts); -} - -static ssize_t -arcmsr_attr_host_fw_model(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - return snprintf(buf, PAGE_SIZE, - "%s\n", - acb->firm_model); -} - -static ssize_t -arcmsr_attr_host_fw_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - - return snprintf(buf, PAGE_SIZE, - "%s\n", - acb->firm_version); -} - -static ssize_t -arcmsr_attr_host_fw_request_len(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - - return snprintf(buf, PAGE_SIZE, - "%4d\n", - acb->firm_request_len); -} - -static ssize_t -arcmsr_attr_host_fw_numbers_queue(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - - return snprintf(buf, PAGE_SIZE, - "%4d\n", - acb->firm_numbers_queue); -} - -static ssize_t -arcmsr_attr_host_fw_sdram_size(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - - return snprintf(buf, PAGE_SIZE, - "%4d\n", - acb->firm_sdram_size); -} - -static ssize_t -arcmsr_attr_host_fw_hd_channels(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - - return snprintf(buf, PAGE_SIZE, - "%4d\n", - acb->firm_hd_channels); -} - -static DEVICE_ATTR(host_driver_version, S_IRUGO, arcmsr_attr_host_driver_version, NULL); -static DEVICE_ATTR(host_driver_posted_cmd, S_IRUGO, arcmsr_attr_host_driver_posted_cmd, NULL); -static DEVICE_ATTR(host_driver_reset, S_IRUGO, arcmsr_attr_host_driver_reset, NULL); -static DEVICE_ATTR(host_driver_abort, S_IRUGO, arcmsr_attr_host_driver_abort, NULL); -static DEVICE_ATTR(host_fw_model, S_IRUGO, arcmsr_attr_host_fw_model, NULL); -static DEVICE_ATTR(host_fw_version, S_IRUGO, arcmsr_attr_host_fw_version, NULL); -static DEVICE_ATTR(host_fw_request_len, S_IRUGO, arcmsr_attr_host_fw_request_len, NULL); -static DEVICE_ATTR(host_fw_numbers_queue, S_IRUGO, arcmsr_attr_host_fw_numbers_queue, NULL); -static DEVICE_ATTR(host_fw_sdram_size, S_IRUGO, arcmsr_attr_host_fw_sdram_size, NULL); -static DEVICE_ATTR(host_fw_hd_channels, S_IRUGO, arcmsr_attr_host_fw_hd_channels, NULL); - -struct device_attribute *arcmsr_host_attrs[] = { - &dev_attr_host_driver_version, - &dev_attr_host_driver_posted_cmd, - &dev_attr_host_driver_reset, - &dev_attr_host_driver_abort, - &dev_attr_host_fw_model, - &dev_attr_host_fw_version, - &dev_attr_host_fw_request_len, - &dev_attr_host_fw_numbers_queue, - &dev_attr_host_fw_sdram_size, - &dev_attr_host_fw_hd_channels, - NULL, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_hba.c b/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_hba.c deleted file mode 100644 index cbde1dca..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arcmsr/arcmsr_hba.c +++ /dev/null @@ -1,3127 +0,0 @@ -/* -******************************************************************************* -** O.S : Linux -** FILE NAME : arcmsr_hba.c -** BY : Nick Cheng -** Description: SCSI RAID Device Driver for -** ARECA RAID Host adapter -******************************************************************************* -** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved -** -** Web site: www.areca.com.tw -** E-mail: support@areca.com.tw -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License version 2 as -** published by the Free Software Foundation. -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -******************************************************************************* -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions -** are met: -** 1. Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** 2. Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** 3. The name of the author may not be used to endorse or promote products -** derived from this software without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING,BUT -** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION)HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE)ARISING IN ANY WAY OUT OF THE USE OF -** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -******************************************************************************* -** For history of changes, see Documentation/scsi/ChangeLog.arcmsr -** Firmware Specification, see Documentation/scsi/arcmsr_spec.txt -******************************************************************************* -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "arcmsr.h" -MODULE_AUTHOR("Nick Cheng "); -MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/16xx/1880) SATA/SAS RAID Host Bus Adapter"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(ARCMSR_DRIVER_VERSION); - -#define ARCMSR_SLEEPTIME 10 -#define ARCMSR_RETRYCOUNT 12 - -wait_queue_head_t wait_q; -static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, - struct scsi_cmnd *cmd); -static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); -static int arcmsr_abort(struct scsi_cmnd *); -static int arcmsr_bus_reset(struct scsi_cmnd *); -static int arcmsr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *info); -static int arcmsr_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); -static int arcmsr_probe(struct pci_dev *pdev, - const struct pci_device_id *id); -static void arcmsr_remove(struct pci_dev *pdev); -static void arcmsr_shutdown(struct pci_dev *pdev); -static void arcmsr_iop_init(struct AdapterControlBlock *acb); -static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb); -static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb); -static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); -static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb); -static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb); -static void arcmsr_request_device_map(unsigned long pacb); -static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb); -static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb); -static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb); -static void arcmsr_message_isr_bh_fn(struct work_struct *work); -static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb); -static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb); -static void arcmsr_hbc_message_isr(struct AdapterControlBlock *pACB); -static void arcmsr_hardware_reset(struct AdapterControlBlock *acb); -static const char *arcmsr_info(struct Scsi_Host *); -static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); -static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, - int queue_depth, int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (queue_depth > ARCMSR_MAX_CMD_PERLUN) - queue_depth = ARCMSR_MAX_CMD_PERLUN; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); - return queue_depth; -} - -static struct scsi_host_template arcmsr_scsi_host_template = { - .module = THIS_MODULE, - .name = "ARCMSR ARECA SATA/SAS RAID Controller" - ARCMSR_DRIVER_VERSION, - .info = arcmsr_info, - .queuecommand = arcmsr_queue_command, - .eh_abort_handler = arcmsr_abort, - .eh_bus_reset_handler = arcmsr_bus_reset, - .bios_param = arcmsr_bios_param, - .change_queue_depth = arcmsr_adjust_disk_queue_depth, - .can_queue = ARCMSR_MAX_FREECCB_NUM, - .this_id = ARCMSR_SCSI_INITIATOR_ID, - .sg_tablesize = ARCMSR_DEFAULT_SG_ENTRIES, - .max_sectors = ARCMSR_MAX_XFER_SECTORS_C, - .cmd_per_lun = ARCMSR_MAX_CMD_PERLUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = arcmsr_host_attrs, -}; -static struct pci_device_id arcmsr_device_id_table[] = { - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1260)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1270)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1280)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1380)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1381)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1680)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1681)}, - {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880)}, - {0, 0}, /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, arcmsr_device_id_table); -static struct pci_driver arcmsr_pci_driver = { - .name = "arcmsr", - .id_table = arcmsr_device_id_table, - .probe = arcmsr_probe, - .remove = arcmsr_remove, - .shutdown = arcmsr_shutdown, -}; -/* -**************************************************************************** -**************************************************************************** -*/ - -static void arcmsr_free_hbb_mu(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: - case ACB_ADAPTER_TYPE_C: - break; - case ACB_ADAPTER_TYPE_B:{ - dma_free_coherent(&acb->pdev->dev, - sizeof(struct MessageUnit_B), - acb->pmuB, acb->dma_coherent_handle_hbb_mu); - } - } -} - -static bool arcmsr_remap_pciregion(struct AdapterControlBlock *acb) -{ - struct pci_dev *pdev = acb->pdev; - switch (acb->adapter_type){ - case ACB_ADAPTER_TYPE_A:{ - acb->pmuA = ioremap(pci_resource_start(pdev,0), pci_resource_len(pdev,0)); - if (!acb->pmuA) { - printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); - return false; - } - break; - } - case ACB_ADAPTER_TYPE_B:{ - void __iomem *mem_base0, *mem_base1; - mem_base0 = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - if (!mem_base0) { - printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); - return false; - } - mem_base1 = ioremap(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); - if (!mem_base1) { - iounmap(mem_base0); - printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); - return false; - } - acb->mem_base0 = mem_base0; - acb->mem_base1 = mem_base1; - break; - } - case ACB_ADAPTER_TYPE_C:{ - acb->pmuC = ioremap_nocache(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); - if (!acb->pmuC) { - printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", acb->host->host_no); - return false; - } - if (readl(&acb->pmuC->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, &acb->pmuC->outbound_doorbell_clear);/*clear interrupt*/ - return true; - } - break; - } - } - return true; -} - -static void arcmsr_unmap_pciregion(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A:{ - iounmap(acb->pmuA); - } - break; - case ACB_ADAPTER_TYPE_B:{ - iounmap(acb->mem_base0); - iounmap(acb->mem_base1); - } - - break; - case ACB_ADAPTER_TYPE_C:{ - iounmap(acb->pmuC); - } - } -} - -static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) -{ - irqreturn_t handle_state; - struct AdapterControlBlock *acb = dev_id; - - handle_state = arcmsr_interrupt(acb); - return handle_state; -} - -static int arcmsr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *geom) -{ - int ret, heads, sectors, cylinders, total_capacity; - unsigned char *buffer;/* return copy of block device's partition table */ - - buffer = scsi_bios_ptable(bdev); - if (buffer) { - ret = scsi_partsize(buffer, capacity, &geom[2], &geom[0], &geom[1]); - kfree(buffer); - if (ret != -1) - return ret; - } - total_capacity = capacity; - heads = 64; - sectors = 32; - cylinders = total_capacity / (heads * sectors); - if (cylinders > 1024) { - heads = 255; - sectors = 63; - cylinders = total_capacity / (heads * sectors); - } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - return 0; -} - -static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) -{ - struct pci_dev *pdev = acb->pdev; - u16 dev_id; - pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); - acb->dev_id = dev_id; - switch (dev_id) { - case 0x1880: { - acb->adapter_type = ACB_ADAPTER_TYPE_C; - } - break; - case 0x1201: { - acb->adapter_type = ACB_ADAPTER_TYPE_B; - } - break; - - default: acb->adapter_type = ACB_ADAPTER_TYPE_A; - } -} - -static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - int i; - - for (i = 0; i < 2000; i++) { - if (readl(®->outbound_intstatus) & - ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, - ®->outbound_intstatus); - return true; - } - msleep(10); - } /* max 20 seconds */ - - return false; -} - -static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - int i; - - for (i = 0; i < 2000; i++) { - if (readl(reg->iop2drv_doorbell) - & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, - reg->iop2drv_doorbell); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, - reg->drv2iop_doorbell); - return true; - } - msleep(10); - } /* max 20 seconds */ - - return false; -} - -static uint8_t arcmsr_hbc_wait_msgint_ready(struct AdapterControlBlock *pACB) -{ - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; - int i; - - for (i = 0; i < 2000; i++) { - if (readl(&phbcmu->outbound_doorbell) - & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, - &phbcmu->outbound_doorbell_clear); /*clear interrupt*/ - return true; - } - msleep(10); - } /* max 20 seconds */ - - return false; -} - -static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - int retry_count = 30; - writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); - do { - if (arcmsr_hba_wait_msgint_ready(acb)) - break; - else { - retry_count--; - printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ - timeout, retry count down = %d \n", acb->host->host_no, retry_count); - } - } while (retry_count != 0); -} - -static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - int retry_count = 30; - writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell); - do { - if (arcmsr_hbb_wait_msgint_ready(acb)) - break; - else { - retry_count--; - printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ - timeout,retry count down = %d \n", acb->host->host_no, retry_count); - } - } while (retry_count != 0); -} - -static void arcmsr_flush_hbc_cache(struct AdapterControlBlock *pACB) -{ - struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; - int retry_count = 30;/* enlarge wait flush adapter cache time: 10 minute */ - writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); - writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - do { - if (arcmsr_hbc_wait_msgint_ready(pACB)) { - break; - } else { - retry_count--; - printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ - timeout,retry count down = %d \n", pACB->host->host_no, retry_count); - } - } while (retry_count != 0); - return; -} -static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - arcmsr_flush_hba_cache(acb); - } - break; - - case ACB_ADAPTER_TYPE_B: { - arcmsr_flush_hbb_cache(acb); - } - break; - case ACB_ADAPTER_TYPE_C: { - arcmsr_flush_hbc_cache(acb); - } - } -} - -static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) -{ - struct pci_dev *pdev = acb->pdev; - void *dma_coherent; - dma_addr_t dma_coherent_handle; - struct CommandControlBlock *ccb_tmp; - int i = 0, j = 0; - dma_addr_t cdb_phyaddr; - unsigned long roundup_ccbsize; - unsigned long max_xfer_len; - unsigned long max_sg_entrys; - uint32_t firm_config_version; - - for (i = 0; i < ARCMSR_MAX_TARGETID; i++) - for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GONE; - - max_xfer_len = ARCMSR_MAX_XFER_LEN; - max_sg_entrys = ARCMSR_DEFAULT_SG_ENTRIES; - firm_config_version = acb->firm_cfg_version; - if((firm_config_version & 0xFF) >= 3){ - max_xfer_len = (ARCMSR_CDB_SG_PAGE_LENGTH << ((firm_config_version >> 8) & 0xFF)) * 1024;/* max 4M byte */ - max_sg_entrys = (max_xfer_len/4096); - } - acb->host->max_sectors = max_xfer_len/512; - acb->host->sg_tablesize = max_sg_entrys; - roundup_ccbsize = roundup(sizeof(struct CommandControlBlock) + (max_sg_entrys - 1) * sizeof(struct SG64ENTRY), 32); - acb->uncache_size = roundup_ccbsize * ARCMSR_MAX_FREECCB_NUM; - dma_coherent = dma_alloc_coherent(&pdev->dev, acb->uncache_size, &dma_coherent_handle, GFP_KERNEL); - if(!dma_coherent){ - printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error\n", acb->host->host_no); - return -ENOMEM; - } - acb->dma_coherent = dma_coherent; - acb->dma_coherent_handle = dma_coherent_handle; - memset(dma_coherent, 0, acb->uncache_size); - ccb_tmp = dma_coherent; - acb->vir2phy_offset = (unsigned long)dma_coherent - (unsigned long)dma_coherent_handle; - for(i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++){ - cdb_phyaddr = dma_coherent_handle + offsetof(struct CommandControlBlock, arcmsr_cdb); - ccb_tmp->cdb_phyaddr_pattern = ((acb->adapter_type == ACB_ADAPTER_TYPE_C) ? cdb_phyaddr : (cdb_phyaddr >> 5)); - acb->pccb_pool[i] = ccb_tmp; - ccb_tmp->acb = acb; - INIT_LIST_HEAD(&ccb_tmp->list); - list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - ccb_tmp = (struct CommandControlBlock *)((unsigned long)ccb_tmp + roundup_ccbsize); - dma_coherent_handle = dma_coherent_handle + roundup_ccbsize; - } - return 0; -} - -static void arcmsr_message_isr_bh_fn(struct work_struct *work) -{ - struct AdapterControlBlock *acb = container_of(work,struct AdapterControlBlock, arcmsr_do_message_isr_bh); - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - - struct MessageUnit_A __iomem *reg = acb->pmuA; - char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem*) (®->message_rwbuffer[0]); - char __iomem *devicemap = (char __iomem*) (®->message_rwbuffer[21]); - int target, lun; - struct scsi_device *psdev; - char diff; - - atomic_inc(&acb->rq_map_token); - if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { - for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) { - diff = (*acb_dev_map)^readb(devicemap); - if (diff != 0) { - char temp; - *acb_dev_map = readb(devicemap); - temp =*acb_dev_map; - for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { - if((temp & 0x01)==1 && (diff & 0x01) == 1) { - scsi_add_device(acb->host, 0, target, lun); - }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { - psdev = scsi_device_lookup(acb->host, 0, target, lun); - if (psdev != NULL ) { - scsi_remove_device(psdev); - scsi_device_put(psdev); - } - } - temp >>= 1; - diff >>= 1; - } - } - devicemap++; - acb_dev_map++; - } - } - break; - } - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem*)(®->message_rwbuffer[0]); - char __iomem *devicemap = (char __iomem*)(®->message_rwbuffer[21]); - int target, lun; - struct scsi_device *psdev; - char diff; - - atomic_inc(&acb->rq_map_token); - if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { - for(target = 0; target < ARCMSR_MAX_TARGETID -1; target++) { - diff = (*acb_dev_map)^readb(devicemap); - if (diff != 0) { - char temp; - *acb_dev_map = readb(devicemap); - temp =*acb_dev_map; - for(lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { - if((temp & 0x01)==1 && (diff & 0x01) == 1) { - scsi_add_device(acb->host, 0, target, lun); - }else if((temp & 0x01) == 0 && (diff & 0x01) == 1) { - psdev = scsi_device_lookup(acb->host, 0, target, lun); - if (psdev != NULL ) { - scsi_remove_device(psdev); - scsi_device_put(psdev); - } - } - temp >>= 1; - diff >>= 1; - } - } - devicemap++; - acb_dev_map++; - } - } - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = acb->pmuC; - char *acb_dev_map = (char *)acb->device_map; - uint32_t __iomem *signature = (uint32_t __iomem *)(®->msgcode_rwbuffer[0]); - char __iomem *devicemap = (char __iomem *)(®->msgcode_rwbuffer[21]); - int target, lun; - struct scsi_device *psdev; - char diff; - - atomic_inc(&acb->rq_map_token); - if (readl(signature) == ARCMSR_SIGNATURE_GET_CONFIG) { - for (target = 0; target < ARCMSR_MAX_TARGETID - 1; target++) { - diff = (*acb_dev_map)^readb(devicemap); - if (diff != 0) { - char temp; - *acb_dev_map = readb(devicemap); - temp = *acb_dev_map; - for (lun = 0; lun < ARCMSR_MAX_TARGETLUN; lun++) { - if ((temp & 0x01) == 1 && (diff & 0x01) == 1) { - scsi_add_device(acb->host, 0, target, lun); - } else if ((temp & 0x01) == 0 && (diff & 0x01) == 1) { - psdev = scsi_device_lookup(acb->host, 0, target, lun); - if (psdev != NULL) { - scsi_remove_device(psdev); - scsi_device_put(psdev); - } - } - temp >>= 1; - diff >>= 1; - } - } - devicemap++; - acb_dev_map++; - } - } - } - } -} - -static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct Scsi_Host *host; - struct AdapterControlBlock *acb; - uint8_t bus,dev_fun; - int error; - error = pci_enable_device(pdev); - if(error){ - return -ENODEV; - } - host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof(struct AdapterControlBlock)); - if(!host){ - goto pci_disable_dev; - } - error = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if(error){ - error = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if(error){ - printk(KERN_WARNING - "scsi%d: No suitable DMA mask available\n", - host->host_no); - goto scsi_host_release; - } - } - init_waitqueue_head(&wait_q); - bus = pdev->bus->number; - dev_fun = pdev->devfn; - acb = (struct AdapterControlBlock *) host->hostdata; - memset(acb,0,sizeof(struct AdapterControlBlock)); - acb->pdev = pdev; - acb->host = host; - host->max_lun = ARCMSR_MAX_TARGETLUN; - host->max_id = ARCMSR_MAX_TARGETID; /*16:8*/ - host->max_cmd_len = 16; /*this is issue of 64bit LBA ,over 2T byte*/ - host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ - host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; - host->this_id = ARCMSR_SCSI_INITIATOR_ID; - host->unique_id = (bus << 8) | dev_fun; - pci_set_drvdata(pdev, host); - pci_set_master(pdev); - error = pci_request_regions(pdev, "arcmsr"); - if(error){ - goto scsi_host_release; - } - spin_lock_init(&acb->eh_lock); - spin_lock_init(&acb->ccblist_lock); - acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | - ACB_F_MESSAGE_RQBUFFER_CLEARED | - ACB_F_MESSAGE_WQBUFFER_READED); - acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; - INIT_LIST_HEAD(&acb->ccb_free_list); - arcmsr_define_adapter_type(acb); - error = arcmsr_remap_pciregion(acb); - if(!error){ - goto pci_release_regs; - } - error = arcmsr_get_firmware_spec(acb); - if(!error){ - goto unmap_pci_region; - } - error = arcmsr_alloc_ccb_pool(acb); - if(error){ - goto free_hbb_mu; - } - arcmsr_iop_init(acb); - error = scsi_add_host(host, &pdev->dev); - if(error){ - goto RAID_controller_stop; - } - error = request_irq(pdev->irq, arcmsr_do_interrupt, IRQF_SHARED, "arcmsr", acb); - if(error){ - goto scsi_host_remove; - } - host->irq = pdev->irq; - scsi_scan_host(host); - INIT_WORK(&acb->arcmsr_do_message_isr_bh, arcmsr_message_isr_bh_fn); - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - init_timer(&acb->eternal_timer); - acb->eternal_timer.expires = jiffies + msecs_to_jiffies(6 * HZ); - acb->eternal_timer.data = (unsigned long) acb; - acb->eternal_timer.function = &arcmsr_request_device_map; - add_timer(&acb->eternal_timer); - if(arcmsr_alloc_sysfs_attr(acb)) - goto out_free_sysfs; - return 0; -out_free_sysfs: -scsi_host_remove: - scsi_remove_host(host); -RAID_controller_stop: - arcmsr_stop_adapter_bgrb(acb); - arcmsr_flush_adapter_cache(acb); - arcmsr_free_ccb_pool(acb); -free_hbb_mu: - arcmsr_free_hbb_mu(acb); -unmap_pci_region: - arcmsr_unmap_pciregion(acb); -pci_release_regs: - pci_release_regions(pdev); -scsi_host_release: - scsi_host_put(host); -pci_disable_dev: - pci_disable_device(pdev); - return -ENODEV; -} - -static uint8_t arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { - printk(KERN_NOTICE - "arcmsr%d: wait 'abort all outstanding command' timeout \n" - , acb->host->host_no); - return false; - } - return true; -} - -static uint8_t arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - - writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE - "arcmsr%d: wait 'abort all outstanding command' timeout \n" - , acb->host->host_no); - return false; - } - return true; -} -static uint8_t arcmsr_abort_hbc_allcmd(struct AdapterControlBlock *pACB) -{ - struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; - writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); - writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - if (!arcmsr_hbc_wait_msgint_ready(pACB)) { - printk(KERN_NOTICE - "arcmsr%d: wait 'abort all outstanding command' timeout \n" - , pACB->host->host_no); - return false; - } - return true; -} -static uint8_t arcmsr_abort_allcmd(struct AdapterControlBlock *acb) -{ - uint8_t rtnval = 0; - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - rtnval = arcmsr_abort_hba_allcmd(acb); - } - break; - - case ACB_ADAPTER_TYPE_B: { - rtnval = arcmsr_abort_hbb_allcmd(acb); - } - break; - - case ACB_ADAPTER_TYPE_C: { - rtnval = arcmsr_abort_hbc_allcmd(acb); - } - } - return rtnval; -} - -static bool arcmsr_hbb_enable_driver_mode(struct AdapterControlBlock *pacb) -{ - struct MessageUnit_B *reg = pacb->pmuB; - writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(pacb)) { - printk(KERN_ERR "arcmsr%d: can't set driver mode. \n", pacb->host->host_no); - return false; - } - return true; -} - -static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) -{ - struct scsi_cmnd *pcmd = ccb->pcmd; - - scsi_dma_unmap(pcmd); -} - -static void arcmsr_ccb_complete(struct CommandControlBlock *ccb) -{ - struct AdapterControlBlock *acb = ccb->acb; - struct scsi_cmnd *pcmd = ccb->pcmd; - unsigned long flags; - atomic_dec(&acb->ccboutstandingcount); - arcmsr_pci_unmap_dma(ccb); - ccb->startdone = ARCMSR_CCB_DONE; - spin_lock_irqsave(&acb->ccblist_lock, flags); - list_add_tail(&ccb->list, &acb->ccb_free_list); - spin_unlock_irqrestore(&acb->ccblist_lock, flags); - pcmd->scsi_done(pcmd); -} - -static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) -{ - - struct scsi_cmnd *pcmd = ccb->pcmd; - struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; - pcmd->result = DID_OK << 16; - if (sensebuffer) { - int sense_data_length = - sizeof(struct SENSE_DATA) < SCSI_SENSE_BUFFERSIZE - ? sizeof(struct SENSE_DATA) : SCSI_SENSE_BUFFERSIZE; - memset(sensebuffer, 0, SCSI_SENSE_BUFFERSIZE); - memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); - sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; - sensebuffer->Valid = 1; - } -} - -static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) -{ - u32 orig_mask = 0; - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A : { - struct MessageUnit_A __iomem *reg = acb->pmuA; - orig_mask = readl(®->outbound_intmask); - writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \ - ®->outbound_intmask); - } - break; - case ACB_ADAPTER_TYPE_B : { - struct MessageUnit_B *reg = acb->pmuB; - orig_mask = readl(reg->iop2drv_doorbell_mask); - writel(0, reg->iop2drv_doorbell_mask); - } - break; - case ACB_ADAPTER_TYPE_C:{ - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - /* disable all outbound interrupt */ - orig_mask = readl(®->host_int_mask); /* disable outbound message0 int */ - writel(orig_mask|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask); - } - break; - } - return orig_mask; -} - -static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, - struct CommandControlBlock *ccb, bool error) -{ - uint8_t id, lun; - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!error) { - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb); - }else{ - switch (ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb); - } - break; - - case ARCMSR_DEV_ABORTED: - - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb); - } - break; - - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb); - } - break; - - default: - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d lun = %d isr get command error done, \ - but got unknown DeviceStatus = 0x%x \n" - , acb->host->host_no - , id - , lun - , ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb); - break; - } - } -} - -static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct CommandControlBlock *pCCB, bool error) -{ - int id, lun; - if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { - if (pCCB->startdone == ARCMSR_CCB_ABORTED) { - struct scsi_cmnd *abortcmd = pCCB->pcmd; - if (abortcmd) { - id = abortcmd->device->id; - lun = abortcmd->device->lun; - abortcmd->result |= DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); - printk(KERN_NOTICE "arcmsr%d: pCCB ='0x%p' isr got aborted command \n", - acb->host->host_no, pCCB); - } - return; - } - printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \ - done acb = '0x%p'" - "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" - " ccboutstandingcount = %d \n" - , acb->host->host_no - , acb - , pCCB - , pCCB->acb - , pCCB->startdone - , atomic_read(&acb->ccboutstandingcount)); - return; - } - arcmsr_report_ccb_state(acb, pCCB, error); -} - -static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) -{ - int i = 0; - uint32_t flag_ccb; - struct ARCMSR_CDB *pARCMSR_CDB; - bool error; - struct CommandControlBlock *pCCB; - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t outbound_intstatus; - outbound_intstatus = readl(®->outbound_intstatus) & - acb->outbound_int_enable; - /*clear and abort all outbound posted Q*/ - writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ - while(((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) - && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ - pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; - arcmsr_drain_donequeue(acb, pCCB, error); - } - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - /*clear all outbound posted Q*/ - writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); /* clear doorbell interrupt */ - for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { - if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) { - writel(0, ®->done_qbuffer[i]); - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ - pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; - arcmsr_drain_donequeue(acb, pCCB, error); - } - reg->post_qbuffer[i] = 0; - } - reg->doneq_index = 0; - reg->postq_index = 0; - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = acb->pmuC; - struct ARCMSR_CDB *pARCMSR_CDB; - uint32_t flag_ccb, ccb_cdb_phy; - bool error; - struct CommandControlBlock *pCCB; - while ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { - /*need to do*/ - flag_ccb = readl(®->outbound_queueport_low); - ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+ccb_cdb_phy);/*frame must be 32 bytes aligned*/ - pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; - arcmsr_drain_donequeue(acb, pCCB, error); - } - } - } -} -static void arcmsr_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - int poll_count = 0; - arcmsr_free_sysfs_attr(acb); - scsi_remove_host(host); - flush_work_sync(&acb->arcmsr_do_message_isr_bh); - del_timer_sync(&acb->eternal_timer); - arcmsr_disable_outbound_ints(acb); - arcmsr_stop_adapter_bgrb(acb); - arcmsr_flush_adapter_cache(acb); - acb->acb_flags |= ACB_F_SCSISTOPADAPTER; - acb->acb_flags &= ~ACB_F_IOP_INITED; - - for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++){ - if (!atomic_read(&acb->ccboutstandingcount)) - break; - arcmsr_interrupt(acb);/* FIXME: need spinlock */ - msleep(25); - } - - if (atomic_read(&acb->ccboutstandingcount)) { - int i; - - arcmsr_abort_allcmd(acb); - arcmsr_done4abort_postqueue(acb); - for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - struct CommandControlBlock *ccb = acb->pccb_pool[i]; - if (ccb->startdone == ARCMSR_CCB_START) { - ccb->startdone = ARCMSR_CCB_ABORTED; - ccb->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(ccb); - } - } - } - free_irq(pdev->irq, acb); - arcmsr_free_ccb_pool(acb); - arcmsr_free_hbb_mu(acb); - arcmsr_unmap_pciregion(acb); - pci_release_regions(pdev); - scsi_host_put(host); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - -static void arcmsr_shutdown(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *)host->hostdata; - del_timer_sync(&acb->eternal_timer); - arcmsr_disable_outbound_ints(acb); - flush_work_sync(&acb->arcmsr_do_message_isr_bh); - arcmsr_stop_adapter_bgrb(acb); - arcmsr_flush_adapter_cache(acb); -} - -static int arcmsr_module_init(void) -{ - int error = 0; - error = pci_register_driver(&arcmsr_pci_driver); - return error; -} - -static void arcmsr_module_exit(void) -{ - pci_unregister_driver(&arcmsr_pci_driver); -} -module_init(arcmsr_module_init); -module_exit(arcmsr_module_exit); - -static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, - u32 intmask_org) -{ - u32 mask; - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE| - ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE); - writel(mask, ®->outbound_intmask); - acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | - ARCMSR_IOP2DRV_DATA_READ_OK | - ARCMSR_IOP2DRV_CDB_DONE | - ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); - writel(mask, reg->iop2drv_doorbell_mask); - acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = acb->pmuC; - mask = ~(ARCMSR_HBCMU_UTILITY_A_ISR_MASK | ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR_MASK|ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR_MASK); - writel(intmask_org & mask, ®->host_int_mask); - acb->outbound_int_enable = ~(intmask_org & mask) & 0x0000000f; - } - } -} - -static int arcmsr_build_ccb(struct AdapterControlBlock *acb, - struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) -{ - struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; - int8_t *psge = (int8_t *)&arcmsr_cdb->u; - __le32 address_lo, address_hi; - int arccdbsize = 0x30; - __le32 length = 0; - int i; - struct scatterlist *sg; - int nseg; - ccb->pcmd = pcmd; - memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); - arcmsr_cdb->TargetID = pcmd->device->id; - arcmsr_cdb->LUN = pcmd->device->lun; - arcmsr_cdb->Function = 1; - arcmsr_cdb->Context = 0; - memcpy(arcmsr_cdb->Cdb, pcmd->cmnd, pcmd->cmd_len); - - nseg = scsi_dma_map(pcmd); - if (unlikely(nseg > acb->host->sg_tablesize || nseg < 0)) - return FAILED; - scsi_for_each_sg(pcmd, sg, nseg, i) { - /* Get the physical address of the current data pointer */ - length = cpu_to_le32(sg_dma_len(sg)); - address_lo = cpu_to_le32(dma_addr_lo32(sg_dma_address(sg))); - address_hi = cpu_to_le32(dma_addr_hi32(sg_dma_address(sg))); - if (address_hi == 0) { - struct SG32ENTRY *pdma_sg = (struct SG32ENTRY *)psge; - - pdma_sg->address = address_lo; - pdma_sg->length = length; - psge += sizeof (struct SG32ENTRY); - arccdbsize += sizeof (struct SG32ENTRY); - } else { - struct SG64ENTRY *pdma_sg = (struct SG64ENTRY *)psge; - - pdma_sg->addresshigh = address_hi; - pdma_sg->address = address_lo; - pdma_sg->length = length|cpu_to_le32(IS_SG64_ADDR); - psge += sizeof (struct SG64ENTRY); - arccdbsize += sizeof (struct SG64ENTRY); - } - } - arcmsr_cdb->sgcount = (uint8_t)nseg; - arcmsr_cdb->DataLength = scsi_bufflen(pcmd); - arcmsr_cdb->msgPages = arccdbsize/0x100 + (arccdbsize % 0x100 ? 1 : 0); - if ( arccdbsize > 256) - arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_SGL_BSIZE; - if (pcmd->sc_data_direction == DMA_TO_DEVICE) - arcmsr_cdb->Flags |= ARCMSR_CDB_FLAG_WRITE; - ccb->arc_cdb_size = arccdbsize; - return SUCCESS; -} - -static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) -{ - uint32_t cdb_phyaddr_pattern = ccb->cdb_phyaddr_pattern; - struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; - atomic_inc(&acb->ccboutstandingcount); - ccb->startdone = ARCMSR_CCB_START; - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - - if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) - writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, - ®->inbound_queueport); - else { - writel(cdb_phyaddr_pattern, ®->inbound_queueport); - } - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - uint32_t ending_index, index = reg->postq_index; - - ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); - writel(0, ®->post_qbuffer[ending_index]); - if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { - writel(cdb_phyaddr_pattern | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ - ®->post_qbuffer[index]); - } else { - writel(cdb_phyaddr_pattern, ®->post_qbuffer[index]); - } - index++; - index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ - reg->postq_index = index; - writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell); - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC; - uint32_t ccb_post_stamp, arc_cdb_size; - - arc_cdb_size = (ccb->arc_cdb_size > 0x300) ? 0x300 : ccb->arc_cdb_size; - ccb_post_stamp = (cdb_phyaddr_pattern | ((arc_cdb_size - 1) >> 6) | 1); - if (acb->cdb_phyaddr_hi32) { - writel(acb->cdb_phyaddr_hi32, &phbcmu->inbound_queueport_high); - writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); - } else { - writel(ccb_post_stamp, &phbcmu->inbound_queueport_low); - } - } - } -} - -static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - acb->acb_flags &= ~ACB_F_MSG_START_BGRB; - writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { - printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" - , acb->host->host_no); - } -} - -static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - acb->acb_flags &= ~ACB_F_MSG_START_BGRB; - writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell); - - if (!arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" - , acb->host->host_no); - } -} - -static void arcmsr_stop_hbc_bgrb(struct AdapterControlBlock *pACB) -{ - struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; - pACB->acb_flags &= ~ACB_F_MSG_START_BGRB; - writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); - writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - if (!arcmsr_hbc_wait_msgint_ready(pACB)) { - printk(KERN_NOTICE - "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" - , pACB->host->host_no); - } - return; -} -static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - arcmsr_stop_hba_bgrb(acb); - } - break; - - case ACB_ADAPTER_TYPE_B: { - arcmsr_stop_hbb_bgrb(acb); - } - break; - case ACB_ADAPTER_TYPE_C: { - arcmsr_stop_hbc_bgrb(acb); - } - } -} - -static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) -{ - dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); -} - -void arcmsr_iop_message_read(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C __iomem *reg = acb->pmuC; - writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); - } - } -} - -static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - /* - ** push inbound doorbell tell iop, driver data write ok - ** and wait reply on next hwinterrupt for next Qbuffer post - */ - writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, ®->inbound_doorbell); - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - /* - ** push inbound doorbell tell iop, driver data write ok - ** and wait reply on next hwinterrupt for next Qbuffer post - */ - writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell); - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C __iomem *reg = acb->pmuC; - /* - ** push inbound doorbell tell iop, driver data write ok - ** and wait reply on next hwinterrupt for next Qbuffer post - */ - writel(ARCMSR_HBCMU_DRV2IOP_DATA_WRITE_OK, ®->inbound_doorbell); - } - break; - } -} - -struct QBUFFER __iomem *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) -{ - struct QBUFFER __iomem *qbuffer = NULL; - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - qbuffer = (struct QBUFFER __iomem *)®->message_rbuffer; - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - qbuffer = (struct QBUFFER __iomem *)reg->message_rbuffer; - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)acb->pmuC; - qbuffer = (struct QBUFFER __iomem *)&phbcmu->message_rbuffer; - } - } - return qbuffer; -} - -static struct QBUFFER __iomem *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb) -{ - struct QBUFFER __iomem *pqbuffer = NULL; - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - pqbuffer = (struct QBUFFER __iomem *) ®->message_wbuffer; - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - pqbuffer = (struct QBUFFER __iomem *)reg->message_wbuffer; - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - pqbuffer = (struct QBUFFER __iomem *)®->message_wbuffer; - } - - } - return pqbuffer; -} - -static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) -{ - struct QBUFFER __iomem *prbuffer; - struct QBUFFER *pQbuffer; - uint8_t __iomem *iop_data; - int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; - rqbuf_lastindex = acb->rqbuf_lastindex; - rqbuf_firstindex = acb->rqbuf_firstindex; - prbuffer = arcmsr_get_iop_rqbuffer(acb); - iop_data = (uint8_t __iomem *)prbuffer->data; - iop_len = prbuffer->data_len; - my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) & (ARCMSR_MAX_QBUFFER - 1); - - if (my_empty_len >= iop_len) - { - while (iop_len > 0) { - pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex]; - memcpy(pQbuffer, iop_data, 1); - rqbuf_lastindex++; - rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - acb->rqbuf_lastindex = rqbuf_lastindex; - arcmsr_iop_message_read(acb); - } - - else { - acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; - } -} - -static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) -{ - acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; - if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { - uint8_t *pQbuffer; - struct QBUFFER __iomem *pwbuffer; - uint8_t __iomem *iop_data; - int32_t allxfer_len = 0; - - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); - pwbuffer = arcmsr_get_iop_wqbuffer(acb); - iop_data = (uint8_t __iomem *)pwbuffer->data; - - while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \ - (allxfer_len < 124)) { - pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex]; - memcpy(iop_data, pQbuffer, 1); - acb->wqbuf_firstindex++; - acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; - } - pwbuffer->data_len = allxfer_len; - - arcmsr_iop_message_wrote(acb); - } - - if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) { - acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; - } -} - -static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) -{ - uint32_t outbound_doorbell; - struct MessageUnit_A __iomem *reg = acb->pmuA; - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell); - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { - arcmsr_iop2drv_data_wrote_handle(acb); - } - - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { - arcmsr_iop2drv_data_read_handle(acb); - } -} -static void arcmsr_hbc_doorbell_isr(struct AdapterControlBlock *pACB) -{ - uint32_t outbound_doorbell; - struct MessageUnit_C *reg = (struct MessageUnit_C *)pACB->pmuC; - /* - ******************************************************************* - ** Maybe here we need to check wrqbuffer_lock is lock or not - ** DOORBELL: din! don! - ** check if there are any mail need to pack from firmware - ******************************************************************* - */ - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell_clear);/*clear interrupt*/ - if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_WRITE_OK) { - arcmsr_iop2drv_data_wrote_handle(pACB); - } - if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_DATA_READ_OK) { - arcmsr_iop2drv_data_read_handle(pACB); - } - if (outbound_doorbell & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { - arcmsr_hbc_message_isr(pACB); /* messenger of "driver to iop commands" */ - } - return; -} -static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) -{ - uint32_t flag_ccb; - struct MessageUnit_A __iomem *reg = acb->pmuA; - struct ARCMSR_CDB *pARCMSR_CDB; - struct CommandControlBlock *pCCB; - bool error; - while ((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) { - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ - pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; - arcmsr_drain_donequeue(acb, pCCB, error); - } -} -static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) -{ - uint32_t index; - uint32_t flag_ccb; - struct MessageUnit_B *reg = acb->pmuB; - struct ARCMSR_CDB *pARCMSR_CDB; - struct CommandControlBlock *pCCB; - bool error; - index = reg->doneq_index; - while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) { - writel(0, ®->done_qbuffer[index]); - pARCMSR_CDB = (struct ARCMSR_CDB *)(acb->vir2phy_offset+(flag_ccb << 5));/*frame must be 32 bytes aligned*/ - pCCB = container_of(pARCMSR_CDB, struct CommandControlBlock, arcmsr_cdb); - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; - arcmsr_drain_donequeue(acb, pCCB, error); - index++; - index %= ARCMSR_MAX_HBB_POSTQUEUE; - reg->doneq_index = index; - } -} - -static void arcmsr_hbc_postqueue_isr(struct AdapterControlBlock *acb) -{ - struct MessageUnit_C *phbcmu; - struct ARCMSR_CDB *arcmsr_cdb; - struct CommandControlBlock *ccb; - uint32_t flag_ccb, ccb_cdb_phy, throttling = 0; - int error; - - phbcmu = (struct MessageUnit_C *)acb->pmuC; - /* areca cdb command done */ - /* Use correct offset and size for syncing */ - - while (readl(&phbcmu->host_int_status) & - ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR){ - /* check if command done with no error*/ - flag_ccb = readl(&phbcmu->outbound_queueport_low); - ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0);/*frame must be 32 bytes aligned*/ - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy); - ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; - /* check if command done with no error */ - arcmsr_drain_donequeue(acb, ccb, error); - if (throttling == ARCMSR_HBC_ISR_THROTTLING_LEVEL) { - writel(ARCMSR_HBCMU_DRV2IOP_POSTQUEUE_THROTTLING, &phbcmu->inbound_doorbell); - break; - } - throttling++; - } -} -/* -********************************************************************************** -** Handle a message interrupt -** -** The only message interrupt we expect is in response to a query for the current adapter config. -** We want this in order to compare the drivemap so that we can detect newly-attached drives. -********************************************************************************** -*/ -static void arcmsr_hba_message_isr(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A *reg = acb->pmuA; - /*clear interrupt and message state*/ - writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, ®->outbound_intstatus); - schedule_work(&acb->arcmsr_do_message_isr_bh); -} -static void arcmsr_hbb_message_isr(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - - /*clear interrupt and message state*/ - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); - schedule_work(&acb->arcmsr_do_message_isr_bh); -} -/* -********************************************************************************** -** Handle a message interrupt -** -** The only message interrupt we expect is in response to a query for the -** current adapter config. -** We want this in order to compare the drivemap so that we can detect newly-attached drives. -********************************************************************************** -*/ -static void arcmsr_hbc_message_isr(struct AdapterControlBlock *acb) -{ - struct MessageUnit_C *reg = acb->pmuC; - /*clear interrupt and message state*/ - writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear); - schedule_work(&acb->arcmsr_do_message_isr_bh); -} - -static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) -{ - uint32_t outbound_intstatus; - struct MessageUnit_A __iomem *reg = acb->pmuA; - outbound_intstatus = readl(®->outbound_intstatus) & - acb->outbound_int_enable; - if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) { - return 1; - } - writel(outbound_intstatus, ®->outbound_intstatus); - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { - arcmsr_hba_doorbell_isr(acb); - } - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { - arcmsr_hba_postqueue_isr(acb); - } - if(outbound_intstatus & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - /* messenger of "driver to iop commands" */ - arcmsr_hba_message_isr(acb); - } - return 0; -} - -static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) -{ - uint32_t outbound_doorbell; - struct MessageUnit_B *reg = acb->pmuB; - outbound_doorbell = readl(reg->iop2drv_doorbell) & - acb->outbound_int_enable; - if (!outbound_doorbell) - return 1; - - writel(~outbound_doorbell, reg->iop2drv_doorbell); - /*in case the last action of doorbell interrupt clearance is cached, - this action can push HW to write down the clear bit*/ - readl(reg->iop2drv_doorbell); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); - if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { - arcmsr_iop2drv_data_wrote_handle(acb); - } - if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { - arcmsr_iop2drv_data_read_handle(acb); - } - if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { - arcmsr_hbb_postqueue_isr(acb); - } - if(outbound_doorbell & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { - /* messenger of "driver to iop commands" */ - arcmsr_hbb_message_isr(acb); - } - return 0; -} - -static int arcmsr_handle_hbc_isr(struct AdapterControlBlock *pACB) -{ - uint32_t host_interrupt_status; - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; - /* - ********************************************* - ** check outbound intstatus - ********************************************* - */ - host_interrupt_status = readl(&phbcmu->host_int_status); - if (!host_interrupt_status) { - /*it must be share irq*/ - return 1; - } - /* MU ioctl transfer doorbell interrupts*/ - if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_DOORBELL_ISR) { - arcmsr_hbc_doorbell_isr(pACB); /* messenger of "ioctl message read write" */ - } - /* MU post queue interrupts*/ - if (host_interrupt_status & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) { - arcmsr_hbc_postqueue_isr(pACB); /* messenger of "scsi commands" */ - } - return 0; -} -static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - if (arcmsr_handle_hba_isr(acb)) { - return IRQ_NONE; - } - } - break; - - case ACB_ADAPTER_TYPE_B: { - if (arcmsr_handle_hbb_isr(acb)) { - return IRQ_NONE; - } - } - break; - case ACB_ADAPTER_TYPE_C: { - if (arcmsr_handle_hbc_isr(acb)) { - return IRQ_NONE; - } - } - } - return IRQ_HANDLED; -} - -static void arcmsr_iop_parking(struct AdapterControlBlock *acb) -{ - if (acb) { - /* stop adapter background rebuild */ - if (acb->acb_flags & ACB_F_MSG_START_BGRB) { - uint32_t intmask_org; - acb->acb_flags &= ~ACB_F_MSG_START_BGRB; - intmask_org = arcmsr_disable_outbound_ints(acb); - arcmsr_stop_adapter_bgrb(acb); - arcmsr_flush_adapter_cache(acb); - arcmsr_enable_outbound_ints(acb, intmask_org); - } - } -} - -void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) -{ - int32_t wqbuf_firstindex, wqbuf_lastindex; - uint8_t *pQbuffer; - struct QBUFFER __iomem *pwbuffer; - uint8_t __iomem *iop_data; - int32_t allxfer_len = 0; - pwbuffer = arcmsr_get_iop_wqbuffer(acb); - iop_data = (uint8_t __iomem *)pwbuffer->data; - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); - wqbuf_firstindex = acb->wqbuf_firstindex; - wqbuf_lastindex = acb->wqbuf_lastindex; - while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) { - pQbuffer = &acb->wqbuffer[wqbuf_firstindex]; - memcpy(iop_data, pQbuffer, 1); - wqbuf_firstindex++; - wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; - } - acb->wqbuf_firstindex = wqbuf_firstindex; - pwbuffer->data_len = allxfer_len; - arcmsr_iop_message_wrote(acb); - } -} - -static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, - struct scsi_cmnd *cmd) -{ - struct CMD_MESSAGE_FIELD *pcmdmessagefld; - int retvalue = 0, transfer_len = 0; - char *buffer; - struct scatterlist *sg; - uint32_t controlcode = (uint32_t ) cmd->cmnd[5] << 24 | - (uint32_t ) cmd->cmnd[6] << 16 | - (uint32_t ) cmd->cmnd[7] << 8 | - (uint32_t ) cmd->cmnd[8]; - /* 4 bytes: Areca io control code */ - sg = scsi_sglist(cmd); - buffer = kmap_atomic(sg_page(sg)) + sg->offset; - if (scsi_sg_count(cmd) > 1) { - retvalue = ARCMSR_MESSAGE_FAIL; - goto message_out; - } - transfer_len += sg->length; - - if (transfer_len > sizeof(struct CMD_MESSAGE_FIELD)) { - retvalue = ARCMSR_MESSAGE_FAIL; - goto message_out; - } - pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; - switch(controlcode) { - - case ARCMSR_MESSAGE_READ_RQBUFFER: { - unsigned char *ver_addr; - uint8_t *pQbuffer, *ptmpQbuffer; - int32_t allxfer_len = 0; - - ver_addr = kmalloc(1032, GFP_ATOMIC); - if (!ver_addr) { - retvalue = ARCMSR_MESSAGE_FAIL; - goto message_out; - } - - ptmpQbuffer = ver_addr; - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) - && (allxfer_len < 1031)) { - pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; - memcpy(ptmpQbuffer, pQbuffer, 1); - acb->rqbuf_firstindex++; - acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - ptmpQbuffer++; - allxfer_len++; - } - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - - struct QBUFFER __iomem *prbuffer; - uint8_t __iomem *iop_data; - int32_t iop_len; - - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - prbuffer = arcmsr_get_iop_rqbuffer(acb); - iop_data = prbuffer->data; - iop_len = readl(&prbuffer->data_len); - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - arcmsr_iop_message_read(acb); - } - memcpy(pcmdmessagefld->messagedatabuffer, ver_addr, allxfer_len); - pcmdmessagefld->cmdmessage.Length = allxfer_len; - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; - } - kfree(ver_addr); - } - break; - - case ARCMSR_MESSAGE_WRITE_WQBUFFER: { - unsigned char *ver_addr; - int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; - uint8_t *pQbuffer, *ptmpuserbuffer; - - ver_addr = kmalloc(1032, GFP_ATOMIC); - if (!ver_addr) { - retvalue = ARCMSR_MESSAGE_FAIL; - goto message_out; - } - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - ptmpuserbuffer = ver_addr; - user_len = pcmdmessagefld->cmdmessage.Length; - memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); - wqbuf_lastindex = acb->wqbuf_lastindex; - wqbuf_firstindex = acb->wqbuf_firstindex; - if (wqbuf_lastindex != wqbuf_firstindex) { - struct SENSE_DATA *sensebuffer = - (struct SENSE_DATA *)cmd->sense_buffer; - arcmsr_post_ioctldata2iop(acb); - /* has error report sensedata */ - sensebuffer->ErrorCode = 0x70; - sensebuffer->SenseKey = ILLEGAL_REQUEST; - sensebuffer->AdditionalSenseLength = 0x0A; - sensebuffer->AdditionalSenseCode = 0x20; - sensebuffer->Valid = 1; - retvalue = ARCMSR_MESSAGE_FAIL; - } else { - my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= user_len) { - while (user_len > 0) { - pQbuffer = - &acb->wqbuffer[acb->wqbuf_lastindex]; - memcpy(pQbuffer, ptmpuserbuffer, 1); - acb->wqbuf_lastindex++; - acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - ptmpuserbuffer++; - user_len--; - } - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { - acb->acb_flags &= - ~ACB_F_MESSAGE_WQBUFFER_CLEARED; - arcmsr_post_ioctldata2iop(acb); - } - } else { - /* has error report sensedata */ - struct SENSE_DATA *sensebuffer = - (struct SENSE_DATA *)cmd->sense_buffer; - sensebuffer->ErrorCode = 0x70; - sensebuffer->SenseKey = ILLEGAL_REQUEST; - sensebuffer->AdditionalSenseLength = 0x0A; - sensebuffer->AdditionalSenseCode = 0x20; - sensebuffer->Valid = 1; - retvalue = ARCMSR_MESSAGE_FAIL; - } - } - kfree(ver_addr); - } - break; - - case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { - uint8_t *pQbuffer = acb->rqbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - arcmsr_iop_message_read(acb); - } - acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - } - break; - - case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { - uint8_t *pQbuffer = acb->wqbuffer; - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - arcmsr_iop_message_read(acb); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED | - ACB_F_MESSAGE_WQBUFFER_READED); - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; - memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - } - break; - - case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { - uint8_t *pQbuffer; - - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - arcmsr_iop_message_read(acb); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED - | ACB_F_MESSAGE_RQBUFFER_CLEARED - | ACB_F_MESSAGE_WQBUFFER_READED); - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; - pQbuffer = acb->rqbuffer; - memset(pQbuffer, 0, sizeof(struct QBUFFER)); - pQbuffer = acb->wqbuffer; - memset(pQbuffer, 0, sizeof(struct QBUFFER)); - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - } - break; - - case ARCMSR_MESSAGE_RETURN_CODE_3F: { - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_3F; - } - break; - } - case ARCMSR_MESSAGE_SAY_HELLO: { - int8_t *hello_string = "Hello! I am ARCMSR"; - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - }else{ - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; - } - memcpy(pcmdmessagefld->messagedatabuffer, hello_string - , (int16_t)strlen(hello_string)); - } - break; - - case ARCMSR_MESSAGE_SAY_GOODBYE: - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } - arcmsr_iop_parking(acb); - break; - - case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: - if(acb->fw_flag == FW_DEADLOCK) { - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_BUS_HANG_ON; - } - arcmsr_flush_adapter_cache(acb); - break; - - default: - retvalue = ARCMSR_MESSAGE_FAIL; - } - message_out: - sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset); - return retvalue; -} - -static struct CommandControlBlock *arcmsr_get_freeccb(struct AdapterControlBlock *acb) -{ - struct list_head *head = &acb->ccb_free_list; - struct CommandControlBlock *ccb = NULL; - unsigned long flags; - spin_lock_irqsave(&acb->ccblist_lock, flags); - if (!list_empty(head)) { - ccb = list_entry(head->next, struct CommandControlBlock, list); - list_del_init(&ccb->list); - }else{ - spin_unlock_irqrestore(&acb->ccblist_lock, flags); - return 0; - } - spin_unlock_irqrestore(&acb->ccblist_lock, flags); - return ccb; -} - -static void arcmsr_handle_virtual_command(struct AdapterControlBlock *acb, - struct scsi_cmnd *cmd) -{ - switch (cmd->cmnd[0]) { - case INQUIRY: { - unsigned char inqdata[36]; - char *buffer; - struct scatterlist *sg; - - if (cmd->device->lun) { - cmd->result = (DID_TIME_OUT << 16); - cmd->scsi_done(cmd); - return; - } - inqdata[0] = TYPE_PROCESSOR; - /* Periph Qualifier & Periph Dev Type */ - inqdata[1] = 0; - /* rem media bit & Dev Type Modifier */ - inqdata[2] = 0; - /* ISO, ECMA, & ANSI versions */ - inqdata[4] = 31; - /* length of additional data */ - strncpy(&inqdata[8], "Areca ", 8); - /* Vendor Identification */ - strncpy(&inqdata[16], "RAID controller ", 16); - /* Product Identification */ - strncpy(&inqdata[32], "R001", 4); /* Product Revision */ - - sg = scsi_sglist(cmd); - buffer = kmap_atomic(sg_page(sg)) + sg->offset; - - memcpy(buffer, inqdata, sizeof(inqdata)); - sg = scsi_sglist(cmd); - kunmap_atomic(buffer - sg->offset); - - cmd->scsi_done(cmd); - } - break; - case WRITE_BUFFER: - case READ_BUFFER: { - if (arcmsr_iop_message_xfer(acb, cmd)) - cmd->result = (DID_ERROR << 16); - cmd->scsi_done(cmd); - } - break; - default: - cmd->scsi_done(cmd); - } -} - -static int arcmsr_queue_command_lck(struct scsi_cmnd *cmd, - void (* done)(struct scsi_cmnd *)) -{ - struct Scsi_Host *host = cmd->device->host; - struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct CommandControlBlock *ccb; - int target = cmd->device->id; - int lun = cmd->device->lun; - uint8_t scsicmd = cmd->cmnd[0]; - cmd->scsi_done = done; - cmd->host_scribble = NULL; - cmd->result = 0; - if ((scsicmd == SYNCHRONIZE_CACHE) ||(scsicmd == SEND_DIAGNOSTIC)){ - if(acb->devstate[target][lun] == ARECA_RAID_GONE) { - cmd->result = (DID_NO_CONNECT << 16); - } - cmd->scsi_done(cmd); - return 0; - } - if (target == 16) { - /* virtual device for iop message transfer */ - arcmsr_handle_virtual_command(acb, cmd); - return 0; - } - if (atomic_read(&acb->ccboutstandingcount) >= - ARCMSR_MAX_OUTSTANDING_CMD) - return SCSI_MLQUEUE_HOST_BUSY; - ccb = arcmsr_get_freeccb(acb); - if (!ccb) - return SCSI_MLQUEUE_HOST_BUSY; - if (arcmsr_build_ccb( acb, ccb, cmd ) == FAILED) { - cmd->result = (DID_ERROR << 16) | (RESERVATION_CONFLICT << 1); - cmd->scsi_done(cmd); - return 0; - } - arcmsr_post_ccb(acb, ccb); - return 0; -} - -static DEF_SCSI_QCMD(arcmsr_queue_command) - -static bool arcmsr_get_hba_config(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - char *acb_firm_model = acb->firm_model; - char *acb_firm_version = acb->firm_version; - char *acb_device_map = acb->device_map; - char __iomem *iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]); - char __iomem *iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]); - char __iomem *iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); - int count; - writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ - miscellaneous data' timeout \n", acb->host->host_no); - return false; - } - count = 8; - while (count){ - *acb_firm_model = readb(iop_firm_model); - acb_firm_model++; - iop_firm_model++; - count--; - } - - count = 16; - while (count){ - *acb_firm_version = readb(iop_firm_version); - acb_firm_version++; - iop_firm_version++; - count--; - } - - count=16; - while(count){ - *acb_device_map = readb(iop_device_map); - acb_device_map++; - iop_device_map++; - count--; - } - printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", - acb->host->host_no, - acb->firm_version, - acb->firm_model); - acb->signature = readl(®->message_rwbuffer[0]); - acb->firm_request_len = readl(®->message_rwbuffer[1]); - acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); - acb->firm_sdram_size = readl(®->message_rwbuffer[3]); - acb->firm_hd_channels = readl(®->message_rwbuffer[4]); - acb->firm_cfg_version = readl(®->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ - return true; -} -static bool arcmsr_get_hbb_config(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - struct pci_dev *pdev = acb->pdev; - void *dma_coherent; - dma_addr_t dma_coherent_handle; - char *acb_firm_model = acb->firm_model; - char *acb_firm_version = acb->firm_version; - char *acb_device_map = acb->device_map; - char __iomem *iop_firm_model; - /*firm_model,15,60-67*/ - char __iomem *iop_firm_version; - /*firm_version,17,68-83*/ - char __iomem *iop_device_map; - /*firm_version,21,84-99*/ - int count; - dma_coherent = dma_alloc_coherent(&pdev->dev, sizeof(struct MessageUnit_B), &dma_coherent_handle, GFP_KERNEL); - if (!dma_coherent){ - printk(KERN_NOTICE "arcmsr%d: dma_alloc_coherent got error for hbb mu\n", acb->host->host_no); - return false; - } - acb->dma_coherent_handle_hbb_mu = dma_coherent_handle; - reg = (struct MessageUnit_B *)dma_coherent; - acb->pmuB = reg; - reg->drv2iop_doorbell= (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL); - reg->drv2iop_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_DRV2IOP_DOORBELL_MASK); - reg->iop2drv_doorbell = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL); - reg->iop2drv_doorbell_mask = (uint32_t __iomem *)((unsigned long)acb->mem_base0 + ARCMSR_IOP2DRV_DOORBELL_MASK); - reg->message_wbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_WBUFFER); - reg->message_rbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RBUFFER); - reg->message_rwbuffer = (uint32_t __iomem *)((unsigned long)acb->mem_base1 + ARCMSR_MESSAGE_RWBUFFER); - iop_firm_model = (char __iomem *)(®->message_rwbuffer[15]); /*firm_model,15,60-67*/ - iop_firm_version = (char __iomem *)(®->message_rwbuffer[17]); /*firm_version,17,68-83*/ - iop_device_map = (char __iomem *)(®->message_rwbuffer[21]); /*firm_version,21,84-99*/ - - writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ - miscellaneous data' timeout \n", acb->host->host_no); - return false; - } - count = 8; - while (count){ - *acb_firm_model = readb(iop_firm_model); - acb_firm_model++; - iop_firm_model++; - count--; - } - count = 16; - while (count){ - *acb_firm_version = readb(iop_firm_version); - acb_firm_version++; - iop_firm_version++; - count--; - } - - count = 16; - while(count){ - *acb_device_map = readb(iop_device_map); - acb_device_map++; - iop_device_map++; - count--; - } - - printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", - acb->host->host_no, - acb->firm_version, - acb->firm_model); - - acb->signature = readl(®->message_rwbuffer[1]); - /*firm_signature,1,00-03*/ - acb->firm_request_len = readl(®->message_rwbuffer[2]); - /*firm_request_len,1,04-07*/ - acb->firm_numbers_queue = readl(®->message_rwbuffer[3]); - /*firm_numbers_queue,2,08-11*/ - acb->firm_sdram_size = readl(®->message_rwbuffer[4]); - /*firm_sdram_size,3,12-15*/ - acb->firm_hd_channels = readl(®->message_rwbuffer[5]); - /*firm_ide_channels,4,16-19*/ - acb->firm_cfg_version = readl(®->message_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ - /*firm_ide_channels,4,16-19*/ - return true; -} - -static bool arcmsr_get_hbc_config(struct AdapterControlBlock *pACB) -{ - uint32_t intmask_org, Index, firmware_state = 0; - struct MessageUnit_C *reg = pACB->pmuC; - char *acb_firm_model = pACB->firm_model; - char *acb_firm_version = pACB->firm_version; - char *iop_firm_model = (char *)(®->msgcode_rwbuffer[15]); /*firm_model,15,60-67*/ - char *iop_firm_version = (char *)(®->msgcode_rwbuffer[17]); /*firm_version,17,68-83*/ - int count; - /* disable all outbound interrupt */ - intmask_org = readl(®->host_int_mask); /* disable outbound message0 int */ - writel(intmask_org|ARCMSR_HBCMU_ALL_INTMASKENABLE, ®->host_int_mask); - /* wait firmware ready */ - do { - firmware_state = readl(®->outbound_msgaddr1); - } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); - /* post "get config" instruction */ - writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - /* wait message ready */ - for (Index = 0; Index < 2000; Index++) { - if (readl(®->outbound_doorbell) & ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE) { - writel(ARCMSR_HBCMU_IOP2DRV_MESSAGE_CMD_DONE_DOORBELL_CLEAR, ®->outbound_doorbell_clear);/*clear interrupt*/ - break; - } - udelay(10); - } /*max 1 seconds*/ - if (Index >= 2000) { - printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ - miscellaneous data' timeout \n", pACB->host->host_no); - return false; - } - count = 8; - while (count) { - *acb_firm_model = readb(iop_firm_model); - acb_firm_model++; - iop_firm_model++; - count--; - } - count = 16; - while (count) { - *acb_firm_version = readb(iop_firm_version); - acb_firm_version++; - iop_firm_version++; - count--; - } - printk(KERN_NOTICE "Areca RAID Controller%d: F/W %s & Model %s\n", - pACB->host->host_no, - pACB->firm_version, - pACB->firm_model); - pACB->firm_request_len = readl(®->msgcode_rwbuffer[1]); /*firm_request_len,1,04-07*/ - pACB->firm_numbers_queue = readl(®->msgcode_rwbuffer[2]); /*firm_numbers_queue,2,08-11*/ - pACB->firm_sdram_size = readl(®->msgcode_rwbuffer[3]); /*firm_sdram_size,3,12-15*/ - pACB->firm_hd_channels = readl(®->msgcode_rwbuffer[4]); /*firm_ide_channels,4,16-19*/ - pACB->firm_cfg_version = readl(®->msgcode_rwbuffer[25]); /*firm_cfg_version,25,100-103*/ - /*all interrupt service will be enable at arcmsr_iop_init*/ - return true; -} -static bool arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) -{ - if (acb->adapter_type == ACB_ADAPTER_TYPE_A) - return arcmsr_get_hba_config(acb); - else if (acb->adapter_type == ACB_ADAPTER_TYPE_B) - return arcmsr_get_hbb_config(acb); - else - return arcmsr_get_hbc_config(acb); -} - -static int arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, - struct CommandControlBlock *poll_ccb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - struct CommandControlBlock *ccb; - struct ARCMSR_CDB *arcmsr_cdb; - uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; - int rtn; - bool error; - polling_hba_ccb_retry: - poll_count++; - outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ - while (1) { - if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { - if (poll_ccb_done){ - rtn = SUCCESS; - break; - }else { - msleep(25); - if (poll_count > 100){ - rtn = FAILED; - break; - } - goto polling_hba_ccb_retry; - } - } - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); - ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - poll_ccb_done = (ccb == poll_ccb) ? 1:0; - if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { - printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" - " poll command abort successfully \n" - , acb->host->host_no - , ccb->pcmd->device->id - , ccb->pcmd->device->lun - , ccb); - ccb->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(ccb); - continue; - } - printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" - " command done ccb = '0x%p'" - "ccboutstandingcount = %d \n" - , acb->host->host_no - , ccb - , atomic_read(&acb->ccboutstandingcount)); - continue; - } - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; - arcmsr_report_ccb_state(acb, ccb, error); - } - return rtn; -} - -static int arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, - struct CommandControlBlock *poll_ccb) -{ - struct MessageUnit_B *reg = acb->pmuB; - struct ARCMSR_CDB *arcmsr_cdb; - struct CommandControlBlock *ccb; - uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; - int index, rtn; - bool error; - polling_hbb_ccb_retry: - - poll_count++; - /* clear doorbell interrupt */ - writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); - while(1){ - index = reg->doneq_index; - if ((flag_ccb = readl(®->done_qbuffer[index])) == 0) { - if (poll_ccb_done){ - rtn = SUCCESS; - break; - }else { - msleep(25); - if (poll_count > 100){ - rtn = FAILED; - break; - } - goto polling_hbb_ccb_retry; - } - } - writel(0, ®->done_qbuffer[index]); - index++; - /*if last index number set it to 0 */ - index %= ARCMSR_MAX_HBB_POSTQUEUE; - reg->doneq_index = index; - /* check if command done with no error*/ - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + (flag_ccb << 5)); - ccb = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - poll_ccb_done = (ccb == poll_ccb) ? 1:0; - if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { - printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" - " poll command abort successfully \n" - ,acb->host->host_no - ,ccb->pcmd->device->id - ,ccb->pcmd->device->lun - ,ccb); - ccb->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(ccb); - continue; - } - printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" - " command done ccb = '0x%p'" - "ccboutstandingcount = %d \n" - , acb->host->host_no - , ccb - , atomic_read(&acb->ccboutstandingcount)); - continue; - } - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE0) ? true : false; - arcmsr_report_ccb_state(acb, ccb, error); - } - return rtn; -} - -static int arcmsr_polling_hbc_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) -{ - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - uint32_t flag_ccb, ccb_cdb_phy; - struct ARCMSR_CDB *arcmsr_cdb; - bool error; - struct CommandControlBlock *pCCB; - uint32_t poll_ccb_done = 0, poll_count = 0; - int rtn; -polling_hbc_ccb_retry: - poll_count++; - while (1) { - if ((readl(®->host_int_status) & ARCMSR_HBCMU_OUTBOUND_POSTQUEUE_ISR) == 0) { - if (poll_ccb_done) { - rtn = SUCCESS; - break; - } else { - msleep(25); - if (poll_count > 100) { - rtn = FAILED; - break; - } - goto polling_hbc_ccb_retry; - } - } - flag_ccb = readl(®->outbound_queueport_low); - ccb_cdb_phy = (flag_ccb & 0xFFFFFFF0); - arcmsr_cdb = (struct ARCMSR_CDB *)(acb->vir2phy_offset + ccb_cdb_phy);/*frame must be 32 bytes aligned*/ - pCCB = container_of(arcmsr_cdb, struct CommandControlBlock, arcmsr_cdb); - poll_ccb_done = (pCCB == poll_ccb) ? 1 : 0; - /* check ifcommand done with no error*/ - if ((pCCB->acb != acb) || (pCCB->startdone != ARCMSR_CCB_START)) { - if (pCCB->startdone == ARCMSR_CCB_ABORTED) { - printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" - " poll command abort successfully \n" - , acb->host->host_no - , pCCB->pcmd->device->id - , pCCB->pcmd->device->lun - , pCCB); - pCCB->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); - continue; - } - printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" - " command done ccb = '0x%p'" - "ccboutstandingcount = %d \n" - , acb->host->host_no - , pCCB - , atomic_read(&acb->ccboutstandingcount)); - continue; - } - error = (flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR_MODE1) ? true : false; - arcmsr_report_ccb_state(acb, pCCB, error); - } - return rtn; -} -static int arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, - struct CommandControlBlock *poll_ccb) -{ - int rtn = 0; - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - rtn = arcmsr_polling_hba_ccbdone(acb, poll_ccb); - } - break; - - case ACB_ADAPTER_TYPE_B: { - rtn = arcmsr_polling_hbb_ccbdone(acb, poll_ccb); - } - break; - case ACB_ADAPTER_TYPE_C: { - rtn = arcmsr_polling_hbc_ccbdone(acb, poll_ccb); - } - } - return rtn; -} - -static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) -{ - uint32_t cdb_phyaddr, cdb_phyaddr_hi32; - dma_addr_t dma_coherent_handle; - /* - ******************************************************************** - ** here we need to tell iop 331 our freeccb.HighPart - ** if freeccb.HighPart is not zero - ******************************************************************** - */ - dma_coherent_handle = acb->dma_coherent_handle; - cdb_phyaddr = (uint32_t)(dma_coherent_handle); - cdb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16); - acb->cdb_phyaddr_hi32 = cdb_phyaddr_hi32; - /* - *********************************************************************** - ** if adapter type B, set window of "post command Q" - *********************************************************************** - */ - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - if (cdb_phyaddr_hi32 != 0) { - struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t intmask_org; - intmask_org = arcmsr_disable_outbound_ints(acb); - writel(ARCMSR_SIGNATURE_SET_CONFIG, \ - ®->message_rwbuffer[0]); - writel(cdb_phyaddr_hi32, ®->message_rwbuffer[1]); - writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \ - ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: ""set ccb high \ - part physical address timeout\n", - acb->host->host_no); - return 1; - } - arcmsr_enable_outbound_ints(acb, intmask_org); - } - } - break; - - case ACB_ADAPTER_TYPE_B: { - unsigned long post_queue_phyaddr; - uint32_t __iomem *rwbuffer; - - struct MessageUnit_B *reg = acb->pmuB; - uint32_t intmask_org; - intmask_org = arcmsr_disable_outbound_ints(acb); - reg->postq_index = 0; - reg->doneq_index = 0; - writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \ - acb->host->host_no); - return 1; - } - post_queue_phyaddr = acb->dma_coherent_handle_hbb_mu; - rwbuffer = reg->message_rwbuffer; - /* driver "set config" signature */ - writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); - /* normal should be zero */ - writel(cdb_phyaddr_hi32, rwbuffer++); - /* postQ size (256 + 8)*4 */ - writel(post_queue_phyaddr, rwbuffer++); - /* doneQ size (256 + 8)*4 */ - writel(post_queue_phyaddr + 1056, rwbuffer++); - /* ccb maxQ size must be --> [(256 + 8)*4]*/ - writel(1056, rwbuffer); - - writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ - timeout \n",acb->host->host_no); - return 1; - } - arcmsr_hbb_enable_driver_mode(acb); - arcmsr_enable_outbound_ints(acb, intmask_org); - } - break; - case ACB_ADAPTER_TYPE_C: { - if (cdb_phyaddr_hi32 != 0) { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - - printk(KERN_NOTICE "arcmsr%d: cdb_phyaddr_hi32=0x%x\n", - acb->adapter_index, cdb_phyaddr_hi32); - writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->msgcode_rwbuffer[0]); - writel(cdb_phyaddr_hi32, ®->msgcode_rwbuffer[1]); - writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); - writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - if (!arcmsr_hbc_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ - timeout \n", acb->host->host_no); - return 1; - } - } - } - } - return 0; -} - -static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) -{ - uint32_t firmware_state = 0; - switch (acb->adapter_type) { - - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - do { - firmware_state = readl(®->outbound_msgaddr1); - } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0); - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - do { - firmware_state = readl(reg->iop2drv_doorbell); - } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); - writel(ARCMSR_DRV2IOP_END_OF_INTERRUPT, reg->drv2iop_doorbell); - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - do { - firmware_state = readl(®->outbound_msgaddr1); - } while ((firmware_state & ARCMSR_HBCMU_MESSAGE_FIRMWARE_OK) == 0); - } - } -} - -static void arcmsr_request_hba_device_map(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - return; - } else { - acb->fw_flag = FW_NORMAL; - if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)){ - atomic_set(&acb->rq_map_token, 16); - } - atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); - if (atomic_dec_and_test(&acb->rq_map_token)) { - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - return; - } - writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - } - return; -} - -static void arcmsr_request_hbb_device_map(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B __iomem *reg = acb->pmuB; - if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0 ) || ((acb->acb_flags & ACB_F_ABORT) != 0 )){ - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - return; - } else { - acb->fw_flag = FW_NORMAL; - if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { - atomic_set(&acb->rq_map_token, 16); - } - atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); - if (atomic_dec_and_test(&acb->rq_map_token)) { - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - return; - } - writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell); - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - } - return; -} - -static void arcmsr_request_hbc_device_map(struct AdapterControlBlock *acb) -{ - struct MessageUnit_C __iomem *reg = acb->pmuC; - if (unlikely(atomic_read(&acb->rq_map_token) == 0) || ((acb->acb_flags & ACB_F_BUS_RESET) != 0) || ((acb->acb_flags & ACB_F_ABORT) != 0)) { - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - return; - } else { - acb->fw_flag = FW_NORMAL; - if (atomic_read(&acb->ante_token_value) == atomic_read(&acb->rq_map_token)) { - atomic_set(&acb->rq_map_token, 16); - } - atomic_set(&acb->ante_token_value, atomic_read(&acb->rq_map_token)); - if (atomic_dec_and_test(&acb->rq_map_token)) { - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - return; - } - writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, ®->inbound_doorbell); - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - } - return; -} - -static void arcmsr_request_device_map(unsigned long pacb) -{ - struct AdapterControlBlock *acb = (struct AdapterControlBlock *)pacb; - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - arcmsr_request_hba_device_map(acb); - } - break; - case ACB_ADAPTER_TYPE_B: { - arcmsr_request_hbb_device_map(acb); - } - break; - case ACB_ADAPTER_TYPE_C: { - arcmsr_request_hbc_device_map(acb); - } - } -} - -static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb) -{ - struct MessageUnit_A __iomem *reg = acb->pmuA; - acb->acb_flags |= ACB_F_MSG_START_BGRB; - writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); - if (!arcmsr_hba_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ - rebulid' timeout \n", acb->host->host_no); - } -} - -static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) -{ - struct MessageUnit_B *reg = acb->pmuB; - acb->acb_flags |= ACB_F_MSG_START_BGRB; - writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ - rebulid' timeout \n",acb->host->host_no); - } -} - -static void arcmsr_start_hbc_bgrb(struct AdapterControlBlock *pACB) -{ - struct MessageUnit_C *phbcmu = (struct MessageUnit_C *)pACB->pmuC; - pACB->acb_flags |= ACB_F_MSG_START_BGRB; - writel(ARCMSR_INBOUND_MESG0_START_BGRB, &phbcmu->inbound_msgaddr0); - writel(ARCMSR_HBCMU_DRV2IOP_MESSAGE_CMD_DONE, &phbcmu->inbound_doorbell); - if (!arcmsr_hbc_wait_msgint_ready(pACB)) { - printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ - rebulid' timeout \n", pACB->host->host_no); - } - return; -} -static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: - arcmsr_start_hba_bgrb(acb); - break; - case ACB_ADAPTER_TYPE_B: - arcmsr_start_hbb_bgrb(acb); - break; - case ACB_ADAPTER_TYPE_C: - arcmsr_start_hbc_bgrb(acb); - } -} - -static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: { - struct MessageUnit_A __iomem *reg = acb->pmuA; - uint32_t outbound_doorbell; - /* empty doorbell Qbuffer if door bell ringed */ - outbound_doorbell = readl(®->outbound_doorbell); - /*clear doorbell interrupt */ - writel(outbound_doorbell, ®->outbound_doorbell); - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); - } - break; - - case ACB_ADAPTER_TYPE_B: { - struct MessageUnit_B *reg = acb->pmuB; - /*clear interrupt and message state*/ - writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell); - writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell); - /* let IOP know data has been read */ - } - break; - case ACB_ADAPTER_TYPE_C: { - struct MessageUnit_C *reg = (struct MessageUnit_C *)acb->pmuC; - uint32_t outbound_doorbell; - /* empty doorbell Qbuffer if door bell ringed */ - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell_clear); - writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); - } - } -} - -static void arcmsr_enable_eoi_mode(struct AdapterControlBlock *acb) -{ - switch (acb->adapter_type) { - case ACB_ADAPTER_TYPE_A: - return; - case ACB_ADAPTER_TYPE_B: - { - struct MessageUnit_B *reg = acb->pmuB; - writel(ARCMSR_MESSAGE_ACTIVE_EOI_MODE, reg->drv2iop_doorbell); - if (!arcmsr_hbb_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "ARCMSR IOP enables EOI_MODE TIMEOUT"); - return; - } - } - break; - case ACB_ADAPTER_TYPE_C: - return; - } - return; -} - -static void arcmsr_hardware_reset(struct AdapterControlBlock *acb) -{ - uint8_t value[64]; - int i, count = 0; - struct MessageUnit_A __iomem *pmuA = acb->pmuA; - struct MessageUnit_C __iomem *pmuC = acb->pmuC; - u32 temp = 0; - /* backup pci config data */ - printk(KERN_NOTICE "arcmsr%d: executing hw bus reset .....\n", acb->host->host_no); - for (i = 0; i < 64; i++) { - pci_read_config_byte(acb->pdev, i, &value[i]); - } - /* hardware reset signal */ - if ((acb->dev_id == 0x1680)) { - writel(ARCMSR_ARC1680_BUS_RESET, &pmuA->reserved1[0]); - } else if ((acb->dev_id == 0x1880)) { - do { - count++; - writel(0xF, &pmuC->write_sequence); - writel(0x4, &pmuC->write_sequence); - writel(0xB, &pmuC->write_sequence); - writel(0x2, &pmuC->write_sequence); - writel(0x7, &pmuC->write_sequence); - writel(0xD, &pmuC->write_sequence); - } while ((((temp = readl(&pmuC->host_diagnostic)) | ARCMSR_ARC1880_DiagWrite_ENABLE) == 0) && (count < 5)); - writel(ARCMSR_ARC1880_RESET_ADAPTER, &pmuC->host_diagnostic); - } else { - pci_write_config_byte(acb->pdev, 0x84, 0x20); - } - msleep(2000); - /* write back pci config data */ - for (i = 0; i < 64; i++) { - pci_write_config_byte(acb->pdev, i, value[i]); - } - msleep(1000); - return; -} -static void arcmsr_iop_init(struct AdapterControlBlock *acb) -{ - uint32_t intmask_org; - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); - arcmsr_wait_firmware_ready(acb); - arcmsr_iop_confirm(acb); - /*start background rebuild*/ - arcmsr_start_adapter_bgrb(acb); - /* empty doorbell Qbuffer if door bell ringed */ - arcmsr_clear_doorbell_queue_buffer(acb); - arcmsr_enable_eoi_mode(acb); - /* enable outbound Post Queue,outbound doorbell Interrupt */ - arcmsr_enable_outbound_ints(acb, intmask_org); - acb->acb_flags |= ACB_F_IOP_INITED; -} - -static uint8_t arcmsr_iop_reset(struct AdapterControlBlock *acb) -{ - struct CommandControlBlock *ccb; - uint32_t intmask_org; - uint8_t rtnval = 0x00; - int i = 0; - unsigned long flags; - - if (atomic_read(&acb->ccboutstandingcount) != 0) { - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); - /* talk to iop 331 outstanding command aborted */ - rtnval = arcmsr_abort_allcmd(acb); - /* clear all outbound posted Q */ - arcmsr_done4abort_postqueue(acb); - for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - ccb = acb->pccb_pool[i]; - if (ccb->startdone == ARCMSR_CCB_START) { - scsi_dma_unmap(ccb->pcmd); - ccb->startdone = ARCMSR_CCB_DONE; - ccb->ccb_flags = 0; - spin_lock_irqsave(&acb->ccblist_lock, flags); - list_add_tail(&ccb->list, &acb->ccb_free_list); - spin_unlock_irqrestore(&acb->ccblist_lock, flags); - } - } - atomic_set(&acb->ccboutstandingcount, 0); - /* enable all outbound interrupt */ - arcmsr_enable_outbound_ints(acb, intmask_org); - return rtnval; - } - return rtnval; -} - -static int arcmsr_bus_reset(struct scsi_cmnd *cmd) -{ - struct AdapterControlBlock *acb; - uint32_t intmask_org, outbound_doorbell; - int retry_count = 0; - int rtn = FAILED; - acb = (struct AdapterControlBlock *) cmd->device->host->hostdata; - printk(KERN_ERR "arcmsr: executing bus reset eh.....num_resets = %d, num_aborts = %d \n", acb->num_resets, acb->num_aborts); - acb->num_resets++; - - switch(acb->adapter_type){ - case ACB_ADAPTER_TYPE_A:{ - if (acb->acb_flags & ACB_F_BUS_RESET){ - long timeout; - printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n"); - timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); - if (timeout) { - return SUCCESS; - } - } - acb->acb_flags |= ACB_F_BUS_RESET; - if (!arcmsr_iop_reset(acb)) { - struct MessageUnit_A __iomem *reg; - reg = acb->pmuA; - arcmsr_hardware_reset(acb); - acb->acb_flags &= ~ACB_F_IOP_INITED; -sleep_again: - ssleep(ARCMSR_SLEEPTIME); - if ((readl(®->outbound_msgaddr1) & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0) { - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count); - if (retry_count > ARCMSR_RETRYCOUNT) { - acb->fw_flag = FW_DEADLOCK; - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no); - return FAILED; - } - retry_count++; - goto sleep_again; - } - acb->acb_flags |= ACB_F_IOP_INITED; - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); - arcmsr_get_firmware_spec(acb); - arcmsr_start_adapter_bgrb(acb); - /* clear Qbuffer if door bell ringed */ - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell); /*clear interrupt */ - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); - /* enable outbound Post Queue,outbound doorbell Interrupt */ - arcmsr_enable_outbound_ints(acb, intmask_org); - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - acb->acb_flags &= ~ACB_F_BUS_RESET; - rtn = SUCCESS; - printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); - } else { - acb->acb_flags &= ~ACB_F_BUS_RESET; - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); - rtn = SUCCESS; - } - break; - } - case ACB_ADAPTER_TYPE_B:{ - acb->acb_flags |= ACB_F_BUS_RESET; - if (!arcmsr_iop_reset(acb)) { - acb->acb_flags &= ~ACB_F_BUS_RESET; - rtn = FAILED; - } else { - acb->acb_flags &= ~ACB_F_BUS_RESET; - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - rtn = SUCCESS; - } - break; - } - case ACB_ADAPTER_TYPE_C:{ - if (acb->acb_flags & ACB_F_BUS_RESET) { - long timeout; - printk(KERN_ERR "arcmsr: there is an bus reset eh proceeding.......\n"); - timeout = wait_event_timeout(wait_q, (acb->acb_flags & ACB_F_BUS_RESET) == 0, 220*HZ); - if (timeout) { - return SUCCESS; - } - } - acb->acb_flags |= ACB_F_BUS_RESET; - if (!arcmsr_iop_reset(acb)) { - struct MessageUnit_C __iomem *reg; - reg = acb->pmuC; - arcmsr_hardware_reset(acb); - acb->acb_flags &= ~ACB_F_IOP_INITED; -sleep: - ssleep(ARCMSR_SLEEPTIME); - if ((readl(®->host_diagnostic) & 0x04) != 0) { - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, retry=%d\n", acb->host->host_no, retry_count); - if (retry_count > ARCMSR_RETRYCOUNT) { - acb->fw_flag = FW_DEADLOCK; - printk(KERN_ERR "arcmsr%d: waiting for hw bus reset return, RETRY TERMINATED!!\n", acb->host->host_no); - return FAILED; - } - retry_count++; - goto sleep; - } - acb->acb_flags |= ACB_F_IOP_INITED; - /* disable all outbound interrupt */ - intmask_org = arcmsr_disable_outbound_ints(acb); - arcmsr_get_firmware_spec(acb); - arcmsr_start_adapter_bgrb(acb); - /* clear Qbuffer if door bell ringed */ - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell_clear); /*clear interrupt */ - writel(ARCMSR_HBCMU_DRV2IOP_DATA_READ_OK, ®->inbound_doorbell); - /* enable outbound Post Queue,outbound doorbell Interrupt */ - arcmsr_enable_outbound_ints(acb, intmask_org); - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6 * HZ)); - acb->acb_flags &= ~ACB_F_BUS_RESET; - rtn = SUCCESS; - printk(KERN_ERR "arcmsr: scsi bus reset eh returns with success\n"); - } else { - acb->acb_flags &= ~ACB_F_BUS_RESET; - atomic_set(&acb->rq_map_token, 16); - atomic_set(&acb->ante_token_value, 16); - acb->fw_flag = FW_NORMAL; - mod_timer(&acb->eternal_timer, jiffies + msecs_to_jiffies(6*HZ)); - rtn = SUCCESS; - } - break; - } - } - return rtn; -} - -static int arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, - struct CommandControlBlock *ccb) -{ - int rtn; - rtn = arcmsr_polling_ccbdone(acb, ccb); - return rtn; -} - -static int arcmsr_abort(struct scsi_cmnd *cmd) -{ - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *)cmd->device->host->hostdata; - int i = 0; - int rtn = FAILED; - printk(KERN_NOTICE - "arcmsr%d: abort device command of scsi id = %d lun = %d \n", - acb->host->host_no, cmd->device->id, cmd->device->lun); - acb->acb_flags |= ACB_F_ABORT; - acb->num_aborts++; - /* - ************************************************ - ** the all interrupt service routine is locked - ** we need to handle it as soon as possible and exit - ************************************************ - */ - if (!atomic_read(&acb->ccboutstandingcount)) - return rtn; - - for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - struct CommandControlBlock *ccb = acb->pccb_pool[i]; - if (ccb->startdone == ARCMSR_CCB_START && ccb->pcmd == cmd) { - ccb->startdone = ARCMSR_CCB_ABORTED; - rtn = arcmsr_abort_one_cmd(acb, ccb); - break; - } - } - acb->acb_flags &= ~ACB_F_ABORT; - return rtn; -} - -static const char *arcmsr_info(struct Scsi_Host *host) -{ - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; - static char buf[256]; - char *type; - int raid6 = 1; - switch (acb->pdev->device) { - case PCI_DEVICE_ID_ARECA_1110: - case PCI_DEVICE_ID_ARECA_1200: - case PCI_DEVICE_ID_ARECA_1202: - case PCI_DEVICE_ID_ARECA_1210: - raid6 = 0; - /*FALLTHRU*/ - case PCI_DEVICE_ID_ARECA_1120: - case PCI_DEVICE_ID_ARECA_1130: - case PCI_DEVICE_ID_ARECA_1160: - case PCI_DEVICE_ID_ARECA_1170: - case PCI_DEVICE_ID_ARECA_1201: - case PCI_DEVICE_ID_ARECA_1220: - case PCI_DEVICE_ID_ARECA_1230: - case PCI_DEVICE_ID_ARECA_1260: - case PCI_DEVICE_ID_ARECA_1270: - case PCI_DEVICE_ID_ARECA_1280: - type = "SATA"; - break; - case PCI_DEVICE_ID_ARECA_1380: - case PCI_DEVICE_ID_ARECA_1381: - case PCI_DEVICE_ID_ARECA_1680: - case PCI_DEVICE_ID_ARECA_1681: - case PCI_DEVICE_ID_ARECA_1880: - type = "SAS"; - break; - default: - type = "X-TYPE"; - break; - } - sprintf(buf, "Areca %s Host Adapter RAID Controller%s\n %s", - type, raid6 ? "( RAID6 capable)" : "", - ARCMSR_DRIVER_VERSION); - return buf; -} diff --git a/ANDROID_3.4.5/drivers/scsi/arm/Kconfig b/ANDROID_3.4.5/drivers/scsi/arm/Kconfig deleted file mode 100644 index a8587f1f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/Kconfig +++ /dev/null @@ -1,84 +0,0 @@ -# -# SCSI driver configuration for Acorn -# -config SCSI_ACORNSCSI_3 - tristate "Acorn SCSI card (aka30) support" - depends on ARCH_ACORN && SCSI - select SCSI_SPI_ATTRS - help - This enables support for the Acorn SCSI card (aka30). If you have an - Acorn system with one of these, say Y. If unsure, say N. - -config SCSI_ACORNSCSI_TAGGED_QUEUE - bool "Support SCSI 2 Tagged queueing" - depends on SCSI_ACORNSCSI_3 - help - Say Y here to enable tagged queuing support on the Acorn SCSI card. - - This is a feature of SCSI-2 which improves performance: the host - adapter can send several SCSI commands to a device's queue even if - previous commands haven't finished yet. Some SCSI devices don't - implement this properly, so the safe answer is N. - -config SCSI_ACORNSCSI_SYNC - bool "Support SCSI 2 Synchronous Transfers" - depends on SCSI_ACORNSCSI_3 - help - Say Y here to enable synchronous transfer negotiation with all - targets on the Acorn SCSI card. - - In general, this improves performance; however some SCSI devices - don't implement it properly, so the safe answer is N. - -config SCSI_ARXESCSI - tristate "ARXE SCSI support" - depends on ARCH_ACORN && SCSI - help - Around 1991, Arxe Systems Limited released a high density floppy - disc interface for the Acorn Archimedes range, to allow the use of - HD discs from the then new A5000 on earlier models. This interface - was either sold on its own or with an integral SCSI controller. - Technical details on this NCR53c94-based device are available at - - Say Y here to compile in support for the SCSI controller. - -config SCSI_CUMANA_2 - tristate "CumanaSCSI II support" - depends on ARCH_ACORN && SCSI - help - This enables support for the Cumana SCSI II card. If you have an - Acorn system with one of these, say Y. If unsure, say N. - -config SCSI_EESOXSCSI - tristate "EESOX support" - depends on ARCH_ACORN && SCSI - help - This enables support for the EESOX SCSI card. If you have an Acorn - system with one of these, say Y, otherwise say N. - -config SCSI_POWERTECSCSI - tristate "PowerTec support" - depends on ARCH_ACORN && SCSI - help - This enables support for the Powertec SCSI card on Acorn systems. If - you have one of these, say Y. If unsure, say N. - -comment "The following drivers are not fully supported" - depends on ARCH_ACORN && EXPERIMENTAL - -config SCSI_CUMANA_1 - tristate "CumanaSCSI I support (EXPERIMENTAL)" - depends on ARCH_ACORN && EXPERIMENTAL && SCSI - select SCSI_SPI_ATTRS - help - This enables support for the Cumana SCSI I card. If you have an - Acorn system with one of these, say Y. If unsure, say N. - -config SCSI_OAK1 - tristate "Oak SCSI support (EXPERIMENTAL)" - depends on ARCH_ACORN && EXPERIMENTAL && SCSI - select SCSI_SPI_ATTRS - help - This enables support for the Oak SCSI card. If you have an Acorn - system with one of these, say Y. If unsure, say N. - diff --git a/ANDROID_3.4.5/drivers/scsi/arm/Makefile b/ANDROID_3.4.5/drivers/scsi/arm/Makefile deleted file mode 100644 index 16c3e86a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# -# Makefile for drivers/scsi/arm -# - -acornscsi_mod-objs := acornscsi.o acornscsi-io.o - -obj-$(CONFIG_SCSI_ACORNSCSI_3) += acornscsi_mod.o queue.o msgqueue.o -obj-$(CONFIG_SCSI_ARXESCSI) += arxescsi.o fas216.o queue.o msgqueue.o -obj-$(CONFIG_SCSI_CUMANA_1) += cumana_1.o -obj-$(CONFIG_SCSI_CUMANA_2) += cumana_2.o fas216.o queue.o msgqueue.o -obj-$(CONFIG_SCSI_OAK1) += oak.o -obj-$(CONFIG_SCSI_POWERTECSCSI) += powertec.o fas216.o queue.o msgqueue.o -obj-$(CONFIG_SCSI_EESOXSCSI) += eesox.o fas216.o queue.o msgqueue.o diff --git a/ANDROID_3.4.5/drivers/scsi/arm/acornscsi-io.S b/ANDROID_3.4.5/drivers/scsi/arm/acornscsi-io.S deleted file mode 100644 index 22171b21..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/acornscsi-io.S +++ /dev/null @@ -1,138 +0,0 @@ -/* - * linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include - -#include -#include - -#if defined(__APCS_32__) -#define LOADREGS(t,r,l...) ldm##t r, l -#elif defined(__APCS_26__) -#define LOADREGS(t,r,l...) ldm##t r, l##^ -#endif - -@ Purpose: transfer a block of data from the acorn scsi card to memory -@ Proto : void acornscsi_in(unsigned int addr_start, char *buffer, int length) -@ Returns: nothing - - .align -ENTRY(__acornscsi_in) - stmfd sp!, {r4 - r7, lr} - bic r0, r0, #3 - mov lr, #0xff - orr lr, lr, #0xff00 -acornscsi_in16lp: - subs r2, r2, #16 - bmi acornscsi_in8 - ldmia r0!, {r3, r4, r5, r6} - and r3, r3, lr - orr r3, r3, r4, lsl #16 - and r4, r5, lr - orr r4, r4, r6, lsl #16 - ldmia r0!, {r5, r6, r7, ip} - and r5, r5, lr - orr r5, r5, r6, lsl #16 - and r6, r7, lr - orr r6, r6, ip, lsl #16 - stmia r1!, {r3 - r6} - bne acornscsi_in16lp - LOADREGS(fd, sp!, {r4 - r7, pc}) - -acornscsi_in8: adds r2, r2, #8 - bmi acornscsi_in4 - ldmia r0!, {r3, r4, r5, r6} - and r3, r3, lr - orr r3, r3, r4, lsl #16 - and r4, r5, lr - orr r4, r4, r6, lsl #16 - stmia r1!, {r3 - r4} - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r2, r2, #8 - -acornscsi_in4: adds r2, r2, #4 - bmi acornscsi_in2 - ldmia r0!, {r3, r4} - and r3, r3, lr - orr r3, r3, r4, lsl #16 - str r3, [r1], #4 - LOADREGS(eqfd, sp!, {r4 - r7, pc}) - sub r2, r2, #4 - -acornscsi_in2: adds r2, r2, #2 - ldr r3, [r0], #4 - and r3, r3, lr - strb r3, [r1], #1 - mov r3, r3, lsr #8 - strplb r3, [r1], #1 - LOADREGS(fd, sp!, {r4 - r7, pc}) - -@ Purpose: transfer a block of data from memory to the acorn scsi card -@ Proto : void acornscsi_in(unsigned int addr_start, char *buffer, int length) -@ Returns: nothing - -ENTRY(__acornscsi_out) - stmfd sp!, {r4 - r6, lr} - bic r0, r0, #3 -acornscsi_out16lp: - subs r2, r2, #16 - bmi acornscsi_out8 - ldmia r1!, {r4, r6, ip, lr} - mov r3, r4, lsl #16 - orr r3, r3, r3, lsr #16 - mov r4, r4, lsr #16 - orr r4, r4, r4, lsl #16 - mov r5, r6, lsl #16 - orr r5, r5, r5, lsr #16 - mov r6, r6, lsr #16 - orr r6, r6, r6, lsl #16 - stmia r0!, {r3, r4, r5, r6} - mov r3, ip, lsl #16 - orr r3, r3, r3, lsr #16 - mov r4, ip, lsr #16 - orr r4, r4, r4, lsl #16 - mov ip, lr, lsl #16 - orr ip, ip, ip, lsr #16 - mov lr, lr, lsr #16 - orr lr, lr, lr, lsl #16 - stmia r0!, {r3, r4, ip, lr} - bne acornscsi_out16lp - LOADREGS(fd, sp!, {r4 - r6, pc}) - -acornscsi_out8: adds r2, r2, #8 - bmi acornscsi_out4 - ldmia r1!, {r4, r6} - mov r3, r4, lsl #16 - orr r3, r3, r3, lsr #16 - mov r4, r4, lsr #16 - orr r4, r4, r4, lsl #16 - mov r5, r6, lsl #16 - orr r5, r5, r5, lsr #16 - mov r6, r6, lsr #16 - orr r6, r6, r6, lsl #16 - stmia r0!, {r3, r4, r5, r6} - LOADREGS(eqfd, sp!, {r4 - r6, pc}) - - sub r2, r2, #8 -acornscsi_out4: adds r2, r2, #4 - bmi acornscsi_out2 - ldr r4, [r1], #4 - mov r3, r4, lsl #16 - orr r3, r3, r3, lsr #16 - mov r4, r4, lsr #16 - orr r4, r4, r4, lsl #16 - stmia r0!, {r3, r4} - LOADREGS(eqfd, sp!, {r4 - r6, pc}) - - sub r2, r2, #4 -acornscsi_out2: adds r2, r2, #2 - ldr r3, [r1], #2 - strb r3, [r0], #1 - mov r3, r3, lsr #8 - strplb r3, [r0], #1 - LOADREGS(fd, sp!, {r4 - r6, pc}) - diff --git a/ANDROID_3.4.5/drivers/scsi/arm/acornscsi.c b/ANDROID_3.4.5/drivers/scsi/arm/acornscsi.c deleted file mode 100644 index b330438a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/acornscsi.c +++ /dev/null @@ -1,3088 +0,0 @@ -/* - * linux/drivers/acorn/scsi/acornscsi.c - * - * Acorn SCSI 3 driver - * By R.M.King. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Abandoned using the Select and Transfer command since there were - * some nasty races between our software and the target devices that - * were not easy to solve, and the device errata had a lot of entries - * for this command, some of them quite nasty... - * - * Changelog: - * 26-Sep-1997 RMK Re-jigged to use the queue module. - * Re-coded state machine to be based on driver - * state not scsi state. Should be easier to debug. - * Added acornscsi_release to clean up properly. - * Updated proc/scsi reporting. - * 05-Oct-1997 RMK Implemented writing to SCSI devices. - * 06-Oct-1997 RMK Corrected small (non-serious) bug with the connect/ - * reconnect race condition causing a warning message. - * 12-Oct-1997 RMK Added catch for re-entering interrupt routine. - * 15-Oct-1997 RMK Improved handling of commands. - * 27-Jun-1998 RMK Changed asm/delay.h to linux/delay.h. - * 13-Dec-1998 RMK Better abort code and command handling. Extra state - * transitions added to allow dodgy devices to work. - */ -#define DEBUG_NO_WRITE 1 -#define DEBUG_QUEUES 2 -#define DEBUG_DMA 4 -#define DEBUG_ABORT 8 -#define DEBUG_DISCON 16 -#define DEBUG_CONNECT 32 -#define DEBUG_PHASES 64 -#define DEBUG_WRITE 128 -#define DEBUG_LINK 256 -#define DEBUG_MESSAGES 512 -#define DEBUG_RESET 1024 -#define DEBUG_ALL (DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\ - DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\ - DEBUG_DMA|DEBUG_QUEUES) - -/* DRIVER CONFIGURATION - * - * SCSI-II Tagged queue support. - * - * I don't have any SCSI devices that support it, so it is totally untested - * (except to make sure that it doesn't interfere with any non-tagging - * devices). It is not fully implemented either - what happens when a - * tagging device reconnects??? - * - * You can tell if you have a device that supports tagged queueing my - * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported - * as '2 TAG'. - * - * Also note that CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE is normally set in the config - * scripts, but disabled here. Once debugged, remove the #undef, otherwise to debug, - * comment out the undef. - */ -#undef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE -/* - * SCSI-II Linked command support. - * - * The higher level code doesn't support linked commands yet, and so the option - * is undef'd here. - */ -#undef CONFIG_SCSI_ACORNSCSI_LINK -/* - * SCSI-II Synchronous transfer support. - * - * Tried and tested... - * - * SDTR_SIZE - maximum number of un-acknowledged bytes (0 = off, 12 = max) - * SDTR_PERIOD - period of REQ signal (min=125, max=1020) - * DEFAULT_PERIOD - default REQ period. - */ -#define SDTR_SIZE 12 -#define SDTR_PERIOD 125 -#define DEFAULT_PERIOD 500 - -/* - * Debugging information - * - * DEBUG - bit mask from list above - * DEBUG_TARGET - is defined to the target number if you want to debug - * a specific target. [only recon/write/dma]. - */ -#define DEBUG (DEBUG_RESET|DEBUG_WRITE|DEBUG_NO_WRITE) -/* only allow writing to SCSI device 0 */ -#define NO_WRITE 0xFE -/*#define DEBUG_TARGET 2*/ -/* - * Select timeout time (in 10ms units) - * - * This is the timeout used between the start of selection and the WD33C93 - * chip deciding that the device isn't responding. - */ -#define TIMEOUT_TIME 10 -/* - * Define this if you want to have verbose explanation of SCSI - * status/messages. - */ -#undef CONFIG_ACORNSCSI_CONSTANTS -/* - * Define this if you want to use the on board DMAC [don't remove this option] - * If not set, then use PIO mode (not currently supported). - */ -#define USE_DMAC - -/* - * ==================================================================================== - */ - -#ifdef DEBUG_TARGET -#define DBG(cmd,xxx...) \ - if (cmd->device->id == DEBUG_TARGET) { \ - xxx; \ - } -#else -#define DBG(cmd,xxx...) xxx -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "../scsi.h" -#include -#include -#include -#include "acornscsi.h" -#include "msgqueue.h" -#include "scsi.h" - -#include - -#define VER_MAJOR 2 -#define VER_MINOR 0 -#define VER_PATCH 6 - -#ifndef ABORT_TAG -#define ABORT_TAG 0xd -#else -#error "Yippee! ABORT TAG is now defined! Remove this error!" -#endif - -#ifdef CONFIG_SCSI_ACORNSCSI_LINK -#error SCSI2 LINKed commands not supported (yet)! -#endif - -#ifdef USE_DMAC -/* - * DMAC setup parameters - */ -#define INIT_DEVCON0 (DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP) -#define INIT_DEVCON1 (DEVCON1_BHLD) -#define DMAC_READ (MODECON_READ) -#define DMAC_WRITE (MODECON_WRITE) -#define INIT_SBICDMA (CTRL_DMABURST) - -#define scsi_xferred have_data_in - -/* - * Size of on-board DMA buffer - */ -#define DMAC_BUFFER_SIZE 65536 -#endif - -#define STATUS_BUFFER_TO_PRINT 24 - -unsigned int sdtr_period = SDTR_PERIOD; -unsigned int sdtr_size = SDTR_SIZE; - -static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, - unsigned int result); -static int acornscsi_reconnect_finish(AS_Host *host); -static void acornscsi_dma_cleanup(AS_Host *host); -static void acornscsi_abortcmd(AS_Host *host, unsigned char tag); - -/* ==================================================================================== - * Miscellaneous - */ - -/* Offsets from MEMC base */ -#define SBIC_REGIDX 0x2000 -#define SBIC_REGVAL 0x2004 -#define DMAC_OFFSET 0x3000 - -/* Offsets from FAST IOC base */ -#define INT_REG 0x2000 -#define PAGE_REG 0x3000 - -static inline void sbic_arm_write(AS_Host *host, unsigned int reg, unsigned int value) -{ - writeb(reg, host->base + SBIC_REGIDX); - writeb(value, host->base + SBIC_REGVAL); -} - -static inline int sbic_arm_read(AS_Host *host, unsigned int reg) -{ - if(reg == SBIC_ASR) - return readl(host->base + SBIC_REGIDX) & 255; - writeb(reg, host->base + SBIC_REGIDX); - return readl(host->base + SBIC_REGVAL) & 255; -} - -#define sbic_arm_writenext(host, val) writeb((val), (host)->base + SBIC_REGVAL) -#define sbic_arm_readnext(host) readb((host)->base + SBIC_REGVAL) - -#ifdef USE_DMAC -#define dmac_read(host,reg) \ - readb((host)->base + DMAC_OFFSET + ((reg) << 2)) - -#define dmac_write(host,reg,value) \ - ({ writeb((value), (host)->base + DMAC_OFFSET + ((reg) << 2)); }) - -#define dmac_clearintr(host) writeb(0, (host)->fast + INT_REG) - -static inline unsigned int dmac_address(AS_Host *host) -{ - return dmac_read(host, DMAC_TXADRHI) << 16 | - dmac_read(host, DMAC_TXADRMD) << 8 | - dmac_read(host, DMAC_TXADRLO); -} - -static -void acornscsi_dumpdma(AS_Host *host, char *where) -{ - unsigned int mode, addr, len; - - mode = dmac_read(host, DMAC_MODECON); - addr = dmac_address(host); - len = dmac_read(host, DMAC_TXCNTHI) << 8 | - dmac_read(host, DMAC_TXCNTLO); - - printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ", - host->host->host_no, where, - mode, addr, (len + 1) & 0xffff, - dmac_read(host, DMAC_MASKREG)); - - printk("DMA @%06x, ", host->dma.start_addr); - printk("BH @%p +%04x, ", host->scsi.SCp.ptr, - host->scsi.SCp.this_residual); - printk("DT @+%04x ST @+%04x", host->dma.transferred, - host->scsi.SCp.scsi_xferred); - printk("\n"); -} -#endif - -static -unsigned long acornscsi_sbic_xfcount(AS_Host *host) -{ - unsigned long length; - - length = sbic_arm_read(host, SBIC_TRANSCNTH) << 16; - length |= sbic_arm_readnext(host) << 8; - length |= sbic_arm_readnext(host); - - return length; -} - -static int -acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg) -{ - int asr; - - do { - asr = sbic_arm_read(host, SBIC_ASR); - - if ((asr & stat_mask) == stat) - return 0; - - udelay(1); - } while (--timeout); - - printk("scsi%d: timeout while %s\n", host->host->host_no, msg); - - return -1; -} - -static -int acornscsi_sbic_issuecmd(AS_Host *host, int command) -{ - if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command")) - return -1; - - sbic_arm_write(host, SBIC_CMND, command); - - return 0; -} - -static void -acornscsi_csdelay(unsigned int cs) -{ - unsigned long target_jiffies, flags; - - target_jiffies = jiffies + 1 + cs * HZ / 100; - - local_save_flags(flags); - local_irq_enable(); - - while (time_before(jiffies, target_jiffies)) barrier(); - - local_irq_restore(flags); -} - -static -void acornscsi_resetcard(AS_Host *host) -{ - unsigned int i, timeout; - - /* assert reset line */ - host->card.page_reg = 0x80; - writeb(host->card.page_reg, host->fast + PAGE_REG); - - /* wait 3 cs. SCSI standard says 25ms. */ - acornscsi_csdelay(3); - - host->card.page_reg = 0; - writeb(host->card.page_reg, host->fast + PAGE_REG); - - /* - * Should get a reset from the card - */ - timeout = 1000; - do { - if (readb(host->fast + INT_REG) & 8) - break; - udelay(1); - } while (--timeout); - - if (timeout == 0) - printk("scsi%d: timeout while resetting card\n", - host->host->host_no); - - sbic_arm_read(host, SBIC_ASR); - sbic_arm_read(host, SBIC_SSR); - - /* setup sbic - WD33C93A */ - sbic_arm_write(host, SBIC_OWNID, OWNID_EAF | host->host->this_id); - sbic_arm_write(host, SBIC_CMND, CMND_RESET); - - /* - * Command should cause a reset interrupt - */ - timeout = 1000; - do { - if (readb(host->fast + INT_REG) & 8) - break; - udelay(1); - } while (--timeout); - - if (timeout == 0) - printk("scsi%d: timeout while resetting card\n", - host->host->host_no); - - sbic_arm_read(host, SBIC_ASR); - if (sbic_arm_read(host, SBIC_SSR) != 0x01) - printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n", - host->host->host_no); - - sbic_arm_write(host, SBIC_CTRL, INIT_SBICDMA | CTRL_IDI); - sbic_arm_write(host, SBIC_TIMEOUT, TIMEOUT_TIME); - sbic_arm_write(host, SBIC_SYNCHTRANSFER, SYNCHTRANSFER_2DBA); - sbic_arm_write(host, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP); - - host->card.page_reg = 0x40; - writeb(host->card.page_reg, host->fast + PAGE_REG); - - /* setup dmac - uPC71071 */ - dmac_write(host, DMAC_INIT, 0); -#ifdef USE_DMAC - dmac_write(host, DMAC_INIT, INIT_8BIT); - dmac_write(host, DMAC_CHANNEL, CHANNEL_0); - dmac_write(host, DMAC_DEVCON0, INIT_DEVCON0); - dmac_write(host, DMAC_DEVCON1, INIT_DEVCON1); -#endif - - host->SCpnt = NULL; - host->scsi.phase = PHASE_IDLE; - host->scsi.disconnectable = 0; - - memset(host->busyluns, 0, sizeof(host->busyluns)); - - for (i = 0; i < 8; i++) { - host->device[i].sync_state = SYNC_NEGOCIATE; - host->device[i].disconnect_ok = 1; - } - - /* wait 25 cs. SCSI standard says 250ms. */ - acornscsi_csdelay(25); -} - -/*============================================================================================= - * Utility routines (eg. debug) - */ -#ifdef CONFIG_ACORNSCSI_CONSTANTS -static char *acornscsi_interrupttype[] = { - "rst", "suc", "p/a", "3", - "term", "5", "6", "7", - "serv", "9", "a", "b", - "c", "d", "e", "f" -}; - -static signed char acornscsi_map[] = { - 0, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 2, -1, -1, -1, -1, 3, -1, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, -1, -1, -1, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 15, 16, 17, 18, 19, -1, -1, 20, 4, 5, 6, 7, 8, 9, 10, 11, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 21, 22, -1, -1, -1, 23, -1, -1, 4, 5, 6, 7, 8, 9, 10, 11, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 -}; - -static char *acornscsi_interruptcode[] = { - /* 0 */ - "reset - normal mode", /* 00 */ - "reset - advanced mode", /* 01 */ - - /* 2 */ - "sel", /* 11 */ - "sel+xfer", /* 16 */ - "data-out", /* 18 */ - "data-in", /* 19 */ - "cmd", /* 1A */ - "stat", /* 1B */ - "??-out", /* 1C */ - "??-in", /* 1D */ - "msg-out", /* 1E */ - "msg-in", /* 1F */ - - /* 12 */ - "/ACK asserted", /* 20 */ - "save-data-ptr", /* 21 */ - "{re}sel", /* 22 */ - - /* 15 */ - "inv cmd", /* 40 */ - "unexpected disconnect", /* 41 */ - "sel timeout", /* 42 */ - "P err", /* 43 */ - "P err+ATN", /* 44 */ - "bad status byte", /* 47 */ - - /* 21 */ - "resel, no id", /* 80 */ - "resel", /* 81 */ - "discon", /* 85 */ -}; - -static -void print_scsi_status(unsigned int ssr) -{ - if (acornscsi_map[ssr] != -1) - printk("%s:%s", - acornscsi_interrupttype[(ssr >> 4)], - acornscsi_interruptcode[acornscsi_map[ssr]]); - else - printk("%X:%X", ssr >> 4, ssr & 0x0f); -} -#endif - -static -void print_sbic_status(int asr, int ssr, int cmdphase) -{ -#ifdef CONFIG_ACORNSCSI_CONSTANTS - printk("sbic: %c%c%c%c%c%c ", - asr & ASR_INT ? 'I' : 'i', - asr & ASR_LCI ? 'L' : 'l', - asr & ASR_BSY ? 'B' : 'b', - asr & ASR_CIP ? 'C' : 'c', - asr & ASR_PE ? 'P' : 'p', - asr & ASR_DBR ? 'D' : 'd'); - printk("scsi: "); - print_scsi_status(ssr); - printk(" ph %02X\n", cmdphase); -#else - printk("sbic: %02X scsi: %X:%X ph: %02X\n", - asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase); -#endif -} - -static void -acornscsi_dumplogline(AS_Host *host, int target, int line) -{ - unsigned long prev; - signed int ptr; - - ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT; - if (ptr < 0) - ptr += STATUS_BUFFER_SIZE; - - printk("%c: %3s:", target == 8 ? 'H' : '0' + target, - line == 0 ? "ph" : line == 1 ? "ssr" : "int"); - - prev = host->status[target][ptr].when; - - for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) { - unsigned long time_diff; - - if (!host->status[target][ptr].when) - continue; - - switch (line) { - case 0: - printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ', - host->status[target][ptr].ph); - break; - - case 1: - printk(" %02X", host->status[target][ptr].ssr); - break; - - case 2: - time_diff = host->status[target][ptr].when - prev; - prev = host->status[target][ptr].when; - if (time_diff == 0) - printk("==^"); - else if (time_diff >= 100) - printk(" "); - else - printk(" %02ld", time_diff); - break; - } - } - - printk("\n"); -} - -static -void acornscsi_dumplog(AS_Host *host, int target) -{ - do { - acornscsi_dumplogline(host, target, 0); - acornscsi_dumplogline(host, target, 1); - acornscsi_dumplogline(host, target, 2); - - if (target == 8) - break; - - target = 8; - } while (1); -} - -static -char acornscsi_target(AS_Host *host) -{ - if (host->SCpnt) - return '0' + host->SCpnt->device->id; - return 'H'; -} - -/* - * Prototype: cmdtype_t acornscsi_cmdtype(int command) - * Purpose : differentiate READ from WRITE from other commands - * Params : command - command to interpret - * Returns : CMD_READ - command reads data, - * CMD_WRITE - command writes data, - * CMD_MISC - everything else - */ -static inline -cmdtype_t acornscsi_cmdtype(int command) -{ - switch (command) { - case WRITE_6: case WRITE_10: case WRITE_12: - return CMD_WRITE; - case READ_6: case READ_10: case READ_12: - return CMD_READ; - default: - return CMD_MISC; - } -} - -/* - * Prototype: int acornscsi_datadirection(int command) - * Purpose : differentiate between commands that have a DATA IN phase - * and a DATA OUT phase - * Params : command - command to interpret - * Returns : DATADIR_OUT - data out phase expected - * DATADIR_IN - data in phase expected - */ -static -datadir_t acornscsi_datadirection(int command) -{ - switch (command) { - case CHANGE_DEFINITION: case COMPARE: case COPY: - case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT: - case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER: - case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: - case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: - case WRITE_6: case WRITE_10: case WRITE_VERIFY: - case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME: - case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12: - case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW: - case MEDIUM_SCAN: case SEND_VOLUME_TAG: case 0xea: - return DATADIR_OUT; - default: - return DATADIR_IN; - } -} - -/* - * Purpose : provide values for synchronous transfers with 33C93. - * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting - * Modified by Russell King for 8MHz WD33C93A - */ -static struct sync_xfer_tbl { - unsigned int period_ns; - unsigned char reg_value; -} sync_xfer_table[] = { - { 1, 0x20 }, { 249, 0x20 }, { 374, 0x30 }, - { 499, 0x40 }, { 624, 0x50 }, { 749, 0x60 }, - { 874, 0x70 }, { 999, 0x00 }, { 0, 0 } -}; - -/* - * Prototype: int acornscsi_getperiod(unsigned char syncxfer) - * Purpose : period for the synchronous transfer setting - * Params : syncxfer SYNCXFER register value - * Returns : period in ns. - */ -static -int acornscsi_getperiod(unsigned char syncxfer) -{ - int i; - - syncxfer &= 0xf0; - if (syncxfer == 0x10) - syncxfer = 0; - - for (i = 1; sync_xfer_table[i].period_ns; i++) - if (syncxfer == sync_xfer_table[i].reg_value) - return sync_xfer_table[i].period_ns; - return 0; -} - -/* - * Prototype: int round_period(unsigned int period) - * Purpose : return index into above table for a required REQ period - * Params : period - time (ns) for REQ - * Returns : table index - * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting - */ -static inline -int round_period(unsigned int period) -{ - int i; - - for (i = 1; sync_xfer_table[i].period_ns; i++) { - if ((period <= sync_xfer_table[i].period_ns) && - (period > sync_xfer_table[i - 1].period_ns)) - return i; - } - return 7; -} - -/* - * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset) - * Purpose : calculate value for 33c93s SYNC register - * Params : period - time (ns) for REQ - * offset - offset in bytes between REQ/ACK - * Returns : value for SYNC register - * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting - */ -static -unsigned char calc_sync_xfer(unsigned int period, unsigned int offset) -{ - return sync_xfer_table[round_period(period)].reg_value | - ((offset < SDTR_SIZE) ? offset : SDTR_SIZE); -} - -/* ==================================================================================== - * Command functions - */ -/* - * Function: acornscsi_kick(AS_Host *host) - * Purpose : kick next command to interface - * Params : host - host to send command to - * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING - * Notes : interrupts are always disabled! - */ -static -intr_ret_t acornscsi_kick(AS_Host *host) -{ - int from_queue = 0; - struct scsi_cmnd *SCpnt; - - /* first check to see if a command is waiting to be executed */ - SCpnt = host->origSCpnt; - host->origSCpnt = NULL; - - /* retrieve next command */ - if (!SCpnt) { - SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns); - if (!SCpnt) - return INTR_IDLE; - - from_queue = 1; - } - - if (host->scsi.disconnectable && host->SCpnt) { - queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); - host->scsi.disconnectable = 0; -#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n", - host->host->host_no, acornscsi_target(host))); -#endif - host->SCpnt = NULL; - } - - /* - * If we have an interrupt pending, then we may have been reselected. - * In this case, we don't want to write to the registers - */ - if (!(sbic_arm_read(host, SBIC_ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) { - sbic_arm_write(host, SBIC_DESTID, SCpnt->device->id); - sbic_arm_write(host, SBIC_CMND, CMND_SELWITHATN); - } - - /* - * claim host busy - all of these must happen atomically wrt - * our interrupt routine. Failure means command loss. - */ - host->scsi.phase = PHASE_CONNECTING; - host->SCpnt = SCpnt; - host->scsi.SCp = SCpnt->SCp; - host->dma.xfer_setup = 0; - host->dma.xfer_required = 0; - host->dma.xfer_done = 0; - -#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT)) - DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n", - host->host->host_no, '0' + SCpnt->device->id, - SCpnt->cmnd[0])); -#endif - - if (from_queue) { -#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE - /* - * tagged queueing - allocate a new tag to this command - */ - if (SCpnt->device->simple_tags) { - SCpnt->device->current_tag += 1; - if (SCpnt->device->current_tag == 0) - SCpnt->device->current_tag = 1; - SCpnt->tag = SCpnt->device->current_tag; - } else -#endif - set_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns); - - host->stats.removes += 1; - - switch (acornscsi_cmdtype(SCpnt->cmnd[0])) { - case CMD_WRITE: - host->stats.writes += 1; - break; - case CMD_READ: - host->stats.reads += 1; - break; - case CMD_MISC: - host->stats.miscs += 1; - break; - } - } - - return INTR_PROCESSING; -} - -/* - * Function: void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, unsigned int result) - * Purpose : complete processing for command - * Params : host - interface that completed - * result - driver byte of result - */ -static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, - unsigned int result) -{ - struct scsi_cmnd *SCpnt = *SCpntp; - - /* clean up */ - sbic_arm_write(host, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP); - - host->stats.fins += 1; - - if (SCpnt) { - *SCpntp = NULL; - - acornscsi_dma_cleanup(host); - - SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status; - - /* - * In theory, this should not happen. In practice, it seems to. - * Only trigger an error if the device attempts to report all happy - * but with untransferred buffers... If we don't do something, then - * data loss will occur. Should we check SCpnt->underflow here? - * It doesn't appear to be set to something meaningful by the higher - * levels all the time. - */ - if (result == DID_OK) { - int xfer_warn = 0; - - if (SCpnt->underflow == 0) { - if (host->scsi.SCp.ptr && - acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC) - xfer_warn = 1; - } else { - if (host->scsi.SCp.scsi_xferred < SCpnt->underflow || - host->scsi.SCp.scsi_xferred != host->dma.transferred) - xfer_warn = 1; - } - - /* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6) - * Targets which break data transfers into multiple - * connections shall end each successful connection - * (except possibly the last) with a SAVE DATA - * POINTER - DISCONNECT message sequence. - * - * This makes it difficult to ensure that a transfer has - * completed. If we reach the end of a transfer during - * the command, then we can only have finished the transfer. - * therefore, if we seem to have some data remaining, this - * is not a problem. - */ - if (host->dma.xfer_done) - xfer_warn = 0; - - if (xfer_warn) { - switch (status_byte(SCpnt->result)) { - case CHECK_CONDITION: - case COMMAND_TERMINATED: - case BUSY: - case QUEUE_FULL: - case RESERVATION_CONFLICT: - break; - - default: - printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=", - host->host->host_no, SCpnt->result); - __scsi_print_command(SCpnt->cmnd); - acornscsi_dumpdma(host, "done"); - acornscsi_dumplog(host, SCpnt->device->id); - SCpnt->result &= 0xffff; - SCpnt->result |= DID_ERROR << 16; - } - } - } - - if (!SCpnt->scsi_done) - panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no); - - clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns); - - SCpnt->scsi_done(SCpnt); - } else - printk("scsi%d: null command in acornscsi_done", host->host->host_no); - - host->scsi.phase = PHASE_IDLE; -} - -/* ==================================================================================== - * DMA routines - */ -/* - * Purpose : update SCSI Data Pointer - * Notes : this will only be one SG entry or less - */ -static -void acornscsi_data_updateptr(AS_Host *host, struct scsi_pointer *SCp, unsigned int length) -{ - SCp->ptr += length; - SCp->this_residual -= length; - - if (SCp->this_residual == 0 && next_SCp(SCp) == 0) - host->dma.xfer_done = 1; -} - -/* - * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr, - * unsigned int start_addr, unsigned int length) - * Purpose : read data from DMA RAM - * Params : host - host to transfer from - * ptr - DRAM address - * start_addr - host mem address - * length - number of bytes to transfer - * Notes : this will only be one SG entry or less - */ -static -void acornscsi_data_read(AS_Host *host, char *ptr, - unsigned int start_addr, unsigned int length) -{ - extern void __acornscsi_in(void __iomem *, char *buf, int len); - unsigned int page, offset, len = length; - - page = (start_addr >> 12); - offset = start_addr & ((1 << 12) - 1); - - writeb((page & 0x3f) | host->card.page_reg, host->fast + PAGE_REG); - - while (len > 0) { - unsigned int this_len; - - if (len + offset > (1 << 12)) - this_len = (1 << 12) - offset; - else - this_len = len; - - __acornscsi_in(host->base + (offset << 1), ptr, this_len); - - offset += this_len; - ptr += this_len; - len -= this_len; - - if (offset == (1 << 12)) { - offset = 0; - page ++; - writeb((page & 0x3f) | host->card.page_reg, host->fast + PAGE_REG); - } - } - writeb(host->card.page_reg, host->fast + PAGE_REG); -} - -/* - * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr, - * unsigned int start_addr, unsigned int length) - * Purpose : write data to DMA RAM - * Params : host - host to transfer from - * ptr - DRAM address - * start_addr - host mem address - * length - number of bytes to transfer - * Notes : this will only be one SG entry or less - */ -static -void acornscsi_data_write(AS_Host *host, char *ptr, - unsigned int start_addr, unsigned int length) -{ - extern void __acornscsi_out(void __iomem *, char *buf, int len); - unsigned int page, offset, len = length; - - page = (start_addr >> 12); - offset = start_addr & ((1 << 12) - 1); - - writeb((page & 0x3f) | host->card.page_reg, host->fast + PAGE_REG); - - while (len > 0) { - unsigned int this_len; - - if (len + offset > (1 << 12)) - this_len = (1 << 12) - offset; - else - this_len = len; - - __acornscsi_out(host->base + (offset << 1), ptr, this_len); - - offset += this_len; - ptr += this_len; - len -= this_len; - - if (offset == (1 << 12)) { - offset = 0; - page ++; - writeb((page & 0x3f) | host->card.page_reg, host->fast + PAGE_REG); - } - } - writeb(host->card.page_reg, host->fast + PAGE_REG); -} - -/* ========================================================================================= - * On-board DMA routines - */ -#ifdef USE_DMAC -/* - * Prototype: void acornscsi_dmastop(AS_Host *host) - * Purpose : stop all DMA - * Params : host - host on which to stop DMA - * Notes : This is called when leaving DATA IN/OUT phase, - * or when interface is RESET - */ -static inline -void acornscsi_dma_stop(AS_Host *host) -{ - dmac_write(host, DMAC_MASKREG, MASK_ON); - dmac_clearintr(host); - -#if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma(host, "stop")); -#endif -} - -/* - * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) - * Purpose : setup DMA controller for data transfer - * Params : host - host to setup - * direction - data transfer direction - * Notes : This is called when entering DATA I/O phase, not - * while we're in a DATA I/O phase - */ -static -void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) -{ - unsigned int address, length, mode; - - host->dma.direction = direction; - - dmac_write(host, DMAC_MASKREG, MASK_ON); - - if (direction == DMA_OUT) { -#if (DEBUG & DEBUG_NO_WRITE) - if (NO_WRITE & (1 << host->SCpnt->device->id)) { - printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n", - host->host->host_no, acornscsi_target(host)); - return; - } -#endif - mode = DMAC_WRITE; - } else - mode = DMAC_READ; - - /* - * Allocate some buffer space, limited to half the buffer size - */ - length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); - if (length) { - host->dma.start_addr = address = host->dma.free_addr; - host->dma.free_addr = (host->dma.free_addr + length) & - (DMAC_BUFFER_SIZE - 1); - - /* - * Transfer data to DMA memory - */ - if (direction == DMA_OUT) - acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr, - length); - - length -= 1; - dmac_write(host, DMAC_TXCNTLO, length); - dmac_write(host, DMAC_TXCNTHI, length >> 8); - dmac_write(host, DMAC_TXADRLO, address); - dmac_write(host, DMAC_TXADRMD, address >> 8); - dmac_write(host, DMAC_TXADRHI, 0); - dmac_write(host, DMAC_MODECON, mode); - dmac_write(host, DMAC_MASKREG, MASK_OFF); - -#if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma(host, "strt")); -#endif - host->dma.xfer_setup = 1; - } -} - -/* - * Function: void acornscsi_dma_cleanup(AS_Host *host) - * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct - * Params : host - host to finish - * Notes : This is called when a command is: - * terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT - * : This must not return until all transfers are completed. - */ -static -void acornscsi_dma_cleanup(AS_Host *host) -{ - dmac_write(host, DMAC_MASKREG, MASK_ON); - dmac_clearintr(host); - - /* - * Check for a pending transfer - */ - if (host->dma.xfer_required) { - host->dma.xfer_required = 0; - if (host->dma.direction == DMA_IN) - acornscsi_data_read(host, host->dma.xfer_ptr, - host->dma.xfer_start, host->dma.xfer_length); - } - - /* - * Has a transfer been setup? - */ - if (host->dma.xfer_setup) { - unsigned int transferred; - - host->dma.xfer_setup = 0; - -#if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma(host, "cupi")); -#endif - - /* - * Calculate number of bytes transferred from DMA. - */ - transferred = dmac_address(host) - host->dma.start_addr; - host->dma.transferred += transferred; - - if (host->dma.direction == DMA_IN) - acornscsi_data_read(host, host->scsi.SCp.ptr, - host->dma.start_addr, transferred); - - /* - * Update SCSI pointers - */ - acornscsi_data_updateptr(host, &host->scsi.SCp, transferred); -#if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo")); -#endif - } -} - -/* - * Function: void acornscsi_dmacintr(AS_Host *host) - * Purpose : handle interrupts from DMAC device - * Params : host - host to process - * Notes : If reading, we schedule the read to main memory & - * allow the transfer to continue. - * : If writing, we fill the onboard DMA memory from main - * memory. - * : Called whenever DMAC finished it's current transfer. - */ -static -void acornscsi_dma_intr(AS_Host *host) -{ - unsigned int address, length, transferred; - -#if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma(host, "inti")); -#endif - - dmac_write(host, DMAC_MASKREG, MASK_ON); - dmac_clearintr(host); - - /* - * Calculate amount transferred via DMA - */ - transferred = dmac_address(host) - host->dma.start_addr; - host->dma.transferred += transferred; - - /* - * Schedule DMA transfer off board - */ - if (host->dma.direction == DMA_IN) { - host->dma.xfer_start = host->dma.start_addr; - host->dma.xfer_length = transferred; - host->dma.xfer_ptr = host->scsi.SCp.ptr; - host->dma.xfer_required = 1; - } - - acornscsi_data_updateptr(host, &host->scsi.SCp, transferred); - - /* - * Allocate some buffer space, limited to half the on-board RAM size - */ - length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2); - if (length) { - host->dma.start_addr = address = host->dma.free_addr; - host->dma.free_addr = (host->dma.free_addr + length) & - (DMAC_BUFFER_SIZE - 1); - - /* - * Transfer data to DMA memory - */ - if (host->dma.direction == DMA_OUT) - acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr, - length); - - length -= 1; - dmac_write(host, DMAC_TXCNTLO, length); - dmac_write(host, DMAC_TXCNTHI, length >> 8); - dmac_write(host, DMAC_TXADRLO, address); - dmac_write(host, DMAC_TXADRMD, address >> 8); - dmac_write(host, DMAC_TXADRHI, 0); - dmac_write(host, DMAC_MASKREG, MASK_OFF); - -#if (DEBUG & DEBUG_DMA) - DBG(host->SCpnt, acornscsi_dumpdma(host, "into")); -#endif - } else { - host->dma.xfer_setup = 0; -#if 0 - /* - * If the interface still wants more, then this is an error. - * We give it another byte, but we also attempt to raise an - * attention condition. We continue giving one byte until - * the device recognises the attention. - */ - if (dmac_read(host, DMAC_STATUS) & STATUS_RQ0) { - acornscsi_abortcmd(host, host->SCpnt->tag); - - dmac_write(host, DMAC_TXCNTLO, 0); - dmac_write(host, DMAC_TXCNTHI, 0); - dmac_write(host, DMAC_TXADRLO, 0); - dmac_write(host, DMAC_TXADRMD, 0); - dmac_write(host, DMAC_TXADRHI, 0); - dmac_write(host, DMAC_MASKREG, MASK_OFF); - } -#endif - } -} - -/* - * Function: void acornscsi_dma_xfer(AS_Host *host) - * Purpose : transfer data between AcornSCSI and memory - * Params : host - host to process - */ -static -void acornscsi_dma_xfer(AS_Host *host) -{ - host->dma.xfer_required = 0; - - if (host->dma.direction == DMA_IN) - acornscsi_data_read(host, host->dma.xfer_ptr, - host->dma.xfer_start, host->dma.xfer_length); -} - -/* - * Function: void acornscsi_dma_adjust(AS_Host *host) - * Purpose : adjust DMA pointers & count for bytes transferred to - * SBIC but not SCSI bus. - * Params : host - host to adjust DMA count for - */ -static -void acornscsi_dma_adjust(AS_Host *host) -{ - if (host->dma.xfer_setup) { - signed long transferred; -#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) - DBG(host->SCpnt, acornscsi_dumpdma(host, "adji")); -#endif - /* - * Calculate correct DMA address - DMA is ahead of SCSI bus while - * writing. - * host->scsi.SCp.scsi_xferred is the number of bytes - * actually transferred to/from the SCSI bus. - * host->dma.transferred is the number of bytes transferred - * over DMA since host->dma.start_addr was last set. - * - * real_dma_addr = host->dma.start_addr + host->scsi.SCp.scsi_xferred - * - host->dma.transferred - */ - transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred; - if (transferred < 0) - printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n", - host->host->host_no, acornscsi_target(host), transferred); - else if (transferred == 0) - host->dma.xfer_setup = 0; - else { - transferred += host->dma.start_addr; - dmac_write(host, DMAC_TXADRLO, transferred); - dmac_write(host, DMAC_TXADRMD, transferred >> 8); - dmac_write(host, DMAC_TXADRHI, transferred >> 16); -#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE)) - DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo")); -#endif - } - } -} -#endif - -/* ========================================================================================= - * Data I/O - */ -static int -acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout) -{ - unsigned int asr, timeout = max_timeout; - int my_ptr = *ptr; - - while (my_ptr < len) { - asr = sbic_arm_read(host, SBIC_ASR); - - if (asr & ASR_DBR) { - timeout = max_timeout; - - sbic_arm_write(host, SBIC_DATA, bytes[my_ptr++]); - } else if (asr & ASR_INT) - break; - else if (--timeout == 0) - break; - udelay(1); - } - - *ptr = my_ptr; - - return (timeout == 0) ? -1 : 0; -} - -/* - * Function: void acornscsi_sendcommand(AS_Host *host) - * Purpose : send a command to a target - * Params : host - host which is connected to target - */ -static void -acornscsi_sendcommand(AS_Host *host) -{ - struct scsi_cmnd *SCpnt = host->SCpnt; - - sbic_arm_write(host, SBIC_TRANSCNTH, 0); - sbic_arm_writenext(host, 0); - sbic_arm_writenext(host, SCpnt->cmd_len - host->scsi.SCp.sent_command); - - acornscsi_sbic_issuecmd(host, CMND_XFERINFO); - - if (acornscsi_write_pio(host, SCpnt->cmnd, - (int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000)) - printk("scsi%d: timeout while sending command\n", host->host->host_no); - - host->scsi.phase = PHASE_COMMAND; -} - -static -void acornscsi_sendmessage(AS_Host *host) -{ - unsigned int message_length = msgqueue_msglength(&host->scsi.msgs); - unsigned int msgnr; - struct message *msg; - -#if (DEBUG & DEBUG_MESSAGES) - printk("scsi%d.%c: sending message ", - host->host->host_no, acornscsi_target(host)); -#endif - - switch (message_length) { - case 0: - acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); - - acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1"); - - sbic_arm_write(host, SBIC_DATA, NOP); - - host->scsi.last_message = NOP; -#if (DEBUG & DEBUG_MESSAGES) - printk("NOP"); -#endif - break; - - case 1: - acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); - msg = msgqueue_getmsg(&host->scsi.msgs, 0); - - acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2"); - - sbic_arm_write(host, SBIC_DATA, msg->msg[0]); - - host->scsi.last_message = msg->msg[0]; -#if (DEBUG & DEBUG_MESSAGES) - spi_print_msg(msg->msg); -#endif - break; - - default: - /* - * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14) - * 'When a target sends this (MESSAGE_REJECT) message, it - * shall change to MESSAGE IN phase and send this message - * prior to requesting additional message bytes from the - * initiator. This provides an interlock so that the - * initiator can determine which message byte is rejected. - */ - sbic_arm_write(host, SBIC_TRANSCNTH, 0); - sbic_arm_writenext(host, 0); - sbic_arm_writenext(host, message_length); - acornscsi_sbic_issuecmd(host, CMND_XFERINFO); - - msgnr = 0; - while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) { - unsigned int i; -#if (DEBUG & DEBUG_MESSAGES) - spi_print_msg(msg); -#endif - i = 0; - if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000)) - printk("scsi%d: timeout while sending message\n", host->host->host_no); - - host->scsi.last_message = msg->msg[0]; - if (msg->msg[0] == EXTENDED_MESSAGE) - host->scsi.last_message |= msg->msg[2] << 8; - - if (i != msg->length) - break; - } - break; - } -#if (DEBUG & DEBUG_MESSAGES) - printk("\n"); -#endif -} - -/* - * Function: void acornscsi_readstatusbyte(AS_Host *host) - * Purpose : Read status byte from connected target - * Params : host - host connected to target - */ -static -void acornscsi_readstatusbyte(AS_Host *host) -{ - acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT); - acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte"); - host->scsi.SCp.Status = sbic_arm_read(host, SBIC_DATA); -} - -/* - * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host) - * Purpose : Read one message byte from connected target - * Params : host - host connected to target - */ -static -unsigned char acornscsi_readmessagebyte(AS_Host *host) -{ - unsigned char message; - - acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT); - - acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte"); - - message = sbic_arm_read(host, SBIC_DATA); - - /* wait for MSGIN-XFER-PAUSED */ - acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte"); - - sbic_arm_read(host, SBIC_SSR); - - return message; -} - -/* - * Function: void acornscsi_message(AS_Host *host) - * Purpose : Read complete message from connected target & action message - * Params : host - host connected to target - */ -static -void acornscsi_message(AS_Host *host) -{ - unsigned char message[16]; - unsigned int msgidx = 0, msglen = 1; - - do { - message[msgidx] = acornscsi_readmessagebyte(host); - - switch (msgidx) { - case 0: - if (message[0] == EXTENDED_MESSAGE || - (message[0] >= 0x20 && message[0] <= 0x2f)) - msglen = 2; - break; - - case 1: - if (message[0] == EXTENDED_MESSAGE) - msglen += message[msgidx]; - break; - } - msgidx += 1; - if (msgidx < msglen) { - acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); - - /* wait for next msg-in */ - acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack"); - sbic_arm_read(host, SBIC_SSR); - } - } while (msgidx < msglen); - -#if (DEBUG & DEBUG_MESSAGES) - printk("scsi%d.%c: message in: ", - host->host->host_no, acornscsi_target(host)); - spi_print_msg(message); - printk("\n"); -#endif - - if (host->scsi.phase == PHASE_RECONNECTED) { - /* - * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17) - * 'Whenever a target reconnects to an initiator to continue - * a tagged I/O process, the SIMPLE QUEUE TAG message shall - * be sent immediately following the IDENTIFY message...' - */ - if (message[0] == SIMPLE_QUEUE_TAG) - host->scsi.reconnected.tag = message[1]; - if (acornscsi_reconnect_finish(host)) - host->scsi.phase = PHASE_MSGIN; - } - - switch (message[0]) { - case ABORT: - case ABORT_TAG: - case COMMAND_COMPLETE: - if (host->scsi.phase != PHASE_STATUSIN) { - printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n", - host->host->host_no, acornscsi_target(host)); - acornscsi_dumplog(host, host->SCpnt->device->id); - } - host->scsi.phase = PHASE_DONE; - host->scsi.SCp.Message = message[0]; - break; - - case SAVE_POINTERS: - /* - * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20) - * 'The SAVE DATA POINTER message is sent from a target to - * direct the initiator to copy the active data pointer to - * the saved data pointer for the current I/O process. - */ - acornscsi_dma_cleanup(host); - host->SCpnt->SCp = host->scsi.SCp; - host->SCpnt->SCp.sent_command = 0; - host->scsi.phase = PHASE_MSGIN; - break; - - case RESTORE_POINTERS: - /* - * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19) - * 'The RESTORE POINTERS message is sent from a target to - * direct the initiator to copy the most recently saved - * command, data, and status pointers for the I/O process - * to the corresponding active pointers. The command and - * status pointers shall be restored to the beginning of - * the present command and status areas.' - */ - acornscsi_dma_cleanup(host); - host->scsi.SCp = host->SCpnt->SCp; - host->scsi.phase = PHASE_MSGIN; - break; - - case DISCONNECT: - /* - * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2) - * 'On those occasions when an error or exception condition occurs - * and the target elects to repeat the information transfer, the - * target may repeat the transfer either issuing a RESTORE POINTERS - * message or by disconnecting without issuing a SAVE POINTERS - * message. When reconnection is completed, the most recent - * saved pointer values are restored.' - */ - acornscsi_dma_cleanup(host); - host->scsi.phase = PHASE_DISCONNECT; - break; - - case MESSAGE_REJECT: -#if 0 /* this isn't needed any more */ - /* - * If we were negociating sync transfer, we don't yet know if - * this REJECT is for the sync transfer or for the tagged queue/wide - * transfer. Re-initiate sync transfer negotiation now, and if - * we got a REJECT in response to SDTR, then it'll be set to DONE. - */ - if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST) - host->device[host->SCpnt->device->id].sync_state = SYNC_NEGOCIATE; -#endif - - /* - * If we have any messages waiting to go out, then assert ATN now - */ - if (msgqueue_msglength(&host->scsi.msgs)) - acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); - - switch (host->scsi.last_message) { -#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - /* - * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17) - * If a target does not implement tagged queuing and a queue tag - * message is received, it shall respond with a MESSAGE REJECT - * message and accept the I/O process as if it were untagged. - */ - printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n", - host->host->host_no, acornscsi_target(host)); - host->SCpnt->device->simple_tags = 0; - set_bit(host->SCpnt->device->id * 8 + host->SCpnt->device->lun, host->busyluns); - break; -#endif - case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8): - /* - * Target can't handle synchronous transfers - */ - printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n", - host->host->host_no, acornscsi_target(host)); - host->device[host->SCpnt->device->id].sync_xfer = SYNCHTRANSFER_2DBA; - host->device[host->SCpnt->device->id].sync_state = SYNC_ASYNCHRONOUS; - sbic_arm_write(host, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer); - break; - - default: - break; - } - break; - - case QUEUE_FULL: - /* TODO: target queue is full */ - break; - - case SIMPLE_QUEUE_TAG: - /* tag queue reconnect... message[1] = queue tag. Print something to indicate something happened! */ - printk("scsi%d.%c: reconnect queue tag %02X\n", - host->host->host_no, acornscsi_target(host), - message[1]); - break; - - case EXTENDED_MESSAGE: - switch (message[2]) { -#ifdef CONFIG_SCSI_ACORNSCSI_SYNC - case EXTENDED_SDTR: - if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST) { - /* - * We requested synchronous transfers. This isn't quite right... - * We can only say if this succeeded if we proceed on to execute the - * command from this message. If we get a MESSAGE PARITY ERROR, - * and the target retries fail, then we fallback to asynchronous mode - */ - host->device[host->SCpnt->device->id].sync_state = SYNC_COMPLETED; - printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n", - host->host->host_no, acornscsi_target(host), - message[4], message[3] * 4); - host->device[host->SCpnt->device->id].sync_xfer = - calc_sync_xfer(message[3] * 4, message[4]); - } else { - unsigned char period, length; - /* - * Target requested synchronous transfers. The agreement is only - * to be in operation AFTER the target leaves message out phase. - */ - acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); - period = max_t(unsigned int, message[3], sdtr_period / 4); - length = min_t(unsigned int, message[4], sdtr_size); - msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3, - EXTENDED_SDTR, period, length); - host->device[host->SCpnt->device->id].sync_xfer = - calc_sync_xfer(period * 4, length); - } - sbic_arm_write(host, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer); - break; -#else - /* We do not accept synchronous transfers. Respond with a - * MESSAGE_REJECT. - */ -#endif - - case EXTENDED_WDTR: - /* The WD33C93A is only 8-bit. We respond with a MESSAGE_REJECT - * to a wide data transfer request. - */ - default: - acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); - msgqueue_flush(&host->scsi.msgs); - msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT); - break; - } - break; - -#ifdef CONFIG_SCSI_ACORNSCSI_LINK - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* - * We don't support linked commands yet - */ - if (0) { -#if (DEBUG & DEBUG_LINK) - printk("scsi%d.%c: lun %d tag %d linked command complete\n", - host->host->host_no, acornscsi_target(host), host->SCpnt->tag); -#endif - /* - * A linked command should only terminate with one of these messages - * if there are more linked commands available. - */ - if (!host->SCpnt->next_link) { - printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n", - instance->host_no, acornscsi_target(host), host->SCpnt->tag); - acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); - msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); - } else { - struct scsi_cmnd *SCpnt = host->SCpnt; - - acornscsi_dma_cleanup(host); - - host->SCpnt = host->SCpnt->next_link; - host->SCpnt->tag = SCpnt->tag; - SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status; - SCpnt->done(SCpnt); - - /* initialise host->SCpnt->SCp */ - } - break; - } -#endif - - default: /* reject message */ - printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n", - host->host->host_no, acornscsi_target(host), - message[0]); - acornscsi_sbic_issuecmd(host, CMND_ASSERTATN); - msgqueue_flush(&host->scsi.msgs); - msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT); - host->scsi.phase = PHASE_MSGIN; - break; - } - acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); -} - -/* - * Function: int acornscsi_buildmessages(AS_Host *host) - * Purpose : build the connection messages for a host - * Params : host - host to add messages to - */ -static -void acornscsi_buildmessages(AS_Host *host) -{ -#if 0 - /* does the device need resetting? */ - if (cmd_reset) { - msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET); - return; - } -#endif - - msgqueue_addmsg(&host->scsi.msgs, 1, - IDENTIFY(host->device[host->SCpnt->device->id].disconnect_ok, - host->SCpnt->device->lun)); - -#if 0 - /* does the device need the current command aborted */ - if (cmd_aborted) { - acornscsi_abortcmd(host->SCpnt->tag); - return; - } -#endif - -#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE - if (host->SCpnt->tag) { - unsigned int tag_type; - - if (host->SCpnt->cmnd[0] == REQUEST_SENSE || - host->SCpnt->cmnd[0] == TEST_UNIT_READY || - host->SCpnt->cmnd[0] == INQUIRY) - tag_type = HEAD_OF_QUEUE_TAG; - else - tag_type = SIMPLE_QUEUE_TAG; - msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag); - } -#endif - -#ifdef CONFIG_SCSI_ACORNSCSI_SYNC - if (host->device[host->SCpnt->device->id].sync_state == SYNC_NEGOCIATE) { - host->device[host->SCpnt->device->id].sync_state = SYNC_SENT_REQUEST; - msgqueue_addmsg(&host->scsi.msgs, 5, - EXTENDED_MESSAGE, 3, EXTENDED_SDTR, - sdtr_period / 4, sdtr_size); - } -#endif -} - -/* - * Function: int acornscsi_starttransfer(AS_Host *host) - * Purpose : transfer data to/from connected target - * Params : host - host to which target is connected - * Returns : 0 if failure - */ -static -int acornscsi_starttransfer(AS_Host *host) -{ - int residual; - - if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) { - printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n", - host->host->host_no, acornscsi_target(host)); - return 0; - } - - residual = scsi_bufflen(host->SCpnt) - host->scsi.SCp.scsi_xferred; - - sbic_arm_write(host, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer); - sbic_arm_writenext(host, residual >> 16); - sbic_arm_writenext(host, residual >> 8); - sbic_arm_writenext(host, residual); - acornscsi_sbic_issuecmd(host, CMND_XFERINFO); - return 1; -} - -/* ========================================================================================= - * Connection & Disconnection - */ -/* - * Function : acornscsi_reconnect(AS_Host *host) - * Purpose : reconnect a previously disconnected command - * Params : host - host specific data - * Remarks : SCSI spec says: - * 'The set of active pointers is restored from the set - * of saved pointers upon reconnection of the I/O process' - */ -static -int acornscsi_reconnect(AS_Host *host) -{ - unsigned int target, lun, ok = 0; - - target = sbic_arm_read(host, SBIC_SOURCEID); - - if (!(target & 8)) - printk(KERN_ERR "scsi%d: invalid source id after reselection " - "- device fault?\n", - host->host->host_no); - - target &= 7; - - if (host->SCpnt && !host->scsi.disconnectable) { - printk(KERN_ERR "scsi%d.%d: reconnected while command in " - "progress to target %d?\n", - host->host->host_no, target, host->SCpnt->device->id); - host->SCpnt = NULL; - } - - lun = sbic_arm_read(host, SBIC_DATA) & 7; - - host->scsi.reconnected.target = target; - host->scsi.reconnected.lun = lun; - host->scsi.reconnected.tag = 0; - - if (host->scsi.disconnectable && host->SCpnt && - host->SCpnt->device->id == target && host->SCpnt->device->lun == lun) - ok = 1; - - if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun)) - ok = 1; - - ADD_STATUS(target, 0x81, host->scsi.phase, 0); - - if (ok) { - host->scsi.phase = PHASE_RECONNECTED; - } else { - /* this doesn't seem to work */ - printk(KERN_ERR "scsi%d.%c: reselected with no command " - "to reconnect with\n", - host->host->host_no, '0' + target); - acornscsi_dumplog(host, target); - acornscsi_abortcmd(host, 0); - if (host->SCpnt) { - queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); - host->SCpnt = NULL; - } - } - acornscsi_sbic_issuecmd(host, CMND_NEGATEACK); - return !ok; -} - -/* - * Function: int acornscsi_reconect_finish(AS_Host *host) - * Purpose : finish reconnecting a command - * Params : host - host to complete - * Returns : 0 if failed - */ -static -int acornscsi_reconnect_finish(AS_Host *host) -{ - if (host->scsi.disconnectable && host->SCpnt) { - host->scsi.disconnectable = 0; - if (host->SCpnt->device->id == host->scsi.reconnected.target && - host->SCpnt->device->lun == host->scsi.reconnected.lun && - host->SCpnt->tag == host->scsi.reconnected.tag) { -#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk("scsi%d.%c: reconnected", - host->host->host_no, acornscsi_target(host))); -#endif - } else { - queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt); -#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk("scsi%d.%c: had to move command " - "to disconnected queue\n", - host->host->host_no, acornscsi_target(host))); -#endif - host->SCpnt = NULL; - } - } - if (!host->SCpnt) { - host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected, - host->scsi.reconnected.target, - host->scsi.reconnected.lun, - host->scsi.reconnected.tag); -#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - DBG(host->SCpnt, printk("scsi%d.%c: had to get command", - host->host->host_no, acornscsi_target(host))); -#endif - } - - if (!host->SCpnt) - acornscsi_abortcmd(host, host->scsi.reconnected.tag); - else { - /* - * Restore data pointer from SAVED pointers. - */ - host->scsi.SCp = host->SCpnt->SCp; -#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - printk(", data pointers: [%p, %X]", - host->scsi.SCp.ptr, host->scsi.SCp.this_residual); -#endif - } -#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON)) - printk("\n"); -#endif - - host->dma.transferred = host->scsi.SCp.scsi_xferred; - - return host->SCpnt != NULL; -} - -/* - * Function: void acornscsi_disconnect_unexpected(AS_Host *host) - * Purpose : handle an unexpected disconnect - * Params : host - host on which disconnect occurred - */ -static -void acornscsi_disconnect_unexpected(AS_Host *host) -{ - printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n", - host->host->host_no, acornscsi_target(host)); -#if (DEBUG & DEBUG_ABORT) - acornscsi_dumplog(host, 8); -#endif - - acornscsi_done(host, &host->SCpnt, DID_ERROR); -} - -/* - * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag) - * Purpose : abort a currently executing command - * Params : host - host with connected command to abort - * tag - tag to abort - */ -static -void acornscsi_abortcmd(AS_Host *host, unsigned char tag) -{ - host->scsi.phase = PHASE_ABORTED; - sbic_arm_write(host, SBIC_CMND, CMND_ASSERTATN); - - msgqueue_flush(&host->scsi.msgs); -#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE - if (tag) - msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag); - else -#endif - msgqueue_addmsg(&host->scsi.msgs, 1, ABORT); -} - -/* ========================================================================================== - * Interrupt routines. - */ -/* - * Function: int acornscsi_sbicintr(AS_Host *host) - * Purpose : handle interrupts from SCSI device - * Params : host - host to process - * Returns : INTR_PROCESS if expecting another SBIC interrupt - * INTR_IDLE if no interrupt - * INTR_NEXT_COMMAND if we have finished processing the command - */ -static -intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq) -{ - unsigned int asr, ssr; - - asr = sbic_arm_read(host, SBIC_ASR); - if (!(asr & ASR_INT)) - return INTR_IDLE; - - ssr = sbic_arm_read(host, SBIC_SSR); - -#if (DEBUG & DEBUG_PHASES) - print_sbic_status(asr, ssr, host->scsi.phase); -#endif - - ADD_STATUS(8, ssr, host->scsi.phase, in_irq); - - if (host->SCpnt && !host->scsi.disconnectable) - ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq); - - switch (ssr) { - case 0x00: /* reset state - not advanced */ - printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n", - host->host->host_no); - /* setup sbic - WD33C93A */ - sbic_arm_write(host, SBIC_OWNID, OWNID_EAF | host->host->this_id); - sbic_arm_write(host, SBIC_CMND, CMND_RESET); - return INTR_IDLE; - - case 0x01: /* reset state - advanced */ - sbic_arm_write(host, SBIC_CTRL, INIT_SBICDMA | CTRL_IDI); - sbic_arm_write(host, SBIC_TIMEOUT, TIMEOUT_TIME); - sbic_arm_write(host, SBIC_SYNCHTRANSFER, SYNCHTRANSFER_2DBA); - sbic_arm_write(host, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP); - msgqueue_flush(&host->scsi.msgs); - return INTR_IDLE; - - case 0x41: /* unexpected disconnect aborted command */ - acornscsi_disconnect_unexpected(host); - return INTR_NEXT_COMMAND; - } - - switch (host->scsi.phase) { - case PHASE_CONNECTING: /* STATE: command removed from issue queue */ - switch (ssr) { - case 0x11: /* -> PHASE_CONNECTED */ - /* BUS FREE -> SELECTION */ - host->scsi.phase = PHASE_CONNECTED; - msgqueue_flush(&host->scsi.msgs); - host->dma.transferred = host->scsi.SCp.scsi_xferred; - /* 33C93 gives next interrupt indicating bus phase */ - asr = sbic_arm_read(host, SBIC_ASR); - if (!(asr & ASR_INT)) - break; - ssr = sbic_arm_read(host, SBIC_SSR); - ADD_STATUS(8, ssr, host->scsi.phase, 1); - ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, 1); - goto connected; - - case 0x42: /* select timed out */ - /* -> PHASE_IDLE */ - acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT); - return INTR_NEXT_COMMAND; - - case 0x81: /* -> PHASE_RECONNECTED or PHASE_ABORTED */ - /* BUS FREE -> RESELECTION */ - host->origSCpnt = host->SCpnt; - host->SCpnt = NULL; - msgqueue_flush(&host->scsi.msgs); - acornscsi_reconnect(host); - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - acornscsi_abortcmd(host, host->SCpnt->tag); - } - return INTR_PROCESSING; - - connected: - case PHASE_CONNECTED: /* STATE: device selected ok */ - switch (ssr) { -#ifdef NONSTANDARD - case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ - /* SELECTION -> COMMAND */ - acornscsi_sendcommand(host); - break; - - case 0x8b: /* -> PHASE_STATUS */ - /* SELECTION -> STATUS */ - acornscsi_readstatusbyte(host); - host->scsi.phase = PHASE_STATUSIN; - break; -#endif - - case 0x8e: /* -> PHASE_MSGOUT */ - /* SELECTION ->MESSAGE OUT */ - host->scsi.phase = PHASE_MSGOUT; - acornscsi_buildmessages(host); - acornscsi_sendmessage(host); - break; - - /* these should not happen */ - case 0x85: /* target disconnected */ - acornscsi_done(host, &host->SCpnt, DID_ERROR); - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - acornscsi_abortcmd(host, host->SCpnt->tag); - } - return INTR_PROCESSING; - - case PHASE_MSGOUT: /* STATE: connected & sent IDENTIFY message */ - /* - * SCSI standard says that MESSAGE OUT phases can be followed by a - * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase - */ - switch (ssr) { - case 0x8a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ - case 0x1a: /* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ - /* MESSAGE OUT -> COMMAND */ - acornscsi_sendcommand(host); - break; - - case 0x8b: /* -> PHASE_STATUS */ - case 0x1b: /* -> PHASE_STATUS */ - /* MESSAGE OUT -> STATUS */ - acornscsi_readstatusbyte(host); - host->scsi.phase = PHASE_STATUSIN; - break; - - case 0x8e: /* -> PHASE_MSGOUT */ - /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */ - acornscsi_sendmessage(host); - break; - - case 0x4f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ - case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ - /* MESSAGE OUT -> MESSAGE IN */ - acornscsi_message(host); - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_COMMAND: /* STATE: connected & command sent */ - switch (ssr) { - case 0x18: /* -> PHASE_DATAOUT */ - /* COMMAND -> DATA OUT */ - if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) - acornscsi_abortcmd(host, host->SCpnt->tag); - acornscsi_dma_setup(host, DMA_OUT); - if (!acornscsi_starttransfer(host)) - acornscsi_abortcmd(host, host->SCpnt->tag); - host->scsi.phase = PHASE_DATAOUT; - return INTR_IDLE; - - case 0x19: /* -> PHASE_DATAIN */ - /* COMMAND -> DATA IN */ - if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len) - acornscsi_abortcmd(host, host->SCpnt->tag); - acornscsi_dma_setup(host, DMA_IN); - if (!acornscsi_starttransfer(host)) - acornscsi_abortcmd(host, host->SCpnt->tag); - host->scsi.phase = PHASE_DATAIN; - return INTR_IDLE; - - case 0x1b: /* -> PHASE_STATUS */ - /* COMMAND -> STATUS */ - acornscsi_readstatusbyte(host); - host->scsi.phase = PHASE_STATUSIN; - break; - - case 0x1e: /* -> PHASE_MSGOUT */ - /* COMMAND -> MESSAGE OUT */ - acornscsi_sendmessage(host); - break; - - case 0x1f: /* -> PHASE_MSGIN, PHASE_DISCONNECT */ - /* COMMAND -> MESSAGE IN */ - acornscsi_message(host); - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_DISCONNECT: /* STATE: connected, received DISCONNECT msg */ - if (ssr == 0x85) { /* -> PHASE_IDLE */ - host->scsi.disconnectable = 1; - host->scsi.reconnected.tag = 0; - host->scsi.phase = PHASE_IDLE; - host->stats.disconnects += 1; - } else { - printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_NEXT_COMMAND; - - case PHASE_IDLE: /* STATE: disconnected */ - if (ssr == 0x81) /* -> PHASE_RECONNECTED or PHASE_ABORTED */ - acornscsi_reconnect(host); - else { - printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_RECONNECTED: /* STATE: device reconnected to initiator */ - /* - * Command reconnected - if MESGIN, get message - it may be - * the tag. If not, get command out of disconnected queue - */ - /* - * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY, - * reconnect I_T_L command - */ - if (ssr != 0x8f && !acornscsi_reconnect_finish(host)) - return INTR_IDLE; - ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq); - switch (ssr) { - case 0x88: /* data out phase */ - /* -> PHASE_DATAOUT */ - /* MESSAGE IN -> DATA OUT */ - acornscsi_dma_setup(host, DMA_OUT); - if (!acornscsi_starttransfer(host)) - acornscsi_abortcmd(host, host->SCpnt->tag); - host->scsi.phase = PHASE_DATAOUT; - return INTR_IDLE; - - case 0x89: /* data in phase */ - /* -> PHASE_DATAIN */ - /* MESSAGE IN -> DATA IN */ - acornscsi_dma_setup(host, DMA_IN); - if (!acornscsi_starttransfer(host)) - acornscsi_abortcmd(host, host->SCpnt->tag); - host->scsi.phase = PHASE_DATAIN; - return INTR_IDLE; - - case 0x8a: /* command out */ - /* MESSAGE IN -> COMMAND */ - acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED */ - break; - - case 0x8b: /* status in */ - /* -> PHASE_STATUSIN */ - /* MESSAGE IN -> STATUS */ - acornscsi_readstatusbyte(host); - host->scsi.phase = PHASE_STATUSIN; - break; - - case 0x8e: /* message out */ - /* -> PHASE_MSGOUT */ - /* MESSAGE IN -> MESSAGE OUT */ - acornscsi_sendmessage(host); - break; - - case 0x8f: /* message in */ - acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_DATAIN: /* STATE: transferred data in */ - /* - * This is simple - if we disconnect then the DMA address & count is - * correct. - */ - switch (ssr) { - case 0x19: /* -> PHASE_DATAIN */ - case 0x89: /* -> PHASE_DATAIN */ - acornscsi_abortcmd(host, host->SCpnt->tag); - return INTR_IDLE; - - case 0x1b: /* -> PHASE_STATUSIN */ - case 0x4b: /* -> PHASE_STATUSIN */ - case 0x8b: /* -> PHASE_STATUSIN */ - /* DATA IN -> STATUS */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - - acornscsi_sbic_xfcount(host); - acornscsi_dma_stop(host); - acornscsi_readstatusbyte(host); - host->scsi.phase = PHASE_STATUSIN; - break; - - case 0x1e: /* -> PHASE_MSGOUT */ - case 0x4e: /* -> PHASE_MSGOUT */ - case 0x8e: /* -> PHASE_MSGOUT */ - /* DATA IN -> MESSAGE OUT */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - - acornscsi_sbic_xfcount(host); - acornscsi_dma_stop(host); - acornscsi_sendmessage(host); - break; - - case 0x1f: /* message in */ - case 0x4f: /* message in */ - case 0x8f: /* message in */ - /* DATA IN -> MESSAGE IN */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - - acornscsi_sbic_xfcount(host); - acornscsi_dma_stop(host); - acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_DATAOUT: /* STATE: transferred data out */ - /* - * This is more complicated - if we disconnect, the DMA could be 12 - * bytes ahead of us. We need to correct this. - */ - switch (ssr) { - case 0x18: /* -> PHASE_DATAOUT */ - case 0x88: /* -> PHASE_DATAOUT */ - acornscsi_abortcmd(host, host->SCpnt->tag); - return INTR_IDLE; - - case 0x1b: /* -> PHASE_STATUSIN */ - case 0x4b: /* -> PHASE_STATUSIN */ - case 0x8b: /* -> PHASE_STATUSIN */ - /* DATA OUT -> STATUS */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - - acornscsi_sbic_xfcount(host); - acornscsi_dma_stop(host); - acornscsi_dma_adjust(host); - acornscsi_readstatusbyte(host); - host->scsi.phase = PHASE_STATUSIN; - break; - - case 0x1e: /* -> PHASE_MSGOUT */ - case 0x4e: /* -> PHASE_MSGOUT */ - case 0x8e: /* -> PHASE_MSGOUT */ - /* DATA OUT -> MESSAGE OUT */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - - acornscsi_sbic_xfcount(host); - acornscsi_dma_stop(host); - acornscsi_dma_adjust(host); - acornscsi_sendmessage(host); - break; - - case 0x1f: /* message in */ - case 0x4f: /* message in */ - case 0x8f: /* message in */ - /* DATA OUT -> MESSAGE IN */ - host->scsi.SCp.scsi_xferred = scsi_bufflen(host->SCpnt) - - acornscsi_sbic_xfcount(host); - acornscsi_dma_stop(host); - acornscsi_dma_adjust(host); - acornscsi_message(host); /* -> PHASE_MSGIN, PHASE_DISCONNECT */ - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_STATUSIN: /* STATE: status in complete */ - switch (ssr) { - case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ - case 0x8f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ - /* STATUS -> MESSAGE IN */ - acornscsi_message(host); - break; - - case 0x1e: /* -> PHASE_MSGOUT */ - case 0x8e: /* -> PHASE_MSGOUT */ - /* STATUS -> MESSAGE OUT */ - acornscsi_sendmessage(host); - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_MSGIN: /* STATE: message in */ - switch (ssr) { - case 0x1e: /* -> PHASE_MSGOUT */ - case 0x4e: /* -> PHASE_MSGOUT */ - case 0x8e: /* -> PHASE_MSGOUT */ - /* MESSAGE IN -> MESSAGE OUT */ - acornscsi_sendmessage(host); - break; - - case 0x1f: /* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */ - case 0x2f: - case 0x4f: - case 0x8f: - acornscsi_message(host); - break; - - case 0x85: - printk("scsi%d.%c: strange message in disconnection\n", - host->host->host_no, acornscsi_target(host)); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - acornscsi_done(host, &host->SCpnt, DID_ERROR); - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_DONE: /* STATE: received status & message */ - switch (ssr) { - case 0x85: /* -> PHASE_IDLE */ - acornscsi_done(host, &host->SCpnt, DID_OK); - return INTR_NEXT_COMMAND; - - case 0x1e: - case 0x8e: - acornscsi_sendmessage(host); - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - case PHASE_ABORTED: - switch (ssr) { - case 0x85: - if (host->SCpnt) - acornscsi_done(host, &host->SCpnt, DID_ABORT); - else { - clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun, - host->busyluns); - host->scsi.phase = PHASE_IDLE; - } - return INTR_NEXT_COMMAND; - - case 0x1e: - case 0x2e: - case 0x4e: - case 0x8e: - acornscsi_sendmessage(host); - break; - - default: - printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; - - default: - printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n", - host->host->host_no, acornscsi_target(host), ssr); - acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8); - } - return INTR_PROCESSING; -} - -/* - * Prototype: void acornscsi_intr(int irq, void *dev_id) - * Purpose : handle interrupts from Acorn SCSI card - * Params : irq - interrupt number - * dev_id - device specific data (AS_Host structure) - */ -static irqreturn_t -acornscsi_intr(int irq, void *dev_id) -{ - AS_Host *host = (AS_Host *)dev_id; - intr_ret_t ret; - int iostatus; - int in_irq = 0; - - do { - ret = INTR_IDLE; - - iostatus = readb(host->fast + INT_REG); - - if (iostatus & 2) { - acornscsi_dma_intr(host); - iostatus = readb(host->fast + INT_REG); - } - - if (iostatus & 8) - ret = acornscsi_sbicintr(host, in_irq); - - /* - * If we have a transfer pending, start it. - * Only start it if the interface has already started transferring - * it's data - */ - if (host->dma.xfer_required) - acornscsi_dma_xfer(host); - - if (ret == INTR_NEXT_COMMAND) - ret = acornscsi_kick(host); - - in_irq = 1; - } while (ret != INTR_IDLE); - - return IRQ_HANDLED; -} - -/*============================================================================================= - * Interfaces between interrupt handler and rest of scsi code - */ - -/* - * Function : acornscsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) - * Purpose : queues a SCSI command - * Params : cmd - SCSI command - * done - function called on completion, with pointer to command descriptor - * Returns : 0, or < 0 on error. - */ -static int acornscsi_queuecmd_lck(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata; - - if (!done) { - /* there should be some way of rejecting errors like this without panicing... */ - panic("scsi%d: queuecommand called with NULL done function [cmd=%p]", - host->host->host_no, SCpnt); - return -EINVAL; - } - -#if (DEBUG & DEBUG_NO_WRITE) - if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->device->id))) { - printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n", - host->host->host_no, '0' + SCpnt->device->id); - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; - } -#endif - - SCpnt->scsi_done = done; - SCpnt->host_scribble = NULL; - SCpnt->result = 0; - SCpnt->tag = 0; - SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]); - SCpnt->SCp.sent_command = 0; - SCpnt->SCp.scsi_xferred = 0; - - init_SCp(SCpnt); - - host->stats.queues += 1; - - { - unsigned long flags; - - if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) { - SCpnt->result = DID_ERROR << 16; - done(SCpnt); - return 0; - } - local_irq_save(flags); - if (host->scsi.phase == PHASE_IDLE) - acornscsi_kick(host); - local_irq_restore(flags); - } - return 0; -} - -DEF_SCSI_QCMD(acornscsi_queuecmd) - -/* - * Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result) - * Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2 - * Params : SCpntp1 - pointer to command to return - * SCpntp2 - pointer to command to check - * result - result to pass back to mid-level done function - * Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2. - */ -static inline void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, - struct scsi_cmnd **SCpntp2, - int result) -{ - struct scsi_cmnd *SCpnt = *SCpntp1; - - if (SCpnt) { - *SCpntp1 = NULL; - - SCpnt->result = result; - SCpnt->scsi_done(SCpnt); - } - - if (SCpnt == *SCpntp2) - *SCpntp2 = NULL; -} - -enum res_abort { res_not_running, res_success, res_success_clear, res_snooze }; - -/* - * Prototype: enum res acornscsi_do_abort(struct scsi_cmnd *SCpnt) - * Purpose : abort a command on this host - * Params : SCpnt - command to abort - * Returns : our abort status - */ -static enum res_abort acornscsi_do_abort(AS_Host *host, struct scsi_cmnd *SCpnt) -{ - enum res_abort res = res_not_running; - - if (queue_remove_cmd(&host->queues.issue, SCpnt)) { - /* - * The command was on the issue queue, and has not been - * issued yet. We can remove the command from the queue, - * and acknowledge the abort. Neither the devices nor the - * interface know about the command. - */ -//#if (DEBUG & DEBUG_ABORT) - printk("on issue queue "); -//#endif - res = res_success; - } else if (queue_remove_cmd(&host->queues.disconnected, SCpnt)) { - /* - * The command was on the disconnected queue. Simply - * acknowledge the abort condition, and when the target - * reconnects, we will give it an ABORT message. The - * target should then disconnect, and we will clear - * the busylun bit. - */ -//#if (DEBUG & DEBUG_ABORT) - printk("on disconnected queue "); -//#endif - res = res_success; - } else if (host->SCpnt == SCpnt) { - unsigned long flags; - -//#if (DEBUG & DEBUG_ABORT) - printk("executing "); -//#endif - - local_irq_save(flags); - switch (host->scsi.phase) { - /* - * If the interface is idle, and the command is 'disconnectable', - * then it is the same as on the disconnected queue. We simply - * remove all traces of the command. When the target reconnects, - * we will give it an ABORT message since the command could not - * be found. When the target finally disconnects, we will clear - * the busylun bit. - */ - case PHASE_IDLE: - if (host->scsi.disconnectable) { - host->scsi.disconnectable = 0; - host->SCpnt = NULL; - res = res_success; - } - break; - - /* - * If the command has connected and done nothing further, - * simply force a disconnect. We also need to clear the - * busylun bit. - */ - case PHASE_CONNECTED: - sbic_arm_write(host, SBIC_CMND, CMND_DISCONNECT); - host->SCpnt = NULL; - res = res_success_clear; - break; - - default: - acornscsi_abortcmd(host, host->SCpnt->tag); - res = res_snooze; - } - local_irq_restore(flags); - } else if (host->origSCpnt == SCpnt) { - /* - * The command will be executed next, but a command - * is currently using the interface. This is similar to - * being on the issue queue, except the busylun bit has - * been set. - */ - host->origSCpnt = NULL; -//#if (DEBUG & DEBUG_ABORT) - printk("waiting for execution "); -//#endif - res = res_success_clear; - } else - printk("unknown "); - - return res; -} - -/* - * Prototype: int acornscsi_abort(struct scsi_cmnd *SCpnt) - * Purpose : abort a command on this host - * Params : SCpnt - command to abort - * Returns : one of SCSI_ABORT_ macros - */ -int acornscsi_abort(struct scsi_cmnd *SCpnt) -{ - AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata; - int result; - - host->stats.aborts += 1; - -#if (DEBUG & DEBUG_ABORT) - { - int asr, ssr; - asr = sbic_arm_read(host, SBIC_ASR); - ssr = sbic_arm_read(host, SBIC_SSR); - - printk(KERN_WARNING "acornscsi_abort: "); - print_sbic_status(asr, ssr, host->scsi.phase); - acornscsi_dumplog(host, SCpnt->device->id); - } -#endif - - printk("scsi%d: ", host->host->host_no); - - switch (acornscsi_do_abort(host, SCpnt)) { - /* - * We managed to find the command and cleared it out. - * We do not expect the command to be executing on the - * target, but we have set the busylun bit. - */ - case res_success_clear: -//#if (DEBUG & DEBUG_ABORT) - printk("clear "); -//#endif - clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns); - - /* - * We found the command, and cleared it out. Either - * the command is still known to be executing on the - * target, or the busylun bit is not set. - */ - case res_success: -//#if (DEBUG & DEBUG_ABORT) - printk("success\n"); -//#endif - result = SUCCESS; - break; - - /* - * We did find the command, but unfortunately we couldn't - * unhook it from ourselves. Wait some more, and if it - * still doesn't complete, reset the interface. - */ - case res_snooze: -//#if (DEBUG & DEBUG_ABORT) - printk("snooze\n"); -//#endif - result = FAILED; - break; - - /* - * The command could not be found (either because it completed, - * or it got dropped. - */ - default: - case res_not_running: - acornscsi_dumplog(host, SCpnt->device->id); - result = FAILED; -//#if (DEBUG & DEBUG_ABORT) - printk("not running\n"); -//#endif - break; - } - - return result; -} - -/* - * Prototype: int acornscsi_reset(struct scsi_cmnd *SCpnt) - * Purpose : reset a command on this host/reset this host - * Params : SCpnt - command causing reset - * Returns : one of SCSI_RESET_ macros - */ -int acornscsi_bus_reset(struct scsi_cmnd *SCpnt) -{ - AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata; - struct scsi_cmnd *SCptr; - - host->stats.resets += 1; - -#if (DEBUG & DEBUG_RESET) - { - int asr, ssr; - - asr = sbic_arm_read(host, SBIC_ASR); - ssr = sbic_arm_read(host, SBIC_SSR); - - printk(KERN_WARNING "acornscsi_reset: "); - print_sbic_status(asr, ssr, host->scsi.phase); - acornscsi_dumplog(host, SCpnt->device->id); - } -#endif - - acornscsi_dma_stop(host); - - /* - * do hard reset. This resets all devices on this host, and so we - * must set the reset status on all commands. - */ - acornscsi_resetcard(host); - - while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL) - ; - - return SUCCESS; -} - -/*============================================================================================== - * initialisation & miscellaneous support - */ - -/* - * Function: char *acornscsi_info(struct Scsi_Host *host) - * Purpose : return a string describing this interface - * Params : host - host to give information on - * Returns : a constant string - */ -const -char *acornscsi_info(struct Scsi_Host *host) -{ - static char string[100], *p; - - p = string; - - p += sprintf(string, "%s at port %08lX irq %d v%d.%d.%d" -#ifdef CONFIG_SCSI_ACORNSCSI_SYNC - " SYNC" -#endif -#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE - " TAG" -#endif -#ifdef CONFIG_SCSI_ACORNSCSI_LINK - " LINK" -#endif -#if (DEBUG & DEBUG_NO_WRITE) - " NOWRITE (" __stringify(NO_WRITE) ")" -#endif - , host->hostt->name, host->io_port, host->irq, - VER_MAJOR, VER_MINOR, VER_PATCH); - return string; -} - -int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset, - int length, int inout) -{ - int pos, begin = 0, devidx; - struct scsi_device *scd; - AS_Host *host; - char *p = buffer; - - if (inout == 1) - return -EINVAL; - - host = (AS_Host *)instance->hostdata; - - p += sprintf(p, "AcornSCSI driver v%d.%d.%d" -#ifdef CONFIG_SCSI_ACORNSCSI_SYNC - " SYNC" -#endif -#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE - " TAG" -#endif -#ifdef CONFIG_SCSI_ACORNSCSI_LINK - " LINK" -#endif -#if (DEBUG & DEBUG_NO_WRITE) - " NOWRITE (" __stringify(NO_WRITE) ")" -#endif - "\n\n", VER_MAJOR, VER_MINOR, VER_PATCH); - - p += sprintf(p, "SBIC: WD33C93A Address: %p IRQ : %d\n", - host->base + SBIC_REGIDX, host->scsi.irq); -#ifdef USE_DMAC - p += sprintf(p, "DMAC: uPC71071 Address: %p IRQ : %d\n\n", - host->base + DMAC_OFFSET, host->scsi.irq); -#endif - - p += sprintf(p, "Statistics:\n" - "Queued commands: %-10u Issued commands: %-10u\n" - "Done commands : %-10u Reads : %-10u\n" - "Writes : %-10u Others : %-10u\n" - "Disconnects : %-10u Aborts : %-10u\n" - "Resets : %-10u\n\nLast phases:", - host->stats.queues, host->stats.removes, - host->stats.fins, host->stats.reads, - host->stats.writes, host->stats.miscs, - host->stats.disconnects, host->stats.aborts, - host->stats.resets); - - for (devidx = 0; devidx < 9; devidx ++) { - unsigned int statptr, prev; - - p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx)); - statptr = host->status_ptr[devidx] - 10; - - if ((signed int)statptr < 0) - statptr += STATUS_BUFFER_SIZE; - - prev = host->status[devidx][statptr].when; - - for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) { - if (host->status[devidx][statptr].when) { - p += sprintf(p, "%c%02X:%02X+%2ld", - host->status[devidx][statptr].irq ? '-' : ' ', - host->status[devidx][statptr].ph, - host->status[devidx][statptr].ssr, - (host->status[devidx][statptr].when - prev) < 100 ? - (host->status[devidx][statptr].when - prev) : 99); - prev = host->status[devidx][statptr].when; - } - } - } - - p += sprintf(p, "\nAttached devices:\n"); - - shost_for_each_device(scd, instance) { - p += sprintf(p, "Device/Lun TaggedQ Sync\n"); - p += sprintf(p, " %d/%d ", scd->id, scd->lun); - if (scd->tagged_supported) - p += sprintf(p, "%3sabled(%3d) ", - scd->simple_tags ? "en" : "dis", - scd->current_tag); - else - p += sprintf(p, "unsupported "); - - if (host->device[scd->id].sync_xfer & 15) - p += sprintf(p, "offset %d, %d ns\n", - host->device[scd->id].sync_xfer & 15, - acornscsi_getperiod(host->device[scd->id].sync_xfer)); - else - p += sprintf(p, "async\n"); - - pos = p - buffer; - if (pos + begin < offset) { - begin += pos; - p = buffer; - } - pos = p - buffer; - if (pos + begin > offset + length) { - scsi_device_put(scd); - break; - } - } - - pos = p - buffer; - - *start = buffer + (offset - begin); - pos -= offset - begin; - - if (pos > length) - pos = length; - - return pos; -} - -static struct scsi_host_template acornscsi_template = { - .module = THIS_MODULE, - .proc_info = acornscsi_proc_info, - .name = "AcornSCSI", - .info = acornscsi_info, - .queuecommand = acornscsi_queuecmd, - .eh_abort_handler = acornscsi_abort, - .eh_bus_reset_handler = acornscsi_bus_reset, - .can_queue = 16, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 2, - .use_clustering = DISABLE_CLUSTERING, - .proc_name = "acornscsi", -}; - -static int __devinit -acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct Scsi_Host *host; - AS_Host *ashost; - int ret; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - host = scsi_host_alloc(&acornscsi_template, sizeof(AS_Host)); - if (!host) { - ret = -ENOMEM; - goto out_release; - } - - ashost = (AS_Host *)host->hostdata; - - ashost->base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); - ashost->fast = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); - if (!ashost->base || !ashost->fast) - goto out_put; - - host->irq = ec->irq; - ashost->host = host; - ashost->scsi.irq = host->irq; - - ec->irqaddr = ashost->fast + INT_REG; - ec->irqmask = 0x0a; - - ret = request_irq(host->irq, acornscsi_intr, IRQF_DISABLED, "acornscsi", ashost); - if (ret) { - printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n", - host->host_no, ashost->scsi.irq, ret); - goto out_put; - } - - memset(&ashost->stats, 0, sizeof (ashost->stats)); - queue_initialise(&ashost->queues.issue); - queue_initialise(&ashost->queues.disconnected); - msgqueue_initialise(&ashost->scsi.msgs); - - acornscsi_resetcard(ashost); - - ret = scsi_add_host(host, &ec->dev); - if (ret) - goto out_irq; - - scsi_scan_host(host); - goto out; - - out_irq: - free_irq(host->irq, ashost); - msgqueue_free(&ashost->scsi.msgs); - queue_free(&ashost->queues.disconnected); - queue_free(&ashost->queues.issue); - out_put: - ecardm_iounmap(ec, ashost->fast); - ecardm_iounmap(ec, ashost->base); - scsi_host_put(host); - out_release: - ecard_release_resources(ec); - out: - return ret; -} - -static void __devexit acornscsi_remove(struct expansion_card *ec) -{ - struct Scsi_Host *host = ecard_get_drvdata(ec); - AS_Host *ashost = (AS_Host *)host->hostdata; - - ecard_set_drvdata(ec, NULL); - scsi_remove_host(host); - - /* - * Put card into RESET state - */ - writeb(0x80, ashost->fast + PAGE_REG); - - free_irq(host->irq, ashost); - - msgqueue_free(&ashost->scsi.msgs); - queue_free(&ashost->queues.disconnected); - queue_free(&ashost->queues.issue); - ecardm_iounmap(ec, ashost->fast); - ecardm_iounmap(ec, ashost->base); - scsi_host_put(host); - ecard_release_resources(ec); -} - -static const struct ecard_id acornscsi_cids[] = { - { MANU_ACORN, PROD_ACORN_SCSI }, - { 0xffff, 0xffff }, -}; - -static struct ecard_driver acornscsi_driver = { - .probe = acornscsi_probe, - .remove = __devexit_p(acornscsi_remove), - .id_table = acornscsi_cids, - .drv = { - .name = "acornscsi", - }, -}; - -static int __init acornscsi_init(void) -{ - return ecard_register_driver(&acornscsi_driver); -} - -static void __exit acornscsi_exit(void) -{ - ecard_remove_driver(&acornscsi_driver); -} - -module_init(acornscsi_init); -module_exit(acornscsi_exit); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("AcornSCSI driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/arm/acornscsi.h b/ANDROID_3.4.5/drivers/scsi/arm/acornscsi.h deleted file mode 100644 index 01bc715a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/acornscsi.h +++ /dev/null @@ -1,353 +0,0 @@ -/* - * linux/drivers/acorn/scsi/acornscsi.h - * - * Copyright (C) 1997 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Acorn SCSI driver - */ -#ifndef ACORNSCSI_H -#define ACORNSCSI_H - -/* SBIC registers */ -#define SBIC_OWNID 0 -#define OWNID_FS1 (1<<7) -#define OWNID_FS2 (1<<6) -#define OWNID_EHP (1<<4) -#define OWNID_EAF (1<<3) - -#define SBIC_CTRL 1 -#define CTRL_DMAMODE (1<<7) -#define CTRL_DMADBAMODE (1<<6) -#define CTRL_DMABURST (1<<5) -#define CTRL_DMAPOLLED 0 -#define CTRL_HHP (1<<4) -#define CTRL_EDI (1<<3) -#define CTRL_IDI (1<<2) -#define CTRL_HA (1<<1) -#define CTRL_HSP (1<<0) - -#define SBIC_TIMEOUT 2 -#define SBIC_TOTSECTS 3 -#define SBIC_TOTHEADS 4 -#define SBIC_TOTCYLH 5 -#define SBIC_TOTCYLL 6 -#define SBIC_LOGADDRH 7 -#define SBIC_LOGADDRM2 8 -#define SBIC_LOGADDRM1 9 -#define SBIC_LOGADDRL 10 -#define SBIC_SECTORNUM 11 -#define SBIC_HEADNUM 12 -#define SBIC_CYLH 13 -#define SBIC_CYLL 14 -#define SBIC_TARGETLUN 15 -#define TARGETLUN_TLV (1<<7) -#define TARGETLUN_DOK (1<<6) - -#define SBIC_CMNDPHASE 16 -#define SBIC_SYNCHTRANSFER 17 -#define SYNCHTRANSFER_OF0 0x00 -#define SYNCHTRANSFER_OF1 0x01 -#define SYNCHTRANSFER_OF2 0x02 -#define SYNCHTRANSFER_OF3 0x03 -#define SYNCHTRANSFER_OF4 0x04 -#define SYNCHTRANSFER_OF5 0x05 -#define SYNCHTRANSFER_OF6 0x06 -#define SYNCHTRANSFER_OF7 0x07 -#define SYNCHTRANSFER_OF8 0x08 -#define SYNCHTRANSFER_OF9 0x09 -#define SYNCHTRANSFER_OF10 0x0A -#define SYNCHTRANSFER_OF11 0x0B -#define SYNCHTRANSFER_OF12 0x0C -#define SYNCHTRANSFER_8DBA 0x00 -#define SYNCHTRANSFER_2DBA 0x20 -#define SYNCHTRANSFER_3DBA 0x30 -#define SYNCHTRANSFER_4DBA 0x40 -#define SYNCHTRANSFER_5DBA 0x50 -#define SYNCHTRANSFER_6DBA 0x60 -#define SYNCHTRANSFER_7DBA 0x70 - -#define SBIC_TRANSCNTH 18 -#define SBIC_TRANSCNTM 19 -#define SBIC_TRANSCNTL 20 -#define SBIC_DESTID 21 -#define DESTID_SCC (1<<7) -#define DESTID_DPD (1<<6) - -#define SBIC_SOURCEID 22 -#define SOURCEID_ER (1<<7) -#define SOURCEID_ES (1<<6) -#define SOURCEID_DSP (1<<5) -#define SOURCEID_SIV (1<<4) - -#define SBIC_SSR 23 -#define SBIC_CMND 24 -#define CMND_RESET 0x00 -#define CMND_ABORT 0x01 -#define CMND_ASSERTATN 0x02 -#define CMND_NEGATEACK 0x03 -#define CMND_DISCONNECT 0x04 -#define CMND_RESELECT 0x05 -#define CMND_SELWITHATN 0x06 -#define CMND_SELECT 0x07 -#define CMND_SELECTATNTRANSFER 0x08 -#define CMND_SELECTTRANSFER 0x09 -#define CMND_RESELECTRXDATA 0x0A -#define CMND_RESELECTTXDATA 0x0B -#define CMND_WAITFORSELRECV 0x0C -#define CMND_SENDSTATCMD 0x0D -#define CMND_SENDDISCONNECT 0x0E -#define CMND_SETIDI 0x0F -#define CMND_RECEIVECMD 0x10 -#define CMND_RECEIVEDTA 0x11 -#define CMND_RECEIVEMSG 0x12 -#define CMND_RECEIVEUSP 0x13 -#define CMND_SENDCMD 0x14 -#define CMND_SENDDATA 0x15 -#define CMND_SENDMSG 0x16 -#define CMND_SENDUSP 0x17 -#define CMND_TRANSLATEADDR 0x18 -#define CMND_XFERINFO 0x20 -#define CMND_SBT (1<<7) - -#define SBIC_DATA 25 -#define SBIC_ASR 26 -#define ASR_INT (1<<7) -#define ASR_LCI (1<<6) -#define ASR_BSY (1<<5) -#define ASR_CIP (1<<4) -#define ASR_PE (1<<1) -#define ASR_DBR (1<<0) - -/* DMAC registers */ -#define DMAC_INIT 0x00 -#define INIT_8BIT (1) - -#define DMAC_CHANNEL 0x80 -#define CHANNEL_0 0x00 -#define CHANNEL_1 0x01 -#define CHANNEL_2 0x02 -#define CHANNEL_3 0x03 - -#define DMAC_TXCNTLO 0x01 -#define DMAC_TXCNTHI 0x81 -#define DMAC_TXADRLO 0x02 -#define DMAC_TXADRMD 0x82 -#define DMAC_TXADRHI 0x03 - -#define DMAC_DEVCON0 0x04 -#define DEVCON0_AKL (1<<7) -#define DEVCON0_RQL (1<<6) -#define DEVCON0_EXW (1<<5) -#define DEVCON0_ROT (1<<4) -#define DEVCON0_CMP (1<<3) -#define DEVCON0_DDMA (1<<2) -#define DEVCON0_AHLD (1<<1) -#define DEVCON0_MTM (1<<0) - -#define DMAC_DEVCON1 0x84 -#define DEVCON1_WEV (1<<1) -#define DEVCON1_BHLD (1<<0) - -#define DMAC_MODECON 0x05 -#define MODECON_WOED 0x01 -#define MODECON_VERIFY 0x00 -#define MODECON_READ 0x04 -#define MODECON_WRITE 0x08 -#define MODECON_AUTOINIT 0x10 -#define MODECON_ADDRDIR 0x20 -#define MODECON_DEMAND 0x00 -#define MODECON_SINGLE 0x40 -#define MODECON_BLOCK 0x80 -#define MODECON_CASCADE 0xC0 - -#define DMAC_STATUS 0x85 -#define STATUS_TC0 (1<<0) -#define STATUS_RQ0 (1<<4) - -#define DMAC_TEMPLO 0x06 -#define DMAC_TEMPHI 0x86 -#define DMAC_REQREG 0x07 -#define DMAC_MASKREG 0x87 -#define MASKREG_M0 0x01 -#define MASKREG_M1 0x02 -#define MASKREG_M2 0x04 -#define MASKREG_M3 0x08 - -/* miscellaneous internal variables */ - -#define MASK_ON (MASKREG_M3|MASKREG_M2|MASKREG_M1|MASKREG_M0) -#define MASK_OFF (MASKREG_M3|MASKREG_M2|MASKREG_M1) - -/* - * SCSI driver phases - */ -typedef enum { - PHASE_IDLE, /* we're not planning on doing anything */ - PHASE_CONNECTING, /* connecting to a target */ - PHASE_CONNECTED, /* connected to a target */ - PHASE_MSGOUT, /* message out to device */ - PHASE_RECONNECTED, /* reconnected */ - PHASE_COMMANDPAUSED, /* command partly sent */ - PHASE_COMMAND, /* command all sent */ - PHASE_DATAOUT, /* data out to device */ - PHASE_DATAIN, /* data in from device */ - PHASE_STATUSIN, /* status in from device */ - PHASE_MSGIN, /* message in from device */ - PHASE_DONE, /* finished */ - PHASE_ABORTED, /* aborted */ - PHASE_DISCONNECT, /* disconnecting */ -} phase_t; - -/* - * After interrupt, what to do now - */ -typedef enum { - INTR_IDLE, /* not expecting another IRQ */ - INTR_NEXT_COMMAND, /* start next command */ - INTR_PROCESSING, /* interrupt routine still processing */ -} intr_ret_t; - -/* - * DMA direction - */ -typedef enum { - DMA_OUT, /* DMA from memory to chip */ - DMA_IN /* DMA from chip to memory */ -} dmadir_t; - -/* - * Synchronous transfer state - */ -typedef enum { /* Synchronous transfer state */ - SYNC_ASYNCHRONOUS, /* don't negotiate synchronous transfers*/ - SYNC_NEGOCIATE, /* start negotiation */ - SYNC_SENT_REQUEST, /* sent SDTR message */ - SYNC_COMPLETED, /* received SDTR reply */ -} syncxfer_t; - -/* - * Command type - */ -typedef enum { /* command type */ - CMD_READ, /* READ_6, READ_10, READ_12 */ - CMD_WRITE, /* WRITE_6, WRITE_10, WRITE_12 */ - CMD_MISC, /* Others */ -} cmdtype_t; - -/* - * Data phase direction - */ -typedef enum { /* Data direction */ - DATADIR_IN, /* Data in phase expected */ - DATADIR_OUT /* Data out phase expected */ -} datadir_t; - -#include "queue.h" -#include "msgqueue.h" - -#define STATUS_BUFFER_SIZE 32 -/* - * This is used to dump the previous states of the SBIC - */ -struct status_entry { - unsigned long when; - unsigned char ssr; - unsigned char ph; - unsigned char irq; - unsigned char unused; -}; - -#define ADD_STATUS(_q,_ssr,_ph,_irq) \ -({ \ - host->status[(_q)][host->status_ptr[(_q)]].when = jiffies; \ - host->status[(_q)][host->status_ptr[(_q)]].ssr = (_ssr); \ - host->status[(_q)][host->status_ptr[(_q)]].ph = (_ph); \ - host->status[(_q)][host->status_ptr[(_q)]].irq = (_irq); \ - host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \ -}) - -/* - * AcornSCSI host specific data - */ -typedef struct acornscsi_hostdata { - /* miscellaneous */ - struct Scsi_Host *host; /* host */ - struct scsi_cmnd *SCpnt; /* currently processing command */ - struct scsi_cmnd *origSCpnt; /* original connecting command */ - void __iomem *base; /* memc base address */ - void __iomem *fast; /* fast ioc base address */ - - /* driver information */ - struct { - unsigned int irq; /* interrupt */ - phase_t phase; /* current phase */ - - struct { - unsigned char target; /* reconnected target */ - unsigned char lun; /* reconnected lun */ - unsigned char tag; /* reconnected tag */ - } reconnected; - - struct scsi_pointer SCp; /* current commands data pointer */ - - MsgQueue_t msgs; - - unsigned short last_message; /* last message to be sent */ - unsigned char disconnectable:1; /* this command can be disconnected */ - } scsi; - - /* statistics information */ - struct { - unsigned int queues; - unsigned int removes; - unsigned int fins; - unsigned int reads; - unsigned int writes; - unsigned int miscs; - unsigned int disconnects; - unsigned int aborts; - unsigned int resets; - } stats; - - /* queue handling */ - struct { - Queue_t issue; /* issue queue */ - Queue_t disconnected; /* disconnected command queue */ - } queues; - - /* per-device info */ - struct { - unsigned char sync_xfer; /* synchronous transfer (SBIC value) */ - syncxfer_t sync_state; /* sync xfer negotiation state */ - unsigned char disconnect_ok:1; /* device can disconnect */ - } device[8]; - unsigned long busyluns[64 / sizeof(unsigned long)];/* array of bits indicating LUNs busy */ - - /* DMA info */ - struct { - unsigned int free_addr; /* next free address */ - unsigned int start_addr; /* start address of current transfer */ - dmadir_t direction; /* dma direction */ - unsigned int transferred; /* number of bytes transferred */ - unsigned int xfer_start; /* scheduled DMA transfer start */ - unsigned int xfer_length; /* scheduled DMA transfer length */ - char *xfer_ptr; /* pointer to area */ - unsigned char xfer_required:1; /* set if we need to transfer something */ - unsigned char xfer_setup:1; /* set if DMA is setup */ - unsigned char xfer_done:1; /* set if DMA reached end of BH list */ - } dma; - - /* card info */ - struct { - unsigned char page_reg; /* current setting of page reg */ - } card; - - unsigned char status_ptr[9]; - struct status_entry status[9][STATUS_BUFFER_SIZE]; -} AS_Host; - -#endif /* ACORNSCSI_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/arm/arxescsi.c b/ANDROID_3.4.5/drivers/scsi/arm/arxescsi.c deleted file mode 100644 index 2a28b4ad..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/arxescsi.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * linux/drivers/scsi/arm/arxescsi.c - * - * Copyright (C) 1997-2000 Russell King, Stefan Hanske - * - * This driver is based on experimentation. Hence, it may have made - * assumptions about the particular card that I have available, and - * may not be reliable! - * - * Changelog: - * 30-08-1997 RMK 0.0.0 Created, READONLY version as cumana_2.c - * 22-01-1998 RMK 0.0.1 Updated to 2.1.80 - * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. - * 11-06-1998 SH 0.0.2 Changed to support ARXE 16-bit SCSI card - * enabled writing - * 01-01-2000 SH 0.1.0 Added *real* pseudo dma writing - * (arxescsi_pseudo_dma_write) - * 02-04-2000 RMK 0.1.1 Updated for new error handling code. - * 22-10-2000 SH Updated for new registering scheme. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "../scsi.h" -#include -#include "fas216.h" - -struct arxescsi_info { - FAS216_Info info; - struct expansion_card *ec; - void __iomem *base; -}; - -#define DMADATA_OFFSET (0x200) - -#define DMASTAT_OFFSET (0x600) -#define DMASTAT_DRQ (1 << 0) - -#define CSTATUS_IRQ (1 << 0) - -#define VERSION "1.10 (23/01/2003 2.5.57)" - -/* - * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type) - * Purpose : initialises DMA/PIO - * Params : host - host - * SCpnt - command - * direction - DMA on to/off of card - * min_type - minimum DMA support that we must have for this transfer - * Returns : 0 if we should not set CMD_WITHDMA for transfer info command - */ -static fasdmatype_t -arxescsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp, - fasdmadir_t direction, fasdmatype_t min_type) -{ - /* - * We don't do real DMA - */ - return fasdma_pseudo; -} - -static void arxescsi_pseudo_dma_write(unsigned char *addr, void __iomem *base) -{ - __asm__ __volatile__( - " stmdb sp!, {r0-r12}\n" - " mov r3, %0\n" - " mov r1, %1\n" - " add r2, r1, #512\n" - " mov r4, #256\n" - ".loop_1: ldmia r3!, {r6, r8, r10, r12}\n" - " mov r5, r6, lsl #16\n" - " mov r7, r8, lsl #16\n" - ".loop_2: ldrb r0, [r1, #1536]\n" - " tst r0, #1\n" - " beq .loop_2\n" - " stmia r2, {r5-r8}\n\t" - " mov r9, r10, lsl #16\n" - " mov r11, r12, lsl #16\n" - ".loop_3: ldrb r0, [r1, #1536]\n" - " tst r0, #1\n" - " beq .loop_3\n" - " stmia r2, {r9-r12}\n" - " subs r4, r4, #16\n" - " bne .loop_1\n" - " ldmia sp!, {r0-r12}\n" - : - : "r" (addr), "r" (base)); -} - -/* - * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer) - * Purpose : handles pseudo DMA - * Params : host - host - * SCpnt - command - * direction - DMA on to/off of card - * transfer - minimum number of bytes we expect to transfer - */ -static void -arxescsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp, - fasdmadir_t direction, int transfer) -{ - struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata; - unsigned int length, error = 0; - void __iomem *base = info->info.scsi.io_base; - unsigned char *addr; - - length = SCp->this_residual; - addr = SCp->ptr; - - if (direction == DMA_OUT) { - unsigned int word; - while (length > 256) { - if (readb(base + 0x80) & STAT_INT) { - error = 1; - break; - } - arxescsi_pseudo_dma_write(addr, base); - addr += 256; - length -= 256; - } - - if (!error) - while (length > 0) { - if (readb(base + 0x80) & STAT_INT) - break; - - if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) - continue; - - word = *addr | *(addr + 1) << 8; - - writew(word, base + DMADATA_OFFSET); - if (length > 1) { - addr += 2; - length -= 2; - } else { - addr += 1; - length -= 1; - } - } - } - else { - if (transfer && (transfer & 255)) { - while (length >= 256) { - if (readb(base + 0x80) & STAT_INT) { - error = 1; - break; - } - - if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) - continue; - - readsw(base + DMADATA_OFFSET, addr, 256 >> 1); - addr += 256; - length -= 256; - } - } - - if (!(error)) - while (length > 0) { - unsigned long word; - - if (readb(base + 0x80) & STAT_INT) - break; - - if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ)) - continue; - - word = readw(base + DMADATA_OFFSET); - *addr++ = word; - if (--length > 0) { - *addr++ = word >> 8; - length --; - } - } - } -} - -/* - * Function: int arxescsi_dma_stop(host, SCpnt) - * Purpose : stops DMA/PIO - * Params : host - host - * SCpnt - command - */ -static void arxescsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp) -{ - /* - * no DMA to stop - */ -} - -/* - * Function: const char *arxescsi_info(struct Scsi_Host * host) - * Purpose : returns a descriptive string about this interface, - * Params : host - driver host structure to return info for. - * Returns : pointer to a static buffer containing null terminated string. - */ -static const char *arxescsi_info(struct Scsi_Host *host) -{ - struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata; - static char string[150]; - - sprintf(string, "%s (%s) in slot %d v%s", - host->hostt->name, info->info.scsi.type, info->ec->slot_no, - VERSION); - - return string; -} - -/* - * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset, - * int length, int host_no, int inout) - * Purpose : Return information about the driver to a user process accessing - * the /proc filesystem. - * Params : buffer - a buffer to write information to - * start - a pointer into this buffer set by this routine to the start - * of the required information. - * offset - offset into information that we have read up to. - * length - length of buffer - * host_no - host number to return information for - * inout - 0 for reading, 1 for writing. - * Returns : length of data written to buffer. - */ -static int -arxescsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, - int inout) -{ - struct arxescsi_info *info; - char *p = buffer; - int pos; - - info = (struct arxescsi_info *)host->hostdata; - if (inout == 1) - return -EINVAL; - - p += sprintf(p, "ARXE 16-bit SCSI driver v%s\n", VERSION); - p += fas216_print_host(&info->info, p); - p += fas216_print_stats(&info->info, p); - p += fas216_print_devices(&info->info, p); - - *start = buffer + offset; - pos = p - buffer - offset; - if (pos > length) - pos = length; - - return pos; -} - -static struct scsi_host_template arxescsi_template = { - .proc_info = arxescsi_proc_info, - .name = "ARXE SCSI card", - .info = arxescsi_info, - .queuecommand = fas216_noqueue_command, - .eh_host_reset_handler = fas216_eh_host_reset, - .eh_bus_reset_handler = fas216_eh_bus_reset, - .eh_device_reset_handler = fas216_eh_device_reset, - .eh_abort_handler = fas216_eh_abort, - .can_queue = 0, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, - .proc_name = "arxescsi", -}; - -static int __devinit -arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct Scsi_Host *host; - struct arxescsi_info *info; - void __iomem *base; - int ret; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); - if (!base) { - ret = -ENOMEM; - goto out_region; - } - - host = scsi_host_alloc(&arxescsi_template, sizeof(struct arxescsi_info)); - if (!host) { - ret = -ENOMEM; - goto out_region; - } - - info = (struct arxescsi_info *)host->hostdata; - info->ec = ec; - info->base = base; - - info->info.scsi.io_base = base + 0x2000; - info->info.scsi.irq = 0; - info->info.scsi.dma = NO_DMA; - info->info.scsi.io_shift = 5; - info->info.ifcfg.clockrate = 24; /* MHz */ - info->info.ifcfg.select_timeout = 255; - info->info.ifcfg.asyncperiod = 200; /* ns */ - info->info.ifcfg.sync_max_depth = 0; - info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; - info->info.ifcfg.disconnect_ok = 0; - info->info.ifcfg.wide_max_size = 0; - info->info.ifcfg.capabilities = FASCAP_PSEUDODMA; - info->info.dma.setup = arxescsi_dma_setup; - info->info.dma.pseudo = arxescsi_dma_pseudo; - info->info.dma.stop = arxescsi_dma_stop; - - ec->irqaddr = base; - ec->irqmask = CSTATUS_IRQ; - - ret = fas216_init(host); - if (ret) - goto out_unregister; - - ret = fas216_add(host, &ec->dev); - if (ret == 0) - goto out; - - fas216_release(host); - out_unregister: - scsi_host_put(host); - out_region: - ecard_release_resources(ec); - out: - return ret; -} - -static void __devexit arxescsi_remove(struct expansion_card *ec) -{ - struct Scsi_Host *host = ecard_get_drvdata(ec); - - ecard_set_drvdata(ec, NULL); - fas216_remove(host); - - fas216_release(host); - scsi_host_put(host); - ecard_release_resources(ec); -} - -static const struct ecard_id arxescsi_cids[] = { - { MANU_ARXE, PROD_ARXE_SCSI }, - { 0xffff, 0xffff }, -}; - -static struct ecard_driver arxescsi_driver = { - .probe = arxescsi_probe, - .remove = __devexit_p(arxescsi_remove), - .id_table = arxescsi_cids, - .drv = { - .name = "arxescsi", - }, -}; - -static int __init init_arxe_scsi_driver(void) -{ - return ecard_register_driver(&arxescsi_driver); -} - -static void __exit exit_arxe_scsi_driver(void) -{ - ecard_remove_driver(&arxescsi_driver); -} - -module_init(init_arxe_scsi_driver); -module_exit(exit_arxe_scsi_driver); - -MODULE_AUTHOR("Stefan Hanske"); -MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines"); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/scsi/arm/cumana_1.c b/ANDROID_3.4.5/drivers/scsi/arm/cumana_1.c deleted file mode 100644 index c3b99c93..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/cumana_1.c +++ /dev/null @@ -1,344 +0,0 @@ -/* - * Generic Generic NCR5380 driver - * - * Copyright 1995-2002, Russell King - */ -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "../scsi.h" -#include - -#include - -#define AUTOSENSE -#define PSEUDO_DMA - -#define CUMANASCSI_PUBLIC_RELEASE 1 - -#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata) -#define NCR5380_local_declare() struct Scsi_Host *_instance -#define NCR5380_setup(instance) _instance = instance -#define NCR5380_read(reg) cumanascsi_read(_instance, reg) -#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value) -#define NCR5380_intr cumanascsi_intr -#define NCR5380_queue_command cumanascsi_queue_command -#define NCR5380_proc_info cumanascsi_proc_info - -#define NCR5380_implementation_fields \ - unsigned ctrl; \ - void __iomem *base; \ - void __iomem *dma - -#define BOARD_NORMAL 0 -#define BOARD_NCR53C400 1 - -#include "../NCR5380.h" - -void cumanascsi_setup(char *str, int *ints) -{ -} - -const char *cumanascsi_info(struct Scsi_Host *spnt) -{ - return ""; -} - -#define CTRL 0x16fc -#define STAT 0x2004 -#define L(v) (((v)<<16)|((v) & 0x0000ffff)) -#define H(v) (((v)>>16)|((v) & 0xffff0000)) - -static inline int -NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr, int len) -{ - unsigned long *laddr; - void __iomem *dma = priv(host)->dma + 0x2000; - - if(!len) return 0; - - writeb(0x02, priv(host)->base + CTRL); - laddr = (unsigned long *)addr; - while(len >= 32) - { - unsigned int status; - unsigned long v; - status = readb(priv(host)->base + STAT); - if(status & 0x80) - goto end; - if(!(status & 0x40)) - continue; - v=*laddr++; writew(L(v), dma); writew(H(v), dma); - v=*laddr++; writew(L(v), dma); writew(H(v), dma); - v=*laddr++; writew(L(v), dma); writew(H(v), dma); - v=*laddr++; writew(L(v), dma); writew(H(v), dma); - v=*laddr++; writew(L(v), dma); writew(H(v), dma); - v=*laddr++; writew(L(v), dma); writew(H(v), dma); - v=*laddr++; writew(L(v), dma); writew(H(v), dma); - v=*laddr++; writew(L(v), dma); writew(H(v), dma); - len -= 32; - if(len == 0) - break; - } - - addr = (unsigned char *)laddr; - writeb(0x12, priv(host)->base + CTRL); - - while(len > 0) - { - unsigned int status; - status = readb(priv(host)->base + STAT); - if(status & 0x80) - goto end; - if(status & 0x40) - { - writeb(*addr++, dma); - if(--len == 0) - break; - } - - status = readb(priv(host)->base + STAT); - if(status & 0x80) - goto end; - if(status & 0x40) - { - writeb(*addr++, dma); - if(--len == 0) - break; - } - } -end: - writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL); - return len; -} - -static inline int -NCR5380_pread(struct Scsi_Host *host, unsigned char *addr, int len) -{ - unsigned long *laddr; - void __iomem *dma = priv(host)->dma + 0x2000; - - if(!len) return 0; - - writeb(0x00, priv(host)->base + CTRL); - laddr = (unsigned long *)addr; - while(len >= 32) - { - unsigned int status; - status = readb(priv(host)->base + STAT); - if(status & 0x80) - goto end; - if(!(status & 0x40)) - continue; - *laddr++ = readw(dma) | (readw(dma) << 16); - *laddr++ = readw(dma) | (readw(dma) << 16); - *laddr++ = readw(dma) | (readw(dma) << 16); - *laddr++ = readw(dma) | (readw(dma) << 16); - *laddr++ = readw(dma) | (readw(dma) << 16); - *laddr++ = readw(dma) | (readw(dma) << 16); - *laddr++ = readw(dma) | (readw(dma) << 16); - *laddr++ = readw(dma) | (readw(dma) << 16); - len -= 32; - if(len == 0) - break; - } - - addr = (unsigned char *)laddr; - writeb(0x10, priv(host)->base + CTRL); - - while(len > 0) - { - unsigned int status; - status = readb(priv(host)->base + STAT); - if(status & 0x80) - goto end; - if(status & 0x40) - { - *addr++ = readb(dma); - if(--len == 0) - break; - } - - status = readb(priv(host)->base + STAT); - if(status & 0x80) - goto end; - if(status & 0x40) - { - *addr++ = readb(dma); - if(--len == 0) - break; - } - } -end: - writeb(priv(host)->ctrl | 0x40, priv(host)->base + CTRL); - return len; -} - -static unsigned char cumanascsi_read(struct Scsi_Host *host, unsigned int reg) -{ - void __iomem *base = priv(host)->base; - unsigned char val; - - writeb(0, base + CTRL); - - val = readb(base + 0x2100 + (reg << 2)); - - priv(host)->ctrl = 0x40; - writeb(0x40, base + CTRL); - - return val; -} - -static void cumanascsi_write(struct Scsi_Host *host, unsigned int reg, unsigned int value) -{ - void __iomem *base = priv(host)->base; - - writeb(0, base + CTRL); - - writeb(value, base + 0x2100 + (reg << 2)); - - priv(host)->ctrl = 0x40; - writeb(0x40, base + CTRL); -} - -#include "../NCR5380.c" - -static struct scsi_host_template cumanascsi_template = { - .module = THIS_MODULE, - .name = "Cumana 16-bit SCSI", - .info = cumanascsi_info, - .queuecommand = cumanascsi_queue_command, - .eh_abort_handler = NCR5380_abort, - .eh_bus_reset_handler = NCR5380_bus_reset, - .can_queue = 16, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 2, - .use_clustering = DISABLE_CLUSTERING, - .proc_name = "CumanaSCSI-1", -}; - -static int __devinit -cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct Scsi_Host *host; - int ret; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata)); - if (!host) { - ret = -ENOMEM; - goto out_release; - } - - priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_IOCSLOW), - ecard_resource_len(ec, ECARD_RES_IOCSLOW)); - priv(host)->dma = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), - ecard_resource_len(ec, ECARD_RES_MEMC)); - if (!priv(host)->base || !priv(host)->dma) { - ret = -ENOMEM; - goto out_unmap; - } - - host->irq = ec->irq; - - NCR5380_init(host, 0); - - priv(host)->ctrl = 0; - writeb(0, priv(host)->base + CTRL); - - host->n_io_port = 255; - if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) { - ret = -EBUSY; - goto out_unmap; - } - - ret = request_irq(host->irq, cumanascsi_intr, IRQF_DISABLED, - "CumanaSCSI-1", host); - if (ret) { - printk("scsi%d: IRQ%d not free: %d\n", - host->host_no, host->irq, ret); - goto out_unmap; - } - - printk("scsi%d: at port 0x%08lx irq %d", - host->host_no, host->io_port, host->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - host->can_queue, host->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE); - printk("\nscsi%d:", host->host_no); - NCR5380_print_options(host); - printk("\n"); - - ret = scsi_add_host(host, &ec->dev); - if (ret) - goto out_free_irq; - - scsi_scan_host(host); - goto out; - - out_free_irq: - free_irq(host->irq, host); - out_unmap: - iounmap(priv(host)->base); - iounmap(priv(host)->dma); - scsi_host_put(host); - out_release: - ecard_release_resources(ec); - out: - return ret; -} - -static void __devexit cumanascsi1_remove(struct expansion_card *ec) -{ - struct Scsi_Host *host = ecard_get_drvdata(ec); - - ecard_set_drvdata(ec, NULL); - - scsi_remove_host(host); - free_irq(host->irq, host); - NCR5380_exit(host); - iounmap(priv(host)->base); - iounmap(priv(host)->dma); - scsi_host_put(host); - ecard_release_resources(ec); -} - -static const struct ecard_id cumanascsi1_cids[] = { - { MANU_CUMANA, PROD_CUMANA_SCSI_1 }, - { 0xffff, 0xffff } -}; - -static struct ecard_driver cumanascsi1_driver = { - .probe = cumanascsi1_probe, - .remove = __devexit_p(cumanascsi1_remove), - .id_table = cumanascsi1_cids, - .drv = { - .name = "cumanascsi1", - }, -}; - -static int __init cumanascsi_init(void) -{ - return ecard_register_driver(&cumanascsi1_driver); -} - -static void __exit cumanascsi_exit(void) -{ - ecard_remove_driver(&cumanascsi1_driver); -} - -module_init(cumanascsi_init); -module_exit(cumanascsi_exit); - -MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/arm/cumana_2.c b/ANDROID_3.4.5/drivers/scsi/arm/cumana_2.c deleted file mode 100644 index 547987b8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/cumana_2.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * linux/drivers/acorn/scsi/cumana_2.c - * - * Copyright (C) 1997-2005 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 30-08-1997 RMK 0.0.0 Created, READONLY version. - * 22-01-1998 RMK 0.0.1 Updated to 2.1.80. - * 15-04-1998 RMK 0.0.1 Only do PIO if FAS216 will allow it. - * 02-05-1998 RMK 0.0.2 Updated & added DMA support. - * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h - * 18-08-1998 RMK 0.0.3 Fixed synchronous transfer depth. - * 02-04-2000 RMK 0.0.4 Updated for new error handling code. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../scsi.h" -#include -#include "fas216.h" -#include "scsi.h" - -#include - -#define CUMANASCSI2_STATUS (0x0000) -#define STATUS_INT (1 << 0) -#define STATUS_DRQ (1 << 1) -#define STATUS_LATCHED (1 << 3) - -#define CUMANASCSI2_ALATCH (0x0014) -#define ALATCH_ENA_INT (3) -#define ALATCH_DIS_INT (2) -#define ALATCH_ENA_TERM (5) -#define ALATCH_DIS_TERM (4) -#define ALATCH_ENA_BIT32 (11) -#define ALATCH_DIS_BIT32 (10) -#define ALATCH_ENA_DMA (13) -#define ALATCH_DIS_DMA (12) -#define ALATCH_DMA_OUT (15) -#define ALATCH_DMA_IN (14) - -#define CUMANASCSI2_PSEUDODMA (0x0200) - -#define CUMANASCSI2_FAS216_OFFSET (0x0300) -#define CUMANASCSI2_FAS216_SHIFT 2 - -/* - * Version - */ -#define VERSION "1.00 (13/11/2002 2.5.47)" - -/* - * Use term=0,1,0,0,0 to turn terminators on/off - */ -static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; - -#define NR_SG 256 - -struct cumanascsi2_info { - FAS216_Info info; - struct expansion_card *ec; - void __iomem *base; - unsigned int terms; /* Terminator state */ - struct scatterlist sg[NR_SG]; /* Scatter DMA list */ -}; - -#define CSTATUS_IRQ (1 << 0) -#define CSTATUS_DRQ (1 << 1) - -/* Prototype: void cumanascsi_2_irqenable(ec, irqnr) - * Purpose : Enable interrupts on Cumana SCSI 2 card - * Params : ec - expansion card structure - * : irqnr - interrupt number - */ -static void -cumanascsi_2_irqenable(struct expansion_card *ec, int irqnr) -{ - struct cumanascsi2_info *info = ec->irq_data; - writeb(ALATCH_ENA_INT, info->base + CUMANASCSI2_ALATCH); -} - -/* Prototype: void cumanascsi_2_irqdisable(ec, irqnr) - * Purpose : Disable interrupts on Cumana SCSI 2 card - * Params : ec - expansion card structure - * : irqnr - interrupt number - */ -static void -cumanascsi_2_irqdisable(struct expansion_card *ec, int irqnr) -{ - struct cumanascsi2_info *info = ec->irq_data; - writeb(ALATCH_DIS_INT, info->base + CUMANASCSI2_ALATCH); -} - -static const expansioncard_ops_t cumanascsi_2_ops = { - .irqenable = cumanascsi_2_irqenable, - .irqdisable = cumanascsi_2_irqdisable, -}; - -/* Prototype: void cumanascsi_2_terminator_ctl(host, on_off) - * Purpose : Turn the Cumana SCSI 2 terminators on or off - * Params : host - card to turn on/off - * : on_off - !0 to turn on, 0 to turn off - */ -static void -cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off) -{ - struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; - - if (on_off) { - info->terms = 1; - writeb(ALATCH_ENA_TERM, info->base + CUMANASCSI2_ALATCH); - } else { - info->terms = 0; - writeb(ALATCH_DIS_TERM, info->base + CUMANASCSI2_ALATCH); - } -} - -/* Prototype: void cumanascsi_2_intr(irq, *dev_id, *regs) - * Purpose : handle interrupts from Cumana SCSI 2 card - * Params : irq - interrupt number - * dev_id - user-defined (Scsi_Host structure) - */ -static irqreturn_t -cumanascsi_2_intr(int irq, void *dev_id) -{ - struct cumanascsi2_info *info = dev_id; - - return fas216_intr(&info->info); -} - -/* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type) - * Purpose : initialises DMA/PIO - * Params : host - host - * SCpnt - command - * direction - DMA on to/off of card - * min_type - minimum DMA support that we must have for this transfer - * Returns : type of transfer to be performed - */ -static fasdmatype_t -cumanascsi_2_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp, - fasdmadir_t direction, fasdmatype_t min_type) -{ - struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; - struct device *dev = scsi_get_device(host); - int dmach = info->info.scsi.dma; - - writeb(ALATCH_DIS_DMA, info->base + CUMANASCSI2_ALATCH); - - if (dmach != NO_DMA && - (min_type == fasdma_real_all || SCp->this_residual >= 512)) { - int bufs, map_dir, dma_dir, alatch_dir; - - bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG); - - if (direction == DMA_OUT) - map_dir = DMA_TO_DEVICE, - dma_dir = DMA_MODE_WRITE, - alatch_dir = ALATCH_DMA_OUT; - else - map_dir = DMA_FROM_DEVICE, - dma_dir = DMA_MODE_READ, - alatch_dir = ALATCH_DMA_IN; - - dma_map_sg(dev, info->sg, bufs, map_dir); - - disable_dma(dmach); - set_dma_sg(dmach, info->sg, bufs); - writeb(alatch_dir, info->base + CUMANASCSI2_ALATCH); - set_dma_mode(dmach, dma_dir); - enable_dma(dmach); - writeb(ALATCH_ENA_DMA, info->base + CUMANASCSI2_ALATCH); - writeb(ALATCH_DIS_BIT32, info->base + CUMANASCSI2_ALATCH); - return fasdma_real_all; - } - - /* - * If we're not doing DMA, - * we'll do pseudo DMA - */ - return fasdma_pio; -} - -/* - * Prototype: void cumanascsi_2_dma_pseudo(host, SCpnt, direction, transfer) - * Purpose : handles pseudo DMA - * Params : host - host - * SCpnt - command - * direction - DMA on to/off of card - * transfer - minimum number of bytes we expect to transfer - */ -static void -cumanascsi_2_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp, - fasdmadir_t direction, int transfer) -{ - struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; - unsigned int length; - unsigned char *addr; - - length = SCp->this_residual; - addr = SCp->ptr; - - if (direction == DMA_OUT) -#if 0 - while (length > 1) { - unsigned long word; - unsigned int status = readb(info->base + CUMANASCSI2_STATUS); - - if (status & STATUS_INT) - goto end; - - if (!(status & STATUS_DRQ)) - continue; - - word = *addr | *(addr + 1) << 8; - writew(word, info->base + CUMANASCSI2_PSEUDODMA); - addr += 2; - length -= 2; - } -#else - printk ("PSEUDO_OUT???\n"); -#endif - else { - if (transfer && (transfer & 255)) { - while (length >= 256) { - unsigned int status = readb(info->base + CUMANASCSI2_STATUS); - - if (status & STATUS_INT) - return; - - if (!(status & STATUS_DRQ)) - continue; - - readsw(info->base + CUMANASCSI2_PSEUDODMA, - addr, 256 >> 1); - addr += 256; - length -= 256; - } - } - - while (length > 0) { - unsigned long word; - unsigned int status = readb(info->base + CUMANASCSI2_STATUS); - - if (status & STATUS_INT) - return; - - if (!(status & STATUS_DRQ)) - continue; - - word = readw(info->base + CUMANASCSI2_PSEUDODMA); - *addr++ = word; - if (--length > 0) { - *addr++ = word >> 8; - length --; - } - } - } -} - -/* Prototype: int cumanascsi_2_dma_stop(host, SCpnt) - * Purpose : stops DMA/PIO - * Params : host - host - * SCpnt - command - */ -static void -cumanascsi_2_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp) -{ - struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; - if (info->info.scsi.dma != NO_DMA) { - writeb(ALATCH_DIS_DMA, info->base + CUMANASCSI2_ALATCH); - disable_dma(info->info.scsi.dma); - } -} - -/* Prototype: const char *cumanascsi_2_info(struct Scsi_Host * host) - * Purpose : returns a descriptive string about this interface, - * Params : host - driver host structure to return info for. - * Returns : pointer to a static buffer containing null terminated string. - */ -const char *cumanascsi_2_info(struct Scsi_Host *host) -{ - struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; - static char string[150]; - - sprintf(string, "%s (%s) in slot %d v%s terminators o%s", - host->hostt->name, info->info.scsi.type, info->ec->slot_no, - VERSION, info->terms ? "n" : "ff"); - - return string; -} - -/* Prototype: int cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length) - * Purpose : Set a driver specific function - * Params : host - host to setup - * : buffer - buffer containing string describing operation - * : length - length of string - * Returns : -EINVAL, or 0 - */ -static int -cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length) -{ - int ret = length; - - if (length >= 11 && strncmp(buffer, "CUMANASCSI2", 11) == 0) { - buffer += 11; - length -= 11; - - if (length >= 5 && strncmp(buffer, "term=", 5) == 0) { - if (buffer[5] == '1') - cumanascsi_2_terminator_ctl(host, 1); - else if (buffer[5] == '0') - cumanascsi_2_terminator_ctl(host, 0); - else - ret = -EINVAL; - } else - ret = -EINVAL; - } else - ret = -EINVAL; - - return ret; -} - -/* Prototype: int cumanascsi_2_proc_info(char *buffer, char **start, off_t offset, - * int length, int host_no, int inout) - * Purpose : Return information about the driver to a user process accessing - * the /proc filesystem. - * Params : buffer - a buffer to write information to - * start - a pointer into this buffer set by this routine to the start - * of the required information. - * offset - offset into information that we have read up to. - * length - length of buffer - * host_no - host number to return information for - * inout - 0 for reading, 1 for writing. - * Returns : length of data written to buffer. - */ -int cumanascsi_2_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int inout) -{ - struct cumanascsi2_info *info; - char *p = buffer; - int pos; - - if (inout == 1) - return cumanascsi_2_set_proc_info(host, buffer, length); - - info = (struct cumanascsi2_info *)host->hostdata; - - p += sprintf(p, "Cumana SCSI II driver v%s\n", VERSION); - p += fas216_print_host(&info->info, p); - p += sprintf(p, "Term : o%s\n", - info->terms ? "n" : "ff"); - - p += fas216_print_stats(&info->info, p); - p += fas216_print_devices(&info->info, p); - - *start = buffer + offset; - pos = p - buffer - offset; - if (pos > length) - pos = length; - - return pos; -} - -static struct scsi_host_template cumanascsi2_template = { - .module = THIS_MODULE, - .proc_info = cumanascsi_2_proc_info, - .name = "Cumana SCSI II", - .info = cumanascsi_2_info, - .queuecommand = fas216_queue_command, - .eh_host_reset_handler = fas216_eh_host_reset, - .eh_bus_reset_handler = fas216_eh_bus_reset, - .eh_device_reset_handler = fas216_eh_device_reset, - .eh_abort_handler = fas216_eh_abort, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, - .dma_boundary = IOMD_DMA_BOUNDARY, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, - .proc_name = "cumanascsi2", -}; - -static int __devinit -cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct Scsi_Host *host; - struct cumanascsi2_info *info; - void __iomem *base; - int ret; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - base = ecardm_iomap(ec, ECARD_RES_MEMC, 0, 0); - if (!base) { - ret = -ENOMEM; - goto out_region; - } - - host = scsi_host_alloc(&cumanascsi2_template, - sizeof(struct cumanascsi2_info)); - if (!host) { - ret = -ENOMEM; - goto out_region; - } - - ecard_set_drvdata(ec, host); - - info = (struct cumanascsi2_info *)host->hostdata; - info->ec = ec; - info->base = base; - - cumanascsi_2_terminator_ctl(host, term[ec->slot_no]); - - info->info.scsi.io_base = base + CUMANASCSI2_FAS216_OFFSET; - info->info.scsi.io_shift = CUMANASCSI2_FAS216_SHIFT; - info->info.scsi.irq = ec->irq; - info->info.scsi.dma = ec->dma; - info->info.ifcfg.clockrate = 40; /* MHz */ - info->info.ifcfg.select_timeout = 255; - info->info.ifcfg.asyncperiod = 200; /* ns */ - info->info.ifcfg.sync_max_depth = 7; - info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; - info->info.ifcfg.disconnect_ok = 1; - info->info.ifcfg.wide_max_size = 0; - info->info.ifcfg.capabilities = FASCAP_PSEUDODMA; - info->info.dma.setup = cumanascsi_2_dma_setup; - info->info.dma.pseudo = cumanascsi_2_dma_pseudo; - info->info.dma.stop = cumanascsi_2_dma_stop; - - ec->irqaddr = info->base + CUMANASCSI2_STATUS; - ec->irqmask = STATUS_INT; - - ecard_setirq(ec, &cumanascsi_2_ops, info); - - ret = fas216_init(host); - if (ret) - goto out_free; - - ret = request_irq(ec->irq, cumanascsi_2_intr, - IRQF_DISABLED, "cumanascsi2", info); - if (ret) { - printk("scsi%d: IRQ%d not free: %d\n", - host->host_no, ec->irq, ret); - goto out_release; - } - - if (info->info.scsi.dma != NO_DMA) { - if (request_dma(info->info.scsi.dma, "cumanascsi2")) { - printk("scsi%d: DMA%d not free, using PIO\n", - host->host_no, info->info.scsi.dma); - info->info.scsi.dma = NO_DMA; - } else { - set_dma_speed(info->info.scsi.dma, 180); - info->info.ifcfg.capabilities |= FASCAP_DMA; - } - } - - ret = fas216_add(host, &ec->dev); - if (ret == 0) - goto out; - - if (info->info.scsi.dma != NO_DMA) - free_dma(info->info.scsi.dma); - free_irq(ec->irq, host); - - out_release: - fas216_release(host); - - out_free: - scsi_host_put(host); - - out_region: - ecard_release_resources(ec); - - out: - return ret; -} - -static void __devexit cumanascsi2_remove(struct expansion_card *ec) -{ - struct Scsi_Host *host = ecard_get_drvdata(ec); - struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata; - - ecard_set_drvdata(ec, NULL); - fas216_remove(host); - - if (info->info.scsi.dma != NO_DMA) - free_dma(info->info.scsi.dma); - free_irq(ec->irq, info); - - fas216_release(host); - scsi_host_put(host); - ecard_release_resources(ec); -} - -static const struct ecard_id cumanascsi2_cids[] = { - { MANU_CUMANA, PROD_CUMANA_SCSI_2 }, - { 0xffff, 0xffff }, -}; - -static struct ecard_driver cumanascsi2_driver = { - .probe = cumanascsi2_probe, - .remove = __devexit_p(cumanascsi2_remove), - .id_table = cumanascsi2_cids, - .drv = { - .name = "cumanascsi2", - }, -}; - -static int __init cumanascsi2_init(void) -{ - return ecard_register_driver(&cumanascsi2_driver); -} - -static void __exit cumanascsi2_exit(void) -{ - ecard_remove_driver(&cumanascsi2_driver); -} - -module_init(cumanascsi2_init); -module_exit(cumanascsi2_exit); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("Cumana SCSI-2 driver for Acorn machines"); -module_param_array(term, int, NULL, 0); -MODULE_PARM_DESC(term, "SCSI bus termination"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/arm/eesox.c b/ANDROID_3.4.5/drivers/scsi/arm/eesox.c deleted file mode 100644 index edfd12b4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/eesox.c +++ /dev/null @@ -1,670 +0,0 @@ -/* - * linux/drivers/acorn/scsi/eesox.c - * - * Copyright (C) 1997-2005 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This driver is based on experimentation. Hence, it may have made - * assumptions about the particular card that I have available, and - * may not be reliable! - * - * Changelog: - * 01-10-1997 RMK Created, READONLY version - * 15-02-1998 RMK READ/WRITE version - * added DMA support and hardware definitions - * 14-03-1998 RMK Updated DMA support - * Added terminator control - * 15-04-1998 RMK Only do PIO if FAS216 will allow it. - * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h - * 02-04-2000 RMK 0.0.3 Fixed NO_IRQ/NO_DMA problem, updated for new - * error handling code. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../scsi.h" -#include -#include "fas216.h" -#include "scsi.h" - -#include - -#define EESOX_FAS216_OFFSET 0x3000 -#define EESOX_FAS216_SHIFT 5 - -#define EESOX_DMASTAT 0x2800 -#define EESOX_STAT_INTR 0x01 -#define EESOX_STAT_DMA 0x02 - -#define EESOX_CONTROL 0x2800 -#define EESOX_INTR_ENABLE 0x04 -#define EESOX_TERM_ENABLE 0x02 -#define EESOX_RESET 0x01 - -#define EESOX_DMADATA 0x3800 - -#define VERSION "1.10 (17/01/2003 2.5.59)" - -/* - * Use term=0,1,0,0,0 to turn terminators on/off - */ -static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; - -#define NR_SG 256 - -struct eesoxscsi_info { - FAS216_Info info; - struct expansion_card *ec; - void __iomem *base; - void __iomem *ctl_port; - unsigned int control; - struct scatterlist sg[NR_SG]; /* Scatter DMA list */ -}; - -/* Prototype: void eesoxscsi_irqenable(ec, irqnr) - * Purpose : Enable interrupts on EESOX SCSI card - * Params : ec - expansion card structure - * : irqnr - interrupt number - */ -static void -eesoxscsi_irqenable(struct expansion_card *ec, int irqnr) -{ - struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data; - - info->control |= EESOX_INTR_ENABLE; - - writeb(info->control, info->ctl_port); -} - -/* Prototype: void eesoxscsi_irqdisable(ec, irqnr) - * Purpose : Disable interrupts on EESOX SCSI card - * Params : ec - expansion card structure - * : irqnr - interrupt number - */ -static void -eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr) -{ - struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data; - - info->control &= ~EESOX_INTR_ENABLE; - - writeb(info->control, info->ctl_port); -} - -static const expansioncard_ops_t eesoxscsi_ops = { - .irqenable = eesoxscsi_irqenable, - .irqdisable = eesoxscsi_irqdisable, -}; - -/* Prototype: void eesoxscsi_terminator_ctl(*host, on_off) - * Purpose : Turn the EESOX SCSI terminators on or off - * Params : host - card to turn on/off - * : on_off - !0 to turn on, 0 to turn off - */ -static void -eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off) -{ - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - unsigned long flags; - - spin_lock_irqsave(host->host_lock, flags); - if (on_off) - info->control |= EESOX_TERM_ENABLE; - else - info->control &= ~EESOX_TERM_ENABLE; - - writeb(info->control, info->ctl_port); - spin_unlock_irqrestore(host->host_lock, flags); -} - -/* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs) - * Purpose : handle interrupts from EESOX SCSI card - * Params : irq - interrupt number - * dev_id - user-defined (Scsi_Host structure) - */ -static irqreturn_t -eesoxscsi_intr(int irq, void *dev_id) -{ - struct eesoxscsi_info *info = dev_id; - - return fas216_intr(&info->info); -} - -/* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type) - * Purpose : initialises DMA/PIO - * Params : host - host - * SCpnt - command - * direction - DMA on to/off of card - * min_type - minimum DMA support that we must have for this transfer - * Returns : type of transfer to be performed - */ -static fasdmatype_t -eesoxscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp, - fasdmadir_t direction, fasdmatype_t min_type) -{ - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - struct device *dev = scsi_get_device(host); - int dmach = info->info.scsi.dma; - - if (dmach != NO_DMA && - (min_type == fasdma_real_all || SCp->this_residual >= 512)) { - int bufs, map_dir, dma_dir; - - bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG); - - if (direction == DMA_OUT) - map_dir = DMA_TO_DEVICE, - dma_dir = DMA_MODE_WRITE; - else - map_dir = DMA_FROM_DEVICE, - dma_dir = DMA_MODE_READ; - - dma_map_sg(dev, info->sg, bufs, map_dir); - - disable_dma(dmach); - set_dma_sg(dmach, info->sg, bufs); - set_dma_mode(dmach, dma_dir); - enable_dma(dmach); - return fasdma_real_all; - } - /* - * We don't do DMA, we only do slow PIO - * - * Some day, we will do Pseudo DMA - */ - return fasdma_pseudo; -} - -static void eesoxscsi_buffer_in(void *buf, int length, void __iomem *base) -{ - const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET; - const void __iomem *reg_dmastat = base + EESOX_DMASTAT; - const void __iomem *reg_dmadata = base + EESOX_DMADATA; - register const unsigned long mask = 0xffff; - - do { - unsigned int status; - - /* - * Interrupt request? - */ - status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT)); - if (status & STAT_INT) - break; - - /* - * DMA request active? - */ - status = readb(reg_dmastat); - if (!(status & EESOX_STAT_DMA)) - continue; - - /* - * Get number of bytes in FIFO - */ - status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF; - if (status > 16) - status = 16; - if (status > length) - status = length; - - /* - * Align buffer. - */ - if (((u32)buf) & 2 && status >= 2) { - *(u16 *)buf = readl(reg_dmadata); - buf += 2; - status -= 2; - length -= 2; - } - - if (status >= 8) { - unsigned long l1, l2; - - l1 = readl(reg_dmadata) & mask; - l1 |= readl(reg_dmadata) << 16; - l2 = readl(reg_dmadata) & mask; - l2 |= readl(reg_dmadata) << 16; - *(u32 *)buf = l1; - buf += 4; - *(u32 *)buf = l2; - buf += 4; - length -= 8; - continue; - } - - if (status >= 4) { - unsigned long l1; - - l1 = readl(reg_dmadata) & mask; - l1 |= readl(reg_dmadata) << 16; - - *(u32 *)buf = l1; - buf += 4; - length -= 4; - continue; - } - - if (status >= 2) { - *(u16 *)buf = readl(reg_dmadata); - buf += 2; - length -= 2; - } - } while (length); -} - -static void eesoxscsi_buffer_out(void *buf, int length, void __iomem *base) -{ - const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET; - const void __iomem *reg_dmastat = base + EESOX_DMASTAT; - const void __iomem *reg_dmadata = base + EESOX_DMADATA; - - do { - unsigned int status; - - /* - * Interrupt request? - */ - status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT)); - if (status & STAT_INT) - break; - - /* - * DMA request active? - */ - status = readb(reg_dmastat); - if (!(status & EESOX_STAT_DMA)) - continue; - - /* - * Get number of bytes in FIFO - */ - status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF; - if (status > 16) - status = 16; - status = 16 - status; - if (status > length) - status = length; - status &= ~1; - - /* - * Align buffer. - */ - if (((u32)buf) & 2 && status >= 2) { - writel(*(u16 *)buf << 16, reg_dmadata); - buf += 2; - status -= 2; - length -= 2; - } - - if (status >= 8) { - unsigned long l1, l2; - - l1 = *(u32 *)buf; - buf += 4; - l2 = *(u32 *)buf; - buf += 4; - - writel(l1 << 16, reg_dmadata); - writel(l1, reg_dmadata); - writel(l2 << 16, reg_dmadata); - writel(l2, reg_dmadata); - length -= 8; - continue; - } - - if (status >= 4) { - unsigned long l1; - - l1 = *(u32 *)buf; - buf += 4; - - writel(l1 << 16, reg_dmadata); - writel(l1, reg_dmadata); - length -= 4; - continue; - } - - if (status >= 2) { - writel(*(u16 *)buf << 16, reg_dmadata); - buf += 2; - length -= 2; - } - } while (length); -} - -static void -eesoxscsi_dma_pseudo(struct Scsi_Host *host, struct scsi_pointer *SCp, - fasdmadir_t dir, int transfer_size) -{ - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - if (dir == DMA_IN) { - eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, info->base); - } else { - eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, info->base); - } -} - -/* Prototype: int eesoxscsi_dma_stop(host, SCpnt) - * Purpose : stops DMA/PIO - * Params : host - host - * SCpnt - command - */ -static void -eesoxscsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp) -{ - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - if (info->info.scsi.dma != NO_DMA) - disable_dma(info->info.scsi.dma); -} - -/* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host) - * Purpose : returns a descriptive string about this interface, - * Params : host - driver host structure to return info for. - * Returns : pointer to a static buffer containing null terminated string. - */ -const char *eesoxscsi_info(struct Scsi_Host *host) -{ - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - static char string[150]; - - sprintf(string, "%s (%s) in slot %d v%s terminators o%s", - host->hostt->name, info->info.scsi.type, info->ec->slot_no, - VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff"); - - return string; -} - -/* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) - * Purpose : Set a driver specific function - * Params : host - host to setup - * : buffer - buffer containing string describing operation - * : length - length of string - * Returns : -EINVAL, or 0 - */ -static int -eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) -{ - int ret = length; - - if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) { - buffer += 9; - length -= 9; - - if (length >= 5 && strncmp(buffer, "term=", 5) == 0) { - if (buffer[5] == '1') - eesoxscsi_terminator_ctl(host, 1); - else if (buffer[5] == '0') - eesoxscsi_terminator_ctl(host, 0); - else - ret = -EINVAL; - } else - ret = -EINVAL; - } else - ret = -EINVAL; - - return ret; -} - -/* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset, - * int length, int host_no, int inout) - * Purpose : Return information about the driver to a user process accessing - * the /proc filesystem. - * Params : buffer - a buffer to write information to - * start - a pointer into this buffer set by this routine to the start - * of the required information. - * offset - offset into information that we have read up to. - * length - length of buffer - * host_no - host number to return information for - * inout - 0 for reading, 1 for writing. - * Returns : length of data written to buffer. - */ -int eesoxscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int inout) -{ - struct eesoxscsi_info *info; - char *p = buffer; - int pos; - - if (inout == 1) - return eesoxscsi_set_proc_info(host, buffer, length); - - info = (struct eesoxscsi_info *)host->hostdata; - - p += sprintf(p, "EESOX SCSI driver v%s\n", VERSION); - p += fas216_print_host(&info->info, p); - p += sprintf(p, "Term : o%s\n", - info->control & EESOX_TERM_ENABLE ? "n" : "ff"); - - p += fas216_print_stats(&info->info, p); - p += fas216_print_devices(&info->info, p); - - *start = buffer + offset; - pos = p - buffer - offset; - if (pos > length) - pos = length; - - return pos; -} - -static ssize_t eesoxscsi_show_term(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct expansion_card *ec = ECARD_DEV(dev); - struct Scsi_Host *host = ecard_get_drvdata(ec); - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - - return sprintf(buf, "%d\n", info->control & EESOX_TERM_ENABLE ? 1 : 0); -} - -static ssize_t eesoxscsi_store_term(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) -{ - struct expansion_card *ec = ECARD_DEV(dev); - struct Scsi_Host *host = ecard_get_drvdata(ec); - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - unsigned long flags; - - if (len > 1) { - spin_lock_irqsave(host->host_lock, flags); - if (buf[0] != '0') { - info->control |= EESOX_TERM_ENABLE; - } else { - info->control &= ~EESOX_TERM_ENABLE; - } - writeb(info->control, info->ctl_port); - spin_unlock_irqrestore(host->host_lock, flags); - } - - return len; -} - -static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR, - eesoxscsi_show_term, eesoxscsi_store_term); - -static struct scsi_host_template eesox_template = { - .module = THIS_MODULE, - .proc_info = eesoxscsi_proc_info, - .name = "EESOX SCSI", - .info = eesoxscsi_info, - .queuecommand = fas216_queue_command, - .eh_host_reset_handler = fas216_eh_host_reset, - .eh_bus_reset_handler = fas216_eh_bus_reset, - .eh_device_reset_handler = fas216_eh_device_reset, - .eh_abort_handler = fas216_eh_abort, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, - .dma_boundary = IOMD_DMA_BOUNDARY, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, - .proc_name = "eesox", -}; - -static int __devinit -eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct Scsi_Host *host; - struct eesoxscsi_info *info; - void __iomem *base; - int ret; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); - if (!base) { - ret = -ENOMEM; - goto out_region; - } - - host = scsi_host_alloc(&eesox_template, - sizeof(struct eesoxscsi_info)); - if (!host) { - ret = -ENOMEM; - goto out_region; - } - - ecard_set_drvdata(ec, host); - - info = (struct eesoxscsi_info *)host->hostdata; - info->ec = ec; - info->base = base; - info->ctl_port = base + EESOX_CONTROL; - info->control = term[ec->slot_no] ? EESOX_TERM_ENABLE : 0; - writeb(info->control, info->ctl_port); - - info->info.scsi.io_base = base + EESOX_FAS216_OFFSET; - info->info.scsi.io_shift = EESOX_FAS216_SHIFT; - info->info.scsi.irq = ec->irq; - info->info.scsi.dma = ec->dma; - info->info.ifcfg.clockrate = 40; /* MHz */ - info->info.ifcfg.select_timeout = 255; - info->info.ifcfg.asyncperiod = 200; /* ns */ - info->info.ifcfg.sync_max_depth = 7; - info->info.ifcfg.cntl3 = CNTL3_FASTSCSI | CNTL3_FASTCLK; - info->info.ifcfg.disconnect_ok = 1; - info->info.ifcfg.wide_max_size = 0; - info->info.ifcfg.capabilities = FASCAP_PSEUDODMA; - info->info.dma.setup = eesoxscsi_dma_setup; - info->info.dma.pseudo = eesoxscsi_dma_pseudo; - info->info.dma.stop = eesoxscsi_dma_stop; - - ec->irqaddr = base + EESOX_DMASTAT; - ec->irqmask = EESOX_STAT_INTR; - - ecard_setirq(ec, &eesoxscsi_ops, info); - - device_create_file(&ec->dev, &dev_attr_bus_term); - - ret = fas216_init(host); - if (ret) - goto out_free; - - ret = request_irq(ec->irq, eesoxscsi_intr, 0, "eesoxscsi", info); - if (ret) { - printk("scsi%d: IRQ%d not free: %d\n", - host->host_no, ec->irq, ret); - goto out_remove; - } - - if (info->info.scsi.dma != NO_DMA) { - if (request_dma(info->info.scsi.dma, "eesox")) { - printk("scsi%d: DMA%d not free, DMA disabled\n", - host->host_no, info->info.scsi.dma); - info->info.scsi.dma = NO_DMA; - } else { - set_dma_speed(info->info.scsi.dma, 180); - info->info.ifcfg.capabilities |= FASCAP_DMA; - info->info.ifcfg.cntl3 |= CNTL3_BS8; - } - } - - ret = fas216_add(host, &ec->dev); - if (ret == 0) - goto out; - - if (info->info.scsi.dma != NO_DMA) - free_dma(info->info.scsi.dma); - free_irq(ec->irq, host); - - out_remove: - fas216_remove(host); - - out_free: - device_remove_file(&ec->dev, &dev_attr_bus_term); - scsi_host_put(host); - - out_region: - ecard_release_resources(ec); - - out: - return ret; -} - -static void __devexit eesoxscsi_remove(struct expansion_card *ec) -{ - struct Scsi_Host *host = ecard_get_drvdata(ec); - struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata; - - ecard_set_drvdata(ec, NULL); - fas216_remove(host); - - if (info->info.scsi.dma != NO_DMA) - free_dma(info->info.scsi.dma); - free_irq(ec->irq, info); - - device_remove_file(&ec->dev, &dev_attr_bus_term); - - fas216_release(host); - scsi_host_put(host); - ecard_release_resources(ec); -} - -static const struct ecard_id eesoxscsi_cids[] = { - { MANU_EESOX, PROD_EESOX_SCSI2 }, - { 0xffff, 0xffff }, -}; - -static struct ecard_driver eesoxscsi_driver = { - .probe = eesoxscsi_probe, - .remove = __devexit_p(eesoxscsi_remove), - .id_table = eesoxscsi_cids, - .drv = { - .name = "eesoxscsi", - }, -}; - -static int __init eesox_init(void) -{ - return ecard_register_driver(&eesoxscsi_driver); -} - -static void __exit eesox_exit(void) -{ - ecard_remove_driver(&eesoxscsi_driver); -} - -module_init(eesox_init); -module_exit(eesox_exit); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines"); -module_param_array(term, int, NULL, 0); -MODULE_PARM_DESC(term, "SCSI bus termination"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/arm/fas216.c b/ANDROID_3.4.5/drivers/scsi/arm/fas216.c deleted file mode 100644 index 6206a666..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/fas216.c +++ /dev/null @@ -1,3045 +0,0 @@ -/* - * linux/drivers/acorn/scsi/fas216.c - * - * Copyright (C) 1997-2003 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and - * other sources, including: - * the AMD Am53CF94 data sheet - * the AMD Am53C94 data sheet - * - * This is a generic driver. To use it, have a look at cumana_2.c. You - * should define your own structure that overlays FAS216_Info, eg: - * struct my_host_data { - * FAS216_Info info; - * ... my host specific data ... - * }; - * - * Changelog: - * 30-08-1997 RMK Created - * 14-09-1997 RMK Started disconnect support - * 08-02-1998 RMK Corrected real DMA support - * 15-02-1998 RMK Started sync xfer support - * 06-04-1998 RMK Tightened conditions for printing incomplete - * transfers - * 02-05-1998 RMK Added extra checks in fas216_reset - * 24-05-1998 RMK Fixed synchronous transfers with period >= 200ns - * 27-06-1998 RMK Changed asm/delay.h to linux/delay.h - * 26-08-1998 RMK Improved message support wrt MESSAGE_REJECT - * 02-04-2000 RMK Converted to use the new error handling, and - * automatically request sense data upon check - * condition status from targets. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../scsi.h" -#include -#include -#include "fas216.h" -#include "scsi.h" - -/* NOTE: SCSI2 Synchronous transfers *require* DMA according to - * the data sheet. This restriction is crazy, especially when - * you only want to send 16 bytes! What were the guys who - * designed this chip on at that time? Did they read the SCSI2 - * spec at all? The following sections are taken from the SCSI2 - * standard (s2r10) concerning this: - * - * > IMPLEMENTORS NOTES: - * > (1) Re-negotiation at every selection is not recommended, since a - * > significant performance impact is likely. - * - * > The implied synchronous agreement shall remain in effect until a BUS DEVICE - * > RESET message is received, until a hard reset condition occurs, or until one - * > of the two SCSI devices elects to modify the agreement. The default data - * > transfer mode is asynchronous data transfer mode. The default data transfer - * > mode is entered at power on, after a BUS DEVICE RESET message, or after a hard - * > reset condition. - * - * In total, this means that once you have elected to use synchronous - * transfers, you must always use DMA. - * - * I was thinking that this was a good chip until I found this restriction ;( - */ -#define SCSI2_SYNC -#undef SCSI2_TAG - -#undef DEBUG_CONNECT -#undef DEBUG_MESSAGES - -#undef CHECK_STRUCTURE - -#define LOG_CONNECT (1 << 0) -#define LOG_BUSSERVICE (1 << 1) -#define LOG_FUNCTIONDONE (1 << 2) -#define LOG_MESSAGES (1 << 3) -#define LOG_BUFFER (1 << 4) -#define LOG_ERROR (1 << 8) - -static int level_mask = LOG_ERROR; - -module_param(level_mask, int, 0644); - -static int __init fas216_log_setup(char *str) -{ - char *s; - - level_mask = 0; - - while ((s = strsep(&str, ",")) != NULL) { - switch (s[0]) { - case 'a': - if (strcmp(s, "all") == 0) - level_mask |= -1; - break; - case 'b': - if (strncmp(s, "bus", 3) == 0) - level_mask |= LOG_BUSSERVICE; - if (strncmp(s, "buf", 3) == 0) - level_mask |= LOG_BUFFER; - break; - case 'c': - level_mask |= LOG_CONNECT; - break; - case 'e': - level_mask |= LOG_ERROR; - break; - case 'm': - level_mask |= LOG_MESSAGES; - break; - case 'n': - if (strcmp(s, "none") == 0) - level_mask = 0; - break; - case 's': - level_mask |= LOG_FUNCTIONDONE; - break; - } - } - return 1; -} - -__setup("fas216_logging=", fas216_log_setup); - -static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg) -{ - unsigned int off = reg << info->scsi.io_shift; - return readb(info->scsi.io_base + off); -} - -static inline void fas216_writeb(FAS216_Info *info, unsigned int reg, unsigned int val) -{ - unsigned int off = reg << info->scsi.io_shift; - writeb(val, info->scsi.io_base + off); -} - -static void fas216_dumpstate(FAS216_Info *info) -{ - unsigned char is, stat, inst; - - is = fas216_readb(info, REG_IS); - stat = fas216_readb(info, REG_STAT); - inst = fas216_readb(info, REG_INST); - - printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X" - " INST=%02X IS=%02X CFIS=%02X", - fas216_readb(info, REG_CTCL), - fas216_readb(info, REG_CTCM), - fas216_readb(info, REG_CMD), stat, inst, is, - fas216_readb(info, REG_CFIS)); - printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n", - fas216_readb(info, REG_CNTL1), - fas216_readb(info, REG_CNTL2), - fas216_readb(info, REG_CNTL3), - fas216_readb(info, REG_CTCH)); -} - -static void print_SCp(struct scsi_pointer *SCp, const char *prefix, const char *suffix) -{ - printk("%sptr %p this_residual 0x%x buffer %p buffers_residual 0x%x%s", - prefix, SCp->ptr, SCp->this_residual, SCp->buffer, - SCp->buffers_residual, suffix); -} - -static void fas216_dumpinfo(FAS216_Info *info) -{ - static int used = 0; - int i; - - if (used++) - return; - - printk("FAS216_Info=\n"); - printk(" { magic_start=%lX host=%p SCpnt=%p origSCpnt=%p\n", - info->magic_start, info->host, info->SCpnt, - info->origSCpnt); - printk(" scsi={ io_shift=%X irq=%X cfg={ %X %X %X %X }\n", - info->scsi.io_shift, info->scsi.irq, - info->scsi.cfg[0], info->scsi.cfg[1], info->scsi.cfg[2], - info->scsi.cfg[3]); - printk(" type=%p phase=%X\n", - info->scsi.type, info->scsi.phase); - print_SCp(&info->scsi.SCp, " SCp={ ", " }\n"); - printk(" msgs async_stp=%X disconnectable=%d aborting=%d }\n", - info->scsi.async_stp, - info->scsi.disconnectable, info->scsi.aborting); - printk(" stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n" - " disconnects=%X aborts=%X bus_resets=%X host_resets=%X}\n", - info->stats.queues, info->stats.removes, info->stats.fins, - info->stats.reads, info->stats.writes, info->stats.miscs, - info->stats.disconnects, info->stats.aborts, info->stats.bus_resets, - info->stats.host_resets); - printk(" ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n", - info->ifcfg.clockrate, info->ifcfg.select_timeout, - info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth); - for (i = 0; i < 8; i++) { - printk(" busyluns[%d]=%08lx dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n", - i, info->busyluns[i], i, - info->device[i].disconnect_ok, info->device[i].stp, - info->device[i].sof, info->device[i].sync_state); - } - printk(" dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n", - info->dma.transfer_type, info->dma.setup, - info->dma.pseudo, info->dma.stop); - printk(" internal_done=%X magic_end=%lX }\n", - info->internal_done, info->magic_end); -} - -#ifdef CHECK_STRUCTURE -static void __fas216_checkmagic(FAS216_Info *info, const char *func) -{ - int corruption = 0; - if (info->magic_start != MAGIC) { - printk(KERN_CRIT "FAS216 Error: magic at start corrupted\n"); - corruption++; - } - if (info->magic_end != MAGIC) { - printk(KERN_CRIT "FAS216 Error: magic at end corrupted\n"); - corruption++; - } - if (corruption) { - fas216_dumpinfo(info); - panic("scsi memory space corrupted in %s", func); - } -} -#define fas216_checkmagic(info) __fas216_checkmagic((info), __func__) -#else -#define fas216_checkmagic(info) -#endif - -static const char *fas216_bus_phase(int stat) -{ - static const char *phases[] = { - "DATA OUT", "DATA IN", - "COMMAND", "STATUS", - "MISC OUT", "MISC IN", - "MESG OUT", "MESG IN" - }; - - return phases[stat & STAT_BUSMASK]; -} - -static const char *fas216_drv_phase(FAS216_Info *info) -{ - static const char *phases[] = { - [PHASE_IDLE] = "idle", - [PHASE_SELECTION] = "selection", - [PHASE_COMMAND] = "command", - [PHASE_DATAOUT] = "data out", - [PHASE_DATAIN] = "data in", - [PHASE_MSGIN] = "message in", - [PHASE_MSGIN_DISCONNECT]= "disconnect", - [PHASE_MSGOUT_EXPECT] = "expect message out", - [PHASE_MSGOUT] = "message out", - [PHASE_STATUS] = "status", - [PHASE_DONE] = "done", - }; - - if (info->scsi.phase < ARRAY_SIZE(phases) && - phases[info->scsi.phase]) - return phases[info->scsi.phase]; - return "???"; -} - -static char fas216_target(FAS216_Info *info) -{ - if (info->SCpnt) - return '0' + info->SCpnt->device->id; - else - return 'H'; -} - -static void -fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap) -{ - static char buf[1024]; - - vsnprintf(buf, sizeof(buf), fmt, ap); - printk("scsi%d.%c: %s", info->host->host_no, target, buf); -} - -static void fas216_log_command(FAS216_Info *info, int level, - struct scsi_cmnd *SCpnt, char *fmt, ...) -{ - va_list args; - - if (level != 0 && !(level & level_mask)) - return; - - va_start(args, fmt); - fas216_do_log(info, '0' + SCpnt->device->id, fmt, args); - va_end(args); - - printk(" CDB: "); - __scsi_print_command(SCpnt->cmnd); -} - -static void -fas216_log_target(FAS216_Info *info, int level, int target, char *fmt, ...) -{ - va_list args; - - if (level != 0 && !(level & level_mask)) - return; - - if (target < 0) - target = 'H'; - else - target += '0'; - - va_start(args, fmt); - fas216_do_log(info, target, fmt, args); - va_end(args); - - printk("\n"); -} - -static void fas216_log(FAS216_Info *info, int level, char *fmt, ...) -{ - va_list args; - - if (level != 0 && !(level & level_mask)) - return; - - va_start(args, fmt); - fas216_do_log(info, fas216_target(info), fmt, args); - va_end(args); - - printk("\n"); -} - -#define PH_SIZE 32 - -static struct { int stat, ssr, isr, ph; } ph_list[PH_SIZE]; -static int ph_ptr; - -static void add_debug_list(int stat, int ssr, int isr, int ph) -{ - ph_list[ph_ptr].stat = stat; - ph_list[ph_ptr].ssr = ssr; - ph_list[ph_ptr].isr = isr; - ph_list[ph_ptr].ph = ph; - - ph_ptr = (ph_ptr + 1) & (PH_SIZE-1); -} - -static struct { int command; void *from; } cmd_list[8]; -static int cmd_ptr; - -static void fas216_cmd(FAS216_Info *info, unsigned int command) -{ - cmd_list[cmd_ptr].command = command; - cmd_list[cmd_ptr].from = __builtin_return_address(0); - - cmd_ptr = (cmd_ptr + 1) & 7; - - fas216_writeb(info, REG_CMD, command); -} - -static void print_debug_list(void) -{ - int i; - - i = ph_ptr; - - printk(KERN_ERR "SCSI IRQ trail\n"); - do { - printk(" %02x:%02x:%02x:%1x", - ph_list[i].stat, ph_list[i].ssr, - ph_list[i].isr, ph_list[i].ph); - i = (i + 1) & (PH_SIZE - 1); - if (((i ^ ph_ptr) & 7) == 0) - printk("\n"); - } while (i != ph_ptr); - if ((i ^ ph_ptr) & 7) - printk("\n"); - - i = cmd_ptr; - printk(KERN_ERR "FAS216 commands: "); - do { - printk("%02x:%p ", cmd_list[i].command, cmd_list[i].from); - i = (i + 1) & 7; - } while (i != cmd_ptr); - printk("\n"); -} - -static void fas216_done(FAS216_Info *info, unsigned int result); - -/** - * fas216_get_last_msg - retrive last message from the list - * @info: interface to search - * @pos: current fifo position - * - * Retrieve a last message from the list, using position in fifo. - */ -static inline unsigned short -fas216_get_last_msg(FAS216_Info *info, int pos) -{ - unsigned short packed_msg = NOP; - struct message *msg; - int msgnr = 0; - - while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { - if (pos >= msg->fifo) - break; - } - - if (msg) { - if (msg->msg[0] == EXTENDED_MESSAGE) - packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8; - else - packed_msg = msg->msg[0]; - } - - fas216_log(info, LOG_MESSAGES, - "Message: %04x found at position %02x\n", packed_msg, pos); - - return packed_msg; -} - -/** - * fas216_syncperiod - calculate STP register value - * @info: state structure for interface connected to device - * @ns: period in ns (between subsequent bytes) - * - * Calculate value to be loaded into the STP register for a given period - * in ns. Returns a value suitable for REG_STP. - */ -static int fas216_syncperiod(FAS216_Info *info, int ns) -{ - int value = (info->ifcfg.clockrate * ns) / 1000; - - fas216_checkmagic(info); - - if (value < 4) - value = 4; - else if (value > 35) - value = 35; - - return value & 31; -} - -/** - * fas216_set_sync - setup FAS216 chip for specified transfer period. - * @info: state structure for interface connected to device - * @target: target - * - * Correctly setup FAS216 chip for specified transfer period. - * Notes : we need to switch the chip out of FASTSCSI mode if we have - * a transfer period >= 200ns - otherwise the chip will violate - * the SCSI timings. - */ -static void fas216_set_sync(FAS216_Info *info, int target) -{ - unsigned int cntl3; - - fas216_writeb(info, REG_SOF, info->device[target].sof); - fas216_writeb(info, REG_STP, info->device[target].stp); - - cntl3 = info->scsi.cfg[2]; - if (info->device[target].period >= (200 / 4)) - cntl3 = cntl3 & ~CNTL3_FASTSCSI; - - fas216_writeb(info, REG_CNTL3, cntl3); -} - -/* Synchronous transfer support - * - * Note: The SCSI II r10 spec says (5.6.12): - * - * (2) Due to historical problems with early host adapters that could - * not accept an SDTR message, some targets may not initiate synchronous - * negotiation after a power cycle as required by this standard. Host - * adapters that support synchronous mode may avoid the ensuing failure - * modes when the target is independently power cycled by initiating a - * synchronous negotiation on each REQUEST SENSE and INQUIRY command. - * This approach increases the SCSI bus overhead and is not recommended - * for new implementations. The correct method is to respond to an - * SDTR message with a MESSAGE REJECT message if the either the - * initiator or target devices does not support synchronous transfers - * or does not want to negotiate for synchronous transfers at the time. - * Using the correct method assures compatibility with wide data - * transfers and future enhancements. - * - * We will always initiate a synchronous transfer negotiation request on - * every INQUIRY or REQUEST SENSE message, unless the target itself has - * at some point performed a synchronous transfer negotiation request, or - * we have synchronous transfers disabled for this device. - */ - -/** - * fas216_handlesync - Handle a synchronous transfer message - * @info: state structure for interface - * @msg: message from target - * - * Handle a synchronous transfer message from the target - */ -static void fas216_handlesync(FAS216_Info *info, char *msg) -{ - struct fas216_device *dev = &info->device[info->SCpnt->device->id]; - enum { sync, async, none, reject } res = none; - -#ifdef SCSI2_SYNC - switch (msg[0]) { - case MESSAGE_REJECT: - /* Synchronous transfer request failed. - * Note: SCSI II r10: - * - * SCSI devices that are capable of synchronous - * data transfers shall not respond to an SDTR - * message with a MESSAGE REJECT message. - * - * Hence, if we get this condition, we disable - * negotiation for this device. - */ - if (dev->sync_state == neg_inprogress) { - dev->sync_state = neg_invalid; - res = async; - } - break; - - case EXTENDED_MESSAGE: - switch (dev->sync_state) { - /* We don't accept synchronous transfer requests. - * Respond with a MESSAGE_REJECT to prevent a - * synchronous transfer agreement from being reached. - */ - case neg_invalid: - res = reject; - break; - - /* We were not negotiating a synchronous transfer, - * but the device sent us a negotiation request. - * Honour the request by sending back a SDTR - * message containing our capability, limited by - * the targets capability. - */ - default: - fas216_cmd(info, CMD_SETATN); - if (msg[4] > info->ifcfg.sync_max_depth) - msg[4] = info->ifcfg.sync_max_depth; - if (msg[3] < 1000 / info->ifcfg.clockrate) - msg[3] = 1000 / info->ifcfg.clockrate; - - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 5, - EXTENDED_MESSAGE, 3, EXTENDED_SDTR, - msg[3], msg[4]); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - - /* This is wrong. The agreement is not in effect - * until this message is accepted by the device - */ - dev->sync_state = neg_targcomplete; - res = sync; - break; - - /* We initiated the synchronous transfer negotiation, - * and have successfully received a response from the - * target. The synchronous transfer agreement has been - * reached. Note: if the values returned are out of our - * bounds, we must reject the message. - */ - case neg_inprogress: - res = reject; - if (msg[4] <= info->ifcfg.sync_max_depth && - msg[3] >= 1000 / info->ifcfg.clockrate) { - dev->sync_state = neg_complete; - res = sync; - } - break; - } - } -#else - res = reject; -#endif - - switch (res) { - case sync: - dev->period = msg[3]; - dev->sof = msg[4]; - dev->stp = fas216_syncperiod(info, msg[3] * 4); - fas216_set_sync(info, info->SCpnt->device->id); - break; - - case reject: - fas216_cmd(info, CMD_SETATN); - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - - case async: - dev->period = info->ifcfg.asyncperiod / 4; - dev->sof = 0; - dev->stp = info->scsi.async_stp; - fas216_set_sync(info, info->SCpnt->device->id); - break; - - case none: - break; - } -} - -/** - * fas216_updateptrs - update data pointers after transfer suspended/paused - * @info: interface's local pointer to update - * @bytes_transferred: number of bytes transferred - * - * Update data pointers after transfer suspended/paused - */ -static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred) -{ - struct scsi_pointer *SCp = &info->scsi.SCp; - - fas216_checkmagic(info); - - BUG_ON(bytes_transferred < 0); - - SCp->phase -= bytes_transferred; - - while (bytes_transferred != 0) { - if (SCp->this_residual > bytes_transferred) - break; - /* - * We have used up this buffer. Move on to the - * next buffer. - */ - bytes_transferred -= SCp->this_residual; - if (!next_SCp(SCp) && bytes_transferred) { - printk(KERN_WARNING "scsi%d.%c: out of buffers\n", - info->host->host_no, '0' + info->SCpnt->device->id); - return; - } - } - - SCp->this_residual -= bytes_transferred; - if (SCp->this_residual) - SCp->ptr += bytes_transferred; - else - SCp->ptr = NULL; -} - -/** - * fas216_pio - transfer data off of/on to card using programmed IO - * @info: interface to transfer data to/from - * @direction: direction to transfer data (DMA_OUT/DMA_IN) - * - * Transfer data off of/on to card using programmed IO. - * Notes: this is incredibly slow. - */ -static void fas216_pio(FAS216_Info *info, fasdmadir_t direction) -{ - struct scsi_pointer *SCp = &info->scsi.SCp; - - fas216_checkmagic(info); - - if (direction == DMA_OUT) - fas216_writeb(info, REG_FF, get_next_SCp_byte(SCp)); - else - put_next_SCp_byte(SCp, fas216_readb(info, REG_FF)); - - if (SCp->this_residual == 0) - next_SCp(SCp); -} - -static void fas216_set_stc(FAS216_Info *info, unsigned int length) -{ - fas216_writeb(info, REG_STCL, length); - fas216_writeb(info, REG_STCM, length >> 8); - fas216_writeb(info, REG_STCH, length >> 16); -} - -static unsigned int fas216_get_ctc(FAS216_Info *info) -{ - return fas216_readb(info, REG_CTCL) + - (fas216_readb(info, REG_CTCM) << 8) + - (fas216_readb(info, REG_CTCH) << 16); -} - -/** - * fas216_cleanuptransfer - clean up after a transfer has completed. - * @info: interface to clean up - * - * Update the data pointers according to the number of bytes transferred - * on the SCSI bus. - */ -static void fas216_cleanuptransfer(FAS216_Info *info) -{ - unsigned long total, residual, fifo; - fasdmatype_t dmatype = info->dma.transfer_type; - - info->dma.transfer_type = fasdma_none; - - /* - * PIO transfers do not need to be cleaned up. - */ - if (dmatype == fasdma_pio || dmatype == fasdma_none) - return; - - if (dmatype == fasdma_real_all) - total = info->scsi.SCp.phase; - else - total = info->scsi.SCp.this_residual; - - residual = fas216_get_ctc(info); - - fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; - - fas216_log(info, LOG_BUFFER, "cleaning up from previous " - "transfer: length 0x%06x, residual 0x%x, fifo %d", - total, residual, fifo); - - /* - * If we were performing Data-Out, the transfer counter - * counts down each time a byte is transferred by the - * host to the FIFO. This means we must include the - * bytes left in the FIFO from the transfer counter. - */ - if (info->scsi.phase == PHASE_DATAOUT) - residual += fifo; - - fas216_updateptrs(info, total - residual); -} - -/** - * fas216_transfer - Perform a DMA/PIO transfer off of/on to card - * @info: interface from which device disconnected from - * - * Start a DMA/PIO transfer off of/on to card - */ -static void fas216_transfer(FAS216_Info *info) -{ - fasdmadir_t direction; - fasdmatype_t dmatype; - - fas216_log(info, LOG_BUFFER, - "starttransfer: buffer %p length 0x%06x reqlen 0x%06x", - info->scsi.SCp.ptr, info->scsi.SCp.this_residual, - info->scsi.SCp.phase); - - if (!info->scsi.SCp.ptr) { - fas216_log(info, LOG_ERROR, "null buffer passed to " - "fas216_starttransfer"); - print_SCp(&info->scsi.SCp, "SCp: ", "\n"); - print_SCp(&info->SCpnt->SCp, "Cmnd SCp: ", "\n"); - return; - } - - /* - * If we have a synchronous transfer agreement in effect, we must - * use DMA mode. If we are using asynchronous transfers, we may - * use DMA mode or PIO mode. - */ - if (info->device[info->SCpnt->device->id].sof) - dmatype = fasdma_real_all; - else - dmatype = fasdma_pio; - - if (info->scsi.phase == PHASE_DATAOUT) - direction = DMA_OUT; - else - direction = DMA_IN; - - if (info->dma.setup) - dmatype = info->dma.setup(info->host, &info->scsi.SCp, - direction, dmatype); - info->dma.transfer_type = dmatype; - - if (dmatype == fasdma_real_all) - fas216_set_stc(info, info->scsi.SCp.phase); - else - fas216_set_stc(info, info->scsi.SCp.this_residual); - - switch (dmatype) { - case fasdma_pio: - fas216_log(info, LOG_BUFFER, "PIO transfer"); - fas216_writeb(info, REG_SOF, 0); - fas216_writeb(info, REG_STP, info->scsi.async_stp); - fas216_cmd(info, CMD_TRANSFERINFO); - fas216_pio(info, direction); - break; - - case fasdma_pseudo: - fas216_log(info, LOG_BUFFER, "pseudo transfer"); - fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA); - info->dma.pseudo(info->host, &info->scsi.SCp, - direction, info->SCpnt->transfersize); - break; - - case fasdma_real_block: - fas216_log(info, LOG_BUFFER, "block dma transfer"); - fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA); - break; - - case fasdma_real_all: - fas216_log(info, LOG_BUFFER, "total dma transfer"); - fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA); - break; - - default: - fas216_log(info, LOG_BUFFER | LOG_ERROR, - "invalid FAS216 DMA type"); - break; - } -} - -/** - * fas216_stoptransfer - Stop a DMA transfer onto / off of the card - * @info: interface from which device disconnected from - * - * Called when we switch away from DATA IN or DATA OUT phases. - */ -static void fas216_stoptransfer(FAS216_Info *info) -{ - fas216_checkmagic(info); - - if (info->dma.transfer_type == fasdma_real_all || - info->dma.transfer_type == fasdma_real_block) - info->dma.stop(info->host, &info->scsi.SCp); - - fas216_cleanuptransfer(info); - - if (info->scsi.phase == PHASE_DATAIN) { - unsigned int fifo; - - /* - * If we were performing Data-In, then the FIFO counter - * contains the number of bytes not transferred via DMA - * from the on-board FIFO. Read them manually. - */ - fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; - while (fifo && info->scsi.SCp.ptr) { - *info->scsi.SCp.ptr = fas216_readb(info, REG_FF); - fas216_updateptrs(info, 1); - fifo--; - } - } else { - /* - * After a Data-Out phase, there may be unsent - * bytes left in the FIFO. Flush them out. - */ - fas216_cmd(info, CMD_FLUSHFIFO); - } -} - -static void fas216_aborttransfer(FAS216_Info *info) -{ - fas216_checkmagic(info); - - if (info->dma.transfer_type == fasdma_real_all || - info->dma.transfer_type == fasdma_real_block) - info->dma.stop(info->host, &info->scsi.SCp); - - info->dma.transfer_type = fasdma_none; - fas216_cmd(info, CMD_FLUSHFIFO); -} - -static void fas216_kick(FAS216_Info *info); - -/** - * fas216_disconnected_intr - handle device disconnection - * @info: interface from which device disconnected from - * - * Handle device disconnection - */ -static void fas216_disconnect_intr(FAS216_Info *info) -{ - unsigned long flags; - - fas216_checkmagic(info); - - fas216_log(info, LOG_CONNECT, "disconnect phase=%02x", - info->scsi.phase); - - msgqueue_flush(&info->scsi.msgs); - - switch (info->scsi.phase) { - case PHASE_SELECTION: /* while selecting - no target */ - case PHASE_SELSTEPS: - fas216_done(info, DID_NO_CONNECT); - break; - - case PHASE_MSGIN_DISCONNECT: /* message in - disconnecting */ - info->scsi.disconnectable = 1; - info->scsi.phase = PHASE_IDLE; - info->stats.disconnects += 1; - spin_lock_irqsave(&info->host_lock, flags); - if (info->scsi.phase == PHASE_IDLE) - fas216_kick(info); - spin_unlock_irqrestore(&info->host_lock, flags); - break; - - case PHASE_DONE: /* at end of command - complete */ - fas216_done(info, DID_OK); - break; - - case PHASE_MSGOUT: /* message out - possible ABORT message */ - if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) { - info->scsi.aborting = 0; - fas216_done(info, DID_ABORT); - break; - } - - default: /* huh? */ - printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n", - info->host->host_no, fas216_target(info), fas216_drv_phase(info)); - print_debug_list(); - fas216_stoptransfer(info); - fas216_done(info, DID_ERROR); - break; - } -} - -/** - * fas216_reselected_intr - start reconnection of a device - * @info: interface which was reselected - * - * Start reconnection of a device - */ -static void -fas216_reselected_intr(FAS216_Info *info) -{ - unsigned int cfis, i; - unsigned char msg[4]; - unsigned char target, lun, tag; - - fas216_checkmagic(info); - - WARN_ON(info->scsi.phase == PHASE_SELECTION || - info->scsi.phase == PHASE_SELSTEPS); - - cfis = fas216_readb(info, REG_CFIS); - - fas216_log(info, LOG_CONNECT, "reconnect phase=%02x cfis=%02x", - info->scsi.phase, cfis); - - cfis &= CFIS_CF; - - if (cfis < 2 || cfis > 4) { - printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n", - info->host->host_no); - goto bad_message; - } - - for (i = 0; i < cfis; i++) - msg[i] = fas216_readb(info, REG_FF); - - if (!(msg[0] & (1 << info->host->this_id)) || - !(msg[1] & 0x80)) - goto initiator_error; - - target = msg[0] & ~(1 << info->host->this_id); - target = ffs(target) - 1; - lun = msg[1] & 7; - tag = 0; - - if (cfis >= 3) { - if (msg[2] != SIMPLE_QUEUE_TAG) - goto initiator_error; - - tag = msg[3]; - } - - /* set up for synchronous transfers */ - fas216_writeb(info, REG_SDID, target); - fas216_set_sync(info, target); - msgqueue_flush(&info->scsi.msgs); - - fas216_log(info, LOG_CONNECT, "Reconnected: target %1x lun %1x tag %02x", - target, lun, tag); - - if (info->scsi.disconnectable && info->SCpnt) { - info->scsi.disconnectable = 0; - if (info->SCpnt->device->id == target && - info->SCpnt->device->lun == lun && - info->SCpnt->tag == tag) { - fas216_log(info, LOG_CONNECT, "reconnected previously executing command"); - } else { - queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt); - fas216_log(info, LOG_CONNECT, "had to move command to disconnected queue"); - info->SCpnt = NULL; - } - } - if (!info->SCpnt) { - info->SCpnt = queue_remove_tgtluntag(&info->queues.disconnected, - target, lun, tag); - fas216_log(info, LOG_CONNECT, "had to get command"); - } - - if (info->SCpnt) { - /* - * Restore data pointer from SAVED data pointer - */ - info->scsi.SCp = info->SCpnt->SCp; - - fas216_log(info, LOG_CONNECT, "data pointers: [%p, %X]", - info->scsi.SCp.ptr, info->scsi.SCp.this_residual); - info->scsi.phase = PHASE_MSGIN; - } else { - /* - * Our command structure not found - abort the - * command on the target. Since we have no - * record of this command, we can't send - * an INITIATOR DETECTED ERROR message. - */ - fas216_cmd(info, CMD_SETATN); - -#if 0 - if (tag) - msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, tag); - else -#endif - msgqueue_addmsg(&info->scsi.msgs, 1, ABORT); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - info->scsi.aborting = 1; - } - - fas216_cmd(info, CMD_MSGACCEPTED); - return; - - initiator_error: - printk(KERN_ERR "scsi%d.H: error during reselection: bytes", - info->host->host_no); - for (i = 0; i < cfis; i++) - printk(" %02x", msg[i]); - printk("\n"); - bad_message: - fas216_cmd(info, CMD_SETATN); - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - fas216_cmd(info, CMD_MSGACCEPTED); -} - -static void fas216_parse_message(FAS216_Info *info, unsigned char *message, int msglen) -{ - int i; - - switch (message[0]) { - case COMMAND_COMPLETE: - if (msglen != 1) - goto unrecognised; - - printk(KERN_ERR "scsi%d.%c: command complete with no " - "status in MESSAGE_IN?\n", - info->host->host_no, fas216_target(info)); - break; - - case SAVE_POINTERS: - if (msglen != 1) - goto unrecognised; - - /* - * Save current data pointer to SAVED data pointer - * SCSI II standard says that we must not acknowledge - * this until we have really saved pointers. - * NOTE: we DO NOT save the command nor status pointers - * as required by the SCSI II standard. These always - * point to the start of their respective areas. - */ - info->SCpnt->SCp = info->scsi.SCp; - info->SCpnt->SCp.sent_command = 0; - fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER, - "save data pointers: [%p, %X]", - info->scsi.SCp.ptr, info->scsi.SCp.this_residual); - break; - - case RESTORE_POINTERS: - if (msglen != 1) - goto unrecognised; - - /* - * Restore current data pointer from SAVED data pointer - */ - info->scsi.SCp = info->SCpnt->SCp; - fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER, - "restore data pointers: [%p, 0x%x]", - info->scsi.SCp.ptr, info->scsi.SCp.this_residual); - break; - - case DISCONNECT: - if (msglen != 1) - goto unrecognised; - - info->scsi.phase = PHASE_MSGIN_DISCONNECT; - break; - - case MESSAGE_REJECT: - if (msglen != 1) - goto unrecognised; - - switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) { - case EXTENDED_MESSAGE | EXTENDED_SDTR << 8: - fas216_handlesync(info, message); - break; - - default: - fas216_log(info, 0, "reject, last message 0x%04x", - fas216_get_last_msg(info, info->scsi.msgin_fifo)); - } - break; - - case NOP: - break; - - case EXTENDED_MESSAGE: - if (msglen < 3) - goto unrecognised; - - switch (message[2]) { - case EXTENDED_SDTR: /* Sync transfer negotiation request/reply */ - fas216_handlesync(info, message); - break; - - default: - goto unrecognised; - } - break; - - default: - goto unrecognised; - } - return; - -unrecognised: - fas216_log(info, 0, "unrecognised message, rejecting"); - printk("scsi%d.%c: message was", info->host->host_no, fas216_target(info)); - for (i = 0; i < msglen; i++) - printk("%s%02X", i & 31 ? " " : "\n ", message[i]); - printk("\n"); - - /* - * Something strange seems to be happening here - - * I can't use SETATN since the chip gives me an - * invalid command interrupt when I do. Weird. - */ -fas216_cmd(info, CMD_NOP); -fas216_dumpstate(info); - fas216_cmd(info, CMD_SETATN); - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT); - info->scsi.phase = PHASE_MSGOUT_EXPECT; -fas216_dumpstate(info); -} - -static int fas216_wait_cmd(FAS216_Info *info, int cmd) -{ - int tout; - int stat; - - fas216_cmd(info, cmd); - - for (tout = 1000; tout; tout -= 1) { - stat = fas216_readb(info, REG_STAT); - if (stat & (STAT_INT|STAT_PARITYERROR)) - break; - udelay(1); - } - - return stat; -} - -static int fas216_get_msg_byte(FAS216_Info *info) -{ - unsigned int stat = fas216_wait_cmd(info, CMD_MSGACCEPTED); - - if ((stat & STAT_INT) == 0) - goto timedout; - - if ((stat & STAT_BUSMASK) != STAT_MESGIN) - goto unexpected_phase_change; - - fas216_readb(info, REG_INST); - - stat = fas216_wait_cmd(info, CMD_TRANSFERINFO); - - if ((stat & STAT_INT) == 0) - goto timedout; - - if (stat & STAT_PARITYERROR) - goto parity_error; - - if ((stat & STAT_BUSMASK) != STAT_MESGIN) - goto unexpected_phase_change; - - fas216_readb(info, REG_INST); - - return fas216_readb(info, REG_FF); - -timedout: - fas216_log(info, LOG_ERROR, "timed out waiting for message byte"); - return -1; - -unexpected_phase_change: - fas216_log(info, LOG_ERROR, "unexpected phase change: status = %02x", stat); - return -2; - -parity_error: - fas216_log(info, LOG_ERROR, "parity error during message in phase"); - return -3; -} - -/** - * fas216_message - handle a function done interrupt from FAS216 chip - * @info: interface which caused function done interrupt - * - * Handle a function done interrupt from FAS216 chip - */ -static void fas216_message(FAS216_Info *info) -{ - unsigned char *message = info->scsi.message; - unsigned int msglen = 1; - int msgbyte = 0; - - fas216_checkmagic(info); - - message[0] = fas216_readb(info, REG_FF); - - if (message[0] == EXTENDED_MESSAGE) { - msgbyte = fas216_get_msg_byte(info); - - if (msgbyte >= 0) { - message[1] = msgbyte; - - for (msglen = 2; msglen < message[1] + 2; msglen++) { - msgbyte = fas216_get_msg_byte(info); - - if (msgbyte >= 0) - message[msglen] = msgbyte; - else - break; - } - } - } - - if (msgbyte == -3) - goto parity_error; - -#ifdef DEBUG_MESSAGES - { - int i; - - printk("scsi%d.%c: message in: ", - info->host->host_no, fas216_target(info)); - for (i = 0; i < msglen; i++) - printk("%02X ", message[i]); - printk("\n"); - } -#endif - - fas216_parse_message(info, message, msglen); - fas216_cmd(info, CMD_MSGACCEPTED); - return; - -parity_error: - fas216_cmd(info, CMD_SETATN); - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, MSG_PARITY_ERROR); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - fas216_cmd(info, CMD_MSGACCEPTED); - return; -} - -/** - * fas216_send_command - send command after all message bytes have been sent - * @info: interface which caused bus service - * - * Send a command to a target after all message bytes have been sent - */ -static void fas216_send_command(FAS216_Info *info) -{ - int i; - - fas216_checkmagic(info); - - fas216_cmd(info, CMD_NOP|CMD_WITHDMA); - fas216_cmd(info, CMD_FLUSHFIFO); - - /* load command */ - for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++) - fas216_writeb(info, REG_FF, info->SCpnt->cmnd[i]); - - fas216_cmd(info, CMD_TRANSFERINFO); - - info->scsi.phase = PHASE_COMMAND; -} - -/** - * fas216_send_messageout - handle bus service to send a message - * @info: interface which caused bus service - * - * Handle bus service to send a message. - * Note: We do not allow the device to change the data direction! - */ -static void fas216_send_messageout(FAS216_Info *info, int start) -{ - unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs); - - fas216_checkmagic(info); - - fas216_cmd(info, CMD_FLUSHFIFO); - - if (tot_msglen) { - struct message *msg; - int msgnr = 0; - - while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { - int i; - - for (i = start; i < msg->length; i++) - fas216_writeb(info, REG_FF, msg->msg[i]); - - msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF); - start = 0; - } - } else - fas216_writeb(info, REG_FF, NOP); - - fas216_cmd(info, CMD_TRANSFERINFO); - - info->scsi.phase = PHASE_MSGOUT; -} - -/** - * fas216_busservice_intr - handle bus service interrupt from FAS216 chip - * @info: interface which caused bus service interrupt - * @stat: Status register contents - * @is: SCSI Status register contents - * - * Handle a bus service interrupt from FAS216 chip - */ -static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int is) -{ - fas216_checkmagic(info); - - fas216_log(info, LOG_BUSSERVICE, - "bus service: stat=%02x is=%02x phase=%02x", - stat, is, info->scsi.phase); - - switch (info->scsi.phase) { - case PHASE_SELECTION: - if ((is & IS_BITS) != IS_MSGBYTESENT) - goto bad_is; - break; - - case PHASE_SELSTEPS: - switch (is & IS_BITS) { - case IS_SELARB: - case IS_MSGBYTESENT: - goto bad_is; - - case IS_NOTCOMMAND: - case IS_EARLYPHASE: - if ((stat & STAT_BUSMASK) == STAT_MESGIN) - break; - goto bad_is; - - case IS_COMPLETE: - break; - } - - default: - break; - } - - fas216_cmd(info, CMD_NOP); - -#define STATE(st,ph) ((ph) << 3 | (st)) - /* This table describes the legal SCSI state transitions, - * as described by the SCSI II spec. - */ - switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) { - case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In */ - case STATE(STAT_DATAIN, PHASE_MSGOUT): /* Message Out -> Data In */ - case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command -> Data In */ - case STATE(STAT_DATAIN, PHASE_MSGIN): /* Message In -> Data In */ - info->scsi.phase = PHASE_DATAIN; - fas216_transfer(info); - return; - - case STATE(STAT_DATAIN, PHASE_DATAIN): /* Data In -> Data In */ - case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out -> Data Out */ - fas216_cleanuptransfer(info); - fas216_transfer(info); - return; - - case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out */ - case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out -> Data Out */ - case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command -> Data Out */ - case STATE(STAT_DATAOUT, PHASE_MSGIN): /* Message In -> Data Out */ - fas216_cmd(info, CMD_FLUSHFIFO); - info->scsi.phase = PHASE_DATAOUT; - fas216_transfer(info); - return; - - case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out -> Status */ - case STATE(STAT_STATUS, PHASE_DATAIN): /* Data In -> Status */ - fas216_stoptransfer(info); - case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status */ - case STATE(STAT_STATUS, PHASE_MSGOUT): /* Message Out -> Status */ - case STATE(STAT_STATUS, PHASE_COMMAND): /* Command -> Status */ - case STATE(STAT_STATUS, PHASE_MSGIN): /* Message In -> Status */ - fas216_cmd(info, CMD_INITCMDCOMPLETE); - info->scsi.phase = PHASE_STATUS; - return; - - case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out -> Message In */ - case STATE(STAT_MESGIN, PHASE_DATAIN): /* Data In -> Message In */ - fas216_stoptransfer(info); - case STATE(STAT_MESGIN, PHASE_COMMAND): /* Command -> Message In */ - case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In */ - case STATE(STAT_MESGIN, PHASE_MSGOUT): /* Message Out -> Message In */ - info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; - fas216_cmd(info, CMD_FLUSHFIFO); - fas216_cmd(info, CMD_TRANSFERINFO); - info->scsi.phase = PHASE_MSGIN; - return; - - case STATE(STAT_MESGIN, PHASE_MSGIN): - info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF; - fas216_cmd(info, CMD_TRANSFERINFO); - return; - - case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out -> Command */ - case STATE(STAT_COMMAND, PHASE_MSGIN): /* Message In -> Command */ - fas216_send_command(info); - info->scsi.phase = PHASE_COMMAND; - return; - - - /* - * Selection -> Message Out - */ - case STATE(STAT_MESGOUT, PHASE_SELECTION): - fas216_send_messageout(info, 1); - return; - - /* - * Message Out -> Message Out - */ - case STATE(STAT_MESGOUT, PHASE_SELSTEPS): - case STATE(STAT_MESGOUT, PHASE_MSGOUT): - /* - * If we get another message out phase, this usually - * means some parity error occurred. Resend complete - * set of messages. If we have more than one byte to - * send, we need to assert ATN again. - */ - if (info->device[info->SCpnt->device->id].parity_check) { - /* - * We were testing... good, the device - * supports parity checking. - */ - info->device[info->SCpnt->device->id].parity_check = 0; - info->device[info->SCpnt->device->id].parity_enabled = 1; - fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); - } - - if (msgqueue_msglength(&info->scsi.msgs) > 1) - fas216_cmd(info, CMD_SETATN); - /*FALLTHROUGH*/ - - /* - * Any -> Message Out - */ - case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT): - fas216_send_messageout(info, 0); - return; - - /* Error recovery rules. - * These either attempt to abort or retry the operation. - * TODO: we need more of these - */ - case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command -> Command */ - /* error - we've sent out all the command bytes - * we have. - * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS - * to include the command bytes sent for this to work - * correctly. - */ - printk(KERN_ERR "scsi%d.%c: " - "target trying to receive more command bytes\n", - info->host->host_no, fas216_target(info)); - fas216_cmd(info, CMD_SETATN); - fas216_set_stc(info, 15); - fas216_cmd(info, CMD_PADBYTES | CMD_WITHDMA); - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - return; - } - - if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) { - printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat)); - msgqueue_flush(&info->scsi.msgs); - fas216_cmd(info, CMD_SETATN); - msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR); - info->scsi.phase = PHASE_MSGOUT_EXPECT; - info->scsi.aborting = 1; - fas216_cmd(info, CMD_TRANSFERINFO); - return; - } - printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n", - info->host->host_no, fas216_target(info), - fas216_bus_phase(stat), - fas216_drv_phase(info)); - print_debug_list(); - return; - -bad_is: - fas216_log(info, 0, "bus service at step %d?", is & IS_BITS); - fas216_dumpstate(info); - print_debug_list(); - - fas216_done(info, DID_ERROR); -} - -/** - * fas216_funcdone_intr - handle a function done interrupt from FAS216 chip - * @info: interface which caused function done interrupt - * @stat: Status register contents - * @is: SCSI Status register contents - * - * Handle a function done interrupt from FAS216 chip - */ -static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int is) -{ - unsigned int fifo_len = fas216_readb(info, REG_CFIS) & CFIS_CF; - - fas216_checkmagic(info); - - fas216_log(info, LOG_FUNCTIONDONE, - "function done: stat=%02x is=%02x phase=%02x", - stat, is, info->scsi.phase); - - switch (info->scsi.phase) { - case PHASE_STATUS: /* status phase - read status and msg */ - if (fifo_len != 2) { - fas216_log(info, 0, "odd number of bytes in FIFO: %d", fifo_len); - } - /* - * Read status then message byte. - */ - info->scsi.SCp.Status = fas216_readb(info, REG_FF); - info->scsi.SCp.Message = fas216_readb(info, REG_FF); - info->scsi.phase = PHASE_DONE; - fas216_cmd(info, CMD_MSGACCEPTED); - break; - - case PHASE_IDLE: - case PHASE_SELECTION: - case PHASE_SELSTEPS: - break; - - case PHASE_MSGIN: /* message in phase */ - if ((stat & STAT_BUSMASK) == STAT_MESGIN) { - info->scsi.msgin_fifo = fifo_len; - fas216_message(info); - break; - } - - default: - fas216_log(info, 0, "internal phase %s for function done?" - " What do I do with this?", - fas216_target(info), fas216_drv_phase(info)); - } -} - -static void fas216_bus_reset(FAS216_Info *info) -{ - neg_t sync_state; - int i; - - msgqueue_flush(&info->scsi.msgs); - - sync_state = neg_invalid; - -#ifdef SCSI2_SYNC - if (info->ifcfg.capabilities & (FASCAP_DMA|FASCAP_PSEUDODMA)) - sync_state = neg_wait; -#endif - - info->scsi.phase = PHASE_IDLE; - info->SCpnt = NULL; /* bug! */ - memset(&info->scsi.SCp, 0, sizeof(info->scsi.SCp)); - - for (i = 0; i < 8; i++) { - info->device[i].disconnect_ok = info->ifcfg.disconnect_ok; - info->device[i].sync_state = sync_state; - info->device[i].period = info->ifcfg.asyncperiod / 4; - info->device[i].stp = info->scsi.async_stp; - info->device[i].sof = 0; - info->device[i].wide_xfer = 0; - } - - info->rst_bus_status = 1; - wake_up(&info->eh_wait); -} - -/** - * fas216_intr - handle interrupts to progress a command - * @info: interface to service - * - * Handle interrupts from the interface to progress a command - */ -irqreturn_t fas216_intr(FAS216_Info *info) -{ - unsigned char inst, is, stat; - int handled = IRQ_NONE; - - fas216_checkmagic(info); - - stat = fas216_readb(info, REG_STAT); - is = fas216_readb(info, REG_IS); - inst = fas216_readb(info, REG_INST); - - add_debug_list(stat, is, inst, info->scsi.phase); - - if (stat & STAT_INT) { - if (inst & INST_BUSRESET) { - fas216_log(info, 0, "bus reset detected"); - fas216_bus_reset(info); - scsi_report_bus_reset(info->host, 0); - } else if (inst & INST_ILLEGALCMD) { - fas216_log(info, LOG_ERROR, "illegal command given\n"); - fas216_dumpstate(info); - print_debug_list(); - } else if (inst & INST_DISCONNECT) - fas216_disconnect_intr(info); - else if (inst & INST_RESELECTED) /* reselected */ - fas216_reselected_intr(info); - else if (inst & INST_BUSSERVICE) /* bus service request */ - fas216_busservice_intr(info, stat, is); - else if (inst & INST_FUNCDONE) /* function done */ - fas216_funcdone_intr(info, stat, is); - else - fas216_log(info, 0, "unknown interrupt received:" - " phase %s inst %02X is %02X stat %02X", - fas216_drv_phase(info), inst, is, stat); - handled = IRQ_HANDLED; - } - return handled; -} - -static void __fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt) -{ - int tot_msglen; - - /* following what the ESP driver says */ - fas216_set_stc(info, 0); - fas216_cmd(info, CMD_NOP | CMD_WITHDMA); - - /* flush FIFO */ - fas216_cmd(info, CMD_FLUSHFIFO); - - /* load bus-id and timeout */ - fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id)); - fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout); - - /* synchronous transfers */ - fas216_set_sync(info, SCpnt->device->id); - - tot_msglen = msgqueue_msglength(&info->scsi.msgs); - -#ifdef DEBUG_MESSAGES - { - struct message *msg; - int msgnr = 0, i; - - printk("scsi%d.%c: message out: ", - info->host->host_no, '0' + SCpnt->device->id); - while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { - printk("{ "); - for (i = 0; i < msg->length; i++) - printk("%02x ", msg->msg[i]); - printk("} "); - } - printk("\n"); - } -#endif - - if (tot_msglen == 1 || tot_msglen == 3) { - /* - * We have an easy message length to send... - */ - struct message *msg; - int msgnr = 0, i; - - info->scsi.phase = PHASE_SELSTEPS; - - /* load message bytes */ - while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) { - for (i = 0; i < msg->length; i++) - fas216_writeb(info, REG_FF, msg->msg[i]); - msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF); - } - - /* load command */ - for (i = 0; i < SCpnt->cmd_len; i++) - fas216_writeb(info, REG_FF, SCpnt->cmnd[i]); - - if (tot_msglen == 1) - fas216_cmd(info, CMD_SELECTATN); - else - fas216_cmd(info, CMD_SELECTATN3); - } else { - /* - * We have an unusual number of message bytes to send. - * Load first byte into fifo, and issue SELECT with ATN and - * stop steps. - */ - struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0); - - fas216_writeb(info, REG_FF, msg->msg[0]); - msg->fifo = 1; - - fas216_cmd(info, CMD_SELECTATNSTOP); - } -} - -/* - * Decide whether we need to perform a parity test on this device. - * Can also be used to force parity error conditions during initial - * information transfer phase (message out) for test purposes. - */ -static int parity_test(FAS216_Info *info, int target) -{ -#if 0 - if (target == 3) { - info->device[target].parity_check = 0; - return 1; - } -#endif - return info->device[target].parity_check; -} - -static void fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt) -{ - int disconnect_ok; - - /* - * claim host busy - */ - info->scsi.phase = PHASE_SELECTION; - info->scsi.SCp = SCpnt->SCp; - info->SCpnt = SCpnt; - info->dma.transfer_type = fasdma_none; - - if (parity_test(info, SCpnt->device->id)) - fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_PTE); - else - fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); - - /* - * Don't allow request sense commands to disconnect. - */ - disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE && - info->device[SCpnt->device->id].disconnect_ok; - - /* - * build outgoing message bytes - */ - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->device->lun)); - - /* - * add tag message if required - */ - if (SCpnt->tag) - msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag); - - do { -#ifdef SCSI2_SYNC - if ((info->device[SCpnt->device->id].sync_state == neg_wait || - info->device[SCpnt->device->id].sync_state == neg_complete) && - (SCpnt->cmnd[0] == REQUEST_SENSE || - SCpnt->cmnd[0] == INQUIRY)) { - info->device[SCpnt->device->id].sync_state = neg_inprogress; - msgqueue_addmsg(&info->scsi.msgs, 5, - EXTENDED_MESSAGE, 3, EXTENDED_SDTR, - 1000 / info->ifcfg.clockrate, - info->ifcfg.sync_max_depth); - break; - } -#endif - } while (0); - - __fas216_start_command(info, SCpnt); -} - -static void fas216_allocate_tag(FAS216_Info *info, struct scsi_cmnd *SCpnt) -{ -#ifdef SCSI2_TAG - /* - * tagged queuing - allocate a new tag to this command - */ - if (SCpnt->device->simple_tags && SCpnt->cmnd[0] != REQUEST_SENSE && - SCpnt->cmnd[0] != INQUIRY) { - SCpnt->device->current_tag += 1; - if (SCpnt->device->current_tag == 0) - SCpnt->device->current_tag = 1; - SCpnt->tag = SCpnt->device->current_tag; - } else -#endif - set_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns); - - info->stats.removes += 1; - switch (SCpnt->cmnd[0]) { - case WRITE_6: - case WRITE_10: - case WRITE_12: - info->stats.writes += 1; - break; - case READ_6: - case READ_10: - case READ_12: - info->stats.reads += 1; - break; - default: - info->stats.miscs += 1; - break; - } -} - -static void fas216_do_bus_device_reset(FAS216_Info *info, - struct scsi_cmnd *SCpnt) -{ - struct message *msg; - - /* - * claim host busy - */ - info->scsi.phase = PHASE_SELECTION; - info->scsi.SCp = SCpnt->SCp; - info->SCpnt = SCpnt; - info->dma.transfer_type = fasdma_none; - - fas216_log(info, LOG_ERROR, "sending bus device reset"); - - msgqueue_flush(&info->scsi.msgs); - msgqueue_addmsg(&info->scsi.msgs, 1, BUS_DEVICE_RESET); - - /* following what the ESP driver says */ - fas216_set_stc(info, 0); - fas216_cmd(info, CMD_NOP | CMD_WITHDMA); - - /* flush FIFO */ - fas216_cmd(info, CMD_FLUSHFIFO); - - /* load bus-id and timeout */ - fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id)); - fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout); - - /* synchronous transfers */ - fas216_set_sync(info, SCpnt->device->id); - - msg = msgqueue_getmsg(&info->scsi.msgs, 0); - - fas216_writeb(info, REG_FF, BUS_DEVICE_RESET); - msg->fifo = 1; - - fas216_cmd(info, CMD_SELECTATNSTOP); -} - -/** - * fas216_kick - kick a command to the interface - * @info: our host interface to kick - * - * Kick a command to the interface, interface should be idle. - * Notes: Interrupts are always disabled! - */ -static void fas216_kick(FAS216_Info *info) -{ - struct scsi_cmnd *SCpnt = NULL; -#define TYPE_OTHER 0 -#define TYPE_RESET 1 -#define TYPE_QUEUE 2 - int where_from = TYPE_OTHER; - - fas216_checkmagic(info); - - /* - * Obtain the next command to process. - */ - do { - if (info->rstSCpnt) { - SCpnt = info->rstSCpnt; - /* don't remove it */ - where_from = TYPE_RESET; - break; - } - - if (info->reqSCpnt) { - SCpnt = info->reqSCpnt; - info->reqSCpnt = NULL; - break; - } - - if (info->origSCpnt) { - SCpnt = info->origSCpnt; - info->origSCpnt = NULL; - break; - } - - /* retrieve next command */ - if (!SCpnt) { - SCpnt = queue_remove_exclude(&info->queues.issue, - info->busyluns); - where_from = TYPE_QUEUE; - break; - } - } while (0); - - if (!SCpnt) { - /* - * no command pending, so enable reselection. - */ - fas216_cmd(info, CMD_ENABLESEL); - return; - } - - /* - * We're going to start a command, so disable reselection - */ - fas216_cmd(info, CMD_DISABLESEL); - - if (info->scsi.disconnectable && info->SCpnt) { - fas216_log(info, LOG_CONNECT, - "moved command for %d to disconnected queue", - info->SCpnt->device->id); - queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt); - info->scsi.disconnectable = 0; - info->SCpnt = NULL; - } - - fas216_log_command(info, LOG_CONNECT | LOG_MESSAGES, SCpnt, - "starting"); - - switch (where_from) { - case TYPE_QUEUE: - fas216_allocate_tag(info, SCpnt); - case TYPE_OTHER: - fas216_start_command(info, SCpnt); - break; - case TYPE_RESET: - fas216_do_bus_device_reset(info, SCpnt); - break; - } - - fas216_log(info, LOG_CONNECT, "select: data pointers [%p, %X]", - info->scsi.SCp.ptr, info->scsi.SCp.this_residual); - - /* - * should now get either DISCONNECT or - * (FUNCTION DONE with BUS SERVICE) interrupt - */ -} - -/* - * Clean up from issuing a BUS DEVICE RESET message to a device. - */ -static void fas216_devicereset_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, - unsigned int result) -{ - fas216_log(info, LOG_ERROR, "fas216 device reset complete"); - - info->rstSCpnt = NULL; - info->rst_dev_status = 1; - wake_up(&info->eh_wait); -} - -/** - * fas216_rq_sns_done - Finish processing automatic request sense command - * @info: interface that completed - * @SCpnt: command that completed - * @result: driver byte of result - * - * Finish processing automatic request sense command - */ -static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, - unsigned int result) -{ - fas216_log_target(info, LOG_CONNECT, SCpnt->device->id, - "request sense complete, result=0x%04x%02x%02x", - result, SCpnt->SCp.Message, SCpnt->SCp.Status); - - if (result != DID_OK || SCpnt->SCp.Status != GOOD) - /* - * Something went wrong. Make sure that we don't - * have valid data in the sense buffer that could - * confuse the higher levels. - */ - memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer)); -//printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id); -//{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); } - /* - * Note that we don't set SCpnt->result, since that should - * reflect the status of the command that we were asked by - * the upper layers to process. This would have been set - * correctly by fas216_std_done. - */ - scsi_eh_restore_cmnd(SCpnt, &info->ses); - SCpnt->scsi_done(SCpnt); -} - -/** - * fas216_std_done - finish processing of standard command - * @info: interface that completed - * @SCpnt: command that completed - * @result: driver byte of result - * - * Finish processing of standard command - */ -static void -fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result) -{ - info->stats.fins += 1; - - SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 | - info->scsi.SCp.Status; - - fas216_log_command(info, LOG_CONNECT, SCpnt, - "command complete, result=0x%08x", SCpnt->result); - - /* - * If the driver detected an error, we're all done. - */ - if (host_byte(SCpnt->result) != DID_OK || - msg_byte(SCpnt->result) != COMMAND_COMPLETE) - goto done; - - /* - * If the command returned CHECK_CONDITION or COMMAND_TERMINATED - * status, request the sense information. - */ - if (status_byte(SCpnt->result) == CHECK_CONDITION || - status_byte(SCpnt->result) == COMMAND_TERMINATED) - goto request_sense; - - /* - * If the command did not complete with GOOD status, - * we are all done here. - */ - if (status_byte(SCpnt->result) != GOOD) - goto done; - - /* - * We have successfully completed a command. Make sure that - * we do not have any buffers left to transfer. The world - * is not perfect, and we seem to occasionally hit this. - * It can be indicative of a buggy driver, target or the upper - * levels of the SCSI code. - */ - if (info->scsi.SCp.ptr) { - switch (SCpnt->cmnd[0]) { - case INQUIRY: - case START_STOP: - case MODE_SENSE: - break; - - default: - printk(KERN_ERR "scsi%d.%c: incomplete data transfer " - "detected: res=%08X ptr=%p len=%X CDB: ", - info->host->host_no, '0' + SCpnt->device->id, - SCpnt->result, info->scsi.SCp.ptr, - info->scsi.SCp.this_residual); - __scsi_print_command(SCpnt->cmnd); - SCpnt->result &= ~(255 << 16); - SCpnt->result |= DID_BAD_TARGET << 16; - goto request_sense; - } - } - -done: - if (SCpnt->scsi_done) { - SCpnt->scsi_done(SCpnt); - return; - } - - panic("scsi%d.H: null scsi_done function in fas216_done", - info->host->host_no); - - -request_sense: - if (SCpnt->cmnd[0] == REQUEST_SENSE) - goto done; - - scsi_eh_prep_cmnd(SCpnt, &info->ses, NULL, 0, ~0); - fas216_log_target(info, LOG_CONNECT, SCpnt->device->id, - "requesting sense"); - init_SCp(SCpnt); - SCpnt->SCp.Message = 0; - SCpnt->SCp.Status = 0; - SCpnt->tag = 0; - SCpnt->host_scribble = (void *)fas216_rq_sns_done; - - /* - * Place this command into the high priority "request - * sense" slot. This will be the very next command - * executed, unless a target connects to us. - */ - if (info->reqSCpnt) - printk(KERN_WARNING "scsi%d.%c: losing request command\n", - info->host->host_no, '0' + SCpnt->device->id); - info->reqSCpnt = SCpnt; -} - -/** - * fas216_done - complete processing for current command - * @info: interface that completed - * @result: driver byte of result - * - * Complete processing for current command - */ -static void fas216_done(FAS216_Info *info, unsigned int result) -{ - void (*fn)(FAS216_Info *, struct scsi_cmnd *, unsigned int); - struct scsi_cmnd *SCpnt; - unsigned long flags; - - fas216_checkmagic(info); - - if (!info->SCpnt) - goto no_command; - - SCpnt = info->SCpnt; - info->SCpnt = NULL; - info->scsi.phase = PHASE_IDLE; - - if (info->scsi.aborting) { - fas216_log(info, 0, "uncaught abort - returning DID_ABORT"); - result = DID_ABORT; - info->scsi.aborting = 0; - } - - /* - * Sanity check the completion - if we have zero bytes left - * to transfer, we should not have a valid pointer. - */ - if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) { - printk("scsi%d.%c: zero bytes left to transfer, but " - "buffer pointer still valid: ptr=%p len=%08x CDB: ", - info->host->host_no, '0' + SCpnt->device->id, - info->scsi.SCp.ptr, info->scsi.SCp.this_residual); - info->scsi.SCp.ptr = NULL; - __scsi_print_command(SCpnt->cmnd); - } - - /* - * Clear down this command as completed. If we need to request - * the sense information, fas216_kick will re-assert the busy - * status. - */ - info->device[SCpnt->device->id].parity_check = 0; - clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns); - - fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble; - fn(info, SCpnt, result); - - if (info->scsi.irq) { - spin_lock_irqsave(&info->host_lock, flags); - if (info->scsi.phase == PHASE_IDLE) - fas216_kick(info); - spin_unlock_irqrestore(&info->host_lock, flags); - } - return; - -no_command: - panic("scsi%d.H: null command in fas216_done", - info->host->host_no); -} - -/** - * fas216_queue_command - queue a command for adapter to process. - * @SCpnt: Command to queue - * @done: done function to call once command is complete - * - * Queue a command for adapter to process. - * Returns: 0 on success, else error. - * Notes: io_request_lock is held, interrupts are disabled. - */ -static int fas216_queue_command_lck(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - int result; - - fas216_checkmagic(info); - - fas216_log_command(info, LOG_CONNECT, SCpnt, - "received command (%p)", SCpnt); - - SCpnt->scsi_done = done; - SCpnt->host_scribble = (void *)fas216_std_done; - SCpnt->result = 0; - - init_SCp(SCpnt); - - info->stats.queues += 1; - SCpnt->tag = 0; - - spin_lock(&info->host_lock); - - /* - * Add command into execute queue and let it complete under - * whatever scheme we're using. - */ - result = !queue_add_cmd_ordered(&info->queues.issue, SCpnt); - - /* - * If we successfully added the command, - * kick the interface to get it moving. - */ - if (result == 0 && info->scsi.phase == PHASE_IDLE) - fas216_kick(info); - spin_unlock(&info->host_lock); - - fas216_log_target(info, LOG_CONNECT, -1, "queue %s", - result ? "failure" : "success"); - - return result; -} - -DEF_SCSI_QCMD(fas216_queue_command) - -/** - * fas216_internal_done - trigger restart of a waiting thread in fas216_noqueue_command - * @SCpnt: Command to wake - * - * Trigger restart of a waiting thread in fas216_command - */ -static void fas216_internal_done(struct scsi_cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - - fas216_checkmagic(info); - - info->internal_done = 1; -} - -/** - * fas216_noqueue_command - process a command for the adapter. - * @SCpnt: Command to queue - * - * Queue a command for adapter to process. - * Returns: scsi result code. - * Notes: io_request_lock is held, interrupts are disabled. - */ -static int fas216_noqueue_command_lck(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - - fas216_checkmagic(info); - - /* - * We should only be using this if we don't have an interrupt. - * Provide some "incentive" to use the queueing code. - */ - BUG_ON(info->scsi.irq); - - info->internal_done = 0; - fas216_queue_command_lck(SCpnt, fas216_internal_done); - - /* - * This wastes time, since we can't return until the command is - * complete. We can't sleep either since we may get re-entered! - * However, we must re-enable interrupts, or else we'll be - * waiting forever. - */ - spin_unlock_irq(info->host->host_lock); - - while (!info->internal_done) { - /* - * If we don't have an IRQ, then we must poll the card for - * it's interrupt, and use that to call this driver's - * interrupt routine. That way, we keep the command - * progressing. Maybe we can add some intelligence here - * and go to sleep if we know that the device is going - * to be some time (eg, disconnected). - */ - if (fas216_readb(info, REG_STAT) & STAT_INT) { - spin_lock_irq(info->host->host_lock); - fas216_intr(info); - spin_unlock_irq(info->host->host_lock); - } - } - - spin_lock_irq(info->host->host_lock); - - done(SCpnt); - - return 0; -} - -DEF_SCSI_QCMD(fas216_noqueue_command) - -/* - * Error handler timeout function. Indicate that we timed out, - * and wake up any error handler process so it can continue. - */ -static void fas216_eh_timer(unsigned long data) -{ - FAS216_Info *info = (FAS216_Info *)data; - - fas216_log(info, LOG_ERROR, "error handling timed out\n"); - - del_timer(&info->eh_timer); - - if (info->rst_bus_status == 0) - info->rst_bus_status = -1; - if (info->rst_dev_status == 0) - info->rst_dev_status = -1; - - wake_up(&info->eh_wait); -} - -enum res_find { - res_failed, /* not found */ - res_success, /* command on issue queue */ - res_hw_abort /* command on disconnected dev */ -}; - -/** - * fas216_do_abort - decide how to abort a command - * @SCpnt: command to abort - * - * Decide how to abort a command. - * Returns: abort status - */ -static enum res_find fas216_find_command(FAS216_Info *info, - struct scsi_cmnd *SCpnt) -{ - enum res_find res = res_failed; - - if (queue_remove_cmd(&info->queues.issue, SCpnt)) { - /* - * The command was on the issue queue, and has not been - * issued yet. We can remove the command from the queue, - * and acknowledge the abort. Neither the device nor the - * interface know about the command. - */ - printk("on issue queue "); - - res = res_success; - } else if (queue_remove_cmd(&info->queues.disconnected, SCpnt)) { - /* - * The command was on the disconnected queue. We must - * reconnect with the device if possible, and send it - * an abort message. - */ - printk("on disconnected queue "); - - res = res_hw_abort; - } else if (info->SCpnt == SCpnt) { - printk("executing "); - - switch (info->scsi.phase) { - /* - * If the interface is idle, and the command is 'disconnectable', - * then it is the same as on the disconnected queue. - */ - case PHASE_IDLE: - if (info->scsi.disconnectable) { - info->scsi.disconnectable = 0; - info->SCpnt = NULL; - res = res_hw_abort; - } - break; - - default: - break; - } - } else if (info->origSCpnt == SCpnt) { - /* - * The command will be executed next, but a command - * is currently using the interface. This is similar to - * being on the issue queue, except the busylun bit has - * been set. - */ - info->origSCpnt = NULL; - clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns); - printk("waiting for execution "); - res = res_success; - } else - printk("unknown "); - - return res; -} - -/** - * fas216_eh_abort - abort this command - * @SCpnt: command to abort - * - * Abort this command. - * Returns: FAILED if unable to abort - * Notes: io_request_lock is taken, and irqs are disabled - */ -int fas216_eh_abort(struct scsi_cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - int result = FAILED; - - fas216_checkmagic(info); - - info->stats.aborts += 1; - - printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no); - __scsi_print_command(SCpnt->cmnd); - - print_debug_list(); - fas216_dumpstate(info); - - printk(KERN_WARNING "scsi%d: abort %p ", info->host->host_no, SCpnt); - - switch (fas216_find_command(info, SCpnt)) { - /* - * We found the command, and cleared it out. Either - * the command is still known to be executing on the - * target, or the busylun bit is not set. - */ - case res_success: - printk("success\n"); - result = SUCCESS; - break; - - /* - * We need to reconnect to the target and send it an - * ABORT or ABORT_TAG message. We can only do this - * if the bus is free. - */ - case res_hw_abort: - - - /* - * We are unable to abort the command for some reason. - */ - default: - case res_failed: - printk("failed\n"); - break; - } - - return result; -} - -/** - * fas216_eh_device_reset - Reset the device associated with this command - * @SCpnt: command specifing device to reset - * - * Reset the device associated with this command. - * Returns: FAILED if unable to reset. - * Notes: We won't be re-entered, so we'll only have one device - * reset on the go at one time. - */ -int fas216_eh_device_reset(struct scsi_cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - unsigned long flags; - int i, res = FAILED, target = SCpnt->device->id; - - fas216_log(info, LOG_ERROR, "device reset for target %d", target); - - spin_lock_irqsave(&info->host_lock, flags); - - do { - /* - * If we are currently connected to a device, and - * it is the device we want to reset, there is - * nothing we can do here. Chances are it is stuck, - * and we need a bus reset. - */ - if (info->SCpnt && !info->scsi.disconnectable && - info->SCpnt->device->id == SCpnt->device->id) - break; - - /* - * We're going to be resetting this device. Remove - * all pending commands from the driver. By doing - * so, we guarantee that we won't touch the command - * structures except to process the reset request. - */ - queue_remove_all_target(&info->queues.issue, target); - queue_remove_all_target(&info->queues.disconnected, target); - if (info->origSCpnt && info->origSCpnt->device->id == target) - info->origSCpnt = NULL; - if (info->reqSCpnt && info->reqSCpnt->device->id == target) - info->reqSCpnt = NULL; - for (i = 0; i < 8; i++) - clear_bit(target * 8 + i, info->busyluns); - - /* - * Hijack this SCSI command structure to send - * a bus device reset message to this device. - */ - SCpnt->host_scribble = (void *)fas216_devicereset_done; - - info->rst_dev_status = 0; - info->rstSCpnt = SCpnt; - - if (info->scsi.phase == PHASE_IDLE) - fas216_kick(info); - - mod_timer(&info->eh_timer, jiffies + 30 * HZ); - spin_unlock_irqrestore(&info->host_lock, flags); - - /* - * Wait up to 30 seconds for the reset to complete. - */ - wait_event(info->eh_wait, info->rst_dev_status); - - del_timer_sync(&info->eh_timer); - spin_lock_irqsave(&info->host_lock, flags); - info->rstSCpnt = NULL; - - if (info->rst_dev_status == 1) - res = SUCCESS; - } while (0); - - SCpnt->host_scribble = NULL; - spin_unlock_irqrestore(&info->host_lock, flags); - - fas216_log(info, LOG_ERROR, "device reset complete: %s\n", - res == SUCCESS ? "success" : "failed"); - - return res; -} - -/** - * fas216_eh_bus_reset - Reset the bus associated with the command - * @SCpnt: command specifing bus to reset - * - * Reset the bus associated with the command. - * Returns: FAILED if unable to reset. - * Notes: Further commands are blocked. - */ -int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - unsigned long flags; - struct scsi_device *SDpnt; - - fas216_checkmagic(info); - fas216_log(info, LOG_ERROR, "resetting bus"); - - info->stats.bus_resets += 1; - - spin_lock_irqsave(&info->host_lock, flags); - - /* - * Stop all activity on this interface. - */ - fas216_aborttransfer(info); - fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]); - - /* - * Clear any pending interrupts. - */ - while (fas216_readb(info, REG_STAT) & STAT_INT) - fas216_readb(info, REG_INST); - - info->rst_bus_status = 0; - - /* - * For each attached hard-reset device, clear out - * all command structures. Leave the running - * command in place. - */ - shost_for_each_device(SDpnt, info->host) { - int i; - - if (SDpnt->soft_reset) - continue; - - queue_remove_all_target(&info->queues.issue, SDpnt->id); - queue_remove_all_target(&info->queues.disconnected, SDpnt->id); - if (info->origSCpnt && info->origSCpnt->device->id == SDpnt->id) - info->origSCpnt = NULL; - if (info->reqSCpnt && info->reqSCpnt->device->id == SDpnt->id) - info->reqSCpnt = NULL; - info->SCpnt = NULL; - - for (i = 0; i < 8; i++) - clear_bit(SDpnt->id * 8 + i, info->busyluns); - } - - info->scsi.phase = PHASE_IDLE; - - /* - * Reset the SCSI bus. Device cleanup happens in - * the interrupt handler. - */ - fas216_cmd(info, CMD_RESETSCSI); - - mod_timer(&info->eh_timer, jiffies + HZ); - spin_unlock_irqrestore(&info->host_lock, flags); - - /* - * Wait one second for the interrupt. - */ - wait_event(info->eh_wait, info->rst_bus_status); - del_timer_sync(&info->eh_timer); - - fas216_log(info, LOG_ERROR, "bus reset complete: %s\n", - info->rst_bus_status == 1 ? "success" : "failed"); - - return info->rst_bus_status == 1 ? SUCCESS : FAILED; -} - -/** - * fas216_init_chip - Initialise FAS216 state after reset - * @info: state structure for interface - * - * Initialise FAS216 state after reset - */ -static void fas216_init_chip(FAS216_Info *info) -{ - unsigned int clock = ((info->ifcfg.clockrate - 1) / 5 + 1) & 7; - fas216_writeb(info, REG_CLKF, clock); - fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); - fas216_writeb(info, REG_CNTL2, info->scsi.cfg[1]); - fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]); - fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout); - fas216_writeb(info, REG_SOF, 0); - fas216_writeb(info, REG_STP, info->scsi.async_stp); - fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); -} - -/** - * fas216_eh_host_reset - Reset the host associated with this command - * @SCpnt: command specifing host to reset - * - * Reset the host associated with this command. - * Returns: FAILED if unable to reset. - * Notes: io_request_lock is taken, and irqs are disabled - */ -int fas216_eh_host_reset(struct scsi_cmnd *SCpnt) -{ - FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata; - - spin_lock_irq(info->host->host_lock); - - fas216_checkmagic(info); - - printk("scsi%d.%c: %s: resetting host\n", - info->host->host_no, '0' + SCpnt->device->id, __func__); - - /* - * Reset the SCSI chip. - */ - fas216_cmd(info, CMD_RESETCHIP); - - /* - * Ugly ugly ugly! - * We need to release the host_lock and enable - * IRQs if we sleep, but we must relock and disable - * IRQs after the sleep. - */ - spin_unlock_irq(info->host->host_lock); - msleep(50 * 1000/100); - spin_lock_irq(info->host->host_lock); - - /* - * Release the SCSI reset. - */ - fas216_cmd(info, CMD_NOP); - - fas216_init_chip(info); - - spin_unlock_irq(info->host->host_lock); - return SUCCESS; -} - -#define TYPE_UNKNOWN 0 -#define TYPE_NCR53C90 1 -#define TYPE_NCR53C90A 2 -#define TYPE_NCR53C9x 3 -#define TYPE_Am53CF94 4 -#define TYPE_EmFAS216 5 -#define TYPE_QLFAS216 6 - -static char *chip_types[] = { - "unknown", - "NS NCR53C90", - "NS NCR53C90A", - "NS NCR53C9x", - "AMD Am53CF94", - "Emulex FAS216", - "QLogic FAS216" -}; - -static int fas216_detect_type(FAS216_Info *info) -{ - int family, rev; - - /* - * Reset the chip. - */ - fas216_writeb(info, REG_CMD, CMD_RESETCHIP); - udelay(50); - fas216_writeb(info, REG_CMD, CMD_NOP); - - /* - * Check to see if control reg 2 is present. - */ - fas216_writeb(info, REG_CNTL3, 0); - fas216_writeb(info, REG_CNTL2, CNTL2_S2FE); - - /* - * If we are unable to read back control reg 2 - * correctly, it is not present, and we have a - * NCR53C90. - */ - if ((fas216_readb(info, REG_CNTL2) & (~0xe0)) != CNTL2_S2FE) - return TYPE_NCR53C90; - - /* - * Now, check control register 3 - */ - fas216_writeb(info, REG_CNTL2, 0); - fas216_writeb(info, REG_CNTL3, 0); - fas216_writeb(info, REG_CNTL3, 5); - - /* - * If we are unable to read the register back - * correctly, we have a NCR53C90A - */ - if (fas216_readb(info, REG_CNTL3) != 5) - return TYPE_NCR53C90A; - - /* - * Now read the ID from the chip. - */ - fas216_writeb(info, REG_CNTL3, 0); - - fas216_writeb(info, REG_CNTL3, CNTL3_ADIDCHK); - fas216_writeb(info, REG_CNTL3, 0); - - fas216_writeb(info, REG_CMD, CMD_RESETCHIP); - udelay(50); - fas216_writeb(info, REG_CMD, CMD_WITHDMA | CMD_NOP); - - fas216_writeb(info, REG_CNTL2, CNTL2_ENF); - fas216_writeb(info, REG_CMD, CMD_RESETCHIP); - udelay(50); - fas216_writeb(info, REG_CMD, CMD_NOP); - - rev = fas216_readb(info, REG_ID); - family = rev >> 3; - rev &= 7; - - switch (family) { - case 0x01: - if (rev == 4) - return TYPE_Am53CF94; - break; - - case 0x02: - switch (rev) { - case 2: - return TYPE_EmFAS216; - case 3: - return TYPE_QLFAS216; - } - break; - - default: - break; - } - printk("family %x rev %x\n", family, rev); - return TYPE_NCR53C9x; -} - -/** - * fas216_reset_state - Initialise driver internal state - * @info: state to initialise - * - * Initialise driver internal state - */ -static void fas216_reset_state(FAS216_Info *info) -{ - int i; - - fas216_checkmagic(info); - - fas216_bus_reset(info); - - /* - * Clear out all stale info in our state structure - */ - memset(info->busyluns, 0, sizeof(info->busyluns)); - info->scsi.disconnectable = 0; - info->scsi.aborting = 0; - - for (i = 0; i < 8; i++) { - info->device[i].parity_enabled = 0; - info->device[i].parity_check = 1; - } - - /* - * Drain all commands on disconnected queue - */ - while (queue_remove(&info->queues.disconnected) != NULL); - - /* - * Remove executing commands. - */ - info->SCpnt = NULL; - info->reqSCpnt = NULL; - info->rstSCpnt = NULL; - info->origSCpnt = NULL; -} - -/** - * fas216_init - initialise FAS/NCR/AMD SCSI structures. - * @host: a driver-specific filled-out structure - * - * Initialise FAS/NCR/AMD SCSI structures. - * Returns: 0 on success - */ -int fas216_init(struct Scsi_Host *host) -{ - FAS216_Info *info = (FAS216_Info *)host->hostdata; - - info->magic_start = MAGIC; - info->magic_end = MAGIC; - info->host = host; - info->scsi.cfg[0] = host->this_id | CNTL1_PERE; - info->scsi.cfg[1] = CNTL2_ENF | CNTL2_S2FE; - info->scsi.cfg[2] = info->ifcfg.cntl3 | - CNTL3_ADIDCHK | CNTL3_QTAG | CNTL3_G2CB | CNTL3_LBTM; - info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod); - - info->rst_dev_status = -1; - info->rst_bus_status = -1; - init_waitqueue_head(&info->eh_wait); - init_timer(&info->eh_timer); - info->eh_timer.data = (unsigned long)info; - info->eh_timer.function = fas216_eh_timer; - - spin_lock_init(&info->host_lock); - - memset(&info->stats, 0, sizeof(info->stats)); - - msgqueue_initialise(&info->scsi.msgs); - - if (!queue_initialise(&info->queues.issue)) - return -ENOMEM; - - if (!queue_initialise(&info->queues.disconnected)) { - queue_free(&info->queues.issue); - return -ENOMEM; - } - - return 0; -} - -/** - * fas216_add - initialise FAS/NCR/AMD SCSI ic. - * @host: a driver-specific filled-out structure - * @dev: parent device - * - * Initialise FAS/NCR/AMD SCSI ic. - * Returns: 0 on success - */ -int fas216_add(struct Scsi_Host *host, struct device *dev) -{ - FAS216_Info *info = (FAS216_Info *)host->hostdata; - int type, ret; - - if (info->ifcfg.clockrate <= 10 || info->ifcfg.clockrate > 40) { - printk(KERN_CRIT "fas216: invalid clock rate %u MHz\n", - info->ifcfg.clockrate); - return -EINVAL; - } - - fas216_reset_state(info); - type = fas216_detect_type(info); - info->scsi.type = chip_types[type]; - - udelay(300); - - /* - * Initialise the chip correctly. - */ - fas216_init_chip(info); - - /* - * Reset the SCSI bus. We don't want to see - * the resulting reset interrupt, so mask it - * out. - */ - fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_DISR); - fas216_writeb(info, REG_CMD, CMD_RESETSCSI); - - /* - * scsi standard says wait 250ms - */ - spin_unlock_irq(info->host->host_lock); - msleep(100*1000/100); - spin_lock_irq(info->host->host_lock); - - fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]); - fas216_readb(info, REG_INST); - - fas216_checkmagic(info); - - ret = scsi_add_host(host, dev); - if (ret) - fas216_writeb(info, REG_CMD, CMD_RESETCHIP); - else - scsi_scan_host(host); - - return ret; -} - -void fas216_remove(struct Scsi_Host *host) -{ - FAS216_Info *info = (FAS216_Info *)host->hostdata; - - fas216_checkmagic(info); - scsi_remove_host(host); - - fas216_writeb(info, REG_CMD, CMD_RESETCHIP); - scsi_host_put(host); -} - -/** - * fas216_release - release all resources for FAS/NCR/AMD SCSI ic. - * @host: a driver-specific filled-out structure - * - * release all resources and put everything to bed for FAS/NCR/AMD SCSI ic. - */ -void fas216_release(struct Scsi_Host *host) -{ - FAS216_Info *info = (FAS216_Info *)host->hostdata; - - queue_free(&info->queues.disconnected); - queue_free(&info->queues.issue); -} - -int fas216_print_host(FAS216_Info *info, char *buffer) -{ - return sprintf(buffer, - "\n" - "Chip : %s\n" - " Address: 0x%p\n" - " IRQ : %d\n" - " DMA : %d\n", - info->scsi.type, info->scsi.io_base, - info->scsi.irq, info->scsi.dma); -} - -int fas216_print_stats(FAS216_Info *info, char *buffer) -{ - char *p = buffer; - - p += sprintf(p, "\n" - "Command Statistics:\n" - " Queued : %u\n" - " Issued : %u\n" - " Completed : %u\n" - " Reads : %u\n" - " Writes : %u\n" - " Others : %u\n" - " Disconnects: %u\n" - " Aborts : %u\n" - " Bus resets : %u\n" - " Host resets: %u\n", - info->stats.queues, info->stats.removes, - info->stats.fins, info->stats.reads, - info->stats.writes, info->stats.miscs, - info->stats.disconnects, info->stats.aborts, - info->stats.bus_resets, info->stats.host_resets); - - return p - buffer; -} - -int fas216_print_devices(FAS216_Info *info, char *buffer) -{ - struct fas216_device *dev; - struct scsi_device *scd; - char *p = buffer; - - p += sprintf(p, "Device/Lun TaggedQ Parity Sync\n"); - - shost_for_each_device(scd, info->host) { - dev = &info->device[scd->id]; - p += sprintf(p, " %d/%d ", scd->id, scd->lun); - if (scd->tagged_supported) - p += sprintf(p, "%3sabled(%3d) ", - scd->simple_tags ? "en" : "dis", - scd->current_tag); - else - p += sprintf(p, "unsupported "); - - p += sprintf(p, "%3sabled ", dev->parity_enabled ? "en" : "dis"); - - if (dev->sof) - p += sprintf(p, "offset %d, %d ns\n", - dev->sof, dev->period * 4); - else - p += sprintf(p, "async\n"); - } - - return p - buffer; -} - -EXPORT_SYMBOL(fas216_init); -EXPORT_SYMBOL(fas216_add); -EXPORT_SYMBOL(fas216_queue_command); -EXPORT_SYMBOL(fas216_noqueue_command); -EXPORT_SYMBOL(fas216_intr); -EXPORT_SYMBOL(fas216_remove); -EXPORT_SYMBOL(fas216_release); -EXPORT_SYMBOL(fas216_eh_abort); -EXPORT_SYMBOL(fas216_eh_device_reset); -EXPORT_SYMBOL(fas216_eh_bus_reset); -EXPORT_SYMBOL(fas216_eh_host_reset); -EXPORT_SYMBOL(fas216_print_host); -EXPORT_SYMBOL(fas216_print_stats); -EXPORT_SYMBOL(fas216_print_devices); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver core"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/arm/fas216.h b/ANDROID_3.4.5/drivers/scsi/arm/fas216.h deleted file mode 100644 index df2e1b3d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/fas216.h +++ /dev/null @@ -1,393 +0,0 @@ -/* - * linux/drivers/acorn/scsi/fas216.h - * - * Copyright (C) 1997-2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * FAS216 generic driver - */ -#ifndef FAS216_H -#define FAS216_H - -#include - -#include "queue.h" -#include "msgqueue.h" - -/* FAS register definitions */ - -/* transfer count low */ -#define REG_CTCL (0) -#define REG_STCL (0) - -/* transfer count medium */ -#define REG_CTCM (1) -#define REG_STCM (1) - -/* fifo data */ -#define REG_FF (2) - -/* command */ -#define REG_CMD (3) -#define CMD_NOP 0x00 -#define CMD_FLUSHFIFO 0x01 -#define CMD_RESETCHIP 0x02 -#define CMD_RESETSCSI 0x03 - -#define CMD_TRANSFERINFO 0x10 -#define CMD_INITCMDCOMPLETE 0x11 -#define CMD_MSGACCEPTED 0x12 -#define CMD_PADBYTES 0x18 -#define CMD_SETATN 0x1a -#define CMD_RSETATN 0x1b - -#define CMD_SELECTWOATN 0x41 -#define CMD_SELECTATN 0x42 -#define CMD_SELECTATNSTOP 0x43 -#define CMD_ENABLESEL 0x44 -#define CMD_DISABLESEL 0x45 -#define CMD_SELECTATN3 0x46 -#define CMD_RESEL3 0x47 - -#define CMD_WITHDMA 0x80 - -/* status register (read) */ -#define REG_STAT (4) -#define STAT_IO (1 << 0) /* IO phase */ -#define STAT_CD (1 << 1) /* CD phase */ -#define STAT_MSG (1 << 2) /* MSG phase */ -#define STAT_TRANSFERDONE (1 << 3) /* Transfer completed */ -#define STAT_TRANSFERCNTZ (1 << 4) /* Transfer counter is zero */ -#define STAT_PARITYERROR (1 << 5) /* Parity error */ -#define STAT_REALBAD (1 << 6) /* Something bad */ -#define STAT_INT (1 << 7) /* Interrupt */ - -#define STAT_BUSMASK (STAT_MSG|STAT_CD|STAT_IO) -#define STAT_DATAOUT (0) /* Data out */ -#define STAT_DATAIN (STAT_IO) /* Data in */ -#define STAT_COMMAND (STAT_CD) /* Command out */ -#define STAT_STATUS (STAT_CD|STAT_IO) /* Status In */ -#define STAT_MESGOUT (STAT_MSG|STAT_CD) /* Message out */ -#define STAT_MESGIN (STAT_MSG|STAT_CD|STAT_IO) /* Message In */ - -/* bus ID for select / reselect */ -#define REG_SDID (4) -#define BUSID(target) ((target) & 7) - -/* Interrupt status register (read) */ -#define REG_INST (5) -#define INST_SELWOATN (1 << 0) /* Select w/o ATN */ -#define INST_SELATN (1 << 1) /* Select w/ATN */ -#define INST_RESELECTED (1 << 2) /* Reselected */ -#define INST_FUNCDONE (1 << 3) /* Function done */ -#define INST_BUSSERVICE (1 << 4) /* Bus service */ -#define INST_DISCONNECT (1 << 5) /* Disconnect */ -#define INST_ILLEGALCMD (1 << 6) /* Illegal command */ -#define INST_BUSRESET (1 << 7) /* SCSI Bus reset */ - -/* Timeout register (write) */ -#define REG_STIM (5) - -/* Sequence step register (read) */ -#define REG_IS (6) -#define IS_BITS 0x07 -#define IS_SELARB 0x00 /* Select & Arb ok */ -#define IS_MSGBYTESENT 0x01 /* One byte message sent*/ -#define IS_NOTCOMMAND 0x02 /* Not in command state */ -#define IS_EARLYPHASE 0x03 /* Early phase change */ -#define IS_COMPLETE 0x04 /* Command ok */ -#define IS_SOF 0x08 /* Sync off flag */ - -/* Transfer period step (write) */ -#define REG_STP (6) - -/* Synchronous Offset (write) */ -#define REG_SOF (7) - -/* Fifo state register (read) */ -#define REG_CFIS (7) -#define CFIS_CF 0x1f /* Num bytes in FIFO */ -#define CFIS_IS 0xe0 /* Step */ - -/* config register 1 */ -#define REG_CNTL1 (8) -#define CNTL1_CID (7 << 0) /* Chip ID */ -#define CNTL1_STE (1 << 3) /* Self test enable */ -#define CNTL1_PERE (1 << 4) /* Parity enable reporting en. */ -#define CNTL1_PTE (1 << 5) /* Parity test enable */ -#define CNTL1_DISR (1 << 6) /* Disable Irq on SCSI reset */ -#define CNTL1_ETM (1 << 7) /* Extended Timing Mode */ - -/* Clock conversion factor (read) */ -#define REG_CLKF (9) -#define CLKF_F37MHZ 0x00 /* 35.01 - 40 MHz */ -#define CLKF_F10MHZ 0x02 /* 10 MHz */ -#define CLKF_F12MHZ 0x03 /* 10.01 - 15 MHz */ -#define CLKF_F17MHZ 0x04 /* 15.01 - 20 MHz */ -#define CLKF_F22MHZ 0x05 /* 20.01 - 25 MHz */ -#define CLKF_F27MHZ 0x06 /* 25.01 - 30 MHz */ -#define CLKF_F32MHZ 0x07 /* 30.01 - 35 MHz */ - -/* Chip test register (write) */ -#define REG_FTM (10) -#define TEST_FTM 0x01 /* Force target mode */ -#define TEST_FIM 0x02 /* Force initiator mode */ -#define TEST_FHI 0x04 /* Force high impedance mode */ - -/* Configuration register 2 (read/write) */ -#define REG_CNTL2 (11) -#define CNTL2_PGDP (1 << 0) /* Pass Th/Generate Data Parity */ -#define CNTL2_PGRP (1 << 1) /* Pass Th/Generate Reg Parity */ -#define CNTL2_ACDPE (1 << 2) /* Abort on Cmd/Data Parity Err */ -#define CNTL2_S2FE (1 << 3) /* SCSI2 Features Enable */ -#define CNTL2_TSDR (1 << 4) /* Tristate DREQ */ -#define CNTL2_SBO (1 << 5) /* Select Byte Order */ -#define CNTL2_ENF (1 << 6) /* Enable features */ -#define CNTL2_DAE (1 << 7) /* Data Alignment Enable */ - -/* Configuration register 3 (read/write) */ -#define REG_CNTL3 (12) -#define CNTL3_BS8 (1 << 0) /* Burst size 8 */ -#define CNTL3_MDM (1 << 1) /* Modify DMA mode */ -#define CNTL3_LBTM (1 << 2) /* Last Byte Transfer mode */ -#define CNTL3_FASTCLK (1 << 3) /* Fast SCSI clocking */ -#define CNTL3_FASTSCSI (1 << 4) /* Fast SCSI */ -#define CNTL3_G2CB (1 << 5) /* Group2 SCSI support */ -#define CNTL3_QTAG (1 << 6) /* Enable 3 byte msgs */ -#define CNTL3_ADIDCHK (1 << 7) /* Additional ID check */ - -/* High transfer count (read/write) */ -#define REG_CTCH (14) -#define REG_STCH (14) - -/* ID register (read only) */ -#define REG_ID (14) - -/* Data alignment */ -#define REG_DAL (15) - -typedef enum { - PHASE_IDLE, /* we're not planning on doing anything */ - PHASE_SELECTION, /* selecting a device */ - PHASE_SELSTEPS, /* selection with command steps */ - PHASE_COMMAND, /* command sent */ - PHASE_MESSAGESENT, /* selected, and we're sending cmd */ - PHASE_DATAOUT, /* data out to device */ - PHASE_DATAIN, /* data in from device */ - PHASE_MSGIN, /* message in from device */ - PHASE_MSGIN_DISCONNECT, /* disconnecting from bus */ - PHASE_MSGOUT, /* after message out phase */ - PHASE_MSGOUT_EXPECT, /* expecting message out */ - PHASE_STATUS, /* status from device */ - PHASE_DONE /* Command complete */ -} phase_t; - -typedef enum { - DMA_OUT, /* DMA from memory to chip */ - DMA_IN /* DMA from chip to memory */ -} fasdmadir_t; - -typedef enum { - fasdma_none, /* No dma */ - fasdma_pio, /* PIO mode */ - fasdma_pseudo, /* Pseudo DMA */ - fasdma_real_block, /* Real DMA, on block by block basis */ - fasdma_real_all /* Real DMA, on request by request */ -} fasdmatype_t; - -typedef enum { - neg_wait, /* Negotiate with device */ - neg_inprogress, /* Negotiation sent */ - neg_complete, /* Negotiation complete */ - neg_targcomplete, /* Target completed negotiation */ - neg_invalid /* Negotiation not supported */ -} neg_t; - -#define MAGIC 0x441296bdUL -#define NR_MSGS 8 - -#define FASCAP_DMA (1 << 0) -#define FASCAP_PSEUDODMA (1 << 1) - -typedef struct { - unsigned long magic_start; - spinlock_t host_lock; - struct Scsi_Host *host; /* host */ - struct scsi_cmnd *SCpnt; /* currently processing command */ - struct scsi_cmnd *origSCpnt; /* original connecting command */ - struct scsi_cmnd *reqSCpnt; /* request sense command */ - struct scsi_cmnd *rstSCpnt; /* reset command */ - struct scsi_cmnd *pending_SCpnt[8]; /* per-device pending commands */ - int next_pending; /* next pending device */ - - /* - * Error recovery - */ - wait_queue_head_t eh_wait; - struct timer_list eh_timer; - unsigned int rst_dev_status; - unsigned int rst_bus_status; - - /* driver information */ - struct { - phase_t phase; /* current phase */ - void __iomem *io_base; /* iomem base of FAS216 */ - unsigned int io_shift; /* shift to adjust reg offsets by */ - unsigned char cfg[4]; /* configuration registers */ - const char *type; /* chip type */ - unsigned int irq; /* interrupt */ - int dma; /* dma channel */ - - struct scsi_pointer SCp; /* current commands data pointer */ - - MsgQueue_t msgs; /* message queue for connected device */ - - unsigned int async_stp; /* Async transfer STP value */ - unsigned char msgin_fifo; /* bytes in fifo at time of message in */ - unsigned char message[256]; /* last message received from device */ - - unsigned char disconnectable:1; /* this command can be disconnected */ - unsigned char aborting:1; /* aborting command */ - } scsi; - - /* statistics information */ - struct { - unsigned int queues; - unsigned int removes; - unsigned int fins; - unsigned int reads; - unsigned int writes; - unsigned int miscs; - unsigned int disconnects; - unsigned int aborts; - unsigned int bus_resets; - unsigned int host_resets; - } stats; - - /* configuration information */ - struct { - unsigned char clockrate; /* clock rate of FAS device (MHz) */ - unsigned char select_timeout; /* timeout (R5) */ - unsigned char sync_max_depth; /* Synchronous xfer max fifo depth */ - unsigned char wide_max_size; /* Maximum wide transfer size */ - unsigned char cntl3; /* Control Reg 3 */ - unsigned int asyncperiod; /* Async transfer period (ns) */ - unsigned int capabilities; /* driver capabilities */ - unsigned int disconnect_ok:1; /* Disconnects allowed? */ - } ifcfg; - - /* queue handling */ - struct { - Queue_t issue; /* issue queue */ - Queue_t disconnected; /* disconnected command queue */ - } queues; - - /* per-device info */ - struct fas216_device { - unsigned char disconnect_ok:1; /* device can disconnect */ - unsigned char parity_enabled:1; /* parity checking enabled */ - unsigned char parity_check:1; /* need to check parity checking */ - unsigned char period; /* sync xfer period in (*4ns) */ - unsigned char stp; /* synchronous transfer period */ - unsigned char sof; /* synchronous offset register */ - unsigned char wide_xfer; /* currently negociated wide transfer */ - neg_t sync_state; /* synchronous transfer mode */ - neg_t wide_state; /* wide transfer mode */ - } device[8]; - unsigned long busyluns[64/sizeof(unsigned long)];/* array of bits indicating LUNs busy */ - - /* dma */ - struct { - fasdmatype_t transfer_type; /* current type of DMA transfer */ - fasdmatype_t (*setup) (struct Scsi_Host *host, struct scsi_pointer *SCp, fasdmadir_t direction, fasdmatype_t min_dma); - void (*pseudo)(struct Scsi_Host *host, struct scsi_pointer *SCp, fasdmadir_t direction, int transfer); - void (*stop) (struct Scsi_Host *host, struct scsi_pointer *SCp); - } dma; - - /* miscellaneous */ - int internal_done; /* flag to indicate request done */ - struct scsi_eh_save ses; /* holds request sense restore info */ - unsigned long magic_end; -} FAS216_Info; - -/* Function: int fas216_init (struct Scsi_Host *instance) - * Purpose : initialise FAS/NCR/AMD SCSI structures. - * Params : instance - a driver-specific filled-out structure - * Returns : 0 on success - */ -extern int fas216_init (struct Scsi_Host *instance); - -/* Function: int fas216_add (struct Scsi_Host *instance, struct device *dev) - * Purpose : initialise FAS/NCR/AMD SCSI ic. - * Params : instance - a driver-specific filled-out structure - * Returns : 0 on success - */ -extern int fas216_add (struct Scsi_Host *instance, struct device *dev); - -/* Function: int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) - * Purpose : queue a command for adapter to process. - * Params : h - host adapter - * : SCpnt - Command to queue - * Returns : 0 - success, else error - */ -extern int fas216_queue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); - -/* Function: int fas216_noqueue_command(struct Scsi_Host *h, struct scsi_cmnd *SCpnt) - * Purpose : queue a command for adapter to process, and process it to completion. - * Params : h - host adapter - * : SCpnt - Command to queue - * Returns : 0 - success, else error - */ -extern int fas216_noqueue_command(struct Scsi_Host *, struct scsi_cmnd *); - -/* Function: irqreturn_t fas216_intr (FAS216_Info *info) - * Purpose : handle interrupts from the interface to progress a command - * Params : info - interface to service - */ -extern irqreturn_t fas216_intr (FAS216_Info *info); - -extern void fas216_remove (struct Scsi_Host *instance); - -/* Function: void fas216_release (struct Scsi_Host *instance) - * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic. - * Params : instance - a driver-specific filled-out structure - * Returns : 0 on success - */ -extern void fas216_release (struct Scsi_Host *instance); - -extern int fas216_print_host(FAS216_Info *info, char *buffer); -extern int fas216_print_stats(FAS216_Info *info, char *buffer); -extern int fas216_print_devices(FAS216_Info *info, char *buffer); - -/* Function: int fas216_eh_abort(struct scsi_cmnd *SCpnt) - * Purpose : abort this command - * Params : SCpnt - command to abort - * Returns : FAILED if unable to abort - */ -extern int fas216_eh_abort(struct scsi_cmnd *SCpnt); - -/* Function: int fas216_eh_device_reset(struct scsi_cmnd *SCpnt) - * Purpose : Reset the device associated with this command - * Params : SCpnt - command specifing device to reset - * Returns : FAILED if unable to reset - */ -extern int fas216_eh_device_reset(struct scsi_cmnd *SCpnt); - -/* Function: int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt) - * Purpose : Reset the complete bus associated with this command - * Params : SCpnt - command specifing bus to reset - * Returns : FAILED if unable to reset - */ -extern int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt); - -/* Function: int fas216_eh_host_reset(struct scsi_cmnd *SCpnt) - * Purpose : Reset the host associated with this command - * Params : SCpnt - command specifing host to reset - * Returns : FAILED if unable to reset - */ -extern int fas216_eh_host_reset(struct scsi_cmnd *SCpnt); - -#endif /* FAS216_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/arm/msgqueue.c b/ANDROID_3.4.5/drivers/scsi/arm/msgqueue.c deleted file mode 100644 index 7c95c758..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/msgqueue.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * linux/drivers/acorn/scsi/msgqueue.c - * - * Copyright (C) 1997-1998 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * message queue handling - */ -#include -#include -#include -#include - -#include "msgqueue.h" - -/* - * Function: struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq) - * Purpose : Allocate a message queue entry - * Params : msgq - message queue to claim entry for - * Returns : message queue entry or NULL. - */ -static struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq) -{ - struct msgqueue_entry *mq; - - if ((mq = msgq->free) != NULL) - msgq->free = mq->next; - - return mq; -} - -/* - * Function: void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq) - * Purpose : free a message queue entry - * Params : msgq - message queue to free entry from - * mq - message queue entry to free - */ -static void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq) -{ - if (mq) { - mq->next = msgq->free; - msgq->free = mq; - } -} - -/* - * Function: void msgqueue_initialise(MsgQueue_t *msgq) - * Purpose : initialise a message queue - * Params : msgq - queue to initialise - */ -void msgqueue_initialise(MsgQueue_t *msgq) -{ - int i; - - msgq->qe = NULL; - msgq->free = &msgq->entries[0]; - - for (i = 0; i < NR_MESSAGES; i++) - msgq->entries[i].next = &msgq->entries[i + 1]; - - msgq->entries[NR_MESSAGES - 1].next = NULL; -} - - -/* - * Function: void msgqueue_free(MsgQueue_t *msgq) - * Purpose : free a queue - * Params : msgq - queue to free - */ -void msgqueue_free(MsgQueue_t *msgq) -{ -} - -/* - * Function: int msgqueue_msglength(MsgQueue_t *msgq) - * Purpose : calculate the total length of all messages on the message queue - * Params : msgq - queue to examine - * Returns : number of bytes of messages in queue - */ -int msgqueue_msglength(MsgQueue_t *msgq) -{ - struct msgqueue_entry *mq = msgq->qe; - int length = 0; - - for (mq = msgq->qe; mq; mq = mq->next) - length += mq->msg.length; - - return length; -} - -/* - * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) - * Purpose : return a message - * Params : msgq - queue to obtain message from - * : msgno - message number - * Returns : pointer to message string, or NULL - */ -struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) -{ - struct msgqueue_entry *mq; - - for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--); - - return mq ? &mq->msg : NULL; -} - -/* - * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...) - * Purpose : add a message onto a message queue - * Params : msgq - queue to add message on - * length - length of message - * ... - message bytes - * Returns : != 0 if successful - */ -int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...) -{ - struct msgqueue_entry *mq = mqe_alloc(msgq); - va_list ap; - - if (mq) { - struct msgqueue_entry **mqp; - int i; - - va_start(ap, length); - for (i = 0; i < length; i++) - mq->msg.msg[i] = va_arg(ap, unsigned int); - va_end(ap); - - mq->msg.length = length; - mq->msg.fifo = 0; - mq->next = NULL; - - mqp = &msgq->qe; - while (*mqp) - mqp = &(*mqp)->next; - - *mqp = mq; - } - - return mq != NULL; -} - -/* - * Function: void msgqueue_flush(MsgQueue_t *msgq) - * Purpose : flush all messages from message queue - * Params : msgq - queue to flush - */ -void msgqueue_flush(MsgQueue_t *msgq) -{ - struct msgqueue_entry *mq, *mqnext; - - for (mq = msgq->qe; mq; mq = mqnext) { - mqnext = mq->next; - mqe_free(msgq, mq); - } - msgq->qe = NULL; -} - -EXPORT_SYMBOL(msgqueue_initialise); -EXPORT_SYMBOL(msgqueue_free); -EXPORT_SYMBOL(msgqueue_msglength); -EXPORT_SYMBOL(msgqueue_getmsg); -EXPORT_SYMBOL(msgqueue_addmsg); -EXPORT_SYMBOL(msgqueue_flush); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("SCSI message queue handling"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/arm/msgqueue.h b/ANDROID_3.4.5/drivers/scsi/arm/msgqueue.h deleted file mode 100644 index 41c7333d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/msgqueue.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * linux/drivers/acorn/scsi/msgqueue.h - * - * Copyright (C) 1997 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * message queue handling - */ -#ifndef MSGQUEUE_H -#define MSGQUEUE_H - -struct message { - char msg[8]; - int length; - int fifo; -}; - -struct msgqueue_entry { - struct message msg; - struct msgqueue_entry *next; -}; - -#define NR_MESSAGES 4 - -typedef struct { - struct msgqueue_entry *qe; - struct msgqueue_entry *free; - struct msgqueue_entry entries[NR_MESSAGES]; -} MsgQueue_t; - -/* - * Function: void msgqueue_initialise(MsgQueue_t *msgq) - * Purpose : initialise a message queue - * Params : msgq - queue to initialise - */ -extern void msgqueue_initialise(MsgQueue_t *msgq); - -/* - * Function: void msgqueue_free(MsgQueue_t *msgq) - * Purpose : free a queue - * Params : msgq - queue to free - */ -extern void msgqueue_free(MsgQueue_t *msgq); - -/* - * Function: int msgqueue_msglength(MsgQueue_t *msgq) - * Purpose : calculate the total length of all messages on the message queue - * Params : msgq - queue to examine - * Returns : number of bytes of messages in queue - */ -extern int msgqueue_msglength(MsgQueue_t *msgq); - -/* - * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno) - * Purpose : return a message & its length - * Params : msgq - queue to obtain message from - * : msgno - message number - * Returns : pointer to message string, or NULL - */ -extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno); - -/* - * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...) - * Purpose : add a message onto a message queue - * Params : msgq - queue to add message on - * length - length of message - * ... - message bytes - * Returns : != 0 if successful - */ -extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...); - -/* - * Function: void msgqueue_flush(MsgQueue_t *msgq) - * Purpose : flush all messages from message queue - * Params : msgq - queue to flush - */ -extern void msgqueue_flush(MsgQueue_t *msgq); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/arm/oak.c b/ANDROID_3.4.5/drivers/scsi/arm/oak.c deleted file mode 100644 index d25f944b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/oak.c +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Oak Generic NCR5380 driver - * - * Copyright 1995-2002, Russell King - */ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "../scsi.h" -#include - -#define AUTOSENSE -/*#define PSEUDO_DMA*/ - -#define OAKSCSI_PUBLIC_RELEASE 1 - -#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata) -#define NCR5380_local_declare() void __iomem *_base -#define NCR5380_setup(host) _base = priv(host)->base - -#define NCR5380_read(reg) readb(_base + ((reg) << 2)) -#define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2)) -#define NCR5380_intr oakscsi_intr -#define NCR5380_queue_command oakscsi_queue_command -#define NCR5380_proc_info oakscsi_proc_info - -#define NCR5380_implementation_fields \ - void __iomem *base - -#define BOARD_NORMAL 0 -#define BOARD_NCR53C400 1 - -#include "../NCR5380.h" - -#undef START_DMA_INITIATOR_RECEIVE_REG -#define START_DMA_INITIATOR_RECEIVE_REG (128 + 7) - -const char * oakscsi_info (struct Scsi_Host *spnt) -{ - return ""; -} - -#define STAT ((128 + 16) << 2) -#define DATA ((128 + 8) << 2) - -static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, - int len) -{ - void __iomem *base = priv(instance)->base; - -printk("writing %p len %d\n",addr, len); - if(!len) return -1; - - while(1) - { - int status; - while (((status = readw(base + STAT)) & 0x100)==0); - } -} - -static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, - int len) -{ - void __iomem *base = priv(instance)->base; -printk("reading %p len %d\n", addr, len); - while(len > 0) - { - unsigned int status, timeout; - unsigned long b; - - timeout = 0x01FFFFFF; - - while (((status = readw(base + STAT)) & 0x100)==0) - { - timeout--; - if(status & 0x200 || !timeout) - { - printk("status = %08X\n", status); - return 1; - } - } - - if(len >= 128) - { - readsw(base + DATA, addr, 128); - addr += 128; - len -= 128; - } - else - { - b = (unsigned long) readw(base + DATA); - *addr ++ = b; - len -= 1; - if(len) - *addr ++ = b>>8; - len -= 1; - } - } - return 0; -} - -#undef STAT -#undef DATA - -#include "../NCR5380.c" - -static struct scsi_host_template oakscsi_template = { - .module = THIS_MODULE, - .proc_info = oakscsi_proc_info, - .name = "Oak 16-bit SCSI", - .info = oakscsi_info, - .queuecommand = oakscsi_queue_command, - .eh_abort_handler = NCR5380_abort, - .eh_bus_reset_handler = NCR5380_bus_reset, - .can_queue = 16, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 2, - .use_clustering = DISABLE_CLUSTERING, - .proc_name = "oakscsi", -}; - -static int __devinit -oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct Scsi_Host *host; - int ret = -ENOMEM; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata)); - if (!host) { - ret = -ENOMEM; - goto release; - } - - priv(host)->base = ioremap(ecard_resource_start(ec, ECARD_RES_MEMC), - ecard_resource_len(ec, ECARD_RES_MEMC)); - if (!priv(host)->base) { - ret = -ENOMEM; - goto unreg; - } - - host->irq = IRQ_NONE; - host->n_io_port = 255; - - NCR5380_init(host, 0); - - printk("scsi%d: at port 0x%08lx irqs disabled", - host->host_no, host->io_port); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - host->can_queue, host->cmd_per_lun, OAKSCSI_PUBLIC_RELEASE); - printk("\nscsi%d:", host->host_no); - NCR5380_print_options(host); - printk("\n"); - - ret = scsi_add_host(host, &ec->dev); - if (ret) - goto out_unmap; - - scsi_scan_host(host); - goto out; - - out_unmap: - iounmap(priv(host)->base); - unreg: - scsi_host_put(host); - release: - ecard_release_resources(ec); - out: - return ret; -} - -static void __devexit oakscsi_remove(struct expansion_card *ec) -{ - struct Scsi_Host *host = ecard_get_drvdata(ec); - - ecard_set_drvdata(ec, NULL); - scsi_remove_host(host); - - NCR5380_exit(host); - iounmap(priv(host)->base); - scsi_host_put(host); - ecard_release_resources(ec); -} - -static const struct ecard_id oakscsi_cids[] = { - { MANU_OAK, PROD_OAK_SCSI }, - { 0xffff, 0xffff } -}; - -static struct ecard_driver oakscsi_driver = { - .probe = oakscsi_probe, - .remove = __devexit_p(oakscsi_remove), - .id_table = oakscsi_cids, - .drv = { - .name = "oakscsi", - }, -}; - -static int __init oakscsi_init(void) -{ - return ecard_register_driver(&oakscsi_driver); -} - -static void __exit oakscsi_exit(void) -{ - ecard_remove_driver(&oakscsi_driver); -} - -module_init(oakscsi_init); -module_exit(oakscsi_exit); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("Oak SCSI driver"); -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/scsi/arm/powertec.c b/ANDROID_3.4.5/drivers/scsi/arm/powertec.c deleted file mode 100644 index 9274c067..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/powertec.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * linux/drivers/acorn/scsi/powertec.c - * - * Copyright (C) 1997-2005 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "../scsi.h" -#include -#include "fas216.h" -#include "scsi.h" - -#include - -#define POWERTEC_FAS216_OFFSET 0x3000 -#define POWERTEC_FAS216_SHIFT 6 - -#define POWERTEC_INTR_STATUS 0x2000 -#define POWERTEC_INTR_BIT 0x80 - -#define POWERTEC_RESET_CONTROL 0x1018 -#define POWERTEC_RESET_BIT 1 - -#define POWERTEC_TERM_CONTROL 0x2018 -#define POWERTEC_TERM_ENABLE 1 - -#define POWERTEC_INTR_CONTROL 0x101c -#define POWERTEC_INTR_ENABLE 1 -#define POWERTEC_INTR_DISABLE 0 - -#define VERSION "1.10 (19/01/2003 2.5.59)" - -/* - * Use term=0,1,0,0,0 to turn terminators on/off. - * One entry per slot. - */ -static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 }; - -#define NR_SG 256 - -struct powertec_info { - FAS216_Info info; - struct expansion_card *ec; - void __iomem *base; - unsigned int term_ctl; - struct scatterlist sg[NR_SG]; -}; - -/* Prototype: void powertecscsi_irqenable(ec, irqnr) - * Purpose : Enable interrupts on Powertec SCSI card - * Params : ec - expansion card structure - * : irqnr - interrupt number - */ -static void -powertecscsi_irqenable(struct expansion_card *ec, int irqnr) -{ - struct powertec_info *info = ec->irq_data; - writeb(POWERTEC_INTR_ENABLE, info->base + POWERTEC_INTR_CONTROL); -} - -/* Prototype: void powertecscsi_irqdisable(ec, irqnr) - * Purpose : Disable interrupts on Powertec SCSI card - * Params : ec - expansion card structure - * : irqnr - interrupt number - */ -static void -powertecscsi_irqdisable(struct expansion_card *ec, int irqnr) -{ - struct powertec_info *info = ec->irq_data; - writeb(POWERTEC_INTR_DISABLE, info->base + POWERTEC_INTR_CONTROL); -} - -static const expansioncard_ops_t powertecscsi_ops = { - .irqenable = powertecscsi_irqenable, - .irqdisable = powertecscsi_irqdisable, -}; - -/* Prototype: void powertecscsi_terminator_ctl(host, on_off) - * Purpose : Turn the Powertec SCSI terminators on or off - * Params : host - card to turn on/off - * : on_off - !0 to turn on, 0 to turn off - */ -static void -powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off) -{ - struct powertec_info *info = (struct powertec_info *)host->hostdata; - - info->term_ctl = on_off ? POWERTEC_TERM_ENABLE : 0; - writeb(info->term_ctl, info->base + POWERTEC_TERM_CONTROL); -} - -/* Prototype: void powertecscsi_intr(irq, *dev_id, *regs) - * Purpose : handle interrupts from Powertec SCSI card - * Params : irq - interrupt number - * dev_id - user-defined (Scsi_Host structure) - */ -static irqreturn_t powertecscsi_intr(int irq, void *dev_id) -{ - struct powertec_info *info = dev_id; - - return fas216_intr(&info->info); -} - -/* Prototype: fasdmatype_t powertecscsi_dma_setup(host, SCpnt, direction, min_type) - * Purpose : initialises DMA/PIO - * Params : host - host - * SCpnt - command - * direction - DMA on to/off of card - * min_type - minimum DMA support that we must have for this transfer - * Returns : type of transfer to be performed - */ -static fasdmatype_t -powertecscsi_dma_setup(struct Scsi_Host *host, struct scsi_pointer *SCp, - fasdmadir_t direction, fasdmatype_t min_type) -{ - struct powertec_info *info = (struct powertec_info *)host->hostdata; - struct device *dev = scsi_get_device(host); - int dmach = info->info.scsi.dma; - - if (info->info.ifcfg.capabilities & FASCAP_DMA && - min_type == fasdma_real_all) { - int bufs, map_dir, dma_dir; - - bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG); - - if (direction == DMA_OUT) - map_dir = DMA_TO_DEVICE, - dma_dir = DMA_MODE_WRITE; - else - map_dir = DMA_FROM_DEVICE, - dma_dir = DMA_MODE_READ; - - dma_map_sg(dev, info->sg, bufs, map_dir); - - disable_dma(dmach); - set_dma_sg(dmach, info->sg, bufs); - set_dma_mode(dmach, dma_dir); - enable_dma(dmach); - return fasdma_real_all; - } - - /* - * If we're not doing DMA, - * we'll do slow PIO - */ - return fasdma_pio; -} - -/* Prototype: int powertecscsi_dma_stop(host, SCpnt) - * Purpose : stops DMA/PIO - * Params : host - host - * SCpnt - command - */ -static void -powertecscsi_dma_stop(struct Scsi_Host *host, struct scsi_pointer *SCp) -{ - struct powertec_info *info = (struct powertec_info *)host->hostdata; - if (info->info.scsi.dma != NO_DMA) - disable_dma(info->info.scsi.dma); -} - -/* Prototype: const char *powertecscsi_info(struct Scsi_Host * host) - * Purpose : returns a descriptive string about this interface, - * Params : host - driver host structure to return info for. - * Returns : pointer to a static buffer containing null terminated string. - */ -const char *powertecscsi_info(struct Scsi_Host *host) -{ - struct powertec_info *info = (struct powertec_info *)host->hostdata; - static char string[150]; - - sprintf(string, "%s (%s) in slot %d v%s terminators o%s", - host->hostt->name, info->info.scsi.type, info->ec->slot_no, - VERSION, info->term_ctl ? "n" : "ff"); - - return string; -} - -/* Prototype: int powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) - * Purpose : Set a driver specific function - * Params : host - host to setup - * : buffer - buffer containing string describing operation - * : length - length of string - * Returns : -EINVAL, or 0 - */ -static int -powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length) -{ - int ret = length; - - if (length >= 12 && strncmp(buffer, "POWERTECSCSI", 12) == 0) { - buffer += 12; - length -= 12; - - if (length >= 5 && strncmp(buffer, "term=", 5) == 0) { - if (buffer[5] == '1') - powertecscsi_terminator_ctl(host, 1); - else if (buffer[5] == '0') - powertecscsi_terminator_ctl(host, 0); - else - ret = -EINVAL; - } else - ret = -EINVAL; - } else - ret = -EINVAL; - - return ret; -} - -/* Prototype: int powertecscsi_proc_info(char *buffer, char **start, off_t offset, - * int length, int host_no, int inout) - * Purpose : Return information about the driver to a user process accessing - * the /proc filesystem. - * Params : buffer - a buffer to write information to - * start - a pointer into this buffer set by this routine to the start - * of the required information. - * offset - offset into information that we have read up to. - * length - length of buffer - * inout - 0 for reading, 1 for writing. - * Returns : length of data written to buffer. - */ -int powertecscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int inout) -{ - struct powertec_info *info; - char *p = buffer; - int pos; - - if (inout == 1) - return powertecscsi_set_proc_info(host, buffer, length); - - info = (struct powertec_info *)host->hostdata; - - p += sprintf(p, "PowerTec SCSI driver v%s\n", VERSION); - p += fas216_print_host(&info->info, p); - p += sprintf(p, "Term : o%s\n", - info->term_ctl ? "n" : "ff"); - - p += fas216_print_stats(&info->info, p); - p += fas216_print_devices(&info->info, p); - - *start = buffer + offset; - pos = p - buffer - offset; - if (pos > length) - pos = length; - - return pos; -} - -static ssize_t powertecscsi_show_term(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct expansion_card *ec = ECARD_DEV(dev); - struct Scsi_Host *host = ecard_get_drvdata(ec); - struct powertec_info *info = (struct powertec_info *)host->hostdata; - - return sprintf(buf, "%d\n", info->term_ctl ? 1 : 0); -} - -static ssize_t -powertecscsi_store_term(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) -{ - struct expansion_card *ec = ECARD_DEV(dev); - struct Scsi_Host *host = ecard_get_drvdata(ec); - - if (len > 1) - powertecscsi_terminator_ctl(host, buf[0] != '0'); - - return len; -} - -static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR, - powertecscsi_show_term, powertecscsi_store_term); - -static struct scsi_host_template powertecscsi_template = { - .module = THIS_MODULE, - .proc_info = powertecscsi_proc_info, - .name = "PowerTec SCSI", - .info = powertecscsi_info, - .queuecommand = fas216_queue_command, - .eh_host_reset_handler = fas216_eh_host_reset, - .eh_bus_reset_handler = fas216_eh_bus_reset, - .eh_device_reset_handler = fas216_eh_device_reset, - .eh_abort_handler = fas216_eh_abort, - - .can_queue = 8, - .this_id = 7, - .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, - .dma_boundary = IOMD_DMA_BOUNDARY, - .cmd_per_lun = 2, - .use_clustering = ENABLE_CLUSTERING, - .proc_name = "powertec", -}; - -static int __devinit -powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id) -{ - struct Scsi_Host *host; - struct powertec_info *info; - void __iomem *base; - int ret; - - ret = ecard_request_resources(ec); - if (ret) - goto out; - - base = ecardm_iomap(ec, ECARD_RES_IOCFAST, 0, 0); - if (!base) { - ret = -ENOMEM; - goto out_region; - } - - host = scsi_host_alloc(&powertecscsi_template, - sizeof (struct powertec_info)); - if (!host) { - ret = -ENOMEM; - goto out_region; - } - - ecard_set_drvdata(ec, host); - - info = (struct powertec_info *)host->hostdata; - info->base = base; - powertecscsi_terminator_ctl(host, term[ec->slot_no]); - - info->ec = ec; - info->info.scsi.io_base = base + POWERTEC_FAS216_OFFSET; - info->info.scsi.io_shift = POWERTEC_FAS216_SHIFT; - info->info.scsi.irq = ec->irq; - info->info.scsi.dma = ec->dma; - info->info.ifcfg.clockrate = 40; /* MHz */ - info->info.ifcfg.select_timeout = 255; - info->info.ifcfg.asyncperiod = 200; /* ns */ - info->info.ifcfg.sync_max_depth = 7; - info->info.ifcfg.cntl3 = CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK; - info->info.ifcfg.disconnect_ok = 1; - info->info.ifcfg.wide_max_size = 0; - info->info.ifcfg.capabilities = 0; - info->info.dma.setup = powertecscsi_dma_setup; - info->info.dma.pseudo = NULL; - info->info.dma.stop = powertecscsi_dma_stop; - - ec->irqaddr = base + POWERTEC_INTR_STATUS; - ec->irqmask = POWERTEC_INTR_BIT; - - ecard_setirq(ec, &powertecscsi_ops, info); - - device_create_file(&ec->dev, &dev_attr_bus_term); - - ret = fas216_init(host); - if (ret) - goto out_free; - - ret = request_irq(ec->irq, powertecscsi_intr, - IRQF_DISABLED, "powertec", info); - if (ret) { - printk("scsi%d: IRQ%d not free: %d\n", - host->host_no, ec->irq, ret); - goto out_release; - } - - if (info->info.scsi.dma != NO_DMA) { - if (request_dma(info->info.scsi.dma, "powertec")) { - printk("scsi%d: DMA%d not free, using PIO\n", - host->host_no, info->info.scsi.dma); - info->info.scsi.dma = NO_DMA; - } else { - set_dma_speed(info->info.scsi.dma, 180); - info->info.ifcfg.capabilities |= FASCAP_DMA; - } - } - - ret = fas216_add(host, &ec->dev); - if (ret == 0) - goto out; - - if (info->info.scsi.dma != NO_DMA) - free_dma(info->info.scsi.dma); - free_irq(ec->irq, host); - - out_release: - fas216_release(host); - - out_free: - device_remove_file(&ec->dev, &dev_attr_bus_term); - scsi_host_put(host); - - out_region: - ecard_release_resources(ec); - - out: - return ret; -} - -static void __devexit powertecscsi_remove(struct expansion_card *ec) -{ - struct Scsi_Host *host = ecard_get_drvdata(ec); - struct powertec_info *info = (struct powertec_info *)host->hostdata; - - ecard_set_drvdata(ec, NULL); - fas216_remove(host); - - device_remove_file(&ec->dev, &dev_attr_bus_term); - - if (info->info.scsi.dma != NO_DMA) - free_dma(info->info.scsi.dma); - free_irq(ec->irq, info); - - fas216_release(host); - scsi_host_put(host); - ecard_release_resources(ec); -} - -static const struct ecard_id powertecscsi_cids[] = { - { MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI }, - { 0xffff, 0xffff }, -}; - -static struct ecard_driver powertecscsi_driver = { - .probe = powertecscsi_probe, - .remove = __devexit_p(powertecscsi_remove), - .id_table = powertecscsi_cids, - .drv = { - .name = "powertecscsi", - }, -}; - -static int __init powertecscsi_init(void) -{ - return ecard_register_driver(&powertecscsi_driver); -} - -static void __exit powertecscsi_exit(void) -{ - ecard_remove_driver(&powertecscsi_driver); -} - -module_init(powertecscsi_init); -module_exit(powertecscsi_exit); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("Powertec SCSI driver"); -module_param_array(term, int, NULL, 0); -MODULE_PARM_DESC(term, "SCSI bus termination"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/arm/queue.c b/ANDROID_3.4.5/drivers/scsi/arm/queue.c deleted file mode 100644 index cb11ccef..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/queue.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * linux/drivers/acorn/scsi/queue.c: queue handling primitives - * - * Copyright (C) 1997-2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Changelog: - * 15-Sep-1997 RMK Created. - * 11-Oct-1997 RMK Corrected problem with queue_remove_exclude - * not updating internal linked list properly - * (was causing commands to go missing). - * 30-Aug-2000 RMK Use Linux list handling and spinlocks - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../scsi.h" - -#define DEBUG - -typedef struct queue_entry { - struct list_head list; - struct scsi_cmnd *SCpnt; -#ifdef DEBUG - unsigned long magic; -#endif -} QE_t; - -#ifdef DEBUG -#define QUEUE_MAGIC_FREE 0xf7e1c9a3 -#define QUEUE_MAGIC_USED 0xf7e1cc33 - -#define SET_MAGIC(q,m) ((q)->magic = (m)) -#define BAD_MAGIC(q,m) ((q)->magic != (m)) -#else -#define SET_MAGIC(q,m) do { } while (0) -#define BAD_MAGIC(q,m) (0) -#endif - -#include "queue.h" - -#define NR_QE 32 - -/* - * Function: void queue_initialise (Queue_t *queue) - * Purpose : initialise a queue - * Params : queue - queue to initialise - */ -int queue_initialise (Queue_t *queue) -{ - unsigned int nqueues = NR_QE; - QE_t *q; - - spin_lock_init(&queue->queue_lock); - INIT_LIST_HEAD(&queue->head); - INIT_LIST_HEAD(&queue->free); - - /* - * If life was easier, then SCpnt would have a - * host-available list head, and we wouldn't - * need to keep free lists or allocate this - * memory. - */ - queue->alloc = q = kmalloc(sizeof(QE_t) * nqueues, GFP_KERNEL); - if (q) { - for (; nqueues; q++, nqueues--) { - SET_MAGIC(q, QUEUE_MAGIC_FREE); - q->SCpnt = NULL; - list_add(&q->list, &queue->free); - } - } - - return queue->alloc != NULL; -} - -/* - * Function: void queue_free (Queue_t *queue) - * Purpose : free a queue - * Params : queue - queue to free - */ -void queue_free (Queue_t *queue) -{ - if (!list_empty(&queue->head)) - printk(KERN_WARNING "freeing non-empty queue %p\n", queue); - kfree(queue->alloc); -} - - -/* - * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head) - * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head. - * Params : queue - destination queue - * SCpnt - command to add - * head - add command to head of queue - * Returns : 0 on error, !0 on success - */ -int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head) -{ - unsigned long flags; - struct list_head *l; - QE_t *q; - int ret = 0; - - spin_lock_irqsave(&queue->queue_lock, flags); - if (list_empty(&queue->free)) - goto empty; - - l = queue->free.next; - list_del(l); - - q = list_entry(l, QE_t, list); - BUG_ON(BAD_MAGIC(q, QUEUE_MAGIC_FREE)); - - SET_MAGIC(q, QUEUE_MAGIC_USED); - q->SCpnt = SCpnt; - - if (head) - list_add(l, &queue->head); - else - list_add_tail(l, &queue->head); - - ret = 1; -empty: - spin_unlock_irqrestore(&queue->queue_lock, flags); - return ret; -} - -static struct scsi_cmnd *__queue_remove(Queue_t *queue, struct list_head *ent) -{ - QE_t *q; - - /* - * Move the entry from the "used" list onto the "free" list - */ - list_del(ent); - q = list_entry(ent, QE_t, list); - BUG_ON(BAD_MAGIC(q, QUEUE_MAGIC_USED)); - - SET_MAGIC(q, QUEUE_MAGIC_FREE); - list_add(ent, &queue->free); - - return q->SCpnt; -} - -/* - * Function: struct scsi_cmnd *queue_remove_exclude (queue, exclude) - * Purpose : remove a SCSI command from a queue - * Params : queue - queue to remove command from - * exclude - bit array of target&lun which is busy - * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available - */ -struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude) -{ - unsigned long flags; - struct list_head *l; - struct scsi_cmnd *SCpnt = NULL; - - spin_lock_irqsave(&queue->queue_lock, flags); - list_for_each(l, &queue->head) { - QE_t *q = list_entry(l, QE_t, list); - if (!test_bit(q->SCpnt->device->id * 8 + q->SCpnt->device->lun, exclude)) { - SCpnt = __queue_remove(queue, l); - break; - } - } - spin_unlock_irqrestore(&queue->queue_lock, flags); - - return SCpnt; -} - -/* - * Function: struct scsi_cmnd *queue_remove (queue) - * Purpose : removes first SCSI command from a queue - * Params : queue - queue to remove command from - * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available - */ -struct scsi_cmnd *queue_remove(Queue_t *queue) -{ - unsigned long flags; - struct scsi_cmnd *SCpnt = NULL; - - spin_lock_irqsave(&queue->queue_lock, flags); - if (!list_empty(&queue->head)) - SCpnt = __queue_remove(queue, queue->head.next); - spin_unlock_irqrestore(&queue->queue_lock, flags); - - return SCpnt; -} - -/* - * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag) - * Purpose : remove a SCSI command from the queue for a specified target/lun/tag - * Params : queue - queue to remove command from - * target - target that we want - * lun - lun on device - * tag - tag on device - * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements - */ -struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, int lun, - int tag) -{ - unsigned long flags; - struct list_head *l; - struct scsi_cmnd *SCpnt = NULL; - - spin_lock_irqsave(&queue->queue_lock, flags); - list_for_each(l, &queue->head) { - QE_t *q = list_entry(l, QE_t, list); - if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun && - q->SCpnt->tag == tag) { - SCpnt = __queue_remove(queue, l); - break; - } - } - spin_unlock_irqrestore(&queue->queue_lock, flags); - - return SCpnt; -} - -/* - * Function: queue_remove_all_target(queue, target) - * Purpose : remove all SCSI commands from the queue for a specified target - * Params : queue - queue to remove command from - * target - target device id - * Returns : nothing - */ -void queue_remove_all_target(Queue_t *queue, int target) -{ - unsigned long flags; - struct list_head *l; - - spin_lock_irqsave(&queue->queue_lock, flags); - list_for_each(l, &queue->head) { - QE_t *q = list_entry(l, QE_t, list); - if (q->SCpnt->device->id == target) - __queue_remove(queue, l); - } - spin_unlock_irqrestore(&queue->queue_lock, flags); -} - -/* - * Function: int queue_probetgtlun (queue, target, lun) - * Purpose : check to see if we have a command in the queue for the specified - * target/lun. - * Params : queue - queue to look in - * target - target we want to probe - * lun - lun on target - * Returns : 0 if not found, != 0 if found - */ -int queue_probetgtlun (Queue_t *queue, int target, int lun) -{ - unsigned long flags; - struct list_head *l; - int found = 0; - - spin_lock_irqsave(&queue->queue_lock, flags); - list_for_each(l, &queue->head) { - QE_t *q = list_entry(l, QE_t, list); - if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun) { - found = 1; - break; - } - } - spin_unlock_irqrestore(&queue->queue_lock, flags); - - return found; -} - -/* - * Function: int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt) - * Purpose : remove a specific command from the queues - * Params : queue - queue to look in - * SCpnt - command to find - * Returns : 0 if not found - */ -int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt) -{ - unsigned long flags; - struct list_head *l; - int found = 0; - - spin_lock_irqsave(&queue->queue_lock, flags); - list_for_each(l, &queue->head) { - QE_t *q = list_entry(l, QE_t, list); - if (q->SCpnt == SCpnt) { - __queue_remove(queue, l); - found = 1; - break; - } - } - spin_unlock_irqrestore(&queue->queue_lock, flags); - - return found; -} - -EXPORT_SYMBOL(queue_initialise); -EXPORT_SYMBOL(queue_free); -EXPORT_SYMBOL(__queue_add); -EXPORT_SYMBOL(queue_remove); -EXPORT_SYMBOL(queue_remove_exclude); -EXPORT_SYMBOL(queue_remove_tgtluntag); -EXPORT_SYMBOL(queue_remove_cmd); -EXPORT_SYMBOL(queue_remove_all_target); -EXPORT_SYMBOL(queue_probetgtlun); - -MODULE_AUTHOR("Russell King"); -MODULE_DESCRIPTION("SCSI command queueing"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/arm/queue.h b/ANDROID_3.4.5/drivers/scsi/arm/queue.h deleted file mode 100644 index 3c519c92..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/queue.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * linux/drivers/acorn/scsi/queue.h: queue handling - * - * Copyright (C) 1997 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef QUEUE_H -#define QUEUE_H - -typedef struct { - struct list_head head; - struct list_head free; - spinlock_t queue_lock; - void *alloc; /* start of allocated mem */ -} Queue_t; - -/* - * Function: void queue_initialise (Queue_t *queue) - * Purpose : initialise a queue - * Params : queue - queue to initialise - */ -extern int queue_initialise (Queue_t *queue); - -/* - * Function: void queue_free (Queue_t *queue) - * Purpose : free a queue - * Params : queue - queue to free - */ -extern void queue_free (Queue_t *queue); - -/* - * Function: struct scsi_cmnd *queue_remove (queue) - * Purpose : removes first SCSI command from a queue - * Params : queue - queue to remove command from - * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available - */ -extern struct scsi_cmnd *queue_remove (Queue_t *queue); - -/* - * Function: struct scsi_cmnd *queue_remove_exclude_ref (queue, exclude) - * Purpose : remove a SCSI command from a queue - * Params : queue - queue to remove command from - * exclude - array of busy LUNs - * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available - */ -extern struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, - unsigned long *exclude); - -#define queue_add_cmd_ordered(queue,SCpnt) \ - __queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE) -#define queue_add_cmd_tail(queue,SCpnt) \ - __queue_add(queue,SCpnt,0) -/* - * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head) - * Purpose : Add a new command onto a queue - * Params : queue - destination queue - * SCpnt - command to add - * head - add command to head of queue - * Returns : 0 on error, !0 on success - */ -extern int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head); - -/* - * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag) - * Purpose : remove a SCSI command from the queue for a specified target/lun/tag - * Params : queue - queue to remove command from - * target - target that we want - * lun - lun on device - * tag - tag on device - * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements - */ -extern struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, - int lun, int tag); - -/* - * Function: queue_remove_all_target(queue, target) - * Purpose : remove all SCSI commands from the queue for a specified target - * Params : queue - queue to remove command from - * target - target device id - * Returns : nothing - */ -extern void queue_remove_all_target(Queue_t *queue, int target); - -/* - * Function: int queue_probetgtlun (queue, target, lun) - * Purpose : check to see if we have a command in the queue for the specified - * target/lun. - * Params : queue - queue to look in - * target - target we want to probe - * lun - lun on target - * Returns : 0 if not found, != 0 if found - */ -extern int queue_probetgtlun (Queue_t *queue, int target, int lun); - -/* - * Function: int queue_remove_cmd (Queue_t *queue, struct scsi_cmnd *SCpnt) - * Purpose : remove a specific command from the queues - * Params : queue - queue to look in - * SCpnt - command to find - * Returns : 0 if not found - */ -int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt); - -#endif /* QUEUE_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/arm/scsi.h b/ANDROID_3.4.5/drivers/scsi/arm/scsi.h deleted file mode 100644 index 138a521b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/arm/scsi.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * linux/drivers/acorn/scsi/scsi.h - * - * Copyright (C) 2002 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Commonly used scsi driver functions. - */ - -#include - -#define BELT_AND_BRACES - -/* - * The scatter-gather list handling. This contains all - * the yucky stuff that needs to be fixed properly. - */ - -/* - * copy_SCp_to_sg() Assumes contiguous allocation at @sg of at-most @max - * entries of uninitialized memory. SCp is from scsi-ml and has a valid - * (possibly chained) sg-list - */ -static inline int copy_SCp_to_sg(struct scatterlist *sg, struct scsi_pointer *SCp, int max) -{ - int bufs = SCp->buffers_residual; - - /* FIXME: It should be easy for drivers to loop on copy_SCp_to_sg(). - * and to remove this BUG_ON. Use min() in-its-place - */ - BUG_ON(bufs + 1 > max); - - sg_set_buf(sg, SCp->ptr, SCp->this_residual); - - if (bufs) { - struct scatterlist *src_sg; - unsigned i; - - for_each_sg(sg_next(SCp->buffer), src_sg, bufs, i) - *(++sg) = *src_sg; - sg_mark_end(sg); - } - - return bufs + 1; -} - -static inline int next_SCp(struct scsi_pointer *SCp) -{ - int ret = SCp->buffers_residual; - if (ret) { - SCp->buffer = sg_next(SCp->buffer); - SCp->buffers_residual--; - SCp->ptr = sg_virt(SCp->buffer); - SCp->this_residual = SCp->buffer->length; - } else { - SCp->ptr = NULL; - SCp->this_residual = 0; - } - return ret; -} - -static inline unsigned char get_next_SCp_byte(struct scsi_pointer *SCp) -{ - char c = *SCp->ptr; - - SCp->ptr += 1; - SCp->this_residual -= 1; - - return c; -} - -static inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c) -{ - *SCp->ptr = c; - SCp->ptr += 1; - SCp->this_residual -= 1; -} - -static inline void init_SCp(struct scsi_cmnd *SCpnt) -{ - memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer)); - - if (scsi_bufflen(SCpnt)) { - unsigned long len = 0; - - SCpnt->SCp.buffer = scsi_sglist(SCpnt); - SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; - SCpnt->SCp.ptr = sg_virt(SCpnt->SCp.buffer); - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.phase = scsi_bufflen(SCpnt); - -#ifdef BELT_AND_BRACES - { /* - * Calculate correct buffer length. Some commands - * come in with the wrong scsi_bufflen. - */ - struct scatterlist *sg; - unsigned i, sg_count = scsi_sg_count(SCpnt); - - scsi_for_each_sg(SCpnt, sg, sg_count, i) - len += sg->length; - - if (scsi_bufflen(SCpnt) != len) { - printk(KERN_WARNING - "scsi%d.%c: bad request buffer " - "length %d, should be %ld\n", - SCpnt->device->host->host_no, - '0' + SCpnt->device->id, - scsi_bufflen(SCpnt), len); - /* - * FIXME: Totaly naive fixup. We should abort - * with error - */ - SCpnt->SCp.phase = - min_t(unsigned long, len, - scsi_bufflen(SCpnt)); - } - } -#endif - } else { - SCpnt->SCp.ptr = NULL; - SCpnt->SCp.this_residual = 0; - SCpnt->SCp.phase = 0; - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/atari_NCR5380.c b/ANDROID_3.4.5/drivers/scsi/atari_NCR5380.c deleted file mode 100644 index 2db79b46..00000000 --- a/ANDROID_3.4.5/drivers/scsi/atari_NCR5380.c +++ /dev/null @@ -1,2993 +0,0 @@ -/* - * NCR 5380 generic driver routines. These should make it *trivial* - * to implement 5380 SCSI drivers under Linux with a non-trantor - * architecture. - * - * Note that these routines also work with NR53c400 family chips. - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 - * - * DISTRIBUTION RELEASE 6. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * ++roman: To port the 5380 driver to the Atari, I had to do some changes in - * this file, too: - * - * - Some of the debug statements were incorrect (undefined variables and the - * like). I fixed that. - * - * - In information_transfer(), I think a #ifdef was wrong. Looking at the - * possible DMA transfer size should also happen for REAL_DMA. I added this - * in the #if statement. - * - * - When using real DMA, information_transfer() should return in a DATAOUT - * phase after starting the DMA. It has nothing more to do. - * - * - The interrupt service routine should run main after end of DMA, too (not - * only after RESELECTION interrupts). Additionally, it should _not_ test - * for more interrupts after running main, since a DMA process may have - * been started and interrupts are turned on now. The new int could happen - * inside the execution of NCR5380_intr(), leading to recursive - * calls. - * - * - I've added a function merge_contiguous_buffers() that tries to - * merge scatter-gather buffers that are located at contiguous - * physical addresses and can be processed with the same DMA setup. - * Since most scatter-gather operations work on a page (4K) of - * 4 buffers (1K), in more than 90% of all cases three interrupts and - * DMA setup actions are saved. - * - * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA - * and USLEEP, because these were messing up readability and will never be - * needed for Atari SCSI. - * - * - I've revised the NCR5380_main() calling scheme (relax the 'main_running' - * stuff), and 'main' is executed in a bottom half if awoken by an - * interrupt. - * - * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..." - * constructs. In my eyes, this made the source rather unreadable, so I - * finally replaced that by the *_PRINTK() macros. - * - */ - -/* - * Further development / testing that should be done : - * 1. Test linked command handling code after Eric is ready with - * the high level code. - */ -#include -#include - -#if (NDEBUG & NDEBUG_LISTS) -#define LIST(x, y) \ - do { \ - printk("LINE:%d Adding %p to %p\n", \ - __LINE__, (void*)(x), (void*)(y)); \ - if ((x) == (y)) \ - udelay(5); \ - } while (0) -#define REMOVE(w, x, y, z) \ - do { \ - printk("LINE:%d Removing: %p->%p %p->%p \n", \ - __LINE__, (void*)(w), (void*)(x), \ - (void*)(y), (void*)(z)); \ - if ((x) == (y)) \ - udelay(5); \ - } while (0) -#else -#define LIST(x,y) -#define REMOVE(w,x,y,z) -#endif - -#ifndef notyet -#undef LINKED -#endif - -/* - * Design - * Issues : - * - * The other Linux SCSI drivers were written when Linux was Intel PC-only, - * and specifically for each board rather than each chip. This makes their - * adaptation to platforms like the Mac (Some of which use NCR5380's) - * more difficult than it has to be. - * - * Also, many of the SCSI drivers were written before the command queuing - * routines were implemented, meaning their implementations of queued - * commands were hacked on rather than designed in from the start. - * - * When I designed the Linux SCSI drivers I figured that - * while having two different SCSI boards in a system might be useful - * for debugging things, two of the same type wouldn't be used. - * Well, I was wrong and a number of users have mailed me about running - * multiple high-performance SCSI boards in a server. - * - * Finally, when I get questions from users, I have no idea what - * revision of my driver they are running. - * - * This driver attempts to address these problems : - * This is a generic 5380 driver. To use it on a different platform, - * one simply writes appropriate system specific macros (ie, data - * transfer - some PC's will use the I/O bus, 68K's must use - * memory mapped) and drops this file in their 'C' wrapper. - * - * As far as command queueing, two queues are maintained for - * each 5380 in the system - commands that haven't been issued yet, - * and commands that are currently executing. This means that an - * unlimited number of commands may be queued, letting - * more commands propagate from the higher driver levels giving higher - * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, - * allowing multiple commands to propagate all the way to a SCSI-II device - * while a command is already executing. - * - * To solve the multiple-boards-in-the-same-system problem, - * there is a separate instance structure for each instance - * of a 5380 in the system. So, multiple NCR5380 drivers will - * be able to coexist with appropriate changes to the high level - * SCSI code. - * - * A NCR5380_PUBLIC_REVISION macro is provided, with the release - * number (updated for each public release) printed by the - * NCR5380_print_options command, which should be called from the - * wrapper detect function, so that I know what release of the driver - * users are using. - * - * Issues specific to the NCR5380 : - * - * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead - * piece of hardware that requires you to sit in a loop polling for - * the REQ signal as long as you are connected. Some devices are - * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect - * while doing long seek operations. - * - * The workaround for this is to keep track of devices that have - * disconnected. If the device hasn't disconnected, for commands that - * should disconnect, we do something like - * - * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } - * - * Some tweaking of N and M needs to be done. An algorithm based - * on "time to data" would give the best results as long as short time - * to datas (ie, on the same track) were considered, however these - * broken devices are the exception rather than the rule and I'd rather - * spend my time optimizing for the normal case. - * - * Architecture : - * - * At the heart of the design is a coroutine, NCR5380_main, - * which is started when not running by the interrupt handler, - * timer, and queue command function. It attempts to establish - * I_T_L or I_T_L_Q nexuses by removing the commands from the - * issue queue and calling NCR5380_select() if a nexus - * is not established. - * - * Once a nexus is established, the NCR5380_information_transfer() - * phase goes through the various phases as instructed by the target. - * if the target goes into MSG IN and sends a DISCONNECT message, - * the command structure is placed into the per instance disconnected - * queue, and NCR5380_main tries to find more work. If USLEEP - * was defined, and the target is idle for too long, the system - * will try to sleep. - * - * If a command has disconnected, eventually an interrupt will trigger, - * calling NCR5380_intr() which will in turn call NCR5380_reselect - * to reestablish a nexus. This will run main if necessary. - * - * On command termination, the done function will be called as - * appropriate. - * - * SCSI pointers are maintained in the SCp field of SCSI command - * structures, being initialized after the command is connected - * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. - * Note that in violation of the standard, an implicit SAVE POINTERS operation - * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. - */ - -/* - * Using this file : - * This file a skeleton Linux SCSI driver for the NCR 5380 series - * of chips. To use it, you write an architecture specific functions - * and macros and include this file in your driver. - * - * These macros control options : - * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. - * - * LINKED - if defined, linked commands are supported. - * - * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. - * - * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible - * - * These macros MUST be defined : - * - * NCR5380_read(register) - read from the specified register - * - * NCR5380_write(register, value) - write to the specific register - * - * Either real DMA *or* pseudo DMA may be implemented - * REAL functions : - * NCR5380_REAL_DMA should be defined if real DMA is to be used. - * Note that the DMA setup functions should return the number of bytes - * that they were able to program the controller for. - * - * Also note that generic i386/PC versions of these macros are - * available as NCR5380_i386_dma_write_setup, - * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. - * - * NCR5380_dma_write_setup(instance, src, count) - initialize - * NCR5380_dma_read_setup(instance, dst, count) - initialize - * NCR5380_dma_residual(instance); - residual count - * - * PSEUDO functions : - * NCR5380_pwrite(instance, src, count) - * NCR5380_pread(instance, dst, count); - * - * If nothing specific to this implementation needs doing (ie, with external - * hardware), you must also define - * - * NCR5380_queue_command - * NCR5380_reset - * NCR5380_abort - * NCR5380_proc_info - * - * to be the global entry points into the specific driver, ie - * #define NCR5380_queue_command t128_queue_command. - * - * If this is not done, the routines will be defined as static functions - * with the NCR5380* names and the user must provide a globally - * accessible wrapper function. - * - * The generic driver is initialized by calling NCR5380_init(instance), - * after setting the appropriate host specific fields and ID. If the - * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, - * possible) function may be used. Before the specific driver initialization - * code finishes, NCR5380_print_options should be called. - */ - -static struct Scsi_Host *first_instance = NULL; -static struct scsi_host_template *the_template = NULL; - -/* Macros ease life... :-) */ -#define SETUP_HOSTDATA(in) \ - struct NCR5380_hostdata *hostdata = \ - (struct NCR5380_hostdata *)(in)->hostdata -#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) - -#define NEXT(cmd) ((Scsi_Cmnd *)(cmd)->host_scribble) -#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next)) -#define NEXTADDR(cmd) ((Scsi_Cmnd **)&(cmd)->host_scribble) - -#define HOSTNO instance->host_no -#define H_NO(cmd) (cmd)->device->host->host_no - -#ifdef SUPPORT_TAGS - -/* - * Functions for handling tagged queuing - * ===================================== - * - * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes: - * - * Using consecutive numbers for the tags is no good idea in my eyes. There - * could be wrong re-usings if the counter (8 bit!) wraps and some early - * command has been preempted for a long time. My solution: a bitfield for - * remembering used tags. - * - * There's also the problem that each target has a certain queue size, but we - * cannot know it in advance :-( We just see a QUEUE_FULL status being - * returned. So, in this case, the driver internal queue size assumption is - * reduced to the number of active tags if QUEUE_FULL is returned by the - * target. The command is returned to the mid-level, but with status changed - * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL - * correctly. - * - * We're also not allowed running tagged commands as long as an untagged - * command is active. And REQUEST SENSE commands after a contingent allegiance - * condition _must_ be untagged. To keep track whether an untagged command has - * been issued, the host->busy array is still employed, as it is without - * support for tagged queuing. - * - * One could suspect that there are possible race conditions between - * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the - * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(), - * which already guaranteed to be running at most once. It is also the only - * place where tags/LUNs are allocated. So no other allocation can slip - * between that pair, there could only happen a reselection, which can free a - * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes - * important: the tag bit must be cleared before 'nr_allocated' is decreased. - */ - -/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */ -#undef TAG_NONE -#define TAG_NONE 0xff - -typedef struct { - DECLARE_BITMAP(allocated, MAX_TAGS); - int nr_allocated; - int queue_size; -} TAG_ALLOC; - -static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ - - -static void __init init_tags(void) -{ - int target, lun; - TAG_ALLOC *ta; - - if (!setup_use_tagged_queuing) - return; - - for (target = 0; target < 8; ++target) { - for (lun = 0; lun < 8; ++lun) { - ta = &TagAlloc[target][lun]; - bitmap_zero(ta->allocated, MAX_TAGS); - ta->nr_allocated = 0; - /* At the beginning, assume the maximum queue size we could - * support (MAX_TAGS). This value will be decreased if the target - * returns QUEUE_FULL status. - */ - ta->queue_size = MAX_TAGS; - } - } -} - - -/* Check if we can issue a command to this LUN: First see if the LUN is marked - * busy by an untagged command. If the command should use tagged queuing, also - * check that there is a free tag and the target's queue won't overflow. This - * function should be called with interrupts disabled to avoid race - * conditions. - */ - -static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged) -{ - SETUP_HOSTDATA(cmd->device->host); - - if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) - return 1; - if (!should_be_tagged || - !setup_use_tagged_queuing || !cmd->device->tagged_supported) - return 0; - if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= - TagAlloc[cmd->device->id][cmd->device->lun].queue_size) { - TAG_PRINTK("scsi%d: target %d lun %d: no free tags\n", - H_NO(cmd), cmd->device->id, cmd->device->lun); - return 1; - } - return 0; -} - - -/* Allocate a tag for a command (there are no checks anymore, check_lun_busy() - * must be called before!), or reserve the LUN in 'busy' if the command is - * untagged. - */ - -static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged) -{ - SETUP_HOSTDATA(cmd->device->host); - - /* If we or the target don't support tagged queuing, allocate the LUN for - * an untagged command. - */ - if (!should_be_tagged || - !setup_use_tagged_queuing || !cmd->device->tagged_supported) { - cmd->tag = TAG_NONE; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - TAG_PRINTK("scsi%d: target %d lun %d now allocated by untagged " - "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun); - } else { - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - - cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS); - set_bit(cmd->tag, ta->allocated); - ta->nr_allocated++; - TAG_PRINTK("scsi%d: using tag %d for target %d lun %d " - "(now %d tags in use)\n", - H_NO(cmd), cmd->tag, cmd->device->id, - cmd->device->lun, ta->nr_allocated); - } -} - - -/* Mark the tag of command 'cmd' as free, or in case of an untagged command, - * unlock the LUN. - */ - -static void cmd_free_tag(Scsi_Cmnd *cmd) -{ - SETUP_HOSTDATA(cmd->device->host); - - if (cmd->tag == TAG_NONE) { - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - TAG_PRINTK("scsi%d: target %d lun %d untagged cmd finished\n", - H_NO(cmd), cmd->device->id, cmd->device->lun); - } else if (cmd->tag >= MAX_TAGS) { - printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", - H_NO(cmd), cmd->tag); - } else { - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - clear_bit(cmd->tag, ta->allocated); - ta->nr_allocated--; - TAG_PRINTK("scsi%d: freed tag %d for target %d lun %d\n", - H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun); - } -} - - -static void free_all_tags(void) -{ - int target, lun; - TAG_ALLOC *ta; - - if (!setup_use_tagged_queuing) - return; - - for (target = 0; target < 8; ++target) { - for (lun = 0; lun < 8; ++lun) { - ta = &TagAlloc[target][lun]; - bitmap_zero(ta->allocated, MAX_TAGS); - ta->nr_allocated = 0; - } - } -} - -#endif /* SUPPORT_TAGS */ - - -/* - * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd ) - * - * Purpose: Try to merge several scatter-gather requests into one DMA - * transfer. This is possible if the scatter buffers lie on - * physical contiguous addresses. - * - * Parameters: Scsi_Cmnd *cmd - * The command to work on. The first scatter buffer's data are - * assumed to be already transferred into ptr/this_residual. - */ - -static void merge_contiguous_buffers(Scsi_Cmnd *cmd) -{ - unsigned long endaddr; -#if (NDEBUG & NDEBUG_MERGING) - unsigned long oldlen = cmd->SCp.this_residual; - int cnt = 1; -#endif - - for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1; - cmd->SCp.buffers_residual && - virt_to_phys(sg_virt(&cmd->SCp.buffer[1])) == endaddr;) { - MER_PRINTK("VTOP(%p) == %08lx -> merging\n", - page_address(sg_page(&cmd->SCp.buffer[1])), endaddr); -#if (NDEBUG & NDEBUG_MERGING) - ++cnt; -#endif - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual += cmd->SCp.buffer->length; - endaddr += cmd->SCp.buffer->length; - } -#if (NDEBUG & NDEBUG_MERGING) - if (oldlen != cmd->SCp.this_residual) - MER_PRINTK("merged %d buffers from %p, new length %08x\n", - cnt, cmd->SCp.ptr, cmd->SCp.this_residual); -#endif -} - -/* - * Function : void initialize_SCp(Scsi_Cmnd *cmd) - * - * Purpose : initialize the saved data pointers for cmd to point to the - * start of the buffer. - * - * Inputs : cmd - Scsi_Cmnd structure to have pointers reset. - */ - -static inline void initialize_SCp(Scsi_Cmnd *cmd) -{ - /* - * Initialize the Scsi Pointer field so that all of the commands in the - * various queues are valid. - */ - - if (scsi_bufflen(cmd)) { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - /* ++roman: Try to merge some scatter-buffers if they are at - * contiguous physical addresses. - */ - merge_contiguous_buffers(cmd); - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = NULL; - cmd->SCp.this_residual = 0; - } -} - -#include - -#if NDEBUG -static struct { - unsigned char mask; - const char *name; -} signals[] = { - { SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, - { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, - { SR_SEL, "SEL" }, {0, NULL} -}, basrs[] = { - {BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL} -}, icrs[] = { - {ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, - {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, - {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, - {0, NULL} -}, mrs[] = { - {MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, - {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, - "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, - {MR_MONITOR_BSY, "MODE MONITOR BSY"}, - {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, - {0, NULL} -}; - -/* - * Function : void NCR5380_print(struct Scsi_Host *instance) - * - * Purpose : print the SCSI bus signals for debugging purposes - * - * Input : instance - which NCR5380 - */ - -static void NCR5380_print(struct Scsi_Host *instance) -{ - unsigned char status, data, basr, mr, icr, i; - unsigned long flags; - - local_irq_save(flags); - data = NCR5380_read(CURRENT_SCSI_DATA_REG); - status = NCR5380_read(STATUS_REG); - mr = NCR5380_read(MODE_REG); - icr = NCR5380_read(INITIATOR_COMMAND_REG); - basr = NCR5380_read(BUS_AND_STATUS_REG); - local_irq_restore(flags); - printk("STATUS_REG: %02x ", status); - for (i = 0; signals[i].mask; ++i) - if (status & signals[i].mask) - printk(",%s", signals[i].name); - printk("\nBASR: %02x ", basr); - for (i = 0; basrs[i].mask; ++i) - if (basr & basrs[i].mask) - printk(",%s", basrs[i].name); - printk("\nICR: %02x ", icr); - for (i = 0; icrs[i].mask; ++i) - if (icr & icrs[i].mask) - printk(",%s", icrs[i].name); - printk("\nMODE: %02x ", mr); - for (i = 0; mrs[i].mask; ++i) - if (mr & mrs[i].mask) - printk(",%s", mrs[i].name); - printk("\n"); -} - -static struct { - unsigned char value; - const char *name; -} phases[] = { - {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, - {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, - {PHASE_UNKNOWN, "UNKNOWN"} -}; - -/* - * Function : void NCR5380_print_phase(struct Scsi_Host *instance) - * - * Purpose : print the current SCSI phase for debugging purposes - * - * Input : instance - which NCR5380 - */ - -static void NCR5380_print_phase(struct Scsi_Host *instance) -{ - unsigned char status; - int i; - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i) - ; - printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); - } -} - -#else /* !NDEBUG */ - -/* dummies... */ -static inline void NCR5380_print(struct Scsi_Host *instance) -{ -}; -static inline void NCR5380_print_phase(struct Scsi_Host *instance) -{ -}; - -#endif - -/* - * ++roman: New scheme of calling NCR5380_main() - * - * If we're not in an interrupt, we can call our main directly, it cannot be - * already running. Else, we queue it on a task queue, if not 'main_running' - * tells us that a lower level is already executing it. This way, - * 'main_running' needs not be protected in a special way. - * - * queue_main() is a utility function for putting our main onto the task - * queue, if main_running is false. It should be called only from a - * interrupt or bottom half. - */ - -#include -#include -#include - -static volatile int main_running; -static DECLARE_WORK(NCR5380_tqueue, NCR5380_main); - -static inline void queue_main(void) -{ - if (!main_running) { - /* If in interrupt and NCR5380_main() not already running, - queue it on the 'immediate' task queue, to be processed - immediately after the current interrupt processing has - finished. */ - schedule_work(&NCR5380_tqueue); - } - /* else: nothing to do: the running NCR5380_main() will pick up - any newly queued command. */ -} - - -static inline void NCR5380_all_init(void) -{ - static int done = 0; - if (!done) { - INI_PRINTK("scsi : NCR5380_all_init()\n"); - done = 1; - } -} - - -/* - * Function : void NCR58380_print_options (struct Scsi_Host *instance) - * - * Purpose : called by probe code indicating the NCR5380 driver - * options that were selected. - * - * Inputs : instance, pointer to this instance. Unused. - */ - -static void __init NCR5380_print_options(struct Scsi_Host *instance) -{ - printk(" generic options" -#ifdef AUTOSENSE - " AUTOSENSE" -#endif -#ifdef REAL_DMA - " REAL DMA" -#endif -#ifdef PARITY - " PARITY" -#endif -#ifdef SUPPORT_TAGS - " SCSI-2 TAGGED QUEUING" -#endif - ); - printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); -} - -/* - * Function : void NCR5380_print_status (struct Scsi_Host *instance) - * - * Purpose : print commands in the various queues, called from - * NCR5380_abort and NCR5380_debug to aid debugging. - * - * Inputs : instance, pointer to this instance. - */ - -static void NCR5380_print_status(struct Scsi_Host *instance) -{ - char *pr_bfr; - char *start; - int len; - - NCR_PRINT(NDEBUG_ANY); - NCR_PRINT_PHASE(NDEBUG_ANY); - - pr_bfr = (char *)__get_free_page(GFP_ATOMIC); - if (!pr_bfr) { - printk("NCR5380_print_status: no memory for print buffer\n"); - return; - } - len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); - pr_bfr[len] = 0; - printk("\n%s\n", pr_bfr); - free_page((unsigned long)pr_bfr); -} - - -/******************************************/ -/* - * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED] - * - * *buffer: I/O buffer - * **start: if inout == FALSE pointer into buffer where user read should start - * offset: current offset - * length: length of buffer - * hostno: Scsi_Host host_no - * inout: TRUE - user is writing; FALSE - user is reading - * - * Return the number of bytes read from or written -*/ - -#undef SPRINTF -#define SPRINTF(fmt,args...) \ - do { \ - if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ - pos += sprintf(pos, fmt , ## args); \ - } while(0) -static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length); - -static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, - char **start, off_t offset, int length, int inout) -{ - char *pos = buffer; - struct NCR5380_hostdata *hostdata; - Scsi_Cmnd *ptr; - unsigned long flags; - off_t begin = 0; -#define check_offset() \ - do { \ - if (pos - buffer < offset - begin) { \ - begin += pos - buffer; \ - pos = buffer; \ - } \ - } while (0) - - hostdata = (struct NCR5380_hostdata *)instance->hostdata; - - if (inout) /* Has data been written to the file ? */ - return -ENOSYS; /* Currently this is a no-op */ - SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); - check_offset(); - local_irq_save(flags); - SPRINTF("NCR5380: coroutine is%s running.\n", - main_running ? "" : "n't"); - check_offset(); - if (!hostdata->connected) - SPRINTF("scsi%d: no currently connected command\n", HOSTNO); - else - pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, - pos, buffer, length); - SPRINTF("scsi%d: issue_queue\n", HOSTNO); - check_offset(); - for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr)) { - pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - check_offset(); - } - - SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); - check_offset(); - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; - ptr = NEXT(ptr)) { - pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length); - check_offset(); - } - - local_irq_restore(flags); - *start = buffer + (offset - begin); - if (pos - buffer < offset - begin) - return 0; - else if (pos - buffer - (offset - begin) < length) - return pos - buffer - (offset - begin); - return length; -} - -static char *lprint_Scsi_Cmnd(Scsi_Cmnd *cmd, char *pos, char *buffer, int length) -{ - int i, s; - unsigned char *command; - SPRINTF("scsi%d: destination target %d, lun %d\n", - H_NO(cmd), cmd->device->id, cmd->device->lun); - SPRINTF(" command = "); - command = cmd->cmnd; - SPRINTF("%2d (0x%02x)", command[0], command[0]); - for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - SPRINTF(" %02x", command[i]); - SPRINTF("\n"); - return pos; -} - - -/* - * Function : void NCR5380_init (struct Scsi_Host *instance) - * - * Purpose : initializes *instance and corresponding 5380 chip. - * - * Inputs : instance - instantiation of the 5380 driver. - * - * Notes : I assume that the host, hostno, and id bits have been - * set correctly. I don't care about the irq and other fields. - * - */ - -static int __init NCR5380_init(struct Scsi_Host *instance, int flags) -{ - int i; - SETUP_HOSTDATA(instance); - - NCR5380_all_init(); - - hostdata->aborted = 0; - hostdata->id_mask = 1 << instance->this_id; - hostdata->id_higher_mask = 0; - for (i = hostdata->id_mask; i <= 0x80; i <<= 1) - if (i > hostdata->id_mask) - hostdata->id_higher_mask |= i; - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; -#ifdef SUPPORT_TAGS - init_tags(); -#endif -#if defined (REAL_DMA) - hostdata->dma_len = 0; -#endif - hostdata->targets_present = 0; - hostdata->connected = NULL; - hostdata->issue_queue = NULL; - hostdata->disconnected_queue = NULL; - hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; - - if (!the_template) { - the_template = instance->hostt; - first_instance = instance; - } - -#ifndef AUTOSENSE - if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) - printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" - " without AUTOSENSE option, contingent allegiance conditions may\n" - " be incorrectly cleared.\n", HOSTNO); -#endif /* def AUTOSENSE */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, 0); - - return 0; -} - -static void NCR5380_exit(struct Scsi_Host *instance) -{ - /* Empty, as we didn't schedule any delayed work */ -} - -/* - * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, - * void (*done)(Scsi_Cmnd *)) - * - * Purpose : enqueues a SCSI command - * - * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. - * - * Returns : 0 - * - * Side effects : - * cmd is added to the per instance issue_queue, with minor - * twiddling done to the host specific fields of cmd. If the - * main coroutine is not running, it is restarted. - * - */ - -static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) -{ - SETUP_HOSTDATA(cmd->device->host); - Scsi_Cmnd *tmp; - unsigned long flags; - -#if (NDEBUG & NDEBUG_NO_WRITE) - switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", - H_NO(cmd)); - cmd->result = (DID_ERROR << 16); - done(cmd); - return 0; - } -#endif /* (NDEBUG & NDEBUG_NO_WRITE) */ - -#ifdef NCR5380_STATS -# if 0 - if (!hostdata->connected && !hostdata->issue_queue && - !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } -# endif -# ifdef NCR5380_STAT_LIMIT - if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) -# endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); - hostdata->pendingw++; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); - hostdata->pendingr++; - break; - } -#endif - - /* - * We use the host_scribble field as a pointer to the next command - * in a queue - */ - - SET_NEXT(cmd, NULL); - cmd->scsi_done = done; - - cmd->result = 0; - - /* - * Insert the cmd into the issue queue. Note that REQUEST SENSE - * commands are added to the head of the queue since any command will - * clear the contingent allegiance condition that exists and the - * sense data is only guaranteed to be valid while the condition exists. - */ - - local_irq_save(flags); - /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. - * Otherwise a running NCR5380_main may steal the lock. - * Lock before actually inserting due to fairness reasons explained in - * atari_scsi.c. If we insert first, then it's impossible for this driver - * to release the lock. - * Stop timer for this command while waiting for the lock, or timeouts - * may happen (and they really do), and it's no good if the command doesn't - * appear in any of the queues. - * ++roman: Just disabling the NCR interrupt isn't sufficient here, - * because also a timer int can trigger an abort or reset, which would - * alter queues and touch the lock. - */ - if (!IS_A_TT()) { - /* perhaps stop command timer here */ - falcon_get_lock(); - /* perhaps restart command timer here */ - } - if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { - LIST(cmd, hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); - hostdata->issue_queue = cmd; - } else { - for (tmp = (Scsi_Cmnd *)hostdata->issue_queue; - NEXT(tmp); tmp = NEXT(tmp)) - ; - LIST(cmd, tmp); - SET_NEXT(tmp, cmd); - } - local_irq_restore(flags); - - QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); - - /* If queue_command() is called from an interrupt (real one or bottom - * half), we let queue_main() do the job of taking care about main. If it - * is already running, this is a no-op, else main will be queued. - * - * If we're not in an interrupt, we can call NCR5380_main() - * unconditionally, because it cannot be already running. - */ - if (in_interrupt() || ((flags >> 8) & 7) >= 6) - queue_main(); - else - NCR5380_main(NULL); - return 0; -} - -static DEF_SCSI_QCMD(NCR5380_queue_command) - -/* - * Function : NCR5380_main (void) - * - * Purpose : NCR5380_main is a coroutine that runs as long as more work can - * be done on the NCR5380 host adapters in a system. Both - * NCR5380_queue_command() and NCR5380_intr() will try to start it - * in case it is not running. - * - * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should - * reenable them. This prevents reentrancy and kernel stack overflow. - */ - -static void NCR5380_main(struct work_struct *work) -{ - Scsi_Cmnd *tmp, *prev; - struct Scsi_Host *instance = first_instance; - struct NCR5380_hostdata *hostdata = HOSTDATA(instance); - int done; - unsigned long flags; - - /* - * We run (with interrupts disabled) until we're sure that none of - * the host adapters have anything that can be done, at which point - * we set main_running to 0 and exit. - * - * Interrupts are enabled before doing various other internal - * instructions, after we've decided that we need to run through - * the loop again. - * - * this should prevent any race conditions. - * - * ++roman: Just disabling the NCR interrupt isn't sufficient here, - * because also a timer int can trigger an abort or reset, which can - * alter queues and touch the Falcon lock. - */ - - /* Tell int handlers main() is now already executing. Note that - no races are possible here. If an int comes in before - 'main_running' is set here, and queues/executes main via the - task queue, it doesn't do any harm, just this instance of main - won't find any work left to do. */ - if (main_running) - return; - main_running = 1; - - local_save_flags(flags); - do { - local_irq_disable(); /* Freeze request queues */ - done = 1; - - if (!hostdata->connected) { - MAIN_PRINTK("scsi%d: not connected\n", HOSTNO); - /* - * Search through the issue_queue for a command destined - * for a target that's not busy. - */ -#if (NDEBUG & NDEBUG_LISTS) - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; - tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) - ; - /*printk("%p ", tmp);*/ - if ((tmp == prev) && tmp) - printk(" LOOP\n"); - /* else printk("\n"); */ -#endif - for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, - prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) { - -#if (NDEBUG & NDEBUG_LISTS) - if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", - tmp, tmp->device->id, hostdata->busy[tmp->device->id], - tmp->device->lun); -#endif - /* When we find one, remove it from the issue queue. */ - /* ++guenther: possible race with Falcon locking */ - if ( -#ifdef SUPPORT_TAGS - !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) -#else - !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) -#endif - ) { - /* ++guenther: just to be sure, this must be atomic */ - local_irq_disable(); - if (prev) { - REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); - } else { - REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); - hostdata->issue_queue = NEXT(tmp); - } - SET_NEXT(tmp, NULL); - falcon_dont_release++; - - /* reenable interrupts after finding one */ - local_irq_restore(flags); - - /* - * Attempt to establish an I_T_L nexus here. - * On success, instance->hostdata->connected is set. - * On failure, we must add the command back to the - * issue queue so we can keep trying. - */ - MAIN_PRINTK("scsi%d: main(): command for target %d " - "lun %d removed from issue_queue\n", - HOSTNO, tmp->device->id, tmp->device->lun); - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - /* ++roman: ...and the standard also requires that - * REQUEST SENSE command are untagged. - */ - -#ifdef SUPPORT_TAGS - cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE); -#endif - if (!NCR5380_select(instance, tmp, - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : - TAG_NEXT)) { - falcon_dont_release--; - /* release if target did not response! */ - falcon_release_lock_if_possible(hostdata); - break; - } else { - local_irq_disable(); - LIST(tmp, hostdata->issue_queue); - SET_NEXT(tmp, hostdata->issue_queue); - hostdata->issue_queue = tmp; -#ifdef SUPPORT_TAGS - cmd_free_tag(tmp); -#endif - falcon_dont_release--; - local_irq_restore(flags); - MAIN_PRINTK("scsi%d: main(): select() failed, " - "returned to issue_queue\n", HOSTNO); - if (hostdata->connected) - break; - } - } /* if target/lun/target queue is not busy */ - } /* for issue_queue */ - } /* if (!hostdata->connected) */ - - if (hostdata->connected -#ifdef REAL_DMA - && !hostdata->dma_len -#endif - ) { - local_irq_restore(flags); - MAIN_PRINTK("scsi%d: main: performing information transfer\n", - HOSTNO); - NCR5380_information_transfer(instance); - MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); - done = 0; - } - } while (!done); - - /* Better allow ints _after_ 'main_running' has been cleared, else - an interrupt could believe we'll pick up the work it left for - us, but we won't see it anymore here... */ - main_running = 0; - local_irq_restore(flags); -} - - -#ifdef REAL_DMA -/* - * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) - * - * Purpose : Called by interrupt handler when DMA finishes or a phase - * mismatch occurs (which would finish the DMA transfer). - * - * Inputs : instance - this instance of the NCR5380. - * - */ - -static void NCR5380_dma_complete(struct Scsi_Host *instance) -{ - SETUP_HOSTDATA(instance); - int transfered, saved_data = 0, overrun = 0, cnt, toPIO; - unsigned char **data, p; - volatile int *count; - - if (!hostdata->connected) { - printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " - "no connected cmd\n", HOSTNO); - return; - } - - if (atari_read_overruns) { - p = hostdata->connected->SCp.phase; - if (p & SR_IO) { - udelay(10); - if ((NCR5380_read(BUS_AND_STATUS_REG) & - (BASR_PHASE_MATCH|BASR_ACK)) == - (BASR_PHASE_MATCH|BASR_ACK)) { - saved_data = NCR5380_read(INPUT_DATA_REG); - overrun = 1; - DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO); - } - } - } - - DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", - HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), - NCR5380_read(STATUS_REG)); - - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - transfered = hostdata->dma_len - NCR5380_dma_residual(instance); - hostdata->dma_len = 0; - - data = (unsigned char **)&hostdata->connected->SCp.ptr; - count = &hostdata->connected->SCp.this_residual; - *data += transfered; - *count -= transfered; - - if (atari_read_overruns) { - if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) { - cnt = toPIO = atari_read_overruns; - if (overrun) { - DMA_PRINTK("Got an input overrun, using saved byte\n"); - *(*data)++ = saved_data; - (*count)--; - cnt--; - toPIO--; - } - DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data); - NCR5380_transfer_pio(instance, &p, &cnt, data); - *count -= toPIO - cnt; - } - } -} -#endif /* REAL_DMA */ - - -/* - * Function : void NCR5380_intr (int irq) - * - * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses - * from the disconnected queue, and restarting NCR5380_main() - * as required. - * - * Inputs : int irq, irq that caused this interrupt. - * - */ - -static irqreturn_t NCR5380_intr(int irq, void *dev_id) -{ - struct Scsi_Host *instance = first_instance; - int done = 1, handled = 0; - unsigned char basr; - - INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); - - /* Look for pending interrupts */ - basr = NCR5380_read(BUS_AND_STATUS_REG); - INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); - /* dispatch to appropriate routine if found and done=0 */ - if (basr & BASR_IRQ) { - NCR_PRINT(NDEBUG_INTR); - if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { - done = 0; - ENABLE_IRQ(); - INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); - NCR5380_reselect(instance); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else if (basr & BASR_PARITY_ERROR) { - INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { - INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } else { - /* - * The rest of the interrupt conditions can occur only during a - * DMA transfer - */ - -#if defined(REAL_DMA) - /* - * We should only get PHASE MISMATCH and EOP interrupts if we have - * DMA enabled, so do a sanity check based on the current setting - * of the MODE register. - */ - - if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && - ((basr & BASR_END_DMA_TRANSFER) || - !(basr & BASR_PHASE_MATCH))) { - - INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); - NCR5380_dma_complete( instance ); - done = 0; - ENABLE_IRQ(); - } else -#endif /* REAL_DMA */ - { -/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ - if (basr & BASR_PHASE_MATCH) - printk(KERN_NOTICE "scsi%d: unknown interrupt, " - "BASR 0x%x, MR 0x%x, SR 0x%x\n", - HOSTNO, basr, NCR5380_read(MODE_REG), - NCR5380_read(STATUS_REG)); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - } /* if !(SELECTION || PARITY) */ - handled = 1; - } /* BASR & IRQ */ else { - printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " - "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, - NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - - if (!done) { - INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); - /* Put a call to NCR5380_main() on the queue... */ - queue_main(); - } - return IRQ_RETVAL(handled); -} - -#ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd) -{ -# ifdef NCR5380_STAT_LIMIT - if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) -# endif - switch (cmd->cmnd[0]) { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/ - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/ - hostdata->pendingr--; - break; - } -} -#endif - -/* - * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, - * int tag); - * - * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, - * including ARBITRATION, SELECTION, and initial message out for - * IDENTIFY and queue messages. - * - * Inputs : instance - instantiation of the 5380 driver on which this - * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for - * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for - * the command that is presently connected. - * - * Returns : -1 if selection could not execute for some reason, - * 0 if selection succeeded or failed because the target - * did not respond. - * - * Side effects : - * If bus busy, arbitration failed, etc, NCR5380_select() will exit - * with registers as they should have been on entry - ie - * SELECT_ENABLE will be set appropriately, the NCR5380 - * will cease to drive any SCSI bus signals. - * - * If successful : I_T_L or I_T_L_Q nexus will be established, - * instance->connected will be set to cmd. - * SELECT interrupt will be disabled. - * - * If failed (no target) : cmd->scsi_done() will be called, and the - * cmd->result host byte set to DID_BAD_TARGET. - */ - -static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag) -{ - SETUP_HOSTDATA(instance); - unsigned char tmp[3], phase; - unsigned char *data; - int len; - unsigned long timeout; - unsigned long flags; - - hostdata->restart_select = 0; - NCR_PRINT(NDEBUG_ARBITRATION); - ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, - instance->this_id); - - /* - * Set the phase bits to 0, otherwise the NCR5380 won't drive the - * data bus during SELECTION. - */ - - local_irq_save(flags); - if (hostdata->connected) { - local_irq_restore(flags); - return -1; - } - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* - * Start arbitration. - */ - - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); - - local_irq_restore(flags); - - /* Wait for arbitration logic to complete */ -#if defined(NCR_TIMEOUT) - { - unsigned long timeout = jiffies + 2*NCR_TIMEOUT; - - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && - time_before(jiffies, timeout) && !hostdata->connected) - ; - if (time_after_eq(jiffies, timeout)) { - printk("scsi : arbitration timeout at %d\n", __LINE__); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - } -#else /* NCR_TIMEOUT */ - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) && - !hostdata->connected) - ; -#endif - - ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); - - if (hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - return -1; - } - /* - * The arbitration delay is 2.2us, but this is a minimum and there is - * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate - * the integral nature of udelay(). - * - */ - - udelay(3); - - /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", - HOSTNO); - return -1; - } - - /* after/during arbitration, BSY should be asserted. - IBM DPES-31080 Version S31Q works now */ - /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ - NCR5380_write(INITIATOR_COMMAND_REG, - ICR_BASE | ICR_ASSERT_SEL | ICR_ASSERT_BSY); - - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", - HOSTNO); - return -1; - } - - /* - * Again, bus clear + bus settle time is 1.2us, however, this is - * a minimum so we'll udelay ceil(1.2) - */ - -#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY - /* ++roman: But some targets (see above :-) seem to need a bit more... */ - udelay(15); -#else - udelay(2); -#endif - - if (hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; - } - - ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); - - /* - * Now that we have won arbitration, start Selection process, asserting - * the host and target ID's on the SCSI bus. - */ - - NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); - - /* - * Raise ATN while SEL is true before BSY goes false from arbitration, - * since this is the only way to guarantee that we'll get a MESSAGE OUT - * phase immediately after selection. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); - NCR5380_write(MODE_REG, MR_BASE); - - /* - * Reselect interrupts must be turned off prior to the dropping of BSY, - * otherwise we will trigger an interrupt. - */ - - if (hostdata->connected) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; - } - - NCR5380_write(SELECT_ENABLE_REG, 0); - - /* - * The initiator shall then wait at least two deskew delays and release - * the BSY signal. - */ - udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ - - /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_ATN | ICR_ASSERT_SEL)); - - /* - * Something weird happens when we cease to drive BSY - looks - * like the board/chip is letting us do another read before the - * appropriate propagation delay has expired, and we're confusing - * a BSY signal from ourselves as the target's response to SELECTION. - * - * A small delay (the 'C++' frontend breaks the pipeline with an - * unnecessary jump, making it work on my 386-33/Trantor T128, the - * tighter 'C' code breaks and requires this) solves the problem - - * the 1 us delay is arbitrary, and only used because this delay will - * be the same on other platforms and since it works here, it should - * work there. - * - * wingel suggests that this could be due to failing to wait - * one deskew delay. - */ - - udelay(1); - - SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); - - /* - * The SCSI specification calls for a 250 ms timeout for the actual - * selection. - */ - - timeout = jiffies + 25; - - /* - * XXX very interesting - we're seeing a bounce where the BSY we - * asserted is being reflected / still asserted (propagation delay?) - * and it's detecting as true. Sigh. - */ - -#if 0 - /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert - * IO while SEL is true. But again, there are some disks out the in the - * world that do that nevertheless. (Somebody claimed that this announces - * reselection capability of the target.) So we better skip that test and - * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) - */ - - while (time_before(jiffies, timeout) && - !(NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO))) - ; - - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_reselect(instance); - printk(KERN_ERR "scsi%d: reselection after won arbitration?\n", - HOSTNO); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } -#else - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)) - ; -#endif - - /* - * No less than two deskew delays after the initiator detects the - * BSY signal is true, it shall release the SEL signal and may - * change the DATA BUS. -wingel - */ - - udelay(1); - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if (hostdata->targets_present & (1 << cmd->device->id)) { - printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); - if (hostdata->restart_select) - printk(KERN_NOTICE "\trestart select\n"); - NCR_PRINT(NDEBUG_ANY); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - cmd->result = DID_BAD_TARGET << 16; -#ifdef NCR5380_STATS - collect_stats(hostdata, cmd); -#endif -#ifdef SUPPORT_TAGS - cmd_free_tag(cmd); -#endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return 0; - } - - hostdata->targets_present |= (1 << cmd->device->id); - - /* - * Since we followed the SCSI spec, and raised ATN while SEL - * was true but before BSY was false during selection, the information - * transfer phase should be a MESSAGE OUT phase so that we can send the - * IDENTIFY message. - * - * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG - * message (2 bytes) with a tag ID that we increment with every command - * until it wraps back to 0. - * - * XXX - it turns out that there are some broken SCSI-II devices, - * which claim to support tagged queuing but fail when more than - * some number of commands are issued at once. - */ - - /* Wait for start of REQ/ACK handshake */ - while (!(NCR5380_read(STATUS_REG) & SR_REQ)) - ; - - SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", - HOSTNO, cmd->device->id); - tmp[0] = IDENTIFY(1, cmd->device->lun); - -#ifdef SUPPORT_TAGS - if (cmd->tag != TAG_NONE) { - tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; - tmp[2] = cmd->tag; - len = 3; - } else - len = 1; -#else - len = 1; - cmd->tag = 0; -#endif /* SUPPORT_TAGS */ - - /* Send message(s) */ - data = tmp; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(instance, &phase, &len, &data); - SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); - /* XXX need to handle errors here */ - hostdata->connected = cmd; -#ifndef SUPPORT_TAGS - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); -#endif - - initialize_SCp(cmd); - - return 0; -} - -/* - * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, - * unsigned char *phase, int *count, unsigned char **data) - * - * Purpose : transfers data in given phase using polled I/O - * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. - * - * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes are transferred or exit - * is in same phase. - * - * Also, *phase, *count, *data are modified in place. - * - * XXX Note : handling for bus free may be useful. - */ - -/* - * Note : this code is not as quick as it could be, however it - * IS 100% reliable, and for the actual data transfer where speed - * counts, we will always do a pseudo DMA or DMA transfer. - */ - -static int NCR5380_transfer_pio(struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data) -{ - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; - - /* - * The NCR5380 chip will only drive the SCSI bus when the - * phase specified in the appropriate bits of the TARGET COMMAND - * REGISTER match the STATUS REGISTER - */ - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - - do { - /* - * Wait for assertion of REQ, after which the phase bits will be - * valid - */ - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)) - ; - - HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); - - /* Check for phase mismatch */ - if ((tmp & PHASE_MASK) != p) { - PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); - NCR_PRINT_PHASE(NDEBUG_PIO); - break; - } - - /* Do actual transfer from SCSI bus to / from memory */ - if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); - else - *d = NCR5380_read(CURRENT_SCSI_DATA_REG); - - ++d; - - /* - * The SCSI standard suggests that in MSGOUT phase, the initiator - * should drop ATN on the last byte of the message phase - * after REQ has been asserted for the handshake but before - * the initiator raises ACK. - */ - - if (!(p & SR_IO)) { - if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ACK); - } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN); - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - } - } else { - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); - } - - while (NCR5380_read(STATUS_REG) & SR_REQ) - ; - - HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); - - /* - * We have several special cases to consider during REQ/ACK handshaking : - * 1. We were in MSGOUT phase, and we are on the last byte of the - * message. ATN must be dropped as ACK is dropped. - * - * 2. We are in a MSGIN phase, and we are on the last byte of the - * message. We must exit with ACK asserted, so that the calling - * code may raise ATN before dropping ACK to reject the message. - * - * 3. ACK and ATN are clear and the target may proceed as normal. - */ - if (!(p == PHASE_MSGIN && c == 1)) { - if (p == PHASE_MSGOUT && c > 1) - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - else - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - } - } while (--c); - - PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); - - *count = c; - *data = d; - tmp = NCR5380_read(STATUS_REG); - /* The phase read from the bus is valid if either REQ is (already) - * asserted or if ACK hasn't been released yet. The latter is the case if - * we're in MSGIN and all wanted bytes have been received. - */ - if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) - *phase = tmp & PHASE_MASK; - else - *phase = PHASE_UNKNOWN; - - if (!c || (*phase == p)) - return 0; - else - return -1; -} - -/* - * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * - * Returns : 0 on success, -1 on failure. - */ - -static int do_abort(struct Scsi_Host *host) -{ - unsigned char tmp, *msgptr, phase; - int len; - - /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - /* - * Wait for the target to indicate a valid phase by asserting - * REQ. Once this happens, we'll have either a MSGOUT phase - * and can immediately send the ABORT message, or we'll have some - * other phase and will have to source/sink data. - * - * We really don't care what value was on the bus or what value - * the target sees, so we just handshake. - */ - - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)) - ; - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ) - ; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - } - - tmp = ABORT; - msgptr = &tmp; - len = 1; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(host, &phase, &len, &msgptr); - - /* - * If we got here, and the command completed successfully, - * we're about to go into bus free state. - */ - - return len ? -1 : 0; -} - -#if defined(REAL_DMA) -/* - * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, - * unsigned char *phase, int *count, unsigned char **data) - * - * Purpose : transfers data in given phase using either real - * or pseudo DMA. - * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. - * - * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transferred or exit - * is in same phase. - * - * Also, *phase, *count, *data are modified in place. - * - */ - - -static int NCR5380_transfer_dma(struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data) -{ - SETUP_HOSTDATA(instance); - register int c = *count; - register unsigned char p = *phase; - register unsigned char *d = *data; - unsigned char tmp; - unsigned long flags; - - if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { - *phase = tmp; - return -1; - } - - if (atari_read_overruns && (p & SR_IO)) - c -= atari_read_overruns; - - DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", - HOSTNO, (p & SR_IO) ? "reading" : "writing", - c, (p & SR_IO) ? "to" : "from", d); - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - -#ifdef REAL_DMA - NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY); -#endif /* def REAL_DMA */ - - if (IS_A_TT()) { - /* On the Medusa, it is a must to initialize the DMA before - * starting the NCR. This is also the cleaner way for the TT. - */ - local_irq_save(flags); - hostdata->dma_len = (p & SR_IO) ? - NCR5380_dma_read_setup(instance, d, c) : - NCR5380_dma_write_setup(instance, d, c); - local_irq_restore(flags); - } - - if (p & SR_IO) - NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); - else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA); - NCR5380_write(START_DMA_SEND_REG, 0); - } - - if (!IS_A_TT()) { - /* On the Falcon, the DMA setup must be done after the last */ - /* NCR access, else the DMA setup gets trashed! - */ - local_irq_save(flags); - hostdata->dma_len = (p & SR_IO) ? - NCR5380_dma_read_setup(instance, d, c) : - NCR5380_dma_write_setup(instance, d, c); - local_irq_restore(flags); - } - return 0; -} -#endif /* defined(REAL_DMA) */ - -/* - * Function : NCR5380_information_transfer (struct Scsi_Host *instance) - * - * Purpose : run through the various SCSI phases and do as the target - * directs us to. Operates on the currently connected command, - * instance->connected. - * - * Inputs : instance, instance for which we are doing commands - * - * Side effects : SCSI things happen, the disconnected queue will be - * modified if a command disconnects, *instance->connected will - * change. - * - * XXX Note : we need to watch for bus free or a reset condition here - * to recover from an unexpected bus free condition. - */ - -static void NCR5380_information_transfer(struct Scsi_Host *instance) -{ - SETUP_HOSTDATA(instance); - unsigned long flags; - unsigned char msgout = NOP; - int sink = 0; - int len; -#if defined(REAL_DMA) - int transfersize; -#endif - unsigned char *data; - unsigned char phase, tmp, extended_msg[10], old_phase = 0xff; - Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected; - - while (1) { - tmp = NCR5380_read(STATUS_REG); - /* We only have a valid SCSI phase when REQ is asserted */ - if (tmp & SR_REQ) { - phase = (tmp & PHASE_MASK); - if (phase != old_phase) { - old_phase = phase; - NCR_PRINT_PHASE(NDEBUG_INFORMATION); - } - - if (sink && (phase != PHASE_MSGOUT)) { - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ) - ; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 0; - continue; - } - - switch (phase) { - case PHASE_DATAOUT: -#if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " - "aborted\n", HOSTNO); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - return; -#endif - case PHASE_DATAIN: - /* - * If there is no room left in the current buffer in the - * scatter-gather list, move onto the next one. - */ - - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - /* ++roman: Try to merge some scatter-buffers if - * they are at contiguous physical addresses. - */ - merge_contiguous_buffers(cmd); - INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", - HOSTNO, cmd->SCp.this_residual, - cmd->SCp.buffers_residual); - } - - /* - * The preferred transfer method is going to be - * PSEUDO-DMA for systems that are strictly PIO, - * since we can let the hardware do the handshaking. - * - * For this to work, we need to know the transfersize - * ahead of time, since the pseudo-DMA code will sit - * in an unconditional loop. - */ - - /* ++roman: I suggest, this should be - * #if def(REAL_DMA) - * instead of leaving REAL_DMA out. - */ - -#if defined(REAL_DMA) - if (!cmd->device->borken && - (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) { - len = transfersize; - cmd->SCp.phase = phase; - if (NCR5380_transfer_dma(instance, &phase, - &len, (unsigned char **)&cmd->SCp.ptr)) { - /* - * If the watchdog timer fires, all future - * accesses to this device will use the - * polled-IO. */ - printk(KERN_NOTICE "scsi%d: switching target %d " - "lun %d to slow handshake\n", HOSTNO, - cmd->device->id, cmd->device->lun); - cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - /* XXX - need to source or sink data here, as appropriate */ - } else { -#ifdef REAL_DMA - /* ++roman: When using real DMA, - * information_transfer() should return after - * starting DMA since it has nothing more to - * do. - */ - return; -#else - cmd->SCp.this_residual -= transfersize - len; -#endif - } - } else -#endif /* defined(REAL_DMA) */ - NCR5380_transfer_pio(instance, &phase, - (int *)&cmd->SCp.this_residual, - (unsigned char **)&cmd->SCp.ptr); - break; - case PHASE_MSGIN: - len = 1; - data = &tmp; - NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Message = tmp; - - switch (tmp) { - /* - * Linking lets us reduce the time required to get the - * next command out to the device, hopefully this will - * mean we don't waste another revolution due to the delays - * required by ARBITRATION and another SELECTION. - * - * In the current implementation proposal, low level drivers - * merely have to start the next command, pointed to by - * next_link, done() is called as with unlinked commands. - */ -#ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - LNK_PRINTK("scsi%d: target %d lun %d linked command " - "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Sanity check : A linked command should only terminate - * with one of these messages if there are more linked - * commands available. - */ - - if (!cmd->next_link) { - printk(KERN_NOTICE "scsi%d: target %d lun %d " - "linked command complete, no next_link\n", - HOSTNO, cmd->device->id, cmd->device->lun); - sink = 1; - do_abort(instance); - return; - } - - initialize_SCp(cmd->next_link); - /* The next command is still part of this process; copy it - * and don't free it! */ - cmd->next_link->tag = cmd->tag; - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - LNK_PRINTK("scsi%d: target %d lun %d linked request " - "done, calling scsi_done().\n", - HOSTNO, cmd->device->id, cmd->device->lun); -#ifdef NCR5380_STATS - collect_stats(hostdata, cmd); -#endif - cmd->scsi_done(cmd); - cmd = hostdata->connected; - break; -#endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* ++guenther: possible race with Falcon locking */ - falcon_dont_release++; - hostdata->connected = NULL; - QU_PRINTK("scsi%d: command for target %d, lun %d " - "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); -#ifdef SUPPORT_TAGS - cmd_free_tag(cmd); - if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { - /* Turn a QUEUE FULL status into BUSY, I think the - * mid level cannot handle QUEUE FULL :-( (The - * command is retried after BUSY). Also update our - * queue size to the number of currently issued - * commands now. - */ - /* ++Andreas: the mid level code knows about - QUEUE_FULL now. */ - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - TAG_PRINTK("scsi%d: target %d lun %d returned " - "QUEUE_FULL after %d commands\n", - HOSTNO, cmd->device->id, cmd->device->lun, - ta->nr_allocated); - if (ta->queue_size > ta->nr_allocated) - ta->nr_allocated = ta->queue_size; - } -#else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); -#endif - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - - /* - * I'm not sure what the correct thing to do here is : - * - * If the command that just executed is NOT a request - * sense, the obvious thing to do is to set the result - * code to the values of the stored parameters. - * - * If it was a REQUEST SENSE command, we need some way to - * differentiate between the failure code of the original - * and the failure code of the REQUEST sense - the obvious - * case is success, where we fall through and leave the - * result code unchanged. - * - * The non-obvious place is where the REQUEST SENSE failed - */ - - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (status_byte(cmd->SCp.Status) != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - -#ifdef AUTOSENSE - if ((cmd->cmnd[0] == REQUEST_SENSE) && - hostdata->ses.cmd_len) { - scsi_eh_restore_cmnd(cmd, &hostdata->ses); - hostdata->ses.cmd_len = 0 ; - } - - if ((cmd->cmnd[0] != REQUEST_SENSE) && - (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { - scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); - - ASEN_PRINTK("scsi%d: performing request sense\n", HOSTNO); - - local_irq_save(flags); - LIST(cmd,hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); - hostdata->issue_queue = (Scsi_Cmnd *) cmd; - local_irq_restore(flags); - QU_PRINTK("scsi%d: REQUEST SENSE added to head of " - "issue queue\n", H_NO(cmd)); - } else -#endif /* def AUTOSENSE */ - { -#ifdef NCR5380_STATS - collect_stats(hostdata, cmd); -#endif - cmd->scsi_done(cmd); - } - - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - - falcon_dont_release--; - /* ++roman: For Falcon SCSI, release the lock on the - * ST-DMA here if no other commands are waiting on the - * disconnected queue. - */ - falcon_release_lock_if_possible(hostdata); - return; - case MESSAGE_REJECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - /* The target obviously doesn't support tagged - * queuing, even though it announced this ability in - * its INQUIRY data ?!? (maybe only this LUN?) Ok, - * clear 'tagged_supported' and lock the LUN, since - * the command is treated as untagged further on. - */ - cmd->device->tagged_supported = 0; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - cmd->tag = TAG_NONE; - TAG_PRINTK("scsi%d: target %d lun %d rejected " - "QUEUE_TAG message; tagged queuing " - "disabled\n", - HOSTNO, cmd->device->id, cmd->device->lun); - break; - } - break; - case DISCONNECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - local_irq_save(flags); - cmd->device->disconnect = 1; - LIST(cmd,hostdata->disconnected_queue); - SET_NEXT(cmd, hostdata->disconnected_queue); - hostdata->connected = NULL; - hostdata->disconnected_queue = cmd; - local_irq_restore(flags); - QU_PRINTK("scsi%d: command for target %d lun %d was " - "moved from connected to the " - "disconnected_queue\n", HOSTNO, - cmd->device->id, cmd->device->lun); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* Wait for bus free to avoid nasty timeouts */ - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - return; - /* - * The SCSI data pointer is *IMPLICITLY* saved on a disconnect - * operation, in violation of the SCSI spec so we can safely - * ignore SAVE/RESTORE pointers calls. - * - * Unfortunately, some disks violate the SCSI spec and - * don't issue the required SAVE_POINTERS message before - * disconnecting, and we have to break spec to remain - * compatible. - */ - case SAVE_POINTERS: - case RESTORE_POINTERS: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - break; - case EXTENDED_MESSAGE: - /* - * Extended messages are sent in the following format : - * Byte - * 0 EXTENDED_MESSAGE == 1 - * 1 length (includes one byte for code, doesn't - * include first two bytes) - * 2 code - * 3..length+1 arguments - * - * Start the extended message buffer with the EXTENDED_MESSAGE - * byte, since spi_print_msg() wants the whole thing. - */ - extended_msg[0] = EXTENDED_MESSAGE; - /* Accept first byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); - - len = 2; - data = extended_msg + 1; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, - (int)extended_msg[1], (int)extended_msg[2]); - - if (!len && extended_msg[1] <= - (sizeof(extended_msg) - 1)) { - /* Accept third byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - len = extended_msg[1] - 1; - data = extended_msg + 3; - phase = PHASE_MSGIN; - - NCR5380_transfer_pio(instance, &phase, &len, &data); - EXT_PRINTK("scsi%d: message received, residual %d\n", - HOSTNO, len); - - switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; - } - } else if (len) { - printk(KERN_NOTICE "scsi%d: error receiving " - "extended message\n", HOSTNO); - tmp = 0; - } else { - printk(KERN_NOTICE "scsi%d: extended message " - "code %02x length %d is too long\n", - HOSTNO, extended_msg[2], extended_msg[1]); - tmp = 0; - } - /* Fall through to reject message */ - - /* - * If we get something weird that we aren't expecting, - * reject it. - */ - default: - if (!tmp) { - printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); - spi_print_msg(extended_msg); - printk("\n"); - } else if (tmp != EXTENDED_MESSAGE) - printk(KERN_DEBUG "scsi%d: rejecting unknown " - "message %02x from target %d, lun %d\n", - HOSTNO, tmp, cmd->device->id, cmd->device->lun); - else - printk(KERN_DEBUG "scsi%d: rejecting unknown " - "extended message " - "code %02x, length %d from target %d, lun %d\n", - HOSTNO, extended_msg[1], extended_msg[0], - cmd->device->id, cmd->device->lun); - - - msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - break; - } /* switch (tmp) */ - break; - case PHASE_MSGOUT: - len = 1; - data = &msgout; - hostdata->last_message = msgout; - NCR5380_transfer_pio(instance, &phase, &len, &data); - if (msgout == ABORT) { -#ifdef SUPPORT_TAGS - cmd_free_tag(cmd); -#else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); -#endif - hostdata->connected = NULL; - cmd->result = DID_ERROR << 16; -#ifdef NCR5380_STATS - collect_stats(hostdata, cmd); -#endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - falcon_release_lock_if_possible(hostdata); - return; - } - msgout = NOP; - break; - case PHASE_CMDOUT: - len = cmd->cmd_len; - data = cmd->cmnd; - /* - * XXX for performance reasons, on machines with a - * PSEUDO-DMA architecture we should probably - * use the dma transfer function. - */ - NCR5380_transfer_pio(instance, &phase, &len, &data); - break; - case PHASE_STATIN: - len = 1; - data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Status = tmp; - break; - default: - printk("scsi%d: unknown phase\n", HOSTNO); - NCR_PRINT(NDEBUG_ANY); - } /* switch(phase) */ - } /* if (tmp * SR_REQ) */ - } /* while (1) */ -} - -/* - * Function : void NCR5380_reselect (struct Scsi_Host *instance) - * - * Purpose : does reselection, initializing the instance->connected - * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q - * nexus has been reestablished, - * - * Inputs : instance - this instance of the NCR5380. - * - */ - - -static void NCR5380_reselect(struct Scsi_Host *instance) -{ - SETUP_HOSTDATA(instance); - unsigned char target_mask; - unsigned char lun, phase; - int len; -#ifdef SUPPORT_TAGS - unsigned char tag; -#endif - unsigned char msg[3]; - unsigned char *data; - Scsi_Cmnd *tmp = NULL, *prev; -/* unsigned long flags; */ - - /* - * Disable arbitration, etc. since the host adapter obviously - * lost, and tell an interrupted NCR5380_select() to restart. - */ - - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); - - RSL_PRINTK("scsi%d: reselect\n", HOSTNO); - - /* - * At this point, we have detected that our SCSI ID is on the bus, - * SEL is true and BSY was false for at least one bus settle delay - * (400 ns). - * - * We must assert BSY ourselves, until the target drops the SEL - * signal. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); - - while (NCR5380_read(STATUS_REG) & SR_SEL) - ; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - /* - * Wait for target to go into MSGIN. - */ - - while (!(NCR5380_read(STATUS_REG) & SR_REQ)) - ; - - len = 1; - data = msg; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - - if (!(msg[0] & 0x80)) { - printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); - spi_print_msg(msg); - do_abort(instance); - return; - } - lun = (msg[0] & 0x07); - -#ifdef SUPPORT_TAGS - /* If the phase is still MSGIN, the target wants to send some more - * messages. In case it supports tagged queuing, this is probably a - * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. - */ - tag = TAG_NONE; - if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { - /* Accept previous IDENTIFY message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - len = 2; - data = msg + 1; - if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && - msg[1] == SIMPLE_QUEUE_TAG) - tag = msg[2]; - TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " - "reselection\n", HOSTNO, target_mask, lun, tag); - } -#endif - - /* - * Find the command corresponding to the I_T_L or I_T_L_Q nexus we - * just reestablished, and remove it from the disconnected queue. - */ - - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = NEXT(tmp)) { - if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) -#ifdef SUPPORT_TAGS - && (tag == tmp->tag) -#endif - ) { - /* ++guenther: prevent race with falcon_release_lock */ - falcon_dont_release++; - if (prev) { - REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); - } else { - REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); - hostdata->disconnected_queue = NEXT(tmp); - } - SET_NEXT(tmp, NULL); - break; - } - } - - if (!tmp) { - printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " -#ifdef SUPPORT_TAGS - "tag %d " -#endif - "not in disconnected_queue.\n", - HOSTNO, target_mask, lun -#ifdef SUPPORT_TAGS - , tag -#endif - ); - /* - * Since we have an established nexus that we can't do anything - * with, we must abort it. - */ - do_abort(instance); - return; - } - - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - hostdata->connected = tmp; - RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", - HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag); - falcon_dont_release--; -} - - -/* - * Function : int NCR5380_abort (Scsi_Cmnd *cmd) - * - * Purpose : abort a command - * - * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the - * host byte of the result field to, if zero DID_ABORTED is - * used. - * - * Returns : 0 - success, -1 on failure. - * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is - * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). - */ - -static -int NCR5380_abort(Scsi_Cmnd *cmd) -{ - struct Scsi_Host *instance = cmd->device->host; - SETUP_HOSTDATA(instance); - Scsi_Cmnd *tmp, **prev; - unsigned long flags; - - printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); - scsi_print_command(cmd); - - NCR5380_print_status(instance); - - local_irq_save(flags); - - if (!IS_A_TT() && !falcon_got_lock) - printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n", - HOSTNO); - - ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, - NCR5380_read(BUS_AND_STATUS_REG), - NCR5380_read(STATUS_REG)); - -#if 1 - /* - * Case 1 : If the command is the currently executing command, - * we'll set the aborted flag and return control so that - * information transfer routine can exit cleanly. - */ - - if (hostdata->connected == cmd) { - - ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); - /* - * We should perform BSY checking, and make sure we haven't slipped - * into BUS FREE. - */ - - /* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ - /* - * Since we can't change phases until we've completed the current - * handshake, we have to source or sink a byte of data if the current - * phase is not MSGOUT. - */ - - /* - * Return control to the executing NCR drive so we can clear the - * aborted flag and get back into our main loop. - */ - - if (do_abort(instance) == 0) { - hostdata->aborted = 1; - hostdata->connected = NULL; - cmd->result = DID_ABORT << 16; -#ifdef SUPPORT_TAGS - cmd_free_tag(cmd); -#else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); -#endif - local_irq_restore(flags); - cmd->scsi_done(cmd); - falcon_release_lock_if_possible(hostdata); - return SCSI_ABORT_SUCCESS; - } else { -/* local_irq_restore(flags); */ - printk("scsi%d: abort of connected command failed!\n", HOSTNO); - return SCSI_ABORT_ERROR; - } - } -#endif - - /* - * Case 2 : If the command hasn't been issued yet, we simply remove it - * from the issue queue. - */ - for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue), - tmp = (Scsi_Cmnd *)hostdata->issue_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) { - if (cmd == tmp) { - REMOVE(5, *prev, tmp, NEXT(tmp)); - (*prev) = NEXT(tmp); - SET_NEXT(tmp, NULL); - tmp->result = DID_ABORT << 16; - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", - HOSTNO); - /* Tagged queuing note: no tag to free here, hasn't been assigned - * yet... */ - tmp->scsi_done(tmp); - falcon_release_lock_if_possible(hostdata); - return SCSI_ABORT_SUCCESS; - } - } - - /* - * Case 3 : If any commands are connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. - * - * Timeouts, and therefore aborted commands, will be highly unlikely - * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. - */ - - if (hostdata->connected) { - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); - return SCSI_ABORT_SNOOZE; - } - - /* - * Case 4: If the command is currently disconnected from the bus, and - * there are no connected commands, we reconnect the I_T_L or - * I_T_L_Q nexus associated with it, go into message out, and send - * an abort message. - * - * This case is especially ugly. In order to reestablish the nexus, we - * need to call NCR5380_select(). The easiest way to implement this - * function was to abort if the bus was busy, and let the interrupt - * handler triggered on the SEL for reselect take care of lost arbitrations - * where necessary, meaning interrupts need to be enabled. - * - * When interrupts are enabled, the queues may change - so we - * can't remove it from the disconnected queue before selecting it - * because that could cause a failure in hashing the nexus if that - * device reselected. - * - * Since the queues may change, we can't use the pointers from when we - * first locate it. - * - * So, we must first locate the command, and if NCR5380_select() - * succeeds, then issue the abort, relocate the command and remove - * it from the disconnected queue. - */ - - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; - tmp = NEXT(tmp)) { - if (cmd == tmp) { - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); - - if (NCR5380_select(instance, cmd, (int)cmd->tag)) - return SCSI_ABORT_BUSY; - - ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); - - do_abort(instance); - - local_irq_save(flags); - for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue), - tmp = (Scsi_Cmnd *)hostdata->disconnected_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) { - if (cmd == tmp) { - REMOVE(5, *prev, tmp, NEXT(tmp)); - *prev = NEXT(tmp); - SET_NEXT(tmp, NULL); - tmp->result = DID_ABORT << 16; - /* We must unlock the tag/LUN immediately here, since the - * target goes to BUS FREE and doesn't send us another - * message (COMMAND_COMPLETE or the like) - */ -#ifdef SUPPORT_TAGS - cmd_free_tag(tmp); -#else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); -#endif - local_irq_restore(flags); - tmp->scsi_done(tmp); - falcon_release_lock_if_possible(hostdata); - return SCSI_ABORT_SUCCESS; - } - } - } - } - - /* - * Case 5 : If we reached this point, the command was not found in any of - * the queues. - * - * We probably reached this point because of an unlikely race condition - * between the command completing successfully and the abortion code, - * so we won't panic, but we will notify the user in case something really - * broke. - */ - - local_irq_restore(flags); - printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO); - - /* Maybe it is sufficient just to release the ST-DMA lock... (if - * possible at all) At least, we should check if the lock could be - * released after the abort, in case it is kept due to some bug. - */ - falcon_release_lock_if_possible(hostdata); - - return SCSI_ABORT_NOT_RUNNING; -} - - -/* - * Function : int NCR5380_reset (Scsi_Cmnd *cmd) - * - * Purpose : reset the SCSI bus. - * - * Returns : SCSI_RESET_WAKEUP - * - */ - -static int NCR5380_bus_reset(Scsi_Cmnd *cmd) -{ - SETUP_HOSTDATA(cmd->device->host); - int i; - unsigned long flags; -#if 1 - Scsi_Cmnd *connected, *disconnected_queue; -#endif - - if (!IS_A_TT() && !falcon_got_lock) - printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n", - H_NO(cmd)); - - NCR5380_print_status(cmd->device->host); - - /* get in phase */ - NCR5380_write(TARGET_COMMAND_REG, - PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG))); - /* assert RST */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - udelay(40); - /* reset NCR registers */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, 0); - /* ++roman: reset interrupt condition! otherwise no interrupts don't get - * through anymore ... */ - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - -#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ - /* XXX see below XXX */ - - /* MSch: old-style reset: actually abort all command processing here */ - - /* After the reset, there are no more connected or disconnected commands - * and no busy units; to avoid problems with re-inserting the commands - * into the issue_queue (via scsi_done()), the aborted commands are - * remembered in local variables first. - */ - local_irq_save(flags); - connected = (Scsi_Cmnd *)hostdata->connected; - hostdata->connected = NULL; - disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue; - hostdata->disconnected_queue = NULL; -#ifdef SUPPORT_TAGS - free_all_tags(); -#endif - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; -#ifdef REAL_DMA - hostdata->dma_len = 0; -#endif - local_irq_restore(flags); - - /* In order to tell the mid-level code which commands were aborted, - * set the command status to DID_RESET and call scsi_done() !!! - * This ultimately aborts processing of these commands in the mid-level. - */ - - if ((cmd = connected)) { - ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); - cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); - cmd->scsi_done(cmd); - } - - for (i = 0; (cmd = disconnected_queue); ++i) { - disconnected_queue = NEXT(cmd); - SET_NEXT(cmd, NULL); - cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); - cmd->scsi_done(cmd); - } - if (i > 0) - ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); - - /* The Falcon lock should be released after a reset... - */ - /* ++guenther: moved to atari_scsi_reset(), to prevent a race between - * unlocking and enabling dma interrupt. - */ -/* falcon_release_lock_if_possible( hostdata );*/ - - /* since all commands have been explicitly terminated, we need to tell - * the midlevel code that the reset was SUCCESSFUL, and there is no - * need to 'wake up' the commands by a request_sense - */ - return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; -#else /* 1 */ - - /* MSch: new-style reset handling: let the mid-level do what it can */ - - /* ++guenther: MID-LEVEL IS STILL BROKEN. - * Mid-level is supposed to requeue all commands that were active on the - * various low-level queues. In fact it does this, but that's not enough - * because all these commands are subject to timeout. And if a timeout - * happens for any removed command, *_abort() is called but all queues - * are now empty. Abort then gives up the falcon lock, which is fatal, - * since the mid-level will queue more commands and must have the lock - * (it's all happening inside timer interrupt handler!!). - * Even worse, abort will return NOT_RUNNING for all those commands not - * on any queue, so they won't be retried ... - * - * Conclusion: either scsi.c disables timeout for all resetted commands - * immediately, or we lose! As of linux-2.0.20 it doesn't. - */ - - /* After the reset, there are no more connected or disconnected commands - * and no busy units; so clear the low-level status here to avoid - * conflicts when the mid-level code tries to wake up the affected - * commands! - */ - - if (hostdata->issue_queue) - ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); - if (hostdata->connected) - ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); - if (hostdata->disconnected_queue) - ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); - - local_irq_save(flags); - hostdata->issue_queue = NULL; - hostdata->connected = NULL; - hostdata->disconnected_queue = NULL; -#ifdef SUPPORT_TAGS - free_all_tags(); -#endif - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; -#ifdef REAL_DMA - hostdata->dma_len = 0; -#endif - local_irq_restore(flags); - - /* we did no complete reset of all commands, so a wakeup is required */ - return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; -#endif /* 1 */ -} diff --git a/ANDROID_3.4.5/drivers/scsi/atari_scsi.c b/ANDROID_3.4.5/drivers/scsi/atari_scsi.c deleted file mode 100644 index 04a154f8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/atari_scsi.c +++ /dev/null @@ -1,1111 +0,0 @@ -/* - * atari_scsi.c -- Device dependent functions for the Atari generic SCSI port - * - * Copyright 1994 Roman Hodek - * - * Loosely based on the work of Robert De Vries' team and added: - * - working real DMA - * - Falcon support (untested yet!) ++bjoern fixed and now it works - * - lots of extensions and bug fixes. - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - */ - - -/**************************************************************************/ -/* */ -/* Notes for Falcon SCSI: */ -/* ---------------------- */ -/* */ -/* Since the Falcon SCSI uses the ST-DMA chip, that is shared among */ -/* several device drivers, locking and unlocking the access to this */ -/* chip is required. But locking is not possible from an interrupt, */ -/* since it puts the process to sleep if the lock is not available. */ -/* This prevents "late" locking of the DMA chip, i.e. locking it just */ -/* before using it, since in case of disconnection-reconnection */ -/* commands, the DMA is started from the reselection interrupt. */ -/* */ -/* Two possible schemes for ST-DMA-locking would be: */ -/* 1) The lock is taken for each command separately and disconnecting */ -/* is forbidden (i.e. can_queue = 1). */ -/* 2) The DMA chip is locked when the first command comes in and */ -/* released when the last command is finished and all queues are */ -/* empty. */ -/* The first alternative would result in bad performance, since the */ -/* interleaving of commands would not be used. The second is unfair to */ -/* other drivers using the ST-DMA, because the queues will seldom be */ -/* totally empty if there is a lot of disk traffic. */ -/* */ -/* For this reasons I decided to employ a more elaborate scheme: */ -/* - First, we give up the lock every time we can (for fairness), this */ -/* means every time a command finishes and there are no other commands */ -/* on the disconnected queue. */ -/* - If there are others waiting to lock the DMA chip, we stop */ -/* issuing commands, i.e. moving them onto the issue queue. */ -/* Because of that, the disconnected queue will run empty in a */ -/* while. Instead we go to sleep on a 'fairness_queue'. */ -/* - If the lock is released, all processes waiting on the fairness */ -/* queue will be woken. The first of them tries to re-lock the DMA, */ -/* the others wait for the first to finish this task. After that, */ -/* they can all run on and do their commands... */ -/* This sounds complicated (and it is it :-(), but it seems to be a */ -/* good compromise between fairness and performance: As long as no one */ -/* else wants to work with the ST-DMA chip, SCSI can go along as */ -/* usual. If now someone else comes, this behaviour is changed to a */ -/* "fairness mode": just already initiated commands are finished and */ -/* then the lock is released. The other one waiting will probably win */ -/* the race for locking the DMA, since it was waiting for longer. And */ -/* after it has finished, SCSI can go ahead again. Finally: I hope I */ -/* have not produced any deadlock possibilities! */ -/* */ -/**************************************************************************/ - - - -#include - -#define NDEBUG (0) - -#define NDEBUG_ABORT 0x00100000 -#define NDEBUG_TAGS 0x00200000 -#define NDEBUG_MERGING 0x00400000 - -#define AUTOSENSE -/* For the Atari version, use only polled IO or REAL_DMA */ -#define REAL_DMA -/* Support tagged queuing? (on devices that are able to... :-) */ -#define SUPPORT_TAGS -#define MAX_TAGS 32 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include "atari_scsi.h" -#include "NCR5380.h" -#include -#include -#include - -#include - -#define IS_A_TT() ATARIHW_PRESENT(TT_SCSI) - -#define SCSI_DMA_WRITE_P(elt,val) \ - do { \ - unsigned long v = val; \ - tt_scsi_dma.elt##_lo = v & 0xff; \ - v >>= 8; \ - tt_scsi_dma.elt##_lmd = v & 0xff; \ - v >>= 8; \ - tt_scsi_dma.elt##_hmd = v & 0xff; \ - v >>= 8; \ - tt_scsi_dma.elt##_hi = v & 0xff; \ - } while(0) - -#define SCSI_DMA_READ_P(elt) \ - (((((((unsigned long)tt_scsi_dma.elt##_hi << 8) | \ - (unsigned long)tt_scsi_dma.elt##_hmd) << 8) | \ - (unsigned long)tt_scsi_dma.elt##_lmd) << 8) | \ - (unsigned long)tt_scsi_dma.elt##_lo) - - -static inline void SCSI_DMA_SETADR(unsigned long adr) -{ - st_dma.dma_lo = (unsigned char)adr; - MFPDELAY(); - adr >>= 8; - st_dma.dma_md = (unsigned char)adr; - MFPDELAY(); - adr >>= 8; - st_dma.dma_hi = (unsigned char)adr; - MFPDELAY(); -} - -static inline unsigned long SCSI_DMA_GETADR(void) -{ - unsigned long adr; - adr = st_dma.dma_lo; - MFPDELAY(); - adr |= (st_dma.dma_md & 0xff) << 8; - MFPDELAY(); - adr |= (st_dma.dma_hi & 0xff) << 16; - MFPDELAY(); - return adr; -} - -static inline void ENABLE_IRQ(void) -{ - if (IS_A_TT()) - atari_enable_irq(IRQ_TT_MFP_SCSI); - else - atari_enable_irq(IRQ_MFP_FSCSI); -} - -static inline void DISABLE_IRQ(void) -{ - if (IS_A_TT()) - atari_disable_irq(IRQ_TT_MFP_SCSI); - else - atari_disable_irq(IRQ_MFP_FSCSI); -} - - -#define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \ - (atari_scsi_host->hostdata))->dma_len) - -/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms, - * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more - * need ten times the standard value... */ -#ifndef CONFIG_ATARI_SCSI_TOSHIBA_DELAY -#define AFTER_RESET_DELAY (HZ/2) -#else -#define AFTER_RESET_DELAY (5*HZ/2) -#endif - -/***************************** Prototypes *****************************/ - -#ifdef REAL_DMA -static int scsi_dma_is_ignored_buserr(unsigned char dma_stat); -static void atari_scsi_fetch_restbytes(void); -static long atari_scsi_dma_residual(struct Scsi_Host *instance); -static int falcon_classify_cmd(Scsi_Cmnd *cmd); -static unsigned long atari_dma_xfer_len(unsigned long wanted_len, - Scsi_Cmnd *cmd, int write_flag); -#endif -static irqreturn_t scsi_tt_intr(int irq, void *dummy); -static irqreturn_t scsi_falcon_intr(int irq, void *dummy); -static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata); -static void falcon_get_lock(void); -#ifdef CONFIG_ATARI_SCSI_RESET_BOOT -static void atari_scsi_reset_boot(void); -#endif -static unsigned char atari_scsi_tt_reg_read(unsigned char reg); -static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value); -static unsigned char atari_scsi_falcon_reg_read(unsigned char reg); -static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value); - -/************************* End of Prototypes **************************/ - - -static struct Scsi_Host *atari_scsi_host; -static unsigned char (*atari_scsi_reg_read)(unsigned char reg); -static void (*atari_scsi_reg_write)(unsigned char reg, unsigned char value); - -#ifdef REAL_DMA -static unsigned long atari_dma_residual, atari_dma_startaddr; -static short atari_dma_active; -/* pointer to the dribble buffer */ -static char *atari_dma_buffer; -/* precalculated physical address of the dribble buffer */ -static unsigned long atari_dma_phys_buffer; -/* != 0 tells the Falcon int handler to copy data from the dribble buffer */ -static char *atari_dma_orig_addr; -/* size of the dribble buffer; 4k seems enough, since the Falcon cannot use - * scatter-gather anyway, so most transfers are 1024 byte only. In the rare - * cases where requests to physical contiguous buffers have been merged, this - * request is <= 4k (one page). So I don't think we have to split transfers - * just due to this buffer size... - */ -#define STRAM_BUFFER_SIZE (4096) -/* mask for address bits that can't be used with the ST-DMA */ -static unsigned long atari_dma_stram_mask; -#define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0) -/* number of bytes to cut from a transfer to handle NCR overruns */ -static int atari_read_overruns; -#endif - -static int setup_can_queue = -1; -module_param(setup_can_queue, int, 0); -static int setup_cmd_per_lun = -1; -module_param(setup_cmd_per_lun, int, 0); -static int setup_sg_tablesize = -1; -module_param(setup_sg_tablesize, int, 0); -#ifdef SUPPORT_TAGS -static int setup_use_tagged_queuing = -1; -module_param(setup_use_tagged_queuing, int, 0); -#endif -static int setup_hostid = -1; -module_param(setup_hostid, int, 0); - - -#if defined(REAL_DMA) - -static int scsi_dma_is_ignored_buserr(unsigned char dma_stat) -{ - int i; - unsigned long addr = SCSI_DMA_READ_P(dma_addr), end_addr; - - if (dma_stat & 0x01) { - - /* A bus error happens when DMA-ing from the last page of a - * physical memory chunk (DMA prefetch!), but that doesn't hurt. - * Check for this case: - */ - - for (i = 0; i < m68k_num_memory; ++i) { - end_addr = m68k_memory[i].addr + m68k_memory[i].size; - if (end_addr <= addr && addr <= end_addr + 4) - return 1; - } - } - return 0; -} - - -#if 0 -/* Dead code... wasn't called anyway :-) and causes some trouble, because at - * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has - * to clear the DMA int pending bit before it allows other level 6 interrupts. - */ -static void scsi_dma_buserr(int irq, void *dummy) -{ - unsigned char dma_stat = tt_scsi_dma.dma_ctrl; - - /* Don't do anything if a NCR interrupt is pending. Probably it's just - * masked... */ - if (atari_irq_pending(IRQ_TT_MFP_SCSI)) - return; - - printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n", - SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt)); - if (dma_stat & 0x80) { - if (!scsi_dma_is_ignored_buserr(dma_stat)) - printk("SCSI DMA bus error -- bad DMA programming!\n"); - } else { - /* Under normal circumstances we never should get to this point, - * since both interrupts are triggered simultaneously and the 5380 - * int has higher priority. When this irq is handled, that DMA - * interrupt is cleared. So a warning message is printed here. - */ - printk("SCSI DMA intr ?? -- this shouldn't happen!\n"); - } -} -#endif - -#endif - - -static irqreturn_t scsi_tt_intr(int irq, void *dummy) -{ -#ifdef REAL_DMA - int dma_stat; - - dma_stat = tt_scsi_dma.dma_ctrl; - - INT_PRINTK("scsi%d: NCR5380 interrupt, DMA status = %02x\n", - atari_scsi_host->host_no, dma_stat & 0xff); - - /* Look if it was the DMA that has interrupted: First possibility - * is that a bus error occurred... - */ - if (dma_stat & 0x80) { - if (!scsi_dma_is_ignored_buserr(dma_stat)) { - printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n", - SCSI_DMA_READ_P(dma_addr)); - printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!"); - } - } - - /* If the DMA is active but not finished, we have the case - * that some other 5380 interrupt occurred within the DMA transfer. - * This means we have residual bytes, if the desired end address - * is not yet reached. Maybe we have to fetch some bytes from the - * rest data register, too. The residual must be calculated from - * the address pointer, not the counter register, because only the - * addr reg counts bytes not yet written and pending in the rest - * data reg! - */ - if ((dma_stat & 0x02) && !(dma_stat & 0x40)) { - atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P(dma_addr) - atari_dma_startaddr); - - DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", - atari_dma_residual); - - if ((signed int)atari_dma_residual < 0) - atari_dma_residual = 0; - if ((dma_stat & 1) == 0) { - /* - * After read operations, we maybe have to - * transport some rest bytes - */ - atari_scsi_fetch_restbytes(); - } else { - /* - * There seems to be a nasty bug in some SCSI-DMA/NCR - * combinations: If a target disconnects while a write - * operation is going on, the address register of the - * DMA may be a few bytes farer than it actually read. - * This is probably due to DMA prefetching and a delay - * between DMA and NCR. Experiments showed that the - * dma_addr is 9 bytes to high, but this could vary. - * The problem is, that the residual is thus calculated - * wrong and the next transfer will start behind where - * it should. So we round up the residual to the next - * multiple of a sector size, if it isn't already a - * multiple and the originally expected transfer size - * was. The latter condition is there to ensure that - * the correction is taken only for "real" data - * transfers and not for, e.g., the parameters of some - * other command. These shouldn't disconnect anyway. - */ - if (atari_dma_residual & 0x1ff) { - DMA_PRINTK("SCSI DMA: DMA bug corrected, " - "difference %ld bytes\n", - 512 - (atari_dma_residual & 0x1ff)); - atari_dma_residual = (atari_dma_residual + 511) & ~0x1ff; - } - } - tt_scsi_dma.dma_ctrl = 0; - } - - /* If the DMA is finished, fetch the rest bytes and turn it off */ - if (dma_stat & 0x40) { - atari_dma_residual = 0; - if ((dma_stat & 1) == 0) - atari_scsi_fetch_restbytes(); - tt_scsi_dma.dma_ctrl = 0; - } - -#endif /* REAL_DMA */ - - NCR5380_intr(irq, dummy); - -#if 0 - /* To be sure the int is not masked */ - atari_enable_irq(IRQ_TT_MFP_SCSI); -#endif - return IRQ_HANDLED; -} - - -static irqreturn_t scsi_falcon_intr(int irq, void *dummy) -{ -#ifdef REAL_DMA - int dma_stat; - - /* Turn off DMA and select sector counter register before - * accessing the status register (Atari recommendation!) - */ - st_dma.dma_mode_status = 0x90; - dma_stat = st_dma.dma_mode_status; - - /* Bit 0 indicates some error in the DMA process... don't know - * what happened exactly (no further docu). - */ - if (!(dma_stat & 0x01)) { - /* DMA error */ - printk(KERN_CRIT "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR()); - } - - /* If the DMA was active, but now bit 1 is not clear, it is some - * other 5380 interrupt that finishes the DMA transfer. We have to - * calculate the number of residual bytes and give a warning if - * bytes are stuck in the ST-DMA fifo (there's no way to reach them!) - */ - if (atari_dma_active && (dma_stat & 0x02)) { - unsigned long transferred; - - transferred = SCSI_DMA_GETADR() - atari_dma_startaddr; - /* The ST-DMA address is incremented in 2-byte steps, but the - * data are written only in 16-byte chunks. If the number of - * transferred bytes is not divisible by 16, the remainder is - * lost somewhere in outer space. - */ - if (transferred & 15) - printk(KERN_ERR "SCSI DMA error: %ld bytes lost in " - "ST-DMA fifo\n", transferred & 15); - - atari_dma_residual = HOSTDATA_DMALEN - transferred; - DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n", - atari_dma_residual); - } else - atari_dma_residual = 0; - atari_dma_active = 0; - - if (atari_dma_orig_addr) { - /* If the dribble buffer was used on a read operation, copy the DMA-ed - * data to the original destination address. - */ - memcpy(atari_dma_orig_addr, phys_to_virt(atari_dma_startaddr), - HOSTDATA_DMALEN - atari_dma_residual); - atari_dma_orig_addr = NULL; - } - -#endif /* REAL_DMA */ - - NCR5380_intr(irq, dummy); - return IRQ_HANDLED; -} - - -#ifdef REAL_DMA -static void atari_scsi_fetch_restbytes(void) -{ - int nr; - char *src, *dst; - unsigned long phys_dst; - - /* fetch rest bytes in the DMA register */ - phys_dst = SCSI_DMA_READ_P(dma_addr); - nr = phys_dst & 3; - if (nr) { - /* there are 'nr' bytes left for the last long address - before the DMA pointer */ - phys_dst ^= nr; - DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx", - nr, phys_dst); - /* The content of the DMA pointer is a physical address! */ - dst = phys_to_virt(phys_dst); - DMA_PRINTK(" = virt addr %p\n", dst); - for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr) - *dst++ = *src++; - } -} -#endif /* REAL_DMA */ - - -static int falcon_got_lock = 0; -static DECLARE_WAIT_QUEUE_HEAD(falcon_fairness_wait); -static int falcon_trying_lock = 0; -static DECLARE_WAIT_QUEUE_HEAD(falcon_try_wait); -static int falcon_dont_release = 0; - -/* This function releases the lock on the DMA chip if there is no - * connected command and the disconnected queue is empty. On - * releasing, instances of falcon_get_lock are awoken, that put - * themselves to sleep for fairness. They can now try to get the lock - * again (but others waiting longer more probably will win). - */ - -static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata) -{ - unsigned long flags; - - if (IS_A_TT()) - return; - - local_irq_save(flags); - - if (falcon_got_lock && !hostdata->disconnected_queue && - !hostdata->issue_queue && !hostdata->connected) { - - if (falcon_dont_release) { -#if 0 - printk("WARNING: Lock release not allowed. Ignored\n"); -#endif - local_irq_restore(flags); - return; - } - falcon_got_lock = 0; - stdma_release(); - wake_up(&falcon_fairness_wait); - } - - local_irq_restore(flags); -} - -/* This function manages the locking of the ST-DMA. - * If the DMA isn't locked already for SCSI, it tries to lock it by - * calling stdma_lock(). But if the DMA is locked by the SCSI code and - * there are other drivers waiting for the chip, we do not issue the - * command immediately but wait on 'falcon_fairness_queue'. We will be - * waked up when the DMA is unlocked by some SCSI interrupt. After that - * we try to get the lock again. - * But we must be prepared that more than one instance of - * falcon_get_lock() is waiting on the fairness queue. They should not - * try all at once to call stdma_lock(), one is enough! For that, the - * first one sets 'falcon_trying_lock', others that see that variable - * set wait on the queue 'falcon_try_wait'. - * Complicated, complicated.... Sigh... - */ - -static void falcon_get_lock(void) -{ - unsigned long flags; - - if (IS_A_TT()) - return; - - local_irq_save(flags); - - while (!in_irq() && falcon_got_lock && stdma_others_waiting()) - sleep_on(&falcon_fairness_wait); - - while (!falcon_got_lock) { - if (in_irq()) - panic("Falcon SCSI hasn't ST-DMA lock in interrupt"); - if (!falcon_trying_lock) { - falcon_trying_lock = 1; - stdma_lock(scsi_falcon_intr, NULL); - falcon_got_lock = 1; - falcon_trying_lock = 0; - wake_up(&falcon_try_wait); - } else { - sleep_on(&falcon_try_wait); - } - } - - local_irq_restore(flags); - if (!falcon_got_lock) - panic("Falcon SCSI: someone stole the lock :-(\n"); -} - - -int __init atari_scsi_detect(struct scsi_host_template *host) -{ - static int called = 0; - struct Scsi_Host *instance; - - if (!MACH_IS_ATARI || - (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) || - called) - return 0; - - host->proc_name = "Atari"; - - atari_scsi_reg_read = IS_A_TT() ? atari_scsi_tt_reg_read : - atari_scsi_falcon_reg_read; - atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write : - atari_scsi_falcon_reg_write; - - /* setup variables */ - host->can_queue = - (setup_can_queue > 0) ? setup_can_queue : - IS_A_TT() ? ATARI_TT_CAN_QUEUE : ATARI_FALCON_CAN_QUEUE; - host->cmd_per_lun = - (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : - IS_A_TT() ? ATARI_TT_CMD_PER_LUN : ATARI_FALCON_CMD_PER_LUN; - /* Force sg_tablesize to 0 on a Falcon! */ - host->sg_tablesize = - !IS_A_TT() ? ATARI_FALCON_SG_TABLESIZE : - (setup_sg_tablesize >= 0) ? setup_sg_tablesize : ATARI_TT_SG_TABLESIZE; - - if (setup_hostid >= 0) - host->this_id = setup_hostid; - else { - /* use 7 as default */ - host->this_id = 7; - /* Test if a host id is set in the NVRam */ - if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) { - unsigned char b = nvram_read_byte( 14 ); - /* Arbitration enabled? (for TOS) If yes, use configured host ID */ - if (b & 0x80) - host->this_id = b & 7; - } - } - -#ifdef SUPPORT_TAGS - if (setup_use_tagged_queuing < 0) - setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING; -#endif -#ifdef REAL_DMA - /* If running on a Falcon and if there's TT-Ram (i.e., more than one - * memory block, since there's always ST-Ram in a Falcon), then allocate a - * STRAM_BUFFER_SIZE byte dribble buffer for transfers from/to alternative - * Ram. - */ - if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) && - !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) { - atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI"); - if (!atari_dma_buffer) { - printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM " - "double buffer\n"); - return 0; - } - atari_dma_phys_buffer = virt_to_phys(atari_dma_buffer); - atari_dma_orig_addr = 0; - } -#endif - instance = scsi_register(host, sizeof(struct NCR5380_hostdata)); - if (instance == NULL) { - atari_stram_free(atari_dma_buffer); - atari_dma_buffer = 0; - return 0; - } - atari_scsi_host = instance; - /* - * Set irq to 0, to avoid that the mid-level code disables our interrupt - * during queue_command calls. This is completely unnecessary, and even - * worse causes bad problems on the Falcon, where the int is shared with - * IDE and floppy! - */ - instance->irq = 0; - -#ifdef CONFIG_ATARI_SCSI_RESET_BOOT - atari_scsi_reset_boot(); -#endif - NCR5380_init(instance, 0); - - if (IS_A_TT()) { - - /* This int is actually "pseudo-slow", i.e. it acts like a slow - * interrupt after having cleared the pending flag for the DMA - * interrupt. */ - if (request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW, - "SCSI NCR5380", instance)) { - printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting",IRQ_TT_MFP_SCSI); - scsi_unregister(atari_scsi_host); - atari_stram_free(atari_dma_buffer); - atari_dma_buffer = 0; - return 0; - } - tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */ -#ifdef REAL_DMA - tt_scsi_dma.dma_ctrl = 0; - atari_dma_residual = 0; - - if (MACH_IS_MEDUSA) { - /* While the read overruns (described by Drew Eckhardt in - * NCR5380.c) never happened on TTs, they do in fact on the Medusa - * (This was the cause why SCSI didn't work right for so long - * there.) Since handling the overruns slows down a bit, I turned - * the #ifdef's into a runtime condition. - * - * In principle it should be sufficient to do max. 1 byte with - * PIO, but there is another problem on the Medusa with the DMA - * rest data register. So 'atari_read_overruns' is currently set - * to 4 to avoid having transfers that aren't a multiple of 4. If - * the rest data bug is fixed, this can be lowered to 1. - */ - atari_read_overruns = 4; - } -#endif /*REAL_DMA*/ - } else { /* ! IS_A_TT */ - - /* Nothing to do for the interrupt: the ST-DMA is initialized - * already by atari_init_INTS() - */ - -#ifdef REAL_DMA - atari_dma_residual = 0; - atari_dma_active = 0; - atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000 - : 0xff000000); -#endif - } - - printk(KERN_INFO "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d " -#ifdef SUPPORT_TAGS - "TAGGED-QUEUING=%s " -#endif - "HOSTID=%d", - instance->host_no, instance->hostt->can_queue, - instance->hostt->cmd_per_lun, - instance->hostt->sg_tablesize, -#ifdef SUPPORT_TAGS - setup_use_tagged_queuing ? "yes" : "no", -#endif - instance->hostt->this_id ); - NCR5380_print_options(instance); - printk("\n"); - - called = 1; - return 1; -} - -int atari_scsi_release(struct Scsi_Host *sh) -{ - if (IS_A_TT()) - free_irq(IRQ_TT_MFP_SCSI, sh); - if (atari_dma_buffer) - atari_stram_free(atari_dma_buffer); - NCR5380_exit(sh); - return 1; -} - -void __init atari_scsi_setup(char *str, int *ints) -{ - /* Format of atascsi parameter is: - * atascsi=,,,, - * Defaults depend on TT or Falcon, hostid determined at run time. - * Negative values mean don't change. - */ - - if (ints[0] < 1) { - printk("atari_scsi_setup: no arguments!\n"); - return; - } - - if (ints[0] >= 1) { - if (ints[1] > 0) - /* no limits on this, just > 0 */ - setup_can_queue = ints[1]; - } - if (ints[0] >= 2) { - if (ints[2] > 0) - setup_cmd_per_lun = ints[2]; - } - if (ints[0] >= 3) { - if (ints[3] >= 0) { - setup_sg_tablesize = ints[3]; - /* Must be <= SG_ALL (255) */ - if (setup_sg_tablesize > SG_ALL) - setup_sg_tablesize = SG_ALL; - } - } - if (ints[0] >= 4) { - /* Must be between 0 and 7 */ - if (ints[4] >= 0 && ints[4] <= 7) - setup_hostid = ints[4]; - else if (ints[4] > 7) - printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]); - } -#ifdef SUPPORT_TAGS - if (ints[0] >= 5) { - if (ints[5] >= 0) - setup_use_tagged_queuing = !!ints[5]; - } -#endif -} - -int atari_scsi_bus_reset(Scsi_Cmnd *cmd) -{ - int rv; - struct NCR5380_hostdata *hostdata = - (struct NCR5380_hostdata *)cmd->device->host->hostdata; - - /* For doing the reset, SCSI interrupts must be disabled first, - * since the 5380 raises its IRQ line while _RST is active and we - * can't disable interrupts completely, since we need the timer. - */ - /* And abort a maybe active DMA transfer */ - if (IS_A_TT()) { - atari_turnoff_irq(IRQ_TT_MFP_SCSI); -#ifdef REAL_DMA - tt_scsi_dma.dma_ctrl = 0; -#endif /* REAL_DMA */ - } else { - atari_turnoff_irq(IRQ_MFP_FSCSI); -#ifdef REAL_DMA - st_dma.dma_mode_status = 0x90; - atari_dma_active = 0; - atari_dma_orig_addr = NULL; -#endif /* REAL_DMA */ - } - - rv = NCR5380_bus_reset(cmd); - - /* Re-enable ints */ - if (IS_A_TT()) { - atari_turnon_irq(IRQ_TT_MFP_SCSI); - } else { - atari_turnon_irq(IRQ_MFP_FSCSI); - } - if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS) - falcon_release_lock_if_possible(hostdata); - - return rv; -} - - -#ifdef CONFIG_ATARI_SCSI_RESET_BOOT -static void __init atari_scsi_reset_boot(void) -{ - unsigned long end; - - /* - * Do a SCSI reset to clean up the bus during initialization. No messing - * with the queues, interrupts, or locks necessary here. - */ - - printk("Atari SCSI: resetting the SCSI bus..."); - - /* get in phase */ - NCR5380_write(TARGET_COMMAND_REG, - PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG))); - - /* assert RST */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); - /* The min. reset hold time is 25us, so 40us should be enough */ - udelay(50); - /* reset RST and interrupt */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - - end = jiffies + AFTER_RESET_DELAY; - while (time_before(jiffies, end)) - barrier(); - - printk(" done\n"); -} -#endif - - -const char *atari_scsi_info(struct Scsi_Host *host) -{ - /* atari_scsi_detect() is verbose enough... */ - static const char string[] = "Atari native SCSI"; - return string; -} - - -#if defined(REAL_DMA) - -unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance, void *data, - unsigned long count, int dir) -{ - unsigned long addr = virt_to_phys(data); - - DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, " - "dir = %d\n", instance->host_no, data, addr, count, dir); - - if (!IS_A_TT() && !STRAM_ADDR(addr)) { - /* If we have a non-DMAable address on a Falcon, use the dribble - * buffer; 'orig_addr' != 0 in the read case tells the interrupt - * handler to copy data from the dribble buffer to the originally - * wanted address. - */ - if (dir) - memcpy(atari_dma_buffer, data, count); - else - atari_dma_orig_addr = data; - addr = atari_dma_phys_buffer; - } - - atari_dma_startaddr = addr; /* Needed for calculating residual later. */ - - /* Cache cleanup stuff: On writes, push any dirty cache out before sending - * it to the peripheral. (Must be done before DMA setup, since at least - * the ST-DMA begins to fill internal buffers right after setup. For - * reads, invalidate any cache, may be altered after DMA without CPU - * knowledge. - * - * ++roman: For the Medusa, there's no need at all for that cache stuff, - * because the hardware does bus snooping (fine!). - */ - dma_cache_maintenance(addr, count, dir); - - if (count == 0) - printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n"); - - if (IS_A_TT()) { - tt_scsi_dma.dma_ctrl = dir; - SCSI_DMA_WRITE_P(dma_addr, addr); - SCSI_DMA_WRITE_P(dma_cnt, count); - tt_scsi_dma.dma_ctrl = dir | 2; - } else { /* ! IS_A_TT */ - - /* set address */ - SCSI_DMA_SETADR(addr); - - /* toggle direction bit to clear FIFO and set DMA direction */ - dir <<= 8; - st_dma.dma_mode_status = 0x90 | dir; - st_dma.dma_mode_status = 0x90 | (dir ^ 0x100); - st_dma.dma_mode_status = 0x90 | dir; - udelay(40); - /* On writes, round up the transfer length to the next multiple of 512 - * (see also comment at atari_dma_xfer_len()). */ - st_dma.fdc_acces_seccount = (count + (dir ? 511 : 0)) >> 9; - udelay(40); - st_dma.dma_mode_status = 0x10 | dir; - udelay(40); - /* need not restore value of dir, only boolean value is tested */ - atari_dma_active = 1; - } - - return count; -} - - -static long atari_scsi_dma_residual(struct Scsi_Host *instance) -{ - return atari_dma_residual; -} - - -#define CMD_SURELY_BLOCK_MODE 0 -#define CMD_SURELY_BYTE_MODE 1 -#define CMD_MODE_UNKNOWN 2 - -static int falcon_classify_cmd(Scsi_Cmnd *cmd) -{ - unsigned char opcode = cmd->cmnd[0]; - - if (opcode == READ_DEFECT_DATA || opcode == READ_LONG || - opcode == READ_BUFFER) - return CMD_SURELY_BYTE_MODE; - else if (opcode == READ_6 || opcode == READ_10 || - opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE || - opcode == RECOVER_BUFFERED_DATA) { - /* In case of a sequential-access target (tape), special care is - * needed here: The transfer is block-mode only if the 'fixed' bit is - * set! */ - if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1)) - return CMD_SURELY_BYTE_MODE; - else - return CMD_SURELY_BLOCK_MODE; - } else - return CMD_MODE_UNKNOWN; -} - - -/* This function calculates the number of bytes that can be transferred via - * DMA. On the TT, this is arbitrary, but on the Falcon we have to use the - * ST-DMA chip. There are only multiples of 512 bytes possible and max. - * 255*512 bytes :-( This means also, that defining READ_OVERRUNS is not - * possible on the Falcon, since that would require to program the DMA for - * n*512 - atari_read_overrun bytes. But it seems that the Falcon doesn't have - * the overrun problem, so this question is academic :-) - */ - -static unsigned long atari_dma_xfer_len(unsigned long wanted_len, - Scsi_Cmnd *cmd, int write_flag) -{ - unsigned long possible_len, limit; - - if (IS_A_TT()) - /* TT SCSI DMA can transfer arbitrary #bytes */ - return wanted_len; - - /* ST DMA chip is stupid -- only multiples of 512 bytes! (and max. - * 255*512 bytes, but this should be enough) - * - * ++roman: Aaargl! Another Falcon-SCSI problem... There are some commands - * that return a number of bytes which cannot be known beforehand. In this - * case, the given transfer length is an "allocation length". Now it - * can happen that this allocation length is a multiple of 512 bytes and - * the DMA is used. But if not n*512 bytes really arrive, some input data - * will be lost in the ST-DMA's FIFO :-( Thus, we have to distinguish - * between commands that do block transfers and those that do byte - * transfers. But this isn't easy... there are lots of vendor specific - * commands, and the user can issue any command via the - * SCSI_IOCTL_SEND_COMMAND. - * - * The solution: We classify SCSI commands in 1) surely block-mode cmd.s, - * 2) surely byte-mode cmd.s and 3) cmd.s with unknown mode. In case 1) - * and 3), the thing to do is obvious: allow any number of blocks via DMA - * or none. In case 2), we apply some heuristic: Byte mode is assumed if - * the transfer (allocation) length is < 1024, hoping that no cmd. not - * explicitly known as byte mode have such big allocation lengths... - * BTW, all the discussion above applies only to reads. DMA writes are - * unproblematic anyways, since the targets aborts the transfer after - * receiving a sufficient number of bytes. - * - * Another point: If the transfer is from/to an non-ST-RAM address, we - * use the dribble buffer and thus can do only STRAM_BUFFER_SIZE bytes. - */ - - if (write_flag) { - /* Write operation can always use the DMA, but the transfer size must - * be rounded up to the next multiple of 512 (atari_dma_setup() does - * this). - */ - possible_len = wanted_len; - } else { - /* Read operations: if the wanted transfer length is not a multiple of - * 512, we cannot use DMA, since the ST-DMA cannot split transfers - * (no interrupt on DMA finished!) - */ - if (wanted_len & 0x1ff) - possible_len = 0; - else { - /* Now classify the command (see above) and decide whether it is - * allowed to do DMA at all */ - switch (falcon_classify_cmd(cmd)) { - case CMD_SURELY_BLOCK_MODE: - possible_len = wanted_len; - break; - case CMD_SURELY_BYTE_MODE: - possible_len = 0; /* DMA prohibited */ - break; - case CMD_MODE_UNKNOWN: - default: - /* For unknown commands assume block transfers if the transfer - * size/allocation length is >= 1024 */ - possible_len = (wanted_len < 1024) ? 0 : wanted_len; - break; - } - } - } - - /* Last step: apply the hard limit on DMA transfers */ - limit = (atari_dma_buffer && !STRAM_ADDR(virt_to_phys(cmd->SCp.ptr))) ? - STRAM_BUFFER_SIZE : 255*512; - if (possible_len > limit) - possible_len = limit; - - if (possible_len != wanted_len) - DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes " - "instead of %ld\n", possible_len, wanted_len); - - return possible_len; -} - - -#endif /* REAL_DMA */ - - -/* NCR5380 register access functions - * - * There are separate functions for TT and Falcon, because the access - * methods are quite different. The calling macros NCR5380_read and - * NCR5380_write call these functions via function pointers. - */ - -static unsigned char atari_scsi_tt_reg_read(unsigned char reg) -{ - return tt_scsi_regp[reg * 2]; -} - -static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value) -{ - tt_scsi_regp[reg * 2] = value; -} - -static unsigned char atari_scsi_falcon_reg_read(unsigned char reg) -{ - dma_wd.dma_mode_status= (u_short)(0x88 + reg); - return (u_char)dma_wd.fdc_acces_seccount; -} - -static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value) -{ - dma_wd.dma_mode_status = (u_short)(0x88 + reg); - dma_wd.fdc_acces_seccount = (u_short)value; -} - - -#include "atari_NCR5380.c" - -static struct scsi_host_template driver_template = { - .proc_info = atari_scsi_proc_info, - .name = "Atari native SCSI", - .detect = atari_scsi_detect, - .release = atari_scsi_release, - .info = atari_scsi_info, - .queuecommand = atari_scsi_queue_command, - .eh_abort_handler = atari_scsi_abort, - .eh_bus_reset_handler = atari_scsi_bus_reset, - .can_queue = 0, /* initialized at run-time */ - .this_id = 0, /* initialized at run-time */ - .sg_tablesize = 0, /* initialized at run-time */ - .cmd_per_lun = 0, /* initialized at run-time */ - .use_clustering = DISABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/atari_scsi.h b/ANDROID_3.4.5/drivers/scsi/atari_scsi.h deleted file mode 100644 index efadb8d5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/atari_scsi.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * atari_scsi.h -- Header file for the Atari native SCSI driver - * - * Copyright 1994 Roman Hodek - * - * (Loosely based on the work of Robert De Vries' team) - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - */ - - -#ifndef ATARI_SCSI_H -#define ATARI_SCSI_H - -/* (I_HAVE_OVERRUNS stuff removed) */ - -#ifndef ASM -int atari_scsi_detect (struct scsi_host_template *); -const char *atari_scsi_info (struct Scsi_Host *); -int atari_scsi_reset (Scsi_Cmnd *, unsigned int); -int atari_scsi_release (struct Scsi_Host *); - -/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher - * values should work, too; try it! (but cmd_per_lun costs memory!) */ - -/* But there seems to be a bug somewhere that requires CAN_QUEUE to be - * 2*CMD_PER_LUN. At least on a TT, no spurious timeouts seen since - * changed CMD_PER_LUN... */ - -/* Note: The Falcon currently uses 8/1 setting due to unsolved problems with - * cmd_per_lun != 1 */ - -#define ATARI_TT_CAN_QUEUE 16 -#define ATARI_TT_CMD_PER_LUN 8 -#define ATARI_TT_SG_TABLESIZE SG_ALL - -#define ATARI_FALCON_CAN_QUEUE 8 -#define ATARI_FALCON_CMD_PER_LUN 1 -#define ATARI_FALCON_SG_TABLESIZE SG_NONE - -#define DEFAULT_USE_TAGGED_QUEUING 0 - - -#define NCR5380_implementation_fields /* none */ - -#define NCR5380_read(reg) atari_scsi_reg_read( reg ) -#define NCR5380_write(reg, value) atari_scsi_reg_write( reg, value ) - -#define NCR5380_intr atari_scsi_intr -#define NCR5380_queue_command atari_scsi_queue_command -#define NCR5380_abort atari_scsi_abort -#define NCR5380_proc_info atari_scsi_proc_info -#define NCR5380_dma_read_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 0) -#define NCR5380_dma_write_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 1) -#define NCR5380_dma_residual(inst) atari_scsi_dma_residual( inst ) -#define NCR5380_dma_xfer_len(i,cmd,phase) \ - atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1) - -/* former generic SCSI error handling stuff */ - -#define SCSI_ABORT_SNOOZE 0 -#define SCSI_ABORT_SUCCESS 1 -#define SCSI_ABORT_PENDING 2 -#define SCSI_ABORT_BUSY 3 -#define SCSI_ABORT_NOT_RUNNING 4 -#define SCSI_ABORT_ERROR 5 - -#define SCSI_RESET_SNOOZE 0 -#define SCSI_RESET_PUNT 1 -#define SCSI_RESET_SUCCESS 2 -#define SCSI_RESET_PENDING 3 -#define SCSI_RESET_WAKEUP 4 -#define SCSI_RESET_NOT_RUNNING 5 -#define SCSI_RESET_ERROR 6 - -#define SCSI_RESET_SYNCHRONOUS 0x01 -#define SCSI_RESET_ASYNCHRONOUS 0x02 -#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 -#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 - -#define SCSI_RESET_BUS_RESET 0x100 -#define SCSI_RESET_HOST_RESET 0x200 -#define SCSI_RESET_ACTION 0xff - -/* Debugging printk definitions: - * - * ARB -> arbitration - * ASEN -> auto-sense - * DMA -> DMA - * HSH -> PIO handshake - * INF -> information transfer - * INI -> initialization - * INT -> interrupt - * LNK -> linked commands - * MAIN -> NCR5380_main() control flow - * NDAT -> no data-out phase - * NWR -> no write commands - * PIO -> PIO transfers - * PDMA -> pseudo DMA (unused on Atari) - * QU -> queues - * RSL -> reselections - * SEL -> selections - * USL -> usleep cpde (unused on Atari) - * LBS -> last byte sent (unused on Atari) - * RSS -> restarting of selections - * EXT -> extended messages - * ABRT -> aborting and resetting - * TAG -> queue tag handling - * MER -> merging of consec. buffers - * - */ - -#define dprint(flg, format...) \ -({ \ - if (NDEBUG & (flg)) \ - printk(KERN_DEBUG format); \ -}) - -#define ARB_PRINTK(format, args...) \ - dprint(NDEBUG_ARBITRATION, format , ## args) -#define ASEN_PRINTK(format, args...) \ - dprint(NDEBUG_AUTOSENSE, format , ## args) -#define DMA_PRINTK(format, args...) \ - dprint(NDEBUG_DMA, format , ## args) -#define HSH_PRINTK(format, args...) \ - dprint(NDEBUG_HANDSHAKE, format , ## args) -#define INF_PRINTK(format, args...) \ - dprint(NDEBUG_INFORMATION, format , ## args) -#define INI_PRINTK(format, args...) \ - dprint(NDEBUG_INIT, format , ## args) -#define INT_PRINTK(format, args...) \ - dprint(NDEBUG_INTR, format , ## args) -#define LNK_PRINTK(format, args...) \ - dprint(NDEBUG_LINKED, format , ## args) -#define MAIN_PRINTK(format, args...) \ - dprint(NDEBUG_MAIN, format , ## args) -#define NDAT_PRINTK(format, args...) \ - dprint(NDEBUG_NO_DATAOUT, format , ## args) -#define NWR_PRINTK(format, args...) \ - dprint(NDEBUG_NO_WRITE, format , ## args) -#define PIO_PRINTK(format, args...) \ - dprint(NDEBUG_PIO, format , ## args) -#define PDMA_PRINTK(format, args...) \ - dprint(NDEBUG_PSEUDO_DMA, format , ## args) -#define QU_PRINTK(format, args...) \ - dprint(NDEBUG_QUEUES, format , ## args) -#define RSL_PRINTK(format, args...) \ - dprint(NDEBUG_RESELECTION, format , ## args) -#define SEL_PRINTK(format, args...) \ - dprint(NDEBUG_SELECTION, format , ## args) -#define USL_PRINTK(format, args...) \ - dprint(NDEBUG_USLEEP, format , ## args) -#define LBS_PRINTK(format, args...) \ - dprint(NDEBUG_LAST_BYTE_SENT, format , ## args) -#define RSS_PRINTK(format, args...) \ - dprint(NDEBUG_RESTART_SELECT, format , ## args) -#define EXT_PRINTK(format, args...) \ - dprint(NDEBUG_EXTENDED, format , ## args) -#define ABRT_PRINTK(format, args...) \ - dprint(NDEBUG_ABORT, format , ## args) -#define TAG_PRINTK(format, args...) \ - dprint(NDEBUG_TAGS, format , ## args) -#define MER_PRINTK(format, args...) \ - dprint(NDEBUG_MERGING, format , ## args) - -/* conditional macros for NCR5380_print_{,phase,status} */ - -#define NCR_PRINT(mask) \ - ((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0) - -#define NCR_PRINT_PHASE(mask) \ - ((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0) - -#define NCR_PRINT_STATUS(mask) \ - ((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0) - - -#endif /* ndef ASM */ -#endif /* ATARI_SCSI_H */ - - diff --git a/ANDROID_3.4.5/drivers/scsi/atp870u.c b/ANDROID_3.4.5/drivers/scsi/atp870u.c deleted file mode 100644 index 68ce0855..00000000 --- a/ANDROID_3.4.5/drivers/scsi/atp870u.c +++ /dev/null @@ -1,3915 +0,0 @@ -/* - * Copyright (C) 1997 Wu Ching Chen - * 2.1.x update (C) 1998 Krzysztof G. Baranowski - * 2.5.x update (C) 2002 Red Hat - * 2.6.x update (C) 2004 Red Hat - * - * Marcelo Tosatti : SMP fixes - * - * Wu Ching Chen : NULL pointer fixes 2000/06/02 - * support atp876 chip - * enable 32 bit fifo transfer - * support cdrom & remove device run ultra speed - * fix disconnect bug 2000/12/21 - * support atp880 chip lvd u160 2001/05/15 - * fix prd table bug 2001/09/12 (7.1) - * - * atp885 support add by ACARD Hao Ping Lian 2005/01/05 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "atp870u.h" - -static struct scsi_host_template atp870u_template; -static void send_s870(struct atp_unit *dev,unsigned char c); -static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c); -static void tscam_885(void); - -static irqreturn_t atp870u_intr_handle(int irq, void *dev_id) -{ - unsigned long flags; - unsigned short int tmpcip, id; - unsigned char i, j, c, target_id, lun,cmdp; - unsigned char *prd; - struct scsi_cmnd *workreq; - unsigned int workport, tmport, tmport1; - unsigned long adrcnt, k; -#ifdef ED_DBGP - unsigned long l; -#endif - int errstus; - struct Scsi_Host *host = dev_id; - struct atp_unit *dev = (struct atp_unit *)&host->hostdata; - - for (c = 0; c < 2; c++) { - tmport = dev->ioport[c] + 0x1f; - j = inb(tmport); - if ((j & 0x80) != 0) - { - goto ch_sel; - } - dev->in_int[c] = 0; - } - return IRQ_NONE; -ch_sel: -#ifdef ED_DBGP - printk("atp870u_intr_handle enter\n"); -#endif - dev->in_int[c] = 1; - cmdp = inb(dev->ioport[c] + 0x10); - workport = dev->ioport[c]; - if (dev->working[c] != 0) { - if (dev->dev_id == ATP885_DEVID) { - tmport1 = workport + 0x16; - if ((inb(tmport1) & 0x80) == 0) - outb((inb(tmport1) | 0x80), tmport1); - } - tmpcip = dev->pciport[c]; - if ((inb(tmpcip) & 0x08) != 0) - { - tmpcip += 0x2; - for (k=0; k < 1000; k++) { - if ((inb(tmpcip) & 0x08) == 0) { - goto stop_dma; - } - if ((inb(tmpcip) & 0x01) == 0) { - goto stop_dma; - } - } - } -stop_dma: - tmpcip = dev->pciport[c]; - outb(0x00, tmpcip); - tmport -= 0x08; - - i = inb(tmport); - - if (dev->dev_id == ATP885_DEVID) { - tmpcip += 2; - outb(0x06, tmpcip); - tmpcip -= 2; - } - - tmport -= 0x02; - target_id = inb(tmport); - tmport += 0x02; - - /* - * Remap wide devices onto id numbers - */ - - if ((target_id & 0x40) != 0) { - target_id = (target_id & 0x07) | 0x08; - } else { - target_id &= 0x07; - } - - if ((j & 0x40) != 0) { - if (dev->last_cmd[c] == 0xff) { - dev->last_cmd[c] = target_id; - } - dev->last_cmd[c] |= 0x40; - } - if (dev->dev_id == ATP885_DEVID) - dev->r1f[c][target_id] |= j; -#ifdef ED_DBGP - printk("atp870u_intr_handle status = %x\n",i); -#endif - if (i == 0x85) { - if ((dev->last_cmd[c] & 0xf0) != 0x40) { - dev->last_cmd[c] = 0xff; - } - if (dev->dev_id == ATP885_DEVID) { - tmport -= 0x05; - adrcnt = 0; - ((unsigned char *) &adrcnt)[2] = inb(tmport++); - ((unsigned char *) &adrcnt)[1] = inb(tmport++); - ((unsigned char *) &adrcnt)[0] = inb(tmport); - if (dev->id[c][target_id].last_len != adrcnt) - { - k = dev->id[c][target_id].last_len; - k -= adrcnt; - dev->id[c][target_id].tran_len = k; - dev->id[c][target_id].last_len = adrcnt; - } -#ifdef ED_DBGP - printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len); -#endif - } - - /* - * Flip wide - */ - if (dev->wide_id[c] != 0) { - tmport = workport + 0x1b; - outb(0x01, tmport); - while ((inb(tmport) & 0x01) != 0x01) { - outb(0x01, tmport); - } - } - /* - * Issue more commands - */ - spin_lock_irqsave(dev->host->host_lock, flags); - if (((dev->quhd[c] != dev->quend[c]) || (dev->last_cmd[c] != 0xff)) && - (dev->in_snd[c] == 0)) { -#ifdef ED_DBGP - printk("Call sent_s870\n"); -#endif - send_s870(dev,c); - } - spin_unlock_irqrestore(dev->host->host_lock, flags); - /* - * Done - */ - dev->in_int[c] = 0; -#ifdef ED_DBGP - printk("Status 0x85 return\n"); -#endif - goto handled; - } - - if (i == 0x40) { - dev->last_cmd[c] |= 0x40; - dev->in_int[c] = 0; - goto handled; - } - - if (i == 0x21) { - if ((dev->last_cmd[c] & 0xf0) != 0x40) { - dev->last_cmd[c] = 0xff; - } - tmport -= 0x05; - adrcnt = 0; - ((unsigned char *) &adrcnt)[2] = inb(tmport++); - ((unsigned char *) &adrcnt)[1] = inb(tmport++); - ((unsigned char *) &adrcnt)[0] = inb(tmport); - k = dev->id[c][target_id].last_len; - k -= adrcnt; - dev->id[c][target_id].tran_len = k; - dev->id[c][target_id].last_len = adrcnt; - tmport -= 0x04; - outb(0x41, tmport); - tmport += 0x08; - outb(0x08, tmport); - dev->in_int[c] = 0; - goto handled; - } - - if (dev->dev_id == ATP885_DEVID) { - if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) { - if ((i == 0x4c) || (i == 0x8c)) - i=0x48; - else - i=0x49; - } - - } - if ((i == 0x80) || (i == 0x8f)) { -#ifdef ED_DBGP - printk(KERN_DEBUG "Device reselect\n"); -#endif - lun = 0; - tmport -= 0x07; - if (cmdp == 0x44 || i==0x80) { - tmport += 0x0d; - lun = inb(tmport) & 0x07; - } else { - if ((dev->last_cmd[c] & 0xf0) != 0x40) { - dev->last_cmd[c] = 0xff; - } - if (cmdp == 0x41) { -#ifdef ED_DBGP - printk("cmdp = 0x41\n"); -#endif - tmport += 0x02; - adrcnt = 0; - ((unsigned char *) &adrcnt)[2] = inb(tmport++); - ((unsigned char *) &adrcnt)[1] = inb(tmport++); - ((unsigned char *) &adrcnt)[0] = inb(tmport); - k = dev->id[c][target_id].last_len; - k -= adrcnt; - dev->id[c][target_id].tran_len = k; - dev->id[c][target_id].last_len = adrcnt; - tmport += 0x04; - outb(0x08, tmport); - dev->in_int[c] = 0; - goto handled; - } else { -#ifdef ED_DBGP - printk("cmdp != 0x41\n"); -#endif - outb(0x46, tmport); - dev->id[c][target_id].dirct = 0x00; - tmport += 0x02; - outb(0x00, tmport++); - outb(0x00, tmport++); - outb(0x00, tmport++); - tmport += 0x03; - outb(0x08, tmport); - dev->in_int[c] = 0; - goto handled; - } - } - if (dev->last_cmd[c] != 0xff) { - dev->last_cmd[c] |= 0x40; - } - if (dev->dev_id == ATP885_DEVID) { - j = inb(dev->baseport + 0x29) & 0xfe; - outb(j, dev->baseport + 0x29); - tmport = workport + 0x16; - } else { - tmport = workport + 0x10; - outb(0x45, tmport); - tmport += 0x06; - } - - target_id = inb(tmport); - /* - * Remap wide identifiers - */ - if ((target_id & 0x10) != 0) { - target_id = (target_id & 0x07) | 0x08; - } else { - target_id &= 0x07; - } - if (dev->dev_id == ATP885_DEVID) { - tmport = workport + 0x10; - outb(0x45, tmport); - } - workreq = dev->id[c][target_id].curr_req; -#ifdef ED_DBGP - scmd_printk(KERN_DEBUG, workreq, "CDB"); - for (l = 0; l < workreq->cmd_len; l++) - printk(KERN_DEBUG " %x",workreq->cmnd[l]); - printk("\n"); -#endif - - tmport = workport + 0x0f; - outb(lun, tmport); - tmport += 0x02; - outb(dev->id[c][target_id].devsp, tmport++); - adrcnt = dev->id[c][target_id].tran_len; - k = dev->id[c][target_id].last_len; - - outb(((unsigned char *) &k)[2], tmport++); - outb(((unsigned char *) &k)[1], tmport++); - outb(((unsigned char *) &k)[0], tmport++); -#ifdef ED_DBGP - printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3)); -#endif - /* Remap wide */ - j = target_id; - if (target_id > 7) { - j = (j & 0x07) | 0x40; - } - /* Add direction */ - j |= dev->id[c][target_id].dirct; - outb(j, tmport++); - outb(0x80,tmport); - - /* enable 32 bit fifo transfer */ - if (dev->dev_id == ATP885_DEVID) { - tmpcip = dev->pciport[c] + 1; - i=inb(tmpcip) & 0xf3; - //j=workreq->cmnd[0]; - if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { - i |= 0x0c; - } - outb(i,tmpcip); - } else if ((dev->dev_id == ATP880_DEVID1) || - (dev->dev_id == ATP880_DEVID2) ) { - tmport = workport - 0x05; - if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { - outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport); - } else { - outb((unsigned char) (inb(tmport) & 0x3f), tmport); - } - } else { - tmport = workport + 0x3a; - if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { - outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport); - } else { - outb((unsigned char) (inb(tmport) & 0xf3), tmport); - } - } - tmport = workport + 0x1b; - j = 0; - id = 1; - id = id << target_id; - /* - * Is this a wide device - */ - if ((id & dev->wide_id[c]) != 0) { - j |= 0x01; - } - outb(j, tmport); - while ((inb(tmport) & 0x01) != j) { - outb(j,tmport); - } - if (dev->id[c][target_id].last_len == 0) { - tmport = workport + 0x18; - outb(0x08, tmport); - dev->in_int[c] = 0; -#ifdef ED_DBGP - printk("dev->id[c][target_id].last_len = 0\n"); -#endif - goto handled; - } -#ifdef ED_DBGP - printk("target_id = %d adrcnt = %d\n",target_id,adrcnt); -#endif - prd = dev->id[c][target_id].prd_pos; - while (adrcnt != 0) { - id = ((unsigned short int *)prd)[2]; - if (id == 0) { - k = 0x10000; - } else { - k = id; - } - if (k > adrcnt) { - ((unsigned short int *)prd)[2] = (unsigned short int) - (k - adrcnt); - ((unsigned long *)prd)[0] += adrcnt; - adrcnt = 0; - dev->id[c][target_id].prd_pos = prd; - } else { - adrcnt -= k; - dev->id[c][target_id].prdaddr += 0x08; - prd += 0x08; - if (adrcnt == 0) { - dev->id[c][target_id].prd_pos = prd; - } - } - } - tmpcip = dev->pciport[c] + 0x04; - outl(dev->id[c][target_id].prdaddr, tmpcip); -#ifdef ED_DBGP - printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr); -#endif - if (dev->dev_id == ATP885_DEVID) { - tmpcip -= 0x04; - } else { - tmpcip -= 0x02; - outb(0x06, tmpcip); - outb(0x00, tmpcip); - tmpcip -= 0x02; - } - tmport = workport + 0x18; - /* - * Check transfer direction - */ - if (dev->id[c][target_id].dirct != 0) { - outb(0x08, tmport); - outb(0x01, tmpcip); - dev->in_int[c] = 0; -#ifdef ED_DBGP - printk("status 0x80 return dirct != 0\n"); -#endif - goto handled; - } - outb(0x08, tmport); - outb(0x09, tmpcip); - dev->in_int[c] = 0; -#ifdef ED_DBGP - printk("status 0x80 return dirct = 0\n"); -#endif - goto handled; - } - - /* - * Current scsi request on this target - */ - - workreq = dev->id[c][target_id].curr_req; - - if (i == 0x42) { - if ((dev->last_cmd[c] & 0xf0) != 0x40) - { - dev->last_cmd[c] = 0xff; - } - errstus = 0x02; - workreq->result = errstus; - goto go_42; - } - if (i == 0x16) { - if ((dev->last_cmd[c] & 0xf0) != 0x40) { - dev->last_cmd[c] = 0xff; - } - errstus = 0; - tmport -= 0x08; - errstus = inb(tmport); - if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) { - printk(KERN_WARNING "AEC67162 CRC ERROR !\n"); - errstus = 0x02; - } - workreq->result = errstus; -go_42: - if (dev->dev_id == ATP885_DEVID) { - j = inb(dev->baseport + 0x29) | 0x01; - outb(j, dev->baseport + 0x29); - } - /* - * Complete the command - */ - scsi_dma_unmap(workreq); - - spin_lock_irqsave(dev->host->host_lock, flags); - (*workreq->scsi_done) (workreq); -#ifdef ED_DBGP - printk("workreq->scsi_done\n"); -#endif - /* - * Clear it off the queue - */ - dev->id[c][target_id].curr_req = NULL; - dev->working[c]--; - spin_unlock_irqrestore(dev->host->host_lock, flags); - /* - * Take it back wide - */ - if (dev->wide_id[c] != 0) { - tmport = workport + 0x1b; - outb(0x01, tmport); - while ((inb(tmport) & 0x01) != 0x01) { - outb(0x01, tmport); - } - } - /* - * If there is stuff to send and nothing going then send it - */ - spin_lock_irqsave(dev->host->host_lock, flags); - if (((dev->last_cmd[c] != 0xff) || (dev->quhd[c] != dev->quend[c])) && - (dev->in_snd[c] == 0)) { -#ifdef ED_DBGP - printk("Call sent_s870(scsi_done)\n"); -#endif - send_s870(dev,c); - } - spin_unlock_irqrestore(dev->host->host_lock, flags); - dev->in_int[c] = 0; - goto handled; - } - if ((dev->last_cmd[c] & 0xf0) != 0x40) { - dev->last_cmd[c] = 0xff; - } - if (i == 0x4f) { - i = 0x89; - } - i &= 0x0f; - if (i == 0x09) { - tmpcip += 4; - outl(dev->id[c][target_id].prdaddr, tmpcip); - tmpcip = tmpcip - 2; - outb(0x06, tmpcip); - outb(0x00, tmpcip); - tmpcip = tmpcip - 2; - tmport = workport + 0x10; - outb(0x41, tmport); - if (dev->dev_id == ATP885_DEVID) { - tmport += 2; - k = dev->id[c][target_id].last_len; - outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++); - outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++); - outb((unsigned char) (((unsigned char *) (&k))[0]), tmport); - dev->id[c][target_id].dirct = 0x00; - tmport += 0x04; - } else { - dev->id[c][target_id].dirct = 0x00; - tmport += 0x08; - } - outb(0x08, tmport); - outb(0x09, tmpcip); - dev->in_int[c] = 0; - goto handled; - } - if (i == 0x08) { - tmpcip += 4; - outl(dev->id[c][target_id].prdaddr, tmpcip); - tmpcip = tmpcip - 2; - outb(0x06, tmpcip); - outb(0x00, tmpcip); - tmpcip = tmpcip - 2; - tmport = workport + 0x10; - outb(0x41, tmport); - if (dev->dev_id == ATP885_DEVID) { - tmport += 2; - k = dev->id[c][target_id].last_len; - outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++); - outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++); - outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++); - } else { - tmport += 5; - } - outb((unsigned char) (inb(tmport) | 0x20), tmport); - dev->id[c][target_id].dirct = 0x20; - tmport += 0x03; - outb(0x08, tmport); - outb(0x01, tmpcip); - dev->in_int[c] = 0; - goto handled; - } - tmport -= 0x07; - if (i == 0x0a) { - outb(0x30, tmport); - } else { - outb(0x46, tmport); - } - dev->id[c][target_id].dirct = 0x00; - tmport += 0x02; - outb(0x00, tmport++); - outb(0x00, tmport++); - outb(0x00, tmport++); - tmport += 0x03; - outb(0x08, tmport); - dev->in_int[c] = 0; - goto handled; - } else { -// tmport = workport + 0x17; -// inb(tmport); -// dev->working[c] = 0; - dev->in_int[c] = 0; - goto handled; - } - -handled: -#ifdef ED_DBGP - printk("atp870u_intr_handle exit\n"); -#endif - return IRQ_HANDLED; -} -/** - * atp870u_queuecommand - Queue SCSI command - * @req_p: request block - * @done: completion function - * - * Queue a command to the ATP queue. Called with the host lock held. - */ -static int atp870u_queuecommand_lck(struct scsi_cmnd *req_p, - void (*done) (struct scsi_cmnd *)) -{ - unsigned char c; - unsigned int tmport,m; - struct atp_unit *dev; - struct Scsi_Host *host; - - c = scmd_channel(req_p); - req_p->sense_buffer[0]=0; - scsi_set_resid(req_p, 0); - if (scmd_channel(req_p) > 1) { - req_p->result = 0x00040000; - done(req_p); -#ifdef ED_DBGP - printk("atp870u_queuecommand : req_p->device->channel > 1\n"); -#endif - return 0; - } - - host = req_p->device->host; - dev = (struct atp_unit *)&host->hostdata; - - - - m = 1; - m = m << scmd_id(req_p); - - /* - * Fake a timeout for missing targets - */ - - if ((m & dev->active_id[c]) == 0) { - req_p->result = 0x00040000; - done(req_p); - return 0; - } - - if (done) { - req_p->scsi_done = done; - } else { -#ifdef ED_DBGP - printk( "atp870u_queuecommand: done can't be NULL\n"); -#endif - req_p->result = 0; - done(req_p); - return 0; - } - - /* - * Count new command - */ - dev->quend[c]++; - if (dev->quend[c] >= qcnt) { - dev->quend[c] = 0; - } - - /* - * Check queue state - */ - if (dev->quhd[c] == dev->quend[c]) { - if (dev->quend[c] == 0) { - dev->quend[c] = qcnt; - } -#ifdef ED_DBGP - printk("atp870u_queuecommand : dev->quhd[c] == dev->quend[c]\n"); -#endif - dev->quend[c]--; - req_p->result = 0x00020000; - done(req_p); - return 0; - } - dev->quereq[c][dev->quend[c]] = req_p; - tmport = dev->ioport[c] + 0x1c; -#ifdef ED_DBGP - printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]); -#endif - if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) { -#ifdef ED_DBGP - printk("Call sent_s870(atp870u_queuecommand)\n"); -#endif - send_s870(dev,c); - } -#ifdef ED_DBGP - printk("atp870u_queuecommand : exit\n"); -#endif - return 0; -} - -static DEF_SCSI_QCMD(atp870u_queuecommand) - -/** - * send_s870 - send a command to the controller - * @host: host - * - * On entry there is work queued to be done. We move some of that work to the - * controller itself. - * - * Caller holds the host lock. - */ -static void send_s870(struct atp_unit *dev,unsigned char c) -{ - unsigned int tmport; - struct scsi_cmnd *workreq; - unsigned int i;//,k; - unsigned char j, target_id; - unsigned char *prd; - unsigned short int tmpcip, w; - unsigned long l, bttl = 0; - unsigned int workport; - unsigned long sg_count; - - if (dev->in_snd[c] != 0) { -#ifdef ED_DBGP - printk("cmnd in_snd\n"); -#endif - return; - } -#ifdef ED_DBGP - printk("Sent_s870 enter\n"); -#endif - dev->in_snd[c] = 1; - if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) { - dev->last_cmd[c] &= 0x0f; - workreq = dev->id[c][dev->last_cmd[c]].curr_req; - if (workreq != NULL) { /* check NULL pointer */ - goto cmd_subp; - } - dev->last_cmd[c] = 0xff; - if (dev->quhd[c] == dev->quend[c]) { - dev->in_snd[c] = 0; - return ; - } - } - if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) { - dev->in_snd[c] = 0; - return ; - } - dev->working[c]++; - j = dev->quhd[c]; - dev->quhd[c]++; - if (dev->quhd[c] >= qcnt) { - dev->quhd[c] = 0; - } - workreq = dev->quereq[c][dev->quhd[c]]; - if (dev->id[c][scmd_id(workreq)].curr_req == NULL) { - dev->id[c][scmd_id(workreq)].curr_req = workreq; - dev->last_cmd[c] = scmd_id(workreq); - goto cmd_subp; - } - dev->quhd[c] = j; - dev->working[c]--; - dev->in_snd[c] = 0; - return; -cmd_subp: - workport = dev->ioport[c]; - tmport = workport + 0x1f; - if ((inb(tmport) & 0xb0) != 0) { - goto abortsnd; - } - tmport = workport + 0x1c; - if (inb(tmport) == 0) { - goto oktosend; - } -abortsnd: -#ifdef ED_DBGP - printk("Abort to Send\n"); -#endif - dev->last_cmd[c] |= 0x40; - dev->in_snd[c] = 0; - return; -oktosend: -#ifdef ED_DBGP - printk("OK to Send\n"); - scmd_printk(KERN_DEBUG, workreq, "CDB"); - for(i=0;icmd_len;i++) { - printk(" %x",workreq->cmnd[i]); - } - printk("\n"); -#endif - l = scsi_bufflen(workreq); - - if (dev->dev_id == ATP885_DEVID) { - j = inb(dev->baseport + 0x29) & 0xfe; - outb(j, dev->baseport + 0x29); - dev->r1f[c][scmd_id(workreq)] = 0; - } - - if (workreq->cmnd[0] == READ_CAPACITY) { - if (l > 8) - l = 8; - } - if (workreq->cmnd[0] == 0x00) { - l = 0; - } - - tmport = workport + 0x1b; - j = 0; - target_id = scmd_id(workreq); - - /* - * Wide ? - */ - w = 1; - w = w << target_id; - if ((w & dev->wide_id[c]) != 0) { - j |= 0x01; - } - outb(j, tmport); - while ((inb(tmport) & 0x01) != j) { - outb(j,tmport); -#ifdef ED_DBGP - printk("send_s870 while loop 1\n"); -#endif - } - /* - * Write the command - */ - - tmport = workport; - outb(workreq->cmd_len, tmport++); - outb(0x2c, tmport++); - if (dev->dev_id == ATP885_DEVID) { - outb(0x7f, tmport++); - } else { - outb(0xcf, tmport++); - } - for (i = 0; i < workreq->cmd_len; i++) { - outb(workreq->cmnd[i], tmport++); - } - tmport = workport + 0x0f; - outb(workreq->device->lun, tmport); - tmport += 0x02; - /* - * Write the target - */ - outb(dev->id[c][target_id].devsp, tmport++); -#ifdef ED_DBGP - printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp); -#endif - - sg_count = scsi_dma_map(workreq); - /* - * Write transfer size - */ - outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++); - outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++); - outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++); - j = target_id; - dev->id[c][j].last_len = l; - dev->id[c][j].tran_len = 0; -#ifdef ED_DBGP - printk("dev->id[%2d][%2d].last_len = %d\n",c,j,dev->id[c][j].last_len); -#endif - /* - * Flip the wide bits - */ - if ((j & 0x08) != 0) { - j = (j & 0x07) | 0x40; - } - /* - * Check transfer direction - */ - if (workreq->sc_data_direction == DMA_TO_DEVICE) { - outb((unsigned char) (j | 0x20), tmport++); - } else { - outb(j, tmport++); - } - outb((unsigned char) (inb(tmport) | 0x80), tmport); - outb(0x80, tmport); - tmport = workport + 0x1c; - dev->id[c][target_id].dirct = 0; - if (l == 0) { - if (inb(tmport) == 0) { - tmport = workport + 0x18; -#ifdef ED_DBGP - printk("change SCSI_CMD_REG 0x08\n"); -#endif - outb(0x08, tmport); - } else { - dev->last_cmd[c] |= 0x40; - } - dev->in_snd[c] = 0; - return; - } - tmpcip = dev->pciport[c]; - prd = dev->id[c][target_id].prd_table; - dev->id[c][target_id].prd_pos = prd; - - /* - * Now write the request list. Either as scatter/gather or as - * a linear chain. - */ - - if (l) { - struct scatterlist *sgpnt; - i = 0; - scsi_for_each_sg(workreq, sgpnt, sg_count, j) { - bttl = sg_dma_address(sgpnt); - l=sg_dma_len(sgpnt); -#ifdef ED_DBGP - printk("1. bttl %x, l %x\n",bttl, l); -#endif - while (l > 0x10000) { - (((u16 *) (prd))[i + 3]) = 0x0000; - (((u16 *) (prd))[i + 2]) = 0x0000; - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); - l -= 0x10000; - bttl += 0x10000; - i += 0x04; - } - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); - (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); - (((u16 *) (prd))[i + 3]) = 0; - i += 0x04; - } - (((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000); -#ifdef ED_DBGP - printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); - printk("2. bttl %x, l %x\n",bttl, l); -#endif - } - tmpcip += 4; -#ifdef ED_DBGP - printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id); -#endif - dev->id[c][target_id].prdaddr = dev->id[c][target_id].prd_bus; - outl(dev->id[c][target_id].prdaddr, tmpcip); - tmpcip = tmpcip - 2; - outb(0x06, tmpcip); - outb(0x00, tmpcip); - if (dev->dev_id == ATP885_DEVID) { - tmpcip--; - j=inb(tmpcip) & 0xf3; - if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || - (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { - j |= 0x0c; - } - outb(j,tmpcip); - tmpcip--; - } else if ((dev->dev_id == ATP880_DEVID1) || - (dev->dev_id == ATP880_DEVID2)) { - tmpcip =tmpcip -2; - tmport = workport - 0x05; - if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { - outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport); - } else { - outb((unsigned char) (inb(tmport) & 0x3f), tmport); - } - } else { - tmpcip =tmpcip -2; - tmport = workport + 0x3a; - if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { - outb((inb(tmport) & 0xf3) | 0x08, tmport); - } else { - outb(inb(tmport) & 0xf3, tmport); - } - } - tmport = workport + 0x1c; - - if(workreq->sc_data_direction == DMA_TO_DEVICE) { - dev->id[c][target_id].dirct = 0x20; - if (inb(tmport) == 0) { - tmport = workport + 0x18; - outb(0x08, tmport); - outb(0x01, tmpcip); -#ifdef ED_DBGP - printk( "start DMA(to target)\n"); -#endif - } else { - dev->last_cmd[c] |= 0x40; - } - dev->in_snd[c] = 0; - return; - } - if (inb(tmport) == 0) { - tmport = workport + 0x18; - outb(0x08, tmport); - outb(0x09, tmpcip); -#ifdef ED_DBGP - printk( "start DMA(to host)\n"); -#endif - } else { - dev->last_cmd[c] |= 0x40; - } - dev->in_snd[c] = 0; - return; - -} - -static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val) -{ - unsigned int tmport; - unsigned short int i, k; - unsigned char j; - - tmport = dev->ioport[0] + 0x1c; - outw(*val, tmport); -FUN_D7: - for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ - k = inw(tmport); - j = (unsigned char) (k >> 8); - if ((k & 0x8000) != 0) { /* DB7 all release? */ - goto FUN_D7; - } - } - *val |= 0x4000; /* assert DB6 */ - outw(*val, tmport); - *val &= 0xdfff; /* assert DB5 */ - outw(*val, tmport); -FUN_D5: - for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ - if ((inw(tmport) & 0x2000) != 0) { /* DB5 all release? */ - goto FUN_D5; - } - } - *val |= 0x8000; /* no DB4-0, assert DB7 */ - *val &= 0xe0ff; - outw(*val, tmport); - *val &= 0xbfff; /* release DB6 */ - outw(*val, tmport); -FUN_D6: - for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ - if ((inw(tmport) & 0x4000) != 0) { /* DB6 all release? */ - goto FUN_D6; - } - } - - return j; -} - -static void tscam(struct Scsi_Host *host) -{ - - unsigned int tmport; - unsigned char i, j, k; - unsigned long n; - unsigned short int m, assignid_map, val; - unsigned char mbuf[33], quintet[2]; - struct atp_unit *dev = (struct atp_unit *)&host->hostdata; - static unsigned char g2q_tab[8] = { - 0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27 - }; - -/* I can't believe we need this before we've even done anything. Remove it - * and see if anyone bitches. - for (i = 0; i < 0x10; i++) { - udelay(0xffff); - } - */ - - tmport = dev->ioport[0] + 1; - outb(0x08, tmport++); - outb(0x7f, tmport); - tmport = dev->ioport[0] + 0x11; - outb(0x20, tmport); - - if ((dev->scam_on & 0x40) == 0) { - return; - } - m = 1; - m <<= dev->host_id[0]; - j = 16; - if (dev->chip_ver < 4) { - m |= 0xff00; - j = 8; - } - assignid_map = m; - tmport = dev->ioport[0] + 0x02; - outb(0x02, tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */ - outb(0, tmport++); - outb(0, tmport++); - outb(0, tmport++); - outb(0, tmport++); - outb(0, tmport++); - outb(0, tmport++); - - for (i = 0; i < j; i++) { - m = 1; - m = m << i; - if ((m & assignid_map) != 0) { - continue; - } - tmport = dev->ioport[0] + 0x0f; - outb(0, tmport++); - tmport += 0x02; - outb(0, tmport++); - outb(0, tmport++); - outb(0, tmport++); - if (i > 7) { - k = (i & 0x07) | 0x40; - } else { - k = i; - } - outb(k, tmport++); - tmport = dev->ioport[0] + 0x1b; - if (dev->chip_ver == 4) { - outb(0x01, tmport); - } else { - outb(0x00, tmport); - } -wait_rdyok: - tmport = dev->ioport[0] + 0x18; - outb(0x09, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - k = inb(tmport); - if (k != 0x16) { - if ((k == 0x85) || (k == 0x42)) { - continue; - } - tmport = dev->ioport[0] + 0x10; - outb(0x41, tmport); - goto wait_rdyok; - } - assignid_map |= m; - - } - tmport = dev->ioport[0] + 0x02; - outb(0x7f, tmport); - tmport = dev->ioport[0] + 0x1b; - outb(0x02, tmport); - - outb(0, 0x80); - - val = 0x0080; /* bsy */ - tmport = dev->ioport[0] + 0x1c; - outw(val, tmport); - val |= 0x0040; /* sel */ - outw(val, tmport); - val |= 0x0004; /* msg */ - outw(val, tmport); - inb(0x80); /* 2 deskew delay(45ns*2=90ns) */ - val &= 0x007f; /* no bsy */ - outw(val, tmport); - mdelay(128); - val &= 0x00fb; /* after 1ms no msg */ - outw(val, tmport); -wait_nomsg: - if ((inb(tmport) & 0x04) != 0) { - goto wait_nomsg; - } - outb(1, 0x80); - udelay(100); - for (n = 0; n < 0x30000; n++) { - if ((inb(tmport) & 0x80) != 0) { /* bsy ? */ - goto wait_io; - } - } - goto TCM_SYNC; -wait_io: - for (n = 0; n < 0x30000; n++) { - if ((inb(tmport) & 0x81) == 0x0081) { - goto wait_io1; - } - } - goto TCM_SYNC; -wait_io1: - inb(0x80); - val |= 0x8003; /* io,cd,db7 */ - outw(val, tmport); - inb(0x80); - val &= 0x00bf; /* no sel */ - outw(val, tmport); - outb(2, 0x80); -TCM_SYNC: - udelay(0x800); - if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */ - outw(0, tmport--); - outb(0, tmport); - tmport = dev->ioport[0] + 0x15; - outb(0, tmport); - tmport += 0x03; - outb(0x09, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) - cpu_relax(); - tmport -= 0x08; - inb(tmport); - return; - } - val &= 0x00ff; /* synchronization */ - val |= 0x3f00; - fun_scam(dev, &val); - outb(3, 0x80); - val &= 0x00ff; /* isolation */ - val |= 0x2000; - fun_scam(dev, &val); - outb(4, 0x80); - i = 8; - j = 0; -TCM_ID: - if ((inw(tmport) & 0x2000) == 0) { - goto TCM_ID; - } - outb(5, 0x80); - val &= 0x00ff; /* get ID_STRING */ - val |= 0x2000; - k = fun_scam(dev, &val); - if ((k & 0x03) == 0) { - goto TCM_5; - } - mbuf[j] <<= 0x01; - mbuf[j] &= 0xfe; - if ((k & 0x02) != 0) { - mbuf[j] |= 0x01; - } - i--; - if (i > 0) { - goto TCM_ID; - } - j++; - i = 8; - goto TCM_ID; - -TCM_5: /* isolation complete.. */ -/* mbuf[32]=0; - printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */ - i = 15; - j = mbuf[0]; - if ((j & 0x20) != 0) { /* bit5=1:ID up to 7 */ - i = 7; - } - if ((j & 0x06) == 0) { /* IDvalid? */ - goto G2Q5; - } - k = mbuf[1]; -small_id: - m = 1; - m <<= k; - if ((m & assignid_map) == 0) { - goto G2Q_QUIN; - } - if (k > 0) { - k--; - goto small_id; - } -G2Q5: /* srch from max acceptable ID# */ - k = i; /* max acceptable ID# */ -G2Q_LP: - m = 1; - m <<= k; - if ((m & assignid_map) == 0) { - goto G2Q_QUIN; - } - if (k > 0) { - k--; - goto G2Q_LP; - } -G2Q_QUIN: /* k=binID#, */ - assignid_map |= m; - if (k < 8) { - quintet[0] = 0x38; /* 1st dft ID<8 */ - } else { - quintet[0] = 0x31; /* 1st ID>=8 */ - } - k &= 0x07; - quintet[1] = g2q_tab[k]; - - val &= 0x00ff; /* AssignID 1stQuintet,AH=001xxxxx */ - m = quintet[0] << 8; - val |= m; - fun_scam(dev, &val); - val &= 0x00ff; /* AssignID 2ndQuintet,AH=001xxxxx */ - m = quintet[1] << 8; - val |= m; - fun_scam(dev, &val); - - goto TCM_SYNC; - -} - -static void is870(struct atp_unit *dev, unsigned int wkport) -{ - unsigned int tmport; - unsigned char i, j, k, rmb, n; - unsigned short int m; - static unsigned char mbuf[512]; - static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 }; - static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 }; - static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e }; - static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e }; - static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 }; - static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 }; - - tmport = wkport + 0x3a; - outb((unsigned char) (inb(tmport) | 0x10), tmport); - - for (i = 0; i < 16; i++) { - if ((dev->chip_ver != 4) && (i > 7)) { - break; - } - m = 1; - m = m << i; - if ((m & dev->active_id[0]) != 0) { - continue; - } - if (i == dev->host_id[0]) { - printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]); - continue; - } - tmport = wkport + 0x1b; - if (dev->chip_ver == 4) { - outb(0x01, tmport); - } else { - outb(0x00, tmport); - } - tmport = wkport + 1; - outb(0x08, tmport++); - outb(0x7f, tmport++); - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - j = i; - if ((j & 0x08) != 0) { - j = (j & 0x07) | 0x40; - } - outb(j, tmport); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x11 && inb(tmport) != 0x8e) - continue; - - while (inb(tmport) != 0x8e) - cpu_relax(); - - dev->active_id[0] |= m; - - tmport = wkport + 0x10; - outb(0x30, tmport); - tmport = wkport + 0x04; - outb(0x00, tmport); - -phase_cmd: - tmport = wkport + 0x18; - outb(0x08, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - tmport = wkport + 0x10; - outb(0x41, tmport); - goto phase_cmd; - } -sel_ok: - tmport = wkport + 3; - outb(inqd[0], tmport++); - outb(inqd[1], tmport++); - outb(inqd[2], tmport++); - outb(inqd[3], tmport++); - outb(inqd[4], tmport++); - outb(inqd[5], tmport); - tmport += 0x07; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(inqd[6], tmport++); - outb(inqd[7], tmport++); - tmport += 0x03; - outb(inqd[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x11 && inb(tmport) != 0x8e) - continue; - - while (inb(tmport) != 0x8e) - cpu_relax(); - - tmport = wkport + 0x1b; - if (dev->chip_ver == 4) - outb(0x00, tmport); - - tmport = wkport + 0x18; - outb(0x08, tmport); - tmport += 0x07; - j = 0; -rd_inq_data: - k = inb(tmport); - if ((k & 0x01) != 0) { - tmport -= 0x06; - mbuf[j++] = inb(tmport); - tmport += 0x06; - goto rd_inq_data; - } - if ((k & 0x80) == 0) { - goto rd_inq_data; - } - tmport -= 0x08; - j = inb(tmport); - if (j == 0x16) { - goto inq_ok; - } - tmport = wkport + 0x10; - outb(0x46, tmport); - tmport += 0x02; - outb(0, tmport++); - outb(0, tmport++); - outb(0, tmport++); - tmport += 0x03; - outb(0x08, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x16) { - goto sel_ok; - } -inq_ok: - mbuf[36] = 0; - printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]); - dev->id[0][i].devtype = mbuf[0]; - rmb = mbuf[1]; - n = mbuf[7]; - if (dev->chip_ver != 4) { - goto not_wide; - } - if ((mbuf[7] & 0x60) == 0) { - goto not_wide; - } - if ((dev->global_map[0] & 0x20) == 0) { - goto not_wide; - } - tmport = wkport + 0x1b; - outb(0x01, tmport); - tmport = wkport + 3; - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x11 && inb(tmport) != 0x8e) - continue; - - while (inb(tmport) != 0x8e) - cpu_relax(); - -try_wide: - j = 0; - tmport = wkport + 0x14; - outb(0x05, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(wide[j++], tmport); - tmport += 0x06; - } - } - tmport -= 0x08; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto try_wide; - } - continue; -widep_out: - tmport = wkport + 0x18; - outb(0x20, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(0, tmport); - tmport += 0x06; - } - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto widep_out; - } - continue; -widep_in: - tmport = wkport + 0x14; - outb(0xff, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - k = 0; -widep_in1: - j = inb(tmport); - if ((j & 0x01) != 0) { - tmport -= 0x06; - mbuf[k++] = inb(tmport); - tmport += 0x06; - goto widep_in1; - } - if ((j & 0x80) == 0x00) { - goto widep_in1; - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto widep_out; - } - continue; -widep_cmd: - tmport = wkport + 0x10; - outb(0x30, tmport); - tmport = wkport + 0x14; - outb(0x00, tmport); - tmport += 0x04; - outb(0x08, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - if (j == 0x4e) { - goto widep_out; - } - continue; - } - if (mbuf[0] != 0x01) { - goto not_wide; - } - if (mbuf[1] != 0x02) { - goto not_wide; - } - if (mbuf[2] != 0x03) { - goto not_wide; - } - if (mbuf[3] != 0x01) { - goto not_wide; - } - m = 1; - m = m << i; - dev->wide_id[0] |= m; -not_wide: - if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) { - goto set_sync; - } - continue; -set_sync: - tmport = wkport + 0x1b; - j = 0; - if ((m & dev->wide_id[0]) != 0) { - j |= 0x01; - } - outb(j, tmport); - tmport = wkport + 3; - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x11 && inb(tmport) != 0x8e) - continue; - - while (inb(tmport) != 0x8e) - cpu_relax(); - -try_sync: - j = 0; - tmport = wkport + 0x14; - outb(0x06, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - if ((m & dev->wide_id[0]) != 0) { - outb(synw[j++], tmport); - } else { - if ((m & dev->ultra_map[0]) != 0) { - outb(synu[j++], tmport); - } else { - outb(synn[j++], tmport); - } - } - tmport += 0x06; - } - } - tmport -= 0x08; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto try_sync; - } - continue; -phase_outs: - tmport = wkport + 0x18; - outb(0x20, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) { - if ((inb(tmport) & 0x01) != 0x00) { - tmport -= 0x06; - outb(0x00, tmport); - tmport += 0x06; - } - } - tmport -= 0x08; - j = inb(tmport); - if (j == 0x85) { - goto tar_dcons; - } - j &= 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto phase_outs; - } - continue; -phase_ins: - tmport = wkport + 0x14; - outb(0xff, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - k = 0; -phase_ins1: - j = inb(tmport); - if ((j & 0x01) != 0x00) { - tmport -= 0x06; - mbuf[k++] = inb(tmport); - tmport += 0x06; - goto phase_ins1; - } - if ((j & 0x80) == 0x00) { - goto phase_ins1; - } - tmport -= 0x08; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - j = inb(tmport); - if (j == 0x85) { - goto tar_dcons; - } - j &= 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto phase_outs; - } - continue; -phase_cmds: - tmport = wkport + 0x10; - outb(0x30, tmport); -tar_dcons: - tmport = wkport + 0x14; - outb(0x00, tmport); - tmport += 0x04; - outb(0x08, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - continue; - } - if (mbuf[0] != 0x01) { - continue; - } - if (mbuf[1] != 0x03) { - continue; - } - if (mbuf[4] == 0x00) { - continue; - } - if (mbuf[3] > 0x64) { - continue; - } - if (mbuf[4] > 0x0c) { - mbuf[4] = 0x0c; - } - dev->id[0][i].devsp = mbuf[4]; - if ((mbuf[3] < 0x0d) && (rmb == 0)) { - j = 0xa0; - goto set_syn_ok; - } - if (mbuf[3] < 0x1a) { - j = 0x20; - goto set_syn_ok; - } - if (mbuf[3] < 0x33) { - j = 0x40; - goto set_syn_ok; - } - if (mbuf[3] < 0x4c) { - j = 0x50; - goto set_syn_ok; - } - j = 0x60; -set_syn_ok: - dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j; - } - tmport = wkport + 0x3a; - outb((unsigned char) (inb(tmport) & 0xef), tmport); -} - -static void is880(struct atp_unit *dev, unsigned int wkport) -{ - unsigned int tmport; - unsigned char i, j, k, rmb, n, lvdmode; - unsigned short int m; - static unsigned char mbuf[512]; - static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 }; - static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 }; - static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e }; - unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e }; - static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e }; - unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e }; - static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 }; - static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 }; - - lvdmode = inb(wkport + 0x3f) & 0x40; - - for (i = 0; i < 16; i++) { - m = 1; - m = m << i; - if ((m & dev->active_id[0]) != 0) { - continue; - } - if (i == dev->host_id[0]) { - printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]); - continue; - } - tmport = wkport + 0x5b; - outb(0x01, tmport); - tmport = wkport + 0x41; - outb(0x08, tmport++); - outb(0x7f, tmport++); - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - j = i; - if ((j & 0x08) != 0) { - j = (j & 0x07) | 0x40; - } - outb(j, tmport); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x11 && inb(tmport) != 0x8e) - continue; - - while (inb(tmport) != 0x8e) - cpu_relax(); - - dev->active_id[0] |= m; - - tmport = wkport + 0x50; - outb(0x30, tmport); - tmport = wkport + 0x54; - outb(0x00, tmport); - -phase_cmd: - tmport = wkport + 0x58; - outb(0x08, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - tmport = wkport + 0x50; - outb(0x41, tmport); - goto phase_cmd; - } -sel_ok: - tmport = wkport + 0x43; - outb(inqd[0], tmport++); - outb(inqd[1], tmport++); - outb(inqd[2], tmport++); - outb(inqd[3], tmport++); - outb(inqd[4], tmport++); - outb(inqd[5], tmport); - tmport += 0x07; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(inqd[6], tmport++); - outb(inqd[7], tmport++); - tmport += 0x03; - outb(inqd[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x11 && inb(tmport) != 0x8e) - continue; - - while (inb(tmport) != 0x8e) - cpu_relax(); - - tmport = wkport + 0x5b; - outb(0x00, tmport); - tmport = wkport + 0x58; - outb(0x08, tmport); - tmport += 0x07; - j = 0; -rd_inq_data: - k = inb(tmport); - if ((k & 0x01) != 0) { - tmport -= 0x06; - mbuf[j++] = inb(tmport); - tmport += 0x06; - goto rd_inq_data; - } - if ((k & 0x80) == 0) { - goto rd_inq_data; - } - tmport -= 0x08; - j = inb(tmport); - if (j == 0x16) { - goto inq_ok; - } - tmport = wkport + 0x50; - outb(0x46, tmport); - tmport += 0x02; - outb(0, tmport++); - outb(0, tmport++); - outb(0, tmport++); - tmport += 0x03; - outb(0x08, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x16) - goto sel_ok; - -inq_ok: - mbuf[36] = 0; - printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]); - dev->id[0][i].devtype = mbuf[0]; - rmb = mbuf[1]; - n = mbuf[7]; - if ((mbuf[7] & 0x60) == 0) { - goto not_wide; - } - if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) { - goto not_wide; - } - if (lvdmode == 0) { - goto chg_wide; - } - if (dev->sp[0][i] != 0x04) // force u2 - { - goto chg_wide; - } - - tmport = wkport + 0x5b; - outb(0x01, tmport); - tmport = wkport + 0x43; - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - - if (inb(tmport) != 0x11 && inb(tmport) != 0x8e) - continue; - - while (inb(tmport) != 0x8e) - cpu_relax(); - -try_u3: - j = 0; - tmport = wkport + 0x54; - outb(0x09, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(u3[j++], tmport); - tmport += 0x06; - } - } - tmport -= 0x08; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto u3p_in; - } - if (j == 0x0a) { - goto u3p_cmd; - } - if (j == 0x0e) { - goto try_u3; - } - continue; -u3p_out: - tmport = wkport + 0x58; - outb(0x20, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(0, tmport); - tmport += 0x06; - } - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto u3p_in; - } - if (j == 0x0a) { - goto u3p_cmd; - } - if (j == 0x0e) { - goto u3p_out; - } - continue; -u3p_in: - tmport = wkport + 0x54; - outb(0x09, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - k = 0; -u3p_in1: - j = inb(tmport); - if ((j & 0x01) != 0) { - tmport -= 0x06; - mbuf[k++] = inb(tmport); - tmport += 0x06; - goto u3p_in1; - } - if ((j & 0x80) == 0x00) { - goto u3p_in1; - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto u3p_in; - } - if (j == 0x0a) { - goto u3p_cmd; - } - if (j == 0x0e) { - goto u3p_out; - } - continue; -u3p_cmd: - tmport = wkport + 0x50; - outb(0x30, tmport); - tmport = wkport + 0x54; - outb(0x00, tmport); - tmport += 0x04; - outb(0x08, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - if (j == 0x4e) { - goto u3p_out; - } - continue; - } - if (mbuf[0] != 0x01) { - goto chg_wide; - } - if (mbuf[1] != 0x06) { - goto chg_wide; - } - if (mbuf[2] != 0x04) { - goto chg_wide; - } - if (mbuf[3] == 0x09) { - m = 1; - m = m << i; - dev->wide_id[0] |= m; - dev->id[0][i].devsp = 0xce; - continue; - } -chg_wide: - tmport = wkport + 0x5b; - outb(0x01, tmport); - tmport = wkport + 0x43; - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if (inb(tmport) != 0x11 && inb(tmport) != 0x8e) - continue; - - while (inb(tmport) != 0x8e) - cpu_relax(); - -try_wide: - j = 0; - tmport = wkport + 0x54; - outb(0x05, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(wide[j++], tmport); - tmport += 0x06; - } - } - tmport -= 0x08; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto try_wide; - } - continue; -widep_out: - tmport = wkport + 0x58; - outb(0x20, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(0, tmport); - tmport += 0x06; - } - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto widep_out; - } - continue; -widep_in: - tmport = wkport + 0x54; - outb(0xff, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - k = 0; -widep_in1: - j = inb(tmport); - if ((j & 0x01) != 0) { - tmport -= 0x06; - mbuf[k++] = inb(tmport); - tmport += 0x06; - goto widep_in1; - } - if ((j & 0x80) == 0x00) { - goto widep_in1; - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto widep_out; - } - continue; -widep_cmd: - tmport = wkport + 0x50; - outb(0x30, tmport); - tmport = wkport + 0x54; - outb(0x00, tmport); - tmport += 0x04; - outb(0x08, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - if (j == 0x4e) { - goto widep_out; - } - continue; - } - if (mbuf[0] != 0x01) { - goto not_wide; - } - if (mbuf[1] != 0x02) { - goto not_wide; - } - if (mbuf[2] != 0x03) { - goto not_wide; - } - if (mbuf[3] != 0x01) { - goto not_wide; - } - m = 1; - m = m << i; - dev->wide_id[0] |= m; -not_wide: - if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) { - m = 1; - m = m << i; - if ((dev->async[0] & m) != 0) { - goto set_sync; - } - } - continue; -set_sync: - if (dev->sp[0][i] == 0x02) { - synu[4] = 0x0c; - synuw[4] = 0x0c; - } else { - if (dev->sp[0][i] >= 0x03) { - synu[4] = 0x0a; - synuw[4] = 0x0a; - } - } - tmport = wkport + 0x5b; - j = 0; - if ((m & dev->wide_id[0]) != 0) { - j |= 0x01; - } - outb(j, tmport); - tmport = wkport + 0x43; - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[0][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { - continue; - } - while (inb(tmport) != 0x8e) - cpu_relax(); - -try_sync: - j = 0; - tmport = wkport + 0x54; - outb(0x06, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - if ((m & dev->wide_id[0]) != 0) { - if ((m & dev->ultra_map[0]) != 0) { - outb(synuw[j++], tmport); - } else { - outb(synw[j++], tmport); - } - } else { - if ((m & dev->ultra_map[0]) != 0) { - outb(synu[j++], tmport); - } else { - outb(synn[j++], tmport); - } - } - tmport += 0x06; - } - } - tmport -= 0x08; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto try_sync; - } - continue; -phase_outs: - tmport = wkport + 0x58; - outb(0x20, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) { - if ((inb(tmport) & 0x01) != 0x00) { - tmport -= 0x06; - outb(0x00, tmport); - tmport += 0x06; - } - } - tmport -= 0x08; - j = inb(tmport); - if (j == 0x85) { - goto tar_dcons; - } - j &= 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto phase_outs; - } - continue; -phase_ins: - tmport = wkport + 0x54; - outb(0x06, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - k = 0; -phase_ins1: - j = inb(tmport); - if ((j & 0x01) != 0x00) { - tmport -= 0x06; - mbuf[k++] = inb(tmport); - tmport += 0x06; - goto phase_ins1; - } - if ((j & 0x80) == 0x00) { - goto phase_ins1; - } - tmport -= 0x08; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - j = inb(tmport); - if (j == 0x85) { - goto tar_dcons; - } - j &= 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto phase_outs; - } - continue; -phase_cmds: - tmport = wkport + 0x50; - outb(0x30, tmport); -tar_dcons: - tmport = wkport + 0x54; - outb(0x00, tmport); - tmport += 0x04; - outb(0x08, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - continue; - } - if (mbuf[0] != 0x01) { - continue; - } - if (mbuf[1] != 0x03) { - continue; - } - if (mbuf[4] == 0x00) { - continue; - } - if (mbuf[3] > 0x64) { - continue; - } - if (mbuf[4] > 0x0e) { - mbuf[4] = 0x0e; - } - dev->id[0][i].devsp = mbuf[4]; - if (mbuf[3] < 0x0c) { - j = 0xb0; - goto set_syn_ok; - } - if ((mbuf[3] < 0x0d) && (rmb == 0)) { - j = 0xa0; - goto set_syn_ok; - } - if (mbuf[3] < 0x1a) { - j = 0x20; - goto set_syn_ok; - } - if (mbuf[3] < 0x33) { - j = 0x40; - goto set_syn_ok; - } - if (mbuf[3] < 0x4c) { - j = 0x50; - goto set_syn_ok; - } - j = 0x60; -set_syn_ok: - dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j; - } -} - -static void atp870u_free_tables(struct Scsi_Host *host) -{ - struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata; - int j, k; - for (j=0; j < 2; j++) { - for (k = 0; k < 16; k++) { - if (!atp_dev->id[j][k].prd_table) - continue; - pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prd_bus); - atp_dev->id[j][k].prd_table = NULL; - } - } -} - -static int atp870u_init_tables(struct Scsi_Host *host) -{ - struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata; - int c,k; - for(c=0;c < 2;c++) { - for(k=0;k<16;k++) { - atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prd_bus)); - if (!atp_dev->id[c][k].prd_table) { - printk("atp870u_init_tables fail\n"); - atp870u_free_tables(host); - return -ENOMEM; - } - atp_dev->id[c][k].prdaddr = atp_dev->id[c][k].prd_bus; - atp_dev->id[c][k].devsp=0x20; - atp_dev->id[c][k].devtype = 0x7f; - atp_dev->id[c][k].curr_req = NULL; - } - - atp_dev->active_id[c] = 0; - atp_dev->wide_id[c] = 0; - atp_dev->host_id[c] = 0x07; - atp_dev->quhd[c] = 0; - atp_dev->quend[c] = 0; - atp_dev->last_cmd[c] = 0xff; - atp_dev->in_snd[c] = 0; - atp_dev->in_int[c] = 0; - - for (k = 0; k < qcnt; k++) { - atp_dev->quereq[c][k] = NULL; - } - for (k = 0; k < 16; k++) { - atp_dev->id[c][k].curr_req = NULL; - atp_dev->sp[c][k] = 0x04; - } - } - return 0; -} - -/* return non-zero on detection */ -static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - unsigned char k, m, c; - unsigned long flags; - unsigned int base_io, tmport, error,n; - unsigned char host_id; - struct Scsi_Host *shpnt = NULL; - struct atp_unit *atpdev, *p; - unsigned char setupdata[2][16]; - int count = 0; - - atpdev = kzalloc(sizeof(*atpdev), GFP_KERNEL); - if (!atpdev) - return -ENOMEM; - - if (pci_enable_device(pdev)) - goto err_eio; - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_INFO "atp870u: use 32bit DMA mask.\n"); - } else { - printk(KERN_ERR "atp870u: DMA mask required but not available.\n"); - goto err_eio; - } - - /* - * It's probably easier to weed out some revisions like - * this than via the PCI device table - */ - if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) { - atpdev->chip_ver = pdev->revision; - if (atpdev->chip_ver < 2) - goto err_eio; - } - - switch (ent->device) { - case PCI_DEVICE_ID_ARTOP_AEC7612UW: - case PCI_DEVICE_ID_ARTOP_AEC7612SUW: - case ATP880_DEVID1: - case ATP880_DEVID2: - case ATP885_DEVID: - atpdev->chip_ver = 0x04; - default: - break; - } - base_io = pci_resource_start(pdev, 0); - base_io &= 0xfffffff8; - - if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) { - atpdev->chip_ver = pdev->revision; - pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803 - - host_id = inb(base_io + 0x39); - host_id >>= 0x04; - - printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d" - " IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); - atpdev->ioport[0] = base_io + 0x40; - atpdev->pciport[0] = base_io + 0x28; - atpdev->dev_id = ent->device; - atpdev->host_id[0] = host_id; - - tmport = base_io + 0x22; - atpdev->scam_on = inb(tmport); - tmport += 0x13; - atpdev->global_map[0] = inb(tmport); - tmport += 0x07; - atpdev->ultra_map[0] = inw(tmport); - - n = 0x3f09; -next_fblk_880: - if (n >= 0x4000) - goto flash_ok_880; - - m = 0; - outw(n, base_io + 0x34); - n += 0x0002; - if (inb(base_io + 0x30) == 0xff) - goto flash_ok_880; - - atpdev->sp[0][m++] = inb(base_io + 0x30); - atpdev->sp[0][m++] = inb(base_io + 0x31); - atpdev->sp[0][m++] = inb(base_io + 0x32); - atpdev->sp[0][m++] = inb(base_io + 0x33); - outw(n, base_io + 0x34); - n += 0x0002; - atpdev->sp[0][m++] = inb(base_io + 0x30); - atpdev->sp[0][m++] = inb(base_io + 0x31); - atpdev->sp[0][m++] = inb(base_io + 0x32); - atpdev->sp[0][m++] = inb(base_io + 0x33); - outw(n, base_io + 0x34); - n += 0x0002; - atpdev->sp[0][m++] = inb(base_io + 0x30); - atpdev->sp[0][m++] = inb(base_io + 0x31); - atpdev->sp[0][m++] = inb(base_io + 0x32); - atpdev->sp[0][m++] = inb(base_io + 0x33); - outw(n, base_io + 0x34); - n += 0x0002; - atpdev->sp[0][m++] = inb(base_io + 0x30); - atpdev->sp[0][m++] = inb(base_io + 0x31); - atpdev->sp[0][m++] = inb(base_io + 0x32); - atpdev->sp[0][m++] = inb(base_io + 0x33); - n += 0x0018; - goto next_fblk_880; -flash_ok_880: - outw(0, base_io + 0x34); - atpdev->ultra_map[0] = 0; - atpdev->async[0] = 0; - for (k = 0; k < 16; k++) { - n = 1; - n = n << k; - if (atpdev->sp[0][k] > 1) { - atpdev->ultra_map[0] |= n; - } else { - if (atpdev->sp[0][k] == 0) - atpdev->async[0] |= n; - } - } - atpdev->async[0] = ~(atpdev->async[0]); - outb(atpdev->global_map[0], base_io + 0x35); - - shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); - if (!shpnt) - goto err_nomem; - - p = (struct atp_unit *)&shpnt->hostdata; - - atpdev->host = shpnt; - atpdev->pdev = pdev; - pci_set_drvdata(pdev, p); - memcpy(p, atpdev, sizeof(*atpdev)); - if (atp870u_init_tables(shpnt) < 0) { - printk(KERN_ERR "Unable to allocate tables for Acard controller\n"); - goto unregister; - } - - if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp880i", shpnt)) { - printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq); - goto free_tables; - } - - spin_lock_irqsave(shpnt->host_lock, flags); - tmport = base_io + 0x38; - k = inb(tmport) & 0x80; - outb(k, tmport); - tmport += 0x03; - outb(0x20, tmport); - mdelay(32); - outb(0, tmport); - mdelay(32); - tmport = base_io + 0x5b; - inb(tmport); - tmport -= 0x04; - inb(tmport); - tmport = base_io + 0x40; - outb((host_id | 0x08), tmport); - tmport += 0x18; - outb(0, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) - mdelay(1); - tmport -= 0x08; - inb(tmport); - tmport = base_io + 0x41; - outb(8, tmport++); - outb(0x7f, tmport); - tmport = base_io + 0x51; - outb(0x20, tmport); - - tscam(shpnt); - is880(p, base_io); - tmport = base_io + 0x38; - outb(0xb0, tmport); - shpnt->max_id = 16; - shpnt->this_id = host_id; - shpnt->unique_id = base_io; - shpnt->io_port = base_io; - shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */ - shpnt->irq = pdev->irq; - } else if (ent->device == ATP885_DEVID) { - printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n" - , base_io, pdev->irq); - - atpdev->pdev = pdev; - atpdev->dev_id = ent->device; - atpdev->baseport = base_io; - atpdev->ioport[0] = base_io + 0x80; - atpdev->ioport[1] = base_io + 0xc0; - atpdev->pciport[0] = base_io + 0x40; - atpdev->pciport[1] = base_io + 0x50; - - shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); - if (!shpnt) - goto err_nomem; - - p = (struct atp_unit *)&shpnt->hostdata; - - atpdev->host = shpnt; - atpdev->pdev = pdev; - pci_set_drvdata(pdev, p); - memcpy(p, atpdev, sizeof(struct atp_unit)); - if (atp870u_init_tables(shpnt) < 0) - goto unregister; - -#ifdef ED_DBGP - printk("request_irq() shpnt %p hostdata %p\n", shpnt, p); -#endif - if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870u", shpnt)) { - printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); - goto free_tables; - } - - spin_lock_irqsave(shpnt->host_lock, flags); - - c=inb(base_io + 0x29); - outb((c | 0x04),base_io + 0x29); - - n=0x1f80; -next_fblk_885: - if (n >= 0x2000) { - goto flash_ok_885; - } - outw(n,base_io + 0x3c); - if (inl(base_io + 0x38) == 0xffffffff) { - goto flash_ok_885; - } - for (m=0; m < 2; m++) { - p->global_map[m]= 0; - for (k=0; k < 4; k++) { - outw(n++,base_io + 0x3c); - ((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38); - } - for (k=0; k < 4; k++) { - outw(n++,base_io + 0x3c); - ((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38); - } - n += 8; - } - goto next_fblk_885; -flash_ok_885: -#ifdef ED_DBGP - printk( "Flash Read OK\n"); -#endif - c=inb(base_io + 0x29); - outb((c & 0xfb),base_io + 0x29); - for (c=0;c < 2;c++) { - p->ultra_map[c]=0; - p->async[c] = 0; - for (k=0; k < 16; k++) { - n=1; - n = n << k; - if (p->sp[c][k] > 1) { - p->ultra_map[c] |= n; - } else { - if (p->sp[c][k] == 0) { - p->async[c] |= n; - } - } - } - p->async[c] = ~(p->async[c]); - - if (p->global_map[c] == 0) { - k=setupdata[c][1]; - if ((k & 0x40) != 0) - p->global_map[c] |= 0x20; - k &= 0x07; - p->global_map[c] |= k; - if ((setupdata[c][2] & 0x04) != 0) - p->global_map[c] |= 0x08; - p->host_id[c] = setupdata[c][0] & 0x07; - } - } - - k = inb(base_io + 0x28) & 0x8f; - k |= 0x10; - outb(k, base_io + 0x28); - outb(0x80, base_io + 0x41); - outb(0x80, base_io + 0x51); - mdelay(100); - outb(0, base_io + 0x41); - outb(0, base_io + 0x51); - mdelay(1000); - inb(base_io + 0x9b); - inb(base_io + 0x97); - inb(base_io + 0xdb); - inb(base_io + 0xd7); - tmport = base_io + 0x80; - k=p->host_id[0]; - if (k > 7) - k = (k & 0x07) | 0x40; - k |= 0x08; - outb(k, tmport); - tmport += 0x18; - outb(0, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) - cpu_relax(); - - tmport -= 0x08; - inb(tmport); - tmport = base_io + 0x81; - outb(8, tmport++); - outb(0x7f, tmport); - tmport = base_io + 0x91; - outb(0x20, tmport); - - tmport = base_io + 0xc0; - k=p->host_id[1]; - if (k > 7) - k = (k & 0x07) | 0x40; - k |= 0x08; - outb(k, tmport); - tmport += 0x18; - outb(0, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) - cpu_relax(); - - tmport -= 0x08; - inb(tmport); - tmport = base_io + 0xc1; - outb(8, tmport++); - outb(0x7f, tmport); - tmport = base_io + 0xd1; - outb(0x20, tmport); - - tscam_885(); - printk(KERN_INFO " Scanning Channel A SCSI Device ...\n"); - is885(p, base_io + 0x80, 0); - printk(KERN_INFO " Scanning Channel B SCSI Device ...\n"); - is885(p, base_io + 0xc0, 1); - - k = inb(base_io + 0x28) & 0xcf; - k |= 0xc0; - outb(k, base_io + 0x28); - k = inb(base_io + 0x1f) | 0x80; - outb(k, base_io + 0x1f); - k = inb(base_io + 0x29) | 0x01; - outb(k, base_io + 0x29); -#ifdef ED_DBGP - //printk("atp885: atp_host[0] 0x%p\n", atp_host[0]); -#endif - shpnt->max_id = 16; - shpnt->max_lun = (p->global_map[0] & 0x07) + 1; - shpnt->max_channel = 1; - shpnt->this_id = p->host_id[0]; - shpnt->unique_id = base_io; - shpnt->io_port = base_io; - shpnt->n_io_port = 0xff; /* Number of bytes of I/O space used */ - shpnt->irq = pdev->irq; - - } else { - error = pci_read_config_byte(pdev, 0x49, &host_id); - - printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d " - "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); - - atpdev->ioport[0] = base_io; - atpdev->pciport[0] = base_io + 0x20; - atpdev->dev_id = ent->device; - host_id &= 0x07; - atpdev->host_id[0] = host_id; - tmport = base_io + 0x22; - atpdev->scam_on = inb(tmport); - tmport += 0x0b; - atpdev->global_map[0] = inb(tmport++); - atpdev->ultra_map[0] = inw(tmport); - - if (atpdev->ultra_map[0] == 0) { - atpdev->scam_on = 0x00; - atpdev->global_map[0] = 0x20; - atpdev->ultra_map[0] = 0xffff; - } - - shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); - if (!shpnt) - goto err_nomem; - - p = (struct atp_unit *)&shpnt->hostdata; - - atpdev->host = shpnt; - atpdev->pdev = pdev; - pci_set_drvdata(pdev, p); - memcpy(p, atpdev, sizeof(*atpdev)); - if (atp870u_init_tables(shpnt) < 0) - goto unregister; - - if (request_irq(pdev->irq, atp870u_intr_handle, IRQF_SHARED, "atp870i", shpnt)) { - printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq); - goto free_tables; - } - - spin_lock_irqsave(shpnt->host_lock, flags); - if (atpdev->chip_ver > 0x07) { /* check if atp876 chip then enable terminator */ - tmport = base_io + 0x3e; - outb(0x00, tmport); - } - - tmport = base_io + 0x3a; - k = (inb(tmport) & 0xf3) | 0x10; - outb(k, tmport); - outb((k & 0xdf), tmport); - mdelay(32); - outb(k, tmport); - mdelay(32); - tmport = base_io; - outb((host_id | 0x08), tmport); - tmport += 0x18; - outb(0, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) - mdelay(1); - - tmport -= 0x08; - inb(tmport); - tmport = base_io + 1; - outb(8, tmport++); - outb(0x7f, tmport); - tmport = base_io + 0x11; - outb(0x20, tmport); - - tscam(shpnt); - is870(p, base_io); - tmport = base_io + 0x3a; - outb((inb(tmport) & 0xef), tmport); - tmport++; - outb((inb(tmport) | 0x20), tmport); - if (atpdev->chip_ver == 4) - shpnt->max_id = 16; - else - shpnt->max_id = 8; - shpnt->this_id = host_id; - shpnt->unique_id = base_io; - shpnt->io_port = base_io; - shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ - shpnt->irq = pdev->irq; - } - spin_unlock_irqrestore(shpnt->host_lock, flags); - if(ent->device==ATP885_DEVID) { - if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */ - goto request_io_fail; - } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) { - if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */ - goto request_io_fail; - } else { - if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */ - goto request_io_fail; - } - count++; - if (scsi_add_host(shpnt, &pdev->dev)) - goto scsi_add_fail; - scsi_scan_host(shpnt); -#ifdef ED_DBGP - printk("atp870u_prob : exit\n"); -#endif - return 0; - -scsi_add_fail: - printk("atp870u_prob:scsi_add_fail\n"); - if(ent->device==ATP885_DEVID) { - release_region(base_io, 0xff); - } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) { - release_region(base_io, 0x60); - } else { - release_region(base_io, 0x40); - } -request_io_fail: - printk("atp870u_prob:request_io_fail\n"); - free_irq(pdev->irq, shpnt); -free_tables: - printk("atp870u_prob:free_table\n"); - atp870u_free_tables(shpnt); -unregister: - printk("atp870u_prob:unregister\n"); - scsi_host_put(shpnt); - return -1; -err_eio: - kfree(atpdev); - return -EIO; -err_nomem: - kfree(atpdev); - return -ENOMEM; -} - -/* The abort command does not leave the device in a clean state where - it is available to be used again. Until this gets worked out, we will - leave it commented out. */ - -static int atp870u_abort(struct scsi_cmnd * SCpnt) -{ - unsigned char j, k, c; - struct scsi_cmnd *workrequ; - unsigned int tmport; - struct atp_unit *dev; - struct Scsi_Host *host; - host = SCpnt->device->host; - - dev = (struct atp_unit *)&host->hostdata; - c = scmd_channel(SCpnt); - printk(" atp870u: abort Channel = %x \n", c); - printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]); - printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]); - tmport = dev->ioport[c]; - for (j = 0; j < 0x18; j++) { - printk(" r%2x=%2x", j, inb(tmport++)); - } - tmport += 0x04; - printk(" r1c=%2x", inb(tmport)); - tmport += 0x03; - printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd[c]); - tmport= dev->pciport[c]; - printk(" d00=%2x", inb(tmport)); - tmport += 0x02; - printk(" d02=%2x", inb(tmport)); - for(j=0;j<16;j++) { - if (dev->id[c][j].curr_req != NULL) { - workrequ = dev->id[c][j].curr_req; - printk("\n que cdb= "); - for (k=0; k < workrequ->cmd_len; k++) { - printk(" %2x ",workrequ->cmnd[k]); - } - printk(" last_lenu= %x ",(unsigned int)dev->id[c][j].last_len); - } - } - return SUCCESS; -} - -static const char *atp870u_info(struct Scsi_Host *notused) -{ - static char buffer[128]; - - strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.6+ac "); - - return buffer; -} - -#define BLS buffer + len + size -static int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer, - char **start, off_t offset, int length, int inout) -{ - static u8 buff[512]; - int size = 0; - int len = 0; - off_t begin = 0; - off_t pos = 0; - - if (inout) - return -EINVAL; - if (offset == 0) - memset(buff, 0, sizeof(buff)); - size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.6+ac\n"); - len += size; - pos = begin + len; - size = 0; - - size += sprintf(BLS, "\n"); - size += sprintf(BLS, "Adapter Configuration:\n"); - size += sprintf(BLS, " Base IO: %#.4lx\n", HBAptr->io_port); - size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); - len += size; - pos = begin + len; - - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) { - len = length; /* Ending slop */ - } - return (len); -} - - -static int atp870u_biosparam(struct scsi_device *disk, struct block_device *dev, - sector_t capacity, int *ip) -{ - int heads, sectors, cylinders; - - heads = 64; - sectors = 32; - cylinders = (unsigned long)capacity / (heads * sectors); - if (cylinders > 1024) { - heads = 255; - sectors = 63; - cylinders = (unsigned long)capacity / (heads * sectors); - } - ip[0] = heads; - ip[1] = sectors; - ip[2] = cylinders; - - return 0; -} - -static void atp870u_remove (struct pci_dev *pdev) -{ - struct atp_unit *devext = pci_get_drvdata(pdev); - struct Scsi_Host *pshost = devext->host; - - - scsi_remove_host(pshost); - printk(KERN_INFO "free_irq : %d\n",pshost->irq); - free_irq(pshost->irq, pshost); - release_region(pshost->io_port, pshost->n_io_port); - printk(KERN_INFO "atp870u_free_tables : %p\n",pshost); - atp870u_free_tables(pshost); - printk(KERN_INFO "scsi_host_put : %p\n",pshost); - scsi_host_put(pshost); - printk(KERN_INFO "pci_set_drvdata : %p\n",pdev); - pci_set_drvdata(pdev, NULL); -} -MODULE_LICENSE("GPL"); - -static struct scsi_host_template atp870u_template = { - .module = THIS_MODULE, - .name = "atp870u" /* name */, - .proc_name = "atp870u", - .proc_info = atp870u_proc_info, - .info = atp870u_info /* info */, - .queuecommand = atp870u_queuecommand /* queuecommand */, - .eh_abort_handler = atp870u_abort /* abort */, - .bios_param = atp870u_biosparam /* biosparm */, - .can_queue = qcnt /* can_queue */, - .this_id = 7 /* SCSI ID */, - .sg_tablesize = ATP870U_SCATTER /*SG_ALL*/ /*SG_NONE*/, - .cmd_per_lun = ATP870U_CMDLUN /* commands per lun */, - .use_clustering = ENABLE_CLUSTERING, - .max_sectors = ATP870U_MAX_SECTORS, -}; - -static struct pci_device_id atp870u_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP885_DEVID) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID1) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID2) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7610) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612UW) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612U) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612S) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612D) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612SUW) }, - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_8060) }, - { 0, }, -}; - -MODULE_DEVICE_TABLE(pci, atp870u_id_table); - -static struct pci_driver atp870u_driver = { - .id_table = atp870u_id_table, - .name = "atp870u", - .probe = atp870u_probe, - .remove = __devexit_p(atp870u_remove), -}; - -static int __init atp870u_init(void) -{ -#ifdef ED_DBGP - printk("atp870u_init: Entry\n"); -#endif - return pci_register_driver(&atp870u_driver); -} - -static void __exit atp870u_exit(void) -{ -#ifdef ED_DBGP - printk("atp870u_exit: Entry\n"); -#endif - pci_unregister_driver(&atp870u_driver); -} - -static void tscam_885(void) -{ - unsigned char i; - - for (i = 0; i < 0x2; i++) { - mdelay(300); - } - return; -} - - - -static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c) -{ - unsigned int tmport; - unsigned char i, j, k, rmb, n, lvdmode; - unsigned short int m; - static unsigned char mbuf[512]; - static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6}; - static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6}; - static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; - unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; - static unsigned char synw[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; - unsigned char synuw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; - static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0}; - static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 }; - - lvdmode=inb(wkport + 0x1b) >> 7; - - for (i = 0; i < 16; i++) { - m = 1; - m = m << i; - if ((m & dev->active_id[c]) != 0) { - continue; - } - if (i == dev->host_id[c]) { - printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[c]); - continue; - } - tmport = wkport + 0x1b; - outb(0x01, tmport); - tmport = wkport + 0x01; - outb(0x08, tmport++); - outb(0x7f, tmport++); - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[c][i].devsp, tmport++); - - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - j = i; - if ((j & 0x08) != 0) { - j = (j & 0x07) | 0x40; - } - outb(j, tmport); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { - continue; - } - while (inb(tmport) != 0x8e) - cpu_relax(); - dev->active_id[c] |= m; - - tmport = wkport + 0x10; - outb(0x30, tmport); - tmport = wkport + 0x14; - outb(0x00, tmport); - -phase_cmd: - tmport = wkport + 0x18; - outb(0x08, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - tmport = wkport + 0x10; - outb(0x41, tmport); - goto phase_cmd; - } -sel_ok: - tmport = wkport + 0x03; - outb(inqd[0], tmport++); - outb(inqd[1], tmport++); - outb(inqd[2], tmport++); - outb(inqd[3], tmport++); - outb(inqd[4], tmport++); - outb(inqd[5], tmport); - tmport += 0x07; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[c][i].devsp, tmport++); - outb(0, tmport++); - outb(inqd[6], tmport++); - outb(inqd[7], tmport++); - tmport += 0x03; - outb(inqd[8], tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { - continue; - } - while (inb(tmport) != 0x8e) - cpu_relax(); - tmport = wkport + 0x1b; - outb(0x00, tmport); - tmport = wkport + 0x18; - outb(0x08, tmport); - tmport += 0x07; - j = 0; -rd_inq_data: - k = inb(tmport); - if ((k & 0x01) != 0) { - tmport -= 0x06; - mbuf[j++] = inb(tmport); - tmport += 0x06; - goto rd_inq_data; - } - if ((k & 0x80) == 0) { - goto rd_inq_data; - } - tmport -= 0x08; - j = inb(tmport); - if (j == 0x16) { - goto inq_ok; - } - tmport = wkport + 0x10; - outb(0x46, tmport); - tmport += 0x02; - outb(0, tmport++); - outb(0, tmport++); - outb(0, tmport++); - tmport += 0x03; - outb(0x08, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - if (inb(tmport) != 0x16) { - goto sel_ok; - } -inq_ok: - mbuf[36] = 0; - printk( KERN_INFO" ID: %2d %s\n", i, &mbuf[8]); - dev->id[c][i].devtype = mbuf[0]; - rmb = mbuf[1]; - n = mbuf[7]; - if ((mbuf[7] & 0x60) == 0) { - goto not_wide; - } - if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) { - goto not_wide; - } - if (lvdmode == 0) { - goto chg_wide; - } - if (dev->sp[c][i] != 0x04) { // force u2 - goto chg_wide; - } - - tmport = wkport + 0x1b; - outb(0x01, tmport); - tmport = wkport + 0x03; - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[c][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { - continue; - } - while (inb(tmport) != 0x8e) - cpu_relax(); -try_u3: - j = 0; - tmport = wkport + 0x14; - outb(0x09, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(u3[j++], tmport); - tmport += 0x06; - } - cpu_relax(); - } - tmport -= 0x08; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto u3p_in; - } - if (j == 0x0a) { - goto u3p_cmd; - } - if (j == 0x0e) { - goto try_u3; - } - continue; -u3p_out: - tmport = wkport + 0x18; - outb(0x20, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(0, tmport); - tmport += 0x06; - } - cpu_relax(); - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto u3p_in; - } - if (j == 0x0a) { - goto u3p_cmd; - } - if (j == 0x0e) { - goto u3p_out; - } - continue; -u3p_in: - tmport = wkport + 0x14; - outb(0x09, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - k = 0; -u3p_in1: - j = inb(tmport); - if ((j & 0x01) != 0) { - tmport -= 0x06; - mbuf[k++] = inb(tmport); - tmport += 0x06; - goto u3p_in1; - } - if ((j & 0x80) == 0x00) { - goto u3p_in1; - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto u3p_in; - } - if (j == 0x0a) { - goto u3p_cmd; - } - if (j == 0x0e) { - goto u3p_out; - } - continue; -u3p_cmd: - tmport = wkport + 0x10; - outb(0x30, tmport); - tmport = wkport + 0x14; - outb(0x00, tmport); - tmport += 0x04; - outb(0x08, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00); - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - if (j == 0x4e) { - goto u3p_out; - } - continue; - } - if (mbuf[0] != 0x01) { - goto chg_wide; - } - if (mbuf[1] != 0x06) { - goto chg_wide; - } - if (mbuf[2] != 0x04) { - goto chg_wide; - } - if (mbuf[3] == 0x09) { - m = 1; - m = m << i; - dev->wide_id[c] |= m; - dev->id[c][i].devsp = 0xce; -#ifdef ED_DBGP - printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp); -#endif - continue; - } -chg_wide: - tmport = wkport + 0x1b; - outb(0x01, tmport); - tmport = wkport + 0x03; - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[c][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { - continue; - } - while (inb(tmport) != 0x8e) - cpu_relax(); -try_wide: - j = 0; - tmport = wkport + 0x14; - outb(0x05, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(wide[j++], tmport); - tmport += 0x06; - } - cpu_relax(); - } - tmport -= 0x08; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto try_wide; - } - continue; -widep_out: - tmport = wkport + 0x18; - outb(0x20, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - outb(0, tmport); - tmport += 0x06; - } - cpu_relax(); - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto widep_out; - } - continue; -widep_in: - tmport = wkport + 0x14; - outb(0xff, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - k = 0; -widep_in1: - j = inb(tmport); - if ((j & 0x01) != 0) { - tmport -= 0x06; - mbuf[k++] = inb(tmport); - tmport += 0x06; - goto widep_in1; - } - if ((j & 0x80) == 0x00) { - goto widep_in1; - } - tmport -= 0x08; - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto widep_in; - } - if (j == 0x0a) { - goto widep_cmd; - } - if (j == 0x0e) { - goto widep_out; - } - continue; -widep_cmd: - tmport = wkport + 0x10; - outb(0x30, tmport); - tmport = wkport + 0x14; - outb(0x00, tmport); - tmport += 0x04; - outb(0x08, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - if (j == 0x4e) { - goto widep_out; - } - continue; - } - if (mbuf[0] != 0x01) { - goto not_wide; - } - if (mbuf[1] != 0x02) { - goto not_wide; - } - if (mbuf[2] != 0x03) { - goto not_wide; - } - if (mbuf[3] != 0x01) { - goto not_wide; - } - m = 1; - m = m << i; - dev->wide_id[c] |= m; -not_wide: - if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) || - ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) { - m = 1; - m = m << i; - if ((dev->async[c] & m) != 0) { - goto set_sync; - } - } - continue; -set_sync: - if (dev->sp[c][i] == 0x02) { - synu[4]=0x0c; - synuw[4]=0x0c; - } else { - if (dev->sp[c][i] >= 0x03) { - synu[4]=0x0a; - synuw[4]=0x0a; - } - } - tmport = wkport + 0x1b; - j = 0; - if ((m & dev->wide_id[c]) != 0) { - j |= 0x01; - } - outb(j, tmport); - tmport = wkport + 0x03; - outb(satn[0], tmport++); - outb(satn[1], tmport++); - outb(satn[2], tmport++); - outb(satn[3], tmport++); - outb(satn[4], tmport++); - outb(satn[5], tmport++); - tmport += 0x06; - outb(0, tmport); - tmport += 0x02; - outb(dev->id[c][i].devsp, tmport++); - outb(0, tmport++); - outb(satn[6], tmport++); - outb(satn[7], tmport++); - tmport += 0x03; - outb(satn[8], tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { - continue; - } - while (inb(tmport) != 0x8e) - cpu_relax(); -try_sync: - j = 0; - tmport = wkport + 0x14; - outb(0x06, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - - while ((inb(tmport) & 0x80) == 0) { - if ((inb(tmport) & 0x01) != 0) { - tmport -= 0x06; - if ((m & dev->wide_id[c]) != 0) { - if ((m & dev->ultra_map[c]) != 0) { - outb(synuw[j++], tmport); - } else { - outb(synw[j++], tmport); - } - } else { - if ((m & dev->ultra_map[c]) != 0) { - outb(synu[j++], tmport); - } else { - outb(synn[j++], tmport); - } - } - tmport += 0x06; - } - } - tmport -= 0x08; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - j = inb(tmport) & 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto try_sync; - } - continue; -phase_outs: - tmport = wkport + 0x18; - outb(0x20, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) { - if ((inb(tmport) & 0x01) != 0x00) { - tmport -= 0x06; - outb(0x00, tmport); - tmport += 0x06; - } - cpu_relax(); - } - tmport -= 0x08; - j = inb(tmport); - if (j == 0x85) { - goto tar_dcons; - } - j &= 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto phase_outs; - } - continue; -phase_ins: - tmport = wkport + 0x14; - outb(0x06, tmport); - tmport += 0x04; - outb(0x20, tmport); - tmport += 0x07; - k = 0; -phase_ins1: - j = inb(tmport); - if ((j & 0x01) != 0x00) { - tmport -= 0x06; - mbuf[k++] = inb(tmport); - tmport += 0x06; - goto phase_ins1; - } - if ((j & 0x80) == 0x00) { - goto phase_ins1; - } - tmport -= 0x08; - while ((inb(tmport) & 0x80) == 0x00); - j = inb(tmport); - if (j == 0x85) { - goto tar_dcons; - } - j &= 0x0f; - if (j == 0x0f) { - goto phase_ins; - } - if (j == 0x0a) { - goto phase_cmds; - } - if (j == 0x0e) { - goto phase_outs; - } - continue; -phase_cmds: - tmport = wkport + 0x10; - outb(0x30, tmport); -tar_dcons: - tmport = wkport + 0x14; - outb(0x00, tmport); - tmport += 0x04; - outb(0x08, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0x00) - cpu_relax(); - tmport -= 0x08; - j = inb(tmport); - if (j != 0x16) { - continue; - } - if (mbuf[0] != 0x01) { - continue; - } - if (mbuf[1] != 0x03) { - continue; - } - if (mbuf[4] == 0x00) { - continue; - } - if (mbuf[3] > 0x64) { - continue; - } - if (mbuf[4] > 0x0e) { - mbuf[4] = 0x0e; - } - dev->id[c][i].devsp = mbuf[4]; - if (mbuf[3] < 0x0c){ - j = 0xb0; - goto set_syn_ok; - } - if ((mbuf[3] < 0x0d) && (rmb == 0)) { - j = 0xa0; - goto set_syn_ok; - } - if (mbuf[3] < 0x1a) { - j = 0x20; - goto set_syn_ok; - } - if (mbuf[3] < 0x33) { - j = 0x40; - goto set_syn_ok; - } - if (mbuf[3] < 0x4c) { - j = 0x50; - goto set_syn_ok; - } - j = 0x60; - set_syn_ok: - dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j; -#ifdef ED_DBGP - printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp); -#endif - } - tmport = wkport + 0x16; - outb(0x80, tmport); -} - -module_init(atp870u_init); -module_exit(atp870u_exit); - diff --git a/ANDROID_3.4.5/drivers/scsi/atp870u.h b/ANDROID_3.4.5/drivers/scsi/atp870u.h deleted file mode 100644 index 62bae64a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/atp870u.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef _ATP870U_H -#define _ATP870U_H - -#include -#include - -/* I/O Port */ - -#define MAX_CDB 12 -#define MAX_SENSE 14 -#define qcnt 32 -#define ATP870U_SCATTER 128 -#define ATP870U_CMDLUN 1 - -#define MAX_ADAPTER 8 -#define MAX_SCSI_ID 16 -#define ATP870U_MAX_SECTORS 128 - -#define ATP885_DEVID 0x808A -#define ATP880_DEVID1 0x8080 -#define ATP880_DEVID2 0x8081 - -//#define ED_DBGP - -struct atp_unit -{ - unsigned long baseport; - unsigned long ioport[2]; - unsigned long pciport[2]; - unsigned long irq; - unsigned char last_cmd[2]; - unsigned char in_snd[2]; - unsigned char in_int[2]; - unsigned char quhd[2]; - unsigned char quend[2]; - unsigned char global_map[2]; - unsigned char chip_ver; - unsigned char scam_on; - unsigned char host_id[2]; - unsigned int working[2]; - unsigned short wide_id[2]; - unsigned short active_id[2]; - unsigned short ultra_map[2]; - unsigned short async[2]; - unsigned short dev_id; - unsigned char sp[2][16]; - unsigned char r1f[2][16]; - struct scsi_cmnd *quereq[2][qcnt]; - struct atp_id - { - unsigned char dirct; - unsigned char devsp; - unsigned char devtype; - unsigned long tran_len; - unsigned long last_len; - unsigned char *prd_pos; - unsigned char *prd_table; /* Kernel address of PRD table */ - dma_addr_t prd_bus; /* Bus address of PRD */ - dma_addr_t prdaddr; /* Dynamically updated in driver */ - struct scsi_cmnd *curr_req; - } id[2][16]; - struct Scsi_Host *host; - struct pci_dev *pdev; - unsigned int unit; -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/Kconfig b/ANDROID_3.4.5/drivers/scsi/be2iscsi/Kconfig deleted file mode 100644 index ceaca32e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config BE2ISCSI - tristate "ServerEngines' 10Gbps iSCSI - BladeEngine 2" - depends on PCI && SCSI && NET - select SCSI_ISCSI_ATTRS - select ISCSI_BOOT_SYSFS - - help - This driver implements the iSCSI functionality for ServerEngines' - 10Gbps Storage adapter - BladeEngine 2. diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/Makefile b/ANDROID_3.4.5/drivers/scsi/be2iscsi/Makefile deleted file mode 100644 index c11f443e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile to build the iSCSI driver for ServerEngine's BladeEngine. -# -# - -obj-$(CONFIG_BE2ISCSI) += be2iscsi.o - -be2iscsi-y := be_iscsi.o be_main.o be_mgmt.o be_cmds.o diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be.h b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be.h deleted file mode 100644 index 1d7b976c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be.h +++ /dev/null @@ -1,190 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#ifndef BEISCSI_H -#define BEISCSI_H - -#include -#include -#include -#define FW_VER_LEN 32 -#define MCC_Q_LEN 128 -#define MCC_CQ_LEN 256 -#define MAX_MCC_CMD 16 -/* BladeEngine Generation numbers */ -#define BE_GEN2 2 -#define BE_GEN3 3 - -struct be_dma_mem { - void *va; - dma_addr_t dma; - u32 size; -}; - -struct be_queue_info { - struct be_dma_mem dma_mem; - u16 len; - u16 entry_size; /* Size of an element in the queue */ - u16 id; - u16 tail, head; - bool created; - atomic_t used; /* Number of valid elements in the queue */ -}; - -static inline u32 MODULO(u16 val, u16 limit) -{ - WARN_ON(limit & (limit - 1)); - return val & (limit - 1); -} - -static inline void index_inc(u16 *index, u16 limit) -{ - *index = MODULO((*index + 1), limit); -} - -static inline void *queue_head_node(struct be_queue_info *q) -{ - return q->dma_mem.va + q->head * q->entry_size; -} - -static inline void *queue_get_wrb(struct be_queue_info *q, unsigned int wrb_num) -{ - return q->dma_mem.va + wrb_num * q->entry_size; -} - -static inline void *queue_tail_node(struct be_queue_info *q) -{ - return q->dma_mem.va + q->tail * q->entry_size; -} - -static inline void queue_head_inc(struct be_queue_info *q) -{ - index_inc(&q->head, q->len); -} - -static inline void queue_tail_inc(struct be_queue_info *q) -{ - index_inc(&q->tail, q->len); -} - -/*ISCSI */ - -struct be_eq_obj { - struct be_queue_info q; - struct beiscsi_hba *phba; - struct be_queue_info *cq; - struct blk_iopoll iopoll; -}; - -struct be_mcc_obj { - struct be_queue_info q; - struct be_queue_info cq; -}; - -struct be_ctrl_info { - u8 __iomem *csr; - u8 __iomem *db; /* Door Bell */ - u8 __iomem *pcicfg; /* PCI config space */ - struct pci_dev *pdev; - - /* Mbox used for cmd request/response */ - spinlock_t mbox_lock; /* For serializing mbox cmds to BE card */ - struct be_dma_mem mbox_mem; - /* Mbox mem is adjusted to align to 16 bytes. The allocated addr - * is stored for freeing purpose */ - struct be_dma_mem mbox_mem_alloced; - - /* MCC Rings */ - struct be_mcc_obj mcc_obj; - spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ - spinlock_t mcc_cq_lock; - - wait_queue_head_t mcc_wait[MAX_MCC_CMD + 1]; - unsigned int mcc_tag[MAX_MCC_CMD]; - unsigned int mcc_numtag[MAX_MCC_CMD + 1]; - unsigned short mcc_alloc_index; - unsigned short mcc_free_index; - unsigned int mcc_tag_available; -}; - -#include "be_cmds.h" - -#define PAGE_SHIFT_4K 12 -#define PAGE_SIZE_4K (1 << PAGE_SHIFT_4K) -#define mcc_timeout 120000 /* 5s timeout */ - -/* Returns number of pages spanned by the data starting at the given addr */ -#define PAGES_4K_SPANNED(_address, size) \ - ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) + \ - (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K)) - -/* Byte offset into the page corresponding to given address */ -#define OFFSET_IN_PAGE(addr) \ - ((size_t)(addr) & (PAGE_SIZE_4K-1)) - -/* Returns bit offset within a DWORD of a bitfield */ -#define AMAP_BIT_OFFSET(_struct, field) \ - (((size_t)&(((_struct *)0)->field))%32) - -/* Returns the bit mask of the field that is NOT shifted into location. */ -static inline u32 amap_mask(u32 bitsize) -{ - return (bitsize == 32 ? 0xFFFFFFFF : (1 << bitsize) - 1); -} - -static inline void amap_set(void *ptr, u32 dw_offset, u32 mask, - u32 offset, u32 value) -{ - u32 *dw = (u32 *) ptr + dw_offset; - *dw &= ~(mask << offset); - *dw |= (mask & value) << offset; -} - -#define AMAP_SET_BITS(_struct, field, ptr, val) \ - amap_set(ptr, \ - offsetof(_struct, field)/32, \ - amap_mask(sizeof(((_struct *)0)->field)), \ - AMAP_BIT_OFFSET(_struct, field), \ - val) - -static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset) -{ - u32 *dw = ptr; - return mask & (*(dw + dw_offset) >> offset); -} - -#define AMAP_GET_BITS(_struct, field, ptr) \ - amap_get(ptr, \ - offsetof(_struct, field)/32, \ - amap_mask(sizeof(((_struct *)0)->field)), \ - AMAP_BIT_OFFSET(_struct, field)) - -#define be_dws_cpu_to_le(wrb, len) swap_dws(wrb, len) -#define be_dws_le_to_cpu(wrb, len) swap_dws(wrb, len) -static inline void swap_dws(void *wrb, int len) -{ -#ifdef __BIG_ENDIAN - u32 *dw = wrb; - WARN_ON(len % 4); - do { - *dw = cpu_to_le32(*dw); - dw++; - len -= 4; - } while (len); -#endif /* __BIG_ENDIAN */ -} -#endif /* BEISCSI_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.c b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.c deleted file mode 100644 index cdb15364..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.c +++ /dev/null @@ -1,890 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#include "be.h" -#include "be_mgmt.h" -#include "be_main.h" - -int beiscsi_pci_soft_reset(struct beiscsi_hba *phba) -{ - u32 sreset; - u8 *pci_reset_offset = 0; - u8 *pci_online0_offset = 0; - u8 *pci_online1_offset = 0; - u32 pconline0 = 0; - u32 pconline1 = 0; - u32 i; - - pci_reset_offset = (u8 *)phba->pci_va + BE2_SOFT_RESET; - pci_online0_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE0; - pci_online1_offset = (u8 *)phba->pci_va + BE2_PCI_ONLINE1; - sreset = readl((void *)pci_reset_offset); - sreset |= BE2_SET_RESET; - writel(sreset, (void *)pci_reset_offset); - - i = 0; - while (sreset & BE2_SET_RESET) { - if (i > 64) - break; - msleep(100); - sreset = readl((void *)pci_reset_offset); - i++; - } - - if (sreset & BE2_SET_RESET) { - printk(KERN_ERR "Soft Reset did not deassert\n"); - return -EIO; - } - pconline1 = BE2_MPU_IRAM_ONLINE; - writel(pconline0, (void *)pci_online0_offset); - writel(pconline1, (void *)pci_online1_offset); - - sreset = BE2_SET_RESET; - writel(sreset, (void *)pci_reset_offset); - - i = 0; - while (sreset & BE2_SET_RESET) { - if (i > 64) - break; - msleep(1); - sreset = readl((void *)pci_reset_offset); - i++; - } - if (sreset & BE2_SET_RESET) { - printk(KERN_ERR "MPU Online Soft Reset did not deassert\n"); - return -EIO; - } - return 0; -} - -int be_chk_reset_complete(struct beiscsi_hba *phba) -{ - unsigned int num_loop; - u8 *mpu_sem = 0; - u32 status; - - num_loop = 1000; - mpu_sem = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; - msleep(5000); - - while (num_loop) { - status = readl((void *)mpu_sem); - - if ((status & 0x80000000) || (status & 0x0000FFFF) == 0xC000) - break; - msleep(60); - num_loop--; - } - - if ((status & 0x80000000) || (!num_loop)) { - printk(KERN_ERR "Failed in be_chk_reset_complete" - "status = 0x%x\n", status); - return -EIO; - } - - return 0; -} - -void be_mcc_notify(struct beiscsi_hba *phba) -{ - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; - u32 val = 0; - - val |= mccq->id & DB_MCCQ_RING_ID_MASK; - val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; - iowrite32(val, phba->db_va + DB_MCCQ_OFFSET); -} - -unsigned int alloc_mcc_tag(struct beiscsi_hba *phba) -{ - unsigned int tag = 0; - - if (phba->ctrl.mcc_tag_available) { - tag = phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index]; - phba->ctrl.mcc_tag[phba->ctrl.mcc_alloc_index] = 0; - phba->ctrl.mcc_numtag[tag] = 0; - } - if (tag) { - phba->ctrl.mcc_tag_available--; - if (phba->ctrl.mcc_alloc_index == (MAX_MCC_CMD - 1)) - phba->ctrl.mcc_alloc_index = 0; - else - phba->ctrl.mcc_alloc_index++; - } - return tag; -} - -void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag) -{ - spin_lock(&ctrl->mbox_lock); - tag = tag & 0x000000FF; - ctrl->mcc_tag[ctrl->mcc_free_index] = tag; - if (ctrl->mcc_free_index == (MAX_MCC_CMD - 1)) - ctrl->mcc_free_index = 0; - else - ctrl->mcc_free_index++; - ctrl->mcc_tag_available++; - spin_unlock(&ctrl->mbox_lock); -} - -bool is_link_state_evt(u32 trailer) -{ - return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & - ASYNC_TRAILER_EVENT_CODE_MASK) == - ASYNC_EVENT_CODE_LINK_STATE); -} - -static inline bool be_mcc_compl_is_new(struct be_mcc_compl *compl) -{ - if (compl->flags != 0) { - compl->flags = le32_to_cpu(compl->flags); - WARN_ON((compl->flags & CQE_FLAGS_VALID_MASK) == 0); - return true; - } else - return false; -} - -static inline void be_mcc_compl_use(struct be_mcc_compl *compl) -{ - compl->flags = 0; -} - -static int be_mcc_compl_process(struct be_ctrl_info *ctrl, - struct be_mcc_compl *compl) -{ - u16 compl_status, extd_status; - - be_dws_le_to_cpu(compl, 4); - - compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & - CQE_STATUS_COMPL_MASK; - if (compl_status != MCC_STATUS_SUCCESS) { - extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & - CQE_STATUS_EXTD_MASK; - dev_err(&ctrl->pdev->dev, - "error in cmd completion: status(compl/extd)=%d/%d\n", - compl_status, extd_status); - return -EBUSY; - } - return 0; -} - -int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, - struct be_mcc_compl *compl) -{ - u16 compl_status, extd_status; - unsigned short tag; - - be_dws_le_to_cpu(compl, 4); - - compl_status = (compl->status >> CQE_STATUS_COMPL_SHIFT) & - CQE_STATUS_COMPL_MASK; - /* The ctrl.mcc_numtag[tag] is filled with - * [31] = valid, [30:24] = Rsvd, [23:16] = wrb, [15:8] = extd_status, - * [7:0] = compl_status - */ - tag = (compl->tag0 & 0x000000FF); - extd_status = (compl->status >> CQE_STATUS_EXTD_SHIFT) & - CQE_STATUS_EXTD_MASK; - - ctrl->mcc_numtag[tag] = 0x80000000; - ctrl->mcc_numtag[tag] |= (compl->tag0 & 0x00FF0000); - ctrl->mcc_numtag[tag] |= (extd_status & 0x000000FF) << 8; - ctrl->mcc_numtag[tag] |= (compl_status & 0x000000FF); - wake_up_interruptible(&ctrl->mcc_wait[tag]); - return 0; -} - -static struct be_mcc_compl *be_mcc_compl_get(struct beiscsi_hba *phba) -{ - struct be_queue_info *mcc_cq = &phba->ctrl.mcc_obj.cq; - struct be_mcc_compl *compl = queue_tail_node(mcc_cq); - - if (be_mcc_compl_is_new(compl)) { - queue_tail_inc(mcc_cq); - return compl; - } - return NULL; -} - -static void be2iscsi_fail_session(struct iscsi_cls_session *cls_session) -{ - iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); -} - -void beiscsi_async_link_state_process(struct beiscsi_hba *phba, - struct be_async_event_link_state *evt) -{ - switch (evt->port_link_status) { - case ASYNC_EVENT_LINK_DOWN: - SE_DEBUG(DBG_LVL_1, "Link Down on Physical Port %d\n", - evt->physical_port); - phba->state |= BE_ADAPTER_LINK_DOWN; - iscsi_host_for_each_session(phba->shost, - be2iscsi_fail_session); - break; - case ASYNC_EVENT_LINK_UP: - phba->state = BE_ADAPTER_UP; - SE_DEBUG(DBG_LVL_1, "Link UP on Physical Port %d\n", - evt->physical_port); - break; - default: - SE_DEBUG(DBG_LVL_1, "Unexpected Async Notification %d on" - "Physical Port %d\n", - evt->port_link_status, - evt->physical_port); - } -} - -static void beiscsi_cq_notify(struct beiscsi_hba *phba, u16 qid, bool arm, - u16 num_popped) -{ - u32 val = 0; - val |= qid & DB_CQ_RING_ID_MASK; - if (arm) - val |= 1 << DB_CQ_REARM_SHIFT; - val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; - iowrite32(val, phba->db_va + DB_CQ_OFFSET); -} - - -int beiscsi_process_mcc(struct beiscsi_hba *phba) -{ - struct be_mcc_compl *compl; - int num = 0, status = 0; - struct be_ctrl_info *ctrl = &phba->ctrl; - - spin_lock_bh(&phba->ctrl.mcc_cq_lock); - while ((compl = be_mcc_compl_get(phba))) { - if (compl->flags & CQE_FLAGS_ASYNC_MASK) { - /* Interpret flags as an async trailer */ - if (is_link_state_evt(compl->flags)) - /* Interpret compl as a async link evt */ - beiscsi_async_link_state_process(phba, - (struct be_async_event_link_state *) compl); - else - SE_DEBUG(DBG_LVL_1, - " Unsupported Async Event, flags" - " = 0x%08x\n", compl->flags); - - } else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) { - status = be_mcc_compl_process(ctrl, compl); - atomic_dec(&phba->ctrl.mcc_obj.q.used); - } - be_mcc_compl_use(compl); - num++; - } - - if (num) - beiscsi_cq_notify(phba, phba->ctrl.mcc_obj.cq.id, true, num); - - spin_unlock_bh(&phba->ctrl.mcc_cq_lock); - return status; -} - -/* Wait till no more pending mcc requests are present */ -static int be_mcc_wait_compl(struct beiscsi_hba *phba) -{ - int i, status; - for (i = 0; i < mcc_timeout; i++) { - status = beiscsi_process_mcc(phba); - if (status) - return status; - - if (atomic_read(&phba->ctrl.mcc_obj.q.used) == 0) - break; - udelay(100); - } - if (i == mcc_timeout) { - dev_err(&phba->pcidev->dev, "mccq poll timed out\n"); - return -EBUSY; - } - return 0; -} - -/* Notify MCC requests and wait for completion */ -int be_mcc_notify_wait(struct beiscsi_hba *phba) -{ - be_mcc_notify(phba); - return be_mcc_wait_compl(phba); -} - -static int be_mbox_db_ready_wait(struct be_ctrl_info *ctrl) -{ -#define long_delay 2000 - void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET; - int cnt = 0, wait = 5; /* in usecs */ - u32 ready; - - do { - ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK; - if (ready) - break; - - if (cnt > 12000000) { - dev_err(&ctrl->pdev->dev, "mbox_db poll timed out\n"); - return -EBUSY; - } - - if (cnt > 50) { - wait = long_delay; - mdelay(long_delay / 1000); - } else - udelay(wait); - cnt += wait; - } while (true); - return 0; -} - -int be_mbox_notify(struct be_ctrl_info *ctrl) -{ - int status; - u32 val = 0; - void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET; - struct be_dma_mem *mbox_mem = &ctrl->mbox_mem; - struct be_mcc_mailbox *mbox = mbox_mem->va; - struct be_mcc_compl *compl = &mbox->compl; - - val &= ~MPU_MAILBOX_DB_RDY_MASK; - val |= MPU_MAILBOX_DB_HI_MASK; - val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; - iowrite32(val, db); - - status = be_mbox_db_ready_wait(ctrl); - if (status != 0) { - SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed\n"); - return status; - } - val = 0; - val &= ~MPU_MAILBOX_DB_RDY_MASK; - val &= ~MPU_MAILBOX_DB_HI_MASK; - val |= (u32) (mbox_mem->dma >> 4) << 2; - iowrite32(val, db); - - status = be_mbox_db_ready_wait(ctrl); - if (status != 0) { - SE_DEBUG(DBG_LVL_1, " be_mbox_db_ready_wait failed\n"); - return status; - } - if (be_mcc_compl_is_new(compl)) { - status = be_mcc_compl_process(ctrl, &mbox->compl); - be_mcc_compl_use(compl); - if (status) { - SE_DEBUG(DBG_LVL_1, "After be_mcc_compl_process\n"); - return status; - } - } else { - dev_err(&ctrl->pdev->dev, "invalid mailbox completion\n"); - return -EBUSY; - } - return 0; -} - -/* - * Insert the mailbox address into the doorbell in two steps - * Polls on the mbox doorbell till a command completion (or a timeout) occurs - */ -static int be_mbox_notify_wait(struct beiscsi_hba *phba) -{ - int status; - u32 val = 0; - void __iomem *db = phba->ctrl.db + MPU_MAILBOX_DB_OFFSET; - struct be_dma_mem *mbox_mem = &phba->ctrl.mbox_mem; - struct be_mcc_mailbox *mbox = mbox_mem->va; - struct be_mcc_compl *compl = &mbox->compl; - struct be_ctrl_info *ctrl = &phba->ctrl; - - val |= MPU_MAILBOX_DB_HI_MASK; - /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */ - val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2; - iowrite32(val, db); - - /* wait for ready to be set */ - status = be_mbox_db_ready_wait(ctrl); - if (status != 0) - return status; - - val = 0; - /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */ - val |= (u32)(mbox_mem->dma >> 4) << 2; - iowrite32(val, db); - - status = be_mbox_db_ready_wait(ctrl); - if (status != 0) - return status; - - /* A cq entry has been made now */ - if (be_mcc_compl_is_new(compl)) { - status = be_mcc_compl_process(ctrl, &mbox->compl); - be_mcc_compl_use(compl); - if (status) - return status; - } else { - dev_err(&phba->pcidev->dev, "invalid mailbox completion\n"); - return -EBUSY; - } - return 0; -} - -void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, - bool embedded, u8 sge_cnt) -{ - if (embedded) - wrb->embedded |= MCC_WRB_EMBEDDED_MASK; - else - wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) << - MCC_WRB_SGE_CNT_SHIFT; - wrb->payload_length = payload_len; - be_dws_cpu_to_le(wrb, 8); -} - -void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, - u8 subsystem, u8 opcode, int cmd_len) -{ - req_hdr->opcode = opcode; - req_hdr->subsystem = subsystem; - req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr)); - req_hdr->timeout = 120; -} - -static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages, - struct be_dma_mem *mem) -{ - int i, buf_pages; - u64 dma = (u64) mem->dma; - - buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages); - for (i = 0; i < buf_pages; i++) { - pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF); - pages[i].hi = cpu_to_le32(upper_32_bits(dma)); - dma += PAGE_SIZE_4K; - } -} - -static u32 eq_delay_to_mult(u32 usec_delay) -{ -#define MAX_INTR_RATE 651042 - const u32 round = 10; - u32 multiplier; - - if (usec_delay == 0) - multiplier = 0; - else { - u32 interrupt_rate = 1000000 / usec_delay; - if (interrupt_rate == 0) - multiplier = 1023; - else { - multiplier = (MAX_INTR_RATE - interrupt_rate) * round; - multiplier /= interrupt_rate; - multiplier = (multiplier + round / 2) / round; - multiplier = min(multiplier, (u32) 1023); - } - } - return multiplier; -} - -struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem) -{ - return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb; -} - -struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba) -{ - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; - struct be_mcc_wrb *wrb; - - BUG_ON(atomic_read(&mccq->used) >= mccq->len); - wrb = queue_head_node(mccq); - memset(wrb, 0, sizeof(*wrb)); - wrb->tag0 = (mccq->head & 0x000000FF) << 16; - queue_head_inc(mccq); - atomic_inc(&mccq->used); - return wrb; -} - - -int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl, - struct be_queue_info *eq, int eq_delay) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_cmd_req_eq_create *req = embedded_payload(wrb); - struct be_cmd_resp_eq_create *resp = embedded_payload(wrb); - struct be_dma_mem *q_mem = &eq->dma_mem; - int status; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_eq_create\n"); - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_EQ_CREATE, sizeof(*req)); - - req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); - - AMAP_SET_BITS(struct amap_eq_context, func, req->context, - PCI_FUNC(ctrl->pdev->devfn)); - AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1); - AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0); - AMAP_SET_BITS(struct amap_eq_context, count, req->context, - __ilog2_u32(eq->len / 256)); - AMAP_SET_BITS(struct amap_eq_context, delaymult, req->context, - eq_delay_to_mult(eq_delay)); - be_dws_cpu_to_le(req->context, sizeof(req->context)); - - be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - - status = be_mbox_notify(ctrl); - if (!status) { - eq->id = le16_to_cpu(resp->eq_id); - eq->created = true; - } - spin_unlock(&ctrl->mbox_lock); - return status; -} - -int be_cmd_fw_initialize(struct be_ctrl_info *ctrl) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - int status; - u8 *endian_check; - - SE_DEBUG(DBG_LVL_8, "In be_cmd_fw_initialize\n"); - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - endian_check = (u8 *) wrb; - *endian_check++ = 0xFF; - *endian_check++ = 0x12; - *endian_check++ = 0x34; - *endian_check++ = 0xFF; - *endian_check++ = 0xFF; - *endian_check++ = 0x56; - *endian_check++ = 0x78; - *endian_check++ = 0xFF; - be_dws_cpu_to_le(wrb, sizeof(*wrb)); - - status = be_mbox_notify(ctrl); - if (status) - SE_DEBUG(DBG_LVL_1, "be_cmd_fw_initialize Failed\n"); - - spin_unlock(&ctrl->mbox_lock); - return status; -} - -int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl, - struct be_queue_info *cq, struct be_queue_info *eq, - bool sol_evts, bool no_delay, int coalesce_wm) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_cmd_req_cq_create *req = embedded_payload(wrb); - struct be_cmd_resp_cq_create *resp = embedded_payload(wrb); - struct be_dma_mem *q_mem = &cq->dma_mem; - void *ctxt = &req->context; - int status; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_cq_create\n"); - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_CQ_CREATE, sizeof(*req)); - if (!q_mem->va) - SE_DEBUG(DBG_LVL_1, "uninitialized q_mem->va\n"); - - req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); - - AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm); - AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay); - AMAP_SET_BITS(struct amap_cq_context, count, ctxt, - __ilog2_u32(cq->len / 256)); - AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts); - AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id); - AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 1); - AMAP_SET_BITS(struct amap_cq_context, func, ctxt, - PCI_FUNC(ctrl->pdev->devfn)); - be_dws_cpu_to_le(ctxt, sizeof(req->context)); - - be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - - status = be_mbox_notify(ctrl); - if (!status) { - cq->id = le16_to_cpu(resp->cq_id); - cq->created = true; - } else - SE_DEBUG(DBG_LVL_1, "In be_cmd_cq_create, status=ox%08x\n", - status); - spin_unlock(&ctrl->mbox_lock); - - return status; -} - -static u32 be_encoded_q_len(int q_len) -{ - u32 len_encoded = fls(q_len); /* log2(len) + 1 */ - if (len_encoded == 16) - len_encoded = 0; - return len_encoded; -} - -int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, - struct be_queue_info *mccq, - struct be_queue_info *cq) -{ - struct be_mcc_wrb *wrb; - struct be_cmd_req_mcc_create *req; - struct be_dma_mem *q_mem = &mccq->dma_mem; - struct be_ctrl_info *ctrl; - void *ctxt; - int status; - - spin_lock(&phba->ctrl.mbox_lock); - ctrl = &phba->ctrl; - wrb = wrb_from_mbox(&ctrl->mbox_mem); - memset(wrb, 0, sizeof(*wrb)); - req = embedded_payload(wrb); - ctxt = &req->context; - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_MCC_CREATE, sizeof(*req)); - - req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); - - AMAP_SET_BITS(struct amap_mcc_context, fid, ctxt, - PCI_FUNC(phba->pcidev->devfn)); - AMAP_SET_BITS(struct amap_mcc_context, valid, ctxt, 1); - AMAP_SET_BITS(struct amap_mcc_context, ring_size, ctxt, - be_encoded_q_len(mccq->len)); - AMAP_SET_BITS(struct amap_mcc_context, cq_id, ctxt, cq->id); - - be_dws_cpu_to_le(ctxt, sizeof(req->context)); - - be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - - status = be_mbox_notify_wait(phba); - if (!status) { - struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb); - mccq->id = le16_to_cpu(resp->id); - mccq->created = true; - } - spin_unlock(&phba->ctrl.mbox_lock); - - return status; -} - -int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, - int queue_type) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_cmd_req_q_destroy *req = embedded_payload(wrb); - u8 subsys = 0, opcode = 0; - int status; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_cmd_q_destroy\n"); - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - - switch (queue_type) { - case QTYPE_EQ: - subsys = CMD_SUBSYSTEM_COMMON; - opcode = OPCODE_COMMON_EQ_DESTROY; - break; - case QTYPE_CQ: - subsys = CMD_SUBSYSTEM_COMMON; - opcode = OPCODE_COMMON_CQ_DESTROY; - break; - case QTYPE_MCCQ: - subsys = CMD_SUBSYSTEM_COMMON; - opcode = OPCODE_COMMON_MCC_DESTROY; - break; - case QTYPE_WRBQ: - subsys = CMD_SUBSYSTEM_ISCSI; - opcode = OPCODE_COMMON_ISCSI_WRBQ_DESTROY; - break; - case QTYPE_DPDUQ: - subsys = CMD_SUBSYSTEM_ISCSI; - opcode = OPCODE_COMMON_ISCSI_DEFQ_DESTROY; - break; - case QTYPE_SGL: - subsys = CMD_SUBSYSTEM_ISCSI; - opcode = OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES; - break; - default: - spin_unlock(&ctrl->mbox_lock); - BUG(); - return -ENXIO; - } - be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req)); - if (queue_type != QTYPE_SGL) - req->id = cpu_to_le16(q->id); - - status = be_mbox_notify(ctrl); - - spin_unlock(&ctrl->mbox_lock); - return status; -} - -int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl, - struct be_queue_info *cq, - struct be_queue_info *dq, int length, - int entry_size) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_defq_create_req *req = embedded_payload(wrb); - struct be_dma_mem *q_mem = &dq->dma_mem; - void *ctxt = &req->context; - int status; - - SE_DEBUG(DBG_LVL_8, "In be_cmd_create_default_pdu_queue\n"); - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_DEFQ_CREATE, sizeof(*req)); - - req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); - AMAP_SET_BITS(struct amap_be_default_pdu_context, rx_pdid, ctxt, 0); - AMAP_SET_BITS(struct amap_be_default_pdu_context, rx_pdid_valid, ctxt, - 1); - AMAP_SET_BITS(struct amap_be_default_pdu_context, pci_func_id, ctxt, - PCI_FUNC(ctrl->pdev->devfn)); - AMAP_SET_BITS(struct amap_be_default_pdu_context, ring_size, ctxt, - be_encoded_q_len(length / sizeof(struct phys_addr))); - AMAP_SET_BITS(struct amap_be_default_pdu_context, default_buffer_size, - ctxt, entry_size); - AMAP_SET_BITS(struct amap_be_default_pdu_context, cq_id_recv, ctxt, - cq->id); - - be_dws_cpu_to_le(ctxt, sizeof(req->context)); - - be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - - status = be_mbox_notify(ctrl); - if (!status) { - struct be_defq_create_resp *resp = embedded_payload(wrb); - - dq->id = le16_to_cpu(resp->id); - dq->created = true; - } - spin_unlock(&ctrl->mbox_lock); - - return status; -} - -int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, - struct be_queue_info *wrbq) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_wrbq_create_req *req = embedded_payload(wrb); - struct be_wrbq_create_resp *resp = embedded_payload(wrb); - int status; - - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_WRBQ_CREATE, sizeof(*req)); - req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size); - be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem); - - status = be_mbox_notify(ctrl); - if (!status) { - wrbq->id = le16_to_cpu(resp->cid); - wrbq->created = true; - } - spin_unlock(&ctrl->mbox_lock); - return status; -} - -int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl, - struct be_dma_mem *q_mem, - u32 page_offset, u32 num_pages) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_post_sgl_pages_req *req = embedded_payload(wrb); - int status; - unsigned int curr_pages; - u32 internal_page_offset = 0; - u32 temp_num_pages = num_pages; - - if (num_pages == 0xff) - num_pages = 1; - - spin_lock(&ctrl->mbox_lock); - do { - memset(wrb, 0, sizeof(*wrb)); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES, - sizeof(*req)); - curr_pages = BE_NUMBER_OF_FIELD(struct be_post_sgl_pages_req, - pages); - req->num_pages = min(num_pages, curr_pages); - req->page_offset = page_offset; - be_cmd_page_addrs_prepare(req->pages, req->num_pages, q_mem); - q_mem->dma = q_mem->dma + (req->num_pages * PAGE_SIZE); - internal_page_offset += req->num_pages; - page_offset += req->num_pages; - num_pages -= req->num_pages; - - if (temp_num_pages == 0xff) - req->num_pages = temp_num_pages; - - status = be_mbox_notify(ctrl); - if (status) { - SE_DEBUG(DBG_LVL_1, - "FW CMD to map iscsi frags failed.\n"); - goto error; - } - } while (num_pages > 0); -error: - spin_unlock(&ctrl->mbox_lock); - if (status != 0) - beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL); - return status; -} - -int beiscsi_cmd_reset_function(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_post_sgl_pages_req *req = embedded_payload(wrb); - int status; - - spin_lock(&ctrl->mbox_lock); - - req = embedded_payload(wrb); - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_FUNCTION_RESET, sizeof(*req)); - status = be_mbox_notify_wait(phba); - - spin_unlock(&ctrl->mbox_lock); - return status; -} diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.h b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.h deleted file mode 100644 index 8b40a5b4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_cmds.h +++ /dev/null @@ -1,1028 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#ifndef BEISCSI_CMDS_H -#define BEISCSI_CMDS_H - -/** - * The driver sends configuration and managements command requests to the - * firmware in the BE. These requests are communicated to the processor - * using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one - * WRB inside a MAILBOX. - * The commands are serviced by the ARM processor in the BladeEngine's MPU. - */ -struct be_sge { - u32 pa_lo; - u32 pa_hi; - u32 len; -}; - -#define MCC_WRB_SGE_CNT_SHIFT 3 /* bits 3 - 7 of dword 0 */ -#define MCC_WRB_SGE_CNT_MASK 0x1F /* bits 3 - 7 of dword 0 */ -struct be_mcc_wrb { - u32 embedded; /* dword 0 */ - u32 payload_length; /* dword 1 */ - u32 tag0; /* dword 2 */ - u32 tag1; /* dword 3 */ - u32 rsvd; /* dword 4 */ - union { - u8 embedded_payload[236]; /* used by embedded cmds */ - struct be_sge sgl[19]; /* used by non-embedded cmds */ - } payload; -}; - -#define CQE_FLAGS_VALID_MASK (1 << 31) -#define CQE_FLAGS_ASYNC_MASK (1 << 30) -#define CQE_FLAGS_COMPLETED_MASK (1 << 28) -#define CQE_FLAGS_CONSUMED_MASK (1 << 27) - -/* Completion Status */ -#define MCC_STATUS_SUCCESS 0x0 - -#define CQE_STATUS_COMPL_MASK 0xFFFF -#define CQE_STATUS_COMPL_SHIFT 0 /* bits 0 - 15 */ -#define CQE_STATUS_EXTD_MASK 0xFFFF -#define CQE_STATUS_EXTD_SHIFT 16 /* bits 0 - 15 */ - -struct be_mcc_compl { - u32 status; /* dword 0 */ - u32 tag0; /* dword 1 */ - u32 tag1; /* dword 2 */ - u32 flags; /* dword 3 */ -}; - -/********* Mailbox door bell *************/ -/** - * Used for driver communication with the FW. - * The software must write this register twice to post any command. First, - * it writes the register with hi=1 and the upper bits of the physical address - * for the MAILBOX structure. Software must poll the ready bit until this - * is acknowledged. Then, sotware writes the register with hi=0 with the lower - * bits in the address. It must poll the ready bit until the command is - * complete. Upon completion, the MAILBOX will contain a valid completion - * queue entry. - */ -#define MPU_MAILBOX_DB_OFFSET 0x160 -#define MPU_MAILBOX_DB_RDY_MASK 0x1 /* bit 0 */ -#define MPU_MAILBOX_DB_HI_MASK 0x2 /* bit 1 */ - -/********** MPU semphore ******************/ -#define MPU_EP_SEMAPHORE_OFFSET 0xac -#define EP_SEMAPHORE_POST_STAGE_MASK 0x0000FFFF -#define EP_SEMAPHORE_POST_ERR_MASK 0x1 -#define EP_SEMAPHORE_POST_ERR_SHIFT 31 - -/********** MCC door bell ************/ -#define DB_MCCQ_OFFSET 0x140 -#define DB_MCCQ_RING_ID_MASK 0x7FF /* bits 0 - 10 */ -/* Number of entries posted */ -#define DB_MCCQ_NUM_POSTED_SHIFT 16 /* bits 16 - 29 */ - -/* MPU semphore POST stage values */ -#define POST_STAGE_ARMFW_RDY 0xc000 /* FW is done with POST */ - -/** - * When the async bit of mcc_compl is set, the last 4 bytes of - * mcc_compl is interpreted as follows: - */ -#define ASYNC_TRAILER_EVENT_CODE_SHIFT 8 /* bits 8 - 15 */ -#define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF -#define ASYNC_EVENT_CODE_LINK_STATE 0x1 -struct be_async_event_trailer { - u32 code; -}; - -enum { - ASYNC_EVENT_LINK_DOWN = 0x0, - ASYNC_EVENT_LINK_UP = 0x1 -}; - -/** - * When the event code of an async trailer is link-state, the mcc_compl - * must be interpreted as follows - */ -struct be_async_event_link_state { - u8 physical_port; - u8 port_link_status; - u8 port_duplex; - u8 port_speed; - u8 port_fault; - u8 rsvd0[7]; - struct be_async_event_trailer trailer; -} __packed; - -struct be_mcc_mailbox { - struct be_mcc_wrb wrb; - struct be_mcc_compl compl; -}; - -/* Type of subsystems supported by FW */ -#define CMD_SUBSYSTEM_COMMON 0x1 -#define CMD_SUBSYSTEM_ISCSI 0x2 -#define CMD_SUBSYSTEM_ETH 0x3 -#define CMD_SUBSYSTEM_ISCSI_INI 0x6 -#define CMD_COMMON_TCP_UPLOAD 0x1 - -/** - * List of common opcodes subsystem CMD_SUBSYSTEM_COMMON - * These opcodes are unique for each subsystem defined above - */ -#define OPCODE_COMMON_CQ_CREATE 12 -#define OPCODE_COMMON_EQ_CREATE 13 -#define OPCODE_COMMON_MCC_CREATE 21 -#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES 32 -#define OPCODE_COMMON_GET_FW_VERSION 35 -#define OPCODE_COMMON_MODIFY_EQ_DELAY 41 -#define OPCODE_COMMON_FIRMWARE_CONFIG 42 -#define OPCODE_COMMON_MCC_DESTROY 53 -#define OPCODE_COMMON_CQ_DESTROY 54 -#define OPCODE_COMMON_EQ_DESTROY 55 -#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG 58 -#define OPCODE_COMMON_FUNCTION_RESET 61 - -/** - * LIST of opcodes that are common between Initiator and Target - * used by CMD_SUBSYSTEM_ISCSI - * These opcodes are unique for each subsystem defined above - */ -#define OPCODE_COMMON_ISCSI_CFG_POST_SGL_PAGES 2 -#define OPCODE_COMMON_ISCSI_CFG_REMOVE_SGL_PAGES 3 -#define OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG 7 -#define OPCODE_COMMON_ISCSI_NTWK_SET_VLAN 14 -#define OPCODE_COMMON_ISCSI_NTWK_CONFIGURE_STATELESS_IP_ADDR 17 -#define OPCODE_COMMON_ISCSI_NTWK_MODIFY_IP_ADDR 21 -#define OPCODE_COMMON_ISCSI_NTWK_GET_DEFAULT_GATEWAY 22 -#define OPCODE_COMMON_ISCSI_NTWK_MODIFY_DEFAULT_GATEWAY 23 -#define OPCODE_COMMON_ISCSI_NTWK_GET_ALL_IF_ID 24 -#define OPCODE_COMMON_ISCSI_NTWK_GET_IF_INFO 25 -#define OPCODE_COMMON_ISCSI_SET_FRAGNUM_BITS_FOR_SGL_CRA 61 -#define OPCODE_COMMON_ISCSI_DEFQ_CREATE 64 -#define OPCODE_COMMON_ISCSI_DEFQ_DESTROY 65 -#define OPCODE_COMMON_ISCSI_WRBQ_CREATE 66 -#define OPCODE_COMMON_ISCSI_WRBQ_DESTROY 67 - -struct be_cmd_req_hdr { - u8 opcode; /* dword 0 */ - u8 subsystem; /* dword 0 */ - u8 port_number; /* dword 0 */ - u8 domain; /* dword 0 */ - u32 timeout; /* dword 1 */ - u32 request_length; /* dword 2 */ - u32 rsvd0; /* dword 3 */ -}; - -struct be_cmd_resp_hdr { - u32 info; /* dword 0 */ - u32 status; /* dword 1 */ - u32 response_length; /* dword 2 */ - u32 actual_resp_len; /* dword 3 */ -}; - -struct phys_addr { - u32 lo; - u32 hi; -}; - -/************************** - * BE Command definitions * - **************************/ - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte - used to calculate offset/shift/mask of each field - */ -struct amap_eq_context { - u8 cidx[13]; /* dword 0 */ - u8 rsvd0[3]; /* dword 0 */ - u8 epidx[13]; /* dword 0 */ - u8 valid; /* dword 0 */ - u8 rsvd1; /* dword 0 */ - u8 size; /* dword 0 */ - u8 pidx[13]; /* dword 1 */ - u8 rsvd2[3]; /* dword 1 */ - u8 pd[10]; /* dword 1 */ - u8 count[3]; /* dword 1 */ - u8 solevent; /* dword 1 */ - u8 stalled; /* dword 1 */ - u8 armed; /* dword 1 */ - u8 rsvd3[4]; /* dword 2 */ - u8 func[8]; /* dword 2 */ - u8 rsvd4; /* dword 2 */ - u8 delaymult[10]; /* dword 2 */ - u8 rsvd5[2]; /* dword 2 */ - u8 phase[2]; /* dword 2 */ - u8 nodelay; /* dword 2 */ - u8 rsvd6[4]; /* dword 2 */ - u8 rsvd7[32]; /* dword 3 */ -} __packed; - -struct be_cmd_req_eq_create { - struct be_cmd_req_hdr hdr; /* dw[4] */ - u16 num_pages; /* sword */ - u16 rsvd0; /* sword */ - u8 context[sizeof(struct amap_eq_context) / 8]; /* dw[4] */ - struct phys_addr pages[8]; -} __packed; - -struct be_cmd_resp_eq_create { - struct be_cmd_resp_hdr resp_hdr; - u16 eq_id; /* sword */ - u16 rsvd0; /* sword */ -} __packed; - -struct mgmt_chap_format { - u32 flags; - u8 intr_chap_name[256]; - u8 intr_secret[16]; - u8 target_chap_name[256]; - u8 target_secret[16]; - u16 intr_chap_name_length; - u16 intr_secret_length; - u16 target_chap_name_length; - u16 target_secret_length; -} __packed; - -struct mgmt_auth_method_format { - u8 auth_method_type; - u8 padding[3]; - struct mgmt_chap_format chap; -} __packed; - -struct mgmt_conn_login_options { - u8 flags; - u8 header_digest; - u8 data_digest; - u8 rsvd0; - u32 max_recv_datasegment_len_ini; - u32 max_recv_datasegment_len_tgt; - u32 tcp_mss; - u32 tcp_window_size; - struct mgmt_auth_method_format auth_data; -} __packed; - -struct ip_address_format { - u16 size_of_structure; - u8 reserved; - u8 ip_type; - u8 ip_address[16]; - u32 rsvd0; -} __packed; - -struct mgmt_conn_info { - u32 connection_handle; - u32 connection_status; - u16 src_port; - u16 dest_port; - u16 dest_port_redirected; - u16 cid; - u32 estimated_throughput; - struct ip_address_format src_ipaddr; - struct ip_address_format dest_ipaddr; - struct ip_address_format dest_ipaddr_redirected; - struct mgmt_conn_login_options negotiated_login_options; -} __packed; - -struct mgmt_session_login_options { - u8 flags; - u8 error_recovery_level; - u16 rsvd0; - u32 first_burst_length; - u32 max_burst_length; - u16 max_connections; - u16 max_outstanding_r2t; - u16 default_time2wait; - u16 default_time2retain; -} __packed; - -struct mgmt_session_info { - u32 session_handle; - u32 status; - u8 isid[6]; - u16 tsih; - u32 session_flags; - u16 conn_count; - u16 pad; - u8 target_name[224]; - u8 initiator_iscsiname[224]; - struct mgmt_session_login_options negotiated_login_options; - struct mgmt_conn_info conn_list[1]; -} __packed; - -struct be_cmd_req_get_session { - struct be_cmd_req_hdr hdr; - u32 session_handle; -} __packed; - -struct be_cmd_resp_get_session { - struct be_cmd_resp_hdr hdr; - struct mgmt_session_info session_info; -} __packed; - -struct mac_addr { - u16 size_of_struct; - u8 addr[ETH_ALEN]; -} __packed; - -struct be_cmd_req_get_boot_target { - struct be_cmd_req_hdr hdr; -} __packed; - -struct be_cmd_resp_get_boot_target { - struct be_cmd_resp_hdr hdr; - u32 boot_session_count; - int boot_session_handle; -}; - -struct be_cmd_req_mac_query { - struct be_cmd_req_hdr hdr; - u8 type; - u8 permanent; - u16 if_id; -} __packed; - -struct be_cmd_resp_mac_query { - struct be_cmd_resp_hdr hdr; - struct mac_addr mac; -}; - -/******************** Create CQ ***************************/ -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte - used to calculate offset/shift/mask of each field - */ -struct amap_cq_context { - u8 cidx[11]; /* dword 0 */ - u8 rsvd0; /* dword 0 */ - u8 coalescwm[2]; /* dword 0 */ - u8 nodelay; /* dword 0 */ - u8 epidx[11]; /* dword 0 */ - u8 rsvd1; /* dword 0 */ - u8 count[2]; /* dword 0 */ - u8 valid; /* dword 0 */ - u8 solevent; /* dword 0 */ - u8 eventable; /* dword 0 */ - u8 pidx[11]; /* dword 1 */ - u8 rsvd2; /* dword 1 */ - u8 pd[10]; /* dword 1 */ - u8 eqid[8]; /* dword 1 */ - u8 stalled; /* dword 1 */ - u8 armed; /* dword 1 */ - u8 rsvd3[4]; /* dword 2 */ - u8 func[8]; /* dword 2 */ - u8 rsvd4[20]; /* dword 2 */ - u8 rsvd5[32]; /* dword 3 */ -} __packed; - -struct be_cmd_req_cq_create { - struct be_cmd_req_hdr hdr; - u16 num_pages; - u16 rsvd0; - u8 context[sizeof(struct amap_cq_context) / 8]; - struct phys_addr pages[4]; -} __packed; - -struct be_cmd_resp_cq_create { - struct be_cmd_resp_hdr hdr; - u16 cq_id; - u16 rsvd0; -} __packed; - -/******************** Create MCCQ ***************************/ -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte - used to calculate offset/shift/mask of each field - */ -struct amap_mcc_context { - u8 con_index[14]; - u8 rsvd0[2]; - u8 ring_size[4]; - u8 fetch_wrb; - u8 fetch_r2t; - u8 cq_id[10]; - u8 prod_index[14]; - u8 fid[8]; - u8 pdid[9]; - u8 valid; - u8 rsvd1[32]; - u8 rsvd2[32]; -} __packed; - -struct be_cmd_req_mcc_create { - struct be_cmd_req_hdr hdr; - u16 num_pages; - u16 rsvd0; - u8 context[sizeof(struct amap_mcc_context) / 8]; - struct phys_addr pages[8]; -} __packed; - -struct be_cmd_resp_mcc_create { - struct be_cmd_resp_hdr hdr; - u16 id; - u16 rsvd0; -} __packed; - -/******************** Q Destroy ***************************/ -/* Type of Queue to be destroyed */ -enum { - QTYPE_EQ = 1, - QTYPE_CQ, - QTYPE_MCCQ, - QTYPE_WRBQ, - QTYPE_DPDUQ, - QTYPE_SGL -}; - -struct be_cmd_req_q_destroy { - struct be_cmd_req_hdr hdr; - u16 id; - u16 bypass_flush; /* valid only for rx q destroy */ -} __packed; - -struct macaddr { - u8 byte[ETH_ALEN]; -}; - -struct be_cmd_req_mcast_mac_config { - struct be_cmd_req_hdr hdr; - u16 num_mac; - u8 promiscuous; - u8 interface_id; - struct macaddr mac[32]; -} __packed; - -static inline void *embedded_payload(struct be_mcc_wrb *wrb) -{ - return wrb->payload.embedded_payload; -} - -static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb) -{ - return &wrb->payload.sgl[0]; -} - -/******************** Modify EQ Delay *******************/ -struct be_cmd_req_modify_eq_delay { - struct be_cmd_req_hdr hdr; - u32 num_eq; - struct { - u32 eq_id; - u32 phase; - u32 delay_multiplier; - } delay[8]; -} __packed; - -/******************** Get MAC ADDR *******************/ - -#define ETH_ALEN 6 - -struct be_cmd_req_get_mac_addr { - struct be_cmd_req_hdr hdr; - u32 nic_port_count; - u32 speed; - u32 max_speed; - u32 link_state; - u32 max_frame_size; - u16 size_of_structure; - u8 mac_address[ETH_ALEN]; - u32 rsvd[23]; -}; - -struct be_cmd_resp_get_mac_addr { - struct be_cmd_resp_hdr hdr; - u32 nic_port_count; - u32 speed; - u32 max_speed; - u32 link_state; - u32 max_frame_size; - u16 size_of_structure; - u8 mac_address[6]; - u32 rsvd[23]; -}; - -int beiscsi_cmd_eq_create(struct be_ctrl_info *ctrl, - struct be_queue_info *eq, int eq_delay); - -int beiscsi_cmd_cq_create(struct be_ctrl_info *ctrl, - struct be_queue_info *cq, struct be_queue_info *eq, - bool sol_evts, bool no_delay, - int num_cqe_dma_coalesce); - -int beiscsi_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, - int type); -int beiscsi_cmd_mccq_create(struct beiscsi_hba *phba, - struct be_queue_info *mccq, - struct be_queue_info *cq); - -int be_poll_mcc(struct be_ctrl_info *ctrl); -int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba); -unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba); -unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba); -unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd); - -void free_mcc_tag(struct be_ctrl_info *ctrl, unsigned int tag); -/*ISCSI Functuions */ -int be_cmd_fw_initialize(struct be_ctrl_info *ctrl); - -struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem); -struct be_mcc_wrb *wrb_from_mccq(struct beiscsi_hba *phba); -int be_mcc_notify_wait(struct beiscsi_hba *phba); -void be_mcc_notify(struct beiscsi_hba *phba); -unsigned int alloc_mcc_tag(struct beiscsi_hba *phba); -void beiscsi_async_link_state_process(struct beiscsi_hba *phba, - struct be_async_event_link_state *evt); -int be_mcc_compl_process_isr(struct be_ctrl_info *ctrl, - struct be_mcc_compl *compl); - -int be_mbox_notify(struct be_ctrl_info *ctrl); - -int be_cmd_create_default_pdu_queue(struct be_ctrl_info *ctrl, - struct be_queue_info *cq, - struct be_queue_info *dq, int length, - int entry_size); - -int be_cmd_iscsi_post_sgl_pages(struct be_ctrl_info *ctrl, - struct be_dma_mem *q_mem, u32 page_offset, - u32 num_pages); - -int beiscsi_cmd_reset_function(struct beiscsi_hba *phba); - -int be_cmd_wrbq_create(struct be_ctrl_info *ctrl, struct be_dma_mem *q_mem, - struct be_queue_info *wrbq); - -bool is_link_state_evt(u32 trailer); - -struct be_default_pdu_context { - u32 dw[4]; -} __packed; - -struct amap_be_default_pdu_context { - u8 dbuf_cindex[13]; /* dword 0 */ - u8 rsvd0[3]; /* dword 0 */ - u8 ring_size[4]; /* dword 0 */ - u8 ring_state[4]; /* dword 0 */ - u8 rsvd1[8]; /* dword 0 */ - u8 dbuf_pindex[13]; /* dword 1 */ - u8 rsvd2; /* dword 1 */ - u8 pci_func_id[8]; /* dword 1 */ - u8 rx_pdid[9]; /* dword 1 */ - u8 rx_pdid_valid; /* dword 1 */ - u8 default_buffer_size[16]; /* dword 2 */ - u8 cq_id_recv[10]; /* dword 2 */ - u8 rx_pdid_not_valid; /* dword 2 */ - u8 rsvd3[5]; /* dword 2 */ - u8 rsvd4[32]; /* dword 3 */ -} __packed; - -struct be_defq_create_req { - struct be_cmd_req_hdr hdr; - u16 num_pages; - u8 ulp_num; - u8 rsvd0; - struct be_default_pdu_context context; - struct phys_addr pages[8]; -} __packed; - -struct be_defq_create_resp { - struct be_cmd_req_hdr hdr; - u16 id; - u16 rsvd0; -} __packed; - -struct be_post_sgl_pages_req { - struct be_cmd_req_hdr hdr; - u16 num_pages; - u16 page_offset; - u32 rsvd0; - struct phys_addr pages[26]; - u32 rsvd1; -} __packed; - -struct be_wrbq_create_req { - struct be_cmd_req_hdr hdr; - u16 num_pages; - u8 ulp_num; - u8 rsvd0; - struct phys_addr pages[8]; -} __packed; - -struct be_wrbq_create_resp { - struct be_cmd_resp_hdr resp_hdr; - u16 cid; - u16 rsvd0; -} __packed; - -#define SOL_CID_MASK 0x0000FFC0 -#define SOL_CODE_MASK 0x0000003F -#define SOL_WRB_INDEX_MASK 0x00FF0000 -#define SOL_CMD_WND_MASK 0xFF000000 -#define SOL_RES_CNT_MASK 0x7FFFFFFF -#define SOL_EXP_CMD_SN_MASK 0xFFFFFFFF -#define SOL_HW_STS_MASK 0x000000FF -#define SOL_STS_MASK 0x0000FF00 -#define SOL_RESP_MASK 0x00FF0000 -#define SOL_FLAGS_MASK 0x7F000000 -#define SOL_S_MASK 0x80000000 - -struct sol_cqe { - u32 dw[4]; -}; - -struct amap_sol_cqe { - u8 hw_sts[8]; /* dword 0 */ - u8 i_sts[8]; /* dword 0 */ - u8 i_resp[8]; /* dword 0 */ - u8 i_flags[7]; /* dword 0 */ - u8 s; /* dword 0 */ - u8 i_exp_cmd_sn[32]; /* dword 1 */ - u8 code[6]; /* dword 2 */ - u8 cid[10]; /* dword 2 */ - u8 wrb_index[8]; /* dword 2 */ - u8 i_cmd_wnd[8]; /* dword 2 */ - u8 i_res_cnt[31]; /* dword 3 */ - u8 valid; /* dword 3 */ -} __packed; - -#define SOL_ICD_INDEX_MASK 0x0003FFC0 -struct amap_sol_cqe_ring { - u8 hw_sts[8]; /* dword 0 */ - u8 i_sts[8]; /* dword 0 */ - u8 i_resp[8]; /* dword 0 */ - u8 i_flags[7]; /* dword 0 */ - u8 s; /* dword 0 */ - u8 i_exp_cmd_sn[32]; /* dword 1 */ - u8 code[6]; /* dword 2 */ - u8 icd_index[12]; /* dword 2 */ - u8 rsvd[6]; /* dword 2 */ - u8 i_cmd_wnd[8]; /* dword 2 */ - u8 i_res_cnt[31]; /* dword 3 */ - u8 valid; /* dword 3 */ -} __packed; - - - -/** - * Post WRB Queue Doorbell Register used by the host Storage - * stack to notify the - * controller of a posted Work Request Block - */ -#define DB_WRB_POST_CID_MASK 0x3FF /* bits 0 - 9 */ -#define DB_DEF_PDU_WRB_INDEX_MASK 0xFF /* bits 0 - 9 */ - -#define DB_DEF_PDU_WRB_INDEX_SHIFT 16 -#define DB_DEF_PDU_NUM_POSTED_SHIFT 24 - -struct fragnum_bits_for_sgl_cra_in { - struct be_cmd_req_hdr hdr; - u32 num_bits; -} __packed; - -struct iscsi_cleanup_req { - struct be_cmd_req_hdr hdr; - u16 chute; - u8 hdr_ring_id; - u8 data_ring_id; - -} __packed; - -struct eq_delay { - u32 eq_id; - u32 phase; - u32 delay_multiplier; -} __packed; - -struct be_eq_delay_params_in { - struct be_cmd_req_hdr hdr; - u32 num_eq; - struct eq_delay delay[8]; -} __packed; - -struct tcp_connect_and_offload_in { - struct be_cmd_req_hdr hdr; - struct ip_address_format ip_address; - u16 tcp_port; - u16 cid; - u16 cq_id; - u16 defq_id; - struct phys_addr dataout_template_pa; - u16 hdr_ring_id; - u16 data_ring_id; - u8 do_offload; - u8 rsvd0[3]; -} __packed; - -struct tcp_connect_and_offload_out { - struct be_cmd_resp_hdr hdr; - u32 connection_handle; - u16 cid; - u16 rsvd0; - -} __packed; - -struct be_mcc_wrb_context { - struct MCC_WRB *wrb; - int *users_final_status; -} __packed; - -#define DB_DEF_PDU_RING_ID_MASK 0x3FF /* bits 0 - 9 */ -#define DB_DEF_PDU_CQPROC_MASK 0x3FFF /* bits 0 - 9 */ -#define DB_DEF_PDU_REARM_SHIFT 14 -#define DB_DEF_PDU_EVENT_SHIFT 15 -#define DB_DEF_PDU_CQPROC_SHIFT 16 - -struct dmsg_cqe { - u32 dw[4]; -} __packed; - -struct tcp_upload_params_in { - struct be_cmd_req_hdr hdr; - u16 id; - u16 upload_type; - u32 reset_seq; -} __packed; - -struct tcp_upload_params_out { - u32 dw[32]; -} __packed; - -union tcp_upload_params { - struct tcp_upload_params_in request; - struct tcp_upload_params_out response; -} __packed; - -struct be_ulp_fw_cfg { - u32 ulp_mode; - u32 etx_base; - u32 etx_count; - u32 sq_base; - u32 sq_count; - u32 rq_base; - u32 rq_count; - u32 dq_base; - u32 dq_count; - u32 lro_base; - u32 lro_count; - u32 icd_base; - u32 icd_count; -}; - -struct be_fw_cfg { - struct be_cmd_req_hdr hdr; - u32 be_config_number; - u32 asic_revision; - u32 phys_port; - u32 function_mode; - struct be_ulp_fw_cfg ulp[2]; - u32 function_caps; -} __packed; - -struct be_all_if_id { - struct be_cmd_req_hdr hdr; - u32 if_count; - u32 if_hndl_list[1]; -} __packed; - -#define ISCSI_OPCODE_SCSI_DATA_OUT 5 -#define OPCODE_COMMON_MODIFY_EQ_DELAY 41 -#define OPCODE_COMMON_ISCSI_CLEANUP 59 -#define OPCODE_COMMON_TCP_UPLOAD 56 -#define OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD 70 -#define OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS 1 -#define OPCODE_ISCSI_INI_CFG_GET_HBA_NAME 6 -#define OPCODE_ISCSI_INI_CFG_SET_HBA_NAME 7 -#define OPCODE_ISCSI_INI_SESSION_GET_A_SESSION 14 -#define OPCODE_ISCSI_INI_DRIVER_OFFLOAD_SESSION 41 -#define OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION 42 -#define OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET 52 - -/* --- CMD_ISCSI_INVALIDATE_CONNECTION_TYPE --- */ -#define CMD_ISCSI_COMMAND_INVALIDATE 1 -#define CMD_ISCSI_CONNECTION_INVALIDATE 0x8001 -#define CMD_ISCSI_CONNECTION_ISSUE_TCP_RST 0x8002 - -#define INI_WR_CMD 1 /* Initiator write command */ -#define INI_TMF_CMD 2 /* Initiator TMF command */ -#define INI_NOPOUT_CMD 3 /* Initiator; Send a NOP-OUT */ -#define INI_RD_CMD 5 /* Initiator requesting to send - * a read command - */ -#define TGT_CTX_UPDT_CMD 7 /* Target context update */ -#define TGT_STS_CMD 8 /* Target R2T and other BHS - * where only the status number - * need to be updated - */ -#define TGT_DATAIN_CMD 9 /* Target Data-Ins in response - * to read command - */ -#define TGT_SOS_PDU 10 /* Target:standalone status - * response - */ -#define TGT_DM_CMD 11 /* Indicates that the bhs - * preparedby - * driver should not be touched - */ -/* --- CMD_CHUTE_TYPE --- */ -#define CMD_CONNECTION_CHUTE_0 1 -#define CMD_CONNECTION_CHUTE_1 2 -#define CMD_CONNECTION_CHUTE_2 3 - -#define EQ_MAJOR_CODE_COMPLETION 0 - -#define CMD_ISCSI_SESSION_DEL_CFG_FROM_FLASH 0 -#define CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH 1 - -/* --- CONNECTION_UPLOAD_PARAMS --- */ -/* These parameters are used to define the type of upload desired. */ -#define CONNECTION_UPLOAD_GRACEFUL 1 /* Graceful upload */ -#define CONNECTION_UPLOAD_ABORT_RESET 2 /* Abortive upload with - * reset - */ -#define CONNECTION_UPLOAD_ABORT 3 /* Abortive upload without - * reset - */ -#define CONNECTION_UPLOAD_ABORT_WITH_SEQ 4 /* Abortive upload with reset, - * sequence number by driver */ - -/* Returns byte size of given field with a structure. */ - -/* Returns the number of items in the field array. */ -#define BE_NUMBER_OF_FIELD(_type_, _field_) \ - (FIELD_SIZEOF(_type_, _field_)/sizeof((((_type_ *)0)->_field_[0])))\ - -/** - * Different types of iSCSI completions to host driver for both initiator - * and taget mode - * of operation. - */ -#define SOL_CMD_COMPLETE 1 /* Solicited command completed - * normally - */ -#define SOL_CMD_KILLED_DATA_DIGEST_ERR 2 /* Solicited command got - * invalidated internally due - * to Data Digest error - */ -#define CXN_KILLED_PDU_SIZE_EXCEEDS_DSL 3 /* Connection got invalidated - * internally - * due to a received PDU - * size > DSL - */ -#define CXN_KILLED_BURST_LEN_MISMATCH 4 /* Connection got invalidated - * internally due ti received - * PDU sequence size > - * FBL/MBL. - */ -#define CXN_KILLED_AHS_RCVD 5 /* Connection got invalidated - * internally due to a received - * PDU Hdr that has - * AHS */ -#define CXN_KILLED_HDR_DIGEST_ERR 6 /* Connection got invalidated - * internally due to Hdr Digest - * error - */ -#define CXN_KILLED_UNKNOWN_HDR 7 /* Connection got invalidated - * internally - * due to a bad opcode in the - * pdu hdr - */ -#define CXN_KILLED_STALE_ITT_TTT_RCVD 8 /* Connection got invalidated - * internally due to a received - * ITT/TTT that does not belong - * to this Connection - */ -#define CXN_KILLED_INVALID_ITT_TTT_RCVD 9 /* Connection got invalidated - * internally due to received - * ITT/TTT value > Max - * Supported ITTs/TTTs - */ -#define CXN_KILLED_RST_RCVD 10 /* Connection got invalidated - * internally due to an - * incoming TCP RST - */ -#define CXN_KILLED_TIMED_OUT 11 /* Connection got invalidated - * internally due to timeout on - * tcp segment 12 retransmit - * attempts failed - */ -#define CXN_KILLED_RST_SENT 12 /* Connection got invalidated - * internally due to TCP RST - * sent by the Tx side - */ -#define CXN_KILLED_FIN_RCVD 13 /* Connection got invalidated - * internally due to an - * incoming TCP FIN. - */ -#define CXN_KILLED_BAD_UNSOL_PDU_RCVD 14 /* Connection got invalidated - * internally due to bad - * unsolicited PDU Unsolicited - * PDUs are PDUs with - * ITT=0xffffffff - */ -#define CXN_KILLED_BAD_WRB_INDEX_ERROR 15 /* Connection got invalidated - * internally due to bad WRB - * index. - */ -#define CXN_KILLED_OVER_RUN_RESIDUAL 16 /* Command got invalidated - * internally due to received - * command has residual - * over run bytes. - */ -#define CXN_KILLED_UNDER_RUN_RESIDUAL 17 /* Command got invalidated - * internally due to received - * command has residual under - * run bytes. - */ -#define CMD_KILLED_INVALID_STATSN_RCVD 18 /* Command got invalidated - * internally due to a received - * PDU has an invalid StatusSN - */ -#define CMD_KILLED_INVALID_R2T_RCVD 19 /* Command got invalidated - * internally due to a received - * an R2T with some invalid - * fields in it - */ -#define CMD_CXN_KILLED_LUN_INVALID 20 /* Command got invalidated - * internally due to received - * PDU has an invalid LUN. - */ -#define CMD_CXN_KILLED_ICD_INVALID 21 /* Command got invalidated - * internally due to the - * corresponding ICD not in a - * valid state - */ -#define CMD_CXN_KILLED_ITT_INVALID 22 /* Command got invalidated due - * to received PDU has an - * invalid ITT. - */ -#define CMD_CXN_KILLED_SEQ_OUTOFORDER 23 /* Command got invalidated due - * to received sequence buffer - * offset is out of order. - */ -#define CMD_CXN_KILLED_INVALID_DATASN_RCVD 24 /* Command got invalidated - * internally due to a - * received PDU has an invalid - * DataSN - */ -#define CXN_INVALIDATE_NOTIFY 25 /* Connection invalidation - * completion notify. - */ -#define CXN_INVALIDATE_INDEX_NOTIFY 26 /* Connection invalidation - * completion - * with data PDU index. - */ -#define CMD_INVALIDATED_NOTIFY 27 /* Command invalidation - * completionnotifify. - */ -#define UNSOL_HDR_NOTIFY 28 /* Unsolicited header notify.*/ -#define UNSOL_DATA_NOTIFY 29 /* Unsolicited data notify.*/ -#define UNSOL_DATA_DIGEST_ERROR_NOTIFY 30 /* Unsolicited data digest - * error notify. - */ -#define DRIVERMSG_NOTIFY 31 /* TCP acknowledge based - * notification. - */ -#define CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN 32 /* Connection got invalidated - * internally due to command - * and data are not on same - * connection. - */ -#define SOL_CMD_KILLED_DIF_ERR 33 /* Solicited command got - * invalidated internally due - * to DIF error - */ -#define CXN_KILLED_SYN_RCVD 34 /* Connection got invalidated - * internally due to incoming - * TCP SYN - */ -#define CXN_KILLED_IMM_DATA_RCVD 35 /* Connection got invalidated - * internally due to an - * incoming Unsolicited PDU - * that has immediate data on - * the cxn - */ - -int beiscsi_pci_soft_reset(struct beiscsi_hba *phba); -int be_chk_reset_complete(struct beiscsi_hba *phba); - -void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len, - bool embedded, u8 sge_cnt); - -void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr, - u8 subsystem, u8 opcode, int cmd_len); - -#endif /* !BEISCSI_CMDS_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.c b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.c deleted file mode 100644 index 33c8f09c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.c +++ /dev/null @@ -1,787 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "be_iscsi.h" - -extern struct iscsi_transport beiscsi_iscsi_transport; - -/** - * beiscsi_session_create - creates a new iscsi session - * @cmds_max: max commands supported - * @qdepth: max queue depth supported - * @initial_cmdsn: initial iscsi CMDSN - */ -struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, - u16 cmds_max, - u16 qdepth, - u32 initial_cmdsn) -{ - struct Scsi_Host *shost; - struct beiscsi_endpoint *beiscsi_ep; - struct iscsi_cls_session *cls_session; - struct beiscsi_hba *phba; - struct iscsi_session *sess; - struct beiscsi_session *beiscsi_sess; - struct beiscsi_io_task *io_task; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_session_create\n"); - - if (!ep) { - SE_DEBUG(DBG_LVL_1, "beiscsi_session_create: invalid ep\n"); - return NULL; - } - beiscsi_ep = ep->dd_data; - phba = beiscsi_ep->phba; - shost = phba->shost; - if (cmds_max > beiscsi_ep->phba->params.wrbs_per_cxn) { - shost_printk(KERN_ERR, shost, "Cannot handle %d cmds." - "Max cmds per session supported is %d. Using %d. " - "\n", cmds_max, - beiscsi_ep->phba->params.wrbs_per_cxn, - beiscsi_ep->phba->params.wrbs_per_cxn); - cmds_max = beiscsi_ep->phba->params.wrbs_per_cxn; - } - - cls_session = iscsi_session_setup(&beiscsi_iscsi_transport, - shost, cmds_max, - sizeof(*beiscsi_sess), - sizeof(*io_task), - initial_cmdsn, ISCSI_MAX_TARGET); - if (!cls_session) - return NULL; - sess = cls_session->dd_data; - beiscsi_sess = sess->dd_data; - beiscsi_sess->bhs_pool = pci_pool_create("beiscsi_bhs_pool", - phba->pcidev, - sizeof(struct be_cmd_bhs), - 64, 0); - if (!beiscsi_sess->bhs_pool) - goto destroy_sess; - - return cls_session; -destroy_sess: - iscsi_session_teardown(cls_session); - return NULL; -} - -/** - * beiscsi_session_destroy - destroys iscsi session - * @cls_session: pointer to iscsi cls session - * - * Destroys iSCSI session instance and releases - * resources allocated for it. - */ -void beiscsi_session_destroy(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *sess = cls_session->dd_data; - struct beiscsi_session *beiscsi_sess = sess->dd_data; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_session_destroy\n"); - pci_pool_destroy(beiscsi_sess->bhs_pool); - iscsi_session_teardown(cls_session); -} - -/** - * beiscsi_conn_create - create an instance of iscsi connection - * @cls_session: ptr to iscsi_cls_session - * @cid: iscsi cid - */ -struct iscsi_cls_conn * -beiscsi_conn_create(struct iscsi_cls_session *cls_session, u32 cid) -{ - struct beiscsi_hba *phba; - struct Scsi_Host *shost; - struct iscsi_cls_conn *cls_conn; - struct beiscsi_conn *beiscsi_conn; - struct iscsi_conn *conn; - struct iscsi_session *sess; - struct beiscsi_session *beiscsi_sess; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_create ,cid" - "from iscsi layer=%d\n", cid); - shost = iscsi_session_to_shost(cls_session); - phba = iscsi_host_priv(shost); - - cls_conn = iscsi_conn_setup(cls_session, sizeof(*beiscsi_conn), cid); - if (!cls_conn) - return NULL; - - conn = cls_conn->dd_data; - beiscsi_conn = conn->dd_data; - beiscsi_conn->ep = NULL; - beiscsi_conn->phba = phba; - beiscsi_conn->conn = conn; - sess = cls_session->dd_data; - beiscsi_sess = sess->dd_data; - beiscsi_conn->beiscsi_sess = beiscsi_sess; - return cls_conn; -} - -/** - * beiscsi_bindconn_cid - Bind the beiscsi_conn with phba connection table - * @beiscsi_conn: The pointer to beiscsi_conn structure - * @phba: The phba instance - * @cid: The cid to free - */ -static int beiscsi_bindconn_cid(struct beiscsi_hba *phba, - struct beiscsi_conn *beiscsi_conn, - unsigned int cid) -{ - if (phba->conn_table[cid]) { - SE_DEBUG(DBG_LVL_1, - "Connection table already occupied. Detected clash\n"); - return -EINVAL; - } else { - SE_DEBUG(DBG_LVL_8, "phba->conn_table[%d]=%p(beiscsi_conn)\n", - cid, beiscsi_conn); - phba->conn_table[cid] = beiscsi_conn; - } - return 0; -} - -/** - * beiscsi_conn_bind - Binds iscsi session/connection with TCP connection - * @cls_session: pointer to iscsi cls session - * @cls_conn: pointer to iscsi cls conn - * @transport_fd: EP handle(64 bit) - * - * This function binds the TCP Conn with iSCSI Connection and Session. - */ -int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, - u64 transport_fd, int is_leading) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct beiscsi_conn *beiscsi_conn = conn->dd_data; - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct beiscsi_hba *phba = iscsi_host_priv(shost); - struct beiscsi_endpoint *beiscsi_ep; - struct iscsi_endpoint *ep; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_bind\n"); - ep = iscsi_lookup_endpoint(transport_fd); - if (!ep) - return -EINVAL; - - beiscsi_ep = ep->dd_data; - - if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) - return -EINVAL; - - if (beiscsi_ep->phba != phba) { - SE_DEBUG(DBG_LVL_8, - "beiscsi_ep->hba=%p not equal to phba=%p\n", - beiscsi_ep->phba, phba); - return -EEXIST; - } - - beiscsi_conn->beiscsi_conn_cid = beiscsi_ep->ep_cid; - beiscsi_conn->ep = beiscsi_ep; - beiscsi_ep->conn = beiscsi_conn; - SE_DEBUG(DBG_LVL_8, "beiscsi_conn=%p conn=%p ep_cid=%d\n", - beiscsi_conn, conn, beiscsi_ep->ep_cid); - return beiscsi_bindconn_cid(phba, beiscsi_conn, beiscsi_ep->ep_cid); -} - -/** - * beiscsi_ep_get_param - get the iscsi parameter - * @ep: pointer to iscsi ep - * @param: parameter type identifier - * @buf: buffer pointer - * - * returns iscsi parameter - */ -int beiscsi_ep_get_param(struct iscsi_endpoint *ep, - enum iscsi_param param, char *buf) -{ - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; - int len = 0; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_param, param= %d\n", param); - - switch (param) { - case ISCSI_PARAM_CONN_PORT: - len = sprintf(buf, "%hu\n", beiscsi_ep->dst_tcpport); - break; - case ISCSI_PARAM_CONN_ADDRESS: - if (beiscsi_ep->ip_type == BE2_IPV4) - len = sprintf(buf, "%pI4\n", &beiscsi_ep->dst_addr); - else - len = sprintf(buf, "%pI6\n", &beiscsi_ep->dst6_addr); - break; - default: - return -ENOSYS; - } - return len; -} - -int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf, int buflen) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - int ret; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_set_param, param= %d\n", param); - ret = iscsi_set_param(cls_conn, param, buf, buflen); - if (ret) - return ret; - /* - * If userspace tried to set the value to higher than we can - * support override here. - */ - switch (param) { - case ISCSI_PARAM_FIRST_BURST: - if (session->first_burst > 8192) - session->first_burst = 8192; - break; - case ISCSI_PARAM_MAX_RECV_DLENGTH: - if (conn->max_recv_dlength > 65536) - conn->max_recv_dlength = 65536; - break; - case ISCSI_PARAM_MAX_BURST: - if (session->max_burst > 262144) - session->max_burst = 262144; - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - if ((conn->max_xmit_dlength > 65536) || - (conn->max_xmit_dlength == 0)) - conn->max_xmit_dlength = 65536; - default: - return 0; - } - - return 0; -} - -/** - * beiscsi_get_host_param - get the iscsi parameter - * @shost: pointer to scsi_host structure - * @param: parameter type identifier - * @buf: buffer pointer - * - * returns host parameter - */ -int beiscsi_get_host_param(struct Scsi_Host *shost, - enum iscsi_host_param param, char *buf) -{ - struct beiscsi_hba *phba = iscsi_host_priv(shost); - int status = 0; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_get_host_param, param= %d\n", param); - switch (param) { - case ISCSI_HOST_PARAM_HWADDRESS: - status = beiscsi_get_macaddr(buf, phba); - if (status < 0) { - SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n"); - return status; - } - break; - default: - return iscsi_host_get_param(shost, param, buf); - } - return status; -} - -int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba) -{ - struct be_cmd_resp_get_mac_addr *resp; - struct be_mcc_wrb *wrb; - unsigned int tag, wrb_num; - unsigned short status, extd_status; - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; - int rc; - - if (phba->read_mac_address) - return sysfs_format_mac(buf, phba->mac_address, - ETH_ALEN); - - tag = be_cmd_get_mac_addr(phba); - if (!tag) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); - return -EBUSY; - } else - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - - wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; - extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; - status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; - if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "Failed to get be_cmd_get_mac_addr" - " status = %d extd_status = %d\n", - status, extd_status); - free_mcc_tag(&phba->ctrl, tag); - return -EAGAIN; - } - wrb = queue_get_wrb(mccq, wrb_num); - free_mcc_tag(&phba->ctrl, tag); - resp = embedded_payload(wrb); - memcpy(phba->mac_address, resp->mac_address, ETH_ALEN); - rc = sysfs_format_mac(buf, phba->mac_address, - ETH_ALEN); - phba->read_mac_address = 1; - return rc; -} - - -/** - * beiscsi_conn_get_stats - get the iscsi stats - * @cls_conn: pointer to iscsi cls conn - * @stats: pointer to iscsi_stats structure - * - * returns iscsi stats - */ -void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_get_stats\n"); - stats->txdata_octets = conn->txdata_octets; - stats->rxdata_octets = conn->rxdata_octets; - stats->dataout_pdus = conn->dataout_pdus_cnt; - stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; - stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; - stats->datain_pdus = conn->datain_pdus_cnt; - stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; - stats->r2t_pdus = conn->r2t_pdus_cnt; - stats->digest_err = 0; - stats->timeout_err = 0; - stats->custom_length = 0; - strcpy(stats->custom[0].desc, "eh_abort_cnt"); - stats->custom[0].value = conn->eh_abort_cnt; -} - -/** - * beiscsi_set_params_for_offld - get the parameters for offload - * @beiscsi_conn: pointer to beiscsi_conn - * @params: pointer to offload_params structure - */ -static void beiscsi_set_params_for_offld(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_offload_params *params) -{ - struct iscsi_conn *conn = beiscsi_conn->conn; - struct iscsi_session *session = conn->session; - - AMAP_SET_BITS(struct amap_beiscsi_offload_params, max_burst_length, - params, session->max_burst); - AMAP_SET_BITS(struct amap_beiscsi_offload_params, - max_send_data_segment_length, params, - conn->max_xmit_dlength); - AMAP_SET_BITS(struct amap_beiscsi_offload_params, first_burst_length, - params, session->first_burst); - AMAP_SET_BITS(struct amap_beiscsi_offload_params, erl, params, - session->erl); - AMAP_SET_BITS(struct amap_beiscsi_offload_params, dde, params, - conn->datadgst_en); - AMAP_SET_BITS(struct amap_beiscsi_offload_params, hde, params, - conn->hdrdgst_en); - AMAP_SET_BITS(struct amap_beiscsi_offload_params, ir2t, params, - session->initial_r2t_en); - AMAP_SET_BITS(struct amap_beiscsi_offload_params, imd, params, - session->imm_data_en); - AMAP_SET_BITS(struct amap_beiscsi_offload_params, exp_statsn, params, - (conn->exp_statsn - 1)); -} - -/** - * beiscsi_conn_start - offload of session to chip - * @cls_conn: pointer to beiscsi_conn - */ -int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct beiscsi_conn *beiscsi_conn = conn->dd_data; - struct beiscsi_endpoint *beiscsi_ep; - struct beiscsi_offload_params params; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_conn_start\n"); - memset(¶ms, 0, sizeof(struct beiscsi_offload_params)); - beiscsi_ep = beiscsi_conn->ep; - if (!beiscsi_ep) - SE_DEBUG(DBG_LVL_1, "In beiscsi_conn_start , no beiscsi_ep\n"); - - beiscsi_conn->login_in_progress = 0; - beiscsi_set_params_for_offld(beiscsi_conn, ¶ms); - beiscsi_offload_connection(beiscsi_conn, ¶ms); - iscsi_conn_start(cls_conn); - return 0; -} - -/** - * beiscsi_get_cid - Allocate a cid - * @phba: The phba instance - */ -static int beiscsi_get_cid(struct beiscsi_hba *phba) -{ - unsigned short cid = 0xFFFF; - - if (!phba->avlbl_cids) - return cid; - - cid = phba->cid_array[phba->cid_alloc++]; - if (phba->cid_alloc == phba->params.cxns_per_ctrl) - phba->cid_alloc = 0; - phba->avlbl_cids--; - return cid; -} - -/** - * beiscsi_put_cid - Free the cid - * @phba: The phba for which the cid is being freed - * @cid: The cid to free - */ -static void beiscsi_put_cid(struct beiscsi_hba *phba, unsigned short cid) -{ - phba->avlbl_cids++; - phba->cid_array[phba->cid_free++] = cid; - if (phba->cid_free == phba->params.cxns_per_ctrl) - phba->cid_free = 0; -} - -/** - * beiscsi_free_ep - free endpoint - * @ep: pointer to iscsi endpoint structure - */ -static void beiscsi_free_ep(struct beiscsi_endpoint *beiscsi_ep) -{ - struct beiscsi_hba *phba = beiscsi_ep->phba; - - beiscsi_put_cid(phba, beiscsi_ep->ep_cid); - beiscsi_ep->phba = NULL; -} - -/** - * beiscsi_open_conn - Ask FW to open a TCP connection - * @ep: endpoint to be used - * @src_addr: The source IP address - * @dst_addr: The Destination IP address - * - * Asks the FW to open a TCP connection - */ -static int beiscsi_open_conn(struct iscsi_endpoint *ep, - struct sockaddr *src_addr, - struct sockaddr *dst_addr, int non_blocking) -{ - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; - struct beiscsi_hba *phba = beiscsi_ep->phba; - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; - struct be_mcc_wrb *wrb; - struct tcp_connect_and_offload_out *ptcpcnct_out; - unsigned short status, extd_status; - struct be_dma_mem nonemb_cmd; - unsigned int tag, wrb_num; - int ret = -ENOMEM; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn\n"); - beiscsi_ep->ep_cid = beiscsi_get_cid(phba); - if (beiscsi_ep->ep_cid == 0xFFFF) { - SE_DEBUG(DBG_LVL_1, "No free cid available\n"); - return ret; - } - SE_DEBUG(DBG_LVL_8, "In beiscsi_open_conn, ep_cid=%d\n", - beiscsi_ep->ep_cid); - phba->ep_array[beiscsi_ep->ep_cid - - phba->fw_config.iscsi_cid_start] = ep; - if (beiscsi_ep->ep_cid > (phba->fw_config.iscsi_cid_start + - phba->params.cxns_per_ctrl * 2)) { - SE_DEBUG(DBG_LVL_1, "Failed in allocate iscsi cid\n"); - goto free_ep; - } - - beiscsi_ep->cid_vld = 0; - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, - sizeof(struct tcp_connect_and_offload_in), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - SE_DEBUG(DBG_LVL_1, - "Failed to allocate memory for mgmt_open_connection" - "\n"); - beiscsi_put_cid(phba, beiscsi_ep->ep_cid); - return -ENOMEM; - } - nonemb_cmd.size = sizeof(struct tcp_connect_and_offload_in); - memset(nonemb_cmd.va, 0, nonemb_cmd.size); - tag = mgmt_open_connection(phba, dst_addr, beiscsi_ep, &nonemb_cmd); - if (!tag) { - SE_DEBUG(DBG_LVL_1, - "mgmt_open_connection Failed for cid=%d\n", - beiscsi_ep->ep_cid); - beiscsi_put_cid(phba, beiscsi_ep->ep_cid); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return -EAGAIN; - } else { - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - } - wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; - extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; - status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; - if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "mgmt_open_connection Failed" - " status = %d extd_status = %d\n", - status, extd_status); - free_mcc_tag(&phba->ctrl, tag); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - goto free_ep; - } else { - wrb = queue_get_wrb(mccq, wrb_num); - free_mcc_tag(&phba->ctrl, tag); - - ptcpcnct_out = embedded_payload(wrb); - beiscsi_ep = ep->dd_data; - beiscsi_ep->fw_handle = ptcpcnct_out->connection_handle; - beiscsi_ep->cid_vld = 1; - SE_DEBUG(DBG_LVL_8, "mgmt_open_connection Success\n"); - } - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return 0; - -free_ep: - beiscsi_free_ep(beiscsi_ep); - return -EBUSY; -} - -/** - * beiscsi_ep_connect - Ask chip to create TCP Conn - * @scsi_host: Pointer to scsi_host structure - * @dst_addr: The IP address of Target - * @non_blocking: blocking or non-blocking call - * - * This routines first asks chip to create a connection and then allocates an EP - */ -struct iscsi_endpoint * -beiscsi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, - int non_blocking) -{ - struct beiscsi_hba *phba; - struct beiscsi_endpoint *beiscsi_ep; - struct iscsi_endpoint *ep; - int ret; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_connect\n"); - if (shost) - phba = iscsi_host_priv(shost); - else { - ret = -ENXIO; - SE_DEBUG(DBG_LVL_1, "shost is NULL\n"); - return ERR_PTR(ret); - } - - if (phba->state != BE_ADAPTER_UP) { - ret = -EBUSY; - SE_DEBUG(DBG_LVL_1, "The Adapter state is Not UP\n"); - return ERR_PTR(ret); - } - - ep = iscsi_create_endpoint(sizeof(struct beiscsi_endpoint)); - if (!ep) { - ret = -ENOMEM; - return ERR_PTR(ret); - } - - beiscsi_ep = ep->dd_data; - beiscsi_ep->phba = phba; - beiscsi_ep->openiscsi_ep = ep; - ret = beiscsi_open_conn(ep, NULL, dst_addr, non_blocking); - if (ret) { - SE_DEBUG(DBG_LVL_1, "Failed in beiscsi_open_conn\n"); - goto free_ep; - } - - return ep; - -free_ep: - iscsi_destroy_endpoint(ep); - return ERR_PTR(ret); -} - -/** - * beiscsi_ep_poll - Poll to see if connection is established - * @ep: endpoint to be used - * @timeout_ms: timeout specified in millisecs - * - * Poll to see if TCP connection established - */ -int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) -{ - struct beiscsi_endpoint *beiscsi_ep = ep->dd_data; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_poll\n"); - if (beiscsi_ep->cid_vld == 1) - return 1; - else - return 0; -} - -/** - * beiscsi_close_conn - Upload the connection - * @ep: The iscsi endpoint - * @flag: The type of connection closure - */ -static int beiscsi_close_conn(struct beiscsi_endpoint *beiscsi_ep, int flag) -{ - int ret = 0; - unsigned int tag; - struct beiscsi_hba *phba = beiscsi_ep->phba; - - tag = mgmt_upload_connection(phba, beiscsi_ep->ep_cid, flag); - if (!tag) { - SE_DEBUG(DBG_LVL_8, "upload failed for cid 0x%x\n", - beiscsi_ep->ep_cid); - ret = -EAGAIN; - } else { - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - free_mcc_tag(&phba->ctrl, tag); - } - return ret; -} - -/** - * beiscsi_unbind_conn_to_cid - Unbind the beiscsi_conn from phba conn table - * @phba: The phba instance - * @cid: The cid to free - */ -static int beiscsi_unbind_conn_to_cid(struct beiscsi_hba *phba, - unsigned int cid) -{ - if (phba->conn_table[cid]) - phba->conn_table[cid] = NULL; - else { - SE_DEBUG(DBG_LVL_8, "Connection table Not occupied.\n"); - return -EINVAL; - } - return 0; -} - -/** - * beiscsi_ep_disconnect - Tears down the TCP connection - * @ep: endpoint to be used - * - * Tears down the TCP connection - */ -void beiscsi_ep_disconnect(struct iscsi_endpoint *ep) -{ - struct beiscsi_conn *beiscsi_conn; - struct beiscsi_endpoint *beiscsi_ep; - struct beiscsi_hba *phba; - unsigned int tag; - unsigned short savecfg_flag = CMD_ISCSI_SESSION_SAVE_CFG_ON_FLASH; - - beiscsi_ep = ep->dd_data; - phba = beiscsi_ep->phba; - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect for ep_cid = %d\n", - beiscsi_ep->ep_cid); - - if (!beiscsi_ep->conn) { - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect, no " - "beiscsi_ep\n"); - return; - } - beiscsi_conn = beiscsi_ep->conn; - iscsi_suspend_queue(beiscsi_conn->conn); - - SE_DEBUG(DBG_LVL_8, "In beiscsi_ep_disconnect ep_cid = %d\n", - beiscsi_ep->ep_cid); - - tag = mgmt_invalidate_connection(phba, beiscsi_ep, - beiscsi_ep->ep_cid, 1, - savecfg_flag); - if (!tag) { - SE_DEBUG(DBG_LVL_1, - "mgmt_invalidate_connection Failed for cid=%d\n", - beiscsi_ep->ep_cid); - } else { - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - free_mcc_tag(&phba->ctrl, tag); - } - - beiscsi_close_conn(beiscsi_ep, CONNECTION_UPLOAD_GRACEFUL); - beiscsi_free_ep(beiscsi_ep); - beiscsi_unbind_conn_to_cid(phba, beiscsi_ep->ep_cid); - iscsi_destroy_endpoint(beiscsi_ep->openiscsi_ep); -} - -umode_t be2iscsi_attr_is_visible(int param_type, int param) -{ - switch (param_type) { - case ISCSI_HOST_PARAM: - switch (param) { - case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_IPADDRESS: - case ISCSI_HOST_PARAM_INITIATOR_NAME: - return S_IRUGO; - default: - return 0; - } - case ISCSI_PARAM: - switch (param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - case ISCSI_PARAM_HDRDGST_EN: - case ISCSI_PARAM_DATADGST_EN: - case ISCSI_PARAM_CONN_ADDRESS: - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_EXP_STATSN: - case ISCSI_PARAM_PERSISTENT_ADDRESS: - case ISCSI_PARAM_PERSISTENT_PORT: - case ISCSI_PARAM_PING_TMO: - case ISCSI_PARAM_RECV_TMO: - case ISCSI_PARAM_INITIAL_R2T_EN: - case ISCSI_PARAM_MAX_R2T: - case ISCSI_PARAM_IMM_DATA_EN: - case ISCSI_PARAM_FIRST_BURST: - case ISCSI_PARAM_MAX_BURST: - case ISCSI_PARAM_PDU_INORDER_EN: - case ISCSI_PARAM_DATASEQ_INORDER_EN: - case ISCSI_PARAM_ERL: - case ISCSI_PARAM_TARGET_NAME: - case ISCSI_PARAM_TPGT: - case ISCSI_PARAM_USERNAME: - case ISCSI_PARAM_PASSWORD: - case ISCSI_PARAM_USERNAME_IN: - case ISCSI_PARAM_PASSWORD_IN: - case ISCSI_PARAM_FAST_ABORT: - case ISCSI_PARAM_ABORT_TMO: - case ISCSI_PARAM_LU_RESET_TMO: - case ISCSI_PARAM_IFACE_NAME: - case ISCSI_PARAM_INITIATOR_NAME: - return S_IRUGO; - default: - return 0; - } - } - - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.h b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.h deleted file mode 100644 index 5c45be13..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_iscsi.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#ifndef _BE_ISCSI_ -#define _BE_ISCSI_ - -#include "be_main.h" -#include "be_mgmt.h" - -#define BE2_IPV4 0x1 -#define BE2_IPV6 0x10 - -umode_t be2iscsi_attr_is_visible(int param_type, int param); - -void beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_offload_params *params); - -void beiscsi_offload_iscsi(struct beiscsi_hba *phba, struct iscsi_conn *conn, - struct beiscsi_conn *beiscsi_conn, - unsigned int fw_handle); - -struct iscsi_cls_session *beiscsi_session_create(struct iscsi_endpoint *ep, - uint16_t cmds_max, - uint16_t qdepth, - uint32_t initial_cmdsn); - -void beiscsi_session_destroy(struct iscsi_cls_session *cls_session); - -struct iscsi_cls_conn *beiscsi_conn_create(struct iscsi_cls_session - *cls_session, uint32_t cid); - -int beiscsi_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, - uint64_t transport_fd, int is_leading); - -int beiscsi_ep_get_param(struct iscsi_endpoint *ep, enum iscsi_param param, - char *buf); - -int beiscsi_get_host_param(struct Scsi_Host *shost, - enum iscsi_host_param param, char *buf); - -int beiscsi_get_macaddr(char *buf, struct beiscsi_hba *phba); - -int beiscsi_set_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf, int buflen); - -int beiscsi_conn_start(struct iscsi_cls_conn *cls_conn); - -struct iscsi_endpoint *beiscsi_ep_connect(struct Scsi_Host *shost, - struct sockaddr *dst_addr, - int non_blocking); - -int beiscsi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms); - -void beiscsi_ep_disconnect(struct iscsi_endpoint *ep); - -void beiscsi_conn_get_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.c b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.c deleted file mode 100644 index 375756fa..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.c +++ /dev/null @@ -1,4485 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include "be_main.h" -#include "be_iscsi.h" -#include "be_mgmt.h" - -static unsigned int be_iopoll_budget = 10; -static unsigned int be_max_phys_size = 64; -static unsigned int enable_msix = 1; -static unsigned int gcrashmode = 0; -static unsigned int num_hba = 0; - -MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); -MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR); -MODULE_AUTHOR("ServerEngines Corporation"); -MODULE_LICENSE("GPL"); -module_param(be_iopoll_budget, int, 0); -module_param(enable_msix, int, 0); -module_param(be_max_phys_size, uint, S_IRUGO); -MODULE_PARM_DESC(be_max_phys_size, "Maximum Size (In Kilobytes) of physically" - "contiguous memory that can be allocated." - "Range is 16 - 128"); - -static int beiscsi_slave_configure(struct scsi_device *sdev) -{ - blk_queue_max_segment_size(sdev->request_queue, 65536); - return 0; -} - -static int beiscsi_eh_abort(struct scsi_cmnd *sc) -{ - struct iscsi_cls_session *cls_session; - struct iscsi_task *aborted_task = (struct iscsi_task *)sc->SCp.ptr; - struct beiscsi_io_task *aborted_io_task; - struct iscsi_conn *conn; - struct beiscsi_conn *beiscsi_conn; - struct beiscsi_hba *phba; - struct iscsi_session *session; - struct invalidate_command_table *inv_tbl; - struct be_dma_mem nonemb_cmd; - unsigned int cid, tag, num_invalidate; - - cls_session = starget_to_session(scsi_target(sc->device)); - session = cls_session->dd_data; - - spin_lock_bh(&session->lock); - if (!aborted_task || !aborted_task->sc) { - /* we raced */ - spin_unlock_bh(&session->lock); - return SUCCESS; - } - - aborted_io_task = aborted_task->dd_data; - if (!aborted_io_task->scsi_cmnd) { - /* raced or invalid command */ - spin_unlock_bh(&session->lock); - return SUCCESS; - } - spin_unlock_bh(&session->lock); - conn = aborted_task->conn; - beiscsi_conn = conn->dd_data; - phba = beiscsi_conn->phba; - - /* invalidate iocb */ - cid = beiscsi_conn->beiscsi_conn_cid; - inv_tbl = phba->inv_tbl; - memset(inv_tbl, 0x0, sizeof(*inv_tbl)); - inv_tbl->cid = cid; - inv_tbl->icd = aborted_io_task->psgl_handle->sgl_index; - num_invalidate = 1; - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, - sizeof(struct invalidate_commands_params_in), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - SE_DEBUG(DBG_LVL_1, - "Failed to allocate memory for" - "mgmt_invalidate_icds\n"); - return FAILED; - } - nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); - - tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, - cid, &nonemb_cmd); - if (!tag) { - shost_printk(KERN_WARNING, phba->shost, - "mgmt_invalidate_icds could not be" - " submitted\n"); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - - return FAILED; - } else { - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - free_mcc_tag(&phba->ctrl, tag); - } - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return iscsi_eh_abort(sc); -} - -static int beiscsi_eh_device_reset(struct scsi_cmnd *sc) -{ - struct iscsi_task *abrt_task; - struct beiscsi_io_task *abrt_io_task; - struct iscsi_conn *conn; - struct beiscsi_conn *beiscsi_conn; - struct beiscsi_hba *phba; - struct iscsi_session *session; - struct iscsi_cls_session *cls_session; - struct invalidate_command_table *inv_tbl; - struct be_dma_mem nonemb_cmd; - unsigned int cid, tag, i, num_invalidate; - int rc = FAILED; - - /* invalidate iocbs */ - cls_session = starget_to_session(scsi_target(sc->device)); - session = cls_session->dd_data; - spin_lock_bh(&session->lock); - if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) - goto unlock; - - conn = session->leadconn; - beiscsi_conn = conn->dd_data; - phba = beiscsi_conn->phba; - cid = beiscsi_conn->beiscsi_conn_cid; - inv_tbl = phba->inv_tbl; - memset(inv_tbl, 0x0, sizeof(*inv_tbl) * BE2_CMDS_PER_CXN); - num_invalidate = 0; - for (i = 0; i < conn->session->cmds_max; i++) { - abrt_task = conn->session->cmds[i]; - abrt_io_task = abrt_task->dd_data; - if (!abrt_task->sc || abrt_task->state == ISCSI_TASK_FREE) - continue; - - if (abrt_task->sc->device->lun != abrt_task->sc->device->lun) - continue; - - inv_tbl->cid = cid; - inv_tbl->icd = abrt_io_task->psgl_handle->sgl_index; - num_invalidate++; - inv_tbl++; - } - spin_unlock_bh(&session->lock); - inv_tbl = phba->inv_tbl; - - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, - sizeof(struct invalidate_commands_params_in), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - SE_DEBUG(DBG_LVL_1, - "Failed to allocate memory for" - "mgmt_invalidate_icds\n"); - return FAILED; - } - nonemb_cmd.size = sizeof(struct invalidate_commands_params_in); - memset(nonemb_cmd.va, 0, nonemb_cmd.size); - tag = mgmt_invalidate_icds(phba, inv_tbl, num_invalidate, - cid, &nonemb_cmd); - if (!tag) { - shost_printk(KERN_WARNING, phba->shost, - "mgmt_invalidate_icds could not be" - " submitted\n"); - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return FAILED; - } else { - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - free_mcc_tag(&phba->ctrl, tag); - } - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return iscsi_eh_device_reset(sc); -unlock: - spin_unlock_bh(&session->lock); - return rc; -} - -static ssize_t beiscsi_show_boot_tgt_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - struct mgmt_session_info *boot_sess = &phba->boot_sess; - struct mgmt_conn_info *boot_conn = &boot_sess->conn_list[0]; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_TGT_NAME: - rc = sprintf(buf, "%.*s\n", - (int)strlen(boot_sess->target_name), - (char *)&boot_sess->target_name); - break; - case ISCSI_BOOT_TGT_IP_ADDR: - if (boot_conn->dest_ipaddr.ip_type == 0x1) - rc = sprintf(buf, "%pI4\n", - (char *)&boot_conn->dest_ipaddr.ip_address); - else - rc = sprintf(str, "%pI6\n", - (char *)&boot_conn->dest_ipaddr.ip_address); - break; - case ISCSI_BOOT_TGT_PORT: - rc = sprintf(str, "%d\n", boot_conn->dest_port); - break; - - case ISCSI_BOOT_TGT_CHAP_NAME: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_chap_name); - break; - case ISCSI_BOOT_TGT_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - target_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.target_secret); - break; - case ISCSI_BOOT_TGT_REV_CHAP_NAME: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_chap_name_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_chap_name); - break; - case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->negotiated_login_options.auth_data.chap. - intr_secret_length, - (char *)&boot_conn->negotiated_login_options. - auth_data.chap.intr_secret); - break; - case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "2\n"); - break; - case ISCSI_BOOT_TGT_NIC_ASSOC: - rc = sprintf(str, "0\n"); - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - -static ssize_t beiscsi_show_boot_ini_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = sprintf(str, "%s\n", phba->boot_sess.initiator_iscsiname); - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - -static ssize_t beiscsi_show_boot_eth_info(void *data, int type, char *buf) -{ - struct beiscsi_hba *phba = data; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "2\n"); - break; - case ISCSI_BOOT_ETH_INDEX: - rc = sprintf(str, "0\n"); - break; - case ISCSI_BOOT_ETH_MAC: - rc = beiscsi_get_macaddr(buf, phba); - if (rc < 0) { - SE_DEBUG(DBG_LVL_1, "beiscsi_get_macaddr Failed\n"); - return rc; - } - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - - -static umode_t beiscsi_tgt_get_attr_visibility(void *data, int type) -{ - umode_t rc; - - switch (type) { - case ISCSI_BOOT_TGT_NAME: - case ISCSI_BOOT_TGT_IP_ADDR: - case ISCSI_BOOT_TGT_PORT: - case ISCSI_BOOT_TGT_CHAP_NAME: - case ISCSI_BOOT_TGT_CHAP_SECRET: - case ISCSI_BOOT_TGT_REV_CHAP_NAME: - case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - case ISCSI_BOOT_TGT_NIC_ASSOC: - case ISCSI_BOOT_TGT_FLAGS: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - -static umode_t beiscsi_ini_get_attr_visibility(void *data, int type) -{ - umode_t rc; - - switch (type) { - case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - - -static umode_t beiscsi_eth_get_attr_visibility(void *data, int type) -{ - umode_t rc; - - switch (type) { - case ISCSI_BOOT_ETH_FLAGS: - case ISCSI_BOOT_ETH_MAC: - case ISCSI_BOOT_ETH_INDEX: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - -/*------------------- PCI Driver operations and data ----------------- */ -static DEFINE_PCI_DEVICE_TABLE(beiscsi_pci_id_table) = { - { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID1) }, - { PCI_DEVICE(BE_VENDOR_ID, BE_DEVICE_ID2) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID1) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID2) }, - { PCI_DEVICE(BE_VENDOR_ID, OC_DEVICE_ID3) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table); - -static struct scsi_host_template beiscsi_sht = { - .module = THIS_MODULE, - .name = "ServerEngines 10Gbe open-iscsi Initiator Driver", - .proc_name = DRV_NAME, - .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, - .slave_configure = beiscsi_slave_configure, - .target_alloc = iscsi_target_alloc, - .eh_abort_handler = beiscsi_eh_abort, - .eh_device_reset_handler = beiscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_session_reset, - .sg_tablesize = BEISCSI_SGLIST_ELEMENTS, - .can_queue = BE2_IO_DEPTH, - .this_id = -1, - .max_sectors = BEISCSI_MAX_SECTORS, - .cmd_per_lun = BEISCSI_CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, -}; - -static struct scsi_transport_template *beiscsi_scsi_transport; - -static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev) -{ - struct beiscsi_hba *phba; - struct Scsi_Host *shost; - - shost = iscsi_host_alloc(&beiscsi_sht, sizeof(*phba), 0); - if (!shost) { - dev_err(&pcidev->dev, "beiscsi_hba_alloc -" - "iscsi_host_alloc failed\n"); - return NULL; - } - shost->dma_boundary = pcidev->dma_mask; - shost->max_id = BE2_MAX_SESSIONS; - shost->max_channel = 0; - shost->max_cmd_len = BEISCSI_MAX_CMD_LEN; - shost->max_lun = BEISCSI_NUM_MAX_LUN; - shost->transportt = beiscsi_scsi_transport; - phba = iscsi_host_priv(shost); - memset(phba, 0, sizeof(*phba)); - phba->shost = shost; - phba->pcidev = pci_dev_get(pcidev); - pci_set_drvdata(pcidev, phba); - - if (iscsi_host_add(shost, &phba->pcidev->dev)) - goto free_devices; - - return phba; - -free_devices: - pci_dev_put(phba->pcidev); - iscsi_host_free(phba->shost); - return NULL; -} - -static void beiscsi_unmap_pci_function(struct beiscsi_hba *phba) -{ - if (phba->csr_va) { - iounmap(phba->csr_va); - phba->csr_va = NULL; - } - if (phba->db_va) { - iounmap(phba->db_va); - phba->db_va = NULL; - } - if (phba->pci_va) { - iounmap(phba->pci_va); - phba->pci_va = NULL; - } -} - -static int beiscsi_map_pci_bars(struct beiscsi_hba *phba, - struct pci_dev *pcidev) -{ - u8 __iomem *addr; - int pcicfg_reg; - - addr = ioremap_nocache(pci_resource_start(pcidev, 2), - pci_resource_len(pcidev, 2)); - if (addr == NULL) - return -ENOMEM; - phba->ctrl.csr = addr; - phba->csr_va = addr; - phba->csr_pa.u.a64.address = pci_resource_start(pcidev, 2); - - addr = ioremap_nocache(pci_resource_start(pcidev, 4), 128 * 1024); - if (addr == NULL) - goto pci_map_err; - phba->ctrl.db = addr; - phba->db_va = addr; - phba->db_pa.u.a64.address = pci_resource_start(pcidev, 4); - - if (phba->generation == BE_GEN2) - pcicfg_reg = 1; - else - pcicfg_reg = 0; - - addr = ioremap_nocache(pci_resource_start(pcidev, pcicfg_reg), - pci_resource_len(pcidev, pcicfg_reg)); - - if (addr == NULL) - goto pci_map_err; - phba->ctrl.pcicfg = addr; - phba->pci_va = addr; - phba->pci_pa.u.a64.address = pci_resource_start(pcidev, pcicfg_reg); - return 0; - -pci_map_err: - beiscsi_unmap_pci_function(phba); - return -ENOMEM; -} - -static int beiscsi_enable_pci(struct pci_dev *pcidev) -{ - int ret; - - ret = pci_enable_device(pcidev); - if (ret) { - dev_err(&pcidev->dev, "beiscsi_enable_pci - enable device " - "failed. Returning -ENODEV\n"); - return ret; - } - - pci_set_master(pcidev); - if (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(64))) { - ret = pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32)); - if (ret) { - dev_err(&pcidev->dev, "Could not set PCI DMA Mask\n"); - pci_disable_device(pcidev); - return ret; - } - } - return 0; -} - -static int be_ctrl_init(struct beiscsi_hba *phba, struct pci_dev *pdev) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced; - struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem; - int status = 0; - - ctrl->pdev = pdev; - status = beiscsi_map_pci_bars(phba, pdev); - if (status) - return status; - mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16; - mbox_mem_alloc->va = pci_alloc_consistent(pdev, - mbox_mem_alloc->size, - &mbox_mem_alloc->dma); - if (!mbox_mem_alloc->va) { - beiscsi_unmap_pci_function(phba); - status = -ENOMEM; - return status; - } - - mbox_mem_align->size = sizeof(struct be_mcc_mailbox); - mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); - mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); - memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); - spin_lock_init(&ctrl->mbox_lock); - spin_lock_init(&phba->ctrl.mcc_lock); - spin_lock_init(&phba->ctrl.mcc_cq_lock); - - return status; -} - -static void beiscsi_get_params(struct beiscsi_hba *phba) -{ - phba->params.ios_per_ctrl = (phba->fw_config.iscsi_icd_count - - (phba->fw_config.iscsi_cid_count - + BE2_TMFS - + BE2_NOPOUT_REQ)); - phba->params.cxns_per_ctrl = phba->fw_config.iscsi_cid_count; - phba->params.asyncpdus_per_ctrl = phba->fw_config.iscsi_cid_count * 2; - phba->params.icds_per_ctrl = phba->fw_config.iscsi_icd_count; - phba->params.num_sge_per_io = BE2_SGE; - phba->params.defpdu_hdr_sz = BE2_DEFPDU_HDR_SZ; - phba->params.defpdu_data_sz = BE2_DEFPDU_DATA_SZ; - phba->params.eq_timer = 64; - phba->params.num_eq_entries = - (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 - + BE2_TMFS) / 512) + 1) * 512; - phba->params.num_eq_entries = (phba->params.num_eq_entries < 1024) - ? 1024 : phba->params.num_eq_entries; - SE_DEBUG(DBG_LVL_8, "phba->params.num_eq_entries=%d\n", - phba->params.num_eq_entries); - phba->params.num_cq_entries = - (((BE2_CMDS_PER_CXN * 2 + phba->fw_config.iscsi_cid_count * 2 - + BE2_TMFS) / 512) + 1) * 512; - phba->params.wrbs_per_cxn = 256; -} - -static void hwi_ring_eq_db(struct beiscsi_hba *phba, - unsigned int id, unsigned int clr_interrupt, - unsigned int num_processed, - unsigned char rearm, unsigned char event) -{ - u32 val = 0; - val |= id & DB_EQ_RING_ID_MASK; - if (rearm) - val |= 1 << DB_EQ_REARM_SHIFT; - if (clr_interrupt) - val |= 1 << DB_EQ_CLR_SHIFT; - if (event) - val |= 1 << DB_EQ_EVNT_SHIFT; - val |= num_processed << DB_EQ_NUM_POPPED_SHIFT; - iowrite32(val, phba->db_va + DB_EQ_OFFSET); -} - -/** - * be_isr_mcc - The isr routine of the driver. - * @irq: Not used - * @dev_id: Pointer to host adapter structure - */ -static irqreturn_t be_isr_mcc(int irq, void *dev_id) -{ - struct beiscsi_hba *phba; - struct be_eq_entry *eqe = NULL; - struct be_queue_info *eq; - struct be_queue_info *mcc; - unsigned int num_eq_processed; - struct be_eq_obj *pbe_eq; - unsigned long flags; - - pbe_eq = dev_id; - eq = &pbe_eq->q; - phba = pbe_eq->phba; - mcc = &phba->ctrl.mcc_obj.cq; - eqe = queue_tail_node(eq); - if (!eqe) - SE_DEBUG(DBG_LVL_1, "eqe is NULL\n"); - - num_eq_processed = 0; - - while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] - & EQE_VALID_MASK) { - if (((eqe->dw[offsetof(struct amap_eq_entry, - resource_id) / 32] & - EQE_RESID_MASK) >> 16) == mcc->id) { - spin_lock_irqsave(&phba->isr_lock, flags); - phba->todo_mcc_cq = 1; - spin_unlock_irqrestore(&phba->isr_lock, flags); - } - AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); - queue_tail_inc(eq); - eqe = queue_tail_node(eq); - num_eq_processed++; - } - if (phba->todo_mcc_cq) - queue_work(phba->wq, &phba->work_cqs); - if (num_eq_processed) - hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 1, 1); - - return IRQ_HANDLED; -} - -/** - * be_isr_msix - The isr routine of the driver. - * @irq: Not used - * @dev_id: Pointer to host adapter structure - */ -static irqreturn_t be_isr_msix(int irq, void *dev_id) -{ - struct beiscsi_hba *phba; - struct be_eq_entry *eqe = NULL; - struct be_queue_info *eq; - struct be_queue_info *cq; - unsigned int num_eq_processed; - struct be_eq_obj *pbe_eq; - unsigned long flags; - - pbe_eq = dev_id; - eq = &pbe_eq->q; - cq = pbe_eq->cq; - eqe = queue_tail_node(eq); - if (!eqe) - SE_DEBUG(DBG_LVL_1, "eqe is NULL\n"); - - phba = pbe_eq->phba; - num_eq_processed = 0; - if (blk_iopoll_enabled) { - while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] - & EQE_VALID_MASK) { - if (!blk_iopoll_sched_prep(&pbe_eq->iopoll)) - blk_iopoll_sched(&pbe_eq->iopoll); - - AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); - queue_tail_inc(eq); - eqe = queue_tail_node(eq); - num_eq_processed++; - } - if (num_eq_processed) - hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 0, 1); - - return IRQ_HANDLED; - } else { - while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] - & EQE_VALID_MASK) { - spin_lock_irqsave(&phba->isr_lock, flags); - phba->todo_cq = 1; - spin_unlock_irqrestore(&phba->isr_lock, flags); - AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); - queue_tail_inc(eq); - eqe = queue_tail_node(eq); - num_eq_processed++; - } - if (phba->todo_cq) - queue_work(phba->wq, &phba->work_cqs); - - if (num_eq_processed) - hwi_ring_eq_db(phba, eq->id, 1, num_eq_processed, 1, 1); - - return IRQ_HANDLED; - } -} - -/** - * be_isr - The isr routine of the driver. - * @irq: Not used - * @dev_id: Pointer to host adapter structure - */ -static irqreturn_t be_isr(int irq, void *dev_id) -{ - struct beiscsi_hba *phba; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct be_eq_entry *eqe = NULL; - struct be_queue_info *eq; - struct be_queue_info *cq; - struct be_queue_info *mcc; - unsigned long flags, index; - unsigned int num_mcceq_processed, num_ioeq_processed; - struct be_ctrl_info *ctrl; - struct be_eq_obj *pbe_eq; - int isr; - - phba = dev_id; - ctrl = &phba->ctrl; - isr = ioread32(ctrl->csr + CEV_ISR0_OFFSET + - (PCI_FUNC(ctrl->pdev->devfn) * CEV_ISR_SIZE)); - if (!isr) - return IRQ_NONE; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - pbe_eq = &phwi_context->be_eq[0]; - - eq = &phwi_context->be_eq[0].q; - mcc = &phba->ctrl.mcc_obj.cq; - index = 0; - eqe = queue_tail_node(eq); - if (!eqe) - SE_DEBUG(DBG_LVL_1, "eqe is NULL\n"); - - num_ioeq_processed = 0; - num_mcceq_processed = 0; - if (blk_iopoll_enabled) { - while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] - & EQE_VALID_MASK) { - if (((eqe->dw[offsetof(struct amap_eq_entry, - resource_id) / 32] & - EQE_RESID_MASK) >> 16) == mcc->id) { - spin_lock_irqsave(&phba->isr_lock, flags); - phba->todo_mcc_cq = 1; - spin_unlock_irqrestore(&phba->isr_lock, flags); - num_mcceq_processed++; - } else { - if (!blk_iopoll_sched_prep(&pbe_eq->iopoll)) - blk_iopoll_sched(&pbe_eq->iopoll); - num_ioeq_processed++; - } - AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); - queue_tail_inc(eq); - eqe = queue_tail_node(eq); - } - if (num_ioeq_processed || num_mcceq_processed) { - if (phba->todo_mcc_cq) - queue_work(phba->wq, &phba->work_cqs); - - if ((num_mcceq_processed) && (!num_ioeq_processed)) - hwi_ring_eq_db(phba, eq->id, 0, - (num_ioeq_processed + - num_mcceq_processed) , 1, 1); - else - hwi_ring_eq_db(phba, eq->id, 0, - (num_ioeq_processed + - num_mcceq_processed), 0, 1); - - return IRQ_HANDLED; - } else - return IRQ_NONE; - } else { - cq = &phwi_context->be_cq[0]; - while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] - & EQE_VALID_MASK) { - - if (((eqe->dw[offsetof(struct amap_eq_entry, - resource_id) / 32] & - EQE_RESID_MASK) >> 16) != cq->id) { - spin_lock_irqsave(&phba->isr_lock, flags); - phba->todo_mcc_cq = 1; - spin_unlock_irqrestore(&phba->isr_lock, flags); - } else { - spin_lock_irqsave(&phba->isr_lock, flags); - phba->todo_cq = 1; - spin_unlock_irqrestore(&phba->isr_lock, flags); - } - AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); - queue_tail_inc(eq); - eqe = queue_tail_node(eq); - num_ioeq_processed++; - } - if (phba->todo_cq || phba->todo_mcc_cq) - queue_work(phba->wq, &phba->work_cqs); - - if (num_ioeq_processed) { - hwi_ring_eq_db(phba, eq->id, 0, - num_ioeq_processed, 1, 1); - return IRQ_HANDLED; - } else - return IRQ_NONE; - } -} - -static int beiscsi_init_irqs(struct beiscsi_hba *phba) -{ - struct pci_dev *pcidev = phba->pcidev; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - int ret, msix_vec, i, j; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - - if (phba->msix_enabled) { - for (i = 0; i < phba->num_cpus; i++) { - phba->msi_name[i] = kzalloc(BEISCSI_MSI_NAME, - GFP_KERNEL); - if (!phba->msi_name[i]) { - ret = -ENOMEM; - goto free_msix_irqs; - } - - sprintf(phba->msi_name[i], "beiscsi_%02x_%02x", - phba->shost->host_no, i); - msix_vec = phba->msix_entries[i].vector; - ret = request_irq(msix_vec, be_isr_msix, 0, - phba->msi_name[i], - &phwi_context->be_eq[i]); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "beiscsi_init_irqs-Failed to" - "register msix for i = %d\n", i); - kfree(phba->msi_name[i]); - goto free_msix_irqs; - } - } - phba->msi_name[i] = kzalloc(BEISCSI_MSI_NAME, GFP_KERNEL); - if (!phba->msi_name[i]) { - ret = -ENOMEM; - goto free_msix_irqs; - } - sprintf(phba->msi_name[i], "beiscsi_mcc_%02x", - phba->shost->host_no); - msix_vec = phba->msix_entries[i].vector; - ret = request_irq(msix_vec, be_isr_mcc, 0, phba->msi_name[i], - &phwi_context->be_eq[i]); - if (ret) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-" - "Failed to register beiscsi_msix_mcc\n"); - kfree(phba->msi_name[i]); - goto free_msix_irqs; - } - - } else { - ret = request_irq(pcidev->irq, be_isr, IRQF_SHARED, - "beiscsi", phba); - if (ret) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_init_irqs-" - "Failed to register irq\\n"); - return ret; - } - } - return 0; -free_msix_irqs: - for (j = i - 1; j >= 0; j--) { - kfree(phba->msi_name[j]); - msix_vec = phba->msix_entries[j].vector; - free_irq(msix_vec, &phwi_context->be_eq[j]); - } - return ret; -} - -static void hwi_ring_cq_db(struct beiscsi_hba *phba, - unsigned int id, unsigned int num_processed, - unsigned char rearm, unsigned char event) -{ - u32 val = 0; - val |= id & DB_CQ_RING_ID_MASK; - if (rearm) - val |= 1 << DB_CQ_REARM_SHIFT; - val |= num_processed << DB_CQ_NUM_POPPED_SHIFT; - iowrite32(val, phba->db_va + DB_CQ_OFFSET); -} - -static unsigned int -beiscsi_process_async_pdu(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, - unsigned short cid, - struct pdu_base *ppdu, - unsigned long pdu_len, - void *pbuffer, unsigned long buf_len) -{ - struct iscsi_conn *conn = beiscsi_conn->conn; - struct iscsi_session *session = conn->session; - struct iscsi_task *task; - struct beiscsi_io_task *io_task; - struct iscsi_hdr *login_hdr; - - switch (ppdu->dw[offsetof(struct amap_pdu_base, opcode) / 32] & - PDUBASE_OPCODE_MASK) { - case ISCSI_OP_NOOP_IN: - pbuffer = NULL; - buf_len = 0; - break; - case ISCSI_OP_ASYNC_EVENT: - break; - case ISCSI_OP_REJECT: - WARN_ON(!pbuffer); - WARN_ON(!(buf_len == 48)); - SE_DEBUG(DBG_LVL_1, "In ISCSI_OP_REJECT\n"); - break; - case ISCSI_OP_LOGIN_RSP: - case ISCSI_OP_TEXT_RSP: - task = conn->login_task; - io_task = task->dd_data; - login_hdr = (struct iscsi_hdr *)ppdu; - login_hdr->itt = io_task->libiscsi_itt; - break; - default: - shost_printk(KERN_WARNING, phba->shost, - "Unrecognized opcode 0x%x in async msg\n", - (ppdu-> - dw[offsetof(struct amap_pdu_base, opcode) / 32] - & PDUBASE_OPCODE_MASK)); - return 1; - } - - spin_lock_bh(&session->lock); - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)ppdu, pbuffer, buf_len); - spin_unlock_bh(&session->lock); - return 0; -} - -static struct sgl_handle *alloc_io_sgl_handle(struct beiscsi_hba *phba) -{ - struct sgl_handle *psgl_handle; - - if (phba->io_sgl_hndl_avbl) { - SE_DEBUG(DBG_LVL_8, - "In alloc_io_sgl_handle,io_sgl_alloc_index=%d\n", - phba->io_sgl_alloc_index); - psgl_handle = phba->io_sgl_hndl_base[phba-> - io_sgl_alloc_index]; - phba->io_sgl_hndl_base[phba->io_sgl_alloc_index] = NULL; - phba->io_sgl_hndl_avbl--; - if (phba->io_sgl_alloc_index == (phba->params. - ios_per_ctrl - 1)) - phba->io_sgl_alloc_index = 0; - else - phba->io_sgl_alloc_index++; - } else - psgl_handle = NULL; - return psgl_handle; -} - -static void -free_io_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) -{ - SE_DEBUG(DBG_LVL_8, "In free_,io_sgl_free_index=%d\n", - phba->io_sgl_free_index); - if (phba->io_sgl_hndl_base[phba->io_sgl_free_index]) { - /* - * this can happen if clean_task is called on a task that - * failed in xmit_task or alloc_pdu. - */ - SE_DEBUG(DBG_LVL_8, - "Double Free in IO SGL io_sgl_free_index=%d," - "value there=%p\n", phba->io_sgl_free_index, - phba->io_sgl_hndl_base[phba->io_sgl_free_index]); - return; - } - phba->io_sgl_hndl_base[phba->io_sgl_free_index] = psgl_handle; - phba->io_sgl_hndl_avbl++; - if (phba->io_sgl_free_index == (phba->params.ios_per_ctrl - 1)) - phba->io_sgl_free_index = 0; - else - phba->io_sgl_free_index++; -} - -/** - * alloc_wrb_handle - To allocate a wrb handle - * @phba: The hba pointer - * @cid: The cid to use for allocation - * - * This happens under session_lock until submission to chip - */ -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid) -{ - struct hwi_wrb_context *pwrb_context; - struct hwi_controller *phwi_ctrlr; - struct wrb_handle *pwrb_handle, *pwrb_handle_tmp; - - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[cid]; - if (pwrb_context->wrb_handles_available >= 2) { - pwrb_handle = pwrb_context->pwrb_handle_base[ - pwrb_context->alloc_index]; - pwrb_context->wrb_handles_available--; - if (pwrb_context->alloc_index == - (phba->params.wrbs_per_cxn - 1)) - pwrb_context->alloc_index = 0; - else - pwrb_context->alloc_index++; - pwrb_handle_tmp = pwrb_context->pwrb_handle_base[ - pwrb_context->alloc_index]; - pwrb_handle->nxt_wrb_index = pwrb_handle_tmp->wrb_index; - } else - pwrb_handle = NULL; - return pwrb_handle; -} - -/** - * free_wrb_handle - To free the wrb handle back to pool - * @phba: The hba pointer - * @pwrb_context: The context to free from - * @pwrb_handle: The wrb_handle to free - * - * This happens under session_lock until submission to chip - */ -static void -free_wrb_handle(struct beiscsi_hba *phba, struct hwi_wrb_context *pwrb_context, - struct wrb_handle *pwrb_handle) -{ - pwrb_context->pwrb_handle_base[pwrb_context->free_index] = pwrb_handle; - pwrb_context->wrb_handles_available++; - if (pwrb_context->free_index == (phba->params.wrbs_per_cxn - 1)) - pwrb_context->free_index = 0; - else - pwrb_context->free_index++; - - SE_DEBUG(DBG_LVL_8, - "FREE WRB: pwrb_handle=%p free_index=0x%x" - "wrb_handles_available=%d\n", - pwrb_handle, pwrb_context->free_index, - pwrb_context->wrb_handles_available); -} - -static struct sgl_handle *alloc_mgmt_sgl_handle(struct beiscsi_hba *phba) -{ - struct sgl_handle *psgl_handle; - - if (phba->eh_sgl_hndl_avbl) { - psgl_handle = phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index]; - phba->eh_sgl_hndl_base[phba->eh_sgl_alloc_index] = NULL; - SE_DEBUG(DBG_LVL_8, "mgmt_sgl_alloc_index=%d=0x%x\n", - phba->eh_sgl_alloc_index, phba->eh_sgl_alloc_index); - phba->eh_sgl_hndl_avbl--; - if (phba->eh_sgl_alloc_index == - (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl - - 1)) - phba->eh_sgl_alloc_index = 0; - else - phba->eh_sgl_alloc_index++; - } else - psgl_handle = NULL; - return psgl_handle; -} - -void -free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle) -{ - - SE_DEBUG(DBG_LVL_8, "In free_mgmt_sgl_handle,eh_sgl_free_index=%d\n", - phba->eh_sgl_free_index); - if (phba->eh_sgl_hndl_base[phba->eh_sgl_free_index]) { - /* - * this can happen if clean_task is called on a task that - * failed in xmit_task or alloc_pdu. - */ - SE_DEBUG(DBG_LVL_8, - "Double Free in eh SGL ,eh_sgl_free_index=%d\n", - phba->eh_sgl_free_index); - return; - } - phba->eh_sgl_hndl_base[phba->eh_sgl_free_index] = psgl_handle; - phba->eh_sgl_hndl_avbl++; - if (phba->eh_sgl_free_index == - (phba->params.icds_per_ctrl - phba->params.ios_per_ctrl - 1)) - phba->eh_sgl_free_index = 0; - else - phba->eh_sgl_free_index++; -} - -static void -be_complete_io(struct beiscsi_conn *beiscsi_conn, - struct iscsi_task *task, struct sol_cqe *psol) -{ - struct beiscsi_io_task *io_task = task->dd_data; - struct be_status_bhs *sts_bhs = - (struct be_status_bhs *)io_task->cmd_bhs; - struct iscsi_conn *conn = beiscsi_conn->conn; - unsigned char *sense; - u32 resid = 0, exp_cmdsn, max_cmdsn; - u8 rsp, status, flags; - - exp_cmdsn = (psol-> - dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32] - & SOL_EXP_CMD_SN_MASK); - max_cmdsn = ((psol-> - dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32] - & SOL_EXP_CMD_SN_MASK) + - ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) - / 32] & SOL_CMD_WND_MASK) >> 24) - 1); - rsp = ((psol->dw[offsetof(struct amap_sol_cqe, i_resp) / 32] - & SOL_RESP_MASK) >> 16); - status = ((psol->dw[offsetof(struct amap_sol_cqe, i_sts) / 32] - & SOL_STS_MASK) >> 8); - flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] - & SOL_FLAGS_MASK) >> 24) | 0x80; - if (!task->sc) { - if (io_task->scsi_cmnd) - scsi_dma_unmap(io_task->scsi_cmnd); - - return; - } - task->sc->result = (DID_OK << 16) | status; - if (rsp != ISCSI_STATUS_CMD_COMPLETED) { - task->sc->result = DID_ERROR << 16; - goto unmap; - } - - /* bidi not initially supported */ - if (flags & (ISCSI_FLAG_CMD_UNDERFLOW | ISCSI_FLAG_CMD_OVERFLOW)) { - resid = (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / - 32] & SOL_RES_CNT_MASK); - - if (!status && (flags & ISCSI_FLAG_CMD_OVERFLOW)) - task->sc->result = DID_ERROR << 16; - - if (flags & ISCSI_FLAG_CMD_UNDERFLOW) { - scsi_set_resid(task->sc, resid); - if (!status && (scsi_bufflen(task->sc) - resid < - task->sc->underflow)) - task->sc->result = DID_ERROR << 16; - } - } - - if (status == SAM_STAT_CHECK_CONDITION) { - u16 sense_len; - unsigned short *slen = (unsigned short *)sts_bhs->sense_info; - - sense = sts_bhs->sense_info + sizeof(unsigned short); - sense_len = be16_to_cpu(*slen); - memcpy(task->sc->sense_buffer, sense, - min_t(u16, sense_len, SCSI_SENSE_BUFFERSIZE)); - } - - if (io_task->cmd_bhs->iscsi_hdr.flags & ISCSI_FLAG_CMD_READ) { - if (psol->dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32] - & SOL_RES_CNT_MASK) - conn->rxdata_octets += (psol-> - dw[offsetof(struct amap_sol_cqe, i_res_cnt) / 32] - & SOL_RES_CNT_MASK); - } -unmap: - scsi_dma_unmap(io_task->scsi_cmnd); - iscsi_complete_scsi_task(task, exp_cmdsn, max_cmdsn); -} - -static void -be_complete_logout(struct beiscsi_conn *beiscsi_conn, - struct iscsi_task *task, struct sol_cqe *psol) -{ - struct iscsi_logout_rsp *hdr; - struct beiscsi_io_task *io_task = task->dd_data; - struct iscsi_conn *conn = beiscsi_conn->conn; - - hdr = (struct iscsi_logout_rsp *)task->hdr; - hdr->opcode = ISCSI_OP_LOGOUT_RSP; - hdr->t2wait = 5; - hdr->t2retain = 0; - hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] - & SOL_FLAGS_MASK) >> 24) | 0x80; - hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) / - 32] & SOL_RESP_MASK); - hdr->exp_cmdsn = cpu_to_be32(psol-> - dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32] - & SOL_EXP_CMD_SN_MASK); - hdr->max_cmdsn = be32_to_cpu((psol-> - dw[offsetof(struct amap_sol_cqe, i_exp_cmd_sn) / 32] - & SOL_EXP_CMD_SN_MASK) + - ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) - / 32] & SOL_CMD_WND_MASK) >> 24) - 1); - hdr->dlength[0] = 0; - hdr->dlength[1] = 0; - hdr->dlength[2] = 0; - hdr->hlength = 0; - hdr->itt = io_task->libiscsi_itt; - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); -} - -static void -be_complete_tmf(struct beiscsi_conn *beiscsi_conn, - struct iscsi_task *task, struct sol_cqe *psol) -{ - struct iscsi_tm_rsp *hdr; - struct iscsi_conn *conn = beiscsi_conn->conn; - struct beiscsi_io_task *io_task = task->dd_data; - - hdr = (struct iscsi_tm_rsp *)task->hdr; - hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; - hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] - & SOL_FLAGS_MASK) >> 24) | 0x80; - hdr->response = (psol->dw[offsetof(struct amap_sol_cqe, i_resp) / - 32] & SOL_RESP_MASK); - hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe, - i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK); - hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe, - i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) + - ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) - / 32] & SOL_CMD_WND_MASK) >> 24) - 1); - hdr->itt = io_task->libiscsi_itt; - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); -} - -static void -hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, struct sol_cqe *psol) -{ - struct hwi_wrb_context *pwrb_context; - struct wrb_handle *pwrb_handle = NULL; - struct hwi_controller *phwi_ctrlr; - struct iscsi_task *task; - struct beiscsi_io_task *io_task; - struct iscsi_conn *conn = beiscsi_conn->conn; - struct iscsi_session *session = conn->session; - - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[((psol-> - dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6) - - phba->fw_config.iscsi_cid_start]; - pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> - dw[offsetof(struct amap_sol_cqe, wrb_index) / - 32] & SOL_WRB_INDEX_MASK) >> 16)]; - task = pwrb_handle->pio_handle; - - io_task = task->dd_data; - spin_lock(&phba->mgmt_sgl_lock); - free_mgmt_sgl_handle(phba, io_task->psgl_handle); - spin_unlock(&phba->mgmt_sgl_lock); - spin_lock_bh(&session->lock); - free_wrb_handle(phba, pwrb_context, pwrb_handle); - spin_unlock_bh(&session->lock); -} - -static void -be_complete_nopin_resp(struct beiscsi_conn *beiscsi_conn, - struct iscsi_task *task, struct sol_cqe *psol) -{ - struct iscsi_nopin *hdr; - struct iscsi_conn *conn = beiscsi_conn->conn; - struct beiscsi_io_task *io_task = task->dd_data; - - hdr = (struct iscsi_nopin *)task->hdr; - hdr->flags = ((psol->dw[offsetof(struct amap_sol_cqe, i_flags) / 32] - & SOL_FLAGS_MASK) >> 24) | 0x80; - hdr->exp_cmdsn = cpu_to_be32(psol->dw[offsetof(struct amap_sol_cqe, - i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK); - hdr->max_cmdsn = be32_to_cpu((psol->dw[offsetof(struct amap_sol_cqe, - i_exp_cmd_sn) / 32] & SOL_EXP_CMD_SN_MASK) + - ((psol->dw[offsetof(struct amap_sol_cqe, i_cmd_wnd) - / 32] & SOL_CMD_WND_MASK) >> 24) - 1); - hdr->opcode = ISCSI_OP_NOOP_IN; - hdr->itt = io_task->libiscsi_itt; - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); -} - -static void hwi_complete_cmd(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, struct sol_cqe *psol) -{ - struct hwi_wrb_context *pwrb_context; - struct wrb_handle *pwrb_handle; - struct iscsi_wrb *pwrb = NULL; - struct hwi_controller *phwi_ctrlr; - struct iscsi_task *task; - unsigned int type; - struct iscsi_conn *conn = beiscsi_conn->conn; - struct iscsi_session *session = conn->session; - - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[((psol->dw[offsetof - (struct amap_sol_cqe, cid) / 32] - & SOL_CID_MASK) >> 6) - - phba->fw_config.iscsi_cid_start]; - pwrb_handle = pwrb_context->pwrb_handle_basestd[((psol-> - dw[offsetof(struct amap_sol_cqe, wrb_index) / - 32] & SOL_WRB_INDEX_MASK) >> 16)]; - task = pwrb_handle->pio_handle; - pwrb = pwrb_handle->pwrb; - type = (pwrb->dw[offsetof(struct amap_iscsi_wrb, type) / 32] & - WRB_TYPE_MASK) >> 28; - - spin_lock_bh(&session->lock); - switch (type) { - case HWH_TYPE_IO: - case HWH_TYPE_IO_RD: - if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == - ISCSI_OP_NOOP_OUT) - be_complete_nopin_resp(beiscsi_conn, task, psol); - else - be_complete_io(beiscsi_conn, task, psol); - break; - - case HWH_TYPE_LOGOUT: - if ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) - be_complete_logout(beiscsi_conn, task, psol); - else - be_complete_tmf(beiscsi_conn, task, psol); - - break; - - case HWH_TYPE_LOGIN: - SE_DEBUG(DBG_LVL_1, - "\t\t No HWH_TYPE_LOGIN Expected in hwi_complete_cmd" - "- Solicited path\n"); - break; - - case HWH_TYPE_NOP: - be_complete_nopin_resp(beiscsi_conn, task, psol); - break; - - default: - shost_printk(KERN_WARNING, phba->shost, - "In hwi_complete_cmd, unknown type = %d" - "wrb_index 0x%x CID 0x%x\n", type, - ((psol->dw[offsetof(struct amap_iscsi_wrb, - type) / 32] & SOL_WRB_INDEX_MASK) >> 16), - ((psol->dw[offsetof(struct amap_sol_cqe, - cid) / 32] & SOL_CID_MASK) >> 6)); - break; - } - - spin_unlock_bh(&session->lock); -} - -static struct list_head *hwi_get_async_busy_list(struct hwi_async_pdu_context - *pasync_ctx, unsigned int is_header, - unsigned int host_write_ptr) -{ - if (is_header) - return &pasync_ctx->async_entry[host_write_ptr]. - header_busy_list; - else - return &pasync_ctx->async_entry[host_write_ptr].data_busy_list; -} - -static struct async_pdu_handle * -hwi_get_async_handle(struct beiscsi_hba *phba, - struct beiscsi_conn *beiscsi_conn, - struct hwi_async_pdu_context *pasync_ctx, - struct i_t_dpdu_cqe *pdpdu_cqe, unsigned int *pcq_index) -{ - struct be_bus_address phys_addr; - struct list_head *pbusy_list; - struct async_pdu_handle *pasync_handle = NULL; - int buffer_len = 0; - unsigned char buffer_index = -1; - unsigned char is_header = 0; - - phys_addr.u.a32.address_lo = - pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_lo) / 32] - - ((pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32] - & PDUCQE_DPL_MASK) >> 16); - phys_addr.u.a32.address_hi = - pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, db_addr_hi) / 32]; - - phys_addr.u.a64.address = - *((unsigned long long *)(&phys_addr.u.a64.address)); - - switch (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, code) / 32] - & PDUCQE_CODE_MASK) { - case UNSOL_HDR_NOTIFY: - is_header = 1; - - pbusy_list = hwi_get_async_busy_list(pasync_ctx, 1, - (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, - index) / 32] & PDUCQE_INDEX_MASK)); - - buffer_len = (unsigned int)(phys_addr.u.a64.address - - pasync_ctx->async_header.pa_base.u.a64.address); - - buffer_index = buffer_len / - pasync_ctx->async_header.buffer_size; - - break; - case UNSOL_DATA_NOTIFY: - pbusy_list = hwi_get_async_busy_list(pasync_ctx, 0, (pdpdu_cqe-> - dw[offsetof(struct amap_i_t_dpdu_cqe, - index) / 32] & PDUCQE_INDEX_MASK)); - buffer_len = (unsigned long)(phys_addr.u.a64.address - - pasync_ctx->async_data.pa_base.u. - a64.address); - buffer_index = buffer_len / pasync_ctx->async_data.buffer_size; - break; - default: - pbusy_list = NULL; - shost_printk(KERN_WARNING, phba->shost, - "Unexpected code=%d\n", - pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, - code) / 32] & PDUCQE_CODE_MASK); - return NULL; - } - - WARN_ON(!(buffer_index <= pasync_ctx->async_data.num_entries)); - WARN_ON(list_empty(pbusy_list)); - list_for_each_entry(pasync_handle, pbusy_list, link) { - WARN_ON(pasync_handle->consumed); - if (pasync_handle->index == buffer_index) - break; - } - - WARN_ON(!pasync_handle); - - pasync_handle->cri = (unsigned short)beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start; - pasync_handle->is_header = is_header; - pasync_handle->buffer_len = ((pdpdu_cqe-> - dw[offsetof(struct amap_i_t_dpdu_cqe, dpl) / 32] - & PDUCQE_DPL_MASK) >> 16); - - *pcq_index = (pdpdu_cqe->dw[offsetof(struct amap_i_t_dpdu_cqe, - index) / 32] & PDUCQE_INDEX_MASK); - return pasync_handle; -} - -static unsigned int -hwi_update_async_writables(struct hwi_async_pdu_context *pasync_ctx, - unsigned int is_header, unsigned int cq_index) -{ - struct list_head *pbusy_list; - struct async_pdu_handle *pasync_handle; - unsigned int num_entries, writables = 0; - unsigned int *pep_read_ptr, *pwritables; - - - if (is_header) { - pep_read_ptr = &pasync_ctx->async_header.ep_read_ptr; - pwritables = &pasync_ctx->async_header.writables; - num_entries = pasync_ctx->async_header.num_entries; - } else { - pep_read_ptr = &pasync_ctx->async_data.ep_read_ptr; - pwritables = &pasync_ctx->async_data.writables; - num_entries = pasync_ctx->async_data.num_entries; - } - - while ((*pep_read_ptr) != cq_index) { - (*pep_read_ptr)++; - *pep_read_ptr = (*pep_read_ptr) % num_entries; - - pbusy_list = hwi_get_async_busy_list(pasync_ctx, is_header, - *pep_read_ptr); - if (writables == 0) - WARN_ON(list_empty(pbusy_list)); - - if (!list_empty(pbusy_list)) { - pasync_handle = list_entry(pbusy_list->next, - struct async_pdu_handle, - link); - WARN_ON(!pasync_handle); - pasync_handle->consumed = 1; - } - - writables++; - } - - if (!writables) { - SE_DEBUG(DBG_LVL_1, - "Duplicate notification received - index 0x%x!!\n", - cq_index); - WARN_ON(1); - } - - *pwritables = *pwritables + writables; - return 0; -} - -static unsigned int hwi_free_async_msg(struct beiscsi_hba *phba, - unsigned int cri) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_handle, *tmp_handle; - struct list_head *plist; - unsigned int i = 0; - - phwi_ctrlr = phba->phwi_ctrlr; - pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); - - plist = &pasync_ctx->async_entry[cri].wait_queue.list; - - list_for_each_entry_safe(pasync_handle, tmp_handle, plist, link) { - list_del(&pasync_handle->link); - - if (i == 0) { - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_header.free_list); - pasync_ctx->async_header.free_entries++; - i++; - } else { - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_data.free_list); - pasync_ctx->async_data.free_entries++; - i++; - } - } - - INIT_LIST_HEAD(&pasync_ctx->async_entry[cri].wait_queue.list); - pasync_ctx->async_entry[cri].wait_queue.hdr_received = 0; - pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0; - return 0; -} - -static struct phys_addr * -hwi_get_ring_address(struct hwi_async_pdu_context *pasync_ctx, - unsigned int is_header, unsigned int host_write_ptr) -{ - struct phys_addr *pasync_sge = NULL; - - if (is_header) - pasync_sge = pasync_ctx->async_header.ring_base; - else - pasync_sge = pasync_ctx->async_data.ring_base; - - return pasync_sge + host_write_ptr; -} - -static void hwi_post_async_buffers(struct beiscsi_hba *phba, - unsigned int is_header) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_handle; - struct list_head *pfree_link, *pbusy_list; - struct phys_addr *pasync_sge; - unsigned int ring_id, num_entries; - unsigned int host_write_num; - unsigned int writables; - unsigned int i = 0; - u32 doorbell = 0; - - phwi_ctrlr = phba->phwi_ctrlr; - pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); - - if (is_header) { - num_entries = pasync_ctx->async_header.num_entries; - writables = min(pasync_ctx->async_header.writables, - pasync_ctx->async_header.free_entries); - pfree_link = pasync_ctx->async_header.free_list.next; - host_write_num = pasync_ctx->async_header.host_write_ptr; - ring_id = phwi_ctrlr->default_pdu_hdr.id; - } else { - num_entries = pasync_ctx->async_data.num_entries; - writables = min(pasync_ctx->async_data.writables, - pasync_ctx->async_data.free_entries); - pfree_link = pasync_ctx->async_data.free_list.next; - host_write_num = pasync_ctx->async_data.host_write_ptr; - ring_id = phwi_ctrlr->default_pdu_data.id; - } - - writables = (writables / 8) * 8; - if (writables) { - for (i = 0; i < writables; i++) { - pbusy_list = - hwi_get_async_busy_list(pasync_ctx, is_header, - host_write_num); - pasync_handle = - list_entry(pfree_link, struct async_pdu_handle, - link); - WARN_ON(!pasync_handle); - pasync_handle->consumed = 0; - - pfree_link = pfree_link->next; - - pasync_sge = hwi_get_ring_address(pasync_ctx, - is_header, host_write_num); - - pasync_sge->hi = pasync_handle->pa.u.a32.address_lo; - pasync_sge->lo = pasync_handle->pa.u.a32.address_hi; - - list_move(&pasync_handle->link, pbusy_list); - - host_write_num++; - host_write_num = host_write_num % num_entries; - } - - if (is_header) { - pasync_ctx->async_header.host_write_ptr = - host_write_num; - pasync_ctx->async_header.free_entries -= writables; - pasync_ctx->async_header.writables -= writables; - pasync_ctx->async_header.busy_entries += writables; - } else { - pasync_ctx->async_data.host_write_ptr = host_write_num; - pasync_ctx->async_data.free_entries -= writables; - pasync_ctx->async_data.writables -= writables; - pasync_ctx->async_data.busy_entries += writables; - } - - doorbell |= ring_id & DB_DEF_PDU_RING_ID_MASK; - doorbell |= 1 << DB_DEF_PDU_REARM_SHIFT; - doorbell |= 0 << DB_DEF_PDU_EVENT_SHIFT; - doorbell |= (writables & DB_DEF_PDU_CQPROC_MASK) - << DB_DEF_PDU_CQPROC_SHIFT; - - iowrite32(doorbell, phba->db_va + DB_RXULP0_OFFSET); - } -} - -static void hwi_flush_default_pdu_buffer(struct beiscsi_hba *phba, - struct beiscsi_conn *beiscsi_conn, - struct i_t_dpdu_cqe *pdpdu_cqe) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_handle = NULL; - unsigned int cq_index = -1; - - phwi_ctrlr = phba->phwi_ctrlr; - pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); - - pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx, - pdpdu_cqe, &cq_index); - BUG_ON(pasync_handle->is_header != 0); - if (pasync_handle->consumed == 0) - hwi_update_async_writables(pasync_ctx, pasync_handle->is_header, - cq_index); - - hwi_free_async_msg(phba, pasync_handle->cri); - hwi_post_async_buffers(phba, pasync_handle->is_header); -} - -static unsigned int -hwi_fwd_async_msg(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, - struct hwi_async_pdu_context *pasync_ctx, unsigned short cri) -{ - struct list_head *plist; - struct async_pdu_handle *pasync_handle; - void *phdr = NULL; - unsigned int hdr_len = 0, buf_len = 0; - unsigned int status, index = 0, offset = 0; - void *pfirst_buffer = NULL; - unsigned int num_buf = 0; - - plist = &pasync_ctx->async_entry[cri].wait_queue.list; - - list_for_each_entry(pasync_handle, plist, link) { - if (index == 0) { - phdr = pasync_handle->pbuffer; - hdr_len = pasync_handle->buffer_len; - } else { - buf_len = pasync_handle->buffer_len; - if (!num_buf) { - pfirst_buffer = pasync_handle->pbuffer; - num_buf++; - } - memcpy(pfirst_buffer + offset, - pasync_handle->pbuffer, buf_len); - offset = buf_len; - } - index++; - } - - status = beiscsi_process_async_pdu(beiscsi_conn, phba, - (beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start), - phdr, hdr_len, pfirst_buffer, - buf_len); - - if (status == 0) - hwi_free_async_msg(phba, cri); - return 0; -} - -static unsigned int -hwi_gather_async_pdu(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, - struct async_pdu_handle *pasync_handle) -{ - struct hwi_async_pdu_context *pasync_ctx; - struct hwi_controller *phwi_ctrlr; - unsigned int bytes_needed = 0, status = 0; - unsigned short cri = pasync_handle->cri; - struct pdu_base *ppdu; - - phwi_ctrlr = phba->phwi_ctrlr; - pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); - - list_del(&pasync_handle->link); - if (pasync_handle->is_header) { - pasync_ctx->async_header.busy_entries--; - if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) { - hwi_free_async_msg(phba, cri); - BUG(); - } - - pasync_ctx->async_entry[cri].wait_queue.bytes_received = 0; - pasync_ctx->async_entry[cri].wait_queue.hdr_received = 1; - pasync_ctx->async_entry[cri].wait_queue.hdr_len = - (unsigned short)pasync_handle->buffer_len; - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_entry[cri].wait_queue.list); - - ppdu = pasync_handle->pbuffer; - bytes_needed = ((((ppdu->dw[offsetof(struct amap_pdu_base, - data_len_hi) / 32] & PDUBASE_DATALENHI_MASK) << 8) & - 0xFFFF0000) | ((be16_to_cpu((ppdu-> - dw[offsetof(struct amap_pdu_base, data_len_lo) / 32] - & PDUBASE_DATALENLO_MASK) >> 16)) & 0x0000FFFF)); - - if (status == 0) { - pasync_ctx->async_entry[cri].wait_queue.bytes_needed = - bytes_needed; - - if (bytes_needed == 0) - status = hwi_fwd_async_msg(beiscsi_conn, phba, - pasync_ctx, cri); - } - } else { - pasync_ctx->async_data.busy_entries--; - if (pasync_ctx->async_entry[cri].wait_queue.hdr_received) { - list_add_tail(&pasync_handle->link, - &pasync_ctx->async_entry[cri].wait_queue. - list); - pasync_ctx->async_entry[cri].wait_queue. - bytes_received += - (unsigned short)pasync_handle->buffer_len; - - if (pasync_ctx->async_entry[cri].wait_queue. - bytes_received >= - pasync_ctx->async_entry[cri].wait_queue. - bytes_needed) - status = hwi_fwd_async_msg(beiscsi_conn, phba, - pasync_ctx, cri); - } - } - return status; -} - -static void hwi_process_default_pdu_ring(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, - struct i_t_dpdu_cqe *pdpdu_cqe) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_handle = NULL; - unsigned int cq_index = -1; - - phwi_ctrlr = phba->phwi_ctrlr; - pasync_ctx = HWI_GET_ASYNC_PDU_CTX(phwi_ctrlr); - pasync_handle = hwi_get_async_handle(phba, beiscsi_conn, pasync_ctx, - pdpdu_cqe, &cq_index); - - if (pasync_handle->consumed == 0) - hwi_update_async_writables(pasync_ctx, pasync_handle->is_header, - cq_index); - hwi_gather_async_pdu(beiscsi_conn, phba, pasync_handle); - hwi_post_async_buffers(phba, pasync_handle->is_header); -} - -static void beiscsi_process_mcc_isr(struct beiscsi_hba *phba) -{ - struct be_queue_info *mcc_cq; - struct be_mcc_compl *mcc_compl; - unsigned int num_processed = 0; - - mcc_cq = &phba->ctrl.mcc_obj.cq; - mcc_compl = queue_tail_node(mcc_cq); - mcc_compl->flags = le32_to_cpu(mcc_compl->flags); - while (mcc_compl->flags & CQE_FLAGS_VALID_MASK) { - - if (num_processed >= 32) { - hwi_ring_cq_db(phba, mcc_cq->id, - num_processed, 0, 0); - num_processed = 0; - } - if (mcc_compl->flags & CQE_FLAGS_ASYNC_MASK) { - /* Interpret flags as an async trailer */ - if (is_link_state_evt(mcc_compl->flags)) - /* Interpret compl as a async link evt */ - beiscsi_async_link_state_process(phba, - (struct be_async_event_link_state *) mcc_compl); - else - SE_DEBUG(DBG_LVL_1, - " Unsupported Async Event, flags" - " = 0x%08x\n", mcc_compl->flags); - } else if (mcc_compl->flags & CQE_FLAGS_COMPLETED_MASK) { - be_mcc_compl_process_isr(&phba->ctrl, mcc_compl); - atomic_dec(&phba->ctrl.mcc_obj.q.used); - } - - mcc_compl->flags = 0; - queue_tail_inc(mcc_cq); - mcc_compl = queue_tail_node(mcc_cq); - mcc_compl->flags = le32_to_cpu(mcc_compl->flags); - num_processed++; - } - - if (num_processed > 0) - hwi_ring_cq_db(phba, mcc_cq->id, num_processed, 1, 0); - -} - -static unsigned int beiscsi_process_cq(struct be_eq_obj *pbe_eq) -{ - struct be_queue_info *cq; - struct sol_cqe *sol; - struct dmsg_cqe *dmsg; - unsigned int num_processed = 0; - unsigned int tot_nump = 0; - struct beiscsi_conn *beiscsi_conn; - struct beiscsi_endpoint *beiscsi_ep; - struct iscsi_endpoint *ep; - struct beiscsi_hba *phba; - - cq = pbe_eq->cq; - sol = queue_tail_node(cq); - phba = pbe_eq->phba; - - while (sol->dw[offsetof(struct amap_sol_cqe, valid) / 32] & - CQE_VALID_MASK) { - be_dws_le_to_cpu(sol, sizeof(struct sol_cqe)); - - ep = phba->ep_array[(u32) ((sol-> - dw[offsetof(struct amap_sol_cqe, cid) / 32] & - SOL_CID_MASK) >> 6) - - phba->fw_config.iscsi_cid_start]; - - beiscsi_ep = ep->dd_data; - beiscsi_conn = beiscsi_ep->conn; - - if (num_processed >= 32) { - hwi_ring_cq_db(phba, cq->id, - num_processed, 0, 0); - tot_nump += num_processed; - num_processed = 0; - } - - switch ((u32) sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK) { - case SOL_CMD_COMPLETE: - hwi_complete_cmd(beiscsi_conn, phba, sol); - break; - case DRIVERMSG_NOTIFY: - SE_DEBUG(DBG_LVL_8, "Received DRIVERMSG_NOTIFY\n"); - dmsg = (struct dmsg_cqe *)sol; - hwi_complete_drvr_msgs(beiscsi_conn, phba, sol); - break; - case UNSOL_HDR_NOTIFY: - SE_DEBUG(DBG_LVL_8, "Received UNSOL_HDR_ NOTIFY\n"); - hwi_process_default_pdu_ring(beiscsi_conn, phba, - (struct i_t_dpdu_cqe *)sol); - break; - case UNSOL_DATA_NOTIFY: - SE_DEBUG(DBG_LVL_8, "Received UNSOL_DATA_NOTIFY\n"); - hwi_process_default_pdu_ring(beiscsi_conn, phba, - (struct i_t_dpdu_cqe *)sol); - break; - case CXN_INVALIDATE_INDEX_NOTIFY: - case CMD_INVALIDATED_NOTIFY: - case CXN_INVALIDATE_NOTIFY: - SE_DEBUG(DBG_LVL_1, - "Ignoring CQ Error notification for cmd/cxn" - "invalidate\n"); - break; - case SOL_CMD_KILLED_DATA_DIGEST_ERR: - case CMD_KILLED_INVALID_STATSN_RCVD: - case CMD_KILLED_INVALID_R2T_RCVD: - case CMD_CXN_KILLED_LUN_INVALID: - case CMD_CXN_KILLED_ICD_INVALID: - case CMD_CXN_KILLED_ITT_INVALID: - case CMD_CXN_KILLED_SEQ_OUTOFORDER: - case CMD_CXN_KILLED_INVALID_DATASN_RCVD: - SE_DEBUG(DBG_LVL_1, - "CQ Error notification for cmd.. " - "code %d cid 0x%x\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, - (sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & SOL_CID_MASK)); - break; - case UNSOL_DATA_DIGEST_ERROR_NOTIFY: - SE_DEBUG(DBG_LVL_1, - "Digest error on def pdu ring, dropping..\n"); - hwi_flush_default_pdu_buffer(phba, beiscsi_conn, - (struct i_t_dpdu_cqe *) sol); - break; - case CXN_KILLED_PDU_SIZE_EXCEEDS_DSL: - case CXN_KILLED_BURST_LEN_MISMATCH: - case CXN_KILLED_AHS_RCVD: - case CXN_KILLED_HDR_DIGEST_ERR: - case CXN_KILLED_UNKNOWN_HDR: - case CXN_KILLED_STALE_ITT_TTT_RCVD: - case CXN_KILLED_INVALID_ITT_TTT_RCVD: - case CXN_KILLED_TIMED_OUT: - case CXN_KILLED_FIN_RCVD: - case CXN_KILLED_BAD_UNSOL_PDU_RCVD: - case CXN_KILLED_BAD_WRB_INDEX_ERROR: - case CXN_KILLED_OVER_RUN_RESIDUAL: - case CXN_KILLED_UNDER_RUN_RESIDUAL: - case CXN_KILLED_CMND_DATA_NOT_ON_SAME_CONN: - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset CID " - "0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, - (sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK)); - iscsi_conn_failure(beiscsi_conn->conn, - ISCSI_ERR_CONN_FAILED); - break; - case CXN_KILLED_RST_SENT: - case CXN_KILLED_RST_RCVD: - SE_DEBUG(DBG_LVL_1, "CQ Error %d, reset" - "received/sent on CID 0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, - (sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK)); - iscsi_conn_failure(beiscsi_conn->conn, - ISCSI_ERR_CONN_FAILED); - break; - default: - SE_DEBUG(DBG_LVL_1, "CQ Error Invalid code= %d " - "received on CID 0x%x...\n", - sol->dw[offsetof(struct amap_sol_cqe, code) / - 32] & CQE_CODE_MASK, - (sol->dw[offsetof(struct amap_sol_cqe, cid) / - 32] & CQE_CID_MASK)); - break; - } - - AMAP_SET_BITS(struct amap_sol_cqe, valid, sol, 0); - queue_tail_inc(cq); - sol = queue_tail_node(cq); - num_processed++; - } - - if (num_processed > 0) { - tot_nump += num_processed; - hwi_ring_cq_db(phba, cq->id, num_processed, 1, 0); - } - return tot_nump; -} - -void beiscsi_process_all_cqs(struct work_struct *work) -{ - unsigned long flags; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct be_eq_obj *pbe_eq; - struct beiscsi_hba *phba = - container_of(work, struct beiscsi_hba, work_cqs); - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - if (phba->msix_enabled) - pbe_eq = &phwi_context->be_eq[phba->num_cpus]; - else - pbe_eq = &phwi_context->be_eq[0]; - - if (phba->todo_mcc_cq) { - spin_lock_irqsave(&phba->isr_lock, flags); - phba->todo_mcc_cq = 0; - spin_unlock_irqrestore(&phba->isr_lock, flags); - beiscsi_process_mcc_isr(phba); - } - - if (phba->todo_cq) { - spin_lock_irqsave(&phba->isr_lock, flags); - phba->todo_cq = 0; - spin_unlock_irqrestore(&phba->isr_lock, flags); - beiscsi_process_cq(pbe_eq); - } -} - -static int be_iopoll(struct blk_iopoll *iop, int budget) -{ - static unsigned int ret; - struct beiscsi_hba *phba; - struct be_eq_obj *pbe_eq; - - pbe_eq = container_of(iop, struct be_eq_obj, iopoll); - ret = beiscsi_process_cq(pbe_eq); - if (ret < budget) { - phba = pbe_eq->phba; - blk_iopoll_complete(iop); - SE_DEBUG(DBG_LVL_8, "rearm pbe_eq->q.id =%d\n", pbe_eq->q.id); - hwi_ring_eq_db(phba, pbe_eq->q.id, 0, 0, 1, 1); - } - return ret; -} - -static void -hwi_write_sgl(struct iscsi_wrb *pwrb, struct scatterlist *sg, - unsigned int num_sg, struct beiscsi_io_task *io_task) -{ - struct iscsi_sge *psgl; - unsigned int sg_len, index; - unsigned int sge_len = 0; - unsigned long long addr; - struct scatterlist *l_sg; - unsigned int offset; - - AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb, - io_task->bhs_pa.u.a32.address_lo); - AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb, - io_task->bhs_pa.u.a32.address_hi); - - l_sg = sg; - for (index = 0; (index < num_sg) && (index < 2); index++, - sg = sg_next(sg)) { - if (index == 0) { - sg_len = sg_dma_len(sg); - addr = (u64) sg_dma_address(sg); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb, - ((u32)(addr & 0xFFFFFFFF))); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb, - ((u32)(addr >> 32))); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, - sg_len); - sge_len = sg_len; - } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_r2t_offset, - pwrb, sge_len); - sg_len = sg_dma_len(sg); - addr = (u64) sg_dma_address(sg); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_lo, pwrb, - ((u32)(addr & 0xFFFFFFFF))); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_addr_hi, pwrb, - ((u32)(addr >> 32))); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_len, pwrb, - sg_len); - } - } - psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag; - memset(psgl, 0, sizeof(*psgl) * BE2_SGE); - - AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len - 2); - - AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, - io_task->bhs_pa.u.a32.address_hi); - AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, - io_task->bhs_pa.u.a32.address_lo); - - if (num_sg == 1) { - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 1); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, - 0); - } else if (num_sg == 2) { - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 0); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, - 1); - } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, - 0); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge1_last, pwrb, - 0); - } - sg = l_sg; - psgl++; - psgl++; - offset = 0; - for (index = 0; index < num_sg; index++, sg = sg_next(sg), psgl++) { - sg_len = sg_dma_len(sg); - addr = (u64) sg_dma_address(sg); - AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, - (addr & 0xFFFFFFFF)); - AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, - (addr >> 32)); - AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, sg_len); - AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, offset); - AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0); - offset += sg_len; - } - psgl--; - AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1); -} - -static void hwi_write_buffer(struct iscsi_wrb *pwrb, struct iscsi_task *task) -{ - struct iscsi_sge *psgl; - unsigned long long addr; - struct beiscsi_io_task *io_task = task->dd_data; - struct beiscsi_conn *beiscsi_conn = io_task->conn; - struct beiscsi_hba *phba = beiscsi_conn->phba; - - io_task->bhs_len = sizeof(struct be_nonio_bhs) - 2; - AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_lo, pwrb, - io_task->bhs_pa.u.a32.address_lo); - AMAP_SET_BITS(struct amap_iscsi_wrb, iscsi_bhs_addr_hi, pwrb, - io_task->bhs_pa.u.a32.address_hi); - - if (task->data) { - if (task->data_count) { - AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); - addr = (u64) pci_map_single(phba->pcidev, - task->data, - task->data_count, 1); - } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); - addr = 0; - } - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_lo, pwrb, - ((u32)(addr & 0xFFFFFFFF))); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_addr_hi, pwrb, - ((u32)(addr >> 32))); - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_len, pwrb, - task->data_count); - - AMAP_SET_BITS(struct amap_iscsi_wrb, sge0_last, pwrb, 1); - } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); - addr = 0; - } - - psgl = (struct iscsi_sge *)io_task->psgl_handle->pfrag; - - AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, io_task->bhs_len); - - AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, - io_task->bhs_pa.u.a32.address_hi); - AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, - io_task->bhs_pa.u.a32.address_lo); - if (task->data) { - psgl++; - AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, 0); - AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, 0); - AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0); - AMAP_SET_BITS(struct amap_iscsi_sge, sge_offset, psgl, 0); - AMAP_SET_BITS(struct amap_iscsi_sge, rsvd0, psgl, 0); - AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 0); - - psgl++; - if (task->data) { - AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, psgl, - ((u32)(addr & 0xFFFFFFFF))); - AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, psgl, - ((u32)(addr >> 32))); - } - AMAP_SET_BITS(struct amap_iscsi_sge, len, psgl, 0x106); - } - AMAP_SET_BITS(struct amap_iscsi_sge, last_sge, psgl, 1); -} - -static void beiscsi_find_mem_req(struct beiscsi_hba *phba) -{ - unsigned int num_cq_pages, num_async_pdu_buf_pages; - unsigned int num_async_pdu_data_pages, wrb_sz_per_cxn; - unsigned int num_async_pdu_buf_sgl_pages, num_async_pdu_data_sgl_pages; - - num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \ - sizeof(struct sol_cqe)); - num_async_pdu_buf_pages = - PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \ - phba->params.defpdu_hdr_sz); - num_async_pdu_buf_sgl_pages = - PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \ - sizeof(struct phys_addr)); - num_async_pdu_data_pages = - PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \ - phba->params.defpdu_data_sz); - num_async_pdu_data_sgl_pages = - PAGES_REQUIRED(phba->params.asyncpdus_per_ctrl * \ - sizeof(struct phys_addr)); - - phba->params.hwi_ws_sz = sizeof(struct hwi_controller); - - phba->mem_req[ISCSI_MEM_GLOBAL_HEADER] = 2 * - BE_ISCSI_PDU_HEADER_SIZE; - phba->mem_req[HWI_MEM_ADDN_CONTEXT] = - sizeof(struct hwi_context_memory); - - - phba->mem_req[HWI_MEM_WRB] = sizeof(struct iscsi_wrb) - * (phba->params.wrbs_per_cxn) - * phba->params.cxns_per_ctrl; - wrb_sz_per_cxn = sizeof(struct wrb_handle) * - (phba->params.wrbs_per_cxn); - phba->mem_req[HWI_MEM_WRBH] = roundup_pow_of_two((wrb_sz_per_cxn) * - phba->params.cxns_per_ctrl); - - phba->mem_req[HWI_MEM_SGLH] = sizeof(struct sgl_handle) * - phba->params.icds_per_ctrl; - phba->mem_req[HWI_MEM_SGE] = sizeof(struct iscsi_sge) * - phba->params.num_sge_per_io * phba->params.icds_per_ctrl; - - phba->mem_req[HWI_MEM_ASYNC_HEADER_BUF] = - num_async_pdu_buf_pages * PAGE_SIZE; - phba->mem_req[HWI_MEM_ASYNC_DATA_BUF] = - num_async_pdu_data_pages * PAGE_SIZE; - phba->mem_req[HWI_MEM_ASYNC_HEADER_RING] = - num_async_pdu_buf_sgl_pages * PAGE_SIZE; - phba->mem_req[HWI_MEM_ASYNC_DATA_RING] = - num_async_pdu_data_sgl_pages * PAGE_SIZE; - phba->mem_req[HWI_MEM_ASYNC_HEADER_HANDLE] = - phba->params.asyncpdus_per_ctrl * - sizeof(struct async_pdu_handle); - phba->mem_req[HWI_MEM_ASYNC_DATA_HANDLE] = - phba->params.asyncpdus_per_ctrl * - sizeof(struct async_pdu_handle); - phba->mem_req[HWI_MEM_ASYNC_PDU_CONTEXT] = - sizeof(struct hwi_async_pdu_context) + - (phba->params.cxns_per_ctrl * sizeof(struct hwi_async_entry)); -} - -static int beiscsi_alloc_mem(struct beiscsi_hba *phba) -{ - struct be_mem_descriptor *mem_descr; - dma_addr_t bus_add; - struct mem_array *mem_arr, *mem_arr_orig; - unsigned int i, j, alloc_size, curr_alloc_size; - - phba->phwi_ctrlr = kmalloc(phba->params.hwi_ws_sz, GFP_KERNEL); - if (!phba->phwi_ctrlr) - return -ENOMEM; - - phba->init_mem = kcalloc(SE_MEM_MAX, sizeof(*mem_descr), - GFP_KERNEL); - if (!phba->init_mem) { - kfree(phba->phwi_ctrlr); - return -ENOMEM; - } - - mem_arr_orig = kmalloc(sizeof(*mem_arr_orig) * BEISCSI_MAX_FRAGS_INIT, - GFP_KERNEL); - if (!mem_arr_orig) { - kfree(phba->init_mem); - kfree(phba->phwi_ctrlr); - return -ENOMEM; - } - - mem_descr = phba->init_mem; - for (i = 0; i < SE_MEM_MAX; i++) { - j = 0; - mem_arr = mem_arr_orig; - alloc_size = phba->mem_req[i]; - memset(mem_arr, 0, sizeof(struct mem_array) * - BEISCSI_MAX_FRAGS_INIT); - curr_alloc_size = min(be_max_phys_size * 1024, alloc_size); - do { - mem_arr->virtual_address = pci_alloc_consistent( - phba->pcidev, - curr_alloc_size, - &bus_add); - if (!mem_arr->virtual_address) { - if (curr_alloc_size <= BE_MIN_MEM_SIZE) - goto free_mem; - if (curr_alloc_size - - rounddown_pow_of_two(curr_alloc_size)) - curr_alloc_size = rounddown_pow_of_two - (curr_alloc_size); - else - curr_alloc_size = curr_alloc_size / 2; - } else { - mem_arr->bus_address.u. - a64.address = (__u64) bus_add; - mem_arr->size = curr_alloc_size; - alloc_size -= curr_alloc_size; - curr_alloc_size = min(be_max_phys_size * - 1024, alloc_size); - j++; - mem_arr++; - } - } while (alloc_size); - mem_descr->num_elements = j; - mem_descr->size_in_bytes = phba->mem_req[i]; - mem_descr->mem_array = kmalloc(sizeof(*mem_arr) * j, - GFP_KERNEL); - if (!mem_descr->mem_array) - goto free_mem; - - memcpy(mem_descr->mem_array, mem_arr_orig, - sizeof(struct mem_array) * j); - mem_descr++; - } - kfree(mem_arr_orig); - return 0; -free_mem: - mem_descr->num_elements = j; - while ((i) || (j)) { - for (j = mem_descr->num_elements; j > 0; j--) { - pci_free_consistent(phba->pcidev, - mem_descr->mem_array[j - 1].size, - mem_descr->mem_array[j - 1]. - virtual_address, - (unsigned long)mem_descr-> - mem_array[j - 1]. - bus_address.u.a64.address); - } - if (i) { - i--; - kfree(mem_descr->mem_array); - mem_descr--; - } - } - kfree(mem_arr_orig); - kfree(phba->init_mem); - kfree(phba->phwi_ctrlr); - return -ENOMEM; -} - -static int beiscsi_get_memory(struct beiscsi_hba *phba) -{ - beiscsi_find_mem_req(phba); - return beiscsi_alloc_mem(phba); -} - -static void iscsi_init_global_templates(struct beiscsi_hba *phba) -{ - struct pdu_data_out *pdata_out; - struct pdu_nop_out *pnop_out; - struct be_mem_descriptor *mem_descr; - - mem_descr = phba->init_mem; - mem_descr += ISCSI_MEM_GLOBAL_HEADER; - pdata_out = - (struct pdu_data_out *)mem_descr->mem_array[0].virtual_address; - memset(pdata_out, 0, BE_ISCSI_PDU_HEADER_SIZE); - - AMAP_SET_BITS(struct amap_pdu_data_out, opcode, pdata_out, - IIOC_SCSI_DATA); - - pnop_out = - (struct pdu_nop_out *)((unsigned char *)mem_descr->mem_array[0]. - virtual_address + BE_ISCSI_PDU_HEADER_SIZE); - - memset(pnop_out, 0, BE_ISCSI_PDU_HEADER_SIZE); - AMAP_SET_BITS(struct amap_pdu_nop_out, ttt, pnop_out, 0xFFFFFFFF); - AMAP_SET_BITS(struct amap_pdu_nop_out, f_bit, pnop_out, 1); - AMAP_SET_BITS(struct amap_pdu_nop_out, i_bit, pnop_out, 0); -} - -static void beiscsi_init_wrb_handle(struct beiscsi_hba *phba) -{ - struct be_mem_descriptor *mem_descr_wrbh, *mem_descr_wrb; - struct wrb_handle *pwrb_handle; - struct hwi_controller *phwi_ctrlr; - struct hwi_wrb_context *pwrb_context; - struct iscsi_wrb *pwrb; - unsigned int num_cxn_wrbh; - unsigned int num_cxn_wrb, j, idx, index; - - mem_descr_wrbh = phba->init_mem; - mem_descr_wrbh += HWI_MEM_WRBH; - - mem_descr_wrb = phba->init_mem; - mem_descr_wrb += HWI_MEM_WRB; - - idx = 0; - pwrb_handle = mem_descr_wrbh->mem_array[idx].virtual_address; - num_cxn_wrbh = ((mem_descr_wrbh->mem_array[idx].size) / - ((sizeof(struct wrb_handle)) * - phba->params.wrbs_per_cxn)); - phwi_ctrlr = phba->phwi_ctrlr; - - for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) { - pwrb_context = &phwi_ctrlr->wrb_context[index]; - pwrb_context->pwrb_handle_base = - kzalloc(sizeof(struct wrb_handle *) * - phba->params.wrbs_per_cxn, GFP_KERNEL); - pwrb_context->pwrb_handle_basestd = - kzalloc(sizeof(struct wrb_handle *) * - phba->params.wrbs_per_cxn, GFP_KERNEL); - if (num_cxn_wrbh) { - pwrb_context->alloc_index = 0; - pwrb_context->wrb_handles_available = 0; - for (j = 0; j < phba->params.wrbs_per_cxn; j++) { - pwrb_context->pwrb_handle_base[j] = pwrb_handle; - pwrb_context->pwrb_handle_basestd[j] = - pwrb_handle; - pwrb_context->wrb_handles_available++; - pwrb_handle->wrb_index = j; - pwrb_handle++; - } - pwrb_context->free_index = 0; - num_cxn_wrbh--; - } else { - idx++; - pwrb_handle = - mem_descr_wrbh->mem_array[idx].virtual_address; - num_cxn_wrbh = - ((mem_descr_wrbh->mem_array[idx].size) / - ((sizeof(struct wrb_handle)) * - phba->params.wrbs_per_cxn)); - pwrb_context->alloc_index = 0; - for (j = 0; j < phba->params.wrbs_per_cxn; j++) { - pwrb_context->pwrb_handle_base[j] = pwrb_handle; - pwrb_context->pwrb_handle_basestd[j] = - pwrb_handle; - pwrb_context->wrb_handles_available++; - pwrb_handle->wrb_index = j; - pwrb_handle++; - } - pwrb_context->free_index = 0; - num_cxn_wrbh--; - } - } - idx = 0; - pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / - ((sizeof(struct iscsi_wrb) * - phba->params.wrbs_per_cxn)); - for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) { - pwrb_context = &phwi_ctrlr->wrb_context[index]; - if (num_cxn_wrb) { - for (j = 0; j < phba->params.wrbs_per_cxn; j++) { - pwrb_handle = pwrb_context->pwrb_handle_base[j]; - pwrb_handle->pwrb = pwrb; - pwrb++; - } - num_cxn_wrb--; - } else { - idx++; - pwrb = mem_descr_wrb->mem_array[idx].virtual_address; - num_cxn_wrb = (mem_descr_wrb->mem_array[idx].size) / - ((sizeof(struct iscsi_wrb) * - phba->params.wrbs_per_cxn)); - for (j = 0; j < phba->params.wrbs_per_cxn; j++) { - pwrb_handle = pwrb_context->pwrb_handle_base[j]; - pwrb_handle->pwrb = pwrb; - pwrb++; - } - num_cxn_wrb--; - } - } -} - -static void hwi_init_async_pdu_ctx(struct beiscsi_hba *phba) -{ - struct hwi_controller *phwi_ctrlr; - struct hba_parameters *p = &phba->params; - struct hwi_async_pdu_context *pasync_ctx; - struct async_pdu_handle *pasync_header_h, *pasync_data_h; - unsigned int index; - struct be_mem_descriptor *mem_descr; - - mem_descr = (struct be_mem_descriptor *)phba->init_mem; - mem_descr += HWI_MEM_ASYNC_PDU_CONTEXT; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_ctrlr->phwi_ctxt->pasync_ctx = (struct hwi_async_pdu_context *) - mem_descr->mem_array[0].virtual_address; - pasync_ctx = phwi_ctrlr->phwi_ctxt->pasync_ctx; - memset(pasync_ctx, 0, sizeof(*pasync_ctx)); - - pasync_ctx->async_header.num_entries = p->asyncpdus_per_ctrl; - pasync_ctx->async_header.buffer_size = p->defpdu_hdr_sz; - pasync_ctx->async_data.buffer_size = p->defpdu_data_sz; - pasync_ctx->async_data.num_entries = p->asyncpdus_per_ctrl; - - mem_descr = (struct be_mem_descriptor *)phba->init_mem; - mem_descr += HWI_MEM_ASYNC_HEADER_BUF; - if (mem_descr->mem_array[0].virtual_address) { - SE_DEBUG(DBG_LVL_8, - "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_BUF" - "va=%p\n", mem_descr->mem_array[0].virtual_address); - } else - shost_printk(KERN_WARNING, phba->shost, - "No Virtual address\n"); - - pasync_ctx->async_header.va_base = - mem_descr->mem_array[0].virtual_address; - - pasync_ctx->async_header.pa_base.u.a64.address = - mem_descr->mem_array[0].bus_address.u.a64.address; - - mem_descr = (struct be_mem_descriptor *)phba->init_mem; - mem_descr += HWI_MEM_ASYNC_HEADER_RING; - if (mem_descr->mem_array[0].virtual_address) { - SE_DEBUG(DBG_LVL_8, - "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_RING" - "va=%p\n", mem_descr->mem_array[0].virtual_address); - } else - shost_printk(KERN_WARNING, phba->shost, - "No Virtual address\n"); - pasync_ctx->async_header.ring_base = - mem_descr->mem_array[0].virtual_address; - - mem_descr = (struct be_mem_descriptor *)phba->init_mem; - mem_descr += HWI_MEM_ASYNC_HEADER_HANDLE; - if (mem_descr->mem_array[0].virtual_address) { - SE_DEBUG(DBG_LVL_8, - "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_HEADER_HANDLE" - "va=%p\n", mem_descr->mem_array[0].virtual_address); - } else - shost_printk(KERN_WARNING, phba->shost, - "No Virtual address\n"); - - pasync_ctx->async_header.handle_base = - mem_descr->mem_array[0].virtual_address; - pasync_ctx->async_header.writables = 0; - INIT_LIST_HEAD(&pasync_ctx->async_header.free_list); - - mem_descr = (struct be_mem_descriptor *)phba->init_mem; - mem_descr += HWI_MEM_ASYNC_DATA_BUF; - if (mem_descr->mem_array[0].virtual_address) { - SE_DEBUG(DBG_LVL_8, - "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_BUF" - "va=%p\n", mem_descr->mem_array[0].virtual_address); - } else - shost_printk(KERN_WARNING, phba->shost, - "No Virtual address\n"); - pasync_ctx->async_data.va_base = - mem_descr->mem_array[0].virtual_address; - pasync_ctx->async_data.pa_base.u.a64.address = - mem_descr->mem_array[0].bus_address.u.a64.address; - - mem_descr = (struct be_mem_descriptor *)phba->init_mem; - mem_descr += HWI_MEM_ASYNC_DATA_RING; - if (mem_descr->mem_array[0].virtual_address) { - SE_DEBUG(DBG_LVL_8, - "hwi_init_async_pdu_ctx HWI_MEM_ASYNC_DATA_RING" - "va=%p\n", mem_descr->mem_array[0].virtual_address); - } else - shost_printk(KERN_WARNING, phba->shost, - "No Virtual address\n"); - - pasync_ctx->async_data.ring_base = - mem_descr->mem_array[0].virtual_address; - - mem_descr = (struct be_mem_descriptor *)phba->init_mem; - mem_descr += HWI_MEM_ASYNC_DATA_HANDLE; - if (!mem_descr->mem_array[0].virtual_address) - shost_printk(KERN_WARNING, phba->shost, - "No Virtual address\n"); - - pasync_ctx->async_data.handle_base = - mem_descr->mem_array[0].virtual_address; - pasync_ctx->async_data.writables = 0; - INIT_LIST_HEAD(&pasync_ctx->async_data.free_list); - - pasync_header_h = - (struct async_pdu_handle *)pasync_ctx->async_header.handle_base; - pasync_data_h = - (struct async_pdu_handle *)pasync_ctx->async_data.handle_base; - - for (index = 0; index < p->asyncpdus_per_ctrl; index++) { - pasync_header_h->cri = -1; - pasync_header_h->index = (char)index; - INIT_LIST_HEAD(&pasync_header_h->link); - pasync_header_h->pbuffer = - (void *)((unsigned long) - (pasync_ctx->async_header.va_base) + - (p->defpdu_hdr_sz * index)); - - pasync_header_h->pa.u.a64.address = - pasync_ctx->async_header.pa_base.u.a64.address + - (p->defpdu_hdr_sz * index); - - list_add_tail(&pasync_header_h->link, - &pasync_ctx->async_header.free_list); - pasync_header_h++; - pasync_ctx->async_header.free_entries++; - pasync_ctx->async_header.writables++; - - INIT_LIST_HEAD(&pasync_ctx->async_entry[index].wait_queue.list); - INIT_LIST_HEAD(&pasync_ctx->async_entry[index]. - header_busy_list); - pasync_data_h->cri = -1; - pasync_data_h->index = (char)index; - INIT_LIST_HEAD(&pasync_data_h->link); - pasync_data_h->pbuffer = - (void *)((unsigned long) - (pasync_ctx->async_data.va_base) + - (p->defpdu_data_sz * index)); - - pasync_data_h->pa.u.a64.address = - pasync_ctx->async_data.pa_base.u.a64.address + - (p->defpdu_data_sz * index); - - list_add_tail(&pasync_data_h->link, - &pasync_ctx->async_data.free_list); - pasync_data_h++; - pasync_ctx->async_data.free_entries++; - pasync_ctx->async_data.writables++; - - INIT_LIST_HEAD(&pasync_ctx->async_entry[index].data_busy_list); - } - - pasync_ctx->async_header.host_write_ptr = 0; - pasync_ctx->async_header.ep_read_ptr = -1; - pasync_ctx->async_data.host_write_ptr = 0; - pasync_ctx->async_data.ep_read_ptr = -1; -} - -static int -be_sgl_create_contiguous(void *virtual_address, - u64 physical_address, u32 length, - struct be_dma_mem *sgl) -{ - WARN_ON(!virtual_address); - WARN_ON(!physical_address); - WARN_ON(!length > 0); - WARN_ON(!sgl); - - sgl->va = virtual_address; - sgl->dma = (unsigned long)physical_address; - sgl->size = length; - - return 0; -} - -static void be_sgl_destroy_contiguous(struct be_dma_mem *sgl) -{ - memset(sgl, 0, sizeof(*sgl)); -} - -static void -hwi_build_be_sgl_arr(struct beiscsi_hba *phba, - struct mem_array *pmem, struct be_dma_mem *sgl) -{ - if (sgl->va) - be_sgl_destroy_contiguous(sgl); - - be_sgl_create_contiguous(pmem->virtual_address, - pmem->bus_address.u.a64.address, - pmem->size, sgl); -} - -static void -hwi_build_be_sgl_by_offset(struct beiscsi_hba *phba, - struct mem_array *pmem, struct be_dma_mem *sgl) -{ - if (sgl->va) - be_sgl_destroy_contiguous(sgl); - - be_sgl_create_contiguous((unsigned char *)pmem->virtual_address, - pmem->bus_address.u.a64.address, - pmem->size, sgl); -} - -static int be_fill_queue(struct be_queue_info *q, - u16 len, u16 entry_size, void *vaddress) -{ - struct be_dma_mem *mem = &q->dma_mem; - - memset(q, 0, sizeof(*q)); - q->len = len; - q->entry_size = entry_size; - mem->size = len * entry_size; - mem->va = vaddress; - if (!mem->va) - return -ENOMEM; - memset(mem->va, 0, mem->size); - return 0; -} - -static int beiscsi_create_eqs(struct beiscsi_hba *phba, - struct hwi_context_memory *phwi_context) -{ - unsigned int i, num_eq_pages; - int ret, eq_for_mcc; - struct be_queue_info *eq; - struct be_dma_mem *mem; - void *eq_vaddress; - dma_addr_t paddr; - - num_eq_pages = PAGES_REQUIRED(phba->params.num_eq_entries * \ - sizeof(struct be_eq_entry)); - - if (phba->msix_enabled) - eq_for_mcc = 1; - else - eq_for_mcc = 0; - for (i = 0; i < (phba->num_cpus + eq_for_mcc); i++) { - eq = &phwi_context->be_eq[i].q; - mem = &eq->dma_mem; - phwi_context->be_eq[i].phba = phba; - eq_vaddress = pci_alloc_consistent(phba->pcidev, - num_eq_pages * PAGE_SIZE, - &paddr); - if (!eq_vaddress) - goto create_eq_error; - - mem->va = eq_vaddress; - ret = be_fill_queue(eq, phba->params.num_eq_entries, - sizeof(struct be_eq_entry), eq_vaddress); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "be_fill_queue Failed for EQ\n"); - goto create_eq_error; - } - - mem->dma = paddr; - ret = beiscsi_cmd_eq_create(&phba->ctrl, eq, - phwi_context->cur_eqd); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "beiscsi_cmd_eq_create" - "Failedfor EQ\n"); - goto create_eq_error; - } - SE_DEBUG(DBG_LVL_8, "eqid = %d\n", phwi_context->be_eq[i].q.id); - } - return 0; -create_eq_error: - for (i = 0; i < (phba->num_cpus + 1); i++) { - eq = &phwi_context->be_eq[i].q; - mem = &eq->dma_mem; - if (mem->va) - pci_free_consistent(phba->pcidev, num_eq_pages - * PAGE_SIZE, - mem->va, mem->dma); - } - return ret; -} - -static int beiscsi_create_cqs(struct beiscsi_hba *phba, - struct hwi_context_memory *phwi_context) -{ - unsigned int i, num_cq_pages; - int ret; - struct be_queue_info *cq, *eq; - struct be_dma_mem *mem; - struct be_eq_obj *pbe_eq; - void *cq_vaddress; - dma_addr_t paddr; - - num_cq_pages = PAGES_REQUIRED(phba->params.num_cq_entries * \ - sizeof(struct sol_cqe)); - - for (i = 0; i < phba->num_cpus; i++) { - cq = &phwi_context->be_cq[i]; - eq = &phwi_context->be_eq[i].q; - pbe_eq = &phwi_context->be_eq[i]; - pbe_eq->cq = cq; - pbe_eq->phba = phba; - mem = &cq->dma_mem; - cq_vaddress = pci_alloc_consistent(phba->pcidev, - num_cq_pages * PAGE_SIZE, - &paddr); - if (!cq_vaddress) - goto create_cq_error; - ret = be_fill_queue(cq, phba->params.num_cq_entries, - sizeof(struct sol_cqe), cq_vaddress); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "be_fill_queue Failed for ISCSI CQ\n"); - goto create_cq_error; - } - - mem->dma = paddr; - ret = beiscsi_cmd_cq_create(&phba->ctrl, cq, eq, false, - false, 0); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "beiscsi_cmd_eq_create" - "Failed for ISCSI CQ\n"); - goto create_cq_error; - } - SE_DEBUG(DBG_LVL_8, "iscsi cq_id is %d for eq_id %d\n", - cq->id, eq->id); - SE_DEBUG(DBG_LVL_8, "ISCSI CQ CREATED\n"); - } - return 0; - -create_cq_error: - for (i = 0; i < phba->num_cpus; i++) { - cq = &phwi_context->be_cq[i]; - mem = &cq->dma_mem; - if (mem->va) - pci_free_consistent(phba->pcidev, num_cq_pages - * PAGE_SIZE, - mem->va, mem->dma); - } - return ret; - -} - -static int -beiscsi_create_def_hdr(struct beiscsi_hba *phba, - struct hwi_context_memory *phwi_context, - struct hwi_controller *phwi_ctrlr, - unsigned int def_pdu_ring_sz) -{ - unsigned int idx; - int ret; - struct be_queue_info *dq, *cq; - struct be_dma_mem *mem; - struct be_mem_descriptor *mem_descr; - void *dq_vaddress; - - idx = 0; - dq = &phwi_context->be_def_hdrq; - cq = &phwi_context->be_cq[0]; - mem = &dq->dma_mem; - mem_descr = phba->init_mem; - mem_descr += HWI_MEM_ASYNC_HEADER_RING; - dq_vaddress = mem_descr->mem_array[idx].virtual_address; - ret = be_fill_queue(dq, mem_descr->mem_array[0].size / - sizeof(struct phys_addr), - sizeof(struct phys_addr), dq_vaddress); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "be_fill_queue Failed for DEF PDU HDR\n"); - return ret; - } - mem->dma = (unsigned long)mem_descr->mem_array[idx]. - bus_address.u.a64.address; - ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dq, - def_pdu_ring_sz, - phba->params.defpdu_hdr_sz); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "be_cmd_create_default_pdu_queue Failed DEFHDR\n"); - return ret; - } - phwi_ctrlr->default_pdu_hdr.id = phwi_context->be_def_hdrq.id; - SE_DEBUG(DBG_LVL_8, "iscsi def pdu id is %d\n", - phwi_context->be_def_hdrq.id); - hwi_post_async_buffers(phba, 1); - return 0; -} - -static int -beiscsi_create_def_data(struct beiscsi_hba *phba, - struct hwi_context_memory *phwi_context, - struct hwi_controller *phwi_ctrlr, - unsigned int def_pdu_ring_sz) -{ - unsigned int idx; - int ret; - struct be_queue_info *dataq, *cq; - struct be_dma_mem *mem; - struct be_mem_descriptor *mem_descr; - void *dq_vaddress; - - idx = 0; - dataq = &phwi_context->be_def_dataq; - cq = &phwi_context->be_cq[0]; - mem = &dataq->dma_mem; - mem_descr = phba->init_mem; - mem_descr += HWI_MEM_ASYNC_DATA_RING; - dq_vaddress = mem_descr->mem_array[idx].virtual_address; - ret = be_fill_queue(dataq, mem_descr->mem_array[0].size / - sizeof(struct phys_addr), - sizeof(struct phys_addr), dq_vaddress); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "be_fill_queue Failed for DEF PDU DATA\n"); - return ret; - } - mem->dma = (unsigned long)mem_descr->mem_array[idx]. - bus_address.u.a64.address; - ret = be_cmd_create_default_pdu_queue(&phba->ctrl, cq, dataq, - def_pdu_ring_sz, - phba->params.defpdu_data_sz); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "be_cmd_create_default_pdu_queue Failed" - " for DEF PDU DATA\n"); - return ret; - } - phwi_ctrlr->default_pdu_data.id = phwi_context->be_def_dataq.id; - SE_DEBUG(DBG_LVL_8, "iscsi def data id is %d\n", - phwi_context->be_def_dataq.id); - hwi_post_async_buffers(phba, 0); - SE_DEBUG(DBG_LVL_8, "DEFAULT PDU DATA RING CREATED\n"); - return 0; -} - -static int -beiscsi_post_pages(struct beiscsi_hba *phba) -{ - struct be_mem_descriptor *mem_descr; - struct mem_array *pm_arr; - unsigned int page_offset, i; - struct be_dma_mem sgl; - int status; - - mem_descr = phba->init_mem; - mem_descr += HWI_MEM_SGE; - pm_arr = mem_descr->mem_array; - - page_offset = (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io * - phba->fw_config.iscsi_icd_start) / PAGE_SIZE; - for (i = 0; i < mem_descr->num_elements; i++) { - hwi_build_be_sgl_arr(phba, pm_arr, &sgl); - status = be_cmd_iscsi_post_sgl_pages(&phba->ctrl, &sgl, - page_offset, - (pm_arr->size / PAGE_SIZE)); - page_offset += pm_arr->size / PAGE_SIZE; - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "post sgl failed.\n"); - return status; - } - pm_arr++; - } - SE_DEBUG(DBG_LVL_8, "POSTED PAGES\n"); - return 0; -} - -static void be_queue_free(struct beiscsi_hba *phba, struct be_queue_info *q) -{ - struct be_dma_mem *mem = &q->dma_mem; - if (mem->va) - pci_free_consistent(phba->pcidev, mem->size, - mem->va, mem->dma); -} - -static int be_queue_alloc(struct beiscsi_hba *phba, struct be_queue_info *q, - u16 len, u16 entry_size) -{ - struct be_dma_mem *mem = &q->dma_mem; - - memset(q, 0, sizeof(*q)); - q->len = len; - q->entry_size = entry_size; - mem->size = len * entry_size; - mem->va = pci_alloc_consistent(phba->pcidev, mem->size, &mem->dma); - if (!mem->va) - return -ENOMEM; - memset(mem->va, 0, mem->size); - return 0; -} - -static int -beiscsi_create_wrb_rings(struct beiscsi_hba *phba, - struct hwi_context_memory *phwi_context, - struct hwi_controller *phwi_ctrlr) -{ - unsigned int wrb_mem_index, offset, size, num_wrb_rings; - u64 pa_addr_lo; - unsigned int idx, num, i; - struct mem_array *pwrb_arr; - void *wrb_vaddr; - struct be_dma_mem sgl; - struct be_mem_descriptor *mem_descr; - int status; - - idx = 0; - mem_descr = phba->init_mem; - mem_descr += HWI_MEM_WRB; - pwrb_arr = kmalloc(sizeof(*pwrb_arr) * phba->params.cxns_per_ctrl, - GFP_KERNEL); - if (!pwrb_arr) { - shost_printk(KERN_ERR, phba->shost, - "Memory alloc failed in create wrb ring.\n"); - return -ENOMEM; - } - wrb_vaddr = mem_descr->mem_array[idx].virtual_address; - pa_addr_lo = mem_descr->mem_array[idx].bus_address.u.a64.address; - num_wrb_rings = mem_descr->mem_array[idx].size / - (phba->params.wrbs_per_cxn * sizeof(struct iscsi_wrb)); - - for (num = 0; num < phba->params.cxns_per_ctrl; num++) { - if (num_wrb_rings) { - pwrb_arr[num].virtual_address = wrb_vaddr; - pwrb_arr[num].bus_address.u.a64.address = pa_addr_lo; - pwrb_arr[num].size = phba->params.wrbs_per_cxn * - sizeof(struct iscsi_wrb); - wrb_vaddr += pwrb_arr[num].size; - pa_addr_lo += pwrb_arr[num].size; - num_wrb_rings--; - } else { - idx++; - wrb_vaddr = mem_descr->mem_array[idx].virtual_address; - pa_addr_lo = mem_descr->mem_array[idx].\ - bus_address.u.a64.address; - num_wrb_rings = mem_descr->mem_array[idx].size / - (phba->params.wrbs_per_cxn * - sizeof(struct iscsi_wrb)); - pwrb_arr[num].virtual_address = wrb_vaddr; - pwrb_arr[num].bus_address.u.a64.address\ - = pa_addr_lo; - pwrb_arr[num].size = phba->params.wrbs_per_cxn * - sizeof(struct iscsi_wrb); - wrb_vaddr += pwrb_arr[num].size; - pa_addr_lo += pwrb_arr[num].size; - num_wrb_rings--; - } - } - for (i = 0; i < phba->params.cxns_per_ctrl; i++) { - wrb_mem_index = 0; - offset = 0; - size = 0; - - hwi_build_be_sgl_by_offset(phba, &pwrb_arr[i], &sgl); - status = be_cmd_wrbq_create(&phba->ctrl, &sgl, - &phwi_context->be_wrbq[i]); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "wrbq create failed."); - kfree(pwrb_arr); - return status; - } - phwi_ctrlr->wrb_context[i * 2].cid = phwi_context->be_wrbq[i]. - id; - } - kfree(pwrb_arr); - return 0; -} - -static void free_wrb_handles(struct beiscsi_hba *phba) -{ - unsigned int index; - struct hwi_controller *phwi_ctrlr; - struct hwi_wrb_context *pwrb_context; - - phwi_ctrlr = phba->phwi_ctrlr; - for (index = 0; index < phba->params.cxns_per_ctrl * 2; index += 2) { - pwrb_context = &phwi_ctrlr->wrb_context[index]; - kfree(pwrb_context->pwrb_handle_base); - kfree(pwrb_context->pwrb_handle_basestd); - } -} - -static void be_mcc_queues_destroy(struct beiscsi_hba *phba) -{ - struct be_queue_info *q; - struct be_ctrl_info *ctrl = &phba->ctrl; - - q = &phba->ctrl.mcc_obj.q; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_MCCQ); - be_queue_free(phba, q); - - q = &phba->ctrl.mcc_obj.cq; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ); - be_queue_free(phba, q); -} - -static void hwi_cleanup(struct beiscsi_hba *phba) -{ - struct be_queue_info *q; - struct be_ctrl_info *ctrl = &phba->ctrl; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - int i, eq_num; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - for (i = 0; i < phba->params.cxns_per_ctrl; i++) { - q = &phwi_context->be_wrbq[i]; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_WRBQ); - } - free_wrb_handles(phba); - - q = &phwi_context->be_def_hdrq; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); - - q = &phwi_context->be_def_dataq; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_DPDUQ); - - beiscsi_cmd_q_destroy(ctrl, NULL, QTYPE_SGL); - - for (i = 0; i < (phba->num_cpus); i++) { - q = &phwi_context->be_cq[i]; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_CQ); - } - if (phba->msix_enabled) - eq_num = 1; - else - eq_num = 0; - for (i = 0; i < (phba->num_cpus + eq_num); i++) { - q = &phwi_context->be_eq[i].q; - if (q->created) - beiscsi_cmd_q_destroy(ctrl, q, QTYPE_EQ); - } - be_mcc_queues_destroy(phba); -} - -static int be_mcc_queues_create(struct beiscsi_hba *phba, - struct hwi_context_memory *phwi_context) -{ - struct be_queue_info *q, *cq; - struct be_ctrl_info *ctrl = &phba->ctrl; - - /* Alloc MCC compl queue */ - cq = &phba->ctrl.mcc_obj.cq; - if (be_queue_alloc(phba, cq, MCC_CQ_LEN, - sizeof(struct be_mcc_compl))) - goto err; - /* Ask BE to create MCC compl queue; */ - if (phba->msix_enabled) { - if (beiscsi_cmd_cq_create(ctrl, cq, &phwi_context->be_eq - [phba->num_cpus].q, false, true, 0)) - goto mcc_cq_free; - } else { - if (beiscsi_cmd_cq_create(ctrl, cq, &phwi_context->be_eq[0].q, - false, true, 0)) - goto mcc_cq_free; - } - - /* Alloc MCC queue */ - q = &phba->ctrl.mcc_obj.q; - if (be_queue_alloc(phba, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb))) - goto mcc_cq_destroy; - - /* Ask BE to create MCC queue */ - if (beiscsi_cmd_mccq_create(phba, q, cq)) - goto mcc_q_free; - - return 0; - -mcc_q_free: - be_queue_free(phba, q); -mcc_cq_destroy: - beiscsi_cmd_q_destroy(ctrl, cq, QTYPE_CQ); -mcc_cq_free: - be_queue_free(phba, cq); -err: - return -ENOMEM; -} - -static int find_num_cpus(void) -{ - int num_cpus = 0; - - num_cpus = num_online_cpus(); - if (num_cpus >= MAX_CPUS) - num_cpus = MAX_CPUS - 1; - - SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", num_cpus); - return num_cpus; -} - -static int hwi_init_port(struct beiscsi_hba *phba) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - unsigned int def_pdu_ring_sz; - struct be_ctrl_info *ctrl = &phba->ctrl; - int status; - - def_pdu_ring_sz = - phba->params.asyncpdus_per_ctrl * sizeof(struct phys_addr); - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - phwi_context->max_eqd = 0; - phwi_context->min_eqd = 0; - phwi_context->cur_eqd = 64; - be_cmd_fw_initialize(&phba->ctrl); - - status = beiscsi_create_eqs(phba, phwi_context); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, "EQ not created\n"); - goto error; - } - - status = be_mcc_queues_create(phba, phwi_context); - if (status != 0) - goto error; - - status = mgmt_check_supported_fw(ctrl, phba); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "Unsupported fw version\n"); - goto error; - } - - status = beiscsi_create_cqs(phba, phwi_context); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, "CQ not created\n"); - goto error; - } - - status = beiscsi_create_def_hdr(phba, phwi_context, phwi_ctrlr, - def_pdu_ring_sz); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "Default Header not created\n"); - goto error; - } - - status = beiscsi_create_def_data(phba, phwi_context, - phwi_ctrlr, def_pdu_ring_sz); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "Default Data not created\n"); - goto error; - } - - status = beiscsi_post_pages(phba); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, "Post SGL Pages Failed\n"); - goto error; - } - - status = beiscsi_create_wrb_rings(phba, phwi_context, phwi_ctrlr); - if (status != 0) { - shost_printk(KERN_ERR, phba->shost, - "WRB Rings not created\n"); - goto error; - } - - SE_DEBUG(DBG_LVL_8, "hwi_init_port success\n"); - return 0; - -error: - shost_printk(KERN_ERR, phba->shost, "hwi_init_port failed"); - hwi_cleanup(phba); - return -ENOMEM; -} - -static int hwi_init_controller(struct beiscsi_hba *phba) -{ - struct hwi_controller *phwi_ctrlr; - - phwi_ctrlr = phba->phwi_ctrlr; - if (1 == phba->init_mem[HWI_MEM_ADDN_CONTEXT].num_elements) { - phwi_ctrlr->phwi_ctxt = (struct hwi_context_memory *)phba-> - init_mem[HWI_MEM_ADDN_CONTEXT].mem_array[0].virtual_address; - SE_DEBUG(DBG_LVL_8, " phwi_ctrlr->phwi_ctxt=%p\n", - phwi_ctrlr->phwi_ctxt); - } else { - shost_printk(KERN_ERR, phba->shost, - "HWI_MEM_ADDN_CONTEXT is more than one element." - "Failing to load\n"); - return -ENOMEM; - } - - iscsi_init_global_templates(phba); - beiscsi_init_wrb_handle(phba); - hwi_init_async_pdu_ctx(phba); - if (hwi_init_port(phba) != 0) { - shost_printk(KERN_ERR, phba->shost, - "hwi_init_controller failed\n"); - return -ENOMEM; - } - return 0; -} - -static void beiscsi_free_mem(struct beiscsi_hba *phba) -{ - struct be_mem_descriptor *mem_descr; - int i, j; - - mem_descr = phba->init_mem; - i = 0; - j = 0; - for (i = 0; i < SE_MEM_MAX; i++) { - for (j = mem_descr->num_elements; j > 0; j--) { - pci_free_consistent(phba->pcidev, - mem_descr->mem_array[j - 1].size, - mem_descr->mem_array[j - 1].virtual_address, - (unsigned long)mem_descr->mem_array[j - 1]. - bus_address.u.a64.address); - } - kfree(mem_descr->mem_array); - mem_descr++; - } - kfree(phba->init_mem); - kfree(phba->phwi_ctrlr); -} - -static int beiscsi_init_controller(struct beiscsi_hba *phba) -{ - int ret = -ENOMEM; - - ret = beiscsi_get_memory(phba); - if (ret < 0) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe -" - "Failed in beiscsi_alloc_memory\n"); - return ret; - } - - ret = hwi_init_controller(phba); - if (ret) - goto free_init; - SE_DEBUG(DBG_LVL_8, "Return success from beiscsi_init_controller"); - return 0; - -free_init: - beiscsi_free_mem(phba); - return -ENOMEM; -} - -static int beiscsi_init_sgl_handle(struct beiscsi_hba *phba) -{ - struct be_mem_descriptor *mem_descr_sglh, *mem_descr_sg; - struct sgl_handle *psgl_handle; - struct iscsi_sge *pfrag; - unsigned int arr_index, i, idx; - - phba->io_sgl_hndl_avbl = 0; - phba->eh_sgl_hndl_avbl = 0; - - mem_descr_sglh = phba->init_mem; - mem_descr_sglh += HWI_MEM_SGLH; - if (1 == mem_descr_sglh->num_elements) { - phba->io_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) * - phba->params.ios_per_ctrl, - GFP_KERNEL); - if (!phba->io_sgl_hndl_base) { - shost_printk(KERN_ERR, phba->shost, - "Mem Alloc Failed. Failing to load\n"); - return -ENOMEM; - } - phba->eh_sgl_hndl_base = kzalloc(sizeof(struct sgl_handle *) * - (phba->params.icds_per_ctrl - - phba->params.ios_per_ctrl), - GFP_KERNEL); - if (!phba->eh_sgl_hndl_base) { - kfree(phba->io_sgl_hndl_base); - shost_printk(KERN_ERR, phba->shost, - "Mem Alloc Failed. Failing to load\n"); - return -ENOMEM; - } - } else { - shost_printk(KERN_ERR, phba->shost, - "HWI_MEM_SGLH is more than one element." - "Failing to load\n"); - return -ENOMEM; - } - - arr_index = 0; - idx = 0; - while (idx < mem_descr_sglh->num_elements) { - psgl_handle = mem_descr_sglh->mem_array[idx].virtual_address; - - for (i = 0; i < (mem_descr_sglh->mem_array[idx].size / - sizeof(struct sgl_handle)); i++) { - if (arr_index < phba->params.ios_per_ctrl) { - phba->io_sgl_hndl_base[arr_index] = psgl_handle; - phba->io_sgl_hndl_avbl++; - arr_index++; - } else { - phba->eh_sgl_hndl_base[arr_index - - phba->params.ios_per_ctrl] = - psgl_handle; - arr_index++; - phba->eh_sgl_hndl_avbl++; - } - psgl_handle++; - } - idx++; - } - SE_DEBUG(DBG_LVL_8, - "phba->io_sgl_hndl_avbl=%d" - "phba->eh_sgl_hndl_avbl=%d\n", - phba->io_sgl_hndl_avbl, - phba->eh_sgl_hndl_avbl); - mem_descr_sg = phba->init_mem; - mem_descr_sg += HWI_MEM_SGE; - SE_DEBUG(DBG_LVL_8, "\n mem_descr_sg->num_elements=%d\n", - mem_descr_sg->num_elements); - arr_index = 0; - idx = 0; - while (idx < mem_descr_sg->num_elements) { - pfrag = mem_descr_sg->mem_array[idx].virtual_address; - - for (i = 0; - i < (mem_descr_sg->mem_array[idx].size) / - (sizeof(struct iscsi_sge) * phba->params.num_sge_per_io); - i++) { - if (arr_index < phba->params.ios_per_ctrl) - psgl_handle = phba->io_sgl_hndl_base[arr_index]; - else - psgl_handle = phba->eh_sgl_hndl_base[arr_index - - phba->params.ios_per_ctrl]; - psgl_handle->pfrag = pfrag; - AMAP_SET_BITS(struct amap_iscsi_sge, addr_hi, pfrag, 0); - AMAP_SET_BITS(struct amap_iscsi_sge, addr_lo, pfrag, 0); - pfrag += phba->params.num_sge_per_io; - psgl_handle->sgl_index = - phba->fw_config.iscsi_icd_start + arr_index++; - } - idx++; - } - phba->io_sgl_free_index = 0; - phba->io_sgl_alloc_index = 0; - phba->eh_sgl_free_index = 0; - phba->eh_sgl_alloc_index = 0; - return 0; -} - -static int hba_setup_cid_tbls(struct beiscsi_hba *phba) -{ - int i, new_cid; - - phba->cid_array = kzalloc(sizeof(void *) * phba->params.cxns_per_ctrl, - GFP_KERNEL); - if (!phba->cid_array) { - shost_printk(KERN_ERR, phba->shost, - "Failed to allocate memory in " - "hba_setup_cid_tbls\n"); - return -ENOMEM; - } - phba->ep_array = kzalloc(sizeof(struct iscsi_endpoint *) * - phba->params.cxns_per_ctrl * 2, GFP_KERNEL); - if (!phba->ep_array) { - shost_printk(KERN_ERR, phba->shost, - "Failed to allocate memory in " - "hba_setup_cid_tbls\n"); - kfree(phba->cid_array); - return -ENOMEM; - } - new_cid = phba->fw_config.iscsi_cid_start; - for (i = 0; i < phba->params.cxns_per_ctrl; i++) { - phba->cid_array[i] = new_cid; - new_cid += 2; - } - phba->avlbl_cids = phba->params.cxns_per_ctrl; - return 0; -} - -static void hwi_enable_intr(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct be_queue_info *eq; - u8 __iomem *addr; - u32 reg, i; - u32 enabled; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - - addr = (u8 __iomem *) ((u8 __iomem *) ctrl->pcicfg + - PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); - reg = ioread32(addr); - - enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - if (!enabled) { - reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - SE_DEBUG(DBG_LVL_8, "reg =x%08x addr=%p\n", reg, addr); - iowrite32(reg, addr); - } - - if (!phba->msix_enabled) { - eq = &phwi_context->be_eq[0].q; - SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); - hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); - } else { - for (i = 0; i <= phba->num_cpus; i++) { - eq = &phwi_context->be_eq[i].q; - SE_DEBUG(DBG_LVL_8, "eq->id=%d\n", eq->id); - hwi_ring_eq_db(phba, eq->id, 0, 0, 1, 1); - } - } -} - -static void hwi_disable_intr(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - - u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; - u32 reg = ioread32(addr); - - u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - if (enabled) { - reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - iowrite32(reg, addr); - } else - shost_printk(KERN_WARNING, phba->shost, - "In hwi_disable_intr, Already Disabled\n"); -} - -static int beiscsi_get_boot_info(struct beiscsi_hba *phba) -{ - struct be_cmd_resp_get_boot_target *boot_resp; - struct be_cmd_resp_get_session *session_resp; - struct be_mcc_wrb *wrb; - struct be_dma_mem nonemb_cmd; - unsigned int tag, wrb_num; - unsigned short status, extd_status; - struct be_queue_info *mccq = &phba->ctrl.mcc_obj.q; - int ret = -ENOMEM; - - tag = beiscsi_get_boot_target(phba); - if (!tag) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed\n"); - return -EAGAIN; - } else - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - - wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; - extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; - status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; - if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "be_cmd_get_mac_addr Failed" - " status = %d extd_status = %d\n", - status, extd_status); - free_mcc_tag(&phba->ctrl, tag); - return -EBUSY; - } - wrb = queue_get_wrb(mccq, wrb_num); - free_mcc_tag(&phba->ctrl, tag); - boot_resp = embedded_payload(wrb); - - if (boot_resp->boot_session_handle < 0) { - shost_printk(KERN_INFO, phba->shost, "No Boot Session.\n"); - return -ENXIO; - } - - nonemb_cmd.va = pci_alloc_consistent(phba->ctrl.pdev, - sizeof(*session_resp), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - SE_DEBUG(DBG_LVL_1, - "Failed to allocate memory for" - "beiscsi_get_session_info\n"); - return -ENOMEM; - } - - memset(nonemb_cmd.va, 0, sizeof(*session_resp)); - tag = beiscsi_get_session_info(phba, - boot_resp->boot_session_handle, &nonemb_cmd); - if (!tag) { - SE_DEBUG(DBG_LVL_1, "beiscsi_get_session_info" - " Failed\n"); - goto boot_freemem; - } else - wait_event_interruptible(phba->ctrl.mcc_wait[tag], - phba->ctrl.mcc_numtag[tag]); - - wrb_num = (phba->ctrl.mcc_numtag[tag] & 0x00FF0000) >> 16; - extd_status = (phba->ctrl.mcc_numtag[tag] & 0x0000FF00) >> 8; - status = phba->ctrl.mcc_numtag[tag] & 0x000000FF; - if (status || extd_status) { - SE_DEBUG(DBG_LVL_1, "beiscsi_get_session_info Failed" - " status = %d extd_status = %d\n", - status, extd_status); - free_mcc_tag(&phba->ctrl, tag); - goto boot_freemem; - } - wrb = queue_get_wrb(mccq, wrb_num); - free_mcc_tag(&phba->ctrl, tag); - session_resp = nonemb_cmd.va ; - - memcpy(&phba->boot_sess, &session_resp->session_info, - sizeof(struct mgmt_session_info)); - ret = 0; - -boot_freemem: - pci_free_consistent(phba->ctrl.pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - return ret; -} - -static void beiscsi_boot_release(void *data) -{ - struct beiscsi_hba *phba = data; - - scsi_host_put(phba->shost); -} - -static int beiscsi_setup_boot_info(struct beiscsi_hba *phba) -{ - struct iscsi_boot_kobj *boot_kobj; - - /* get boot info using mgmt cmd */ - if (beiscsi_get_boot_info(phba)) - /* Try to see if we can carry on without this */ - return 0; - - phba->boot_kset = iscsi_boot_create_host_kset(phba->shost->host_no); - if (!phba->boot_kset) - return -ENOMEM; - - /* get a ref because the show function will ref the phba */ - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_target(phba->boot_kset, 0, phba, - beiscsi_show_boot_tgt_info, - beiscsi_tgt_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_initiator(phba->boot_kset, 0, phba, - beiscsi_show_boot_ini_info, - beiscsi_ini_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - - if (!scsi_host_get(phba->shost)) - goto free_kset; - boot_kobj = iscsi_boot_create_ethernet(phba->boot_kset, 0, phba, - beiscsi_show_boot_eth_info, - beiscsi_eth_get_attr_visibility, - beiscsi_boot_release); - if (!boot_kobj) - goto put_shost; - return 0; - -put_shost: - scsi_host_put(phba->shost); -free_kset: - iscsi_boot_destroy_kset(phba->boot_kset); - return -ENOMEM; -} - -static int beiscsi_init_port(struct beiscsi_hba *phba) -{ - int ret; - - ret = beiscsi_init_controller(phba); - if (ret < 0) { - shost_printk(KERN_ERR, phba->shost, - "beiscsi_dev_probe - Failed in" - "beiscsi_init_controller\n"); - return ret; - } - ret = beiscsi_init_sgl_handle(phba); - if (ret < 0) { - shost_printk(KERN_ERR, phba->shost, - "beiscsi_dev_probe - Failed in" - "beiscsi_init_sgl_handle\n"); - goto do_cleanup_ctrlr; - } - - if (hba_setup_cid_tbls(phba)) { - shost_printk(KERN_ERR, phba->shost, - "Failed in hba_setup_cid_tbls\n"); - kfree(phba->io_sgl_hndl_base); - kfree(phba->eh_sgl_hndl_base); - goto do_cleanup_ctrlr; - } - - return ret; - -do_cleanup_ctrlr: - hwi_cleanup(phba); - return ret; -} - -static void hwi_purge_eq(struct beiscsi_hba *phba) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct be_queue_info *eq; - struct be_eq_entry *eqe = NULL; - int i, eq_msix; - unsigned int num_processed; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - if (phba->msix_enabled) - eq_msix = 1; - else - eq_msix = 0; - - for (i = 0; i < (phba->num_cpus + eq_msix); i++) { - eq = &phwi_context->be_eq[i].q; - eqe = queue_tail_node(eq); - num_processed = 0; - while (eqe->dw[offsetof(struct amap_eq_entry, valid) / 32] - & EQE_VALID_MASK) { - AMAP_SET_BITS(struct amap_eq_entry, valid, eqe, 0); - queue_tail_inc(eq); - eqe = queue_tail_node(eq); - num_processed++; - } - - if (num_processed) - hwi_ring_eq_db(phba, eq->id, 1, num_processed, 1, 1); - } -} - -static void beiscsi_clean_port(struct beiscsi_hba *phba) -{ - int mgmt_status; - - mgmt_status = mgmt_epfw_cleanup(phba, CMD_CONNECTION_CHUTE_0); - if (mgmt_status) - shost_printk(KERN_WARNING, phba->shost, - "mgmt_epfw_cleanup FAILED\n"); - - hwi_purge_eq(phba); - hwi_cleanup(phba); - kfree(phba->io_sgl_hndl_base); - kfree(phba->eh_sgl_hndl_base); - kfree(phba->cid_array); - kfree(phba->ep_array); -} - -void -beiscsi_offload_connection(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_offload_params *params) -{ - struct wrb_handle *pwrb_handle; - struct iscsi_target_context_update_wrb *pwrb = NULL; - struct be_mem_descriptor *mem_descr; - struct beiscsi_hba *phba = beiscsi_conn->phba; - u32 doorbell = 0; - - /* - * We can always use 0 here because it is reserved by libiscsi for - * login/startup related tasks. - */ - pwrb_handle = alloc_wrb_handle(phba, (beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start)); - pwrb = (struct iscsi_target_context_update_wrb *)pwrb_handle->pwrb; - memset(pwrb, 0, sizeof(*pwrb)); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, - max_burst_length, pwrb, params->dw[offsetof - (struct amap_beiscsi_offload_params, - max_burst_length) / 32]); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, - max_send_data_segment_length, pwrb, - params->dw[offsetof(struct amap_beiscsi_offload_params, - max_send_data_segment_length) / 32]); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, - first_burst_length, - pwrb, - params->dw[offsetof(struct amap_beiscsi_offload_params, - first_burst_length) / 32]); - - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, erl, pwrb, - (params->dw[offsetof(struct amap_beiscsi_offload_params, - erl) / 32] & OFFLD_PARAMS_ERL)); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, dde, pwrb, - (params->dw[offsetof(struct amap_beiscsi_offload_params, - dde) / 32] & OFFLD_PARAMS_DDE) >> 2); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, hde, pwrb, - (params->dw[offsetof(struct amap_beiscsi_offload_params, - hde) / 32] & OFFLD_PARAMS_HDE) >> 3); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ir2t, pwrb, - (params->dw[offsetof(struct amap_beiscsi_offload_params, - ir2t) / 32] & OFFLD_PARAMS_IR2T) >> 4); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, imd, pwrb, - (params->dw[offsetof(struct amap_beiscsi_offload_params, - imd) / 32] & OFFLD_PARAMS_IMD) >> 5); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, stat_sn, - pwrb, - (params->dw[offsetof(struct amap_beiscsi_offload_params, - exp_statsn) / 32] + 1)); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, type, pwrb, - 0x7); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, wrb_idx, - pwrb, pwrb_handle->wrb_index); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, ptr2nextwrb, - pwrb, pwrb_handle->nxt_wrb_index); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, - session_state, pwrb, 0); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, compltonack, - pwrb, 1); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, notpredblq, - pwrb, 0); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, mode, pwrb, - 0); - - mem_descr = phba->init_mem; - mem_descr += ISCSI_MEM_GLOBAL_HEADER; - - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, - pad_buffer_addr_hi, pwrb, - mem_descr->mem_array[0].bus_address.u.a32.address_hi); - AMAP_SET_BITS(struct amap_iscsi_target_context_update_wrb, - pad_buffer_addr_lo, pwrb, - mem_descr->mem_array[0].bus_address.u.a32.address_lo); - - be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_target_context_update_wrb)); - - doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; - doorbell |= (pwrb_handle->wrb_index & DB_DEF_PDU_WRB_INDEX_MASK) - << DB_DEF_PDU_WRB_INDEX_SHIFT; - doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; - - iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); -} - -static void beiscsi_parse_pdu(struct iscsi_conn *conn, itt_t itt, - int *index, int *age) -{ - *index = (int)itt; - if (age) - *age = conn->session->age; -} - -/** - * beiscsi_alloc_pdu - allocates pdu and related resources - * @task: libiscsi task - * @opcode: opcode of pdu for task - * - * This is called with the session lock held. It will allocate - * the wrb and sgl if needed for the command. And it will prep - * the pdu's itt. beiscsi_parse_pdu will later translate - * the pdu itt to the libiscsi task itt. - */ -static int beiscsi_alloc_pdu(struct iscsi_task *task, uint8_t opcode) -{ - struct beiscsi_io_task *io_task = task->dd_data; - struct iscsi_conn *conn = task->conn; - struct beiscsi_conn *beiscsi_conn = conn->dd_data; - struct beiscsi_hba *phba = beiscsi_conn->phba; - struct hwi_wrb_context *pwrb_context; - struct hwi_controller *phwi_ctrlr; - itt_t itt; - struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; - dma_addr_t paddr; - - io_task->cmd_bhs = pci_pool_alloc(beiscsi_sess->bhs_pool, - GFP_ATOMIC, &paddr); - if (!io_task->cmd_bhs) - return -ENOMEM; - io_task->bhs_pa.u.a64.address = paddr; - io_task->libiscsi_itt = (itt_t)task->itt; - io_task->conn = beiscsi_conn; - - task->hdr = (struct iscsi_hdr *)&io_task->cmd_bhs->iscsi_hdr; - task->hdr_max = sizeof(struct be_cmd_bhs); - io_task->psgl_handle = NULL; - io_task->psgl_handle = NULL; - - if (task->sc) { - spin_lock(&phba->io_sgl_lock); - io_task->psgl_handle = alloc_io_sgl_handle(phba); - spin_unlock(&phba->io_sgl_lock); - if (!io_task->psgl_handle) - goto free_hndls; - io_task->pwrb_handle = alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start); - if (!io_task->pwrb_handle) - goto free_io_hndls; - } else { - io_task->scsi_cmnd = NULL; - if ((opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN) { - if (!beiscsi_conn->login_in_progress) { - spin_lock(&phba->mgmt_sgl_lock); - io_task->psgl_handle = (struct sgl_handle *) - alloc_mgmt_sgl_handle(phba); - spin_unlock(&phba->mgmt_sgl_lock); - if (!io_task->psgl_handle) - goto free_hndls; - - beiscsi_conn->login_in_progress = 1; - beiscsi_conn->plogin_sgl_handle = - io_task->psgl_handle; - io_task->pwrb_handle = - alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start); - if (!io_task->pwrb_handle) - goto free_io_hndls; - beiscsi_conn->plogin_wrb_handle = - io_task->pwrb_handle; - - } else { - io_task->psgl_handle = - beiscsi_conn->plogin_sgl_handle; - io_task->pwrb_handle = - beiscsi_conn->plogin_wrb_handle; - } - } else { - spin_lock(&phba->mgmt_sgl_lock); - io_task->psgl_handle = alloc_mgmt_sgl_handle(phba); - spin_unlock(&phba->mgmt_sgl_lock); - if (!io_task->psgl_handle) - goto free_hndls; - io_task->pwrb_handle = - alloc_wrb_handle(phba, - beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start); - if (!io_task->pwrb_handle) - goto free_mgmt_hndls; - - } - } - itt = (itt_t) cpu_to_be32(((unsigned int)io_task->pwrb_handle-> - wrb_index << 16) | (unsigned int) - (io_task->psgl_handle->sgl_index)); - io_task->pwrb_handle->pio_handle = task; - - io_task->cmd_bhs->iscsi_hdr.itt = itt; - return 0; - -free_io_hndls: - spin_lock(&phba->io_sgl_lock); - free_io_sgl_handle(phba, io_task->psgl_handle); - spin_unlock(&phba->io_sgl_lock); - goto free_hndls; -free_mgmt_hndls: - spin_lock(&phba->mgmt_sgl_lock); - free_mgmt_sgl_handle(phba, io_task->psgl_handle); - spin_unlock(&phba->mgmt_sgl_lock); -free_hndls: - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[ - beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start]; - if (io_task->pwrb_handle) - free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); - io_task->pwrb_handle = NULL; - pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, - io_task->bhs_pa.u.a64.address); - SE_DEBUG(DBG_LVL_1, "Alloc of SGL_ICD Failed\n"); - return -ENOMEM; -} - -static void beiscsi_cleanup_task(struct iscsi_task *task) -{ - struct beiscsi_io_task *io_task = task->dd_data; - struct iscsi_conn *conn = task->conn; - struct beiscsi_conn *beiscsi_conn = conn->dd_data; - struct beiscsi_hba *phba = beiscsi_conn->phba; - struct beiscsi_session *beiscsi_sess = beiscsi_conn->beiscsi_sess; - struct hwi_wrb_context *pwrb_context; - struct hwi_controller *phwi_ctrlr; - - phwi_ctrlr = phba->phwi_ctrlr; - pwrb_context = &phwi_ctrlr->wrb_context[beiscsi_conn->beiscsi_conn_cid - - phba->fw_config.iscsi_cid_start]; - if (io_task->pwrb_handle) { - free_wrb_handle(phba, pwrb_context, io_task->pwrb_handle); - io_task->pwrb_handle = NULL; - } - - if (io_task->cmd_bhs) { - pci_pool_free(beiscsi_sess->bhs_pool, io_task->cmd_bhs, - io_task->bhs_pa.u.a64.address); - } - - if (task->sc) { - if (io_task->psgl_handle) { - spin_lock(&phba->io_sgl_lock); - free_io_sgl_handle(phba, io_task->psgl_handle); - spin_unlock(&phba->io_sgl_lock); - io_task->psgl_handle = NULL; - } - } else { - if (task->hdr && - ((task->hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGIN)) - return; - if (io_task->psgl_handle) { - spin_lock(&phba->mgmt_sgl_lock); - free_mgmt_sgl_handle(phba, io_task->psgl_handle); - spin_unlock(&phba->mgmt_sgl_lock); - io_task->psgl_handle = NULL; - } - } -} - -static int beiscsi_iotask(struct iscsi_task *task, struct scatterlist *sg, - unsigned int num_sg, unsigned int xferlen, - unsigned int writedir) -{ - - struct beiscsi_io_task *io_task = task->dd_data; - struct iscsi_conn *conn = task->conn; - struct beiscsi_conn *beiscsi_conn = conn->dd_data; - struct beiscsi_hba *phba = beiscsi_conn->phba; - struct iscsi_wrb *pwrb = NULL; - unsigned int doorbell = 0; - - pwrb = io_task->pwrb_handle->pwrb; - io_task->cmd_bhs->iscsi_hdr.exp_statsn = 0; - io_task->bhs_len = sizeof(struct be_cmd_bhs); - - if (writedir) { - memset(&io_task->cmd_bhs->iscsi_data_pdu, 0, 48); - AMAP_SET_BITS(struct amap_pdu_data_out, itt, - &io_task->cmd_bhs->iscsi_data_pdu, - (unsigned int)io_task->cmd_bhs->iscsi_hdr.itt); - AMAP_SET_BITS(struct amap_pdu_data_out, opcode, - &io_task->cmd_bhs->iscsi_data_pdu, - ISCSI_OPCODE_SCSI_DATA_OUT); - AMAP_SET_BITS(struct amap_pdu_data_out, final_bit, - &io_task->cmd_bhs->iscsi_data_pdu, 1); - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_WR_CMD); - AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 1); - } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); - AMAP_SET_BITS(struct amap_iscsi_wrb, dsp, pwrb, 0); - } - memcpy(&io_task->cmd_bhs->iscsi_data_pdu. - dw[offsetof(struct amap_pdu_data_out, lun) / 32], - &io_task->cmd_bhs->iscsi_hdr.lun, sizeof(struct scsi_lun)); - - AMAP_SET_BITS(struct amap_iscsi_wrb, lun, pwrb, - cpu_to_be16(*(unsigned short *)&io_task->cmd_bhs->iscsi_hdr.lun)); - AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, xferlen); - AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, - io_task->pwrb_handle->wrb_index); - AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, - be32_to_cpu(task->cmdsn)); - AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb, - io_task->psgl_handle->sgl_index); - - hwi_write_sgl(pwrb, sg, num_sg, io_task); - - AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); - be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); - - doorbell |= beiscsi_conn->beiscsi_conn_cid & DB_WRB_POST_CID_MASK; - doorbell |= (io_task->pwrb_handle->wrb_index & - DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; - doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; - - iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); - return 0; -} - -static int beiscsi_mtask(struct iscsi_task *task) -{ - struct beiscsi_io_task *io_task = task->dd_data; - struct iscsi_conn *conn = task->conn; - struct beiscsi_conn *beiscsi_conn = conn->dd_data; - struct beiscsi_hba *phba = beiscsi_conn->phba; - struct iscsi_wrb *pwrb = NULL; - unsigned int doorbell = 0; - unsigned int cid; - - cid = beiscsi_conn->beiscsi_conn_cid; - pwrb = io_task->pwrb_handle->pwrb; - memset(pwrb, 0, sizeof(*pwrb)); - AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, - be32_to_cpu(task->cmdsn)); - AMAP_SET_BITS(struct amap_iscsi_wrb, wrb_idx, pwrb, - io_task->pwrb_handle->wrb_index); - AMAP_SET_BITS(struct amap_iscsi_wrb, sgl_icd_idx, pwrb, - io_task->psgl_handle->sgl_index); - - switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { - case ISCSI_OP_LOGIN: - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - TGT_DM_CMD); - AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, pwrb, 1); - hwi_write_buffer(pwrb, task); - break; - case ISCSI_OP_NOOP_OUT: - if (task->hdr->ttt != ISCSI_RESERVED_TAG) { - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - TGT_DM_CMD); - AMAP_SET_BITS(struct amap_iscsi_wrb, cmdsn_itt, - pwrb, 0); - AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 1); - } else { - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_RD_CMD); - AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - } - hwi_write_buffer(pwrb, task); - break; - case ISCSI_OP_TEXT: - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - TGT_DM_CMD); - AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - hwi_write_buffer(pwrb, task); - break; - case ISCSI_OP_SCSI_TMFUNC: - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - INI_TMF_CMD); - AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - hwi_write_buffer(pwrb, task); - break; - case ISCSI_OP_LOGOUT: - AMAP_SET_BITS(struct amap_iscsi_wrb, dmsg, pwrb, 0); - AMAP_SET_BITS(struct amap_iscsi_wrb, type, pwrb, - HWH_TYPE_LOGOUT); - hwi_write_buffer(pwrb, task); - break; - - default: - SE_DEBUG(DBG_LVL_1, "opcode =%d Not supported\n", - task->hdr->opcode & ISCSI_OPCODE_MASK); - return -EINVAL; - } - - AMAP_SET_BITS(struct amap_iscsi_wrb, r2t_exp_dtl, pwrb, - task->data_count); - AMAP_SET_BITS(struct amap_iscsi_wrb, ptr2nextwrb, pwrb, - io_task->pwrb_handle->nxt_wrb_index); - be_dws_le_to_cpu(pwrb, sizeof(struct iscsi_wrb)); - - doorbell |= cid & DB_WRB_POST_CID_MASK; - doorbell |= (io_task->pwrb_handle->wrb_index & - DB_DEF_PDU_WRB_INDEX_MASK) << DB_DEF_PDU_WRB_INDEX_SHIFT; - doorbell |= 1 << DB_DEF_PDU_NUM_POSTED_SHIFT; - iowrite32(doorbell, phba->db_va + DB_TXULP0_OFFSET); - return 0; -} - -static int beiscsi_task_xmit(struct iscsi_task *task) -{ - struct beiscsi_io_task *io_task = task->dd_data; - struct scsi_cmnd *sc = task->sc; - struct scatterlist *sg; - int num_sg; - unsigned int writedir = 0, xferlen = 0; - - if (!sc) - return beiscsi_mtask(task); - - io_task->scsi_cmnd = sc; - num_sg = scsi_dma_map(sc); - if (num_sg < 0) { - SE_DEBUG(DBG_LVL_1, " scsi_dma_map Failed\n") - return num_sg; - } - xferlen = scsi_bufflen(sc); - sg = scsi_sglist(sc); - if (sc->sc_data_direction == DMA_TO_DEVICE) { - writedir = 1; - SE_DEBUG(DBG_LVL_4, "task->imm_count=0x%08x\n", - task->imm_count); - } else - writedir = 0; - return beiscsi_iotask(task, sg, num_sg, xferlen, writedir); -} - -static void beiscsi_quiesce(struct beiscsi_hba *phba) -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct be_eq_obj *pbe_eq; - unsigned int i, msix_vec; - u8 *real_offset = 0; - u32 value = 0; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - hwi_disable_intr(phba); - if (phba->msix_enabled) { - for (i = 0; i <= phba->num_cpus; i++) { - msix_vec = phba->msix_entries[i].vector; - free_irq(msix_vec, &phwi_context->be_eq[i]); - kfree(phba->msi_name[i]); - } - } else - if (phba->pcidev->irq) - free_irq(phba->pcidev->irq, phba); - pci_disable_msix(phba->pcidev); - destroy_workqueue(phba->wq); - if (blk_iopoll_enabled) - for (i = 0; i < phba->num_cpus; i++) { - pbe_eq = &phwi_context->be_eq[i]; - blk_iopoll_disable(&pbe_eq->iopoll); - } - - beiscsi_clean_port(phba); - beiscsi_free_mem(phba); - real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; - - value = readl((void *)real_offset); - - if (value & 0x00010000) { - value &= 0xfffeffff; - writel(value, (void *)real_offset); - } - beiscsi_unmap_pci_function(phba); - pci_free_consistent(phba->pcidev, - phba->ctrl.mbox_mem_alloced.size, - phba->ctrl.mbox_mem_alloced.va, - phba->ctrl.mbox_mem_alloced.dma); -} - -static void beiscsi_remove(struct pci_dev *pcidev) -{ - - struct beiscsi_hba *phba = NULL; - - phba = pci_get_drvdata(pcidev); - if (!phba) { - dev_err(&pcidev->dev, "beiscsi_remove called with no phba\n"); - return; - } - - beiscsi_quiesce(phba); - iscsi_boot_destroy_kset(phba->boot_kset); - iscsi_host_remove(phba->shost); - pci_dev_put(phba->pcidev); - iscsi_host_free(phba->shost); - pci_disable_device(pcidev); -} - -static void beiscsi_shutdown(struct pci_dev *pcidev) -{ - - struct beiscsi_hba *phba = NULL; - - phba = (struct beiscsi_hba *)pci_get_drvdata(pcidev); - if (!phba) { - dev_err(&pcidev->dev, "beiscsi_shutdown called with no phba\n"); - return; - } - - beiscsi_quiesce(phba); - pci_disable_device(pcidev); -} - -static void beiscsi_msix_enable(struct beiscsi_hba *phba) -{ - int i, status; - - for (i = 0; i <= phba->num_cpus; i++) - phba->msix_entries[i].entry = i; - - status = pci_enable_msix(phba->pcidev, phba->msix_entries, - (phba->num_cpus + 1)); - if (!status) - phba->msix_enabled = true; - - return; -} - -static int __devinit beiscsi_dev_probe(struct pci_dev *pcidev, - const struct pci_device_id *id) -{ - struct beiscsi_hba *phba = NULL; - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct be_eq_obj *pbe_eq; - int ret, num_cpus, i; - u8 *real_offset = 0; - u32 value = 0; - - ret = beiscsi_enable_pci(pcidev); - if (ret < 0) { - dev_err(&pcidev->dev, "beiscsi_dev_probe-" - " Failed to enable pci device\n"); - return ret; - } - - phba = beiscsi_hba_alloc(pcidev); - if (!phba) { - dev_err(&pcidev->dev, "beiscsi_dev_probe-" - " Failed in beiscsi_hba_alloc\n"); - goto disable_pci; - } - - switch (pcidev->device) { - case BE_DEVICE_ID1: - case OC_DEVICE_ID1: - case OC_DEVICE_ID2: - phba->generation = BE_GEN2; - break; - case BE_DEVICE_ID2: - case OC_DEVICE_ID3: - phba->generation = BE_GEN3; - break; - default: - phba->generation = 0; - } - - if (enable_msix) - num_cpus = find_num_cpus(); - else - num_cpus = 1; - phba->num_cpus = num_cpus; - SE_DEBUG(DBG_LVL_8, "num_cpus = %d\n", phba->num_cpus); - - if (enable_msix) - beiscsi_msix_enable(phba); - ret = be_ctrl_init(phba, pcidev); - if (ret) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" - "Failed in be_ctrl_init\n"); - goto hba_free; - } - - if (!num_hba) { - real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; - value = readl((void *)real_offset); - if (value & 0x00010000) { - gcrashmode++; - shost_printk(KERN_ERR, phba->shost, - "Loading Driver in crashdump mode\n"); - ret = beiscsi_cmd_reset_function(phba); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "Reset Failed. Aborting Crashdump\n"); - goto hba_free; - } - ret = be_chk_reset_complete(phba); - if (ret) { - shost_printk(KERN_ERR, phba->shost, - "Failed to get out of reset." - "Aborting Crashdump\n"); - goto hba_free; - } - } else { - value |= 0x00010000; - writel(value, (void *)real_offset); - num_hba++; - } - } - - spin_lock_init(&phba->io_sgl_lock); - spin_lock_init(&phba->mgmt_sgl_lock); - spin_lock_init(&phba->isr_lock); - ret = mgmt_get_fw_config(&phba->ctrl, phba); - if (ret != 0) { - shost_printk(KERN_ERR, phba->shost, - "Error getting fw config\n"); - goto free_port; - } - phba->shost->max_id = phba->fw_config.iscsi_cid_count; - beiscsi_get_params(phba); - phba->shost->can_queue = phba->params.ios_per_ctrl; - ret = beiscsi_init_port(phba); - if (ret < 0) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" - "Failed in beiscsi_init_port\n"); - goto free_port; - } - - for (i = 0; i < MAX_MCC_CMD ; i++) { - init_waitqueue_head(&phba->ctrl.mcc_wait[i + 1]); - phba->ctrl.mcc_tag[i] = i + 1; - phba->ctrl.mcc_numtag[i + 1] = 0; - phba->ctrl.mcc_tag_available++; - } - - phba->ctrl.mcc_alloc_index = phba->ctrl.mcc_free_index = 0; - - snprintf(phba->wq_name, sizeof(phba->wq_name), "beiscsi_q_irq%u", - phba->shost->host_no); - phba->wq = alloc_workqueue(phba->wq_name, WQ_MEM_RECLAIM, 1); - if (!phba->wq) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" - "Failed to allocate work queue\n"); - goto free_twq; - } - - INIT_WORK(&phba->work_cqs, beiscsi_process_all_cqs); - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - if (blk_iopoll_enabled) { - for (i = 0; i < phba->num_cpus; i++) { - pbe_eq = &phwi_context->be_eq[i]; - blk_iopoll_init(&pbe_eq->iopoll, be_iopoll_budget, - be_iopoll); - blk_iopoll_enable(&pbe_eq->iopoll); - } - } - ret = beiscsi_init_irqs(phba); - if (ret < 0) { - shost_printk(KERN_ERR, phba->shost, "beiscsi_dev_probe-" - "Failed to beiscsi_init_irqs\n"); - goto free_blkenbld; - } - hwi_enable_intr(phba); - - if (beiscsi_setup_boot_info(phba)) - /* - * log error but continue, because we may not be using - * iscsi boot. - */ - shost_printk(KERN_ERR, phba->shost, "Could not set up " - "iSCSI boot info."); - - SE_DEBUG(DBG_LVL_8, "\n\n\n SUCCESS - DRIVER LOADED\n\n\n"); - return 0; - -free_blkenbld: - destroy_workqueue(phba->wq); - if (blk_iopoll_enabled) - for (i = 0; i < phba->num_cpus; i++) { - pbe_eq = &phwi_context->be_eq[i]; - blk_iopoll_disable(&pbe_eq->iopoll); - } -free_twq: - beiscsi_clean_port(phba); - beiscsi_free_mem(phba); -free_port: - real_offset = (u8 *)phba->csr_va + MPU_EP_SEMAPHORE; - - value = readl((void *)real_offset); - - if (value & 0x00010000) { - value &= 0xfffeffff; - writel(value, (void *)real_offset); - } - - pci_free_consistent(phba->pcidev, - phba->ctrl.mbox_mem_alloced.size, - phba->ctrl.mbox_mem_alloced.va, - phba->ctrl.mbox_mem_alloced.dma); - beiscsi_unmap_pci_function(phba); -hba_free: - if (phba->msix_enabled) - pci_disable_msix(phba->pcidev); - iscsi_host_remove(phba->shost); - pci_dev_put(phba->pcidev); - iscsi_host_free(phba->shost); -disable_pci: - pci_disable_device(pcidev); - return ret; -} - -struct iscsi_transport beiscsi_iscsi_transport = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_TEXT_NEGO | - CAP_MULTI_R2T | CAP_DATADGST | CAP_DATA_PATH_OFFLOAD, - .create_session = beiscsi_session_create, - .destroy_session = beiscsi_session_destroy, - .create_conn = beiscsi_conn_create, - .bind_conn = beiscsi_conn_bind, - .destroy_conn = iscsi_conn_teardown, - .attr_is_visible = be2iscsi_attr_is_visible, - .set_param = beiscsi_set_param, - .get_conn_param = iscsi_conn_get_param, - .get_session_param = iscsi_session_get_param, - .get_host_param = beiscsi_get_host_param, - .start_conn = beiscsi_conn_start, - .stop_conn = iscsi_conn_stop, - .send_pdu = iscsi_conn_send_pdu, - .xmit_task = beiscsi_task_xmit, - .cleanup_task = beiscsi_cleanup_task, - .alloc_pdu = beiscsi_alloc_pdu, - .parse_pdu_itt = beiscsi_parse_pdu, - .get_stats = beiscsi_conn_get_stats, - .get_ep_param = beiscsi_ep_get_param, - .ep_connect = beiscsi_ep_connect, - .ep_poll = beiscsi_ep_poll, - .ep_disconnect = beiscsi_ep_disconnect, - .session_recovery_timedout = iscsi_session_recovery_timedout, -}; - -static struct pci_driver beiscsi_pci_driver = { - .name = DRV_NAME, - .probe = beiscsi_dev_probe, - .remove = beiscsi_remove, - .shutdown = beiscsi_shutdown, - .id_table = beiscsi_pci_id_table -}; - - -static int __init beiscsi_module_init(void) -{ - int ret; - - beiscsi_scsi_transport = - iscsi_register_transport(&beiscsi_iscsi_transport); - if (!beiscsi_scsi_transport) { - SE_DEBUG(DBG_LVL_1, - "beiscsi_module_init - Unable to register beiscsi" - "transport.\n"); - return -ENOMEM; - } - SE_DEBUG(DBG_LVL_8, "In beiscsi_module_init, tt=%p\n", - &beiscsi_iscsi_transport); - - ret = pci_register_driver(&beiscsi_pci_driver); - if (ret) { - SE_DEBUG(DBG_LVL_1, - "beiscsi_module_init - Unable to register" - "beiscsi pci driver.\n"); - goto unregister_iscsi_transport; - } - return 0; - -unregister_iscsi_transport: - iscsi_unregister_transport(&beiscsi_iscsi_transport); - return ret; -} - -static void __exit beiscsi_module_exit(void) -{ - pci_unregister_driver(&beiscsi_pci_driver); - iscsi_unregister_transport(&beiscsi_iscsi_transport); -} - -module_init(beiscsi_module_init); -module_exit(beiscsi_module_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.h b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.h deleted file mode 100644 index b4a06d5e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_main.h +++ /dev/null @@ -1,862 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#ifndef _BEISCSI_MAIN_ -#define _BEISCSI_MAIN_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "be.h" -#define DRV_NAME "be2iscsi" -#define BUILD_STR "4.1.239.0" -#define BE_NAME "ServerEngines BladeEngine2" \ - "Linux iSCSI Driver version" BUILD_STR -#define DRV_DESC BE_NAME " " "Driver" - -#define BE_VENDOR_ID 0x19A2 -/* DEVICE ID's for BE2 */ -#define BE_DEVICE_ID1 0x212 -#define OC_DEVICE_ID1 0x702 -#define OC_DEVICE_ID2 0x703 - -/* DEVICE ID's for BE3 */ -#define BE_DEVICE_ID2 0x222 -#define OC_DEVICE_ID3 0x712 - -#define BE2_IO_DEPTH 1024 -#define BE2_MAX_SESSIONS 256 -#define BE2_CMDS_PER_CXN 128 -#define BE2_TMFS 16 -#define BE2_NOPOUT_REQ 16 -#define BE2_SGE 32 -#define BE2_DEFPDU_HDR_SZ 64 -#define BE2_DEFPDU_DATA_SZ 8192 - -#define MAX_CPUS 31 -#define BEISCSI_SGLIST_ELEMENTS 30 - -#define BEISCSI_CMD_PER_LUN 128 /* scsi_host->cmd_per_lun */ -#define BEISCSI_MAX_SECTORS 2048 /* scsi_host->max_sectors */ - -#define BEISCSI_MAX_CMD_LEN 16 /* scsi_host->max_cmd_len */ -#define BEISCSI_NUM_MAX_LUN 256 /* scsi_host->max_lun */ -#define BEISCSI_NUM_DEVICES_SUPPORTED 0x01 -#define BEISCSI_MAX_FRAGS_INIT 192 -#define BE_NUM_MSIX_ENTRIES 1 - -#define MPU_EP_CONTROL 0 -#define MPU_EP_SEMAPHORE 0xac -#define BE2_SOFT_RESET 0x5c -#define BE2_PCI_ONLINE0 0xb0 -#define BE2_PCI_ONLINE1 0xb4 -#define BE2_SET_RESET 0x80 -#define BE2_MPU_IRAM_ONLINE 0x00000080 - -#define BE_SENSE_INFO_SIZE 258 -#define BE_ISCSI_PDU_HEADER_SIZE 64 -#define BE_MIN_MEM_SIZE 16384 -#define MAX_CMD_SZ 65536 -#define IIOC_SCSI_DATA 0x05 /* Write Operation */ - -#define DBG_LVL 0x00000001 -#define DBG_LVL_1 0x00000001 -#define DBG_LVL_2 0x00000002 -#define DBG_LVL_3 0x00000004 -#define DBG_LVL_4 0x00000008 -#define DBG_LVL_5 0x00000010 -#define DBG_LVL_6 0x00000020 -#define DBG_LVL_7 0x00000040 -#define DBG_LVL_8 0x00000080 - -#define SE_DEBUG(debug_mask, fmt, args...) \ -do { \ - if (debug_mask & DBG_LVL) { \ - printk(KERN_ERR "(%s():%d):", __func__, __LINE__);\ - printk(fmt, ##args); \ - } \ -} while (0); - -#define BE_ADAPTER_UP 0x00000000 -#define BE_ADAPTER_LINK_DOWN 0x00000001 -/** - * hardware needs the async PDU buffers to be posted in multiples of 8 - * So have atleast 8 of them by default - */ - -#define HWI_GET_ASYNC_PDU_CTX(phwi) (phwi->phwi_ctxt->pasync_ctx) - -/********* Memory BAR register ************/ -#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET 0xfc -/** - * Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt - * Disable" may still globally block interrupts in addition to individual - * interrupt masks; a mechanism for the device driver to block all interrupts - * atomically without having to arbitrate for the PCI Interrupt Disable bit - * with the OS. - */ -#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */ - -/********* ISR0 Register offset **********/ -#define CEV_ISR0_OFFSET 0xC18 -#define CEV_ISR_SIZE 4 - -/** - * Macros for reading/writing a protection domain or CSR registers - * in BladeEngine. - */ - -#define DB_TXULP0_OFFSET 0x40 -#define DB_RXULP0_OFFSET 0xA0 -/********* Event Q door bell *************/ -#define DB_EQ_OFFSET DB_CQ_OFFSET -#define DB_EQ_RING_ID_MASK 0x1FF /* bits 0 - 8 */ -/* Clear the interrupt for this eq */ -#define DB_EQ_CLR_SHIFT (9) /* bit 9 */ -/* Must be 1 */ -#define DB_EQ_EVNT_SHIFT (10) /* bit 10 */ -/* Number of event entries processed */ -#define DB_EQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ -/* Rearm bit */ -#define DB_EQ_REARM_SHIFT (29) /* bit 29 */ - -/********* Compl Q door bell *************/ -#define DB_CQ_OFFSET 0x120 -#define DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */ -/* Number of event entries processed */ -#define DB_CQ_NUM_POPPED_SHIFT (16) /* bits 16 - 28 */ -/* Rearm bit */ -#define DB_CQ_REARM_SHIFT (29) /* bit 29 */ - -#define GET_HWI_CONTROLLER_WS(pc) (pc->phwi_ctrlr) -#define HWI_GET_DEF_BUFQ_ID(pc) (((struct hwi_controller *)\ - (GET_HWI_CONTROLLER_WS(pc)))->default_pdu_data.id) -#define HWI_GET_DEF_HDRQ_ID(pc) (((struct hwi_controller *)\ - (GET_HWI_CONTROLLER_WS(pc)))->default_pdu_hdr.id) - -#define PAGES_REQUIRED(x) \ - ((x < PAGE_SIZE) ? 1 : ((x + PAGE_SIZE - 1) / PAGE_SIZE)) - -#define BEISCSI_MSI_NAME 20 /* size of msi_name string */ - -enum be_mem_enum { - HWI_MEM_ADDN_CONTEXT, - HWI_MEM_WRB, - HWI_MEM_WRBH, - HWI_MEM_SGLH, - HWI_MEM_SGE, - HWI_MEM_ASYNC_HEADER_BUF, /* 5 */ - HWI_MEM_ASYNC_DATA_BUF, - HWI_MEM_ASYNC_HEADER_RING, - HWI_MEM_ASYNC_DATA_RING, - HWI_MEM_ASYNC_HEADER_HANDLE, - HWI_MEM_ASYNC_DATA_HANDLE, /* 10 */ - HWI_MEM_ASYNC_PDU_CONTEXT, - ISCSI_MEM_GLOBAL_HEADER, - SE_MEM_MAX -}; - -struct be_bus_address32 { - unsigned int address_lo; - unsigned int address_hi; -}; - -struct be_bus_address64 { - unsigned long long address; -}; - -struct be_bus_address { - union { - struct be_bus_address32 a32; - struct be_bus_address64 a64; - } u; -}; - -struct mem_array { - struct be_bus_address bus_address; /* Bus address of location */ - void *virtual_address; /* virtual address to the location */ - unsigned int size; /* Size required by memory block */ -}; - -struct be_mem_descriptor { - unsigned int index; /* Index of this memory parameter */ - unsigned int category; /* type indicates cached/non-cached */ - unsigned int num_elements; /* number of elements in this - * descriptor - */ - unsigned int alignment_mask; /* Alignment mask for this block */ - unsigned int size_in_bytes; /* Size required by memory block */ - struct mem_array *mem_array; -}; - -struct sgl_handle { - unsigned int sgl_index; - unsigned int type; - unsigned int cid; - struct iscsi_task *task; - struct iscsi_sge *pfrag; -}; - -struct hba_parameters { - unsigned int ios_per_ctrl; - unsigned int cxns_per_ctrl; - unsigned int asyncpdus_per_ctrl; - unsigned int icds_per_ctrl; - unsigned int num_sge_per_io; - unsigned int defpdu_hdr_sz; - unsigned int defpdu_data_sz; - unsigned int num_cq_entries; - unsigned int num_eq_entries; - unsigned int wrbs_per_cxn; - unsigned int crashmode; - unsigned int hba_num; - - unsigned int mgmt_ws_sz; - unsigned int hwi_ws_sz; - - unsigned int eto; - unsigned int ldto; - - unsigned int dbg_flags; - unsigned int num_cxn; - - unsigned int eq_timer; - /** - * These are calculated from other params. They're here - * for debug purposes - */ - unsigned int num_mcc_pages; - unsigned int num_mcc_cq_pages; - unsigned int num_cq_pages; - unsigned int num_eq_pages; - - unsigned int num_async_pdu_buf_pages; - unsigned int num_async_pdu_buf_sgl_pages; - unsigned int num_async_pdu_buf_cq_pages; - - unsigned int num_async_pdu_hdr_pages; - unsigned int num_async_pdu_hdr_sgl_pages; - unsigned int num_async_pdu_hdr_cq_pages; - - unsigned int num_sge; -}; - -struct invalidate_command_table { - unsigned short icd; - unsigned short cid; -} __packed; - -struct beiscsi_hba { - struct hba_parameters params; - struct hwi_controller *phwi_ctrlr; - unsigned int mem_req[SE_MEM_MAX]; - /* PCI BAR mapped addresses */ - u8 __iomem *csr_va; /* CSR */ - u8 __iomem *db_va; /* Door Bell */ - u8 __iomem *pci_va; /* PCI Config */ - struct be_bus_address csr_pa; /* CSR */ - struct be_bus_address db_pa; /* CSR */ - struct be_bus_address pci_pa; /* CSR */ - /* PCI representation of our HBA */ - struct pci_dev *pcidev; - unsigned int state; - unsigned short asic_revision; - unsigned int num_cpus; - unsigned int nxt_cqid; - struct msix_entry msix_entries[MAX_CPUS + 1]; - char *msi_name[MAX_CPUS + 1]; - bool msix_enabled; - struct be_mem_descriptor *init_mem; - - unsigned short io_sgl_alloc_index; - unsigned short io_sgl_free_index; - unsigned short io_sgl_hndl_avbl; - struct sgl_handle **io_sgl_hndl_base; - struct sgl_handle **sgl_hndl_array; - - unsigned short eh_sgl_alloc_index; - unsigned short eh_sgl_free_index; - unsigned short eh_sgl_hndl_avbl; - struct sgl_handle **eh_sgl_hndl_base; - spinlock_t io_sgl_lock; - spinlock_t mgmt_sgl_lock; - spinlock_t isr_lock; - unsigned int age; - unsigned short avlbl_cids; - unsigned short cid_alloc; - unsigned short cid_free; - struct beiscsi_conn *conn_table[BE2_MAX_SESSIONS * 2]; - struct list_head hba_queue; - unsigned short *cid_array; - struct iscsi_endpoint **ep_array; - struct iscsi_boot_kset *boot_kset; - struct Scsi_Host *shost; - struct { - /** - * group together since they are used most frequently - * for cid to cri conversion - */ - unsigned int iscsi_cid_start; - unsigned int phys_port; - - unsigned int isr_offset; - unsigned int iscsi_icd_start; - unsigned int iscsi_cid_count; - unsigned int iscsi_icd_count; - unsigned int pci_function; - - unsigned short cid_alloc; - unsigned short cid_free; - unsigned short avlbl_cids; - unsigned short iscsi_features; - spinlock_t cid_lock; - } fw_config; - - u8 mac_address[ETH_ALEN]; - unsigned short todo_cq; - unsigned short todo_mcc_cq; - char wq_name[20]; - struct workqueue_struct *wq; /* The actuak work queue */ - struct work_struct work_cqs; /* The work being queued */ - struct be_ctrl_info ctrl; - unsigned int generation; - unsigned int read_mac_address; - struct mgmt_session_info boot_sess; - struct invalidate_command_table inv_tbl[128]; - -}; - -struct beiscsi_session { - struct pci_pool *bhs_pool; -}; - -/** - * struct beiscsi_conn - iscsi connection structure - */ -struct beiscsi_conn { - struct iscsi_conn *conn; - struct beiscsi_hba *phba; - u32 exp_statsn; - u32 beiscsi_conn_cid; - struct beiscsi_endpoint *ep; - unsigned short login_in_progress; - struct wrb_handle *plogin_wrb_handle; - struct sgl_handle *plogin_sgl_handle; - struct beiscsi_session *beiscsi_sess; - struct iscsi_task *task; -}; - -/* This structure is used by the chip */ -struct pdu_data_out { - u32 dw[12]; -}; -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_pdu_data_out { - u8 opcode[6]; /* opcode */ - u8 rsvd0[2]; /* should be 0 */ - u8 rsvd1[7]; - u8 final_bit; /* F bit */ - u8 rsvd2[16]; - u8 ahs_length[8]; /* no AHS */ - u8 data_len_hi[8]; - u8 data_len_lo[16]; /* DataSegmentLength */ - u8 lun[64]; - u8 itt[32]; /* ITT; initiator task tag */ - u8 ttt[32]; /* TTT; valid for R2T or 0xffffffff */ - u8 rsvd3[32]; - u8 exp_stat_sn[32]; - u8 rsvd4[32]; - u8 data_sn[32]; - u8 buffer_offset[32]; - u8 rsvd5[32]; -}; - -struct be_cmd_bhs { - struct iscsi_scsi_req iscsi_hdr; - unsigned char pad1[16]; - struct pdu_data_out iscsi_data_pdu; - unsigned char pad2[BE_SENSE_INFO_SIZE - - sizeof(struct pdu_data_out)]; -}; - -struct beiscsi_io_task { - struct wrb_handle *pwrb_handle; - struct sgl_handle *psgl_handle; - struct beiscsi_conn *conn; - struct scsi_cmnd *scsi_cmnd; - unsigned int cmd_sn; - unsigned int flags; - unsigned short cid; - unsigned short header_len; - itt_t libiscsi_itt; - struct be_cmd_bhs *cmd_bhs; - struct be_bus_address bhs_pa; - unsigned short bhs_len; -}; - -struct be_nonio_bhs { - struct iscsi_hdr iscsi_hdr; - unsigned char pad1[16]; - struct pdu_data_out iscsi_data_pdu; - unsigned char pad2[BE_SENSE_INFO_SIZE - - sizeof(struct pdu_data_out)]; -}; - -struct be_status_bhs { - struct iscsi_scsi_req iscsi_hdr; - unsigned char pad1[16]; - /** - * The plus 2 below is to hold the sense info length that gets - * DMA'ed by RxULP - */ - unsigned char sense_info[BE_SENSE_INFO_SIZE]; -}; - -struct iscsi_sge { - u32 dw[4]; -}; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_iscsi_sge { - u8 addr_hi[32]; - u8 addr_lo[32]; - u8 sge_offset[22]; /* DWORD 2 */ - u8 rsvd0[9]; /* DWORD 2 */ - u8 last_sge; /* DWORD 2 */ - u8 len[17]; /* DWORD 3 */ - u8 rsvd1[15]; /* DWORD 3 */ -}; - -struct beiscsi_offload_params { - u32 dw[5]; -}; - -#define OFFLD_PARAMS_ERL 0x00000003 -#define OFFLD_PARAMS_DDE 0x00000004 -#define OFFLD_PARAMS_HDE 0x00000008 -#define OFFLD_PARAMS_IR2T 0x00000010 -#define OFFLD_PARAMS_IMD 0x00000020 - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_beiscsi_offload_params { - u8 max_burst_length[32]; - u8 max_send_data_segment_length[32]; - u8 first_burst_length[32]; - u8 erl[2]; - u8 dde[1]; - u8 hde[1]; - u8 ir2t[1]; - u8 imd[1]; - u8 pad[26]; - u8 exp_statsn[32]; -}; - -/* void hwi_complete_drvr_msgs(struct beiscsi_conn *beiscsi_conn, - struct beiscsi_hba *phba, struct sol_cqe *psol);*/ - -struct async_pdu_handle { - struct list_head link; - struct be_bus_address pa; - void *pbuffer; - unsigned int consumed; - unsigned char index; - unsigned char is_header; - unsigned short cri; - unsigned long buffer_len; -}; - -struct hwi_async_entry { - struct { - unsigned char hdr_received; - unsigned char hdr_len; - unsigned short bytes_received; - unsigned int bytes_needed; - struct list_head list; - } wait_queue; - - struct list_head header_busy_list; - struct list_head data_busy_list; -}; - -struct hwi_async_pdu_context { - struct { - struct be_bus_address pa_base; - void *va_base; - void *ring_base; - struct async_pdu_handle *handle_base; - - unsigned int host_write_ptr; - unsigned int ep_read_ptr; - unsigned int writables; - - unsigned int free_entries; - unsigned int busy_entries; - unsigned int buffer_size; - unsigned int num_entries; - - struct list_head free_list; - } async_header; - - struct { - struct be_bus_address pa_base; - void *va_base; - void *ring_base; - struct async_pdu_handle *handle_base; - - unsigned int host_write_ptr; - unsigned int ep_read_ptr; - unsigned int writables; - - unsigned int free_entries; - unsigned int busy_entries; - unsigned int buffer_size; - struct list_head free_list; - unsigned int num_entries; - } async_data; - - /** - * This is a varying size list! Do not add anything - * after this entry!! - */ - struct hwi_async_entry async_entry[BE2_MAX_SESSIONS * 2]; -}; - -#define PDUCQE_CODE_MASK 0x0000003F -#define PDUCQE_DPL_MASK 0xFFFF0000 -#define PDUCQE_INDEX_MASK 0x0000FFFF - -struct i_t_dpdu_cqe { - u32 dw[4]; -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_i_t_dpdu_cqe { - u8 db_addr_hi[32]; - u8 db_addr_lo[32]; - u8 code[6]; - u8 cid[10]; - u8 dpl[16]; - u8 index[16]; - u8 num_cons[10]; - u8 rsvd0[4]; - u8 final; - u8 valid; -} __packed; - -#define CQE_VALID_MASK 0x80000000 -#define CQE_CODE_MASK 0x0000003F -#define CQE_CID_MASK 0x0000FFC0 - -#define EQE_VALID_MASK 0x00000001 -#define EQE_MAJORCODE_MASK 0x0000000E -#define EQE_RESID_MASK 0xFFFF0000 - -struct be_eq_entry { - u32 dw[1]; -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_eq_entry { - u8 valid; /* DWORD 0 */ - u8 major_code[3]; /* DWORD 0 */ - u8 minor_code[12]; /* DWORD 0 */ - u8 resource_id[16]; /* DWORD 0 */ - -} __packed; - -struct cq_db { - u32 dw[1]; -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_cq_db { - u8 qid[10]; - u8 event[1]; - u8 rsvd0[5]; - u8 num_popped[13]; - u8 rearm[1]; - u8 rsvd1[2]; -} __packed; - -void beiscsi_process_eq(struct beiscsi_hba *phba); - -struct iscsi_wrb { - u32 dw[16]; -} __packed; - -#define WRB_TYPE_MASK 0xF0000000 - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_iscsi_wrb { - u8 lun[14]; /* DWORD 0 */ - u8 lt; /* DWORD 0 */ - u8 invld; /* DWORD 0 */ - u8 wrb_idx[8]; /* DWORD 0 */ - u8 dsp; /* DWORD 0 */ - u8 dmsg; /* DWORD 0 */ - u8 undr_run; /* DWORD 0 */ - u8 over_run; /* DWORD 0 */ - u8 type[4]; /* DWORD 0 */ - u8 ptr2nextwrb[8]; /* DWORD 1 */ - u8 r2t_exp_dtl[24]; /* DWORD 1 */ - u8 sgl_icd_idx[12]; /* DWORD 2 */ - u8 rsvd0[20]; /* DWORD 2 */ - u8 exp_data_sn[32]; /* DWORD 3 */ - u8 iscsi_bhs_addr_hi[32]; /* DWORD 4 */ - u8 iscsi_bhs_addr_lo[32]; /* DWORD 5 */ - u8 cmdsn_itt[32]; /* DWORD 6 */ - u8 dif_ref_tag[32]; /* DWORD 7 */ - u8 sge0_addr_hi[32]; /* DWORD 8 */ - u8 sge0_addr_lo[32]; /* DWORD 9 */ - u8 sge0_offset[22]; /* DWORD 10 */ - u8 pbs; /* DWORD 10 */ - u8 dif_mode[2]; /* DWORD 10 */ - u8 rsvd1[6]; /* DWORD 10 */ - u8 sge0_last; /* DWORD 10 */ - u8 sge0_len[17]; /* DWORD 11 */ - u8 dif_meta_tag[14]; /* DWORD 11 */ - u8 sge0_in_ddr; /* DWORD 11 */ - u8 sge1_addr_hi[32]; /* DWORD 12 */ - u8 sge1_addr_lo[32]; /* DWORD 13 */ - u8 sge1_r2t_offset[22]; /* DWORD 14 */ - u8 rsvd2[9]; /* DWORD 14 */ - u8 sge1_last; /* DWORD 14 */ - u8 sge1_len[17]; /* DWORD 15 */ - u8 ref_sgl_icd_idx[12]; /* DWORD 15 */ - u8 rsvd3[2]; /* DWORD 15 */ - u8 sge1_in_ddr; /* DWORD 15 */ - -} __packed; - -struct wrb_handle *alloc_wrb_handle(struct beiscsi_hba *phba, unsigned int cid); -void -free_mgmt_sgl_handle(struct beiscsi_hba *phba, struct sgl_handle *psgl_handle); - -void beiscsi_process_all_cqs(struct work_struct *work); - -struct pdu_nop_out { - u32 dw[12]; -}; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_pdu_nop_out { - u8 opcode[6]; /* opcode 0x00 */ - u8 i_bit; /* I Bit */ - u8 x_bit; /* reserved; should be 0 */ - u8 fp_bit_filler1[7]; - u8 f_bit; /* always 1 */ - u8 reserved1[16]; - u8 ahs_length[8]; /* no AHS */ - u8 data_len_hi[8]; - u8 data_len_lo[16]; /* DataSegmentLength */ - u8 lun[64]; - u8 itt[32]; /* initiator id for ping or 0xffffffff */ - u8 ttt[32]; /* target id for ping or 0xffffffff */ - u8 cmd_sn[32]; - u8 exp_stat_sn[32]; - u8 reserved5[128]; -}; - -#define PDUBASE_OPCODE_MASK 0x0000003F -#define PDUBASE_DATALENHI_MASK 0x0000FF00 -#define PDUBASE_DATALENLO_MASK 0xFFFF0000 - -struct pdu_base { - u32 dw[16]; -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_pdu_base { - u8 opcode[6]; - u8 i_bit; /* immediate bit */ - u8 x_bit; /* reserved, always 0 */ - u8 reserved1[24]; /* opcode-specific fields */ - u8 ahs_length[8]; /* length units is 4 byte words */ - u8 data_len_hi[8]; - u8 data_len_lo[16]; /* DatasegmentLength */ - u8 lun[64]; /* lun or opcode-specific fields */ - u8 itt[32]; /* initiator task tag */ - u8 reserved4[224]; -}; - -struct iscsi_target_context_update_wrb { - u32 dw[16]; -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_iscsi_target_context_update_wrb { - u8 lun[14]; /* DWORD 0 */ - u8 lt; /* DWORD 0 */ - u8 invld; /* DWORD 0 */ - u8 wrb_idx[8]; /* DWORD 0 */ - u8 dsp; /* DWORD 0 */ - u8 dmsg; /* DWORD 0 */ - u8 undr_run; /* DWORD 0 */ - u8 over_run; /* DWORD 0 */ - u8 type[4]; /* DWORD 0 */ - u8 ptr2nextwrb[8]; /* DWORD 1 */ - u8 max_burst_length[19]; /* DWORD 1 */ - u8 rsvd0[5]; /* DWORD 1 */ - u8 rsvd1[15]; /* DWORD 2 */ - u8 max_send_data_segment_length[17]; /* DWORD 2 */ - u8 first_burst_length[14]; /* DWORD 3 */ - u8 rsvd2[2]; /* DWORD 3 */ - u8 tx_wrbindex_drv_msg[8]; /* DWORD 3 */ - u8 rsvd3[5]; /* DWORD 3 */ - u8 session_state[3]; /* DWORD 3 */ - u8 rsvd4[16]; /* DWORD 4 */ - u8 tx_jumbo; /* DWORD 4 */ - u8 hde; /* DWORD 4 */ - u8 dde; /* DWORD 4 */ - u8 erl[2]; /* DWORD 4 */ - u8 domain_id[5]; /* DWORD 4 */ - u8 mode; /* DWORD 4 */ - u8 imd; /* DWORD 4 */ - u8 ir2t; /* DWORD 4 */ - u8 notpredblq[2]; /* DWORD 4 */ - u8 compltonack; /* DWORD 4 */ - u8 stat_sn[32]; /* DWORD 5 */ - u8 pad_buffer_addr_hi[32]; /* DWORD 6 */ - u8 pad_buffer_addr_lo[32]; /* DWORD 7 */ - u8 pad_addr_hi[32]; /* DWORD 8 */ - u8 pad_addr_lo[32]; /* DWORD 9 */ - u8 rsvd5[32]; /* DWORD 10 */ - u8 rsvd6[32]; /* DWORD 11 */ - u8 rsvd7[32]; /* DWORD 12 */ - u8 rsvd8[32]; /* DWORD 13 */ - u8 rsvd9[32]; /* DWORD 14 */ - u8 rsvd10[32]; /* DWORD 15 */ - -} __packed; - -struct be_ring { - u32 pages; /* queue size in pages */ - u32 id; /* queue id assigned by beklib */ - u32 num; /* number of elements in queue */ - u32 cidx; /* consumer index */ - u32 pidx; /* producer index -- not used by most rings */ - u32 item_size; /* size in bytes of one object */ - - void *va; /* The virtual address of the ring. This - * should be last to allow 32 & 64 bit debugger - * extensions to work. - */ -}; - -struct hwi_wrb_context { - struct list_head wrb_handle_list; - struct list_head wrb_handle_drvr_list; - struct wrb_handle **pwrb_handle_base; - struct wrb_handle **pwrb_handle_basestd; - struct iscsi_wrb *plast_wrb; - unsigned short alloc_index; - unsigned short free_index; - unsigned short wrb_handles_available; - unsigned short cid; -}; - -struct hwi_controller { - struct list_head io_sgl_list; - struct list_head eh_sgl_list; - struct sgl_handle *psgl_handle_base; - unsigned int wrb_mem_index; - - struct hwi_wrb_context wrb_context[BE2_MAX_SESSIONS * 2]; - struct mcc_wrb *pmcc_wrb_base; - struct be_ring default_pdu_hdr; - struct be_ring default_pdu_data; - struct hwi_context_memory *phwi_ctxt; -}; - -enum hwh_type_enum { - HWH_TYPE_IO = 1, - HWH_TYPE_LOGOUT = 2, - HWH_TYPE_TMF = 3, - HWH_TYPE_NOP = 4, - HWH_TYPE_IO_RD = 5, - HWH_TYPE_LOGIN = 11, - HWH_TYPE_INVALID = 0xFFFFFFFF -}; - -struct wrb_handle { - enum hwh_type_enum type; - unsigned short wrb_index; - unsigned short nxt_wrb_index; - - struct iscsi_task *pio_handle; - struct iscsi_wrb *pwrb; -}; - -struct hwi_context_memory { - /* Adaptive interrupt coalescing (AIC) info */ - u16 min_eqd; /* in usecs */ - u16 max_eqd; /* in usecs */ - u16 cur_eqd; /* in usecs */ - struct be_eq_obj be_eq[MAX_CPUS]; - struct be_queue_info be_cq[MAX_CPUS]; - - struct be_queue_info be_def_hdrq; - struct be_queue_info be_def_dataq; - - struct be_queue_info be_wrbq[BE2_MAX_SESSIONS]; - struct be_mcc_wrb_context *pbe_mcc_context; - - struct hwi_async_pdu_context *pasync_ctx; -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.c b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.c deleted file mode 100644 index 44762cfa..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.c +++ /dev/null @@ -1,449 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#include "be_mgmt.h" -#include "be_iscsi.h" -#include - -unsigned int beiscsi_get_boot_target(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_req_get_mac_addr *req; - unsigned int tag = 0; - - SE_DEBUG(DBG_LVL_8, "In bescsi_get_boot_target\n"); - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - - wrb = wrb_from_mccq(phba); - req = embedded_payload(wrb); - wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_BOOT_GET_BOOT_TARGET, - sizeof(*req)); - - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int beiscsi_get_session_info(struct beiscsi_hba *phba, - u32 boot_session_handle, - struct be_dma_mem *nonemb_cmd) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - unsigned int tag = 0; - struct be_cmd_req_get_session *req; - struct be_cmd_resp_get_session *resp; - struct be_sge *sge; - - SE_DEBUG(DBG_LVL_8, "In beiscsi_get_session_info\n"); - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - - nonemb_cmd->size = sizeof(*resp); - req = nonemb_cmd->va; - memset(req, 0, sizeof(*req)); - wrb = wrb_from_mccq(phba); - sge = nonembedded_sgl(wrb); - wrb->tag0 |= tag; - - - wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_SESSION_GET_A_SESSION, - sizeof(*resp)); - req->session_handle = boot_session_handle; - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd->size); - - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -int mgmt_get_fw_config(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba) -{ - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_fw_cfg *req = embedded_payload(wrb); - int status = 0; - - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req)); - status = be_mbox_notify(ctrl); - if (!status) { - struct be_fw_cfg *pfw_cfg; - pfw_cfg = req; - phba->fw_config.phys_port = pfw_cfg->phys_port; - phba->fw_config.iscsi_icd_start = - pfw_cfg->ulp[0].icd_base; - phba->fw_config.iscsi_icd_count = - pfw_cfg->ulp[0].icd_count; - phba->fw_config.iscsi_cid_start = - pfw_cfg->ulp[0].sq_base; - phba->fw_config.iscsi_cid_count = - pfw_cfg->ulp[0].sq_count; - if (phba->fw_config.iscsi_cid_count > (BE2_MAX_SESSIONS / 2)) { - SE_DEBUG(DBG_LVL_8, - "FW reported MAX CXNS as %d\t" - "Max Supported = %d.\n", - phba->fw_config.iscsi_cid_count, - BE2_MAX_SESSIONS); - phba->fw_config.iscsi_cid_count = BE2_MAX_SESSIONS / 2; - } - } else { - shost_printk(KERN_WARNING, phba->shost, - "Failed in mgmt_get_fw_config\n"); - } - - spin_unlock(&ctrl->mbox_lock); - return status; -} - -int mgmt_check_supported_fw(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba) -{ - struct be_dma_mem nonemb_cmd; - struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); - struct be_mgmt_controller_attributes *req; - struct be_sge *sge = nonembedded_sgl(wrb); - int status = 0; - - nonemb_cmd.va = pci_alloc_consistent(ctrl->pdev, - sizeof(struct be_mgmt_controller_attributes), - &nonemb_cmd.dma); - if (nonemb_cmd.va == NULL) { - SE_DEBUG(DBG_LVL_1, - "Failed to allocate memory for mgmt_check_supported_fw" - "\n"); - return -ENOMEM; - } - nonemb_cmd.size = sizeof(struct be_mgmt_controller_attributes); - req = nonemb_cmd.va; - memset(req, 0, sizeof(*req)); - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, - OPCODE_COMMON_GET_CNTL_ATTRIBUTES, sizeof(*req)); - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd.dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd.dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd.size); - status = be_mbox_notify(ctrl); - if (!status) { - struct be_mgmt_controller_attributes_resp *resp = nonemb_cmd.va; - SE_DEBUG(DBG_LVL_8, "Firmware version of CMD: %s\n", - resp->params.hba_attribs.flashrom_version_string); - SE_DEBUG(DBG_LVL_8, "Firmware version is : %s\n", - resp->params.hba_attribs.firmware_version_string); - SE_DEBUG(DBG_LVL_8, - "Developer Build, not performing version check...\n"); - phba->fw_config.iscsi_features = - resp->params.hba_attribs.iscsi_features; - SE_DEBUG(DBG_LVL_8, " phba->fw_config.iscsi_features = %d\n", - phba->fw_config.iscsi_features); - } else - SE_DEBUG(DBG_LVL_1, " Failed in mgmt_check_supported_fw\n"); - spin_unlock(&ctrl->mbox_lock); - if (nonemb_cmd.va) - pci_free_consistent(ctrl->pdev, nonemb_cmd.size, - nonemb_cmd.va, nonemb_cmd.dma); - - return status; -} - -int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb = wrb_from_mccq(phba); - struct iscsi_cleanup_req *req = embedded_payload(wrb); - int status = 0; - - spin_lock(&ctrl->mbox_lock); - memset(wrb, 0, sizeof(*wrb)); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_CLEANUP, sizeof(*req)); - - req->chute = chute; - req->hdr_ring_id = cpu_to_le16(HWI_GET_DEF_HDRQ_ID(phba)); - req->data_ring_id = cpu_to_le16(HWI_GET_DEF_BUFQ_ID(phba)); - - status = be_mcc_notify_wait(phba); - if (status) - shost_printk(KERN_WARNING, phba->shost, - " mgmt_epfw_cleanup , FAILED\n"); - spin_unlock(&ctrl->mbox_lock); - return status; -} - -unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invalidate_command_table *inv_tbl, - unsigned int num_invalidate, unsigned int cid, - struct be_dma_mem *nonemb_cmd) - -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_sge *sge; - struct invalidate_commands_params_in *req; - unsigned int i, tag = 0; - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - - req = nonemb_cmd->va; - memset(req, 0, sizeof(*req)); - wrb = wrb_from_mccq(phba); - sge = nonembedded_sgl(wrb); - wrb->tag0 |= tag; - - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_ERROR_RECOVERY_INVALIDATE_COMMANDS, - sizeof(*req)); - req->ref_handle = 0; - req->cleanup_type = CMD_ISCSI_COMMAND_INVALIDATE; - for (i = 0; i < num_invalidate; i++) { - req->table[i].icd = inv_tbl->icd; - req->table[i].cid = inv_tbl->cid; - req->icd_count++; - inv_tbl++; - } - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd->size); - - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, - struct beiscsi_endpoint *beiscsi_ep, - unsigned short cid, - unsigned short issue_reset, - unsigned short savecfg_flag) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct iscsi_invalidate_connection_params_in *req; - unsigned int tag = 0; - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - wrb = wrb_from_mccq(phba); - wrb->tag0 |= tag; - req = embedded_payload(wrb); - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI_INI, - OPCODE_ISCSI_INI_DRIVER_INVALIDATE_CONNECTION, - sizeof(*req)); - req->session_handle = beiscsi_ep->fw_handle; - req->cid = cid; - if (issue_reset) - req->cleanup_type = CMD_ISCSI_CONNECTION_ISSUE_TCP_RST; - else - req->cleanup_type = CMD_ISCSI_CONNECTION_INVALIDATE; - req->save_cfg = savecfg_flag; - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, - unsigned short cid, unsigned int upload_flag) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct tcp_upload_params_in *req; - unsigned int tag = 0; - - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - wrb = wrb_from_mccq(phba); - req = embedded_payload(wrb); - wrb->tag0 |= tag; - - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_COMMON_TCP_UPLOAD, - OPCODE_COMMON_TCP_UPLOAD, sizeof(*req)); - req->id = (unsigned short)cid; - req->upload_type = (unsigned char)upload_flag; - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -int mgmt_open_connection(struct beiscsi_hba *phba, - struct sockaddr *dst_addr, - struct beiscsi_endpoint *beiscsi_ep, - struct be_dma_mem *nonemb_cmd) - -{ - struct hwi_controller *phwi_ctrlr; - struct hwi_context_memory *phwi_context; - struct sockaddr_in *daddr_in = (struct sockaddr_in *)dst_addr; - struct sockaddr_in6 *daddr_in6 = (struct sockaddr_in6 *)dst_addr; - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct tcp_connect_and_offload_in *req; - unsigned short def_hdr_id; - unsigned short def_data_id; - struct phys_addr template_address = { 0, 0 }; - struct phys_addr *ptemplate_address; - unsigned int tag = 0; - unsigned int i; - unsigned short cid = beiscsi_ep->ep_cid; - struct be_sge *sge; - - phwi_ctrlr = phba->phwi_ctrlr; - phwi_context = phwi_ctrlr->phwi_ctxt; - def_hdr_id = (unsigned short)HWI_GET_DEF_HDRQ_ID(phba); - def_data_id = (unsigned short)HWI_GET_DEF_BUFQ_ID(phba); - - ptemplate_address = &template_address; - ISCSI_GET_PDU_TEMPLATE_ADDRESS(phba, ptemplate_address); - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - wrb = wrb_from_mccq(phba); - memset(wrb, 0, sizeof(*wrb)); - sge = nonembedded_sgl(wrb); - - req = nonemb_cmd->va; - memset(req, 0, sizeof(*req)); - wrb->tag0 |= tag; - - be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_TCP_CONNECT_AND_OFFLOAD, - sizeof(*req)); - if (dst_addr->sa_family == PF_INET) { - __be32 s_addr = daddr_in->sin_addr.s_addr; - req->ip_address.ip_type = BE2_IPV4; - req->ip_address.ip_address[0] = s_addr & 0x000000ff; - req->ip_address.ip_address[1] = (s_addr & 0x0000ff00) >> 8; - req->ip_address.ip_address[2] = (s_addr & 0x00ff0000) >> 16; - req->ip_address.ip_address[3] = (s_addr & 0xff000000) >> 24; - req->tcp_port = ntohs(daddr_in->sin_port); - beiscsi_ep->dst_addr = daddr_in->sin_addr.s_addr; - beiscsi_ep->dst_tcpport = ntohs(daddr_in->sin_port); - beiscsi_ep->ip_type = BE2_IPV4; - } else if (dst_addr->sa_family == PF_INET6) { - req->ip_address.ip_type = BE2_IPV6; - memcpy(&req->ip_address.ip_address, - &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); - req->tcp_port = ntohs(daddr_in6->sin6_port); - beiscsi_ep->dst_tcpport = ntohs(daddr_in6->sin6_port); - memcpy(&beiscsi_ep->dst6_addr, - &daddr_in6->sin6_addr.in6_u.u6_addr8, 16); - beiscsi_ep->ip_type = BE2_IPV6; - } else{ - shost_printk(KERN_ERR, phba->shost, "unknown addr family %d\n", - dst_addr->sa_family); - spin_unlock(&ctrl->mbox_lock); - free_mcc_tag(&phba->ctrl, tag); - return -EINVAL; - - } - req->cid = cid; - i = phba->nxt_cqid++; - if (phba->nxt_cqid == phba->num_cpus) - phba->nxt_cqid = 0; - req->cq_id = phwi_context->be_cq[i].id; - SE_DEBUG(DBG_LVL_8, "i=%d cq_id=%d\n", i, req->cq_id); - req->defq_id = def_hdr_id; - req->hdr_ring_id = def_hdr_id; - req->data_ring_id = def_data_id; - req->do_offload = 1; - req->dataout_template_pa.lo = ptemplate_address->lo; - req->dataout_template_pa.hi = ptemplate_address->hi; - sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma)); - sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF); - sge->len = cpu_to_le32(nonemb_cmd->size); - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - -unsigned int be_cmd_get_mac_addr(struct beiscsi_hba *phba) -{ - struct be_ctrl_info *ctrl = &phba->ctrl; - struct be_mcc_wrb *wrb; - struct be_cmd_req_get_mac_addr *req; - unsigned int tag = 0; - - SE_DEBUG(DBG_LVL_8, "In be_cmd_get_mac_addr\n"); - spin_lock(&ctrl->mbox_lock); - tag = alloc_mcc_tag(phba); - if (!tag) { - spin_unlock(&ctrl->mbox_lock); - return tag; - } - - wrb = wrb_from_mccq(phba); - req = embedded_payload(wrb); - wrb->tag0 |= tag; - be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); - be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ISCSI, - OPCODE_COMMON_ISCSI_NTWK_GET_NIC_CONFIG, - sizeof(*req)); - - be_mcc_notify(phba); - spin_unlock(&ctrl->mbox_lock); - return tag; -} - diff --git a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.h b/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.h deleted file mode 100644 index 08428824..00000000 --- a/ANDROID_3.4.5/drivers/scsi/be2iscsi/be_mgmt.h +++ /dev/null @@ -1,251 +0,0 @@ -/** - * Copyright (C) 2005 - 2011 Emulex - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. The full GNU General - * Public License is included in this distribution in the file called COPYING. - * - * Written by: Jayamohan Kallickal (jayamohan.kallickal@emulex.com) - * - * Contact Information: - * linux-drivers@emulex.com - * - * Emulex - * 3333 Susan Street - * Costa Mesa, CA 92626 - */ - -#ifndef _BEISCSI_MGMT_ -#define _BEISCSI_MGMT_ - -#include -#include -#include "be_iscsi.h" -#include "be_main.h" - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_sge { - u8 pa_lo[32]; /* dword 0 */ - u8 pa_hi[32]; /* dword 1 */ - u8 length[32]; /* DWORD 2 */ -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_wrb_payload { - union { - struct amap_mcc_sge sgl[19]; - u8 embedded[59 * 32]; /* DWORDS 57 to 115 */ - } u; -} __packed; - -/** - * Pseudo amap definition in which each bit of the actual structure is defined - * as a byte: used to calculate offset/shift/mask of each field - */ -struct amap_mcc_wrb { - u8 embedded; /* DWORD 0 */ - u8 rsvd0[2]; /* DWORD 0 */ - u8 sge_count[5]; /* DWORD 0 */ - u8 rsvd1[16]; /* DWORD 0 */ - u8 special[8]; /* DWORD 0 */ - u8 payload_length[32]; - u8 tag[64]; /* DWORD 2 */ - u8 rsvd2[32]; /* DWORD 4 */ - struct amap_mcc_wrb_payload payload; -}; - -struct mcc_sge { - u32 pa_lo; /* dword 0 */ - u32 pa_hi; /* dword 1 */ - u32 length; /* DWORD 2 */ -} __packed; - -struct mcc_wrb_payload { - union { - struct mcc_sge sgl[19]; - u32 embedded[59]; /* DWORDS 57 to 115 */ - } u; -} __packed; - -#define MCC_WRB_EMBEDDED_MASK 0x00000001 - -struct mcc_wrb { - u32 dw[0]; /* DWORD 0 */ - u32 payload_length; - u32 tag[2]; /* DWORD 2 */ - u32 rsvd2[1]; /* DWORD 4 */ - struct mcc_wrb_payload payload; -}; - -int mgmt_epfw_cleanup(struct beiscsi_hba *phba, unsigned short chute); -int mgmt_open_connection(struct beiscsi_hba *phba, - struct sockaddr *dst_addr, - struct beiscsi_endpoint *beiscsi_ep, - struct be_dma_mem *nonemb_cmd); - -unsigned int mgmt_upload_connection(struct beiscsi_hba *phba, - unsigned short cid, - unsigned int upload_flag); -unsigned int mgmt_invalidate_icds(struct beiscsi_hba *phba, - struct invalidate_command_table *inv_tbl, - unsigned int num_invalidate, unsigned int cid, - struct be_dma_mem *nonemb_cmd); - -struct iscsi_invalidate_connection_params_in { - struct be_cmd_req_hdr hdr; - unsigned int session_handle; - unsigned short cid; - unsigned short unused; - unsigned short cleanup_type; - unsigned short save_cfg; -} __packed; - -struct iscsi_invalidate_connection_params_out { - unsigned int session_handle; - unsigned short cid; - unsigned short unused; -} __packed; - -union iscsi_invalidate_connection_params { - struct iscsi_invalidate_connection_params_in request; - struct iscsi_invalidate_connection_params_out response; -} __packed; - -struct invalidate_commands_params_in { - struct be_cmd_req_hdr hdr; - unsigned int ref_handle; - unsigned int icd_count; - struct invalidate_command_table table[128]; - unsigned short cleanup_type; - unsigned short unused; -} __packed; - -struct invalidate_commands_params_out { - unsigned int ref_handle; - unsigned int icd_count; - unsigned int icd_status[128]; -} __packed; - -union invalidate_commands_params { - struct invalidate_commands_params_in request; - struct invalidate_commands_params_out response; -} __packed; - -struct mgmt_hba_attributes { - u8 flashrom_version_string[32]; - u8 manufacturer_name[32]; - u32 supported_modes; - u8 seeprom_version_lo; - u8 seeprom_version_hi; - u8 rsvd0[2]; - u32 fw_cmd_data_struct_version; - u32 ep_fw_data_struct_version; - u32 future_reserved[12]; - u32 default_extended_timeout; - u8 controller_model_number[32]; - u8 controller_description[64]; - u8 controller_serial_number[32]; - u8 ip_version_string[32]; - u8 firmware_version_string[32]; - u8 bios_version_string[32]; - u8 redboot_version_string[32]; - u8 driver_version_string[32]; - u8 fw_on_flash_version_string[32]; - u32 functionalities_supported; - u16 max_cdblength; - u8 asic_revision; - u8 generational_guid[16]; - u8 hba_port_count; - u16 default_link_down_timeout; - u8 iscsi_ver_min_max; - u8 multifunction_device; - u8 cache_valid; - u8 hba_status; - u8 max_domains_supported; - u8 phy_port; - u32 firmware_post_status; - u32 hba_mtu[8]; - u8 iscsi_features; - u8 future_u8[3]; - u32 future_u32[3]; -} __packed; - -struct mgmt_controller_attributes { - struct mgmt_hba_attributes hba_attribs; - u16 pci_vendor_id; - u16 pci_device_id; - u16 pci_sub_vendor_id; - u16 pci_sub_system_id; - u8 pci_bus_number; - u8 pci_device_number; - u8 pci_function_number; - u8 interface_type; - u64 unique_identifier; - u8 netfilters; - u8 rsvd0[3]; - u8 future_u32[4]; -} __packed; - -struct be_mgmt_controller_attributes { - struct be_cmd_req_hdr hdr; - struct mgmt_controller_attributes params; -} __packed; - -struct be_mgmt_controller_attributes_resp { - struct be_cmd_resp_hdr hdr; - struct mgmt_controller_attributes params; -} __packed; - -/* configuration management */ - -#define GET_MGMT_CONTROLLER_WS(phba) (phba->pmgmt_ws) - -/* MGMT CMD flags */ - -#define MGMT_CMDH_FREE (1<<0) - -/* --- MGMT_ERROR_CODES --- */ -/* Error Codes returned in the status field of the CMD response header */ -#define MGMT_STATUS_SUCCESS 0 /* The CMD completed without errors */ -#define MGMT_STATUS_FAILED 1 /* Error status in the Status field of */ - /* the CMD_RESPONSE_HEADER */ - -#define ISCSI_GET_PDU_TEMPLATE_ADDRESS(pc, pa) {\ - pa->lo = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ - bus_address.u.a32.address_lo; \ - pa->hi = phba->init_mem[ISCSI_MEM_GLOBAL_HEADER].mem_array[0].\ - bus_address.u.a32.address_hi; \ -} - -struct beiscsi_endpoint { - struct beiscsi_hba *phba; - struct beiscsi_sess *sess; - struct beiscsi_conn *conn; - struct iscsi_endpoint *openiscsi_ep; - unsigned short ip_type; - char dst6_addr[ISCSI_ADDRESS_BUF_LEN]; - unsigned long dst_addr; - unsigned short ep_cid; - unsigned int fw_handle; - u16 dst_tcpport; - u16 cid_vld; -}; - -int mgmt_get_fw_config(struct be_ctrl_info *ctrl, - struct beiscsi_hba *phba); - -unsigned int mgmt_invalidate_connection(struct beiscsi_hba *phba, - struct beiscsi_endpoint *beiscsi_ep, - unsigned short cid, - unsigned short issue_reset, - unsigned short savecfg_flag); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/Makefile b/ANDROID_3.4.5/drivers/scsi/bfa/Makefile deleted file mode 100644 index 475cf925..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -obj-$(CONFIG_SCSI_BFA_FC) := bfa.o - -bfa-y := bfad.o bfad_im.o bfad_attr.o bfad_debugfs.o bfad_bsg.o -bfa-y += bfa_ioc.o bfa_ioc_cb.o bfa_ioc_ct.o bfa_hw_cb.o bfa_hw_ct.o -bfa-y += bfa_fcs.o bfa_fcs_lport.o bfa_fcs_rport.o bfa_fcs_fcpim.o bfa_fcbuild.o -bfa-y += bfa_port.o bfa_fcpim.o bfa_core.o bfa_svc.o diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa.h deleted file mode 100644 index 4ad7e368..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa.h +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_H__ -#define __BFA_H__ - -#include "bfad_drv.h" -#include "bfa_cs.h" -#include "bfa_plog.h" -#include "bfa_defs_svc.h" -#include "bfi.h" -#include "bfa_ioc.h" - -struct bfa_s; - -typedef void (*bfa_isr_func_t) (struct bfa_s *bfa, struct bfi_msg_s *m); -typedef void (*bfa_cb_cbfn_status_t) (void *cbarg, bfa_status_t status); - -/* - * Interrupt message handlers - */ -void bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m); - -/* - * Request and response queue related defines - */ -#define BFA_REQQ_NELEMS_MIN (4) -#define BFA_RSPQ_NELEMS_MIN (4) - -#define bfa_reqq_pi(__bfa, __reqq) ((__bfa)->iocfc.req_cq_pi[__reqq]) -#define bfa_reqq_ci(__bfa, __reqq) \ - (*(u32 *)((__bfa)->iocfc.req_cq_shadow_ci[__reqq].kva)) - -#define bfa_reqq_full(__bfa, __reqq) \ - (((bfa_reqq_pi(__bfa, __reqq) + 1) & \ - ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1)) == \ - bfa_reqq_ci(__bfa, __reqq)) - -#define bfa_reqq_next(__bfa, __reqq) \ - (bfa_reqq_full(__bfa, __reqq) ? NULL : \ - ((void *)((struct bfi_msg_s *)((__bfa)->iocfc.req_cq_ba[__reqq].kva) \ - + bfa_reqq_pi((__bfa), (__reqq))))) - -#define bfa_reqq_produce(__bfa, __reqq, __mh) do { \ - (__mh).mtag.h2i.qid = (__bfa)->iocfc.hw_qid[__reqq];\ - (__bfa)->iocfc.req_cq_pi[__reqq]++; \ - (__bfa)->iocfc.req_cq_pi[__reqq] &= \ - ((__bfa)->iocfc.cfg.drvcfg.num_reqq_elems - 1); \ - writel((__bfa)->iocfc.req_cq_pi[__reqq], \ - (__bfa)->iocfc.bfa_regs.cpe_q_pi[__reqq]); \ - mmiowb(); \ - } while (0) - -#define bfa_rspq_pi(__bfa, __rspq) \ - (*(u32 *)((__bfa)->iocfc.rsp_cq_shadow_pi[__rspq].kva)) - -#define bfa_rspq_ci(__bfa, __rspq) ((__bfa)->iocfc.rsp_cq_ci[__rspq]) -#define bfa_rspq_elem(__bfa, __rspq, __ci) \ - (&((struct bfi_msg_s *)((__bfa)->iocfc.rsp_cq_ba[__rspq].kva))[__ci]) - -#define CQ_INCR(__index, __size) do { \ - (__index)++; \ - (__index) &= ((__size) - 1); \ -} while (0) - -/* - * Circular queue usage assignments - */ -enum { - BFA_REQQ_IOC = 0, /* all low-priority IOC msgs */ - BFA_REQQ_FCXP = 0, /* all FCXP messages */ - BFA_REQQ_LPS = 0, /* all lport service msgs */ - BFA_REQQ_PORT = 0, /* all port messages */ - BFA_REQQ_FLASH = 0, /* for flash module */ - BFA_REQQ_DIAG = 0, /* for diag module */ - BFA_REQQ_RPORT = 0, /* all port messages */ - BFA_REQQ_SBOOT = 0, /* all san boot messages */ - BFA_REQQ_QOS_LO = 1, /* all low priority IO */ - BFA_REQQ_QOS_MD = 2, /* all medium priority IO */ - BFA_REQQ_QOS_HI = 3, /* all high priority IO */ -}; - -static inline void -bfa_reqq_winit(struct bfa_reqq_wait_s *wqe, void (*qresume) (void *cbarg), - void *cbarg) -{ - wqe->qresume = qresume; - wqe->cbarg = cbarg; -} - -#define bfa_reqq(__bfa, __reqq) (&(__bfa)->reqq_waitq[__reqq]) - -/* - * static inline void - * bfa_reqq_wait(struct bfa_s *bfa, int reqq, struct bfa_reqq_wait_s *wqe) - */ -#define bfa_reqq_wait(__bfa, __reqq, __wqe) do { \ - \ - struct list_head *waitq = bfa_reqq(__bfa, __reqq); \ - \ - WARN_ON(((__reqq) >= BFI_IOC_MAX_CQS)); \ - WARN_ON(!((__wqe)->qresume && (__wqe)->cbarg)); \ - \ - list_add_tail(&(__wqe)->qe, waitq); \ - } while (0) - -#define bfa_reqq_wcancel(__wqe) list_del(&(__wqe)->qe) - -#define bfa_cb_queue(__bfa, __hcb_qe, __cbfn, __cbarg) do { \ - (__hcb_qe)->cbfn = (__cbfn); \ - (__hcb_qe)->cbarg = (__cbarg); \ - (__hcb_qe)->pre_rmv = BFA_FALSE; \ - list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \ - } while (0) - -#define bfa_cb_dequeue(__hcb_qe) list_del(&(__hcb_qe)->qe) - -#define bfa_cb_queue_once(__bfa, __hcb_qe, __cbfn, __cbarg) do { \ - (__hcb_qe)->cbfn = (__cbfn); \ - (__hcb_qe)->cbarg = (__cbarg); \ - if (!(__hcb_qe)->once) { \ - list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \ - (__hcb_qe)->once = BFA_TRUE; \ - } \ - } while (0) - -#define bfa_cb_queue_status(__bfa, __hcb_qe, __status) do { \ - (__hcb_qe)->fw_status = (__status); \ - list_add_tail(&(__hcb_qe)->qe, &(__bfa)->comp_q); \ -} while (0) - -#define bfa_cb_queue_done(__hcb_qe) do { \ - (__hcb_qe)->once = BFA_FALSE; \ - } while (0) - - -/* - * PCI devices supported by the current BFA - */ -struct bfa_pciid_s { - u16 device_id; - u16 vendor_id; -}; - -extern char bfa_version[]; - -struct bfa_iocfc_regs_s { - void __iomem *intr_status; - void __iomem *intr_mask; - void __iomem *cpe_q_pi[BFI_IOC_MAX_CQS]; - void __iomem *cpe_q_ci[BFI_IOC_MAX_CQS]; - void __iomem *cpe_q_ctrl[BFI_IOC_MAX_CQS]; - void __iomem *rme_q_ci[BFI_IOC_MAX_CQS]; - void __iomem *rme_q_pi[BFI_IOC_MAX_CQS]; - void __iomem *rme_q_ctrl[BFI_IOC_MAX_CQS]; -}; - -/* - * MSIX vector handlers - */ -#define BFA_MSIX_MAX_VECTORS 22 -typedef void (*bfa_msix_handler_t)(struct bfa_s *bfa, int vec); -struct bfa_msix_s { - int nvecs; - bfa_msix_handler_t handler[BFA_MSIX_MAX_VECTORS]; -}; - -/* - * Chip specific interfaces - */ -struct bfa_hwif_s { - void (*hw_reginit)(struct bfa_s *bfa); - void (*hw_reqq_ack)(struct bfa_s *bfa, int reqq); - void (*hw_rspq_ack)(struct bfa_s *bfa, int rspq, u32 ci); - void (*hw_msix_init)(struct bfa_s *bfa, int nvecs); - void (*hw_msix_ctrl_install)(struct bfa_s *bfa); - void (*hw_msix_queue_install)(struct bfa_s *bfa); - void (*hw_msix_uninstall)(struct bfa_s *bfa); - void (*hw_isr_mode_set)(struct bfa_s *bfa, bfa_boolean_t msix); - void (*hw_msix_getvecs)(struct bfa_s *bfa, u32 *vecmap, - u32 *nvecs, u32 *maxvec); - void (*hw_msix_get_rme_range) (struct bfa_s *bfa, u32 *start, - u32 *end); - int cpe_vec_q0; - int rme_vec_q0; -}; -typedef void (*bfa_cb_iocfc_t) (void *cbarg, enum bfa_status status); - -struct bfa_faa_cbfn_s { - bfa_cb_iocfc_t faa_cbfn; - void *faa_cbarg; -}; - -#define BFA_FAA_ENABLED 1 -#define BFA_FAA_DISABLED 2 - -/* - * FAA attributes - */ -struct bfa_faa_attr_s { - wwn_t faa; - u8 faa_state; - u8 pwwn_source; - u8 rsvd[6]; -}; - -struct bfa_faa_args_s { - struct bfa_faa_attr_s *faa_attr; - struct bfa_faa_cbfn_s faa_cb; - u8 faa_state; - bfa_boolean_t busy; -}; - -struct bfa_iocfc_s { - bfa_fsm_t fsm; - struct bfa_s *bfa; - struct bfa_iocfc_cfg_s cfg; - u32 req_cq_pi[BFI_IOC_MAX_CQS]; - u32 rsp_cq_ci[BFI_IOC_MAX_CQS]; - u8 hw_qid[BFI_IOC_MAX_CQS]; - struct bfa_cb_qe_s init_hcb_qe; - struct bfa_cb_qe_s stop_hcb_qe; - struct bfa_cb_qe_s dis_hcb_qe; - struct bfa_cb_qe_s en_hcb_qe; - struct bfa_cb_qe_s stats_hcb_qe; - bfa_boolean_t submod_enabled; - bfa_boolean_t cb_reqd; /* Driver call back reqd */ - bfa_status_t op_status; /* Status of bfa iocfc op */ - - struct bfa_dma_s cfg_info; - struct bfi_iocfc_cfg_s *cfginfo; - struct bfa_dma_s cfgrsp_dma; - struct bfi_iocfc_cfgrsp_s *cfgrsp; - struct bfa_dma_s req_cq_ba[BFI_IOC_MAX_CQS]; - struct bfa_dma_s req_cq_shadow_ci[BFI_IOC_MAX_CQS]; - struct bfa_dma_s rsp_cq_ba[BFI_IOC_MAX_CQS]; - struct bfa_dma_s rsp_cq_shadow_pi[BFI_IOC_MAX_CQS]; - struct bfa_iocfc_regs_s bfa_regs; /* BFA device registers */ - struct bfa_hwif_s hwif; - bfa_cb_iocfc_t updateq_cbfn; /* bios callback function */ - void *updateq_cbarg; /* bios callback arg */ - u32 intr_mask; - struct bfa_faa_args_s faa_args; - struct bfa_mem_dma_s ioc_dma; - struct bfa_mem_dma_s iocfc_dma; - struct bfa_mem_dma_s reqq_dma[BFI_IOC_MAX_CQS]; - struct bfa_mem_dma_s rspq_dma[BFI_IOC_MAX_CQS]; - struct bfa_mem_kva_s kva_seg; -}; - -#define BFA_MEM_IOC_DMA(_bfa) (&((_bfa)->iocfc.ioc_dma)) -#define BFA_MEM_IOCFC_DMA(_bfa) (&((_bfa)->iocfc.iocfc_dma)) -#define BFA_MEM_REQQ_DMA(_bfa, _qno) (&((_bfa)->iocfc.reqq_dma[(_qno)])) -#define BFA_MEM_RSPQ_DMA(_bfa, _qno) (&((_bfa)->iocfc.rspq_dma[(_qno)])) -#define BFA_MEM_IOCFC_KVA(_bfa) (&((_bfa)->iocfc.kva_seg)) - -#define bfa_fn_lpu(__bfa) \ - bfi_fn_lpu(bfa_ioc_pcifn(&(__bfa)->ioc), bfa_ioc_portid(&(__bfa)->ioc)) -#define bfa_msix_init(__bfa, __nvecs) \ - ((__bfa)->iocfc.hwif.hw_msix_init(__bfa, __nvecs)) -#define bfa_msix_ctrl_install(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_ctrl_install(__bfa)) -#define bfa_msix_queue_install(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_queue_install(__bfa)) -#define bfa_msix_uninstall(__bfa) \ - ((__bfa)->iocfc.hwif.hw_msix_uninstall(__bfa)) -#define bfa_isr_rspq_ack(__bfa, __queue, __ci) \ - ((__bfa)->iocfc.hwif.hw_rspq_ack(__bfa, __queue, __ci)) -#define bfa_isr_reqq_ack(__bfa, __queue) do { \ - if ((__bfa)->iocfc.hwif.hw_reqq_ack) \ - (__bfa)->iocfc.hwif.hw_reqq_ack(__bfa, __queue); \ -} while (0) -#define bfa_isr_mode_set(__bfa, __msix) do { \ - if ((__bfa)->iocfc.hwif.hw_isr_mode_set) \ - (__bfa)->iocfc.hwif.hw_isr_mode_set(__bfa, __msix); \ -} while (0) -#define bfa_msix_getvecs(__bfa, __vecmap, __nvecs, __maxvec) \ - ((__bfa)->iocfc.hwif.hw_msix_getvecs(__bfa, __vecmap, \ - __nvecs, __maxvec)) -#define bfa_msix_get_rme_range(__bfa, __start, __end) \ - ((__bfa)->iocfc.hwif.hw_msix_get_rme_range(__bfa, __start, __end)) -#define bfa_msix(__bfa, __vec) \ - ((__bfa)->msix.handler[__vec](__bfa, __vec)) - -/* - * FC specific IOC functions. - */ -void bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); -void bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, - struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev); -void bfa_iocfc_init(struct bfa_s *bfa); -void bfa_iocfc_start(struct bfa_s *bfa); -void bfa_iocfc_stop(struct bfa_s *bfa); -void bfa_iocfc_isr(void *bfa, struct bfi_mbmsg_s *msg); -void bfa_iocfc_set_snsbase(struct bfa_s *bfa, int seg_no, u64 snsbase_pa); -bfa_boolean_t bfa_iocfc_is_operational(struct bfa_s *bfa); -void bfa_iocfc_reset_queues(struct bfa_s *bfa); - -void bfa_msix_all(struct bfa_s *bfa, int vec); -void bfa_msix_reqq(struct bfa_s *bfa, int vec); -void bfa_msix_rspq(struct bfa_s *bfa, int vec); -void bfa_msix_lpu_err(struct bfa_s *bfa, int vec); - -void bfa_hwcb_reginit(struct bfa_s *bfa); -void bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci); -void bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs); -void bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa); -void bfa_hwcb_msix_queue_install(struct bfa_s *bfa); -void bfa_hwcb_msix_uninstall(struct bfa_s *bfa); -void bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); -void bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, - u32 *maxvec); -void bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, - u32 *end); -void bfa_hwct_reginit(struct bfa_s *bfa); -void bfa_hwct2_reginit(struct bfa_s *bfa); -void bfa_hwct_reqq_ack(struct bfa_s *bfa, int rspq); -void bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci); -void bfa_hwct2_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci); -void bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs); -void bfa_hwct_msix_ctrl_install(struct bfa_s *bfa); -void bfa_hwct_msix_queue_install(struct bfa_s *bfa); -void bfa_hwct_msix_uninstall(struct bfa_s *bfa); -void bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix); -void bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *vecmap, u32 *nvecs, - u32 *maxvec); -void bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, - u32 *end); -void bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns); -int bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, - struct bfi_pbc_vport_s *pbc_vport); - - -/* - *---------------------------------------------------------------------- - * BFA public interfaces - *---------------------------------------------------------------------- - */ -#define bfa_stats(_mod, _stats) ((_mod)->stats._stats++) -#define bfa_ioc_get_stats(__bfa, __ioc_stats) \ - bfa_ioc_fetch_stats(&(__bfa)->ioc, __ioc_stats) -#define bfa_ioc_clear_stats(__bfa) \ - bfa_ioc_clr_stats(&(__bfa)->ioc) -#define bfa_get_nports(__bfa) \ - bfa_ioc_get_nports(&(__bfa)->ioc) -#define bfa_get_adapter_manufacturer(__bfa, __manufacturer) \ - bfa_ioc_get_adapter_manufacturer(&(__bfa)->ioc, __manufacturer) -#define bfa_get_adapter_model(__bfa, __model) \ - bfa_ioc_get_adapter_model(&(__bfa)->ioc, __model) -#define bfa_get_adapter_serial_num(__bfa, __serial_num) \ - bfa_ioc_get_adapter_serial_num(&(__bfa)->ioc, __serial_num) -#define bfa_get_adapter_fw_ver(__bfa, __fw_ver) \ - bfa_ioc_get_adapter_fw_ver(&(__bfa)->ioc, __fw_ver) -#define bfa_get_adapter_optrom_ver(__bfa, __optrom_ver) \ - bfa_ioc_get_adapter_optrom_ver(&(__bfa)->ioc, __optrom_ver) -#define bfa_get_pci_chip_rev(__bfa, __chip_rev) \ - bfa_ioc_get_pci_chip_rev(&(__bfa)->ioc, __chip_rev) -#define bfa_get_ioc_state(__bfa) \ - bfa_ioc_get_state(&(__bfa)->ioc) -#define bfa_get_type(__bfa) \ - bfa_ioc_get_type(&(__bfa)->ioc) -#define bfa_get_mac(__bfa) \ - bfa_ioc_get_mac(&(__bfa)->ioc) -#define bfa_get_mfg_mac(__bfa) \ - bfa_ioc_get_mfg_mac(&(__bfa)->ioc) -#define bfa_get_fw_clock_res(__bfa) \ - ((__bfa)->iocfc.cfgrsp->fwcfg.fw_tick_res) - -/* - * lun mask macros return NULL when min cfg is enabled and there is - * no memory allocated for lunmask. - */ -#define bfa_get_lun_mask(__bfa) \ - ((&(__bfa)->modules.dconf_mod)->min_cfg) ? NULL : \ - (&(BFA_DCONF_MOD(__bfa)->dconf->lun_mask)) - -#define bfa_get_lun_mask_list(_bfa) \ - ((&(_bfa)->modules.dconf_mod)->min_cfg) ? NULL : \ - (bfa_get_lun_mask(_bfa)->lun_list) - -#define bfa_get_lun_mask_status(_bfa) \ - (((&(_bfa)->modules.dconf_mod)->min_cfg) \ - ? BFA_LUNMASK_MINCFG : ((bfa_get_lun_mask(_bfa))->status)) - -void bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids); -void bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg); -void bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg); -void bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); -void bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_pcidev_s *pcidev); -void bfa_detach(struct bfa_s *bfa); -void bfa_cb_init(void *bfad, bfa_status_t status); -void bfa_cb_updateq(void *bfad, bfa_status_t status); - -bfa_boolean_t bfa_intx(struct bfa_s *bfa); -void bfa_isr_enable(struct bfa_s *bfa); -void bfa_isr_disable(struct bfa_s *bfa); - -void bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q); -void bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q); -void bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q); - -typedef void (*bfa_cb_ioc_t) (void *cbarg, enum bfa_status status); -void bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr); - - -bfa_status_t bfa_iocfc_israttr_set(struct bfa_s *bfa, - struct bfa_iocfc_intr_attr_s *attr); - -void bfa_iocfc_enable(struct bfa_s *bfa); -void bfa_iocfc_disable(struct bfa_s *bfa); -#define bfa_timer_start(_bfa, _timer, _timercb, _arg, _timeout) \ - bfa_timer_begin(&(_bfa)->timer_mod, _timer, _timercb, _arg, _timeout) - -struct bfa_cb_pending_q_s { - struct bfa_cb_qe_s hcb_qe; - void *data; /* Driver buffer */ -}; - -/* Common macros to operate on pending stats/attr apis */ -#define bfa_pending_q_init(__qe, __cbfn, __cbarg, __data) do { \ - bfa_q_qe_init(&((__qe)->hcb_qe.qe)); \ - (__qe)->hcb_qe.cbfn = (__cbfn); \ - (__qe)->hcb_qe.cbarg = (__cbarg); \ - (__qe)->hcb_qe.pre_rmv = BFA_TRUE; \ - (__qe)->data = (__data); \ -} while (0) - -#endif /* __BFA_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_core.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_core.c deleted file mode 100644 index 456e5762..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_core.c +++ /dev/null @@ -1,1925 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfa_modules.h" -#include "bfi_reg.h" - -BFA_TRC_FILE(HAL, CORE); - -/* - * BFA module list terminated by NULL - */ -static struct bfa_module_s *hal_mods[] = { - &hal_mod_fcdiag, - &hal_mod_sgpg, - &hal_mod_fcport, - &hal_mod_fcxp, - &hal_mod_lps, - &hal_mod_uf, - &hal_mod_rport, - &hal_mod_fcp, - &hal_mod_dconf, - NULL -}; - -/* - * Message handlers for various modules. - */ -static bfa_isr_func_t bfa_isrs[BFI_MC_MAX] = { - bfa_isr_unhandled, /* NONE */ - bfa_isr_unhandled, /* BFI_MC_IOC */ - bfa_fcdiag_intr, /* BFI_MC_DIAG */ - bfa_isr_unhandled, /* BFI_MC_FLASH */ - bfa_isr_unhandled, /* BFI_MC_CEE */ - bfa_fcport_isr, /* BFI_MC_FCPORT */ - bfa_isr_unhandled, /* BFI_MC_IOCFC */ - bfa_isr_unhandled, /* BFI_MC_LL */ - bfa_uf_isr, /* BFI_MC_UF */ - bfa_fcxp_isr, /* BFI_MC_FCXP */ - bfa_lps_isr, /* BFI_MC_LPS */ - bfa_rport_isr, /* BFI_MC_RPORT */ - bfa_itn_isr, /* BFI_MC_ITN */ - bfa_isr_unhandled, /* BFI_MC_IOIM_READ */ - bfa_isr_unhandled, /* BFI_MC_IOIM_WRITE */ - bfa_isr_unhandled, /* BFI_MC_IOIM_IO */ - bfa_ioim_isr, /* BFI_MC_IOIM */ - bfa_ioim_good_comp_isr, /* BFI_MC_IOIM_IOCOM */ - bfa_tskim_isr, /* BFI_MC_TSKIM */ - bfa_isr_unhandled, /* BFI_MC_SBOOT */ - bfa_isr_unhandled, /* BFI_MC_IPFC */ - bfa_isr_unhandled, /* BFI_MC_PORT */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ - bfa_isr_unhandled, /* --------- */ -}; -/* - * Message handlers for mailbox command classes - */ -static bfa_ioc_mbox_mcfunc_t bfa_mbox_isrs[BFI_MC_MAX] = { - NULL, - NULL, /* BFI_MC_IOC */ - NULL, /* BFI_MC_DIAG */ - NULL, /* BFI_MC_FLASH */ - NULL, /* BFI_MC_CEE */ - NULL, /* BFI_MC_PORT */ - bfa_iocfc_isr, /* BFI_MC_IOCFC */ - NULL, -}; - - - -static void -bfa_com_port_attach(struct bfa_s *bfa) -{ - struct bfa_port_s *port = &bfa->modules.port; - struct bfa_mem_dma_s *port_dma = BFA_MEM_PORT_DMA(bfa); - - bfa_port_attach(port, &bfa->ioc, bfa, bfa->trcmod); - bfa_port_mem_claim(port, port_dma->kva_curp, port_dma->dma_curp); -} - -/* - * ablk module attach - */ -static void -bfa_com_ablk_attach(struct bfa_s *bfa) -{ - struct bfa_ablk_s *ablk = &bfa->modules.ablk; - struct bfa_mem_dma_s *ablk_dma = BFA_MEM_ABLK_DMA(bfa); - - bfa_ablk_attach(ablk, &bfa->ioc); - bfa_ablk_memclaim(ablk, ablk_dma->kva_curp, ablk_dma->dma_curp); -} - -static void -bfa_com_cee_attach(struct bfa_s *bfa) -{ - struct bfa_cee_s *cee = &bfa->modules.cee; - struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa); - - cee->trcmod = bfa->trcmod; - bfa_cee_attach(cee, &bfa->ioc, bfa); - bfa_cee_mem_claim(cee, cee_dma->kva_curp, cee_dma->dma_curp); -} - -static void -bfa_com_sfp_attach(struct bfa_s *bfa) -{ - struct bfa_sfp_s *sfp = BFA_SFP_MOD(bfa); - struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa); - - bfa_sfp_attach(sfp, &bfa->ioc, bfa, bfa->trcmod); - bfa_sfp_memclaim(sfp, sfp_dma->kva_curp, sfp_dma->dma_curp); -} - -static void -bfa_com_flash_attach(struct bfa_s *bfa, bfa_boolean_t mincfg) -{ - struct bfa_flash_s *flash = BFA_FLASH(bfa); - struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa); - - bfa_flash_attach(flash, &bfa->ioc, bfa, bfa->trcmod, mincfg); - bfa_flash_memclaim(flash, flash_dma->kva_curp, - flash_dma->dma_curp, mincfg); -} - -static void -bfa_com_diag_attach(struct bfa_s *bfa) -{ - struct bfa_diag_s *diag = BFA_DIAG_MOD(bfa); - struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa); - - bfa_diag_attach(diag, &bfa->ioc, bfa, bfa_fcport_beacon, bfa->trcmod); - bfa_diag_memclaim(diag, diag_dma->kva_curp, diag_dma->dma_curp); -} - -static void -bfa_com_phy_attach(struct bfa_s *bfa, bfa_boolean_t mincfg) -{ - struct bfa_phy_s *phy = BFA_PHY(bfa); - struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa); - - bfa_phy_attach(phy, &bfa->ioc, bfa, bfa->trcmod, mincfg); - bfa_phy_memclaim(phy, phy_dma->kva_curp, phy_dma->dma_curp, mincfg); -} - -/* - * BFA IOC FC related definitions - */ - -/* - * IOC local definitions - */ -#define BFA_IOCFC_TOV 5000 /* msecs */ - -enum { - BFA_IOCFC_ACT_NONE = 0, - BFA_IOCFC_ACT_INIT = 1, - BFA_IOCFC_ACT_STOP = 2, - BFA_IOCFC_ACT_DISABLE = 3, - BFA_IOCFC_ACT_ENABLE = 4, -}; - -#define DEF_CFG_NUM_FABRICS 1 -#define DEF_CFG_NUM_LPORTS 256 -#define DEF_CFG_NUM_CQS 4 -#define DEF_CFG_NUM_IOIM_REQS (BFA_IOIM_MAX) -#define DEF_CFG_NUM_TSKIM_REQS 128 -#define DEF_CFG_NUM_FCXP_REQS 64 -#define DEF_CFG_NUM_UF_BUFS 64 -#define DEF_CFG_NUM_RPORTS 1024 -#define DEF_CFG_NUM_ITNIMS (DEF_CFG_NUM_RPORTS) -#define DEF_CFG_NUM_TINS 256 - -#define DEF_CFG_NUM_SGPGS 2048 -#define DEF_CFG_NUM_REQQ_ELEMS 256 -#define DEF_CFG_NUM_RSPQ_ELEMS 64 -#define DEF_CFG_NUM_SBOOT_TGTS 16 -#define DEF_CFG_NUM_SBOOT_LUNS 16 - -/* - * IOCFC state machine definitions/declarations - */ -bfa_fsm_state_decl(bfa_iocfc, stopped, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, initing, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, dconf_read, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, init_cfg_wait, - struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, init_cfg_done, - struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, operational, - struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, dconf_write, - struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, stopping, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, enabling, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, cfg_wait, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, disabling, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, disabled, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, failed, struct bfa_iocfc_s, enum iocfc_event); -bfa_fsm_state_decl(bfa_iocfc, init_failed, - struct bfa_iocfc_s, enum iocfc_event); - -/* - * forward declaration for IOC FC functions - */ -static void bfa_iocfc_start_submod(struct bfa_s *bfa); -static void bfa_iocfc_disable_submod(struct bfa_s *bfa); -static void bfa_iocfc_send_cfg(void *bfa_arg); -static void bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status); -static void bfa_iocfc_disable_cbfn(void *bfa_arg); -static void bfa_iocfc_hbfail_cbfn(void *bfa_arg); -static void bfa_iocfc_reset_cbfn(void *bfa_arg); -static struct bfa_ioc_cbfn_s bfa_iocfc_cbfn; -static void bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete); -static void bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl); -static void bfa_iocfc_enable_cb(void *bfa_arg, bfa_boolean_t compl); -static void bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl); - -static void -bfa_iocfc_sm_stopped_entry(struct bfa_iocfc_s *iocfc) -{ -} - -static void -bfa_iocfc_sm_stopped(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_INIT: - case IOCFC_E_ENABLE: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_initing); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_initing_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_ioc_enable(&iocfc->bfa->ioc); -} - -static void -bfa_iocfc_sm_initing(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_IOC_ENABLED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_read); - break; - case IOCFC_E_IOC_FAILED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_dconf_read_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_dconf_modinit(iocfc->bfa); -} - -static void -bfa_iocfc_sm_dconf_read(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_DCONF_DONE: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_cfg_wait); - break; - case IOCFC_E_IOC_FAILED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_init_cfg_wait_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_iocfc_send_cfg(iocfc->bfa); -} - -static void -bfa_iocfc_sm_init_cfg_wait(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_CFG_DONE: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_cfg_done); - break; - case IOCFC_E_IOC_FAILED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_init_failed); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_init_cfg_done_entry(struct bfa_iocfc_s *iocfc) -{ - iocfc->bfa->iocfc.op_status = BFA_STATUS_OK; - bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.init_hcb_qe, - bfa_iocfc_init_cb, iocfc->bfa); -} - -static void -bfa_iocfc_sm_init_cfg_done(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_START: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_operational); - break; - case IOCFC_E_STOP: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping); - break; - case IOCFC_E_DISABLE: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling); - break; - case IOCFC_E_IOC_FAILED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_operational_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_fcport_init(iocfc->bfa); - bfa_iocfc_start_submod(iocfc->bfa); -} - -static void -bfa_iocfc_sm_operational(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_STOP: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_write); - break; - case IOCFC_E_DISABLE: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling); - break; - case IOCFC_E_IOC_FAILED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_dconf_write_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_dconf_modexit(iocfc->bfa); -} - -static void -bfa_iocfc_sm_dconf_write(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_DCONF_DONE: - case IOCFC_E_IOC_FAILED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_stopping_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_ioc_disable(&iocfc->bfa->ioc); -} - -static void -bfa_iocfc_sm_stopping(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_IOC_DISABLED: - bfa_isr_disable(iocfc->bfa); - bfa_iocfc_disable_submod(iocfc->bfa); - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopped); - iocfc->bfa->iocfc.op_status = BFA_STATUS_OK; - bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.stop_hcb_qe, - bfa_iocfc_stop_cb, iocfc->bfa); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_enabling_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_ioc_enable(&iocfc->bfa->ioc); -} - -static void -bfa_iocfc_sm_enabling(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_IOC_ENABLED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_cfg_wait); - break; - case IOCFC_E_IOC_FAILED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed); - - if (iocfc->bfa->iocfc.cb_reqd == BFA_FALSE) - break; - - iocfc->bfa->iocfc.op_status = BFA_STATUS_FAILED; - bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.en_hcb_qe, - bfa_iocfc_enable_cb, iocfc->bfa); - iocfc->bfa->iocfc.cb_reqd = BFA_FALSE; - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_cfg_wait_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_iocfc_send_cfg(iocfc->bfa); -} - -static void -bfa_iocfc_sm_cfg_wait(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_CFG_DONE: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_operational); - if (iocfc->bfa->iocfc.cb_reqd == BFA_FALSE) - break; - - iocfc->bfa->iocfc.op_status = BFA_STATUS_OK; - bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.en_hcb_qe, - bfa_iocfc_enable_cb, iocfc->bfa); - iocfc->bfa->iocfc.cb_reqd = BFA_FALSE; - break; - case IOCFC_E_IOC_FAILED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_failed); - if (iocfc->bfa->iocfc.cb_reqd == BFA_FALSE) - break; - - iocfc->bfa->iocfc.op_status = BFA_STATUS_FAILED; - bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.en_hcb_qe, - bfa_iocfc_enable_cb, iocfc->bfa); - iocfc->bfa->iocfc.cb_reqd = BFA_FALSE; - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_disabling_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_ioc_disable(&iocfc->bfa->ioc); -} - -static void -bfa_iocfc_sm_disabling(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_IOC_DISABLED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabled); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_disabled_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_isr_disable(iocfc->bfa); - bfa_iocfc_disable_submod(iocfc->bfa); - iocfc->bfa->iocfc.op_status = BFA_STATUS_OK; - bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.dis_hcb_qe, - bfa_iocfc_disable_cb, iocfc->bfa); -} - -static void -bfa_iocfc_sm_disabled(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_STOP: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_write); - break; - case IOCFC_E_ENABLE: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_enabling); - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_failed_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_isr_disable(iocfc->bfa); - bfa_iocfc_disable_submod(iocfc->bfa); -} - -static void -bfa_iocfc_sm_failed(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_STOP: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_write); - break; - case IOCFC_E_DISABLE: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_disabling); - break; - case IOCFC_E_IOC_ENABLED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_cfg_wait); - break; - case IOCFC_E_IOC_FAILED: - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -static void -bfa_iocfc_sm_init_failed_entry(struct bfa_iocfc_s *iocfc) -{ - bfa_isr_disable(iocfc->bfa); - iocfc->bfa->iocfc.op_status = BFA_STATUS_FAILED; - bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.init_hcb_qe, - bfa_iocfc_init_cb, iocfc->bfa); -} - -static void -bfa_iocfc_sm_init_failed(struct bfa_iocfc_s *iocfc, enum iocfc_event event) -{ - bfa_trc(iocfc->bfa, event); - - switch (event) { - case IOCFC_E_STOP: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopping); - break; - case IOCFC_E_DISABLE: - bfa_ioc_disable(&iocfc->bfa->ioc); - break; - case IOCFC_E_IOC_ENABLED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_dconf_read); - break; - case IOCFC_E_IOC_DISABLED: - bfa_fsm_set_state(iocfc, bfa_iocfc_sm_stopped); - iocfc->bfa->iocfc.op_status = BFA_STATUS_OK; - bfa_cb_queue(iocfc->bfa, &iocfc->bfa->iocfc.dis_hcb_qe, - bfa_iocfc_disable_cb, iocfc->bfa); - break; - case IOCFC_E_IOC_FAILED: - break; - default: - bfa_sm_fault(iocfc->bfa, event); - break; - } -} - -/* - * BFA Interrupt handling functions - */ -static void -bfa_reqq_resume(struct bfa_s *bfa, int qid) -{ - struct list_head *waitq, *qe, *qen; - struct bfa_reqq_wait_s *wqe; - - waitq = bfa_reqq(bfa, qid); - list_for_each_safe(qe, qen, waitq) { - /* - * Callback only as long as there is room in request queue - */ - if (bfa_reqq_full(bfa, qid)) - break; - - list_del(qe); - wqe = (struct bfa_reqq_wait_s *) qe; - wqe->qresume(wqe->cbarg); - } -} - -bfa_boolean_t -bfa_isr_rspq(struct bfa_s *bfa, int qid) -{ - struct bfi_msg_s *m; - u32 pi, ci; - struct list_head *waitq; - bfa_boolean_t ret; - - ci = bfa_rspq_ci(bfa, qid); - pi = bfa_rspq_pi(bfa, qid); - - ret = (ci != pi); - - while (ci != pi) { - m = bfa_rspq_elem(bfa, qid, ci); - WARN_ON(m->mhdr.msg_class >= BFI_MC_MAX); - - bfa_isrs[m->mhdr.msg_class] (bfa, m); - CQ_INCR(ci, bfa->iocfc.cfg.drvcfg.num_rspq_elems); - } - - /* - * acknowledge RME completions and update CI - */ - bfa_isr_rspq_ack(bfa, qid, ci); - - /* - * Resume any pending requests in the corresponding reqq. - */ - waitq = bfa_reqq(bfa, qid); - if (!list_empty(waitq)) - bfa_reqq_resume(bfa, qid); - - return ret; -} - -static inline void -bfa_isr_reqq(struct bfa_s *bfa, int qid) -{ - struct list_head *waitq; - - bfa_isr_reqq_ack(bfa, qid); - - /* - * Resume any pending requests in the corresponding reqq. - */ - waitq = bfa_reqq(bfa, qid); - if (!list_empty(waitq)) - bfa_reqq_resume(bfa, qid); -} - -void -bfa_msix_all(struct bfa_s *bfa, int vec) -{ - u32 intr, qintr; - int queue; - - intr = readl(bfa->iocfc.bfa_regs.intr_status); - if (!intr) - return; - - /* - * RME completion queue interrupt - */ - qintr = intr & __HFN_INT_RME_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_rspq(bfa, queue); - } - - intr &= ~qintr; - if (!intr) - return; - - /* - * CPE completion queue interrupt - */ - qintr = intr & __HFN_INT_CPE_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_reqq(bfa, queue); - } - intr &= ~qintr; - if (!intr) - return; - - bfa_msix_lpu_err(bfa, intr); -} - -bfa_boolean_t -bfa_intx(struct bfa_s *bfa) -{ - u32 intr, qintr; - int queue; - bfa_boolean_t rspq_comp = BFA_FALSE; - - intr = readl(bfa->iocfc.bfa_regs.intr_status); - - qintr = intr & (__HFN_INT_RME_MASK | __HFN_INT_CPE_MASK); - if (qintr) - writel(qintr, bfa->iocfc.bfa_regs.intr_status); - - /* - * Unconditional RME completion queue interrupt - */ - if (bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - if (bfa_isr_rspq(bfa, queue)) - rspq_comp = BFA_TRUE; - } - - if (!intr) - return (qintr | rspq_comp) ? BFA_TRUE : BFA_FALSE; - - /* - * CPE completion queue interrupt - */ - qintr = intr & __HFN_INT_CPE_MASK; - if (qintr && bfa->queue_process) { - for (queue = 0; queue < BFI_IOC_MAX_CQS; queue++) - bfa_isr_reqq(bfa, queue); - } - intr &= ~qintr; - if (!intr) - return BFA_TRUE; - - bfa_msix_lpu_err(bfa, intr); - - return BFA_TRUE; -} - -void -bfa_isr_enable(struct bfa_s *bfa) -{ - u32 umsk; - int pci_func = bfa_ioc_pcifn(&bfa->ioc); - - bfa_trc(bfa, pci_func); - - bfa_msix_ctrl_install(bfa); - - if (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)) { - umsk = __HFN_INT_ERR_MASK_CT2; - umsk |= pci_func == 0 ? - __HFN_INT_FN0_MASK_CT2 : __HFN_INT_FN1_MASK_CT2; - } else { - umsk = __HFN_INT_ERR_MASK; - umsk |= pci_func == 0 ? __HFN_INT_FN0_MASK : __HFN_INT_FN1_MASK; - } - - writel(umsk, bfa->iocfc.bfa_regs.intr_status); - writel(~umsk, bfa->iocfc.bfa_regs.intr_mask); - bfa->iocfc.intr_mask = ~umsk; - bfa_isr_mode_set(bfa, bfa->msix.nvecs != 0); -} - -void -bfa_isr_disable(struct bfa_s *bfa) -{ - bfa_isr_mode_set(bfa, BFA_FALSE); - writel(-1L, bfa->iocfc.bfa_regs.intr_mask); - bfa_msix_uninstall(bfa); -} - -void -bfa_msix_reqq(struct bfa_s *bfa, int vec) -{ - bfa_isr_reqq(bfa, vec - bfa->iocfc.hwif.cpe_vec_q0); -} - -void -bfa_isr_unhandled(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - bfa_trc(bfa, m->mhdr.msg_class); - bfa_trc(bfa, m->mhdr.msg_id); - bfa_trc(bfa, m->mhdr.mtag.i2htok); - WARN_ON(1); - bfa_trc_stop(bfa->trcmod); -} - -void -bfa_msix_rspq(struct bfa_s *bfa, int vec) -{ - bfa_isr_rspq(bfa, vec - bfa->iocfc.hwif.rme_vec_q0); -} - -void -bfa_msix_lpu_err(struct bfa_s *bfa, int vec) -{ - u32 intr, curr_value; - bfa_boolean_t lpu_isr, halt_isr, pss_isr; - - intr = readl(bfa->iocfc.bfa_regs.intr_status); - - if (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id)) { - halt_isr = intr & __HFN_INT_CPQ_HALT_CT2; - pss_isr = intr & __HFN_INT_ERR_PSS_CT2; - lpu_isr = intr & (__HFN_INT_MBOX_LPU0_CT2 | - __HFN_INT_MBOX_LPU1_CT2); - intr &= __HFN_INT_ERR_MASK_CT2; - } else { - halt_isr = bfa_asic_id_ct(bfa->ioc.pcidev.device_id) ? - (intr & __HFN_INT_LL_HALT) : 0; - pss_isr = intr & __HFN_INT_ERR_PSS; - lpu_isr = intr & (__HFN_INT_MBOX_LPU0 | __HFN_INT_MBOX_LPU1); - intr &= __HFN_INT_ERR_MASK; - } - - if (lpu_isr) - bfa_ioc_mbox_isr(&bfa->ioc); - - if (intr) { - if (halt_isr) { - /* - * If LL_HALT bit is set then FW Init Halt LL Port - * Register needs to be cleared as well so Interrupt - * Status Register will be cleared. - */ - curr_value = readl(bfa->ioc.ioc_regs.ll_halt); - curr_value &= ~__FW_INIT_HALT_P; - writel(curr_value, bfa->ioc.ioc_regs.ll_halt); - } - - if (pss_isr) { - /* - * ERR_PSS bit needs to be cleared as well in case - * interrups are shared so driver's interrupt handler is - * still called even though it is already masked out. - */ - curr_value = readl( - bfa->ioc.ioc_regs.pss_err_status_reg); - writel(curr_value, - bfa->ioc.ioc_regs.pss_err_status_reg); - } - - writel(intr, bfa->iocfc.bfa_regs.intr_status); - bfa_ioc_error_isr(&bfa->ioc); - } -} - -/* - * BFA IOC FC related functions - */ - -/* - * BFA IOC private functions - */ - -/* - * Use the Mailbox interface to send BFI_IOCFC_H2I_CFG_REQ - */ -static void -bfa_iocfc_send_cfg(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfg_req_s cfg_req; - struct bfi_iocfc_cfg_s *cfg_info = iocfc->cfginfo; - struct bfa_iocfc_cfg_s *cfg = &iocfc->cfg; - int i; - - WARN_ON(cfg->fwcfg.num_cqs > BFI_IOC_MAX_CQS); - bfa_trc(bfa, cfg->fwcfg.num_cqs); - - bfa_iocfc_reset_queues(bfa); - - /* - * initialize IOC configuration info - */ - cfg_info->single_msix_vec = 0; - if (bfa->msix.nvecs == 1) - cfg_info->single_msix_vec = 1; - cfg_info->endian_sig = BFI_IOC_ENDIAN_SIG; - cfg_info->num_cqs = cfg->fwcfg.num_cqs; - cfg_info->num_ioim_reqs = cpu_to_be16(cfg->fwcfg.num_ioim_reqs); - cfg_info->num_fwtio_reqs = cpu_to_be16(cfg->fwcfg.num_fwtio_reqs); - - bfa_dma_be_addr_set(cfg_info->cfgrsp_addr, iocfc->cfgrsp_dma.pa); - /* - * dma map REQ and RSP circular queues and shadow pointers - */ - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - bfa_dma_be_addr_set(cfg_info->req_cq_ba[i], - iocfc->req_cq_ba[i].pa); - bfa_dma_be_addr_set(cfg_info->req_shadow_ci[i], - iocfc->req_cq_shadow_ci[i].pa); - cfg_info->req_cq_elems[i] = - cpu_to_be16(cfg->drvcfg.num_reqq_elems); - - bfa_dma_be_addr_set(cfg_info->rsp_cq_ba[i], - iocfc->rsp_cq_ba[i].pa); - bfa_dma_be_addr_set(cfg_info->rsp_shadow_pi[i], - iocfc->rsp_cq_shadow_pi[i].pa); - cfg_info->rsp_cq_elems[i] = - cpu_to_be16(cfg->drvcfg.num_rspq_elems); - } - - /* - * Enable interrupt coalescing if it is driver init path - * and not ioc disable/enable path. - */ - if (bfa_fsm_cmp_state(iocfc, bfa_iocfc_sm_init_cfg_wait)) - cfg_info->intr_attr.coalesce = BFA_TRUE; - - /* - * dma map IOC configuration itself - */ - bfi_h2i_set(cfg_req.mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_CFG_REQ, - bfa_fn_lpu(bfa)); - bfa_dma_be_addr_set(cfg_req.ioc_cfg_dma_addr, iocfc->cfg_info.pa); - - bfa_ioc_mbox_send(&bfa->ioc, &cfg_req, - sizeof(struct bfi_iocfc_cfg_req_s)); -} - -static void -bfa_iocfc_init_mem(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - bfa->bfad = bfad; - iocfc->bfa = bfa; - iocfc->cfg = *cfg; - - /* - * Initialize chip specific handlers. - */ - if (bfa_asic_id_ctc(bfa_ioc_devid(&bfa->ioc))) { - iocfc->hwif.hw_reginit = bfa_hwct_reginit; - iocfc->hwif.hw_reqq_ack = bfa_hwct_reqq_ack; - iocfc->hwif.hw_rspq_ack = bfa_hwct_rspq_ack; - iocfc->hwif.hw_msix_init = bfa_hwct_msix_init; - iocfc->hwif.hw_msix_ctrl_install = bfa_hwct_msix_ctrl_install; - iocfc->hwif.hw_msix_queue_install = bfa_hwct_msix_queue_install; - iocfc->hwif.hw_msix_uninstall = bfa_hwct_msix_uninstall; - iocfc->hwif.hw_isr_mode_set = bfa_hwct_isr_mode_set; - iocfc->hwif.hw_msix_getvecs = bfa_hwct_msix_getvecs; - iocfc->hwif.hw_msix_get_rme_range = bfa_hwct_msix_get_rme_range; - iocfc->hwif.rme_vec_q0 = BFI_MSIX_RME_QMIN_CT; - iocfc->hwif.cpe_vec_q0 = BFI_MSIX_CPE_QMIN_CT; - } else { - iocfc->hwif.hw_reginit = bfa_hwcb_reginit; - iocfc->hwif.hw_reqq_ack = NULL; - iocfc->hwif.hw_rspq_ack = bfa_hwcb_rspq_ack; - iocfc->hwif.hw_msix_init = bfa_hwcb_msix_init; - iocfc->hwif.hw_msix_ctrl_install = bfa_hwcb_msix_ctrl_install; - iocfc->hwif.hw_msix_queue_install = bfa_hwcb_msix_queue_install; - iocfc->hwif.hw_msix_uninstall = bfa_hwcb_msix_uninstall; - iocfc->hwif.hw_isr_mode_set = bfa_hwcb_isr_mode_set; - iocfc->hwif.hw_msix_getvecs = bfa_hwcb_msix_getvecs; - iocfc->hwif.hw_msix_get_rme_range = bfa_hwcb_msix_get_rme_range; - iocfc->hwif.rme_vec_q0 = BFI_MSIX_RME_QMIN_CB + - bfa_ioc_pcifn(&bfa->ioc) * BFI_IOC_MAX_CQS; - iocfc->hwif.cpe_vec_q0 = BFI_MSIX_CPE_QMIN_CB + - bfa_ioc_pcifn(&bfa->ioc) * BFI_IOC_MAX_CQS; - } - - if (bfa_asic_id_ct2(bfa_ioc_devid(&bfa->ioc))) { - iocfc->hwif.hw_reginit = bfa_hwct2_reginit; - iocfc->hwif.hw_isr_mode_set = NULL; - iocfc->hwif.hw_rspq_ack = bfa_hwct2_rspq_ack; - } - - iocfc->hwif.hw_reginit(bfa); - bfa->msix.nvecs = 0; -} - -static void -bfa_iocfc_mem_claim(struct bfa_s *bfa, struct bfa_iocfc_cfg_s *cfg) -{ - u8 *dm_kva = NULL; - u64 dm_pa = 0; - int i, per_reqq_sz, per_rspq_sz, dbgsz; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfa_mem_dma_s *ioc_dma = BFA_MEM_IOC_DMA(bfa); - struct bfa_mem_dma_s *iocfc_dma = BFA_MEM_IOCFC_DMA(bfa); - struct bfa_mem_dma_s *reqq_dma, *rspq_dma; - - /* First allocate dma memory for IOC */ - bfa_ioc_mem_claim(&bfa->ioc, bfa_mem_dma_virt(ioc_dma), - bfa_mem_dma_phys(ioc_dma)); - - /* Claim DMA-able memory for the request/response queues */ - per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - reqq_dma = BFA_MEM_REQQ_DMA(bfa, i); - iocfc->req_cq_ba[i].kva = bfa_mem_dma_virt(reqq_dma); - iocfc->req_cq_ba[i].pa = bfa_mem_dma_phys(reqq_dma); - memset(iocfc->req_cq_ba[i].kva, 0, per_reqq_sz); - - rspq_dma = BFA_MEM_RSPQ_DMA(bfa, i); - iocfc->rsp_cq_ba[i].kva = bfa_mem_dma_virt(rspq_dma); - iocfc->rsp_cq_ba[i].pa = bfa_mem_dma_phys(rspq_dma); - memset(iocfc->rsp_cq_ba[i].kva, 0, per_rspq_sz); - } - - /* Claim IOCFC dma memory - for shadow CI/PI */ - dm_kva = bfa_mem_dma_virt(iocfc_dma); - dm_pa = bfa_mem_dma_phys(iocfc_dma); - - for (i = 0; i < cfg->fwcfg.num_cqs; i++) { - iocfc->req_cq_shadow_ci[i].kva = dm_kva; - iocfc->req_cq_shadow_ci[i].pa = dm_pa; - dm_kva += BFA_CACHELINE_SZ; - dm_pa += BFA_CACHELINE_SZ; - - iocfc->rsp_cq_shadow_pi[i].kva = dm_kva; - iocfc->rsp_cq_shadow_pi[i].pa = dm_pa; - dm_kva += BFA_CACHELINE_SZ; - dm_pa += BFA_CACHELINE_SZ; - } - - /* Claim IOCFC dma memory - for the config info page */ - bfa->iocfc.cfg_info.kva = dm_kva; - bfa->iocfc.cfg_info.pa = dm_pa; - bfa->iocfc.cfginfo = (struct bfi_iocfc_cfg_s *) dm_kva; - dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - - /* Claim IOCFC dma memory - for the config response */ - bfa->iocfc.cfgrsp_dma.kva = dm_kva; - bfa->iocfc.cfgrsp_dma.pa = dm_pa; - bfa->iocfc.cfgrsp = (struct bfi_iocfc_cfgrsp_s *) dm_kva; - dm_kva += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); - dm_pa += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); - - /* Claim IOCFC kva memory */ - dbgsz = (bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0; - if (dbgsz > 0) { - bfa_ioc_debug_memclaim(&bfa->ioc, bfa_mem_kva_curp(iocfc)); - bfa_mem_kva_curp(iocfc) += dbgsz; - } -} - -/* - * Start BFA submodules. - */ -static void -bfa_iocfc_start_submod(struct bfa_s *bfa) -{ - int i; - - bfa->queue_process = BFA_TRUE; - for (i = 0; i < BFI_IOC_MAX_CQS; i++) - bfa_isr_rspq_ack(bfa, i, bfa_rspq_ci(bfa, i)); - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->start(bfa); - - bfa->iocfc.submod_enabled = BFA_TRUE; -} - -/* - * Disable BFA submodules. - */ -static void -bfa_iocfc_disable_submod(struct bfa_s *bfa) -{ - int i; - - if (bfa->iocfc.submod_enabled == BFA_FALSE) - return; - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->iocdisable(bfa); - - bfa->iocfc.submod_enabled = BFA_FALSE; -} - -static void -bfa_iocfc_init_cb(void *bfa_arg, bfa_boolean_t complete) -{ - struct bfa_s *bfa = bfa_arg; - - if (complete) - bfa_cb_init(bfa->bfad, bfa->iocfc.op_status); -} - -static void -bfa_iocfc_stop_cb(void *bfa_arg, bfa_boolean_t compl) -{ - struct bfa_s *bfa = bfa_arg; - struct bfad_s *bfad = bfa->bfad; - - if (compl) - complete(&bfad->comp); -} - -static void -bfa_iocfc_enable_cb(void *bfa_arg, bfa_boolean_t compl) -{ - struct bfa_s *bfa = bfa_arg; - struct bfad_s *bfad = bfa->bfad; - - if (compl) - complete(&bfad->enable_comp); -} - -static void -bfa_iocfc_disable_cb(void *bfa_arg, bfa_boolean_t compl) -{ - struct bfa_s *bfa = bfa_arg; - struct bfad_s *bfad = bfa->bfad; - - if (compl) - complete(&bfad->disable_comp); -} - -/** - * configure queue registers from firmware response - */ -static void -bfa_iocfc_qreg(struct bfa_s *bfa, struct bfi_iocfc_qreg_s *qreg) -{ - int i; - struct bfa_iocfc_regs_s *r = &bfa->iocfc.bfa_regs; - void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - - for (i = 0; i < BFI_IOC_MAX_CQS; i++) { - bfa->iocfc.hw_qid[i] = qreg->hw_qid[i]; - r->cpe_q_ci[i] = kva + be32_to_cpu(qreg->cpe_q_ci_off[i]); - r->cpe_q_pi[i] = kva + be32_to_cpu(qreg->cpe_q_pi_off[i]); - r->cpe_q_ctrl[i] = kva + be32_to_cpu(qreg->cpe_qctl_off[i]); - r->rme_q_ci[i] = kva + be32_to_cpu(qreg->rme_q_ci_off[i]); - r->rme_q_pi[i] = kva + be32_to_cpu(qreg->rme_q_pi_off[i]); - r->rme_q_ctrl[i] = kva + be32_to_cpu(qreg->rme_qctl_off[i]); - } -} - -static void -bfa_iocfc_res_recfg(struct bfa_s *bfa, struct bfa_iocfc_fwcfg_s *fwcfg) -{ - bfa_fcxp_res_recfg(bfa, fwcfg->num_fcxp_reqs); - bfa_uf_res_recfg(bfa, fwcfg->num_uf_bufs); - bfa_rport_res_recfg(bfa, fwcfg->num_rports); - bfa_fcp_res_recfg(bfa, fwcfg->num_ioim_reqs); - bfa_tskim_res_recfg(bfa, fwcfg->num_tskim_reqs); -} - -/* - * Update BFA configuration from firmware configuration. - */ -static void -bfa_iocfc_cfgrsp(struct bfa_s *bfa) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - struct bfa_iocfc_fwcfg_s *fwcfg = &cfgrsp->fwcfg; - - fwcfg->num_cqs = fwcfg->num_cqs; - fwcfg->num_ioim_reqs = be16_to_cpu(fwcfg->num_ioim_reqs); - fwcfg->num_fwtio_reqs = be16_to_cpu(fwcfg->num_fwtio_reqs); - fwcfg->num_tskim_reqs = be16_to_cpu(fwcfg->num_tskim_reqs); - fwcfg->num_fcxp_reqs = be16_to_cpu(fwcfg->num_fcxp_reqs); - fwcfg->num_uf_bufs = be16_to_cpu(fwcfg->num_uf_bufs); - fwcfg->num_rports = be16_to_cpu(fwcfg->num_rports); - - /* - * configure queue register offsets as learnt from firmware - */ - bfa_iocfc_qreg(bfa, &cfgrsp->qreg); - - /* - * Re-configure resources as learnt from Firmware - */ - bfa_iocfc_res_recfg(bfa, fwcfg); - - /* - * Install MSIX queue handlers - */ - bfa_msix_queue_install(bfa); - - if (bfa->iocfc.cfgrsp->pbc_cfg.pbc_pwwn != 0) { - bfa->ioc.attr->pwwn = bfa->iocfc.cfgrsp->pbc_cfg.pbc_pwwn; - bfa->ioc.attr->nwwn = bfa->iocfc.cfgrsp->pbc_cfg.pbc_nwwn; - bfa_fsm_send_event(iocfc, IOCFC_E_CFG_DONE); - } -} - -void -bfa_iocfc_reset_queues(struct bfa_s *bfa) -{ - int q; - - for (q = 0; q < BFI_IOC_MAX_CQS; q++) { - bfa_reqq_ci(bfa, q) = 0; - bfa_reqq_pi(bfa, q) = 0; - bfa_rspq_ci(bfa, q) = 0; - bfa_rspq_pi(bfa, q) = 0; - } -} - -/* - * Process FAA pwwn msg from fw. - */ -static void -bfa_iocfc_process_faa_addr(struct bfa_s *bfa, struct bfi_faa_addr_msg_s *msg) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - - cfgrsp->pbc_cfg.pbc_pwwn = msg->pwwn; - cfgrsp->pbc_cfg.pbc_nwwn = msg->nwwn; - - bfa->ioc.attr->pwwn = msg->pwwn; - bfa->ioc.attr->nwwn = msg->nwwn; - bfa_fsm_send_event(iocfc, IOCFC_E_CFG_DONE); -} - -/* Fabric Assigned Address specific functions */ - -/* - * Check whether IOC is ready before sending command down - */ -static bfa_status_t -bfa_faa_validate_request(struct bfa_s *bfa) -{ - enum bfa_ioc_type_e ioc_type = bfa_get_type(bfa); - u32 card_type = bfa->ioc.attr->card_type; - - if (bfa_ioc_is_operational(&bfa->ioc)) { - if ((ioc_type != BFA_IOC_TYPE_FC) || bfa_mfg_is_mezz(card_type)) - return BFA_STATUS_FEATURE_NOT_SUPPORTED; - } else { - return BFA_STATUS_IOC_NON_OP; - } - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr, - bfa_cb_iocfc_t cbfn, void *cbarg) -{ - struct bfi_faa_query_s faa_attr_req; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - bfa_status_t status; - - iocfc->faa_args.faa_attr = attr; - iocfc->faa_args.faa_cb.faa_cbfn = cbfn; - iocfc->faa_args.faa_cb.faa_cbarg = cbarg; - - status = bfa_faa_validate_request(bfa); - if (status != BFA_STATUS_OK) - return status; - - if (iocfc->faa_args.busy == BFA_TRUE) - return BFA_STATUS_DEVBUSY; - - iocfc->faa_args.busy = BFA_TRUE; - memset(&faa_attr_req, 0, sizeof(struct bfi_faa_query_s)); - bfi_h2i_set(faa_attr_req.mh, BFI_MC_IOCFC, - BFI_IOCFC_H2I_FAA_QUERY_REQ, bfa_fn_lpu(bfa)); - - bfa_ioc_mbox_send(&bfa->ioc, &faa_attr_req, - sizeof(struct bfi_faa_query_s)); - - return BFA_STATUS_OK; -} - -/* - * FAA query response - */ -static void -bfa_faa_query_reply(struct bfa_iocfc_s *iocfc, - bfi_faa_query_rsp_t *rsp) -{ - void *cbarg = iocfc->faa_args.faa_cb.faa_cbarg; - - if (iocfc->faa_args.faa_attr) { - iocfc->faa_args.faa_attr->faa = rsp->faa; - iocfc->faa_args.faa_attr->faa_state = rsp->faa_status; - iocfc->faa_args.faa_attr->pwwn_source = rsp->addr_source; - } - - WARN_ON(!iocfc->faa_args.faa_cb.faa_cbfn); - - iocfc->faa_args.faa_cb.faa_cbfn(cbarg, BFA_STATUS_OK); - iocfc->faa_args.busy = BFA_FALSE; -} - -/* - * IOC enable request is complete - */ -static void -bfa_iocfc_enable_cbfn(void *bfa_arg, enum bfa_status status) -{ - struct bfa_s *bfa = bfa_arg; - - if (status == BFA_STATUS_OK) - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_IOC_ENABLED); - else - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_IOC_FAILED); -} - -/* - * IOC disable request is complete - */ -static void -bfa_iocfc_disable_cbfn(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_IOC_DISABLED); -} - -/* - * Notify sub-modules of hardware failure. - */ -static void -bfa_iocfc_hbfail_cbfn(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - - bfa->queue_process = BFA_FALSE; - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_IOC_FAILED); -} - -/* - * Actions on chip-reset completion. - */ -static void -bfa_iocfc_reset_cbfn(void *bfa_arg) -{ - struct bfa_s *bfa = bfa_arg; - - bfa_iocfc_reset_queues(bfa); - bfa_isr_enable(bfa); -} - -/* - * Query IOC memory requirement information. - */ -void -bfa_iocfc_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) -{ - int q, per_reqq_sz, per_rspq_sz; - struct bfa_mem_dma_s *ioc_dma = BFA_MEM_IOC_DMA(bfa); - struct bfa_mem_dma_s *iocfc_dma = BFA_MEM_IOCFC_DMA(bfa); - struct bfa_mem_kva_s *iocfc_kva = BFA_MEM_IOCFC_KVA(bfa); - u32 dm_len = 0; - - /* dma memory setup for IOC */ - bfa_mem_dma_setup(meminfo, ioc_dma, - BFA_ROUNDUP(sizeof(struct bfi_ioc_attr_s), BFA_DMA_ALIGN_SZ)); - - /* dma memory setup for REQ/RSP queues */ - per_reqq_sz = BFA_ROUNDUP((cfg->drvcfg.num_reqq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - per_rspq_sz = BFA_ROUNDUP((cfg->drvcfg.num_rspq_elems * BFI_LMSG_SZ), - BFA_DMA_ALIGN_SZ); - - for (q = 0; q < cfg->fwcfg.num_cqs; q++) { - bfa_mem_dma_setup(meminfo, BFA_MEM_REQQ_DMA(bfa, q), - per_reqq_sz); - bfa_mem_dma_setup(meminfo, BFA_MEM_RSPQ_DMA(bfa, q), - per_rspq_sz); - } - - /* IOCFC dma memory - calculate Shadow CI/PI size */ - for (q = 0; q < cfg->fwcfg.num_cqs; q++) - dm_len += (2 * BFA_CACHELINE_SZ); - - /* IOCFC dma memory - calculate config info / rsp size */ - dm_len += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfg_s), BFA_CACHELINE_SZ); - dm_len += BFA_ROUNDUP(sizeof(struct bfi_iocfc_cfgrsp_s), - BFA_CACHELINE_SZ); - - /* dma memory setup for IOCFC */ - bfa_mem_dma_setup(meminfo, iocfc_dma, dm_len); - - /* kva memory setup for IOCFC */ - bfa_mem_kva_setup(meminfo, iocfc_kva, - ((bfa_auto_recover) ? BFA_DBG_FWTRC_LEN : 0)); -} - -/* - * Query IOC memory requirement information. - */ -void -bfa_iocfc_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - int i; - struct bfa_ioc_s *ioc = &bfa->ioc; - - bfa_iocfc_cbfn.enable_cbfn = bfa_iocfc_enable_cbfn; - bfa_iocfc_cbfn.disable_cbfn = bfa_iocfc_disable_cbfn; - bfa_iocfc_cbfn.hbfail_cbfn = bfa_iocfc_hbfail_cbfn; - bfa_iocfc_cbfn.reset_cbfn = bfa_iocfc_reset_cbfn; - - ioc->trcmod = bfa->trcmod; - bfa_ioc_attach(&bfa->ioc, bfa, &bfa_iocfc_cbfn, &bfa->timer_mod); - - bfa_ioc_pci_init(&bfa->ioc, pcidev, BFI_PCIFN_CLASS_FC); - bfa_ioc_mbox_register(&bfa->ioc, bfa_mbox_isrs); - - bfa_iocfc_init_mem(bfa, bfad, cfg, pcidev); - bfa_iocfc_mem_claim(bfa, cfg); - INIT_LIST_HEAD(&bfa->timer_mod.timer_q); - - INIT_LIST_HEAD(&bfa->comp_q); - for (i = 0; i < BFI_IOC_MAX_CQS; i++) - INIT_LIST_HEAD(&bfa->reqq_waitq[i]); - - bfa->iocfc.cb_reqd = BFA_FALSE; - bfa->iocfc.op_status = BFA_STATUS_OK; - bfa->iocfc.submod_enabled = BFA_FALSE; - - bfa_fsm_set_state(&bfa->iocfc, bfa_iocfc_sm_stopped); -} - -/* - * Query IOC memory requirement information. - */ -void -bfa_iocfc_init(struct bfa_s *bfa) -{ - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_INIT); -} - -/* - * IOC start called from bfa_start(). Called to start IOC operations - * at driver instantiation for this instance. - */ -void -bfa_iocfc_start(struct bfa_s *bfa) -{ - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_START); -} - -/* - * IOC stop called from bfa_stop(). Called only when driver is unloaded - * for this instance. - */ -void -bfa_iocfc_stop(struct bfa_s *bfa) -{ - bfa->queue_process = BFA_FALSE; - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_STOP); -} - -void -bfa_iocfc_isr(void *bfaarg, struct bfi_mbmsg_s *m) -{ - struct bfa_s *bfa = bfaarg; - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - union bfi_iocfc_i2h_msg_u *msg; - - msg = (union bfi_iocfc_i2h_msg_u *) m; - bfa_trc(bfa, msg->mh.msg_id); - - switch (msg->mh.msg_id) { - case BFI_IOCFC_I2H_CFG_REPLY: - bfa_iocfc_cfgrsp(bfa); - break; - case BFI_IOCFC_I2H_UPDATEQ_RSP: - iocfc->updateq_cbfn(iocfc->updateq_cbarg, BFA_STATUS_OK); - break; - case BFI_IOCFC_I2H_ADDR_MSG: - bfa_iocfc_process_faa_addr(bfa, - (struct bfi_faa_addr_msg_s *)msg); - break; - case BFI_IOCFC_I2H_FAA_QUERY_RSP: - bfa_faa_query_reply(iocfc, (bfi_faa_query_rsp_t *)msg); - break; - default: - WARN_ON(1); - } -} - -void -bfa_iocfc_get_attr(struct bfa_s *bfa, struct bfa_iocfc_attr_s *attr) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - attr->intr_attr.coalesce = iocfc->cfginfo->intr_attr.coalesce; - - attr->intr_attr.delay = iocfc->cfginfo->intr_attr.delay ? - be16_to_cpu(iocfc->cfginfo->intr_attr.delay) : - be16_to_cpu(iocfc->cfgrsp->intr_attr.delay); - - attr->intr_attr.latency = iocfc->cfginfo->intr_attr.latency ? - be16_to_cpu(iocfc->cfginfo->intr_attr.latency) : - be16_to_cpu(iocfc->cfgrsp->intr_attr.latency); - - attr->config = iocfc->cfg; -} - -bfa_status_t -bfa_iocfc_israttr_set(struct bfa_s *bfa, struct bfa_iocfc_intr_attr_s *attr) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_set_intr_req_s *m; - - iocfc->cfginfo->intr_attr.coalesce = attr->coalesce; - iocfc->cfginfo->intr_attr.delay = cpu_to_be16(attr->delay); - iocfc->cfginfo->intr_attr.latency = cpu_to_be16(attr->latency); - - if (!bfa_iocfc_is_operational(bfa)) - return BFA_STATUS_OK; - - m = bfa_reqq_next(bfa, BFA_REQQ_IOC); - if (!m) - return BFA_STATUS_DEVBUSY; - - bfi_h2i_set(m->mh, BFI_MC_IOCFC, BFI_IOCFC_H2I_SET_INTR_REQ, - bfa_fn_lpu(bfa)); - m->coalesce = iocfc->cfginfo->intr_attr.coalesce; - m->delay = iocfc->cfginfo->intr_attr.delay; - m->latency = iocfc->cfginfo->intr_attr.latency; - - bfa_trc(bfa, attr->delay); - bfa_trc(bfa, attr->latency); - - bfa_reqq_produce(bfa, BFA_REQQ_IOC, m->mh); - return BFA_STATUS_OK; -} - -void -bfa_iocfc_set_snsbase(struct bfa_s *bfa, int seg_no, u64 snsbase_pa) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - - iocfc->cfginfo->sense_buf_len = (BFI_IOIM_SNSLEN - 1); - bfa_dma_be_addr_set(iocfc->cfginfo->ioim_snsbase[seg_no], snsbase_pa); -} -/* - * Enable IOC after it is disabled. - */ -void -bfa_iocfc_enable(struct bfa_s *bfa) -{ - bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, - "IOC Enable"); - bfa->iocfc.cb_reqd = BFA_TRUE; - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_ENABLE); -} - -void -bfa_iocfc_disable(struct bfa_s *bfa) -{ - bfa_plog_str(bfa->plog, BFA_PL_MID_HAL, BFA_PL_EID_MISC, 0, - "IOC Disable"); - - bfa->queue_process = BFA_FALSE; - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_DISABLE); -} - -bfa_boolean_t -bfa_iocfc_is_operational(struct bfa_s *bfa) -{ - return bfa_ioc_is_operational(&bfa->ioc) && - bfa_fsm_cmp_state(&bfa->iocfc, bfa_iocfc_sm_operational); -} - -/* - * Return boot target port wwns -- read from boot information in flash. - */ -void -bfa_iocfc_get_bootwwns(struct bfa_s *bfa, u8 *nwwns, wwn_t *wwns) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - int i; - - if (cfgrsp->pbc_cfg.boot_enabled && cfgrsp->pbc_cfg.nbluns) { - bfa_trc(bfa, cfgrsp->pbc_cfg.nbluns); - *nwwns = cfgrsp->pbc_cfg.nbluns; - for (i = 0; i < cfgrsp->pbc_cfg.nbluns; i++) - wwns[i] = cfgrsp->pbc_cfg.blun[i].tgt_pwwn; - - return; - } - - *nwwns = cfgrsp->bootwwns.nwwns; - memcpy(wwns, cfgrsp->bootwwns.wwn, sizeof(cfgrsp->bootwwns.wwn)); -} - -int -bfa_iocfc_get_pbc_vports(struct bfa_s *bfa, struct bfi_pbc_vport_s *pbc_vport) -{ - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - - memcpy(pbc_vport, cfgrsp->pbc_cfg.vport, sizeof(cfgrsp->pbc_cfg.vport)); - return cfgrsp->pbc_cfg.nvports; -} - - -/* - * Use this function query the memory requirement of the BFA library. - * This function needs to be called before bfa_attach() to get the - * memory required of the BFA layer for a given driver configuration. - * - * This call will fail, if the cap is out of range compared to pre-defined - * values within the BFA library - * - * @param[in] cfg - pointer to bfa_ioc_cfg_t. Driver layer should indicate - * its configuration in this structure. - * The default values for struct bfa_iocfc_cfg_s can be - * fetched using bfa_cfg_get_default() API. - * - * If cap's boundary check fails, the library will use - * the default bfa_cap_t values (and log a warning msg). - * - * @param[out] meminfo - pointer to bfa_meminfo_t. This content - * indicates the memory type (see bfa_mem_type_t) and - * amount of memory required. - * - * Driver should allocate the memory, populate the - * starting address for each block and provide the same - * structure as input parameter to bfa_attach() call. - * - * @param[in] bfa - pointer to the bfa structure, used while fetching the - * dma, kva memory information of the bfa sub-modules. - * - * @return void - * - * Special Considerations: @note - */ -void -bfa_cfg_get_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) -{ - int i; - struct bfa_mem_dma_s *port_dma = BFA_MEM_PORT_DMA(bfa); - struct bfa_mem_dma_s *ablk_dma = BFA_MEM_ABLK_DMA(bfa); - struct bfa_mem_dma_s *cee_dma = BFA_MEM_CEE_DMA(bfa); - struct bfa_mem_dma_s *sfp_dma = BFA_MEM_SFP_DMA(bfa); - struct bfa_mem_dma_s *flash_dma = BFA_MEM_FLASH_DMA(bfa); - struct bfa_mem_dma_s *diag_dma = BFA_MEM_DIAG_DMA(bfa); - struct bfa_mem_dma_s *phy_dma = BFA_MEM_PHY_DMA(bfa); - - WARN_ON((cfg == NULL) || (meminfo == NULL)); - - memset((void *)meminfo, 0, sizeof(struct bfa_meminfo_s)); - - /* Initialize the DMA & KVA meminfo queues */ - INIT_LIST_HEAD(&meminfo->dma_info.qe); - INIT_LIST_HEAD(&meminfo->kva_info.qe); - - bfa_iocfc_meminfo(cfg, meminfo, bfa); - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->meminfo(cfg, meminfo, bfa); - - /* dma info setup */ - bfa_mem_dma_setup(meminfo, port_dma, bfa_port_meminfo()); - bfa_mem_dma_setup(meminfo, ablk_dma, bfa_ablk_meminfo()); - bfa_mem_dma_setup(meminfo, cee_dma, bfa_cee_meminfo()); - bfa_mem_dma_setup(meminfo, sfp_dma, bfa_sfp_meminfo()); - bfa_mem_dma_setup(meminfo, flash_dma, - bfa_flash_meminfo(cfg->drvcfg.min_cfg)); - bfa_mem_dma_setup(meminfo, diag_dma, bfa_diag_meminfo()); - bfa_mem_dma_setup(meminfo, phy_dma, - bfa_phy_meminfo(cfg->drvcfg.min_cfg)); -} - -/* - * Use this function to do attach the driver instance with the BFA - * library. This function will not trigger any HW initialization - * process (which will be done in bfa_init() call) - * - * This call will fail, if the cap is out of range compared to - * pre-defined values within the BFA library - * - * @param[out] bfa Pointer to bfa_t. - * @param[in] bfad Opaque handle back to the driver's IOC structure - * @param[in] cfg Pointer to bfa_ioc_cfg_t. Should be same structure - * that was used in bfa_cfg_get_meminfo(). - * @param[in] meminfo Pointer to bfa_meminfo_t. The driver should - * use the bfa_cfg_get_meminfo() call to - * find the memory blocks required, allocate the - * required memory and provide the starting addresses. - * @param[in] pcidev pointer to struct bfa_pcidev_s - * - * @return - * void - * - * Special Considerations: - * - * @note - * - */ -void -bfa_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, struct bfa_pcidev_s *pcidev) -{ - int i; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; - - bfa->fcs = BFA_FALSE; - - WARN_ON((cfg == NULL) || (meminfo == NULL)); - - /* Initialize memory pointers for iterative allocation */ - dma_info = &meminfo->dma_info; - dma_info->kva_curp = dma_info->kva; - dma_info->dma_curp = dma_info->dma; - - kva_info = &meminfo->kva_info; - kva_info->kva_curp = kva_info->kva; - - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_elem->kva_curp = dma_elem->kva; - dma_elem->dma_curp = dma_elem->dma; - } - - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - kva_elem->kva_curp = kva_elem->kva; - } - - bfa_iocfc_attach(bfa, bfad, cfg, pcidev); - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->attach(bfa, bfad, cfg, pcidev); - - bfa_com_port_attach(bfa); - bfa_com_ablk_attach(bfa); - bfa_com_cee_attach(bfa); - bfa_com_sfp_attach(bfa); - bfa_com_flash_attach(bfa, cfg->drvcfg.min_cfg); - bfa_com_diag_attach(bfa); - bfa_com_phy_attach(bfa, cfg->drvcfg.min_cfg); -} - -/* - * Use this function to delete a BFA IOC. IOC should be stopped (by - * calling bfa_stop()) before this function call. - * - * @param[in] bfa - pointer to bfa_t. - * - * @return - * void - * - * Special Considerations: - * - * @note - */ -void -bfa_detach(struct bfa_s *bfa) -{ - int i; - - for (i = 0; hal_mods[i]; i++) - hal_mods[i]->detach(bfa); - bfa_ioc_detach(&bfa->ioc); -} - -void -bfa_comp_deq(struct bfa_s *bfa, struct list_head *comp_q) -{ - INIT_LIST_HEAD(comp_q); - list_splice_tail_init(&bfa->comp_q, comp_q); -} - -void -bfa_comp_process(struct bfa_s *bfa, struct list_head *comp_q) -{ - struct list_head *qe; - struct list_head *qen; - struct bfa_cb_qe_s *hcb_qe; - bfa_cb_cbfn_status_t cbfn; - - list_for_each_safe(qe, qen, comp_q) { - hcb_qe = (struct bfa_cb_qe_s *) qe; - if (hcb_qe->pre_rmv) { - /* qe is invalid after return, dequeue before cbfn() */ - list_del(qe); - cbfn = (bfa_cb_cbfn_status_t)(hcb_qe->cbfn); - cbfn(hcb_qe->cbarg, hcb_qe->fw_status); - } else - hcb_qe->cbfn(hcb_qe->cbarg, BFA_TRUE); - } -} - -void -bfa_comp_free(struct bfa_s *bfa, struct list_head *comp_q) -{ - struct list_head *qe; - struct bfa_cb_qe_s *hcb_qe; - - while (!list_empty(comp_q)) { - bfa_q_deq(comp_q, &qe); - hcb_qe = (struct bfa_cb_qe_s *) qe; - WARN_ON(hcb_qe->pre_rmv); - hcb_qe->cbfn(hcb_qe->cbarg, BFA_FALSE); - } -} - -/* - * Return the list of PCI vendor/device id lists supported by this - * BFA instance. - */ -void -bfa_get_pciids(struct bfa_pciid_s **pciids, int *npciids) -{ - static struct bfa_pciid_s __pciids[] = { - {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G2P}, - {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_FC_8G1P}, - {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT}, - {BFA_PCI_VENDOR_ID_BROCADE, BFA_PCI_DEVICE_ID_CT_FC}, - }; - - *npciids = sizeof(__pciids) / sizeof(__pciids[0]); - *pciids = __pciids; -} - -/* - * Use this function query the default struct bfa_iocfc_cfg_s value (compiled - * into BFA layer). The OS driver can then turn back and overwrite entries that - * have been configured by the user. - * - * @param[in] cfg - pointer to bfa_ioc_cfg_t - * - * @return - * void - * - * Special Considerations: - * note - */ -void -bfa_cfg_get_default(struct bfa_iocfc_cfg_s *cfg) -{ - cfg->fwcfg.num_fabrics = DEF_CFG_NUM_FABRICS; - cfg->fwcfg.num_lports = DEF_CFG_NUM_LPORTS; - cfg->fwcfg.num_rports = DEF_CFG_NUM_RPORTS; - cfg->fwcfg.num_ioim_reqs = DEF_CFG_NUM_IOIM_REQS; - cfg->fwcfg.num_tskim_reqs = DEF_CFG_NUM_TSKIM_REQS; - cfg->fwcfg.num_fcxp_reqs = DEF_CFG_NUM_FCXP_REQS; - cfg->fwcfg.num_uf_bufs = DEF_CFG_NUM_UF_BUFS; - cfg->fwcfg.num_cqs = DEF_CFG_NUM_CQS; - cfg->fwcfg.num_fwtio_reqs = 0; - - cfg->drvcfg.num_reqq_elems = DEF_CFG_NUM_REQQ_ELEMS; - cfg->drvcfg.num_rspq_elems = DEF_CFG_NUM_RSPQ_ELEMS; - cfg->drvcfg.num_sgpgs = DEF_CFG_NUM_SGPGS; - cfg->drvcfg.num_sboot_tgts = DEF_CFG_NUM_SBOOT_TGTS; - cfg->drvcfg.num_sboot_luns = DEF_CFG_NUM_SBOOT_LUNS; - cfg->drvcfg.path_tov = BFA_FCPIM_PATHTOV_DEF; - cfg->drvcfg.ioc_recover = BFA_FALSE; - cfg->drvcfg.delay_comp = BFA_FALSE; - -} - -void -bfa_cfg_get_min(struct bfa_iocfc_cfg_s *cfg) -{ - bfa_cfg_get_default(cfg); - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN; - cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN; - cfg->fwcfg.num_fcxp_reqs = BFA_FCXP_MIN; - cfg->fwcfg.num_uf_bufs = BFA_UF_MIN; - cfg->fwcfg.num_rports = BFA_RPORT_MIN; - cfg->fwcfg.num_fwtio_reqs = 0; - - cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; - cfg->drvcfg.num_reqq_elems = BFA_REQQ_NELEMS_MIN; - cfg->drvcfg.num_rspq_elems = BFA_RSPQ_NELEMS_MIN; - cfg->drvcfg.min_cfg = BFA_TRUE; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_cs.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_cs.h deleted file mode 100644 index 12bfeed2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_cs.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * bfa_cs.h BFA common services - */ - -#ifndef __BFA_CS_H__ -#define __BFA_CS_H__ - -#include "bfad_drv.h" - -/* - * BFA TRC - */ - -#ifndef BFA_TRC_MAX -#define BFA_TRC_MAX (4 * 1024) -#endif - -#define BFA_TRC_TS(_trcm) \ - ({ \ - struct timeval tv; \ - \ - do_gettimeofday(&tv); \ - (tv.tv_sec*1000000+tv.tv_usec); \ - }) - -#ifndef BFA_TRC_TS -#define BFA_TRC_TS(_trcm) ((_trcm)->ticks++) -#endif - -struct bfa_trc_s { -#ifdef __BIG_ENDIAN - u16 fileno; - u16 line; -#else - u16 line; - u16 fileno; -#endif - u32 timestamp; - union { - struct { - u32 rsvd; - u32 u32; - } u32; - u64 u64; - } data; -}; - -struct bfa_trc_mod_s { - u32 head; - u32 tail; - u32 ntrc; - u32 stopped; - u32 ticks; - u32 rsvd[3]; - struct bfa_trc_s trc[BFA_TRC_MAX]; -}; - -enum { - BFA_TRC_HAL = 1, /* BFA modules */ - BFA_TRC_FCS = 2, /* BFA FCS modules */ - BFA_TRC_LDRV = 3, /* Linux driver modules */ - BFA_TRC_CNA = 4, /* Common modules */ -}; -#define BFA_TRC_MOD_SH 10 -#define BFA_TRC_MOD(__mod) ((BFA_TRC_ ## __mod) << BFA_TRC_MOD_SH) - -/* - * Define a new tracing file (module). Module should match one defined above. - */ -#define BFA_TRC_FILE(__mod, __submod) \ - static int __trc_fileno = ((BFA_TRC_ ## __mod ## _ ## __submod) | \ - BFA_TRC_MOD(__mod)) - - -#define bfa_trc32(_trcp, _data) \ - __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u32)_data) -#define bfa_trc(_trcp, _data) \ - __bfa_trc((_trcp)->trcmod, __trc_fileno, __LINE__, (u64)_data) - -static inline void -bfa_trc_init(struct bfa_trc_mod_s *trcm) -{ - trcm->head = trcm->tail = trcm->stopped = 0; - trcm->ntrc = BFA_TRC_MAX; -} - -static inline void -bfa_trc_stop(struct bfa_trc_mod_s *trcm) -{ - trcm->stopped = 1; -} - -static inline void -__bfa_trc(struct bfa_trc_mod_s *trcm, int fileno, int line, u64 data) -{ - int tail = trcm->tail; - struct bfa_trc_s *trc = &trcm->trc[tail]; - - if (trcm->stopped) - return; - - trc->fileno = (u16) fileno; - trc->line = (u16) line; - trc->data.u64 = data; - trc->timestamp = BFA_TRC_TS(trcm); - - trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1); - if (trcm->tail == trcm->head) - trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1); -} - - -static inline void -__bfa_trc32(struct bfa_trc_mod_s *trcm, int fileno, int line, u32 data) -{ - int tail = trcm->tail; - struct bfa_trc_s *trc = &trcm->trc[tail]; - - if (trcm->stopped) - return; - - trc->fileno = (u16) fileno; - trc->line = (u16) line; - trc->data.u32.u32 = data; - trc->timestamp = BFA_TRC_TS(trcm); - - trcm->tail = (trcm->tail + 1) & (BFA_TRC_MAX - 1); - if (trcm->tail == trcm->head) - trcm->head = (trcm->head + 1) & (BFA_TRC_MAX - 1); -} - -#define bfa_sm_fault(__mod, __event) do { \ - bfa_trc(__mod, (((u32)0xDEAD << 16) | __event)); \ - printk(KERN_ERR "Assertion failure: %s:%d: %d", \ - __FILE__, __LINE__, (__event)); \ -} while (0) - -/* BFA queue definitions */ -#define bfa_q_first(_q) ((void *)(((struct list_head *) (_q))->next)) -#define bfa_q_next(_qe) (((struct list_head *) (_qe))->next) -#define bfa_q_prev(_qe) (((struct list_head *) (_qe))->prev) - -/* - * bfa_q_qe_init - to initialize a queue element - */ -#define bfa_q_qe_init(_qe) { \ - bfa_q_next(_qe) = (struct list_head *) NULL; \ - bfa_q_prev(_qe) = (struct list_head *) NULL; \ -} - -/* - * bfa_q_deq - dequeue an element from head of the queue - */ -#define bfa_q_deq(_q, _qe) { \ - if (!list_empty(_q)) { \ - (*((struct list_head **) (_qe))) = bfa_q_next(_q); \ - bfa_q_prev(bfa_q_next(*((struct list_head **) _qe))) = \ - (struct list_head *) (_q); \ - bfa_q_next(_q) = bfa_q_next(*((struct list_head **) _qe));\ - } else { \ - *((struct list_head **) (_qe)) = (struct list_head *) NULL;\ - } \ -} - -/* - * bfa_q_deq_tail - dequeue an element from tail of the queue - */ -#define bfa_q_deq_tail(_q, _qe) { \ - if (!list_empty(_q)) { \ - *((struct list_head **) (_qe)) = bfa_q_prev(_q); \ - bfa_q_next(bfa_q_prev(*((struct list_head **) _qe))) = \ - (struct list_head *) (_q); \ - bfa_q_prev(_q) = bfa_q_prev(*(struct list_head **) _qe);\ - } else { \ - *((struct list_head **) (_qe)) = (struct list_head *) NULL;\ - } \ -} - -static inline int -bfa_q_is_on_q_func(struct list_head *q, struct list_head *qe) -{ - struct list_head *tqe; - - tqe = bfa_q_next(q); - while (tqe != q) { - if (tqe == qe) - return 1; - tqe = bfa_q_next(tqe); - if (tqe == NULL) - break; - } - return 0; -} - -#define bfa_q_is_on_q(_q, _qe) \ - bfa_q_is_on_q_func(_q, (struct list_head *)(_qe)) - -/* - * @ BFA state machine interfaces - */ - -typedef void (*bfa_sm_t)(void *sm, int event); - -/* - * oc - object class eg. bfa_ioc - * st - state, eg. reset - * otype - object type, eg. struct bfa_ioc_s - * etype - object type, eg. enum ioc_event - */ -#define bfa_sm_state_decl(oc, st, otype, etype) \ - static void oc ## _sm_ ## st(otype * fsm, etype event) - -#define bfa_sm_set_state(_sm, _state) ((_sm)->sm = (bfa_sm_t)(_state)) -#define bfa_sm_send_event(_sm, _event) ((_sm)->sm((_sm), (_event))) -#define bfa_sm_get_state(_sm) ((_sm)->sm) -#define bfa_sm_cmp_state(_sm, _state) ((_sm)->sm == (bfa_sm_t)(_state)) - -/* - * For converting from state machine function to state encoding. - */ -struct bfa_sm_table_s { - bfa_sm_t sm; /* state machine function */ - int state; /* state machine encoding */ - char *name; /* state name for display */ -}; -#define BFA_SM(_sm) ((bfa_sm_t)(_sm)) - -/* - * State machine with entry actions. - */ -typedef void (*bfa_fsm_t)(void *fsm, int event); - -/* - * oc - object class eg. bfa_ioc - * st - state, eg. reset - * otype - object type, eg. struct bfa_ioc_s - * etype - object type, eg. enum ioc_event - */ -#define bfa_fsm_state_decl(oc, st, otype, etype) \ - static void oc ## _sm_ ## st(otype * fsm, etype event); \ - static void oc ## _sm_ ## st ## _entry(otype * fsm) - -#define bfa_fsm_set_state(_fsm, _state) do { \ - (_fsm)->fsm = (bfa_fsm_t)(_state); \ - _state ## _entry(_fsm); \ -} while (0) - -#define bfa_fsm_send_event(_fsm, _event) ((_fsm)->fsm((_fsm), (_event))) -#define bfa_fsm_get_state(_fsm) ((_fsm)->fsm) -#define bfa_fsm_cmp_state(_fsm, _state) \ - ((_fsm)->fsm == (bfa_fsm_t)(_state)) - -static inline int -bfa_sm_to_state(struct bfa_sm_table_s *smt, bfa_sm_t sm) -{ - int i = 0; - - while (smt[i].sm && smt[i].sm != sm) - i++; - return smt[i].state; -} - -/* - * @ Generic wait counter. - */ - -typedef void (*bfa_wc_resume_t) (void *cbarg); - -struct bfa_wc_s { - bfa_wc_resume_t wc_resume; - void *wc_cbarg; - int wc_count; -}; - -static inline void -bfa_wc_up(struct bfa_wc_s *wc) -{ - wc->wc_count++; -} - -static inline void -bfa_wc_down(struct bfa_wc_s *wc) -{ - wc->wc_count--; - if (wc->wc_count == 0) - wc->wc_resume(wc->wc_cbarg); -} - -/* - * Initialize a waiting counter. - */ -static inline void -bfa_wc_init(struct bfa_wc_s *wc, bfa_wc_resume_t wc_resume, void *wc_cbarg) -{ - wc->wc_resume = wc_resume; - wc->wc_cbarg = wc_cbarg; - wc->wc_count = 0; - bfa_wc_up(wc); -} - -/* - * Wait for counter to reach zero - */ -static inline void -bfa_wc_wait(struct bfa_wc_s *wc) -{ - bfa_wc_down(wc); -} - -static inline void -wwn2str(char *wwn_str, u64 wwn) -{ - union { - u64 wwn; - u8 byte[8]; - } w; - - w.wwn = wwn; - sprintf(wwn_str, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", w.byte[0], - w.byte[1], w.byte[2], w.byte[3], w.byte[4], w.byte[5], - w.byte[6], w.byte[7]); -} - -static inline void -fcid2str(char *fcid_str, u32 fcid) -{ - union { - u32 fcid; - u8 byte[4]; - } f; - - f.fcid = fcid; - sprintf(fcid_str, "%02x:%02x:%02x", f.byte[1], f.byte[2], f.byte[3]); -} - -#define bfa_swap_3b(_x) \ - ((((_x) & 0xff) << 16) | \ - ((_x) & 0x00ff00) | \ - (((_x) & 0xff0000) >> 16)) - -#ifndef __BIG_ENDIAN -#define bfa_hton3b(_x) bfa_swap_3b(_x) -#else -#define bfa_hton3b(_x) (_x) -#endif - -#define bfa_ntoh3b(_x) bfa_hton3b(_x) - -#endif /* __BFA_CS_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs.h deleted file mode 100644 index b5a1595c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs.h +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_H__ -#define __BFA_DEFS_H__ - -#include "bfa_fc.h" -#include "bfad_drv.h" - -#define BFA_MFG_SERIALNUM_SIZE 11 -#define STRSZ(_n) (((_n) + 4) & ~3) - -/* - * Manufacturing card type - */ -enum { - BFA_MFG_TYPE_CB_MAX = 825, /* Crossbow card type max */ - BFA_MFG_TYPE_FC8P2 = 825, /* 8G 2port FC card */ - BFA_MFG_TYPE_FC8P1 = 815, /* 8G 1port FC card */ - BFA_MFG_TYPE_FC4P2 = 425, /* 4G 2port FC card */ - BFA_MFG_TYPE_FC4P1 = 415, /* 4G 1port FC card */ - BFA_MFG_TYPE_CNA10P2 = 1020, /* 10G 2port CNA card */ - BFA_MFG_TYPE_CNA10P1 = 1010, /* 10G 1port CNA card */ - BFA_MFG_TYPE_JAYHAWK = 804, /* Jayhawk mezz card */ - BFA_MFG_TYPE_WANCHESE = 1007, /* Wanchese mezz card */ - BFA_MFG_TYPE_ASTRA = 807, /* Astra mezz card */ - BFA_MFG_TYPE_LIGHTNING_P0 = 902, /* Lightning mezz card - old */ - BFA_MFG_TYPE_LIGHTNING = 1741, /* Lightning mezz card */ - BFA_MFG_TYPE_PROWLER_F = 1560, /* Prowler FC only cards */ - BFA_MFG_TYPE_PROWLER_N = 1410, /* Prowler NIC only cards */ - BFA_MFG_TYPE_PROWLER_C = 1710, /* Prowler CNA only cards */ - BFA_MFG_TYPE_PROWLER_D = 1860, /* Prowler Dual cards */ - BFA_MFG_TYPE_CHINOOK = 1867, /* Chinook cards */ - BFA_MFG_TYPE_INVALID = 0, /* Invalid card type */ -}; - -#pragma pack(1) - -/* - * Check if Mezz card - */ -#define bfa_mfg_is_mezz(type) (( \ - (type) == BFA_MFG_TYPE_JAYHAWK || \ - (type) == BFA_MFG_TYPE_WANCHESE || \ - (type) == BFA_MFG_TYPE_ASTRA || \ - (type) == BFA_MFG_TYPE_LIGHTNING_P0 || \ - (type) == BFA_MFG_TYPE_LIGHTNING || \ - (type) == BFA_MFG_TYPE_CHINOOK)) - -/* - * Check if the card having old wwn/mac handling - */ -#define bfa_mfg_is_old_wwn_mac_model(type) (( \ - (type) == BFA_MFG_TYPE_FC8P2 || \ - (type) == BFA_MFG_TYPE_FC8P1 || \ - (type) == BFA_MFG_TYPE_FC4P2 || \ - (type) == BFA_MFG_TYPE_FC4P1 || \ - (type) == BFA_MFG_TYPE_CNA10P2 || \ - (type) == BFA_MFG_TYPE_CNA10P1 || \ - (type) == BFA_MFG_TYPE_JAYHAWK || \ - (type) == BFA_MFG_TYPE_WANCHESE)) - -#define bfa_mfg_increment_wwn_mac(m, i) \ -do { \ - u32 t = ((u32)(m)[0] << 16) | ((u32)(m)[1] << 8) | \ - (u32)(m)[2]; \ - t += (i); \ - (m)[0] = (t >> 16) & 0xFF; \ - (m)[1] = (t >> 8) & 0xFF; \ - (m)[2] = t & 0xFF; \ -} while (0) - -/* - * VPD data length - */ -#define BFA_MFG_VPD_LEN 512 - -/* - * VPD vendor tag - */ -enum { - BFA_MFG_VPD_UNKNOWN = 0, /* vendor unknown */ - BFA_MFG_VPD_IBM = 1, /* vendor IBM */ - BFA_MFG_VPD_HP = 2, /* vendor HP */ - BFA_MFG_VPD_DELL = 3, /* vendor DELL */ - BFA_MFG_VPD_PCI_IBM = 0x08, /* PCI VPD IBM */ - BFA_MFG_VPD_PCI_HP = 0x10, /* PCI VPD HP */ - BFA_MFG_VPD_PCI_DELL = 0x20, /* PCI VPD DELL */ - BFA_MFG_VPD_PCI_BRCD = 0xf8, /* PCI VPD Brocade */ -}; - -/* - * All numerical fields are in big-endian format. - */ -struct bfa_mfg_vpd_s { - u8 version; /* vpd data version */ - u8 vpd_sig[3]; /* characters 'V', 'P', 'D' */ - u8 chksum; /* u8 checksum */ - u8 vendor; /* vendor */ - u8 len; /* vpd data length excluding header */ - u8 rsv; - u8 data[BFA_MFG_VPD_LEN]; /* vpd data */ -}; - -#pragma pack() - -/* - * Status return values - */ -enum bfa_status { - BFA_STATUS_OK = 0, /* Success */ - BFA_STATUS_FAILED = 1, /* Operation failed */ - BFA_STATUS_EINVAL = 2, /* Invalid params Check input - * parameters */ - BFA_STATUS_ENOMEM = 3, /* Out of resources */ - BFA_STATUS_ETIMER = 5, /* Timer expired - Retry, if persists, - * contact support */ - BFA_STATUS_EPROTOCOL = 6, /* Protocol error */ - BFA_STATUS_SFP_UNSUPP = 10, /* Unsupported SFP - Replace SFP */ - BFA_STATUS_UNKNOWN_VFID = 11, /* VF_ID not found */ - BFA_STATUS_DATACORRUPTED = 12, /* Diag returned data corrupted */ - BFA_STATUS_DEVBUSY = 13, /* Device busy - Retry operation */ - BFA_STATUS_HDMA_FAILED = 16, /* Host dma failed contact support */ - BFA_STATUS_FLASH_BAD_LEN = 17, /* Flash bad length */ - BFA_STATUS_UNKNOWN_LWWN = 18, /* LPORT PWWN not found */ - BFA_STATUS_UNKNOWN_RWWN = 19, /* RPORT PWWN not found */ - BFA_STATUS_VPORT_EXISTS = 21, /* VPORT already exists */ - BFA_STATUS_VPORT_MAX = 22, /* Reached max VPORT supported limit */ - BFA_STATUS_UNSUPP_SPEED = 23, /* Invalid Speed Check speed setting */ - BFA_STATUS_INVLD_DFSZ = 24, /* Invalid Max data field size */ - BFA_STATUS_CMD_NOTSUPP = 26, /* Command/API not supported */ - BFA_STATUS_FABRIC_RJT = 29, /* Reject from attached fabric */ - BFA_STATUS_UNKNOWN_VWWN = 30, /* VPORT PWWN not found */ - BFA_STATUS_PORT_OFFLINE = 34, /* Port is not online */ - BFA_STATUS_VPORT_WWN_BP = 46, /* WWN is same as base port's WWN */ - BFA_STATUS_PORT_NOT_DISABLED = 47, /* Port not disabled disable port */ - BFA_STATUS_NO_FCPIM_NEXUS = 52, /* No FCP Nexus exists with the rport */ - BFA_STATUS_IOC_FAILURE = 56, /* IOC failure - Retry, if persists - * contact support */ - BFA_STATUS_INVALID_WWN = 57, /* Invalid WWN */ - BFA_STATUS_ADAPTER_ENABLED = 60, /* Adapter is not disabled */ - BFA_STATUS_IOC_NON_OP = 61, /* IOC is not operational */ - BFA_STATUS_VERSION_FAIL = 70, /* Application/Driver version mismatch */ - BFA_STATUS_DIAG_BUSY = 71, /* diag busy */ - BFA_STATUS_BEACON_ON = 72, /* Port Beacon already on */ - BFA_STATUS_ENOFSAVE = 78, /* No saved firmware trace */ - BFA_STATUS_IOC_DISABLED = 82, /* IOC is already disabled */ - BFA_STATUS_NO_SFP_DEV = 89, /* No SFP device check or replace SFP */ - BFA_STATUS_MEMTEST_FAILED = 90, /* Memory test failed contact support */ - BFA_STATUS_LEDTEST_OP = 109, /* LED test is operating */ - BFA_STATUS_INVALID_MAC = 134, /* Invalid MAC address */ - BFA_STATUS_PBC = 154, /* Operation not allowed for pre-boot - * configuration */ - BFA_STATUS_BAD_FWCFG = 156, /* Bad firmware configuration */ - BFA_STATUS_INVALID_VENDOR = 158, /* Invalid switch vendor */ - BFA_STATUS_SFP_NOT_READY = 159, /* SFP info is not ready. Retry */ - BFA_STATUS_TRUNK_ENABLED = 164, /* Trunk is already enabled on - * this adapter */ - BFA_STATUS_TRUNK_DISABLED = 165, /* Trunking is disabled on - * the adapter */ - BFA_STATUS_IOPROFILE_OFF = 175, /* IO profile OFF */ - BFA_STATUS_PHY_NOT_PRESENT = 183, /* PHY module not present */ - BFA_STATUS_FEATURE_NOT_SUPPORTED = 192, /* Feature not supported */ - BFA_STATUS_ENTRY_EXISTS = 193, /* Entry already exists */ - BFA_STATUS_ENTRY_NOT_EXISTS = 194, /* Entry does not exist */ - BFA_STATUS_NO_CHANGE = 195, /* Feature already in that state */ - BFA_STATUS_FAA_ENABLED = 197, /* FAA is already enabled */ - BFA_STATUS_FAA_DISABLED = 198, /* FAA is already disabled */ - BFA_STATUS_FAA_ACQUIRED = 199, /* FAA is already acquired */ - BFA_STATUS_FAA_ACQ_ADDR = 200, /* Acquiring addr */ - BFA_STATUS_ERROR_TRUNK_ENABLED = 203, /* Trunk enabled on adapter */ - BFA_STATUS_MAX_ENTRY_REACHED = 212, /* MAX entry reached */ - BFA_STATUS_MAX_VAL /* Unknown error code */ -}; -#define bfa_status_t enum bfa_status - -enum bfa_eproto_status { - BFA_EPROTO_BAD_ACCEPT = 0, - BFA_EPROTO_UNKNOWN_RSP = 1 -}; -#define bfa_eproto_status_t enum bfa_eproto_status - -enum bfa_boolean { - BFA_FALSE = 0, - BFA_TRUE = 1 -}; -#define bfa_boolean_t enum bfa_boolean - -#define BFA_STRING_32 32 -#define BFA_VERSION_LEN 64 - -/* - * ---------------------- adapter definitions ------------ - */ - -/* - * BFA adapter level attributes. - */ -enum { - BFA_ADAPTER_SERIAL_NUM_LEN = STRSZ(BFA_MFG_SERIALNUM_SIZE), - /* - *!< adapter serial num length - */ - BFA_ADAPTER_MODEL_NAME_LEN = 16, /* model name length */ - BFA_ADAPTER_MODEL_DESCR_LEN = 128, /* model description length */ - BFA_ADAPTER_MFG_NAME_LEN = 8, /* manufacturer name length */ - BFA_ADAPTER_SYM_NAME_LEN = 64, /* adapter symbolic name length */ - BFA_ADAPTER_OS_TYPE_LEN = 64, /* adapter os type length */ -}; - -struct bfa_adapter_attr_s { - char manufacturer[BFA_ADAPTER_MFG_NAME_LEN]; - char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; - u32 card_type; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; - wwn_t pwwn; - char node_symname[FC_SYMNAME_MAX]; - char hw_ver[BFA_VERSION_LEN]; - char fw_ver[BFA_VERSION_LEN]; - char optrom_ver[BFA_VERSION_LEN]; - char os_type[BFA_ADAPTER_OS_TYPE_LEN]; - struct bfa_mfg_vpd_s vpd; - struct mac_s mac; - - u8 nports; - u8 max_speed; - u8 prototype; - char asic_rev; - - u8 pcie_gen; - u8 pcie_lanes_orig; - u8 pcie_lanes; - u8 cna_capable; - - u8 is_mezz; - u8 trunk_capable; -}; - -/* - * ---------------------- IOC definitions ------------ - */ - -enum { - BFA_IOC_DRIVER_LEN = 16, - BFA_IOC_CHIP_REV_LEN = 8, -}; - -/* - * Driver and firmware versions. - */ -struct bfa_ioc_driver_attr_s { - char driver[BFA_IOC_DRIVER_LEN]; /* driver name */ - char driver_ver[BFA_VERSION_LEN]; /* driver version */ - char fw_ver[BFA_VERSION_LEN]; /* firmware version */ - char bios_ver[BFA_VERSION_LEN]; /* bios version */ - char efi_ver[BFA_VERSION_LEN]; /* EFI version */ - char ob_ver[BFA_VERSION_LEN]; /* openboot version */ -}; - -/* - * IOC PCI device attributes - */ -struct bfa_ioc_pci_attr_s { - u16 vendor_id; /* PCI vendor ID */ - u16 device_id; /* PCI device ID */ - u16 ssid; /* subsystem ID */ - u16 ssvid; /* subsystem vendor ID */ - u32 pcifn; /* PCI device function */ - u32 rsvd; /* padding */ - char chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */ -}; - -/* - * IOC states - */ -enum bfa_ioc_state { - BFA_IOC_UNINIT = 1, /* IOC is in uninit state */ - BFA_IOC_RESET = 2, /* IOC is in reset state */ - BFA_IOC_SEMWAIT = 3, /* Waiting for IOC h/w semaphore */ - BFA_IOC_HWINIT = 4, /* IOC h/w is being initialized */ - BFA_IOC_GETATTR = 5, /* IOC is being configured */ - BFA_IOC_OPERATIONAL = 6, /* IOC is operational */ - BFA_IOC_INITFAIL = 7, /* IOC hardware failure */ - BFA_IOC_FAIL = 8, /* IOC heart-beat failure */ - BFA_IOC_DISABLING = 9, /* IOC is being disabled */ - BFA_IOC_DISABLED = 10, /* IOC is disabled */ - BFA_IOC_FWMISMATCH = 11, /* IOC f/w different from drivers */ - BFA_IOC_ENABLING = 12, /* IOC is being enabled */ - BFA_IOC_HWFAIL = 13, /* PCI mapping doesn't exist */ - BFA_IOC_ACQ_ADDR = 14, /* Acquiring addr from fabric */ -}; - -/* - * IOC firmware stats - */ -struct bfa_fw_ioc_stats_s { - u32 enable_reqs; - u32 disable_reqs; - u32 get_attr_reqs; - u32 dbg_sync; - u32 dbg_dump; - u32 unknown_reqs; -}; - -/* - * IOC driver stats - */ -struct bfa_ioc_drv_stats_s { - u32 ioc_isrs; - u32 ioc_enables; - u32 ioc_disables; - u32 ioc_hbfails; - u32 ioc_boots; - u32 stats_tmos; - u32 hb_count; - u32 disable_reqs; - u32 enable_reqs; - u32 disable_replies; - u32 enable_replies; - u32 rsvd; -}; - -/* - * IOC statistics - */ -struct bfa_ioc_stats_s { - struct bfa_ioc_drv_stats_s drv_stats; /* driver IOC stats */ - struct bfa_fw_ioc_stats_s fw_stats; /* firmware IOC stats */ -}; - -enum bfa_ioc_type_e { - BFA_IOC_TYPE_FC = 1, - BFA_IOC_TYPE_FCoE = 2, - BFA_IOC_TYPE_LL = 3, -}; - -/* - * IOC attributes returned in queries - */ -struct bfa_ioc_attr_s { - enum bfa_ioc_type_e ioc_type; - enum bfa_ioc_state state; /* IOC state */ - struct bfa_adapter_attr_s adapter_attr; /* HBA attributes */ - struct bfa_ioc_driver_attr_s driver_attr; /* driver attr */ - struct bfa_ioc_pci_attr_s pci_attr; - u8 port_id; /* port number */ - u8 port_mode; /* bfa_mode_s */ - u8 cap_bm; /* capability */ - u8 port_mode_cfg; /* bfa_mode_s */ - u8 rsvd[4]; /* 64bit align */ -}; - -/* - * AEN related definitions - */ -enum bfa_aen_category { - BFA_AEN_CAT_ADAPTER = 1, - BFA_AEN_CAT_PORT = 2, - BFA_AEN_CAT_LPORT = 3, - BFA_AEN_CAT_RPORT = 4, - BFA_AEN_CAT_ITNIM = 5, - BFA_AEN_CAT_AUDIT = 8, - BFA_AEN_CAT_IOC = 9, -}; - -/* BFA adapter level events */ -enum bfa_adapter_aen_event { - BFA_ADAPTER_AEN_ADD = 1, /* New Adapter found event */ - BFA_ADAPTER_AEN_REMOVE = 2, /* Adapter removed event */ -}; - -struct bfa_adapter_aen_data_s { - char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; - u32 nports; /* Number of NPorts */ - wwn_t pwwn; /* WWN of one of its physical port */ -}; - -/* BFA physical port Level events */ -enum bfa_port_aen_event { - BFA_PORT_AEN_ONLINE = 1, /* Physical Port online event */ - BFA_PORT_AEN_OFFLINE = 2, /* Physical Port offline event */ - BFA_PORT_AEN_RLIR = 3, /* RLIR event, not supported */ - BFA_PORT_AEN_SFP_INSERT = 4, /* SFP inserted event */ - BFA_PORT_AEN_SFP_REMOVE = 5, /* SFP removed event */ - BFA_PORT_AEN_SFP_POM = 6, /* SFP POM event */ - BFA_PORT_AEN_ENABLE = 7, /* Physical Port enable event */ - BFA_PORT_AEN_DISABLE = 8, /* Physical Port disable event */ - BFA_PORT_AEN_AUTH_ON = 9, /* Physical Port auth success event */ - BFA_PORT_AEN_AUTH_OFF = 10, /* Physical Port auth fail event */ - BFA_PORT_AEN_DISCONNECT = 11, /* Physical Port disconnect event */ - BFA_PORT_AEN_QOS_NEG = 12, /* Base Port QOS negotiation event */ - BFA_PORT_AEN_FABRIC_NAME_CHANGE = 13, /* Fabric Name/WWN change */ - BFA_PORT_AEN_SFP_ACCESS_ERROR = 14, /* SFP read error event */ - BFA_PORT_AEN_SFP_UNSUPPORT = 15, /* Unsupported SFP event */ -}; - -enum bfa_port_aen_sfp_pom { - BFA_PORT_AEN_SFP_POM_GREEN = 1, /* Normal */ - BFA_PORT_AEN_SFP_POM_AMBER = 2, /* Warning */ - BFA_PORT_AEN_SFP_POM_RED = 3, /* Critical */ - BFA_PORT_AEN_SFP_POM_MAX = BFA_PORT_AEN_SFP_POM_RED -}; - -struct bfa_port_aen_data_s { - wwn_t pwwn; /* WWN of the physical port */ - wwn_t fwwn; /* WWN of the fabric port */ - u32 phy_port_num; /* For SFP related events */ - u16 ioc_type; - u16 level; /* Only transitions will be informed */ - mac_t mac; /* MAC address of the ethernet port */ - u16 rsvd; -}; - -/* BFA AEN logical port events */ -enum bfa_lport_aen_event { - BFA_LPORT_AEN_NEW = 1, /* LPort created event */ - BFA_LPORT_AEN_DELETE = 2, /* LPort deleted event */ - BFA_LPORT_AEN_ONLINE = 3, /* LPort online event */ - BFA_LPORT_AEN_OFFLINE = 4, /* LPort offline event */ - BFA_LPORT_AEN_DISCONNECT = 5, /* LPort disconnect event */ - BFA_LPORT_AEN_NEW_PROP = 6, /* VPort created event */ - BFA_LPORT_AEN_DELETE_PROP = 7, /* VPort deleted event */ - BFA_LPORT_AEN_NEW_STANDARD = 8, /* VPort created event */ - BFA_LPORT_AEN_DELETE_STANDARD = 9, /* VPort deleted event */ - BFA_LPORT_AEN_NPIV_DUP_WWN = 10, /* VPort with duplicate WWN */ - BFA_LPORT_AEN_NPIV_FABRIC_MAX = 11, /* Max NPIV in fabric/fport */ - BFA_LPORT_AEN_NPIV_UNKNOWN = 12, /* Unknown NPIV Error code */ -}; - -struct bfa_lport_aen_data_s { - u16 vf_id; /* vf_id of this logical port */ - u16 roles; /* Logical port mode,IM/TM/IP etc */ - u32 rsvd; - wwn_t ppwwn; /* WWN of its physical port */ - wwn_t lpwwn; /* WWN of this logical port */ -}; - -/* BFA ITNIM events */ -enum bfa_itnim_aen_event { - BFA_ITNIM_AEN_ONLINE = 1, /* Target online */ - BFA_ITNIM_AEN_OFFLINE = 2, /* Target offline */ - BFA_ITNIM_AEN_DISCONNECT = 3, /* Target disconnected */ -}; - -struct bfa_itnim_aen_data_s { - u16 vf_id; /* vf_id of the IT nexus */ - u16 rsvd[3]; - wwn_t ppwwn; /* WWN of its physical port */ - wwn_t lpwwn; /* WWN of logical port */ - wwn_t rpwwn; /* WWN of remote(target) port */ -}; - -/* BFA audit events */ -enum bfa_audit_aen_event { - BFA_AUDIT_AEN_AUTH_ENABLE = 1, - BFA_AUDIT_AEN_AUTH_DISABLE = 2, - BFA_AUDIT_AEN_FLASH_ERASE = 3, - BFA_AUDIT_AEN_FLASH_UPDATE = 4, -}; - -struct bfa_audit_aen_data_s { - wwn_t pwwn; - int partition_inst; - int partition_type; -}; - -/* BFA IOC level events */ -enum bfa_ioc_aen_event { - BFA_IOC_AEN_HBGOOD = 1, /* Heart Beat restore event */ - BFA_IOC_AEN_HBFAIL = 2, /* Heart Beat failure event */ - BFA_IOC_AEN_ENABLE = 3, /* IOC enabled event */ - BFA_IOC_AEN_DISABLE = 4, /* IOC disabled event */ - BFA_IOC_AEN_FWMISMATCH = 5, /* IOC firmware mismatch */ - BFA_IOC_AEN_FWCFG_ERROR = 6, /* IOC firmware config error */ - BFA_IOC_AEN_INVALID_VENDOR = 7, - BFA_IOC_AEN_INVALID_NWWN = 8, /* Zero NWWN */ - BFA_IOC_AEN_INVALID_PWWN = 9 /* Zero PWWN */ -}; - -struct bfa_ioc_aen_data_s { - wwn_t pwwn; - u16 ioc_type; - mac_t mac; -}; - -/* - * ---------------------- mfg definitions ------------ - */ - -/* - * Checksum size - */ -#define BFA_MFG_CHKSUM_SIZE 16 - -#define BFA_MFG_PARTNUM_SIZE 14 -#define BFA_MFG_SUPPLIER_ID_SIZE 10 -#define BFA_MFG_SUPPLIER_PARTNUM_SIZE 20 -#define BFA_MFG_SUPPLIER_SERIALNUM_SIZE 20 -#define BFA_MFG_SUPPLIER_REVISION_SIZE 4 -/* - * Initial capability definition - */ -#define BFA_MFG_IC_FC 0x01 -#define BFA_MFG_IC_ETH 0x02 - -/* - * Adapter capability mask definition - */ -#define BFA_CM_HBA 0x01 -#define BFA_CM_CNA 0x02 -#define BFA_CM_NIC 0x04 -#define BFA_CM_FC16G 0x08 -#define BFA_CM_SRIOV 0x10 -#define BFA_CM_MEZZ 0x20 - -#pragma pack(1) - -/* - * All numerical fields are in big-endian format. - */ -struct bfa_mfg_block_s { - u8 version; /*!< manufacturing block version */ - u8 mfg_sig[3]; /*!< characters 'M', 'F', 'G' */ - u16 mfgsize; /*!< mfg block size */ - u16 u16_chksum; /*!< old u16 checksum */ - char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; - char brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)]; - u8 mfg_day; /*!< manufacturing day */ - u8 mfg_month; /*!< manufacturing month */ - u16 mfg_year; /*!< manufacturing year */ - wwn_t mfg_wwn; /*!< wwn base for this adapter */ - u8 num_wwn; /*!< number of wwns assigned */ - u8 mfg_speeds; /*!< speeds allowed for this adapter */ - u8 rsv[2]; - char supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)]; - char supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)]; - char supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)]; - char supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)]; - mac_t mfg_mac; /*!< base mac address */ - u8 num_mac; /*!< number of mac addresses */ - u8 rsv2; - u32 card_type; /*!< card type */ - char cap_nic; /*!< capability nic */ - char cap_cna; /*!< capability cna */ - char cap_hba; /*!< capability hba */ - char cap_fc16g; /*!< capability fc 16g */ - char cap_sriov; /*!< capability sriov */ - char cap_mezz; /*!< capability mezz */ - u8 rsv3; - u8 mfg_nports; /*!< number of ports */ - char media[8]; /*!< xfi/xaui */ - char initial_mode[8]; /*!< initial mode: hba/cna/nic */ - u8 rsv4[84]; - u8 md5_chksum[BFA_MFG_CHKSUM_SIZE]; /*!< md5 checksum */ -}; - -#pragma pack() - -/* - * ---------------------- pci definitions ------------ - */ - -/* - * PCI device and vendor ID information - */ -enum { - BFA_PCI_VENDOR_ID_BROCADE = 0x1657, - BFA_PCI_DEVICE_ID_FC_8G2P = 0x13, - BFA_PCI_DEVICE_ID_FC_8G1P = 0x17, - BFA_PCI_DEVICE_ID_CT = 0x14, - BFA_PCI_DEVICE_ID_CT_FC = 0x21, - BFA_PCI_DEVICE_ID_CT2 = 0x22, -}; - -#define bfa_asic_id_cb(__d) \ - ((__d) == BFA_PCI_DEVICE_ID_FC_8G2P || \ - (__d) == BFA_PCI_DEVICE_ID_FC_8G1P) -#define bfa_asic_id_ct(__d) \ - ((__d) == BFA_PCI_DEVICE_ID_CT || \ - (__d) == BFA_PCI_DEVICE_ID_CT_FC) -#define bfa_asic_id_ct2(__d) ((__d) == BFA_PCI_DEVICE_ID_CT2) -#define bfa_asic_id_ctc(__d) \ - (bfa_asic_id_ct(__d) || bfa_asic_id_ct2(__d)) - -/* - * PCI sub-system device and vendor ID information - */ -enum { - BFA_PCI_FCOE_SSDEVICE_ID = 0x14, - BFA_PCI_CT2_SSID_FCoE = 0x22, - BFA_PCI_CT2_SSID_ETH = 0x23, - BFA_PCI_CT2_SSID_FC = 0x24, -}; - -/* - * Maximum number of device address ranges mapped through different BAR(s) - */ -#define BFA_PCI_ACCESS_RANGES 1 - -/* - * Port speed settings. Each specific speed is a bit field. Use multiple - * bits to specify speeds to be selected for auto-negotiation. - */ -enum bfa_port_speed { - BFA_PORT_SPEED_UNKNOWN = 0, - BFA_PORT_SPEED_1GBPS = 1, - BFA_PORT_SPEED_2GBPS = 2, - BFA_PORT_SPEED_4GBPS = 4, - BFA_PORT_SPEED_8GBPS = 8, - BFA_PORT_SPEED_10GBPS = 10, - BFA_PORT_SPEED_16GBPS = 16, - BFA_PORT_SPEED_AUTO = 0xf, -}; -#define bfa_port_speed_t enum bfa_port_speed - -enum { - BFA_BOOT_BOOTLUN_MAX = 4, /* maximum boot lun per IOC */ - BFA_PREBOOT_BOOTLUN_MAX = 8, /* maximum preboot lun per IOC */ -}; - -#define BOOT_CFG_REV1 1 -#define BOOT_CFG_VLAN 1 - -/* - * Boot options setting. Boot options setting determines from where - * to get the boot lun information - */ -enum bfa_boot_bootopt { - BFA_BOOT_AUTO_DISCOVER = 0, /* Boot from blun provided by fabric */ - BFA_BOOT_STORED_BLUN = 1, /* Boot from bluns stored in flash */ - BFA_BOOT_FIRST_LUN = 2, /* Boot from first discovered blun */ - BFA_BOOT_PBC = 3, /* Boot from pbc configured blun */ -}; - -#pragma pack(1) -/* - * Boot lun information. - */ -struct bfa_boot_bootlun_s { - wwn_t pwwn; /* port wwn of target */ - struct scsi_lun lun; /* 64-bit lun */ -}; -#pragma pack() - -/* - * BOOT boot configuraton - */ -struct bfa_boot_cfg_s { - u8 version; - u8 rsvd1; - u16 chksum; - u8 enable; /* enable/disable SAN boot */ - u8 speed; /* boot speed settings */ - u8 topology; /* boot topology setting */ - u8 bootopt; /* bfa_boot_bootopt_t */ - u32 nbluns; /* number of boot luns */ - u32 rsvd2; - struct bfa_boot_bootlun_s blun[BFA_BOOT_BOOTLUN_MAX]; - struct bfa_boot_bootlun_s blun_disc[BFA_BOOT_BOOTLUN_MAX]; -}; - -struct bfa_boot_pbc_s { - u8 enable; /* enable/disable SAN boot */ - u8 speed; /* boot speed settings */ - u8 topology; /* boot topology setting */ - u8 rsvd1; - u32 nbluns; /* number of boot luns */ - struct bfa_boot_bootlun_s pblun[BFA_PREBOOT_BOOTLUN_MAX]; -}; - -struct bfa_ethboot_cfg_s { - u8 version; - u8 rsvd1; - u16 chksum; - u8 enable; /* enable/disable Eth/PXE boot */ - u8 rsvd2; - u16 vlan; -}; - -/* - * ASIC block configuration related structures - */ -#define BFA_ABLK_MAX_PORTS 2 -#define BFA_ABLK_MAX_PFS 16 -#define BFA_ABLK_MAX 2 - -#pragma pack(1) -enum bfa_mode_s { - BFA_MODE_HBA = 1, - BFA_MODE_CNA = 2, - BFA_MODE_NIC = 3 -}; - -struct bfa_adapter_cfg_mode_s { - u16 max_pf; - u16 max_vf; - enum bfa_mode_s mode; -}; - -struct bfa_ablk_cfg_pf_s { - u16 pers; - u8 port_id; - u8 optrom; - u8 valid; - u8 sriov; - u8 max_vfs; - u8 rsvd[1]; - u16 num_qpairs; - u16 num_vectors; - u32 bw; -}; - -struct bfa_ablk_cfg_port_s { - u8 mode; - u8 type; - u8 max_pfs; - u8 rsvd[5]; -}; - -struct bfa_ablk_cfg_inst_s { - u8 nports; - u8 max_pfs; - u8 rsvd[6]; - struct bfa_ablk_cfg_pf_s pf_cfg[BFA_ABLK_MAX_PFS]; - struct bfa_ablk_cfg_port_s port_cfg[BFA_ABLK_MAX_PORTS]; -}; - -struct bfa_ablk_cfg_s { - struct bfa_ablk_cfg_inst_s inst[BFA_ABLK_MAX]; -}; - - -/* - * SFP module specific - */ -#define SFP_DIAGMON_SIZE 10 /* num bytes of diag monitor data */ - -/* SFP state change notification event */ -#define BFA_SFP_SCN_REMOVED 0 -#define BFA_SFP_SCN_INSERTED 1 -#define BFA_SFP_SCN_POM 2 -#define BFA_SFP_SCN_FAILED 3 -#define BFA_SFP_SCN_UNSUPPORT 4 -#define BFA_SFP_SCN_VALID 5 - -enum bfa_defs_sfp_media_e { - BFA_SFP_MEDIA_UNKNOWN = 0x00, - BFA_SFP_MEDIA_CU = 0x01, - BFA_SFP_MEDIA_LW = 0x02, - BFA_SFP_MEDIA_SW = 0x03, - BFA_SFP_MEDIA_EL = 0x04, - BFA_SFP_MEDIA_UNSUPPORT = 0x05, -}; - -/* - * values for xmtr_tech above - */ -enum { - SFP_XMTR_TECH_CU = (1 << 0), /* copper FC-BaseT */ - SFP_XMTR_TECH_CP = (1 << 1), /* copper passive */ - SFP_XMTR_TECH_CA = (1 << 2), /* copper active */ - SFP_XMTR_TECH_LL = (1 << 3), /* longwave laser */ - SFP_XMTR_TECH_SL = (1 << 4), /* shortwave laser w/ OFC */ - SFP_XMTR_TECH_SN = (1 << 5), /* shortwave laser w/o OFC */ - SFP_XMTR_TECH_EL_INTRA = (1 << 6), /* elec intra-enclosure */ - SFP_XMTR_TECH_EL_INTER = (1 << 7), /* elec inter-enclosure */ - SFP_XMTR_TECH_LC = (1 << 8), /* longwave laser */ - SFP_XMTR_TECH_SA = (1 << 9) -}; - -/* - * Serial ID: Data Fields -- Address A0h - * Basic ID field total 64 bytes - */ -struct sfp_srlid_base_s { - u8 id; /* 00: Identifier */ - u8 extid; /* 01: Extended Identifier */ - u8 connector; /* 02: Connector */ - u8 xcvr[8]; /* 03-10: Transceiver */ - u8 encoding; /* 11: Encoding */ - u8 br_norm; /* 12: BR, Nominal */ - u8 rate_id; /* 13: Rate Identifier */ - u8 len_km; /* 14: Length single mode km */ - u8 len_100m; /* 15: Length single mode 100m */ - u8 len_om2; /* 16: Length om2 fiber 10m */ - u8 len_om1; /* 17: Length om1 fiber 10m */ - u8 len_cu; /* 18: Length copper 1m */ - u8 len_om3; /* 19: Length om3 fiber 10m */ - u8 vendor_name[16];/* 20-35 */ - u8 unalloc1; - u8 vendor_oui[3]; /* 37-39 */ - u8 vendor_pn[16]; /* 40-55 */ - u8 vendor_rev[4]; /* 56-59 */ - u8 wavelen[2]; /* 60-61 */ - u8 unalloc2; - u8 cc_base; /* 63: check code for base id field */ -}; - -/* - * Serial ID: Data Fields -- Address A0h - * Extended id field total 32 bytes - */ -struct sfp_srlid_ext_s { - u8 options[2]; - u8 br_max; - u8 br_min; - u8 vendor_sn[16]; - u8 date_code[8]; - u8 diag_mon_type; /* 92: Diagnostic Monitoring type */ - u8 en_options; - u8 sff_8472; - u8 cc_ext; -}; - -/* - * Diagnostic: Data Fields -- Address A2h - * Diagnostic and control/status base field total 96 bytes - */ -struct sfp_diag_base_s { - /* - * Alarm and warning Thresholds 40 bytes - */ - u8 temp_high_alarm[2]; /* 00-01 */ - u8 temp_low_alarm[2]; /* 02-03 */ - u8 temp_high_warning[2]; /* 04-05 */ - u8 temp_low_warning[2]; /* 06-07 */ - - u8 volt_high_alarm[2]; /* 08-09 */ - u8 volt_low_alarm[2]; /* 10-11 */ - u8 volt_high_warning[2]; /* 12-13 */ - u8 volt_low_warning[2]; /* 14-15 */ - - u8 bias_high_alarm[2]; /* 16-17 */ - u8 bias_low_alarm[2]; /* 18-19 */ - u8 bias_high_warning[2]; /* 20-21 */ - u8 bias_low_warning[2]; /* 22-23 */ - - u8 tx_pwr_high_alarm[2]; /* 24-25 */ - u8 tx_pwr_low_alarm[2]; /* 26-27 */ - u8 tx_pwr_high_warning[2]; /* 28-29 */ - u8 tx_pwr_low_warning[2]; /* 30-31 */ - - u8 rx_pwr_high_alarm[2]; /* 32-33 */ - u8 rx_pwr_low_alarm[2]; /* 34-35 */ - u8 rx_pwr_high_warning[2]; /* 36-37 */ - u8 rx_pwr_low_warning[2]; /* 38-39 */ - - u8 unallocate_1[16]; - - /* - * ext_cal_const[36] - */ - u8 rx_pwr[20]; - u8 tx_i[4]; - u8 tx_pwr[4]; - u8 temp[4]; - u8 volt[4]; - u8 unallocate_2[3]; - u8 cc_dmi; -}; - -/* - * Diagnostic: Data Fields -- Address A2h - * Diagnostic and control/status extended field total 24 bytes - */ -struct sfp_diag_ext_s { - u8 diag[SFP_DIAGMON_SIZE]; - u8 unalloc1[4]; - u8 status_ctl; - u8 rsvd; - u8 alarm_flags[2]; - u8 unalloc2[2]; - u8 warning_flags[2]; - u8 ext_status_ctl[2]; -}; - -struct sfp_mem_s { - struct sfp_srlid_base_s srlid_base; - struct sfp_srlid_ext_s srlid_ext; - struct sfp_diag_base_s diag_base; - struct sfp_diag_ext_s diag_ext; -}; - -/* - * transceiver codes (SFF-8472 Rev 10.2 Table 3.5) - */ -union sfp_xcvr_e10g_code_u { - u8 b; - struct { -#ifdef __BIG_ENDIAN - u8 e10g_unall:1; /* 10G Ethernet compliance */ - u8 e10g_lrm:1; - u8 e10g_lr:1; - u8 e10g_sr:1; - u8 ib_sx:1; /* Infiniband compliance */ - u8 ib_lx:1; - u8 ib_cu_a:1; - u8 ib_cu_p:1; -#else - u8 ib_cu_p:1; - u8 ib_cu_a:1; - u8 ib_lx:1; - u8 ib_sx:1; /* Infiniband compliance */ - u8 e10g_sr:1; - u8 e10g_lr:1; - u8 e10g_lrm:1; - u8 e10g_unall:1; /* 10G Ethernet compliance */ -#endif - } r; -}; - -union sfp_xcvr_so1_code_u { - u8 b; - struct { - u8 escon:2; /* ESCON compliance code */ - u8 oc192_reach:1; /* SONET compliance code */ - u8 so_reach:2; - u8 oc48_reach:3; - } r; -}; - -union sfp_xcvr_so2_code_u { - u8 b; - struct { - u8 reserved:1; - u8 oc12_reach:3; /* OC12 reach */ - u8 reserved1:1; - u8 oc3_reach:3; /* OC3 reach */ - } r; -}; - -union sfp_xcvr_eth_code_u { - u8 b; - struct { - u8 base_px:1; - u8 base_bx10:1; - u8 e100base_fx:1; - u8 e100base_lx:1; - u8 e1000base_t:1; - u8 e1000base_cx:1; - u8 e1000base_lx:1; - u8 e1000base_sx:1; - } r; -}; - -struct sfp_xcvr_fc1_code_s { - u8 link_len:5; /* FC link length */ - u8 xmtr_tech2:3; - u8 xmtr_tech1:7; /* FC transmitter technology */ - u8 reserved1:1; -}; - -union sfp_xcvr_fc2_code_u { - u8 b; - struct { - u8 tw_media:1; /* twin axial pair (tw) */ - u8 tp_media:1; /* shielded twisted pair (sp) */ - u8 mi_media:1; /* miniature coax (mi) */ - u8 tv_media:1; /* video coax (tv) */ - u8 m6_media:1; /* multimode, 62.5m (m6) */ - u8 m5_media:1; /* multimode, 50m (m5) */ - u8 reserved:1; - u8 sm_media:1; /* single mode (sm) */ - } r; -}; - -union sfp_xcvr_fc3_code_u { - u8 b; - struct { -#ifdef __BIG_ENDIAN - u8 rsv4:1; - u8 mb800:1; /* 800 Mbytes/sec */ - u8 mb1600:1; /* 1600 Mbytes/sec */ - u8 mb400:1; /* 400 Mbytes/sec */ - u8 rsv2:1; - u8 mb200:1; /* 200 Mbytes/sec */ - u8 rsv1:1; - u8 mb100:1; /* 100 Mbytes/sec */ -#else - u8 mb100:1; /* 100 Mbytes/sec */ - u8 rsv1:1; - u8 mb200:1; /* 200 Mbytes/sec */ - u8 rsv2:1; - u8 mb400:1; /* 400 Mbytes/sec */ - u8 mb1600:1; /* 1600 Mbytes/sec */ - u8 mb800:1; /* 800 Mbytes/sec */ - u8 rsv4:1; -#endif - } r; -}; - -struct sfp_xcvr_s { - union sfp_xcvr_e10g_code_u e10g; - union sfp_xcvr_so1_code_u so1; - union sfp_xcvr_so2_code_u so2; - union sfp_xcvr_eth_code_u eth; - struct sfp_xcvr_fc1_code_s fc1; - union sfp_xcvr_fc2_code_u fc2; - union sfp_xcvr_fc3_code_u fc3; -}; - -/* - * Flash module specific - */ -#define BFA_FLASH_PART_ENTRY_SIZE 32 /* partition entry size */ -#define BFA_FLASH_PART_MAX 32 /* maximal # of partitions */ - -enum bfa_flash_part_type { - BFA_FLASH_PART_OPTROM = 1, /* option rom partition */ - BFA_FLASH_PART_FWIMG = 2, /* firmware image partition */ - BFA_FLASH_PART_FWCFG = 3, /* firmware tuneable config */ - BFA_FLASH_PART_DRV = 4, /* IOC driver config */ - BFA_FLASH_PART_BOOT = 5, /* boot config */ - BFA_FLASH_PART_ASIC = 6, /* asic bootstrap configuration */ - BFA_FLASH_PART_MFG = 7, /* manufacturing block partition */ - BFA_FLASH_PART_OPTROM2 = 8, /* 2nd option rom partition */ - BFA_FLASH_PART_VPD = 9, /* vpd data of OEM info */ - BFA_FLASH_PART_PBC = 10, /* pre-boot config */ - BFA_FLASH_PART_BOOTOVL = 11, /* boot overlay partition */ - BFA_FLASH_PART_LOG = 12, /* firmware log partition */ - BFA_FLASH_PART_PXECFG = 13, /* pxe boot config partition */ - BFA_FLASH_PART_PXEOVL = 14, /* pxe boot overlay partition */ - BFA_FLASH_PART_PORTCFG = 15, /* port cfg partition */ - BFA_FLASH_PART_ASICBK = 16, /* asic backup partition */ -}; - -/* - * flash partition attributes - */ -struct bfa_flash_part_attr_s { - u32 part_type; /* partition type */ - u32 part_instance; /* partition instance */ - u32 part_off; /* partition offset */ - u32 part_size; /* partition size */ - u32 part_len; /* partition content length */ - u32 part_status; /* partition status */ - char rsv[BFA_FLASH_PART_ENTRY_SIZE - 24]; -}; - -/* - * flash attributes - */ -struct bfa_flash_attr_s { - u32 status; /* flash overall status */ - u32 npart; /* num of partitions */ - struct bfa_flash_part_attr_s part[BFA_FLASH_PART_MAX]; -}; - -/* - * DIAG module specific - */ -#define LB_PATTERN_DEFAULT 0xB5B5B5B5 -#define QTEST_CNT_DEFAULT 10 -#define QTEST_PAT_DEFAULT LB_PATTERN_DEFAULT - -struct bfa_diag_memtest_s { - u8 algo; - u8 rsvd[7]; -}; - -struct bfa_diag_memtest_result { - u32 status; - u32 addr; - u32 exp; /* expect value read from reg */ - u32 act; /* actually value read */ - u32 err_status; /* error status reg */ - u32 err_status1; /* extra error info reg */ - u32 err_addr; /* error address reg */ - u8 algo; - u8 rsv[3]; -}; - -struct bfa_diag_loopback_result_s { - u32 numtxmfrm; /* no. of transmit frame */ - u32 numosffrm; /* no. of outstanding frame */ - u32 numrcvfrm; /* no. of received good frame */ - u32 badfrminf; /* mis-match info */ - u32 badfrmnum; /* mis-match fram number */ - u8 status; /* loopback test result */ - u8 rsvd[3]; -}; - -struct bfa_diag_ledtest_s { - u32 cmd; /* bfa_led_op_t */ - u32 color; /* bfa_led_color_t */ - u16 freq; /* no. of blinks every 10 secs */ - u8 led; /* bitmap of LEDs to be tested */ - u8 rsvd[5]; -}; - -struct bfa_diag_loopback_s { - u32 loopcnt; - u32 pattern; - u8 lb_mode; /* bfa_port_opmode_t */ - u8 speed; /* bfa_port_speed_t */ - u8 rsvd[2]; -}; - -/* - * PHY module specific - */ -enum bfa_phy_status_e { - BFA_PHY_STATUS_GOOD = 0, /* phy is good */ - BFA_PHY_STATUS_NOT_PRESENT = 1, /* phy does not exist */ - BFA_PHY_STATUS_BAD = 2, /* phy is bad */ -}; - -/* - * phy attributes for phy query - */ -struct bfa_phy_attr_s { - u32 status; /* phy present/absent status */ - u32 length; /* firmware length */ - u32 fw_ver; /* firmware version */ - u32 an_status; /* AN status */ - u32 pma_pmd_status; /* PMA/PMD link status */ - u32 pma_pmd_signal; /* PMA/PMD signal detect */ - u32 pcs_status; /* PCS link status */ -}; - -/* - * phy stats - */ -struct bfa_phy_stats_s { - u32 status; /* phy stats status */ - u32 link_breaks; /* Num of link breaks after linkup */ - u32 pma_pmd_fault; /* NPMA/PMD fault */ - u32 pcs_fault; /* PCS fault */ - u32 speed_neg; /* Num of speed negotiation */ - u32 tx_eq_training; /* Num of TX EQ training */ - u32 tx_eq_timeout; /* Num of TX EQ timeout */ - u32 crc_error; /* Num of CRC errors */ -}; - -#pragma pack() - -#endif /* __BFA_DEFS_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_fcs.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_fcs.h deleted file mode 100644 index 3bbc583f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_fcs.h +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_FCS_H__ -#define __BFA_DEFS_FCS_H__ - -#include "bfa_fc.h" -#include "bfa_defs_svc.h" - -/* - * VF states - */ -enum bfa_vf_state { - BFA_VF_UNINIT = 0, /* fabric is not yet initialized */ - BFA_VF_LINK_DOWN = 1, /* link is down */ - BFA_VF_FLOGI = 2, /* flogi is in progress */ - BFA_VF_AUTH = 3, /* authentication in progress */ - BFA_VF_NOFABRIC = 4, /* fabric is not present */ - BFA_VF_ONLINE = 5, /* login to fabric is complete */ - BFA_VF_EVFP = 6, /* EVFP is in progress */ - BFA_VF_ISOLATED = 7, /* port isolated due to vf_id mismatch */ -}; - -/* - * VF statistics - */ -struct bfa_vf_stats_s { - u32 flogi_sent; /* Num FLOGIs sent */ - u32 flogi_rsp_err; /* FLOGI response errors */ - u32 flogi_acc_err; /* FLOGI accept errors */ - u32 flogi_accepts; /* FLOGI accepts received */ - u32 flogi_rejects; /* FLOGI rejects received */ - u32 flogi_unknown_rsp; /* Unknown responses for FLOGI */ - u32 flogi_alloc_wait; /* Allocation waits prior to sending FLOGI */ - u32 flogi_rcvd; /* FLOGIs received */ - u32 flogi_rejected; /* Incoming FLOGIs rejected */ - u32 fabric_onlines; /* Internal fabric online notification sent - * to other modules */ - u32 fabric_offlines; /* Internal fabric offline notification sent - * to other modules */ - u32 resvd; /* padding for 64 bit alignment */ -}; - -/* - * VF attributes returned in queries - */ -struct bfa_vf_attr_s { - enum bfa_vf_state state; /* VF state */ - u32 rsvd; - wwn_t fabric_name; /* fabric name */ -}; - -#define BFA_FCS_MAX_LPORTS 256 -#define BFA_FCS_FABRIC_IPADDR_SZ 16 - -/* - * symbolic names for base port/virtual port - */ -#define BFA_SYMNAME_MAXLEN 128 /* 128 bytes */ -struct bfa_lport_symname_s { - char symname[BFA_SYMNAME_MAXLEN]; -}; - -/* -* Roles of FCS port: - * - FCP IM and FCP TM roles cannot be enabled together for a FCS port - * - Create multiple ports if both IM and TM functions required. - * - Atleast one role must be specified. - */ -enum bfa_lport_role { - BFA_LPORT_ROLE_FCP_IM = 0x01, /* FCP initiator role */ - BFA_LPORT_ROLE_FCP_MAX = BFA_LPORT_ROLE_FCP_IM, -}; - -/* - * FCS port configuration. - */ -struct bfa_lport_cfg_s { - wwn_t pwwn; /* port wwn */ - wwn_t nwwn; /* node wwn */ - struct bfa_lport_symname_s sym_name; /* vm port symbolic name */ - enum bfa_lport_role roles; /* FCS port roles */ - u32 rsvd; - bfa_boolean_t preboot_vp; /* vport created from PBC */ - u8 tag[16]; /* opaque tag from application */ - u8 padding[4]; -}; - -/* - * FCS port states - */ -enum bfa_lport_state { - BFA_LPORT_UNINIT = 0, /* PORT is not yet initialized */ - BFA_LPORT_FDISC = 1, /* FDISC is in progress */ - BFA_LPORT_ONLINE = 2, /* login to fabric is complete */ - BFA_LPORT_OFFLINE = 3, /* No login to fabric */ -}; - -/* - * FCS port type. - */ -enum bfa_lport_type { - BFA_LPORT_TYPE_PHYSICAL = 0, - BFA_LPORT_TYPE_VIRTUAL, -}; - -/* - * FCS port offline reason. - */ -enum bfa_lport_offline_reason { - BFA_LPORT_OFFLINE_UNKNOWN = 0, - BFA_LPORT_OFFLINE_LINKDOWN, - BFA_LPORT_OFFLINE_FAB_UNSUPPORTED, /* NPIV not supported by the - * fabric */ - BFA_LPORT_OFFLINE_FAB_NORESOURCES, - BFA_LPORT_OFFLINE_FAB_LOGOUT, -}; - -/* - * FCS lport info. - */ -struct bfa_lport_info_s { - u8 port_type; /* bfa_lport_type_t : physical or - * virtual */ - u8 port_state; /* one of bfa_lport_state values */ - u8 offline_reason; /* one of bfa_lport_offline_reason_t - * values */ - wwn_t port_wwn; - wwn_t node_wwn; - - /* - * following 4 feilds are valid for Physical Ports only - */ - u32 max_vports_supp; /* Max supported vports */ - u32 num_vports_inuse; /* Num of in use vports */ - u32 max_rports_supp; /* Max supported rports */ - u32 num_rports_inuse; /* Num of doscovered rports */ - -}; - -/* - * FCS port statistics - */ -struct bfa_lport_stats_s { - u32 ns_plogi_sent; - u32 ns_plogi_rsp_err; - u32 ns_plogi_acc_err; - u32 ns_plogi_accepts; - u32 ns_rejects; /* NS command rejects */ - u32 ns_plogi_unknown_rsp; - u32 ns_plogi_alloc_wait; - - u32 ns_retries; /* NS command retries */ - u32 ns_timeouts; /* NS command timeouts */ - - u32 ns_rspnid_sent; - u32 ns_rspnid_accepts; - u32 ns_rspnid_rsp_err; - u32 ns_rspnid_rejects; - u32 ns_rspnid_alloc_wait; - - u32 ns_rftid_sent; - u32 ns_rftid_accepts; - u32 ns_rftid_rsp_err; - u32 ns_rftid_rejects; - u32 ns_rftid_alloc_wait; - - u32 ns_rffid_sent; - u32 ns_rffid_accepts; - u32 ns_rffid_rsp_err; - u32 ns_rffid_rejects; - u32 ns_rffid_alloc_wait; - - u32 ns_gidft_sent; - u32 ns_gidft_accepts; - u32 ns_gidft_rsp_err; - u32 ns_gidft_rejects; - u32 ns_gidft_unknown_rsp; - u32 ns_gidft_alloc_wait; - - /* - * Mgmt Server stats - */ - u32 ms_retries; /* MS command retries */ - u32 ms_timeouts; /* MS command timeouts */ - u32 ms_plogi_sent; - u32 ms_plogi_rsp_err; - u32 ms_plogi_acc_err; - u32 ms_plogi_accepts; - u32 ms_rejects; /* MS command rejects */ - u32 ms_plogi_unknown_rsp; - u32 ms_plogi_alloc_wait; - - u32 num_rscn; /* Num of RSCN received */ - u32 num_portid_rscn;/* Num portid format RSCN - * received */ - - u32 uf_recvs; /* Unsolicited recv frames */ - u32 uf_recv_drops; /* Dropped received frames */ - - u32 plogi_rcvd; /* Received plogi */ - u32 prli_rcvd; /* Received prli */ - u32 adisc_rcvd; /* Received adisc */ - u32 prlo_rcvd; /* Received prlo */ - u32 logo_rcvd; /* Received logo */ - u32 rpsc_rcvd; /* Received rpsc */ - u32 un_handled_els_rcvd; /* Received unhandled ELS */ - u32 rport_plogi_timeouts; /* Rport plogi retry timeout count */ - u32 rport_del_max_plogi_retry; /* Deleted rport - * (max retry of plogi) */ -}; - -/* - * BFA port attribute returned in queries - */ -struct bfa_lport_attr_s { - enum bfa_lport_state state; /* port state */ - u32 pid; /* port ID */ - struct bfa_lport_cfg_s port_cfg; /* port configuration */ - enum bfa_port_type port_type; /* current topology */ - u32 loopback; /* cable is externally looped back */ - wwn_t fabric_name; /* attached switch's nwwn */ - u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; /* attached - * fabric's ip addr */ - mac_t fpma_mac; /* Lport's FPMA Mac address */ - u16 authfail; /* auth failed state */ -}; - - -/* - * VPORT states - */ -enum bfa_vport_state { - BFA_FCS_VPORT_UNINIT = 0, - BFA_FCS_VPORT_CREATED = 1, - BFA_FCS_VPORT_OFFLINE = 1, - BFA_FCS_VPORT_FDISC_SEND = 2, - BFA_FCS_VPORT_FDISC = 3, - BFA_FCS_VPORT_FDISC_RETRY = 4, - BFA_FCS_VPORT_FDISC_RSP_WAIT = 5, - BFA_FCS_VPORT_ONLINE = 6, - BFA_FCS_VPORT_DELETING = 7, - BFA_FCS_VPORT_CLEANUP = 8, - BFA_FCS_VPORT_LOGO_SEND = 9, - BFA_FCS_VPORT_LOGO = 10, - BFA_FCS_VPORT_ERROR = 11, - BFA_FCS_VPORT_MAX_STATE, -}; - -/* - * vport statistics - */ -struct bfa_vport_stats_s { - struct bfa_lport_stats_s port_stats; /* base class (port) stats */ - /* - * TODO - remove - */ - - u32 fdisc_sent; /* num fdisc sent */ - u32 fdisc_accepts; /* fdisc accepts */ - u32 fdisc_retries; /* fdisc retries */ - u32 fdisc_timeouts; /* fdisc timeouts */ - u32 fdisc_rsp_err; /* fdisc response error */ - u32 fdisc_acc_bad; /* bad fdisc accepts */ - u32 fdisc_rejects; /* fdisc rejects */ - u32 fdisc_unknown_rsp; - /* - *!< fdisc rsp unknown error - */ - u32 fdisc_alloc_wait;/* fdisc req (fcxp)alloc wait */ - - u32 logo_alloc_wait;/* logo req (fcxp) alloc wait */ - u32 logo_sent; /* logo sent */ - u32 logo_accepts; /* logo accepts */ - u32 logo_rejects; /* logo rejects */ - u32 logo_rsp_err; /* logo rsp errors */ - u32 logo_unknown_rsp; - /* logo rsp unknown errors */ - - u32 fab_no_npiv; /* fabric does not support npiv */ - - u32 fab_offline; /* offline events from fab SM */ - u32 fab_online; /* online events from fab SM */ - u32 fab_cleanup; /* cleanup request from fab SM */ - u32 rsvd; -}; - -/* - * BFA vport attribute returned in queries - */ -struct bfa_vport_attr_s { - struct bfa_lport_attr_s port_attr; /* base class (port) attributes */ - enum bfa_vport_state vport_state; /* vport state */ - u32 rsvd; -}; - -/* - * FCS remote port states - */ -enum bfa_rport_state { - BFA_RPORT_UNINIT = 0, /* PORT is not yet initialized */ - BFA_RPORT_OFFLINE = 1, /* rport is offline */ - BFA_RPORT_PLOGI = 2, /* PLOGI to rport is in progress */ - BFA_RPORT_ONLINE = 3, /* login to rport is complete */ - BFA_RPORT_PLOGI_RETRY = 4, /* retrying login to rport */ - BFA_RPORT_NSQUERY = 5, /* nameserver query */ - BFA_RPORT_ADISC = 6, /* ADISC authentication */ - BFA_RPORT_LOGO = 7, /* logging out with rport */ - BFA_RPORT_LOGORCV = 8, /* handling LOGO from rport */ - BFA_RPORT_NSDISC = 9, /* re-discover rport */ -}; - -/* - * Rport Scsi Function : Initiator/Target. - */ -enum bfa_rport_function { - BFA_RPORT_INITIATOR = 0x01, /* SCSI Initiator */ - BFA_RPORT_TARGET = 0x02, /* SCSI Target */ -}; - -/* - * port/node symbolic names for rport - */ -#define BFA_RPORT_SYMNAME_MAXLEN 255 -struct bfa_rport_symname_s { - char symname[BFA_RPORT_SYMNAME_MAXLEN]; -}; - -/* - * FCS remote port statistics - */ -struct bfa_rport_stats_s { - u32 offlines; /* remote port offline count */ - u32 onlines; /* remote port online count */ - u32 rscns; /* RSCN affecting rport */ - u32 plogis; /* plogis sent */ - u32 plogi_accs; /* plogi accepts */ - u32 plogi_timeouts; /* plogi timeouts */ - u32 plogi_rejects; /* rcvd plogi rejects */ - u32 plogi_failed; /* local failure */ - u32 plogi_rcvd; /* plogis rcvd */ - u32 prli_rcvd; /* inbound PRLIs */ - u32 adisc_rcvd; /* ADISCs received */ - u32 adisc_rejects; /* recvd ADISC rejects */ - u32 adisc_sent; /* ADISC requests sent */ - u32 adisc_accs; /* ADISC accepted by rport */ - u32 adisc_failed; /* ADISC failed (no response) */ - u32 adisc_rejected; /* ADISC rejected by us */ - u32 logos; /* logos sent */ - u32 logo_accs; /* LOGO accepts from rport */ - u32 logo_failed; /* LOGO failures */ - u32 logo_rejected; /* LOGO rejects from rport */ - u32 logo_rcvd; /* LOGO from remote port */ - - u32 rpsc_rcvd; /* RPSC received */ - u32 rpsc_rejects; /* recvd RPSC rejects */ - u32 rpsc_sent; /* RPSC requests sent */ - u32 rpsc_accs; /* RPSC accepted by rport */ - u32 rpsc_failed; /* RPSC failed (no response) */ - u32 rpsc_rejected; /* RPSC rejected by us */ - - u32 rjt_insuff_res; /* LS RJT with insuff resources */ - struct bfa_rport_hal_stats_s hal_stats; /* BFA rport stats */ -}; - -/* - * FCS remote port attributes returned in queries - */ -struct bfa_rport_attr_s { - wwn_t nwwn; /* node wwn */ - wwn_t pwwn; /* port wwn */ - enum fc_cos cos_supported; /* supported class of services */ - u32 pid; /* port ID */ - u32 df_sz; /* Max payload size */ - enum bfa_rport_state state; /* Rport State machine state */ - enum fc_cos fc_cos; /* FC classes of services */ - bfa_boolean_t cisc; /* CISC capable device */ - struct bfa_rport_symname_s symname; /* Symbolic Name */ - enum bfa_rport_function scsi_function; /* Initiator/Target */ - struct bfa_rport_qos_attr_s qos_attr; /* qos attributes */ - enum bfa_port_speed curr_speed; /* operating speed got from - * RPSC ELS. UNKNOWN, if RPSC - * is not supported */ - bfa_boolean_t trl_enforced; /* TRL enforced ? TRUE/FALSE */ - enum bfa_port_speed assigned_speed; /* Speed assigned by the user. - * will be used if RPSC is not - * supported by the rport */ -}; - -struct bfa_rport_remote_link_stats_s { - u32 lfc; /* Link Failure Count */ - u32 lsyc; /* Loss of Synchronization Count */ - u32 lsic; /* Loss of Signal Count */ - u32 pspec; /* Primitive Sequence Protocol Error Count */ - u32 itwc; /* Invalid Transmission Word Count */ - u32 icc; /* Invalid CRC Count */ -}; - - -#define BFA_MAX_IO_INDEX 7 -#define BFA_NO_IO_INDEX 9 - -/* - * FCS itnim states - */ -enum bfa_itnim_state { - BFA_ITNIM_OFFLINE = 0, /* offline */ - BFA_ITNIM_PRLI_SEND = 1, /* prli send */ - BFA_ITNIM_PRLI_SENT = 2, /* prli sent */ - BFA_ITNIM_PRLI_RETRY = 3, /* prli retry */ - BFA_ITNIM_HCB_ONLINE = 4, /* online callback */ - BFA_ITNIM_ONLINE = 5, /* online */ - BFA_ITNIM_HCB_OFFLINE = 6, /* offline callback */ - BFA_ITNIM_INITIATIOR = 7, /* initiator */ -}; - -/* - * FCS remote port statistics - */ -struct bfa_itnim_stats_s { - u32 onlines; /* num rport online */ - u32 offlines; /* num rport offline */ - u32 prli_sent; /* num prli sent out */ - u32 fcxp_alloc_wait;/* num fcxp alloc waits */ - u32 prli_rsp_err; /* num prli rsp errors */ - u32 prli_rsp_acc; /* num prli rsp accepts */ - u32 initiator; /* rport is an initiator */ - u32 prli_rsp_parse_err; /* prli rsp parsing errors */ - u32 prli_rsp_rjt; /* num prli rsp rejects */ - u32 timeout; /* num timeouts detected */ - u32 sler; /* num sler notification from BFA */ - u32 rsvd; /* padding for 64 bit alignment */ -}; - -/* - * FCS itnim attributes returned in queries - */ -struct bfa_itnim_attr_s { - enum bfa_itnim_state state; /* FCS itnim state */ - u8 retry; /* data retransmision support */ - u8 task_retry_id; /* task retry ident support */ - u8 rec_support; /* REC supported */ - u8 conf_comp; /* confirmed completion supp */ -}; - -#endif /* __BFA_DEFS_FCS_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_svc.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_svc.h deleted file mode 100644 index 36756ce0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_defs_svc.h +++ /dev/null @@ -1,1328 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_DEFS_SVC_H__ -#define __BFA_DEFS_SVC_H__ - -#include "bfa_defs.h" -#include "bfa_fc.h" -#include "bfi.h" - -#define BFA_IOCFC_INTR_DELAY 1125 -#define BFA_IOCFC_INTR_LATENCY 225 -#define BFA_IOCFCOE_INTR_DELAY 25 -#define BFA_IOCFCOE_INTR_LATENCY 5 - -/* - * Interrupt coalescing configuration. - */ -#pragma pack(1) -struct bfa_iocfc_intr_attr_s { - u8 coalesce; /* enable/disable coalescing */ - u8 rsvd[3]; - __be16 latency; /* latency in microseconds */ - __be16 delay; /* delay in microseconds */ -}; - -/* - * IOC firmware configuraton - */ -struct bfa_iocfc_fwcfg_s { - u16 num_fabrics; /* number of fabrics */ - u16 num_lports; /* number of local lports */ - u16 num_rports; /* number of remote ports */ - u16 num_ioim_reqs; /* number of IO reqs */ - u16 num_tskim_reqs; /* task management requests */ - u16 num_fwtio_reqs; /* number of TM IO reqs in FW */ - u16 num_fcxp_reqs; /* unassisted FC exchanges */ - u16 num_uf_bufs; /* unsolicited recv buffers */ - u8 num_cqs; - u8 fw_tick_res; /* FW clock resolution in ms */ - u8 rsvd[6]; -}; -#pragma pack() - -struct bfa_iocfc_drvcfg_s { - u16 num_reqq_elems; /* number of req queue elements */ - u16 num_rspq_elems; /* number of rsp queue elements */ - u16 num_sgpgs; /* number of total SG pages */ - u16 num_sboot_tgts; /* number of SAN boot targets */ - u16 num_sboot_luns; /* number of SAN boot luns */ - u16 ioc_recover; /* IOC recovery mode */ - u16 min_cfg; /* minimum configuration */ - u16 path_tov; /* device path timeout */ - u16 num_tio_reqs; /* number of TM IO reqs */ - u8 port_mode; - u8 rsvd_a; - bfa_boolean_t delay_comp; /* delay completion of failed - * inflight IOs */ - u16 num_ttsk_reqs; /* TM task management requests */ - u32 rsvd; -}; - -/* - * IOC configuration - */ -struct bfa_iocfc_cfg_s { - struct bfa_iocfc_fwcfg_s fwcfg; /* firmware side config */ - struct bfa_iocfc_drvcfg_s drvcfg; /* driver side config */ -}; - -/* - * IOC firmware IO stats - */ -struct bfa_fw_ioim_stats_s { - u32 host_abort; /* IO aborted by host driver*/ - u32 host_cleanup; /* IO clean up by host driver */ - - u32 fw_io_timeout; /* IOs timedout */ - u32 fw_frm_parse; /* frame parsed by f/w */ - u32 fw_frm_data; /* fcp_data frame parsed by f/w */ - u32 fw_frm_rsp; /* fcp_rsp frame parsed by f/w */ - u32 fw_frm_xfer_rdy; /* xfer_rdy frame parsed by f/w */ - u32 fw_frm_bls_acc; /* BLS ACC frame parsed by f/w */ - u32 fw_frm_tgt_abort; /* target ABTS parsed by f/w */ - u32 fw_frm_unknown; /* unknown parsed by f/w */ - u32 fw_data_dma; /* f/w DMA'ed the data frame */ - u32 fw_frm_drop; /* f/w drop the frame */ - - u32 rec_timeout; /* FW rec timed out */ - u32 error_rec; /* FW sending rec on - * an error condition*/ - u32 wait_for_si; /* FW wait for SI */ - u32 rec_rsp_inval; /* REC rsp invalid */ - u32 seqr_io_abort; /* target does not know cmd so abort */ - u32 seqr_io_retry; /* SEQR failed so retry IO */ - - u32 itn_cisc_upd_rsp; /* ITN cisc updated on fcp_rsp */ - u32 itn_cisc_upd_data; /* ITN cisc updated on fcp_data */ - u32 itn_cisc_upd_xfer_rdy; /* ITN cisc updated on fcp_data */ - - u32 fcp_data_lost; /* fcp data lost */ - - u32 ro_set_in_xfer_rdy; /* Target set RO in Xfer_rdy frame */ - u32 xfer_rdy_ooo_err; /* Out of order Xfer_rdy received */ - u32 xfer_rdy_unknown_err; /* unknown error in xfer_rdy frame */ - - u32 io_abort_timeout; /* ABTS timedout */ - u32 sler_initiated; /* SLER initiated */ - - u32 unexp_fcp_rsp; /* fcp response in wrong state */ - - u32 fcp_rsp_under_run; /* fcp rsp IO underrun */ - u32 fcp_rsp_under_run_wr; /* fcp rsp IO underrun for write */ - u32 fcp_rsp_under_run_err; /* fcp rsp IO underrun error */ - u32 fcp_rsp_resid_inval; /* invalid residue */ - u32 fcp_rsp_over_run; /* fcp rsp IO overrun */ - u32 fcp_rsp_over_run_err; /* fcp rsp IO overrun error */ - u32 fcp_rsp_proto_err; /* protocol error in fcp rsp */ - u32 fcp_rsp_sense_err; /* error in sense info in fcp rsp */ - u32 fcp_conf_req; /* FCP conf requested */ - - u32 tgt_aborted_io; /* target initiated abort */ - - u32 ioh_edtov_timeout_event;/* IOH edtov timer popped */ - u32 ioh_fcp_rsp_excp_event; /* IOH FCP_RSP exception */ - u32 ioh_fcp_conf_event; /* IOH FCP_CONF */ - u32 ioh_mult_frm_rsp_event; /* IOH multi_frame FCP_RSP */ - u32 ioh_hit_class2_event; /* IOH hit class2 */ - u32 ioh_miss_other_event; /* IOH miss other */ - u32 ioh_seq_cnt_err_event; /* IOH seq cnt error */ - u32 ioh_len_err_event; /* IOH len error - fcp_dl != - * bytes xfered */ - u32 ioh_seq_len_err_event; /* IOH seq len error */ - u32 ioh_data_oor_event; /* Data out of range */ - u32 ioh_ro_ooo_event; /* Relative offset out of range */ - u32 ioh_cpu_owned_event; /* IOH hit -iost owned by f/w */ - u32 ioh_unexp_frame_event; /* unexpected frame received - * count */ - u32 ioh_err_int; /* IOH error int during data-phase - * for scsi write */ -}; - -struct bfa_fw_tio_stats_s { - u32 tio_conf_proc; /* TIO CONF processed */ - u32 tio_conf_drop; /* TIO CONF dropped */ - u32 tio_cleanup_req; /* TIO cleanup requested */ - u32 tio_cleanup_comp; /* TIO cleanup completed */ - u32 tio_abort_rsp; /* TIO abort response */ - u32 tio_abort_rsp_comp; /* TIO abort rsp completed */ - u32 tio_abts_req; /* TIO ABTS requested */ - u32 tio_abts_ack; /* TIO ABTS ack-ed */ - u32 tio_abts_ack_nocomp;/* TIO ABTS ack-ed but not completed */ - u32 tio_abts_tmo; /* TIO ABTS timeout */ - u32 tio_snsdata_dma; /* TIO sense data DMA */ - u32 tio_rxwchan_wait; /* TIO waiting for RX wait channel */ - u32 tio_rxwchan_avail; /* TIO RX wait channel available */ - u32 tio_hit_bls; /* TIO IOH BLS event */ - u32 tio_uf_recv; /* TIO received UF */ - u32 tio_rd_invalid_sm; /* TIO read reqst in wrong state machine */ - u32 tio_wr_invalid_sm; /* TIO write reqst in wrong state machine */ - - u32 ds_rxwchan_wait; /* DS waiting for RX wait channel */ - u32 ds_rxwchan_avail; /* DS RX wait channel available */ - u32 ds_unaligned_rd; /* DS unaligned read */ - u32 ds_rdcomp_invalid_sm; /* DS read completed in wrong state - * machine */ - u32 ds_wrcomp_invalid_sm; /* DS write completed in wrong state - * machine */ - u32 ds_flush_req; /* DS flush requested */ - u32 ds_flush_comp; /* DS flush completed */ - u32 ds_xfrdy_exp; /* DS XFER_RDY expired */ - u32 ds_seq_cnt_err; /* DS seq cnt error */ - u32 ds_seq_len_err; /* DS seq len error */ - u32 ds_data_oor; /* DS data out of order */ - u32 ds_hit_bls; /* DS hit BLS */ - u32 ds_edtov_timer_exp; /* DS edtov expired */ - u32 ds_cpu_owned; /* DS cpu owned */ - u32 ds_hit_class2; /* DS hit class2 */ - u32 ds_length_err; /* DS length error */ - u32 ds_ro_ooo_err; /* DS relative offset out-of-order error */ - u32 ds_rectov_timer_exp;/* DS rectov expired */ - u32 ds_unexp_fr_err; /* DS unexp frame error */ -}; - -/* - * IOC firmware IO stats - */ -struct bfa_fw_io_stats_s { - struct bfa_fw_ioim_stats_s ioim_stats; - struct bfa_fw_tio_stats_s tio_stats; -}; - -/* - * IOC port firmware stats - */ - -struct bfa_fw_port_fpg_stats_s { - u32 intr_evt; - u32 intr; - u32 intr_excess; - u32 intr_cause0; - u32 intr_other; - u32 intr_other_ign; - u32 sig_lost; - u32 sig_regained; - u32 sync_lost; - u32 sync_to; - u32 sync_regained; - u32 div2_overflow; - u32 div2_underflow; - u32 efifo_overflow; - u32 efifo_underflow; - u32 idle_rx; - u32 lrr_rx; - u32 lr_rx; - u32 ols_rx; - u32 nos_rx; - u32 lip_rx; - u32 arbf0_rx; - u32 arb_rx; - u32 mrk_rx; - u32 const_mrk_rx; - u32 prim_unknown; -}; - - -struct bfa_fw_port_lksm_stats_s { - u32 hwsm_success; /* hwsm state machine success */ - u32 hwsm_fails; /* hwsm fails */ - u32 hwsm_wdtov; /* hwsm timed out */ - u32 swsm_success; /* swsm success */ - u32 swsm_fails; /* swsm fails */ - u32 swsm_wdtov; /* swsm timed out */ - u32 busybufs; /* link init failed due to busybuf */ - u32 buf_waits; /* bufwait state entries */ - u32 link_fails; /* link failures */ - u32 psp_errors; /* primitive sequence protocol errors */ - u32 lr_unexp; /* No. of times LR rx-ed unexpectedly */ - u32 lrr_unexp; /* No. of times LRR rx-ed unexpectedly */ - u32 lr_tx; /* No. of times LR tx started */ - u32 lrr_tx; /* No. of times LRR tx started */ - u32 ols_tx; /* No. of times OLS tx started */ - u32 nos_tx; /* No. of times NOS tx started */ - u32 hwsm_lrr_rx; /* No. of times LRR rx-ed by HWSM */ - u32 hwsm_lr_rx; /* No. of times LR rx-ed by HWSM */ - u32 bbsc_lr; /* LKSM LR tx for credit recovery */ -}; - -struct bfa_fw_port_snsm_stats_s { - u32 hwsm_success; /* Successful hwsm terminations */ - u32 hwsm_fails; /* hwsm fail count */ - u32 hwsm_wdtov; /* hwsm timed out */ - u32 swsm_success; /* swsm success */ - u32 swsm_wdtov; /* swsm timed out */ - u32 error_resets; /* error resets initiated by upsm */ - u32 sync_lost; /* Sync loss count */ - u32 sig_lost; /* Signal loss count */ - u32 asn8g_attempts; /* SNSM HWSM at 8Gbps attempts */ -}; - -struct bfa_fw_port_physm_stats_s { - u32 module_inserts; /* Module insert count */ - u32 module_xtracts; /* Module extracts count */ - u32 module_invalids; /* Invalid module inserted count */ - u32 module_read_ign; /* Module validation status ignored */ - u32 laser_faults; /* Laser fault count */ - u32 rsvd; -}; - -struct bfa_fw_fip_stats_s { - u32 vlan_req; /* vlan discovery requests */ - u32 vlan_notify; /* vlan notifications */ - u32 vlan_err; /* vlan response error */ - u32 vlan_timeouts; /* vlan disvoery timeouts */ - u32 vlan_invalids; /* invalid vlan in discovery advert. */ - u32 disc_req; /* Discovery solicit requests */ - u32 disc_rsp; /* Discovery solicit response */ - u32 disc_err; /* Discovery advt. parse errors */ - u32 disc_unsol; /* Discovery unsolicited */ - u32 disc_timeouts; /* Discovery timeouts */ - u32 disc_fcf_unavail; /* Discovery FCF Not Avail. */ - u32 linksvc_unsupp; /* Unsupported link service req */ - u32 linksvc_err; /* Parse error in link service req */ - u32 logo_req; /* FIP logos received */ - u32 clrvlink_req; /* Clear virtual link req */ - u32 op_unsupp; /* Unsupported FIP operation */ - u32 untagged; /* Untagged frames (ignored) */ - u32 invalid_version; /* Invalid FIP version */ -}; - -struct bfa_fw_lps_stats_s { - u32 mac_invalids; /* Invalid mac assigned */ - u32 rsvd; -}; - -struct bfa_fw_fcoe_stats_s { - u32 cee_linkups; /* CEE link up count */ - u32 cee_linkdns; /* CEE link down count */ - u32 fip_linkups; /* FIP link up count */ - u32 fip_linkdns; /* FIP link up count */ - u32 fip_fails; /* FIP fail count */ - u32 mac_invalids; /* Invalid mac assigned */ -}; - -/* - * IOC firmware FCoE port stats - */ -struct bfa_fw_fcoe_port_stats_s { - struct bfa_fw_fcoe_stats_s fcoe_stats; - struct bfa_fw_fip_stats_s fip_stats; -}; - -/* - * IOC firmware FC uport stats - */ -struct bfa_fw_fc_uport_stats_s { - struct bfa_fw_port_snsm_stats_s snsm_stats; - struct bfa_fw_port_lksm_stats_s lksm_stats; -}; - -/* - * IOC firmware FC port stats - */ -union bfa_fw_fc_port_stats_s { - struct bfa_fw_fc_uport_stats_s fc_stats; - struct bfa_fw_fcoe_port_stats_s fcoe_stats; -}; - -/* - * IOC firmware port stats - */ -struct bfa_fw_port_stats_s { - struct bfa_fw_port_fpg_stats_s fpg_stats; - struct bfa_fw_port_physm_stats_s physm_stats; - union bfa_fw_fc_port_stats_s fc_port; -}; - -/* - * fcxchg module statistics - */ -struct bfa_fw_fcxchg_stats_s { - u32 ua_tag_inv; - u32 ua_state_inv; -}; - -struct bfa_fw_lpsm_stats_s { - u32 cls_rx; - u32 cls_tx; -}; - -/* - * Trunk statistics - */ -struct bfa_fw_trunk_stats_s { - u32 emt_recvd; /* Trunk EMT received */ - u32 emt_accepted; /* Trunk EMT Accepted */ - u32 emt_rejected; /* Trunk EMT rejected */ - u32 etp_recvd; /* Trunk ETP received */ - u32 etp_accepted; /* Trunk ETP Accepted */ - u32 etp_rejected; /* Trunk ETP rejected */ - u32 lr_recvd; /* Trunk LR received */ - u32 rsvd; /* padding for 64 bit alignment */ -}; - -struct bfa_fw_advsm_stats_s { - u32 flogi_sent; /* Flogi sent */ - u32 flogi_acc_recvd; /* Flogi Acc received */ - u32 flogi_rjt_recvd; /* Flogi rejects received */ - u32 flogi_retries; /* Flogi retries */ - - u32 elp_recvd; /* ELP received */ - u32 elp_accepted; /* ELP Accepted */ - u32 elp_rejected; /* ELP rejected */ - u32 elp_dropped; /* ELP dropped */ -}; - -/* - * IOCFC firmware stats - */ -struct bfa_fw_iocfc_stats_s { - u32 cfg_reqs; /* cfg request */ - u32 updq_reqs; /* update queue request */ - u32 ic_reqs; /* interrupt coalesce reqs */ - u32 unknown_reqs; - u32 set_intr_reqs; /* set interrupt reqs */ -}; - -/* - * IOC attributes returned in queries - */ -struct bfa_iocfc_attr_s { - struct bfa_iocfc_cfg_s config; /* IOCFC config */ - struct bfa_iocfc_intr_attr_s intr_attr; /* interrupt attr */ -}; - -/* - * Eth_sndrcv mod stats - */ -struct bfa_fw_eth_sndrcv_stats_s { - u32 crc_err; - u32 rsvd; /* 64bit align */ -}; - -/* - * CT MAC mod stats - */ -struct bfa_fw_mac_mod_stats_s { - u32 mac_on; /* MAC got turned-on */ - u32 link_up; /* link-up */ - u32 signal_off; /* lost signal */ - u32 dfe_on; /* DFE on */ - u32 mac_reset; /* # of MAC reset to bring lnk up */ - u32 pcs_reset; /* # of PCS reset to bring lnk up */ - u32 loopback; /* MAC got into serdes loopback */ - u32 lb_mac_reset; - /* # of MAC reset to bring link up in loopback */ - u32 lb_pcs_reset; - /* # of PCS reset to bring link up in loopback */ - u32 rsvd; /* 64bit align */ -}; - -/* - * CT MOD stats - */ -struct bfa_fw_ct_mod_stats_s { - u32 rxa_rds_undrun; /* RxA RDS underrun */ - u32 rad_bpc_ovfl; /* RAD BPC overflow */ - u32 rad_rlb_bpc_ovfl; /* RAD RLB BPC overflow */ - u32 bpc_fcs_err; /* BPC FCS_ERR */ - u32 txa_tso_hdr; /* TxA TSO header too long */ - u32 rsvd; /* 64bit align */ -}; - -/* - * IOC firmware stats - */ -struct bfa_fw_stats_s { - struct bfa_fw_ioc_stats_s ioc_stats; - struct bfa_fw_iocfc_stats_s iocfc_stats; - struct bfa_fw_io_stats_s io_stats; - struct bfa_fw_port_stats_s port_stats; - struct bfa_fw_fcxchg_stats_s fcxchg_stats; - struct bfa_fw_lpsm_stats_s lpsm_stats; - struct bfa_fw_lps_stats_s lps_stats; - struct bfa_fw_trunk_stats_s trunk_stats; - struct bfa_fw_advsm_stats_s advsm_stats; - struct bfa_fw_mac_mod_stats_s macmod_stats; - struct bfa_fw_ct_mod_stats_s ctmod_stats; - struct bfa_fw_eth_sndrcv_stats_s ethsndrcv_stats; -}; - -#define BFA_IOCFC_PATHTOV_MAX 60 -#define BFA_IOCFC_QDEPTH_MAX 2000 - -/* - * QoS states - */ -enum bfa_qos_state { - BFA_QOS_DISABLED = 0, /* QoS is disabled */ - BFA_QOS_ONLINE = 1, /* QoS is online */ - BFA_QOS_OFFLINE = 2, /* QoS is offline */ -}; - -/* - * QoS Priority levels. - */ -enum bfa_qos_priority { - BFA_QOS_UNKNOWN = 0, - BFA_QOS_HIGH = 1, /* QoS Priority Level High */ - BFA_QOS_MED = 2, /* QoS Priority Level Medium */ - BFA_QOS_LOW = 3, /* QoS Priority Level Low */ -}; - -/* - * QoS bandwidth allocation for each priority level - */ -enum bfa_qos_bw_alloc { - BFA_QOS_BW_HIGH = 60, /* bandwidth allocation for High */ - BFA_QOS_BW_MED = 30, /* bandwidth allocation for Medium */ - BFA_QOS_BW_LOW = 10, /* bandwidth allocation for Low */ -}; -#pragma pack(1) -/* - * QoS attribute returned in QoS Query - */ -struct bfa_qos_attr_s { - u8 state; /* QoS current state */ - u8 rsvd[3]; - u32 total_bb_cr; /* Total BB Credits */ -}; - -/* - * These fields should be displayed only from the CLI. - * There will be a separate BFAL API (get_qos_vc_attr ?) - * to retrieve this. - * - */ -#define BFA_QOS_MAX_VC 16 - -struct bfa_qos_vc_info_s { - u8 vc_credit; - u8 borrow_credit; - u8 priority; - u8 resvd; -}; - -struct bfa_qos_vc_attr_s { - u16 total_vc_count; /* Total VC Count */ - u16 shared_credit; - u32 elp_opmode_flags; - struct bfa_qos_vc_info_s vc_info[BFA_QOS_MAX_VC]; /* as many as - * total_vc_count */ -}; - -/* - * QoS statistics - */ -struct bfa_qos_stats_s { - u32 flogi_sent; /* QoS Flogi sent */ - u32 flogi_acc_recvd; /* QoS Flogi Acc received */ - u32 flogi_rjt_recvd; /* QoS Flogi rejects received */ - u32 flogi_retries; /* QoS Flogi retries */ - - u32 elp_recvd; /* QoS ELP received */ - u32 elp_accepted; /* QoS ELP Accepted */ - u32 elp_rejected; /* QoS ELP rejected */ - u32 elp_dropped; /* QoS ELP dropped */ - - u32 qos_rscn_recvd; /* QoS RSCN received */ - u32 rsvd; /* padding for 64 bit alignment */ -}; - -/* - * FCoE statistics - */ -struct bfa_fcoe_stats_s { - u64 secs_reset; /* Seconds since stats reset */ - u64 cee_linkups; /* CEE link up */ - u64 cee_linkdns; /* CEE link down */ - u64 fip_linkups; /* FIP link up */ - u64 fip_linkdns; /* FIP link down */ - u64 fip_fails; /* FIP failures */ - u64 mac_invalids; /* Invalid mac assignments */ - u64 vlan_req; /* Vlan requests */ - u64 vlan_notify; /* Vlan notifications */ - u64 vlan_err; /* Vlan notification errors */ - u64 vlan_timeouts; /* Vlan request timeouts */ - u64 vlan_invalids; /* Vlan invalids */ - u64 disc_req; /* Discovery requests */ - u64 disc_rsp; /* Discovery responses */ - u64 disc_err; /* Discovery error frames */ - u64 disc_unsol; /* Discovery unsolicited */ - u64 disc_timeouts; /* Discovery timeouts */ - u64 disc_fcf_unavail; /* Discovery FCF not avail */ - u64 linksvc_unsupp; /* FIP link service req unsupp */ - u64 linksvc_err; /* FIP link service req errors */ - u64 logo_req; /* FIP logos received */ - u64 clrvlink_req; /* Clear virtual link requests */ - u64 op_unsupp; /* FIP operation unsupp. */ - u64 untagged; /* FIP untagged frames */ - u64 txf_ucast; /* Tx FCoE unicast frames */ - u64 txf_ucast_vlan; /* Tx FCoE unicast vlan frames */ - u64 txf_ucast_octets; /* Tx FCoE unicast octets */ - u64 txf_mcast; /* Tx FCoE multicast frames */ - u64 txf_mcast_vlan; /* Tx FCoE multicast vlan frames */ - u64 txf_mcast_octets; /* Tx FCoE multicast octets */ - u64 txf_bcast; /* Tx FCoE broadcast frames */ - u64 txf_bcast_vlan; /* Tx FCoE broadcast vlan frames */ - u64 txf_bcast_octets; /* Tx FCoE broadcast octets */ - u64 txf_timeout; /* Tx timeouts */ - u64 txf_parity_errors; /* Transmit parity err */ - u64 txf_fid_parity_errors; /* Transmit FID parity err */ - u64 rxf_ucast_octets; /* Rx FCoE unicast octets */ - u64 rxf_ucast; /* Rx FCoE unicast frames */ - u64 rxf_ucast_vlan; /* Rx FCoE unicast vlan frames */ - u64 rxf_mcast_octets; /* Rx FCoE multicast octets */ - u64 rxf_mcast; /* Rx FCoE multicast frames */ - u64 rxf_mcast_vlan; /* Rx FCoE multicast vlan frames */ - u64 rxf_bcast_octets; /* Rx FCoE broadcast octets */ - u64 rxf_bcast; /* Rx FCoE broadcast frames */ - u64 rxf_bcast_vlan; /* Rx FCoE broadcast vlan frames */ -}; - -/* - * QoS or FCoE stats (fcport stats excluding physical FC port stats) - */ -union bfa_fcport_stats_u { - struct bfa_qos_stats_s fcqos; - struct bfa_fcoe_stats_s fcoe; -}; -#pragma pack() - -struct bfa_fcpim_del_itn_stats_s { - u32 del_itn_iocomp_aborted; /* Aborted IO requests */ - u32 del_itn_iocomp_timedout; /* IO timeouts */ - u32 del_itn_iocom_sqer_needed; /* IO retry for SQ error recovery */ - u32 del_itn_iocom_res_free; /* Delayed freeing of IO resources */ - u32 del_itn_iocom_hostabrts; /* Host IO abort requests */ - u32 del_itn_total_ios; /* Total IO count */ - u32 del_io_iocdowns; /* IO cleaned-up due to IOC down */ - u32 del_tm_iocdowns; /* TM cleaned-up due to IOC down */ -}; - -struct bfa_itnim_iostats_s { - - u32 total_ios; /* Total IO Requests */ - u32 input_reqs; /* Data in-bound requests */ - u32 output_reqs; /* Data out-bound requests */ - u32 io_comps; /* Total IO Completions */ - u32 wr_throughput; /* Write data transferred in bytes */ - u32 rd_throughput; /* Read data transferred in bytes */ - - u32 iocomp_ok; /* Slowpath IO completions */ - u32 iocomp_underrun; /* IO underrun */ - u32 iocomp_overrun; /* IO overrun */ - u32 qwait; /* IO Request-Q wait */ - u32 qresumes; /* IO Request-Q wait done */ - u32 no_iotags; /* No free IO tag */ - u32 iocomp_timedout; /* IO timeouts */ - u32 iocom_nexus_abort; /* IO failure due to target offline */ - u32 iocom_proto_err; /* IO protocol errors */ - u32 iocom_dif_err; /* IO SBC-3 protection errors */ - - u32 iocom_sqer_needed; /* fcp-2 error recovery failed */ - u32 iocom_res_free; /* Delayed freeing of IO tag */ - - - u32 io_aborts; /* Host IO abort requests */ - u32 iocom_hostabrts; /* Host IO abort completions */ - u32 io_cleanups; /* IO clean-up requests */ - u32 path_tov_expired; /* IO path tov expired */ - u32 iocomp_aborted; /* IO abort completions */ - u32 io_iocdowns; /* IO cleaned-up due to IOC down */ - u32 iocom_utags; /* IO comp with unknown tags */ - - u32 io_tmaborts; /* Abort request due to TM command */ - u32 tm_io_comps; /* Abort completion due to TM command */ - - u32 creates; /* IT Nexus create requests */ - u32 fw_create; /* IT Nexus FW create requests */ - u32 create_comps; /* IT Nexus FW create completions */ - u32 onlines; /* IT Nexus onlines */ - u32 offlines; /* IT Nexus offlines */ - u32 fw_delete; /* IT Nexus FW delete requests */ - u32 delete_comps; /* IT Nexus FW delete completions */ - u32 deletes; /* IT Nexus delete requests */ - u32 sler_events; /* SLER events */ - u32 ioc_disabled; /* Num IOC disables */ - u32 cleanup_comps; /* IT Nexus cleanup completions */ - - u32 tm_cmnds; /* TM Requests */ - u32 tm_fw_rsps; /* TM Completions */ - u32 tm_success; /* TM initiated IO cleanup success */ - u32 tm_failures; /* TM initiated IO cleanup failure */ - u32 no_tskims; /* No free TM tag */ - u32 tm_qwait; /* TM Request-Q wait */ - u32 tm_qresumes; /* TM Request-Q wait done */ - - u32 tm_iocdowns; /* TM cleaned-up due to IOC down */ - u32 tm_cleanups; /* TM cleanup requests */ - u32 tm_cleanup_comps; /* TM cleanup completions */ - u32 rsvd[6]; -}; - -/* Modify char* port_stt[] in bfal_port.c if a new state was added */ -enum bfa_port_states { - BFA_PORT_ST_UNINIT = 1, - BFA_PORT_ST_ENABLING_QWAIT = 2, - BFA_PORT_ST_ENABLING = 3, - BFA_PORT_ST_LINKDOWN = 4, - BFA_PORT_ST_LINKUP = 5, - BFA_PORT_ST_DISABLING_QWAIT = 6, - BFA_PORT_ST_DISABLING = 7, - BFA_PORT_ST_DISABLED = 8, - BFA_PORT_ST_STOPPED = 9, - BFA_PORT_ST_IOCDOWN = 10, - BFA_PORT_ST_IOCDIS = 11, - BFA_PORT_ST_FWMISMATCH = 12, - BFA_PORT_ST_PREBOOT_DISABLED = 13, - BFA_PORT_ST_TOGGLING_QWAIT = 14, - BFA_PORT_ST_ACQ_ADDR = 15, - BFA_PORT_ST_MAX_STATE, -}; - -/* - * Port operational type (in sync with SNIA port type). - */ -enum bfa_port_type { - BFA_PORT_TYPE_UNKNOWN = 1, /* port type is unknown */ - BFA_PORT_TYPE_NPORT = 5, /* P2P with switched fabric */ - BFA_PORT_TYPE_NLPORT = 6, /* public loop */ - BFA_PORT_TYPE_LPORT = 20, /* private loop */ - BFA_PORT_TYPE_P2P = 21, /* P2P with no switched fabric */ - BFA_PORT_TYPE_VPORT = 22, /* NPIV - virtual port */ -}; - -/* - * Port topology setting. A port's topology and fabric login status - * determine its operational type. - */ -enum bfa_port_topology { - BFA_PORT_TOPOLOGY_NONE = 0, /* No valid topology */ - BFA_PORT_TOPOLOGY_P2P = 1, /* P2P only */ - BFA_PORT_TOPOLOGY_LOOP = 2, /* LOOP topology */ - BFA_PORT_TOPOLOGY_AUTO = 3, /* auto topology selection */ -}; - -/* - * Physical port loopback types. - */ -enum bfa_port_opmode { - BFA_PORT_OPMODE_NORMAL = 0x00, /* normal non-loopback mode */ - BFA_PORT_OPMODE_LB_INT = 0x01, /* internal loop back */ - BFA_PORT_OPMODE_LB_SLW = 0x02, /* serial link wrapback (serdes) */ - BFA_PORT_OPMODE_LB_EXT = 0x04, /* external loop back (serdes) */ - BFA_PORT_OPMODE_LB_CBL = 0x08, /* cabled loop back */ - BFA_PORT_OPMODE_LB_NLINT = 0x20, /* NL_Port internal loopback */ -}; - -#define BFA_PORT_OPMODE_LB_HARD(_mode) \ - ((_mode == BFA_PORT_OPMODE_LB_INT) || \ - (_mode == BFA_PORT_OPMODE_LB_SLW) || \ - (_mode == BFA_PORT_OPMODE_LB_EXT)) - -/* - * Port link state - */ -enum bfa_port_linkstate { - BFA_PORT_LINKUP = 1, /* Physical port/Trunk link up */ - BFA_PORT_LINKDOWN = 2, /* Physical port/Trunk link down */ -}; - -/* - * Port link state reason code - */ -enum bfa_port_linkstate_rsn { - BFA_PORT_LINKSTATE_RSN_NONE = 0, - BFA_PORT_LINKSTATE_RSN_DISABLED = 1, - BFA_PORT_LINKSTATE_RSN_RX_NOS = 2, - BFA_PORT_LINKSTATE_RSN_RX_OLS = 3, - BFA_PORT_LINKSTATE_RSN_RX_LIP = 4, - BFA_PORT_LINKSTATE_RSN_RX_LIPF7 = 5, - BFA_PORT_LINKSTATE_RSN_SFP_REMOVED = 6, - BFA_PORT_LINKSTATE_RSN_PORT_FAULT = 7, - BFA_PORT_LINKSTATE_RSN_RX_LOS = 8, - BFA_PORT_LINKSTATE_RSN_LOCAL_FAULT = 9, - BFA_PORT_LINKSTATE_RSN_REMOTE_FAULT = 10, - BFA_PORT_LINKSTATE_RSN_TIMEOUT = 11, - - - - /* CEE related reason codes/errors */ - CEE_LLDP_INFO_AGED_OUT = 20, - CEE_LLDP_SHUTDOWN_TLV_RCVD = 21, - CEE_PEER_NOT_ADVERTISE_DCBX = 22, - CEE_PEER_NOT_ADVERTISE_PG = 23, - CEE_PEER_NOT_ADVERTISE_PFC = 24, - CEE_PEER_NOT_ADVERTISE_FCOE = 25, - CEE_PG_NOT_COMPATIBLE = 26, - CEE_PFC_NOT_COMPATIBLE = 27, - CEE_FCOE_NOT_COMPATIBLE = 28, - CEE_BAD_PG_RCVD = 29, - CEE_BAD_BW_RCVD = 30, - CEE_BAD_PFC_RCVD = 31, - CEE_BAD_APP_PRI_RCVD = 32, - CEE_FCOE_PRI_PFC_OFF = 33, - CEE_DUP_CONTROL_TLV_RCVD = 34, - CEE_DUP_FEAT_TLV_RCVD = 35, - CEE_APPLY_NEW_CFG = 36, /* reason, not error */ - CEE_PROTOCOL_INIT = 37, /* reason, not error */ - CEE_PHY_LINK_DOWN = 38, - CEE_LLS_FCOE_ABSENT = 39, - CEE_LLS_FCOE_DOWN = 40, - CEE_ISCSI_NOT_COMPATIBLE = 41, - CEE_ISCSI_PRI_PFC_OFF = 42, - CEE_ISCSI_PRI_OVERLAP_FCOE_PRI = 43 -}; - -#define MAX_LUN_MASK_CFG 16 - -/* - * Initially flash content may be fff. On making LUN mask enable and disable - * state chnage. when report lun command is being processed it goes from - * BFA_LUN_MASK_ACTIVE to BFA_LUN_MASK_FETCH and comes back to - * BFA_LUN_MASK_ACTIVE. - */ -enum bfa_ioim_lun_mask_state_s { - BFA_IOIM_LUN_MASK_INACTIVE = 0, - BFA_IOIM_LUN_MASK_ACTIVE = 1, - BFA_IOIM_LUN_MASK_FETCHED = 2, -}; - -enum bfa_lunmask_state_s { - BFA_LUNMASK_DISABLED = 0x00, - BFA_LUNMASK_ENABLED = 0x01, - BFA_LUNMASK_MINCFG = 0x02, - BFA_LUNMASK_UNINITIALIZED = 0xff, -}; - -#pragma pack(1) -/* - * LUN mask configuration - */ -struct bfa_lun_mask_s { - wwn_t lp_wwn; - wwn_t rp_wwn; - struct scsi_lun lun; - u8 ua; - u8 rsvd[3]; - u16 rp_tag; - u8 lp_tag; - u8 state; -}; - -#define MAX_LUN_MASK_CFG 16 -struct bfa_lunmask_cfg_s { - u32 status; - u32 rsvd; - struct bfa_lun_mask_s lun_list[MAX_LUN_MASK_CFG]; -}; - -/* - * Physical port configuration - */ -struct bfa_port_cfg_s { - u8 topology; /* bfa_port_topology */ - u8 speed; /* enum bfa_port_speed */ - u8 trunked; /* trunked or not */ - u8 qos_enabled; /* qos enabled or not */ - u8 cfg_hardalpa; /* is hard alpa configured */ - u8 hardalpa; /* configured hard alpa */ - __be16 maxfrsize; /* maximum frame size */ - u8 rx_bbcredit; /* receive buffer credits */ - u8 tx_bbcredit; /* transmit buffer credits */ - u8 ratelimit; /* ratelimit enabled or not */ - u8 trl_def_speed; /* ratelimit default speed */ - u8 bb_scn; /* BB_SCN value from FLOGI Exchg */ - u8 bb_scn_state; /* Config state of BB_SCN */ - u8 faa_state; /* FAA enabled/disabled */ - u8 rsvd[1]; - u16 path_tov; /* device path timeout */ - u16 q_depth; /* SCSI Queue depth */ -}; -#pragma pack() - -/* - * Port attribute values. - */ -struct bfa_port_attr_s { - /* - * Static fields - */ - wwn_t nwwn; /* node wwn */ - wwn_t pwwn; /* port wwn */ - wwn_t factorynwwn; /* factory node wwn */ - wwn_t factorypwwn; /* factory port wwn */ - enum fc_cos cos_supported; /* supported class of - * services */ - u32 rsvd; - struct fc_symname_s port_symname; /* port symbolic name */ - enum bfa_port_speed speed_supported; /* supported speeds */ - bfa_boolean_t pbind_enabled; - - /* - * Configured values - */ - struct bfa_port_cfg_s pport_cfg; /* pport cfg */ - - /* - * Dynamic field - info from BFA - */ - enum bfa_port_states port_state; /* current port state */ - enum bfa_port_speed speed; /* current speed */ - enum bfa_port_topology topology; /* current topology */ - bfa_boolean_t beacon; /* current beacon status */ - bfa_boolean_t link_e2e_beacon; /* link beacon is on */ - bfa_boolean_t bbsc_op_status; /* fc credit recovery oper - * state */ - - /* - * Dynamic field - info from FCS - */ - u32 pid; /* port ID */ - enum bfa_port_type port_type; /* current topology */ - u32 loopback; /* external loopback */ - u32 authfail; /* auth fail state */ - - /* FCoE specific */ - u16 fcoe_vlan; - u8 rsvd1[2]; -}; - -/* - * Port FCP mappings. - */ -struct bfa_port_fcpmap_s { - char osdevname[256]; - u32 bus; - u32 target; - u32 oslun; - u32 fcid; - wwn_t nwwn; - wwn_t pwwn; - u64 fcplun; - char luid[256]; -}; - -/* - * Port RNID info. - */ -struct bfa_port_rnid_s { - wwn_t wwn; - u32 unittype; - u32 portid; - u32 attached_nodes_num; - u16 ip_version; - u16 udp_port; - u8 ipaddr[16]; - u16 rsvd; - u16 topologydiscoveryflags; -}; - -#pragma pack(1) -struct bfa_fcport_fcf_s { - wwn_t name; /* FCF name */ - wwn_t fabric_name; /* Fabric Name */ - u8 fipenabled; /* FIP enabled or not */ - u8 fipfailed; /* FIP failed or not */ - u8 resv[2]; - u8 pri; /* FCF priority */ - u8 version; /* FIP version used */ - u8 available; /* Available for login */ - u8 fka_disabled; /* FKA is disabled */ - u8 maxsz_verified; /* FCoE max size verified */ - u8 fc_map[3]; /* FC map */ - __be16 vlan; /* FCoE vlan tag/priority */ - u32 fka_adv_per; /* FIP ka advert. period */ - mac_t mac; /* FCF mac */ -}; - -/* - * Trunk states for BCU/BFAL - */ -enum bfa_trunk_state { - BFA_TRUNK_DISABLED = 0, /* Trunk is not configured */ - BFA_TRUNK_ONLINE = 1, /* Trunk is online */ - BFA_TRUNK_OFFLINE = 2, /* Trunk is offline */ -}; - -/* - * VC attributes for trunked link - */ -struct bfa_trunk_vc_attr_s { - u32 bb_credit; - u32 elp_opmode_flags; - u32 req_credit; - u16 vc_credits[8]; -}; - -/* - * Link state information - */ -struct bfa_port_link_s { - u8 linkstate; /* Link state bfa_port_linkstate */ - u8 linkstate_rsn; /* bfa_port_linkstate_rsn_t */ - u8 topology; /* P2P/LOOP bfa_port_topology */ - u8 speed; /* Link speed (1/2/4/8 G) */ - u32 linkstate_opt; /* Linkstate optional data (debug) */ - u8 trunked; /* Trunked or not (1 or 0) */ - u8 resvd[3]; - struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ - union { - struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */ - struct bfa_trunk_vc_attr_s trunk_vc_attr; - struct bfa_fcport_fcf_s fcf; /* FCF information (for FCoE) */ - } vc_fcf; -}; -#pragma pack() - -enum bfa_trunk_link_fctl { - BFA_TRUNK_LINK_FCTL_NORMAL, - BFA_TRUNK_LINK_FCTL_VC, - BFA_TRUNK_LINK_FCTL_VC_QOS, -}; - -enum bfa_trunk_link_state { - BFA_TRUNK_LINK_STATE_UP = 1, /* link part of trunk */ - BFA_TRUNK_LINK_STATE_DN_LINKDN = 2, /* physical link down */ - BFA_TRUNK_LINK_STATE_DN_GRP_MIS = 3, /* trunk group different */ - BFA_TRUNK_LINK_STATE_DN_SPD_MIS = 4, /* speed mismatch */ - BFA_TRUNK_LINK_STATE_DN_MODE_MIS = 5, /* remote port not trunked */ -}; - -#define BFA_TRUNK_MAX_PORTS 2 -struct bfa_trunk_link_attr_s { - wwn_t trunk_wwn; - enum bfa_trunk_link_fctl fctl; - enum bfa_trunk_link_state link_state; - enum bfa_port_speed speed; - u32 deskew; -}; - -struct bfa_trunk_attr_s { - enum bfa_trunk_state state; - enum bfa_port_speed speed; - u32 port_id; - u32 rsvd; - struct bfa_trunk_link_attr_s link_attr[BFA_TRUNK_MAX_PORTS]; -}; - -struct bfa_rport_hal_stats_s { - u32 sm_un_cr; /* uninit: create events */ - u32 sm_un_unexp; /* uninit: exception events */ - u32 sm_cr_on; /* created: online events */ - u32 sm_cr_del; /* created: delete events */ - u32 sm_cr_hwf; /* created: IOC down */ - u32 sm_cr_unexp; /* created: exception events */ - u32 sm_fwc_rsp; /* fw create: f/w responses */ - u32 sm_fwc_del; /* fw create: delete events */ - u32 sm_fwc_off; /* fw create: offline events */ - u32 sm_fwc_hwf; /* fw create: IOC down */ - u32 sm_fwc_unexp; /* fw create: exception events*/ - u32 sm_on_off; /* online: offline events */ - u32 sm_on_del; /* online: delete events */ - u32 sm_on_hwf; /* online: IOC down events */ - u32 sm_on_unexp; /* online: exception events */ - u32 sm_fwd_rsp; /* fw delete: fw responses */ - u32 sm_fwd_del; /* fw delete: delete events */ - u32 sm_fwd_hwf; /* fw delete: IOC down events */ - u32 sm_fwd_unexp; /* fw delete: exception events*/ - u32 sm_off_del; /* offline: delete events */ - u32 sm_off_on; /* offline: online events */ - u32 sm_off_hwf; /* offline: IOC down events */ - u32 sm_off_unexp; /* offline: exception events */ - u32 sm_del_fwrsp; /* delete: fw responses */ - u32 sm_del_hwf; /* delete: IOC down events */ - u32 sm_del_unexp; /* delete: exception events */ - u32 sm_delp_fwrsp; /* delete pend: fw responses */ - u32 sm_delp_hwf; /* delete pend: IOC downs */ - u32 sm_delp_unexp; /* delete pend: exceptions */ - u32 sm_offp_fwrsp; /* off-pending: fw responses */ - u32 sm_offp_del; /* off-pending: deletes */ - u32 sm_offp_hwf; /* off-pending: IOC downs */ - u32 sm_offp_unexp; /* off-pending: exceptions */ - u32 sm_iocd_off; /* IOC down: offline events */ - u32 sm_iocd_del; /* IOC down: delete events */ - u32 sm_iocd_on; /* IOC down: online events */ - u32 sm_iocd_unexp; /* IOC down: exceptions */ - u32 rsvd; -}; -#pragma pack(1) -/* - * Rport's QoS attributes - */ -struct bfa_rport_qos_attr_s { - u8 qos_priority; /* rport's QoS priority */ - u8 rsvd[3]; - u32 qos_flow_id; /* QoS flow Id */ -}; -#pragma pack() - -#define BFA_IOBUCKET_MAX 14 - -struct bfa_itnim_latency_s { - u32 min[BFA_IOBUCKET_MAX]; - u32 max[BFA_IOBUCKET_MAX]; - u32 count[BFA_IOBUCKET_MAX]; - u32 avg[BFA_IOBUCKET_MAX]; -}; - -struct bfa_itnim_ioprofile_s { - u32 clock_res_mul; - u32 clock_res_div; - u32 index; - u32 io_profile_start_time; /* IO profile start time */ - u32 iocomps[BFA_IOBUCKET_MAX]; /* IO completed */ - struct bfa_itnim_latency_s io_latency; -}; - -/* - * vHBA port attribute values. - */ -struct bfa_vhba_attr_s { - wwn_t nwwn; /* node wwn */ - wwn_t pwwn; /* port wwn */ - u32 pid; /* port ID */ - bfa_boolean_t io_profile; /* get it from fcpim mod */ - bfa_boolean_t plog_enabled; /* portlog is enabled */ - u16 path_tov; - u8 rsvd[2]; -}; - -/* - * FC physical port statistics. - */ -struct bfa_port_fc_stats_s { - u64 secs_reset; /* Seconds since stats is reset */ - u64 tx_frames; /* Tx frames */ - u64 tx_words; /* Tx words */ - u64 tx_lip; /* Tx LIP */ - u64 tx_nos; /* Tx NOS */ - u64 tx_ols; /* Tx OLS */ - u64 tx_lr; /* Tx LR */ - u64 tx_lrr; /* Tx LRR */ - u64 rx_frames; /* Rx frames */ - u64 rx_words; /* Rx words */ - u64 lip_count; /* Rx LIP */ - u64 nos_count; /* Rx NOS */ - u64 ols_count; /* Rx OLS */ - u64 lr_count; /* Rx LR */ - u64 lrr_count; /* Rx LRR */ - u64 invalid_crcs; /* Rx CRC err frames */ - u64 invalid_crc_gd_eof; /* Rx CRC err good EOF frames */ - u64 undersized_frm; /* Rx undersized frames */ - u64 oversized_frm; /* Rx oversized frames */ - u64 bad_eof_frm; /* Rx frames with bad EOF */ - u64 error_frames; /* Errored frames */ - u64 dropped_frames; /* Dropped frames */ - u64 link_failures; /* Link Failure (LF) count */ - u64 loss_of_syncs; /* Loss of sync count */ - u64 loss_of_signals; /* Loss of signal count */ - u64 primseq_errs; /* Primitive sequence protocol err. */ - u64 bad_os_count; /* Invalid ordered sets */ - u64 err_enc_out; /* Encoding err nonframe_8b10b */ - u64 err_enc; /* Encoding err frame_8b10b */ - u64 bbsc_frames_lost; /* Credit Recovery-Frames Lost */ - u64 bbsc_credits_lost; /* Credit Recovery-Credits Lost */ - u64 bbsc_link_resets; /* Credit Recovery-Link Resets */ -}; - -/* - * Eth Physical Port statistics. - */ -struct bfa_port_eth_stats_s { - u64 secs_reset; /* Seconds since stats is reset */ - u64 frame_64; /* Frames 64 bytes */ - u64 frame_65_127; /* Frames 65-127 bytes */ - u64 frame_128_255; /* Frames 128-255 bytes */ - u64 frame_256_511; /* Frames 256-511 bytes */ - u64 frame_512_1023; /* Frames 512-1023 bytes */ - u64 frame_1024_1518; /* Frames 1024-1518 bytes */ - u64 frame_1519_1522; /* Frames 1519-1522 bytes */ - u64 tx_bytes; /* Tx bytes */ - u64 tx_packets; /* Tx packets */ - u64 tx_mcast_packets; /* Tx multicast packets */ - u64 tx_bcast_packets; /* Tx broadcast packets */ - u64 tx_control_frame; /* Tx control frame */ - u64 tx_drop; /* Tx drops */ - u64 tx_jabber; /* Tx jabber */ - u64 tx_fcs_error; /* Tx FCS errors */ - u64 tx_fragments; /* Tx fragments */ - u64 rx_bytes; /* Rx bytes */ - u64 rx_packets; /* Rx packets */ - u64 rx_mcast_packets; /* Rx multicast packets */ - u64 rx_bcast_packets; /* Rx broadcast packets */ - u64 rx_control_frames; /* Rx control frames */ - u64 rx_unknown_opcode; /* Rx unknown opcode */ - u64 rx_drop; /* Rx drops */ - u64 rx_jabber; /* Rx jabber */ - u64 rx_fcs_error; /* Rx FCS errors */ - u64 rx_alignment_error; /* Rx alignment errors */ - u64 rx_frame_length_error; /* Rx frame len errors */ - u64 rx_code_error; /* Rx code errors */ - u64 rx_fragments; /* Rx fragments */ - u64 rx_pause; /* Rx pause */ - u64 rx_zero_pause; /* Rx zero pause */ - u64 tx_pause; /* Tx pause */ - u64 tx_zero_pause; /* Tx zero pause */ - u64 rx_fcoe_pause; /* Rx FCoE pause */ - u64 rx_fcoe_zero_pause; /* Rx FCoE zero pause */ - u64 tx_fcoe_pause; /* Tx FCoE pause */ - u64 tx_fcoe_zero_pause; /* Tx FCoE zero pause */ - u64 rx_iscsi_pause; /* Rx iSCSI pause */ - u64 rx_iscsi_zero_pause; /* Rx iSCSI zero pause */ - u64 tx_iscsi_pause; /* Tx iSCSI pause */ - u64 tx_iscsi_zero_pause; /* Tx iSCSI zero pause */ -}; - -/* - * Port statistics. - */ -union bfa_port_stats_u { - struct bfa_port_fc_stats_s fc; - struct bfa_port_eth_stats_s eth; -}; - -struct bfa_port_cfg_mode_s { - u16 max_pf; - u16 max_vf; - enum bfa_mode_s mode; -}; - -#pragma pack(1) - -#define BFA_CEE_LLDP_MAX_STRING_LEN (128) -#define BFA_CEE_DCBX_MAX_PRIORITY (8) -#define BFA_CEE_DCBX_MAX_PGID (8) - -struct bfa_cee_lldp_str_s { - u8 sub_type; - u8 len; - u8 rsvd[2]; - u8 value[BFA_CEE_LLDP_MAX_STRING_LEN]; -}; - -struct bfa_cee_lldp_cfg_s { - struct bfa_cee_lldp_str_s chassis_id; - struct bfa_cee_lldp_str_s port_id; - struct bfa_cee_lldp_str_s port_desc; - struct bfa_cee_lldp_str_s sys_name; - struct bfa_cee_lldp_str_s sys_desc; - struct bfa_cee_lldp_str_s mgmt_addr; - u16 time_to_live; - u16 enabled_system_cap; -}; - -/* CEE/DCBX parameters */ -struct bfa_cee_dcbx_cfg_s { - u8 pgid[BFA_CEE_DCBX_MAX_PRIORITY]; - u8 pg_percentage[BFA_CEE_DCBX_MAX_PGID]; - u8 pfc_primap; /* bitmap of priorties with PFC enabled */ - u8 fcoe_primap; /* bitmap of priorities used for FcoE traffic */ - u8 iscsi_primap; /* bitmap of priorities used for iSCSI traffic */ - u8 dcbx_version; /* operating version:CEE or preCEE */ - u8 lls_fcoe; /* FCoE Logical Link Status */ - u8 lls_lan; /* LAN Logical Link Status */ - u8 rsvd[2]; -}; - -/* CEE Query */ -struct bfa_cee_attr_s { - u8 cee_status; - u8 error_reason; - struct bfa_cee_lldp_cfg_s lldp_remote; - struct bfa_cee_dcbx_cfg_s dcbx_remote; - mac_t src_mac; - u8 link_speed; - u8 nw_priority; - u8 filler[2]; -}; - -/* LLDP/DCBX/CEE Statistics */ -struct bfa_cee_stats_s { - u32 lldp_tx_frames; /* LLDP Tx Frames */ - u32 lldp_rx_frames; /* LLDP Rx Frames */ - u32 lldp_rx_frames_invalid; /* LLDP Rx Frames invalid */ - u32 lldp_rx_frames_new; /* LLDP Rx Frames new */ - u32 lldp_tlvs_unrecognized; /* LLDP Rx unrecog. TLVs */ - u32 lldp_rx_shutdown_tlvs; /* LLDP Rx shutdown TLVs */ - u32 lldp_info_aged_out; /* LLDP remote info aged */ - u32 dcbx_phylink_ups; /* DCBX phy link ups */ - u32 dcbx_phylink_downs; /* DCBX phy link downs */ - u32 dcbx_rx_tlvs; /* DCBX Rx TLVs */ - u32 dcbx_rx_tlvs_invalid; /* DCBX Rx TLVs invalid */ - u32 dcbx_control_tlv_error; /* DCBX control TLV errors */ - u32 dcbx_feature_tlv_error; /* DCBX feature TLV errors */ - u32 dcbx_cee_cfg_new; /* DCBX new CEE cfg rcvd */ - u32 cee_status_down; /* DCB status down */ - u32 cee_status_up; /* DCB status up */ - u32 cee_hw_cfg_changed; /* DCB hw cfg changed */ - u32 cee_rx_invalid_cfg; /* DCB invalid cfg */ -}; - -#pragma pack() - -/* - * AEN related definitions - */ -#define BFAD_NL_VENDOR_ID (((u64)0x01 << SCSI_NL_VID_TYPE_SHIFT) \ - | BFA_PCI_VENDOR_ID_BROCADE) - -/* BFA remote port events */ -enum bfa_rport_aen_event { - BFA_RPORT_AEN_ONLINE = 1, /* RPort online event */ - BFA_RPORT_AEN_OFFLINE = 2, /* RPort offline event */ - BFA_RPORT_AEN_DISCONNECT = 3, /* RPort disconnect event */ - BFA_RPORT_AEN_QOS_PRIO = 4, /* QOS priority change event */ - BFA_RPORT_AEN_QOS_FLOWID = 5, /* QOS flow Id change event */ -}; - -struct bfa_rport_aen_data_s { - u16 vf_id; /* vf_id of this logical port */ - u16 rsvd[3]; - wwn_t ppwwn; /* WWN of its physical port */ - wwn_t lpwwn; /* WWN of this logical port */ - wwn_t rpwwn; /* WWN of this remote port */ - union { - struct bfa_rport_qos_attr_s qos; - } priv; -}; - -union bfa_aen_data_u { - struct bfa_adapter_aen_data_s adapter; - struct bfa_port_aen_data_s port; - struct bfa_lport_aen_data_s lport; - struct bfa_rport_aen_data_s rport; - struct bfa_itnim_aen_data_s itnim; - struct bfa_audit_aen_data_s audit; - struct bfa_ioc_aen_data_s ioc; -}; - -#define BFA_AEN_MAX_ENTRY 512 - -struct bfa_aen_entry_s { - struct list_head qe; - enum bfa_aen_category aen_category; - u32 aen_type; - union bfa_aen_data_u aen_data; - struct timeval aen_tv; - u32 seq_num; - u32 bfad_num; -}; - -#endif /* __BFA_DEFS_SVC_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fc.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fc.h deleted file mode 100644 index 8d0b88f6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fc.h +++ /dev/null @@ -1,1598 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FC_H__ -#define __BFA_FC_H__ - -#include "bfad_drv.h" - -typedef u64 wwn_t; - -#define WWN_NULL (0) -#define FC_SYMNAME_MAX 256 /* max name server symbolic name size */ - -#pragma pack(1) - -#define MAC_ADDRLEN (6) -struct mac_s { u8 mac[MAC_ADDRLEN]; }; -#define mac_t struct mac_s - -/* - * generic SCSI cdb definition - */ -#define SCSI_MAX_CDBLEN 16 -struct scsi_cdb_s { - u8 scsi_cdb[SCSI_MAX_CDBLEN]; -}; - -/* ------------------------------------------------------------ - * SCSI status byte values - * ------------------------------------------------------------ - */ -#define SCSI_STATUS_GOOD 0x00 -#define SCSI_STATUS_CHECK_CONDITION 0x02 -#define SCSI_STATUS_CONDITION_MET 0x04 -#define SCSI_STATUS_BUSY 0x08 -#define SCSI_STATUS_INTERMEDIATE 0x10 -#define SCSI_STATUS_ICM 0x14 /* intermediate condition met */ -#define SCSI_STATUS_RESERVATION_CONFLICT 0x18 -#define SCSI_STATUS_COMMAND_TERMINATED 0x22 -#define SCSI_STATUS_QUEUE_FULL 0x28 -#define SCSI_STATUS_ACA_ACTIVE 0x30 - -#define SCSI_MAX_ALLOC_LEN 0xFF /* maximum allocarion length */ - -/* - * Fibre Channel Header Structure (FCHS) definition - */ -struct fchs_s { -#ifdef __BIG_ENDIAN - u32 routing:4; /* routing bits */ - u32 cat_info:4; /* category info */ -#else - u32 cat_info:4; /* category info */ - u32 routing:4; /* routing bits */ -#endif - u32 d_id:24; /* destination identifier */ - - u32 cs_ctl:8; /* class specific control */ - u32 s_id:24; /* source identifier */ - - u32 type:8; /* data structure type */ - u32 f_ctl:24; /* initial frame control */ - - u8 seq_id; /* sequence identifier */ - u8 df_ctl; /* data field control */ - u16 seq_cnt; /* sequence count */ - - __be16 ox_id; /* originator exchange ID */ - u16 rx_id; /* responder exchange ID */ - - u32 ro; /* relative offset */ -}; - -/* - * routing bit definitions - */ -enum { - FC_RTG_FC4_DEV_DATA = 0x0, /* FC-4 Device Data */ - FC_RTG_EXT_LINK = 0x2, /* Extended Link Data */ - FC_RTG_FC4_LINK_DATA = 0x3, /* FC-4 Link Data */ - FC_RTG_VIDEO_DATA = 0x4, /* Video Data */ - FC_RTG_EXT_HDR = 0x5, /* VFT, IFR or Encapsuled */ - FC_RTG_BASIC_LINK = 0x8, /* Basic Link data */ - FC_RTG_LINK_CTRL = 0xC, /* Link Control */ -}; - -/* - * information category for extended link data and FC-4 Link Data - */ -enum { - FC_CAT_LD_REQUEST = 0x2, /* Request */ - FC_CAT_LD_REPLY = 0x3, /* Reply */ - FC_CAT_LD_DIAG = 0xF, /* for DIAG use only */ -}; - -/* - * information category for extended headers (VFT, IFR or encapsulation) - */ -enum { - FC_CAT_VFT_HDR = 0x0, /* Virtual fabric tagging header */ - FC_CAT_IFR_HDR = 0x1, /* Inter-Fabric routing header */ - FC_CAT_ENC_HDR = 0x2, /* Encapsulation header */ -}; - -/* - * information category for FC-4 device data - */ -enum { - FC_CAT_UNCATEG_INFO = 0x0, /* Uncategorized information */ - FC_CAT_SOLICIT_DATA = 0x1, /* Solicited Data */ - FC_CAT_UNSOLICIT_CTRL = 0x2, /* Unsolicited Control */ - FC_CAT_SOLICIT_CTRL = 0x3, /* Solicited Control */ - FC_CAT_UNSOLICIT_DATA = 0x4, /* Unsolicited Data */ - FC_CAT_DATA_DESC = 0x5, /* Data Descriptor */ - FC_CAT_UNSOLICIT_CMD = 0x6, /* Unsolicited Command */ - FC_CAT_CMD_STATUS = 0x7, /* Command Status */ -}; - -/* - * Type Field Definitions. FC-PH Section 18.5 pg. 165 - */ -enum { - FC_TYPE_BLS = 0x0, /* Basic Link Service */ - FC_TYPE_ELS = 0x1, /* Extended Link Service */ - FC_TYPE_IP = 0x5, /* IP */ - FC_TYPE_FCP = 0x8, /* SCSI-FCP */ - FC_TYPE_GPP = 0x9, /* SCSI_GPP */ - FC_TYPE_SERVICES = 0x20, /* Fibre Channel Services */ - FC_TYPE_FC_FSS = 0x22, /* Fabric Switch Services */ - FC_TYPE_FC_AL = 0x23, /* FC-AL */ - FC_TYPE_FC_SNMP = 0x24, /* FC-SNMP */ - FC_TYPE_FC_SPINFAB = 0xEE, /* SPINFAB */ - FC_TYPE_FC_DIAG = 0xEF, /* DIAG */ - FC_TYPE_MAX = 256, /* 256 FC-4 types */ -}; - -/* - * Frame Control Definitions. FC-PH Table-45. pg. 168 - */ -enum { - FCTL_EC_ORIG = 0x000000, /* exchange originator */ - FCTL_EC_RESP = 0x800000, /* exchange responder */ - FCTL_SEQ_INI = 0x000000, /* sequence initiator */ - FCTL_SEQ_REC = 0x400000, /* sequence recipient */ - FCTL_FS_EXCH = 0x200000, /* first sequence of xchg */ - FCTL_LS_EXCH = 0x100000, /* last sequence of xchg */ - FCTL_END_SEQ = 0x080000, /* last frame of sequence */ - FCTL_SI_XFER = 0x010000, /* seq initiative transfer */ - FCTL_RO_PRESENT = 0x000008, /* relative offset present */ - FCTL_FILLBYTE_MASK = 0x000003 /* , fill byte mask */ -}; - -/* - * Fabric Well Known Addresses - */ -enum { - FC_MIN_WELL_KNOWN_ADDR = 0xFFFFF0, - FC_DOMAIN_CONTROLLER_MASK = 0xFFFC00, - FC_ALIAS_SERVER = 0xFFFFF8, - FC_MGMT_SERVER = 0xFFFFFA, - FC_TIME_SERVER = 0xFFFFFB, - FC_NAME_SERVER = 0xFFFFFC, - FC_FABRIC_CONTROLLER = 0xFFFFFD, - FC_FABRIC_PORT = 0xFFFFFE, - FC_BROADCAST_SERVER = 0xFFFFFF -}; - -/* - * domain/area/port defines - */ -#define FC_DOMAIN_MASK 0xFF0000 -#define FC_DOMAIN_SHIFT 16 -#define FC_AREA_MASK 0x00FF00 -#define FC_AREA_SHIFT 8 -#define FC_PORT_MASK 0x0000FF -#define FC_PORT_SHIFT 0 - -#define FC_GET_DOMAIN(p) (((p) & FC_DOMAIN_MASK) >> FC_DOMAIN_SHIFT) -#define FC_GET_AREA(p) (((p) & FC_AREA_MASK) >> FC_AREA_SHIFT) -#define FC_GET_PORT(p) (((p) & FC_PORT_MASK) >> FC_PORT_SHIFT) - -#define FC_DOMAIN_CTRLR(p) (FC_DOMAIN_CONTROLLER_MASK | (FC_GET_DOMAIN(p))) - -enum { - FC_RXID_ANY = 0xFFFFU, -}; - -/* - * generic ELS command - */ -struct fc_els_cmd_s { - u32 els_code:8; /* ELS Command Code */ - u32 reserved:24; -}; - -/* - * ELS Command Codes. FC-PH Table-75. pg. 223 - */ -enum { - FC_ELS_LS_RJT = 0x1, /* Link Service Reject. */ - FC_ELS_ACC = 0x02, /* Accept */ - FC_ELS_PLOGI = 0x03, /* N_Port Login. */ - FC_ELS_FLOGI = 0x04, /* F_Port Login. */ - FC_ELS_LOGO = 0x05, /* Logout. */ - FC_ELS_ABTX = 0x06, /* Abort Exchange */ - FC_ELS_RES = 0x08, /* Read Exchange status */ - FC_ELS_RSS = 0x09, /* Read sequence status block */ - FC_ELS_RSI = 0x0A, /* Request Sequence Initiative */ - FC_ELS_ESTC = 0x0C, /* Estimate Credit. */ - FC_ELS_RTV = 0x0E, /* Read Timeout Value. */ - FC_ELS_RLS = 0x0F, /* Read Link Status. */ - FC_ELS_ECHO = 0x10, /* Echo */ - FC_ELS_TEST = 0x11, /* Test */ - FC_ELS_RRQ = 0x12, /* Reinstate Recovery Qualifier. */ - FC_ELS_REC = 0x13, /* Add this for TAPE support in FCR */ - FC_ELS_PRLI = 0x20, /* Process Login */ - FC_ELS_PRLO = 0x21, /* Process Logout. */ - FC_ELS_SCN = 0x22, /* State Change Notification. */ - FC_ELS_TPRLO = 0x24, /* Third Party Process Logout. */ - FC_ELS_PDISC = 0x50, /* Discover N_Port Parameters. */ - FC_ELS_FDISC = 0x51, /* Discover F_Port Parameters. */ - FC_ELS_ADISC = 0x52, /* Discover Address. */ - FC_ELS_FARP_REQ = 0x54, /* FARP Request. */ - FC_ELS_FARP_REP = 0x55, /* FARP Reply. */ - FC_ELS_FAN = 0x60, /* Fabric Address Notification */ - FC_ELS_RSCN = 0x61, /* Reg State Change Notification */ - FC_ELS_SCR = 0x62, /* State Change Registration. */ - FC_ELS_RTIN = 0x77, /* Mangement server request */ - FC_ELS_RNID = 0x78, /* Mangement server request */ - FC_ELS_RLIR = 0x79, /* Registered Link Incident Record */ - - FC_ELS_RPSC = 0x7D, /* Report Port Speed Capabilities */ - FC_ELS_QSA = 0x7E, /* Query Security Attributes. Ref FC-SP */ - FC_ELS_E2E_LBEACON = 0x81, - /* End-to-End Link Beacon */ - FC_ELS_AUTH = 0x90, /* Authentication. Ref FC-SP */ - FC_ELS_RFCN = 0x97, /* Request Fabric Change Notification. Ref - *FC-SP */ -}; - -/* - * Version numbers for FC-PH standards, - * used in login to indicate what port - * supports. See FC-PH-X table 158. - */ -enum { - FC_PH_VER_4_3 = 0x09, - FC_PH_VER_PH_3 = 0x20, -}; - -/* - * PDU size defines - */ -enum { - FC_MIN_PDUSZ = 512, - FC_MAX_PDUSZ = 2112, -}; - -/* - * N_Port PLOGI Common Service Parameters. - * FC-PH-x. Figure-76. pg. 308. - */ -struct fc_plogi_csp_s { - u8 verhi; /* FC-PH high version */ - u8 verlo; /* FC-PH low version */ - __be16 bbcred; /* BB_Credit */ - -#ifdef __BIG_ENDIAN - u8 ciro:1, /* continuously increasing RO */ - rro:1, /* random relative offset */ - npiv_supp:1, /* NPIV supported */ - port_type:1, /* N_Port/F_port */ - altbbcred:1, /* alternate BB_Credit */ - resolution:1, /* ms/ns ED_TOV resolution */ - vvl_info:1, /* VVL Info included */ - reserved1:1; - - u8 hg_supp:1, - query_dbc:1, - security:1, - sync_cap:1, - r_t_tov:1, - dh_dup_supp:1, - cisc:1, /* continuously increasing seq count */ - payload:1; -#else - u8 reserved2:2, - resolution:1, /* ms/ns ED_TOV resolution */ - altbbcred:1, /* alternate BB_Credit */ - port_type:1, /* N_Port/F_port */ - npiv_supp:1, /* NPIV supported */ - rro:1, /* random relative offset */ - ciro:1; /* continuously increasing RO */ - - u8 payload:1, - cisc:1, /* continuously increasing seq count */ - dh_dup_supp:1, - r_t_tov:1, - sync_cap:1, - security:1, - query_dbc:1, - hg_supp:1; -#endif - __be16 rxsz; /* receive data_field size */ - __be16 conseq; - __be16 ro_bitmap; - __be32 e_d_tov; -}; - -/* - * N_Port PLOGI Class Specific Parameters. - * FC-PH-x. Figure 78. pg. 318. - */ -struct fc_plogi_clp_s { -#ifdef __BIG_ENDIAN - u32 class_valid:1; - u32 intermix:1; /* class intermix supported if set =1. - * valid only for class1. Reserved for - * class2 & class3 */ - u32 reserved1:2; - u32 sequential:1; - u32 reserved2:3; -#else - u32 reserved2:3; - u32 sequential:1; - u32 reserved1:2; - u32 intermix:1; /* class intermix supported if set =1. - * valid only for class1. Reserved for - * class2 & class3 */ - u32 class_valid:1; -#endif - u32 reserved3:24; - - u32 reserved4:16; - u32 rxsz:16; /* Receive data_field size */ - - u32 reserved5:8; - u32 conseq:8; - u32 e2e_credit:16; /* end to end credit */ - - u32 reserved7:8; - u32 ospx:8; - u32 reserved8:16; -}; - -/* ASCII value for each character in string "BRCD" */ -#define FLOGI_VVL_BRCD 0x42524344 - -/* - * PLOGI els command and reply payload - */ -struct fc_logi_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - struct fc_plogi_csp_s csp; /* common service params */ - wwn_t port_name; - wwn_t node_name; - struct fc_plogi_clp_s class1; /* class 1 service parameters */ - struct fc_plogi_clp_s class2; /* class 2 service parameters */ - struct fc_plogi_clp_s class3; /* class 3 service parameters */ - struct fc_plogi_clp_s class4; /* class 4 service parameters */ - u8 vvl[16]; /* vendor version level */ -}; - -/* - * LOGO els command payload - */ -struct fc_logo_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - u32 res1:8; - u32 nport_id:24; /* N_Port identifier of source */ - wwn_t orig_port_name; /* Port name of the LOGO originator */ -}; - -/* - * ADISC els command payload - */ -struct fc_adisc_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - u32 res1:8; - u32 orig_HA:24; /* originator hard address */ - wwn_t orig_port_name; /* originator port name */ - wwn_t orig_node_name; /* originator node name */ - u32 res2:8; - u32 nport_id:24; /* originator NPortID */ -}; - -/* - * Exchange status block - */ -struct fc_exch_status_blk_s { - u32 oxid:16; - u32 rxid:16; - u32 res1:8; - u32 orig_np:24; /* originator NPortID */ - u32 res2:8; - u32 resp_np:24; /* responder NPortID */ - u32 es_bits; - u32 res3; - /* - * un modified section of the fields - */ -}; - -/* - * RES els command payload - */ -struct fc_res_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - u32 res1:8; - u32 nport_id:24; /* N_Port identifier of source */ - u32 oxid:16; - u32 rxid:16; - u8 assoc_hdr[32]; -}; - -/* - * RES els accept payload - */ -struct fc_res_acc_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - struct fc_exch_status_blk_s fc_exch_blk; /* Exchange status block */ -}; - -/* - * REC els command payload - */ -struct fc_rec_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - u32 res1:8; - u32 nport_id:24; /* N_Port identifier of source */ - u32 oxid:16; - u32 rxid:16; -}; - -#define FC_REC_ESB_OWN_RSP 0x80000000 /* responder owns */ -#define FC_REC_ESB_SI 0x40000000 /* SI is owned */ -#define FC_REC_ESB_COMP 0x20000000 /* exchange is complete */ -#define FC_REC_ESB_ENDCOND_ABN 0x10000000 /* abnormal ending */ -#define FC_REC_ESB_RQACT 0x04000000 /* recovery qual active */ -#define FC_REC_ESB_ERRP_MSK 0x03000000 -#define FC_REC_ESB_OXID_INV 0x00800000 /* invalid OXID */ -#define FC_REC_ESB_RXID_INV 0x00400000 /* invalid RXID */ -#define FC_REC_ESB_PRIO_INUSE 0x00200000 - -/* - * REC els accept payload - */ -struct fc_rec_acc_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - u32 oxid:16; - u32 rxid:16; - u32 res1:8; - u32 orig_id:24; /* N_Port id of exchange originator */ - u32 res2:8; - u32 resp_id:24; /* N_Port id of exchange responder */ - u32 count; /* data transfer count */ - u32 e_stat; /* exchange status */ -}; - -/* - * RSI els payload - */ -struct fc_rsi_s { - struct fc_els_cmd_s els_cmd; - u32 res1:8; - u32 orig_sid:24; - u32 oxid:16; - u32 rxid:16; -}; - -/* - * structure for PRLI paramater pages, both request & response - * see FC-PH-X table 113 & 115 for explanation also FCP table 8 - */ -struct fc_prli_params_s { - u32 reserved:16; -#ifdef __BIG_ENDIAN - u32 reserved1:5; - u32 rec_support:1; - u32 task_retry_id:1; - u32 retry:1; - - u32 confirm:1; - u32 doverlay:1; - u32 initiator:1; - u32 target:1; - u32 cdmix:1; - u32 drmix:1; - u32 rxrdisab:1; - u32 wxrdisab:1; -#else - u32 retry:1; - u32 task_retry_id:1; - u32 rec_support:1; - u32 reserved1:5; - - u32 wxrdisab:1; - u32 rxrdisab:1; - u32 drmix:1; - u32 cdmix:1; - u32 target:1; - u32 initiator:1; - u32 doverlay:1; - u32 confirm:1; -#endif -}; - -/* - * valid values for rspcode in PRLI ACC payload - */ -enum { - FC_PRLI_ACC_XQTD = 0x1, /* request executed */ - FC_PRLI_ACC_PREDEF_IMG = 0x5, /* predefined image - no prli needed */ -}; - -struct fc_prli_params_page_s { - u32 type:8; - u32 codext:8; -#ifdef __BIG_ENDIAN - u32 origprocasv:1; - u32 rsppav:1; - u32 imagepair:1; - u32 reserved1:1; - u32 rspcode:4; -#else - u32 rspcode:4; - u32 reserved1:1; - u32 imagepair:1; - u32 rsppav:1; - u32 origprocasv:1; -#endif - u32 reserved2:8; - - u32 origprocas; - u32 rspprocas; - struct fc_prli_params_s servparams; -}; - -/* - * PRLI request and accept payload, FC-PH-X tables 112 & 114 - */ -struct fc_prli_s { - u32 command:8; - u32 pglen:8; - u32 pagebytes:16; - struct fc_prli_params_page_s parampage; -}; - -/* - * PRLO logout params page - */ -struct fc_prlo_params_page_s { - u32 type:8; - u32 type_ext:8; -#ifdef __BIG_ENDIAN - u32 opa_valid:1; /* originator process associator valid */ - u32 rpa_valid:1; /* responder process associator valid */ - u32 res1:14; -#else - u32 res1:14; - u32 rpa_valid:1; /* responder process associator valid */ - u32 opa_valid:1; /* originator process associator valid */ -#endif - u32 orig_process_assc; - u32 resp_process_assc; - - u32 res2; -}; - -/* - * PRLO els command payload - */ -struct fc_prlo_s { - u32 command:8; - u32 page_len:8; - u32 payload_len:16; - struct fc_prlo_params_page_s prlo_params[1]; -}; - -/* - * PRLO Logout response parameter page - */ -struct fc_prlo_acc_params_page_s { - u32 type:8; - u32 type_ext:8; - -#ifdef __BIG_ENDIAN - u32 opa_valid:1; /* originator process associator valid */ - u32 rpa_valid:1; /* responder process associator valid */ - u32 res1:14; -#else - u32 res1:14; - u32 rpa_valid:1; /* responder process associator valid */ - u32 opa_valid:1; /* originator process associator valid */ -#endif - u32 orig_process_assc; - u32 resp_process_assc; - - u32 fc4type_csp; -}; - -/* - * PRLO els command ACC payload - */ -struct fc_prlo_acc_s { - u32 command:8; - u32 page_len:8; - u32 payload_len:16; - struct fc_prlo_acc_params_page_s prlo_acc_params[1]; -}; - -/* - * SCR els command payload - */ -enum { - FC_SCR_REG_FUNC_FABRIC_DETECTED = 0x01, - FC_SCR_REG_FUNC_N_PORT_DETECTED = 0x02, - FC_SCR_REG_FUNC_FULL = 0x03, - FC_SCR_REG_FUNC_CLEAR_REG = 0xFF, -}; - -/* SCR VU registrations */ -enum { - FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE = 0x01 -}; - -struct fc_scr_s { - u32 command:8; - u32 res:24; - u32 vu_reg_func:8; /* Vendor Unique Registrations */ - u32 res1:16; - u32 reg_func:8; -}; - -/* - * Information category for Basic link data - */ -enum { - FC_CAT_NOP = 0x0, - FC_CAT_ABTS = 0x1, - FC_CAT_RMC = 0x2, - FC_CAT_BA_ACC = 0x4, - FC_CAT_BA_RJT = 0x5, - FC_CAT_PRMT = 0x6, -}; - -/* - * LS_RJT els reply payload - */ -struct fc_ls_rjt_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - u32 res1:8; - u32 reason_code:8; /* Reason code for reject */ - u32 reason_code_expl:8; /* Reason code explanation */ - u32 vendor_unique:8; /* Vendor specific */ -}; - -/* - * LS_RJT reason codes - */ -enum { - FC_LS_RJT_RSN_INV_CMD_CODE = 0x01, - FC_LS_RJT_RSN_LOGICAL_ERROR = 0x03, - FC_LS_RJT_RSN_LOGICAL_BUSY = 0x05, - FC_LS_RJT_RSN_PROTOCOL_ERROR = 0x07, - FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD = 0x09, - FC_LS_RJT_RSN_CMD_NOT_SUPP = 0x0B, -}; - -/* - * LS_RJT reason code explanation - */ -enum { - FC_LS_RJT_EXP_NO_ADDL_INFO = 0x00, - FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS = 0x01, - FC_LS_RJT_EXP_SPARMS_ERR_INI_CTL = 0x03, - FC_LS_RJT_EXP_SPARMS_ERR_REC_CTL = 0x05, - FC_LS_RJT_EXP_SPARMS_ERR_RXSZ = 0x07, - FC_LS_RJT_EXP_SPARMS_ERR_CONSEQ = 0x09, - FC_LS_RJT_EXP_SPARMS_ERR_CREDIT = 0x0B, - FC_LS_RJT_EXP_INV_PORT_NAME = 0x0D, - FC_LS_RJT_EXP_INV_NODE_FABRIC_NAME = 0x0E, - FC_LS_RJT_EXP_INV_CSP = 0x0F, - FC_LS_RJT_EXP_INV_ASSOC_HDR = 0x11, - FC_LS_RJT_EXP_ASSOC_HDR_REQD = 0x13, - FC_LS_RJT_EXP_INV_ORIG_S_ID = 0x15, - FC_LS_RJT_EXP_INV_OXID_RXID_COMB = 0x17, - FC_LS_RJT_EXP_CMD_ALREADY_IN_PROG = 0x19, - FC_LS_RJT_EXP_LOGIN_REQUIRED = 0x1E, - FC_LS_RJT_EXP_INVALID_NPORT_ID = 0x1F, - FC_LS_RJT_EXP_INSUFF_RES = 0x29, - FC_LS_RJT_EXP_CMD_NOT_SUPP = 0x2C, - FC_LS_RJT_EXP_INV_PAYLOAD_LEN = 0x2D, -}; - -/* - * RRQ els command payload - */ -struct fc_rrq_s { - struct fc_els_cmd_s els_cmd; /* ELS command code */ - u32 res1:8; - u32 s_id:24; /* exchange originator S_ID */ - - u32 ox_id:16; /* originator exchange ID */ - u32 rx_id:16; /* responder exchange ID */ - - u32 res2[8]; /* optional association header */ -}; - -/* - * ABTS BA_ACC reply payload - */ -struct fc_ba_acc_s { - u32 seq_id_valid:8; /* set to 0x00 for Abort Exchange */ - u32 seq_id:8; /* invalid for Abort Exchange */ - u32 res2:16; - u32 ox_id:16; /* OX_ID from ABTS frame */ - u32 rx_id:16; /* RX_ID from ABTS frame */ - u32 low_seq_cnt:16; /* set to 0x0000 for Abort Exchange */ - u32 high_seq_cnt:16; /* set to 0xFFFF for Abort Exchange */ -}; - -/* - * ABTS BA_RJT reject payload - */ -struct fc_ba_rjt_s { - u32 res1:8; /* Reserved */ - u32 reason_code:8; /* reason code for reject */ - u32 reason_expl:8; /* reason code explanation */ - u32 vendor_unique:8; /* vendor unique reason code,set to 0 */ -}; - -/* - * TPRLO logout parameter page - */ -struct fc_tprlo_params_page_s { - u32 type:8; - u32 type_ext:8; - -#ifdef __BIG_ENDIAN - u32 opa_valid:1; - u32 rpa_valid:1; - u32 tpo_nport_valid:1; - u32 global_process_logout:1; - u32 res1:12; -#else - u32 res1:12; - u32 global_process_logout:1; - u32 tpo_nport_valid:1; - u32 rpa_valid:1; - u32 opa_valid:1; -#endif - - u32 orig_process_assc; - u32 resp_process_assc; - - u32 res2:8; - u32 tpo_nport_id; -}; - -/* - * TPRLO ELS command payload - */ -struct fc_tprlo_s { - u32 command:8; - u32 page_len:8; - u32 payload_len:16; - - struct fc_tprlo_params_page_s tprlo_params[1]; -}; - -enum fc_tprlo_type { - FC_GLOBAL_LOGO = 1, - FC_TPR_LOGO -}; - -/* - * TPRLO els command ACC payload - */ -struct fc_tprlo_acc_s { - u32 command:8; - u32 page_len:8; - u32 payload_len:16; - struct fc_prlo_acc_params_page_s tprlo_acc_params[1]; -}; - -/* - * RSCN els command req payload - */ -#define FC_RSCN_PGLEN 0x4 - -enum fc_rscn_format { - FC_RSCN_FORMAT_PORTID = 0x0, - FC_RSCN_FORMAT_AREA = 0x1, - FC_RSCN_FORMAT_DOMAIN = 0x2, - FC_RSCN_FORMAT_FABRIC = 0x3, -}; - -struct fc_rscn_event_s { - u32 format:2; - u32 qualifier:4; - u32 resvd:2; - u32 portid:24; -}; - -struct fc_rscn_pl_s { - u8 command; - u8 pagelen; - __be16 payldlen; - struct fc_rscn_event_s event[1]; -}; - -/* - * ECHO els command req payload - */ -struct fc_echo_s { - struct fc_els_cmd_s els_cmd; -}; - -/* - * RNID els command - */ -#define RNID_NODEID_DATA_FORMAT_COMMON 0x00 -#define RNID_NODEID_DATA_FORMAT_FCP3 0x08 -#define RNID_NODEID_DATA_FORMAT_DISCOVERY 0xDF - -#define RNID_ASSOCIATED_TYPE_UNKNOWN 0x00000001 -#define RNID_ASSOCIATED_TYPE_OTHER 0x00000002 -#define RNID_ASSOCIATED_TYPE_HUB 0x00000003 -#define RNID_ASSOCIATED_TYPE_SWITCH 0x00000004 -#define RNID_ASSOCIATED_TYPE_GATEWAY 0x00000005 -#define RNID_ASSOCIATED_TYPE_STORAGE_DEVICE 0x00000009 -#define RNID_ASSOCIATED_TYPE_HOST 0x0000000A -#define RNID_ASSOCIATED_TYPE_STORAGE_SUBSYSTEM 0x0000000B -#define RNID_ASSOCIATED_TYPE_STORAGE_ACCESS_DEVICE 0x0000000E -#define RNID_ASSOCIATED_TYPE_NAS_SERVER 0x00000011 -#define RNID_ASSOCIATED_TYPE_BRIDGE 0x00000002 -#define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE 0x00000003 -#define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE 0x000000FF - -/* - * RNID els command payload - */ -struct fc_rnid_cmd_s { - struct fc_els_cmd_s els_cmd; - u32 node_id_data_format:8; - u32 reserved:24; -}; - -/* - * RNID els response payload - */ - -struct fc_rnid_common_id_data_s { - wwn_t port_name; - wwn_t node_name; -}; - -struct fc_rnid_general_topology_data_s { - u32 vendor_unique[4]; - __be32 asso_type; - u32 phy_port_num; - __be32 num_attached_nodes; - u32 node_mgmt:8; - u32 ip_version:8; - u32 udp_tcp_port_num:16; - u32 ip_address[4]; - u32 reserved:16; - u32 vendor_specific:16; -}; - -struct fc_rnid_acc_s { - struct fc_els_cmd_s els_cmd; - u32 node_id_data_format:8; - u32 common_id_data_length:8; - u32 reserved:8; - u32 specific_id_data_length:8; - struct fc_rnid_common_id_data_s common_id_data; - struct fc_rnid_general_topology_data_s gen_topology_data; -}; - -#define RNID_ASSOCIATED_TYPE_UNKNOWN 0x00000001 -#define RNID_ASSOCIATED_TYPE_OTHER 0x00000002 -#define RNID_ASSOCIATED_TYPE_HUB 0x00000003 -#define RNID_ASSOCIATED_TYPE_SWITCH 0x00000004 -#define RNID_ASSOCIATED_TYPE_GATEWAY 0x00000005 -#define RNID_ASSOCIATED_TYPE_STORAGE_DEVICE 0x00000009 -#define RNID_ASSOCIATED_TYPE_HOST 0x0000000A -#define RNID_ASSOCIATED_TYPE_STORAGE_SUBSYSTEM 0x0000000B -#define RNID_ASSOCIATED_TYPE_STORAGE_ACCESS_DEVICE 0x0000000E -#define RNID_ASSOCIATED_TYPE_NAS_SERVER 0x00000011 -#define RNID_ASSOCIATED_TYPE_BRIDGE 0x00000002 -#define RNID_ASSOCIATED_TYPE_VIRTUALIZATION_DEVICE 0x00000003 -#define RNID_ASSOCIATED_TYPE_MULTI_FUNCTION_DEVICE 0x000000FF - -enum fc_rpsc_speed_cap { - RPSC_SPEED_CAP_1G = 0x8000, - RPSC_SPEED_CAP_2G = 0x4000, - RPSC_SPEED_CAP_4G = 0x2000, - RPSC_SPEED_CAP_10G = 0x1000, - RPSC_SPEED_CAP_8G = 0x0800, - RPSC_SPEED_CAP_16G = 0x0400, - - RPSC_SPEED_CAP_UNKNOWN = 0x0001, -}; - -enum fc_rpsc_op_speed { - RPSC_OP_SPEED_1G = 0x8000, - RPSC_OP_SPEED_2G = 0x4000, - RPSC_OP_SPEED_4G = 0x2000, - RPSC_OP_SPEED_10G = 0x1000, - RPSC_OP_SPEED_8G = 0x0800, - RPSC_OP_SPEED_16G = 0x0400, - - RPSC_OP_SPEED_NOT_EST = 0x0001, /* speed not established */ -}; - -struct fc_rpsc_speed_info_s { - __be16 port_speed_cap; /* see enum fc_rpsc_speed_cap */ - __be16 port_op_speed; /* see enum fc_rpsc_op_speed */ -}; - -/* - * If RPSC request is sent to the Domain Controller, the request is for - * all the ports within that domain. - */ -struct fc_rpsc_cmd_s { - struct fc_els_cmd_s els_cmd; -}; - -/* - * RPSC Acc - */ -struct fc_rpsc_acc_s { - u32 command:8; - u32 rsvd:8; - u32 num_entries:16; - - struct fc_rpsc_speed_info_s speed_info[1]; -}; - -/* - * If RPSC2 request is sent to the Domain Controller, - */ -#define FC_BRCD_TOKEN 0x42524344 - -struct fc_rpsc2_cmd_s { - struct fc_els_cmd_s els_cmd; - __be32 token; - u16 resvd; - __be16 num_pids; /* Number of pids in the request */ - struct { - u32 rsvd1:8; - u32 pid:24; /* port identifier */ - } pid_list[1]; -}; - -enum fc_rpsc2_port_type { - RPSC2_PORT_TYPE_UNKNOWN = 0, - RPSC2_PORT_TYPE_NPORT = 1, - RPSC2_PORT_TYPE_NLPORT = 2, - RPSC2_PORT_TYPE_NPIV_PORT = 0x5f, - RPSC2_PORT_TYPE_NPORT_TRUNK = 0x6f, -}; - -/* - * RPSC2 portInfo entry structure - */ -struct fc_rpsc2_port_info_s { - __be32 pid; /* PID */ - u16 resvd1; - __be16 index; /* port number / index */ - u8 resvd2; - u8 type; /* port type N/NL/... */ - __be16 speed; /* port Operating Speed */ -}; - -/* - * RPSC2 Accept payload - */ -struct fc_rpsc2_acc_s { - u8 els_cmd; - u8 resvd; - __be16 num_pids; /* Number of pids in the request */ - struct fc_rpsc2_port_info_s port_info[1]; /* port information */ -}; - -/* - * bit fields so that multiple classes can be specified - */ -enum fc_cos { - FC_CLASS_2 = 0x04, - FC_CLASS_3 = 0x08, - FC_CLASS_2_3 = 0x0C, -}; - -/* - * symbolic name - */ -struct fc_symname_s { - u8 symname[FC_SYMNAME_MAX]; -}; - -/* - * protocol default timeout values - */ -#define FC_ED_TOV 2 -#define FC_REC_TOV (FC_ED_TOV + 1) -#define FC_RA_TOV 10 -#define FC_ELS_TOV ((2 * FC_RA_TOV) + 1) -#define FC_FCCT_TOV (3 * FC_RA_TOV) - -/* - * virtual fabric related defines - */ -#define FC_VF_ID_NULL 0 /* must not be used as VF_ID */ -#define FC_VF_ID_MIN 1 -#define FC_VF_ID_MAX 0xEFF -#define FC_VF_ID_CTL 0xFEF /* control VF_ID */ - -/* - * Virtual Fabric Tagging header format - * @caution This is defined only in BIG ENDIAN format. - */ -struct fc_vft_s { - u32 r_ctl:8; - u32 ver:2; - u32 type:4; - u32 res_a:2; - u32 priority:3; - u32 vf_id:12; - u32 res_b:1; - u32 hopct:8; - u32 res_c:24; -}; - -/* - * FCP_CMND definitions - */ -#define FCP_CMND_CDB_LEN 16 -#define FCP_CMND_LUN_LEN 8 - -struct fcp_cmnd_s { - struct scsi_lun lun; /* 64-bit LU number */ - u8 crn; /* command reference number */ -#ifdef __BIG_ENDIAN - u8 resvd:1, - priority:4, /* FCP-3: SAM-3 priority */ - taskattr:3; /* scsi task attribute */ -#else - u8 taskattr:3, /* scsi task attribute */ - priority:4, /* FCP-3: SAM-3 priority */ - resvd:1; -#endif - u8 tm_flags; /* task management flags */ -#ifdef __BIG_ENDIAN - u8 addl_cdb_len:6, /* additional CDB length words */ - iodir:2; /* read/write FCP_DATA IUs */ -#else - u8 iodir:2, /* read/write FCP_DATA IUs */ - addl_cdb_len:6; /* additional CDB length */ -#endif - struct scsi_cdb_s cdb; - - __be32 fcp_dl; /* bytes to be transferred */ -}; - -#define fcp_cmnd_cdb_len(_cmnd) ((_cmnd)->addl_cdb_len * 4 + FCP_CMND_CDB_LEN) -#define fcp_cmnd_fcpdl(_cmnd) ((&(_cmnd)->fcp_dl)[(_cmnd)->addl_cdb_len]) - -/* - * struct fcp_cmnd_s .iodir field values - */ -enum fcp_iodir { - FCP_IODIR_NONE = 0, - FCP_IODIR_WRITE = 1, - FCP_IODIR_READ = 2, - FCP_IODIR_RW = 3, -}; - -/* - * Task management flags field - only one bit shall be set - */ -enum fcp_tm_cmnd { - FCP_TM_ABORT_TASK_SET = BIT(1), - FCP_TM_CLEAR_TASK_SET = BIT(2), - FCP_TM_LUN_RESET = BIT(4), - FCP_TM_TARGET_RESET = BIT(5), /* obsolete in FCP-3 */ - FCP_TM_CLEAR_ACA = BIT(6), -}; - -/* - * FCP_RSP residue flags - */ -enum fcp_residue { - FCP_NO_RESIDUE = 0, /* no residue */ - FCP_RESID_OVER = 1, /* more data left that was not sent */ - FCP_RESID_UNDER = 2, /* less data than requested */ -}; - -struct fcp_rspinfo_s { - u32 res0:24; - u32 rsp_code:8; /* response code (as above) */ - u32 res1; -}; - -struct fcp_resp_s { - u32 reserved[2]; /* 2 words reserved */ - u16 reserved2; -#ifdef __BIG_ENDIAN - u8 reserved3:3; - u8 fcp_conf_req:1; /* FCP_CONF is requested */ - u8 resid_flags:2; /* underflow/overflow */ - u8 sns_len_valid:1; /* sense len is valid */ - u8 rsp_len_valid:1; /* response len is valid */ -#else - u8 rsp_len_valid:1; /* response len is valid */ - u8 sns_len_valid:1; /* sense len is valid */ - u8 resid_flags:2; /* underflow/overflow */ - u8 fcp_conf_req:1; /* FCP_CONF is requested */ - u8 reserved3:3; -#endif - u8 scsi_status; /* one byte SCSI status */ - u32 residue; /* residual data bytes */ - u32 sns_len; /* length od sense info */ - u32 rsp_len; /* length of response info */ -}; - -#define fcp_snslen(__fcprsp) ((__fcprsp)->sns_len_valid ? \ - (__fcprsp)->sns_len : 0) -#define fcp_rsplen(__fcprsp) ((__fcprsp)->rsp_len_valid ? \ - (__fcprsp)->rsp_len : 0) -#define fcp_rspinfo(__fcprsp) ((struct fcp_rspinfo_s *)((__fcprsp) + 1)) -#define fcp_snsinfo(__fcprsp) (((u8 *)fcp_rspinfo(__fcprsp)) + \ - fcp_rsplen(__fcprsp)) -/* - * CT - */ -struct ct_hdr_s { - u32 rev_id:8; /* Revision of the CT */ - u32 in_id:24; /* Initiator Id */ - u32 gs_type:8; /* Generic service Type */ - u32 gs_sub_type:8; /* Generic service sub type */ - u32 options:8; /* options */ - u32 rsvrd:8; /* reserved */ - u32 cmd_rsp_code:16;/* ct command/response code */ - u32 max_res_size:16;/* maximum/residual size */ - u32 frag_id:8; /* fragment ID */ - u32 reason_code:8; /* reason code */ - u32 exp_code:8; /* explanation code */ - u32 vendor_unq:8; /* vendor unique */ -}; - -/* - * defines for the Revision - */ -enum { - CT_GS3_REVISION = 0x01, -}; - -/* - * defines for gs_type - */ -enum { - CT_GSTYPE_KEYSERVICE = 0xF7, - CT_GSTYPE_ALIASSERVICE = 0xF8, - CT_GSTYPE_MGMTSERVICE = 0xFA, - CT_GSTYPE_TIMESERVICE = 0xFB, - CT_GSTYPE_DIRSERVICE = 0xFC, -}; - -/* - * defines for gs_sub_type for gs type directory service - */ -enum { - CT_GSSUBTYPE_NAMESERVER = 0x02, -}; - -/* - * defines for gs_sub_type for gs type management service - */ -enum { - CT_GSSUBTYPE_CFGSERVER = 0x01, - CT_GSSUBTYPE_UNZONED_NS = 0x02, - CT_GSSUBTYPE_ZONESERVER = 0x03, - CT_GSSUBTYPE_LOCKSERVER = 0x04, - CT_GSSUBTYPE_HBA_MGMTSERVER = 0x10, /* for FDMI */ -}; - -/* - * defines for CT response code field - */ -enum { - CT_RSP_REJECT = 0x8001, - CT_RSP_ACCEPT = 0x8002, -}; - -/* - * defintions for CT reason code - */ -enum { - CT_RSN_INV_CMD = 0x01, - CT_RSN_INV_VER = 0x02, - CT_RSN_LOGIC_ERR = 0x03, - CT_RSN_INV_SIZE = 0x04, - CT_RSN_LOGICAL_BUSY = 0x05, - CT_RSN_PROTO_ERR = 0x07, - CT_RSN_UNABLE_TO_PERF = 0x09, - CT_RSN_NOT_SUPP = 0x0B, - CT_RSN_SERVER_NOT_AVBL = 0x0D, - CT_RSN_SESSION_COULD_NOT_BE_ESTBD = 0x0E, - CT_RSN_VENDOR_SPECIFIC = 0xFF, - -}; - -/* - * definitions for explanations code for Name server - */ -enum { - CT_NS_EXP_NOADDITIONAL = 0x00, - CT_NS_EXP_ID_NOT_REG = 0x01, - CT_NS_EXP_PN_NOT_REG = 0x02, - CT_NS_EXP_NN_NOT_REG = 0x03, - CT_NS_EXP_CS_NOT_REG = 0x04, - CT_NS_EXP_IPN_NOT_REG = 0x05, - CT_NS_EXP_IPA_NOT_REG = 0x06, - CT_NS_EXP_FT_NOT_REG = 0x07, - CT_NS_EXP_SPN_NOT_REG = 0x08, - CT_NS_EXP_SNN_NOT_REG = 0x09, - CT_NS_EXP_PT_NOT_REG = 0x0A, - CT_NS_EXP_IPP_NOT_REG = 0x0B, - CT_NS_EXP_FPN_NOT_REG = 0x0C, - CT_NS_EXP_HA_NOT_REG = 0x0D, - CT_NS_EXP_FD_NOT_REG = 0x0E, - CT_NS_EXP_FF_NOT_REG = 0x0F, - CT_NS_EXP_ACCESSDENIED = 0x10, - CT_NS_EXP_UNACCEPTABLE_ID = 0x11, - CT_NS_EXP_DATABASEEMPTY = 0x12, - CT_NS_EXP_NOT_REG_IN_SCOPE = 0x13, - CT_NS_EXP_DOM_ID_NOT_PRESENT = 0x14, - CT_NS_EXP_PORT_NUM_NOT_PRESENT = 0x15, - CT_NS_EXP_NO_DEVICE_ATTACHED = 0x16 -}; - -/* - * defintions for the explanation code for all servers - */ -enum { - CT_EXP_AUTH_EXCEPTION = 0xF1, - CT_EXP_DB_FULL = 0xF2, - CT_EXP_DB_EMPTY = 0xF3, - CT_EXP_PROCESSING_REQ = 0xF4, - CT_EXP_UNABLE_TO_VERIFY_CONN = 0xF5, - CT_EXP_DEVICES_NOT_IN_CMN_ZONE = 0xF6 -}; - -/* - * Command codes for Name server - */ -enum { - GS_GID_PN = 0x0121, /* Get Id on port name */ - GS_GPN_ID = 0x0112, /* Get port name on ID */ - GS_GNN_ID = 0x0113, /* Get node name on ID */ - GS_GID_FT = 0x0171, /* Get Id on FC4 type */ - GS_GSPN_ID = 0x0118, /* Get symbolic PN on ID */ - GS_RFT_ID = 0x0217, /* Register fc4type on ID */ - GS_RSPN_ID = 0x0218, /* Register symbolic PN on ID */ - GS_RPN_ID = 0x0212, /* Register port name */ - GS_RNN_ID = 0x0213, /* Register node name */ - GS_RCS_ID = 0x0214, /* Register class of service */ - GS_RPT_ID = 0x021A, /* Register port type */ - GS_GA_NXT = 0x0100, /* Get all next */ - GS_RFF_ID = 0x021F, /* Register FC4 Feature */ -}; - -struct fcgs_id_req_s { - u32 rsvd:8; - u32 dap:24; /* port identifier */ -}; -#define fcgs_gpnid_req_t struct fcgs_id_req_s -#define fcgs_gnnid_req_t struct fcgs_id_req_s -#define fcgs_gspnid_req_t struct fcgs_id_req_s - -struct fcgs_gidpn_req_s { - wwn_t port_name; /* port wwn */ -}; - -struct fcgs_gidpn_resp_s { - u32 rsvd:8; - u32 dap:24; /* port identifier */ -}; - -/* - * RFT_ID - */ -struct fcgs_rftid_req_s { - u32 rsvd:8; - u32 dap:24; /* port identifier */ - __be32 fc4_type[8]; /* fc4 types */ -}; - -/* - * RFF_ID : Register FC4 features. - */ -#define FC_GS_FCP_FC4_FEATURE_INITIATOR 0x02 -#define FC_GS_FCP_FC4_FEATURE_TARGET 0x01 - -struct fcgs_rffid_req_s { - u32 rsvd:8; - u32 dap:24; /* port identifier */ - u32 rsvd1:16; - u32 fc4ftr_bits:8; /* fc4 feature bits */ - u32 fc4_type:8; /* corresponding FC4 Type */ -}; - -/* - * GID_FT Request - */ -struct fcgs_gidft_req_s { - u8 reserved; - u8 domain_id; /* domain, 0 - all fabric */ - u8 area_id; /* area, 0 - whole domain */ - u8 fc4_type; /* FC_TYPE_FCP for SCSI devices */ -}; - -/* - * GID_FT Response - */ -struct fcgs_gidft_resp_s { - u8 last:1; /* last port identifier flag */ - u8 reserved:7; - u32 pid:24; /* port identifier */ -}; - -/* - * RSPN_ID - */ -struct fcgs_rspnid_req_s { - u32 rsvd:8; - u32 dap:24; /* port identifier */ - u8 spn_len; /* symbolic port name length */ - u8 spn[256]; /* symbolic port name */ -}; - -/* - * RPN_ID - */ -struct fcgs_rpnid_req_s { - u32 rsvd:8; - u32 port_id:24; - wwn_t port_name; -}; - -/* - * RNN_ID - */ -struct fcgs_rnnid_req_s { - u32 rsvd:8; - u32 port_id:24; - wwn_t node_name; -}; - -/* - * RCS_ID - */ -struct fcgs_rcsid_req_s { - u32 rsvd:8; - u32 port_id:24; - u32 cos; -}; - -/* - * RPT_ID - */ -struct fcgs_rptid_req_s { - u32 rsvd:8; - u32 port_id:24; - u32 port_type:8; - u32 rsvd1:24; -}; - -/* - * GA_NXT Request - */ -struct fcgs_ganxt_req_s { - u32 rsvd:8; - u32 port_id:24; -}; - -/* - * GA_NXT Response - */ -struct fcgs_ganxt_rsp_s { - u32 port_type:8; /* Port Type */ - u32 port_id:24; /* Port Identifier */ - wwn_t port_name; /* Port Name */ - u8 spn_len; /* Length of Symbolic Port Name */ - char spn[255]; /* Symbolic Port Name */ - wwn_t node_name; /* Node Name */ - u8 snn_len; /* Length of Symbolic Node Name */ - char snn[255]; /* Symbolic Node Name */ - u8 ipa[8]; /* Initial Process Associator */ - u8 ip[16]; /* IP Address */ - u32 cos; /* Class of Service */ - u32 fc4types[8]; /* FC-4 TYPEs */ - wwn_t fabric_port_name; /* Fabric Port Name */ - u32 rsvd:8; /* Reserved */ - u32 hard_addr:24; /* Hard Address */ -}; - -/* - * Command codes for Fabric Configuration Server - */ -enum { - GS_FC_GFN_CMD = 0x0114, /* GS FC Get Fabric Name */ - GS_FC_GMAL_CMD = 0x0116, /* GS FC GMAL */ - GS_FC_TRACE_CMD = 0x0400, /* GS FC Trace Route */ - GS_FC_PING_CMD = 0x0401, /* GS FC Ping */ -}; - -/* - * GMAL Command ( Get ( interconnect Element) Management Address List) - * To retrieve the IP Address of a Switch. - */ -#define CT_GMAL_RESP_PREFIX_TELNET "telnet://" -#define CT_GMAL_RESP_PREFIX_HTTP "http://" - -/* GMAL/GFN request */ -struct fcgs_req_s { - wwn_t wwn; /* PWWN/NWWN */ -}; - -#define fcgs_gmal_req_t struct fcgs_req_s -#define fcgs_gfn_req_t struct fcgs_req_s - -/* Accept Response to GMAL */ -struct fcgs_gmal_resp_s { - __be32 ms_len; /* Num of entries */ - u8 ms_ma[256]; -}; - -struct fcgs_gmal_entry_s { - u8 len; - u8 prefix[7]; /* like "http://" */ - u8 ip_addr[248]; -}; - -/* - * FDMI Command Codes - */ -#define FDMI_GRHL 0x0100 -#define FDMI_GHAT 0x0101 -#define FDMI_GRPL 0x0102 -#define FDMI_GPAT 0x0110 -#define FDMI_RHBA 0x0200 -#define FDMI_RHAT 0x0201 -#define FDMI_RPRT 0x0210 -#define FDMI_RPA 0x0211 -#define FDMI_DHBA 0x0300 -#define FDMI_DPRT 0x0310 - -/* - * FDMI reason codes - */ -#define FDMI_NO_ADDITIONAL_EXP 0x00 -#define FDMI_HBA_ALREADY_REG 0x10 -#define FDMI_HBA_ATTRIB_NOT_REG 0x11 -#define FDMI_HBA_ATTRIB_MULTIPLE 0x12 -#define FDMI_HBA_ATTRIB_LENGTH_INVALID 0x13 -#define FDMI_HBA_ATTRIB_NOT_PRESENT 0x14 -#define FDMI_PORT_ORIG_NOT_IN_LIST 0x15 -#define FDMI_PORT_HBA_NOT_IN_LIST 0x16 -#define FDMI_PORT_ATTRIB_NOT_REG 0x20 -#define FDMI_PORT_NOT_REG 0x21 -#define FDMI_PORT_ATTRIB_MULTIPLE 0x22 -#define FDMI_PORT_ATTRIB_LENGTH_INVALID 0x23 -#define FDMI_PORT_ALREADY_REGISTEREED 0x24 - -/* - * FDMI Transmission Speed Mask values - */ -#define FDMI_TRANS_SPEED_1G 0x00000001 -#define FDMI_TRANS_SPEED_2G 0x00000002 -#define FDMI_TRANS_SPEED_10G 0x00000004 -#define FDMI_TRANS_SPEED_4G 0x00000008 -#define FDMI_TRANS_SPEED_8G 0x00000010 -#define FDMI_TRANS_SPEED_16G 0x00000020 -#define FDMI_TRANS_SPEED_UNKNOWN 0x00008000 - -/* - * FDMI HBA attribute types - */ -enum fdmi_hba_attribute_type { - FDMI_HBA_ATTRIB_NODENAME = 1, /* 0x0001 */ - FDMI_HBA_ATTRIB_MANUFACTURER, /* 0x0002 */ - FDMI_HBA_ATTRIB_SERIALNUM, /* 0x0003 */ - FDMI_HBA_ATTRIB_MODEL, /* 0x0004 */ - FDMI_HBA_ATTRIB_MODEL_DESC, /* 0x0005 */ - FDMI_HBA_ATTRIB_HW_VERSION, /* 0x0006 */ - FDMI_HBA_ATTRIB_DRIVER_VERSION, /* 0x0007 */ - FDMI_HBA_ATTRIB_ROM_VERSION, /* 0x0008 */ - FDMI_HBA_ATTRIB_FW_VERSION, /* 0x0009 */ - FDMI_HBA_ATTRIB_OS_NAME, /* 0x000A */ - FDMI_HBA_ATTRIB_MAX_CT, /* 0x000B */ - - FDMI_HBA_ATTRIB_MAX_TYPE -}; - -/* - * FDMI Port attribute types - */ -enum fdmi_port_attribute_type { - FDMI_PORT_ATTRIB_FC4_TYPES = 1, /* 0x0001 */ - FDMI_PORT_ATTRIB_SUPP_SPEED, /* 0x0002 */ - FDMI_PORT_ATTRIB_PORT_SPEED, /* 0x0003 */ - FDMI_PORT_ATTRIB_FRAME_SIZE, /* 0x0004 */ - FDMI_PORT_ATTRIB_DEV_NAME, /* 0x0005 */ - FDMI_PORT_ATTRIB_HOST_NAME, /* 0x0006 */ - - FDMI_PORT_ATTR_MAX_TYPE -}; - -/* - * FDMI attribute - */ -struct fdmi_attr_s { - __be16 type; - __be16 len; - u8 value[1]; -}; - -/* - * HBA Attribute Block - */ -struct fdmi_hba_attr_s { - __be32 attr_count; /* # of attributes */ - struct fdmi_attr_s hba_attr; /* n attributes */ -}; - -/* - * Registered Port List - */ -struct fdmi_port_list_s { - __be32 num_ports; /* number Of Port Entries */ - wwn_t port_entry; /* one or more */ -}; - -/* - * Port Attribute Block - */ -struct fdmi_port_attr_s { - __be32 attr_count; /* # of attributes */ - struct fdmi_attr_s port_attr; /* n attributes */ -}; - -/* - * FDMI Register HBA Attributes - */ -struct fdmi_rhba_s { - wwn_t hba_id; /* HBA Identifier */ - struct fdmi_port_list_s port_list; /* Registered Port List */ - struct fdmi_hba_attr_s hba_attr_blk; /* HBA attribute block */ -}; - -/* - * FDMI Register Port - */ -struct fdmi_rprt_s { - wwn_t hba_id; /* HBA Identifier */ - wwn_t port_name; /* Port wwn */ - struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */ -}; - -/* - * FDMI Register Port Attributes - */ -struct fdmi_rpa_s { - wwn_t port_name; /* port wwn */ - struct fdmi_port_attr_s port_attr_blk; /* Port Attr Block */ -}; - -#pragma pack() - -#endif /* __BFA_FC_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.c deleted file mode 100644 index 17b59b8b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.c +++ /dev/null @@ -1,1438 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -/* - * fcbuild.c - FC link service frame building and parsing routines - */ - -#include "bfad_drv.h" -#include "bfa_fcbuild.h" - -/* - * static build functions - */ -static void fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - __be16 ox_id); -static void fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - __be16 ox_id); -static struct fchs_s fc_els_req_tmpl; -static struct fchs_s fc_els_rsp_tmpl; -static struct fchs_s fc_bls_req_tmpl; -static struct fchs_s fc_bls_rsp_tmpl; -static struct fc_ba_acc_s ba_acc_tmpl; -static struct fc_logi_s plogi_tmpl; -static struct fc_prli_s prli_tmpl; -static struct fc_rrq_s rrq_tmpl; -static struct fchs_s fcp_fchs_tmpl; - -void -fcbuild_init(void) -{ - /* - * fc_els_req_tmpl - */ - fc_els_req_tmpl.routing = FC_RTG_EXT_LINK; - fc_els_req_tmpl.cat_info = FC_CAT_LD_REQUEST; - fc_els_req_tmpl.type = FC_TYPE_ELS; - fc_els_req_tmpl.f_ctl = - bfa_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ | - FCTL_SI_XFER); - fc_els_req_tmpl.rx_id = FC_RXID_ANY; - - /* - * fc_els_rsp_tmpl - */ - fc_els_rsp_tmpl.routing = FC_RTG_EXT_LINK; - fc_els_rsp_tmpl.cat_info = FC_CAT_LD_REPLY; - fc_els_rsp_tmpl.type = FC_TYPE_ELS; - fc_els_rsp_tmpl.f_ctl = - bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH | - FCTL_END_SEQ | FCTL_SI_XFER); - fc_els_rsp_tmpl.rx_id = FC_RXID_ANY; - - /* - * fc_bls_req_tmpl - */ - fc_bls_req_tmpl.routing = FC_RTG_BASIC_LINK; - fc_bls_req_tmpl.type = FC_TYPE_BLS; - fc_bls_req_tmpl.f_ctl = bfa_hton3b(FCTL_END_SEQ | FCTL_SI_XFER); - fc_bls_req_tmpl.rx_id = FC_RXID_ANY; - - /* - * fc_bls_rsp_tmpl - */ - fc_bls_rsp_tmpl.routing = FC_RTG_BASIC_LINK; - fc_bls_rsp_tmpl.cat_info = FC_CAT_BA_ACC; - fc_bls_rsp_tmpl.type = FC_TYPE_BLS; - fc_bls_rsp_tmpl.f_ctl = - bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH | - FCTL_END_SEQ | FCTL_SI_XFER); - fc_bls_rsp_tmpl.rx_id = FC_RXID_ANY; - - /* - * ba_acc_tmpl - */ - ba_acc_tmpl.seq_id_valid = 0; - ba_acc_tmpl.low_seq_cnt = 0; - ba_acc_tmpl.high_seq_cnt = 0xFFFF; - - /* - * plogi_tmpl - */ - plogi_tmpl.csp.verhi = FC_PH_VER_PH_3; - plogi_tmpl.csp.verlo = FC_PH_VER_4_3; - plogi_tmpl.csp.ciro = 0x1; - plogi_tmpl.csp.cisc = 0x0; - plogi_tmpl.csp.altbbcred = 0x0; - plogi_tmpl.csp.conseq = cpu_to_be16(0x00FF); - plogi_tmpl.csp.ro_bitmap = cpu_to_be16(0x0002); - plogi_tmpl.csp.e_d_tov = cpu_to_be32(2000); - - plogi_tmpl.class3.class_valid = 1; - plogi_tmpl.class3.sequential = 1; - plogi_tmpl.class3.conseq = 0xFF; - plogi_tmpl.class3.ospx = 1; - - /* - * prli_tmpl - */ - prli_tmpl.command = FC_ELS_PRLI; - prli_tmpl.pglen = 0x10; - prli_tmpl.pagebytes = cpu_to_be16(0x0014); - prli_tmpl.parampage.type = FC_TYPE_FCP; - prli_tmpl.parampage.imagepair = 1; - prli_tmpl.parampage.servparams.rxrdisab = 1; - - /* - * rrq_tmpl - */ - rrq_tmpl.els_cmd.els_code = FC_ELS_RRQ; - - /* - * fcp_struct fchs_s mpl - */ - fcp_fchs_tmpl.routing = FC_RTG_FC4_DEV_DATA; - fcp_fchs_tmpl.cat_info = FC_CAT_UNSOLICIT_CMD; - fcp_fchs_tmpl.type = FC_TYPE_FCP; - fcp_fchs_tmpl.f_ctl = - bfa_hton3b(FCTL_FS_EXCH | FCTL_END_SEQ | FCTL_SI_XFER); - fcp_fchs_tmpl.seq_id = 1; - fcp_fchs_tmpl.rx_id = FC_RXID_ANY; -} - -static void -fc_gs_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u32 ox_id) -{ - memset(fchs, 0, sizeof(struct fchs_s)); - - fchs->routing = FC_RTG_FC4_DEV_DATA; - fchs->cat_info = FC_CAT_UNSOLICIT_CTRL; - fchs->type = FC_TYPE_SERVICES; - fchs->f_ctl = - bfa_hton3b(FCTL_SEQ_INI | FCTL_FS_EXCH | FCTL_END_SEQ | - FCTL_SI_XFER); - fchs->rx_id = FC_RXID_ANY; - fchs->d_id = (d_id); - fchs->s_id = (s_id); - fchs->ox_id = cpu_to_be16(ox_id); - - /* - * @todo no need to set ox_id for request - * no need to set rx_id for response - */ -} - -static void -fc_gsresp_fchdr_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) -{ - memset(fchs, 0, sizeof(struct fchs_s)); - - fchs->routing = FC_RTG_FC4_DEV_DATA; - fchs->cat_info = FC_CAT_SOLICIT_CTRL; - fchs->type = FC_TYPE_SERVICES; - fchs->f_ctl = - bfa_hton3b(FCTL_EC_RESP | FCTL_SEQ_INI | FCTL_LS_EXCH | - FCTL_END_SEQ | FCTL_SI_XFER); - fchs->d_id = d_id; - fchs->s_id = s_id; - fchs->ox_id = ox_id; -} - -void -fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) -{ - memcpy(fchs, &fc_els_req_tmpl, sizeof(struct fchs_s)); - fchs->d_id = (d_id); - fchs->s_id = (s_id); - fchs->ox_id = cpu_to_be16(ox_id); -} - -static void -fc_els_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) -{ - memcpy(fchs, &fc_els_rsp_tmpl, sizeof(struct fchs_s)); - fchs->d_id = d_id; - fchs->s_id = s_id; - fchs->ox_id = ox_id; -} - -enum fc_parse_status -fc_els_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - struct fc_ls_rjt_s *ls_rjt = (struct fc_ls_rjt_s *) els_cmd; - - len = len; - - switch (els_cmd->els_code) { - case FC_ELS_LS_RJT: - if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY) - return FC_PARSE_BUSY; - else - return FC_PARSE_FAILURE; - - case FC_ELS_ACC: - return FC_PARSE_OK; - } - return FC_PARSE_OK; -} - -static void -fc_bls_rsp_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id) -{ - memcpy(fchs, &fc_bls_rsp_tmpl, sizeof(struct fchs_s)); - fchs->d_id = d_id; - fchs->s_id = s_id; - fchs->ox_id = ox_id; -} - -static u16 -fc_plogi_x_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, - __be16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr, u8 els_code) -{ - struct fc_logi_s *plogi = (struct fc_logi_s *) (pld); - - memcpy(plogi, &plogi_tmpl, sizeof(struct fc_logi_s)); - - plogi->els_cmd.els_code = els_code; - if (els_code == FC_ELS_PLOGI) - fc_els_req_build(fchs, d_id, s_id, ox_id); - else - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - plogi->csp.rxsz = plogi->class3.rxsz = cpu_to_be16(pdu_size); - plogi->csp.bbcred = cpu_to_be16(bb_cr); - - memcpy(&plogi->port_name, &port_name, sizeof(wwn_t)); - memcpy(&plogi->node_name, &node_name, sizeof(wwn_t)); - - return sizeof(struct fc_logi_s); -} - -u16 -fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size, - u8 set_npiv, u8 set_auth, u16 local_bb_credits) -{ - u32 d_id = bfa_hton3b(FC_FABRIC_PORT); - __be32 *vvl_info; - - memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); - - flogi->els_cmd.els_code = FC_ELS_FLOGI; - fc_els_req_build(fchs, d_id, s_id, ox_id); - - flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size); - flogi->port_name = port_name; - flogi->node_name = node_name; - - /* - * Set the NPIV Capability Bit ( word 1, bit 31) of Common - * Service Parameters. - */ - flogi->csp.ciro = set_npiv; - - /* set AUTH capability */ - flogi->csp.security = set_auth; - - flogi->csp.bbcred = cpu_to_be16(local_bb_credits); - - /* Set brcd token in VVL */ - vvl_info = (u32 *)&flogi->vvl[0]; - - /* set the flag to indicate the presence of VVL */ - flogi->csp.npiv_supp = 1; /* @todo. field name is not correct */ - vvl_info[0] = cpu_to_be32(FLOGI_VVL_BRCD); - - return sizeof(struct fc_logi_s); -} - -u16 -fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, - __be16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 local_bb_credits, u8 bb_scn) -{ - u32 d_id = 0; - u16 bbscn_rxsz = (bb_scn << 12) | pdu_size; - - memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - flogi->els_cmd.els_code = FC_ELS_ACC; - flogi->class3.rxsz = cpu_to_be16(pdu_size); - flogi->csp.rxsz = cpu_to_be16(bbscn_rxsz); /* bb_scn/rxsz */ - flogi->port_name = port_name; - flogi->node_name = node_name; - - flogi->csp.bbcred = cpu_to_be16(local_bb_credits); - - return sizeof(struct fc_logi_s); -} - -u16 -fc_fdisc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, u16 pdu_size) -{ - u32 d_id = bfa_hton3b(FC_FABRIC_PORT); - - memcpy(flogi, &plogi_tmpl, sizeof(struct fc_logi_s)); - - flogi->els_cmd.els_code = FC_ELS_FDISC; - fc_els_req_build(fchs, d_id, s_id, ox_id); - - flogi->csp.rxsz = flogi->class3.rxsz = cpu_to_be16(pdu_size); - flogi->port_name = port_name; - flogi->node_name = node_name; - - return sizeof(struct fc_logi_s); -} - -u16 -fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr) -{ - return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name, - node_name, pdu_size, bb_cr, FC_ELS_PLOGI); -} - -u16 -fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr) -{ - return fc_plogi_x_build(fchs, pld, d_id, s_id, ox_id, port_name, - node_name, pdu_size, bb_cr, FC_ELS_ACC); -} - -enum fc_parse_status -fc_plogi_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - struct fc_logi_s *plogi; - struct fc_ls_rjt_s *ls_rjt; - - switch (els_cmd->els_code) { - case FC_ELS_LS_RJT: - ls_rjt = (struct fc_ls_rjt_s *) (fchs + 1); - if (ls_rjt->reason_code == FC_LS_RJT_RSN_LOGICAL_BUSY) - return FC_PARSE_BUSY; - else - return FC_PARSE_FAILURE; - case FC_ELS_ACC: - plogi = (struct fc_logi_s *) (fchs + 1); - if (len < sizeof(struct fc_logi_s)) - return FC_PARSE_FAILURE; - - if (!wwn_is_equal(plogi->port_name, port_name)) - return FC_PARSE_FAILURE; - - if (!plogi->class3.class_valid) - return FC_PARSE_FAILURE; - - if (be16_to_cpu(plogi->class3.rxsz) < (FC_MIN_PDUSZ)) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; - default: - return FC_PARSE_FAILURE; - } -} - -enum fc_parse_status -fc_plogi_parse(struct fchs_s *fchs) -{ - struct fc_logi_s *plogi = (struct fc_logi_s *) (fchs + 1); - - if (plogi->class3.class_valid != 1) - return FC_PARSE_FAILURE; - - if ((be16_to_cpu(plogi->class3.rxsz) < FC_MIN_PDUSZ) - || (be16_to_cpu(plogi->class3.rxsz) > FC_MAX_PDUSZ) - || (plogi->class3.rxsz == 0)) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - -u16 -fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, - u16 ox_id) -{ - struct fc_prli_s *prli = (struct fc_prli_s *) (pld); - - fc_els_req_build(fchs, d_id, s_id, ox_id); - memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s)); - - prli->command = FC_ELS_PRLI; - prli->parampage.servparams.initiator = 1; - prli->parampage.servparams.retry = 1; - prli->parampage.servparams.rec_support = 1; - prli->parampage.servparams.task_retry_id = 0; - prli->parampage.servparams.confirm = 1; - - return sizeof(struct fc_prli_s); -} - -u16 -fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, - __be16 ox_id, enum bfa_lport_role role) -{ - struct fc_prli_s *prli = (struct fc_prli_s *) (pld); - - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - memcpy(prli, &prli_tmpl, sizeof(struct fc_prli_s)); - - prli->command = FC_ELS_ACC; - - prli->parampage.servparams.initiator = 1; - - prli->parampage.rspcode = FC_PRLI_ACC_XQTD; - - return sizeof(struct fc_prli_s); -} - -enum fc_parse_status -fc_prli_rsp_parse(struct fc_prli_s *prli, int len) -{ - if (len < sizeof(struct fc_prli_s)) - return FC_PARSE_FAILURE; - - if (prli->command != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - if ((prli->parampage.rspcode != FC_PRLI_ACC_XQTD) - && (prli->parampage.rspcode != FC_PRLI_ACC_PREDEF_IMG)) - return FC_PARSE_FAILURE; - - if (prli->parampage.servparams.target != 1) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - -enum fc_parse_status -fc_prli_parse(struct fc_prli_s *prli) -{ - if (prli->parampage.type != FC_TYPE_FCP) - return FC_PARSE_FAILURE; - - if (!prli->parampage.imagepair) - return FC_PARSE_FAILURE; - - if (!prli->parampage.servparams.initiator) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - -u16 -fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, u32 s_id, - u16 ox_id, wwn_t port_name) -{ - fc_els_req_build(fchs, d_id, s_id, ox_id); - - memset(logo, '\0', sizeof(struct fc_logo_s)); - logo->els_cmd.els_code = FC_ELS_LOGO; - logo->nport_id = (s_id); - logo->orig_port_name = port_name; - - return sizeof(struct fc_logo_s); -} - -static u16 -fc_adisc_x_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, - u32 s_id, __be16 ox_id, wwn_t port_name, - wwn_t node_name, u8 els_code) -{ - memset(adisc, '\0', sizeof(struct fc_adisc_s)); - - adisc->els_cmd.els_code = els_code; - - if (els_code == FC_ELS_ADISC) - fc_els_req_build(fchs, d_id, s_id, ox_id); - else - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - adisc->orig_HA = 0; - adisc->orig_port_name = port_name; - adisc->orig_node_name = node_name; - adisc->nport_id = (s_id); - - return sizeof(struct fc_adisc_s); -} - -u16 -fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, - u32 s_id, __be16 ox_id, wwn_t port_name, wwn_t node_name) -{ - return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name, - node_name, FC_ELS_ADISC); -} - -u16 -fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, u32 d_id, - u32 s_id, __be16 ox_id, wwn_t port_name, - wwn_t node_name) -{ - return fc_adisc_x_build(fchs, adisc, d_id, s_id, ox_id, port_name, - node_name, FC_ELS_ACC); -} - -enum fc_parse_status -fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, wwn_t port_name, - wwn_t node_name) -{ - - if (len < sizeof(struct fc_adisc_s)) - return FC_PARSE_FAILURE; - - if (adisc->els_cmd.els_code != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - if (!wwn_is_equal(adisc->orig_port_name, port_name)) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - -enum fc_parse_status -fc_adisc_parse(struct fchs_s *fchs, void *pld, u32 host_dap, wwn_t node_name, - wwn_t port_name) -{ - struct fc_adisc_s *adisc = (struct fc_adisc_s *) pld; - - if (adisc->els_cmd.els_code != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - if ((adisc->nport_id == (host_dap)) - && wwn_is_equal(adisc->orig_port_name, port_name) - && wwn_is_equal(adisc->orig_node_name, node_name)) - return FC_PARSE_OK; - - return FC_PARSE_FAILURE; -} - -enum fc_parse_status -fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, wwn_t port_name) -{ - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); - - if (pdisc->class3.class_valid != 1) - return FC_PARSE_FAILURE; - - if ((be16_to_cpu(pdisc->class3.rxsz) < - (FC_MIN_PDUSZ - sizeof(struct fchs_s))) - || (pdisc->class3.rxsz == 0)) - return FC_PARSE_FAILURE; - - if (!wwn_is_equal(pdisc->port_name, port_name)) - return FC_PARSE_FAILURE; - - if (!wwn_is_equal(pdisc->node_name, node_name)) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - -u16 -fc_abts_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id) -{ - memcpy(fchs, &fc_bls_req_tmpl, sizeof(struct fchs_s)); - fchs->cat_info = FC_CAT_ABTS; - fchs->d_id = (d_id); - fchs->s_id = (s_id); - fchs->ox_id = cpu_to_be16(ox_id); - - return sizeof(struct fchs_s); -} - -enum fc_parse_status -fc_abts_rsp_parse(struct fchs_s *fchs, int len) -{ - if ((fchs->cat_info == FC_CAT_BA_ACC) - || (fchs->cat_info == FC_CAT_BA_RJT)) - return FC_PARSE_OK; - - return FC_PARSE_FAILURE; -} - -u16 -fc_rrq_build(struct fchs_s *fchs, struct fc_rrq_s *rrq, u32 d_id, u32 s_id, - u16 ox_id, u16 rrq_oxid) -{ - fc_els_req_build(fchs, d_id, s_id, ox_id); - - /* - * build rrq payload - */ - memcpy(rrq, &rrq_tmpl, sizeof(struct fc_rrq_s)); - rrq->s_id = (s_id); - rrq->ox_id = cpu_to_be16(rrq_oxid); - rrq->rx_id = FC_RXID_ANY; - - return sizeof(struct fc_rrq_s); -} - -u16 -fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, u32 s_id, - __be16 ox_id) -{ - struct fc_els_cmd_s *acc = pld; - - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - memset(acc, 0, sizeof(struct fc_els_cmd_s)); - acc->els_code = FC_ELS_ACC; - - return sizeof(struct fc_els_cmd_s); -} - -u16 -fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, u32 d_id, - u32 s_id, __be16 ox_id, u8 reason_code, - u8 reason_code_expl) -{ - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - memset(ls_rjt, 0, sizeof(struct fc_ls_rjt_s)); - - ls_rjt->els_cmd.els_code = FC_ELS_LS_RJT; - ls_rjt->reason_code = reason_code; - ls_rjt->reason_code_expl = reason_code_expl; - ls_rjt->vendor_unique = 0x00; - - return sizeof(struct fc_ls_rjt_s); -} - -u16 -fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id, - u32 s_id, __be16 ox_id, u16 rx_id) -{ - fc_bls_rsp_build(fchs, d_id, s_id, ox_id); - - memcpy(ba_acc, &ba_acc_tmpl, sizeof(struct fc_ba_acc_s)); - - fchs->rx_id = rx_id; - - ba_acc->ox_id = fchs->ox_id; - ba_acc->rx_id = fchs->rx_id; - - return sizeof(struct fc_ba_acc_s); -} - -u16 -fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, u32 d_id, - u32 s_id, __be16 ox_id) -{ - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - memset(els_cmd, 0, sizeof(struct fc_els_cmd_s)); - els_cmd->els_code = FC_ELS_ACC; - - return sizeof(struct fc_els_cmd_s); -} - -int -fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code) -{ - int num_pages = 0; - struct fc_prlo_s *prlo; - struct fc_tprlo_s *tprlo; - - if (els_code == FC_ELS_PRLO) { - prlo = (struct fc_prlo_s *) (fc_frame + 1); - num_pages = (be16_to_cpu(prlo->payload_len) - 4) / 16; - } else { - tprlo = (struct fc_tprlo_s *) (fc_frame + 1); - num_pages = (be16_to_cpu(tprlo->payload_len) - 4) / 16; - } - return num_pages; -} - -u16 -fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, - u32 d_id, u32 s_id, __be16 ox_id, int num_pages) -{ - int page; - - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - memset(tprlo_acc, 0, (num_pages * 16) + 4); - tprlo_acc->command = FC_ELS_ACC; - - tprlo_acc->page_len = 0x10; - tprlo_acc->payload_len = cpu_to_be16((num_pages * 16) + 4); - - for (page = 0; page < num_pages; page++) { - tprlo_acc->tprlo_acc_params[page].opa_valid = 0; - tprlo_acc->tprlo_acc_params[page].rpa_valid = 0; - tprlo_acc->tprlo_acc_params[page].fc4type_csp = FC_TYPE_FCP; - tprlo_acc->tprlo_acc_params[page].orig_process_assc = 0; - tprlo_acc->tprlo_acc_params[page].resp_process_assc = 0; - } - return be16_to_cpu(tprlo_acc->payload_len); -} - -u16 -fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, u32 d_id, - u32 s_id, __be16 ox_id, int num_pages) -{ - int page; - - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - memset(prlo_acc, 0, (num_pages * 16) + 4); - prlo_acc->command = FC_ELS_ACC; - prlo_acc->page_len = 0x10; - prlo_acc->payload_len = cpu_to_be16((num_pages * 16) + 4); - - for (page = 0; page < num_pages; page++) { - prlo_acc->prlo_acc_params[page].opa_valid = 0; - prlo_acc->prlo_acc_params[page].rpa_valid = 0; - prlo_acc->prlo_acc_params[page].fc4type_csp = FC_TYPE_FCP; - prlo_acc->prlo_acc_params[page].orig_process_assc = 0; - prlo_acc->prlo_acc_params[page].resp_process_assc = 0; - } - - return be16_to_cpu(prlo_acc->payload_len); -} - -u16 -fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, u32 d_id, - u32 s_id, u16 ox_id, u32 data_format) -{ - fc_els_req_build(fchs, d_id, s_id, ox_id); - - memset(rnid, 0, sizeof(struct fc_rnid_cmd_s)); - - rnid->els_cmd.els_code = FC_ELS_RNID; - rnid->node_id_data_format = data_format; - - return sizeof(struct fc_rnid_cmd_s); -} - -u16 -fc_rnid_acc_build(struct fchs_s *fchs, struct fc_rnid_acc_s *rnid_acc, u32 d_id, - u32 s_id, __be16 ox_id, u32 data_format, - struct fc_rnid_common_id_data_s *common_id_data, - struct fc_rnid_general_topology_data_s *gen_topo_data) -{ - memset(rnid_acc, 0, sizeof(struct fc_rnid_acc_s)); - - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - rnid_acc->els_cmd.els_code = FC_ELS_ACC; - rnid_acc->node_id_data_format = data_format; - rnid_acc->common_id_data_length = - sizeof(struct fc_rnid_common_id_data_s); - rnid_acc->common_id_data = *common_id_data; - - if (data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) { - rnid_acc->specific_id_data_length = - sizeof(struct fc_rnid_general_topology_data_s); - rnid_acc->gen_topology_data = *gen_topo_data; - return sizeof(struct fc_rnid_acc_s); - } else { - return sizeof(struct fc_rnid_acc_s) - - sizeof(struct fc_rnid_general_topology_data_s); - } - -} - -u16 -fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, u32 d_id, - u32 s_id, u16 ox_id) -{ - fc_els_req_build(fchs, d_id, s_id, ox_id); - - memset(rpsc, 0, sizeof(struct fc_rpsc_cmd_s)); - - rpsc->els_cmd.els_code = FC_ELS_RPSC; - return sizeof(struct fc_rpsc_cmd_s); -} - -u16 -fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rpsc2, u32 d_id, - u32 s_id, u32 *pid_list, u16 npids) -{ - u32 dctlr_id = FC_DOMAIN_CTRLR(bfa_hton3b(d_id)); - int i = 0; - - fc_els_req_build(fchs, bfa_hton3b(dctlr_id), s_id, 0); - - memset(rpsc2, 0, sizeof(struct fc_rpsc2_cmd_s)); - - rpsc2->els_cmd.els_code = FC_ELS_RPSC; - rpsc2->token = cpu_to_be32(FC_BRCD_TOKEN); - rpsc2->num_pids = cpu_to_be16(npids); - for (i = 0; i < npids; i++) - rpsc2->pid_list[i].pid = pid_list[i]; - - return sizeof(struct fc_rpsc2_cmd_s) + ((npids - 1) * (sizeof(u32))); -} - -u16 -fc_rpsc_acc_build(struct fchs_s *fchs, struct fc_rpsc_acc_s *rpsc_acc, - u32 d_id, u32 s_id, __be16 ox_id, - struct fc_rpsc_speed_info_s *oper_speed) -{ - memset(rpsc_acc, 0, sizeof(struct fc_rpsc_acc_s)); - - fc_els_rsp_build(fchs, d_id, s_id, ox_id); - - rpsc_acc->command = FC_ELS_ACC; - rpsc_acc->num_entries = cpu_to_be16(1); - - rpsc_acc->speed_info[0].port_speed_cap = - cpu_to_be16(oper_speed->port_speed_cap); - - rpsc_acc->speed_info[0].port_op_speed = - cpu_to_be16(oper_speed->port_op_speed); - - return sizeof(struct fc_rpsc_acc_s); -} - -u16 -fc_logo_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - len = len; - if (els_cmd->els_code != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - -u16 -fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, - wwn_t port_name, wwn_t node_name, u16 pdu_size) -{ - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); - - memcpy(pdisc, &plogi_tmpl, sizeof(struct fc_logi_s)); - - pdisc->els_cmd.els_code = FC_ELS_PDISC; - fc_els_req_build(fchs, d_id, s_id, ox_id); - - pdisc->csp.rxsz = pdisc->class3.rxsz = cpu_to_be16(pdu_size); - pdisc->port_name = port_name; - pdisc->node_name = node_name; - - return sizeof(struct fc_logi_s); -} - -u16 -fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name) -{ - struct fc_logi_s *pdisc = (struct fc_logi_s *) (fchs + 1); - - if (len < sizeof(struct fc_logi_s)) - return FC_PARSE_LEN_INVAL; - - if (pdisc->els_cmd.els_code != FC_ELS_ACC) - return FC_PARSE_ACC_INVAL; - - if (!wwn_is_equal(pdisc->port_name, port_name)) - return FC_PARSE_PWWN_NOT_EQUAL; - - if (!pdisc->class3.class_valid) - return FC_PARSE_NWWN_NOT_EQUAL; - - if (be16_to_cpu(pdisc->class3.rxsz) < (FC_MIN_PDUSZ)) - return FC_PARSE_RXSZ_INVAL; - - return FC_PARSE_OK; -} - -u16 -fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, - int num_pages) -{ - struct fc_prlo_s *prlo = (struct fc_prlo_s *) (fchs + 1); - int page; - - fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(prlo, 0, (num_pages * 16) + 4); - prlo->command = FC_ELS_PRLO; - prlo->page_len = 0x10; - prlo->payload_len = cpu_to_be16((num_pages * 16) + 4); - - for (page = 0; page < num_pages; page++) { - prlo->prlo_params[page].type = FC_TYPE_FCP; - prlo->prlo_params[page].opa_valid = 0; - prlo->prlo_params[page].rpa_valid = 0; - prlo->prlo_params[page].orig_process_assc = 0; - prlo->prlo_params[page].resp_process_assc = 0; - } - - return be16_to_cpu(prlo->payload_len); -} - -u16 -fc_prlo_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_prlo_acc_s *prlo = (struct fc_prlo_acc_s *) (fchs + 1); - int num_pages = 0; - int page = 0; - - len = len; - - if (prlo->command != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - num_pages = ((be16_to_cpu(prlo->payload_len)) - 4) / 16; - - for (page = 0; page < num_pages; page++) { - if (prlo->prlo_acc_params[page].type != FC_TYPE_FCP) - return FC_PARSE_FAILURE; - - if (prlo->prlo_acc_params[page].opa_valid != 0) - return FC_PARSE_FAILURE; - - if (prlo->prlo_acc_params[page].rpa_valid != 0) - return FC_PARSE_FAILURE; - - if (prlo->prlo_acc_params[page].orig_process_assc != 0) - return FC_PARSE_FAILURE; - - if (prlo->prlo_acc_params[page].resp_process_assc != 0) - return FC_PARSE_FAILURE; - } - return FC_PARSE_OK; - -} - -u16 -fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, u16 ox_id, - int num_pages, enum fc_tprlo_type tprlo_type, u32 tpr_id) -{ - struct fc_tprlo_s *tprlo = (struct fc_tprlo_s *) (fchs + 1); - int page; - - fc_els_req_build(fchs, d_id, s_id, ox_id); - memset(tprlo, 0, (num_pages * 16) + 4); - tprlo->command = FC_ELS_TPRLO; - tprlo->page_len = 0x10; - tprlo->payload_len = cpu_to_be16((num_pages * 16) + 4); - - for (page = 0; page < num_pages; page++) { - tprlo->tprlo_params[page].type = FC_TYPE_FCP; - tprlo->tprlo_params[page].opa_valid = 0; - tprlo->tprlo_params[page].rpa_valid = 0; - tprlo->tprlo_params[page].orig_process_assc = 0; - tprlo->tprlo_params[page].resp_process_assc = 0; - if (tprlo_type == FC_GLOBAL_LOGO) { - tprlo->tprlo_params[page].global_process_logout = 1; - } else if (tprlo_type == FC_TPR_LOGO) { - tprlo->tprlo_params[page].tpo_nport_valid = 1; - tprlo->tprlo_params[page].tpo_nport_id = (tpr_id); - } - } - - return be16_to_cpu(tprlo->payload_len); -} - -u16 -fc_tprlo_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_tprlo_acc_s *tprlo = (struct fc_tprlo_acc_s *) (fchs + 1); - int num_pages = 0; - int page = 0; - - len = len; - - if (tprlo->command != FC_ELS_ACC) - return FC_PARSE_ACC_INVAL; - - num_pages = (be16_to_cpu(tprlo->payload_len) - 4) / 16; - - for (page = 0; page < num_pages; page++) { - if (tprlo->tprlo_acc_params[page].type != FC_TYPE_FCP) - return FC_PARSE_NOT_FCP; - if (tprlo->tprlo_acc_params[page].opa_valid != 0) - return FC_PARSE_OPAFLAG_INVAL; - if (tprlo->tprlo_acc_params[page].rpa_valid != 0) - return FC_PARSE_RPAFLAG_INVAL; - if (tprlo->tprlo_acc_params[page].orig_process_assc != 0) - return FC_PARSE_OPA_INVAL; - if (tprlo->tprlo_acc_params[page].resp_process_assc != 0) - return FC_PARSE_RPA_INVAL; - } - return FC_PARSE_OK; -} - -enum fc_parse_status -fc_rrq_rsp_parse(struct fchs_s *fchs, int len) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - len = len; - if (els_cmd->els_code != FC_ELS_ACC) - return FC_PARSE_FAILURE; - - return FC_PARSE_OK; -} - -u16 -fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, __be16 ox_id, - u32 reason_code, u32 reason_expl) -{ - struct fc_ba_rjt_s *ba_rjt = (struct fc_ba_rjt_s *) (fchs + 1); - - fc_bls_rsp_build(fchs, d_id, s_id, ox_id); - - fchs->cat_info = FC_CAT_BA_RJT; - ba_rjt->reason_code = reason_code; - ba_rjt->reason_expl = reason_expl; - return sizeof(struct fc_ba_rjt_s); -} - -static void -fc_gs_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code) -{ - memset(cthdr, 0, sizeof(struct ct_hdr_s)); - cthdr->rev_id = CT_GS3_REVISION; - cthdr->gs_type = CT_GSTYPE_DIRSERVICE; - cthdr->gs_sub_type = CT_GSSUBTYPE_NAMESERVER; - cthdr->cmd_rsp_code = cpu_to_be16(cmd_code); -} - -static void -fc_gs_fdmi_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code) -{ - memset(cthdr, 0, sizeof(struct ct_hdr_s)); - cthdr->rev_id = CT_GS3_REVISION; - cthdr->gs_type = CT_GSTYPE_MGMTSERVICE; - cthdr->gs_sub_type = CT_GSSUBTYPE_HBA_MGMTSERVER; - cthdr->cmd_rsp_code = cpu_to_be16(cmd_code); -} - -static void -fc_gs_ms_cthdr_build(struct ct_hdr_s *cthdr, u32 s_id, u16 cmd_code, - u8 sub_type) -{ - memset(cthdr, 0, sizeof(struct ct_hdr_s)); - cthdr->rev_id = CT_GS3_REVISION; - cthdr->gs_type = CT_GSTYPE_MGMTSERVICE; - cthdr->gs_sub_type = sub_type; - cthdr->cmd_rsp_code = cpu_to_be16(cmd_code); -} - -u16 -fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - wwn_t port_name) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_gidpn_req_s *gidpn = (struct fcgs_gidpn_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_GID_PN); - - memset(gidpn, 0, sizeof(struct fcgs_gidpn_req_s)); - gidpn->port_name = port_name; - return sizeof(struct fcgs_gidpn_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_gpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u32 port_id) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - fcgs_gpnid_req_t *gpnid = (fcgs_gpnid_req_t *) (cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_GPN_ID); - - memset(gpnid, 0, sizeof(fcgs_gpnid_req_t)); - gpnid->dap = port_id; - return sizeof(fcgs_gpnid_req_t) + sizeof(struct ct_hdr_s); -} - -u16 -fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u32 port_id) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - fcgs_gnnid_req_t *gnnid = (fcgs_gnnid_req_t *) (cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_GNN_ID); - - memset(gnnid, 0, sizeof(fcgs_gnnid_req_t)); - gnnid->dap = port_id; - return sizeof(fcgs_gnnid_req_t) + sizeof(struct ct_hdr_s); -} - -u16 -fc_ct_rsp_parse(struct ct_hdr_s *cthdr) -{ - if (be16_to_cpu(cthdr->cmd_rsp_code) != CT_RSP_ACCEPT) { - if (cthdr->reason_code == CT_RSN_LOGICAL_BUSY) - return FC_PARSE_BUSY; - else - return FC_PARSE_FAILURE; - } - - return FC_PARSE_OK; -} - -u16 -fc_gs_rjt_build(struct fchs_s *fchs, struct ct_hdr_s *cthdr, - u32 d_id, u32 s_id, u16 ox_id, u8 reason_code, - u8 reason_code_expl) -{ - fc_gsresp_fchdr_build(fchs, d_id, s_id, ox_id); - - cthdr->cmd_rsp_code = cpu_to_be16(CT_RSP_REJECT); - cthdr->rev_id = CT_GS3_REVISION; - - cthdr->reason_code = reason_code; - cthdr->exp_code = reason_code_expl; - return sizeof(struct ct_hdr_s); -} - -u16 -fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, - u8 set_br_reg, u32 s_id, u16 ox_id) -{ - u32 d_id = bfa_hton3b(FC_FABRIC_CONTROLLER); - - fc_els_req_build(fchs, d_id, s_id, ox_id); - - memset(scr, 0, sizeof(struct fc_scr_s)); - scr->command = FC_ELS_SCR; - scr->reg_func = FC_SCR_REG_FUNC_FULL; - if (set_br_reg) - scr->vu_reg_func = FC_VU_SCR_REG_FUNC_FABRIC_NAME_CHANGE; - - return sizeof(struct fc_scr_s); -} - -u16 -fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, - u32 s_id, u16 ox_id) -{ - u32 d_id = bfa_hton3b(FC_FABRIC_CONTROLLER); - u16 payldlen; - - fc_els_req_build(fchs, d_id, s_id, ox_id); - rscn->command = FC_ELS_RSCN; - rscn->pagelen = sizeof(rscn->event[0]); - - payldlen = sizeof(u32) + rscn->pagelen; - rscn->payldlen = cpu_to_be16(payldlen); - - rscn->event[0].format = FC_RSCN_FORMAT_PORTID; - rscn->event[0].portid = s_id; - - return sizeof(struct fc_rscn_pl_s); -} - -u16 -fc_rftid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - enum bfa_lport_role roles) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1); - u32 type_value, d_id = bfa_hton3b(FC_NAME_SERVER); - u8 index; - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID); - - memset(rftid, 0, sizeof(struct fcgs_rftid_req_s)); - - rftid->dap = s_id; - - /* By default, FCP FC4 Type is registered */ - index = FC_TYPE_FCP >> 5; - type_value = 1 << (FC_TYPE_FCP % 32); - rftid->fc4_type[index] = cpu_to_be32(type_value); - - return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u8 *fc4_bitmap, u32 bitmap_size) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rftid_req_s *rftid = (struct fcgs_rftid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_RFT_ID); - - memset(rftid, 0, sizeof(struct fcgs_rftid_req_s)); - - rftid->dap = s_id; - memcpy((void *)rftid->fc4_type, (void *)fc4_bitmap, - (bitmap_size < 32 ? bitmap_size : 32)); - - return sizeof(struct fcgs_rftid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u8 fc4_type, u8 fc4_ftrs) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rffid_req_s *rffid = (struct fcgs_rffid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_RFF_ID); - - memset(rffid, 0, sizeof(struct fcgs_rffid_req_s)); - - rffid->dap = s_id; - rffid->fc4ftr_bits = fc4_ftrs; - rffid->fc4_type = fc4_type; - - return sizeof(struct fcgs_rffid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_rspnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u8 *name) -{ - - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rspnid_req_s *rspnid = - (struct fcgs_rspnid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, ox_id); - fc_gs_cthdr_build(cthdr, s_id, GS_RSPN_ID); - - memset(rspnid, 0, sizeof(struct fcgs_rspnid_req_s)); - - rspnid->dap = s_id; - rspnid->spn_len = (u8) strlen((char *)name); - strncpy((char *)rspnid->spn, (char *)name, rspnid->spn_len); - - return sizeof(struct fcgs_rspnid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_gid_ft_build(struct fchs_s *fchs, void *pyld, u32 s_id, u8 fc4_type) -{ - - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_gidft_req_s *gidft = (struct fcgs_gidft_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - - fc_gs_cthdr_build(cthdr, s_id, GS_GID_FT); - - memset(gidft, 0, sizeof(struct fcgs_gidft_req_s)); - gidft->fc4_type = fc4_type; - gidft->domain_id = 0; - gidft->area_id = 0; - - return sizeof(struct fcgs_gidft_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, - wwn_t port_name) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rpnid_req_s *rpnid = (struct fcgs_rpnid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_RPN_ID); - - memset(rpnid, 0, sizeof(struct fcgs_rpnid_req_s)); - rpnid->port_id = port_id; - rpnid->port_name = port_name; - - return sizeof(struct fcgs_rpnid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, - wwn_t node_name) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rnnid_req_s *rnnid = (struct fcgs_rnnid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_RNN_ID); - - memset(rnnid, 0, sizeof(struct fcgs_rnnid_req_s)); - rnnid->port_id = port_id; - rnnid->node_name = node_name; - - return sizeof(struct fcgs_rnnid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, - u32 cos) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rcsid_req_s *rcsid = - (struct fcgs_rcsid_req_s *) (cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_RCS_ID); - - memset(rcsid, 0, sizeof(struct fcgs_rcsid_req_s)); - rcsid->port_id = port_id; - rcsid->cos = cos; - - return sizeof(struct fcgs_rcsid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id, - u8 port_type) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_rptid_req_s *rptid = (struct fcgs_rptid_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_RPT_ID); - - memset(rptid, 0, sizeof(struct fcgs_rptid_req_s)); - rptid->port_id = port_id; - rptid->port_type = port_type; - - return sizeof(struct fcgs_rptid_req_s) + sizeof(struct ct_hdr_s); -} - -u16 -fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, u32 port_id) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - struct fcgs_ganxt_req_s *ganxt = (struct fcgs_ganxt_req_s *)(cthdr + 1); - u32 d_id = bfa_hton3b(FC_NAME_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_cthdr_build(cthdr, s_id, GS_GA_NXT); - - memset(ganxt, 0, sizeof(struct fcgs_ganxt_req_s)); - ganxt->port_id = port_id; - - return sizeof(struct ct_hdr_s) + sizeof(struct fcgs_ganxt_req_s); -} - -/* - * Builds fc hdr and ct hdr for FDMI requests. - */ -u16 -fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 cmd_code) -{ - - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - u32 d_id = bfa_hton3b(FC_MGMT_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_fdmi_cthdr_build(cthdr, s_id, cmd_code); - - return sizeof(struct ct_hdr_s); -} - -/* - * Given a FC4 Type, this function returns a fc4 type bitmask - */ -void -fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask) -{ - u8 index; - __be32 *ptr = (__be32 *) bit_mask; - u32 type_value; - - /* - * @todo : Check for bitmask size - */ - - index = fc4_type >> 5; - type_value = 1 << (fc4_type % 32); - ptr[index] = cpu_to_be32(type_value); - -} - -/* - * GMAL Request - */ -u16 -fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - fcgs_gmal_req_t *gmal = (fcgs_gmal_req_t *) (cthdr + 1); - u32 d_id = bfa_hton3b(FC_MGMT_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GMAL_CMD, - CT_GSSUBTYPE_CFGSERVER); - - memset(gmal, 0, sizeof(fcgs_gmal_req_t)); - gmal->wwn = wwn; - - return sizeof(struct ct_hdr_s) + sizeof(fcgs_gmal_req_t); -} - -/* - * GFN (Get Fabric Name) Request - */ -u16 -fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn) -{ - struct ct_hdr_s *cthdr = (struct ct_hdr_s *) pyld; - fcgs_gfn_req_t *gfn = (fcgs_gfn_req_t *) (cthdr + 1); - u32 d_id = bfa_hton3b(FC_MGMT_SERVER); - - fc_gs_fchdr_build(fchs, d_id, s_id, 0); - fc_gs_ms_cthdr_build(cthdr, s_id, GS_FC_GFN_CMD, - CT_GSSUBTYPE_CFGSERVER); - - memset(gfn, 0, sizeof(fcgs_gfn_req_t)); - gfn->wwn = wwn; - - return sizeof(struct ct_hdr_s) + sizeof(fcgs_gfn_req_t); -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.h deleted file mode 100644 index 42cd9d4d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcbuild.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -/* - * fcbuild.h - FC link service frame building and parsing routines - */ - -#ifndef __FCBUILD_H__ -#define __FCBUILD_H__ - -#include "bfad_drv.h" -#include "bfa_fc.h" -#include "bfa_defs_fcs.h" - -/* - * Utility Macros/functions - */ - -#define wwn_is_equal(_wwn1, _wwn2) \ - (memcmp(&(_wwn1), &(_wwn2), sizeof(wwn_t)) == 0) - -#define fc_roundup(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1)) - -/* - * Given the fc response length, this routine will return - * the length of the actual payload bytes following the CT header. - * - * Assumes the input response length does not include the crc, eof, etc. - */ -static inline u32 -fc_get_ctresp_pyld_len(u32 resp_len) -{ - return resp_len - sizeof(struct ct_hdr_s); -} - -/* - * Convert bfa speed to rpsc speed value. - */ -static inline enum bfa_port_speed -fc_rpsc_operspeed_to_bfa_speed(enum fc_rpsc_op_speed speed) -{ - switch (speed) { - - case RPSC_OP_SPEED_1G: - return BFA_PORT_SPEED_1GBPS; - - case RPSC_OP_SPEED_2G: - return BFA_PORT_SPEED_2GBPS; - - case RPSC_OP_SPEED_4G: - return BFA_PORT_SPEED_4GBPS; - - case RPSC_OP_SPEED_8G: - return BFA_PORT_SPEED_8GBPS; - - case RPSC_OP_SPEED_16G: - return BFA_PORT_SPEED_16GBPS; - - case RPSC_OP_SPEED_10G: - return BFA_PORT_SPEED_10GBPS; - - default: - return BFA_PORT_SPEED_UNKNOWN; - } -} - -/* - * Convert RPSC speed to bfa speed value. - */ -static inline enum fc_rpsc_op_speed -fc_bfa_speed_to_rpsc_operspeed(enum bfa_port_speed op_speed) -{ - switch (op_speed) { - - case BFA_PORT_SPEED_1GBPS: - return RPSC_OP_SPEED_1G; - - case BFA_PORT_SPEED_2GBPS: - return RPSC_OP_SPEED_2G; - - case BFA_PORT_SPEED_4GBPS: - return RPSC_OP_SPEED_4G; - - case BFA_PORT_SPEED_8GBPS: - return RPSC_OP_SPEED_8G; - - case BFA_PORT_SPEED_16GBPS: - return RPSC_OP_SPEED_16G; - - case BFA_PORT_SPEED_10GBPS: - return RPSC_OP_SPEED_10G; - - default: - return RPSC_OP_SPEED_NOT_EST; - } -} - -enum fc_parse_status { - FC_PARSE_OK = 0, - FC_PARSE_FAILURE = 1, - FC_PARSE_BUSY = 2, - FC_PARSE_LEN_INVAL, - FC_PARSE_ACC_INVAL, - FC_PARSE_PWWN_NOT_EQUAL, - FC_PARSE_NWWN_NOT_EQUAL, - FC_PARSE_RXSZ_INVAL, - FC_PARSE_NOT_FCP, - FC_PARSE_OPAFLAG_INVAL, - FC_PARSE_RPAFLAG_INVAL, - FC_PARSE_OPA_INVAL, - FC_PARSE_RPA_INVAL, - -}; - -struct fc_templates_s { - struct fchs_s fc_els_req; - struct fchs_s fc_bls_req; - struct fc_logi_s plogi; - struct fc_rrq_s rrq; -}; - -void fcbuild_init(void); - -u16 fc_flogi_build(struct fchs_s *fchs, struct fc_logi_s *flogi, - u32 s_id, u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size, u8 set_npiv, u8 set_auth, - u16 local_bb_credits); - -u16 fc_fdisc_build(struct fchs_s *buf, struct fc_logi_s *flogi, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size); - -u16 fc_flogi_acc_build(struct fchs_s *fchs, struct fc_logi_s *flogi, - u32 s_id, __be16 ox_id, - wwn_t port_name, wwn_t node_name, - u16 pdu_size, - u16 local_bb_credits, u8 bb_scn); - -u16 fc_plogi_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, u16 ox_id, wwn_t port_name, - wwn_t node_name, u16 pdu_size, u16 bb_cr); - -enum fc_parse_status fc_plogi_parse(struct fchs_s *fchs); - -u16 fc_abts_build(struct fchs_s *buf, u32 d_id, u32 s_id, - u16 ox_id); - -enum fc_parse_status fc_abts_rsp_parse(struct fchs_s *buf, int len); - -u16 fc_rrq_build(struct fchs_s *buf, struct fc_rrq_s *rrq, u32 d_id, - u32 s_id, u16 ox_id, u16 rrq_oxid); -enum fc_parse_status fc_rrq_rsp_parse(struct fchs_s *buf, int len); - -u16 fc_rspnid_build(struct fchs_s *fchs, void *pld, u32 s_id, - u16 ox_id, u8 *name); - -u16 fc_rftid_build(struct fchs_s *fchs, void *pld, u32 s_id, - u16 ox_id, enum bfa_lport_role role); - -u16 fc_rftid_build_sol(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, u8 *fc4_bitmap, - u32 bitmap_size); - -u16 fc_rffid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, u8 fc4_type, u8 fc4_ftrs); - -u16 fc_gidpn_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 ox_id, wwn_t port_name); - -u16 fc_gpnid_build(struct fchs_s *fchs, void *pld, u32 s_id, - u16 ox_id, u32 port_id); - -u16 fc_gs_rjt_build(struct fchs_s *fchs, struct ct_hdr_s *cthdr, - u32 d_id, u32 s_id, u16 ox_id, - u8 reason_code, u8 reason_code_expl); - -u16 fc_scr_build(struct fchs_s *fchs, struct fc_scr_s *scr, - u8 set_br_reg, u32 s_id, u16 ox_id); - -u16 fc_plogi_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, u16 ox_id, - wwn_t port_name, wwn_t node_name, - u16 pdu_size, u16 bb_cr); - -u16 fc_adisc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, - u32 d_id, u32 s_id, __be16 ox_id, wwn_t port_name, - wwn_t node_name); - -enum fc_parse_status fc_adisc_parse(struct fchs_s *fchs, void *pld, - u32 host_dap, wwn_t node_name, wwn_t port_name); - -enum fc_parse_status fc_adisc_rsp_parse(struct fc_adisc_s *adisc, int len, - wwn_t port_name, wwn_t node_name); - -u16 fc_adisc_acc_build(struct fchs_s *fchs, struct fc_adisc_s *adisc, - u32 d_id, u32 s_id, __be16 ox_id, - wwn_t port_name, wwn_t node_name); -u16 fc_ls_rjt_build(struct fchs_s *fchs, struct fc_ls_rjt_s *ls_rjt, - u32 d_id, u32 s_id, __be16 ox_id, - u8 reason_code, u8 reason_code_expl); -u16 fc_ls_acc_build(struct fchs_s *fchs, struct fc_els_cmd_s *els_cmd, - u32 d_id, u32 s_id, __be16 ox_id); -u16 fc_prli_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, u16 ox_id); - -enum fc_parse_status fc_prli_rsp_parse(struct fc_prli_s *prli, int len); - -u16 fc_prli_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, __be16 ox_id, - enum bfa_lport_role role); - -u16 fc_rnid_build(struct fchs_s *fchs, struct fc_rnid_cmd_s *rnid, - u32 d_id, u32 s_id, u16 ox_id, - u32 data_format); - -u16 fc_rnid_acc_build(struct fchs_s *fchs, - struct fc_rnid_acc_s *rnid_acc, u32 d_id, u32 s_id, - __be16 ox_id, u32 data_format, - struct fc_rnid_common_id_data_s *common_id_data, - struct fc_rnid_general_topology_data_s *gen_topo_data); - -u16 fc_rpsc2_build(struct fchs_s *fchs, struct fc_rpsc2_cmd_s *rps2c, - u32 d_id, u32 s_id, u32 *pid_list, u16 npids); -u16 fc_rpsc_build(struct fchs_s *fchs, struct fc_rpsc_cmd_s *rpsc, - u32 d_id, u32 s_id, u16 ox_id); -u16 fc_rpsc_acc_build(struct fchs_s *fchs, - struct fc_rpsc_acc_s *rpsc_acc, u32 d_id, u32 s_id, - __be16 ox_id, struct fc_rpsc_speed_info_s *oper_speed); -u16 fc_gid_ft_build(struct fchs_s *fchs, void *pld, u32 s_id, - u8 fc4_type); - -u16 fc_rpnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, wwn_t port_name); - -u16 fc_rnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, wwn_t node_name); - -u16 fc_rcsid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, u32 cos); - -u16 fc_rptid_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id, u8 port_type); - -u16 fc_ganxt_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u32 port_id); - -u16 fc_logo_build(struct fchs_s *fchs, struct fc_logo_s *logo, u32 d_id, - u32 s_id, u16 ox_id, wwn_t port_name); - -u16 fc_logo_acc_build(struct fchs_s *fchs, void *pld, u32 d_id, - u32 s_id, __be16 ox_id); - -u16 fc_fdmi_reqhdr_build(struct fchs_s *fchs, void *pyld, u32 s_id, - u16 cmd_code); -u16 fc_gmal_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn); -u16 fc_gfn_req_build(struct fchs_s *fchs, void *pyld, u32 s_id, wwn_t wwn); - -void fc_get_fc4type_bitmask(u8 fc4_type, u8 *bit_mask); - -void fc_els_req_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - __be16 ox_id); - -enum fc_parse_status fc_els_rsp_parse(struct fchs_s *fchs, int len); - -enum fc_parse_status fc_plogi_rsp_parse(struct fchs_s *fchs, int len, - wwn_t port_name); - -enum fc_parse_status fc_prli_parse(struct fc_prli_s *prli); - -enum fc_parse_status fc_pdisc_parse(struct fchs_s *fchs, wwn_t node_name, - wwn_t port_name); - -u16 fc_ba_acc_build(struct fchs_s *fchs, struct fc_ba_acc_s *ba_acc, u32 d_id, - u32 s_id, __be16 ox_id, u16 rx_id); - -int fc_logout_params_pages(struct fchs_s *fc_frame, u8 els_code); - -u16 fc_tprlo_acc_build(struct fchs_s *fchs, struct fc_tprlo_acc_s *tprlo_acc, - u32 d_id, u32 s_id, __be16 ox_id, int num_pages); - -u16 fc_prlo_acc_build(struct fchs_s *fchs, struct fc_prlo_acc_s *prlo_acc, - u32 d_id, u32 s_id, __be16 ox_id, int num_pages); - -u16 fc_logo_rsp_parse(struct fchs_s *fchs, int len); - -u16 fc_pdisc_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, wwn_t port_name, wwn_t node_name, - u16 pdu_size); - -u16 fc_pdisc_rsp_parse(struct fchs_s *fchs, int len, wwn_t port_name); - -u16 fc_prlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, int num_pages); - -u16 fc_prlo_rsp_parse(struct fchs_s *fchs, int len); - -u16 fc_tprlo_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - u16 ox_id, int num_pages, enum fc_tprlo_type tprlo_type, - u32 tpr_id); - -u16 fc_tprlo_rsp_parse(struct fchs_s *fchs, int len); - -u16 fc_ba_rjt_build(struct fchs_s *fchs, u32 d_id, u32 s_id, - __be16 ox_id, u32 reason_code, u32 reason_expl); - -u16 fc_gnnid_build(struct fchs_s *fchs, void *pyld, u32 s_id, u16 ox_id, - u32 port_id); - -u16 fc_ct_rsp_parse(struct ct_hdr_s *cthdr); - -u16 fc_rscn_build(struct fchs_s *fchs, struct fc_rscn_pl_s *rscn, u32 s_id, - u16 ox_id); -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.c deleted file mode 100644 index f0f80e28..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.c +++ /dev/null @@ -1,3825 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfa_modules.h" - -BFA_TRC_FILE(HAL, FCPIM); - -/* - * BFA ITNIM Related definitions - */ -static void bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim); -static void bfa_ioim_lm_init(struct bfa_s *bfa); - -#define BFA_ITNIM_FROM_TAG(_fcpim, _tag) \ - (((_fcpim)->itnim_arr + ((_tag) & ((_fcpim)->num_itnims - 1)))) - -#define bfa_fcpim_additn(__itnim) \ - list_add_tail(&(__itnim)->qe, &(__itnim)->fcpim->itnim_q) -#define bfa_fcpim_delitn(__itnim) do { \ - WARN_ON(!bfa_q_is_on_q(&(__itnim)->fcpim->itnim_q, __itnim)); \ - bfa_itnim_update_del_itn_stats(__itnim); \ - list_del(&(__itnim)->qe); \ - WARN_ON(!list_empty(&(__itnim)->io_q)); \ - WARN_ON(!list_empty(&(__itnim)->io_cleanup_q)); \ - WARN_ON(!list_empty(&(__itnim)->pending_q)); \ -} while (0) - -#define bfa_itnim_online_cb(__itnim) do { \ - if ((__itnim)->bfa->fcs) \ - bfa_cb_itnim_online((__itnim)->ditn); \ - else { \ - bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ - __bfa_cb_itnim_online, (__itnim)); \ - } \ -} while (0) - -#define bfa_itnim_offline_cb(__itnim) do { \ - if ((__itnim)->bfa->fcs) \ - bfa_cb_itnim_offline((__itnim)->ditn); \ - else { \ - bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ - __bfa_cb_itnim_offline, (__itnim)); \ - } \ -} while (0) - -#define bfa_itnim_sler_cb(__itnim) do { \ - if ((__itnim)->bfa->fcs) \ - bfa_cb_itnim_sler((__itnim)->ditn); \ - else { \ - bfa_cb_queue((__itnim)->bfa, &(__itnim)->hcb_qe, \ - __bfa_cb_itnim_sler, (__itnim)); \ - } \ -} while (0) - -enum bfa_ioim_lm_ua_status { - BFA_IOIM_LM_UA_RESET = 0, - BFA_IOIM_LM_UA_SET = 1, -}; - -/* - * itnim state machine event - */ -enum bfa_itnim_event { - BFA_ITNIM_SM_CREATE = 1, /* itnim is created */ - BFA_ITNIM_SM_ONLINE = 2, /* itnim is online */ - BFA_ITNIM_SM_OFFLINE = 3, /* itnim is offline */ - BFA_ITNIM_SM_FWRSP = 4, /* firmware response */ - BFA_ITNIM_SM_DELETE = 5, /* deleting an existing itnim */ - BFA_ITNIM_SM_CLEANUP = 6, /* IO cleanup completion */ - BFA_ITNIM_SM_SLER = 7, /* second level error recovery */ - BFA_ITNIM_SM_HWFAIL = 8, /* IOC h/w failure event */ - BFA_ITNIM_SM_QRESUME = 9, /* queue space available */ -}; - -/* - * BFA IOIM related definitions - */ -#define bfa_ioim_move_to_comp_q(__ioim) do { \ - list_del(&(__ioim)->qe); \ - list_add_tail(&(__ioim)->qe, &(__ioim)->fcpim->ioim_comp_q); \ -} while (0) - - -#define bfa_ioim_cb_profile_comp(__fcpim, __ioim) do { \ - if ((__fcpim)->profile_comp) \ - (__fcpim)->profile_comp(__ioim); \ -} while (0) - -#define bfa_ioim_cb_profile_start(__fcpim, __ioim) do { \ - if ((__fcpim)->profile_start) \ - (__fcpim)->profile_start(__ioim); \ -} while (0) - -/* - * IO state machine events - */ -enum bfa_ioim_event { - BFA_IOIM_SM_START = 1, /* io start request from host */ - BFA_IOIM_SM_COMP_GOOD = 2, /* io good comp, resource free */ - BFA_IOIM_SM_COMP = 3, /* io comp, resource is free */ - BFA_IOIM_SM_COMP_UTAG = 4, /* io comp, resource is free */ - BFA_IOIM_SM_DONE = 5, /* io comp, resource not free */ - BFA_IOIM_SM_FREE = 6, /* io resource is freed */ - BFA_IOIM_SM_ABORT = 7, /* abort request from scsi stack */ - BFA_IOIM_SM_ABORT_COMP = 8, /* abort from f/w */ - BFA_IOIM_SM_ABORT_DONE = 9, /* abort completion from f/w */ - BFA_IOIM_SM_QRESUME = 10, /* CQ space available to queue IO */ - BFA_IOIM_SM_SGALLOCED = 11, /* SG page allocation successful */ - BFA_IOIM_SM_SQRETRY = 12, /* sequence recovery retry */ - BFA_IOIM_SM_HCB = 13, /* bfa callback complete */ - BFA_IOIM_SM_CLEANUP = 14, /* IO cleanup from itnim */ - BFA_IOIM_SM_TMSTART = 15, /* IO cleanup from tskim */ - BFA_IOIM_SM_TMDONE = 16, /* IO cleanup from tskim */ - BFA_IOIM_SM_HWFAIL = 17, /* IOC h/w failure event */ - BFA_IOIM_SM_IOTOV = 18, /* ITN offline TOV */ -}; - - -/* - * BFA TSKIM related definitions - */ - -/* - * task management completion handling - */ -#define bfa_tskim_qcomp(__tskim, __cbfn) do { \ - bfa_cb_queue((__tskim)->bfa, &(__tskim)->hcb_qe, __cbfn, (__tskim));\ - bfa_tskim_notify_comp(__tskim); \ -} while (0) - -#define bfa_tskim_notify_comp(__tskim) do { \ - if ((__tskim)->notify) \ - bfa_itnim_tskdone((__tskim)->itnim); \ -} while (0) - - -enum bfa_tskim_event { - BFA_TSKIM_SM_START = 1, /* TM command start */ - BFA_TSKIM_SM_DONE = 2, /* TM completion */ - BFA_TSKIM_SM_QRESUME = 3, /* resume after qfull */ - BFA_TSKIM_SM_HWFAIL = 5, /* IOC h/w failure event */ - BFA_TSKIM_SM_HCB = 6, /* BFA callback completion */ - BFA_TSKIM_SM_IOS_DONE = 7, /* IO and sub TM completions */ - BFA_TSKIM_SM_CLEANUP = 8, /* TM cleanup on ITN offline */ - BFA_TSKIM_SM_CLEANUP_DONE = 9, /* TM abort completion */ -}; - -/* - * forward declaration for BFA ITNIM functions - */ -static void bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim); -static bfa_boolean_t bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim); -static bfa_boolean_t bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim); -static void bfa_itnim_cleanp_comp(void *itnim_cbarg); -static void bfa_itnim_cleanup(struct bfa_itnim_s *itnim); -static void __bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete); -static void bfa_itnim_iotov_online(struct bfa_itnim_s *itnim); -static void bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim); -static void bfa_itnim_iotov(void *itnim_arg); -static void bfa_itnim_iotov_start(struct bfa_itnim_s *itnim); -static void bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim); -static void bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim); - -/* - * forward declaration of ITNIM state machine - */ -static void bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_created(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_online(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); -static void bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event); - -/* - * forward declaration for BFA IOIM functions - */ -static bfa_boolean_t bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim); -static bfa_boolean_t bfa_ioim_sgpg_alloc(struct bfa_ioim_s *ioim); -static bfa_boolean_t bfa_ioim_send_abort(struct bfa_ioim_s *ioim); -static void bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim); -static void __bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete); -static bfa_boolean_t bfa_ioim_is_abortable(struct bfa_ioim_s *ioim); - -/* - * forward declaration of BFA IO state machine - */ -static void bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_active(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -static void bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, - enum bfa_ioim_event event); -/* - * forward declaration for BFA TSKIM functions - */ -static void __bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete); -static void __bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete); -static bfa_boolean_t bfa_tskim_match_scope(struct bfa_tskim_s *tskim, - struct scsi_lun lun); -static void bfa_tskim_gather_ios(struct bfa_tskim_s *tskim); -static void bfa_tskim_cleanp_comp(void *tskim_cbarg); -static void bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim); -static bfa_boolean_t bfa_tskim_send(struct bfa_tskim_s *tskim); -static bfa_boolean_t bfa_tskim_send_abort(struct bfa_tskim_s *tskim); -static void bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim); - -/* - * forward declaration of BFA TSKIM state machine - */ -static void bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_active(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -static void bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event); -/* - * BFA FCP Initiator Mode module - */ - -/* - * Compute and return memory needed by FCP(im) module. - */ -static void -bfa_fcpim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) -{ - bfa_itnim_meminfo(cfg, km_len); - - /* - * IO memory - */ - *km_len += cfg->fwcfg.num_ioim_reqs * - (sizeof(struct bfa_ioim_s) + sizeof(struct bfa_ioim_sp_s)); - - /* - * task management command memory - */ - if (cfg->fwcfg.num_tskim_reqs < BFA_TSKIM_MIN) - cfg->fwcfg.num_tskim_reqs = BFA_TSKIM_MIN; - *km_len += cfg->fwcfg.num_tskim_reqs * sizeof(struct bfa_tskim_s); -} - - -static void -bfa_fcpim_attach(struct bfa_fcp_mod_s *fcp, void *bfad, - struct bfa_iocfc_cfg_s *cfg, struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcpim_s *fcpim = &fcp->fcpim; - struct bfa_s *bfa = fcp->bfa; - - bfa_trc(bfa, cfg->drvcfg.path_tov); - bfa_trc(bfa, cfg->fwcfg.num_rports); - bfa_trc(bfa, cfg->fwcfg.num_ioim_reqs); - bfa_trc(bfa, cfg->fwcfg.num_tskim_reqs); - - fcpim->fcp = fcp; - fcpim->bfa = bfa; - fcpim->num_itnims = cfg->fwcfg.num_rports; - fcpim->num_tskim_reqs = cfg->fwcfg.num_tskim_reqs; - fcpim->path_tov = cfg->drvcfg.path_tov; - fcpim->delay_comp = cfg->drvcfg.delay_comp; - fcpim->profile_comp = NULL; - fcpim->profile_start = NULL; - - bfa_itnim_attach(fcpim); - bfa_tskim_attach(fcpim); - bfa_ioim_attach(fcpim); -} - -static void -bfa_fcpim_iocdisable(struct bfa_fcp_mod_s *fcp) -{ - struct bfa_fcpim_s *fcpim = &fcp->fcpim; - struct bfa_itnim_s *itnim; - struct list_head *qe, *qen; - - /* Enqueue unused ioim resources to free_q */ - list_splice_tail_init(&fcpim->tskim_unused_q, &fcpim->tskim_free_q); - - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - bfa_itnim_iocdisable(itnim); - } -} - -void -bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - - fcpim->path_tov = path_tov * 1000; - if (fcpim->path_tov > BFA_FCPIM_PATHTOV_MAX) - fcpim->path_tov = BFA_FCPIM_PATHTOV_MAX; -} - -u16 -bfa_fcpim_path_tov_get(struct bfa_s *bfa) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - - return fcpim->path_tov / 1000; -} - -#define bfa_fcpim_add_iostats(__l, __r, __stats) \ - (__l->__stats += __r->__stats) - -void -bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *lstats, - struct bfa_itnim_iostats_s *rstats) -{ - bfa_fcpim_add_iostats(lstats, rstats, total_ios); - bfa_fcpim_add_iostats(lstats, rstats, qresumes); - bfa_fcpim_add_iostats(lstats, rstats, no_iotags); - bfa_fcpim_add_iostats(lstats, rstats, io_aborts); - bfa_fcpim_add_iostats(lstats, rstats, no_tskims); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_ok); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_underrun); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_overrun); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_aborted); - bfa_fcpim_add_iostats(lstats, rstats, iocomp_timedout); - bfa_fcpim_add_iostats(lstats, rstats, iocom_nexus_abort); - bfa_fcpim_add_iostats(lstats, rstats, iocom_proto_err); - bfa_fcpim_add_iostats(lstats, rstats, iocom_dif_err); - bfa_fcpim_add_iostats(lstats, rstats, iocom_sqer_needed); - bfa_fcpim_add_iostats(lstats, rstats, iocom_res_free); - bfa_fcpim_add_iostats(lstats, rstats, iocom_hostabrts); - bfa_fcpim_add_iostats(lstats, rstats, iocom_utags); - bfa_fcpim_add_iostats(lstats, rstats, io_cleanups); - bfa_fcpim_add_iostats(lstats, rstats, io_tmaborts); - bfa_fcpim_add_iostats(lstats, rstats, onlines); - bfa_fcpim_add_iostats(lstats, rstats, offlines); - bfa_fcpim_add_iostats(lstats, rstats, creates); - bfa_fcpim_add_iostats(lstats, rstats, deletes); - bfa_fcpim_add_iostats(lstats, rstats, create_comps); - bfa_fcpim_add_iostats(lstats, rstats, delete_comps); - bfa_fcpim_add_iostats(lstats, rstats, sler_events); - bfa_fcpim_add_iostats(lstats, rstats, fw_create); - bfa_fcpim_add_iostats(lstats, rstats, fw_delete); - bfa_fcpim_add_iostats(lstats, rstats, ioc_disabled); - bfa_fcpim_add_iostats(lstats, rstats, cleanup_comps); - bfa_fcpim_add_iostats(lstats, rstats, tm_cmnds); - bfa_fcpim_add_iostats(lstats, rstats, tm_fw_rsps); - bfa_fcpim_add_iostats(lstats, rstats, tm_success); - bfa_fcpim_add_iostats(lstats, rstats, tm_failures); - bfa_fcpim_add_iostats(lstats, rstats, tm_io_comps); - bfa_fcpim_add_iostats(lstats, rstats, tm_qresumes); - bfa_fcpim_add_iostats(lstats, rstats, tm_iocdowns); - bfa_fcpim_add_iostats(lstats, rstats, tm_cleanups); - bfa_fcpim_add_iostats(lstats, rstats, tm_cleanup_comps); - bfa_fcpim_add_iostats(lstats, rstats, io_comps); - bfa_fcpim_add_iostats(lstats, rstats, input_reqs); - bfa_fcpim_add_iostats(lstats, rstats, output_reqs); - bfa_fcpim_add_iostats(lstats, rstats, rd_throughput); - bfa_fcpim_add_iostats(lstats, rstats, wr_throughput); -} - -bfa_status_t -bfa_fcpim_port_iostats(struct bfa_s *bfa, - struct bfa_itnim_iostats_s *stats, u8 lp_tag) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct list_head *qe, *qen; - struct bfa_itnim_s *itnim; - - /* accumulate IO stats from itnim */ - memset(stats, 0, sizeof(struct bfa_itnim_iostats_s)); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - if (itnim->rport->rport_info.lp_tag != lp_tag) - continue; - bfa_fcpim_add_stats(stats, &(itnim->stats)); - } - return BFA_STATUS_OK; -} - -void -bfa_ioim_profile_comp(struct bfa_ioim_s *ioim) -{ - struct bfa_itnim_latency_s *io_lat = - &(ioim->itnim->ioprofile.io_latency); - u32 val, idx; - - val = (u32)(jiffies - ioim->start_time); - idx = bfa_ioim_get_index(scsi_bufflen((struct scsi_cmnd *)ioim->dio)); - bfa_itnim_ioprofile_update(ioim->itnim, idx); - - io_lat->count[idx]++; - io_lat->min[idx] = (io_lat->min[idx] < val) ? io_lat->min[idx] : val; - io_lat->max[idx] = (io_lat->max[idx] > val) ? io_lat->max[idx] : val; - io_lat->avg[idx] += val; -} - -void -bfa_ioim_profile_start(struct bfa_ioim_s *ioim) -{ - ioim->start_time = jiffies; -} - -bfa_status_t -bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time) -{ - struct bfa_itnim_s *itnim; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct list_head *qe, *qen; - - /* accumulate IO stats from itnim */ - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - bfa_itnim_clear_stats(itnim); - } - fcpim->io_profile = BFA_TRUE; - fcpim->io_profile_start_time = time; - fcpim->profile_comp = bfa_ioim_profile_comp; - fcpim->profile_start = bfa_ioim_profile_start; - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_fcpim_profile_off(struct bfa_s *bfa) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - fcpim->io_profile = BFA_FALSE; - fcpim->io_profile_start_time = 0; - fcpim->profile_comp = NULL; - fcpim->profile_start = NULL; - return BFA_STATUS_OK; -} - -u16 -bfa_fcpim_qdepth_get(struct bfa_s *bfa) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - - return fcpim->q_depth; -} - -/* - * BFA ITNIM module state machine functions - */ - -/* - * Beginning/unallocated state - no events expected. - */ -static void -bfa_itnim_sm_uninit(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_CREATE: - bfa_sm_set_state(itnim, bfa_itnim_sm_created); - itnim->is_online = BFA_FALSE; - bfa_fcpim_additn(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Beginning state, only online event expected. - */ -static void -bfa_itnim_sm_created(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_ONLINE: - if (bfa_itnim_send_fwcreate(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_fcpim_delitn(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Waiting for itnim create response from firmware. - */ -static void -bfa_itnim_sm_fwcreate(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_FWRSP: - bfa_sm_set_state(itnim, bfa_itnim_sm_online); - itnim->is_online = BFA_TRUE; - bfa_itnim_iotov_online(itnim); - bfa_itnim_online_cb(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_delete_pending); - break; - - case BFA_ITNIM_SM_OFFLINE: - if (bfa_itnim_send_fwdelete(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -static void -bfa_itnim_sm_fwcreate_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_QRESUME: - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); - bfa_itnim_send_fwcreate(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_reqq_wcancel(&itnim->reqq_wait); - bfa_fcpim_delitn(itnim); - break; - - case BFA_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_itnim_sm_offline); - bfa_reqq_wcancel(&itnim->reqq_wait); - bfa_itnim_offline_cb(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_reqq_wcancel(&itnim->reqq_wait); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Waiting for itnim create response from firmware, a delete is pending. - */ -static void -bfa_itnim_sm_delete_pending(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_FWRSP: - if (bfa_itnim_send_fwdelete(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_fcpim_delitn(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Online state - normal parking state. - */ -static void -bfa_itnim_sm_online(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline); - itnim->is_online = BFA_FALSE; - bfa_itnim_iotov_start(itnim); - bfa_itnim_cleanup(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); - itnim->is_online = BFA_FALSE; - bfa_itnim_cleanup(itnim); - break; - - case BFA_ITNIM_SM_SLER: - bfa_sm_set_state(itnim, bfa_itnim_sm_sler); - itnim->is_online = BFA_FALSE; - bfa_itnim_iotov_start(itnim); - bfa_itnim_sler_cb(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - itnim->is_online = BFA_FALSE; - bfa_itnim_iotov_start(itnim); - bfa_itnim_iocdisable_cleanup(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Second level error recovery need. - */ -static void -bfa_itnim_sm_sler(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_offline); - bfa_itnim_cleanup(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); - bfa_itnim_cleanup(itnim); - bfa_itnim_iotov_delete(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_itnim_iocdisable_cleanup(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Going offline. Waiting for active IO cleanup. - */ -static void -bfa_itnim_sm_cleanup_offline(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_CLEANUP: - if (bfa_itnim_send_fwdelete(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete_qfull); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_cleanup_delete); - bfa_itnim_iotov_delete(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_itnim_iocdisable_cleanup(itnim); - bfa_itnim_offline_cb(itnim); - break; - - case BFA_ITNIM_SM_SLER: - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Deleting itnim. Waiting for active IO cleanup. - */ -static void -bfa_itnim_sm_cleanup_delete(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_CLEANUP: - if (bfa_itnim_send_fwdelete(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_itnim_iocdisable_cleanup(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Rport offline. Fimrware itnim is being deleted - awaiting f/w response. - */ -static void -bfa_itnim_sm_fwdelete(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_FWRSP: - bfa_sm_set_state(itnim, bfa_itnim_sm_offline); - bfa_itnim_offline_cb(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_itnim_offline_cb(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -static void -bfa_itnim_sm_fwdelete_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_QRESUME: - bfa_sm_set_state(itnim, bfa_itnim_sm_fwdelete); - bfa_itnim_send_fwdelete(itnim); - break; - - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - bfa_reqq_wcancel(&itnim->reqq_wait); - bfa_itnim_offline_cb(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Offline state. - */ -static void -bfa_itnim_sm_offline(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_itnim_iotov_delete(itnim); - bfa_fcpim_delitn(itnim); - break; - - case BFA_ITNIM_SM_ONLINE: - if (bfa_itnim_send_fwcreate(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_iocdisable); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -static void -bfa_itnim_sm_iocdisable(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_itnim_iotov_delete(itnim); - bfa_fcpim_delitn(itnim); - break; - - case BFA_ITNIM_SM_OFFLINE: - bfa_itnim_offline_cb(itnim); - break; - - case BFA_ITNIM_SM_ONLINE: - if (bfa_itnim_send_fwcreate(itnim)) - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate); - else - bfa_sm_set_state(itnim, bfa_itnim_sm_fwcreate_qfull); - break; - - case BFA_ITNIM_SM_HWFAIL: - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Itnim is deleted, waiting for firmware response to delete. - */ -static void -bfa_itnim_sm_deleting(struct bfa_itnim_s *itnim, enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_FWRSP: - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_fcpim_delitn(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -static void -bfa_itnim_sm_deleting_qfull(struct bfa_itnim_s *itnim, - enum bfa_itnim_event event) -{ - bfa_trc(itnim->bfa, itnim->rport->rport_tag); - bfa_trc(itnim->bfa, event); - - switch (event) { - case BFA_ITNIM_SM_QRESUME: - bfa_sm_set_state(itnim, bfa_itnim_sm_deleting); - bfa_itnim_send_fwdelete(itnim); - break; - - case BFA_ITNIM_SM_HWFAIL: - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - bfa_reqq_wcancel(&itnim->reqq_wait); - bfa_fcpim_delitn(itnim); - break; - - default: - bfa_sm_fault(itnim->bfa, event); - } -} - -/* - * Initiate cleanup of all IOs on an IOC failure. - */ -static void -bfa_itnim_iocdisable_cleanup(struct bfa_itnim_s *itnim) -{ - struct bfa_tskim_s *tskim; - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &itnim->tsk_q) { - tskim = (struct bfa_tskim_s *) qe; - bfa_tskim_iocdisable(tskim); - } - - list_for_each_safe(qe, qen, &itnim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_ioim_iocdisable(ioim); - } - - /* - * For IO request in pending queue, we pretend an early timeout. - */ - list_for_each_safe(qe, qen, &itnim->pending_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_ioim_tov(ioim); - } - - list_for_each_safe(qe, qen, &itnim->io_cleanup_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_ioim_iocdisable(ioim); - } -} - -/* - * IO cleanup completion - */ -static void -bfa_itnim_cleanp_comp(void *itnim_cbarg) -{ - struct bfa_itnim_s *itnim = itnim_cbarg; - - bfa_stats(itnim, cleanup_comps); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_CLEANUP); -} - -/* - * Initiate cleanup of all IOs. - */ -static void -bfa_itnim_cleanup(struct bfa_itnim_s *itnim) -{ - struct bfa_ioim_s *ioim; - struct bfa_tskim_s *tskim; - struct list_head *qe, *qen; - - bfa_wc_init(&itnim->wc, bfa_itnim_cleanp_comp, itnim); - - list_for_each_safe(qe, qen, &itnim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - - /* - * Move IO to a cleanup queue from active queue so that a later - * TM will not pickup this IO. - */ - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &itnim->io_cleanup_q); - - bfa_wc_up(&itnim->wc); - bfa_ioim_cleanup(ioim); - } - - list_for_each_safe(qe, qen, &itnim->tsk_q) { - tskim = (struct bfa_tskim_s *) qe; - bfa_wc_up(&itnim->wc); - bfa_tskim_cleanup(tskim); - } - - bfa_wc_wait(&itnim->wc); -} - -static void -__bfa_cb_itnim_online(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_itnim_s *itnim = cbarg; - - if (complete) - bfa_cb_itnim_online(itnim->ditn); -} - -static void -__bfa_cb_itnim_offline(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_itnim_s *itnim = cbarg; - - if (complete) - bfa_cb_itnim_offline(itnim->ditn); -} - -static void -__bfa_cb_itnim_sler(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_itnim_s *itnim = cbarg; - - if (complete) - bfa_cb_itnim_sler(itnim->ditn); -} - -/* - * Call to resume any I/O requests waiting for room in request queue. - */ -static void -bfa_itnim_qresume(void *cbarg) -{ - struct bfa_itnim_s *itnim = cbarg; - - bfa_sm_send_event(itnim, BFA_ITNIM_SM_QRESUME); -} - -/* - * bfa_itnim_public - */ - -void -bfa_itnim_iodone(struct bfa_itnim_s *itnim) -{ - bfa_wc_down(&itnim->wc); -} - -void -bfa_itnim_tskdone(struct bfa_itnim_s *itnim) -{ - bfa_wc_down(&itnim->wc); -} - -void -bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len) -{ - /* - * ITN memory - */ - *km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itnim_s); -} - -void -bfa_itnim_attach(struct bfa_fcpim_s *fcpim) -{ - struct bfa_s *bfa = fcpim->bfa; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; - struct bfa_itnim_s *itnim; - int i, j; - - INIT_LIST_HEAD(&fcpim->itnim_q); - - itnim = (struct bfa_itnim_s *) bfa_mem_kva_curp(fcp); - fcpim->itnim_arr = itnim; - - for (i = 0; i < fcpim->num_itnims; i++, itnim++) { - memset(itnim, 0, sizeof(struct bfa_itnim_s)); - itnim->bfa = bfa; - itnim->fcpim = fcpim; - itnim->reqq = BFA_REQQ_QOS_LO; - itnim->rport = BFA_RPORT_FROM_TAG(bfa, i); - itnim->iotov_active = BFA_FALSE; - bfa_reqq_winit(&itnim->reqq_wait, bfa_itnim_qresume, itnim); - - INIT_LIST_HEAD(&itnim->io_q); - INIT_LIST_HEAD(&itnim->io_cleanup_q); - INIT_LIST_HEAD(&itnim->pending_q); - INIT_LIST_HEAD(&itnim->tsk_q); - INIT_LIST_HEAD(&itnim->delay_comp_q); - for (j = 0; j < BFA_IOBUCKET_MAX; j++) - itnim->ioprofile.io_latency.min[j] = ~0; - bfa_sm_set_state(itnim, bfa_itnim_sm_uninit); - } - - bfa_mem_kva_curp(fcp) = (u8 *) itnim; -} - -void -bfa_itnim_iocdisable(struct bfa_itnim_s *itnim) -{ - bfa_stats(itnim, ioc_disabled); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_HWFAIL); -} - -static bfa_boolean_t -bfa_itnim_send_fwcreate(struct bfa_itnim_s *itnim) -{ - struct bfi_itn_create_req_s *m; - - itnim->msg_no++; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(itnim->bfa, itnim->reqq); - if (!m) { - bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_ITN, BFI_ITN_H2I_CREATE_REQ, - bfa_fn_lpu(itnim->bfa)); - m->fw_handle = itnim->rport->fw_handle; - m->class = FC_CLASS_3; - m->seq_rec = itnim->seq_rec; - m->msg_no = itnim->msg_no; - bfa_stats(itnim, fw_create); - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(itnim->bfa, itnim->reqq, m->mh); - return BFA_TRUE; -} - -static bfa_boolean_t -bfa_itnim_send_fwdelete(struct bfa_itnim_s *itnim) -{ - struct bfi_itn_delete_req_s *m; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(itnim->bfa, itnim->reqq); - if (!m) { - bfa_reqq_wait(itnim->bfa, itnim->reqq, &itnim->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_ITN, BFI_ITN_H2I_DELETE_REQ, - bfa_fn_lpu(itnim->bfa)); - m->fw_handle = itnim->rport->fw_handle; - bfa_stats(itnim, fw_delete); - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(itnim->bfa, itnim->reqq, m->mh); - return BFA_TRUE; -} - -/* - * Cleanup all pending failed inflight requests. - */ -static void -bfa_itnim_delayed_comp(struct bfa_itnim_s *itnim, bfa_boolean_t iotov) -{ - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &itnim->delay_comp_q) { - ioim = (struct bfa_ioim_s *)qe; - bfa_ioim_delayed_comp(ioim, iotov); - } -} - -/* - * Start all pending IO requests. - */ -static void -bfa_itnim_iotov_online(struct bfa_itnim_s *itnim) -{ - struct bfa_ioim_s *ioim; - - bfa_itnim_iotov_stop(itnim); - - /* - * Abort all inflight IO requests in the queue - */ - bfa_itnim_delayed_comp(itnim, BFA_FALSE); - - /* - * Start all pending IO requests. - */ - while (!list_empty(&itnim->pending_q)) { - bfa_q_deq(&itnim->pending_q, &ioim); - list_add_tail(&ioim->qe, &itnim->io_q); - bfa_ioim_start(ioim); - } -} - -/* - * Fail all pending IO requests - */ -static void -bfa_itnim_iotov_cleanup(struct bfa_itnim_s *itnim) -{ - struct bfa_ioim_s *ioim; - - /* - * Fail all inflight IO requests in the queue - */ - bfa_itnim_delayed_comp(itnim, BFA_TRUE); - - /* - * Fail any pending IO requests. - */ - while (!list_empty(&itnim->pending_q)) { - bfa_q_deq(&itnim->pending_q, &ioim); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); - bfa_ioim_tov(ioim); - } -} - -/* - * IO TOV timer callback. Fail any pending IO requests. - */ -static void -bfa_itnim_iotov(void *itnim_arg) -{ - struct bfa_itnim_s *itnim = itnim_arg; - - itnim->iotov_active = BFA_FALSE; - - bfa_cb_itnim_tov_begin(itnim->ditn); - bfa_itnim_iotov_cleanup(itnim); - bfa_cb_itnim_tov(itnim->ditn); -} - -/* - * Start IO TOV timer for failing back pending IO requests in offline state. - */ -static void -bfa_itnim_iotov_start(struct bfa_itnim_s *itnim) -{ - if (itnim->fcpim->path_tov > 0) { - - itnim->iotov_active = BFA_TRUE; - WARN_ON(!bfa_itnim_hold_io(itnim)); - bfa_timer_start(itnim->bfa, &itnim->timer, - bfa_itnim_iotov, itnim, itnim->fcpim->path_tov); - } -} - -/* - * Stop IO TOV timer. - */ -static void -bfa_itnim_iotov_stop(struct bfa_itnim_s *itnim) -{ - if (itnim->iotov_active) { - itnim->iotov_active = BFA_FALSE; - bfa_timer_stop(&itnim->timer); - } -} - -/* - * Stop IO TOV timer. - */ -static void -bfa_itnim_iotov_delete(struct bfa_itnim_s *itnim) -{ - bfa_boolean_t pathtov_active = BFA_FALSE; - - if (itnim->iotov_active) - pathtov_active = BFA_TRUE; - - bfa_itnim_iotov_stop(itnim); - if (pathtov_active) - bfa_cb_itnim_tov_begin(itnim->ditn); - bfa_itnim_iotov_cleanup(itnim); - if (pathtov_active) - bfa_cb_itnim_tov(itnim->ditn); -} - -static void -bfa_itnim_update_del_itn_stats(struct bfa_itnim_s *itnim) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(itnim->bfa); - fcpim->del_itn_stats.del_itn_iocomp_aborted += - itnim->stats.iocomp_aborted; - fcpim->del_itn_stats.del_itn_iocomp_timedout += - itnim->stats.iocomp_timedout; - fcpim->del_itn_stats.del_itn_iocom_sqer_needed += - itnim->stats.iocom_sqer_needed; - fcpim->del_itn_stats.del_itn_iocom_res_free += - itnim->stats.iocom_res_free; - fcpim->del_itn_stats.del_itn_iocom_hostabrts += - itnim->stats.iocom_hostabrts; - fcpim->del_itn_stats.del_itn_total_ios += itnim->stats.total_ios; - fcpim->del_itn_stats.del_io_iocdowns += itnim->stats.io_iocdowns; - fcpim->del_itn_stats.del_tm_iocdowns += itnim->stats.tm_iocdowns; -} - -/* - * bfa_itnim_public - */ - -/* - * Itnim interrupt processing. - */ -void -bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - union bfi_itn_i2h_msg_u msg; - struct bfa_itnim_s *itnim; - - bfa_trc(bfa, m->mhdr.msg_id); - - msg.msg = m; - - switch (m->mhdr.msg_id) { - case BFI_ITN_I2H_CREATE_RSP: - itnim = BFA_ITNIM_FROM_TAG(fcpim, - msg.create_rsp->bfa_handle); - WARN_ON(msg.create_rsp->status != BFA_STATUS_OK); - bfa_stats(itnim, create_comps); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); - break; - - case BFI_ITN_I2H_DELETE_RSP: - itnim = BFA_ITNIM_FROM_TAG(fcpim, - msg.delete_rsp->bfa_handle); - WARN_ON(msg.delete_rsp->status != BFA_STATUS_OK); - bfa_stats(itnim, delete_comps); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_FWRSP); - break; - - case BFI_ITN_I2H_SLER_EVENT: - itnim = BFA_ITNIM_FROM_TAG(fcpim, - msg.sler_event->bfa_handle); - bfa_stats(itnim, sler_events); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_SLER); - break; - - default: - bfa_trc(bfa, m->mhdr.msg_id); - WARN_ON(1); - } -} - -/* - * bfa_itnim_api - */ - -struct bfa_itnim_s * -bfa_itnim_create(struct bfa_s *bfa, struct bfa_rport_s *rport, void *ditn) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct bfa_itnim_s *itnim; - - bfa_itn_create(bfa, rport, bfa_itnim_isr); - - itnim = BFA_ITNIM_FROM_TAG(fcpim, rport->rport_tag); - WARN_ON(itnim->rport != rport); - - itnim->ditn = ditn; - - bfa_stats(itnim, creates); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_CREATE); - - return itnim; -} - -void -bfa_itnim_delete(struct bfa_itnim_s *itnim) -{ - bfa_stats(itnim, deletes); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_DELETE); -} - -void -bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec) -{ - itnim->seq_rec = seq_rec; - bfa_stats(itnim, onlines); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_ONLINE); -} - -void -bfa_itnim_offline(struct bfa_itnim_s *itnim) -{ - bfa_stats(itnim, offlines); - bfa_sm_send_event(itnim, BFA_ITNIM_SM_OFFLINE); -} - -/* - * Return true if itnim is considered offline for holding off IO request. - * IO is not held if itnim is being deleted. - */ -bfa_boolean_t -bfa_itnim_hold_io(struct bfa_itnim_s *itnim) -{ - return itnim->fcpim->path_tov && itnim->iotov_active && - (bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwcreate) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_sler) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_cleanup_offline) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_fwdelete) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_offline) || - bfa_sm_cmp_state(itnim, bfa_itnim_sm_iocdisable)); -} - -#define bfa_io_lat_clock_res_div HZ -#define bfa_io_lat_clock_res_mul 1000 -bfa_status_t -bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim, - struct bfa_itnim_ioprofile_s *ioprofile) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(itnim->bfa); - if (!fcpim->io_profile) - return BFA_STATUS_IOPROFILE_OFF; - - itnim->ioprofile.index = BFA_IOBUCKET_MAX; - itnim->ioprofile.io_profile_start_time = - bfa_io_profile_start_time(itnim->bfa); - itnim->ioprofile.clock_res_mul = bfa_io_lat_clock_res_mul; - itnim->ioprofile.clock_res_div = bfa_io_lat_clock_res_div; - *ioprofile = itnim->ioprofile; - - return BFA_STATUS_OK; -} - -void -bfa_itnim_clear_stats(struct bfa_itnim_s *itnim) -{ - int j; - memset(&itnim->stats, 0, sizeof(itnim->stats)); - memset(&itnim->ioprofile, 0, sizeof(itnim->ioprofile)); - for (j = 0; j < BFA_IOBUCKET_MAX; j++) - itnim->ioprofile.io_latency.min[j] = ~0; -} - -/* - * BFA IO module state machine functions - */ - -/* - * IO is not started (unallocated). - */ -static void -bfa_ioim_sm_uninit(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - switch (event) { - case BFA_IOIM_SM_START: - if (!bfa_itnim_is_online(ioim->itnim)) { - if (!bfa_itnim_hold_io(ioim->itnim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - list_del(&ioim->qe); - list_add_tail(&ioim->qe, - &ioim->fcpim->ioim_comp_q); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_pathtov, ioim); - } else { - list_del(&ioim->qe); - list_add_tail(&ioim->qe, - &ioim->itnim->pending_q); - } - break; - } - - if (ioim->nsges > BFI_SGE_INLINE) { - if (!bfa_ioim_sgpg_alloc(ioim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_sgalloc); - return; - } - } - - if (!bfa_ioim_send_ioreq(ioim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); - break; - } - - bfa_sm_set_state(ioim, bfa_ioim_sm_active); - break; - - case BFA_IOIM_SM_IOTOV: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_pathtov, ioim); - break; - - case BFA_IOIM_SM_ABORT: - /* - * IO in pending queue can get abort requests. Complete abort - * requests immediately. - */ - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - WARN_ON(!bfa_q_is_on_q(&ioim->itnim->pending_q, ioim)); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_abort, ioim); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO is waiting for SG pages. - */ -static void -bfa_ioim_sm_sgalloc(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_SGALLOCED: - if (!bfa_ioim_send_ioreq(ioim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); - break; - } - bfa_sm_set_state(ioim, bfa_ioim_sm_active); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_ABORT: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_sgpg_wcancel(ioim->bfa, &ioim->iosp->sgpg_wqe); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO is active. - */ -static void -bfa_ioim_sm_active(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - switch (event) { - case BFA_IOIM_SM_COMP_GOOD: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_good_comp, ioim); - break; - - case BFA_IOIM_SM_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp, - ioim); - break; - - case BFA_IOIM_SM_DONE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_comp, - ioim); - break; - - case BFA_IOIM_SM_ABORT: - ioim->iosp->abort_explicit = BFA_TRUE; - ioim->io_cbfn = __bfa_cb_ioim_abort; - - if (bfa_ioim_send_abort(ioim)) - bfa_sm_set_state(ioim, bfa_ioim_sm_abort); - else { - bfa_sm_set_state(ioim, bfa_ioim_sm_abort_qfull); - bfa_stats(ioim->itnim, qwait); - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - } - break; - - case BFA_IOIM_SM_CLEANUP: - ioim->iosp->abort_explicit = BFA_FALSE; - ioim->io_cbfn = __bfa_cb_ioim_failed; - - if (bfa_ioim_send_abort(ioim)) - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); - else { - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - bfa_stats(ioim->itnim, qwait); - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - } - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - break; - - case BFA_IOIM_SM_SQRETRY: - if (bfa_ioim_maxretry_reached(ioim)) { - /* max retry reached, free IO */ - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_failed, ioim); - break; - } - /* waiting for IO tag resource free */ - bfa_sm_set_state(ioim, bfa_ioim_sm_cmnd_retry); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO is retried with new tag. - */ -static void -bfa_ioim_sm_cmnd_retry(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - switch (event) { - case BFA_IOIM_SM_FREE: - /* abts and rrq done. Now retry the IO with new tag */ - bfa_ioim_update_iotag(ioim); - if (!bfa_ioim_send_ioreq(ioim)) { - bfa_sm_set_state(ioim, bfa_ioim_sm_qfull); - break; - } - bfa_sm_set_state(ioim, bfa_ioim_sm_active); - break; - - case BFA_IOIM_SM_CLEANUP: - ioim->iosp->abort_explicit = BFA_FALSE; - ioim->io_cbfn = __bfa_cb_ioim_failed; - - if (bfa_ioim_send_abort(ioim)) - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); - else { - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - bfa_stats(ioim->itnim, qwait); - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - } - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, - __bfa_cb_ioim_failed, ioim); - break; - - case BFA_IOIM_SM_ABORT: - /* in this state IO abort is done. - * Waiting for IO tag resource free. - */ - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO is being aborted, waiting for completion from firmware. - */ -static void -bfa_ioim_sm_abort(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_COMP_GOOD: - case BFA_IOIM_SM_COMP: - case BFA_IOIM_SM_DONE: - case BFA_IOIM_SM_FREE: - break; - - case BFA_IOIM_SM_ABORT_DONE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - case BFA_IOIM_SM_ABORT_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - case BFA_IOIM_SM_COMP_UTAG: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - case BFA_IOIM_SM_CLEANUP: - WARN_ON(ioim->iosp->abort_explicit != BFA_TRUE); - ioim->iosp->abort_explicit = BFA_FALSE; - - if (bfa_ioim_send_abort(ioim)) - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); - else { - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - bfa_stats(ioim->itnim, qwait); - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - } - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO is being cleaned up (implicit abort), waiting for completion from - * firmware. - */ -static void -bfa_ioim_sm_cleanup(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_COMP_GOOD: - case BFA_IOIM_SM_COMP: - case BFA_IOIM_SM_DONE: - case BFA_IOIM_SM_FREE: - break; - - case BFA_IOIM_SM_ABORT: - /* - * IO is already being aborted implicitly - */ - ioim->io_cbfn = __bfa_cb_ioim_abort; - break; - - case BFA_IOIM_SM_ABORT_DONE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_ABORT_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_COMP_UTAG: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - break; - - case BFA_IOIM_SM_CLEANUP: - /* - * IO can be in cleanup state already due to TM command. - * 2nd cleanup request comes from ITN offline event. - */ - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO is waiting for room in request CQ - */ -static void -bfa_ioim_sm_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_QRESUME: - bfa_sm_set_state(ioim, bfa_ioim_sm_active); - bfa_ioim_send_ioreq(ioim); - break; - - case BFA_IOIM_SM_ABORT: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * Active IO is being aborted, waiting for room in request CQ. - */ -static void -bfa_ioim_sm_abort_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_QRESUME: - bfa_sm_set_state(ioim, bfa_ioim_sm_abort); - bfa_ioim_send_abort(ioim); - break; - - case BFA_IOIM_SM_CLEANUP: - WARN_ON(ioim->iosp->abort_explicit != BFA_TRUE); - ioim->iosp->abort_explicit = BFA_FALSE; - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup_qfull); - break; - - case BFA_IOIM_SM_COMP_GOOD: - case BFA_IOIM_SM_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - case BFA_IOIM_SM_DONE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_abort, - ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * Active IO is being cleaned up, waiting for room in request CQ. - */ -static void -bfa_ioim_sm_cleanup_qfull(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_QRESUME: - bfa_sm_set_state(ioim, bfa_ioim_sm_cleanup); - bfa_ioim_send_abort(ioim); - break; - - case BFA_IOIM_SM_ABORT: - /* - * IO is already being cleaned up implicitly - */ - ioim->io_cbfn = __bfa_cb_ioim_abort; - break; - - case BFA_IOIM_SM_COMP_GOOD: - case BFA_IOIM_SM_COMP: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_DONE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb_free); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - bfa_reqq_wcancel(&ioim->iosp->reqq_wait); - bfa_ioim_move_to_comp_q(ioim); - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, __bfa_cb_ioim_failed, - ioim); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO bfa callback is pending. - */ -static void -bfa_ioim_sm_hcb(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - switch (event) { - case BFA_IOIM_SM_HCB: - bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); - bfa_ioim_free(ioim); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO bfa callback is pending. IO resource cannot be freed. - */ -static void -bfa_ioim_sm_hcb_free(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_HCB: - bfa_sm_set_state(ioim, bfa_ioim_sm_resfree); - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_resfree_q); - break; - - case BFA_IOIM_SM_FREE: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - bfa_sm_set_state(ioim, bfa_ioim_sm_hcb); - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * IO is completed, waiting resource free from firmware. - */ -static void -bfa_ioim_sm_resfree(struct bfa_ioim_s *ioim, enum bfa_ioim_event event) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, event); - - switch (event) { - case BFA_IOIM_SM_FREE: - bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); - bfa_ioim_free(ioim); - break; - - case BFA_IOIM_SM_CLEANUP: - bfa_ioim_notify_cleanup(ioim); - break; - - case BFA_IOIM_SM_HWFAIL: - break; - - default: - bfa_sm_fault(ioim->bfa, event); - } -} - -/* - * This is called from bfa_fcpim_start after the bfa_init() with flash read - * is complete by driver. now invalidate the stale content of lun mask - * like unit attention, rp tag and lp tag. - */ -static void -bfa_ioim_lm_init(struct bfa_s *bfa) -{ - struct bfa_lun_mask_s *lunm_list; - int i; - - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG) - return; - - lunm_list = bfa_get_lun_mask_list(bfa); - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - lunm_list[i].ua = BFA_IOIM_LM_UA_RESET; - lunm_list[i].lp_tag = BFA_LP_TAG_INVALID; - lunm_list[i].rp_tag = BFA_RPORT_TAG_INVALID; - } -} - -static void -__bfa_cb_ioim_good_comp(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - bfa_cb_ioim_good_comp(ioim->bfa->bfad, ioim->dio); -} - -static void -__bfa_cb_ioim_comp(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - struct bfi_ioim_rsp_s *m; - u8 *snsinfo = NULL; - u8 sns_len = 0; - s32 residue = 0; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - m = (struct bfi_ioim_rsp_s *) &ioim->iosp->comp_rspmsg; - if (m->io_status == BFI_IOIM_STS_OK) { - /* - * setup sense information, if present - */ - if ((m->scsi_status == SCSI_STATUS_CHECK_CONDITION) && - m->sns_len) { - sns_len = m->sns_len; - snsinfo = BFA_SNSINFO_FROM_TAG(ioim->fcpim->fcp, - ioim->iotag); - } - - /* - * setup residue value correctly for normal completions - */ - if (m->resid_flags == FCP_RESID_UNDER) { - residue = be32_to_cpu(m->residue); - bfa_stats(ioim->itnim, iocomp_underrun); - } - if (m->resid_flags == FCP_RESID_OVER) { - residue = be32_to_cpu(m->residue); - residue = -residue; - bfa_stats(ioim->itnim, iocomp_overrun); - } - } - - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, m->io_status, - m->scsi_status, sns_len, snsinfo, residue); -} - -void -bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn, wwn_t rp_wwn, - u16 rp_tag, u8 lp_tag) -{ - struct bfa_lun_mask_s *lun_list; - u8 i; - - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG) - return; - - lun_list = bfa_get_lun_mask_list(bfa); - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lun_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE) { - if ((lun_list[i].lp_wwn == lp_wwn) && - (lun_list[i].rp_wwn == rp_wwn)) { - lun_list[i].rp_tag = rp_tag; - lun_list[i].lp_tag = lp_tag; - } - } - } -} - -/* - * set UA for all active luns in LM DB - */ -static void -bfa_ioim_lm_set_ua(struct bfa_s *bfa) -{ - struct bfa_lun_mask_s *lunm_list; - int i; - - lunm_list = bfa_get_lun_mask_list(bfa); - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lunm_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE) - continue; - lunm_list[i].ua = BFA_IOIM_LM_UA_SET; - } -} - -bfa_status_t -bfa_fcpim_lunmask_update(struct bfa_s *bfa, u32 update) -{ - struct bfa_lunmask_cfg_s *lun_mask; - - bfa_trc(bfa, bfa_get_lun_mask_status(bfa)); - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG) - return BFA_STATUS_FAILED; - - if (bfa_get_lun_mask_status(bfa) == update) - return BFA_STATUS_NO_CHANGE; - - lun_mask = bfa_get_lun_mask(bfa); - lun_mask->status = update; - - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_ENABLED) - bfa_ioim_lm_set_ua(bfa); - - return bfa_dconf_update(bfa); -} - -bfa_status_t -bfa_fcpim_lunmask_clear(struct bfa_s *bfa) -{ - int i; - struct bfa_lun_mask_s *lunm_list; - - bfa_trc(bfa, bfa_get_lun_mask_status(bfa)); - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG) - return BFA_STATUS_FAILED; - - lunm_list = bfa_get_lun_mask_list(bfa); - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lunm_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE) { - if (lunm_list[i].rp_tag != BFA_RPORT_TAG_INVALID) - bfa_rport_unset_lunmask(bfa, - BFA_RPORT_FROM_TAG(bfa, lunm_list[i].rp_tag)); - } - } - - memset(lunm_list, 0, sizeof(struct bfa_lun_mask_s) * MAX_LUN_MASK_CFG); - return bfa_dconf_update(bfa); -} - -bfa_status_t -bfa_fcpim_lunmask_query(struct bfa_s *bfa, void *buf) -{ - struct bfa_lunmask_cfg_s *lun_mask; - - bfa_trc(bfa, bfa_get_lun_mask_status(bfa)); - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG) - return BFA_STATUS_FAILED; - - lun_mask = bfa_get_lun_mask(bfa); - memcpy(buf, lun_mask, sizeof(struct bfa_lunmask_cfg_s)); - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn, - wwn_t rpwwn, struct scsi_lun lun) -{ - struct bfa_lun_mask_s *lunm_list; - struct bfa_rport_s *rp = NULL; - int i, free_index = MAX_LUN_MASK_CFG + 1; - struct bfa_fcs_lport_s *port = NULL; - struct bfa_fcs_rport_s *rp_fcs; - - bfa_trc(bfa, bfa_get_lun_mask_status(bfa)); - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG) - return BFA_STATUS_FAILED; - - port = bfa_fcs_lookup_port(&((struct bfad_s *)bfa->bfad)->bfa_fcs, - vf_id, *pwwn); - if (port) { - *pwwn = port->port_cfg.pwwn; - rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn); - if (rp_fcs) - rp = rp_fcs->bfa_rport; - } - - lunm_list = bfa_get_lun_mask_list(bfa); - /* if entry exists */ - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lunm_list[i].state != BFA_IOIM_LUN_MASK_ACTIVE) - free_index = i; - if ((lunm_list[i].lp_wwn == *pwwn) && - (lunm_list[i].rp_wwn == rpwwn) && - (scsilun_to_int((struct scsi_lun *)&lunm_list[i].lun) == - scsilun_to_int((struct scsi_lun *)&lun))) - return BFA_STATUS_ENTRY_EXISTS; - } - - if (free_index > MAX_LUN_MASK_CFG) - return BFA_STATUS_MAX_ENTRY_REACHED; - - if (rp) { - lunm_list[free_index].lp_tag = bfa_lps_get_tag_from_pid(bfa, - rp->rport_info.local_pid); - lunm_list[free_index].rp_tag = rp->rport_tag; - } else { - lunm_list[free_index].lp_tag = BFA_LP_TAG_INVALID; - lunm_list[free_index].rp_tag = BFA_RPORT_TAG_INVALID; - } - - lunm_list[free_index].lp_wwn = *pwwn; - lunm_list[free_index].rp_wwn = rpwwn; - lunm_list[free_index].lun = lun; - lunm_list[free_index].state = BFA_IOIM_LUN_MASK_ACTIVE; - - /* set for all luns in this rp */ - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if ((lunm_list[i].lp_wwn == *pwwn) && - (lunm_list[i].rp_wwn == rpwwn)) - lunm_list[i].ua = BFA_IOIM_LM_UA_SET; - } - - return bfa_dconf_update(bfa); -} - -bfa_status_t -bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id, wwn_t *pwwn, - wwn_t rpwwn, struct scsi_lun lun) -{ - struct bfa_lun_mask_s *lunm_list; - struct bfa_rport_s *rp = NULL; - struct bfa_fcs_lport_s *port = NULL; - struct bfa_fcs_rport_s *rp_fcs; - int i; - - /* in min cfg lunm_list could be NULL but no commands should run. */ - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_MINCFG) - return BFA_STATUS_FAILED; - - bfa_trc(bfa, bfa_get_lun_mask_status(bfa)); - bfa_trc(bfa, *pwwn); - bfa_trc(bfa, rpwwn); - bfa_trc(bfa, scsilun_to_int((struct scsi_lun *)&lun)); - - if (*pwwn == 0) { - port = bfa_fcs_lookup_port( - &((struct bfad_s *)bfa->bfad)->bfa_fcs, - vf_id, *pwwn); - if (port) { - *pwwn = port->port_cfg.pwwn; - rp_fcs = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn); - if (rp_fcs) - rp = rp_fcs->bfa_rport; - } - } - - lunm_list = bfa_get_lun_mask_list(bfa); - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if ((lunm_list[i].lp_wwn == *pwwn) && - (lunm_list[i].rp_wwn == rpwwn) && - (scsilun_to_int((struct scsi_lun *)&lunm_list[i].lun) == - scsilun_to_int((struct scsi_lun *)&lun))) { - lunm_list[i].lp_wwn = 0; - lunm_list[i].rp_wwn = 0; - int_to_scsilun(0, &lunm_list[i].lun); - lunm_list[i].state = BFA_IOIM_LUN_MASK_INACTIVE; - if (lunm_list[i].rp_tag != BFA_RPORT_TAG_INVALID) { - lunm_list[i].rp_tag = BFA_RPORT_TAG_INVALID; - lunm_list[i].lp_tag = BFA_LP_TAG_INVALID; - } - return bfa_dconf_update(bfa); - } - } - - /* set for all luns in this rp */ - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if ((lunm_list[i].lp_wwn == *pwwn) && - (lunm_list[i].rp_wwn == rpwwn)) - lunm_list[i].ua = BFA_IOIM_LM_UA_SET; - } - - return BFA_STATUS_ENTRY_NOT_EXISTS; -} - -static void -__bfa_cb_ioim_failed(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_ABORTED, - 0, 0, NULL, 0); -} - -static void -__bfa_cb_ioim_pathtov(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - - bfa_stats(ioim->itnim, path_tov_expired); - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - bfa_cb_ioim_done(ioim->bfa->bfad, ioim->dio, BFI_IOIM_STS_PATHTOV, - 0, 0, NULL, 0); -} - -static void -__bfa_cb_ioim_abort(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_ioim_s *ioim = cbarg; - - if (!complete) { - bfa_sm_send_event(ioim, BFA_IOIM_SM_HCB); - return; - } - - bfa_cb_ioim_abort(ioim->bfa->bfad, ioim->dio); -} - -static void -bfa_ioim_sgpg_alloced(void *cbarg) -{ - struct bfa_ioim_s *ioim = cbarg; - - ioim->nsgpgs = BFA_SGPG_NPAGE(ioim->nsges); - list_splice_tail_init(&ioim->iosp->sgpg_wqe.sgpg_q, &ioim->sgpg_q); - ioim->sgpg = bfa_q_first(&ioim->sgpg_q); - bfa_sm_send_event(ioim, BFA_IOIM_SM_SGALLOCED); -} - -/* - * Send I/O request to firmware. - */ -static bfa_boolean_t -bfa_ioim_send_ioreq(struct bfa_ioim_s *ioim) -{ - struct bfa_itnim_s *itnim = ioim->itnim; - struct bfi_ioim_req_s *m; - static struct fcp_cmnd_s cmnd_z0 = { { { 0 } } }; - struct bfi_sge_s *sge, *sgpge; - u32 pgdlen = 0; - u32 fcp_dl; - u64 addr; - struct scatterlist *sg; - struct bfa_sgpg_s *sgpg; - struct scsi_cmnd *cmnd = (struct scsi_cmnd *) ioim->dio; - u32 i, sge_id, pgcumsz; - enum dma_data_direction dmadir; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(ioim->bfa, ioim->reqq); - if (!m) { - bfa_stats(ioim->itnim, qwait); - bfa_reqq_wait(ioim->bfa, ioim->reqq, - &ioim->iosp->reqq_wait); - return BFA_FALSE; - } - - /* - * build i/o request message next - */ - m->io_tag = cpu_to_be16(ioim->iotag); - m->rport_hdl = ioim->itnim->rport->fw_handle; - m->io_timeout = 0; - - sge = &m->sges[0]; - sgpg = ioim->sgpg; - sge_id = 0; - sgpge = NULL; - pgcumsz = 0; - scsi_for_each_sg(cmnd, sg, ioim->nsges, i) { - if (i == 0) { - /* build inline IO SG element */ - addr = bfa_sgaddr_le(sg_dma_address(sg)); - sge->sga = *(union bfi_addr_u *) &addr; - pgdlen = sg_dma_len(sg); - sge->sg_len = pgdlen; - sge->flags = (ioim->nsges > BFI_SGE_INLINE) ? - BFI_SGE_DATA_CPL : BFI_SGE_DATA_LAST; - bfa_sge_to_be(sge); - sge++; - } else { - if (sge_id == 0) - sgpge = sgpg->sgpg->sges; - - addr = bfa_sgaddr_le(sg_dma_address(sg)); - sgpge->sga = *(union bfi_addr_u *) &addr; - sgpge->sg_len = sg_dma_len(sg); - pgcumsz += sgpge->sg_len; - - /* set flags */ - if (i < (ioim->nsges - 1) && - sge_id < (BFI_SGPG_DATA_SGES - 1)) - sgpge->flags = BFI_SGE_DATA; - else if (i < (ioim->nsges - 1)) - sgpge->flags = BFI_SGE_DATA_CPL; - else - sgpge->flags = BFI_SGE_DATA_LAST; - - bfa_sge_to_le(sgpge); - - sgpge++; - if (i == (ioim->nsges - 1)) { - sgpge->flags = BFI_SGE_PGDLEN; - sgpge->sga.a32.addr_lo = 0; - sgpge->sga.a32.addr_hi = 0; - sgpge->sg_len = pgcumsz; - bfa_sge_to_le(sgpge); - } else if (++sge_id == BFI_SGPG_DATA_SGES) { - sgpg = (struct bfa_sgpg_s *) bfa_q_next(sgpg); - sgpge->flags = BFI_SGE_LINK; - sgpge->sga = sgpg->sgpg_pa; - sgpge->sg_len = pgcumsz; - bfa_sge_to_le(sgpge); - sge_id = 0; - pgcumsz = 0; - } - } - } - - if (ioim->nsges > BFI_SGE_INLINE) { - sge->sga = ioim->sgpg->sgpg_pa; - } else { - sge->sga.a32.addr_lo = 0; - sge->sga.a32.addr_hi = 0; - } - sge->sg_len = pgdlen; - sge->flags = BFI_SGE_PGDLEN; - bfa_sge_to_be(sge); - - /* - * set up I/O command parameters - */ - m->cmnd = cmnd_z0; - int_to_scsilun(cmnd->device->lun, &m->cmnd.lun); - dmadir = cmnd->sc_data_direction; - if (dmadir == DMA_TO_DEVICE) - m->cmnd.iodir = FCP_IODIR_WRITE; - else if (dmadir == DMA_FROM_DEVICE) - m->cmnd.iodir = FCP_IODIR_READ; - else - m->cmnd.iodir = FCP_IODIR_NONE; - - m->cmnd.cdb = *(struct scsi_cdb_s *) cmnd->cmnd; - fcp_dl = scsi_bufflen(cmnd); - m->cmnd.fcp_dl = cpu_to_be32(fcp_dl); - - /* - * set up I/O message header - */ - switch (m->cmnd.iodir) { - case FCP_IODIR_READ: - bfi_h2i_set(m->mh, BFI_MC_IOIM_READ, 0, bfa_fn_lpu(ioim->bfa)); - bfa_stats(itnim, input_reqs); - ioim->itnim->stats.rd_throughput += fcp_dl; - break; - case FCP_IODIR_WRITE: - bfi_h2i_set(m->mh, BFI_MC_IOIM_WRITE, 0, bfa_fn_lpu(ioim->bfa)); - bfa_stats(itnim, output_reqs); - ioim->itnim->stats.wr_throughput += fcp_dl; - break; - case FCP_IODIR_RW: - bfa_stats(itnim, input_reqs); - bfa_stats(itnim, output_reqs); - default: - bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa)); - } - if (itnim->seq_rec || - (scsi_bufflen(cmnd) & (sizeof(u32) - 1))) - bfi_h2i_set(m->mh, BFI_MC_IOIM_IO, 0, bfa_fn_lpu(ioim->bfa)); - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(ioim->bfa, ioim->reqq, m->mh); - return BFA_TRUE; -} - -/* - * Setup any additional SG pages needed.Inline SG element is setup - * at queuing time. - */ -static bfa_boolean_t -bfa_ioim_sgpg_alloc(struct bfa_ioim_s *ioim) -{ - u16 nsgpgs; - - WARN_ON(ioim->nsges <= BFI_SGE_INLINE); - - /* - * allocate SG pages needed - */ - nsgpgs = BFA_SGPG_NPAGE(ioim->nsges); - if (!nsgpgs) - return BFA_TRUE; - - if (bfa_sgpg_malloc(ioim->bfa, &ioim->sgpg_q, nsgpgs) - != BFA_STATUS_OK) { - bfa_sgpg_wait(ioim->bfa, &ioim->iosp->sgpg_wqe, nsgpgs); - return BFA_FALSE; - } - - ioim->nsgpgs = nsgpgs; - ioim->sgpg = bfa_q_first(&ioim->sgpg_q); - - return BFA_TRUE; -} - -/* - * Send I/O abort request to firmware. - */ -static bfa_boolean_t -bfa_ioim_send_abort(struct bfa_ioim_s *ioim) -{ - struct bfi_ioim_abort_req_s *m; - enum bfi_ioim_h2i msgop; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(ioim->bfa, ioim->reqq); - if (!m) - return BFA_FALSE; - - /* - * build i/o request message next - */ - if (ioim->iosp->abort_explicit) - msgop = BFI_IOIM_H2I_IOABORT_REQ; - else - msgop = BFI_IOIM_H2I_IOCLEANUP_REQ; - - bfi_h2i_set(m->mh, BFI_MC_IOIM, msgop, bfa_fn_lpu(ioim->bfa)); - m->io_tag = cpu_to_be16(ioim->iotag); - m->abort_tag = ++ioim->abort_tag; - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(ioim->bfa, ioim->reqq, m->mh); - return BFA_TRUE; -} - -/* - * Call to resume any I/O requests waiting for room in request queue. - */ -static void -bfa_ioim_qresume(void *cbarg) -{ - struct bfa_ioim_s *ioim = cbarg; - - bfa_stats(ioim->itnim, qresumes); - bfa_sm_send_event(ioim, BFA_IOIM_SM_QRESUME); -} - - -static void -bfa_ioim_notify_cleanup(struct bfa_ioim_s *ioim) -{ - /* - * Move IO from itnim queue to fcpim global queue since itnim will be - * freed. - */ - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); - - if (!ioim->iosp->tskim) { - if (ioim->fcpim->delay_comp && ioim->itnim->iotov_active) { - bfa_cb_dequeue(&ioim->hcb_qe); - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->itnim->delay_comp_q); - } - bfa_itnim_iodone(ioim->itnim); - } else - bfa_wc_down(&ioim->iosp->tskim->wc); -} - -static bfa_boolean_t -bfa_ioim_is_abortable(struct bfa_ioim_s *ioim) -{ - if ((bfa_sm_cmp_state(ioim, bfa_ioim_sm_uninit) && - (!bfa_q_is_on_q(&ioim->itnim->pending_q, ioim))) || - (bfa_sm_cmp_state(ioim, bfa_ioim_sm_abort)) || - (bfa_sm_cmp_state(ioim, bfa_ioim_sm_abort_qfull)) || - (bfa_sm_cmp_state(ioim, bfa_ioim_sm_hcb)) || - (bfa_sm_cmp_state(ioim, bfa_ioim_sm_hcb_free)) || - (bfa_sm_cmp_state(ioim, bfa_ioim_sm_resfree))) - return BFA_FALSE; - - return BFA_TRUE; -} - -void -bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, bfa_boolean_t iotov) -{ - /* - * If path tov timer expired, failback with PATHTOV status - these - * IO requests are not normally retried by IO stack. - * - * Otherwise device cameback online and fail it with normal failed - * status so that IO stack retries these failed IO requests. - */ - if (iotov) - ioim->io_cbfn = __bfa_cb_ioim_pathtov; - else { - ioim->io_cbfn = __bfa_cb_ioim_failed; - bfa_stats(ioim->itnim, iocom_nexus_abort); - } - bfa_cb_queue(ioim->bfa, &ioim->hcb_qe, ioim->io_cbfn, ioim); - - /* - * Move IO to fcpim global queue since itnim will be - * freed. - */ - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); -} - - -/* - * Memory allocation and initialization. - */ -void -bfa_ioim_attach(struct bfa_fcpim_s *fcpim) -{ - struct bfa_ioim_s *ioim; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; - struct bfa_ioim_sp_s *iosp; - u16 i; - - /* - * claim memory first - */ - ioim = (struct bfa_ioim_s *) bfa_mem_kva_curp(fcp); - fcpim->ioim_arr = ioim; - bfa_mem_kva_curp(fcp) = (u8 *) (ioim + fcpim->fcp->num_ioim_reqs); - - iosp = (struct bfa_ioim_sp_s *) bfa_mem_kva_curp(fcp); - fcpim->ioim_sp_arr = iosp; - bfa_mem_kva_curp(fcp) = (u8 *) (iosp + fcpim->fcp->num_ioim_reqs); - - /* - * Initialize ioim free queues - */ - INIT_LIST_HEAD(&fcpim->ioim_resfree_q); - INIT_LIST_HEAD(&fcpim->ioim_comp_q); - - for (i = 0; i < fcpim->fcp->num_ioim_reqs; - i++, ioim++, iosp++) { - /* - * initialize IOIM - */ - memset(ioim, 0, sizeof(struct bfa_ioim_s)); - ioim->iotag = i; - ioim->bfa = fcpim->bfa; - ioim->fcpim = fcpim; - ioim->iosp = iosp; - INIT_LIST_HEAD(&ioim->sgpg_q); - bfa_reqq_winit(&ioim->iosp->reqq_wait, - bfa_ioim_qresume, ioim); - bfa_sgpg_winit(&ioim->iosp->sgpg_wqe, - bfa_ioim_sgpg_alloced, ioim); - bfa_sm_set_state(ioim, bfa_ioim_sm_uninit); - } -} - -void -bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; - struct bfa_ioim_s *ioim; - u16 iotag; - enum bfa_ioim_event evt = BFA_IOIM_SM_COMP; - - iotag = be16_to_cpu(rsp->io_tag); - - ioim = BFA_IOIM_FROM_TAG(fcpim, iotag); - WARN_ON(ioim->iotag != iotag); - - bfa_trc(ioim->bfa, ioim->iotag); - bfa_trc(ioim->bfa, rsp->io_status); - bfa_trc(ioim->bfa, rsp->reuse_io_tag); - - if (bfa_sm_cmp_state(ioim, bfa_ioim_sm_active)) - ioim->iosp->comp_rspmsg = *m; - - switch (rsp->io_status) { - case BFI_IOIM_STS_OK: - bfa_stats(ioim->itnim, iocomp_ok); - if (rsp->reuse_io_tag == 0) - evt = BFA_IOIM_SM_DONE; - else - evt = BFA_IOIM_SM_COMP; - break; - - case BFI_IOIM_STS_TIMEDOUT: - bfa_stats(ioim->itnim, iocomp_timedout); - case BFI_IOIM_STS_ABORTED: - rsp->io_status = BFI_IOIM_STS_ABORTED; - bfa_stats(ioim->itnim, iocomp_aborted); - if (rsp->reuse_io_tag == 0) - evt = BFA_IOIM_SM_DONE; - else - evt = BFA_IOIM_SM_COMP; - break; - - case BFI_IOIM_STS_PROTO_ERR: - bfa_stats(ioim->itnim, iocom_proto_err); - WARN_ON(!rsp->reuse_io_tag); - evt = BFA_IOIM_SM_COMP; - break; - - case BFI_IOIM_STS_SQER_NEEDED: - bfa_stats(ioim->itnim, iocom_sqer_needed); - WARN_ON(rsp->reuse_io_tag != 0); - evt = BFA_IOIM_SM_SQRETRY; - break; - - case BFI_IOIM_STS_RES_FREE: - bfa_stats(ioim->itnim, iocom_res_free); - evt = BFA_IOIM_SM_FREE; - break; - - case BFI_IOIM_STS_HOST_ABORTED: - bfa_stats(ioim->itnim, iocom_hostabrts); - if (rsp->abort_tag != ioim->abort_tag) { - bfa_trc(ioim->bfa, rsp->abort_tag); - bfa_trc(ioim->bfa, ioim->abort_tag); - return; - } - - if (rsp->reuse_io_tag) - evt = BFA_IOIM_SM_ABORT_COMP; - else - evt = BFA_IOIM_SM_ABORT_DONE; - break; - - case BFI_IOIM_STS_UTAG: - bfa_stats(ioim->itnim, iocom_utags); - evt = BFA_IOIM_SM_COMP_UTAG; - break; - - default: - WARN_ON(1); - } - - bfa_sm_send_event(ioim, evt); -} - -void -bfa_ioim_good_comp_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct bfi_ioim_rsp_s *rsp = (struct bfi_ioim_rsp_s *) m; - struct bfa_ioim_s *ioim; - u16 iotag; - - iotag = be16_to_cpu(rsp->io_tag); - - ioim = BFA_IOIM_FROM_TAG(fcpim, iotag); - WARN_ON(BFA_IOIM_TAG_2_ID(ioim->iotag) != iotag); - - bfa_ioim_cb_profile_comp(fcpim, ioim); - - bfa_sm_send_event(ioim, BFA_IOIM_SM_COMP_GOOD); -} - -/* - * Called by itnim to clean up IO while going offline. - */ -void -bfa_ioim_cleanup(struct bfa_ioim_s *ioim) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_stats(ioim->itnim, io_cleanups); - - ioim->iosp->tskim = NULL; - bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP); -} - -void -bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, struct bfa_tskim_s *tskim) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_stats(ioim->itnim, io_tmaborts); - - ioim->iosp->tskim = tskim; - bfa_sm_send_event(ioim, BFA_IOIM_SM_CLEANUP); -} - -/* - * IOC failure handling. - */ -void -bfa_ioim_iocdisable(struct bfa_ioim_s *ioim) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_stats(ioim->itnim, io_iocdowns); - bfa_sm_send_event(ioim, BFA_IOIM_SM_HWFAIL); -} - -/* - * IO offline TOV popped. Fail the pending IO. - */ -void -bfa_ioim_tov(struct bfa_ioim_s *ioim) -{ - bfa_trc(ioim->bfa, ioim->iotag); - bfa_sm_send_event(ioim, BFA_IOIM_SM_IOTOV); -} - - -/* - * Allocate IOIM resource for initiator mode I/O request. - */ -struct bfa_ioim_s * -bfa_ioim_alloc(struct bfa_s *bfa, struct bfad_ioim_s *dio, - struct bfa_itnim_s *itnim, u16 nsges) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct bfa_ioim_s *ioim; - struct bfa_iotag_s *iotag = NULL; - - /* - * alocate IOIM resource - */ - bfa_q_deq(&fcpim->fcp->iotag_ioim_free_q, &iotag); - if (!iotag) { - bfa_stats(itnim, no_iotags); - return NULL; - } - - ioim = BFA_IOIM_FROM_TAG(fcpim, iotag->tag); - - ioim->dio = dio; - ioim->itnim = itnim; - ioim->nsges = nsges; - ioim->nsgpgs = 0; - - bfa_stats(itnim, total_ios); - fcpim->ios_active++; - - list_add_tail(&ioim->qe, &itnim->io_q); - - return ioim; -} - -void -bfa_ioim_free(struct bfa_ioim_s *ioim) -{ - struct bfa_fcpim_s *fcpim = ioim->fcpim; - struct bfa_iotag_s *iotag; - - if (ioim->nsgpgs > 0) - bfa_sgpg_mfree(ioim->bfa, &ioim->sgpg_q, ioim->nsgpgs); - - bfa_stats(ioim->itnim, io_comps); - fcpim->ios_active--; - - ioim->iotag &= BFA_IOIM_IOTAG_MASK; - - WARN_ON(!(ioim->iotag < - (fcpim->fcp->num_ioim_reqs + fcpim->fcp->num_fwtio_reqs))); - iotag = BFA_IOTAG_FROM_TAG(fcpim->fcp, ioim->iotag); - - if (ioim->iotag < fcpim->fcp->num_ioim_reqs) - list_add_tail(&iotag->qe, &fcpim->fcp->iotag_ioim_free_q); - else - list_add_tail(&iotag->qe, &fcpim->fcp->iotag_tio_free_q); - - list_del(&ioim->qe); -} - -void -bfa_ioim_start(struct bfa_ioim_s *ioim) -{ - bfa_ioim_cb_profile_start(ioim->fcpim, ioim); - - /* - * Obtain the queue over which this request has to be issued - */ - ioim->reqq = bfa_fcpim_ioredirect_enabled(ioim->bfa) ? - BFA_FALSE : bfa_itnim_get_reqq(ioim); - - bfa_sm_send_event(ioim, BFA_IOIM_SM_START); -} - -/* - * Driver I/O abort request. - */ -bfa_status_t -bfa_ioim_abort(struct bfa_ioim_s *ioim) -{ - - bfa_trc(ioim->bfa, ioim->iotag); - - if (!bfa_ioim_is_abortable(ioim)) - return BFA_STATUS_FAILED; - - bfa_stats(ioim->itnim, io_aborts); - bfa_sm_send_event(ioim, BFA_IOIM_SM_ABORT); - - return BFA_STATUS_OK; -} - -/* - * BFA TSKIM state machine functions - */ - -/* - * Task management command beginning state. - */ -static void -bfa_tskim_sm_uninit(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_START: - bfa_sm_set_state(tskim, bfa_tskim_sm_active); - bfa_tskim_gather_ios(tskim); - - /* - * If device is offline, do not send TM on wire. Just cleanup - * any pending IO requests and complete TM request. - */ - if (!bfa_itnim_is_online(tskim->itnim)) { - bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); - tskim->tsk_status = BFI_TSKIM_STS_OK; - bfa_tskim_cleanup_ios(tskim); - return; - } - - if (!bfa_tskim_send(tskim)) { - bfa_sm_set_state(tskim, bfa_tskim_sm_qfull); - bfa_stats(tskim->itnim, tm_qwait); - bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq, - &tskim->reqq_wait); - } - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/* - * TM command is active, awaiting completion from firmware to - * cleanup IO requests in TM scope. - */ -static void -bfa_tskim_sm_active(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_DONE: - bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); - bfa_tskim_cleanup_ios(tskim); - break; - - case BFA_TSKIM_SM_CLEANUP: - bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); - if (!bfa_tskim_send_abort(tskim)) { - bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup_qfull); - bfa_stats(tskim->itnim, tm_qwait); - bfa_reqq_wait(tskim->bfa, tskim->itnim->reqq, - &tskim->reqq_wait); - } - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/* - * An active TM is being cleaned up since ITN is offline. Awaiting cleanup - * completion event from firmware. - */ -static void -bfa_tskim_sm_cleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_DONE: - /* - * Ignore and wait for ABORT completion from firmware. - */ - break; - - case BFA_TSKIM_SM_CLEANUP_DONE: - bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); - bfa_tskim_cleanup_ios(tskim); - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -static void -bfa_tskim_sm_iocleanup(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_IOS_DONE: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_done); - break; - - case BFA_TSKIM_SM_CLEANUP: - /* - * Ignore, TM command completed on wire. - * Notify TM conmpletion on IO cleanup completion. - */ - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/* - * Task management command is waiting for room in request CQ - */ -static void -bfa_tskim_sm_qfull(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_QRESUME: - bfa_sm_set_state(tskim, bfa_tskim_sm_active); - bfa_tskim_send(tskim); - break; - - case BFA_TSKIM_SM_CLEANUP: - /* - * No need to send TM on wire since ITN is offline. - */ - bfa_sm_set_state(tskim, bfa_tskim_sm_iocleanup); - bfa_reqq_wcancel(&tskim->reqq_wait); - bfa_tskim_cleanup_ios(tskim); - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_reqq_wcancel(&tskim->reqq_wait); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/* - * Task management command is active, awaiting for room in request CQ - * to send clean up request. - */ -static void -bfa_tskim_sm_cleanup_qfull(struct bfa_tskim_s *tskim, - enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_DONE: - bfa_reqq_wcancel(&tskim->reqq_wait); - /* - * Fall through !!! - */ - case BFA_TSKIM_SM_QRESUME: - bfa_sm_set_state(tskim, bfa_tskim_sm_cleanup); - bfa_tskim_send_abort(tskim); - break; - - case BFA_TSKIM_SM_HWFAIL: - bfa_sm_set_state(tskim, bfa_tskim_sm_hcb); - bfa_reqq_wcancel(&tskim->reqq_wait); - bfa_tskim_iocdisable_ios(tskim); - bfa_tskim_qcomp(tskim, __bfa_cb_tskim_failed); - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -/* - * BFA callback is pending - */ -static void -bfa_tskim_sm_hcb(struct bfa_tskim_s *tskim, enum bfa_tskim_event event) -{ - bfa_trc(tskim->bfa, event); - - switch (event) { - case BFA_TSKIM_SM_HCB: - bfa_sm_set_state(tskim, bfa_tskim_sm_uninit); - bfa_tskim_free(tskim); - break; - - case BFA_TSKIM_SM_CLEANUP: - bfa_tskim_notify_comp(tskim); - break; - - case BFA_TSKIM_SM_HWFAIL: - break; - - default: - bfa_sm_fault(tskim->bfa, event); - } -} - -static void -__bfa_cb_tskim_done(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_tskim_s *tskim = cbarg; - - if (!complete) { - bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB); - return; - } - - bfa_stats(tskim->itnim, tm_success); - bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, tskim->tsk_status); -} - -static void -__bfa_cb_tskim_failed(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_tskim_s *tskim = cbarg; - - if (!complete) { - bfa_sm_send_event(tskim, BFA_TSKIM_SM_HCB); - return; - } - - bfa_stats(tskim->itnim, tm_failures); - bfa_cb_tskim_done(tskim->bfa->bfad, tskim->dtsk, - BFI_TSKIM_STS_FAILED); -} - -static bfa_boolean_t -bfa_tskim_match_scope(struct bfa_tskim_s *tskim, struct scsi_lun lun) -{ - switch (tskim->tm_cmnd) { - case FCP_TM_TARGET_RESET: - return BFA_TRUE; - - case FCP_TM_ABORT_TASK_SET: - case FCP_TM_CLEAR_TASK_SET: - case FCP_TM_LUN_RESET: - case FCP_TM_CLEAR_ACA: - return !memcmp(&tskim->lun, &lun, sizeof(lun)); - - default: - WARN_ON(1); - } - - return BFA_FALSE; -} - -/* - * Gather affected IO requests and task management commands. - */ -static void -bfa_tskim_gather_ios(struct bfa_tskim_s *tskim) -{ - struct bfa_itnim_s *itnim = tskim->itnim; - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - struct scsi_cmnd *cmnd; - struct scsi_lun scsilun; - - INIT_LIST_HEAD(&tskim->io_q); - - /* - * Gather any active IO requests first. - */ - list_for_each_safe(qe, qen, &itnim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - cmnd = (struct scsi_cmnd *) ioim->dio; - int_to_scsilun(cmnd->device->lun, &scsilun); - if (bfa_tskim_match_scope(tskim, scsilun)) { - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &tskim->io_q); - } - } - - /* - * Failback any pending IO requests immediately. - */ - list_for_each_safe(qe, qen, &itnim->pending_q) { - ioim = (struct bfa_ioim_s *) qe; - cmnd = (struct scsi_cmnd *) ioim->dio; - int_to_scsilun(cmnd->device->lun, &scsilun); - if (bfa_tskim_match_scope(tskim, scsilun)) { - list_del(&ioim->qe); - list_add_tail(&ioim->qe, &ioim->fcpim->ioim_comp_q); - bfa_ioim_tov(ioim); - } - } -} - -/* - * IO cleanup completion - */ -static void -bfa_tskim_cleanp_comp(void *tskim_cbarg) -{ - struct bfa_tskim_s *tskim = tskim_cbarg; - - bfa_stats(tskim->itnim, tm_io_comps); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_IOS_DONE); -} - -/* - * Gather affected IO requests and task management commands. - */ -static void -bfa_tskim_cleanup_ios(struct bfa_tskim_s *tskim) -{ - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - bfa_wc_init(&tskim->wc, bfa_tskim_cleanp_comp, tskim); - - list_for_each_safe(qe, qen, &tskim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_wc_up(&tskim->wc); - bfa_ioim_cleanup_tm(ioim, tskim); - } - - bfa_wc_wait(&tskim->wc); -} - -/* - * Send task management request to firmware. - */ -static bfa_boolean_t -bfa_tskim_send(struct bfa_tskim_s *tskim) -{ - struct bfa_itnim_s *itnim = tskim->itnim; - struct bfi_tskim_req_s *m; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(tskim->bfa, itnim->reqq); - if (!m) - return BFA_FALSE; - - /* - * build i/o request message next - */ - bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_TM_REQ, - bfa_fn_lpu(tskim->bfa)); - - m->tsk_tag = cpu_to_be16(tskim->tsk_tag); - m->itn_fhdl = tskim->itnim->rport->fw_handle; - m->t_secs = tskim->tsecs; - m->lun = tskim->lun; - m->tm_flags = tskim->tm_cmnd; - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(tskim->bfa, itnim->reqq, m->mh); - return BFA_TRUE; -} - -/* - * Send abort request to cleanup an active TM to firmware. - */ -static bfa_boolean_t -bfa_tskim_send_abort(struct bfa_tskim_s *tskim) -{ - struct bfa_itnim_s *itnim = tskim->itnim; - struct bfi_tskim_abortreq_s *m; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(tskim->bfa, itnim->reqq); - if (!m) - return BFA_FALSE; - - /* - * build i/o request message next - */ - bfi_h2i_set(m->mh, BFI_MC_TSKIM, BFI_TSKIM_H2I_ABORT_REQ, - bfa_fn_lpu(tskim->bfa)); - - m->tsk_tag = cpu_to_be16(tskim->tsk_tag); - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(tskim->bfa, itnim->reqq, m->mh); - return BFA_TRUE; -} - -/* - * Call to resume task management cmnd waiting for room in request queue. - */ -static void -bfa_tskim_qresume(void *cbarg) -{ - struct bfa_tskim_s *tskim = cbarg; - - bfa_stats(tskim->itnim, tm_qresumes); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_QRESUME); -} - -/* - * Cleanup IOs associated with a task mangement command on IOC failures. - */ -static void -bfa_tskim_iocdisable_ios(struct bfa_tskim_s *tskim) -{ - struct bfa_ioim_s *ioim; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &tskim->io_q) { - ioim = (struct bfa_ioim_s *) qe; - bfa_ioim_iocdisable(ioim); - } -} - -/* - * Notification on completions from related ioim. - */ -void -bfa_tskim_iodone(struct bfa_tskim_s *tskim) -{ - bfa_wc_down(&tskim->wc); -} - -/* - * Handle IOC h/w failure notification from itnim. - */ -void -bfa_tskim_iocdisable(struct bfa_tskim_s *tskim) -{ - tskim->notify = BFA_FALSE; - bfa_stats(tskim->itnim, tm_iocdowns); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_HWFAIL); -} - -/* - * Cleanup TM command and associated IOs as part of ITNIM offline. - */ -void -bfa_tskim_cleanup(struct bfa_tskim_s *tskim) -{ - tskim->notify = BFA_TRUE; - bfa_stats(tskim->itnim, tm_cleanups); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP); -} - -/* - * Memory allocation and initialization. - */ -void -bfa_tskim_attach(struct bfa_fcpim_s *fcpim) -{ - struct bfa_tskim_s *tskim; - struct bfa_fcp_mod_s *fcp = fcpim->fcp; - u16 i; - - INIT_LIST_HEAD(&fcpim->tskim_free_q); - INIT_LIST_HEAD(&fcpim->tskim_unused_q); - - tskim = (struct bfa_tskim_s *) bfa_mem_kva_curp(fcp); - fcpim->tskim_arr = tskim; - - for (i = 0; i < fcpim->num_tskim_reqs; i++, tskim++) { - /* - * initialize TSKIM - */ - memset(tskim, 0, sizeof(struct bfa_tskim_s)); - tskim->tsk_tag = i; - tskim->bfa = fcpim->bfa; - tskim->fcpim = fcpim; - tskim->notify = BFA_FALSE; - bfa_reqq_winit(&tskim->reqq_wait, bfa_tskim_qresume, - tskim); - bfa_sm_set_state(tskim, bfa_tskim_sm_uninit); - - list_add_tail(&tskim->qe, &fcpim->tskim_free_q); - } - - bfa_mem_kva_curp(fcp) = (u8 *) tskim; -} - -void -bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct bfi_tskim_rsp_s *rsp = (struct bfi_tskim_rsp_s *) m; - struct bfa_tskim_s *tskim; - u16 tsk_tag = be16_to_cpu(rsp->tsk_tag); - - tskim = BFA_TSKIM_FROM_TAG(fcpim, tsk_tag); - WARN_ON(tskim->tsk_tag != tsk_tag); - - tskim->tsk_status = rsp->tsk_status; - - /* - * Firmware sends BFI_TSKIM_STS_ABORTED status for abort - * requests. All other statuses are for normal completions. - */ - if (rsp->tsk_status == BFI_TSKIM_STS_ABORTED) { - bfa_stats(tskim->itnim, tm_cleanup_comps); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_CLEANUP_DONE); - } else { - bfa_stats(tskim->itnim, tm_fw_rsps); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_DONE); - } -} - - -struct bfa_tskim_s * -bfa_tskim_alloc(struct bfa_s *bfa, struct bfad_tskim_s *dtsk) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct bfa_tskim_s *tskim; - - bfa_q_deq(&fcpim->tskim_free_q, &tskim); - - if (tskim) - tskim->dtsk = dtsk; - - return tskim; -} - -void -bfa_tskim_free(struct bfa_tskim_s *tskim) -{ - WARN_ON(!bfa_q_is_on_q_func(&tskim->itnim->tsk_q, &tskim->qe)); - list_del(&tskim->qe); - list_add_tail(&tskim->qe, &tskim->fcpim->tskim_free_q); -} - -/* - * Start a task management command. - * - * @param[in] tskim BFA task management command instance - * @param[in] itnim i-t nexus for the task management command - * @param[in] lun lun, if applicable - * @param[in] tm_cmnd Task management command code. - * @param[in] t_secs Timeout in seconds - * - * @return None. - */ -void -bfa_tskim_start(struct bfa_tskim_s *tskim, struct bfa_itnim_s *itnim, - struct scsi_lun lun, - enum fcp_tm_cmnd tm_cmnd, u8 tsecs) -{ - tskim->itnim = itnim; - tskim->lun = lun; - tskim->tm_cmnd = tm_cmnd; - tskim->tsecs = tsecs; - tskim->notify = BFA_FALSE; - bfa_stats(itnim, tm_cmnds); - - list_add_tail(&tskim->qe, &itnim->tsk_q); - bfa_sm_send_event(tskim, BFA_TSKIM_SM_START); -} - -void -bfa_tskim_res_recfg(struct bfa_s *bfa, u16 num_tskim_fw) -{ - struct bfa_fcpim_s *fcpim = BFA_FCPIM(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (fcpim->num_tskim_reqs - num_tskim_fw); i++) { - bfa_q_deq_tail(&fcpim->tskim_free_q, &qe); - list_add_tail(qe, &fcpim->tskim_unused_q); - } -} - -/* BFA FCP module - parent module for fcpim */ - -BFA_MODULE(fcp); - -static void -bfa_fcp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_mem_kva_s *fcp_kva = BFA_MEM_FCP_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_ios, num_io_req; - u32 km_len = 0; - - /* - * ZERO for num_ioim_reqs and num_fwtio_reqs is allowed config value. - * So if the values are non zero, adjust them appropriately. - */ - if (cfg->fwcfg.num_ioim_reqs && - cfg->fwcfg.num_ioim_reqs < BFA_IOIM_MIN) - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MIN; - else if (cfg->fwcfg.num_ioim_reqs > BFA_IOIM_MAX) - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; - - if (cfg->fwcfg.num_fwtio_reqs > BFA_FWTIO_MAX) - cfg->fwcfg.num_fwtio_reqs = BFA_FWTIO_MAX; - - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - if (num_io_req > BFA_IO_MAX) { - if (cfg->fwcfg.num_ioim_reqs && cfg->fwcfg.num_fwtio_reqs) { - cfg->fwcfg.num_ioim_reqs = BFA_IO_MAX/2; - cfg->fwcfg.num_fwtio_reqs = BFA_IO_MAX/2; - } else if (cfg->fwcfg.num_fwtio_reqs) - cfg->fwcfg.num_fwtio_reqs = BFA_FWTIO_MAX; - else - cfg->fwcfg.num_ioim_reqs = BFA_IOIM_MAX; - } - - bfa_fcpim_meminfo(cfg, &km_len); - - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - km_len += num_io_req * sizeof(struct bfa_iotag_s); - km_len += cfg->fwcfg.num_rports * sizeof(struct bfa_itn_s); - - /* dma memory */ - nsegs = BFI_MEM_DMA_NSEGS(num_io_req, BFI_IOIM_SNSLEN); - per_seg_ios = BFI_MEM_NREQS_SEG(BFI_IOIM_SNSLEN); - - bfa_mem_dma_seg_iter(fcp, seg_ptr, nsegs, idx) { - if (num_io_req >= per_seg_ios) { - num_io_req -= per_seg_ios; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_ios * BFI_IOIM_SNSLEN); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_io_req * BFI_IOIM_SNSLEN); - } - - /* kva memory */ - bfa_mem_kva_setup(minfo, fcp_kva, km_len); -} - -static void -bfa_fcp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 idx, nsegs, num_io_req; - - fcp->num_ioim_reqs = cfg->fwcfg.num_ioim_reqs; - fcp->num_fwtio_reqs = cfg->fwcfg.num_fwtio_reqs; - fcp->num_itns = cfg->fwcfg.num_rports; - fcp->bfa = bfa; - - /* - * Setup the pool of snsbase addr's, that is passed to fw as - * part of bfi_iocfc_cfg_s. - */ - num_io_req = (cfg->fwcfg.num_ioim_reqs + cfg->fwcfg.num_fwtio_reqs); - nsegs = BFI_MEM_DMA_NSEGS(num_io_req, BFI_IOIM_SNSLEN); - - bfa_mem_dma_seg_iter(fcp, seg_ptr, nsegs, idx) { - - if (!bfa_mem_dma_virt(seg_ptr)) - break; - - fcp->snsbase[idx].pa = bfa_mem_dma_phys(seg_ptr); - fcp->snsbase[idx].kva = bfa_mem_dma_virt(seg_ptr); - bfa_iocfc_set_snsbase(bfa, idx, fcp->snsbase[idx].pa); - } - - bfa_fcpim_attach(fcp, bfad, cfg, pcidev); - - bfa_iotag_attach(fcp); - - fcp->itn_arr = (struct bfa_itn_s *) bfa_mem_kva_curp(fcp); - bfa_mem_kva_curp(fcp) = (u8 *)fcp->itn_arr + - (fcp->num_itns * sizeof(struct bfa_itn_s)); - memset(fcp->itn_arr, 0, - (fcp->num_itns * sizeof(struct bfa_itn_s))); -} - -static void -bfa_fcp_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_start(struct bfa_s *bfa) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - - /* - * bfa_init() with flash read is complete. now invalidate the stale - * content of lun mask like unit attention, rp tag and lp tag. - */ - bfa_ioim_lm_init(fcp->bfa); -} - -static void -bfa_fcp_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_fcp_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - - /* Enqueue unused ioim resources to free_q */ - list_splice_tail_init(&fcp->iotag_unused_q, &fcp->iotag_ioim_free_q); - - bfa_fcpim_iocdisable(fcp); -} - -void -bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw) -{ - struct bfa_fcp_mod_s *mod = BFA_FCP_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_ioim_reqs - num_ioim_fw); i++) { - bfa_q_deq_tail(&mod->iotag_ioim_free_q, &qe); - list_add_tail(qe, &mod->iotag_unused_q); - } -} - -void -bfa_itn_create(struct bfa_s *bfa, struct bfa_rport_s *rport, - void (*isr)(struct bfa_s *bfa, struct bfi_msg_s *m)) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - struct bfa_itn_s *itn; - - itn = BFA_ITN_FROM_TAG(fcp, rport->rport_tag); - itn->isr = isr; -} - -/* - * Itn interrupt processing. - */ -void -bfa_itn_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - struct bfa_fcp_mod_s *fcp = BFA_FCP_MOD(bfa); - union bfi_itn_i2h_msg_u msg; - struct bfa_itn_s *itn; - - msg.msg = m; - itn = BFA_ITN_FROM_TAG(fcp, msg.create_rsp->bfa_handle); - - if (itn->isr) - itn->isr(bfa, m); - else - WARN_ON(1); -} - -void -bfa_iotag_attach(struct bfa_fcp_mod_s *fcp) -{ - struct bfa_iotag_s *iotag; - u16 num_io_req, i; - - iotag = (struct bfa_iotag_s *) bfa_mem_kva_curp(fcp); - fcp->iotag_arr = iotag; - - INIT_LIST_HEAD(&fcp->iotag_ioim_free_q); - INIT_LIST_HEAD(&fcp->iotag_tio_free_q); - INIT_LIST_HEAD(&fcp->iotag_unused_q); - - num_io_req = fcp->num_ioim_reqs + fcp->num_fwtio_reqs; - for (i = 0; i < num_io_req; i++, iotag++) { - memset(iotag, 0, sizeof(struct bfa_iotag_s)); - iotag->tag = i; - if (i < fcp->num_ioim_reqs) - list_add_tail(&iotag->qe, &fcp->iotag_ioim_free_q); - else - list_add_tail(&iotag->qe, &fcp->iotag_tio_free_q); - } - - bfa_mem_kva_curp(fcp) = (u8 *) iotag; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.h deleted file mode 100644 index 36f26da8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcpim.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCPIM_H__ -#define __BFA_FCPIM_H__ - -#include "bfa.h" -#include "bfa_svc.h" -#include "bfi_ms.h" -#include "bfa_defs_svc.h" -#include "bfa_cs.h" - -/* FCP module related definitions */ -#define BFA_IO_MAX BFI_IO_MAX -#define BFA_FWTIO_MAX 2000 - -struct bfa_fcp_mod_s; -struct bfa_iotag_s { - struct list_head qe; /* queue element */ - u16 tag; /* FW IO tag */ -}; - -struct bfa_itn_s { - bfa_isr_func_t isr; -}; - -void bfa_itn_create(struct bfa_s *bfa, struct bfa_rport_s *rport, - void (*isr)(struct bfa_s *bfa, struct bfi_msg_s *m)); -void bfa_itn_isr(struct bfa_s *bfa, struct bfi_msg_s *m); -void bfa_iotag_attach(struct bfa_fcp_mod_s *fcp); -void bfa_fcp_res_recfg(struct bfa_s *bfa, u16 num_ioim_fw); - -#define BFA_FCP_MOD(_hal) (&(_hal)->modules.fcp_mod) -#define BFA_MEM_FCP_KVA(__bfa) (&(BFA_FCP_MOD(__bfa)->kva_seg)) -#define BFA_IOTAG_FROM_TAG(_fcp, _tag) \ - (&(_fcp)->iotag_arr[(_tag & BFA_IOIM_IOTAG_MASK)]) -#define BFA_ITN_FROM_TAG(_fcp, _tag) \ - ((_fcp)->itn_arr + ((_tag) & ((_fcp)->num_itns - 1))) -#define BFA_SNSINFO_FROM_TAG(_fcp, _tag) \ - bfa_mem_get_dmabuf_kva(_fcp, _tag, BFI_IOIM_SNSLEN) - -#define BFA_ITNIM_MIN 32 -#define BFA_ITNIM_MAX 1024 - -#define BFA_IOIM_MIN 8 -#define BFA_IOIM_MAX 2000 - -#define BFA_TSKIM_MIN 4 -#define BFA_TSKIM_MAX 512 -#define BFA_FCPIM_PATHTOV_DEF (30 * 1000) /* in millisecs */ -#define BFA_FCPIM_PATHTOV_MAX (90 * 1000) /* in millisecs */ - - -#define bfa_itnim_ioprofile_update(__itnim, __index) \ - (__itnim->ioprofile.iocomps[__index]++) - -#define BFA_IOIM_RETRY_TAG_OFFSET 11 -#define BFA_IOIM_IOTAG_MASK 0x07ff /* 2K IOs */ -#define BFA_IOIM_RETRY_MAX 7 - -/* Buckets are are 512 bytes to 2MB */ -static inline u32 -bfa_ioim_get_index(u32 n) { - int pos = 0; - if (n >= (1UL)<<22) - return BFA_IOBUCKET_MAX - 1; - n >>= 8; - if (n >= (1UL)<<16) { - n >>= 16; - pos += 16; - } - if (n >= 1 << 8) { - n >>= 8; - pos += 8; - } - if (n >= 1 << 4) { - n >>= 4; - pos += 4; - } - if (n >= 1 << 2) { - n >>= 2; - pos += 2; - } - if (n >= 1 << 1) - pos += 1; - - return (n == 0) ? (0) : pos; -} - -/* - * forward declarations - */ -struct bfa_ioim_s; -struct bfa_tskim_s; -struct bfad_ioim_s; -struct bfad_tskim_s; - -typedef void (*bfa_fcpim_profile_t) (struct bfa_ioim_s *ioim); - -struct bfa_fcpim_s { - struct bfa_s *bfa; - struct bfa_fcp_mod_s *fcp; - struct bfa_itnim_s *itnim_arr; - struct bfa_ioim_s *ioim_arr; - struct bfa_ioim_sp_s *ioim_sp_arr; - struct bfa_tskim_s *tskim_arr; - int num_itnims; - int num_tskim_reqs; - u32 path_tov; - u16 q_depth; - u8 reqq; /* Request queue to be used */ - struct list_head itnim_q; /* queue of active itnim */ - struct list_head ioim_resfree_q; /* IOs waiting for f/w */ - struct list_head ioim_comp_q; /* IO global comp Q */ - struct list_head tskim_free_q; - struct list_head tskim_unused_q; /* Unused tskim Q */ - u32 ios_active; /* current active IOs */ - u32 delay_comp; - struct bfa_fcpim_del_itn_stats_s del_itn_stats; - bfa_boolean_t ioredirect; - bfa_boolean_t io_profile; - u32 io_profile_start_time; - bfa_fcpim_profile_t profile_comp; - bfa_fcpim_profile_t profile_start; -}; - -/* Max FCP dma segs required */ -#define BFA_FCP_DMA_SEGS BFI_IOIM_SNSBUF_SEGS - -struct bfa_fcp_mod_s { - struct bfa_s *bfa; - struct list_head iotag_ioim_free_q; /* free IO resources */ - struct list_head iotag_tio_free_q; /* free IO resources */ - struct list_head iotag_unused_q; /* unused IO resources*/ - struct bfa_iotag_s *iotag_arr; - struct bfa_itn_s *itn_arr; - int num_ioim_reqs; - int num_fwtio_reqs; - int num_itns; - struct bfa_dma_s snsbase[BFA_FCP_DMA_SEGS]; - struct bfa_fcpim_s fcpim; - struct bfa_mem_dma_s dma_seg[BFA_FCP_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; -}; - -/* - * BFA IO (initiator mode) - */ -struct bfa_ioim_s { - struct list_head qe; /* queue elememt */ - bfa_sm_t sm; /* BFA ioim state machine */ - struct bfa_s *bfa; /* BFA module */ - struct bfa_fcpim_s *fcpim; /* parent fcpim module */ - struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ - struct bfad_ioim_s *dio; /* driver IO handle */ - u16 iotag; /* FWI IO tag */ - u16 abort_tag; /* unqiue abort request tag */ - u16 nsges; /* number of SG elements */ - u16 nsgpgs; /* number of SG pages */ - struct bfa_sgpg_s *sgpg; /* first SG page */ - struct list_head sgpg_q; /* allocated SG pages */ - struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ - bfa_cb_cbfn_t io_cbfn; /* IO completion handler */ - struct bfa_ioim_sp_s *iosp; /* slow-path IO handling */ - u8 reqq; /* Request queue for I/O */ - u8 mode; /* IO is passthrough or not */ - u64 start_time; /* IO's Profile start val */ -}; - -struct bfa_ioim_sp_s { - struct bfi_msg_s comp_rspmsg; /* IO comp f/w response */ - struct bfa_sgpg_wqe_s sgpg_wqe; /* waitq elem for sgpg */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - bfa_boolean_t abort_explicit; /* aborted by OS */ - struct bfa_tskim_s *tskim; /* Relevant TM cmd */ -}; - -/* - * BFA Task management command (initiator mode) - */ -struct bfa_tskim_s { - struct list_head qe; - bfa_sm_t sm; - struct bfa_s *bfa; /* BFA module */ - struct bfa_fcpim_s *fcpim; /* parent fcpim module */ - struct bfa_itnim_s *itnim; /* i-t-n nexus for this IO */ - struct bfad_tskim_s *dtsk; /* driver task mgmt cmnd */ - bfa_boolean_t notify; /* notify itnim on TM comp */ - struct scsi_lun lun; /* lun if applicable */ - enum fcp_tm_cmnd tm_cmnd; /* task management command */ - u16 tsk_tag; /* FWI IO tag */ - u8 tsecs; /* timeout in seconds */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - struct list_head io_q; /* queue of affected IOs */ - struct bfa_wc_s wc; /* waiting counter */ - struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ - enum bfi_tskim_status tsk_status; /* TM status */ -}; - -/* - * BFA i-t-n (initiator mode) - */ -struct bfa_itnim_s { - struct list_head qe; /* queue element */ - bfa_sm_t sm; /* i-t-n im BFA state machine */ - struct bfa_s *bfa; /* bfa instance */ - struct bfa_rport_s *rport; /* bfa rport */ - void *ditn; /* driver i-t-n structure */ - struct bfi_mhdr_s mhdr; /* pre-built mhdr */ - u8 msg_no; /* itnim/rport firmware handle */ - u8 reqq; /* CQ for requests */ - struct bfa_cb_qe_s hcb_qe; /* bfa callback qelem */ - struct list_head pending_q; /* queue of pending IO requests */ - struct list_head io_q; /* queue of active IO requests */ - struct list_head io_cleanup_q; /* IO being cleaned up */ - struct list_head tsk_q; /* queue of active TM commands */ - struct list_head delay_comp_q; /* queue of failed inflight cmds */ - bfa_boolean_t seq_rec; /* SQER supported */ - bfa_boolean_t is_online; /* itnim is ONLINE for IO */ - bfa_boolean_t iotov_active; /* IO TOV timer is active */ - struct bfa_wc_s wc; /* waiting counter */ - struct bfa_timer_s timer; /* pending IO TOV */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - struct bfa_fcpim_s *fcpim; /* fcpim module */ - struct bfa_itnim_iostats_s stats; - struct bfa_itnim_ioprofile_s ioprofile; -}; - -#define bfa_itnim_is_online(_itnim) ((_itnim)->is_online) -#define BFA_FCPIM(_hal) (&(_hal)->modules.fcp_mod.fcpim) -#define BFA_IOIM_TAG_2_ID(_iotag) ((_iotag) & BFA_IOIM_IOTAG_MASK) -#define BFA_IOIM_FROM_TAG(_fcpim, _iotag) \ - (&fcpim->ioim_arr[(_iotag & BFA_IOIM_IOTAG_MASK)]) -#define BFA_TSKIM_FROM_TAG(_fcpim, _tmtag) \ - (&fcpim->tskim_arr[_tmtag & (fcpim->num_tskim_reqs - 1)]) - -#define bfa_io_profile_start_time(_bfa) \ - ((_bfa)->modules.fcp_mod.fcpim.io_profile_start_time) -#define bfa_fcpim_get_io_profile(_bfa) \ - ((_bfa)->modules.fcp_mod.fcpim.io_profile) -#define bfa_ioim_update_iotag(__ioim) do { \ - uint16_t k = (__ioim)->iotag >> BFA_IOIM_RETRY_TAG_OFFSET; \ - k++; (__ioim)->iotag &= BFA_IOIM_IOTAG_MASK; \ - (__ioim)->iotag |= k << BFA_IOIM_RETRY_TAG_OFFSET; \ -} while (0) - -static inline bfa_boolean_t -bfa_ioim_maxretry_reached(struct bfa_ioim_s *ioim) -{ - uint16_t k = ioim->iotag >> BFA_IOIM_RETRY_TAG_OFFSET; - if (k < BFA_IOIM_RETRY_MAX) - return BFA_FALSE; - return BFA_TRUE; -} - -/* - * function prototypes - */ -void bfa_ioim_attach(struct bfa_fcpim_s *fcpim); -void bfa_ioim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_ioim_good_comp_isr(struct bfa_s *bfa, - struct bfi_msg_s *msg); -void bfa_ioim_cleanup(struct bfa_ioim_s *ioim); -void bfa_ioim_cleanup_tm(struct bfa_ioim_s *ioim, - struct bfa_tskim_s *tskim); -void bfa_ioim_iocdisable(struct bfa_ioim_s *ioim); -void bfa_ioim_tov(struct bfa_ioim_s *ioim); - -void bfa_tskim_attach(struct bfa_fcpim_s *fcpim); -void bfa_tskim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_tskim_iodone(struct bfa_tskim_s *tskim); -void bfa_tskim_iocdisable(struct bfa_tskim_s *tskim); -void bfa_tskim_cleanup(struct bfa_tskim_s *tskim); -void bfa_tskim_res_recfg(struct bfa_s *bfa, u16 num_tskim_fw); - -void bfa_itnim_meminfo(struct bfa_iocfc_cfg_s *cfg, u32 *km_len); -void bfa_itnim_attach(struct bfa_fcpim_s *fcpim); -void bfa_itnim_iocdisable(struct bfa_itnim_s *itnim); -void bfa_itnim_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_itnim_iodone(struct bfa_itnim_s *itnim); -void bfa_itnim_tskdone(struct bfa_itnim_s *itnim); -bfa_boolean_t bfa_itnim_hold_io(struct bfa_itnim_s *itnim); - -/* - * bfa fcpim module API functions - */ -void bfa_fcpim_path_tov_set(struct bfa_s *bfa, u16 path_tov); -u16 bfa_fcpim_path_tov_get(struct bfa_s *bfa); -u16 bfa_fcpim_qdepth_get(struct bfa_s *bfa); -bfa_status_t bfa_fcpim_port_iostats(struct bfa_s *bfa, - struct bfa_itnim_iostats_s *stats, u8 lp_tag); -void bfa_fcpim_add_stats(struct bfa_itnim_iostats_s *fcpim_stats, - struct bfa_itnim_iostats_s *itnim_stats); -bfa_status_t bfa_fcpim_profile_on(struct bfa_s *bfa, u32 time); -bfa_status_t bfa_fcpim_profile_off(struct bfa_s *bfa); - -#define bfa_fcpim_ioredirect_enabled(__bfa) \ - (((struct bfa_fcpim_s *)(BFA_FCPIM(__bfa)))->ioredirect) - -#define bfa_fcpim_get_next_reqq(__bfa, __qid) \ -{ \ - struct bfa_fcpim_s *__fcpim = BFA_FCPIM(__bfa); \ - __fcpim->reqq++; \ - __fcpim->reqq &= (BFI_IOC_MAX_CQS - 1); \ - *(__qid) = __fcpim->reqq; \ -} - -#define bfa_iocfc_map_msg_to_qid(__msg, __qid) \ - *(__qid) = (u8)((__msg) & (BFI_IOC_MAX_CQS - 1)); -/* - * bfa itnim API functions - */ -struct bfa_itnim_s *bfa_itnim_create(struct bfa_s *bfa, - struct bfa_rport_s *rport, void *itnim); -void bfa_itnim_delete(struct bfa_itnim_s *itnim); -void bfa_itnim_online(struct bfa_itnim_s *itnim, bfa_boolean_t seq_rec); -void bfa_itnim_offline(struct bfa_itnim_s *itnim); -void bfa_itnim_clear_stats(struct bfa_itnim_s *itnim); -bfa_status_t bfa_itnim_get_ioprofile(struct bfa_itnim_s *itnim, - struct bfa_itnim_ioprofile_s *ioprofile); - -#define bfa_itnim_get_reqq(__ioim) (((struct bfa_ioim_s *)__ioim)->itnim->reqq) - -/* - * BFA completion callback for bfa_itnim_online(). - */ -void bfa_cb_itnim_online(void *itnim); - -/* - * BFA completion callback for bfa_itnim_offline(). - */ -void bfa_cb_itnim_offline(void *itnim); -void bfa_cb_itnim_tov_begin(void *itnim); -void bfa_cb_itnim_tov(void *itnim); - -/* - * BFA notification to FCS/driver for second level error recovery. - * Atleast one I/O request has timedout and target is unresponsive to - * repeated abort requests. Second level error recovery should be initiated - * by starting implicit logout and recovery procedures. - */ -void bfa_cb_itnim_sler(void *itnim); - -/* - * bfa ioim API functions - */ -struct bfa_ioim_s *bfa_ioim_alloc(struct bfa_s *bfa, - struct bfad_ioim_s *dio, - struct bfa_itnim_s *itnim, - u16 nsgles); - -void bfa_ioim_free(struct bfa_ioim_s *ioim); -void bfa_ioim_start(struct bfa_ioim_s *ioim); -bfa_status_t bfa_ioim_abort(struct bfa_ioim_s *ioim); -void bfa_ioim_delayed_comp(struct bfa_ioim_s *ioim, - bfa_boolean_t iotov); -/* - * I/O completion notification. - * - * @param[in] dio driver IO structure - * @param[in] io_status IO completion status - * @param[in] scsi_status SCSI status returned by target - * @param[in] sns_len SCSI sense length, 0 if none - * @param[in] sns_info SCSI sense data, if any - * @param[in] residue Residual length - * - * @return None - */ -void bfa_cb_ioim_done(void *bfad, struct bfad_ioim_s *dio, - enum bfi_ioim_status io_status, - u8 scsi_status, int sns_len, - u8 *sns_info, s32 residue); - -/* - * I/O good completion notification. - */ -void bfa_cb_ioim_good_comp(void *bfad, struct bfad_ioim_s *dio); - -/* - * I/O abort completion notification - */ -void bfa_cb_ioim_abort(void *bfad, struct bfad_ioim_s *dio); - -/* - * bfa tskim API functions - */ -struct bfa_tskim_s *bfa_tskim_alloc(struct bfa_s *bfa, - struct bfad_tskim_s *dtsk); -void bfa_tskim_free(struct bfa_tskim_s *tskim); -void bfa_tskim_start(struct bfa_tskim_s *tskim, - struct bfa_itnim_s *itnim, struct scsi_lun lun, - enum fcp_tm_cmnd tm, u8 t_secs); -void bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, - enum bfi_tskim_status tsk_status); - -void bfa_fcpim_lunmask_rp_update(struct bfa_s *bfa, wwn_t lp_wwn, - wwn_t rp_wwn, u16 rp_tag, u8 lp_tag); -bfa_status_t bfa_fcpim_lunmask_update(struct bfa_s *bfa, u32 on_off); -bfa_status_t bfa_fcpim_lunmask_query(struct bfa_s *bfa, void *buf); -bfa_status_t bfa_fcpim_lunmask_delete(struct bfa_s *bfa, u16 vf_id, - wwn_t *pwwn, wwn_t rpwwn, struct scsi_lun lun); -bfa_status_t bfa_fcpim_lunmask_add(struct bfa_s *bfa, u16 vf_id, - wwn_t *pwwn, wwn_t rpwwn, struct scsi_lun lun); -bfa_status_t bfa_fcpim_lunmask_clear(struct bfa_s *bfa); - -#endif /* __BFA_FCPIM_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.c deleted file mode 100644 index eaac57e1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.c +++ /dev/null @@ -1,1548 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * bfa_fcs.c BFA FCS main - */ - -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfa_fcs.h" -#include "bfa_fcbuild.h" - -BFA_TRC_FILE(FCS, FCS); - -/* - * FCS sub-modules - */ -struct bfa_fcs_mod_s { - void (*attach) (struct bfa_fcs_s *fcs); - void (*modinit) (struct bfa_fcs_s *fcs); - void (*modexit) (struct bfa_fcs_s *fcs); -}; - -#define BFA_FCS_MODULE(_mod) { _mod ## _modinit, _mod ## _modexit } - -static struct bfa_fcs_mod_s fcs_modules[] = { - { bfa_fcs_port_attach, NULL, NULL }, - { bfa_fcs_uf_attach, NULL, NULL }, - { bfa_fcs_fabric_attach, bfa_fcs_fabric_modinit, - bfa_fcs_fabric_modexit }, -}; - -/* - * fcs_api BFA FCS API - */ - -static void -bfa_fcs_exit_comp(void *fcs_cbarg) -{ - struct bfa_fcs_s *fcs = fcs_cbarg; - struct bfad_s *bfad = fcs->bfad; - - complete(&bfad->comp); -} - - - -/* - * fcs_api BFA FCS API - */ - -/* - * fcs attach -- called once to initialize data structures at driver attach time - */ -void -bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, struct bfad_s *bfad, - bfa_boolean_t min_cfg) -{ - int i; - struct bfa_fcs_mod_s *mod; - - fcs->bfa = bfa; - fcs->bfad = bfad; - fcs->min_cfg = min_cfg; - - bfa->fcs = BFA_TRUE; - fcbuild_init(); - - for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) { - mod = &fcs_modules[i]; - if (mod->attach) - mod->attach(fcs); - } -} - -/* - * fcs initialization, called once after bfa initialization is complete - */ -void -bfa_fcs_init(struct bfa_fcs_s *fcs) -{ - int i; - struct bfa_fcs_mod_s *mod; - - for (i = 0; i < sizeof(fcs_modules) / sizeof(fcs_modules[0]); i++) { - mod = &fcs_modules[i]; - if (mod->modinit) - mod->modinit(fcs); - } -} - -/* - * FCS update cfg - reset the pwwn/nwwn of fabric base logical port - * with values learned during bfa_init firmware GETATTR REQ. - */ -void -bfa_fcs_update_cfg(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric = &fcs->fabric; - struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg; - struct bfa_ioc_s *ioc = &fabric->fcs->bfa->ioc; - - port_cfg->nwwn = ioc->attr->nwwn; - port_cfg->pwwn = ioc->attr->pwwn; -} - -/* - * fcs pbc vport initialization - */ -void -bfa_fcs_pbc_vport_init(struct bfa_fcs_s *fcs) -{ - int i, npbc_vports; - struct bfi_pbc_vport_s pbc_vports[BFI_PBC_MAX_VPORTS]; - - /* Initialize pbc vports */ - if (!fcs->min_cfg) { - npbc_vports = - bfa_iocfc_get_pbc_vports(fcs->bfa, pbc_vports); - for (i = 0; i < npbc_vports; i++) - bfa_fcb_pbc_vport_create(fcs->bfa->bfad, pbc_vports[i]); - } -} - -/* - * brief - * FCS driver details initialization. - * - * param[in] fcs FCS instance - * param[in] driver_info Driver Details - * - * return None - */ -void -bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, - struct bfa_fcs_driver_info_s *driver_info) -{ - - fcs->driver_info = *driver_info; - - bfa_fcs_fabric_psymb_init(&fcs->fabric); -} - -/* - * brief - * FCS instance cleanup and exit. - * - * param[in] fcs FCS instance - * return None - */ -void -bfa_fcs_exit(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_mod_s *mod; - int nmods, i; - - bfa_wc_init(&fcs->wc, bfa_fcs_exit_comp, fcs); - - nmods = sizeof(fcs_modules) / sizeof(fcs_modules[0]); - - for (i = 0; i < nmods; i++) { - - mod = &fcs_modules[i]; - if (mod->modexit) { - bfa_wc_up(&fcs->wc); - mod->modexit(fcs); - } - } - - bfa_wc_wait(&fcs->wc); -} - - -/* - * Fabric module implementation. - */ - -#define BFA_FCS_FABRIC_RETRY_DELAY (2000) /* Milliseconds */ -#define BFA_FCS_FABRIC_CLEANUP_DELAY (10000) /* Milliseconds */ - -#define bfa_fcs_fabric_set_opertype(__fabric) do { \ - if (bfa_fcport_get_topology((__fabric)->fcs->bfa) \ - == BFA_PORT_TOPOLOGY_P2P) { \ - if (fabric->fab_type == BFA_FCS_FABRIC_SWITCHED) \ - (__fabric)->oper_type = BFA_PORT_TYPE_NPORT; \ - else \ - (__fabric)->oper_type = BFA_PORT_TYPE_P2P; \ - } else \ - (__fabric)->oper_type = BFA_PORT_TYPE_NLPORT; \ -} while (0) - -/* - * forward declarations - */ -static void bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_delay(void *cbarg); -static void bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_delete_comp(void *cbarg); -static void bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, - struct fchs_s *fchs, u16 len); -static void bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, - struct fchs_s *fchs, u16 len); -static void bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric); -static void bfa_fcs_fabric_flogiacc_comp(void *fcsarg, - struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rspfchs); -static u8 bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric); -static bfa_boolean_t bfa_fcs_fabric_is_bbscn_enabled( - struct bfa_fcs_fabric_s *fabric); - -static void bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -static void bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -/* - * Beginning state before fabric creation. - */ -static void -bfa_fcs_fabric_sm_uninit(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_CREATE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_created); - bfa_fcs_fabric_init(fabric); - bfa_fcs_lport_init(&fabric->bport, &fabric->bport.port_cfg); - break; - - case BFA_FCS_FABRIC_SM_LINK_UP: - case BFA_FCS_FABRIC_SM_LINK_DOWN: - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * Beginning state before fabric creation. - */ -static void -bfa_fcs_fabric_sm_created(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_START: - if (bfa_fcport_is_linkup(fabric->fcs->bfa)) { - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); - bfa_fcs_fabric_login(fabric); - } else - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - break; - - case BFA_FCS_FABRIC_SM_LINK_UP: - case BFA_FCS_FABRIC_SM_LINK_DOWN: - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * Link is down, awaiting LINK UP event from port. This is also the - * first state at fabric creation. - */ -static void -bfa_fcs_fabric_sm_linkdown(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_UP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); - bfa_fcs_fabric_login(fabric); - break; - - case BFA_FCS_FABRIC_SM_RETRY_OP: - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * FLOGI is in progress, awaiting FLOGI reply. - */ -static void -bfa_fcs_fabric_sm_flogi(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_CONT_OP: - - bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); - fabric->fab_type = BFA_FCS_FABRIC_SWITCHED; - - if (fabric->auth_reqd && fabric->is_auth) { - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth); - bfa_trc(fabric->fcs, event); - } else { - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); - bfa_fcs_fabric_notify_online(fabric); - } - break; - - case BFA_FCS_FABRIC_SM_RETRY_OP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi_retry); - bfa_timer_start(fabric->fcs->bfa, &fabric->delay_timer, - bfa_fcs_fabric_delay, fabric, - BFA_FCS_FABRIC_RETRY_DELAY); - break; - - case BFA_FCS_FABRIC_SM_LOOPBACK: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_loopback); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_fabric_set_opertype(fabric); - break; - - case BFA_FCS_FABRIC_SM_NO_FABRIC: - fabric->fab_type = BFA_FCS_FABRIC_N2N; - bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); - bfa_fcs_fabric_notify_online(fabric); - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_nofabric); - break; - - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - - -static void -bfa_fcs_fabric_sm_flogi_retry(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_DELAYED: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_flogi); - bfa_fcs_fabric_login(fabric); - break; - - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_timer_stop(&fabric->delay_timer); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_timer_stop(&fabric->delay_timer); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * Authentication is in progress, awaiting authentication results. - */ -static void -bfa_fcs_fabric_sm_auth(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_AUTH_FAILED: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - break; - - case BFA_FCS_FABRIC_SM_AUTH_SUCCESS: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_online); - bfa_fcs_fabric_notify_online(fabric); - break; - - case BFA_FCS_FABRIC_SM_PERF_EVFP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp); - break; - - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * Authentication failed - */ -void -bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_fcs_fabric_notify_offline(fabric); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * Port is in loopback mode. - */ -void -bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_fcs_fabric_notify_offline(fabric); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * There is no attached fabric - private loop or NPort-to-NPort topology. - */ -static void -bfa_fcs_fabric_sm_nofabric(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_fabric_notify_offline(fabric); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - case BFA_FCS_FABRIC_SM_NO_FABRIC: - bfa_trc(fabric->fcs, fabric->bb_credit); - bfa_fcport_set_tx_bbcredit(fabric->fcs->bfa, - fabric->bb_credit, - bfa_fcs_fabric_oper_bbscn(fabric)); - break; - - case BFA_FCS_FABRIC_SM_RETRY_OP: - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * Fabric is online - normal operating state. - */ -void -bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_linkdown); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_fabric_notify_offline(fabric); - break; - - case BFA_FCS_FABRIC_SM_DELETE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_deleting); - bfa_fcs_fabric_delete(fabric); - break; - - case BFA_FCS_FABRIC_SM_AUTH_FAILED: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_auth_failed); - bfa_sm_send_event(fabric->lps, BFA_LPS_SM_OFFLINE); - break; - - case BFA_FCS_FABRIC_SM_AUTH_SUCCESS: - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * Exchanging virtual fabric parameters. - */ -static void -bfa_fcs_fabric_sm_evfp(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_CONT_OP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_evfp_done); - break; - - case BFA_FCS_FABRIC_SM_ISOLATE: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_isolated); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - -/* - * EVFP exchange complete and VFT tagging is enabled. - */ -static void -bfa_fcs_fabric_sm_evfp_done(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); -} - -/* - * Port is isolated after EVFP exchange due to VF_ID mismatch (N and F). - */ -static void -bfa_fcs_fabric_sm_isolated(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - struct bfad_s *bfad = (struct bfad_s *)fabric->fcs->bfad; - char pwwn_ptr[BFA_STRING_32]; - - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - wwn2str(pwwn_ptr, fabric->bport.port_cfg.pwwn); - - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Port is isolated due to VF_ID mismatch. " - "PWWN: %s Port VF_ID: %04x switch port VF_ID: %04x.", - pwwn_ptr, fabric->fcs->port_vfid, - fabric->event_arg.swp_vfid); -} - -/* - * Fabric is being deleted, awaiting vport delete completions. - */ -static void -bfa_fcs_fabric_sm_deleting(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, event); - - switch (event) { - case BFA_FCS_FABRIC_SM_DELCOMP: - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); - bfa_wc_down(&fabric->fcs->wc); - break; - - case BFA_FCS_FABRIC_SM_LINK_UP: - break; - - case BFA_FCS_FABRIC_SM_LINK_DOWN: - bfa_fcs_fabric_notify_offline(fabric); - break; - - default: - bfa_sm_fault(fabric->fcs, event); - } -} - - - -/* - * fcs_fabric_private fabric private functions - */ - -static void -bfa_fcs_fabric_init(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg; - - port_cfg->roles = BFA_LPORT_ROLE_FCP_IM; - port_cfg->nwwn = fabric->fcs->bfa->ioc.attr->nwwn; - port_cfg->pwwn = fabric->fcs->bfa->ioc.attr->pwwn; -} - -/* - * Port Symbolic Name Creation for base port. - */ -void -bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_lport_cfg_s *port_cfg = &fabric->bport.port_cfg; - char model[BFA_ADAPTER_MODEL_NAME_LEN] = {0}; - struct bfa_fcs_driver_info_s *driver_info = &fabric->fcs->driver_info; - - bfa_ioc_get_adapter_model(&fabric->fcs->bfa->ioc, model); - - /* Model name/number */ - strncpy((char *)&port_cfg->sym_name, model, - BFA_FCS_PORT_SYMBNAME_MODEL_SZ); - strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - - /* Driver Version */ - strncat((char *)&port_cfg->sym_name, (char *)driver_info->version, - BFA_FCS_PORT_SYMBNAME_VERSION_SZ); - strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - - /* Host machine name */ - strncat((char *)&port_cfg->sym_name, - (char *)driver_info->host_machine_name, - BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ); - strncat((char *)&port_cfg->sym_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - - /* - * Host OS Info : - * If OS Patch Info is not there, do not truncate any bytes from the - * OS name string and instead copy the entire OS info string (64 bytes). - */ - if (driver_info->host_os_patch[0] == '\0') { - strncat((char *)&port_cfg->sym_name, - (char *)driver_info->host_os_name, - BFA_FCS_OS_STR_LEN); - strncat((char *)&port_cfg->sym_name, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - } else { - strncat((char *)&port_cfg->sym_name, - (char *)driver_info->host_os_name, - BFA_FCS_PORT_SYMBNAME_OSINFO_SZ); - strncat((char *)&port_cfg->sym_name, - BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - - /* Append host OS Patch Info */ - strncat((char *)&port_cfg->sym_name, - (char *)driver_info->host_os_patch, - BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ); - } - - /* null terminate */ - port_cfg->sym_name.symname[BFA_SYMNAME_MAXLEN - 1] = 0; -} - -/* - * bfa lps login completion callback - */ -void -bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status) -{ - struct bfa_fcs_fabric_s *fabric = uarg; - - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_trc(fabric->fcs, status); - - switch (status) { - case BFA_STATUS_OK: - fabric->stats.flogi_accepts++; - break; - - case BFA_STATUS_INVALID_MAC: - /* Only for CNA */ - fabric->stats.flogi_acc_err++; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); - - return; - - case BFA_STATUS_EPROTOCOL: - switch (fabric->lps->ext_status) { - case BFA_EPROTO_BAD_ACCEPT: - fabric->stats.flogi_acc_err++; - break; - - case BFA_EPROTO_UNKNOWN_RSP: - fabric->stats.flogi_unknown_rsp++; - break; - - default: - break; - } - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); - - return; - - case BFA_STATUS_FABRIC_RJT: - fabric->stats.flogi_rejects++; - if (fabric->lps->lsrjt_rsn == FC_LS_RJT_RSN_LOGICAL_ERROR && - fabric->lps->lsrjt_expl == FC_LS_RJT_EXP_NO_ADDL_INFO) - fabric->fcs->bbscn_flogi_rjt = BFA_TRUE; - - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); - return; - - default: - fabric->stats.flogi_rsp_err++; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_RETRY_OP); - return; - } - - fabric->bb_credit = fabric->lps->pr_bbcred; - bfa_trc(fabric->fcs, fabric->bb_credit); - - if (!(fabric->lps->brcd_switch)) - fabric->fabric_name = fabric->lps->pr_nwwn; - - /* - * Check port type. It should be 1 = F-port. - */ - if (fabric->lps->fport) { - fabric->bport.pid = fabric->lps->lp_pid; - fabric->is_npiv = fabric->lps->npiv_en; - fabric->is_auth = fabric->lps->auth_req; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_CONT_OP); - } else { - /* - * Nport-2-Nport direct attached - */ - fabric->bport.port_topo.pn2n.rem_port_wwn = - fabric->lps->pr_pwwn; - fabric->fab_type = BFA_FCS_FABRIC_N2N; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); - } - - bfa_trc(fabric->fcs, fabric->bport.pid); - bfa_trc(fabric->fcs, fabric->is_npiv); - bfa_trc(fabric->fcs, fabric->is_auth); -} -/* - * Allocate and send FLOGI. - */ -static void -bfa_fcs_fabric_login(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_s *bfa = fabric->fcs->bfa; - struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg; - u8 alpa = 0, bb_scn = 0; - - if (bfa_fcport_get_topology(bfa) == BFA_PORT_TOPOLOGY_LOOP) - alpa = bfa_fcport_get_myalpa(bfa); - - if (bfa_fcs_fabric_is_bbscn_enabled(fabric) && - (!fabric->fcs->bbscn_flogi_rjt)) - bb_scn = BFA_FCS_PORT_DEF_BB_SCN; - - bfa_lps_flogi(fabric->lps, fabric, alpa, bfa_fcport_get_maxfrsize(bfa), - pcfg->pwwn, pcfg->nwwn, fabric->auth_reqd, bb_scn); - - fabric->stats.flogi_sent++; -} - -static void -bfa_fcs_fabric_notify_online(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcs_vport_s *vport; - struct list_head *qe, *qen; - - bfa_trc(fabric->fcs, fabric->fabric_name); - - bfa_fcs_fabric_set_opertype(fabric); - fabric->stats.fabric_onlines++; - - /* - * notify online event to base and then virtual ports - */ - bfa_fcs_lport_online(&fabric->bport); - - list_for_each_safe(qe, qen, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *) qe; - bfa_fcs_vport_online(vport); - } -} - -static void -bfa_fcs_fabric_notify_offline(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcs_vport_s *vport; - struct list_head *qe, *qen; - - bfa_trc(fabric->fcs, fabric->fabric_name); - fabric->stats.fabric_offlines++; - - /* - * notify offline event first to vports and then base port. - */ - list_for_each_safe(qe, qen, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *) qe; - bfa_fcs_vport_offline(vport); - } - - bfa_fcs_lport_offline(&fabric->bport); - - fabric->fabric_name = 0; - fabric->fabric_ip_addr[0] = 0; -} - -static void -bfa_fcs_fabric_delay(void *cbarg) -{ - struct bfa_fcs_fabric_s *fabric = cbarg; - - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELAYED); -} - -/* - * Computes operating BB_SCN value - */ -static u8 -bfa_fcs_fabric_oper_bbscn(struct bfa_fcs_fabric_s *fabric) -{ - u8 pr_bbscn = fabric->lps->pr_bbscn; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa); - - if (!(fcport->cfg.bb_scn_state && pr_bbscn)) - return 0; - - /* return max of local/remote bb_scn values */ - return ((pr_bbscn > BFA_FCS_PORT_DEF_BB_SCN) ? - pr_bbscn : BFA_FCS_PORT_DEF_BB_SCN); -} - -/* - * Check if BB_SCN can be enabled. - */ -static bfa_boolean_t -bfa_fcs_fabric_is_bbscn_enabled(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fabric->fcs->bfa); - - if (bfa_ioc_get_fcmode(&fabric->fcs->bfa->ioc) && - fcport->cfg.bb_scn_state && - !bfa_fcport_is_qos_enabled(fabric->fcs->bfa) && - !bfa_fcport_is_trunk_enabled(fabric->fcs->bfa)) - return BFA_TRUE; - else - return BFA_FALSE; -} - -/* - * Delete all vports and wait for vport delete completions. - */ -static void -bfa_fcs_fabric_delete(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_fcs_vport_s *vport; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *) qe; - bfa_fcs_vport_fcs_delete(vport); - } - - bfa_fcs_lport_delete(&fabric->bport); - bfa_wc_wait(&fabric->wc); -} - -static void -bfa_fcs_fabric_delete_comp(void *cbarg) -{ - struct bfa_fcs_fabric_s *fabric = cbarg; - - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELCOMP); -} - -/* - * fcs_fabric_public fabric public functions - */ - -/* - * Attach time initialization. - */ -void -bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - fabric = &fcs->fabric; - memset(fabric, 0, sizeof(struct bfa_fcs_fabric_s)); - - /* - * Initialize base fabric. - */ - fabric->fcs = fcs; - INIT_LIST_HEAD(&fabric->vport_q); - INIT_LIST_HEAD(&fabric->vf_q); - fabric->lps = bfa_lps_alloc(fcs->bfa); - WARN_ON(!fabric->lps); - - /* - * Initialize fabric delete completion handler. Fabric deletion is - * complete when the last vport delete is complete. - */ - bfa_wc_init(&fabric->wc, bfa_fcs_fabric_delete_comp, fabric); - bfa_wc_up(&fabric->wc); /* For the base port */ - - bfa_sm_set_state(fabric, bfa_fcs_fabric_sm_uninit); - bfa_fcs_lport_attach(&fabric->bport, fabric->fcs, FC_VF_ID_NULL, NULL); -} - -void -bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs) -{ - bfa_sm_send_event(&fcs->fabric, BFA_FCS_FABRIC_SM_CREATE); - bfa_trc(fcs, 0); -} - -/* - * Module cleanup - */ -void -bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - bfa_trc(fcs, 0); - - /* - * Cleanup base fabric. - */ - fabric = &fcs->fabric; - bfa_lps_delete(fabric->lps); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_DELETE); -} - -/* - * Fabric module start -- kick starts FCS actions - */ -void -bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs) -{ - struct bfa_fcs_fabric_s *fabric; - - bfa_trc(fcs, 0); - fabric = &fcs->fabric; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_START); -} - - -/* - * Link up notification from BFA physical port module. - */ -void -bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_UP); -} - -/* - * Link down notification from BFA physical port module. - */ -void -bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric) -{ - bfa_trc(fabric->fcs, fabric->bport.port_cfg.pwwn); - fabric->fcs->bbscn_flogi_rjt = BFA_FALSE; - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LINK_DOWN); -} - -/* - * A child vport is being created in the fabric. - * - * Call from vport module at vport creation. A list of base port and vports - * belonging to a fabric is maintained to propagate link events. - * - * param[in] fabric - Fabric instance. This can be a base fabric or vf. - * param[in] vport - Vport being created. - * - * @return None (always succeeds) - */ -void -bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, - struct bfa_fcs_vport_s *vport) -{ - /* - * - add vport to fabric's vport_q - */ - bfa_trc(fabric->fcs, fabric->vf_id); - - list_add_tail(&vport->qe, &fabric->vport_q); - fabric->num_vports++; - bfa_wc_up(&fabric->wc); -} - -/* - * A child vport is being deleted from fabric. - * - * Vport is being deleted. - */ -void -bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, - struct bfa_fcs_vport_s *vport) -{ - list_del(&vport->qe); - fabric->num_vports--; - bfa_wc_down(&fabric->wc); -} - - -/* - * Lookup for a vport within a fabric given its pwwn - */ -struct bfa_fcs_vport_s * -bfa_fcs_fabric_vport_lookup(struct bfa_fcs_fabric_s *fabric, wwn_t pwwn) -{ - struct bfa_fcs_vport_s *vport; - struct list_head *qe; - - list_for_each(qe, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *) qe; - if (bfa_fcs_lport_get_pwwn(&vport->lport) == pwwn) - return vport; - } - - return NULL; -} - - -/* - * Get OUI of the attached switch. - * - * Note : Use of this function should be avoided as much as possible. - * This function should be used only if there is any requirement -* to check for FOS version below 6.3. - * To check if the attached fabric is a brocade fabric, use - * bfa_lps_is_brcd_fabric() which works for FOS versions 6.3 - * or above only. - */ - -u16 -bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric) -{ - wwn_t fab_nwwn; - u8 *tmp; - u16 oui; - - fab_nwwn = fabric->lps->pr_nwwn; - - tmp = (u8 *)&fab_nwwn; - oui = (tmp[3] << 8) | tmp[4]; - - return oui; -} -/* - * Unsolicited frame receive handling. - */ -void -bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs, - u16 len) -{ - u32 pid = fchs->d_id; - struct bfa_fcs_vport_s *vport; - struct list_head *qe; - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - struct fc_logi_s *flogi = (struct fc_logi_s *) els_cmd; - - bfa_trc(fabric->fcs, len); - bfa_trc(fabric->fcs, pid); - - /* - * Look for our own FLOGI frames being looped back. This means an - * external loopback cable is in place. Our own FLOGI frames are - * sometimes looped back when switch port gets temporarily bypassed. - */ - if ((pid == bfa_ntoh3b(FC_FABRIC_PORT)) && - (els_cmd->els_code == FC_ELS_FLOGI) && - (flogi->port_name == bfa_fcs_lport_get_pwwn(&fabric->bport))) { - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_LOOPBACK); - return; - } - - /* - * FLOGI/EVFP exchanges should be consumed by base fabric. - */ - if (fchs->d_id == bfa_hton3b(FC_FABRIC_PORT)) { - bfa_trc(fabric->fcs, pid); - bfa_fcs_fabric_process_uf(fabric, fchs, len); - return; - } - - if (fabric->bport.pid == pid) { - /* - * All authentication frames should be routed to auth - */ - bfa_trc(fabric->fcs, els_cmd->els_code); - if (els_cmd->els_code == FC_ELS_AUTH) { - bfa_trc(fabric->fcs, els_cmd->els_code); - return; - } - - bfa_trc(fabric->fcs, *(u8 *) ((u8 *) fchs)); - bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len); - return; - } - - /* - * look for a matching local port ID - */ - list_for_each(qe, &fabric->vport_q) { - vport = (struct bfa_fcs_vport_s *) qe; - if (vport->lport.pid == pid) { - bfa_fcs_lport_uf_recv(&vport->lport, fchs, len); - return; - } - } - bfa_trc(fabric->fcs, els_cmd->els_code); - bfa_fcs_lport_uf_recv(&fabric->bport, fchs, len); -} - -/* - * Unsolicited frames to be processed by fabric. - */ -static void -bfa_fcs_fabric_process_uf(struct bfa_fcs_fabric_s *fabric, struct fchs_s *fchs, - u16 len) -{ - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - bfa_trc(fabric->fcs, els_cmd->els_code); - - switch (els_cmd->els_code) { - case FC_ELS_FLOGI: - bfa_fcs_fabric_process_flogi(fabric, fchs, len); - break; - - default: - /* - * need to generate a LS_RJT - */ - break; - } -} - -/* - * Process incoming FLOGI - */ -static void -bfa_fcs_fabric_process_flogi(struct bfa_fcs_fabric_s *fabric, - struct fchs_s *fchs, u16 len) -{ - struct fc_logi_s *flogi = (struct fc_logi_s *) (fchs + 1); - struct bfa_fcs_lport_s *bport = &fabric->bport; - - bfa_trc(fabric->fcs, fchs->s_id); - - fabric->stats.flogi_rcvd++; - /* - * Check port type. It should be 0 = n-port. - */ - if (flogi->csp.port_type) { - /* - * @todo: may need to send a LS_RJT - */ - bfa_trc(fabric->fcs, flogi->port_name); - fabric->stats.flogi_rejected++; - return; - } - - fabric->bb_credit = be16_to_cpu(flogi->csp.bbcred); - fabric->lps->pr_bbscn = (be16_to_cpu(flogi->csp.rxsz) >> 12); - bport->port_topo.pn2n.rem_port_wwn = flogi->port_name; - bport->port_topo.pn2n.reply_oxid = fchs->ox_id; - - /* - * Send a Flogi Acc - */ - bfa_fcs_fabric_send_flogi_acc(fabric); - bfa_sm_send_event(fabric, BFA_FCS_FABRIC_SM_NO_FABRIC); -} - -static void -bfa_fcs_fabric_send_flogi_acc(struct bfa_fcs_fabric_s *fabric) -{ - struct bfa_lport_cfg_s *pcfg = &fabric->bport.port_cfg; - struct bfa_fcs_lport_n2n_s *n2n_port = &fabric->bport.port_topo.pn2n; - struct bfa_s *bfa = fabric->fcs->bfa; - struct bfa_fcxp_s *fcxp; - u16 reqlen; - struct fchs_s fchs; - - fcxp = bfa_fcs_fcxp_alloc(fabric->fcs); - /* - * Do not expect this failure -- expect remote node to retry - */ - if (!fcxp) - return; - - reqlen = fc_flogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_hton3b(FC_FABRIC_PORT), - n2n_port->reply_oxid, pcfg->pwwn, - pcfg->nwwn, - bfa_fcport_get_maxfrsize(bfa), - bfa_fcport_get_rx_bbcredit(bfa), - bfa_fcs_fabric_oper_bbscn(fabric)); - - bfa_fcxp_send(fcxp, NULL, fabric->vf_id, fabric->lps->bfa_tag, - BFA_FALSE, FC_CLASS_3, - reqlen, &fchs, bfa_fcs_fabric_flogiacc_comp, fabric, - FC_MAX_PDUSZ, 0); -} - -/* - * Flogi Acc completion callback. - */ -static void -bfa_fcs_fabric_flogiacc_comp(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t status, u32 rsp_len, - u32 resid_len, struct fchs_s *rspfchs) -{ - struct bfa_fcs_fabric_s *fabric = cbarg; - - bfa_trc(fabric->fcs, status); -} - - -/* - * Send AEN notification - */ -static void -bfa_fcs_fabric_aen_post(struct bfa_fcs_lport_s *port, - enum bfa_port_aen_event event) -{ - struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad; - struct bfa_aen_entry_s *aen_entry; - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - aen_entry->aen_data.port.pwwn = bfa_fcs_lport_get_pwwn(port); - aen_entry->aen_data.port.fwwn = bfa_fcs_lport_get_fabric_name(port); - - /* Send the AEN notification */ - bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq, - BFA_AEN_CAT_PORT, event); -} - -/* - * - * @param[in] fabric - fabric - * @param[in] wwn_t - new fabric name - * - * @return - none - */ -void -bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, - wwn_t fabric_name) -{ - struct bfad_s *bfad = (struct bfad_s *)fabric->fcs->bfad; - char pwwn_ptr[BFA_STRING_32]; - char fwwn_ptr[BFA_STRING_32]; - - bfa_trc(fabric->fcs, fabric_name); - - if (fabric->fabric_name == 0) { - /* - * With BRCD switches, we don't get Fabric Name in FLOGI. - * Don't generate a fabric name change event in this case. - */ - fabric->fabric_name = fabric_name; - } else { - fabric->fabric_name = fabric_name; - wwn2str(pwwn_ptr, bfa_fcs_lport_get_pwwn(&fabric->bport)); - wwn2str(fwwn_ptr, - bfa_fcs_lport_get_fabric_name(&fabric->bport)); - BFA_LOG(KERN_WARNING, bfad, bfa_log_level, - "Base port WWN = %s Fabric WWN = %s\n", - pwwn_ptr, fwwn_ptr); - bfa_fcs_fabric_aen_post(&fabric->bport, - BFA_PORT_AEN_FABRIC_NAME_CHANGE); - } -} - -/* - * Returns FCS vf structure for a given vf_id. - * - * param[in] vf_id - VF_ID - * - * return - * If lookup succeeds, retuns fcs vf object, otherwise returns NULL - */ -bfa_fcs_vf_t * -bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id) -{ - bfa_trc(fcs, vf_id); - if (vf_id == FC_VF_ID_NULL) - return &fcs->fabric; - - return NULL; -} - -/* - * Return the list of local logical ports present in the given VF. - * - * @param[in] vf vf for which logical ports are returned - * @param[out] lpwwn returned logical port wwn list - * @param[in,out] nlports in:size of lpwwn list; - * out:total elements present, - * actual elements returned is limited by the size - */ -void -bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t lpwwn[], int *nlports) -{ - struct list_head *qe; - struct bfa_fcs_vport_s *vport; - int i = 0; - struct bfa_fcs_s *fcs; - - if (vf == NULL || lpwwn == NULL || *nlports == 0) - return; - - fcs = vf->fcs; - - bfa_trc(fcs, vf->vf_id); - bfa_trc(fcs, (uint32_t) *nlports); - - lpwwn[i++] = vf->bport.port_cfg.pwwn; - - list_for_each(qe, &vf->vport_q) { - if (i >= *nlports) - break; - - vport = (struct bfa_fcs_vport_s *) qe; - lpwwn[i++] = vport->lport.port_cfg.pwwn; - } - - bfa_trc(fcs, i); - *nlports = i; -} - -/* - * BFA FCS PPORT ( physical port) - */ -static void -bfa_fcs_port_event_handler(void *cbarg, enum bfa_port_linkstate event) -{ - struct bfa_fcs_s *fcs = cbarg; - - bfa_trc(fcs, event); - - switch (event) { - case BFA_PORT_LINKUP: - bfa_fcs_fabric_link_up(&fcs->fabric); - break; - - case BFA_PORT_LINKDOWN: - bfa_fcs_fabric_link_down(&fcs->fabric); - break; - - default: - WARN_ON(1); - } -} - -void -bfa_fcs_port_attach(struct bfa_fcs_s *fcs) -{ - bfa_fcport_event_register(fcs->bfa, bfa_fcs_port_event_handler, fcs); -} - -/* - * BFA FCS UF ( Unsolicited Frames) - */ - -/* - * BFA callback for unsolicited frame receive handler. - * - * @param[in] cbarg callback arg for receive handler - * @param[in] uf unsolicited frame descriptor - * - * @return None - */ -static void -bfa_fcs_uf_recv(void *cbarg, struct bfa_uf_s *uf) -{ - struct bfa_fcs_s *fcs = (struct bfa_fcs_s *) cbarg; - struct fchs_s *fchs = bfa_uf_get_frmbuf(uf); - u16 len = bfa_uf_get_frmlen(uf); - struct fc_vft_s *vft; - struct bfa_fcs_fabric_s *fabric; - - /* - * check for VFT header - */ - if (fchs->routing == FC_RTG_EXT_HDR && - fchs->cat_info == FC_CAT_VFT_HDR) { - bfa_stats(fcs, uf.tagged); - vft = bfa_uf_get_frmbuf(uf); - if (fcs->port_vfid == vft->vf_id) - fabric = &fcs->fabric; - else - fabric = bfa_fcs_vf_lookup(fcs, (u16) vft->vf_id); - - /* - * drop frame if vfid is unknown - */ - if (!fabric) { - WARN_ON(1); - bfa_stats(fcs, uf.vfid_unknown); - bfa_uf_free(uf); - return; - } - - /* - * skip vft header - */ - fchs = (struct fchs_s *) (vft + 1); - len -= sizeof(struct fc_vft_s); - - bfa_trc(fcs, vft->vf_id); - } else { - bfa_stats(fcs, uf.untagged); - fabric = &fcs->fabric; - } - - bfa_trc(fcs, ((u32 *) fchs)[0]); - bfa_trc(fcs, ((u32 *) fchs)[1]); - bfa_trc(fcs, ((u32 *) fchs)[2]); - bfa_trc(fcs, ((u32 *) fchs)[3]); - bfa_trc(fcs, ((u32 *) fchs)[4]); - bfa_trc(fcs, ((u32 *) fchs)[5]); - bfa_trc(fcs, len); - - bfa_fcs_fabric_uf_recv(fabric, fchs, len); - bfa_uf_free(uf); -} - -void -bfa_fcs_uf_attach(struct bfa_fcs_s *fcs) -{ - bfa_uf_recv_register(fcs->bfa, bfa_fcs_uf_recv, fcs); -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.h deleted file mode 100644 index e75e07d2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs.h +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_FCS_H__ -#define __BFA_FCS_H__ - -#include "bfa_cs.h" -#include "bfa_defs.h" -#include "bfa_defs_fcs.h" -#include "bfa_modules.h" -#include "bfa_fc.h" - -#define BFA_FCS_OS_STR_LEN 64 - -/* - * lps_pvt BFA LPS private functions - */ - -enum bfa_lps_event { - BFA_LPS_SM_LOGIN = 1, /* login request from user */ - BFA_LPS_SM_LOGOUT = 2, /* logout request from user */ - BFA_LPS_SM_FWRSP = 3, /* f/w response to login/logout */ - BFA_LPS_SM_RESUME = 4, /* space present in reqq queue */ - BFA_LPS_SM_DELETE = 5, /* lps delete from user */ - BFA_LPS_SM_OFFLINE = 6, /* Link is offline */ - BFA_LPS_SM_RX_CVL = 7, /* Rx clear virtual link */ - BFA_LPS_SM_SET_N2N_PID = 8, /* Set assigned PID for n2n */ -}; - - -/* - * !!! Only append to the enums defined here to avoid any versioning - * !!! needed between trace utility and driver version - */ -enum { - BFA_TRC_FCS_FCS = 1, - BFA_TRC_FCS_PORT = 2, - BFA_TRC_FCS_RPORT = 3, - BFA_TRC_FCS_FCPIM = 4, -}; - - -struct bfa_fcs_s; - -#define __fcs_min_cfg(__fcs) ((__fcs)->min_cfg) - -#define BFA_FCS_BRCD_SWITCH_OUI 0x051e -#define N2N_LOCAL_PID 0x010000 -#define N2N_REMOTE_PID 0x020000 -#define BFA_FCS_RETRY_TIMEOUT 2000 -#define BFA_FCS_PID_IS_WKA(pid) ((bfa_ntoh3b(pid) > 0xFFF000) ? 1 : 0) - - - -struct bfa_fcs_lport_ns_s { - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; - struct bfa_fcs_lport_s *port; /* parent port */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; -}; - - -struct bfa_fcs_lport_scn_s { - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; - struct bfa_fcs_lport_s *port; /* parent port */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; -}; - - -struct bfa_fcs_lport_fdmi_s { - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; - struct bfa_fcs_lport_ms_s *ms; /* parent ms */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; - u8 retry_cnt; /* retry count */ - u8 rsvd[3]; -}; - - -struct bfa_fcs_lport_ms_s { - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; - struct bfa_fcs_lport_s *port; /* parent port */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; - struct bfa_fcs_lport_fdmi_s fdmi; /* FDMI component of MS */ - u8 retry_cnt; /* retry count */ - u8 rsvd[3]; -}; - - -struct bfa_fcs_lport_fab_s { - struct bfa_fcs_lport_ns_s ns; /* NS component of port */ - struct bfa_fcs_lport_scn_s scn; /* scn component of port */ - struct bfa_fcs_lport_ms_s ms; /* MS component of port */ -}; - -#define MAX_ALPA_COUNT 127 - -struct bfa_fcs_lport_loop_s { - u8 num_alpa; /* Num of ALPA entries in the map */ - u8 alpa_pos_map[MAX_ALPA_COUNT]; /* ALPA Positional - *Map */ - struct bfa_fcs_lport_s *port; /* parent port */ -}; - -struct bfa_fcs_lport_n2n_s { - u32 rsvd; - __be16 reply_oxid; /* ox_id from the req flogi to be - *used in flogi acc */ - wwn_t rem_port_wwn; /* Attached port's wwn */ -}; - - -union bfa_fcs_lport_topo_u { - struct bfa_fcs_lport_fab_s pfab; - struct bfa_fcs_lport_loop_s ploop; - struct bfa_fcs_lport_n2n_s pn2n; -}; - - -struct bfa_fcs_lport_s { - struct list_head qe; /* used by port/vport */ - bfa_sm_t sm; /* state machine */ - struct bfa_fcs_fabric_s *fabric; /* parent fabric */ - struct bfa_lport_cfg_s port_cfg; /* port configuration */ - struct bfa_timer_s link_timer; /* timer for link offline */ - u32 pid:24; /* FC address */ - u8 lp_tag; /* lport tag */ - u16 num_rports; /* Num of r-ports */ - struct list_head rport_q; /* queue of discovered r-ports */ - struct bfa_fcs_s *fcs; /* FCS instance */ - union bfa_fcs_lport_topo_u port_topo; /* fabric/loop/n2n details */ - struct bfad_port_s *bfad_port; /* driver peer instance */ - struct bfa_fcs_vport_s *vport; /* NULL for base ports */ - struct bfa_fcxp_s *fcxp; - struct bfa_fcxp_wqe_s fcxp_wqe; - struct bfa_lport_stats_s stats; - struct bfa_wc_s wc; /* waiting counter for events */ -}; -#define BFA_FCS_GET_HAL_FROM_PORT(port) (port->fcs->bfa) -#define BFA_FCS_GET_NS_FROM_PORT(port) (&port->port_topo.pfab.ns) -#define BFA_FCS_GET_SCN_FROM_PORT(port) (&port->port_topo.pfab.scn) -#define BFA_FCS_GET_MS_FROM_PORT(port) (&port->port_topo.pfab.ms) -#define BFA_FCS_GET_FDMI_FROM_PORT(port) (&port->port_topo.pfab.ms.fdmi) -#define BFA_FCS_VPORT_IS_INITIATOR_MODE(port) \ - (port->port_cfg.roles & BFA_LPORT_ROLE_FCP_IM) - -/* - * forward declaration - */ -struct bfad_vf_s; - -enum bfa_fcs_fabric_type { - BFA_FCS_FABRIC_UNKNOWN = 0, - BFA_FCS_FABRIC_SWITCHED = 1, - BFA_FCS_FABRIC_N2N = 2, -}; - - -struct bfa_fcs_fabric_s { - struct list_head qe; /* queue element */ - bfa_sm_t sm; /* state machine */ - struct bfa_fcs_s *fcs; /* FCS instance */ - struct bfa_fcs_lport_s bport; /* base logical port */ - enum bfa_fcs_fabric_type fab_type; /* fabric type */ - enum bfa_port_type oper_type; /* current link topology */ - u8 is_vf; /* is virtual fabric? */ - u8 is_npiv; /* is NPIV supported ? */ - u8 is_auth; /* is Security/Auth supported ? */ - u16 bb_credit; /* BB credit from fabric */ - u16 vf_id; /* virtual fabric ID */ - u16 num_vports; /* num vports */ - u16 rsvd; - struct list_head vport_q; /* queue of virtual ports */ - struct list_head vf_q; /* queue of virtual fabrics */ - struct bfad_vf_s *vf_drv; /* driver vf structure */ - struct bfa_timer_s link_timer; /* Link Failure timer. Vport */ - wwn_t fabric_name; /* attached fabric name */ - bfa_boolean_t auth_reqd; /* authentication required */ - struct bfa_timer_s delay_timer; /* delay timer */ - union { - u16 swp_vfid;/* switch port VF id */ - } event_arg; - struct bfa_wc_s wc; /* wait counter for delete */ - struct bfa_vf_stats_s stats; /* fabric/vf stats */ - struct bfa_lps_s *lps; /* lport login services */ - u8 fabric_ip_addr[BFA_FCS_FABRIC_IPADDR_SZ]; - /* attached fabric's ip addr */ -}; - -#define bfa_fcs_fabric_npiv_capable(__f) ((__f)->is_npiv) -#define bfa_fcs_fabric_is_switched(__f) \ - ((__f)->fab_type == BFA_FCS_FABRIC_SWITCHED) - -/* - * The design calls for a single implementation of base fabric and vf. - */ -#define bfa_fcs_vf_t struct bfa_fcs_fabric_s - -struct bfa_vf_event_s { - u32 undefined; -}; - -struct bfa_fcs_s; -struct bfa_fcs_fabric_s; - -/* - * @todo : need to move to a global config file. - * Maximum Rports supported per port (physical/logical). - */ -#define BFA_FCS_MAX_RPORTS_SUPP 256 /* @todo : tentative value */ - -#define bfa_fcs_lport_t struct bfa_fcs_lport_s - -/* - * Symbolic Name related defines - * Total bytes 255. - * Physical Port's symbolic name 128 bytes. - * For Vports, Vport's symbolic name is appended to the Physical port's - * Symbolic Name. - * - * Physical Port's symbolic name Format : (Total 128 bytes) - * Adapter Model number/name : 12 bytes - * Driver Version : 10 bytes - * Host Machine Name : 30 bytes - * Host OS Info : 48 bytes - * Host OS PATCH Info : 16 bytes - * ( remaining 12 bytes reserved to be used for separator) - */ -#define BFA_FCS_PORT_SYMBNAME_SEPARATOR " | " - -#define BFA_FCS_PORT_SYMBNAME_MODEL_SZ 12 -#define BFA_FCS_PORT_SYMBNAME_VERSION_SZ 10 -#define BFA_FCS_PORT_SYMBNAME_MACHINENAME_SZ 30 -#define BFA_FCS_PORT_SYMBNAME_OSINFO_SZ 48 -#define BFA_FCS_PORT_SYMBNAME_OSPATCH_SZ 16 - -/* bb_scn value in 2^bb_scn */ -#define BFA_FCS_PORT_DEF_BB_SCN 3 - -/* - * Get FC port ID for a logical port. - */ -#define bfa_fcs_lport_get_fcid(_lport) ((_lport)->pid) -#define bfa_fcs_lport_get_pwwn(_lport) ((_lport)->port_cfg.pwwn) -#define bfa_fcs_lport_get_nwwn(_lport) ((_lport)->port_cfg.nwwn) -#define bfa_fcs_lport_get_psym_name(_lport) ((_lport)->port_cfg.sym_name) -#define bfa_fcs_lport_is_initiator(_lport) \ - ((_lport)->port_cfg.roles & BFA_LPORT_ROLE_FCP_IM) -#define bfa_fcs_lport_get_nrports(_lport) \ - ((_lport) ? (_lport)->num_rports : 0) - -static inline struct bfad_port_s * -bfa_fcs_lport_get_drvport(struct bfa_fcs_lport_s *port) -{ - return port->bfad_port; -} - -#define bfa_fcs_lport_get_opertype(_lport) ((_lport)->fabric->oper_type) -#define bfa_fcs_lport_get_fabric_name(_lport) ((_lport)->fabric->fabric_name) -#define bfa_fcs_lport_get_fabric_ipaddr(_lport) \ - ((_lport)->fabric->fabric_ip_addr) - -/* - * bfa fcs port public functions - */ - -bfa_boolean_t bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port); -struct bfa_fcs_lport_s *bfa_fcs_get_base_port(struct bfa_fcs_s *fcs); -void bfa_fcs_lport_get_rports(struct bfa_fcs_lport_s *port, - wwn_t rport_wwns[], int *nrports); - -wwn_t bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn, - int index, int nrports, bfa_boolean_t bwwn); - -struct bfa_fcs_lport_s *bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, - u16 vf_id, wwn_t lpwwn); - -void bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port, - struct bfa_lport_info_s *port_info); -void bfa_fcs_lport_get_attr(struct bfa_fcs_lport_s *port, - struct bfa_lport_attr_s *port_attr); -void bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port, - struct bfa_lport_stats_s *port_stats); -void bfa_fcs_lport_clear_stats(struct bfa_fcs_lport_s *fcs_port); -enum bfa_port_speed bfa_fcs_lport_get_rport_max_speed( - struct bfa_fcs_lport_s *port); - -/* MS FCS routines */ -void bfa_fcs_lport_ms_init(struct bfa_fcs_lport_s *port); -void bfa_fcs_lport_ms_offline(struct bfa_fcs_lport_s *port); -void bfa_fcs_lport_ms_online(struct bfa_fcs_lport_s *port); -void bfa_fcs_lport_ms_fabric_rscn(struct bfa_fcs_lport_s *port); - -/* FDMI FCS routines */ -void bfa_fcs_lport_fdmi_init(struct bfa_fcs_lport_ms_s *ms); -void bfa_fcs_lport_fdmi_offline(struct bfa_fcs_lport_ms_s *ms); -void bfa_fcs_lport_fdmi_online(struct bfa_fcs_lport_ms_s *ms); -void bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport, struct fchs_s *fchs, - u16 len); -void bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs, - u16 vf_id, struct bfa_fcs_vport_s *vport); -void bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport, - struct bfa_lport_cfg_s *port_cfg); -void bfa_fcs_lport_online(struct bfa_fcs_lport_s *port); -void bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port); -void bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port); -struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_pid( - struct bfa_fcs_lport_s *port, u32 pid); -struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_pwwn( - struct bfa_fcs_lport_s *port, wwn_t pwwn); -struct bfa_fcs_rport_s *bfa_fcs_lport_get_rport_by_nwwn( - struct bfa_fcs_lport_s *port, wwn_t nwwn); -void bfa_fcs_lport_add_rport(struct bfa_fcs_lport_s *port, - struct bfa_fcs_rport_s *rport); -void bfa_fcs_lport_del_rport(struct bfa_fcs_lport_s *port, - struct bfa_fcs_rport_s *rport); -void bfa_fcs_lport_ns_init(struct bfa_fcs_lport_s *vport); -void bfa_fcs_lport_ns_offline(struct bfa_fcs_lport_s *vport); -void bfa_fcs_lport_ns_online(struct bfa_fcs_lport_s *vport); -void bfa_fcs_lport_ns_query(struct bfa_fcs_lport_s *port); -void bfa_fcs_lport_scn_init(struct bfa_fcs_lport_s *vport); -void bfa_fcs_lport_scn_offline(struct bfa_fcs_lport_s *vport); -void bfa_fcs_lport_scn_online(struct bfa_fcs_lport_s *vport); -void bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_frame, u32 len); - -struct bfa_fcs_vport_s { - struct list_head qe; /* queue elem */ - bfa_sm_t sm; /* state machine */ - bfa_fcs_lport_t lport; /* logical port */ - struct bfa_timer_s timer; - struct bfad_vport_s *vport_drv; /* Driver private */ - struct bfa_vport_stats_s vport_stats; /* vport statistics */ - struct bfa_lps_s *lps; /* Lport login service*/ - int fdisc_retries; -}; - -#define bfa_fcs_vport_get_port(vport) \ - ((struct bfa_fcs_lport_s *)(&vport->port)) - -/* - * bfa fcs vport public functions - */ -bfa_status_t bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, - struct bfa_fcs_s *fcs, u16 vf_id, - struct bfa_lport_cfg_s *port_cfg, - struct bfad_vport_s *vport_drv); -bfa_status_t bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, - struct bfa_fcs_s *fcs, u16 vf_id, - struct bfa_lport_cfg_s *port_cfg, - struct bfad_vport_s *vport_drv); -bfa_boolean_t bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport); -bfa_status_t bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport); -bfa_status_t bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport); -bfa_status_t bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport); -void bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, - struct bfa_vport_attr_s *vport_attr); -struct bfa_fcs_vport_s *bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, - u16 vf_id, wwn_t vpwwn); -void bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport); -void bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport); -void bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport); -void bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport); -void bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport); -void bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport); - -#define BFA_FCS_RPORT_DEF_DEL_TIMEOUT 90 /* in secs */ -#define BFA_FCS_RPORT_MAX_RETRIES (5) - -/* - * forward declarations - */ -struct bfad_rport_s; - -struct bfa_fcs_itnim_s; -struct bfa_fcs_tin_s; -struct bfa_fcs_iprp_s; - -/* Rport Features (RPF) */ -struct bfa_fcs_rpf_s { - bfa_sm_t sm; /* state machine */ - struct bfa_fcs_rport_s *rport; /* parent rport */ - struct bfa_timer_s timer; /* general purpose timer */ - struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */ - struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */ - int rpsc_retries; /* max RPSC retry attempts */ - enum bfa_port_speed rpsc_speed; - /* Current Speed from RPSC. O if RPSC fails */ - enum bfa_port_speed assigned_speed; - /* - * Speed assigned by the user. will be used if RPSC is - * not supported by the rport. - */ -}; - -struct bfa_fcs_rport_s { - struct list_head qe; /* used by port/vport */ - struct bfa_fcs_lport_s *port; /* parent FCS port */ - struct bfa_fcs_s *fcs; /* fcs instance */ - struct bfad_rport_s *rp_drv; /* driver peer instance */ - u32 pid; /* port ID of rport */ - u16 maxfrsize; /* maximum frame size */ - __be16 reply_oxid; /* OX_ID of inbound requests */ - enum fc_cos fc_cos; /* FC classes of service supp */ - bfa_boolean_t cisc; /* CISC capable device */ - bfa_boolean_t prlo; /* processing prlo or LOGO */ - bfa_boolean_t plogi_pending; /* Rx Plogi Pending */ - wwn_t pwwn; /* port wwn of rport */ - wwn_t nwwn; /* node wwn of rport */ - struct bfa_rport_symname_s psym_name; /* port symbolic name */ - bfa_sm_t sm; /* state machine */ - struct bfa_timer_s timer; /* general purpose timer */ - struct bfa_fcs_itnim_s *itnim; /* ITN initiator mode role */ - struct bfa_fcs_tin_s *tin; /* ITN initiator mode role */ - struct bfa_fcs_iprp_s *iprp; /* IP/FC role */ - struct bfa_rport_s *bfa_rport; /* BFA Rport */ - struct bfa_fcxp_s *fcxp; /* FCXP needed for discarding */ - int plogi_retries; /* max plogi retry attempts */ - int ns_retries; /* max NS query retry attempts */ - struct bfa_fcxp_wqe_s fcxp_wqe; /* fcxp wait queue element */ - struct bfa_rport_stats_s stats; /* rport stats */ - enum bfa_rport_function scsi_function; /* Initiator/Target */ - struct bfa_fcs_rpf_s rpf; /* Rport features module */ -}; - -static inline struct bfa_rport_s * -bfa_fcs_rport_get_halrport(struct bfa_fcs_rport_s *rport) -{ - return rport->bfa_rport; -} - -/* - * bfa fcs rport API functions - */ -void bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, - struct bfa_rport_attr_s *attr); -struct bfa_fcs_rport_s *bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, - wwn_t rpwwn); -struct bfa_fcs_rport_s *bfa_fcs_rport_lookup_by_nwwn( - struct bfa_fcs_lport_s *port, wwn_t rnwwn); -void bfa_fcs_rport_set_del_timeout(u8 rport_tmo); - -void bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, - struct fchs_s *fchs, u16 len); -void bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport); - -struct bfa_fcs_rport_s *bfa_fcs_rport_create(struct bfa_fcs_lport_s *port, - u32 pid); -void bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, - struct fc_logi_s *plogi_rsp); -void bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, - struct fc_logi_s *plogi); -void bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs, - struct fc_logi_s *plogi); -void bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, __be16 ox_id); - -void bfa_fcs_rport_itntm_ack(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rport_fcptm_offline_done(struct bfa_fcs_rport_s *rport); -int bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport); -struct bfa_fcs_rport_s *bfa_fcs_rport_create_by_wwn( - struct bfa_fcs_lport_s *port, wwn_t wwn); -void bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport); -void bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport); - -/* - * forward declarations - */ -struct bfad_itnim_s; - -struct bfa_fcs_itnim_s { - bfa_sm_t sm; /* state machine */ - struct bfa_fcs_rport_s *rport; /* parent remote rport */ - struct bfad_itnim_s *itnim_drv; /* driver peer instance */ - struct bfa_fcs_s *fcs; /* fcs instance */ - struct bfa_timer_s timer; /* timer functions */ - struct bfa_itnim_s *bfa_itnim; /* BFA itnim struct */ - u32 prli_retries; /* max prli retry attempts */ - bfa_boolean_t seq_rec; /* seq recovery support */ - bfa_boolean_t rec_support; /* REC supported */ - bfa_boolean_t conf_comp; /* FCP_CONF support */ - bfa_boolean_t task_retry_id; /* task retry id supp */ - struct bfa_fcxp_wqe_s fcxp_wqe; /* wait qelem for fcxp */ - struct bfa_fcxp_s *fcxp; /* FCXP in use */ - struct bfa_itnim_stats_s stats; /* itn statistics */ -}; -#define bfa_fcs_fcxp_alloc(__fcs) \ - bfa_fcxp_alloc(NULL, (__fcs)->bfa, 0, 0, NULL, NULL, NULL, NULL) - -#define bfa_fcs_fcxp_alloc_wait(__bfa, __wqe, __alloc_cbfn, __alloc_cbarg) \ - bfa_fcxp_alloc_wait(__bfa, __wqe, __alloc_cbfn, __alloc_cbarg, \ - NULL, 0, 0, NULL, NULL, NULL, NULL) - -static inline struct bfad_port_s * -bfa_fcs_itnim_get_drvport(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->port->bfad_port; -} - - -static inline struct bfa_fcs_lport_s * -bfa_fcs_itnim_get_port(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->port; -} - - -static inline wwn_t -bfa_fcs_itnim_get_nwwn(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->nwwn; -} - - -static inline wwn_t -bfa_fcs_itnim_get_pwwn(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->pwwn; -} - - -static inline u32 -bfa_fcs_itnim_get_fcid(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->pid; -} - - -static inline u32 -bfa_fcs_itnim_get_maxfrsize(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->maxfrsize; -} - - -static inline enum fc_cos -bfa_fcs_itnim_get_cos(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->rport->fc_cos; -} - - -static inline struct bfad_itnim_s * -bfa_fcs_itnim_get_drvitn(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->itnim_drv; -} - - -static inline struct bfa_itnim_s * -bfa_fcs_itnim_get_halitn(struct bfa_fcs_itnim_s *itnim) -{ - return itnim->bfa_itnim; -} - -/* - * bfa fcs FCP Initiator mode API functions - */ -void bfa_fcs_itnim_get_attr(struct bfa_fcs_itnim_s *itnim, - struct bfa_itnim_attr_s *attr); -void bfa_fcs_itnim_get_stats(struct bfa_fcs_itnim_s *itnim, - struct bfa_itnim_stats_s *stats); -struct bfa_fcs_itnim_s *bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, - wwn_t rpwwn); -bfa_status_t bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, - struct bfa_itnim_attr_s *attr); -bfa_status_t bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, - struct bfa_itnim_stats_s *stats); -bfa_status_t bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, - wwn_t rpwwn); -struct bfa_fcs_itnim_s *bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport); -void bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim); -void bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim); -void bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim); -bfa_status_t bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim); -void bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim); -void bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, - struct fchs_s *fchs, u16 len); - -#define BFA_FCS_FDMI_SUPP_SPEEDS_4G (FDMI_TRANS_SPEED_1G | \ - FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_8G (FDMI_TRANS_SPEED_1G | \ - FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G | \ - FDMI_TRANS_SPEED_8G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_16G (FDMI_TRANS_SPEED_2G | \ - FDMI_TRANS_SPEED_4G | \ - FDMI_TRANS_SPEED_8G | \ - FDMI_TRANS_SPEED_16G) - -#define BFA_FCS_FDMI_SUPP_SPEEDS_10G FDMI_TRANS_SPEED_10G - -/* - * HBA Attribute Block : BFA internal representation. Note : Some variable - * sizes have been trimmed to suit BFA For Ex : Model will be "Brocade". Based - * on this the size has been reduced to 16 bytes from the standard's 64 bytes. - */ -struct bfa_fcs_fdmi_hba_attr_s { - wwn_t node_name; - u8 manufacturer[64]; - u8 serial_num[64]; - u8 model[16]; - u8 model_desc[256]; - u8 hw_version[8]; - u8 driver_version[8]; - u8 option_rom_ver[BFA_VERSION_LEN]; - u8 fw_version[8]; - u8 os_name[256]; - __be32 max_ct_pyld; -}; - -/* - * Port Attribute Block - */ -struct bfa_fcs_fdmi_port_attr_s { - u8 supp_fc4_types[32]; /* supported FC4 types */ - __be32 supp_speed; /* supported speed */ - __be32 curr_speed; /* current Speed */ - __be32 max_frm_size; /* max frame size */ - u8 os_device_name[256]; /* OS device Name */ - u8 host_name[256]; /* host name */ -}; - -struct bfa_fcs_stats_s { - struct { - u32 untagged; /* untagged receive frames */ - u32 tagged; /* tagged receive frames */ - u32 vfid_unknown; /* VF id is unknown */ - } uf; -}; - -struct bfa_fcs_driver_info_s { - u8 version[BFA_VERSION_LEN]; /* Driver Version */ - u8 host_machine_name[BFA_FCS_OS_STR_LEN]; - u8 host_os_name[BFA_FCS_OS_STR_LEN]; /* OS name and version */ - u8 host_os_patch[BFA_FCS_OS_STR_LEN]; /* patch or service pack */ - u8 os_device_name[BFA_FCS_OS_STR_LEN]; /* Driver Device Name */ -}; - -struct bfa_fcs_s { - struct bfa_s *bfa; /* corresponding BFA bfa instance */ - struct bfad_s *bfad; /* corresponding BDA driver instance */ - struct bfa_trc_mod_s *trcmod; /* tracing module */ - bfa_boolean_t vf_enabled; /* VF mode is enabled */ - bfa_boolean_t fdmi_enabled; /* FDMI is enabled */ - bfa_boolean_t bbscn_enabled; /* Driver Config Parameter */ - bfa_boolean_t bbscn_flogi_rjt;/* FLOGI reject due to BB_SCN */ - bfa_boolean_t min_cfg; /* min cfg enabled/disabled */ - u16 port_vfid; /* port default VF ID */ - struct bfa_fcs_driver_info_s driver_info; - struct bfa_fcs_fabric_s fabric; /* base fabric state machine */ - struct bfa_fcs_stats_s stats; /* FCS statistics */ - struct bfa_wc_s wc; /* waiting counter */ - int fcs_aen_seq; -}; - -/* - * fcs_fabric_sm fabric state machine functions - */ - -/* - * Fabric state machine events - */ -enum bfa_fcs_fabric_event { - BFA_FCS_FABRIC_SM_CREATE = 1, /* create from driver */ - BFA_FCS_FABRIC_SM_DELETE = 2, /* delete from driver */ - BFA_FCS_FABRIC_SM_LINK_DOWN = 3, /* link down from port */ - BFA_FCS_FABRIC_SM_LINK_UP = 4, /* link up from port */ - BFA_FCS_FABRIC_SM_CONT_OP = 5, /* flogi/auth continue op */ - BFA_FCS_FABRIC_SM_RETRY_OP = 6, /* flogi/auth retry op */ - BFA_FCS_FABRIC_SM_NO_FABRIC = 7, /* from flogi/auth */ - BFA_FCS_FABRIC_SM_PERF_EVFP = 8, /* from flogi/auth */ - BFA_FCS_FABRIC_SM_ISOLATE = 9, /* from EVFP processing */ - BFA_FCS_FABRIC_SM_NO_TAGGING = 10, /* no VFT tagging from EVFP */ - BFA_FCS_FABRIC_SM_DELAYED = 11, /* timeout delay event */ - BFA_FCS_FABRIC_SM_AUTH_FAILED = 12, /* auth failed */ - BFA_FCS_FABRIC_SM_AUTH_SUCCESS = 13, /* auth successful */ - BFA_FCS_FABRIC_SM_DELCOMP = 14, /* all vports deleted event */ - BFA_FCS_FABRIC_SM_LOOPBACK = 15, /* Received our own FLOGI */ - BFA_FCS_FABRIC_SM_START = 16, /* from driver */ -}; - -/* - * fcs_rport_sm FCS rport state machine events - */ - -enum rport_event { - RPSM_EVENT_PLOGI_SEND = 1, /* new rport; start with PLOGI */ - RPSM_EVENT_PLOGI_RCVD = 2, /* Inbound PLOGI from remote port */ - RPSM_EVENT_PLOGI_COMP = 3, /* PLOGI completed to rport */ - RPSM_EVENT_LOGO_RCVD = 4, /* LOGO from remote device */ - RPSM_EVENT_LOGO_IMP = 5, /* implicit logo for SLER */ - RPSM_EVENT_FCXP_SENT = 6, /* Frame from has been sent */ - RPSM_EVENT_DELETE = 7, /* RPORT delete request */ - RPSM_EVENT_SCN = 8, /* state change notification */ - RPSM_EVENT_ACCEPTED = 9, /* Good response from remote device */ - RPSM_EVENT_FAILED = 10, /* Request to rport failed. */ - RPSM_EVENT_TIMEOUT = 11, /* Rport SM timeout event */ - RPSM_EVENT_HCB_ONLINE = 12, /* BFA rport online callback */ - RPSM_EVENT_HCB_OFFLINE = 13, /* BFA rport offline callback */ - RPSM_EVENT_FC4_OFFLINE = 14, /* FC-4 offline complete */ - RPSM_EVENT_ADDRESS_CHANGE = 15, /* Rport's PID has changed */ - RPSM_EVENT_ADDRESS_DISC = 16, /* Need to Discover rport's PID */ - RPSM_EVENT_PRLO_RCVD = 17, /* PRLO from remote device */ - RPSM_EVENT_PLOGI_RETRY = 18, /* Retry PLOGI continuously */ -}; - -/* - * bfa fcs API functions - */ -void bfa_fcs_attach(struct bfa_fcs_s *fcs, struct bfa_s *bfa, - struct bfad_s *bfad, - bfa_boolean_t min_cfg); -void bfa_fcs_init(struct bfa_fcs_s *fcs); -void bfa_fcs_pbc_vport_init(struct bfa_fcs_s *fcs); -void bfa_fcs_update_cfg(struct bfa_fcs_s *fcs); -void bfa_fcs_driver_info_init(struct bfa_fcs_s *fcs, - struct bfa_fcs_driver_info_s *driver_info); -void bfa_fcs_exit(struct bfa_fcs_s *fcs); - -/* - * bfa fcs vf public functions - */ -bfa_fcs_vf_t *bfa_fcs_vf_lookup(struct bfa_fcs_s *fcs, u16 vf_id); -void bfa_fcs_vf_get_ports(bfa_fcs_vf_t *vf, wwn_t vpwwn[], int *nports); - -/* - * fabric protected interface functions - */ -void bfa_fcs_fabric_attach(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_modinit(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_modexit(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_link_up(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_fabric_link_down(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_fabric_addvport(struct bfa_fcs_fabric_s *fabric, - struct bfa_fcs_vport_s *vport); -void bfa_fcs_fabric_delvport(struct bfa_fcs_fabric_s *fabric, - struct bfa_fcs_vport_s *vport); -struct bfa_fcs_vport_s *bfa_fcs_fabric_vport_lookup( - struct bfa_fcs_fabric_s *fabric, wwn_t pwwn); -void bfa_fcs_fabric_modstart(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_uf_recv(struct bfa_fcs_fabric_s *fabric, - struct fchs_s *fchs, u16 len); -void bfa_fcs_fabric_psymb_init(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_fabric_set_fabric_name(struct bfa_fcs_fabric_s *fabric, - wwn_t fabric_name); -u16 bfa_fcs_fabric_get_switch_oui(struct bfa_fcs_fabric_s *fabric); -void bfa_fcs_uf_attach(struct bfa_fcs_s *fcs); -void bfa_fcs_port_attach(struct bfa_fcs_s *fcs); -void bfa_fcs_fabric_sm_online(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -void bfa_fcs_fabric_sm_loopback(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); -void bfa_fcs_fabric_sm_auth_failed(struct bfa_fcs_fabric_s *fabric, - enum bfa_fcs_fabric_event event); - -/* - * BFA FCS callback interfaces - */ - -/* - * fcb Main fcs callbacks - */ - -struct bfad_port_s; -struct bfad_vf_s; -struct bfad_vport_s; -struct bfad_rport_s; - -/* - * lport callbacks - */ -struct bfad_port_s *bfa_fcb_lport_new(struct bfad_s *bfad, - struct bfa_fcs_lport_s *port, - enum bfa_lport_role roles, - struct bfad_vf_s *vf_drv, - struct bfad_vport_s *vp_drv); -void bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles, - struct bfad_vf_s *vf_drv, - struct bfad_vport_s *vp_drv); - -/* - * vport callbacks - */ -void bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s); - -/* - * rport callbacks - */ -bfa_status_t bfa_fcb_rport_alloc(struct bfad_s *bfad, - struct bfa_fcs_rport_s **rport, - struct bfad_rport_s **rport_drv); - -/* - * itnim callbacks - */ -void bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim, - struct bfad_itnim_s **itnim_drv); -void bfa_fcb_itnim_free(struct bfad_s *bfad, - struct bfad_itnim_s *itnim_drv); -void bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv); -void bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv); - -#endif /* __BFA_FCS_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_fcpim.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_fcpim.c deleted file mode 100644 index 9272840a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_fcpim.c +++ /dev/null @@ -1,826 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * fcpim.c - FCP initiator mode i-t nexus state machine - */ - -#include "bfad_drv.h" -#include "bfa_fcs.h" -#include "bfa_fcbuild.h" -#include "bfad_im.h" - -BFA_TRC_FILE(FCS, FCPIM); - -/* - * forward declarations - */ -static void bfa_fcs_itnim_timeout(void *arg); -static void bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim); -static void bfa_fcs_itnim_send_prli(void *itnim_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_itnim_prli_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs); -static void bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim, - enum bfa_itnim_aen_event event); - -/* - * fcs_itnim_sm FCS itnim state machine events - */ - -enum bfa_fcs_itnim_event { - BFA_FCS_ITNIM_SM_ONLINE = 1, /* rport online event */ - BFA_FCS_ITNIM_SM_OFFLINE = 2, /* rport offline */ - BFA_FCS_ITNIM_SM_FRMSENT = 3, /* prli frame is sent */ - BFA_FCS_ITNIM_SM_RSP_OK = 4, /* good response */ - BFA_FCS_ITNIM_SM_RSP_ERROR = 5, /* error response */ - BFA_FCS_ITNIM_SM_TIMEOUT = 6, /* delay timeout */ - BFA_FCS_ITNIM_SM_HCB_OFFLINE = 7, /* BFA online callback */ - BFA_FCS_ITNIM_SM_HCB_ONLINE = 8, /* BFA offline callback */ - BFA_FCS_ITNIM_SM_INITIATOR = 9, /* rport is initiator */ - BFA_FCS_ITNIM_SM_DELETE = 10, /* delete event from rport */ - BFA_FCS_ITNIM_SM_PRLO = 11, /* delete event from rport */ - BFA_FCS_ITNIM_SM_RSP_NOT_SUPP = 12, /* cmd not supported rsp */ -}; - -static void bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event); -static void bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event); - -static struct bfa_sm_table_s itnim_sm_table[] = { - {BFA_SM(bfa_fcs_itnim_sm_offline), BFA_ITNIM_OFFLINE}, - {BFA_SM(bfa_fcs_itnim_sm_prli_send), BFA_ITNIM_PRLI_SEND}, - {BFA_SM(bfa_fcs_itnim_sm_prli), BFA_ITNIM_PRLI_SENT}, - {BFA_SM(bfa_fcs_itnim_sm_prli_retry), BFA_ITNIM_PRLI_RETRY}, - {BFA_SM(bfa_fcs_itnim_sm_hcb_online), BFA_ITNIM_HCB_ONLINE}, - {BFA_SM(bfa_fcs_itnim_sm_online), BFA_ITNIM_ONLINE}, - {BFA_SM(bfa_fcs_itnim_sm_hcb_offline), BFA_ITNIM_HCB_OFFLINE}, - {BFA_SM(bfa_fcs_itnim_sm_initiator), BFA_ITNIM_INITIATIOR}, -}; - -/* - * fcs_itnim_sm FCS itnim state machine - */ - -static void -bfa_fcs_itnim_sm_offline(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) -{ - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_trc(itnim->fcs, event); - - switch (event) { - case BFA_FCS_ITNIM_SM_ONLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); - itnim->prli_retries = 0; - bfa_fcs_itnim_send_prli(itnim, NULL); - break; - - case BFA_FCS_ITNIM_SM_OFFLINE: - bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE); - break; - - case BFA_FCS_ITNIM_SM_INITIATOR: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); - break; - - case BFA_FCS_ITNIM_SM_DELETE: - bfa_fcs_itnim_free(itnim); - break; - - default: - bfa_sm_fault(itnim->fcs, event); - } - -} - -static void -bfa_fcs_itnim_sm_prli_send(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) -{ - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_trc(itnim->fcs, event); - - switch (event) { - case BFA_FCS_ITNIM_SM_FRMSENT: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli); - break; - - case BFA_FCS_ITNIM_SM_INITIATOR: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); - bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); - break; - - case BFA_FCS_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); - bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE); - break; - - case BFA_FCS_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_fcxp_walloc_cancel(itnim->fcs->bfa, &itnim->fcxp_wqe); - bfa_fcs_itnim_free(itnim); - break; - - default: - bfa_sm_fault(itnim->fcs, event); - } -} - -static void -bfa_fcs_itnim_sm_prli(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) -{ - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_trc(itnim->fcs, event); - - switch (event) { - case BFA_FCS_ITNIM_SM_RSP_OK: - if (itnim->rport->scsi_function == BFA_RPORT_INITIATOR) { - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); - } else { - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_online); - bfa_itnim_online(itnim->bfa_itnim, itnim->seq_rec); - } - break; - - case BFA_FCS_ITNIM_SM_RSP_ERROR: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_retry); - bfa_timer_start(itnim->fcs->bfa, &itnim->timer, - bfa_fcs_itnim_timeout, itnim, - BFA_FCS_RETRY_TIMEOUT); - break; - - case BFA_FCS_ITNIM_SM_RSP_NOT_SUPP: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - break; - - case BFA_FCS_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_fcxp_discard(itnim->fcxp); - bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE); - break; - - case BFA_FCS_ITNIM_SM_INITIATOR: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); - bfa_fcxp_discard(itnim->fcxp); - break; - - case BFA_FCS_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_fcxp_discard(itnim->fcxp); - bfa_fcs_itnim_free(itnim); - break; - - default: - bfa_sm_fault(itnim->fcs, event); - } -} - -static void -bfa_fcs_itnim_sm_prli_retry(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) -{ - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_trc(itnim->fcs, event); - - switch (event) { - case BFA_FCS_ITNIM_SM_TIMEOUT: - if (itnim->prli_retries < BFA_FCS_RPORT_MAX_RETRIES) { - itnim->prli_retries++; - bfa_trc(itnim->fcs, itnim->prli_retries); - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_prli_send); - bfa_fcs_itnim_send_prli(itnim, NULL); - } else { - /* invoke target offline */ - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP); - } - break; - - - case BFA_FCS_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_timer_stop(&itnim->timer); - bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE); - break; - - case BFA_FCS_ITNIM_SM_INITIATOR: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_initiator); - bfa_timer_stop(&itnim->timer); - break; - - case BFA_FCS_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_timer_stop(&itnim->timer); - bfa_fcs_itnim_free(itnim); - break; - - default: - bfa_sm_fault(itnim->fcs, event); - } -} - -static void -bfa_fcs_itnim_sm_hcb_online(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) -{ - struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad; - char lpwwn_buf[BFA_STRING_32]; - char rpwwn_buf[BFA_STRING_32]; - - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_trc(itnim->fcs, event); - - switch (event) { - case BFA_FCS_ITNIM_SM_HCB_ONLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_online); - bfa_fcb_itnim_online(itnim->itnim_drv); - wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port)); - wwn2str(rpwwn_buf, itnim->rport->pwwn); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Target (WWN = %s) is online for initiator (WWN = %s)\n", - rpwwn_buf, lpwwn_buf); - bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_ONLINE); - break; - - case BFA_FCS_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_itnim_offline(itnim->bfa_itnim); - bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE); - break; - - case BFA_FCS_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_fcs_itnim_free(itnim); - break; - - default: - bfa_sm_fault(itnim->fcs, event); - } -} - -static void -bfa_fcs_itnim_sm_online(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) -{ - struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad; - char lpwwn_buf[BFA_STRING_32]; - char rpwwn_buf[BFA_STRING_32]; - - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_trc(itnim->fcs, event); - - switch (event) { - case BFA_FCS_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_hcb_offline); - bfa_fcb_itnim_offline(itnim->itnim_drv); - bfa_itnim_offline(itnim->bfa_itnim); - wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(itnim->rport->port)); - wwn2str(rpwwn_buf, itnim->rport->pwwn); - if (bfa_fcs_lport_is_online(itnim->rport->port) == BFA_TRUE) { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "Target (WWN = %s) connectivity lost for " - "initiator (WWN = %s)\n", rpwwn_buf, lpwwn_buf); - bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_DISCONNECT); - } else { - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Target (WWN = %s) offlined by initiator (WWN = %s)\n", - rpwwn_buf, lpwwn_buf); - bfa_fcs_itnim_aen_post(itnim, BFA_ITNIM_AEN_OFFLINE); - } - break; - - case BFA_FCS_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_fcs_itnim_free(itnim); - break; - - default: - bfa_sm_fault(itnim->fcs, event); - } -} - -static void -bfa_fcs_itnim_sm_hcb_offline(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) -{ - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_trc(itnim->fcs, event); - - switch (event) { - case BFA_FCS_ITNIM_SM_HCB_OFFLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE); - break; - - case BFA_FCS_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_fcs_itnim_free(itnim); - break; - - default: - bfa_sm_fault(itnim->fcs, event); - } -} - -/* - * This state is set when a discovered rport is also in intiator mode. - * This ITN is marked as no_op and is not active and will not be truned into - * online state. - */ -static void -bfa_fcs_itnim_sm_initiator(struct bfa_fcs_itnim_s *itnim, - enum bfa_fcs_itnim_event event) -{ - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_trc(itnim->fcs, event); - - switch (event) { - case BFA_FCS_ITNIM_SM_OFFLINE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_sm_send_event(itnim->rport, RPSM_EVENT_FC4_OFFLINE); - break; - - case BFA_FCS_ITNIM_SM_RSP_ERROR: - case BFA_FCS_ITNIM_SM_ONLINE: - case BFA_FCS_ITNIM_SM_INITIATOR: - break; - - case BFA_FCS_ITNIM_SM_DELETE: - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - bfa_fcs_itnim_free(itnim); - break; - - default: - bfa_sm_fault(itnim->fcs, event); - } -} - -static void -bfa_fcs_itnim_aen_post(struct bfa_fcs_itnim_s *itnim, - enum bfa_itnim_aen_event event) -{ - struct bfa_fcs_rport_s *rport = itnim->rport; - struct bfad_s *bfad = (struct bfad_s *)itnim->fcs->bfad; - struct bfa_aen_entry_s *aen_entry; - - /* Don't post events for well known addresses */ - if (BFA_FCS_PID_IS_WKA(rport->pid)) - return; - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - aen_entry->aen_data.itnim.vf_id = rport->port->fabric->vf_id; - aen_entry->aen_data.itnim.ppwwn = bfa_fcs_lport_get_pwwn( - bfa_fcs_get_base_port(itnim->fcs)); - aen_entry->aen_data.itnim.lpwwn = bfa_fcs_lport_get_pwwn(rport->port); - aen_entry->aen_data.itnim.rpwwn = rport->pwwn; - - /* Send the AEN notification */ - bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq, - BFA_AEN_CAT_ITNIM, event); -} - -static void -bfa_fcs_itnim_send_prli(void *itnim_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_itnim_s *itnim = itnim_cbarg; - struct bfa_fcs_rport_s *rport = itnim->rport; - struct bfa_fcs_lport_s *port = rport->port; - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - int len; - - bfa_trc(itnim->fcs, itnim->rport->pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - itnim->stats.fcxp_alloc_wait++; - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &itnim->fcxp_wqe, - bfa_fcs_itnim_send_prli, itnim); - return; - } - itnim->fcxp = fcxp; - - len = fc_prli_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - itnim->rport->pid, bfa_fcs_lport_get_fcid(port), 0); - - bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, - bfa_fcs_itnim_prli_response, (void *)itnim, - FC_MAX_PDUSZ, FC_ELS_TOV); - - itnim->stats.prli_sent++; - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_FRMSENT); -} - -static void -bfa_fcs_itnim_prli_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg; - struct fc_els_cmd_s *els_cmd; - struct fc_prli_s *prli_resp; - struct fc_ls_rjt_s *ls_rjt; - struct fc_prli_params_s *sparams; - - bfa_trc(itnim->fcs, req_status); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - itnim->stats.prli_rsp_err++; - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR); - return; - } - - els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); - - if (els_cmd->els_code == FC_ELS_ACC) { - prli_resp = (struct fc_prli_s *) els_cmd; - - if (fc_prli_rsp_parse(prli_resp, rsp_len) != FC_PARSE_OK) { - bfa_trc(itnim->fcs, rsp_len); - /* - * Check if this r-port is also in Initiator mode. - * If so, we need to set this ITN as a no-op. - */ - if (prli_resp->parampage.servparams.initiator) { - bfa_trc(itnim->fcs, prli_resp->parampage.type); - itnim->rport->scsi_function = - BFA_RPORT_INITIATOR; - itnim->stats.prli_rsp_acc++; - itnim->stats.initiator++; - bfa_sm_send_event(itnim, - BFA_FCS_ITNIM_SM_RSP_OK); - return; - } - - itnim->stats.prli_rsp_parse_err++; - return; - } - itnim->rport->scsi_function = BFA_RPORT_TARGET; - - sparams = &prli_resp->parampage.servparams; - itnim->seq_rec = sparams->retry; - itnim->rec_support = sparams->rec_support; - itnim->task_retry_id = sparams->task_retry_id; - itnim->conf_comp = sparams->confirm; - - itnim->stats.prli_rsp_acc++; - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_OK); - } else { - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - - bfa_trc(itnim->fcs, ls_rjt->reason_code); - bfa_trc(itnim->fcs, ls_rjt->reason_code_expl); - - itnim->stats.prli_rsp_rjt++; - if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) { - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_NOT_SUPP); - return; - } - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_RSP_ERROR); - } -} - -static void -bfa_fcs_itnim_timeout(void *arg) -{ - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) arg; - - itnim->stats.timeout++; - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_TIMEOUT); -} - -static void -bfa_fcs_itnim_free(struct bfa_fcs_itnim_s *itnim) -{ - bfa_itnim_delete(itnim->bfa_itnim); - bfa_fcb_itnim_free(itnim->fcs->bfad, itnim->itnim_drv); -} - - - -/* - * itnim_public FCS ITNIM public interfaces - */ - -/* - * Called by rport when a new rport is created. - * - * @param[in] rport - remote port. - */ -struct bfa_fcs_itnim_s * -bfa_fcs_itnim_create(struct bfa_fcs_rport_s *rport) -{ - struct bfa_fcs_lport_s *port = rport->port; - struct bfa_fcs_itnim_s *itnim; - struct bfad_itnim_s *itnim_drv; - struct bfa_itnim_s *bfa_itnim; - - /* - * call bfad to allocate the itnim - */ - bfa_fcb_itnim_alloc(port->fcs->bfad, &itnim, &itnim_drv); - if (itnim == NULL) { - bfa_trc(port->fcs, rport->pwwn); - return NULL; - } - - /* - * Initialize itnim - */ - itnim->rport = rport; - itnim->fcs = rport->fcs; - itnim->itnim_drv = itnim_drv; - - /* - * call BFA to create the itnim - */ - bfa_itnim = - bfa_itnim_create(port->fcs->bfa, rport->bfa_rport, itnim); - - if (bfa_itnim == NULL) { - bfa_trc(port->fcs, rport->pwwn); - bfa_fcb_itnim_free(port->fcs->bfad, itnim_drv); - WARN_ON(1); - return NULL; - } - - itnim->bfa_itnim = bfa_itnim; - itnim->seq_rec = BFA_FALSE; - itnim->rec_support = BFA_FALSE; - itnim->conf_comp = BFA_FALSE; - itnim->task_retry_id = BFA_FALSE; - - /* - * Set State machine - */ - bfa_sm_set_state(itnim, bfa_fcs_itnim_sm_offline); - - return itnim; -} - -/* - * Called by rport to delete the instance of FCPIM. - * - * @param[in] rport - remote port. - */ -void -bfa_fcs_itnim_delete(struct bfa_fcs_itnim_s *itnim) -{ - bfa_trc(itnim->fcs, itnim->rport->pid); - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_DELETE); -} - -/* - * Notification from rport that PLOGI is complete to initiate FC-4 session. - */ -void -bfa_fcs_itnim_rport_online(struct bfa_fcs_itnim_s *itnim) -{ - itnim->stats.onlines++; - - if (!BFA_FCS_PID_IS_WKA(itnim->rport->pid)) { - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_ONLINE); - } else { - /* - * For well known addresses, we set the itnim to initiator - * state - */ - itnim->stats.initiator++; - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR); - } -} - -/* - * Called by rport to handle a remote device offline. - */ -void -bfa_fcs_itnim_rport_offline(struct bfa_fcs_itnim_s *itnim) -{ - itnim->stats.offlines++; - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_OFFLINE); -} - -/* - * Called by rport when remote port is known to be an initiator from - * PRLI received. - */ -void -bfa_fcs_itnim_is_initiator(struct bfa_fcs_itnim_s *itnim) -{ - bfa_trc(itnim->fcs, itnim->rport->pid); - itnim->stats.initiator++; - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_INITIATOR); -} - -/* - * Called by rport to check if the itnim is online. - */ -bfa_status_t -bfa_fcs_itnim_get_online_state(struct bfa_fcs_itnim_s *itnim) -{ - bfa_trc(itnim->fcs, itnim->rport->pid); - switch (bfa_sm_to_state(itnim_sm_table, itnim->sm)) { - case BFA_ITNIM_ONLINE: - case BFA_ITNIM_INITIATIOR: - return BFA_STATUS_OK; - - default: - return BFA_STATUS_NO_FCPIM_NEXUS; - } -} - -/* - * BFA completion callback for bfa_itnim_online(). - */ -void -bfa_cb_itnim_online(void *cbarg) -{ - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cbarg; - - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_ONLINE); -} - -/* - * BFA completion callback for bfa_itnim_offline(). - */ -void -bfa_cb_itnim_offline(void *cb_arg) -{ - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; - - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_sm_send_event(itnim, BFA_FCS_ITNIM_SM_HCB_OFFLINE); -} - -/* - * Mark the beginning of PATH TOV handling. IO completion callbacks - * are still pending. - */ -void -bfa_cb_itnim_tov_begin(void *cb_arg) -{ - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; - - bfa_trc(itnim->fcs, itnim->rport->pwwn); -} - -/* - * Mark the end of PATH TOV handling. All pending IOs are already cleaned up. - */ -void -bfa_cb_itnim_tov(void *cb_arg) -{ - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; - struct bfad_itnim_s *itnim_drv = itnim->itnim_drv; - - bfa_trc(itnim->fcs, itnim->rport->pwwn); - itnim_drv->state = ITNIM_STATE_TIMEOUT; -} - -/* - * BFA notification to FCS/driver for second level error recovery. - * - * Atleast one I/O request has timedout and target is unresponsive to - * repeated abort requests. Second level error recovery should be initiated - * by starting implicit logout and recovery procedures. - */ -void -bfa_cb_itnim_sler(void *cb_arg) -{ - struct bfa_fcs_itnim_s *itnim = (struct bfa_fcs_itnim_s *) cb_arg; - - itnim->stats.sler++; - bfa_trc(itnim->fcs, itnim->rport->pwwn); - bfa_sm_send_event(itnim->rport, RPSM_EVENT_LOGO_IMP); -} - -struct bfa_fcs_itnim_s * -bfa_fcs_itnim_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn) -{ - struct bfa_fcs_rport_s *rport; - rport = bfa_fcs_rport_lookup(port, rpwwn); - - if (!rport) - return NULL; - - WARN_ON(rport->itnim == NULL); - return rport->itnim; -} - -bfa_status_t -bfa_fcs_itnim_attr_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, - struct bfa_itnim_attr_s *attr) -{ - struct bfa_fcs_itnim_s *itnim = NULL; - - itnim = bfa_fcs_itnim_lookup(port, rpwwn); - - if (itnim == NULL) - return BFA_STATUS_NO_FCPIM_NEXUS; - - attr->state = bfa_sm_to_state(itnim_sm_table, itnim->sm); - attr->retry = itnim->seq_rec; - attr->rec_support = itnim->rec_support; - attr->conf_comp = itnim->conf_comp; - attr->task_retry_id = itnim->task_retry_id; - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_fcs_itnim_stats_get(struct bfa_fcs_lport_s *port, wwn_t rpwwn, - struct bfa_itnim_stats_s *stats) -{ - struct bfa_fcs_itnim_s *itnim = NULL; - - WARN_ON(port == NULL); - - itnim = bfa_fcs_itnim_lookup(port, rpwwn); - - if (itnim == NULL) - return BFA_STATUS_NO_FCPIM_NEXUS; - - memcpy(stats, &itnim->stats, sizeof(struct bfa_itnim_stats_s)); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_fcs_itnim_stats_clear(struct bfa_fcs_lport_s *port, wwn_t rpwwn) -{ - struct bfa_fcs_itnim_s *itnim = NULL; - - WARN_ON(port == NULL); - - itnim = bfa_fcs_itnim_lookup(port, rpwwn); - - if (itnim == NULL) - return BFA_STATUS_NO_FCPIM_NEXUS; - - memset(&itnim->stats, 0, sizeof(struct bfa_itnim_stats_s)); - return BFA_STATUS_OK; -} - -void -bfa_fcs_fcpim_uf_recv(struct bfa_fcs_itnim_s *itnim, - struct fchs_s *fchs, u16 len) -{ - struct fc_els_cmd_s *els_cmd; - - bfa_trc(itnim->fcs, fchs->type); - - if (fchs->type != FC_TYPE_ELS) - return; - - els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - bfa_trc(itnim->fcs, els_cmd->els_code); - - switch (els_cmd->els_code) { - case FC_ELS_PRLO: - bfa_fcs_rport_prlo(itnim->rport, fchs->ox_id); - break; - - default: - WARN_ON(1); - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_lport.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_lport.c deleted file mode 100644 index 5d2a1307..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_lport.c +++ /dev/null @@ -1,6069 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfa_fcs.h" -#include "bfa_fcbuild.h" -#include "bfa_fc.h" - -BFA_TRC_FILE(FCS, PORT); - -static void bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, u8 reason_code, - u8 reason_code_expl); -static void bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, struct fc_logi_s *plogi); -static void bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_echo(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, - struct fc_echo_s *echo, u16 len); -static void bfa_fcs_lport_rnid(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, - struct fc_rnid_cmd_s *rnid, u16 len); -static void bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port, - struct fc_rnid_general_topology_data_s *gen_topo_data); - -static void bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port); - -static void bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port); -static void bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port); - -static struct { - void (*init) (struct bfa_fcs_lport_s *port); - void (*online) (struct bfa_fcs_lport_s *port); - void (*offline) (struct bfa_fcs_lport_s *port); -} __port_action[] = { - { - bfa_fcs_lport_unknown_init, bfa_fcs_lport_unknown_online, - bfa_fcs_lport_unknown_offline}, { - bfa_fcs_lport_fab_init, bfa_fcs_lport_fab_online, - bfa_fcs_lport_fab_offline}, { - bfa_fcs_lport_n2n_init, bfa_fcs_lport_n2n_online, - bfa_fcs_lport_n2n_offline}, - }; - -/* - * fcs_port_sm FCS logical port state machine - */ - -enum bfa_fcs_lport_event { - BFA_FCS_PORT_SM_CREATE = 1, - BFA_FCS_PORT_SM_ONLINE = 2, - BFA_FCS_PORT_SM_OFFLINE = 3, - BFA_FCS_PORT_SM_DELETE = 4, - BFA_FCS_PORT_SM_DELRPORT = 5, - BFA_FCS_PORT_SM_STOP = 6, -}; - -static void bfa_fcs_lport_sm_uninit(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event); -static void bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event); -static void bfa_fcs_lport_sm_online(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event); -static void bfa_fcs_lport_sm_offline(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event); -static void bfa_fcs_lport_sm_deleting(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event); -static void bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event); - -static void -bfa_fcs_lport_sm_uninit( - struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event) -{ - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case BFA_FCS_PORT_SM_CREATE: - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_sm_init(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event) -{ - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case BFA_FCS_PORT_SM_ONLINE: - bfa_sm_set_state(port, bfa_fcs_lport_sm_online); - bfa_fcs_lport_online_actions(port); - break; - - case BFA_FCS_PORT_SM_DELETE: - bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); - bfa_fcs_lport_deleted(port); - break; - - case BFA_FCS_PORT_SM_STOP: - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - break; - - case BFA_FCS_PORT_SM_OFFLINE: - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_sm_online( - struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event) -{ - struct bfa_fcs_rport_s *rport; - struct list_head *qe, *qen; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case BFA_FCS_PORT_SM_OFFLINE: - bfa_sm_set_state(port, bfa_fcs_lport_sm_offline); - bfa_fcs_lport_offline_actions(port); - break; - - case BFA_FCS_PORT_SM_STOP: - __port_action[port->fabric->fab_type].offline(port); - - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } else { - bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - break; - - case BFA_FCS_PORT_SM_DELETE: - - __port_action[port->fabric->fab_type].offline(port); - - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); - bfa_fcs_lport_deleted(port); - } else { - bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting); - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - break; - - case BFA_FCS_PORT_SM_DELRPORT: - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_sm_offline( - struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event) -{ - struct bfa_fcs_rport_s *rport; - struct list_head *qe, *qen; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case BFA_FCS_PORT_SM_ONLINE: - bfa_sm_set_state(port, bfa_fcs_lport_sm_online); - bfa_fcs_lport_online_actions(port); - break; - - case BFA_FCS_PORT_SM_STOP: - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } else { - bfa_sm_set_state(port, bfa_fcs_lport_sm_stopping); - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - break; - - case BFA_FCS_PORT_SM_DELETE: - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); - bfa_fcs_lport_deleted(port); - } else { - bfa_sm_set_state(port, bfa_fcs_lport_sm_deleting); - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - break; - - case BFA_FCS_PORT_SM_DELRPORT: - case BFA_FCS_PORT_SM_OFFLINE: - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_sm_stopping(struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event) -{ - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case BFA_FCS_PORT_SM_DELRPORT: - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_init); - /* If vport - send completion call back */ - if (port->vport) - bfa_fcs_vport_stop_comp(port->vport); - } - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_sm_deleting( - struct bfa_fcs_lport_s *port, - enum bfa_fcs_lport_event event) -{ - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case BFA_FCS_PORT_SM_DELRPORT: - if (port->num_rports == 0) { - bfa_sm_set_state(port, bfa_fcs_lport_sm_uninit); - bfa_fcs_lport_deleted(port); - } - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -/* - * fcs_port_pvt - */ - -/* - * Send AEN notification - */ -static void -bfa_fcs_lport_aen_post(struct bfa_fcs_lport_s *port, - enum bfa_lport_aen_event event) -{ - struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad; - struct bfa_aen_entry_s *aen_entry; - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - aen_entry->aen_data.lport.vf_id = port->fabric->vf_id; - aen_entry->aen_data.lport.roles = port->port_cfg.roles; - aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn( - bfa_fcs_get_base_port(port->fcs)); - aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port); - - /* Send the AEN notification */ - bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq, - BFA_AEN_CAT_LPORT, event); -} - -/* - * Send a LS reject - */ -static void -bfa_fcs_lport_send_ls_rjt(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, - u8 reason_code, u8 reason_code_expl) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - int len; - - bfa_trc(port->fcs, rx_fchs->d_id); - bfa_trc(port->fcs, rx_fchs->s_id); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, reason_code, reason_code_expl); - - bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - -/* - * Send a FCCT Reject - */ -static void -bfa_fcs_lport_send_fcgs_rjt(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, u8 reason_code, u8 reason_code_expl) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - int len; - struct ct_hdr_s *rx_cthdr = (struct ct_hdr_s *)(rx_fchs + 1); - struct ct_hdr_s *ct_hdr; - - bfa_trc(port->fcs, rx_fchs->d_id); - bfa_trc(port->fcs, rx_fchs->s_id); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - ct_hdr = bfa_fcxp_get_reqbuf(fcxp); - ct_hdr->gs_type = rx_cthdr->gs_type; - ct_hdr->gs_sub_type = rx_cthdr->gs_sub_type; - - len = fc_gs_rjt_build(&fchs, ct_hdr, rx_fchs->s_id, - bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, reason_code, reason_code_expl); - - bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - -/* - * Process incoming plogi from a remote port. - */ -static void -bfa_fcs_lport_plogi(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs, struct fc_logi_s *plogi) -{ - struct bfa_fcs_rport_s *rport; - - bfa_trc(port->fcs, rx_fchs->d_id); - bfa_trc(port->fcs, rx_fchs->s_id); - - /* - * If min cfg mode is enabled, drop any incoming PLOGIs - */ - if (__fcs_min_cfg(port->fcs)) { - bfa_trc(port->fcs, rx_fchs->s_id); - return; - } - - if (fc_plogi_parse(rx_fchs) != FC_PARSE_OK) { - bfa_trc(port->fcs, rx_fchs->s_id); - /* - * send a LS reject - */ - bfa_fcs_lport_send_ls_rjt(port, rx_fchs, - FC_LS_RJT_RSN_PROTOCOL_ERROR, - FC_LS_RJT_EXP_SPARMS_ERR_OPTIONS); - return; - } - - /* - * Direct Attach P2P mode : verify address assigned by the r-port. - */ - if ((!bfa_fcs_fabric_is_switched(port->fabric)) && - (memcmp((void *)&bfa_fcs_lport_get_pwwn(port), - (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { - if (BFA_FCS_PID_IS_WKA(rx_fchs->d_id)) { - /* Address assigned to us cannot be a WKA */ - bfa_fcs_lport_send_ls_rjt(port, rx_fchs, - FC_LS_RJT_RSN_PROTOCOL_ERROR, - FC_LS_RJT_EXP_INVALID_NPORT_ID); - return; - } - port->pid = rx_fchs->d_id; - bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id); - } - - /* - * First, check if we know the device by pwwn. - */ - rport = bfa_fcs_lport_get_rport_by_pwwn(port, plogi->port_name); - if (rport) { - /* - * Direct Attach P2P mode : handle address assigned by r-port. - */ - if ((!bfa_fcs_fabric_is_switched(port->fabric)) && - (memcmp((void *)&bfa_fcs_lport_get_pwwn(port), - (void *)&plogi->port_name, sizeof(wwn_t)) < 0)) { - port->pid = rx_fchs->d_id; - bfa_lps_set_n2n_pid(port->fabric->lps, rx_fchs->d_id); - rport->pid = rx_fchs->s_id; - } - bfa_fcs_rport_plogi(rport, rx_fchs, plogi); - return; - } - - /* - * Next, lookup rport by PID. - */ - rport = bfa_fcs_lport_get_rport_by_pid(port, rx_fchs->s_id); - if (!rport) { - /* - * Inbound PLOGI from a new device. - */ - bfa_fcs_rport_plogi_create(port, rx_fchs, plogi); - return; - } - - /* - * Rport is known only by PID. - */ - if (rport->pwwn) { - /* - * This is a different device with the same pid. Old device - * disappeared. Send implicit LOGO to old device. - */ - WARN_ON(rport->pwwn == plogi->port_name); - bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP); - - /* - * Inbound PLOGI from a new device (with old PID). - */ - bfa_fcs_rport_plogi_create(port, rx_fchs, plogi); - return; - } - - /* - * PLOGI crossing each other. - */ - WARN_ON(rport->pwwn != WWN_NULL); - bfa_fcs_rport_plogi(rport, rx_fchs, plogi); -} - -/* - * Process incoming ECHO. - * Since it does not require a login, it is processed here. - */ -static void -bfa_fcs_lport_echo(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, - struct fc_echo_s *echo, u16 rx_len) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - int len, pyld_len; - - bfa_trc(port->fcs, rx_fchs->s_id); - bfa_trc(port->fcs, rx_fchs->d_id); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id); - - /* - * Copy the payload (if any) from the echo frame - */ - pyld_len = rx_len - sizeof(struct fchs_s); - bfa_trc(port->fcs, rx_len); - bfa_trc(port->fcs, pyld_len); - - if (pyld_len > len) - memcpy(((u8 *) bfa_fcxp_get_reqbuf(fcxp)) + - sizeof(struct fc_echo_s), (echo + 1), - (pyld_len - sizeof(struct fc_echo_s))); - - bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, pyld_len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - -/* - * Process incoming RNID. - * Since it does not require a login, it is processed here. - */ -static void -bfa_fcs_lport_rnid(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs, - struct fc_rnid_cmd_s *rnid, u16 rx_len) -{ - struct fc_rnid_common_id_data_s common_id_data; - struct fc_rnid_general_topology_data_s gen_topo_data; - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - u16 len; - u32 data_format; - - bfa_trc(port->fcs, rx_fchs->s_id); - bfa_trc(port->fcs, rx_fchs->d_id); - bfa_trc(port->fcs, rx_len); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - /* - * Check Node Indentification Data Format - * We only support General Topology Discovery Format. - * For any other requested Data Formats, we return Common Node Id Data - * only, as per FC-LS. - */ - bfa_trc(port->fcs, rnid->node_id_data_format); - if (rnid->node_id_data_format == RNID_NODEID_DATA_FORMAT_DISCOVERY) { - data_format = RNID_NODEID_DATA_FORMAT_DISCOVERY; - /* - * Get General topology data for this port - */ - bfa_fs_port_get_gen_topo_data(port, &gen_topo_data); - } else { - data_format = RNID_NODEID_DATA_FORMAT_COMMON; - } - - /* - * Copy the Node Id Info - */ - common_id_data.port_name = bfa_fcs_lport_get_pwwn(port); - common_id_data.node_name = bfa_fcs_lport_get_nwwn(port); - - len = fc_rnid_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, data_format, &common_id_data, - &gen_topo_data); - - bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - -/* - * Fill out General Topolpgy Discovery Data for RNID ELS. - */ -static void -bfa_fs_port_get_gen_topo_data(struct bfa_fcs_lport_s *port, - struct fc_rnid_general_topology_data_s *gen_topo_data) -{ - memset(gen_topo_data, 0, - sizeof(struct fc_rnid_general_topology_data_s)); - - gen_topo_data->asso_type = cpu_to_be32(RNID_ASSOCIATED_TYPE_HOST); - gen_topo_data->phy_port_num = 0; /* @todo */ - gen_topo_data->num_attached_nodes = cpu_to_be32(1); -} - -static void -bfa_fcs_lport_online_actions(struct bfa_fcs_lport_s *port) -{ - struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; - char lpwwn_buf[BFA_STRING_32]; - - bfa_trc(port->fcs, port->fabric->oper_type); - - __port_action[port->fabric->fab_type].init(port); - __port_action[port->fabric->fab_type].online(port); - - wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Logical port online: WWN = %s Role = %s\n", - lpwwn_buf, "Initiator"); - bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_ONLINE); - - bfad->bfad_flags |= BFAD_PORT_ONLINE; -} - -static void -bfa_fcs_lport_offline_actions(struct bfa_fcs_lport_s *port) -{ - struct list_head *qe, *qen; - struct bfa_fcs_rport_s *rport; - struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; - char lpwwn_buf[BFA_STRING_32]; - - bfa_trc(port->fcs, port->fabric->oper_type); - - __port_action[port->fabric->fab_type].offline(port); - - wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); - if (bfa_sm_cmp_state(port->fabric, - bfa_fcs_fabric_sm_online) == BFA_TRUE) { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "Logical port lost fabric connectivity: WWN = %s Role = %s\n", - lpwwn_buf, "Initiator"); - bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DISCONNECT); - } else { - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Logical port taken offline: WWN = %s Role = %s\n", - lpwwn_buf, "Initiator"); - bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_OFFLINE); - } - - list_for_each_safe(qe, qen, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - bfa_sm_send_event(rport, RPSM_EVENT_LOGO_IMP); - } -} - -static void -bfa_fcs_lport_unknown_init(struct bfa_fcs_lport_s *port) -{ - WARN_ON(1); -} - -static void -bfa_fcs_lport_unknown_online(struct bfa_fcs_lport_s *port) -{ - WARN_ON(1); -} - -static void -bfa_fcs_lport_unknown_offline(struct bfa_fcs_lport_s *port) -{ - WARN_ON(1); -} - -static void -bfa_fcs_lport_abts_acc(struct bfa_fcs_lport_s *port, struct fchs_s *rx_fchs) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - int len; - - bfa_trc(port->fcs, rx_fchs->d_id); - bfa_trc(port->fcs, rx_fchs->s_id); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - len = fc_ba_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, 0); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} -static void -bfa_fcs_lport_deleted(struct bfa_fcs_lport_s *port) -{ - struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; - char lpwwn_buf[BFA_STRING_32]; - - wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Logical port deleted: WWN = %s Role = %s\n", - lpwwn_buf, "Initiator"); - bfa_fcs_lport_aen_post(port, BFA_LPORT_AEN_DELETE); - - /* Base port will be deleted by the OS driver */ - if (port->vport) { - bfa_fcb_lport_delete(port->fcs->bfad, port->port_cfg.roles, - port->fabric->vf_drv, - port->vport ? port->vport->vport_drv : NULL); - bfa_fcs_vport_delete_comp(port->vport); - } else { - bfa_wc_down(&port->fabric->wc); - } -} - - -/* - * Unsolicited frame receive handling. - */ -void -bfa_fcs_lport_uf_recv(struct bfa_fcs_lport_s *lport, - struct fchs_s *fchs, u16 len) -{ - u32 pid = fchs->s_id; - struct bfa_fcs_rport_s *rport = NULL; - struct fc_els_cmd_s *els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - bfa_stats(lport, uf_recvs); - bfa_trc(lport->fcs, fchs->type); - - if (!bfa_fcs_lport_is_online(lport)) { - bfa_stats(lport, uf_recv_drops); - return; - } - - /* - * First, handle ELSs that donot require a login. - */ - /* - * Handle PLOGI first - */ - if ((fchs->type == FC_TYPE_ELS) && - (els_cmd->els_code == FC_ELS_PLOGI)) { - bfa_fcs_lport_plogi(lport, fchs, (struct fc_logi_s *) els_cmd); - return; - } - - /* - * Handle ECHO separately. - */ - if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_ECHO)) { - bfa_fcs_lport_echo(lport, fchs, - (struct fc_echo_s *)els_cmd, len); - return; - } - - /* - * Handle RNID separately. - */ - if ((fchs->type == FC_TYPE_ELS) && (els_cmd->els_code == FC_ELS_RNID)) { - bfa_fcs_lport_rnid(lport, fchs, - (struct fc_rnid_cmd_s *) els_cmd, len); - return; - } - - if (fchs->type == FC_TYPE_BLS) { - if ((fchs->routing == FC_RTG_BASIC_LINK) && - (fchs->cat_info == FC_CAT_ABTS)) - bfa_fcs_lport_abts_acc(lport, fchs); - return; - } - - if (fchs->type == FC_TYPE_SERVICES) { - /* - * Unhandled FC-GS frames. Send a FC-CT Reject - */ - bfa_fcs_lport_send_fcgs_rjt(lport, fchs, CT_RSN_NOT_SUPP, - CT_NS_EXP_NOADDITIONAL); - return; - } - - /* - * look for a matching remote port ID - */ - rport = bfa_fcs_lport_get_rport_by_pid(lport, pid); - if (rport) { - bfa_trc(rport->fcs, fchs->s_id); - bfa_trc(rport->fcs, fchs->d_id); - bfa_trc(rport->fcs, fchs->type); - - bfa_fcs_rport_uf_recv(rport, fchs, len); - return; - } - - /* - * Only handles ELS frames for now. - */ - if (fchs->type != FC_TYPE_ELS) { - bfa_trc(lport->fcs, fchs->s_id); - bfa_trc(lport->fcs, fchs->d_id); - /* ignore type FC_TYPE_FC_FSS */ - if (fchs->type != FC_TYPE_FC_FSS) - bfa_sm_fault(lport->fcs, fchs->type); - return; - } - - bfa_trc(lport->fcs, els_cmd->els_code); - if (els_cmd->els_code == FC_ELS_RSCN) { - bfa_fcs_lport_scn_process_rscn(lport, fchs, len); - return; - } - - if (els_cmd->els_code == FC_ELS_LOGO) { - /* - * @todo Handle LOGO frames received. - */ - return; - } - - if (els_cmd->els_code == FC_ELS_PRLI) { - /* - * @todo Handle PRLI frames received. - */ - return; - } - - /* - * Unhandled ELS frames. Send a LS_RJT. - */ - bfa_fcs_lport_send_ls_rjt(lport, fchs, FC_LS_RJT_RSN_CMD_NOT_SUPP, - FC_LS_RJT_EXP_NO_ADDL_INFO); - -} - -/* - * PID based Lookup for a R-Port in the Port R-Port Queue - */ -struct bfa_fcs_rport_s * -bfa_fcs_lport_get_rport_by_pid(struct bfa_fcs_lport_s *port, u32 pid) -{ - struct bfa_fcs_rport_s *rport; - struct list_head *qe; - - list_for_each(qe, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - if (rport->pid == pid) - return rport; - } - - bfa_trc(port->fcs, pid); - return NULL; -} - -/* - * PWWN based Lookup for a R-Port in the Port R-Port Queue - */ -struct bfa_fcs_rport_s * -bfa_fcs_lport_get_rport_by_pwwn(struct bfa_fcs_lport_s *port, wwn_t pwwn) -{ - struct bfa_fcs_rport_s *rport; - struct list_head *qe; - - list_for_each(qe, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - if (wwn_is_equal(rport->pwwn, pwwn)) - return rport; - } - - bfa_trc(port->fcs, pwwn); - return NULL; -} - -/* - * NWWN based Lookup for a R-Port in the Port R-Port Queue - */ -struct bfa_fcs_rport_s * -bfa_fcs_lport_get_rport_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t nwwn) -{ - struct bfa_fcs_rport_s *rport; - struct list_head *qe; - - list_for_each(qe, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - if (wwn_is_equal(rport->nwwn, nwwn)) - return rport; - } - - bfa_trc(port->fcs, nwwn); - return NULL; -} - -/* - * Called by rport module when new rports are discovered. - */ -void -bfa_fcs_lport_add_rport( - struct bfa_fcs_lport_s *port, - struct bfa_fcs_rport_s *rport) -{ - list_add_tail(&rport->qe, &port->rport_q); - port->num_rports++; -} - -/* - * Called by rport module to when rports are deleted. - */ -void -bfa_fcs_lport_del_rport( - struct bfa_fcs_lport_s *port, - struct bfa_fcs_rport_s *rport) -{ - WARN_ON(!bfa_q_is_on_q(&port->rport_q, rport)); - list_del(&rport->qe); - port->num_rports--; - - bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELRPORT); -} - -/* - * Called by fabric for base port when fabric login is complete. - * Called by vport for virtual ports when FDISC is complete. - */ -void -bfa_fcs_lport_online(struct bfa_fcs_lport_s *port) -{ - bfa_sm_send_event(port, BFA_FCS_PORT_SM_ONLINE); -} - -/* - * Called by fabric for base port when fabric goes offline. - * Called by vport for virtual ports when virtual port becomes offline. - */ -void -bfa_fcs_lport_offline(struct bfa_fcs_lport_s *port) -{ - bfa_sm_send_event(port, BFA_FCS_PORT_SM_OFFLINE); -} - -/* - * Called by fabric to delete base lport and associated resources. - * - * Called by vport to delete lport and associated resources. Should call - * bfa_fcs_vport_delete_comp() for vports on completion. - */ -void -bfa_fcs_lport_delete(struct bfa_fcs_lport_s *port) -{ - bfa_sm_send_event(port, BFA_FCS_PORT_SM_DELETE); -} - -/* - * Return TRUE if port is online, else return FALSE - */ -bfa_boolean_t -bfa_fcs_lport_is_online(struct bfa_fcs_lport_s *port) -{ - return bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online); -} - -/* - * Attach time initialization of logical ports. - */ -void -bfa_fcs_lport_attach(struct bfa_fcs_lport_s *lport, struct bfa_fcs_s *fcs, - u16 vf_id, struct bfa_fcs_vport_s *vport) -{ - lport->fcs = fcs; - lport->fabric = bfa_fcs_vf_lookup(fcs, vf_id); - lport->vport = vport; - lport->lp_tag = (vport) ? vport->lps->bfa_tag : - lport->fabric->lps->bfa_tag; - - INIT_LIST_HEAD(&lport->rport_q); - lport->num_rports = 0; -} - -/* - * Logical port initialization of base or virtual port. - * Called by fabric for base port or by vport for virtual ports. - */ - -void -bfa_fcs_lport_init(struct bfa_fcs_lport_s *lport, - struct bfa_lport_cfg_s *port_cfg) -{ - struct bfa_fcs_vport_s *vport = lport->vport; - struct bfad_s *bfad = (struct bfad_s *)lport->fcs->bfad; - char lpwwn_buf[BFA_STRING_32]; - - lport->port_cfg = *port_cfg; - - lport->bfad_port = bfa_fcb_lport_new(lport->fcs->bfad, lport, - lport->port_cfg.roles, - lport->fabric->vf_drv, - vport ? vport->vport_drv : NULL); - - wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(lport)); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "New logical port created: WWN = %s Role = %s\n", - lpwwn_buf, "Initiator"); - bfa_fcs_lport_aen_post(lport, BFA_LPORT_AEN_NEW); - - bfa_sm_set_state(lport, bfa_fcs_lport_sm_uninit); - bfa_sm_send_event(lport, BFA_FCS_PORT_SM_CREATE); -} - -/* - * fcs_lport_api - */ - -void -bfa_fcs_lport_get_attr( - struct bfa_fcs_lport_s *port, - struct bfa_lport_attr_s *port_attr) -{ - if (bfa_sm_cmp_state(port, bfa_fcs_lport_sm_online)) - port_attr->pid = port->pid; - else - port_attr->pid = 0; - - port_attr->port_cfg = port->port_cfg; - - if (port->fabric) { - port_attr->port_type = port->fabric->oper_type; - port_attr->loopback = bfa_sm_cmp_state(port->fabric, - bfa_fcs_fabric_sm_loopback); - port_attr->authfail = - bfa_sm_cmp_state(port->fabric, - bfa_fcs_fabric_sm_auth_failed); - port_attr->fabric_name = bfa_fcs_lport_get_fabric_name(port); - memcpy(port_attr->fabric_ip_addr, - bfa_fcs_lport_get_fabric_ipaddr(port), - BFA_FCS_FABRIC_IPADDR_SZ); - - if (port->vport != NULL) { - port_attr->port_type = BFA_PORT_TYPE_VPORT; - port_attr->fpma_mac = - port->vport->lps->lp_mac; - } else { - port_attr->fpma_mac = - port->fabric->lps->lp_mac; - } - } else { - port_attr->port_type = BFA_PORT_TYPE_UNKNOWN; - port_attr->state = BFA_LPORT_UNINIT; - } -} - -/* - * bfa_fcs_lport_fab port fab functions - */ - -/* - * Called by port to initialize fabric services of the base port. - */ -static void -bfa_fcs_lport_fab_init(struct bfa_fcs_lport_s *port) -{ - bfa_fcs_lport_ns_init(port); - bfa_fcs_lport_scn_init(port); - bfa_fcs_lport_ms_init(port); -} - -/* - * Called by port to notify transition to online state. - */ -static void -bfa_fcs_lport_fab_online(struct bfa_fcs_lport_s *port) -{ - bfa_fcs_lport_ns_online(port); - bfa_fcs_lport_scn_online(port); -} - -/* - * Called by port to notify transition to offline state. - */ -static void -bfa_fcs_lport_fab_offline(struct bfa_fcs_lport_s *port) -{ - bfa_fcs_lport_ns_offline(port); - bfa_fcs_lport_scn_offline(port); - bfa_fcs_lport_ms_offline(port); -} - -/* - * bfa_fcs_lport_n2n functions - */ - -/* - * Called by fcs/port to initialize N2N topology. - */ -static void -bfa_fcs_lport_n2n_init(struct bfa_fcs_lport_s *port) -{ -} - -/* - * Called by fcs/port to notify transition to online state. - */ -static void -bfa_fcs_lport_n2n_online(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_n2n_s *n2n_port = &port->port_topo.pn2n; - struct bfa_lport_cfg_s *pcfg = &port->port_cfg; - struct bfa_fcs_rport_s *rport; - - bfa_trc(port->fcs, pcfg->pwwn); - - /* - * If our PWWN is > than that of the r-port, we have to initiate PLOGI - * and assign an Address. if not, we need to wait for its PLOGI. - * - * If our PWWN is < than that of the remote port, it will send a PLOGI - * with the PIDs assigned. The rport state machine take care of this - * incoming PLOGI. - */ - if (memcmp - ((void *)&pcfg->pwwn, (void *)&n2n_port->rem_port_wwn, - sizeof(wwn_t)) > 0) { - port->pid = N2N_LOCAL_PID; - bfa_lps_set_n2n_pid(port->fabric->lps, N2N_LOCAL_PID); - /* - * First, check if we know the device by pwwn. - */ - rport = bfa_fcs_lport_get_rport_by_pwwn(port, - n2n_port->rem_port_wwn); - if (rport) { - bfa_trc(port->fcs, rport->pid); - bfa_trc(port->fcs, rport->pwwn); - rport->pid = N2N_REMOTE_PID; - bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND); - return; - } - - /* - * In n2n there can be only one rport. Delete the old one - * whose pid should be zero, because it is offline. - */ - if (port->num_rports > 0) { - rport = bfa_fcs_lport_get_rport_by_pid(port, 0); - WARN_ON(rport == NULL); - if (rport) { - bfa_trc(port->fcs, rport->pwwn); - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - } - } - bfa_fcs_rport_create(port, N2N_REMOTE_PID); - } -} - -/* - * Called by fcs/port to notify transition to offline state. - */ -static void -bfa_fcs_lport_n2n_offline(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_n2n_s *n2n_port = &port->port_topo.pn2n; - - bfa_trc(port->fcs, port->pid); - port->pid = 0; - n2n_port->rem_port_wwn = 0; - n2n_port->reply_oxid = 0; -} - -#define BFA_FCS_FDMI_CMD_MAX_RETRIES 2 - -/* - * forward declarations - */ -static void bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_fdmi_rpa_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_fdmi_timeout(void *arg); -static u16 bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, - u8 *pyld); -static u16 bfa_fcs_lport_fdmi_build_rprt_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, - u8 *pyld); -static u16 bfa_fcs_lport_fdmi_build_rpa_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, - u8 *pyld); -static u16 bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s * - fdmi, u8 *pyld); -static void bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi, - struct bfa_fcs_fdmi_hba_attr_s *hba_attr); -static void bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, - struct bfa_fcs_fdmi_port_attr_s *port_attr); -u32 bfa_fcs_fdmi_convert_speed(enum bfa_port_speed pport_speed); - -/* - * fcs_fdmi_sm FCS FDMI state machine - */ - -/* - * FDMI State Machine events - */ -enum port_fdmi_event { - FDMISM_EVENT_PORT_ONLINE = 1, - FDMISM_EVENT_PORT_OFFLINE = 2, - FDMISM_EVENT_RSP_OK = 4, - FDMISM_EVENT_RSP_ERROR = 5, - FDMISM_EVENT_TIMEOUT = 6, - FDMISM_EVENT_RHBA_SENT = 7, - FDMISM_EVENT_RPRT_SENT = 8, - FDMISM_EVENT_RPA_SENT = 9, -}; - -static void bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_sending_rhba( - struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_rhba(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_rhba_retry( - struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_sending_rprt( - struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_rprt(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_rprt_retry( - struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_sending_rpa( - struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_rpa(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_rpa_retry( - struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -static void bfa_fcs_lport_fdmi_sm_disabled( - struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event); -/* - * Start in offline state - awaiting MS to send start. - */ -static void -bfa_fcs_lport_fdmi_sm_offline(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - fdmi->retry_cnt = 0; - - switch (event) { - case FDMISM_EVENT_PORT_ONLINE: - if (port->vport) { - /* - * For Vports, register a new port. - */ - bfa_sm_set_state(fdmi, - bfa_fcs_lport_fdmi_sm_sending_rprt); - bfa_fcs_lport_fdmi_send_rprt(fdmi, NULL); - } else { - /* - * For a base port, we should first register the HBA - * attribute. The HBA attribute also contains the base - * port registration. - */ - bfa_sm_set_state(fdmi, - bfa_fcs_lport_fdmi_sm_sending_rhba); - bfa_fcs_lport_fdmi_send_rhba(fdmi, NULL); - } - break; - - case FDMISM_EVENT_PORT_OFFLINE: - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_fdmi_sm_sending_rhba(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RHBA_SENT: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rhba); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->fcxp_wqe); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_fdmi_sm_rhba(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RSP_ERROR: - /* - * if max retries have not been reached, start timer for a - * delayed retry - */ - if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { - bfa_sm_set_state(fdmi, - bfa_fcs_lport_fdmi_sm_rhba_retry); - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->timer, - bfa_fcs_lport_fdmi_timeout, fdmi, - BFA_FCS_RETRY_TIMEOUT); - } else { - /* - * set state to offline - */ - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - } - break; - - case FDMISM_EVENT_RSP_OK: - /* - * Initiate Register Port Attributes - */ - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rpa); - fdmi->retry_cnt = 0; - bfa_fcs_lport_fdmi_send_rpa(fdmi, NULL); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_fcxp_discard(fdmi->fcxp); - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_fdmi_sm_rhba_retry(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rhba); - bfa_fcs_lport_fdmi_send_rhba(fdmi, NULL); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - bfa_timer_stop(&fdmi->timer); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -/* -* RPRT : Register Port - */ -static void -bfa_fcs_lport_fdmi_sm_sending_rprt(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RPRT_SENT: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rprt); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->fcxp_wqe); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_fdmi_sm_rprt(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RSP_ERROR: - /* - * if max retries have not been reached, start timer for a - * delayed retry - */ - if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { - bfa_sm_set_state(fdmi, - bfa_fcs_lport_fdmi_sm_rprt_retry); - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->timer, - bfa_fcs_lport_fdmi_timeout, fdmi, - BFA_FCS_RETRY_TIMEOUT); - - } else { - /* - * set state to offline - */ - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - fdmi->retry_cnt = 0; - } - break; - - case FDMISM_EVENT_RSP_OK: - fdmi->retry_cnt = 0; - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_online); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_fcxp_discard(fdmi->fcxp); - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_fdmi_sm_rprt_retry(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rprt); - bfa_fcs_lport_fdmi_send_rprt(fdmi, NULL); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - bfa_timer_stop(&fdmi->timer); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -/* - * Register Port Attributes - */ -static void -bfa_fcs_lport_fdmi_sm_sending_rpa(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RPA_SENT: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rpa); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->fcxp_wqe); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_fdmi_sm_rpa(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_RSP_ERROR: - /* - * if max retries have not been reached, start timer for a - * delayed retry - */ - if (fdmi->retry_cnt++ < BFA_FCS_FDMI_CMD_MAX_RETRIES) { - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_rpa_retry); - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(port), - &fdmi->timer, - bfa_fcs_lport_fdmi_timeout, fdmi, - BFA_FCS_RETRY_TIMEOUT); - } else { - /* - * set state to offline - */ - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - fdmi->retry_cnt = 0; - } - break; - - case FDMISM_EVENT_RSP_OK: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_online); - fdmi->retry_cnt = 0; - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_fcxp_discard(fdmi->fcxp); - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_fdmi_sm_rpa_retry(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_sending_rpa); - bfa_fcs_lport_fdmi_send_rpa(fdmi, NULL); - break; - - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - bfa_timer_stop(&fdmi->timer); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_fdmi_sm_online(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - switch (event) { - case FDMISM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} -/* - * FDMI is disabled state. - */ -static void -bfa_fcs_lport_fdmi_sm_disabled(struct bfa_fcs_lport_fdmi_s *fdmi, - enum port_fdmi_event event) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - bfa_trc(port->fcs, event); - - /* No op State. It can only be enabled at Driver Init. */ -} - -/* -* RHBA : Register HBA Attributes. - */ -static void -bfa_fcs_lport_fdmi_send_rhba(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg; - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct fchs_s fchs; - int len, attr_len; - struct bfa_fcxp_s *fcxp; - u8 *pyld; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, - bfa_fcs_lport_fdmi_send_rhba, fdmi); - return; - } - fdmi->fcxp = fcxp; - - pyld = bfa_fcxp_get_reqbuf(fcxp); - memset(pyld, 0, FC_MAX_PDUSZ); - - len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port), - FDMI_RHBA); - - attr_len = - bfa_fcs_lport_fdmi_build_rhba_pyld(fdmi, - (u8 *) ((struct ct_hdr_s *) pyld - + 1)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, (len + attr_len), &fchs, - bfa_fcs_lport_fdmi_rhba_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(fdmi, FDMISM_EVENT_RHBA_SENT); -} - -static u16 -bfa_fcs_lport_fdmi_build_rhba_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct bfa_fcs_fdmi_hba_attr_s hba_attr; - struct bfa_fcs_fdmi_hba_attr_s *fcs_hba_attr = &hba_attr; - struct fdmi_rhba_s *rhba = (struct fdmi_rhba_s *) pyld; - struct fdmi_attr_s *attr; - u8 *curr_ptr; - u16 len, count; - u16 templen; - - /* - * get hba attributes - */ - bfa_fcs_fdmi_get_hbaattr(fdmi, fcs_hba_attr); - - rhba->hba_id = bfa_fcs_lport_get_pwwn(port); - rhba->port_list.num_ports = cpu_to_be32(1); - rhba->port_list.port_entry = bfa_fcs_lport_get_pwwn(port); - - len = sizeof(rhba->hba_id) + sizeof(rhba->port_list); - - count = 0; - len += sizeof(rhba->hba_attr_blk.attr_count); - - /* - * fill out the invididual entries of the HBA attrib Block - */ - curr_ptr = (u8 *) &rhba->hba_attr_blk.hba_attr; - - /* - * Node Name - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_NODENAME); - templen = sizeof(wwn_t); - memcpy(attr->value, &bfa_fcs_lport_get_nwwn(port), templen); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * Manufacturer - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MANUFACTURER); - templen = (u16) strlen(fcs_hba_attr->manufacturer); - memcpy(attr->value, fcs_hba_attr->manufacturer, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * Serial Number - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_SERIALNUM); - templen = (u16) strlen(fcs_hba_attr->serial_num); - memcpy(attr->value, fcs_hba_attr->serial_num, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * Model - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL); - templen = (u16) strlen(fcs_hba_attr->model); - memcpy(attr->value, fcs_hba_attr->model, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * Model Desc - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MODEL_DESC); - templen = (u16) strlen(fcs_hba_attr->model_desc); - memcpy(attr->value, fcs_hba_attr->model_desc, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * H/W Version - */ - if (fcs_hba_attr->hw_version[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_HW_VERSION); - templen = (u16) strlen(fcs_hba_attr->hw_version); - memcpy(attr->value, fcs_hba_attr->hw_version, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - } - - /* - * Driver Version - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_DRIVER_VERSION); - templen = (u16) strlen(fcs_hba_attr->driver_version); - memcpy(attr->value, fcs_hba_attr->driver_version, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * Option Rom Version - */ - if (fcs_hba_attr->option_rom_ver[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_ROM_VERSION); - templen = (u16) strlen(fcs_hba_attr->option_rom_ver); - memcpy(attr->value, fcs_hba_attr->option_rom_ver, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - } - - /* - * f/w Version = driver version - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_FW_VERSION); - templen = (u16) strlen(fcs_hba_attr->driver_version); - memcpy(attr->value, fcs_hba_attr->driver_version, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * OS Name - */ - if (fcs_hba_attr->os_name[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_OS_NAME); - templen = (u16) strlen(fcs_hba_attr->os_name); - memcpy(attr->value, fcs_hba_attr->os_name, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - } - - /* - * MAX_CT_PAYLOAD - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_HBA_ATTRIB_MAX_CT); - templen = sizeof(fcs_hba_attr->max_ct_pyld); - memcpy(attr->value, &fcs_hba_attr->max_ct_pyld, templen); - len += templen; - count++; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * Update size of payload - */ - len += ((sizeof(attr->type) + sizeof(attr->len)) * count); - - rhba->hba_attr_blk.attr_count = cpu_to_be32(count); - return len; -} - -static void -bfa_fcs_lport_fdmi_rhba_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = - (struct bfa_fcs_lport_fdmi_s *) cbarg; - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); -} - -/* -* RPRT : Register Port - */ -static void -bfa_fcs_lport_fdmi_send_rprt(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg; - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct fchs_s fchs; - u16 len, attr_len; - struct bfa_fcxp_s *fcxp; - u8 *pyld; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, - bfa_fcs_lport_fdmi_send_rprt, fdmi); - return; - } - fdmi->fcxp = fcxp; - - pyld = bfa_fcxp_get_reqbuf(fcxp); - memset(pyld, 0, FC_MAX_PDUSZ); - - len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port), - FDMI_RPRT); - - attr_len = - bfa_fcs_lport_fdmi_build_rprt_pyld(fdmi, - (u8 *) ((struct ct_hdr_s *) pyld - + 1)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len + attr_len, &fchs, - bfa_fcs_lport_fdmi_rprt_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(fdmi, FDMISM_EVENT_RPRT_SENT); -} - -/* - * This routine builds Port Attribute Block that used in RPA, RPRT commands. - */ -static u16 -bfa_fcs_lport_fdmi_build_portattr_block(struct bfa_fcs_lport_fdmi_s *fdmi, - u8 *pyld) -{ - struct bfa_fcs_fdmi_port_attr_s fcs_port_attr; - struct fdmi_port_attr_s *port_attrib = (struct fdmi_port_attr_s *) pyld; - struct fdmi_attr_s *attr; - u8 *curr_ptr; - u16 len; - u8 count = 0; - u16 templen; - - /* - * get port attributes - */ - bfa_fcs_fdmi_get_portattr(fdmi, &fcs_port_attr); - - len = sizeof(port_attrib->attr_count); - - /* - * fill out the invididual entries - */ - curr_ptr = (u8 *) &port_attrib->port_attr; - - /* - * FC4 Types - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FC4_TYPES); - templen = sizeof(fcs_port_attr.supp_fc4_types); - memcpy(attr->value, fcs_port_attr.supp_fc4_types, templen); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - ++count; - attr->len = - cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * Supported Speed - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_SUPP_SPEED); - templen = sizeof(fcs_port_attr.supp_speed); - memcpy(attr->value, &fcs_port_attr.supp_speed, templen); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - ++count; - attr->len = - cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * current Port Speed - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_PORT_SPEED); - templen = sizeof(fcs_port_attr.curr_speed); - memcpy(attr->value, &fcs_port_attr.curr_speed, templen); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - ++count; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * max frame size - */ - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_FRAME_SIZE); - templen = sizeof(fcs_port_attr.max_frm_size); - memcpy(attr->value, &fcs_port_attr.max_frm_size, templen); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - ++count; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - - /* - * OS Device Name - */ - if (fcs_port_attr.os_device_name[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_DEV_NAME); - templen = (u16) strlen(fcs_port_attr.os_device_name); - memcpy(attr->value, fcs_port_attr.os_device_name, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - ++count; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - } - /* - * Host Name - */ - if (fcs_port_attr.host_name[0] != '\0') { - attr = (struct fdmi_attr_s *) curr_ptr; - attr->type = cpu_to_be16(FDMI_PORT_ATTRIB_HOST_NAME); - templen = (u16) strlen(fcs_port_attr.host_name); - memcpy(attr->value, fcs_port_attr.host_name, templen); - templen = fc_roundup(templen, sizeof(u32)); - curr_ptr += sizeof(attr->type) + sizeof(templen) + templen; - len += templen; - ++count; - attr->len = cpu_to_be16(templen + sizeof(attr->type) + - sizeof(templen)); - } - - /* - * Update size of payload - */ - port_attrib->attr_count = cpu_to_be32(count); - len += ((sizeof(attr->type) + sizeof(attr->len)) * count); - return len; -} - -static u16 -bfa_fcs_lport_fdmi_build_rprt_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct fdmi_rprt_s *rprt = (struct fdmi_rprt_s *) pyld; - u16 len; - - rprt->hba_id = bfa_fcs_lport_get_pwwn(bfa_fcs_get_base_port(port->fcs)); - rprt->port_name = bfa_fcs_lport_get_pwwn(port); - - len = bfa_fcs_lport_fdmi_build_portattr_block(fdmi, - (u8 *) &rprt->port_attr_blk); - - len += sizeof(rprt->hba_id) + sizeof(rprt->port_name); - - return len; -} - -static void -bfa_fcs_lport_fdmi_rprt_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = - (struct bfa_fcs_lport_fdmi_s *) cbarg; - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); -} - -/* -* RPA : Register Port Attributes. - */ -static void -bfa_fcs_lport_fdmi_send_rpa(void *fdmi_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = fdmi_cbarg; - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct fchs_s fchs; - u16 len, attr_len; - struct bfa_fcxp_s *fcxp; - u8 *pyld; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &fdmi->fcxp_wqe, - bfa_fcs_lport_fdmi_send_rpa, fdmi); - return; - } - fdmi->fcxp = fcxp; - - pyld = bfa_fcxp_get_reqbuf(fcxp); - memset(pyld, 0, FC_MAX_PDUSZ); - - len = fc_fdmi_reqhdr_build(&fchs, pyld, bfa_fcs_lport_get_fcid(port), - FDMI_RPA); - - attr_len = bfa_fcs_lport_fdmi_build_rpa_pyld(fdmi, - (u8 *) ((struct ct_hdr_s *) pyld + 1)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len + attr_len, &fchs, - bfa_fcs_lport_fdmi_rpa_response, (void *)fdmi, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(fdmi, FDMISM_EVENT_RPA_SENT); -} - -static u16 -bfa_fcs_lport_fdmi_build_rpa_pyld(struct bfa_fcs_lport_fdmi_s *fdmi, u8 *pyld) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct fdmi_rpa_s *rpa = (struct fdmi_rpa_s *) pyld; - u16 len; - - rpa->port_name = bfa_fcs_lport_get_pwwn(port); - - len = bfa_fcs_lport_fdmi_build_portattr_block(fdmi, - (u8 *) &rpa->port_attr_blk); - - len += sizeof(rpa->port_name); - - return len; -} - -static void -bfa_fcs_lport_fdmi_rpa_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = - (struct bfa_fcs_lport_fdmi_s *) cbarg; - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(fdmi, FDMISM_EVENT_RSP_ERROR); -} - -static void -bfa_fcs_lport_fdmi_timeout(void *arg) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = (struct bfa_fcs_lport_fdmi_s *) arg; - - bfa_sm_send_event(fdmi, FDMISM_EVENT_TIMEOUT); -} - -static void -bfa_fcs_fdmi_get_hbaattr(struct bfa_fcs_lport_fdmi_s *fdmi, - struct bfa_fcs_fdmi_hba_attr_s *hba_attr) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; - - memset(hba_attr, 0, sizeof(struct bfa_fcs_fdmi_hba_attr_s)); - - bfa_ioc_get_adapter_manufacturer(&port->fcs->bfa->ioc, - hba_attr->manufacturer); - bfa_ioc_get_adapter_serial_num(&port->fcs->bfa->ioc, - hba_attr->serial_num); - bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc, - hba_attr->model); - bfa_ioc_get_adapter_model(&port->fcs->bfa->ioc, - hba_attr->model_desc); - bfa_ioc_get_pci_chip_rev(&port->fcs->bfa->ioc, - hba_attr->hw_version); - bfa_ioc_get_adapter_optrom_ver(&port->fcs->bfa->ioc, - hba_attr->option_rom_ver); - bfa_ioc_get_adapter_fw_ver(&port->fcs->bfa->ioc, - hba_attr->fw_version); - - strncpy(hba_attr->driver_version, (char *)driver_info->version, - sizeof(hba_attr->driver_version)); - - strncpy(hba_attr->os_name, driver_info->host_os_name, - sizeof(hba_attr->os_name)); - - /* - * If there is a patch level, append it - * to the os name along with a separator - */ - if (driver_info->host_os_patch[0] != '\0') { - strncat(hba_attr->os_name, BFA_FCS_PORT_SYMBNAME_SEPARATOR, - sizeof(BFA_FCS_PORT_SYMBNAME_SEPARATOR)); - strncat(hba_attr->os_name, driver_info->host_os_patch, - sizeof(driver_info->host_os_patch)); - } - - hba_attr->max_ct_pyld = cpu_to_be32(FC_MAX_PDUSZ); -} - -static void -bfa_fcs_fdmi_get_portattr(struct bfa_fcs_lport_fdmi_s *fdmi, - struct bfa_fcs_fdmi_port_attr_s *port_attr) -{ - struct bfa_fcs_lport_s *port = fdmi->ms->port; - struct bfa_fcs_driver_info_s *driver_info = &port->fcs->driver_info; - struct bfa_port_attr_s pport_attr; - - memset(port_attr, 0, sizeof(struct bfa_fcs_fdmi_port_attr_s)); - - /* - * get pport attributes from hal - */ - bfa_fcport_get_attr(port->fcs->bfa, &pport_attr); - - /* - * get FC4 type Bitmask - */ - fc_get_fc4type_bitmask(FC_TYPE_FCP, port_attr->supp_fc4_types); - - /* - * Supported Speeds - */ - switch (pport_attr.speed_supported) { - case BFA_PORT_SPEED_16GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_16G); - break; - - case BFA_PORT_SPEED_10GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_10G); - break; - - case BFA_PORT_SPEED_8GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_8G); - break; - - case BFA_PORT_SPEED_4GBPS: - port_attr->supp_speed = - cpu_to_be32(BFA_FCS_FDMI_SUPP_SPEEDS_4G); - break; - - default: - bfa_sm_fault(port->fcs, pport_attr.speed_supported); - } - - /* - * Current Speed - */ - port_attr->curr_speed = cpu_to_be32( - bfa_fcs_fdmi_convert_speed(pport_attr.speed)); - - /* - * Max PDU Size. - */ - port_attr->max_frm_size = cpu_to_be32(FC_MAX_PDUSZ); - - /* - * OS device Name - */ - strncpy(port_attr->os_device_name, (char *)driver_info->os_device_name, - sizeof(port_attr->os_device_name)); - - /* - * Host name - */ - strncpy(port_attr->host_name, (char *)driver_info->host_machine_name, - sizeof(port_attr->host_name)); - -} - -/* - * Convert BFA speed to FDMI format. - */ -u32 -bfa_fcs_fdmi_convert_speed(bfa_port_speed_t pport_speed) -{ - u32 ret; - - switch (pport_speed) { - case BFA_PORT_SPEED_1GBPS: - case BFA_PORT_SPEED_2GBPS: - ret = pport_speed; - break; - - case BFA_PORT_SPEED_4GBPS: - ret = FDMI_TRANS_SPEED_4G; - break; - - case BFA_PORT_SPEED_8GBPS: - ret = FDMI_TRANS_SPEED_8G; - break; - - case BFA_PORT_SPEED_10GBPS: - ret = FDMI_TRANS_SPEED_10G; - break; - - case BFA_PORT_SPEED_16GBPS: - ret = FDMI_TRANS_SPEED_16G; - break; - - default: - ret = FDMI_TRANS_SPEED_UNKNOWN; - } - return ret; -} - -void -bfa_fcs_lport_fdmi_init(struct bfa_fcs_lport_ms_s *ms) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi; - - fdmi->ms = ms; - if (ms->port->fcs->fdmi_enabled) - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_offline); - else - bfa_sm_set_state(fdmi, bfa_fcs_lport_fdmi_sm_disabled); -} - -void -bfa_fcs_lport_fdmi_offline(struct bfa_fcs_lport_ms_s *ms) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi; - - fdmi->ms = ms; - bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_OFFLINE); -} - -void -bfa_fcs_lport_fdmi_online(struct bfa_fcs_lport_ms_s *ms) -{ - struct bfa_fcs_lport_fdmi_s *fdmi = &ms->fdmi; - - fdmi->ms = ms; - bfa_sm_send_event(fdmi, FDMISM_EVENT_PORT_ONLINE); -} - -#define BFA_FCS_MS_CMD_MAX_RETRIES 2 - -/* - * forward declarations - */ -static void bfa_fcs_lport_ms_send_plogi(void *ms_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_ms_timeout(void *arg); -static void bfa_fcs_lport_ms_plogi_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); - -static void bfa_fcs_lport_ms_send_gmal(void *ms_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_ms_gmal_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_ms_send_gfn(void *ms_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_ms_gfn_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -/* - * fcs_ms_sm FCS MS state machine - */ - -/* - * MS State Machine events - */ -enum port_ms_event { - MSSM_EVENT_PORT_ONLINE = 1, - MSSM_EVENT_PORT_OFFLINE = 2, - MSSM_EVENT_RSP_OK = 3, - MSSM_EVENT_RSP_ERROR = 4, - MSSM_EVENT_TIMEOUT = 5, - MSSM_EVENT_FCXP_SENT = 6, - MSSM_EVENT_PORT_FABRIC_RSCN = 7 -}; - -static void bfa_fcs_lport_ms_sm_offline(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_plogi_sending(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_plogi(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_plogi_retry(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_gmal_sending(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_gmal(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_gmal_retry(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_gfn_sending(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_gfn(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -static void bfa_fcs_lport_ms_sm_online(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event); -/* - * Start in offline state - awaiting NS to send start. - */ -static void -bfa_fcs_lport_ms_sm_offline(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_PORT_ONLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_sending); - bfa_fcs_lport_ms_send_plogi(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_plogi_sending(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_FCXP_SENT: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->fcxp_wqe); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_plogi(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_retry); - ms->port->stats.ms_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->timer, bfa_fcs_lport_ms_timeout, ms, - BFA_FCS_RETRY_TIMEOUT); - break; - - case MSSM_EVENT_RSP_OK: - /* - * since plogi is done, now invoke MS related sub-modules - */ - bfa_fcs_lport_fdmi_online(ms); - - /* - * if this is a Vport, go to online state. - */ - if (ms->port->vport) { - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online); - break; - } - - /* - * For a base port we need to get the - * switch's IP address. - */ - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_sending); - bfa_fcs_lport_ms_send_gmal(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_fcxp_discard(ms->fcxp); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_plogi_retry(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_plogi_sending); - bfa_fcs_lport_ms_send_plogi(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_timer_stop(&ms->timer); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_online(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - break; - - case MSSM_EVENT_PORT_FABRIC_RSCN: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending); - ms->retry_cnt = 0; - bfa_fcs_lport_ms_send_gfn(ms, NULL); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_gmal_sending(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_FCXP_SENT: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->fcxp_wqe); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_gmal(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_retry); - ms->port->stats.ms_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->timer, bfa_fcs_lport_ms_timeout, ms, - BFA_FCS_RETRY_TIMEOUT); - } else { - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending); - bfa_fcs_lport_ms_send_gfn(ms, NULL); - ms->retry_cnt = 0; - } - break; - - case MSSM_EVENT_RSP_OK: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending); - bfa_fcs_lport_ms_send_gfn(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_fcxp_discard(ms->fcxp); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_gmal_retry(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gmal_sending); - bfa_fcs_lport_ms_send_gmal(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_timer_stop(&ms->timer); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} -/* - * ms_pvt MS local functions - */ - -static void -bfa_fcs_lport_ms_send_gmal(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_ms_s *ms = ms_cbarg; - bfa_fcs_lport_t *port = ms->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, - bfa_fcs_lport_ms_send_gmal, ms); - return; - } - ms->fcxp = fcxp; - - len = fc_gmal_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_lport_get_fcid(port), - port->fabric->lps->pr_nwwn); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_ms_gmal_response, (void *)ms, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_lport_ms_gmal_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg; - bfa_fcs_lport_t *port = ms->port; - struct ct_hdr_s *cthdr = NULL; - struct fcgs_gmal_resp_s *gmal_resp; - struct fcgs_gmal_entry_s *gmal_entry; - u32 num_entries; - u8 *rsp_str; - - bfa_trc(port->fcs, req_status); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - gmal_resp = (struct fcgs_gmal_resp_s *)(cthdr + 1); - - num_entries = be32_to_cpu(gmal_resp->ms_len); - if (num_entries == 0) { - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - return; - } - /* - * The response could contain multiple Entries. - * Entries for SNMP interface, etc. - * We look for the entry with a telnet prefix. - * First "http://" entry refers to IP addr - */ - - gmal_entry = (struct fcgs_gmal_entry_s *)gmal_resp->ms_ma; - while (num_entries > 0) { - if (strncmp(gmal_entry->prefix, - CT_GMAL_RESP_PREFIX_HTTP, - sizeof(gmal_entry->prefix)) == 0) { - - /* - * if the IP address is terminating with a '/', - * remove it. - * Byte 0 consists of the length of the string. - */ - rsp_str = &(gmal_entry->prefix[0]); - if (rsp_str[gmal_entry->len-1] == '/') - rsp_str[gmal_entry->len-1] = 0; - - /* copy IP Address to fabric */ - strncpy(bfa_fcs_lport_get_fabric_ipaddr(port), - gmal_entry->ip_addr, - BFA_FCS_FABRIC_IPADDR_SZ); - break; - } else { - --num_entries; - ++gmal_entry; - } - } - - bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); -} - -static void -bfa_fcs_lport_ms_sm_gfn_sending(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_FCXP_SENT: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->fcxp_wqe); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_gfn(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - if (ms->retry_cnt++ < BFA_FCS_MS_CMD_MAX_RETRIES) { - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_retry); - ms->port->stats.ms_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ms->port), - &ms->timer, bfa_fcs_lport_ms_timeout, ms, - BFA_FCS_RETRY_TIMEOUT); - } else { - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online); - ms->retry_cnt = 0; - } - break; - - case MSSM_EVENT_RSP_OK: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_online); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_fcxp_discard(ms->fcxp); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ms_sm_gfn_retry(struct bfa_fcs_lport_ms_s *ms, - enum port_ms_event event) -{ - bfa_trc(ms->port->fcs, ms->port->port_cfg.pwwn); - bfa_trc(ms->port->fcs, event); - - switch (event) { - case MSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_gfn_sending); - bfa_fcs_lport_ms_send_gfn(ms, NULL); - break; - - case MSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - bfa_timer_stop(&ms->timer); - break; - - default: - bfa_sm_fault(ms->port->fcs, event); - } -} -/* - * ms_pvt MS local functions - */ - -static void -bfa_fcs_lport_ms_send_gfn(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_ms_s *ms = ms_cbarg; - bfa_fcs_lport_t *port = ms->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, - bfa_fcs_lport_ms_send_gfn, ms); - return; - } - ms->fcxp = fcxp; - - len = fc_gfn_req_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_lport_get_fcid(port), - port->fabric->lps->pr_nwwn); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_ms_gfn_response, (void *)ms, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_lport_ms_gfn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg; - bfa_fcs_lport_t *port = ms->port; - struct ct_hdr_s *cthdr = NULL; - wwn_t *gfn_resp; - - bfa_trc(port->fcs, req_status); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - gfn_resp = (wwn_t *)(cthdr + 1); - /* check if it has actually changed */ - if ((memcmp((void *)&bfa_fcs_lport_get_fabric_name(port), - gfn_resp, sizeof(wwn_t)) != 0)) { - bfa_fcs_fabric_set_fabric_name(port->fabric, *gfn_resp); - } - bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); - return; - } - - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); -} - -/* - * ms_pvt MS local functions - */ - -static void -bfa_fcs_lport_ms_send_plogi(void *ms_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_ms_s *ms = ms_cbarg; - struct bfa_fcs_lport_s *port = ms->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ms_plogi_alloc_wait++; - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ms->fcxp_wqe, - bfa_fcs_lport_ms_send_plogi, ms); - return; - } - ms->fcxp = fcxp; - - len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_hton3b(FC_MGMT_SERVER), - bfa_fcs_lport_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_ms_plogi_response, (void *)ms, - FC_MAX_PDUSZ, FC_ELS_TOV); - - port->stats.ms_plogi_sent++; - bfa_sm_send_event(ms, MSSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_lport_ms_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) cbarg; - struct bfa_fcs_lport_s *port = ms->port; - struct fc_els_cmd_s *els_cmd; - struct fc_ls_rjt_s *ls_rjt; - - bfa_trc(port->fcs, req_status); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - port->stats.ms_plogi_rsp_err++; - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - return; - } - - els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); - - switch (els_cmd->els_code) { - - case FC_ELS_ACC: - if (rsp_len < sizeof(struct fc_logi_s)) { - bfa_trc(port->fcs, rsp_len); - port->stats.ms_plogi_acc_err++; - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - break; - } - port->stats.ms_plogi_accepts++; - bfa_sm_send_event(ms, MSSM_EVENT_RSP_OK); - break; - - case FC_ELS_LS_RJT: - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - - bfa_trc(port->fcs, ls_rjt->reason_code); - bfa_trc(port->fcs, ls_rjt->reason_code_expl); - - port->stats.ms_rejects++; - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - break; - - default: - port->stats.ms_plogi_unknown_rsp++; - bfa_trc(port->fcs, els_cmd->els_code); - bfa_sm_send_event(ms, MSSM_EVENT_RSP_ERROR); - } -} - -static void -bfa_fcs_lport_ms_timeout(void *arg) -{ - struct bfa_fcs_lport_ms_s *ms = (struct bfa_fcs_lport_ms_s *) arg; - - ms->port->stats.ms_timeouts++; - bfa_sm_send_event(ms, MSSM_EVENT_TIMEOUT); -} - - -void -bfa_fcs_lport_ms_init(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); - - ms->port = port; - bfa_sm_set_state(ms, bfa_fcs_lport_ms_sm_offline); - - /* - * Invoke init routines of sub modules. - */ - bfa_fcs_lport_fdmi_init(ms); -} - -void -bfa_fcs_lport_ms_offline(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); - - ms->port = port; - bfa_sm_send_event(ms, MSSM_EVENT_PORT_OFFLINE); - bfa_fcs_lport_fdmi_offline(ms); -} - -void -bfa_fcs_lport_ms_online(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); - - ms->port = port; - bfa_sm_send_event(ms, MSSM_EVENT_PORT_ONLINE); -} -void -bfa_fcs_lport_ms_fabric_rscn(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_ms_s *ms = BFA_FCS_GET_MS_FROM_PORT(port); - - /* todo. Handle this only when in Online state */ - if (bfa_sm_cmp_state(ms, bfa_fcs_lport_ms_sm_online)) - bfa_sm_send_event(ms, MSSM_EVENT_PORT_FABRIC_RSCN); -} - -/* - * @page ns_sm_info VPORT NS State Machine - * - * @section ns_sm_interactions VPORT NS State Machine Interactions - * - * @section ns_sm VPORT NS State Machine - * img ns_sm.jpg - */ - -/* - * forward declarations - */ -static void bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_ns_send_rft_id(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_ns_send_rff_id(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_ns_send_gid_ft(void *ns_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_ns_timeout(void *arg); -static void bfa_fcs_lport_ns_plogi_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_ns_rft_id_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_ns_rff_id_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_ns_process_gidft_pids( - struct bfa_fcs_lport_s *port, - u32 *pid_buf, u32 n_pids); - -static void bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port); -/* - * fcs_ns_sm FCS nameserver interface state machine - */ - -/* - * VPort NS State Machine events - */ -enum vport_ns_event { - NSSM_EVENT_PORT_ONLINE = 1, - NSSM_EVENT_PORT_OFFLINE = 2, - NSSM_EVENT_PLOGI_SENT = 3, - NSSM_EVENT_RSP_OK = 4, - NSSM_EVENT_RSP_ERROR = 5, - NSSM_EVENT_TIMEOUT = 6, - NSSM_EVENT_NS_QUERY = 7, - NSSM_EVENT_RSPNID_SENT = 8, - NSSM_EVENT_RFTID_SENT = 9, - NSSM_EVENT_RFFID_SENT = 10, - NSSM_EVENT_GIDFT_SENT = 11, -}; - -static void bfa_fcs_lport_ns_sm_offline(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_plogi_sending(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_plogi(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_plogi_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_sending_rspn_id( - struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_rspn_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_rspn_id_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_sending_rft_id( - struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_rft_id_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_rft_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_sending_rff_id( - struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_rff_id_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_rff_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_sending_gid_ft( - struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_gid_ft(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_gid_ft_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -static void bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event); -/* - * Start in offline state - awaiting linkup - */ -static void -bfa_fcs_lport_ns_sm_offline(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_PORT_ONLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_sending); - bfa_fcs_lport_ns_send_plogi(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_plogi_sending(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_PLOGI_SENT: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_plogi(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->timer, bfa_fcs_lport_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_RSP_OK: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rspn_id); - bfa_fcs_lport_ns_send_rspn_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_discard(ns->fcxp); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_plogi_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_plogi_sending); - bfa_fcs_lport_ns_send_plogi(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_sending_rspn_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSPNID_SENT: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rspn_id); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_rspn_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rspn_id_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->timer, bfa_fcs_lport_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_RSP_OK: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rft_id); - bfa_fcs_lport_ns_send_rft_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_fcxp_discard(ns->fcxp); - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_rspn_id_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - /* - * Retry Timer Expired. Re-send - */ - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rspn_id); - bfa_fcs_lport_ns_send_rspn_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_sending_rft_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RFTID_SENT: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rft_id); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_rft_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_OK: - /* Now move to register FC4 Features */ - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rff_id); - bfa_fcs_lport_ns_send_rff_id(ns, NULL); - break; - - case NSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rft_id_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->timer, bfa_fcs_lport_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_discard(ns->fcxp); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_rft_id_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rft_id); - bfa_fcs_lport_ns_send_rft_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_sending_rff_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RFFID_SENT: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rff_id); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_rff_id(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_OK: - - /* - * If min cfg mode is enabled, we donot initiate rport - * discovery with the fabric. Instead, we will retrieve the - * boot targets from HAL/FW. - */ - if (__fcs_min_cfg(ns->port->fcs)) { - bfa_fcs_lport_ns_boot_target_disc(ns->port); - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_online); - return; - } - - /* - * If the port role is Initiator Mode issue NS query. - * If it is Target Mode, skip this and go to online. - */ - if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { - bfa_sm_set_state(ns, - bfa_fcs_lport_ns_sm_sending_gid_ft); - bfa_fcs_lport_ns_send_gid_ft(ns, NULL); - } - /* - * kick off mgmt srvr state machine - */ - bfa_fcs_lport_ms_online(ns->port); - break; - - case NSSM_EVENT_RSP_ERROR: - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_rff_id_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->timer, bfa_fcs_lport_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_discard(ns->fcxp); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_rff_id_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_rff_id); - bfa_fcs_lport_ns_send_rff_id(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} -static void -bfa_fcs_lport_ns_sm_sending_gid_ft(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_GIDFT_SENT: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_gid_ft); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_walloc_cancel(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->fcxp_wqe); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_gid_ft(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_RSP_OK: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_online); - break; - - case NSSM_EVENT_RSP_ERROR: - /* - * TBD: for certain reject codes, we don't need to retry - */ - /* - * Start timer for a delayed retry - */ - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_gid_ft_retry); - ns->port->stats.ns_retries++; - bfa_timer_start(BFA_FCS_GET_HAL_FROM_PORT(ns->port), - &ns->timer, bfa_fcs_lport_ns_timeout, ns, - BFA_FCS_RETRY_TIMEOUT); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_fcxp_discard(ns->fcxp); - break; - - case NSSM_EVENT_NS_QUERY: - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_gid_ft_retry(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_TIMEOUT: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_sending_gid_ft); - bfa_fcs_lport_ns_send_gid_ft(ns, NULL); - break; - - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - bfa_timer_stop(&ns->timer); - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - -static void -bfa_fcs_lport_ns_sm_online(struct bfa_fcs_lport_ns_s *ns, - enum vport_ns_event event) -{ - bfa_trc(ns->port->fcs, ns->port->port_cfg.pwwn); - bfa_trc(ns->port->fcs, event); - - switch (event) { - case NSSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); - break; - - case NSSM_EVENT_NS_QUERY: - /* - * If the port role is Initiator Mode issue NS query. - * If it is Target Mode, skip this and go to online. - */ - if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) { - bfa_sm_set_state(ns, - bfa_fcs_lport_ns_sm_sending_gid_ft); - bfa_fcs_lport_ns_send_gid_ft(ns, NULL); - }; - break; - - default: - bfa_sm_fault(ns->port->fcs, event); - } -} - - - -/* - * ns_pvt Nameserver local functions - */ - -static void -bfa_fcs_lport_ns_send_plogi(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_ns_s *ns = ns_cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_plogi_alloc_wait++; - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_lport_ns_send_plogi, ns); - return; - } - ns->fcxp = fcxp; - - len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_hton3b(FC_NAME_SERVER), - bfa_fcs_lport_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_ns_plogi_response, (void *)ns, - FC_MAX_PDUSZ, FC_ELS_TOV); - port->stats.ns_plogi_sent++; - - bfa_sm_send_event(ns, NSSM_EVENT_PLOGI_SENT); -} - -static void -bfa_fcs_lport_ns_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; - struct bfa_fcs_lport_s *port = ns->port; - /* struct fc_logi_s *plogi_resp; */ - struct fc_els_cmd_s *els_cmd; - struct fc_ls_rjt_s *ls_rjt; - - bfa_trc(port->fcs, req_status); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_plogi_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); - - switch (els_cmd->els_code) { - - case FC_ELS_ACC: - if (rsp_len < sizeof(struct fc_logi_s)) { - bfa_trc(port->fcs, rsp_len); - port->stats.ns_plogi_acc_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - break; - } - port->stats.ns_plogi_accepts++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - break; - - case FC_ELS_LS_RJT: - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - - bfa_trc(port->fcs, ls_rjt->reason_code); - bfa_trc(port->fcs, ls_rjt->reason_code_expl); - - port->stats.ns_rejects++; - - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - break; - - default: - port->stats.ns_plogi_unknown_rsp++; - bfa_trc(port->fcs, els_cmd->els_code); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - } -} - -/* - * Register the symbolic port name. - */ -static void -bfa_fcs_lport_ns_send_rspn_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_ns_s *ns = ns_cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - u8 symbl[256]; - u8 *psymbl = &symbl[0]; - - memset(symbl, 0, sizeof(symbl)); - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_rspnid_alloc_wait++; - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_lport_ns_send_rspn_id, ns); - return; - } - ns->fcxp = fcxp; - - /* - * for V-Port, form a Port Symbolic Name - */ - if (port->vport) { - /* - * For Vports, we append the vport's port symbolic name - * to that of the base port. - */ - - strncpy((char *)psymbl, - (char *) & - (bfa_fcs_lport_get_psym_name - (bfa_fcs_get_base_port(port->fcs))), - strlen((char *) & - bfa_fcs_lport_get_psym_name(bfa_fcs_get_base_port - (port->fcs)))); - - /* Ensure we have a null terminating string. */ - ((char *)psymbl)[strlen((char *) & - bfa_fcs_lport_get_psym_name(bfa_fcs_get_base_port - (port->fcs)))] = 0; - strncat((char *)psymbl, - (char *) &(bfa_fcs_lport_get_psym_name(port)), - strlen((char *) &bfa_fcs_lport_get_psym_name(port))); - } else { - psymbl = (u8 *) &(bfa_fcs_lport_get_psym_name(port)); - } - - len = fc_rspnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_lport_get_fcid(port), 0, psymbl); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_ns_rspn_id_response, (void *)ns, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - port->stats.ns_rspnid_sent++; - - bfa_sm_send_event(ns, NSSM_EVENT_RSPNID_SENT); -} - -static void -bfa_fcs_lport_ns_rspn_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_rspnid_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - port->stats.ns_rspnid_accepts++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - return; - } - - port->stats.ns_rspnid_rejects++; - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); -} - -/* - * Register FC4-Types - */ -static void -bfa_fcs_lport_ns_send_rft_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_ns_s *ns = ns_cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_rftid_alloc_wait++; - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_lport_ns_send_rft_id, ns); - return; - } - ns->fcxp = fcxp; - - len = fc_rftid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_lport_get_fcid(port), 0, port->port_cfg.roles); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_ns_rft_id_response, (void *)ns, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - port->stats.ns_rftid_sent++; - bfa_sm_send_event(ns, NSSM_EVENT_RFTID_SENT); -} - -static void -bfa_fcs_lport_ns_rft_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_rftid_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - port->stats.ns_rftid_accepts++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - return; - } - - port->stats.ns_rftid_rejects++; - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); -} - -/* - * Register FC4-Features : Should be done after RFT_ID - */ -static void -bfa_fcs_lport_ns_send_rff_id(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_ns_s *ns = ns_cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - u8 fc4_ftrs = 0; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_rffid_alloc_wait++; - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_lport_ns_send_rff_id, ns); - return; - } - ns->fcxp = fcxp; - - if (BFA_FCS_VPORT_IS_INITIATOR_MODE(ns->port)) - fc4_ftrs = FC_GS_FCP_FC4_FEATURE_INITIATOR; - - len = fc_rffid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_lport_get_fcid(port), 0, - FC_TYPE_FCP, fc4_ftrs); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_ns_rff_id_response, (void *)ns, - FC_MAX_PDUSZ, FC_FCCT_TOV); - - port->stats.ns_rffid_sent++; - bfa_sm_send_event(ns, NSSM_EVENT_RFFID_SENT); -} - -static void -bfa_fcs_lport_ns_rff_id_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct ct_hdr_s *cthdr = NULL; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_rffid_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - port->stats.ns_rffid_accepts++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - return; - } - - port->stats.ns_rffid_rejects++; - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - - if (cthdr->reason_code == CT_RSN_NOT_SUPP) { - /* if this command is not supported, we don't retry */ - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - } else - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); -} -/* - * Query Fabric for FC4-Types Devices. - * -* TBD : Need to use a local (FCS private) response buffer, since the response - * can be larger than 2K. - */ -static void -bfa_fcs_lport_ns_send_gid_ft(void *ns_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_ns_s *ns = ns_cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - port->stats.ns_gidft_alloc_wait++; - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &ns->fcxp_wqe, - bfa_fcs_lport_ns_send_gid_ft, ns); - return; - } - ns->fcxp = fcxp; - - /* - * This query is only initiated for FCP initiator mode. - */ - len = fc_gid_ft_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - ns->port->pid, FC_TYPE_FCP); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_ns_gid_ft_response, (void *)ns, - bfa_fcxp_get_maxrsp(port->fcs->bfa), FC_FCCT_TOV); - - port->stats.ns_gidft_sent++; - - bfa_sm_send_event(ns, NSSM_EVENT_GIDFT_SENT); -} - -static void -bfa_fcs_lport_ns_gid_ft_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) cbarg; - struct bfa_fcs_lport_s *port = ns->port; - struct ct_hdr_s *cthdr = NULL; - u32 n_pids; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - port->stats.ns_gidft_rsp_err++; - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - return; - } - - if (resid_len != 0) { - /* - * TBD : we will need to allocate a larger buffer & retry the - * command - */ - bfa_trc(port->fcs, rsp_len); - bfa_trc(port->fcs, resid_len); - return; - } - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - switch (cthdr->cmd_rsp_code) { - - case CT_RSP_ACCEPT: - - port->stats.ns_gidft_accepts++; - n_pids = (fc_get_ctresp_pyld_len(rsp_len) / sizeof(u32)); - bfa_trc(port->fcs, n_pids); - bfa_fcs_lport_ns_process_gidft_pids(port, - (u32 *) (cthdr + 1), - n_pids); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - break; - - case CT_RSP_REJECT: - - /* - * Check the reason code & explanation. - * There may not have been any FC4 devices in the fabric - */ - port->stats.ns_gidft_rejects++; - bfa_trc(port->fcs, cthdr->reason_code); - bfa_trc(port->fcs, cthdr->exp_code); - - if ((cthdr->reason_code == CT_RSN_UNABLE_TO_PERF) - && (cthdr->exp_code == CT_NS_EXP_FT_NOT_REG)) { - - bfa_sm_send_event(ns, NSSM_EVENT_RSP_OK); - } else { - /* - * for all other errors, retry - */ - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - } - break; - - default: - port->stats.ns_gidft_unknown_rsp++; - bfa_trc(port->fcs, cthdr->cmd_rsp_code); - bfa_sm_send_event(ns, NSSM_EVENT_RSP_ERROR); - } -} - -/* - * This routine will be called by bfa_timer on timer timeouts. - * - * param[in] port - pointer to bfa_fcs_lport_t. - * - * return - * void - * - * Special Considerations: - * - * note - */ -static void -bfa_fcs_lport_ns_timeout(void *arg) -{ - struct bfa_fcs_lport_ns_s *ns = (struct bfa_fcs_lport_ns_s *) arg; - - ns->port->stats.ns_timeouts++; - bfa_sm_send_event(ns, NSSM_EVENT_TIMEOUT); -} - -/* - * Process the PID list in GID_FT response - */ -static void -bfa_fcs_lport_ns_process_gidft_pids(struct bfa_fcs_lport_s *port, u32 *pid_buf, - u32 n_pids) -{ - struct fcgs_gidft_resp_s *gidft_entry; - struct bfa_fcs_rport_s *rport; - u32 ii; - - for (ii = 0; ii < n_pids; ii++) { - gidft_entry = (struct fcgs_gidft_resp_s *) &pid_buf[ii]; - - if (gidft_entry->pid == port->pid) - continue; - - /* - * Check if this rport already exists - */ - rport = bfa_fcs_lport_get_rport_by_pid(port, gidft_entry->pid); - if (rport == NULL) { - /* - * this is a new device. create rport - */ - rport = bfa_fcs_rport_create(port, gidft_entry->pid); - } else { - /* - * this rport already exists - */ - bfa_fcs_rport_scn(rport); - } - - bfa_trc(port->fcs, gidft_entry->pid); - - /* - * if the last entry bit is set, bail out. - */ - if (gidft_entry->last) - return; - } -} - -/* - * fcs_ns_public FCS nameserver public interfaces - */ - -/* - * Functions called by port/fab. - * These will send relevant Events to the ns state machine. - */ -void -bfa_fcs_lport_ns_init(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); - - ns->port = port; - bfa_sm_set_state(ns, bfa_fcs_lport_ns_sm_offline); -} - -void -bfa_fcs_lport_ns_offline(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); - - ns->port = port; - bfa_sm_send_event(ns, NSSM_EVENT_PORT_OFFLINE); -} - -void -bfa_fcs_lport_ns_online(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); - - ns->port = port; - bfa_sm_send_event(ns, NSSM_EVENT_PORT_ONLINE); -} - -void -bfa_fcs_lport_ns_query(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_ns_s *ns = BFA_FCS_GET_NS_FROM_PORT(port); - - bfa_trc(port->fcs, port->pid); - bfa_sm_send_event(ns, NSSM_EVENT_NS_QUERY); -} - -static void -bfa_fcs_lport_ns_boot_target_disc(bfa_fcs_lport_t *port) -{ - - struct bfa_fcs_rport_s *rport; - u8 nwwns; - wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; - int ii; - - bfa_iocfc_get_bootwwns(port->fcs->bfa, &nwwns, wwns); - - for (ii = 0 ; ii < nwwns; ++ii) { - rport = bfa_fcs_rport_create_by_wwn(port, wwns[ii]); - WARN_ON(!rport); - } -} - -/* - * FCS SCN - */ - -#define FC_QOS_RSCN_EVENT 0x0c -#define FC_FABRIC_NAME_RSCN_EVENT 0x0d - -/* - * forward declarations - */ -static void bfa_fcs_lport_scn_send_scr(void *scn_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_lport_scn_scr_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); -static void bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs); -static void bfa_fcs_lport_scn_timeout(void *arg); - -/* - * fcs_scm_sm FCS SCN state machine - */ - -/* - * VPort SCN State Machine events - */ -enum port_scn_event { - SCNSM_EVENT_PORT_ONLINE = 1, - SCNSM_EVENT_PORT_OFFLINE = 2, - SCNSM_EVENT_RSP_OK = 3, - SCNSM_EVENT_RSP_ERROR = 4, - SCNSM_EVENT_TIMEOUT = 5, - SCNSM_EVENT_SCR_SENT = 6, -}; - -static void bfa_fcs_lport_scn_sm_offline(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event); -static void bfa_fcs_lport_scn_sm_sending_scr( - struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event); -static void bfa_fcs_lport_scn_sm_scr(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event); -static void bfa_fcs_lport_scn_sm_scr_retry(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event); -static void bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event); - -/* - * Starting state - awaiting link up. - */ -static void -bfa_fcs_lport_scn_sm_offline(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event) -{ - switch (event) { - case SCNSM_EVENT_PORT_ONLINE: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_sending_scr); - bfa_fcs_lport_scn_send_scr(scn, NULL); - break; - - case SCNSM_EVENT_PORT_OFFLINE: - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - -static void -bfa_fcs_lport_scn_sm_sending_scr(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event) -{ - switch (event) { - case SCNSM_EVENT_SCR_SENT: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_scr); - break; - - case SCNSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); - bfa_fcxp_walloc_cancel(scn->port->fcs->bfa, &scn->fcxp_wqe); - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - -static void -bfa_fcs_lport_scn_sm_scr(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event) -{ - struct bfa_fcs_lport_s *port = scn->port; - - switch (event) { - case SCNSM_EVENT_RSP_OK: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_online); - break; - - case SCNSM_EVENT_RSP_ERROR: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_scr_retry); - bfa_timer_start(port->fcs->bfa, &scn->timer, - bfa_fcs_lport_scn_timeout, scn, - BFA_FCS_RETRY_TIMEOUT); - break; - - case SCNSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); - bfa_fcxp_discard(scn->fcxp); - break; - - default: - bfa_sm_fault(port->fcs, event); - } -} - -static void -bfa_fcs_lport_scn_sm_scr_retry(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event) -{ - switch (event) { - case SCNSM_EVENT_TIMEOUT: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_sending_scr); - bfa_fcs_lport_scn_send_scr(scn, NULL); - break; - - case SCNSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); - bfa_timer_stop(&scn->timer); - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - -static void -bfa_fcs_lport_scn_sm_online(struct bfa_fcs_lport_scn_s *scn, - enum port_scn_event event) -{ - switch (event) { - case SCNSM_EVENT_PORT_OFFLINE: - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); - break; - - default: - bfa_sm_fault(scn->port->fcs, event); - } -} - - - -/* - * fcs_scn_private FCS SCN private functions - */ - -/* - * This routine will be called to send a SCR command. - */ -static void -bfa_fcs_lport_scn_send_scr(void *scn_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_lport_scn_s *scn = scn_cbarg; - struct bfa_fcs_lport_s *port = scn->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(port->fcs, port->pid); - bfa_trc(port->fcs, port->port_cfg.pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &scn->fcxp_wqe, - bfa_fcs_lport_scn_send_scr, scn); - return; - } - scn->fcxp = fcxp; - - /* Handle VU registrations for Base port only */ - if ((!port->vport) && bfa_ioc_get_fcmode(&port->fcs->bfa->ioc)) { - len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - port->fabric->lps->brcd_switch, - port->pid, 0); - } else { - len = fc_scr_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - BFA_FALSE, - port->pid, 0); - } - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, - bfa_fcs_lport_scn_scr_response, - (void *)scn, FC_MAX_PDUSZ, FC_ELS_TOV); - - bfa_sm_send_event(scn, SCNSM_EVENT_SCR_SENT); -} - -static void -bfa_fcs_lport_scn_scr_response(void *fcsarg, struct bfa_fcxp_s *fcxp, - void *cbarg, bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_lport_scn_s *scn = (struct bfa_fcs_lport_scn_s *) cbarg; - struct bfa_fcs_lport_s *port = scn->port; - struct fc_els_cmd_s *els_cmd; - struct fc_ls_rjt_s *ls_rjt; - - bfa_trc(port->fcs, port->port_cfg.pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(port->fcs, req_status); - bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); - return; - } - - els_cmd = (struct fc_els_cmd_s *) BFA_FCXP_RSP_PLD(fcxp); - - switch (els_cmd->els_code) { - - case FC_ELS_ACC: - bfa_sm_send_event(scn, SCNSM_EVENT_RSP_OK); - break; - - case FC_ELS_LS_RJT: - - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - - bfa_trc(port->fcs, ls_rjt->reason_code); - bfa_trc(port->fcs, ls_rjt->reason_code_expl); - - bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); - break; - - default: - bfa_sm_send_event(scn, SCNSM_EVENT_RSP_ERROR); - } -} - -/* - * Send a LS Accept - */ -static void -bfa_fcs_lport_scn_send_ls_acc(struct bfa_fcs_lport_s *port, - struct fchs_s *rx_fchs) -{ - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - struct bfa_rport_s *bfa_rport = NULL; - int len; - - bfa_trc(port->fcs, rx_fchs->s_id); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - len = fc_ls_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id); - - bfa_fcxp_send(fcxp, bfa_rport, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - -/* - * This routine will be called by bfa_timer on timer timeouts. - * - * param[in] vport - pointer to bfa_fcs_lport_t. - * param[out] vport_status - pointer to return vport status in - * - * return - * void - * - * Special Considerations: - * - * note - */ -static void -bfa_fcs_lport_scn_timeout(void *arg) -{ - struct bfa_fcs_lport_scn_s *scn = (struct bfa_fcs_lport_scn_s *) arg; - - bfa_sm_send_event(scn, SCNSM_EVENT_TIMEOUT); -} - - - -/* - * fcs_scn_public FCS state change notification public interfaces - */ - -/* - * Functions called by port/fab - */ -void -bfa_fcs_lport_scn_init(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); - - scn->port = port; - bfa_sm_set_state(scn, bfa_fcs_lport_scn_sm_offline); -} - -void -bfa_fcs_lport_scn_offline(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); - - scn->port = port; - bfa_sm_send_event(scn, SCNSM_EVENT_PORT_OFFLINE); -} - -void -bfa_fcs_lport_scn_online(struct bfa_fcs_lport_s *port) -{ - struct bfa_fcs_lport_scn_s *scn = BFA_FCS_GET_SCN_FROM_PORT(port); - - scn->port = port; - bfa_sm_send_event(scn, SCNSM_EVENT_PORT_ONLINE); -} - -static void -bfa_fcs_lport_scn_portid_rscn(struct bfa_fcs_lport_s *port, u32 rpid) -{ - struct bfa_fcs_rport_s *rport; - - bfa_trc(port->fcs, rpid); - - /* - * If this is an unknown device, then it just came online. - * Otherwise let rport handle the RSCN event. - */ - rport = bfa_fcs_lport_get_rport_by_pid(port, rpid); - if (rport == NULL) { - /* - * If min cfg mode is enabled, we donot need to - * discover any new rports. - */ - if (!__fcs_min_cfg(port->fcs)) - rport = bfa_fcs_rport_create(port, rpid); - } else - bfa_fcs_rport_scn(rport); -} - -/* - * rscn format based PID comparison - */ -#define __fc_pid_match(__c0, __c1, __fmt) \ - (((__fmt) == FC_RSCN_FORMAT_FABRIC) || \ - (((__fmt) == FC_RSCN_FORMAT_DOMAIN) && \ - ((__c0)[0] == (__c1)[0])) || \ - (((__fmt) == FC_RSCN_FORMAT_AREA) && \ - ((__c0)[0] == (__c1)[0]) && \ - ((__c0)[1] == (__c1)[1]))) - -static void -bfa_fcs_lport_scn_multiport_rscn(struct bfa_fcs_lport_s *port, - enum fc_rscn_format format, - u32 rscn_pid) -{ - struct bfa_fcs_rport_s *rport; - struct list_head *qe, *qe_next; - u8 *c0, *c1; - - bfa_trc(port->fcs, format); - bfa_trc(port->fcs, rscn_pid); - - c0 = (u8 *) &rscn_pid; - - list_for_each_safe(qe, qe_next, &port->rport_q) { - rport = (struct bfa_fcs_rport_s *) qe; - c1 = (u8 *) &rport->pid; - if (__fc_pid_match(c0, c1, format)) - bfa_fcs_rport_scn(rport); - } -} - - -void -bfa_fcs_lport_scn_process_rscn(struct bfa_fcs_lport_s *port, - struct fchs_s *fchs, u32 len) -{ - struct fc_rscn_pl_s *rscn = (struct fc_rscn_pl_s *) (fchs + 1); - int num_entries; - u32 rscn_pid; - bfa_boolean_t nsquery = BFA_FALSE, found; - int i = 0, j; - - num_entries = - (be16_to_cpu(rscn->payldlen) - - sizeof(u32)) / sizeof(rscn->event[0]); - - bfa_trc(port->fcs, num_entries); - - port->stats.num_rscn++; - - bfa_fcs_lport_scn_send_ls_acc(port, fchs); - - for (i = 0; i < num_entries; i++) { - rscn_pid = rscn->event[i].portid; - - bfa_trc(port->fcs, rscn->event[i].format); - bfa_trc(port->fcs, rscn_pid); - - /* check for duplicate entries in the list */ - found = BFA_FALSE; - for (j = 0; j < i; j++) { - if (rscn->event[j].portid == rscn_pid) { - found = BFA_TRUE; - break; - } - } - - /* if found in down the list, pid has been already processed */ - if (found) { - bfa_trc(port->fcs, rscn_pid); - continue; - } - - switch (rscn->event[i].format) { - case FC_RSCN_FORMAT_PORTID: - if (rscn->event[i].qualifier == FC_QOS_RSCN_EVENT) { - /* - * Ignore this event. - * f/w would have processed it - */ - bfa_trc(port->fcs, rscn_pid); - } else { - port->stats.num_portid_rscn++; - bfa_fcs_lport_scn_portid_rscn(port, rscn_pid); - } - break; - - case FC_RSCN_FORMAT_FABRIC: - if (rscn->event[i].qualifier == - FC_FABRIC_NAME_RSCN_EVENT) { - bfa_fcs_lport_ms_fabric_rscn(port); - break; - } - /* !!!!!!!!! Fall Through !!!!!!!!!!!!! */ - - case FC_RSCN_FORMAT_AREA: - case FC_RSCN_FORMAT_DOMAIN: - nsquery = BFA_TRUE; - bfa_fcs_lport_scn_multiport_rscn(port, - rscn->event[i].format, - rscn_pid); - break; - - - default: - WARN_ON(1); - nsquery = BFA_TRUE; - } - } - - /* - * If any of area, domain or fabric RSCN is received, do a fresh - * discovery to find new devices. - */ - if (nsquery) - bfa_fcs_lport_ns_query(port); -} - -/* - * BFA FCS port - */ -/* - * fcs_port_api BFA FCS port API - */ -struct bfa_fcs_lport_s * -bfa_fcs_get_base_port(struct bfa_fcs_s *fcs) -{ - return &fcs->fabric.bport; -} - -wwn_t -bfa_fcs_lport_get_rport(struct bfa_fcs_lport_s *port, wwn_t wwn, int index, - int nrports, bfa_boolean_t bwwn) -{ - struct list_head *qh, *qe; - struct bfa_fcs_rport_s *rport = NULL; - int i; - struct bfa_fcs_s *fcs; - - if (port == NULL || nrports == 0) - return (wwn_t) 0; - - fcs = port->fcs; - bfa_trc(fcs, (u32) nrports); - - i = 0; - qh = &port->rport_q; - qe = bfa_q_first(qh); - - while ((qe != qh) && (i < nrports)) { - rport = (struct bfa_fcs_rport_s *) qe; - if (bfa_ntoh3b(rport->pid) > 0xFFF000) { - qe = bfa_q_next(qe); - bfa_trc(fcs, (u32) rport->pwwn); - bfa_trc(fcs, rport->pid); - bfa_trc(fcs, i); - continue; - } - - if (bwwn) { - if (!memcmp(&wwn, &rport->pwwn, 8)) - break; - } else { - if (i == index) - break; - } - - i++; - qe = bfa_q_next(qe); - } - - bfa_trc(fcs, i); - if (rport) - return rport->pwwn; - else - return (wwn_t) 0; -} - -void -bfa_fcs_lport_get_rports(struct bfa_fcs_lport_s *port, - wwn_t rport_wwns[], int *nrports) -{ - struct list_head *qh, *qe; - struct bfa_fcs_rport_s *rport = NULL; - int i; - struct bfa_fcs_s *fcs; - - if (port == NULL || rport_wwns == NULL || *nrports == 0) - return; - - fcs = port->fcs; - bfa_trc(fcs, (u32) *nrports); - - i = 0; - qh = &port->rport_q; - qe = bfa_q_first(qh); - - while ((qe != qh) && (i < *nrports)) { - rport = (struct bfa_fcs_rport_s *) qe; - if (bfa_ntoh3b(rport->pid) > 0xFFF000) { - qe = bfa_q_next(qe); - bfa_trc(fcs, (u32) rport->pwwn); - bfa_trc(fcs, rport->pid); - bfa_trc(fcs, i); - continue; - } - - rport_wwns[i] = rport->pwwn; - - i++; - qe = bfa_q_next(qe); - } - - bfa_trc(fcs, i); - *nrports = i; -} - -/* - * Iterate's through all the rport's in the given port to - * determine the maximum operating speed. - * - * !!!! To be used in TRL Functionality only !!!! - */ -bfa_port_speed_t -bfa_fcs_lport_get_rport_max_speed(bfa_fcs_lport_t *port) -{ - struct list_head *qh, *qe; - struct bfa_fcs_rport_s *rport = NULL; - struct bfa_fcs_s *fcs; - bfa_port_speed_t max_speed = 0; - struct bfa_port_attr_s port_attr; - bfa_port_speed_t port_speed, rport_speed; - bfa_boolean_t trl_enabled = bfa_fcport_is_ratelim(port->fcs->bfa); - - - if (port == NULL) - return 0; - - fcs = port->fcs; - - /* Get Physical port's current speed */ - bfa_fcport_get_attr(port->fcs->bfa, &port_attr); - port_speed = port_attr.speed; - bfa_trc(fcs, port_speed); - - qh = &port->rport_q; - qe = bfa_q_first(qh); - - while (qe != qh) { - rport = (struct bfa_fcs_rport_s *) qe; - if ((bfa_ntoh3b(rport->pid) > 0xFFF000) || - (bfa_fcs_rport_get_state(rport) == BFA_RPORT_OFFLINE) || - (rport->scsi_function != BFA_RPORT_TARGET)) { - qe = bfa_q_next(qe); - continue; - } - - rport_speed = rport->rpf.rpsc_speed; - if ((trl_enabled) && (rport_speed == - BFA_PORT_SPEED_UNKNOWN)) { - /* Use default ratelim speed setting */ - rport_speed = - bfa_fcport_get_ratelim_speed(port->fcs->bfa); - } - - if (rport_speed > max_speed) - max_speed = rport_speed; - - qe = bfa_q_next(qe); - } - - if (max_speed > port_speed) - max_speed = port_speed; - - bfa_trc(fcs, max_speed); - return max_speed; -} - -struct bfa_fcs_lport_s * -bfa_fcs_lookup_port(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t lpwwn) -{ - struct bfa_fcs_vport_s *vport; - bfa_fcs_vf_t *vf; - - WARN_ON(fcs == NULL); - - vf = bfa_fcs_vf_lookup(fcs, vf_id); - if (vf == NULL) { - bfa_trc(fcs, vf_id); - return NULL; - } - - if (!lpwwn || (vf->bport.port_cfg.pwwn == lpwwn)) - return &vf->bport; - - vport = bfa_fcs_fabric_vport_lookup(vf, lpwwn); - if (vport) - return &vport->lport; - - return NULL; -} - -/* - * API corresponding to NPIV_VPORT_GETINFO. - */ -void -bfa_fcs_lport_get_info(struct bfa_fcs_lport_s *port, - struct bfa_lport_info_s *port_info) -{ - - bfa_trc(port->fcs, port->fabric->fabric_name); - - if (port->vport == NULL) { - /* - * This is a Physical port - */ - port_info->port_type = BFA_LPORT_TYPE_PHYSICAL; - - /* - * @todo : need to fix the state & reason - */ - port_info->port_state = 0; - port_info->offline_reason = 0; - - port_info->port_wwn = bfa_fcs_lport_get_pwwn(port); - port_info->node_wwn = bfa_fcs_lport_get_nwwn(port); - - port_info->max_vports_supp = - bfa_lps_get_max_vport(port->fcs->bfa); - port_info->num_vports_inuse = - port->fabric->num_vports; - port_info->max_rports_supp = BFA_FCS_MAX_RPORTS_SUPP; - port_info->num_rports_inuse = port->num_rports; - } else { - /* - * This is a virtual port - */ - port_info->port_type = BFA_LPORT_TYPE_VIRTUAL; - - /* - * @todo : need to fix the state & reason - */ - port_info->port_state = 0; - port_info->offline_reason = 0; - - port_info->port_wwn = bfa_fcs_lport_get_pwwn(port); - port_info->node_wwn = bfa_fcs_lport_get_nwwn(port); - } -} - -void -bfa_fcs_lport_get_stats(struct bfa_fcs_lport_s *fcs_port, - struct bfa_lport_stats_s *port_stats) -{ - *port_stats = fcs_port->stats; -} - -void -bfa_fcs_lport_clear_stats(struct bfa_fcs_lport_s *fcs_port) -{ - memset(&fcs_port->stats, 0, sizeof(struct bfa_lport_stats_s)); -} - -/* - * FCS virtual port state machine - */ - -#define __vport_fcs(__vp) ((__vp)->lport.fcs) -#define __vport_pwwn(__vp) ((__vp)->lport.port_cfg.pwwn) -#define __vport_nwwn(__vp) ((__vp)->lport.port_cfg.nwwn) -#define __vport_bfa(__vp) ((__vp)->lport.fcs->bfa) -#define __vport_fcid(__vp) ((__vp)->lport.pid) -#define __vport_fabric(__vp) ((__vp)->lport.fabric) -#define __vport_vfid(__vp) ((__vp)->lport.fabric->vf_id) - -#define BFA_FCS_VPORT_MAX_RETRIES 5 -/* - * Forward declarations - */ -static void bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport); -static void bfa_fcs_vport_timeout(void *vport_arg); -static void bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport); -static void bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport); - -/* - * fcs_vport_sm FCS virtual port state machine - */ - -/* - * VPort State Machine events - */ -enum bfa_fcs_vport_event { - BFA_FCS_VPORT_SM_CREATE = 1, /* vport create event */ - BFA_FCS_VPORT_SM_DELETE = 2, /* vport delete event */ - BFA_FCS_VPORT_SM_START = 3, /* vport start request */ - BFA_FCS_VPORT_SM_STOP = 4, /* stop: unsupported */ - BFA_FCS_VPORT_SM_ONLINE = 5, /* fabric online */ - BFA_FCS_VPORT_SM_OFFLINE = 6, /* fabric offline event */ - BFA_FCS_VPORT_SM_FRMSENT = 7, /* fdisc/logo sent events */ - BFA_FCS_VPORT_SM_RSP_OK = 8, /* good response */ - BFA_FCS_VPORT_SM_RSP_ERROR = 9, /* error/bad response */ - BFA_FCS_VPORT_SM_TIMEOUT = 10, /* delay timer event */ - BFA_FCS_VPORT_SM_DELCOMP = 11, /* lport delete completion */ - BFA_FCS_VPORT_SM_RSP_DUP_WWN = 12, /* Dup wnn error*/ - BFA_FCS_VPORT_SM_RSP_FAILED = 13, /* non-retryable failure */ - BFA_FCS_VPORT_SM_STOPCOMP = 14, /* vport delete completion */ -}; - -static void bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_fdisc_rsp_wait(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); -static void bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event); - -static struct bfa_sm_table_s vport_sm_table[] = { - {BFA_SM(bfa_fcs_vport_sm_uninit), BFA_FCS_VPORT_UNINIT}, - {BFA_SM(bfa_fcs_vport_sm_created), BFA_FCS_VPORT_CREATED}, - {BFA_SM(bfa_fcs_vport_sm_offline), BFA_FCS_VPORT_OFFLINE}, - {BFA_SM(bfa_fcs_vport_sm_fdisc), BFA_FCS_VPORT_FDISC}, - {BFA_SM(bfa_fcs_vport_sm_fdisc_retry), BFA_FCS_VPORT_FDISC_RETRY}, - {BFA_SM(bfa_fcs_vport_sm_fdisc_rsp_wait), BFA_FCS_VPORT_FDISC_RSP_WAIT}, - {BFA_SM(bfa_fcs_vport_sm_online), BFA_FCS_VPORT_ONLINE}, - {BFA_SM(bfa_fcs_vport_sm_deleting), BFA_FCS_VPORT_DELETING}, - {BFA_SM(bfa_fcs_vport_sm_cleanup), BFA_FCS_VPORT_CLEANUP}, - {BFA_SM(bfa_fcs_vport_sm_logo), BFA_FCS_VPORT_LOGO}, - {BFA_SM(bfa_fcs_vport_sm_error), BFA_FCS_VPORT_ERROR} -}; - -/* - * Beginning state. - */ -static void -bfa_fcs_vport_sm_uninit(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_CREATE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); - bfa_fcs_fabric_addvport(__vport_fabric(vport), vport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * Created state - a start event is required to start up the state machine. - */ -static void -bfa_fcs_vport_sm_created(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_START: - if (bfa_sm_cmp_state(__vport_fabric(vport), - bfa_fcs_fabric_sm_online) - && bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) { - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); - bfa_fcs_vport_do_fdisc(vport); - } else { - /* - * Fabric is offline or not NPIV capable, stay in - * offline state. - */ - vport->vport_stats.fab_no_npiv++; - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - } - break; - - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_fcs_lport_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_ONLINE: - case BFA_FCS_VPORT_SM_OFFLINE: - /* - * Ignore ONLINE/OFFLINE events from fabric - * till vport is started. - */ - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * Offline state - awaiting ONLINE event from fabric SM. - */ -static void -bfa_fcs_vport_sm_offline(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_fcs_lport_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_ONLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); - vport->fdisc_retries = 0; - bfa_fcs_vport_do_fdisc(vport); - break; - - case BFA_FCS_VPORT_SM_STOP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_sm_send_event(&vport->lport, BFA_FCS_PORT_SM_STOP); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - /* - * This can happen if the vport couldn't be initialzied - * due the fact that the npiv was not enabled on the switch. - * In that case we will put the vport in offline state. - * However, the link can go down and cause the this event to - * be sent when we are already offline. Ignore it. - */ - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - - -/* - * FDISC is sent and awaiting reply from fabric. - */ -static void -bfa_fcs_vport_sm_fdisc(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_rsp_wait); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - break; - - case BFA_FCS_VPORT_SM_RSP_OK: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_online); - bfa_fcs_lport_online(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_RSP_ERROR: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc_retry); - bfa_timer_start(__vport_bfa(vport), &vport->timer, - bfa_fcs_vport_timeout, vport, - BFA_FCS_RETRY_TIMEOUT); - break; - - case BFA_FCS_VPORT_SM_RSP_FAILED: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - break; - - case BFA_FCS_VPORT_SM_RSP_DUP_WWN: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_error); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * FDISC attempt failed - a timer is active to retry FDISC. - */ -static void -bfa_fcs_vport_sm_fdisc_retry(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_timer_stop(&vport->timer); - bfa_fcs_lport_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - bfa_timer_stop(&vport->timer); - break; - - case BFA_FCS_VPORT_SM_TIMEOUT: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_fdisc); - vport->vport_stats.fdisc_retries++; - vport->fdisc_retries++; - bfa_fcs_vport_do_fdisc(vport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * FDISC is in progress and we got a vport delete request - - * this is a wait state while we wait for fdisc response and - * we will transition to the appropriate state - on rsp status. - */ -static void -bfa_fcs_vport_sm_fdisc_rsp_wait(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_RSP_OK: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting); - bfa_fcs_lport_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_DELETE: - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - case BFA_FCS_VPORT_SM_RSP_ERROR: - case BFA_FCS_VPORT_SM_RSP_FAILED: - case BFA_FCS_VPORT_SM_RSP_DUP_WWN: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_lport_delete(&vport->lport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * Vport is online (FDISC is complete). - */ -static void -bfa_fcs_vport_sm_online(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_deleting); - bfa_fcs_lport_delete(&vport->lport); - break; - - case BFA_FCS_VPORT_SM_STOP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_stopping); - bfa_sm_send_event(&vport->lport, BFA_FCS_PORT_SM_STOP); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_offline); - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - bfa_fcs_lport_offline(&vport->lport); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * Vport is being stopped - awaiting lport stop completion to send - * LOGO to fabric. - */ -static void -bfa_fcs_vport_sm_stopping(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_STOPCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo_for_stop); - bfa_fcs_vport_do_logo(vport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * Vport is being deleted - awaiting lport delete completion to send - * LOGO to fabric. - */ -static void -bfa_fcs_vport_sm_deleting(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - break; - - case BFA_FCS_VPORT_SM_DELCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_logo); - bfa_fcs_vport_do_logo(vport); - break; - - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * Error State. - * This state will be set when the Vport Creation fails due - * to errors like Dup WWN. In this state only operation allowed - * is a Vport Delete. - */ -static void -bfa_fcs_vport_sm_error(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELETE: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_cleanup); - bfa_fcs_lport_delete(&vport->lport); - break; - - default: - bfa_trc(__vport_fcs(vport), event); - } -} - -/* - * Lport cleanup is in progress since vport is being deleted. Fabric is - * offline, so no LOGO is needed to complete vport deletion. - */ -static void -bfa_fcs_vport_sm_cleanup(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_DELCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); - bfa_fcs_vport_free(vport); - break; - - case BFA_FCS_VPORT_SM_STOPCOMP: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); - break; - - case BFA_FCS_VPORT_SM_DELETE: - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * LOGO is sent to fabric. Vport stop is in progress. Lport stop cleanup - * is done. - */ -static void -bfa_fcs_vport_sm_logo_for_stop(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - /* - * !!! fall through !!! - */ - - case BFA_FCS_VPORT_SM_RSP_OK: - case BFA_FCS_VPORT_SM_RSP_ERROR: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_created); - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - -/* - * LOGO is sent to fabric. Vport delete is in progress. Lport delete cleanup - * is done. - */ -static void -bfa_fcs_vport_sm_logo(struct bfa_fcs_vport_s *vport, - enum bfa_fcs_vport_event event) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), event); - - switch (event) { - case BFA_FCS_VPORT_SM_OFFLINE: - bfa_sm_send_event(vport->lps, BFA_LPS_SM_OFFLINE); - /* - * !!! fall through !!! - */ - - case BFA_FCS_VPORT_SM_RSP_OK: - case BFA_FCS_VPORT_SM_RSP_ERROR: - bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); - bfa_fcs_vport_free(vport); - break; - - case BFA_FCS_VPORT_SM_DELETE: - break; - - default: - bfa_sm_fault(__vport_fcs(vport), event); - } -} - - - -/* - * fcs_vport_private FCS virtual port private functions - */ -/* - * Send AEN notification - */ -static void -bfa_fcs_vport_aen_post(struct bfa_fcs_lport_s *port, - enum bfa_lport_aen_event event) -{ - struct bfad_s *bfad = (struct bfad_s *)port->fabric->fcs->bfad; - struct bfa_aen_entry_s *aen_entry; - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - aen_entry->aen_data.lport.vf_id = port->fabric->vf_id; - aen_entry->aen_data.lport.roles = port->port_cfg.roles; - aen_entry->aen_data.lport.ppwwn = bfa_fcs_lport_get_pwwn( - bfa_fcs_get_base_port(port->fcs)); - aen_entry->aen_data.lport.lpwwn = bfa_fcs_lport_get_pwwn(port); - - /* Send the AEN notification */ - bfad_im_post_vendor_event(aen_entry, bfad, ++port->fcs->fcs_aen_seq, - BFA_AEN_CAT_LPORT, event); -} - -/* - * This routine will be called to send a FDISC command. - */ -static void -bfa_fcs_vport_do_fdisc(struct bfa_fcs_vport_s *vport) -{ - bfa_lps_fdisc(vport->lps, vport, - bfa_fcport_get_maxfrsize(__vport_bfa(vport)), - __vport_pwwn(vport), __vport_nwwn(vport)); - vport->vport_stats.fdisc_sent++; -} - -static void -bfa_fcs_vport_fdisc_rejected(struct bfa_fcs_vport_s *vport) -{ - u8 lsrjt_rsn = vport->lps->lsrjt_rsn; - u8 lsrjt_expl = vport->lps->lsrjt_expl; - - bfa_trc(__vport_fcs(vport), lsrjt_rsn); - bfa_trc(__vport_fcs(vport), lsrjt_expl); - - /* For certain reason codes, we don't want to retry. */ - switch (vport->lps->lsrjt_expl) { - case FC_LS_RJT_EXP_INV_PORT_NAME: /* by brocade */ - case FC_LS_RJT_EXP_INVALID_NPORT_ID: /* by Cisco */ - if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES) - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - else { - bfa_fcs_vport_aen_post(&vport->lport, - BFA_LPORT_AEN_NPIV_DUP_WWN); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_DUP_WWN); - } - break; - - case FC_LS_RJT_EXP_INSUFF_RES: - /* - * This means max logins per port/switch setting on the - * switch was exceeded. - */ - if (vport->fdisc_retries < BFA_FCS_VPORT_MAX_RETRIES) - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - else { - bfa_fcs_vport_aen_post(&vport->lport, - BFA_LPORT_AEN_NPIV_FABRIC_MAX); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_FAILED); - } - break; - - default: - if (vport->fdisc_retries == 0) - bfa_fcs_vport_aen_post(&vport->lport, - BFA_LPORT_AEN_NPIV_UNKNOWN); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - } -} - -/* - * Called to send a logout to the fabric. Used when a V-Port is - * deleted/stopped. - */ -static void -bfa_fcs_vport_do_logo(struct bfa_fcs_vport_s *vport) -{ - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - - vport->vport_stats.logo_sent++; - bfa_lps_fdisclogo(vport->lps); -} - - -/* - * This routine will be called by bfa_timer on timer timeouts. - * - * param[in] vport - pointer to bfa_fcs_vport_t. - * param[out] vport_status - pointer to return vport status in - * - * return - * void - * - * Special Considerations: - * - * note - */ -static void -bfa_fcs_vport_timeout(void *vport_arg) -{ - struct bfa_fcs_vport_s *vport = (struct bfa_fcs_vport_s *) vport_arg; - - vport->vport_stats.fdisc_timeouts++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_TIMEOUT); -} - -static void -bfa_fcs_vport_free(struct bfa_fcs_vport_s *vport) -{ - struct bfad_vport_s *vport_drv = - (struct bfad_vport_s *)vport->vport_drv; - - bfa_fcs_fabric_delvport(__vport_fabric(vport), vport); - - if (vport_drv->comp_del) - complete(vport_drv->comp_del); - else - kfree(vport_drv); - - bfa_lps_delete(vport->lps); -} - - - -/* - * fcs_vport_public FCS virtual port public interfaces - */ - -/* - * Online notification from fabric SM. - */ -void -bfa_fcs_vport_online(struct bfa_fcs_vport_s *vport) -{ - vport->vport_stats.fab_online++; - if (bfa_fcs_fabric_npiv_capable(__vport_fabric(vport))) - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); - else - vport->vport_stats.fab_no_npiv++; -} - -/* - * Offline notification from fabric SM. - */ -void -bfa_fcs_vport_offline(struct bfa_fcs_vport_s *vport) -{ - vport->vport_stats.fab_offline++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE); -} - -/* - * Cleanup notification from fabric SM on link timer expiry. - */ -void -bfa_fcs_vport_cleanup(struct bfa_fcs_vport_s *vport) -{ - vport->vport_stats.fab_cleanup++; -} -/* - * delete notification from fabric SM. To be invoked from within FCS. - */ -void -bfa_fcs_vport_fcs_delete(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE); -} - -/* - * Stop completion callback from associated lport - */ -void -bfa_fcs_vport_stop_comp(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOPCOMP); -} - -/* - * Delete completion callback from associated lport - */ -void -bfa_fcs_vport_delete_comp(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELCOMP); -} - - - -/* - * fcs_vport_api Virtual port API - */ - -/* - * Use this function to instantiate a new FCS vport object. This - * function will not trigger any HW initialization process (which will be - * done in vport_start() call) - * - * param[in] vport - pointer to bfa_fcs_vport_t. This space - * needs to be allocated by the driver. - * param[in] fcs - FCS instance - * param[in] vport_cfg - vport configuration - * param[in] vf_id - VF_ID if vport is created within a VF. - * FC_VF_ID_NULL to specify base fabric. - * param[in] vport_drv - Opaque handle back to the driver's vport - * structure - * - * retval BFA_STATUS_OK - on success. - * retval BFA_STATUS_FAILED - on failure. - */ -bfa_status_t -bfa_fcs_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, - u16 vf_id, struct bfa_lport_cfg_s *vport_cfg, - struct bfad_vport_s *vport_drv) -{ - if (vport_cfg->pwwn == 0) - return BFA_STATUS_INVALID_WWN; - - if (bfa_fcs_lport_get_pwwn(&fcs->fabric.bport) == vport_cfg->pwwn) - return BFA_STATUS_VPORT_WWN_BP; - - if (bfa_fcs_vport_lookup(fcs, vf_id, vport_cfg->pwwn) != NULL) - return BFA_STATUS_VPORT_EXISTS; - - if (fcs->fabric.num_vports == - bfa_lps_get_max_vport(fcs->bfa)) - return BFA_STATUS_VPORT_MAX; - - vport->lps = bfa_lps_alloc(fcs->bfa); - if (!vport->lps) - return BFA_STATUS_VPORT_MAX; - - vport->vport_drv = vport_drv; - vport_cfg->preboot_vp = BFA_FALSE; - - bfa_sm_set_state(vport, bfa_fcs_vport_sm_uninit); - bfa_fcs_lport_attach(&vport->lport, fcs, vf_id, vport); - bfa_fcs_lport_init(&vport->lport, vport_cfg); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_CREATE); - - return BFA_STATUS_OK; -} - -/* - * Use this function to instantiate a new FCS PBC vport object. This - * function will not trigger any HW initialization process (which will be - * done in vport_start() call) - * - * param[in] vport - pointer to bfa_fcs_vport_t. This space - * needs to be allocated by the driver. - * param[in] fcs - FCS instance - * param[in] vport_cfg - vport configuration - * param[in] vf_id - VF_ID if vport is created within a VF. - * FC_VF_ID_NULL to specify base fabric. - * param[in] vport_drv - Opaque handle back to the driver's vport - * structure - * - * retval BFA_STATUS_OK - on success. - * retval BFA_STATUS_FAILED - on failure. - */ -bfa_status_t -bfa_fcs_pbc_vport_create(struct bfa_fcs_vport_s *vport, struct bfa_fcs_s *fcs, - u16 vf_id, struct bfa_lport_cfg_s *vport_cfg, - struct bfad_vport_s *vport_drv) -{ - bfa_status_t rc; - - rc = bfa_fcs_vport_create(vport, fcs, vf_id, vport_cfg, vport_drv); - vport->lport.port_cfg.preboot_vp = BFA_TRUE; - - return rc; -} - -/* - * Use this function to findout if this is a pbc vport or not. - * - * @param[in] vport - pointer to bfa_fcs_vport_t. - * - * @returns None - */ -bfa_boolean_t -bfa_fcs_is_pbc_vport(struct bfa_fcs_vport_s *vport) -{ - - if (vport && (vport->lport.port_cfg.preboot_vp == BFA_TRUE)) - return BFA_TRUE; - else - return BFA_FALSE; - -} - -/* - * Use this function initialize the vport. - * - * @param[in] vport - pointer to bfa_fcs_vport_t. - * - * @returns None - */ -bfa_status_t -bfa_fcs_vport_start(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_START); - - return BFA_STATUS_OK; -} - -/* - * Use this function quiese the vport object. This function will return - * immediately, when the vport is actually stopped, the - * bfa_drv_vport_stop_cb() will be called. - * - * param[in] vport - pointer to bfa_fcs_vport_t. - * - * return None - */ -bfa_status_t -bfa_fcs_vport_stop(struct bfa_fcs_vport_s *vport) -{ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_STOP); - - return BFA_STATUS_OK; -} - -/* - * Use this function to delete a vport object. Fabric object should - * be stopped before this function call. - * - * !!!!!!! Donot invoke this from within FCS !!!!!!! - * - * param[in] vport - pointer to bfa_fcs_vport_t. - * - * return None - */ -bfa_status_t -bfa_fcs_vport_delete(struct bfa_fcs_vport_s *vport) -{ - - if (vport->lport.port_cfg.preboot_vp) - return BFA_STATUS_PBC; - - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_DELETE); - - return BFA_STATUS_OK; -} - -/* - * Use this function to get vport's current status info. - * - * param[in] vport pointer to bfa_fcs_vport_t. - * param[out] attr pointer to return vport attributes - * - * return None - */ -void -bfa_fcs_vport_get_attr(struct bfa_fcs_vport_s *vport, - struct bfa_vport_attr_s *attr) -{ - if (vport == NULL || attr == NULL) - return; - - memset(attr, 0, sizeof(struct bfa_vport_attr_s)); - - bfa_fcs_lport_get_attr(&vport->lport, &attr->port_attr); - attr->vport_state = bfa_sm_to_state(vport_sm_table, vport->sm); -} - - -/* - * Lookup a virtual port. Excludes base port from lookup. - */ -struct bfa_fcs_vport_s * -bfa_fcs_vport_lookup(struct bfa_fcs_s *fcs, u16 vf_id, wwn_t vpwwn) -{ - struct bfa_fcs_vport_s *vport; - struct bfa_fcs_fabric_s *fabric; - - bfa_trc(fcs, vf_id); - bfa_trc(fcs, vpwwn); - - fabric = bfa_fcs_vf_lookup(fcs, vf_id); - if (!fabric) { - bfa_trc(fcs, vf_id); - return NULL; - } - - vport = bfa_fcs_fabric_vport_lookup(fabric, vpwwn); - return vport; -} - -/* - * FDISC Response - */ -void -bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status) -{ - struct bfa_fcs_vport_s *vport = uarg; - - bfa_trc(__vport_fcs(vport), __vport_pwwn(vport)); - bfa_trc(__vport_fcs(vport), status); - - switch (status) { - case BFA_STATUS_OK: - /* - * Initialize the V-Port fields - */ - __vport_fcid(vport) = vport->lps->lp_pid; - vport->vport_stats.fdisc_accepts++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK); - break; - - case BFA_STATUS_INVALID_MAC: - /* Only for CNA */ - vport->vport_stats.fdisc_acc_bad++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - - break; - - case BFA_STATUS_EPROTOCOL: - switch (vport->lps->ext_status) { - case BFA_EPROTO_BAD_ACCEPT: - vport->vport_stats.fdisc_acc_bad++; - break; - - case BFA_EPROTO_UNKNOWN_RSP: - vport->vport_stats.fdisc_unknown_rsp++; - break; - - default: - break; - } - - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - break; - - case BFA_STATUS_FABRIC_RJT: - vport->vport_stats.fdisc_rejects++; - bfa_fcs_vport_fdisc_rejected(vport); - break; - - default: - vport->vport_stats.fdisc_rsp_err++; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_ERROR); - } -} - -/* - * LOGO response - */ -void -bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg) -{ - struct bfa_fcs_vport_s *vport = uarg; - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_RSP_OK); -} - -/* - * Received clear virtual link - */ -void -bfa_cb_lps_cvl_event(void *bfad, void *uarg) -{ - struct bfa_fcs_vport_s *vport = uarg; - - /* Send an Offline followed by an ONLINE */ - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_OFFLINE); - bfa_sm_send_event(vport, BFA_FCS_VPORT_SM_ONLINE); -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_rport.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_rport.c deleted file mode 100644 index fe0463a1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_fcs_rport.c +++ /dev/null @@ -1,3019 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * rport.c Remote port implementation. - */ - -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfa_fcs.h" -#include "bfa_fcbuild.h" - -BFA_TRC_FILE(FCS, RPORT); - -static u32 -bfa_fcs_rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT * 1000; - /* In millisecs */ -/* - * forward declarations - */ -static struct bfa_fcs_rport_s *bfa_fcs_rport_alloc( - struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid); -static void bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport); -static void bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, - struct fc_logi_s *plogi); -static void bfa_fcs_rport_timeout(void *arg); -static void bfa_fcs_rport_send_plogi(void *rport_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_send_plogiacc(void *rport_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_plogi_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs); -static void bfa_fcs_rport_send_adisc(void *rport_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_adisc_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs); -static void bfa_fcs_rport_send_nsdisc(void *rport_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_gidpn_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs); -static void bfa_fcs_rport_gpnid_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs); -static void bfa_fcs_rport_send_logo(void *rport_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rport_send_logo_acc(void *rport_cbarg); -static void bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u16 len); -static void bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u8 reason_code, - u8 reason_code_expl); -static void bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u16 len); -static void bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport); - -static void bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, - enum rport_event event); -static void bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, - enum rport_event event); - -static struct bfa_sm_table_s rport_sm_table[] = { - {BFA_SM(bfa_fcs_rport_sm_uninit), BFA_RPORT_UNINIT}, - {BFA_SM(bfa_fcs_rport_sm_plogi_sending), BFA_RPORT_PLOGI}, - {BFA_SM(bfa_fcs_rport_sm_plogiacc_sending), BFA_RPORT_ONLINE}, - {BFA_SM(bfa_fcs_rport_sm_plogi_retry), BFA_RPORT_PLOGI_RETRY}, - {BFA_SM(bfa_fcs_rport_sm_plogi), BFA_RPORT_PLOGI}, - {BFA_SM(bfa_fcs_rport_sm_hal_online), BFA_RPORT_ONLINE}, - {BFA_SM(bfa_fcs_rport_sm_online), BFA_RPORT_ONLINE}, - {BFA_SM(bfa_fcs_rport_sm_nsquery_sending), BFA_RPORT_NSQUERY}, - {BFA_SM(bfa_fcs_rport_sm_nsquery), BFA_RPORT_NSQUERY}, - {BFA_SM(bfa_fcs_rport_sm_adisc_sending), BFA_RPORT_ADISC}, - {BFA_SM(bfa_fcs_rport_sm_adisc), BFA_RPORT_ADISC}, - {BFA_SM(bfa_fcs_rport_sm_fc4_logorcv), BFA_RPORT_LOGORCV}, - {BFA_SM(bfa_fcs_rport_sm_fc4_logosend), BFA_RPORT_LOGO}, - {BFA_SM(bfa_fcs_rport_sm_fc4_offline), BFA_RPORT_OFFLINE}, - {BFA_SM(bfa_fcs_rport_sm_hcb_offline), BFA_RPORT_OFFLINE}, - {BFA_SM(bfa_fcs_rport_sm_hcb_logorcv), BFA_RPORT_LOGORCV}, - {BFA_SM(bfa_fcs_rport_sm_hcb_logosend), BFA_RPORT_LOGO}, - {BFA_SM(bfa_fcs_rport_sm_logo_sending), BFA_RPORT_LOGO}, - {BFA_SM(bfa_fcs_rport_sm_offline), BFA_RPORT_OFFLINE}, - {BFA_SM(bfa_fcs_rport_sm_nsdisc_sending), BFA_RPORT_NSDISC}, - {BFA_SM(bfa_fcs_rport_sm_nsdisc_retry), BFA_RPORT_NSDISC}, - {BFA_SM(bfa_fcs_rport_sm_nsdisc_sent), BFA_RPORT_NSDISC}, -}; - -/* - * Beginning state. - */ -static void -bfa_fcs_rport_sm_uninit(struct bfa_fcs_rport_s *rport, enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_PLOGI_SEND: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); - rport->plogi_retries = 0; - bfa_fcs_rport_send_plogi(rport, NULL); - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - - case RPSM_EVENT_PLOGI_COMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - bfa_fcs_rport_hal_online(rport); - break; - - case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_ADDRESS_DISC: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - break; - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * PLOGI is being sent. - */ -static void -bfa_fcs_rport_sm_plogi_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FCXP_SENT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - - case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_SCN: - /* query the NS */ - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - break; - - case RPSM_EVENT_LOGO_IMP: - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - break; - - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * PLOGI is being sent. - */ -static void -bfa_fcs_rport_sm_plogiacc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FCXP_SENT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - bfa_fcs_rport_hal_online(rport); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_PLOGI_COMP: - case RPSM_EVENT_SCN: - /* - * Ignore, SCN is possibly online notification. - */ - break; - - case RPSM_EVENT_ADDRESS_CHANGE: - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - break; - - case RPSM_EVENT_LOGO_IMP: - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - break; - - case RPSM_EVENT_HCB_OFFLINE: - /* - * Ignore BFA callback, on a PLOGI receive we call bfa offline. - */ - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * PLOGI is sent. - */ -static void -bfa_fcs_rport_sm_plogi_retry(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_TIMEOUT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); - bfa_fcs_rport_send_plogi(rport, NULL); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_LOGO_RCVD: - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - - case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_SCN: - bfa_timer_stop(&rport->timer); - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - break; - - case RPSM_EVENT_LOGO_IMP: - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_timer_stop(&rport->timer); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - break; - - case RPSM_EVENT_PLOGI_COMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_hal_online(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * PLOGI is sent. - */ -static void -bfa_fcs_rport_sm_plogi(struct bfa_fcs_rport_s *rport, enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_ACCEPTED: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - rport->plogi_retries = 0; - bfa_fcs_rport_hal_online(rport); - break; - - case RPSM_EVENT_LOGO_RCVD: - bfa_fcs_rport_send_logo_acc(rport); - /* - * !! fall through !! - */ - case RPSM_EVENT_PRLO_RCVD: - if (rport->prlo == BFA_TRUE) - bfa_fcs_rport_send_prlo_acc(rport); - - bfa_fcxp_discard(rport->fcxp); - /* - * !! fall through !! - */ - case RPSM_EVENT_FAILED: - if (rport->plogi_retries < BFA_FCS_RPORT_MAX_RETRIES) { - rport->plogi_retries++; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_retry); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - BFA_FCS_RETRY_TIMEOUT); - } else { - bfa_stats(rport->port, rport_del_max_plogi_retry); - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - } - break; - - case RPSM_EVENT_PLOGI_RETRY: - rport->plogi_retries = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_retry); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - (FC_RA_TOV * 1000)); - break; - - case RPSM_EVENT_LOGO_IMP: - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_fcxp_discard(rport->fcxp); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - break; - - case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_SCN: - bfa_fcxp_discard(rport->fcxp); - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_PLOGI_COMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_hal_online(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * PLOGI is complete. Awaiting BFA rport online callback. FC-4s - * are offline. - */ -static void -bfa_fcs_rport_sm_hal_online(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_HCB_ONLINE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_online); - bfa_fcs_rport_online_action(rport); - break; - - case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_PLOGI_COMP: - break; - - case RPSM_EVENT_LOGO_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv); - bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); - break; - - case RPSM_EVENT_LOGO_IMP: - case RPSM_EVENT_ADDRESS_CHANGE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); - bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); - break; - - case RPSM_EVENT_PLOGI_RCVD: - rport->plogi_pending = BFA_TRUE; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); - bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend); - bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); - break; - - case RPSM_EVENT_SCN: - /* - * @todo - * Ignore SCN - PLOGI just completed, FC-4 login should detect - * device failures. - */ - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport is ONLINE. FC-4s active. - */ -static void -bfa_fcs_rport_sm_online(struct bfa_fcs_rport_s *rport, enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_SCN: - if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsquery_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - } else { - bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending); - bfa_fcs_rport_send_adisc(rport, NULL); - } - break; - - case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_LOGO_IMP: - case RPSM_EVENT_ADDRESS_CHANGE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_PLOGI_COMP: - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * An SCN event is received in ONLINE state. NS query is being sent - * prior to ADISC authentication with rport. FC-4s are paused. - */ -static void -bfa_fcs_rport_sm_nsquery_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FCXP_SENT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsquery); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_SCN: - /* - * ignore SCN, wait for response to query itself - */ - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_LOGO_IMP: - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - break; - - case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_PLOGI_COMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_offline_action(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * An SCN event is received in ONLINE state. NS query is sent to rport. - * FC-4s are paused. - */ -static void -bfa_fcs_rport_sm_nsquery(struct bfa_fcs_rport_s *rport, enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_ACCEPTED: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc_sending); - bfa_fcs_rport_send_adisc(rport, NULL); - break; - - case RPSM_EVENT_FAILED: - rport->ns_retries++; - if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsquery_sending); - bfa_fcs_rport_send_nsdisc(rport, NULL); - } else { - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); - bfa_fcs_rport_offline_action(rport); - } - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_SCN: - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_PLOGI_COMP: - case RPSM_EVENT_ADDRESS_CHANGE: - case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_LOGO_IMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_offline_action(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * An SCN event is received in ONLINE state. ADISC is being sent for - * authenticating with rport. FC-4s are paused. - */ -static void -bfa_fcs_rport_sm_adisc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FCXP_SENT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_adisc); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_LOGO_IMP: - case RPSM_EVENT_ADDRESS_CHANGE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_SCN: - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_offline_action(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * An SCN event is received in ONLINE state. ADISC is to rport. - * FC-4s are paused. - */ -static void -bfa_fcs_rport_sm_adisc(struct bfa_fcs_rport_s *rport, enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_ACCEPTED: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_online); - break; - - case RPSM_EVENT_PLOGI_RCVD: - /* - * Too complex to cleanup FC-4 & rport and then acc to PLOGI. - * At least go offline when a PLOGI is received. - */ - bfa_fcxp_discard(rport->fcxp); - /* - * !!! fall through !!! - */ - - case RPSM_EVENT_FAILED: - case RPSM_EVENT_ADDRESS_CHANGE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_SCN: - /* - * already processing RSCN - */ - break; - - case RPSM_EVENT_LOGO_IMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_offline); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_offline_action(rport); - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logorcv); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_offline_action(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport has sent LOGO. Awaiting FC-4 offline completion callback. - */ -static void -bfa_fcs_rport_sm_fc4_logorcv(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FC4_OFFLINE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logorcv); - bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_ADDRESS_CHANGE: - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * LOGO needs to be sent to rport. Awaiting FC-4 offline completion - * callback. - */ -static void -bfa_fcs_rport_sm_fc4_logosend(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FC4_OFFLINE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend); - bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport is going offline. Awaiting FC-4 offline completion callback. - */ -static void -bfa_fcs_rport_sm_fc4_offline(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FC4_OFFLINE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); - bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_OFFLINE); - break; - - case RPSM_EVENT_SCN: - case RPSM_EVENT_LOGO_IMP: - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_ADDRESS_CHANGE: - /* - * rport is already going offline. - * SCN - ignore and wait till transitioning to offline state - */ - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_fc4_logosend); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport is offline. FC-4s are offline. Awaiting BFA rport offline - * callback. - */ -static void -bfa_fcs_rport_sm_hcb_offline(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_HCB_OFFLINE: - if (bfa_fcs_lport_is_online(rport->port) && - (rport->plogi_pending)) { - rport->plogi_pending = BFA_FALSE; - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_plogiacc_sending); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - } - /* - * !! fall through !! - */ - - case RPSM_EVENT_ADDRESS_CHANGE: - if (bfa_fcs_lport_is_online(rport->port)) { - if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - } else { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_plogi_sending); - rport->plogi_retries = 0; - bfa_fcs_rport_send_plogi(rport, NULL); - } - } else { - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - } - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_SCN: - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_PLOGI_RCVD: - case RPSM_EVENT_LOGO_IMP: - /* - * Ignore, already offline. - */ - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport is offline. FC-4s are offline. Awaiting BFA rport offline - * callback to send LOGO accept. - */ -static void -bfa_fcs_rport_sm_hcb_logorcv(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_HCB_OFFLINE: - case RPSM_EVENT_ADDRESS_CHANGE: - if (rport->pid && (rport->prlo == BFA_TRUE)) - bfa_fcs_rport_send_prlo_acc(rport); - if (rport->pid && (rport->prlo == BFA_FALSE)) - bfa_fcs_rport_send_logo_acc(rport); - /* - * If the lport is online and if the rport is not a well - * known address port, - * we try to re-discover the r-port. - */ - if (bfa_fcs_lport_is_online(rport->port) && - (!BFA_FCS_PID_IS_WKA(rport->pid))) { - if (bfa_fcs_fabric_is_switched(rport->port->fabric)) { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - } else { - /* For N2N Direct Attach, try to re-login */ - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_plogi_sending); - rport->plogi_retries = 0; - bfa_fcs_rport_send_plogi(rport, NULL); - } - } else { - /* - * if it is not a well known address, reset the - * pid to 0. - */ - if (!BFA_FCS_PID_IS_WKA(rport->pid)) - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - } - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_logosend); - break; - - case RPSM_EVENT_LOGO_IMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hcb_offline); - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - /* - * Ignore - already processing a LOGO. - */ - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport is being deleted. FC-4s are offline. - * Awaiting BFA rport offline - * callback to send LOGO. - */ -static void -bfa_fcs_rport_sm_hcb_logosend(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_HCB_OFFLINE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_logo_sending); - bfa_fcs_rport_send_logo(rport, NULL); - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_ADDRESS_CHANGE: - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport is being deleted. FC-4s are offline. LOGO is being sent. - */ -static void -bfa_fcs_rport_sm_logo_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FCXP_SENT: - /* Once LOGO is sent, we donot wait for the response */ - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_SCN: - case RPSM_EVENT_ADDRESS_CHANGE: - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_free(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport is offline. FC-4s are offline. BFA rport is offline. - * Timer active to delete stale rport. - */ -static void -bfa_fcs_rport_sm_offline(struct bfa_fcs_rport_s *rport, enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_TIMEOUT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_SCN: - case RPSM_EVENT_ADDRESS_CHANGE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - bfa_timer_stop(&rport->timer); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_LOGO_IMP: - break; - - case RPSM_EVENT_PLOGI_COMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_hal_online(rport); - break; - - case RPSM_EVENT_PLOGI_SEND: - bfa_timer_stop(&rport->timer); - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); - rport->plogi_retries = 0; - bfa_fcs_rport_send_plogi(rport, NULL); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport address has changed. Nameserver discovery request is being sent. - */ -static void -bfa_fcs_rport_sm_nsdisc_sending(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_FCXP_SENT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sent); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - - case RPSM_EVENT_SCN: - case RPSM_EVENT_LOGO_RCVD: - case RPSM_EVENT_PRLO_RCVD: - case RPSM_EVENT_PLOGI_SEND: - break; - - case RPSM_EVENT_ADDRESS_CHANGE: - rport->ns_retries = 0; /* reset the retry count */ - break; - - case RPSM_EVENT_LOGO_IMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - break; - - case RPSM_EVENT_PLOGI_COMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rport->fcxp_wqe); - bfa_fcs_rport_hal_online(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Nameserver discovery failed. Waiting for timeout to retry. - */ -static void -bfa_fcs_rport_sm_nsdisc_retry(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_TIMEOUT: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - bfa_fcs_rport_send_nsdisc(rport, NULL); - break; - - case RPSM_EVENT_SCN: - case RPSM_EVENT_ADDRESS_CHANGE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_nsdisc_sending); - bfa_timer_stop(&rport->timer); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - - case RPSM_EVENT_LOGO_IMP: - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_timer_stop(&rport->timer); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - break; - - case RPSM_EVENT_LOGO_RCVD: - bfa_fcs_rport_send_logo_acc(rport); - break; - case RPSM_EVENT_PRLO_RCVD: - bfa_fcs_rport_send_prlo_acc(rport); - break; - - case RPSM_EVENT_PLOGI_COMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - bfa_timer_stop(&rport->timer); - bfa_fcs_rport_hal_online(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -/* - * Rport address has changed. Nameserver discovery request is sent. - */ -static void -bfa_fcs_rport_sm_nsdisc_sent(struct bfa_fcs_rport_s *rport, - enum rport_event event) -{ - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPSM_EVENT_ACCEPTED: - case RPSM_EVENT_ADDRESS_CHANGE: - if (rport->pid) { - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogi_sending); - bfa_fcs_rport_send_plogi(rport, NULL); - } else { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); - rport->ns_retries = 0; - bfa_fcs_rport_send_nsdisc(rport, NULL); - } - break; - - case RPSM_EVENT_FAILED: - rport->ns_retries++; - if (rport->ns_retries < BFA_FCS_RPORT_MAX_RETRIES) { - bfa_sm_set_state(rport, - bfa_fcs_rport_sm_nsdisc_sending); - bfa_fcs_rport_send_nsdisc(rport, NULL); - } else { - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - }; - break; - - case RPSM_EVENT_DELETE: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_free(rport); - break; - - case RPSM_EVENT_PLOGI_RCVD: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_plogiacc_sending); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_send_plogiacc(rport, NULL); - break; - - case RPSM_EVENT_LOGO_IMP: - rport->pid = 0; - bfa_sm_set_state(rport, bfa_fcs_rport_sm_offline); - bfa_fcxp_discard(rport->fcxp); - bfa_timer_start(rport->fcs->bfa, &rport->timer, - bfa_fcs_rport_timeout, rport, - bfa_fcs_rport_del_timeout); - break; - - - case RPSM_EVENT_PRLO_RCVD: - bfa_fcs_rport_send_prlo_acc(rport); - break; - case RPSM_EVENT_SCN: - /* - * ignore, wait for NS query response - */ - break; - - case RPSM_EVENT_LOGO_RCVD: - /* - * Not logged-in yet. Accept LOGO. - */ - bfa_fcs_rport_send_logo_acc(rport); - break; - - case RPSM_EVENT_PLOGI_COMP: - bfa_sm_set_state(rport, bfa_fcs_rport_sm_hal_online); - bfa_fcxp_discard(rport->fcxp); - bfa_fcs_rport_hal_online(rport); - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - - - -/* - * fcs_rport_private FCS RPORT provate functions - */ - -static void -bfa_fcs_rport_send_plogi(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_lport_s *port = rport->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(rport->fcs, rport->pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_plogi, rport); - return; - } - rport->fcxp = fcxp; - - len = fc_plogi_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_lport_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_rport_plogi_response, - (void *)rport, FC_MAX_PDUSZ, FC_ELS_TOV); - - rport->stats.plogis++; - bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_rport_plogi_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; - struct fc_logi_s *plogi_rsp; - struct fc_ls_rjt_s *ls_rjt; - struct bfa_fcs_rport_s *twin; - struct list_head *qe; - - bfa_trc(rport->fcs, rport->pwwn); - - /* - * Sanity Checks - */ - if (req_status != BFA_STATUS_OK) { - bfa_trc(rport->fcs, req_status); - rport->stats.plogi_failed++; - bfa_sm_send_event(rport, RPSM_EVENT_FAILED); - return; - } - - plogi_rsp = (struct fc_logi_s *) BFA_FCXP_RSP_PLD(fcxp); - - /* - * Check for failure first. - */ - if (plogi_rsp->els_cmd.els_code != FC_ELS_ACC) { - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - - bfa_trc(rport->fcs, ls_rjt->reason_code); - bfa_trc(rport->fcs, ls_rjt->reason_code_expl); - - if ((ls_rjt->reason_code == FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD) && - (ls_rjt->reason_code_expl == FC_LS_RJT_EXP_INSUFF_RES)) { - rport->stats.rjt_insuff_res++; - bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RETRY); - return; - } - - rport->stats.plogi_rejects++; - bfa_sm_send_event(rport, RPSM_EVENT_FAILED); - return; - } - - /* - * PLOGI is complete. Make sure this device is not one of the known - * device with a new FC port address. - */ - list_for_each(qe, &rport->port->rport_q) { - twin = (struct bfa_fcs_rport_s *) qe; - if (twin == rport) - continue; - if (!rport->pwwn && (plogi_rsp->port_name == twin->pwwn)) { - bfa_trc(rport->fcs, twin->pid); - bfa_trc(rport->fcs, rport->pid); - - /* Update plogi stats in twin */ - twin->stats.plogis += rport->stats.plogis; - twin->stats.plogi_rejects += - rport->stats.plogi_rejects; - twin->stats.plogi_timeouts += - rport->stats.plogi_timeouts; - twin->stats.plogi_failed += - rport->stats.plogi_failed; - twin->stats.plogi_rcvd += rport->stats.plogi_rcvd; - twin->stats.plogi_accs++; - - bfa_sm_send_event(rport, RPSM_EVENT_DELETE); - - bfa_fcs_rport_update(twin, plogi_rsp); - twin->pid = rsp_fchs->s_id; - bfa_sm_send_event(twin, RPSM_EVENT_PLOGI_COMP); - return; - } - } - - /* - * Normal login path -- no evil twins. - */ - rport->stats.plogi_accs++; - bfa_fcs_rport_update(rport, plogi_rsp); - bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); -} - -static void -bfa_fcs_rport_send_plogiacc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_lport_s *port = rport->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->reply_oxid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_plogiacc, rport); - return; - } - rport->fcxp = fcxp; - - len = fc_plogi_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rport->pid, bfa_fcs_lport_get_fcid(port), - rport->reply_oxid, port->port_cfg.pwwn, - port->port_cfg.nwwn, - bfa_fcport_get_maxfrsize(port->fcs->bfa), - bfa_fcport_get_rx_bbcredit(port->fcs->bfa)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); - - bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_rport_send_adisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_lport_s *port = rport->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(rport->fcs, rport->pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_adisc, rport); - return; - } - rport->fcxp = fcxp; - - len = fc_adisc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_lport_get_fcid(port), 0, - port->port_cfg.pwwn, port->port_cfg.nwwn); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_rport_adisc_response, - rport, FC_MAX_PDUSZ, FC_ELS_TOV); - - rport->stats.adisc_sent++; - bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_rport_adisc_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; - void *pld = bfa_fcxp_get_rspbuf(fcxp); - struct fc_ls_rjt_s *ls_rjt; - - if (req_status != BFA_STATUS_OK) { - bfa_trc(rport->fcs, req_status); - rport->stats.adisc_failed++; - bfa_sm_send_event(rport, RPSM_EVENT_FAILED); - return; - } - - if (fc_adisc_rsp_parse((struct fc_adisc_s *)pld, rsp_len, rport->pwwn, - rport->nwwn) == FC_PARSE_OK) { - rport->stats.adisc_accs++; - bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); - return; - } - - rport->stats.adisc_rejects++; - ls_rjt = pld; - bfa_trc(rport->fcs, ls_rjt->els_cmd.els_code); - bfa_trc(rport->fcs, ls_rjt->reason_code); - bfa_trc(rport->fcs, ls_rjt->reason_code_expl); - bfa_sm_send_event(rport, RPSM_EVENT_FAILED); -} - -static void -bfa_fcs_rport_send_nsdisc(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_lport_s *port = rport->port; - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - int len; - bfa_cb_fcxp_send_t cbfn; - - bfa_trc(rport->fcs, rport->pid); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_nsdisc, rport); - return; - } - rport->fcxp = fcxp; - - if (rport->pwwn) { - len = fc_gidpn_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_lport_get_fcid(port), 0, rport->pwwn); - cbfn = bfa_fcs_rport_gidpn_response; - } else { - len = fc_gpnid_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - bfa_fcs_lport_get_fcid(port), 0, rport->pid); - cbfn = bfa_fcs_rport_gpnid_response; - } - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, cbfn, - (void *)rport, FC_MAX_PDUSZ, FC_FCCT_TOV); - - bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); -} - -static void -bfa_fcs_rport_gidpn_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; - struct ct_hdr_s *cthdr; - struct fcgs_gidpn_resp_s *gidpn_rsp; - struct bfa_fcs_rport_s *twin; - struct list_head *qe; - - bfa_trc(rport->fcs, rport->pwwn); - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - /* Check if the pid is the same as before. */ - gidpn_rsp = (struct fcgs_gidpn_resp_s *) (cthdr + 1); - - if (gidpn_rsp->dap == rport->pid) { - /* Device is online */ - bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); - } else { - /* - * Device's PID has changed. We need to cleanup - * and re-login. If there is another device with - * the the newly discovered pid, send an scn notice - * so that its new pid can be discovered. - */ - list_for_each(qe, &rport->port->rport_q) { - twin = (struct bfa_fcs_rport_s *) qe; - if (twin == rport) - continue; - if (gidpn_rsp->dap == twin->pid) { - bfa_trc(rport->fcs, twin->pid); - bfa_trc(rport->fcs, rport->pid); - - twin->pid = 0; - bfa_sm_send_event(twin, - RPSM_EVENT_ADDRESS_CHANGE); - } - } - rport->pid = gidpn_rsp->dap; - bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_CHANGE); - } - return; - } - - /* - * Reject Response - */ - switch (cthdr->reason_code) { - case CT_RSN_LOGICAL_BUSY: - /* - * Need to retry - */ - bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT); - break; - - case CT_RSN_UNABLE_TO_PERF: - /* - * device doesn't exist : Start timer to cleanup this later. - */ - bfa_sm_send_event(rport, RPSM_EVENT_FAILED); - break; - - default: - bfa_sm_send_event(rport, RPSM_EVENT_FAILED); - break; - } -} - -static void -bfa_fcs_rport_gpnid_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; - struct ct_hdr_s *cthdr; - - bfa_trc(rport->fcs, rport->pwwn); - - cthdr = (struct ct_hdr_s *) BFA_FCXP_RSP_PLD(fcxp); - cthdr->cmd_rsp_code = be16_to_cpu(cthdr->cmd_rsp_code); - - if (cthdr->cmd_rsp_code == CT_RSP_ACCEPT) { - bfa_sm_send_event(rport, RPSM_EVENT_ACCEPTED); - return; - } - - /* - * Reject Response - */ - switch (cthdr->reason_code) { - case CT_RSN_LOGICAL_BUSY: - /* - * Need to retry - */ - bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT); - break; - - case CT_RSN_UNABLE_TO_PERF: - /* - * device doesn't exist : Start timer to cleanup this later. - */ - bfa_sm_send_event(rport, RPSM_EVENT_FAILED); - break; - - default: - bfa_sm_send_event(rport, RPSM_EVENT_FAILED); - break; - } -} - -/* - * Called to send a logout to the rport. - */ -static void -bfa_fcs_rport_send_logo(void *rport_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_lport_s *port; - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - u16 len; - - bfa_trc(rport->fcs, rport->pid); - - port = rport->port; - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rport->fcxp_wqe, - bfa_fcs_rport_send_logo, rport); - return; - } - rport->fcxp = fcxp; - - len = fc_logo_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_lport_get_fcid(port), 0, - bfa_fcs_lport_get_pwwn(port)); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, - rport, FC_MAX_PDUSZ, FC_ELS_TOV); - - rport->stats.logos++; - bfa_fcxp_discard(rport->fcxp); - bfa_sm_send_event(rport, RPSM_EVENT_FCXP_SENT); -} - -/* - * Send ACC for a LOGO received. - */ -static void -bfa_fcs_rport_send_logo_acc(void *rport_cbarg) -{ - struct bfa_fcs_rport_s *rport = rport_cbarg; - struct bfa_fcs_lport_s *port; - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - u16 len; - - bfa_trc(rport->fcs, rport->pid); - - port = rport->port; - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - rport->stats.logo_rcvd++; - len = fc_logo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rport->pid, bfa_fcs_lport_get_fcid(port), - rport->reply_oxid); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); -} - -/* - * brief - * This routine will be called by bfa_timer on timer timeouts. - * - * param[in] rport - pointer to bfa_fcs_lport_ns_t. - * param[out] rport_status - pointer to return vport status in - * - * return - * void - * - * Special Considerations: - * - * note - */ -static void -bfa_fcs_rport_timeout(void *arg) -{ - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) arg; - - rport->stats.plogi_timeouts++; - bfa_stats(rport->port, rport_plogi_timeouts); - bfa_sm_send_event(rport, RPSM_EVENT_TIMEOUT); -} - -static void -bfa_fcs_rport_process_prli(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u16 len) -{ - struct bfa_fcxp_s *fcxp; - struct fchs_s fchs; - struct bfa_fcs_lport_s *port = rport->port; - struct fc_prli_s *prli; - - bfa_trc(port->fcs, rx_fchs->s_id); - bfa_trc(port->fcs, rx_fchs->d_id); - - rport->stats.prli_rcvd++; - - /* - * We are in Initiator Mode - */ - prli = (struct fc_prli_s *) (rx_fchs + 1); - - if (prli->parampage.servparams.target) { - /* - * PRLI from a target ? - * Send the Acc. - * PRLI sent by us will be used to transition the IT nexus, - * once the response is received from the target. - */ - bfa_trc(port->fcs, rx_fchs->s_id); - rport->scsi_function = BFA_RPORT_TARGET; - } else { - bfa_trc(rport->fcs, prli->parampage.type); - rport->scsi_function = BFA_RPORT_INITIATOR; - bfa_fcs_itnim_is_initiator(rport->itnim); - } - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - len = fc_prli_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, port->port_cfg.roles); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); -} - -static void -bfa_fcs_rport_process_rpsc(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u16 len) -{ - struct bfa_fcxp_s *fcxp; - struct fchs_s fchs; - struct bfa_fcs_lport_s *port = rport->port; - struct fc_rpsc_speed_info_s speeds; - struct bfa_port_attr_s pport_attr; - - bfa_trc(port->fcs, rx_fchs->s_id); - bfa_trc(port->fcs, rx_fchs->d_id); - - rport->stats.rpsc_rcvd++; - speeds.port_speed_cap = - RPSC_SPEED_CAP_1G | RPSC_SPEED_CAP_2G | RPSC_SPEED_CAP_4G | - RPSC_SPEED_CAP_8G; - - /* - * get curent speed from pport attributes from BFA - */ - bfa_fcport_get_attr(port->fcs->bfa, &pport_attr); - - speeds.port_op_speed = fc_bfa_speed_to_rpsc_operspeed(pport_attr.speed); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - len = fc_rpsc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, &speeds); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, NULL, NULL, FC_MAX_PDUSZ, 0); -} - -static void -bfa_fcs_rport_process_adisc(struct bfa_fcs_rport_s *rport, - struct fchs_s *rx_fchs, u16 len) -{ - struct bfa_fcxp_s *fcxp; - struct fchs_s fchs; - struct bfa_fcs_lport_s *port = rport->port; - struct fc_adisc_s *adisc; - - bfa_trc(port->fcs, rx_fchs->s_id); - bfa_trc(port->fcs, rx_fchs->d_id); - - rport->stats.adisc_rcvd++; - - adisc = (struct fc_adisc_s *) (rx_fchs + 1); - - /* - * Accept if the itnim for this rport is online. - * Else reject the ADISC. - */ - if (bfa_fcs_itnim_get_online_state(rport->itnim) == BFA_STATUS_OK) { - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - - len = fc_adisc_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, port->port_cfg.pwwn, - port->port_cfg.nwwn); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); - } else { - rport->stats.adisc_rejected++; - bfa_fcs_rport_send_ls_rjt(rport, rx_fchs, - FC_LS_RJT_RSN_UNABLE_TO_PERF_CMD, - FC_LS_RJT_EXP_LOGIN_REQUIRED); - } -} - -static void -bfa_fcs_rport_hal_online(struct bfa_fcs_rport_s *rport) -{ - struct bfa_fcs_lport_s *port = rport->port; - struct bfa_rport_info_s rport_info; - - rport_info.pid = rport->pid; - rport_info.local_pid = port->pid; - rport_info.lp_tag = port->lp_tag; - rport_info.vf_id = port->fabric->vf_id; - rport_info.vf_en = port->fabric->is_vf; - rport_info.fc_class = rport->fc_cos; - rport_info.cisc = rport->cisc; - rport_info.max_frmsz = rport->maxfrsize; - bfa_rport_online(rport->bfa_rport, &rport_info); -} - -static struct bfa_fcs_rport_s * -bfa_fcs_rport_alloc(struct bfa_fcs_lport_s *port, wwn_t pwwn, u32 rpid) -{ - struct bfa_fcs_s *fcs = port->fcs; - struct bfa_fcs_rport_s *rport; - struct bfad_rport_s *rport_drv; - - /* - * allocate rport - */ - if (bfa_fcb_rport_alloc(fcs->bfad, &rport, &rport_drv) - != BFA_STATUS_OK) { - bfa_trc(fcs, rpid); - return NULL; - } - - /* - * Initialize r-port - */ - rport->port = port; - rport->fcs = fcs; - rport->rp_drv = rport_drv; - rport->pid = rpid; - rport->pwwn = pwwn; - - /* - * allocate BFA rport - */ - rport->bfa_rport = bfa_rport_create(port->fcs->bfa, rport); - if (!rport->bfa_rport) { - bfa_trc(fcs, rpid); - kfree(rport_drv); - return NULL; - } - - /* - * allocate FC-4s - */ - WARN_ON(!bfa_fcs_lport_is_initiator(port)); - - if (bfa_fcs_lport_is_initiator(port)) { - rport->itnim = bfa_fcs_itnim_create(rport); - if (!rport->itnim) { - bfa_trc(fcs, rpid); - bfa_sm_send_event(rport->bfa_rport, - BFA_RPORT_SM_DELETE); - kfree(rport_drv); - return NULL; - } - } - - bfa_fcs_lport_add_rport(port, rport); - - bfa_sm_set_state(rport, bfa_fcs_rport_sm_uninit); - - /* Initialize the Rport Features(RPF) Sub Module */ - if (!BFA_FCS_PID_IS_WKA(rport->pid)) - bfa_fcs_rpf_init(rport); - - return rport; -} - - -static void -bfa_fcs_rport_free(struct bfa_fcs_rport_s *rport) -{ - struct bfa_fcs_lport_s *port = rport->port; - - /* - * - delete FC-4s - * - delete BFA rport - * - remove from queue of rports - */ - if (bfa_fcs_lport_is_initiator(port)) { - bfa_fcs_itnim_delete(rport->itnim); - if (rport->pid != 0 && !BFA_FCS_PID_IS_WKA(rport->pid)) - bfa_fcs_rpf_rport_offline(rport); - } - - bfa_sm_send_event(rport->bfa_rport, BFA_RPORT_SM_DELETE); - bfa_fcs_lport_del_rport(port, rport); - kfree(rport->rp_drv); -} - -static void -bfa_fcs_rport_aen_post(struct bfa_fcs_rport_s *rport, - enum bfa_rport_aen_event event, - struct bfa_rport_aen_data_s *data) -{ - struct bfa_fcs_lport_s *port = rport->port; - struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; - struct bfa_aen_entry_s *aen_entry; - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - if (event == BFA_RPORT_AEN_QOS_PRIO) - aen_entry->aen_data.rport.priv.qos = data->priv.qos; - else if (event == BFA_RPORT_AEN_QOS_FLOWID) - aen_entry->aen_data.rport.priv.qos = data->priv.qos; - - aen_entry->aen_data.rport.vf_id = rport->port->fabric->vf_id; - aen_entry->aen_data.rport.ppwwn = bfa_fcs_lport_get_pwwn( - bfa_fcs_get_base_port(rport->fcs)); - aen_entry->aen_data.rport.lpwwn = bfa_fcs_lport_get_pwwn(rport->port); - aen_entry->aen_data.rport.rpwwn = rport->pwwn; - - /* Send the AEN notification */ - bfad_im_post_vendor_event(aen_entry, bfad, ++rport->fcs->fcs_aen_seq, - BFA_AEN_CAT_RPORT, event); -} - -static void -bfa_fcs_rport_online_action(struct bfa_fcs_rport_s *rport) -{ - struct bfa_fcs_lport_s *port = rport->port; - struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; - char lpwwn_buf[BFA_STRING_32]; - char rpwwn_buf[BFA_STRING_32]; - - rport->stats.onlines++; - - if ((!rport->pid) || (!rport->pwwn)) { - bfa_trc(rport->fcs, rport->pid); - bfa_sm_fault(rport->fcs, rport->pid); - } - - if (bfa_fcs_lport_is_initiator(port)) { - bfa_fcs_itnim_rport_online(rport->itnim); - if (!BFA_FCS_PID_IS_WKA(rport->pid)) - bfa_fcs_rpf_rport_online(rport); - }; - - wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); - wwn2str(rpwwn_buf, rport->pwwn); - if (!BFA_FCS_PID_IS_WKA(rport->pid)) { - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Remote port (WWN = %s) online for logical port (WWN = %s)\n", - rpwwn_buf, lpwwn_buf); - bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_ONLINE, NULL); - } -} - -static void -bfa_fcs_rport_offline_action(struct bfa_fcs_rport_s *rport) -{ - struct bfa_fcs_lport_s *port = rport->port; - struct bfad_s *bfad = (struct bfad_s *)port->fcs->bfad; - char lpwwn_buf[BFA_STRING_32]; - char rpwwn_buf[BFA_STRING_32]; - - rport->stats.offlines++; - rport->plogi_pending = BFA_FALSE; - - wwn2str(lpwwn_buf, bfa_fcs_lport_get_pwwn(port)); - wwn2str(rpwwn_buf, rport->pwwn); - if (!BFA_FCS_PID_IS_WKA(rport->pid)) { - if (bfa_fcs_lport_is_online(rport->port) == BFA_TRUE) { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "Remote port (WWN = %s) connectivity lost for " - "logical port (WWN = %s)\n", - rpwwn_buf, lpwwn_buf); - bfa_fcs_rport_aen_post(rport, - BFA_RPORT_AEN_DISCONNECT, NULL); - } else { - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Remote port (WWN = %s) offlined by " - "logical port (WWN = %s)\n", - rpwwn_buf, lpwwn_buf); - bfa_fcs_rport_aen_post(rport, - BFA_RPORT_AEN_OFFLINE, NULL); - } - } - - if (bfa_fcs_lport_is_initiator(port)) { - bfa_fcs_itnim_rport_offline(rport->itnim); - if (!BFA_FCS_PID_IS_WKA(rport->pid)) - bfa_fcs_rpf_rport_offline(rport); - } -} - -/* - * Update rport parameters from PLOGI or PLOGI accept. - */ -static void -bfa_fcs_rport_update(struct bfa_fcs_rport_s *rport, struct fc_logi_s *plogi) -{ - bfa_fcs_lport_t *port = rport->port; - - /* - * - port name - * - node name - */ - rport->pwwn = plogi->port_name; - rport->nwwn = plogi->node_name; - - /* - * - class of service - */ - rport->fc_cos = 0; - if (plogi->class3.class_valid) - rport->fc_cos = FC_CLASS_3; - - if (plogi->class2.class_valid) - rport->fc_cos |= FC_CLASS_2; - - /* - * - CISC - * - MAX receive frame size - */ - rport->cisc = plogi->csp.cisc; - if (be16_to_cpu(plogi->class3.rxsz) < be16_to_cpu(plogi->csp.rxsz)) - rport->maxfrsize = be16_to_cpu(plogi->class3.rxsz); - else - rport->maxfrsize = be16_to_cpu(plogi->csp.rxsz); - - bfa_trc(port->fcs, be16_to_cpu(plogi->csp.bbcred)); - bfa_trc(port->fcs, port->fabric->bb_credit); - /* - * Direct Attach P2P mode : - * This is to handle a bug (233476) in IBM targets in Direct Attach - * Mode. Basically, in FLOGI Accept the target would have - * erroneously set the BB Credit to the value used in the FLOGI - * sent by the HBA. It uses the correct value (its own BB credit) - * in PLOGI. - */ - if ((!bfa_fcs_fabric_is_switched(port->fabric)) && - (be16_to_cpu(plogi->csp.bbcred) < port->fabric->bb_credit)) { - - bfa_trc(port->fcs, be16_to_cpu(plogi->csp.bbcred)); - bfa_trc(port->fcs, port->fabric->bb_credit); - - port->fabric->bb_credit = be16_to_cpu(plogi->csp.bbcred); - bfa_fcport_set_tx_bbcredit(port->fcs->bfa, - port->fabric->bb_credit, 0); - } - -} - -/* - * Called to handle LOGO received from an existing remote port. - */ -static void -bfa_fcs_rport_process_logo(struct bfa_fcs_rport_s *rport, struct fchs_s *fchs) -{ - rport->reply_oxid = fchs->ox_id; - bfa_trc(rport->fcs, rport->reply_oxid); - - rport->prlo = BFA_FALSE; - rport->stats.logo_rcvd++; - bfa_sm_send_event(rport, RPSM_EVENT_LOGO_RCVD); -} - - - -/* - * fcs_rport_public FCS rport public interfaces - */ - -/* - * Called by bport/vport to create a remote port instance for a discovered - * remote device. - * - * @param[in] port - base port or vport - * @param[in] rpid - remote port ID - * - * @return None - */ -struct bfa_fcs_rport_s * -bfa_fcs_rport_create(struct bfa_fcs_lport_s *port, u32 rpid) -{ - struct bfa_fcs_rport_s *rport; - - bfa_trc(port->fcs, rpid); - rport = bfa_fcs_rport_alloc(port, WWN_NULL, rpid); - if (!rport) - return NULL; - - bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_SEND); - return rport; -} - -/* - * Called to create a rport for which only the wwn is known. - * - * @param[in] port - base port - * @param[in] rpwwn - remote port wwn - * - * @return None - */ -struct bfa_fcs_rport_s * -bfa_fcs_rport_create_by_wwn(struct bfa_fcs_lport_s *port, wwn_t rpwwn) -{ - struct bfa_fcs_rport_s *rport; - bfa_trc(port->fcs, rpwwn); - rport = bfa_fcs_rport_alloc(port, rpwwn, 0); - if (!rport) - return NULL; - - bfa_sm_send_event(rport, RPSM_EVENT_ADDRESS_DISC); - return rport; -} -/* - * Called by bport in private loop topology to indicate that a - * rport has been discovered and plogi has been completed. - * - * @param[in] port - base port or vport - * @param[in] rpid - remote port ID - */ -void -bfa_fcs_rport_start(struct bfa_fcs_lport_s *port, struct fchs_s *fchs, - struct fc_logi_s *plogi) -{ - struct bfa_fcs_rport_s *rport; - - rport = bfa_fcs_rport_alloc(port, WWN_NULL, fchs->s_id); - if (!rport) - return; - - bfa_fcs_rport_update(rport, plogi); - - bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_COMP); -} - -/* - * Called by bport/vport to handle PLOGI received from a new remote port. - * If an existing rport does a plogi, it will be handled separately. - */ -void -bfa_fcs_rport_plogi_create(struct bfa_fcs_lport_s *port, struct fchs_s *fchs, - struct fc_logi_s *plogi) -{ - struct bfa_fcs_rport_s *rport; - - rport = bfa_fcs_rport_alloc(port, plogi->port_name, fchs->s_id); - if (!rport) - return; - - bfa_fcs_rport_update(rport, plogi); - - rport->reply_oxid = fchs->ox_id; - bfa_trc(rport->fcs, rport->reply_oxid); - - rport->stats.plogi_rcvd++; - bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD); -} - -/* - * Called by bport/vport to handle PLOGI received from an existing - * remote port. - */ -void -bfa_fcs_rport_plogi(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, - struct fc_logi_s *plogi) -{ - /* - * @todo Handle P2P and initiator-initiator. - */ - - bfa_fcs_rport_update(rport, plogi); - - rport->reply_oxid = rx_fchs->ox_id; - bfa_trc(rport->fcs, rport->reply_oxid); - - rport->pid = rx_fchs->s_id; - bfa_trc(rport->fcs, rport->pid); - - rport->stats.plogi_rcvd++; - bfa_sm_send_event(rport, RPSM_EVENT_PLOGI_RCVD); -} - - -/* - * Called by bport/vport to notify SCN for the remote port - */ -void -bfa_fcs_rport_scn(struct bfa_fcs_rport_s *rport) -{ - rport->stats.rscns++; - bfa_sm_send_event(rport, RPSM_EVENT_SCN); -} - - -/* - * brief - * This routine BFA callback for bfa_rport_online() call. - * - * param[in] cb_arg - rport struct. - * - * return - * void - * - * Special Considerations: - * - * note - */ -void -bfa_cb_rport_online(void *cbarg) -{ - - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_sm_send_event(rport, RPSM_EVENT_HCB_ONLINE); -} - -/* - * brief - * This routine BFA callback for bfa_rport_offline() call. - * - * param[in] rport - - * - * return - * void - * - * Special Considerations: - * - * note - */ -void -bfa_cb_rport_offline(void *cbarg) -{ - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_sm_send_event(rport, RPSM_EVENT_HCB_OFFLINE); -} - -/* - * brief - * This routine is a static BFA callback when there is a QoS flow_id - * change notification - * - * param[in] rport - - * - * return - * void - * - * Special Considerations: - * - * note - */ -void -bfa_cb_rport_qos_scn_flowid(void *cbarg, - struct bfa_rport_qos_attr_s old_qos_attr, - struct bfa_rport_qos_attr_s new_qos_attr) -{ - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; - struct bfa_rport_aen_data_s aen_data; - - bfa_trc(rport->fcs, rport->pwwn); - aen_data.priv.qos = new_qos_attr; - bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_FLOWID, &aen_data); -} - -/* - * brief - * This routine is a static BFA callback when there is a QoS priority - * change notification - * - * param[in] rport - - * - * return - * void - * - * Special Considerations: - * - * note - */ -void -bfa_cb_rport_qos_scn_prio(void *cbarg, - struct bfa_rport_qos_attr_s old_qos_attr, - struct bfa_rport_qos_attr_s new_qos_attr) -{ - struct bfa_fcs_rport_s *rport = (struct bfa_fcs_rport_s *) cbarg; - struct bfa_rport_aen_data_s aen_data; - - bfa_trc(rport->fcs, rport->pwwn); - aen_data.priv.qos = new_qos_attr; - bfa_fcs_rport_aen_post(rport, BFA_RPORT_AEN_QOS_PRIO, &aen_data); -} - -/* - * Called to process any unsolicted frames from this remote port - */ -void -bfa_fcs_rport_uf_recv(struct bfa_fcs_rport_s *rport, - struct fchs_s *fchs, u16 len) -{ - struct bfa_fcs_lport_s *port = rport->port; - struct fc_els_cmd_s *els_cmd; - - bfa_trc(rport->fcs, fchs->s_id); - bfa_trc(rport->fcs, fchs->d_id); - bfa_trc(rport->fcs, fchs->type); - - if (fchs->type != FC_TYPE_ELS) - return; - - els_cmd = (struct fc_els_cmd_s *) (fchs + 1); - - bfa_trc(rport->fcs, els_cmd->els_code); - - switch (els_cmd->els_code) { - case FC_ELS_LOGO: - bfa_stats(port, plogi_rcvd); - bfa_fcs_rport_process_logo(rport, fchs); - break; - - case FC_ELS_ADISC: - bfa_stats(port, adisc_rcvd); - bfa_fcs_rport_process_adisc(rport, fchs, len); - break; - - case FC_ELS_PRLO: - bfa_stats(port, prlo_rcvd); - if (bfa_fcs_lport_is_initiator(port)) - bfa_fcs_fcpim_uf_recv(rport->itnim, fchs, len); - break; - - case FC_ELS_PRLI: - bfa_stats(port, prli_rcvd); - bfa_fcs_rport_process_prli(rport, fchs, len); - break; - - case FC_ELS_RPSC: - bfa_stats(port, rpsc_rcvd); - bfa_fcs_rport_process_rpsc(rport, fchs, len); - break; - - default: - bfa_stats(port, un_handled_els_rcvd); - bfa_fcs_rport_send_ls_rjt(rport, fchs, - FC_LS_RJT_RSN_CMD_NOT_SUPP, - FC_LS_RJT_EXP_NO_ADDL_INFO); - break; - } -} - -/* send best case acc to prlo */ -static void -bfa_fcs_rport_send_prlo_acc(struct bfa_fcs_rport_s *rport) -{ - struct bfa_fcs_lport_s *port = rport->port; - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - int len; - - bfa_trc(rport->fcs, rport->pid); - - fcxp = bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) - return; - len = fc_prlo_acc_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rport->pid, bfa_fcs_lport_get_fcid(port), - rport->reply_oxid, 0); - - bfa_fcxp_send(fcxp, rport->bfa_rport, port->fabric->vf_id, - port->lp_tag, BFA_FALSE, FC_CLASS_3, len, &fchs, - NULL, NULL, FC_MAX_PDUSZ, 0); -} - -/* - * Send a LS reject - */ -static void -bfa_fcs_rport_send_ls_rjt(struct bfa_fcs_rport_s *rport, struct fchs_s *rx_fchs, - u8 reason_code, u8 reason_code_expl) -{ - struct bfa_fcs_lport_s *port = rport->port; - struct fchs_s fchs; - struct bfa_fcxp_s *fcxp; - int len; - - bfa_trc(rport->fcs, rx_fchs->s_id); - - fcxp = bfa_fcs_fcxp_alloc(rport->fcs); - if (!fcxp) - return; - - len = fc_ls_rjt_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), - rx_fchs->s_id, bfa_fcs_lport_get_fcid(port), - rx_fchs->ox_id, reason_code, reason_code_expl); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, - BFA_FALSE, FC_CLASS_3, len, &fchs, NULL, NULL, - FC_MAX_PDUSZ, 0); -} - -/* - * Return state of rport. - */ -int -bfa_fcs_rport_get_state(struct bfa_fcs_rport_s *rport) -{ - return bfa_sm_to_state(rport_sm_table, rport->sm); -} - - -/* - * brief - * Called by the Driver to set rport delete/ageout timeout - * - * param[in] rport timeout value in seconds. - * - * return None - */ -void -bfa_fcs_rport_set_del_timeout(u8 rport_tmo) -{ - /* convert to Millisecs */ - if (rport_tmo > 0) - bfa_fcs_rport_del_timeout = rport_tmo * 1000; -} -void -bfa_fcs_rport_prlo(struct bfa_fcs_rport_s *rport, __be16 ox_id) -{ - bfa_trc(rport->fcs, rport->pid); - - rport->prlo = BFA_TRUE; - rport->reply_oxid = ox_id; - bfa_sm_send_event(rport, RPSM_EVENT_PRLO_RCVD); -} - -void -bfa_fcs_rport_get_attr(struct bfa_fcs_rport_s *rport, - struct bfa_rport_attr_s *rport_attr) -{ - struct bfa_rport_qos_attr_s qos_attr; - struct bfa_fcs_lport_s *port = rport->port; - bfa_port_speed_t rport_speed = rport->rpf.rpsc_speed; - - memset(rport_attr, 0, sizeof(struct bfa_rport_attr_s)); - memset(&qos_attr, 0, sizeof(struct bfa_rport_qos_attr_s)); - - rport_attr->pid = rport->pid; - rport_attr->pwwn = rport->pwwn; - rport_attr->nwwn = rport->nwwn; - rport_attr->cos_supported = rport->fc_cos; - rport_attr->df_sz = rport->maxfrsize; - rport_attr->state = bfa_fcs_rport_get_state(rport); - rport_attr->fc_cos = rport->fc_cos; - rport_attr->cisc = rport->cisc; - rport_attr->scsi_function = rport->scsi_function; - rport_attr->curr_speed = rport->rpf.rpsc_speed; - rport_attr->assigned_speed = rport->rpf.assigned_speed; - - qos_attr.qos_priority = rport->bfa_rport->qos_attr.qos_priority; - qos_attr.qos_flow_id = - cpu_to_be32(rport->bfa_rport->qos_attr.qos_flow_id); - rport_attr->qos_attr = qos_attr; - - rport_attr->trl_enforced = BFA_FALSE; - if (bfa_fcport_is_ratelim(port->fcs->bfa) && - (rport->scsi_function == BFA_RPORT_TARGET)) { - if (rport_speed == BFA_PORT_SPEED_UNKNOWN) - rport_speed = - bfa_fcport_get_ratelim_speed(rport->fcs->bfa); - - if (rport_speed < bfa_fcs_lport_get_rport_max_speed(port)) - rport_attr->trl_enforced = BFA_TRUE; - } -} - -/* - * Remote port implementation. - */ - -/* - * fcs_rport_api FCS rport API. - */ - -struct bfa_fcs_rport_s * -bfa_fcs_rport_lookup(struct bfa_fcs_lport_s *port, wwn_t rpwwn) -{ - struct bfa_fcs_rport_s *rport; - - rport = bfa_fcs_lport_get_rport_by_pwwn(port, rpwwn); - if (rport == NULL) { - /* - * TBD Error handling - */ - } - - return rport; -} - -struct bfa_fcs_rport_s * -bfa_fcs_rport_lookup_by_nwwn(struct bfa_fcs_lport_s *port, wwn_t rnwwn) -{ - struct bfa_fcs_rport_s *rport; - - rport = bfa_fcs_lport_get_rport_by_nwwn(port, rnwwn); - if (rport == NULL) { - /* - * TBD Error handling - */ - } - - return rport; -} - -/* - * Remote port features (RPF) implementation. - */ - -#define BFA_FCS_RPF_RETRIES (3) -#define BFA_FCS_RPF_RETRY_TIMEOUT (1000) /* 1 sec (In millisecs) */ - -static void bfa_fcs_rpf_send_rpsc2(void *rport_cbarg, - struct bfa_fcxp_s *fcxp_alloced); -static void bfa_fcs_rpf_rpsc2_response(void *fcsarg, - struct bfa_fcxp_s *fcxp, - void *cbarg, - bfa_status_t req_status, - u32 rsp_len, - u32 resid_len, - struct fchs_s *rsp_fchs); - -static void bfa_fcs_rpf_timeout(void *arg); - -/* - * fcs_rport_ftrs_sm FCS rport state machine events - */ - -enum rpf_event { - RPFSM_EVENT_RPORT_OFFLINE = 1, /* Rport offline */ - RPFSM_EVENT_RPORT_ONLINE = 2, /* Rport online */ - RPFSM_EVENT_FCXP_SENT = 3, /* Frame from has been sent */ - RPFSM_EVENT_TIMEOUT = 4, /* Rport SM timeout event */ - RPFSM_EVENT_RPSC_COMP = 5, - RPFSM_EVENT_RPSC_FAIL = 6, - RPFSM_EVENT_RPSC_ERROR = 7, -}; - -static void bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); -static void bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, - enum rpf_event event); - -static void -bfa_fcs_rpf_sm_uninit(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - struct bfa_fcs_fabric_s *fabric = &rport->fcs->fabric; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_RPORT_ONLINE: - /* Send RPSC2 to a Brocade fabric only. */ - if ((!BFA_FCS_PID_IS_WKA(rport->pid)) && - ((rport->port->fabric->lps->brcd_switch) || - (bfa_fcs_fabric_get_switch_oui(fabric) == - BFA_FCS_BRCD_SWITCH_OUI))) { - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); - rpf->rpsc_retries = 0; - bfa_fcs_rpf_send_rpsc2(rpf, NULL); - } - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_rpsc_sending(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_FCXP_SENT: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc); - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); - bfa_fcxp_walloc_cancel(rport->fcs->bfa, &rpf->fcxp_wqe); - rpf->rpsc_retries = 0; - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_rpsc(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_RPSC_COMP: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); - /* Update speed info in f/w via BFA */ - if (rpf->rpsc_speed != BFA_PORT_SPEED_UNKNOWN) - bfa_rport_speed(rport->bfa_rport, rpf->rpsc_speed); - else if (rpf->assigned_speed != BFA_PORT_SPEED_UNKNOWN) - bfa_rport_speed(rport->bfa_rport, rpf->assigned_speed); - break; - - case RPFSM_EVENT_RPSC_FAIL: - /* RPSC not supported by rport */ - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); - break; - - case RPFSM_EVENT_RPSC_ERROR: - /* need to retry...delayed a bit. */ - if (rpf->rpsc_retries++ < BFA_FCS_RPF_RETRIES) { - bfa_timer_start(rport->fcs->bfa, &rpf->timer, - bfa_fcs_rpf_timeout, rpf, - BFA_FCS_RPF_RETRY_TIMEOUT); - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_retry); - } else { - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_online); - } - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); - bfa_fcxp_discard(rpf->fcxp); - rpf->rpsc_retries = 0; - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_rpsc_retry(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_TIMEOUT: - /* re-send the RPSC */ - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); - bfa_fcs_rpf_send_rpsc2(rpf, NULL); - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - bfa_timer_stop(&rpf->timer); - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); - rpf->rpsc_retries = 0; - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_online(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_RPORT_OFFLINE: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_offline); - rpf->rpsc_retries = 0; - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} - -static void -bfa_fcs_rpf_sm_offline(struct bfa_fcs_rpf_s *rpf, enum rpf_event event) -{ - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pwwn); - bfa_trc(rport->fcs, rport->pid); - bfa_trc(rport->fcs, event); - - switch (event) { - case RPFSM_EVENT_RPORT_ONLINE: - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_rpsc_sending); - bfa_fcs_rpf_send_rpsc2(rpf, NULL); - break; - - case RPFSM_EVENT_RPORT_OFFLINE: - break; - - default: - bfa_sm_fault(rport->fcs, event); - } -} -/* - * Called when Rport is created. - */ -void -bfa_fcs_rpf_init(struct bfa_fcs_rport_s *rport) -{ - struct bfa_fcs_rpf_s *rpf = &rport->rpf; - - bfa_trc(rport->fcs, rport->pid); - rpf->rport = rport; - - bfa_sm_set_state(rpf, bfa_fcs_rpf_sm_uninit); -} - -/* - * Called when Rport becomes online - */ -void -bfa_fcs_rpf_rport_online(struct bfa_fcs_rport_s *rport) -{ - bfa_trc(rport->fcs, rport->pid); - - if (__fcs_min_cfg(rport->port->fcs)) - return; - - if (bfa_fcs_fabric_is_switched(rport->port->fabric)) - bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_ONLINE); -} - -/* - * Called when Rport becomes offline - */ -void -bfa_fcs_rpf_rport_offline(struct bfa_fcs_rport_s *rport) -{ - bfa_trc(rport->fcs, rport->pid); - - if (__fcs_min_cfg(rport->port->fcs)) - return; - - rport->rpf.rpsc_speed = 0; - bfa_sm_send_event(&rport->rpf, RPFSM_EVENT_RPORT_OFFLINE); -} - -static void -bfa_fcs_rpf_timeout(void *arg) -{ - struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) arg; - struct bfa_fcs_rport_s *rport = rpf->rport; - - bfa_trc(rport->fcs, rport->pid); - bfa_sm_send_event(rpf, RPFSM_EVENT_TIMEOUT); -} - -static void -bfa_fcs_rpf_send_rpsc2(void *rpf_cbarg, struct bfa_fcxp_s *fcxp_alloced) -{ - struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *)rpf_cbarg; - struct bfa_fcs_rport_s *rport = rpf->rport; - struct bfa_fcs_lport_s *port = rport->port; - struct fchs_s fchs; - int len; - struct bfa_fcxp_s *fcxp; - - bfa_trc(rport->fcs, rport->pwwn); - - fcxp = fcxp_alloced ? fcxp_alloced : bfa_fcs_fcxp_alloc(port->fcs); - if (!fcxp) { - bfa_fcs_fcxp_alloc_wait(port->fcs->bfa, &rpf->fcxp_wqe, - bfa_fcs_rpf_send_rpsc2, rpf); - return; - } - rpf->fcxp = fcxp; - - len = fc_rpsc2_build(&fchs, bfa_fcxp_get_reqbuf(fcxp), rport->pid, - bfa_fcs_lport_get_fcid(port), &rport->pid, 1); - - bfa_fcxp_send(fcxp, NULL, port->fabric->vf_id, port->lp_tag, BFA_FALSE, - FC_CLASS_3, len, &fchs, bfa_fcs_rpf_rpsc2_response, - rpf, FC_MAX_PDUSZ, FC_ELS_TOV); - rport->stats.rpsc_sent++; - bfa_sm_send_event(rpf, RPFSM_EVENT_FCXP_SENT); - -} - -static void -bfa_fcs_rpf_rpsc2_response(void *fcsarg, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - struct bfa_fcs_rpf_s *rpf = (struct bfa_fcs_rpf_s *) cbarg; - struct bfa_fcs_rport_s *rport = rpf->rport; - struct fc_ls_rjt_s *ls_rjt; - struct fc_rpsc2_acc_s *rpsc2_acc; - u16 num_ents; - - bfa_trc(rport->fcs, req_status); - - if (req_status != BFA_STATUS_OK) { - bfa_trc(rport->fcs, req_status); - if (req_status == BFA_STATUS_ETIMER) - rport->stats.rpsc_failed++; - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); - return; - } - - rpsc2_acc = (struct fc_rpsc2_acc_s *) BFA_FCXP_RSP_PLD(fcxp); - if (rpsc2_acc->els_cmd == FC_ELS_ACC) { - rport->stats.rpsc_accs++; - num_ents = be16_to_cpu(rpsc2_acc->num_pids); - bfa_trc(rport->fcs, num_ents); - if (num_ents > 0) { - WARN_ON(rpsc2_acc->port_info[0].pid == rport->pid); - bfa_trc(rport->fcs, - be16_to_cpu(rpsc2_acc->port_info[0].pid)); - bfa_trc(rport->fcs, - be16_to_cpu(rpsc2_acc->port_info[0].speed)); - bfa_trc(rport->fcs, - be16_to_cpu(rpsc2_acc->port_info[0].index)); - bfa_trc(rport->fcs, - rpsc2_acc->port_info[0].type); - - if (rpsc2_acc->port_info[0].speed == 0) { - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); - return; - } - - rpf->rpsc_speed = fc_rpsc_operspeed_to_bfa_speed( - be16_to_cpu(rpsc2_acc->port_info[0].speed)); - - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_COMP); - } - } else { - ls_rjt = (struct fc_ls_rjt_s *) BFA_FCXP_RSP_PLD(fcxp); - bfa_trc(rport->fcs, ls_rjt->reason_code); - bfa_trc(rport->fcs, ls_rjt->reason_code_expl); - rport->stats.rpsc_rejects++; - if (ls_rjt->reason_code == FC_LS_RJT_RSN_CMD_NOT_SUPP) - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_FAIL); - else - bfa_sm_send_event(rpf, RPFSM_EVENT_RPSC_ERROR); - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_cb.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_cb.c deleted file mode 100644 index ea24d4c6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_cb.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfa_modules.h" -#include "bfi_reg.h" - -void -bfa_hwcb_reginit(struct bfa_s *bfa) -{ - struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; - void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - int fn = bfa_ioc_pcifn(&bfa->ioc); - - if (fn == 0) { - bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); - bfa_regs->intr_mask = (kva + HOSTFN0_INT_MSK); - } else { - bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS); - bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK); - } -} - -static void -bfa_hwcb_reqq_ack_msix(struct bfa_s *bfa, int reqq) -{ - writel(__HFN_INT_CPE_Q0 << CPE_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), reqq), - bfa->iocfc.bfa_regs.intr_status); -} - -/* - * Actions to respond RME Interrupt for Crossbow ASIC: - * - Write 1 to Interrupt Status register - * INTX - done in bfa_intx() - * MSIX - done in bfa_hwcb_rspq_ack_msix() - * - Update CI (only if new CI) - */ -static void -bfa_hwcb_rspq_ack_msix(struct bfa_s *bfa, int rspq, u32 ci) -{ - writel(__HFN_INT_RME_Q0 << RME_Q_NUM(bfa_ioc_pcifn(&bfa->ioc), rspq), - bfa->iocfc.bfa_regs.intr_status); - - if (bfa_rspq_ci(bfa, rspq) == ci) - return; - - bfa_rspq_ci(bfa, rspq) = ci; - writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]); - mmiowb(); -} - -void -bfa_hwcb_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci) -{ - if (bfa_rspq_ci(bfa, rspq) == ci) - return; - - bfa_rspq_ci(bfa, rspq) = ci; - writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]); - mmiowb(); -} - -void -bfa_hwcb_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, - u32 *num_vecs, u32 *max_vec_bit) -{ -#define __HFN_NUMINTS 13 - if (bfa_ioc_pcifn(&bfa->ioc) == 0) { - *msix_vecs_bmap = (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | - __HFN_INT_CPE_Q2 | __HFN_INT_CPE_Q3 | - __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | - __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | - __HFN_INT_MBOX_LPU0); - *max_vec_bit = __HFN_INT_MBOX_LPU0; - } else { - *msix_vecs_bmap = (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | - __HFN_INT_CPE_Q6 | __HFN_INT_CPE_Q7 | - __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | - __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | - __HFN_INT_MBOX_LPU1); - *max_vec_bit = __HFN_INT_MBOX_LPU1; - } - - *msix_vecs_bmap |= (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | - __HFN_INT_ERR_LPU1 | __HFN_INT_ERR_PSS); - *num_vecs = __HFN_NUMINTS; -} - -/* - * Dummy interrupt handler for handling spurious interrupts. - */ -static void -bfa_hwcb_msix_dummy(struct bfa_s *bfa, int vec) -{ -} - -/* - * No special setup required for crossbow -- vector assignments are implicit. - */ -void -bfa_hwcb_msix_init(struct bfa_s *bfa, int nvecs) -{ - WARN_ON((nvecs != 1) && (nvecs != __HFN_NUMINTS)); - - bfa->msix.nvecs = nvecs; - bfa_hwcb_msix_uninstall(bfa); -} - -void -bfa_hwcb_msix_ctrl_install(struct bfa_s *bfa) -{ - int i; - - if (bfa->msix.nvecs == 0) - return; - - if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CB; i < BFI_MSIX_CB_MAX; i++) - bfa->msix.handler[i] = bfa_msix_all; - return; - } - - for (i = BFI_MSIX_RME_QMAX_CB+1; i < BFI_MSIX_CB_MAX; i++) - bfa->msix.handler[i] = bfa_msix_lpu_err; -} - -void -bfa_hwcb_msix_queue_install(struct bfa_s *bfa) -{ - int i; - - if (bfa->msix.nvecs == 0) - return; - - if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CB; i <= BFI_MSIX_RME_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_all; - return; - } - - for (i = BFI_MSIX_CPE_QMIN_CB; i <= BFI_MSIX_CPE_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_reqq; - - for (i = BFI_MSIX_RME_QMIN_CB; i <= BFI_MSIX_RME_QMAX_CB; i++) - bfa->msix.handler[i] = bfa_msix_rspq; -} - -void -bfa_hwcb_msix_uninstall(struct bfa_s *bfa) -{ - int i; - - for (i = 0; i < BFI_MSIX_CB_MAX; i++) - bfa->msix.handler[i] = bfa_hwcb_msix_dummy; -} - -/* - * No special enable/disable -- vector assignments are implicit. - */ -void -bfa_hwcb_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) -{ - if (msix) { - bfa->iocfc.hwif.hw_reqq_ack = bfa_hwcb_reqq_ack_msix; - bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack_msix; - } else { - bfa->iocfc.hwif.hw_reqq_ack = NULL; - bfa->iocfc.hwif.hw_rspq_ack = bfa_hwcb_rspq_ack; - } -} - -void -bfa_hwcb_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end) -{ - *start = BFI_MSIX_RME_QMIN_CB; - *end = BFI_MSIX_RME_QMAX_CB; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_ct.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_ct.c deleted file mode 100644 index 637527f4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_hw_ct.c +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfa_modules.h" -#include "bfi_reg.h" - -BFA_TRC_FILE(HAL, IOCFC_CT); - -/* - * Dummy interrupt handler for handling spurious interrupt during chip-reinit. - */ -static void -bfa_hwct_msix_dummy(struct bfa_s *bfa, int vec) -{ -} - -void -bfa_hwct_reginit(struct bfa_s *bfa) -{ - struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; - void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - int fn = bfa_ioc_pcifn(&bfa->ioc); - - if (fn == 0) { - bfa_regs->intr_status = (kva + HOSTFN0_INT_STATUS); - bfa_regs->intr_mask = (kva + HOSTFN0_INT_MSK); - } else { - bfa_regs->intr_status = (kva + HOSTFN1_INT_STATUS); - bfa_regs->intr_mask = (kva + HOSTFN1_INT_MSK); - } -} - -void -bfa_hwct2_reginit(struct bfa_s *bfa) -{ - struct bfa_iocfc_regs_s *bfa_regs = &bfa->iocfc.bfa_regs; - void __iomem *kva = bfa_ioc_bar0(&bfa->ioc); - - bfa_regs->intr_status = (kva + CT2_HOSTFN_INT_STATUS); - bfa_regs->intr_mask = (kva + CT2_HOSTFN_INTR_MASK); -} - -void -bfa_hwct_reqq_ack(struct bfa_s *bfa, int reqq) -{ - u32 r32; - - r32 = readl(bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]); - writel(r32, bfa->iocfc.bfa_regs.cpe_q_ctrl[reqq]); -} - -/* - * Actions to respond RME Interrupt for Catapult ASIC: - * - Write 1 to Interrupt Status register (INTx only - done in bfa_intx()) - * - Acknowledge by writing to RME Queue Control register - * - Update CI - */ -void -bfa_hwct_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci) -{ - u32 r32; - - r32 = readl(bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]); - writel(r32, bfa->iocfc.bfa_regs.rme_q_ctrl[rspq]); - - bfa_rspq_ci(bfa, rspq) = ci; - writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]); - mmiowb(); -} - -/* - * Actions to respond RME Interrupt for Catapult2 ASIC: - * - Write 1 to Interrupt Status register (INTx only - done in bfa_intx()) - * - Update CI - */ -void -bfa_hwct2_rspq_ack(struct bfa_s *bfa, int rspq, u32 ci) -{ - bfa_rspq_ci(bfa, rspq) = ci; - writel(ci, bfa->iocfc.bfa_regs.rme_q_ci[rspq]); - mmiowb(); -} - -void -bfa_hwct_msix_getvecs(struct bfa_s *bfa, u32 *msix_vecs_bmap, - u32 *num_vecs, u32 *max_vec_bit) -{ - *msix_vecs_bmap = (1 << BFI_MSIX_CT_MAX) - 1; - *max_vec_bit = (1 << (BFI_MSIX_CT_MAX - 1)); - *num_vecs = BFI_MSIX_CT_MAX; -} - -/* - * Setup MSI-X vector for catapult - */ -void -bfa_hwct_msix_init(struct bfa_s *bfa, int nvecs) -{ - WARN_ON((nvecs != 1) && (nvecs != BFI_MSIX_CT_MAX)); - bfa_trc(bfa, nvecs); - - bfa->msix.nvecs = nvecs; - bfa_hwct_msix_uninstall(bfa); -} - -void -bfa_hwct_msix_ctrl_install(struct bfa_s *bfa) -{ - if (bfa->msix.nvecs == 0) - return; - - if (bfa->msix.nvecs == 1) - bfa->msix.handler[BFI_MSIX_LPU_ERR_CT] = bfa_msix_all; - else - bfa->msix.handler[BFI_MSIX_LPU_ERR_CT] = bfa_msix_lpu_err; -} - -void -bfa_hwct_msix_queue_install(struct bfa_s *bfa) -{ - int i; - - if (bfa->msix.nvecs == 0) - return; - - if (bfa->msix.nvecs == 1) { - for (i = BFI_MSIX_CPE_QMIN_CT; i < BFI_MSIX_CT_MAX; i++) - bfa->msix.handler[i] = bfa_msix_all; - return; - } - - for (i = BFI_MSIX_CPE_QMIN_CT; i <= BFI_MSIX_CPE_QMAX_CT; i++) - bfa->msix.handler[i] = bfa_msix_reqq; - - for (i = BFI_MSIX_RME_QMIN_CT; i <= BFI_MSIX_RME_QMAX_CT; i++) - bfa->msix.handler[i] = bfa_msix_rspq; -} - -void -bfa_hwct_msix_uninstall(struct bfa_s *bfa) -{ - int i; - - for (i = 0; i < BFI_MSIX_CT_MAX; i++) - bfa->msix.handler[i] = bfa_hwct_msix_dummy; -} - -/* - * Enable MSI-X vectors - */ -void -bfa_hwct_isr_mode_set(struct bfa_s *bfa, bfa_boolean_t msix) -{ - bfa_trc(bfa, 0); - bfa_ioc_isr_mode_set(&bfa->ioc, msix); -} - -void -bfa_hwct_msix_get_rme_range(struct bfa_s *bfa, u32 *start, u32 *end) -{ - *start = BFI_MSIX_RME_QMIN_CT; - *end = BFI_MSIX_RME_QMAX_CT; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.c deleted file mode 100644 index 14e6284e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.c +++ /dev/null @@ -1,5937 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfa_ioc.h" -#include "bfi_reg.h" -#include "bfa_defs.h" -#include "bfa_defs_svc.h" - -BFA_TRC_FILE(CNA, IOC); - -/* - * IOC local definitions - */ -#define BFA_IOC_TOV 3000 /* msecs */ -#define BFA_IOC_HWSEM_TOV 500 /* msecs */ -#define BFA_IOC_HB_TOV 500 /* msecs */ -#define BFA_IOC_TOV_RECOVER BFA_IOC_HB_TOV -#define BFA_IOC_POLL_TOV BFA_TIMER_FREQ - -#define bfa_ioc_timer_start(__ioc) \ - bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ - bfa_ioc_timeout, (__ioc), BFA_IOC_TOV) -#define bfa_ioc_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer) - -#define bfa_hb_timer_start(__ioc) \ - bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->hb_timer, \ - bfa_ioc_hb_check, (__ioc), BFA_IOC_HB_TOV) -#define bfa_hb_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->hb_timer) - -#define BFA_DBG_FWTRC_OFF(_fn) (BFI_IOC_TRC_OFF + BFA_DBG_FWTRC_LEN * (_fn)) - -/* - * Asic specific macros : see bfa_hw_cb.c and bfa_hw_ct.c for details. - */ - -#define bfa_ioc_firmware_lock(__ioc) \ - ((__ioc)->ioc_hwif->ioc_firmware_lock(__ioc)) -#define bfa_ioc_firmware_unlock(__ioc) \ - ((__ioc)->ioc_hwif->ioc_firmware_unlock(__ioc)) -#define bfa_ioc_reg_init(__ioc) ((__ioc)->ioc_hwif->ioc_reg_init(__ioc)) -#define bfa_ioc_map_port(__ioc) ((__ioc)->ioc_hwif->ioc_map_port(__ioc)) -#define bfa_ioc_notify_fail(__ioc) \ - ((__ioc)->ioc_hwif->ioc_notify_fail(__ioc)) -#define bfa_ioc_sync_start(__ioc) \ - ((__ioc)->ioc_hwif->ioc_sync_start(__ioc)) -#define bfa_ioc_sync_join(__ioc) \ - ((__ioc)->ioc_hwif->ioc_sync_join(__ioc)) -#define bfa_ioc_sync_leave(__ioc) \ - ((__ioc)->ioc_hwif->ioc_sync_leave(__ioc)) -#define bfa_ioc_sync_ack(__ioc) \ - ((__ioc)->ioc_hwif->ioc_sync_ack(__ioc)) -#define bfa_ioc_sync_complete(__ioc) \ - ((__ioc)->ioc_hwif->ioc_sync_complete(__ioc)) - -#define bfa_ioc_mbox_cmd_pending(__ioc) \ - (!list_empty(&((__ioc)->mbox_mod.cmd_q)) || \ - readl((__ioc)->ioc_regs.hfn_mbox_cmd)) - -bfa_boolean_t bfa_auto_recover = BFA_TRUE; - -/* - * forward declarations - */ -static void bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc); -static void bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force); -static void bfa_ioc_timeout(void *ioc); -static void bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc); -static void bfa_ioc_send_enable(struct bfa_ioc_s *ioc); -static void bfa_ioc_send_disable(struct bfa_ioc_s *ioc); -static void bfa_ioc_send_getattr(struct bfa_ioc_s *ioc); -static void bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc); -static void bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc); -static void bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc); -static void bfa_ioc_recover(struct bfa_ioc_s *ioc); -static void bfa_ioc_event_notify(struct bfa_ioc_s *ioc , - enum bfa_ioc_event_e event); -static void bfa_ioc_disable_comp(struct bfa_ioc_s *ioc); -static void bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc); -static void bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc); -static void bfa_ioc_fail_notify(struct bfa_ioc_s *ioc); -static void bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc); - -/* - * IOC state machine definitions/declarations - */ -enum ioc_event { - IOC_E_RESET = 1, /* IOC reset request */ - IOC_E_ENABLE = 2, /* IOC enable request */ - IOC_E_DISABLE = 3, /* IOC disable request */ - IOC_E_DETACH = 4, /* driver detach cleanup */ - IOC_E_ENABLED = 5, /* f/w enabled */ - IOC_E_FWRSP_GETATTR = 6, /* IOC get attribute response */ - IOC_E_DISABLED = 7, /* f/w disabled */ - IOC_E_PFFAILED = 8, /* failure notice by iocpf sm */ - IOC_E_HBFAIL = 9, /* heartbeat failure */ - IOC_E_HWERROR = 10, /* hardware error interrupt */ - IOC_E_TIMEOUT = 11, /* timeout */ - IOC_E_HWFAILED = 12, /* PCI mapping failure notice */ -}; - -bfa_fsm_state_decl(bfa_ioc, uninit, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, reset, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, enabling, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, getattr, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, op, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, fail_retry, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, fail, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, disabling, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, disabled, struct bfa_ioc_s, enum ioc_event); -bfa_fsm_state_decl(bfa_ioc, hwfail, struct bfa_ioc_s, enum ioc_event); - -static struct bfa_sm_table_s ioc_sm_table[] = { - {BFA_SM(bfa_ioc_sm_uninit), BFA_IOC_UNINIT}, - {BFA_SM(bfa_ioc_sm_reset), BFA_IOC_RESET}, - {BFA_SM(bfa_ioc_sm_enabling), BFA_IOC_ENABLING}, - {BFA_SM(bfa_ioc_sm_getattr), BFA_IOC_GETATTR}, - {BFA_SM(bfa_ioc_sm_op), BFA_IOC_OPERATIONAL}, - {BFA_SM(bfa_ioc_sm_fail_retry), BFA_IOC_INITFAIL}, - {BFA_SM(bfa_ioc_sm_fail), BFA_IOC_FAIL}, - {BFA_SM(bfa_ioc_sm_disabling), BFA_IOC_DISABLING}, - {BFA_SM(bfa_ioc_sm_disabled), BFA_IOC_DISABLED}, - {BFA_SM(bfa_ioc_sm_hwfail), BFA_IOC_HWFAIL}, -}; - -/* - * IOCPF state machine definitions/declarations - */ - -#define bfa_iocpf_timer_start(__ioc) \ - bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ - bfa_iocpf_timeout, (__ioc), BFA_IOC_TOV) -#define bfa_iocpf_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->ioc_timer) - -#define bfa_iocpf_poll_timer_start(__ioc) \ - bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->ioc_timer, \ - bfa_iocpf_poll_timeout, (__ioc), BFA_IOC_POLL_TOV) - -#define bfa_sem_timer_start(__ioc) \ - bfa_timer_begin((__ioc)->timer_mod, &(__ioc)->sem_timer, \ - bfa_iocpf_sem_timeout, (__ioc), BFA_IOC_HWSEM_TOV) -#define bfa_sem_timer_stop(__ioc) bfa_timer_stop(&(__ioc)->sem_timer) - -/* - * Forward declareations for iocpf state machine - */ -static void bfa_iocpf_timeout(void *ioc_arg); -static void bfa_iocpf_sem_timeout(void *ioc_arg); -static void bfa_iocpf_poll_timeout(void *ioc_arg); - -/* - * IOCPF state machine events - */ -enum iocpf_event { - IOCPF_E_ENABLE = 1, /* IOCPF enable request */ - IOCPF_E_DISABLE = 2, /* IOCPF disable request */ - IOCPF_E_STOP = 3, /* stop on driver detach */ - IOCPF_E_FWREADY = 4, /* f/w initialization done */ - IOCPF_E_FWRSP_ENABLE = 5, /* enable f/w response */ - IOCPF_E_FWRSP_DISABLE = 6, /* disable f/w response */ - IOCPF_E_FAIL = 7, /* failure notice by ioc sm */ - IOCPF_E_INITFAIL = 8, /* init fail notice by ioc sm */ - IOCPF_E_GETATTRFAIL = 9, /* init fail notice by ioc sm */ - IOCPF_E_SEMLOCKED = 10, /* h/w semaphore is locked */ - IOCPF_E_TIMEOUT = 11, /* f/w response timeout */ - IOCPF_E_SEM_ERROR = 12, /* h/w sem mapping error */ -}; - -/* - * IOCPF states - */ -enum bfa_iocpf_state { - BFA_IOCPF_RESET = 1, /* IOC is in reset state */ - BFA_IOCPF_SEMWAIT = 2, /* Waiting for IOC h/w semaphore */ - BFA_IOCPF_HWINIT = 3, /* IOC h/w is being initialized */ - BFA_IOCPF_READY = 4, /* IOCPF is initialized */ - BFA_IOCPF_INITFAIL = 5, /* IOCPF failed */ - BFA_IOCPF_FAIL = 6, /* IOCPF failed */ - BFA_IOCPF_DISABLING = 7, /* IOCPF is being disabled */ - BFA_IOCPF_DISABLED = 8, /* IOCPF is disabled */ - BFA_IOCPF_FWMISMATCH = 9, /* IOC f/w different from drivers */ -}; - -bfa_fsm_state_decl(bfa_iocpf, reset, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, fwcheck, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, mismatch, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, semwait, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, hwinit, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, enabling, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, ready, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, initfail_sync, struct bfa_iocpf_s, - enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, initfail, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, fail_sync, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, fail, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, disabling, struct bfa_iocpf_s, enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, disabling_sync, struct bfa_iocpf_s, - enum iocpf_event); -bfa_fsm_state_decl(bfa_iocpf, disabled, struct bfa_iocpf_s, enum iocpf_event); - -static struct bfa_sm_table_s iocpf_sm_table[] = { - {BFA_SM(bfa_iocpf_sm_reset), BFA_IOCPF_RESET}, - {BFA_SM(bfa_iocpf_sm_fwcheck), BFA_IOCPF_FWMISMATCH}, - {BFA_SM(bfa_iocpf_sm_mismatch), BFA_IOCPF_FWMISMATCH}, - {BFA_SM(bfa_iocpf_sm_semwait), BFA_IOCPF_SEMWAIT}, - {BFA_SM(bfa_iocpf_sm_hwinit), BFA_IOCPF_HWINIT}, - {BFA_SM(bfa_iocpf_sm_enabling), BFA_IOCPF_HWINIT}, - {BFA_SM(bfa_iocpf_sm_ready), BFA_IOCPF_READY}, - {BFA_SM(bfa_iocpf_sm_initfail_sync), BFA_IOCPF_INITFAIL}, - {BFA_SM(bfa_iocpf_sm_initfail), BFA_IOCPF_INITFAIL}, - {BFA_SM(bfa_iocpf_sm_fail_sync), BFA_IOCPF_FAIL}, - {BFA_SM(bfa_iocpf_sm_fail), BFA_IOCPF_FAIL}, - {BFA_SM(bfa_iocpf_sm_disabling), BFA_IOCPF_DISABLING}, - {BFA_SM(bfa_iocpf_sm_disabling_sync), BFA_IOCPF_DISABLING}, - {BFA_SM(bfa_iocpf_sm_disabled), BFA_IOCPF_DISABLED}, -}; - -/* - * IOC State Machine - */ - -/* - * Beginning state. IOC uninit state. - */ - -static void -bfa_ioc_sm_uninit_entry(struct bfa_ioc_s *ioc) -{ -} - -/* - * IOC is in uninit state. - */ -static void -bfa_ioc_sm_uninit(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_RESET: - bfa_fsm_set_state(ioc, bfa_ioc_sm_reset); - break; - - default: - bfa_sm_fault(ioc, event); - } -} -/* - * Reset entry actions -- initialize state machine - */ -static void -bfa_ioc_sm_reset_entry(struct bfa_ioc_s *ioc) -{ - bfa_fsm_set_state(&ioc->iocpf, bfa_iocpf_sm_reset); -} - -/* - * IOC is in reset state. - */ -static void -bfa_ioc_sm_reset(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_ENABLE: - bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling); - break; - - case IOC_E_DISABLE: - bfa_ioc_disable_comp(ioc); - break; - - case IOC_E_DETACH: - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - - -static void -bfa_ioc_sm_enabling_entry(struct bfa_ioc_s *ioc) -{ - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_ENABLE); -} - -/* - * Host IOC function is being enabled, awaiting response from firmware. - * Semaphore is acquired. - */ -static void -bfa_ioc_sm_enabling(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_ENABLED: - bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr); - break; - - case IOC_E_PFFAILED: - /* !!! fall through !!! */ - case IOC_E_HWERROR: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); - if (event != IOC_E_PFFAILED) - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL); - break; - - case IOC_E_HWFAILED: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); - break; - - case IOC_E_DISABLE: - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); - break; - - case IOC_E_DETACH: - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP); - break; - - case IOC_E_ENABLE: - break; - - default: - bfa_sm_fault(ioc, event); - } -} - - -static void -bfa_ioc_sm_getattr_entry(struct bfa_ioc_s *ioc) -{ - bfa_ioc_timer_start(ioc); - bfa_ioc_send_getattr(ioc); -} - -/* - * IOC configuration in progress. Timer is active. - */ -static void -bfa_ioc_sm_getattr(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_FWRSP_GETATTR: - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_op); - break; - - case IOC_E_PFFAILED: - case IOC_E_HWERROR: - bfa_ioc_timer_stop(ioc); - /* !!! fall through !!! */ - case IOC_E_TIMEOUT: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); - if (event != IOC_E_PFFAILED) - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_GETATTRFAIL); - break; - - case IOC_E_DISABLE: - bfa_ioc_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); - break; - - case IOC_E_ENABLE: - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_ioc_sm_op_entry(struct bfa_ioc_s *ioc) -{ - struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; - - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_OK); - bfa_ioc_event_notify(ioc, BFA_IOC_E_ENABLED); - bfa_ioc_hb_monitor(ioc); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC enabled\n"); - bfa_ioc_aen_post(ioc, BFA_IOC_AEN_ENABLE); -} - -static void -bfa_ioc_sm_op(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_ENABLE: - break; - - case IOC_E_DISABLE: - bfa_hb_timer_stop(ioc); - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); - break; - - case IOC_E_PFFAILED: - case IOC_E_HWERROR: - bfa_hb_timer_stop(ioc); - /* !!! fall through !!! */ - case IOC_E_HBFAIL: - if (ioc->iocpf.auto_recover) - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail_retry); - else - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); - - bfa_ioc_fail_notify(ioc); - - if (event != IOC_E_PFFAILED) - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - - -static void -bfa_ioc_sm_disabling_entry(struct bfa_ioc_s *ioc) -{ - struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_DISABLE); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, "IOC disabled\n"); - bfa_ioc_aen_post(ioc, BFA_IOC_AEN_DISABLE); -} - -/* - * IOC is being disabled - */ -static void -bfa_ioc_sm_disabling(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_DISABLED: - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabled); - break; - - case IOC_E_HWERROR: - /* - * No state change. Will move to disabled state - * after iocpf sm completes failure processing and - * moves to disabled state. - */ - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FAIL); - break; - - case IOC_E_HWFAILED: - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); - bfa_ioc_disable_comp(ioc); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -/* - * IOC disable completion entry. - */ -static void -bfa_ioc_sm_disabled_entry(struct bfa_ioc_s *ioc) -{ - bfa_ioc_disable_comp(ioc); -} - -static void -bfa_ioc_sm_disabled(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_ENABLE: - bfa_fsm_set_state(ioc, bfa_ioc_sm_enabling); - break; - - case IOC_E_DISABLE: - ioc->cbfn->disable_cbfn(ioc->bfa); - break; - - case IOC_E_DETACH: - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - - -static void -bfa_ioc_sm_fail_retry_entry(struct bfa_ioc_s *ioc) -{ - bfa_trc(ioc, 0); -} - -/* - * Hardware initialization retry. - */ -static void -bfa_ioc_sm_fail_retry(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_ENABLED: - bfa_fsm_set_state(ioc, bfa_ioc_sm_getattr); - break; - - case IOC_E_PFFAILED: - case IOC_E_HWERROR: - /* - * Initialization retry failed. - */ - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_fail); - if (event != IOC_E_PFFAILED) - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_INITFAIL); - break; - - case IOC_E_HWFAILED: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - bfa_fsm_set_state(ioc, bfa_ioc_sm_hwfail); - break; - - case IOC_E_ENABLE: - break; - - case IOC_E_DISABLE: - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); - break; - - case IOC_E_DETACH: - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - - -static void -bfa_ioc_sm_fail_entry(struct bfa_ioc_s *ioc) -{ - bfa_trc(ioc, 0); -} - -/* - * IOC failure. - */ -static void -bfa_ioc_sm_fail(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - - case IOC_E_ENABLE: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - break; - - case IOC_E_DISABLE: - bfa_fsm_set_state(ioc, bfa_ioc_sm_disabling); - break; - - case IOC_E_DETACH: - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_STOP); - break; - - case IOC_E_HWERROR: - /* - * HB failure notification, ignore. - */ - break; - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_ioc_sm_hwfail_entry(struct bfa_ioc_s *ioc) -{ - bfa_trc(ioc, 0); -} - -static void -bfa_ioc_sm_hwfail(struct bfa_ioc_s *ioc, enum ioc_event event) -{ - bfa_trc(ioc, event); - - switch (event) { - case IOC_E_ENABLE: - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - break; - - case IOC_E_DISABLE: - ioc->cbfn->disable_cbfn(ioc->bfa); - break; - - case IOC_E_DETACH: - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -/* - * IOCPF State Machine - */ - -/* - * Reset entry actions -- initialize state machine - */ -static void -bfa_iocpf_sm_reset_entry(struct bfa_iocpf_s *iocpf) -{ - iocpf->fw_mismatch_notified = BFA_FALSE; - iocpf->auto_recover = bfa_auto_recover; -} - -/* - * Beginning state. IOC is in reset state. - */ -static void -bfa_iocpf_sm_reset(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_ENABLE: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck); - break; - - case IOCPF_E_STOP: - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -/* - * Semaphore should be acquired for version check. - */ -static void -bfa_iocpf_sm_fwcheck_entry(struct bfa_iocpf_s *iocpf) -{ - struct bfi_ioc_image_hdr_s fwhdr; - u32 r32, fwstate, pgnum, pgoff, loff = 0; - int i; - - /* - * Spin on init semaphore to serialize. - */ - r32 = readl(iocpf->ioc->ioc_regs.ioc_init_sem_reg); - while (r32 & 0x1) { - udelay(20); - r32 = readl(iocpf->ioc->ioc_regs.ioc_init_sem_reg); - } - - /* h/w sem init */ - fwstate = readl(iocpf->ioc->ioc_regs.ioc_fwstate); - if (fwstate == BFI_IOC_UNINIT) { - writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg); - goto sem_get; - } - - bfa_ioc_fwver_get(iocpf->ioc, &fwhdr); - - if (swab32(fwhdr.exec) == BFI_FWBOOT_TYPE_NORMAL) { - writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg); - goto sem_get; - } - - /* - * Clear fwver hdr - */ - pgnum = PSS_SMEM_PGNUM(iocpf->ioc->ioc_regs.smem_pg0, loff); - pgoff = PSS_SMEM_PGOFF(loff); - writel(pgnum, iocpf->ioc->ioc_regs.host_page_num_fn); - - for (i = 0; i < sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32); i++) { - bfa_mem_write(iocpf->ioc->ioc_regs.smem_page_start, loff, 0); - loff += sizeof(u32); - } - - bfa_trc(iocpf->ioc, fwstate); - bfa_trc(iocpf->ioc, swab32(fwhdr.exec)); - writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_UNINIT, iocpf->ioc->ioc_regs.alt_ioc_fwstate); - - /* - * Unlock the hw semaphore. Should be here only once per boot. - */ - readl(iocpf->ioc->ioc_regs.ioc_sem_reg); - writel(1, iocpf->ioc->ioc_regs.ioc_sem_reg); - - /* - * unlock init semaphore. - */ - writel(1, iocpf->ioc->ioc_regs.ioc_init_sem_reg); - -sem_get: - bfa_ioc_hw_sem_get(iocpf->ioc); -} - -/* - * Awaiting h/w semaphore to continue with version check. - */ -static void -bfa_iocpf_sm_fwcheck(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_SEMLOCKED: - if (bfa_ioc_firmware_lock(ioc)) { - if (bfa_ioc_sync_start(ioc)) { - bfa_ioc_sync_join(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); - } else { - bfa_ioc_firmware_unlock(ioc); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_sem_timer_start(ioc); - } - } else { - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_mismatch); - } - break; - - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - - case IOCPF_E_DISABLE: - bfa_sem_timer_stop(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); - bfa_fsm_send_event(ioc, IOC_E_DISABLED); - break; - - case IOCPF_E_STOP: - bfa_sem_timer_stop(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -/* - * Notify enable completion callback. - */ -static void -bfa_iocpf_sm_mismatch_entry(struct bfa_iocpf_s *iocpf) -{ - /* - * Call only the first time sm enters fwmismatch state. - */ - if (iocpf->fw_mismatch_notified == BFA_FALSE) - bfa_ioc_pf_fwmismatch(iocpf->ioc); - - iocpf->fw_mismatch_notified = BFA_TRUE; - bfa_iocpf_timer_start(iocpf->ioc); -} - -/* - * Awaiting firmware version match. - */ -static void -bfa_iocpf_sm_mismatch(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_TIMEOUT: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fwcheck); - break; - - case IOCPF_E_DISABLE: - bfa_iocpf_timer_stop(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); - bfa_fsm_send_event(ioc, IOC_E_DISABLED); - break; - - case IOCPF_E_STOP: - bfa_iocpf_timer_stop(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -/* - * Request for semaphore. - */ -static void -bfa_iocpf_sm_semwait_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_ioc_hw_sem_get(iocpf->ioc); -} - -/* - * Awaiting semaphore for h/w initialzation. - */ -static void -bfa_iocpf_sm_semwait(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_SEMLOCKED: - if (bfa_ioc_sync_complete(ioc)) { - bfa_ioc_sync_join(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); - } else { - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_sem_timer_start(ioc); - } - break; - - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - - case IOCPF_E_DISABLE: - bfa_sem_timer_stop(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_hwinit_entry(struct bfa_iocpf_s *iocpf) -{ - iocpf->poll_time = 0; - bfa_ioc_hwinit(iocpf->ioc, BFA_FALSE); -} - -/* - * Hardware is being initialized. Interrupts are enabled. - * Holding hardware semaphore lock. - */ -static void -bfa_iocpf_sm_hwinit(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_FWREADY: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_enabling); - break; - - case IOCPF_E_TIMEOUT: - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_send_event(ioc, IOC_E_PFFAILED); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync); - break; - - case IOCPF_E_DISABLE: - bfa_iocpf_timer_stop(ioc); - bfa_ioc_sync_leave(ioc); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_enabling_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_iocpf_timer_start(iocpf->ioc); - /* - * Enable Interrupts before sending fw IOC ENABLE cmd. - */ - iocpf->ioc->cbfn->reset_cbfn(iocpf->ioc->bfa); - bfa_ioc_send_enable(iocpf->ioc); -} - -/* - * Host IOC function is being enabled, awaiting response from firmware. - * Semaphore is acquired. - */ -static void -bfa_iocpf_sm_enabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_FWRSP_ENABLE: - bfa_iocpf_timer_stop(ioc); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_ready); - break; - - case IOCPF_E_INITFAIL: - bfa_iocpf_timer_stop(ioc); - /* - * !!! fall through !!! - */ - - case IOCPF_E_TIMEOUT: - writel(1, ioc->ioc_regs.ioc_sem_reg); - if (event == IOCPF_E_TIMEOUT) - bfa_fsm_send_event(ioc, IOC_E_PFFAILED); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync); - break; - - case IOCPF_E_DISABLE: - bfa_iocpf_timer_stop(ioc); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_ready_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_fsm_send_event(iocpf->ioc, IOC_E_ENABLED); -} - -static void -bfa_iocpf_sm_ready(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_DISABLE: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling); - break; - - case IOCPF_E_GETATTRFAIL: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail_sync); - break; - - case IOCPF_E_FAIL: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail_sync); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_disabling_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_iocpf_timer_start(iocpf->ioc); - bfa_ioc_send_disable(iocpf->ioc); -} - -/* - * IOC is being disabled - */ -static void -bfa_iocpf_sm_disabling(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_FWRSP_DISABLE: - bfa_iocpf_timer_stop(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); - break; - - case IOCPF_E_FAIL: - bfa_iocpf_timer_stop(ioc); - /* - * !!! fall through !!! - */ - - case IOCPF_E_TIMEOUT: - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); - break; - - case IOCPF_E_FWRSP_ENABLE: - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_disabling_sync_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_ioc_hw_sem_get(iocpf->ioc); -} - -/* - * IOC hb ack request is being removed. - */ -static void -bfa_iocpf_sm_disabling_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_SEMLOCKED: - bfa_ioc_sync_leave(ioc); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); - break; - - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - - case IOCPF_E_FAIL: - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -/* - * IOC disable completion entry. - */ -static void -bfa_iocpf_sm_disabled_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_ioc_mbox_flush(iocpf->ioc); - bfa_fsm_send_event(iocpf->ioc, IOC_E_DISABLED); -} - -static void -bfa_iocpf_sm_disabled(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_ENABLE: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); - break; - - case IOCPF_E_STOP: - bfa_ioc_firmware_unlock(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_initfail_sync_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_ioc_debug_save_ftrc(iocpf->ioc); - bfa_ioc_hw_sem_get(iocpf->ioc); -} - -/* - * Hardware initialization failed. - */ -static void -bfa_iocpf_sm_initfail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_SEMLOCKED: - bfa_ioc_notify_fail(ioc); - bfa_ioc_sync_leave(ioc); - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_initfail); - break; - - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - - case IOCPF_E_DISABLE: - bfa_sem_timer_stop(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); - break; - - case IOCPF_E_STOP: - bfa_sem_timer_stop(ioc); - bfa_ioc_firmware_unlock(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); - break; - - case IOCPF_E_FAIL: - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_initfail_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_trc(iocpf->ioc, 0); -} - -/* - * Hardware initialization failed. - */ -static void -bfa_iocpf_sm_initfail(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_DISABLE: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); - break; - - case IOCPF_E_STOP: - bfa_ioc_firmware_unlock(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_reset); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_fail_sync_entry(struct bfa_iocpf_s *iocpf) -{ - /* - * Mark IOC as failed in hardware and stop firmware. - */ - bfa_ioc_lpu_stop(iocpf->ioc); - - /* - * Flush any queued up mailbox requests. - */ - bfa_ioc_mbox_flush(iocpf->ioc); - - bfa_ioc_hw_sem_get(iocpf->ioc); -} - -static void -bfa_iocpf_sm_fail_sync(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_SEMLOCKED: - bfa_ioc_sync_ack(ioc); - bfa_ioc_notify_fail(ioc); - if (!iocpf->auto_recover) { - bfa_ioc_sync_leave(ioc); - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - } else { - if (bfa_ioc_sync_complete(ioc)) - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_hwinit); - else { - writel(1, ioc->ioc_regs.ioc_sem_reg); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_semwait); - } - } - break; - - case IOCPF_E_SEM_ERROR: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_fail); - bfa_fsm_send_event(ioc, IOC_E_HWFAILED); - break; - - case IOCPF_E_DISABLE: - bfa_sem_timer_stop(ioc); - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabling_sync); - break; - - case IOCPF_E_FAIL: - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -static void -bfa_iocpf_sm_fail_entry(struct bfa_iocpf_s *iocpf) -{ - bfa_trc(iocpf->ioc, 0); -} - -/* - * IOC is in failed state. - */ -static void -bfa_iocpf_sm_fail(struct bfa_iocpf_s *iocpf, enum iocpf_event event) -{ - struct bfa_ioc_s *ioc = iocpf->ioc; - - bfa_trc(ioc, event); - - switch (event) { - case IOCPF_E_DISABLE: - bfa_fsm_set_state(iocpf, bfa_iocpf_sm_disabled); - break; - - default: - bfa_sm_fault(ioc, event); - } -} - -/* - * BFA IOC private functions - */ - -/* - * Notify common modules registered for notification. - */ -static void -bfa_ioc_event_notify(struct bfa_ioc_s *ioc, enum bfa_ioc_event_e event) -{ - struct bfa_ioc_notify_s *notify; - struct list_head *qe; - - list_for_each(qe, &ioc->notify_q) { - notify = (struct bfa_ioc_notify_s *)qe; - notify->cbfn(notify->cbarg, event); - } -} - -static void -bfa_ioc_disable_comp(struct bfa_ioc_s *ioc) -{ - ioc->cbfn->disable_cbfn(ioc->bfa); - bfa_ioc_event_notify(ioc, BFA_IOC_E_DISABLED); -} - -bfa_boolean_t -bfa_ioc_sem_get(void __iomem *sem_reg) -{ - u32 r32; - int cnt = 0; -#define BFA_SEM_SPINCNT 3000 - - r32 = readl(sem_reg); - - while ((r32 & 1) && (cnt < BFA_SEM_SPINCNT)) { - cnt++; - udelay(2); - r32 = readl(sem_reg); - } - - if (!(r32 & 1)) - return BFA_TRUE; - - return BFA_FALSE; -} - -static void -bfa_ioc_hw_sem_get(struct bfa_ioc_s *ioc) -{ - u32 r32; - - /* - * First read to the semaphore register will return 0, subsequent reads - * will return 1. Semaphore is released by writing 1 to the register - */ - r32 = readl(ioc->ioc_regs.ioc_sem_reg); - if (r32 == ~0) { - WARN_ON(r32 == ~0); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEM_ERROR); - return; - } - if (!(r32 & 1)) { - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_SEMLOCKED); - return; - } - - bfa_sem_timer_start(ioc); -} - -/* - * Initialize LPU local memory (aka secondary memory / SRAM) - */ -static void -bfa_ioc_lmem_init(struct bfa_ioc_s *ioc) -{ - u32 pss_ctl; - int i; -#define PSS_LMEM_INIT_TIME 10000 - - pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg); - pss_ctl &= ~__PSS_LMEM_RESET; - pss_ctl |= __PSS_LMEM_INIT_EN; - - /* - * i2c workaround 12.5khz clock - */ - pss_ctl |= __PSS_I2C_CLK_DIV(3UL); - writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg); - - /* - * wait for memory initialization to be complete - */ - i = 0; - do { - pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg); - i++; - } while (!(pss_ctl & __PSS_LMEM_INIT_DONE) && (i < PSS_LMEM_INIT_TIME)); - - /* - * If memory initialization is not successful, IOC timeout will catch - * such failures. - */ - WARN_ON(!(pss_ctl & __PSS_LMEM_INIT_DONE)); - bfa_trc(ioc, pss_ctl); - - pss_ctl &= ~(__PSS_LMEM_INIT_DONE | __PSS_LMEM_INIT_EN); - writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg); -} - -static void -bfa_ioc_lpu_start(struct bfa_ioc_s *ioc) -{ - u32 pss_ctl; - - /* - * Take processor out of reset. - */ - pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg); - pss_ctl &= ~__PSS_LPU0_RESET; - - writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg); -} - -static void -bfa_ioc_lpu_stop(struct bfa_ioc_s *ioc) -{ - u32 pss_ctl; - - /* - * Put processors in reset. - */ - pss_ctl = readl(ioc->ioc_regs.pss_ctl_reg); - pss_ctl |= (__PSS_LPU0_RESET | __PSS_LPU1_RESET); - - writel(pss_ctl, ioc->ioc_regs.pss_ctl_reg); -} - -/* - * Get driver and firmware versions. - */ -void -bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) -{ - u32 pgnum, pgoff; - u32 loff = 0; - int i; - u32 *fwsig = (u32 *) fwhdr; - - pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff); - pgoff = PSS_SMEM_PGOFF(loff); - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - - for (i = 0; i < (sizeof(struct bfi_ioc_image_hdr_s) / sizeof(u32)); - i++) { - fwsig[i] = - bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); - loff += sizeof(u32); - } -} - -/* - * Returns TRUE if same. - */ -bfa_boolean_t -bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, struct bfi_ioc_image_hdr_s *fwhdr) -{ - struct bfi_ioc_image_hdr_s *drv_fwhdr; - int i; - - drv_fwhdr = (struct bfi_ioc_image_hdr_s *) - bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); - - for (i = 0; i < BFI_IOC_MD5SUM_SZ; i++) { - if (fwhdr->md5sum[i] != drv_fwhdr->md5sum[i]) { - bfa_trc(ioc, i); - bfa_trc(ioc, fwhdr->md5sum[i]); - bfa_trc(ioc, drv_fwhdr->md5sum[i]); - return BFA_FALSE; - } - } - - bfa_trc(ioc, fwhdr->md5sum[0]); - return BFA_TRUE; -} - -/* - * Return true if current running version is valid. Firmware signature and - * execution context (driver/bios) must match. - */ -static bfa_boolean_t -bfa_ioc_fwver_valid(struct bfa_ioc_s *ioc, u32 boot_env) -{ - struct bfi_ioc_image_hdr_s fwhdr, *drv_fwhdr; - - bfa_ioc_fwver_get(ioc, &fwhdr); - drv_fwhdr = (struct bfi_ioc_image_hdr_s *) - bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), 0); - - if (fwhdr.signature != drv_fwhdr->signature) { - bfa_trc(ioc, fwhdr.signature); - bfa_trc(ioc, drv_fwhdr->signature); - return BFA_FALSE; - } - - if (swab32(fwhdr.bootenv) != boot_env) { - bfa_trc(ioc, fwhdr.bootenv); - bfa_trc(ioc, boot_env); - return BFA_FALSE; - } - - return bfa_ioc_fwver_cmp(ioc, &fwhdr); -} - -/* - * Conditionally flush any pending message from firmware at start. - */ -static void -bfa_ioc_msgflush(struct bfa_ioc_s *ioc) -{ - u32 r32; - - r32 = readl(ioc->ioc_regs.lpu_mbox_cmd); - if (r32) - writel(1, ioc->ioc_regs.lpu_mbox_cmd); -} - -static void -bfa_ioc_hwinit(struct bfa_ioc_s *ioc, bfa_boolean_t force) -{ - enum bfi_ioc_state ioc_fwstate; - bfa_boolean_t fwvalid; - u32 boot_type; - u32 boot_env; - - ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate); - - if (force) - ioc_fwstate = BFI_IOC_UNINIT; - - bfa_trc(ioc, ioc_fwstate); - - boot_type = BFI_FWBOOT_TYPE_NORMAL; - boot_env = BFI_FWBOOT_ENV_OS; - - /* - * check if firmware is valid - */ - fwvalid = (ioc_fwstate == BFI_IOC_UNINIT) ? - BFA_FALSE : bfa_ioc_fwver_valid(ioc, boot_env); - - if (!fwvalid) { - bfa_ioc_boot(ioc, boot_type, boot_env); - bfa_ioc_poll_fwinit(ioc); - return; - } - - /* - * If hardware initialization is in progress (initialized by other IOC), - * just wait for an initialization completion interrupt. - */ - if (ioc_fwstate == BFI_IOC_INITING) { - bfa_ioc_poll_fwinit(ioc); - return; - } - - /* - * If IOC function is disabled and firmware version is same, - * just re-enable IOC. - * - * If option rom, IOC must not be in operational state. With - * convergence, IOC will be in operational state when 2nd driver - * is loaded. - */ - if (ioc_fwstate == BFI_IOC_DISABLED || ioc_fwstate == BFI_IOC_OP) { - - /* - * When using MSI-X any pending firmware ready event should - * be flushed. Otherwise MSI-X interrupts are not delivered. - */ - bfa_ioc_msgflush(ioc); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY); - return; - } - - /* - * Initialize the h/w for any other states. - */ - bfa_ioc_boot(ioc, boot_type, boot_env); - bfa_ioc_poll_fwinit(ioc); -} - -static void -bfa_ioc_timeout(void *ioc_arg) -{ - struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; - - bfa_trc(ioc, 0); - bfa_fsm_send_event(ioc, IOC_E_TIMEOUT); -} - -void -bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len) -{ - u32 *msgp = (u32 *) ioc_msg; - u32 i; - - bfa_trc(ioc, msgp[0]); - bfa_trc(ioc, len); - - WARN_ON(len > BFI_IOC_MSGLEN_MAX); - - /* - * first write msg to mailbox registers - */ - for (i = 0; i < len / sizeof(u32); i++) - writel(cpu_to_le32(msgp[i]), - ioc->ioc_regs.hfn_mbox + i * sizeof(u32)); - - for (; i < BFI_IOC_MSGLEN_MAX / sizeof(u32); i++) - writel(0, ioc->ioc_regs.hfn_mbox + i * sizeof(u32)); - - /* - * write 1 to mailbox CMD to trigger LPU event - */ - writel(1, ioc->ioc_regs.hfn_mbox_cmd); - (void) readl(ioc->ioc_regs.hfn_mbox_cmd); -} - -static void -bfa_ioc_send_enable(struct bfa_ioc_s *ioc) -{ - struct bfi_ioc_ctrl_req_s enable_req; - struct timeval tv; - - bfi_h2i_set(enable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_ENABLE_REQ, - bfa_ioc_portid(ioc)); - enable_req.clscode = cpu_to_be16(ioc->clscode); - do_gettimeofday(&tv); - enable_req.tv_sec = be32_to_cpu(tv.tv_sec); - bfa_ioc_mbox_send(ioc, &enable_req, sizeof(struct bfi_ioc_ctrl_req_s)); -} - -static void -bfa_ioc_send_disable(struct bfa_ioc_s *ioc) -{ - struct bfi_ioc_ctrl_req_s disable_req; - - bfi_h2i_set(disable_req.mh, BFI_MC_IOC, BFI_IOC_H2I_DISABLE_REQ, - bfa_ioc_portid(ioc)); - bfa_ioc_mbox_send(ioc, &disable_req, sizeof(struct bfi_ioc_ctrl_req_s)); -} - -static void -bfa_ioc_send_getattr(struct bfa_ioc_s *ioc) -{ - struct bfi_ioc_getattr_req_s attr_req; - - bfi_h2i_set(attr_req.mh, BFI_MC_IOC, BFI_IOC_H2I_GETATTR_REQ, - bfa_ioc_portid(ioc)); - bfa_dma_be_addr_set(attr_req.attr_addr, ioc->attr_dma.pa); - bfa_ioc_mbox_send(ioc, &attr_req, sizeof(attr_req)); -} - -static void -bfa_ioc_hb_check(void *cbarg) -{ - struct bfa_ioc_s *ioc = cbarg; - u32 hb_count; - - hb_count = readl(ioc->ioc_regs.heartbeat); - if (ioc->hb_count == hb_count) { - bfa_ioc_recover(ioc); - return; - } else { - ioc->hb_count = hb_count; - } - - bfa_ioc_mbox_poll(ioc); - bfa_hb_timer_start(ioc); -} - -static void -bfa_ioc_hb_monitor(struct bfa_ioc_s *ioc) -{ - ioc->hb_count = readl(ioc->ioc_regs.heartbeat); - bfa_hb_timer_start(ioc); -} - -/* - * Initiate a full firmware download. - */ -static void -bfa_ioc_download_fw(struct bfa_ioc_s *ioc, u32 boot_type, - u32 boot_env) -{ - u32 *fwimg; - u32 pgnum, pgoff; - u32 loff = 0; - u32 chunkno = 0; - u32 i; - u32 asicmode; - - bfa_trc(ioc, bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc))); - fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), chunkno); - - pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff); - pgoff = PSS_SMEM_PGOFF(loff); - - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - - for (i = 0; i < bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)); i++) { - - if (BFA_IOC_FLASH_CHUNK_NO(i) != chunkno) { - chunkno = BFA_IOC_FLASH_CHUNK_NO(i); - fwimg = bfa_cb_image_get_chunk(bfa_ioc_asic_gen(ioc), - BFA_IOC_FLASH_CHUNK_ADDR(chunkno)); - } - - /* - * write smem - */ - bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, - fwimg[BFA_IOC_FLASH_OFFSET_IN_CHUNK(i)]); - - loff += sizeof(u32); - - /* - * handle page offset wrap around - */ - loff = PSS_SMEM_PGOFF(loff); - if (loff == 0) { - pgnum++; - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - } - } - - writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0), - ioc->ioc_regs.host_page_num_fn); - - /* - * Set boot type and device mode at the end. - */ - asicmode = BFI_FWBOOT_DEVMODE(ioc->asic_gen, ioc->asic_mode, - ioc->port0_mode, ioc->port1_mode); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_DEVMODE_OFF, - swab32(asicmode)); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_TYPE_OFF, - swab32(boot_type)); - bfa_mem_write(ioc->ioc_regs.smem_page_start, BFI_FWBOOT_ENV_OFF, - swab32(boot_env)); -} - - -/* - * Update BFA configuration from firmware configuration. - */ -static void -bfa_ioc_getattr_reply(struct bfa_ioc_s *ioc) -{ - struct bfi_ioc_attr_s *attr = ioc->attr; - - attr->adapter_prop = be32_to_cpu(attr->adapter_prop); - attr->card_type = be32_to_cpu(attr->card_type); - attr->maxfrsize = be16_to_cpu(attr->maxfrsize); - ioc->fcmode = (attr->port_mode == BFI_PORT_MODE_FC); - - bfa_fsm_send_event(ioc, IOC_E_FWRSP_GETATTR); -} - -/* - * Attach time initialization of mbox logic. - */ -static void -bfa_ioc_mbox_attach(struct bfa_ioc_s *ioc) -{ - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - int mc; - - INIT_LIST_HEAD(&mod->cmd_q); - for (mc = 0; mc < BFI_MC_MAX; mc++) { - mod->mbhdlr[mc].cbfn = NULL; - mod->mbhdlr[mc].cbarg = ioc->bfa; - } -} - -/* - * Mbox poll timer -- restarts any pending mailbox requests. - */ -static void -bfa_ioc_mbox_poll(struct bfa_ioc_s *ioc) -{ - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - struct bfa_mbox_cmd_s *cmd; - u32 stat; - - /* - * If no command pending, do nothing - */ - if (list_empty(&mod->cmd_q)) - return; - - /* - * If previous command is not yet fetched by firmware, do nothing - */ - stat = readl(ioc->ioc_regs.hfn_mbox_cmd); - if (stat) - return; - - /* - * Enqueue command to firmware. - */ - bfa_q_deq(&mod->cmd_q, &cmd); - bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg)); -} - -/* - * Cleanup any pending requests. - */ -static void -bfa_ioc_mbox_flush(struct bfa_ioc_s *ioc) -{ - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - struct bfa_mbox_cmd_s *cmd; - - while (!list_empty(&mod->cmd_q)) - bfa_q_deq(&mod->cmd_q, &cmd); -} - -/* - * Read data from SMEM to host through PCI memmap - * - * @param[in] ioc memory for IOC - * @param[in] tbuf app memory to store data from smem - * @param[in] soff smem offset - * @param[in] sz size of smem in bytes - */ -static bfa_status_t -bfa_ioc_smem_read(struct bfa_ioc_s *ioc, void *tbuf, u32 soff, u32 sz) -{ - u32 pgnum, loff; - __be32 r32; - int i, len; - u32 *buf = tbuf; - - pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff); - loff = PSS_SMEM_PGOFF(soff); - bfa_trc(ioc, pgnum); - bfa_trc(ioc, loff); - bfa_trc(ioc, sz); - - /* - * Hold semaphore to serialize pll init and fwtrc. - */ - if (BFA_FALSE == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg)) { - bfa_trc(ioc, 0); - return BFA_STATUS_FAILED; - } - - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - - len = sz/sizeof(u32); - bfa_trc(ioc, len); - for (i = 0; i < len; i++) { - r32 = bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); - buf[i] = be32_to_cpu(r32); - loff += sizeof(u32); - - /* - * handle page offset wrap around - */ - loff = PSS_SMEM_PGOFF(loff); - if (loff == 0) { - pgnum++; - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - } - } - writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0), - ioc->ioc_regs.host_page_num_fn); - /* - * release semaphore. - */ - readl(ioc->ioc_regs.ioc_init_sem_reg); - writel(1, ioc->ioc_regs.ioc_init_sem_reg); - - bfa_trc(ioc, pgnum); - return BFA_STATUS_OK; -} - -/* - * Clear SMEM data from host through PCI memmap - * - * @param[in] ioc memory for IOC - * @param[in] soff smem offset - * @param[in] sz size of smem in bytes - */ -static bfa_status_t -bfa_ioc_smem_clr(struct bfa_ioc_s *ioc, u32 soff, u32 sz) -{ - int i, len; - u32 pgnum, loff; - - pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, soff); - loff = PSS_SMEM_PGOFF(soff); - bfa_trc(ioc, pgnum); - bfa_trc(ioc, loff); - bfa_trc(ioc, sz); - - /* - * Hold semaphore to serialize pll init and fwtrc. - */ - if (BFA_FALSE == bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg)) { - bfa_trc(ioc, 0); - return BFA_STATUS_FAILED; - } - - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - - len = sz/sizeof(u32); /* len in words */ - bfa_trc(ioc, len); - for (i = 0; i < len; i++) { - bfa_mem_write(ioc->ioc_regs.smem_page_start, loff, 0); - loff += sizeof(u32); - - /* - * handle page offset wrap around - */ - loff = PSS_SMEM_PGOFF(loff); - if (loff == 0) { - pgnum++; - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - } - } - writel(PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, 0), - ioc->ioc_regs.host_page_num_fn); - - /* - * release semaphore. - */ - readl(ioc->ioc_regs.ioc_init_sem_reg); - writel(1, ioc->ioc_regs.ioc_init_sem_reg); - bfa_trc(ioc, pgnum); - return BFA_STATUS_OK; -} - -static void -bfa_ioc_fail_notify(struct bfa_ioc_s *ioc) -{ - struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; - - /* - * Notify driver and common modules registered for notification. - */ - ioc->cbfn->hbfail_cbfn(ioc->bfa); - bfa_ioc_event_notify(ioc, BFA_IOC_E_FAILED); - - bfa_ioc_debug_save_ftrc(ioc); - - BFA_LOG(KERN_CRIT, bfad, bfa_log_level, - "Heart Beat of IOC has failed\n"); - bfa_ioc_aen_post(ioc, BFA_IOC_AEN_HBFAIL); - -} - -static void -bfa_ioc_pf_fwmismatch(struct bfa_ioc_s *ioc) -{ - struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; - /* - * Provide enable completion callback. - */ - ioc->cbfn->enable_cbfn(ioc->bfa, BFA_STATUS_IOC_FAILURE); - BFA_LOG(KERN_WARNING, bfad, bfa_log_level, - "Running firmware version is incompatible " - "with the driver version\n"); - bfa_ioc_aen_post(ioc, BFA_IOC_AEN_FWMISMATCH); -} - -bfa_status_t -bfa_ioc_pll_init(struct bfa_ioc_s *ioc) -{ - - /* - * Hold semaphore so that nobody can access the chip during init. - */ - bfa_ioc_sem_get(ioc->ioc_regs.ioc_init_sem_reg); - - bfa_ioc_pll_init_asic(ioc); - - ioc->pllinit = BFA_TRUE; - - /* - * Initialize LMEM - */ - bfa_ioc_lmem_init(ioc); - - /* - * release semaphore. - */ - readl(ioc->ioc_regs.ioc_init_sem_reg); - writel(1, ioc->ioc_regs.ioc_init_sem_reg); - - return BFA_STATUS_OK; -} - -/* - * Interface used by diag module to do firmware boot with memory test - * as the entry vector. - */ -void -bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, u32 boot_env) -{ - bfa_ioc_stats(ioc, ioc_boots); - - if (bfa_ioc_pll_init(ioc) != BFA_STATUS_OK) - return; - - /* - * Initialize IOC state of all functions on a chip reset. - */ - if (boot_type == BFI_FWBOOT_TYPE_MEMTEST) { - writel(BFI_IOC_MEMTEST, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_MEMTEST, ioc->ioc_regs.alt_ioc_fwstate); - } else { - writel(BFI_IOC_INITING, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_INITING, ioc->ioc_regs.alt_ioc_fwstate); - } - - bfa_ioc_msgflush(ioc); - bfa_ioc_download_fw(ioc, boot_type, boot_env); - bfa_ioc_lpu_start(ioc); -} - -/* - * Enable/disable IOC failure auto recovery. - */ -void -bfa_ioc_auto_recover(bfa_boolean_t auto_recover) -{ - bfa_auto_recover = auto_recover; -} - - - -bfa_boolean_t -bfa_ioc_is_operational(struct bfa_ioc_s *ioc) -{ - return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op); -} - -bfa_boolean_t -bfa_ioc_is_initialized(struct bfa_ioc_s *ioc) -{ - u32 r32 = readl(ioc->ioc_regs.ioc_fwstate); - - return ((r32 != BFI_IOC_UNINIT) && - (r32 != BFI_IOC_INITING) && - (r32 != BFI_IOC_MEMTEST)); -} - -bfa_boolean_t -bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg) -{ - __be32 *msgp = mbmsg; - u32 r32; - int i; - - r32 = readl(ioc->ioc_regs.lpu_mbox_cmd); - if ((r32 & 1) == 0) - return BFA_FALSE; - - /* - * read the MBOX msg - */ - for (i = 0; i < (sizeof(union bfi_ioc_i2h_msg_u) / sizeof(u32)); - i++) { - r32 = readl(ioc->ioc_regs.lpu_mbox + - i * sizeof(u32)); - msgp[i] = cpu_to_be32(r32); - } - - /* - * turn off mailbox interrupt by clearing mailbox status - */ - writel(1, ioc->ioc_regs.lpu_mbox_cmd); - readl(ioc->ioc_regs.lpu_mbox_cmd); - - return BFA_TRUE; -} - -void -bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *m) -{ - union bfi_ioc_i2h_msg_u *msg; - struct bfa_iocpf_s *iocpf = &ioc->iocpf; - - msg = (union bfi_ioc_i2h_msg_u *) m; - - bfa_ioc_stats(ioc, ioc_isrs); - - switch (msg->mh.msg_id) { - case BFI_IOC_I2H_HBEAT: - break; - - case BFI_IOC_I2H_ENABLE_REPLY: - ioc->port_mode = ioc->port_mode_cfg = - (enum bfa_mode_s)msg->fw_event.port_mode; - ioc->ad_cap_bm = msg->fw_event.cap_bm; - bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_ENABLE); - break; - - case BFI_IOC_I2H_DISABLE_REPLY: - bfa_fsm_send_event(iocpf, IOCPF_E_FWRSP_DISABLE); - break; - - case BFI_IOC_I2H_GETATTR_REPLY: - bfa_ioc_getattr_reply(ioc); - break; - - default: - bfa_trc(ioc, msg->mh.msg_id); - WARN_ON(1); - } -} - -/* - * IOC attach time initialization and setup. - * - * @param[in] ioc memory for IOC - * @param[in] bfa driver instance structure - */ -void -bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, struct bfa_ioc_cbfn_s *cbfn, - struct bfa_timer_mod_s *timer_mod) -{ - ioc->bfa = bfa; - ioc->cbfn = cbfn; - ioc->timer_mod = timer_mod; - ioc->fcmode = BFA_FALSE; - ioc->pllinit = BFA_FALSE; - ioc->dbg_fwsave_once = BFA_TRUE; - ioc->iocpf.ioc = ioc; - - bfa_ioc_mbox_attach(ioc); - INIT_LIST_HEAD(&ioc->notify_q); - - bfa_fsm_set_state(ioc, bfa_ioc_sm_uninit); - bfa_fsm_send_event(ioc, IOC_E_RESET); -} - -/* - * Driver detach time IOC cleanup. - */ -void -bfa_ioc_detach(struct bfa_ioc_s *ioc) -{ - bfa_fsm_send_event(ioc, IOC_E_DETACH); - INIT_LIST_HEAD(&ioc->notify_q); -} - -/* - * Setup IOC PCI properties. - * - * @param[in] pcidev PCI device information for this IOC - */ -void -bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, - enum bfi_pcifn_class clscode) -{ - ioc->clscode = clscode; - ioc->pcidev = *pcidev; - - /* - * Initialize IOC and device personality - */ - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_FC; - ioc->asic_mode = BFI_ASIC_MODE_FC; - - switch (pcidev->device_id) { - case BFA_PCI_DEVICE_ID_FC_8G1P: - case BFA_PCI_DEVICE_ID_FC_8G2P: - ioc->asic_gen = BFI_ASIC_GEN_CB; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - break; - - case BFA_PCI_DEVICE_ID_CT: - ioc->asic_gen = BFI_ASIC_GEN_CT; - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH; - ioc->asic_mode = BFI_ASIC_MODE_ETH; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_CNA; - ioc->ad_cap_bm = BFA_CM_CNA; - break; - - case BFA_PCI_DEVICE_ID_CT_FC: - ioc->asic_gen = BFI_ASIC_GEN_CT; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - break; - - case BFA_PCI_DEVICE_ID_CT2: - ioc->asic_gen = BFI_ASIC_GEN_CT2; - if (clscode == BFI_PCIFN_CLASS_FC && - pcidev->ssid == BFA_PCI_CT2_SSID_FC) { - ioc->asic_mode = BFI_ASIC_MODE_FC16; - ioc->fcmode = BFA_TRUE; - ioc->port_mode = ioc->port_mode_cfg = BFA_MODE_HBA; - ioc->ad_cap_bm = BFA_CM_HBA; - } else { - ioc->port0_mode = ioc->port1_mode = BFI_PORT_MODE_ETH; - ioc->asic_mode = BFI_ASIC_MODE_ETH; - if (pcidev->ssid == BFA_PCI_CT2_SSID_FCoE) { - ioc->port_mode = - ioc->port_mode_cfg = BFA_MODE_CNA; - ioc->ad_cap_bm = BFA_CM_CNA; - } else { - ioc->port_mode = - ioc->port_mode_cfg = BFA_MODE_NIC; - ioc->ad_cap_bm = BFA_CM_NIC; - } - } - break; - - default: - WARN_ON(1); - } - - /* - * Set asic specific interfaces. See bfa_ioc_cb.c and bfa_ioc_ct.c - */ - if (ioc->asic_gen == BFI_ASIC_GEN_CB) - bfa_ioc_set_cb_hwif(ioc); - else if (ioc->asic_gen == BFI_ASIC_GEN_CT) - bfa_ioc_set_ct_hwif(ioc); - else { - WARN_ON(ioc->asic_gen != BFI_ASIC_GEN_CT2); - bfa_ioc_set_ct2_hwif(ioc); - bfa_ioc_ct2_poweron(ioc); - } - - bfa_ioc_map_port(ioc); - bfa_ioc_reg_init(ioc); -} - -/* - * Initialize IOC dma memory - * - * @param[in] dm_kva kernel virtual address of IOC dma memory - * @param[in] dm_pa physical address of IOC dma memory - */ -void -bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa) -{ - /* - * dma memory for firmware attribute - */ - ioc->attr_dma.kva = dm_kva; - ioc->attr_dma.pa = dm_pa; - ioc->attr = (struct bfi_ioc_attr_s *) dm_kva; -} - -void -bfa_ioc_enable(struct bfa_ioc_s *ioc) -{ - bfa_ioc_stats(ioc, ioc_enables); - ioc->dbg_fwsave_once = BFA_TRUE; - - bfa_fsm_send_event(ioc, IOC_E_ENABLE); -} - -void -bfa_ioc_disable(struct bfa_ioc_s *ioc) -{ - bfa_ioc_stats(ioc, ioc_disables); - bfa_fsm_send_event(ioc, IOC_E_DISABLE); -} - - -/* - * Initialize memory for saving firmware trace. Driver must initialize - * trace memory before call bfa_ioc_enable(). - */ -void -bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave) -{ - ioc->dbg_fwsave = dbg_fwsave; - ioc->dbg_fwsave_len = (ioc->iocpf.auto_recover) ? BFA_DBG_FWTRC_LEN : 0; -} - -/* - * Register mailbox message handler functions - * - * @param[in] ioc IOC instance - * @param[in] mcfuncs message class handler functions - */ -void -bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, bfa_ioc_mbox_mcfunc_t *mcfuncs) -{ - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - int mc; - - for (mc = 0; mc < BFI_MC_MAX; mc++) - mod->mbhdlr[mc].cbfn = mcfuncs[mc]; -} - -/* - * Register mailbox message handler function, to be called by common modules - */ -void -bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, - bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg) -{ - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - - mod->mbhdlr[mc].cbfn = cbfn; - mod->mbhdlr[mc].cbarg = cbarg; -} - -/* - * Queue a mailbox command request to firmware. Waits if mailbox is busy. - * Responsibility of caller to serialize - * - * @param[in] ioc IOC instance - * @param[i] cmd Mailbox command - */ -void -bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd) -{ - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - u32 stat; - - /* - * If a previous command is pending, queue new command - */ - if (!list_empty(&mod->cmd_q)) { - list_add_tail(&cmd->qe, &mod->cmd_q); - return; - } - - /* - * If mailbox is busy, queue command for poll timer - */ - stat = readl(ioc->ioc_regs.hfn_mbox_cmd); - if (stat) { - list_add_tail(&cmd->qe, &mod->cmd_q); - return; - } - - /* - * mailbox is free -- queue command to firmware - */ - bfa_ioc_mbox_send(ioc, cmd->msg, sizeof(cmd->msg)); -} - -/* - * Handle mailbox interrupts - */ -void -bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc) -{ - struct bfa_ioc_mbox_mod_s *mod = &ioc->mbox_mod; - struct bfi_mbmsg_s m; - int mc; - - if (bfa_ioc_msgget(ioc, &m)) { - /* - * Treat IOC message class as special. - */ - mc = m.mh.msg_class; - if (mc == BFI_MC_IOC) { - bfa_ioc_isr(ioc, &m); - return; - } - - if ((mc > BFI_MC_MAX) || (mod->mbhdlr[mc].cbfn == NULL)) - return; - - mod->mbhdlr[mc].cbfn(mod->mbhdlr[mc].cbarg, &m); - } - - bfa_ioc_lpu_read_stat(ioc); - - /* - * Try to send pending mailbox commands - */ - bfa_ioc_mbox_poll(ioc); -} - -void -bfa_ioc_error_isr(struct bfa_ioc_s *ioc) -{ - bfa_ioc_stats(ioc, ioc_hbfails); - ioc->stats.hb_count = ioc->hb_count; - bfa_fsm_send_event(ioc, IOC_E_HWERROR); -} - -/* - * return true if IOC is disabled - */ -bfa_boolean_t -bfa_ioc_is_disabled(struct bfa_ioc_s *ioc) -{ - return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabling) || - bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled); -} - -/* - * return true if IOC firmware is different. - */ -bfa_boolean_t -bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc) -{ - return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_reset) || - bfa_fsm_cmp_state(&ioc->iocpf, bfa_iocpf_sm_fwcheck) || - bfa_fsm_cmp_state(&ioc->iocpf, bfa_iocpf_sm_mismatch); -} - -#define bfa_ioc_state_disabled(__sm) \ - (((__sm) == BFI_IOC_UNINIT) || \ - ((__sm) == BFI_IOC_INITING) || \ - ((__sm) == BFI_IOC_HWINIT) || \ - ((__sm) == BFI_IOC_DISABLED) || \ - ((__sm) == BFI_IOC_FAIL) || \ - ((__sm) == BFI_IOC_CFG_DISABLED)) - -/* - * Check if adapter is disabled -- both IOCs should be in a disabled - * state. - */ -bfa_boolean_t -bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc) -{ - u32 ioc_state; - - if (!bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled)) - return BFA_FALSE; - - ioc_state = readl(ioc->ioc_regs.ioc_fwstate); - if (!bfa_ioc_state_disabled(ioc_state)) - return BFA_FALSE; - - if (ioc->pcidev.device_id != BFA_PCI_DEVICE_ID_FC_8G1P) { - ioc_state = readl(ioc->ioc_regs.alt_ioc_fwstate); - if (!bfa_ioc_state_disabled(ioc_state)) - return BFA_FALSE; - } - - return BFA_TRUE; -} - -/* - * Reset IOC fwstate registers. - */ -void -bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc) -{ - writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate); -} - -#define BFA_MFG_NAME "Brocade" -void -bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, - struct bfa_adapter_attr_s *ad_attr) -{ - struct bfi_ioc_attr_s *ioc_attr; - - ioc_attr = ioc->attr; - - bfa_ioc_get_adapter_serial_num(ioc, ad_attr->serial_num); - bfa_ioc_get_adapter_fw_ver(ioc, ad_attr->fw_ver); - bfa_ioc_get_adapter_optrom_ver(ioc, ad_attr->optrom_ver); - bfa_ioc_get_adapter_manufacturer(ioc, ad_attr->manufacturer); - memcpy(&ad_attr->vpd, &ioc_attr->vpd, - sizeof(struct bfa_mfg_vpd_s)); - - ad_attr->nports = bfa_ioc_get_nports(ioc); - ad_attr->max_speed = bfa_ioc_speed_sup(ioc); - - bfa_ioc_get_adapter_model(ioc, ad_attr->model); - /* For now, model descr uses same model string */ - bfa_ioc_get_adapter_model(ioc, ad_attr->model_descr); - - ad_attr->card_type = ioc_attr->card_type; - ad_attr->is_mezz = bfa_mfg_is_mezz(ioc_attr->card_type); - - if (BFI_ADAPTER_IS_SPECIAL(ioc_attr->adapter_prop)) - ad_attr->prototype = 1; - else - ad_attr->prototype = 0; - - ad_attr->pwwn = ioc->attr->pwwn; - ad_attr->mac = bfa_ioc_get_mac(ioc); - - ad_attr->pcie_gen = ioc_attr->pcie_gen; - ad_attr->pcie_lanes = ioc_attr->pcie_lanes; - ad_attr->pcie_lanes_orig = ioc_attr->pcie_lanes_orig; - ad_attr->asic_rev = ioc_attr->asic_rev; - - bfa_ioc_get_pci_chip_rev(ioc, ad_attr->hw_ver); - - ad_attr->cna_capable = bfa_ioc_is_cna(ioc); - ad_attr->trunk_capable = (ad_attr->nports > 1) && - !bfa_ioc_is_cna(ioc) && !ad_attr->is_mezz; -} - -enum bfa_ioc_type_e -bfa_ioc_get_type(struct bfa_ioc_s *ioc) -{ - if (ioc->clscode == BFI_PCIFN_CLASS_ETH) - return BFA_IOC_TYPE_LL; - - WARN_ON(ioc->clscode != BFI_PCIFN_CLASS_FC); - - return (ioc->attr->port_mode == BFI_PORT_MODE_FC) - ? BFA_IOC_TYPE_FC : BFA_IOC_TYPE_FCoE; -} - -void -bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num) -{ - memset((void *)serial_num, 0, BFA_ADAPTER_SERIAL_NUM_LEN); - memcpy((void *)serial_num, - (void *)ioc->attr->brcd_serialnum, - BFA_ADAPTER_SERIAL_NUM_LEN); -} - -void -bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver) -{ - memset((void *)fw_ver, 0, BFA_VERSION_LEN); - memcpy(fw_ver, ioc->attr->fw_version, BFA_VERSION_LEN); -} - -void -bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev) -{ - WARN_ON(!chip_rev); - - memset((void *)chip_rev, 0, BFA_IOC_CHIP_REV_LEN); - - chip_rev[0] = 'R'; - chip_rev[1] = 'e'; - chip_rev[2] = 'v'; - chip_rev[3] = '-'; - chip_rev[4] = ioc->attr->asic_rev; - chip_rev[5] = '\0'; -} - -void -bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver) -{ - memset((void *)optrom_ver, 0, BFA_VERSION_LEN); - memcpy(optrom_ver, ioc->attr->optrom_version, - BFA_VERSION_LEN); -} - -void -bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, char *manufacturer) -{ - memset((void *)manufacturer, 0, BFA_ADAPTER_MFG_NAME_LEN); - memcpy(manufacturer, BFA_MFG_NAME, BFA_ADAPTER_MFG_NAME_LEN); -} - -void -bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model) -{ - struct bfi_ioc_attr_s *ioc_attr; - - WARN_ON(!model); - memset((void *)model, 0, BFA_ADAPTER_MODEL_NAME_LEN); - - ioc_attr = ioc->attr; - - snprintf(model, BFA_ADAPTER_MODEL_NAME_LEN, "%s-%u", - BFA_MFG_NAME, ioc_attr->card_type); -} - -enum bfa_ioc_state -bfa_ioc_get_state(struct bfa_ioc_s *ioc) -{ - enum bfa_iocpf_state iocpf_st; - enum bfa_ioc_state ioc_st = bfa_sm_to_state(ioc_sm_table, ioc->fsm); - - if (ioc_st == BFA_IOC_ENABLING || - ioc_st == BFA_IOC_FAIL || ioc_st == BFA_IOC_INITFAIL) { - - iocpf_st = bfa_sm_to_state(iocpf_sm_table, ioc->iocpf.fsm); - - switch (iocpf_st) { - case BFA_IOCPF_SEMWAIT: - ioc_st = BFA_IOC_SEMWAIT; - break; - - case BFA_IOCPF_HWINIT: - ioc_st = BFA_IOC_HWINIT; - break; - - case BFA_IOCPF_FWMISMATCH: - ioc_st = BFA_IOC_FWMISMATCH; - break; - - case BFA_IOCPF_FAIL: - ioc_st = BFA_IOC_FAIL; - break; - - case BFA_IOCPF_INITFAIL: - ioc_st = BFA_IOC_INITFAIL; - break; - - default: - break; - } - } - - return ioc_st; -} - -void -bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr) -{ - memset((void *)ioc_attr, 0, sizeof(struct bfa_ioc_attr_s)); - - ioc_attr->state = bfa_ioc_get_state(ioc); - ioc_attr->port_id = ioc->port_id; - ioc_attr->port_mode = ioc->port_mode; - ioc_attr->port_mode_cfg = ioc->port_mode_cfg; - ioc_attr->cap_bm = ioc->ad_cap_bm; - - ioc_attr->ioc_type = bfa_ioc_get_type(ioc); - - bfa_ioc_get_adapter_attr(ioc, &ioc_attr->adapter_attr); - - ioc_attr->pci_attr.device_id = ioc->pcidev.device_id; - ioc_attr->pci_attr.pcifn = ioc->pcidev.pci_func; - bfa_ioc_get_pci_chip_rev(ioc, ioc_attr->pci_attr.chip_rev); -} - -mac_t -bfa_ioc_get_mac(struct bfa_ioc_s *ioc) -{ - /* - * Check the IOC type and return the appropriate MAC - */ - if (bfa_ioc_get_type(ioc) == BFA_IOC_TYPE_FCoE) - return ioc->attr->fcoe_mac; - else - return ioc->attr->mac; -} - -mac_t -bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc) -{ - mac_t m; - - m = ioc->attr->mfg_mac; - if (bfa_mfg_is_old_wwn_mac_model(ioc->attr->card_type)) - m.mac[MAC_ADDRLEN - 1] += bfa_ioc_pcifn(ioc); - else - bfa_mfg_increment_wwn_mac(&(m.mac[MAC_ADDRLEN-3]), - bfa_ioc_pcifn(ioc)); - - return m; -} - -/* - * Send AEN notification - */ -void -bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event) -{ - struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; - struct bfa_aen_entry_s *aen_entry; - enum bfa_ioc_type_e ioc_type; - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - ioc_type = bfa_ioc_get_type(ioc); - switch (ioc_type) { - case BFA_IOC_TYPE_FC: - aen_entry->aen_data.ioc.pwwn = ioc->attr->pwwn; - break; - case BFA_IOC_TYPE_FCoE: - aen_entry->aen_data.ioc.pwwn = ioc->attr->pwwn; - aen_entry->aen_data.ioc.mac = bfa_ioc_get_mac(ioc); - break; - case BFA_IOC_TYPE_LL: - aen_entry->aen_data.ioc.mac = bfa_ioc_get_mac(ioc); - break; - default: - WARN_ON(ioc_type != BFA_IOC_TYPE_FC); - break; - } - - /* Send the AEN notification */ - aen_entry->aen_data.ioc.ioc_type = ioc_type; - bfad_im_post_vendor_event(aen_entry, bfad, ++ioc->ioc_aen_seq, - BFA_AEN_CAT_IOC, event); -} - -/* - * Retrieve saved firmware trace from a prior IOC failure. - */ -bfa_status_t -bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, int *trclen) -{ - int tlen; - - if (ioc->dbg_fwsave_len == 0) - return BFA_STATUS_ENOFSAVE; - - tlen = *trclen; - if (tlen > ioc->dbg_fwsave_len) - tlen = ioc->dbg_fwsave_len; - - memcpy(trcdata, ioc->dbg_fwsave, tlen); - *trclen = tlen; - return BFA_STATUS_OK; -} - - -/* - * Retrieve saved firmware trace from a prior IOC failure. - */ -bfa_status_t -bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, int *trclen) -{ - u32 loff = BFA_DBG_FWTRC_OFF(bfa_ioc_portid(ioc)); - int tlen; - bfa_status_t status; - - bfa_trc(ioc, *trclen); - - tlen = *trclen; - if (tlen > BFA_DBG_FWTRC_LEN) - tlen = BFA_DBG_FWTRC_LEN; - - status = bfa_ioc_smem_read(ioc, trcdata, loff, tlen); - *trclen = tlen; - return status; -} - -static void -bfa_ioc_send_fwsync(struct bfa_ioc_s *ioc) -{ - struct bfa_mbox_cmd_s cmd; - struct bfi_ioc_ctrl_req_s *req = (struct bfi_ioc_ctrl_req_s *) cmd.msg; - - bfi_h2i_set(req->mh, BFI_MC_IOC, BFI_IOC_H2I_DBG_SYNC, - bfa_ioc_portid(ioc)); - req->clscode = cpu_to_be16(ioc->clscode); - bfa_ioc_mbox_queue(ioc, &cmd); -} - -static void -bfa_ioc_fwsync(struct bfa_ioc_s *ioc) -{ - u32 fwsync_iter = 1000; - - bfa_ioc_send_fwsync(ioc); - - /* - * After sending a fw sync mbox command wait for it to - * take effect. We will not wait for a response because - * 1. fw_sync mbox cmd doesn't have a response. - * 2. Even if we implement that, interrupts might not - * be enabled when we call this function. - * So, just keep checking if any mbox cmd is pending, and - * after waiting for a reasonable amount of time, go ahead. - * It is possible that fw has crashed and the mbox command - * is never acknowledged. - */ - while (bfa_ioc_mbox_cmd_pending(ioc) && fwsync_iter > 0) - fwsync_iter--; -} - -/* - * Dump firmware smem - */ -bfa_status_t -bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf, - u32 *offset, int *buflen) -{ - u32 loff; - int dlen; - bfa_status_t status; - u32 smem_len = BFA_IOC_FW_SMEM_SIZE(ioc); - - if (*offset >= smem_len) { - *offset = *buflen = 0; - return BFA_STATUS_EINVAL; - } - - loff = *offset; - dlen = *buflen; - - /* - * First smem read, sync smem before proceeding - * No need to sync before reading every chunk. - */ - if (loff == 0) - bfa_ioc_fwsync(ioc); - - if ((loff + dlen) >= smem_len) - dlen = smem_len - loff; - - status = bfa_ioc_smem_read(ioc, buf, loff, dlen); - - if (status != BFA_STATUS_OK) { - *offset = *buflen = 0; - return status; - } - - *offset += dlen; - - if (*offset >= smem_len) - *offset = 0; - - *buflen = dlen; - - return status; -} - -/* - * Firmware statistics - */ -bfa_status_t -bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats) -{ - u32 loff = BFI_IOC_FWSTATS_OFF + \ - BFI_IOC_FWSTATS_SZ * (bfa_ioc_portid(ioc)); - int tlen; - bfa_status_t status; - - if (ioc->stats_busy) { - bfa_trc(ioc, ioc->stats_busy); - return BFA_STATUS_DEVBUSY; - } - ioc->stats_busy = BFA_TRUE; - - tlen = sizeof(struct bfa_fw_stats_s); - status = bfa_ioc_smem_read(ioc, stats, loff, tlen); - - ioc->stats_busy = BFA_FALSE; - return status; -} - -bfa_status_t -bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc) -{ - u32 loff = BFI_IOC_FWSTATS_OFF + \ - BFI_IOC_FWSTATS_SZ * (bfa_ioc_portid(ioc)); - int tlen; - bfa_status_t status; - - if (ioc->stats_busy) { - bfa_trc(ioc, ioc->stats_busy); - return BFA_STATUS_DEVBUSY; - } - ioc->stats_busy = BFA_TRUE; - - tlen = sizeof(struct bfa_fw_stats_s); - status = bfa_ioc_smem_clr(ioc, loff, tlen); - - ioc->stats_busy = BFA_FALSE; - return status; -} - -/* - * Save firmware trace if configured. - */ -static void -bfa_ioc_debug_save_ftrc(struct bfa_ioc_s *ioc) -{ - int tlen; - - if (ioc->dbg_fwsave_once) { - ioc->dbg_fwsave_once = BFA_FALSE; - if (ioc->dbg_fwsave_len) { - tlen = ioc->dbg_fwsave_len; - bfa_ioc_debug_fwtrc(ioc, ioc->dbg_fwsave, &tlen); - } - } -} - -/* - * Firmware failure detected. Start recovery actions. - */ -static void -bfa_ioc_recover(struct bfa_ioc_s *ioc) -{ - bfa_ioc_stats(ioc, ioc_hbfails); - ioc->stats.hb_count = ioc->hb_count; - bfa_fsm_send_event(ioc, IOC_E_HBFAIL); -} - -/* - * BFA IOC PF private functions - */ -static void -bfa_iocpf_timeout(void *ioc_arg) -{ - struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; - - bfa_trc(ioc, 0); - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_TIMEOUT); -} - -static void -bfa_iocpf_sem_timeout(void *ioc_arg) -{ - struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; - - bfa_ioc_hw_sem_get(ioc); -} - -static void -bfa_ioc_poll_fwinit(struct bfa_ioc_s *ioc) -{ - u32 fwstate = readl(ioc->ioc_regs.ioc_fwstate); - - bfa_trc(ioc, fwstate); - - if (fwstate == BFI_IOC_DISABLED) { - bfa_fsm_send_event(&ioc->iocpf, IOCPF_E_FWREADY); - return; - } - - if (ioc->iocpf.poll_time >= BFA_IOC_TOV) - bfa_iocpf_timeout(ioc); - else { - ioc->iocpf.poll_time += BFA_IOC_POLL_TOV; - bfa_iocpf_poll_timer_start(ioc); - } -} - -static void -bfa_iocpf_poll_timeout(void *ioc_arg) -{ - struct bfa_ioc_s *ioc = (struct bfa_ioc_s *) ioc_arg; - - bfa_ioc_poll_fwinit(ioc); -} - -/* - * bfa timer function - */ -void -bfa_timer_beat(struct bfa_timer_mod_s *mod) -{ - struct list_head *qh = &mod->timer_q; - struct list_head *qe, *qe_next; - struct bfa_timer_s *elem; - struct list_head timedout_q; - - INIT_LIST_HEAD(&timedout_q); - - qe = bfa_q_next(qh); - - while (qe != qh) { - qe_next = bfa_q_next(qe); - - elem = (struct bfa_timer_s *) qe; - if (elem->timeout <= BFA_TIMER_FREQ) { - elem->timeout = 0; - list_del(&elem->qe); - list_add_tail(&elem->qe, &timedout_q); - } else { - elem->timeout -= BFA_TIMER_FREQ; - } - - qe = qe_next; /* go to next elem */ - } - - /* - * Pop all the timeout entries - */ - while (!list_empty(&timedout_q)) { - bfa_q_deq(&timedout_q, &elem); - elem->timercb(elem->arg); - } -} - -/* - * Should be called with lock protection - */ -void -bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer, - void (*timercb) (void *), void *arg, unsigned int timeout) -{ - - WARN_ON(timercb == NULL); - WARN_ON(bfa_q_is_on_q(&mod->timer_q, timer)); - - timer->timeout = timeout; - timer->timercb = timercb; - timer->arg = arg; - - list_add_tail(&timer->qe, &mod->timer_q); -} - -/* - * Should be called with lock protection - */ -void -bfa_timer_stop(struct bfa_timer_s *timer) -{ - WARN_ON(list_empty(&timer->qe)); - - list_del(&timer->qe); -} - -/* - * ASIC block related - */ -static void -bfa_ablk_config_swap(struct bfa_ablk_cfg_s *cfg) -{ - struct bfa_ablk_cfg_inst_s *cfg_inst; - int i, j; - u16 be16; - u32 be32; - - for (i = 0; i < BFA_ABLK_MAX; i++) { - cfg_inst = &cfg->inst[i]; - for (j = 0; j < BFA_ABLK_MAX_PFS; j++) { - be16 = cfg_inst->pf_cfg[j].pers; - cfg_inst->pf_cfg[j].pers = be16_to_cpu(be16); - be16 = cfg_inst->pf_cfg[j].num_qpairs; - cfg_inst->pf_cfg[j].num_qpairs = be16_to_cpu(be16); - be16 = cfg_inst->pf_cfg[j].num_vectors; - cfg_inst->pf_cfg[j].num_vectors = be16_to_cpu(be16); - be32 = cfg_inst->pf_cfg[j].bw; - cfg_inst->pf_cfg[j].bw = be16_to_cpu(be32); - } - } -} - -static void -bfa_ablk_isr(void *cbarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_ablk_s *ablk = (struct bfa_ablk_s *)cbarg; - struct bfi_ablk_i2h_rsp_s *rsp = (struct bfi_ablk_i2h_rsp_s *)msg; - bfa_ablk_cbfn_t cbfn; - - WARN_ON(msg->mh.msg_class != BFI_MC_ABLK); - bfa_trc(ablk->ioc, msg->mh.msg_id); - - switch (msg->mh.msg_id) { - case BFI_ABLK_I2H_QUERY: - if (rsp->status == BFA_STATUS_OK) { - memcpy(ablk->cfg, ablk->dma_addr.kva, - sizeof(struct bfa_ablk_cfg_s)); - bfa_ablk_config_swap(ablk->cfg); - ablk->cfg = NULL; - } - break; - - case BFI_ABLK_I2H_ADPT_CONFIG: - case BFI_ABLK_I2H_PORT_CONFIG: - /* update config port mode */ - ablk->ioc->port_mode_cfg = rsp->port_mode; - - case BFI_ABLK_I2H_PF_DELETE: - case BFI_ABLK_I2H_PF_UPDATE: - case BFI_ABLK_I2H_OPTROM_ENABLE: - case BFI_ABLK_I2H_OPTROM_DISABLE: - /* No-op */ - break; - - case BFI_ABLK_I2H_PF_CREATE: - *(ablk->pcifn) = rsp->pcifn; - ablk->pcifn = NULL; - break; - - default: - WARN_ON(1); - } - - ablk->busy = BFA_FALSE; - if (ablk->cbfn) { - cbfn = ablk->cbfn; - ablk->cbfn = NULL; - cbfn(ablk->cbarg, rsp->status); - } -} - -static void -bfa_ablk_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_ablk_s *ablk = (struct bfa_ablk_s *)cbarg; - - bfa_trc(ablk->ioc, event); - - switch (event) { - case BFA_IOC_E_ENABLED: - WARN_ON(ablk->busy != BFA_FALSE); - break; - - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - /* Fail any pending requests */ - ablk->pcifn = NULL; - if (ablk->busy) { - if (ablk->cbfn) - ablk->cbfn(ablk->cbarg, BFA_STATUS_FAILED); - ablk->cbfn = NULL; - ablk->busy = BFA_FALSE; - } - break; - - default: - WARN_ON(1); - break; - } -} - -u32 -bfa_ablk_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct bfa_ablk_cfg_s), BFA_DMA_ALIGN_SZ); -} - -void -bfa_ablk_memclaim(struct bfa_ablk_s *ablk, u8 *dma_kva, u64 dma_pa) -{ - ablk->dma_addr.kva = dma_kva; - ablk->dma_addr.pa = dma_pa; -} - -void -bfa_ablk_attach(struct bfa_ablk_s *ablk, struct bfa_ioc_s *ioc) -{ - ablk->ioc = ioc; - - bfa_ioc_mbox_regisr(ablk->ioc, BFI_MC_ABLK, bfa_ablk_isr, ablk); - bfa_q_qe_init(&ablk->ioc_notify); - bfa_ioc_notify_init(&ablk->ioc_notify, bfa_ablk_notify, ablk); - list_add_tail(&ablk->ioc_notify.qe, &ablk->ioc->notify_q); -} - -bfa_status_t -bfa_ablk_query(struct bfa_ablk_s *ablk, struct bfa_ablk_cfg_s *ablk_cfg, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_query_s *m; - - WARN_ON(!ablk_cfg); - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cfg = ablk_cfg; - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_query_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_QUERY, - bfa_ioc_portid(ablk->ioc)); - bfa_dma_be_addr_set(m->addr, ablk->dma_addr.pa); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, - u8 port, enum bfi_pcifn_class personality, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->pcifn = pcifn; - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_CREATE, - bfa_ioc_portid(ablk->ioc)); - m->pers = cpu_to_be16((u16)personality); - m->bw = cpu_to_be32(bw); - m->port = port; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_delete(struct bfa_ablk_s *ablk, int pcifn, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_DELETE, - bfa_ioc_portid(ablk->ioc)); - m->pcifn = (u8)pcifn; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_adapter_config(struct bfa_ablk_s *ablk, enum bfa_mode_s mode, - int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_cfg_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_cfg_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_ADPT_CONFIG, - bfa_ioc_portid(ablk->ioc)); - m->mode = (u8)mode; - m->max_pf = (u8)max_pf; - m->max_vf = (u8)max_vf; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, enum bfa_mode_s mode, - int max_pf, int max_vf, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_cfg_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_cfg_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PORT_CONFIG, - bfa_ioc_portid(ablk->ioc)); - m->port = (u8)port; - m->mode = (u8)mode; - m->max_pf = (u8)max_pf; - m->max_vf = (u8)max_vf; - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_pf_req_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_pf_req_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_PF_UPDATE, - bfa_ioc_portid(ablk->ioc)); - m->pcifn = (u8)pcifn; - m->bw = cpu_to_be32(bw); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_optrom_en(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_optrom_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_optrom_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_OPTROM_ENABLE, - bfa_ioc_portid(ablk->ioc)); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, bfa_ablk_cbfn_t cbfn, void *cbarg) -{ - struct bfi_ablk_h2i_optrom_s *m; - - if (!bfa_ioc_is_operational(ablk->ioc)) { - bfa_trc(ablk->ioc, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (ablk->busy) { - bfa_trc(ablk->ioc, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - ablk->cbfn = cbfn; - ablk->cbarg = cbarg; - ablk->busy = BFA_TRUE; - - m = (struct bfi_ablk_h2i_optrom_s *)ablk->mb.msg; - bfi_h2i_set(m->mh, BFI_MC_ABLK, BFI_ABLK_H2I_OPTROM_DISABLE, - bfa_ioc_portid(ablk->ioc)); - bfa_ioc_mbox_queue(ablk->ioc, &ablk->mb); - - return BFA_STATUS_OK; -} - -/* - * SFP module specific - */ - -/* forward declarations */ -static void bfa_sfp_getdata_send(struct bfa_sfp_s *sfp); -static void bfa_sfp_media_get(struct bfa_sfp_s *sfp); -static bfa_status_t bfa_sfp_speed_valid(struct bfa_sfp_s *sfp, - enum bfa_port_speed portspeed); - -static void -bfa_cb_sfp_show(struct bfa_sfp_s *sfp) -{ - bfa_trc(sfp, sfp->lock); - if (sfp->cbfn) - sfp->cbfn(sfp->cbarg, sfp->status); - sfp->lock = 0; - sfp->cbfn = NULL; -} - -static void -bfa_cb_sfp_state_query(struct bfa_sfp_s *sfp) -{ - bfa_trc(sfp, sfp->portspeed); - if (sfp->media) { - bfa_sfp_media_get(sfp); - if (sfp->state_query_cbfn) - sfp->state_query_cbfn(sfp->state_query_cbarg, - sfp->status); - sfp->media = NULL; - } - - if (sfp->portspeed) { - sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed); - if (sfp->state_query_cbfn) - sfp->state_query_cbfn(sfp->state_query_cbarg, - sfp->status); - sfp->portspeed = BFA_PORT_SPEED_UNKNOWN; - } - - sfp->state_query_lock = 0; - sfp->state_query_cbfn = NULL; -} - -/* - * IOC event handler. - */ -static void -bfa_sfp_notify(void *sfp_arg, enum bfa_ioc_event_e event) -{ - struct bfa_sfp_s *sfp = sfp_arg; - - bfa_trc(sfp, event); - bfa_trc(sfp, sfp->lock); - bfa_trc(sfp, sfp->state_query_lock); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (sfp->lock) { - sfp->status = BFA_STATUS_IOC_FAILURE; - bfa_cb_sfp_show(sfp); - } - - if (sfp->state_query_lock) { - sfp->status = BFA_STATUS_IOC_FAILURE; - bfa_cb_sfp_state_query(sfp); - } - break; - - default: - break; - } -} - -/* - * SFP's State Change Notification post to AEN - */ -static void -bfa_sfp_scn_aen_post(struct bfa_sfp_s *sfp, struct bfi_sfp_scn_s *rsp) -{ - struct bfad_s *bfad = (struct bfad_s *)sfp->ioc->bfa->bfad; - struct bfa_aen_entry_s *aen_entry; - enum bfa_port_aen_event aen_evt = 0; - - bfa_trc(sfp, (((u64)rsp->pomlvl) << 16) | (((u64)rsp->sfpid) << 8) | - ((u64)rsp->event)); - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - aen_entry->aen_data.port.ioc_type = bfa_ioc_get_type(sfp->ioc); - aen_entry->aen_data.port.pwwn = sfp->ioc->attr->pwwn; - aen_entry->aen_data.port.mac = bfa_ioc_get_mac(sfp->ioc); - - switch (rsp->event) { - case BFA_SFP_SCN_INSERTED: - aen_evt = BFA_PORT_AEN_SFP_INSERT; - break; - case BFA_SFP_SCN_REMOVED: - aen_evt = BFA_PORT_AEN_SFP_REMOVE; - break; - case BFA_SFP_SCN_FAILED: - aen_evt = BFA_PORT_AEN_SFP_ACCESS_ERROR; - break; - case BFA_SFP_SCN_UNSUPPORT: - aen_evt = BFA_PORT_AEN_SFP_UNSUPPORT; - break; - case BFA_SFP_SCN_POM: - aen_evt = BFA_PORT_AEN_SFP_POM; - aen_entry->aen_data.port.level = rsp->pomlvl; - break; - default: - bfa_trc(sfp, rsp->event); - WARN_ON(1); - } - - /* Send the AEN notification */ - bfad_im_post_vendor_event(aen_entry, bfad, ++sfp->ioc->ioc_aen_seq, - BFA_AEN_CAT_PORT, aen_evt); -} - -/* - * SFP get data send - */ -static void -bfa_sfp_getdata_send(struct bfa_sfp_s *sfp) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - bfa_trc(sfp, req->memtype); - - /* build host command */ - bfi_h2i_set(req->mh, BFI_MC_SFP, BFI_SFP_H2I_SHOW, - bfa_ioc_portid(sfp->ioc)); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(sfp->ioc, &sfp->mbcmd); -} - -/* - * SFP is valid, read sfp data - */ -static void -bfa_sfp_getdata(struct bfa_sfp_s *sfp, enum bfi_sfp_mem_e memtype) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - WARN_ON(sfp->lock != 0); - bfa_trc(sfp, sfp->state); - - sfp->lock = 1; - sfp->memtype = memtype; - req->memtype = memtype; - - /* Setup SG list */ - bfa_alen_set(&req->alen, sizeof(struct sfp_mem_s), sfp->dbuf_pa); - - bfa_sfp_getdata_send(sfp); -} - -/* - * SFP scn handler - */ -static void -bfa_sfp_scn(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg) -{ - struct bfi_sfp_scn_s *rsp = (struct bfi_sfp_scn_s *) msg; - - switch (rsp->event) { - case BFA_SFP_SCN_INSERTED: - sfp->state = BFA_SFP_STATE_INSERTED; - sfp->data_valid = 0; - bfa_sfp_scn_aen_post(sfp, rsp); - break; - case BFA_SFP_SCN_REMOVED: - sfp->state = BFA_SFP_STATE_REMOVED; - sfp->data_valid = 0; - bfa_sfp_scn_aen_post(sfp, rsp); - break; - case BFA_SFP_SCN_FAILED: - sfp->state = BFA_SFP_STATE_FAILED; - sfp->data_valid = 0; - bfa_sfp_scn_aen_post(sfp, rsp); - break; - case BFA_SFP_SCN_UNSUPPORT: - sfp->state = BFA_SFP_STATE_UNSUPPORT; - bfa_sfp_scn_aen_post(sfp, rsp); - if (!sfp->lock) - bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL); - break; - case BFA_SFP_SCN_POM: - bfa_sfp_scn_aen_post(sfp, rsp); - break; - case BFA_SFP_SCN_VALID: - sfp->state = BFA_SFP_STATE_VALID; - if (!sfp->lock) - bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL); - break; - default: - bfa_trc(sfp, rsp->event); - WARN_ON(1); - } -} - -/* - * SFP show complete - */ -static void -bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg) -{ - struct bfi_sfp_rsp_s *rsp = (struct bfi_sfp_rsp_s *) msg; - - if (!sfp->lock) { - /* - * receiving response after ioc failure - */ - bfa_trc(sfp, sfp->lock); - return; - } - - bfa_trc(sfp, rsp->status); - if (rsp->status == BFA_STATUS_OK) { - sfp->data_valid = 1; - if (sfp->state == BFA_SFP_STATE_VALID) - sfp->status = BFA_STATUS_OK; - else if (sfp->state == BFA_SFP_STATE_UNSUPPORT) - sfp->status = BFA_STATUS_SFP_UNSUPP; - else - bfa_trc(sfp, sfp->state); - } else { - sfp->data_valid = 0; - sfp->status = rsp->status; - /* sfpshow shouldn't change sfp state */ - } - - bfa_trc(sfp, sfp->memtype); - if (sfp->memtype == BFI_SFP_MEM_DIAGEXT) { - bfa_trc(sfp, sfp->data_valid); - if (sfp->data_valid) { - u32 size = sizeof(struct sfp_mem_s); - u8 *des = (u8 *) &(sfp->sfpmem->srlid_base); - memcpy(des, sfp->dbuf_kva, size); - } - /* - * Queue completion callback. - */ - bfa_cb_sfp_show(sfp); - } else - sfp->lock = 0; - - bfa_trc(sfp, sfp->state_query_lock); - if (sfp->state_query_lock) { - sfp->state = rsp->state; - /* Complete callback */ - bfa_cb_sfp_state_query(sfp); - } -} - -/* - * SFP query fw sfp state - */ -static void -bfa_sfp_state_query(struct bfa_sfp_s *sfp) -{ - struct bfi_sfp_req_s *req = (struct bfi_sfp_req_s *)sfp->mbcmd.msg; - - /* Should not be doing query if not in _INIT state */ - WARN_ON(sfp->state != BFA_SFP_STATE_INIT); - WARN_ON(sfp->state_query_lock != 0); - bfa_trc(sfp, sfp->state); - - sfp->state_query_lock = 1; - req->memtype = 0; - - if (!sfp->lock) - bfa_sfp_getdata(sfp, BFI_SFP_MEM_ALL); -} - -static void -bfa_sfp_media_get(struct bfa_sfp_s *sfp) -{ - enum bfa_defs_sfp_media_e *media = sfp->media; - - *media = BFA_SFP_MEDIA_UNKNOWN; - - if (sfp->state == BFA_SFP_STATE_UNSUPPORT) - *media = BFA_SFP_MEDIA_UNSUPPORT; - else if (sfp->state == BFA_SFP_STATE_VALID) { - union sfp_xcvr_e10g_code_u e10g; - struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva; - u16 xmtr_tech = (sfpmem->srlid_base.xcvr[4] & 0x3) << 7 | - (sfpmem->srlid_base.xcvr[5] >> 1); - - e10g.b = sfpmem->srlid_base.xcvr[0]; - bfa_trc(sfp, e10g.b); - bfa_trc(sfp, xmtr_tech); - /* check fc transmitter tech */ - if ((xmtr_tech & SFP_XMTR_TECH_CU) || - (xmtr_tech & SFP_XMTR_TECH_CP) || - (xmtr_tech & SFP_XMTR_TECH_CA)) - *media = BFA_SFP_MEDIA_CU; - else if ((xmtr_tech & SFP_XMTR_TECH_EL_INTRA) || - (xmtr_tech & SFP_XMTR_TECH_EL_INTER)) - *media = BFA_SFP_MEDIA_EL; - else if ((xmtr_tech & SFP_XMTR_TECH_LL) || - (xmtr_tech & SFP_XMTR_TECH_LC)) - *media = BFA_SFP_MEDIA_LW; - else if ((xmtr_tech & SFP_XMTR_TECH_SL) || - (xmtr_tech & SFP_XMTR_TECH_SN) || - (xmtr_tech & SFP_XMTR_TECH_SA)) - *media = BFA_SFP_MEDIA_SW; - /* Check 10G Ethernet Compilance code */ - else if (e10g.r.e10g_sr) - *media = BFA_SFP_MEDIA_SW; - else if (e10g.r.e10g_lrm && e10g.r.e10g_lr) - *media = BFA_SFP_MEDIA_LW; - else if (e10g.r.e10g_unall) - *media = BFA_SFP_MEDIA_UNKNOWN; - else - bfa_trc(sfp, 0); - } else - bfa_trc(sfp, sfp->state); -} - -static bfa_status_t -bfa_sfp_speed_valid(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed) -{ - struct sfp_mem_s *sfpmem = (struct sfp_mem_s *)sfp->dbuf_kva; - struct sfp_xcvr_s *xcvr = (struct sfp_xcvr_s *) sfpmem->srlid_base.xcvr; - union sfp_xcvr_fc3_code_u fc3 = xcvr->fc3; - union sfp_xcvr_e10g_code_u e10g = xcvr->e10g; - - if (portspeed == BFA_PORT_SPEED_10GBPS) { - if (e10g.r.e10g_sr || e10g.r.e10g_lr) - return BFA_STATUS_OK; - else { - bfa_trc(sfp, e10g.b); - return BFA_STATUS_UNSUPP_SPEED; - } - } - if (((portspeed & BFA_PORT_SPEED_16GBPS) && fc3.r.mb1600) || - ((portspeed & BFA_PORT_SPEED_8GBPS) && fc3.r.mb800) || - ((portspeed & BFA_PORT_SPEED_4GBPS) && fc3.r.mb400) || - ((portspeed & BFA_PORT_SPEED_2GBPS) && fc3.r.mb200) || - ((portspeed & BFA_PORT_SPEED_1GBPS) && fc3.r.mb100)) - return BFA_STATUS_OK; - else { - bfa_trc(sfp, portspeed); - bfa_trc(sfp, fc3.b); - bfa_trc(sfp, e10g.b); - return BFA_STATUS_UNSUPP_SPEED; - } -} - -/* - * SFP hmbox handler - */ -void -bfa_sfp_intr(void *sfparg, struct bfi_mbmsg_s *msg) -{ - struct bfa_sfp_s *sfp = sfparg; - - switch (msg->mh.msg_id) { - case BFI_SFP_I2H_SHOW: - bfa_sfp_show_comp(sfp, msg); - break; - - case BFI_SFP_I2H_SCN: - bfa_sfp_scn(sfp, msg); - break; - - default: - bfa_trc(sfp, msg->mh.msg_id); - WARN_ON(1); - } -} - -/* - * Return DMA memory needed by sfp module. - */ -u32 -bfa_sfp_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); -} - -/* - * Attach virtual and physical memory for SFP. - */ -void -bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod) -{ - sfp->dev = dev; - sfp->ioc = ioc; - sfp->trcmod = trcmod; - - sfp->cbfn = NULL; - sfp->cbarg = NULL; - sfp->sfpmem = NULL; - sfp->lock = 0; - sfp->data_valid = 0; - sfp->state = BFA_SFP_STATE_INIT; - sfp->state_query_lock = 0; - sfp->state_query_cbfn = NULL; - sfp->state_query_cbarg = NULL; - sfp->media = NULL; - sfp->portspeed = BFA_PORT_SPEED_UNKNOWN; - sfp->is_elb = BFA_FALSE; - - bfa_ioc_mbox_regisr(sfp->ioc, BFI_MC_SFP, bfa_sfp_intr, sfp); - bfa_q_qe_init(&sfp->ioc_notify); - bfa_ioc_notify_init(&sfp->ioc_notify, bfa_sfp_notify, sfp); - list_add_tail(&sfp->ioc_notify.qe, &sfp->ioc->notify_q); -} - -/* - * Claim Memory for SFP - */ -void -bfa_sfp_memclaim(struct bfa_sfp_s *sfp, u8 *dm_kva, u64 dm_pa) -{ - sfp->dbuf_kva = dm_kva; - sfp->dbuf_pa = dm_pa; - memset(sfp->dbuf_kva, 0, sizeof(struct sfp_mem_s)); - - dm_kva += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(sizeof(struct sfp_mem_s), BFA_DMA_ALIGN_SZ); -} - -/* - * Show SFP eeprom content - * - * @param[in] sfp - bfa sfp module - * - * @param[out] sfpmem - sfp eeprom data - * - */ -bfa_status_t -bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - - if (!bfa_ioc_is_operational(sfp->ioc)) { - bfa_trc(sfp, 0); - return BFA_STATUS_IOC_NON_OP; - } - - if (sfp->lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } - - sfp->cbfn = cbfn; - sfp->cbarg = cbarg; - sfp->sfpmem = sfpmem; - - bfa_sfp_getdata(sfp, BFI_SFP_MEM_DIAGEXT); - return BFA_STATUS_OK; -} - -/* - * Return SFP Media type - * - * @param[in] sfp - bfa sfp module - * - * @param[out] media - port speed from user - * - */ -bfa_status_t -bfa_sfp_media(struct bfa_sfp_s *sfp, enum bfa_defs_sfp_media_e *media, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - if (!bfa_ioc_is_operational(sfp->ioc)) { - bfa_trc(sfp, 0); - return BFA_STATUS_IOC_NON_OP; - } - - sfp->media = media; - if (sfp->state == BFA_SFP_STATE_INIT) { - if (sfp->state_query_lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } else { - sfp->state_query_cbfn = cbfn; - sfp->state_query_cbarg = cbarg; - bfa_sfp_state_query(sfp); - return BFA_STATUS_SFP_NOT_READY; - } - } - - bfa_sfp_media_get(sfp); - return BFA_STATUS_OK; -} - -/* - * Check if user set port speed is allowed by the SFP - * - * @param[in] sfp - bfa sfp module - * @param[in] portspeed - port speed from user - * - */ -bfa_status_t -bfa_sfp_speed(struct bfa_sfp_s *sfp, enum bfa_port_speed portspeed, - bfa_cb_sfp_t cbfn, void *cbarg) -{ - WARN_ON(portspeed == BFA_PORT_SPEED_UNKNOWN); - - if (!bfa_ioc_is_operational(sfp->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* For Mezz card, all speed is allowed */ - if (bfa_mfg_is_mezz(sfp->ioc->attr->card_type)) - return BFA_STATUS_OK; - - /* Check SFP state */ - sfp->portspeed = portspeed; - if (sfp->state == BFA_SFP_STATE_INIT) { - if (sfp->state_query_lock) { - bfa_trc(sfp, 0); - return BFA_STATUS_DEVBUSY; - } else { - sfp->state_query_cbfn = cbfn; - sfp->state_query_cbarg = cbarg; - bfa_sfp_state_query(sfp); - return BFA_STATUS_SFP_NOT_READY; - } - } - - if (sfp->state == BFA_SFP_STATE_REMOVED || - sfp->state == BFA_SFP_STATE_FAILED) { - bfa_trc(sfp, sfp->state); - return BFA_STATUS_NO_SFP_DEV; - } - - if (sfp->state == BFA_SFP_STATE_INSERTED) { - bfa_trc(sfp, sfp->state); - return BFA_STATUS_DEVBUSY; /* sfp is reading data */ - } - - /* For eloopback, all speed is allowed */ - if (sfp->is_elb) - return BFA_STATUS_OK; - - return bfa_sfp_speed_valid(sfp, portspeed); -} - -/* - * Flash module specific - */ - -/* - * FLASH DMA buffer should be big enough to hold both MFG block and - * asic block(64k) at the same time and also should be 2k aligned to - * avoid write segement to cross sector boundary. - */ -#define BFA_FLASH_SEG_SZ 2048 -#define BFA_FLASH_DMA_BUF_SZ \ - BFA_ROUNDUP(0x010000 + sizeof(struct bfa_mfg_block_s), BFA_FLASH_SEG_SZ) - -static void -bfa_flash_aen_audit_post(struct bfa_ioc_s *ioc, enum bfa_audit_aen_event event, - int inst, int type) -{ - struct bfad_s *bfad = (struct bfad_s *)ioc->bfa->bfad; - struct bfa_aen_entry_s *aen_entry; - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - aen_entry->aen_data.audit.pwwn = ioc->attr->pwwn; - aen_entry->aen_data.audit.partition_inst = inst; - aen_entry->aen_data.audit.partition_type = type; - - /* Send the AEN notification */ - bfad_im_post_vendor_event(aen_entry, bfad, ++ioc->ioc_aen_seq, - BFA_AEN_CAT_AUDIT, event); -} - -static void -bfa_flash_cb(struct bfa_flash_s *flash) -{ - flash->op_busy = 0; - if (flash->cbfn) - flash->cbfn(flash->cbarg, flash->status); -} - -static void -bfa_flash_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_flash_s *flash = cbarg; - - bfa_trc(flash, event); - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (flash->op_busy) { - flash->status = BFA_STATUS_IOC_FAILURE; - flash->cbfn(flash->cbarg, flash->status); - flash->op_busy = 0; - } - break; - - default: - break; - } -} - -/* - * Send flash attribute query request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_query_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_query_req_s *msg = - (struct bfi_flash_query_req_s *) flash->mb.msg; - - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_QUERY_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_flash_attr_s), - flash->dbuf_pa); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Send flash write request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_write_send(struct bfa_flash_s *flash) -{ - struct bfi_flash_write_req_s *msg = - (struct bfi_flash_write_req_s *) flash->mb.msg; - u32 len; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - msg->offset = be32_to_cpu(flash->addr_off + flash->offset); - len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ? - flash->residue : BFA_FLASH_DMA_BUF_SZ; - msg->length = be32_to_cpu(len); - - /* indicate if it's the last msg of the whole write operation */ - msg->last = (len == flash->residue) ? 1 : 0; - - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_WRITE_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, len, flash->dbuf_pa); - memcpy(flash->dbuf_kva, flash->ubuf + flash->offset, len); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); - - flash->residue -= len; - flash->offset += len; -} - -/* - * Send flash read request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_read_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_read_req_s *msg = - (struct bfi_flash_read_req_s *) flash->mb.msg; - u32 len; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - msg->offset = be32_to_cpu(flash->addr_off + flash->offset); - len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ? - flash->residue : BFA_FLASH_DMA_BUF_SZ; - msg->length = be32_to_cpu(len); - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_READ_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_alen_set(&msg->alen, len, flash->dbuf_pa); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Send flash erase request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_flash_erase_send(void *cbarg) -{ - struct bfa_flash_s *flash = cbarg; - struct bfi_flash_erase_req_s *msg = - (struct bfi_flash_erase_req_s *) flash->mb.msg; - - msg->type = be32_to_cpu(flash->type); - msg->instance = flash->instance; - bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_ERASE_REQ, - bfa_ioc_portid(flash->ioc)); - bfa_ioc_mbox_queue(flash->ioc, &flash->mb); -} - -/* - * Process flash response messages upon receiving interrupts. - * - * @param[in] flasharg - flash structure - * @param[in] msg - message structure - */ -static void -bfa_flash_intr(void *flasharg, struct bfi_mbmsg_s *msg) -{ - struct bfa_flash_s *flash = flasharg; - u32 status; - - union { - struct bfi_flash_query_rsp_s *query; - struct bfi_flash_erase_rsp_s *erase; - struct bfi_flash_write_rsp_s *write; - struct bfi_flash_read_rsp_s *read; - struct bfi_flash_event_s *event; - struct bfi_mbmsg_s *msg; - } m; - - m.msg = msg; - bfa_trc(flash, msg->mh.msg_id); - - if (!flash->op_busy && msg->mh.msg_id != BFI_FLASH_I2H_EVENT) { - /* receiving response after ioc failure */ - bfa_trc(flash, 0x9999); - return; - } - - switch (msg->mh.msg_id) { - case BFI_FLASH_I2H_QUERY_RSP: - status = be32_to_cpu(m.query->status); - bfa_trc(flash, status); - if (status == BFA_STATUS_OK) { - u32 i; - struct bfa_flash_attr_s *attr, *f; - - attr = (struct bfa_flash_attr_s *) flash->ubuf; - f = (struct bfa_flash_attr_s *) flash->dbuf_kva; - attr->status = be32_to_cpu(f->status); - attr->npart = be32_to_cpu(f->npart); - bfa_trc(flash, attr->status); - bfa_trc(flash, attr->npart); - for (i = 0; i < attr->npart; i++) { - attr->part[i].part_type = - be32_to_cpu(f->part[i].part_type); - attr->part[i].part_instance = - be32_to_cpu(f->part[i].part_instance); - attr->part[i].part_off = - be32_to_cpu(f->part[i].part_off); - attr->part[i].part_size = - be32_to_cpu(f->part[i].part_size); - attr->part[i].part_len = - be32_to_cpu(f->part[i].part_len); - attr->part[i].part_status = - be32_to_cpu(f->part[i].part_status); - } - } - flash->status = status; - bfa_flash_cb(flash); - break; - case BFI_FLASH_I2H_ERASE_RSP: - status = be32_to_cpu(m.erase->status); - bfa_trc(flash, status); - flash->status = status; - bfa_flash_cb(flash); - break; - case BFI_FLASH_I2H_WRITE_RSP: - status = be32_to_cpu(m.write->status); - bfa_trc(flash, status); - if (status != BFA_STATUS_OK || flash->residue == 0) { - flash->status = status; - bfa_flash_cb(flash); - } else { - bfa_trc(flash, flash->offset); - bfa_flash_write_send(flash); - } - break; - case BFI_FLASH_I2H_READ_RSP: - status = be32_to_cpu(m.read->status); - bfa_trc(flash, status); - if (status != BFA_STATUS_OK) { - flash->status = status; - bfa_flash_cb(flash); - } else { - u32 len = be32_to_cpu(m.read->length); - bfa_trc(flash, flash->offset); - bfa_trc(flash, len); - memcpy(flash->ubuf + flash->offset, - flash->dbuf_kva, len); - flash->residue -= len; - flash->offset += len; - if (flash->residue == 0) { - flash->status = status; - bfa_flash_cb(flash); - } else - bfa_flash_read_send(flash); - } - break; - case BFI_FLASH_I2H_BOOT_VER_RSP: - break; - case BFI_FLASH_I2H_EVENT: - status = be32_to_cpu(m.event->status); - bfa_trc(flash, status); - if (status == BFA_STATUS_BAD_FWCFG) - bfa_ioc_aen_post(flash->ioc, BFA_IOC_AEN_FWCFG_ERROR); - else if (status == BFA_STATUS_INVALID_VENDOR) { - u32 param; - param = be32_to_cpu(m.event->param); - bfa_trc(flash, param); - bfa_ioc_aen_post(flash->ioc, - BFA_IOC_AEN_INVALID_VENDOR); - } - break; - - default: - WARN_ON(1); - } -} - -/* - * Flash memory info API. - * - * @param[in] mincfg - minimal cfg variable - */ -u32 -bfa_flash_meminfo(bfa_boolean_t mincfg) -{ - /* min driver doesn't need flash */ - if (mincfg) - return 0; - return BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Flash attach API. - * - * @param[in] flash - flash structure - * @param[in] ioc - ioc structure - * @param[in] dev - device structure - * @param[in] trcmod - trace module - * @param[in] logmod - log module - */ -void -bfa_flash_attach(struct bfa_flash_s *flash, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg) -{ - flash->ioc = ioc; - flash->trcmod = trcmod; - flash->cbfn = NULL; - flash->cbarg = NULL; - flash->op_busy = 0; - - bfa_ioc_mbox_regisr(flash->ioc, BFI_MC_FLASH, bfa_flash_intr, flash); - bfa_q_qe_init(&flash->ioc_notify); - bfa_ioc_notify_init(&flash->ioc_notify, bfa_flash_notify, flash); - list_add_tail(&flash->ioc_notify.qe, &flash->ioc->notify_q); - - /* min driver doesn't need flash */ - if (mincfg) { - flash->dbuf_kva = NULL; - flash->dbuf_pa = 0; - } -} - -/* - * Claim memory for flash - * - * @param[in] flash - flash structure - * @param[in] dm_kva - pointer to virtual memory address - * @param[in] dm_pa - physical memory address - * @param[in] mincfg - minimal cfg variable - */ -void -bfa_flash_memclaim(struct bfa_flash_s *flash, u8 *dm_kva, u64 dm_pa, - bfa_boolean_t mincfg) -{ - if (mincfg) - return; - - flash->dbuf_kva = dm_kva; - flash->dbuf_pa = dm_pa; - memset(flash->dbuf_kva, 0, BFA_FLASH_DMA_BUF_SZ); - dm_kva += BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Get flash attribute. - * - * @param[in] flash - flash structure - * @param[in] attr - flash attribute structure - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_get_attr(struct bfa_flash_s *flash, struct bfa_flash_attr_s *attr, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_QUERY_REQ); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->ubuf = (u8 *) attr; - bfa_flash_query_send(flash); - - return BFA_STATUS_OK; -} - -/* - * Erase flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_erase_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_ERASE_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - - bfa_flash_erase_send(flash); - bfa_flash_aen_audit_post(flash->ioc, BFA_AUDIT_AEN_FLASH_ERASE, - instance, type); - return BFA_STATUS_OK; -} - -/* - * Update flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] buf - update data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to the partition starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_update_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_WRITE_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - bfa_trc(flash, len); - bfa_trc(flash, offset); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* - * 'len' must be in word (4-byte) boundary - * 'offset' must be in sector (16kb) boundary - */ - if (!len || (len & 0x03) || (offset & 0x00003FFF)) - return BFA_STATUS_FLASH_BAD_LEN; - - if (type == BFA_FLASH_PART_MFG) - return BFA_STATUS_EINVAL; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - flash->residue = len; - flash->offset = 0; - flash->addr_off = offset; - flash->ubuf = buf; - - bfa_flash_write_send(flash); - return BFA_STATUS_OK; -} - -/* - * Read flash partition. - * - * @param[in] flash - flash structure - * @param[in] type - flash partition type - * @param[in] instance - flash partition instance - * @param[in] buf - read data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to the partition starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_flash_read_part(struct bfa_flash_s *flash, enum bfa_flash_part_type type, - u8 instance, void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg) -{ - bfa_trc(flash, BFI_FLASH_H2I_READ_REQ); - bfa_trc(flash, type); - bfa_trc(flash, instance); - bfa_trc(flash, len); - bfa_trc(flash, offset); - - if (!bfa_ioc_is_operational(flash->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* - * 'len' must be in word (4-byte) boundary - * 'offset' must be in sector (16kb) boundary - */ - if (!len || (len & 0x03) || (offset & 0x00003FFF)) - return BFA_STATUS_FLASH_BAD_LEN; - - if (flash->op_busy) { - bfa_trc(flash, flash->op_busy); - return BFA_STATUS_DEVBUSY; - } - - flash->op_busy = 1; - flash->cbfn = cbfn; - flash->cbarg = cbarg; - flash->type = type; - flash->instance = instance; - flash->residue = len; - flash->offset = 0; - flash->addr_off = offset; - flash->ubuf = buf; - bfa_flash_read_send(flash); - - return BFA_STATUS_OK; -} - -/* - * DIAG module specific - */ - -#define BFA_DIAG_MEMTEST_TOV 50000 /* memtest timeout in msec */ -#define CT2_BFA_DIAG_MEMTEST_TOV (9*30*1000) /* 4.5 min */ - -/* IOC event handler */ -static void -bfa_diag_notify(void *diag_arg, enum bfa_ioc_event_e event) -{ - struct bfa_diag_s *diag = diag_arg; - - bfa_trc(diag, event); - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->fwping.lock); - bfa_trc(diag, diag->tsensor.lock); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (diag->fwping.lock) { - diag->fwping.status = BFA_STATUS_IOC_FAILURE; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - } - - if (diag->tsensor.lock) { - diag->tsensor.status = BFA_STATUS_IOC_FAILURE; - diag->tsensor.cbfn(diag->tsensor.cbarg, - diag->tsensor.status); - diag->tsensor.lock = 0; - } - - if (diag->block) { - if (diag->timer_active) { - bfa_timer_stop(&diag->timer); - diag->timer_active = 0; - } - - diag->status = BFA_STATUS_IOC_FAILURE; - diag->cbfn(diag->cbarg, diag->status); - diag->block = 0; - } - break; - - default: - break; - } -} - -static void -bfa_diag_memtest_done(void *cbarg) -{ - struct bfa_diag_s *diag = cbarg; - struct bfa_ioc_s *ioc = diag->ioc; - struct bfa_diag_memtest_result *res = diag->result; - u32 loff = BFI_BOOT_MEMTEST_RES_ADDR; - u32 pgnum, pgoff, i; - - pgnum = PSS_SMEM_PGNUM(ioc->ioc_regs.smem_pg0, loff); - pgoff = PSS_SMEM_PGOFF(loff); - - writel(pgnum, ioc->ioc_regs.host_page_num_fn); - - for (i = 0; i < (sizeof(struct bfa_diag_memtest_result) / - sizeof(u32)); i++) { - /* read test result from smem */ - *((u32 *) res + i) = - bfa_mem_read(ioc->ioc_regs.smem_page_start, loff); - loff += sizeof(u32); - } - - /* Reset IOC fwstates to BFI_IOC_UNINIT */ - bfa_ioc_reset_fwstate(ioc); - - res->status = swab32(res->status); - bfa_trc(diag, res->status); - - if (res->status == BFI_BOOT_MEMTEST_RES_SIG) - diag->status = BFA_STATUS_OK; - else { - diag->status = BFA_STATUS_MEMTEST_FAILED; - res->addr = swab32(res->addr); - res->exp = swab32(res->exp); - res->act = swab32(res->act); - res->err_status = swab32(res->err_status); - res->err_status1 = swab32(res->err_status1); - res->err_addr = swab32(res->err_addr); - bfa_trc(diag, res->addr); - bfa_trc(diag, res->exp); - bfa_trc(diag, res->act); - bfa_trc(diag, res->err_status); - bfa_trc(diag, res->err_status1); - bfa_trc(diag, res->err_addr); - } - diag->timer_active = 0; - diag->cbfn(diag->cbarg, diag->status); - diag->block = 0; -} - -/* - * Firmware ping - */ - -/* - * Perform DMA test directly - */ -static void -diag_fwping_send(struct bfa_diag_s *diag) -{ - struct bfi_diag_fwping_req_s *fwping_req; - u32 i; - - bfa_trc(diag, diag->fwping.dbuf_pa); - - /* fill DMA area with pattern */ - for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++) - *((u32 *)diag->fwping.dbuf_kva + i) = diag->fwping.data; - - /* Fill mbox msg */ - fwping_req = (struct bfi_diag_fwping_req_s *)diag->fwping.mbcmd.msg; - - /* Setup SG list */ - bfa_alen_set(&fwping_req->alen, BFI_DIAG_DMA_BUF_SZ, - diag->fwping.dbuf_pa); - /* Set up dma count */ - fwping_req->count = cpu_to_be32(diag->fwping.count); - /* Set up data pattern */ - fwping_req->data = diag->fwping.data; - - /* build host command */ - bfi_h2i_set(fwping_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_FWPING, - bfa_ioc_portid(diag->ioc)); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->fwping.mbcmd); -} - -static void -diag_fwping_comp(struct bfa_diag_s *diag, - struct bfi_diag_fwping_rsp_s *diag_rsp) -{ - u32 rsp_data = diag_rsp->data; - u8 rsp_dma_status = diag_rsp->dma_status; - - bfa_trc(diag, rsp_data); - bfa_trc(diag, rsp_dma_status); - - if (rsp_dma_status == BFA_STATUS_OK) { - u32 i, pat; - pat = (diag->fwping.count & 0x1) ? ~(diag->fwping.data) : - diag->fwping.data; - /* Check mbox data */ - if (diag->fwping.data != rsp_data) { - bfa_trc(diag, rsp_data); - diag->fwping.result->dmastatus = - BFA_STATUS_DATACORRUPTED; - diag->fwping.status = BFA_STATUS_DATACORRUPTED; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - return; - } - /* Check dma pattern */ - for (i = 0; i < (BFI_DIAG_DMA_BUF_SZ >> 2); i++) { - if (*((u32 *)diag->fwping.dbuf_kva + i) != pat) { - bfa_trc(diag, i); - bfa_trc(diag, pat); - bfa_trc(diag, - *((u32 *)diag->fwping.dbuf_kva + i)); - diag->fwping.result->dmastatus = - BFA_STATUS_DATACORRUPTED; - diag->fwping.status = BFA_STATUS_DATACORRUPTED; - diag->fwping.cbfn(diag->fwping.cbarg, - diag->fwping.status); - diag->fwping.lock = 0; - return; - } - } - diag->fwping.result->dmastatus = BFA_STATUS_OK; - diag->fwping.status = BFA_STATUS_OK; - diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status); - diag->fwping.lock = 0; - } else { - diag->fwping.status = BFA_STATUS_HDMA_FAILED; - diag->fwping.cbfn(diag->fwping.cbarg, diag->fwping.status); - diag->fwping.lock = 0; - } -} - -/* - * Temperature Sensor - */ - -static void -diag_tempsensor_send(struct bfa_diag_s *diag) -{ - struct bfi_diag_ts_req_s *msg; - - msg = (struct bfi_diag_ts_req_s *)diag->tsensor.mbcmd.msg; - bfa_trc(diag, msg->temp); - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_TEMPSENSOR, - bfa_ioc_portid(diag->ioc)); - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->tsensor.mbcmd); -} - -static void -diag_tempsensor_comp(struct bfa_diag_s *diag, bfi_diag_ts_rsp_t *rsp) -{ - if (!diag->tsensor.lock) { - /* receiving response after ioc failure */ - bfa_trc(diag, diag->tsensor.lock); - return; - } - - /* - * ASIC junction tempsensor is a reg read operation - * it will always return OK - */ - diag->tsensor.temp->temp = be16_to_cpu(rsp->temp); - diag->tsensor.temp->ts_junc = rsp->ts_junc; - diag->tsensor.temp->ts_brd = rsp->ts_brd; - diag->tsensor.temp->status = BFA_STATUS_OK; - - if (rsp->ts_brd) { - if (rsp->status == BFA_STATUS_OK) { - diag->tsensor.temp->brd_temp = - be16_to_cpu(rsp->brd_temp); - } else { - bfa_trc(diag, rsp->status); - diag->tsensor.temp->brd_temp = 0; - diag->tsensor.temp->status = BFA_STATUS_DEVBUSY; - } - } - bfa_trc(diag, rsp->ts_junc); - bfa_trc(diag, rsp->temp); - bfa_trc(diag, rsp->ts_brd); - bfa_trc(diag, rsp->brd_temp); - diag->tsensor.cbfn(diag->tsensor.cbarg, diag->tsensor.status); - diag->tsensor.lock = 0; -} - -/* - * LED Test command - */ -static void -diag_ledtest_send(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest) -{ - struct bfi_diag_ledtest_req_s *msg; - - msg = (struct bfi_diag_ledtest_req_s *)diag->ledtest.mbcmd.msg; - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LEDTEST, - bfa_ioc_portid(diag->ioc)); - - /* - * convert the freq from N blinks per 10 sec to - * crossbow ontime value. We do it here because division is need - */ - if (ledtest->freq) - ledtest->freq = 500 / ledtest->freq; - - if (ledtest->freq == 0) - ledtest->freq = 1; - - bfa_trc(diag, ledtest->freq); - /* mcpy(&ledtest_req->req, ledtest, sizeof(bfa_diag_ledtest_t)); */ - msg->cmd = (u8) ledtest->cmd; - msg->color = (u8) ledtest->color; - msg->portid = bfa_ioc_portid(diag->ioc); - msg->led = ledtest->led; - msg->freq = cpu_to_be16(ledtest->freq); - - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->ledtest.mbcmd); -} - -static void -diag_ledtest_comp(struct bfa_diag_s *diag, struct bfi_diag_ledtest_rsp_s *msg) -{ - bfa_trc(diag, diag->ledtest.lock); - diag->ledtest.lock = BFA_FALSE; - /* no bfa_cb_queue is needed because driver is not waiting */ -} - -/* - * Port beaconing - */ -static void -diag_portbeacon_send(struct bfa_diag_s *diag, bfa_boolean_t beacon, u32 sec) -{ - struct bfi_diag_portbeacon_req_s *msg; - - msg = (struct bfi_diag_portbeacon_req_s *)diag->beacon.mbcmd.msg; - /* build host command */ - bfi_h2i_set(msg->mh, BFI_MC_DIAG, BFI_DIAG_H2I_PORTBEACON, - bfa_ioc_portid(diag->ioc)); - msg->beacon = beacon; - msg->period = cpu_to_be32(sec); - /* send mbox cmd */ - bfa_ioc_mbox_queue(diag->ioc, &diag->beacon.mbcmd); -} - -static void -diag_portbeacon_comp(struct bfa_diag_s *diag) -{ - bfa_trc(diag, diag->beacon.state); - diag->beacon.state = BFA_FALSE; - if (diag->cbfn_beacon) - diag->cbfn_beacon(diag->dev, BFA_FALSE, diag->beacon.link_e2e); -} - -/* - * Diag hmbox handler - */ -void -bfa_diag_intr(void *diagarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_diag_s *diag = diagarg; - - switch (msg->mh.msg_id) { - case BFI_DIAG_I2H_PORTBEACON: - diag_portbeacon_comp(diag); - break; - case BFI_DIAG_I2H_FWPING: - diag_fwping_comp(diag, (struct bfi_diag_fwping_rsp_s *) msg); - break; - case BFI_DIAG_I2H_TEMPSENSOR: - diag_tempsensor_comp(diag, (bfi_diag_ts_rsp_t *) msg); - break; - case BFI_DIAG_I2H_LEDTEST: - diag_ledtest_comp(diag, (struct bfi_diag_ledtest_rsp_s *) msg); - break; - default: - bfa_trc(diag, msg->mh.msg_id); - WARN_ON(1); - } -} - -/* - * Gen RAM Test - * - * @param[in] *diag - diag data struct - * @param[in] *memtest - mem test params input from upper layer, - * @param[in] pattern - mem test pattern - * @param[in] *result - mem test result - * @param[in] cbfn - mem test callback functioin - * @param[in] cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_memtest(struct bfa_diag_s *diag, struct bfa_diag_memtest_s *memtest, - u32 pattern, struct bfa_diag_memtest_result *result, - bfa_cb_diag_t cbfn, void *cbarg) -{ - u32 memtest_tov; - - bfa_trc(diag, pattern); - - if (!bfa_ioc_adapter_is_disabled(diag->ioc)) - return BFA_STATUS_ADAPTER_ENABLED; - - /* check to see if there is another destructive diag cmd running */ - if (diag->block) { - bfa_trc(diag, diag->block); - return BFA_STATUS_DEVBUSY; - } else - diag->block = 1; - - diag->result = result; - diag->cbfn = cbfn; - diag->cbarg = cbarg; - - /* download memtest code and take LPU0 out of reset */ - bfa_ioc_boot(diag->ioc, BFI_FWBOOT_TYPE_MEMTEST, BFI_FWBOOT_ENV_OS); - - memtest_tov = (bfa_ioc_asic_gen(diag->ioc) == BFI_ASIC_GEN_CT2) ? - CT2_BFA_DIAG_MEMTEST_TOV : BFA_DIAG_MEMTEST_TOV; - bfa_timer_begin(diag->ioc->timer_mod, &diag->timer, - bfa_diag_memtest_done, diag, memtest_tov); - diag->timer_active = 1; - return BFA_STATUS_OK; -} - -/* - * DIAG firmware ping command - * - * @param[in] *diag - diag data struct - * @param[in] cnt - dma loop count for testing PCIE - * @param[in] data - data pattern to pass in fw - * @param[in] *result - pt to bfa_diag_fwping_result_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt, u32 data, - struct bfa_diag_results_fwping *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - bfa_trc(diag, cnt); - bfa_trc(diag, data); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (bfa_asic_id_ct2(bfa_ioc_devid((diag->ioc))) && - ((diag->ioc)->clscode == BFI_PCIFN_CLASS_ETH)) - return BFA_STATUS_CMD_NOTSUPP; - - /* check to see if there is another destructive diag cmd running */ - if (diag->block || diag->fwping.lock) { - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->fwping.lock); - return BFA_STATUS_DEVBUSY; - } - - /* Initialization */ - diag->fwping.lock = 1; - diag->fwping.cbfn = cbfn; - diag->fwping.cbarg = cbarg; - diag->fwping.result = result; - diag->fwping.data = data; - diag->fwping.count = cnt; - - /* Init test results */ - diag->fwping.result->data = 0; - diag->fwping.result->status = BFA_STATUS_OK; - - /* kick off the first ping */ - diag_fwping_send(diag); - return BFA_STATUS_OK; -} - -/* - * Read Temperature Sensor - * - * @param[in] *diag - diag data struct - * @param[in] *result - pt to bfa_diag_temp_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_diag_tsensor_query(struct bfa_diag_s *diag, - struct bfa_diag_results_tempsensor_s *result, - bfa_cb_diag_t cbfn, void *cbarg) -{ - /* check to see if there is a destructive diag cmd running */ - if (diag->block || diag->tsensor.lock) { - bfa_trc(diag, diag->block); - bfa_trc(diag, diag->tsensor.lock); - return BFA_STATUS_DEVBUSY; - } - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* Init diag mod params */ - diag->tsensor.lock = 1; - diag->tsensor.temp = result; - diag->tsensor.cbfn = cbfn; - diag->tsensor.cbarg = cbarg; - - /* Send msg to fw */ - diag_tempsensor_send(diag); - - return BFA_STATUS_OK; -} - -/* - * LED Test command - * - * @param[in] *diag - diag data struct - * @param[in] *ledtest - pt to ledtest data structure - * - * @param[out] - */ -bfa_status_t -bfa_diag_ledtest(struct bfa_diag_s *diag, struct bfa_diag_ledtest_s *ledtest) -{ - bfa_trc(diag, ledtest->cmd); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (diag->beacon.state) - return BFA_STATUS_BEACON_ON; - - if (diag->ledtest.lock) - return BFA_STATUS_LEDTEST_OP; - - /* Send msg to fw */ - diag->ledtest.lock = BFA_TRUE; - diag_ledtest_send(diag, ledtest); - - return BFA_STATUS_OK; -} - -/* - * Port beaconing command - * - * @param[in] *diag - diag data struct - * @param[in] beacon - port beaconing 1:ON 0:OFF - * @param[in] link_e2e_beacon - link beaconing 1:ON 0:OFF - * @param[in] sec - beaconing duration in seconds - * - * @param[out] - */ -bfa_status_t -bfa_diag_beacon_port(struct bfa_diag_s *diag, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon, uint32_t sec) -{ - bfa_trc(diag, beacon); - bfa_trc(diag, link_e2e_beacon); - bfa_trc(diag, sec); - - if (!bfa_ioc_is_operational(diag->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (diag->ledtest.lock) - return BFA_STATUS_LEDTEST_OP; - - if (diag->beacon.state && beacon) /* beacon alread on */ - return BFA_STATUS_BEACON_ON; - - diag->beacon.state = beacon; - diag->beacon.link_e2e = link_e2e_beacon; - if (diag->cbfn_beacon) - diag->cbfn_beacon(diag->dev, beacon, link_e2e_beacon); - - /* Send msg to fw */ - diag_portbeacon_send(diag, beacon, sec); - - return BFA_STATUS_OK; -} - -/* - * Return DMA memory needed by diag module. - */ -u32 -bfa_diag_meminfo(void) -{ - return BFA_ROUNDUP(BFI_DIAG_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Attach virtual and physical memory for Diag. - */ -void -bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev, - bfa_cb_diag_beacon_t cbfn_beacon, struct bfa_trc_mod_s *trcmod) -{ - diag->dev = dev; - diag->ioc = ioc; - diag->trcmod = trcmod; - - diag->block = 0; - diag->cbfn = NULL; - diag->cbarg = NULL; - diag->result = NULL; - diag->cbfn_beacon = cbfn_beacon; - - bfa_ioc_mbox_regisr(diag->ioc, BFI_MC_DIAG, bfa_diag_intr, diag); - bfa_q_qe_init(&diag->ioc_notify); - bfa_ioc_notify_init(&diag->ioc_notify, bfa_diag_notify, diag); - list_add_tail(&diag->ioc_notify.qe, &diag->ioc->notify_q); -} - -void -bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa) -{ - diag->fwping.dbuf_kva = dm_kva; - diag->fwping.dbuf_pa = dm_pa; - memset(diag->fwping.dbuf_kva, 0, BFI_DIAG_DMA_BUF_SZ); -} - -/* - * PHY module specific - */ -#define BFA_PHY_DMA_BUF_SZ 0x02000 /* 8k dma buffer */ -#define BFA_PHY_LOCK_STATUS 0x018878 /* phy semaphore status reg */ - -static void -bfa_phy_ntoh32(u32 *obuf, u32 *ibuf, int sz) -{ - int i, m = sz >> 2; - - for (i = 0; i < m; i++) - obuf[i] = be32_to_cpu(ibuf[i]); -} - -static bfa_boolean_t -bfa_phy_present(struct bfa_phy_s *phy) -{ - return (phy->ioc->attr->card_type == BFA_MFG_TYPE_LIGHTNING); -} - -static void -bfa_phy_notify(void *cbarg, enum bfa_ioc_event_e event) -{ - struct bfa_phy_s *phy = cbarg; - - bfa_trc(phy, event); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (phy->op_busy) { - phy->status = BFA_STATUS_IOC_FAILURE; - phy->cbfn(phy->cbarg, phy->status); - phy->op_busy = 0; - } - break; - - default: - break; - } -} - -/* - * Send phy attribute query request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_query_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_query_req_s *msg = - (struct bfi_phy_query_req_s *) phy->mb.msg; - - msg->instance = phy->instance; - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_QUERY_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_attr_s), phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Send phy write request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_write_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_write_req_s *msg = - (struct bfi_phy_write_req_s *) phy->mb.msg; - u32 len; - u16 *buf, *dbuf; - int i, sz; - - msg->instance = phy->instance; - msg->offset = cpu_to_be32(phy->addr_off + phy->offset); - len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ? - phy->residue : BFA_PHY_DMA_BUF_SZ; - msg->length = cpu_to_be32(len); - - /* indicate if it's the last msg of the whole write operation */ - msg->last = (len == phy->residue) ? 1 : 0; - - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_WRITE_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, len, phy->dbuf_pa); - - buf = (u16 *) (phy->ubuf + phy->offset); - dbuf = (u16 *)phy->dbuf_kva; - sz = len >> 1; - for (i = 0; i < sz; i++) - buf[i] = cpu_to_be16(dbuf[i]); - - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); - - phy->residue -= len; - phy->offset += len; -} - -/* - * Send phy read request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_read_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_read_req_s *msg = - (struct bfi_phy_read_req_s *) phy->mb.msg; - u32 len; - - msg->instance = phy->instance; - msg->offset = cpu_to_be32(phy->addr_off + phy->offset); - len = (phy->residue < BFA_PHY_DMA_BUF_SZ) ? - phy->residue : BFA_PHY_DMA_BUF_SZ; - msg->length = cpu_to_be32(len); - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_READ_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, len, phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Send phy stats request. - * - * @param[in] cbarg - callback argument - */ -static void -bfa_phy_stats_send(void *cbarg) -{ - struct bfa_phy_s *phy = cbarg; - struct bfi_phy_stats_req_s *msg = - (struct bfi_phy_stats_req_s *) phy->mb.msg; - - msg->instance = phy->instance; - bfi_h2i_set(msg->mh, BFI_MC_PHY, BFI_PHY_H2I_STATS_REQ, - bfa_ioc_portid(phy->ioc)); - bfa_alen_set(&msg->alen, sizeof(struct bfa_phy_stats_s), phy->dbuf_pa); - bfa_ioc_mbox_queue(phy->ioc, &phy->mb); -} - -/* - * Flash memory info API. - * - * @param[in] mincfg - minimal cfg variable - */ -u32 -bfa_phy_meminfo(bfa_boolean_t mincfg) -{ - /* min driver doesn't need phy */ - if (mincfg) - return 0; - - return BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -/* - * Flash attach API. - * - * @param[in] phy - phy structure - * @param[in] ioc - ioc structure - * @param[in] dev - device structure - * @param[in] trcmod - trace module - * @param[in] logmod - log module - */ -void -bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc, void *dev, - struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg) -{ - phy->ioc = ioc; - phy->trcmod = trcmod; - phy->cbfn = NULL; - phy->cbarg = NULL; - phy->op_busy = 0; - - bfa_ioc_mbox_regisr(phy->ioc, BFI_MC_PHY, bfa_phy_intr, phy); - bfa_q_qe_init(&phy->ioc_notify); - bfa_ioc_notify_init(&phy->ioc_notify, bfa_phy_notify, phy); - list_add_tail(&phy->ioc_notify.qe, &phy->ioc->notify_q); - - /* min driver doesn't need phy */ - if (mincfg) { - phy->dbuf_kva = NULL; - phy->dbuf_pa = 0; - } -} - -/* - * Claim memory for phy - * - * @param[in] phy - phy structure - * @param[in] dm_kva - pointer to virtual memory address - * @param[in] dm_pa - physical memory address - * @param[in] mincfg - minimal cfg variable - */ -void -bfa_phy_memclaim(struct bfa_phy_s *phy, u8 *dm_kva, u64 dm_pa, - bfa_boolean_t mincfg) -{ - if (mincfg) - return; - - phy->dbuf_kva = dm_kva; - phy->dbuf_pa = dm_pa; - memset(phy->dbuf_kva, 0, BFA_PHY_DMA_BUF_SZ); - dm_kva += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); - dm_pa += BFA_ROUNDUP(BFA_PHY_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ); -} - -bfa_boolean_t -bfa_phy_busy(struct bfa_ioc_s *ioc) -{ - void __iomem *rb; - - rb = bfa_ioc_bar0(ioc); - return readl(rb + BFA_PHY_LOCK_STATUS); -} - -/* - * Get phy attribute. - * - * @param[in] phy - phy structure - * @param[in] attr - phy attribute structure - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_attr_s *attr, bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_QUERY_REQ); - bfa_trc(phy, instance); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->ubuf = (uint8_t *) attr; - bfa_phy_query_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Get phy stats. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] stats - pointer to phy stats - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_stats_s *stats, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_STATS_REQ); - bfa_trc(phy, instance); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->ubuf = (u8 *) stats; - bfa_phy_stats_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Update phy image. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] buf - update data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_update(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_WRITE_REQ); - bfa_trc(phy, instance); - bfa_trc(phy, len); - bfa_trc(phy, offset); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* 'len' must be in word (4-byte) boundary */ - if (!len || (len & 0x03)) - return BFA_STATUS_FAILED; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->residue = len; - phy->offset = 0; - phy->addr_off = offset; - phy->ubuf = buf; - - bfa_phy_write_send(phy); - return BFA_STATUS_OK; -} - -/* - * Read phy image. - * - * @param[in] phy - phy structure - * @param[in] instance - phy image instance - * @param[in] buf - read data buffer - * @param[in] len - data buffer length - * @param[in] offset - offset relative to starting address - * @param[in] cbfn - callback function - * @param[in] cbarg - callback argument - * - * Return status. - */ -bfa_status_t -bfa_phy_read(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg) -{ - bfa_trc(phy, BFI_PHY_H2I_READ_REQ); - bfa_trc(phy, instance); - bfa_trc(phy, len); - bfa_trc(phy, offset); - - if (!bfa_phy_present(phy)) - return BFA_STATUS_PHY_NOT_PRESENT; - - if (!bfa_ioc_is_operational(phy->ioc)) - return BFA_STATUS_IOC_NON_OP; - - /* 'len' must be in word (4-byte) boundary */ - if (!len || (len & 0x03)) - return BFA_STATUS_FAILED; - - if (phy->op_busy || bfa_phy_busy(phy->ioc)) { - bfa_trc(phy, phy->op_busy); - return BFA_STATUS_DEVBUSY; - } - - phy->op_busy = 1; - phy->cbfn = cbfn; - phy->cbarg = cbarg; - phy->instance = instance; - phy->residue = len; - phy->offset = 0; - phy->addr_off = offset; - phy->ubuf = buf; - bfa_phy_read_send(phy); - - return BFA_STATUS_OK; -} - -/* - * Process phy response messages upon receiving interrupts. - * - * @param[in] phyarg - phy structure - * @param[in] msg - message structure - */ -void -bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg) -{ - struct bfa_phy_s *phy = phyarg; - u32 status; - - union { - struct bfi_phy_query_rsp_s *query; - struct bfi_phy_stats_rsp_s *stats; - struct bfi_phy_write_rsp_s *write; - struct bfi_phy_read_rsp_s *read; - struct bfi_mbmsg_s *msg; - } m; - - m.msg = msg; - bfa_trc(phy, msg->mh.msg_id); - - if (!phy->op_busy) { - /* receiving response after ioc failure */ - bfa_trc(phy, 0x9999); - return; - } - - switch (msg->mh.msg_id) { - case BFI_PHY_I2H_QUERY_RSP: - status = be32_to_cpu(m.query->status); - bfa_trc(phy, status); - - if (status == BFA_STATUS_OK) { - struct bfa_phy_attr_s *attr = - (struct bfa_phy_attr_s *) phy->ubuf; - bfa_phy_ntoh32((u32 *)attr, (u32 *)phy->dbuf_kva, - sizeof(struct bfa_phy_attr_s)); - bfa_trc(phy, attr->status); - bfa_trc(phy, attr->length); - } - - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - break; - case BFI_PHY_I2H_STATS_RSP: - status = be32_to_cpu(m.stats->status); - bfa_trc(phy, status); - - if (status == BFA_STATUS_OK) { - struct bfa_phy_stats_s *stats = - (struct bfa_phy_stats_s *) phy->ubuf; - bfa_phy_ntoh32((u32 *)stats, (u32 *)phy->dbuf_kva, - sizeof(struct bfa_phy_stats_s)); - bfa_trc(phy, stats->status); - } - - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - break; - case BFI_PHY_I2H_WRITE_RSP: - status = be32_to_cpu(m.write->status); - bfa_trc(phy, status); - - if (status != BFA_STATUS_OK || phy->residue == 0) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else { - bfa_trc(phy, phy->offset); - bfa_phy_write_send(phy); - } - break; - case BFI_PHY_I2H_READ_RSP: - status = be32_to_cpu(m.read->status); - bfa_trc(phy, status); - - if (status != BFA_STATUS_OK) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else { - u32 len = be32_to_cpu(m.read->length); - u16 *buf = (u16 *)(phy->ubuf + phy->offset); - u16 *dbuf = (u16 *)phy->dbuf_kva; - int i, sz = len >> 1; - - bfa_trc(phy, phy->offset); - bfa_trc(phy, len); - - for (i = 0; i < sz; i++) - buf[i] = be16_to_cpu(dbuf[i]); - - phy->residue -= len; - phy->offset += len; - - if (phy->residue == 0) { - phy->status = status; - phy->op_busy = 0; - if (phy->cbfn) - phy->cbfn(phy->cbarg, phy->status); - } else - bfa_phy_read_send(phy); - } - break; - default: - WARN_ON(1); - } -} - -/* - * DCONF module specific - */ - -BFA_MODULE(dconf); - -/* - * DCONF state machine events - */ -enum bfa_dconf_event { - BFA_DCONF_SM_INIT = 1, /* dconf Init */ - BFA_DCONF_SM_FLASH_COMP = 2, /* read/write to flash */ - BFA_DCONF_SM_WR = 3, /* binding change, map */ - BFA_DCONF_SM_TIMEOUT = 4, /* Start timer */ - BFA_DCONF_SM_EXIT = 5, /* exit dconf module */ - BFA_DCONF_SM_IOCDISABLE = 6, /* IOC disable event */ -}; - -/* forward declaration of DCONF state machine */ -static void bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event); -static void bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event); -static void bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event); -static void bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event); -static void bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event); -static void bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event); -static void bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event); - -static void bfa_dconf_cbfn(void *dconf, bfa_status_t status); -static void bfa_dconf_timer(void *cbarg); -static bfa_status_t bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf); -static void bfa_dconf_init_cb(void *arg, bfa_status_t status); - -/* - * Begining state of dconf module. Waiting for an event to start. - */ -static void -bfa_dconf_sm_uninit(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) -{ - bfa_status_t bfa_status; - bfa_trc(dconf->bfa, event); - - switch (event) { - case BFA_DCONF_SM_INIT: - if (dconf->min_cfg) { - bfa_trc(dconf->bfa, dconf->min_cfg); - bfa_fsm_send_event(&dconf->bfa->iocfc, - IOCFC_E_DCONF_DONE); - return; - } - bfa_sm_set_state(dconf, bfa_dconf_sm_flash_read); - bfa_timer_start(dconf->bfa, &dconf->timer, - bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); - bfa_status = bfa_flash_read_part(BFA_FLASH(dconf->bfa), - BFA_FLASH_PART_DRV, dconf->instance, - dconf->dconf, - sizeof(struct bfa_dconf_s), 0, - bfa_dconf_init_cb, dconf->bfa); - if (bfa_status != BFA_STATUS_OK) { - bfa_timer_stop(&dconf->timer); - bfa_dconf_init_cb(dconf->bfa, BFA_STATUS_FAILED); - bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); - return; - } - break; - case BFA_DCONF_SM_EXIT: - bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE); - case BFA_DCONF_SM_IOCDISABLE: - case BFA_DCONF_SM_WR: - case BFA_DCONF_SM_FLASH_COMP: - break; - default: - bfa_sm_fault(dconf->bfa, event); - } -} - -/* - * Read flash for dconf entries and make a call back to the driver once done. - */ -static void -bfa_dconf_sm_flash_read(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event) -{ - bfa_trc(dconf->bfa, event); - - switch (event) { - case BFA_DCONF_SM_FLASH_COMP: - bfa_timer_stop(&dconf->timer); - bfa_sm_set_state(dconf, bfa_dconf_sm_ready); - break; - case BFA_DCONF_SM_TIMEOUT: - bfa_sm_set_state(dconf, bfa_dconf_sm_ready); - bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_IOC_FAILED); - break; - case BFA_DCONF_SM_EXIT: - bfa_timer_stop(&dconf->timer); - bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); - bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE); - break; - case BFA_DCONF_SM_IOCDISABLE: - bfa_timer_stop(&dconf->timer); - bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); - break; - default: - bfa_sm_fault(dconf->bfa, event); - } -} - -/* - * DCONF Module is in ready state. Has completed the initialization. - */ -static void -bfa_dconf_sm_ready(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) -{ - bfa_trc(dconf->bfa, event); - - switch (event) { - case BFA_DCONF_SM_WR: - bfa_timer_start(dconf->bfa, &dconf->timer, - bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); - bfa_sm_set_state(dconf, bfa_dconf_sm_dirty); - break; - case BFA_DCONF_SM_EXIT: - bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); - bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE); - break; - case BFA_DCONF_SM_INIT: - case BFA_DCONF_SM_IOCDISABLE: - break; - default: - bfa_sm_fault(dconf->bfa, event); - } -} - -/* - * entries are dirty, write back to the flash. - */ - -static void -bfa_dconf_sm_dirty(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) -{ - bfa_trc(dconf->bfa, event); - - switch (event) { - case BFA_DCONF_SM_TIMEOUT: - bfa_sm_set_state(dconf, bfa_dconf_sm_sync); - bfa_dconf_flash_write(dconf); - break; - case BFA_DCONF_SM_WR: - bfa_timer_stop(&dconf->timer); - bfa_timer_start(dconf->bfa, &dconf->timer, - bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); - break; - case BFA_DCONF_SM_EXIT: - bfa_timer_stop(&dconf->timer); - bfa_timer_start(dconf->bfa, &dconf->timer, - bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); - bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync); - bfa_dconf_flash_write(dconf); - break; - case BFA_DCONF_SM_FLASH_COMP: - break; - case BFA_DCONF_SM_IOCDISABLE: - bfa_timer_stop(&dconf->timer); - bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty); - break; - default: - bfa_sm_fault(dconf->bfa, event); - } -} - -/* - * Sync the dconf entries to the flash. - */ -static void -bfa_dconf_sm_final_sync(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event) -{ - bfa_trc(dconf->bfa, event); - - switch (event) { - case BFA_DCONF_SM_IOCDISABLE: - case BFA_DCONF_SM_FLASH_COMP: - bfa_timer_stop(&dconf->timer); - case BFA_DCONF_SM_TIMEOUT: - bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); - bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE); - break; - default: - bfa_sm_fault(dconf->bfa, event); - } -} - -static void -bfa_dconf_sm_sync(struct bfa_dconf_mod_s *dconf, enum bfa_dconf_event event) -{ - bfa_trc(dconf->bfa, event); - - switch (event) { - case BFA_DCONF_SM_FLASH_COMP: - bfa_sm_set_state(dconf, bfa_dconf_sm_ready); - break; - case BFA_DCONF_SM_WR: - bfa_timer_start(dconf->bfa, &dconf->timer, - bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); - bfa_sm_set_state(dconf, bfa_dconf_sm_dirty); - break; - case BFA_DCONF_SM_EXIT: - bfa_timer_start(dconf->bfa, &dconf->timer, - bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); - bfa_sm_set_state(dconf, bfa_dconf_sm_final_sync); - break; - case BFA_DCONF_SM_IOCDISABLE: - bfa_sm_set_state(dconf, bfa_dconf_sm_iocdown_dirty); - break; - default: - bfa_sm_fault(dconf->bfa, event); - } -} - -static void -bfa_dconf_sm_iocdown_dirty(struct bfa_dconf_mod_s *dconf, - enum bfa_dconf_event event) -{ - bfa_trc(dconf->bfa, event); - - switch (event) { - case BFA_DCONF_SM_INIT: - bfa_timer_start(dconf->bfa, &dconf->timer, - bfa_dconf_timer, dconf, BFA_DCONF_UPDATE_TOV); - bfa_sm_set_state(dconf, bfa_dconf_sm_dirty); - break; - case BFA_DCONF_SM_EXIT: - bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); - bfa_fsm_send_event(&dconf->bfa->iocfc, IOCFC_E_DCONF_DONE); - break; - case BFA_DCONF_SM_IOCDISABLE: - break; - default: - bfa_sm_fault(dconf->bfa, event); - } -} - -/* - * Compute and return memory needed by DRV_CFG module. - */ -static void -bfa_dconf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) -{ - struct bfa_mem_kva_s *dconf_kva = BFA_MEM_DCONF_KVA(bfa); - - if (cfg->drvcfg.min_cfg) - bfa_mem_kva_setup(meminfo, dconf_kva, - sizeof(struct bfa_dconf_hdr_s)); - else - bfa_mem_kva_setup(meminfo, dconf_kva, - sizeof(struct bfa_dconf_s)); -} - -static void -bfa_dconf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); - - dconf->bfad = bfad; - dconf->bfa = bfa; - dconf->instance = bfa->ioc.port_id; - bfa_trc(bfa, dconf->instance); - - dconf->dconf = (struct bfa_dconf_s *) bfa_mem_kva_curp(dconf); - if (cfg->drvcfg.min_cfg) { - bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_hdr_s); - dconf->min_cfg = BFA_TRUE; - } else { - dconf->min_cfg = BFA_FALSE; - bfa_mem_kva_curp(dconf) += sizeof(struct bfa_dconf_s); - } - - bfa_dconf_read_data_valid(bfa) = BFA_FALSE; - bfa_sm_set_state(dconf, bfa_dconf_sm_uninit); -} - -static void -bfa_dconf_init_cb(void *arg, bfa_status_t status) -{ - struct bfa_s *bfa = arg; - struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); - - bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP); - if (status == BFA_STATUS_OK) { - bfa_dconf_read_data_valid(bfa) = BFA_TRUE; - if (dconf->dconf->hdr.signature != BFI_DCONF_SIGNATURE) - dconf->dconf->hdr.signature = BFI_DCONF_SIGNATURE; - if (dconf->dconf->hdr.version != BFI_DCONF_VERSION) - dconf->dconf->hdr.version = BFI_DCONF_VERSION; - } - bfa_fsm_send_event(&bfa->iocfc, IOCFC_E_DCONF_DONE); -} - -void -bfa_dconf_modinit(struct bfa_s *bfa) -{ - struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); - bfa_sm_send_event(dconf, BFA_DCONF_SM_INIT); -} -static void -bfa_dconf_start(struct bfa_s *bfa) -{ -} - -static void -bfa_dconf_stop(struct bfa_s *bfa) -{ -} - -static void bfa_dconf_timer(void *cbarg) -{ - struct bfa_dconf_mod_s *dconf = cbarg; - bfa_sm_send_event(dconf, BFA_DCONF_SM_TIMEOUT); -} -static void -bfa_dconf_iocdisable(struct bfa_s *bfa) -{ - struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); - bfa_sm_send_event(dconf, BFA_DCONF_SM_IOCDISABLE); -} - -static void -bfa_dconf_detach(struct bfa_s *bfa) -{ -} - -static bfa_status_t -bfa_dconf_flash_write(struct bfa_dconf_mod_s *dconf) -{ - bfa_status_t bfa_status; - bfa_trc(dconf->bfa, 0); - - bfa_status = bfa_flash_update_part(BFA_FLASH(dconf->bfa), - BFA_FLASH_PART_DRV, dconf->instance, - dconf->dconf, sizeof(struct bfa_dconf_s), 0, - bfa_dconf_cbfn, dconf); - if (bfa_status != BFA_STATUS_OK) - WARN_ON(bfa_status); - bfa_trc(dconf->bfa, bfa_status); - - return bfa_status; -} - -bfa_status_t -bfa_dconf_update(struct bfa_s *bfa) -{ - struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); - bfa_trc(dconf->bfa, 0); - if (bfa_sm_cmp_state(dconf, bfa_dconf_sm_iocdown_dirty)) - return BFA_STATUS_FAILED; - - if (dconf->min_cfg) { - bfa_trc(dconf->bfa, dconf->min_cfg); - return BFA_STATUS_FAILED; - } - - bfa_sm_send_event(dconf, BFA_DCONF_SM_WR); - return BFA_STATUS_OK; -} - -static void -bfa_dconf_cbfn(void *arg, bfa_status_t status) -{ - struct bfa_dconf_mod_s *dconf = arg; - WARN_ON(status); - bfa_sm_send_event(dconf, BFA_DCONF_SM_FLASH_COMP); -} - -void -bfa_dconf_modexit(struct bfa_s *bfa) -{ - struct bfa_dconf_mod_s *dconf = BFA_DCONF_MOD(bfa); - bfa_sm_send_event(dconf, BFA_DCONF_SM_EXIT); -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.h deleted file mode 100644 index 1a99d4b5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc.h +++ /dev/null @@ -1,981 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_IOC_H__ -#define __BFA_IOC_H__ - -#include "bfad_drv.h" -#include "bfa_cs.h" -#include "bfi.h" - -#define BFA_DBG_FWTRC_ENTS (BFI_IOC_TRC_ENTS) -#define BFA_DBG_FWTRC_LEN \ - (BFA_DBG_FWTRC_ENTS * sizeof(struct bfa_trc_s) + \ - (sizeof(struct bfa_trc_mod_s) - \ - BFA_TRC_MAX * sizeof(struct bfa_trc_s))) -/* - * BFA timer declarations - */ -typedef void (*bfa_timer_cbfn_t)(void *); - -/* - * BFA timer data structure - */ -struct bfa_timer_s { - struct list_head qe; - bfa_timer_cbfn_t timercb; - void *arg; - int timeout; /* in millisecs */ -}; - -/* - * Timer module structure - */ -struct bfa_timer_mod_s { - struct list_head timer_q; -}; - -#define BFA_TIMER_FREQ 200 /* specified in millisecs */ - -void bfa_timer_beat(struct bfa_timer_mod_s *mod); -void bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer, - bfa_timer_cbfn_t timercb, void *arg, - unsigned int timeout); -void bfa_timer_stop(struct bfa_timer_s *timer); - -/* - * Generic Scatter Gather Element used by driver - */ -struct bfa_sge_s { - u32 sg_len; - void *sg_addr; -}; - -#define bfa_sge_word_swap(__sge) do { \ - ((u32 *)(__sge))[0] = swab32(((u32 *)(__sge))[0]); \ - ((u32 *)(__sge))[1] = swab32(((u32 *)(__sge))[1]); \ - ((u32 *)(__sge))[2] = swab32(((u32 *)(__sge))[2]); \ -} while (0) - -#define bfa_swap_words(_x) ( \ - ((_x) << 32) | ((_x) >> 32)) - -#ifdef __BIG_ENDIAN -#define bfa_sge_to_be(_x) -#define bfa_sge_to_le(_x) bfa_sge_word_swap(_x) -#define bfa_sgaddr_le(_x) bfa_swap_words(_x) -#else -#define bfa_sge_to_be(_x) bfa_sge_word_swap(_x) -#define bfa_sge_to_le(_x) -#define bfa_sgaddr_le(_x) (_x) -#endif - -/* - * BFA memory resources - */ -struct bfa_mem_dma_s { - struct list_head qe; /* Queue of DMA elements */ - u32 mem_len; /* Total Length in Bytes */ - u8 *kva; /* kernel virtual address */ - u64 dma; /* dma address if DMA memory */ - u8 *kva_curp; /* kva allocation cursor */ - u64 dma_curp; /* dma allocation cursor */ -}; -#define bfa_mem_dma_t struct bfa_mem_dma_s - -struct bfa_mem_kva_s { - struct list_head qe; /* Queue of KVA elements */ - u32 mem_len; /* Total Length in Bytes */ - u8 *kva; /* kernel virtual address */ - u8 *kva_curp; /* kva allocation cursor */ -}; -#define bfa_mem_kva_t struct bfa_mem_kva_s - -struct bfa_meminfo_s { - struct bfa_mem_dma_s dma_info; - struct bfa_mem_kva_s kva_info; -}; - -/* BFA memory segment setup macros */ -#define bfa_mem_dma_setup(_meminfo, _dm_ptr, _seg_sz) do { \ - ((bfa_mem_dma_t *)(_dm_ptr))->mem_len = (_seg_sz); \ - if (_seg_sz) \ - list_add_tail(&((bfa_mem_dma_t *)_dm_ptr)->qe, \ - &(_meminfo)->dma_info.qe); \ -} while (0) - -#define bfa_mem_kva_setup(_meminfo, _kva_ptr, _seg_sz) do { \ - ((bfa_mem_kva_t *)(_kva_ptr))->mem_len = (_seg_sz); \ - if (_seg_sz) \ - list_add_tail(&((bfa_mem_kva_t *)_kva_ptr)->qe, \ - &(_meminfo)->kva_info.qe); \ -} while (0) - -/* BFA dma memory segments iterator */ -#define bfa_mem_dma_sptr(_mod, _i) (&(_mod)->dma_seg[(_i)]) -#define bfa_mem_dma_seg_iter(_mod, _sptr, _nr, _i) \ - for (_i = 0, _sptr = bfa_mem_dma_sptr(_mod, _i); _i < (_nr); \ - _i++, _sptr = bfa_mem_dma_sptr(_mod, _i)) - -#define bfa_mem_kva_curp(_mod) ((_mod)->kva_seg.kva_curp) -#define bfa_mem_dma_virt(_sptr) ((_sptr)->kva_curp) -#define bfa_mem_dma_phys(_sptr) ((_sptr)->dma_curp) -#define bfa_mem_dma_len(_sptr) ((_sptr)->mem_len) - -/* Get the corresponding dma buf kva for a req - from the tag */ -#define bfa_mem_get_dmabuf_kva(_mod, _tag, _rqsz) \ - (((u8 *)(_mod)->dma_seg[BFI_MEM_SEG_FROM_TAG(_tag, _rqsz)].kva_curp) +\ - BFI_MEM_SEG_REQ_OFFSET(_tag, _rqsz) * (_rqsz)) - -/* Get the corresponding dma buf pa for a req - from the tag */ -#define bfa_mem_get_dmabuf_pa(_mod, _tag, _rqsz) \ - ((_mod)->dma_seg[BFI_MEM_SEG_FROM_TAG(_tag, _rqsz)].dma_curp + \ - BFI_MEM_SEG_REQ_OFFSET(_tag, _rqsz) * (_rqsz)) - -/* - * PCI device information required by IOC - */ -struct bfa_pcidev_s { - int pci_slot; - u8 pci_func; - u16 device_id; - u16 ssid; - void __iomem *pci_bar_kva; -}; - -/* - * Structure used to remember the DMA-able memory block's KVA and Physical - * Address - */ -struct bfa_dma_s { - void *kva; /* ! Kernel virtual address */ - u64 pa; /* ! Physical address */ -}; - -#define BFA_DMA_ALIGN_SZ 256 -#define BFA_ROUNDUP(_l, _s) (((_l) + ((_s) - 1)) & ~((_s) - 1)) - -/* - * smem size for Crossbow and Catapult - */ -#define BFI_SMEM_CB_SIZE 0x200000U /* ! 2MB for crossbow */ -#define BFI_SMEM_CT_SIZE 0x280000U /* ! 2.5MB for catapult */ - -#define bfa_dma_be_addr_set(dma_addr, pa) \ - __bfa_dma_be_addr_set(&dma_addr, (u64)pa) -static inline void -__bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa) -{ - dma_addr->a32.addr_lo = cpu_to_be32(pa); - dma_addr->a32.addr_hi = cpu_to_be32(pa >> 32); -} - -#define bfa_alen_set(__alen, __len, __pa) \ - __bfa_alen_set(__alen, __len, (u64)__pa) - -static inline void -__bfa_alen_set(struct bfi_alen_s *alen, u32 len, u64 pa) -{ - alen->al_len = cpu_to_be32(len); - bfa_dma_be_addr_set(alen->al_addr, pa); -} - -struct bfa_ioc_regs_s { - void __iomem *hfn_mbox_cmd; - void __iomem *hfn_mbox; - void __iomem *lpu_mbox_cmd; - void __iomem *lpu_mbox; - void __iomem *lpu_read_stat; - void __iomem *pss_ctl_reg; - void __iomem *pss_err_status_reg; - void __iomem *app_pll_fast_ctl_reg; - void __iomem *app_pll_slow_ctl_reg; - void __iomem *ioc_sem_reg; - void __iomem *ioc_usage_sem_reg; - void __iomem *ioc_init_sem_reg; - void __iomem *ioc_usage_reg; - void __iomem *host_page_num_fn; - void __iomem *heartbeat; - void __iomem *ioc_fwstate; - void __iomem *alt_ioc_fwstate; - void __iomem *ll_halt; - void __iomem *alt_ll_halt; - void __iomem *err_set; - void __iomem *ioc_fail_sync; - void __iomem *shirq_isr_next; - void __iomem *shirq_msk_next; - void __iomem *smem_page_start; - u32 smem_pg0; -}; - -#define bfa_mem_read(_raddr, _off) swab32(readl(((_raddr) + (_off)))) -#define bfa_mem_write(_raddr, _off, _val) \ - writel(swab32((_val)), ((_raddr) + (_off))) -/* - * IOC Mailbox structures - */ -struct bfa_mbox_cmd_s { - struct list_head qe; - u32 msg[BFI_IOC_MSGSZ]; -}; - -/* - * IOC mailbox module - */ -typedef void (*bfa_ioc_mbox_mcfunc_t)(void *cbarg, struct bfi_mbmsg_s *m); -struct bfa_ioc_mbox_mod_s { - struct list_head cmd_q; /* pending mbox queue */ - int nmclass; /* number of handlers */ - struct { - bfa_ioc_mbox_mcfunc_t cbfn; /* message handlers */ - void *cbarg; - } mbhdlr[BFI_MC_MAX]; -}; - -/* - * IOC callback function interfaces - */ -typedef void (*bfa_ioc_enable_cbfn_t)(void *bfa, enum bfa_status status); -typedef void (*bfa_ioc_disable_cbfn_t)(void *bfa); -typedef void (*bfa_ioc_hbfail_cbfn_t)(void *bfa); -typedef void (*bfa_ioc_reset_cbfn_t)(void *bfa); -struct bfa_ioc_cbfn_s { - bfa_ioc_enable_cbfn_t enable_cbfn; - bfa_ioc_disable_cbfn_t disable_cbfn; - bfa_ioc_hbfail_cbfn_t hbfail_cbfn; - bfa_ioc_reset_cbfn_t reset_cbfn; -}; - -/* - * IOC event notification mechanism. - */ -enum bfa_ioc_event_e { - BFA_IOC_E_ENABLED = 1, - BFA_IOC_E_DISABLED = 2, - BFA_IOC_E_FAILED = 3, -}; - -typedef void (*bfa_ioc_notify_cbfn_t)(void *, enum bfa_ioc_event_e); - -struct bfa_ioc_notify_s { - struct list_head qe; - bfa_ioc_notify_cbfn_t cbfn; - void *cbarg; -}; - -/* - * Initialize a IOC event notification structure - */ -#define bfa_ioc_notify_init(__notify, __cbfn, __cbarg) do { \ - (__notify)->cbfn = (__cbfn); \ - (__notify)->cbarg = (__cbarg); \ -} while (0) - -struct bfa_iocpf_s { - bfa_fsm_t fsm; - struct bfa_ioc_s *ioc; - bfa_boolean_t fw_mismatch_notified; - bfa_boolean_t auto_recover; - u32 poll_time; -}; - -struct bfa_ioc_s { - bfa_fsm_t fsm; - struct bfa_s *bfa; - struct bfa_pcidev_s pcidev; - struct bfa_timer_mod_s *timer_mod; - struct bfa_timer_s ioc_timer; - struct bfa_timer_s sem_timer; - struct bfa_timer_s hb_timer; - u32 hb_count; - struct list_head notify_q; - void *dbg_fwsave; - int dbg_fwsave_len; - bfa_boolean_t dbg_fwsave_once; - enum bfi_pcifn_class clscode; - struct bfa_ioc_regs_s ioc_regs; - struct bfa_trc_mod_s *trcmod; - struct bfa_ioc_drv_stats_s stats; - bfa_boolean_t fcmode; - bfa_boolean_t pllinit; - bfa_boolean_t stats_busy; /* outstanding stats */ - u8 port_id; - struct bfa_dma_s attr_dma; - struct bfi_ioc_attr_s *attr; - struct bfa_ioc_cbfn_s *cbfn; - struct bfa_ioc_mbox_mod_s mbox_mod; - struct bfa_ioc_hwif_s *ioc_hwif; - struct bfa_iocpf_s iocpf; - enum bfi_asic_gen asic_gen; - enum bfi_asic_mode asic_mode; - enum bfi_port_mode port0_mode; - enum bfi_port_mode port1_mode; - enum bfa_mode_s port_mode; - u8 ad_cap_bm; /* adapter cap bit mask */ - u8 port_mode_cfg; /* config port mode */ - int ioc_aen_seq; -}; - -struct bfa_ioc_hwif_s { - bfa_status_t (*ioc_pll_init) (void __iomem *rb, enum bfi_asic_mode m); - bfa_boolean_t (*ioc_firmware_lock) (struct bfa_ioc_s *ioc); - void (*ioc_firmware_unlock) (struct bfa_ioc_s *ioc); - void (*ioc_reg_init) (struct bfa_ioc_s *ioc); - void (*ioc_map_port) (struct bfa_ioc_s *ioc); - void (*ioc_isr_mode_set) (struct bfa_ioc_s *ioc, - bfa_boolean_t msix); - void (*ioc_notify_fail) (struct bfa_ioc_s *ioc); - void (*ioc_ownership_reset) (struct bfa_ioc_s *ioc); - bfa_boolean_t (*ioc_sync_start) (struct bfa_ioc_s *ioc); - void (*ioc_sync_join) (struct bfa_ioc_s *ioc); - void (*ioc_sync_leave) (struct bfa_ioc_s *ioc); - void (*ioc_sync_ack) (struct bfa_ioc_s *ioc); - bfa_boolean_t (*ioc_sync_complete) (struct bfa_ioc_s *ioc); - bfa_boolean_t (*ioc_lpu_read_stat) (struct bfa_ioc_s *ioc); -}; - -/* - * Queue element to wait for room in request queue. FIFO order is - * maintained when fullfilling requests. - */ -struct bfa_reqq_wait_s { - struct list_head qe; - void (*qresume) (void *cbarg); - void *cbarg; -}; - -typedef void (*bfa_cb_cbfn_t) (void *cbarg, bfa_boolean_t complete); - -/* - * Generic BFA callback element. - */ -struct bfa_cb_qe_s { - struct list_head qe; - bfa_cb_cbfn_t cbfn; - bfa_boolean_t once; - bfa_boolean_t pre_rmv; /* set for stack based qe(s) */ - bfa_status_t fw_status; /* to access fw status in comp proc */ - void *cbarg; -}; - -/* - * IOCFC state machine definitions/declarations - */ -enum iocfc_event { - IOCFC_E_INIT = 1, /* IOCFC init request */ - IOCFC_E_START = 2, /* IOCFC mod start request */ - IOCFC_E_STOP = 3, /* IOCFC stop request */ - IOCFC_E_ENABLE = 4, /* IOCFC enable request */ - IOCFC_E_DISABLE = 5, /* IOCFC disable request */ - IOCFC_E_IOC_ENABLED = 6, /* IOC enabled message */ - IOCFC_E_IOC_DISABLED = 7, /* IOC disabled message */ - IOCFC_E_IOC_FAILED = 8, /* failure notice by IOC sm */ - IOCFC_E_DCONF_DONE = 9, /* dconf read/write done */ - IOCFC_E_CFG_DONE = 10, /* IOCFC config complete */ -}; - -/* - * ASIC block configurtion related - */ - -typedef void (*bfa_ablk_cbfn_t)(void *, enum bfa_status); - -struct bfa_ablk_s { - struct bfa_ioc_s *ioc; - struct bfa_ablk_cfg_s *cfg; - u16 *pcifn; - struct bfa_dma_s dma_addr; - bfa_boolean_t busy; - struct bfa_mbox_cmd_s mb; - bfa_ablk_cbfn_t cbfn; - void *cbarg; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_mem_dma_s ablk_dma; -}; -#define BFA_MEM_ABLK_DMA(__bfa) (&((__bfa)->modules.ablk.ablk_dma)) - -/* - * SFP module specific - */ -typedef void (*bfa_cb_sfp_t) (void *cbarg, bfa_status_t status); - -struct bfa_sfp_s { - void *dev; - struct bfa_ioc_s *ioc; - struct bfa_trc_mod_s *trcmod; - struct sfp_mem_s *sfpmem; - bfa_cb_sfp_t cbfn; - void *cbarg; - enum bfi_sfp_mem_e memtype; /* mem access type */ - u32 status; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_ioc_notify_s ioc_notify; - enum bfa_defs_sfp_media_e *media; - enum bfa_port_speed portspeed; - bfa_cb_sfp_t state_query_cbfn; - void *state_query_cbarg; - u8 lock; - u8 data_valid; /* data in dbuf is valid */ - u8 state; /* sfp state */ - u8 state_query_lock; - struct bfa_mem_dma_s sfp_dma; - u8 is_elb; /* eloopback */ -}; - -#define BFA_SFP_MOD(__bfa) (&(__bfa)->modules.sfp) -#define BFA_MEM_SFP_DMA(__bfa) (&(BFA_SFP_MOD(__bfa)->sfp_dma)) - -u32 bfa_sfp_meminfo(void); - -void bfa_sfp_attach(struct bfa_sfp_s *sfp, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod); - -void bfa_sfp_memclaim(struct bfa_sfp_s *diag, u8 *dm_kva, u64 dm_pa); -void bfa_sfp_intr(void *bfaarg, struct bfi_mbmsg_s *msg); - -bfa_status_t bfa_sfp_show(struct bfa_sfp_s *sfp, struct sfp_mem_s *sfpmem, - bfa_cb_sfp_t cbfn, void *cbarg); - -bfa_status_t bfa_sfp_media(struct bfa_sfp_s *sfp, - enum bfa_defs_sfp_media_e *media, - bfa_cb_sfp_t cbfn, void *cbarg); - -bfa_status_t bfa_sfp_speed(struct bfa_sfp_s *sfp, - enum bfa_port_speed portspeed, - bfa_cb_sfp_t cbfn, void *cbarg); - -/* - * Flash module specific - */ -typedef void (*bfa_cb_flash_t) (void *cbarg, bfa_status_t status); - -struct bfa_flash_s { - struct bfa_ioc_s *ioc; /* back pointer to ioc */ - struct bfa_trc_mod_s *trcmod; - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 op_busy; /* operation busy flag */ - u32 residue; /* residual length */ - u32 offset; /* offset */ - bfa_status_t status; /* status */ - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - bfa_cb_flash_t cbfn; /* user callback function */ - void *cbarg; /* user callback arg */ - u8 *ubuf; /* user supplied buffer */ - struct bfa_cb_qe_s hcb_qe; /* comp: BFA callback qelem */ - u32 addr_off; /* partition address offset */ - struct bfa_mbox_cmd_s mb; /* mailbox */ - struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */ - struct bfa_mem_dma_s flash_dma; -}; - -#define BFA_FLASH(__bfa) (&(__bfa)->modules.flash) -#define BFA_MEM_FLASH_DMA(__bfa) (&(BFA_FLASH(__bfa)->flash_dma)) - -bfa_status_t bfa_flash_get_attr(struct bfa_flash_s *flash, - struct bfa_flash_attr_s *attr, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_erase_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_update_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_flash_t cbfn, void *cbarg); -bfa_status_t bfa_flash_read_part(struct bfa_flash_s *flash, - enum bfa_flash_part_type type, u8 instance, void *buf, - u32 len, u32 offset, bfa_cb_flash_t cbfn, void *cbarg); -u32 bfa_flash_meminfo(bfa_boolean_t mincfg); -void bfa_flash_attach(struct bfa_flash_s *flash, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg); -void bfa_flash_memclaim(struct bfa_flash_s *flash, - u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg); - -/* - * DIAG module specific - */ - -typedef void (*bfa_cb_diag_t) (void *cbarg, bfa_status_t status); -typedef void (*bfa_cb_diag_beacon_t) (void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon); - -/* - * Firmware ping test results - */ -struct bfa_diag_results_fwping { - u32 data; /* store the corrupted data */ - u32 status; - u32 dmastatus; - u8 rsvd[4]; -}; - -struct bfa_diag_qtest_result_s { - u32 status; - u16 count; /* sucessful queue test count */ - u8 queue; - u8 rsvd; /* 64-bit align */ -}; - -/* - * Firmware ping test results - */ -struct bfa_diag_fwping_s { - struct bfa_diag_results_fwping *result; - bfa_cb_diag_t cbfn; - void *cbarg; - u32 data; - u8 lock; - u8 rsv[3]; - u32 status; - u32 count; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ -}; - -/* - * Temperature sensor query results - */ -struct bfa_diag_results_tempsensor_s { - u32 status; - u16 temp; /* 10-bit A/D value */ - u16 brd_temp; /* 9-bit board temp */ - u8 ts_junc; /* show junction tempsensor */ - u8 ts_brd; /* show board tempsensor */ - u8 rsvd[6]; /* keep 8 bytes alignment */ -}; - -struct bfa_diag_tsensor_s { - bfa_cb_diag_t cbfn; - void *cbarg; - struct bfa_diag_results_tempsensor_s *temp; - u8 lock; - u8 rsv[3]; - u32 status; - struct bfa_mbox_cmd_s mbcmd; -}; - -struct bfa_diag_sfpshow_s { - struct sfp_mem_s *sfpmem; - bfa_cb_diag_t cbfn; - void *cbarg; - u8 lock; - u8 static_data; - u8 rsv[2]; - u32 status; - struct bfa_mbox_cmd_s mbcmd; - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ -}; - -struct bfa_diag_led_s { - struct bfa_mbox_cmd_s mbcmd; - bfa_boolean_t lock; /* 1: ledtest is operating */ -}; - -struct bfa_diag_beacon_s { - struct bfa_mbox_cmd_s mbcmd; - bfa_boolean_t state; /* port beacon state */ - bfa_boolean_t link_e2e; /* link beacon state */ -}; - -struct bfa_diag_s { - void *dev; - struct bfa_ioc_s *ioc; - struct bfa_trc_mod_s *trcmod; - struct bfa_diag_fwping_s fwping; - struct bfa_diag_tsensor_s tsensor; - struct bfa_diag_sfpshow_s sfpshow; - struct bfa_diag_led_s ledtest; - struct bfa_diag_beacon_s beacon; - void *result; - struct bfa_timer_s timer; - bfa_cb_diag_beacon_t cbfn_beacon; - bfa_cb_diag_t cbfn; - void *cbarg; - u8 block; - u8 timer_active; - u8 rsvd[2]; - u32 status; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_mem_dma_s diag_dma; -}; - -#define BFA_DIAG_MOD(__bfa) (&(__bfa)->modules.diag_mod) -#define BFA_MEM_DIAG_DMA(__bfa) (&(BFA_DIAG_MOD(__bfa)->diag_dma)) - -u32 bfa_diag_meminfo(void); -void bfa_diag_memclaim(struct bfa_diag_s *diag, u8 *dm_kva, u64 dm_pa); -void bfa_diag_attach(struct bfa_diag_s *diag, struct bfa_ioc_s *ioc, void *dev, - bfa_cb_diag_beacon_t cbfn_beacon, - struct bfa_trc_mod_s *trcmod); -bfa_status_t bfa_diag_reg_read(struct bfa_diag_s *diag, u32 offset, - u32 len, u32 *buf, u32 force); -bfa_status_t bfa_diag_reg_write(struct bfa_diag_s *diag, u32 offset, - u32 len, u32 value, u32 force); -bfa_status_t bfa_diag_tsensor_query(struct bfa_diag_s *diag, - struct bfa_diag_results_tempsensor_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_fwping(struct bfa_diag_s *diag, u32 cnt, - u32 pattern, struct bfa_diag_results_fwping *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_sfpshow(struct bfa_diag_s *diag, - struct sfp_mem_s *sfpmem, u8 static_data, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_memtest(struct bfa_diag_s *diag, - struct bfa_diag_memtest_s *memtest, u32 pattern, - struct bfa_diag_memtest_result *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_diag_ledtest(struct bfa_diag_s *diag, - struct bfa_diag_ledtest_s *ledtest); -bfa_status_t bfa_diag_beacon_port(struct bfa_diag_s *diag, - bfa_boolean_t beacon, bfa_boolean_t link_e2e_beacon, - u32 sec); - -/* - * PHY module specific - */ -typedef void (*bfa_cb_phy_t) (void *cbarg, bfa_status_t status); - -struct bfa_phy_s { - struct bfa_ioc_s *ioc; /* back pointer to ioc */ - struct bfa_trc_mod_s *trcmod; /* trace module */ - u8 instance; /* port instance */ - u8 op_busy; /* operation busy flag */ - u8 rsv[2]; - u32 residue; /* residual length */ - u32 offset; /* offset */ - bfa_status_t status; /* status */ - u8 *dbuf_kva; /* dma buf virtual address */ - u64 dbuf_pa; /* dma buf physical address */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - bfa_cb_phy_t cbfn; /* user callback function */ - void *cbarg; /* user callback arg */ - u8 *ubuf; /* user supplied buffer */ - struct bfa_cb_qe_s hcb_qe; /* comp: BFA callback qelem */ - u32 addr_off; /* phy address offset */ - struct bfa_mbox_cmd_s mb; /* mailbox */ - struct bfa_ioc_notify_s ioc_notify; /* ioc event notify */ - struct bfa_mem_dma_s phy_dma; -}; -#define BFA_PHY(__bfa) (&(__bfa)->modules.phy) -#define BFA_MEM_PHY_DMA(__bfa) (&(BFA_PHY(__bfa)->phy_dma)) - -bfa_boolean_t bfa_phy_busy(struct bfa_ioc_s *ioc); -bfa_status_t bfa_phy_get_attr(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_attr_s *attr, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_get_stats(struct bfa_phy_s *phy, u8 instance, - struct bfa_phy_stats_s *stats, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_update(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg); -bfa_status_t bfa_phy_read(struct bfa_phy_s *phy, u8 instance, - void *buf, u32 len, u32 offset, - bfa_cb_phy_t cbfn, void *cbarg); - -u32 bfa_phy_meminfo(bfa_boolean_t mincfg); -void bfa_phy_attach(struct bfa_phy_s *phy, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod, bfa_boolean_t mincfg); -void bfa_phy_memclaim(struct bfa_phy_s *phy, - u8 *dm_kva, u64 dm_pa, bfa_boolean_t mincfg); -void bfa_phy_intr(void *phyarg, struct bfi_mbmsg_s *msg); - -/* - * Driver Config( dconf) specific - */ -#define BFI_DCONF_SIGNATURE 0xabcdabcd -#define BFI_DCONF_VERSION 1 - -#pragma pack(1) -struct bfa_dconf_hdr_s { - u32 signature; - u32 version; -}; - -struct bfa_dconf_s { - struct bfa_dconf_hdr_s hdr; - struct bfa_lunmask_cfg_s lun_mask; -}; -#pragma pack() - -struct bfa_dconf_mod_s { - bfa_sm_t sm; - u8 instance; - bfa_boolean_t read_data_valid; - bfa_boolean_t min_cfg; - struct bfa_timer_s timer; - struct bfa_s *bfa; - void *bfad; - void *trcmod; - struct bfa_dconf_s *dconf; - struct bfa_mem_kva_s kva_seg; -}; - -#define BFA_DCONF_MOD(__bfa) \ - (&(__bfa)->modules.dconf_mod) -#define BFA_MEM_DCONF_KVA(__bfa) (&(BFA_DCONF_MOD(__bfa)->kva_seg)) -#define bfa_dconf_read_data_valid(__bfa) \ - (BFA_DCONF_MOD(__bfa)->read_data_valid) -#define BFA_DCONF_UPDATE_TOV 5000 /* memtest timeout in msec */ - -void bfa_dconf_modinit(struct bfa_s *bfa); -void bfa_dconf_modexit(struct bfa_s *bfa); -bfa_status_t bfa_dconf_update(struct bfa_s *bfa); - -/* - * IOC specfic macros - */ -#define bfa_ioc_pcifn(__ioc) ((__ioc)->pcidev.pci_func) -#define bfa_ioc_devid(__ioc) ((__ioc)->pcidev.device_id) -#define bfa_ioc_bar0(__ioc) ((__ioc)->pcidev.pci_bar_kva) -#define bfa_ioc_portid(__ioc) ((__ioc)->port_id) -#define bfa_ioc_asic_gen(__ioc) ((__ioc)->asic_gen) -#define bfa_ioc_is_cna(__ioc) \ - ((bfa_ioc_get_type(__ioc) == BFA_IOC_TYPE_FCoE) || \ - (bfa_ioc_get_type(__ioc) == BFA_IOC_TYPE_LL)) -#define bfa_ioc_fetch_stats(__ioc, __stats) \ - (((__stats)->drv_stats) = (__ioc)->stats) -#define bfa_ioc_clr_stats(__ioc) \ - memset(&(__ioc)->stats, 0, sizeof((__ioc)->stats)) -#define bfa_ioc_maxfrsize(__ioc) ((__ioc)->attr->maxfrsize) -#define bfa_ioc_rx_bbcredit(__ioc) ((__ioc)->attr->rx_bbcredit) -#define bfa_ioc_speed_sup(__ioc) \ - BFI_ADAPTER_GETP(SPEED, (__ioc)->attr->adapter_prop) -#define bfa_ioc_get_nports(__ioc) \ - BFI_ADAPTER_GETP(NPORTS, (__ioc)->attr->adapter_prop) - -#define bfa_ioc_stats(_ioc, _stats) ((_ioc)->stats._stats++) -#define BFA_IOC_FWIMG_MINSZ (16 * 1024) -#define BFA_IOC_FW_SMEM_SIZE(__ioc) \ - ((bfa_ioc_asic_gen(__ioc) == BFI_ASIC_GEN_CB) \ - ? BFI_SMEM_CB_SIZE : BFI_SMEM_CT_SIZE) -#define BFA_IOC_FLASH_CHUNK_NO(off) (off / BFI_FLASH_CHUNK_SZ_WORDS) -#define BFA_IOC_FLASH_OFFSET_IN_CHUNK(off) (off % BFI_FLASH_CHUNK_SZ_WORDS) -#define BFA_IOC_FLASH_CHUNK_ADDR(chunkno) (chunkno * BFI_FLASH_CHUNK_SZ_WORDS) - -/* - * IOC mailbox interface - */ -void bfa_ioc_mbox_queue(struct bfa_ioc_s *ioc, struct bfa_mbox_cmd_s *cmd); -void bfa_ioc_mbox_register(struct bfa_ioc_s *ioc, - bfa_ioc_mbox_mcfunc_t *mcfuncs); -void bfa_ioc_mbox_isr(struct bfa_ioc_s *ioc); -void bfa_ioc_mbox_send(struct bfa_ioc_s *ioc, void *ioc_msg, int len); -bfa_boolean_t bfa_ioc_msgget(struct bfa_ioc_s *ioc, void *mbmsg); -void bfa_ioc_mbox_regisr(struct bfa_ioc_s *ioc, enum bfi_mclass mc, - bfa_ioc_mbox_mcfunc_t cbfn, void *cbarg); - -/* - * IOC interfaces - */ - -#define bfa_ioc_pll_init_asic(__ioc) \ - ((__ioc)->ioc_hwif->ioc_pll_init((__ioc)->pcidev.pci_bar_kva, \ - (__ioc)->asic_mode)) - -bfa_status_t bfa_ioc_pll_init(struct bfa_ioc_s *ioc); -bfa_status_t bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode mode); -bfa_status_t bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode); -bfa_status_t bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode); - -#define bfa_ioc_isr_mode_set(__ioc, __msix) do { \ - if ((__ioc)->ioc_hwif->ioc_isr_mode_set) \ - ((__ioc)->ioc_hwif->ioc_isr_mode_set(__ioc, __msix)); \ -} while (0) -#define bfa_ioc_ownership_reset(__ioc) \ - ((__ioc)->ioc_hwif->ioc_ownership_reset(__ioc)) -#define bfa_ioc_get_fcmode(__ioc) ((__ioc)->fcmode) -#define bfa_ioc_lpu_read_stat(__ioc) do { \ - if ((__ioc)->ioc_hwif->ioc_lpu_read_stat) \ - ((__ioc)->ioc_hwif->ioc_lpu_read_stat(__ioc)); \ -} while (0) - -void bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc); -void bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc); -void bfa_ioc_set_ct2_hwif(struct bfa_ioc_s *ioc); -void bfa_ioc_ct2_poweron(struct bfa_ioc_s *ioc); - -void bfa_ioc_attach(struct bfa_ioc_s *ioc, void *bfa, - struct bfa_ioc_cbfn_s *cbfn, struct bfa_timer_mod_s *timer_mod); -void bfa_ioc_auto_recover(bfa_boolean_t auto_recover); -void bfa_ioc_detach(struct bfa_ioc_s *ioc); -void bfa_ioc_pci_init(struct bfa_ioc_s *ioc, struct bfa_pcidev_s *pcidev, - enum bfi_pcifn_class clscode); -void bfa_ioc_mem_claim(struct bfa_ioc_s *ioc, u8 *dm_kva, u64 dm_pa); -void bfa_ioc_enable(struct bfa_ioc_s *ioc); -void bfa_ioc_disable(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_intx_claim(struct bfa_ioc_s *ioc); - -void bfa_ioc_boot(struct bfa_ioc_s *ioc, u32 boot_type, - u32 boot_env); -void bfa_ioc_isr(struct bfa_ioc_s *ioc, struct bfi_mbmsg_s *msg); -void bfa_ioc_error_isr(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_is_operational(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_is_initialized(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_is_disabled(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_is_acq_addr(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_fw_mismatch(struct bfa_ioc_s *ioc); -bfa_boolean_t bfa_ioc_adapter_is_disabled(struct bfa_ioc_s *ioc); -void bfa_ioc_reset_fwstate(struct bfa_ioc_s *ioc); -enum bfa_ioc_type_e bfa_ioc_get_type(struct bfa_ioc_s *ioc); -void bfa_ioc_get_adapter_serial_num(struct bfa_ioc_s *ioc, char *serial_num); -void bfa_ioc_get_adapter_fw_ver(struct bfa_ioc_s *ioc, char *fw_ver); -void bfa_ioc_get_adapter_optrom_ver(struct bfa_ioc_s *ioc, char *optrom_ver); -void bfa_ioc_get_adapter_model(struct bfa_ioc_s *ioc, char *model); -void bfa_ioc_get_adapter_manufacturer(struct bfa_ioc_s *ioc, - char *manufacturer); -void bfa_ioc_get_pci_chip_rev(struct bfa_ioc_s *ioc, char *chip_rev); -enum bfa_ioc_state bfa_ioc_get_state(struct bfa_ioc_s *ioc); - -void bfa_ioc_get_attr(struct bfa_ioc_s *ioc, struct bfa_ioc_attr_s *ioc_attr); -void bfa_ioc_get_adapter_attr(struct bfa_ioc_s *ioc, - struct bfa_adapter_attr_s *ad_attr); -void bfa_ioc_debug_memclaim(struct bfa_ioc_s *ioc, void *dbg_fwsave); -bfa_status_t bfa_ioc_debug_fwsave(struct bfa_ioc_s *ioc, void *trcdata, - int *trclen); -bfa_status_t bfa_ioc_debug_fwtrc(struct bfa_ioc_s *ioc, void *trcdata, - int *trclen); -bfa_status_t bfa_ioc_debug_fwcore(struct bfa_ioc_s *ioc, void *buf, - u32 *offset, int *buflen); -bfa_boolean_t bfa_ioc_sem_get(void __iomem *sem_reg); -void bfa_ioc_fwver_get(struct bfa_ioc_s *ioc, - struct bfi_ioc_image_hdr_s *fwhdr); -bfa_boolean_t bfa_ioc_fwver_cmp(struct bfa_ioc_s *ioc, - struct bfi_ioc_image_hdr_s *fwhdr); -void bfa_ioc_aen_post(struct bfa_ioc_s *ioc, enum bfa_ioc_aen_event event); -bfa_status_t bfa_ioc_fw_stats_get(struct bfa_ioc_s *ioc, void *stats); -bfa_status_t bfa_ioc_fw_stats_clear(struct bfa_ioc_s *ioc); - -/* - * asic block configuration related APIs - */ -u32 bfa_ablk_meminfo(void); -void bfa_ablk_memclaim(struct bfa_ablk_s *ablk, u8 *dma_kva, u64 dma_pa); -void bfa_ablk_attach(struct bfa_ablk_s *ablk, struct bfa_ioc_s *ioc); -bfa_status_t bfa_ablk_query(struct bfa_ablk_s *ablk, - struct bfa_ablk_cfg_s *ablk_cfg, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_adapter_config(struct bfa_ablk_s *ablk, - enum bfa_mode_s mode, int max_pf, int max_vf, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_port_config(struct bfa_ablk_s *ablk, int port, - enum bfa_mode_s mode, int max_pf, int max_vf, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_create(struct bfa_ablk_s *ablk, u16 *pcifn, - u8 port, enum bfi_pcifn_class personality, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_delete(struct bfa_ablk_s *ablk, int pcifn, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_pf_update(struct bfa_ablk_s *ablk, int pcifn, int bw, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_optrom_en(struct bfa_ablk_s *ablk, - bfa_ablk_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_ablk_optrom_dis(struct bfa_ablk_s *ablk, - bfa_ablk_cbfn_t cbfn, void *cbarg); - -/* - * bfa mfg wwn API functions - */ -mac_t bfa_ioc_get_mac(struct bfa_ioc_s *ioc); -mac_t bfa_ioc_get_mfg_mac(struct bfa_ioc_s *ioc); - -/* - * F/W Image Size & Chunk - */ -extern u32 bfi_image_cb_size; -extern u32 bfi_image_ct_size; -extern u32 bfi_image_ct2_size; -extern u32 *bfi_image_cb; -extern u32 *bfi_image_ct; -extern u32 *bfi_image_ct2; - -static inline u32 * -bfi_image_cb_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_cb + off); -} - -static inline u32 * -bfi_image_ct_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_ct + off); -} - -static inline u32 * -bfi_image_ct2_get_chunk(u32 off) -{ - return (u32 *)(bfi_image_ct2 + off); -} - -static inline u32* -bfa_cb_image_get_chunk(enum bfi_asic_gen asic_gen, u32 off) -{ - switch (asic_gen) { - case BFI_ASIC_GEN_CB: - return bfi_image_cb_get_chunk(off); - break; - case BFI_ASIC_GEN_CT: - return bfi_image_ct_get_chunk(off); - break; - case BFI_ASIC_GEN_CT2: - return bfi_image_ct2_get_chunk(off); - break; - default: - return NULL; - } -} - -static inline u32 -bfa_cb_image_get_size(enum bfi_asic_gen asic_gen) -{ - switch (asic_gen) { - case BFI_ASIC_GEN_CB: - return bfi_image_cb_size; - break; - case BFI_ASIC_GEN_CT: - return bfi_image_ct_size; - break; - case BFI_ASIC_GEN_CT2: - return bfi_image_ct2_size; - break; - default: - return 0; - } -} - -/* - * CNA TRCMOD declaration - */ -/* - * !!! Only append to the enums defined here to avoid any versioning - * !!! needed between trace utility and driver version - */ -enum { - BFA_TRC_CNA_PORT = 1, - BFA_TRC_CNA_IOC = 2, - BFA_TRC_CNA_IOC_CB = 3, - BFA_TRC_CNA_IOC_CT = 4, -}; - -#endif /* __BFA_IOC_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_cb.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_cb.c deleted file mode 100644 index 30df8a28..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_cb.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfa_ioc.h" -#include "bfi_reg.h" -#include "bfa_defs.h" - -BFA_TRC_FILE(CNA, IOC_CB); - -/* - * forward declarations - */ -static bfa_boolean_t bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc); -static void bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc); -static void bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc); -static void bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc); -static void bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix); -static void bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc); -static void bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc); -static bfa_boolean_t bfa_ioc_cb_sync_start(struct bfa_ioc_s *ioc); -static void bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc); -static void bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc); -static void bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc); -static bfa_boolean_t bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc); - -static struct bfa_ioc_hwif_s hwif_cb; - -/* - * Called from bfa_ioc_attach() to map asic specific calls. - */ -void -bfa_ioc_set_cb_hwif(struct bfa_ioc_s *ioc) -{ - hwif_cb.ioc_pll_init = bfa_ioc_cb_pll_init; - hwif_cb.ioc_firmware_lock = bfa_ioc_cb_firmware_lock; - hwif_cb.ioc_firmware_unlock = bfa_ioc_cb_firmware_unlock; - hwif_cb.ioc_reg_init = bfa_ioc_cb_reg_init; - hwif_cb.ioc_map_port = bfa_ioc_cb_map_port; - hwif_cb.ioc_isr_mode_set = bfa_ioc_cb_isr_mode_set; - hwif_cb.ioc_notify_fail = bfa_ioc_cb_notify_fail; - hwif_cb.ioc_ownership_reset = bfa_ioc_cb_ownership_reset; - hwif_cb.ioc_sync_start = bfa_ioc_cb_sync_start; - hwif_cb.ioc_sync_join = bfa_ioc_cb_sync_join; - hwif_cb.ioc_sync_leave = bfa_ioc_cb_sync_leave; - hwif_cb.ioc_sync_ack = bfa_ioc_cb_sync_ack; - hwif_cb.ioc_sync_complete = bfa_ioc_cb_sync_complete; - - ioc->ioc_hwif = &hwif_cb; -} - -/* - * Return true if firmware of current driver matches the running firmware. - */ -static bfa_boolean_t -bfa_ioc_cb_firmware_lock(struct bfa_ioc_s *ioc) -{ - return BFA_TRUE; -} - -static void -bfa_ioc_cb_firmware_unlock(struct bfa_ioc_s *ioc) -{ -} - -/* - * Notify other functions on HB failure. - */ -static void -bfa_ioc_cb_notify_fail(struct bfa_ioc_s *ioc) -{ - writel(~0U, ioc->ioc_regs.err_set); - readl(ioc->ioc_regs.err_set); -} - -/* - * Host to LPU mailbox message addresses - */ -static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } iocreg_fnreg[] = { - { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 }, - { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 } -}; - -/* - * Host <-> LPU mailbox command/status registers - */ -static struct { u32 hfn, lpu; } iocreg_mbcmd[] = { - - { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT }, - { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT } -}; - -static void -bfa_ioc_cb_reg_init(struct bfa_ioc_s *ioc) -{ - void __iomem *rb; - int pcifn = bfa_ioc_pcifn(ioc); - - rb = bfa_ioc_bar0(ioc); - - ioc->ioc_regs.hfn_mbox = rb + iocreg_fnreg[pcifn].hfn_mbox; - ioc->ioc_regs.lpu_mbox = rb + iocreg_fnreg[pcifn].lpu_mbox; - ioc->ioc_regs.host_page_num_fn = rb + iocreg_fnreg[pcifn].hfn_pgn; - - if (ioc->port_id == 0) { - ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; - ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; - ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG; - } else { - ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); - ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); - ioc->ioc_regs.alt_ioc_fwstate = (rb + BFA_IOC0_STATE_REG); - } - - /* - * Host <-> LPU mailbox command/status registers - */ - ioc->ioc_regs.hfn_mbox_cmd = rb + iocreg_mbcmd[pcifn].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + iocreg_mbcmd[pcifn].lpu; - - /* - * PSS control registers - */ - ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); - ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_SCLK_CTL_REG); - - /* - * IOC semaphore registers and serialization - */ - ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG); - ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG); - - /* - * sram memory access - */ - ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); - ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CB; - - /* - * err set reg : for notification of hb failure - */ - ioc->ioc_regs.err_set = (rb + ERR_SET_REG); -} - -/* - * Initialize IOC to port mapping. - */ - -static void -bfa_ioc_cb_map_port(struct bfa_ioc_s *ioc) -{ - /* - * For crossbow, port id is same as pci function. - */ - ioc->port_id = bfa_ioc_pcifn(ioc); - - bfa_trc(ioc, ioc->port_id); -} - -/* - * Set interrupt mode for a function: INTX or MSIX - */ -static void -bfa_ioc_cb_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) -{ -} - -/* - * Synchronized IOC failure processing routines - */ -static bfa_boolean_t -bfa_ioc_cb_sync_start(struct bfa_ioc_s *ioc) -{ - return bfa_ioc_cb_sync_complete(ioc); -} - -/* - * Cleanup hw semaphore and usecnt registers - */ -static void -bfa_ioc_cb_ownership_reset(struct bfa_ioc_s *ioc) -{ - - /* - * Read the hw sem reg to make sure that it is locked - * before we clear it. If it is not locked, writing 1 - * will lock it instead of clearing it. - */ - readl(ioc->ioc_regs.ioc_sem_reg); - writel(1, ioc->ioc_regs.ioc_sem_reg); -} - -/* - * Synchronized IOC failure processing routines - */ -static void -bfa_ioc_cb_sync_join(struct bfa_ioc_s *ioc) -{ -} - -static void -bfa_ioc_cb_sync_leave(struct bfa_ioc_s *ioc) -{ -} - -static void -bfa_ioc_cb_sync_ack(struct bfa_ioc_s *ioc) -{ - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); -} - -static bfa_boolean_t -bfa_ioc_cb_sync_complete(struct bfa_ioc_s *ioc) -{ - uint32_t fwstate, alt_fwstate; - fwstate = readl(ioc->ioc_regs.ioc_fwstate); - - /* - * At this point, this IOC is hoding the hw sem in the - * start path (fwcheck) OR in the disable/enable path - * OR to check if the other IOC has acknowledged failure. - * - * So, this IOC can be in UNINIT, INITING, DISABLED, FAIL - * or in MEMTEST states. In a normal scenario, this IOC - * can not be in OP state when this function is called. - * - * However, this IOC could still be in OP state when - * the OS driver is starting up, if the OptROM code has - * left it in that state. - * - * If we had marked this IOC's fwstate as BFI_IOC_FAIL - * in the failure case and now, if the fwstate is not - * BFI_IOC_FAIL it implies that the other PCI fn have - * reinitialized the ASIC or this IOC got disabled, so - * return TRUE. - */ - if (fwstate == BFI_IOC_UNINIT || - fwstate == BFI_IOC_INITING || - fwstate == BFI_IOC_DISABLED || - fwstate == BFI_IOC_MEMTEST || - fwstate == BFI_IOC_OP) - return BFA_TRUE; - else { - alt_fwstate = readl(ioc->ioc_regs.alt_ioc_fwstate); - if (alt_fwstate == BFI_IOC_FAIL || - alt_fwstate == BFI_IOC_DISABLED || - alt_fwstate == BFI_IOC_UNINIT || - alt_fwstate == BFI_IOC_INITING || - alt_fwstate == BFI_IOC_MEMTEST) - return BFA_TRUE; - else - return BFA_FALSE; - } -} - -bfa_status_t -bfa_ioc_cb_pll_init(void __iomem *rb, enum bfi_asic_mode fcmode) -{ - u32 pll_sclk, pll_fclk; - - pll_sclk = __APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN | - __APP_PLL_SCLK_P0_1(3U) | - __APP_PLL_SCLK_JITLMT0_1(3U) | - __APP_PLL_SCLK_CNTLMT0_1(3U); - pll_fclk = __APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN | - __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) | - __APP_PLL_LCLK_JITLMT0_1(3U) | - __APP_PLL_LCLK_CNTLMT0_1(3U); - writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG)); - writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG)); - writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); - writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); - writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); - writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); - writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); - writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); - writel(__APP_PLL_SCLK_LOGIC_SOFT_RESET, rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_SCLK_BYPASS | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_LCLK_LOGIC_SOFT_RESET, rb + APP_PLL_LCLK_CTL_REG); - writel(__APP_PLL_LCLK_BYPASS | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); - udelay(2); - writel(__APP_PLL_SCLK_LOGIC_SOFT_RESET, rb + APP_PLL_SCLK_CTL_REG); - writel(__APP_PLL_LCLK_LOGIC_SOFT_RESET, rb + APP_PLL_LCLK_CTL_REG); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); - udelay(2000); - writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); - writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); - writel(pll_sclk, (rb + APP_PLL_SCLK_CTL_REG)); - writel(pll_fclk, (rb + APP_PLL_LCLK_CTL_REG)); - - return BFA_STATUS_OK; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_ct.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_ct.c deleted file mode 100644 index 2eb0c6a2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_ioc_ct.c +++ /dev/null @@ -1,921 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfa_ioc.h" -#include "bfi_reg.h" -#include "bfa_defs.h" - -BFA_TRC_FILE(CNA, IOC_CT); - -#define bfa_ioc_ct_sync_pos(__ioc) \ - ((uint32_t) (1 << bfa_ioc_pcifn(__ioc))) -#define BFA_IOC_SYNC_REQD_SH 16 -#define bfa_ioc_ct_get_sync_ackd(__val) (__val & 0x0000ffff) -#define bfa_ioc_ct_clear_sync_ackd(__val) (__val & 0xffff0000) -#define bfa_ioc_ct_get_sync_reqd(__val) (__val >> BFA_IOC_SYNC_REQD_SH) -#define bfa_ioc_ct_sync_reqd_pos(__ioc) \ - (bfa_ioc_ct_sync_pos(__ioc) << BFA_IOC_SYNC_REQD_SH) - -/* - * forward declarations - */ -static bfa_boolean_t bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc); -static void bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc); -static void bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc); -static void bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc); -static bfa_boolean_t bfa_ioc_ct_sync_start(struct bfa_ioc_s *ioc); -static void bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc); -static void bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc); -static void bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc); -static bfa_boolean_t bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc); - -static struct bfa_ioc_hwif_s hwif_ct; -static struct bfa_ioc_hwif_s hwif_ct2; - -/* - * Return true if firmware of current driver matches the running firmware. - */ -static bfa_boolean_t -bfa_ioc_ct_firmware_lock(struct bfa_ioc_s *ioc) -{ - enum bfi_ioc_state ioc_fwstate; - u32 usecnt; - struct bfi_ioc_image_hdr_s fwhdr; - - /* - * If bios boot (flash based) -- do not increment usage count - */ - if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) < - BFA_IOC_FWIMG_MINSZ) - return BFA_TRUE; - - bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); - usecnt = readl(ioc->ioc_regs.ioc_usage_reg); - - /* - * If usage count is 0, always return TRUE. - */ - if (usecnt == 0) { - writel(1, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); - writel(1, ioc->ioc_regs.ioc_usage_sem_reg); - writel(0, ioc->ioc_regs.ioc_fail_sync); - bfa_trc(ioc, usecnt); - return BFA_TRUE; - } - - ioc_fwstate = readl(ioc->ioc_regs.ioc_fwstate); - bfa_trc(ioc, ioc_fwstate); - - /* - * Use count cannot be non-zero and chip in uninitialized state. - */ - WARN_ON(ioc_fwstate == BFI_IOC_UNINIT); - - /* - * Check if another driver with a different firmware is active - */ - bfa_ioc_fwver_get(ioc, &fwhdr); - if (!bfa_ioc_fwver_cmp(ioc, &fwhdr)) { - readl(ioc->ioc_regs.ioc_usage_sem_reg); - writel(1, ioc->ioc_regs.ioc_usage_sem_reg); - bfa_trc(ioc, usecnt); - return BFA_FALSE; - } - - /* - * Same firmware version. Increment the reference count. - */ - usecnt++; - writel(usecnt, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); - writel(1, ioc->ioc_regs.ioc_usage_sem_reg); - bfa_trc(ioc, usecnt); - return BFA_TRUE; -} - -static void -bfa_ioc_ct_firmware_unlock(struct bfa_ioc_s *ioc) -{ - u32 usecnt; - - /* - * If bios boot (flash based) -- do not decrement usage count - */ - if (bfa_cb_image_get_size(bfa_ioc_asic_gen(ioc)) < - BFA_IOC_FWIMG_MINSZ) - return; - - /* - * decrement usage count - */ - bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); - usecnt = readl(ioc->ioc_regs.ioc_usage_reg); - WARN_ON(usecnt <= 0); - - usecnt--; - writel(usecnt, ioc->ioc_regs.ioc_usage_reg); - bfa_trc(ioc, usecnt); - - readl(ioc->ioc_regs.ioc_usage_sem_reg); - writel(1, ioc->ioc_regs.ioc_usage_sem_reg); -} - -/* - * Notify other functions on HB failure. - */ -static void -bfa_ioc_ct_notify_fail(struct bfa_ioc_s *ioc) -{ - if (bfa_ioc_is_cna(ioc)) { - writel(__FW_INIT_HALT_P, ioc->ioc_regs.ll_halt); - writel(__FW_INIT_HALT_P, ioc->ioc_regs.alt_ll_halt); - /* Wait for halt to take effect */ - readl(ioc->ioc_regs.ll_halt); - readl(ioc->ioc_regs.alt_ll_halt); - } else { - writel(~0U, ioc->ioc_regs.err_set); - readl(ioc->ioc_regs.err_set); - } -} - -/* - * Host to LPU mailbox message addresses - */ -static struct { u32 hfn_mbox, lpu_mbox, hfn_pgn; } ct_fnreg[] = { - { HOSTFN0_LPU_MBOX0_0, LPU_HOSTFN0_MBOX0_0, HOST_PAGE_NUM_FN0 }, - { HOSTFN1_LPU_MBOX0_8, LPU_HOSTFN1_MBOX0_8, HOST_PAGE_NUM_FN1 }, - { HOSTFN2_LPU_MBOX0_0, LPU_HOSTFN2_MBOX0_0, HOST_PAGE_NUM_FN2 }, - { HOSTFN3_LPU_MBOX0_8, LPU_HOSTFN3_MBOX0_8, HOST_PAGE_NUM_FN3 } -}; - -/* - * Host <-> LPU mailbox command/status registers - port 0 - */ -static struct { u32 hfn, lpu; } ct_p0reg[] = { - { HOSTFN0_LPU0_CMD_STAT, LPU0_HOSTFN0_CMD_STAT }, - { HOSTFN1_LPU0_CMD_STAT, LPU0_HOSTFN1_CMD_STAT }, - { HOSTFN2_LPU0_CMD_STAT, LPU0_HOSTFN2_CMD_STAT }, - { HOSTFN3_LPU0_CMD_STAT, LPU0_HOSTFN3_CMD_STAT } -}; - -/* - * Host <-> LPU mailbox command/status registers - port 1 - */ -static struct { u32 hfn, lpu; } ct_p1reg[] = { - { HOSTFN0_LPU1_CMD_STAT, LPU1_HOSTFN0_CMD_STAT }, - { HOSTFN1_LPU1_CMD_STAT, LPU1_HOSTFN1_CMD_STAT }, - { HOSTFN2_LPU1_CMD_STAT, LPU1_HOSTFN2_CMD_STAT }, - { HOSTFN3_LPU1_CMD_STAT, LPU1_HOSTFN3_CMD_STAT } -}; - -static struct { uint32_t hfn_mbox, lpu_mbox, hfn_pgn, hfn, lpu, lpu_read; } - ct2_reg[] = { - { CT2_HOSTFN_LPU0_MBOX0, CT2_LPU0_HOSTFN_MBOX0, CT2_HOSTFN_PAGE_NUM, - CT2_HOSTFN_LPU0_CMD_STAT, CT2_LPU0_HOSTFN_CMD_STAT, - CT2_HOSTFN_LPU0_READ_STAT}, - { CT2_HOSTFN_LPU1_MBOX0, CT2_LPU1_HOSTFN_MBOX0, CT2_HOSTFN_PAGE_NUM, - CT2_HOSTFN_LPU1_CMD_STAT, CT2_LPU1_HOSTFN_CMD_STAT, - CT2_HOSTFN_LPU1_READ_STAT}, -}; - -static void -bfa_ioc_ct_reg_init(struct bfa_ioc_s *ioc) -{ - void __iomem *rb; - int pcifn = bfa_ioc_pcifn(ioc); - - rb = bfa_ioc_bar0(ioc); - - ioc->ioc_regs.hfn_mbox = rb + ct_fnreg[pcifn].hfn_mbox; - ioc->ioc_regs.lpu_mbox = rb + ct_fnreg[pcifn].lpu_mbox; - ioc->ioc_regs.host_page_num_fn = rb + ct_fnreg[pcifn].hfn_pgn; - - if (ioc->port_id == 0) { - ioc->ioc_regs.heartbeat = rb + BFA_IOC0_HBEAT_REG; - ioc->ioc_regs.ioc_fwstate = rb + BFA_IOC0_STATE_REG; - ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC1_STATE_REG; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct_p0reg[pcifn].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct_p0reg[pcifn].lpu; - ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; - ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1; - } else { - ioc->ioc_regs.heartbeat = (rb + BFA_IOC1_HBEAT_REG); - ioc->ioc_regs.ioc_fwstate = (rb + BFA_IOC1_STATE_REG); - ioc->ioc_regs.alt_ioc_fwstate = rb + BFA_IOC0_STATE_REG; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct_p1reg[pcifn].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct_p1reg[pcifn].lpu; - ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; - ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0; - } - - /* - * PSS control registers - */ - ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); - ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + APP_PLL_SCLK_CTL_REG); - - /* - * IOC semaphore registers and serialization - */ - ioc->ioc_regs.ioc_sem_reg = (rb + HOST_SEM0_REG); - ioc->ioc_regs.ioc_usage_sem_reg = (rb + HOST_SEM1_REG); - ioc->ioc_regs.ioc_init_sem_reg = (rb + HOST_SEM2_REG); - ioc->ioc_regs.ioc_usage_reg = (rb + BFA_FW_USE_COUNT); - ioc->ioc_regs.ioc_fail_sync = (rb + BFA_IOC_FAIL_SYNC); - - /* - * sram memory access - */ - ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); - ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT; - - /* - * err set reg : for notification of hb failure in fcmode - */ - ioc->ioc_regs.err_set = (rb + ERR_SET_REG); -} - -static void -bfa_ioc_ct2_reg_init(struct bfa_ioc_s *ioc) -{ - void __iomem *rb; - int port = bfa_ioc_portid(ioc); - - rb = bfa_ioc_bar0(ioc); - - ioc->ioc_regs.hfn_mbox = rb + ct2_reg[port].hfn_mbox; - ioc->ioc_regs.lpu_mbox = rb + ct2_reg[port].lpu_mbox; - ioc->ioc_regs.host_page_num_fn = rb + ct2_reg[port].hfn_pgn; - ioc->ioc_regs.hfn_mbox_cmd = rb + ct2_reg[port].hfn; - ioc->ioc_regs.lpu_mbox_cmd = rb + ct2_reg[port].lpu; - ioc->ioc_regs.lpu_read_stat = rb + ct2_reg[port].lpu_read; - - if (port == 0) { - ioc->ioc_regs.heartbeat = rb + CT2_BFA_IOC0_HBEAT_REG; - ioc->ioc_regs.ioc_fwstate = rb + CT2_BFA_IOC0_STATE_REG; - ioc->ioc_regs.alt_ioc_fwstate = rb + CT2_BFA_IOC1_STATE_REG; - ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P0; - ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P1; - } else { - ioc->ioc_regs.heartbeat = (rb + CT2_BFA_IOC1_HBEAT_REG); - ioc->ioc_regs.ioc_fwstate = (rb + CT2_BFA_IOC1_STATE_REG); - ioc->ioc_regs.alt_ioc_fwstate = rb + CT2_BFA_IOC0_STATE_REG; - ioc->ioc_regs.ll_halt = rb + FW_INIT_HALT_P1; - ioc->ioc_regs.alt_ll_halt = rb + FW_INIT_HALT_P0; - } - - /* - * PSS control registers - */ - ioc->ioc_regs.pss_ctl_reg = (rb + PSS_CTL_REG); - ioc->ioc_regs.pss_err_status_reg = (rb + PSS_ERR_STATUS_REG); - ioc->ioc_regs.app_pll_fast_ctl_reg = (rb + CT2_APP_PLL_LCLK_CTL_REG); - ioc->ioc_regs.app_pll_slow_ctl_reg = (rb + CT2_APP_PLL_SCLK_CTL_REG); - - /* - * IOC semaphore registers and serialization - */ - ioc->ioc_regs.ioc_sem_reg = (rb + CT2_HOST_SEM0_REG); - ioc->ioc_regs.ioc_usage_sem_reg = (rb + CT2_HOST_SEM1_REG); - ioc->ioc_regs.ioc_init_sem_reg = (rb + CT2_HOST_SEM2_REG); - ioc->ioc_regs.ioc_usage_reg = (rb + CT2_BFA_FW_USE_COUNT); - ioc->ioc_regs.ioc_fail_sync = (rb + CT2_BFA_IOC_FAIL_SYNC); - - /* - * sram memory access - */ - ioc->ioc_regs.smem_page_start = (rb + PSS_SMEM_PAGE_START); - ioc->ioc_regs.smem_pg0 = BFI_IOC_SMEM_PG0_CT; - - /* - * err set reg : for notification of hb failure in fcmode - */ - ioc->ioc_regs.err_set = (rb + ERR_SET_REG); -} - -/* - * Initialize IOC to port mapping. - */ - -#define FNC_PERS_FN_SHIFT(__fn) ((__fn) * 8) -static void -bfa_ioc_ct_map_port(struct bfa_ioc_s *ioc) -{ - void __iomem *rb = ioc->pcidev.pci_bar_kva; - u32 r32; - - /* - * For catapult, base port id on personality register and IOC type - */ - r32 = readl(rb + FNC_PERS_REG); - r32 >>= FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc)); - ioc->port_id = (r32 & __F0_PORT_MAP_MK) >> __F0_PORT_MAP_SH; - - bfa_trc(ioc, bfa_ioc_pcifn(ioc)); - bfa_trc(ioc, ioc->port_id); -} - -static void -bfa_ioc_ct2_map_port(struct bfa_ioc_s *ioc) -{ - void __iomem *rb = ioc->pcidev.pci_bar_kva; - u32 r32; - - r32 = readl(rb + CT2_HOSTFN_PERSONALITY0); - ioc->port_id = ((r32 & __FC_LL_PORT_MAP__MK) >> __FC_LL_PORT_MAP__SH); - - bfa_trc(ioc, bfa_ioc_pcifn(ioc)); - bfa_trc(ioc, ioc->port_id); -} - -/* - * Set interrupt mode for a function: INTX or MSIX - */ -static void -bfa_ioc_ct_isr_mode_set(struct bfa_ioc_s *ioc, bfa_boolean_t msix) -{ - void __iomem *rb = ioc->pcidev.pci_bar_kva; - u32 r32, mode; - - r32 = readl(rb + FNC_PERS_REG); - bfa_trc(ioc, r32); - - mode = (r32 >> FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))) & - __F0_INTX_STATUS; - - /* - * If already in desired mode, do not change anything - */ - if ((!msix && mode) || (msix && !mode)) - return; - - if (msix) - mode = __F0_INTX_STATUS_MSIX; - else - mode = __F0_INTX_STATUS_INTA; - - r32 &= ~(__F0_INTX_STATUS << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))); - r32 |= (mode << FNC_PERS_FN_SHIFT(bfa_ioc_pcifn(ioc))); - bfa_trc(ioc, r32); - - writel(r32, rb + FNC_PERS_REG); -} - -bfa_boolean_t -bfa_ioc_ct2_lpu_read_stat(struct bfa_ioc_s *ioc) -{ - u32 r32; - - r32 = readl(ioc->ioc_regs.lpu_read_stat); - if (r32) { - writel(1, ioc->ioc_regs.lpu_read_stat); - return BFA_TRUE; - } - - return BFA_FALSE; -} - -/* - * Cleanup hw semaphore and usecnt registers - */ -static void -bfa_ioc_ct_ownership_reset(struct bfa_ioc_s *ioc) -{ - - if (bfa_ioc_is_cna(ioc)) { - bfa_ioc_sem_get(ioc->ioc_regs.ioc_usage_sem_reg); - writel(0, ioc->ioc_regs.ioc_usage_reg); - readl(ioc->ioc_regs.ioc_usage_sem_reg); - writel(1, ioc->ioc_regs.ioc_usage_sem_reg); - } - - /* - * Read the hw sem reg to make sure that it is locked - * before we clear it. If it is not locked, writing 1 - * will lock it instead of clearing it. - */ - readl(ioc->ioc_regs.ioc_sem_reg); - writel(1, ioc->ioc_regs.ioc_sem_reg); -} - -static bfa_boolean_t -bfa_ioc_ct_sync_start(struct bfa_ioc_s *ioc) -{ - uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); - uint32_t sync_reqd = bfa_ioc_ct_get_sync_reqd(r32); - - /* - * Driver load time. If the sync required bit for this PCI fn - * is set, it is due to an unclean exit by the driver for this - * PCI fn in the previous incarnation. Whoever comes here first - * should clean it up, no matter which PCI fn. - */ - - if (sync_reqd & bfa_ioc_ct_sync_pos(ioc)) { - writel(0, ioc->ioc_regs.ioc_fail_sync); - writel(1, ioc->ioc_regs.ioc_usage_reg); - writel(BFI_IOC_UNINIT, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_UNINIT, ioc->ioc_regs.alt_ioc_fwstate); - return BFA_TRUE; - } - - return bfa_ioc_ct_sync_complete(ioc); -} - -/* - * Synchronized IOC failure processing routines - */ -static void -bfa_ioc_ct_sync_join(struct bfa_ioc_s *ioc) -{ - uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); - uint32_t sync_pos = bfa_ioc_ct_sync_reqd_pos(ioc); - - writel((r32 | sync_pos), ioc->ioc_regs.ioc_fail_sync); -} - -static void -bfa_ioc_ct_sync_leave(struct bfa_ioc_s *ioc) -{ - uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); - uint32_t sync_msk = bfa_ioc_ct_sync_reqd_pos(ioc) | - bfa_ioc_ct_sync_pos(ioc); - - writel((r32 & ~sync_msk), ioc->ioc_regs.ioc_fail_sync); -} - -static void -bfa_ioc_ct_sync_ack(struct bfa_ioc_s *ioc) -{ - uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); - - writel((r32 | bfa_ioc_ct_sync_pos(ioc)), - ioc->ioc_regs.ioc_fail_sync); -} - -static bfa_boolean_t -bfa_ioc_ct_sync_complete(struct bfa_ioc_s *ioc) -{ - uint32_t r32 = readl(ioc->ioc_regs.ioc_fail_sync); - uint32_t sync_reqd = bfa_ioc_ct_get_sync_reqd(r32); - uint32_t sync_ackd = bfa_ioc_ct_get_sync_ackd(r32); - uint32_t tmp_ackd; - - if (sync_ackd == 0) - return BFA_TRUE; - - /* - * The check below is to see whether any other PCI fn - * has reinitialized the ASIC (reset sync_ackd bits) - * and failed again while this IOC was waiting for hw - * semaphore (in bfa_iocpf_sm_semwait()). - */ - tmp_ackd = sync_ackd; - if ((sync_reqd & bfa_ioc_ct_sync_pos(ioc)) && - !(sync_ackd & bfa_ioc_ct_sync_pos(ioc))) - sync_ackd |= bfa_ioc_ct_sync_pos(ioc); - - if (sync_reqd == sync_ackd) { - writel(bfa_ioc_ct_clear_sync_ackd(r32), - ioc->ioc_regs.ioc_fail_sync); - writel(BFI_IOC_FAIL, ioc->ioc_regs.ioc_fwstate); - writel(BFI_IOC_FAIL, ioc->ioc_regs.alt_ioc_fwstate); - return BFA_TRUE; - } - - /* - * If another PCI fn reinitialized and failed again while - * this IOC was waiting for hw sem, the sync_ackd bit for - * this IOC need to be set again to allow reinitialization. - */ - if (tmp_ackd != sync_ackd) - writel((r32 | sync_ackd), ioc->ioc_regs.ioc_fail_sync); - - return BFA_FALSE; -} - -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -static void -bfa_ioc_set_ctx_hwif(struct bfa_ioc_s *ioc, struct bfa_ioc_hwif_s *hwif) -{ - hwif->ioc_firmware_lock = bfa_ioc_ct_firmware_lock; - hwif->ioc_firmware_unlock = bfa_ioc_ct_firmware_unlock; - hwif->ioc_notify_fail = bfa_ioc_ct_notify_fail; - hwif->ioc_ownership_reset = bfa_ioc_ct_ownership_reset; - hwif->ioc_sync_start = bfa_ioc_ct_sync_start; - hwif->ioc_sync_join = bfa_ioc_ct_sync_join; - hwif->ioc_sync_leave = bfa_ioc_ct_sync_leave; - hwif->ioc_sync_ack = bfa_ioc_ct_sync_ack; - hwif->ioc_sync_complete = bfa_ioc_ct_sync_complete; -} - -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -void -bfa_ioc_set_ct_hwif(struct bfa_ioc_s *ioc) -{ - bfa_ioc_set_ctx_hwif(ioc, &hwif_ct); - - hwif_ct.ioc_pll_init = bfa_ioc_ct_pll_init; - hwif_ct.ioc_reg_init = bfa_ioc_ct_reg_init; - hwif_ct.ioc_map_port = bfa_ioc_ct_map_port; - hwif_ct.ioc_isr_mode_set = bfa_ioc_ct_isr_mode_set; - ioc->ioc_hwif = &hwif_ct; -} - -/** - * Called from bfa_ioc_attach() to map asic specific calls. - */ -void -bfa_ioc_set_ct2_hwif(struct bfa_ioc_s *ioc) -{ - bfa_ioc_set_ctx_hwif(ioc, &hwif_ct2); - - hwif_ct2.ioc_pll_init = bfa_ioc_ct2_pll_init; - hwif_ct2.ioc_reg_init = bfa_ioc_ct2_reg_init; - hwif_ct2.ioc_map_port = bfa_ioc_ct2_map_port; - hwif_ct2.ioc_lpu_read_stat = bfa_ioc_ct2_lpu_read_stat; - hwif_ct2.ioc_isr_mode_set = NULL; - ioc->ioc_hwif = &hwif_ct2; -} - -/* - * Workaround for MSI-X resource allocation for catapult-2 with no asic block - */ -#define HOSTFN_MSIX_DEFAULT 64 -#define HOSTFN_MSIX_VT_INDEX_MBOX_ERR 0x30138 -#define HOSTFN_MSIX_VT_OFST_NUMVT 0x3013c -#define __MSIX_VT_NUMVT__MK 0x003ff800 -#define __MSIX_VT_NUMVT__SH 11 -#define __MSIX_VT_NUMVT_(_v) ((_v) << __MSIX_VT_NUMVT__SH) -#define __MSIX_VT_OFST_ 0x000007ff -void -bfa_ioc_ct2_poweron(struct bfa_ioc_s *ioc) -{ - void __iomem *rb = ioc->pcidev.pci_bar_kva; - u32 r32; - - r32 = readl(rb + HOSTFN_MSIX_VT_OFST_NUMVT); - if (r32 & __MSIX_VT_NUMVT__MK) { - writel(r32 & __MSIX_VT_OFST_, - rb + HOSTFN_MSIX_VT_INDEX_MBOX_ERR); - return; - } - - writel(__MSIX_VT_NUMVT_(HOSTFN_MSIX_DEFAULT - 1) | - HOSTFN_MSIX_DEFAULT * bfa_ioc_pcifn(ioc), - rb + HOSTFN_MSIX_VT_OFST_NUMVT); - writel(HOSTFN_MSIX_DEFAULT * bfa_ioc_pcifn(ioc), - rb + HOSTFN_MSIX_VT_INDEX_MBOX_ERR); -} - -bfa_status_t -bfa_ioc_ct_pll_init(void __iomem *rb, enum bfi_asic_mode mode) -{ - u32 pll_sclk, pll_fclk, r32; - bfa_boolean_t fcmode = (mode == BFI_ASIC_MODE_FC); - - pll_sclk = __APP_PLL_SCLK_LRESETN | __APP_PLL_SCLK_ENARST | - __APP_PLL_SCLK_RSEL200500 | __APP_PLL_SCLK_P0_1(3U) | - __APP_PLL_SCLK_JITLMT0_1(3U) | - __APP_PLL_SCLK_CNTLMT0_1(1U); - pll_fclk = __APP_PLL_LCLK_LRESETN | __APP_PLL_LCLK_ENARST | - __APP_PLL_LCLK_RSEL200500 | __APP_PLL_LCLK_P0_1(3U) | - __APP_PLL_LCLK_JITLMT0_1(3U) | - __APP_PLL_LCLK_CNTLMT0_1(1U); - - if (fcmode) { - writel(0, (rb + OP_MODE)); - writel(__APP_EMS_CMLCKSEL | __APP_EMS_REFCKBUFEN2 | - __APP_EMS_CHANNEL_SEL, (rb + ETH_MAC_SER_REG)); - } else { - writel(__GLOBAL_FCOE_MODE, (rb + OP_MODE)); - writel(__APP_EMS_REFCKBUFEN1, (rb + ETH_MAC_SER_REG)); - } - writel(BFI_IOC_UNINIT, (rb + BFA_IOC0_STATE_REG)); - writel(BFI_IOC_UNINIT, (rb + BFA_IOC1_STATE_REG)); - writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); - writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); - writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); - writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); - writel(0xffffffffU, (rb + HOSTFN0_INT_MSK)); - writel(0xffffffffU, (rb + HOSTFN1_INT_MSK)); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET, - rb + APP_PLL_LCLK_CTL_REG); - writel(pll_sclk | __APP_PLL_SCLK_LOGIC_SOFT_RESET | - __APP_PLL_SCLK_ENABLE, rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_LOGIC_SOFT_RESET | - __APP_PLL_LCLK_ENABLE, rb + APP_PLL_LCLK_CTL_REG); - readl(rb + HOSTFN0_INT_MSK); - udelay(2000); - writel(0xffffffffU, (rb + HOSTFN0_INT_STATUS)); - writel(0xffffffffU, (rb + HOSTFN1_INT_STATUS)); - writel(pll_sclk | __APP_PLL_SCLK_ENABLE, rb + APP_PLL_SCLK_CTL_REG); - writel(pll_fclk | __APP_PLL_LCLK_ENABLE, rb + APP_PLL_LCLK_CTL_REG); - - if (!fcmode) { - writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P0)); - writel(__PMM_1T_RESET_P, (rb + PMM_1T_RESET_REG_P1)); - } - r32 = readl((rb + PSS_CTL_REG)); - r32 &= ~__PSS_LMEM_RESET; - writel(r32, (rb + PSS_CTL_REG)); - udelay(1000); - if (!fcmode) { - writel(0, (rb + PMM_1T_RESET_REG_P0)); - writel(0, (rb + PMM_1T_RESET_REG_P1)); - } - - writel(__EDRAM_BISTR_START, (rb + MBIST_CTL_REG)); - udelay(1000); - r32 = readl((rb + MBIST_STAT_REG)); - writel(0, (rb + MBIST_CTL_REG)); - return BFA_STATUS_OK; -} - -static void -bfa_ioc_ct2_sclk_init(void __iomem *rb) -{ - u32 r32; - - /* - * put s_clk PLL and PLL FSM in reset - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= ~(__APP_PLL_SCLK_ENABLE | __APP_PLL_SCLK_LRESETN); - r32 |= (__APP_PLL_SCLK_ENARST | __APP_PLL_SCLK_BYPASS | - __APP_PLL_SCLK_LOGIC_SOFT_RESET); - writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * Ignore mode and program for the max clock (which is FC16) - * Firmware/NFC will do the PLL init appropiately - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= ~(__APP_PLL_SCLK_REFCLK_SEL | __APP_PLL_SCLK_CLK_DIV2); - writel(r32, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * while doing PLL init dont clock gate ethernet subsystem - */ - r32 = readl((rb + CT2_CHIP_MISC_PRG)); - writel(r32 | __ETH_CLK_ENABLE_PORT0, (rb + CT2_CHIP_MISC_PRG)); - - r32 = readl((rb + CT2_PCIE_MISC_REG)); - writel(r32 | __ETH_CLK_ENABLE_PORT1, (rb + CT2_PCIE_MISC_REG)); - - /* - * set sclk value - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - r32 &= (__P_SCLK_PLL_LOCK | __APP_PLL_SCLK_REFCLK_SEL | - __APP_PLL_SCLK_CLK_DIV2); - writel(r32 | 0x1061731b, (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * poll for s_clk lock or delay 1ms - */ - udelay(1000); -} - -static void -bfa_ioc_ct2_lclk_init(void __iomem *rb) -{ - u32 r32; - - /* - * put l_clk PLL and PLL FSM in reset - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - r32 &= ~(__APP_PLL_LCLK_ENABLE | __APP_PLL_LCLK_LRESETN); - r32 |= (__APP_PLL_LCLK_ENARST | __APP_PLL_LCLK_BYPASS | - __APP_PLL_LCLK_LOGIC_SOFT_RESET); - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * set LPU speed (set for FC16 which will work for other modes) - */ - r32 = readl((rb + CT2_CHIP_MISC_PRG)); - writel(r32, (rb + CT2_CHIP_MISC_PRG)); - - /* - * set LPU half speed (set for FC16 which will work for other modes) - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * set lclk for mode (set for FC16) - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - r32 &= (__P_LCLK_PLL_LOCK | __APP_LPUCLK_HALFSPEED); - r32 |= 0x20c1731b; - writel(r32, (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* - * poll for s_clk lock or delay 1ms - */ - udelay(1000); -} - -static void -bfa_ioc_ct2_mem_init(void __iomem *rb) -{ - u32 r32; - - r32 = readl((rb + PSS_CTL_REG)); - r32 &= ~__PSS_LMEM_RESET; - writel(r32, (rb + PSS_CTL_REG)); - udelay(1000); - - writel(__EDRAM_BISTR_START, (rb + CT2_MBIST_CTL_REG)); - udelay(1000); - writel(0, (rb + CT2_MBIST_CTL_REG)); -} - -void -bfa_ioc_ct2_mac_reset(void __iomem *rb) -{ - u32 r32; - - bfa_ioc_ct2_sclk_init(rb); - bfa_ioc_ct2_lclk_init(rb); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_SCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl((rb + CT2_APP_PLL_LCLK_CTL_REG)); - writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_LCLK_CTL_REG)); - - /* put port0, port1 MAC & AHB in reset */ - writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET), - rb + CT2_CSI_MAC_CONTROL_REG(0)); - writel((__CSI_MAC_RESET | __CSI_MAC_AHB_RESET), - rb + CT2_CSI_MAC_CONTROL_REG(1)); -} - -#define CT2_NFC_MAX_DELAY 1000 -#define CT2_NFC_VER_VALID 0x143 -#define BFA_IOC_PLL_POLL 1000000 - -static bfa_boolean_t -bfa_ioc_ct2_nfc_halted(void __iomem *rb) -{ - u32 r32; - - r32 = readl(rb + CT2_NFC_CSR_SET_REG); - if (r32 & __NFC_CONTROLLER_HALTED) - return BFA_TRUE; - - return BFA_FALSE; -} - -static void -bfa_ioc_ct2_nfc_resume(void __iomem *rb) -{ - u32 r32; - int i; - - writel(__HALT_NFC_CONTROLLER, rb + CT2_NFC_CSR_CLR_REG); - for (i = 0; i < CT2_NFC_MAX_DELAY; i++) { - r32 = readl(rb + CT2_NFC_CSR_SET_REG); - if (!(r32 & __NFC_CONTROLLER_HALTED)) - return; - udelay(1000); - } - WARN_ON(1); -} - -bfa_status_t -bfa_ioc_ct2_pll_init(void __iomem *rb, enum bfi_asic_mode mode) -{ - u32 wgn, r32, nfc_ver, i; - - wgn = readl(rb + CT2_WGN_STATUS); - nfc_ver = readl(rb + CT2_RSC_GPR15_REG); - - if ((wgn == (__A2T_AHB_LOAD | __WGN_READY)) && - (nfc_ver >= CT2_NFC_VER_VALID)) { - if (bfa_ioc_ct2_nfc_halted(rb)) - bfa_ioc_ct2_nfc_resume(rb); - - writel(__RESET_AND_START_SCLK_LCLK_PLLS, - rb + CT2_CSI_FW_CTL_SET_REG); - - for (i = 0; i < BFA_IOC_PLL_POLL; i++) { - r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG); - if (r32 & __RESET_AND_START_SCLK_LCLK_PLLS) - break; - } - - WARN_ON(!(r32 & __RESET_AND_START_SCLK_LCLK_PLLS)); - - for (i = 0; i < BFA_IOC_PLL_POLL; i++) { - r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG); - if (!(r32 & __RESET_AND_START_SCLK_LCLK_PLLS)) - break; - } - - WARN_ON(r32 & __RESET_AND_START_SCLK_LCLK_PLLS); - udelay(1000); - - r32 = readl(rb + CT2_CSI_FW_CTL_REG); - WARN_ON(r32 & __RESET_AND_START_SCLK_LCLK_PLLS); - } else { - writel(__HALT_NFC_CONTROLLER, rb + CT2_NFC_CSR_SET_REG); - for (i = 0; i < CT2_NFC_MAX_DELAY; i++) { - r32 = readl(rb + CT2_NFC_CSR_SET_REG); - if (r32 & __NFC_CONTROLLER_HALTED) - break; - udelay(1000); - } - - bfa_ioc_ct2_mac_reset(rb); - bfa_ioc_ct2_sclk_init(rb); - bfa_ioc_ct2_lclk_init(rb); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl(rb + CT2_APP_PLL_SCLK_CTL_REG); - writel(r32 & ~__APP_PLL_SCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_SCLK_CTL_REG)); - - /* - * release soft reset on s_clk & l_clk - */ - r32 = readl(rb + CT2_APP_PLL_LCLK_CTL_REG); - writel(r32 & ~__APP_PLL_LCLK_LOGIC_SOFT_RESET, - (rb + CT2_APP_PLL_LCLK_CTL_REG)); - } - - /* - * Announce flash device presence, if flash was corrupted. - */ - if (wgn == (__WGN_READY | __GLBL_PF_VF_CFG_RDY)) { - r32 = readl(rb + PSS_GPIO_OUT_REG); - writel(r32 & ~1, (rb + PSS_GPIO_OUT_REG)); - r32 = readl(rb + PSS_GPIO_OE_REG); - writel(r32 | 1, (rb + PSS_GPIO_OE_REG)); - } - - /* - * Mask the interrupts and clear any - * pending interrupts. - */ - writel(1, (rb + CT2_LPU0_HOSTFN_MBOX0_MSK)); - writel(1, (rb + CT2_LPU1_HOSTFN_MBOX0_MSK)); - - /* For first time initialization, no need to clear interrupts */ - r32 = readl(rb + HOST_SEM5_REG); - if (r32 & 0x1) { - r32 = readl(rb + CT2_LPU0_HOSTFN_CMD_STAT); - if (r32 == 1) { - writel(1, rb + CT2_LPU0_HOSTFN_CMD_STAT); - readl((rb + CT2_LPU0_HOSTFN_CMD_STAT)); - } - r32 = readl(rb + CT2_LPU1_HOSTFN_CMD_STAT); - if (r32 == 1) { - writel(1, rb + CT2_LPU1_HOSTFN_CMD_STAT); - readl(rb + CT2_LPU1_HOSTFN_CMD_STAT); - } - } - - bfa_ioc_ct2_mem_init(rb); - - writel(BFI_IOC_UNINIT, rb + CT2_BFA_IOC0_STATE_REG); - writel(BFI_IOC_UNINIT, rb + CT2_BFA_IOC1_STATE_REG); - - return BFA_STATUS_OK; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_modules.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_modules.h deleted file mode 100644 index 2d36e482..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_modules.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * bfa_modules.h BFA modules - */ - -#ifndef __BFA_MODULES_H__ -#define __BFA_MODULES_H__ - -#include "bfa_cs.h" -#include "bfa.h" -#include "bfa_svc.h" -#include "bfa_fcpim.h" -#include "bfa_port.h" - -struct bfa_modules_s { - struct bfa_fcdiag_s fcdiag; /* fcdiag module */ - struct bfa_fcport_s fcport; /* fc port module */ - struct bfa_fcxp_mod_s fcxp_mod; /* fcxp module */ - struct bfa_lps_mod_s lps_mod; /* fcxp module */ - struct bfa_uf_mod_s uf_mod; /* unsolicited frame module */ - struct bfa_rport_mod_s rport_mod; /* remote port module */ - struct bfa_fcp_mod_s fcp_mod; /* FCP initiator module */ - struct bfa_sgpg_mod_s sgpg_mod; /* SG page module */ - struct bfa_port_s port; /* Physical port module */ - struct bfa_ablk_s ablk; /* ASIC block config module */ - struct bfa_cee_s cee; /* CEE Module */ - struct bfa_sfp_s sfp; /* SFP module */ - struct bfa_flash_s flash; /* flash module */ - struct bfa_diag_s diag_mod; /* diagnostics module */ - struct bfa_phy_s phy; /* phy module */ - struct bfa_dconf_mod_s dconf_mod; /* DCONF common module */ -}; - -/* - * !!! Only append to the enums defined here to avoid any versioning - * !!! needed between trace utility and driver version - */ -enum { - BFA_TRC_HAL_CORE = 1, - BFA_TRC_HAL_FCXP = 2, - BFA_TRC_HAL_FCPIM = 3, - BFA_TRC_HAL_IOCFC_CT = 4, - BFA_TRC_HAL_IOCFC_CB = 5, -}; - -/* - * Macro to define a new BFA module - */ -#define BFA_MODULE(__mod) \ - static void bfa_ ## __mod ## _meminfo( \ - struct bfa_iocfc_cfg_s *cfg, \ - struct bfa_meminfo_s *meminfo, \ - struct bfa_s *bfa); \ - static void bfa_ ## __mod ## _attach(struct bfa_s *bfa, \ - void *bfad, struct bfa_iocfc_cfg_s *cfg, \ - struct bfa_pcidev_s *pcidev); \ - static void bfa_ ## __mod ## _detach(struct bfa_s *bfa); \ - static void bfa_ ## __mod ## _start(struct bfa_s *bfa); \ - static void bfa_ ## __mod ## _stop(struct bfa_s *bfa); \ - static void bfa_ ## __mod ## _iocdisable(struct bfa_s *bfa); \ - \ - extern struct bfa_module_s hal_mod_ ## __mod; \ - struct bfa_module_s hal_mod_ ## __mod = { \ - bfa_ ## __mod ## _meminfo, \ - bfa_ ## __mod ## _attach, \ - bfa_ ## __mod ## _detach, \ - bfa_ ## __mod ## _start, \ - bfa_ ## __mod ## _stop, \ - bfa_ ## __mod ## _iocdisable, \ - } - -#define BFA_CACHELINE_SZ (256) - -/* - * Structure used to interact between different BFA sub modules - * - * Each sub module needs to implement only the entry points relevant to it (and - * can leave entry points as NULL) - */ -struct bfa_module_s { - void (*meminfo) (struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa); - void (*attach) (struct bfa_s *bfa, void *bfad, - struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev); - void (*detach) (struct bfa_s *bfa); - void (*start) (struct bfa_s *bfa); - void (*stop) (struct bfa_s *bfa); - void (*iocdisable) (struct bfa_s *bfa); -}; - - -struct bfa_s { - void *bfad; /* BFA driver instance */ - struct bfa_plog_s *plog; /* portlog buffer */ - struct bfa_trc_mod_s *trcmod; /* driver tracing */ - struct bfa_ioc_s ioc; /* IOC module */ - struct bfa_iocfc_s iocfc; /* IOCFC module */ - struct bfa_timer_mod_s timer_mod; /* timer module */ - struct bfa_modules_s modules; /* BFA modules */ - struct list_head comp_q; /* pending completions */ - bfa_boolean_t queue_process; /* queue processing enabled */ - struct list_head reqq_waitq[BFI_IOC_MAX_CQS]; - bfa_boolean_t fcs; /* FCS is attached to BFA */ - struct bfa_msix_s msix; - int bfa_aen_seq; -}; - -extern bfa_boolean_t bfa_auto_recover; -extern struct bfa_module_s hal_mod_fcdiag; -extern struct bfa_module_s hal_mod_sgpg; -extern struct bfa_module_s hal_mod_fcport; -extern struct bfa_module_s hal_mod_fcxp; -extern struct bfa_module_s hal_mod_lps; -extern struct bfa_module_s hal_mod_uf; -extern struct bfa_module_s hal_mod_rport; -extern struct bfa_module_s hal_mod_fcp; -extern struct bfa_module_s hal_mod_dconf; - -#endif /* __BFA_MODULES_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_plog.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_plog.h deleted file mode 100644 index 1c9baa68..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_plog.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef __BFA_PORTLOG_H__ -#define __BFA_PORTLOG_H__ - -#include "bfa_fc.h" -#include "bfa_defs.h" - -#define BFA_PL_NLOG_ENTS 256 -#define BFA_PL_LOG_REC_INCR(_x) ((_x)++, (_x) %= BFA_PL_NLOG_ENTS) - -#define BFA_PL_STRING_LOG_SZ 32 /* number of chars in string log */ -#define BFA_PL_INT_LOG_SZ 8 /* number of integers in the integer log */ - -enum bfa_plog_log_type { - BFA_PL_LOG_TYPE_INVALID = 0, - BFA_PL_LOG_TYPE_INT = 1, - BFA_PL_LOG_TYPE_STRING = 2, -}; - -/* - * the (fixed size) record format for each entry in the portlog - */ -struct bfa_plog_rec_s { - u64 tv; /* timestamp */ - u8 port; /* Source port that logged this entry */ - u8 mid; /* module id */ - u8 eid; /* indicates Rx, Tx, IOCTL, etc. bfa_plog_eid */ - u8 log_type; /* string/integer log, bfa_plog_log_type_t */ - u8 log_num_ints; - /* - * interpreted only if log_type is INT_LOG. indicates number of - * integers in the int_log[] (0-PL_INT_LOG_SZ). - */ - u8 rsvd; - u16 misc; /* can be used to indicate fc frame length */ - union { - char string_log[BFA_PL_STRING_LOG_SZ]; - u32 int_log[BFA_PL_INT_LOG_SZ]; - } log_entry; - -}; - -/* - * the following #defines will be used by the logging entities to indicate - * their module id. BFAL will convert the integer value to string format - * -* process to be used while changing the following #defines: - * - Always add new entries at the end - * - define corresponding string in BFAL - * - Do not remove any entry or rearrange the order. - */ -enum bfa_plog_mid { - BFA_PL_MID_INVALID = 0, - BFA_PL_MID_DEBUG = 1, - BFA_PL_MID_DRVR = 2, - BFA_PL_MID_HAL = 3, - BFA_PL_MID_HAL_FCXP = 4, - BFA_PL_MID_HAL_UF = 5, - BFA_PL_MID_FCS = 6, - BFA_PL_MID_LPS = 7, - BFA_PL_MID_MAX = 8 -}; - -#define BFA_PL_MID_STRLEN 8 -struct bfa_plog_mid_strings_s { - char m_str[BFA_PL_MID_STRLEN]; -}; - -/* - * the following #defines will be used by the logging entities to indicate - * their event type. BFAL will convert the integer value to string format - * -* process to be used while changing the following #defines: - * - Always add new entries at the end - * - define corresponding string in BFAL - * - Do not remove any entry or rearrange the order. - */ -enum bfa_plog_eid { - BFA_PL_EID_INVALID = 0, - BFA_PL_EID_IOC_DISABLE = 1, - BFA_PL_EID_IOC_ENABLE = 2, - BFA_PL_EID_PORT_DISABLE = 3, - BFA_PL_EID_PORT_ENABLE = 4, - BFA_PL_EID_PORT_ST_CHANGE = 5, - BFA_PL_EID_TX = 6, - BFA_PL_EID_TX_ACK1 = 7, - BFA_PL_EID_TX_RJT = 8, - BFA_PL_EID_TX_BSY = 9, - BFA_PL_EID_RX = 10, - BFA_PL_EID_RX_ACK1 = 11, - BFA_PL_EID_RX_RJT = 12, - BFA_PL_EID_RX_BSY = 13, - BFA_PL_EID_CT_IN = 14, - BFA_PL_EID_CT_OUT = 15, - BFA_PL_EID_DRIVER_START = 16, - BFA_PL_EID_RSCN = 17, - BFA_PL_EID_DEBUG = 18, - BFA_PL_EID_MISC = 19, - BFA_PL_EID_FIP_FCF_DISC = 20, - BFA_PL_EID_FIP_FCF_CVL = 21, - BFA_PL_EID_LOGIN = 22, - BFA_PL_EID_LOGO = 23, - BFA_PL_EID_TRUNK_SCN = 24, - BFA_PL_EID_MAX -}; - -#define BFA_PL_ENAME_STRLEN 8 -struct bfa_plog_eid_strings_s { - char e_str[BFA_PL_ENAME_STRLEN]; -}; - -#define BFA_PL_SIG_LEN 8 -#define BFA_PL_SIG_STR "12pl123" - -/* - * per port circular log buffer - */ -struct bfa_plog_s { - char plog_sig[BFA_PL_SIG_LEN]; /* Start signature */ - u8 plog_enabled; - u8 rsvd[7]; - u32 ticks; - u16 head; - u16 tail; - struct bfa_plog_rec_s plog_recs[BFA_PL_NLOG_ENTS]; -}; - -void bfa_plog_init(struct bfa_plog_s *plog); -void bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, u16 misc, char *log_str); -void bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, u16 misc, - u32 *intarr, u32 num_ints); -void bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr); -void bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, u16 misc, - struct fchs_s *fchdr, u32 pld_w0); - -#endif /* __BFA_PORTLOG_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.c deleted file mode 100644 index 95e4ad87..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.c +++ /dev/null @@ -1,848 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfa_defs_svc.h" -#include "bfa_port.h" -#include "bfi.h" -#include "bfa_ioc.h" - - -BFA_TRC_FILE(CNA, PORT); - -static void -bfa_port_stats_swap(struct bfa_port_s *port, union bfa_port_stats_u *stats) -{ - u32 *dip = (u32 *) stats; - __be32 t0, t1; - int i; - - for (i = 0; i < sizeof(union bfa_port_stats_u)/sizeof(u32); - i += 2) { - t0 = dip[i]; - t1 = dip[i + 1]; -#ifdef __BIG_ENDIAN - dip[i] = be32_to_cpu(t0); - dip[i + 1] = be32_to_cpu(t1); -#else - dip[i] = be32_to_cpu(t1); - dip[i + 1] = be32_to_cpu(t0); -#endif - } -} - -/* - * bfa_port_enable_isr() - * - * - * @param[in] port - Pointer to the port module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_port_enable_isr(struct bfa_port_s *port, bfa_status_t status) -{ - bfa_trc(port, status); - port->endis_pending = BFA_FALSE; - port->endis_cbfn(port->endis_cbarg, status); -} - -/* - * bfa_port_disable_isr() - * - * - * @param[in] port - Pointer to the port module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_port_disable_isr(struct bfa_port_s *port, bfa_status_t status) -{ - bfa_trc(port, status); - port->endis_pending = BFA_FALSE; - port->endis_cbfn(port->endis_cbarg, status); -} - -/* - * bfa_port_get_stats_isr() - * - * - * @param[in] port - Pointer to the Port module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_port_get_stats_isr(struct bfa_port_s *port, bfa_status_t status) -{ - port->stats_status = status; - port->stats_busy = BFA_FALSE; - - if (status == BFA_STATUS_OK) { - struct timeval tv; - - memcpy(port->stats, port->stats_dma.kva, - sizeof(union bfa_port_stats_u)); - bfa_port_stats_swap(port, port->stats); - - do_gettimeofday(&tv); - port->stats->fc.secs_reset = tv.tv_sec - port->stats_reset_time; - } - - if (port->stats_cbfn) { - port->stats_cbfn(port->stats_cbarg, status); - port->stats_cbfn = NULL; - } -} - -/* - * bfa_port_clear_stats_isr() - * - * - * @param[in] port - Pointer to the Port module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_port_clear_stats_isr(struct bfa_port_s *port, bfa_status_t status) -{ - struct timeval tv; - - port->stats_status = status; - port->stats_busy = BFA_FALSE; - - /* - * re-initialize time stamp for stats reset - */ - do_gettimeofday(&tv); - port->stats_reset_time = tv.tv_sec; - - if (port->stats_cbfn) { - port->stats_cbfn(port->stats_cbarg, status); - port->stats_cbfn = NULL; - } -} - -/* - * bfa_port_isr() - * - * - * @param[in] Pointer to the Port module data structure. - * - * @return void - */ -static void -bfa_port_isr(void *cbarg, struct bfi_mbmsg_s *m) -{ - struct bfa_port_s *port = (struct bfa_port_s *) cbarg; - union bfi_port_i2h_msg_u *i2hmsg; - - i2hmsg = (union bfi_port_i2h_msg_u *) m; - bfa_trc(port, m->mh.msg_id); - - switch (m->mh.msg_id) { - case BFI_PORT_I2H_ENABLE_RSP: - if (port->endis_pending == BFA_FALSE) - break; - bfa_port_enable_isr(port, i2hmsg->enable_rsp.status); - break; - - case BFI_PORT_I2H_DISABLE_RSP: - if (port->endis_pending == BFA_FALSE) - break; - bfa_port_disable_isr(port, i2hmsg->disable_rsp.status); - break; - - case BFI_PORT_I2H_GET_STATS_RSP: - /* Stats busy flag is still set? (may be cmd timed out) */ - if (port->stats_busy == BFA_FALSE) - break; - bfa_port_get_stats_isr(port, i2hmsg->getstats_rsp.status); - break; - - case BFI_PORT_I2H_CLEAR_STATS_RSP: - if (port->stats_busy == BFA_FALSE) - break; - bfa_port_clear_stats_isr(port, i2hmsg->clearstats_rsp.status); - break; - - default: - WARN_ON(1); - } -} - -/* - * bfa_port_meminfo() - * - * - * @param[in] void - * - * @return Size of DMA region - */ -u32 -bfa_port_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(union bfa_port_stats_u), BFA_DMA_ALIGN_SZ); -} - -/* - * bfa_port_mem_claim() - * - * - * @param[in] port Port module pointer - * dma_kva Kernel Virtual Address of Port DMA Memory - * dma_pa Physical Address of Port DMA Memory - * - * @return void - */ -void -bfa_port_mem_claim(struct bfa_port_s *port, u8 *dma_kva, u64 dma_pa) -{ - port->stats_dma.kva = dma_kva; - port->stats_dma.pa = dma_pa; -} - -/* - * bfa_port_enable() - * - * Send the Port enable request to the f/w - * - * @param[in] Pointer to the Port module data structure. - * - * @return Status - */ -bfa_status_t -bfa_port_enable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, - void *cbarg) -{ - struct bfi_port_generic_req_s *m; - - /* If port is PBC disabled, return error */ - if (port->pbc_disabled) { - bfa_trc(port, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - - if (bfa_ioc_is_disabled(port->ioc)) { - bfa_trc(port, BFA_STATUS_IOC_DISABLED); - return BFA_STATUS_IOC_DISABLED; - } - - if (!bfa_ioc_is_operational(port->ioc)) { - bfa_trc(port, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (port->endis_pending) { - bfa_trc(port, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - m = (struct bfi_port_generic_req_s *) port->endis_mb.msg; - - port->msgtag++; - port->endis_cbfn = cbfn; - port->endis_cbarg = cbarg; - port->endis_pending = BFA_TRUE; - - bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_ENABLE_REQ, - bfa_ioc_portid(port->ioc)); - bfa_ioc_mbox_queue(port->ioc, &port->endis_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_port_disable() - * - * Send the Port disable request to the f/w - * - * @param[in] Pointer to the Port module data structure. - * - * @return Status - */ -bfa_status_t -bfa_port_disable(struct bfa_port_s *port, bfa_port_endis_cbfn_t cbfn, - void *cbarg) -{ - struct bfi_port_generic_req_s *m; - - /* If port is PBC disabled, return error */ - if (port->pbc_disabled) { - bfa_trc(port, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - - if (bfa_ioc_is_disabled(port->ioc)) { - bfa_trc(port, BFA_STATUS_IOC_DISABLED); - return BFA_STATUS_IOC_DISABLED; - } - - if (!bfa_ioc_is_operational(port->ioc)) { - bfa_trc(port, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (port->endis_pending) { - bfa_trc(port, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - m = (struct bfi_port_generic_req_s *) port->endis_mb.msg; - - port->msgtag++; - port->endis_cbfn = cbfn; - port->endis_cbarg = cbarg; - port->endis_pending = BFA_TRUE; - - bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_DISABLE_REQ, - bfa_ioc_portid(port->ioc)); - bfa_ioc_mbox_queue(port->ioc, &port->endis_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_port_get_stats() - * - * Send the request to the f/w to fetch Port statistics. - * - * @param[in] Pointer to the Port module data structure. - * - * @return Status - */ -bfa_status_t -bfa_port_get_stats(struct bfa_port_s *port, union bfa_port_stats_u *stats, - bfa_port_stats_cbfn_t cbfn, void *cbarg) -{ - struct bfi_port_get_stats_req_s *m; - - if (!bfa_ioc_is_operational(port->ioc)) { - bfa_trc(port, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (port->stats_busy) { - bfa_trc(port, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - m = (struct bfi_port_get_stats_req_s *) port->stats_mb.msg; - - port->stats = stats; - port->stats_cbfn = cbfn; - port->stats_cbarg = cbarg; - port->stats_busy = BFA_TRUE; - bfa_dma_be_addr_set(m->dma_addr, port->stats_dma.pa); - - bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_GET_STATS_REQ, - bfa_ioc_portid(port->ioc)); - bfa_ioc_mbox_queue(port->ioc, &port->stats_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_port_clear_stats() - * - * - * @param[in] Pointer to the Port module data structure. - * - * @return Status - */ -bfa_status_t -bfa_port_clear_stats(struct bfa_port_s *port, bfa_port_stats_cbfn_t cbfn, - void *cbarg) -{ - struct bfi_port_generic_req_s *m; - - if (!bfa_ioc_is_operational(port->ioc)) { - bfa_trc(port, BFA_STATUS_IOC_FAILURE); - return BFA_STATUS_IOC_FAILURE; - } - - if (port->stats_busy) { - bfa_trc(port, BFA_STATUS_DEVBUSY); - return BFA_STATUS_DEVBUSY; - } - - m = (struct bfi_port_generic_req_s *) port->stats_mb.msg; - - port->stats_cbfn = cbfn; - port->stats_cbarg = cbarg; - port->stats_busy = BFA_TRUE; - - bfi_h2i_set(m->mh, BFI_MC_PORT, BFI_PORT_H2I_CLEAR_STATS_REQ, - bfa_ioc_portid(port->ioc)); - bfa_ioc_mbox_queue(port->ioc, &port->stats_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_port_notify() - * - * Port module IOC event handler - * - * @param[in] Pointer to the Port module data structure. - * @param[in] IOC event structure - * - * @return void - */ -void -bfa_port_notify(void *arg, enum bfa_ioc_event_e event) -{ - struct bfa_port_s *port = (struct bfa_port_s *) arg; - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - /* Fail any pending get_stats/clear_stats requests */ - if (port->stats_busy) { - if (port->stats_cbfn) - port->stats_cbfn(port->stats_cbarg, - BFA_STATUS_FAILED); - port->stats_cbfn = NULL; - port->stats_busy = BFA_FALSE; - } - - /* Clear any enable/disable is pending */ - if (port->endis_pending) { - if (port->endis_cbfn) - port->endis_cbfn(port->endis_cbarg, - BFA_STATUS_FAILED); - port->endis_cbfn = NULL; - port->endis_pending = BFA_FALSE; - } - break; - default: - break; - } -} - -/* - * bfa_port_attach() - * - * - * @param[in] port - Pointer to the Port module data structure - * ioc - Pointer to the ioc module data structure - * dev - Pointer to the device driver module data structure - * The device driver specific mbox ISR functions have - * this pointer as one of the parameters. - * trcmod - - * - * @return void - */ -void -bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod) -{ - struct timeval tv; - - WARN_ON(!port); - - port->dev = dev; - port->ioc = ioc; - port->trcmod = trcmod; - - port->stats_busy = BFA_FALSE; - port->endis_pending = BFA_FALSE; - port->stats_cbfn = NULL; - port->endis_cbfn = NULL; - port->pbc_disabled = BFA_FALSE; - - bfa_ioc_mbox_regisr(port->ioc, BFI_MC_PORT, bfa_port_isr, port); - bfa_q_qe_init(&port->ioc_notify); - bfa_ioc_notify_init(&port->ioc_notify, bfa_port_notify, port); - list_add_tail(&port->ioc_notify.qe, &port->ioc->notify_q); - - /* - * initialize time stamp for stats reset - */ - do_gettimeofday(&tv); - port->stats_reset_time = tv.tv_sec; - - bfa_trc(port, 0); -} - -/* - * CEE module specific definitions - */ - -/* - * bfa_cee_get_attr_isr() - * - * @brief CEE ISR for get-attributes responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_get_attr_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - struct bfa_cee_lldp_cfg_s *lldp_cfg = &cee->attr->lldp_remote; - - cee->get_attr_status = status; - bfa_trc(cee, 0); - if (status == BFA_STATUS_OK) { - bfa_trc(cee, 0); - memcpy(cee->attr, cee->attr_dma.kva, - sizeof(struct bfa_cee_attr_s)); - lldp_cfg->time_to_live = be16_to_cpu(lldp_cfg->time_to_live); - lldp_cfg->enabled_system_cap = - be16_to_cpu(lldp_cfg->enabled_system_cap); - } - cee->get_attr_pending = BFA_FALSE; - if (cee->cbfn.get_attr_cbfn) { - bfa_trc(cee, 0); - cee->cbfn.get_attr_cbfn(cee->cbfn.get_attr_cbarg, status); - } -} - -/* - * bfa_cee_get_stats_isr() - * - * @brief CEE ISR for get-stats responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_get_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - u32 *buffer; - int i; - - cee->get_stats_status = status; - bfa_trc(cee, 0); - if (status == BFA_STATUS_OK) { - bfa_trc(cee, 0); - memcpy(cee->stats, cee->stats_dma.kva, - sizeof(struct bfa_cee_stats_s)); - /* swap the cee stats */ - buffer = (u32 *)cee->stats; - for (i = 0; i < (sizeof(struct bfa_cee_stats_s) / - sizeof(u32)); i++) - buffer[i] = cpu_to_be32(buffer[i]); - } - cee->get_stats_pending = BFA_FALSE; - bfa_trc(cee, 0); - if (cee->cbfn.get_stats_cbfn) { - bfa_trc(cee, 0); - cee->cbfn.get_stats_cbfn(cee->cbfn.get_stats_cbarg, status); - } -} - -/* - * bfa_cee_reset_stats_isr() - * - * @brief CEE ISR for reset-stats responses from f/w - * - * @param[in] cee - Pointer to the CEE module - * status - Return status from the f/w - * - * @return void - */ -static void -bfa_cee_reset_stats_isr(struct bfa_cee_s *cee, bfa_status_t status) -{ - cee->reset_stats_status = status; - cee->reset_stats_pending = BFA_FALSE; - if (cee->cbfn.reset_stats_cbfn) - cee->cbfn.reset_stats_cbfn(cee->cbfn.reset_stats_cbarg, status); -} - -/* - * bfa_cee_meminfo() - * - * @brief Returns the size of the DMA memory needed by CEE module - * - * @param[in] void - * - * @return Size of DMA region - */ -u32 -bfa_cee_meminfo(void) -{ - return BFA_ROUNDUP(sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ) + - BFA_ROUNDUP(sizeof(struct bfa_cee_stats_s), BFA_DMA_ALIGN_SZ); -} - -/* - * bfa_cee_mem_claim() - * - * @brief Initialized CEE DMA Memory - * - * @param[in] cee CEE module pointer - * dma_kva Kernel Virtual Address of CEE DMA Memory - * dma_pa Physical Address of CEE DMA Memory - * - * @return void - */ -void -bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa) -{ - cee->attr_dma.kva = dma_kva; - cee->attr_dma.pa = dma_pa; - cee->stats_dma.kva = dma_kva + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ); - cee->stats_dma.pa = dma_pa + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ); - cee->attr = (struct bfa_cee_attr_s *) dma_kva; - cee->stats = (struct bfa_cee_stats_s *) (dma_kva + BFA_ROUNDUP( - sizeof(struct bfa_cee_attr_s), BFA_DMA_ALIGN_SZ)); -} - -/* - * bfa_cee_get_attr() - * - * @brief - * Send the request to the f/w to fetch CEE attributes. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_get_attr(struct bfa_cee_s *cee, struct bfa_cee_attr_s *attr, - bfa_cee_get_attr_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_get_req_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - bfa_trc(cee, 0); - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->get_attr_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->get_attr_pending = BFA_TRUE; - cmd = (struct bfi_cee_get_req_s *) cee->get_cfg_mb.msg; - cee->attr = attr; - cee->cbfn.get_attr_cbfn = cbfn; - cee->cbfn.get_attr_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ, - bfa_ioc_portid(cee->ioc)); - bfa_dma_be_addr_set(cmd->dma_addr, cee->attr_dma.pa); - bfa_ioc_mbox_queue(cee->ioc, &cee->get_cfg_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_get_stats() - * - * @brief - * Send the request to the f/w to fetch CEE statistics. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_get_stats(struct bfa_cee_s *cee, struct bfa_cee_stats_s *stats, - bfa_cee_get_stats_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_get_req_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->get_stats_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->get_stats_pending = BFA_TRUE; - cmd = (struct bfi_cee_get_req_s *) cee->get_stats_mb.msg; - cee->stats = stats; - cee->cbfn.get_stats_cbfn = cbfn; - cee->cbfn.get_stats_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ, - bfa_ioc_portid(cee->ioc)); - bfa_dma_be_addr_set(cmd->dma_addr, cee->stats_dma.pa); - bfa_ioc_mbox_queue(cee->ioc, &cee->get_stats_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_reset_stats() - * - * @brief Clears CEE Stats in the f/w. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return Status - */ - -bfa_status_t -bfa_cee_reset_stats(struct bfa_cee_s *cee, - bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg) -{ - struct bfi_cee_reset_stats_s *cmd; - - WARN_ON((cee == NULL) || (cee->ioc == NULL)); - if (!bfa_ioc_is_operational(cee->ioc)) { - bfa_trc(cee, 0); - return BFA_STATUS_IOC_FAILURE; - } - if (cee->reset_stats_pending == BFA_TRUE) { - bfa_trc(cee, 0); - return BFA_STATUS_DEVBUSY; - } - cee->reset_stats_pending = BFA_TRUE; - cmd = (struct bfi_cee_reset_stats_s *) cee->reset_stats_mb.msg; - cee->cbfn.reset_stats_cbfn = cbfn; - cee->cbfn.reset_stats_cbarg = cbarg; - bfi_h2i_set(cmd->mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS, - bfa_ioc_portid(cee->ioc)); - bfa_ioc_mbox_queue(cee->ioc, &cee->reset_stats_mb); - - return BFA_STATUS_OK; -} - -/* - * bfa_cee_isrs() - * - * @brief Handles Mail-box interrupts for CEE module. - * - * @param[in] Pointer to the CEE module data structure. - * - * @return void - */ - -void -bfa_cee_isr(void *cbarg, struct bfi_mbmsg_s *m) -{ - union bfi_cee_i2h_msg_u *msg; - struct bfi_cee_get_rsp_s *get_rsp; - struct bfa_cee_s *cee = (struct bfa_cee_s *) cbarg; - msg = (union bfi_cee_i2h_msg_u *) m; - get_rsp = (struct bfi_cee_get_rsp_s *) m; - bfa_trc(cee, msg->mh.msg_id); - switch (msg->mh.msg_id) { - case BFI_CEE_I2H_GET_CFG_RSP: - bfa_trc(cee, get_rsp->cmd_status); - bfa_cee_get_attr_isr(cee, get_rsp->cmd_status); - break; - case BFI_CEE_I2H_GET_STATS_RSP: - bfa_cee_get_stats_isr(cee, get_rsp->cmd_status); - break; - case BFI_CEE_I2H_RESET_STATS_RSP: - bfa_cee_reset_stats_isr(cee, get_rsp->cmd_status); - break; - default: - WARN_ON(1); - } -} - -/* - * bfa_cee_notify() - * - * @brief CEE module IOC event handler. - * - * @param[in] Pointer to the CEE module data structure. - * @param[in] IOC event type - * - * @return void - */ - -void -bfa_cee_notify(void *arg, enum bfa_ioc_event_e event) -{ - struct bfa_cee_s *cee = (struct bfa_cee_s *) arg; - - bfa_trc(cee, event); - - switch (event) { - case BFA_IOC_E_DISABLED: - case BFA_IOC_E_FAILED: - if (cee->get_attr_pending == BFA_TRUE) { - cee->get_attr_status = BFA_STATUS_FAILED; - cee->get_attr_pending = BFA_FALSE; - if (cee->cbfn.get_attr_cbfn) { - cee->cbfn.get_attr_cbfn( - cee->cbfn.get_attr_cbarg, - BFA_STATUS_FAILED); - } - } - if (cee->get_stats_pending == BFA_TRUE) { - cee->get_stats_status = BFA_STATUS_FAILED; - cee->get_stats_pending = BFA_FALSE; - if (cee->cbfn.get_stats_cbfn) { - cee->cbfn.get_stats_cbfn( - cee->cbfn.get_stats_cbarg, - BFA_STATUS_FAILED); - } - } - if (cee->reset_stats_pending == BFA_TRUE) { - cee->reset_stats_status = BFA_STATUS_FAILED; - cee->reset_stats_pending = BFA_FALSE; - if (cee->cbfn.reset_stats_cbfn) { - cee->cbfn.reset_stats_cbfn( - cee->cbfn.reset_stats_cbarg, - BFA_STATUS_FAILED); - } - } - break; - - default: - break; - } -} - -/* - * bfa_cee_attach() - * - * @brief CEE module-attach API - * - * @param[in] cee - Pointer to the CEE module data structure - * ioc - Pointer to the ioc module data structure - * dev - Pointer to the device driver module data structure - * The device driver specific mbox ISR functions have - * this pointer as one of the parameters. - * - * @return void - */ -void -bfa_cee_attach(struct bfa_cee_s *cee, struct bfa_ioc_s *ioc, - void *dev) -{ - WARN_ON(cee == NULL); - cee->dev = dev; - cee->ioc = ioc; - - bfa_ioc_mbox_regisr(cee->ioc, BFI_MC_CEE, bfa_cee_isr, cee); - bfa_q_qe_init(&cee->ioc_notify); - bfa_ioc_notify_init(&cee->ioc_notify, bfa_cee_notify, cee); - list_add_tail(&cee->ioc_notify.qe, &cee->ioc->notify_q); -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.h deleted file mode 100644 index 947f8973..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_port.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_PORT_H__ -#define __BFA_PORT_H__ - -#include "bfa_defs_svc.h" -#include "bfa_ioc.h" -#include "bfa_cs.h" - -typedef void (*bfa_port_stats_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_port_endis_cbfn_t) (void *dev, bfa_status_t status); - -struct bfa_port_s { - void *dev; - struct bfa_ioc_s *ioc; - struct bfa_trc_mod_s *trcmod; - u32 msgtag; - bfa_boolean_t stats_busy; - struct bfa_mbox_cmd_s stats_mb; - bfa_port_stats_cbfn_t stats_cbfn; - void *stats_cbarg; - bfa_status_t stats_status; - u32 stats_reset_time; - union bfa_port_stats_u *stats; - struct bfa_dma_s stats_dma; - bfa_boolean_t endis_pending; - struct bfa_mbox_cmd_s endis_mb; - bfa_port_endis_cbfn_t endis_cbfn; - void *endis_cbarg; - bfa_status_t endis_status; - struct bfa_ioc_notify_s ioc_notify; - bfa_boolean_t pbc_disabled; - struct bfa_mem_dma_s port_dma; -}; - -#define BFA_MEM_PORT_DMA(__bfa) (&((__bfa)->modules.port.port_dma)) - -void bfa_port_attach(struct bfa_port_s *port, struct bfa_ioc_s *ioc, - void *dev, struct bfa_trc_mod_s *trcmod); -void bfa_port_notify(void *arg, enum bfa_ioc_event_e event); - -bfa_status_t bfa_port_get_stats(struct bfa_port_s *port, - union bfa_port_stats_u *stats, - bfa_port_stats_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_port_clear_stats(struct bfa_port_s *port, - bfa_port_stats_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_port_enable(struct bfa_port_s *port, - bfa_port_endis_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_port_disable(struct bfa_port_s *port, - bfa_port_endis_cbfn_t cbfn, void *cbarg); -u32 bfa_port_meminfo(void); -void bfa_port_mem_claim(struct bfa_port_s *port, - u8 *dma_kva, u64 dma_pa); - -/* - * CEE declaration - */ -typedef void (*bfa_cee_get_attr_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_get_stats_cbfn_t) (void *dev, bfa_status_t status); -typedef void (*bfa_cee_reset_stats_cbfn_t) (void *dev, bfa_status_t status); - -struct bfa_cee_cbfn_s { - bfa_cee_get_attr_cbfn_t get_attr_cbfn; - void *get_attr_cbarg; - bfa_cee_get_stats_cbfn_t get_stats_cbfn; - void *get_stats_cbarg; - bfa_cee_reset_stats_cbfn_t reset_stats_cbfn; - void *reset_stats_cbarg; -}; - -struct bfa_cee_s { - void *dev; - bfa_boolean_t get_attr_pending; - bfa_boolean_t get_stats_pending; - bfa_boolean_t reset_stats_pending; - bfa_status_t get_attr_status; - bfa_status_t get_stats_status; - bfa_status_t reset_stats_status; - struct bfa_cee_cbfn_s cbfn; - struct bfa_ioc_notify_s ioc_notify; - struct bfa_trc_mod_s *trcmod; - struct bfa_cee_attr_s *attr; - struct bfa_cee_stats_s *stats; - struct bfa_dma_s attr_dma; - struct bfa_dma_s stats_dma; - struct bfa_ioc_s *ioc; - struct bfa_mbox_cmd_s get_cfg_mb; - struct bfa_mbox_cmd_s get_stats_mb; - struct bfa_mbox_cmd_s reset_stats_mb; - struct bfa_mem_dma_s cee_dma; -}; - -#define BFA_MEM_CEE_DMA(__bfa) (&((__bfa)->modules.cee.cee_dma)) - -u32 bfa_cee_meminfo(void); -void bfa_cee_mem_claim(struct bfa_cee_s *cee, u8 *dma_kva, u64 dma_pa); -void bfa_cee_attach(struct bfa_cee_s *cee, - struct bfa_ioc_s *ioc, void *dev); -bfa_status_t bfa_cee_get_attr(struct bfa_cee_s *cee, - struct bfa_cee_attr_s *attr, - bfa_cee_get_attr_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_cee_get_stats(struct bfa_cee_s *cee, - struct bfa_cee_stats_s *stats, - bfa_cee_get_stats_cbfn_t cbfn, void *cbarg); -bfa_status_t bfa_cee_reset_stats(struct bfa_cee_s *cee, - bfa_cee_reset_stats_cbfn_t cbfn, void *cbarg); - -#endif /* __BFA_PORT_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.c deleted file mode 100644 index 2e856e67..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.c +++ /dev/null @@ -1,5721 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfa_plog.h" -#include "bfa_cs.h" -#include "bfa_modules.h" - -BFA_TRC_FILE(HAL, FCXP); -BFA_MODULE(fcdiag); -BFA_MODULE(fcxp); -BFA_MODULE(sgpg); -BFA_MODULE(lps); -BFA_MODULE(fcport); -BFA_MODULE(rport); -BFA_MODULE(uf); - -/* - * LPS related definitions - */ -#define BFA_LPS_MIN_LPORTS (1) -#define BFA_LPS_MAX_LPORTS (256) - -/* - * Maximum Vports supported per physical port or vf. - */ -#define BFA_LPS_MAX_VPORTS_SUPP_CB 255 -#define BFA_LPS_MAX_VPORTS_SUPP_CT 190 - - -/* - * FC PORT related definitions - */ -/* - * The port is considered disabled if corresponding physical port or IOC are - * disabled explicitly - */ -#define BFA_PORT_IS_DISABLED(bfa) \ - ((bfa_fcport_is_disabled(bfa) == BFA_TRUE) || \ - (bfa_ioc_is_disabled(&bfa->ioc) == BFA_TRUE)) - -/* - * BFA port state machine events - */ -enum bfa_fcport_sm_event { - BFA_FCPORT_SM_START = 1, /* start port state machine */ - BFA_FCPORT_SM_STOP = 2, /* stop port state machine */ - BFA_FCPORT_SM_ENABLE = 3, /* enable port */ - BFA_FCPORT_SM_DISABLE = 4, /* disable port state machine */ - BFA_FCPORT_SM_FWRSP = 5, /* firmware enable/disable rsp */ - BFA_FCPORT_SM_LINKUP = 6, /* firmware linkup event */ - BFA_FCPORT_SM_LINKDOWN = 7, /* firmware linkup down */ - BFA_FCPORT_SM_QRESUME = 8, /* CQ space available */ - BFA_FCPORT_SM_HWFAIL = 9, /* IOC h/w failure */ -}; - -/* - * BFA port link notification state machine events - */ - -enum bfa_fcport_ln_sm_event { - BFA_FCPORT_LN_SM_LINKUP = 1, /* linkup event */ - BFA_FCPORT_LN_SM_LINKDOWN = 2, /* linkdown event */ - BFA_FCPORT_LN_SM_NOTIFICATION = 3 /* done notification */ -}; - -/* - * RPORT related definitions - */ -#define bfa_rport_offline_cb(__rp) do { \ - if ((__rp)->bfa->fcs) \ - bfa_cb_rport_offline((__rp)->rport_drv); \ - else { \ - bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \ - __bfa_cb_rport_offline, (__rp)); \ - } \ -} while (0) - -#define bfa_rport_online_cb(__rp) do { \ - if ((__rp)->bfa->fcs) \ - bfa_cb_rport_online((__rp)->rport_drv); \ - else { \ - bfa_cb_queue((__rp)->bfa, &(__rp)->hcb_qe, \ - __bfa_cb_rport_online, (__rp)); \ - } \ -} while (0) - -/* - * forward declarations FCXP related functions - */ -static void __bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete); -static void hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, - struct bfi_fcxp_send_rsp_s *fcxp_rsp); -static void hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, - struct bfa_fcxp_s *fcxp, struct fchs_s *fchs); -static void bfa_fcxp_qresume(void *cbarg); -static void bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, - struct bfi_fcxp_send_req_s *send_req); - -/* - * forward declarations for LPS functions - */ -static void bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, - struct bfa_meminfo_s *minfo, struct bfa_s *bfa); -static void bfa_lps_attach(struct bfa_s *bfa, void *bfad, - struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev); -static void bfa_lps_detach(struct bfa_s *bfa); -static void bfa_lps_start(struct bfa_s *bfa); -static void bfa_lps_stop(struct bfa_s *bfa); -static void bfa_lps_iocdisable(struct bfa_s *bfa); -static void bfa_lps_login_rsp(struct bfa_s *bfa, - struct bfi_lps_login_rsp_s *rsp); -static void bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count); -static void bfa_lps_logout_rsp(struct bfa_s *bfa, - struct bfi_lps_logout_rsp_s *rsp); -static void bfa_lps_reqq_resume(void *lps_arg); -static void bfa_lps_free(struct bfa_lps_s *lps); -static void bfa_lps_send_login(struct bfa_lps_s *lps); -static void bfa_lps_send_logout(struct bfa_lps_s *lps); -static void bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps); -static void bfa_lps_login_comp(struct bfa_lps_s *lps); -static void bfa_lps_logout_comp(struct bfa_lps_s *lps); -static void bfa_lps_cvl_event(struct bfa_lps_s *lps); - -/* - * forward declaration for LPS state machine - */ -static void bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event); -static void bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event); -static void bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event - event); -static void bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event); -static void bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, - enum bfa_lps_event event); -static void bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event); -static void bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event - event); - -/* - * forward declaration for FC Port functions - */ -static bfa_boolean_t bfa_fcport_send_enable(struct bfa_fcport_s *fcport); -static bfa_boolean_t bfa_fcport_send_disable(struct bfa_fcport_s *fcport); -static void bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport); -static void bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport); -static void bfa_fcport_set_wwns(struct bfa_fcport_s *fcport); -static void __bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete); -static void bfa_fcport_scn(struct bfa_fcport_s *fcport, - enum bfa_port_linkstate event, bfa_boolean_t trunk); -static void bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, - enum bfa_port_linkstate event); -static void __bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete); -static void bfa_fcport_stats_get_timeout(void *cbarg); -static void bfa_fcport_stats_clr_timeout(void *cbarg); -static void bfa_trunk_iocdisable(struct bfa_s *bfa); - -/* - * forward declaration for FC PORT state machine - */ -static void bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_toggling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); -static void bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event); - -static void bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); -static void bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event); - -static struct bfa_sm_table_s hal_port_sm_table[] = { - {BFA_SM(bfa_fcport_sm_uninit), BFA_PORT_ST_UNINIT}, - {BFA_SM(bfa_fcport_sm_enabling_qwait), BFA_PORT_ST_ENABLING_QWAIT}, - {BFA_SM(bfa_fcport_sm_enabling), BFA_PORT_ST_ENABLING}, - {BFA_SM(bfa_fcport_sm_linkdown), BFA_PORT_ST_LINKDOWN}, - {BFA_SM(bfa_fcport_sm_linkup), BFA_PORT_ST_LINKUP}, - {BFA_SM(bfa_fcport_sm_disabling_qwait), BFA_PORT_ST_DISABLING_QWAIT}, - {BFA_SM(bfa_fcport_sm_toggling_qwait), BFA_PORT_ST_TOGGLING_QWAIT}, - {BFA_SM(bfa_fcport_sm_disabling), BFA_PORT_ST_DISABLING}, - {BFA_SM(bfa_fcport_sm_disabled), BFA_PORT_ST_DISABLED}, - {BFA_SM(bfa_fcport_sm_stopped), BFA_PORT_ST_STOPPED}, - {BFA_SM(bfa_fcport_sm_iocdown), BFA_PORT_ST_IOCDOWN}, - {BFA_SM(bfa_fcport_sm_iocfail), BFA_PORT_ST_IOCDOWN}, -}; - - -/* - * forward declaration for RPORT related functions - */ -static struct bfa_rport_s *bfa_rport_alloc(struct bfa_rport_mod_s *rp_mod); -static void bfa_rport_free(struct bfa_rport_s *rport); -static bfa_boolean_t bfa_rport_send_fwcreate(struct bfa_rport_s *rp); -static bfa_boolean_t bfa_rport_send_fwdelete(struct bfa_rport_s *rp); -static bfa_boolean_t bfa_rport_send_fwspeed(struct bfa_rport_s *rp); -static void __bfa_cb_rport_online(void *cbarg, - bfa_boolean_t complete); -static void __bfa_cb_rport_offline(void *cbarg, - bfa_boolean_t complete); - -/* - * forward declaration for RPORT state machine - */ -static void bfa_rport_sm_uninit(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_created(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_online(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_offline(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_deleting(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_offline_pending(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_delete_pending(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, - enum bfa_rport_event event); -static void bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, - enum bfa_rport_event event); - -/* - * PLOG related definitions - */ -static int -plkd_validate_logrec(struct bfa_plog_rec_s *pl_rec) -{ - if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) && - (pl_rec->log_type != BFA_PL_LOG_TYPE_STRING)) - return 1; - - if ((pl_rec->log_type != BFA_PL_LOG_TYPE_INT) && - (pl_rec->log_num_ints > BFA_PL_INT_LOG_SZ)) - return 1; - - return 0; -} - -static u64 -bfa_get_log_time(void) -{ - u64 system_time = 0; - struct timeval tv; - do_gettimeofday(&tv); - - /* We are interested in seconds only. */ - system_time = tv.tv_sec; - return system_time; -} - -static void -bfa_plog_add(struct bfa_plog_s *plog, struct bfa_plog_rec_s *pl_rec) -{ - u16 tail; - struct bfa_plog_rec_s *pl_recp; - - if (plog->plog_enabled == 0) - return; - - if (plkd_validate_logrec(pl_rec)) { - WARN_ON(1); - return; - } - - tail = plog->tail; - - pl_recp = &(plog->plog_recs[tail]); - - memcpy(pl_recp, pl_rec, sizeof(struct bfa_plog_rec_s)); - - pl_recp->tv = bfa_get_log_time(); - BFA_PL_LOG_REC_INCR(plog->tail); - - if (plog->head == plog->tail) - BFA_PL_LOG_REC_INCR(plog->head); -} - -void -bfa_plog_init(struct bfa_plog_s *plog) -{ - memset((char *)plog, 0, sizeof(struct bfa_plog_s)); - - memcpy(plog->plog_sig, BFA_PL_SIG_STR, BFA_PL_SIG_LEN); - plog->head = plog->tail = 0; - plog->plog_enabled = 1; -} - -void -bfa_plog_str(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, - u16 misc, char *log_str) -{ - struct bfa_plog_rec_s lp; - - if (plog->plog_enabled) { - memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); - lp.mid = mid; - lp.eid = event; - lp.log_type = BFA_PL_LOG_TYPE_STRING; - lp.misc = misc; - strncpy(lp.log_entry.string_log, log_str, - BFA_PL_STRING_LOG_SZ - 1); - lp.log_entry.string_log[BFA_PL_STRING_LOG_SZ - 1] = '\0'; - bfa_plog_add(plog, &lp); - } -} - -void -bfa_plog_intarr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, - u16 misc, u32 *intarr, u32 num_ints) -{ - struct bfa_plog_rec_s lp; - u32 i; - - if (num_ints > BFA_PL_INT_LOG_SZ) - num_ints = BFA_PL_INT_LOG_SZ; - - if (plog->plog_enabled) { - memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); - lp.mid = mid; - lp.eid = event; - lp.log_type = BFA_PL_LOG_TYPE_INT; - lp.misc = misc; - - for (i = 0; i < num_ints; i++) - lp.log_entry.int_log[i] = intarr[i]; - - lp.log_num_ints = (u8) num_ints; - - bfa_plog_add(plog, &lp); - } -} - -void -bfa_plog_fchdr(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, - u16 misc, struct fchs_s *fchdr) -{ - struct bfa_plog_rec_s lp; - u32 *tmp_int = (u32 *) fchdr; - u32 ints[BFA_PL_INT_LOG_SZ]; - - if (plog->plog_enabled) { - memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); - - ints[0] = tmp_int[0]; - ints[1] = tmp_int[1]; - ints[2] = tmp_int[4]; - - bfa_plog_intarr(plog, mid, event, misc, ints, 3); - } -} - -void -bfa_plog_fchdr_and_pl(struct bfa_plog_s *plog, enum bfa_plog_mid mid, - enum bfa_plog_eid event, u16 misc, struct fchs_s *fchdr, - u32 pld_w0) -{ - struct bfa_plog_rec_s lp; - u32 *tmp_int = (u32 *) fchdr; - u32 ints[BFA_PL_INT_LOG_SZ]; - - if (plog->plog_enabled) { - memset(&lp, 0, sizeof(struct bfa_plog_rec_s)); - - ints[0] = tmp_int[0]; - ints[1] = tmp_int[1]; - ints[2] = tmp_int[4]; - ints[3] = pld_w0; - - bfa_plog_intarr(plog, mid, event, misc, ints, 4); - } -} - - -/* - * fcxp_pvt BFA FCXP private functions - */ - -static void -claim_fcxps_mem(struct bfa_fcxp_mod_s *mod) -{ - u16 i; - struct bfa_fcxp_s *fcxp; - - fcxp = (struct bfa_fcxp_s *) bfa_mem_kva_curp(mod); - memset(fcxp, 0, sizeof(struct bfa_fcxp_s) * mod->num_fcxps); - - INIT_LIST_HEAD(&mod->fcxp_free_q); - INIT_LIST_HEAD(&mod->fcxp_active_q); - INIT_LIST_HEAD(&mod->fcxp_unused_q); - - mod->fcxp_list = fcxp; - - for (i = 0; i < mod->num_fcxps; i++) { - fcxp->fcxp_mod = mod; - fcxp->fcxp_tag = i; - - list_add_tail(&fcxp->qe, &mod->fcxp_free_q); - bfa_reqq_winit(&fcxp->reqq_wqe, bfa_fcxp_qresume, fcxp); - fcxp->reqq_waiting = BFA_FALSE; - - fcxp = fcxp + 1; - } - - bfa_mem_kva_curp(mod) = (void *)fcxp; -} - -static void -bfa_fcxp_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_fcxp_mod_s *fcxp_mod = BFA_FCXP_MOD(bfa); - struct bfa_mem_kva_s *fcxp_kva = BFA_MEM_FCXP_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_fcxp; - u16 num_fcxps = cfg->fwcfg.num_fcxp_reqs; - u32 per_fcxp_sz; - - if (num_fcxps == 0) - return; - - if (cfg->drvcfg.min_cfg) - per_fcxp_sz = 2 * BFA_FCXP_MAX_IBUF_SZ; - else - per_fcxp_sz = BFA_FCXP_MAX_IBUF_SZ + BFA_FCXP_MAX_LBUF_SZ; - - /* dma memory */ - nsegs = BFI_MEM_DMA_NSEGS(num_fcxps, per_fcxp_sz); - per_seg_fcxp = BFI_MEM_NREQS_SEG(per_fcxp_sz); - - bfa_mem_dma_seg_iter(fcxp_mod, seg_ptr, nsegs, idx) { - if (num_fcxps >= per_seg_fcxp) { - num_fcxps -= per_seg_fcxp; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_fcxp * per_fcxp_sz); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_fcxps * per_fcxp_sz); - } - - /* kva memory */ - bfa_mem_kva_setup(minfo, fcxp_kva, - cfg->fwcfg.num_fcxp_reqs * sizeof(struct bfa_fcxp_s)); -} - -static void -bfa_fcxp_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - - mod->bfa = bfa; - mod->num_fcxps = cfg->fwcfg.num_fcxp_reqs; - - /* - * Initialize FCXP request and response payload sizes. - */ - mod->req_pld_sz = mod->rsp_pld_sz = BFA_FCXP_MAX_IBUF_SZ; - if (!cfg->drvcfg.min_cfg) - mod->rsp_pld_sz = BFA_FCXP_MAX_LBUF_SZ; - - INIT_LIST_HEAD(&mod->wait_q); - - claim_fcxps_mem(mod); -} - -static void -bfa_fcxp_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcxp_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcxp_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_fcxp_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - struct bfa_fcxp_s *fcxp; - struct list_head *qe, *qen; - - /* Enqueue unused fcxp resources to free_q */ - list_splice_tail_init(&mod->fcxp_unused_q, &mod->fcxp_free_q); - - list_for_each_safe(qe, qen, &mod->fcxp_active_q) { - fcxp = (struct bfa_fcxp_s *) qe; - if (fcxp->caller == NULL) { - fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, - BFA_STATUS_IOC_FAILURE, 0, 0, NULL); - bfa_fcxp_free(fcxp); - } else { - fcxp->rsp_status = BFA_STATUS_IOC_FAILURE; - bfa_cb_queue(bfa, &fcxp->hcb_qe, - __bfa_fcxp_send_cbfn, fcxp); - } - } -} - -static struct bfa_fcxp_s * -bfa_fcxp_get(struct bfa_fcxp_mod_s *fm) -{ - struct bfa_fcxp_s *fcxp; - - bfa_q_deq(&fm->fcxp_free_q, &fcxp); - - if (fcxp) - list_add_tail(&fcxp->qe, &fm->fcxp_active_q); - - return fcxp; -} - -static void -bfa_fcxp_init_reqrsp(struct bfa_fcxp_s *fcxp, - struct bfa_s *bfa, - u8 *use_ibuf, - u32 *nr_sgles, - bfa_fcxp_get_sgaddr_t *r_sga_cbfn, - bfa_fcxp_get_sglen_t *r_sglen_cbfn, - struct list_head *r_sgpg_q, - int n_sgles, - bfa_fcxp_get_sgaddr_t sga_cbfn, - bfa_fcxp_get_sglen_t sglen_cbfn) -{ - - WARN_ON(bfa == NULL); - - bfa_trc(bfa, fcxp->fcxp_tag); - - if (n_sgles == 0) { - *use_ibuf = 1; - } else { - WARN_ON(*sga_cbfn == NULL); - WARN_ON(*sglen_cbfn == NULL); - - *use_ibuf = 0; - *r_sga_cbfn = sga_cbfn; - *r_sglen_cbfn = sglen_cbfn; - - *nr_sgles = n_sgles; - - /* - * alloc required sgpgs - */ - if (n_sgles > BFI_SGE_INLINE) - WARN_ON(1); - } - -} - -static void -bfa_fcxp_init(struct bfa_fcxp_s *fcxp, - void *caller, struct bfa_s *bfa, int nreq_sgles, - int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, - bfa_fcxp_get_sglen_t req_sglen_cbfn, - bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, - bfa_fcxp_get_sglen_t rsp_sglen_cbfn) -{ - - WARN_ON(bfa == NULL); - - bfa_trc(bfa, fcxp->fcxp_tag); - - fcxp->caller = caller; - - bfa_fcxp_init_reqrsp(fcxp, bfa, - &fcxp->use_ireqbuf, &fcxp->nreq_sgles, &fcxp->req_sga_cbfn, - &fcxp->req_sglen_cbfn, &fcxp->req_sgpg_q, - nreq_sgles, req_sga_cbfn, req_sglen_cbfn); - - bfa_fcxp_init_reqrsp(fcxp, bfa, - &fcxp->use_irspbuf, &fcxp->nrsp_sgles, &fcxp->rsp_sga_cbfn, - &fcxp->rsp_sglen_cbfn, &fcxp->rsp_sgpg_q, - nrsp_sgles, rsp_sga_cbfn, rsp_sglen_cbfn); - -} - -static void -bfa_fcxp_put(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - struct bfa_fcxp_wqe_s *wqe; - - bfa_q_deq(&mod->wait_q, &wqe); - if (wqe) { - bfa_trc(mod->bfa, fcxp->fcxp_tag); - - bfa_fcxp_init(fcxp, wqe->caller, wqe->bfa, wqe->nreq_sgles, - wqe->nrsp_sgles, wqe->req_sga_cbfn, - wqe->req_sglen_cbfn, wqe->rsp_sga_cbfn, - wqe->rsp_sglen_cbfn); - - wqe->alloc_cbfn(wqe->alloc_cbarg, fcxp); - return; - } - - WARN_ON(!bfa_q_is_on_q(&mod->fcxp_active_q, fcxp)); - list_del(&fcxp->qe); - list_add_tail(&fcxp->qe, &mod->fcxp_free_q); -} - -static void -bfa_fcxp_null_comp(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, - u32 resid_len, struct fchs_s *rsp_fchs) -{ - /* discarded fcxp completion */ -} - -static void -__bfa_fcxp_send_cbfn(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_fcxp_s *fcxp = cbarg; - - if (complete) { - fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, - fcxp->rsp_status, fcxp->rsp_len, - fcxp->residue_len, &fcxp->rsp_fchs); - } else { - bfa_fcxp_free(fcxp); - } -} - -static void -hal_fcxp_send_comp(struct bfa_s *bfa, struct bfi_fcxp_send_rsp_s *fcxp_rsp) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - struct bfa_fcxp_s *fcxp; - u16 fcxp_tag = be16_to_cpu(fcxp_rsp->fcxp_tag); - - bfa_trc(bfa, fcxp_tag); - - fcxp_rsp->rsp_len = be32_to_cpu(fcxp_rsp->rsp_len); - - /* - * @todo f/w should not set residue to non-0 when everything - * is received. - */ - if (fcxp_rsp->req_status == BFA_STATUS_OK) - fcxp_rsp->residue_len = 0; - else - fcxp_rsp->residue_len = be32_to_cpu(fcxp_rsp->residue_len); - - fcxp = BFA_FCXP_FROM_TAG(mod, fcxp_tag); - - WARN_ON(fcxp->send_cbfn == NULL); - - hal_fcxp_rx_plog(mod->bfa, fcxp, fcxp_rsp); - - if (fcxp->send_cbfn != NULL) { - bfa_trc(mod->bfa, (NULL == fcxp->caller)); - if (fcxp->caller == NULL) { - fcxp->send_cbfn(fcxp->caller, fcxp, fcxp->send_cbarg, - fcxp_rsp->req_status, fcxp_rsp->rsp_len, - fcxp_rsp->residue_len, &fcxp_rsp->fchs); - /* - * fcxp automatically freed on return from the callback - */ - bfa_fcxp_free(fcxp); - } else { - fcxp->rsp_status = fcxp_rsp->req_status; - fcxp->rsp_len = fcxp_rsp->rsp_len; - fcxp->residue_len = fcxp_rsp->residue_len; - fcxp->rsp_fchs = fcxp_rsp->fchs; - - bfa_cb_queue(bfa, &fcxp->hcb_qe, - __bfa_fcxp_send_cbfn, fcxp); - } - } else { - bfa_trc(bfa, (NULL == fcxp->send_cbfn)); - } -} - -static void -hal_fcxp_tx_plog(struct bfa_s *bfa, u32 reqlen, struct bfa_fcxp_s *fcxp, - struct fchs_s *fchs) -{ - /* - * TODO: TX ox_id - */ - if (reqlen > 0) { - if (fcxp->use_ireqbuf) { - u32 pld_w0 = - *((u32 *) BFA_FCXP_REQ_PLD(fcxp)); - - bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, - BFA_PL_EID_TX, - reqlen + sizeof(struct fchs_s), fchs, - pld_w0); - } else { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, - BFA_PL_EID_TX, - reqlen + sizeof(struct fchs_s), - fchs); - } - } else { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_TX, - reqlen + sizeof(struct fchs_s), fchs); - } -} - -static void -hal_fcxp_rx_plog(struct bfa_s *bfa, struct bfa_fcxp_s *fcxp, - struct bfi_fcxp_send_rsp_s *fcxp_rsp) -{ - if (fcxp_rsp->rsp_len > 0) { - if (fcxp->use_irspbuf) { - u32 pld_w0 = - *((u32 *) BFA_FCXP_RSP_PLD(fcxp)); - - bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_FCXP, - BFA_PL_EID_RX, - (u16) fcxp_rsp->rsp_len, - &fcxp_rsp->fchs, pld_w0); - } else { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, - BFA_PL_EID_RX, - (u16) fcxp_rsp->rsp_len, - &fcxp_rsp->fchs); - } - } else { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_FCXP, BFA_PL_EID_RX, - (u16) fcxp_rsp->rsp_len, &fcxp_rsp->fchs); - } -} - -/* - * Handler to resume sending fcxp when space in available in cpe queue. - */ -static void -bfa_fcxp_qresume(void *cbarg) -{ - struct bfa_fcxp_s *fcxp = cbarg; - struct bfa_s *bfa = fcxp->fcxp_mod->bfa; - struct bfi_fcxp_send_req_s *send_req; - - fcxp->reqq_waiting = BFA_FALSE; - send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); - bfa_fcxp_queue(fcxp, send_req); -} - -/* - * Queue fcxp send request to foimrware. - */ -static void -bfa_fcxp_queue(struct bfa_fcxp_s *fcxp, struct bfi_fcxp_send_req_s *send_req) -{ - struct bfa_s *bfa = fcxp->fcxp_mod->bfa; - struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; - struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; - struct bfa_rport_s *rport = reqi->bfa_rport; - - bfi_h2i_set(send_req->mh, BFI_MC_FCXP, BFI_FCXP_H2I_SEND_REQ, - bfa_fn_lpu(bfa)); - - send_req->fcxp_tag = cpu_to_be16(fcxp->fcxp_tag); - if (rport) { - send_req->rport_fw_hndl = rport->fw_handle; - send_req->max_frmsz = cpu_to_be16(rport->rport_info.max_frmsz); - if (send_req->max_frmsz == 0) - send_req->max_frmsz = cpu_to_be16(FC_MAX_PDUSZ); - } else { - send_req->rport_fw_hndl = 0; - send_req->max_frmsz = cpu_to_be16(FC_MAX_PDUSZ); - } - - send_req->vf_id = cpu_to_be16(reqi->vf_id); - send_req->lp_fwtag = bfa_lps_get_fwtag(bfa, reqi->lp_tag); - send_req->class = reqi->class; - send_req->rsp_timeout = rspi->rsp_timeout; - send_req->cts = reqi->cts; - send_req->fchs = reqi->fchs; - - send_req->req_len = cpu_to_be32(reqi->req_tot_len); - send_req->rsp_maxlen = cpu_to_be32(rspi->rsp_maxlen); - - /* - * setup req sgles - */ - if (fcxp->use_ireqbuf == 1) { - bfa_alen_set(&send_req->req_alen, reqi->req_tot_len, - BFA_FCXP_REQ_PLD_PA(fcxp)); - } else { - if (fcxp->nreq_sgles > 0) { - WARN_ON(fcxp->nreq_sgles != 1); - bfa_alen_set(&send_req->req_alen, reqi->req_tot_len, - fcxp->req_sga_cbfn(fcxp->caller, 0)); - } else { - WARN_ON(reqi->req_tot_len != 0); - bfa_alen_set(&send_req->rsp_alen, 0, 0); - } - } - - /* - * setup rsp sgles - */ - if (fcxp->use_irspbuf == 1) { - WARN_ON(rspi->rsp_maxlen > BFA_FCXP_MAX_LBUF_SZ); - - bfa_alen_set(&send_req->rsp_alen, rspi->rsp_maxlen, - BFA_FCXP_RSP_PLD_PA(fcxp)); - } else { - if (fcxp->nrsp_sgles > 0) { - WARN_ON(fcxp->nrsp_sgles != 1); - bfa_alen_set(&send_req->rsp_alen, rspi->rsp_maxlen, - fcxp->rsp_sga_cbfn(fcxp->caller, 0)); - - } else { - WARN_ON(rspi->rsp_maxlen != 0); - bfa_alen_set(&send_req->rsp_alen, 0, 0); - } - } - - hal_fcxp_tx_plog(bfa, reqi->req_tot_len, fcxp, &reqi->fchs); - - bfa_reqq_produce(bfa, BFA_REQQ_FCXP, send_req->mh); - - bfa_trc(bfa, bfa_reqq_pi(bfa, BFA_REQQ_FCXP)); - bfa_trc(bfa, bfa_reqq_ci(bfa, BFA_REQQ_FCXP)); -} - -/* - * Allocate an FCXP instance to send a response or to send a request - * that has a response. Request/response buffers are allocated by caller. - * - * @param[in] bfa BFA bfa instance - * @param[in] nreq_sgles Number of SG elements required for request - * buffer. 0, if fcxp internal buffers are used. - * Use bfa_fcxp_get_reqbuf() to get the - * internal req buffer. - * @param[in] req_sgles SG elements describing request buffer. Will be - * copied in by BFA and hence can be freed on - * return from this function. - * @param[in] get_req_sga function ptr to be called to get a request SG - * Address (given the sge index). - * @param[in] get_req_sglen function ptr to be called to get a request SG - * len (given the sge index). - * @param[in] get_rsp_sga function ptr to be called to get a response SG - * Address (given the sge index). - * @param[in] get_rsp_sglen function ptr to be called to get a response SG - * len (given the sge index). - * - * @return FCXP instance. NULL on failure. - */ -struct bfa_fcxp_s * -bfa_fcxp_alloc(void *caller, struct bfa_s *bfa, int nreq_sgles, - int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, - bfa_fcxp_get_sglen_t req_sglen_cbfn, - bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, - bfa_fcxp_get_sglen_t rsp_sglen_cbfn) -{ - struct bfa_fcxp_s *fcxp = NULL; - - WARN_ON(bfa == NULL); - - fcxp = bfa_fcxp_get(BFA_FCXP_MOD(bfa)); - if (fcxp == NULL) - return NULL; - - bfa_trc(bfa, fcxp->fcxp_tag); - - bfa_fcxp_init(fcxp, caller, bfa, nreq_sgles, nrsp_sgles, req_sga_cbfn, - req_sglen_cbfn, rsp_sga_cbfn, rsp_sglen_cbfn); - - return fcxp; -} - -/* - * Get the internal request buffer pointer - * - * @param[in] fcxp BFA fcxp pointer - * - * @return pointer to the internal request buffer - */ -void * -bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - void *reqbuf; - - WARN_ON(fcxp->use_ireqbuf != 1); - reqbuf = bfa_mem_get_dmabuf_kva(mod, fcxp->fcxp_tag, - mod->req_pld_sz + mod->rsp_pld_sz); - return reqbuf; -} - -u32 -bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - - return mod->req_pld_sz; -} - -/* - * Get the internal response buffer pointer - * - * @param[in] fcxp BFA fcxp pointer - * - * @return pointer to the internal request buffer - */ -void * -bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - void *fcxp_buf; - - WARN_ON(fcxp->use_irspbuf != 1); - - fcxp_buf = bfa_mem_get_dmabuf_kva(mod, fcxp->fcxp_tag, - mod->req_pld_sz + mod->rsp_pld_sz); - - /* fcxp_buf = req_buf + rsp_buf :- add req_buf_sz to get to rsp_buf */ - return ((u8 *) fcxp_buf) + mod->req_pld_sz; -} - -/* - * Free the BFA FCXP - * - * @param[in] fcxp BFA fcxp pointer - * - * @return void - */ -void -bfa_fcxp_free(struct bfa_fcxp_s *fcxp) -{ - struct bfa_fcxp_mod_s *mod = fcxp->fcxp_mod; - - WARN_ON(fcxp == NULL); - bfa_trc(mod->bfa, fcxp->fcxp_tag); - bfa_fcxp_put(fcxp); -} - -/* - * Send a FCXP request - * - * @param[in] fcxp BFA fcxp pointer - * @param[in] rport BFA rport pointer. Could be left NULL for WKA rports - * @param[in] vf_id virtual Fabric ID - * @param[in] lp_tag lport tag - * @param[in] cts use Continuous sequence - * @param[in] cos fc Class of Service - * @param[in] reqlen request length, does not include FCHS length - * @param[in] fchs fc Header Pointer. The header content will be copied - * in by BFA. - * - * @param[in] cbfn call back function to be called on receiving - * the response - * @param[in] cbarg arg for cbfn - * @param[in] rsp_timeout - * response timeout - * - * @return bfa_status_t - */ -void -bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, - u16 vf_id, u8 lp_tag, bfa_boolean_t cts, enum fc_cos cos, - u32 reqlen, struct fchs_s *fchs, bfa_cb_fcxp_send_t cbfn, - void *cbarg, u32 rsp_maxlen, u8 rsp_timeout) -{ - struct bfa_s *bfa = fcxp->fcxp_mod->bfa; - struct bfa_fcxp_req_info_s *reqi = &fcxp->req_info; - struct bfa_fcxp_rsp_info_s *rspi = &fcxp->rsp_info; - struct bfi_fcxp_send_req_s *send_req; - - bfa_trc(bfa, fcxp->fcxp_tag); - - /* - * setup request/response info - */ - reqi->bfa_rport = rport; - reqi->vf_id = vf_id; - reqi->lp_tag = lp_tag; - reqi->class = cos; - rspi->rsp_timeout = rsp_timeout; - reqi->cts = cts; - reqi->fchs = *fchs; - reqi->req_tot_len = reqlen; - rspi->rsp_maxlen = rsp_maxlen; - fcxp->send_cbfn = cbfn ? cbfn : bfa_fcxp_null_comp; - fcxp->send_cbarg = cbarg; - - /* - * If no room in CPE queue, wait for space in request queue - */ - send_req = bfa_reqq_next(bfa, BFA_REQQ_FCXP); - if (!send_req) { - bfa_trc(bfa, fcxp->fcxp_tag); - fcxp->reqq_waiting = BFA_TRUE; - bfa_reqq_wait(bfa, BFA_REQQ_FCXP, &fcxp->reqq_wqe); - return; - } - - bfa_fcxp_queue(fcxp, send_req); -} - -/* - * Abort a BFA FCXP - * - * @param[in] fcxp BFA fcxp pointer - * - * @return void - */ -bfa_status_t -bfa_fcxp_abort(struct bfa_fcxp_s *fcxp) -{ - bfa_trc(fcxp->fcxp_mod->bfa, fcxp->fcxp_tag); - WARN_ON(1); - return BFA_STATUS_OK; -} - -void -bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, - bfa_fcxp_alloc_cbfn_t alloc_cbfn, void *alloc_cbarg, - void *caller, int nreq_sgles, - int nrsp_sgles, bfa_fcxp_get_sgaddr_t req_sga_cbfn, - bfa_fcxp_get_sglen_t req_sglen_cbfn, - bfa_fcxp_get_sgaddr_t rsp_sga_cbfn, - bfa_fcxp_get_sglen_t rsp_sglen_cbfn) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - - WARN_ON(!list_empty(&mod->fcxp_free_q)); - - wqe->alloc_cbfn = alloc_cbfn; - wqe->alloc_cbarg = alloc_cbarg; - wqe->caller = caller; - wqe->bfa = bfa; - wqe->nreq_sgles = nreq_sgles; - wqe->nrsp_sgles = nrsp_sgles; - wqe->req_sga_cbfn = req_sga_cbfn; - wqe->req_sglen_cbfn = req_sglen_cbfn; - wqe->rsp_sga_cbfn = rsp_sga_cbfn; - wqe->rsp_sglen_cbfn = rsp_sglen_cbfn; - - list_add_tail(&wqe->qe, &mod->wait_q); -} - -void -bfa_fcxp_walloc_cancel(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - - WARN_ON(!bfa_q_is_on_q(&mod->wait_q, wqe)); - list_del(&wqe->qe); -} - -void -bfa_fcxp_discard(struct bfa_fcxp_s *fcxp) -{ - /* - * If waiting for room in request queue, cancel reqq wait - * and free fcxp. - */ - if (fcxp->reqq_waiting) { - fcxp->reqq_waiting = BFA_FALSE; - bfa_reqq_wcancel(&fcxp->reqq_wqe); - bfa_fcxp_free(fcxp); - return; - } - - fcxp->send_cbfn = bfa_fcxp_null_comp; -} - -void -bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - switch (msg->mhdr.msg_id) { - case BFI_FCXP_I2H_SEND_RSP: - hal_fcxp_send_comp(bfa, (struct bfi_fcxp_send_rsp_s *) msg); - break; - - default: - bfa_trc(bfa, msg->mhdr.msg_id); - WARN_ON(1); - } -} - -u32 -bfa_fcxp_get_maxrsp(struct bfa_s *bfa) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - - return mod->rsp_pld_sz; -} - -void -bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw) -{ - struct bfa_fcxp_mod_s *mod = BFA_FCXP_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_fcxps - num_fcxp_fw); i++) { - bfa_q_deq_tail(&mod->fcxp_free_q, &qe); - list_add_tail(qe, &mod->fcxp_unused_q); - } -} - -/* - * BFA LPS state machine functions - */ - -/* - * Init state -- no login - */ -static void -bfa_lps_sm_init(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->bfa_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_LOGIN: - if (bfa_reqq_full(lps->bfa, lps->reqq)) { - bfa_sm_set_state(lps, bfa_lps_sm_loginwait); - bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); - } else { - bfa_sm_set_state(lps, bfa_lps_sm_login); - bfa_lps_send_login(lps); - } - - if (lps->fdisc) - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, "FDISC Request"); - else - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, "FLOGI Request"); - break; - - case BFA_LPS_SM_LOGOUT: - bfa_lps_logout_comp(lps); - break; - - case BFA_LPS_SM_DELETE: - bfa_lps_free(lps); - break; - - case BFA_LPS_SM_RX_CVL: - case BFA_LPS_SM_OFFLINE: - break; - - case BFA_LPS_SM_FWRSP: - /* - * Could happen when fabric detects loopback and discards - * the lps request. Fw will eventually sent out the timeout - * Just ignore - */ - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/* - * login is in progress -- awaiting response from firmware - */ -static void -bfa_lps_sm_login(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->bfa_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_FWRSP: - if (lps->status == BFA_STATUS_OK) { - bfa_sm_set_state(lps, bfa_lps_sm_online); - if (lps->fdisc) - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, "FDISC Accept"); - else - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, "FLOGI Accept"); - /* If N2N, send the assigned PID to FW */ - bfa_trc(lps->bfa, lps->fport); - bfa_trc(lps->bfa, lps->lp_pid); - - if (!lps->fport && lps->lp_pid) - bfa_sm_send_event(lps, BFA_LPS_SM_SET_N2N_PID); - } else { - bfa_sm_set_state(lps, bfa_lps_sm_init); - if (lps->fdisc) - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, - "FDISC Fail (RJT or timeout)"); - else - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGIN, 0, - "FLOGI Fail (RJT or timeout)"); - } - bfa_lps_login_comp(lps); - break; - - case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - break; - - case BFA_LPS_SM_SET_N2N_PID: - bfa_trc(lps->bfa, lps->fport); - bfa_trc(lps->bfa, lps->lp_pid); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/* - * login pending - awaiting space in request queue - */ -static void -bfa_lps_sm_loginwait(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->bfa_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_RESUME: - bfa_sm_set_state(lps, bfa_lps_sm_login); - bfa_lps_send_login(lps); - break; - - case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - bfa_reqq_wcancel(&lps->wqe); - break; - - case BFA_LPS_SM_RX_CVL: - /* - * Login was not even sent out; so when getting out - * of this state, it will appear like a login retry - * after Clear virtual link - */ - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/* - * login complete - */ -static void -bfa_lps_sm_online(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->bfa_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_LOGOUT: - if (bfa_reqq_full(lps->bfa, lps->reqq)) { - bfa_sm_set_state(lps, bfa_lps_sm_logowait); - bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); - } else { - bfa_sm_set_state(lps, bfa_lps_sm_logout); - bfa_lps_send_logout(lps); - } - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGO, 0, "Logout"); - break; - - case BFA_LPS_SM_RX_CVL: - bfa_sm_set_state(lps, bfa_lps_sm_init); - - /* Let the vport module know about this event */ - bfa_lps_cvl_event(lps); - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx"); - break; - - case BFA_LPS_SM_SET_N2N_PID: - if (bfa_reqq_full(lps->bfa, lps->reqq)) { - bfa_sm_set_state(lps, bfa_lps_sm_online_n2n_pid_wait); - bfa_reqq_wait(lps->bfa, lps->reqq, &lps->wqe); - } else - bfa_lps_send_set_n2n_pid(lps); - break; - - case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/* - * login complete - */ -static void -bfa_lps_sm_online_n2n_pid_wait(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->bfa_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_RESUME: - bfa_sm_set_state(lps, bfa_lps_sm_online); - bfa_lps_send_set_n2n_pid(lps); - break; - - case BFA_LPS_SM_LOGOUT: - bfa_sm_set_state(lps, bfa_lps_sm_logowait); - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_LOGO, 0, "Logout"); - break; - - case BFA_LPS_SM_RX_CVL: - bfa_sm_set_state(lps, bfa_lps_sm_init); - bfa_reqq_wcancel(&lps->wqe); - - /* Let the vport module know about this event */ - bfa_lps_cvl_event(lps); - bfa_plog_str(lps->bfa->plog, BFA_PL_MID_LPS, - BFA_PL_EID_FIP_FCF_CVL, 0, "FCF Clear Virt. Link Rx"); - break; - - case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - bfa_reqq_wcancel(&lps->wqe); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/* - * logout in progress - awaiting firmware response - */ -static void -bfa_lps_sm_logout(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->bfa_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_FWRSP: - bfa_sm_set_state(lps, bfa_lps_sm_init); - bfa_lps_logout_comp(lps); - break; - - case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - -/* - * logout pending -- awaiting space in request queue - */ -static void -bfa_lps_sm_logowait(struct bfa_lps_s *lps, enum bfa_lps_event event) -{ - bfa_trc(lps->bfa, lps->bfa_tag); - bfa_trc(lps->bfa, event); - - switch (event) { - case BFA_LPS_SM_RESUME: - bfa_sm_set_state(lps, bfa_lps_sm_logout); - bfa_lps_send_logout(lps); - break; - - case BFA_LPS_SM_OFFLINE: - case BFA_LPS_SM_DELETE: - bfa_sm_set_state(lps, bfa_lps_sm_init); - bfa_reqq_wcancel(&lps->wqe); - break; - - default: - bfa_sm_fault(lps->bfa, event); - } -} - - - -/* - * lps_pvt BFA LPS private functions - */ - -/* - * return memory requirement - */ -static void -bfa_lps_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_mem_kva_s *lps_kva = BFA_MEM_LPS_KVA(bfa); - - if (cfg->drvcfg.min_cfg) - bfa_mem_kva_setup(minfo, lps_kva, - sizeof(struct bfa_lps_s) * BFA_LPS_MIN_LPORTS); - else - bfa_mem_kva_setup(minfo, lps_kva, - sizeof(struct bfa_lps_s) * BFA_LPS_MAX_LPORTS); -} - -/* - * bfa module attach at initialization time - */ -static void -bfa_lps_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - int i; - - mod->num_lps = BFA_LPS_MAX_LPORTS; - if (cfg->drvcfg.min_cfg) - mod->num_lps = BFA_LPS_MIN_LPORTS; - else - mod->num_lps = BFA_LPS_MAX_LPORTS; - mod->lps_arr = lps = (struct bfa_lps_s *) bfa_mem_kva_curp(mod); - - bfa_mem_kva_curp(mod) += mod->num_lps * sizeof(struct bfa_lps_s); - - INIT_LIST_HEAD(&mod->lps_free_q); - INIT_LIST_HEAD(&mod->lps_active_q); - INIT_LIST_HEAD(&mod->lps_login_q); - - for (i = 0; i < mod->num_lps; i++, lps++) { - lps->bfa = bfa; - lps->bfa_tag = (u8) i; - lps->reqq = BFA_REQQ_LPS; - bfa_reqq_winit(&lps->wqe, bfa_lps_reqq_resume, lps); - list_add_tail(&lps->qe, &mod->lps_free_q); - } -} - -static void -bfa_lps_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_lps_start(struct bfa_s *bfa) -{ -} - -static void -bfa_lps_stop(struct bfa_s *bfa) -{ -} - -/* - * IOC in disabled state -- consider all lps offline - */ -static void -bfa_lps_iocdisable(struct bfa_s *bfa) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - struct list_head *qe, *qen; - - list_for_each_safe(qe, qen, &mod->lps_active_q) { - lps = (struct bfa_lps_s *) qe; - bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); - } - list_for_each_safe(qe, qen, &mod->lps_login_q) { - lps = (struct bfa_lps_s *) qe; - bfa_sm_send_event(lps, BFA_LPS_SM_OFFLINE); - } - list_splice_tail_init(&mod->lps_login_q, &mod->lps_active_q); -} - -/* - * Firmware login response - */ -static void -bfa_lps_login_rsp(struct bfa_s *bfa, struct bfi_lps_login_rsp_s *rsp) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - - WARN_ON(rsp->bfa_tag >= mod->num_lps); - lps = BFA_LPS_FROM_TAG(mod, rsp->bfa_tag); - - lps->status = rsp->status; - switch (rsp->status) { - case BFA_STATUS_OK: - lps->fw_tag = rsp->fw_tag; - lps->fport = rsp->f_port; - if (lps->fport) - lps->lp_pid = rsp->lp_pid; - lps->npiv_en = rsp->npiv_en; - lps->pr_bbcred = be16_to_cpu(rsp->bb_credit); - lps->pr_pwwn = rsp->port_name; - lps->pr_nwwn = rsp->node_name; - lps->auth_req = rsp->auth_req; - lps->lp_mac = rsp->lp_mac; - lps->brcd_switch = rsp->brcd_switch; - lps->fcf_mac = rsp->fcf_mac; - lps->pr_bbscn = rsp->bb_scn; - - break; - - case BFA_STATUS_FABRIC_RJT: - lps->lsrjt_rsn = rsp->lsrjt_rsn; - lps->lsrjt_expl = rsp->lsrjt_expl; - - break; - - case BFA_STATUS_EPROTOCOL: - lps->ext_status = rsp->ext_status; - - break; - - case BFA_STATUS_VPORT_MAX: - if (rsp->ext_status) - bfa_lps_no_res(lps, rsp->ext_status); - break; - - default: - /* Nothing to do with other status */ - break; - } - - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_active_q); - bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); -} - -static void -bfa_lps_no_res(struct bfa_lps_s *first_lps, u8 count) -{ - struct bfa_s *bfa = first_lps->bfa; - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct list_head *qe, *qe_next; - struct bfa_lps_s *lps; - - bfa_trc(bfa, count); - - qe = bfa_q_next(first_lps); - - while (count && qe) { - qe_next = bfa_q_next(qe); - lps = (struct bfa_lps_s *)qe; - bfa_trc(bfa, lps->bfa_tag); - lps->status = first_lps->status; - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_active_q); - bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); - qe = qe_next; - count--; - } -} - -/* - * Firmware logout response - */ -static void -bfa_lps_logout_rsp(struct bfa_s *bfa, struct bfi_lps_logout_rsp_s *rsp) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - - WARN_ON(rsp->bfa_tag >= mod->num_lps); - lps = BFA_LPS_FROM_TAG(mod, rsp->bfa_tag); - - bfa_sm_send_event(lps, BFA_LPS_SM_FWRSP); -} - -/* - * Firmware received a Clear virtual link request (for FCoE) - */ -static void -bfa_lps_rx_cvl_event(struct bfa_s *bfa, struct bfi_lps_cvl_event_s *cvl) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - - lps = BFA_LPS_FROM_TAG(mod, cvl->bfa_tag); - - bfa_sm_send_event(lps, BFA_LPS_SM_RX_CVL); -} - -/* - * Space is available in request queue, resume queueing request to firmware. - */ -static void -bfa_lps_reqq_resume(void *lps_arg) -{ - struct bfa_lps_s *lps = lps_arg; - - bfa_sm_send_event(lps, BFA_LPS_SM_RESUME); -} - -/* - * lps is freed -- triggered by vport delete - */ -static void -bfa_lps_free(struct bfa_lps_s *lps) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa); - - lps->lp_pid = 0; - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_free_q); -} - -/* - * send login request to firmware - */ -static void -bfa_lps_send_login(struct bfa_lps_s *lps) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(lps->bfa); - struct bfi_lps_login_req_s *m; - - m = bfa_reqq_next(lps->bfa, lps->reqq); - WARN_ON(!m); - - bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGIN_REQ, - bfa_fn_lpu(lps->bfa)); - - m->bfa_tag = lps->bfa_tag; - m->alpa = lps->alpa; - m->pdu_size = cpu_to_be16(lps->pdusz); - m->pwwn = lps->pwwn; - m->nwwn = lps->nwwn; - m->fdisc = lps->fdisc; - m->auth_en = lps->auth_en; - m->bb_scn = lps->bb_scn; - - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); - list_del(&lps->qe); - list_add_tail(&lps->qe, &mod->lps_login_q); -} - -/* - * send logout request to firmware - */ -static void -bfa_lps_send_logout(struct bfa_lps_s *lps) -{ - struct bfi_lps_logout_req_s *m; - - m = bfa_reqq_next(lps->bfa, lps->reqq); - WARN_ON(!m); - - bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_LOGOUT_REQ, - bfa_fn_lpu(lps->bfa)); - - m->fw_tag = lps->fw_tag; - m->port_name = lps->pwwn; - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); -} - -/* - * send n2n pid set request to firmware - */ -static void -bfa_lps_send_set_n2n_pid(struct bfa_lps_s *lps) -{ - struct bfi_lps_n2n_pid_req_s *m; - - m = bfa_reqq_next(lps->bfa, lps->reqq); - WARN_ON(!m); - - bfi_h2i_set(m->mh, BFI_MC_LPS, BFI_LPS_H2I_N2N_PID_REQ, - bfa_fn_lpu(lps->bfa)); - - m->fw_tag = lps->fw_tag; - m->lp_pid = lps->lp_pid; - bfa_reqq_produce(lps->bfa, lps->reqq, m->mh); -} - -/* - * Indirect login completion handler for non-fcs - */ -static void -bfa_lps_login_comp_cb(void *arg, bfa_boolean_t complete) -{ - struct bfa_lps_s *lps = arg; - - if (!complete) - return; - - if (lps->fdisc) - bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); - else - bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); -} - -/* - * Login completion handler -- direct call for fcs, queue for others - */ -static void -bfa_lps_login_comp(struct bfa_lps_s *lps) -{ - if (!lps->bfa->fcs) { - bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_login_comp_cb, - lps); - return; - } - - if (lps->fdisc) - bfa_cb_lps_fdisc_comp(lps->bfa->bfad, lps->uarg, lps->status); - else - bfa_cb_lps_flogi_comp(lps->bfa->bfad, lps->uarg, lps->status); -} - -/* - * Indirect logout completion handler for non-fcs - */ -static void -bfa_lps_logout_comp_cb(void *arg, bfa_boolean_t complete) -{ - struct bfa_lps_s *lps = arg; - - if (!complete) - return; - - if (lps->fdisc) - bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); -} - -/* - * Logout completion handler -- direct call for fcs, queue for others - */ -static void -bfa_lps_logout_comp(struct bfa_lps_s *lps) -{ - if (!lps->bfa->fcs) { - bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_logout_comp_cb, - lps); - return; - } - if (lps->fdisc) - bfa_cb_lps_fdisclogo_comp(lps->bfa->bfad, lps->uarg); -} - -/* - * Clear virtual link completion handler for non-fcs - */ -static void -bfa_lps_cvl_event_cb(void *arg, bfa_boolean_t complete) -{ - struct bfa_lps_s *lps = arg; - - if (!complete) - return; - - /* Clear virtual link to base port will result in link down */ - if (lps->fdisc) - bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg); -} - -/* - * Received Clear virtual link event --direct call for fcs, - * queue for others - */ -static void -bfa_lps_cvl_event(struct bfa_lps_s *lps) -{ - if (!lps->bfa->fcs) { - bfa_cb_queue(lps->bfa, &lps->hcb_qe, bfa_lps_cvl_event_cb, - lps); - return; - } - - /* Clear virtual link to base port will result in link down */ - if (lps->fdisc) - bfa_cb_lps_cvl_event(lps->bfa->bfad, lps->uarg); -} - - - -/* - * lps_public BFA LPS public functions - */ - -u32 -bfa_lps_get_max_vport(struct bfa_s *bfa) -{ - if (bfa_ioc_devid(&bfa->ioc) == BFA_PCI_DEVICE_ID_CT) - return BFA_LPS_MAX_VPORTS_SUPP_CT; - else - return BFA_LPS_MAX_VPORTS_SUPP_CB; -} - -/* - * Allocate a lport srvice tag. - */ -struct bfa_lps_s * -bfa_lps_alloc(struct bfa_s *bfa) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps = NULL; - - bfa_q_deq(&mod->lps_free_q, &lps); - - if (lps == NULL) - return NULL; - - list_add_tail(&lps->qe, &mod->lps_active_q); - - bfa_sm_set_state(lps, bfa_lps_sm_init); - return lps; -} - -/* - * Free lport service tag. This can be called anytime after an alloc. - * No need to wait for any pending login/logout completions. - */ -void -bfa_lps_delete(struct bfa_lps_s *lps) -{ - bfa_sm_send_event(lps, BFA_LPS_SM_DELETE); -} - -/* - * Initiate a lport login. - */ -void -bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, u16 pdusz, - wwn_t pwwn, wwn_t nwwn, bfa_boolean_t auth_en, uint8_t bb_scn) -{ - lps->uarg = uarg; - lps->alpa = alpa; - lps->pdusz = pdusz; - lps->pwwn = pwwn; - lps->nwwn = nwwn; - lps->fdisc = BFA_FALSE; - lps->auth_en = auth_en; - lps->bb_scn = bb_scn; - bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); -} - -/* - * Initiate a lport fdisc login. - */ -void -bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, wwn_t pwwn, - wwn_t nwwn) -{ - lps->uarg = uarg; - lps->alpa = 0; - lps->pdusz = pdusz; - lps->pwwn = pwwn; - lps->nwwn = nwwn; - lps->fdisc = BFA_TRUE; - lps->auth_en = BFA_FALSE; - bfa_sm_send_event(lps, BFA_LPS_SM_LOGIN); -} - - -/* - * Initiate a lport FDSIC logout. - */ -void -bfa_lps_fdisclogo(struct bfa_lps_s *lps) -{ - bfa_sm_send_event(lps, BFA_LPS_SM_LOGOUT); -} - -u8 -bfa_lps_get_fwtag(struct bfa_s *bfa, u8 lp_tag) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - - return BFA_LPS_FROM_TAG(mod, lp_tag)->fw_tag; -} - -/* - * Return lport services tag given the pid - */ -u8 -bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - struct bfa_lps_s *lps; - int i; - - for (i = 0, lps = mod->lps_arr; i < mod->num_lps; i++, lps++) { - if (lps->lp_pid == pid) - return lps->bfa_tag; - } - - /* Return base port tag anyway */ - return 0; -} - - -/* - * return port id assigned to the base lport - */ -u32 -bfa_lps_get_base_pid(struct bfa_s *bfa) -{ - struct bfa_lps_mod_s *mod = BFA_LPS_MOD(bfa); - - return BFA_LPS_FROM_TAG(mod, 0)->lp_pid; -} - -/* - * Set PID in case of n2n (which is assigned during PLOGI) - */ -void -bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, uint32_t n2n_pid) -{ - bfa_trc(lps->bfa, lps->bfa_tag); - bfa_trc(lps->bfa, n2n_pid); - - lps->lp_pid = n2n_pid; - bfa_sm_send_event(lps, BFA_LPS_SM_SET_N2N_PID); -} - -/* - * LPS firmware message class handler. - */ -void -bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - union bfi_lps_i2h_msg_u msg; - - bfa_trc(bfa, m->mhdr.msg_id); - msg.msg = m; - - switch (m->mhdr.msg_id) { - case BFI_LPS_I2H_LOGIN_RSP: - bfa_lps_login_rsp(bfa, msg.login_rsp); - break; - - case BFI_LPS_I2H_LOGOUT_RSP: - bfa_lps_logout_rsp(bfa, msg.logout_rsp); - break; - - case BFI_LPS_I2H_CVL_EVENT: - bfa_lps_rx_cvl_event(bfa, msg.cvl_event); - break; - - default: - bfa_trc(bfa, m->mhdr.msg_id); - WARN_ON(1); - } -} - -static void -bfa_fcport_aen_post(struct bfa_fcport_s *fcport, enum bfa_port_aen_event event) -{ - struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; - struct bfa_aen_entry_s *aen_entry; - - bfad_get_aen_entry(bfad, aen_entry); - if (!aen_entry) - return; - - aen_entry->aen_data.port.ioc_type = bfa_get_type(fcport->bfa); - aen_entry->aen_data.port.pwwn = fcport->pwwn; - - /* Send the AEN notification */ - bfad_im_post_vendor_event(aen_entry, bfad, ++fcport->bfa->bfa_aen_seq, - BFA_AEN_CAT_PORT, event); -} - -/* - * FC PORT state machine functions - */ -static void -bfa_fcport_sm_uninit(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - /* - * Start event after IOC is configured and BFA is started. - */ - fcport->use_flash_cfg = BFA_TRUE; - - if (bfa_fcport_send_enable(fcport)) { - bfa_trc(fcport->bfa, BFA_TRUE); - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - } else { - bfa_trc(fcport->bfa, BFA_FALSE); - bfa_sm_set_state(fcport, - bfa_fcport_sm_enabling_qwait); - } - break; - - case BFA_FCPORT_SM_ENABLE: - /* - * Port is persistently configured to be in enabled state. Do - * not change state. Port enabling is done when START event is - * received. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - /* - * If a port is persistently configured to be disabled, the - * first event will a port disable request. - */ - bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_enabling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - char pwwn_buf[BFA_STRING_32]; - struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_QRESUME: - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - bfa_fcport_send_enable(fcport); - break; - - case BFA_FCPORT_SM_STOP: - bfa_reqq_wcancel(&fcport->reqq_wait); - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_ENABLE: - /* - * Already enable is in progress. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - /* - * Just send disable request to firmware when room becomes - * available in request queue. - */ - bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); - bfa_reqq_wcancel(&fcport->reqq_wait); - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); - wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port disabled: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); - break; - - case BFA_FCPORT_SM_LINKUP: - case BFA_FCPORT_SM_LINKDOWN: - /* - * Possible to get link events when doing back-to-back - * enable/disables. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_reqq_wcancel(&fcport->reqq_wait); - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_enabling(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - char pwwn_buf[BFA_STRING_32]; - struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_FWRSP: - case BFA_FCPORT_SM_LINKDOWN: - bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown); - break; - - case BFA_FCPORT_SM_LINKUP: - bfa_fcport_update_linkinfo(fcport); - bfa_sm_set_state(fcport, bfa_fcport_sm_linkup); - - WARN_ON(!fcport->event_cbfn); - bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE); - break; - - case BFA_FCPORT_SM_ENABLE: - /* - * Already being enabled. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - if (bfa_fcport_send_disable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - else - bfa_sm_set_state(fcport, - bfa_fcport_sm_disabling_qwait); - - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); - wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port disabled: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_linkdown(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event; - char pwwn_buf[BFA_STRING_32]; - struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; - - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_LINKUP: - bfa_fcport_update_linkinfo(fcport); - bfa_sm_set_state(fcport, bfa_fcport_sm_linkup); - WARN_ON(!fcport->event_cbfn); - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkup"); - if (!bfa_ioc_get_fcmode(&fcport->bfa->ioc)) { - - bfa_trc(fcport->bfa, - pevent->link_state.vc_fcf.fcf.fipenabled); - bfa_trc(fcport->bfa, - pevent->link_state.vc_fcf.fcf.fipfailed); - - if (pevent->link_state.vc_fcf.fcf.fipfailed) - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_FIP_FCF_DISC, 0, - "FIP FCF Discovery Failed"); - else - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_FIP_FCF_DISC, 0, - "FIP FCF Discovered"); - } - - bfa_fcport_scn(fcport, BFA_PORT_LINKUP, BFA_FALSE); - wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port online: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ONLINE); - - /* If QoS is enabled and it is not online, send AEN */ - if (fcport->cfg.qos_enabled && - fcport->qos_attr.state != BFA_QOS_ONLINE) - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_QOS_NEG); - break; - - case BFA_FCPORT_SM_LINKDOWN: - /* - * Possible to get link down event. - */ - break; - - case BFA_FCPORT_SM_ENABLE: - /* - * Already enabled. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - if (bfa_fcport_send_disable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - else - bfa_sm_set_state(fcport, - bfa_fcport_sm_disabling_qwait); - - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); - wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port disabled: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_linkup(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - char pwwn_buf[BFA_STRING_32]; - struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; - - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_ENABLE: - /* - * Already enabled. - */ - break; - - case BFA_FCPORT_SM_DISABLE: - if (bfa_fcport_send_disable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - else - bfa_sm_set_state(fcport, - bfa_fcport_sm_disabling_qwait); - - bfa_fcport_reset_linkinfo(fcport); - bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_DISABLE, 0, "Port Disable"); - wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port offline: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port disabled: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISABLE); - break; - - case BFA_FCPORT_SM_LINKDOWN: - bfa_sm_set_state(fcport, bfa_fcport_sm_linkdown); - bfa_fcport_reset_linkinfo(fcport); - bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_ST_CHANGE, 0, "Port Linkdown"); - wwn2str(pwwn_buf, fcport->pwwn); - if (BFA_PORT_IS_DISABLED(fcport->bfa)) { - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port offline: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE); - } else { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "Base port (WWN = %s) " - "lost fabric connectivity\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); - } - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - bfa_fcport_reset_linkinfo(fcport); - wwn2str(pwwn_buf, fcport->pwwn); - if (BFA_PORT_IS_DISABLED(fcport->bfa)) { - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port offline: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE); - } else { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "Base port (WWN = %s) " - "lost fabric connectivity\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); - } - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - bfa_fcport_reset_linkinfo(fcport); - bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_FALSE); - wwn2str(pwwn_buf, fcport->pwwn); - if (BFA_PORT_IS_DISABLED(fcport->bfa)) { - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port offline: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_OFFLINE); - } else { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "Base port (WWN = %s) " - "lost fabric connectivity\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_DISCONNECT); - } - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_disabling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_QRESUME: - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - bfa_fcport_send_disable(fcport); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - bfa_reqq_wcancel(&fcport->reqq_wait); - break; - - case BFA_FCPORT_SM_ENABLE: - bfa_sm_set_state(fcport, bfa_fcport_sm_toggling_qwait); - break; - - case BFA_FCPORT_SM_DISABLE: - /* - * Already being disabled. - */ - break; - - case BFA_FCPORT_SM_LINKUP: - case BFA_FCPORT_SM_LINKDOWN: - /* - * Possible to get link events when doing back-to-back - * enable/disables. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); - bfa_reqq_wcancel(&fcport->reqq_wait); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_toggling_qwait(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_QRESUME: - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling); - bfa_fcport_send_disable(fcport); - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, - bfa_fcport_sm_enabling_qwait); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - bfa_reqq_wcancel(&fcport->reqq_wait); - break; - - case BFA_FCPORT_SM_ENABLE: - break; - - case BFA_FCPORT_SM_DISABLE: - bfa_sm_set_state(fcport, bfa_fcport_sm_disabling_qwait); - break; - - case BFA_FCPORT_SM_LINKUP: - case BFA_FCPORT_SM_LINKDOWN: - /* - * Possible to get link events when doing back-to-back - * enable/disables. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); - bfa_reqq_wcancel(&fcport->reqq_wait); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_disabling(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - char pwwn_buf[BFA_STRING_32]; - struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_FWRSP: - bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); - break; - - case BFA_FCPORT_SM_DISABLE: - /* - * Already being disabled. - */ - break; - - case BFA_FCPORT_SM_ENABLE: - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, - bfa_fcport_sm_enabling_qwait); - - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); - wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port enabled: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE); - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_LINKUP: - case BFA_FCPORT_SM_LINKDOWN: - /* - * Possible to get link events when doing back-to-back - * enable/disables. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_disabled(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - char pwwn_buf[BFA_STRING_32]; - struct bfad_s *bfad = (struct bfad_s *)fcport->bfa->bfad; - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - /* - * Ignore start event for a port that is disabled. - */ - break; - - case BFA_FCPORT_SM_STOP: - bfa_sm_set_state(fcport, bfa_fcport_sm_stopped); - break; - - case BFA_FCPORT_SM_ENABLE: - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, - bfa_fcport_sm_enabling_qwait); - - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_PORT_ENABLE, 0, "Port Enable"); - wwn2str(pwwn_buf, fcport->pwwn); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "Base port enabled: WWN = %s\n", pwwn_buf); - bfa_fcport_aen_post(fcport, BFA_PORT_AEN_ENABLE); - break; - - case BFA_FCPORT_SM_DISABLE: - /* - * Already disabled. - */ - break; - - case BFA_FCPORT_SM_HWFAIL: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocfail); - break; - - default: - bfa_sm_fault(fcport->bfa, event); - } -} - -static void -bfa_fcport_sm_stopped(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, - bfa_fcport_sm_enabling_qwait); - break; - - default: - /* - * Ignore all other events. - */ - ; - } -} - -/* - * Port is enabled. IOC is down/failed. - */ -static void -bfa_fcport_sm_iocdown(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - if (bfa_fcport_send_enable(fcport)) - bfa_sm_set_state(fcport, bfa_fcport_sm_enabling); - else - bfa_sm_set_state(fcport, - bfa_fcport_sm_enabling_qwait); - break; - - default: - /* - * Ignore all events. - */ - ; - } -} - -/* - * Port is disabled. IOC is down/failed. - */ -static void -bfa_fcport_sm_iocfail(struct bfa_fcport_s *fcport, - enum bfa_fcport_sm_event event) -{ - bfa_trc(fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_SM_START: - bfa_sm_set_state(fcport, bfa_fcport_sm_disabled); - break; - - case BFA_FCPORT_SM_ENABLE: - bfa_sm_set_state(fcport, bfa_fcport_sm_iocdown); - break; - - default: - /* - * Ignore all events. - */ - ; - } -} - -/* - * Link state is down - */ -static void -bfa_fcport_ln_sm_dn(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKUP: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_nf); - bfa_fcport_queue_cb(ln, BFA_PORT_LINKUP); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/* - * Link state is waiting for down notification - */ -static void -bfa_fcport_ln_sm_dn_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKUP: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_up_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/* - * Link state is waiting for down notification and there is a pending up - */ -static void -bfa_fcport_ln_sm_dn_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKDOWN: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_nf); - bfa_fcport_queue_cb(ln, BFA_PORT_LINKUP); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/* - * Link state is up - */ -static void -bfa_fcport_ln_sm_up(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKDOWN: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); - bfa_fcport_queue_cb(ln, BFA_PORT_LINKDOWN); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/* - * Link state is waiting for up notification - */ -static void -bfa_fcport_ln_sm_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKDOWN: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/* - * Link state is waiting for up notification and there is a pending down - */ -static void -bfa_fcport_ln_sm_up_dn_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKUP: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_up_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_nf); - bfa_fcport_queue_cb(ln, BFA_PORT_LINKDOWN); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -/* - * Link state is waiting for up notification and there are pending down and up - */ -static void -bfa_fcport_ln_sm_up_dn_up_nf(struct bfa_fcport_ln_s *ln, - enum bfa_fcport_ln_sm_event event) -{ - bfa_trc(ln->fcport->bfa, event); - - switch (event) { - case BFA_FCPORT_LN_SM_LINKDOWN: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_up_dn_nf); - break; - - case BFA_FCPORT_LN_SM_NOTIFICATION: - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn_up_nf); - bfa_fcport_queue_cb(ln, BFA_PORT_LINKDOWN); - break; - - default: - bfa_sm_fault(ln->fcport->bfa, event); - } -} - -static void -__bfa_cb_fcport_event(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_fcport_ln_s *ln = cbarg; - - if (complete) - ln->fcport->event_cbfn(ln->fcport->event_cbarg, ln->ln_event); - else - bfa_sm_send_event(ln, BFA_FCPORT_LN_SM_NOTIFICATION); -} - -/* - * Send SCN notification to upper layers. - * trunk - false if caller is fcport to ignore fcport event in trunked mode - */ -static void -bfa_fcport_scn(struct bfa_fcport_s *fcport, enum bfa_port_linkstate event, - bfa_boolean_t trunk) -{ - if (fcport->cfg.trunked && !trunk) - return; - - switch (event) { - case BFA_PORT_LINKUP: - bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKUP); - break; - case BFA_PORT_LINKDOWN: - bfa_sm_send_event(&fcport->ln, BFA_FCPORT_LN_SM_LINKDOWN); - break; - default: - WARN_ON(1); - } -} - -static void -bfa_fcport_queue_cb(struct bfa_fcport_ln_s *ln, enum bfa_port_linkstate event) -{ - struct bfa_fcport_s *fcport = ln->fcport; - - if (fcport->bfa->fcs) { - fcport->event_cbfn(fcport->event_cbarg, event); - bfa_sm_send_event(ln, BFA_FCPORT_LN_SM_NOTIFICATION); - } else { - ln->ln_event = event; - bfa_cb_queue(fcport->bfa, &ln->ln_qe, - __bfa_cb_fcport_event, ln); - } -} - -#define FCPORT_STATS_DMA_SZ (BFA_ROUNDUP(sizeof(union bfa_fcport_stats_u), \ - BFA_CACHELINE_SZ)) - -static void -bfa_fcport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_mem_dma_s *fcport_dma = BFA_MEM_FCPORT_DMA(bfa); - - bfa_mem_dma_setup(minfo, fcport_dma, FCPORT_STATS_DMA_SZ); -} - -static void -bfa_fcport_qresume(void *cbarg) -{ - struct bfa_fcport_s *fcport = cbarg; - - bfa_sm_send_event(fcport, BFA_FCPORT_SM_QRESUME); -} - -static void -bfa_fcport_mem_claim(struct bfa_fcport_s *fcport) -{ - struct bfa_mem_dma_s *fcport_dma = &fcport->fcport_dma; - - fcport->stats_kva = bfa_mem_dma_virt(fcport_dma); - fcport->stats_pa = bfa_mem_dma_phys(fcport_dma); - fcport->stats = (union bfa_fcport_stats_u *) - bfa_mem_dma_virt(fcport_dma); -} - -/* - * Memory initialization. - */ -static void -bfa_fcport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - struct bfa_port_cfg_s *port_cfg = &fcport->cfg; - struct bfa_fcport_ln_s *ln = &fcport->ln; - struct timeval tv; - - fcport->bfa = bfa; - ln->fcport = fcport; - - bfa_fcport_mem_claim(fcport); - - bfa_sm_set_state(fcport, bfa_fcport_sm_uninit); - bfa_sm_set_state(ln, bfa_fcport_ln_sm_dn); - - /* - * initialize time stamp for stats reset - */ - do_gettimeofday(&tv); - fcport->stats_reset_time = tv.tv_sec; - - /* - * initialize and set default configuration - */ - port_cfg->topology = BFA_PORT_TOPOLOGY_P2P; - port_cfg->speed = BFA_PORT_SPEED_AUTO; - port_cfg->trunked = BFA_FALSE; - port_cfg->maxfrsize = 0; - - port_cfg->trl_def_speed = BFA_PORT_SPEED_1GBPS; - - INIT_LIST_HEAD(&fcport->stats_pending_q); - INIT_LIST_HEAD(&fcport->statsclr_pending_q); - - bfa_reqq_winit(&fcport->reqq_wait, bfa_fcport_qresume, fcport); -} - -static void -bfa_fcport_detach(struct bfa_s *bfa) -{ -} - -/* - * Called when IOC is ready. - */ -static void -bfa_fcport_start(struct bfa_s *bfa) -{ - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_START); -} - -/* - * Called before IOC is stopped. - */ -static void -bfa_fcport_stop(struct bfa_s *bfa) -{ - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_STOP); - bfa_trunk_iocdisable(bfa); -} - -/* - * Called when IOC failure is detected. - */ -static void -bfa_fcport_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_sm_send_event(fcport, BFA_FCPORT_SM_HWFAIL); - bfa_trunk_iocdisable(bfa); -} - -static void -bfa_fcport_update_linkinfo(struct bfa_fcport_s *fcport) -{ - struct bfi_fcport_event_s *pevent = fcport->event_arg.i2hmsg.event; - struct bfa_fcport_trunk_s *trunk = &fcport->trunk; - - fcport->speed = pevent->link_state.speed; - fcport->topology = pevent->link_state.topology; - - if (fcport->topology == BFA_PORT_TOPOLOGY_LOOP) - fcport->myalpa = 0; - - /* QoS Details */ - fcport->qos_attr = pevent->link_state.qos_attr; - fcport->qos_vc_attr = pevent->link_state.vc_fcf.qos_vc_attr; - - /* - * update trunk state if applicable - */ - if (!fcport->cfg.trunked) - trunk->attr.state = BFA_TRUNK_DISABLED; - - /* update FCoE specific */ - fcport->fcoe_vlan = be16_to_cpu(pevent->link_state.vc_fcf.fcf.vlan); - - bfa_trc(fcport->bfa, fcport->speed); - bfa_trc(fcport->bfa, fcport->topology); -} - -static void -bfa_fcport_reset_linkinfo(struct bfa_fcport_s *fcport) -{ - fcport->speed = BFA_PORT_SPEED_UNKNOWN; - fcport->topology = BFA_PORT_TOPOLOGY_NONE; - fcport->bbsc_op_state = BFA_FALSE; -} - -/* - * Send port enable message to firmware. - */ -static bfa_boolean_t -bfa_fcport_send_enable(struct bfa_fcport_s *fcport) -{ - struct bfi_fcport_enable_req_s *m; - - /* - * Increment message tag before queue check, so that responses to old - * requests are discarded. - */ - fcport->msgtag++; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - if (!m) { - bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, - &fcport->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_ENABLE_REQ, - bfa_fn_lpu(fcport->bfa)); - m->nwwn = fcport->nwwn; - m->pwwn = fcport->pwwn; - m->port_cfg = fcport->cfg; - m->msgtag = fcport->msgtag; - m->port_cfg.maxfrsize = cpu_to_be16(fcport->cfg.maxfrsize); - m->use_flash_cfg = fcport->use_flash_cfg; - bfa_dma_be_addr_set(m->stats_dma_addr, fcport->stats_pa); - bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_lo); - bfa_trc(fcport->bfa, m->stats_dma_addr.a32.addr_hi); - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh); - return BFA_TRUE; -} - -/* - * Send port disable message to firmware. - */ -static bfa_boolean_t -bfa_fcport_send_disable(struct bfa_fcport_s *fcport) -{ - struct bfi_fcport_req_s *m; - - /* - * Increment message tag before queue check, so that responses to old - * requests are discarded. - */ - fcport->msgtag++; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - if (!m) { - bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, - &fcport->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_DISABLE_REQ, - bfa_fn_lpu(fcport->bfa)); - m->msgtag = fcport->msgtag; - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, m->mh); - - return BFA_TRUE; -} - -static void -bfa_fcport_set_wwns(struct bfa_fcport_s *fcport) -{ - fcport->pwwn = fcport->bfa->ioc.attr->pwwn; - fcport->nwwn = fcport->bfa->ioc.attr->nwwn; - - bfa_trc(fcport->bfa, fcport->pwwn); - bfa_trc(fcport->bfa, fcport->nwwn); -} - -static void -bfa_fcport_qos_stats_swap(struct bfa_qos_stats_s *d, - struct bfa_qos_stats_s *s) -{ - u32 *dip = (u32 *) d; - __be32 *sip = (__be32 *) s; - int i; - - /* Now swap the 32 bit fields */ - for (i = 0; i < (sizeof(struct bfa_qos_stats_s)/sizeof(u32)); ++i) - dip[i] = be32_to_cpu(sip[i]); -} - -static void -bfa_fcport_fcoe_stats_swap(struct bfa_fcoe_stats_s *d, - struct bfa_fcoe_stats_s *s) -{ - u32 *dip = (u32 *) d; - __be32 *sip = (__be32 *) s; - int i; - - for (i = 0; i < ((sizeof(struct bfa_fcoe_stats_s))/sizeof(u32)); - i = i + 2) { -#ifdef __BIG_ENDIAN - dip[i] = be32_to_cpu(sip[i]); - dip[i + 1] = be32_to_cpu(sip[i + 1]); -#else - dip[i] = be32_to_cpu(sip[i + 1]); - dip[i + 1] = be32_to_cpu(sip[i]); -#endif - } -} - -static void -__bfa_cb_fcport_stats_get(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *)cbarg; - struct bfa_cb_pending_q_s *cb; - struct list_head *qe, *qen; - union bfa_fcport_stats_u *ret; - - if (complete) { - struct timeval tv; - if (fcport->stats_status == BFA_STATUS_OK) - do_gettimeofday(&tv); - - list_for_each_safe(qe, qen, &fcport->stats_pending_q) { - bfa_q_deq(&fcport->stats_pending_q, &qe); - cb = (struct bfa_cb_pending_q_s *)qe; - if (fcport->stats_status == BFA_STATUS_OK) { - ret = (union bfa_fcport_stats_u *)cb->data; - /* Swap FC QoS or FCoE stats */ - if (bfa_ioc_get_fcmode(&fcport->bfa->ioc)) - bfa_fcport_qos_stats_swap(&ret->fcqos, - &fcport->stats->fcqos); - else { - bfa_fcport_fcoe_stats_swap(&ret->fcoe, - &fcport->stats->fcoe); - ret->fcoe.secs_reset = - tv.tv_sec - fcport->stats_reset_time; - } - } - bfa_cb_queue_status(fcport->bfa, &cb->hcb_qe, - fcport->stats_status); - } - fcport->stats_status = BFA_STATUS_OK; - } else { - INIT_LIST_HEAD(&fcport->stats_pending_q); - fcport->stats_status = BFA_STATUS_OK; - } -} - -static void -bfa_fcport_stats_get_timeout(void *cbarg) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - - bfa_trc(fcport->bfa, fcport->stats_qfull); - - if (fcport->stats_qfull) { - bfa_reqq_wcancel(&fcport->stats_reqq_wait); - fcport->stats_qfull = BFA_FALSE; - } - - fcport->stats_status = BFA_STATUS_ETIMER; - __bfa_cb_fcport_stats_get(fcport, BFA_TRUE); -} - -static void -bfa_fcport_send_stats_get(void *cbarg) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - struct bfi_fcport_req_s *msg; - - msg = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - - if (!msg) { - fcport->stats_qfull = BFA_TRUE; - bfa_reqq_winit(&fcport->stats_reqq_wait, - bfa_fcport_send_stats_get, fcport); - bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, - &fcport->stats_reqq_wait); - return; - } - fcport->stats_qfull = BFA_FALSE; - - memset(msg, 0, sizeof(struct bfi_fcport_req_s)); - bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_GET_REQ, - bfa_fn_lpu(fcport->bfa)); - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, msg->mh); -} - -static void -__bfa_cb_fcport_stats_clr(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - struct bfa_cb_pending_q_s *cb; - struct list_head *qe, *qen; - - if (complete) { - struct timeval tv; - - /* - * re-initialize time stamp for stats reset - */ - do_gettimeofday(&tv); - fcport->stats_reset_time = tv.tv_sec; - list_for_each_safe(qe, qen, &fcport->statsclr_pending_q) { - bfa_q_deq(&fcport->statsclr_pending_q, &qe); - cb = (struct bfa_cb_pending_q_s *)qe; - bfa_cb_queue_status(fcport->bfa, &cb->hcb_qe, - fcport->stats_status); - } - fcport->stats_status = BFA_STATUS_OK; - } else { - INIT_LIST_HEAD(&fcport->statsclr_pending_q); - fcport->stats_status = BFA_STATUS_OK; - } -} - -static void -bfa_fcport_stats_clr_timeout(void *cbarg) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - - bfa_trc(fcport->bfa, fcport->stats_qfull); - - if (fcport->stats_qfull) { - bfa_reqq_wcancel(&fcport->stats_reqq_wait); - fcport->stats_qfull = BFA_FALSE; - } - - fcport->stats_status = BFA_STATUS_ETIMER; - __bfa_cb_fcport_stats_clr(fcport, BFA_TRUE); -} - -static void -bfa_fcport_send_stats_clear(void *cbarg) -{ - struct bfa_fcport_s *fcport = (struct bfa_fcport_s *) cbarg; - struct bfi_fcport_req_s *msg; - - msg = bfa_reqq_next(fcport->bfa, BFA_REQQ_PORT); - - if (!msg) { - fcport->stats_qfull = BFA_TRUE; - bfa_reqq_winit(&fcport->stats_reqq_wait, - bfa_fcport_send_stats_clear, fcport); - bfa_reqq_wait(fcport->bfa, BFA_REQQ_PORT, - &fcport->stats_reqq_wait); - return; - } - fcport->stats_qfull = BFA_FALSE; - - memset(msg, 0, sizeof(struct bfi_fcport_req_s)); - bfi_h2i_set(msg->mh, BFI_MC_FCPORT, BFI_FCPORT_H2I_STATS_CLEAR_REQ, - bfa_fn_lpu(fcport->bfa)); - bfa_reqq_produce(fcport->bfa, BFA_REQQ_PORT, msg->mh); -} - -/* - * Handle trunk SCN event from firmware. - */ -static void -bfa_trunk_scn(struct bfa_fcport_s *fcport, struct bfi_fcport_trunk_scn_s *scn) -{ - struct bfa_fcport_trunk_s *trunk = &fcport->trunk; - struct bfi_fcport_trunk_link_s *tlink; - struct bfa_trunk_link_attr_s *lattr; - enum bfa_trunk_state state_prev; - int i; - int link_bm = 0; - - bfa_trc(fcport->bfa, fcport->cfg.trunked); - WARN_ON(scn->trunk_state != BFA_TRUNK_ONLINE && - scn->trunk_state != BFA_TRUNK_OFFLINE); - - bfa_trc(fcport->bfa, trunk->attr.state); - bfa_trc(fcport->bfa, scn->trunk_state); - bfa_trc(fcport->bfa, scn->trunk_speed); - - /* - * Save off new state for trunk attribute query - */ - state_prev = trunk->attr.state; - if (fcport->cfg.trunked && (trunk->attr.state != BFA_TRUNK_DISABLED)) - trunk->attr.state = scn->trunk_state; - trunk->attr.speed = scn->trunk_speed; - for (i = 0; i < BFA_TRUNK_MAX_PORTS; i++) { - lattr = &trunk->attr.link_attr[i]; - tlink = &scn->tlink[i]; - - lattr->link_state = tlink->state; - lattr->trunk_wwn = tlink->trunk_wwn; - lattr->fctl = tlink->fctl; - lattr->speed = tlink->speed; - lattr->deskew = be32_to_cpu(tlink->deskew); - - if (tlink->state == BFA_TRUNK_LINK_STATE_UP) { - fcport->speed = tlink->speed; - fcport->topology = BFA_PORT_TOPOLOGY_P2P; - link_bm |= 1 << i; - } - - bfa_trc(fcport->bfa, lattr->link_state); - bfa_trc(fcport->bfa, lattr->trunk_wwn); - bfa_trc(fcport->bfa, lattr->fctl); - bfa_trc(fcport->bfa, lattr->speed); - bfa_trc(fcport->bfa, lattr->deskew); - } - - switch (link_bm) { - case 3: - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_TRUNK_SCN, 0, "Trunk up(0,1)"); - break; - case 2: - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_TRUNK_SCN, 0, "Trunk up(-,1)"); - break; - case 1: - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_TRUNK_SCN, 0, "Trunk up(0,-)"); - break; - default: - bfa_plog_str(fcport->bfa->plog, BFA_PL_MID_HAL, - BFA_PL_EID_TRUNK_SCN, 0, "Trunk down"); - } - - /* - * Notify upper layers if trunk state changed. - */ - if ((state_prev != trunk->attr.state) || - (scn->trunk_state == BFA_TRUNK_OFFLINE)) { - bfa_fcport_scn(fcport, (scn->trunk_state == BFA_TRUNK_ONLINE) ? - BFA_PORT_LINKUP : BFA_PORT_LINKDOWN, BFA_TRUE); - } -} - -static void -bfa_trunk_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - int i = 0; - - /* - * In trunked mode, notify upper layers that link is down - */ - if (fcport->cfg.trunked) { - if (fcport->trunk.attr.state == BFA_TRUNK_ONLINE) - bfa_fcport_scn(fcport, BFA_PORT_LINKDOWN, BFA_TRUE); - - fcport->trunk.attr.state = BFA_TRUNK_OFFLINE; - fcport->trunk.attr.speed = BFA_PORT_SPEED_UNKNOWN; - for (i = 0; i < BFA_TRUNK_MAX_PORTS; i++) { - fcport->trunk.attr.link_attr[i].trunk_wwn = 0; - fcport->trunk.attr.link_attr[i].fctl = - BFA_TRUNK_LINK_FCTL_NORMAL; - fcport->trunk.attr.link_attr[i].link_state = - BFA_TRUNK_LINK_STATE_DN_LINKDN; - fcport->trunk.attr.link_attr[i].speed = - BFA_PORT_SPEED_UNKNOWN; - fcport->trunk.attr.link_attr[i].deskew = 0; - } - } -} - -/* - * Called to initialize port attributes - */ -void -bfa_fcport_init(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - /* - * Initialize port attributes from IOC hardware data. - */ - bfa_fcport_set_wwns(fcport); - if (fcport->cfg.maxfrsize == 0) - fcport->cfg.maxfrsize = bfa_ioc_maxfrsize(&bfa->ioc); - fcport->cfg.rx_bbcredit = bfa_ioc_rx_bbcredit(&bfa->ioc); - fcport->speed_sup = bfa_ioc_speed_sup(&bfa->ioc); - - if (bfa_fcport_is_pbcdisabled(bfa)) - bfa->modules.port.pbc_disabled = BFA_TRUE; - - WARN_ON(!fcport->cfg.maxfrsize); - WARN_ON(!fcport->cfg.rx_bbcredit); - WARN_ON(!fcport->speed_sup); -} - -/* - * Firmware message handler. - */ -void -bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - union bfi_fcport_i2h_msg_u i2hmsg; - - i2hmsg.msg = msg; - fcport->event_arg.i2hmsg = i2hmsg; - - bfa_trc(bfa, msg->mhdr.msg_id); - bfa_trc(bfa, bfa_sm_to_state(hal_port_sm_table, fcport->sm)); - - switch (msg->mhdr.msg_id) { - case BFI_FCPORT_I2H_ENABLE_RSP: - if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) { - - if (fcport->use_flash_cfg) { - fcport->cfg = i2hmsg.penable_rsp->port_cfg; - fcport->cfg.maxfrsize = - cpu_to_be16(fcport->cfg.maxfrsize); - fcport->cfg.path_tov = - cpu_to_be16(fcport->cfg.path_tov); - fcport->cfg.q_depth = - cpu_to_be16(fcport->cfg.q_depth); - - if (fcport->cfg.trunked) - fcport->trunk.attr.state = - BFA_TRUNK_OFFLINE; - else - fcport->trunk.attr.state = - BFA_TRUNK_DISABLED; - fcport->use_flash_cfg = BFA_FALSE; - } - - if (fcport->cfg.qos_enabled) - fcport->qos_attr.state = BFA_QOS_OFFLINE; - else - fcport->qos_attr.state = BFA_QOS_DISABLED; - - bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP); - } - break; - - case BFI_FCPORT_I2H_DISABLE_RSP: - if (fcport->msgtag == i2hmsg.penable_rsp->msgtag) - bfa_sm_send_event(fcport, BFA_FCPORT_SM_FWRSP); - break; - - case BFI_FCPORT_I2H_EVENT: - if (i2hmsg.event->link_state.linkstate == BFA_PORT_LINKUP) - bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKUP); - else - bfa_sm_send_event(fcport, BFA_FCPORT_SM_LINKDOWN); - break; - - case BFI_FCPORT_I2H_TRUNK_SCN: - bfa_trunk_scn(fcport, i2hmsg.trunk_scn); - break; - - case BFI_FCPORT_I2H_STATS_GET_RSP: - /* - * check for timer pop before processing the rsp - */ - if (list_empty(&fcport->stats_pending_q) || - (fcport->stats_status == BFA_STATUS_ETIMER)) - break; - - bfa_timer_stop(&fcport->timer); - fcport->stats_status = i2hmsg.pstatsget_rsp->status; - __bfa_cb_fcport_stats_get(fcport, BFA_TRUE); - break; - - case BFI_FCPORT_I2H_STATS_CLEAR_RSP: - /* - * check for timer pop before processing the rsp - */ - if (list_empty(&fcport->statsclr_pending_q) || - (fcport->stats_status == BFA_STATUS_ETIMER)) - break; - - bfa_timer_stop(&fcport->timer); - fcport->stats_status = BFA_STATUS_OK; - __bfa_cb_fcport_stats_clr(fcport, BFA_TRUE); - break; - - case BFI_FCPORT_I2H_ENABLE_AEN: - bfa_sm_send_event(fcport, BFA_FCPORT_SM_ENABLE); - break; - - case BFI_FCPORT_I2H_DISABLE_AEN: - bfa_sm_send_event(fcport, BFA_FCPORT_SM_DISABLE); - break; - - default: - WARN_ON(1); - break; - } -} - -/* - * Registered callback for port events. - */ -void -bfa_fcport_event_register(struct bfa_s *bfa, - void (*cbfn) (void *cbarg, - enum bfa_port_linkstate event), - void *cbarg) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - fcport->event_cbfn = cbfn; - fcport->event_cbarg = cbarg; -} - -bfa_status_t -bfa_fcport_enable(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - if (bfa_fcport_is_pbcdisabled(bfa)) - return BFA_STATUS_PBC; - - if (bfa_ioc_is_disabled(&bfa->ioc)) - return BFA_STATUS_IOC_DISABLED; - - if (fcport->diag_busy) - return BFA_STATUS_DIAG_BUSY; - - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_ENABLE); - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_fcport_disable(struct bfa_s *bfa) -{ - if (bfa_fcport_is_pbcdisabled(bfa)) - return BFA_STATUS_PBC; - - if (bfa_ioc_is_disabled(&bfa->ioc)) - return BFA_STATUS_IOC_DISABLED; - - bfa_sm_send_event(BFA_FCPORT_MOD(bfa), BFA_FCPORT_SM_DISABLE); - return BFA_STATUS_OK; -} - -/* If PBC is disabled on port, return error */ -bfa_status_t -bfa_fcport_is_pbcdisabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - struct bfa_iocfc_s *iocfc = &bfa->iocfc; - struct bfi_iocfc_cfgrsp_s *cfgrsp = iocfc->cfgrsp; - - if (cfgrsp->pbc_cfg.port_enabled == BFI_PBC_PORT_DISABLED) { - bfa_trc(bfa, fcport->pwwn); - return BFA_STATUS_PBC; - } - return BFA_STATUS_OK; -} - -/* - * Configure port speed. - */ -bfa_status_t -bfa_fcport_cfg_speed(struct bfa_s *bfa, enum bfa_port_speed speed) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, speed); - - if (fcport->cfg.trunked == BFA_TRUE) - return BFA_STATUS_TRUNK_ENABLED; - if ((speed != BFA_PORT_SPEED_AUTO) && (speed > fcport->speed_sup)) { - bfa_trc(bfa, fcport->speed_sup); - return BFA_STATUS_UNSUPP_SPEED; - } - - /* Port speed entered needs to be checked */ - if (bfa_ioc_get_type(&fcport->bfa->ioc) == BFA_IOC_TYPE_FC) { - /* For CT2, 1G is not supported */ - if ((speed == BFA_PORT_SPEED_1GBPS) && - (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id))) - return BFA_STATUS_UNSUPP_SPEED; - - /* Already checked for Auto Speed and Max Speed supp */ - if (!(speed == BFA_PORT_SPEED_1GBPS || - speed == BFA_PORT_SPEED_2GBPS || - speed == BFA_PORT_SPEED_4GBPS || - speed == BFA_PORT_SPEED_8GBPS || - speed == BFA_PORT_SPEED_16GBPS || - speed == BFA_PORT_SPEED_AUTO)) - return BFA_STATUS_UNSUPP_SPEED; - } else { - if (speed != BFA_PORT_SPEED_10GBPS) - return BFA_STATUS_UNSUPP_SPEED; - } - - fcport->cfg.speed = speed; - - return BFA_STATUS_OK; -} - -/* - * Get current speed. - */ -enum bfa_port_speed -bfa_fcport_get_speed(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->speed; -} - -/* - * Configure port topology. - */ -bfa_status_t -bfa_fcport_cfg_topology(struct bfa_s *bfa, enum bfa_port_topology topology) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, topology); - bfa_trc(bfa, fcport->cfg.topology); - - switch (topology) { - case BFA_PORT_TOPOLOGY_P2P: - case BFA_PORT_TOPOLOGY_LOOP: - case BFA_PORT_TOPOLOGY_AUTO: - break; - - default: - return BFA_STATUS_EINVAL; - } - - fcport->cfg.topology = topology; - return BFA_STATUS_OK; -} - -/* - * Get current topology. - */ -enum bfa_port_topology -bfa_fcport_get_topology(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->topology; -} - -bfa_status_t -bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, alpa); - bfa_trc(bfa, fcport->cfg.cfg_hardalpa); - bfa_trc(bfa, fcport->cfg.hardalpa); - - fcport->cfg.cfg_hardalpa = BFA_TRUE; - fcport->cfg.hardalpa = alpa; - - return BFA_STATUS_OK; -} - -bfa_status_t -bfa_fcport_clr_hardalpa(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, fcport->cfg.cfg_hardalpa); - bfa_trc(bfa, fcport->cfg.hardalpa); - - fcport->cfg.cfg_hardalpa = BFA_FALSE; - return BFA_STATUS_OK; -} - -bfa_boolean_t -bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - *alpa = fcport->cfg.hardalpa; - return fcport->cfg.cfg_hardalpa; -} - -u8 -bfa_fcport_get_myalpa(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->myalpa; -} - -bfa_status_t -bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxfrsize) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, maxfrsize); - bfa_trc(bfa, fcport->cfg.maxfrsize); - - /* with in range */ - if ((maxfrsize > FC_MAX_PDUSZ) || (maxfrsize < FC_MIN_PDUSZ)) - return BFA_STATUS_INVLD_DFSZ; - - /* power of 2, if not the max frame size of 2112 */ - if ((maxfrsize != FC_MAX_PDUSZ) && (maxfrsize & (maxfrsize - 1))) - return BFA_STATUS_INVLD_DFSZ; - - fcport->cfg.maxfrsize = maxfrsize; - return BFA_STATUS_OK; -} - -u16 -bfa_fcport_get_maxfrsize(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.maxfrsize; -} - -u8 -bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.rx_bbcredit; -} - -void -bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit, u8 bb_scn) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - fcport->cfg.tx_bbcredit = (u8)tx_bbcredit; - fcport->cfg.bb_scn = bb_scn; - if (bb_scn) - fcport->bbsc_op_state = BFA_TRUE; -} - -/* - * Get port attributes. - */ - -wwn_t -bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - if (node) - return fcport->nwwn; - else - return fcport->pwwn; -} - -void -bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - memset(attr, 0, sizeof(struct bfa_port_attr_s)); - - attr->nwwn = fcport->nwwn; - attr->pwwn = fcport->pwwn; - - attr->factorypwwn = bfa->ioc.attr->mfg_pwwn; - attr->factorynwwn = bfa->ioc.attr->mfg_nwwn; - - memcpy(&attr->pport_cfg, &fcport->cfg, - sizeof(struct bfa_port_cfg_s)); - /* speed attributes */ - attr->pport_cfg.speed = fcport->cfg.speed; - attr->speed_supported = fcport->speed_sup; - attr->speed = fcport->speed; - attr->cos_supported = FC_CLASS_3; - - /* topology attributes */ - attr->pport_cfg.topology = fcport->cfg.topology; - attr->topology = fcport->topology; - attr->pport_cfg.trunked = fcport->cfg.trunked; - - /* beacon attributes */ - attr->beacon = fcport->beacon; - attr->link_e2e_beacon = fcport->link_e2e_beacon; - - attr->pport_cfg.path_tov = bfa_fcpim_path_tov_get(bfa); - attr->pport_cfg.q_depth = bfa_fcpim_qdepth_get(bfa); - attr->port_state = bfa_sm_to_state(hal_port_sm_table, fcport->sm); - attr->bbsc_op_status = fcport->bbsc_op_state; - - /* PBC Disabled State */ - if (bfa_fcport_is_pbcdisabled(bfa)) - attr->port_state = BFA_PORT_ST_PREBOOT_DISABLED; - else { - if (bfa_ioc_is_disabled(&fcport->bfa->ioc)) - attr->port_state = BFA_PORT_ST_IOCDIS; - else if (bfa_ioc_fw_mismatch(&fcport->bfa->ioc)) - attr->port_state = BFA_PORT_ST_FWMISMATCH; - } - - /* FCoE vlan */ - attr->fcoe_vlan = fcport->fcoe_vlan; -} - -#define BFA_FCPORT_STATS_TOV 1000 - -/* - * Fetch port statistics (FCQoS or FCoE). - */ -bfa_status_t -bfa_fcport_get_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - if (bfa_ioc_is_disabled(&bfa->ioc)) - return BFA_STATUS_IOC_DISABLED; - - if (!list_empty(&fcport->statsclr_pending_q)) - return BFA_STATUS_DEVBUSY; - - if (list_empty(&fcport->stats_pending_q)) { - list_add_tail(&cb->hcb_qe.qe, &fcport->stats_pending_q); - bfa_fcport_send_stats_get(fcport); - bfa_timer_start(bfa, &fcport->timer, - bfa_fcport_stats_get_timeout, - fcport, BFA_FCPORT_STATS_TOV); - } else - list_add_tail(&cb->hcb_qe.qe, &fcport->stats_pending_q); - - return BFA_STATUS_OK; -} - -/* - * Reset port statistics (FCQoS or FCoE). - */ -bfa_status_t -bfa_fcport_clear_stats(struct bfa_s *bfa, struct bfa_cb_pending_q_s *cb) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - if (!list_empty(&fcport->stats_pending_q)) - return BFA_STATUS_DEVBUSY; - - if (list_empty(&fcport->statsclr_pending_q)) { - list_add_tail(&cb->hcb_qe.qe, &fcport->statsclr_pending_q); - bfa_fcport_send_stats_clear(fcport); - bfa_timer_start(bfa, &fcport->timer, - bfa_fcport_stats_clr_timeout, - fcport, BFA_FCPORT_STATS_TOV); - } else - list_add_tail(&cb->hcb_qe.qe, &fcport->statsclr_pending_q); - - return BFA_STATUS_OK; -} - -/* - * Fetch port attributes. - */ -bfa_boolean_t -bfa_fcport_is_disabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return bfa_sm_to_state(hal_port_sm_table, fcport->sm) == - BFA_PORT_ST_DISABLED; - -} - -bfa_boolean_t -bfa_fcport_is_ratelim(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.ratelimit ? BFA_TRUE : BFA_FALSE; - -} - -/* - * Enable/Disable FAA feature in port config - */ -void -bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, state); - fcport->cfg.faa_state = state; -} - -/* - * Get default minimum ratelim speed - */ -enum bfa_port_speed -bfa_fcport_get_ratelim_speed(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, fcport->cfg.trl_def_speed); - return fcport->cfg.trl_def_speed; - -} - -void -bfa_fcport_beacon(void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon) -{ - struct bfa_s *bfa = dev; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - bfa_trc(bfa, beacon); - bfa_trc(bfa, link_e2e_beacon); - bfa_trc(bfa, fcport->beacon); - bfa_trc(bfa, fcport->link_e2e_beacon); - - fcport->beacon = beacon; - fcport->link_e2e_beacon = link_e2e_beacon; -} - -bfa_boolean_t -bfa_fcport_is_linkup(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return (!fcport->cfg.trunked && - bfa_sm_cmp_state(fcport, bfa_fcport_sm_linkup)) || - (fcport->cfg.trunked && - fcport->trunk.attr.state == BFA_TRUNK_ONLINE); -} - -bfa_boolean_t -bfa_fcport_is_qos_enabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.qos_enabled; -} - -bfa_boolean_t -bfa_fcport_is_trunk_enabled(struct bfa_s *bfa) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(bfa); - - return fcport->cfg.trunked; -} - -/* - * Rport State machine functions - */ -/* - * Beginning state, only online event expected. - */ -static void -bfa_rport_sm_uninit(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_CREATE: - bfa_stats(rp, sm_un_cr); - bfa_sm_set_state(rp, bfa_rport_sm_created); - break; - - default: - bfa_stats(rp, sm_un_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -static void -bfa_rport_sm_created(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_ONLINE: - bfa_stats(rp, sm_cr_on); - if (bfa_rport_send_fwcreate(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_cr_del); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_cr_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - default: - bfa_stats(rp, sm_cr_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * Waiting for rport create response from firmware. - */ -static void -bfa_rport_sm_fwcreate(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_fwc_rsp); - bfa_sm_set_state(rp, bfa_rport_sm_online); - bfa_rport_online_cb(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_fwc_del); - bfa_sm_set_state(rp, bfa_rport_sm_delete_pending); - break; - - case BFA_RPORT_SM_OFFLINE: - bfa_stats(rp, sm_fwc_off); - bfa_sm_set_state(rp, bfa_rport_sm_offline_pending); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_fwc_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - default: - bfa_stats(rp, sm_fwc_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * Request queue is full, awaiting queue resume to send create request. - */ -static void -bfa_rport_sm_fwcreate_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_QRESUME: - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); - bfa_rport_send_fwcreate(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_fwc_del); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_reqq_wcancel(&rp->reqq_wait); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_OFFLINE: - bfa_stats(rp, sm_fwc_off); - bfa_sm_set_state(rp, bfa_rport_sm_offline); - bfa_reqq_wcancel(&rp->reqq_wait); - bfa_rport_offline_cb(rp); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_fwc_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - bfa_reqq_wcancel(&rp->reqq_wait); - break; - - default: - bfa_stats(rp, sm_fwc_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * Online state - normal parking state. - */ -static void -bfa_rport_sm_online(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - struct bfi_rport_qos_scn_s *qos_scn; - - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_OFFLINE: - bfa_stats(rp, sm_on_off); - if (bfa_rport_send_fwdelete(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_on_del); - if (bfa_rport_send_fwdelete(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_deleting); - else - bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_on_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - case BFA_RPORT_SM_SET_SPEED: - bfa_rport_send_fwspeed(rp); - break; - - case BFA_RPORT_SM_QOS_SCN: - qos_scn = (struct bfi_rport_qos_scn_s *) rp->event_arg.fw_msg; - rp->qos_attr = qos_scn->new_qos_attr; - bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_flow_id); - bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_flow_id); - bfa_trc(rp->bfa, qos_scn->old_qos_attr.qos_priority); - bfa_trc(rp->bfa, qos_scn->new_qos_attr.qos_priority); - - qos_scn->old_qos_attr.qos_flow_id = - be32_to_cpu(qos_scn->old_qos_attr.qos_flow_id); - qos_scn->new_qos_attr.qos_flow_id = - be32_to_cpu(qos_scn->new_qos_attr.qos_flow_id); - - if (qos_scn->old_qos_attr.qos_flow_id != - qos_scn->new_qos_attr.qos_flow_id) - bfa_cb_rport_qos_scn_flowid(rp->rport_drv, - qos_scn->old_qos_attr, - qos_scn->new_qos_attr); - if (qos_scn->old_qos_attr.qos_priority != - qos_scn->new_qos_attr.qos_priority) - bfa_cb_rport_qos_scn_prio(rp->rport_drv, - qos_scn->old_qos_attr, - qos_scn->new_qos_attr); - break; - - default: - bfa_stats(rp, sm_on_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * Firmware rport is being deleted - awaiting f/w response. - */ -static void -bfa_rport_sm_fwdelete(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_fwd_rsp); - bfa_sm_set_state(rp, bfa_rport_sm_offline); - bfa_rport_offline_cb(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_fwd_del); - bfa_sm_set_state(rp, bfa_rport_sm_deleting); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_fwd_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - bfa_rport_offline_cb(rp); - break; - - default: - bfa_stats(rp, sm_fwd_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -static void -bfa_rport_sm_fwdelete_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_QRESUME: - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); - bfa_rport_send_fwdelete(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_fwd_del); - bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_fwd_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - bfa_reqq_wcancel(&rp->reqq_wait); - bfa_rport_offline_cb(rp); - break; - - default: - bfa_stats(rp, sm_fwd_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * Offline state. - */ -static void -bfa_rport_sm_offline(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_off_del); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_ONLINE: - bfa_stats(rp, sm_off_on); - if (bfa_rport_send_fwcreate(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_off_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - default: - bfa_stats(rp, sm_off_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * Rport is deleted, waiting for firmware response to delete. - */ -static void -bfa_rport_sm_deleting(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_del_fwrsp); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_del_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - default: - bfa_sm_fault(rp->bfa, event); - } -} - -static void -bfa_rport_sm_deleting_qfull(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_QRESUME: - bfa_stats(rp, sm_del_fwrsp); - bfa_sm_set_state(rp, bfa_rport_sm_deleting); - bfa_rport_send_fwdelete(rp); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_del_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_reqq_wcancel(&rp->reqq_wait); - bfa_rport_free(rp); - break; - - default: - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * Waiting for rport create response from firmware. A delete is pending. - */ -static void -bfa_rport_sm_delete_pending(struct bfa_rport_s *rp, - enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_delp_fwrsp); - if (bfa_rport_send_fwdelete(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_deleting); - else - bfa_sm_set_state(rp, bfa_rport_sm_deleting_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_delp_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - default: - bfa_stats(rp, sm_delp_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * Waiting for rport create response from firmware. Rport offline is pending. - */ -static void -bfa_rport_sm_offline_pending(struct bfa_rport_s *rp, - enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_FWRSP: - bfa_stats(rp, sm_offp_fwrsp); - if (bfa_rport_send_fwdelete(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwdelete_qfull); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_offp_del); - bfa_sm_set_state(rp, bfa_rport_sm_delete_pending); - break; - - case BFA_RPORT_SM_HWFAIL: - bfa_stats(rp, sm_offp_hwf); - bfa_sm_set_state(rp, bfa_rport_sm_iocdisable); - break; - - default: - bfa_stats(rp, sm_offp_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - -/* - * IOC h/w failed. - */ -static void -bfa_rport_sm_iocdisable(struct bfa_rport_s *rp, enum bfa_rport_event event) -{ - bfa_trc(rp->bfa, rp->rport_tag); - bfa_trc(rp->bfa, event); - - switch (event) { - case BFA_RPORT_SM_OFFLINE: - bfa_stats(rp, sm_iocd_off); - bfa_rport_offline_cb(rp); - break; - - case BFA_RPORT_SM_DELETE: - bfa_stats(rp, sm_iocd_del); - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - bfa_rport_free(rp); - break; - - case BFA_RPORT_SM_ONLINE: - bfa_stats(rp, sm_iocd_on); - if (bfa_rport_send_fwcreate(rp)) - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate); - else - bfa_sm_set_state(rp, bfa_rport_sm_fwcreate_qfull); - break; - - case BFA_RPORT_SM_HWFAIL: - break; - - default: - bfa_stats(rp, sm_iocd_unexp); - bfa_sm_fault(rp->bfa, event); - } -} - - - -/* - * bfa_rport_private BFA rport private functions - */ - -static void -__bfa_cb_rport_online(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_rport_s *rp = cbarg; - - if (complete) - bfa_cb_rport_online(rp->rport_drv); -} - -static void -__bfa_cb_rport_offline(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_rport_s *rp = cbarg; - - if (complete) - bfa_cb_rport_offline(rp->rport_drv); -} - -static void -bfa_rport_qresume(void *cbarg) -{ - struct bfa_rport_s *rp = cbarg; - - bfa_sm_send_event(rp, BFA_RPORT_SM_QRESUME); -} - -static void -bfa_rport_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_mem_kva_s *rport_kva = BFA_MEM_RPORT_KVA(bfa); - - if (cfg->fwcfg.num_rports < BFA_RPORT_MIN) - cfg->fwcfg.num_rports = BFA_RPORT_MIN; - - /* kva memory */ - bfa_mem_kva_setup(minfo, rport_kva, - cfg->fwcfg.num_rports * sizeof(struct bfa_rport_s)); -} - -static void -bfa_rport_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); - struct bfa_rport_s *rp; - u16 i; - - INIT_LIST_HEAD(&mod->rp_free_q); - INIT_LIST_HEAD(&mod->rp_active_q); - INIT_LIST_HEAD(&mod->rp_unused_q); - - rp = (struct bfa_rport_s *) bfa_mem_kva_curp(mod); - mod->rps_list = rp; - mod->num_rports = cfg->fwcfg.num_rports; - - WARN_ON(!mod->num_rports || - (mod->num_rports & (mod->num_rports - 1))); - - for (i = 0; i < mod->num_rports; i++, rp++) { - memset(rp, 0, sizeof(struct bfa_rport_s)); - rp->bfa = bfa; - rp->rport_tag = i; - bfa_sm_set_state(rp, bfa_rport_sm_uninit); - - /* - * - is unused - */ - if (i) - list_add_tail(&rp->qe, &mod->rp_free_q); - - bfa_reqq_winit(&rp->reqq_wait, bfa_rport_qresume, rp); - } - - /* - * consume memory - */ - bfa_mem_kva_curp(mod) = (u8 *) rp; -} - -static void -bfa_rport_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_rport_start(struct bfa_s *bfa) -{ -} - -static void -bfa_rport_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_rport_iocdisable(struct bfa_s *bfa) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); - struct bfa_rport_s *rport; - struct list_head *qe, *qen; - - /* Enqueue unused rport resources to free_q */ - list_splice_tail_init(&mod->rp_unused_q, &mod->rp_free_q); - - list_for_each_safe(qe, qen, &mod->rp_active_q) { - rport = (struct bfa_rport_s *) qe; - bfa_sm_send_event(rport, BFA_RPORT_SM_HWFAIL); - } -} - -static struct bfa_rport_s * -bfa_rport_alloc(struct bfa_rport_mod_s *mod) -{ - struct bfa_rport_s *rport; - - bfa_q_deq(&mod->rp_free_q, &rport); - if (rport) - list_add_tail(&rport->qe, &mod->rp_active_q); - - return rport; -} - -static void -bfa_rport_free(struct bfa_rport_s *rport) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(rport->bfa); - - WARN_ON(!bfa_q_is_on_q(&mod->rp_active_q, rport)); - list_del(&rport->qe); - list_add_tail(&rport->qe, &mod->rp_free_q); -} - -static bfa_boolean_t -bfa_rport_send_fwcreate(struct bfa_rport_s *rp) -{ - struct bfi_rport_create_req_s *m; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); - if (!m) { - bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_CREATE_REQ, - bfa_fn_lpu(rp->bfa)); - m->bfa_handle = rp->rport_tag; - m->max_frmsz = cpu_to_be16(rp->rport_info.max_frmsz); - m->pid = rp->rport_info.pid; - m->lp_fwtag = bfa_lps_get_fwtag(rp->bfa, (u8)rp->rport_info.lp_tag); - m->local_pid = rp->rport_info.local_pid; - m->fc_class = rp->rport_info.fc_class; - m->vf_en = rp->rport_info.vf_en; - m->vf_id = rp->rport_info.vf_id; - m->cisc = rp->rport_info.cisc; - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); - return BFA_TRUE; -} - -static bfa_boolean_t -bfa_rport_send_fwdelete(struct bfa_rport_s *rp) -{ - struct bfi_rport_delete_req_s *m; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); - if (!m) { - bfa_reqq_wait(rp->bfa, BFA_REQQ_RPORT, &rp->reqq_wait); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_DELETE_REQ, - bfa_fn_lpu(rp->bfa)); - m->fw_handle = rp->fw_handle; - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); - return BFA_TRUE; -} - -static bfa_boolean_t -bfa_rport_send_fwspeed(struct bfa_rport_s *rp) -{ - struct bfa_rport_speed_req_s *m; - - /* - * check for room in queue to send request now - */ - m = bfa_reqq_next(rp->bfa, BFA_REQQ_RPORT); - if (!m) { - bfa_trc(rp->bfa, rp->rport_info.speed); - return BFA_FALSE; - } - - bfi_h2i_set(m->mh, BFI_MC_RPORT, BFI_RPORT_H2I_SET_SPEED_REQ, - bfa_fn_lpu(rp->bfa)); - m->fw_handle = rp->fw_handle; - m->speed = (u8)rp->rport_info.speed; - - /* - * queue I/O message to firmware - */ - bfa_reqq_produce(rp->bfa, BFA_REQQ_RPORT, m->mh); - return BFA_TRUE; -} - - - -/* - * bfa_rport_public - */ - -/* - * Rport interrupt processing. - */ -void -bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *m) -{ - union bfi_rport_i2h_msg_u msg; - struct bfa_rport_s *rp; - - bfa_trc(bfa, m->mhdr.msg_id); - - msg.msg = m; - - switch (m->mhdr.msg_id) { - case BFI_RPORT_I2H_CREATE_RSP: - rp = BFA_RPORT_FROM_TAG(bfa, msg.create_rsp->bfa_handle); - rp->fw_handle = msg.create_rsp->fw_handle; - rp->qos_attr = msg.create_rsp->qos_attr; - bfa_rport_set_lunmask(bfa, rp); - WARN_ON(msg.create_rsp->status != BFA_STATUS_OK); - bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP); - break; - - case BFI_RPORT_I2H_DELETE_RSP: - rp = BFA_RPORT_FROM_TAG(bfa, msg.delete_rsp->bfa_handle); - WARN_ON(msg.delete_rsp->status != BFA_STATUS_OK); - bfa_rport_unset_lunmask(bfa, rp); - bfa_sm_send_event(rp, BFA_RPORT_SM_FWRSP); - break; - - case BFI_RPORT_I2H_QOS_SCN: - rp = BFA_RPORT_FROM_TAG(bfa, msg.qos_scn_evt->bfa_handle); - rp->event_arg.fw_msg = msg.qos_scn_evt; - bfa_sm_send_event(rp, BFA_RPORT_SM_QOS_SCN); - break; - - default: - bfa_trc(bfa, m->mhdr.msg_id); - WARN_ON(1); - } -} - -void -bfa_rport_res_recfg(struct bfa_s *bfa, u16 num_rport_fw) -{ - struct bfa_rport_mod_s *mod = BFA_RPORT_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_rports - num_rport_fw); i++) { - bfa_q_deq_tail(&mod->rp_free_q, &qe); - list_add_tail(qe, &mod->rp_unused_q); - } -} - -/* - * bfa_rport_api - */ - -struct bfa_rport_s * -bfa_rport_create(struct bfa_s *bfa, void *rport_drv) -{ - struct bfa_rport_s *rp; - - rp = bfa_rport_alloc(BFA_RPORT_MOD(bfa)); - - if (rp == NULL) - return NULL; - - rp->bfa = bfa; - rp->rport_drv = rport_drv; - memset(&rp->stats, 0, sizeof(rp->stats)); - - WARN_ON(!bfa_sm_cmp_state(rp, bfa_rport_sm_uninit)); - bfa_sm_send_event(rp, BFA_RPORT_SM_CREATE); - - return rp; -} - -void -bfa_rport_online(struct bfa_rport_s *rport, struct bfa_rport_info_s *rport_info) -{ - WARN_ON(rport_info->max_frmsz == 0); - - /* - * Some JBODs are seen to be not setting PDU size correctly in PLOGI - * responses. Default to minimum size. - */ - if (rport_info->max_frmsz == 0) { - bfa_trc(rport->bfa, rport->rport_tag); - rport_info->max_frmsz = FC_MIN_PDUSZ; - } - - rport->rport_info = *rport_info; - bfa_sm_send_event(rport, BFA_RPORT_SM_ONLINE); -} - -void -bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed) -{ - WARN_ON(speed == 0); - WARN_ON(speed == BFA_PORT_SPEED_AUTO); - - rport->rport_info.speed = speed; - bfa_sm_send_event(rport, BFA_RPORT_SM_SET_SPEED); -} - -/* Set Rport LUN Mask */ -void -bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp) -{ - struct bfa_lps_mod_s *lps_mod = BFA_LPS_MOD(bfa); - wwn_t lp_wwn, rp_wwn; - u8 lp_tag = (u8)rp->rport_info.lp_tag; - - rp_wwn = ((struct bfa_fcs_rport_s *)rp->rport_drv)->pwwn; - lp_wwn = (BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag))->pwwn; - - BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag)->lun_mask = - rp->lun_mask = BFA_TRUE; - bfa_fcpim_lunmask_rp_update(bfa, lp_wwn, rp_wwn, rp->rport_tag, lp_tag); -} - -/* Unset Rport LUN mask */ -void -bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp) -{ - struct bfa_lps_mod_s *lps_mod = BFA_LPS_MOD(bfa); - wwn_t lp_wwn, rp_wwn; - - rp_wwn = ((struct bfa_fcs_rport_s *)rp->rport_drv)->pwwn; - lp_wwn = (BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag))->pwwn; - - BFA_LPS_FROM_TAG(lps_mod, rp->rport_info.lp_tag)->lun_mask = - rp->lun_mask = BFA_FALSE; - bfa_fcpim_lunmask_rp_update(bfa, lp_wwn, rp_wwn, - BFA_RPORT_TAG_INVALID, BFA_LP_TAG_INVALID); -} - -/* - * SGPG related functions - */ - -/* - * Compute and return memory needed by FCP(im) module. - */ -static void -bfa_sgpg_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_sgpg_mod_s *sgpg_mod = BFA_SGPG_MOD(bfa); - struct bfa_mem_kva_s *sgpg_kva = BFA_MEM_SGPG_KVA(bfa); - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_sgpg, num_sgpg; - u32 sgpg_sz = sizeof(struct bfi_sgpg_s); - - if (cfg->drvcfg.num_sgpgs < BFA_SGPG_MIN) - cfg->drvcfg.num_sgpgs = BFA_SGPG_MIN; - else if (cfg->drvcfg.num_sgpgs > BFA_SGPG_MAX) - cfg->drvcfg.num_sgpgs = BFA_SGPG_MAX; - - num_sgpg = cfg->drvcfg.num_sgpgs; - - nsegs = BFI_MEM_DMA_NSEGS(num_sgpg, sgpg_sz); - per_seg_sgpg = BFI_MEM_NREQS_SEG(sgpg_sz); - - bfa_mem_dma_seg_iter(sgpg_mod, seg_ptr, nsegs, idx) { - if (num_sgpg >= per_seg_sgpg) { - num_sgpg -= per_seg_sgpg; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_sgpg * sgpg_sz); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_sgpg * sgpg_sz); - } - - /* kva memory */ - bfa_mem_kva_setup(minfo, sgpg_kva, - cfg->drvcfg.num_sgpgs * sizeof(struct bfa_sgpg_s)); -} - -static void -bfa_sgpg_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - struct bfa_sgpg_s *hsgpg; - struct bfi_sgpg_s *sgpg; - u64 align_len; - struct bfa_mem_dma_s *seg_ptr; - u32 sgpg_sz = sizeof(struct bfi_sgpg_s); - u16 i, idx, nsegs, per_seg_sgpg, num_sgpg; - - union { - u64 pa; - union bfi_addr_u addr; - } sgpg_pa, sgpg_pa_tmp; - - INIT_LIST_HEAD(&mod->sgpg_q); - INIT_LIST_HEAD(&mod->sgpg_wait_q); - - bfa_trc(bfa, cfg->drvcfg.num_sgpgs); - - mod->free_sgpgs = mod->num_sgpgs = cfg->drvcfg.num_sgpgs; - - num_sgpg = cfg->drvcfg.num_sgpgs; - nsegs = BFI_MEM_DMA_NSEGS(num_sgpg, sgpg_sz); - - /* dma/kva mem claim */ - hsgpg = (struct bfa_sgpg_s *) bfa_mem_kva_curp(mod); - - bfa_mem_dma_seg_iter(mod, seg_ptr, nsegs, idx) { - - if (!bfa_mem_dma_virt(seg_ptr)) - break; - - align_len = BFA_SGPG_ROUNDUP(bfa_mem_dma_phys(seg_ptr)) - - bfa_mem_dma_phys(seg_ptr); - - sgpg = (struct bfi_sgpg_s *) - (((u8 *) bfa_mem_dma_virt(seg_ptr)) + align_len); - sgpg_pa.pa = bfa_mem_dma_phys(seg_ptr) + align_len; - WARN_ON(sgpg_pa.pa & (sgpg_sz - 1)); - - per_seg_sgpg = (seg_ptr->mem_len - (u32)align_len) / sgpg_sz; - - for (i = 0; num_sgpg > 0 && i < per_seg_sgpg; i++, num_sgpg--) { - memset(hsgpg, 0, sizeof(*hsgpg)); - memset(sgpg, 0, sizeof(*sgpg)); - - hsgpg->sgpg = sgpg; - sgpg_pa_tmp.pa = bfa_sgaddr_le(sgpg_pa.pa); - hsgpg->sgpg_pa = sgpg_pa_tmp.addr; - list_add_tail(&hsgpg->qe, &mod->sgpg_q); - - sgpg++; - hsgpg++; - sgpg_pa.pa += sgpg_sz; - } - } - - bfa_mem_kva_curp(mod) = (u8 *) hsgpg; -} - -static void -bfa_sgpg_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_start(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_sgpg_iocdisable(struct bfa_s *bfa) -{ -} - -bfa_status_t -bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - struct bfa_sgpg_s *hsgpg; - int i; - - if (mod->free_sgpgs < nsgpgs) - return BFA_STATUS_ENOMEM; - - for (i = 0; i < nsgpgs; i++) { - bfa_q_deq(&mod->sgpg_q, &hsgpg); - WARN_ON(!hsgpg); - list_add_tail(&hsgpg->qe, sgpg_q); - } - - mod->free_sgpgs -= nsgpgs; - return BFA_STATUS_OK; -} - -void -bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpg) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - struct bfa_sgpg_wqe_s *wqe; - - mod->free_sgpgs += nsgpg; - WARN_ON(mod->free_sgpgs > mod->num_sgpgs); - - list_splice_tail_init(sgpg_q, &mod->sgpg_q); - - if (list_empty(&mod->sgpg_wait_q)) - return; - - /* - * satisfy as many waiting requests as possible - */ - do { - wqe = bfa_q_first(&mod->sgpg_wait_q); - if (mod->free_sgpgs < wqe->nsgpg) - nsgpg = mod->free_sgpgs; - else - nsgpg = wqe->nsgpg; - bfa_sgpg_malloc(bfa, &wqe->sgpg_q, nsgpg); - wqe->nsgpg -= nsgpg; - if (wqe->nsgpg == 0) { - list_del(&wqe->qe); - wqe->cbfn(wqe->cbarg); - } - } while (mod->free_sgpgs && !list_empty(&mod->sgpg_wait_q)); -} - -void -bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpg) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - - WARN_ON(nsgpg <= 0); - WARN_ON(nsgpg <= mod->free_sgpgs); - - wqe->nsgpg_total = wqe->nsgpg = nsgpg; - - /* - * allocate any left to this one first - */ - if (mod->free_sgpgs) { - /* - * no one else is waiting for SGPG - */ - WARN_ON(!list_empty(&mod->sgpg_wait_q)); - list_splice_tail_init(&mod->sgpg_q, &wqe->sgpg_q); - wqe->nsgpg -= mod->free_sgpgs; - mod->free_sgpgs = 0; - } - - list_add_tail(&wqe->qe, &mod->sgpg_wait_q); -} - -void -bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe) -{ - struct bfa_sgpg_mod_s *mod = BFA_SGPG_MOD(bfa); - - WARN_ON(!bfa_q_is_on_q(&mod->sgpg_wait_q, wqe)); - list_del(&wqe->qe); - - if (wqe->nsgpg_total != wqe->nsgpg) - bfa_sgpg_mfree(bfa, &wqe->sgpg_q, - wqe->nsgpg_total - wqe->nsgpg); -} - -void -bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, void (*cbfn) (void *cbarg), - void *cbarg) -{ - INIT_LIST_HEAD(&wqe->sgpg_q); - wqe->cbfn = cbfn; - wqe->cbarg = cbarg; -} - -/* - * UF related functions - */ -/* - ***************************************************************************** - * Internal functions - ***************************************************************************** - */ -static void -__bfa_cb_uf_recv(void *cbarg, bfa_boolean_t complete) -{ - struct bfa_uf_s *uf = cbarg; - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(uf->bfa); - - if (complete) - ufm->ufrecv(ufm->cbarg, uf); -} - -static void -claim_uf_post_msgs(struct bfa_uf_mod_s *ufm) -{ - struct bfi_uf_buf_post_s *uf_bp_msg; - u16 i; - u16 buf_len; - - ufm->uf_buf_posts = (struct bfi_uf_buf_post_s *) bfa_mem_kva_curp(ufm); - uf_bp_msg = ufm->uf_buf_posts; - - for (i = 0, uf_bp_msg = ufm->uf_buf_posts; i < ufm->num_ufs; - i++, uf_bp_msg++) { - memset(uf_bp_msg, 0, sizeof(struct bfi_uf_buf_post_s)); - - uf_bp_msg->buf_tag = i; - buf_len = sizeof(struct bfa_uf_buf_s); - uf_bp_msg->buf_len = cpu_to_be16(buf_len); - bfi_h2i_set(uf_bp_msg->mh, BFI_MC_UF, BFI_UF_H2I_BUF_POST, - bfa_fn_lpu(ufm->bfa)); - bfa_alen_set(&uf_bp_msg->alen, buf_len, ufm_pbs_pa(ufm, i)); - } - - /* - * advance pointer beyond consumed memory - */ - bfa_mem_kva_curp(ufm) = (u8 *) uf_bp_msg; -} - -static void -claim_ufs(struct bfa_uf_mod_s *ufm) -{ - u16 i; - struct bfa_uf_s *uf; - - /* - * Claim block of memory for UF list - */ - ufm->uf_list = (struct bfa_uf_s *) bfa_mem_kva_curp(ufm); - - /* - * Initialize UFs and queue it in UF free queue - */ - for (i = 0, uf = ufm->uf_list; i < ufm->num_ufs; i++, uf++) { - memset(uf, 0, sizeof(struct bfa_uf_s)); - uf->bfa = ufm->bfa; - uf->uf_tag = i; - uf->pb_len = BFA_PER_UF_DMA_SZ; - uf->buf_kva = bfa_mem_get_dmabuf_kva(ufm, i, BFA_PER_UF_DMA_SZ); - uf->buf_pa = ufm_pbs_pa(ufm, i); - list_add_tail(&uf->qe, &ufm->uf_free_q); - } - - /* - * advance memory pointer - */ - bfa_mem_kva_curp(ufm) = (u8 *) uf; -} - -static void -uf_mem_claim(struct bfa_uf_mod_s *ufm) -{ - claim_ufs(ufm); - claim_uf_post_msgs(ufm); -} - -static void -bfa_uf_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *minfo, - struct bfa_s *bfa) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - struct bfa_mem_kva_s *uf_kva = BFA_MEM_UF_KVA(bfa); - u32 num_ufs = cfg->fwcfg.num_uf_bufs; - struct bfa_mem_dma_s *seg_ptr; - u16 nsegs, idx, per_seg_uf = 0; - - nsegs = BFI_MEM_DMA_NSEGS(num_ufs, BFA_PER_UF_DMA_SZ); - per_seg_uf = BFI_MEM_NREQS_SEG(BFA_PER_UF_DMA_SZ); - - bfa_mem_dma_seg_iter(ufm, seg_ptr, nsegs, idx) { - if (num_ufs >= per_seg_uf) { - num_ufs -= per_seg_uf; - bfa_mem_dma_setup(minfo, seg_ptr, - per_seg_uf * BFA_PER_UF_DMA_SZ); - } else - bfa_mem_dma_setup(minfo, seg_ptr, - num_ufs * BFA_PER_UF_DMA_SZ); - } - - /* kva memory */ - bfa_mem_kva_setup(minfo, uf_kva, cfg->fwcfg.num_uf_bufs * - (sizeof(struct bfa_uf_s) + sizeof(struct bfi_uf_buf_post_s))); -} - -static void -bfa_uf_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - - ufm->bfa = bfa; - ufm->num_ufs = cfg->fwcfg.num_uf_bufs; - INIT_LIST_HEAD(&ufm->uf_free_q); - INIT_LIST_HEAD(&ufm->uf_posted_q); - INIT_LIST_HEAD(&ufm->uf_unused_q); - - uf_mem_claim(ufm); -} - -static void -bfa_uf_detach(struct bfa_s *bfa) -{ -} - -static struct bfa_uf_s * -bfa_uf_get(struct bfa_uf_mod_s *uf_mod) -{ - struct bfa_uf_s *uf; - - bfa_q_deq(&uf_mod->uf_free_q, &uf); - return uf; -} - -static void -bfa_uf_put(struct bfa_uf_mod_s *uf_mod, struct bfa_uf_s *uf) -{ - list_add_tail(&uf->qe, &uf_mod->uf_free_q); -} - -static bfa_status_t -bfa_uf_post(struct bfa_uf_mod_s *ufm, struct bfa_uf_s *uf) -{ - struct bfi_uf_buf_post_s *uf_post_msg; - - uf_post_msg = bfa_reqq_next(ufm->bfa, BFA_REQQ_FCXP); - if (!uf_post_msg) - return BFA_STATUS_FAILED; - - memcpy(uf_post_msg, &ufm->uf_buf_posts[uf->uf_tag], - sizeof(struct bfi_uf_buf_post_s)); - bfa_reqq_produce(ufm->bfa, BFA_REQQ_FCXP, uf_post_msg->mh); - - bfa_trc(ufm->bfa, uf->uf_tag); - - list_add_tail(&uf->qe, &ufm->uf_posted_q); - return BFA_STATUS_OK; -} - -static void -bfa_uf_post_all(struct bfa_uf_mod_s *uf_mod) -{ - struct bfa_uf_s *uf; - - while ((uf = bfa_uf_get(uf_mod)) != NULL) { - if (bfa_uf_post(uf_mod, uf) != BFA_STATUS_OK) - break; - } -} - -static void -uf_recv(struct bfa_s *bfa, struct bfi_uf_frm_rcvd_s *m) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - u16 uf_tag = m->buf_tag; - struct bfa_uf_s *uf = &ufm->uf_list[uf_tag]; - struct bfa_uf_buf_s *uf_buf; - uint8_t *buf; - struct fchs_s *fchs; - - uf_buf = (struct bfa_uf_buf_s *) - bfa_mem_get_dmabuf_kva(ufm, uf_tag, uf->pb_len); - buf = &uf_buf->d[0]; - - m->frm_len = be16_to_cpu(m->frm_len); - m->xfr_len = be16_to_cpu(m->xfr_len); - - fchs = (struct fchs_s *)uf_buf; - - list_del(&uf->qe); /* dequeue from posted queue */ - - uf->data_ptr = buf; - uf->data_len = m->xfr_len; - - WARN_ON(uf->data_len < sizeof(struct fchs_s)); - - if (uf->data_len == sizeof(struct fchs_s)) { - bfa_plog_fchdr(bfa->plog, BFA_PL_MID_HAL_UF, BFA_PL_EID_RX, - uf->data_len, (struct fchs_s *)buf); - } else { - u32 pld_w0 = *((u32 *) (buf + sizeof(struct fchs_s))); - bfa_plog_fchdr_and_pl(bfa->plog, BFA_PL_MID_HAL_UF, - BFA_PL_EID_RX, uf->data_len, - (struct fchs_s *)buf, pld_w0); - } - - if (bfa->fcs) - __bfa_cb_uf_recv(uf, BFA_TRUE); - else - bfa_cb_queue(bfa, &uf->hcb_qe, __bfa_cb_uf_recv, uf); -} - -static void -bfa_uf_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_uf_iocdisable(struct bfa_s *bfa) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - struct bfa_uf_s *uf; - struct list_head *qe, *qen; - - /* Enqueue unused uf resources to free_q */ - list_splice_tail_init(&ufm->uf_unused_q, &ufm->uf_free_q); - - list_for_each_safe(qe, qen, &ufm->uf_posted_q) { - uf = (struct bfa_uf_s *) qe; - list_del(&uf->qe); - bfa_uf_put(ufm, uf); - } -} - -static void -bfa_uf_start(struct bfa_s *bfa) -{ - bfa_uf_post_all(BFA_UF_MOD(bfa)); -} - -/* - * Register handler for all unsolicted receive frames. - * - * @param[in] bfa BFA instance - * @param[in] ufrecv receive handler function - * @param[in] cbarg receive handler arg - */ -void -bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, void *cbarg) -{ - struct bfa_uf_mod_s *ufm = BFA_UF_MOD(bfa); - - ufm->ufrecv = ufrecv; - ufm->cbarg = cbarg; -} - -/* - * Free an unsolicited frame back to BFA. - * - * @param[in] uf unsolicited frame to be freed - * - * @return None - */ -void -bfa_uf_free(struct bfa_uf_s *uf) -{ - bfa_uf_put(BFA_UF_MOD(uf->bfa), uf); - bfa_uf_post_all(BFA_UF_MOD(uf->bfa)); -} - - - -/* - * uf_pub BFA uf module public functions - */ -void -bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - bfa_trc(bfa, msg->mhdr.msg_id); - - switch (msg->mhdr.msg_id) { - case BFI_UF_I2H_FRM_RCVD: - uf_recv(bfa, (struct bfi_uf_frm_rcvd_s *) msg); - break; - - default: - bfa_trc(bfa, msg->mhdr.msg_id); - WARN_ON(1); - } -} - -void -bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw) -{ - struct bfa_uf_mod_s *mod = BFA_UF_MOD(bfa); - struct list_head *qe; - int i; - - for (i = 0; i < (mod->num_ufs - num_uf_fw); i++) { - bfa_q_deq_tail(&mod->uf_free_q, &qe); - list_add_tail(qe, &mod->uf_unused_q); - } -} - -/* - * BFA fcdiag module - */ -#define BFA_DIAG_QTEST_TOV 1000 /* msec */ - -/* - * Set port status to busy - */ -static void -bfa_fcdiag_set_busy_status(struct bfa_fcdiag_s *fcdiag) -{ - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(fcdiag->bfa); - - if (fcdiag->lb.lock) - fcport->diag_busy = BFA_TRUE; - else - fcport->diag_busy = BFA_FALSE; -} - -static void -bfa_fcdiag_meminfo(struct bfa_iocfc_cfg_s *cfg, struct bfa_meminfo_s *meminfo, - struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_attach(struct bfa_s *bfa, void *bfad, struct bfa_iocfc_cfg_s *cfg, - struct bfa_pcidev_s *pcidev) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - fcdiag->bfa = bfa; - fcdiag->trcmod = bfa->trcmod; - /* The common DIAG attach bfa_diag_attach() will do all memory claim */ -} - -static void -bfa_fcdiag_iocdisable(struct bfa_s *bfa) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - bfa_trc(fcdiag, fcdiag->lb.lock); - if (fcdiag->lb.lock) { - fcdiag->lb.status = BFA_STATUS_IOC_FAILURE; - fcdiag->lb.cbfn(fcdiag->lb.cbarg, fcdiag->lb.status); - fcdiag->lb.lock = 0; - bfa_fcdiag_set_busy_status(fcdiag); - } -} - -static void -bfa_fcdiag_detach(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_start(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_stop(struct bfa_s *bfa) -{ -} - -static void -bfa_fcdiag_queuetest_timeout(void *cbarg) -{ - struct bfa_fcdiag_s *fcdiag = cbarg; - struct bfa_diag_qtest_result_s *res = fcdiag->qtest.result; - - bfa_trc(fcdiag, fcdiag->qtest.all); - bfa_trc(fcdiag, fcdiag->qtest.count); - - fcdiag->qtest.timer_active = 0; - - res->status = BFA_STATUS_ETIMER; - res->count = QTEST_CNT_DEFAULT - fcdiag->qtest.count; - if (fcdiag->qtest.all) - res->queue = fcdiag->qtest.all; - - bfa_trc(fcdiag, BFA_STATUS_ETIMER); - fcdiag->qtest.status = BFA_STATUS_ETIMER; - fcdiag->qtest.cbfn(fcdiag->qtest.cbarg, fcdiag->qtest.status); - fcdiag->qtest.lock = 0; -} - -static bfa_status_t -bfa_fcdiag_queuetest_send(struct bfa_fcdiag_s *fcdiag) -{ - u32 i; - struct bfi_diag_qtest_req_s *req; - - req = bfa_reqq_next(fcdiag->bfa, fcdiag->qtest.queue); - if (!req) - return BFA_STATUS_DEVBUSY; - - /* build host command */ - bfi_h2i_set(req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_QTEST, - bfa_fn_lpu(fcdiag->bfa)); - - for (i = 0; i < BFI_LMSG_PL_WSZ; i++) - req->data[i] = QTEST_PAT_DEFAULT; - - bfa_trc(fcdiag, fcdiag->qtest.queue); - /* ring door bell */ - bfa_reqq_produce(fcdiag->bfa, fcdiag->qtest.queue, req->mh); - return BFA_STATUS_OK; -} - -static void -bfa_fcdiag_queuetest_comp(struct bfa_fcdiag_s *fcdiag, - bfi_diag_qtest_rsp_t *rsp) -{ - struct bfa_diag_qtest_result_s *res = fcdiag->qtest.result; - bfa_status_t status = BFA_STATUS_OK; - int i; - - /* Check timer, should still be active */ - if (!fcdiag->qtest.timer_active) { - bfa_trc(fcdiag, fcdiag->qtest.timer_active); - return; - } - - /* update count */ - fcdiag->qtest.count--; - - /* Check result */ - for (i = 0; i < BFI_LMSG_PL_WSZ; i++) { - if (rsp->data[i] != ~(QTEST_PAT_DEFAULT)) { - res->status = BFA_STATUS_DATACORRUPTED; - break; - } - } - - if (res->status == BFA_STATUS_OK) { - if (fcdiag->qtest.count > 0) { - status = bfa_fcdiag_queuetest_send(fcdiag); - if (status == BFA_STATUS_OK) - return; - else - res->status = status; - } else if (fcdiag->qtest.all > 0 && - fcdiag->qtest.queue < (BFI_IOC_MAX_CQS - 1)) { - fcdiag->qtest.count = QTEST_CNT_DEFAULT; - fcdiag->qtest.queue++; - status = bfa_fcdiag_queuetest_send(fcdiag); - if (status == BFA_STATUS_OK) - return; - else - res->status = status; - } - } - - /* Stop timer when we comp all queue */ - if (fcdiag->qtest.timer_active) { - bfa_timer_stop(&fcdiag->qtest.timer); - fcdiag->qtest.timer_active = 0; - } - res->queue = fcdiag->qtest.queue; - res->count = QTEST_CNT_DEFAULT - fcdiag->qtest.count; - bfa_trc(fcdiag, res->count); - bfa_trc(fcdiag, res->status); - fcdiag->qtest.status = res->status; - fcdiag->qtest.cbfn(fcdiag->qtest.cbarg, fcdiag->qtest.status); - fcdiag->qtest.lock = 0; -} - -static void -bfa_fcdiag_loopback_comp(struct bfa_fcdiag_s *fcdiag, - struct bfi_diag_lb_rsp_s *rsp) -{ - struct bfa_diag_loopback_result_s *res = fcdiag->lb.result; - - res->numtxmfrm = be32_to_cpu(rsp->res.numtxmfrm); - res->numosffrm = be32_to_cpu(rsp->res.numosffrm); - res->numrcvfrm = be32_to_cpu(rsp->res.numrcvfrm); - res->badfrminf = be32_to_cpu(rsp->res.badfrminf); - res->badfrmnum = be32_to_cpu(rsp->res.badfrmnum); - res->status = rsp->res.status; - fcdiag->lb.status = rsp->res.status; - bfa_trc(fcdiag, fcdiag->lb.status); - fcdiag->lb.cbfn(fcdiag->lb.cbarg, fcdiag->lb.status); - fcdiag->lb.lock = 0; - bfa_fcdiag_set_busy_status(fcdiag); -} - -static bfa_status_t -bfa_fcdiag_loopback_send(struct bfa_fcdiag_s *fcdiag, - struct bfa_diag_loopback_s *loopback) -{ - struct bfi_diag_lb_req_s *lb_req; - - lb_req = bfa_reqq_next(fcdiag->bfa, BFA_REQQ_DIAG); - if (!lb_req) - return BFA_STATUS_DEVBUSY; - - /* build host command */ - bfi_h2i_set(lb_req->mh, BFI_MC_DIAG, BFI_DIAG_H2I_LOOPBACK, - bfa_fn_lpu(fcdiag->bfa)); - - lb_req->lb_mode = loopback->lb_mode; - lb_req->speed = loopback->speed; - lb_req->loopcnt = loopback->loopcnt; - lb_req->pattern = loopback->pattern; - - /* ring door bell */ - bfa_reqq_produce(fcdiag->bfa, BFA_REQQ_DIAG, lb_req->mh); - - bfa_trc(fcdiag, loopback->lb_mode); - bfa_trc(fcdiag, loopback->speed); - bfa_trc(fcdiag, loopback->loopcnt); - bfa_trc(fcdiag, loopback->pattern); - return BFA_STATUS_OK; -} - -/* - * cpe/rme intr handler - */ -void -bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - - switch (msg->mhdr.msg_id) { - case BFI_DIAG_I2H_LOOPBACK: - bfa_fcdiag_loopback_comp(fcdiag, - (struct bfi_diag_lb_rsp_s *) msg); - break; - case BFI_DIAG_I2H_QTEST: - bfa_fcdiag_queuetest_comp(fcdiag, (bfi_diag_qtest_rsp_t *)msg); - break; - default: - bfa_trc(fcdiag, msg->mhdr.msg_id); - WARN_ON(1); - } -} - -/* - * Loopback test - * - * @param[in] *bfa - bfa data struct - * @param[in] opmode - port operation mode - * @param[in] speed - port speed - * @param[in] lpcnt - loop count - * @param[in] pat - pattern to build packet - * @param[in] *result - pt to bfa_diag_loopback_result_t data struct - * @param[in] cbfn - callback function - * @param[in] cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_loopback(struct bfa_s *bfa, enum bfa_port_opmode opmode, - enum bfa_port_speed speed, u32 lpcnt, u32 pat, - struct bfa_diag_loopback_result_s *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - struct bfa_diag_loopback_s loopback; - struct bfa_port_attr_s attr; - bfa_status_t status; - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - - if (!bfa_iocfc_is_operational(bfa)) - return BFA_STATUS_IOC_NON_OP; - - /* if port is PBC disabled, return error */ - if (bfa_fcport_is_pbcdisabled(bfa)) { - bfa_trc(fcdiag, BFA_STATUS_PBC); - return BFA_STATUS_PBC; - } - - if (bfa_fcport_is_disabled(bfa) == BFA_FALSE) { - bfa_trc(fcdiag, opmode); - return BFA_STATUS_PORT_NOT_DISABLED; - } - - /* - * Check if input speed is supported by the port mode - */ - if (bfa_ioc_get_type(&bfa->ioc) == BFA_IOC_TYPE_FC) { - if (!(speed == BFA_PORT_SPEED_1GBPS || - speed == BFA_PORT_SPEED_2GBPS || - speed == BFA_PORT_SPEED_4GBPS || - speed == BFA_PORT_SPEED_8GBPS || - speed == BFA_PORT_SPEED_16GBPS || - speed == BFA_PORT_SPEED_AUTO)) { - bfa_trc(fcdiag, speed); - return BFA_STATUS_UNSUPP_SPEED; - } - bfa_fcport_get_attr(bfa, &attr); - bfa_trc(fcdiag, attr.speed_supported); - if (speed > attr.speed_supported) - return BFA_STATUS_UNSUPP_SPEED; - } else { - if (speed != BFA_PORT_SPEED_10GBPS) { - bfa_trc(fcdiag, speed); - return BFA_STATUS_UNSUPP_SPEED; - } - } - - /* For Mezz card, port speed entered needs to be checked */ - if (bfa_mfg_is_mezz(bfa->ioc.attr->card_type)) { - if (bfa_ioc_get_type(&bfa->ioc) == BFA_IOC_TYPE_FC) { - if ((speed == BFA_PORT_SPEED_1GBPS) && - (bfa_asic_id_ct2(bfa->ioc.pcidev.device_id))) - return BFA_STATUS_UNSUPP_SPEED; - if (!(speed == BFA_PORT_SPEED_1GBPS || - speed == BFA_PORT_SPEED_2GBPS || - speed == BFA_PORT_SPEED_4GBPS || - speed == BFA_PORT_SPEED_8GBPS || - speed == BFA_PORT_SPEED_16GBPS || - speed == BFA_PORT_SPEED_AUTO)) - return BFA_STATUS_UNSUPP_SPEED; - } else { - if (speed != BFA_PORT_SPEED_10GBPS) - return BFA_STATUS_UNSUPP_SPEED; - } - } - - /* check to see if there is another destructive diag cmd running */ - if (fcdiag->lb.lock) { - bfa_trc(fcdiag, fcdiag->lb.lock); - return BFA_STATUS_DEVBUSY; - } - - fcdiag->lb.lock = 1; - loopback.lb_mode = opmode; - loopback.speed = speed; - loopback.loopcnt = lpcnt; - loopback.pattern = pat; - fcdiag->lb.result = result; - fcdiag->lb.cbfn = cbfn; - fcdiag->lb.cbarg = cbarg; - memset(result, 0, sizeof(struct bfa_diag_loopback_result_s)); - bfa_fcdiag_set_busy_status(fcdiag); - - /* Send msg to fw */ - status = bfa_fcdiag_loopback_send(fcdiag, &loopback); - return status; -} - -/* - * DIAG queue test command - * - * @param[in] *bfa - bfa data struct - * @param[in] force - 1: don't do ioc op checking - * @param[in] queue - queue no. to test - * @param[in] *result - pt to bfa_diag_qtest_result_t data struct - * @param[in] cbfn - callback function - * @param[in] *cbarg - callback functioin arg - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 force, u32 queue, - struct bfa_diag_qtest_result_s *result, bfa_cb_diag_t cbfn, - void *cbarg) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - bfa_status_t status; - bfa_trc(fcdiag, force); - bfa_trc(fcdiag, queue); - - if (!force && !bfa_iocfc_is_operational(bfa)) - return BFA_STATUS_IOC_NON_OP; - - /* check to see if there is another destructive diag cmd running */ - if (fcdiag->qtest.lock) { - bfa_trc(fcdiag, fcdiag->qtest.lock); - return BFA_STATUS_DEVBUSY; - } - - /* Initialization */ - fcdiag->qtest.lock = 1; - fcdiag->qtest.cbfn = cbfn; - fcdiag->qtest.cbarg = cbarg; - fcdiag->qtest.result = result; - fcdiag->qtest.count = QTEST_CNT_DEFAULT; - - /* Init test results */ - fcdiag->qtest.result->status = BFA_STATUS_OK; - fcdiag->qtest.result->count = 0; - - /* send */ - if (queue < BFI_IOC_MAX_CQS) { - fcdiag->qtest.result->queue = (u8)queue; - fcdiag->qtest.queue = (u8)queue; - fcdiag->qtest.all = 0; - } else { - fcdiag->qtest.result->queue = 0; - fcdiag->qtest.queue = 0; - fcdiag->qtest.all = 1; - } - status = bfa_fcdiag_queuetest_send(fcdiag); - - /* Start a timer */ - if (status == BFA_STATUS_OK) { - bfa_timer_start(bfa, &fcdiag->qtest.timer, - bfa_fcdiag_queuetest_timeout, fcdiag, - BFA_DIAG_QTEST_TOV); - fcdiag->qtest.timer_active = 1; - } - return status; -} - -/* - * DIAG PLB is running - * - * @param[in] *bfa - bfa data struct - * - * @param[out] - */ -bfa_status_t -bfa_fcdiag_lb_is_running(struct bfa_s *bfa) -{ - struct bfa_fcdiag_s *fcdiag = BFA_FCDIAG_MOD(bfa); - return fcdiag->lb.lock ? BFA_STATUS_DIAG_BUSY : BFA_STATUS_OK; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.h deleted file mode 100644 index f3006756..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfa_svc.h +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFA_SVC_H__ -#define __BFA_SVC_H__ - -#include "bfa_cs.h" -#include "bfi_ms.h" - - -/* - * Scatter-gather DMA related defines - */ -#define BFA_SGPG_MIN (16) -#define BFA_SGPG_MAX (8192) - -/* - * Alignment macro for SG page allocation - */ -#define BFA_SGPG_ROUNDUP(_l) (((_l) + (sizeof(struct bfi_sgpg_s) - 1)) \ - & ~(sizeof(struct bfi_sgpg_s) - 1)) - -struct bfa_sgpg_wqe_s { - struct list_head qe; /* queue sg page element */ - int nsgpg; /* pages to be allocated */ - int nsgpg_total; /* total pages required */ - void (*cbfn) (void *cbarg); /* callback function */ - void *cbarg; /* callback arg */ - struct list_head sgpg_q; /* queue of alloced sgpgs */ -}; - -struct bfa_sgpg_s { - struct list_head qe; /* queue sg page element */ - struct bfi_sgpg_s *sgpg; /* va of SG page */ - union bfi_addr_u sgpg_pa; /* pa of SG page */ -}; - -/* - * Given number of SG elements, BFA_SGPG_NPAGE() returns the number of - * SG pages required. - */ -#define BFA_SGPG_NPAGE(_nsges) (((_nsges) / BFI_SGPG_DATA_SGES) + 1) - -/* Max SGPG dma segs required */ -#define BFA_SGPG_DMA_SEGS \ - BFI_MEM_DMA_NSEGS(BFA_SGPG_MAX, (uint32_t)sizeof(struct bfi_sgpg_s)) - -struct bfa_sgpg_mod_s { - struct bfa_s *bfa; - int num_sgpgs; /* number of SG pages */ - int free_sgpgs; /* number of free SG pages */ - struct list_head sgpg_q; /* queue of free SG pages */ - struct list_head sgpg_wait_q; /* wait queue for SG pages */ - struct bfa_mem_dma_s dma_seg[BFA_SGPG_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; -}; -#define BFA_SGPG_MOD(__bfa) (&(__bfa)->modules.sgpg_mod) -#define BFA_MEM_SGPG_KVA(__bfa) (&(BFA_SGPG_MOD(__bfa)->kva_seg)) - -bfa_status_t bfa_sgpg_malloc(struct bfa_s *bfa, struct list_head *sgpg_q, - int nsgpgs); -void bfa_sgpg_mfree(struct bfa_s *bfa, struct list_head *sgpg_q, int nsgpgs); -void bfa_sgpg_winit(struct bfa_sgpg_wqe_s *wqe, - void (*cbfn) (void *cbarg), void *cbarg); -void bfa_sgpg_wait(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe, int nsgpgs); -void bfa_sgpg_wcancel(struct bfa_s *bfa, struct bfa_sgpg_wqe_s *wqe); - - -/* - * FCXP related defines - */ -#define BFA_FCXP_MIN (1) -#define BFA_FCXP_MAX (256) -#define BFA_FCXP_MAX_IBUF_SZ (2 * 1024 + 256) -#define BFA_FCXP_MAX_LBUF_SZ (4 * 1024 + 256) - -/* Max FCXP dma segs required */ -#define BFA_FCXP_DMA_SEGS \ - BFI_MEM_DMA_NSEGS(BFA_FCXP_MAX, \ - (u32)BFA_FCXP_MAX_IBUF_SZ + BFA_FCXP_MAX_LBUF_SZ) - -struct bfa_fcxp_mod_s { - struct bfa_s *bfa; /* backpointer to BFA */ - struct bfa_fcxp_s *fcxp_list; /* array of FCXPs */ - u16 num_fcxps; /* max num FCXP requests */ - struct list_head fcxp_free_q; /* free FCXPs */ - struct list_head fcxp_active_q; /* active FCXPs */ - struct list_head wait_q; /* wait queue for free fcxp */ - struct list_head fcxp_unused_q; /* unused fcxps */ - u32 req_pld_sz; - u32 rsp_pld_sz; - struct bfa_mem_dma_s dma_seg[BFA_FCXP_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; -}; - -#define BFA_FCXP_MOD(__bfa) (&(__bfa)->modules.fcxp_mod) -#define BFA_FCXP_FROM_TAG(__mod, __tag) (&(__mod)->fcxp_list[__tag]) -#define BFA_MEM_FCXP_KVA(__bfa) (&(BFA_FCXP_MOD(__bfa)->kva_seg)) - -typedef void (*fcxp_send_cb_t) (struct bfa_s *ioc, struct bfa_fcxp_s *fcxp, - void *cb_arg, bfa_status_t req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs); - -typedef u64 (*bfa_fcxp_get_sgaddr_t) (void *bfad_fcxp, int sgeid); -typedef u32 (*bfa_fcxp_get_sglen_t) (void *bfad_fcxp, int sgeid); -typedef void (*bfa_cb_fcxp_send_t) (void *bfad_fcxp, struct bfa_fcxp_s *fcxp, - void *cbarg, enum bfa_status req_status, - u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs); -typedef void (*bfa_fcxp_alloc_cbfn_t) (void *cbarg, struct bfa_fcxp_s *fcxp); - - - -/* - * Information needed for a FCXP request - */ -struct bfa_fcxp_req_info_s { - struct bfa_rport_s *bfa_rport; - /* Pointer to the bfa rport that was - * returned from bfa_rport_create(). - * This could be left NULL for WKA or - * for FCXP interactions before the - * rport nexus is established - */ - struct fchs_s fchs; /* request FC header structure */ - u8 cts; /* continuous sequence */ - u8 class; /* FC class for the request/response */ - u16 max_frmsz; /* max send frame size */ - u16 vf_id; /* vsan tag if applicable */ - u8 lp_tag; /* lport tag */ - u32 req_tot_len; /* request payload total length */ -}; - -struct bfa_fcxp_rsp_info_s { - struct fchs_s rsp_fchs; - /* Response frame's FC header will - * be sent back in this field */ - u8 rsp_timeout; - /* timeout in seconds, 0-no response */ - u8 rsvd2[3]; - u32 rsp_maxlen; /* max response length expected */ -}; - -struct bfa_fcxp_s { - struct list_head qe; /* fcxp queue element */ - bfa_sm_t sm; /* state machine */ - void *caller; /* driver or fcs */ - struct bfa_fcxp_mod_s *fcxp_mod; - /* back pointer to fcxp mod */ - u16 fcxp_tag; /* internal tag */ - struct bfa_fcxp_req_info_s req_info; - /* request info */ - struct bfa_fcxp_rsp_info_s rsp_info; - /* response info */ - u8 use_ireqbuf; /* use internal req buf */ - u8 use_irspbuf; /* use internal rsp buf */ - u32 nreq_sgles; /* num request SGLEs */ - u32 nrsp_sgles; /* num response SGLEs */ - struct list_head req_sgpg_q; /* SG pages for request buf */ - struct list_head req_sgpg_wqe; /* wait queue for req SG page */ - struct list_head rsp_sgpg_q; /* SG pages for response buf */ - struct list_head rsp_sgpg_wqe; /* wait queue for rsp SG page */ - - bfa_fcxp_get_sgaddr_t req_sga_cbfn; - /* SG elem addr user function */ - bfa_fcxp_get_sglen_t req_sglen_cbfn; - /* SG elem len user function */ - bfa_fcxp_get_sgaddr_t rsp_sga_cbfn; - /* SG elem addr user function */ - bfa_fcxp_get_sglen_t rsp_sglen_cbfn; - /* SG elem len user function */ - bfa_cb_fcxp_send_t send_cbfn; /* send completion callback */ - void *send_cbarg; /* callback arg */ - struct bfa_sge_s req_sge[BFA_FCXP_MAX_SGES]; - /* req SG elems */ - struct bfa_sge_s rsp_sge[BFA_FCXP_MAX_SGES]; - /* rsp SG elems */ - u8 rsp_status; /* comp: rsp status */ - u32 rsp_len; /* comp: actual response len */ - u32 residue_len; /* comp: residual rsp length */ - struct fchs_s rsp_fchs; /* comp: response fchs */ - struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */ - struct bfa_reqq_wait_s reqq_wqe; - bfa_boolean_t reqq_waiting; -}; - -struct bfa_fcxp_wqe_s { - struct list_head qe; - bfa_fcxp_alloc_cbfn_t alloc_cbfn; - void *alloc_cbarg; - void *caller; - struct bfa_s *bfa; - int nreq_sgles; - int nrsp_sgles; - bfa_fcxp_get_sgaddr_t req_sga_cbfn; - bfa_fcxp_get_sglen_t req_sglen_cbfn; - bfa_fcxp_get_sgaddr_t rsp_sga_cbfn; - bfa_fcxp_get_sglen_t rsp_sglen_cbfn; -}; - -#define BFA_FCXP_REQ_PLD(_fcxp) (bfa_fcxp_get_reqbuf(_fcxp)) -#define BFA_FCXP_RSP_FCHS(_fcxp) (&((_fcxp)->rsp_info.fchs)) -#define BFA_FCXP_RSP_PLD(_fcxp) (bfa_fcxp_get_rspbuf(_fcxp)) - -#define BFA_FCXP_REQ_PLD_PA(_fcxp) \ - bfa_mem_get_dmabuf_pa((_fcxp)->fcxp_mod, (_fcxp)->fcxp_tag, \ - (_fcxp)->fcxp_mod->req_pld_sz + (_fcxp)->fcxp_mod->rsp_pld_sz) - -/* fcxp_buf = req_buf + rsp_buf :- add req_buf_sz to get to rsp_buf */ -#define BFA_FCXP_RSP_PLD_PA(_fcxp) \ - (bfa_mem_get_dmabuf_pa((_fcxp)->fcxp_mod, (_fcxp)->fcxp_tag, \ - (_fcxp)->fcxp_mod->req_pld_sz + (_fcxp)->fcxp_mod->rsp_pld_sz) + \ - (_fcxp)->fcxp_mod->req_pld_sz) - -void bfa_fcxp_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); - - -/* - * RPORT related defines - */ -enum bfa_rport_event { - BFA_RPORT_SM_CREATE = 1, /* rport create event */ - BFA_RPORT_SM_DELETE = 2, /* deleting an existing rport */ - BFA_RPORT_SM_ONLINE = 3, /* rport is online */ - BFA_RPORT_SM_OFFLINE = 4, /* rport is offline */ - BFA_RPORT_SM_FWRSP = 5, /* firmware response */ - BFA_RPORT_SM_HWFAIL = 6, /* IOC h/w failure */ - BFA_RPORT_SM_QOS_SCN = 7, /* QoS SCN from firmware */ - BFA_RPORT_SM_SET_SPEED = 8, /* Set Rport Speed */ - BFA_RPORT_SM_QRESUME = 9, /* space in requeue queue */ -}; - -#define BFA_RPORT_MIN 4 - -struct bfa_rport_mod_s { - struct bfa_rport_s *rps_list; /* list of rports */ - struct list_head rp_free_q; /* free bfa_rports */ - struct list_head rp_active_q; /* free bfa_rports */ - struct list_head rp_unused_q; /* unused bfa rports */ - u16 num_rports; /* number of rports */ - struct bfa_mem_kva_s kva_seg; -}; - -#define BFA_RPORT_MOD(__bfa) (&(__bfa)->modules.rport_mod) -#define BFA_MEM_RPORT_KVA(__bfa) (&(BFA_RPORT_MOD(__bfa)->kva_seg)) - -/* - * Convert rport tag to RPORT - */ -#define BFA_RPORT_FROM_TAG(__bfa, _tag) \ - (BFA_RPORT_MOD(__bfa)->rps_list + \ - ((_tag) & (BFA_RPORT_MOD(__bfa)->num_rports - 1))) - -/* - * protected functions - */ -void bfa_rport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_rport_res_recfg(struct bfa_s *bfa, u16 num_rport_fw); - -/* - * BFA rport information. - */ -struct bfa_rport_info_s { - u16 max_frmsz; /* max rcv pdu size */ - u32 pid:24, /* remote port ID */ - lp_tag:8; /* tag */ - u32 local_pid:24, /* local port ID */ - cisc:8; /* CIRO supported */ - u8 fc_class; /* supported FC classes. enum fc_cos */ - u8 vf_en; /* virtual fabric enable */ - u16 vf_id; /* virtual fabric ID */ - enum bfa_port_speed speed; /* Rport's current speed */ -}; - -/* - * BFA rport data structure - */ -struct bfa_rport_s { - struct list_head qe; /* queue element */ - bfa_sm_t sm; /* state machine */ - struct bfa_s *bfa; /* backpointer to BFA */ - void *rport_drv; /* fcs/driver rport object */ - u16 fw_handle; /* firmware rport handle */ - u16 rport_tag; /* BFA rport tag */ - u8 lun_mask; /* LUN mask flag */ - struct bfa_rport_info_s rport_info; /* rport info from fcs/driver */ - struct bfa_reqq_wait_s reqq_wait; /* to wait for room in reqq */ - struct bfa_cb_qe_s hcb_qe; /* BFA callback qelem */ - struct bfa_rport_hal_stats_s stats; /* BFA rport statistics */ - struct bfa_rport_qos_attr_s qos_attr; - union a { - bfa_status_t status; /* f/w status */ - void *fw_msg; /* QoS scn event */ - } event_arg; -}; -#define BFA_RPORT_FC_COS(_rport) ((_rport)->rport_info.fc_class) - - -/* - * UF - unsolicited receive related defines - */ - -#define BFA_UF_MIN (4) -#define BFA_UF_MAX (256) - -struct bfa_uf_s { - struct list_head qe; /* queue element */ - struct bfa_s *bfa; /* bfa instance */ - u16 uf_tag; /* identifying tag fw msgs */ - u16 vf_id; - u16 src_rport_handle; - u16 rsvd; - u8 *data_ptr; - u16 data_len; /* actual receive length */ - u16 pb_len; /* posted buffer length */ - void *buf_kva; /* buffer virtual address */ - u64 buf_pa; /* buffer physical address */ - struct bfa_cb_qe_s hcb_qe; /* comp: BFA comp qelem */ - struct bfa_sge_s sges[BFI_SGE_INLINE_MAX]; -}; - -/* - * Callback prototype for unsolicited frame receive handler. - * - * @param[in] cbarg callback arg for receive handler - * @param[in] uf unsolicited frame descriptor - * - * @return None - */ -typedef void (*bfa_cb_uf_recv_t) (void *cbarg, struct bfa_uf_s *uf); - -#define BFA_UF_BUFSZ (2 * 1024 + 256) - -struct bfa_uf_buf_s { - u8 d[BFA_UF_BUFSZ]; -}; - -#define BFA_PER_UF_DMA_SZ \ - (u32)BFA_ROUNDUP(sizeof(struct bfa_uf_buf_s), BFA_DMA_ALIGN_SZ) - -/* Max UF dma segs required */ -#define BFA_UF_DMA_SEGS BFI_MEM_DMA_NSEGS(BFA_UF_MAX, BFA_PER_UF_DMA_SZ) - -struct bfa_uf_mod_s { - struct bfa_s *bfa; /* back pointer to BFA */ - struct bfa_uf_s *uf_list; /* array of UFs */ - u16 num_ufs; /* num unsolicited rx frames */ - struct list_head uf_free_q; /* free UFs */ - struct list_head uf_posted_q; /* UFs posted to IOC */ - struct list_head uf_unused_q; /* unused UF's */ - struct bfi_uf_buf_post_s *uf_buf_posts; - /* pre-built UF post msgs */ - bfa_cb_uf_recv_t ufrecv; /* uf recv handler function */ - void *cbarg; /* uf receive handler arg */ - struct bfa_mem_dma_s dma_seg[BFA_UF_DMA_SEGS]; - struct bfa_mem_kva_s kva_seg; -}; - -#define BFA_UF_MOD(__bfa) (&(__bfa)->modules.uf_mod) -#define BFA_MEM_UF_KVA(__bfa) (&(BFA_UF_MOD(__bfa)->kva_seg)) - -#define ufm_pbs_pa(_ufmod, _uftag) \ - bfa_mem_get_dmabuf_pa(_ufmod, _uftag, BFA_PER_UF_DMA_SZ) - -void bfa_uf_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); -void bfa_uf_res_recfg(struct bfa_s *bfa, u16 num_uf_fw); - -/* - * LPS - bfa lport login/logout service interface - */ -struct bfa_lps_s { - struct list_head qe; /* queue element */ - struct bfa_s *bfa; /* parent bfa instance */ - bfa_sm_t sm; /* finite state machine */ - u8 bfa_tag; /* lport tag */ - u8 fw_tag; /* lport fw tag */ - u8 reqq; /* lport request queue */ - u8 alpa; /* ALPA for loop topologies */ - u32 lp_pid; /* lport port ID */ - bfa_boolean_t fdisc; /* snd FDISC instead of FLOGI */ - bfa_boolean_t auth_en; /* enable authentication */ - bfa_boolean_t auth_req; /* authentication required */ - bfa_boolean_t npiv_en; /* NPIV is allowed by peer */ - bfa_boolean_t fport; /* attached peer is F_PORT */ - bfa_boolean_t brcd_switch; /* attached peer is brcd sw */ - bfa_status_t status; /* login status */ - u16 pdusz; /* max receive PDU size */ - u16 pr_bbcred; /* BB_CREDIT from peer */ - u8 pr_bbscn; /* BB_SCN from peer */ - u8 bb_scn; /* local BB_SCN */ - u8 lsrjt_rsn; /* LSRJT reason */ - u8 lsrjt_expl; /* LSRJT explanation */ - u8 lun_mask; /* LUN mask flag */ - wwn_t pwwn; /* port wwn of lport */ - wwn_t nwwn; /* node wwn of lport */ - wwn_t pr_pwwn; /* port wwn of lport peer */ - wwn_t pr_nwwn; /* node wwn of lport peer */ - mac_t lp_mac; /* fpma/spma MAC for lport */ - mac_t fcf_mac; /* FCF MAC of lport */ - struct bfa_reqq_wait_s wqe; /* request wait queue element */ - void *uarg; /* user callback arg */ - struct bfa_cb_qe_s hcb_qe; /* comp: callback qelem */ - struct bfi_lps_login_rsp_s *loginrsp; - bfa_eproto_status_t ext_status; -}; - -struct bfa_lps_mod_s { - struct list_head lps_free_q; - struct list_head lps_active_q; - struct list_head lps_login_q; - struct bfa_lps_s *lps_arr; - int num_lps; - struct bfa_mem_kva_s kva_seg; -}; - -#define BFA_LPS_MOD(__bfa) (&(__bfa)->modules.lps_mod) -#define BFA_LPS_FROM_TAG(__mod, __tag) (&(__mod)->lps_arr[__tag]) -#define BFA_MEM_LPS_KVA(__bfa) (&(BFA_LPS_MOD(__bfa)->kva_seg)) - -/* - * external functions - */ -void bfa_lps_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); - - -/* - * FCPORT related defines - */ - -#define BFA_FCPORT(_bfa) (&((_bfa)->modules.port)) - -/* - * Link notification data structure - */ -struct bfa_fcport_ln_s { - struct bfa_fcport_s *fcport; - bfa_sm_t sm; - struct bfa_cb_qe_s ln_qe; /* BFA callback queue elem for ln */ - enum bfa_port_linkstate ln_event; /* ln event for callback */ -}; - -struct bfa_fcport_trunk_s { - struct bfa_trunk_attr_s attr; -}; - -/* - * BFA FC port data structure - */ -struct bfa_fcport_s { - struct bfa_s *bfa; /* parent BFA instance */ - bfa_sm_t sm; /* port state machine */ - wwn_t nwwn; /* node wwn of physical port */ - wwn_t pwwn; /* port wwn of physical oprt */ - enum bfa_port_speed speed_sup; - /* supported speeds */ - enum bfa_port_speed speed; /* current speed */ - enum bfa_port_topology topology; /* current topology */ - u8 myalpa; /* my ALPA in LOOP topology */ - u8 rsvd[3]; - struct bfa_port_cfg_s cfg; /* current port configuration */ - bfa_boolean_t use_flash_cfg; /* get port cfg from flash */ - struct bfa_qos_attr_s qos_attr; /* QoS Attributes */ - struct bfa_qos_vc_attr_s qos_vc_attr; /* VC info from ELP */ - struct bfa_reqq_wait_s reqq_wait; - /* to wait for room in reqq */ - struct bfa_reqq_wait_s svcreq_wait; - /* to wait for room in reqq */ - struct bfa_reqq_wait_s stats_reqq_wait; - /* to wait for room in reqq (stats) */ - void *event_cbarg; - void (*event_cbfn) (void *cbarg, - enum bfa_port_linkstate event); - union { - union bfi_fcport_i2h_msg_u i2hmsg; - } event_arg; - void *bfad; /* BFA driver handle */ - struct bfa_fcport_ln_s ln; /* Link Notification */ - struct bfa_cb_qe_s hcb_qe; /* BFA callback queue elem */ - struct bfa_timer_s timer; /* timer */ - u32 msgtag; /* fimrware msg tag for reply */ - u8 *stats_kva; - u64 stats_pa; - union bfa_fcport_stats_u *stats; - bfa_status_t stats_status; /* stats/statsclr status */ - struct list_head stats_pending_q; - struct list_head statsclr_pending_q; - bfa_boolean_t stats_qfull; - u32 stats_reset_time; /* stats reset time stamp */ - bfa_boolean_t diag_busy; /* diag busy status */ - bfa_boolean_t beacon; /* port beacon status */ - bfa_boolean_t link_e2e_beacon; /* link beacon status */ - bfa_boolean_t bbsc_op_state; /* Cred recov Oper State */ - struct bfa_fcport_trunk_s trunk; - u16 fcoe_vlan; - struct bfa_mem_dma_s fcport_dma; -}; - -#define BFA_FCPORT_MOD(__bfa) (&(__bfa)->modules.fcport) -#define BFA_MEM_FCPORT_DMA(__bfa) (&(BFA_FCPORT_MOD(__bfa)->fcport_dma)) - -/* - * protected functions - */ -void bfa_fcport_init(struct bfa_s *bfa); -void bfa_fcport_isr(struct bfa_s *bfa, struct bfi_msg_s *msg); - -/* - * bfa fcport API functions - */ -bfa_status_t bfa_fcport_enable(struct bfa_s *bfa); -bfa_status_t bfa_fcport_disable(struct bfa_s *bfa); -bfa_status_t bfa_fcport_cfg_speed(struct bfa_s *bfa, - enum bfa_port_speed speed); -enum bfa_port_speed bfa_fcport_get_speed(struct bfa_s *bfa); -bfa_status_t bfa_fcport_cfg_topology(struct bfa_s *bfa, - enum bfa_port_topology topo); -enum bfa_port_topology bfa_fcport_get_topology(struct bfa_s *bfa); -bfa_status_t bfa_fcport_cfg_hardalpa(struct bfa_s *bfa, u8 alpa); -bfa_boolean_t bfa_fcport_get_hardalpa(struct bfa_s *bfa, u8 *alpa); -u8 bfa_fcport_get_myalpa(struct bfa_s *bfa); -bfa_status_t bfa_fcport_clr_hardalpa(struct bfa_s *bfa); -bfa_status_t bfa_fcport_cfg_maxfrsize(struct bfa_s *bfa, u16 maxsize); -u16 bfa_fcport_get_maxfrsize(struct bfa_s *bfa); -u8 bfa_fcport_get_rx_bbcredit(struct bfa_s *bfa); -void bfa_fcport_get_attr(struct bfa_s *bfa, struct bfa_port_attr_s *attr); -wwn_t bfa_fcport_get_wwn(struct bfa_s *bfa, bfa_boolean_t node); -void bfa_fcport_event_register(struct bfa_s *bfa, - void (*event_cbfn) (void *cbarg, - enum bfa_port_linkstate event), void *event_cbarg); -bfa_boolean_t bfa_fcport_is_disabled(struct bfa_s *bfa); -enum bfa_port_speed bfa_fcport_get_ratelim_speed(struct bfa_s *bfa); - -void bfa_fcport_set_tx_bbcredit(struct bfa_s *bfa, u16 tx_bbcredit, u8 bb_scn); -bfa_boolean_t bfa_fcport_is_ratelim(struct bfa_s *bfa); -void bfa_fcport_beacon(void *dev, bfa_boolean_t beacon, - bfa_boolean_t link_e2e_beacon); -bfa_boolean_t bfa_fcport_is_linkup(struct bfa_s *bfa); -bfa_status_t bfa_fcport_get_stats(struct bfa_s *bfa, - struct bfa_cb_pending_q_s *cb); -bfa_status_t bfa_fcport_clear_stats(struct bfa_s *bfa, - struct bfa_cb_pending_q_s *cb); -bfa_boolean_t bfa_fcport_is_qos_enabled(struct bfa_s *bfa); -bfa_boolean_t bfa_fcport_is_trunk_enabled(struct bfa_s *bfa); -bfa_status_t bfa_fcport_is_pbcdisabled(struct bfa_s *bfa); -void bfa_fcport_cfg_faa(struct bfa_s *bfa, u8 state); - -/* - * bfa rport API functions - */ -struct bfa_rport_s *bfa_rport_create(struct bfa_s *bfa, void *rport_drv); -void bfa_rport_online(struct bfa_rport_s *rport, - struct bfa_rport_info_s *rport_info); -void bfa_rport_speed(struct bfa_rport_s *rport, enum bfa_port_speed speed); -void bfa_cb_rport_online(void *rport); -void bfa_cb_rport_offline(void *rport); -void bfa_cb_rport_qos_scn_flowid(void *rport, - struct bfa_rport_qos_attr_s old_qos_attr, - struct bfa_rport_qos_attr_s new_qos_attr); -void bfa_cb_rport_qos_scn_prio(void *rport, - struct bfa_rport_qos_attr_s old_qos_attr, - struct bfa_rport_qos_attr_s new_qos_attr); - -/* - * Rport LUN masking related - */ -#define BFA_RPORT_TAG_INVALID 0xffff -#define BFA_LP_TAG_INVALID 0xff -void bfa_rport_set_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp); -void bfa_rport_unset_lunmask(struct bfa_s *bfa, struct bfa_rport_s *rp); - -/* - * bfa fcxp API functions - */ -struct bfa_fcxp_s *bfa_fcxp_alloc(void *bfad_fcxp, struct bfa_s *bfa, - int nreq_sgles, int nrsp_sgles, - bfa_fcxp_get_sgaddr_t get_req_sga, - bfa_fcxp_get_sglen_t get_req_sglen, - bfa_fcxp_get_sgaddr_t get_rsp_sga, - bfa_fcxp_get_sglen_t get_rsp_sglen); -void bfa_fcxp_alloc_wait(struct bfa_s *bfa, struct bfa_fcxp_wqe_s *wqe, - bfa_fcxp_alloc_cbfn_t alloc_cbfn, - void *cbarg, void *bfad_fcxp, - int nreq_sgles, int nrsp_sgles, - bfa_fcxp_get_sgaddr_t get_req_sga, - bfa_fcxp_get_sglen_t get_req_sglen, - bfa_fcxp_get_sgaddr_t get_rsp_sga, - bfa_fcxp_get_sglen_t get_rsp_sglen); -void bfa_fcxp_walloc_cancel(struct bfa_s *bfa, - struct bfa_fcxp_wqe_s *wqe); -void bfa_fcxp_discard(struct bfa_fcxp_s *fcxp); - -void *bfa_fcxp_get_reqbuf(struct bfa_fcxp_s *fcxp); -void *bfa_fcxp_get_rspbuf(struct bfa_fcxp_s *fcxp); - -void bfa_fcxp_free(struct bfa_fcxp_s *fcxp); - -void bfa_fcxp_send(struct bfa_fcxp_s *fcxp, struct bfa_rport_s *rport, - u16 vf_id, u8 lp_tag, - bfa_boolean_t cts, enum fc_cos cos, - u32 reqlen, struct fchs_s *fchs, - bfa_cb_fcxp_send_t cbfn, - void *cbarg, - u32 rsp_maxlen, u8 rsp_timeout); -bfa_status_t bfa_fcxp_abort(struct bfa_fcxp_s *fcxp); -u32 bfa_fcxp_get_reqbufsz(struct bfa_fcxp_s *fcxp); -u32 bfa_fcxp_get_maxrsp(struct bfa_s *bfa); -void bfa_fcxp_res_recfg(struct bfa_s *bfa, u16 num_fcxp_fw); - -static inline void * -bfa_uf_get_frmbuf(struct bfa_uf_s *uf) -{ - return uf->data_ptr; -} - -static inline u16 -bfa_uf_get_frmlen(struct bfa_uf_s *uf) -{ - return uf->data_len; -} - -/* - * bfa uf API functions - */ -void bfa_uf_recv_register(struct bfa_s *bfa, bfa_cb_uf_recv_t ufrecv, - void *cbarg); -void bfa_uf_free(struct bfa_uf_s *uf); - -/* - * bfa lport service api - */ - -u32 bfa_lps_get_max_vport(struct bfa_s *bfa); -struct bfa_lps_s *bfa_lps_alloc(struct bfa_s *bfa); -void bfa_lps_delete(struct bfa_lps_s *lps); -void bfa_lps_flogi(struct bfa_lps_s *lps, void *uarg, u8 alpa, - u16 pdusz, wwn_t pwwn, wwn_t nwwn, - bfa_boolean_t auth_en, u8 bb_scn); -void bfa_lps_fdisc(struct bfa_lps_s *lps, void *uarg, u16 pdusz, - wwn_t pwwn, wwn_t nwwn); -void bfa_lps_fdisclogo(struct bfa_lps_s *lps); -void bfa_lps_set_n2n_pid(struct bfa_lps_s *lps, u32 n2n_pid); -u8 bfa_lps_get_fwtag(struct bfa_s *bfa, u8 lp_tag); -u32 bfa_lps_get_base_pid(struct bfa_s *bfa); -u8 bfa_lps_get_tag_from_pid(struct bfa_s *bfa, u32 pid); -void bfa_cb_lps_flogi_comp(void *bfad, void *uarg, bfa_status_t status); -void bfa_cb_lps_fdisc_comp(void *bfad, void *uarg, bfa_status_t status); -void bfa_cb_lps_fdisclogo_comp(void *bfad, void *uarg); -void bfa_cb_lps_cvl_event(void *bfad, void *uarg); - -/* FAA specific APIs */ -bfa_status_t bfa_faa_query(struct bfa_s *bfa, struct bfa_faa_attr_s *attr, - bfa_cb_iocfc_t cbfn, void *cbarg); - -/* - * FC DIAG data structure - */ -struct bfa_fcdiag_qtest_s { - struct bfa_diag_qtest_result_s *result; - bfa_cb_diag_t cbfn; - void *cbarg; - struct bfa_timer_s timer; - u32 status; - u32 count; - u8 lock; - u8 queue; - u8 all; - u8 timer_active; -}; - -struct bfa_fcdiag_lb_s { - bfa_cb_diag_t cbfn; - void *cbarg; - void *result; - bfa_boolean_t lock; - u32 status; -}; - -struct bfa_fcdiag_s { - struct bfa_s *bfa; /* Back pointer to BFA */ - struct bfa_trc_mod_s *trcmod; - struct bfa_fcdiag_lb_s lb; - struct bfa_fcdiag_qtest_s qtest; -}; - -#define BFA_FCDIAG_MOD(__bfa) (&(__bfa)->modules.fcdiag) - -void bfa_fcdiag_intr(struct bfa_s *bfa, struct bfi_msg_s *msg); - -bfa_status_t bfa_fcdiag_loopback(struct bfa_s *bfa, - enum bfa_port_opmode opmode, - enum bfa_port_speed speed, u32 lpcnt, u32 pat, - struct bfa_diag_loopback_result_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_fcdiag_queuetest(struct bfa_s *bfa, u32 ignore, - u32 queue, struct bfa_diag_qtest_result_s *result, - bfa_cb_diag_t cbfn, void *cbarg); -bfa_status_t bfa_fcdiag_lb_is_running(struct bfa_s *bfa); - -#endif /* __BFA_SVC_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfad.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfad.c deleted file mode 100644 index 404fd10d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfad.c +++ /dev/null @@ -1,1652 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * bfad.c Linux driver PCI interface module. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfa_fcs.h" -#include "bfa_defs.h" -#include "bfa.h" - -BFA_TRC_FILE(LDRV, BFAD); -DEFINE_MUTEX(bfad_mutex); -LIST_HEAD(bfad_list); - -static int bfad_inst; -static int num_sgpgs_parm; -int supported_fc4s; -char *host_name, *os_name, *os_patch; -int num_rports, num_ios, num_tms; -int num_fcxps, num_ufbufs; -int reqq_size, rspq_size, num_sgpgs; -int rport_del_timeout = BFA_FCS_RPORT_DEF_DEL_TIMEOUT; -int bfa_lun_queue_depth = BFAD_LUN_QUEUE_DEPTH; -int bfa_io_max_sge = BFAD_IO_MAX_SGE; -int bfa_log_level = 3; /* WARNING log level */ -int ioc_auto_recover = BFA_TRUE; -int bfa_linkup_delay = -1; -int fdmi_enable = BFA_TRUE; -int pcie_max_read_reqsz; -int bfa_debugfs_enable = 1; -int msix_disable_cb = 0, msix_disable_ct = 0; -int max_xfer_size = BFAD_MAX_SECTORS >> 1; - -/* Firmware releated */ -u32 bfi_image_cb_size, bfi_image_ct_size, bfi_image_ct2_size; -u32 *bfi_image_cb, *bfi_image_ct, *bfi_image_ct2; - -#define BFAD_FW_FILE_CB "cbfw.bin" -#define BFAD_FW_FILE_CT "ctfw.bin" -#define BFAD_FW_FILE_CT2 "ct2fw.bin" - -static u32 *bfad_load_fwimg(struct pci_dev *pdev); -static void bfad_free_fwimg(void); -static void bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, - u32 *bfi_image_size, char *fw_name); - -static const char *msix_name_ct[] = { - "ctrl", - "cpe0", "cpe1", "cpe2", "cpe3", - "rme0", "rme1", "rme2", "rme3" }; - -static const char *msix_name_cb[] = { - "cpe0", "cpe1", "cpe2", "cpe3", - "rme0", "rme1", "rme2", "rme3", - "eemc", "elpu0", "elpu1", "epss", "mlpu" }; - -MODULE_FIRMWARE(BFAD_FW_FILE_CB); -MODULE_FIRMWARE(BFAD_FW_FILE_CT); -MODULE_FIRMWARE(BFAD_FW_FILE_CT2); - -module_param(os_name, charp, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(os_name, "OS name of the hba host machine"); -module_param(os_patch, charp, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(os_patch, "OS patch level of the hba host machine"); -module_param(host_name, charp, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(host_name, "Hostname of the hba host machine"); -module_param(num_rports, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(num_rports, "Max number of rports supported per port " - "(physical/logical), default=1024"); -module_param(num_ios, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(num_ios, "Max number of ioim requests, default=2000"); -module_param(num_tms, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(num_tms, "Max number of task im requests, default=128"); -module_param(num_fcxps, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(num_fcxps, "Max number of fcxp requests, default=64"); -module_param(num_ufbufs, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(num_ufbufs, "Max number of unsolicited frame " - "buffers, default=64"); -module_param(reqq_size, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(reqq_size, "Max number of request queue elements, " - "default=256"); -module_param(rspq_size, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rspq_size, "Max number of response queue elements, " - "default=64"); -module_param(num_sgpgs, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(num_sgpgs, "Number of scatter/gather pages, default=2048"); -module_param(rport_del_timeout, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rport_del_timeout, "Rport delete timeout, default=90 secs, " - "Range[>0]"); -module_param(bfa_lun_queue_depth, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(bfa_lun_queue_depth, "Lun queue depth, default=32, Range[>0]"); -module_param(bfa_io_max_sge, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(bfa_io_max_sge, "Max io scatter/gather elements, default=255"); -module_param(bfa_log_level, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(bfa_log_level, "Driver log level, default=3, " - "Range[Critical:1|Error:2|Warning:3|Info:4]"); -module_param(ioc_auto_recover, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ioc_auto_recover, "IOC auto recovery, default=1, " - "Range[off:0|on:1]"); -module_param(bfa_linkup_delay, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(bfa_linkup_delay, "Link up delay, default=30 secs for " - "boot port. Otherwise 10 secs in RHEL4 & 0 for " - "[RHEL5, SLES10, ESX40] Range[>0]"); -module_param(msix_disable_cb, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(msix_disable_cb, "Disable Message Signaled Interrupts " - "for Brocade-415/425/815/825 cards, default=0, " - " Range[false:0|true:1]"); -module_param(msix_disable_ct, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(msix_disable_ct, "Disable Message Signaled Interrupts " - "if possible for Brocade-1010/1020/804/1007/902/1741 " - "cards, default=0, Range[false:0|true:1]"); -module_param(fdmi_enable, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(fdmi_enable, "Enables fdmi registration, default=1, " - "Range[false:0|true:1]"); -module_param(pcie_max_read_reqsz, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(pcie_max_read_reqsz, "PCIe max read request size, default=0 " - "(use system setting), Range[128|256|512|1024|2048|4096]"); -module_param(bfa_debugfs_enable, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(bfa_debugfs_enable, "Enables debugfs feature, default=1," - " Range[false:0|true:1]"); -module_param(max_xfer_size, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_xfer_size, "default=32MB," - " Range[64k|128k|256k|512k|1024k|2048k]"); - -static void -bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event); -static void -bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event); -static void -bfad_sm_initializing(struct bfad_s *bfad, enum bfad_sm_event event); -static void -bfad_sm_operational(struct bfad_s *bfad, enum bfad_sm_event event); -static void -bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event); -static void -bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event); -static void -bfad_sm_fcs_exit(struct bfad_s *bfad, enum bfad_sm_event event); - -/* - * Beginning state for the driver instance, awaiting the pci_probe event - */ -static void -bfad_sm_uninit(struct bfad_s *bfad, enum bfad_sm_event event) -{ - bfa_trc(bfad, event); - - switch (event) { - case BFAD_E_CREATE: - bfa_sm_set_state(bfad, bfad_sm_created); - bfad->bfad_tsk = kthread_create(bfad_worker, (void *) bfad, - "%s", "bfad_worker"); - if (IS_ERR(bfad->bfad_tsk)) { - printk(KERN_INFO "bfad[%d]: Kernel thread " - "creation failed!\n", bfad->inst_no); - bfa_sm_send_event(bfad, BFAD_E_KTHREAD_CREATE_FAILED); - } - bfa_sm_send_event(bfad, BFAD_E_INIT); - break; - - case BFAD_E_STOP: - /* Ignore stop; already in uninit */ - break; - - default: - bfa_sm_fault(bfad, event); - } -} - -/* - * Driver Instance is created, awaiting event INIT to initialize the bfad - */ -static void -bfad_sm_created(struct bfad_s *bfad, enum bfad_sm_event event) -{ - unsigned long flags; - - bfa_trc(bfad, event); - - switch (event) { - case BFAD_E_INIT: - bfa_sm_set_state(bfad, bfad_sm_initializing); - - init_completion(&bfad->comp); - - /* Enable Interrupt and wait bfa_init completion */ - if (bfad_setup_intr(bfad)) { - printk(KERN_WARNING "bfad%d: bfad_setup_intr failed\n", - bfad->inst_no); - bfa_sm_send_event(bfad, BFAD_E_INTR_INIT_FAILED); - break; - } - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_iocfc_init(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* Set up interrupt handler for each vectors */ - if ((bfad->bfad_flags & BFAD_MSIX_ON) && - bfad_install_msix_handler(bfad)) { - printk(KERN_WARNING "%s: install_msix failed, bfad%d\n", - __func__, bfad->inst_no); - } - - bfad_init_timer(bfad); - - wait_for_completion(&bfad->comp); - - if ((bfad->bfad_flags & BFAD_HAL_INIT_DONE)) { - bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); - } else { - printk(KERN_WARNING - "bfa %s: bfa init failed\n", - bfad->pci_name); - bfad->bfad_flags |= BFAD_HAL_INIT_FAIL; - bfa_sm_send_event(bfad, BFAD_E_INIT_FAILED); - } - - break; - - case BFAD_E_KTHREAD_CREATE_FAILED: - bfa_sm_set_state(bfad, bfad_sm_uninit); - break; - - default: - bfa_sm_fault(bfad, event); - } -} - -static void -bfad_sm_initializing(struct bfad_s *bfad, enum bfad_sm_event event) -{ - int retval; - unsigned long flags; - - bfa_trc(bfad, event); - - switch (event) { - case BFAD_E_INIT_SUCCESS: - kthread_stop(bfad->bfad_tsk); - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfad->bfad_tsk = NULL; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - retval = bfad_start_ops(bfad); - if (retval != BFA_STATUS_OK) - break; - bfa_sm_set_state(bfad, bfad_sm_operational); - break; - - case BFAD_E_INTR_INIT_FAILED: - bfa_sm_set_state(bfad, bfad_sm_uninit); - kthread_stop(bfad->bfad_tsk); - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfad->bfad_tsk = NULL; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - break; - - case BFAD_E_INIT_FAILED: - bfa_sm_set_state(bfad, bfad_sm_failed); - break; - default: - bfa_sm_fault(bfad, event); - } -} - -static void -bfad_sm_failed(struct bfad_s *bfad, enum bfad_sm_event event) -{ - int retval; - - bfa_trc(bfad, event); - - switch (event) { - case BFAD_E_INIT_SUCCESS: - retval = bfad_start_ops(bfad); - if (retval != BFA_STATUS_OK) - break; - bfa_sm_set_state(bfad, bfad_sm_operational); - break; - - case BFAD_E_STOP: - if (bfad->bfad_flags & BFAD_CFG_PPORT_DONE) - bfad_uncfg_pport(bfad); - if (bfad->bfad_flags & BFAD_FC4_PROBE_DONE) { - bfad_im_probe_undo(bfad); - bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; - } - bfad_stop(bfad); - break; - - case BFAD_E_EXIT_COMP: - bfa_sm_set_state(bfad, bfad_sm_uninit); - bfad_remove_intr(bfad); - del_timer_sync(&bfad->hal_tmo); - break; - - default: - bfa_sm_fault(bfad, event); - } -} - -static void -bfad_sm_operational(struct bfad_s *bfad, enum bfad_sm_event event) -{ - bfa_trc(bfad, event); - - switch (event) { - case BFAD_E_STOP: - bfa_sm_set_state(bfad, bfad_sm_fcs_exit); - bfad_fcs_stop(bfad); - break; - - default: - bfa_sm_fault(bfad, event); - } -} - -static void -bfad_sm_fcs_exit(struct bfad_s *bfad, enum bfad_sm_event event) -{ - bfa_trc(bfad, event); - - switch (event) { - case BFAD_E_FCS_EXIT_COMP: - bfa_sm_set_state(bfad, bfad_sm_stopping); - bfad_stop(bfad); - break; - - default: - bfa_sm_fault(bfad, event); - } -} - -static void -bfad_sm_stopping(struct bfad_s *bfad, enum bfad_sm_event event) -{ - bfa_trc(bfad, event); - - switch (event) { - case BFAD_E_EXIT_COMP: - bfa_sm_set_state(bfad, bfad_sm_uninit); - bfad_remove_intr(bfad); - del_timer_sync(&bfad->hal_tmo); - bfad_im_probe_undo(bfad); - bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; - bfad_uncfg_pport(bfad); - break; - - default: - bfa_sm_fault(bfad, event); - break; - } -} - -/* - * BFA callbacks - */ -void -bfad_hcb_comp(void *arg, bfa_status_t status) -{ - struct bfad_hal_comp *fcomp = (struct bfad_hal_comp *)arg; - - fcomp->status = status; - complete(&fcomp->comp); -} - -/* - * bfa_init callback - */ -void -bfa_cb_init(void *drv, bfa_status_t init_status) -{ - struct bfad_s *bfad = drv; - - if (init_status == BFA_STATUS_OK) { - bfad->bfad_flags |= BFAD_HAL_INIT_DONE; - - /* - * If BFAD_HAL_INIT_FAIL flag is set: - * Wake up the kernel thread to start - * the bfad operations after HAL init done - */ - if ((bfad->bfad_flags & BFAD_HAL_INIT_FAIL)) { - bfad->bfad_flags &= ~BFAD_HAL_INIT_FAIL; - wake_up_process(bfad->bfad_tsk); - } - } - - complete(&bfad->comp); -} - -/* - * BFA_FCS callbacks - */ -struct bfad_port_s * -bfa_fcb_lport_new(struct bfad_s *bfad, struct bfa_fcs_lport_s *port, - enum bfa_lport_role roles, struct bfad_vf_s *vf_drv, - struct bfad_vport_s *vp_drv) -{ - bfa_status_t rc; - struct bfad_port_s *port_drv; - - if (!vp_drv && !vf_drv) { - port_drv = &bfad->pport; - port_drv->pvb_type = BFAD_PORT_PHYS_BASE; - } else if (!vp_drv && vf_drv) { - port_drv = &vf_drv->base_port; - port_drv->pvb_type = BFAD_PORT_VF_BASE; - } else if (vp_drv && !vf_drv) { - port_drv = &vp_drv->drv_port; - port_drv->pvb_type = BFAD_PORT_PHYS_VPORT; - } else { - port_drv = &vp_drv->drv_port; - port_drv->pvb_type = BFAD_PORT_VF_VPORT; - } - - port_drv->fcs_port = port; - port_drv->roles = roles; - - if (roles & BFA_LPORT_ROLE_FCP_IM) { - rc = bfad_im_port_new(bfad, port_drv); - if (rc != BFA_STATUS_OK) { - bfad_im_port_delete(bfad, port_drv); - port_drv = NULL; - } - } - - return port_drv; -} - -void -bfa_fcb_lport_delete(struct bfad_s *bfad, enum bfa_lport_role roles, - struct bfad_vf_s *vf_drv, struct bfad_vport_s *vp_drv) -{ - struct bfad_port_s *port_drv; - - /* this will be only called from rmmod context */ - if (vp_drv && !vp_drv->comp_del) { - port_drv = (vp_drv) ? (&(vp_drv)->drv_port) : - ((vf_drv) ? (&(vf_drv)->base_port) : - (&(bfad)->pport)); - bfa_trc(bfad, roles); - if (roles & BFA_LPORT_ROLE_FCP_IM) - bfad_im_port_delete(bfad, port_drv); - } -} - -/* - * FCS RPORT alloc callback, after successful PLOGI by FCS - */ -bfa_status_t -bfa_fcb_rport_alloc(struct bfad_s *bfad, struct bfa_fcs_rport_s **rport, - struct bfad_rport_s **rport_drv) -{ - bfa_status_t rc = BFA_STATUS_OK; - - *rport_drv = kzalloc(sizeof(struct bfad_rport_s), GFP_ATOMIC); - if (*rport_drv == NULL) { - rc = BFA_STATUS_ENOMEM; - goto ext; - } - - *rport = &(*rport_drv)->fcs_rport; - -ext: - return rc; -} - -/* - * FCS PBC VPORT Create - */ -void -bfa_fcb_pbc_vport_create(struct bfad_s *bfad, struct bfi_pbc_vport_s pbc_vport) -{ - - struct bfa_lport_cfg_s port_cfg = {0}; - struct bfad_vport_s *vport; - int rc; - - vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL); - if (!vport) { - bfa_trc(bfad, 0); - return; - } - - vport->drv_port.bfad = bfad; - port_cfg.roles = BFA_LPORT_ROLE_FCP_IM; - port_cfg.pwwn = pbc_vport.vp_pwwn; - port_cfg.nwwn = pbc_vport.vp_nwwn; - port_cfg.preboot_vp = BFA_TRUE; - - rc = bfa_fcs_pbc_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, 0, - &port_cfg, vport); - - if (rc != BFA_STATUS_OK) { - bfa_trc(bfad, 0); - return; - } - - list_add_tail(&vport->list_entry, &bfad->pbc_vport_list); -} - -void -bfad_hal_mem_release(struct bfad_s *bfad) -{ - struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; - - dma_info = &hal_meminfo->dma_info; - kva_info = &hal_meminfo->kva_info; - - /* Iterate through the KVA meminfo queue */ - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - vfree(kva_elem->kva); - } - - /* Iterate through the DMA meminfo queue */ - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_free_coherent(&bfad->pcidev->dev, - dma_elem->mem_len, dma_elem->kva, - (dma_addr_t) dma_elem->dma); - } - - memset(hal_meminfo, 0, sizeof(struct bfa_meminfo_s)); -} - -void -bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg) -{ - if (num_rports > 0) - bfa_cfg->fwcfg.num_rports = num_rports; - if (num_ios > 0) - bfa_cfg->fwcfg.num_ioim_reqs = num_ios; - if (num_tms > 0) - bfa_cfg->fwcfg.num_tskim_reqs = num_tms; - if (num_fcxps > 0 && num_fcxps <= BFA_FCXP_MAX) - bfa_cfg->fwcfg.num_fcxp_reqs = num_fcxps; - if (num_ufbufs > 0 && num_ufbufs <= BFA_UF_MAX) - bfa_cfg->fwcfg.num_uf_bufs = num_ufbufs; - if (reqq_size > 0) - bfa_cfg->drvcfg.num_reqq_elems = reqq_size; - if (rspq_size > 0) - bfa_cfg->drvcfg.num_rspq_elems = rspq_size; - if (num_sgpgs > 0 && num_sgpgs <= BFA_SGPG_MAX) - bfa_cfg->drvcfg.num_sgpgs = num_sgpgs; - - /* - * populate the hal values back to the driver for sysfs use. - * otherwise, the default values will be shown as 0 in sysfs - */ - num_rports = bfa_cfg->fwcfg.num_rports; - num_ios = bfa_cfg->fwcfg.num_ioim_reqs; - num_tms = bfa_cfg->fwcfg.num_tskim_reqs; - num_fcxps = bfa_cfg->fwcfg.num_fcxp_reqs; - num_ufbufs = bfa_cfg->fwcfg.num_uf_bufs; - reqq_size = bfa_cfg->drvcfg.num_reqq_elems; - rspq_size = bfa_cfg->drvcfg.num_rspq_elems; - num_sgpgs = bfa_cfg->drvcfg.num_sgpgs; -} - -bfa_status_t -bfad_hal_mem_alloc(struct bfad_s *bfad) -{ - struct bfa_meminfo_s *hal_meminfo = &bfad->meminfo; - struct bfa_mem_dma_s *dma_info, *dma_elem; - struct bfa_mem_kva_s *kva_info, *kva_elem; - struct list_head *dm_qe, *km_qe; - bfa_status_t rc = BFA_STATUS_OK; - dma_addr_t phys_addr; - - bfa_cfg_get_default(&bfad->ioc_cfg); - bfad_update_hal_cfg(&bfad->ioc_cfg); - bfad->cfg_data.ioc_queue_depth = bfad->ioc_cfg.fwcfg.num_ioim_reqs; - bfa_cfg_get_meminfo(&bfad->ioc_cfg, hal_meminfo, &bfad->bfa); - - dma_info = &hal_meminfo->dma_info; - kva_info = &hal_meminfo->kva_info; - - /* Iterate through the KVA meminfo queue */ - list_for_each(km_qe, &kva_info->qe) { - kva_elem = (struct bfa_mem_kva_s *) km_qe; - kva_elem->kva = vmalloc(kva_elem->mem_len); - if (kva_elem->kva == NULL) { - bfad_hal_mem_release(bfad); - rc = BFA_STATUS_ENOMEM; - goto ext; - } - memset(kva_elem->kva, 0, kva_elem->mem_len); - } - - /* Iterate through the DMA meminfo queue */ - list_for_each(dm_qe, &dma_info->qe) { - dma_elem = (struct bfa_mem_dma_s *) dm_qe; - dma_elem->kva = dma_alloc_coherent(&bfad->pcidev->dev, - dma_elem->mem_len, - &phys_addr, GFP_KERNEL); - if (dma_elem->kva == NULL) { - bfad_hal_mem_release(bfad); - rc = BFA_STATUS_ENOMEM; - goto ext; - } - dma_elem->dma = phys_addr; - memset(dma_elem->kva, 0, dma_elem->mem_len); - } -ext: - return rc; -} - -/* - * Create a vport under a vf. - */ -bfa_status_t -bfad_vport_create(struct bfad_s *bfad, u16 vf_id, - struct bfa_lport_cfg_s *port_cfg, struct device *dev) -{ - struct bfad_vport_s *vport; - int rc = BFA_STATUS_OK; - unsigned long flags; - struct completion fcomp; - - vport = kzalloc(sizeof(struct bfad_vport_s), GFP_KERNEL); - if (!vport) { - rc = BFA_STATUS_ENOMEM; - goto ext; - } - - vport->drv_port.bfad = bfad; - spin_lock_irqsave(&bfad->bfad_lock, flags); - rc = bfa_fcs_vport_create(&vport->fcs_vport, &bfad->bfa_fcs, vf_id, - port_cfg, vport); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (rc != BFA_STATUS_OK) - goto ext_free_vport; - - if (port_cfg->roles & BFA_LPORT_ROLE_FCP_IM) { - rc = bfad_im_scsi_host_alloc(bfad, vport->drv_port.im_port, - dev); - if (rc != BFA_STATUS_OK) - goto ext_free_fcs_vport; - } - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcs_vport_start(&vport->fcs_vport); - list_add_tail(&vport->list_entry, &bfad->vport_list); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return BFA_STATUS_OK; - -ext_free_fcs_vport: - spin_lock_irqsave(&bfad->bfad_lock, flags); - vport->comp_del = &fcomp; - init_completion(vport->comp_del); - bfa_fcs_vport_delete(&vport->fcs_vport); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(vport->comp_del); -ext_free_vport: - kfree(vport); -ext: - return rc; -} - -void -bfad_bfa_tmo(unsigned long data) -{ - struct bfad_s *bfad = (struct bfad_s *) data; - unsigned long flags; - struct list_head doneq; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - bfa_timer_beat(&bfad->bfa.timer_mod); - - bfa_comp_deq(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (!list_empty(&doneq)) { - bfa_comp_process(&bfad->bfa, &doneq); - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_comp_free(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } - - mod_timer(&bfad->hal_tmo, - jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); -} - -void -bfad_init_timer(struct bfad_s *bfad) -{ - init_timer(&bfad->hal_tmo); - bfad->hal_tmo.function = bfad_bfa_tmo; - bfad->hal_tmo.data = (unsigned long)bfad; - - mod_timer(&bfad->hal_tmo, - jiffies + msecs_to_jiffies(BFA_TIMER_FREQ)); -} - -int -bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad) -{ - int rc = -ENODEV; - - if (pci_enable_device(pdev)) { - printk(KERN_ERR "pci_enable_device fail %p\n", pdev); - goto out; - } - - if (pci_request_regions(pdev, BFAD_DRIVER_NAME)) - goto out_disable_device; - - pci_set_master(pdev); - - - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) != 0)) { - printk(KERN_ERR "pci_set_dma_mask fail %p\n", pdev); - goto out_release_region; - } - } - - bfad->pci_bar0_kva = pci_iomap(pdev, 0, pci_resource_len(pdev, 0)); - bfad->pci_bar2_kva = pci_iomap(pdev, 2, pci_resource_len(pdev, 2)); - - if (bfad->pci_bar0_kva == NULL) { - printk(KERN_ERR "Fail to map bar0\n"); - goto out_release_region; - } - - bfad->hal_pcidev.pci_slot = PCI_SLOT(pdev->devfn); - bfad->hal_pcidev.pci_func = PCI_FUNC(pdev->devfn); - bfad->hal_pcidev.pci_bar_kva = bfad->pci_bar0_kva; - bfad->hal_pcidev.device_id = pdev->device; - bfad->hal_pcidev.ssid = pdev->subsystem_device; - bfad->pci_name = pci_name(pdev); - - bfad->pci_attr.vendor_id = pdev->vendor; - bfad->pci_attr.device_id = pdev->device; - bfad->pci_attr.ssid = pdev->subsystem_device; - bfad->pci_attr.ssvid = pdev->subsystem_vendor; - bfad->pci_attr.pcifn = PCI_FUNC(pdev->devfn); - - bfad->pcidev = pdev; - - /* Adjust PCIe Maximum Read Request Size */ - if (pcie_max_read_reqsz > 0) { - int pcie_cap_reg; - u16 pcie_dev_ctl; - u16 mask = 0xffff; - - switch (pcie_max_read_reqsz) { - case 128: - mask = 0x0; - break; - case 256: - mask = 0x1000; - break; - case 512: - mask = 0x2000; - break; - case 1024: - mask = 0x3000; - break; - case 2048: - mask = 0x4000; - break; - case 4096: - mask = 0x5000; - break; - default: - break; - } - - pcie_cap_reg = pci_find_capability(pdev, PCI_CAP_ID_EXP); - if (mask != 0xffff && pcie_cap_reg) { - pcie_cap_reg += 0x08; - pci_read_config_word(pdev, pcie_cap_reg, &pcie_dev_ctl); - if ((pcie_dev_ctl & 0x7000) != mask) { - printk(KERN_WARNING "BFA[%s]: " - "pcie_max_read_request_size is %d, " - "reset to %d\n", bfad->pci_name, - (1 << ((pcie_dev_ctl & 0x7000) >> 12)) << 7, - pcie_max_read_reqsz); - - pcie_dev_ctl &= ~0x7000; - pci_write_config_word(pdev, pcie_cap_reg, - pcie_dev_ctl | mask); - } - } - } - - return 0; - -out_release_region: - pci_release_regions(pdev); -out_disable_device: - pci_disable_device(pdev); -out: - return rc; -} - -void -bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad) -{ - pci_iounmap(pdev, bfad->pci_bar0_kva); - pci_iounmap(pdev, bfad->pci_bar2_kva); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - -bfa_status_t -bfad_drv_init(struct bfad_s *bfad) -{ - bfa_status_t rc; - unsigned long flags; - - bfad->cfg_data.rport_del_timeout = rport_del_timeout; - bfad->cfg_data.lun_queue_depth = bfa_lun_queue_depth; - bfad->cfg_data.io_max_sge = bfa_io_max_sge; - bfad->cfg_data.binding_method = FCP_PWWN_BINDING; - - rc = bfad_hal_mem_alloc(bfad); - if (rc != BFA_STATUS_OK) { - printk(KERN_WARNING "bfad%d bfad_hal_mem_alloc failure\n", - bfad->inst_no); - printk(KERN_WARNING - "Not enough memory to attach all Brocade HBA ports, %s", - "System may need more memory.\n"); - goto out_hal_mem_alloc_failure; - } - - bfad->bfa.trcmod = bfad->trcmod; - bfad->bfa.plog = &bfad->plog_buf; - bfa_plog_init(&bfad->plog_buf); - bfa_plog_str(&bfad->plog_buf, BFA_PL_MID_DRVR, BFA_PL_EID_DRIVER_START, - 0, "Driver Attach"); - - bfa_attach(&bfad->bfa, bfad, &bfad->ioc_cfg, &bfad->meminfo, - &bfad->hal_pcidev); - - /* FCS INIT */ - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfad->bfa_fcs.trcmod = bfad->trcmod; - bfa_fcs_attach(&bfad->bfa_fcs, &bfad->bfa, bfad, BFA_FALSE); - bfad->bfa_fcs.fdmi_enabled = fdmi_enable; - bfa_fcs_init(&bfad->bfa_fcs); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - bfad->bfad_flags |= BFAD_DRV_INIT_DONE; - - /* configure base port */ - rc = bfad_cfg_pport(bfad, BFA_LPORT_ROLE_FCP_IM); - if (rc != BFA_STATUS_OK) - goto out_cfg_pport_fail; - - return BFA_STATUS_OK; - -out_cfg_pport_fail: - /* fcs exit - on cfg pport failure */ - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfad->pport.flags |= BFAD_PORT_DELETE; - bfa_fcs_exit(&bfad->bfa_fcs); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); - /* bfa detach - free hal memory */ - bfa_detach(&bfad->bfa); - bfad_hal_mem_release(bfad); -out_hal_mem_alloc_failure: - return BFA_STATUS_FAILED; -} - -void -bfad_drv_uninit(struct bfad_s *bfad) -{ - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfa_iocfc_stop(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); - - del_timer_sync(&bfad->hal_tmo); - bfa_isr_disable(&bfad->bfa); - bfa_detach(&bfad->bfa); - bfad_remove_intr(bfad); - bfad_hal_mem_release(bfad); - - bfad->bfad_flags &= ~BFAD_DRV_INIT_DONE; -} - -void -bfad_drv_start(struct bfad_s *bfad) -{ - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_iocfc_start(&bfad->bfa); - bfa_fcs_pbc_vport_init(&bfad->bfa_fcs); - bfa_fcs_fabric_modstart(&bfad->bfa_fcs); - bfad->bfad_flags |= BFAD_HAL_START_DONE; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (bfad->im) - flush_workqueue(bfad->im->drv_workq); -} - -void -bfad_fcs_stop(struct bfad_s *bfad) -{ - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfad->pport.flags |= BFAD_PORT_DELETE; - bfa_fcs_exit(&bfad->bfa_fcs); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); - - bfa_sm_send_event(bfad, BFAD_E_FCS_EXIT_COMP); -} - -void -bfad_stop(struct bfad_s *bfad) -{ - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - init_completion(&bfad->comp); - bfa_iocfc_stop(&bfad->bfa); - bfad->bfad_flags &= ~BFAD_HAL_START_DONE; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->comp); - - bfa_sm_send_event(bfad, BFAD_E_EXIT_COMP); -} - -bfa_status_t -bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role) -{ - int rc = BFA_STATUS_OK; - - /* Allocate scsi_host for the physical port */ - if ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) && - (role & BFA_LPORT_ROLE_FCP_IM)) { - if (bfad->pport.im_port == NULL) { - rc = BFA_STATUS_FAILED; - goto out; - } - - rc = bfad_im_scsi_host_alloc(bfad, bfad->pport.im_port, - &bfad->pcidev->dev); - if (rc != BFA_STATUS_OK) - goto out; - - bfad->pport.roles |= BFA_LPORT_ROLE_FCP_IM; - } - - bfad->bfad_flags |= BFAD_CFG_PPORT_DONE; - -out: - return rc; -} - -void -bfad_uncfg_pport(struct bfad_s *bfad) -{ - if ((supported_fc4s & BFA_LPORT_ROLE_FCP_IM) && - (bfad->pport.roles & BFA_LPORT_ROLE_FCP_IM)) { - bfad_im_scsi_host_free(bfad, bfad->pport.im_port); - bfad_im_port_clean(bfad->pport.im_port); - kfree(bfad->pport.im_port); - bfad->pport.roles &= ~BFA_LPORT_ROLE_FCP_IM; - } - - bfad->bfad_flags &= ~BFAD_CFG_PPORT_DONE; -} - -bfa_status_t -bfad_start_ops(struct bfad_s *bfad) { - - int retval; - unsigned long flags; - struct bfad_vport_s *vport, *vport_new; - struct bfa_fcs_driver_info_s driver_info; - - /* Limit min/max. xfer size to [64k-32MB] */ - if (max_xfer_size < BFAD_MIN_SECTORS >> 1) - max_xfer_size = BFAD_MIN_SECTORS >> 1; - if (max_xfer_size > BFAD_MAX_SECTORS >> 1) - max_xfer_size = BFAD_MAX_SECTORS >> 1; - - /* Fill the driver_info info to fcs*/ - memset(&driver_info, 0, sizeof(driver_info)); - strncpy(driver_info.version, BFAD_DRIVER_VERSION, - sizeof(driver_info.version) - 1); - if (host_name) - strncpy(driver_info.host_machine_name, host_name, - sizeof(driver_info.host_machine_name) - 1); - if (os_name) - strncpy(driver_info.host_os_name, os_name, - sizeof(driver_info.host_os_name) - 1); - if (os_patch) - strncpy(driver_info.host_os_patch, os_patch, - sizeof(driver_info.host_os_patch) - 1); - - strncpy(driver_info.os_device_name, bfad->pci_name, - sizeof(driver_info.os_device_name - 1)); - - /* FCS driver info init */ - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcs_driver_info_init(&bfad->bfa_fcs, &driver_info); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* - * FCS update cfg - reset the pwwn/nwwn of fabric base logical port - * with values learned during bfa_init firmware GETATTR REQ. - */ - bfa_fcs_update_cfg(&bfad->bfa_fcs); - - /* Setup fc host fixed attribute if the lk supports */ - bfad_fc_host_init(bfad->pport.im_port); - - /* BFAD level FC4 IM specific resource allocation */ - retval = bfad_im_probe(bfad); - if (retval != BFA_STATUS_OK) { - printk(KERN_WARNING "bfad_im_probe failed\n"); - if (bfa_sm_cmp_state(bfad, bfad_sm_initializing)) - bfa_sm_set_state(bfad, bfad_sm_failed); - bfad_im_probe_undo(bfad); - bfad->bfad_flags &= ~BFAD_FC4_PROBE_DONE; - bfad_uncfg_pport(bfad); - bfad_stop(bfad); - return BFA_STATUS_FAILED; - } else - bfad->bfad_flags |= BFAD_FC4_PROBE_DONE; - - bfad_drv_start(bfad); - - /* Complete pbc vport create */ - list_for_each_entry_safe(vport, vport_new, &bfad->pbc_vport_list, - list_entry) { - struct fc_vport_identifiers vid; - struct fc_vport *fc_vport; - char pwwn_buf[BFA_STRING_32]; - - memset(&vid, 0, sizeof(vid)); - vid.roles = FC_PORT_ROLE_FCP_INITIATOR; - vid.vport_type = FC_PORTTYPE_NPIV; - vid.disable = false; - vid.node_name = wwn_to_u64((u8 *) - (&((vport->fcs_vport).lport.port_cfg.nwwn))); - vid.port_name = wwn_to_u64((u8 *) - (&((vport->fcs_vport).lport.port_cfg.pwwn))); - fc_vport = fc_vport_create(bfad->pport.im_port->shost, 0, &vid); - if (!fc_vport) { - wwn2str(pwwn_buf, vid.port_name); - printk(KERN_WARNING "bfad%d: failed to create pbc vport" - " %s\n", bfad->inst_no, pwwn_buf); - } - list_del(&vport->list_entry); - kfree(vport); - } - - /* - * If bfa_linkup_delay is set to -1 default; try to retrive the - * value using the bfad_get_linkup_delay(); else use the - * passed in module param value as the bfa_linkup_delay. - */ - if (bfa_linkup_delay < 0) { - bfa_linkup_delay = bfad_get_linkup_delay(bfad); - bfad_rport_online_wait(bfad); - bfa_linkup_delay = -1; - } else - bfad_rport_online_wait(bfad); - - BFA_LOG(KERN_INFO, bfad, bfa_log_level, "bfa device claimed\n"); - - return BFA_STATUS_OK; -} - -int -bfad_worker(void *ptr) -{ - struct bfad_s *bfad; - unsigned long flags; - - bfad = (struct bfad_s *)ptr; - - while (!kthread_should_stop()) { - - /* Send event BFAD_E_INIT_SUCCESS */ - bfa_sm_send_event(bfad, BFAD_E_INIT_SUCCESS); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfad->bfad_tsk = NULL; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - break; - } - - return 0; -} - -/* - * BFA driver interrupt functions - */ -irqreturn_t -bfad_intx(int irq, void *dev_id) -{ - struct bfad_s *bfad = dev_id; - struct list_head doneq; - unsigned long flags; - bfa_boolean_t rc; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - rc = bfa_intx(&bfad->bfa); - if (!rc) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return IRQ_NONE; - } - - bfa_comp_deq(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (!list_empty(&doneq)) { - bfa_comp_process(&bfad->bfa, &doneq); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_comp_free(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } - - return IRQ_HANDLED; - -} - -static irqreturn_t -bfad_msix(int irq, void *dev_id) -{ - struct bfad_msix_s *vec = dev_id; - struct bfad_s *bfad = vec->bfad; - struct list_head doneq; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - bfa_msix(&bfad->bfa, vec->msix.entry); - bfa_comp_deq(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (!list_empty(&doneq)) { - bfa_comp_process(&bfad->bfa, &doneq); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_comp_free(&bfad->bfa, &doneq); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } - - return IRQ_HANDLED; -} - -/* - * Initialize the MSIX entry table. - */ -static void -bfad_init_msix_entry(struct bfad_s *bfad, struct msix_entry *msix_entries, - int mask, int max_bit) -{ - int i; - int match = 0x00000001; - - for (i = 0, bfad->nvec = 0; i < MAX_MSIX_ENTRY; i++) { - if (mask & match) { - bfad->msix_tab[bfad->nvec].msix.entry = i; - bfad->msix_tab[bfad->nvec].bfad = bfad; - msix_entries[bfad->nvec].entry = i; - bfad->nvec++; - } - - match <<= 1; - } - -} - -int -bfad_install_msix_handler(struct bfad_s *bfad) -{ - int i, error = 0; - - for (i = 0; i < bfad->nvec; i++) { - sprintf(bfad->msix_tab[i].name, "bfa-%s-%s", - bfad->pci_name, - ((bfa_asic_id_cb(bfad->hal_pcidev.device_id)) ? - msix_name_cb[i] : msix_name_ct[i])); - - error = request_irq(bfad->msix_tab[i].msix.vector, - (irq_handler_t) bfad_msix, 0, - bfad->msix_tab[i].name, &bfad->msix_tab[i]); - bfa_trc(bfad, i); - bfa_trc(bfad, bfad->msix_tab[i].msix.vector); - if (error) { - int j; - - for (j = 0; j < i; j++) - free_irq(bfad->msix_tab[j].msix.vector, - &bfad->msix_tab[j]); - - bfad->bfad_flags &= ~BFAD_MSIX_ON; - pci_disable_msix(bfad->pcidev); - - return 1; - } - } - - return 0; -} - -/* - * Setup MSIX based interrupt. - */ -int -bfad_setup_intr(struct bfad_s *bfad) -{ - int error = 0; - u32 mask = 0, i, num_bit = 0, max_bit = 0; - struct msix_entry msix_entries[MAX_MSIX_ENTRY]; - struct pci_dev *pdev = bfad->pcidev; - u16 reg; - - /* Call BFA to get the msix map for this PCI function. */ - bfa_msix_getvecs(&bfad->bfa, &mask, &num_bit, &max_bit); - - /* Set up the msix entry table */ - bfad_init_msix_entry(bfad, msix_entries, mask, max_bit); - - if ((bfa_asic_id_ctc(pdev->device) && !msix_disable_ct) || - (bfa_asic_id_cb(pdev->device) && !msix_disable_cb)) { - - error = pci_enable_msix(bfad->pcidev, msix_entries, bfad->nvec); - if (error) { - /* - * Only error number of vector is available. - * We don't have a mechanism to map multiple - * interrupts into one vector, so even if we - * can try to request less vectors, we don't - * know how to associate interrupt events to - * vectors. Linux doesn't duplicate vectors - * in the MSIX table for this case. - */ - - printk(KERN_WARNING "bfad%d: " - "pci_enable_msix failed (%d)," - " use line based.\n", bfad->inst_no, error); - - goto line_based; - } - - /* Disable INTX in MSI-X mode */ - pci_read_config_word(pdev, PCI_COMMAND, ®); - - if (!(reg & PCI_COMMAND_INTX_DISABLE)) - pci_write_config_word(pdev, PCI_COMMAND, - reg | PCI_COMMAND_INTX_DISABLE); - - /* Save the vectors */ - for (i = 0; i < bfad->nvec; i++) { - bfa_trc(bfad, msix_entries[i].vector); - bfad->msix_tab[i].msix.vector = msix_entries[i].vector; - } - - bfa_msix_init(&bfad->bfa, bfad->nvec); - - bfad->bfad_flags |= BFAD_MSIX_ON; - - return error; - } - -line_based: - error = 0; - if (request_irq - (bfad->pcidev->irq, (irq_handler_t) bfad_intx, BFAD_IRQ_FLAGS, - BFAD_DRIVER_NAME, bfad) != 0) { - /* Enable interrupt handler failed */ - return 1; - } - bfad->bfad_flags |= BFAD_INTX_ON; - - return error; -} - -void -bfad_remove_intr(struct bfad_s *bfad) -{ - int i; - - if (bfad->bfad_flags & BFAD_MSIX_ON) { - for (i = 0; i < bfad->nvec; i++) - free_irq(bfad->msix_tab[i].msix.vector, - &bfad->msix_tab[i]); - - pci_disable_msix(bfad->pcidev); - bfad->bfad_flags &= ~BFAD_MSIX_ON; - } else if (bfad->bfad_flags & BFAD_INTX_ON) { - free_irq(bfad->pcidev->irq, bfad); - } -} - -/* - * PCI probe entry. - */ -int -bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid) -{ - struct bfad_s *bfad; - int error = -ENODEV, retval, i; - - /* For single port cards - only claim function 0 */ - if ((pdev->device == BFA_PCI_DEVICE_ID_FC_8G1P) && - (PCI_FUNC(pdev->devfn) != 0)) - return -ENODEV; - - bfad = kzalloc(sizeof(struct bfad_s), GFP_KERNEL); - if (!bfad) { - error = -ENOMEM; - goto out; - } - - bfad->trcmod = kzalloc(sizeof(struct bfa_trc_mod_s), GFP_KERNEL); - if (!bfad->trcmod) { - printk(KERN_WARNING "Error alloc trace buffer!\n"); - error = -ENOMEM; - goto out_alloc_trace_failure; - } - - /* TRACE INIT */ - bfa_trc_init(bfad->trcmod); - bfa_trc(bfad, bfad_inst); - - /* AEN INIT */ - INIT_LIST_HEAD(&bfad->free_aen_q); - INIT_LIST_HEAD(&bfad->active_aen_q); - for (i = 0; i < BFA_AEN_MAX_ENTRY; i++) - list_add_tail(&bfad->aen_list[i].qe, &bfad->free_aen_q); - - if (!(bfad_load_fwimg(pdev))) { - kfree(bfad->trcmod); - goto out_alloc_trace_failure; - } - - retval = bfad_pci_init(pdev, bfad); - if (retval) { - printk(KERN_WARNING "bfad_pci_init failure!\n"); - error = retval; - goto out_pci_init_failure; - } - - mutex_lock(&bfad_mutex); - bfad->inst_no = bfad_inst++; - list_add_tail(&bfad->list_entry, &bfad_list); - mutex_unlock(&bfad_mutex); - - /* Initializing the state machine: State set to uninit */ - bfa_sm_set_state(bfad, bfad_sm_uninit); - - spin_lock_init(&bfad->bfad_lock); - pci_set_drvdata(pdev, bfad); - - bfad->ref_count = 0; - bfad->pport.bfad = bfad; - INIT_LIST_HEAD(&bfad->pbc_vport_list); - INIT_LIST_HEAD(&bfad->vport_list); - - /* Setup the debugfs node for this bfad */ - if (bfa_debugfs_enable) - bfad_debugfs_init(&bfad->pport); - - retval = bfad_drv_init(bfad); - if (retval != BFA_STATUS_OK) - goto out_drv_init_failure; - - bfa_sm_send_event(bfad, BFAD_E_CREATE); - - if (bfa_sm_cmp_state(bfad, bfad_sm_uninit)) - goto out_bfad_sm_failure; - - return 0; - -out_bfad_sm_failure: - bfa_detach(&bfad->bfa); - bfad_hal_mem_release(bfad); -out_drv_init_failure: - /* Remove the debugfs node for this bfad */ - kfree(bfad->regdata); - bfad_debugfs_exit(&bfad->pport); - mutex_lock(&bfad_mutex); - bfad_inst--; - list_del(&bfad->list_entry); - mutex_unlock(&bfad_mutex); - bfad_pci_uninit(pdev, bfad); -out_pci_init_failure: - kfree(bfad->trcmod); -out_alloc_trace_failure: - kfree(bfad); -out: - return error; -} - -/* - * PCI remove entry. - */ -void -bfad_pci_remove(struct pci_dev *pdev) -{ - struct bfad_s *bfad = pci_get_drvdata(pdev); - unsigned long flags; - - bfa_trc(bfad, bfad->inst_no); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (bfad->bfad_tsk != NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - kthread_stop(bfad->bfad_tsk); - } else { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } - - /* Send Event BFAD_E_STOP */ - bfa_sm_send_event(bfad, BFAD_E_STOP); - - /* Driver detach and dealloc mem */ - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_detach(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfad_hal_mem_release(bfad); - - /* Remove the debugfs node for this bfad */ - kfree(bfad->regdata); - bfad_debugfs_exit(&bfad->pport); - - /* Cleaning the BFAD instance */ - mutex_lock(&bfad_mutex); - bfad_inst--; - list_del(&bfad->list_entry); - mutex_unlock(&bfad_mutex); - bfad_pci_uninit(pdev, bfad); - - kfree(bfad->trcmod); - kfree(bfad); -} - -struct pci_device_id bfad_id_table[] = { - { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_FC_8G2P, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_FC_8G1P, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_CT, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = (PCI_CLASS_SERIAL_FIBER << 8), - .class_mask = ~0, - }, - { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_CT_FC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = (PCI_CLASS_SERIAL_FIBER << 8), - .class_mask = ~0, - }, - { - .vendor = BFA_PCI_VENDOR_ID_BROCADE, - .device = BFA_PCI_DEVICE_ID_CT2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = (PCI_CLASS_SERIAL_FIBER << 8), - .class_mask = ~0, - }, - - {0, 0}, -}; - -MODULE_DEVICE_TABLE(pci, bfad_id_table); - -static struct pci_driver bfad_pci_driver = { - .name = BFAD_DRIVER_NAME, - .id_table = bfad_id_table, - .probe = bfad_pci_probe, - .remove = __devexit_p(bfad_pci_remove), -}; - -/* - * Driver module init. - */ -static int __init -bfad_init(void) -{ - int error = 0; - - printk(KERN_INFO "Brocade BFA FC/FCOE SCSI driver - version: %s\n", - BFAD_DRIVER_VERSION); - - if (num_sgpgs > 0) - num_sgpgs_parm = num_sgpgs; - - error = bfad_im_module_init(); - if (error) { - error = -ENOMEM; - printk(KERN_WARNING "bfad_im_module_init failure\n"); - goto ext; - } - - if (strcmp(FCPI_NAME, " fcpim") == 0) - supported_fc4s |= BFA_LPORT_ROLE_FCP_IM; - - bfa_auto_recover = ioc_auto_recover; - bfa_fcs_rport_set_del_timeout(rport_del_timeout); - - error = pci_register_driver(&bfad_pci_driver); - if (error) { - printk(KERN_WARNING "pci_register_driver failure\n"); - goto ext; - } - - return 0; - -ext: - bfad_im_module_exit(); - return error; -} - -/* - * Driver module exit. - */ -static void __exit -bfad_exit(void) -{ - pci_unregister_driver(&bfad_pci_driver); - bfad_im_module_exit(); - bfad_free_fwimg(); -} - -/* Firmware handling */ -static void -bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image, - u32 *bfi_image_size, char *fw_name) -{ - const struct firmware *fw; - - if (request_firmware(&fw, fw_name, &pdev->dev)) { - printk(KERN_ALERT "Can't locate firmware %s\n", fw_name); - *bfi_image = NULL; - goto out; - } - - *bfi_image = vmalloc(fw->size); - if (NULL == *bfi_image) { - printk(KERN_ALERT "Fail to allocate buffer for fw image " - "size=%x!\n", (u32) fw->size); - goto out; - } - - memcpy(*bfi_image, fw->data, fw->size); - *bfi_image_size = fw->size/sizeof(u32); -out: - release_firmware(fw); -} - -static u32 * -bfad_load_fwimg(struct pci_dev *pdev) -{ - if (pdev->device == BFA_PCI_DEVICE_ID_CT2) { - if (bfi_image_ct2_size == 0) - bfad_read_firmware(pdev, &bfi_image_ct2, - &bfi_image_ct2_size, BFAD_FW_FILE_CT2); - return bfi_image_ct2; - } else if (bfa_asic_id_ct(pdev->device)) { - if (bfi_image_ct_size == 0) - bfad_read_firmware(pdev, &bfi_image_ct, - &bfi_image_ct_size, BFAD_FW_FILE_CT); - return bfi_image_ct; - } else { - if (bfi_image_cb_size == 0) - bfad_read_firmware(pdev, &bfi_image_cb, - &bfi_image_cb_size, BFAD_FW_FILE_CB); - return bfi_image_cb; - } -} - -static void -bfad_free_fwimg(void) -{ - if (bfi_image_ct2_size && bfi_image_ct2) - vfree(bfi_image_ct2); - if (bfi_image_ct_size && bfi_image_ct) - vfree(bfi_image_ct); - if (bfi_image_cb_size && bfi_image_cb) - vfree(bfi_image_cb); -} - -module_init(bfad_init); -module_exit(bfad_exit); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Brocade Fibre Channel HBA Driver" BFAD_PROTO_NAME); -MODULE_AUTHOR("Brocade Communications Systems, Inc."); -MODULE_VERSION(BFAD_DRIVER_VERSION); diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_attr.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfad_attr.c deleted file mode 100644 index 7b1ecd2b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_attr.c +++ /dev/null @@ -1,978 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * bfa_attr.c Linux driver configuration interface module. - */ - -#include "bfad_drv.h" -#include "bfad_im.h" - -/* - * FC transport template entry, get SCSI target port ID. - */ -static void -bfad_im_get_starget_port_id(struct scsi_target *starget) -{ - struct Scsi_Host *shost; - struct bfad_im_port_s *im_port; - struct bfad_s *bfad; - struct bfad_itnim_s *itnim = NULL; - u32 fc_id = -1; - unsigned long flags; - - shost = dev_to_shost(starget->dev.parent); - im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - bfad = im_port->bfad; - spin_lock_irqsave(&bfad->bfad_lock, flags); - - itnim = bfad_get_itnim(im_port, starget->id); - if (itnim) - fc_id = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim); - - fc_starget_port_id(starget) = fc_id; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); -} - -/* - * FC transport template entry, get SCSI target nwwn. - */ -static void -bfad_im_get_starget_node_name(struct scsi_target *starget) -{ - struct Scsi_Host *shost; - struct bfad_im_port_s *im_port; - struct bfad_s *bfad; - struct bfad_itnim_s *itnim = NULL; - u64 node_name = 0; - unsigned long flags; - - shost = dev_to_shost(starget->dev.parent); - im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - bfad = im_port->bfad; - spin_lock_irqsave(&bfad->bfad_lock, flags); - - itnim = bfad_get_itnim(im_port, starget->id); - if (itnim) - node_name = bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim); - - fc_starget_node_name(starget) = cpu_to_be64(node_name); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); -} - -/* - * FC transport template entry, get SCSI target pwwn. - */ -static void -bfad_im_get_starget_port_name(struct scsi_target *starget) -{ - struct Scsi_Host *shost; - struct bfad_im_port_s *im_port; - struct bfad_s *bfad; - struct bfad_itnim_s *itnim = NULL; - u64 port_name = 0; - unsigned long flags; - - shost = dev_to_shost(starget->dev.parent); - im_port = (struct bfad_im_port_s *) shost->hostdata[0]; - bfad = im_port->bfad; - spin_lock_irqsave(&bfad->bfad_lock, flags); - - itnim = bfad_get_itnim(im_port, starget->id); - if (itnim) - port_name = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim); - - fc_starget_port_name(starget) = cpu_to_be64(port_name); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); -} - -/* - * FC transport template entry, get SCSI host port ID. - */ -static void -bfad_im_get_host_port_id(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_port_s *port = im_port->port; - - fc_host_port_id(shost) = - bfa_hton3b(bfa_fcs_lport_get_fcid(port->fcs_port)); -} - -/* - * FC transport template entry, get SCSI host port type. - */ -static void -bfad_im_get_host_port_type(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfa_lport_attr_s port_attr; - - bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr); - - switch (port_attr.port_type) { - case BFA_PORT_TYPE_NPORT: - fc_host_port_type(shost) = FC_PORTTYPE_NPORT; - break; - case BFA_PORT_TYPE_NLPORT: - fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; - break; - case BFA_PORT_TYPE_P2P: - fc_host_port_type(shost) = FC_PORTTYPE_PTP; - break; - case BFA_PORT_TYPE_LPORT: - fc_host_port_type(shost) = FC_PORTTYPE_LPORT; - break; - default: - fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; - break; - } -} - -/* - * FC transport template entry, get SCSI host port state. - */ -static void -bfad_im_get_host_port_state(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfa_port_attr_s attr; - - bfa_fcport_get_attr(&bfad->bfa, &attr); - - switch (attr.port_state) { - case BFA_PORT_ST_LINKDOWN: - fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; - break; - case BFA_PORT_ST_LINKUP: - fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; - break; - case BFA_PORT_ST_DISABLED: - case BFA_PORT_ST_STOPPED: - case BFA_PORT_ST_IOCDOWN: - case BFA_PORT_ST_IOCDIS: - fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; - break; - case BFA_PORT_ST_UNINIT: - case BFA_PORT_ST_ENABLING_QWAIT: - case BFA_PORT_ST_ENABLING: - case BFA_PORT_ST_DISABLING_QWAIT: - case BFA_PORT_ST_DISABLING: - default: - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - break; - } -} - -/* - * FC transport template entry, get SCSI host active fc4s. - */ -static void -bfad_im_get_host_active_fc4s(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_port_s *port = im_port->port; - - memset(fc_host_active_fc4s(shost), 0, - sizeof(fc_host_active_fc4s(shost))); - - if (port->supported_fc4s & BFA_LPORT_ROLE_FCP_IM) - fc_host_active_fc4s(shost)[2] = 1; - - fc_host_active_fc4s(shost)[7] = 1; -} - -/* - * FC transport template entry, get SCSI host link speed. - */ -static void -bfad_im_get_host_speed(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfa_port_attr_s attr; - - bfa_fcport_get_attr(&bfad->bfa, &attr); - switch (attr.speed) { - case BFA_PORT_SPEED_10GBPS: - fc_host_speed(shost) = FC_PORTSPEED_10GBIT; - break; - case BFA_PORT_SPEED_16GBPS: - fc_host_speed(shost) = FC_PORTSPEED_16GBIT; - break; - case BFA_PORT_SPEED_8GBPS: - fc_host_speed(shost) = FC_PORTSPEED_8GBIT; - break; - case BFA_PORT_SPEED_4GBPS: - fc_host_speed(shost) = FC_PORTSPEED_4GBIT; - break; - case BFA_PORT_SPEED_2GBPS: - fc_host_speed(shost) = FC_PORTSPEED_2GBIT; - break; - case BFA_PORT_SPEED_1GBPS: - fc_host_speed(shost) = FC_PORTSPEED_1GBIT; - break; - default: - fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - break; - } -} - -/* - * FC transport template entry, get SCSI host port type. - */ -static void -bfad_im_get_host_fabric_name(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_port_s *port = im_port->port; - wwn_t fabric_nwwn = 0; - - fabric_nwwn = bfa_fcs_lport_get_fabric_name(port->fcs_port); - - fc_host_fabric_name(shost) = cpu_to_be64(fabric_nwwn); - -} - -/* - * FC transport template entry, get BFAD statistics. - */ -static struct fc_host_statistics * -bfad_im_get_stats(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfad_hal_comp fcomp; - union bfa_port_stats_u *fcstats; - struct fc_host_statistics *hstats; - bfa_status_t rc; - unsigned long flags; - - fcstats = kzalloc(sizeof(union bfa_port_stats_u), GFP_KERNEL); - if (fcstats == NULL) - return NULL; - - hstats = &bfad->link_stats; - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - memset(hstats, 0, sizeof(struct fc_host_statistics)); - rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa), - fcstats, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (rc != BFA_STATUS_OK) - return NULL; - - wait_for_completion(&fcomp.comp); - - /* Fill the fc_host_statistics structure */ - hstats->seconds_since_last_reset = fcstats->fc.secs_reset; - hstats->tx_frames = fcstats->fc.tx_frames; - hstats->tx_words = fcstats->fc.tx_words; - hstats->rx_frames = fcstats->fc.rx_frames; - hstats->rx_words = fcstats->fc.rx_words; - hstats->lip_count = fcstats->fc.lip_count; - hstats->nos_count = fcstats->fc.nos_count; - hstats->error_frames = fcstats->fc.error_frames; - hstats->dumped_frames = fcstats->fc.dropped_frames; - hstats->link_failure_count = fcstats->fc.link_failures; - hstats->loss_of_sync_count = fcstats->fc.loss_of_syncs; - hstats->loss_of_signal_count = fcstats->fc.loss_of_signals; - hstats->prim_seq_protocol_err_count = fcstats->fc.primseq_errs; - hstats->invalid_crc_count = fcstats->fc.invalid_crcs; - - kfree(fcstats); - return hstats; -} - -/* - * FC transport template entry, reset BFAD statistics. - */ -static void -bfad_im_reset_stats(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfad_hal_comp fcomp; - unsigned long flags; - bfa_status_t rc; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - rc = bfa_port_clear_stats(BFA_FCPORT(&bfad->bfa), bfad_hcb_comp, - &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (rc != BFA_STATUS_OK) - return; - - wait_for_completion(&fcomp.comp); - - return; -} - -/* - * FC transport template entry, get rport loss timeout. - */ -static void -bfad_im_get_rport_loss_tmo(struct fc_rport *rport) -{ - struct bfad_itnim_data_s *itnim_data = rport->dd_data; - struct bfad_itnim_s *itnim = itnim_data->itnim; - struct bfad_s *bfad = itnim->im->bfad; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - rport->dev_loss_tmo = bfa_fcpim_path_tov_get(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); -} - -/* - * FC transport template entry, set rport loss timeout. - */ -static void -bfad_im_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout) -{ - struct bfad_itnim_data_s *itnim_data = rport->dd_data; - struct bfad_itnim_s *itnim = itnim_data->itnim; - struct bfad_s *bfad = itnim->im->bfad; - unsigned long flags; - - if (timeout > 0) { - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcpim_path_tov_set(&bfad->bfa, timeout); - rport->dev_loss_tmo = bfa_fcpim_path_tov_get(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } - -} - -static int -bfad_im_vport_create(struct fc_vport *fc_vport, bool disable) -{ - char *vname = fc_vport->symbolic_name; - struct Scsi_Host *shost = fc_vport->shost; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfa_lport_cfg_s port_cfg; - struct bfad_vport_s *vp; - int status = 0, rc; - unsigned long flags; - - memset(&port_cfg, 0, sizeof(port_cfg)); - u64_to_wwn(fc_vport->node_name, (u8 *)&port_cfg.nwwn); - u64_to_wwn(fc_vport->port_name, (u8 *)&port_cfg.pwwn); - if (strlen(vname) > 0) - strcpy((char *)&port_cfg.sym_name, vname); - port_cfg.roles = BFA_LPORT_ROLE_FCP_IM; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - list_for_each_entry(vp, &bfad->pbc_vport_list, list_entry) { - if (port_cfg.pwwn == - vp->fcs_vport.lport.port_cfg.pwwn) { - port_cfg.preboot_vp = - vp->fcs_vport.lport.port_cfg.preboot_vp; - break; - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - rc = bfad_vport_create(bfad, 0, &port_cfg, &fc_vport->dev); - if (rc == BFA_STATUS_OK) { - struct bfad_vport_s *vport; - struct bfa_fcs_vport_s *fcs_vport; - struct Scsi_Host *vshost; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, - port_cfg.pwwn); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (fcs_vport == NULL) - return VPCERR_BAD_WWN; - - fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE); - if (disable) { - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcs_vport_stop(fcs_vport); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - fc_vport_set_state(fc_vport, FC_VPORT_DISABLED); - } - - vport = fcs_vport->vport_drv; - vshost = vport->drv_port.im_port->shost; - fc_host_node_name(vshost) = wwn_to_u64((u8 *)&port_cfg.nwwn); - fc_host_port_name(vshost) = wwn_to_u64((u8 *)&port_cfg.pwwn); - fc_vport->dd_data = vport; - vport->drv_port.im_port->fc_vport = fc_vport; - } else if (rc == BFA_STATUS_INVALID_WWN) - return VPCERR_BAD_WWN; - else if (rc == BFA_STATUS_VPORT_EXISTS) - return VPCERR_BAD_WWN; - else if (rc == BFA_STATUS_VPORT_MAX) - return VPCERR_NO_FABRIC_SUPP; - else if (rc == BFA_STATUS_VPORT_WWN_BP) - return VPCERR_BAD_WWN; - else - return FC_VPORT_FAILED; - - return status; -} - -int -bfad_im_issue_fc_host_lip(struct Scsi_Host *shost) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfad_hal_comp fcomp; - unsigned long flags; - uint32_t status; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - status = bfa_port_disable(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (status != BFA_STATUS_OK) - return -EIO; - - wait_for_completion(&fcomp.comp); - if (fcomp.status != BFA_STATUS_OK) - return -EIO; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - status = bfa_port_enable(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (status != BFA_STATUS_OK) - return -EIO; - - wait_for_completion(&fcomp.comp); - if (fcomp.status != BFA_STATUS_OK) - return -EIO; - - return 0; -} - -static int -bfad_im_vport_delete(struct fc_vport *fc_vport) -{ - struct bfad_vport_s *vport = (struct bfad_vport_s *)fc_vport->dd_data; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) vport->drv_port.im_port; - struct bfad_s *bfad = im_port->bfad; - struct bfad_port_s *port; - struct bfa_fcs_vport_s *fcs_vport; - struct Scsi_Host *vshost; - wwn_t pwwn; - int rc; - unsigned long flags; - struct completion fcomp; - - if (im_port->flags & BFAD_PORT_DELETE) { - bfad_scsi_host_free(bfad, im_port); - list_del(&vport->list_entry); - return 0; - } - - port = im_port->port; - - vshost = vport->drv_port.im_port->shost; - u64_to_wwn(fc_host_port_name(vshost), (u8 *)&pwwn); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (fcs_vport == NULL) - return VPCERR_BAD_WWN; - - vport->drv_port.flags |= BFAD_PORT_DELETE; - - vport->comp_del = &fcomp; - init_completion(vport->comp_del); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - rc = bfa_fcs_vport_delete(&vport->fcs_vport); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (rc == BFA_STATUS_PBC) { - vport->drv_port.flags &= ~BFAD_PORT_DELETE; - vport->comp_del = NULL; - return -1; - } - - wait_for_completion(vport->comp_del); - - bfad_scsi_host_free(bfad, im_port); - list_del(&vport->list_entry); - kfree(vport); - - return 0; -} - -static int -bfad_im_vport_disable(struct fc_vport *fc_vport, bool disable) -{ - struct bfad_vport_s *vport; - struct bfad_s *bfad; - struct bfa_fcs_vport_s *fcs_vport; - struct Scsi_Host *vshost; - wwn_t pwwn; - unsigned long flags; - - vport = (struct bfad_vport_s *)fc_vport->dd_data; - bfad = vport->drv_port.bfad; - vshost = vport->drv_port.im_port->shost; - u64_to_wwn(fc_host_port_name(vshost), (u8 *)&pwwn); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, 0, pwwn); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (fcs_vport == NULL) - return VPCERR_BAD_WWN; - - if (disable) { - bfa_fcs_vport_stop(fcs_vport); - fc_vport_set_state(fc_vport, FC_VPORT_DISABLED); - } else { - bfa_fcs_vport_start(fcs_vport); - fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE); - } - - return 0; -} - -struct fc_function_template bfad_im_fc_function_template = { - - /* Target dynamic attributes */ - .get_starget_port_id = bfad_im_get_starget_port_id, - .show_starget_port_id = 1, - .get_starget_node_name = bfad_im_get_starget_node_name, - .show_starget_node_name = 1, - .get_starget_port_name = bfad_im_get_starget_port_name, - .show_starget_port_name = 1, - - /* Host dynamic attribute */ - .get_host_port_id = bfad_im_get_host_port_id, - .show_host_port_id = 1, - - /* Host fixed attributes */ - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_supported_speeds = 1, - .show_host_maxframe_size = 1, - - /* More host dynamic attributes */ - .show_host_port_type = 1, - .get_host_port_type = bfad_im_get_host_port_type, - .show_host_port_state = 1, - .get_host_port_state = bfad_im_get_host_port_state, - .show_host_active_fc4s = 1, - .get_host_active_fc4s = bfad_im_get_host_active_fc4s, - .show_host_speed = 1, - .get_host_speed = bfad_im_get_host_speed, - .show_host_fabric_name = 1, - .get_host_fabric_name = bfad_im_get_host_fabric_name, - - .show_host_symbolic_name = 1, - - /* Statistics */ - .get_fc_host_stats = bfad_im_get_stats, - .reset_fc_host_stats = bfad_im_reset_stats, - - /* Allocation length for host specific data */ - .dd_fcrport_size = sizeof(struct bfad_itnim_data_s *), - - /* Remote port fixed attributes */ - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - .show_rport_dev_loss_tmo = 1, - .get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo, - .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo, - .issue_fc_host_lip = bfad_im_issue_fc_host_lip, - .vport_create = bfad_im_vport_create, - .vport_delete = bfad_im_vport_delete, - .vport_disable = bfad_im_vport_disable, - .bsg_request = bfad_im_bsg_request, - .bsg_timeout = bfad_im_bsg_timeout, -}; - -struct fc_function_template bfad_im_vport_fc_function_template = { - - /* Target dynamic attributes */ - .get_starget_port_id = bfad_im_get_starget_port_id, - .show_starget_port_id = 1, - .get_starget_node_name = bfad_im_get_starget_node_name, - .show_starget_node_name = 1, - .get_starget_port_name = bfad_im_get_starget_port_name, - .show_starget_port_name = 1, - - /* Host dynamic attribute */ - .get_host_port_id = bfad_im_get_host_port_id, - .show_host_port_id = 1, - - /* Host fixed attributes */ - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_supported_speeds = 1, - .show_host_maxframe_size = 1, - - /* More host dynamic attributes */ - .show_host_port_type = 1, - .get_host_port_type = bfad_im_get_host_port_type, - .show_host_port_state = 1, - .get_host_port_state = bfad_im_get_host_port_state, - .show_host_active_fc4s = 1, - .get_host_active_fc4s = bfad_im_get_host_active_fc4s, - .show_host_speed = 1, - .get_host_speed = bfad_im_get_host_speed, - .show_host_fabric_name = 1, - .get_host_fabric_name = bfad_im_get_host_fabric_name, - - .show_host_symbolic_name = 1, - - /* Statistics */ - .get_fc_host_stats = bfad_im_get_stats, - .reset_fc_host_stats = bfad_im_reset_stats, - - /* Allocation length for host specific data */ - .dd_fcrport_size = sizeof(struct bfad_itnim_data_s *), - - /* Remote port fixed attributes */ - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - .show_rport_dev_loss_tmo = 1, - .get_rport_dev_loss_tmo = bfad_im_get_rport_loss_tmo, - .set_rport_dev_loss_tmo = bfad_im_set_rport_loss_tmo, -}; - -/* - * Scsi_Host_attrs SCSI host attributes - */ -static ssize_t -bfad_im_serial_num_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; - - bfa_get_adapter_serial_num(&bfad->bfa, serial_num); - return snprintf(buf, PAGE_SIZE, "%s\n", serial_num); -} - -static ssize_t -bfad_im_model_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - - bfa_get_adapter_model(&bfad->bfa, model); - return snprintf(buf, PAGE_SIZE, "%s\n", model); -} - -static ssize_t -bfad_im_model_desc_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - char model_descr[BFA_ADAPTER_MODEL_DESCR_LEN]; - int nports = 0; - - bfa_get_adapter_model(&bfad->bfa, model); - nports = bfa_get_nports(&bfad->bfa); - if (!strcmp(model, "Brocade-425")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 4Gbps PCIe dual port FC HBA"); - else if (!strcmp(model, "Brocade-825")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps PCIe dual port FC HBA"); - else if (!strcmp(model, "Brocade-42B")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 4Gbps PCIe dual port FC HBA for HP"); - else if (!strcmp(model, "Brocade-82B")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps PCIe dual port FC HBA for HP"); - else if (!strcmp(model, "Brocade-1010")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps single port CNA"); - else if (!strcmp(model, "Brocade-1020")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps dual port CNA"); - else if (!strcmp(model, "Brocade-1007")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps CNA for IBM Blade Center"); - else if (!strcmp(model, "Brocade-415")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 4Gbps PCIe single port FC HBA"); - else if (!strcmp(model, "Brocade-815")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps PCIe single port FC HBA"); - else if (!strcmp(model, "Brocade-41B")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 4Gbps PCIe single port FC HBA for HP"); - else if (!strcmp(model, "Brocade-81B")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps PCIe single port FC HBA for HP"); - else if (!strcmp(model, "Brocade-804")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 8Gbps FC HBA for HP Bladesystem C-class"); - else if (!strcmp(model, "Brocade-902") || - !strcmp(model, "Brocade-1741")) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps CNA for Dell M-Series Blade Servers"); - else if (strstr(model, "Brocade-1560")) { - if (nports == 1) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe single port FC HBA"); - else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe dual port FC HBA"); - } else if (strstr(model, "Brocade-1710")) { - if (nports == 1) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps single port CNA"); - else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps dual port CNA"); - } else if (strstr(model, "Brocade-1860")) { - if (nports == 1 && bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps single port CNA"); - else if (nports == 1 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe single port FC HBA"); - else if (nports == 2 && bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 10Gbps dual port CNA"); - else if (nports == 2 && !bfa_ioc_is_cna(&bfad->bfa.ioc)) - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Brocade 16Gbps PCIe dual port FC HBA"); - } else - snprintf(model_descr, BFA_ADAPTER_MODEL_DESCR_LEN, - "Invalid Model"); - - return snprintf(buf, PAGE_SIZE, "%s\n", model_descr); -} - -static ssize_t -bfad_im_node_name_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_port_s *port = im_port->port; - u64 nwwn; - - nwwn = bfa_fcs_lport_get_nwwn(port->fcs_port); - return snprintf(buf, PAGE_SIZE, "0x%llx\n", cpu_to_be64(nwwn)); -} - -static ssize_t -bfad_im_symbolic_name_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfa_lport_attr_s port_attr; - char symname[BFA_SYMNAME_MAXLEN]; - - bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr); - strncpy(symname, port_attr.port_cfg.sym_name.symname, - BFA_SYMNAME_MAXLEN); - return snprintf(buf, PAGE_SIZE, "%s\n", symname); -} - -static ssize_t -bfad_im_hw_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - char hw_ver[BFA_VERSION_LEN]; - - bfa_get_pci_chip_rev(&bfad->bfa, hw_ver); - return snprintf(buf, PAGE_SIZE, "%s\n", hw_ver); -} - -static ssize_t -bfad_im_drv_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", BFAD_DRIVER_VERSION); -} - -static ssize_t -bfad_im_optionrom_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - char optrom_ver[BFA_VERSION_LEN]; - - bfa_get_adapter_optrom_ver(&bfad->bfa, optrom_ver); - return snprintf(buf, PAGE_SIZE, "%s\n", optrom_ver); -} - -static ssize_t -bfad_im_fw_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - char fw_ver[BFA_VERSION_LEN]; - - bfa_get_adapter_fw_ver(&bfad->bfa, fw_ver); - return snprintf(buf, PAGE_SIZE, "%s\n", fw_ver); -} - -static ssize_t -bfad_im_num_of_ports_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - - return snprintf(buf, PAGE_SIZE, "%d\n", - bfa_get_nports(&bfad->bfa)); -} - -static ssize_t -bfad_im_drv_name_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", BFAD_DRIVER_NAME); -} - -static ssize_t -bfad_im_num_of_discovered_ports_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_port_s *port = im_port->port; - struct bfad_s *bfad = im_port->bfad; - int nrports = 2048; - wwn_t *rports = NULL; - unsigned long flags; - - rports = kzalloc(sizeof(wwn_t) * nrports , GFP_ATOMIC); - if (rports == NULL) - return snprintf(buf, PAGE_SIZE, "Failed\n"); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcs_lport_get_rports(port->fcs_port, rports, &nrports); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - kfree(rports); - - return snprintf(buf, PAGE_SIZE, "%d\n", nrports); -} - -static DEVICE_ATTR(serial_number, S_IRUGO, - bfad_im_serial_num_show, NULL); -static DEVICE_ATTR(model, S_IRUGO, bfad_im_model_show, NULL); -static DEVICE_ATTR(model_description, S_IRUGO, - bfad_im_model_desc_show, NULL); -static DEVICE_ATTR(node_name, S_IRUGO, bfad_im_node_name_show, NULL); -static DEVICE_ATTR(symbolic_name, S_IRUGO, - bfad_im_symbolic_name_show, NULL); -static DEVICE_ATTR(hardware_version, S_IRUGO, - bfad_im_hw_version_show, NULL); -static DEVICE_ATTR(driver_version, S_IRUGO, - bfad_im_drv_version_show, NULL); -static DEVICE_ATTR(option_rom_version, S_IRUGO, - bfad_im_optionrom_version_show, NULL); -static DEVICE_ATTR(firmware_version, S_IRUGO, - bfad_im_fw_version_show, NULL); -static DEVICE_ATTR(number_of_ports, S_IRUGO, - bfad_im_num_of_ports_show, NULL); -static DEVICE_ATTR(driver_name, S_IRUGO, bfad_im_drv_name_show, NULL); -static DEVICE_ATTR(number_of_discovered_ports, S_IRUGO, - bfad_im_num_of_discovered_ports_show, NULL); - -struct device_attribute *bfad_im_host_attrs[] = { - &dev_attr_serial_number, - &dev_attr_model, - &dev_attr_model_description, - &dev_attr_node_name, - &dev_attr_symbolic_name, - &dev_attr_hardware_version, - &dev_attr_driver_version, - &dev_attr_option_rom_version, - &dev_attr_firmware_version, - &dev_attr_number_of_ports, - &dev_attr_driver_name, - &dev_attr_number_of_discovered_ports, - NULL, -}; - -struct device_attribute *bfad_im_vport_attrs[] = { - &dev_attr_serial_number, - &dev_attr_model, - &dev_attr_model_description, - &dev_attr_node_name, - &dev_attr_symbolic_name, - &dev_attr_hardware_version, - &dev_attr_driver_version, - &dev_attr_option_rom_version, - &dev_attr_firmware_version, - &dev_attr_number_of_ports, - &dev_attr_driver_name, - &dev_attr_number_of_discovered_ports, - NULL, -}; - - diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.c deleted file mode 100644 index e1f4b10d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.c +++ /dev/null @@ -1,3216 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfad_bsg.h" - -BFA_TRC_FILE(LDRV, BSG); - -int -bfad_iocmd_ioc_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - /* If IOC is not in disabled state - return */ - if (!bfa_ioc_is_disabled(&bfad->bfa.ioc)) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_IOC_FAILURE; - return rc; - } - - init_completion(&bfad->enable_comp); - bfa_iocfc_enable(&bfad->bfa); - iocmd->status = BFA_STATUS_OK; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_for_completion(&bfad->enable_comp); - - return rc; -} - -int -bfad_iocmd_ioc_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (bfad->disable_active) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return -EBUSY; - } - - bfad->disable_active = BFA_TRUE; - init_completion(&bfad->disable_comp); - bfa_iocfc_disable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - wait_for_completion(&bfad->disable_comp); - bfad->disable_active = BFA_FALSE; - iocmd->status = BFA_STATUS_OK; - - return rc; -} - -static int -bfad_iocmd_ioc_get_info(struct bfad_s *bfad, void *cmd) -{ - int i; - struct bfa_bsg_ioc_info_s *iocmd = (struct bfa_bsg_ioc_info_s *)cmd; - struct bfad_im_port_s *im_port; - struct bfa_port_attr_s pattr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcport_get_attr(&bfad->bfa, &pattr); - iocmd->nwwn = pattr.nwwn; - iocmd->pwwn = pattr.pwwn; - iocmd->ioc_type = bfa_get_type(&bfad->bfa); - iocmd->mac = bfa_get_mac(&bfad->bfa); - iocmd->factory_mac = bfa_get_mfg_mac(&bfad->bfa); - bfa_get_adapter_serial_num(&bfad->bfa, iocmd->serialnum); - iocmd->factorynwwn = pattr.factorynwwn; - iocmd->factorypwwn = pattr.factorypwwn; - iocmd->bfad_num = bfad->inst_no; - im_port = bfad->pport.im_port; - iocmd->host = im_port->shost->host_no; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - strcpy(iocmd->name, bfad->adapter_name); - strcpy(iocmd->port_name, bfad->port_name); - strcpy(iocmd->hwpath, bfad->pci_name); - - /* set adapter hw path */ - strcpy(iocmd->adapter_hwpath, bfad->pci_name); - i = strlen(iocmd->adapter_hwpath) - 1; - while (iocmd->adapter_hwpath[i] != '.') - i--; - iocmd->adapter_hwpath[i] = '\0'; - iocmd->status = BFA_STATUS_OK; - return 0; -} - -static int -bfad_iocmd_ioc_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_ioc_attr_s *iocmd = (struct bfa_bsg_ioc_attr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_ioc_get_attr(&bfad->bfa.ioc, &iocmd->ioc_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* fill in driver attr info */ - strcpy(iocmd->ioc_attr.driver_attr.driver, BFAD_DRIVER_NAME); - strncpy(iocmd->ioc_attr.driver_attr.driver_ver, - BFAD_DRIVER_VERSION, BFA_VERSION_LEN); - strcpy(iocmd->ioc_attr.driver_attr.fw_ver, - iocmd->ioc_attr.adapter_attr.fw_ver); - strcpy(iocmd->ioc_attr.driver_attr.bios_ver, - iocmd->ioc_attr.adapter_attr.optrom_ver); - - /* copy chip rev info first otherwise it will be overwritten */ - memcpy(bfad->pci_attr.chip_rev, iocmd->ioc_attr.pci_attr.chip_rev, - sizeof(bfad->pci_attr.chip_rev)); - memcpy(&iocmd->ioc_attr.pci_attr, &bfad->pci_attr, - sizeof(struct bfa_ioc_pci_attr_s)); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_ioc_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_ioc_stats_s *iocmd = (struct bfa_bsg_ioc_stats_s *)cmd; - - bfa_ioc_get_stats(&bfad->bfa, &iocmd->ioc_stats); - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_ioc_get_fwstats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_ioc_fwstats_s *iocmd = - (struct bfa_bsg_ioc_fwstats_s *)cmd; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_ioc_fwstats_s), - sizeof(struct bfa_fw_stats_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - goto out; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_ioc_fwstats_s); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ioc_fw_stats_get(&bfad->bfa.ioc, iocmd_bufptr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } -out: - bfa_trc(bfad, 0x6666); - return 0; -} - -int -bfad_iocmd_ioc_reset_stats(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - if (v_cmd == IOCMD_IOC_RESET_STATS) { - bfa_ioc_clear_stats(&bfad->bfa); - iocmd->status = BFA_STATUS_OK; - } else if (v_cmd == IOCMD_IOC_RESET_FWSTATS) { - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ioc_fw_stats_clear(&bfad->bfa.ioc); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } - - return 0; -} - -int -bfad_iocmd_ioc_set_name(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) -{ - struct bfa_bsg_ioc_name_s *iocmd = (struct bfa_bsg_ioc_name_s *) cmd; - - if (v_cmd == IOCMD_IOC_SET_ADAPTER_NAME) - strcpy(bfad->adapter_name, iocmd->name); - else if (v_cmd == IOCMD_IOC_SET_PORT_NAME) - strcpy(bfad->port_name, iocmd->name); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_iocfc_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_iocfc_attr_s *iocmd = (struct bfa_bsg_iocfc_attr_s *)cmd; - - iocmd->status = BFA_STATUS_OK; - bfa_iocfc_get_attr(&bfad->bfa, &iocmd->iocfc_attr); - - return 0; -} - -int -bfad_iocmd_iocfc_set_intr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_iocfc_intr_s *iocmd = (struct bfa_bsg_iocfc_intr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_iocfc_israttr_set(&bfad->bfa, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_port_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_enable(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - return 0; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - return 0; -} - -int -bfad_iocmd_port_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_disable(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - return 0; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - return 0; -} - -static int -bfad_iocmd_port_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_port_attr_s *iocmd = (struct bfa_bsg_port_attr_s *)cmd; - struct bfa_lport_attr_s port_attr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcport_get_attr(&bfad->bfa, &iocmd->attr); - bfa_fcs_lport_get_attr(&bfad->bfa_fcs.fabric.bport, &port_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->attr.topology != BFA_PORT_TOPOLOGY_NONE) - iocmd->attr.pid = port_attr.pid; - else - iocmd->attr.pid = 0; - - iocmd->attr.port_type = port_attr.port_type; - iocmd->attr.loopback = port_attr.loopback; - iocmd->attr.authfail = port_attr.authfail; - strncpy(iocmd->attr.port_symname.symname, - port_attr.port_cfg.sym_name.symname, - sizeof(port_attr.port_cfg.sym_name.symname)); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_port_get_stats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_port_stats_s *iocmd = (struct bfa_bsg_port_stats_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_port_stats_s), - sizeof(union bfa_port_stats_u)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_port_stats_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_get_stats(&bfad->bfa.modules.port, - iocmd_bufptr, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_port_reset_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_port_clear_stats(&bfad->bfa.modules.port, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - return 0; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - return 0; -} - -int -bfad_iocmd_set_port_cfg(struct bfad_s *bfad, void *iocmd, unsigned int v_cmd) -{ - struct bfa_bsg_port_cfg_s *cmd = (struct bfa_bsg_port_cfg_s *)iocmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (v_cmd == IOCMD_PORT_CFG_TOPO) - cmd->status = bfa_fcport_cfg_topology(&bfad->bfa, cmd->param); - else if (v_cmd == IOCMD_PORT_CFG_SPEED) - cmd->status = bfa_fcport_cfg_speed(&bfad->bfa, cmd->param); - else if (v_cmd == IOCMD_PORT_CFG_ALPA) - cmd->status = bfa_fcport_cfg_hardalpa(&bfad->bfa, cmd->param); - else if (v_cmd == IOCMD_PORT_CLR_ALPA) - cmd->status = bfa_fcport_clr_hardalpa(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_port_cfg_maxfrsize(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_port_cfg_maxfrsize_s *iocmd = - (struct bfa_bsg_port_cfg_maxfrsize_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_cfg_maxfrsize(&bfad->bfa, iocmd->maxfrsize); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_port_cfg_bbsc(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (bfa_ioc_get_type(&bfad->bfa.ioc) == BFA_IOC_TYPE_FC) { - if (v_cmd == IOCMD_PORT_BBSC_ENABLE) - fcport->cfg.bb_scn_state = BFA_TRUE; - else if (v_cmd == IOCMD_PORT_BBSC_DISABLE) - fcport->cfg.bb_scn_state = BFA_FALSE; - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -static int -bfad_iocmd_lport_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_attr_s *iocmd = (struct bfa_bsg_lport_attr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_attr(fcs_port, &iocmd->port_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_stats_s *iocmd = - (struct bfa_bsg_lport_stats_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_stats(fcs_port, &iocmd->port_stats); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_reset_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_reset_stats_s *iocmd = - (struct bfa_bsg_reset_stats_s *)cmd; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa); - struct list_head *qe, *qen; - struct bfa_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->vpwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_clear_stats(fcs_port); - /* clear IO stats from all active itnims */ - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - if (itnim->rport->rport_info.lp_tag != fcs_port->lp_tag) - continue; - bfa_itnim_clear_stats(itnim); - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_iostats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_lport_s *fcs_port; - struct bfa_bsg_lport_iostats_s *iocmd = - (struct bfa_bsg_lport_iostats_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcpim_port_iostats(&bfad->bfa, &iocmd->iostats, - fcs_port->lp_tag); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_lport_get_rports(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_lport_get_rports_s *iocmd = - (struct bfa_bsg_lport_get_rports_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - unsigned long flags; - void *iocmd_bufptr; - - if (iocmd->nrports == 0) - return -EINVAL; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_lport_get_rports_s), - sizeof(wwn_t) * iocmd->nrports) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + - sizeof(struct bfa_bsg_lport_get_rports_s); - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, 0); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - bfa_fcs_lport_get_rports(fcs_port, (wwn_t *)iocmd_bufptr, - &iocmd->nrports); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_rport_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_attr_s *iocmd = (struct bfa_bsg_rport_attr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn); - if (fcs_rport == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - bfa_fcs_rport_get_attr(fcs_rport, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -static int -bfad_iocmd_rport_get_addr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_scsi_addr_s *iocmd = - (struct bfa_bsg_rport_scsi_addr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *fcs_itnim; - struct bfad_itnim_s *drv_itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (fcs_itnim == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - drv_itnim = fcs_itnim->itnim_drv; - - if (drv_itnim && drv_itnim->im_port) - iocmd->host = drv_itnim->im_port->shost->host_no; - else { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - iocmd->target = drv_itnim->scsi_tgt_id; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->bus = 0; - iocmd->lun = 0; - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_rport_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_stats_s *iocmd = - (struct bfa_bsg_rport_stats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn); - if (fcs_rport == NULL) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - memcpy((void *)&iocmd->stats, (void *)&fcs_rport->stats, - sizeof(struct bfa_rport_stats_s)); - memcpy((void *)&iocmd->stats.hal_stats, - (void *)&(bfa_fcs_rport_get_halrport(fcs_rport)->stats), - sizeof(struct bfa_rport_hal_stats_s)); - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_rport_clr_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_reset_stats_s *iocmd = - (struct bfa_bsg_rport_reset_stats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - struct bfa_rport_s *rport; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn); - if (fcs_rport == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - memset((char *)&fcs_rport->stats, 0, sizeof(struct bfa_rport_stats_s)); - rport = bfa_fcs_rport_get_halrport(fcs_rport); - memset(&rport->stats, 0, sizeof(rport->stats)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_rport_set_speed(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_set_speed_s *iocmd = - (struct bfa_bsg_rport_set_speed_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (fcs_port == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - goto out; - } - - fcs_rport = bfa_fcs_rport_lookup(fcs_port, iocmd->rpwwn); - if (fcs_rport == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - goto out; - } - - fcs_rport->rpf.assigned_speed = iocmd->speed; - /* Set this speed in f/w only if the RPSC speed is not available */ - if (fcs_rport->rpf.rpsc_speed == BFA_PORT_SPEED_UNKNOWN) - bfa_rport_speed(fcs_rport->bfa_rport, iocmd->speed); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_vport_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_vport_s *fcs_vport; - struct bfa_bsg_vport_attr_s *iocmd = (struct bfa_bsg_vport_attr_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->vpwwn); - if (fcs_vport == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_VWWN; - goto out; - } - - bfa_fcs_vport_get_attr(fcs_vport, &iocmd->vport_attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_vport_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_vport_s *fcs_vport; - struct bfa_bsg_vport_stats_s *iocmd = - (struct bfa_bsg_vport_stats_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->vpwwn); - if (fcs_vport == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_VWWN; - goto out; - } - - memcpy((void *)&iocmd->vport_stats, (void *)&fcs_vport->vport_stats, - sizeof(struct bfa_vport_stats_s)); - memcpy((void *)&iocmd->vport_stats.port_stats, - (void *)&fcs_vport->lport.stats, - sizeof(struct bfa_lport_stats_s)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_vport_clr_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_fcs_vport_s *fcs_vport; - struct bfa_bsg_reset_stats_s *iocmd = - (struct bfa_bsg_reset_stats_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vport = bfa_fcs_vport_lookup(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->vpwwn); - if (fcs_vport == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_VWWN; - goto out; - } - - memset(&fcs_vport->vport_stats, 0, sizeof(struct bfa_vport_stats_s)); - memset(&fcs_vport->lport.stats, 0, sizeof(struct bfa_lport_stats_s)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -static int -bfad_iocmd_fabric_get_lports(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_fabric_get_lports_s *iocmd = - (struct bfa_bsg_fabric_get_lports_s *)cmd; - bfa_fcs_vf_t *fcs_vf; - uint32_t nports = iocmd->nports; - unsigned long flags; - void *iocmd_bufptr; - - if (nports == 0) { - iocmd->status = BFA_STATUS_EINVAL; - goto out; - } - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_fabric_get_lports_s), - sizeof(wwn_t[iocmd->nports])) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - goto out; - } - - iocmd_bufptr = (char *)iocmd + - sizeof(struct bfa_bsg_fabric_get_lports_s); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id); - if (fcs_vf == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_VFID; - goto out; - } - bfa_fcs_vf_get_ports(fcs_vf, (wwn_t *)iocmd_bufptr, &nports); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->nports = nports; - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_ratelim(struct bfad_s *bfad, unsigned int cmd, void *pcmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - if (cmd == IOCMD_RATELIM_ENABLE) - fcport->cfg.ratelimit = BFA_TRUE; - else if (cmd == IOCMD_RATELIM_DISABLE) - fcport->cfg.ratelimit = BFA_FALSE; - - if (fcport->cfg.trl_def_speed == BFA_PORT_SPEED_UNKNOWN) - fcport->cfg.trl_def_speed = BFA_PORT_SPEED_1GBPS; - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; - - return 0; -} - -int -bfad_iocmd_ratelim_speed(struct bfad_s *bfad, unsigned int cmd, void *pcmd) -{ - struct bfa_bsg_trl_speed_s *iocmd = (struct bfa_bsg_trl_speed_s *)pcmd; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - /* Auto and speeds greater than the supported speed, are invalid */ - if ((iocmd->speed == BFA_PORT_SPEED_AUTO) || - (iocmd->speed > fcport->speed_sup)) { - iocmd->status = BFA_STATUS_UNSUPP_SPEED; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; - } - - fcport->cfg.trl_def_speed = iocmd->speed; - iocmd->status = BFA_STATUS_OK; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_cfg_fcpim(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_s *iocmd = (struct bfa_bsg_fcpim_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfa_fcpim_path_tov_set(&bfad->bfa, iocmd->param); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_fcpim_get_modstats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_modstats_s *iocmd = - (struct bfa_bsg_fcpim_modstats_s *)cmd; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa); - struct list_head *qe, *qen; - struct bfa_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - /* accumulate IO stats from itnim */ - memset((void *)&iocmd->modstats, 0, sizeof(struct bfa_itnim_iostats_s)); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - bfa_fcpim_add_stats(&iocmd->modstats, &(itnim->stats)); - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_fcpim_clr_modstats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_modstatsclr_s *iocmd = - (struct bfa_bsg_fcpim_modstatsclr_s *)cmd; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa); - struct list_head *qe, *qen; - struct bfa_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - list_for_each_safe(qe, qen, &fcpim->itnim_q) { - itnim = (struct bfa_itnim_s *) qe; - bfa_itnim_clear_stats(itnim); - } - memset(&fcpim->del_itn_stats, 0, - sizeof(struct bfa_fcpim_del_itn_stats_s)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_fcpim_get_del_itn_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_del_itn_stats_s *iocmd = - (struct bfa_bsg_fcpim_del_itn_stats_s *)cmd; - struct bfa_fcpim_s *fcpim = BFA_FCPIM(&bfad->bfa); - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - memcpy((void *)&iocmd->modstats, (void *)&fcpim->del_itn_stats, - sizeof(struct bfa_fcpim_del_itn_stats_s)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -static int -bfad_iocmd_itnim_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_attr_s *iocmd = (struct bfa_bsg_itnim_attr_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - else - iocmd->status = bfa_fcs_itnim_attr_get(fcs_port, - iocmd->rpwwn, &iocmd->attr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -static int -bfad_iocmd_itnim_get_iostats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_iostats_s *iocmd = - (struct bfa_bsg_itnim_iostats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) { - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - bfa_trc(bfad, 0); - } else { - itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (itnim == NULL) - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - else { - iocmd->status = BFA_STATUS_OK; - memcpy((void *)&iocmd->iostats, (void *) - &(bfa_fcs_itnim_get_halitn(itnim)->stats), - sizeof(struct bfa_itnim_iostats_s)); - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -static int -bfad_iocmd_itnim_reset_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_rport_reset_stats_s *iocmd = - (struct bfa_bsg_rport_reset_stats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->pwwn); - if (!fcs_port) - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - else { - itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (itnim == NULL) - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - else { - iocmd->status = BFA_STATUS_OK; - bfa_fcs_itnim_stats_clear(fcs_port, iocmd->rpwwn); - bfa_itnim_clear_stats(bfa_fcs_itnim_get_halitn(itnim)); - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -static int -bfad_iocmd_itnim_get_itnstats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_itnstats_s *iocmd = - (struct bfa_bsg_itnim_itnstats_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) { - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - bfa_trc(bfad, 0); - } else { - itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (itnim == NULL) - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - else { - iocmd->status = BFA_STATUS_OK; - bfa_fcs_itnim_stats_get(fcs_port, iocmd->rpwwn, - &iocmd->itnstats); - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_fcport_enable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_enable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_fcport_disable(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_disable(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_ioc_get_pcifn_cfg(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_cfg_s *iocmd = (struct bfa_bsg_pcifn_cfg_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_query(&bfad->bfa.modules.ablk, - &iocmd->pcifn_cfg, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_create(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_create(&bfad->bfa.modules.ablk, - &iocmd->pcifn_id, iocmd->port, - iocmd->pcifn_class, iocmd->bandwidth, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_delete(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_delete(&bfad->bfa.modules.ablk, - iocmd->pcifn_id, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_pcifn_bw(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_pcifn_s *iocmd = (struct bfa_bsg_pcifn_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_pf_update(&bfad->bfa.modules.ablk, - iocmd->pcifn_id, iocmd->bandwidth, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - bfa_trc(bfad, iocmd->status); -out: - return 0; -} - -int -bfad_iocmd_adapter_cfg_mode(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_adapter_cfg_mode_s *iocmd = - (struct bfa_bsg_adapter_cfg_mode_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags = 0; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_adapter_config(&bfad->bfa.modules.ablk, - iocmd->cfg.mode, iocmd->cfg.max_pf, - iocmd->cfg.max_vf, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_port_cfg_mode(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_port_cfg_mode_s *iocmd = - (struct bfa_bsg_port_cfg_mode_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags = 0; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_ablk_port_config(&bfad->bfa.modules.ablk, - iocmd->instance, iocmd->cfg.mode, - iocmd->cfg.max_pf, iocmd->cfg.max_vf, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_ablk_optrom(struct bfad_s *bfad, unsigned int cmd, void *pcmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (cmd == IOCMD_FLASH_ENABLE_OPTROM) - iocmd->status = bfa_ablk_optrom_en(&bfad->bfa.modules.ablk, - bfad_hcb_comp, &fcomp); - else - iocmd->status = bfa_ablk_optrom_dis(&bfad->bfa.modules.ablk, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_faa_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_faa_attr_s *iocmd = (struct bfa_bsg_faa_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - iocmd->status = BFA_STATUS_OK; - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_faa_query(&bfad->bfa, &iocmd->faa_attr, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (iocmd->status != BFA_STATUS_OK) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_cee_attr(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_cee_attr_s *iocmd = - (struct bfa_bsg_cee_attr_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp cee_comp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_cee_attr_s), - sizeof(struct bfa_cee_attr_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_cee_attr_s); - - cee_comp.status = 0; - init_completion(&cee_comp.comp); - mutex_lock(&bfad_mutex); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_get_attr(&bfad->bfa.modules.cee, iocmd_bufptr, - bfad_hcb_comp, &cee_comp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - mutex_unlock(&bfad_mutex); - bfa_trc(bfad, 0x5555); - goto out; - } - wait_for_completion(&cee_comp.comp); - mutex_unlock(&bfad_mutex); -out: - return 0; -} - -int -bfad_iocmd_cee_get_stats(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_cee_stats_s *iocmd = - (struct bfa_bsg_cee_stats_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp cee_comp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_cee_stats_s), - sizeof(struct bfa_cee_stats_s)) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_cee_stats_s); - - cee_comp.status = 0; - init_completion(&cee_comp.comp); - mutex_lock(&bfad_mutex); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_get_stats(&bfad->bfa.modules.cee, iocmd_bufptr, - bfad_hcb_comp, &cee_comp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - mutex_unlock(&bfad_mutex); - bfa_trc(bfad, 0x5555); - goto out; - } - wait_for_completion(&cee_comp.comp); - mutex_unlock(&bfad_mutex); -out: - return 0; -} - -int -bfad_iocmd_cee_reset_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_cee_reset_stats(&bfad->bfa.modules.cee, NULL, NULL); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - bfa_trc(bfad, 0x5555); - return 0; -} - -int -bfad_iocmd_sfp_media(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_media_s *iocmd = (struct bfa_bsg_sfp_media_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_media(BFA_SFP_MOD(&bfad->bfa), &iocmd->media, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_SFP_NOT_READY) - goto out; - - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_sfp_speed(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_speed_s *iocmd = (struct bfa_bsg_sfp_speed_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_speed(BFA_SFP_MOD(&bfad->bfa), iocmd->speed, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_SFP_NOT_READY) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_flash_attr_s *iocmd = - (struct bfa_bsg_flash_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_get_attr(BFA_FLASH(&bfad->bfa), &iocmd->attr, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_erase_part(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_erase_part(BFA_FLASH(&bfad->bfa), iocmd->type, - iocmd->instance, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_update_part(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp fcomp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_flash_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_flash_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa), - iocmd->type, iocmd->instance, iocmd_bufptr, - iocmd->bufsz, 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_flash_read_part(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_flash_s *iocmd = (struct bfa_bsg_flash_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_flash_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_flash_s); - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa), iocmd->type, - iocmd->instance, iocmd_bufptr, iocmd->bufsz, 0, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_temp(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_get_temp_s *iocmd = - (struct bfa_bsg_diag_get_temp_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_tsensor_query(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_memtest(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_memtest_s *iocmd = - (struct bfa_bsg_diag_memtest_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_memtest(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->memtest, iocmd->pat, - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_loopback(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_loopback_s *iocmd = - (struct bfa_bsg_diag_loopback_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_loopback(&bfad->bfa, iocmd->opmode, - iocmd->speed, iocmd->lpcnt, iocmd->pat, - &iocmd->result, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_fwping(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_fwping_s *iocmd = - (struct bfa_bsg_diag_fwping_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_fwping(BFA_DIAG_MOD(&bfad->bfa), iocmd->cnt, - iocmd->pattern, &iocmd->result, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - bfa_trc(bfad, 0x77771); - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_queuetest(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_qtest_s *iocmd = (struct bfa_bsg_diag_qtest_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_queuetest(&bfad->bfa, iocmd->force, - iocmd->queue, &iocmd->result, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_diag_sfp(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_sfp_show_s *iocmd = - (struct bfa_bsg_sfp_show_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_sfp_show(BFA_SFP_MOD(&bfad->bfa), &iocmd->sfp, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - bfa_trc(bfad, iocmd->status); -out: - return 0; -} - -int -bfad_iocmd_diag_led(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_led_s *iocmd = (struct bfa_bsg_diag_led_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_ledtest(BFA_DIAG_MOD(&bfad->bfa), - &iocmd->ledtest); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_diag_beacon_lport(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_beacon_s *iocmd = - (struct bfa_bsg_diag_beacon_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_diag_beacon_port(BFA_DIAG_MOD(&bfad->bfa), - iocmd->beacon, iocmd->link_e2e_beacon, - iocmd->second); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_diag_lb_stat(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_diag_lb_stat_s *iocmd = - (struct bfa_bsg_diag_lb_stat_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcdiag_lb_is_running(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfa_trc(bfad, iocmd->status); - - return 0; -} - -int -bfad_iocmd_phy_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_phy_attr_s *iocmd = - (struct bfa_bsg_phy_attr_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_get_attr(BFA_PHY(&bfad->bfa), iocmd->instance, - &iocmd->attr, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_phy_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_phy_stats_s *iocmd = - (struct bfa_bsg_phy_stats_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_get_stats(BFA_PHY(&bfad->bfa), iocmd->instance, - &iocmd->stats, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_phy_read(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_phy_s *iocmd = (struct bfa_bsg_phy_s *)cmd; - struct bfad_hal_comp fcomp; - void *iocmd_bufptr; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_phy_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_phy_s); - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_read(BFA_PHY(&bfad->bfa), - iocmd->instance, iocmd_bufptr, iocmd->bufsz, - 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; - if (iocmd->status != BFA_STATUS_OK) - goto out; -out: - return 0; -} - -int -bfad_iocmd_vhba_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_vhba_attr_s *iocmd = - (struct bfa_bsg_vhba_attr_s *)cmd; - struct bfa_vhba_attr_s *attr = &iocmd->attr; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - attr->pwwn = bfad->bfa.ioc.attr->pwwn; - attr->nwwn = bfad->bfa.ioc.attr->nwwn; - attr->plog_enabled = (bfa_boolean_t)bfad->bfa.plog->plog_enabled; - attr->io_profile = bfa_fcpim_get_io_profile(&bfad->bfa); - attr->path_tov = bfa_fcpim_path_tov_get(&bfad->bfa); - iocmd->status = BFA_STATUS_OK; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_phy_update(struct bfad_s *bfad, void *cmd, unsigned int payload_len) -{ - struct bfa_bsg_phy_s *iocmd = (struct bfa_bsg_phy_s *)cmd; - void *iocmd_bufptr; - struct bfad_hal_comp fcomp; - unsigned long flags; - - if (bfad_chk_iocmd_sz(payload_len, - sizeof(struct bfa_bsg_phy_s), - iocmd->bufsz) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_phy_s); - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_phy_update(BFA_PHY(&bfad->bfa), - iocmd->instance, iocmd_bufptr, iocmd->bufsz, - 0, bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_porglog_get(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_debug_s *iocmd = (struct bfa_bsg_debug_s *)cmd; - void *iocmd_bufptr; - - if (iocmd->bufsz < sizeof(struct bfa_plog_s)) { - bfa_trc(bfad, sizeof(struct bfa_plog_s)); - iocmd->status = BFA_STATUS_EINVAL; - goto out; - } - - iocmd->status = BFA_STATUS_OK; - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_debug_s); - memcpy(iocmd_bufptr, (u8 *) &bfad->plog_buf, sizeof(struct bfa_plog_s)); -out: - return 0; -} - -#define BFA_DEBUG_FW_CORE_CHUNK_SZ 0x4000U /* 16K chunks for FW dump */ -int -bfad_iocmd_debug_fw_core(struct bfad_s *bfad, void *cmd, - unsigned int payload_len) -{ - struct bfa_bsg_debug_s *iocmd = (struct bfa_bsg_debug_s *)cmd; - void *iocmd_bufptr; - unsigned long flags; - u32 offset; - - if (bfad_chk_iocmd_sz(payload_len, sizeof(struct bfa_bsg_debug_s), - BFA_DEBUG_FW_CORE_CHUNK_SZ) != BFA_STATUS_OK) { - iocmd->status = BFA_STATUS_VERSION_FAIL; - return 0; - } - - if (iocmd->bufsz < BFA_DEBUG_FW_CORE_CHUNK_SZ || - !IS_ALIGNED(iocmd->bufsz, sizeof(u16)) || - !IS_ALIGNED(iocmd->offset, sizeof(u32))) { - bfa_trc(bfad, BFA_DEBUG_FW_CORE_CHUNK_SZ); - iocmd->status = BFA_STATUS_EINVAL; - goto out; - } - - iocmd_bufptr = (char *)iocmd + sizeof(struct bfa_bsg_debug_s); - spin_lock_irqsave(&bfad->bfad_lock, flags); - offset = iocmd->offset; - iocmd->status = bfa_ioc_debug_fwcore(&bfad->bfa.ioc, iocmd_bufptr, - &offset, &iocmd->bufsz); - iocmd->offset = offset; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); -out: - return 0; -} - -int -bfad_iocmd_debug_ctl(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - unsigned long flags; - - if (v_cmd == IOCMD_DEBUG_FW_STATE_CLR) { - spin_lock_irqsave(&bfad->bfad_lock, flags); - bfad->bfa.ioc.dbg_fwsave_once = BFA_TRUE; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - } else if (v_cmd == IOCMD_DEBUG_PORTLOG_CLR) - bfad->plog_buf.head = bfad->plog_buf.tail = 0; - else if (v_cmd == IOCMD_DEBUG_START_DTRC) - bfa_trc_init(bfad->trcmod); - else if (v_cmd == IOCMD_DEBUG_STOP_DTRC) - bfa_trc_stop(bfad->trcmod); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_porglog_ctl(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_portlogctl_s *iocmd = (struct bfa_bsg_portlogctl_s *)cmd; - - if (iocmd->ctl == BFA_TRUE) - bfad->plog_buf.plog_enabled = 1; - else - bfad->plog_buf.plog_enabled = 0; - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_fcpim_cfg_profile(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) -{ - struct bfa_bsg_fcpim_profile_s *iocmd = - (struct bfa_bsg_fcpim_profile_s *)cmd; - struct timeval tv; - unsigned long flags; - - do_gettimeofday(&tv); - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (v_cmd == IOCMD_FCPIM_PROFILE_ON) - iocmd->status = bfa_fcpim_profile_on(&bfad->bfa, tv.tv_sec); - else if (v_cmd == IOCMD_FCPIM_PROFILE_OFF) - iocmd->status = bfa_fcpim_profile_off(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -static int -bfad_iocmd_itnim_get_ioprofile(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_itnim_ioprofile_s *iocmd = - (struct bfa_bsg_itnim_ioprofile_s *)cmd; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_itnim_s *itnim; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, - iocmd->vf_id, iocmd->lpwwn); - if (!fcs_port) - iocmd->status = BFA_STATUS_UNKNOWN_LWWN; - else { - itnim = bfa_fcs_itnim_lookup(fcs_port, iocmd->rpwwn); - if (itnim == NULL) - iocmd->status = BFA_STATUS_UNKNOWN_RWWN; - else - iocmd->status = bfa_itnim_get_ioprofile( - bfa_fcs_itnim_get_halitn(itnim), - &iocmd->ioprofile); - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_fcport_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcport_stats_s *iocmd = - (struct bfa_bsg_fcport_stats_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - struct bfa_cb_pending_q_s cb_qe; - - init_completion(&fcomp.comp); - bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, - &fcomp, &iocmd->stats); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_fcport_reset_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - struct bfa_cb_pending_q_s cb_qe; - - init_completion(&fcomp.comp); - bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, &fcomp, NULL); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_boot_cfg(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_boot_s *iocmd = (struct bfa_bsg_boot_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa), - BFA_FLASH_PART_BOOT, PCI_FUNC(bfad->pcidev->devfn), - &iocmd->cfg, sizeof(struct bfa_boot_cfg_s), 0, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_boot_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_boot_s *iocmd = (struct bfa_bsg_boot_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa), - BFA_FLASH_PART_BOOT, PCI_FUNC(bfad->pcidev->devfn), - &iocmd->cfg, sizeof(struct bfa_boot_cfg_s), 0, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_preboot_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_preboot_s *iocmd = (struct bfa_bsg_preboot_s *)cmd; - struct bfi_iocfc_cfgrsp_s *cfgrsp = bfad->bfa.iocfc.cfgrsp; - struct bfa_boot_pbc_s *pbcfg = &iocmd->cfg; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - pbcfg->enable = cfgrsp->pbc_cfg.boot_enabled; - pbcfg->nbluns = cfgrsp->pbc_cfg.nbluns; - pbcfg->speed = cfgrsp->pbc_cfg.port_speed; - memcpy(pbcfg->pblun, cfgrsp->pbc_cfg.blun, sizeof(pbcfg->pblun)); - iocmd->status = BFA_STATUS_OK; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; -} - -int -bfad_iocmd_ethboot_cfg(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_ethboot_s *iocmd = (struct bfa_bsg_ethboot_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_update_part(BFA_FLASH(&bfad->bfa), - BFA_FLASH_PART_PXECFG, - bfad->bfa.ioc.port_id, &iocmd->cfg, - sizeof(struct bfa_ethboot_cfg_s), 0, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_ethboot_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_ethboot_s *iocmd = (struct bfa_bsg_ethboot_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - - init_completion(&fcomp.comp); - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_flash_read_part(BFA_FLASH(&bfad->bfa), - BFA_FLASH_PART_PXECFG, - bfad->bfa.ioc.port_id, &iocmd->cfg, - sizeof(struct bfa_ethboot_cfg_s), 0, - bfad_hcb_comp, &fcomp); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) - goto out; - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_cfg_trunk(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - struct bfa_fcport_trunk_s *trunk = &fcport->trunk; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - if (v_cmd == IOCMD_TRUNK_ENABLE) { - trunk->attr.state = BFA_TRUNK_OFFLINE; - bfa_fcport_disable(&bfad->bfa); - fcport->cfg.trunked = BFA_TRUE; - } else if (v_cmd == IOCMD_TRUNK_DISABLE) { - trunk->attr.state = BFA_TRUNK_DISABLED; - bfa_fcport_disable(&bfad->bfa); - fcport->cfg.trunked = BFA_FALSE; - } - - if (!bfa_fcport_is_disabled(&bfad->bfa)) - bfa_fcport_enable(&bfad->bfa); - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_trunk_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_trunk_attr_s *iocmd = (struct bfa_bsg_trunk_attr_s *)cmd; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - struct bfa_fcport_trunk_s *trunk = &fcport->trunk; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - memcpy((void *)&iocmd->attr, (void *)&trunk->attr, - sizeof(struct bfa_trunk_attr_s)); - iocmd->attr.port_id = bfa_lps_get_base_pid(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_qos(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (bfa_ioc_get_type(&bfad->bfa.ioc) == BFA_IOC_TYPE_FC) { - if (v_cmd == IOCMD_QOS_ENABLE) - fcport->cfg.qos_enabled = BFA_TRUE; - else if (v_cmd == IOCMD_QOS_DISABLE) - fcport->cfg.qos_enabled = BFA_FALSE; - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_qos_get_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_qos_attr_s *iocmd = (struct bfa_bsg_qos_attr_s *)cmd; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->attr.state = fcport->qos_attr.state; - iocmd->attr.total_bb_cr = be32_to_cpu(fcport->qos_attr.total_bb_cr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_qos_get_vc_attr(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_qos_vc_attr_s *iocmd = - (struct bfa_bsg_qos_vc_attr_s *)cmd; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - struct bfa_qos_vc_attr_s *bfa_vc_attr = &fcport->qos_vc_attr; - unsigned long flags; - u32 i = 0; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->attr.total_vc_count = be16_to_cpu(bfa_vc_attr->total_vc_count); - iocmd->attr.shared_credit = be16_to_cpu(bfa_vc_attr->shared_credit); - iocmd->attr.elp_opmode_flags = - be32_to_cpu(bfa_vc_attr->elp_opmode_flags); - - /* Individual VC info */ - while (i < iocmd->attr.total_vc_count) { - iocmd->attr.vc_info[i].vc_credit = - bfa_vc_attr->vc_info[i].vc_credit; - iocmd->attr.vc_info[i].borrow_credit = - bfa_vc_attr->vc_info[i].borrow_credit; - iocmd->attr.vc_info[i].priority = - bfa_vc_attr->vc_info[i].priority; - i++; - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - iocmd->status = BFA_STATUS_OK; - return 0; -} - -int -bfad_iocmd_qos_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcport_stats_s *iocmd = - (struct bfa_bsg_fcport_stats_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - struct bfa_cb_pending_q_s cb_qe; - - init_completion(&fcomp.comp); - bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, - &fcomp, &iocmd->stats); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc)); - iocmd->status = bfa_fcport_get_stats(&bfad->bfa, &cb_qe); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_qos_reset_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)cmd; - struct bfad_hal_comp fcomp; - unsigned long flags; - struct bfa_cb_pending_q_s cb_qe; - - init_completion(&fcomp.comp); - bfa_pending_q_init(&cb_qe, (bfa_cb_cbfn_t)bfad_hcb_comp, - &fcomp, NULL); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - WARN_ON(!bfa_ioc_get_fcmode(&bfad->bfa.ioc)); - iocmd->status = bfa_fcport_clear_stats(&bfad->bfa, &cb_qe); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (iocmd->status != BFA_STATUS_OK) { - bfa_trc(bfad, iocmd->status); - goto out; - } - wait_for_completion(&fcomp.comp); - iocmd->status = fcomp.status; -out: - return 0; -} - -int -bfad_iocmd_vf_get_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_vf_stats_s *iocmd = - (struct bfa_bsg_vf_stats_s *)cmd; - struct bfa_fcs_fabric_s *fcs_vf; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id); - if (fcs_vf == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_VFID; - goto out; - } - memcpy((void *)&iocmd->stats, (void *)&fcs_vf->stats, - sizeof(struct bfa_vf_stats_s)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -int -bfad_iocmd_vf_clr_stats(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_vf_reset_stats_s *iocmd = - (struct bfa_bsg_vf_reset_stats_s *)cmd; - struct bfa_fcs_fabric_s *fcs_vf; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_vf = bfa_fcs_vf_lookup(&bfad->bfa_fcs, iocmd->vf_id); - if (fcs_vf == NULL) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_UNKNOWN_VFID; - goto out; - } - memset((void *)&fcs_vf->stats, 0, sizeof(struct bfa_vf_stats_s)); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - iocmd->status = BFA_STATUS_OK; -out: - return 0; -} - -/* Function to reset the LUN SCAN mode */ -static void -bfad_iocmd_lunmask_reset_lunscan_mode(struct bfad_s *bfad, int lunmask_cfg) -{ - struct bfad_im_port_s *pport_im = bfad->pport.im_port; - struct bfad_vport_s *vport = NULL; - - /* Set the scsi device LUN SCAN flags for base port */ - bfad_reset_sdev_bflags(pport_im, lunmask_cfg); - - /* Set the scsi device LUN SCAN flags for the vports */ - list_for_each_entry(vport, &bfad->vport_list, list_entry) - bfad_reset_sdev_bflags(vport->drv_port.im_port, lunmask_cfg); -} - -int -bfad_iocmd_lunmask(struct bfad_s *bfad, void *pcmd, unsigned int v_cmd) -{ - struct bfa_bsg_gen_s *iocmd = (struct bfa_bsg_gen_s *)pcmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (v_cmd == IOCMD_FCPIM_LUNMASK_ENABLE) { - iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_TRUE); - /* Set the LUN Scanning mode to be Sequential scan */ - if (iocmd->status == BFA_STATUS_OK) - bfad_iocmd_lunmask_reset_lunscan_mode(bfad, BFA_TRUE); - } else if (v_cmd == IOCMD_FCPIM_LUNMASK_DISABLE) { - iocmd->status = bfa_fcpim_lunmask_update(&bfad->bfa, BFA_FALSE); - /* Set the LUN Scanning mode to default REPORT_LUNS scan */ - if (iocmd->status == BFA_STATUS_OK) - bfad_iocmd_lunmask_reset_lunscan_mode(bfad, BFA_FALSE); - } else if (v_cmd == IOCMD_FCPIM_LUNMASK_CLEAR) - iocmd->status = bfa_fcpim_lunmask_clear(&bfad->bfa); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_fcpim_lunmask_query(struct bfad_s *bfad, void *cmd) -{ - struct bfa_bsg_fcpim_lunmask_query_s *iocmd = - (struct bfa_bsg_fcpim_lunmask_query_s *)cmd; - struct bfa_lunmask_cfg_s *lun_mask = &iocmd->lun_mask; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - iocmd->status = bfa_fcpim_lunmask_query(&bfad->bfa, lun_mask); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -int -bfad_iocmd_fcpim_cfg_lunmask(struct bfad_s *bfad, void *cmd, unsigned int v_cmd) -{ - struct bfa_bsg_fcpim_lunmask_s *iocmd = - (struct bfa_bsg_fcpim_lunmask_s *)cmd; - unsigned long flags; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (v_cmd == IOCMD_FCPIM_LUNMASK_ADD) - iocmd->status = bfa_fcpim_lunmask_add(&bfad->bfa, iocmd->vf_id, - &iocmd->pwwn, iocmd->rpwwn, iocmd->lun); - else if (v_cmd == IOCMD_FCPIM_LUNMASK_DELETE) - iocmd->status = bfa_fcpim_lunmask_delete(&bfad->bfa, - iocmd->vf_id, &iocmd->pwwn, - iocmd->rpwwn, iocmd->lun); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return 0; -} - -static int -bfad_iocmd_handler(struct bfad_s *bfad, unsigned int cmd, void *iocmd, - unsigned int payload_len) -{ - int rc = -EINVAL; - - switch (cmd) { - case IOCMD_IOC_ENABLE: - rc = bfad_iocmd_ioc_enable(bfad, iocmd); - break; - case IOCMD_IOC_DISABLE: - rc = bfad_iocmd_ioc_disable(bfad, iocmd); - break; - case IOCMD_IOC_GET_INFO: - rc = bfad_iocmd_ioc_get_info(bfad, iocmd); - break; - case IOCMD_IOC_GET_ATTR: - rc = bfad_iocmd_ioc_get_attr(bfad, iocmd); - break; - case IOCMD_IOC_GET_STATS: - rc = bfad_iocmd_ioc_get_stats(bfad, iocmd); - break; - case IOCMD_IOC_GET_FWSTATS: - rc = bfad_iocmd_ioc_get_fwstats(bfad, iocmd, payload_len); - break; - case IOCMD_IOC_RESET_STATS: - case IOCMD_IOC_RESET_FWSTATS: - rc = bfad_iocmd_ioc_reset_stats(bfad, iocmd, cmd); - break; - case IOCMD_IOC_SET_ADAPTER_NAME: - case IOCMD_IOC_SET_PORT_NAME: - rc = bfad_iocmd_ioc_set_name(bfad, iocmd, cmd); - break; - case IOCMD_IOCFC_GET_ATTR: - rc = bfad_iocmd_iocfc_get_attr(bfad, iocmd); - break; - case IOCMD_IOCFC_SET_INTR: - rc = bfad_iocmd_iocfc_set_intr(bfad, iocmd); - break; - case IOCMD_PORT_ENABLE: - rc = bfad_iocmd_port_enable(bfad, iocmd); - break; - case IOCMD_PORT_DISABLE: - rc = bfad_iocmd_port_disable(bfad, iocmd); - break; - case IOCMD_PORT_GET_ATTR: - rc = bfad_iocmd_port_get_attr(bfad, iocmd); - break; - case IOCMD_PORT_GET_STATS: - rc = bfad_iocmd_port_get_stats(bfad, iocmd, payload_len); - break; - case IOCMD_PORT_RESET_STATS: - rc = bfad_iocmd_port_reset_stats(bfad, iocmd); - break; - case IOCMD_PORT_CFG_TOPO: - case IOCMD_PORT_CFG_SPEED: - case IOCMD_PORT_CFG_ALPA: - case IOCMD_PORT_CLR_ALPA: - rc = bfad_iocmd_set_port_cfg(bfad, iocmd, cmd); - break; - case IOCMD_PORT_CFG_MAXFRSZ: - rc = bfad_iocmd_port_cfg_maxfrsize(bfad, iocmd); - break; - case IOCMD_PORT_BBSC_ENABLE: - case IOCMD_PORT_BBSC_DISABLE: - rc = bfad_iocmd_port_cfg_bbsc(bfad, iocmd, cmd); - break; - case IOCMD_LPORT_GET_ATTR: - rc = bfad_iocmd_lport_get_attr(bfad, iocmd); - break; - case IOCMD_LPORT_GET_STATS: - rc = bfad_iocmd_lport_get_stats(bfad, iocmd); - break; - case IOCMD_LPORT_RESET_STATS: - rc = bfad_iocmd_lport_reset_stats(bfad, iocmd); - break; - case IOCMD_LPORT_GET_IOSTATS: - rc = bfad_iocmd_lport_get_iostats(bfad, iocmd); - break; - case IOCMD_LPORT_GET_RPORTS: - rc = bfad_iocmd_lport_get_rports(bfad, iocmd, payload_len); - break; - case IOCMD_RPORT_GET_ATTR: - rc = bfad_iocmd_rport_get_attr(bfad, iocmd); - break; - case IOCMD_RPORT_GET_ADDR: - rc = bfad_iocmd_rport_get_addr(bfad, iocmd); - break; - case IOCMD_RPORT_GET_STATS: - rc = bfad_iocmd_rport_get_stats(bfad, iocmd); - break; - case IOCMD_RPORT_RESET_STATS: - rc = bfad_iocmd_rport_clr_stats(bfad, iocmd); - break; - case IOCMD_RPORT_SET_SPEED: - rc = bfad_iocmd_rport_set_speed(bfad, iocmd); - break; - case IOCMD_VPORT_GET_ATTR: - rc = bfad_iocmd_vport_get_attr(bfad, iocmd); - break; - case IOCMD_VPORT_GET_STATS: - rc = bfad_iocmd_vport_get_stats(bfad, iocmd); - break; - case IOCMD_VPORT_RESET_STATS: - rc = bfad_iocmd_vport_clr_stats(bfad, iocmd); - break; - case IOCMD_FABRIC_GET_LPORTS: - rc = bfad_iocmd_fabric_get_lports(bfad, iocmd, payload_len); - break; - case IOCMD_RATELIM_ENABLE: - case IOCMD_RATELIM_DISABLE: - rc = bfad_iocmd_ratelim(bfad, cmd, iocmd); - break; - case IOCMD_RATELIM_DEF_SPEED: - rc = bfad_iocmd_ratelim_speed(bfad, cmd, iocmd); - break; - case IOCMD_FCPIM_FAILOVER: - rc = bfad_iocmd_cfg_fcpim(bfad, iocmd); - break; - case IOCMD_FCPIM_MODSTATS: - rc = bfad_iocmd_fcpim_get_modstats(bfad, iocmd); - break; - case IOCMD_FCPIM_MODSTATSCLR: - rc = bfad_iocmd_fcpim_clr_modstats(bfad, iocmd); - break; - case IOCMD_FCPIM_DEL_ITN_STATS: - rc = bfad_iocmd_fcpim_get_del_itn_stats(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_ATTR: - rc = bfad_iocmd_itnim_get_attr(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_IOSTATS: - rc = bfad_iocmd_itnim_get_iostats(bfad, iocmd); - break; - case IOCMD_ITNIM_RESET_STATS: - rc = bfad_iocmd_itnim_reset_stats(bfad, iocmd); - break; - case IOCMD_ITNIM_GET_ITNSTATS: - rc = bfad_iocmd_itnim_get_itnstats(bfad, iocmd); - break; - case IOCMD_FCPORT_ENABLE: - rc = bfad_iocmd_fcport_enable(bfad, iocmd); - break; - case IOCMD_FCPORT_DISABLE: - rc = bfad_iocmd_fcport_disable(bfad, iocmd); - break; - case IOCMD_IOC_PCIFN_CFG: - rc = bfad_iocmd_ioc_get_pcifn_cfg(bfad, iocmd); - break; - case IOCMD_PCIFN_CREATE: - rc = bfad_iocmd_pcifn_create(bfad, iocmd); - break; - case IOCMD_PCIFN_DELETE: - rc = bfad_iocmd_pcifn_delete(bfad, iocmd); - break; - case IOCMD_PCIFN_BW: - rc = bfad_iocmd_pcifn_bw(bfad, iocmd); - break; - case IOCMD_ADAPTER_CFG_MODE: - rc = bfad_iocmd_adapter_cfg_mode(bfad, iocmd); - break; - case IOCMD_PORT_CFG_MODE: - rc = bfad_iocmd_port_cfg_mode(bfad, iocmd); - break; - case IOCMD_FLASH_ENABLE_OPTROM: - case IOCMD_FLASH_DISABLE_OPTROM: - rc = bfad_iocmd_ablk_optrom(bfad, cmd, iocmd); - break; - case IOCMD_FAA_QUERY: - rc = bfad_iocmd_faa_query(bfad, iocmd); - break; - case IOCMD_CEE_GET_ATTR: - rc = bfad_iocmd_cee_attr(bfad, iocmd, payload_len); - break; - case IOCMD_CEE_GET_STATS: - rc = bfad_iocmd_cee_get_stats(bfad, iocmd, payload_len); - break; - case IOCMD_CEE_RESET_STATS: - rc = bfad_iocmd_cee_reset_stats(bfad, iocmd); - break; - case IOCMD_SFP_MEDIA: - rc = bfad_iocmd_sfp_media(bfad, iocmd); - break; - case IOCMD_SFP_SPEED: - rc = bfad_iocmd_sfp_speed(bfad, iocmd); - break; - case IOCMD_FLASH_GET_ATTR: - rc = bfad_iocmd_flash_get_attr(bfad, iocmd); - break; - case IOCMD_FLASH_ERASE_PART: - rc = bfad_iocmd_flash_erase_part(bfad, iocmd); - break; - case IOCMD_FLASH_UPDATE_PART: - rc = bfad_iocmd_flash_update_part(bfad, iocmd, payload_len); - break; - case IOCMD_FLASH_READ_PART: - rc = bfad_iocmd_flash_read_part(bfad, iocmd, payload_len); - break; - case IOCMD_DIAG_TEMP: - rc = bfad_iocmd_diag_temp(bfad, iocmd); - break; - case IOCMD_DIAG_MEMTEST: - rc = bfad_iocmd_diag_memtest(bfad, iocmd); - break; - case IOCMD_DIAG_LOOPBACK: - rc = bfad_iocmd_diag_loopback(bfad, iocmd); - break; - case IOCMD_DIAG_FWPING: - rc = bfad_iocmd_diag_fwping(bfad, iocmd); - break; - case IOCMD_DIAG_QUEUETEST: - rc = bfad_iocmd_diag_queuetest(bfad, iocmd); - break; - case IOCMD_DIAG_SFP: - rc = bfad_iocmd_diag_sfp(bfad, iocmd); - break; - case IOCMD_DIAG_LED: - rc = bfad_iocmd_diag_led(bfad, iocmd); - break; - case IOCMD_DIAG_BEACON_LPORT: - rc = bfad_iocmd_diag_beacon_lport(bfad, iocmd); - break; - case IOCMD_DIAG_LB_STAT: - rc = bfad_iocmd_diag_lb_stat(bfad, iocmd); - break; - case IOCMD_PHY_GET_ATTR: - rc = bfad_iocmd_phy_get_attr(bfad, iocmd); - break; - case IOCMD_PHY_GET_STATS: - rc = bfad_iocmd_phy_get_stats(bfad, iocmd); - break; - case IOCMD_PHY_UPDATE_FW: - rc = bfad_iocmd_phy_update(bfad, iocmd, payload_len); - break; - case IOCMD_PHY_READ_FW: - rc = bfad_iocmd_phy_read(bfad, iocmd, payload_len); - break; - case IOCMD_VHBA_QUERY: - rc = bfad_iocmd_vhba_query(bfad, iocmd); - break; - case IOCMD_DEBUG_PORTLOG: - rc = bfad_iocmd_porglog_get(bfad, iocmd); - break; - case IOCMD_DEBUG_FW_CORE: - rc = bfad_iocmd_debug_fw_core(bfad, iocmd, payload_len); - break; - case IOCMD_DEBUG_FW_STATE_CLR: - case IOCMD_DEBUG_PORTLOG_CLR: - case IOCMD_DEBUG_START_DTRC: - case IOCMD_DEBUG_STOP_DTRC: - rc = bfad_iocmd_debug_ctl(bfad, iocmd, cmd); - break; - case IOCMD_DEBUG_PORTLOG_CTL: - rc = bfad_iocmd_porglog_ctl(bfad, iocmd); - break; - case IOCMD_FCPIM_PROFILE_ON: - case IOCMD_FCPIM_PROFILE_OFF: - rc = bfad_iocmd_fcpim_cfg_profile(bfad, iocmd, cmd); - break; - case IOCMD_ITNIM_GET_IOPROFILE: - rc = bfad_iocmd_itnim_get_ioprofile(bfad, iocmd); - break; - case IOCMD_FCPORT_GET_STATS: - rc = bfad_iocmd_fcport_get_stats(bfad, iocmd); - break; - case IOCMD_FCPORT_RESET_STATS: - rc = bfad_iocmd_fcport_reset_stats(bfad, iocmd); - break; - case IOCMD_BOOT_CFG: - rc = bfad_iocmd_boot_cfg(bfad, iocmd); - break; - case IOCMD_BOOT_QUERY: - rc = bfad_iocmd_boot_query(bfad, iocmd); - break; - case IOCMD_PREBOOT_QUERY: - rc = bfad_iocmd_preboot_query(bfad, iocmd); - break; - case IOCMD_ETHBOOT_CFG: - rc = bfad_iocmd_ethboot_cfg(bfad, iocmd); - break; - case IOCMD_ETHBOOT_QUERY: - rc = bfad_iocmd_ethboot_query(bfad, iocmd); - break; - case IOCMD_TRUNK_ENABLE: - case IOCMD_TRUNK_DISABLE: - rc = bfad_iocmd_cfg_trunk(bfad, iocmd, cmd); - break; - case IOCMD_TRUNK_GET_ATTR: - rc = bfad_iocmd_trunk_get_attr(bfad, iocmd); - break; - case IOCMD_QOS_ENABLE: - case IOCMD_QOS_DISABLE: - rc = bfad_iocmd_qos(bfad, iocmd, cmd); - break; - case IOCMD_QOS_GET_ATTR: - rc = bfad_iocmd_qos_get_attr(bfad, iocmd); - break; - case IOCMD_QOS_GET_VC_ATTR: - rc = bfad_iocmd_qos_get_vc_attr(bfad, iocmd); - break; - case IOCMD_QOS_GET_STATS: - rc = bfad_iocmd_qos_get_stats(bfad, iocmd); - break; - case IOCMD_QOS_RESET_STATS: - rc = bfad_iocmd_qos_reset_stats(bfad, iocmd); - break; - case IOCMD_VF_GET_STATS: - rc = bfad_iocmd_vf_get_stats(bfad, iocmd); - break; - case IOCMD_VF_RESET_STATS: - rc = bfad_iocmd_vf_clr_stats(bfad, iocmd); - break; - case IOCMD_FCPIM_LUNMASK_ENABLE: - case IOCMD_FCPIM_LUNMASK_DISABLE: - case IOCMD_FCPIM_LUNMASK_CLEAR: - rc = bfad_iocmd_lunmask(bfad, iocmd, cmd); - break; - case IOCMD_FCPIM_LUNMASK_QUERY: - rc = bfad_iocmd_fcpim_lunmask_query(bfad, iocmd); - break; - case IOCMD_FCPIM_LUNMASK_ADD: - case IOCMD_FCPIM_LUNMASK_DELETE: - rc = bfad_iocmd_fcpim_cfg_lunmask(bfad, iocmd, cmd); - break; - default: - rc = -EINVAL; - break; - } - return rc; -} - -static int -bfad_im_bsg_vendor_request(struct fc_bsg_job *job) -{ - uint32_t vendor_cmd = job->request->rqst_data.h_vendor.vendor_cmd[0]; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) job->shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct request_queue *request_q = job->req->q; - void *payload_kbuf; - int rc = -EINVAL; - - /* - * Set the BSG device request_queue size to 256 to support - * payloads larger than 512*1024K bytes. - */ - blk_queue_max_segments(request_q, 256); - - /* Allocate a temp buffer to hold the passed in user space command */ - payload_kbuf = kzalloc(job->request_payload.payload_len, GFP_KERNEL); - if (!payload_kbuf) { - rc = -ENOMEM; - goto out; - } - - /* Copy the sg_list passed in to a linear buffer: holds the cmnd data */ - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, payload_kbuf, - job->request_payload.payload_len); - - /* Invoke IOCMD handler - to handle all the vendor command requests */ - rc = bfad_iocmd_handler(bfad, vendor_cmd, payload_kbuf, - job->request_payload.payload_len); - if (rc != BFA_STATUS_OK) - goto error; - - /* Copy the response data to the job->reply_payload sg_list */ - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - payload_kbuf, - job->reply_payload.payload_len); - - /* free the command buffer */ - kfree(payload_kbuf); - - /* Fill the BSG job reply data */ - job->reply_len = job->reply_payload.payload_len; - job->reply->reply_payload_rcv_len = job->reply_payload.payload_len; - job->reply->result = rc; - - job->job_done(job); - return rc; -error: - /* free the command buffer */ - kfree(payload_kbuf); -out: - job->reply->result = rc; - job->reply_len = sizeof(uint32_t); - job->reply->reply_payload_rcv_len = 0; - return rc; -} - -/* FC passthru call backs */ -u64 -bfad_fcxp_get_req_sgaddr_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - u64 addr; - - sge = drv_fcxp->req_sge + sgeid; - addr = (u64)(size_t) sge->sg_addr; - return addr; -} - -u32 -bfad_fcxp_get_req_sglen_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - - sge = drv_fcxp->req_sge + sgeid; - return sge->sg_len; -} - -u64 -bfad_fcxp_get_rsp_sgaddr_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - u64 addr; - - sge = drv_fcxp->rsp_sge + sgeid; - addr = (u64)(size_t) sge->sg_addr; - return addr; -} - -u32 -bfad_fcxp_get_rsp_sglen_cb(void *bfad_fcxp, int sgeid) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - struct bfa_sge_s *sge; - - sge = drv_fcxp->rsp_sge + sgeid; - return sge->sg_len; -} - -void -bfad_send_fcpt_cb(void *bfad_fcxp, struct bfa_fcxp_s *fcxp, void *cbarg, - bfa_status_t req_status, u32 rsp_len, u32 resid_len, - struct fchs_s *rsp_fchs) -{ - struct bfad_fcxp *drv_fcxp = bfad_fcxp; - - drv_fcxp->req_status = req_status; - drv_fcxp->rsp_len = rsp_len; - - /* bfa_fcxp will be automatically freed by BFA */ - drv_fcxp->bfa_fcxp = NULL; - complete(&drv_fcxp->comp); -} - -struct bfad_buf_info * -bfad_fcxp_map_sg(struct bfad_s *bfad, void *payload_kbuf, - uint32_t payload_len, uint32_t *num_sgles) -{ - struct bfad_buf_info *buf_base, *buf_info; - struct bfa_sge_s *sg_table; - int sge_num = 1; - - buf_base = kzalloc((sizeof(struct bfad_buf_info) + - sizeof(struct bfa_sge_s)) * sge_num, GFP_KERNEL); - if (!buf_base) - return NULL; - - sg_table = (struct bfa_sge_s *) (((uint8_t *)buf_base) + - (sizeof(struct bfad_buf_info) * sge_num)); - - /* Allocate dma coherent memory */ - buf_info = buf_base; - buf_info->size = payload_len; - buf_info->virt = dma_alloc_coherent(&bfad->pcidev->dev, buf_info->size, - &buf_info->phys, GFP_KERNEL); - if (!buf_info->virt) - goto out_free_mem; - - /* copy the linear bsg buffer to buf_info */ - memset(buf_info->virt, 0, buf_info->size); - memcpy(buf_info->virt, payload_kbuf, buf_info->size); - - /* - * Setup SG table - */ - sg_table->sg_len = buf_info->size; - sg_table->sg_addr = (void *)(size_t) buf_info->phys; - - *num_sgles = sge_num; - - return buf_base; - -out_free_mem: - kfree(buf_base); - return NULL; -} - -void -bfad_fcxp_free_mem(struct bfad_s *bfad, struct bfad_buf_info *buf_base, - uint32_t num_sgles) -{ - int i; - struct bfad_buf_info *buf_info = buf_base; - - if (buf_base) { - for (i = 0; i < num_sgles; buf_info++, i++) { - if (buf_info->virt != NULL) - dma_free_coherent(&bfad->pcidev->dev, - buf_info->size, buf_info->virt, - buf_info->phys); - } - kfree(buf_base); - } -} - -int -bfad_fcxp_bsg_send(struct fc_bsg_job *job, struct bfad_fcxp *drv_fcxp, - bfa_bsg_fcpt_t *bsg_fcpt) -{ - struct bfa_fcxp_s *hal_fcxp; - struct bfad_s *bfad = drv_fcxp->port->bfad; - unsigned long flags; - uint8_t lp_tag; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - - /* Allocate bfa_fcxp structure */ - hal_fcxp = bfa_fcxp_alloc(drv_fcxp, &bfad->bfa, - drv_fcxp->num_req_sgles, - drv_fcxp->num_rsp_sgles, - bfad_fcxp_get_req_sgaddr_cb, - bfad_fcxp_get_req_sglen_cb, - bfad_fcxp_get_rsp_sgaddr_cb, - bfad_fcxp_get_rsp_sglen_cb); - if (!hal_fcxp) { - bfa_trc(bfad, 0); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return BFA_STATUS_ENOMEM; - } - - drv_fcxp->bfa_fcxp = hal_fcxp; - - lp_tag = bfa_lps_get_tag_from_pid(&bfad->bfa, bsg_fcpt->fchs.s_id); - - bfa_fcxp_send(hal_fcxp, drv_fcxp->bfa_rport, bsg_fcpt->vf_id, lp_tag, - bsg_fcpt->cts, bsg_fcpt->cos, - job->request_payload.payload_len, - &bsg_fcpt->fchs, bfad_send_fcpt_cb, bfad, - job->reply_payload.payload_len, bsg_fcpt->tsecs); - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return BFA_STATUS_OK; -} - -int -bfad_im_bsg_els_ct_request(struct fc_bsg_job *job) -{ - struct bfa_bsg_data *bsg_data; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) job->shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - bfa_bsg_fcpt_t *bsg_fcpt; - struct bfad_fcxp *drv_fcxp; - struct bfa_fcs_lport_s *fcs_port; - struct bfa_fcs_rport_s *fcs_rport; - uint32_t command_type = job->request->msgcode; - unsigned long flags; - struct bfad_buf_info *rsp_buf_info; - void *req_kbuf = NULL, *rsp_kbuf = NULL; - int rc = -EINVAL; - - job->reply_len = sizeof(uint32_t); /* Atleast uint32_t reply_len */ - job->reply->reply_payload_rcv_len = 0; - - /* Get the payload passed in from userspace */ - bsg_data = (struct bfa_bsg_data *) (((char *)job->request) + - sizeof(struct fc_bsg_request)); - if (bsg_data == NULL) - goto out; - - /* - * Allocate buffer for bsg_fcpt and do a copy_from_user op for payload - * buffer of size bsg_data->payload_len - */ - bsg_fcpt = kzalloc(bsg_data->payload_len, GFP_KERNEL); - if (!bsg_fcpt) - goto out; - - if (copy_from_user((uint8_t *)bsg_fcpt, bsg_data->payload, - bsg_data->payload_len)) { - kfree(bsg_fcpt); - goto out; - } - - drv_fcxp = kzalloc(sizeof(struct bfad_fcxp), GFP_KERNEL); - if (drv_fcxp == NULL) { - kfree(bsg_fcpt); - rc = -ENOMEM; - goto out; - } - - spin_lock_irqsave(&bfad->bfad_lock, flags); - fcs_port = bfa_fcs_lookup_port(&bfad->bfa_fcs, bsg_fcpt->vf_id, - bsg_fcpt->lpwwn); - if (fcs_port == NULL) { - bsg_fcpt->status = BFA_STATUS_UNKNOWN_LWWN; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - /* Check if the port is online before sending FC Passthru cmd */ - if (!bfa_fcs_lport_is_online(fcs_port)) { - bsg_fcpt->status = BFA_STATUS_PORT_OFFLINE; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - drv_fcxp->port = fcs_port->bfad_port; - - if (drv_fcxp->port->bfad == 0) - drv_fcxp->port->bfad = bfad; - - /* Fetch the bfa_rport - if nexus needed */ - if (command_type == FC_BSG_HST_ELS_NOLOGIN || - command_type == FC_BSG_HST_CT) { - /* BSG HST commands: no nexus needed */ - drv_fcxp->bfa_rport = NULL; - - } else if (command_type == FC_BSG_RPT_ELS || - command_type == FC_BSG_RPT_CT) { - /* BSG RPT commands: nexus needed */ - fcs_rport = bfa_fcs_lport_get_rport_by_pwwn(fcs_port, - bsg_fcpt->dpwwn); - if (fcs_rport == NULL) { - bsg_fcpt->status = BFA_STATUS_UNKNOWN_RWWN; - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - drv_fcxp->bfa_rport = fcs_rport->bfa_rport; - - } else { /* Unknown BSG msgcode; return -EINVAL */ - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - goto out_free_mem; - } - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* allocate memory for req / rsp buffers */ - req_kbuf = kzalloc(job->request_payload.payload_len, GFP_KERNEL); - if (!req_kbuf) { - printk(KERN_INFO "bfa %s: fcpt request buffer alloc failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - rsp_kbuf = kzalloc(job->reply_payload.payload_len, GFP_KERNEL); - if (!rsp_kbuf) { - printk(KERN_INFO "bfa %s: fcpt response buffer alloc failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - /* map req sg - copy the sg_list passed in to the linear buffer */ - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, req_kbuf, - job->request_payload.payload_len); - - drv_fcxp->reqbuf_info = bfad_fcxp_map_sg(bfad, req_kbuf, - job->request_payload.payload_len, - &drv_fcxp->num_req_sgles); - if (!drv_fcxp->reqbuf_info) { - printk(KERN_INFO "bfa %s: fcpt request fcxp_map_sg failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - drv_fcxp->req_sge = (struct bfa_sge_s *) - (((uint8_t *)drv_fcxp->reqbuf_info) + - (sizeof(struct bfad_buf_info) * - drv_fcxp->num_req_sgles)); - - /* map rsp sg */ - drv_fcxp->rspbuf_info = bfad_fcxp_map_sg(bfad, rsp_kbuf, - job->reply_payload.payload_len, - &drv_fcxp->num_rsp_sgles); - if (!drv_fcxp->rspbuf_info) { - printk(KERN_INFO "bfa %s: fcpt response fcxp_map_sg failed\n", - bfad->pci_name); - rc = -ENOMEM; - goto out_free_mem; - } - - rsp_buf_info = (struct bfad_buf_info *)drv_fcxp->rspbuf_info; - drv_fcxp->rsp_sge = (struct bfa_sge_s *) - (((uint8_t *)drv_fcxp->rspbuf_info) + - (sizeof(struct bfad_buf_info) * - drv_fcxp->num_rsp_sgles)); - - /* fcxp send */ - init_completion(&drv_fcxp->comp); - rc = bfad_fcxp_bsg_send(job, drv_fcxp, bsg_fcpt); - if (rc == BFA_STATUS_OK) { - wait_for_completion(&drv_fcxp->comp); - bsg_fcpt->status = drv_fcxp->req_status; - } else { - bsg_fcpt->status = rc; - goto out_free_mem; - } - - /* fill the job->reply data */ - if (drv_fcxp->req_status == BFA_STATUS_OK) { - job->reply_len = drv_fcxp->rsp_len; - job->reply->reply_payload_rcv_len = drv_fcxp->rsp_len; - job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; - } else { - job->reply->reply_payload_rcv_len = - sizeof(struct fc_bsg_ctels_reply); - job->reply_len = sizeof(uint32_t); - job->reply->reply_data.ctels_reply.status = - FC_CTELS_STATUS_REJECT; - } - - /* Copy the response data to the reply_payload sg list */ - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - (uint8_t *)rsp_buf_info->virt, - job->reply_payload.payload_len); - -out_free_mem: - bfad_fcxp_free_mem(bfad, drv_fcxp->rspbuf_info, - drv_fcxp->num_rsp_sgles); - bfad_fcxp_free_mem(bfad, drv_fcxp->reqbuf_info, - drv_fcxp->num_req_sgles); - kfree(req_kbuf); - kfree(rsp_kbuf); - - /* Need a copy to user op */ - if (copy_to_user(bsg_data->payload, (void *) bsg_fcpt, - bsg_data->payload_len)) - rc = -EIO; - - kfree(bsg_fcpt); - kfree(drv_fcxp); -out: - job->reply->result = rc; - - if (rc == BFA_STATUS_OK) - job->job_done(job); - - return rc; -} - -int -bfad_im_bsg_request(struct fc_bsg_job *job) -{ - uint32_t rc = BFA_STATUS_OK; - - switch (job->request->msgcode) { - case FC_BSG_HST_VENDOR: - /* Process BSG HST Vendor requests */ - rc = bfad_im_bsg_vendor_request(job); - break; - case FC_BSG_HST_ELS_NOLOGIN: - case FC_BSG_RPT_ELS: - case FC_BSG_HST_CT: - case FC_BSG_RPT_CT: - /* Process BSG ELS/CT commands */ - rc = bfad_im_bsg_els_ct_request(job); - break; - default: - job->reply->result = rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - break; - } - - return rc; -} - -int -bfad_im_bsg_timeout(struct fc_bsg_job *job) -{ - /* Don't complete the BSG job request - return -EAGAIN - * to reset bsg job timeout : for ELS/CT pass thru we - * already have timer to track the request. - */ - return -EAGAIN; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.h deleted file mode 100644 index 17ad6728..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_bsg.h +++ /dev/null @@ -1,744 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#ifndef BFAD_BSG_H -#define BFAD_BSG_H - -#include "bfa_defs.h" -#include "bfa_defs_fcs.h" - -/* Definitions of vendor unique structures and command codes passed in - * using FC_BSG_HST_VENDOR message code. - */ -enum { - IOCMD_IOC_ENABLE = 0x1, - IOCMD_IOC_DISABLE, - IOCMD_IOC_GET_ATTR, - IOCMD_IOC_GET_INFO, - IOCMD_IOC_GET_STATS, - IOCMD_IOC_GET_FWSTATS, - IOCMD_IOC_RESET_STATS, - IOCMD_IOC_RESET_FWSTATS, - IOCMD_IOC_SET_ADAPTER_NAME, - IOCMD_IOC_SET_PORT_NAME, - IOCMD_IOCFC_GET_ATTR, - IOCMD_IOCFC_SET_INTR, - IOCMD_PORT_ENABLE, - IOCMD_PORT_DISABLE, - IOCMD_PORT_GET_ATTR, - IOCMD_PORT_GET_STATS, - IOCMD_PORT_RESET_STATS, - IOCMD_PORT_CFG_TOPO, - IOCMD_PORT_CFG_SPEED, - IOCMD_PORT_CFG_ALPA, - IOCMD_PORT_CFG_MAXFRSZ, - IOCMD_PORT_CLR_ALPA, - IOCMD_PORT_BBSC_ENABLE, - IOCMD_PORT_BBSC_DISABLE, - IOCMD_LPORT_GET_ATTR, - IOCMD_LPORT_GET_RPORTS, - IOCMD_LPORT_GET_STATS, - IOCMD_LPORT_RESET_STATS, - IOCMD_LPORT_GET_IOSTATS, - IOCMD_RPORT_GET_ATTR, - IOCMD_RPORT_GET_ADDR, - IOCMD_RPORT_GET_STATS, - IOCMD_RPORT_RESET_STATS, - IOCMD_RPORT_SET_SPEED, - IOCMD_VPORT_GET_ATTR, - IOCMD_VPORT_GET_STATS, - IOCMD_VPORT_RESET_STATS, - IOCMD_FABRIC_GET_LPORTS, - IOCMD_RATELIM_ENABLE, - IOCMD_RATELIM_DISABLE, - IOCMD_RATELIM_DEF_SPEED, - IOCMD_FCPIM_FAILOVER, - IOCMD_FCPIM_MODSTATS, - IOCMD_FCPIM_MODSTATSCLR, - IOCMD_FCPIM_DEL_ITN_STATS, - IOCMD_ITNIM_GET_ATTR, - IOCMD_ITNIM_GET_IOSTATS, - IOCMD_ITNIM_RESET_STATS, - IOCMD_ITNIM_GET_ITNSTATS, - IOCMD_IOC_PCIFN_CFG, - IOCMD_FCPORT_ENABLE, - IOCMD_FCPORT_DISABLE, - IOCMD_PCIFN_CREATE, - IOCMD_PCIFN_DELETE, - IOCMD_PCIFN_BW, - IOCMD_ADAPTER_CFG_MODE, - IOCMD_PORT_CFG_MODE, - IOCMD_FLASH_ENABLE_OPTROM, - IOCMD_FLASH_DISABLE_OPTROM, - IOCMD_FAA_QUERY, - IOCMD_CEE_GET_ATTR, - IOCMD_CEE_GET_STATS, - IOCMD_CEE_RESET_STATS, - IOCMD_SFP_MEDIA, - IOCMD_SFP_SPEED, - IOCMD_FLASH_GET_ATTR, - IOCMD_FLASH_ERASE_PART, - IOCMD_FLASH_UPDATE_PART, - IOCMD_FLASH_READ_PART, - IOCMD_DIAG_TEMP, - IOCMD_DIAG_MEMTEST, - IOCMD_DIAG_LOOPBACK, - IOCMD_DIAG_FWPING, - IOCMD_DIAG_QUEUETEST, - IOCMD_DIAG_SFP, - IOCMD_DIAG_LED, - IOCMD_DIAG_BEACON_LPORT, - IOCMD_DIAG_LB_STAT, - IOCMD_PHY_GET_ATTR, - IOCMD_PHY_GET_STATS, - IOCMD_PHY_UPDATE_FW, - IOCMD_PHY_READ_FW, - IOCMD_VHBA_QUERY, - IOCMD_DEBUG_PORTLOG, - IOCMD_DEBUG_FW_CORE, - IOCMD_DEBUG_FW_STATE_CLR, - IOCMD_DEBUG_PORTLOG_CLR, - IOCMD_DEBUG_START_DTRC, - IOCMD_DEBUG_STOP_DTRC, - IOCMD_DEBUG_PORTLOG_CTL, - IOCMD_FCPIM_PROFILE_ON, - IOCMD_FCPIM_PROFILE_OFF, - IOCMD_ITNIM_GET_IOPROFILE, - IOCMD_FCPORT_GET_STATS, - IOCMD_FCPORT_RESET_STATS, - IOCMD_BOOT_CFG, - IOCMD_BOOT_QUERY, - IOCMD_PREBOOT_QUERY, - IOCMD_ETHBOOT_CFG, - IOCMD_ETHBOOT_QUERY, - IOCMD_TRUNK_ENABLE, - IOCMD_TRUNK_DISABLE, - IOCMD_TRUNK_GET_ATTR, - IOCMD_QOS_ENABLE, - IOCMD_QOS_DISABLE, - IOCMD_QOS_GET_ATTR, - IOCMD_QOS_GET_VC_ATTR, - IOCMD_QOS_GET_STATS, - IOCMD_QOS_RESET_STATS, - IOCMD_VF_GET_STATS, - IOCMD_VF_RESET_STATS, - IOCMD_FCPIM_LUNMASK_ENABLE, - IOCMD_FCPIM_LUNMASK_DISABLE, - IOCMD_FCPIM_LUNMASK_CLEAR, - IOCMD_FCPIM_LUNMASK_QUERY, - IOCMD_FCPIM_LUNMASK_ADD, - IOCMD_FCPIM_LUNMASK_DELETE, -}; - -struct bfa_bsg_gen_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; -}; - -struct bfa_bsg_portlogctl_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - bfa_boolean_t ctl; - int inst_no; -}; - -struct bfa_bsg_fcpim_profile_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; -}; - -struct bfa_bsg_itnim_ioprofile_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_ioprofile_s ioprofile; -}; - -struct bfa_bsg_fcport_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - union bfa_fcport_stats_u stats; -}; - -struct bfa_bsg_ioc_name_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - char name[BFA_ADAPTER_SYM_NAME_LEN]; -}; - -struct bfa_bsg_ioc_info_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - char serialnum[64]; - char hwpath[BFA_STRING_32]; - char adapter_hwpath[BFA_STRING_32]; - char guid[BFA_ADAPTER_SYM_NAME_LEN*2]; - char name[BFA_ADAPTER_SYM_NAME_LEN]; - char port_name[BFA_ADAPTER_SYM_NAME_LEN]; - char eth_name[BFA_ADAPTER_SYM_NAME_LEN]; - wwn_t pwwn; - wwn_t nwwn; - wwn_t factorypwwn; - wwn_t factorynwwn; - mac_t mac; - mac_t factory_mac; /* Factory mac address */ - mac_t current_mac; /* Currently assigned mac address */ - enum bfa_ioc_type_e ioc_type; - u16 pvid; /* Port vlan id */ - u16 rsvd1; - u32 host; - u32 bandwidth; /* For PF support */ - u32 rsvd2; -}; - -struct bfa_bsg_ioc_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ioc_attr_s ioc_attr; -}; - -struct bfa_bsg_ioc_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ioc_stats_s ioc_stats; -}; - -struct bfa_bsg_ioc_fwstats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_iocfc_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_iocfc_attr_s iocfc_attr; -}; - -struct bfa_bsg_iocfc_intr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_iocfc_intr_attr_s attr; -}; - -struct bfa_bsg_port_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_port_attr_s attr; -}; - -struct bfa_bsg_port_cfg_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 param; - u32 rsvd1; -}; - -struct bfa_bsg_port_cfg_maxfrsize_s { - bfa_status_t status; - u16 bfad_num; - u16 maxfrsize; -}; - -struct bfa_bsg_port_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_lport_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_lport_attr_s port_attr; -}; - -struct bfa_bsg_lport_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_lport_stats_s port_stats; -}; - -struct bfa_bsg_lport_iostats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - struct bfa_itnim_iostats_s iostats; -}; - -struct bfa_bsg_lport_get_rports_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - u64 rbuf_ptr; - u32 nrports; - u32 rsvd; -}; - -struct bfa_bsg_rport_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - struct bfa_rport_attr_s attr; -}; - -struct bfa_bsg_rport_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - struct bfa_rport_stats_s stats; -}; - -struct bfa_bsg_rport_scsi_addr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - u32 host; - u32 bus; - u32 target; - u32 lun; -}; - -struct bfa_bsg_rport_reset_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; -}; - -struct bfa_bsg_rport_set_speed_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - enum bfa_port_speed speed; - u32 rsvd; - wwn_t pwwn; - wwn_t rpwwn; -}; - -struct bfa_bsg_vport_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t vpwwn; - struct bfa_vport_attr_s vport_attr; -}; - -struct bfa_bsg_vport_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t vpwwn; - struct bfa_vport_stats_s vport_stats; -}; - -struct bfa_bsg_reset_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t vpwwn; -}; - -struct bfa_bsg_fabric_get_lports_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - u64 buf_ptr; - u32 nports; - u32 rsvd; -}; - -struct bfa_bsg_trl_speed_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_port_speed speed; -}; - -struct bfa_bsg_fcpim_s { - bfa_status_t status; - u16 bfad_num; - u16 param; -}; - -struct bfa_bsg_fcpim_modstats_s { - bfa_status_t status; - u16 bfad_num; - struct bfa_itnim_iostats_s modstats; -}; - -struct bfa_bsg_fcpim_del_itn_stats_s { - bfa_status_t status; - u16 bfad_num; - struct bfa_fcpim_del_itn_stats_s modstats; -}; - -struct bfa_bsg_fcpim_modstatsclr_s { - bfa_status_t status; - u16 bfad_num; -}; - -struct bfa_bsg_itnim_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_attr_s attr; -}; - -struct bfa_bsg_itnim_iostats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_iostats_s iostats; -}; - -struct bfa_bsg_itnim_itnstats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t lpwwn; - wwn_t rpwwn; - struct bfa_itnim_stats_s itnstats; -}; - -struct bfa_bsg_pcifn_cfg_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ablk_cfg_s pcifn_cfg; -}; - -struct bfa_bsg_pcifn_s { - bfa_status_t status; - u16 bfad_num; - u16 pcifn_id; - u32 bandwidth; - u8 port; - enum bfi_pcifn_class pcifn_class; - u8 rsvd[1]; -}; - -struct bfa_bsg_adapter_cfg_mode_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_adapter_cfg_mode_s cfg; -}; - -struct bfa_bsg_port_cfg_mode_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_port_cfg_mode_s cfg; -}; - -struct bfa_bsg_faa_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_faa_attr_s faa_attr; -}; - -struct bfa_bsg_cee_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_cee_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 buf_size; - u32 rsvd1; - u64 buf_ptr; -}; - -struct bfa_bsg_sfp_media_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_defs_sfp_media_e media; -}; - -struct bfa_bsg_sfp_speed_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_port_speed speed; -}; - -struct bfa_bsg_flash_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_flash_attr_s attr; -}; - -struct bfa_bsg_flash_s { - bfa_status_t status; - u16 bfad_num; - u8 instance; - u8 rsvd; - enum bfa_flash_part_type type; - int bufsz; - u64 buf_ptr; -}; - -struct bfa_bsg_diag_get_temp_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_diag_results_tempsensor_s result; -}; - -struct bfa_bsg_diag_memtest_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd[3]; - u32 pat; - struct bfa_diag_memtest_result result; - struct bfa_diag_memtest_s memtest; -}; - -struct bfa_bsg_diag_loopback_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - enum bfa_port_opmode opmode; - enum bfa_port_speed speed; - u32 lpcnt; - u32 pat; - struct bfa_diag_loopback_result_s result; -}; - -struct bfa_bsg_diag_fwping_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 cnt; - u32 pattern; - struct bfa_diag_results_fwping result; -}; - -struct bfa_bsg_diag_qtest_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 force; - u32 queue; - struct bfa_diag_qtest_result_s result; -}; - -struct bfa_bsg_sfp_show_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct sfp_mem_s sfp; -}; - -struct bfa_bsg_diag_led_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_diag_ledtest_s ledtest; -}; - -struct bfa_bsg_diag_beacon_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - bfa_boolean_t beacon; - bfa_boolean_t link_e2e_beacon; - u32 second; -}; - -struct bfa_bsg_diag_lb_stat_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; -}; - -struct bfa_bsg_phy_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_phy_attr_s attr; -}; - -struct bfa_bsg_phy_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - u64 bufsz; - u64 buf_ptr; -}; - -struct bfa_bsg_debug_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - u32 bufsz; - int inst_no; - u64 buf_ptr; - u64 offset; -}; - -struct bfa_bsg_phy_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 instance; - struct bfa_phy_stats_s stats; -}; - -struct bfa_bsg_vhba_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 pcifn_id; - struct bfa_vhba_attr_s attr; -}; - -struct bfa_bsg_boot_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_boot_cfg_s cfg; -}; - -struct bfa_bsg_preboot_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_boot_pbc_s cfg; -}; - -struct bfa_bsg_ethboot_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_ethboot_cfg_s cfg; -}; - -struct bfa_bsg_trunk_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_trunk_attr_s attr; -}; - -struct bfa_bsg_qos_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_qos_attr_s attr; -}; - -struct bfa_bsg_qos_vc_attr_s { - bfa_status_t status; - u16 bfad_num; - u16 rsvd; - struct bfa_qos_vc_attr_s attr; -}; - -struct bfa_bsg_vf_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - struct bfa_vf_stats_s stats; -}; - -struct bfa_bsg_vf_reset_stats_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; -}; - -struct bfa_bsg_fcpim_lunmask_query_s { - bfa_status_t status; - u16 bfad_num; - struct bfa_lunmask_cfg_s lun_mask; -}; - -struct bfa_bsg_fcpim_lunmask_s { - bfa_status_t status; - u16 bfad_num; - u16 vf_id; - wwn_t pwwn; - wwn_t rpwwn; - struct scsi_lun lun; -}; - -struct bfa_bsg_fcpt_s { - bfa_status_t status; - u16 vf_id; - wwn_t lpwwn; - wwn_t dpwwn; - u32 tsecs; - int cts; - enum fc_cos cos; - struct fchs_s fchs; -}; -#define bfa_bsg_fcpt_t struct bfa_bsg_fcpt_s - -struct bfa_bsg_data { - int payload_len; - void *payload; -}; - -#define bfad_chk_iocmd_sz(__payload_len, __hdrsz, __bufsz) \ - (((__payload_len) != ((__hdrsz) + (__bufsz))) ? \ - BFA_STATUS_FAILED : BFA_STATUS_OK) - -#endif /* BFAD_BSG_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_debugfs.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfad_debugfs.c deleted file mode 100644 index 439c012b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_debugfs.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include -#include - -#include "bfad_drv.h" -#include "bfad_im.h" - -/* - * BFA debufs interface - * - * To access the interface, debugfs file system should be mounted - * if not already mounted using: - * mount -t debugfs none /sys/kernel/debug - * - * BFA Hierarchy: - * - bfa/pci_dev: - * where the pci_name corresponds to the one under /sys/bus/pci/drivers/bfa - * - * Debugging service available per pci_dev: - * fwtrc: To collect current firmware trace. - * drvtrc: To collect current driver trace - * fwsave: To collect last saved fw trace as a result of firmware crash. - * regwr: To write one word to chip register - * regrd: To read one or more words from chip register. - */ - -struct bfad_debug_info { - char *debug_buffer; - void *i_private; - int buffer_len; -}; - -static int -bfad_debugfs_open_drvtrc(struct inode *inode, struct file *file) -{ - struct bfad_port_s *port = inode->i_private; - struct bfad_s *bfad = port->bfad; - struct bfad_debug_info *debug; - - debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); - if (!debug) - return -ENOMEM; - - debug->debug_buffer = (void *) bfad->trcmod; - debug->buffer_len = sizeof(struct bfa_trc_mod_s); - - file->private_data = debug; - - return 0; -} - -static int -bfad_debugfs_open_fwtrc(struct inode *inode, struct file *file) -{ - struct bfad_port_s *port = inode->i_private; - struct bfad_s *bfad = port->bfad; - struct bfad_debug_info *fw_debug; - unsigned long flags; - int rc; - - fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); - if (!fw_debug) - return -ENOMEM; - - fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s); - - fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len); - if (!fw_debug->debug_buffer) { - kfree(fw_debug); - printk(KERN_INFO "bfad[%d]: Failed to allocate fwtrc buffer\n", - bfad->inst_no); - return -ENOMEM; - } - - memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - rc = bfa_ioc_debug_fwtrc(&bfad->bfa.ioc, - fw_debug->debug_buffer, - &fw_debug->buffer_len); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (rc != BFA_STATUS_OK) { - vfree(fw_debug->debug_buffer); - fw_debug->debug_buffer = NULL; - kfree(fw_debug); - printk(KERN_INFO "bfad[%d]: Failed to collect fwtrc\n", - bfad->inst_no); - return -ENOMEM; - } - - file->private_data = fw_debug; - - return 0; -} - -static int -bfad_debugfs_open_fwsave(struct inode *inode, struct file *file) -{ - struct bfad_port_s *port = inode->i_private; - struct bfad_s *bfad = port->bfad; - struct bfad_debug_info *fw_debug; - unsigned long flags; - int rc; - - fw_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); - if (!fw_debug) - return -ENOMEM; - - fw_debug->buffer_len = sizeof(struct bfa_trc_mod_s); - - fw_debug->debug_buffer = vmalloc(fw_debug->buffer_len); - if (!fw_debug->debug_buffer) { - kfree(fw_debug); - printk(KERN_INFO "bfad[%d]: Failed to allocate fwsave buffer\n", - bfad->inst_no); - return -ENOMEM; - } - - memset(fw_debug->debug_buffer, 0, fw_debug->buffer_len); - - spin_lock_irqsave(&bfad->bfad_lock, flags); - rc = bfa_ioc_debug_fwsave(&bfad->bfa.ioc, - fw_debug->debug_buffer, - &fw_debug->buffer_len); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (rc != BFA_STATUS_OK) { - vfree(fw_debug->debug_buffer); - fw_debug->debug_buffer = NULL; - kfree(fw_debug); - printk(KERN_INFO "bfad[%d]: Failed to collect fwsave\n", - bfad->inst_no); - return -ENOMEM; - } - - file->private_data = fw_debug; - - return 0; -} - -static int -bfad_debugfs_open_reg(struct inode *inode, struct file *file) -{ - struct bfad_debug_info *reg_debug; - - reg_debug = kzalloc(sizeof(struct bfad_debug_info), GFP_KERNEL); - if (!reg_debug) - return -ENOMEM; - - reg_debug->i_private = inode->i_private; - - file->private_data = reg_debug; - - return 0; -} - -/* Changes the current file position */ -static loff_t -bfad_debugfs_lseek(struct file *file, loff_t offset, int orig) -{ - struct bfad_debug_info *debug; - loff_t pos = file->f_pos; - - debug = file->private_data; - - switch (orig) { - case 0: - file->f_pos = offset; - break; - case 1: - file->f_pos += offset; - break; - case 2: - file->f_pos = debug->buffer_len - offset; - break; - default: - return -EINVAL; - } - - if (file->f_pos < 0 || file->f_pos > debug->buffer_len) { - file->f_pos = pos; - return -EINVAL; - } - - return file->f_pos; -} - -static ssize_t -bfad_debugfs_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *pos) -{ - struct bfad_debug_info *debug = file->private_data; - - if (!debug || !debug->debug_buffer) - return 0; - - return simple_read_from_buffer(buf, nbytes, pos, - debug->debug_buffer, debug->buffer_len); -} - -#define BFA_REG_CT_ADDRSZ (0x40000) -#define BFA_REG_CB_ADDRSZ (0x20000) -#define BFA_REG_ADDRSZ(__ioc) \ - ((u32)(bfa_asic_id_ctc(bfa_ioc_devid(__ioc)) ? \ - BFA_REG_CT_ADDRSZ : BFA_REG_CB_ADDRSZ)) -#define BFA_REG_ADDRMSK(__ioc) (BFA_REG_ADDRSZ(__ioc) - 1) - -static bfa_status_t -bfad_reg_offset_check(struct bfa_s *bfa, u32 offset, u32 len) -{ - u8 area; - - /* check [16:15] */ - area = (offset >> 15) & 0x7; - if (area == 0) { - /* PCIe core register */ - if ((offset + (len<<2)) > 0x8000) /* 8k dwords or 32KB */ - return BFA_STATUS_EINVAL; - } else if (area == 0x1) { - /* CB 32 KB memory page */ - if ((offset + (len<<2)) > 0x10000) /* 8k dwords or 32KB */ - return BFA_STATUS_EINVAL; - } else { - /* CB register space 64KB */ - if ((offset + (len<<2)) > BFA_REG_ADDRMSK(&bfa->ioc)) - return BFA_STATUS_EINVAL; - } - return BFA_STATUS_OK; -} - -static ssize_t -bfad_debugfs_read_regrd(struct file *file, char __user *buf, - size_t nbytes, loff_t *pos) -{ - struct bfad_debug_info *regrd_debug = file->private_data; - struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private; - struct bfad_s *bfad = port->bfad; - ssize_t rc; - - if (!bfad->regdata) - return 0; - - rc = simple_read_from_buffer(buf, nbytes, pos, - bfad->regdata, bfad->reglen); - - if ((*pos + nbytes) >= bfad->reglen) { - kfree(bfad->regdata); - bfad->regdata = NULL; - bfad->reglen = 0; - } - - return rc; -} - -static ssize_t -bfad_debugfs_write_regrd(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct bfad_debug_info *regrd_debug = file->private_data; - struct bfad_port_s *port = (struct bfad_port_s *)regrd_debug->i_private; - struct bfad_s *bfad = port->bfad; - struct bfa_s *bfa = &bfad->bfa; - struct bfa_ioc_s *ioc = &bfa->ioc; - int addr, len, rc, i; - u32 *regbuf; - void __iomem *rb, *reg_addr; - unsigned long flags; - void *kern_buf; - - kern_buf = kzalloc(nbytes, GFP_KERNEL); - - if (!kern_buf) { - printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n", - bfad->inst_no); - return -ENOMEM; - } - - if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) { - kfree(kern_buf); - return -ENOMEM; - } - - rc = sscanf(kern_buf, "%x:%x", &addr, &len); - if (rc < 2) { - printk(KERN_INFO - "bfad[%d]: %s failed to read user buf\n", - bfad->inst_no, __func__); - kfree(kern_buf); - return -EINVAL; - } - - kfree(kern_buf); - kfree(bfad->regdata); - bfad->regdata = NULL; - bfad->reglen = 0; - - bfad->regdata = kzalloc(len << 2, GFP_KERNEL); - if (!bfad->regdata) { - printk(KERN_INFO "bfad[%d]: Failed to allocate regrd buffer\n", - bfad->inst_no); - return -ENOMEM; - } - - bfad->reglen = len << 2; - rb = bfa_ioc_bar0(ioc); - addr &= BFA_REG_ADDRMSK(ioc); - - /* offset and len sanity check */ - rc = bfad_reg_offset_check(bfa, addr, len); - if (rc) { - printk(KERN_INFO "bfad[%d]: Failed reg offset check\n", - bfad->inst_no); - kfree(bfad->regdata); - bfad->regdata = NULL; - bfad->reglen = 0; - return -EINVAL; - } - - reg_addr = rb + addr; - regbuf = (u32 *)bfad->regdata; - spin_lock_irqsave(&bfad->bfad_lock, flags); - for (i = 0; i < len; i++) { - *regbuf = readl(reg_addr); - regbuf++; - reg_addr += sizeof(u32); - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return nbytes; -} - -static ssize_t -bfad_debugfs_write_regwr(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct bfad_debug_info *debug = file->private_data; - struct bfad_port_s *port = (struct bfad_port_s *)debug->i_private; - struct bfad_s *bfad = port->bfad; - struct bfa_s *bfa = &bfad->bfa; - struct bfa_ioc_s *ioc = &bfa->ioc; - int addr, val, rc; - void __iomem *reg_addr; - unsigned long flags; - void *kern_buf; - - kern_buf = kzalloc(nbytes, GFP_KERNEL); - - if (!kern_buf) { - printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n", - bfad->inst_no); - return -ENOMEM; - } - - if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) { - kfree(kern_buf); - return -ENOMEM; - } - - rc = sscanf(kern_buf, "%x:%x", &addr, &val); - if (rc < 2) { - printk(KERN_INFO - "bfad[%d]: %s failed to read user buf\n", - bfad->inst_no, __func__); - kfree(kern_buf); - return -EINVAL; - } - kfree(kern_buf); - - addr &= BFA_REG_ADDRMSK(ioc); /* offset only 17 bit and word align */ - - /* offset and len sanity check */ - rc = bfad_reg_offset_check(bfa, addr, 1); - if (rc) { - printk(KERN_INFO - "bfad[%d]: Failed reg offset check\n", - bfad->inst_no); - return -EINVAL; - } - - reg_addr = (bfa_ioc_bar0(ioc)) + addr; - spin_lock_irqsave(&bfad->bfad_lock, flags); - writel(val, reg_addr); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return nbytes; -} - -static int -bfad_debugfs_release(struct inode *inode, struct file *file) -{ - struct bfad_debug_info *debug = file->private_data; - - if (!debug) - return 0; - - file->private_data = NULL; - kfree(debug); - return 0; -} - -static int -bfad_debugfs_release_fwtrc(struct inode *inode, struct file *file) -{ - struct bfad_debug_info *fw_debug = file->private_data; - - if (!fw_debug) - return 0; - - if (fw_debug->debug_buffer) - vfree(fw_debug->debug_buffer); - - file->private_data = NULL; - kfree(fw_debug); - return 0; -} - -static const struct file_operations bfad_debugfs_op_drvtrc = { - .owner = THIS_MODULE, - .open = bfad_debugfs_open_drvtrc, - .llseek = bfad_debugfs_lseek, - .read = bfad_debugfs_read, - .release = bfad_debugfs_release, -}; - -static const struct file_operations bfad_debugfs_op_fwtrc = { - .owner = THIS_MODULE, - .open = bfad_debugfs_open_fwtrc, - .llseek = bfad_debugfs_lseek, - .read = bfad_debugfs_read, - .release = bfad_debugfs_release_fwtrc, -}; - -static const struct file_operations bfad_debugfs_op_fwsave = { - .owner = THIS_MODULE, - .open = bfad_debugfs_open_fwsave, - .llseek = bfad_debugfs_lseek, - .read = bfad_debugfs_read, - .release = bfad_debugfs_release_fwtrc, -}; - -static const struct file_operations bfad_debugfs_op_regrd = { - .owner = THIS_MODULE, - .open = bfad_debugfs_open_reg, - .llseek = bfad_debugfs_lseek, - .read = bfad_debugfs_read_regrd, - .write = bfad_debugfs_write_regrd, - .release = bfad_debugfs_release, -}; - -static const struct file_operations bfad_debugfs_op_regwr = { - .owner = THIS_MODULE, - .open = bfad_debugfs_open_reg, - .llseek = bfad_debugfs_lseek, - .write = bfad_debugfs_write_regwr, - .release = bfad_debugfs_release, -}; - -struct bfad_debugfs_entry { - const char *name; - umode_t mode; - const struct file_operations *fops; -}; - -static const struct bfad_debugfs_entry bfad_debugfs_files[] = { - { "drvtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_drvtrc, }, - { "fwtrc", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwtrc, }, - { "fwsave", S_IFREG|S_IRUGO, &bfad_debugfs_op_fwsave, }, - { "regrd", S_IFREG|S_IRUGO|S_IWUSR, &bfad_debugfs_op_regrd, }, - { "regwr", S_IFREG|S_IWUSR, &bfad_debugfs_op_regwr, }, -}; - -static struct dentry *bfa_debugfs_root; -static atomic_t bfa_debugfs_port_count; - -inline void -bfad_debugfs_init(struct bfad_port_s *port) -{ - struct bfad_s *bfad = port->bfad; - const struct bfad_debugfs_entry *file; - char name[64]; - int i; - - if (!bfa_debugfs_enable) - return; - - /* Setup the BFA debugfs root directory*/ - if (!bfa_debugfs_root) { - bfa_debugfs_root = debugfs_create_dir("bfa", NULL); - atomic_set(&bfa_debugfs_port_count, 0); - if (!bfa_debugfs_root) { - printk(KERN_WARNING - "BFA debugfs root dir creation failed\n"); - goto err; - } - } - - /* Setup the pci_dev debugfs directory for the port */ - snprintf(name, sizeof(name), "pci_dev:%s", bfad->pci_name); - if (!port->port_debugfs_root) { - port->port_debugfs_root = - debugfs_create_dir(name, bfa_debugfs_root); - if (!port->port_debugfs_root) { - printk(KERN_WARNING - "bfa %s: debugfs root creation failed\n", - bfad->pci_name); - goto err; - } - - atomic_inc(&bfa_debugfs_port_count); - - for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { - file = &bfad_debugfs_files[i]; - bfad->bfad_dentry_files[i] = - debugfs_create_file(file->name, - file->mode, - port->port_debugfs_root, - port, - file->fops); - if (!bfad->bfad_dentry_files[i]) { - printk(KERN_WARNING - "bfa %s: debugfs %s creation failed\n", - bfad->pci_name, file->name); - goto err; - } - } - } - -err: - return; -} - -inline void -bfad_debugfs_exit(struct bfad_port_s *port) -{ - struct bfad_s *bfad = port->bfad; - int i; - - for (i = 0; i < ARRAY_SIZE(bfad_debugfs_files); i++) { - if (bfad->bfad_dentry_files[i]) { - debugfs_remove(bfad->bfad_dentry_files[i]); - bfad->bfad_dentry_files[i] = NULL; - } - } - - /* Remove the pci_dev debugfs directory for the port */ - if (port->port_debugfs_root) { - debugfs_remove(port->port_debugfs_root); - port->port_debugfs_root = NULL; - atomic_dec(&bfa_debugfs_port_count); - } - - /* Remove the BFA debugfs root directory */ - if (atomic_read(&bfa_debugfs_port_count) == 0) { - debugfs_remove(bfa_debugfs_root); - bfa_debugfs_root = NULL; - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_drv.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfad_drv.h deleted file mode 100644 index 7f74f1d1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_drv.h +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * Contains base driver definitions. - */ - -/* - * bfa_drv.h Linux driver data structures. - */ - -#ifndef __BFAD_DRV_H__ -#define __BFAD_DRV_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bfa_modules.h" -#include "bfa_fcs.h" -#include "bfa_defs_fcs.h" - -#include "bfa_plog.h" -#include "bfa_cs.h" - -#define BFAD_DRIVER_NAME "bfa" -#ifdef BFA_DRIVER_VERSION -#define BFAD_DRIVER_VERSION BFA_DRIVER_VERSION -#else -#define BFAD_DRIVER_VERSION "3.0.23.0" -#endif - -#define BFAD_PROTO_NAME FCPI_NAME -#define BFAD_IRQ_FLAGS IRQF_SHARED - -#ifndef FC_PORTSPEED_8GBIT -#define FC_PORTSPEED_8GBIT 0x10 -#endif - -/* - * BFAD flags - */ -#define BFAD_MSIX_ON 0x00000001 -#define BFAD_HAL_INIT_DONE 0x00000002 -#define BFAD_DRV_INIT_DONE 0x00000004 -#define BFAD_CFG_PPORT_DONE 0x00000008 -#define BFAD_HAL_START_DONE 0x00000010 -#define BFAD_PORT_ONLINE 0x00000020 -#define BFAD_RPORT_ONLINE 0x00000040 -#define BFAD_FCS_INIT_DONE 0x00000080 -#define BFAD_HAL_INIT_FAIL 0x00000100 -#define BFAD_FC4_PROBE_DONE 0x00000200 -#define BFAD_PORT_DELETE 0x00000001 -#define BFAD_INTX_ON 0x00000400 -/* - * BFAD related definition - */ -#define SCSI_SCAN_DELAY HZ -#define BFAD_STOP_TIMEOUT 30 -#define BFAD_SUSPEND_TIMEOUT BFAD_STOP_TIMEOUT - -/* - * BFAD configuration parameter default values - */ -#define BFAD_LUN_QUEUE_DEPTH 32 -#define BFAD_IO_MAX_SGE SG_ALL -#define BFAD_MIN_SECTORS 128 /* 64k */ -#define BFAD_MAX_SECTORS 0xFFFF /* 32 MB */ - -#define bfad_isr_t irq_handler_t - -#define MAX_MSIX_ENTRY 22 - -struct bfad_msix_s { - struct bfad_s *bfad; - struct msix_entry msix; - char name[32]; -}; - -/* - * Only append to the enums defined here to avoid any versioning - * needed between trace utility and driver version - */ -enum { - BFA_TRC_LDRV_BFAD = 1, - BFA_TRC_LDRV_IM = 2, - BFA_TRC_LDRV_BSG = 3, -}; - -enum bfad_port_pvb_type { - BFAD_PORT_PHYS_BASE = 0, - BFAD_PORT_PHYS_VPORT = 1, - BFAD_PORT_VF_BASE = 2, - BFAD_PORT_VF_VPORT = 3, -}; - -/* - * PORT data structure - */ -struct bfad_port_s { - struct list_head list_entry; - struct bfad_s *bfad; - struct bfa_fcs_lport_s *fcs_port; - u32 roles; - s32 flags; - u32 supported_fc4s; - enum bfad_port_pvb_type pvb_type; - struct bfad_im_port_s *im_port; /* IM specific data */ - /* port debugfs specific data */ - struct dentry *port_debugfs_root; -}; - -/* - * VPORT data structure - */ -struct bfad_vport_s { - struct bfad_port_s drv_port; - struct bfa_fcs_vport_s fcs_vport; - struct completion *comp_del; - struct list_head list_entry; -}; - -/* - * VF data structure - */ -struct bfad_vf_s { - bfa_fcs_vf_t fcs_vf; - struct bfad_port_s base_port; /* base port for vf */ - struct bfad_s *bfad; -}; - -struct bfad_cfg_param_s { - u32 rport_del_timeout; - u32 ioc_queue_depth; - u32 lun_queue_depth; - u32 io_max_sge; - u32 binding_method; -}; - -union bfad_tmp_buf { - /* From struct bfa_adapter_attr_s */ - char manufacturer[BFA_ADAPTER_MFG_NAME_LEN]; - char serial_num[BFA_ADAPTER_SERIAL_NUM_LEN]; - char model[BFA_ADAPTER_MODEL_NAME_LEN]; - char fw_ver[BFA_VERSION_LEN]; - char optrom_ver[BFA_VERSION_LEN]; - - /* From struct bfa_ioc_pci_attr_s */ - u8 chip_rev[BFA_IOC_CHIP_REV_LEN]; /* chip revision */ - - wwn_t wwn[BFA_FCS_MAX_LPORTS]; -}; - -/* - * BFAD (PCI function) data structure - */ -struct bfad_s { - bfa_sm_t sm; /* state machine */ - struct list_head list_entry; - struct bfa_s bfa; - struct bfa_fcs_s bfa_fcs; - struct pci_dev *pcidev; - const char *pci_name; - struct bfa_pcidev_s hal_pcidev; - struct bfa_ioc_pci_attr_s pci_attr; - void __iomem *pci_bar0_kva; - void __iomem *pci_bar2_kva; - struct completion comp; - struct completion suspend; - struct completion enable_comp; - struct completion disable_comp; - bfa_boolean_t disable_active; - struct bfad_port_s pport; /* physical port of the BFAD */ - struct bfa_meminfo_s meminfo; - struct bfa_iocfc_cfg_s ioc_cfg; - u32 inst_no; /* BFAD instance number */ - u32 bfad_flags; - spinlock_t bfad_lock; - struct task_struct *bfad_tsk; - struct bfad_cfg_param_s cfg_data; - struct bfad_msix_s msix_tab[MAX_MSIX_ENTRY]; - int nvec; - char adapter_name[BFA_ADAPTER_SYM_NAME_LEN]; - char port_name[BFA_ADAPTER_SYM_NAME_LEN]; - struct timer_list hal_tmo; - unsigned long hs_start; - struct bfad_im_s *im; /* IM specific data */ - struct bfa_trc_mod_s *trcmod; - struct bfa_plog_s plog_buf; - int ref_count; - union bfad_tmp_buf tmp_buf; - struct fc_host_statistics link_stats; - struct list_head pbc_vport_list; - /* debugfs specific data */ - char *regdata; - u32 reglen; - struct dentry *bfad_dentry_files[5]; - struct list_head free_aen_q; - struct list_head active_aen_q; - struct bfa_aen_entry_s aen_list[BFA_AEN_MAX_ENTRY]; - spinlock_t bfad_aen_spinlock; - struct list_head vport_list; -}; - -/* BFAD state machine events */ -enum bfad_sm_event { - BFAD_E_CREATE = 1, - BFAD_E_KTHREAD_CREATE_FAILED = 2, - BFAD_E_INIT = 3, - BFAD_E_INIT_SUCCESS = 4, - BFAD_E_INIT_FAILED = 5, - BFAD_E_INTR_INIT_FAILED = 6, - BFAD_E_FCS_EXIT_COMP = 7, - BFAD_E_EXIT_COMP = 8, - BFAD_E_STOP = 9 -}; - -/* - * RPORT data structure - */ -struct bfad_rport_s { - struct bfa_fcs_rport_s fcs_rport; -}; - -struct bfad_buf_info { - void *virt; - dma_addr_t phys; - u32 size; -}; - -struct bfad_fcxp { - struct bfad_port_s *port; - struct bfa_rport_s *bfa_rport; - bfa_status_t req_status; - u16 tag; - u16 rsp_len; - u16 rsp_maxlen; - u8 use_ireqbuf; - u8 use_irspbuf; - u32 num_req_sgles; - u32 num_rsp_sgles; - struct fchs_s fchs; - void *reqbuf_info; - void *rspbuf_info; - struct bfa_sge_s *req_sge; - struct bfa_sge_s *rsp_sge; - fcxp_send_cb_t send_cbfn; - void *send_cbarg; - void *bfa_fcxp; - struct completion comp; -}; - -struct bfad_hal_comp { - bfa_status_t status; - struct completion comp; -}; - -#define BFA_LOG(level, bfad, mask, fmt, arg...) \ -do { \ - if (((mask) == 4) || (level[1] <= '4')) \ - dev_printk(level, &((bfad)->pcidev)->dev, fmt, ##arg); \ -} while (0) - -bfa_status_t bfad_vport_create(struct bfad_s *bfad, u16 vf_id, - struct bfa_lport_cfg_s *port_cfg, - struct device *dev); -bfa_status_t bfad_vf_create(struct bfad_s *bfad, u16 vf_id, - struct bfa_lport_cfg_s *port_cfg); -bfa_status_t bfad_cfg_pport(struct bfad_s *bfad, enum bfa_lport_role role); -bfa_status_t bfad_drv_init(struct bfad_s *bfad); -bfa_status_t bfad_start_ops(struct bfad_s *bfad); -void bfad_drv_start(struct bfad_s *bfad); -void bfad_uncfg_pport(struct bfad_s *bfad); -void bfad_stop(struct bfad_s *bfad); -void bfad_fcs_stop(struct bfad_s *bfad); -void bfad_remove_intr(struct bfad_s *bfad); -void bfad_hal_mem_release(struct bfad_s *bfad); -void bfad_hcb_comp(void *arg, bfa_status_t status); - -int bfad_setup_intr(struct bfad_s *bfad); -void bfad_remove_intr(struct bfad_s *bfad); -void bfad_update_hal_cfg(struct bfa_iocfc_cfg_s *bfa_cfg); -bfa_status_t bfad_hal_mem_alloc(struct bfad_s *bfad); -void bfad_bfa_tmo(unsigned long data); -void bfad_init_timer(struct bfad_s *bfad); -int bfad_pci_init(struct pci_dev *pdev, struct bfad_s *bfad); -void bfad_pci_uninit(struct pci_dev *pdev, struct bfad_s *bfad); -void bfad_drv_uninit(struct bfad_s *bfad); -int bfad_worker(void *ptr); -void bfad_debugfs_init(struct bfad_port_s *port); -void bfad_debugfs_exit(struct bfad_port_s *port); - -void bfad_pci_remove(struct pci_dev *pdev); -int bfad_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pid); -void bfad_rport_online_wait(struct bfad_s *bfad); -int bfad_get_linkup_delay(struct bfad_s *bfad); -int bfad_install_msix_handler(struct bfad_s *bfad); - -extern struct idr bfad_im_port_index; -extern struct pci_device_id bfad_id_table[]; -extern struct list_head bfad_list; -extern char *os_name; -extern char *os_patch; -extern char *host_name; -extern int num_rports; -extern int num_ios; -extern int num_tms; -extern int num_fcxps; -extern int num_ufbufs; -extern int reqq_size; -extern int rspq_size; -extern int num_sgpgs; -extern int rport_del_timeout; -extern int bfa_lun_queue_depth; -extern int bfa_io_max_sge; -extern int bfa_log_level; -extern int ioc_auto_recover; -extern int bfa_linkup_delay; -extern int msix_disable_cb; -extern int msix_disable_ct; -extern int fdmi_enable; -extern int supported_fc4s; -extern int pcie_max_read_reqsz; -extern int max_xfer_size; -extern int bfa_debugfs_enable; -extern struct mutex bfad_mutex; - -#endif /* __BFAD_DRV_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.c b/ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.c deleted file mode 100644 index 3153923f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.c +++ /dev/null @@ -1,1323 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * bfad_im.c Linux driver IM module. - */ - -#include - -#include "bfad_drv.h" -#include "bfad_im.h" -#include "bfa_fcs.h" - -BFA_TRC_FILE(LDRV, IM); - -DEFINE_IDR(bfad_im_port_index); -struct scsi_transport_template *bfad_im_scsi_transport_template; -struct scsi_transport_template *bfad_im_scsi_vport_transport_template; -static void bfad_im_itnim_work_handler(struct work_struct *work); -static int bfad_im_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmnd); -static int bfad_im_slave_alloc(struct scsi_device *sdev); -static void bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, - struct bfad_itnim_s *itnim); - -void -bfa_cb_ioim_done(void *drv, struct bfad_ioim_s *dio, - enum bfi_ioim_status io_status, u8 scsi_status, - int sns_len, u8 *sns_info, s32 residue) -{ - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; - struct bfad_s *bfad = drv; - struct bfad_itnim_data_s *itnim_data; - struct bfad_itnim_s *itnim; - u8 host_status = DID_OK; - - switch (io_status) { - case BFI_IOIM_STS_OK: - bfa_trc(bfad, scsi_status); - scsi_set_resid(cmnd, 0); - - if (sns_len > 0) { - bfa_trc(bfad, sns_len); - if (sns_len > SCSI_SENSE_BUFFERSIZE) - sns_len = SCSI_SENSE_BUFFERSIZE; - memcpy(cmnd->sense_buffer, sns_info, sns_len); - } - - if (residue > 0) { - bfa_trc(bfad, residue); - scsi_set_resid(cmnd, residue); - if (!sns_len && (scsi_status == SAM_STAT_GOOD) && - (scsi_bufflen(cmnd) - residue) < - cmnd->underflow) { - bfa_trc(bfad, 0); - host_status = DID_ERROR; - } - } - cmnd->result = ScsiResult(host_status, scsi_status); - - break; - - case BFI_IOIM_STS_ABORTED: - case BFI_IOIM_STS_TIMEDOUT: - case BFI_IOIM_STS_PATHTOV: - default: - host_status = DID_ERROR; - cmnd->result = ScsiResult(host_status, 0); - } - - /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */ - if (cmnd->device->host != NULL) - scsi_dma_unmap(cmnd); - - cmnd->host_scribble = NULL; - bfa_trc(bfad, cmnd->result); - - itnim_data = cmnd->device->hostdata; - if (itnim_data) { - itnim = itnim_data->itnim; - if (!cmnd->result && itnim && - (bfa_lun_queue_depth > cmnd->device->queue_depth)) { - /* Queue depth adjustment for good status completion */ - bfad_ramp_up_qdepth(itnim, cmnd->device); - } else if (cmnd->result == SAM_STAT_TASK_SET_FULL && itnim) { - /* qfull handling */ - bfad_handle_qfull(itnim, cmnd->device); - } - } - - cmnd->scsi_done(cmnd); -} - -void -bfa_cb_ioim_good_comp(void *drv, struct bfad_ioim_s *dio) -{ - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; - struct bfad_itnim_data_s *itnim_data; - struct bfad_itnim_s *itnim; - - cmnd->result = ScsiResult(DID_OK, SCSI_STATUS_GOOD); - - /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */ - if (cmnd->device->host != NULL) - scsi_dma_unmap(cmnd); - - cmnd->host_scribble = NULL; - - /* Queue depth adjustment */ - if (bfa_lun_queue_depth > cmnd->device->queue_depth) { - itnim_data = cmnd->device->hostdata; - if (itnim_data) { - itnim = itnim_data->itnim; - if (itnim) - bfad_ramp_up_qdepth(itnim, cmnd->device); - } - } - - cmnd->scsi_done(cmnd); -} - -void -bfa_cb_ioim_abort(void *drv, struct bfad_ioim_s *dio) -{ - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dio; - struct bfad_s *bfad = drv; - - cmnd->result = ScsiResult(DID_ERROR, 0); - - /* Unmap DMA, if host is NULL, it means a scsi passthru cmd */ - if (cmnd->device->host != NULL) - scsi_dma_unmap(cmnd); - - bfa_trc(bfad, cmnd->result); - cmnd->host_scribble = NULL; -} - -void -bfa_cb_tskim_done(void *bfad, struct bfad_tskim_s *dtsk, - enum bfi_tskim_status tsk_status) -{ - struct scsi_cmnd *cmnd = (struct scsi_cmnd *)dtsk; - wait_queue_head_t *wq; - - cmnd->SCp.Status |= tsk_status << 1; - set_bit(IO_DONE_BIT, (unsigned long *)&cmnd->SCp.Status); - wq = (wait_queue_head_t *) cmnd->SCp.ptr; - cmnd->SCp.ptr = NULL; - - if (wq) - wake_up(wq); -} - -/* - * Scsi_Host_template SCSI host template - */ -/* - * Scsi_Host template entry, returns BFAD PCI info. - */ -static const char * -bfad_im_info(struct Scsi_Host *shost) -{ - static char bfa_buf[256]; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - - memset(bfa_buf, 0, sizeof(bfa_buf)); - snprintf(bfa_buf, sizeof(bfa_buf), - "Brocade FC/FCOE Adapter, " "hwpath: %s driver: %s", - bfad->pci_name, BFAD_DRIVER_VERSION); - - return bfa_buf; -} - -/* - * Scsi_Host template entry, aborts the specified SCSI command. - * - * Returns: SUCCESS or FAILED. - */ -static int -bfad_im_abort_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfa_ioim_s *hal_io; - unsigned long flags; - u32 timeout; - int rc = FAILED; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - hal_io = (struct bfa_ioim_s *) cmnd->host_scribble; - if (!hal_io) { - /* IO has been completed, retrun success */ - rc = SUCCESS; - goto out; - } - if (hal_io->dio != (struct bfad_ioim_s *) cmnd) { - rc = FAILED; - goto out; - } - - bfa_trc(bfad, hal_io->iotag); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "scsi%d: abort cmnd %p iotag %x\n", - im_port->shost->host_no, cmnd, hal_io->iotag); - (void) bfa_ioim_abort(hal_io); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - /* Need to wait until the command get aborted */ - timeout = 10; - while ((struct bfa_ioim_s *) cmnd->host_scribble == hal_io) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(timeout); - if (timeout < 4 * HZ) - timeout *= 2; - } - - cmnd->scsi_done(cmnd); - bfa_trc(bfad, hal_io->iotag); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "scsi%d: complete abort 0x%p iotag 0x%x\n", - im_port->shost->host_no, cmnd, hal_io->iotag); - return SUCCESS; -out: - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - return rc; -} - -static bfa_status_t -bfad_im_target_reset_send(struct bfad_s *bfad, struct scsi_cmnd *cmnd, - struct bfad_itnim_s *itnim) -{ - struct bfa_tskim_s *tskim; - struct bfa_itnim_s *bfa_itnim; - bfa_status_t rc = BFA_STATUS_OK; - struct scsi_lun scsilun; - - tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); - if (!tskim) { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "target reset, fail to allocate tskim\n"); - rc = BFA_STATUS_FAILED; - goto out; - } - - /* - * Set host_scribble to NULL to avoid aborting a task command if - * happens. - */ - cmnd->host_scribble = NULL; - cmnd->SCp.Status = 0; - bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim); - memset(&scsilun, 0, sizeof(scsilun)); - bfa_tskim_start(tskim, bfa_itnim, scsilun, - FCP_TM_TARGET_RESET, BFAD_TARGET_RESET_TMO); -out: - return rc; -} - -/* - * Scsi_Host template entry, resets a LUN and abort its all commands. - * - * Returns: SUCCESS or FAILED. - * - */ -static int -bfad_im_reset_lun_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata; - struct bfad_s *bfad = im_port->bfad; - struct bfa_tskim_s *tskim; - struct bfad_itnim_s *itnim; - struct bfa_itnim_s *bfa_itnim; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - int rc = SUCCESS; - unsigned long flags; - enum bfi_tskim_status task_status; - struct scsi_lun scsilun; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - itnim = itnim_data->itnim; - if (!itnim) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - rc = FAILED; - goto out; - } - - tskim = bfa_tskim_alloc(&bfad->bfa, (struct bfad_tskim_s *) cmnd); - if (!tskim) { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "LUN reset, fail to allocate tskim"); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - rc = FAILED; - goto out; - } - - /* - * Set host_scribble to NULL to avoid aborting a task command - * if happens. - */ - cmnd->host_scribble = NULL; - cmnd->SCp.ptr = (char *)&wq; - cmnd->SCp.Status = 0; - bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim->fcs_itnim); - int_to_scsilun(cmnd->device->lun, &scsilun); - bfa_tskim_start(tskim, bfa_itnim, scsilun, - FCP_TM_LUN_RESET, BFAD_LUN_RESET_TMO); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - wait_event(wq, test_bit(IO_DONE_BIT, - (unsigned long *)&cmnd->SCp.Status)); - - task_status = cmnd->SCp.Status >> 1; - if (task_status != BFI_TSKIM_STS_OK) { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "LUN reset failure, status: %d\n", task_status); - rc = FAILED; - } - -out: - return rc; -} - -/* - * Scsi_Host template entry, resets the bus and abort all commands. - */ -static int -bfad_im_reset_bus_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) shost->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfad_itnim_s *itnim; - unsigned long flags; - u32 i, rc, err_cnt = 0; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - enum bfi_tskim_status task_status; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - for (i = 0; i < MAX_FCP_TARGET; i++) { - itnim = bfad_get_itnim(im_port, i); - if (itnim) { - cmnd->SCp.ptr = (char *)&wq; - rc = bfad_im_target_reset_send(bfad, cmnd, itnim); - if (rc != BFA_STATUS_OK) { - err_cnt++; - continue; - } - - /* wait target reset to complete */ - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - wait_event(wq, test_bit(IO_DONE_BIT, - (unsigned long *)&cmnd->SCp.Status)); - spin_lock_irqsave(&bfad->bfad_lock, flags); - - task_status = cmnd->SCp.Status >> 1; - if (task_status != BFI_TSKIM_STS_OK) { - BFA_LOG(KERN_ERR, bfad, bfa_log_level, - "target reset failure," - " status: %d\n", task_status); - err_cnt++; - } - } - } - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - if (err_cnt) - return FAILED; - - return SUCCESS; -} - -/* - * Scsi_Host template entry slave_destroy. - */ -static void -bfad_im_slave_destroy(struct scsi_device *sdev) -{ - sdev->hostdata = NULL; - return; -} - -/* - * BFA FCS itnim callbacks - */ - -/* - * BFA FCS itnim alloc callback, after successful PRLI - * Context: Interrupt - */ -void -bfa_fcb_itnim_alloc(struct bfad_s *bfad, struct bfa_fcs_itnim_s **itnim, - struct bfad_itnim_s **itnim_drv) -{ - *itnim_drv = kzalloc(sizeof(struct bfad_itnim_s), GFP_ATOMIC); - if (*itnim_drv == NULL) - return; - - (*itnim_drv)->im = bfad->im; - *itnim = &(*itnim_drv)->fcs_itnim; - (*itnim_drv)->state = ITNIM_STATE_NONE; - - /* - * Initiaze the itnim_work - */ - INIT_WORK(&(*itnim_drv)->itnim_work, bfad_im_itnim_work_handler); - bfad->bfad_flags |= BFAD_RPORT_ONLINE; -} - -/* - * BFA FCS itnim free callback. - * Context: Interrupt. bfad_lock is held - */ -void -bfa_fcb_itnim_free(struct bfad_s *bfad, struct bfad_itnim_s *itnim_drv) -{ - struct bfad_port_s *port; - wwn_t wwpn; - u32 fcid; - char wwpn_str[32], fcid_str[16]; - struct bfad_im_s *im = itnim_drv->im; - - /* online to free state transtion should not happen */ - WARN_ON(itnim_drv->state == ITNIM_STATE_ONLINE); - - itnim_drv->queue_work = 1; - /* offline request is not yet done, use the same request to free */ - if (itnim_drv->state == ITNIM_STATE_OFFLINE_PENDING) - itnim_drv->queue_work = 0; - - itnim_drv->state = ITNIM_STATE_FREE; - port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); - itnim_drv->im_port = port->im_port; - wwpn = bfa_fcs_itnim_get_pwwn(&itnim_drv->fcs_itnim); - fcid = bfa_fcs_itnim_get_fcid(&itnim_drv->fcs_itnim); - wwn2str(wwpn_str, wwpn); - fcid2str(fcid_str, fcid); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "ITNIM FREE scsi%d: FCID: %s WWPN: %s\n", - port->im_port->shost->host_no, - fcid_str, wwpn_str); - - /* ITNIM processing */ - if (itnim_drv->queue_work) - queue_work(im->drv_workq, &itnim_drv->itnim_work); -} - -/* - * BFA FCS itnim online callback. - * Context: Interrupt. bfad_lock is held - */ -void -bfa_fcb_itnim_online(struct bfad_itnim_s *itnim_drv) -{ - struct bfad_port_s *port; - struct bfad_im_s *im = itnim_drv->im; - - itnim_drv->bfa_itnim = bfa_fcs_itnim_get_halitn(&itnim_drv->fcs_itnim); - port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); - itnim_drv->state = ITNIM_STATE_ONLINE; - itnim_drv->queue_work = 1; - itnim_drv->im_port = port->im_port; - - /* ITNIM processing */ - if (itnim_drv->queue_work) - queue_work(im->drv_workq, &itnim_drv->itnim_work); -} - -/* - * BFA FCS itnim offline callback. - * Context: Interrupt. bfad_lock is held - */ -void -bfa_fcb_itnim_offline(struct bfad_itnim_s *itnim_drv) -{ - struct bfad_port_s *port; - struct bfad_s *bfad; - struct bfad_im_s *im = itnim_drv->im; - - port = bfa_fcs_itnim_get_drvport(&itnim_drv->fcs_itnim); - bfad = port->bfad; - if ((bfad->pport.flags & BFAD_PORT_DELETE) || - (port->flags & BFAD_PORT_DELETE)) { - itnim_drv->state = ITNIM_STATE_OFFLINE; - return; - } - itnim_drv->im_port = port->im_port; - itnim_drv->state = ITNIM_STATE_OFFLINE_PENDING; - itnim_drv->queue_work = 1; - - /* ITNIM processing */ - if (itnim_drv->queue_work) - queue_work(im->drv_workq, &itnim_drv->itnim_work); -} - -/* - * Allocate a Scsi_Host for a port. - */ -int -bfad_im_scsi_host_alloc(struct bfad_s *bfad, struct bfad_im_port_s *im_port, - struct device *dev) -{ - int error = 1; - - mutex_lock(&bfad_mutex); - if (!idr_pre_get(&bfad_im_port_index, GFP_KERNEL)) { - mutex_unlock(&bfad_mutex); - printk(KERN_WARNING "idr_pre_get failure\n"); - goto out; - } - - error = idr_get_new(&bfad_im_port_index, im_port, - &im_port->idr_id); - if (error) { - mutex_unlock(&bfad_mutex); - printk(KERN_WARNING "idr_get_new failure\n"); - goto out; - } - - mutex_unlock(&bfad_mutex); - - im_port->shost = bfad_scsi_host_alloc(im_port, bfad); - if (!im_port->shost) { - error = 1; - goto out_free_idr; - } - - im_port->shost->hostdata[0] = (unsigned long)im_port; - im_port->shost->unique_id = im_port->idr_id; - im_port->shost->this_id = -1; - im_port->shost->max_id = MAX_FCP_TARGET; - im_port->shost->max_lun = MAX_FCP_LUN; - im_port->shost->max_cmd_len = 16; - im_port->shost->can_queue = bfad->cfg_data.ioc_queue_depth; - if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE) - im_port->shost->transportt = bfad_im_scsi_transport_template; - else - im_port->shost->transportt = - bfad_im_scsi_vport_transport_template; - - error = scsi_add_host_with_dma(im_port->shost, dev, &bfad->pcidev->dev); - if (error) { - printk(KERN_WARNING "scsi_add_host failure %d\n", error); - goto out_fc_rel; - } - - return 0; - -out_fc_rel: - scsi_host_put(im_port->shost); - im_port->shost = NULL; -out_free_idr: - mutex_lock(&bfad_mutex); - idr_remove(&bfad_im_port_index, im_port->idr_id); - mutex_unlock(&bfad_mutex); -out: - return error; -} - -void -bfad_im_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) -{ - bfa_trc(bfad, bfad->inst_no); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, "Free scsi%d\n", - im_port->shost->host_no); - - fc_remove_host(im_port->shost); - - scsi_remove_host(im_port->shost); - scsi_host_put(im_port->shost); - - mutex_lock(&bfad_mutex); - idr_remove(&bfad_im_port_index, im_port->idr_id); - mutex_unlock(&bfad_mutex); -} - -static void -bfad_im_port_delete_handler(struct work_struct *work) -{ - struct bfad_im_port_s *im_port = - container_of(work, struct bfad_im_port_s, port_delete_work); - - if (im_port->port->pvb_type != BFAD_PORT_PHYS_BASE) { - im_port->flags |= BFAD_PORT_DELETE; - fc_vport_terminate(im_port->fc_vport); - } -} - -bfa_status_t -bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port) -{ - int rc = BFA_STATUS_OK; - struct bfad_im_port_s *im_port; - - im_port = kzalloc(sizeof(struct bfad_im_port_s), GFP_ATOMIC); - if (im_port == NULL) { - rc = BFA_STATUS_ENOMEM; - goto ext; - } - port->im_port = im_port; - im_port->port = port; - im_port->bfad = bfad; - - INIT_WORK(&im_port->port_delete_work, bfad_im_port_delete_handler); - INIT_LIST_HEAD(&im_port->itnim_mapped_list); - INIT_LIST_HEAD(&im_port->binding_list); - -ext: - return rc; -} - -void -bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port) -{ - struct bfad_im_port_s *im_port = port->im_port; - - queue_work(bfad->im->drv_workq, - &im_port->port_delete_work); -} - -void -bfad_im_port_clean(struct bfad_im_port_s *im_port) -{ - struct bfad_fcp_binding *bp, *bp_new; - unsigned long flags; - struct bfad_s *bfad = im_port->bfad; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - list_for_each_entry_safe(bp, bp_new, &im_port->binding_list, - list_entry) { - list_del(&bp->list_entry); - kfree(bp); - } - - /* the itnim_mapped_list must be empty at this time */ - WARN_ON(!list_empty(&im_port->itnim_mapped_list)); - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); -} - -static void bfad_aen_im_notify_handler(struct work_struct *work) -{ - struct bfad_im_s *im = - container_of(work, struct bfad_im_s, aen_im_notify_work); - struct bfa_aen_entry_s *aen_entry; - struct bfad_s *bfad = im->bfad; - struct Scsi_Host *shost = bfad->pport.im_port->shost; - void *event_data; - unsigned long flags; - - while (!list_empty(&bfad->active_aen_q)) { - spin_lock_irqsave(&bfad->bfad_aen_spinlock, flags); - bfa_q_deq(&bfad->active_aen_q, &aen_entry); - spin_unlock_irqrestore(&bfad->bfad_aen_spinlock, flags); - event_data = (char *)aen_entry + sizeof(struct list_head); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(struct bfa_aen_entry_s) - - sizeof(struct list_head), - (char *)event_data, BFAD_NL_VENDOR_ID); - spin_lock_irqsave(&bfad->bfad_aen_spinlock, flags); - list_add_tail(&aen_entry->qe, &bfad->free_aen_q); - spin_unlock_irqrestore(&bfad->bfad_aen_spinlock, flags); - } -} - -bfa_status_t -bfad_im_probe(struct bfad_s *bfad) -{ - struct bfad_im_s *im; - bfa_status_t rc = BFA_STATUS_OK; - - im = kzalloc(sizeof(struct bfad_im_s), GFP_KERNEL); - if (im == NULL) { - rc = BFA_STATUS_ENOMEM; - goto ext; - } - - bfad->im = im; - im->bfad = bfad; - - if (bfad_thread_workq(bfad) != BFA_STATUS_OK) { - kfree(im); - rc = BFA_STATUS_FAILED; - } - - INIT_WORK(&im->aen_im_notify_work, bfad_aen_im_notify_handler); -ext: - return rc; -} - -void -bfad_im_probe_undo(struct bfad_s *bfad) -{ - if (bfad->im) { - bfad_destroy_workq(bfad->im); - kfree(bfad->im); - bfad->im = NULL; - } -} - -struct Scsi_Host * -bfad_scsi_host_alloc(struct bfad_im_port_s *im_port, struct bfad_s *bfad) -{ - struct scsi_host_template *sht; - - if (im_port->port->pvb_type == BFAD_PORT_PHYS_BASE) - sht = &bfad_im_scsi_host_template; - else - sht = &bfad_im_vport_template; - - if (max_xfer_size != BFAD_MAX_SECTORS >> 1) - sht->max_sectors = max_xfer_size << 1; - - sht->sg_tablesize = bfad->cfg_data.io_max_sge; - - return scsi_host_alloc(sht, sizeof(unsigned long)); -} - -void -bfad_scsi_host_free(struct bfad_s *bfad, struct bfad_im_port_s *im_port) -{ - if (!(im_port->flags & BFAD_PORT_DELETE)) - flush_workqueue(bfad->im->drv_workq); - bfad_im_scsi_host_free(im_port->bfad, im_port); - bfad_im_port_clean(im_port); - kfree(im_port); -} - -void -bfad_destroy_workq(struct bfad_im_s *im) -{ - if (im && im->drv_workq) { - flush_workqueue(im->drv_workq); - destroy_workqueue(im->drv_workq); - im->drv_workq = NULL; - } -} - -bfa_status_t -bfad_thread_workq(struct bfad_s *bfad) -{ - struct bfad_im_s *im = bfad->im; - - bfa_trc(bfad, 0); - snprintf(im->drv_workq_name, KOBJ_NAME_LEN, "bfad_wq_%d", - bfad->inst_no); - im->drv_workq = create_singlethread_workqueue(im->drv_workq_name); - if (!im->drv_workq) - return BFA_STATUS_FAILED; - - return BFA_STATUS_OK; -} - -/* - * Scsi_Host template entry. - * - * Description: - * OS entry point to adjust the queue_depths on a per-device basis. - * Called once per device during the bus scan. - * Return non-zero if fails. - */ -static int -bfad_im_slave_configure(struct scsi_device *sdev) -{ - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, bfa_lun_queue_depth); - else - scsi_deactivate_tcq(sdev, bfa_lun_queue_depth); - - return 0; -} - -struct scsi_host_template bfad_im_scsi_host_template = { - .module = THIS_MODULE, - .name = BFAD_DRIVER_NAME, - .info = bfad_im_info, - .queuecommand = bfad_im_queuecommand, - .eh_abort_handler = bfad_im_abort_handler, - .eh_device_reset_handler = bfad_im_reset_lun_handler, - .eh_bus_reset_handler = bfad_im_reset_bus_handler, - - .slave_alloc = bfad_im_slave_alloc, - .slave_configure = bfad_im_slave_configure, - .slave_destroy = bfad_im_slave_destroy, - - .this_id = -1, - .sg_tablesize = BFAD_IO_MAX_SGE, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = bfad_im_host_attrs, - .max_sectors = BFAD_MAX_SECTORS, - .vendor_id = BFA_PCI_VENDOR_ID_BROCADE, -}; - -struct scsi_host_template bfad_im_vport_template = { - .module = THIS_MODULE, - .name = BFAD_DRIVER_NAME, - .info = bfad_im_info, - .queuecommand = bfad_im_queuecommand, - .eh_abort_handler = bfad_im_abort_handler, - .eh_device_reset_handler = bfad_im_reset_lun_handler, - .eh_bus_reset_handler = bfad_im_reset_bus_handler, - - .slave_alloc = bfad_im_slave_alloc, - .slave_configure = bfad_im_slave_configure, - .slave_destroy = bfad_im_slave_destroy, - - .this_id = -1, - .sg_tablesize = BFAD_IO_MAX_SGE, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = bfad_im_vport_attrs, - .max_sectors = BFAD_MAX_SECTORS, -}; - -bfa_status_t -bfad_im_module_init(void) -{ - bfad_im_scsi_transport_template = - fc_attach_transport(&bfad_im_fc_function_template); - if (!bfad_im_scsi_transport_template) - return BFA_STATUS_ENOMEM; - - bfad_im_scsi_vport_transport_template = - fc_attach_transport(&bfad_im_vport_fc_function_template); - if (!bfad_im_scsi_vport_transport_template) { - fc_release_transport(bfad_im_scsi_transport_template); - return BFA_STATUS_ENOMEM; - } - - return BFA_STATUS_OK; -} - -void -bfad_im_module_exit(void) -{ - if (bfad_im_scsi_transport_template) - fc_release_transport(bfad_im_scsi_transport_template); - - if (bfad_im_scsi_vport_transport_template) - fc_release_transport(bfad_im_scsi_vport_transport_template); -} - -void -bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev) -{ - struct scsi_device *tmp_sdev; - - if (((jiffies - itnim->last_ramp_up_time) > - BFA_QUEUE_FULL_RAMP_UP_TIME * HZ) && - ((jiffies - itnim->last_queue_full_time) > - BFA_QUEUE_FULL_RAMP_UP_TIME * HZ)) { - shost_for_each_device(tmp_sdev, sdev->host) { - if (bfa_lun_queue_depth > tmp_sdev->queue_depth) { - if (tmp_sdev->id != sdev->id) - continue; - if (tmp_sdev->ordered_tags) - scsi_adjust_queue_depth(tmp_sdev, - MSG_ORDERED_TAG, - tmp_sdev->queue_depth + 1); - else - scsi_adjust_queue_depth(tmp_sdev, - MSG_SIMPLE_TAG, - tmp_sdev->queue_depth + 1); - - itnim->last_ramp_up_time = jiffies; - } - } - } -} - -void -bfad_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev) -{ - struct scsi_device *tmp_sdev; - - itnim->last_queue_full_time = jiffies; - - shost_for_each_device(tmp_sdev, sdev->host) { - if (tmp_sdev->id != sdev->id) - continue; - scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1); - } -} - -struct bfad_itnim_s * -bfad_get_itnim(struct bfad_im_port_s *im_port, int id) -{ - struct bfad_itnim_s *itnim = NULL; - - /* Search the mapped list for this target ID */ - list_for_each_entry(itnim, &im_port->itnim_mapped_list, list_entry) { - if (id == itnim->scsi_tgt_id) - return itnim; - } - - return NULL; -} - -/* - * Function is invoked from the SCSI Host Template slave_alloc() entry point. - * Has the logic to query the LUN Mask database to check if this LUN needs to - * be made visible to the SCSI mid-layer or not. - * - * Returns BFA_STATUS_OK if this LUN needs to be added to the OS stack. - * Returns -ENXIO to notify SCSI mid-layer to not add this LUN to the OS stack. - */ -static int -bfad_im_check_if_make_lun_visible(struct scsi_device *sdev, - struct fc_rport *rport) -{ - struct bfad_itnim_data_s *itnim_data = - (struct bfad_itnim_data_s *) rport->dd_data; - struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa; - struct bfa_rport_s *bfa_rport = itnim_data->itnim->bfa_itnim->rport; - struct bfa_lun_mask_s *lun_list = bfa_get_lun_mask_list(bfa); - int i = 0, ret = -ENXIO; - - for (i = 0; i < MAX_LUN_MASK_CFG; i++) { - if (lun_list[i].state == BFA_IOIM_LUN_MASK_ACTIVE && - scsilun_to_int(&lun_list[i].lun) == sdev->lun && - lun_list[i].rp_tag == bfa_rport->rport_tag && - lun_list[i].lp_tag == (u8)bfa_rport->rport_info.lp_tag) { - ret = BFA_STATUS_OK; - break; - } - } - return ret; -} - -/* - * Scsi_Host template entry slave_alloc - */ -static int -bfad_im_slave_alloc(struct scsi_device *sdev) -{ - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - struct bfad_itnim_data_s *itnim_data = - (struct bfad_itnim_data_s *) rport->dd_data; - struct bfa_s *bfa = itnim_data->itnim->bfa_itnim->bfa; - - if (!rport || fc_remote_port_chkready(rport)) - return -ENXIO; - - if (bfa_get_lun_mask_status(bfa) == BFA_LUNMASK_ENABLED) { - /* - * We should not mask LUN 0 - since this will translate - * to no LUN / TARGET for SCSI ml resulting no scan. - */ - if (sdev->lun == 0) { - sdev->sdev_bflags |= BLIST_NOREPORTLUN | - BLIST_SPARSELUN; - goto done; - } - - /* - * Query LUN Mask configuration - to expose this LUN - * to the SCSI mid-layer or to mask it. - */ - if (bfad_im_check_if_make_lun_visible(sdev, rport) != - BFA_STATUS_OK) - return -ENXIO; - } -done: - sdev->hostdata = rport->dd_data; - - return 0; -} - -static u32 -bfad_im_supported_speeds(struct bfa_s *bfa) -{ - struct bfa_ioc_attr_s *ioc_attr; - u32 supported_speed = 0; - - ioc_attr = kzalloc(sizeof(struct bfa_ioc_attr_s), GFP_KERNEL); - if (!ioc_attr) - return 0; - - bfa_ioc_get_attr(&bfa->ioc, ioc_attr); - if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_16GBPS) - supported_speed |= FC_PORTSPEED_16GBIT | FC_PORTSPEED_8GBIT | - FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT; - else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_8GBPS) { - if (ioc_attr->adapter_attr.is_mezz) { - supported_speed |= FC_PORTSPEED_8GBIT | - FC_PORTSPEED_4GBIT | - FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; - } else { - supported_speed |= FC_PORTSPEED_8GBIT | - FC_PORTSPEED_4GBIT | - FC_PORTSPEED_2GBIT; - } - } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_4GBPS) { - supported_speed |= FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | - FC_PORTSPEED_1GBIT; - } else if (ioc_attr->adapter_attr.max_speed == BFA_PORT_SPEED_10GBPS) { - supported_speed |= FC_PORTSPEED_10GBIT; - } - kfree(ioc_attr); - return supported_speed; -} - -void -bfad_fc_host_init(struct bfad_im_port_s *im_port) -{ - struct Scsi_Host *host = im_port->shost; - struct bfad_s *bfad = im_port->bfad; - struct bfad_port_s *port = im_port->port; - char symname[BFA_SYMNAME_MAXLEN]; - struct bfa_fcport_s *fcport = BFA_FCPORT_MOD(&bfad->bfa); - - fc_host_node_name(host) = - cpu_to_be64((bfa_fcs_lport_get_nwwn(port->fcs_port))); - fc_host_port_name(host) = - cpu_to_be64((bfa_fcs_lport_get_pwwn(port->fcs_port))); - fc_host_max_npiv_vports(host) = bfa_lps_get_max_vport(&bfad->bfa); - - fc_host_supported_classes(host) = FC_COS_CLASS3; - - memset(fc_host_supported_fc4s(host), 0, - sizeof(fc_host_supported_fc4s(host))); - if (supported_fc4s & BFA_LPORT_ROLE_FCP_IM) - /* For FCP type 0x08 */ - fc_host_supported_fc4s(host)[2] = 1; - /* For fibre channel services type 0x20 */ - fc_host_supported_fc4s(host)[7] = 1; - - strncpy(symname, bfad->bfa_fcs.fabric.bport.port_cfg.sym_name.symname, - BFA_SYMNAME_MAXLEN); - sprintf(fc_host_symbolic_name(host), "%s", symname); - - fc_host_supported_speeds(host) = bfad_im_supported_speeds(&bfad->bfa); - fc_host_maxframe_size(host) = fcport->cfg.maxfrsize; -} - -static void -bfad_im_fc_rport_add(struct bfad_im_port_s *im_port, struct bfad_itnim_s *itnim) -{ - struct fc_rport_identifiers rport_ids; - struct fc_rport *fc_rport; - struct bfad_itnim_data_s *itnim_data; - - rport_ids.node_name = - cpu_to_be64(bfa_fcs_itnim_get_nwwn(&itnim->fcs_itnim)); - rport_ids.port_name = - cpu_to_be64(bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim)); - rport_ids.port_id = - bfa_hton3b(bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim)); - rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; - - itnim->fc_rport = fc_rport = - fc_remote_port_add(im_port->shost, 0, &rport_ids); - - if (!fc_rport) - return; - - fc_rport->maxframe_size = - bfa_fcs_itnim_get_maxfrsize(&itnim->fcs_itnim); - fc_rport->supported_classes = bfa_fcs_itnim_get_cos(&itnim->fcs_itnim); - - itnim_data = fc_rport->dd_data; - itnim_data->itnim = itnim; - - rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; - - if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) - fc_remote_port_rolechg(fc_rport, rport_ids.roles); - - if ((fc_rport->scsi_target_id != -1) - && (fc_rport->scsi_target_id < MAX_FCP_TARGET)) - itnim->scsi_tgt_id = fc_rport->scsi_target_id; - - itnim->channel = fc_rport->channel; - - return; -} - -/* - * Work queue handler using FC transport service -* Context: kernel - */ -static void -bfad_im_itnim_work_handler(struct work_struct *work) -{ - struct bfad_itnim_s *itnim = container_of(work, struct bfad_itnim_s, - itnim_work); - struct bfad_im_s *im = itnim->im; - struct bfad_s *bfad = im->bfad; - struct bfad_im_port_s *im_port; - unsigned long flags; - struct fc_rport *fc_rport; - wwn_t wwpn; - u32 fcid; - char wwpn_str[32], fcid_str[16]; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - im_port = itnim->im_port; - bfa_trc(bfad, itnim->state); - switch (itnim->state) { - case ITNIM_STATE_ONLINE: - if (!itnim->fc_rport) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - bfad_im_fc_rport_add(im_port, itnim); - spin_lock_irqsave(&bfad->bfad_lock, flags); - wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim); - fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim); - wwn2str(wwpn_str, wwpn); - fcid2str(fcid_str, fcid); - list_add_tail(&itnim->list_entry, - &im_port->itnim_mapped_list); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "ITNIM ONLINE Target: %d:0:%d " - "FCID: %s WWPN: %s\n", - im_port->shost->host_no, - itnim->scsi_tgt_id, - fcid_str, wwpn_str); - } else { - printk(KERN_WARNING - "%s: itnim %llx is already in online state\n", - __func__, - bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim)); - } - - break; - case ITNIM_STATE_OFFLINE_PENDING: - itnim->state = ITNIM_STATE_OFFLINE; - if (itnim->fc_rport) { - fc_rport = itnim->fc_rport; - ((struct bfad_itnim_data_s *) - fc_rport->dd_data)->itnim = NULL; - itnim->fc_rport = NULL; - if (!(im_port->port->flags & BFAD_PORT_DELETE)) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - fc_rport->dev_loss_tmo = - bfa_fcpim_path_tov_get(&bfad->bfa) + 1; - fc_remote_port_delete(fc_rport); - spin_lock_irqsave(&bfad->bfad_lock, flags); - } - wwpn = bfa_fcs_itnim_get_pwwn(&itnim->fcs_itnim); - fcid = bfa_fcs_itnim_get_fcid(&itnim->fcs_itnim); - wwn2str(wwpn_str, wwpn); - fcid2str(fcid_str, fcid); - list_del(&itnim->list_entry); - BFA_LOG(KERN_INFO, bfad, bfa_log_level, - "ITNIM OFFLINE Target: %d:0:%d " - "FCID: %s WWPN: %s\n", - im_port->shost->host_no, - itnim->scsi_tgt_id, - fcid_str, wwpn_str); - } - break; - case ITNIM_STATE_FREE: - if (itnim->fc_rport) { - fc_rport = itnim->fc_rport; - ((struct bfad_itnim_data_s *) - fc_rport->dd_data)->itnim = NULL; - itnim->fc_rport = NULL; - if (!(im_port->port->flags & BFAD_PORT_DELETE)) { - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - fc_rport->dev_loss_tmo = - bfa_fcpim_path_tov_get(&bfad->bfa) + 1; - fc_remote_port_delete(fc_rport); - spin_lock_irqsave(&bfad->bfad_lock, flags); - } - list_del(&itnim->list_entry); - } - - kfree(itnim); - break; - default: - WARN_ON(1); - break; - } - - spin_unlock_irqrestore(&bfad->bfad_lock, flags); -} - -/* - * Scsi_Host template entry, queue a SCSI command to the BFAD. - */ -static int -bfad_im_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) -{ - struct bfad_im_port_s *im_port = - (struct bfad_im_port_s *) cmnd->device->host->hostdata[0]; - struct bfad_s *bfad = im_port->bfad; - struct bfad_itnim_data_s *itnim_data = cmnd->device->hostdata; - struct bfad_itnim_s *itnim; - struct bfa_ioim_s *hal_io; - unsigned long flags; - int rc; - int sg_cnt = 0; - struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); - - rc = fc_remote_port_chkready(rport); - if (rc) { - cmnd->result = rc; - done(cmnd); - return 0; - } - - sg_cnt = scsi_dma_map(cmnd); - if (sg_cnt < 0) - return SCSI_MLQUEUE_HOST_BUSY; - - cmnd->scsi_done = done; - - spin_lock_irqsave(&bfad->bfad_lock, flags); - if (!(bfad->bfad_flags & BFAD_HAL_START_DONE)) { - printk(KERN_WARNING - "bfad%d, queuecommand %p %x failed, BFA stopped\n", - bfad->inst_no, cmnd, cmnd->cmnd[0]); - cmnd->result = ScsiResult(DID_NO_CONNECT, 0); - goto out_fail_cmd; - } - - - itnim = itnim_data->itnim; - if (!itnim) { - cmnd->result = ScsiResult(DID_IMM_RETRY, 0); - goto out_fail_cmd; - } - - hal_io = bfa_ioim_alloc(&bfad->bfa, (struct bfad_ioim_s *) cmnd, - itnim->bfa_itnim, sg_cnt); - if (!hal_io) { - printk(KERN_WARNING "hal_io failure\n"); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - scsi_dma_unmap(cmnd); - return SCSI_MLQUEUE_HOST_BUSY; - } - - cmnd->host_scribble = (char *)hal_io; - bfa_ioim_start(hal_io); - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - - return 0; - -out_fail_cmd: - spin_unlock_irqrestore(&bfad->bfad_lock, flags); - scsi_dma_unmap(cmnd); - if (done) - done(cmnd); - - return 0; -} - -static DEF_SCSI_QCMD(bfad_im_queuecommand) - -void -bfad_rport_online_wait(struct bfad_s *bfad) -{ - int i; - int rport_delay = 10; - - for (i = 0; !(bfad->bfad_flags & BFAD_PORT_ONLINE) - && i < bfa_linkup_delay; i++) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - } - - if (bfad->bfad_flags & BFAD_PORT_ONLINE) { - rport_delay = rport_delay < bfa_linkup_delay ? - rport_delay : bfa_linkup_delay; - for (i = 0; !(bfad->bfad_flags & BFAD_RPORT_ONLINE) - && i < rport_delay; i++) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - } - - if (rport_delay > 0 && (bfad->bfad_flags & BFAD_RPORT_ONLINE)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(rport_delay * HZ); - } - } -} - -int -bfad_get_linkup_delay(struct bfad_s *bfad) -{ - u8 nwwns = 0; - wwn_t wwns[BFA_PREBOOT_BOOTLUN_MAX]; - int linkup_delay; - - /* - * Querying for the boot target port wwns - * -- read from boot information in flash. - * If nwwns > 0 => boot over SAN and set linkup_delay = 30 - * else => local boot machine set linkup_delay = 0 - */ - - bfa_iocfc_get_bootwwns(&bfad->bfa, &nwwns, wwns); - - if (nwwns > 0) - /* If Boot over SAN set linkup_delay = 30sec */ - linkup_delay = 30; - else - /* If local boot; no linkup_delay */ - linkup_delay = 0; - - return linkup_delay; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.h deleted file mode 100644 index 0814367e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfad_im.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFAD_IM_H__ -#define __BFAD_IM_H__ - -#include "bfa_fcs.h" - -#define FCPI_NAME " fcpim" - -#ifndef KOBJ_NAME_LEN -#define KOBJ_NAME_LEN 20 -#endif - -bfa_status_t bfad_im_module_init(void); -void bfad_im_module_exit(void); -bfa_status_t bfad_im_probe(struct bfad_s *bfad); -void bfad_im_probe_undo(struct bfad_s *bfad); -bfa_status_t bfad_im_port_new(struct bfad_s *bfad, struct bfad_port_s *port); -void bfad_im_port_delete(struct bfad_s *bfad, struct bfad_port_s *port); -void bfad_im_port_clean(struct bfad_im_port_s *im_port); -int bfad_im_scsi_host_alloc(struct bfad_s *bfad, - struct bfad_im_port_s *im_port, struct device *dev); -void bfad_im_scsi_host_free(struct bfad_s *bfad, - struct bfad_im_port_s *im_port); - -#define MAX_FCP_TARGET 1024 -#define MAX_FCP_LUN 16384 -#define BFAD_TARGET_RESET_TMO 60 -#define BFAD_LUN_RESET_TMO 60 -#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) -#define BFA_QUEUE_FULL_RAMP_UP_TIME 120 - -/* - * itnim flags - */ -#define IO_DONE_BIT 0 - -struct bfad_itnim_data_s { - struct bfad_itnim_s *itnim; -}; - -struct bfad_im_port_s { - struct bfad_s *bfad; - struct bfad_port_s *port; - struct work_struct port_delete_work; - int idr_id; - u16 cur_scsi_id; - u16 flags; - struct list_head binding_list; - struct Scsi_Host *shost; - struct list_head itnim_mapped_list; - struct fc_vport *fc_vport; -}; - -enum bfad_itnim_state { - ITNIM_STATE_NONE, - ITNIM_STATE_ONLINE, - ITNIM_STATE_OFFLINE_PENDING, - ITNIM_STATE_OFFLINE, - ITNIM_STATE_TIMEOUT, - ITNIM_STATE_FREE, -}; - -/* - * Per itnim data structure - */ -struct bfad_itnim_s { - struct list_head list_entry; - struct bfa_fcs_itnim_s fcs_itnim; - struct work_struct itnim_work; - u32 flags; - enum bfad_itnim_state state; - struct bfad_im_s *im; - struct bfad_im_port_s *im_port; - struct bfad_rport_s *drv_rport; - struct fc_rport *fc_rport; - struct bfa_itnim_s *bfa_itnim; - u16 scsi_tgt_id; - u16 channel; - u16 queue_work; - unsigned long last_ramp_up_time; - unsigned long last_queue_full_time; -}; - -enum bfad_binding_type { - FCP_PWWN_BINDING = 0x1, - FCP_NWWN_BINDING = 0x2, - FCP_FCID_BINDING = 0x3, -}; - -struct bfad_fcp_binding { - struct list_head list_entry; - enum bfad_binding_type binding_type; - u16 scsi_target_id; - u32 fc_id; - wwn_t nwwn; - wwn_t pwwn; -}; - -struct bfad_im_s { - struct bfad_s *bfad; - struct workqueue_struct *drv_workq; - char drv_workq_name[KOBJ_NAME_LEN]; - struct work_struct aen_im_notify_work; -}; - -#define bfad_get_aen_entry(_drv, _entry) do { \ - unsigned long _flags; \ - spin_lock_irqsave(&(_drv)->bfad_aen_spinlock, _flags); \ - bfa_q_deq(&(_drv)->free_aen_q, &(_entry)); \ - if (_entry) \ - list_add_tail(&(_entry)->qe, &(_drv)->active_aen_q); \ - spin_unlock_irqrestore(&(_drv)->bfad_aen_spinlock, _flags); \ -} while (0) - -/* post fc_host vendor event */ -#define bfad_im_post_vendor_event(_entry, _drv, _cnt, _cat, _evt) do { \ - do_gettimeofday(&(_entry)->aen_tv); \ - (_entry)->bfad_num = (_drv)->inst_no; \ - (_entry)->seq_num = (_cnt); \ - (_entry)->aen_category = (_cat); \ - (_entry)->aen_type = (_evt); \ - if ((_drv)->bfad_flags & BFAD_FC4_PROBE_DONE) \ - queue_work((_drv)->im->drv_workq, \ - &(_drv)->im->aen_im_notify_work); \ -} while (0) - -struct Scsi_Host *bfad_scsi_host_alloc(struct bfad_im_port_s *im_port, - struct bfad_s *); -bfa_status_t bfad_thread_workq(struct bfad_s *bfad); -void bfad_destroy_workq(struct bfad_im_s *im); -void bfad_fc_host_init(struct bfad_im_port_s *im_port); -void bfad_scsi_host_free(struct bfad_s *bfad, - struct bfad_im_port_s *im_port); -void bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, - struct scsi_device *sdev); -void bfad_handle_qfull(struct bfad_itnim_s *itnim, struct scsi_device *sdev); -struct bfad_itnim_s *bfad_get_itnim(struct bfad_im_port_s *im_port, int id); - -extern struct scsi_host_template bfad_im_scsi_host_template; -extern struct scsi_host_template bfad_im_vport_template; -extern struct fc_function_template bfad_im_fc_function_template; -extern struct fc_function_template bfad_im_vport_fc_function_template; -extern struct scsi_transport_template *bfad_im_scsi_transport_template; -extern struct scsi_transport_template *bfad_im_scsi_vport_transport_template; - -extern struct device_attribute *bfad_im_host_attrs[]; -extern struct device_attribute *bfad_im_vport_attrs[]; - -irqreturn_t bfad_intx(int irq, void *dev_id); - -int bfad_im_bsg_request(struct fc_bsg_job *job); -int bfad_im_bsg_timeout(struct fc_bsg_job *job); - -/* - * Macro to set the SCSI device sdev_bflags - sdev_bflags are used by the - * SCSI mid-layer to choose LUN Scanning mode REPORT_LUNS vs. Sequential Scan - * - * Internally iterate's over all the ITNIM's part of the im_port & set's the - * sdev_bflags for the scsi_device associated with LUN #0. - */ -#define bfad_reset_sdev_bflags(__im_port, __lunmask_cfg) do { \ - struct scsi_device *__sdev = NULL; \ - struct bfad_itnim_s *__itnim = NULL; \ - u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; \ - list_for_each_entry(__itnim, &((__im_port)->itnim_mapped_list), \ - list_entry) { \ - __sdev = scsi_device_lookup((__im_port)->shost, \ - __itnim->channel, \ - __itnim->scsi_tgt_id, 0); \ - if (__sdev) { \ - if ((__lunmask_cfg) == BFA_TRUE) \ - __sdev->sdev_bflags |= scan_flags; \ - else \ - __sdev->sdev_bflags &= ~scan_flags; \ - scsi_device_put(__sdev); \ - } \ - } \ -} while (0) - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfi.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfi.h deleted file mode 100644 index b2ba0b2e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfi.h +++ /dev/null @@ -1,1152 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_H__ -#define __BFI_H__ - -#include "bfa_defs.h" -#include "bfa_defs_svc.h" - -#pragma pack(1) - -/* Per dma segment max size */ -#define BFI_MEM_DMA_SEG_SZ (131072) - -/* Get number of dma segments required */ -#define BFI_MEM_DMA_NSEGS(_num_reqs, _req_sz) \ - ((u16)(((((_num_reqs) * (_req_sz)) + BFI_MEM_DMA_SEG_SZ - 1) & \ - ~(BFI_MEM_DMA_SEG_SZ - 1)) / BFI_MEM_DMA_SEG_SZ)) - -/* Get num dma reqs - that fit in a segment */ -#define BFI_MEM_NREQS_SEG(_rqsz) (BFI_MEM_DMA_SEG_SZ / (_rqsz)) - -/* Get segment num from tag */ -#define BFI_MEM_SEG_FROM_TAG(_tag, _rqsz) ((_tag) / BFI_MEM_NREQS_SEG(_rqsz)) - -/* Get dma req offset in a segment */ -#define BFI_MEM_SEG_REQ_OFFSET(_tag, _sz) \ - ((_tag) - (BFI_MEM_SEG_FROM_TAG(_tag, _sz) * BFI_MEM_NREQS_SEG(_sz))) - -/* - * BFI FW image type - */ -#define BFI_FLASH_CHUNK_SZ 256 /* Flash chunk size */ -#define BFI_FLASH_CHUNK_SZ_WORDS (BFI_FLASH_CHUNK_SZ/sizeof(u32)) - -/* - * Msg header common to all msgs - */ -struct bfi_mhdr_s { - u8 msg_class; /* @ref bfi_mclass_t */ - u8 msg_id; /* msg opcode with in the class */ - union { - struct { - u8 qid; - u8 fn_lpu; /* msg destination */ - } h2i; - u16 i2htok; /* token in msgs to host */ - } mtag; -}; - -#define bfi_fn_lpu(__fn, __lpu) ((__fn) << 1 | (__lpu)) -#define bfi_mhdr_2_fn(_mh) ((_mh)->mtag.h2i.fn_lpu >> 1) - -#define bfi_h2i_set(_mh, _mc, _op, _fn_lpu) do { \ - (_mh).msg_class = (_mc); \ - (_mh).msg_id = (_op); \ - (_mh).mtag.h2i.fn_lpu = (_fn_lpu); \ -} while (0) - -#define bfi_i2h_set(_mh, _mc, _op, _i2htok) do { \ - (_mh).msg_class = (_mc); \ - (_mh).msg_id = (_op); \ - (_mh).mtag.i2htok = (_i2htok); \ -} while (0) - -/* - * Message opcodes: 0-127 to firmware, 128-255 to host - */ -#define BFI_I2H_OPCODE_BASE 128 -#define BFA_I2HM(_x) ((_x) + BFI_I2H_OPCODE_BASE) - -/* - **************************************************************************** - * - * Scatter Gather Element and Page definition - * - **************************************************************************** - */ - -#define BFI_SGE_INLINE 1 -#define BFI_SGE_INLINE_MAX (BFI_SGE_INLINE + 1) - -/* - * SG Flags - */ -enum { - BFI_SGE_DATA = 0, /* data address, not last */ - BFI_SGE_DATA_CPL = 1, /* data addr, last in current page */ - BFI_SGE_DATA_LAST = 3, /* data address, last */ - BFI_SGE_LINK = 2, /* link address */ - BFI_SGE_PGDLEN = 2, /* cumulative data length for page */ -}; - -/* - * DMA addresses - */ -union bfi_addr_u { - struct { - __be32 addr_lo; - __be32 addr_hi; - } a32; -}; - -/* - * Scatter Gather Element used for fast-path IO requests - */ -struct bfi_sge_s { -#ifdef __BIG_ENDIAN - u32 flags:2, - rsvd:2, - sg_len:28; -#else - u32 sg_len:28, - rsvd:2, - flags:2; -#endif - union bfi_addr_u sga; -}; - -/** - * Generic DMA addr-len pair. - */ -struct bfi_alen_s { - union bfi_addr_u al_addr; /* DMA addr of buffer */ - u32 al_len; /* length of buffer */ -}; - -/* - * Scatter Gather Page - */ -#define BFI_SGPG_DATA_SGES 7 -#define BFI_SGPG_SGES_MAX (BFI_SGPG_DATA_SGES + 1) -#define BFI_SGPG_RSVD_WD_LEN 8 -struct bfi_sgpg_s { - struct bfi_sge_s sges[BFI_SGPG_SGES_MAX]; - u32 rsvd[BFI_SGPG_RSVD_WD_LEN]; -}; - -/* FCP module definitions */ -#define BFI_IO_MAX (2000) -#define BFI_IOIM_SNSLEN (256) -#define BFI_IOIM_SNSBUF_SEGS \ - BFI_MEM_DMA_NSEGS(BFI_IO_MAX, BFI_IOIM_SNSLEN) - -/* - * Large Message structure - 128 Bytes size Msgs - */ -#define BFI_LMSG_SZ 128 -#define BFI_LMSG_PL_WSZ \ - ((BFI_LMSG_SZ - sizeof(struct bfi_mhdr_s)) / 4) - -struct bfi_msg_s { - struct bfi_mhdr_s mhdr; - u32 pl[BFI_LMSG_PL_WSZ]; -}; - -/* - * Mailbox message structure - */ -#define BFI_MBMSG_SZ 7 -struct bfi_mbmsg_s { - struct bfi_mhdr_s mh; - u32 pl[BFI_MBMSG_SZ]; -}; - -/* - * Supported PCI function class codes (personality) - */ -enum bfi_pcifn_class { - BFI_PCIFN_CLASS_FC = 0x0c04, - BFI_PCIFN_CLASS_ETH = 0x0200, -}; - -/* - * Message Classes - */ -enum bfi_mclass { - BFI_MC_IOC = 1, /* IO Controller (IOC) */ - BFI_MC_DIAG = 2, /* Diagnostic Msgs */ - BFI_MC_FLASH = 3, /* Flash message class */ - BFI_MC_CEE = 4, /* CEE */ - BFI_MC_FCPORT = 5, /* FC port */ - BFI_MC_IOCFC = 6, /* FC - IO Controller (IOC) */ - BFI_MC_ABLK = 7, /* ASIC block configuration */ - BFI_MC_UF = 8, /* Unsolicited frame receive */ - BFI_MC_FCXP = 9, /* FC Transport */ - BFI_MC_LPS = 10, /* lport fc login services */ - BFI_MC_RPORT = 11, /* Remote port */ - BFI_MC_ITN = 12, /* I-T nexus (Initiator mode) */ - BFI_MC_IOIM_READ = 13, /* read IO (Initiator mode) */ - BFI_MC_IOIM_WRITE = 14, /* write IO (Initiator mode) */ - BFI_MC_IOIM_IO = 15, /* IO (Initiator mode) */ - BFI_MC_IOIM = 16, /* IO (Initiator mode) */ - BFI_MC_IOIM_IOCOM = 17, /* good IO completion */ - BFI_MC_TSKIM = 18, /* Initiator Task management */ - BFI_MC_PORT = 21, /* Physical port */ - BFI_MC_SFP = 22, /* SFP module */ - BFI_MC_PHY = 25, /* External PHY message class */ - BFI_MC_MAX = 32 -}; - -#define BFI_IOC_MAX_CQS 4 -#define BFI_IOC_MAX_CQS_ASIC 8 -#define BFI_IOC_MSGLEN_MAX 32 /* 32 bytes */ - -/* - *---------------------------------------------------------------------- - * IOC - *---------------------------------------------------------------------- - */ - -/* - * Different asic generations - */ -enum bfi_asic_gen { - BFI_ASIC_GEN_CB = 1, /* crossbow 8G FC */ - BFI_ASIC_GEN_CT = 2, /* catapult 8G FC or 10G CNA */ - BFI_ASIC_GEN_CT2 = 3, /* catapult-2 16G FC or 10G CNA */ -}; - -enum bfi_asic_mode { - BFI_ASIC_MODE_FC = 1, /* FC upto 8G speed */ - BFI_ASIC_MODE_FC16 = 2, /* FC upto 16G speed */ - BFI_ASIC_MODE_ETH = 3, /* Ethernet ports */ - BFI_ASIC_MODE_COMBO = 4, /* FC 16G and Ethernet 10G port */ -}; - -enum bfi_ioc_h2i_msgs { - BFI_IOC_H2I_ENABLE_REQ = 1, - BFI_IOC_H2I_DISABLE_REQ = 2, - BFI_IOC_H2I_GETATTR_REQ = 3, - BFI_IOC_H2I_DBG_SYNC = 4, - BFI_IOC_H2I_DBG_DUMP = 5, -}; - -enum bfi_ioc_i2h_msgs { - BFI_IOC_I2H_ENABLE_REPLY = BFA_I2HM(1), - BFI_IOC_I2H_DISABLE_REPLY = BFA_I2HM(2), - BFI_IOC_I2H_GETATTR_REPLY = BFA_I2HM(3), - BFI_IOC_I2H_HBEAT = BFA_I2HM(4), - BFI_IOC_I2H_ACQ_ADDR_REPLY = BFA_I2HM(5), -}; - -/* - * BFI_IOC_H2I_GETATTR_REQ message - */ -struct bfi_ioc_getattr_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u attr_addr; -}; - -struct bfi_ioc_attr_s { - wwn_t mfg_pwwn; /* Mfg port wwn */ - wwn_t mfg_nwwn; /* Mfg node wwn */ - mac_t mfg_mac; /* Mfg mac */ - u8 port_mode; /* bfi_port_mode */ - u8 rsvd_a; - wwn_t pwwn; - wwn_t nwwn; - mac_t mac; /* PBC or Mfg mac */ - u16 rsvd_b; - mac_t fcoe_mac; - u16 rsvd_c; - char brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)]; - u8 pcie_gen; - u8 pcie_lanes_orig; - u8 pcie_lanes; - u8 rx_bbcredit; /* receive buffer credits */ - u32 adapter_prop; /* adapter properties */ - u16 maxfrsize; /* max receive frame size */ - char asic_rev; - u8 rsvd_d; - char fw_version[BFA_VERSION_LEN]; - char optrom_version[BFA_VERSION_LEN]; - struct bfa_mfg_vpd_s vpd; - u32 card_type; /* card type */ -}; - -/* - * BFI_IOC_I2H_GETATTR_REPLY message - */ -struct bfi_ioc_getattr_reply_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 status; /* cfg reply status */ - u8 rsvd[3]; -}; - -/* - * Firmware memory page offsets - */ -#define BFI_IOC_SMEM_PG0_CB (0x40) -#define BFI_IOC_SMEM_PG0_CT (0x180) - -/* - * Firmware statistic offset - */ -#define BFI_IOC_FWSTATS_OFF (0x6B40) -#define BFI_IOC_FWSTATS_SZ (4096) - -/* - * Firmware trace offset - */ -#define BFI_IOC_TRC_OFF (0x4b00) -#define BFI_IOC_TRC_ENTS 256 - -#define BFI_IOC_FW_SIGNATURE (0xbfadbfad) -#define BFI_IOC_MD5SUM_SZ 4 -struct bfi_ioc_image_hdr_s { - u32 signature; /* constant signature */ - u8 asic_gen; /* asic generation */ - u8 asic_mode; - u8 port0_mode; /* device mode for port 0 */ - u8 port1_mode; /* device mode for port 1 */ - u32 exec; /* exec vector */ - u32 bootenv; /* fimware boot env */ - u32 rsvd_b[4]; - u32 md5sum[BFI_IOC_MD5SUM_SZ]; -}; - -#define BFI_FWBOOT_DEVMODE_OFF 4 -#define BFI_FWBOOT_TYPE_OFF 8 -#define BFI_FWBOOT_ENV_OFF 12 -#define BFI_FWBOOT_DEVMODE(__asic_gen, __asic_mode, __p0_mode, __p1_mode) \ - (((u32)(__asic_gen)) << 24 | \ - ((u32)(__asic_mode)) << 16 | \ - ((u32)(__p0_mode)) << 8 | \ - ((u32)(__p1_mode))) - -#define BFI_FWBOOT_TYPE_NORMAL 0 -#define BFI_FWBOOT_TYPE_MEMTEST 2 -#define BFI_FWBOOT_ENV_OS 0 - -enum bfi_port_mode { - BFI_PORT_MODE_FC = 1, - BFI_PORT_MODE_ETH = 2, -}; - -struct bfi_ioc_hbeat_s { - struct bfi_mhdr_s mh; /* common msg header */ - u32 hb_count; /* current heart beat count */ -}; - -/* - * IOC hardware/firmware state - */ -enum bfi_ioc_state { - BFI_IOC_UNINIT = 0, /* not initialized */ - BFI_IOC_INITING = 1, /* h/w is being initialized */ - BFI_IOC_HWINIT = 2, /* h/w is initialized */ - BFI_IOC_CFG = 3, /* IOC configuration in progress */ - BFI_IOC_OP = 4, /* IOC is operational */ - BFI_IOC_DISABLING = 5, /* IOC is being disabled */ - BFI_IOC_DISABLED = 6, /* IOC is disabled */ - BFI_IOC_CFG_DISABLED = 7, /* IOC is being disabled;transient */ - BFI_IOC_FAIL = 8, /* IOC heart-beat failure */ - BFI_IOC_MEMTEST = 9, /* IOC is doing memtest */ -}; - -#define BFI_IOC_ENDIAN_SIG 0x12345678 - -enum { - BFI_ADAPTER_TYPE_FC = 0x01, /* FC adapters */ - BFI_ADAPTER_TYPE_MK = 0x0f0000, /* adapter type mask */ - BFI_ADAPTER_TYPE_SH = 16, /* adapter type shift */ - BFI_ADAPTER_NPORTS_MK = 0xff00, /* number of ports mask */ - BFI_ADAPTER_NPORTS_SH = 8, /* number of ports shift */ - BFI_ADAPTER_SPEED_MK = 0xff, /* adapter speed mask */ - BFI_ADAPTER_SPEED_SH = 0, /* adapter speed shift */ - BFI_ADAPTER_PROTO = 0x100000, /* prototype adapaters */ - BFI_ADAPTER_TTV = 0x200000, /* TTV debug capable */ - BFI_ADAPTER_UNSUPP = 0x400000, /* unknown adapter type */ -}; - -#define BFI_ADAPTER_GETP(__prop, __adap_prop) \ - (((__adap_prop) & BFI_ADAPTER_ ## __prop ## _MK) >> \ - BFI_ADAPTER_ ## __prop ## _SH) -#define BFI_ADAPTER_SETP(__prop, __val) \ - ((__val) << BFI_ADAPTER_ ## __prop ## _SH) -#define BFI_ADAPTER_IS_PROTO(__adap_type) \ - ((__adap_type) & BFI_ADAPTER_PROTO) -#define BFI_ADAPTER_IS_TTV(__adap_type) \ - ((__adap_type) & BFI_ADAPTER_TTV) -#define BFI_ADAPTER_IS_UNSUPP(__adap_type) \ - ((__adap_type) & BFI_ADAPTER_UNSUPP) -#define BFI_ADAPTER_IS_SPECIAL(__adap_type) \ - ((__adap_type) & (BFI_ADAPTER_TTV | BFI_ADAPTER_PROTO | \ - BFI_ADAPTER_UNSUPP)) - -/* - * BFI_IOC_H2I_ENABLE_REQ & BFI_IOC_H2I_DISABLE_REQ messages - */ -struct bfi_ioc_ctrl_req_s { - struct bfi_mhdr_s mh; - u16 clscode; - u16 rsvd; - u32 tv_sec; -}; -#define bfi_ioc_enable_req_t struct bfi_ioc_ctrl_req_s; -#define bfi_ioc_disable_req_t struct bfi_ioc_ctrl_req_s; - -/* - * BFI_IOC_I2H_ENABLE_REPLY & BFI_IOC_I2H_DISABLE_REPLY messages - */ -struct bfi_ioc_ctrl_reply_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 status; /* enable/disable status */ - u8 port_mode; /* bfa_mode_s */ - u8 cap_bm; /* capability bit mask */ - u8 rsvd; -}; -#define bfi_ioc_enable_reply_t struct bfi_ioc_ctrl_reply_s; -#define bfi_ioc_disable_reply_t struct bfi_ioc_ctrl_reply_s; - -#define BFI_IOC_MSGSZ 8 -/* - * H2I Messages - */ -union bfi_ioc_h2i_msg_u { - struct bfi_mhdr_s mh; - struct bfi_ioc_ctrl_req_s enable_req; - struct bfi_ioc_ctrl_req_s disable_req; - struct bfi_ioc_getattr_req_s getattr_req; - u32 mboxmsg[BFI_IOC_MSGSZ]; -}; - -/* - * I2H Messages - */ -union bfi_ioc_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_ioc_ctrl_reply_s fw_event; - u32 mboxmsg[BFI_IOC_MSGSZ]; -}; - - -/* - *---------------------------------------------------------------------- - * PBC - *---------------------------------------------------------------------- - */ - -#define BFI_PBC_MAX_BLUNS 8 -#define BFI_PBC_MAX_VPORTS 16 -#define BFI_PBC_PORT_DISABLED 2 - -/* - * PBC boot lun configuration - */ -struct bfi_pbc_blun_s { - wwn_t tgt_pwwn; - struct scsi_lun tgt_lun; -}; - -/* - * PBC virtual port configuration - */ -struct bfi_pbc_vport_s { - wwn_t vp_pwwn; - wwn_t vp_nwwn; -}; - -/* - * BFI pre-boot configuration information - */ -struct bfi_pbc_s { - u8 port_enabled; - u8 boot_enabled; - u8 nbluns; - u8 nvports; - u8 port_speed; - u8 rsvd_a; - u16 hss; - wwn_t pbc_pwwn; - wwn_t pbc_nwwn; - struct bfi_pbc_blun_s blun[BFI_PBC_MAX_BLUNS]; - struct bfi_pbc_vport_s vport[BFI_PBC_MAX_VPORTS]; -}; - -/* - *---------------------------------------------------------------------- - * MSGQ - *---------------------------------------------------------------------- - */ -#define BFI_MSGQ_FULL(_q) (((_q->pi + 1) % _q->q_depth) == _q->ci) -#define BFI_MSGQ_EMPTY(_q) (_q->pi == _q->ci) -#define BFI_MSGQ_UPDATE_CI(_q) (_q->ci = (_q->ci + 1) % _q->q_depth) -#define BFI_MSGQ_UPDATE_PI(_q) (_q->pi = (_q->pi + 1) % _q->q_depth) - -/* q_depth must be power of 2 */ -#define BFI_MSGQ_FREE_CNT(_q) ((_q->ci - _q->pi - 1) & (_q->q_depth - 1)) - -enum bfi_msgq_h2i_msgs_e { - BFI_MSGQ_H2I_INIT_REQ = 1, - BFI_MSGQ_H2I_DOORBELL = 2, - BFI_MSGQ_H2I_SHUTDOWN = 3, -}; - -enum bfi_msgq_i2h_msgs_e { - BFI_MSGQ_I2H_INIT_RSP = 1, - BFI_MSGQ_I2H_DOORBELL = 2, -}; - - -/* Messages(commands/responsed/AENS will have the following header */ -struct bfi_msgq_mhdr_s { - u8 msg_class; - u8 msg_id; - u16 msg_token; - u16 num_entries; - u8 enet_id; - u8 rsvd[1]; -}; - -#define bfi_msgq_mhdr_set(_mh, _mc, _mid, _tok, _enet_id) do { \ - (_mh).msg_class = (_mc); \ - (_mh).msg_id = (_mid); \ - (_mh).msg_token = (_tok); \ - (_mh).enet_id = (_enet_id); \ -} while (0) - -/* - * Mailbox for messaging interface - * -*/ -#define BFI_MSGQ_CMD_ENTRY_SIZE (64) /* TBD */ -#define BFI_MSGQ_RSP_ENTRY_SIZE (64) /* TBD */ -#define BFI_MSGQ_MSG_SIZE_MAX (2048) /* TBD */ - -struct bfi_msgq_s { - union bfi_addr_u addr; - u16 q_depth; /* Total num of entries in the queue */ - u8 rsvd[2]; -}; - -/* BFI_ENET_MSGQ_CFG_REQ TBD init or cfg? */ -struct bfi_msgq_cfg_req_s { - struct bfi_mhdr_s mh; - struct bfi_msgq_s cmdq; - struct bfi_msgq_s rspq; -}; - -/* BFI_ENET_MSGQ_CFG_RSP */ -struct bfi_msgq_cfg_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - - -/* BFI_MSGQ_H2I_DOORBELL */ -struct bfi_msgq_h2i_db_s { - struct bfi_mhdr_s mh; - u16 cmdq_pi; - u16 rspq_ci; -}; - -/* BFI_MSGQ_I2H_DOORBELL */ -struct bfi_msgq_i2h_db_s { - struct bfi_mhdr_s mh; - u16 rspq_pi; - u16 cmdq_ci; -}; - -#pragma pack() - -/* BFI port specific */ -#pragma pack(1) - -enum bfi_port_h2i { - BFI_PORT_H2I_ENABLE_REQ = (1), - BFI_PORT_H2I_DISABLE_REQ = (2), - BFI_PORT_H2I_GET_STATS_REQ = (3), - BFI_PORT_H2I_CLEAR_STATS_REQ = (4), -}; - -enum bfi_port_i2h { - BFI_PORT_I2H_ENABLE_RSP = BFA_I2HM(1), - BFI_PORT_I2H_DISABLE_RSP = BFA_I2HM(2), - BFI_PORT_I2H_GET_STATS_RSP = BFA_I2HM(3), - BFI_PORT_I2H_CLEAR_STATS_RSP = BFA_I2HM(4), -}; - -/* - * Generic REQ type - */ -struct bfi_port_generic_req_s { - struct bfi_mhdr_s mh; /* msg header */ - u32 msgtag; /* msgtag for reply */ - u32 rsvd; -}; - -/* - * Generic RSP type - */ -struct bfi_port_generic_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* port enable status */ - u8 rsvd[3]; - u32 msgtag; /* msgtag for reply */ -}; - -/* - * BFI_PORT_H2I_GET_STATS_REQ - */ -struct bfi_port_get_stats_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - union bfi_addr_u dma_addr; -}; - -union bfi_port_h2i_msg_u { - struct bfi_mhdr_s mh; - struct bfi_port_generic_req_s enable_req; - struct bfi_port_generic_req_s disable_req; - struct bfi_port_get_stats_req_s getstats_req; - struct bfi_port_generic_req_s clearstats_req; -}; - -union bfi_port_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_port_generic_rsp_s enable_rsp; - struct bfi_port_generic_rsp_s disable_rsp; - struct bfi_port_generic_rsp_s getstats_rsp; - struct bfi_port_generic_rsp_s clearstats_rsp; -}; - -/* - *---------------------------------------------------------------------- - * ABLK - *---------------------------------------------------------------------- - */ -enum bfi_ablk_h2i_msgs_e { - BFI_ABLK_H2I_QUERY = 1, - BFI_ABLK_H2I_ADPT_CONFIG = 2, - BFI_ABLK_H2I_PORT_CONFIG = 3, - BFI_ABLK_H2I_PF_CREATE = 4, - BFI_ABLK_H2I_PF_DELETE = 5, - BFI_ABLK_H2I_PF_UPDATE = 6, - BFI_ABLK_H2I_OPTROM_ENABLE = 7, - BFI_ABLK_H2I_OPTROM_DISABLE = 8, -}; - -enum bfi_ablk_i2h_msgs_e { - BFI_ABLK_I2H_QUERY = BFA_I2HM(BFI_ABLK_H2I_QUERY), - BFI_ABLK_I2H_ADPT_CONFIG = BFA_I2HM(BFI_ABLK_H2I_ADPT_CONFIG), - BFI_ABLK_I2H_PORT_CONFIG = BFA_I2HM(BFI_ABLK_H2I_PORT_CONFIG), - BFI_ABLK_I2H_PF_CREATE = BFA_I2HM(BFI_ABLK_H2I_PF_CREATE), - BFI_ABLK_I2H_PF_DELETE = BFA_I2HM(BFI_ABLK_H2I_PF_DELETE), - BFI_ABLK_I2H_PF_UPDATE = BFA_I2HM(BFI_ABLK_H2I_PF_UPDATE), - BFI_ABLK_I2H_OPTROM_ENABLE = BFA_I2HM(BFI_ABLK_H2I_OPTROM_ENABLE), - BFI_ABLK_I2H_OPTROM_DISABLE = BFA_I2HM(BFI_ABLK_H2I_OPTROM_DISABLE), -}; - -/* BFI_ABLK_H2I_QUERY */ -struct bfi_ablk_h2i_query_s { - struct bfi_mhdr_s mh; - union bfi_addr_u addr; -}; - -/* BFI_ABL_H2I_ADPT_CONFIG, BFI_ABLK_H2I_PORT_CONFIG */ -struct bfi_ablk_h2i_cfg_req_s { - struct bfi_mhdr_s mh; - u8 mode; - u8 port; - u8 max_pf; - u8 max_vf; -}; - -/* - * BFI_ABLK_H2I_PF_CREATE, BFI_ABLK_H2I_PF_DELETE, - */ -struct bfi_ablk_h2i_pf_req_s { - struct bfi_mhdr_s mh; - u8 pcifn; - u8 port; - u16 pers; - u32 bw; -}; - -/* BFI_ABLK_H2I_OPTROM_ENABLE, BFI_ABLK_H2I_OPTROM_DISABLE */ -struct bfi_ablk_h2i_optrom_s { - struct bfi_mhdr_s mh; -}; - -/* - * BFI_ABLK_I2H_QUERY - * BFI_ABLK_I2H_PORT_CONFIG - * BFI_ABLK_I2H_PF_CREATE - * BFI_ABLK_I2H_PF_DELETE - * BFI_ABLK_I2H_PF_UPDATE - * BFI_ABLK_I2H_OPTROM_ENABLE - * BFI_ABLK_I2H_OPTROM_DISABLE - */ -struct bfi_ablk_i2h_rsp_s { - struct bfi_mhdr_s mh; - u8 status; - u8 pcifn; - u8 port_mode; -}; - - -/* - * CEE module specific messages - */ - -/* Mailbox commands from host to firmware */ -enum bfi_cee_h2i_msgs_e { - BFI_CEE_H2I_GET_CFG_REQ = 1, - BFI_CEE_H2I_RESET_STATS = 2, - BFI_CEE_H2I_GET_STATS_REQ = 3, -}; - -enum bfi_cee_i2h_msgs_e { - BFI_CEE_I2H_GET_CFG_RSP = BFA_I2HM(1), - BFI_CEE_I2H_RESET_STATS_RSP = BFA_I2HM(2), - BFI_CEE_I2H_GET_STATS_RSP = BFA_I2HM(3), -}; - -/* - * H2I command structure for resetting the stats - */ -struct bfi_cee_reset_stats_s { - struct bfi_mhdr_s mh; -}; - -/* - * Get configuration command from host - */ -struct bfi_cee_get_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u dma_addr; -}; - -/* - * Reply message from firmware - */ -struct bfi_cee_get_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - -/* - * Reply message from firmware - */ -struct bfi_cee_stats_rsp_s { - struct bfi_mhdr_s mh; - u8 cmd_status; - u8 rsvd[3]; -}; - -/* Mailbox message structures from firmware to host */ -union bfi_cee_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_cee_get_rsp_s get_rsp; - struct bfi_cee_stats_rsp_s stats_rsp; -}; - -/* - * SFP related - */ - -enum bfi_sfp_h2i_e { - BFI_SFP_H2I_SHOW = 1, - BFI_SFP_H2I_SCN = 2, -}; - -enum bfi_sfp_i2h_e { - BFI_SFP_I2H_SHOW = BFA_I2HM(BFI_SFP_H2I_SHOW), - BFI_SFP_I2H_SCN = BFA_I2HM(BFI_SFP_H2I_SCN), -}; - -/* - * SFP state change notification - */ -struct bfi_sfp_scn_s { - struct bfi_mhdr_s mhr; /* host msg header */ - u8 event; - u8 sfpid; - u8 pomlvl; /* pom level: normal/warning/alarm */ - u8 is_elb; /* e-loopback */ -}; - -/* - * SFP state - */ -enum bfa_sfp_stat_e { - BFA_SFP_STATE_INIT = 0, /* SFP state is uninit */ - BFA_SFP_STATE_REMOVED = 1, /* SFP is removed */ - BFA_SFP_STATE_INSERTED = 2, /* SFP is inserted */ - BFA_SFP_STATE_VALID = 3, /* SFP is valid */ - BFA_SFP_STATE_UNSUPPORT = 4, /* SFP is unsupport */ - BFA_SFP_STATE_FAILED = 5, /* SFP i2c read fail */ -}; - -/* - * SFP memory access type - */ -enum bfi_sfp_mem_e { - BFI_SFP_MEM_ALL = 0x1, /* access all data field */ - BFI_SFP_MEM_DIAGEXT = 0x2, /* access diag ext data field only */ -}; - -struct bfi_sfp_req_s { - struct bfi_mhdr_s mh; - u8 memtype; - u8 rsvd[3]; - struct bfi_alen_s alen; -}; - -struct bfi_sfp_rsp_s { - struct bfi_mhdr_s mh; - u8 status; - u8 state; - u8 rsvd[2]; -}; - -/* - * FLASH module specific - */ -enum bfi_flash_h2i_msgs { - BFI_FLASH_H2I_QUERY_REQ = 1, - BFI_FLASH_H2I_ERASE_REQ = 2, - BFI_FLASH_H2I_WRITE_REQ = 3, - BFI_FLASH_H2I_READ_REQ = 4, - BFI_FLASH_H2I_BOOT_VER_REQ = 5, -}; - -enum bfi_flash_i2h_msgs { - BFI_FLASH_I2H_QUERY_RSP = BFA_I2HM(1), - BFI_FLASH_I2H_ERASE_RSP = BFA_I2HM(2), - BFI_FLASH_I2H_WRITE_RSP = BFA_I2HM(3), - BFI_FLASH_I2H_READ_RSP = BFA_I2HM(4), - BFI_FLASH_I2H_BOOT_VER_RSP = BFA_I2HM(5), - BFI_FLASH_I2H_EVENT = BFA_I2HM(127), -}; - -/* - * Flash query request - */ -struct bfi_flash_query_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - struct bfi_alen_s alen; -}; - -/* - * Flash erase request - */ -struct bfi_flash_erase_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; -}; - -/* - * Flash write request - */ -struct bfi_flash_write_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - struct bfi_alen_s alen; - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 last; - u8 rsv[2]; - u32 offset; - u32 length; -}; - -/* - * Flash read request - */ -struct bfi_flash_read_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * Flash query response - */ -struct bfi_flash_query_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * Flash read response - */ -struct bfi_flash_read_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; - u32 length; -}; - -/* - * Flash write response - */ -struct bfi_flash_write_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; - u32 length; -}; - -/* - * Flash erase response - */ -struct bfi_flash_erase_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 type; /* partition type */ - u8 instance; /* partition instance */ - u8 rsv[3]; - u32 status; -}; - -/* - * Flash event notification - */ -struct bfi_flash_event_s { - struct bfi_mhdr_s mh; /* Common msg header */ - bfa_status_t status; - u32 param; -}; - -/* - *---------------------------------------------------------------------- - * DIAG - *---------------------------------------------------------------------- - */ -enum bfi_diag_h2i { - BFI_DIAG_H2I_PORTBEACON = 1, - BFI_DIAG_H2I_LOOPBACK = 2, - BFI_DIAG_H2I_FWPING = 3, - BFI_DIAG_H2I_TEMPSENSOR = 4, - BFI_DIAG_H2I_LEDTEST = 5, - BFI_DIAG_H2I_QTEST = 6, -}; - -enum bfi_diag_i2h { - BFI_DIAG_I2H_PORTBEACON = BFA_I2HM(BFI_DIAG_H2I_PORTBEACON), - BFI_DIAG_I2H_LOOPBACK = BFA_I2HM(BFI_DIAG_H2I_LOOPBACK), - BFI_DIAG_I2H_FWPING = BFA_I2HM(BFI_DIAG_H2I_FWPING), - BFI_DIAG_I2H_TEMPSENSOR = BFA_I2HM(BFI_DIAG_H2I_TEMPSENSOR), - BFI_DIAG_I2H_LEDTEST = BFA_I2HM(BFI_DIAG_H2I_LEDTEST), - BFI_DIAG_I2H_QTEST = BFA_I2HM(BFI_DIAG_H2I_QTEST), -}; - -#define BFI_DIAG_MAX_SGES 2 -#define BFI_DIAG_DMA_BUF_SZ (2 * 1024) -#define BFI_BOOT_MEMTEST_RES_ADDR 0x900 -#define BFI_BOOT_MEMTEST_RES_SIG 0xA0A1A2A3 - -struct bfi_diag_lb_req_s { - struct bfi_mhdr_s mh; - u32 loopcnt; - u32 pattern; - u8 lb_mode; /*!< bfa_port_opmode_t */ - u8 speed; /*!< bfa_port_speed_t */ - u8 rsvd[2]; -}; - -struct bfi_diag_lb_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - struct bfa_diag_loopback_result_s res; /* 16 bytes */ -}; - -struct bfi_diag_fwping_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - struct bfi_alen_s alen; /* 12 bytes */ - u32 data; /* user input data pattern */ - u32 count; /* user input dma count */ - u8 qtag; /* track CPE vc */ - u8 rsv[3]; -}; - -struct bfi_diag_fwping_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 data; /* user input data pattern */ - u8 qtag; /* track CPE vc */ - u8 dma_status; /* dma status */ - u8 rsv[2]; -}; - -/* - * Temperature Sensor - */ -struct bfi_diag_ts_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u16 temp; /* 10-bit A/D value */ - u16 brd_temp; /* 9-bit board temp */ - u8 status; - u8 ts_junc; /* show junction tempsensor */ - u8 ts_brd; /* show board tempsensor */ - u8 rsv; -}; -#define bfi_diag_ts_rsp_t struct bfi_diag_ts_req_s - -struct bfi_diag_ledtest_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u8 cmd; - u8 color; - u8 portid; - u8 led; /* bitmap of LEDs to be tested */ - u16 freq; /* no. of blinks every 10 secs */ - u8 rsv[2]; -}; - -/* notify host led operation is done */ -struct bfi_diag_ledtest_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ -}; - -struct bfi_diag_portbeacon_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 period; /* beaconing period */ - u8 beacon; /* 1: beacon on */ - u8 rsvd[3]; -}; - -/* notify host the beacon is off */ -struct bfi_diag_portbeacon_rsp_s { - struct bfi_mhdr_s mh; /* 4 bytes */ -}; - -struct bfi_diag_qtest_req_s { - struct bfi_mhdr_s mh; /* 4 bytes */ - u32 data[BFI_LMSG_PL_WSZ]; /* fill up tcm prefetch area */ -}; -#define bfi_diag_qtest_rsp_t struct bfi_diag_qtest_req_s - -/* - * PHY module specific - */ -enum bfi_phy_h2i_msgs_e { - BFI_PHY_H2I_QUERY_REQ = 1, - BFI_PHY_H2I_STATS_REQ = 2, - BFI_PHY_H2I_WRITE_REQ = 3, - BFI_PHY_H2I_READ_REQ = 4, -}; - -enum bfi_phy_i2h_msgs_e { - BFI_PHY_I2H_QUERY_RSP = BFA_I2HM(1), - BFI_PHY_I2H_STATS_RSP = BFA_I2HM(2), - BFI_PHY_I2H_WRITE_RSP = BFA_I2HM(3), - BFI_PHY_I2H_READ_RSP = BFA_I2HM(4), -}; - -/* - * External PHY query request - */ -struct bfi_phy_query_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - struct bfi_alen_s alen; -}; - -/* - * External PHY stats request - */ -struct bfi_phy_stats_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - struct bfi_alen_s alen; -}; - -/* - * External PHY write request - */ -struct bfi_phy_write_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 last; - u8 rsv[2]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * External PHY read request - */ -struct bfi_phy_read_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 instance; - u8 rsv[3]; - u32 offset; - u32 length; - struct bfi_alen_s alen; -}; - -/* - * External PHY query response - */ -struct bfi_phy_query_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * External PHY stats response - */ -struct bfi_phy_stats_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; -}; - -/* - * External PHY read response - */ -struct bfi_phy_read_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; - u32 length; -}; - -/* - * External PHY write response - */ -struct bfi_phy_write_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u32 status; - u32 length; -}; - -#pragma pack() - -#endif /* __BFI_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfi_ms.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfi_ms.h deleted file mode 100644 index d4220e13..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfi_ms.h +++ /dev/null @@ -1,865 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef __BFI_MS_H__ -#define __BFI_MS_H__ - -#include "bfi.h" -#include "bfa_fc.h" -#include "bfa_defs_svc.h" - -#pragma pack(1) - -enum bfi_iocfc_h2i_msgs { - BFI_IOCFC_H2I_CFG_REQ = 1, - BFI_IOCFC_H2I_SET_INTR_REQ = 2, - BFI_IOCFC_H2I_UPDATEQ_REQ = 3, - BFI_IOCFC_H2I_FAA_QUERY_REQ = 4, - BFI_IOCFC_H2I_ADDR_REQ = 5, -}; - -enum bfi_iocfc_i2h_msgs { - BFI_IOCFC_I2H_CFG_REPLY = BFA_I2HM(1), - BFI_IOCFC_I2H_UPDATEQ_RSP = BFA_I2HM(3), - BFI_IOCFC_I2H_FAA_QUERY_RSP = BFA_I2HM(4), - BFI_IOCFC_I2H_ADDR_MSG = BFA_I2HM(5), -}; - -struct bfi_iocfc_cfg_s { - u8 num_cqs; /* Number of CQs to be used */ - u8 sense_buf_len; /* SCSI sense length */ - u16 rsvd_1; - u32 endian_sig; /* endian signature of host */ - u8 rsvd_2; - u8 single_msix_vec; - u8 rsvd[2]; - __be16 num_ioim_reqs; - __be16 num_fwtio_reqs; - - - /* - * Request and response circular queue base addresses, size and - * shadow index pointers. - */ - union bfi_addr_u req_cq_ba[BFI_IOC_MAX_CQS]; - union bfi_addr_u req_shadow_ci[BFI_IOC_MAX_CQS]; - __be16 req_cq_elems[BFI_IOC_MAX_CQS]; - union bfi_addr_u rsp_cq_ba[BFI_IOC_MAX_CQS]; - union bfi_addr_u rsp_shadow_pi[BFI_IOC_MAX_CQS]; - __be16 rsp_cq_elems[BFI_IOC_MAX_CQS]; - - union bfi_addr_u stats_addr; /* DMA-able address for stats */ - union bfi_addr_u cfgrsp_addr; /* config response dma address */ - union bfi_addr_u ioim_snsbase[BFI_IOIM_SNSBUF_SEGS]; - /* IO sense buf base addr segments */ - struct bfa_iocfc_intr_attr_s intr_attr; /* IOC interrupt attributes */ -}; - -/* - * Boot target wwn information for this port. This contains either the stored - * or discovered boot target port wwns for the port. - */ -struct bfi_iocfc_bootwwns { - wwn_t wwn[BFA_BOOT_BOOTLUN_MAX]; - u8 nwwns; - u8 rsvd[7]; -}; - -/** - * Queue configuration response from firmware - */ -struct bfi_iocfc_qreg_s { - u32 cpe_q_ci_off[BFI_IOC_MAX_CQS]; - u32 cpe_q_pi_off[BFI_IOC_MAX_CQS]; - u32 cpe_qctl_off[BFI_IOC_MAX_CQS]; - u32 rme_q_ci_off[BFI_IOC_MAX_CQS]; - u32 rme_q_pi_off[BFI_IOC_MAX_CQS]; - u32 rme_qctl_off[BFI_IOC_MAX_CQS]; - u8 hw_qid[BFI_IOC_MAX_CQS]; -}; - -struct bfi_iocfc_cfgrsp_s { - struct bfa_iocfc_fwcfg_s fwcfg; - struct bfa_iocfc_intr_attr_s intr_attr; - struct bfi_iocfc_bootwwns bootwwns; - struct bfi_pbc_s pbc_cfg; - struct bfi_iocfc_qreg_s qreg; -}; - -/* - * BFI_IOCFC_H2I_CFG_REQ message - */ -struct bfi_iocfc_cfg_req_s { - struct bfi_mhdr_s mh; - union bfi_addr_u ioc_cfg_dma_addr; -}; - - -/* - * BFI_IOCFC_I2H_CFG_REPLY message - */ -struct bfi_iocfc_cfg_reply_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u8 cfg_success; /* cfg reply status */ - u8 lpu_bm; /* LPUs assigned for this IOC */ - u8 rsvd[2]; -}; - - -/* - * BFI_IOCFC_H2I_SET_INTR_REQ message - */ -struct bfi_iocfc_set_intr_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 coalesce; /* enable intr coalescing */ - u8 rsvd[3]; - __be16 delay; /* delay timer 0..1125us */ - __be16 latency; /* latency timer 0..225us */ -}; - - -/* - * BFI_IOCFC_H2I_UPDATEQ_REQ message - */ -struct bfi_iocfc_updateq_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u32 reqq_ba; /* reqq base addr */ - u32 rspq_ba; /* rspq base addr */ - u32 reqq_sci; /* reqq shadow ci */ - u32 rspq_spi; /* rspq shadow pi */ -}; - - -/* - * BFI_IOCFC_I2H_UPDATEQ_RSP message - */ -struct bfi_iocfc_updateq_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* updateq status */ - u8 rsvd[3]; -}; - - -/* - * H2I Messages - */ -union bfi_iocfc_h2i_msg_u { - struct bfi_mhdr_s mh; - struct bfi_iocfc_cfg_req_s cfg_req; - struct bfi_iocfc_updateq_req_s updateq_req; - u32 mboxmsg[BFI_IOC_MSGSZ]; -}; - - -/* - * I2H Messages - */ -union bfi_iocfc_i2h_msg_u { - struct bfi_mhdr_s mh; - struct bfi_iocfc_cfg_reply_s cfg_reply; - struct bfi_iocfc_updateq_rsp_s updateq_rsp; - u32 mboxmsg[BFI_IOC_MSGSZ]; -}; - -/* - * BFI_IOCFC_H2I_FAA_ENABLE_REQ BFI_IOCFC_H2I_FAA_DISABLE_REQ message - */ -struct bfi_faa_en_dis_s { - struct bfi_mhdr_s mh; /* common msg header */ -}; - -struct bfi_faa_addr_msg_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 rsvd[4]; - wwn_t pwwn; /* Fabric acquired PWWN */ - wwn_t nwwn; /* Fabric acquired PWWN */ -}; - -/* - * BFI_IOCFC_H2I_FAA_QUERY_REQ message - */ -struct bfi_faa_query_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 faa_status; /* FAA status */ - u8 addr_source; /* PWWN source */ - u8 rsvd[2]; - wwn_t faa; /* Fabric acquired PWWN */ -}; - -/* - * BFI_IOCFC_I2H_FAA_ENABLE_RSP, BFI_IOCFC_I2H_FAA_DISABLE_RSP message - */ -struct bfi_faa_en_dis_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* updateq status */ - u8 rsvd[3]; -}; - -/* - * BFI_IOCFC_I2H_FAA_QUERY_RSP message - */ -#define bfi_faa_query_rsp_t struct bfi_faa_query_s - -enum bfi_fcport_h2i { - BFI_FCPORT_H2I_ENABLE_REQ = (1), - BFI_FCPORT_H2I_DISABLE_REQ = (2), - BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ = (3), - BFI_FCPORT_H2I_STATS_GET_REQ = (4), - BFI_FCPORT_H2I_STATS_CLEAR_REQ = (5), -}; - - -enum bfi_fcport_i2h { - BFI_FCPORT_I2H_ENABLE_RSP = BFA_I2HM(1), - BFI_FCPORT_I2H_DISABLE_RSP = BFA_I2HM(2), - BFI_FCPORT_I2H_SET_SVC_PARAMS_RSP = BFA_I2HM(3), - BFI_FCPORT_I2H_STATS_GET_RSP = BFA_I2HM(4), - BFI_FCPORT_I2H_STATS_CLEAR_RSP = BFA_I2HM(5), - BFI_FCPORT_I2H_EVENT = BFA_I2HM(6), - BFI_FCPORT_I2H_TRUNK_SCN = BFA_I2HM(7), - BFI_FCPORT_I2H_ENABLE_AEN = BFA_I2HM(8), - BFI_FCPORT_I2H_DISABLE_AEN = BFA_I2HM(9), -}; - - -/* - * Generic REQ type - */ -struct bfi_fcport_req_s { - struct bfi_mhdr_s mh; /* msg header */ - u32 msgtag; /* msgtag for reply */ -}; - -/* - * Generic RSP type - */ -struct bfi_fcport_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* port enable status */ - u8 rsvd[3]; - struct bfa_port_cfg_s port_cfg;/* port configuration */ - u32 msgtag; /* msgtag for reply */ -}; - -/* - * BFI_FCPORT_H2I_ENABLE_REQ - */ -struct bfi_fcport_enable_req_s { - struct bfi_mhdr_s mh; /* msg header */ - u32 rsvd1; - wwn_t nwwn; /* node wwn of physical port */ - wwn_t pwwn; /* port wwn of physical port */ - struct bfa_port_cfg_s port_cfg; /* port configuration */ - union bfi_addr_u stats_dma_addr; /* DMA address for stats */ - u32 msgtag; /* msgtag for reply */ - u8 use_flash_cfg; /* get prot cfg from flash */ - u8 rsvd2[3]; -}; - -/* - * BFI_FCPORT_H2I_SET_SVC_PARAMS_REQ - */ -struct bfi_fcport_set_svc_params_req_s { - struct bfi_mhdr_s mh; /* msg header */ - __be16 tx_bbcredit; /* Tx credits */ - u8 bb_scn; /* BB_SC FC credit recovery */ - u8 rsvd; -}; - -/* - * BFI_FCPORT_I2H_EVENT - */ -struct bfi_fcport_event_s { - struct bfi_mhdr_s mh; /* common msg header */ - struct bfa_port_link_s link_state; -}; - -/* - * BFI_FCPORT_I2H_TRUNK_SCN - */ -struct bfi_fcport_trunk_link_s { - wwn_t trunk_wwn; - u8 fctl; /* bfa_trunk_link_fctl_t */ - u8 state; /* bfa_trunk_link_state_t */ - u8 speed; /* bfa_port_speed_t */ - u8 rsvd; - __be32 deskew; -}; - -#define BFI_FCPORT_MAX_LINKS 2 -struct bfi_fcport_trunk_scn_s { - struct bfi_mhdr_s mh; - u8 trunk_state; /* bfa_trunk_state_t */ - u8 trunk_speed; /* bfa_port_speed_t */ - u8 rsvd_a[2]; - struct bfi_fcport_trunk_link_s tlink[BFI_FCPORT_MAX_LINKS]; -}; - -/* - * fcport H2I message - */ -union bfi_fcport_h2i_msg_u { - struct bfi_mhdr_s *mhdr; - struct bfi_fcport_enable_req_s *penable; - struct bfi_fcport_req_s *pdisable; - struct bfi_fcport_set_svc_params_req_s *psetsvcparams; - struct bfi_fcport_req_s *pstatsget; - struct bfi_fcport_req_s *pstatsclear; -}; - -/* - * fcport I2H message - */ -union bfi_fcport_i2h_msg_u { - struct bfi_msg_s *msg; - struct bfi_fcport_rsp_s *penable_rsp; - struct bfi_fcport_rsp_s *pdisable_rsp; - struct bfi_fcport_rsp_s *psetsvcparams_rsp; - struct bfi_fcport_rsp_s *pstatsget_rsp; - struct bfi_fcport_rsp_s *pstatsclear_rsp; - struct bfi_fcport_event_s *event; - struct bfi_fcport_trunk_scn_s *trunk_scn; -}; - -enum bfi_fcxp_h2i { - BFI_FCXP_H2I_SEND_REQ = 1, -}; - -enum bfi_fcxp_i2h { - BFI_FCXP_I2H_SEND_RSP = BFA_I2HM(1), -}; - -#define BFA_FCXP_MAX_SGES 2 - -/* - * FCXP send request structure - */ -struct bfi_fcxp_send_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - __be16 fcxp_tag; /* driver request tag */ - __be16 max_frmsz; /* max send frame size */ - __be16 vf_id; /* vsan tag if applicable */ - u16 rport_fw_hndl; /* FW Handle for the remote port */ - u8 class; /* FC class used for req/rsp */ - u8 rsp_timeout; /* timeout in secs, 0-no response */ - u8 cts; /* continue sequence */ - u8 lp_fwtag; /* lport tag */ - struct fchs_s fchs; /* request FC header structure */ - __be32 req_len; /* request payload length */ - __be32 rsp_maxlen; /* max response length expected */ - struct bfi_alen_s req_alen; /* request buffer */ - struct bfi_alen_s rsp_alen; /* response buffer */ -}; - -/* - * FCXP send response structure - */ -struct bfi_fcxp_send_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - __be16 fcxp_tag; /* send request tag */ - u8 req_status; /* request status */ - u8 rsvd; - __be32 rsp_len; /* actual response length */ - __be32 residue_len; /* residual response length */ - struct fchs_s fchs; /* response FC header structure */ -}; - -enum bfi_uf_h2i { - BFI_UF_H2I_BUF_POST = 1, -}; - -enum bfi_uf_i2h { - BFI_UF_I2H_FRM_RCVD = BFA_I2HM(1), -}; - -#define BFA_UF_MAX_SGES 2 - -struct bfi_uf_buf_post_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 buf_tag; /* buffer tag */ - __be16 buf_len; /* total buffer length */ - struct bfi_alen_s alen; /* buffer address/len pair */ -}; - -struct bfi_uf_frm_rcvd_s { - struct bfi_mhdr_s mh; /* Common msg header */ - u16 buf_tag; /* buffer tag */ - u16 rsvd; - u16 frm_len; /* received frame length */ - u16 xfr_len; /* tranferred length */ -}; - -enum bfi_lps_h2i_msgs { - BFI_LPS_H2I_LOGIN_REQ = 1, - BFI_LPS_H2I_LOGOUT_REQ = 2, - BFI_LPS_H2I_N2N_PID_REQ = 3, -}; - -enum bfi_lps_i2h_msgs { - BFI_LPS_I2H_LOGIN_RSP = BFA_I2HM(1), - BFI_LPS_I2H_LOGOUT_RSP = BFA_I2HM(2), - BFI_LPS_I2H_CVL_EVENT = BFA_I2HM(3), -}; - -struct bfi_lps_login_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; - u8 alpa; - __be16 pdu_size; - wwn_t pwwn; - wwn_t nwwn; - u8 fdisc; - u8 auth_en; - u8 lps_role; - u8 bb_scn; -}; - -struct bfi_lps_login_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; - u8 status; - u8 lsrjt_rsn; - u8 lsrjt_expl; - wwn_t port_name; - wwn_t node_name; - __be16 bb_credit; - u8 f_port; - u8 npiv_en; - u32 lp_pid:24; - u32 auth_req:8; - mac_t lp_mac; - mac_t fcf_mac; - u8 ext_status; - u8 brcd_switch; /* attached peer is brcd switch */ - u8 bb_scn; /* atatched port's bb_scn */ - u8 bfa_tag; -}; - -struct bfi_lps_logout_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; - u8 rsvd[3]; - wwn_t port_name; -}; - -struct bfi_lps_logout_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; - u8 status; - u8 rsvd[2]; -}; - -struct bfi_lps_cvl_event_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 bfa_tag; - u8 rsvd[3]; -}; - -struct bfi_lps_n2n_pid_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 fw_tag; - u32 lp_pid:24; -}; - -union bfi_lps_h2i_msg_u { - struct bfi_mhdr_s *msg; - struct bfi_lps_login_req_s *login_req; - struct bfi_lps_logout_req_s *logout_req; - struct bfi_lps_n2n_pid_req_s *n2n_pid_req; -}; - -union bfi_lps_i2h_msg_u { - struct bfi_msg_s *msg; - struct bfi_lps_login_rsp_s *login_rsp; - struct bfi_lps_logout_rsp_s *logout_rsp; - struct bfi_lps_cvl_event_s *cvl_event; -}; - -enum bfi_rport_h2i_msgs { - BFI_RPORT_H2I_CREATE_REQ = 1, - BFI_RPORT_H2I_DELETE_REQ = 2, - BFI_RPORT_H2I_SET_SPEED_REQ = 3, -}; - -enum bfi_rport_i2h_msgs { - BFI_RPORT_I2H_CREATE_RSP = BFA_I2HM(1), - BFI_RPORT_I2H_DELETE_RSP = BFA_I2HM(2), - BFI_RPORT_I2H_QOS_SCN = BFA_I2HM(3), -}; - -struct bfi_rport_create_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* host rport handle */ - __be16 max_frmsz; /* max rcv pdu size */ - u32 pid:24, /* remote port ID */ - lp_fwtag:8; /* local port tag */ - u32 local_pid:24, /* local port ID */ - cisc:8; - u8 fc_class; /* supported FC classes */ - u8 vf_en; /* virtual fabric enable */ - u16 vf_id; /* virtual fabric ID */ -}; - -struct bfi_rport_create_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u8 status; /* rport creation status */ - u8 rsvd[3]; - u16 bfa_handle; /* host rport handle */ - u16 fw_handle; /* firmware rport handle */ - struct bfa_rport_qos_attr_s qos_attr; /* QoS Attributes */ -}; - -struct bfa_rport_speed_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 fw_handle; /* firmware rport handle */ - u8 speed; /* rport's speed via RPSC */ - u8 rsvd; -}; - -struct bfi_rport_delete_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 fw_handle; /* firmware rport handle */ - u16 rsvd; -}; - -struct bfi_rport_delete_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* host rport handle */ - u8 status; /* rport deletion status */ - u8 rsvd; -}; - -struct bfi_rport_qos_scn_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* host rport handle */ - u16 rsvd; - struct bfa_rport_qos_attr_s old_qos_attr; /* Old QoS Attributes */ - struct bfa_rport_qos_attr_s new_qos_attr; /* New QoS Attributes */ -}; - -union bfi_rport_h2i_msg_u { - struct bfi_msg_s *msg; - struct bfi_rport_create_req_s *create_req; - struct bfi_rport_delete_req_s *delete_req; - struct bfi_rport_speed_req_s *speed_req; -}; - -union bfi_rport_i2h_msg_u { - struct bfi_msg_s *msg; - struct bfi_rport_create_rsp_s *create_rsp; - struct bfi_rport_delete_rsp_s *delete_rsp; - struct bfi_rport_qos_scn_s *qos_scn_evt; -}; - -/* - * Initiator mode I-T nexus interface defines. - */ - -enum bfi_itn_h2i { - BFI_ITN_H2I_CREATE_REQ = 1, /* i-t nexus creation */ - BFI_ITN_H2I_DELETE_REQ = 2, /* i-t nexus deletion */ -}; - -enum bfi_itn_i2h { - BFI_ITN_I2H_CREATE_RSP = BFA_I2HM(1), - BFI_ITN_I2H_DELETE_RSP = BFA_I2HM(2), - BFI_ITN_I2H_SLER_EVENT = BFA_I2HM(3), -}; - -struct bfi_itn_create_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 fw_handle; /* f/w handle for itnim */ - u8 class; /* FC class for IO */ - u8 seq_rec; /* sequence recovery support */ - u8 msg_no; /* seq id of the msg */ - u8 role; -}; - -struct bfi_itn_create_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* bfa handle for itnim */ - u8 status; /* fcp request status */ - u8 seq_id; /* seq id of the msg */ -}; - -struct bfi_itn_delete_req_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 fw_handle; /* f/w itnim handle */ - u8 seq_id; /* seq id of the msg */ - u8 rsvd; -}; - -struct bfi_itn_delete_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* bfa handle for itnim */ - u8 status; /* fcp request status */ - u8 seq_id; /* seq id of the msg */ -}; - -struct bfi_itn_sler_event_s { - struct bfi_mhdr_s mh; /* common msg header */ - u16 bfa_handle; /* bfa handle for itnim */ - u16 rsvd; -}; - -union bfi_itn_h2i_msg_u { - struct bfi_itn_create_req_s *create_req; - struct bfi_itn_delete_req_s *delete_req; - struct bfi_msg_s *msg; -}; - -union bfi_itn_i2h_msg_u { - struct bfi_itn_create_rsp_s *create_rsp; - struct bfi_itn_delete_rsp_s *delete_rsp; - struct bfi_itn_sler_event_s *sler_event; - struct bfi_msg_s *msg; -}; - -/* - * Initiator mode IO interface defines. - */ - -enum bfi_ioim_h2i { - BFI_IOIM_H2I_IOABORT_REQ = 1, /* IO abort request */ - BFI_IOIM_H2I_IOCLEANUP_REQ = 2, /* IO cleanup request */ -}; - -enum bfi_ioim_i2h { - BFI_IOIM_I2H_IO_RSP = BFA_I2HM(1), /* non-fp IO response */ - BFI_IOIM_I2H_IOABORT_RSP = BFA_I2HM(2), /* ABORT rsp */ -}; - -/* - * IO command DIF info - */ -struct bfi_ioim_dif_s { - u32 dif_info[4]; -}; - -/* - * FCP IO messages overview - * - * @note - * - Max CDB length supported is 64 bytes. - * - SCSI Linked commands and SCSI bi-directional Commands not - * supported. - * - */ -struct bfi_ioim_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - __be16 io_tag; /* I/O tag */ - u16 rport_hdl; /* itnim/rport firmware handle */ - struct fcp_cmnd_s cmnd; /* IO request info */ - - /* - * SG elements array within the IO request must be double word - * aligned. This aligment is required to optimize SGM setup for the IO. - */ - struct bfi_sge_s sges[BFI_SGE_INLINE_MAX]; - u8 io_timeout; - u8 dif_en; - u8 rsvd_a[2]; - struct bfi_ioim_dif_s dif; -}; - -/* - * This table shows various IO status codes from firmware and their - * meaning. Host driver can use these status codes to further process - * IO completions. - * - * BFI_IOIM_STS_OK : IO completed with error free SCSI & - * transport status. - * io-tag can be reused. - * - * BFA_IOIM_STS_SCSI_ERR : IO completed with scsi error. - * - io-tag can be reused. - * - * BFI_IOIM_STS_HOST_ABORTED : IO was aborted successfully due to - * host request. - * - io-tag cannot be reused yet. - * - * BFI_IOIM_STS_ABORTED : IO was aborted successfully - * internally by f/w. - * - io-tag cannot be reused yet. - * - * BFI_IOIM_STS_TIMEDOUT : IO timedout and ABTS/RRQ is happening - * in the firmware and - * - io-tag cannot be reused yet. - * - * BFI_IOIM_STS_SQER_NEEDED : Firmware could not recover the IO - * with sequence level error - * logic and hence host needs to retry - * this IO with a different IO tag - * - io-tag cannot be used yet. - * - * BFI_IOIM_STS_NEXUS_ABORT : Second Level Error Recovery from host - * is required because 2 consecutive ABTS - * timedout and host needs logout and - * re-login with the target - * - io-tag cannot be used yet. - * - * BFI_IOIM_STS_UNDERRUN : IO completed with SCSI status good, - * but the data tranferred is less than - * the fcp data length in the command. - * ex. SCSI INQUIRY where transferred - * data length and residue count in FCP - * response accounts for total fcp-dl - * - io-tag can be reused. - * - * BFI_IOIM_STS_OVERRUN : IO completed with SCSI status good, - * but the data transerred is more than - * fcp data length in the command. ex. - * TAPE IOs where blocks can of unequal - * lengths. - * - io-tag can be reused. - * - * BFI_IOIM_STS_RES_FREE : Firmware has completed using io-tag - * during abort process - * - io-tag can be reused. - * - * BFI_IOIM_STS_PROTO_ERR : Firmware detected a protocol error. - * ex target sent more data than - * requested, or there was data frame - * loss and other reasons - * - io-tag cannot be used yet. - * - * BFI_IOIM_STS_DIF_ERR : Firwmare detected DIF error. ex: DIF - * CRC err or Ref Tag err or App tag err. - * - io-tag can be reused. - * - * BFA_IOIM_STS_TSK_MGT_ABORT : IO was aborted because of Task - * Management command from the host - * - io-tag can be reused. - * - * BFI_IOIM_STS_UTAG : Firmware does not know about this - * io_tag. - * - io-tag can be reused. - */ -enum bfi_ioim_status { - BFI_IOIM_STS_OK = 0, - BFI_IOIM_STS_HOST_ABORTED = 1, - BFI_IOIM_STS_ABORTED = 2, - BFI_IOIM_STS_TIMEDOUT = 3, - BFI_IOIM_STS_RES_FREE = 4, - BFI_IOIM_STS_SQER_NEEDED = 5, - BFI_IOIM_STS_PROTO_ERR = 6, - BFI_IOIM_STS_UTAG = 7, - BFI_IOIM_STS_PATHTOV = 8, -}; - -/* - * I/O response message - */ -struct bfi_ioim_rsp_s { - struct bfi_mhdr_s mh; /* common msg header */ - __be16 io_tag; /* completed IO tag */ - u16 bfa_rport_hndl; /* releated rport handle */ - u8 io_status; /* IO completion status */ - u8 reuse_io_tag; /* IO tag can be reused */ - u16 abort_tag; /* host abort request tag */ - u8 scsi_status; /* scsi status from target */ - u8 sns_len; /* scsi sense length */ - u8 resid_flags; /* IO residue flags */ - u8 rsvd_a; - __be32 residue; /* IO residual length in bytes */ - u32 rsvd_b[3]; -}; - -struct bfi_ioim_abort_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - __be16 io_tag; /* I/O tag */ - u16 abort_tag; /* unique request tag */ -}; - -/* - * Initiator mode task management command interface defines. - */ - -enum bfi_tskim_h2i { - BFI_TSKIM_H2I_TM_REQ = 1, /* task-mgmt command */ - BFI_TSKIM_H2I_ABORT_REQ = 2, /* task-mgmt command */ -}; - -enum bfi_tskim_i2h { - BFI_TSKIM_I2H_TM_RSP = BFA_I2HM(1), -}; - -struct bfi_tskim_req_s { - struct bfi_mhdr_s mh; /* Common msg header */ - __be16 tsk_tag; /* task management tag */ - u16 itn_fhdl; /* itn firmware handle */ - struct scsi_lun lun; /* LU number */ - u8 tm_flags; /* see enum fcp_tm_cmnd */ - u8 t_secs; /* Timeout value in seconds */ - u8 rsvd[2]; -}; - -struct bfi_tskim_abortreq_s { - struct bfi_mhdr_s mh; /* Common msg header */ - __be16 tsk_tag; /* task management tag */ - u16 rsvd; -}; - -enum bfi_tskim_status { - /* - * Following are FCP-4 spec defined status codes, - * **DO NOT CHANGE THEM ** - */ - BFI_TSKIM_STS_OK = 0, - BFI_TSKIM_STS_NOT_SUPP = 4, - BFI_TSKIM_STS_FAILED = 5, - - /* - * Defined by BFA - */ - BFI_TSKIM_STS_TIMEOUT = 10, /* TM request timedout */ - BFI_TSKIM_STS_ABORTED = 11, /* Aborted on host request */ -}; - -struct bfi_tskim_rsp_s { - struct bfi_mhdr_s mh; /* Common msg header */ - __be16 tsk_tag; /* task mgmt cmnd tag */ - u8 tsk_status; /* @ref bfi_tskim_status */ - u8 rsvd; -}; - -#pragma pack() - -/* - * Crossbow PCI MSI-X vector defines - */ -enum { - BFI_MSIX_CPE_QMIN_CB = 0, - BFI_MSIX_CPE_QMAX_CB = 7, - BFI_MSIX_RME_QMIN_CB = 8, - BFI_MSIX_RME_QMAX_CB = 15, - BFI_MSIX_CB_MAX = 22, -}; - -/* - * Catapult FC PCI MSI-X vector defines - */ -enum { - BFI_MSIX_LPU_ERR_CT = 0, - BFI_MSIX_CPE_QMIN_CT = 1, - BFI_MSIX_CPE_QMAX_CT = 4, - BFI_MSIX_RME_QMIN_CT = 5, - BFI_MSIX_RME_QMAX_CT = 8, - BFI_MSIX_CT_MAX = 9, -}; - -#endif /* __BFI_MS_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bfa/bfi_reg.h b/ANDROID_3.4.5/drivers/scsi/bfa/bfi_reg.h deleted file mode 100644 index ed5f159e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bfa/bfi_reg.h +++ /dev/null @@ -1,456 +0,0 @@ -/* - * Copyright (c) 2005-2010 Brocade Communications Systems, Inc. - * All rights reserved - * www.brocade.com - * - * Linux driver for Brocade Fibre Channel Host Bus Adapter. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License (GPL) Version 2 as - * published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -/* - * bfi_reg.h ASIC register defines for all Brocade adapter ASICs - */ - -#ifndef __BFI_REG_H__ -#define __BFI_REG_H__ - -#define HOSTFN0_INT_STATUS 0x00014000 /* cb/ct */ -#define HOSTFN1_INT_STATUS 0x00014100 /* cb/ct */ -#define HOSTFN2_INT_STATUS 0x00014300 /* ct */ -#define HOSTFN3_INT_STATUS 0x00014400 /* ct */ -#define HOSTFN0_INT_MSK 0x00014004 /* cb/ct */ -#define HOSTFN1_INT_MSK 0x00014104 /* cb/ct */ -#define HOSTFN2_INT_MSK 0x00014304 /* ct */ -#define HOSTFN3_INT_MSK 0x00014404 /* ct */ - -#define HOST_PAGE_NUM_FN0 0x00014008 /* cb/ct */ -#define HOST_PAGE_NUM_FN1 0x00014108 /* cb/ct */ -#define HOST_PAGE_NUM_FN2 0x00014308 /* ct */ -#define HOST_PAGE_NUM_FN3 0x00014408 /* ct */ - -#define APP_PLL_LCLK_CTL_REG 0x00014204 /* cb/ct */ -#define __P_LCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_LCLK_SRAM_USE_100MHZ 0x00100000 -#define __APP_PLL_LCLK_RESET_TIMER_MK 0x000e0000 -#define __APP_PLL_LCLK_RESET_TIMER_SH 17 -#define __APP_PLL_LCLK_RESET_TIMER(_v) ((_v) << __APP_PLL_LCLK_RESET_TIMER_SH) -#define __APP_PLL_LCLK_LOGIC_SOFT_RESET 0x00010000 -#define __APP_PLL_LCLK_CNTLMT0_1_MK 0x0000c000 -#define __APP_PLL_LCLK_CNTLMT0_1_SH 14 -#define __APP_PLL_LCLK_CNTLMT0_1(_v) ((_v) << __APP_PLL_LCLK_CNTLMT0_1_SH) -#define __APP_PLL_LCLK_JITLMT0_1_MK 0x00003000 -#define __APP_PLL_LCLK_JITLMT0_1_SH 12 -#define __APP_PLL_LCLK_JITLMT0_1(_v) ((_v) << __APP_PLL_LCLK_JITLMT0_1_SH) -#define __APP_PLL_LCLK_HREF 0x00000800 -#define __APP_PLL_LCLK_HDIV 0x00000400 -#define __APP_PLL_LCLK_P0_1_MK 0x00000300 -#define __APP_PLL_LCLK_P0_1_SH 8 -#define __APP_PLL_LCLK_P0_1(_v) ((_v) << __APP_PLL_LCLK_P0_1_SH) -#define __APP_PLL_LCLK_Z0_2_MK 0x000000e0 -#define __APP_PLL_LCLK_Z0_2_SH 5 -#define __APP_PLL_LCLK_Z0_2(_v) ((_v) << __APP_PLL_LCLK_Z0_2_SH) -#define __APP_PLL_LCLK_RSEL200500 0x00000010 -#define __APP_PLL_LCLK_ENARST 0x00000008 -#define __APP_PLL_LCLK_BYPASS 0x00000004 -#define __APP_PLL_LCLK_LRESETN 0x00000002 -#define __APP_PLL_LCLK_ENABLE 0x00000001 -#define APP_PLL_SCLK_CTL_REG 0x00014208 /* cb/ct */ -#define __P_SCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_SCLK_RESET_TIMER_MK 0x000e0000 -#define __APP_PLL_SCLK_RESET_TIMER_SH 17 -#define __APP_PLL_SCLK_RESET_TIMER(_v) ((_v) << __APP_PLL_SCLK_RESET_TIMER_SH) -#define __APP_PLL_SCLK_LOGIC_SOFT_RESET 0x00010000 -#define __APP_PLL_SCLK_CNTLMT0_1_MK 0x0000c000 -#define __APP_PLL_SCLK_CNTLMT0_1_SH 14 -#define __APP_PLL_SCLK_CNTLMT0_1(_v) ((_v) << __APP_PLL_SCLK_CNTLMT0_1_SH) -#define __APP_PLL_SCLK_JITLMT0_1_MK 0x00003000 -#define __APP_PLL_SCLK_JITLMT0_1_SH 12 -#define __APP_PLL_SCLK_JITLMT0_1(_v) ((_v) << __APP_PLL_SCLK_JITLMT0_1_SH) -#define __APP_PLL_SCLK_HREF 0x00000800 -#define __APP_PLL_SCLK_HDIV 0x00000400 -#define __APP_PLL_SCLK_P0_1_MK 0x00000300 -#define __APP_PLL_SCLK_P0_1_SH 8 -#define __APP_PLL_SCLK_P0_1(_v) ((_v) << __APP_PLL_SCLK_P0_1_SH) -#define __APP_PLL_SCLK_Z0_2_MK 0x000000e0 -#define __APP_PLL_SCLK_Z0_2_SH 5 -#define __APP_PLL_SCLK_Z0_2(_v) ((_v) << __APP_PLL_SCLK_Z0_2_SH) -#define __APP_PLL_SCLK_RSEL200500 0x00000010 -#define __APP_PLL_SCLK_ENARST 0x00000008 -#define __APP_PLL_SCLK_BYPASS 0x00000004 -#define __APP_PLL_SCLK_LRESETN 0x00000002 -#define __APP_PLL_SCLK_ENABLE 0x00000001 -#define __ENABLE_MAC_AHB_1 0x00800000 /* ct */ -#define __ENABLE_MAC_AHB_0 0x00400000 /* ct */ -#define __ENABLE_MAC_1 0x00200000 /* ct */ -#define __ENABLE_MAC_0 0x00100000 /* ct */ - -#define HOST_SEM0_REG 0x00014230 /* cb/ct */ -#define HOST_SEM1_REG 0x00014234 /* cb/ct */ -#define HOST_SEM2_REG 0x00014238 /* cb/ct */ -#define HOST_SEM3_REG 0x0001423c /* cb/ct */ -#define HOST_SEM4_REG 0x00014610 /* cb/ct */ -#define HOST_SEM5_REG 0x00014614 /* cb/ct */ -#define HOST_SEM6_REG 0x00014618 /* cb/ct */ -#define HOST_SEM7_REG 0x0001461c /* cb/ct */ -#define HOST_SEM0_INFO_REG 0x00014240 /* cb/ct */ -#define HOST_SEM1_INFO_REG 0x00014244 /* cb/ct */ -#define HOST_SEM2_INFO_REG 0x00014248 /* cb/ct */ -#define HOST_SEM3_INFO_REG 0x0001424c /* cb/ct */ -#define HOST_SEM4_INFO_REG 0x00014620 /* cb/ct */ -#define HOST_SEM5_INFO_REG 0x00014624 /* cb/ct */ -#define HOST_SEM6_INFO_REG 0x00014628 /* cb/ct */ -#define HOST_SEM7_INFO_REG 0x0001462c /* cb/ct */ - -#define HOSTFN0_LPU0_CMD_STAT 0x00019000 /* cb/ct */ -#define HOSTFN0_LPU1_CMD_STAT 0x00019004 /* cb/ct */ -#define HOSTFN1_LPU0_CMD_STAT 0x00019010 /* cb/ct */ -#define HOSTFN1_LPU1_CMD_STAT 0x00019014 /* cb/ct */ -#define HOSTFN2_LPU0_CMD_STAT 0x00019150 /* ct */ -#define HOSTFN2_LPU1_CMD_STAT 0x00019154 /* ct */ -#define HOSTFN3_LPU0_CMD_STAT 0x00019160 /* ct */ -#define HOSTFN3_LPU1_CMD_STAT 0x00019164 /* ct */ -#define LPU0_HOSTFN0_CMD_STAT 0x00019008 /* cb/ct */ -#define LPU1_HOSTFN0_CMD_STAT 0x0001900c /* cb/ct */ -#define LPU0_HOSTFN1_CMD_STAT 0x00019018 /* cb/ct */ -#define LPU1_HOSTFN1_CMD_STAT 0x0001901c /* cb/ct */ -#define LPU0_HOSTFN2_CMD_STAT 0x00019158 /* ct */ -#define LPU1_HOSTFN2_CMD_STAT 0x0001915c /* ct */ -#define LPU0_HOSTFN3_CMD_STAT 0x00019168 /* ct */ -#define LPU1_HOSTFN3_CMD_STAT 0x0001916c /* ct */ - -#define PSS_CTL_REG 0x00018800 /* cb/ct */ -#define __PSS_I2C_CLK_DIV_MK 0x007f0000 -#define __PSS_I2C_CLK_DIV_SH 16 -#define __PSS_I2C_CLK_DIV(_v) ((_v) << __PSS_I2C_CLK_DIV_SH) -#define __PSS_LMEM_INIT_DONE 0x00001000 -#define __PSS_LMEM_RESET 0x00000200 -#define __PSS_LMEM_INIT_EN 0x00000100 -#define __PSS_LPU1_RESET 0x00000002 -#define __PSS_LPU0_RESET 0x00000001 -#define PSS_ERR_STATUS_REG 0x00018810 /* cb/ct */ -#define ERR_SET_REG 0x00018818 /* cb/ct */ -#define PSS_GPIO_OUT_REG 0x000188c0 /* cb/ct */ -#define __PSS_GPIO_OUT_REG 0x00000fff -#define PSS_GPIO_OE_REG 0x000188c8 /* cb/ct */ -#define __PSS_GPIO_OE_REG 0x000000ff - -#define HOSTFN0_LPU_MBOX0_0 0x00019200 /* cb/ct */ -#define HOSTFN1_LPU_MBOX0_8 0x00019260 /* cb/ct */ -#define LPU_HOSTFN0_MBOX0_0 0x00019280 /* cb/ct */ -#define LPU_HOSTFN1_MBOX0_8 0x000192e0 /* cb/ct */ -#define HOSTFN2_LPU_MBOX0_0 0x00019400 /* ct */ -#define HOSTFN3_LPU_MBOX0_8 0x00019460 /* ct */ -#define LPU_HOSTFN2_MBOX0_0 0x00019480 /* ct */ -#define LPU_HOSTFN3_MBOX0_8 0x000194e0 /* ct */ - -#define HOST_MSIX_ERR_INDEX_FN0 0x0001400c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN1 0x0001410c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN2 0x0001430c /* ct */ -#define HOST_MSIX_ERR_INDEX_FN3 0x0001440c /* ct */ - -#define MBIST_CTL_REG 0x00014220 /* ct */ -#define __EDRAM_BISTR_START 0x00000004 -#define MBIST_STAT_REG 0x00014224 /* ct */ -#define ETH_MAC_SER_REG 0x00014288 /* ct */ -#define __APP_EMS_CKBUFAMPIN 0x00000020 -#define __APP_EMS_REFCLKSEL 0x00000010 -#define __APP_EMS_CMLCKSEL 0x00000008 -#define __APP_EMS_REFCKBUFEN2 0x00000004 -#define __APP_EMS_REFCKBUFEN1 0x00000002 -#define __APP_EMS_CHANNEL_SEL 0x00000001 -#define FNC_PERS_REG 0x00014604 /* ct */ -#define __F3_FUNCTION_ACTIVE 0x80000000 -#define __F3_FUNCTION_MODE 0x40000000 -#define __F3_PORT_MAP_MK 0x30000000 -#define __F3_PORT_MAP_SH 28 -#define __F3_PORT_MAP(_v) ((_v) << __F3_PORT_MAP_SH) -#define __F3_VM_MODE 0x08000000 -#define __F3_INTX_STATUS_MK 0x07000000 -#define __F3_INTX_STATUS_SH 24 -#define __F3_INTX_STATUS(_v) ((_v) << __F3_INTX_STATUS_SH) -#define __F2_FUNCTION_ACTIVE 0x00800000 -#define __F2_FUNCTION_MODE 0x00400000 -#define __F2_PORT_MAP_MK 0x00300000 -#define __F2_PORT_MAP_SH 20 -#define __F2_PORT_MAP(_v) ((_v) << __F2_PORT_MAP_SH) -#define __F2_VM_MODE 0x00080000 -#define __F2_INTX_STATUS_MK 0x00070000 -#define __F2_INTX_STATUS_SH 16 -#define __F2_INTX_STATUS(_v) ((_v) << __F2_INTX_STATUS_SH) -#define __F1_FUNCTION_ACTIVE 0x00008000 -#define __F1_FUNCTION_MODE 0x00004000 -#define __F1_PORT_MAP_MK 0x00003000 -#define __F1_PORT_MAP_SH 12 -#define __F1_PORT_MAP(_v) ((_v) << __F1_PORT_MAP_SH) -#define __F1_VM_MODE 0x00000800 -#define __F1_INTX_STATUS_MK 0x00000700 -#define __F1_INTX_STATUS_SH 8 -#define __F1_INTX_STATUS(_v) ((_v) << __F1_INTX_STATUS_SH) -#define __F0_FUNCTION_ACTIVE 0x00000080 -#define __F0_FUNCTION_MODE 0x00000040 -#define __F0_PORT_MAP_MK 0x00000030 -#define __F0_PORT_MAP_SH 4 -#define __F0_PORT_MAP(_v) ((_v) << __F0_PORT_MAP_SH) -#define __F0_VM_MODE 0x00000008 -#define __F0_INTX_STATUS 0x00000007 -enum { - __F0_INTX_STATUS_MSIX = 0x0, - __F0_INTX_STATUS_INTA = 0x1, - __F0_INTX_STATUS_INTB = 0x2, - __F0_INTX_STATUS_INTC = 0x3, - __F0_INTX_STATUS_INTD = 0x4, -}; - -#define OP_MODE 0x0001460c /* ct */ -#define __APP_ETH_CLK_LOWSPEED 0x00000004 -#define __GLOBAL_CORECLK_HALFSPEED 0x00000002 -#define __GLOBAL_FCOE_MODE 0x00000001 -#define FW_INIT_HALT_P0 0x000191ac /* ct */ -#define __FW_INIT_HALT_P 0x00000001 -#define FW_INIT_HALT_P1 0x000191bc /* ct */ -#define PMM_1T_RESET_REG_P0 0x0002381c /* ct */ -#define __PMM_1T_RESET_P 0x00000001 -#define PMM_1T_RESET_REG_P1 0x00023c1c /* ct */ - -/** - * Catapult-2 specific defines - */ -#define CT2_PCI_CPQ_BASE 0x00030000 -#define CT2_PCI_APP_BASE 0x00030100 -#define CT2_PCI_ETH_BASE 0x00030400 - -/* - * APP block registers - */ -#define CT2_HOSTFN_INT_STATUS (CT2_PCI_APP_BASE + 0x00) -#define CT2_HOSTFN_INTR_MASK (CT2_PCI_APP_BASE + 0x04) -#define CT2_HOSTFN_PERSONALITY0 (CT2_PCI_APP_BASE + 0x08) -#define __PME_STATUS_ 0x00200000 -#define __PF_VF_BAR_SIZE_MODE__MK 0x00180000 -#define __PF_VF_BAR_SIZE_MODE__SH 19 -#define __PF_VF_BAR_SIZE_MODE_(_v) ((_v) << __PF_VF_BAR_SIZE_MODE__SH) -#define __FC_LL_PORT_MAP__MK 0x00060000 -#define __FC_LL_PORT_MAP__SH 17 -#define __FC_LL_PORT_MAP_(_v) ((_v) << __FC_LL_PORT_MAP__SH) -#define __PF_VF_ACTIVE_ 0x00010000 -#define __PF_VF_CFG_RDY_ 0x00008000 -#define __PF_VF_ENABLE_ 0x00004000 -#define __PF_DRIVER_ACTIVE_ 0x00002000 -#define __PF_PME_SEND_ENABLE_ 0x00001000 -#define __PF_EXROM_OFFSET__MK 0x00000ff0 -#define __PF_EXROM_OFFSET__SH 4 -#define __PF_EXROM_OFFSET_(_v) ((_v) << __PF_EXROM_OFFSET__SH) -#define __FC_LL_MODE_ 0x00000008 -#define __PF_INTX_PIN_ 0x00000007 -#define CT2_HOSTFN_PERSONALITY1 (CT2_PCI_APP_BASE + 0x0C) -#define __PF_NUM_QUEUES1__MK 0xff000000 -#define __PF_NUM_QUEUES1__SH 24 -#define __PF_NUM_QUEUES1_(_v) ((_v) << __PF_NUM_QUEUES1__SH) -#define __PF_VF_QUE_OFFSET1__MK 0x00ff0000 -#define __PF_VF_QUE_OFFSET1__SH 16 -#define __PF_VF_QUE_OFFSET1_(_v) ((_v) << __PF_VF_QUE_OFFSET1__SH) -#define __PF_VF_NUM_QUEUES__MK 0x0000ff00 -#define __PF_VF_NUM_QUEUES__SH 8 -#define __PF_VF_NUM_QUEUES_(_v) ((_v) << __PF_VF_NUM_QUEUES__SH) -#define __PF_VF_QUE_OFFSET_ 0x000000ff -#define CT2_HOSTFN_PAGE_NUM (CT2_PCI_APP_BASE + 0x18) -#define CT2_HOSTFN_MSIX_VT_INDEX_MBOX_ERR (CT2_PCI_APP_BASE + 0x38) - -/* - * Catapult-2 CPQ block registers - */ -#define CT2_HOSTFN_LPU0_MBOX0 (CT2_PCI_CPQ_BASE + 0x00) -#define CT2_HOSTFN_LPU1_MBOX0 (CT2_PCI_CPQ_BASE + 0x20) -#define CT2_LPU0_HOSTFN_MBOX0 (CT2_PCI_CPQ_BASE + 0x40) -#define CT2_LPU1_HOSTFN_MBOX0 (CT2_PCI_CPQ_BASE + 0x60) -#define CT2_HOSTFN_LPU0_CMD_STAT (CT2_PCI_CPQ_BASE + 0x80) -#define CT2_HOSTFN_LPU1_CMD_STAT (CT2_PCI_CPQ_BASE + 0x84) -#define CT2_LPU0_HOSTFN_CMD_STAT (CT2_PCI_CPQ_BASE + 0x88) -#define CT2_LPU1_HOSTFN_CMD_STAT (CT2_PCI_CPQ_BASE + 0x8c) -#define CT2_HOSTFN_LPU0_READ_STAT (CT2_PCI_CPQ_BASE + 0x90) -#define CT2_HOSTFN_LPU1_READ_STAT (CT2_PCI_CPQ_BASE + 0x94) -#define CT2_LPU0_HOSTFN_MBOX0_MSK (CT2_PCI_CPQ_BASE + 0x98) -#define CT2_LPU1_HOSTFN_MBOX0_MSK (CT2_PCI_CPQ_BASE + 0x9C) -#define CT2_HOST_SEM0_REG 0x000148f0 -#define CT2_HOST_SEM1_REG 0x000148f4 -#define CT2_HOST_SEM2_REG 0x000148f8 -#define CT2_HOST_SEM3_REG 0x000148fc -#define CT2_HOST_SEM4_REG 0x00014900 -#define CT2_HOST_SEM5_REG 0x00014904 -#define CT2_HOST_SEM6_REG 0x00014908 -#define CT2_HOST_SEM7_REG 0x0001490c -#define CT2_HOST_SEM0_INFO_REG 0x000148b0 -#define CT2_HOST_SEM1_INFO_REG 0x000148b4 -#define CT2_HOST_SEM2_INFO_REG 0x000148b8 -#define CT2_HOST_SEM3_INFO_REG 0x000148bc -#define CT2_HOST_SEM4_INFO_REG 0x000148c0 -#define CT2_HOST_SEM5_INFO_REG 0x000148c4 -#define CT2_HOST_SEM6_INFO_REG 0x000148c8 -#define CT2_HOST_SEM7_INFO_REG 0x000148cc - -#define CT2_APP_PLL_LCLK_CTL_REG 0x00014808 -#define __APP_LPUCLK_HALFSPEED 0x40000000 -#define __APP_PLL_LCLK_LOAD 0x20000000 -#define __APP_PLL_LCLK_FBCNT_MK 0x1fe00000 -#define __APP_PLL_LCLK_FBCNT_SH 21 -#define __APP_PLL_LCLK_FBCNT(_v) ((_v) << __APP_PLL_SCLK_FBCNT_SH) -enum { - __APP_PLL_LCLK_FBCNT_425_MHZ = 6, - __APP_PLL_LCLK_FBCNT_468_MHZ = 4, -}; -#define __APP_PLL_LCLK_EXTFB 0x00000800 -#define __APP_PLL_LCLK_ENOUTS 0x00000400 -#define __APP_PLL_LCLK_RATE 0x00000010 -#define CT2_APP_PLL_SCLK_CTL_REG 0x0001480c -#define __P_SCLK_PLL_LOCK 0x80000000 -#define __APP_PLL_SCLK_REFCLK_SEL 0x40000000 -#define __APP_PLL_SCLK_CLK_DIV2 0x20000000 -#define __APP_PLL_SCLK_LOAD 0x10000000 -#define __APP_PLL_SCLK_FBCNT_MK 0x0ff00000 -#define __APP_PLL_SCLK_FBCNT_SH 20 -#define __APP_PLL_SCLK_FBCNT(_v) ((_v) << __APP_PLL_SCLK_FBCNT_SH) -enum { - __APP_PLL_SCLK_FBCNT_NORM = 6, - __APP_PLL_SCLK_FBCNT_10G_FC = 10, -}; -#define __APP_PLL_SCLK_EXTFB 0x00000800 -#define __APP_PLL_SCLK_ENOUTS 0x00000400 -#define __APP_PLL_SCLK_RATE 0x00000010 -#define CT2_PCIE_MISC_REG 0x00014804 -#define __ETH_CLK_ENABLE_PORT1 0x00000010 -#define CT2_CHIP_MISC_PRG 0x000148a4 -#define __ETH_CLK_ENABLE_PORT0 0x00004000 -#define __APP_LPU_SPEED 0x00000002 -#define CT2_MBIST_STAT_REG 0x00014818 -#define CT2_MBIST_CTL_REG 0x0001481c -#define CT2_PMM_1T_CONTROL_REG_P0 0x0002381c -#define __PMM_1T_PNDB_P 0x00000002 -#define CT2_PMM_1T_CONTROL_REG_P1 0x00023c1c -#define CT2_WGN_STATUS 0x00014990 -#define __A2T_AHB_LOAD 0x00000800 -#define __WGN_READY 0x00000400 -#define __GLBL_PF_VF_CFG_RDY 0x00000200 -#define CT2_NFC_CSR_CLR_REG 0x00027420 -#define CT2_NFC_CSR_SET_REG 0x00027424 -#define __HALT_NFC_CONTROLLER 0x00000002 -#define __NFC_CONTROLLER_HALTED 0x00001000 -#define CT2_RSC_GPR15_REG 0x0002765c -#define CT2_CSI_FW_CTL_REG 0x00027080 -#define CT2_CSI_FW_CTL_SET_REG 0x00027088 -#define __RESET_AND_START_SCLK_LCLK_PLLS 0x00010000 - -#define CT2_CSI_MAC0_CONTROL_REG 0x000270d0 -#define __CSI_MAC_RESET 0x00000010 -#define __CSI_MAC_AHB_RESET 0x00000008 -#define CT2_CSI_MAC1_CONTROL_REG 0x000270d4 -#define CT2_CSI_MAC_CONTROL_REG(__n) \ - (CT2_CSI_MAC0_CONTROL_REG + \ - (__n) * (CT2_CSI_MAC1_CONTROL_REG - CT2_CSI_MAC0_CONTROL_REG)) - -/* - * Name semaphore registers based on usage - */ -#define BFA_IOC0_HBEAT_REG HOST_SEM0_INFO_REG -#define BFA_IOC0_STATE_REG HOST_SEM1_INFO_REG -#define BFA_IOC1_HBEAT_REG HOST_SEM2_INFO_REG -#define BFA_IOC1_STATE_REG HOST_SEM3_INFO_REG -#define BFA_FW_USE_COUNT HOST_SEM4_INFO_REG -#define BFA_IOC_FAIL_SYNC HOST_SEM5_INFO_REG - -/* - * CT2 semaphore register locations changed - */ -#define CT2_BFA_IOC0_HBEAT_REG CT2_HOST_SEM0_INFO_REG -#define CT2_BFA_IOC0_STATE_REG CT2_HOST_SEM1_INFO_REG -#define CT2_BFA_IOC1_HBEAT_REG CT2_HOST_SEM2_INFO_REG -#define CT2_BFA_IOC1_STATE_REG CT2_HOST_SEM3_INFO_REG -#define CT2_BFA_FW_USE_COUNT CT2_HOST_SEM4_INFO_REG -#define CT2_BFA_IOC_FAIL_SYNC CT2_HOST_SEM5_INFO_REG - -#define CPE_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) -#define RME_Q_NUM(__fn, __q) (((__fn) << 2) + (__q)) - -/* - * And corresponding host interrupt status bit field defines - */ -#define __HFN_INT_CPE_Q0 0x00000001U -#define __HFN_INT_CPE_Q1 0x00000002U -#define __HFN_INT_CPE_Q2 0x00000004U -#define __HFN_INT_CPE_Q3 0x00000008U -#define __HFN_INT_CPE_Q4 0x00000010U -#define __HFN_INT_CPE_Q5 0x00000020U -#define __HFN_INT_CPE_Q6 0x00000040U -#define __HFN_INT_CPE_Q7 0x00000080U -#define __HFN_INT_RME_Q0 0x00000100U -#define __HFN_INT_RME_Q1 0x00000200U -#define __HFN_INT_RME_Q2 0x00000400U -#define __HFN_INT_RME_Q3 0x00000800U -#define __HFN_INT_RME_Q4 0x00001000U -#define __HFN_INT_RME_Q5 0x00002000U -#define __HFN_INT_RME_Q6 0x00004000U -#define __HFN_INT_RME_Q7 0x00008000U -#define __HFN_INT_ERR_EMC 0x00010000U -#define __HFN_INT_ERR_LPU0 0x00020000U -#define __HFN_INT_ERR_LPU1 0x00040000U -#define __HFN_INT_ERR_PSS 0x00080000U -#define __HFN_INT_MBOX_LPU0 0x00100000U -#define __HFN_INT_MBOX_LPU1 0x00200000U -#define __HFN_INT_MBOX1_LPU0 0x00400000U -#define __HFN_INT_MBOX1_LPU1 0x00800000U -#define __HFN_INT_LL_HALT 0x01000000U -#define __HFN_INT_CPE_MASK 0x000000ffU -#define __HFN_INT_RME_MASK 0x0000ff00U -#define __HFN_INT_ERR_MASK \ - (__HFN_INT_ERR_EMC | __HFN_INT_ERR_LPU0 | __HFN_INT_ERR_LPU1 | \ - __HFN_INT_ERR_PSS | __HFN_INT_LL_HALT) -#define __HFN_INT_FN0_MASK \ - (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | __HFN_INT_CPE_Q2 | \ - __HFN_INT_CPE_Q3 | __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | \ - __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | __HFN_INT_MBOX_LPU0) -#define __HFN_INT_FN1_MASK \ - (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | __HFN_INT_CPE_Q6 | \ - __HFN_INT_CPE_Q7 | __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | \ - __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | __HFN_INT_MBOX_LPU1) - -/* - * Host interrupt status defines for catapult-2 - */ -#define __HFN_INT_MBOX_LPU0_CT2 0x00010000U -#define __HFN_INT_MBOX_LPU1_CT2 0x00020000U -#define __HFN_INT_ERR_PSS_CT2 0x00040000U -#define __HFN_INT_ERR_LPU0_CT2 0x00080000U -#define __HFN_INT_ERR_LPU1_CT2 0x00100000U -#define __HFN_INT_CPQ_HALT_CT2 0x00200000U -#define __HFN_INT_ERR_WGN_CT2 0x00400000U -#define __HFN_INT_ERR_LEHRX_CT2 0x00800000U -#define __HFN_INT_ERR_LEHTX_CT2 0x01000000U -#define __HFN_INT_ERR_MASK_CT2 \ - (__HFN_INT_ERR_PSS_CT2 | __HFN_INT_ERR_LPU0_CT2 | \ - __HFN_INT_ERR_LPU1_CT2 | __HFN_INT_CPQ_HALT_CT2 | \ - __HFN_INT_ERR_WGN_CT2 | __HFN_INT_ERR_LEHRX_CT2 | \ - __HFN_INT_ERR_LEHTX_CT2) -#define __HFN_INT_FN0_MASK_CT2 \ - (__HFN_INT_CPE_Q0 | __HFN_INT_CPE_Q1 | __HFN_INT_CPE_Q2 | \ - __HFN_INT_CPE_Q3 | __HFN_INT_RME_Q0 | __HFN_INT_RME_Q1 | \ - __HFN_INT_RME_Q2 | __HFN_INT_RME_Q3 | __HFN_INT_MBOX_LPU0_CT2) -#define __HFN_INT_FN1_MASK_CT2 \ - (__HFN_INT_CPE_Q4 | __HFN_INT_CPE_Q5 | __HFN_INT_CPE_Q6 | \ - __HFN_INT_CPE_Q7 | __HFN_INT_RME_Q4 | __HFN_INT_RME_Q5 | \ - __HFN_INT_RME_Q6 | __HFN_INT_RME_Q7 | __HFN_INT_MBOX_LPU1_CT2) - -/* - * asic memory map. - */ -#define PSS_SMEM_PAGE_START 0x8000 -#define PSS_SMEM_PGNUM(_pg0, _ma) ((_pg0) + ((_ma) >> 15)) -#define PSS_SMEM_PGOFF(_ma) ((_ma) & 0x7fff) - -#endif /* __BFI_REG_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h b/ANDROID_3.4.5/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h deleted file mode 100644 index e1f1e344..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h +++ /dev/null @@ -1,990 +0,0 @@ -#ifndef __57XX_FCOE_HSI_LINUX_LE__ -#define __57XX_FCOE_HSI_LINUX_LE__ - -/* - * common data for all protocols - */ -struct b577xx_doorbell_hdr { - u8 header; -#define B577XX_DOORBELL_HDR_RX (0x1<<0) -#define B577XX_DOORBELL_HDR_RX_SHIFT 0 -#define B577XX_DOORBELL_HDR_DB_TYPE (0x1<<1) -#define B577XX_DOORBELL_HDR_DB_TYPE_SHIFT 1 -#define B577XX_DOORBELL_HDR_DPM_SIZE (0x3<<2) -#define B577XX_DOORBELL_HDR_DPM_SIZE_SHIFT 2 -#define B577XX_DOORBELL_HDR_CONN_TYPE (0xF<<4) -#define B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT 4 -}; - -/* - * doorbell message sent to the chip - */ -struct b577xx_doorbell { -#if defined(__BIG_ENDIAN) - u16 zero_fill2; - u8 zero_fill1; - struct b577xx_doorbell_hdr header; -#elif defined(__LITTLE_ENDIAN) - struct b577xx_doorbell_hdr header; - u8 zero_fill1; - u16 zero_fill2; -#endif -}; - - - -/* - * doorbell message sent to the chip - */ -struct b577xx_doorbell_set_prod { -#if defined(__BIG_ENDIAN) - u16 prod; - u8 zero_fill1; - struct b577xx_doorbell_hdr header; -#elif defined(__LITTLE_ENDIAN) - struct b577xx_doorbell_hdr header; - u8 zero_fill1; - u16 prod; -#endif -}; - - -struct regpair { - __le32 lo; - __le32 hi; -}; - - -/* - * ABTS info $$KEEP_ENDIANNESS$$ - */ -struct fcoe_abts_info { - __le16 aborted_task_id; - __le16 reserved0; - __le32 reserved1; -}; - - -/* - * Fixed size structure in order to plant it in Union structure - * $$KEEP_ENDIANNESS$$ - */ -struct fcoe_abts_rsp_union { - u8 r_ctl; - u8 rsrv[3]; - __le32 abts_rsp_payload[7]; -}; - - -/* - * 4 regs size $$KEEP_ENDIANNESS$$ - */ -struct fcoe_bd_ctx { - __le32 buf_addr_hi; - __le32 buf_addr_lo; - __le16 buf_len; - __le16 rsrv0; - __le16 flags; - __le16 rsrv1; -}; - - -/* - * FCoE cached sges context $$KEEP_ENDIANNESS$$ - */ -struct fcoe_cached_sge_ctx { - struct regpair cur_buf_addr; - __le16 cur_buf_rem; - __le16 second_buf_rem; - struct regpair second_buf_addr; -}; - - -/* - * Cleanup info $$KEEP_ENDIANNESS$$ - */ -struct fcoe_cleanup_info { - __le16 cleaned_task_id; - __le16 rolled_tx_seq_cnt; - __le32 rolled_tx_data_offset; -}; - - -/* - * Fcp RSP flags $$KEEP_ENDIANNESS$$ - */ -struct fcoe_fcp_rsp_flags { - u8 flags; -#define FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID (0x1<<0) -#define FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID_SHIFT 0 -#define FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID (0x1<<1) -#define FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID_SHIFT 1 -#define FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER (0x1<<2) -#define FCOE_FCP_RSP_FLAGS_FCP_RESID_OVER_SHIFT 2 -#define FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER (0x1<<3) -#define FCOE_FCP_RSP_FLAGS_FCP_RESID_UNDER_SHIFT 3 -#define FCOE_FCP_RSP_FLAGS_FCP_CONF_REQ (0x1<<4) -#define FCOE_FCP_RSP_FLAGS_FCP_CONF_REQ_SHIFT 4 -#define FCOE_FCP_RSP_FLAGS_FCP_BIDI_FLAGS (0x7<<5) -#define FCOE_FCP_RSP_FLAGS_FCP_BIDI_FLAGS_SHIFT 5 -}; - -/* - * Fcp RSP payload $$KEEP_ENDIANNESS$$ - */ -struct fcoe_fcp_rsp_payload { - struct regpair reserved0; - __le32 fcp_resid; - u8 scsi_status_code; - struct fcoe_fcp_rsp_flags fcp_flags; - __le16 retry_delay_timer; - __le32 fcp_rsp_len; - __le32 fcp_sns_len; -}; - -/* - * Fixed size structure in order to plant it in Union structure - * $$KEEP_ENDIANNESS$$ - */ -struct fcoe_fcp_rsp_union { - struct fcoe_fcp_rsp_payload payload; - struct regpair reserved0; -}; - -/* - * FC header $$KEEP_ENDIANNESS$$ - */ -struct fcoe_fc_hdr { - u8 s_id[3]; - u8 cs_ctl; - u8 d_id[3]; - u8 r_ctl; - __le16 seq_cnt; - u8 df_ctl; - u8 seq_id; - u8 f_ctl[3]; - u8 type; - __le32 parameters; - __le16 rx_id; - __le16 ox_id; -}; - -/* - * FC header union $$KEEP_ENDIANNESS$$ - */ -struct fcoe_mp_rsp_union { - struct fcoe_fc_hdr fc_hdr; - __le32 mp_payload_len; - __le32 rsrv; -}; - -/* - * Completion information $$KEEP_ENDIANNESS$$ - */ -union fcoe_comp_flow_info { - struct fcoe_fcp_rsp_union fcp_rsp; - struct fcoe_abts_rsp_union abts_rsp; - struct fcoe_mp_rsp_union mp_rsp; - __le32 opaque[8]; -}; - - -/* - * External ABTS info $$KEEP_ENDIANNESS$$ - */ -struct fcoe_ext_abts_info { - __le32 rsrv0[6]; - struct fcoe_abts_info ctx; -}; - - -/* - * External cleanup info $$KEEP_ENDIANNESS$$ - */ -struct fcoe_ext_cleanup_info { - __le32 rsrv0[6]; - struct fcoe_cleanup_info ctx; -}; - - -/* - * Fcoe FW Tx sequence context $$KEEP_ENDIANNESS$$ - */ -struct fcoe_fw_tx_seq_ctx { - __le32 data_offset; - __le16 seq_cnt; - __le16 rsrv0; -}; - -/* - * Fcoe external FW Tx sequence context $$KEEP_ENDIANNESS$$ - */ -struct fcoe_ext_fw_tx_seq_ctx { - __le32 rsrv0[6]; - struct fcoe_fw_tx_seq_ctx ctx; -}; - - -/* - * FCoE multiple sges context $$KEEP_ENDIANNESS$$ - */ -struct fcoe_mul_sges_ctx { - struct regpair cur_sge_addr; - __le16 cur_sge_off; - u8 cur_sge_idx; - u8 sgl_size; -}; - -/* - * FCoE external multiple sges context $$KEEP_ENDIANNESS$$ - */ -struct fcoe_ext_mul_sges_ctx { - struct fcoe_mul_sges_ctx mul_sgl; - struct regpair rsrv0; -}; - - -/* - * FCP CMD payload $$KEEP_ENDIANNESS$$ - */ -struct fcoe_fcp_cmd_payload { - __le32 opaque[8]; -}; - - - - - -/* - * Fcp xfr rdy payload $$KEEP_ENDIANNESS$$ - */ -struct fcoe_fcp_xfr_rdy_payload { - __le32 burst_len; - __le32 data_ro; -}; - - -/* - * FC frame $$KEEP_ENDIANNESS$$ - */ -struct fcoe_fc_frame { - struct fcoe_fc_hdr fc_hdr; - __le32 reserved0[2]; -}; - - - - -/* - * FCoE KCQ CQE parameters $$KEEP_ENDIANNESS$$ - */ -union fcoe_kcqe_params { - __le32 reserved0[4]; -}; - -/* - * FCoE KCQ CQE $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kcqe { - __le32 fcoe_conn_id; - __le32 completion_status; - __le32 fcoe_conn_context_id; - union fcoe_kcqe_params params; - __le16 qe_self_seq; - u8 op_code; - u8 flags; -#define FCOE_KCQE_RESERVED0 (0x7<<0) -#define FCOE_KCQE_RESERVED0_SHIFT 0 -#define FCOE_KCQE_RAMROD_COMPLETION (0x1<<3) -#define FCOE_KCQE_RAMROD_COMPLETION_SHIFT 3 -#define FCOE_KCQE_LAYER_CODE (0x7<<4) -#define FCOE_KCQE_LAYER_CODE_SHIFT 4 -#define FCOE_KCQE_LINKED_WITH_NEXT (0x1<<7) -#define FCOE_KCQE_LINKED_WITH_NEXT_SHIFT 7 -}; - - - -/* - * FCoE KWQE header $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_header { - u8 op_code; - u8 flags; -#define FCOE_KWQE_HEADER_RESERVED0 (0xF<<0) -#define FCOE_KWQE_HEADER_RESERVED0_SHIFT 0 -#define FCOE_KWQE_HEADER_LAYER_CODE (0x7<<4) -#define FCOE_KWQE_HEADER_LAYER_CODE_SHIFT 4 -#define FCOE_KWQE_HEADER_RESERVED1 (0x1<<7) -#define FCOE_KWQE_HEADER_RESERVED1_SHIFT 7 -}; - -/* - * FCoE firmware init request 1 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_init1 { - __le16 num_tasks; - struct fcoe_kwqe_header hdr; - __le32 task_list_pbl_addr_lo; - __le32 task_list_pbl_addr_hi; - __le32 dummy_buffer_addr_lo; - __le32 dummy_buffer_addr_hi; - __le16 sq_num_wqes; - __le16 rq_num_wqes; - __le16 rq_buffer_log_size; - __le16 cq_num_wqes; - __le16 mtu; - u8 num_sessions_log; - u8 flags; -#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE (0xF<<0) -#define FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT 0 -#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC (0x7<<4) -#define FCOE_KWQE_INIT1_LOG_CACHED_PBES_PER_FUNC_SHIFT 4 -#define FCOE_KWQE_INIT1_RESERVED1 (0x1<<7) -#define FCOE_KWQE_INIT1_RESERVED1_SHIFT 7 -}; - -/* - * FCoE firmware init request 2 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_init2 { - u8 hsi_major_version; - u8 hsi_minor_version; - struct fcoe_kwqe_header hdr; - __le32 hash_tbl_pbl_addr_lo; - __le32 hash_tbl_pbl_addr_hi; - __le32 t2_hash_tbl_addr_lo; - __le32 t2_hash_tbl_addr_hi; - __le32 t2_ptr_hash_tbl_addr_lo; - __le32 t2_ptr_hash_tbl_addr_hi; - __le32 free_list_count; -}; - -/* - * FCoE firmware init request 3 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_init3 { - __le16 reserved0; - struct fcoe_kwqe_header hdr; - __le32 error_bit_map_lo; - __le32 error_bit_map_hi; - u8 perf_config; - u8 reserved21[3]; - __le32 reserved2[4]; -}; - -/* - * FCoE connection offload request 1 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_conn_offload1 { - __le16 fcoe_conn_id; - struct fcoe_kwqe_header hdr; - __le32 sq_addr_lo; - __le32 sq_addr_hi; - __le32 rq_pbl_addr_lo; - __le32 rq_pbl_addr_hi; - __le32 rq_first_pbe_addr_lo; - __le32 rq_first_pbe_addr_hi; - __le16 rq_prod; - __le16 reserved0; -}; - -/* - * FCoE connection offload request 2 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_conn_offload2 { - __le16 tx_max_fc_pay_len; - struct fcoe_kwqe_header hdr; - __le32 cq_addr_lo; - __le32 cq_addr_hi; - __le32 xferq_addr_lo; - __le32 xferq_addr_hi; - __le32 conn_db_addr_lo; - __le32 conn_db_addr_hi; - __le32 reserved1; -}; - -/* - * FCoE connection offload request 3 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_conn_offload3 { - __le16 vlan_tag; -#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID (0xFFF<<0) -#define FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT 0 -#define FCOE_KWQE_CONN_OFFLOAD3_CFI (0x1<<12) -#define FCOE_KWQE_CONN_OFFLOAD3_CFI_SHIFT 12 -#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY (0x7<<13) -#define FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT 13 - struct fcoe_kwqe_header hdr; - u8 s_id[3]; - u8 tx_max_conc_seqs_c3; - u8 d_id[3]; - u8 flags; -#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS (0x1<<0) -#define FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT 0 -#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES (0x1<<1) -#define FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT 1 -#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT (0x1<<2) -#define FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT 2 -#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ (0x1<<3) -#define FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT 3 -#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID (0x1<<4) -#define FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT 4 -#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID (0x1<<5) -#define FCOE_KWQE_CONN_OFFLOAD3_B_C2_VALID_SHIFT 5 -#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0 (0x1<<6) -#define FCOE_KWQE_CONN_OFFLOAD3_B_ACK_0_SHIFT 6 -#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG (0x1<<7) -#define FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT 7 - __le32 reserved; - __le32 confq_first_pbe_addr_lo; - __le32 confq_first_pbe_addr_hi; - __le16 tx_total_conc_seqs; - __le16 rx_max_fc_pay_len; - __le16 rx_total_conc_seqs; - u8 rx_max_conc_seqs_c3; - u8 rx_open_seqs_exch_c3; -}; - -/* - * FCoE connection offload request 4 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_conn_offload4 { - u8 e_d_tov_timer_val; - u8 reserved2; - struct fcoe_kwqe_header hdr; - u8 src_mac_addr_lo[2]; - u8 src_mac_addr_mid[2]; - u8 src_mac_addr_hi[2]; - u8 dst_mac_addr_hi[2]; - u8 dst_mac_addr_lo[2]; - u8 dst_mac_addr_mid[2]; - __le32 lcq_addr_lo; - __le32 lcq_addr_hi; - __le32 confq_pbl_base_addr_lo; - __le32 confq_pbl_base_addr_hi; -}; - -/* - * FCoE connection enable request $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_conn_enable_disable { - __le16 reserved0; - struct fcoe_kwqe_header hdr; - u8 src_mac_addr_lo[2]; - u8 src_mac_addr_mid[2]; - u8 src_mac_addr_hi[2]; - u16 vlan_tag; -#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID (0xFFF<<0) -#define FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT 0 -#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI (0x1<<12) -#define FCOE_KWQE_CONN_ENABLE_DISABLE_CFI_SHIFT 12 -#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY (0x7<<13) -#define FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT 13 - u8 dst_mac_addr_lo[2]; - u8 dst_mac_addr_mid[2]; - u8 dst_mac_addr_hi[2]; - __le16 reserved1; - u8 s_id[3]; - u8 vlan_flag; - u8 d_id[3]; - u8 reserved3; - __le32 context_id; - __le32 conn_id; - __le32 reserved4; -}; - -/* - * FCoE connection destroy request $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_conn_destroy { - __le16 reserved0; - struct fcoe_kwqe_header hdr; - __le32 context_id; - __le32 conn_id; - __le32 reserved1[5]; -}; - -/* - * FCoe destroy request $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_destroy { - __le16 reserved0; - struct fcoe_kwqe_header hdr; - __le32 reserved1[7]; -}; - -/* - * FCoe statistics request $$KEEP_ENDIANNESS$$ - */ -struct fcoe_kwqe_stat { - __le16 reserved0; - struct fcoe_kwqe_header hdr; - __le32 stat_params_addr_lo; - __le32 stat_params_addr_hi; - __le32 reserved1[5]; -}; - -/* - * FCoE KWQ WQE $$KEEP_ENDIANNESS$$ - */ -union fcoe_kwqe { - struct fcoe_kwqe_init1 init1; - struct fcoe_kwqe_init2 init2; - struct fcoe_kwqe_init3 init3; - struct fcoe_kwqe_conn_offload1 conn_offload1; - struct fcoe_kwqe_conn_offload2 conn_offload2; - struct fcoe_kwqe_conn_offload3 conn_offload3; - struct fcoe_kwqe_conn_offload4 conn_offload4; - struct fcoe_kwqe_conn_enable_disable conn_enable_disable; - struct fcoe_kwqe_conn_destroy conn_destroy; - struct fcoe_kwqe_destroy destroy; - struct fcoe_kwqe_stat statistics; -}; - - - - - - - - - - - - - - - - -/* - * TX SGL context $$KEEP_ENDIANNESS$$ - */ -union fcoe_sgl_union_ctx { - struct fcoe_cached_sge_ctx cached_sge; - struct fcoe_ext_mul_sges_ctx sgl; - __le32 opaque[5]; -}; - -/* - * Data-In/ELS/BLS information $$KEEP_ENDIANNESS$$ - */ -struct fcoe_read_flow_info { - union fcoe_sgl_union_ctx sgl_ctx; - __le32 rsrv0[3]; -}; - - -/* - * Fcoe stat context $$KEEP_ENDIANNESS$$ - */ -struct fcoe_s_stat_ctx { - u8 flags; -#define FCOE_S_STAT_CTX_ACTIVE (0x1<<0) -#define FCOE_S_STAT_CTX_ACTIVE_SHIFT 0 -#define FCOE_S_STAT_CTX_ACK_ABORT_SEQ_COND (0x1<<1) -#define FCOE_S_STAT_CTX_ACK_ABORT_SEQ_COND_SHIFT 1 -#define FCOE_S_STAT_CTX_ABTS_PERFORMED (0x1<<2) -#define FCOE_S_STAT_CTX_ABTS_PERFORMED_SHIFT 2 -#define FCOE_S_STAT_CTX_SEQ_TIMEOUT (0x1<<3) -#define FCOE_S_STAT_CTX_SEQ_TIMEOUT_SHIFT 3 -#define FCOE_S_STAT_CTX_P_RJT (0x1<<4) -#define FCOE_S_STAT_CTX_P_RJT_SHIFT 4 -#define FCOE_S_STAT_CTX_ACK_EOFT (0x1<<5) -#define FCOE_S_STAT_CTX_ACK_EOFT_SHIFT 5 -#define FCOE_S_STAT_CTX_RSRV1 (0x3<<6) -#define FCOE_S_STAT_CTX_RSRV1_SHIFT 6 -}; - -/* - * Fcoe rx seq context $$KEEP_ENDIANNESS$$ - */ -struct fcoe_rx_seq_ctx { - u8 seq_id; - struct fcoe_s_stat_ctx s_stat; - __le16 seq_cnt; - __le32 low_exp_ro; - __le32 high_exp_ro; -}; - - -/* - * Fcoe rx_wr union context $$KEEP_ENDIANNESS$$ - */ -union fcoe_rx_wr_union_ctx { - struct fcoe_read_flow_info read_info; - union fcoe_comp_flow_info comp_info; - __le32 opaque[8]; -}; - - - -/* - * FCoE SQ element $$KEEP_ENDIANNESS$$ - */ -struct fcoe_sqe { - __le16 wqe; -#define FCOE_SQE_TASK_ID (0x7FFF<<0) -#define FCOE_SQE_TASK_ID_SHIFT 0 -#define FCOE_SQE_TOGGLE_BIT (0x1<<15) -#define FCOE_SQE_TOGGLE_BIT_SHIFT 15 -}; - - - -/* - * 14 regs $$KEEP_ENDIANNESS$$ - */ -struct fcoe_tce_tx_only { - union fcoe_sgl_union_ctx sgl_ctx; - __le32 rsrv0; -}; - -/* - * 32 bytes (8 regs) used for TX only purposes $$KEEP_ENDIANNESS$$ - */ -union fcoe_tx_wr_rx_rd_union_ctx { - struct fcoe_fc_frame tx_frame; - struct fcoe_fcp_cmd_payload fcp_cmd; - struct fcoe_ext_cleanup_info cleanup; - struct fcoe_ext_abts_info abts; - struct fcoe_ext_fw_tx_seq_ctx tx_seq; - __le32 opaque[8]; -}; - -/* - * tce_tx_wr_rx_rd_const $$KEEP_ENDIANNESS$$ - */ -struct fcoe_tce_tx_wr_rx_rd_const { - u8 init_flags; -#define FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE (0x7<<0) -#define FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT 0 -#define FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE (0x1<<3) -#define FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT 3 -#define FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE (0x1<<4) -#define FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT 4 -#define FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE (0x3<<5) -#define FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT 5 -#define FCOE_TCE_TX_WR_RX_RD_CONST_SUPPORT_REC_TOV (0x1<<7) -#define FCOE_TCE_TX_WR_RX_RD_CONST_SUPPORT_REC_TOV_SHIFT 7 - u8 tx_flags; -#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_VALID (0x1<<0) -#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_VALID_SHIFT 0 -#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE (0xF<<1) -#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT 1 -#define FCOE_TCE_TX_WR_RX_RD_CONST_RSRV1 (0x1<<5) -#define FCOE_TCE_TX_WR_RX_RD_CONST_RSRV1_SHIFT 5 -#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_SEQ_INIT (0x1<<6) -#define FCOE_TCE_TX_WR_RX_RD_CONST_TX_SEQ_INIT_SHIFT 6 -#define FCOE_TCE_TX_WR_RX_RD_CONST_RSRV2 (0x1<<7) -#define FCOE_TCE_TX_WR_RX_RD_CONST_RSRV2_SHIFT 7 - __le16 rsrv3; - __le32 verify_tx_seq; -}; - -/* - * tce_tx_wr_rx_rd $$KEEP_ENDIANNESS$$ - */ -struct fcoe_tce_tx_wr_rx_rd { - union fcoe_tx_wr_rx_rd_union_ctx union_ctx; - struct fcoe_tce_tx_wr_rx_rd_const const_ctx; -}; - -/* - * tce_rx_wr_tx_rd_const $$KEEP_ENDIANNESS$$ - */ -struct fcoe_tce_rx_wr_tx_rd_const { - __le32 data_2_trns; - __le32 init_flags; -#define FCOE_TCE_RX_WR_TX_RD_CONST_CID (0xFFFFFF<<0) -#define FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT 0 -#define FCOE_TCE_RX_WR_TX_RD_CONST_RSRV0 (0xFF<<24) -#define FCOE_TCE_RX_WR_TX_RD_CONST_RSRV0_SHIFT 24 -}; - -/* - * tce_rx_wr_tx_rd_var $$KEEP_ENDIANNESS$$ - */ -struct fcoe_tce_rx_wr_tx_rd_var { - __le16 rx_flags; -#define FCOE_TCE_RX_WR_TX_RD_VAR_RSRV1 (0xF<<0) -#define FCOE_TCE_RX_WR_TX_RD_VAR_RSRV1_SHIFT 0 -#define FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE (0x7<<4) -#define FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT 4 -#define FCOE_TCE_RX_WR_TX_RD_VAR_CONF_REQ (0x1<<7) -#define FCOE_TCE_RX_WR_TX_RD_VAR_CONF_REQ_SHIFT 7 -#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE (0xF<<8) -#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE_SHIFT 8 -#define FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME (0x1<<12) -#define FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT 12 -#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_SEQ_INIT (0x1<<13) -#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_SEQ_INIT_SHIFT 13 -#define FCOE_TCE_RX_WR_TX_RD_VAR_RSRV2 (0x1<<14) -#define FCOE_TCE_RX_WR_TX_RD_VAR_RSRV2_SHIFT 14 -#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_VALID (0x1<<15) -#define FCOE_TCE_RX_WR_TX_RD_VAR_RX_VALID_SHIFT 15 - __le16 rx_id; - struct fcoe_fcp_xfr_rdy_payload fcp_xfr_rdy; -}; - -/* - * tce_rx_wr_tx_rd $$KEEP_ENDIANNESS$$ - */ -struct fcoe_tce_rx_wr_tx_rd { - struct fcoe_tce_rx_wr_tx_rd_const const_ctx; - struct fcoe_tce_rx_wr_tx_rd_var var_ctx; -}; - -/* - * tce_rx_only $$KEEP_ENDIANNESS$$ - */ -struct fcoe_tce_rx_only { - struct fcoe_rx_seq_ctx rx_seq_ctx; - union fcoe_rx_wr_union_ctx union_ctx; -}; - -/* - * task_ctx_entry $$KEEP_ENDIANNESS$$ - */ -struct fcoe_task_ctx_entry { - struct fcoe_tce_tx_only txwr_only; - struct fcoe_tce_tx_wr_rx_rd txwr_rxrd; - struct fcoe_tce_rx_wr_tx_rd rxwr_txrd; - struct fcoe_tce_rx_only rxwr_only; -}; - - - - - - - - - - -/* - * FCoE XFRQ element $$KEEP_ENDIANNESS$$ - */ -struct fcoe_xfrqe { - __le16 wqe; -#define FCOE_XFRQE_TASK_ID (0x7FFF<<0) -#define FCOE_XFRQE_TASK_ID_SHIFT 0 -#define FCOE_XFRQE_TOGGLE_BIT (0x1<<15) -#define FCOE_XFRQE_TOGGLE_BIT_SHIFT 15 -}; - - -/* - * fcoe rx doorbell message sent to the chip $$KEEP_ENDIANNESS$$ - */ -struct b577xx_fcoe_rx_doorbell { - struct b577xx_doorbell_hdr hdr; - u8 params; -#define B577XX_FCOE_RX_DOORBELL_NEGATIVE_ARM (0x1F<<0) -#define B577XX_FCOE_RX_DOORBELL_NEGATIVE_ARM_SHIFT 0 -#define B577XX_FCOE_RX_DOORBELL_OPCODE (0x7<<5) -#define B577XX_FCOE_RX_DOORBELL_OPCODE_SHIFT 5 - __le16 doorbell_cq_cons; -}; - - -/* - * FCoE CONFQ element $$KEEP_ENDIANNESS$$ - */ -struct fcoe_confqe { - __le16 ox_id; - __le16 rx_id; - __le32 param; -}; - - -/* - * FCoE conection data base - */ -struct fcoe_conn_db { -#if defined(__BIG_ENDIAN) - u16 rsrv0; - u16 rq_prod; -#elif defined(__LITTLE_ENDIAN) - u16 rq_prod; - u16 rsrv0; -#endif - u32 rsrv1; - struct regpair cq_arm; -}; - - -/* - * FCoE CQ element $$KEEP_ENDIANNESS$$ - */ -struct fcoe_cqe { - __le16 wqe; -#define FCOE_CQE_CQE_INFO (0x3FFF<<0) -#define FCOE_CQE_CQE_INFO_SHIFT 0 -#define FCOE_CQE_CQE_TYPE (0x1<<14) -#define FCOE_CQE_CQE_TYPE_SHIFT 14 -#define FCOE_CQE_TOGGLE_BIT (0x1<<15) -#define FCOE_CQE_TOGGLE_BIT_SHIFT 15 -}; - - -/* - * FCoE error/warning reporting entry $$KEEP_ENDIANNESS$$ - */ -struct fcoe_partial_err_report_entry { - __le32 err_warn_bitmap_lo; - __le32 err_warn_bitmap_hi; - __le32 tx_buf_off; - __le32 rx_buf_off; -}; - -/* - * FCoE error/warning reporting entry $$KEEP_ENDIANNESS$$ - */ -struct fcoe_err_report_entry { - struct fcoe_partial_err_report_entry data; - struct fcoe_fc_hdr fc_hdr; -}; - - -/* - * FCoE hash table entry (32 bytes) $$KEEP_ENDIANNESS$$ - */ -struct fcoe_hash_table_entry { - u8 s_id_0; - u8 s_id_1; - u8 s_id_2; - u8 d_id_0; - u8 d_id_1; - u8 d_id_2; - __le16 dst_mac_addr_hi; - __le16 dst_mac_addr_mid; - __le16 dst_mac_addr_lo; - __le16 src_mac_addr_hi; - __le16 vlan_id; - __le16 src_mac_addr_lo; - __le16 src_mac_addr_mid; - u8 vlan_flag; - u8 reserved0; - __le16 reserved1; - __le32 reserved2; - __le32 field_id; -#define FCOE_HASH_TABLE_ENTRY_CID (0xFFFFFF<<0) -#define FCOE_HASH_TABLE_ENTRY_CID_SHIFT 0 -#define FCOE_HASH_TABLE_ENTRY_RESERVED3 (0x7F<<24) -#define FCOE_HASH_TABLE_ENTRY_RESERVED3_SHIFT 24 -#define FCOE_HASH_TABLE_ENTRY_VALID (0x1<<31) -#define FCOE_HASH_TABLE_ENTRY_VALID_SHIFT 31 -}; - - -/* - * FCoE LCQ element $$KEEP_ENDIANNESS$$ - */ -struct fcoe_lcqe { - __le32 wqe; -#define FCOE_LCQE_TASK_ID (0xFFFF<<0) -#define FCOE_LCQE_TASK_ID_SHIFT 0 -#define FCOE_LCQE_LCQE_TYPE (0xFF<<16) -#define FCOE_LCQE_LCQE_TYPE_SHIFT 16 -#define FCOE_LCQE_RESERVED (0xFF<<24) -#define FCOE_LCQE_RESERVED_SHIFT 24 -}; - - - -/* - * FCoE pending work request CQE $$KEEP_ENDIANNESS$$ - */ -struct fcoe_pend_wq_cqe { - __le16 wqe; -#define FCOE_PEND_WQ_CQE_TASK_ID (0x3FFF<<0) -#define FCOE_PEND_WQ_CQE_TASK_ID_SHIFT 0 -#define FCOE_PEND_WQ_CQE_CQE_TYPE (0x1<<14) -#define FCOE_PEND_WQ_CQE_CQE_TYPE_SHIFT 14 -#define FCOE_PEND_WQ_CQE_TOGGLE_BIT (0x1<<15) -#define FCOE_PEND_WQ_CQE_TOGGLE_BIT_SHIFT 15 -}; - - -/* - * FCoE RX statistics parameters section#0 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_rx_stat_params_section0 { - __le32 fcoe_rx_pkt_cnt; - __le32 fcoe_rx_byte_cnt; -}; - - -/* - * FCoE RX statistics parameters section#1 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_rx_stat_params_section1 { - __le32 fcoe_ver_cnt; - __le32 fcoe_rx_drop_pkt_cnt; -}; - - -/* - * FCoE RX statistics parameters section#2 $$KEEP_ENDIANNESS$$ - */ -struct fcoe_rx_stat_params_section2 { - __le32 fc_crc_cnt; - __le32 eofa_del_cnt; - __le32 miss_frame_cnt; - __le32 seq_timeout_cnt; - __le32 drop_seq_cnt; - __le32 fcoe_rx_drop_pkt_cnt; - __le32 fcp_rx_pkt_cnt; - __le32 reserved0; -}; - - -/* - * FCoE TX statistics parameters $$KEEP_ENDIANNESS$$ - */ -struct fcoe_tx_stat_params { - __le32 fcoe_tx_pkt_cnt; - __le32 fcoe_tx_byte_cnt; - __le32 fcp_tx_pkt_cnt; - __le32 reserved0; -}; - -/* - * FCoE statistics parameters $$KEEP_ENDIANNESS$$ - */ -struct fcoe_statistics_params { - struct fcoe_tx_stat_params tx_stat; - struct fcoe_rx_stat_params_section0 rx_stat0; - struct fcoe_rx_stat_params_section1 rx_stat1; - struct fcoe_rx_stat_params_section2 rx_stat2; -}; - - -/* - * FCoE t2 hash table entry (64 bytes) $$KEEP_ENDIANNESS$$ - */ -struct fcoe_t2_hash_table_entry { - struct fcoe_hash_table_entry data; - struct regpair next; - struct regpair reserved0[3]; -}; - - - -/* - * FCoE unsolicited CQE $$KEEP_ENDIANNESS$$ - */ -struct fcoe_unsolicited_cqe { - __le16 wqe; -#define FCOE_UNSOLICITED_CQE_SUBTYPE (0x3<<0) -#define FCOE_UNSOLICITED_CQE_SUBTYPE_SHIFT 0 -#define FCOE_UNSOLICITED_CQE_PKT_LEN (0xFFF<<2) -#define FCOE_UNSOLICITED_CQE_PKT_LEN_SHIFT 2 -#define FCOE_UNSOLICITED_CQE_CQE_TYPE (0x1<<14) -#define FCOE_UNSOLICITED_CQE_CQE_TYPE_SHIFT 14 -#define FCOE_UNSOLICITED_CQE_TOGGLE_BIT (0x1<<15) -#define FCOE_UNSOLICITED_CQE_TOGGLE_BIT_SHIFT 15 -}; - -#endif /* __57XX_FCOE_HSI_LINUX_LE__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/Kconfig b/ANDROID_3.4.5/drivers/scsi/bnx2fc/Kconfig deleted file mode 100644 index cfcad8bd..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config SCSI_BNX2X_FCOE - tristate "Broadcom NetXtreme II FCoE support" - depends on PCI - select NETDEVICES - select ETHERNET - select NET_VENDOR_BROADCOM - select LIBFC - select LIBFCOE - select CNIC - ---help--- - This driver supports FCoE offload for the Broadcom NetXtreme II - devices. diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/Makefile b/ANDROID_3.4.5/drivers/scsi/bnx2fc/Makefile deleted file mode 100644 index a92695a2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_SCSI_BNX2X_FCOE) += bnx2fc.o - -bnx2fc-y := bnx2fc_els.o bnx2fc_fcoe.o bnx2fc_hwi.o bnx2fc_io.o bnx2fc_tgt.o diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc.h b/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc.h deleted file mode 100644 index a4953ef9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc.h +++ /dev/null @@ -1,554 +0,0 @@ -#ifndef _BNX2FC_H_ -#define _BNX2FC_H_ -/* bnx2fc.h: Broadcom NetXtreme II Linux FCoE offload driver. - * - * Copyright (c) 2008 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "57xx_hsi_bnx2fc.h" -#include "bnx2fc_debug.h" -#include "../../net/ethernet/broadcom/cnic_if.h" -#include "bnx2fc_constants.h" - -#define BNX2FC_NAME "bnx2fc" -#define BNX2FC_VERSION "1.0.10" - -#define PFX "bnx2fc: " - -#define BNX2X_DOORBELL_PCI_BAR 2 - -#define BNX2FC_MAX_BD_LEN 0xffff -#define BNX2FC_BD_SPLIT_SZ 0x8000 -#define BNX2FC_MAX_BDS_PER_CMD 256 - -#define BNX2FC_SQ_WQES_MAX 256 - -#define BNX2FC_SCSI_MAX_SQES ((3 * BNX2FC_SQ_WQES_MAX) / 8) -#define BNX2FC_TM_MAX_SQES ((BNX2FC_SQ_WQES_MAX) / 2) -#define BNX2FC_ELS_MAX_SQES (BNX2FC_TM_MAX_SQES - 1) - -#define BNX2FC_RQ_WQES_MAX 16 -#define BNX2FC_CQ_WQES_MAX (BNX2FC_SQ_WQES_MAX + BNX2FC_RQ_WQES_MAX) - -#define BNX2FC_NUM_MAX_SESS 1024 -#define BNX2FC_NUM_MAX_SESS_LOG (ilog2(BNX2FC_NUM_MAX_SESS)) - -#define BNX2FC_MAX_OUTSTANDING_CMNDS 2048 -#define BNX2FC_CAN_QUEUE BNX2FC_MAX_OUTSTANDING_CMNDS -#define BNX2FC_ELSTM_XIDS BNX2FC_CAN_QUEUE -#define BNX2FC_MIN_PAYLOAD 256 -#define BNX2FC_MAX_PAYLOAD 2048 -#define BNX2FC_MFS \ - (BNX2FC_MAX_PAYLOAD + sizeof(struct fc_frame_header)) -#define BNX2FC_MINI_JUMBO_MTU 2500 - - -#define BNX2FC_RQ_BUF_SZ 256 -#define BNX2FC_RQ_BUF_LOG_SZ (ilog2(BNX2FC_RQ_BUF_SZ)) - -#define BNX2FC_SQ_WQE_SIZE (sizeof(struct fcoe_sqe)) -#define BNX2FC_CQ_WQE_SIZE (sizeof(struct fcoe_cqe)) -#define BNX2FC_RQ_WQE_SIZE (BNX2FC_RQ_BUF_SZ) -#define BNX2FC_XFERQ_WQE_SIZE (sizeof(struct fcoe_xfrqe)) -#define BNX2FC_CONFQ_WQE_SIZE (sizeof(struct fcoe_confqe)) -#define BNX2FC_5771X_DB_PAGE_SIZE 128 - -#define BNX2FC_MAX_TASKS \ - (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS) -#define BNX2FC_TASK_SIZE 128 -#define BNX2FC_TASKS_PER_PAGE (PAGE_SIZE/BNX2FC_TASK_SIZE) -#define BNX2FC_TASK_CTX_ARR_SZ (BNX2FC_MAX_TASKS/BNX2FC_TASKS_PER_PAGE) - -#define BNX2FC_MAX_ROWS_IN_HASH_TBL 8 -#define BNX2FC_HASH_TBL_CHUNK_SIZE (16 * 1024) - -#define BNX2FC_MAX_SEQS 255 -#define BNX2FC_MAX_RETRY_CNT 3 -#define BNX2FC_MAX_RPORT_RETRY_CNT 255 - -#define BNX2FC_READ (1 << 1) -#define BNX2FC_WRITE (1 << 0) - -#define BNX2FC_MIN_XID 0 -#define BNX2FC_MAX_XID \ - (BNX2FC_MAX_OUTSTANDING_CMNDS + BNX2FC_ELSTM_XIDS - 1) -#define FCOE_MAX_NUM_XIDS 0x2000 -#define FCOE_MIN_XID (BNX2FC_MAX_XID + 1) -#define FCOE_MAX_XID (FCOE_MIN_XID + FCOE_MAX_NUM_XIDS - 1) -#define FCOE_XIDS_PER_CPU (FCOE_MIN_XID + (512 * nr_cpu_ids) - 1) -#define BNX2FC_MAX_LUN 0xFFFF -#define BNX2FC_MAX_FCP_TGT 256 -#define BNX2FC_MAX_CMD_LEN 16 - -#define BNX2FC_TM_TIMEOUT 60 /* secs */ -#define BNX2FC_IO_TIMEOUT 20000UL /* msecs */ - -#define BNX2FC_WAIT_CNT 1200 -#define BNX2FC_FW_TIMEOUT (3 * HZ) -#define PORT_MAX 2 - -#define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status) - -/* FC FCP Status */ -#define FC_GOOD 0 - -#define BNX2FC_RNID_HBA 0x7 - -#define SRR_RETRY_COUNT 5 -#define REC_RETRY_COUNT 1 -#define BNX2FC_NUM_ERR_BITS 63 - -#define BNX2FC_RELOGIN_WAIT_TIME 200 -#define BNX2FC_RELOGIN_WAIT_CNT 10 - -/* bnx2fc driver uses only one instance of fcoe_percpu_s */ -extern struct fcoe_percpu_s bnx2fc_global; - -extern struct workqueue_struct *bnx2fc_wq; - -struct bnx2fc_percpu_s { - struct task_struct *iothread; - struct list_head work_list; - spinlock_t fp_work_lock; -}; - -struct bnx2fc_hba { - struct list_head list; - struct cnic_dev *cnic; - struct pci_dev *pcidev; - struct net_device *phys_dev; - unsigned long reg_with_cnic; - #define BNX2FC_CNIC_REGISTERED 1 - struct bnx2fc_cmd_mgr *cmd_mgr; - spinlock_t hba_lock; - struct mutex hba_mutex; - unsigned long adapter_state; - #define ADAPTER_STATE_UP 0 - #define ADAPTER_STATE_GOING_DOWN 1 - #define ADAPTER_STATE_LINK_DOWN 2 - #define ADAPTER_STATE_READY 3 - unsigned long flags; - #define BNX2FC_FLAG_FW_INIT_DONE 0 - #define BNX2FC_FLAG_DESTROY_CMPL 1 - u32 next_conn_id; - struct fcoe_task_ctx_entry **task_ctx; - dma_addr_t *task_ctx_dma; - struct regpair *task_ctx_bd_tbl; - dma_addr_t task_ctx_bd_dma; - - int hash_tbl_segment_count; - void **hash_tbl_segments; - void *hash_tbl_pbl; - dma_addr_t hash_tbl_pbl_dma; - struct fcoe_t2_hash_table_entry *t2_hash_tbl; - dma_addr_t t2_hash_tbl_dma; - char *t2_hash_tbl_ptr; - dma_addr_t t2_hash_tbl_ptr_dma; - - char *dummy_buffer; - dma_addr_t dummy_buf_dma; - - /* Active list of offloaded sessions */ - struct bnx2fc_rport **tgt_ofld_list; - - /* statistics */ - struct fcoe_statistics_params *stats_buffer; - dma_addr_t stats_buf_dma; - struct completion stat_req_done; - - /*destroy handling */ - struct timer_list destroy_timer; - wait_queue_head_t destroy_wait; - - /* linkdown handling */ - wait_queue_head_t shutdown_wait; - int wait_for_link_down; - int num_ofld_sess; - struct list_head vports; -}; - -struct bnx2fc_interface { - struct list_head list; - unsigned long if_flags; - #define BNX2FC_CTLR_INIT_DONE 0 - struct bnx2fc_hba *hba; - struct net_device *netdev; - struct packet_type fcoe_packet_type; - struct packet_type fip_packet_type; - struct workqueue_struct *timer_work_queue; - struct kref kref; - struct fcoe_ctlr ctlr; - u8 vlan_enabled; - int vlan_id; - bool enabled; -}; - -#define bnx2fc_from_ctlr(fip) container_of(fip, struct bnx2fc_interface, ctlr) - -struct bnx2fc_lport { - struct list_head list; - struct fc_lport *lport; -}; - -struct bnx2fc_cmd_mgr { - struct bnx2fc_hba *hba; - u16 next_idx; - struct list_head *free_list; - spinlock_t *free_list_lock; - struct io_bdt **io_bdt_pool; - struct bnx2fc_cmd **cmds; -}; - -struct bnx2fc_rport { - struct fcoe_port *port; - struct fc_rport *rport; - struct fc_rport_priv *rdata; - void __iomem *ctx_base; -#define DPM_TRIGER_TYPE 0x40 - u32 io_timeout; - u32 fcoe_conn_id; - u32 context_id; - u32 sid; - int dev_type; - - unsigned long flags; -#define BNX2FC_FLAG_SESSION_READY 0x1 -#define BNX2FC_FLAG_OFFLOADED 0x2 -#define BNX2FC_FLAG_DISABLED 0x3 -#define BNX2FC_FLAG_DESTROYED 0x4 -#define BNX2FC_FLAG_OFLD_REQ_CMPL 0x5 -#define BNX2FC_FLAG_CTX_ALLOC_FAILURE 0x6 -#define BNX2FC_FLAG_UPLD_REQ_COMPL 0x7 -#define BNX2FC_FLAG_EXPL_LOGO 0x8 - - u8 src_addr[ETH_ALEN]; - u32 max_sqes; - u32 max_rqes; - u32 max_cqes; - atomic_t free_sqes; - - struct b577xx_doorbell_set_prod sq_db; - struct b577xx_fcoe_rx_doorbell rx_db; - - struct fcoe_sqe *sq; - dma_addr_t sq_dma; - u16 sq_prod_idx; - u8 sq_curr_toggle_bit; - u32 sq_mem_size; - - struct fcoe_cqe *cq; - dma_addr_t cq_dma; - u16 cq_cons_idx; - u8 cq_curr_toggle_bit; - u32 cq_mem_size; - - void *rq; - dma_addr_t rq_dma; - u32 rq_prod_idx; - u32 rq_cons_idx; - u32 rq_mem_size; - - void *rq_pbl; - dma_addr_t rq_pbl_dma; - u32 rq_pbl_size; - - struct fcoe_xfrqe *xferq; - dma_addr_t xferq_dma; - u32 xferq_mem_size; - - struct fcoe_confqe *confq; - dma_addr_t confq_dma; - u32 confq_mem_size; - - void *confq_pbl; - dma_addr_t confq_pbl_dma; - u32 confq_pbl_size; - - struct fcoe_conn_db *conn_db; - dma_addr_t conn_db_dma; - u32 conn_db_mem_size; - - struct fcoe_sqe *lcq; - dma_addr_t lcq_dma; - u32 lcq_mem_size; - - void *ofld_req[4]; - dma_addr_t ofld_req_dma[4]; - void *enbl_req; - dma_addr_t enbl_req_dma; - - spinlock_t tgt_lock; - spinlock_t cq_lock; - atomic_t num_active_ios; - u32 flush_in_prog; - unsigned long timestamp; - struct list_head free_task_list; - struct bnx2fc_cmd *pending_queue[BNX2FC_SQ_WQES_MAX+1]; - struct list_head active_cmd_queue; - struct list_head els_queue; - struct list_head io_retire_queue; - struct list_head active_tm_queue; - - struct timer_list ofld_timer; - wait_queue_head_t ofld_wait; - - struct timer_list upld_timer; - wait_queue_head_t upld_wait; -}; - -struct bnx2fc_mp_req { - u8 tm_flags; - - u32 req_len; - void *req_buf; - dma_addr_t req_buf_dma; - struct fcoe_bd_ctx *mp_req_bd; - dma_addr_t mp_req_bd_dma; - struct fc_frame_header req_fc_hdr; - - u32 resp_len; - void *resp_buf; - dma_addr_t resp_buf_dma; - struct fcoe_bd_ctx *mp_resp_bd; - dma_addr_t mp_resp_bd_dma; - struct fc_frame_header resp_fc_hdr; -}; - -struct bnx2fc_els_cb_arg { - struct bnx2fc_cmd *aborted_io_req; - struct bnx2fc_cmd *io_req; - u16 l2_oxid; - u32 offset; - enum fc_rctl r_ctl; -}; - -/* bnx2fc command structure */ -struct bnx2fc_cmd { - struct list_head link; - u8 on_active_queue; - u8 on_tmf_queue; - u8 cmd_type; -#define BNX2FC_SCSI_CMD 1 -#define BNX2FC_TASK_MGMT_CMD 2 -#define BNX2FC_ABTS 3 -#define BNX2FC_ELS 4 -#define BNX2FC_CLEANUP 5 -#define BNX2FC_SEQ_CLEANUP 6 - u8 io_req_flags; - struct kref refcount; - struct fcoe_port *port; - struct bnx2fc_rport *tgt; - struct scsi_cmnd *sc_cmd; - struct bnx2fc_cmd_mgr *cmd_mgr; - struct bnx2fc_mp_req mp_req; - void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg); - struct bnx2fc_els_cb_arg *cb_arg; - struct delayed_work timeout_work; /* timer for ULP timeouts */ - struct completion tm_done; - int wait_for_comp; - u16 xid; - struct fcoe_err_report_entry err_entry; - struct fcoe_task_ctx_entry *task; - struct io_bdt *bd_tbl; - struct fcp_rsp *rsp; - size_t data_xfer_len; - unsigned long req_flags; -#define BNX2FC_FLAG_ISSUE_RRQ 0x1 -#define BNX2FC_FLAG_ISSUE_ABTS 0x2 -#define BNX2FC_FLAG_ABTS_DONE 0x3 -#define BNX2FC_FLAG_TM_COMPL 0x4 -#define BNX2FC_FLAG_TM_TIMEOUT 0x5 -#define BNX2FC_FLAG_IO_CLEANUP 0x6 -#define BNX2FC_FLAG_RETIRE_OXID 0x7 -#define BNX2FC_FLAG_EH_ABORT 0x8 -#define BNX2FC_FLAG_IO_COMPL 0x9 -#define BNX2FC_FLAG_ELS_DONE 0xa -#define BNX2FC_FLAG_ELS_TIMEOUT 0xb -#define BNX2FC_FLAG_CMD_LOST 0xc -#define BNX2FC_FLAG_SRR_SENT 0xd - u8 rec_retry; - u8 srr_retry; - u32 srr_offset; - u8 srr_rctl; - u32 fcp_resid; - u32 fcp_rsp_len; - u32 fcp_sns_len; - u8 cdb_status; /* SCSI IO status */ - u8 fcp_status; /* FCP IO status */ - u8 fcp_rsp_code; - u8 scsi_comp_flags; -}; - -struct io_bdt { - struct bnx2fc_cmd *io_req; - struct fcoe_bd_ctx *bd_tbl; - dma_addr_t bd_tbl_dma; - u16 bd_valid; -}; - -struct bnx2fc_work { - struct list_head list; - struct bnx2fc_rport *tgt; - u16 wqe; -}; -struct bnx2fc_unsol_els { - struct fc_lport *lport; - struct fc_frame *fp; - struct bnx2fc_hba *hba; - struct work_struct unsol_els_work; -}; - - - -struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt); -struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type); -void bnx2fc_cmd_release(struct kref *ref); -int bnx2fc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc_cmd); -int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba); -int bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba); -int bnx2fc_send_session_ofld_req(struct fcoe_port *port, - struct bnx2fc_rport *tgt); -int bnx2fc_send_session_disable_req(struct fcoe_port *port, - struct bnx2fc_rport *tgt); -int bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba, - struct bnx2fc_rport *tgt); -int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt); -void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[], - u32 num_cqe); -int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba); -void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba); -int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba); -void bnx2fc_free_fw_resc(struct bnx2fc_hba *hba); -struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, - u16 min_xid, u16 max_xid); -void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr); -void bnx2fc_get_link_state(struct bnx2fc_hba *hba); -char *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items); -void bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items); -int bnx2fc_get_paged_crc_eof(struct sk_buff *skb, int tlen); -int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req); -int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp); -int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp); -int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp); -int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req); -int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req); -void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req, - unsigned int timer_msec); -int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req); -void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u16 orig_xid); -void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnup_req, - struct fcoe_task_ctx_entry *task, - struct bnx2fc_cmd *orig_io_req, - u32 offset); -void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task); -void bnx2fc_init_task(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task); -void bnx2fc_add_2_sq(struct bnx2fc_rport *tgt, u16 xid); -void bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt); -int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd); -int bnx2fc_eh_host_reset(struct scsi_cmnd *sc_cmd); -int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd); -int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd); -void bnx2fc_rport_event_handler(struct fc_lport *lport, - struct fc_rport_priv *rport, - enum fc_rport_event event); -void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u8 num_rq); -void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u8 num_rq); -void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u8 num_rq); -void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u8 num_rq); -void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req, - struct fcoe_task_ctx_entry *task, - u8 num_rq); -void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req, - struct fcp_cmnd *fcp_cmnd); - - - -void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt); -struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did, - struct fc_frame *fp, unsigned int op, - void (*resp)(struct fc_seq *, - struct fc_frame *, - void *), - void *arg, u32 timeout); -void bnx2fc_arm_cq(struct bnx2fc_rport *tgt); -int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt); -void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe); -struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port, - u32 port_id); -void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, - unsigned char *buf, - u32 frame_len, u16 l2_oxid); -int bnx2fc_send_stat_req(struct bnx2fc_hba *hba); -int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, struct bnx2fc_cmd *io_req); -int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req); -int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl); -void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnup_req, - struct fcoe_task_ctx_entry *task, - u8 rx_state); -int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset, - enum fc_rctl r_ctl); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_constants.h b/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_constants.h deleted file mode 100644 index dad9924a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_constants.h +++ /dev/null @@ -1,274 +0,0 @@ -#ifndef __BNX2FC_CONSTANTS_H_ -#define __BNX2FC_CONSTANTS_H_ - -/** - * This file defines HSI constants for the FCoE flows - */ - -/* Current FCoE HSI version number composed of two fields (16 bit) */ -/* Implies on a change broken previous HSI */ -#define FCOE_HSI_MAJOR_VERSION (2) -/* Implies on a change which does not broken previous HSI */ -#define FCOE_HSI_MINOR_VERSION (1) - -/* KWQ/KCQ FCoE layer code */ -#define FCOE_KWQE_LAYER_CODE (7) - -/* KWQ (kernel work queue) request op codes */ -#define FCOE_KWQE_OPCODE_INIT1 (0) -#define FCOE_KWQE_OPCODE_INIT2 (1) -#define FCOE_KWQE_OPCODE_INIT3 (2) -#define FCOE_KWQE_OPCODE_OFFLOAD_CONN1 (3) -#define FCOE_KWQE_OPCODE_OFFLOAD_CONN2 (4) -#define FCOE_KWQE_OPCODE_OFFLOAD_CONN3 (5) -#define FCOE_KWQE_OPCODE_OFFLOAD_CONN4 (6) -#define FCOE_KWQE_OPCODE_ENABLE_CONN (7) -#define FCOE_KWQE_OPCODE_DISABLE_CONN (8) -#define FCOE_KWQE_OPCODE_DESTROY_CONN (9) -#define FCOE_KWQE_OPCODE_DESTROY (10) -#define FCOE_KWQE_OPCODE_STAT (11) - -/* KCQ (kernel completion queue) response op codes */ -#define FCOE_KCQE_OPCODE_INIT_FUNC (0x10) -#define FCOE_KCQE_OPCODE_DESTROY_FUNC (0x11) -#define FCOE_KCQE_OPCODE_STAT_FUNC (0x12) -#define FCOE_KCQE_OPCODE_OFFLOAD_CONN (0x15) -#define FCOE_KCQE_OPCODE_ENABLE_CONN (0x16) -#define FCOE_KCQE_OPCODE_DISABLE_CONN (0x17) -#define FCOE_KCQE_OPCODE_DESTROY_CONN (0x18) -#define FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20) -#define FCOE_KCQE_OPCODE_FCOE_ERROR (0x21) - -/* KCQ (kernel completion queue) completion status */ -#define FCOE_KCQE_COMPLETION_STATUS_SUCCESS (0x0) -#define FCOE_KCQE_COMPLETION_STATUS_ERROR (0x1) -#define FCOE_KCQE_COMPLETION_STATUS_INVALID_OPCODE (0x2) -#define FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE (0x3) -#define FCOE_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE (0x4) -#define FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR (0x5) -#define FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION (0x6) -#define FCOE_KCQE_COMPLETION_STATUS_PARITY_ERROR (0x81) - -/* CQE type */ -#define FCOE_PENDING_CQE_TYPE 0 -#define FCOE_UNSOLIC_CQE_TYPE 1 - -/* Unsolicited CQE type */ -#define FCOE_UNSOLICITED_FRAME_CQE_TYPE 0 -#define FCOE_ERROR_DETECTION_CQE_TYPE 1 -#define FCOE_WARNING_DETECTION_CQE_TYPE 2 - -/* E_D_TOV timer resolution in ms */ -#define FCOE_E_D_TOV_TIMER_RESOLUTION_MS (20) - -/* E_D_TOV timer resolution for SDM (4 micro) */ -#define FCOE_E_D_TOV_SDM_TIMER_RESOLUTION \ - (FCOE_E_D_TOV_TIMER_RESOLUTION_MS * 1000 / 4) - -/* REC timer resolution in ms */ -#define FCOE_REC_TIMER_RESOLUTION_MS (20) - -/* REC timer resolution for SDM (4 micro) */ -#define FCOE_REC_SDM_TIMER_RESOLUTION (FCOE_REC_TIMER_RESOLUTION_MS * 1000 / 4) - -/* E_D_TOV timer default wraparound value (2 sec) in 20 ms resolution */ -#define FCOE_E_D_TOV_DEFAULT_WRAPAROUND_VAL \ - (2000 / FCOE_E_D_TOV_TIMER_RESOLUTION_MS) - -/* REC_TOV timer default wraparound value (3 sec) in 20 ms resolution */ -#define FCOE_REC_TOV_DEFAULT_WRAPAROUND_VAL \ - (3000 / FCOE_REC_TIMER_RESOLUTION_MS) - -#define FCOE_NUM_OF_TIMER_TASKS (8 * 1024) - -#define FCOE_NUM_OF_CACHED_TASKS_TIMER (8) - -/* Task context constants */ -/******** Remove FCP_CMD write tce sleep ***********************/ -/* In case timer services are required then shall be updated by Xstorm after - * start processing the task. In case no timer facilities are required then the - * driver would initialize the state to this value - * -#define FCOE_TASK_TX_STATE_NORMAL 0 - * After driver has initialize the task in case timer services required * -#define FCOE_TASK_TX_STATE_INIT 1 -******** Remove FCP_CMD write tce sleep ***********************/ -/* After driver has initialize the task in case timer services required */ -#define FCOE_TASK_TX_STATE_INIT 0 -/* In case timer services are required then shall be updated by Xstorm after - * start processing the task. In case no timer facilities are required then the - * driver would initialize the state to this value - */ -#define FCOE_TASK_TX_STATE_NORMAL 1 -/* Task is under abort procedure. Updated in order to stop processing of - * pending WQEs on this task - */ -#define FCOE_TASK_TX_STATE_ABORT 2 -/* For E_D_T_TOV timer expiration in Xstorm (Class 2 only) */ -#define FCOE_TASK_TX_STATE_ERROR 3 -/* For REC_TOV timer expiration indication received from Xstorm */ -#define FCOE_TASK_TX_STATE_WARNING 4 -/* For completed unsolicited task */ -#define FCOE_TASK_TX_STATE_UNSOLICITED_COMPLETED 5 -/* For exchange cleanup request task */ -#define FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP 6 -/* For sequence cleanup request task */ -#define FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP 7 -/* For completion the ABTS task. */ -#define FCOE_TASK_TX_STATE_ABTS_TX 8 - -#define FCOE_TASK_RX_STATE_NORMAL 0 -#define FCOE_TASK_RX_STATE_COMPLETED 1 -/* Obsolete: Intermediate completion (middle path with local completion) */ -#define FCOE_TASK_RX_STATE_INTER_COMP 2 -/* For REC_TOV timer expiration indication received from Xstorm */ -#define FCOE_TASK_RX_STATE_WARNING 3 -/* For E_D_T_TOV timer expiration in Ustorm */ -#define FCOE_TASK_RX_STATE_ERROR 4 -/* FW only: First visit at rx-path, part of the abts round trip */ -#define FCOE_TASK_RX_STATE_ABTS_IN_PROCESS 5 -/* FW only: Second visit at rx-path, after ABTS frame transmitted */ -#define FCOE_TASK_RX_STATE_ABTS_TRANSMITTED 6 -/* Special completion indication in case of task was aborted. */ -#define FCOE_TASK_RX_STATE_ABTS_COMPLETED 7 -/* FW only: First visit at rx-path, part of the cleanup round trip */ -#define FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_IN_PROCESS 8 -/* FW only: Special completion indication in case of task was cleaned. */ -#define FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED 9 -/* Not in used: Special completion indication (in task requested the exchange - * cleanup) in case cleaned task is in non-valid. - */ -#define FCOE_TASK_RX_STATE_ABORT_CLEANUP_COMPLETED 10 -/* Special completion indication (in task requested the sequence cleanup) in - * case cleaned task was already returned to normal. - */ -#define FCOE_TASK_RX_STATE_IGNORED_SEQUENCE_CLEANUP 11 - - -#define FCOE_TASK_TYPE_WRITE 0 -#define FCOE_TASK_TYPE_READ 1 -#define FCOE_TASK_TYPE_MIDPATH 2 -#define FCOE_TASK_TYPE_UNSOLICITED 3 -#define FCOE_TASK_TYPE_ABTS 4 -#define FCOE_TASK_TYPE_EXCHANGE_CLEANUP 5 -#define FCOE_TASK_TYPE_SEQUENCE_CLEANUP 6 - -#define FCOE_TASK_DEV_TYPE_DISK 0 -#define FCOE_TASK_DEV_TYPE_TAPE 1 - -#define FCOE_TASK_CLASS_TYPE_3 0 -#define FCOE_TASK_CLASS_TYPE_2 1 - -/* FCoE/FC packet fields */ -#define FCOE_ETH_TYPE 0x8906 - -/* FCoE maximum elements in hash table */ -#define FCOE_MAX_ELEMENTS_IN_HASH_TABLE_ROW 8 - -/* FCoE half of the elements in hash table */ -#define FCOE_HALF_ELEMENTS_IN_HASH_TABLE_ROW \ - (FCOE_MAX_ELEMENTS_IN_HASH_TABLE_ROW / 2) - -/* FcoE number of cached T2 entries */ -#define T_FCOE_NUMBER_OF_CACHED_T2_ENTRIES (4) - -/* FCoE maximum elements in hash table */ -#define FCOE_HASH_TBL_CHUNK_SIZE 16384 - -/* Everest FCoE connection type */ -#define B577XX_FCOE_CONNECTION_TYPE 4 - -/* FCoE number of rows (in log). This number derives - * from the maximum connections supported which is 2048. - * TBA: Need a different constant for E2 - */ -#define FCOE_MAX_NUM_SESSIONS_LOG 11 - -#define FC_ABTS_REPLY_MAX_PAYLOAD_LEN 12 - -/* Error codes for Error Reporting in slow path flows */ -#define FCOE_SLOW_PATH_ERROR_CODE_TOO_MANY_FUNCS 0 -#define FCOE_SLOW_PATH_ERROR_CODE_NO_LICENSE 1 - -/* Error codes for Error Reporting in fast path flows - * XFER error codes - */ -#define FCOE_ERROR_CODE_XFER_OOO_RO 0 -#define FCOE_ERROR_CODE_XFER_RO_NOT_ALIGNED 1 -#define FCOE_ERROR_CODE_XFER_NULL_BURST_LEN 2 -#define FCOE_ERROR_CODE_XFER_RO_GREATER_THAN_DATA2TRNS 3 -#define FCOE_ERROR_CODE_XFER_INVALID_PAYLOAD_SIZE 4 -#define FCOE_ERROR_CODE_XFER_TASK_TYPE_NOT_WRITE 5 -#define FCOE_ERROR_CODE_XFER_PEND_XFER_SET 6 -#define FCOE_ERROR_CODE_XFER_OPENED_SEQ 7 -#define FCOE_ERROR_CODE_XFER_FCTL 8 - -/* FCP RSP error codes */ -#define FCOE_ERROR_CODE_FCP_RSP_BIDI_FLAGS_SET 9 -#define FCOE_ERROR_CODE_FCP_RSP_UNDERFLOW 10 -#define FCOE_ERROR_CODE_FCP_RSP_OVERFLOW 11 -#define FCOE_ERROR_CODE_FCP_RSP_INVALID_LENGTH_FIELD 12 -#define FCOE_ERROR_CODE_FCP_RSP_INVALID_SNS_FIELD 13 -#define FCOE_ERROR_CODE_FCP_RSP_INVALID_PAYLOAD_SIZE 14 -#define FCOE_ERROR_CODE_FCP_RSP_PEND_XFER_SET 15 -#define FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ 16 -#define FCOE_ERROR_CODE_FCP_RSP_FCTL 17 -#define FCOE_ERROR_CODE_FCP_RSP_LAST_SEQ_RESET 18 -#define FCOE_ERROR_CODE_FCP_RSP_CONF_REQ_NOT_SUPPORTED_YET 19 - -/* FCP DATA error codes */ -#define FCOE_ERROR_CODE_DATA_OOO_RO 20 -#define FCOE_ERROR_CODE_DATA_EXCEEDS_DEFINED_MAX_FRAME_SIZE 21 -#define FCOE_ERROR_CODE_DATA_EXCEEDS_DATA2TRNS 22 -#define FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET 23 -#define FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET 24 -#define FCOE_ERROR_CODE_DATA_EOFN_END_SEQ_SET 25 -#define FCOE_ERROR_CODE_DATA_EOFT_END_SEQ_RESET 26 -#define FCOE_ERROR_CODE_DATA_TASK_TYPE_NOT_READ 27 -#define FCOE_ERROR_CODE_DATA_FCTL 28 - -/* Middle path error codes */ -#define FCOE_ERROR_CODE_MIDPATH_INVALID_TYPE 29 -#define FCOE_ERROR_CODE_MIDPATH_SOFI3_SEQ_ACTIVE_SET 30 -#define FCOE_ERROR_CODE_MIDPATH_SOFN_SEQ_ACTIVE_RESET 31 -#define FCOE_ERROR_CODE_MIDPATH_EOFN_END_SEQ_SET 32 -#define FCOE_ERROR_CODE_MIDPATH_EOFT_END_SEQ_RESET 33 -#define FCOE_ERROR_CODE_MIDPATH_REPLY_FCTL 34 -#define FCOE_ERROR_CODE_MIDPATH_INVALID_REPLY 35 -#define FCOE_ERROR_CODE_MIDPATH_ELS_REPLY_RCTL 36 - -/* ABTS error codes */ -#define FCOE_ERROR_CODE_ABTS_REPLY_F_CTL 37 -#define FCOE_ERROR_CODE_ABTS_REPLY_DDF_RCTL_FIELD 38 -#define FCOE_ERROR_CODE_ABTS_REPLY_INVALID_BLS_RCTL 39 -#define FCOE_ERROR_CODE_ABTS_REPLY_INVALID_RCTL 40 -#define FCOE_ERROR_CODE_ABTS_REPLY_RCTL_GENERAL_MISMATCH 41 - -/* Common error codes */ -#define FCOE_ERROR_CODE_COMMON_MIDDLE_FRAME_WITH_PAD 42 -#define FCOE_ERROR_CODE_COMMON_SEQ_INIT_IN_TCE 43 -#define FCOE_ERROR_CODE_COMMON_FC_HDR_RX_ID_MISMATCH 44 -#define FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT 45 -#define FCOE_ERROR_CODE_COMMON_DATA_FC_HDR_FCP_TYPE_MISMATCH 46 -#define FCOE_ERROR_CODE_COMMON_DATA_NO_MORE_SGES 47 -#define FCOE_ERROR_CODE_COMMON_OPTIONAL_FC_HDR 48 -#define FCOE_ERROR_CODE_COMMON_READ_TCE_OX_ID_TOO_BIG 49 -#define FCOE_ERROR_CODE_COMMON_DATA_WAS_NOT_TRANSMITTED 50 - -/* Unsolicited Rx error codes */ -#define FCOE_ERROR_CODE_UNSOLICITED_TYPE_NOT_ELS 51 -#define FCOE_ERROR_CODE_UNSOLICITED_TYPE_NOT_BLS 52 -#define FCOE_ERROR_CODE_UNSOLICITED_FCTL_ELS 53 -#define FCOE_ERROR_CODE_UNSOLICITED_FCTL_BLS 54 -#define FCOE_ERROR_CODE_UNSOLICITED_R_CTL 55 - -#define FCOE_ERROR_CODE_RW_TASK_DDF_RCTL_INFO_FIELD 56 -#define FCOE_ERROR_CODE_RW_TASK_INVALID_RCTL 57 -#define FCOE_ERROR_CODE_RW_TASK_RCTL_GENERAL_MISMATCH 58 - -/* Timer error codes */ -#define FCOE_ERROR_CODE_E_D_TOV_TIMER_EXPIRATION 60 -#define FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION 61 - - -#endif /* BNX2FC_CONSTANTS_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_debug.h b/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_debug.h deleted file mode 100644 index 3416d9a7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_debug.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef __BNX2FC_DEBUG__ -#define __BNX2FC_DEBUG__ - -/* Log level bit mask */ -#define LOG_IO 0x01 /* scsi cmd error, cleanup */ -#define LOG_TGT 0x02 /* Session setup, cleanup, etc' */ -#define LOG_HBA 0x04 /* lport events, link, mtu, etc' */ -#define LOG_ELS 0x08 /* ELS logs */ -#define LOG_MISC 0x10 /* fcoe L2 frame related logs*/ -#define LOG_ALL 0xff /* LOG all messages */ - -extern unsigned int bnx2fc_debug_level; - -#define BNX2FC_CHK_LOGGING(LEVEL, CMD) \ - do { \ - if (unlikely(bnx2fc_debug_level & LEVEL)) \ - do { \ - CMD; \ - } while (0); \ - } while (0) - -#define BNX2FC_ELS_DBG(fmt, arg...) \ - BNX2FC_CHK_LOGGING(LOG_ELS, \ - printk(KERN_INFO PFX fmt, ##arg)) - -#define BNX2FC_MISC_DBG(fmt, arg...) \ - BNX2FC_CHK_LOGGING(LOG_MISC, \ - printk(KERN_INFO PFX fmt, ##arg)) - -#define BNX2FC_IO_DBG(io_req, fmt, arg...) \ - do { \ - if (!io_req || !io_req->port || !io_req->port->lport || \ - !io_req->port->lport->host) \ - BNX2FC_CHK_LOGGING(LOG_IO, \ - printk(KERN_INFO PFX "NULL " fmt, ##arg)); \ - else \ - BNX2FC_CHK_LOGGING(LOG_IO, \ - shost_printk(KERN_INFO, \ - (io_req)->port->lport->host, \ - PFX "xid:0x%x " fmt, \ - (io_req)->xid, ##arg)); \ - } while (0) - -#define BNX2FC_TGT_DBG(tgt, fmt, arg...) \ - do { \ - if (!tgt || !tgt->port || !tgt->port->lport || \ - !tgt->port->lport->host || !tgt->rport) \ - BNX2FC_CHK_LOGGING(LOG_TGT, \ - printk(KERN_INFO PFX "NULL " fmt, ##arg)); \ - else \ - BNX2FC_CHK_LOGGING(LOG_TGT, \ - shost_printk(KERN_INFO, \ - (tgt)->port->lport->host, \ - PFX "port:%x " fmt, \ - (tgt)->rport->port_id, ##arg)); \ - } while (0) - - -#define BNX2FC_HBA_DBG(lport, fmt, arg...) \ - do { \ - if (!lport || !lport->host) \ - BNX2FC_CHK_LOGGING(LOG_HBA, \ - printk(KERN_INFO PFX "NULL " fmt, ##arg)); \ - else \ - BNX2FC_CHK_LOGGING(LOG_HBA, \ - shost_printk(KERN_INFO, lport->host, \ - PFX fmt, ##arg)); \ - } while (0) - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_els.c b/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_els.c deleted file mode 100644 index ce0ce3e3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_els.c +++ /dev/null @@ -1,929 +0,0 @@ -/* - * bnx2fc_els.c: Broadcom NetXtreme II Linux FCoE offload driver. - * This file contains helper routines that handle ELS requests - * and responses. - * - * Copyright (c) 2008 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) - */ - -#include "bnx2fc.h" - -static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp, - void *arg); -static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, - void *arg); -static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, - void *data, u32 data_len, - void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg), - struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec); - -static void bnx2fc_rrq_compl(struct bnx2fc_els_cb_arg *cb_arg) -{ - struct bnx2fc_cmd *orig_io_req; - struct bnx2fc_cmd *rrq_req; - int rc = 0; - - BUG_ON(!cb_arg); - rrq_req = cb_arg->io_req; - orig_io_req = cb_arg->aborted_io_req; - BUG_ON(!orig_io_req); - BNX2FC_ELS_DBG("rrq_compl: orig xid = 0x%x, rrq_xid = 0x%x\n", - orig_io_req->xid, rrq_req->xid); - - kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); - - if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rrq_req->req_flags)) { - /* - * els req is timed out. cleanup the IO with FW and - * drop the completion. Remove from active_cmd_queue. - */ - BNX2FC_ELS_DBG("rrq xid - 0x%x timed out, clean it up\n", - rrq_req->xid); - - if (rrq_req->on_active_queue) { - list_del_init(&rrq_req->link); - rrq_req->on_active_queue = 0; - rc = bnx2fc_initiate_cleanup(rrq_req); - BUG_ON(rc); - } - } - kfree(cb_arg); -} -int bnx2fc_send_rrq(struct bnx2fc_cmd *aborted_io_req) -{ - - struct fc_els_rrq rrq; - struct bnx2fc_rport *tgt = aborted_io_req->tgt; - struct fc_lport *lport = tgt->rdata->local_port; - struct bnx2fc_els_cb_arg *cb_arg = NULL; - u32 sid = tgt->sid; - u32 r_a_tov = lport->r_a_tov; - unsigned long start = jiffies; - int rc; - - BNX2FC_ELS_DBG("Sending RRQ orig_xid = 0x%x\n", - aborted_io_req->xid); - memset(&rrq, 0, sizeof(rrq)); - - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_NOIO); - if (!cb_arg) { - printk(KERN_ERR PFX "Unable to allocate cb_arg for RRQ\n"); - rc = -ENOMEM; - goto rrq_err; - } - - cb_arg->aborted_io_req = aborted_io_req; - - rrq.rrq_cmd = ELS_RRQ; - hton24(rrq.rrq_s_id, sid); - rrq.rrq_ox_id = htons(aborted_io_req->xid); - rrq.rrq_rx_id = htons(aborted_io_req->task->rxwr_txrd.var_ctx.rx_id); - -retry_rrq: - rc = bnx2fc_initiate_els(tgt, ELS_RRQ, &rrq, sizeof(rrq), - bnx2fc_rrq_compl, cb_arg, - r_a_tov); - if (rc == -ENOMEM) { - if (time_after(jiffies, start + (10 * HZ))) { - BNX2FC_ELS_DBG("rrq Failed\n"); - rc = FAILED; - goto rrq_err; - } - msleep(20); - goto retry_rrq; - } -rrq_err: - if (rc) { - BNX2FC_ELS_DBG("RRQ failed - release orig io req 0x%x\n", - aborted_io_req->xid); - kfree(cb_arg); - spin_lock_bh(&tgt->tgt_lock); - kref_put(&aborted_io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - } - return rc; -} - -static void bnx2fc_l2_els_compl(struct bnx2fc_els_cb_arg *cb_arg) -{ - struct bnx2fc_cmd *els_req; - struct bnx2fc_rport *tgt; - struct bnx2fc_mp_req *mp_req; - struct fc_frame_header *fc_hdr; - unsigned char *buf; - void *resp_buf; - u32 resp_len, hdr_len; - u16 l2_oxid; - int frame_len; - int rc = 0; - - l2_oxid = cb_arg->l2_oxid; - BNX2FC_ELS_DBG("ELS COMPL - l2_oxid = 0x%x\n", l2_oxid); - - els_req = cb_arg->io_req; - if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &els_req->req_flags)) { - /* - * els req is timed out. cleanup the IO with FW and - * drop the completion. libfc will handle the els timeout - */ - if (els_req->on_active_queue) { - list_del_init(&els_req->link); - els_req->on_active_queue = 0; - rc = bnx2fc_initiate_cleanup(els_req); - BUG_ON(rc); - } - goto free_arg; - } - - tgt = els_req->tgt; - mp_req = &(els_req->mp_req); - fc_hdr = &(mp_req->resp_fc_hdr); - resp_len = mp_req->resp_len; - resp_buf = mp_req->resp_buf; - - buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); - if (!buf) { - printk(KERN_ERR PFX "Unable to alloc mp buf\n"); - goto free_arg; - } - hdr_len = sizeof(*fc_hdr); - if (hdr_len + resp_len > PAGE_SIZE) { - printk(KERN_ERR PFX "l2_els_compl: resp len is " - "beyond page size\n"); - goto free_buf; - } - memcpy(buf, fc_hdr, hdr_len); - memcpy(buf + hdr_len, resp_buf, resp_len); - frame_len = hdr_len + resp_len; - - bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, l2_oxid); - -free_buf: - kfree(buf); -free_arg: - kfree(cb_arg); -} - -int bnx2fc_send_adisc(struct bnx2fc_rport *tgt, struct fc_frame *fp) -{ - struct fc_els_adisc *adisc; - struct fc_frame_header *fh; - struct bnx2fc_els_cb_arg *cb_arg; - struct fc_lport *lport = tgt->rdata->local_port; - u32 r_a_tov = lport->r_a_tov; - int rc; - - fh = fc_frame_header_get(fp); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); - if (!cb_arg) { - printk(KERN_ERR PFX "Unable to allocate cb_arg for ADISC\n"); - return -ENOMEM; - } - - cb_arg->l2_oxid = ntohs(fh->fh_ox_id); - - BNX2FC_ELS_DBG("send ADISC: l2_oxid = 0x%x\n", cb_arg->l2_oxid); - adisc = fc_frame_payload_get(fp, sizeof(*adisc)); - /* adisc is initialized by libfc */ - rc = bnx2fc_initiate_els(tgt, ELS_ADISC, adisc, sizeof(*adisc), - bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); - if (rc) - kfree(cb_arg); - return rc; -} - -int bnx2fc_send_logo(struct bnx2fc_rport *tgt, struct fc_frame *fp) -{ - struct fc_els_logo *logo; - struct fc_frame_header *fh; - struct bnx2fc_els_cb_arg *cb_arg; - struct fc_lport *lport = tgt->rdata->local_port; - u32 r_a_tov = lport->r_a_tov; - int rc; - - fh = fc_frame_header_get(fp); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); - if (!cb_arg) { - printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n"); - return -ENOMEM; - } - - cb_arg->l2_oxid = ntohs(fh->fh_ox_id); - - BNX2FC_ELS_DBG("Send LOGO: l2_oxid = 0x%x\n", cb_arg->l2_oxid); - logo = fc_frame_payload_get(fp, sizeof(*logo)); - /* logo is initialized by libfc */ - rc = bnx2fc_initiate_els(tgt, ELS_LOGO, logo, sizeof(*logo), - bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); - if (rc) - kfree(cb_arg); - return rc; -} - -int bnx2fc_send_rls(struct bnx2fc_rport *tgt, struct fc_frame *fp) -{ - struct fc_els_rls *rls; - struct fc_frame_header *fh; - struct bnx2fc_els_cb_arg *cb_arg; - struct fc_lport *lport = tgt->rdata->local_port; - u32 r_a_tov = lport->r_a_tov; - int rc; - - fh = fc_frame_header_get(fp); - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); - if (!cb_arg) { - printk(KERN_ERR PFX "Unable to allocate cb_arg for LOGO\n"); - return -ENOMEM; - } - - cb_arg->l2_oxid = ntohs(fh->fh_ox_id); - - rls = fc_frame_payload_get(fp, sizeof(*rls)); - /* rls is initialized by libfc */ - rc = bnx2fc_initiate_els(tgt, ELS_RLS, rls, sizeof(*rls), - bnx2fc_l2_els_compl, cb_arg, 2 * r_a_tov); - if (rc) - kfree(cb_arg); - return rc; -} - -void bnx2fc_srr_compl(struct bnx2fc_els_cb_arg *cb_arg) -{ - struct bnx2fc_mp_req *mp_req; - struct fc_frame_header *fc_hdr, *fh; - struct bnx2fc_cmd *srr_req; - struct bnx2fc_cmd *orig_io_req; - struct fc_frame *fp; - unsigned char *buf; - void *resp_buf; - u32 resp_len, hdr_len; - u8 opcode; - int rc = 0; - - orig_io_req = cb_arg->aborted_io_req; - srr_req = cb_arg->io_req; - if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &srr_req->req_flags)) { - /* SRR timedout */ - BNX2FC_IO_DBG(srr_req, "srr timed out, abort " - "orig_io - 0x%x\n", - orig_io_req->xid); - rc = bnx2fc_initiate_abts(srr_req); - if (rc != SUCCESS) { - BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts " - "failed. issue cleanup\n"); - bnx2fc_initiate_cleanup(srr_req); - } - if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || - test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(srr_req, "srr_compl:xid 0x%x flags = %lx", - orig_io_req->xid, orig_io_req->req_flags); - goto srr_compl_done; - } - orig_io_req->srr_retry++; - if (orig_io_req->srr_retry <= SRR_RETRY_COUNT) { - struct bnx2fc_rport *tgt = orig_io_req->tgt; - spin_unlock_bh(&tgt->tgt_lock); - rc = bnx2fc_send_srr(orig_io_req, - orig_io_req->srr_offset, - orig_io_req->srr_rctl); - spin_lock_bh(&tgt->tgt_lock); - if (!rc) - goto srr_compl_done; - } - - rc = bnx2fc_initiate_abts(orig_io_req); - if (rc != SUCCESS) { - BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts " - "failed xid = 0x%x. issue cleanup\n", - orig_io_req->xid); - bnx2fc_initiate_cleanup(orig_io_req); - } - goto srr_compl_done; - } - if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags) || - test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(srr_req, "srr_compl:xid - 0x%x flags = %lx", - orig_io_req->xid, orig_io_req->req_flags); - goto srr_compl_done; - } - mp_req = &(srr_req->mp_req); - fc_hdr = &(mp_req->resp_fc_hdr); - resp_len = mp_req->resp_len; - resp_buf = mp_req->resp_buf; - - hdr_len = sizeof(*fc_hdr); - buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); - if (!buf) { - printk(KERN_ERR PFX "srr buf: mem alloc failure\n"); - goto srr_compl_done; - } - memcpy(buf, fc_hdr, hdr_len); - memcpy(buf + hdr_len, resp_buf, resp_len); - - fp = fc_frame_alloc(NULL, resp_len); - if (!fp) { - printk(KERN_ERR PFX "fc_frame_alloc failure\n"); - goto free_buf; - } - - fh = (struct fc_frame_header *) fc_frame_header_get(fp); - /* Copy FC Frame header and payload into the frame */ - memcpy(fh, buf, hdr_len + resp_len); - - opcode = fc_frame_payload_op(fp); - switch (opcode) { - case ELS_LS_ACC: - BNX2FC_IO_DBG(srr_req, "SRR success\n"); - break; - case ELS_LS_RJT: - BNX2FC_IO_DBG(srr_req, "SRR rejected\n"); - rc = bnx2fc_initiate_abts(orig_io_req); - if (rc != SUCCESS) { - BNX2FC_IO_DBG(srr_req, "srr_compl: initiate_abts " - "failed xid = 0x%x. issue cleanup\n", - orig_io_req->xid); - bnx2fc_initiate_cleanup(orig_io_req); - } - break; - default: - BNX2FC_IO_DBG(srr_req, "srr compl - invalid opcode = %d\n", - opcode); - break; - } - fc_frame_free(fp); -free_buf: - kfree(buf); -srr_compl_done: - kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); -} - -void bnx2fc_rec_compl(struct bnx2fc_els_cb_arg *cb_arg) -{ - struct bnx2fc_cmd *orig_io_req, *new_io_req; - struct bnx2fc_cmd *rec_req; - struct bnx2fc_mp_req *mp_req; - struct fc_frame_header *fc_hdr, *fh; - struct fc_els_ls_rjt *rjt; - struct fc_els_rec_acc *acc; - struct bnx2fc_rport *tgt; - struct fcoe_err_report_entry *err_entry; - struct scsi_cmnd *sc_cmd; - enum fc_rctl r_ctl; - unsigned char *buf; - void *resp_buf; - struct fc_frame *fp; - u8 opcode; - u32 offset; - u32 e_stat; - u32 resp_len, hdr_len; - int rc = 0; - bool send_seq_clnp = false; - bool abort_io = false; - - BNX2FC_MISC_DBG("Entered rec_compl callback\n"); - rec_req = cb_arg->io_req; - orig_io_req = cb_arg->aborted_io_req; - BNX2FC_IO_DBG(rec_req, "rec_compl: orig xid = 0x%x", orig_io_req->xid); - tgt = orig_io_req->tgt; - - /* Handle REC timeout case */ - if (test_and_clear_bit(BNX2FC_FLAG_ELS_TIMEOUT, &rec_req->req_flags)) { - BNX2FC_IO_DBG(rec_req, "timed out, abort " - "orig_io - 0x%x\n", - orig_io_req->xid); - /* els req is timed out. send abts for els */ - rc = bnx2fc_initiate_abts(rec_req); - if (rc != SUCCESS) { - BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts " - "failed. issue cleanup\n"); - bnx2fc_initiate_cleanup(rec_req); - } - orig_io_req->rec_retry++; - /* REC timedout. send ABTS to the orig IO req */ - if (orig_io_req->rec_retry <= REC_RETRY_COUNT) { - spin_unlock_bh(&tgt->tgt_lock); - rc = bnx2fc_send_rec(orig_io_req); - spin_lock_bh(&tgt->tgt_lock); - if (!rc) - goto rec_compl_done; - } - rc = bnx2fc_initiate_abts(orig_io_req); - if (rc != SUCCESS) { - BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts " - "failed xid = 0x%x. issue cleanup\n", - orig_io_req->xid); - bnx2fc_initiate_cleanup(orig_io_req); - } - goto rec_compl_done; - } - - if (test_bit(BNX2FC_FLAG_IO_COMPL, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(rec_req, "completed" - "orig_io - 0x%x\n", - orig_io_req->xid); - goto rec_compl_done; - } - if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &orig_io_req->req_flags)) { - BNX2FC_IO_DBG(rec_req, "abts in prog " - "orig_io - 0x%x\n", - orig_io_req->xid); - goto rec_compl_done; - } - - mp_req = &(rec_req->mp_req); - fc_hdr = &(mp_req->resp_fc_hdr); - resp_len = mp_req->resp_len; - acc = resp_buf = mp_req->resp_buf; - - hdr_len = sizeof(*fc_hdr); - - buf = kzalloc(PAGE_SIZE, GFP_ATOMIC); - if (!buf) { - printk(KERN_ERR PFX "rec buf: mem alloc failure\n"); - goto rec_compl_done; - } - memcpy(buf, fc_hdr, hdr_len); - memcpy(buf + hdr_len, resp_buf, resp_len); - - fp = fc_frame_alloc(NULL, resp_len); - if (!fp) { - printk(KERN_ERR PFX "fc_frame_alloc failure\n"); - goto free_buf; - } - - fh = (struct fc_frame_header *) fc_frame_header_get(fp); - /* Copy FC Frame header and payload into the frame */ - memcpy(fh, buf, hdr_len + resp_len); - - opcode = fc_frame_payload_op(fp); - if (opcode == ELS_LS_RJT) { - BNX2FC_IO_DBG(rec_req, "opcode is RJT\n"); - rjt = fc_frame_payload_get(fp, sizeof(*rjt)); - if ((rjt->er_reason == ELS_RJT_LOGIC || - rjt->er_reason == ELS_RJT_UNAB) && - rjt->er_explan == ELS_EXPL_OXID_RXID) { - BNX2FC_IO_DBG(rec_req, "handle CMD LOST case\n"); - new_io_req = bnx2fc_cmd_alloc(tgt); - if (!new_io_req) - goto abort_io; - new_io_req->sc_cmd = orig_io_req->sc_cmd; - /* cleanup orig_io_req that is with the FW */ - set_bit(BNX2FC_FLAG_CMD_LOST, - &orig_io_req->req_flags); - bnx2fc_initiate_cleanup(orig_io_req); - /* Post a new IO req with the same sc_cmd */ - BNX2FC_IO_DBG(rec_req, "Post IO request again\n"); - spin_unlock_bh(&tgt->tgt_lock); - rc = bnx2fc_post_io_req(tgt, new_io_req); - spin_lock_bh(&tgt->tgt_lock); - if (!rc) - goto free_frame; - BNX2FC_IO_DBG(rec_req, "REC: io post err\n"); - } -abort_io: - rc = bnx2fc_initiate_abts(orig_io_req); - if (rc != SUCCESS) { - BNX2FC_IO_DBG(rec_req, "rec_compl: initiate_abts " - "failed. issue cleanup\n"); - bnx2fc_initiate_cleanup(orig_io_req); - } - } else if (opcode == ELS_LS_ACC) { - /* REVISIT: Check if the exchange is already aborted */ - offset = ntohl(acc->reca_fc4value); - e_stat = ntohl(acc->reca_e_stat); - if (e_stat & ESB_ST_SEQ_INIT) { - BNX2FC_IO_DBG(rec_req, "target has the seq init\n"); - goto free_frame; - } - BNX2FC_IO_DBG(rec_req, "e_stat = 0x%x, offset = 0x%x\n", - e_stat, offset); - /* Seq initiative is with us */ - err_entry = (struct fcoe_err_report_entry *) - &orig_io_req->err_entry; - sc_cmd = orig_io_req->sc_cmd; - if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { - /* SCSI WRITE command */ - if (offset == orig_io_req->data_xfer_len) { - BNX2FC_IO_DBG(rec_req, "WRITE - resp lost\n"); - /* FCP_RSP lost */ - r_ctl = FC_RCTL_DD_CMD_STATUS; - offset = 0; - } else { - /* start transmitting from offset */ - BNX2FC_IO_DBG(rec_req, "XFER_RDY/DATA lost\n"); - send_seq_clnp = true; - r_ctl = FC_RCTL_DD_DATA_DESC; - if (bnx2fc_initiate_seq_cleanup(orig_io_req, - offset, r_ctl)) - abort_io = true; - /* XFER_RDY */ - } - } else { - /* SCSI READ command */ - if (err_entry->data.rx_buf_off == - orig_io_req->data_xfer_len) { - /* FCP_RSP lost */ - BNX2FC_IO_DBG(rec_req, "READ - resp lost\n"); - r_ctl = FC_RCTL_DD_CMD_STATUS; - offset = 0; - } else { - /* request retransmission from this offset */ - send_seq_clnp = true; - offset = err_entry->data.rx_buf_off; - BNX2FC_IO_DBG(rec_req, "RD DATA lost\n"); - /* FCP_DATA lost */ - r_ctl = FC_RCTL_DD_SOL_DATA; - if (bnx2fc_initiate_seq_cleanup(orig_io_req, - offset, r_ctl)) - abort_io = true; - } - } - if (abort_io) { - rc = bnx2fc_initiate_abts(orig_io_req); - if (rc != SUCCESS) { - BNX2FC_IO_DBG(rec_req, "rec_compl:initiate_abts" - " failed. issue cleanup\n"); - bnx2fc_initiate_cleanup(orig_io_req); - } - } else if (!send_seq_clnp) { - BNX2FC_IO_DBG(rec_req, "Send SRR - FCP_RSP\n"); - spin_unlock_bh(&tgt->tgt_lock); - rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl); - spin_lock_bh(&tgt->tgt_lock); - - if (rc) { - BNX2FC_IO_DBG(rec_req, "Unable to send SRR" - " IO will abort\n"); - } - } - } -free_frame: - fc_frame_free(fp); -free_buf: - kfree(buf); -rec_compl_done: - kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); - kfree(cb_arg); -} - -int bnx2fc_send_rec(struct bnx2fc_cmd *orig_io_req) -{ - struct fc_els_rec rec; - struct bnx2fc_rport *tgt = orig_io_req->tgt; - struct fc_lport *lport = tgt->rdata->local_port; - struct bnx2fc_els_cb_arg *cb_arg = NULL; - u32 sid = tgt->sid; - u32 r_a_tov = lport->r_a_tov; - int rc; - - BNX2FC_IO_DBG(orig_io_req, "Sending REC\n"); - memset(&rec, 0, sizeof(rec)); - - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); - if (!cb_arg) { - printk(KERN_ERR PFX "Unable to allocate cb_arg for REC\n"); - rc = -ENOMEM; - goto rec_err; - } - kref_get(&orig_io_req->refcount); - - cb_arg->aborted_io_req = orig_io_req; - - rec.rec_cmd = ELS_REC; - hton24(rec.rec_s_id, sid); - rec.rec_ox_id = htons(orig_io_req->xid); - rec.rec_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id); - - rc = bnx2fc_initiate_els(tgt, ELS_REC, &rec, sizeof(rec), - bnx2fc_rec_compl, cb_arg, - r_a_tov); -rec_err: - if (rc) { - BNX2FC_IO_DBG(orig_io_req, "REC failed - release\n"); - spin_lock_bh(&tgt->tgt_lock); - kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - kfree(cb_arg); - } - return rc; -} - -int bnx2fc_send_srr(struct bnx2fc_cmd *orig_io_req, u32 offset, u8 r_ctl) -{ - struct fcp_srr srr; - struct bnx2fc_rport *tgt = orig_io_req->tgt; - struct fc_lport *lport = tgt->rdata->local_port; - struct bnx2fc_els_cb_arg *cb_arg = NULL; - u32 r_a_tov = lport->r_a_tov; - int rc; - - BNX2FC_IO_DBG(orig_io_req, "Sending SRR\n"); - memset(&srr, 0, sizeof(srr)); - - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); - if (!cb_arg) { - printk(KERN_ERR PFX "Unable to allocate cb_arg for SRR\n"); - rc = -ENOMEM; - goto srr_err; - } - kref_get(&orig_io_req->refcount); - - cb_arg->aborted_io_req = orig_io_req; - - srr.srr_op = ELS_SRR; - srr.srr_ox_id = htons(orig_io_req->xid); - srr.srr_rx_id = htons(orig_io_req->task->rxwr_txrd.var_ctx.rx_id); - srr.srr_rel_off = htonl(offset); - srr.srr_r_ctl = r_ctl; - orig_io_req->srr_offset = offset; - orig_io_req->srr_rctl = r_ctl; - - rc = bnx2fc_initiate_els(tgt, ELS_SRR, &srr, sizeof(srr), - bnx2fc_srr_compl, cb_arg, - r_a_tov); -srr_err: - if (rc) { - BNX2FC_IO_DBG(orig_io_req, "SRR failed - release\n"); - spin_lock_bh(&tgt->tgt_lock); - kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - kfree(cb_arg); - } else - set_bit(BNX2FC_FLAG_SRR_SENT, &orig_io_req->req_flags); - - return rc; -} - -static int bnx2fc_initiate_els(struct bnx2fc_rport *tgt, unsigned int op, - void *data, u32 data_len, - void (*cb_func)(struct bnx2fc_els_cb_arg *cb_arg), - struct bnx2fc_els_cb_arg *cb_arg, u32 timer_msec) -{ - struct fcoe_port *port = tgt->port; - struct bnx2fc_interface *interface = port->priv; - struct fc_rport *rport = tgt->rport; - struct fc_lport *lport = port->lport; - struct bnx2fc_cmd *els_req; - struct bnx2fc_mp_req *mp_req; - struct fc_frame_header *fc_hdr; - struct fcoe_task_ctx_entry *task; - struct fcoe_task_ctx_entry *task_page; - int rc = 0; - int task_idx, index; - u32 did, sid; - u16 xid; - - rc = fc_remote_port_chkready(rport); - if (rc) { - printk(KERN_ERR PFX "els 0x%x: rport not ready\n", op); - rc = -EINVAL; - goto els_err; - } - if (lport->state != LPORT_ST_READY || !(lport->link_up)) { - printk(KERN_ERR PFX "els 0x%x: link is not ready\n", op); - rc = -EINVAL; - goto els_err; - } - if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) || - (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags))) { - printk(KERN_ERR PFX "els 0x%x: tgt not ready\n", op); - rc = -EINVAL; - goto els_err; - } - els_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ELS); - if (!els_req) { - rc = -ENOMEM; - goto els_err; - } - - els_req->sc_cmd = NULL; - els_req->port = port; - els_req->tgt = tgt; - els_req->cb_func = cb_func; - cb_arg->io_req = els_req; - els_req->cb_arg = cb_arg; - - mp_req = (struct bnx2fc_mp_req *)&(els_req->mp_req); - rc = bnx2fc_init_mp_req(els_req); - if (rc == FAILED) { - printk(KERN_ERR PFX "ELS MP request init failed\n"); - spin_lock_bh(&tgt->tgt_lock); - kref_put(&els_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - rc = -ENOMEM; - goto els_err; - } else { - /* rc SUCCESS */ - rc = 0; - } - - /* Set the data_xfer_len to the size of ELS payload */ - mp_req->req_len = data_len; - els_req->data_xfer_len = mp_req->req_len; - - /* Fill ELS Payload */ - if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) { - memcpy(mp_req->req_buf, data, data_len); - } else { - printk(KERN_ERR PFX "Invalid ELS op 0x%x\n", op); - els_req->cb_func = NULL; - els_req->cb_arg = NULL; - spin_lock_bh(&tgt->tgt_lock); - kref_put(&els_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - rc = -EINVAL; - } - - if (rc) - goto els_err; - - /* Fill FC header */ - fc_hdr = &(mp_req->req_fc_hdr); - - did = tgt->rport->port_id; - sid = tgt->sid; - - if (op == ELS_SRR) - __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS4_REQ, did, sid, - FC_TYPE_FCP, FC_FC_FIRST_SEQ | - FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - else - __fc_fill_fc_hdr(fc_hdr, FC_RCTL_ELS_REQ, did, sid, - FC_TYPE_ELS, FC_FC_FIRST_SEQ | - FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - - /* Obtain exchange id */ - xid = els_req->xid; - task_idx = xid/BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - - /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[task_idx]; - task = &(task_page[index]); - bnx2fc_init_mp_task(els_req, task); - - spin_lock_bh(&tgt->tgt_lock); - - if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { - printk(KERN_ERR PFX "initiate_els.. session not ready\n"); - els_req->cb_func = NULL; - els_req->cb_arg = NULL; - kref_put(&els_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return -EINVAL; - } - - if (timer_msec) - bnx2fc_cmd_timer_set(els_req, timer_msec); - bnx2fc_add_2_sq(tgt, xid); - - els_req->on_active_queue = 1; - list_add_tail(&els_req->link, &tgt->els_queue); - - /* Ring doorbell */ - bnx2fc_ring_doorbell(tgt); - spin_unlock_bh(&tgt->tgt_lock); - -els_err: - return rc; -} - -void bnx2fc_process_els_compl(struct bnx2fc_cmd *els_req, - struct fcoe_task_ctx_entry *task, u8 num_rq) -{ - struct bnx2fc_mp_req *mp_req; - struct fc_frame_header *fc_hdr; - u64 *hdr; - u64 *temp_hdr; - - BNX2FC_ELS_DBG("Entered process_els_compl xid = 0x%x" - "cmd_type = %d\n", els_req->xid, els_req->cmd_type); - - if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE, - &els_req->req_flags)) { - BNX2FC_ELS_DBG("Timer context finished processing this " - "els - 0x%x\n", els_req->xid); - /* This IO doesn't receive cleanup completion */ - kref_put(&els_req->refcount, bnx2fc_cmd_release); - return; - } - - /* Cancel the timeout_work, as we received the response */ - if (cancel_delayed_work(&els_req->timeout_work)) - kref_put(&els_req->refcount, - bnx2fc_cmd_release); /* drop timer hold */ - - if (els_req->on_active_queue) { - list_del_init(&els_req->link); - els_req->on_active_queue = 0; - } - - mp_req = &(els_req->mp_req); - fc_hdr = &(mp_req->resp_fc_hdr); - - hdr = (u64 *)fc_hdr; - temp_hdr = (u64 *) - &task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr; - hdr[0] = cpu_to_be64(temp_hdr[0]); - hdr[1] = cpu_to_be64(temp_hdr[1]); - hdr[2] = cpu_to_be64(temp_hdr[2]); - - mp_req->resp_len = - task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len; - - /* Parse ELS response */ - if ((els_req->cb_func) && (els_req->cb_arg)) { - els_req->cb_func(els_req->cb_arg); - els_req->cb_arg = NULL; - } - - kref_put(&els_req->refcount, bnx2fc_cmd_release); -} - -static void bnx2fc_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, - void *arg) -{ - struct fcoe_ctlr *fip = arg; - struct fc_exch *exch = fc_seq_exch(seq); - struct fc_lport *lport = exch->lp; - u8 *mac; - struct fc_frame_header *fh; - u8 op; - - if (IS_ERR(fp)) - goto done; - - mac = fr_cb(fp)->granted_mac; - if (is_zero_ether_addr(mac)) { - fh = fc_frame_header_get(fp); - if (fh->fh_type != FC_TYPE_ELS) { - printk(KERN_ERR PFX "bnx2fc_flogi_resp:" - "fh_type != FC_TYPE_ELS\n"); - fc_frame_free(fp); - return; - } - op = fc_frame_payload_op(fp); - if (lport->vport) { - if (op == ELS_LS_RJT) { - printk(KERN_ERR PFX "bnx2fc_flogi_resp is LS_RJT\n"); - fc_vport_terminate(lport->vport); - fc_frame_free(fp); - return; - } - } - if (fcoe_ctlr_recv_flogi(fip, lport, fp)) { - fc_frame_free(fp); - return; - } - } - fip->update_mac(lport, mac); -done: - fc_lport_flogi_resp(seq, fp, lport); -} - -static void bnx2fc_logo_resp(struct fc_seq *seq, struct fc_frame *fp, - void *arg) -{ - struct fcoe_ctlr *fip = arg; - struct fc_exch *exch = fc_seq_exch(seq); - struct fc_lport *lport = exch->lp; - static u8 zero_mac[ETH_ALEN] = { 0 }; - - if (!IS_ERR(fp)) - fip->update_mac(lport, zero_mac); - fc_lport_logo_resp(seq, fp, lport); -} - -struct fc_seq *bnx2fc_elsct_send(struct fc_lport *lport, u32 did, - struct fc_frame *fp, unsigned int op, - void (*resp)(struct fc_seq *, - struct fc_frame *, - void *), - void *arg, u32 timeout) -{ - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_interface *interface = port->priv; - struct fcoe_ctlr *fip = &interface->ctlr; - struct fc_frame_header *fh = fc_frame_header_get(fp); - - switch (op) { - case ELS_FLOGI: - case ELS_FDISC: - return fc_elsct_send(lport, did, fp, op, bnx2fc_flogi_resp, - fip, timeout); - case ELS_LOGO: - /* only hook onto fabric logouts, not port logouts */ - if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) - break; - return fc_elsct_send(lport, did, fp, op, bnx2fc_logo_resp, - fip, timeout); - } - return fc_elsct_send(lport, did, fp, op, resp, arg, timeout); -} diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_fcoe.c deleted file mode 100644 index c1c6a92a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ /dev/null @@ -1,2559 +0,0 @@ -/* bnx2fc_fcoe.c: Broadcom NetXtreme II Linux FCoE offload driver. - * This file contains the code that interacts with libfc, libfcoe, - * cnic modules to create FCoE instances, send/receive non-offloaded - * FIP/FCoE packets, listen to link events etc. - * - * Copyright (c) 2008 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) - */ - -#include "bnx2fc.h" - -static struct list_head adapter_list; -static struct list_head if_list; -static u32 adapter_count; -static DEFINE_MUTEX(bnx2fc_dev_lock); -DEFINE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); - -#define DRV_MODULE_NAME "bnx2fc" -#define DRV_MODULE_VERSION BNX2FC_VERSION -#define DRV_MODULE_RELDATE "Jan 22, 2011" - - -static char version[] __devinitdata = - "Broadcom NetXtreme II FCoE Driver " DRV_MODULE_NAME \ - " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; - - -MODULE_AUTHOR("Bhanu Prakash Gollapudi "); -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 FCoE Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); - -#define BNX2FC_MAX_QUEUE_DEPTH 256 -#define BNX2FC_MIN_QUEUE_DEPTH 32 -#define FCOE_WORD_TO_BYTE 4 - -static struct scsi_transport_template *bnx2fc_transport_template; -static struct scsi_transport_template *bnx2fc_vport_xport_template; - -struct workqueue_struct *bnx2fc_wq; - -/* bnx2fc structure needs only one instance of the fcoe_percpu_s structure. - * Here the io threads are per cpu but the l2 thread is just one - */ -struct fcoe_percpu_s bnx2fc_global; -DEFINE_SPINLOCK(bnx2fc_global_lock); - -static struct cnic_ulp_ops bnx2fc_cnic_cb; -static struct libfc_function_template bnx2fc_libfc_fcn_templ; -static struct scsi_host_template bnx2fc_shost_template; -static struct fc_function_template bnx2fc_transport_function; -static struct fc_function_template bnx2fc_vport_xport_function; -static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode); -static void __bnx2fc_destroy(struct bnx2fc_interface *interface); -static int bnx2fc_destroy(struct net_device *net_device); -static int bnx2fc_enable(struct net_device *netdev); -static int bnx2fc_disable(struct net_device *netdev); - -static void bnx2fc_recv_frame(struct sk_buff *skb); - -static void bnx2fc_start_disc(struct bnx2fc_interface *interface); -static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev); -static int bnx2fc_lport_config(struct fc_lport *lport); -static int bnx2fc_em_config(struct fc_lport *lport); -static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba); -static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba); -static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba); -static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba); -static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, - struct device *parent, int npiv); -static void bnx2fc_destroy_work(struct work_struct *work); - -static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device *phys_dev); -static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device - *phys_dev); -static inline void bnx2fc_interface_put(struct bnx2fc_interface *interface); -static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic); - -static int bnx2fc_fw_init(struct bnx2fc_hba *hba); -static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba); - -static void bnx2fc_port_shutdown(struct fc_lport *lport); -static void bnx2fc_stop(struct bnx2fc_interface *interface); -static int __init bnx2fc_mod_init(void); -static void __exit bnx2fc_mod_exit(void); - -unsigned int bnx2fc_debug_level; -module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR); - -static int bnx2fc_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu); -/* notification function for CPU hotplug events */ -static struct notifier_block bnx2fc_cpu_notifier = { - .notifier_call = bnx2fc_cpu_callback, -}; - -static inline struct net_device *bnx2fc_netdev(const struct fc_lport *lport) -{ - return ((struct bnx2fc_interface *) - ((struct fcoe_port *)lport_priv(lport))->priv)->netdev; -} - -/** - * bnx2fc_get_lesb() - Fill the FCoE Link Error Status Block - * @lport: the local port - * @fc_lesb: the link error status block - */ -static void bnx2fc_get_lesb(struct fc_lport *lport, - struct fc_els_lesb *fc_lesb) -{ - struct net_device *netdev = bnx2fc_netdev(lport); - - __fcoe_get_lesb(lport, fc_lesb, netdev); -} - -static void bnx2fc_clean_rx_queue(struct fc_lport *lp) -{ - struct fcoe_percpu_s *bg; - struct fcoe_rcv_info *fr; - struct sk_buff_head *list; - struct sk_buff *skb, *next; - struct sk_buff *head; - - bg = &bnx2fc_global; - spin_lock_bh(&bg->fcoe_rx_list.lock); - list = &bg->fcoe_rx_list; - head = list->next; - for (skb = head; skb != (struct sk_buff *)list; - skb = next) { - next = skb->next; - fr = fcoe_dev_from_skb(skb); - if (fr->fr_dev == lp) { - __skb_unlink(skb, list); - kfree_skb(skb); - } - } - spin_unlock_bh(&bg->fcoe_rx_list.lock); -} - -int bnx2fc_get_paged_crc_eof(struct sk_buff *skb, int tlen) -{ - int rc; - spin_lock(&bnx2fc_global_lock); - rc = fcoe_get_paged_crc_eof(skb, tlen, &bnx2fc_global); - spin_unlock(&bnx2fc_global_lock); - - return rc; -} - -static void bnx2fc_abort_io(struct fc_lport *lport) -{ - /* - * This function is no-op for bnx2fc, but we do - * not want to leave it as NULL either, as libfc - * can call the default function which is - * fc_fcp_abort_io. - */ -} - -static void bnx2fc_cleanup(struct fc_lport *lport) -{ - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct bnx2fc_rport *tgt; - int i; - - BNX2FC_MISC_DBG("Entered %s\n", __func__); - mutex_lock(&hba->hba_mutex); - spin_lock_bh(&hba->hba_lock); - for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) { - tgt = hba->tgt_ofld_list[i]; - if (tgt) { - /* Cleanup IOs belonging to requested vport */ - if (tgt->port == port) { - spin_unlock_bh(&hba->hba_lock); - BNX2FC_TGT_DBG(tgt, "flush/cleanup\n"); - bnx2fc_flush_active_ios(tgt); - spin_lock_bh(&hba->hba_lock); - } - } - } - spin_unlock_bh(&hba->hba_lock); - mutex_unlock(&hba->hba_mutex); -} - -static int bnx2fc_xmit_l2_frame(struct bnx2fc_rport *tgt, - struct fc_frame *fp) -{ - struct fc_rport_priv *rdata = tgt->rdata; - struct fc_frame_header *fh; - int rc = 0; - - fh = fc_frame_header_get(fp); - BNX2FC_TGT_DBG(tgt, "Xmit L2 frame rport = 0x%x, oxid = 0x%x, " - "r_ctl = 0x%x\n", rdata->ids.port_id, - ntohs(fh->fh_ox_id), fh->fh_r_ctl); - if ((fh->fh_type == FC_TYPE_ELS) && - (fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { - - switch (fc_frame_payload_op(fp)) { - case ELS_ADISC: - rc = bnx2fc_send_adisc(tgt, fp); - break; - case ELS_LOGO: - rc = bnx2fc_send_logo(tgt, fp); - break; - case ELS_RLS: - rc = bnx2fc_send_rls(tgt, fp); - break; - default: - break; - } - } else if ((fh->fh_type == FC_TYPE_BLS) && - (fh->fh_r_ctl == FC_RCTL_BA_ABTS)) - BNX2FC_TGT_DBG(tgt, "ABTS frame\n"); - else { - BNX2FC_TGT_DBG(tgt, "Send L2 frame type 0x%x " - "rctl 0x%x thru non-offload path\n", - fh->fh_type, fh->fh_r_ctl); - return -ENODEV; - } - if (rc) - return -ENOMEM; - else - return 0; -} - -/** - * bnx2fc_xmit - bnx2fc's FCoE frame transmit function - * - * @lport: the associated local port - * @fp: the fc_frame to be transmitted - */ -static int bnx2fc_xmit(struct fc_lport *lport, struct fc_frame *fp) -{ - struct ethhdr *eh; - struct fcoe_crc_eof *cp; - struct sk_buff *skb; - struct fc_frame_header *fh; - struct bnx2fc_interface *interface; - struct bnx2fc_hba *hba; - struct fcoe_port *port; - struct fcoe_hdr *hp; - struct bnx2fc_rport *tgt; - struct fcoe_dev_stats *stats; - u8 sof, eof; - u32 crc; - unsigned int hlen, tlen, elen; - int wlen, rc = 0; - - port = (struct fcoe_port *)lport_priv(lport); - interface = port->priv; - hba = interface->hba; - - fh = fc_frame_header_get(fp); - - skb = fp_skb(fp); - if (!lport->link_up) { - BNX2FC_HBA_DBG(lport, "bnx2fc_xmit link down\n"); - kfree_skb(skb); - return 0; - } - - if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) { - if (!interface->ctlr.sel_fcf) { - BNX2FC_HBA_DBG(lport, "FCF not selected yet!\n"); - kfree_skb(skb); - return -EINVAL; - } - if (fcoe_ctlr_els_send(&interface->ctlr, lport, skb)) - return 0; - } - - sof = fr_sof(fp); - eof = fr_eof(fp); - - /* - * Snoop the frame header to check if the frame is for - * an offloaded session - */ - /* - * tgt_ofld_list access is synchronized using - * both hba mutex and hba lock. Atleast hba mutex or - * hba lock needs to be held for read access. - */ - - spin_lock_bh(&hba->hba_lock); - tgt = bnx2fc_tgt_lookup(port, ntoh24(fh->fh_d_id)); - if (tgt && (test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) { - /* This frame is for offloaded session */ - BNX2FC_HBA_DBG(lport, "xmit: Frame is for offloaded session " - "port_id = 0x%x\n", ntoh24(fh->fh_d_id)); - spin_unlock_bh(&hba->hba_lock); - rc = bnx2fc_xmit_l2_frame(tgt, fp); - if (rc != -ENODEV) { - kfree_skb(skb); - return rc; - } - } else { - spin_unlock_bh(&hba->hba_lock); - } - - elen = sizeof(struct ethhdr); - hlen = sizeof(struct fcoe_hdr); - tlen = sizeof(struct fcoe_crc_eof); - wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; - - skb->ip_summed = CHECKSUM_NONE; - crc = fcoe_fc_crc(fp); - - /* copy port crc and eof to the skb buff */ - if (skb_is_nonlinear(skb)) { - skb_frag_t *frag; - if (bnx2fc_get_paged_crc_eof(skb, tlen)) { - kfree_skb(skb); - return -ENOMEM; - } - frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset; - } else { - cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); - } - - memset(cp, 0, sizeof(*cp)); - cp->fcoe_eof = eof; - cp->fcoe_crc32 = cpu_to_le32(~crc); - if (skb_is_nonlinear(skb)) { - kunmap_atomic(cp); - cp = NULL; - } - - /* adjust skb network/transport offsets to match mac/fcoe/port */ - skb_push(skb, elen + hlen); - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - skb->mac_len = elen; - skb->protocol = htons(ETH_P_FCOE); - skb->dev = interface->netdev; - - /* fill up mac and fcoe headers */ - eh = eth_hdr(skb); - eh->h_proto = htons(ETH_P_FCOE); - if (interface->ctlr.map_dest) - fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id); - else - /* insert GW address */ - memcpy(eh->h_dest, interface->ctlr.dest_addr, ETH_ALEN); - - if (unlikely(interface->ctlr.flogi_oxid != FC_XID_UNKNOWN)) - memcpy(eh->h_source, interface->ctlr.ctl_src_addr, ETH_ALEN); - else - memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); - - hp = (struct fcoe_hdr *)(eh + 1); - memset(hp, 0, sizeof(*hp)); - if (FC_FCOE_VER) - FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); - hp->fcoe_sof = sof; - - /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ - if (lport->seq_offload && fr_max_payload(fp)) { - skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; - skb_shinfo(skb)->gso_size = fr_max_payload(fp); - } else { - skb_shinfo(skb)->gso_type = 0; - skb_shinfo(skb)->gso_size = 0; - } - - /*update tx stats */ - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - stats->TxFrames++; - stats->TxWords += wlen; - put_cpu(); - - /* send down to lld */ - fr_dev(fp) = lport; - if (port->fcoe_pending_queue.qlen) - fcoe_check_wait_queue(lport, skb); - else if (fcoe_start_io(skb)) - fcoe_check_wait_queue(lport, skb); - - return 0; -} - -/** - * bnx2fc_rcv - This is bnx2fc's receive function called by NET_RX_SOFTIRQ - * - * @skb: the receive socket buffer - * @dev: associated net device - * @ptype: context - * @olddev: last device - * - * This function receives the packet and builds FC frame and passes it up - */ -static int bnx2fc_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, struct net_device *olddev) -{ - struct fc_lport *lport; - struct bnx2fc_interface *interface; - struct fc_frame_header *fh; - struct fcoe_rcv_info *fr; - struct fcoe_percpu_s *bg; - unsigned short oxid; - - interface = container_of(ptype, struct bnx2fc_interface, - fcoe_packet_type); - lport = interface->ctlr.lp; - - if (unlikely(lport == NULL)) { - printk(KERN_ERR PFX "bnx2fc_rcv: lport is NULL\n"); - goto err; - } - - if (unlikely(eth_hdr(skb)->h_proto != htons(ETH_P_FCOE))) { - printk(KERN_ERR PFX "bnx2fc_rcv: Wrong FC type frame\n"); - goto err; - } - - /* - * Check for minimum frame length, and make sure required FCoE - * and FC headers are pulled into the linear data area. - */ - if (unlikely((skb->len < FCOE_MIN_FRAME) || - !pskb_may_pull(skb, FCOE_HEADER_LEN))) - goto err; - - skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); - fh = (struct fc_frame_header *) skb_transport_header(skb); - - oxid = ntohs(fh->fh_ox_id); - - fr = fcoe_dev_from_skb(skb); - fr->fr_dev = lport; - - bg = &bnx2fc_global; - spin_lock(&bg->fcoe_rx_list.lock); - - __skb_queue_tail(&bg->fcoe_rx_list, skb); - if (bg->fcoe_rx_list.qlen == 1) - wake_up_process(bg->thread); - - spin_unlock(&bg->fcoe_rx_list.lock); - - return 0; -err: - kfree_skb(skb); - return -1; -} - -static int bnx2fc_l2_rcv_thread(void *arg) -{ - struct fcoe_percpu_s *bg = arg; - struct sk_buff *skb; - - set_user_nice(current, -20); - set_current_state(TASK_INTERRUPTIBLE); - while (!kthread_should_stop()) { - schedule(); - spin_lock_bh(&bg->fcoe_rx_list.lock); - while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) { - spin_unlock_bh(&bg->fcoe_rx_list.lock); - bnx2fc_recv_frame(skb); - spin_lock_bh(&bg->fcoe_rx_list.lock); - } - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&bg->fcoe_rx_list.lock); - } - __set_current_state(TASK_RUNNING); - return 0; -} - - -static void bnx2fc_recv_frame(struct sk_buff *skb) -{ - u32 fr_len; - struct fc_lport *lport; - struct fcoe_rcv_info *fr; - struct fcoe_dev_stats *stats; - struct fc_frame_header *fh; - struct fcoe_crc_eof crc_eof; - struct fc_frame *fp; - struct fc_lport *vn_port; - struct fcoe_port *port; - u8 *mac = NULL; - u8 *dest_mac = NULL; - struct fcoe_hdr *hp; - - fr = fcoe_dev_from_skb(skb); - lport = fr->fr_dev; - if (unlikely(lport == NULL)) { - printk(KERN_ERR PFX "Invalid lport struct\n"); - kfree_skb(skb); - return; - } - - if (skb_is_nonlinear(skb)) - skb_linearize(skb); - mac = eth_hdr(skb)->h_source; - dest_mac = eth_hdr(skb)->h_dest; - - /* Pull the header */ - hp = (struct fcoe_hdr *) skb_network_header(skb); - fh = (struct fc_frame_header *) skb_transport_header(skb); - skb_pull(skb, sizeof(struct fcoe_hdr)); - fr_len = skb->len - sizeof(struct fcoe_crc_eof); - - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - stats->RxFrames++; - stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; - - fp = (struct fc_frame *)skb; - fc_frame_init(fp); - fr_dev(fp) = lport; - fr_sof(fp) = hp->fcoe_sof; - if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) { - put_cpu(); - kfree_skb(skb); - return; - } - fr_eof(fp) = crc_eof.fcoe_eof; - fr_crc(fp) = crc_eof.fcoe_crc32; - if (pskb_trim(skb, fr_len)) { - put_cpu(); - kfree_skb(skb); - return; - } - - fh = fc_frame_header_get(fp); - - vn_port = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id)); - if (vn_port) { - port = lport_priv(vn_port); - if (compare_ether_addr(port->data_src_addr, dest_mac) - != 0) { - BNX2FC_HBA_DBG(lport, "fpma mismatch\n"); - put_cpu(); - kfree_skb(skb); - return; - } - } - if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && - fh->fh_type == FC_TYPE_FCP) { - /* Drop FCP data. We dont this in L2 path */ - put_cpu(); - kfree_skb(skb); - return; - } - if (fh->fh_r_ctl == FC_RCTL_ELS_REQ && - fh->fh_type == FC_TYPE_ELS) { - switch (fc_frame_payload_op(fp)) { - case ELS_LOGO: - if (ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { - /* drop non-FIP LOGO */ - put_cpu(); - kfree_skb(skb); - return; - } - break; - } - } - - if (fh->fh_r_ctl == FC_RCTL_BA_ABTS) { - /* Drop incoming ABTS */ - put_cpu(); - kfree_skb(skb); - return; - } - - if (le32_to_cpu(fr_crc(fp)) != - ~crc32(~0, skb->data, fr_len)) { - if (stats->InvalidCRCCount < 5) - printk(KERN_WARNING PFX "dropping frame with " - "CRC error\n"); - stats->InvalidCRCCount++; - put_cpu(); - kfree_skb(skb); - return; - } - put_cpu(); - fc_exch_recv(lport, fp); -} - -/** - * bnx2fc_percpu_io_thread - thread per cpu for ios - * - * @arg: ptr to bnx2fc_percpu_info structure - */ -int bnx2fc_percpu_io_thread(void *arg) -{ - struct bnx2fc_percpu_s *p = arg; - struct bnx2fc_work *work, *tmp; - LIST_HEAD(work_list); - - set_user_nice(current, -20); - set_current_state(TASK_INTERRUPTIBLE); - while (!kthread_should_stop()) { - schedule(); - spin_lock_bh(&p->fp_work_lock); - while (!list_empty(&p->work_list)) { - list_splice_init(&p->work_list, &work_list); - spin_unlock_bh(&p->fp_work_lock); - - list_for_each_entry_safe(work, tmp, &work_list, list) { - list_del_init(&work->list); - bnx2fc_process_cq_compl(work->tgt, work->wqe); - kfree(work); - } - - spin_lock_bh(&p->fp_work_lock); - } - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&p->fp_work_lock); - } - __set_current_state(TASK_RUNNING); - - return 0; -} - -static struct fc_host_statistics *bnx2fc_get_host_stats(struct Scsi_Host *shost) -{ - struct fc_host_statistics *bnx2fc_stats; - struct fc_lport *lport = shost_priv(shost); - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct fcoe_statistics_params *fw_stats; - int rc = 0; - - fw_stats = (struct fcoe_statistics_params *)hba->stats_buffer; - if (!fw_stats) - return NULL; - - bnx2fc_stats = fc_get_host_stats(shost); - - init_completion(&hba->stat_req_done); - if (bnx2fc_send_stat_req(hba)) - return bnx2fc_stats; - rc = wait_for_completion_timeout(&hba->stat_req_done, (2 * HZ)); - if (!rc) { - BNX2FC_HBA_DBG(lport, "FW stat req timed out\n"); - return bnx2fc_stats; - } - bnx2fc_stats->invalid_crc_count += fw_stats->rx_stat2.fc_crc_cnt; - bnx2fc_stats->tx_frames += fw_stats->tx_stat.fcoe_tx_pkt_cnt; - bnx2fc_stats->tx_words += (fw_stats->tx_stat.fcoe_tx_byte_cnt) / 4; - bnx2fc_stats->rx_frames += fw_stats->rx_stat0.fcoe_rx_pkt_cnt; - bnx2fc_stats->rx_words += (fw_stats->rx_stat0.fcoe_rx_byte_cnt) / 4; - - bnx2fc_stats->dumped_frames = 0; - bnx2fc_stats->lip_count = 0; - bnx2fc_stats->nos_count = 0; - bnx2fc_stats->loss_of_sync_count = 0; - bnx2fc_stats->loss_of_signal_count = 0; - bnx2fc_stats->prim_seq_protocol_err_count = 0; - - return bnx2fc_stats; -} - -static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev) -{ - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_interface *interface = port->priv; - struct Scsi_Host *shost = lport->host; - int rc = 0; - - shost->max_cmd_len = BNX2FC_MAX_CMD_LEN; - shost->max_lun = BNX2FC_MAX_LUN; - shost->max_id = BNX2FC_MAX_FCP_TGT; - shost->max_channel = 0; - if (lport->vport) - shost->transportt = bnx2fc_vport_xport_template; - else - shost->transportt = bnx2fc_transport_template; - - /* Add the new host to SCSI-ml */ - rc = scsi_add_host(lport->host, dev); - if (rc) { - printk(KERN_ERR PFX "Error on scsi_add_host\n"); - return rc; - } - if (!lport->vport) - fc_host_max_npiv_vports(lport->host) = USHRT_MAX; - sprintf(fc_host_symbolic_name(lport->host), "%s v%s over %s", - BNX2FC_NAME, BNX2FC_VERSION, - interface->netdev->name); - - return 0; -} - -static void bnx2fc_link_speed_update(struct fc_lport *lport) -{ - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_interface *interface = port->priv; - struct net_device *netdev = interface->netdev; - struct ethtool_cmd ecmd; - - if (!__ethtool_get_settings(netdev, &ecmd)) { - lport->link_supported_speeds &= - ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); - if (ecmd.supported & (SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full)) - lport->link_supported_speeds |= FC_PORTSPEED_1GBIT; - if (ecmd.supported & SUPPORTED_10000baseT_Full) - lport->link_supported_speeds |= FC_PORTSPEED_10GBIT; - - switch (ethtool_cmd_speed(&ecmd)) { - case SPEED_1000: - lport->link_speed = FC_PORTSPEED_1GBIT; - break; - case SPEED_2500: - lport->link_speed = FC_PORTSPEED_2GBIT; - break; - case SPEED_10000: - lport->link_speed = FC_PORTSPEED_10GBIT; - break; - } - } -} -static int bnx2fc_link_ok(struct fc_lport *lport) -{ - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct net_device *dev = hba->phys_dev; - int rc = 0; - - if ((dev->flags & IFF_UP) && netif_carrier_ok(dev)) - clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); - else { - set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); - rc = -1; - } - return rc; -} - -/** - * bnx2fc_get_link_state - get network link state - * - * @hba: adapter instance pointer - * - * updates adapter structure flag based on netdev state - */ -void bnx2fc_get_link_state(struct bnx2fc_hba *hba) -{ - if (test_bit(__LINK_STATE_NOCARRIER, &hba->phys_dev->state)) - set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); - else - clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); -} - -static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev) -{ - struct bnx2fc_hba *hba; - struct bnx2fc_interface *interface; - struct fcoe_port *port; - u64 wwnn, wwpn; - - port = lport_priv(lport); - interface = port->priv; - hba = interface->hba; - - /* require support for get_pauseparam ethtool op. */ - if (!hba->phys_dev->ethtool_ops || - !hba->phys_dev->ethtool_ops->get_pauseparam) - return -EOPNOTSUPP; - - if (fc_set_mfs(lport, BNX2FC_MFS)) - return -EINVAL; - - skb_queue_head_init(&port->fcoe_pending_queue); - port->fcoe_pending_queue_active = 0; - setup_timer(&port->timer, fcoe_queue_timer, (unsigned long) lport); - - bnx2fc_link_speed_update(lport); - - if (!lport->vport) { - if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) - wwnn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, - 1, 0); - BNX2FC_HBA_DBG(lport, "WWNN = 0x%llx\n", wwnn); - fc_set_wwnn(lport, wwnn); - - if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) - wwpn = fcoe_wwn_from_mac(interface->ctlr.ctl_src_addr, - 2, 0); - - BNX2FC_HBA_DBG(lport, "WWPN = 0x%llx\n", wwpn); - fc_set_wwpn(lport, wwpn); - } - - return 0; -} - -static void bnx2fc_destroy_timer(unsigned long data) -{ - struct bnx2fc_hba *hba = (struct bnx2fc_hba *)data; - - printk(KERN_ERR PFX "ERROR:bnx2fc_destroy_timer - " - "Destroy compl not received!!\n"); - set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); - wake_up_interruptible(&hba->destroy_wait); -} - -/** - * bnx2fc_indicate_netevent - Generic netdev event handler - * - * @context: adapter structure pointer - * @event: event type - * @vlan_id: vlan id - associated vlan id with this event - * - * Handles NETDEV_UP, NETDEV_DOWN, NETDEV_GOING_DOWN,NETDEV_CHANGE and - * NETDEV_CHANGE_MTU events. Handle NETDEV_UNREGISTER only for vlans. - */ -static void bnx2fc_indicate_netevent(void *context, unsigned long event, - u16 vlan_id) -{ - struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; - struct fc_lport *lport; - struct fc_lport *vport; - struct bnx2fc_interface *interface, *tmp; - int wait_for_upload = 0; - u32 link_possible = 1; - - if (vlan_id != 0 && event != NETDEV_UNREGISTER) - return; - - switch (event) { - case NETDEV_UP: - if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) - printk(KERN_ERR "indicate_netevent: "\ - "hba is not UP!!\n"); - break; - - case NETDEV_DOWN: - clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); - clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); - link_possible = 0; - break; - - case NETDEV_GOING_DOWN: - set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); - link_possible = 0; - break; - - case NETDEV_CHANGE: - break; - - case NETDEV_UNREGISTER: - if (!vlan_id) - return; - mutex_lock(&bnx2fc_dev_lock); - list_for_each_entry_safe(interface, tmp, &if_list, list) { - if (interface->hba == hba && - interface->vlan_id == (vlan_id & VLAN_VID_MASK)) - __bnx2fc_destroy(interface); - } - mutex_unlock(&bnx2fc_dev_lock); - return; - - default: - printk(KERN_ERR PFX "Unkonwn netevent %ld", event); - return; - } - - mutex_lock(&bnx2fc_dev_lock); - list_for_each_entry(interface, &if_list, list) { - - if (interface->hba != hba) - continue; - - lport = interface->ctlr.lp; - BNX2FC_HBA_DBG(lport, "netevent handler - event=%s %ld\n", - interface->netdev->name, event); - - bnx2fc_link_speed_update(lport); - - if (link_possible && !bnx2fc_link_ok(lport)) { - /* Reset max recv frame size to default */ - fc_set_mfs(lport, BNX2FC_MFS); - /* - * ctlr link up will only be handled during - * enable to avoid sending discovery solicitation - * on a stale vlan - */ - if (interface->enabled) - fcoe_ctlr_link_up(&interface->ctlr); - } else if (fcoe_ctlr_link_down(&interface->ctlr)) { - mutex_lock(&lport->lp_mutex); - list_for_each_entry(vport, &lport->vports, list) - fc_host_port_type(vport->host) = - FC_PORTTYPE_UNKNOWN; - mutex_unlock(&lport->lp_mutex); - fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; - per_cpu_ptr(lport->dev_stats, - get_cpu())->LinkFailureCount++; - put_cpu(); - fcoe_clean_pending_queue(lport); - wait_for_upload = 1; - } - } - mutex_unlock(&bnx2fc_dev_lock); - - if (wait_for_upload) { - clear_bit(ADAPTER_STATE_READY, &hba->adapter_state); - init_waitqueue_head(&hba->shutdown_wait); - BNX2FC_MISC_DBG("indicate_netevent " - "num_ofld_sess = %d\n", - hba->num_ofld_sess); - hba->wait_for_link_down = 1; - wait_event_interruptible(hba->shutdown_wait, - (hba->num_ofld_sess == 0)); - BNX2FC_MISC_DBG("wakeup - num_ofld_sess = %d\n", - hba->num_ofld_sess); - hba->wait_for_link_down = 0; - - if (signal_pending(current)) - flush_signals(current); - } -} - -static int bnx2fc_libfc_config(struct fc_lport *lport) -{ - - /* Set the function pointers set by bnx2fc driver */ - memcpy(&lport->tt, &bnx2fc_libfc_fcn_templ, - sizeof(struct libfc_function_template)); - fc_elsct_init(lport); - fc_exch_init(lport); - fc_rport_init(lport); - fc_disc_init(lport); - return 0; -} - -static int bnx2fc_em_config(struct fc_lport *lport) -{ - int max_xid; - - if (nr_cpu_ids <= 2) - max_xid = FCOE_XIDS_PER_CPU; - else - max_xid = FCOE_MAX_XID; - if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, FCOE_MIN_XID, - max_xid, NULL)) { - printk(KERN_ERR PFX "em_config:fc_exch_mgr_alloc failed\n"); - return -ENOMEM; - } - - return 0; -} - -static int bnx2fc_lport_config(struct fc_lport *lport) -{ - lport->link_up = 0; - lport->qfull = 0; - lport->max_retry_count = BNX2FC_MAX_RETRY_CNT; - lport->max_rport_retry_count = BNX2FC_MAX_RPORT_RETRY_CNT; - lport->e_d_tov = 2 * 1000; - lport->r_a_tov = 10 * 1000; - - lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | - FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); - lport->does_npiv = 1; - - memset(&lport->rnid_gen, 0, sizeof(struct fc_els_rnid_gen)); - lport->rnid_gen.rnid_atype = BNX2FC_RNID_HBA; - - /* alloc stats structure */ - if (fc_lport_init_stats(lport)) - return -ENOMEM; - - /* Finish fc_lport configuration */ - fc_lport_config(lport); - - return 0; -} - -/** - * bnx2fc_fip_recv - handle a received FIP frame. - * - * @skb: the received skb - * @dev: associated &net_device - * @ptype: the &packet_type structure which was used to register this handler. - * @orig_dev: original receive &net_device, in case @ dev is a bond. - * - * Returns: 0 for success - */ -static int bnx2fc_fip_recv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *ptype, - struct net_device *orig_dev) -{ - struct bnx2fc_interface *interface; - interface = container_of(ptype, struct bnx2fc_interface, - fip_packet_type); - fcoe_ctlr_recv(&interface->ctlr, skb); - return 0; -} - -/** - * bnx2fc_update_src_mac - Update Ethernet MAC filters. - * - * @fip: FCoE controller. - * @old: Unicast MAC address to delete if the MAC is non-zero. - * @new: Unicast MAC address to add. - * - * Remove any previously-set unicast MAC filter. - * Add secondary FCoE MAC address filter for our OUI. - */ -static void bnx2fc_update_src_mac(struct fc_lport *lport, u8 *addr) -{ - struct fcoe_port *port = lport_priv(lport); - - memcpy(port->data_src_addr, addr, ETH_ALEN); -} - -/** - * bnx2fc_get_src_mac - return the ethernet source address for an lport - * - * @lport: libfc port - */ -static u8 *bnx2fc_get_src_mac(struct fc_lport *lport) -{ - struct fcoe_port *port; - - port = (struct fcoe_port *)lport_priv(lport); - return port->data_src_addr; -} - -/** - * bnx2fc_fip_send - send an Ethernet-encapsulated FIP frame. - * - * @fip: FCoE controller. - * @skb: FIP Packet. - */ -static void bnx2fc_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - skb->dev = bnx2fc_from_ctlr(fip)->netdev; - dev_queue_xmit(skb); -} - -static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled) -{ - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_lport *n_port = shost_priv(shost); - struct fcoe_port *port = lport_priv(n_port); - struct bnx2fc_interface *interface = port->priv; - struct net_device *netdev = interface->netdev; - struct fc_lport *vn_port; - int rc; - char buf[32]; - - rc = fcoe_validate_vport_create(vport); - if (rc) { - fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); - printk(KERN_ERR PFX "Failed to create vport, " - "WWPN (0x%s) already exists\n", - buf); - return rc; - } - - if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) { - printk(KERN_ERR PFX "vn ports cannot be created on" - "this interface\n"); - return -EIO; - } - rtnl_lock(); - mutex_lock(&bnx2fc_dev_lock); - vn_port = bnx2fc_if_create(interface, &vport->dev, 1); - mutex_unlock(&bnx2fc_dev_lock); - rtnl_unlock(); - - if (IS_ERR(vn_port)) { - printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n", - netdev->name); - return -EIO; - } - - if (disabled) { - fc_vport_set_state(vport, FC_VPORT_DISABLED); - } else { - vn_port->boot_time = jiffies; - fc_lport_init(vn_port); - fc_fabric_login(vn_port); - fc_vport_setlink(vn_port); - } - return 0; -} - -static void bnx2fc_free_vport(struct bnx2fc_hba *hba, struct fc_lport *lport) -{ - struct bnx2fc_lport *blport, *tmp; - - spin_lock_bh(&hba->hba_lock); - list_for_each_entry_safe(blport, tmp, &hba->vports, list) { - if (blport->lport == lport) { - list_del(&blport->list); - kfree(blport); - } - } - spin_unlock_bh(&hba->hba_lock); -} - -static int bnx2fc_vport_destroy(struct fc_vport *vport) -{ - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_lport *n_port = shost_priv(shost); - struct fc_lport *vn_port = vport->dd_data; - struct fcoe_port *port = lport_priv(vn_port); - struct bnx2fc_interface *interface = port->priv; - struct fc_lport *v_port; - bool found = false; - - mutex_lock(&n_port->lp_mutex); - list_for_each_entry(v_port, &n_port->vports, list) - if (v_port->vport == vport) { - found = true; - break; - } - - if (!found) { - mutex_unlock(&n_port->lp_mutex); - return -ENOENT; - } - list_del(&vn_port->list); - mutex_unlock(&n_port->lp_mutex); - bnx2fc_free_vport(interface->hba, port->lport); - bnx2fc_port_shutdown(port->lport); - bnx2fc_interface_put(interface); - queue_work(bnx2fc_wq, &port->destroy_work); - return 0; -} - -static int bnx2fc_vport_disable(struct fc_vport *vport, bool disable) -{ - struct fc_lport *lport = vport->dd_data; - - if (disable) { - fc_vport_set_state(vport, FC_VPORT_DISABLED); - fc_fabric_logoff(lport); - } else { - lport->boot_time = jiffies; - fc_fabric_login(lport); - fc_vport_setlink(lport); - } - return 0; -} - - -static int bnx2fc_interface_setup(struct bnx2fc_interface *interface) -{ - struct net_device *netdev = interface->netdev; - struct net_device *physdev = interface->hba->phys_dev; - struct netdev_hw_addr *ha; - int sel_san_mac = 0; - - /* setup Source MAC Address */ - rcu_read_lock(); - for_each_dev_addr(physdev, ha) { - BNX2FC_MISC_DBG("net_config: ha->type = %d, fip_mac = ", - ha->type); - printk(KERN_INFO "%2x:%2x:%2x:%2x:%2x:%2x\n", ha->addr[0], - ha->addr[1], ha->addr[2], ha->addr[3], - ha->addr[4], ha->addr[5]); - - if ((ha->type == NETDEV_HW_ADDR_T_SAN) && - (is_valid_ether_addr(ha->addr))) { - memcpy(interface->ctlr.ctl_src_addr, ha->addr, - ETH_ALEN); - sel_san_mac = 1; - BNX2FC_MISC_DBG("Found SAN MAC\n"); - } - } - rcu_read_unlock(); - - if (!sel_san_mac) - return -ENODEV; - - interface->fip_packet_type.func = bnx2fc_fip_recv; - interface->fip_packet_type.type = htons(ETH_P_FIP); - interface->fip_packet_type.dev = netdev; - dev_add_pack(&interface->fip_packet_type); - - interface->fcoe_packet_type.func = bnx2fc_rcv; - interface->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); - interface->fcoe_packet_type.dev = netdev; - dev_add_pack(&interface->fcoe_packet_type); - - return 0; -} - -static int bnx2fc_attach_transport(void) -{ - bnx2fc_transport_template = - fc_attach_transport(&bnx2fc_transport_function); - - if (bnx2fc_transport_template == NULL) { - printk(KERN_ERR PFX "Failed to attach FC transport\n"); - return -ENODEV; - } - - bnx2fc_vport_xport_template = - fc_attach_transport(&bnx2fc_vport_xport_function); - if (bnx2fc_vport_xport_template == NULL) { - printk(KERN_ERR PFX - "Failed to attach FC transport for vport\n"); - fc_release_transport(bnx2fc_transport_template); - bnx2fc_transport_template = NULL; - return -ENODEV; - } - return 0; -} -static void bnx2fc_release_transport(void) -{ - fc_release_transport(bnx2fc_transport_template); - fc_release_transport(bnx2fc_vport_xport_template); - bnx2fc_transport_template = NULL; - bnx2fc_vport_xport_template = NULL; -} - -static void bnx2fc_interface_release(struct kref *kref) -{ - struct bnx2fc_interface *interface; - struct net_device *netdev; - - interface = container_of(kref, struct bnx2fc_interface, kref); - BNX2FC_MISC_DBG("Interface is being released\n"); - - netdev = interface->netdev; - - /* tear-down FIP controller */ - if (test_and_clear_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags)) - fcoe_ctlr_destroy(&interface->ctlr); - - kfree(interface); - - dev_put(netdev); - module_put(THIS_MODULE); -} - -static inline void bnx2fc_interface_get(struct bnx2fc_interface *interface) -{ - kref_get(&interface->kref); -} - -static inline void bnx2fc_interface_put(struct bnx2fc_interface *interface) -{ - kref_put(&interface->kref, bnx2fc_interface_release); -} -static void bnx2fc_hba_destroy(struct bnx2fc_hba *hba) -{ - /* Free the command manager */ - if (hba->cmd_mgr) { - bnx2fc_cmd_mgr_free(hba->cmd_mgr); - hba->cmd_mgr = NULL; - } - kfree(hba->tgt_ofld_list); - bnx2fc_unbind_pcidev(hba); - kfree(hba); -} - -/** - * bnx2fc_hba_create - create a new bnx2fc hba - * - * @cnic: pointer to cnic device - * - * Creates a new FCoE hba on the given device. - * - */ -static struct bnx2fc_hba *bnx2fc_hba_create(struct cnic_dev *cnic) -{ - struct bnx2fc_hba *hba; - int rc; - - hba = kzalloc(sizeof(*hba), GFP_KERNEL); - if (!hba) { - printk(KERN_ERR PFX "Unable to allocate hba structure\n"); - return NULL; - } - spin_lock_init(&hba->hba_lock); - mutex_init(&hba->hba_mutex); - - hba->cnic = cnic; - rc = bnx2fc_bind_pcidev(hba); - if (rc) { - printk(KERN_ERR PFX "create_adapter: bind error\n"); - goto bind_err; - } - hba->phys_dev = cnic->netdev; - hba->next_conn_id = 0; - - hba->tgt_ofld_list = - kzalloc(sizeof(struct bnx2fc_rport *) * BNX2FC_NUM_MAX_SESS, - GFP_KERNEL); - if (!hba->tgt_ofld_list) { - printk(KERN_ERR PFX "Unable to allocate tgt offload list\n"); - goto tgtofld_err; - } - - hba->num_ofld_sess = 0; - - hba->cmd_mgr = bnx2fc_cmd_mgr_alloc(hba, BNX2FC_MIN_XID, - BNX2FC_MAX_XID); - if (!hba->cmd_mgr) { - printk(KERN_ERR PFX "em_config:bnx2fc_cmd_mgr_alloc failed\n"); - goto cmgr_err; - } - - init_waitqueue_head(&hba->shutdown_wait); - init_waitqueue_head(&hba->destroy_wait); - INIT_LIST_HEAD(&hba->vports); - - return hba; - -cmgr_err: - kfree(hba->tgt_ofld_list); -tgtofld_err: - bnx2fc_unbind_pcidev(hba); -bind_err: - kfree(hba); - return NULL; -} - -struct bnx2fc_interface *bnx2fc_interface_create(struct bnx2fc_hba *hba, - struct net_device *netdev, - enum fip_state fip_mode) -{ - struct bnx2fc_interface *interface; - int rc = 0; - - interface = kzalloc(sizeof(*interface), GFP_KERNEL); - if (!interface) { - printk(KERN_ERR PFX "Unable to allocate interface structure\n"); - return NULL; - } - dev_hold(netdev); - kref_init(&interface->kref); - interface->hba = hba; - interface->netdev = netdev; - - /* Initialize FIP */ - fcoe_ctlr_init(&interface->ctlr, fip_mode); - interface->ctlr.send = bnx2fc_fip_send; - interface->ctlr.update_mac = bnx2fc_update_src_mac; - interface->ctlr.get_src_addr = bnx2fc_get_src_mac; - set_bit(BNX2FC_CTLR_INIT_DONE, &interface->if_flags); - - rc = bnx2fc_interface_setup(interface); - if (!rc) - return interface; - - fcoe_ctlr_destroy(&interface->ctlr); - dev_put(netdev); - kfree(interface); - return NULL; -} - -/** - * bnx2fc_if_create - Create FCoE instance on a given interface - * - * @interface: FCoE interface to create a local port on - * @parent: Device pointer to be the parent in sysfs for the SCSI host - * @npiv: Indicates if the port is vport or not - * - * Creates a fc_lport instance and a Scsi_Host instance and configure them. - * - * Returns: Allocated fc_lport or an error pointer - */ -static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface, - struct device *parent, int npiv) -{ - struct fc_lport *lport, *n_port; - struct fcoe_port *port; - struct Scsi_Host *shost; - struct fc_vport *vport = dev_to_vport(parent); - struct bnx2fc_lport *blport; - struct bnx2fc_hba *hba; - int rc = 0; - - blport = kzalloc(sizeof(struct bnx2fc_lport), GFP_KERNEL); - if (!blport) { - BNX2FC_HBA_DBG(interface->ctlr.lp, "Unable to alloc blport\n"); - return NULL; - } - - /* Allocate Scsi_Host structure */ - if (!npiv) - lport = libfc_host_alloc(&bnx2fc_shost_template, sizeof(*port)); - else - lport = libfc_vport_create(vport, sizeof(*port)); - - if (!lport) { - printk(KERN_ERR PFX "could not allocate scsi host structure\n"); - goto free_blport; - } - shost = lport->host; - port = lport_priv(lport); - port->lport = lport; - port->priv = interface; - INIT_WORK(&port->destroy_work, bnx2fc_destroy_work); - - /* Configure fcoe_port */ - rc = bnx2fc_lport_config(lport); - if (rc) - goto lp_config_err; - - if (npiv) { - printk(KERN_ERR PFX "Setting vport names, 0x%llX 0x%llX\n", - vport->node_name, vport->port_name); - fc_set_wwnn(lport, vport->node_name); - fc_set_wwpn(lport, vport->port_name); - } - /* Configure netdev and networking properties of the lport */ - rc = bnx2fc_net_config(lport, interface->netdev); - if (rc) { - printk(KERN_ERR PFX "Error on bnx2fc_net_config\n"); - goto lp_config_err; - } - - rc = bnx2fc_shost_config(lport, parent); - if (rc) { - printk(KERN_ERR PFX "Couldnt configure shost for %s\n", - interface->netdev->name); - goto lp_config_err; - } - - /* Initialize the libfc library */ - rc = bnx2fc_libfc_config(lport); - if (rc) { - printk(KERN_ERR PFX "Couldnt configure libfc\n"); - goto shost_err; - } - fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; - - /* Allocate exchange manager */ - if (!npiv) - rc = bnx2fc_em_config(lport); - else { - shost = vport_to_shost(vport); - n_port = shost_priv(shost); - rc = fc_exch_mgr_list_clone(n_port, lport); - } - - if (rc) { - printk(KERN_ERR PFX "Error on bnx2fc_em_config\n"); - goto shost_err; - } - - bnx2fc_interface_get(interface); - - hba = interface->hba; - spin_lock_bh(&hba->hba_lock); - blport->lport = lport; - list_add_tail(&blport->list, &hba->vports); - spin_unlock_bh(&hba->hba_lock); - - return lport; - -shost_err: - scsi_remove_host(shost); -lp_config_err: - scsi_host_put(lport->host); -free_blport: - kfree(blport); - return NULL; -} - -static void bnx2fc_net_cleanup(struct bnx2fc_interface *interface) -{ - /* Dont listen for Ethernet packets anymore */ - __dev_remove_pack(&interface->fcoe_packet_type); - __dev_remove_pack(&interface->fip_packet_type); - synchronize_net(); -} - -static void bnx2fc_interface_cleanup(struct bnx2fc_interface *interface) -{ - struct fc_lport *lport = interface->ctlr.lp; - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_hba *hba = interface->hba; - - /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); - - /* Free existing transmit skbs */ - fcoe_clean_pending_queue(lport); - - bnx2fc_net_cleanup(interface); - - bnx2fc_free_vport(hba, lport); -} - -static void bnx2fc_if_destroy(struct fc_lport *lport) -{ - - /* Free queued packets for the receive thread */ - bnx2fc_clean_rx_queue(lport); - - /* Detach from scsi-ml */ - fc_remove_host(lport->host); - scsi_remove_host(lport->host); - - /* - * Note that only the physical lport will have the exchange manager. - * for vports, this function is NOP - */ - fc_exch_mgr_free(lport); - - /* Free memory used by statistical counters */ - fc_lport_free_stats(lport); - - /* Release Scsi_Host */ - scsi_host_put(lport->host); -} - -static void __bnx2fc_destroy(struct bnx2fc_interface *interface) -{ - struct fc_lport *lport = interface->ctlr.lp; - struct fcoe_port *port = lport_priv(lport); - - bnx2fc_interface_cleanup(interface); - bnx2fc_stop(interface); - list_del(&interface->list); - bnx2fc_interface_put(interface); - queue_work(bnx2fc_wq, &port->destroy_work); -} - -/** - * bnx2fc_destroy - Destroy a bnx2fc FCoE interface - * - * @buffer: The name of the Ethernet interface to be destroyed - * @kp: The associated kernel parameter - * - * Called from sysfs. - * - * Returns: 0 for success - */ -static int bnx2fc_destroy(struct net_device *netdev) -{ - struct bnx2fc_interface *interface = NULL; - struct workqueue_struct *timer_work_queue; - int rc = 0; - - rtnl_lock(); - mutex_lock(&bnx2fc_dev_lock); - - interface = bnx2fc_interface_lookup(netdev); - if (!interface || !interface->ctlr.lp) { - rc = -ENODEV; - printk(KERN_ERR PFX "bnx2fc_destroy: interface or lport not found\n"); - goto netdev_err; - } - - timer_work_queue = interface->timer_work_queue; - __bnx2fc_destroy(interface); - destroy_workqueue(timer_work_queue); - -netdev_err: - mutex_unlock(&bnx2fc_dev_lock); - rtnl_unlock(); - return rc; -} - -static void bnx2fc_destroy_work(struct work_struct *work) -{ - struct fcoe_port *port; - struct fc_lport *lport; - - port = container_of(work, struct fcoe_port, destroy_work); - lport = port->lport; - - BNX2FC_HBA_DBG(lport, "Entered bnx2fc_destroy_work\n"); - - bnx2fc_if_destroy(lport); -} - -static void bnx2fc_unbind_adapter_devices(struct bnx2fc_hba *hba) -{ - bnx2fc_free_fw_resc(hba); - bnx2fc_free_task_ctx(hba); -} - -/** - * bnx2fc_bind_adapter_devices - binds bnx2fc adapter with the associated - * pci structure - * - * @hba: Adapter instance - */ -static int bnx2fc_bind_adapter_devices(struct bnx2fc_hba *hba) -{ - if (bnx2fc_setup_task_ctx(hba)) - goto mem_err; - - if (bnx2fc_setup_fw_resc(hba)) - goto mem_err; - - return 0; -mem_err: - bnx2fc_unbind_adapter_devices(hba); - return -ENOMEM; -} - -static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba) -{ - struct cnic_dev *cnic; - - if (!hba->cnic) { - printk(KERN_ERR PFX "cnic is NULL\n"); - return -ENODEV; - } - cnic = hba->cnic; - hba->pcidev = cnic->pcidev; - if (hba->pcidev) - pci_dev_get(hba->pcidev); - - return 0; -} - -static void bnx2fc_unbind_pcidev(struct bnx2fc_hba *hba) -{ - if (hba->pcidev) - pci_dev_put(hba->pcidev); - hba->pcidev = NULL; -} - - - -/** - * bnx2fc_ulp_start - cnic callback to initialize & start adapter instance - * - * @handle: transport handle pointing to adapter struture - * - * This function maps adapter structure to pcidev structure and initiates - * firmware handshake to enable/initialize on-chip FCoE components. - * This bnx2fc - cnic interface api callback is used after following - * conditions are met - - * a) underlying network interface is up (marked by event NETDEV_UP - * from netdev - * b) bnx2fc adatper structure is registered. - */ -static void bnx2fc_ulp_start(void *handle) -{ - struct bnx2fc_hba *hba = handle; - struct bnx2fc_interface *interface; - struct fc_lport *lport; - - mutex_lock(&bnx2fc_dev_lock); - - if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) - bnx2fc_fw_init(hba); - - BNX2FC_MISC_DBG("bnx2fc started.\n"); - - list_for_each_entry(interface, &if_list, list) { - if (interface->hba == hba) { - lport = interface->ctlr.lp; - /* Kick off Fabric discovery*/ - printk(KERN_ERR PFX "ulp_init: start discovery\n"); - lport->tt.frame_send = bnx2fc_xmit; - bnx2fc_start_disc(interface); - } - } - - mutex_unlock(&bnx2fc_dev_lock); -} - -static void bnx2fc_port_shutdown(struct fc_lport *lport) -{ - BNX2FC_MISC_DBG("Entered %s\n", __func__); - fc_fabric_logoff(lport); - fc_lport_destroy(lport); -} - -static void bnx2fc_stop(struct bnx2fc_interface *interface) -{ - struct fc_lport *lport; - struct fc_lport *vport; - - if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) - return; - - lport = interface->ctlr.lp; - bnx2fc_port_shutdown(lport); - - mutex_lock(&lport->lp_mutex); - list_for_each_entry(vport, &lport->vports, list) - fc_host_port_type(vport->host) = - FC_PORTTYPE_UNKNOWN; - mutex_unlock(&lport->lp_mutex); - fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN; - fcoe_ctlr_link_down(&interface->ctlr); - fcoe_clean_pending_queue(lport); -} - -static int bnx2fc_fw_init(struct bnx2fc_hba *hba) -{ -#define BNX2FC_INIT_POLL_TIME (1000 / HZ) - int rc = -1; - int i = HZ; - - rc = bnx2fc_bind_adapter_devices(hba); - if (rc) { - printk(KERN_ALERT PFX - "bnx2fc_bind_adapter_devices failed - rc = %d\n", rc); - goto err_out; - } - - rc = bnx2fc_send_fw_fcoe_init_msg(hba); - if (rc) { - printk(KERN_ALERT PFX - "bnx2fc_send_fw_fcoe_init_msg failed - rc = %d\n", rc); - goto err_unbind; - } - - /* - * Wait until the adapter init message is complete, and adapter - * state is UP. - */ - while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) - msleep(BNX2FC_INIT_POLL_TIME); - - if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) { - printk(KERN_ERR PFX "bnx2fc_start: %s failed to initialize. " - "Ignoring...\n", - hba->cnic->netdev->name); - rc = -1; - goto err_unbind; - } - - - set_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags); - return 0; - -err_unbind: - bnx2fc_unbind_adapter_devices(hba); -err_out: - return rc; -} - -static void bnx2fc_fw_destroy(struct bnx2fc_hba *hba) -{ - if (test_and_clear_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) { - if (bnx2fc_send_fw_fcoe_destroy_msg(hba) == 0) { - init_timer(&hba->destroy_timer); - hba->destroy_timer.expires = BNX2FC_FW_TIMEOUT + - jiffies; - hba->destroy_timer.function = bnx2fc_destroy_timer; - hba->destroy_timer.data = (unsigned long)hba; - add_timer(&hba->destroy_timer); - wait_event_interruptible(hba->destroy_wait, - test_bit(BNX2FC_FLAG_DESTROY_CMPL, - &hba->flags)); - clear_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); - /* This should never happen */ - if (signal_pending(current)) - flush_signals(current); - - del_timer_sync(&hba->destroy_timer); - } - bnx2fc_unbind_adapter_devices(hba); - } -} - -/** - * bnx2fc_ulp_stop - cnic callback to shutdown adapter instance - * - * @handle: transport handle pointing to adapter structure - * - * Driver checks if adapter is already in shutdown mode, if not start - * the shutdown process. - */ -static void bnx2fc_ulp_stop(void *handle) -{ - struct bnx2fc_hba *hba = handle; - struct bnx2fc_interface *interface; - - printk(KERN_ERR "ULP_STOP\n"); - - mutex_lock(&bnx2fc_dev_lock); - if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &hba->flags)) - goto exit; - list_for_each_entry(interface, &if_list, list) { - if (interface->hba == hba) - bnx2fc_stop(interface); - } - BUG_ON(hba->num_ofld_sess != 0); - - mutex_lock(&hba->hba_mutex); - clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); - clear_bit(ADAPTER_STATE_GOING_DOWN, - &hba->adapter_state); - - clear_bit(ADAPTER_STATE_READY, &hba->adapter_state); - mutex_unlock(&hba->hba_mutex); - - bnx2fc_fw_destroy(hba); -exit: - mutex_unlock(&bnx2fc_dev_lock); -} - -static void bnx2fc_start_disc(struct bnx2fc_interface *interface) -{ - struct fc_lport *lport; - int wait_cnt = 0; - - BNX2FC_MISC_DBG("Entered %s\n", __func__); - /* Kick off FIP/FLOGI */ - if (!test_bit(BNX2FC_FLAG_FW_INIT_DONE, &interface->hba->flags)) { - printk(KERN_ERR PFX "Init not done yet\n"); - return; - } - - lport = interface->ctlr.lp; - BNX2FC_HBA_DBG(lport, "calling fc_fabric_login\n"); - - if (!bnx2fc_link_ok(lport) && interface->enabled) { - BNX2FC_HBA_DBG(lport, "ctlr_link_up\n"); - fcoe_ctlr_link_up(&interface->ctlr); - fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; - set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); - } - - /* wait for the FCF to be selected before issuing FLOGI */ - while (!interface->ctlr.sel_fcf) { - msleep(250); - /* give up after 3 secs */ - if (++wait_cnt > 12) - break; - } - - /* Reset max receive frame size to default */ - if (fc_set_mfs(lport, BNX2FC_MFS)) - return; - - fc_lport_init(lport); - fc_fabric_login(lport); -} - - -/** - * bnx2fc_ulp_init - Initialize an adapter instance - * - * @dev : cnic device handle - * Called from cnic_register_driver() context to initialize all - * enumerated cnic devices. This routine allocates adapter structure - * and other device specific resources. - */ -static void bnx2fc_ulp_init(struct cnic_dev *dev) -{ - struct bnx2fc_hba *hba; - int rc = 0; - - BNX2FC_MISC_DBG("Entered %s\n", __func__); - /* bnx2fc works only when bnx2x is loaded */ - if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) || - (dev->max_fcoe_conn == 0)) { - printk(KERN_ERR PFX "bnx2fc FCoE not supported on %s," - " flags: %lx fcoe_conn: %d\n", - dev->netdev->name, dev->flags, dev->max_fcoe_conn); - return; - } - - hba = bnx2fc_hba_create(dev); - if (!hba) { - printk(KERN_ERR PFX "hba initialization failed\n"); - return; - } - - /* Add HBA to the adapter list */ - mutex_lock(&bnx2fc_dev_lock); - list_add_tail(&hba->list, &adapter_list); - adapter_count++; - mutex_unlock(&bnx2fc_dev_lock); - - clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic); - rc = dev->register_device(dev, CNIC_ULP_FCOE, - (void *) hba); - if (rc) - printk(KERN_ERR PFX "register_device failed, rc = %d\n", rc); - else - set_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic); -} - - -static int bnx2fc_disable(struct net_device *netdev) -{ - struct bnx2fc_interface *interface; - int rc = 0; - - rtnl_lock(); - mutex_lock(&bnx2fc_dev_lock); - - interface = bnx2fc_interface_lookup(netdev); - if (!interface || !interface->ctlr.lp) { - rc = -ENODEV; - printk(KERN_ERR PFX "bnx2fc_disable: interface or lport not found\n"); - } else { - interface->enabled = false; - fcoe_ctlr_link_down(&interface->ctlr); - fcoe_clean_pending_queue(interface->ctlr.lp); - } - - mutex_unlock(&bnx2fc_dev_lock); - rtnl_unlock(); - return rc; -} - - -static int bnx2fc_enable(struct net_device *netdev) -{ - struct bnx2fc_interface *interface; - int rc = 0; - - rtnl_lock(); - mutex_lock(&bnx2fc_dev_lock); - - interface = bnx2fc_interface_lookup(netdev); - if (!interface || !interface->ctlr.lp) { - rc = -ENODEV; - printk(KERN_ERR PFX "bnx2fc_enable: interface or lport not found\n"); - } else if (!bnx2fc_link_ok(interface->ctlr.lp)) { - fcoe_ctlr_link_up(&interface->ctlr); - interface->enabled = true; - } - - mutex_unlock(&bnx2fc_dev_lock); - rtnl_unlock(); - return rc; -} - -/** - * bnx2fc_create - Create bnx2fc FCoE interface - * - * @buffer: The name of Ethernet interface to create on - * @kp: The associated kernel param - * - * Called from sysfs. - * - * Returns: 0 for success - */ -static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode) -{ - struct bnx2fc_interface *interface; - struct bnx2fc_hba *hba; - struct net_device *phys_dev; - struct fc_lport *lport; - struct ethtool_drvinfo drvinfo; - int rc = 0; - int vlan_id; - - BNX2FC_MISC_DBG("Entered bnx2fc_create\n"); - if (fip_mode != FIP_MODE_FABRIC) { - printk(KERN_ERR "fip mode not FABRIC\n"); - return -EIO; - } - - rtnl_lock(); - - mutex_lock(&bnx2fc_dev_lock); - - if (!try_module_get(THIS_MODULE)) { - rc = -EINVAL; - goto mod_err; - } - - /* obtain physical netdev */ - if (netdev->priv_flags & IFF_802_1Q_VLAN) { - phys_dev = vlan_dev_real_dev(netdev); - vlan_id = vlan_dev_vlan_id(netdev); - } else { - printk(KERN_ERR PFX "Not a vlan device\n"); - rc = -EINVAL; - goto netdev_err; - } - /* verify if the physical device is a netxtreme2 device */ - if (phys_dev->ethtool_ops && phys_dev->ethtool_ops->get_drvinfo) { - memset(&drvinfo, 0, sizeof(drvinfo)); - phys_dev->ethtool_ops->get_drvinfo(phys_dev, &drvinfo); - if (strncmp(drvinfo.driver, "bnx2x", strlen("bnx2x"))) { - printk(KERN_ERR PFX "Not a netxtreme2 device\n"); - rc = -EINVAL; - goto netdev_err; - } - } else { - printk(KERN_ERR PFX "unable to obtain drv_info\n"); - rc = -EINVAL; - goto netdev_err; - } - - /* obtain interface and initialize rest of the structure */ - hba = bnx2fc_hba_lookup(phys_dev); - if (!hba) { - rc = -ENODEV; - printk(KERN_ERR PFX "bnx2fc_create: hba not found\n"); - goto netdev_err; - } - - if (bnx2fc_interface_lookup(netdev)) { - rc = -EEXIST; - goto netdev_err; - } - - interface = bnx2fc_interface_create(hba, netdev, fip_mode); - if (!interface) { - printk(KERN_ERR PFX "bnx2fc_interface_create failed\n"); - goto ifput_err; - } - - interface->vlan_id = vlan_id; - interface->vlan_enabled = 1; - - interface->timer_work_queue = - create_singlethread_workqueue("bnx2fc_timer_wq"); - if (!interface->timer_work_queue) { - printk(KERN_ERR PFX "ulp_init could not create timer_wq\n"); - rc = -EINVAL; - goto ifput_err; - } - - lport = bnx2fc_if_create(interface, &interface->hba->pcidev->dev, 0); - if (!lport) { - printk(KERN_ERR PFX "Failed to create interface (%s)\n", - netdev->name); - rc = -EINVAL; - goto if_create_err; - } - - /* Add interface to if_list */ - list_add_tail(&interface->list, &if_list); - - lport->boot_time = jiffies; - - /* Make this master N_port */ - interface->ctlr.lp = lport; - - if (!bnx2fc_link_ok(lport)) { - fcoe_ctlr_link_up(&interface->ctlr); - fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; - set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state); - } - - BNX2FC_HBA_DBG(lport, "create: START DISC\n"); - bnx2fc_start_disc(interface); - interface->enabled = true; - /* - * Release from kref_init in bnx2fc_interface_setup, on success - * lport should be holding a reference taken in bnx2fc_if_create - */ - bnx2fc_interface_put(interface); - /* put netdev that was held while calling dev_get_by_name */ - mutex_unlock(&bnx2fc_dev_lock); - rtnl_unlock(); - return 0; - -if_create_err: - destroy_workqueue(interface->timer_work_queue); -ifput_err: - bnx2fc_net_cleanup(interface); - bnx2fc_interface_put(interface); - goto mod_err; -netdev_err: - module_put(THIS_MODULE); -mod_err: - mutex_unlock(&bnx2fc_dev_lock); - rtnl_unlock(); - return rc; -} - -/** - * bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc hba instance - * - * @cnic: Pointer to cnic device instance - * - **/ -static struct bnx2fc_hba *bnx2fc_find_hba_for_cnic(struct cnic_dev *cnic) -{ - struct list_head *list; - struct list_head *temp; - struct bnx2fc_hba *hba; - - /* Called with bnx2fc_dev_lock held */ - list_for_each_safe(list, temp, &adapter_list) { - hba = (struct bnx2fc_hba *)list; - if (hba->cnic == cnic) - return hba; - } - return NULL; -} - -static struct bnx2fc_interface *bnx2fc_interface_lookup(struct net_device - *netdev) -{ - struct bnx2fc_interface *interface; - - /* Called with bnx2fc_dev_lock held */ - list_for_each_entry(interface, &if_list, list) { - if (interface->netdev == netdev) - return interface; - } - return NULL; -} - -static struct bnx2fc_hba *bnx2fc_hba_lookup(struct net_device - *phys_dev) -{ - struct bnx2fc_hba *hba; - - /* Called with bnx2fc_dev_lock held */ - list_for_each_entry(hba, &adapter_list, list) { - if (hba->phys_dev == phys_dev) - return hba; - } - printk(KERN_ERR PFX "adapter_lookup: hba NULL\n"); - return NULL; -} - -/** - * bnx2fc_ulp_exit - shuts down adapter instance and frees all resources - * - * @dev cnic device handle - */ -static void bnx2fc_ulp_exit(struct cnic_dev *dev) -{ - struct bnx2fc_hba *hba; - struct bnx2fc_interface *interface, *tmp; - - BNX2FC_MISC_DBG("Entered bnx2fc_ulp_exit\n"); - - if (!test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) { - printk(KERN_ERR PFX "bnx2fc port check: %s, flags: %lx\n", - dev->netdev->name, dev->flags); - return; - } - - mutex_lock(&bnx2fc_dev_lock); - hba = bnx2fc_find_hba_for_cnic(dev); - if (!hba) { - printk(KERN_ERR PFX "bnx2fc_ulp_exit: hba not found, dev 0%p\n", - dev); - mutex_unlock(&bnx2fc_dev_lock); - return; - } - - list_del_init(&hba->list); - adapter_count--; - - list_for_each_entry_safe(interface, tmp, &if_list, list) - /* destroy not called yet, move to quiesced list */ - if (interface->hba == hba) - __bnx2fc_destroy(interface); - mutex_unlock(&bnx2fc_dev_lock); - - bnx2fc_ulp_stop(hba); - /* unregister cnic device */ - if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic)) - hba->cnic->unregister_device(hba->cnic, CNIC_ULP_FCOE); - bnx2fc_hba_destroy(hba); -} - -/** - * bnx2fc_fcoe_reset - Resets the fcoe - * - * @shost: shost the reset is from - * - * Returns: always 0 - */ -static int bnx2fc_fcoe_reset(struct Scsi_Host *shost) -{ - struct fc_lport *lport = shost_priv(shost); - fc_lport_reset(lport); - return 0; -} - - -static bool bnx2fc_match(struct net_device *netdev) -{ - mutex_lock(&bnx2fc_dev_lock); - if (netdev->priv_flags & IFF_802_1Q_VLAN) { - struct net_device *phys_dev = vlan_dev_real_dev(netdev); - - if (bnx2fc_hba_lookup(phys_dev)) { - mutex_unlock(&bnx2fc_dev_lock); - return true; - } - } - mutex_unlock(&bnx2fc_dev_lock); - return false; -} - - -static struct fcoe_transport bnx2fc_transport = { - .name = {"bnx2fc"}, - .attached = false, - .list = LIST_HEAD_INIT(bnx2fc_transport.list), - .match = bnx2fc_match, - .create = bnx2fc_create, - .destroy = bnx2fc_destroy, - .enable = bnx2fc_enable, - .disable = bnx2fc_disable, -}; - -/** - * bnx2fc_percpu_thread_create - Create a receive thread for an - * online CPU - * - * @cpu: cpu index for the online cpu - */ -static void bnx2fc_percpu_thread_create(unsigned int cpu) -{ - struct bnx2fc_percpu_s *p; - struct task_struct *thread; - - p = &per_cpu(bnx2fc_percpu, cpu); - - thread = kthread_create(bnx2fc_percpu_io_thread, - (void *)p, - "bnx2fc_thread/%d", cpu); - /* bind thread to the cpu */ - if (likely(!IS_ERR(thread))) { - kthread_bind(thread, cpu); - p->iothread = thread; - wake_up_process(thread); - } -} - -static void bnx2fc_percpu_thread_destroy(unsigned int cpu) -{ - struct bnx2fc_percpu_s *p; - struct task_struct *thread; - struct bnx2fc_work *work, *tmp; - - BNX2FC_MISC_DBG("destroying io thread for CPU %d\n", cpu); - - /* Prevent any new work from being queued for this CPU */ - p = &per_cpu(bnx2fc_percpu, cpu); - spin_lock_bh(&p->fp_work_lock); - thread = p->iothread; - p->iothread = NULL; - - - /* Free all work in the list */ - list_for_each_entry_safe(work, tmp, &p->work_list, list) { - list_del_init(&work->list); - bnx2fc_process_cq_compl(work->tgt, work->wqe); - kfree(work); - } - - spin_unlock_bh(&p->fp_work_lock); - - if (thread) - kthread_stop(thread); -} - -/** - * bnx2fc_cpu_callback - Handler for CPU hotplug events - * - * @nfb: The callback data block - * @action: The event triggering the callback - * @hcpu: The index of the CPU that the event is for - * - * This creates or destroys per-CPU data for fcoe - * - * Returns NOTIFY_OK always. - */ -static int bnx2fc_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - printk(PFX "CPU %x online: Create Rx thread\n", cpu); - bnx2fc_percpu_thread_create(cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - printk(PFX "CPU %x offline: Remove Rx thread\n", cpu); - bnx2fc_percpu_thread_destroy(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - -/** - * bnx2fc_mod_init - module init entry point - * - * Initialize driver wide global data structures, and register - * with cnic module - **/ -static int __init bnx2fc_mod_init(void) -{ - struct fcoe_percpu_s *bg; - struct task_struct *l2_thread; - int rc = 0; - unsigned int cpu = 0; - struct bnx2fc_percpu_s *p; - - printk(KERN_INFO PFX "%s", version); - - /* register as a fcoe transport */ - rc = fcoe_transport_attach(&bnx2fc_transport); - if (rc) { - printk(KERN_ERR "failed to register an fcoe transport, check " - "if libfcoe is loaded\n"); - goto out; - } - - INIT_LIST_HEAD(&adapter_list); - INIT_LIST_HEAD(&if_list); - mutex_init(&bnx2fc_dev_lock); - adapter_count = 0; - - /* Attach FC transport template */ - rc = bnx2fc_attach_transport(); - if (rc) - goto detach_ft; - - bnx2fc_wq = alloc_workqueue("bnx2fc", 0, 0); - if (!bnx2fc_wq) { - rc = -ENOMEM; - goto release_bt; - } - - bg = &bnx2fc_global; - skb_queue_head_init(&bg->fcoe_rx_list); - l2_thread = kthread_create(bnx2fc_l2_rcv_thread, - (void *)bg, - "bnx2fc_l2_thread"); - if (IS_ERR(l2_thread)) { - rc = PTR_ERR(l2_thread); - goto free_wq; - } - wake_up_process(l2_thread); - spin_lock_bh(&bg->fcoe_rx_list.lock); - bg->thread = l2_thread; - spin_unlock_bh(&bg->fcoe_rx_list.lock); - - for_each_possible_cpu(cpu) { - p = &per_cpu(bnx2fc_percpu, cpu); - INIT_LIST_HEAD(&p->work_list); - spin_lock_init(&p->fp_work_lock); - } - - for_each_online_cpu(cpu) { - bnx2fc_percpu_thread_create(cpu); - } - - /* Initialize per CPU interrupt thread */ - register_hotcpu_notifier(&bnx2fc_cpu_notifier); - - cnic_register_driver(CNIC_ULP_FCOE, &bnx2fc_cnic_cb); - - return 0; - -free_wq: - destroy_workqueue(bnx2fc_wq); -release_bt: - bnx2fc_release_transport(); -detach_ft: - fcoe_transport_detach(&bnx2fc_transport); -out: - return rc; -} - -static void __exit bnx2fc_mod_exit(void) -{ - LIST_HEAD(to_be_deleted); - struct bnx2fc_hba *hba, *next; - struct fcoe_percpu_s *bg; - struct task_struct *l2_thread; - struct sk_buff *skb; - unsigned int cpu = 0; - - /* - * NOTE: Since cnic calls register_driver routine rtnl_lock, - * it will have higher precedence than bnx2fc_dev_lock. - * unregister_device() cannot be called with bnx2fc_dev_lock - * held. - */ - mutex_lock(&bnx2fc_dev_lock); - list_splice(&adapter_list, &to_be_deleted); - INIT_LIST_HEAD(&adapter_list); - adapter_count = 0; - mutex_unlock(&bnx2fc_dev_lock); - - /* Unregister with cnic */ - list_for_each_entry_safe(hba, next, &to_be_deleted, list) { - list_del_init(&hba->list); - printk(KERN_ERR PFX "MOD_EXIT:destroy hba = 0x%p\n", - hba); - bnx2fc_ulp_stop(hba); - /* unregister cnic device */ - if (test_and_clear_bit(BNX2FC_CNIC_REGISTERED, - &hba->reg_with_cnic)) - hba->cnic->unregister_device(hba->cnic, - CNIC_ULP_FCOE); - bnx2fc_hba_destroy(hba); - } - cnic_unregister_driver(CNIC_ULP_FCOE); - - /* Destroy global thread */ - bg = &bnx2fc_global; - spin_lock_bh(&bg->fcoe_rx_list.lock); - l2_thread = bg->thread; - bg->thread = NULL; - while ((skb = __skb_dequeue(&bg->fcoe_rx_list)) != NULL) - kfree_skb(skb); - - spin_unlock_bh(&bg->fcoe_rx_list.lock); - - if (l2_thread) - kthread_stop(l2_thread); - - unregister_hotcpu_notifier(&bnx2fc_cpu_notifier); - - /* Destroy per cpu threads */ - for_each_online_cpu(cpu) { - bnx2fc_percpu_thread_destroy(cpu); - } - - destroy_workqueue(bnx2fc_wq); - /* - * detach from scsi transport - * must happen after all destroys are done - */ - bnx2fc_release_transport(); - - /* detach from fcoe transport */ - fcoe_transport_detach(&bnx2fc_transport); -} - -module_init(bnx2fc_mod_init); -module_exit(bnx2fc_mod_exit); - -static struct fc_function_template bnx2fc_transport_function = { - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_active_fc4s = 1, - .show_host_maxframe_size = 1, - - .show_host_port_id = 1, - .show_host_supported_speeds = 1, - .get_host_speed = fc_get_host_speed, - .show_host_speed = 1, - .show_host_port_type = 1, - .get_host_port_state = fc_get_host_port_state, - .show_host_port_state = 1, - .show_host_symbolic_name = 1, - - .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) + - sizeof(struct bnx2fc_rport)), - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - - .show_host_fabric_name = 1, - .show_starget_node_name = 1, - .show_starget_port_name = 1, - .show_starget_port_id = 1, - .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - .get_fc_host_stats = bnx2fc_get_host_stats, - - .issue_fc_host_lip = bnx2fc_fcoe_reset, - - .terminate_rport_io = fc_rport_terminate_io, - - .vport_create = bnx2fc_vport_create, - .vport_delete = bnx2fc_vport_destroy, - .vport_disable = bnx2fc_vport_disable, - .bsg_request = fc_lport_bsg_request, -}; - -static struct fc_function_template bnx2fc_vport_xport_function = { - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_active_fc4s = 1, - .show_host_maxframe_size = 1, - - .show_host_port_id = 1, - .show_host_supported_speeds = 1, - .get_host_speed = fc_get_host_speed, - .show_host_speed = 1, - .show_host_port_type = 1, - .get_host_port_state = fc_get_host_port_state, - .show_host_port_state = 1, - .show_host_symbolic_name = 1, - - .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) + - sizeof(struct bnx2fc_rport)), - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - - .show_host_fabric_name = 1, - .show_starget_node_name = 1, - .show_starget_port_name = 1, - .show_starget_port_id = 1, - .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - .get_fc_host_stats = fc_get_host_stats, - .issue_fc_host_lip = bnx2fc_fcoe_reset, - .terminate_rport_io = fc_rport_terminate_io, - .bsg_request = fc_lport_bsg_request, -}; - -/** - * scsi_host_template structure used while registering with SCSI-ml - */ -static struct scsi_host_template bnx2fc_shost_template = { - .module = THIS_MODULE, - .name = "Broadcom Offload FCoE Initiator", - .queuecommand = bnx2fc_queuecommand, - .eh_abort_handler = bnx2fc_eh_abort, /* abts */ - .eh_device_reset_handler = bnx2fc_eh_device_reset, /* lun reset */ - .eh_target_reset_handler = bnx2fc_eh_target_reset, /* tgt reset */ - .eh_host_reset_handler = fc_eh_host_reset, - .slave_alloc = fc_slave_alloc, - .change_queue_depth = fc_change_queue_depth, - .change_queue_type = fc_change_queue_type, - .this_id = -1, - .cmd_per_lun = 3, - .can_queue = BNX2FC_CAN_QUEUE, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = BNX2FC_MAX_BDS_PER_CMD, - .max_sectors = 512, -}; - -static struct libfc_function_template bnx2fc_libfc_fcn_templ = { - .frame_send = bnx2fc_xmit, - .elsct_send = bnx2fc_elsct_send, - .fcp_abort_io = bnx2fc_abort_io, - .fcp_cleanup = bnx2fc_cleanup, - .get_lesb = bnx2fc_get_lesb, - .rport_event_callback = bnx2fc_rport_event_handler, -}; - -/** - * bnx2fc_cnic_cb - global template of bnx2fc - cnic driver interface - * structure carrying callback function pointers - */ -static struct cnic_ulp_ops bnx2fc_cnic_cb = { - .owner = THIS_MODULE, - .cnic_init = bnx2fc_ulp_init, - .cnic_exit = bnx2fc_ulp_exit, - .cnic_start = bnx2fc_ulp_start, - .cnic_stop = bnx2fc_ulp_stop, - .indicate_kcqes = bnx2fc_indicate_kcqe, - .indicate_netevent = bnx2fc_indicate_netevent, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_hwi.c b/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_hwi.c deleted file mode 100644 index afd57096..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_hwi.c +++ /dev/null @@ -1,2189 +0,0 @@ -/* bnx2fc_hwi.c: Broadcom NetXtreme II Linux FCoE offload driver. - * This file contains the code that low level functions that interact - * with 57712 FCoE firmware. - * - * Copyright (c) 2008 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) - */ - -#include "bnx2fc.h" - -DECLARE_PER_CPU(struct bnx2fc_percpu_s, bnx2fc_percpu); - -static void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba, - struct fcoe_kcqe *new_cqe_kcqe); -static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, - struct fcoe_kcqe *ofld_kcqe); -static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, - struct fcoe_kcqe *ofld_kcqe); -static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code); -static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba, - struct fcoe_kcqe *destroy_kcqe); - -int bnx2fc_send_stat_req(struct bnx2fc_hba *hba) -{ - struct fcoe_kwqe_stat stat_req; - struct kwqe *kwqe_arr[2]; - int num_kwqes = 1; - int rc = 0; - - memset(&stat_req, 0x00, sizeof(struct fcoe_kwqe_stat)); - stat_req.hdr.op_code = FCOE_KWQE_OPCODE_STAT; - stat_req.hdr.flags = - (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - stat_req.stat_params_addr_lo = (u32) hba->stats_buf_dma; - stat_req.stat_params_addr_hi = (u32) ((u64)hba->stats_buf_dma >> 32); - - kwqe_arr[0] = (struct kwqe *) &stat_req; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - - return rc; -} - -/** - * bnx2fc_send_fw_fcoe_init_msg - initiates initial handshake with FCoE f/w - * - * @hba: adapter structure pointer - * - * Send down FCoE firmware init KWQEs which initiates the initial handshake - * with the f/w. - * - */ -int bnx2fc_send_fw_fcoe_init_msg(struct bnx2fc_hba *hba) -{ - struct fcoe_kwqe_init1 fcoe_init1; - struct fcoe_kwqe_init2 fcoe_init2; - struct fcoe_kwqe_init3 fcoe_init3; - struct kwqe *kwqe_arr[3]; - int num_kwqes = 3; - int rc = 0; - - if (!hba->cnic) { - printk(KERN_ERR PFX "hba->cnic NULL during fcoe fw init\n"); - return -ENODEV; - } - - /* fill init1 KWQE */ - memset(&fcoe_init1, 0x00, sizeof(struct fcoe_kwqe_init1)); - fcoe_init1.hdr.op_code = FCOE_KWQE_OPCODE_INIT1; - fcoe_init1.hdr.flags = (FCOE_KWQE_LAYER_CODE << - FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - fcoe_init1.num_tasks = BNX2FC_MAX_TASKS; - fcoe_init1.sq_num_wqes = BNX2FC_SQ_WQES_MAX; - fcoe_init1.rq_num_wqes = BNX2FC_RQ_WQES_MAX; - fcoe_init1.rq_buffer_log_size = BNX2FC_RQ_BUF_LOG_SZ; - fcoe_init1.cq_num_wqes = BNX2FC_CQ_WQES_MAX; - fcoe_init1.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma; - fcoe_init1.dummy_buffer_addr_hi = (u32) ((u64)hba->dummy_buf_dma >> 32); - fcoe_init1.task_list_pbl_addr_lo = (u32) hba->task_ctx_bd_dma; - fcoe_init1.task_list_pbl_addr_hi = - (u32) ((u64) hba->task_ctx_bd_dma >> 32); - fcoe_init1.mtu = BNX2FC_MINI_JUMBO_MTU; - - fcoe_init1.flags = (PAGE_SHIFT << - FCOE_KWQE_INIT1_LOG_PAGE_SIZE_SHIFT); - - fcoe_init1.num_sessions_log = BNX2FC_NUM_MAX_SESS_LOG; - - /* fill init2 KWQE */ - memset(&fcoe_init2, 0x00, sizeof(struct fcoe_kwqe_init2)); - fcoe_init2.hdr.op_code = FCOE_KWQE_OPCODE_INIT2; - fcoe_init2.hdr.flags = (FCOE_KWQE_LAYER_CODE << - FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - fcoe_init2.hsi_major_version = FCOE_HSI_MAJOR_VERSION; - fcoe_init2.hsi_minor_version = FCOE_HSI_MINOR_VERSION; - - - fcoe_init2.hash_tbl_pbl_addr_lo = (u32) hba->hash_tbl_pbl_dma; - fcoe_init2.hash_tbl_pbl_addr_hi = (u32) - ((u64) hba->hash_tbl_pbl_dma >> 32); - - fcoe_init2.t2_hash_tbl_addr_lo = (u32) hba->t2_hash_tbl_dma; - fcoe_init2.t2_hash_tbl_addr_hi = (u32) - ((u64) hba->t2_hash_tbl_dma >> 32); - - fcoe_init2.t2_ptr_hash_tbl_addr_lo = (u32) hba->t2_hash_tbl_ptr_dma; - fcoe_init2.t2_ptr_hash_tbl_addr_hi = (u32) - ((u64) hba->t2_hash_tbl_ptr_dma >> 32); - - fcoe_init2.free_list_count = BNX2FC_NUM_MAX_SESS; - - /* fill init3 KWQE */ - memset(&fcoe_init3, 0x00, sizeof(struct fcoe_kwqe_init3)); - fcoe_init3.hdr.op_code = FCOE_KWQE_OPCODE_INIT3; - fcoe_init3.hdr.flags = (FCOE_KWQE_LAYER_CODE << - FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - fcoe_init3.error_bit_map_lo = 0xffffffff; - fcoe_init3.error_bit_map_hi = 0xffffffff; - - fcoe_init3.perf_config = 1; - - kwqe_arr[0] = (struct kwqe *) &fcoe_init1; - kwqe_arr[1] = (struct kwqe *) &fcoe_init2; - kwqe_arr[2] = (struct kwqe *) &fcoe_init3; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - - return rc; -} -int bnx2fc_send_fw_fcoe_destroy_msg(struct bnx2fc_hba *hba) -{ - struct fcoe_kwqe_destroy fcoe_destroy; - struct kwqe *kwqe_arr[2]; - int num_kwqes = 1; - int rc = -1; - - /* fill destroy KWQE */ - memset(&fcoe_destroy, 0x00, sizeof(struct fcoe_kwqe_destroy)); - fcoe_destroy.hdr.op_code = FCOE_KWQE_OPCODE_DESTROY; - fcoe_destroy.hdr.flags = (FCOE_KWQE_LAYER_CODE << - FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - kwqe_arr[0] = (struct kwqe *) &fcoe_destroy; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - return rc; -} - -/** - * bnx2fc_send_session_ofld_req - initiates FCoE Session offload process - * - * @port: port structure pointer - * @tgt: bnx2fc_rport structure pointer - */ -int bnx2fc_send_session_ofld_req(struct fcoe_port *port, - struct bnx2fc_rport *tgt) -{ - struct fc_lport *lport = port->lport; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct kwqe *kwqe_arr[4]; - struct fcoe_kwqe_conn_offload1 ofld_req1; - struct fcoe_kwqe_conn_offload2 ofld_req2; - struct fcoe_kwqe_conn_offload3 ofld_req3; - struct fcoe_kwqe_conn_offload4 ofld_req4; - struct fc_rport_priv *rdata = tgt->rdata; - struct fc_rport *rport = tgt->rport; - int num_kwqes = 4; - u32 port_id; - int rc = 0; - u16 conn_id; - - /* Initialize offload request 1 structure */ - memset(&ofld_req1, 0x00, sizeof(struct fcoe_kwqe_conn_offload1)); - - ofld_req1.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN1; - ofld_req1.hdr.flags = - (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - - conn_id = (u16)tgt->fcoe_conn_id; - ofld_req1.fcoe_conn_id = conn_id; - - - ofld_req1.sq_addr_lo = (u32) tgt->sq_dma; - ofld_req1.sq_addr_hi = (u32)((u64) tgt->sq_dma >> 32); - - ofld_req1.rq_pbl_addr_lo = (u32) tgt->rq_pbl_dma; - ofld_req1.rq_pbl_addr_hi = (u32)((u64) tgt->rq_pbl_dma >> 32); - - ofld_req1.rq_first_pbe_addr_lo = (u32) tgt->rq_dma; - ofld_req1.rq_first_pbe_addr_hi = - (u32)((u64) tgt->rq_dma >> 32); - - ofld_req1.rq_prod = 0x8000; - - /* Initialize offload request 2 structure */ - memset(&ofld_req2, 0x00, sizeof(struct fcoe_kwqe_conn_offload2)); - - ofld_req2.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN2; - ofld_req2.hdr.flags = - (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - ofld_req2.tx_max_fc_pay_len = rdata->maxframe_size; - - ofld_req2.cq_addr_lo = (u32) tgt->cq_dma; - ofld_req2.cq_addr_hi = (u32)((u64)tgt->cq_dma >> 32); - - ofld_req2.xferq_addr_lo = (u32) tgt->xferq_dma; - ofld_req2.xferq_addr_hi = (u32)((u64)tgt->xferq_dma >> 32); - - ofld_req2.conn_db_addr_lo = (u32)tgt->conn_db_dma; - ofld_req2.conn_db_addr_hi = (u32)((u64)tgt->conn_db_dma >> 32); - - /* Initialize offload request 3 structure */ - memset(&ofld_req3, 0x00, sizeof(struct fcoe_kwqe_conn_offload3)); - - ofld_req3.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN3; - ofld_req3.hdr.flags = - (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - ofld_req3.vlan_tag = interface->vlan_id << - FCOE_KWQE_CONN_OFFLOAD3_VLAN_ID_SHIFT; - ofld_req3.vlan_tag |= 3 << FCOE_KWQE_CONN_OFFLOAD3_PRIORITY_SHIFT; - - port_id = fc_host_port_id(lport->host); - if (port_id == 0) { - BNX2FC_HBA_DBG(lport, "ofld_req: port_id = 0, link down?\n"); - return -EINVAL; - } - - /* - * Store s_id of the initiator for further reference. This will - * be used during disable/destroy during linkdown processing as - * when the lport is reset, the port_id also is reset to 0 - */ - tgt->sid = port_id; - ofld_req3.s_id[0] = (port_id & 0x000000FF); - ofld_req3.s_id[1] = (port_id & 0x0000FF00) >> 8; - ofld_req3.s_id[2] = (port_id & 0x00FF0000) >> 16; - - port_id = rport->port_id; - ofld_req3.d_id[0] = (port_id & 0x000000FF); - ofld_req3.d_id[1] = (port_id & 0x0000FF00) >> 8; - ofld_req3.d_id[2] = (port_id & 0x00FF0000) >> 16; - - ofld_req3.tx_total_conc_seqs = rdata->max_seq; - - ofld_req3.tx_max_conc_seqs_c3 = rdata->max_seq; - ofld_req3.rx_max_fc_pay_len = lport->mfs; - - ofld_req3.rx_total_conc_seqs = BNX2FC_MAX_SEQS; - ofld_req3.rx_max_conc_seqs_c3 = BNX2FC_MAX_SEQS; - ofld_req3.rx_open_seqs_exch_c3 = 1; - - ofld_req3.confq_first_pbe_addr_lo = tgt->confq_dma; - ofld_req3.confq_first_pbe_addr_hi = (u32)((u64) tgt->confq_dma >> 32); - - /* set mul_n_port_ids supported flag to 0, until it is supported */ - ofld_req3.flags = 0; - /* - ofld_req3.flags |= (((lport->send_sp_features & FC_SP_FT_MNA) ? 1:0) << - FCOE_KWQE_CONN_OFFLOAD3_B_MUL_N_PORT_IDS_SHIFT); - */ - /* Info from PLOGI response */ - ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_EDTR) ? 1 : 0) << - FCOE_KWQE_CONN_OFFLOAD3_B_E_D_TOV_RES_SHIFT); - - ofld_req3.flags |= (((rdata->sp_features & FC_SP_FT_SEQC) ? 1 : 0) << - FCOE_KWQE_CONN_OFFLOAD3_B_CONT_INCR_SEQ_CNT_SHIFT); - - /* - * Info from PRLI response, this info is used for sequence level error - * recovery support - */ - if (tgt->dev_type == TYPE_TAPE) { - ofld_req3.flags |= 1 << - FCOE_KWQE_CONN_OFFLOAD3_B_CONF_REQ_SHIFT; - ofld_req3.flags |= (((rdata->flags & FC_RP_FLAGS_REC_SUPPORTED) - ? 1 : 0) << - FCOE_KWQE_CONN_OFFLOAD3_B_REC_VALID_SHIFT); - } - - /* vlan flag */ - ofld_req3.flags |= (interface->vlan_enabled << - FCOE_KWQE_CONN_OFFLOAD3_B_VLAN_FLAG_SHIFT); - - /* C2_VALID and ACK flags are not set as they are not suppported */ - - - /* Initialize offload request 4 structure */ - memset(&ofld_req4, 0x00, sizeof(struct fcoe_kwqe_conn_offload4)); - ofld_req4.hdr.op_code = FCOE_KWQE_OPCODE_OFFLOAD_CONN4; - ofld_req4.hdr.flags = - (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - ofld_req4.e_d_tov_timer_val = lport->e_d_tov / 20; - - - ofld_req4.src_mac_addr_lo[0] = port->data_src_addr[5]; - /* local mac */ - ofld_req4.src_mac_addr_lo[1] = port->data_src_addr[4]; - ofld_req4.src_mac_addr_mid[0] = port->data_src_addr[3]; - ofld_req4.src_mac_addr_mid[1] = port->data_src_addr[2]; - ofld_req4.src_mac_addr_hi[0] = port->data_src_addr[1]; - ofld_req4.src_mac_addr_hi[1] = port->data_src_addr[0]; - ofld_req4.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; - /* fcf mac */ - ofld_req4.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; - ofld_req4.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; - ofld_req4.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; - ofld_req4.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; - ofld_req4.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; - - ofld_req4.lcq_addr_lo = (u32) tgt->lcq_dma; - ofld_req4.lcq_addr_hi = (u32)((u64) tgt->lcq_dma >> 32); - - ofld_req4.confq_pbl_base_addr_lo = (u32) tgt->confq_pbl_dma; - ofld_req4.confq_pbl_base_addr_hi = - (u32)((u64) tgt->confq_pbl_dma >> 32); - - kwqe_arr[0] = (struct kwqe *) &ofld_req1; - kwqe_arr[1] = (struct kwqe *) &ofld_req2; - kwqe_arr[2] = (struct kwqe *) &ofld_req3; - kwqe_arr[3] = (struct kwqe *) &ofld_req4; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - - return rc; -} - -/** - * bnx2fc_send_session_enable_req - initiates FCoE Session enablement - * - * @port: port structure pointer - * @tgt: bnx2fc_rport structure pointer - */ -static int bnx2fc_send_session_enable_req(struct fcoe_port *port, - struct bnx2fc_rport *tgt) -{ - struct kwqe *kwqe_arr[2]; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct fcoe_kwqe_conn_enable_disable enbl_req; - struct fc_lport *lport = port->lport; - struct fc_rport *rport = tgt->rport; - int num_kwqes = 1; - int rc = 0; - u32 port_id; - - memset(&enbl_req, 0x00, - sizeof(struct fcoe_kwqe_conn_enable_disable)); - enbl_req.hdr.op_code = FCOE_KWQE_OPCODE_ENABLE_CONN; - enbl_req.hdr.flags = - (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - enbl_req.src_mac_addr_lo[0] = port->data_src_addr[5]; - /* local mac */ - enbl_req.src_mac_addr_lo[1] = port->data_src_addr[4]; - enbl_req.src_mac_addr_mid[0] = port->data_src_addr[3]; - enbl_req.src_mac_addr_mid[1] = port->data_src_addr[2]; - enbl_req.src_mac_addr_hi[0] = port->data_src_addr[1]; - enbl_req.src_mac_addr_hi[1] = port->data_src_addr[0]; - memcpy(tgt->src_addr, port->data_src_addr, ETH_ALEN); - - enbl_req.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; - enbl_req.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; - enbl_req.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; - enbl_req.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; - enbl_req.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; - enbl_req.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; - - port_id = fc_host_port_id(lport->host); - if (port_id != tgt->sid) { - printk(KERN_ERR PFX "WARN: enable_req port_id = 0x%x," - "sid = 0x%x\n", port_id, tgt->sid); - port_id = tgt->sid; - } - enbl_req.s_id[0] = (port_id & 0x000000FF); - enbl_req.s_id[1] = (port_id & 0x0000FF00) >> 8; - enbl_req.s_id[2] = (port_id & 0x00FF0000) >> 16; - - port_id = rport->port_id; - enbl_req.d_id[0] = (port_id & 0x000000FF); - enbl_req.d_id[1] = (port_id & 0x0000FF00) >> 8; - enbl_req.d_id[2] = (port_id & 0x00FF0000) >> 16; - enbl_req.vlan_tag = interface->vlan_id << - FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT; - enbl_req.vlan_tag |= 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT; - enbl_req.vlan_flag = interface->vlan_enabled; - enbl_req.context_id = tgt->context_id; - enbl_req.conn_id = tgt->fcoe_conn_id; - - kwqe_arr[0] = (struct kwqe *) &enbl_req; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - return rc; -} - -/** - * bnx2fc_send_session_disable_req - initiates FCoE Session disable - * - * @port: port structure pointer - * @tgt: bnx2fc_rport structure pointer - */ -int bnx2fc_send_session_disable_req(struct fcoe_port *port, - struct bnx2fc_rport *tgt) -{ - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct fcoe_kwqe_conn_enable_disable disable_req; - struct kwqe *kwqe_arr[2]; - struct fc_rport *rport = tgt->rport; - int num_kwqes = 1; - int rc = 0; - u32 port_id; - - memset(&disable_req, 0x00, - sizeof(struct fcoe_kwqe_conn_enable_disable)); - disable_req.hdr.op_code = FCOE_KWQE_OPCODE_DISABLE_CONN; - disable_req.hdr.flags = - (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - disable_req.src_mac_addr_lo[0] = tgt->src_addr[5]; - disable_req.src_mac_addr_lo[1] = tgt->src_addr[4]; - disable_req.src_mac_addr_mid[0] = tgt->src_addr[3]; - disable_req.src_mac_addr_mid[1] = tgt->src_addr[2]; - disable_req.src_mac_addr_hi[0] = tgt->src_addr[1]; - disable_req.src_mac_addr_hi[1] = tgt->src_addr[0]; - - disable_req.dst_mac_addr_lo[0] = interface->ctlr.dest_addr[5]; - disable_req.dst_mac_addr_lo[1] = interface->ctlr.dest_addr[4]; - disable_req.dst_mac_addr_mid[0] = interface->ctlr.dest_addr[3]; - disable_req.dst_mac_addr_mid[1] = interface->ctlr.dest_addr[2]; - disable_req.dst_mac_addr_hi[0] = interface->ctlr.dest_addr[1]; - disable_req.dst_mac_addr_hi[1] = interface->ctlr.dest_addr[0]; - - port_id = tgt->sid; - disable_req.s_id[0] = (port_id & 0x000000FF); - disable_req.s_id[1] = (port_id & 0x0000FF00) >> 8; - disable_req.s_id[2] = (port_id & 0x00FF0000) >> 16; - - - port_id = rport->port_id; - disable_req.d_id[0] = (port_id & 0x000000FF); - disable_req.d_id[1] = (port_id & 0x0000FF00) >> 8; - disable_req.d_id[2] = (port_id & 0x00FF0000) >> 16; - disable_req.context_id = tgt->context_id; - disable_req.conn_id = tgt->fcoe_conn_id; - disable_req.vlan_tag = interface->vlan_id << - FCOE_KWQE_CONN_ENABLE_DISABLE_VLAN_ID_SHIFT; - disable_req.vlan_tag |= - 3 << FCOE_KWQE_CONN_ENABLE_DISABLE_PRIORITY_SHIFT; - disable_req.vlan_flag = interface->vlan_enabled; - - kwqe_arr[0] = (struct kwqe *) &disable_req; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - - return rc; -} - -/** - * bnx2fc_send_session_destroy_req - initiates FCoE Session destroy - * - * @port: port structure pointer - * @tgt: bnx2fc_rport structure pointer - */ -int bnx2fc_send_session_destroy_req(struct bnx2fc_hba *hba, - struct bnx2fc_rport *tgt) -{ - struct fcoe_kwqe_conn_destroy destroy_req; - struct kwqe *kwqe_arr[2]; - int num_kwqes = 1; - int rc = 0; - - memset(&destroy_req, 0x00, sizeof(struct fcoe_kwqe_conn_destroy)); - destroy_req.hdr.op_code = FCOE_KWQE_OPCODE_DESTROY_CONN; - destroy_req.hdr.flags = - (FCOE_KWQE_LAYER_CODE << FCOE_KWQE_HEADER_LAYER_CODE_SHIFT); - - destroy_req.context_id = tgt->context_id; - destroy_req.conn_id = tgt->fcoe_conn_id; - - kwqe_arr[0] = (struct kwqe *) &destroy_req; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - - return rc; -} - -static bool is_valid_lport(struct bnx2fc_hba *hba, struct fc_lport *lport) -{ - struct bnx2fc_lport *blport; - - spin_lock_bh(&hba->hba_lock); - list_for_each_entry(blport, &hba->vports, list) { - if (blport->lport == lport) { - spin_unlock_bh(&hba->hba_lock); - return true; - } - } - spin_unlock_bh(&hba->hba_lock); - return false; - -} - - -static void bnx2fc_unsol_els_work(struct work_struct *work) -{ - struct bnx2fc_unsol_els *unsol_els; - struct fc_lport *lport; - struct bnx2fc_hba *hba; - struct fc_frame *fp; - - unsol_els = container_of(work, struct bnx2fc_unsol_els, unsol_els_work); - lport = unsol_els->lport; - fp = unsol_els->fp; - hba = unsol_els->hba; - if (is_valid_lport(hba, lport)) - fc_exch_recv(lport, fp); - kfree(unsol_els); -} - -void bnx2fc_process_l2_frame_compl(struct bnx2fc_rport *tgt, - unsigned char *buf, - u32 frame_len, u16 l2_oxid) -{ - struct fcoe_port *port = tgt->port; - struct fc_lport *lport = port->lport; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_unsol_els *unsol_els; - struct fc_frame_header *fh; - struct fc_frame *fp; - struct sk_buff *skb; - u32 payload_len; - u32 crc; - u8 op; - - - unsol_els = kzalloc(sizeof(*unsol_els), GFP_ATOMIC); - if (!unsol_els) { - BNX2FC_TGT_DBG(tgt, "Unable to allocate unsol_work\n"); - return; - } - - BNX2FC_TGT_DBG(tgt, "l2_frame_compl l2_oxid = 0x%x, frame_len = %d\n", - l2_oxid, frame_len); - - payload_len = frame_len - sizeof(struct fc_frame_header); - - fp = fc_frame_alloc(lport, payload_len); - if (!fp) { - printk(KERN_ERR PFX "fc_frame_alloc failure\n"); - kfree(unsol_els); - return; - } - - fh = (struct fc_frame_header *) fc_frame_header_get(fp); - /* Copy FC Frame header and payload into the frame */ - memcpy(fh, buf, frame_len); - - if (l2_oxid != FC_XID_UNKNOWN) - fh->fh_ox_id = htons(l2_oxid); - - skb = fp_skb(fp); - - if ((fh->fh_r_ctl == FC_RCTL_ELS_REQ) || - (fh->fh_r_ctl == FC_RCTL_ELS_REP)) { - - if (fh->fh_type == FC_TYPE_ELS) { - op = fc_frame_payload_op(fp); - if ((op == ELS_TEST) || (op == ELS_ESTC) || - (op == ELS_FAN) || (op == ELS_CSU)) { - /* - * No need to reply for these - * ELS requests - */ - printk(KERN_ERR PFX "dropping ELS 0x%x\n", op); - kfree_skb(skb); - kfree(unsol_els); - return; - } - } - crc = fcoe_fc_crc(fp); - fc_frame_init(fp); - fr_dev(fp) = lport; - fr_sof(fp) = FC_SOF_I3; - fr_eof(fp) = FC_EOF_T; - fr_crc(fp) = cpu_to_le32(~crc); - unsol_els->lport = lport; - unsol_els->hba = interface->hba; - unsol_els->fp = fp; - INIT_WORK(&unsol_els->unsol_els_work, bnx2fc_unsol_els_work); - queue_work(bnx2fc_wq, &unsol_els->unsol_els_work); - } else { - BNX2FC_HBA_DBG(lport, "fh_r_ctl = 0x%x\n", fh->fh_r_ctl); - kfree_skb(skb); - kfree(unsol_els); - } -} - -static void bnx2fc_process_unsol_compl(struct bnx2fc_rport *tgt, u16 wqe) -{ - u8 num_rq; - struct fcoe_err_report_entry *err_entry; - unsigned char *rq_data; - unsigned char *buf = NULL, *buf1; - int i; - u16 xid; - u32 frame_len, len; - struct bnx2fc_cmd *io_req = NULL; - struct fcoe_task_ctx_entry *task, *task_page; - struct bnx2fc_interface *interface = tgt->port->priv; - struct bnx2fc_hba *hba = interface->hba; - int task_idx, index; - int rc = 0; - u64 err_warn_bit_map; - u8 err_warn = 0xff; - - - BNX2FC_TGT_DBG(tgt, "Entered UNSOL COMPLETION wqe = 0x%x\n", wqe); - switch (wqe & FCOE_UNSOLICITED_CQE_SUBTYPE) { - case FCOE_UNSOLICITED_FRAME_CQE_TYPE: - frame_len = (wqe & FCOE_UNSOLICITED_CQE_PKT_LEN) >> - FCOE_UNSOLICITED_CQE_PKT_LEN_SHIFT; - - num_rq = (frame_len + BNX2FC_RQ_BUF_SZ - 1) / BNX2FC_RQ_BUF_SZ; - - spin_lock_bh(&tgt->tgt_lock); - rq_data = (unsigned char *)bnx2fc_get_next_rqe(tgt, num_rq); - spin_unlock_bh(&tgt->tgt_lock); - - if (rq_data) { - buf = rq_data; - } else { - buf1 = buf = kmalloc((num_rq * BNX2FC_RQ_BUF_SZ), - GFP_ATOMIC); - - if (!buf1) { - BNX2FC_TGT_DBG(tgt, "Memory alloc failure\n"); - break; - } - - for (i = 0; i < num_rq; i++) { - spin_lock_bh(&tgt->tgt_lock); - rq_data = (unsigned char *) - bnx2fc_get_next_rqe(tgt, 1); - spin_unlock_bh(&tgt->tgt_lock); - len = BNX2FC_RQ_BUF_SZ; - memcpy(buf1, rq_data, len); - buf1 += len; - } - } - bnx2fc_process_l2_frame_compl(tgt, buf, frame_len, - FC_XID_UNKNOWN); - - if (buf != rq_data) - kfree(buf); - spin_lock_bh(&tgt->tgt_lock); - bnx2fc_return_rqe(tgt, num_rq); - spin_unlock_bh(&tgt->tgt_lock); - break; - - case FCOE_ERROR_DETECTION_CQE_TYPE: - /* - * In case of error reporting CQE a single RQ entry - * is consumed. - */ - spin_lock_bh(&tgt->tgt_lock); - num_rq = 1; - err_entry = (struct fcoe_err_report_entry *) - bnx2fc_get_next_rqe(tgt, 1); - xid = err_entry->fc_hdr.ox_id; - BNX2FC_TGT_DBG(tgt, "Unsol Error Frame OX_ID = 0x%x\n", xid); - BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x\n", - err_entry->data.err_warn_bitmap_hi, - err_entry->data.err_warn_bitmap_lo); - BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x\n", - err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); - - - if (xid > BNX2FC_MAX_XID) { - BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", - xid); - goto ret_err_rqe; - } - - task_idx = xid / BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - task_page = (struct fcoe_task_ctx_entry *) - hba->task_ctx[task_idx]; - task = &(task_page[index]); - - io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; - if (!io_req) - goto ret_err_rqe; - - if (io_req->cmd_type != BNX2FC_SCSI_CMD) { - printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); - goto ret_err_rqe; - } - - if (test_and_clear_bit(BNX2FC_FLAG_IO_CLEANUP, - &io_req->req_flags)) { - BNX2FC_IO_DBG(io_req, "unsol_err: cleanup in " - "progress.. ignore unsol err\n"); - goto ret_err_rqe; - } - - err_warn_bit_map = (u64) - ((u64)err_entry->data.err_warn_bitmap_hi << 32) | - (u64)err_entry->data.err_warn_bitmap_lo; - for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { - if (err_warn_bit_map & (u64)((u64)1 << i)) { - err_warn = i; - break; - } - } - - /* - * If ABTS is already in progress, and FW error is - * received after that, do not cancel the timeout_work - * and let the error recovery continue by explicitly - * logging out the target, when the ABTS eventually - * times out. - */ - if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { - printk(KERN_ERR PFX "err_warn: io_req (0x%x) already " - "in ABTS processing\n", xid); - goto ret_err_rqe; - } - BNX2FC_TGT_DBG(tgt, "err = 0x%x\n", err_warn); - if (tgt->dev_type != TYPE_TAPE) - goto skip_rec; - switch (err_warn) { - case FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION: - case FCOE_ERROR_CODE_DATA_OOO_RO: - case FCOE_ERROR_CODE_COMMON_INCORRECT_SEQ_CNT: - case FCOE_ERROR_CODE_DATA_SOFI3_SEQ_ACTIVE_SET: - case FCOE_ERROR_CODE_FCP_RSP_OPENED_SEQ: - case FCOE_ERROR_CODE_DATA_SOFN_SEQ_ACTIVE_RESET: - BNX2FC_TGT_DBG(tgt, "REC TOV popped for xid - 0x%x\n", - xid); - memset(&io_req->err_entry, 0, - sizeof(struct fcoe_err_report_entry)); - memcpy(&io_req->err_entry, err_entry, - sizeof(struct fcoe_err_report_entry)); - if (!test_bit(BNX2FC_FLAG_SRR_SENT, - &io_req->req_flags)) { - spin_unlock_bh(&tgt->tgt_lock); - rc = bnx2fc_send_rec(io_req); - spin_lock_bh(&tgt->tgt_lock); - - if (rc) - goto skip_rec; - } else - printk(KERN_ERR PFX "SRR in progress\n"); - goto ret_err_rqe; - break; - default: - break; - } - -skip_rec: - set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags); - /* - * Cancel the timeout_work, as we received IO - * completion with FW error. - */ - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, bnx2fc_cmd_release); - - rc = bnx2fc_initiate_abts(io_req); - if (rc != SUCCESS) { - printk(KERN_ERR PFX "err_warn: initiate_abts " - "failed xid = 0x%x. issue cleanup\n", - io_req->xid); - bnx2fc_initiate_cleanup(io_req); - } -ret_err_rqe: - bnx2fc_return_rqe(tgt, 1); - spin_unlock_bh(&tgt->tgt_lock); - break; - - case FCOE_WARNING_DETECTION_CQE_TYPE: - /* - *In case of warning reporting CQE a single RQ entry - * is consumes. - */ - spin_lock_bh(&tgt->tgt_lock); - num_rq = 1; - err_entry = (struct fcoe_err_report_entry *) - bnx2fc_get_next_rqe(tgt, 1); - xid = cpu_to_be16(err_entry->fc_hdr.ox_id); - BNX2FC_TGT_DBG(tgt, "Unsol Warning Frame OX_ID = 0x%x\n", xid); - BNX2FC_TGT_DBG(tgt, "err_warn_bitmap = %08x:%08x", - err_entry->data.err_warn_bitmap_hi, - err_entry->data.err_warn_bitmap_lo); - BNX2FC_TGT_DBG(tgt, "buf_offsets - tx = 0x%x, rx = 0x%x", - err_entry->data.tx_buf_off, err_entry->data.rx_buf_off); - - if (xid > BNX2FC_MAX_XID) { - BNX2FC_TGT_DBG(tgt, "xid(0x%x) out of FW range\n", xid); - goto ret_warn_rqe; - } - - err_warn_bit_map = (u64) - ((u64)err_entry->data.err_warn_bitmap_hi << 32) | - (u64)err_entry->data.err_warn_bitmap_lo; - for (i = 0; i < BNX2FC_NUM_ERR_BITS; i++) { - if (err_warn_bit_map & (u64) (1 << i)) { - err_warn = i; - break; - } - } - BNX2FC_TGT_DBG(tgt, "warn = 0x%x\n", err_warn); - - task_idx = xid / BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[task_idx]; - task = &(task_page[index]); - io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; - if (!io_req) - goto ret_warn_rqe; - - if (io_req->cmd_type != BNX2FC_SCSI_CMD) { - printk(KERN_ERR PFX "err_warn: Not a SCSI cmd\n"); - goto ret_warn_rqe; - } - - memset(&io_req->err_entry, 0, - sizeof(struct fcoe_err_report_entry)); - memcpy(&io_req->err_entry, err_entry, - sizeof(struct fcoe_err_report_entry)); - - if (err_warn == FCOE_ERROR_CODE_REC_TOV_TIMER_EXPIRATION) - /* REC_TOV is not a warning code */ - BUG_ON(1); - else - BNX2FC_TGT_DBG(tgt, "Unsolicited warning\n"); -ret_warn_rqe: - bnx2fc_return_rqe(tgt, 1); - spin_unlock_bh(&tgt->tgt_lock); - break; - - default: - printk(KERN_ERR PFX "Unsol Compl: Invalid CQE Subtype\n"); - break; - } -} - -void bnx2fc_process_cq_compl(struct bnx2fc_rport *tgt, u16 wqe) -{ - struct fcoe_task_ctx_entry *task; - struct fcoe_task_ctx_entry *task_page; - struct fcoe_port *port = tgt->port; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct bnx2fc_cmd *io_req; - int task_idx, index; - u16 xid; - u8 cmd_type; - u8 rx_state = 0; - u8 num_rq; - - spin_lock_bh(&tgt->tgt_lock); - xid = wqe & FCOE_PEND_WQ_CQE_TASK_ID; - if (xid >= BNX2FC_MAX_TASKS) { - printk(KERN_ERR PFX "ERROR:xid out of range\n"); - spin_unlock_bh(&tgt->tgt_lock); - return; - } - task_idx = xid / BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - task_page = (struct fcoe_task_ctx_entry *)hba->task_ctx[task_idx]; - task = &(task_page[index]); - - num_rq = ((task->rxwr_txrd.var_ctx.rx_flags & - FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE) >> - FCOE_TCE_RX_WR_TX_RD_VAR_NUM_RQ_WQE_SHIFT); - - io_req = (struct bnx2fc_cmd *)hba->cmd_mgr->cmds[xid]; - - if (io_req == NULL) { - printk(KERN_ERR PFX "ERROR? cq_compl - io_req is NULL\n"); - spin_unlock_bh(&tgt->tgt_lock); - return; - } - - /* Timestamp IO completion time */ - cmd_type = io_req->cmd_type; - - rx_state = ((task->rxwr_txrd.var_ctx.rx_flags & - FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE) >> - FCOE_TCE_RX_WR_TX_RD_VAR_RX_STATE_SHIFT); - - /* Process other IO completion types */ - switch (cmd_type) { - case BNX2FC_SCSI_CMD: - if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) { - bnx2fc_process_scsi_cmd_compl(io_req, task, num_rq); - spin_unlock_bh(&tgt->tgt_lock); - return; - } - - if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED) - bnx2fc_process_abts_compl(io_req, task, num_rq); - else if (rx_state == - FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED) - bnx2fc_process_cleanup_compl(io_req, task, num_rq); - else - printk(KERN_ERR PFX "Invalid rx state - %d\n", - rx_state); - break; - - case BNX2FC_TASK_MGMT_CMD: - BNX2FC_IO_DBG(io_req, "Processing TM complete\n"); - bnx2fc_process_tm_compl(io_req, task, num_rq); - break; - - case BNX2FC_ABTS: - /* - * ABTS request received by firmware. ABTS response - * will be delivered to the task belonging to the IO - * that was aborted - */ - BNX2FC_IO_DBG(io_req, "cq_compl- ABTS sent out by fw\n"); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - break; - - case BNX2FC_ELS: - if (rx_state == FCOE_TASK_RX_STATE_COMPLETED) - bnx2fc_process_els_compl(io_req, task, num_rq); - else if (rx_state == FCOE_TASK_RX_STATE_ABTS_COMPLETED) - bnx2fc_process_abts_compl(io_req, task, num_rq); - else if (rx_state == - FCOE_TASK_RX_STATE_EXCHANGE_CLEANUP_COMPLETED) - bnx2fc_process_cleanup_compl(io_req, task, num_rq); - else - printk(KERN_ERR PFX "Invalid rx state = %d\n", - rx_state); - break; - - case BNX2FC_CLEANUP: - BNX2FC_IO_DBG(io_req, "cq_compl- cleanup resp rcvd\n"); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - break; - - case BNX2FC_SEQ_CLEANUP: - BNX2FC_IO_DBG(io_req, "cq_compl(0x%x) - seq cleanup resp\n", - io_req->xid); - bnx2fc_process_seq_cleanup_compl(io_req, task, rx_state); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - break; - - default: - printk(KERN_ERR PFX "Invalid cmd_type %d\n", cmd_type); - break; - } - spin_unlock_bh(&tgt->tgt_lock); -} - -void bnx2fc_arm_cq(struct bnx2fc_rport *tgt) -{ - struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db; - u32 msg; - - wmb(); - rx_db->doorbell_cq_cons = tgt->cq_cons_idx | (tgt->cq_curr_toggle_bit << - FCOE_CQE_TOGGLE_BIT_SHIFT); - msg = *((u32 *)rx_db); - writel(cpu_to_le32(msg), tgt->ctx_base); - mmiowb(); - -} - -struct bnx2fc_work *bnx2fc_alloc_work(struct bnx2fc_rport *tgt, u16 wqe) -{ - struct bnx2fc_work *work; - work = kzalloc(sizeof(struct bnx2fc_work), GFP_ATOMIC); - if (!work) - return NULL; - - INIT_LIST_HEAD(&work->list); - work->tgt = tgt; - work->wqe = wqe; - return work; -} - -int bnx2fc_process_new_cqes(struct bnx2fc_rport *tgt) -{ - struct fcoe_cqe *cq; - u32 cq_cons; - struct fcoe_cqe *cqe; - u32 num_free_sqes = 0; - u32 num_cqes = 0; - u16 wqe; - - /* - * cq_lock is a low contention lock used to protect - * the CQ data structure from being freed up during - * the upload operation - */ - spin_lock_bh(&tgt->cq_lock); - - if (!tgt->cq) { - printk(KERN_ERR PFX "process_new_cqes: cq is NULL\n"); - spin_unlock_bh(&tgt->cq_lock); - return 0; - } - cq = tgt->cq; - cq_cons = tgt->cq_cons_idx; - cqe = &cq[cq_cons]; - - while (((wqe = cqe->wqe) & FCOE_CQE_TOGGLE_BIT) == - (tgt->cq_curr_toggle_bit << - FCOE_CQE_TOGGLE_BIT_SHIFT)) { - - /* new entry on the cq */ - if (wqe & FCOE_CQE_CQE_TYPE) { - /* Unsolicited event notification */ - bnx2fc_process_unsol_compl(tgt, wqe); - } else { - /* Pending work request completion */ - struct bnx2fc_work *work = NULL; - struct bnx2fc_percpu_s *fps = NULL; - unsigned int cpu = wqe % num_possible_cpus(); - - fps = &per_cpu(bnx2fc_percpu, cpu); - spin_lock_bh(&fps->fp_work_lock); - if (unlikely(!fps->iothread)) - goto unlock; - - work = bnx2fc_alloc_work(tgt, wqe); - if (work) - list_add_tail(&work->list, - &fps->work_list); -unlock: - spin_unlock_bh(&fps->fp_work_lock); - - /* Pending work request completion */ - if (fps->iothread && work) - wake_up_process(fps->iothread); - else - bnx2fc_process_cq_compl(tgt, wqe); - num_free_sqes++; - } - cqe++; - tgt->cq_cons_idx++; - num_cqes++; - - if (tgt->cq_cons_idx == BNX2FC_CQ_WQES_MAX) { - tgt->cq_cons_idx = 0; - cqe = cq; - tgt->cq_curr_toggle_bit = - 1 - tgt->cq_curr_toggle_bit; - } - } - if (num_cqes) { - /* Arm CQ only if doorbell is mapped */ - if (tgt->ctx_base) - bnx2fc_arm_cq(tgt); - atomic_add(num_free_sqes, &tgt->free_sqes); - } - spin_unlock_bh(&tgt->cq_lock); - return 0; -} - -/** - * bnx2fc_fastpath_notification - process global event queue (KCQ) - * - * @hba: adapter structure pointer - * @new_cqe_kcqe: pointer to newly DMA'd KCQ entry - * - * Fast path event notification handler - */ -static void bnx2fc_fastpath_notification(struct bnx2fc_hba *hba, - struct fcoe_kcqe *new_cqe_kcqe) -{ - u32 conn_id = new_cqe_kcqe->fcoe_conn_id; - struct bnx2fc_rport *tgt = hba->tgt_ofld_list[conn_id]; - - if (!tgt) { - printk(KERN_ERR PFX "conn_id 0x%x not valid\n", conn_id); - return; - } - - bnx2fc_process_new_cqes(tgt); -} - -/** - * bnx2fc_process_ofld_cmpl - process FCoE session offload completion - * - * @hba: adapter structure pointer - * @ofld_kcqe: connection offload kcqe pointer - * - * handle session offload completion, enable the session if offload is - * successful. - */ -static void bnx2fc_process_ofld_cmpl(struct bnx2fc_hba *hba, - struct fcoe_kcqe *ofld_kcqe) -{ - struct bnx2fc_rport *tgt; - struct fcoe_port *port; - struct bnx2fc_interface *interface; - u32 conn_id; - u32 context_id; - int rc; - - conn_id = ofld_kcqe->fcoe_conn_id; - context_id = ofld_kcqe->fcoe_conn_context_id; - tgt = hba->tgt_ofld_list[conn_id]; - if (!tgt) { - printk(KERN_ALERT PFX "ERROR:ofld_cmpl: No pending ofld req\n"); - return; - } - BNX2FC_TGT_DBG(tgt, "Entered ofld compl - context_id = 0x%x\n", - ofld_kcqe->fcoe_conn_context_id); - port = tgt->port; - interface = tgt->port->priv; - if (hba != interface->hba) { - printk(KERN_ERR PFX "ERROR:ofld_cmpl: HBA mis-match\n"); - goto ofld_cmpl_err; - } - /* - * cnic has allocated a context_id for this session; use this - * while enabling the session. - */ - tgt->context_id = context_id; - if (ofld_kcqe->completion_status) { - if (ofld_kcqe->completion_status == - FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE) { - printk(KERN_ERR PFX "unable to allocate FCoE context " - "resources\n"); - set_bit(BNX2FC_FLAG_CTX_ALLOC_FAILURE, &tgt->flags); - } - goto ofld_cmpl_err; - } else { - - /* now enable the session */ - rc = bnx2fc_send_session_enable_req(port, tgt); - if (rc) { - printk(KERN_ERR PFX "enable session failed\n"); - goto ofld_cmpl_err; - } - } - return; -ofld_cmpl_err: - set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); - wake_up_interruptible(&tgt->ofld_wait); -} - -/** - * bnx2fc_process_enable_conn_cmpl - process FCoE session enable completion - * - * @hba: adapter structure pointer - * @ofld_kcqe: connection offload kcqe pointer - * - * handle session enable completion, mark the rport as ready - */ - -static void bnx2fc_process_enable_conn_cmpl(struct bnx2fc_hba *hba, - struct fcoe_kcqe *ofld_kcqe) -{ - struct bnx2fc_rport *tgt; - struct bnx2fc_interface *interface; - u32 conn_id; - u32 context_id; - - context_id = ofld_kcqe->fcoe_conn_context_id; - conn_id = ofld_kcqe->fcoe_conn_id; - tgt = hba->tgt_ofld_list[conn_id]; - if (!tgt) { - printk(KERN_ERR PFX "ERROR:enbl_cmpl: No pending ofld req\n"); - return; - } - - BNX2FC_TGT_DBG(tgt, "Enable compl - context_id = 0x%x\n", - ofld_kcqe->fcoe_conn_context_id); - - /* - * context_id should be the same for this target during offload - * and enable - */ - if (tgt->context_id != context_id) { - printk(KERN_ERR PFX "context id mis-match\n"); - return; - } - interface = tgt->port->priv; - if (hba != interface->hba) { - printk(KERN_ERR PFX "bnx2fc-enbl_cmpl: HBA mis-match\n"); - goto enbl_cmpl_err; - } - if (ofld_kcqe->completion_status) - goto enbl_cmpl_err; - else { - /* enable successful - rport ready for issuing IOs */ - set_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); - set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); - wake_up_interruptible(&tgt->ofld_wait); - } - return; - -enbl_cmpl_err: - set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); - wake_up_interruptible(&tgt->ofld_wait); -} - -static void bnx2fc_process_conn_disable_cmpl(struct bnx2fc_hba *hba, - struct fcoe_kcqe *disable_kcqe) -{ - - struct bnx2fc_rport *tgt; - u32 conn_id; - - conn_id = disable_kcqe->fcoe_conn_id; - tgt = hba->tgt_ofld_list[conn_id]; - if (!tgt) { - printk(KERN_ERR PFX "ERROR: disable_cmpl: No disable req\n"); - return; - } - - BNX2FC_TGT_DBG(tgt, PFX "disable_cmpl: conn_id %d\n", conn_id); - - if (disable_kcqe->completion_status) { - printk(KERN_ERR PFX "Disable failed with cmpl status %d\n", - disable_kcqe->completion_status); - return; - } else { - /* disable successful */ - BNX2FC_TGT_DBG(tgt, "disable successful\n"); - clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); - set_bit(BNX2FC_FLAG_DISABLED, &tgt->flags); - set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); - wake_up_interruptible(&tgt->upld_wait); - } -} - -static void bnx2fc_process_conn_destroy_cmpl(struct bnx2fc_hba *hba, - struct fcoe_kcqe *destroy_kcqe) -{ - struct bnx2fc_rport *tgt; - u32 conn_id; - - conn_id = destroy_kcqe->fcoe_conn_id; - tgt = hba->tgt_ofld_list[conn_id]; - if (!tgt) { - printk(KERN_ERR PFX "destroy_cmpl: No destroy req\n"); - return; - } - - BNX2FC_TGT_DBG(tgt, "destroy_cmpl: conn_id %d\n", conn_id); - - if (destroy_kcqe->completion_status) { - printk(KERN_ERR PFX "Destroy conn failed, cmpl status %d\n", - destroy_kcqe->completion_status); - return; - } else { - /* destroy successful */ - BNX2FC_TGT_DBG(tgt, "upload successful\n"); - clear_bit(BNX2FC_FLAG_DISABLED, &tgt->flags); - set_bit(BNX2FC_FLAG_DESTROYED, &tgt->flags); - set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); - wake_up_interruptible(&tgt->upld_wait); - } -} - -static void bnx2fc_init_failure(struct bnx2fc_hba *hba, u32 err_code) -{ - switch (err_code) { - case FCOE_KCQE_COMPLETION_STATUS_INVALID_OPCODE: - printk(KERN_ERR PFX "init_failure due to invalid opcode\n"); - break; - - case FCOE_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE: - printk(KERN_ERR PFX "init failed due to ctx alloc failure\n"); - break; - - case FCOE_KCQE_COMPLETION_STATUS_NIC_ERROR: - printk(KERN_ERR PFX "init_failure due to NIC error\n"); - break; - case FCOE_KCQE_COMPLETION_STATUS_ERROR: - printk(KERN_ERR PFX "init failure due to compl status err\n"); - break; - case FCOE_KCQE_COMPLETION_STATUS_WRONG_HSI_VERSION: - printk(KERN_ERR PFX "init failure due to HSI mismatch\n"); - break; - default: - printk(KERN_ERR PFX "Unknown Error code %d\n", err_code); - } -} - -/** - * bnx2fc_indicae_kcqe - process KCQE - * - * @hba: adapter structure pointer - * @kcqe: kcqe pointer - * @num_cqe: Number of completion queue elements - * - * Generic KCQ event handler - */ -void bnx2fc_indicate_kcqe(void *context, struct kcqe *kcq[], - u32 num_cqe) -{ - struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context; - int i = 0; - struct fcoe_kcqe *kcqe = NULL; - - while (i < num_cqe) { - kcqe = (struct fcoe_kcqe *) kcq[i++]; - - switch (kcqe->op_code) { - case FCOE_KCQE_OPCODE_CQ_EVENT_NOTIFICATION: - bnx2fc_fastpath_notification(hba, kcqe); - break; - - case FCOE_KCQE_OPCODE_OFFLOAD_CONN: - bnx2fc_process_ofld_cmpl(hba, kcqe); - break; - - case FCOE_KCQE_OPCODE_ENABLE_CONN: - bnx2fc_process_enable_conn_cmpl(hba, kcqe); - break; - - case FCOE_KCQE_OPCODE_INIT_FUNC: - if (kcqe->completion_status != - FCOE_KCQE_COMPLETION_STATUS_SUCCESS) { - bnx2fc_init_failure(hba, - kcqe->completion_status); - } else { - set_bit(ADAPTER_STATE_UP, &hba->adapter_state); - bnx2fc_get_link_state(hba); - printk(KERN_INFO PFX "[%.2x]: FCOE_INIT passed\n", - (u8)hba->pcidev->bus->number); - } - break; - - case FCOE_KCQE_OPCODE_DESTROY_FUNC: - if (kcqe->completion_status != - FCOE_KCQE_COMPLETION_STATUS_SUCCESS) { - - printk(KERN_ERR PFX "DESTROY failed\n"); - } else { - printk(KERN_ERR PFX "DESTROY success\n"); - } - set_bit(BNX2FC_FLAG_DESTROY_CMPL, &hba->flags); - wake_up_interruptible(&hba->destroy_wait); - break; - - case FCOE_KCQE_OPCODE_DISABLE_CONN: - bnx2fc_process_conn_disable_cmpl(hba, kcqe); - break; - - case FCOE_KCQE_OPCODE_DESTROY_CONN: - bnx2fc_process_conn_destroy_cmpl(hba, kcqe); - break; - - case FCOE_KCQE_OPCODE_STAT_FUNC: - if (kcqe->completion_status != - FCOE_KCQE_COMPLETION_STATUS_SUCCESS) - printk(KERN_ERR PFX "STAT failed\n"); - complete(&hba->stat_req_done); - break; - - case FCOE_KCQE_OPCODE_FCOE_ERROR: - /* fall thru */ - default: - printk(KERN_ERR PFX "unknown opcode 0x%x\n", - kcqe->op_code); - } - } -} - -void bnx2fc_add_2_sq(struct bnx2fc_rport *tgt, u16 xid) -{ - struct fcoe_sqe *sqe; - - sqe = &tgt->sq[tgt->sq_prod_idx]; - - /* Fill SQ WQE */ - sqe->wqe = xid << FCOE_SQE_TASK_ID_SHIFT; - sqe->wqe |= tgt->sq_curr_toggle_bit << FCOE_SQE_TOGGLE_BIT_SHIFT; - - /* Advance SQ Prod Idx */ - if (++tgt->sq_prod_idx == BNX2FC_SQ_WQES_MAX) { - tgt->sq_prod_idx = 0; - tgt->sq_curr_toggle_bit = 1 - tgt->sq_curr_toggle_bit; - } -} - -void bnx2fc_ring_doorbell(struct bnx2fc_rport *tgt) -{ - struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db; - u32 msg; - - wmb(); - sq_db->prod = tgt->sq_prod_idx | - (tgt->sq_curr_toggle_bit << 15); - msg = *((u32 *)sq_db); - writel(cpu_to_le32(msg), tgt->ctx_base); - mmiowb(); - -} - -int bnx2fc_map_doorbell(struct bnx2fc_rport *tgt) -{ - u32 context_id = tgt->context_id; - struct fcoe_port *port = tgt->port; - u32 reg_off; - resource_size_t reg_base; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - - reg_base = pci_resource_start(hba->pcidev, - BNX2X_DOORBELL_PCI_BAR); - reg_off = BNX2FC_5771X_DB_PAGE_SIZE * - (context_id & 0x1FFFF) + DPM_TRIGER_TYPE; - tgt->ctx_base = ioremap_nocache(reg_base + reg_off, 4); - if (!tgt->ctx_base) - return -ENOMEM; - return 0; -} - -char *bnx2fc_get_next_rqe(struct bnx2fc_rport *tgt, u8 num_items) -{ - char *buf = (char *)tgt->rq + (tgt->rq_cons_idx * BNX2FC_RQ_BUF_SZ); - - if (tgt->rq_cons_idx + num_items > BNX2FC_RQ_WQES_MAX) - return NULL; - - tgt->rq_cons_idx += num_items; - - if (tgt->rq_cons_idx >= BNX2FC_RQ_WQES_MAX) - tgt->rq_cons_idx -= BNX2FC_RQ_WQES_MAX; - - return buf; -} - -void bnx2fc_return_rqe(struct bnx2fc_rport *tgt, u8 num_items) -{ - /* return the rq buffer */ - u32 next_prod_idx = tgt->rq_prod_idx + num_items; - if ((next_prod_idx & 0x7fff) == BNX2FC_RQ_WQES_MAX) { - /* Wrap around RQ */ - next_prod_idx += 0x8000 - BNX2FC_RQ_WQES_MAX; - } - tgt->rq_prod_idx = next_prod_idx; - tgt->conn_db->rq_prod = tgt->rq_prod_idx; -} - -void bnx2fc_init_seq_cleanup_task(struct bnx2fc_cmd *seq_clnp_req, - struct fcoe_task_ctx_entry *task, - struct bnx2fc_cmd *orig_io_req, - u32 offset) -{ - struct scsi_cmnd *sc_cmd = orig_io_req->sc_cmd; - struct bnx2fc_rport *tgt = seq_clnp_req->tgt; - struct bnx2fc_interface *interface = tgt->port->priv; - struct fcoe_bd_ctx *bd = orig_io_req->bd_tbl->bd_tbl; - struct fcoe_task_ctx_entry *orig_task; - struct fcoe_task_ctx_entry *task_page; - struct fcoe_ext_mul_sges_ctx *sgl; - u8 task_type = FCOE_TASK_TYPE_SEQUENCE_CLEANUP; - u8 orig_task_type; - u16 orig_xid = orig_io_req->xid; - u32 context_id = tgt->context_id; - u64 phys_addr = (u64)orig_io_req->bd_tbl->bd_tbl_dma; - u32 orig_offset = offset; - int bd_count; - int orig_task_idx, index; - int i; - - memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); - - if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) - orig_task_type = FCOE_TASK_TYPE_WRITE; - else - orig_task_type = FCOE_TASK_TYPE_READ; - - /* Tx flags */ - task->txwr_rxrd.const_ctx.tx_flags = - FCOE_TASK_TX_STATE_SEQUENCE_CLEANUP << - FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; - /* init flags */ - task->txwr_rxrd.const_ctx.init_flags = task_type << - FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; - task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << - FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; - task->rxwr_txrd.const_ctx.init_flags = context_id << - FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; - task->rxwr_txrd.const_ctx.init_flags = context_id << - FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; - - task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid; - - task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_seq_cnt = 0; - task->txwr_rxrd.union_ctx.cleanup.ctx.rolled_tx_data_offset = offset; - - bd_count = orig_io_req->bd_tbl->bd_valid; - - /* obtain the appropriate bd entry from relative offset */ - for (i = 0; i < bd_count; i++) { - if (offset < bd[i].buf_len) - break; - offset -= bd[i].buf_len; - } - phys_addr += (i * sizeof(struct fcoe_bd_ctx)); - - if (orig_task_type == FCOE_TASK_TYPE_WRITE) { - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = - (u32)phys_addr; - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = - (u32)((u64)phys_addr >> 32); - task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = - bd_count; - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_off = - offset; /* adjusted offset */ - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_idx = i; - } else { - orig_task_idx = orig_xid / BNX2FC_TASKS_PER_PAGE; - index = orig_xid % BNX2FC_TASKS_PER_PAGE; - - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[orig_task_idx]; - orig_task = &(task_page[index]); - - /* Multiple SGEs were used for this IO */ - sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; - sgl->mul_sgl.cur_sge_addr.lo = (u32)phys_addr; - sgl->mul_sgl.cur_sge_addr.hi = (u32)((u64)phys_addr >> 32); - sgl->mul_sgl.sgl_size = bd_count; - sgl->mul_sgl.cur_sge_off = offset; /*adjusted offset */ - sgl->mul_sgl.cur_sge_idx = i; - - memset(&task->rxwr_only.rx_seq_ctx, 0, - sizeof(struct fcoe_rx_seq_ctx)); - task->rxwr_only.rx_seq_ctx.low_exp_ro = orig_offset; - task->rxwr_only.rx_seq_ctx.high_exp_ro = orig_offset; - } -} -void bnx2fc_init_cleanup_task(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u16 orig_xid) -{ - u8 task_type = FCOE_TASK_TYPE_EXCHANGE_CLEANUP; - struct bnx2fc_rport *tgt = io_req->tgt; - u32 context_id = tgt->context_id; - - memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); - - /* Tx Write Rx Read */ - /* init flags */ - task->txwr_rxrd.const_ctx.init_flags = task_type << - FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; - task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << - FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; - if (tgt->dev_type == TYPE_TAPE) - task->txwr_rxrd.const_ctx.init_flags |= - FCOE_TASK_DEV_TYPE_TAPE << - FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; - else - task->txwr_rxrd.const_ctx.init_flags |= - FCOE_TASK_DEV_TYPE_DISK << - FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; - task->txwr_rxrd.union_ctx.cleanup.ctx.cleaned_task_id = orig_xid; - - /* Tx flags */ - task->txwr_rxrd.const_ctx.tx_flags = - FCOE_TASK_TX_STATE_EXCHANGE_CLEANUP << - FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; - - /* Rx Read Tx Write */ - task->rxwr_txrd.const_ctx.init_flags = context_id << - FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; - task->rxwr_txrd.var_ctx.rx_flags |= 1 << - FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; -} - -void bnx2fc_init_mp_task(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task) -{ - struct bnx2fc_mp_req *mp_req = &(io_req->mp_req); - struct bnx2fc_rport *tgt = io_req->tgt; - struct fc_frame_header *fc_hdr; - struct fcoe_ext_mul_sges_ctx *sgl; - u8 task_type = 0; - u64 *hdr; - u64 temp_hdr[3]; - u32 context_id; - - - /* Obtain task_type */ - if ((io_req->cmd_type == BNX2FC_TASK_MGMT_CMD) || - (io_req->cmd_type == BNX2FC_ELS)) { - task_type = FCOE_TASK_TYPE_MIDPATH; - } else if (io_req->cmd_type == BNX2FC_ABTS) { - task_type = FCOE_TASK_TYPE_ABTS; - } - - memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); - - /* Setup the task from io_req for easy reference */ - io_req->task = task; - - BNX2FC_IO_DBG(io_req, "Init MP task for cmd_type = %d task_type = %d\n", - io_req->cmd_type, task_type); - - /* Tx only */ - if ((task_type == FCOE_TASK_TYPE_MIDPATH) || - (task_type == FCOE_TASK_TYPE_UNSOLICITED)) { - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = - (u32)mp_req->mp_req_bd_dma; - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = - (u32)((u64)mp_req->mp_req_bd_dma >> 32); - task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = 1; - } - - /* Tx Write Rx Read */ - /* init flags */ - task->txwr_rxrd.const_ctx.init_flags = task_type << - FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; - if (tgt->dev_type == TYPE_TAPE) - task->txwr_rxrd.const_ctx.init_flags |= - FCOE_TASK_DEV_TYPE_TAPE << - FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; - else - task->txwr_rxrd.const_ctx.init_flags |= - FCOE_TASK_DEV_TYPE_DISK << - FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; - task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << - FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; - - /* tx flags */ - task->txwr_rxrd.const_ctx.tx_flags = FCOE_TASK_TX_STATE_INIT << - FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; - - /* Rx Write Tx Read */ - task->rxwr_txrd.const_ctx.data_2_trns = io_req->data_xfer_len; - - /* rx flags */ - task->rxwr_txrd.var_ctx.rx_flags |= 1 << - FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; - - context_id = tgt->context_id; - task->rxwr_txrd.const_ctx.init_flags = context_id << - FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; - - fc_hdr = &(mp_req->req_fc_hdr); - if (task_type == FCOE_TASK_TYPE_MIDPATH) { - fc_hdr->fh_ox_id = cpu_to_be16(io_req->xid); - fc_hdr->fh_rx_id = htons(0xffff); - task->rxwr_txrd.var_ctx.rx_id = 0xffff; - } else if (task_type == FCOE_TASK_TYPE_UNSOLICITED) { - fc_hdr->fh_rx_id = cpu_to_be16(io_req->xid); - } - - /* Fill FC Header into middle path buffer */ - hdr = (u64 *) &task->txwr_rxrd.union_ctx.tx_frame.fc_hdr; - memcpy(temp_hdr, fc_hdr, sizeof(temp_hdr)); - hdr[0] = cpu_to_be64(temp_hdr[0]); - hdr[1] = cpu_to_be64(temp_hdr[1]); - hdr[2] = cpu_to_be64(temp_hdr[2]); - - /* Rx Only */ - if (task_type == FCOE_TASK_TYPE_MIDPATH) { - sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; - - sgl->mul_sgl.cur_sge_addr.lo = (u32)mp_req->mp_resp_bd_dma; - sgl->mul_sgl.cur_sge_addr.hi = - (u32)((u64)mp_req->mp_resp_bd_dma >> 32); - sgl->mul_sgl.sgl_size = 1; - } -} - -void bnx2fc_init_task(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task) -{ - u8 task_type; - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - struct io_bdt *bd_tbl = io_req->bd_tbl; - struct bnx2fc_rport *tgt = io_req->tgt; - struct fcoe_cached_sge_ctx *cached_sge; - struct fcoe_ext_mul_sges_ctx *sgl; - int dev_type = tgt->dev_type; - u64 *fcp_cmnd; - u64 tmp_fcp_cmnd[4]; - u32 context_id; - int cnt, i; - int bd_count; - - memset(task, 0, sizeof(struct fcoe_task_ctx_entry)); - - /* Setup the task from io_req for easy reference */ - io_req->task = task; - - if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) - task_type = FCOE_TASK_TYPE_WRITE; - else - task_type = FCOE_TASK_TYPE_READ; - - /* Tx only */ - bd_count = bd_tbl->bd_valid; - cached_sge = &task->rxwr_only.union_ctx.read_info.sgl_ctx.cached_sge; - if (task_type == FCOE_TASK_TYPE_WRITE) { - if ((dev_type == TYPE_DISK) && (bd_count == 1)) { - struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; - - task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.lo = - cached_sge->cur_buf_addr.lo = - fcoe_bd_tbl->buf_addr_lo; - task->txwr_only.sgl_ctx.cached_sge.cur_buf_addr.hi = - cached_sge->cur_buf_addr.hi = - fcoe_bd_tbl->buf_addr_hi; - task->txwr_only.sgl_ctx.cached_sge.cur_buf_rem = - cached_sge->cur_buf_rem = - fcoe_bd_tbl->buf_len; - - task->txwr_rxrd.const_ctx.init_flags |= 1 << - FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; - } else { - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.lo = - (u32)bd_tbl->bd_tbl_dma; - task->txwr_only.sgl_ctx.sgl.mul_sgl.cur_sge_addr.hi = - (u32)((u64)bd_tbl->bd_tbl_dma >> 32); - task->txwr_only.sgl_ctx.sgl.mul_sgl.sgl_size = - bd_tbl->bd_valid; - } - } - - /*Tx Write Rx Read */ - /* Init state to NORMAL */ - task->txwr_rxrd.const_ctx.init_flags |= task_type << - FCOE_TCE_TX_WR_RX_RD_CONST_TASK_TYPE_SHIFT; - if (dev_type == TYPE_TAPE) { - task->txwr_rxrd.const_ctx.init_flags |= - FCOE_TASK_DEV_TYPE_TAPE << - FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; - io_req->rec_retry = 0; - io_req->rec_retry = 0; - } else - task->txwr_rxrd.const_ctx.init_flags |= - FCOE_TASK_DEV_TYPE_DISK << - FCOE_TCE_TX_WR_RX_RD_CONST_DEV_TYPE_SHIFT; - task->txwr_rxrd.const_ctx.init_flags |= FCOE_TASK_CLASS_TYPE_3 << - FCOE_TCE_TX_WR_RX_RD_CONST_CLASS_TYPE_SHIFT; - /* tx flags */ - task->txwr_rxrd.const_ctx.tx_flags = FCOE_TASK_TX_STATE_NORMAL << - FCOE_TCE_TX_WR_RX_RD_CONST_TX_STATE_SHIFT; - - /* Set initial seq counter */ - task->txwr_rxrd.union_ctx.tx_seq.ctx.seq_cnt = 1; - - /* Fill FCP_CMND IU */ - fcp_cmnd = (u64 *) - task->txwr_rxrd.union_ctx.fcp_cmd.opaque; - bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)&tmp_fcp_cmnd); - - /* swap fcp_cmnd */ - cnt = sizeof(struct fcp_cmnd) / sizeof(u64); - - for (i = 0; i < cnt; i++) { - *fcp_cmnd = cpu_to_be64(tmp_fcp_cmnd[i]); - fcp_cmnd++; - } - - /* Rx Write Tx Read */ - task->rxwr_txrd.const_ctx.data_2_trns = io_req->data_xfer_len; - - context_id = tgt->context_id; - task->rxwr_txrd.const_ctx.init_flags = context_id << - FCOE_TCE_RX_WR_TX_RD_CONST_CID_SHIFT; - - /* rx flags */ - /* Set state to "waiting for the first packet" */ - task->rxwr_txrd.var_ctx.rx_flags |= 1 << - FCOE_TCE_RX_WR_TX_RD_VAR_EXP_FIRST_FRAME_SHIFT; - - task->rxwr_txrd.var_ctx.rx_id = 0xffff; - - /* Rx Only */ - if (task_type != FCOE_TASK_TYPE_READ) - return; - - sgl = &task->rxwr_only.union_ctx.read_info.sgl_ctx.sgl; - bd_count = bd_tbl->bd_valid; - - if (dev_type == TYPE_DISK) { - if (bd_count == 1) { - - struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; - - cached_sge->cur_buf_addr.lo = fcoe_bd_tbl->buf_addr_lo; - cached_sge->cur_buf_addr.hi = fcoe_bd_tbl->buf_addr_hi; - cached_sge->cur_buf_rem = fcoe_bd_tbl->buf_len; - task->txwr_rxrd.const_ctx.init_flags |= 1 << - FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; - } else if (bd_count == 2) { - struct fcoe_bd_ctx *fcoe_bd_tbl = bd_tbl->bd_tbl; - - cached_sge->cur_buf_addr.lo = fcoe_bd_tbl->buf_addr_lo; - cached_sge->cur_buf_addr.hi = fcoe_bd_tbl->buf_addr_hi; - cached_sge->cur_buf_rem = fcoe_bd_tbl->buf_len; - - fcoe_bd_tbl++; - cached_sge->second_buf_addr.lo = - fcoe_bd_tbl->buf_addr_lo; - cached_sge->second_buf_addr.hi = - fcoe_bd_tbl->buf_addr_hi; - cached_sge->second_buf_rem = fcoe_bd_tbl->buf_len; - task->txwr_rxrd.const_ctx.init_flags |= 1 << - FCOE_TCE_TX_WR_RX_RD_CONST_CACHED_SGE_SHIFT; - } else { - - sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma; - sgl->mul_sgl.cur_sge_addr.hi = - (u32)((u64)bd_tbl->bd_tbl_dma >> 32); - sgl->mul_sgl.sgl_size = bd_count; - } - } else { - sgl->mul_sgl.cur_sge_addr.lo = (u32)bd_tbl->bd_tbl_dma; - sgl->mul_sgl.cur_sge_addr.hi = - (u32)((u64)bd_tbl->bd_tbl_dma >> 32); - sgl->mul_sgl.sgl_size = bd_count; - } -} - -/** - * bnx2fc_setup_task_ctx - allocate and map task context - * - * @hba: pointer to adapter structure - * - * allocate memory for task context, and associated BD table to be used - * by firmware - * - */ -int bnx2fc_setup_task_ctx(struct bnx2fc_hba *hba) -{ - int rc = 0; - struct regpair *task_ctx_bdt; - dma_addr_t addr; - int i; - - /* - * Allocate task context bd table. A page size of bd table - * can map 256 buffers. Each buffer contains 32 task context - * entries. Hence the limit with one page is 8192 task context - * entries. - */ - hba->task_ctx_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, - PAGE_SIZE, - &hba->task_ctx_bd_dma, - GFP_KERNEL); - if (!hba->task_ctx_bd_tbl) { - printk(KERN_ERR PFX "unable to allocate task context BDT\n"); - rc = -1; - goto out; - } - memset(hba->task_ctx_bd_tbl, 0, PAGE_SIZE); - - /* - * Allocate task_ctx which is an array of pointers pointing to - * a page containing 32 task contexts - */ - hba->task_ctx = kzalloc((BNX2FC_TASK_CTX_ARR_SZ * sizeof(void *)), - GFP_KERNEL); - if (!hba->task_ctx) { - printk(KERN_ERR PFX "unable to allocate task context array\n"); - rc = -1; - goto out1; - } - - /* - * Allocate task_ctx_dma which is an array of dma addresses - */ - hba->task_ctx_dma = kmalloc((BNX2FC_TASK_CTX_ARR_SZ * - sizeof(dma_addr_t)), GFP_KERNEL); - if (!hba->task_ctx_dma) { - printk(KERN_ERR PFX "unable to alloc context mapping array\n"); - rc = -1; - goto out2; - } - - task_ctx_bdt = (struct regpair *)hba->task_ctx_bd_tbl; - for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) { - - hba->task_ctx[i] = dma_alloc_coherent(&hba->pcidev->dev, - PAGE_SIZE, - &hba->task_ctx_dma[i], - GFP_KERNEL); - if (!hba->task_ctx[i]) { - printk(KERN_ERR PFX "unable to alloc task context\n"); - rc = -1; - goto out3; - } - memset(hba->task_ctx[i], 0, PAGE_SIZE); - addr = (u64)hba->task_ctx_dma[i]; - task_ctx_bdt->hi = cpu_to_le32((u64)addr >> 32); - task_ctx_bdt->lo = cpu_to_le32((u32)addr); - task_ctx_bdt++; - } - return 0; - -out3: - for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) { - if (hba->task_ctx[i]) { - - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->task_ctx[i], hba->task_ctx_dma[i]); - hba->task_ctx[i] = NULL; - } - } - - kfree(hba->task_ctx_dma); - hba->task_ctx_dma = NULL; -out2: - kfree(hba->task_ctx); - hba->task_ctx = NULL; -out1: - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->task_ctx_bd_tbl, hba->task_ctx_bd_dma); - hba->task_ctx_bd_tbl = NULL; -out: - return rc; -} - -void bnx2fc_free_task_ctx(struct bnx2fc_hba *hba) -{ - int i; - - if (hba->task_ctx_bd_tbl) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->task_ctx_bd_tbl, - hba->task_ctx_bd_dma); - hba->task_ctx_bd_tbl = NULL; - } - - if (hba->task_ctx) { - for (i = 0; i < BNX2FC_TASK_CTX_ARR_SZ; i++) { - if (hba->task_ctx[i]) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->task_ctx[i], - hba->task_ctx_dma[i]); - hba->task_ctx[i] = NULL; - } - } - kfree(hba->task_ctx); - hba->task_ctx = NULL; - } - - kfree(hba->task_ctx_dma); - hba->task_ctx_dma = NULL; -} - -static void bnx2fc_free_hash_table(struct bnx2fc_hba *hba) -{ - int i; - int segment_count; - int hash_table_size; - u32 *pbl; - - segment_count = hba->hash_tbl_segment_count; - hash_table_size = BNX2FC_NUM_MAX_SESS * BNX2FC_MAX_ROWS_IN_HASH_TBL * - sizeof(struct fcoe_hash_table_entry); - - pbl = hba->hash_tbl_pbl; - for (i = 0; i < segment_count; ++i) { - dma_addr_t dma_address; - - dma_address = le32_to_cpu(*pbl); - ++pbl; - dma_address += ((u64)le32_to_cpu(*pbl)) << 32; - ++pbl; - dma_free_coherent(&hba->pcidev->dev, - BNX2FC_HASH_TBL_CHUNK_SIZE, - hba->hash_tbl_segments[i], - dma_address); - - } - - if (hba->hash_tbl_pbl) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->hash_tbl_pbl, - hba->hash_tbl_pbl_dma); - hba->hash_tbl_pbl = NULL; - } -} - -static int bnx2fc_allocate_hash_table(struct bnx2fc_hba *hba) -{ - int i; - int hash_table_size; - int segment_count; - int segment_array_size; - int dma_segment_array_size; - dma_addr_t *dma_segment_array; - u32 *pbl; - - hash_table_size = BNX2FC_NUM_MAX_SESS * BNX2FC_MAX_ROWS_IN_HASH_TBL * - sizeof(struct fcoe_hash_table_entry); - - segment_count = hash_table_size + BNX2FC_HASH_TBL_CHUNK_SIZE - 1; - segment_count /= BNX2FC_HASH_TBL_CHUNK_SIZE; - hba->hash_tbl_segment_count = segment_count; - - segment_array_size = segment_count * sizeof(*hba->hash_tbl_segments); - hba->hash_tbl_segments = kzalloc(segment_array_size, GFP_KERNEL); - if (!hba->hash_tbl_segments) { - printk(KERN_ERR PFX "hash table pointers alloc failed\n"); - return -ENOMEM; - } - dma_segment_array_size = segment_count * sizeof(*dma_segment_array); - dma_segment_array = kzalloc(dma_segment_array_size, GFP_KERNEL); - if (!dma_segment_array) { - printk(KERN_ERR PFX "hash table pointers (dma) alloc failed\n"); - return -ENOMEM; - } - - for (i = 0; i < segment_count; ++i) { - hba->hash_tbl_segments[i] = - dma_alloc_coherent(&hba->pcidev->dev, - BNX2FC_HASH_TBL_CHUNK_SIZE, - &dma_segment_array[i], - GFP_KERNEL); - if (!hba->hash_tbl_segments[i]) { - printk(KERN_ERR PFX "hash segment alloc failed\n"); - while (--i >= 0) { - dma_free_coherent(&hba->pcidev->dev, - BNX2FC_HASH_TBL_CHUNK_SIZE, - hba->hash_tbl_segments[i], - dma_segment_array[i]); - hba->hash_tbl_segments[i] = NULL; - } - kfree(dma_segment_array); - return -ENOMEM; - } - memset(hba->hash_tbl_segments[i], 0, - BNX2FC_HASH_TBL_CHUNK_SIZE); - } - - hba->hash_tbl_pbl = dma_alloc_coherent(&hba->pcidev->dev, - PAGE_SIZE, - &hba->hash_tbl_pbl_dma, - GFP_KERNEL); - if (!hba->hash_tbl_pbl) { - printk(KERN_ERR PFX "hash table pbl alloc failed\n"); - kfree(dma_segment_array); - return -ENOMEM; - } - memset(hba->hash_tbl_pbl, 0, PAGE_SIZE); - - pbl = hba->hash_tbl_pbl; - for (i = 0; i < segment_count; ++i) { - u64 paddr = dma_segment_array[i]; - *pbl = cpu_to_le32((u32) paddr); - ++pbl; - *pbl = cpu_to_le32((u32) (paddr >> 32)); - ++pbl; - } - pbl = hba->hash_tbl_pbl; - i = 0; - while (*pbl && *(pbl + 1)) { - u32 lo; - u32 hi; - lo = *pbl; - ++pbl; - hi = *pbl; - ++pbl; - ++i; - } - kfree(dma_segment_array); - return 0; -} - -/** - * bnx2fc_setup_fw_resc - Allocate and map hash table and dummy buffer - * - * @hba: Pointer to adapter structure - * - */ -int bnx2fc_setup_fw_resc(struct bnx2fc_hba *hba) -{ - u64 addr; - u32 mem_size; - int i; - - if (bnx2fc_allocate_hash_table(hba)) - return -ENOMEM; - - mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair); - hba->t2_hash_tbl_ptr = dma_alloc_coherent(&hba->pcidev->dev, mem_size, - &hba->t2_hash_tbl_ptr_dma, - GFP_KERNEL); - if (!hba->t2_hash_tbl_ptr) { - printk(KERN_ERR PFX "unable to allocate t2 hash table ptr\n"); - bnx2fc_free_fw_resc(hba); - return -ENOMEM; - } - memset(hba->t2_hash_tbl_ptr, 0x00, mem_size); - - mem_size = BNX2FC_NUM_MAX_SESS * - sizeof(struct fcoe_t2_hash_table_entry); - hba->t2_hash_tbl = dma_alloc_coherent(&hba->pcidev->dev, mem_size, - &hba->t2_hash_tbl_dma, - GFP_KERNEL); - if (!hba->t2_hash_tbl) { - printk(KERN_ERR PFX "unable to allocate t2 hash table\n"); - bnx2fc_free_fw_resc(hba); - return -ENOMEM; - } - memset(hba->t2_hash_tbl, 0x00, mem_size); - for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) { - addr = (unsigned long) hba->t2_hash_tbl_dma + - ((i+1) * sizeof(struct fcoe_t2_hash_table_entry)); - hba->t2_hash_tbl[i].next.lo = addr & 0xffffffff; - hba->t2_hash_tbl[i].next.hi = addr >> 32; - } - - hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, - PAGE_SIZE, &hba->dummy_buf_dma, - GFP_KERNEL); - if (!hba->dummy_buffer) { - printk(KERN_ERR PFX "unable to alloc MP Dummy Buffer\n"); - bnx2fc_free_fw_resc(hba); - return -ENOMEM; - } - - hba->stats_buffer = dma_alloc_coherent(&hba->pcidev->dev, - PAGE_SIZE, - &hba->stats_buf_dma, - GFP_KERNEL); - if (!hba->stats_buffer) { - printk(KERN_ERR PFX "unable to alloc Stats Buffer\n"); - bnx2fc_free_fw_resc(hba); - return -ENOMEM; - } - memset(hba->stats_buffer, 0x00, PAGE_SIZE); - - return 0; -} - -void bnx2fc_free_fw_resc(struct bnx2fc_hba *hba) -{ - u32 mem_size; - - if (hba->stats_buffer) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->stats_buffer, hba->stats_buf_dma); - hba->stats_buffer = NULL; - } - - if (hba->dummy_buffer) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->dummy_buffer, hba->dummy_buf_dma); - hba->dummy_buffer = NULL; - } - - if (hba->t2_hash_tbl_ptr) { - mem_size = BNX2FC_NUM_MAX_SESS * sizeof(struct regpair); - dma_free_coherent(&hba->pcidev->dev, mem_size, - hba->t2_hash_tbl_ptr, - hba->t2_hash_tbl_ptr_dma); - hba->t2_hash_tbl_ptr = NULL; - } - - if (hba->t2_hash_tbl) { - mem_size = BNX2FC_NUM_MAX_SESS * - sizeof(struct fcoe_t2_hash_table_entry); - dma_free_coherent(&hba->pcidev->dev, mem_size, - hba->t2_hash_tbl, hba->t2_hash_tbl_dma); - hba->t2_hash_tbl = NULL; - } - bnx2fc_free_hash_table(hba); -} diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_io.c b/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_io.c deleted file mode 100644 index e897ce97..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_io.c +++ /dev/null @@ -1,2032 +0,0 @@ -/* bnx2fc_io.c: Broadcom NetXtreme II Linux FCoE offload driver. - * IO manager and SCSI IO processing. - * - * Copyright (c) 2008 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) - */ - -#include "bnx2fc.h" - -#define RESERVE_FREE_LIST_INDEX num_possible_cpus() - -static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, - int bd_index); -static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req); -static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req); -static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req); -static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req); -static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, - struct fcoe_fcp_rsp_payload *fcp_rsp, - u8 num_rq); - -void bnx2fc_cmd_timer_set(struct bnx2fc_cmd *io_req, - unsigned int timer_msec) -{ - struct bnx2fc_interface *interface = io_req->port->priv; - - if (queue_delayed_work(interface->timer_work_queue, - &io_req->timeout_work, - msecs_to_jiffies(timer_msec))) - kref_get(&io_req->refcount); -} - -static void bnx2fc_cmd_timeout(struct work_struct *work) -{ - struct bnx2fc_cmd *io_req = container_of(work, struct bnx2fc_cmd, - timeout_work.work); - struct fc_lport *lport; - struct fc_rport_priv *rdata; - u8 cmd_type = io_req->cmd_type; - struct bnx2fc_rport *tgt = io_req->tgt; - int logo_issued; - int rc; - - BNX2FC_IO_DBG(io_req, "cmd_timeout, cmd_type = %d," - "req_flags = %lx\n", cmd_type, io_req->req_flags); - - spin_lock_bh(&tgt->tgt_lock); - if (test_and_clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags)) { - clear_bit(BNX2FC_FLAG_RETIRE_OXID, &io_req->req_flags); - /* - * ideally we should hold the io_req until RRQ complets, - * and release io_req from timeout hold. - */ - spin_unlock_bh(&tgt->tgt_lock); - bnx2fc_send_rrq(io_req); - return; - } - if (test_and_clear_bit(BNX2FC_FLAG_RETIRE_OXID, &io_req->req_flags)) { - BNX2FC_IO_DBG(io_req, "IO ready for reuse now\n"); - goto done; - } - - switch (cmd_type) { - case BNX2FC_SCSI_CMD: - if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, - &io_req->req_flags)) { - /* Handle eh_abort timeout */ - BNX2FC_IO_DBG(io_req, "eh_abort timed out\n"); - complete(&io_req->tm_done); - } else if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, - &io_req->req_flags)) { - /* Handle internally generated ABTS timeout */ - BNX2FC_IO_DBG(io_req, "ABTS timed out refcnt = %d\n", - io_req->refcount.refcount.counter); - if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, - &io_req->req_flags))) { - - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - - /* Explicitly logo the target */ - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicit " - "logo - tgt flags = 0x%lx\n", - tgt->flags); - - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } - return; - } - } else { - /* Hanlde IO timeout */ - BNX2FC_IO_DBG(io_req, "IO timed out. issue ABTS\n"); - if (test_and_set_bit(BNX2FC_FLAG_IO_COMPL, - &io_req->req_flags)) { - BNX2FC_IO_DBG(io_req, "IO completed before " - " timer expiry\n"); - goto done; - } - - if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, - &io_req->req_flags)) { - rc = bnx2fc_initiate_abts(io_req); - if (rc == SUCCESS) - goto done; - /* - * Explicitly logo the target if - * abts initiation fails - */ - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicit " - "logo - tgt flags = 0x%lx\n", - tgt->flags); - - - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } - return; - } else { - BNX2FC_IO_DBG(io_req, "IO already in " - "ABTS processing\n"); - } - } - break; - case BNX2FC_ELS: - - if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { - BNX2FC_IO_DBG(io_req, "ABTS for ELS timed out\n"); - - if (!test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, - &io_req->req_flags)) { - lport = io_req->port->lport; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit( - BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - - /* Explicitly logo the target */ - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Explicitly logo" - "(els)\n"); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } - return; - } - } else { - /* - * Handle ELS timeout. - * tgt_lock is used to sync compl path and timeout - * path. If els compl path is processing this IO, we - * have nothing to do here, just release the timer hold - */ - BNX2FC_IO_DBG(io_req, "ELS timed out\n"); - if (test_and_set_bit(BNX2FC_FLAG_ELS_DONE, - &io_req->req_flags)) - goto done; - - /* Indicate the cb_func that this ELS is timed out */ - set_bit(BNX2FC_FLAG_ELS_TIMEOUT, &io_req->req_flags); - - if ((io_req->cb_func) && (io_req->cb_arg)) { - io_req->cb_func(io_req->cb_arg); - io_req->cb_arg = NULL; - } - } - break; - default: - printk(KERN_ERR PFX "cmd_timeout: invalid cmd_type %d\n", - cmd_type); - break; - } - -done: - /* release the cmd that was held when timer was set */ - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); -} - -static void bnx2fc_scsi_done(struct bnx2fc_cmd *io_req, int err_code) -{ - /* Called with host lock held */ - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - - /* - * active_cmd_queue may have other command types as well, - * and during flush operation, we want to error back only - * scsi commands. - */ - if (io_req->cmd_type != BNX2FC_SCSI_CMD) - return; - - BNX2FC_IO_DBG(io_req, "scsi_done. err_code = 0x%x\n", err_code); - if (test_bit(BNX2FC_FLAG_CMD_LOST, &io_req->req_flags)) { - /* Do not call scsi done for this IO */ - return; - } - - bnx2fc_unmap_sg_list(io_req); - io_req->sc_cmd = NULL; - if (!sc_cmd) { - printk(KERN_ERR PFX "scsi_done - sc_cmd NULL. " - "IO(0x%x) already cleaned up\n", - io_req->xid); - return; - } - sc_cmd->result = err_code << 16; - - BNX2FC_IO_DBG(io_req, "sc=%p, result=0x%x, retries=%d, allowed=%d\n", - sc_cmd, host_byte(sc_cmd->result), sc_cmd->retries, - sc_cmd->allowed); - scsi_set_resid(sc_cmd, scsi_bufflen(sc_cmd)); - sc_cmd->SCp.ptr = NULL; - sc_cmd->scsi_done(sc_cmd); -} - -struct bnx2fc_cmd_mgr *bnx2fc_cmd_mgr_alloc(struct bnx2fc_hba *hba, - u16 min_xid, u16 max_xid) -{ - struct bnx2fc_cmd_mgr *cmgr; - struct io_bdt *bdt_info; - struct bnx2fc_cmd *io_req; - size_t len; - u32 mem_size; - u16 xid; - int i; - int num_ios, num_pri_ios; - size_t bd_tbl_sz; - int arr_sz = num_possible_cpus() + 1; - - if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { - printk(KERN_ERR PFX "cmd_mgr_alloc: Invalid min_xid 0x%x \ - and max_xid 0x%x\n", min_xid, max_xid); - return NULL; - } - BNX2FC_MISC_DBG("min xid 0x%x, max xid 0x%x\n", min_xid, max_xid); - - num_ios = max_xid - min_xid + 1; - len = (num_ios * (sizeof(struct bnx2fc_cmd *))); - len += sizeof(struct bnx2fc_cmd_mgr); - - cmgr = kzalloc(len, GFP_KERNEL); - if (!cmgr) { - printk(KERN_ERR PFX "failed to alloc cmgr\n"); - return NULL; - } - - cmgr->free_list = kzalloc(sizeof(*cmgr->free_list) * - arr_sz, GFP_KERNEL); - if (!cmgr->free_list) { - printk(KERN_ERR PFX "failed to alloc free_list\n"); - goto mem_err; - } - - cmgr->free_list_lock = kzalloc(sizeof(*cmgr->free_list_lock) * - arr_sz, GFP_KERNEL); - if (!cmgr->free_list_lock) { - printk(KERN_ERR PFX "failed to alloc free_list_lock\n"); - goto mem_err; - } - - cmgr->hba = hba; - cmgr->cmds = (struct bnx2fc_cmd **)(cmgr + 1); - - for (i = 0; i < arr_sz; i++) { - INIT_LIST_HEAD(&cmgr->free_list[i]); - spin_lock_init(&cmgr->free_list_lock[i]); - } - - /* - * Pre-allocated pool of bnx2fc_cmds. - * Last entry in the free list array is the free list - * of slow path requests. - */ - xid = BNX2FC_MIN_XID; - num_pri_ios = num_ios - BNX2FC_ELSTM_XIDS; - for (i = 0; i < num_ios; i++) { - io_req = kzalloc(sizeof(*io_req), GFP_KERNEL); - - if (!io_req) { - printk(KERN_ERR PFX "failed to alloc io_req\n"); - goto mem_err; - } - - INIT_LIST_HEAD(&io_req->link); - INIT_DELAYED_WORK(&io_req->timeout_work, bnx2fc_cmd_timeout); - - io_req->xid = xid++; - if (i < num_pri_ios) - list_add_tail(&io_req->link, - &cmgr->free_list[io_req->xid % - num_possible_cpus()]); - else - list_add_tail(&io_req->link, - &cmgr->free_list[num_possible_cpus()]); - io_req++; - } - - /* Allocate pool of io_bdts - one for each bnx2fc_cmd */ - mem_size = num_ios * sizeof(struct io_bdt *); - cmgr->io_bdt_pool = kmalloc(mem_size, GFP_KERNEL); - if (!cmgr->io_bdt_pool) { - printk(KERN_ERR PFX "failed to alloc io_bdt_pool\n"); - goto mem_err; - } - - mem_size = sizeof(struct io_bdt); - for (i = 0; i < num_ios; i++) { - cmgr->io_bdt_pool[i] = kmalloc(mem_size, GFP_KERNEL); - if (!cmgr->io_bdt_pool[i]) { - printk(KERN_ERR PFX "failed to alloc " - "io_bdt_pool[%d]\n", i); - goto mem_err; - } - } - - /* Allocate an map fcoe_bdt_ctx structures */ - bd_tbl_sz = BNX2FC_MAX_BDS_PER_CMD * sizeof(struct fcoe_bd_ctx); - for (i = 0; i < num_ios; i++) { - bdt_info = cmgr->io_bdt_pool[i]; - bdt_info->bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, - bd_tbl_sz, - &bdt_info->bd_tbl_dma, - GFP_KERNEL); - if (!bdt_info->bd_tbl) { - printk(KERN_ERR PFX "failed to alloc " - "bdt_tbl[%d]\n", i); - goto mem_err; - } - } - - return cmgr; - -mem_err: - bnx2fc_cmd_mgr_free(cmgr); - return NULL; -} - -void bnx2fc_cmd_mgr_free(struct bnx2fc_cmd_mgr *cmgr) -{ - struct io_bdt *bdt_info; - struct bnx2fc_hba *hba = cmgr->hba; - size_t bd_tbl_sz; - u16 min_xid = BNX2FC_MIN_XID; - u16 max_xid = BNX2FC_MAX_XID; - int num_ios; - int i; - - num_ios = max_xid - min_xid + 1; - - /* Free fcoe_bdt_ctx structures */ - if (!cmgr->io_bdt_pool) - goto free_cmd_pool; - - bd_tbl_sz = BNX2FC_MAX_BDS_PER_CMD * sizeof(struct fcoe_bd_ctx); - for (i = 0; i < num_ios; i++) { - bdt_info = cmgr->io_bdt_pool[i]; - if (bdt_info->bd_tbl) { - dma_free_coherent(&hba->pcidev->dev, bd_tbl_sz, - bdt_info->bd_tbl, - bdt_info->bd_tbl_dma); - bdt_info->bd_tbl = NULL; - } - } - - /* Destroy io_bdt pool */ - for (i = 0; i < num_ios; i++) { - kfree(cmgr->io_bdt_pool[i]); - cmgr->io_bdt_pool[i] = NULL; - } - - kfree(cmgr->io_bdt_pool); - cmgr->io_bdt_pool = NULL; - -free_cmd_pool: - kfree(cmgr->free_list_lock); - - /* Destroy cmd pool */ - if (!cmgr->free_list) - goto free_cmgr; - - for (i = 0; i < num_possible_cpus() + 1; i++) { - struct list_head *list; - struct list_head *tmp; - - list_for_each_safe(list, tmp, &cmgr->free_list[i]) { - struct bnx2fc_cmd *io_req = (struct bnx2fc_cmd *)list; - list_del(&io_req->link); - kfree(io_req); - } - } - kfree(cmgr->free_list); -free_cmgr: - /* Free command manager itself */ - kfree(cmgr); -} - -struct bnx2fc_cmd *bnx2fc_elstm_alloc(struct bnx2fc_rport *tgt, int type) -{ - struct fcoe_port *port = tgt->port; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_cmd_mgr *cmd_mgr = interface->hba->cmd_mgr; - struct bnx2fc_cmd *io_req; - struct list_head *listp; - struct io_bdt *bd_tbl; - int index = RESERVE_FREE_LIST_INDEX; - u32 free_sqes; - u32 max_sqes; - u16 xid; - - max_sqes = tgt->max_sqes; - switch (type) { - case BNX2FC_TASK_MGMT_CMD: - max_sqes = BNX2FC_TM_MAX_SQES; - break; - case BNX2FC_ELS: - max_sqes = BNX2FC_ELS_MAX_SQES; - break; - default: - break; - } - - /* - * NOTE: Free list insertions and deletions are protected with - * cmgr lock - */ - spin_lock_bh(&cmd_mgr->free_list_lock[index]); - free_sqes = atomic_read(&tgt->free_sqes); - if ((list_empty(&(cmd_mgr->free_list[index]))) || - (tgt->num_active_ios.counter >= max_sqes) || - (free_sqes + max_sqes <= BNX2FC_SQ_WQES_MAX)) { - BNX2FC_TGT_DBG(tgt, "No free els_tm cmds available " - "ios(%d):sqes(%d)\n", - tgt->num_active_ios.counter, tgt->max_sqes); - if (list_empty(&(cmd_mgr->free_list[index]))) - printk(KERN_ERR PFX "elstm_alloc: list_empty\n"); - spin_unlock_bh(&cmd_mgr->free_list_lock[index]); - return NULL; - } - - listp = (struct list_head *) - cmd_mgr->free_list[index].next; - list_del_init(listp); - io_req = (struct bnx2fc_cmd *) listp; - xid = io_req->xid; - cmd_mgr->cmds[xid] = io_req; - atomic_inc(&tgt->num_active_ios); - atomic_dec(&tgt->free_sqes); - spin_unlock_bh(&cmd_mgr->free_list_lock[index]); - - INIT_LIST_HEAD(&io_req->link); - - io_req->port = port; - io_req->cmd_mgr = cmd_mgr; - io_req->req_flags = 0; - io_req->cmd_type = type; - - /* Bind io_bdt for this io_req */ - /* Have a static link between io_req and io_bdt_pool */ - bd_tbl = io_req->bd_tbl = cmd_mgr->io_bdt_pool[xid]; - bd_tbl->io_req = io_req; - - /* Hold the io_req against deletion */ - kref_init(&io_req->refcount); - return io_req; -} - -struct bnx2fc_cmd *bnx2fc_cmd_alloc(struct bnx2fc_rport *tgt) -{ - struct fcoe_port *port = tgt->port; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_cmd_mgr *cmd_mgr = interface->hba->cmd_mgr; - struct bnx2fc_cmd *io_req; - struct list_head *listp; - struct io_bdt *bd_tbl; - u32 free_sqes; - u32 max_sqes; - u16 xid; - int index = get_cpu(); - - max_sqes = BNX2FC_SCSI_MAX_SQES; - /* - * NOTE: Free list insertions and deletions are protected with - * cmgr lock - */ - spin_lock_bh(&cmd_mgr->free_list_lock[index]); - free_sqes = atomic_read(&tgt->free_sqes); - if ((list_empty(&cmd_mgr->free_list[index])) || - (tgt->num_active_ios.counter >= max_sqes) || - (free_sqes + max_sqes <= BNX2FC_SQ_WQES_MAX)) { - spin_unlock_bh(&cmd_mgr->free_list_lock[index]); - put_cpu(); - return NULL; - } - - listp = (struct list_head *) - cmd_mgr->free_list[index].next; - list_del_init(listp); - io_req = (struct bnx2fc_cmd *) listp; - xid = io_req->xid; - cmd_mgr->cmds[xid] = io_req; - atomic_inc(&tgt->num_active_ios); - atomic_dec(&tgt->free_sqes); - spin_unlock_bh(&cmd_mgr->free_list_lock[index]); - put_cpu(); - - INIT_LIST_HEAD(&io_req->link); - - io_req->port = port; - io_req->cmd_mgr = cmd_mgr; - io_req->req_flags = 0; - - /* Bind io_bdt for this io_req */ - /* Have a static link between io_req and io_bdt_pool */ - bd_tbl = io_req->bd_tbl = cmd_mgr->io_bdt_pool[xid]; - bd_tbl->io_req = io_req; - - /* Hold the io_req against deletion */ - kref_init(&io_req->refcount); - return io_req; -} - -void bnx2fc_cmd_release(struct kref *ref) -{ - struct bnx2fc_cmd *io_req = container_of(ref, - struct bnx2fc_cmd, refcount); - struct bnx2fc_cmd_mgr *cmd_mgr = io_req->cmd_mgr; - int index; - - if (io_req->cmd_type == BNX2FC_SCSI_CMD) - index = io_req->xid % num_possible_cpus(); - else - index = RESERVE_FREE_LIST_INDEX; - - - spin_lock_bh(&cmd_mgr->free_list_lock[index]); - if (io_req->cmd_type != BNX2FC_SCSI_CMD) - bnx2fc_free_mp_resc(io_req); - cmd_mgr->cmds[io_req->xid] = NULL; - /* Delete IO from retire queue */ - list_del_init(&io_req->link); - /* Add it to the free list */ - list_add(&io_req->link, - &cmd_mgr->free_list[index]); - atomic_dec(&io_req->tgt->num_active_ios); - spin_unlock_bh(&cmd_mgr->free_list_lock[index]); - -} - -static void bnx2fc_free_mp_resc(struct bnx2fc_cmd *io_req) -{ - struct bnx2fc_mp_req *mp_req = &(io_req->mp_req); - struct bnx2fc_interface *interface = io_req->port->priv; - struct bnx2fc_hba *hba = interface->hba; - size_t sz = sizeof(struct fcoe_bd_ctx); - - /* clear tm flags */ - mp_req->tm_flags = 0; - if (mp_req->mp_req_bd) { - dma_free_coherent(&hba->pcidev->dev, sz, - mp_req->mp_req_bd, - mp_req->mp_req_bd_dma); - mp_req->mp_req_bd = NULL; - } - if (mp_req->mp_resp_bd) { - dma_free_coherent(&hba->pcidev->dev, sz, - mp_req->mp_resp_bd, - mp_req->mp_resp_bd_dma); - mp_req->mp_resp_bd = NULL; - } - if (mp_req->req_buf) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - mp_req->req_buf, - mp_req->req_buf_dma); - mp_req->req_buf = NULL; - } - if (mp_req->resp_buf) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - mp_req->resp_buf, - mp_req->resp_buf_dma); - mp_req->resp_buf = NULL; - } -} - -int bnx2fc_init_mp_req(struct bnx2fc_cmd *io_req) -{ - struct bnx2fc_mp_req *mp_req; - struct fcoe_bd_ctx *mp_req_bd; - struct fcoe_bd_ctx *mp_resp_bd; - struct bnx2fc_interface *interface = io_req->port->priv; - struct bnx2fc_hba *hba = interface->hba; - dma_addr_t addr; - size_t sz; - - mp_req = (struct bnx2fc_mp_req *)&(io_req->mp_req); - memset(mp_req, 0, sizeof(struct bnx2fc_mp_req)); - - mp_req->req_len = sizeof(struct fcp_cmnd); - io_req->data_xfer_len = mp_req->req_len; - mp_req->req_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, - &mp_req->req_buf_dma, - GFP_ATOMIC); - if (!mp_req->req_buf) { - printk(KERN_ERR PFX "unable to alloc MP req buffer\n"); - bnx2fc_free_mp_resc(io_req); - return FAILED; - } - - mp_req->resp_buf = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, - &mp_req->resp_buf_dma, - GFP_ATOMIC); - if (!mp_req->resp_buf) { - printk(KERN_ERR PFX "unable to alloc TM resp buffer\n"); - bnx2fc_free_mp_resc(io_req); - return FAILED; - } - memset(mp_req->req_buf, 0, PAGE_SIZE); - memset(mp_req->resp_buf, 0, PAGE_SIZE); - - /* Allocate and map mp_req_bd and mp_resp_bd */ - sz = sizeof(struct fcoe_bd_ctx); - mp_req->mp_req_bd = dma_alloc_coherent(&hba->pcidev->dev, sz, - &mp_req->mp_req_bd_dma, - GFP_ATOMIC); - if (!mp_req->mp_req_bd) { - printk(KERN_ERR PFX "unable to alloc MP req bd\n"); - bnx2fc_free_mp_resc(io_req); - return FAILED; - } - mp_req->mp_resp_bd = dma_alloc_coherent(&hba->pcidev->dev, sz, - &mp_req->mp_resp_bd_dma, - GFP_ATOMIC); - if (!mp_req->mp_req_bd) { - printk(KERN_ERR PFX "unable to alloc MP resp bd\n"); - bnx2fc_free_mp_resc(io_req); - return FAILED; - } - /* Fill bd table */ - addr = mp_req->req_buf_dma; - mp_req_bd = mp_req->mp_req_bd; - mp_req_bd->buf_addr_lo = (u32)addr & 0xffffffff; - mp_req_bd->buf_addr_hi = (u32)((u64)addr >> 32); - mp_req_bd->buf_len = PAGE_SIZE; - mp_req_bd->flags = 0; - - /* - * MP buffer is either a task mgmt command or an ELS. - * So the assumption is that it consumes a single bd - * entry in the bd table - */ - mp_resp_bd = mp_req->mp_resp_bd; - addr = mp_req->resp_buf_dma; - mp_resp_bd->buf_addr_lo = (u32)addr & 0xffffffff; - mp_resp_bd->buf_addr_hi = (u32)((u64)addr >> 32); - mp_resp_bd->buf_len = PAGE_SIZE; - mp_resp_bd->flags = 0; - - return SUCCESS; -} - -static int bnx2fc_initiate_tmf(struct scsi_cmnd *sc_cmd, u8 tm_flags) -{ - struct fc_lport *lport; - struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); - struct fc_rport_libfc_priv *rp = rport->dd_data; - struct fcoe_port *port; - struct bnx2fc_interface *interface; - struct bnx2fc_rport *tgt; - struct bnx2fc_cmd *io_req; - struct bnx2fc_mp_req *tm_req; - struct fcoe_task_ctx_entry *task; - struct fcoe_task_ctx_entry *task_page; - struct Scsi_Host *host = sc_cmd->device->host; - struct fc_frame_header *fc_hdr; - struct fcp_cmnd *fcp_cmnd; - int task_idx, index; - int rc = SUCCESS; - u16 xid; - u32 sid, did; - unsigned long start = jiffies; - - lport = shost_priv(host); - port = lport_priv(lport); - interface = port->priv; - - if (rport == NULL) { - printk(KERN_ERR PFX "device_reset: rport is NULL\n"); - rc = FAILED; - goto tmf_err; - } - - rc = fc_block_scsi_eh(sc_cmd); - if (rc) - return rc; - - if (lport->state != LPORT_ST_READY || !(lport->link_up)) { - printk(KERN_ERR PFX "device_reset: link is not ready\n"); - rc = FAILED; - goto tmf_err; - } - /* rport and tgt are allocated together, so tgt should be non-NULL */ - tgt = (struct bnx2fc_rport *)&rp[1]; - - if (!(test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags))) { - printk(KERN_ERR PFX "device_reset: tgt not offloaded\n"); - rc = FAILED; - goto tmf_err; - } -retry_tmf: - io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_TASK_MGMT_CMD); - if (!io_req) { - if (time_after(jiffies, start + HZ)) { - printk(KERN_ERR PFX "tmf: Failed TMF"); - rc = FAILED; - goto tmf_err; - } - msleep(20); - goto retry_tmf; - } - /* Initialize rest of io_req fields */ - io_req->sc_cmd = sc_cmd; - io_req->port = port; - io_req->tgt = tgt; - - tm_req = (struct bnx2fc_mp_req *)&(io_req->mp_req); - - rc = bnx2fc_init_mp_req(io_req); - if (rc == FAILED) { - printk(KERN_ERR PFX "Task mgmt MP request init failed\n"); - spin_lock_bh(&tgt->tgt_lock); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - goto tmf_err; - } - - /* Set TM flags */ - io_req->io_req_flags = 0; - tm_req->tm_flags = tm_flags; - - /* Fill FCP_CMND */ - bnx2fc_build_fcp_cmnd(io_req, (struct fcp_cmnd *)tm_req->req_buf); - fcp_cmnd = (struct fcp_cmnd *)tm_req->req_buf; - memset(fcp_cmnd->fc_cdb, 0, sc_cmd->cmd_len); - fcp_cmnd->fc_dl = 0; - - /* Fill FC header */ - fc_hdr = &(tm_req->req_fc_hdr); - sid = tgt->sid; - did = rport->port_id; - __fc_fill_fc_hdr(fc_hdr, FC_RCTL_DD_UNSOL_CMD, did, sid, - FC_TYPE_FCP, FC_FC_FIRST_SEQ | FC_FC_END_SEQ | - FC_FC_SEQ_INIT, 0); - /* Obtain exchange id */ - xid = io_req->xid; - - BNX2FC_TGT_DBG(tgt, "Initiate TMF - xid = 0x%x\n", xid); - task_idx = xid/BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - - /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[task_idx]; - task = &(task_page[index]); - bnx2fc_init_mp_task(io_req, task); - - sc_cmd->SCp.ptr = (char *)io_req; - - /* Obtain free SQ entry */ - spin_lock_bh(&tgt->tgt_lock); - bnx2fc_add_2_sq(tgt, xid); - - /* Enqueue the io_req to active_tm_queue */ - io_req->on_tmf_queue = 1; - list_add_tail(&io_req->link, &tgt->active_tm_queue); - - init_completion(&io_req->tm_done); - io_req->wait_for_comp = 1; - - /* Ring doorbell */ - bnx2fc_ring_doorbell(tgt); - spin_unlock_bh(&tgt->tgt_lock); - - rc = wait_for_completion_timeout(&io_req->tm_done, - BNX2FC_TM_TIMEOUT * HZ); - spin_lock_bh(&tgt->tgt_lock); - - io_req->wait_for_comp = 0; - if (!(test_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags))) - set_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags); - - spin_unlock_bh(&tgt->tgt_lock); - - if (!rc) { - BNX2FC_TGT_DBG(tgt, "task mgmt command failed...\n"); - rc = FAILED; - } else { - BNX2FC_TGT_DBG(tgt, "task mgmt command success...\n"); - rc = SUCCESS; - } -tmf_err: - return rc; -} - -int bnx2fc_initiate_abts(struct bnx2fc_cmd *io_req) -{ - struct fc_lport *lport; - struct bnx2fc_rport *tgt = io_req->tgt; - struct fc_rport *rport = tgt->rport; - struct fc_rport_priv *rdata = tgt->rdata; - struct bnx2fc_interface *interface; - struct fcoe_port *port; - struct bnx2fc_cmd *abts_io_req; - struct fcoe_task_ctx_entry *task; - struct fcoe_task_ctx_entry *task_page; - struct fc_frame_header *fc_hdr; - struct bnx2fc_mp_req *abts_req; - int task_idx, index; - u32 sid, did; - u16 xid; - int rc = SUCCESS; - u32 r_a_tov = rdata->r_a_tov; - - /* called with tgt_lock held */ - BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_abts\n"); - - port = io_req->port; - interface = port->priv; - lport = port->lport; - - if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { - printk(KERN_ERR PFX "initiate_abts: tgt not offloaded\n"); - rc = FAILED; - goto abts_err; - } - - if (rport == NULL) { - printk(KERN_ERR PFX "initiate_abts: rport is NULL\n"); - rc = FAILED; - goto abts_err; - } - - if (lport->state != LPORT_ST_READY || !(lport->link_up)) { - printk(KERN_ERR PFX "initiate_abts: link is not ready\n"); - rc = FAILED; - goto abts_err; - } - - abts_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_ABTS); - if (!abts_io_req) { - printk(KERN_ERR PFX "abts: couldnt allocate cmd\n"); - rc = FAILED; - goto abts_err; - } - - /* Initialize rest of io_req fields */ - abts_io_req->sc_cmd = NULL; - abts_io_req->port = port; - abts_io_req->tgt = tgt; - abts_io_req->data_xfer_len = 0; /* No data transfer for ABTS */ - - abts_req = (struct bnx2fc_mp_req *)&(abts_io_req->mp_req); - memset(abts_req, 0, sizeof(struct bnx2fc_mp_req)); - - /* Fill FC header */ - fc_hdr = &(abts_req->req_fc_hdr); - - /* Obtain oxid and rxid for the original exchange to be aborted */ - fc_hdr->fh_ox_id = htons(io_req->xid); - fc_hdr->fh_rx_id = htons(io_req->task->rxwr_txrd.var_ctx.rx_id); - - sid = tgt->sid; - did = rport->port_id; - - __fc_fill_fc_hdr(fc_hdr, FC_RCTL_BA_ABTS, did, sid, - FC_TYPE_BLS, FC_FC_FIRST_SEQ | FC_FC_END_SEQ | - FC_FC_SEQ_INIT, 0); - - xid = abts_io_req->xid; - BNX2FC_IO_DBG(abts_io_req, "ABTS io_req\n"); - task_idx = xid/BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - - /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[task_idx]; - task = &(task_page[index]); - bnx2fc_init_mp_task(abts_io_req, task); - - /* - * ABTS task is a temporary task that will be cleaned up - * irrespective of ABTS response. We need to start the timer - * for the original exchange, as the CQE is posted for the original - * IO request. - * - * Timer for ABTS is started only when it is originated by a - * TM request. For the ABTS issued as part of ULP timeout, - * scsi-ml maintains the timers. - */ - - /* if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags))*/ - bnx2fc_cmd_timer_set(io_req, 2 * r_a_tov); - - /* Obtain free SQ entry */ - bnx2fc_add_2_sq(tgt, xid); - - /* Ring doorbell */ - bnx2fc_ring_doorbell(tgt); - -abts_err: - return rc; -} - -int bnx2fc_initiate_seq_cleanup(struct bnx2fc_cmd *orig_io_req, u32 offset, - enum fc_rctl r_ctl) -{ - struct fc_lport *lport; - struct bnx2fc_rport *tgt = orig_io_req->tgt; - struct bnx2fc_interface *interface; - struct fcoe_port *port; - struct bnx2fc_cmd *seq_clnp_req; - struct fcoe_task_ctx_entry *task; - struct fcoe_task_ctx_entry *task_page; - struct bnx2fc_els_cb_arg *cb_arg = NULL; - int task_idx, index; - u16 xid; - int rc = 0; - - BNX2FC_IO_DBG(orig_io_req, "bnx2fc_initiate_seq_cleanup xid = 0x%x\n", - orig_io_req->xid); - kref_get(&orig_io_req->refcount); - - port = orig_io_req->port; - interface = port->priv; - lport = port->lport; - - cb_arg = kzalloc(sizeof(struct bnx2fc_els_cb_arg), GFP_ATOMIC); - if (!cb_arg) { - printk(KERN_ERR PFX "Unable to alloc cb_arg for seq clnup\n"); - rc = -ENOMEM; - goto cleanup_err; - } - - seq_clnp_req = bnx2fc_elstm_alloc(tgt, BNX2FC_SEQ_CLEANUP); - if (!seq_clnp_req) { - printk(KERN_ERR PFX "cleanup: couldnt allocate cmd\n"); - rc = -ENOMEM; - kfree(cb_arg); - goto cleanup_err; - } - /* Initialize rest of io_req fields */ - seq_clnp_req->sc_cmd = NULL; - seq_clnp_req->port = port; - seq_clnp_req->tgt = tgt; - seq_clnp_req->data_xfer_len = 0; /* No data transfer for cleanup */ - - xid = seq_clnp_req->xid; - - task_idx = xid/BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - - /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[task_idx]; - task = &(task_page[index]); - cb_arg->aborted_io_req = orig_io_req; - cb_arg->io_req = seq_clnp_req; - cb_arg->r_ctl = r_ctl; - cb_arg->offset = offset; - seq_clnp_req->cb_arg = cb_arg; - - printk(KERN_ERR PFX "call init_seq_cleanup_task\n"); - bnx2fc_init_seq_cleanup_task(seq_clnp_req, task, orig_io_req, offset); - - /* Obtain free SQ entry */ - bnx2fc_add_2_sq(tgt, xid); - - /* Ring doorbell */ - bnx2fc_ring_doorbell(tgt); -cleanup_err: - return rc; -} - -int bnx2fc_initiate_cleanup(struct bnx2fc_cmd *io_req) -{ - struct fc_lport *lport; - struct bnx2fc_rport *tgt = io_req->tgt; - struct bnx2fc_interface *interface; - struct fcoe_port *port; - struct bnx2fc_cmd *cleanup_io_req; - struct fcoe_task_ctx_entry *task; - struct fcoe_task_ctx_entry *task_page; - int task_idx, index; - u16 xid, orig_xid; - int rc = 0; - - /* ASSUMPTION: called with tgt_lock held */ - BNX2FC_IO_DBG(io_req, "Entered bnx2fc_initiate_cleanup\n"); - - port = io_req->port; - interface = port->priv; - lport = port->lport; - - cleanup_io_req = bnx2fc_elstm_alloc(tgt, BNX2FC_CLEANUP); - if (!cleanup_io_req) { - printk(KERN_ERR PFX "cleanup: couldnt allocate cmd\n"); - rc = -1; - goto cleanup_err; - } - - /* Initialize rest of io_req fields */ - cleanup_io_req->sc_cmd = NULL; - cleanup_io_req->port = port; - cleanup_io_req->tgt = tgt; - cleanup_io_req->data_xfer_len = 0; /* No data transfer for cleanup */ - - xid = cleanup_io_req->xid; - - task_idx = xid/BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - - /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) - interface->hba->task_ctx[task_idx]; - task = &(task_page[index]); - orig_xid = io_req->xid; - - BNX2FC_IO_DBG(io_req, "CLEANUP io_req xid = 0x%x\n", xid); - - bnx2fc_init_cleanup_task(cleanup_io_req, task, orig_xid); - - /* Obtain free SQ entry */ - bnx2fc_add_2_sq(tgt, xid); - - /* Ring doorbell */ - bnx2fc_ring_doorbell(tgt); - -cleanup_err: - return rc; -} - -/** - * bnx2fc_eh_target_reset: Reset a target - * - * @sc_cmd: SCSI command - * - * Set from SCSI host template to send task mgmt command to the target - * and wait for the response - */ -int bnx2fc_eh_target_reset(struct scsi_cmnd *sc_cmd) -{ - return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_TGT_RESET); -} - -/** - * bnx2fc_eh_device_reset - Reset a single LUN - * - * @sc_cmd: SCSI command - * - * Set from SCSI host template to send task mgmt command to the target - * and wait for the response - */ -int bnx2fc_eh_device_reset(struct scsi_cmnd *sc_cmd) -{ - return bnx2fc_initiate_tmf(sc_cmd, FCP_TMF_LUN_RESET); -} - -/** - * bnx2fc_eh_abort - eh_abort_handler api to abort an outstanding - * SCSI command - * - * @sc_cmd: SCSI_ML command pointer - * - * SCSI abort request handler - */ -int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) -{ - struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); - struct fc_rport_libfc_priv *rp = rport->dd_data; - struct bnx2fc_cmd *io_req; - struct fc_lport *lport; - struct fc_rport_priv *rdata; - struct bnx2fc_rport *tgt; - int logo_issued; - int wait_cnt = 0; - int rc = FAILED; - - - rc = fc_block_scsi_eh(sc_cmd); - if (rc) - return rc; - - lport = shost_priv(sc_cmd->device->host); - if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) { - printk(KERN_ERR PFX "eh_abort: link not ready\n"); - return rc; - } - - tgt = (struct bnx2fc_rport *)&rp[1]; - - BNX2FC_TGT_DBG(tgt, "Entered bnx2fc_eh_abort\n"); - - spin_lock_bh(&tgt->tgt_lock); - io_req = (struct bnx2fc_cmd *)sc_cmd->SCp.ptr; - if (!io_req) { - /* Command might have just completed */ - printk(KERN_ERR PFX "eh_abort: io_req is NULL\n"); - spin_unlock_bh(&tgt->tgt_lock); - return SUCCESS; - } - BNX2FC_IO_DBG(io_req, "eh_abort - refcnt = %d\n", - io_req->refcount.refcount.counter); - - /* Hold IO request across abort processing */ - kref_get(&io_req->refcount); - - BUG_ON(tgt != io_req->tgt); - - /* Remove the io_req from the active_q. */ - /* - * Task Mgmt functions (LUN RESET & TGT RESET) will not - * issue an ABTS on this particular IO req, as the - * io_req is no longer in the active_q. - */ - if (tgt->flush_in_prog) { - printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " - "flush in progress\n", io_req->xid); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return SUCCESS; - } - - if (io_req->on_active_queue == 0) { - printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " - "not on active_q\n", io_req->xid); - /* - * This condition can happen only due to the FW bug, - * where we do not receive cleanup response from - * the FW. Handle this case gracefully by erroring - * back the IO request to SCSI-ml - */ - bnx2fc_scsi_done(io_req, DID_ABORT); - - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return SUCCESS; - } - - /* - * Only eh_abort processing will remove the IO from - * active_cmd_q before processing the request. this is - * done to avoid race conditions between IOs aborted - * as part of task management completion and eh_abort - * processing - */ - list_del_init(&io_req->link); - io_req->on_active_queue = 0; - /* Move IO req to retire queue */ - list_add_tail(&io_req->link, &tgt->io_retire_queue); - - init_completion(&io_req->tm_done); - io_req->wait_for_comp = 1; - - if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) { - /* Cancel the current timer running on this io_req */ - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* drop timer hold */ - set_bit(BNX2FC_FLAG_EH_ABORT, &io_req->req_flags); - rc = bnx2fc_initiate_abts(io_req); - } else { - printk(KERN_ERR PFX "eh_abort: io_req (xid = 0x%x) " - "already in abts processing\n", io_req->xid); - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* drop timer hold */ - bnx2fc_initiate_cleanup(io_req); - - spin_unlock_bh(&tgt->tgt_lock); - - wait_for_completion(&io_req->tm_done); - - spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; - rdata = io_req->tgt->rdata; - logo_issued = test_and_set_bit(BNX2FC_FLAG_EXPL_LOGO, - &tgt->flags); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - - if (!logo_issued) { - BNX2FC_IO_DBG(io_req, "Expl logo - tgt flags = 0x%lx\n", - tgt->flags); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_logoff(rdata); - mutex_unlock(&lport->disc.disc_mutex); - do { - msleep(BNX2FC_RELOGIN_WAIT_TIME); - /* - * If session not recovered, let SCSI-ml - * escalate error recovery. - */ - if (wait_cnt++ > BNX2FC_RELOGIN_WAIT_CNT) - return FAILED; - } while (!test_bit(BNX2FC_FLAG_SESSION_READY, - &tgt->flags)); - } - return SUCCESS; - } - if (rc == FAILED) { - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return rc; - } - spin_unlock_bh(&tgt->tgt_lock); - - wait_for_completion(&io_req->tm_done); - - spin_lock_bh(&tgt->tgt_lock); - io_req->wait_for_comp = 0; - if (!(test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, - &io_req->req_flags))) { - /* Let the scsi-ml try to recover this command */ - printk(KERN_ERR PFX "abort failed, xid = 0x%x\n", - io_req->xid); - rc = FAILED; - } else { - /* - * We come here even when there was a race condition - * between timeout and abts completion, and abts - * completion happens just in time. - */ - BNX2FC_IO_DBG(io_req, "abort succeeded\n"); - rc = SUCCESS; - bnx2fc_scsi_done(io_req, DID_ABORT); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - } - - /* release the reference taken in eh_abort */ - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return rc; -} - -void bnx2fc_process_seq_cleanup_compl(struct bnx2fc_cmd *seq_clnp_req, - struct fcoe_task_ctx_entry *task, - u8 rx_state) -{ - struct bnx2fc_els_cb_arg *cb_arg = seq_clnp_req->cb_arg; - struct bnx2fc_cmd *orig_io_req = cb_arg->aborted_io_req; - u32 offset = cb_arg->offset; - enum fc_rctl r_ctl = cb_arg->r_ctl; - int rc = 0; - struct bnx2fc_rport *tgt = orig_io_req->tgt; - - BNX2FC_IO_DBG(orig_io_req, "Entered process_cleanup_compl xid = 0x%x" - "cmd_type = %d\n", - seq_clnp_req->xid, seq_clnp_req->cmd_type); - - if (rx_state == FCOE_TASK_RX_STATE_IGNORED_SEQUENCE_CLEANUP) { - printk(KERN_ERR PFX "seq cleanup ignored - xid = 0x%x\n", - seq_clnp_req->xid); - goto free_cb_arg; - } - - spin_unlock_bh(&tgt->tgt_lock); - rc = bnx2fc_send_srr(orig_io_req, offset, r_ctl); - spin_lock_bh(&tgt->tgt_lock); - - if (rc) - printk(KERN_ERR PFX "clnup_compl: Unable to send SRR" - " IO will abort\n"); - seq_clnp_req->cb_arg = NULL; - kref_put(&orig_io_req->refcount, bnx2fc_cmd_release); -free_cb_arg: - kfree(cb_arg); - return; -} - -void bnx2fc_process_cleanup_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u8 num_rq) -{ - BNX2FC_IO_DBG(io_req, "Entered process_cleanup_compl " - "refcnt = %d, cmd_type = %d\n", - io_req->refcount.refcount.counter, io_req->cmd_type); - bnx2fc_scsi_done(io_req, DID_ERROR); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - if (io_req->wait_for_comp) - complete(&io_req->tm_done); -} - -void bnx2fc_process_abts_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u8 num_rq) -{ - u32 r_ctl; - u32 r_a_tov = FC_DEF_R_A_TOV; - u8 issue_rrq = 0; - struct bnx2fc_rport *tgt = io_req->tgt; - - BNX2FC_IO_DBG(io_req, "Entered process_abts_compl xid = 0x%x" - "refcnt = %d, cmd_type = %d\n", - io_req->xid, - io_req->refcount.refcount.counter, io_req->cmd_type); - - if (test_and_set_bit(BNX2FC_FLAG_ABTS_DONE, - &io_req->req_flags)) { - BNX2FC_IO_DBG(io_req, "Timer context finished processing" - " this io\n"); - return; - } - - /* Do not issue RRQ as this IO is already cleanedup */ - if (test_and_set_bit(BNX2FC_FLAG_IO_CLEANUP, - &io_req->req_flags)) - goto io_compl; - - /* - * For ABTS issued due to SCSI eh_abort_handler, timeout - * values are maintained by scsi-ml itself. Cancel timeout - * in case ABTS issued as part of task management function - * or due to FW error. - */ - if (test_bit(BNX2FC_FLAG_ISSUE_ABTS, &io_req->req_flags)) - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* drop timer hold */ - - r_ctl = (u8)task->rxwr_only.union_ctx.comp_info.abts_rsp.r_ctl; - - switch (r_ctl) { - case FC_RCTL_BA_ACC: - /* - * Dont release this cmd yet. It will be relesed - * after we get RRQ response - */ - BNX2FC_IO_DBG(io_req, "ABTS response - ACC Send RRQ\n"); - issue_rrq = 1; - break; - - case FC_RCTL_BA_RJT: - BNX2FC_IO_DBG(io_req, "ABTS response - RJT\n"); - break; - default: - printk(KERN_ERR PFX "Unknown ABTS response\n"); - break; - } - - if (issue_rrq) { - BNX2FC_IO_DBG(io_req, "Issue RRQ after R_A_TOV\n"); - set_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags); - } - set_bit(BNX2FC_FLAG_RETIRE_OXID, &io_req->req_flags); - bnx2fc_cmd_timer_set(io_req, r_a_tov); - -io_compl: - if (io_req->wait_for_comp) { - if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, - &io_req->req_flags)) - complete(&io_req->tm_done); - } else { - /* - * We end up here when ABTS is issued as - * in asynchronous context, i.e., as part - * of task management completion, or - * when FW error is received or when the - * ABTS is issued when the IO is timed - * out. - */ - - if (io_req->on_active_queue) { - list_del_init(&io_req->link); - io_req->on_active_queue = 0; - /* Move IO req to retire queue */ - list_add_tail(&io_req->link, &tgt->io_retire_queue); - } - bnx2fc_scsi_done(io_req, DID_ERROR); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - } -} - -static void bnx2fc_lun_reset_cmpl(struct bnx2fc_cmd *io_req) -{ - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - struct bnx2fc_rport *tgt = io_req->tgt; - struct list_head *list; - struct list_head *tmp; - struct bnx2fc_cmd *cmd; - int tm_lun = sc_cmd->device->lun; - int rc = 0; - int lun; - - /* called with tgt_lock held */ - BNX2FC_IO_DBG(io_req, "Entered bnx2fc_lun_reset_cmpl\n"); - /* - * Walk thru the active_ios queue and ABORT the IO - * that matches with the LUN that was reset - */ - list_for_each_safe(list, tmp, &tgt->active_cmd_queue) { - BNX2FC_TGT_DBG(tgt, "LUN RST cmpl: scan for pending IOs\n"); - cmd = (struct bnx2fc_cmd *)list; - lun = cmd->sc_cmd->device->lun; - if (lun == tm_lun) { - /* Initiate ABTS on this cmd */ - if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, - &cmd->req_flags)) { - /* cancel the IO timeout */ - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); - /* timer hold */ - rc = bnx2fc_initiate_abts(cmd); - /* abts shouldn't fail in this context */ - WARN_ON(rc != SUCCESS); - } else - printk(KERN_ERR PFX "lun_rst: abts already in" - " progress for this IO 0x%x\n", - cmd->xid); - } - } -} - -static void bnx2fc_tgt_reset_cmpl(struct bnx2fc_cmd *io_req) -{ - struct bnx2fc_rport *tgt = io_req->tgt; - struct list_head *list; - struct list_head *tmp; - struct bnx2fc_cmd *cmd; - int rc = 0; - - /* called with tgt_lock held */ - BNX2FC_IO_DBG(io_req, "Entered bnx2fc_tgt_reset_cmpl\n"); - /* - * Walk thru the active_ios queue and ABORT the IO - * that matches with the LUN that was reset - */ - list_for_each_safe(list, tmp, &tgt->active_cmd_queue) { - BNX2FC_TGT_DBG(tgt, "TGT RST cmpl: scan for pending IOs\n"); - cmd = (struct bnx2fc_cmd *)list; - /* Initiate ABTS */ - if (!test_and_set_bit(BNX2FC_FLAG_ISSUE_ABTS, - &cmd->req_flags)) { - /* cancel the IO timeout */ - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* timer hold */ - rc = bnx2fc_initiate_abts(cmd); - /* abts shouldn't fail in this context */ - WARN_ON(rc != SUCCESS); - - } else - printk(KERN_ERR PFX "tgt_rst: abts already in progress" - " for this IO 0x%x\n", cmd->xid); - } -} - -void bnx2fc_process_tm_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, u8 num_rq) -{ - struct bnx2fc_mp_req *tm_req; - struct fc_frame_header *fc_hdr; - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - u64 *hdr; - u64 *temp_hdr; - void *rsp_buf; - - /* Called with tgt_lock held */ - BNX2FC_IO_DBG(io_req, "Entered process_tm_compl\n"); - - if (!(test_bit(BNX2FC_FLAG_TM_TIMEOUT, &io_req->req_flags))) - set_bit(BNX2FC_FLAG_TM_COMPL, &io_req->req_flags); - else { - /* TM has already timed out and we got - * delayed completion. Ignore completion - * processing. - */ - return; - } - - tm_req = &(io_req->mp_req); - fc_hdr = &(tm_req->resp_fc_hdr); - hdr = (u64 *)fc_hdr; - temp_hdr = (u64 *) - &task->rxwr_only.union_ctx.comp_info.mp_rsp.fc_hdr; - hdr[0] = cpu_to_be64(temp_hdr[0]); - hdr[1] = cpu_to_be64(temp_hdr[1]); - hdr[2] = cpu_to_be64(temp_hdr[2]); - - tm_req->resp_len = - task->rxwr_only.union_ctx.comp_info.mp_rsp.mp_payload_len; - - rsp_buf = tm_req->resp_buf; - - if (fc_hdr->fh_r_ctl == FC_RCTL_DD_CMD_STATUS) { - bnx2fc_parse_fcp_rsp(io_req, - (struct fcoe_fcp_rsp_payload *) - rsp_buf, num_rq); - if (io_req->fcp_rsp_code == 0) { - /* TM successful */ - if (tm_req->tm_flags & FCP_TMF_LUN_RESET) - bnx2fc_lun_reset_cmpl(io_req); - else if (tm_req->tm_flags & FCP_TMF_TGT_RESET) - bnx2fc_tgt_reset_cmpl(io_req); - } - } else { - printk(KERN_ERR PFX "tmf's fc_hdr r_ctl = 0x%x\n", - fc_hdr->fh_r_ctl); - } - if (!sc_cmd->SCp.ptr) { - printk(KERN_ERR PFX "tm_compl: SCp.ptr is NULL\n"); - return; - } - switch (io_req->fcp_status) { - case FC_GOOD: - if (io_req->cdb_status == 0) { - /* Good IO completion */ - sc_cmd->result = DID_OK << 16; - } else { - /* Transport status is good, SCSI status not good */ - sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; - } - if (io_req->fcp_resid) - scsi_set_resid(sc_cmd, io_req->fcp_resid); - break; - - default: - BNX2FC_IO_DBG(io_req, "process_tm_compl: fcp_status = %d\n", - io_req->fcp_status); - break; - } - - sc_cmd = io_req->sc_cmd; - io_req->sc_cmd = NULL; - - /* check if the io_req exists in tgt's tmf_q */ - if (io_req->on_tmf_queue) { - - list_del_init(&io_req->link); - io_req->on_tmf_queue = 0; - } else { - - printk(KERN_ERR PFX "Command not on active_cmd_queue!\n"); - return; - } - - sc_cmd->SCp.ptr = NULL; - sc_cmd->scsi_done(sc_cmd); - - kref_put(&io_req->refcount, bnx2fc_cmd_release); - if (io_req->wait_for_comp) { - BNX2FC_IO_DBG(io_req, "tm_compl - wake up the waiter\n"); - complete(&io_req->tm_done); - } -} - -static int bnx2fc_split_bd(struct bnx2fc_cmd *io_req, u64 addr, int sg_len, - int bd_index) -{ - struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl; - int frag_size, sg_frags; - - sg_frags = 0; - while (sg_len) { - if (sg_len >= BNX2FC_BD_SPLIT_SZ) - frag_size = BNX2FC_BD_SPLIT_SZ; - else - frag_size = sg_len; - bd[bd_index + sg_frags].buf_addr_lo = addr & 0xffffffff; - bd[bd_index + sg_frags].buf_addr_hi = addr >> 32; - bd[bd_index + sg_frags].buf_len = (u16)frag_size; - bd[bd_index + sg_frags].flags = 0; - - addr += (u64) frag_size; - sg_frags++; - sg_len -= frag_size; - } - return sg_frags; - -} - -static int bnx2fc_map_sg(struct bnx2fc_cmd *io_req) -{ - struct bnx2fc_interface *interface = io_req->port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct scsi_cmnd *sc = io_req->sc_cmd; - struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl; - struct scatterlist *sg; - int byte_count = 0; - int sg_count = 0; - int bd_count = 0; - int sg_frags; - unsigned int sg_len; - u64 addr; - int i; - - sg_count = dma_map_sg(&hba->pcidev->dev, scsi_sglist(sc), - scsi_sg_count(sc), sc->sc_data_direction); - scsi_for_each_sg(sc, sg, sg_count, i) { - sg_len = sg_dma_len(sg); - addr = sg_dma_address(sg); - if (sg_len > BNX2FC_MAX_BD_LEN) { - sg_frags = bnx2fc_split_bd(io_req, addr, sg_len, - bd_count); - } else { - - sg_frags = 1; - bd[bd_count].buf_addr_lo = addr & 0xffffffff; - bd[bd_count].buf_addr_hi = addr >> 32; - bd[bd_count].buf_len = (u16)sg_len; - bd[bd_count].flags = 0; - } - bd_count += sg_frags; - byte_count += sg_len; - } - if (byte_count != scsi_bufflen(sc)) - printk(KERN_ERR PFX "byte_count = %d != scsi_bufflen = %d, " - "task_id = 0x%x\n", byte_count, scsi_bufflen(sc), - io_req->xid); - return bd_count; -} - -static int bnx2fc_build_bd_list_from_sg(struct bnx2fc_cmd *io_req) -{ - struct scsi_cmnd *sc = io_req->sc_cmd; - struct fcoe_bd_ctx *bd = io_req->bd_tbl->bd_tbl; - int bd_count; - - if (scsi_sg_count(sc)) { - bd_count = bnx2fc_map_sg(io_req); - if (bd_count == 0) - return -ENOMEM; - } else { - bd_count = 0; - bd[0].buf_addr_lo = bd[0].buf_addr_hi = 0; - bd[0].buf_len = bd[0].flags = 0; - } - io_req->bd_tbl->bd_valid = bd_count; - - return 0; -} - -static void bnx2fc_unmap_sg_list(struct bnx2fc_cmd *io_req) -{ - struct scsi_cmnd *sc = io_req->sc_cmd; - - if (io_req->bd_tbl->bd_valid && sc) { - scsi_dma_unmap(sc); - io_req->bd_tbl->bd_valid = 0; - } -} - -void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req, - struct fcp_cmnd *fcp_cmnd) -{ - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - char tag[2]; - - memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd)); - - int_to_scsilun(sc_cmd->device->lun, &fcp_cmnd->fc_lun); - - fcp_cmnd->fc_dl = htonl(io_req->data_xfer_len); - memcpy(fcp_cmnd->fc_cdb, sc_cmd->cmnd, sc_cmd->cmd_len); - - fcp_cmnd->fc_cmdref = 0; - fcp_cmnd->fc_pri_ta = 0; - fcp_cmnd->fc_tm_flags = io_req->mp_req.tm_flags; - fcp_cmnd->fc_flags = io_req->io_req_flags; - - if (scsi_populate_tag_msg(sc_cmd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - fcp_cmnd->fc_pri_ta = FCP_PTA_HEADQ; - break; - case ORDERED_QUEUE_TAG: - fcp_cmnd->fc_pri_ta = FCP_PTA_ORDERED; - break; - default: - fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE; - break; - } - } else { - fcp_cmnd->fc_pri_ta = 0; - } -} - -static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req, - struct fcoe_fcp_rsp_payload *fcp_rsp, - u8 num_rq) -{ - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - struct bnx2fc_rport *tgt = io_req->tgt; - u8 rsp_flags = fcp_rsp->fcp_flags.flags; - u32 rq_buff_len = 0; - int i; - unsigned char *rq_data; - unsigned char *dummy; - int fcp_sns_len = 0; - int fcp_rsp_len = 0; - - io_req->fcp_status = FC_GOOD; - io_req->fcp_resid = fcp_rsp->fcp_resid; - - io_req->scsi_comp_flags = rsp_flags; - CMD_SCSI_STATUS(sc_cmd) = io_req->cdb_status = - fcp_rsp->scsi_status_code; - - /* Fetch fcp_rsp_info and fcp_sns_info if available */ - if (num_rq) { - - /* - * We do not anticipate num_rq >1, as the linux defined - * SCSI_SENSE_BUFFERSIZE is 96 bytes + 8 bytes of FCP_RSP_INFO - * 256 bytes of single rq buffer is good enough to hold this. - */ - - if (rsp_flags & - FCOE_FCP_RSP_FLAGS_FCP_RSP_LEN_VALID) { - fcp_rsp_len = rq_buff_len - = fcp_rsp->fcp_rsp_len; - } - - if (rsp_flags & - FCOE_FCP_RSP_FLAGS_FCP_SNS_LEN_VALID) { - fcp_sns_len = fcp_rsp->fcp_sns_len; - rq_buff_len += fcp_rsp->fcp_sns_len; - } - - io_req->fcp_rsp_len = fcp_rsp_len; - io_req->fcp_sns_len = fcp_sns_len; - - if (rq_buff_len > num_rq * BNX2FC_RQ_BUF_SZ) { - /* Invalid sense sense length. */ - printk(KERN_ERR PFX "invalid sns length %d\n", - rq_buff_len); - /* reset rq_buff_len */ - rq_buff_len = num_rq * BNX2FC_RQ_BUF_SZ; - } - - rq_data = bnx2fc_get_next_rqe(tgt, 1); - - if (num_rq > 1) { - /* We do not need extra sense data */ - for (i = 1; i < num_rq; i++) - dummy = bnx2fc_get_next_rqe(tgt, 1); - } - - /* fetch fcp_rsp_code */ - if ((fcp_rsp_len == 4) || (fcp_rsp_len == 8)) { - /* Only for task management function */ - io_req->fcp_rsp_code = rq_data[3]; - printk(KERN_ERR PFX "fcp_rsp_code = %d\n", - io_req->fcp_rsp_code); - } - - /* fetch sense data */ - rq_data += fcp_rsp_len; - - if (fcp_sns_len > SCSI_SENSE_BUFFERSIZE) { - printk(KERN_ERR PFX "Truncating sense buffer\n"); - fcp_sns_len = SCSI_SENSE_BUFFERSIZE; - } - - memset(sc_cmd->sense_buffer, 0, sizeof(sc_cmd->sense_buffer)); - if (fcp_sns_len) - memcpy(sc_cmd->sense_buffer, rq_data, fcp_sns_len); - - /* return RQ entries */ - for (i = 0; i < num_rq; i++) - bnx2fc_return_rqe(tgt, 1); - } -} - -/** - * bnx2fc_queuecommand - Queuecommand function of the scsi template - * - * @host: The Scsi_Host the command was issued to - * @sc_cmd: struct scsi_cmnd to be executed - * - * This is the IO strategy routine, called by SCSI-ML - **/ -int bnx2fc_queuecommand(struct Scsi_Host *host, - struct scsi_cmnd *sc_cmd) -{ - struct fc_lport *lport = shost_priv(host); - struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); - struct fc_rport_libfc_priv *rp = rport->dd_data; - struct bnx2fc_rport *tgt; - struct bnx2fc_cmd *io_req; - int rc = 0; - int rval; - - rval = fc_remote_port_chkready(rport); - if (rval) { - sc_cmd->result = rval; - sc_cmd->scsi_done(sc_cmd); - return 0; - } - - if ((lport->state != LPORT_ST_READY) || !(lport->link_up)) { - rc = SCSI_MLQUEUE_HOST_BUSY; - goto exit_qcmd; - } - - /* rport and tgt are allocated together, so tgt should be non-NULL */ - tgt = (struct bnx2fc_rport *)&rp[1]; - - if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { - /* - * Session is not offloaded yet. Let SCSI-ml retry - * the command. - */ - rc = SCSI_MLQUEUE_TARGET_BUSY; - goto exit_qcmd; - } - - io_req = bnx2fc_cmd_alloc(tgt); - if (!io_req) { - rc = SCSI_MLQUEUE_HOST_BUSY; - goto exit_qcmd; - } - io_req->sc_cmd = sc_cmd; - - if (bnx2fc_post_io_req(tgt, io_req)) { - printk(KERN_ERR PFX "Unable to post io_req\n"); - rc = SCSI_MLQUEUE_HOST_BUSY; - goto exit_qcmd; - } -exit_qcmd: - return rc; -} - -void bnx2fc_process_scsi_cmd_compl(struct bnx2fc_cmd *io_req, - struct fcoe_task_ctx_entry *task, - u8 num_rq) -{ - struct fcoe_fcp_rsp_payload *fcp_rsp; - struct bnx2fc_rport *tgt = io_req->tgt; - struct scsi_cmnd *sc_cmd; - struct Scsi_Host *host; - - - /* scsi_cmd_cmpl is called with tgt lock held */ - - if (test_and_set_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags)) { - /* we will not receive ABTS response for this IO */ - BNX2FC_IO_DBG(io_req, "Timer context finished processing " - "this scsi cmd\n"); - } - - /* Cancel the timeout_work, as we received IO completion */ - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* drop timer hold */ - - sc_cmd = io_req->sc_cmd; - if (sc_cmd == NULL) { - printk(KERN_ERR PFX "scsi_cmd_compl - sc_cmd is NULL\n"); - return; - } - - /* Fetch fcp_rsp from task context and perform cmd completion */ - fcp_rsp = (struct fcoe_fcp_rsp_payload *) - &(task->rxwr_only.union_ctx.comp_info.fcp_rsp.payload); - - /* parse fcp_rsp and obtain sense data from RQ if available */ - bnx2fc_parse_fcp_rsp(io_req, fcp_rsp, num_rq); - - host = sc_cmd->device->host; - if (!sc_cmd->SCp.ptr) { - printk(KERN_ERR PFX "SCp.ptr is NULL\n"); - return; - } - - if (io_req->on_active_queue) { - list_del_init(&io_req->link); - io_req->on_active_queue = 0; - /* Move IO req to retire queue */ - list_add_tail(&io_req->link, &tgt->io_retire_queue); - } else { - /* This should not happen, but could have been pulled - * by bnx2fc_flush_active_ios(), or during a race - * between command abort and (late) completion. - */ - BNX2FC_IO_DBG(io_req, "xid not on active_cmd_queue\n"); - if (io_req->wait_for_comp) - if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, - &io_req->req_flags)) - complete(&io_req->tm_done); - } - - bnx2fc_unmap_sg_list(io_req); - io_req->sc_cmd = NULL; - - switch (io_req->fcp_status) { - case FC_GOOD: - if (io_req->cdb_status == 0) { - /* Good IO completion */ - sc_cmd->result = DID_OK << 16; - } else { - /* Transport status is good, SCSI status not good */ - BNX2FC_IO_DBG(io_req, "scsi_cmpl: cdb_status = %d" - " fcp_resid = 0x%x\n", - io_req->cdb_status, io_req->fcp_resid); - sc_cmd->result = (DID_OK << 16) | io_req->cdb_status; - } - if (io_req->fcp_resid) - scsi_set_resid(sc_cmd, io_req->fcp_resid); - break; - default: - printk(KERN_ERR PFX "scsi_cmd_compl: fcp_status = %d\n", - io_req->fcp_status); - break; - } - sc_cmd->SCp.ptr = NULL; - sc_cmd->scsi_done(sc_cmd); - kref_put(&io_req->refcount, bnx2fc_cmd_release); -} - -int bnx2fc_post_io_req(struct bnx2fc_rport *tgt, - struct bnx2fc_cmd *io_req) -{ - struct fcoe_task_ctx_entry *task; - struct fcoe_task_ctx_entry *task_page; - struct scsi_cmnd *sc_cmd = io_req->sc_cmd; - struct fcoe_port *port = tgt->port; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct fc_lport *lport = port->lport; - struct fcoe_dev_stats *stats; - int task_idx, index; - u16 xid; - - /* Initialize rest of io_req fields */ - io_req->cmd_type = BNX2FC_SCSI_CMD; - io_req->port = port; - io_req->tgt = tgt; - io_req->data_xfer_len = scsi_bufflen(sc_cmd); - sc_cmd->SCp.ptr = (char *)io_req; - - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) { - io_req->io_req_flags = BNX2FC_READ; - stats->InputRequests++; - stats->InputBytes += io_req->data_xfer_len; - } else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { - io_req->io_req_flags = BNX2FC_WRITE; - stats->OutputRequests++; - stats->OutputBytes += io_req->data_xfer_len; - } else { - io_req->io_req_flags = 0; - stats->ControlRequests++; - } - put_cpu(); - - xid = io_req->xid; - - /* Build buffer descriptor list for firmware from sg list */ - if (bnx2fc_build_bd_list_from_sg(io_req)) { - printk(KERN_ERR PFX "BD list creation failed\n"); - spin_lock_bh(&tgt->tgt_lock); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return -EAGAIN; - } - - task_idx = xid / BNX2FC_TASKS_PER_PAGE; - index = xid % BNX2FC_TASKS_PER_PAGE; - - /* Initialize task context for this IO request */ - task_page = (struct fcoe_task_ctx_entry *) hba->task_ctx[task_idx]; - task = &(task_page[index]); - bnx2fc_init_task(io_req, task); - - spin_lock_bh(&tgt->tgt_lock); - - if (tgt->flush_in_prog) { - printk(KERN_ERR PFX "Flush in progress..Host Busy\n"); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return -EAGAIN; - } - - if (!test_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags)) { - printk(KERN_ERR PFX "Session not ready...post_io\n"); - kref_put(&io_req->refcount, bnx2fc_cmd_release); - spin_unlock_bh(&tgt->tgt_lock); - return -EAGAIN; - } - - /* Time IO req */ - if (tgt->io_timeout) - bnx2fc_cmd_timer_set(io_req, BNX2FC_IO_TIMEOUT); - /* Obtain free SQ entry */ - bnx2fc_add_2_sq(tgt, xid); - - /* Enqueue the io_req to active_cmd_queue */ - - io_req->on_active_queue = 1; - /* move io_req from pending_queue to active_queue */ - list_add_tail(&io_req->link, &tgt->active_cmd_queue); - - /* Ring doorbell */ - bnx2fc_ring_doorbell(tgt); - spin_unlock_bh(&tgt->tgt_lock); - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_tgt.c b/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_tgt.c deleted file mode 100644 index c1800b53..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2fc/bnx2fc_tgt.c +++ /dev/null @@ -1,870 +0,0 @@ -/* bnx2fc_tgt.c: Broadcom NetXtreme II Linux FCoE offload driver. - * Handles operations such as session offload/upload etc, and manages - * session resources such as connection id and qp resources. - * - * Copyright (c) 2008 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Bhanu Prakash Gollapudi (bprakash@broadcom.com) - */ - -#include "bnx2fc.h" -static void bnx2fc_upld_timer(unsigned long data); -static void bnx2fc_ofld_timer(unsigned long data); -static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt, - struct fcoe_port *port, - struct fc_rport_priv *rdata); -static u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba, - struct bnx2fc_rport *tgt); -static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, - struct bnx2fc_rport *tgt); -static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, - struct bnx2fc_rport *tgt); -static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id); - -static void bnx2fc_upld_timer(unsigned long data) -{ - - struct bnx2fc_rport *tgt = (struct bnx2fc_rport *)data; - - BNX2FC_TGT_DBG(tgt, "upld_timer - Upload compl not received!!\n"); - /* fake upload completion */ - clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); - set_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); - wake_up_interruptible(&tgt->upld_wait); -} - -static void bnx2fc_ofld_timer(unsigned long data) -{ - - struct bnx2fc_rport *tgt = (struct bnx2fc_rport *)data; - - BNX2FC_TGT_DBG(tgt, "entered bnx2fc_ofld_timer\n"); - /* NOTE: This function should never be called, as - * offload should never timeout - */ - /* - * If the timer has expired, this session is dead - * Clear offloaded flag and logout of this device. - * Since OFFLOADED flag is cleared, this case - * will be considered as offload error and the - * port will be logged off, and conn_id, session - * resources are freed up in bnx2fc_offload_session - */ - clear_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags); - set_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); - wake_up_interruptible(&tgt->ofld_wait); -} - -static void bnx2fc_offload_session(struct fcoe_port *port, - struct bnx2fc_rport *tgt, - struct fc_rport_priv *rdata) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_rport *rport = rdata->rport; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - int rval; - int i = 0; - - /* Initialize bnx2fc_rport */ - /* NOTE: tgt is already bzero'd */ - rval = bnx2fc_init_tgt(tgt, port, rdata); - if (rval) { - printk(KERN_ERR PFX "Failed to allocate conn id for " - "port_id (%6x)\n", rport->port_id); - goto tgt_init_err; - } - - /* Allocate session resources */ - rval = bnx2fc_alloc_session_resc(hba, tgt); - if (rval) { - printk(KERN_ERR PFX "Failed to allocate resources\n"); - goto ofld_err; - } - - /* - * Initialize FCoE session offload process. - * Upon completion of offload process add - * rport to list of rports - */ -retry_ofld: - clear_bit(BNX2FC_FLAG_OFLD_REQ_CMPL, &tgt->flags); - rval = bnx2fc_send_session_ofld_req(port, tgt); - if (rval) { - printk(KERN_ERR PFX "ofld_req failed\n"); - goto ofld_err; - } - - /* - * wait for the session is offloaded and enabled. 3 Secs - * should be ample time for this process to complete. - */ - setup_timer(&tgt->ofld_timer, bnx2fc_ofld_timer, (unsigned long)tgt); - mod_timer(&tgt->ofld_timer, jiffies + BNX2FC_FW_TIMEOUT); - - wait_event_interruptible(tgt->ofld_wait, - (test_bit( - BNX2FC_FLAG_OFLD_REQ_CMPL, - &tgt->flags))); - if (signal_pending(current)) - flush_signals(current); - - del_timer_sync(&tgt->ofld_timer); - - if (!(test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags))) { - if (test_and_clear_bit(BNX2FC_FLAG_CTX_ALLOC_FAILURE, - &tgt->flags)) { - BNX2FC_TGT_DBG(tgt, "ctx_alloc_failure, " - "retry ofld..%d\n", i++); - msleep_interruptible(1000); - if (i > 3) { - i = 0; - goto ofld_err; - } - goto retry_ofld; - } - goto ofld_err; - } - if (bnx2fc_map_doorbell(tgt)) { - printk(KERN_ERR PFX "map doorbell failed - no mem\n"); - /* upload will take care of cleaning up sess resc */ - lport->tt.rport_logoff(rdata); - } - return; - -ofld_err: - /* couldn't offload the session. log off from this rport */ - BNX2FC_TGT_DBG(tgt, "bnx2fc_offload_session - offload error\n"); - /* Free session resources */ - bnx2fc_free_session_resc(hba, tgt); -tgt_init_err: - if (tgt->fcoe_conn_id != -1) - bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); - lport->tt.rport_logoff(rdata); -} - -void bnx2fc_flush_active_ios(struct bnx2fc_rport *tgt) -{ - struct bnx2fc_cmd *io_req; - struct list_head *list; - struct list_head *tmp; - int rc; - int i = 0; - BNX2FC_TGT_DBG(tgt, "Entered flush_active_ios - %d\n", - tgt->num_active_ios.counter); - - spin_lock_bh(&tgt->tgt_lock); - tgt->flush_in_prog = 1; - - list_for_each_safe(list, tmp, &tgt->active_cmd_queue) { - i++; - io_req = (struct bnx2fc_cmd *)list; - list_del_init(&io_req->link); - io_req->on_active_queue = 0; - BNX2FC_IO_DBG(io_req, "cmd_queue cleanup\n"); - - if (cancel_delayed_work(&io_req->timeout_work)) { - if (test_and_clear_bit(BNX2FC_FLAG_EH_ABORT, - &io_req->req_flags)) { - /* Handle eh_abort timeout */ - BNX2FC_IO_DBG(io_req, "eh_abort for IO " - "cleaned up\n"); - complete(&io_req->tm_done); - } - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* drop timer hold */ - } - - set_bit(BNX2FC_FLAG_IO_COMPL, &io_req->req_flags); - set_bit(BNX2FC_FLAG_IO_CLEANUP, &io_req->req_flags); - rc = bnx2fc_initiate_cleanup(io_req); - BUG_ON(rc); - } - - list_for_each_safe(list, tmp, &tgt->els_queue) { - i++; - io_req = (struct bnx2fc_cmd *)list; - list_del_init(&io_req->link); - io_req->on_active_queue = 0; - - BNX2FC_IO_DBG(io_req, "els_queue cleanup\n"); - - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, - bnx2fc_cmd_release); /* drop timer hold */ - - if ((io_req->cb_func) && (io_req->cb_arg)) { - io_req->cb_func(io_req->cb_arg); - io_req->cb_arg = NULL; - } - - rc = bnx2fc_initiate_cleanup(io_req); - BUG_ON(rc); - } - - list_for_each_safe(list, tmp, &tgt->io_retire_queue) { - i++; - io_req = (struct bnx2fc_cmd *)list; - list_del_init(&io_req->link); - - BNX2FC_IO_DBG(io_req, "retire_queue flush\n"); - - if (cancel_delayed_work(&io_req->timeout_work)) - kref_put(&io_req->refcount, bnx2fc_cmd_release); - - clear_bit(BNX2FC_FLAG_ISSUE_RRQ, &io_req->req_flags); - } - - BNX2FC_TGT_DBG(tgt, "IOs flushed = %d\n", i); - i = 0; - spin_unlock_bh(&tgt->tgt_lock); - /* wait for active_ios to go to 0 */ - while ((tgt->num_active_ios.counter != 0) && (i++ < BNX2FC_WAIT_CNT)) - msleep(25); - if (tgt->num_active_ios.counter != 0) - printk(KERN_ERR PFX "CLEANUP on port 0x%x:" - " active_ios = %d\n", - tgt->rdata->ids.port_id, tgt->num_active_ios.counter); - spin_lock_bh(&tgt->tgt_lock); - tgt->flush_in_prog = 0; - spin_unlock_bh(&tgt->tgt_lock); -} - -static void bnx2fc_upload_session(struct fcoe_port *port, - struct bnx2fc_rport *tgt) -{ - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - - BNX2FC_TGT_DBG(tgt, "upload_session: active_ios = %d\n", - tgt->num_active_ios.counter); - - /* - * Called with hba->hba_mutex held. - * This is a blocking call - */ - clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); - bnx2fc_send_session_disable_req(port, tgt); - - /* - * wait for upload to complete. 3 Secs - * should be sufficient time for this process to complete. - */ - setup_timer(&tgt->upld_timer, bnx2fc_upld_timer, (unsigned long)tgt); - mod_timer(&tgt->upld_timer, jiffies + BNX2FC_FW_TIMEOUT); - - BNX2FC_TGT_DBG(tgt, "waiting for disable compl\n"); - wait_event_interruptible(tgt->upld_wait, - (test_bit( - BNX2FC_FLAG_UPLD_REQ_COMPL, - &tgt->flags))); - - if (signal_pending(current)) - flush_signals(current); - - del_timer_sync(&tgt->upld_timer); - - /* - * traverse thru the active_q and tmf_q and cleanup - * IOs in these lists - */ - BNX2FC_TGT_DBG(tgt, "flush/upload - disable wait flags = 0x%lx\n", - tgt->flags); - bnx2fc_flush_active_ios(tgt); - - /* Issue destroy KWQE */ - if (test_bit(BNX2FC_FLAG_DISABLED, &tgt->flags)) { - BNX2FC_TGT_DBG(tgt, "send destroy req\n"); - clear_bit(BNX2FC_FLAG_UPLD_REQ_COMPL, &tgt->flags); - bnx2fc_send_session_destroy_req(hba, tgt); - - /* wait for destroy to complete */ - setup_timer(&tgt->upld_timer, - bnx2fc_upld_timer, (unsigned long)tgt); - mod_timer(&tgt->upld_timer, jiffies + BNX2FC_FW_TIMEOUT); - - wait_event_interruptible(tgt->upld_wait, - (test_bit( - BNX2FC_FLAG_UPLD_REQ_COMPL, - &tgt->flags))); - - if (!(test_bit(BNX2FC_FLAG_DESTROYED, &tgt->flags))) - printk(KERN_ERR PFX "ERROR!! destroy timed out\n"); - - BNX2FC_TGT_DBG(tgt, "destroy wait complete flags = 0x%lx\n", - tgt->flags); - if (signal_pending(current)) - flush_signals(current); - - del_timer_sync(&tgt->upld_timer); - - } else - printk(KERN_ERR PFX "ERROR!! DISABLE req timed out, destroy" - " not sent to FW\n"); - - /* Free session resources */ - bnx2fc_free_session_resc(hba, tgt); - bnx2fc_free_conn_id(hba, tgt->fcoe_conn_id); -} - -static int bnx2fc_init_tgt(struct bnx2fc_rport *tgt, - struct fcoe_port *port, - struct fc_rport_priv *rdata) -{ - - struct fc_rport *rport = rdata->rport; - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct b577xx_doorbell_set_prod *sq_db = &tgt->sq_db; - struct b577xx_fcoe_rx_doorbell *rx_db = &tgt->rx_db; - - tgt->rport = rport; - tgt->rdata = rdata; - tgt->port = port; - - if (hba->num_ofld_sess >= BNX2FC_NUM_MAX_SESS) { - BNX2FC_TGT_DBG(tgt, "exceeded max sessions. logoff this tgt\n"); - tgt->fcoe_conn_id = -1; - return -1; - } - - tgt->fcoe_conn_id = bnx2fc_alloc_conn_id(hba, tgt); - if (tgt->fcoe_conn_id == -1) - return -1; - - BNX2FC_TGT_DBG(tgt, "init_tgt - conn_id = 0x%x\n", tgt->fcoe_conn_id); - - tgt->max_sqes = BNX2FC_SQ_WQES_MAX; - tgt->max_rqes = BNX2FC_RQ_WQES_MAX; - tgt->max_cqes = BNX2FC_CQ_WQES_MAX; - atomic_set(&tgt->free_sqes, BNX2FC_SQ_WQES_MAX); - - /* Initialize the toggle bit */ - tgt->sq_curr_toggle_bit = 1; - tgt->cq_curr_toggle_bit = 1; - tgt->sq_prod_idx = 0; - tgt->cq_cons_idx = 0; - tgt->rq_prod_idx = 0x8000; - tgt->rq_cons_idx = 0; - atomic_set(&tgt->num_active_ios, 0); - - if (rdata->flags & FC_RP_FLAGS_RETRY) { - tgt->dev_type = TYPE_TAPE; - tgt->io_timeout = 0; /* use default ULP timeout */ - } else { - tgt->dev_type = TYPE_DISK; - tgt->io_timeout = BNX2FC_IO_TIMEOUT; - } - - /* initialize sq doorbell */ - sq_db->header.header = B577XX_DOORBELL_HDR_DB_TYPE; - sq_db->header.header |= B577XX_FCOE_CONNECTION_TYPE << - B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT; - /* initialize rx doorbell */ - rx_db->hdr.header = ((0x1 << B577XX_DOORBELL_HDR_RX_SHIFT) | - (0x1 << B577XX_DOORBELL_HDR_DB_TYPE_SHIFT) | - (B577XX_FCOE_CONNECTION_TYPE << - B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT)); - rx_db->params = (0x2 << B577XX_FCOE_RX_DOORBELL_NEGATIVE_ARM_SHIFT) | - (0x3 << B577XX_FCOE_RX_DOORBELL_OPCODE_SHIFT); - - spin_lock_init(&tgt->tgt_lock); - spin_lock_init(&tgt->cq_lock); - - /* Initialize active_cmd_queue list */ - INIT_LIST_HEAD(&tgt->active_cmd_queue); - - /* Initialize IO retire queue */ - INIT_LIST_HEAD(&tgt->io_retire_queue); - - INIT_LIST_HEAD(&tgt->els_queue); - - /* Initialize active_tm_queue list */ - INIT_LIST_HEAD(&tgt->active_tm_queue); - - init_waitqueue_head(&tgt->ofld_wait); - init_waitqueue_head(&tgt->upld_wait); - - return 0; -} - -/** - * This event_callback is called after successful completion of libfc - * initiated target login. bnx2fc can proceed with initiating the session - * establishment. - */ -void bnx2fc_rport_event_handler(struct fc_lport *lport, - struct fc_rport_priv *rdata, - enum fc_rport_event event) -{ - struct fcoe_port *port = lport_priv(lport); - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct fc_rport *rport = rdata->rport; - struct fc_rport_libfc_priv *rp; - struct bnx2fc_rport *tgt; - u32 port_id; - - BNX2FC_HBA_DBG(lport, "rport_event_hdlr: event = %d, port_id = 0x%x\n", - event, rdata->ids.port_id); - switch (event) { - case RPORT_EV_READY: - if (!rport) { - printk(KERN_ERR PFX "rport is NULL: ERROR!\n"); - break; - } - - rp = rport->dd_data; - if (rport->port_id == FC_FID_DIR_SERV) { - /* - * bnx2fc_rport structure doesn't exist for - * directory server. - * We should not come here, as lport will - * take care of fabric login - */ - printk(KERN_ERR PFX "%x - rport_event_handler ERROR\n", - rdata->ids.port_id); - break; - } - - if (rdata->spp_type != FC_TYPE_FCP) { - BNX2FC_HBA_DBG(lport, "not FCP type target." - " not offloading\n"); - break; - } - if (!(rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET)) { - BNX2FC_HBA_DBG(lport, "not FCP_TARGET" - " not offloading\n"); - break; - } - - /* - * Offlaod process is protected with hba mutex. - * Use the same mutex_lock for upload process too - */ - mutex_lock(&hba->hba_mutex); - tgt = (struct bnx2fc_rport *)&rp[1]; - - /* This can happen when ADISC finds the same target */ - if (test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags)) { - BNX2FC_TGT_DBG(tgt, "already offloaded\n"); - mutex_unlock(&hba->hba_mutex); - return; - } - - /* - * Offload the session. This is a blocking call, and will - * wait until the session is offloaded. - */ - bnx2fc_offload_session(port, tgt, rdata); - - BNX2FC_TGT_DBG(tgt, "OFFLOAD num_ofld_sess = %d\n", - hba->num_ofld_sess); - - if (test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags)) { - /* - * Session is offloaded and enabled. Map - * doorbell register for this target - */ - BNX2FC_TGT_DBG(tgt, "sess offloaded\n"); - /* This counter is protected with hba mutex */ - hba->num_ofld_sess++; - - set_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); - } else { - /* - * Offload or enable would have failed. - * In offload/enable completion path, the - * rport would have already been removed - */ - BNX2FC_TGT_DBG(tgt, "Port is being logged off as " - "offloaded flag not set\n"); - } - mutex_unlock(&hba->hba_mutex); - break; - case RPORT_EV_LOGO: - case RPORT_EV_FAILED: - case RPORT_EV_STOP: - port_id = rdata->ids.port_id; - if (port_id == FC_FID_DIR_SERV) - break; - - if (!rport) { - printk(KERN_INFO PFX "%x - rport not created Yet!!\n", - port_id); - break; - } - rp = rport->dd_data; - mutex_lock(&hba->hba_mutex); - /* - * Perform session upload. Note that rdata->peers is already - * removed from disc->rports list before we get this event. - */ - tgt = (struct bnx2fc_rport *)&rp[1]; - - if (!(test_bit(BNX2FC_FLAG_OFFLOADED, &tgt->flags))) { - mutex_unlock(&hba->hba_mutex); - break; - } - clear_bit(BNX2FC_FLAG_SESSION_READY, &tgt->flags); - - bnx2fc_upload_session(port, tgt); - hba->num_ofld_sess--; - BNX2FC_TGT_DBG(tgt, "UPLOAD num_ofld_sess = %d\n", - hba->num_ofld_sess); - /* - * Try to wake up the linkdown wait thread. If num_ofld_sess - * is 0, the waiting therad wakes up - */ - if ((hba->wait_for_link_down) && - (hba->num_ofld_sess == 0)) { - wake_up_interruptible(&hba->shutdown_wait); - } - if (test_bit(BNX2FC_FLAG_EXPL_LOGO, &tgt->flags)) { - printk(KERN_ERR PFX "Relogin to the tgt\n"); - mutex_lock(&lport->disc.disc_mutex); - lport->tt.rport_login(rdata); - mutex_unlock(&lport->disc.disc_mutex); - } - mutex_unlock(&hba->hba_mutex); - - break; - - case RPORT_EV_NONE: - break; - } -} - -/** - * bnx2fc_tgt_lookup() - Lookup a bnx2fc_rport by port_id - * - * @port: fcoe_port struct to lookup the target port on - * @port_id: The remote port ID to look up - */ -struct bnx2fc_rport *bnx2fc_tgt_lookup(struct fcoe_port *port, - u32 port_id) -{ - struct bnx2fc_interface *interface = port->priv; - struct bnx2fc_hba *hba = interface->hba; - struct bnx2fc_rport *tgt; - struct fc_rport_priv *rdata; - int i; - - for (i = 0; i < BNX2FC_NUM_MAX_SESS; i++) { - tgt = hba->tgt_ofld_list[i]; - if ((tgt) && (tgt->port == port)) { - rdata = tgt->rdata; - if (rdata->ids.port_id == port_id) { - if (rdata->rp_state != RPORT_ST_DELETE) { - BNX2FC_TGT_DBG(tgt, "rport " - "obtained\n"); - return tgt; - } else { - BNX2FC_TGT_DBG(tgt, "rport 0x%x " - "is in DELETED state\n", - rdata->ids.port_id); - return NULL; - } - } - } - } - return NULL; -} - - -/** - * bnx2fc_alloc_conn_id - allocates FCOE Connection id - * - * @hba: pointer to adapter structure - * @tgt: pointer to bnx2fc_rport structure - */ -static u32 bnx2fc_alloc_conn_id(struct bnx2fc_hba *hba, - struct bnx2fc_rport *tgt) -{ - u32 conn_id, next; - - /* called with hba mutex held */ - - /* - * tgt_ofld_list access is synchronized using - * both hba mutex and hba lock. Atleast hba mutex or - * hba lock needs to be held for read access. - */ - - spin_lock_bh(&hba->hba_lock); - next = hba->next_conn_id; - conn_id = hba->next_conn_id++; - if (hba->next_conn_id == BNX2FC_NUM_MAX_SESS) - hba->next_conn_id = 0; - - while (hba->tgt_ofld_list[conn_id] != NULL) { - conn_id++; - if (conn_id == BNX2FC_NUM_MAX_SESS) - conn_id = 0; - - if (conn_id == next) { - /* No free conn_ids are available */ - spin_unlock_bh(&hba->hba_lock); - return -1; - } - } - hba->tgt_ofld_list[conn_id] = tgt; - tgt->fcoe_conn_id = conn_id; - spin_unlock_bh(&hba->hba_lock); - return conn_id; -} - -static void bnx2fc_free_conn_id(struct bnx2fc_hba *hba, u32 conn_id) -{ - /* called with hba mutex held */ - spin_lock_bh(&hba->hba_lock); - hba->tgt_ofld_list[conn_id] = NULL; - spin_unlock_bh(&hba->hba_lock); -} - -/** - *bnx2fc_alloc_session_resc - Allocate qp resources for the session - * - */ -static int bnx2fc_alloc_session_resc(struct bnx2fc_hba *hba, - struct bnx2fc_rport *tgt) -{ - dma_addr_t page; - int num_pages; - u32 *pbl; - - /* Allocate and map SQ */ - tgt->sq_mem_size = tgt->max_sqes * BNX2FC_SQ_WQE_SIZE; - tgt->sq_mem_size = (tgt->sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - tgt->sq = dma_alloc_coherent(&hba->pcidev->dev, tgt->sq_mem_size, - &tgt->sq_dma, GFP_KERNEL); - if (!tgt->sq) { - printk(KERN_ERR PFX "unable to allocate SQ memory %d\n", - tgt->sq_mem_size); - goto mem_alloc_failure; - } - memset(tgt->sq, 0, tgt->sq_mem_size); - - /* Allocate and map CQ */ - tgt->cq_mem_size = tgt->max_cqes * BNX2FC_CQ_WQE_SIZE; - tgt->cq_mem_size = (tgt->cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - tgt->cq = dma_alloc_coherent(&hba->pcidev->dev, tgt->cq_mem_size, - &tgt->cq_dma, GFP_KERNEL); - if (!tgt->cq) { - printk(KERN_ERR PFX "unable to allocate CQ memory %d\n", - tgt->cq_mem_size); - goto mem_alloc_failure; - } - memset(tgt->cq, 0, tgt->cq_mem_size); - - /* Allocate and map RQ and RQ PBL */ - tgt->rq_mem_size = tgt->max_rqes * BNX2FC_RQ_WQE_SIZE; - tgt->rq_mem_size = (tgt->rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - tgt->rq = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_mem_size, - &tgt->rq_dma, GFP_KERNEL); - if (!tgt->rq) { - printk(KERN_ERR PFX "unable to allocate RQ memory %d\n", - tgt->rq_mem_size); - goto mem_alloc_failure; - } - memset(tgt->rq, 0, tgt->rq_mem_size); - - tgt->rq_pbl_size = (tgt->rq_mem_size / PAGE_SIZE) * sizeof(void *); - tgt->rq_pbl_size = (tgt->rq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - tgt->rq_pbl = dma_alloc_coherent(&hba->pcidev->dev, tgt->rq_pbl_size, - &tgt->rq_pbl_dma, GFP_KERNEL); - if (!tgt->rq_pbl) { - printk(KERN_ERR PFX "unable to allocate RQ PBL %d\n", - tgt->rq_pbl_size); - goto mem_alloc_failure; - } - - memset(tgt->rq_pbl, 0, tgt->rq_pbl_size); - num_pages = tgt->rq_mem_size / PAGE_SIZE; - page = tgt->rq_dma; - pbl = (u32 *)tgt->rq_pbl; - - while (num_pages--) { - *pbl = (u32)page; - pbl++; - *pbl = (u32)((u64)page >> 32); - pbl++; - page += PAGE_SIZE; - } - - /* Allocate and map XFERQ */ - tgt->xferq_mem_size = tgt->max_sqes * BNX2FC_XFERQ_WQE_SIZE; - tgt->xferq_mem_size = (tgt->xferq_mem_size + (PAGE_SIZE - 1)) & - PAGE_MASK; - - tgt->xferq = dma_alloc_coherent(&hba->pcidev->dev, tgt->xferq_mem_size, - &tgt->xferq_dma, GFP_KERNEL); - if (!tgt->xferq) { - printk(KERN_ERR PFX "unable to allocate XFERQ %d\n", - tgt->xferq_mem_size); - goto mem_alloc_failure; - } - memset(tgt->xferq, 0, tgt->xferq_mem_size); - - /* Allocate and map CONFQ & CONFQ PBL */ - tgt->confq_mem_size = tgt->max_sqes * BNX2FC_CONFQ_WQE_SIZE; - tgt->confq_mem_size = (tgt->confq_mem_size + (PAGE_SIZE - 1)) & - PAGE_MASK; - - tgt->confq = dma_alloc_coherent(&hba->pcidev->dev, tgt->confq_mem_size, - &tgt->confq_dma, GFP_KERNEL); - if (!tgt->confq) { - printk(KERN_ERR PFX "unable to allocate CONFQ %d\n", - tgt->confq_mem_size); - goto mem_alloc_failure; - } - memset(tgt->confq, 0, tgt->confq_mem_size); - - tgt->confq_pbl_size = - (tgt->confq_mem_size / PAGE_SIZE) * sizeof(void *); - tgt->confq_pbl_size = - (tgt->confq_pbl_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - tgt->confq_pbl = dma_alloc_coherent(&hba->pcidev->dev, - tgt->confq_pbl_size, - &tgt->confq_pbl_dma, GFP_KERNEL); - if (!tgt->confq_pbl) { - printk(KERN_ERR PFX "unable to allocate CONFQ PBL %d\n", - tgt->confq_pbl_size); - goto mem_alloc_failure; - } - - memset(tgt->confq_pbl, 0, tgt->confq_pbl_size); - num_pages = tgt->confq_mem_size / PAGE_SIZE; - page = tgt->confq_dma; - pbl = (u32 *)tgt->confq_pbl; - - while (num_pages--) { - *pbl = (u32)page; - pbl++; - *pbl = (u32)((u64)page >> 32); - pbl++; - page += PAGE_SIZE; - } - - /* Allocate and map ConnDB */ - tgt->conn_db_mem_size = sizeof(struct fcoe_conn_db); - - tgt->conn_db = dma_alloc_coherent(&hba->pcidev->dev, - tgt->conn_db_mem_size, - &tgt->conn_db_dma, GFP_KERNEL); - if (!tgt->conn_db) { - printk(KERN_ERR PFX "unable to allocate conn_db %d\n", - tgt->conn_db_mem_size); - goto mem_alloc_failure; - } - memset(tgt->conn_db, 0, tgt->conn_db_mem_size); - - - /* Allocate and map LCQ */ - tgt->lcq_mem_size = (tgt->max_sqes + 8) * BNX2FC_SQ_WQE_SIZE; - tgt->lcq_mem_size = (tgt->lcq_mem_size + (PAGE_SIZE - 1)) & - PAGE_MASK; - - tgt->lcq = dma_alloc_coherent(&hba->pcidev->dev, tgt->lcq_mem_size, - &tgt->lcq_dma, GFP_KERNEL); - - if (!tgt->lcq) { - printk(KERN_ERR PFX "unable to allocate lcq %d\n", - tgt->lcq_mem_size); - goto mem_alloc_failure; - } - memset(tgt->lcq, 0, tgt->lcq_mem_size); - - tgt->conn_db->rq_prod = 0x8000; - - return 0; - -mem_alloc_failure: - return -ENOMEM; -} - -/** - * bnx2i_free_session_resc - free qp resources for the session - * - * @hba: adapter structure pointer - * @tgt: bnx2fc_rport structure pointer - * - * Free QP resources - SQ/RQ/CQ/XFERQ memory and PBL - */ -static void bnx2fc_free_session_resc(struct bnx2fc_hba *hba, - struct bnx2fc_rport *tgt) -{ - void __iomem *ctx_base_ptr; - - BNX2FC_TGT_DBG(tgt, "Freeing up session resources\n"); - - spin_lock_bh(&tgt->cq_lock); - ctx_base_ptr = tgt->ctx_base; - tgt->ctx_base = NULL; - - /* Free LCQ */ - if (tgt->lcq) { - dma_free_coherent(&hba->pcidev->dev, tgt->lcq_mem_size, - tgt->lcq, tgt->lcq_dma); - tgt->lcq = NULL; - } - /* Free connDB */ - if (tgt->conn_db) { - dma_free_coherent(&hba->pcidev->dev, tgt->conn_db_mem_size, - tgt->conn_db, tgt->conn_db_dma); - tgt->conn_db = NULL; - } - /* Free confq and confq pbl */ - if (tgt->confq_pbl) { - dma_free_coherent(&hba->pcidev->dev, tgt->confq_pbl_size, - tgt->confq_pbl, tgt->confq_pbl_dma); - tgt->confq_pbl = NULL; - } - if (tgt->confq) { - dma_free_coherent(&hba->pcidev->dev, tgt->confq_mem_size, - tgt->confq, tgt->confq_dma); - tgt->confq = NULL; - } - /* Free XFERQ */ - if (tgt->xferq) { - dma_free_coherent(&hba->pcidev->dev, tgt->xferq_mem_size, - tgt->xferq, tgt->xferq_dma); - tgt->xferq = NULL; - } - /* Free RQ PBL and RQ */ - if (tgt->rq_pbl) { - dma_free_coherent(&hba->pcidev->dev, tgt->rq_pbl_size, - tgt->rq_pbl, tgt->rq_pbl_dma); - tgt->rq_pbl = NULL; - } - if (tgt->rq) { - dma_free_coherent(&hba->pcidev->dev, tgt->rq_mem_size, - tgt->rq, tgt->rq_dma); - tgt->rq = NULL; - } - /* Free CQ */ - if (tgt->cq) { - dma_free_coherent(&hba->pcidev->dev, tgt->cq_mem_size, - tgt->cq, tgt->cq_dma); - tgt->cq = NULL; - } - /* Free SQ */ - if (tgt->sq) { - dma_free_coherent(&hba->pcidev->dev, tgt->sq_mem_size, - tgt->sq, tgt->sq_dma); - tgt->sq = NULL; - } - spin_unlock_bh(&tgt->cq_lock); - - if (ctx_base_ptr) - iounmap(ctx_base_ptr); -} diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_constants.h b/ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_constants.h deleted file mode 100644 index 495a8416..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_constants.h +++ /dev/null @@ -1,159 +0,0 @@ -/* 57xx_iscsi_constants.h: Broadcom NetXtreme II iSCSI HSI - * - * Copyright (c) 2006 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) - * Maintained by: Eddie Wai (eddie.wai@broadcom.com) - */ -#ifndef __57XX_ISCSI_CONSTANTS_H_ -#define __57XX_ISCSI_CONSTANTS_H_ - -/** -* This file defines HSI constants for the iSCSI flows -*/ - -/* iSCSI request op codes */ -#define ISCSI_OPCODE_CLEANUP_REQUEST (7) - -/* iSCSI response/messages op codes */ -#define ISCSI_OPCODE_CLEANUP_RESPONSE (0x27) -#define ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION (0) - -/* iSCSI task types */ -#define ISCSI_TASK_TYPE_READ (0) -#define ISCSI_TASK_TYPE_WRITE (1) -#define ISCSI_TASK_TYPE_MPATH (2) - -/* initial CQ sequence numbers */ -#define ISCSI_INITIAL_SN (1) - -/* KWQ (kernel work queue) layer codes */ -#define ISCSI_KWQE_LAYER_CODE (6) - -/* KWQ (kernel work queue) request op codes */ -#define ISCSI_KWQE_OPCODE_OFFLOAD_CONN1 (0) -#define ISCSI_KWQE_OPCODE_OFFLOAD_CONN2 (1) -#define ISCSI_KWQE_OPCODE_UPDATE_CONN (2) -#define ISCSI_KWQE_OPCODE_DESTROY_CONN (3) -#define ISCSI_KWQE_OPCODE_INIT1 (4) -#define ISCSI_KWQE_OPCODE_INIT2 (5) - -/* KCQ (kernel completion queue) response op codes */ -#define ISCSI_KCQE_OPCODE_OFFLOAD_CONN (0x10) -#define ISCSI_KCQE_OPCODE_UPDATE_CONN (0x12) -#define ISCSI_KCQE_OPCODE_DESTROY_CONN (0x13) -#define ISCSI_KCQE_OPCODE_INIT (0x14) -#define ISCSI_KCQE_OPCODE_FW_CLEAN_TASK (0x15) -#define ISCSI_KCQE_OPCODE_TCP_RESET (0x16) -#define ISCSI_KCQE_OPCODE_TCP_SYN (0x17) -#define ISCSI_KCQE_OPCODE_TCP_FIN (0X18) -#define ISCSI_KCQE_OPCODE_TCP_ERROR (0x19) -#define ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION (0x20) -#define ISCSI_KCQE_OPCODE_ISCSI_ERROR (0x21) - -/* KCQ (kernel completion queue) completion status */ -#define ISCSI_KCQE_COMPLETION_STATUS_SUCCESS (0x0) -#define ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE (0x1) -#define ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE (0x2) -#define ISCSI_KCQE_COMPLETION_STATUS_CTX_FREE_FAILURE (0x3) -#define ISCSI_KCQE_COMPLETION_STATUS_NIC_ERROR (0x4) - -#define ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR (0x5) -#define ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR (0x6) - -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_UNEXPECTED_OPCODE (0xa) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE (0xb) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN (0xc) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT (0xd) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN (0xe) - -/* Response */ -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN (0xf) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T (0x10) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_IS_ZERO (0x2c) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG (0x2d) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0 (0x11) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1 (0x12) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2 (0x13) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3 (0x14) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4 (0x15) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5 (0x16) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6 (0x17) - -/* Data-In */ -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN (0x18) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN (0x19) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO (0x1a) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV (0x1b) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN (0x1c) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN (0x1d) - -/* R2T */ -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF (0x1f) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN (0x20) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN (0x21) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0 (0x22) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1 (0x23) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED (0x24) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV (0x25) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN (0x26) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO (0x27) - -/* TMF */ -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN (0x28) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN (0x29) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN (0x2a) -#define ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP (0x2b) - -/* IP/TCP processing errors: */ -#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT (0x40) -#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS (0x41) -#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG (0x42) -#define ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_MAX_RTRANS (0x43) - -/* iSCSI licensing errors */ -/* general iSCSI license not installed */ -#define ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED (0x50) -/* additional LOM specific iSCSI license not installed */ -#define ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED (0x51) - -#define ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY (0x80) -#define ISCSI_KCQE_COMPLETION_STATUS_PARITY_ERR (0x81) - -/* SQ/RQ/CQ DB structure sizes */ -#define ISCSI_SQ_DB_SIZE (16) -#define ISCSI_RQ_DB_SIZE (64) -#define ISCSI_CQ_DB_SIZE (80) - -#define ISCSI_SQN_TO_NOTIFY_NOT_VALID 0xFFFF - -/* Page size codes (for flags field in connection offload request) */ -#define ISCSI_PAGE_SIZE_256 (0) -#define ISCSI_PAGE_SIZE_512 (1) -#define ISCSI_PAGE_SIZE_1K (2) -#define ISCSI_PAGE_SIZE_2K (3) -#define ISCSI_PAGE_SIZE_4K (4) -#define ISCSI_PAGE_SIZE_8K (5) -#define ISCSI_PAGE_SIZE_16K (6) -#define ISCSI_PAGE_SIZE_32K (7) -#define ISCSI_PAGE_SIZE_64K (8) -#define ISCSI_PAGE_SIZE_128K (9) -#define ISCSI_PAGE_SIZE_256K (10) -#define ISCSI_PAGE_SIZE_512K (11) -#define ISCSI_PAGE_SIZE_1M (12) -#define ISCSI_PAGE_SIZE_2M (13) -#define ISCSI_PAGE_SIZE_4M (14) -#define ISCSI_PAGE_SIZE_8M (15) - -/* Iscsi PDU related defines */ -#define ISCSI_HEADER_SIZE (48) -#define ISCSI_DIGEST_SHIFT (2) -#define ISCSI_DIGEST_SIZE (4) - -#define B577XX_ISCSI_CONNECTION_TYPE 3 - -#endif /*__57XX_ISCSI_CONSTANTS_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_hsi.h b/ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_hsi.h deleted file mode 100644 index 72118db8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/57xx_iscsi_hsi.h +++ /dev/null @@ -1,1514 +0,0 @@ -/* 57xx_iscsi_hsi.h: Broadcom NetXtreme II iSCSI HSI. - * - * Copyright (c) 2006 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) - * Maintained by: Eddie Wai (eddie.wai@broadcom.com) - */ -#ifndef __57XX_ISCSI_HSI_LINUX_LE__ -#define __57XX_ISCSI_HSI_LINUX_LE__ - -/* - * iSCSI Async CQE - */ -struct bnx2i_async_msg { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 reserved1; - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 reserved1; - u8 op_code; -#endif - u32 reserved2; - u32 exp_cmd_sn; - u32 max_cmd_sn; - u32 reserved3[2]; -#if defined(__BIG_ENDIAN) - u16 reserved5; - u8 err_code; - u8 reserved4; -#elif defined(__LITTLE_ENDIAN) - u8 reserved4; - u8 err_code; - u16 reserved5; -#endif - u32 reserved6; - u32 lun[2]; -#if defined(__BIG_ENDIAN) - u8 async_event; - u8 async_vcode; - u16 param1; -#elif defined(__LITTLE_ENDIAN) - u16 param1; - u8 async_vcode; - u8 async_event; -#endif -#if defined(__BIG_ENDIAN) - u16 param2; - u16 param3; -#elif defined(__LITTLE_ENDIAN) - u16 param3; - u16 param2; -#endif - u32 reserved7[3]; - u32 cq_req_sn; -}; - - -/* - * iSCSI Buffer Descriptor (BD) - */ -struct iscsi_bd { - u32 buffer_addr_hi; - u32 buffer_addr_lo; -#if defined(__BIG_ENDIAN) - u16 reserved0; - u16 buffer_length; -#elif defined(__LITTLE_ENDIAN) - u16 buffer_length; - u16 reserved0; -#endif -#if defined(__BIG_ENDIAN) - u16 reserved3; - u16 flags; -#define ISCSI_BD_RESERVED1 (0x3F<<0) -#define ISCSI_BD_RESERVED1_SHIFT 0 -#define ISCSI_BD_LAST_IN_BD_CHAIN (0x1<<6) -#define ISCSI_BD_LAST_IN_BD_CHAIN_SHIFT 6 -#define ISCSI_BD_FIRST_IN_BD_CHAIN (0x1<<7) -#define ISCSI_BD_FIRST_IN_BD_CHAIN_SHIFT 7 -#define ISCSI_BD_RESERVED2 (0xFF<<8) -#define ISCSI_BD_RESERVED2_SHIFT 8 -#elif defined(__LITTLE_ENDIAN) - u16 flags; -#define ISCSI_BD_RESERVED1 (0x3F<<0) -#define ISCSI_BD_RESERVED1_SHIFT 0 -#define ISCSI_BD_LAST_IN_BD_CHAIN (0x1<<6) -#define ISCSI_BD_LAST_IN_BD_CHAIN_SHIFT 6 -#define ISCSI_BD_FIRST_IN_BD_CHAIN (0x1<<7) -#define ISCSI_BD_FIRST_IN_BD_CHAIN_SHIFT 7 -#define ISCSI_BD_RESERVED2 (0xFF<<8) -#define ISCSI_BD_RESERVED2_SHIFT 8 - u16 reserved3; -#endif -}; - - -/* - * iSCSI Cleanup SQ WQE - */ -struct bnx2i_cleanup_request { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 reserved1; - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 reserved1; - u8 op_code; -#endif - u32 reserved2[3]; -#if defined(__BIG_ENDIAN) - u16 reserved3; - u16 itt; -#define ISCSI_CLEANUP_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_CLEANUP_REQUEST_INDEX_SHIFT 0 -#define ISCSI_CLEANUP_REQUEST_TYPE (0x3<<14) -#define ISCSI_CLEANUP_REQUEST_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_CLEANUP_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_CLEANUP_REQUEST_INDEX_SHIFT 0 -#define ISCSI_CLEANUP_REQUEST_TYPE (0x3<<14) -#define ISCSI_CLEANUP_REQUEST_TYPE_SHIFT 14 - u16 reserved3; -#endif - u32 reserved4[10]; -#if defined(__BIG_ENDIAN) - u8 cq_index; - u8 reserved6; - u16 reserved5; -#elif defined(__LITTLE_ENDIAN) - u16 reserved5; - u8 reserved6; - u8 cq_index; -#endif -}; - - -/* - * iSCSI Cleanup CQE - */ -struct bnx2i_cleanup_response { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 status; - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 status; - u8 op_code; -#endif - u32 reserved1[3]; - u32 reserved2[2]; -#if defined(__BIG_ENDIAN) - u16 reserved4; - u8 err_code; - u8 reserved3; -#elif defined(__LITTLE_ENDIAN) - u8 reserved3; - u8 err_code; - u16 reserved4; -#endif - u32 reserved5[7]; -#if defined(__BIG_ENDIAN) - u16 reserved6; - u16 itt; -#define ISCSI_CLEANUP_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_CLEANUP_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_CLEANUP_RESPONSE_TYPE (0x3<<14) -#define ISCSI_CLEANUP_RESPONSE_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_CLEANUP_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_CLEANUP_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_CLEANUP_RESPONSE_TYPE (0x3<<14) -#define ISCSI_CLEANUP_RESPONSE_TYPE_SHIFT 14 - u16 reserved6; -#endif - u32 cq_req_sn; -}; - - -/* - * SCSI read/write SQ WQE - */ -struct bnx2i_cmd_request { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 op_attr; -#define ISCSI_CMD_REQUEST_TASK_ATTR (0x7<<0) -#define ISCSI_CMD_REQUEST_TASK_ATTR_SHIFT 0 -#define ISCSI_CMD_REQUEST_RESERVED1 (0x3<<3) -#define ISCSI_CMD_REQUEST_RESERVED1_SHIFT 3 -#define ISCSI_CMD_REQUEST_WRITE (0x1<<5) -#define ISCSI_CMD_REQUEST_WRITE_SHIFT 5 -#define ISCSI_CMD_REQUEST_READ (0x1<<6) -#define ISCSI_CMD_REQUEST_READ_SHIFT 6 -#define ISCSI_CMD_REQUEST_FINAL (0x1<<7) -#define ISCSI_CMD_REQUEST_FINAL_SHIFT 7 - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 op_attr; -#define ISCSI_CMD_REQUEST_TASK_ATTR (0x7<<0) -#define ISCSI_CMD_REQUEST_TASK_ATTR_SHIFT 0 -#define ISCSI_CMD_REQUEST_RESERVED1 (0x3<<3) -#define ISCSI_CMD_REQUEST_RESERVED1_SHIFT 3 -#define ISCSI_CMD_REQUEST_WRITE (0x1<<5) -#define ISCSI_CMD_REQUEST_WRITE_SHIFT 5 -#define ISCSI_CMD_REQUEST_READ (0x1<<6) -#define ISCSI_CMD_REQUEST_READ_SHIFT 6 -#define ISCSI_CMD_REQUEST_FINAL (0x1<<7) -#define ISCSI_CMD_REQUEST_FINAL_SHIFT 7 - u8 op_code; -#endif -#if defined(__BIG_ENDIAN) - u16 ud_buffer_offset; - u16 sd_buffer_offset; -#elif defined(__LITTLE_ENDIAN) - u16 sd_buffer_offset; - u16 ud_buffer_offset; -#endif - u32 lun[2]; -#if defined(__BIG_ENDIAN) - u16 reserved2; - u16 itt; -#define ISCSI_CMD_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_CMD_REQUEST_INDEX_SHIFT 0 -#define ISCSI_CMD_REQUEST_TYPE (0x3<<14) -#define ISCSI_CMD_REQUEST_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_CMD_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_CMD_REQUEST_INDEX_SHIFT 0 -#define ISCSI_CMD_REQUEST_TYPE (0x3<<14) -#define ISCSI_CMD_REQUEST_TYPE_SHIFT 14 - u16 reserved2; -#endif - u32 total_data_transfer_length; - u32 cmd_sn; - u32 reserved3; - u32 cdb[4]; - u32 zero_fill; - u32 bd_list_addr_lo; - u32 bd_list_addr_hi; -#if defined(__BIG_ENDIAN) - u8 cq_index; - u8 sd_start_bd_index; - u8 ud_start_bd_index; - u8 num_bds; -#elif defined(__LITTLE_ENDIAN) - u8 num_bds; - u8 ud_start_bd_index; - u8 sd_start_bd_index; - u8 cq_index; -#endif -}; - - -/* - * task statistics for write response - */ -struct bnx2i_write_resp_task_stat { - u32 num_data_ins; -}; - -/* - * task statistics for read response - */ -struct bnx2i_read_resp_task_stat { -#if defined(__BIG_ENDIAN) - u16 num_data_outs; - u16 num_r2ts; -#elif defined(__LITTLE_ENDIAN) - u16 num_r2ts; - u16 num_data_outs; -#endif -}; - -/* - * task statistics for iSCSI cmd response - */ -union bnx2i_cmd_resp_task_stat { - struct bnx2i_write_resp_task_stat write_stat; - struct bnx2i_read_resp_task_stat read_stat; -}; - -/* - * SCSI Command CQE - */ -struct bnx2i_cmd_response { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 response_flags; -#define ISCSI_CMD_RESPONSE_RESERVED0 (0x1<<0) -#define ISCSI_CMD_RESPONSE_RESERVED0_SHIFT 0 -#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW (0x1<<1) -#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW_SHIFT 1 -#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW (0x1<<2) -#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW_SHIFT 2 -#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW (0x1<<3) -#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW_SHIFT 3 -#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW (0x1<<4) -#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW_SHIFT 4 -#define ISCSI_CMD_RESPONSE_RESERVED1 (0x7<<5) -#define ISCSI_CMD_RESPONSE_RESERVED1_SHIFT 5 - u8 response; - u8 status; -#elif defined(__LITTLE_ENDIAN) - u8 status; - u8 response; - u8 response_flags; -#define ISCSI_CMD_RESPONSE_RESERVED0 (0x1<<0) -#define ISCSI_CMD_RESPONSE_RESERVED0_SHIFT 0 -#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW (0x1<<1) -#define ISCSI_CMD_RESPONSE_RESIDUAL_UNDERFLOW_SHIFT 1 -#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW (0x1<<2) -#define ISCSI_CMD_RESPONSE_RESIDUAL_OVERFLOW_SHIFT 2 -#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW (0x1<<3) -#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_UNDERFLOW_SHIFT 3 -#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW (0x1<<4) -#define ISCSI_CMD_RESPONSE_BR_RESIDUAL_OVERFLOW_SHIFT 4 -#define ISCSI_CMD_RESPONSE_RESERVED1 (0x7<<5) -#define ISCSI_CMD_RESPONSE_RESERVED1_SHIFT 5 - u8 op_code; -#endif - u32 data_length; - u32 exp_cmd_sn; - u32 max_cmd_sn; - u32 reserved2; - u32 residual_count; -#if defined(__BIG_ENDIAN) - u16 reserved4; - u8 err_code; - u8 reserved3; -#elif defined(__LITTLE_ENDIAN) - u8 reserved3; - u8 err_code; - u16 reserved4; -#endif - u32 reserved5[5]; - union bnx2i_cmd_resp_task_stat task_stat; - u32 reserved6; -#if defined(__BIG_ENDIAN) - u16 reserved7; - u16 itt; -#define ISCSI_CMD_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_CMD_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_CMD_RESPONSE_TYPE (0x3<<14) -#define ISCSI_CMD_RESPONSE_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_CMD_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_CMD_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_CMD_RESPONSE_TYPE (0x3<<14) -#define ISCSI_CMD_RESPONSE_TYPE_SHIFT 14 - u16 reserved7; -#endif - u32 cq_req_sn; -}; - - - -/* - * firmware middle-path request SQ WQE - */ -struct bnx2i_fw_mp_request { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 op_attr; - u16 hdr_opaque1; -#elif defined(__LITTLE_ENDIAN) - u16 hdr_opaque1; - u8 op_attr; - u8 op_code; -#endif - u32 data_length; - u32 hdr_opaque2[2]; -#if defined(__BIG_ENDIAN) - u16 reserved0; - u16 itt; -#define ISCSI_FW_MP_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_FW_MP_REQUEST_INDEX_SHIFT 0 -#define ISCSI_FW_MP_REQUEST_TYPE (0x3<<14) -#define ISCSI_FW_MP_REQUEST_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_FW_MP_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_FW_MP_REQUEST_INDEX_SHIFT 0 -#define ISCSI_FW_MP_REQUEST_TYPE (0x3<<14) -#define ISCSI_FW_MP_REQUEST_TYPE_SHIFT 14 - u16 reserved0; -#endif - u32 hdr_opaque3[4]; - u32 resp_bd_list_addr_lo; - u32 resp_bd_list_addr_hi; - u32 resp_buffer; -#define ISCSI_FW_MP_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0) -#define ISCSI_FW_MP_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0 -#define ISCSI_FW_MP_REQUEST_NUM_RESP_BDS (0xFF<<24) -#define ISCSI_FW_MP_REQUEST_NUM_RESP_BDS_SHIFT 24 -#if defined(__BIG_ENDIAN) - u16 reserved4; - u8 reserved3; - u8 flags; -#define ISCSI_FW_MP_REQUEST_RESERVED1 (0x1<<0) -#define ISCSI_FW_MP_REQUEST_RESERVED1_SHIFT 0 -#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION (0x1<<1) -#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION_SHIFT 1 -#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2) -#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2 -#define ISCSI_FW_MP_REQUEST_RESERVED2 (0x1F<<3) -#define ISCSI_FW_MP_REQUEST_RESERVED2_SHIFT 3 -#elif defined(__LITTLE_ENDIAN) - u8 flags; -#define ISCSI_FW_MP_REQUEST_RESERVED1 (0x1<<0) -#define ISCSI_FW_MP_REQUEST_RESERVED1_SHIFT 0 -#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION (0x1<<1) -#define ISCSI_FW_MP_REQUEST_LOCAL_COMPLETION_SHIFT 1 -#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2) -#define ISCSI_FW_MP_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2 -#define ISCSI_FW_MP_REQUEST_RESERVED2 (0x1F<<3) -#define ISCSI_FW_MP_REQUEST_RESERVED2_SHIFT 3 - u8 reserved3; - u16 reserved4; -#endif - u32 bd_list_addr_lo; - u32 bd_list_addr_hi; -#if defined(__BIG_ENDIAN) - u8 cq_index; - u8 reserved6; - u8 reserved5; - u8 num_bds; -#elif defined(__LITTLE_ENDIAN) - u8 num_bds; - u8 reserved5; - u8 reserved6; - u8 cq_index; -#endif -}; - - -/* - * firmware response - CQE: used only by firmware - */ -struct bnx2i_fw_response { - u32 hdr_dword1[2]; - u32 hdr_exp_cmd_sn; - u32 hdr_max_cmd_sn; - u32 hdr_ttt; - u32 hdr_res_cnt; - u32 cqe_flags; -#define ISCSI_FW_RESPONSE_RESERVED2 (0xFF<<0) -#define ISCSI_FW_RESPONSE_RESERVED2_SHIFT 0 -#define ISCSI_FW_RESPONSE_ERR_CODE (0xFF<<8) -#define ISCSI_FW_RESPONSE_ERR_CODE_SHIFT 8 -#define ISCSI_FW_RESPONSE_RESERVED3 (0xFFFF<<16) -#define ISCSI_FW_RESPONSE_RESERVED3_SHIFT 16 - u32 stat_sn; - u32 hdr_dword2[2]; - u32 hdr_dword3[2]; - u32 task_stat; - u32 reserved0; - u32 hdr_itt; - u32 cq_req_sn; -}; - - -/* - * iSCSI KCQ CQE parameters - */ -union iscsi_kcqe_params { - u32 reserved0[4]; -}; - -/* - * iSCSI KCQ CQE - */ -struct iscsi_kcqe { - u32 iscsi_conn_id; - u32 completion_status; - u32 iscsi_conn_context_id; - union iscsi_kcqe_params params; -#if defined(__BIG_ENDIAN) - u8 flags; -#define ISCSI_KCQE_RESERVED0 (0xF<<0) -#define ISCSI_KCQE_RESERVED0_SHIFT 0 -#define ISCSI_KCQE_LAYER_CODE (0x7<<4) -#define ISCSI_KCQE_LAYER_CODE_SHIFT 4 -#define ISCSI_KCQE_RESERVED1 (0x1<<7) -#define ISCSI_KCQE_RESERVED1_SHIFT 7 - u8 op_code; - u16 qe_self_seq; -#elif defined(__LITTLE_ENDIAN) - u16 qe_self_seq; - u8 op_code; - u8 flags; -#define ISCSI_KCQE_RESERVED0 (0xF<<0) -#define ISCSI_KCQE_RESERVED0_SHIFT 0 -#define ISCSI_KCQE_LAYER_CODE (0x7<<4) -#define ISCSI_KCQE_LAYER_CODE_SHIFT 4 -#define ISCSI_KCQE_RESERVED1 (0x1<<7) -#define ISCSI_KCQE_RESERVED1_SHIFT 7 -#endif -}; - - - -/* - * iSCSI KWQE header - */ -struct iscsi_kwqe_header { -#if defined(__BIG_ENDIAN) - u8 flags; -#define ISCSI_KWQE_HEADER_RESERVED0 (0xF<<0) -#define ISCSI_KWQE_HEADER_RESERVED0_SHIFT 0 -#define ISCSI_KWQE_HEADER_LAYER_CODE (0x7<<4) -#define ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT 4 -#define ISCSI_KWQE_HEADER_RESERVED1 (0x1<<7) -#define ISCSI_KWQE_HEADER_RESERVED1_SHIFT 7 - u8 op_code; -#elif defined(__LITTLE_ENDIAN) - u8 op_code; - u8 flags; -#define ISCSI_KWQE_HEADER_RESERVED0 (0xF<<0) -#define ISCSI_KWQE_HEADER_RESERVED0_SHIFT 0 -#define ISCSI_KWQE_HEADER_LAYER_CODE (0x7<<4) -#define ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT 4 -#define ISCSI_KWQE_HEADER_RESERVED1 (0x1<<7) -#define ISCSI_KWQE_HEADER_RESERVED1_SHIFT 7 -#endif -}; - -/* - * iSCSI firmware init request 1 - */ -struct iscsi_kwqe_init1 { -#if defined(__BIG_ENDIAN) - struct iscsi_kwqe_header hdr; - u8 reserved0; - u8 num_cqs; -#elif defined(__LITTLE_ENDIAN) - u8 num_cqs; - u8 reserved0; - struct iscsi_kwqe_header hdr; -#endif - u32 dummy_buffer_addr_lo; - u32 dummy_buffer_addr_hi; -#if defined(__BIG_ENDIAN) - u16 num_ccells_per_conn; - u16 num_tasks_per_conn; -#elif defined(__LITTLE_ENDIAN) - u16 num_tasks_per_conn; - u16 num_ccells_per_conn; -#endif -#if defined(__BIG_ENDIAN) - u16 sq_wqes_per_page; - u16 sq_num_wqes; -#elif defined(__LITTLE_ENDIAN) - u16 sq_num_wqes; - u16 sq_wqes_per_page; -#endif -#if defined(__BIG_ENDIAN) - u8 cq_log_wqes_per_page; - u8 flags; -#define ISCSI_KWQE_INIT1_PAGE_SIZE (0xF<<0) -#define ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT 0 -#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE (0x1<<4) -#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4 -#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5) -#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5 -#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6) -#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6 - u16 cq_num_wqes; -#elif defined(__LITTLE_ENDIAN) - u16 cq_num_wqes; - u8 flags; -#define ISCSI_KWQE_INIT1_PAGE_SIZE (0xF<<0) -#define ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT 0 -#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE (0x1<<4) -#define ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE_SHIFT 4 -#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE (0x1<<5) -#define ISCSI_KWQE_INIT1_KEEP_ALIVE_ENABLE_SHIFT 5 -#define ISCSI_KWQE_INIT1_RESERVED1 (0x3<<6) -#define ISCSI_KWQE_INIT1_RESERVED1_SHIFT 6 - u8 cq_log_wqes_per_page; -#endif -#if defined(__BIG_ENDIAN) - u16 cq_num_pages; - u16 sq_num_pages; -#elif defined(__LITTLE_ENDIAN) - u16 sq_num_pages; - u16 cq_num_pages; -#endif -#if defined(__BIG_ENDIAN) - u16 rq_buffer_size; - u16 rq_num_wqes; -#elif defined(__LITTLE_ENDIAN) - u16 rq_num_wqes; - u16 rq_buffer_size; -#endif -}; - -/* - * iSCSI firmware init request 2 - */ -struct iscsi_kwqe_init2 { -#if defined(__BIG_ENDIAN) - struct iscsi_kwqe_header hdr; - u16 max_cq_sqn; -#elif defined(__LITTLE_ENDIAN) - u16 max_cq_sqn; - struct iscsi_kwqe_header hdr; -#endif - u32 error_bit_map[2]; - u32 reserved1[5]; -}; - -/* - * Initial iSCSI connection offload request 1 - */ -struct iscsi_kwqe_conn_offload1 { -#if defined(__BIG_ENDIAN) - struct iscsi_kwqe_header hdr; - u16 iscsi_conn_id; -#elif defined(__LITTLE_ENDIAN) - u16 iscsi_conn_id; - struct iscsi_kwqe_header hdr; -#endif - u32 sq_page_table_addr_lo; - u32 sq_page_table_addr_hi; - u32 cq_page_table_addr_lo; - u32 cq_page_table_addr_hi; - u32 reserved0[3]; -}; - -/* - * iSCSI Page Table Entry (PTE) - */ -struct iscsi_pte { - u32 hi; - u32 lo; -}; - -/* - * Initial iSCSI connection offload request 2 - */ -struct iscsi_kwqe_conn_offload2 { -#if defined(__BIG_ENDIAN) - struct iscsi_kwqe_header hdr; - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - struct iscsi_kwqe_header hdr; -#endif - u32 rq_page_table_addr_lo; - u32 rq_page_table_addr_hi; - struct iscsi_pte sq_first_pte; - struct iscsi_pte cq_first_pte; - u32 num_additional_wqes; -}; - - -/* - * Initial iSCSI connection offload request 3 - */ -struct iscsi_kwqe_conn_offload3 { -#if defined(__BIG_ENDIAN) - struct iscsi_kwqe_header hdr; - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - struct iscsi_kwqe_header hdr; -#endif - u32 reserved1; - struct iscsi_pte qp_first_pte[3]; -}; - - -/* - * iSCSI connection update request - */ -struct iscsi_kwqe_conn_update { -#if defined(__BIG_ENDIAN) - struct iscsi_kwqe_header hdr; - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - struct iscsi_kwqe_header hdr; -#endif -#if defined(__BIG_ENDIAN) - u8 session_error_recovery_level; - u8 max_outstanding_r2ts; - u8 reserved2; - u8 conn_flags; -#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0) -#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST_SHIFT 0 -#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST (0x1<<1) -#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST_SHIFT 1 -#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T (0x1<<2) -#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2 -#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3) -#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3 -#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE (0x3<<4) -#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE_SHIFT 4 -#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0x3<<6) -#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 6 -#elif defined(__LITTLE_ENDIAN) - u8 conn_flags; -#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST (0x1<<0) -#define ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST_SHIFT 0 -#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST (0x1<<1) -#define ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST_SHIFT 1 -#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T (0x1<<2) -#define ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T_SHIFT 2 -#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA (0x1<<3) -#define ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA_SHIFT 3 -#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE (0x3<<4) -#define ISCSI_KWQE_CONN_UPDATE_OOO_SUPPORT_MODE_SHIFT 4 -#define ISCSI_KWQE_CONN_UPDATE_RESERVED1 (0x3<<6) -#define ISCSI_KWQE_CONN_UPDATE_RESERVED1_SHIFT 6 - u8 reserved2; - u8 max_outstanding_r2ts; - u8 session_error_recovery_level; -#endif - u32 context_id; - u32 max_send_pdu_length; - u32 max_recv_pdu_length; - u32 first_burst_length; - u32 max_burst_length; - u32 exp_stat_sn; -}; - -/* - * iSCSI destroy connection request - */ -struct iscsi_kwqe_conn_destroy { -#if defined(__BIG_ENDIAN) - struct iscsi_kwqe_header hdr; - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - struct iscsi_kwqe_header hdr; -#endif - u32 context_id; - u32 reserved1[6]; -}; - -/* - * iSCSI KWQ WQE - */ -union iscsi_kwqe { - struct iscsi_kwqe_init1 init1; - struct iscsi_kwqe_init2 init2; - struct iscsi_kwqe_conn_offload1 conn_offload1; - struct iscsi_kwqe_conn_offload2 conn_offload2; - struct iscsi_kwqe_conn_update conn_update; - struct iscsi_kwqe_conn_destroy conn_destroy; -}; - -/* - * iSCSI Login SQ WQE - */ -struct bnx2i_login_request { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 op_attr; -#define ISCSI_LOGIN_REQUEST_NEXT_STAGE (0x3<<0) -#define ISCSI_LOGIN_REQUEST_NEXT_STAGE_SHIFT 0 -#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE (0x3<<2) -#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE_SHIFT 2 -#define ISCSI_LOGIN_REQUEST_RESERVED0 (0x3<<4) -#define ISCSI_LOGIN_REQUEST_RESERVED0_SHIFT 4 -#define ISCSI_LOGIN_REQUEST_CONT (0x1<<6) -#define ISCSI_LOGIN_REQUEST_CONT_SHIFT 6 -#define ISCSI_LOGIN_REQUEST_TRANSIT (0x1<<7) -#define ISCSI_LOGIN_REQUEST_TRANSIT_SHIFT 7 - u8 version_max; - u8 version_min; -#elif defined(__LITTLE_ENDIAN) - u8 version_min; - u8 version_max; - u8 op_attr; -#define ISCSI_LOGIN_REQUEST_NEXT_STAGE (0x3<<0) -#define ISCSI_LOGIN_REQUEST_NEXT_STAGE_SHIFT 0 -#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE (0x3<<2) -#define ISCSI_LOGIN_REQUEST_CURRENT_STAGE_SHIFT 2 -#define ISCSI_LOGIN_REQUEST_RESERVED0 (0x3<<4) -#define ISCSI_LOGIN_REQUEST_RESERVED0_SHIFT 4 -#define ISCSI_LOGIN_REQUEST_CONT (0x1<<6) -#define ISCSI_LOGIN_REQUEST_CONT_SHIFT 6 -#define ISCSI_LOGIN_REQUEST_TRANSIT (0x1<<7) -#define ISCSI_LOGIN_REQUEST_TRANSIT_SHIFT 7 - u8 op_code; -#endif - u32 data_length; - u32 isid_lo; -#if defined(__BIG_ENDIAN) - u16 isid_hi; - u16 tsih; -#elif defined(__LITTLE_ENDIAN) - u16 tsih; - u16 isid_hi; -#endif -#if defined(__BIG_ENDIAN) - u16 reserved2; - u16 itt; -#define ISCSI_LOGIN_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_LOGIN_REQUEST_INDEX_SHIFT 0 -#define ISCSI_LOGIN_REQUEST_TYPE (0x3<<14) -#define ISCSI_LOGIN_REQUEST_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_LOGIN_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_LOGIN_REQUEST_INDEX_SHIFT 0 -#define ISCSI_LOGIN_REQUEST_TYPE (0x3<<14) -#define ISCSI_LOGIN_REQUEST_TYPE_SHIFT 14 - u16 reserved2; -#endif -#if defined(__BIG_ENDIAN) - u16 cid; - u16 reserved3; -#elif defined(__LITTLE_ENDIAN) - u16 reserved3; - u16 cid; -#endif - u32 cmd_sn; - u32 exp_stat_sn; - u32 reserved4; - u32 resp_bd_list_addr_lo; - u32 resp_bd_list_addr_hi; - u32 resp_buffer; -#define ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0) -#define ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0 -#define ISCSI_LOGIN_REQUEST_NUM_RESP_BDS (0xFF<<24) -#define ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT 24 -#if defined(__BIG_ENDIAN) - u16 reserved8; - u8 reserved7; - u8 flags; -#define ISCSI_LOGIN_REQUEST_RESERVED5 (0x3<<0) -#define ISCSI_LOGIN_REQUEST_RESERVED5_SHIFT 0 -#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2) -#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2 -#define ISCSI_LOGIN_REQUEST_RESERVED6 (0x1F<<3) -#define ISCSI_LOGIN_REQUEST_RESERVED6_SHIFT 3 -#elif defined(__LITTLE_ENDIAN) - u8 flags; -#define ISCSI_LOGIN_REQUEST_RESERVED5 (0x3<<0) -#define ISCSI_LOGIN_REQUEST_RESERVED5_SHIFT 0 -#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN (0x1<<2) -#define ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN_SHIFT 2 -#define ISCSI_LOGIN_REQUEST_RESERVED6 (0x1F<<3) -#define ISCSI_LOGIN_REQUEST_RESERVED6_SHIFT 3 - u8 reserved7; - u16 reserved8; -#endif - u32 bd_list_addr_lo; - u32 bd_list_addr_hi; -#if defined(__BIG_ENDIAN) - u8 cq_index; - u8 reserved10; - u8 reserved9; - u8 num_bds; -#elif defined(__LITTLE_ENDIAN) - u8 num_bds; - u8 reserved9; - u8 reserved10; - u8 cq_index; -#endif -}; - - -/* - * iSCSI Login CQE - */ -struct bnx2i_login_response { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 response_flags; -#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE (0x3<<0) -#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE_SHIFT 0 -#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE (0x3<<2) -#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE_SHIFT 2 -#define ISCSI_LOGIN_RESPONSE_RESERVED0 (0x3<<4) -#define ISCSI_LOGIN_RESPONSE_RESERVED0_SHIFT 4 -#define ISCSI_LOGIN_RESPONSE_CONT (0x1<<6) -#define ISCSI_LOGIN_RESPONSE_CONT_SHIFT 6 -#define ISCSI_LOGIN_RESPONSE_TRANSIT (0x1<<7) -#define ISCSI_LOGIN_RESPONSE_TRANSIT_SHIFT 7 - u8 version_max; - u8 version_active; -#elif defined(__LITTLE_ENDIAN) - u8 version_active; - u8 version_max; - u8 response_flags; -#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE (0x3<<0) -#define ISCSI_LOGIN_RESPONSE_NEXT_STAGE_SHIFT 0 -#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE (0x3<<2) -#define ISCSI_LOGIN_RESPONSE_CURRENT_STAGE_SHIFT 2 -#define ISCSI_LOGIN_RESPONSE_RESERVED0 (0x3<<4) -#define ISCSI_LOGIN_RESPONSE_RESERVED0_SHIFT 4 -#define ISCSI_LOGIN_RESPONSE_CONT (0x1<<6) -#define ISCSI_LOGIN_RESPONSE_CONT_SHIFT 6 -#define ISCSI_LOGIN_RESPONSE_TRANSIT (0x1<<7) -#define ISCSI_LOGIN_RESPONSE_TRANSIT_SHIFT 7 - u8 op_code; -#endif - u32 data_length; - u32 exp_cmd_sn; - u32 max_cmd_sn; - u32 reserved1[2]; -#if defined(__BIG_ENDIAN) - u16 reserved3; - u8 err_code; - u8 reserved2; -#elif defined(__LITTLE_ENDIAN) - u8 reserved2; - u8 err_code; - u16 reserved3; -#endif - u32 stat_sn; - u32 isid_lo; -#if defined(__BIG_ENDIAN) - u16 isid_hi; - u16 tsih; -#elif defined(__LITTLE_ENDIAN) - u16 tsih; - u16 isid_hi; -#endif -#if defined(__BIG_ENDIAN) - u8 status_class; - u8 status_detail; - u16 reserved4; -#elif defined(__LITTLE_ENDIAN) - u16 reserved4; - u8 status_detail; - u8 status_class; -#endif - u32 reserved5[3]; -#if defined(__BIG_ENDIAN) - u16 reserved6; - u16 itt; -#define ISCSI_LOGIN_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_LOGIN_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_LOGIN_RESPONSE_TYPE (0x3<<14) -#define ISCSI_LOGIN_RESPONSE_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_LOGIN_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_LOGIN_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_LOGIN_RESPONSE_TYPE (0x3<<14) -#define ISCSI_LOGIN_RESPONSE_TYPE_SHIFT 14 - u16 reserved6; -#endif - u32 cq_req_sn; -}; - - -/* - * iSCSI Logout SQ WQE - */ -struct bnx2i_logout_request { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 op_attr; -#define ISCSI_LOGOUT_REQUEST_REASON (0x7F<<0) -#define ISCSI_LOGOUT_REQUEST_REASON_SHIFT 0 -#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE (0x1<<7) -#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE_SHIFT 7 - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 op_attr; -#define ISCSI_LOGOUT_REQUEST_REASON (0x7F<<0) -#define ISCSI_LOGOUT_REQUEST_REASON_SHIFT 0 -#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE (0x1<<7) -#define ISCSI_LOGOUT_REQUEST_ALWAYS_ONE_SHIFT 7 - u8 op_code; -#endif - u32 data_length; - u32 reserved1[2]; -#if defined(__BIG_ENDIAN) - u16 reserved2; - u16 itt; -#define ISCSI_LOGOUT_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_LOGOUT_REQUEST_INDEX_SHIFT 0 -#define ISCSI_LOGOUT_REQUEST_TYPE (0x3<<14) -#define ISCSI_LOGOUT_REQUEST_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_LOGOUT_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_LOGOUT_REQUEST_INDEX_SHIFT 0 -#define ISCSI_LOGOUT_REQUEST_TYPE (0x3<<14) -#define ISCSI_LOGOUT_REQUEST_TYPE_SHIFT 14 - u16 reserved2; -#endif -#if defined(__BIG_ENDIAN) - u16 cid; - u16 reserved3; -#elif defined(__LITTLE_ENDIAN) - u16 reserved3; - u16 cid; -#endif - u32 cmd_sn; - u32 reserved4[5]; - u32 zero_fill; - u32 bd_list_addr_lo; - u32 bd_list_addr_hi; -#if defined(__BIG_ENDIAN) - u8 cq_index; - u8 reserved6; - u8 reserved5; - u8 num_bds; -#elif defined(__LITTLE_ENDIAN) - u8 num_bds; - u8 reserved5; - u8 reserved6; - u8 cq_index; -#endif -}; - - -/* - * iSCSI Logout CQE - */ -struct bnx2i_logout_response { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 reserved1; - u8 response; - u8 reserved0; -#elif defined(__LITTLE_ENDIAN) - u8 reserved0; - u8 response; - u8 reserved1; - u8 op_code; -#endif - u32 reserved2; - u32 exp_cmd_sn; - u32 max_cmd_sn; - u32 reserved3[2]; -#if defined(__BIG_ENDIAN) - u16 reserved5; - u8 err_code; - u8 reserved4; -#elif defined(__LITTLE_ENDIAN) - u8 reserved4; - u8 err_code; - u16 reserved5; -#endif - u32 reserved6[3]; -#if defined(__BIG_ENDIAN) - u16 time_to_wait; - u16 time_to_retain; -#elif defined(__LITTLE_ENDIAN) - u16 time_to_retain; - u16 time_to_wait; -#endif - u32 reserved7[3]; -#if defined(__BIG_ENDIAN) - u16 reserved8; - u16 itt; -#define ISCSI_LOGOUT_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_LOGOUT_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_LOGOUT_RESPONSE_TYPE (0x3<<14) -#define ISCSI_LOGOUT_RESPONSE_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_LOGOUT_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_LOGOUT_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_LOGOUT_RESPONSE_TYPE (0x3<<14) -#define ISCSI_LOGOUT_RESPONSE_TYPE_SHIFT 14 - u16 reserved8; -#endif - u32 cq_req_sn; -}; - - -/* - * iSCSI Nop-In CQE - */ -struct bnx2i_nop_in_msg { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 reserved1; - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 reserved1; - u8 op_code; -#endif - u32 data_length; - u32 exp_cmd_sn; - u32 max_cmd_sn; - u32 ttt; - u32 reserved2; -#if defined(__BIG_ENDIAN) - u16 reserved4; - u8 err_code; - u8 reserved3; -#elif defined(__LITTLE_ENDIAN) - u8 reserved3; - u8 err_code; - u16 reserved4; -#endif - u32 reserved5; - u32 lun[2]; - u32 reserved6[4]; -#if defined(__BIG_ENDIAN) - u16 reserved7; - u16 itt; -#define ISCSI_NOP_IN_MSG_INDEX (0x3FFF<<0) -#define ISCSI_NOP_IN_MSG_INDEX_SHIFT 0 -#define ISCSI_NOP_IN_MSG_TYPE (0x3<<14) -#define ISCSI_NOP_IN_MSG_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_NOP_IN_MSG_INDEX (0x3FFF<<0) -#define ISCSI_NOP_IN_MSG_INDEX_SHIFT 0 -#define ISCSI_NOP_IN_MSG_TYPE (0x3<<14) -#define ISCSI_NOP_IN_MSG_TYPE_SHIFT 14 - u16 reserved7; -#endif - u32 cq_req_sn; -}; - - -/* - * iSCSI NOP-OUT SQ WQE - */ -struct bnx2i_nop_out_request { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 op_attr; -#define ISCSI_NOP_OUT_REQUEST_RESERVED1 (0x7F<<0) -#define ISCSI_NOP_OUT_REQUEST_RESERVED1_SHIFT 0 -#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE (0x1<<7) -#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE_SHIFT 7 - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 op_attr; -#define ISCSI_NOP_OUT_REQUEST_RESERVED1 (0x7F<<0) -#define ISCSI_NOP_OUT_REQUEST_RESERVED1_SHIFT 0 -#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE (0x1<<7) -#define ISCSI_NOP_OUT_REQUEST_ALWAYS_ONE_SHIFT 7 - u8 op_code; -#endif - u32 data_length; - u32 lun[2]; -#if defined(__BIG_ENDIAN) - u16 reserved2; - u16 itt; -#define ISCSI_NOP_OUT_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_NOP_OUT_REQUEST_INDEX_SHIFT 0 -#define ISCSI_NOP_OUT_REQUEST_TYPE (0x3<<14) -#define ISCSI_NOP_OUT_REQUEST_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_NOP_OUT_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_NOP_OUT_REQUEST_INDEX_SHIFT 0 -#define ISCSI_NOP_OUT_REQUEST_TYPE (0x3<<14) -#define ISCSI_NOP_OUT_REQUEST_TYPE_SHIFT 14 - u16 reserved2; -#endif - u32 ttt; - u32 cmd_sn; - u32 reserved3[2]; - u32 resp_bd_list_addr_lo; - u32 resp_bd_list_addr_hi; - u32 resp_buffer; -#define ISCSI_NOP_OUT_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0) -#define ISCSI_NOP_OUT_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0 -#define ISCSI_NOP_OUT_REQUEST_NUM_RESP_BDS (0xFF<<24) -#define ISCSI_NOP_OUT_REQUEST_NUM_RESP_BDS_SHIFT 24 -#if defined(__BIG_ENDIAN) - u16 reserved7; - u8 reserved6; - u8 flags; -#define ISCSI_NOP_OUT_REQUEST_RESERVED4 (0x1<<0) -#define ISCSI_NOP_OUT_REQUEST_RESERVED4_SHIFT 0 -#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION (0x1<<1) -#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION_SHIFT 1 -#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL (0x3F<<2) -#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL_SHIFT 2 -#elif defined(__LITTLE_ENDIAN) - u8 flags; -#define ISCSI_NOP_OUT_REQUEST_RESERVED4 (0x1<<0) -#define ISCSI_NOP_OUT_REQUEST_RESERVED4_SHIFT 0 -#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION (0x1<<1) -#define ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION_SHIFT 1 -#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL (0x3F<<2) -#define ISCSI_NOP_OUT_REQUEST_ZERO_FILL_SHIFT 2 - u8 reserved6; - u16 reserved7; -#endif - u32 bd_list_addr_lo; - u32 bd_list_addr_hi; -#if defined(__BIG_ENDIAN) - u8 cq_index; - u8 reserved9; - u8 reserved8; - u8 num_bds; -#elif defined(__LITTLE_ENDIAN) - u8 num_bds; - u8 reserved8; - u8 reserved9; - u8 cq_index; -#endif -}; - -/* - * iSCSI Reject CQE - */ -struct bnx2i_reject_msg { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 reserved1; - u8 reason; - u8 reserved0; -#elif defined(__LITTLE_ENDIAN) - u8 reserved0; - u8 reason; - u8 reserved1; - u8 op_code; -#endif - u32 data_length; - u32 exp_cmd_sn; - u32 max_cmd_sn; - u32 reserved2[2]; -#if defined(__BIG_ENDIAN) - u16 reserved4; - u8 err_code; - u8 reserved3; -#elif defined(__LITTLE_ENDIAN) - u8 reserved3; - u8 err_code; - u16 reserved4; -#endif - u32 reserved5[8]; - u32 cq_req_sn; -}; - -/* - * bnx2i iSCSI TMF SQ WQE - */ -struct bnx2i_tmf_request { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 op_attr; -#define ISCSI_TMF_REQUEST_FUNCTION (0x7F<<0) -#define ISCSI_TMF_REQUEST_FUNCTION_SHIFT 0 -#define ISCSI_TMF_REQUEST_ALWAYS_ONE (0x1<<7) -#define ISCSI_TMF_REQUEST_ALWAYS_ONE_SHIFT 7 - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 op_attr; -#define ISCSI_TMF_REQUEST_FUNCTION (0x7F<<0) -#define ISCSI_TMF_REQUEST_FUNCTION_SHIFT 0 -#define ISCSI_TMF_REQUEST_ALWAYS_ONE (0x1<<7) -#define ISCSI_TMF_REQUEST_ALWAYS_ONE_SHIFT 7 - u8 op_code; -#endif - u32 data_length; - u32 lun[2]; -#if defined(__BIG_ENDIAN) - u16 reserved1; - u16 itt; -#define ISCSI_TMF_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_TMF_REQUEST_INDEX_SHIFT 0 -#define ISCSI_TMF_REQUEST_TYPE (0x3<<14) -#define ISCSI_TMF_REQUEST_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_TMF_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_TMF_REQUEST_INDEX_SHIFT 0 -#define ISCSI_TMF_REQUEST_TYPE (0x3<<14) -#define ISCSI_TMF_REQUEST_TYPE_SHIFT 14 - u16 reserved1; -#endif - u32 ref_itt; - u32 cmd_sn; - u32 reserved2; - u32 ref_cmd_sn; - u32 reserved3[3]; - u32 zero_fill; - u32 bd_list_addr_lo; - u32 bd_list_addr_hi; -#if defined(__BIG_ENDIAN) - u8 cq_index; - u8 reserved5; - u8 reserved4; - u8 num_bds; -#elif defined(__LITTLE_ENDIAN) - u8 num_bds; - u8 reserved4; - u8 reserved5; - u8 cq_index; -#endif -}; - -/* - * iSCSI Text SQ WQE - */ -struct bnx2i_text_request { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 op_attr; -#define ISCSI_TEXT_REQUEST_RESERVED1 (0x3F<<0) -#define ISCSI_TEXT_REQUEST_RESERVED1_SHIFT 0 -#define ISCSI_TEXT_REQUEST_CONT (0x1<<6) -#define ISCSI_TEXT_REQUEST_CONT_SHIFT 6 -#define ISCSI_TEXT_REQUEST_FINAL (0x1<<7) -#define ISCSI_TEXT_REQUEST_FINAL_SHIFT 7 - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 op_attr; -#define ISCSI_TEXT_REQUEST_RESERVED1 (0x3F<<0) -#define ISCSI_TEXT_REQUEST_RESERVED1_SHIFT 0 -#define ISCSI_TEXT_REQUEST_CONT (0x1<<6) -#define ISCSI_TEXT_REQUEST_CONT_SHIFT 6 -#define ISCSI_TEXT_REQUEST_FINAL (0x1<<7) -#define ISCSI_TEXT_REQUEST_FINAL_SHIFT 7 - u8 op_code; -#endif - u32 data_length; - u32 lun[2]; -#if defined(__BIG_ENDIAN) - u16 reserved3; - u16 itt; -#define ISCSI_TEXT_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_TEXT_REQUEST_INDEX_SHIFT 0 -#define ISCSI_TEXT_REQUEST_TYPE (0x3<<14) -#define ISCSI_TEXT_REQUEST_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_TEXT_REQUEST_INDEX (0x3FFF<<0) -#define ISCSI_TEXT_REQUEST_INDEX_SHIFT 0 -#define ISCSI_TEXT_REQUEST_TYPE (0x3<<14) -#define ISCSI_TEXT_REQUEST_TYPE_SHIFT 14 - u16 reserved3; -#endif - u32 ttt; - u32 cmd_sn; - u32 reserved4[2]; - u32 resp_bd_list_addr_lo; - u32 resp_bd_list_addr_hi; - u32 resp_buffer; -#define ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH (0xFFFFFF<<0) -#define ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT 0 -#define ISCSI_TEXT_REQUEST_NUM_RESP_BDS (0xFF<<24) -#define ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT 24 - u32 zero_fill; - u32 bd_list_addr_lo; - u32 bd_list_addr_hi; -#if defined(__BIG_ENDIAN) - u8 cq_index; - u8 reserved7; - u8 reserved6; - u8 num_bds; -#elif defined(__LITTLE_ENDIAN) - u8 num_bds; - u8 reserved6; - u8 reserved7; - u8 cq_index; -#endif -}; - -/* - * iSCSI SQ WQE - */ -union iscsi_request { - struct bnx2i_cmd_request cmd; - struct bnx2i_tmf_request tmf; - struct bnx2i_nop_out_request nop_out; - struct bnx2i_login_request login_req; - struct bnx2i_text_request text; - struct bnx2i_logout_request logout_req; - struct bnx2i_cleanup_request cleanup; -}; - - -/* - * iSCSI TMF CQE - */ -struct bnx2i_tmf_response { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 reserved1; - u8 response; - u8 reserved0; -#elif defined(__LITTLE_ENDIAN) - u8 reserved0; - u8 response; - u8 reserved1; - u8 op_code; -#endif - u32 reserved2; - u32 exp_cmd_sn; - u32 max_cmd_sn; - u32 reserved3[2]; -#if defined(__BIG_ENDIAN) - u16 reserved5; - u8 err_code; - u8 reserved4; -#elif defined(__LITTLE_ENDIAN) - u8 reserved4; - u8 err_code; - u16 reserved5; -#endif - u32 reserved6[7]; -#if defined(__BIG_ENDIAN) - u16 reserved7; - u16 itt; -#define ISCSI_TMF_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_TMF_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_TMF_RESPONSE_TYPE (0x3<<14) -#define ISCSI_TMF_RESPONSE_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_TMF_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_TMF_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_TMF_RESPONSE_TYPE (0x3<<14) -#define ISCSI_TMF_RESPONSE_TYPE_SHIFT 14 - u16 reserved7; -#endif - u32 cq_req_sn; -}; - -/* - * iSCSI Text CQE - */ -struct bnx2i_text_response { -#if defined(__BIG_ENDIAN) - u8 op_code; - u8 response_flags; -#define ISCSI_TEXT_RESPONSE_RESERVED1 (0x3F<<0) -#define ISCSI_TEXT_RESPONSE_RESERVED1_SHIFT 0 -#define ISCSI_TEXT_RESPONSE_CONT (0x1<<6) -#define ISCSI_TEXT_RESPONSE_CONT_SHIFT 6 -#define ISCSI_TEXT_RESPONSE_FINAL (0x1<<7) -#define ISCSI_TEXT_RESPONSE_FINAL_SHIFT 7 - u16 reserved0; -#elif defined(__LITTLE_ENDIAN) - u16 reserved0; - u8 response_flags; -#define ISCSI_TEXT_RESPONSE_RESERVED1 (0x3F<<0) -#define ISCSI_TEXT_RESPONSE_RESERVED1_SHIFT 0 -#define ISCSI_TEXT_RESPONSE_CONT (0x1<<6) -#define ISCSI_TEXT_RESPONSE_CONT_SHIFT 6 -#define ISCSI_TEXT_RESPONSE_FINAL (0x1<<7) -#define ISCSI_TEXT_RESPONSE_FINAL_SHIFT 7 - u8 op_code; -#endif - u32 data_length; - u32 exp_cmd_sn; - u32 max_cmd_sn; - u32 ttt; - u32 reserved2; -#if defined(__BIG_ENDIAN) - u16 reserved4; - u8 err_code; - u8 reserved3; -#elif defined(__LITTLE_ENDIAN) - u8 reserved3; - u8 err_code; - u16 reserved4; -#endif - u32 reserved5; - u32 lun[2]; - u32 reserved6[4]; -#if defined(__BIG_ENDIAN) - u16 reserved7; - u16 itt; -#define ISCSI_TEXT_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_TEXT_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_TEXT_RESPONSE_TYPE (0x3<<14) -#define ISCSI_TEXT_RESPONSE_TYPE_SHIFT 14 -#elif defined(__LITTLE_ENDIAN) - u16 itt; -#define ISCSI_TEXT_RESPONSE_INDEX (0x3FFF<<0) -#define ISCSI_TEXT_RESPONSE_INDEX_SHIFT 0 -#define ISCSI_TEXT_RESPONSE_TYPE (0x3<<14) -#define ISCSI_TEXT_RESPONSE_TYPE_SHIFT 14 - u16 reserved7; -#endif - u32 cq_req_sn; -}; - -/* - * iSCSI CQE - */ -union iscsi_response { - struct bnx2i_cmd_response cmd; - struct bnx2i_tmf_response tmf; - struct bnx2i_login_response login_resp; - struct bnx2i_text_response text; - struct bnx2i_logout_response logout_resp; - struct bnx2i_cleanup_response cleanup; - struct bnx2i_reject_msg reject; - struct bnx2i_async_msg async; - struct bnx2i_nop_in_msg nop_in; -}; - -#endif /* __57XX_ISCSI_HSI_LINUX_LE__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/Kconfig b/ANDROID_3.4.5/drivers/scsi/bnx2i/Kconfig deleted file mode 100644 index 01cff189..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config SCSI_BNX2_ISCSI - tristate "Broadcom NetXtreme II iSCSI support" - depends on NET - depends on PCI - select SCSI_ISCSI_ATTRS - select NETDEVICES - select ETHERNET - select NET_VENDOR_BROADCOM - select CNIC - ---help--- - This driver supports iSCSI offload for the Broadcom NetXtreme II - devices. diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/Makefile b/ANDROID_3.4.5/drivers/scsi/bnx2i/Makefile deleted file mode 100644 index b5802bd2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -bnx2i-y := bnx2i_init.o bnx2i_hwi.o bnx2i_iscsi.o bnx2i_sysfs.o - -obj-$(CONFIG_SCSI_BNX2_ISCSI) += bnx2i.o diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i.h b/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i.h deleted file mode 100644 index 0bd70e80..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i.h +++ /dev/null @@ -1,821 +0,0 @@ -/* bnx2i.h: Broadcom NetXtreme II iSCSI driver. - * - * Copyright (c) 2006 - 2011 Broadcom Corporation - * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. - * Copyright (c) 2007, 2008 Mike Christie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) - * Maintained by: Eddie Wai (eddie.wai@broadcom.com) - */ - -#ifndef _BNX2I_H_ -#define _BNX2I_H_ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../../net/ethernet/broadcom/cnic_if.h" -#include "57xx_iscsi_hsi.h" -#include "57xx_iscsi_constants.h" - -#define BNX2_ISCSI_DRIVER_NAME "bnx2i" - -#define BNX2I_MAX_ADAPTERS 8 - -#define ISCSI_MAX_CONNS_PER_HBA 128 -#define ISCSI_MAX_SESS_PER_HBA ISCSI_MAX_CONNS_PER_HBA -#define ISCSI_MAX_CMDS_PER_SESS 128 - -/* Total active commands across all connections supported by devices */ -#define ISCSI_MAX_CMDS_PER_HBA_5708 (28 * (ISCSI_MAX_CMDS_PER_SESS - 1)) -#define ISCSI_MAX_CMDS_PER_HBA_5709 (128 * (ISCSI_MAX_CMDS_PER_SESS - 1)) -#define ISCSI_MAX_CMDS_PER_HBA_57710 (256 * (ISCSI_MAX_CMDS_PER_SESS - 1)) - -#define ISCSI_MAX_BDS_PER_CMD 32 - -#define MAX_PAGES_PER_CTRL_STRUCT_POOL 8 -#define BNX2I_RESERVED_SLOW_PATH_CMD_SLOTS 4 - -#define BNX2I_5771X_DBELL_PAGE_SIZE 128 - -/* 5706/08 hardware has limit on maximum buffer size per BD it can handle */ -#define MAX_BD_LENGTH 65535 -#define BD_SPLIT_SIZE 32768 - -/* min, max & default values for SQ/RQ/CQ size, configurable via' modparam */ -#define BNX2I_SQ_WQES_MIN 16 -#define BNX2I_570X_SQ_WQES_MAX 128 -#define BNX2I_5770X_SQ_WQES_MAX 512 -#define BNX2I_570X_SQ_WQES_DEFAULT 128 -#define BNX2I_5770X_SQ_WQES_DEFAULT 128 - -#define BNX2I_570X_CQ_WQES_MAX 128 -#define BNX2I_5770X_CQ_WQES_MAX 512 - -#define BNX2I_RQ_WQES_MIN 16 -#define BNX2I_RQ_WQES_MAX 32 -#define BNX2I_RQ_WQES_DEFAULT 16 - -/* CCELLs per conn */ -#define BNX2I_CCELLS_MIN 16 -#define BNX2I_CCELLS_MAX 96 -#define BNX2I_CCELLS_DEFAULT 64 - -#define ITT_INVALID_SIGNATURE 0xFFFF - -#define ISCSI_CMD_CLEANUP_TIMEOUT 100 - -#define BNX2I_CONN_CTX_BUF_SIZE 16384 - -#define BNX2I_SQ_WQE_SIZE 64 -#define BNX2I_RQ_WQE_SIZE 256 -#define BNX2I_CQE_SIZE 64 - -#define MB_KERNEL_CTX_SHIFT 8 -#define MB_KERNEL_CTX_SIZE (1 << MB_KERNEL_CTX_SHIFT) - -#define CTX_SHIFT 7 -#define GET_CID_NUM(cid_addr) ((cid_addr) >> CTX_SHIFT) - -#define CTX_OFFSET 0x10000 -#define MAX_CID_CNT 0x4000 - -#define BNX2I_570X_PAGE_SIZE_DEFAULT 4096 - -/* 5709 context registers */ -#define BNX2_MQ_CONFIG2 0x00003d00 -#define BNX2_MQ_CONFIG2_CONT_SZ (0x7L<<4) -#define BNX2_MQ_CONFIG2_FIRST_L4L5 (0x1fL<<8) - -/* 57710's BAR2 is mapped to doorbell registers */ -#define BNX2X_DOORBELL_PCI_BAR 2 -#define BNX2X_MAX_CQS 8 - -#define CNIC_ARM_CQE 1 -#define CNIC_ARM_CQE_FP 2 -#define CNIC_DISARM_CQE 0 - -#define REG_RD(__hba, offset) \ - readl(__hba->regview + offset) -#define REG_WR(__hba, offset, val) \ - writel(val, __hba->regview + offset) - - -/** - * struct generic_pdu_resc - login pdu resource structure - * - * @req_buf: driver buffer used to stage payload associated with - * the login request - * @req_dma_addr: dma address for iscsi login request payload buffer - * @req_buf_size: actual login request payload length - * @req_wr_ptr: pointer into login request buffer when next data is - * to be written - * @resp_hdr: iscsi header where iscsi login response header is to - * be recreated - * @resp_buf: buffer to stage login response payload - * @resp_dma_addr: login response payload buffer dma address - * @resp_buf_size: login response paylod length - * @resp_wr_ptr: pointer into login response buffer when next data is - * to be written - * @req_bd_tbl: iscsi login request payload BD table - * @req_bd_dma: login request BD table dma address - * @resp_bd_tbl: iscsi login response payload BD table - * @resp_bd_dma: login request BD table dma address - * - * following structure defines buffer info for generic pdus such as iSCSI Login, - * Logout and NOP - */ -struct generic_pdu_resc { - char *req_buf; - dma_addr_t req_dma_addr; - u32 req_buf_size; - char *req_wr_ptr; - struct iscsi_hdr resp_hdr; - char *resp_buf; - dma_addr_t resp_dma_addr; - u32 resp_buf_size; - char *resp_wr_ptr; - char *req_bd_tbl; - dma_addr_t req_bd_dma; - char *resp_bd_tbl; - dma_addr_t resp_bd_dma; -}; - - -/** - * struct bd_resc_page - tracks DMA'able memory allocated for BD tables - * - * @link: list head to link elements - * @max_ptrs: maximun pointers that can be stored in this page - * @num_valid: number of pointer valid in this page - * @page: base addess for page pointer array - * - * structure to track DMA'able memory allocated for command BD tables - */ -struct bd_resc_page { - struct list_head link; - u32 max_ptrs; - u32 num_valid; - void *page[1]; -}; - - -/** - * struct io_bdt - I/O buffer destricptor table - * - * @bd_tbl: BD table's virtual address - * @bd_tbl_dma: BD table's dma address - * @bd_valid: num valid BD entries - * - * IO BD table - */ -struct io_bdt { - struct iscsi_bd *bd_tbl; - dma_addr_t bd_tbl_dma; - u16 bd_valid; -}; - - -/** - * bnx2i_cmd - iscsi command structure - * - * @hdr: iSCSI header - * @conn: iscsi_conn pointer - * @scsi_cmd: SCSI-ML task pointer corresponding to this iscsi cmd - * @sg: SG list - * @io_tbl: buffer descriptor (BD) table - * @bd_tbl_dma: buffer descriptor (BD) table's dma address - * @req: bnx2i specific command request struct - */ -struct bnx2i_cmd { - struct iscsi_hdr hdr; - struct bnx2i_conn *conn; - struct scsi_cmnd *scsi_cmd; - struct scatterlist *sg; - struct io_bdt io_tbl; - dma_addr_t bd_tbl_dma; - struct bnx2i_cmd_request req; -}; - - -/** - * struct bnx2i_conn - iscsi connection structure - * - * @cls_conn: pointer to iscsi cls conn - * @hba: adapter structure pointer - * @iscsi_conn_cid: iscsi conn id - * @fw_cid: firmware iscsi context id - * @ep: endpoint structure pointer - * @gen_pdu: login/nopout/logout pdu resources - * @violation_notified: bit mask used to track iscsi error/warning messages - * already printed out - * @work_cnt: keeps track of the number of outstanding work - * - * iSCSI connection structure - */ -struct bnx2i_conn { - struct iscsi_cls_conn *cls_conn; - struct bnx2i_hba *hba; - struct completion cmd_cleanup_cmpl; - - u32 iscsi_conn_cid; -#define BNX2I_CID_RESERVED 0x5AFF - u32 fw_cid; - - struct timer_list poll_timer; - /* - * Queue Pair (QP) related structure elements. - */ - struct bnx2i_endpoint *ep; - - /* - * Buffer for login negotiation process - */ - struct generic_pdu_resc gen_pdu; - u64 violation_notified; - - atomic_t work_cnt; -}; - - - -/** - * struct iscsi_cid_queue - Per adapter iscsi cid queue - * - * @cid_que_base: queue base memory - * @cid_que: queue memory pointer - * @cid_q_prod_idx: produce index - * @cid_q_cons_idx: consumer index - * @cid_q_max_idx: max index. used to detect wrap around condition - * @cid_free_cnt: queue size - * @conn_cid_tbl: iscsi cid to conn structure mapping table - * - * Per adapter iSCSI CID Queue - */ -struct iscsi_cid_queue { - void *cid_que_base; - u32 *cid_que; - u32 cid_q_prod_idx; - u32 cid_q_cons_idx; - u32 cid_q_max_idx; - u32 cid_free_cnt; - struct bnx2i_conn **conn_cid_tbl; -}; - -/** - * struct bnx2i_hba - bnx2i adapter structure - * - * @link: list head to link elements - * @cnic: pointer to cnic device - * @pcidev: pointer to pci dev - * @netdev: pointer to netdev structure - * @regview: mapped PCI register space - * @age: age, incremented by every recovery - * @cnic_dev_type: cnic device type, 5706/5708/5709/57710 - * @mail_queue_access: mailbox queue access mode, applicable to 5709 only - * @reg_with_cnic: indicates whether the device is register with CNIC - * @adapter_state: adapter state, UP, GOING_DOWN, LINK_DOWN - * @mtu_supported: Ethernet MTU supported - * @shost: scsi host pointer - * @max_sqes: SQ size - * @max_rqes: RQ size - * @max_cqes: CQ size - * @num_ccell: number of command cells per connection - * @ofld_conns_active: active connection list - * @eh_wait: wait queue for the endpoint to shutdown - * @max_active_conns: max offload connections supported by this device - * @cid_que: iscsi cid queue - * @ep_rdwr_lock: read / write lock to synchronize various ep lists - * @ep_ofld_list: connection list for pending offload completion - * @ep_active_list: connection list for active offload endpoints - * @ep_destroy_list: connection list for pending offload completion - * @mp_bd_tbl: BD table to be used with middle path requests - * @mp_bd_dma: DMA address of 'mp_bd_tbl' memory buffer - * @dummy_buffer: Dummy buffer to be used with zero length scsicmd reqs - * @dummy_buf_dma: DMA address of 'dummy_buffer' memory buffer - * @lock: lock to synchonize access to hba structure - * @hba_shutdown_tmo: Timeout value to shutdown each connection - * @conn_teardown_tmo: Timeout value to tear down each connection - * @conn_ctx_destroy_tmo: Timeout value to destroy context of each connection - * @pci_did: PCI device ID - * @pci_vid: PCI vendor ID - * @pci_sdid: PCI subsystem device ID - * @pci_svid: PCI subsystem vendor ID - * @pci_func: PCI function number in system pci tree - * @pci_devno: PCI device number in system pci tree - * @num_wqe_sent: statistic counter, total wqe's sent - * @num_cqe_rcvd: statistic counter, total cqe's received - * @num_intr_claimed: statistic counter, total interrupts claimed - * @link_changed_count: statistic counter, num of link change notifications - * received - * @ipaddr_changed_count: statistic counter, num times IP address changed while - * at least one connection is offloaded - * @num_sess_opened: statistic counter, total num sessions opened - * @num_conn_opened: statistic counter, total num conns opened on this hba - * @ctx_ccell_tasks: captures number of ccells and tasks supported by - * currently offloaded connection, used to decode - * context memory - * - * Adapter Data Structure - */ -struct bnx2i_hba { - struct list_head link; - struct cnic_dev *cnic; - struct pci_dev *pcidev; - struct net_device *netdev; - void __iomem *regview; - - u32 age; - unsigned long cnic_dev_type; - #define BNX2I_NX2_DEV_5706 0x0 - #define BNX2I_NX2_DEV_5708 0x1 - #define BNX2I_NX2_DEV_5709 0x2 - #define BNX2I_NX2_DEV_57710 0x3 - u32 mail_queue_access; - #define BNX2I_MQ_KERNEL_MODE 0x0 - #define BNX2I_MQ_KERNEL_BYPASS_MODE 0x1 - #define BNX2I_MQ_BIN_MODE 0x2 - unsigned long reg_with_cnic; - #define BNX2I_CNIC_REGISTERED 1 - - unsigned long adapter_state; - #define ADAPTER_STATE_UP 0 - #define ADAPTER_STATE_GOING_DOWN 1 - #define ADAPTER_STATE_LINK_DOWN 2 - #define ADAPTER_STATE_INIT_FAILED 31 - unsigned int mtu_supported; - #define BNX2I_MAX_MTU_SUPPORTED 9000 - - struct Scsi_Host *shost; - - u32 max_sqes; - u32 max_rqes; - u32 max_cqes; - u32 num_ccell; - - int ofld_conns_active; - wait_queue_head_t eh_wait; - - int max_active_conns; - struct iscsi_cid_queue cid_que; - - rwlock_t ep_rdwr_lock; - struct list_head ep_ofld_list; - struct list_head ep_active_list; - struct list_head ep_destroy_list; - - /* - * BD table to be used with MP (Middle Path requests. - */ - char *mp_bd_tbl; - dma_addr_t mp_bd_dma; - char *dummy_buffer; - dma_addr_t dummy_buf_dma; - - spinlock_t lock; /* protects hba structure access */ - struct mutex net_dev_lock;/* sync net device access */ - - int hba_shutdown_tmo; - int conn_teardown_tmo; - int conn_ctx_destroy_tmo; - /* - * PCI related info. - */ - u16 pci_did; - u16 pci_vid; - u16 pci_sdid; - u16 pci_svid; - u16 pci_func; - u16 pci_devno; - - /* - * Following are a bunch of statistics useful during development - * and later stage for score boarding. - */ - u32 num_wqe_sent; - u32 num_cqe_rcvd; - u32 num_intr_claimed; - u32 link_changed_count; - u32 ipaddr_changed_count; - u32 num_sess_opened; - u32 num_conn_opened; - unsigned int ctx_ccell_tasks; -}; - - -/******************************************************************************* - * QP [ SQ / RQ / CQ ] info. - ******************************************************************************/ - -/* - * SQ/RQ/CQ generic structure definition - */ -struct sqe { - u8 sqe_byte[BNX2I_SQ_WQE_SIZE]; -}; - -struct rqe { - u8 rqe_byte[BNX2I_RQ_WQE_SIZE]; -}; - -struct cqe { - u8 cqe_byte[BNX2I_CQE_SIZE]; -}; - - -enum { -#if defined(__LITTLE_ENDIAN) - CNIC_EVENT_COAL_INDEX = 0x0, - CNIC_SEND_DOORBELL = 0x4, - CNIC_EVENT_CQ_ARM = 0x7, - CNIC_RECV_DOORBELL = 0x8 -#elif defined(__BIG_ENDIAN) - CNIC_EVENT_COAL_INDEX = 0x2, - CNIC_SEND_DOORBELL = 0x6, - CNIC_EVENT_CQ_ARM = 0x4, - CNIC_RECV_DOORBELL = 0xa -#endif -}; - - -/* - * CQ DB - */ -struct bnx2x_iscsi_cq_pend_cmpl { - /* CQ producer, updated by Ustorm */ - u16 ustrom_prod; - /* CQ pending completion counter */ - u16 pend_cntr; -}; - - -struct bnx2i_5771x_cq_db { - struct bnx2x_iscsi_cq_pend_cmpl qp_pend_cmpl[BNX2X_MAX_CQS]; - /* CQ pending completion ITT array */ - u16 itt[BNX2X_MAX_CQS]; - /* Cstorm CQ sequence to notify array, updated by driver */; - u16 sqn[BNX2X_MAX_CQS]; - u32 reserved[4] /* 16 byte allignment */; -}; - - -struct bnx2i_5771x_sq_rq_db { - u16 prod_idx; - u8 reserved0[62]; /* Pad structure size to 64 bytes */ -}; - - -struct bnx2i_5771x_dbell_hdr { - u8 header; - /* 1 for rx doorbell, 0 for tx doorbell */ -#define B577XX_DOORBELL_HDR_RX (0x1<<0) -#define B577XX_DOORBELL_HDR_RX_SHIFT 0 - /* 0 for normal doorbell, 1 for advertise wnd doorbell */ -#define B577XX_DOORBELL_HDR_DB_TYPE (0x1<<1) -#define B577XX_DOORBELL_HDR_DB_TYPE_SHIFT 1 - /* rdma tx only: DPM transaction size specifier (64/128/256/512B) */ -#define B577XX_DOORBELL_HDR_DPM_SIZE (0x3<<2) -#define B577XX_DOORBELL_HDR_DPM_SIZE_SHIFT 2 - /* connection type */ -#define B577XX_DOORBELL_HDR_CONN_TYPE (0xF<<4) -#define B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT 4 -}; - -struct bnx2i_5771x_dbell { - struct bnx2i_5771x_dbell_hdr dbell; - u8 pad[3]; - -}; - -/** - * struct qp_info - QP (share queue region) atrributes structure - * - * @ctx_base: ioremapped pci register base to access doorbell register - * pertaining to this offloaded connection - * @sq_virt: virtual address of send queue (SQ) region - * @sq_phys: DMA address of SQ memory region - * @sq_mem_size: SQ size - * @sq_prod_qe: SQ producer entry pointer - * @sq_cons_qe: SQ consumer entry pointer - * @sq_first_qe: virtaul address of first entry in SQ - * @sq_last_qe: virtaul address of last entry in SQ - * @sq_prod_idx: SQ producer index - * @sq_cons_idx: SQ consumer index - * @sqe_left: number sq entry left - * @sq_pgtbl_virt: page table describing buffer consituting SQ region - * @sq_pgtbl_phys: dma address of 'sq_pgtbl_virt' - * @sq_pgtbl_size: SQ page table size - * @cq_virt: virtual address of completion queue (CQ) region - * @cq_phys: DMA address of RQ memory region - * @cq_mem_size: CQ size - * @cq_prod_qe: CQ producer entry pointer - * @cq_cons_qe: CQ consumer entry pointer - * @cq_first_qe: virtaul address of first entry in CQ - * @cq_last_qe: virtaul address of last entry in CQ - * @cq_prod_idx: CQ producer index - * @cq_cons_idx: CQ consumer index - * @cqe_left: number cq entry left - * @cqe_size: size of each CQ entry - * @cqe_exp_seq_sn: next expected CQE sequence number - * @cq_pgtbl_virt: page table describing buffer consituting CQ region - * @cq_pgtbl_phys: dma address of 'cq_pgtbl_virt' - * @cq_pgtbl_size: CQ page table size - * @rq_virt: virtual address of receive queue (RQ) region - * @rq_phys: DMA address of RQ memory region - * @rq_mem_size: RQ size - * @rq_prod_qe: RQ producer entry pointer - * @rq_cons_qe: RQ consumer entry pointer - * @rq_first_qe: virtaul address of first entry in RQ - * @rq_last_qe: virtaul address of last entry in RQ - * @rq_prod_idx: RQ producer index - * @rq_cons_idx: RQ consumer index - * @rqe_left: number rq entry left - * @rq_pgtbl_virt: page table describing buffer consituting RQ region - * @rq_pgtbl_phys: dma address of 'rq_pgtbl_virt' - * @rq_pgtbl_size: RQ page table size - * - * queue pair (QP) is a per connection shared data structure which is used - * to send work requests (SQ), receive completion notifications (CQ) - * and receive asynchoronous / scsi sense info (RQ). 'qp_info' structure - * below holds queue memory, consumer/producer indexes and page table - * information - */ -struct qp_info { - void __iomem *ctx_base; -#define DPM_TRIGER_TYPE 0x40 - -#define BNX2I_570x_QUE_DB_SIZE 0 -#define BNX2I_5771x_QUE_DB_SIZE 16 - struct sqe *sq_virt; - dma_addr_t sq_phys; - u32 sq_mem_size; - - struct sqe *sq_prod_qe; - struct sqe *sq_cons_qe; - struct sqe *sq_first_qe; - struct sqe *sq_last_qe; - u16 sq_prod_idx; - u16 sq_cons_idx; - u32 sqe_left; - - void *sq_pgtbl_virt; - dma_addr_t sq_pgtbl_phys; - u32 sq_pgtbl_size; /* set to PAGE_SIZE for 5708 & 5709 */ - - struct cqe *cq_virt; - dma_addr_t cq_phys; - u32 cq_mem_size; - - struct cqe *cq_prod_qe; - struct cqe *cq_cons_qe; - struct cqe *cq_first_qe; - struct cqe *cq_last_qe; - u16 cq_prod_idx; - u16 cq_cons_idx; - u32 cqe_left; - u32 cqe_size; - u32 cqe_exp_seq_sn; - - void *cq_pgtbl_virt; - dma_addr_t cq_pgtbl_phys; - u32 cq_pgtbl_size; /* set to PAGE_SIZE for 5708 & 5709 */ - - struct rqe *rq_virt; - dma_addr_t rq_phys; - u32 rq_mem_size; - - struct rqe *rq_prod_qe; - struct rqe *rq_cons_qe; - struct rqe *rq_first_qe; - struct rqe *rq_last_qe; - u16 rq_prod_idx; - u16 rq_cons_idx; - u32 rqe_left; - - void *rq_pgtbl_virt; - dma_addr_t rq_pgtbl_phys; - u32 rq_pgtbl_size; /* set to PAGE_SIZE for 5708 & 5709 */ -}; - - - -/* - * CID handles - */ -struct ep_handles { - u32 fw_cid; - u32 drv_iscsi_cid; - u16 pg_cid; - u16 rsvd; -}; - - -enum { - EP_STATE_IDLE = 0x0, - EP_STATE_PG_OFLD_START = 0x1, - EP_STATE_PG_OFLD_COMPL = 0x2, - EP_STATE_OFLD_START = 0x4, - EP_STATE_OFLD_COMPL = 0x8, - EP_STATE_CONNECT_START = 0x10, - EP_STATE_CONNECT_COMPL = 0x20, - EP_STATE_ULP_UPDATE_START = 0x40, - EP_STATE_ULP_UPDATE_COMPL = 0x80, - EP_STATE_DISCONN_START = 0x100, - EP_STATE_DISCONN_COMPL = 0x200, - EP_STATE_CLEANUP_START = 0x400, - EP_STATE_CLEANUP_CMPL = 0x800, - EP_STATE_TCP_FIN_RCVD = 0x1000, - EP_STATE_TCP_RST_RCVD = 0x2000, - EP_STATE_LOGOUT_SENT = 0x4000, - EP_STATE_LOGOUT_RESP_RCVD = 0x8000, - EP_STATE_PG_OFLD_FAILED = 0x1000000, - EP_STATE_ULP_UPDATE_FAILED = 0x2000000, - EP_STATE_CLEANUP_FAILED = 0x4000000, - EP_STATE_OFLD_FAILED = 0x8000000, - EP_STATE_CONNECT_FAILED = 0x10000000, - EP_STATE_DISCONN_TIMEDOUT = 0x20000000, - EP_STATE_OFLD_FAILED_CID_BUSY = 0x80000000, -}; - -/** - * struct bnx2i_endpoint - representation of tcp connection in NX2 world - * - * @link: list head to link elements - * @hba: adapter to which this connection belongs - * @conn: iscsi connection this EP is linked to - * @cls_ep: associated iSCSI endpoint pointer - * @cm_sk: cnic sock struct - * @hba_age: age to detect if 'iscsid' issues ep_disconnect() - * after HBA reset is completed by bnx2i/cnic/bnx2 - * modules - * @state: tracks offload connection state machine - * @timestamp: tracks the start time when the ep begins to connect - * @num_active_cmds: tracks the number of outstanding commands for this ep - * @ec_shift: the amount of shift as part of the event coal calc - * @qp: QP information - * @ids: contains chip allocated *context id* & driver assigned - * *iscsi cid* - * @ofld_timer: offload timer to detect timeout - * @ofld_wait: wait queue - * - * Endpoint Structure - equivalent of tcp socket structure - */ -struct bnx2i_endpoint { - struct list_head link; - struct bnx2i_hba *hba; - struct bnx2i_conn *conn; - struct iscsi_endpoint *cls_ep; - struct cnic_sock *cm_sk; - u32 hba_age; - u32 state; - unsigned long timestamp; - atomic_t num_active_cmds; - u32 ec_shift; - - struct qp_info qp; - struct ep_handles ids; - #define ep_iscsi_cid ids.drv_iscsi_cid - #define ep_cid ids.fw_cid - #define ep_pg_cid ids.pg_cid - struct timer_list ofld_timer; - wait_queue_head_t ofld_wait; -}; - - -struct bnx2i_work { - struct list_head list; - struct iscsi_session *session; - struct bnx2i_conn *bnx2i_conn; - struct cqe cqe; -}; - -struct bnx2i_percpu_s { - struct task_struct *iothread; - struct list_head work_list; - spinlock_t p_work_lock; -}; - - -/* Global variables */ -extern unsigned int error_mask1, error_mask2; -extern u64 iscsi_error_mask; -extern unsigned int en_tcp_dack; -extern unsigned int event_coal_div; -extern unsigned int event_coal_min; - -extern struct scsi_transport_template *bnx2i_scsi_xport_template; -extern struct iscsi_transport bnx2i_iscsi_transport; -extern struct cnic_ulp_ops bnx2i_cnic_cb; - -extern unsigned int sq_size; -extern unsigned int rq_size; - -extern struct device_attribute *bnx2i_dev_attributes[]; - - - -/* - * Function Prototypes - */ -extern void bnx2i_identify_device(struct bnx2i_hba *hba); - -extern void bnx2i_ulp_init(struct cnic_dev *dev); -extern void bnx2i_ulp_exit(struct cnic_dev *dev); -extern void bnx2i_start(void *handle); -extern void bnx2i_stop(void *handle); -extern struct bnx2i_hba *get_adapter_list_head(void); - -struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba, - u16 iscsi_cid); - -int bnx2i_alloc_ep_pool(void); -void bnx2i_release_ep_pool(void); -struct bnx2i_endpoint *bnx2i_ep_ofld_list_next(struct bnx2i_hba *hba); -struct bnx2i_endpoint *bnx2i_ep_destroy_list_next(struct bnx2i_hba *hba); - -struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic); - -struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic); -void bnx2i_free_hba(struct bnx2i_hba *hba); - -void bnx2i_get_rq_buf(struct bnx2i_conn *conn, char *ptr, int len); -void bnx2i_put_rq_buf(struct bnx2i_conn *conn, int count); - -void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd); - -void bnx2i_drop_session(struct iscsi_cls_session *session); - -extern int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba); -extern int bnx2i_send_iscsi_login(struct bnx2i_conn *conn, - struct iscsi_task *mtask); -extern int bnx2i_send_iscsi_tmf(struct bnx2i_conn *conn, - struct iscsi_task *mtask); -extern int bnx2i_send_iscsi_text(struct bnx2i_conn *conn, - struct iscsi_task *mtask); -extern int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *conn, - struct bnx2i_cmd *cmnd); -extern int bnx2i_send_iscsi_nopout(struct bnx2i_conn *conn, - struct iscsi_task *mtask, - char *datap, int data_len, int unsol); -extern int bnx2i_send_iscsi_logout(struct bnx2i_conn *conn, - struct iscsi_task *mtask); -extern void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, - struct bnx2i_cmd *cmd); -extern int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep); -extern void bnx2i_update_iscsi_conn(struct iscsi_conn *conn); -extern int bnx2i_send_conn_destroy(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep); - -extern int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep); -extern void bnx2i_free_qp_resc(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep); -extern void bnx2i_ep_ofld_timer(unsigned long data); -extern struct bnx2i_endpoint *bnx2i_find_ep_in_ofld_list( - struct bnx2i_hba *hba, u32 iscsi_cid); -extern struct bnx2i_endpoint *bnx2i_find_ep_in_destroy_list( - struct bnx2i_hba *hba, u32 iscsi_cid); - -extern int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep); -extern int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action); - -extern int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep); - -/* Debug related function prototypes */ -extern void bnx2i_print_pend_cmd_queue(struct bnx2i_conn *conn); -extern void bnx2i_print_active_cmd_queue(struct bnx2i_conn *conn); -extern void bnx2i_print_xmit_pdu_queue(struct bnx2i_conn *conn); -extern void bnx2i_print_recv_state(struct bnx2i_conn *conn); - -extern int bnx2i_percpu_io_thread(void *arg); -extern int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe); -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_hwi.c b/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_hwi.c deleted file mode 100644 index f9d6f412..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_hwi.c +++ /dev/null @@ -1,2751 +0,0 @@ -/* bnx2i_hwi.c: Broadcom NetXtreme II iSCSI driver. - * - * Copyright (c) 2006 - 2011 Broadcom Corporation - * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. - * Copyright (c) 2007, 2008 Mike Christie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) - * Maintained by: Eddie Wai (eddie.wai@broadcom.com) - */ - -#include -#include -#include -#include "bnx2i.h" - -DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); - -/** - * bnx2i_get_cid_num - get cid from ep - * @ep: endpoint pointer - * - * Only applicable to 57710 family of devices - */ -static u32 bnx2i_get_cid_num(struct bnx2i_endpoint *ep) -{ - u32 cid; - - if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) - cid = ep->ep_cid; - else - cid = GET_CID_NUM(ep->ep_cid); - return cid; -} - - -/** - * bnx2i_adjust_qp_size - Adjust SQ/RQ/CQ size for 57710 device type - * @hba: Adapter for which adjustments is to be made - * - * Only applicable to 57710 family of devices - */ -static void bnx2i_adjust_qp_size(struct bnx2i_hba *hba) -{ - u32 num_elements_per_pg; - - if (test_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type) || - test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type) || - test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) { - if (!is_power_of_2(hba->max_sqes)) - hba->max_sqes = rounddown_pow_of_two(hba->max_sqes); - - if (!is_power_of_2(hba->max_rqes)) - hba->max_rqes = rounddown_pow_of_two(hba->max_rqes); - } - - /* Adjust each queue size if the user selection does not - * yield integral num of page buffers - */ - /* adjust SQ */ - num_elements_per_pg = PAGE_SIZE / BNX2I_SQ_WQE_SIZE; - if (hba->max_sqes < num_elements_per_pg) - hba->max_sqes = num_elements_per_pg; - else if (hba->max_sqes % num_elements_per_pg) - hba->max_sqes = (hba->max_sqes + num_elements_per_pg - 1) & - ~(num_elements_per_pg - 1); - - /* adjust CQ */ - num_elements_per_pg = PAGE_SIZE / BNX2I_CQE_SIZE; - if (hba->max_cqes < num_elements_per_pg) - hba->max_cqes = num_elements_per_pg; - else if (hba->max_cqes % num_elements_per_pg) - hba->max_cqes = (hba->max_cqes + num_elements_per_pg - 1) & - ~(num_elements_per_pg - 1); - - /* adjust RQ */ - num_elements_per_pg = PAGE_SIZE / BNX2I_RQ_WQE_SIZE; - if (hba->max_rqes < num_elements_per_pg) - hba->max_rqes = num_elements_per_pg; - else if (hba->max_rqes % num_elements_per_pg) - hba->max_rqes = (hba->max_rqes + num_elements_per_pg - 1) & - ~(num_elements_per_pg - 1); -} - - -/** - * bnx2i_get_link_state - get network interface link state - * @hba: adapter instance pointer - * - * updates adapter structure flag based on netdev state - */ -static void bnx2i_get_link_state(struct bnx2i_hba *hba) -{ - if (test_bit(__LINK_STATE_NOCARRIER, &hba->netdev->state)) - set_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); - else - clear_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state); -} - - -/** - * bnx2i_iscsi_license_error - displays iscsi license related error message - * @hba: adapter instance pointer - * @error_code: error classification - * - * Puts out an error log when driver is unable to offload iscsi connection - * due to license restrictions - */ -static void bnx2i_iscsi_license_error(struct bnx2i_hba *hba, u32 error_code) -{ - if (error_code == ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED) - /* iSCSI offload not supported on this device */ - printk(KERN_ERR "bnx2i: iSCSI not supported, dev=%s\n", - hba->netdev->name); - if (error_code == ISCSI_KCQE_COMPLETION_STATUS_LOM_ISCSI_NOT_ENABLED) - /* iSCSI offload not supported on this LOM device */ - printk(KERN_ERR "bnx2i: LOM is not enable to " - "offload iSCSI connections, dev=%s\n", - hba->netdev->name); - set_bit(ADAPTER_STATE_INIT_FAILED, &hba->adapter_state); -} - - -/** - * bnx2i_arm_cq_event_coalescing - arms CQ to enable EQ notification - * @ep: endpoint (transport indentifier) structure - * @action: action, ARM or DISARM. For now only ARM_CQE is used - * - * Arm'ing CQ will enable chip to generate global EQ events inorder to interrupt - * the driver. EQ event is generated CQ index is hit or at least 1 CQ is - * outstanding and on chip timer expires - */ -int bnx2i_arm_cq_event_coalescing(struct bnx2i_endpoint *ep, u8 action) -{ - struct bnx2i_5771x_cq_db *cq_db; - u16 cq_index; - u16 next_index = 0; - u32 num_active_cmds; - - /* Coalesce CQ entries only on 10G devices */ - if (!test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) - return 0; - - /* Do not update CQ DB multiple times before firmware writes - * '0xFFFF' to CQDB->SQN field. Deviation may cause spurious - * interrupts and other unwanted results - */ - cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt; - - if (action != CNIC_ARM_CQE_FP) - if (cq_db->sqn[0] && cq_db->sqn[0] != 0xFFFF) - return 0; - - if (action == CNIC_ARM_CQE || action == CNIC_ARM_CQE_FP) { - num_active_cmds = atomic_read(&ep->num_active_cmds); - if (num_active_cmds <= event_coal_min) - next_index = 1; - else { - next_index = num_active_cmds >> ep->ec_shift; - if (next_index > num_active_cmds - event_coal_min) - next_index = num_active_cmds - event_coal_min; - } - if (!next_index) - next_index = 1; - cq_index = ep->qp.cqe_exp_seq_sn + next_index - 1; - if (cq_index > ep->qp.cqe_size * 2) - cq_index -= ep->qp.cqe_size * 2; - if (!cq_index) - cq_index = 1; - - cq_db->sqn[0] = cq_index; - } - return next_index; -} - - -/** - * bnx2i_get_rq_buf - copy RQ buffer contents to driver buffer - * @conn: iscsi connection on which RQ event occurred - * @ptr: driver buffer to which RQ buffer contents is to - * be copied - * @len: length of valid data inside RQ buf - * - * Copies RQ buffer contents from shared (DMA'able) memory region to - * driver buffer. RQ is used to DMA unsolicitated iscsi pdu's and - * scsi sense info - */ -void bnx2i_get_rq_buf(struct bnx2i_conn *bnx2i_conn, char *ptr, int len) -{ - if (!bnx2i_conn->ep->qp.rqe_left) - return; - - bnx2i_conn->ep->qp.rqe_left--; - memcpy(ptr, (u8 *) bnx2i_conn->ep->qp.rq_cons_qe, len); - if (bnx2i_conn->ep->qp.rq_cons_qe == bnx2i_conn->ep->qp.rq_last_qe) { - bnx2i_conn->ep->qp.rq_cons_qe = bnx2i_conn->ep->qp.rq_first_qe; - bnx2i_conn->ep->qp.rq_cons_idx = 0; - } else { - bnx2i_conn->ep->qp.rq_cons_qe++; - bnx2i_conn->ep->qp.rq_cons_idx++; - } -} - - -static void bnx2i_ring_577xx_doorbell(struct bnx2i_conn *conn) -{ - struct bnx2i_5771x_dbell dbell; - u32 msg; - - memset(&dbell, 0, sizeof(dbell)); - dbell.dbell.header = (B577XX_ISCSI_CONNECTION_TYPE << - B577XX_DOORBELL_HDR_CONN_TYPE_SHIFT); - msg = *((u32 *)&dbell); - /* TODO : get doorbell register mapping */ - writel(cpu_to_le32(msg), conn->ep->qp.ctx_base); -} - - -/** - * bnx2i_put_rq_buf - Replenish RQ buffer, if required ring on chip doorbell - * @conn: iscsi connection on which event to post - * @count: number of RQ buffer being posted to chip - * - * No need to ring hardware doorbell for 57710 family of devices - */ -void bnx2i_put_rq_buf(struct bnx2i_conn *bnx2i_conn, int count) -{ - struct bnx2i_5771x_sq_rq_db *rq_db; - u16 hi_bit = (bnx2i_conn->ep->qp.rq_prod_idx & 0x8000); - struct bnx2i_endpoint *ep = bnx2i_conn->ep; - - ep->qp.rqe_left += count; - ep->qp.rq_prod_idx &= 0x7FFF; - ep->qp.rq_prod_idx += count; - - if (ep->qp.rq_prod_idx > bnx2i_conn->hba->max_rqes) { - ep->qp.rq_prod_idx %= bnx2i_conn->hba->max_rqes; - if (!hi_bit) - ep->qp.rq_prod_idx |= 0x8000; - } else - ep->qp.rq_prod_idx |= hi_bit; - - if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { - rq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.rq_pgtbl_virt; - rq_db->prod_idx = ep->qp.rq_prod_idx; - /* no need to ring hardware doorbell for 57710 */ - } else { - writew(ep->qp.rq_prod_idx, - ep->qp.ctx_base + CNIC_RECV_DOORBELL); - } - mmiowb(); -} - - -/** - * bnx2i_ring_sq_dbell - Ring SQ doorbell to wake-up the processing engine - * @conn: iscsi connection to which new SQ entries belong - * @count: number of SQ WQEs to post - * - * SQ DB is updated in host memory and TX Doorbell is rung for 57710 family - * of devices. For 5706/5708/5709 new SQ WQE count is written into the - * doorbell register - */ -static void bnx2i_ring_sq_dbell(struct bnx2i_conn *bnx2i_conn, int count) -{ - struct bnx2i_5771x_sq_rq_db *sq_db; - struct bnx2i_endpoint *ep = bnx2i_conn->ep; - - atomic_inc(&ep->num_active_cmds); - wmb(); /* flush SQ WQE memory before the doorbell is rung */ - if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { - sq_db = (struct bnx2i_5771x_sq_rq_db *) ep->qp.sq_pgtbl_virt; - sq_db->prod_idx = ep->qp.sq_prod_idx; - bnx2i_ring_577xx_doorbell(bnx2i_conn); - } else - writew(count, ep->qp.ctx_base + CNIC_SEND_DOORBELL); - - mmiowb(); /* flush posted PCI writes */ -} - - -/** - * bnx2i_ring_dbell_update_sq_params - update SQ driver parameters - * @conn: iscsi connection to which new SQ entries belong - * @count: number of SQ WQEs to post - * - * this routine will update SQ driver parameters and ring the doorbell - */ -static void bnx2i_ring_dbell_update_sq_params(struct bnx2i_conn *bnx2i_conn, - int count) -{ - int tmp_cnt; - - if (count == 1) { - if (bnx2i_conn->ep->qp.sq_prod_qe == - bnx2i_conn->ep->qp.sq_last_qe) - bnx2i_conn->ep->qp.sq_prod_qe = - bnx2i_conn->ep->qp.sq_first_qe; - else - bnx2i_conn->ep->qp.sq_prod_qe++; - } else { - if ((bnx2i_conn->ep->qp.sq_prod_qe + count) <= - bnx2i_conn->ep->qp.sq_last_qe) - bnx2i_conn->ep->qp.sq_prod_qe += count; - else { - tmp_cnt = bnx2i_conn->ep->qp.sq_last_qe - - bnx2i_conn->ep->qp.sq_prod_qe; - bnx2i_conn->ep->qp.sq_prod_qe = - &bnx2i_conn->ep->qp.sq_first_qe[count - - (tmp_cnt + 1)]; - } - } - bnx2i_conn->ep->qp.sq_prod_idx += count; - /* Ring the doorbell */ - bnx2i_ring_sq_dbell(bnx2i_conn, bnx2i_conn->ep->qp.sq_prod_idx); -} - - -/** - * bnx2i_send_iscsi_login - post iSCSI login request MP WQE to hardware - * @conn: iscsi connection - * @cmd: driver command structure which is requesting - * a WQE to sent to chip for further processing - * - * prepare and post an iSCSI Login request WQE to CNIC firmware - */ -int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn, - struct iscsi_task *task) -{ - struct bnx2i_cmd *bnx2i_cmd; - struct bnx2i_login_request *login_wqe; - struct iscsi_login_req *login_hdr; - u32 dword; - - bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data; - login_hdr = (struct iscsi_login_req *)task->hdr; - login_wqe = (struct bnx2i_login_request *) - bnx2i_conn->ep->qp.sq_prod_qe; - - login_wqe->op_code = login_hdr->opcode; - login_wqe->op_attr = login_hdr->flags; - login_wqe->version_max = login_hdr->max_version; - login_wqe->version_min = login_hdr->min_version; - login_wqe->data_length = ntoh24(login_hdr->dlength); - login_wqe->isid_lo = *((u32 *) login_hdr->isid); - login_wqe->isid_hi = *((u16 *) login_hdr->isid + 2); - login_wqe->tsih = login_hdr->tsih; - login_wqe->itt = task->itt | - (ISCSI_TASK_TYPE_MPATH << ISCSI_LOGIN_REQUEST_TYPE_SHIFT); - login_wqe->cid = login_hdr->cid; - - login_wqe->cmd_sn = be32_to_cpu(login_hdr->cmdsn); - login_wqe->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn); - login_wqe->flags = ISCSI_LOGIN_REQUEST_UPDATE_EXP_STAT_SN; - - login_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma; - login_wqe->resp_bd_list_addr_hi = - (u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32); - - dword = ((1 << ISCSI_LOGIN_REQUEST_NUM_RESP_BDS_SHIFT) | - (bnx2i_conn->gen_pdu.resp_buf_size << - ISCSI_LOGIN_REQUEST_RESP_BUFFER_LENGTH_SHIFT)); - login_wqe->resp_buffer = dword; - login_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma; - login_wqe->bd_list_addr_hi = - (u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32); - login_wqe->num_bds = 1; - login_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ - - bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); - return 0; -} - -/** - * bnx2i_send_iscsi_tmf - post iSCSI task management request MP WQE to hardware - * @conn: iscsi connection - * @mtask: driver command structure which is requesting - * a WQE to sent to chip for further processing - * - * prepare and post an iSCSI Login request WQE to CNIC firmware - */ -int bnx2i_send_iscsi_tmf(struct bnx2i_conn *bnx2i_conn, - struct iscsi_task *mtask) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct iscsi_tm *tmfabort_hdr; - struct scsi_cmnd *ref_sc; - struct iscsi_task *ctask; - struct bnx2i_cmd *bnx2i_cmd; - struct bnx2i_tmf_request *tmfabort_wqe; - u32 dword; - u32 scsi_lun[2]; - - bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data; - tmfabort_hdr = (struct iscsi_tm *)mtask->hdr; - tmfabort_wqe = (struct bnx2i_tmf_request *) - bnx2i_conn->ep->qp.sq_prod_qe; - - tmfabort_wqe->op_code = tmfabort_hdr->opcode; - tmfabort_wqe->op_attr = tmfabort_hdr->flags; - - tmfabort_wqe->itt = (mtask->itt | (ISCSI_TASK_TYPE_MPATH << 14)); - tmfabort_wqe->reserved2 = 0; - tmfabort_wqe->cmd_sn = be32_to_cpu(tmfabort_hdr->cmdsn); - - switch (tmfabort_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) { - case ISCSI_TM_FUNC_ABORT_TASK: - case ISCSI_TM_FUNC_TASK_REASSIGN: - ctask = iscsi_itt_to_task(conn, tmfabort_hdr->rtt); - if (!ctask || !ctask->sc) - /* - * the iscsi layer must have completed the cmd while - * was starting up. - * - * Note: In the case of a SCSI cmd timeout, the task's - * sc is still active; hence ctask->sc != 0 - * In this case, the task must be aborted - */ - return 0; - - ref_sc = ctask->sc; - if (ref_sc->sc_data_direction == DMA_TO_DEVICE) - dword = (ISCSI_TASK_TYPE_WRITE << - ISCSI_CMD_REQUEST_TYPE_SHIFT); - else - dword = (ISCSI_TASK_TYPE_READ << - ISCSI_CMD_REQUEST_TYPE_SHIFT); - tmfabort_wqe->ref_itt = (dword | - (tmfabort_hdr->rtt & ISCSI_ITT_MASK)); - break; - default: - tmfabort_wqe->ref_itt = RESERVED_ITT; - } - memcpy(scsi_lun, &tmfabort_hdr->lun, sizeof(struct scsi_lun)); - tmfabort_wqe->lun[0] = be32_to_cpu(scsi_lun[0]); - tmfabort_wqe->lun[1] = be32_to_cpu(scsi_lun[1]); - - tmfabort_wqe->ref_cmd_sn = be32_to_cpu(tmfabort_hdr->refcmdsn); - - tmfabort_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma; - tmfabort_wqe->bd_list_addr_hi = (u32) - ((u64) bnx2i_conn->hba->mp_bd_dma >> 32); - tmfabort_wqe->num_bds = 1; - tmfabort_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ - - bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); - return 0; -} - -/** - * bnx2i_send_iscsi_text - post iSCSI text WQE to hardware - * @conn: iscsi connection - * @mtask: driver command structure which is requesting - * a WQE to sent to chip for further processing - * - * prepare and post an iSCSI Text request WQE to CNIC firmware - */ -int bnx2i_send_iscsi_text(struct bnx2i_conn *bnx2i_conn, - struct iscsi_task *mtask) -{ - struct bnx2i_cmd *bnx2i_cmd; - struct bnx2i_text_request *text_wqe; - struct iscsi_text *text_hdr; - u32 dword; - - bnx2i_cmd = (struct bnx2i_cmd *)mtask->dd_data; - text_hdr = (struct iscsi_text *)mtask->hdr; - text_wqe = (struct bnx2i_text_request *) bnx2i_conn->ep->qp.sq_prod_qe; - - memset(text_wqe, 0, sizeof(struct bnx2i_text_request)); - - text_wqe->op_code = text_hdr->opcode; - text_wqe->op_attr = text_hdr->flags; - text_wqe->data_length = ntoh24(text_hdr->dlength); - text_wqe->itt = mtask->itt | - (ISCSI_TASK_TYPE_MPATH << ISCSI_TEXT_REQUEST_TYPE_SHIFT); - text_wqe->ttt = be32_to_cpu(text_hdr->ttt); - - text_wqe->cmd_sn = be32_to_cpu(text_hdr->cmdsn); - - text_wqe->resp_bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_bd_dma; - text_wqe->resp_bd_list_addr_hi = - (u32) ((u64) bnx2i_conn->gen_pdu.resp_bd_dma >> 32); - - dword = ((1 << ISCSI_TEXT_REQUEST_NUM_RESP_BDS_SHIFT) | - (bnx2i_conn->gen_pdu.resp_buf_size << - ISCSI_TEXT_REQUEST_RESP_BUFFER_LENGTH_SHIFT)); - text_wqe->resp_buffer = dword; - text_wqe->bd_list_addr_lo = (u32) bnx2i_conn->gen_pdu.req_bd_dma; - text_wqe->bd_list_addr_hi = - (u32) ((u64) bnx2i_conn->gen_pdu.req_bd_dma >> 32); - text_wqe->num_bds = 1; - text_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ - - bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); - return 0; -} - - -/** - * bnx2i_send_iscsi_scsicmd - post iSCSI scsicmd request WQE to hardware - * @conn: iscsi connection - * @cmd: driver command structure which is requesting - * a WQE to sent to chip for further processing - * - * prepare and post an iSCSI SCSI-CMD request WQE to CNIC firmware - */ -int bnx2i_send_iscsi_scsicmd(struct bnx2i_conn *bnx2i_conn, - struct bnx2i_cmd *cmd) -{ - struct bnx2i_cmd_request *scsi_cmd_wqe; - - scsi_cmd_wqe = (struct bnx2i_cmd_request *) - bnx2i_conn->ep->qp.sq_prod_qe; - memcpy(scsi_cmd_wqe, &cmd->req, sizeof(struct bnx2i_cmd_request)); - scsi_cmd_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ - - bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); - return 0; -} - -/** - * bnx2i_send_iscsi_nopout - post iSCSI NOPOUT request WQE to hardware - * @conn: iscsi connection - * @cmd: driver command structure which is requesting - * a WQE to sent to chip for further processing - * @datap: payload buffer pointer - * @data_len: payload data length - * @unsol: indicated whether nopout pdu is unsolicited pdu or - * in response to target's NOPIN w/ TTT != FFFFFFFF - * - * prepare and post a nopout request WQE to CNIC firmware - */ -int bnx2i_send_iscsi_nopout(struct bnx2i_conn *bnx2i_conn, - struct iscsi_task *task, - char *datap, int data_len, int unsol) -{ - struct bnx2i_endpoint *ep = bnx2i_conn->ep; - struct bnx2i_cmd *bnx2i_cmd; - struct bnx2i_nop_out_request *nopout_wqe; - struct iscsi_nopout *nopout_hdr; - - bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data; - nopout_hdr = (struct iscsi_nopout *)task->hdr; - nopout_wqe = (struct bnx2i_nop_out_request *)ep->qp.sq_prod_qe; - - memset(nopout_wqe, 0x00, sizeof(struct bnx2i_nop_out_request)); - - nopout_wqe->op_code = nopout_hdr->opcode; - nopout_wqe->op_attr = ISCSI_FLAG_CMD_FINAL; - memcpy(nopout_wqe->lun, &nopout_hdr->lun, 8); - - if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { - u32 tmp = nopout_wqe->lun[0]; - /* 57710 requires LUN field to be swapped */ - nopout_wqe->lun[0] = nopout_wqe->lun[1]; - nopout_wqe->lun[1] = tmp; - } - - nopout_wqe->itt = ((u16)task->itt | - (ISCSI_TASK_TYPE_MPATH << - ISCSI_TMF_REQUEST_TYPE_SHIFT)); - nopout_wqe->ttt = be32_to_cpu(nopout_hdr->ttt); - nopout_wqe->flags = 0; - if (!unsol) - nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION; - else if (nopout_hdr->itt == RESERVED_ITT) - nopout_wqe->flags = ISCSI_NOP_OUT_REQUEST_LOCAL_COMPLETION; - - nopout_wqe->cmd_sn = be32_to_cpu(nopout_hdr->cmdsn); - nopout_wqe->data_length = data_len; - if (data_len) { - /* handle payload data, not required in first release */ - printk(KERN_ALERT "NOPOUT: WARNING!! payload len != 0\n"); - } else { - nopout_wqe->bd_list_addr_lo = (u32) - bnx2i_conn->hba->mp_bd_dma; - nopout_wqe->bd_list_addr_hi = - (u32) ((u64) bnx2i_conn->hba->mp_bd_dma >> 32); - nopout_wqe->num_bds = 1; - } - nopout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ - - bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); - return 0; -} - - -/** - * bnx2i_send_iscsi_logout - post iSCSI logout request WQE to hardware - * @conn: iscsi connection - * @cmd: driver command structure which is requesting - * a WQE to sent to chip for further processing - * - * prepare and post logout request WQE to CNIC firmware - */ -int bnx2i_send_iscsi_logout(struct bnx2i_conn *bnx2i_conn, - struct iscsi_task *task) -{ - struct bnx2i_cmd *bnx2i_cmd; - struct bnx2i_logout_request *logout_wqe; - struct iscsi_logout *logout_hdr; - - bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data; - logout_hdr = (struct iscsi_logout *)task->hdr; - - logout_wqe = (struct bnx2i_logout_request *) - bnx2i_conn->ep->qp.sq_prod_qe; - memset(logout_wqe, 0x00, sizeof(struct bnx2i_logout_request)); - - logout_wqe->op_code = logout_hdr->opcode; - logout_wqe->cmd_sn = be32_to_cpu(logout_hdr->cmdsn); - logout_wqe->op_attr = - logout_hdr->flags | ISCSI_LOGOUT_REQUEST_ALWAYS_ONE; - logout_wqe->itt = ((u16)task->itt | - (ISCSI_TASK_TYPE_MPATH << - ISCSI_LOGOUT_REQUEST_TYPE_SHIFT)); - logout_wqe->data_length = 0; - logout_wqe->cid = 0; - - logout_wqe->bd_list_addr_lo = (u32) bnx2i_conn->hba->mp_bd_dma; - logout_wqe->bd_list_addr_hi = (u32) - ((u64) bnx2i_conn->hba->mp_bd_dma >> 32); - logout_wqe->num_bds = 1; - logout_wqe->cq_index = 0; /* CQ# used for completion, 5771x only */ - - bnx2i_conn->ep->state = EP_STATE_LOGOUT_SENT; - - bnx2i_ring_dbell_update_sq_params(bnx2i_conn, 1); - return 0; -} - - -/** - * bnx2i_update_iscsi_conn - post iSCSI logout request WQE to hardware - * @conn: iscsi connection which requires iscsi parameter update - * - * sends down iSCSI Conn Update request to move iSCSI conn to FFP - */ -void bnx2i_update_iscsi_conn(struct iscsi_conn *conn) -{ - struct bnx2i_conn *bnx2i_conn = conn->dd_data; - struct bnx2i_hba *hba = bnx2i_conn->hba; - struct kwqe *kwqe_arr[2]; - struct iscsi_kwqe_conn_update *update_wqe; - struct iscsi_kwqe_conn_update conn_update_kwqe; - - update_wqe = &conn_update_kwqe; - - update_wqe->hdr.op_code = ISCSI_KWQE_OPCODE_UPDATE_CONN; - update_wqe->hdr.flags = - (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); - - /* 5771x requires conn context id to be passed as is */ - if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_conn->ep->hba->cnic_dev_type)) - update_wqe->context_id = bnx2i_conn->ep->ep_cid; - else - update_wqe->context_id = (bnx2i_conn->ep->ep_cid >> 7); - update_wqe->conn_flags = 0; - if (conn->hdrdgst_en) - update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_HEADER_DIGEST; - if (conn->datadgst_en) - update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_DATA_DIGEST; - if (conn->session->initial_r2t_en) - update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_INITIAL_R2T; - if (conn->session->imm_data_en) - update_wqe->conn_flags |= ISCSI_KWQE_CONN_UPDATE_IMMEDIATE_DATA; - - update_wqe->max_send_pdu_length = conn->max_xmit_dlength; - update_wqe->max_recv_pdu_length = conn->max_recv_dlength; - update_wqe->first_burst_length = conn->session->first_burst; - update_wqe->max_burst_length = conn->session->max_burst; - update_wqe->exp_stat_sn = conn->exp_statsn; - update_wqe->max_outstanding_r2ts = conn->session->max_r2t; - update_wqe->session_error_recovery_level = conn->session->erl; - iscsi_conn_printk(KERN_ALERT, conn, - "bnx2i: conn update - MBL 0x%x FBL 0x%x" - "MRDSL_I 0x%x MRDSL_T 0x%x \n", - update_wqe->max_burst_length, - update_wqe->first_burst_length, - update_wqe->max_recv_pdu_length, - update_wqe->max_send_pdu_length); - - kwqe_arr[0] = (struct kwqe *) update_wqe; - if (hba->cnic && hba->cnic->submit_kwqes) - hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1); -} - - -/** - * bnx2i_ep_ofld_timer - post iSCSI logout request WQE to hardware - * @data: endpoint (transport handle) structure pointer - * - * routine to handle connection offload/destroy request timeout - */ -void bnx2i_ep_ofld_timer(unsigned long data) -{ - struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) data; - - if (ep->state == EP_STATE_OFLD_START) { - printk(KERN_ALERT "ofld_timer: CONN_OFLD timeout\n"); - ep->state = EP_STATE_OFLD_FAILED; - } else if (ep->state == EP_STATE_DISCONN_START) { - printk(KERN_ALERT "ofld_timer: CONN_DISCON timeout\n"); - ep->state = EP_STATE_DISCONN_TIMEDOUT; - } else if (ep->state == EP_STATE_CLEANUP_START) { - printk(KERN_ALERT "ofld_timer: CONN_CLEANUP timeout\n"); - ep->state = EP_STATE_CLEANUP_FAILED; - } - - wake_up_interruptible(&ep->ofld_wait); -} - - -static int bnx2i_power_of2(u32 val) -{ - u32 power = 0; - if (val & (val - 1)) - return power; - val--; - while (val) { - val = val >> 1; - power++; - } - return power; -} - - -/** - * bnx2i_send_cmd_cleanup_req - send iscsi cmd context clean-up request - * @hba: adapter structure pointer - * @cmd: driver command structure which is requesting - * a WQE to sent to chip for further processing - * - * prepares and posts CONN_OFLD_REQ1/2 KWQE - */ -void bnx2i_send_cmd_cleanup_req(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd) -{ - struct bnx2i_cleanup_request *cmd_cleanup; - - cmd_cleanup = - (struct bnx2i_cleanup_request *)cmd->conn->ep->qp.sq_prod_qe; - memset(cmd_cleanup, 0x00, sizeof(struct bnx2i_cleanup_request)); - - cmd_cleanup->op_code = ISCSI_OPCODE_CLEANUP_REQUEST; - cmd_cleanup->itt = cmd->req.itt; - cmd_cleanup->cq_index = 0; /* CQ# used for completion, 5771x only */ - - bnx2i_ring_dbell_update_sq_params(cmd->conn, 1); -} - - -/** - * bnx2i_send_conn_destroy - initiates iscsi connection teardown process - * @hba: adapter structure pointer - * @ep: endpoint (transport indentifier) structure - * - * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE to initiate - * iscsi connection context clean-up process - */ -int bnx2i_send_conn_destroy(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) -{ - struct kwqe *kwqe_arr[2]; - struct iscsi_kwqe_conn_destroy conn_cleanup; - int rc = -EINVAL; - - memset(&conn_cleanup, 0x00, sizeof(struct iscsi_kwqe_conn_destroy)); - - conn_cleanup.hdr.op_code = ISCSI_KWQE_OPCODE_DESTROY_CONN; - conn_cleanup.hdr.flags = - (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); - /* 5771x requires conn context id to be passed as is */ - if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) - conn_cleanup.context_id = ep->ep_cid; - else - conn_cleanup.context_id = (ep->ep_cid >> 7); - - conn_cleanup.reserved0 = (u16)ep->ep_iscsi_cid; - - kwqe_arr[0] = (struct kwqe *) &conn_cleanup; - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 1); - - return rc; -} - - -/** - * bnx2i_570x_send_conn_ofld_req - initiates iscsi conn context setup process - * @hba: adapter structure pointer - * @ep: endpoint (transport indentifier) structure - * - * 5706/5708/5709 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE - */ -static int bnx2i_570x_send_conn_ofld_req(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - struct kwqe *kwqe_arr[2]; - struct iscsi_kwqe_conn_offload1 ofld_req1; - struct iscsi_kwqe_conn_offload2 ofld_req2; - dma_addr_t dma_addr; - int num_kwqes = 2; - u32 *ptbl; - int rc = -EINVAL; - - ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1; - ofld_req1.hdr.flags = - (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); - - ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid; - - dma_addr = ep->qp.sq_pgtbl_phys; - ofld_req1.sq_page_table_addr_lo = (u32) dma_addr; - ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); - - dma_addr = ep->qp.cq_pgtbl_phys; - ofld_req1.cq_page_table_addr_lo = (u32) dma_addr; - ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); - - ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2; - ofld_req2.hdr.flags = - (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); - - dma_addr = ep->qp.rq_pgtbl_phys; - ofld_req2.rq_page_table_addr_lo = (u32) dma_addr; - ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); - - ptbl = (u32 *) ep->qp.sq_pgtbl_virt; - - ofld_req2.sq_first_pte.hi = *ptbl++; - ofld_req2.sq_first_pte.lo = *ptbl; - - ptbl = (u32 *) ep->qp.cq_pgtbl_virt; - ofld_req2.cq_first_pte.hi = *ptbl++; - ofld_req2.cq_first_pte.lo = *ptbl; - - kwqe_arr[0] = (struct kwqe *) &ofld_req1; - kwqe_arr[1] = (struct kwqe *) &ofld_req2; - ofld_req2.num_additional_wqes = 0; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - - return rc; -} - - -/** - * bnx2i_5771x_send_conn_ofld_req - initiates iscsi connection context creation - * @hba: adapter structure pointer - * @ep: endpoint (transport indentifier) structure - * - * 57710 specific - prepares and posts CONN_OFLD_REQ1/2 KWQE - */ -static int bnx2i_5771x_send_conn_ofld_req(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - struct kwqe *kwqe_arr[5]; - struct iscsi_kwqe_conn_offload1 ofld_req1; - struct iscsi_kwqe_conn_offload2 ofld_req2; - struct iscsi_kwqe_conn_offload3 ofld_req3[1]; - dma_addr_t dma_addr; - int num_kwqes = 2; - u32 *ptbl; - int rc = -EINVAL; - - ofld_req1.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN1; - ofld_req1.hdr.flags = - (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); - - ofld_req1.iscsi_conn_id = (u16) ep->ep_iscsi_cid; - - dma_addr = ep->qp.sq_pgtbl_phys + ISCSI_SQ_DB_SIZE; - ofld_req1.sq_page_table_addr_lo = (u32) dma_addr; - ofld_req1.sq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); - - dma_addr = ep->qp.cq_pgtbl_phys + ISCSI_CQ_DB_SIZE; - ofld_req1.cq_page_table_addr_lo = (u32) dma_addr; - ofld_req1.cq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); - - ofld_req2.hdr.op_code = ISCSI_KWQE_OPCODE_OFFLOAD_CONN2; - ofld_req2.hdr.flags = - (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); - - dma_addr = ep->qp.rq_pgtbl_phys + ISCSI_RQ_DB_SIZE; - ofld_req2.rq_page_table_addr_lo = (u32) dma_addr; - ofld_req2.rq_page_table_addr_hi = (u32) ((u64) dma_addr >> 32); - - ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE); - ofld_req2.sq_first_pte.hi = *ptbl++; - ofld_req2.sq_first_pte.lo = *ptbl; - - ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE); - ofld_req2.cq_first_pte.hi = *ptbl++; - ofld_req2.cq_first_pte.lo = *ptbl; - - kwqe_arr[0] = (struct kwqe *) &ofld_req1; - kwqe_arr[1] = (struct kwqe *) &ofld_req2; - - ofld_req2.num_additional_wqes = 1; - memset(ofld_req3, 0x00, sizeof(ofld_req3[0])); - ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE); - ofld_req3[0].qp_first_pte[0].hi = *ptbl++; - ofld_req3[0].qp_first_pte[0].lo = *ptbl; - - kwqe_arr[2] = (struct kwqe *) ofld_req3; - /* need if we decide to go with multiple KCQE's per conn */ - num_kwqes += 1; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, num_kwqes); - - return rc; -} - -/** - * bnx2i_send_conn_ofld_req - initiates iscsi connection context setup process - * - * @hba: adapter structure pointer - * @ep: endpoint (transport indentifier) structure - * - * this routine prepares and posts CONN_OFLD_REQ1/2 KWQE - */ -int bnx2i_send_conn_ofld_req(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) -{ - int rc; - - if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) - rc = bnx2i_5771x_send_conn_ofld_req(hba, ep); - else - rc = bnx2i_570x_send_conn_ofld_req(hba, ep); - - return rc; -} - - -/** - * setup_qp_page_tables - iscsi QP page table setup function - * @ep: endpoint (transport indentifier) structure - * - * Sets up page tables for SQ/RQ/CQ, 1G/sec (5706/5708/5709) devices requires - * 64-bit address in big endian format. Whereas 10G/sec (57710) requires - * PT in little endian format - */ -static void setup_qp_page_tables(struct bnx2i_endpoint *ep) -{ - int num_pages; - u32 *ptbl; - dma_addr_t page; - int cnic_dev_10g; - - if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) - cnic_dev_10g = 1; - else - cnic_dev_10g = 0; - - /* SQ page table */ - memset(ep->qp.sq_pgtbl_virt, 0, ep->qp.sq_pgtbl_size); - num_pages = ep->qp.sq_mem_size / PAGE_SIZE; - page = ep->qp.sq_phys; - - if (cnic_dev_10g) - ptbl = (u32 *)((u8 *)ep->qp.sq_pgtbl_virt + ISCSI_SQ_DB_SIZE); - else - ptbl = (u32 *) ep->qp.sq_pgtbl_virt; - while (num_pages--) { - if (cnic_dev_10g) { - /* PTE is written in little endian format for 57710 */ - *ptbl = (u32) page; - ptbl++; - *ptbl = (u32) ((u64) page >> 32); - ptbl++; - page += PAGE_SIZE; - } else { - /* PTE is written in big endian format for - * 5706/5708/5709 devices */ - *ptbl = (u32) ((u64) page >> 32); - ptbl++; - *ptbl = (u32) page; - ptbl++; - page += PAGE_SIZE; - } - } - - /* RQ page table */ - memset(ep->qp.rq_pgtbl_virt, 0, ep->qp.rq_pgtbl_size); - num_pages = ep->qp.rq_mem_size / PAGE_SIZE; - page = ep->qp.rq_phys; - - if (cnic_dev_10g) - ptbl = (u32 *)((u8 *)ep->qp.rq_pgtbl_virt + ISCSI_RQ_DB_SIZE); - else - ptbl = (u32 *) ep->qp.rq_pgtbl_virt; - while (num_pages--) { - if (cnic_dev_10g) { - /* PTE is written in little endian format for 57710 */ - *ptbl = (u32) page; - ptbl++; - *ptbl = (u32) ((u64) page >> 32); - ptbl++; - page += PAGE_SIZE; - } else { - /* PTE is written in big endian format for - * 5706/5708/5709 devices */ - *ptbl = (u32) ((u64) page >> 32); - ptbl++; - *ptbl = (u32) page; - ptbl++; - page += PAGE_SIZE; - } - } - - /* CQ page table */ - memset(ep->qp.cq_pgtbl_virt, 0, ep->qp.cq_pgtbl_size); - num_pages = ep->qp.cq_mem_size / PAGE_SIZE; - page = ep->qp.cq_phys; - - if (cnic_dev_10g) - ptbl = (u32 *)((u8 *)ep->qp.cq_pgtbl_virt + ISCSI_CQ_DB_SIZE); - else - ptbl = (u32 *) ep->qp.cq_pgtbl_virt; - while (num_pages--) { - if (cnic_dev_10g) { - /* PTE is written in little endian format for 57710 */ - *ptbl = (u32) page; - ptbl++; - *ptbl = (u32) ((u64) page >> 32); - ptbl++; - page += PAGE_SIZE; - } else { - /* PTE is written in big endian format for - * 5706/5708/5709 devices */ - *ptbl = (u32) ((u64) page >> 32); - ptbl++; - *ptbl = (u32) page; - ptbl++; - page += PAGE_SIZE; - } - } -} - - -/** - * bnx2i_alloc_qp_resc - allocates required resources for QP. - * @hba: adapter structure pointer - * @ep: endpoint (transport indentifier) structure - * - * Allocate QP (transport layer for iSCSI connection) resources, DMA'able - * memory for SQ/RQ/CQ and page tables. EP structure elements such - * as producer/consumer indexes/pointers, queue sizes and page table - * contents are setup - */ -int bnx2i_alloc_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) -{ - struct bnx2i_5771x_cq_db *cq_db; - - ep->hba = hba; - ep->conn = NULL; - ep->ep_cid = ep->ep_iscsi_cid = ep->ep_pg_cid = 0; - - /* Allocate page table memory for SQ which is page aligned */ - ep->qp.sq_mem_size = hba->max_sqes * BNX2I_SQ_WQE_SIZE; - ep->qp.sq_mem_size = - (ep->qp.sq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; - ep->qp.sq_pgtbl_size = - (ep->qp.sq_mem_size / PAGE_SIZE) * sizeof(void *); - ep->qp.sq_pgtbl_size = - (ep->qp.sq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - ep->qp.sq_pgtbl_virt = - dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size, - &ep->qp.sq_pgtbl_phys, GFP_KERNEL); - if (!ep->qp.sq_pgtbl_virt) { - printk(KERN_ALERT "bnx2i: unable to alloc SQ PT mem (%d)\n", - ep->qp.sq_pgtbl_size); - goto mem_alloc_err; - } - - /* Allocate memory area for actual SQ element */ - ep->qp.sq_virt = - dma_alloc_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size, - &ep->qp.sq_phys, GFP_KERNEL); - if (!ep->qp.sq_virt) { - printk(KERN_ALERT "bnx2i: unable to alloc SQ BD memory %d\n", - ep->qp.sq_mem_size); - goto mem_alloc_err; - } - - memset(ep->qp.sq_virt, 0x00, ep->qp.sq_mem_size); - ep->qp.sq_first_qe = ep->qp.sq_virt; - ep->qp.sq_prod_qe = ep->qp.sq_first_qe; - ep->qp.sq_cons_qe = ep->qp.sq_first_qe; - ep->qp.sq_last_qe = &ep->qp.sq_first_qe[hba->max_sqes - 1]; - ep->qp.sq_prod_idx = 0; - ep->qp.sq_cons_idx = 0; - ep->qp.sqe_left = hba->max_sqes; - - /* Allocate page table memory for CQ which is page aligned */ - ep->qp.cq_mem_size = hba->max_cqes * BNX2I_CQE_SIZE; - ep->qp.cq_mem_size = - (ep->qp.cq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; - ep->qp.cq_pgtbl_size = - (ep->qp.cq_mem_size / PAGE_SIZE) * sizeof(void *); - ep->qp.cq_pgtbl_size = - (ep->qp.cq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - ep->qp.cq_pgtbl_virt = - dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size, - &ep->qp.cq_pgtbl_phys, GFP_KERNEL); - if (!ep->qp.cq_pgtbl_virt) { - printk(KERN_ALERT "bnx2i: unable to alloc CQ PT memory %d\n", - ep->qp.cq_pgtbl_size); - goto mem_alloc_err; - } - - /* Allocate memory area for actual CQ element */ - ep->qp.cq_virt = - dma_alloc_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size, - &ep->qp.cq_phys, GFP_KERNEL); - if (!ep->qp.cq_virt) { - printk(KERN_ALERT "bnx2i: unable to alloc CQ BD memory %d\n", - ep->qp.cq_mem_size); - goto mem_alloc_err; - } - memset(ep->qp.cq_virt, 0x00, ep->qp.cq_mem_size); - - ep->qp.cq_first_qe = ep->qp.cq_virt; - ep->qp.cq_prod_qe = ep->qp.cq_first_qe; - ep->qp.cq_cons_qe = ep->qp.cq_first_qe; - ep->qp.cq_last_qe = &ep->qp.cq_first_qe[hba->max_cqes - 1]; - ep->qp.cq_prod_idx = 0; - ep->qp.cq_cons_idx = 0; - ep->qp.cqe_left = hba->max_cqes; - ep->qp.cqe_exp_seq_sn = ISCSI_INITIAL_SN; - ep->qp.cqe_size = hba->max_cqes; - - /* Invalidate all EQ CQE index, req only for 57710 */ - cq_db = (struct bnx2i_5771x_cq_db *) ep->qp.cq_pgtbl_virt; - memset(cq_db->sqn, 0xFF, sizeof(cq_db->sqn[0]) * BNX2X_MAX_CQS); - - /* Allocate page table memory for RQ which is page aligned */ - ep->qp.rq_mem_size = hba->max_rqes * BNX2I_RQ_WQE_SIZE; - ep->qp.rq_mem_size = - (ep->qp.rq_mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; - ep->qp.rq_pgtbl_size = - (ep->qp.rq_mem_size / PAGE_SIZE) * sizeof(void *); - ep->qp.rq_pgtbl_size = - (ep->qp.rq_pgtbl_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - ep->qp.rq_pgtbl_virt = - dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size, - &ep->qp.rq_pgtbl_phys, GFP_KERNEL); - if (!ep->qp.rq_pgtbl_virt) { - printk(KERN_ALERT "bnx2i: unable to alloc RQ PT mem %d\n", - ep->qp.rq_pgtbl_size); - goto mem_alloc_err; - } - - /* Allocate memory area for actual RQ element */ - ep->qp.rq_virt = - dma_alloc_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size, - &ep->qp.rq_phys, GFP_KERNEL); - if (!ep->qp.rq_virt) { - printk(KERN_ALERT "bnx2i: unable to alloc RQ BD memory %d\n", - ep->qp.rq_mem_size); - goto mem_alloc_err; - } - - ep->qp.rq_first_qe = ep->qp.rq_virt; - ep->qp.rq_prod_qe = ep->qp.rq_first_qe; - ep->qp.rq_cons_qe = ep->qp.rq_first_qe; - ep->qp.rq_last_qe = &ep->qp.rq_first_qe[hba->max_rqes - 1]; - ep->qp.rq_prod_idx = 0x8000; - ep->qp.rq_cons_idx = 0; - ep->qp.rqe_left = hba->max_rqes; - - setup_qp_page_tables(ep); - - return 0; - -mem_alloc_err: - bnx2i_free_qp_resc(hba, ep); - return -ENOMEM; -} - - - -/** - * bnx2i_free_qp_resc - free memory resources held by QP - * @hba: adapter structure pointer - * @ep: endpoint (transport indentifier) structure - * - * Free QP resources - SQ/RQ/CQ memory and page tables. - */ -void bnx2i_free_qp_resc(struct bnx2i_hba *hba, struct bnx2i_endpoint *ep) -{ - if (ep->qp.ctx_base) { - iounmap(ep->qp.ctx_base); - ep->qp.ctx_base = NULL; - } - /* Free SQ mem */ - if (ep->qp.sq_pgtbl_virt) { - dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_pgtbl_size, - ep->qp.sq_pgtbl_virt, ep->qp.sq_pgtbl_phys); - ep->qp.sq_pgtbl_virt = NULL; - ep->qp.sq_pgtbl_phys = 0; - } - if (ep->qp.sq_virt) { - dma_free_coherent(&hba->pcidev->dev, ep->qp.sq_mem_size, - ep->qp.sq_virt, ep->qp.sq_phys); - ep->qp.sq_virt = NULL; - ep->qp.sq_phys = 0; - } - - /* Free RQ mem */ - if (ep->qp.rq_pgtbl_virt) { - dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_pgtbl_size, - ep->qp.rq_pgtbl_virt, ep->qp.rq_pgtbl_phys); - ep->qp.rq_pgtbl_virt = NULL; - ep->qp.rq_pgtbl_phys = 0; - } - if (ep->qp.rq_virt) { - dma_free_coherent(&hba->pcidev->dev, ep->qp.rq_mem_size, - ep->qp.rq_virt, ep->qp.rq_phys); - ep->qp.rq_virt = NULL; - ep->qp.rq_phys = 0; - } - - /* Free CQ mem */ - if (ep->qp.cq_pgtbl_virt) { - dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_pgtbl_size, - ep->qp.cq_pgtbl_virt, ep->qp.cq_pgtbl_phys); - ep->qp.cq_pgtbl_virt = NULL; - ep->qp.cq_pgtbl_phys = 0; - } - if (ep->qp.cq_virt) { - dma_free_coherent(&hba->pcidev->dev, ep->qp.cq_mem_size, - ep->qp.cq_virt, ep->qp.cq_phys); - ep->qp.cq_virt = NULL; - ep->qp.cq_phys = 0; - } -} - - -/** - * bnx2i_send_fw_iscsi_init_msg - initiates initial handshake with iscsi f/w - * @hba: adapter structure pointer - * - * Send down iscsi_init KWQEs which initiates the initial handshake with the f/w - * This results in iSCSi support validation and on-chip context manager - * initialization. Firmware completes this handshake with a CQE carrying - * the result of iscsi support validation. Parameter carried by - * iscsi init request determines the number of offloaded connection and - * tolerance level for iscsi protocol violation this hba/chip can support - */ -int bnx2i_send_fw_iscsi_init_msg(struct bnx2i_hba *hba) -{ - struct kwqe *kwqe_arr[3]; - struct iscsi_kwqe_init1 iscsi_init; - struct iscsi_kwqe_init2 iscsi_init2; - int rc = 0; - u64 mask64; - - bnx2i_adjust_qp_size(hba); - - iscsi_init.flags = - ISCSI_PAGE_SIZE_4K << ISCSI_KWQE_INIT1_PAGE_SIZE_SHIFT; - if (en_tcp_dack) - iscsi_init.flags |= ISCSI_KWQE_INIT1_DELAYED_ACK_ENABLE; - iscsi_init.reserved0 = 0; - iscsi_init.num_cqs = 1; - iscsi_init.hdr.op_code = ISCSI_KWQE_OPCODE_INIT1; - iscsi_init.hdr.flags = - (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); - - iscsi_init.dummy_buffer_addr_lo = (u32) hba->dummy_buf_dma; - iscsi_init.dummy_buffer_addr_hi = - (u32) ((u64) hba->dummy_buf_dma >> 32); - - hba->num_ccell = hba->max_sqes >> 1; - hba->ctx_ccell_tasks = - ((hba->num_ccell & 0xFFFF) | (hba->max_sqes << 16)); - iscsi_init.num_ccells_per_conn = hba->num_ccell; - iscsi_init.num_tasks_per_conn = hba->max_sqes; - iscsi_init.sq_wqes_per_page = PAGE_SIZE / BNX2I_SQ_WQE_SIZE; - iscsi_init.sq_num_wqes = hba->max_sqes; - iscsi_init.cq_log_wqes_per_page = - (u8) bnx2i_power_of2(PAGE_SIZE / BNX2I_CQE_SIZE); - iscsi_init.cq_num_wqes = hba->max_cqes; - iscsi_init.cq_num_pages = (hba->max_cqes * BNX2I_CQE_SIZE + - (PAGE_SIZE - 1)) / PAGE_SIZE; - iscsi_init.sq_num_pages = (hba->max_sqes * BNX2I_SQ_WQE_SIZE + - (PAGE_SIZE - 1)) / PAGE_SIZE; - iscsi_init.rq_buffer_size = BNX2I_RQ_WQE_SIZE; - iscsi_init.rq_num_wqes = hba->max_rqes; - - - iscsi_init2.hdr.op_code = ISCSI_KWQE_OPCODE_INIT2; - iscsi_init2.hdr.flags = - (ISCSI_KWQE_LAYER_CODE << ISCSI_KWQE_HEADER_LAYER_CODE_SHIFT); - iscsi_init2.max_cq_sqn = hba->max_cqes * 2 + 1; - mask64 = 0x0ULL; - mask64 |= ( - /* CISCO MDS */ - (1UL << - ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV) | - /* HP MSA1510i */ - (1UL << - ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN) | - /* EMC */ - (1ULL << ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN)); - if (error_mask1) { - iscsi_init2.error_bit_map[0] = error_mask1; - mask64 &= (u32)(~mask64); - mask64 |= error_mask1; - } else - iscsi_init2.error_bit_map[0] = (u32) mask64; - - if (error_mask2) { - iscsi_init2.error_bit_map[1] = error_mask2; - mask64 &= 0xffffffff; - mask64 |= ((u64)error_mask2 << 32); - } else - iscsi_init2.error_bit_map[1] = (u32) (mask64 >> 32); - - iscsi_error_mask = mask64; - - kwqe_arr[0] = (struct kwqe *) &iscsi_init; - kwqe_arr[1] = (struct kwqe *) &iscsi_init2; - - if (hba->cnic && hba->cnic->submit_kwqes) - rc = hba->cnic->submit_kwqes(hba->cnic, kwqe_arr, 2); - return rc; -} - - -/** - * bnx2i_process_scsi_cmd_resp - this function handles scsi cmd completion. - * @session: iscsi session - * @bnx2i_conn: bnx2i connection - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process SCSI CMD Response CQE & complete the request to SCSI-ML - */ -int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct bnx2i_cmd_response *resp_cqe; - struct bnx2i_cmd *bnx2i_cmd; - struct iscsi_task *task; - struct iscsi_scsi_rsp *hdr; - u32 datalen = 0; - - resp_cqe = (struct bnx2i_cmd_response *)cqe; - spin_lock_bh(&session->lock); - task = iscsi_itt_to_task(conn, - resp_cqe->itt & ISCSI_CMD_RESPONSE_INDEX); - if (!task) - goto fail; - - bnx2i_cmd = task->dd_data; - - if (bnx2i_cmd->req.op_attr & ISCSI_CMD_REQUEST_READ) { - conn->datain_pdus_cnt += - resp_cqe->task_stat.read_stat.num_data_outs; - conn->rxdata_octets += - bnx2i_cmd->req.total_data_transfer_length; - } else { - conn->dataout_pdus_cnt += - resp_cqe->task_stat.read_stat.num_data_outs; - conn->r2t_pdus_cnt += - resp_cqe->task_stat.read_stat.num_r2ts; - conn->txdata_octets += - bnx2i_cmd->req.total_data_transfer_length; - } - bnx2i_iscsi_unmap_sg_list(bnx2i_cmd); - - hdr = (struct iscsi_scsi_rsp *)task->hdr; - resp_cqe = (struct bnx2i_cmd_response *)cqe; - hdr->opcode = resp_cqe->op_code; - hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn); - hdr->exp_cmdsn = cpu_to_be32(resp_cqe->exp_cmd_sn); - hdr->response = resp_cqe->response; - hdr->cmd_status = resp_cqe->status; - hdr->flags = resp_cqe->response_flags; - hdr->residual_count = cpu_to_be32(resp_cqe->residual_count); - - if (resp_cqe->op_code == ISCSI_OP_SCSI_DATA_IN) - goto done; - - if (resp_cqe->status == SAM_STAT_CHECK_CONDITION) { - datalen = resp_cqe->data_length; - if (datalen < 2) - goto done; - - if (datalen > BNX2I_RQ_WQE_SIZE) { - iscsi_conn_printk(KERN_ERR, conn, - "sense data len %d > RQ sz\n", - datalen); - datalen = BNX2I_RQ_WQE_SIZE; - } else if (datalen > ISCSI_DEF_MAX_RECV_SEG_LEN) { - iscsi_conn_printk(KERN_ERR, conn, - "sense data len %d > conn data\n", - datalen); - datalen = ISCSI_DEF_MAX_RECV_SEG_LEN; - } - - bnx2i_get_rq_buf(bnx2i_cmd->conn, conn->data, datalen); - bnx2i_put_rq_buf(bnx2i_cmd->conn, 1); - } - -done: - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, - conn->data, datalen); -fail: - spin_unlock_bh(&session->lock); - return 0; -} - - -/** - * bnx2i_process_login_resp - this function handles iscsi login response - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process Login Response CQE & complete it to open-iscsi user daemon - */ -static int bnx2i_process_login_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct iscsi_task *task; - struct bnx2i_login_response *login; - struct iscsi_login_rsp *resp_hdr; - int pld_len; - int pad_len; - - login = (struct bnx2i_login_response *) cqe; - spin_lock(&session->lock); - task = iscsi_itt_to_task(conn, - login->itt & ISCSI_LOGIN_RESPONSE_INDEX); - if (!task) - goto done; - - resp_hdr = (struct iscsi_login_rsp *) &bnx2i_conn->gen_pdu.resp_hdr; - memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); - resp_hdr->opcode = login->op_code; - resp_hdr->flags = login->response_flags; - resp_hdr->max_version = login->version_max; - resp_hdr->active_version = login->version_active; - resp_hdr->hlength = 0; - - hton24(resp_hdr->dlength, login->data_length); - memcpy(resp_hdr->isid, &login->isid_lo, 6); - resp_hdr->tsih = cpu_to_be16(login->tsih); - resp_hdr->itt = task->hdr->itt; - resp_hdr->statsn = cpu_to_be32(login->stat_sn); - resp_hdr->exp_cmdsn = cpu_to_be32(login->exp_cmd_sn); - resp_hdr->max_cmdsn = cpu_to_be32(login->max_cmd_sn); - resp_hdr->status_class = login->status_class; - resp_hdr->status_detail = login->status_detail; - pld_len = login->data_length; - bnx2i_conn->gen_pdu.resp_wr_ptr = - bnx2i_conn->gen_pdu.resp_buf + pld_len; - - pad_len = 0; - if (pld_len & 0x3) - pad_len = 4 - (pld_len % 4); - - if (pad_len) { - int i = 0; - for (i = 0; i < pad_len; i++) { - bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0; - bnx2i_conn->gen_pdu.resp_wr_ptr++; - } - } - - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, - bnx2i_conn->gen_pdu.resp_buf, - bnx2i_conn->gen_pdu.resp_wr_ptr - bnx2i_conn->gen_pdu.resp_buf); -done: - spin_unlock(&session->lock); - return 0; -} - - -/** - * bnx2i_process_text_resp - this function handles iscsi text response - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process iSCSI Text Response CQE& complete it to open-iscsi user daemon - */ -static int bnx2i_process_text_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct iscsi_task *task; - struct bnx2i_text_response *text; - struct iscsi_text_rsp *resp_hdr; - int pld_len; - int pad_len; - - text = (struct bnx2i_text_response *) cqe; - spin_lock(&session->lock); - task = iscsi_itt_to_task(conn, text->itt & ISCSI_LOGIN_RESPONSE_INDEX); - if (!task) - goto done; - - resp_hdr = (struct iscsi_text_rsp *)&bnx2i_conn->gen_pdu.resp_hdr; - memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); - resp_hdr->opcode = text->op_code; - resp_hdr->flags = text->response_flags; - resp_hdr->hlength = 0; - - hton24(resp_hdr->dlength, text->data_length); - resp_hdr->itt = task->hdr->itt; - resp_hdr->ttt = cpu_to_be32(text->ttt); - resp_hdr->statsn = task->hdr->exp_statsn; - resp_hdr->exp_cmdsn = cpu_to_be32(text->exp_cmd_sn); - resp_hdr->max_cmdsn = cpu_to_be32(text->max_cmd_sn); - pld_len = text->data_length; - bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf + - pld_len; - pad_len = 0; - if (pld_len & 0x3) - pad_len = 4 - (pld_len % 4); - - if (pad_len) { - int i = 0; - for (i = 0; i < pad_len; i++) { - bnx2i_conn->gen_pdu.resp_wr_ptr[0] = 0; - bnx2i_conn->gen_pdu.resp_wr_ptr++; - } - } - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, - bnx2i_conn->gen_pdu.resp_buf, - bnx2i_conn->gen_pdu.resp_wr_ptr - - bnx2i_conn->gen_pdu.resp_buf); -done: - spin_unlock(&session->lock); - return 0; -} - - -/** - * bnx2i_process_tmf_resp - this function handles iscsi TMF response - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process iSCSI TMF Response CQE and wake up the driver eh thread. - */ -static int bnx2i_process_tmf_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct iscsi_task *task; - struct bnx2i_tmf_response *tmf_cqe; - struct iscsi_tm_rsp *resp_hdr; - - tmf_cqe = (struct bnx2i_tmf_response *)cqe; - spin_lock(&session->lock); - task = iscsi_itt_to_task(conn, - tmf_cqe->itt & ISCSI_TMF_RESPONSE_INDEX); - if (!task) - goto done; - - resp_hdr = (struct iscsi_tm_rsp *) &bnx2i_conn->gen_pdu.resp_hdr; - memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); - resp_hdr->opcode = tmf_cqe->op_code; - resp_hdr->max_cmdsn = cpu_to_be32(tmf_cqe->max_cmd_sn); - resp_hdr->exp_cmdsn = cpu_to_be32(tmf_cqe->exp_cmd_sn); - resp_hdr->itt = task->hdr->itt; - resp_hdr->response = tmf_cqe->response; - - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0); -done: - spin_unlock(&session->lock); - return 0; -} - -/** - * bnx2i_process_logout_resp - this function handles iscsi logout response - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process iSCSI Logout Response CQE & make function call to - * notify the user daemon. - */ -static int bnx2i_process_logout_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct iscsi_task *task; - struct bnx2i_logout_response *logout; - struct iscsi_logout_rsp *resp_hdr; - - logout = (struct bnx2i_logout_response *) cqe; - spin_lock(&session->lock); - task = iscsi_itt_to_task(conn, - logout->itt & ISCSI_LOGOUT_RESPONSE_INDEX); - if (!task) - goto done; - - resp_hdr = (struct iscsi_logout_rsp *) &bnx2i_conn->gen_pdu.resp_hdr; - memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); - resp_hdr->opcode = logout->op_code; - resp_hdr->flags = logout->response; - resp_hdr->hlength = 0; - - resp_hdr->itt = task->hdr->itt; - resp_hdr->statsn = task->hdr->exp_statsn; - resp_hdr->exp_cmdsn = cpu_to_be32(logout->exp_cmd_sn); - resp_hdr->max_cmdsn = cpu_to_be32(logout->max_cmd_sn); - - resp_hdr->t2wait = cpu_to_be32(logout->time_to_wait); - resp_hdr->t2retain = cpu_to_be32(logout->time_to_retain); - - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0); - - bnx2i_conn->ep->state = EP_STATE_LOGOUT_RESP_RCVD; -done: - spin_unlock(&session->lock); - return 0; -} - -/** - * bnx2i_process_nopin_local_cmpl - this function handles iscsi nopin CQE - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process iSCSI NOPIN local completion CQE, frees IIT and command structures - */ -static void bnx2i_process_nopin_local_cmpl(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct bnx2i_nop_in_msg *nop_in; - struct iscsi_task *task; - - nop_in = (struct bnx2i_nop_in_msg *)cqe; - spin_lock(&session->lock); - task = iscsi_itt_to_task(conn, - nop_in->itt & ISCSI_NOP_IN_MSG_INDEX); - if (task) - __iscsi_put_task(task); - spin_unlock(&session->lock); -} - -/** - * bnx2i_unsol_pdu_adjust_rq - makes adjustments to RQ after unsol pdu is recvd - * @conn: iscsi connection - * - * Firmware advances RQ producer index for every unsolicited PDU even if - * payload data length is '0'. This function makes corresponding - * adjustments on the driver side to match this f/w behavior - */ -static void bnx2i_unsol_pdu_adjust_rq(struct bnx2i_conn *bnx2i_conn) -{ - char dummy_rq_data[2]; - bnx2i_get_rq_buf(bnx2i_conn, dummy_rq_data, 1); - bnx2i_put_rq_buf(bnx2i_conn, 1); -} - - -/** - * bnx2i_process_nopin_mesg - this function handles iscsi nopin CQE - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process iSCSI target's proactive iSCSI NOPIN request - */ -static int bnx2i_process_nopin_mesg(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct iscsi_task *task; - struct bnx2i_nop_in_msg *nop_in; - struct iscsi_nopin *hdr; - int tgt_async_nop = 0; - - nop_in = (struct bnx2i_nop_in_msg *)cqe; - - spin_lock(&session->lock); - hdr = (struct iscsi_nopin *)&bnx2i_conn->gen_pdu.resp_hdr; - memset(hdr, 0, sizeof(struct iscsi_hdr)); - hdr->opcode = nop_in->op_code; - hdr->max_cmdsn = cpu_to_be32(nop_in->max_cmd_sn); - hdr->exp_cmdsn = cpu_to_be32(nop_in->exp_cmd_sn); - hdr->ttt = cpu_to_be32(nop_in->ttt); - - if (nop_in->itt == (u16) RESERVED_ITT) { - bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); - hdr->itt = RESERVED_ITT; - tgt_async_nop = 1; - goto done; - } - - /* this is a response to one of our nop-outs */ - task = iscsi_itt_to_task(conn, - (itt_t) (nop_in->itt & ISCSI_NOP_IN_MSG_INDEX)); - if (task) { - hdr->flags = ISCSI_FLAG_CMD_FINAL; - hdr->itt = task->hdr->itt; - hdr->ttt = cpu_to_be32(nop_in->ttt); - memcpy(&hdr->lun, nop_in->lun, 8); - } -done: - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, NULL, 0); - spin_unlock(&session->lock); - - return tgt_async_nop; -} - - -/** - * bnx2i_process_async_mesg - this function handles iscsi async message - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process iSCSI ASYNC Message - */ -static void bnx2i_process_async_mesg(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct bnx2i_async_msg *async_cqe; - struct iscsi_async *resp_hdr; - u8 async_event; - - bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); - - async_cqe = (struct bnx2i_async_msg *)cqe; - async_event = async_cqe->async_event; - - if (async_event == ISCSI_ASYNC_MSG_SCSI_EVENT) { - iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data, - "async: scsi events not supported\n"); - return; - } - - spin_lock(&session->lock); - resp_hdr = (struct iscsi_async *) &bnx2i_conn->gen_pdu.resp_hdr; - memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); - resp_hdr->opcode = async_cqe->op_code; - resp_hdr->flags = 0x80; - - memcpy(&resp_hdr->lun, async_cqe->lun, 8); - resp_hdr->exp_cmdsn = cpu_to_be32(async_cqe->exp_cmd_sn); - resp_hdr->max_cmdsn = cpu_to_be32(async_cqe->max_cmd_sn); - - resp_hdr->async_event = async_cqe->async_event; - resp_hdr->async_vcode = async_cqe->async_vcode; - - resp_hdr->param1 = cpu_to_be16(async_cqe->param1); - resp_hdr->param2 = cpu_to_be16(async_cqe->param2); - resp_hdr->param3 = cpu_to_be16(async_cqe->param3); - - __iscsi_complete_pdu(bnx2i_conn->cls_conn->dd_data, - (struct iscsi_hdr *)resp_hdr, NULL, 0); - spin_unlock(&session->lock); -} - - -/** - * bnx2i_process_reject_mesg - process iscsi reject pdu - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process iSCSI REJECT message - */ -static void bnx2i_process_reject_mesg(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct bnx2i_reject_msg *reject; - struct iscsi_reject *hdr; - - reject = (struct bnx2i_reject_msg *) cqe; - if (reject->data_length) { - bnx2i_get_rq_buf(bnx2i_conn, conn->data, reject->data_length); - bnx2i_put_rq_buf(bnx2i_conn, 1); - } else - bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); - - spin_lock(&session->lock); - hdr = (struct iscsi_reject *) &bnx2i_conn->gen_pdu.resp_hdr; - memset(hdr, 0, sizeof(struct iscsi_hdr)); - hdr->opcode = reject->op_code; - hdr->reason = reject->reason; - hton24(hdr->dlength, reject->data_length); - hdr->max_cmdsn = cpu_to_be32(reject->max_cmd_sn); - hdr->exp_cmdsn = cpu_to_be32(reject->exp_cmd_sn); - hdr->ffffffff = cpu_to_be32(RESERVED_ITT); - __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, conn->data, - reject->data_length); - spin_unlock(&session->lock); -} - -/** - * bnx2i_process_cmd_cleanup_resp - process scsi command clean-up completion - * @session: iscsi session pointer - * @bnx2i_conn: iscsi connection pointer - * @cqe: pointer to newly DMA'ed CQE entry for processing - * - * process command cleanup response CQE during conn shutdown or error recovery - */ -static void bnx2i_process_cmd_cleanup_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct cqe *cqe) -{ - struct bnx2i_cleanup_response *cmd_clean_rsp; - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct iscsi_task *task; - - cmd_clean_rsp = (struct bnx2i_cleanup_response *)cqe; - spin_lock(&session->lock); - task = iscsi_itt_to_task(conn, - cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX); - if (!task) - printk(KERN_ALERT "bnx2i: cmd clean ITT %x not active\n", - cmd_clean_rsp->itt & ISCSI_CLEANUP_RESPONSE_INDEX); - spin_unlock(&session->lock); - complete(&bnx2i_conn->cmd_cleanup_cmpl); -} - - -/** - * bnx2i_percpu_io_thread - thread per cpu for ios - * - * @arg: ptr to bnx2i_percpu_info structure - */ -int bnx2i_percpu_io_thread(void *arg) -{ - struct bnx2i_percpu_s *p = arg; - struct bnx2i_work *work, *tmp; - LIST_HEAD(work_list); - - set_user_nice(current, -20); - - while (!kthread_should_stop()) { - spin_lock_bh(&p->p_work_lock); - while (!list_empty(&p->work_list)) { - list_splice_init(&p->work_list, &work_list); - spin_unlock_bh(&p->p_work_lock); - - list_for_each_entry_safe(work, tmp, &work_list, list) { - list_del_init(&work->list); - /* work allocated in the bh, freed here */ - bnx2i_process_scsi_cmd_resp(work->session, - work->bnx2i_conn, - &work->cqe); - atomic_dec(&work->bnx2i_conn->work_cnt); - kfree(work); - } - spin_lock_bh(&p->p_work_lock); - } - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&p->p_work_lock); - schedule(); - } - __set_current_state(TASK_RUNNING); - - return 0; -} - - -/** - * bnx2i_queue_scsi_cmd_resp - queue cmd completion to the percpu thread - * @bnx2i_conn: bnx2i connection - * - * this function is called by generic KCQ handler to queue all pending cmd - * completion CQEs - * - * The implementation is to queue the cmd response based on the - * last recorded command for the given connection. The - * cpu_id gets recorded upon task_xmit. No out-of-order completion! - */ -static int bnx2i_queue_scsi_cmd_resp(struct iscsi_session *session, - struct bnx2i_conn *bnx2i_conn, - struct bnx2i_nop_in_msg *cqe) -{ - struct bnx2i_work *bnx2i_work = NULL; - struct bnx2i_percpu_s *p = NULL; - struct iscsi_task *task; - struct scsi_cmnd *sc; - int rc = 0; - int cpu; - - spin_lock(&session->lock); - task = iscsi_itt_to_task(bnx2i_conn->cls_conn->dd_data, - cqe->itt & ISCSI_CMD_RESPONSE_INDEX); - if (!task || !task->sc) { - spin_unlock(&session->lock); - return -EINVAL; - } - sc = task->sc; - - if (!blk_rq_cpu_valid(sc->request)) - cpu = smp_processor_id(); - else - cpu = sc->request->cpu; - - spin_unlock(&session->lock); - - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock(&p->p_work_lock); - if (unlikely(!p->iothread)) { - rc = -EINVAL; - goto err; - } - /* Alloc and copy to the cqe */ - bnx2i_work = kzalloc(sizeof(struct bnx2i_work), GFP_ATOMIC); - if (bnx2i_work) { - INIT_LIST_HEAD(&bnx2i_work->list); - bnx2i_work->session = session; - bnx2i_work->bnx2i_conn = bnx2i_conn; - memcpy(&bnx2i_work->cqe, cqe, sizeof(struct cqe)); - list_add_tail(&bnx2i_work->list, &p->work_list); - atomic_inc(&bnx2i_conn->work_cnt); - wake_up_process(p->iothread); - spin_unlock(&p->p_work_lock); - goto done; - } else - rc = -ENOMEM; -err: - spin_unlock(&p->p_work_lock); - bnx2i_process_scsi_cmd_resp(session, bnx2i_conn, (struct cqe *)cqe); -done: - return rc; -} - - -/** - * bnx2i_process_new_cqes - process newly DMA'ed CQE's - * @bnx2i_conn: bnx2i connection - * - * this function is called by generic KCQ handler to process all pending CQE's - */ -static int bnx2i_process_new_cqes(struct bnx2i_conn *bnx2i_conn) -{ - struct iscsi_conn *conn = bnx2i_conn->cls_conn->dd_data; - struct iscsi_session *session = conn->session; - struct qp_info *qp; - struct bnx2i_nop_in_msg *nopin; - int tgt_async_msg; - int cqe_cnt = 0; - - if (bnx2i_conn->ep == NULL) - return 0; - - qp = &bnx2i_conn->ep->qp; - - if (!qp->cq_virt) { - printk(KERN_ALERT "bnx2i (%s): cq resr freed in bh execution!", - bnx2i_conn->hba->netdev->name); - goto out; - } - while (1) { - nopin = (struct bnx2i_nop_in_msg *) qp->cq_cons_qe; - if (nopin->cq_req_sn != qp->cqe_exp_seq_sn) - break; - - if (unlikely(test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx))) { - if (nopin->op_code == ISCSI_OP_NOOP_IN && - nopin->itt == (u16) RESERVED_ITT) { - printk(KERN_ALERT "bnx2i: Unsolicited " - "NOP-In detected for suspended " - "connection dev=%s!\n", - bnx2i_conn->hba->netdev->name); - bnx2i_unsol_pdu_adjust_rq(bnx2i_conn); - goto cqe_out; - } - break; - } - tgt_async_msg = 0; - - switch (nopin->op_code) { - case ISCSI_OP_SCSI_CMD_RSP: - case ISCSI_OP_SCSI_DATA_IN: - /* Run the kthread engine only for data cmds - All other cmds will be completed in this bh! */ - bnx2i_queue_scsi_cmd_resp(session, bnx2i_conn, nopin); - break; - case ISCSI_OP_LOGIN_RSP: - bnx2i_process_login_resp(session, bnx2i_conn, - qp->cq_cons_qe); - break; - case ISCSI_OP_SCSI_TMFUNC_RSP: - bnx2i_process_tmf_resp(session, bnx2i_conn, - qp->cq_cons_qe); - break; - case ISCSI_OP_TEXT_RSP: - bnx2i_process_text_resp(session, bnx2i_conn, - qp->cq_cons_qe); - break; - case ISCSI_OP_LOGOUT_RSP: - bnx2i_process_logout_resp(session, bnx2i_conn, - qp->cq_cons_qe); - break; - case ISCSI_OP_NOOP_IN: - if (bnx2i_process_nopin_mesg(session, bnx2i_conn, - qp->cq_cons_qe)) - tgt_async_msg = 1; - break; - case ISCSI_OPCODE_NOPOUT_LOCAL_COMPLETION: - bnx2i_process_nopin_local_cmpl(session, bnx2i_conn, - qp->cq_cons_qe); - break; - case ISCSI_OP_ASYNC_EVENT: - bnx2i_process_async_mesg(session, bnx2i_conn, - qp->cq_cons_qe); - tgt_async_msg = 1; - break; - case ISCSI_OP_REJECT: - bnx2i_process_reject_mesg(session, bnx2i_conn, - qp->cq_cons_qe); - break; - case ISCSI_OPCODE_CLEANUP_RESPONSE: - bnx2i_process_cmd_cleanup_resp(session, bnx2i_conn, - qp->cq_cons_qe); - break; - default: - printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", - nopin->op_code); - } - if (!tgt_async_msg) { - if (!atomic_read(&bnx2i_conn->ep->num_active_cmds)) - printk(KERN_ALERT "bnx2i (%s): no active cmd! " - "op 0x%x\n", - bnx2i_conn->hba->netdev->name, - nopin->op_code); - else - atomic_dec(&bnx2i_conn->ep->num_active_cmds); - } -cqe_out: - /* clear out in production version only, till beta keep opcode - * field intact, will be helpful in debugging (context dump) - * nopin->op_code = 0; - */ - cqe_cnt++; - qp->cqe_exp_seq_sn++; - if (qp->cqe_exp_seq_sn == (qp->cqe_size * 2 + 1)) - qp->cqe_exp_seq_sn = ISCSI_INITIAL_SN; - - if (qp->cq_cons_qe == qp->cq_last_qe) { - qp->cq_cons_qe = qp->cq_first_qe; - qp->cq_cons_idx = 0; - } else { - qp->cq_cons_qe++; - qp->cq_cons_idx++; - } - } -out: - return cqe_cnt; -} - -/** - * bnx2i_fastpath_notification - process global event queue (KCQ) - * @hba: adapter structure pointer - * @new_cqe_kcqe: pointer to newly DMA'ed KCQE entry - * - * Fast path event notification handler, KCQ entry carries context id - * of the connection that has 1 or more pending CQ entries - */ -static void bnx2i_fastpath_notification(struct bnx2i_hba *hba, - struct iscsi_kcqe *new_cqe_kcqe) -{ - struct bnx2i_conn *bnx2i_conn; - u32 iscsi_cid; - int nxt_idx; - - iscsi_cid = new_cqe_kcqe->iscsi_conn_id; - bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); - - if (!bnx2i_conn) { - printk(KERN_ALERT "cid #%x not valid\n", iscsi_cid); - return; - } - if (!bnx2i_conn->ep) { - printk(KERN_ALERT "cid #%x - ep not bound\n", iscsi_cid); - return; - } - - bnx2i_process_new_cqes(bnx2i_conn); - nxt_idx = bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, - CNIC_ARM_CQE_FP); - if (nxt_idx && nxt_idx == bnx2i_process_new_cqes(bnx2i_conn)) - bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE_FP); -} - - -/** - * bnx2i_process_update_conn_cmpl - process iscsi conn update completion KCQE - * @hba: adapter structure pointer - * @update_kcqe: kcqe pointer - * - * CONN_UPDATE completion handler, this completes iSCSI connection FFP migration - */ -static void bnx2i_process_update_conn_cmpl(struct bnx2i_hba *hba, - struct iscsi_kcqe *update_kcqe) -{ - struct bnx2i_conn *conn; - u32 iscsi_cid; - - iscsi_cid = update_kcqe->iscsi_conn_id; - conn = bnx2i_get_conn_from_id(hba, iscsi_cid); - - if (!conn) { - printk(KERN_ALERT "conn_update: cid %x not valid\n", iscsi_cid); - return; - } - if (!conn->ep) { - printk(KERN_ALERT "cid %x does not have ep bound\n", iscsi_cid); - return; - } - - if (update_kcqe->completion_status) { - printk(KERN_ALERT "request failed cid %x\n", iscsi_cid); - conn->ep->state = EP_STATE_ULP_UPDATE_FAILED; - } else - conn->ep->state = EP_STATE_ULP_UPDATE_COMPL; - - wake_up_interruptible(&conn->ep->ofld_wait); -} - - -/** - * bnx2i_recovery_que_add_conn - add connection to recovery queue - * @hba: adapter structure pointer - * @bnx2i_conn: iscsi connection - * - * Add connection to recovery queue and schedule adapter eh worker - */ -static void bnx2i_recovery_que_add_conn(struct bnx2i_hba *hba, - struct bnx2i_conn *bnx2i_conn) -{ - iscsi_conn_failure(bnx2i_conn->cls_conn->dd_data, - ISCSI_ERR_CONN_FAILED); -} - - -/** - * bnx2i_process_tcp_error - process error notification on a given connection - * - * @hba: adapter structure pointer - * @tcp_err: tcp error kcqe pointer - * - * handles tcp level error notifications from FW. - */ -static void bnx2i_process_tcp_error(struct bnx2i_hba *hba, - struct iscsi_kcqe *tcp_err) -{ - struct bnx2i_conn *bnx2i_conn; - u32 iscsi_cid; - - iscsi_cid = tcp_err->iscsi_conn_id; - bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); - - if (!bnx2i_conn) { - printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid); - return; - } - - printk(KERN_ALERT "bnx2i - cid 0x%x had TCP errors, error code 0x%x\n", - iscsi_cid, tcp_err->completion_status); - bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn); -} - - -/** - * bnx2i_process_iscsi_error - process error notification on a given connection - * @hba: adapter structure pointer - * @iscsi_err: iscsi error kcqe pointer - * - * handles iscsi error notifications from the FW. Firmware based in initial - * handshake classifies iscsi protocol / TCP rfc violation into either - * warning or error indications. If indication is of "Error" type, driver - * will initiate session recovery for that connection/session. For - * "Warning" type indication, driver will put out a system log message - * (there will be only one message for each type for the life of the - * session, this is to avoid un-necessarily overloading the system) - */ -static void bnx2i_process_iscsi_error(struct bnx2i_hba *hba, - struct iscsi_kcqe *iscsi_err) -{ - struct bnx2i_conn *bnx2i_conn; - u32 iscsi_cid; - char warn_notice[] = "iscsi_warning"; - char error_notice[] = "iscsi_error"; - char additional_notice[64]; - char *message; - int need_recovery; - u64 err_mask64; - - iscsi_cid = iscsi_err->iscsi_conn_id; - bnx2i_conn = bnx2i_get_conn_from_id(hba, iscsi_cid); - if (!bnx2i_conn) { - printk(KERN_ALERT "bnx2i - cid 0x%x not valid\n", iscsi_cid); - return; - } - - err_mask64 = (0x1ULL << iscsi_err->completion_status); - - if (err_mask64 & iscsi_error_mask) { - need_recovery = 0; - message = warn_notice; - } else { - need_recovery = 1; - message = error_notice; - } - - switch (iscsi_err->completion_status) { - case ISCSI_KCQE_COMPLETION_STATUS_HDR_DIG_ERR: - strcpy(additional_notice, "hdr digest err"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_DATA_DIG_ERR: - strcpy(additional_notice, "data digest err"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_OPCODE: - strcpy(additional_notice, "wrong opcode rcvd"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_AHS_LEN: - strcpy(additional_notice, "AHS len > 0 rcvd"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ITT: - strcpy(additional_notice, "invalid ITT rcvd"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_STATSN: - strcpy(additional_notice, "wrong StatSN rcvd"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_EXP_DATASN: - strcpy(additional_notice, "wrong DataSN rcvd"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T: - strcpy(additional_notice, "pend R2T violation"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_0: - strcpy(additional_notice, "ERL0, UO"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_1: - strcpy(additional_notice, "ERL0, U1"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_2: - strcpy(additional_notice, "ERL0, U2"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_3: - strcpy(additional_notice, "ERL0, U3"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_4: - strcpy(additional_notice, "ERL0, U4"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_5: - strcpy(additional_notice, "ERL0, U5"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_O_U_6: - strcpy(additional_notice, "ERL0, U6"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_RCV_LEN: - strcpy(additional_notice, "invalid resi len"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_RCV_PDU_LEN: - strcpy(additional_notice, "MRDSL violation"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_F_BIT_ZERO: - strcpy(additional_notice, "F-bit not set"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_NOT_RSRV: - strcpy(additional_notice, "invalid TTT"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATASN: - strcpy(additional_notice, "invalid DataSN"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REMAIN_BURST_LEN: - strcpy(additional_notice, "burst len violation"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_BUFFER_OFF: - strcpy(additional_notice, "buf offset violation"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_LUN: - strcpy(additional_notice, "invalid LUN field"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_R2TSN: - strcpy(additional_notice, "invalid R2TSN field"); - break; -#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0 \ - ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0 - case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_0: - strcpy(additional_notice, "invalid cmd len1"); - break; -#define BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1 \ - ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1 - case BNX2I_ERR_DESIRED_DATA_TRNS_LEN_1: - strcpy(additional_notice, "invalid cmd len2"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_EXCEED: - strcpy(additional_notice, - "pend r2t exceeds MaxOutstandingR2T value"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_TTT_IS_RSRV: - strcpy(additional_notice, "TTT is rsvd"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_MAX_BURST_LEN: - strcpy(additional_notice, "MBL violation"); - break; -#define BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO \ - ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_DATA_SEG_LEN_NOT_ZERO - case BNX2I_ERR_DATA_SEG_LEN_NOT_ZERO: - strcpy(additional_notice, "data seg len != 0"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_REJECT_PDU_LEN: - strcpy(additional_notice, "reject pdu len error"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_ASYNC_PDU_LEN: - strcpy(additional_notice, "async pdu len error"); - break; - case ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_NOPIN_PDU_LEN: - strcpy(additional_notice, "nopin pdu len error"); - break; -#define BNX2_ERR_PEND_R2T_IN_CLEANUP \ - ISCSI_KCQE_COMPLETION_STATUS_PROTOCOL_ERR_PEND_R2T_IN_CLEANUP - case BNX2_ERR_PEND_R2T_IN_CLEANUP: - strcpy(additional_notice, "pend r2t in cleanup"); - break; - - case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_FRAGMENT: - strcpy(additional_notice, "IP fragments rcvd"); - break; - case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_IP_OPTIONS: - strcpy(additional_notice, "IP options error"); - break; - case ISCI_KCQE_COMPLETION_STATUS_TCP_ERROR_URGENT_FLAG: - strcpy(additional_notice, "urgent flag error"); - break; - default: - printk(KERN_ALERT "iscsi_err - unknown err %x\n", - iscsi_err->completion_status); - } - - if (need_recovery) { - iscsi_conn_printk(KERN_ALERT, - bnx2i_conn->cls_conn->dd_data, - "bnx2i: %s - %s\n", - message, additional_notice); - - iscsi_conn_printk(KERN_ALERT, - bnx2i_conn->cls_conn->dd_data, - "conn_err - hostno %d conn %p, " - "iscsi_cid %x cid %x\n", - bnx2i_conn->hba->shost->host_no, - bnx2i_conn, bnx2i_conn->ep->ep_iscsi_cid, - bnx2i_conn->ep->ep_cid); - bnx2i_recovery_que_add_conn(bnx2i_conn->hba, bnx2i_conn); - } else - if (!test_and_set_bit(iscsi_err->completion_status, - (void *) &bnx2i_conn->violation_notified)) - iscsi_conn_printk(KERN_ALERT, - bnx2i_conn->cls_conn->dd_data, - "bnx2i: %s - %s\n", - message, additional_notice); -} - - -/** - * bnx2i_process_conn_destroy_cmpl - process iscsi conn destroy completion - * @hba: adapter structure pointer - * @conn_destroy: conn destroy kcqe pointer - * - * handles connection destroy completion request. - */ -static void bnx2i_process_conn_destroy_cmpl(struct bnx2i_hba *hba, - struct iscsi_kcqe *conn_destroy) -{ - struct bnx2i_endpoint *ep; - - ep = bnx2i_find_ep_in_destroy_list(hba, conn_destroy->iscsi_conn_id); - if (!ep) { - printk(KERN_ALERT "bnx2i_conn_destroy_cmpl: no pending " - "offload request, unexpected complection\n"); - return; - } - - if (hba != ep->hba) { - printk(KERN_ALERT "conn destroy- error hba mis-match\n"); - return; - } - - if (conn_destroy->completion_status) { - printk(KERN_ALERT "conn_destroy_cmpl: op failed\n"); - ep->state = EP_STATE_CLEANUP_FAILED; - } else - ep->state = EP_STATE_CLEANUP_CMPL; - wake_up_interruptible(&ep->ofld_wait); -} - - -/** - * bnx2i_process_ofld_cmpl - process initial iscsi conn offload completion - * @hba: adapter structure pointer - * @ofld_kcqe: conn offload kcqe pointer - * - * handles initial connection offload completion, ep_connect() thread is - * woken-up to continue with LLP connect process - */ -static void bnx2i_process_ofld_cmpl(struct bnx2i_hba *hba, - struct iscsi_kcqe *ofld_kcqe) -{ - u32 cid_addr; - struct bnx2i_endpoint *ep; - u32 cid_num; - - ep = bnx2i_find_ep_in_ofld_list(hba, ofld_kcqe->iscsi_conn_id); - if (!ep) { - printk(KERN_ALERT "ofld_cmpl: no pend offload request\n"); - return; - } - - if (hba != ep->hba) { - printk(KERN_ALERT "ofld_cmpl: error hba mis-match\n"); - return; - } - - if (ofld_kcqe->completion_status) { - ep->state = EP_STATE_OFLD_FAILED; - if (ofld_kcqe->completion_status == - ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE) - printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - unable " - "to allocate iSCSI context resources\n", - hba->netdev->name); - else if (ofld_kcqe->completion_status == - ISCSI_KCQE_COMPLETION_STATUS_INVALID_OPCODE) - printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " - "opcode\n", hba->netdev->name); - else if (ofld_kcqe->completion_status == - ISCSI_KCQE_COMPLETION_STATUS_CID_BUSY) - /* error status code valid only for 5771x chipset */ - ep->state = EP_STATE_OFLD_FAILED_CID_BUSY; - else - printk(KERN_ALERT "bnx2i (%s): ofld1 cmpl - invalid " - "error code %d\n", hba->netdev->name, - ofld_kcqe->completion_status); - } else { - ep->state = EP_STATE_OFLD_COMPL; - cid_addr = ofld_kcqe->iscsi_conn_context_id; - cid_num = bnx2i_get_cid_num(ep); - ep->ep_cid = cid_addr; - ep->qp.ctx_base = NULL; - } - wake_up_interruptible(&ep->ofld_wait); -} - -/** - * bnx2i_indicate_kcqe - process iscsi conn update completion KCQE - * @hba: adapter structure pointer - * @update_kcqe: kcqe pointer - * - * Generic KCQ event handler/dispatcher - */ -static void bnx2i_indicate_kcqe(void *context, struct kcqe *kcqe[], - u32 num_cqe) -{ - struct bnx2i_hba *hba = context; - int i = 0; - struct iscsi_kcqe *ikcqe = NULL; - - while (i < num_cqe) { - ikcqe = (struct iscsi_kcqe *) kcqe[i++]; - - if (ikcqe->op_code == - ISCSI_KCQE_OPCODE_CQ_EVENT_NOTIFICATION) - bnx2i_fastpath_notification(hba, ikcqe); - else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_OFFLOAD_CONN) - bnx2i_process_ofld_cmpl(hba, ikcqe); - else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_UPDATE_CONN) - bnx2i_process_update_conn_cmpl(hba, ikcqe); - else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_INIT) { - if (ikcqe->completion_status != - ISCSI_KCQE_COMPLETION_STATUS_SUCCESS) - bnx2i_iscsi_license_error(hba, ikcqe->\ - completion_status); - else { - set_bit(ADAPTER_STATE_UP, &hba->adapter_state); - bnx2i_get_link_state(hba); - printk(KERN_INFO "bnx2i [%.2x:%.2x.%.2x]: " - "ISCSI_INIT passed\n", - (u8)hba->pcidev->bus->number, - hba->pci_devno, - (u8)hba->pci_func); - - - } - } else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_DESTROY_CONN) - bnx2i_process_conn_destroy_cmpl(hba, ikcqe); - else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_ISCSI_ERROR) - bnx2i_process_iscsi_error(hba, ikcqe); - else if (ikcqe->op_code == ISCSI_KCQE_OPCODE_TCP_ERROR) - bnx2i_process_tcp_error(hba, ikcqe); - else - printk(KERN_ALERT "bnx2i: unknown opcode 0x%x\n", - ikcqe->op_code); - } -} - - -/** - * bnx2i_indicate_netevent - Generic netdev event handler - * @context: adapter structure pointer - * @event: event type - * @vlan_id: vlans id - associated vlan id with this event - * - * Handles four netdev events, NETDEV_UP, NETDEV_DOWN, - * NETDEV_GOING_DOWN and NETDEV_CHANGE - */ -static void bnx2i_indicate_netevent(void *context, unsigned long event, - u16 vlan_id) -{ - struct bnx2i_hba *hba = context; - - /* Ignore all netevent coming from vlans */ - if (vlan_id != 0) - return; - - switch (event) { - case NETDEV_UP: - if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state)) - bnx2i_send_fw_iscsi_init_msg(hba); - break; - case NETDEV_DOWN: - clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); - clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); - break; - case NETDEV_GOING_DOWN: - set_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); - iscsi_host_for_each_session(hba->shost, - bnx2i_drop_session); - break; - case NETDEV_CHANGE: - bnx2i_get_link_state(hba); - break; - default: - ; - } -} - - -/** - * bnx2i_cm_connect_cmpl - process iscsi conn establishment completion - * @cm_sk: cnic sock structure pointer - * - * function callback exported via bnx2i - cnic driver interface to - * indicate completion of option-2 TCP connect request. - */ -static void bnx2i_cm_connect_cmpl(struct cnic_sock *cm_sk) -{ - struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; - - if (test_bit(ADAPTER_STATE_GOING_DOWN, &ep->hba->adapter_state)) - ep->state = EP_STATE_CONNECT_FAILED; - else if (test_bit(SK_F_OFFLD_COMPLETE, &cm_sk->flags)) - ep->state = EP_STATE_CONNECT_COMPL; - else - ep->state = EP_STATE_CONNECT_FAILED; - - wake_up_interruptible(&ep->ofld_wait); -} - - -/** - * bnx2i_cm_close_cmpl - process tcp conn close completion - * @cm_sk: cnic sock structure pointer - * - * function callback exported via bnx2i - cnic driver interface to - * indicate completion of option-2 graceful TCP connect shutdown - */ -static void bnx2i_cm_close_cmpl(struct cnic_sock *cm_sk) -{ - struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; - - ep->state = EP_STATE_DISCONN_COMPL; - wake_up_interruptible(&ep->ofld_wait); -} - - -/** - * bnx2i_cm_abort_cmpl - process abortive tcp conn teardown completion - * @cm_sk: cnic sock structure pointer - * - * function callback exported via bnx2i - cnic driver interface to - * indicate completion of option-2 abortive TCP connect termination - */ -static void bnx2i_cm_abort_cmpl(struct cnic_sock *cm_sk) -{ - struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; - - ep->state = EP_STATE_DISCONN_COMPL; - wake_up_interruptible(&ep->ofld_wait); -} - - -/** - * bnx2i_cm_remote_close - process received TCP FIN - * @hba: adapter structure pointer - * @update_kcqe: kcqe pointer - * - * function callback exported via bnx2i - cnic driver interface to indicate - * async TCP events such as FIN - */ -static void bnx2i_cm_remote_close(struct cnic_sock *cm_sk) -{ - struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; - - ep->state = EP_STATE_TCP_FIN_RCVD; - if (ep->conn) - bnx2i_recovery_que_add_conn(ep->hba, ep->conn); -} - -/** - * bnx2i_cm_remote_abort - process TCP RST and start conn cleanup - * @hba: adapter structure pointer - * @update_kcqe: kcqe pointer - * - * function callback exported via bnx2i - cnic driver interface to - * indicate async TCP events (RST) sent by the peer. - */ -static void bnx2i_cm_remote_abort(struct cnic_sock *cm_sk) -{ - struct bnx2i_endpoint *ep = (struct bnx2i_endpoint *) cm_sk->context; - u32 old_state = ep->state; - - ep->state = EP_STATE_TCP_RST_RCVD; - if (old_state == EP_STATE_DISCONN_START) - wake_up_interruptible(&ep->ofld_wait); - else - if (ep->conn) - bnx2i_recovery_que_add_conn(ep->hba, ep->conn); -} - - -static int bnx2i_send_nl_mesg(void *context, u32 msg_type, - char *buf, u16 buflen) -{ - struct bnx2i_hba *hba = context; - int rc; - - if (!hba) - return -ENODEV; - - rc = iscsi_offload_mesg(hba->shost, &bnx2i_iscsi_transport, - msg_type, buf, buflen); - if (rc) - printk(KERN_ALERT "bnx2i: private nl message send error\n"); - - return rc; -} - - -/** - * bnx2i_cnic_cb - global template of bnx2i - cnic driver interface structure - * carrying callback function pointers - * - */ -struct cnic_ulp_ops bnx2i_cnic_cb = { - .cnic_init = bnx2i_ulp_init, - .cnic_exit = bnx2i_ulp_exit, - .cnic_start = bnx2i_start, - .cnic_stop = bnx2i_stop, - .indicate_kcqes = bnx2i_indicate_kcqe, - .indicate_netevent = bnx2i_indicate_netevent, - .cm_connect_complete = bnx2i_cm_connect_cmpl, - .cm_close_complete = bnx2i_cm_close_cmpl, - .cm_abort_complete = bnx2i_cm_abort_cmpl, - .cm_remote_close = bnx2i_cm_remote_close, - .cm_remote_abort = bnx2i_cm_remote_abort, - .iscsi_nl_send_msg = bnx2i_send_nl_mesg, - .owner = THIS_MODULE -}; - - -/** - * bnx2i_map_ep_dbell_regs - map connection doorbell registers - * @ep: bnx2i endpoint - * - * maps connection's SQ and RQ doorbell registers, 5706/5708/5709 hosts these - * register in BAR #0. Whereas in 57710 these register are accessed by - * mapping BAR #1 - */ -int bnx2i_map_ep_dbell_regs(struct bnx2i_endpoint *ep) -{ - u32 cid_num; - u32 reg_off; - u32 first_l4l5; - u32 ctx_sz; - u32 config2; - resource_size_t reg_base; - - cid_num = bnx2i_get_cid_num(ep); - - if (test_bit(BNX2I_NX2_DEV_57710, &ep->hba->cnic_dev_type)) { - reg_base = pci_resource_start(ep->hba->pcidev, - BNX2X_DOORBELL_PCI_BAR); - reg_off = BNX2I_5771X_DBELL_PAGE_SIZE * (cid_num & 0x1FFFF) + - DPM_TRIGER_TYPE; - ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, 4); - goto arm_cq; - } - - reg_base = ep->hba->netdev->base_addr; - if ((test_bit(BNX2I_NX2_DEV_5709, &ep->hba->cnic_dev_type)) && - (ep->hba->mail_queue_access == BNX2I_MQ_BIN_MODE)) { - config2 = REG_RD(ep->hba, BNX2_MQ_CONFIG2); - first_l4l5 = config2 & BNX2_MQ_CONFIG2_FIRST_L4L5; - ctx_sz = (config2 & BNX2_MQ_CONFIG2_CONT_SZ) >> 3; - if (ctx_sz) - reg_off = CTX_OFFSET + MAX_CID_CNT * MB_KERNEL_CTX_SIZE - + BNX2I_570X_PAGE_SIZE_DEFAULT * - (((cid_num - first_l4l5) / ctx_sz) + 256); - else - reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num); - } else - /* 5709 device in normal node and 5706/5708 devices */ - reg_off = CTX_OFFSET + (MB_KERNEL_CTX_SIZE * cid_num); - - ep->qp.ctx_base = ioremap_nocache(reg_base + reg_off, - MB_KERNEL_CTX_SIZE); - if (!ep->qp.ctx_base) - return -ENOMEM; - -arm_cq: - bnx2i_arm_cq_event_coalescing(ep, CNIC_ARM_CQE); - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_init.c b/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_init.c deleted file mode 100644 index 4927cca7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_init.c +++ /dev/null @@ -1,565 +0,0 @@ -/* bnx2i.c: Broadcom NetXtreme II iSCSI driver. - * - * Copyright (c) 2006 - 2011 Broadcom Corporation - * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. - * Copyright (c) 2007, 2008 Mike Christie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) - * Maintained by: Eddie Wai (eddie.wai@broadcom.com) - */ - -#include "bnx2i.h" - -static struct list_head adapter_list = LIST_HEAD_INIT(adapter_list); -static u32 adapter_count; - -#define DRV_MODULE_NAME "bnx2i" -#define DRV_MODULE_VERSION "2.7.0.3" -#define DRV_MODULE_RELDATE "Jun 15, 2011" - -static char version[] __devinitdata = - "Broadcom NetXtreme II iSCSI Driver " DRV_MODULE_NAME \ - " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; - - -MODULE_AUTHOR("Anil Veerabhadrappa and " - "Eddie Wai "); - -MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708/5709/57710/57711/57712" - "/57800/57810/57840 iSCSI Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_MODULE_VERSION); - -static DEFINE_MUTEX(bnx2i_dev_lock); - -unsigned int event_coal_min = 24; -module_param(event_coal_min, int, 0664); -MODULE_PARM_DESC(event_coal_min, "Event Coalescing Minimum Commands"); - -unsigned int event_coal_div = 2; -module_param(event_coal_div, int, 0664); -MODULE_PARM_DESC(event_coal_div, "Event Coalescing Divide Factor"); - -unsigned int en_tcp_dack = 1; -module_param(en_tcp_dack, int, 0664); -MODULE_PARM_DESC(en_tcp_dack, "Enable TCP Delayed ACK"); - -unsigned int error_mask1 = 0x00; -module_param(error_mask1, uint, 0664); -MODULE_PARM_DESC(error_mask1, "Config FW iSCSI Error Mask #1"); - -unsigned int error_mask2 = 0x00; -module_param(error_mask2, uint, 0664); -MODULE_PARM_DESC(error_mask2, "Config FW iSCSI Error Mask #2"); - -unsigned int sq_size; -module_param(sq_size, int, 0664); -MODULE_PARM_DESC(sq_size, "Configure SQ size"); - -unsigned int rq_size = BNX2I_RQ_WQES_DEFAULT; -module_param(rq_size, int, 0664); -MODULE_PARM_DESC(rq_size, "Configure RQ size"); - -u64 iscsi_error_mask = 0x00; - -DEFINE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); - -static int bnx2i_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu); -/* notification function for CPU hotplug events */ -static struct notifier_block bnx2i_cpu_notifier = { - .notifier_call = bnx2i_cpu_callback, -}; - - -/** - * bnx2i_identify_device - identifies NetXtreme II device type - * @hba: Adapter structure pointer - * - * This function identifies the NX2 device type and sets appropriate - * queue mailbox register access method, 5709 requires driver to - * access MBOX regs using *bin* mode - */ -void bnx2i_identify_device(struct bnx2i_hba *hba) -{ - hba->cnic_dev_type = 0; - if ((hba->pci_did == PCI_DEVICE_ID_NX2_5706) || - (hba->pci_did == PCI_DEVICE_ID_NX2_5706S)) - set_bit(BNX2I_NX2_DEV_5706, &hba->cnic_dev_type); - else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5708) || - (hba->pci_did == PCI_DEVICE_ID_NX2_5708S)) - set_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type); - else if ((hba->pci_did == PCI_DEVICE_ID_NX2_5709) || - (hba->pci_did == PCI_DEVICE_ID_NX2_5709S)) { - set_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type); - hba->mail_queue_access = BNX2I_MQ_BIN_MODE; - } else if (hba->pci_did == PCI_DEVICE_ID_NX2_57710 || - hba->pci_did == PCI_DEVICE_ID_NX2_57711 || - hba->pci_did == PCI_DEVICE_ID_NX2_57711E || - hba->pci_did == PCI_DEVICE_ID_NX2_57712 || - hba->pci_did == PCI_DEVICE_ID_NX2_57712E || - hba->pci_did == PCI_DEVICE_ID_NX2_57800 || - hba->pci_did == PCI_DEVICE_ID_NX2_57800_MF || - hba->pci_did == PCI_DEVICE_ID_NX2_57800_VF || - hba->pci_did == PCI_DEVICE_ID_NX2_57810 || - hba->pci_did == PCI_DEVICE_ID_NX2_57810_MF || - hba->pci_did == PCI_DEVICE_ID_NX2_57810_VF || - hba->pci_did == PCI_DEVICE_ID_NX2_57840 || - hba->pci_did == PCI_DEVICE_ID_NX2_57840_MF || - hba->pci_did == PCI_DEVICE_ID_NX2_57840_VF) - set_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type); - else - printk(KERN_ALERT "bnx2i: unknown device, 0x%x\n", - hba->pci_did); -} - - -/** - * get_adapter_list_head - returns head of adapter list - */ -struct bnx2i_hba *get_adapter_list_head(void) -{ - struct bnx2i_hba *hba = NULL; - struct bnx2i_hba *tmp_hba; - - if (!adapter_count) - goto hba_not_found; - - mutex_lock(&bnx2i_dev_lock); - list_for_each_entry(tmp_hba, &adapter_list, link) { - if (tmp_hba->cnic && tmp_hba->cnic->cm_select_dev) { - hba = tmp_hba; - break; - } - } - mutex_unlock(&bnx2i_dev_lock); -hba_not_found: - return hba; -} - - -/** - * bnx2i_find_hba_for_cnic - maps cnic device instance to bnx2i adapter instance - * @cnic: pointer to cnic device instance - * - */ -struct bnx2i_hba *bnx2i_find_hba_for_cnic(struct cnic_dev *cnic) -{ - struct bnx2i_hba *hba, *temp; - - mutex_lock(&bnx2i_dev_lock); - list_for_each_entry_safe(hba, temp, &adapter_list, link) { - if (hba->cnic == cnic) { - mutex_unlock(&bnx2i_dev_lock); - return hba; - } - } - mutex_unlock(&bnx2i_dev_lock); - return NULL; -} - - -/** - * bnx2i_start - cnic callback to initialize & start adapter instance - * @handle: transparent handle pointing to adapter structure - * - * This function maps adapter structure to pcidev structure and initiates - * firmware handshake to enable/initialize on chip iscsi components - * This bnx2i - cnic interface api callback is issued after following - * 2 conditions are met - - * a) underlying network interface is up (marked by event 'NETDEV_UP' - * from netdev - * b) bnx2i adapter instance is registered - */ -void bnx2i_start(void *handle) -{ -#define BNX2I_INIT_POLL_TIME (1000 / HZ) - struct bnx2i_hba *hba = handle; - int i = HZ; - - /* - * We should never register devices that don't support iSCSI - * (see bnx2i_init_one), so something is wrong if we try to - * start a iSCSI adapter on hardware with 0 supported iSCSI - * connections - */ - BUG_ON(!hba->cnic->max_iscsi_conn); - - bnx2i_send_fw_iscsi_init_msg(hba); - while (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) && i--) - msleep(BNX2I_INIT_POLL_TIME); -} - - -/** - * bnx2i_chip_cleanup - local routine to handle chip cleanup - * @hba: Adapter instance to register - * - * Driver checks if adapter still has any active connections before - * executing the cleanup process - */ -static void bnx2i_chip_cleanup(struct bnx2i_hba *hba) -{ - struct bnx2i_endpoint *bnx2i_ep; - struct list_head *pos, *tmp; - - if (hba->ofld_conns_active) { - /* Stage to force the disconnection - * This is the case where the daemon is either slow or - * not present - */ - printk(KERN_ALERT "bnx2i: (%s) chip cleanup for %d active " - "connections\n", hba->netdev->name, - hba->ofld_conns_active); - mutex_lock(&hba->net_dev_lock); - list_for_each_safe(pos, tmp, &hba->ep_active_list) { - bnx2i_ep = list_entry(pos, struct bnx2i_endpoint, link); - /* Clean up the chip only */ - bnx2i_hw_ep_disconnect(bnx2i_ep); - bnx2i_ep->cm_sk = NULL; - } - mutex_unlock(&hba->net_dev_lock); - } -} - - -/** - * bnx2i_stop - cnic callback to shutdown adapter instance - * @handle: transparent handle pointing to adapter structure - * - * driver checks if adapter is already in shutdown mode, if not start - * the shutdown process - */ -void bnx2i_stop(void *handle) -{ - struct bnx2i_hba *hba = handle; - int conns_active; - int wait_delay = 1 * HZ; - - /* check if cleanup happened in GOING_DOWN context */ - if (!test_and_set_bit(ADAPTER_STATE_GOING_DOWN, - &hba->adapter_state)) { - iscsi_host_for_each_session(hba->shost, - bnx2i_drop_session); - wait_delay = hba->hba_shutdown_tmo; - } - /* Wait for inflight offload connection tasks to complete before - * proceeding. Forcefully terminate all connection recovery in - * progress at the earliest, either in bind(), send_pdu(LOGIN), - * or conn_start() - */ - wait_event_interruptible_timeout(hba->eh_wait, - (list_empty(&hba->ep_ofld_list) && - list_empty(&hba->ep_destroy_list)), - 2 * HZ); - /* Wait for all endpoints to be torn down, Chip will be reset once - * control returns to network driver. So it is required to cleanup and - * release all connection resources before returning from this routine. - */ - while (hba->ofld_conns_active) { - conns_active = hba->ofld_conns_active; - wait_event_interruptible_timeout(hba->eh_wait, - (hba->ofld_conns_active != conns_active), - wait_delay); - if (hba->ofld_conns_active == conns_active) - break; - } - bnx2i_chip_cleanup(hba); - - /* This flag should be cleared last so that ep_disconnect() gracefully - * cleans up connection context - */ - clear_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state); - clear_bit(ADAPTER_STATE_UP, &hba->adapter_state); -} - - -/** - * bnx2i_init_one - initialize an adapter instance and allocate memory resources - * @hba: bnx2i adapter instance - * @cnic: cnic device handle - * - * Global resource lock is held during critical sections below. This routine is - * called from either cnic_register_driver() or device hot plug context and - * and does majority of device specific initialization - */ -static int bnx2i_init_one(struct bnx2i_hba *hba, struct cnic_dev *cnic) -{ - int rc; - - mutex_lock(&bnx2i_dev_lock); - if (!cnic->max_iscsi_conn) { - printk(KERN_ALERT "bnx2i: dev %s does not support " - "iSCSI\n", hba->netdev->name); - rc = -EOPNOTSUPP; - goto out; - } - - hba->cnic = cnic; - rc = cnic->register_device(cnic, CNIC_ULP_ISCSI, hba); - if (!rc) { - hba->age++; - set_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); - list_add_tail(&hba->link, &adapter_list); - adapter_count++; - } else if (rc == -EBUSY) /* duplicate registration */ - printk(KERN_ALERT "bnx2i, duplicate registration" - "hba=%p, cnic=%p\n", hba, cnic); - else if (rc == -EAGAIN) - printk(KERN_ERR "bnx2i, driver not registered\n"); - else if (rc == -EINVAL) - printk(KERN_ERR "bnx2i, invalid type %d\n", CNIC_ULP_ISCSI); - else - printk(KERN_ERR "bnx2i dev reg, unknown error, %d\n", rc); - -out: - mutex_unlock(&bnx2i_dev_lock); - - return rc; -} - - -/** - * bnx2i_ulp_init - initialize an adapter instance - * @dev: cnic device handle - * - * Called from cnic_register_driver() context to initialize all enumerated - * cnic devices. This routine allocate adapter structure and other - * device specific resources. - */ -void bnx2i_ulp_init(struct cnic_dev *dev) -{ - struct bnx2i_hba *hba; - - /* Allocate a HBA structure for this device */ - hba = bnx2i_alloc_hba(dev); - if (!hba) { - printk(KERN_ERR "bnx2i init: hba initialization failed\n"); - return; - } - - /* Get PCI related information and update hba struct members */ - clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); - if (bnx2i_init_one(hba, dev)) { - printk(KERN_ERR "bnx2i - hba %p init failed\n", hba); - bnx2i_free_hba(hba); - } -} - - -/** - * bnx2i_ulp_exit - shuts down adapter instance and frees all resources - * @dev: cnic device handle - * - */ -void bnx2i_ulp_exit(struct cnic_dev *dev) -{ - struct bnx2i_hba *hba; - - hba = bnx2i_find_hba_for_cnic(dev); - if (!hba) { - printk(KERN_INFO "bnx2i_ulp_exit: hba not " - "found, dev 0x%p\n", dev); - return; - } - mutex_lock(&bnx2i_dev_lock); - list_del_init(&hba->link); - adapter_count--; - - if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { - hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); - clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); - } - mutex_unlock(&bnx2i_dev_lock); - - bnx2i_free_hba(hba); -} - - -/** - * bnx2i_percpu_thread_create - Create a receive thread for an - * online CPU - * - * @cpu: cpu index for the online cpu - */ -static void bnx2i_percpu_thread_create(unsigned int cpu) -{ - struct bnx2i_percpu_s *p; - struct task_struct *thread; - - p = &per_cpu(bnx2i_percpu, cpu); - - thread = kthread_create_on_node(bnx2i_percpu_io_thread, (void *)p, - cpu_to_node(cpu), - "bnx2i_thread/%d", cpu); - /* bind thread to the cpu */ - if (likely(!IS_ERR(thread))) { - kthread_bind(thread, cpu); - p->iothread = thread; - wake_up_process(thread); - } -} - - -static void bnx2i_percpu_thread_destroy(unsigned int cpu) -{ - struct bnx2i_percpu_s *p; - struct task_struct *thread; - struct bnx2i_work *work, *tmp; - - /* Prevent any new work from being queued for this CPU */ - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock_bh(&p->p_work_lock); - thread = p->iothread; - p->iothread = NULL; - - /* Free all work in the list */ - list_for_each_entry_safe(work, tmp, &p->work_list, list) { - list_del_init(&work->list); - bnx2i_process_scsi_cmd_resp(work->session, - work->bnx2i_conn, &work->cqe); - kfree(work); - } - - spin_unlock_bh(&p->p_work_lock); - if (thread) - kthread_stop(thread); -} - - -/** - * bnx2i_cpu_callback - Handler for CPU hotplug events - * - * @nfb: The callback data block - * @action: The event triggering the callback - * @hcpu: The index of the CPU that the event is for - * - * This creates or destroys per-CPU data for iSCSI - * - * Returns NOTIFY_OK always. - */ -static int bnx2i_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - printk(KERN_INFO "bnx2i: CPU %x online: Create Rx thread\n", - cpu); - bnx2i_percpu_thread_create(cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - printk(KERN_INFO "CPU %x offline: Remove Rx thread\n", cpu); - bnx2i_percpu_thread_destroy(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - - -/** - * bnx2i_mod_init - module init entry point - * - * initialize any driver wide global data structures such as endpoint pool, - * tcp port manager/queue, sysfs. finally driver will register itself - * with the cnic module - */ -static int __init bnx2i_mod_init(void) -{ - int err; - unsigned cpu = 0; - struct bnx2i_percpu_s *p; - - printk(KERN_INFO "%s", version); - - if (sq_size && !is_power_of_2(sq_size)) - sq_size = roundup_pow_of_two(sq_size); - - mutex_init(&bnx2i_dev_lock); - - bnx2i_scsi_xport_template = - iscsi_register_transport(&bnx2i_iscsi_transport); - if (!bnx2i_scsi_xport_template) { - printk(KERN_ERR "Could not register bnx2i transport.\n"); - err = -ENOMEM; - goto out; - } - - err = cnic_register_driver(CNIC_ULP_ISCSI, &bnx2i_cnic_cb); - if (err) { - printk(KERN_ERR "Could not register bnx2i cnic driver.\n"); - goto unreg_xport; - } - - /* Create percpu kernel threads to handle iSCSI I/O completions */ - for_each_possible_cpu(cpu) { - p = &per_cpu(bnx2i_percpu, cpu); - INIT_LIST_HEAD(&p->work_list); - spin_lock_init(&p->p_work_lock); - p->iothread = NULL; - } - - for_each_online_cpu(cpu) - bnx2i_percpu_thread_create(cpu); - - /* Initialize per CPU interrupt thread */ - register_hotcpu_notifier(&bnx2i_cpu_notifier); - - return 0; - -unreg_xport: - iscsi_unregister_transport(&bnx2i_iscsi_transport); -out: - return err; -} - - -/** - * bnx2i_mod_exit - module cleanup/exit entry point - * - * Global resource lock and host adapter lock is held during critical sections - * in this function. Driver will browse through the adapter list, cleans-up - * each instance, unregisters iscsi transport name and finally driver will - * unregister itself with the cnic module - */ -static void __exit bnx2i_mod_exit(void) -{ - struct bnx2i_hba *hba; - unsigned cpu = 0; - - mutex_lock(&bnx2i_dev_lock); - while (!list_empty(&adapter_list)) { - hba = list_entry(adapter_list.next, struct bnx2i_hba, link); - list_del(&hba->link); - adapter_count--; - - if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { - bnx2i_chip_cleanup(hba); - hba->cnic->unregister_device(hba->cnic, CNIC_ULP_ISCSI); - clear_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic); - } - - bnx2i_free_hba(hba); - } - mutex_unlock(&bnx2i_dev_lock); - - unregister_hotcpu_notifier(&bnx2i_cpu_notifier); - - for_each_online_cpu(cpu) - bnx2i_percpu_thread_destroy(cpu); - - iscsi_unregister_transport(&bnx2i_iscsi_transport); - cnic_unregister_driver(CNIC_ULP_ISCSI); -} - -module_init(bnx2i_mod_init); -module_exit(bnx2i_mod_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_iscsi.c b/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_iscsi.c deleted file mode 100644 index 1a44b45e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ /dev/null @@ -1,2287 +0,0 @@ -/* - * bnx2i_iscsi.c: Broadcom NetXtreme II iSCSI driver. - * - * Copyright (c) 2006 - 2011 Broadcom Corporation - * Copyright (c) 2007, 2008 Red Hat, Inc. All rights reserved. - * Copyright (c) 2007, 2008 Mike Christie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) - * Maintained by: Eddie Wai (eddie.wai@broadcom.com) - */ - -#include -#include -#include -#include "bnx2i.h" - -struct scsi_transport_template *bnx2i_scsi_xport_template; -struct iscsi_transport bnx2i_iscsi_transport; -static struct scsi_host_template bnx2i_host_template; - -/* - * Global endpoint resource info - */ -static DEFINE_SPINLOCK(bnx2i_resc_lock); /* protects global resources */ - -DECLARE_PER_CPU(struct bnx2i_percpu_s, bnx2i_percpu); - -static int bnx2i_adapter_ready(struct bnx2i_hba *hba) -{ - int retval = 0; - - if (!hba || !test_bit(ADAPTER_STATE_UP, &hba->adapter_state) || - test_bit(ADAPTER_STATE_GOING_DOWN, &hba->adapter_state) || - test_bit(ADAPTER_STATE_LINK_DOWN, &hba->adapter_state)) - retval = -EPERM; - return retval; -} - -/** - * bnx2i_get_write_cmd_bd_idx - identifies various BD bookmarks - * @cmd: iscsi cmd struct pointer - * @buf_off: absolute buffer offset - * @start_bd_off: u32 pointer to return the offset within the BD - * indicated by 'start_bd_idx' on which 'buf_off' falls - * @start_bd_idx: index of the BD on which 'buf_off' falls - * - * identifies & marks various bd info for scsi command's imm data, - * unsolicited data and the first solicited data seq. - */ -static void bnx2i_get_write_cmd_bd_idx(struct bnx2i_cmd *cmd, u32 buf_off, - u32 *start_bd_off, u32 *start_bd_idx) -{ - struct iscsi_bd *bd_tbl = cmd->io_tbl.bd_tbl; - u32 cur_offset = 0; - u32 cur_bd_idx = 0; - - if (buf_off) { - while (buf_off >= (cur_offset + bd_tbl->buffer_length)) { - cur_offset += bd_tbl->buffer_length; - cur_bd_idx++; - bd_tbl++; - } - } - - *start_bd_off = buf_off - cur_offset; - *start_bd_idx = cur_bd_idx; -} - -/** - * bnx2i_setup_write_cmd_bd_info - sets up BD various information - * @task: transport layer's cmd struct pointer - * - * identifies & marks various bd info for scsi command's immediate data, - * unsolicited data and first solicited data seq which includes BD start - * index & BD buf off. his function takes into account iscsi parameter such - * as immediate data and unsolicited data is support on this connection. - */ -static void bnx2i_setup_write_cmd_bd_info(struct iscsi_task *task) -{ - struct bnx2i_cmd *cmd = task->dd_data; - u32 start_bd_offset; - u32 start_bd_idx; - u32 buffer_offset = 0; - u32 cmd_len = cmd->req.total_data_transfer_length; - - /* if ImmediateData is turned off & IntialR2T is turned on, - * there will be no immediate or unsolicited data, just return. - */ - if (!iscsi_task_has_unsol_data(task) && !task->imm_count) - return; - - /* Immediate data */ - buffer_offset += task->imm_count; - if (task->imm_count == cmd_len) - return; - - if (iscsi_task_has_unsol_data(task)) { - bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset, - &start_bd_offset, &start_bd_idx); - cmd->req.ud_buffer_offset = start_bd_offset; - cmd->req.ud_start_bd_index = start_bd_idx; - buffer_offset += task->unsol_r2t.data_length; - } - - if (buffer_offset != cmd_len) { - bnx2i_get_write_cmd_bd_idx(cmd, buffer_offset, - &start_bd_offset, &start_bd_idx); - if ((start_bd_offset > task->conn->session->first_burst) || - (start_bd_idx > scsi_sg_count(cmd->scsi_cmd))) { - int i = 0; - - iscsi_conn_printk(KERN_ALERT, task->conn, - "bnx2i- error, buf offset 0x%x " - "bd_valid %d use_sg %d\n", - buffer_offset, cmd->io_tbl.bd_valid, - scsi_sg_count(cmd->scsi_cmd)); - for (i = 0; i < cmd->io_tbl.bd_valid; i++) - iscsi_conn_printk(KERN_ALERT, task->conn, - "bnx2i err, bd[%d]: len %x\n", - i, cmd->io_tbl.bd_tbl[i].\ - buffer_length); - } - cmd->req.sd_buffer_offset = start_bd_offset; - cmd->req.sd_start_bd_index = start_bd_idx; - } -} - - - -/** - * bnx2i_map_scsi_sg - maps IO buffer and prepares the BD table - * @hba: adapter instance - * @cmd: iscsi cmd struct pointer - * - * map SG list - */ -static int bnx2i_map_scsi_sg(struct bnx2i_hba *hba, struct bnx2i_cmd *cmd) -{ - struct scsi_cmnd *sc = cmd->scsi_cmd; - struct iscsi_bd *bd = cmd->io_tbl.bd_tbl; - struct scatterlist *sg; - int byte_count = 0; - int bd_count = 0; - int sg_count; - int sg_len; - u64 addr; - int i; - - BUG_ON(scsi_sg_count(sc) > ISCSI_MAX_BDS_PER_CMD); - - sg_count = scsi_dma_map(sc); - - scsi_for_each_sg(sc, sg, sg_count, i) { - sg_len = sg_dma_len(sg); - addr = (u64) sg_dma_address(sg); - bd[bd_count].buffer_addr_lo = addr & 0xffffffff; - bd[bd_count].buffer_addr_hi = addr >> 32; - bd[bd_count].buffer_length = sg_len; - bd[bd_count].flags = 0; - if (bd_count == 0) - bd[bd_count].flags = ISCSI_BD_FIRST_IN_BD_CHAIN; - - byte_count += sg_len; - bd_count++; - } - - if (bd_count) - bd[bd_count - 1].flags |= ISCSI_BD_LAST_IN_BD_CHAIN; - - BUG_ON(byte_count != scsi_bufflen(sc)); - return bd_count; -} - -/** - * bnx2i_iscsi_map_sg_list - maps SG list - * @cmd: iscsi cmd struct pointer - * - * creates BD list table for the command - */ -static void bnx2i_iscsi_map_sg_list(struct bnx2i_cmd *cmd) -{ - int bd_count; - - bd_count = bnx2i_map_scsi_sg(cmd->conn->hba, cmd); - if (!bd_count) { - struct iscsi_bd *bd = cmd->io_tbl.bd_tbl; - - bd[0].buffer_addr_lo = bd[0].buffer_addr_hi = 0; - bd[0].buffer_length = bd[0].flags = 0; - } - cmd->io_tbl.bd_valid = bd_count; -} - - -/** - * bnx2i_iscsi_unmap_sg_list - unmaps SG list - * @cmd: iscsi cmd struct pointer - * - * unmap IO buffers and invalidate the BD table - */ -void bnx2i_iscsi_unmap_sg_list(struct bnx2i_cmd *cmd) -{ - struct scsi_cmnd *sc = cmd->scsi_cmd; - - if (cmd->io_tbl.bd_valid && sc) { - scsi_dma_unmap(sc); - cmd->io_tbl.bd_valid = 0; - } -} - -static void bnx2i_setup_cmd_wqe_template(struct bnx2i_cmd *cmd) -{ - memset(&cmd->req, 0x00, sizeof(cmd->req)); - cmd->req.op_code = 0xFF; - cmd->req.bd_list_addr_lo = (u32) cmd->io_tbl.bd_tbl_dma; - cmd->req.bd_list_addr_hi = - (u32) ((u64) cmd->io_tbl.bd_tbl_dma >> 32); - -} - - -/** - * bnx2i_bind_conn_to_iscsi_cid - bind conn structure to 'iscsi_cid' - * @hba: pointer to adapter instance - * @conn: pointer to iscsi connection - * @iscsi_cid: iscsi context ID, range 0 - (MAX_CONN - 1) - * - * update iscsi cid table entry with connection pointer. This enables - * driver to quickly get hold of connection structure pointer in - * completion/interrupt thread using iscsi context ID - */ -static int bnx2i_bind_conn_to_iscsi_cid(struct bnx2i_hba *hba, - struct bnx2i_conn *bnx2i_conn, - u32 iscsi_cid) -{ - if (hba && hba->cid_que.conn_cid_tbl[iscsi_cid]) { - iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data, - "conn bind - entry #%d not free\n", iscsi_cid); - return -EBUSY; - } - - hba->cid_que.conn_cid_tbl[iscsi_cid] = bnx2i_conn; - return 0; -} - - -/** - * bnx2i_get_conn_from_id - maps an iscsi cid to corresponding conn ptr - * @hba: pointer to adapter instance - * @iscsi_cid: iscsi context ID, range 0 - (MAX_CONN - 1) - */ -struct bnx2i_conn *bnx2i_get_conn_from_id(struct bnx2i_hba *hba, - u16 iscsi_cid) -{ - if (!hba->cid_que.conn_cid_tbl) { - printk(KERN_ERR "bnx2i: ERROR - missing conn<->cid table\n"); - return NULL; - - } else if (iscsi_cid >= hba->max_active_conns) { - printk(KERN_ERR "bnx2i: wrong cid #%d\n", iscsi_cid); - return NULL; - } - return hba->cid_que.conn_cid_tbl[iscsi_cid]; -} - - -/** - * bnx2i_alloc_iscsi_cid - allocates a iscsi_cid from free pool - * @hba: pointer to adapter instance - */ -static u32 bnx2i_alloc_iscsi_cid(struct bnx2i_hba *hba) -{ - int idx; - - if (!hba->cid_que.cid_free_cnt) - return -1; - - idx = hba->cid_que.cid_q_cons_idx; - hba->cid_que.cid_q_cons_idx++; - if (hba->cid_que.cid_q_cons_idx == hba->cid_que.cid_q_max_idx) - hba->cid_que.cid_q_cons_idx = 0; - - hba->cid_que.cid_free_cnt--; - return hba->cid_que.cid_que[idx]; -} - - -/** - * bnx2i_free_iscsi_cid - returns tcp port to free list - * @hba: pointer to adapter instance - * @iscsi_cid: iscsi context ID to free - */ -static void bnx2i_free_iscsi_cid(struct bnx2i_hba *hba, u16 iscsi_cid) -{ - int idx; - - if (iscsi_cid == (u16) -1) - return; - - hba->cid_que.cid_free_cnt++; - - idx = hba->cid_que.cid_q_prod_idx; - hba->cid_que.cid_que[idx] = iscsi_cid; - hba->cid_que.conn_cid_tbl[iscsi_cid] = NULL; - hba->cid_que.cid_q_prod_idx++; - if (hba->cid_que.cid_q_prod_idx == hba->cid_que.cid_q_max_idx) - hba->cid_que.cid_q_prod_idx = 0; -} - - -/** - * bnx2i_setup_free_cid_que - sets up free iscsi cid queue - * @hba: pointer to adapter instance - * - * allocates memory for iscsi cid queue & 'cid - conn ptr' mapping table, - * and initialize table attributes - */ -static int bnx2i_setup_free_cid_que(struct bnx2i_hba *hba) -{ - int mem_size; - int i; - - mem_size = hba->max_active_conns * sizeof(u32); - mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; - - hba->cid_que.cid_que_base = kmalloc(mem_size, GFP_KERNEL); - if (!hba->cid_que.cid_que_base) - return -ENOMEM; - - mem_size = hba->max_active_conns * sizeof(struct bnx2i_conn *); - mem_size = (mem_size + (PAGE_SIZE - 1)) & PAGE_MASK; - hba->cid_que.conn_cid_tbl = kmalloc(mem_size, GFP_KERNEL); - if (!hba->cid_que.conn_cid_tbl) { - kfree(hba->cid_que.cid_que_base); - hba->cid_que.cid_que_base = NULL; - return -ENOMEM; - } - - hba->cid_que.cid_que = (u32 *)hba->cid_que.cid_que_base; - hba->cid_que.cid_q_prod_idx = 0; - hba->cid_que.cid_q_cons_idx = 0; - hba->cid_que.cid_q_max_idx = hba->max_active_conns; - hba->cid_que.cid_free_cnt = hba->max_active_conns; - - for (i = 0; i < hba->max_active_conns; i++) { - hba->cid_que.cid_que[i] = i; - hba->cid_que.conn_cid_tbl[i] = NULL; - } - return 0; -} - - -/** - * bnx2i_release_free_cid_que - releases 'iscsi_cid' queue resources - * @hba: pointer to adapter instance - */ -static void bnx2i_release_free_cid_que(struct bnx2i_hba *hba) -{ - kfree(hba->cid_que.cid_que_base); - hba->cid_que.cid_que_base = NULL; - - kfree(hba->cid_que.conn_cid_tbl); - hba->cid_que.conn_cid_tbl = NULL; -} - - -/** - * bnx2i_alloc_ep - allocates ep structure from global pool - * @hba: pointer to adapter instance - * - * routine allocates a free endpoint structure from global pool and - * a tcp port to be used for this connection. Global resource lock, - * 'bnx2i_resc_lock' is held while accessing shared global data structures - */ -static struct iscsi_endpoint *bnx2i_alloc_ep(struct bnx2i_hba *hba) -{ - struct iscsi_endpoint *ep; - struct bnx2i_endpoint *bnx2i_ep; - u32 ec_div; - - ep = iscsi_create_endpoint(sizeof(*bnx2i_ep)); - if (!ep) { - printk(KERN_ERR "bnx2i: Could not allocate ep\n"); - return NULL; - } - - bnx2i_ep = ep->dd_data; - bnx2i_ep->cls_ep = ep; - INIT_LIST_HEAD(&bnx2i_ep->link); - bnx2i_ep->state = EP_STATE_IDLE; - bnx2i_ep->ep_iscsi_cid = (u16) -1; - bnx2i_ep->hba = hba; - bnx2i_ep->hba_age = hba->age; - - ec_div = event_coal_div; - while (ec_div >>= 1) - bnx2i_ep->ec_shift += 1; - - hba->ofld_conns_active++; - init_waitqueue_head(&bnx2i_ep->ofld_wait); - return ep; -} - - -/** - * bnx2i_free_ep - free endpoint - * @ep: pointer to iscsi endpoint structure - */ -static void bnx2i_free_ep(struct iscsi_endpoint *ep) -{ - struct bnx2i_endpoint *bnx2i_ep = ep->dd_data; - unsigned long flags; - - spin_lock_irqsave(&bnx2i_resc_lock, flags); - bnx2i_ep->state = EP_STATE_IDLE; - bnx2i_ep->hba->ofld_conns_active--; - - if (bnx2i_ep->ep_iscsi_cid != (u16) -1) - bnx2i_free_iscsi_cid(bnx2i_ep->hba, bnx2i_ep->ep_iscsi_cid); - - if (bnx2i_ep->conn) { - bnx2i_ep->conn->ep = NULL; - bnx2i_ep->conn = NULL; - } - - bnx2i_ep->hba = NULL; - spin_unlock_irqrestore(&bnx2i_resc_lock, flags); - iscsi_destroy_endpoint(ep); -} - - -/** - * bnx2i_alloc_bdt - allocates buffer descriptor (BD) table for the command - * @hba: adapter instance pointer - * @session: iscsi session pointer - * @cmd: iscsi command structure - */ -static int bnx2i_alloc_bdt(struct bnx2i_hba *hba, struct iscsi_session *session, - struct bnx2i_cmd *cmd) -{ - struct io_bdt *io = &cmd->io_tbl; - struct iscsi_bd *bd; - - io->bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, - ISCSI_MAX_BDS_PER_CMD * sizeof(*bd), - &io->bd_tbl_dma, GFP_KERNEL); - if (!io->bd_tbl) { - iscsi_session_printk(KERN_ERR, session, "Could not " - "allocate bdt.\n"); - return -ENOMEM; - } - io->bd_valid = 0; - return 0; -} - -/** - * bnx2i_destroy_cmd_pool - destroys iscsi command pool and release BD table - * @hba: adapter instance pointer - * @session: iscsi session pointer - * @cmd: iscsi command structure - */ -static void bnx2i_destroy_cmd_pool(struct bnx2i_hba *hba, - struct iscsi_session *session) -{ - int i; - - for (i = 0; i < session->cmds_max; i++) { - struct iscsi_task *task = session->cmds[i]; - struct bnx2i_cmd *cmd = task->dd_data; - - if (cmd->io_tbl.bd_tbl) - dma_free_coherent(&hba->pcidev->dev, - ISCSI_MAX_BDS_PER_CMD * - sizeof(struct iscsi_bd), - cmd->io_tbl.bd_tbl, - cmd->io_tbl.bd_tbl_dma); - } - -} - - -/** - * bnx2i_setup_cmd_pool - sets up iscsi command pool for the session - * @hba: adapter instance pointer - * @session: iscsi session pointer - */ -static int bnx2i_setup_cmd_pool(struct bnx2i_hba *hba, - struct iscsi_session *session) -{ - int i; - - for (i = 0; i < session->cmds_max; i++) { - struct iscsi_task *task = session->cmds[i]; - struct bnx2i_cmd *cmd = task->dd_data; - - task->hdr = &cmd->hdr; - task->hdr_max = sizeof(struct iscsi_hdr); - - if (bnx2i_alloc_bdt(hba, session, cmd)) - goto free_bdts; - } - - return 0; - -free_bdts: - bnx2i_destroy_cmd_pool(hba, session); - return -ENOMEM; -} - - -/** - * bnx2i_setup_mp_bdt - allocate BD table resources - * @hba: pointer to adapter structure - * - * Allocate memory for dummy buffer and associated BD - * table to be used by middle path (MP) requests - */ -static int bnx2i_setup_mp_bdt(struct bnx2i_hba *hba) -{ - int rc = 0; - struct iscsi_bd *mp_bdt; - u64 addr; - - hba->mp_bd_tbl = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, - &hba->mp_bd_dma, GFP_KERNEL); - if (!hba->mp_bd_tbl) { - printk(KERN_ERR "unable to allocate Middle Path BDT\n"); - rc = -1; - goto out; - } - - hba->dummy_buffer = dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, - &hba->dummy_buf_dma, GFP_KERNEL); - if (!hba->dummy_buffer) { - printk(KERN_ERR "unable to alloc Middle Path Dummy Buffer\n"); - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->mp_bd_tbl, hba->mp_bd_dma); - hba->mp_bd_tbl = NULL; - rc = -1; - goto out; - } - - mp_bdt = (struct iscsi_bd *) hba->mp_bd_tbl; - addr = (unsigned long) hba->dummy_buf_dma; - mp_bdt->buffer_addr_lo = addr & 0xffffffff; - mp_bdt->buffer_addr_hi = addr >> 32; - mp_bdt->buffer_length = PAGE_SIZE; - mp_bdt->flags = ISCSI_BD_LAST_IN_BD_CHAIN | - ISCSI_BD_FIRST_IN_BD_CHAIN; -out: - return rc; -} - - -/** - * bnx2i_free_mp_bdt - releases ITT back to free pool - * @hba: pointer to adapter instance - * - * free MP dummy buffer and associated BD table - */ -static void bnx2i_free_mp_bdt(struct bnx2i_hba *hba) -{ - if (hba->mp_bd_tbl) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->mp_bd_tbl, hba->mp_bd_dma); - hba->mp_bd_tbl = NULL; - } - if (hba->dummy_buffer) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - hba->dummy_buffer, hba->dummy_buf_dma); - hba->dummy_buffer = NULL; - } - return; -} - -/** - * bnx2i_drop_session - notifies iscsid of connection error. - * @hba: adapter instance pointer - * @session: iscsi session pointer - * - * This notifies iscsid that there is a error, so it can initiate - * recovery. - * - * This relies on caller using the iscsi class iterator so the object - * is refcounted and does not disapper from under us. - */ -void bnx2i_drop_session(struct iscsi_cls_session *cls_session) -{ - iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_CONN_FAILED); -} - -/** - * bnx2i_ep_destroy_list_add - add an entry to EP destroy list - * @hba: pointer to adapter instance - * @ep: pointer to endpoint (transport indentifier) structure - * - * EP destroy queue manager - */ -static int bnx2i_ep_destroy_list_add(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - write_lock_bh(&hba->ep_rdwr_lock); - list_add_tail(&ep->link, &hba->ep_destroy_list); - write_unlock_bh(&hba->ep_rdwr_lock); - return 0; -} - -/** - * bnx2i_ep_destroy_list_del - add an entry to EP destroy list - * - * @hba: pointer to adapter instance - * @ep: pointer to endpoint (transport indentifier) structure - * - * EP destroy queue manager - */ -static int bnx2i_ep_destroy_list_del(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - write_lock_bh(&hba->ep_rdwr_lock); - list_del_init(&ep->link); - write_unlock_bh(&hba->ep_rdwr_lock); - - return 0; -} - -/** - * bnx2i_ep_ofld_list_add - add an entry to ep offload pending list - * @hba: pointer to adapter instance - * @ep: pointer to endpoint (transport indentifier) structure - * - * pending conn offload completion queue manager - */ -static int bnx2i_ep_ofld_list_add(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - write_lock_bh(&hba->ep_rdwr_lock); - list_add_tail(&ep->link, &hba->ep_ofld_list); - write_unlock_bh(&hba->ep_rdwr_lock); - return 0; -} - -/** - * bnx2i_ep_ofld_list_del - add an entry to ep offload pending list - * @hba: pointer to adapter instance - * @ep: pointer to endpoint (transport indentifier) structure - * - * pending conn offload completion queue manager - */ -static int bnx2i_ep_ofld_list_del(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - write_lock_bh(&hba->ep_rdwr_lock); - list_del_init(&ep->link); - write_unlock_bh(&hba->ep_rdwr_lock); - return 0; -} - - -/** - * bnx2i_find_ep_in_ofld_list - find iscsi_cid in pending list of endpoints - * - * @hba: pointer to adapter instance - * @iscsi_cid: iscsi context ID to find - * - */ -struct bnx2i_endpoint * -bnx2i_find_ep_in_ofld_list(struct bnx2i_hba *hba, u32 iscsi_cid) -{ - struct list_head *list; - struct list_head *tmp; - struct bnx2i_endpoint *ep; - - read_lock_bh(&hba->ep_rdwr_lock); - list_for_each_safe(list, tmp, &hba->ep_ofld_list) { - ep = (struct bnx2i_endpoint *)list; - - if (ep->ep_iscsi_cid == iscsi_cid) - break; - ep = NULL; - } - read_unlock_bh(&hba->ep_rdwr_lock); - - if (!ep) - printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid); - return ep; -} - -/** - * bnx2i_find_ep_in_destroy_list - find iscsi_cid in destroy list - * @hba: pointer to adapter instance - * @iscsi_cid: iscsi context ID to find - * - */ -struct bnx2i_endpoint * -bnx2i_find_ep_in_destroy_list(struct bnx2i_hba *hba, u32 iscsi_cid) -{ - struct list_head *list; - struct list_head *tmp; - struct bnx2i_endpoint *ep; - - read_lock_bh(&hba->ep_rdwr_lock); - list_for_each_safe(list, tmp, &hba->ep_destroy_list) { - ep = (struct bnx2i_endpoint *)list; - - if (ep->ep_iscsi_cid == iscsi_cid) - break; - ep = NULL; - } - read_unlock_bh(&hba->ep_rdwr_lock); - - if (!ep) - printk(KERN_ERR "l5 cid %d not found\n", iscsi_cid); - - return ep; -} - -/** - * bnx2i_ep_active_list_add - add an entry to ep active list - * @hba: pointer to adapter instance - * @ep: pointer to endpoint (transport indentifier) structure - * - * current active conn queue manager - */ -static void bnx2i_ep_active_list_add(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - write_lock_bh(&hba->ep_rdwr_lock); - list_add_tail(&ep->link, &hba->ep_active_list); - write_unlock_bh(&hba->ep_rdwr_lock); -} - - -/** - * bnx2i_ep_active_list_del - deletes an entry to ep active list - * @hba: pointer to adapter instance - * @ep: pointer to endpoint (transport indentifier) structure - * - * current active conn queue manager - */ -static void bnx2i_ep_active_list_del(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - write_lock_bh(&hba->ep_rdwr_lock); - list_del_init(&ep->link); - write_unlock_bh(&hba->ep_rdwr_lock); -} - - -/** - * bnx2i_setup_host_queue_size - assigns shost->can_queue param - * @hba: pointer to adapter instance - * @shost: scsi host pointer - * - * Initializes 'can_queue' parameter based on how many outstanding commands - * the device can handle. Each device 5708/5709/57710 has different - * capabilities - */ -static void bnx2i_setup_host_queue_size(struct bnx2i_hba *hba, - struct Scsi_Host *shost) -{ - if (test_bit(BNX2I_NX2_DEV_5708, &hba->cnic_dev_type)) - shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708; - else if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) - shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5709; - else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) - shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_57710; - else - shost->can_queue = ISCSI_MAX_CMDS_PER_HBA_5708; -} - - -/** - * bnx2i_alloc_hba - allocate and init adapter instance - * @cnic: cnic device pointer - * - * allocate & initialize adapter structure and call other - * support routines to do per adapter initialization - */ -struct bnx2i_hba *bnx2i_alloc_hba(struct cnic_dev *cnic) -{ - struct Scsi_Host *shost; - struct bnx2i_hba *hba; - - shost = iscsi_host_alloc(&bnx2i_host_template, sizeof(*hba), 0); - if (!shost) - return NULL; - shost->dma_boundary = cnic->pcidev->dma_mask; - shost->transportt = bnx2i_scsi_xport_template; - shost->max_id = ISCSI_MAX_CONNS_PER_HBA; - shost->max_channel = 0; - shost->max_lun = 512; - shost->max_cmd_len = 16; - - hba = iscsi_host_priv(shost); - hba->shost = shost; - hba->netdev = cnic->netdev; - /* Get PCI related information and update hba struct members */ - hba->pcidev = cnic->pcidev; - pci_dev_get(hba->pcidev); - hba->pci_did = hba->pcidev->device; - hba->pci_vid = hba->pcidev->vendor; - hba->pci_sdid = hba->pcidev->subsystem_device; - hba->pci_svid = hba->pcidev->subsystem_vendor; - hba->pci_func = PCI_FUNC(hba->pcidev->devfn); - hba->pci_devno = PCI_SLOT(hba->pcidev->devfn); - - bnx2i_identify_device(hba); - bnx2i_setup_host_queue_size(hba, shost); - - if (test_bit(BNX2I_NX2_DEV_5709, &hba->cnic_dev_type)) { - hba->regview = ioremap_nocache(hba->netdev->base_addr, - BNX2_MQ_CONFIG2); - if (!hba->regview) - goto ioreg_map_err; - } else if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) { - hba->regview = ioremap_nocache(hba->netdev->base_addr, 4096); - if (!hba->regview) - goto ioreg_map_err; - } - - if (bnx2i_setup_mp_bdt(hba)) - goto mp_bdt_mem_err; - - INIT_LIST_HEAD(&hba->ep_ofld_list); - INIT_LIST_HEAD(&hba->ep_active_list); - INIT_LIST_HEAD(&hba->ep_destroy_list); - rwlock_init(&hba->ep_rdwr_lock); - - hba->mtu_supported = BNX2I_MAX_MTU_SUPPORTED; - - /* different values for 5708/5709/57710 */ - hba->max_active_conns = ISCSI_MAX_CONNS_PER_HBA; - - if (bnx2i_setup_free_cid_que(hba)) - goto cid_que_err; - - /* SQ/RQ/CQ size can be changed via sysfx interface */ - if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) { - if (sq_size && sq_size <= BNX2I_5770X_SQ_WQES_MAX) - hba->max_sqes = sq_size; - else - hba->max_sqes = BNX2I_5770X_SQ_WQES_DEFAULT; - } else { /* 5706/5708/5709 */ - if (sq_size && sq_size <= BNX2I_570X_SQ_WQES_MAX) - hba->max_sqes = sq_size; - else - hba->max_sqes = BNX2I_570X_SQ_WQES_DEFAULT; - } - - hba->max_rqes = rq_size; - hba->max_cqes = hba->max_sqes + rq_size; - if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) { - if (hba->max_cqes > BNX2I_5770X_CQ_WQES_MAX) - hba->max_cqes = BNX2I_5770X_CQ_WQES_MAX; - } else if (hba->max_cqes > BNX2I_570X_CQ_WQES_MAX) - hba->max_cqes = BNX2I_570X_CQ_WQES_MAX; - - hba->num_ccell = hba->max_sqes / 2; - - spin_lock_init(&hba->lock); - mutex_init(&hba->net_dev_lock); - init_waitqueue_head(&hba->eh_wait); - if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) { - hba->hba_shutdown_tmo = 30 * HZ; - hba->conn_teardown_tmo = 20 * HZ; - hba->conn_ctx_destroy_tmo = 6 * HZ; - } else { /* 5706/5708/5709 */ - hba->hba_shutdown_tmo = 20 * HZ; - hba->conn_teardown_tmo = 10 * HZ; - hba->conn_ctx_destroy_tmo = 2 * HZ; - } - - if (iscsi_host_add(shost, &hba->pcidev->dev)) - goto free_dump_mem; - return hba; - -free_dump_mem: - bnx2i_release_free_cid_que(hba); -cid_que_err: - bnx2i_free_mp_bdt(hba); -mp_bdt_mem_err: - if (hba->regview) { - iounmap(hba->regview); - hba->regview = NULL; - } -ioreg_map_err: - pci_dev_put(hba->pcidev); - scsi_host_put(shost); - return NULL; -} - -/** - * bnx2i_free_hba- releases hba structure and resources held by the adapter - * @hba: pointer to adapter instance - * - * free adapter structure and call various cleanup routines. - */ -void bnx2i_free_hba(struct bnx2i_hba *hba) -{ - struct Scsi_Host *shost = hba->shost; - - iscsi_host_remove(shost); - INIT_LIST_HEAD(&hba->ep_ofld_list); - INIT_LIST_HEAD(&hba->ep_active_list); - INIT_LIST_HEAD(&hba->ep_destroy_list); - pci_dev_put(hba->pcidev); - - if (hba->regview) { - iounmap(hba->regview); - hba->regview = NULL; - } - bnx2i_free_mp_bdt(hba); - bnx2i_release_free_cid_que(hba); - iscsi_host_free(shost); -} - -/** - * bnx2i_conn_free_login_resources - free DMA resources used for login process - * @hba: pointer to adapter instance - * @bnx2i_conn: iscsi connection pointer - * - * Login related resources, mostly BDT & payload DMA memory is freed - */ -static void bnx2i_conn_free_login_resources(struct bnx2i_hba *hba, - struct bnx2i_conn *bnx2i_conn) -{ - if (bnx2i_conn->gen_pdu.resp_bd_tbl) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - bnx2i_conn->gen_pdu.resp_bd_tbl, - bnx2i_conn->gen_pdu.resp_bd_dma); - bnx2i_conn->gen_pdu.resp_bd_tbl = NULL; - } - - if (bnx2i_conn->gen_pdu.req_bd_tbl) { - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - bnx2i_conn->gen_pdu.req_bd_tbl, - bnx2i_conn->gen_pdu.req_bd_dma); - bnx2i_conn->gen_pdu.req_bd_tbl = NULL; - } - - if (bnx2i_conn->gen_pdu.resp_buf) { - dma_free_coherent(&hba->pcidev->dev, - ISCSI_DEF_MAX_RECV_SEG_LEN, - bnx2i_conn->gen_pdu.resp_buf, - bnx2i_conn->gen_pdu.resp_dma_addr); - bnx2i_conn->gen_pdu.resp_buf = NULL; - } - - if (bnx2i_conn->gen_pdu.req_buf) { - dma_free_coherent(&hba->pcidev->dev, - ISCSI_DEF_MAX_RECV_SEG_LEN, - bnx2i_conn->gen_pdu.req_buf, - bnx2i_conn->gen_pdu.req_dma_addr); - bnx2i_conn->gen_pdu.req_buf = NULL; - } -} - -/** - * bnx2i_conn_alloc_login_resources - alloc DMA resources for login/nop. - * @hba: pointer to adapter instance - * @bnx2i_conn: iscsi connection pointer - * - * Mgmt task DNA resources are allocated in this routine. - */ -static int bnx2i_conn_alloc_login_resources(struct bnx2i_hba *hba, - struct bnx2i_conn *bnx2i_conn) -{ - /* Allocate memory for login request/response buffers */ - bnx2i_conn->gen_pdu.req_buf = - dma_alloc_coherent(&hba->pcidev->dev, - ISCSI_DEF_MAX_RECV_SEG_LEN, - &bnx2i_conn->gen_pdu.req_dma_addr, - GFP_KERNEL); - if (bnx2i_conn->gen_pdu.req_buf == NULL) - goto login_req_buf_failure; - - bnx2i_conn->gen_pdu.req_buf_size = 0; - bnx2i_conn->gen_pdu.req_wr_ptr = bnx2i_conn->gen_pdu.req_buf; - - bnx2i_conn->gen_pdu.resp_buf = - dma_alloc_coherent(&hba->pcidev->dev, - ISCSI_DEF_MAX_RECV_SEG_LEN, - &bnx2i_conn->gen_pdu.resp_dma_addr, - GFP_KERNEL); - if (bnx2i_conn->gen_pdu.resp_buf == NULL) - goto login_resp_buf_failure; - - bnx2i_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN; - bnx2i_conn->gen_pdu.resp_wr_ptr = bnx2i_conn->gen_pdu.resp_buf; - - bnx2i_conn->gen_pdu.req_bd_tbl = - dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, - &bnx2i_conn->gen_pdu.req_bd_dma, GFP_KERNEL); - if (bnx2i_conn->gen_pdu.req_bd_tbl == NULL) - goto login_req_bd_tbl_failure; - - bnx2i_conn->gen_pdu.resp_bd_tbl = - dma_alloc_coherent(&hba->pcidev->dev, PAGE_SIZE, - &bnx2i_conn->gen_pdu.resp_bd_dma, - GFP_KERNEL); - if (bnx2i_conn->gen_pdu.resp_bd_tbl == NULL) - goto login_resp_bd_tbl_failure; - - return 0; - -login_resp_bd_tbl_failure: - dma_free_coherent(&hba->pcidev->dev, PAGE_SIZE, - bnx2i_conn->gen_pdu.req_bd_tbl, - bnx2i_conn->gen_pdu.req_bd_dma); - bnx2i_conn->gen_pdu.req_bd_tbl = NULL; - -login_req_bd_tbl_failure: - dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN, - bnx2i_conn->gen_pdu.resp_buf, - bnx2i_conn->gen_pdu.resp_dma_addr); - bnx2i_conn->gen_pdu.resp_buf = NULL; -login_resp_buf_failure: - dma_free_coherent(&hba->pcidev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN, - bnx2i_conn->gen_pdu.req_buf, - bnx2i_conn->gen_pdu.req_dma_addr); - bnx2i_conn->gen_pdu.req_buf = NULL; -login_req_buf_failure: - iscsi_conn_printk(KERN_ERR, bnx2i_conn->cls_conn->dd_data, - "login resource alloc failed!!\n"); - return -ENOMEM; - -} - - -/** - * bnx2i_iscsi_prep_generic_pdu_bd - prepares BD table. - * @bnx2i_conn: iscsi connection pointer - * - * Allocates buffers and BD tables before shipping requests to cnic - * for PDUs prepared by 'iscsid' daemon - */ -static void bnx2i_iscsi_prep_generic_pdu_bd(struct bnx2i_conn *bnx2i_conn) -{ - struct iscsi_bd *bd_tbl; - - bd_tbl = (struct iscsi_bd *) bnx2i_conn->gen_pdu.req_bd_tbl; - - bd_tbl->buffer_addr_hi = - (u32) ((u64) bnx2i_conn->gen_pdu.req_dma_addr >> 32); - bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.req_dma_addr; - bd_tbl->buffer_length = bnx2i_conn->gen_pdu.req_wr_ptr - - bnx2i_conn->gen_pdu.req_buf; - bd_tbl->reserved0 = 0; - bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN | - ISCSI_BD_FIRST_IN_BD_CHAIN; - - bd_tbl = (struct iscsi_bd *) bnx2i_conn->gen_pdu.resp_bd_tbl; - bd_tbl->buffer_addr_hi = (u64) bnx2i_conn->gen_pdu.resp_dma_addr >> 32; - bd_tbl->buffer_addr_lo = (u32) bnx2i_conn->gen_pdu.resp_dma_addr; - bd_tbl->buffer_length = ISCSI_DEF_MAX_RECV_SEG_LEN; - bd_tbl->reserved0 = 0; - bd_tbl->flags = ISCSI_BD_LAST_IN_BD_CHAIN | - ISCSI_BD_FIRST_IN_BD_CHAIN; -} - - -/** - * bnx2i_iscsi_send_generic_request - called to send mgmt tasks. - * @task: transport layer task pointer - * - * called to transmit PDUs prepared by the 'iscsid' daemon. iSCSI login, - * Nop-out and Logout requests flow through this path. - */ -static int bnx2i_iscsi_send_generic_request(struct iscsi_task *task) -{ - struct bnx2i_cmd *cmd = task->dd_data; - struct bnx2i_conn *bnx2i_conn = cmd->conn; - int rc = 0; - char *buf; - int data_len; - - bnx2i_iscsi_prep_generic_pdu_bd(bnx2i_conn); - switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { - case ISCSI_OP_LOGIN: - bnx2i_send_iscsi_login(bnx2i_conn, task); - break; - case ISCSI_OP_NOOP_OUT: - data_len = bnx2i_conn->gen_pdu.req_buf_size; - buf = bnx2i_conn->gen_pdu.req_buf; - if (data_len) - rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task, - buf, data_len, 1); - else - rc = bnx2i_send_iscsi_nopout(bnx2i_conn, task, - NULL, 0, 1); - break; - case ISCSI_OP_LOGOUT: - rc = bnx2i_send_iscsi_logout(bnx2i_conn, task); - break; - case ISCSI_OP_SCSI_TMFUNC: - rc = bnx2i_send_iscsi_tmf(bnx2i_conn, task); - break; - case ISCSI_OP_TEXT: - rc = bnx2i_send_iscsi_text(bnx2i_conn, task); - break; - default: - iscsi_conn_printk(KERN_ALERT, bnx2i_conn->cls_conn->dd_data, - "send_gen: unsupported op 0x%x\n", - task->hdr->opcode); - } - return rc; -} - - -/********************************************************************** - * SCSI-ML Interface - **********************************************************************/ - -/** - * bnx2i_cpy_scsi_cdb - copies LUN & CDB fields in required format to sq wqe - * @sc: SCSI-ML command pointer - * @cmd: iscsi cmd pointer - */ -static void bnx2i_cpy_scsi_cdb(struct scsi_cmnd *sc, struct bnx2i_cmd *cmd) -{ - u32 dword; - int lpcnt; - u8 *srcp; - u32 *dstp; - u32 scsi_lun[2]; - - int_to_scsilun(sc->device->lun, (struct scsi_lun *) scsi_lun); - cmd->req.lun[0] = be32_to_cpu(scsi_lun[0]); - cmd->req.lun[1] = be32_to_cpu(scsi_lun[1]); - - lpcnt = cmd->scsi_cmd->cmd_len / sizeof(dword); - srcp = (u8 *) sc->cmnd; - dstp = (u32 *) cmd->req.cdb; - while (lpcnt--) { - memcpy(&dword, (const void *) srcp, 4); - *dstp = cpu_to_be32(dword); - srcp += 4; - dstp++; - } - if (sc->cmd_len & 0x3) { - dword = (u32) srcp[0] | ((u32) srcp[1] << 8); - *dstp = cpu_to_be32(dword); - } -} - -static void bnx2i_cleanup_task(struct iscsi_task *task) -{ - struct iscsi_conn *conn = task->conn; - struct bnx2i_conn *bnx2i_conn = conn->dd_data; - struct bnx2i_hba *hba = bnx2i_conn->hba; - - /* - * mgmt task or cmd was never sent to us to transmit. - */ - if (!task->sc || task->state == ISCSI_TASK_PENDING) - return; - /* - * need to clean-up task context to claim dma buffers - */ - if (task->state == ISCSI_TASK_ABRT_TMF) { - bnx2i_send_cmd_cleanup_req(hba, task->dd_data); - - spin_unlock_bh(&conn->session->lock); - wait_for_completion_timeout(&bnx2i_conn->cmd_cleanup_cmpl, - msecs_to_jiffies(ISCSI_CMD_CLEANUP_TIMEOUT)); - spin_lock_bh(&conn->session->lock); - } - bnx2i_iscsi_unmap_sg_list(task->dd_data); -} - -/** - * bnx2i_mtask_xmit - transmit mtask to chip for further processing - * @conn: transport layer conn structure pointer - * @task: transport layer command structure pointer - */ -static int -bnx2i_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) -{ - struct bnx2i_conn *bnx2i_conn = conn->dd_data; - struct bnx2i_cmd *cmd = task->dd_data; - - memset(bnx2i_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN); - - bnx2i_setup_cmd_wqe_template(cmd); - bnx2i_conn->gen_pdu.req_buf_size = task->data_count; - if (task->data_count) { - memcpy(bnx2i_conn->gen_pdu.req_buf, task->data, - task->data_count); - bnx2i_conn->gen_pdu.req_wr_ptr = - bnx2i_conn->gen_pdu.req_buf + task->data_count; - } - cmd->conn = conn->dd_data; - cmd->scsi_cmd = NULL; - return bnx2i_iscsi_send_generic_request(task); -} - -/** - * bnx2i_task_xmit - transmit iscsi command to chip for further processing - * @task: transport layer command structure pointer - * - * maps SG buffers and send request to chip/firmware in the form of SQ WQE - */ -static int bnx2i_task_xmit(struct iscsi_task *task) -{ - struct iscsi_conn *conn = task->conn; - struct iscsi_session *session = conn->session; - struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); - struct bnx2i_hba *hba = iscsi_host_priv(shost); - struct bnx2i_conn *bnx2i_conn = conn->dd_data; - struct scsi_cmnd *sc = task->sc; - struct bnx2i_cmd *cmd = task->dd_data; - struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr; - - if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1 > - hba->max_sqes) - return -ENOMEM; - - /* - * If there is no scsi_cmnd this must be a mgmt task - */ - if (!sc) - return bnx2i_mtask_xmit(conn, task); - - bnx2i_setup_cmd_wqe_template(cmd); - cmd->req.op_code = ISCSI_OP_SCSI_CMD; - cmd->conn = bnx2i_conn; - cmd->scsi_cmd = sc; - cmd->req.total_data_transfer_length = scsi_bufflen(sc); - cmd->req.cmd_sn = be32_to_cpu(hdr->cmdsn); - - bnx2i_iscsi_map_sg_list(cmd); - bnx2i_cpy_scsi_cdb(sc, cmd); - - cmd->req.op_attr = ISCSI_ATTR_SIMPLE; - if (sc->sc_data_direction == DMA_TO_DEVICE) { - cmd->req.op_attr |= ISCSI_CMD_REQUEST_WRITE; - cmd->req.itt = task->itt | - (ISCSI_TASK_TYPE_WRITE << ISCSI_CMD_REQUEST_TYPE_SHIFT); - bnx2i_setup_write_cmd_bd_info(task); - } else { - if (scsi_bufflen(sc)) - cmd->req.op_attr |= ISCSI_CMD_REQUEST_READ; - cmd->req.itt = task->itt | - (ISCSI_TASK_TYPE_READ << ISCSI_CMD_REQUEST_TYPE_SHIFT); - } - - cmd->req.num_bds = cmd->io_tbl.bd_valid; - if (!cmd->io_tbl.bd_valid) { - cmd->req.bd_list_addr_lo = (u32) hba->mp_bd_dma; - cmd->req.bd_list_addr_hi = (u32) ((u64) hba->mp_bd_dma >> 32); - cmd->req.num_bds = 1; - } - - bnx2i_send_iscsi_scsicmd(bnx2i_conn, cmd); - return 0; -} - -/** - * bnx2i_session_create - create a new iscsi session - * @cmds_max: max commands supported - * @qdepth: scsi queue depth to support - * @initial_cmdsn: initial iscsi CMDSN to be used for this session - * - * Creates a new iSCSI session instance on given device. - */ -static struct iscsi_cls_session * -bnx2i_session_create(struct iscsi_endpoint *ep, - uint16_t cmds_max, uint16_t qdepth, - uint32_t initial_cmdsn) -{ - struct Scsi_Host *shost; - struct iscsi_cls_session *cls_session; - struct bnx2i_hba *hba; - struct bnx2i_endpoint *bnx2i_ep; - - if (!ep) { - printk(KERN_ERR "bnx2i: missing ep.\n"); - return NULL; - } - - bnx2i_ep = ep->dd_data; - shost = bnx2i_ep->hba->shost; - hba = iscsi_host_priv(shost); - if (bnx2i_adapter_ready(hba)) - return NULL; - - /* - * user can override hw limit as long as it is within - * the min/max. - */ - if (cmds_max > hba->max_sqes) - cmds_max = hba->max_sqes; - else if (cmds_max < BNX2I_SQ_WQES_MIN) - cmds_max = BNX2I_SQ_WQES_MIN; - - cls_session = iscsi_session_setup(&bnx2i_iscsi_transport, shost, - cmds_max, 0, sizeof(struct bnx2i_cmd), - initial_cmdsn, ISCSI_MAX_TARGET); - if (!cls_session) - return NULL; - - if (bnx2i_setup_cmd_pool(hba, cls_session->dd_data)) - goto session_teardown; - return cls_session; - -session_teardown: - iscsi_session_teardown(cls_session); - return NULL; -} - - -/** - * bnx2i_session_destroy - destroys iscsi session - * @cls_session: pointer to iscsi cls session - * - * Destroys previously created iSCSI session instance and releases - * all resources held by it - */ -static void bnx2i_session_destroy(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *session = cls_session->dd_data; - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct bnx2i_hba *hba = iscsi_host_priv(shost); - - bnx2i_destroy_cmd_pool(hba, session); - iscsi_session_teardown(cls_session); -} - - -/** - * bnx2i_conn_create - create iscsi connection instance - * @cls_session: pointer to iscsi cls session - * @cid: iscsi cid as per rfc (not NX2's CID terminology) - * - * Creates a new iSCSI connection instance for a given session - */ -static struct iscsi_cls_conn * -bnx2i_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct bnx2i_hba *hba = iscsi_host_priv(shost); - struct bnx2i_conn *bnx2i_conn; - struct iscsi_cls_conn *cls_conn; - struct iscsi_conn *conn; - - cls_conn = iscsi_conn_setup(cls_session, sizeof(*bnx2i_conn), - cid); - if (!cls_conn) - return NULL; - conn = cls_conn->dd_data; - - bnx2i_conn = conn->dd_data; - bnx2i_conn->cls_conn = cls_conn; - bnx2i_conn->hba = hba; - - atomic_set(&bnx2i_conn->work_cnt, 0); - - /* 'ep' ptr will be assigned in bind() call */ - bnx2i_conn->ep = NULL; - init_completion(&bnx2i_conn->cmd_cleanup_cmpl); - - if (bnx2i_conn_alloc_login_resources(hba, bnx2i_conn)) { - iscsi_conn_printk(KERN_ALERT, conn, - "conn_new: login resc alloc failed!!\n"); - goto free_conn; - } - - return cls_conn; - -free_conn: - iscsi_conn_teardown(cls_conn); - return NULL; -} - -/** - * bnx2i_conn_bind - binds iscsi sess, conn and ep objects together - * @cls_session: pointer to iscsi cls session - * @cls_conn: pointer to iscsi cls conn - * @transport_fd: 64-bit EP handle - * @is_leading: leading connection on this session? - * - * Binds together iSCSI session instance, iSCSI connection instance - * and the TCP connection. This routine returns error code if - * TCP connection does not belong on the device iSCSI sess/conn - * is bound - */ -static int bnx2i_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, - uint64_t transport_fd, int is_leading) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct bnx2i_conn *bnx2i_conn = conn->dd_data; - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - struct bnx2i_hba *hba = iscsi_host_priv(shost); - struct bnx2i_endpoint *bnx2i_ep; - struct iscsi_endpoint *ep; - int ret_code; - - ep = iscsi_lookup_endpoint(transport_fd); - if (!ep) - return -EINVAL; - /* - * Forcefully terminate all in progress connection recovery at the - * earliest, either in bind(), send_pdu(LOGIN), or conn_start() - */ - if (bnx2i_adapter_ready(hba)) - return -EIO; - - bnx2i_ep = ep->dd_data; - if ((bnx2i_ep->state == EP_STATE_TCP_FIN_RCVD) || - (bnx2i_ep->state == EP_STATE_TCP_RST_RCVD)) - /* Peer disconnect via' FIN or RST */ - return -EINVAL; - - if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) - return -EINVAL; - - if (bnx2i_ep->hba != hba) { - /* Error - TCP connection does not belong to this device - */ - iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data, - "conn bind, ep=0x%p (%s) does not", - bnx2i_ep, bnx2i_ep->hba->netdev->name); - iscsi_conn_printk(KERN_ALERT, cls_conn->dd_data, - "belong to hba (%s)\n", - hba->netdev->name); - return -EEXIST; - } - bnx2i_ep->conn = bnx2i_conn; - bnx2i_conn->ep = bnx2i_ep; - bnx2i_conn->iscsi_conn_cid = bnx2i_ep->ep_iscsi_cid; - bnx2i_conn->fw_cid = bnx2i_ep->ep_cid; - - ret_code = bnx2i_bind_conn_to_iscsi_cid(hba, bnx2i_conn, - bnx2i_ep->ep_iscsi_cid); - - /* 5706/5708/5709 FW takes RQ as full when initiated, but for 57710 - * driver needs to explicitly replenish RQ index during setup. - */ - if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type)) - bnx2i_put_rq_buf(bnx2i_conn, 0); - - bnx2i_arm_cq_event_coalescing(bnx2i_conn->ep, CNIC_ARM_CQE); - return ret_code; -} - - -/** - * bnx2i_conn_destroy - destroy iscsi connection instance & release resources - * @cls_conn: pointer to iscsi cls conn - * - * Destroy an iSCSI connection instance and release memory resources held by - * this connection - */ -static void bnx2i_conn_destroy(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct bnx2i_conn *bnx2i_conn = conn->dd_data; - struct Scsi_Host *shost; - struct bnx2i_hba *hba; - struct bnx2i_work *work, *tmp; - unsigned cpu = 0; - struct bnx2i_percpu_s *p; - - shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); - hba = iscsi_host_priv(shost); - - bnx2i_conn_free_login_resources(hba, bnx2i_conn); - - if (atomic_read(&bnx2i_conn->work_cnt)) { - for_each_online_cpu(cpu) { - p = &per_cpu(bnx2i_percpu, cpu); - spin_lock_bh(&p->p_work_lock); - list_for_each_entry_safe(work, tmp, - &p->work_list, list) { - if (work->session == conn->session && - work->bnx2i_conn == bnx2i_conn) { - list_del_init(&work->list); - kfree(work); - if (!atomic_dec_and_test( - &bnx2i_conn->work_cnt)) - break; - } - } - spin_unlock_bh(&p->p_work_lock); - } - } - - iscsi_conn_teardown(cls_conn); -} - - -/** - * bnx2i_ep_get_param - return iscsi ep parameter to caller - * @ep: pointer to iscsi endpoint - * @param: parameter type identifier - * @buf: buffer pointer - * - * returns iSCSI ep parameters - */ -static int bnx2i_ep_get_param(struct iscsi_endpoint *ep, - enum iscsi_param param, char *buf) -{ - struct bnx2i_endpoint *bnx2i_ep = ep->dd_data; - struct bnx2i_hba *hba = bnx2i_ep->hba; - int len = -ENOTCONN; - - if (!hba) - return -ENOTCONN; - - switch (param) { - case ISCSI_PARAM_CONN_PORT: - mutex_lock(&hba->net_dev_lock); - if (bnx2i_ep->cm_sk) - len = sprintf(buf, "%hu\n", bnx2i_ep->cm_sk->dst_port); - mutex_unlock(&hba->net_dev_lock); - break; - case ISCSI_PARAM_CONN_ADDRESS: - mutex_lock(&hba->net_dev_lock); - if (bnx2i_ep->cm_sk) - len = sprintf(buf, "%pI4\n", &bnx2i_ep->cm_sk->dst_ip); - mutex_unlock(&hba->net_dev_lock); - break; - default: - return -ENOSYS; - } - - return len; -} - -/** - * bnx2i_host_get_param - returns host (adapter) related parameters - * @shost: scsi host pointer - * @param: parameter type identifier - * @buf: buffer pointer - */ -static int bnx2i_host_get_param(struct Scsi_Host *shost, - enum iscsi_host_param param, char *buf) -{ - struct bnx2i_hba *hba = iscsi_host_priv(shost); - int len = 0; - - switch (param) { - case ISCSI_HOST_PARAM_HWADDRESS: - len = sysfs_format_mac(buf, hba->cnic->mac_addr, 6); - break; - case ISCSI_HOST_PARAM_NETDEV_NAME: - len = sprintf(buf, "%s\n", hba->netdev->name); - break; - case ISCSI_HOST_PARAM_IPADDRESS: { - struct list_head *active_list = &hba->ep_active_list; - - read_lock_bh(&hba->ep_rdwr_lock); - if (!list_empty(&hba->ep_active_list)) { - struct bnx2i_endpoint *bnx2i_ep; - struct cnic_sock *csk; - - bnx2i_ep = list_first_entry(active_list, - struct bnx2i_endpoint, - link); - csk = bnx2i_ep->cm_sk; - if (test_bit(SK_F_IPV6, &csk->flags)) - len = sprintf(buf, "%pI6\n", csk->src_ip); - else - len = sprintf(buf, "%pI4\n", csk->src_ip); - } - read_unlock_bh(&hba->ep_rdwr_lock); - break; - } - default: - return iscsi_host_get_param(shost, param, buf); - } - return len; -} - -/** - * bnx2i_conn_start - completes iscsi connection migration to FFP - * @cls_conn: pointer to iscsi cls conn - * - * last call in FFP migration to handover iscsi conn to the driver - */ -static int bnx2i_conn_start(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct bnx2i_conn *bnx2i_conn = conn->dd_data; - - bnx2i_conn->ep->state = EP_STATE_ULP_UPDATE_START; - bnx2i_update_iscsi_conn(conn); - - /* - * this should normally not sleep for a long time so it should - * not disrupt the caller. - */ - bnx2i_conn->ep->ofld_timer.expires = 1 * HZ + jiffies; - bnx2i_conn->ep->ofld_timer.function = bnx2i_ep_ofld_timer; - bnx2i_conn->ep->ofld_timer.data = (unsigned long) bnx2i_conn->ep; - add_timer(&bnx2i_conn->ep->ofld_timer); - /* update iSCSI context for this conn, wait for CNIC to complete */ - wait_event_interruptible(bnx2i_conn->ep->ofld_wait, - bnx2i_conn->ep->state != EP_STATE_ULP_UPDATE_START); - - if (signal_pending(current)) - flush_signals(current); - del_timer_sync(&bnx2i_conn->ep->ofld_timer); - - iscsi_conn_start(cls_conn); - return 0; -} - - -/** - * bnx2i_conn_get_stats - returns iSCSI stats - * @cls_conn: pointer to iscsi cls conn - * @stats: pointer to iscsi statistic struct - */ -static void bnx2i_conn_get_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - - stats->txdata_octets = conn->txdata_octets; - stats->rxdata_octets = conn->rxdata_octets; - stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; - stats->dataout_pdus = conn->dataout_pdus_cnt; - stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; - stats->datain_pdus = conn->datain_pdus_cnt; - stats->r2t_pdus = conn->r2t_pdus_cnt; - stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; - stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->custom_length = 3; - strcpy(stats->custom[2].desc, "eh_abort_cnt"); - stats->custom[2].value = conn->eh_abort_cnt; - stats->digest_err = 0; - stats->timeout_err = 0; - stats->custom_length = 0; -} - - -/** - * bnx2i_check_route - checks if target IP route belongs to one of NX2 devices - * @dst_addr: target IP address - * - * check if route resolves to BNX2 device - */ -static struct bnx2i_hba *bnx2i_check_route(struct sockaddr *dst_addr) -{ - struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr; - struct bnx2i_hba *hba; - struct cnic_dev *cnic = NULL; - - hba = get_adapter_list_head(); - if (hba && hba->cnic) - cnic = hba->cnic->cm_select_dev(desti, CNIC_ULP_ISCSI); - if (!cnic) { - printk(KERN_ALERT "bnx2i: no route," - "can't connect using cnic\n"); - goto no_nx2_route; - } - hba = bnx2i_find_hba_for_cnic(cnic); - if (!hba) - goto no_nx2_route; - - if (bnx2i_adapter_ready(hba)) { - printk(KERN_ALERT "bnx2i: check route, hba not found\n"); - goto no_nx2_route; - } - if (hba->netdev->mtu > hba->mtu_supported) { - printk(KERN_ALERT "bnx2i: %s network i/f mtu is set to %d\n", - hba->netdev->name, hba->netdev->mtu); - printk(KERN_ALERT "bnx2i: iSCSI HBA can support mtu of %d\n", - hba->mtu_supported); - goto no_nx2_route; - } - return hba; -no_nx2_route: - return NULL; -} - - -/** - * bnx2i_tear_down_conn - tear down iscsi/tcp connection and free resources - * @hba: pointer to adapter instance - * @ep: endpoint (transport indentifier) structure - * - * destroys cm_sock structure and on chip iscsi context - */ -static int bnx2i_tear_down_conn(struct bnx2i_hba *hba, - struct bnx2i_endpoint *ep) -{ - if (test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic) && ep->cm_sk) - hba->cnic->cm_destroy(ep->cm_sk); - - if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type) && - ep->state == EP_STATE_DISCONN_TIMEDOUT) { - if (ep->conn && ep->conn->cls_conn && - ep->conn->cls_conn->dd_data) { - struct iscsi_conn *conn = ep->conn->cls_conn->dd_data; - - /* Must suspend all rx queue activity for this ep */ - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); - } - /* CONN_DISCONNECT timeout may or may not be an issue depending - * on what transcribed in TCP layer, different targets behave - * differently - */ - printk(KERN_ALERT "bnx2i (%s): - WARN - CONN_DISCON timed out, " - "please submit GRC Dump, NW/PCIe trace, " - "driver msgs to developers for analysis\n", - hba->netdev->name); - } - - ep->state = EP_STATE_CLEANUP_START; - init_timer(&ep->ofld_timer); - ep->ofld_timer.expires = hba->conn_ctx_destroy_tmo + jiffies; - ep->ofld_timer.function = bnx2i_ep_ofld_timer; - ep->ofld_timer.data = (unsigned long) ep; - add_timer(&ep->ofld_timer); - - bnx2i_ep_destroy_list_add(hba, ep); - - /* destroy iSCSI context, wait for it to complete */ - if (bnx2i_send_conn_destroy(hba, ep)) - ep->state = EP_STATE_CLEANUP_CMPL; - - wait_event_interruptible(ep->ofld_wait, - (ep->state != EP_STATE_CLEANUP_START)); - - if (signal_pending(current)) - flush_signals(current); - del_timer_sync(&ep->ofld_timer); - - bnx2i_ep_destroy_list_del(hba, ep); - - if (ep->state != EP_STATE_CLEANUP_CMPL) - /* should never happen */ - printk(KERN_ALERT "bnx2i - conn destroy failed\n"); - - return 0; -} - - -/** - * bnx2i_ep_connect - establish TCP connection to target portal - * @shost: scsi host - * @dst_addr: target IP address - * @non_blocking: blocking or non-blocking call - * - * this routine initiates the TCP/IP connection by invoking Option-2 i/f - * with l5_core and the CNIC. This is a multi-step process of resolving - * route to target, create a iscsi connection context, handshaking with - * CNIC module to create/initialize the socket struct and finally - * sending down option-2 request to complete TCP 3-way handshake - */ -static struct iscsi_endpoint *bnx2i_ep_connect(struct Scsi_Host *shost, - struct sockaddr *dst_addr, - int non_blocking) -{ - u32 iscsi_cid = BNX2I_CID_RESERVED; - struct sockaddr_in *desti = (struct sockaddr_in *) dst_addr; - struct sockaddr_in6 *desti6; - struct bnx2i_endpoint *bnx2i_ep; - struct bnx2i_hba *hba; - struct cnic_dev *cnic; - struct cnic_sockaddr saddr; - struct iscsi_endpoint *ep; - int rc = 0; - - if (shost) { - /* driver is given scsi host to work with */ - hba = iscsi_host_priv(shost); - } else - /* - * check if the given destination can be reached through - * a iscsi capable NetXtreme2 device - */ - hba = bnx2i_check_route(dst_addr); - - if (!hba) { - rc = -EINVAL; - goto nohba; - } - mutex_lock(&hba->net_dev_lock); - - if (bnx2i_adapter_ready(hba) || !hba->cid_que.cid_free_cnt) { - rc = -EPERM; - goto check_busy; - } - cnic = hba->cnic; - ep = bnx2i_alloc_ep(hba); - if (!ep) { - rc = -ENOMEM; - goto check_busy; - } - bnx2i_ep = ep->dd_data; - - atomic_set(&bnx2i_ep->num_active_cmds, 0); - iscsi_cid = bnx2i_alloc_iscsi_cid(hba); - if (iscsi_cid == -1) { - printk(KERN_ALERT "bnx2i (%s): alloc_ep - unable to allocate " - "iscsi cid\n", hba->netdev->name); - rc = -ENOMEM; - bnx2i_free_ep(ep); - goto check_busy; - } - bnx2i_ep->hba_age = hba->age; - - rc = bnx2i_alloc_qp_resc(hba, bnx2i_ep); - if (rc != 0) { - printk(KERN_ALERT "bnx2i (%s): ep_conn - alloc QP resc error" - "\n", hba->netdev->name); - rc = -ENOMEM; - goto qp_resc_err; - } - - bnx2i_ep->ep_iscsi_cid = (u16)iscsi_cid; - bnx2i_ep->state = EP_STATE_OFLD_START; - bnx2i_ep_ofld_list_add(hba, bnx2i_ep); - - init_timer(&bnx2i_ep->ofld_timer); - bnx2i_ep->ofld_timer.expires = 2 * HZ + jiffies; - bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer; - bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep; - add_timer(&bnx2i_ep->ofld_timer); - - if (bnx2i_send_conn_ofld_req(hba, bnx2i_ep)) { - if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) { - printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n", - hba->netdev->name, bnx2i_ep->ep_iscsi_cid); - rc = -EBUSY; - } else - rc = -ENOSPC; - printk(KERN_ALERT "bnx2i (%s): unable to send conn offld kwqe" - "\n", hba->netdev->name); - bnx2i_ep_ofld_list_del(hba, bnx2i_ep); - goto conn_failed; - } - - /* Wait for CNIC hardware to setup conn context and return 'cid' */ - wait_event_interruptible(bnx2i_ep->ofld_wait, - bnx2i_ep->state != EP_STATE_OFLD_START); - - if (signal_pending(current)) - flush_signals(current); - del_timer_sync(&bnx2i_ep->ofld_timer); - - bnx2i_ep_ofld_list_del(hba, bnx2i_ep); - - if (bnx2i_ep->state != EP_STATE_OFLD_COMPL) { - if (bnx2i_ep->state == EP_STATE_OFLD_FAILED_CID_BUSY) { - printk(KERN_ALERT "bnx2i (%s): iscsi cid %d is busy\n", - hba->netdev->name, bnx2i_ep->ep_iscsi_cid); - rc = -EBUSY; - } else - rc = -ENOSPC; - goto conn_failed; - } - - rc = cnic->cm_create(cnic, CNIC_ULP_ISCSI, bnx2i_ep->ep_cid, - iscsi_cid, &bnx2i_ep->cm_sk, bnx2i_ep); - if (rc) { - rc = -EINVAL; - /* Need to terminate and cleanup the connection */ - goto release_ep; - } - - bnx2i_ep->cm_sk->rcv_buf = 256 * 1024; - bnx2i_ep->cm_sk->snd_buf = 256 * 1024; - clear_bit(SK_TCP_TIMESTAMP, &bnx2i_ep->cm_sk->tcp_flags); - - memset(&saddr, 0, sizeof(saddr)); - if (dst_addr->sa_family == AF_INET) { - desti = (struct sockaddr_in *) dst_addr; - saddr.remote.v4 = *desti; - saddr.local.v4.sin_family = desti->sin_family; - } else if (dst_addr->sa_family == AF_INET6) { - desti6 = (struct sockaddr_in6 *) dst_addr; - saddr.remote.v6 = *desti6; - saddr.local.v6.sin6_family = desti6->sin6_family; - } - - bnx2i_ep->timestamp = jiffies; - bnx2i_ep->state = EP_STATE_CONNECT_START; - if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) { - rc = -EINVAL; - goto conn_failed; - } else - rc = cnic->cm_connect(bnx2i_ep->cm_sk, &saddr); - if (rc) - goto release_ep; - - bnx2i_ep_active_list_add(hba, bnx2i_ep); - - if (bnx2i_map_ep_dbell_regs(bnx2i_ep)) - goto del_active_ep; - - mutex_unlock(&hba->net_dev_lock); - return ep; - -del_active_ep: - bnx2i_ep_active_list_del(hba, bnx2i_ep); -release_ep: - if (bnx2i_tear_down_conn(hba, bnx2i_ep)) { - mutex_unlock(&hba->net_dev_lock); - return ERR_PTR(rc); - } -conn_failed: - bnx2i_free_qp_resc(hba, bnx2i_ep); -qp_resc_err: - bnx2i_free_ep(ep); -check_busy: - mutex_unlock(&hba->net_dev_lock); -nohba: - return ERR_PTR(rc); -} - - -/** - * bnx2i_ep_poll - polls for TCP connection establishement - * @ep: TCP connection (endpoint) handle - * @timeout_ms: timeout value in milli secs - * - * polls for TCP connect request to complete - */ -static int bnx2i_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) -{ - struct bnx2i_endpoint *bnx2i_ep; - int rc = 0; - - bnx2i_ep = ep->dd_data; - if ((bnx2i_ep->state == EP_STATE_IDLE) || - (bnx2i_ep->state == EP_STATE_CONNECT_FAILED) || - (bnx2i_ep->state == EP_STATE_OFLD_FAILED)) - return -1; - if (bnx2i_ep->state == EP_STATE_CONNECT_COMPL) - return 1; - - rc = wait_event_interruptible_timeout(bnx2i_ep->ofld_wait, - ((bnx2i_ep->state == - EP_STATE_OFLD_FAILED) || - (bnx2i_ep->state == - EP_STATE_CONNECT_FAILED) || - (bnx2i_ep->state == - EP_STATE_CONNECT_COMPL)), - msecs_to_jiffies(timeout_ms)); - if (bnx2i_ep->state == EP_STATE_OFLD_FAILED) - rc = -1; - - if (rc > 0) - return 1; - else if (!rc) - return 0; /* timeout */ - else - return rc; -} - - -/** - * bnx2i_ep_tcp_conn_active - check EP state transition - * @ep: endpoint pointer - * - * check if underlying TCP connection is active - */ -static int bnx2i_ep_tcp_conn_active(struct bnx2i_endpoint *bnx2i_ep) -{ - int ret; - int cnic_dev_10g = 0; - - if (test_bit(BNX2I_NX2_DEV_57710, &bnx2i_ep->hba->cnic_dev_type)) - cnic_dev_10g = 1; - - switch (bnx2i_ep->state) { - case EP_STATE_CLEANUP_FAILED: - case EP_STATE_OFLD_FAILED: - case EP_STATE_DISCONN_TIMEDOUT: - ret = 0; - break; - case EP_STATE_CONNECT_START: - case EP_STATE_CONNECT_FAILED: - case EP_STATE_CONNECT_COMPL: - case EP_STATE_ULP_UPDATE_START: - case EP_STATE_ULP_UPDATE_COMPL: - case EP_STATE_TCP_FIN_RCVD: - case EP_STATE_LOGOUT_SENT: - case EP_STATE_LOGOUT_RESP_RCVD: - case EP_STATE_ULP_UPDATE_FAILED: - ret = 1; - break; - case EP_STATE_TCP_RST_RCVD: - if (cnic_dev_10g) - ret = 0; - else - ret = 1; - break; - default: - ret = 0; - } - - return ret; -} - - -/* - * bnx2i_hw_ep_disconnect - executes TCP connection teardown process in the hw - * @ep: TCP connection (bnx2i endpoint) handle - * - * executes TCP connection teardown process - */ -int bnx2i_hw_ep_disconnect(struct bnx2i_endpoint *bnx2i_ep) -{ - struct bnx2i_hba *hba = bnx2i_ep->hba; - struct cnic_dev *cnic; - struct iscsi_session *session = NULL; - struct iscsi_conn *conn = NULL; - int ret = 0; - int close = 0; - int close_ret = 0; - - if (!hba) - return 0; - - cnic = hba->cnic; - if (!cnic) - return 0; - - if (bnx2i_ep->state == EP_STATE_IDLE || - bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) - return 0; - - if (!bnx2i_ep_tcp_conn_active(bnx2i_ep)) - goto destroy_conn; - - if (bnx2i_ep->conn) { - conn = bnx2i_ep->conn->cls_conn->dd_data; - session = conn->session; - } - - init_timer(&bnx2i_ep->ofld_timer); - bnx2i_ep->ofld_timer.expires = hba->conn_teardown_tmo + jiffies; - bnx2i_ep->ofld_timer.function = bnx2i_ep_ofld_timer; - bnx2i_ep->ofld_timer.data = (unsigned long) bnx2i_ep; - add_timer(&bnx2i_ep->ofld_timer); - - if (!test_bit(BNX2I_CNIC_REGISTERED, &hba->reg_with_cnic)) - goto out; - - if (session) { - spin_lock_bh(&session->lock); - if (bnx2i_ep->state != EP_STATE_TCP_FIN_RCVD) { - if (session->state == ISCSI_STATE_LOGGING_OUT) { - if (bnx2i_ep->state == EP_STATE_LOGOUT_SENT) { - /* Logout sent, but no resp */ - printk(KERN_ALERT "bnx2i (%s): WARNING" - " logout response was not " - "received!\n", - bnx2i_ep->hba->netdev->name); - } else if (bnx2i_ep->state == - EP_STATE_LOGOUT_RESP_RCVD) - close = 1; - } - } else - close = 1; - - spin_unlock_bh(&session->lock); - } - - bnx2i_ep->state = EP_STATE_DISCONN_START; - - if (close) - close_ret = cnic->cm_close(bnx2i_ep->cm_sk); - else - close_ret = cnic->cm_abort(bnx2i_ep->cm_sk); - - if (close_ret) - printk(KERN_ALERT "bnx2i (%s): close/abort(%d) returned %d\n", - bnx2i_ep->hba->netdev->name, close, close_ret); - else - /* wait for option-2 conn teardown */ - wait_event_interruptible(bnx2i_ep->ofld_wait, - bnx2i_ep->state != EP_STATE_DISCONN_START); - - if (signal_pending(current)) - flush_signals(current); - del_timer_sync(&bnx2i_ep->ofld_timer); - -destroy_conn: - bnx2i_ep_active_list_del(hba, bnx2i_ep); - if (bnx2i_tear_down_conn(hba, bnx2i_ep)) - return -EINVAL; -out: - bnx2i_ep->state = EP_STATE_IDLE; - return ret; -} - - -/** - * bnx2i_ep_disconnect - executes TCP connection teardown process - * @ep: TCP connection (iscsi endpoint) handle - * - * executes TCP connection teardown process - */ -static void bnx2i_ep_disconnect(struct iscsi_endpoint *ep) -{ - struct bnx2i_endpoint *bnx2i_ep; - struct bnx2i_conn *bnx2i_conn = NULL; - struct iscsi_conn *conn = NULL; - struct bnx2i_hba *hba; - - bnx2i_ep = ep->dd_data; - - /* driver should not attempt connection cleanup until TCP_CONNECT - * completes either successfully or fails. Timeout is 9-secs, so - * wait for it to complete - */ - while ((bnx2i_ep->state == EP_STATE_CONNECT_START) && - !time_after(jiffies, bnx2i_ep->timestamp + (12 * HZ))) - msleep(250); - - if (bnx2i_ep->conn) { - bnx2i_conn = bnx2i_ep->conn; - conn = bnx2i_conn->cls_conn->dd_data; - iscsi_suspend_queue(conn); - } - hba = bnx2i_ep->hba; - - mutex_lock(&hba->net_dev_lock); - - if (bnx2i_ep->state == EP_STATE_DISCONN_TIMEDOUT) - goto out; - - if (bnx2i_ep->state == EP_STATE_IDLE) - goto free_resc; - - if (!test_bit(ADAPTER_STATE_UP, &hba->adapter_state) || - (bnx2i_ep->hba_age != hba->age)) { - bnx2i_ep_active_list_del(hba, bnx2i_ep); - goto free_resc; - } - - /* Do all chip cleanup here */ - if (bnx2i_hw_ep_disconnect(bnx2i_ep)) { - mutex_unlock(&hba->net_dev_lock); - return; - } -free_resc: - bnx2i_free_qp_resc(hba, bnx2i_ep); - - if (bnx2i_conn) - bnx2i_conn->ep = NULL; - - bnx2i_free_ep(ep); -out: - mutex_unlock(&hba->net_dev_lock); - - wake_up_interruptible(&hba->eh_wait); -} - - -/** - * bnx2i_nl_set_path - ISCSI_UEVENT_PATH_UPDATE user message handler - * @buf: pointer to buffer containing iscsi path message - * - */ -static int bnx2i_nl_set_path(struct Scsi_Host *shost, struct iscsi_path *params) -{ - struct bnx2i_hba *hba = iscsi_host_priv(shost); - char *buf = (char *) params; - u16 len = sizeof(*params); - - /* handled by cnic driver */ - hba->cnic->iscsi_nl_msg_recv(hba->cnic, ISCSI_UEVENT_PATH_UPDATE, buf, - len); - - return 0; -} - -static umode_t bnx2i_attr_is_visible(int param_type, int param) -{ - switch (param_type) { - case ISCSI_HOST_PARAM: - switch (param) { - case ISCSI_HOST_PARAM_NETDEV_NAME: - case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_IPADDRESS: - return S_IRUGO; - default: - return 0; - } - case ISCSI_PARAM: - switch (param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - case ISCSI_PARAM_HDRDGST_EN: - case ISCSI_PARAM_DATADGST_EN: - case ISCSI_PARAM_CONN_ADDRESS: - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_EXP_STATSN: - case ISCSI_PARAM_PERSISTENT_ADDRESS: - case ISCSI_PARAM_PERSISTENT_PORT: - case ISCSI_PARAM_PING_TMO: - case ISCSI_PARAM_RECV_TMO: - case ISCSI_PARAM_INITIAL_R2T_EN: - case ISCSI_PARAM_MAX_R2T: - case ISCSI_PARAM_IMM_DATA_EN: - case ISCSI_PARAM_FIRST_BURST: - case ISCSI_PARAM_MAX_BURST: - case ISCSI_PARAM_PDU_INORDER_EN: - case ISCSI_PARAM_DATASEQ_INORDER_EN: - case ISCSI_PARAM_ERL: - case ISCSI_PARAM_TARGET_NAME: - case ISCSI_PARAM_TPGT: - case ISCSI_PARAM_USERNAME: - case ISCSI_PARAM_PASSWORD: - case ISCSI_PARAM_USERNAME_IN: - case ISCSI_PARAM_PASSWORD_IN: - case ISCSI_PARAM_FAST_ABORT: - case ISCSI_PARAM_ABORT_TMO: - case ISCSI_PARAM_LU_RESET_TMO: - case ISCSI_PARAM_TGT_RESET_TMO: - case ISCSI_PARAM_IFACE_NAME: - case ISCSI_PARAM_INITIATOR_NAME: - return S_IRUGO; - default: - return 0; - } - } - - return 0; -} - -/* - * 'Scsi_Host_Template' structure and 'iscsi_tranport' structure template - * used while registering with the scsi host and iSCSI transport module. - */ -static struct scsi_host_template bnx2i_host_template = { - .module = THIS_MODULE, - .name = "Broadcom Offload iSCSI Initiator", - .proc_name = "bnx2i", - .queuecommand = iscsi_queuecommand, - .eh_abort_handler = iscsi_eh_abort, - .eh_device_reset_handler = iscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_recover_target, - .change_queue_depth = iscsi_change_queue_depth, - .can_queue = 2048, - .max_sectors = 127, - .cmd_per_lun = 128, - .this_id = -1, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = ISCSI_MAX_BDS_PER_CMD, - .shost_attrs = bnx2i_dev_attributes, -}; - -struct iscsi_transport bnx2i_iscsi_transport = { - .owner = THIS_MODULE, - .name = "bnx2i", - .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | - CAP_MULTI_R2T | CAP_DATADGST | - CAP_DATA_PATH_OFFLOAD | - CAP_TEXT_NEGO, - .create_session = bnx2i_session_create, - .destroy_session = bnx2i_session_destroy, - .create_conn = bnx2i_conn_create, - .bind_conn = bnx2i_conn_bind, - .destroy_conn = bnx2i_conn_destroy, - .attr_is_visible = bnx2i_attr_is_visible, - .set_param = iscsi_set_param, - .get_conn_param = iscsi_conn_get_param, - .get_session_param = iscsi_session_get_param, - .get_host_param = bnx2i_host_get_param, - .start_conn = bnx2i_conn_start, - .stop_conn = iscsi_conn_stop, - .send_pdu = iscsi_conn_send_pdu, - .xmit_task = bnx2i_task_xmit, - .get_stats = bnx2i_conn_get_stats, - /* TCP connect - disconnect - option-2 interface calls */ - .get_ep_param = bnx2i_ep_get_param, - .ep_connect = bnx2i_ep_connect, - .ep_poll = bnx2i_ep_poll, - .ep_disconnect = bnx2i_ep_disconnect, - .set_path = bnx2i_nl_set_path, - /* Error recovery timeout call */ - .session_recovery_timedout = iscsi_session_recovery_timedout, - .cleanup_task = bnx2i_cleanup_task, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_sysfs.c b/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_sysfs.c deleted file mode 100644 index 83a77f72..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bnx2i/bnx2i_sysfs.c +++ /dev/null @@ -1,143 +0,0 @@ -/* bnx2i_sysfs.c: Broadcom NetXtreme II iSCSI driver. - * - * Copyright (c) 2004 - 2011 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Anil Veerabhadrappa (anilgv@broadcom.com) - * Maintained by: Eddie Wai (eddie.wai@broadcom.com) - */ - -#include "bnx2i.h" - -/** - * bnx2i_dev_to_hba - maps dev pointer to adapter struct - * @dev: device pointer - * - * Map device to hba structure - */ -static inline struct bnx2i_hba *bnx2i_dev_to_hba(struct device *dev) -{ - struct Scsi_Host *shost = class_to_shost(dev); - return iscsi_host_priv(shost); -} - - -/** - * bnx2i_show_sq_info - return(s currently configured send queue (SQ) size - * @dev: device pointer - * @buf: buffer to return current SQ size parameter - * - * Returns current SQ size parameter, this paramater determines the number - * outstanding iSCSI commands supported on a connection - */ -static ssize_t bnx2i_show_sq_info(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev); - - return sprintf(buf, "0x%x\n", hba->max_sqes); -} - - -/** - * bnx2i_set_sq_info - update send queue (SQ) size parameter - * @dev: device pointer - * @buf: buffer to return current SQ size parameter - * @count: parameter buffer size - * - * Interface for user to change shared queue size allocated for each conn - * Must be within SQ limits and a power of 2. For the latter this is needed - * because of how libiscsi preallocates tasks. - */ -static ssize_t bnx2i_set_sq_info(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev); - u32 val; - int max_sq_size; - - if (hba->ofld_conns_active) - goto skip_config; - - if (test_bit(BNX2I_NX2_DEV_57710, &hba->cnic_dev_type)) - max_sq_size = BNX2I_5770X_SQ_WQES_MAX; - else - max_sq_size = BNX2I_570X_SQ_WQES_MAX; - - if (sscanf(buf, " 0x%x ", &val) > 0) { - if ((val >= BNX2I_SQ_WQES_MIN) && (val <= max_sq_size) && - (is_power_of_2(val))) - hba->max_sqes = val; - } - - return count; - -skip_config: - printk(KERN_ERR "bnx2i: device busy, cannot change SQ size\n"); - return 0; -} - - -/** - * bnx2i_show_ccell_info - returns command cell (HQ) size - * @dev: device pointer - * @buf: buffer to return current SQ size parameter - * - * returns per-connection TCP history queue size parameter - */ -static ssize_t bnx2i_show_ccell_info(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev); - - return sprintf(buf, "0x%x\n", hba->num_ccell); -} - - -/** - * bnx2i_get_link_state - set command cell (HQ) size - * @dev: device pointer - * @buf: buffer to return current SQ size parameter - * @count: parameter buffer size - * - * updates per-connection TCP history queue size parameter - */ -static ssize_t bnx2i_set_ccell_info(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - u32 val; - struct bnx2i_hba *hba = bnx2i_dev_to_hba(dev); - - if (hba->ofld_conns_active) - goto skip_config; - - if (sscanf(buf, " 0x%x ", &val) > 0) { - if ((val >= BNX2I_CCELLS_MIN) && - (val <= BNX2I_CCELLS_MAX)) { - hba->num_ccell = val; - } - } - - return count; - -skip_config: - printk(KERN_ERR "bnx2i: device busy, cannot change CCELL size\n"); - return 0; -} - - -static DEVICE_ATTR(sq_size, S_IRUGO | S_IWUSR, - bnx2i_show_sq_info, bnx2i_set_sq_info); -static DEVICE_ATTR(num_ccell, S_IRUGO | S_IWUSR, - bnx2i_show_ccell_info, bnx2i_set_ccell_info); - -struct device_attribute *bnx2i_dev_attributes[] = { - &dev_attr_sq_size, - &dev_attr_num_ccell, - NULL -}; diff --git a/ANDROID_3.4.5/drivers/scsi/bvme6000_scsi.c b/ANDROID_3.4.5/drivers/scsi/bvme6000_scsi.c deleted file mode 100644 index d40ea2f5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/bvme6000_scsi.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux. - * - * Based on work by Alan Hourihane and Kars de Jong - * - * Rewritten to use 53c700.c by Richard Hirst - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "53c700.h" - -MODULE_AUTHOR("Richard Hirst "); -MODULE_DESCRIPTION("BVME6000 NCR53C710 driver"); -MODULE_LICENSE("GPL"); - -static struct scsi_host_template bvme6000_scsi_driver_template = { - .name = "BVME6000 NCR53c710 SCSI", - .proc_name = "BVME6000", - .this_id = 7, - .module = THIS_MODULE, -}; - -static struct platform_device *bvme6000_scsi_device; - -static __devinit int -bvme6000_probe(struct platform_device *dev) -{ - struct Scsi_Host *host; - struct NCR_700_Host_Parameters *hostdata; - - if (!MACH_IS_BVME6000) - goto out; - - hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); - if (!hostdata) { - printk(KERN_ERR "bvme6000-scsi: " - "Failed to allocate host data\n"); - goto out; - } - - /* Fill in the required pieces of hostdata */ - hostdata->base = (void __iomem *)BVME_NCR53C710_BASE; - hostdata->clock = 40; /* XXX - depends on the CPU clock! */ - hostdata->chip710 = 1; - hostdata->dmode_extra = DMODE_FC2; - hostdata->dcntl_extra = EA_710; - hostdata->ctest7_extra = CTEST7_TT1; - - /* and register the chip */ - host = NCR_700_detect(&bvme6000_scsi_driver_template, hostdata, - &dev->dev); - if (!host) { - printk(KERN_ERR "bvme6000-scsi: No host detected; " - "board configuration problem?\n"); - goto out_free; - } - host->base = BVME_NCR53C710_BASE; - host->this_id = 7; - host->irq = BVME_IRQ_SCSI; - if (request_irq(BVME_IRQ_SCSI, NCR_700_intr, 0, "bvme6000-scsi", - host)) { - printk(KERN_ERR "bvme6000-scsi: request_irq failed\n"); - goto out_put_host; - } - - platform_set_drvdata(dev, host); - scsi_scan_host(host); - - return 0; - - out_put_host: - scsi_host_put(host); - out_free: - kfree(hostdata); - out: - return -ENODEV; -} - -static __devexit int -bvme6000_device_remove(struct platform_device *dev) -{ - struct Scsi_Host *host = platform_get_drvdata(dev); - struct NCR_700_Host_Parameters *hostdata = shost_priv(host); - - scsi_remove_host(host); - NCR_700_release(host); - kfree(hostdata); - free_irq(host->irq, host); - - return 0; -} - -static struct platform_driver bvme6000_scsi_driver = { - .driver = { - .name = "bvme6000-scsi", - .owner = THIS_MODULE, - }, - .probe = bvme6000_probe, - .remove = __devexit_p(bvme6000_device_remove), -}; - -static int __init bvme6000_scsi_init(void) -{ - int err; - - err = platform_driver_register(&bvme6000_scsi_driver); - if (err) - return err; - - bvme6000_scsi_device = platform_device_register_simple("bvme6000-scsi", - -1, NULL, 0); - if (IS_ERR(bvme6000_scsi_device)) { - platform_driver_unregister(&bvme6000_scsi_driver); - return PTR_ERR(bvme6000_scsi_device); - } - - return 0; -} - -static void __exit bvme6000_scsi_exit(void) -{ - platform_device_unregister(bvme6000_scsi_device); - platform_driver_unregister(&bvme6000_scsi_driver); -} - -module_init(bvme6000_scsi_init); -module_exit(bvme6000_scsi_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/ch.c b/ANDROID_3.4.5/drivers/scsi/ch.c deleted file mode 100644 index a15474ee..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ch.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * SCSI Media Changer device driver for Linux 2.6 - * - * (c) 1996-2003 Gerd Knorr - * - */ - -#define VERSION "0.25" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* here are all the ioctls */ -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define CH_DT_MAX 16 -#define CH_TYPES 8 -#define CH_MAX_DEVS 128 - -MODULE_DESCRIPTION("device driver for scsi media changer devices"); -MODULE_AUTHOR("Gerd Knorr "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_MEDIUM_CHANGER); - -static DEFINE_MUTEX(ch_mutex); -static int init = 1; -module_param(init, int, 0444); -MODULE_PARM_DESC(init, \ - "initialize element status on driver load (default: on)"); - -static int timeout_move = 300; -module_param(timeout_move, int, 0644); -MODULE_PARM_DESC(timeout_move,"timeout for move commands " - "(default: 300 seconds)"); - -static int timeout_init = 3600; -module_param(timeout_init, int, 0644); -MODULE_PARM_DESC(timeout_init,"timeout for INITIALIZE ELEMENT STATUS " - "(default: 3600 seconds)"); - -static int verbose = 1; -module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose,"be verbose (default: on)"); - -static int debug = 0; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable/disable debug messages, also prints more " - "detailed sense codes on scsi errors (default: off)"); - -static int dt_id[CH_DT_MAX] = { [ 0 ... (CH_DT_MAX-1) ] = -1 }; -static int dt_lun[CH_DT_MAX]; -module_param_array(dt_id, int, NULL, 0444); -module_param_array(dt_lun, int, NULL, 0444); - -/* tell the driver about vendor-specific slots */ -static int vendor_firsts[CH_TYPES-4]; -static int vendor_counts[CH_TYPES-4]; -module_param_array(vendor_firsts, int, NULL, 0444); -module_param_array(vendor_counts, int, NULL, 0444); - -static const char * vendor_labels[CH_TYPES-4] = { - "v0", "v1", "v2", "v3" -}; -// module_param_string_array(vendor_labels, NULL, 0444); - -#define DPRINTK(fmt, arg...) \ -do { \ - if (debug) \ - printk(KERN_DEBUG "%s: " fmt, ch->name, ##arg); \ -} while (0) -#define VPRINTK(level, fmt, arg...) \ -do { \ - if (verbose) \ - printk(level "%s: " fmt, ch->name, ##arg); \ -} while (0) - -/* ------------------------------------------------------------------- */ - -#define MAX_RETRIES 1 - -static struct class * ch_sysfs_class; - -typedef struct { - struct list_head list; - int minor; - char name[8]; - struct scsi_device *device; - struct scsi_device **dt; /* ptrs to data transfer elements */ - u_int firsts[CH_TYPES]; - u_int counts[CH_TYPES]; - u_int unit_attention; - u_int voltags; - struct mutex lock; -} scsi_changer; - -static DEFINE_IDR(ch_index_idr); -static DEFINE_SPINLOCK(ch_index_lock); - -static const struct { - unsigned char sense; - unsigned char asc; - unsigned char ascq; - int errno; -} ch_err[] = { -/* Just filled in what looks right. Hav'nt checked any standard paper for - these errno assignments, so they may be wrong... */ - { - .sense = ILLEGAL_REQUEST, - .asc = 0x21, - .ascq = 0x01, - .errno = EBADSLT, /* Invalid element address */ - },{ - .sense = ILLEGAL_REQUEST, - .asc = 0x28, - .ascq = 0x01, - .errno = EBADE, /* Import or export element accessed */ - },{ - .sense = ILLEGAL_REQUEST, - .asc = 0x3B, - .ascq = 0x0D, - .errno = EXFULL, /* Medium destination element full */ - },{ - .sense = ILLEGAL_REQUEST, - .asc = 0x3B, - .ascq = 0x0E, - .errno = EBADE, /* Medium source element empty */ - },{ - .sense = ILLEGAL_REQUEST, - .asc = 0x20, - .ascq = 0x00, - .errno = EBADRQC, /* Invalid command operation code */ - },{ - /* end of list */ - } -}; - -/* ------------------------------------------------------------------- */ - -static int ch_find_errno(struct scsi_sense_hdr *sshdr) -{ - int i,errno = 0; - - /* Check to see if additional sense information is available */ - if (scsi_sense_valid(sshdr) && - sshdr->asc != 0) { - for (i = 0; ch_err[i].errno != 0; i++) { - if (ch_err[i].sense == sshdr->sense_key && - ch_err[i].asc == sshdr->asc && - ch_err[i].ascq == sshdr->ascq) { - errno = -ch_err[i].errno; - break; - } - } - } - if (errno == 0) - errno = -EIO; - return errno; -} - -static int -ch_do_scsi(scsi_changer *ch, unsigned char *cmd, - void *buffer, unsigned buflength, - enum dma_data_direction direction) -{ - int errno, retries = 0, timeout, result; - struct scsi_sense_hdr sshdr; - - timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) - ? timeout_init : timeout_move; - - retry: - errno = 0; - if (debug) { - DPRINTK("command: "); - __scsi_print_command(cmd); - } - - result = scsi_execute_req(ch->device, cmd, direction, buffer, - buflength, &sshdr, timeout * HZ, - MAX_RETRIES, NULL); - - DPRINTK("result: 0x%x\n",result); - if (driver_byte(result) & DRIVER_SENSE) { - if (debug) - scsi_print_sense_hdr(ch->name, &sshdr); - errno = ch_find_errno(&sshdr); - - switch(sshdr.sense_key) { - case UNIT_ATTENTION: - ch->unit_attention = 1; - if (retries++ < 3) - goto retry; - break; - } - } - return errno; -} - -/* ------------------------------------------------------------------------ */ - -static int -ch_elem_to_typecode(scsi_changer *ch, u_int elem) -{ - int i; - - for (i = 0; i < CH_TYPES; i++) { - if (elem >= ch->firsts[i] && - elem < ch->firsts[i] + - ch->counts[i]) - return i+1; - } - return 0; -} - -static int -ch_read_element_status(scsi_changer *ch, u_int elem, char *data) -{ - u_char cmd[12]; - u_char *buffer; - int result; - - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); - if(!buffer) - return -ENOMEM; - - retry: - memset(cmd,0,sizeof(cmd)); - cmd[0] = READ_ELEMENT_STATUS; - cmd[1] = (ch->device->lun << 5) | - (ch->voltags ? 0x10 : 0) | - ch_elem_to_typecode(ch,elem); - cmd[2] = (elem >> 8) & 0xff; - cmd[3] = elem & 0xff; - cmd[5] = 1; - cmd[9] = 255; - if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) { - if (((buffer[16] << 8) | buffer[17]) != elem) { - DPRINTK("asked for element 0x%02x, got 0x%02x\n", - elem,(buffer[16] << 8) | buffer[17]); - kfree(buffer); - return -EIO; - } - memcpy(data,buffer+16,16); - } else { - if (ch->voltags) { - ch->voltags = 0; - VPRINTK(KERN_INFO, "device has no volume tag support\n"); - goto retry; - } - DPRINTK("READ ELEMENT STATUS for element 0x%x failed\n",elem); - } - kfree(buffer); - return result; -} - -static int -ch_init_elem(scsi_changer *ch) -{ - int err; - u_char cmd[6]; - - VPRINTK(KERN_INFO, "INITIALIZE ELEMENT STATUS, may take some time ...\n"); - memset(cmd,0,sizeof(cmd)); - cmd[0] = INITIALIZE_ELEMENT_STATUS; - cmd[1] = ch->device->lun << 5; - err = ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE); - VPRINTK(KERN_INFO, "... finished\n"); - return err; -} - -static int -ch_readconfig(scsi_changer *ch) -{ - u_char cmd[10], data[16]; - u_char *buffer; - int result,id,lun,i; - u_int elem; - - buffer = kzalloc(512, GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - - memset(cmd,0,sizeof(cmd)); - cmd[0] = MODE_SENSE; - cmd[1] = ch->device->lun << 5; - cmd[2] = 0x1d; - cmd[4] = 255; - result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE); - if (0 != result) { - cmd[1] |= (1<<3); - result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE); - } - if (0 == result) { - ch->firsts[CHET_MT] = - (buffer[buffer[3]+ 6] << 8) | buffer[buffer[3]+ 7]; - ch->counts[CHET_MT] = - (buffer[buffer[3]+ 8] << 8) | buffer[buffer[3]+ 9]; - ch->firsts[CHET_ST] = - (buffer[buffer[3]+10] << 8) | buffer[buffer[3]+11]; - ch->counts[CHET_ST] = - (buffer[buffer[3]+12] << 8) | buffer[buffer[3]+13]; - ch->firsts[CHET_IE] = - (buffer[buffer[3]+14] << 8) | buffer[buffer[3]+15]; - ch->counts[CHET_IE] = - (buffer[buffer[3]+16] << 8) | buffer[buffer[3]+17]; - ch->firsts[CHET_DT] = - (buffer[buffer[3]+18] << 8) | buffer[buffer[3]+19]; - ch->counts[CHET_DT] = - (buffer[buffer[3]+20] << 8) | buffer[buffer[3]+21]; - VPRINTK(KERN_INFO, "type #1 (mt): 0x%x+%d [medium transport]\n", - ch->firsts[CHET_MT], - ch->counts[CHET_MT]); - VPRINTK(KERN_INFO, "type #2 (st): 0x%x+%d [storage]\n", - ch->firsts[CHET_ST], - ch->counts[CHET_ST]); - VPRINTK(KERN_INFO, "type #3 (ie): 0x%x+%d [import/export]\n", - ch->firsts[CHET_IE], - ch->counts[CHET_IE]); - VPRINTK(KERN_INFO, "type #4 (dt): 0x%x+%d [data transfer]\n", - ch->firsts[CHET_DT], - ch->counts[CHET_DT]); - } else { - VPRINTK(KERN_INFO, "reading element address assigment page failed!\n"); - } - - /* vendor specific element types */ - for (i = 0; i < 4; i++) { - if (0 == vendor_counts[i]) - continue; - if (NULL == vendor_labels[i]) - continue; - ch->firsts[CHET_V1+i] = vendor_firsts[i]; - ch->counts[CHET_V1+i] = vendor_counts[i]; - VPRINTK(KERN_INFO, "type #%d (v%d): 0x%x+%d [%s, vendor specific]\n", - i+5,i+1,vendor_firsts[i],vendor_counts[i], - vendor_labels[i]); - } - - /* look up the devices of the data transfer elements */ - ch->dt = kcalloc(ch->counts[CHET_DT], sizeof(*ch->dt), - GFP_KERNEL); - - if (!ch->dt) { - kfree(buffer); - return -ENOMEM; - } - - for (elem = 0; elem < ch->counts[CHET_DT]; elem++) { - id = -1; - lun = 0; - if (elem < CH_DT_MAX && -1 != dt_id[elem]) { - id = dt_id[elem]; - lun = dt_lun[elem]; - VPRINTK(KERN_INFO, "dt 0x%x: [insmod option] ", - elem+ch->firsts[CHET_DT]); - } else if (0 != ch_read_element_status - (ch,elem+ch->firsts[CHET_DT],data)) { - VPRINTK(KERN_INFO, "dt 0x%x: READ ELEMENT STATUS failed\n", - elem+ch->firsts[CHET_DT]); - } else { - VPRINTK(KERN_INFO, "dt 0x%x: ",elem+ch->firsts[CHET_DT]); - if (data[6] & 0x80) { - VPRINTK(KERN_CONT, "not this SCSI bus\n"); - ch->dt[elem] = NULL; - } else if (0 == (data[6] & 0x30)) { - VPRINTK(KERN_CONT, "ID/LUN unknown\n"); - ch->dt[elem] = NULL; - } else { - id = ch->device->id; - lun = 0; - if (data[6] & 0x20) id = data[7]; - if (data[6] & 0x10) lun = data[6] & 7; - } - } - if (-1 != id) { - VPRINTK(KERN_CONT, "ID %i, LUN %i, ",id,lun); - ch->dt[elem] = - scsi_device_lookup(ch->device->host, - ch->device->channel, - id,lun); - if (!ch->dt[elem]) { - /* should not happen */ - VPRINTK(KERN_CONT, "Huh? device not found!\n"); - } else { - VPRINTK(KERN_CONT, "name: %8.8s %16.16s %4.4s\n", - ch->dt[elem]->vendor, - ch->dt[elem]->model, - ch->dt[elem]->rev); - } - } - } - ch->voltags = 1; - kfree(buffer); - - return 0; -} - -/* ------------------------------------------------------------------------ */ - -static int -ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate) -{ - u_char cmd[10]; - - DPRINTK("position: 0x%x\n",elem); - if (0 == trans) - trans = ch->firsts[CHET_MT]; - memset(cmd,0,sizeof(cmd)); - cmd[0] = POSITION_TO_ELEMENT; - cmd[1] = ch->device->lun << 5; - cmd[2] = (trans >> 8) & 0xff; - cmd[3] = trans & 0xff; - cmd[4] = (elem >> 8) & 0xff; - cmd[5] = elem & 0xff; - cmd[8] = rotate ? 1 : 0; - return ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE); -} - -static int -ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate) -{ - u_char cmd[12]; - - DPRINTK("move: 0x%x => 0x%x\n",src,dest); - if (0 == trans) - trans = ch->firsts[CHET_MT]; - memset(cmd,0,sizeof(cmd)); - cmd[0] = MOVE_MEDIUM; - cmd[1] = ch->device->lun << 5; - cmd[2] = (trans >> 8) & 0xff; - cmd[3] = trans & 0xff; - cmd[4] = (src >> 8) & 0xff; - cmd[5] = src & 0xff; - cmd[6] = (dest >> 8) & 0xff; - cmd[7] = dest & 0xff; - cmd[10] = rotate ? 1 : 0; - return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE); -} - -static int -ch_exchange(scsi_changer *ch, u_int trans, u_int src, - u_int dest1, u_int dest2, int rotate1, int rotate2) -{ - u_char cmd[12]; - - DPRINTK("exchange: 0x%x => 0x%x => 0x%x\n", - src,dest1,dest2); - if (0 == trans) - trans = ch->firsts[CHET_MT]; - memset(cmd,0,sizeof(cmd)); - cmd[0] = EXCHANGE_MEDIUM; - cmd[1] = ch->device->lun << 5; - cmd[2] = (trans >> 8) & 0xff; - cmd[3] = trans & 0xff; - cmd[4] = (src >> 8) & 0xff; - cmd[5] = src & 0xff; - cmd[6] = (dest1 >> 8) & 0xff; - cmd[7] = dest1 & 0xff; - cmd[8] = (dest2 >> 8) & 0xff; - cmd[9] = dest2 & 0xff; - cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0); - - return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE); -} - -static void -ch_check_voltag(char *tag) -{ - int i; - - for (i = 0; i < 32; i++) { - /* restrict to ascii */ - if (tag[i] >= 0x7f || tag[i] < 0x20) - tag[i] = ' '; - /* don't allow search wildcards */ - if (tag[i] == '?' || - tag[i] == '*') - tag[i] = ' '; - } -} - -static int -ch_set_voltag(scsi_changer *ch, u_int elem, - int alternate, int clear, u_char *tag) -{ - u_char cmd[12]; - u_char *buffer; - int result; - - buffer = kzalloc(512, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - DPRINTK("%s %s voltag: 0x%x => \"%s\"\n", - clear ? "clear" : "set", - alternate ? "alternate" : "primary", - elem, tag); - memset(cmd,0,sizeof(cmd)); - cmd[0] = SEND_VOLUME_TAG; - cmd[1] = (ch->device->lun << 5) | - ch_elem_to_typecode(ch,elem); - cmd[2] = (elem >> 8) & 0xff; - cmd[3] = elem & 0xff; - cmd[5] = clear - ? (alternate ? 0x0d : 0x0c) - : (alternate ? 0x0b : 0x0a); - - cmd[9] = 255; - - memcpy(buffer,tag,32); - ch_check_voltag(buffer); - - result = ch_do_scsi(ch, cmd, buffer, 256, DMA_TO_DEVICE); - kfree(buffer); - return result; -} - -static int ch_gstatus(scsi_changer *ch, int type, unsigned char __user *dest) -{ - int retval = 0; - u_char data[16]; - unsigned int i; - - mutex_lock(&ch->lock); - for (i = 0; i < ch->counts[type]; i++) { - if (0 != ch_read_element_status - (ch, ch->firsts[type]+i,data)) { - retval = -EIO; - break; - } - put_user(data[2], dest+i); - if (data[2] & CESTATUS_EXCEPT) - VPRINTK(KERN_INFO, "element 0x%x: asc=0x%x, ascq=0x%x\n", - ch->firsts[type]+i, - (int)data[4],(int)data[5]); - retval = ch_read_element_status - (ch, ch->firsts[type]+i,data); - if (0 != retval) - break; - } - mutex_unlock(&ch->lock); - return retval; -} - -/* ------------------------------------------------------------------------ */ - -static int -ch_release(struct inode *inode, struct file *file) -{ - scsi_changer *ch = file->private_data; - - scsi_device_put(ch->device); - file->private_data = NULL; - return 0; -} - -static int -ch_open(struct inode *inode, struct file *file) -{ - scsi_changer *ch; - int minor = iminor(inode); - - mutex_lock(&ch_mutex); - spin_lock(&ch_index_lock); - ch = idr_find(&ch_index_idr, minor); - - if (NULL == ch || scsi_device_get(ch->device)) { - spin_unlock(&ch_index_lock); - mutex_unlock(&ch_mutex); - return -ENXIO; - } - spin_unlock(&ch_index_lock); - - file->private_data = ch; - mutex_unlock(&ch_mutex); - return 0; -} - -static int -ch_checkrange(scsi_changer *ch, unsigned int type, unsigned int unit) -{ - if (type >= CH_TYPES || unit >= ch->counts[type]) - return -1; - return 0; -} - -static long ch_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - scsi_changer *ch = file->private_data; - int retval; - void __user *argp = (void __user *)arg; - - switch (cmd) { - case CHIOGPARAMS: - { - struct changer_params params; - - params.cp_curpicker = 0; - params.cp_npickers = ch->counts[CHET_MT]; - params.cp_nslots = ch->counts[CHET_ST]; - params.cp_nportals = ch->counts[CHET_IE]; - params.cp_ndrives = ch->counts[CHET_DT]; - - if (copy_to_user(argp, ¶ms, sizeof(params))) - return -EFAULT; - return 0; - } - case CHIOGVPARAMS: - { - struct changer_vendor_params vparams; - - memset(&vparams,0,sizeof(vparams)); - if (ch->counts[CHET_V1]) { - vparams.cvp_n1 = ch->counts[CHET_V1]; - strncpy(vparams.cvp_label1,vendor_labels[0],16); - } - if (ch->counts[CHET_V2]) { - vparams.cvp_n2 = ch->counts[CHET_V2]; - strncpy(vparams.cvp_label2,vendor_labels[1],16); - } - if (ch->counts[CHET_V3]) { - vparams.cvp_n3 = ch->counts[CHET_V3]; - strncpy(vparams.cvp_label3,vendor_labels[2],16); - } - if (ch->counts[CHET_V4]) { - vparams.cvp_n4 = ch->counts[CHET_V4]; - strncpy(vparams.cvp_label4,vendor_labels[3],16); - } - if (copy_to_user(argp, &vparams, sizeof(vparams))) - return -EFAULT; - return 0; - } - - case CHIOPOSITION: - { - struct changer_position pos; - - if (copy_from_user(&pos, argp, sizeof (pos))) - return -EFAULT; - - if (0 != ch_checkrange(ch, pos.cp_type, pos.cp_unit)) { - DPRINTK("CHIOPOSITION: invalid parameter\n"); - return -EBADSLT; - } - mutex_lock(&ch->lock); - retval = ch_position(ch,0, - ch->firsts[pos.cp_type] + pos.cp_unit, - pos.cp_flags & CP_INVERT); - mutex_unlock(&ch->lock); - return retval; - } - - case CHIOMOVE: - { - struct changer_move mv; - - if (copy_from_user(&mv, argp, sizeof (mv))) - return -EFAULT; - - if (0 != ch_checkrange(ch, mv.cm_fromtype, mv.cm_fromunit) || - 0 != ch_checkrange(ch, mv.cm_totype, mv.cm_tounit )) { - DPRINTK("CHIOMOVE: invalid parameter\n"); - return -EBADSLT; - } - - mutex_lock(&ch->lock); - retval = ch_move(ch,0, - ch->firsts[mv.cm_fromtype] + mv.cm_fromunit, - ch->firsts[mv.cm_totype] + mv.cm_tounit, - mv.cm_flags & CM_INVERT); - mutex_unlock(&ch->lock); - return retval; - } - - case CHIOEXCHANGE: - { - struct changer_exchange mv; - - if (copy_from_user(&mv, argp, sizeof (mv))) - return -EFAULT; - - if (0 != ch_checkrange(ch, mv.ce_srctype, mv.ce_srcunit ) || - 0 != ch_checkrange(ch, mv.ce_fdsttype, mv.ce_fdstunit) || - 0 != ch_checkrange(ch, mv.ce_sdsttype, mv.ce_sdstunit)) { - DPRINTK("CHIOEXCHANGE: invalid parameter\n"); - return -EBADSLT; - } - - mutex_lock(&ch->lock); - retval = ch_exchange - (ch,0, - ch->firsts[mv.ce_srctype] + mv.ce_srcunit, - ch->firsts[mv.ce_fdsttype] + mv.ce_fdstunit, - ch->firsts[mv.ce_sdsttype] + mv.ce_sdstunit, - mv.ce_flags & CE_INVERT1, mv.ce_flags & CE_INVERT2); - mutex_unlock(&ch->lock); - return retval; - } - - case CHIOGSTATUS: - { - struct changer_element_status ces; - - if (copy_from_user(&ces, argp, sizeof (ces))) - return -EFAULT; - if (ces.ces_type < 0 || ces.ces_type >= CH_TYPES) - return -EINVAL; - - return ch_gstatus(ch, ces.ces_type, ces.ces_data); - } - - case CHIOGELEM: - { - struct changer_get_element cge; - u_char ch_cmd[12]; - u_char *buffer; - unsigned int elem; - int result,i; - - if (copy_from_user(&cge, argp, sizeof (cge))) - return -EFAULT; - - if (0 != ch_checkrange(ch, cge.cge_type, cge.cge_unit)) - return -EINVAL; - elem = ch->firsts[cge.cge_type] + cge.cge_unit; - - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - mutex_lock(&ch->lock); - - voltag_retry: - memset(ch_cmd, 0, sizeof(ch_cmd)); - ch_cmd[0] = READ_ELEMENT_STATUS; - ch_cmd[1] = (ch->device->lun << 5) | - (ch->voltags ? 0x10 : 0) | - ch_elem_to_typecode(ch,elem); - ch_cmd[2] = (elem >> 8) & 0xff; - ch_cmd[3] = elem & 0xff; - ch_cmd[5] = 1; - ch_cmd[9] = 255; - - result = ch_do_scsi(ch, ch_cmd, buffer, 256, DMA_FROM_DEVICE); - if (!result) { - cge.cge_status = buffer[18]; - cge.cge_flags = 0; - if (buffer[18] & CESTATUS_EXCEPT) { - cge.cge_errno = EIO; - } - if (buffer[25] & 0x80) { - cge.cge_flags |= CGE_SRC; - if (buffer[25] & 0x40) - cge.cge_flags |= CGE_INVERT; - elem = (buffer[26]<<8) | buffer[27]; - for (i = 0; i < 4; i++) { - if (elem >= ch->firsts[i] && - elem < ch->firsts[i] + ch->counts[i]) { - cge.cge_srctype = i; - cge.cge_srcunit = elem-ch->firsts[i]; - } - } - } - if ((buffer[22] & 0x30) == 0x30) { - cge.cge_flags |= CGE_IDLUN; - cge.cge_id = buffer[23]; - cge.cge_lun = buffer[22] & 7; - } - if (buffer[9] & 0x80) { - cge.cge_flags |= CGE_PVOLTAG; - memcpy(cge.cge_pvoltag,buffer+28,36); - } - if (buffer[9] & 0x40) { - cge.cge_flags |= CGE_AVOLTAG; - memcpy(cge.cge_avoltag,buffer+64,36); - } - } else if (ch->voltags) { - ch->voltags = 0; - VPRINTK(KERN_INFO, "device has no volume tag support\n"); - goto voltag_retry; - } - kfree(buffer); - mutex_unlock(&ch->lock); - - if (copy_to_user(argp, &cge, sizeof (cge))) - return -EFAULT; - return result; - } - - case CHIOINITELEM: - { - mutex_lock(&ch->lock); - retval = ch_init_elem(ch); - mutex_unlock(&ch->lock); - return retval; - } - - case CHIOSVOLTAG: - { - struct changer_set_voltag csv; - int elem; - - if (copy_from_user(&csv, argp, sizeof(csv))) - return -EFAULT; - - if (0 != ch_checkrange(ch, csv.csv_type, csv.csv_unit)) { - DPRINTK("CHIOSVOLTAG: invalid parameter\n"); - return -EBADSLT; - } - elem = ch->firsts[csv.csv_type] + csv.csv_unit; - mutex_lock(&ch->lock); - retval = ch_set_voltag(ch, elem, - csv.csv_flags & CSV_AVOLTAG, - csv.csv_flags & CSV_CLEARTAG, - csv.csv_voltag); - mutex_unlock(&ch->lock); - return retval; - } - - default: - return scsi_ioctl(ch->device, cmd, argp); - - } -} - -#ifdef CONFIG_COMPAT - -struct changer_element_status32 { - int ces_type; - compat_uptr_t ces_data; -}; -#define CHIOGSTATUS32 _IOW('c', 8,struct changer_element_status32) - -static long ch_ioctl_compat(struct file * file, - unsigned int cmd, unsigned long arg) -{ - scsi_changer *ch = file->private_data; - - switch (cmd) { - case CHIOGPARAMS: - case CHIOGVPARAMS: - case CHIOPOSITION: - case CHIOMOVE: - case CHIOEXCHANGE: - case CHIOGELEM: - case CHIOINITELEM: - case CHIOSVOLTAG: - /* compatible */ - return ch_ioctl(file, cmd, arg); - case CHIOGSTATUS32: - { - struct changer_element_status32 ces32; - unsigned char __user *data; - - if (copy_from_user(&ces32, (void __user *)arg, sizeof (ces32))) - return -EFAULT; - if (ces32.ces_type < 0 || ces32.ces_type >= CH_TYPES) - return -EINVAL; - - data = compat_ptr(ces32.ces_data); - return ch_gstatus(ch, ces32.ces_type, data); - } - default: - // return scsi_ioctl_compat(ch->device, cmd, (void*)arg); - return -ENOIOCTLCMD; - - } -} -#endif - -/* ------------------------------------------------------------------------ */ - -static int ch_probe(struct device *dev) -{ - struct scsi_device *sd = to_scsi_device(dev); - struct device *class_dev; - int minor, ret = -ENOMEM; - scsi_changer *ch; - - if (sd->type != TYPE_MEDIUM_CHANGER) - return -ENODEV; - - ch = kzalloc(sizeof(*ch), GFP_KERNEL); - if (NULL == ch) - return -ENOMEM; - - if (!idr_pre_get(&ch_index_idr, GFP_KERNEL)) - goto free_ch; - - spin_lock(&ch_index_lock); - ret = idr_get_new(&ch_index_idr, ch, &minor); - spin_unlock(&ch_index_lock); - - if (ret) - goto free_ch; - - if (minor > CH_MAX_DEVS) { - ret = -ENODEV; - goto remove_idr; - } - - ch->minor = minor; - sprintf(ch->name,"ch%d",ch->minor); - - class_dev = device_create(ch_sysfs_class, dev, - MKDEV(SCSI_CHANGER_MAJOR, ch->minor), ch, - "s%s", ch->name); - if (IS_ERR(class_dev)) { - printk(KERN_WARNING "ch%d: device_create failed\n", - ch->minor); - ret = PTR_ERR(class_dev); - goto remove_idr; - } - - mutex_init(&ch->lock); - ch->device = sd; - ch_readconfig(ch); - if (init) - ch_init_elem(ch); - - dev_set_drvdata(dev, ch); - sdev_printk(KERN_INFO, sd, "Attached scsi changer %s\n", ch->name); - - return 0; -remove_idr: - idr_remove(&ch_index_idr, minor); -free_ch: - kfree(ch); - return ret; -} - -static int ch_remove(struct device *dev) -{ - scsi_changer *ch = dev_get_drvdata(dev); - - spin_lock(&ch_index_lock); - idr_remove(&ch_index_idr, ch->minor); - spin_unlock(&ch_index_lock); - - device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); - kfree(ch->dt); - kfree(ch); - return 0; -} - -static struct scsi_driver ch_template = { - .owner = THIS_MODULE, - .gendrv = { - .name = "ch", - .probe = ch_probe, - .remove = ch_remove, - }, -}; - -static const struct file_operations changer_fops = { - .owner = THIS_MODULE, - .open = ch_open, - .release = ch_release, - .unlocked_ioctl = ch_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ch_ioctl_compat, -#endif - .llseek = noop_llseek, -}; - -static int __init init_ch_module(void) -{ - int rc; - - printk(KERN_INFO "SCSI Media Changer driver v" VERSION " \n"); - ch_sysfs_class = class_create(THIS_MODULE, "scsi_changer"); - if (IS_ERR(ch_sysfs_class)) { - rc = PTR_ERR(ch_sysfs_class); - return rc; - } - rc = register_chrdev(SCSI_CHANGER_MAJOR,"ch",&changer_fops); - if (rc < 0) { - printk("Unable to get major %d for SCSI-Changer\n", - SCSI_CHANGER_MAJOR); - goto fail1; - } - rc = scsi_register_driver(&ch_template.gendrv); - if (rc < 0) - goto fail2; - return 0; - - fail2: - unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); - fail1: - class_destroy(ch_sysfs_class); - return rc; -} - -static void __exit exit_ch_module(void) -{ - scsi_unregister_driver(&ch_template.gendrv); - unregister_chrdev(SCSI_CHANGER_MAJOR, "ch"); - class_destroy(ch_sysfs_class); - idr_destroy(&ch_index_idr); -} - -module_init(init_ch_module); -module_exit(exit_ch_module); - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/ANDROID_3.4.5/drivers/scsi/constants.c b/ANDROID_3.4.5/drivers/scsi/constants.c deleted file mode 100644 index 450e011f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/constants.c +++ /dev/null @@ -1,1462 +0,0 @@ -/* - * ASCII values for a number of symbolic constants, printing functions, - * etc. - * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422) - * Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002) - * by D. Gilbert and aeb (20020609) - * Update to SPC-4 T10/1713-D Rev 20, 22 May 2009, D. Gilbert 20090624 - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - - -/* Commands with service actions that change the command name */ -#define MAINTENANCE_IN 0xa3 -#define MAINTENANCE_OUT 0xa4 -#define SERVICE_ACTION_IN_12 0xab -#define SERVICE_ACTION_OUT_12 0xa9 -#define SERVICE_ACTION_IN_16 0x9e -#define SERVICE_ACTION_OUT_16 0x9f - - - -#ifdef CONFIG_SCSI_CONSTANTS -static const char * cdb_byte0_names[] = { -/* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense", -/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL, - "Reassign Blocks", -/* 08-0d */ "Read(6)", NULL, "Write(6)", "Seek(6)", NULL, NULL, -/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ "Verify(6)", "Recover Buffered Data", "Mode Select(6)", - "Reserve(6)", -/* 17-1a */ "Release(6)", "Copy", "Erase", "Mode Sense(6)", -/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic", -/* 1e-1f */ "Prevent/Allow Medium Removal", NULL, -/* 20-22 */ NULL, NULL, NULL, -/* 23-28 */ "Read Format Capacities", "Set Window", - "Read Capacity(10)", NULL, NULL, "Read(10)", -/* 29-2d */ "Read Generation", "Write(10)", "Seek(10)", "Erase(10)", - "Read updated block", -/* 2e-31 */ "Write Verify(10)", "Verify(10)", "Search High", "Search Equal", -/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position", -/* 35-37 */ "Synchronize Cache(10)", "Lock/Unlock Cache(10)", - "Read Defect Data(10)", -/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", - "Read Buffer", -/* 3d-3f */ "Update Block", "Read Long(10)", "Write Long(10)", -/* 40-41 */ "Change Definition", "Write Same(10)", -/* 42-48 */ "Unmap/Read sub-channel", "Read TOC/PMA/ATIP", - "Read density support", "Play audio(10)", "Get configuration", - "Play audio msf", "Play audio track/index", -/* 49-4f */ "Play track relative(10)", "Get event status notification", - "Pause/resume", "Log Select", "Log Sense", "Stop play/scan", - NULL, -/* 50-55 */ "Xdwrite", "Xpwrite, Read disk info", "Xdread, Read track info", - "Reserve track", "Send OPC info", "Mode Select(10)", -/* 56-5b */ "Reserve(10)", "Release(10)", "Repair track", "Read master cue", - "Mode Sense(10)", "Close track/session", -/* 5c-5f */ "Read buffer capacity", "Send cue sheet", "Persistent reserve in", - "Persistent reserve out", -/* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -/* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, "Extended CDB", - "Variable length", -/* 80-84 */ "Xdwrite(16)", "Rebuild(16)", "Regenerate(16)", "Extended copy", - "Receive copy results", -/* 85-89 */ "ATA command pass through(16)", "Access control in", - "Access control out", "Read(16)", "Memory Export Out(16)", -/* 8a-8f */ "Write(16)", "ORWrite", "Read attributes", "Write attributes", - "Write and verify(16)", "Verify(16)", -/* 90-94 */ "Pre-fetch(16)", "Synchronize cache(16)", - "Lock/unlock cache(16)", "Write same(16)", NULL, -/* 95-99 */ NULL, NULL, NULL, NULL, NULL, -/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in(16)", - "Service action out(16)", -/* a0-a5 */ "Report luns", "ATA command pass through(12)/Blank", - "Security protocol in", "Maintenance in", "Maintenance out", - "Move medium/play audio(12)", -/* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)", - "Play track relative(12)", -/* aa-ae */ "Write(12)", NULL, "Erase(12), Get Performance", - "Read DVD structure", "Write and verify(12)", -/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)", -/* b2-b4 */ "Search data low(12)", "Set limits(12)", - "Read element status attached", -/* b5-b6 */ "Security protocol out", "Send volume tag, set streaming", -/* b7-b9 */ "Read defect data(12)", "Read element status", "Read CD msf", -/* ba-bc */ "Redundancy group (in), Scan", - "Redundancy group (out), Set cd-rom speed", "Spare (in), Play cd", -/* bd-bf */ "Spare (out), Mechanism status", "Volume set (in), Read cd", - "Volume set (out), Send DVD structure", -}; - -struct value_name_pair { - int value; - const char * name; -}; - -static const struct value_name_pair maint_in_arr[] = { - {0x5, "Report identifying information"}, - {0xa, "Report target port groups"}, - {0xb, "Report aliases"}, - {0xc, "Report supported operation codes"}, - {0xd, "Report supported task management functions"}, - {0xe, "Report priority"}, - {0xf, "Report timestamp"}, - {0x10, "Management protocol in"}, -}; -#define MAINT_IN_SZ ARRAY_SIZE(maint_in_arr) - -static const struct value_name_pair maint_out_arr[] = { - {0x6, "Set identifying information"}, - {0xa, "Set target port groups"}, - {0xb, "Change aliases"}, - {0xe, "Set priority"}, - {0xf, "Set timestamp"}, - {0x10, "Management protocol out"}, -}; -#define MAINT_OUT_SZ ARRAY_SIZE(maint_out_arr) - -static const struct value_name_pair serv_in12_arr[] = { - {0x1, "Read media serial number"}, -}; -#define SERV_IN12_SZ ARRAY_SIZE(serv_in12_arr) - -static const struct value_name_pair serv_out12_arr[] = { - {-1, "dummy entry"}, -}; -#define SERV_OUT12_SZ ARRAY_SIZE(serv_out12_arr) - -static const struct value_name_pair serv_in16_arr[] = { - {0x10, "Read capacity(16)"}, - {0x11, "Read long(16)"}, - {0x12, "Get LBA status"}, -}; -#define SERV_IN16_SZ ARRAY_SIZE(serv_in16_arr) - -static const struct value_name_pair serv_out16_arr[] = { - {0x11, "Write long(16)"}, - {0x1f, "Notify data transfer device(16)"}, -}; -#define SERV_OUT16_SZ ARRAY_SIZE(serv_out16_arr) - -static const struct value_name_pair variable_length_arr[] = { - {0x1, "Rebuild(32)"}, - {0x2, "Regenerate(32)"}, - {0x3, "Xdread(32)"}, - {0x4, "Xdwrite(32)"}, - {0x5, "Xdwrite extended(32)"}, - {0x6, "Xpwrite(32)"}, - {0x7, "Xdwriteread(32)"}, - {0x8, "Xdwrite extended(64)"}, - {0x9, "Read(32)"}, - {0xa, "Verify(32)"}, - {0xb, "Write(32)"}, - {0xc, "Write an verify(32)"}, - {0xd, "Write same(32)"}, - {0x8801, "Format OSD"}, - {0x8802, "Create (osd)"}, - {0x8803, "List (osd)"}, - {0x8805, "Read (osd)"}, - {0x8806, "Write (osd)"}, - {0x8807, "Append (osd)"}, - {0x8808, "Flush (osd)"}, - {0x880a, "Remove (osd)"}, - {0x880b, "Create partition (osd)"}, - {0x880c, "Remove partition (osd)"}, - {0x880e, "Get attributes (osd)"}, - {0x880f, "Set attributes (osd)"}, - {0x8812, "Create and write (osd)"}, - {0x8815, "Create collection (osd)"}, - {0x8816, "Remove collection (osd)"}, - {0x8817, "List collection (osd)"}, - {0x8818, "Set key (osd)"}, - {0x8819, "Set master key (osd)"}, - {0x881a, "Flush collection (osd)"}, - {0x881b, "Flush partition (osd)"}, - {0x881c, "Flush OSD"}, - {0x8f7e, "Perform SCSI command (osd)"}, - {0x8f7f, "Perform task management function (osd)"}, -}; -#define VARIABLE_LENGTH_SZ ARRAY_SIZE(variable_length_arr) - -static const char * get_sa_name(const struct value_name_pair * arr, - int arr_sz, int service_action) -{ - int k; - - for (k = 0; k < arr_sz; ++k, ++arr) { - if (service_action == arr->value) - break; - } - return (k < arr_sz) ? arr->name : NULL; -} - -/* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */ -static void print_opcode_name(unsigned char * cdbp, int cdb_len) -{ - int sa, len, cdb0; - const char * name; - - cdb0 = cdbp[0]; - switch(cdb0) { - case VARIABLE_LENGTH_CMD: - len = scsi_varlen_cdb_length(cdbp); - if (len < 10) { - printk("short variable length command, " - "len=%d ext_len=%d", len, cdb_len); - break; - } - sa = (cdbp[8] << 8) + cdbp[9]; - name = get_sa_name(variable_length_arr, VARIABLE_LENGTH_SZ, sa); - if (name) - printk("%s", name); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - - if ((cdb_len > 0) && (len != cdb_len)) - printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len); - - break; - case MAINTENANCE_IN: - sa = cdbp[1] & 0x1f; - name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa); - if (name) - printk("%s", name); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - break; - case MAINTENANCE_OUT: - sa = cdbp[1] & 0x1f; - name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa); - if (name) - printk("%s", name); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - break; - case SERVICE_ACTION_IN_12: - sa = cdbp[1] & 0x1f; - name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa); - if (name) - printk("%s", name); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - break; - case SERVICE_ACTION_OUT_12: - sa = cdbp[1] & 0x1f; - name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa); - if (name) - printk("%s", name); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - break; - case SERVICE_ACTION_IN_16: - sa = cdbp[1] & 0x1f; - name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa); - if (name) - printk("%s", name); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - break; - case SERVICE_ACTION_OUT_16: - sa = cdbp[1] & 0x1f; - name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa); - if (name) - printk("%s", name); - else - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - break; - default: - if (cdb0 < 0xc0) { - name = cdb_byte0_names[cdb0]; - if (name) - printk("%s", name); - else - printk("cdb[0]=0x%x (reserved)", cdb0); - } else - printk("cdb[0]=0x%x (vendor)", cdb0); - break; - } -} - -#else /* ifndef CONFIG_SCSI_CONSTANTS */ - -static void print_opcode_name(unsigned char * cdbp, int cdb_len) -{ - int sa, len, cdb0; - - cdb0 = cdbp[0]; - switch(cdb0) { - case VARIABLE_LENGTH_CMD: - len = scsi_varlen_cdb_length(cdbp); - if (len < 10) { - printk("short opcode=0x%x command, len=%d " - "ext_len=%d", cdb0, len, cdb_len); - break; - } - sa = (cdbp[8] << 8) + cdbp[9]; - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - if (len != cdb_len) - printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len); - break; - case MAINTENANCE_IN: - case MAINTENANCE_OUT: - case SERVICE_ACTION_IN_12: - case SERVICE_ACTION_OUT_12: - case SERVICE_ACTION_IN_16: - case SERVICE_ACTION_OUT_16: - sa = cdbp[1] & 0x1f; - printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa); - break; - default: - if (cdb0 < 0xc0) - printk("cdb[0]=0x%x", cdb0); - else - printk("cdb[0]=0x%x (vendor)", cdb0); - break; - } -} -#endif - -void __scsi_print_command(unsigned char *cdb) -{ - int k, len; - - print_opcode_name(cdb, 0); - len = scsi_command_size(cdb); - /* print out all bytes in cdb */ - for (k = 0; k < len; ++k) - printk(" %02x", cdb[k]); - printk("\n"); -} -EXPORT_SYMBOL(__scsi_print_command); - -void scsi_print_command(struct scsi_cmnd *cmd) -{ - int k; - - if (cmd->cmnd == NULL) - return; - - scmd_printk(KERN_INFO, cmd, "CDB: "); - print_opcode_name(cmd->cmnd, cmd->cmd_len); - - /* print out all bytes in cdb */ - printk(":"); - for (k = 0; k < cmd->cmd_len; ++k) - printk(" %02x", cmd->cmnd[k]); - printk("\n"); -} -EXPORT_SYMBOL(scsi_print_command); - -/** - * scsi_print_status - print scsi status description - * @scsi_status: scsi status value - * - * If the status is recognized, the description is printed. - * Otherwise "Unknown status" is output. No trailing space. - * If CONFIG_SCSI_CONSTANTS is not set, then print status in hex - * (e.g. "0x2" for Check Condition). - **/ -void -scsi_print_status(unsigned char scsi_status) { -#ifdef CONFIG_SCSI_CONSTANTS - const char * ccp; - - switch (scsi_status) { - case 0: ccp = "Good"; break; - case 0x2: ccp = "Check Condition"; break; - case 0x4: ccp = "Condition Met"; break; - case 0x8: ccp = "Busy"; break; - case 0x10: ccp = "Intermediate"; break; - case 0x14: ccp = "Intermediate-Condition Met"; break; - case 0x18: ccp = "Reservation Conflict"; break; - case 0x22: ccp = "Command Terminated"; break; /* obsolete */ - case 0x28: ccp = "Task set Full"; break; /* was: Queue Full */ - case 0x30: ccp = "ACA Active"; break; - case 0x40: ccp = "Task Aborted"; break; - default: ccp = "Unknown status"; - } - printk(KERN_INFO "%s", ccp); -#else - printk(KERN_INFO "0x%0x", scsi_status); -#endif -} -EXPORT_SYMBOL(scsi_print_status); - -#ifdef CONFIG_SCSI_CONSTANTS - -struct error_info { - unsigned short code12; /* 0x0302 looks better than 0x03,0x02 */ - const char * text; -}; - -/* - * The canonical list of T10 Additional Sense Codes is available at: - * http://www.t10.org/lists/asc-num.txt - */ -static const struct error_info additional[] = -{ - {0x0000, "No additional sense information"}, - {0x0001, "Filemark detected"}, - {0x0002, "End-of-partition/medium detected"}, - {0x0003, "Setmark detected"}, - {0x0004, "Beginning-of-partition/medium detected"}, - {0x0005, "End-of-data detected"}, - {0x0006, "I/O process terminated"}, - {0x0007, "Programmable early warning detected"}, - {0x0011, "Audio play operation in progress"}, - {0x0012, "Audio play operation paused"}, - {0x0013, "Audio play operation successfully completed"}, - {0x0014, "Audio play operation stopped due to error"}, - {0x0015, "No current audio status to return"}, - {0x0016, "Operation in progress"}, - {0x0017, "Cleaning requested"}, - {0x0018, "Erase operation in progress"}, - {0x0019, "Locate operation in progress"}, - {0x001A, "Rewind operation in progress"}, - {0x001B, "Set capacity operation in progress"}, - {0x001C, "Verify operation in progress"}, - {0x001D, "ATA pass through information available"}, - {0x001E, "Conflicting SA creation request"}, - - {0x0100, "No index/sector signal"}, - - {0x0200, "No seek complete"}, - - {0x0300, "Peripheral device write fault"}, - {0x0301, "No write current"}, - {0x0302, "Excessive write errors"}, - - {0x0400, "Logical unit not ready, cause not reportable"}, - {0x0401, "Logical unit is in process of becoming ready"}, - {0x0402, "Logical unit not ready, initializing command required"}, - {0x0403, "Logical unit not ready, manual intervention required"}, - {0x0404, "Logical unit not ready, format in progress"}, - {0x0405, "Logical unit not ready, rebuild in progress"}, - {0x0406, "Logical unit not ready, recalculation in progress"}, - {0x0407, "Logical unit not ready, operation in progress"}, - {0x0408, "Logical unit not ready, long write in progress"}, - {0x0409, "Logical unit not ready, self-test in progress"}, - {0x040A, "Logical unit not accessible, asymmetric access state " - "transition"}, - {0x040B, "Logical unit not accessible, target port in standby state"}, - {0x040C, "Logical unit not accessible, target port in unavailable " - "state"}, - {0x040D, "Logical unit not ready, structure check required"}, - {0x0410, "Logical unit not ready, auxiliary memory not accessible"}, - {0x0411, "Logical unit not ready, notify (enable spinup) required"}, - {0x0412, "Logical unit not ready, offline"}, - {0x0413, "Logical unit not ready, SA creation in progress"}, - {0x0414, "Logical unit not ready, space allocation in progress"}, - - {0x0500, "Logical unit does not respond to selection"}, - - {0x0600, "No reference position found"}, - - {0x0700, "Multiple peripheral devices selected"}, - - {0x0800, "Logical unit communication failure"}, - {0x0801, "Logical unit communication time-out"}, - {0x0802, "Logical unit communication parity error"}, - {0x0803, "Logical unit communication CRC error (Ultra-DMA/32)"}, - {0x0804, "Unreachable copy target"}, - - {0x0900, "Track following error"}, - {0x0901, "Tracking servo failure"}, - {0x0902, "Focus servo failure"}, - {0x0903, "Spindle servo failure"}, - {0x0904, "Head select fault"}, - - {0x0A00, "Error log overflow"}, - - {0x0B00, "Warning"}, - {0x0B01, "Warning - specified temperature exceeded"}, - {0x0B02, "Warning - enclosure degraded"}, - {0x0B03, "Warning - background self-test failed"}, - {0x0B04, "Warning - background pre-scan detected medium error"}, - {0x0B05, "Warning - background medium scan detected medium error"}, - {0x0B06, "Warning - non-volatile cache now volatile"}, - {0x0B07, "Warning - degraded power to non-volatile cache"}, - {0x0B08, "Warning - power loss expected"}, - - {0x0C00, "Write error"}, - {0x0C01, "Write error - recovered with auto reallocation"}, - {0x0C02, "Write error - auto reallocation failed"}, - {0x0C03, "Write error - recommend reassignment"}, - {0x0C04, "Compression check miscompare error"}, - {0x0C05, "Data expansion occurred during compression"}, - {0x0C06, "Block not compressible"}, - {0x0C07, "Write error - recovery needed"}, - {0x0C08, "Write error - recovery failed"}, - {0x0C09, "Write error - loss of streaming"}, - {0x0C0A, "Write error - padding blocks added"}, - {0x0C0B, "Auxiliary memory write error"}, - {0x0C0C, "Write error - unexpected unsolicited data"}, - {0x0C0D, "Write error - not enough unsolicited data"}, - {0x0C0F, "Defects in error window"}, - - {0x0D00, "Error detected by third party temporary initiator"}, - {0x0D01, "Third party device failure"}, - {0x0D02, "Copy target device not reachable"}, - {0x0D03, "Incorrect copy target device type"}, - {0x0D04, "Copy target device data underrun"}, - {0x0D05, "Copy target device data overrun"}, - - {0x0E00, "Invalid information unit"}, - {0x0E01, "Information unit too short"}, - {0x0E02, "Information unit too long"}, - {0x0E03, "Invalid field in command information unit"}, - - {0x1000, "Id CRC or ECC error"}, - {0x1001, "Logical block guard check failed"}, - {0x1002, "Logical block application tag check failed"}, - {0x1003, "Logical block reference tag check failed"}, - - {0x1100, "Unrecovered read error"}, - {0x1101, "Read retries exhausted"}, - {0x1102, "Error too long to correct"}, - {0x1103, "Multiple read errors"}, - {0x1104, "Unrecovered read error - auto reallocate failed"}, - {0x1105, "L-EC uncorrectable error"}, - {0x1106, "CIRC unrecovered error"}, - {0x1107, "Data re-synchronization error"}, - {0x1108, "Incomplete block read"}, - {0x1109, "No gap found"}, - {0x110A, "Miscorrected error"}, - {0x110B, "Unrecovered read error - recommend reassignment"}, - {0x110C, "Unrecovered read error - recommend rewrite the data"}, - {0x110D, "De-compression CRC error"}, - {0x110E, "Cannot decompress using declared algorithm"}, - {0x110F, "Error reading UPC/EAN number"}, - {0x1110, "Error reading ISRC number"}, - {0x1111, "Read error - loss of streaming"}, - {0x1112, "Auxiliary memory read error"}, - {0x1113, "Read error - failed retransmission request"}, - {0x1114, "Read error - lba marked bad by application client"}, - - {0x1200, "Address mark not found for id field"}, - - {0x1300, "Address mark not found for data field"}, - - {0x1400, "Recorded entity not found"}, - {0x1401, "Record not found"}, - {0x1402, "Filemark or setmark not found"}, - {0x1403, "End-of-data not found"}, - {0x1404, "Block sequence error"}, - {0x1405, "Record not found - recommend reassignment"}, - {0x1406, "Record not found - data auto-reallocated"}, - {0x1407, "Locate operation failure"}, - - {0x1500, "Random positioning error"}, - {0x1501, "Mechanical positioning error"}, - {0x1502, "Positioning error detected by read of medium"}, - - {0x1600, "Data synchronization mark error"}, - {0x1601, "Data sync error - data rewritten"}, - {0x1602, "Data sync error - recommend rewrite"}, - {0x1603, "Data sync error - data auto-reallocated"}, - {0x1604, "Data sync error - recommend reassignment"}, - - {0x1700, "Recovered data with no error correction applied"}, - {0x1701, "Recovered data with retries"}, - {0x1702, "Recovered data with positive head offset"}, - {0x1703, "Recovered data with negative head offset"}, - {0x1704, "Recovered data with retries and/or circ applied"}, - {0x1705, "Recovered data using previous sector id"}, - {0x1706, "Recovered data without ECC - data auto-reallocated"}, - {0x1707, "Recovered data without ECC - recommend reassignment"}, - {0x1708, "Recovered data without ECC - recommend rewrite"}, - {0x1709, "Recovered data without ECC - data rewritten"}, - - {0x1800, "Recovered data with error correction applied"}, - {0x1801, "Recovered data with error corr. & retries applied"}, - {0x1802, "Recovered data - data auto-reallocated"}, - {0x1803, "Recovered data with CIRC"}, - {0x1804, "Recovered data with L-EC"}, - {0x1805, "Recovered data - recommend reassignment"}, - {0x1806, "Recovered data - recommend rewrite"}, - {0x1807, "Recovered data with ECC - data rewritten"}, - {0x1808, "Recovered data with linking"}, - - {0x1900, "Defect list error"}, - {0x1901, "Defect list not available"}, - {0x1902, "Defect list error in primary list"}, - {0x1903, "Defect list error in grown list"}, - - {0x1A00, "Parameter list length error"}, - - {0x1B00, "Synchronous data transfer error"}, - - {0x1C00, "Defect list not found"}, - {0x1C01, "Primary defect list not found"}, - {0x1C02, "Grown defect list not found"}, - - {0x1D00, "Miscompare during verify operation"}, - {0x1D01, "Miscompare verify of unmapped LBA"}, - - {0x1E00, "Recovered id with ECC correction"}, - - {0x1F00, "Partial defect list transfer"}, - - {0x2000, "Invalid command operation code"}, - {0x2001, "Access denied - initiator pending-enrolled"}, - {0x2002, "Access denied - no access rights"}, - {0x2003, "Access denied - invalid mgmt id key"}, - {0x2004, "Illegal command while in write capable state"}, - {0x2005, "Obsolete"}, - {0x2006, "Illegal command while in explicit address mode"}, - {0x2007, "Illegal command while in implicit address mode"}, - {0x2008, "Access denied - enrollment conflict"}, - {0x2009, "Access denied - invalid LU identifier"}, - {0x200A, "Access denied - invalid proxy token"}, - {0x200B, "Access denied - ACL LUN conflict"}, - - {0x2100, "Logical block address out of range"}, - {0x2101, "Invalid element address"}, - {0x2102, "Invalid address for write"}, - {0x2103, "Invalid write crossing layer jump"}, - - {0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"}, - - {0x2400, "Invalid field in cdb"}, - {0x2401, "CDB decryption error"}, - {0x2402, "Obsolete"}, - {0x2403, "Obsolete"}, - {0x2404, "Security audit value frozen"}, - {0x2405, "Security working key frozen"}, - {0x2406, "Nonce not unique"}, - {0x2407, "Nonce timestamp out of range"}, - {0x2408, "Invalid XCDB"}, - - {0x2500, "Logical unit not supported"}, - - {0x2600, "Invalid field in parameter list"}, - {0x2601, "Parameter not supported"}, - {0x2602, "Parameter value invalid"}, - {0x2603, "Threshold parameters not supported"}, - {0x2604, "Invalid release of persistent reservation"}, - {0x2605, "Data decryption error"}, - {0x2606, "Too many target descriptors"}, - {0x2607, "Unsupported target descriptor type code"}, - {0x2608, "Too many segment descriptors"}, - {0x2609, "Unsupported segment descriptor type code"}, - {0x260A, "Unexpected inexact segment"}, - {0x260B, "Inline data length exceeded"}, - {0x260C, "Invalid operation for copy source or destination"}, - {0x260D, "Copy segment granularity violation"}, - {0x260E, "Invalid parameter while port is enabled"}, - {0x260F, "Invalid data-out buffer integrity check value"}, - {0x2610, "Data decryption key fail limit reached"}, - {0x2611, "Incomplete key-associated data set"}, - {0x2612, "Vendor specific key reference not found"}, - - {0x2700, "Write protected"}, - {0x2701, "Hardware write protected"}, - {0x2702, "Logical unit software write protected"}, - {0x2703, "Associated write protect"}, - {0x2704, "Persistent write protect"}, - {0x2705, "Permanent write protect"}, - {0x2706, "Conditional write protect"}, - {0x2707, "Space allocation failed write protect"}, - - {0x2800, "Not ready to ready change, medium may have changed"}, - {0x2801, "Import or export element accessed"}, - {0x2802, "Format-layer may have changed"}, - {0x2803, "Import/export element accessed, medium changed"}, - - {0x2900, "Power on, reset, or bus device reset occurred"}, - {0x2901, "Power on occurred"}, - {0x2902, "Scsi bus reset occurred"}, - {0x2903, "Bus device reset function occurred"}, - {0x2904, "Device internal reset"}, - {0x2905, "Transceiver mode changed to single-ended"}, - {0x2906, "Transceiver mode changed to lvd"}, - {0x2907, "I_T nexus loss occurred"}, - - {0x2A00, "Parameters changed"}, - {0x2A01, "Mode parameters changed"}, - {0x2A02, "Log parameters changed"}, - {0x2A03, "Reservations preempted"}, - {0x2A04, "Reservations released"}, - {0x2A05, "Registrations preempted"}, - {0x2A06, "Asymmetric access state changed"}, - {0x2A07, "Implicit asymmetric access state transition failed"}, - {0x2A08, "Priority changed"}, - {0x2A09, "Capacity data has changed"}, - {0x2A0A, "Error history I_T nexus cleared"}, - {0x2A0B, "Error history snapshot released"}, - {0x2A0C, "Error recovery attributes have changed"}, - {0x2A0D, "Data encryption capabilities changed"}, - {0x2A10, "Timestamp changed"}, - {0x2A11, "Data encryption parameters changed by another i_t nexus"}, - {0x2A12, "Data encryption parameters changed by vendor specific " - "event"}, - {0x2A13, "Data encryption key instance counter has changed"}, - {0x2A14, "SA creation capabilities data has changed"}, - - {0x2B00, "Copy cannot execute since host cannot disconnect"}, - - {0x2C00, "Command sequence error"}, - {0x2C01, "Too many windows specified"}, - {0x2C02, "Invalid combination of windows specified"}, - {0x2C03, "Current program area is not empty"}, - {0x2C04, "Current program area is empty"}, - {0x2C05, "Illegal power condition request"}, - {0x2C06, "Persistent prevent conflict"}, - {0x2C07, "Previous busy status"}, - {0x2C08, "Previous task set full status"}, - {0x2C09, "Previous reservation conflict status"}, - {0x2C0A, "Partition or collection contains user objects"}, - {0x2C0B, "Not reserved"}, - - {0x2D00, "Overwrite error on update in place"}, - - {0x2E00, "Insufficient time for operation"}, - - {0x2F00, "Commands cleared by another initiator"}, - {0x2F01, "Commands cleared by power loss notification"}, - {0x2F02, "Commands cleared by device server"}, - - {0x3000, "Incompatible medium installed"}, - {0x3001, "Cannot read medium - unknown format"}, - {0x3002, "Cannot read medium - incompatible format"}, - {0x3003, "Cleaning cartridge installed"}, - {0x3004, "Cannot write medium - unknown format"}, - {0x3005, "Cannot write medium - incompatible format"}, - {0x3006, "Cannot format medium - incompatible medium"}, - {0x3007, "Cleaning failure"}, - {0x3008, "Cannot write - application code mismatch"}, - {0x3009, "Current session not fixated for append"}, - {0x300A, "Cleaning request rejected"}, - {0x300C, "WORM medium - overwrite attempted"}, - {0x300D, "WORM medium - integrity check"}, - {0x3010, "Medium not formatted"}, - {0x3011, "Incompatible volume type"}, - {0x3012, "Incompatible volume qualifier"}, - - {0x3100, "Medium format corrupted"}, - {0x3101, "Format command failed"}, - {0x3102, "Zoned formatting failed due to spare linking"}, - - {0x3200, "No defect spare location available"}, - {0x3201, "Defect list update failure"}, - - {0x3300, "Tape length error"}, - - {0x3400, "Enclosure failure"}, - - {0x3500, "Enclosure services failure"}, - {0x3501, "Unsupported enclosure function"}, - {0x3502, "Enclosure services unavailable"}, - {0x3503, "Enclosure services transfer failure"}, - {0x3504, "Enclosure services transfer refused"}, - {0x3505, "Enclosure services checksum error"}, - - {0x3600, "Ribbon, ink, or toner failure"}, - - {0x3700, "Rounded parameter"}, - - {0x3800, "Event status notification"}, - {0x3802, "Esn - power management class event"}, - {0x3804, "Esn - media class event"}, - {0x3806, "Esn - device busy class event"}, - {0x3807, "Thin Provisioning soft threshold reached"}, - - {0x3900, "Saving parameters not supported"}, - - {0x3A00, "Medium not present"}, - {0x3A01, "Medium not present - tray closed"}, - {0x3A02, "Medium not present - tray open"}, - {0x3A03, "Medium not present - loadable"}, - {0x3A04, "Medium not present - medium auxiliary memory accessible"}, - - {0x3B00, "Sequential positioning error"}, - {0x3B01, "Tape position error at beginning-of-medium"}, - {0x3B02, "Tape position error at end-of-medium"}, - {0x3B03, "Tape or electronic vertical forms unit not ready"}, - {0x3B04, "Slew failure"}, - {0x3B05, "Paper jam"}, - {0x3B06, "Failed to sense top-of-form"}, - {0x3B07, "Failed to sense bottom-of-form"}, - {0x3B08, "Reposition error"}, - {0x3B09, "Read past end of medium"}, - {0x3B0A, "Read past beginning of medium"}, - {0x3B0B, "Position past end of medium"}, - {0x3B0C, "Position past beginning of medium"}, - {0x3B0D, "Medium destination element full"}, - {0x3B0E, "Medium source element empty"}, - {0x3B0F, "End of medium reached"}, - {0x3B11, "Medium magazine not accessible"}, - {0x3B12, "Medium magazine removed"}, - {0x3B13, "Medium magazine inserted"}, - {0x3B14, "Medium magazine locked"}, - {0x3B15, "Medium magazine unlocked"}, - {0x3B16, "Mechanical positioning or changer error"}, - {0x3B17, "Read past end of user object"}, - {0x3B18, "Element disabled"}, - {0x3B19, "Element enabled"}, - {0x3B1A, "Data transfer device removed"}, - {0x3B1B, "Data transfer device inserted"}, - - {0x3D00, "Invalid bits in identify message"}, - - {0x3E00, "Logical unit has not self-configured yet"}, - {0x3E01, "Logical unit failure"}, - {0x3E02, "Timeout on logical unit"}, - {0x3E03, "Logical unit failed self-test"}, - {0x3E04, "Logical unit unable to update self-test log"}, - - {0x3F00, "Target operating conditions have changed"}, - {0x3F01, "Microcode has been changed"}, - {0x3F02, "Changed operating definition"}, - {0x3F03, "Inquiry data has changed"}, - {0x3F04, "Component device attached"}, - {0x3F05, "Device identifier changed"}, - {0x3F06, "Redundancy group created or modified"}, - {0x3F07, "Redundancy group deleted"}, - {0x3F08, "Spare created or modified"}, - {0x3F09, "Spare deleted"}, - {0x3F0A, "Volume set created or modified"}, - {0x3F0B, "Volume set deleted"}, - {0x3F0C, "Volume set deassigned"}, - {0x3F0D, "Volume set reassigned"}, - {0x3F0E, "Reported luns data has changed"}, - {0x3F0F, "Echo buffer overwritten"}, - {0x3F10, "Medium loadable"}, - {0x3F11, "Medium auxiliary memory accessible"}, - {0x3F12, "iSCSI IP address added"}, - {0x3F13, "iSCSI IP address removed"}, - {0x3F14, "iSCSI IP address changed"}, -/* - * {0x40NN, "Ram failure"}, - * {0x40NN, "Diagnostic failure on component nn"}, - * {0x41NN, "Data path failure"}, - * {0x42NN, "Power-on or self-test failure"}, - */ - {0x4300, "Message error"}, - - {0x4400, "Internal target failure"}, - {0x4471, "ATA device failed set features"}, - - {0x4500, "Select or reselect failure"}, - - {0x4600, "Unsuccessful soft reset"}, - - {0x4700, "Scsi parity error"}, - {0x4701, "Data phase CRC error detected"}, - {0x4702, "Scsi parity error detected during st data phase"}, - {0x4703, "Information unit iuCRC error detected"}, - {0x4704, "Asynchronous information protection error detected"}, - {0x4705, "Protocol service CRC error"}, - {0x4706, "Phy test function in progress"}, - {0x477f, "Some commands cleared by iSCSI Protocol event"}, - - {0x4800, "Initiator detected error message received"}, - - {0x4900, "Invalid message error"}, - - {0x4A00, "Command phase error"}, - - {0x4B00, "Data phase error"}, - {0x4B01, "Invalid target port transfer tag received"}, - {0x4B02, "Too much write data"}, - {0x4B03, "Ack/nak timeout"}, - {0x4B04, "Nak received"}, - {0x4B05, "Data offset error"}, - {0x4B06, "Initiator response timeout"}, - - {0x4C00, "Logical unit failed self-configuration"}, -/* - * {0x4DNN, "Tagged overlapped commands (nn = queue tag)"}, - */ - {0x4E00, "Overlapped commands attempted"}, - - {0x5000, "Write append error"}, - {0x5001, "Write append position error"}, - {0x5002, "Position error related to timing"}, - - {0x5100, "Erase failure"}, - {0x5101, "Erase failure - incomplete erase operation detected"}, - - {0x5200, "Cartridge fault"}, - - {0x5300, "Media load or eject failed"}, - {0x5301, "Unload tape failure"}, - {0x5302, "Medium removal prevented"}, - {0x5303, "Medium removal prevented by data transfer element"}, - {0x5304, "Medium thread or unthread failure"}, - - {0x5400, "Scsi to host system interface failure"}, - - {0x5500, "System resource failure"}, - {0x5501, "System buffer full"}, - {0x5502, "Insufficient reservation resources"}, - {0x5503, "Insufficient resources"}, - {0x5504, "Insufficient registration resources"}, - {0x5505, "Insufficient access control resources"}, - {0x5506, "Auxiliary memory out of space"}, - {0x5507, "Quota error"}, - {0x5508, "Maximum number of supplemental decryption keys exceeded"}, - {0x5509, "Medium auxiliary memory not accessible"}, - {0x550A, "Data currently unavailable"}, - - {0x5700, "Unable to recover table-of-contents"}, - - {0x5800, "Generation does not exist"}, - - {0x5900, "Updated block read"}, - - {0x5A00, "Operator request or state change input"}, - {0x5A01, "Operator medium removal request"}, - {0x5A02, "Operator selected write protect"}, - {0x5A03, "Operator selected write permit"}, - - {0x5B00, "Log exception"}, - {0x5B01, "Threshold condition met"}, - {0x5B02, "Log counter at maximum"}, - {0x5B03, "Log list codes exhausted"}, - - {0x5C00, "Rpl status change"}, - {0x5C01, "Spindles synchronized"}, - {0x5C02, "Spindles not synchronized"}, - - {0x5D00, "Failure prediction threshold exceeded"}, - {0x5D01, "Media failure prediction threshold exceeded"}, - {0x5D02, "Logical unit failure prediction threshold exceeded"}, - {0x5D03, "Spare area exhaustion prediction threshold exceeded"}, - {0x5D10, "Hardware impending failure general hard drive failure"}, - {0x5D11, "Hardware impending failure drive error rate too high"}, - {0x5D12, "Hardware impending failure data error rate too high"}, - {0x5D13, "Hardware impending failure seek error rate too high"}, - {0x5D14, "Hardware impending failure too many block reassigns"}, - {0x5D15, "Hardware impending failure access times too high"}, - {0x5D16, "Hardware impending failure start unit times too high"}, - {0x5D17, "Hardware impending failure channel parametrics"}, - {0x5D18, "Hardware impending failure controller detected"}, - {0x5D19, "Hardware impending failure throughput performance"}, - {0x5D1A, "Hardware impending failure seek time performance"}, - {0x5D1B, "Hardware impending failure spin-up retry count"}, - {0x5D1C, "Hardware impending failure drive calibration retry count"}, - {0x5D20, "Controller impending failure general hard drive failure"}, - {0x5D21, "Controller impending failure drive error rate too high"}, - {0x5D22, "Controller impending failure data error rate too high"}, - {0x5D23, "Controller impending failure seek error rate too high"}, - {0x5D24, "Controller impending failure too many block reassigns"}, - {0x5D25, "Controller impending failure access times too high"}, - {0x5D26, "Controller impending failure start unit times too high"}, - {0x5D27, "Controller impending failure channel parametrics"}, - {0x5D28, "Controller impending failure controller detected"}, - {0x5D29, "Controller impending failure throughput performance"}, - {0x5D2A, "Controller impending failure seek time performance"}, - {0x5D2B, "Controller impending failure spin-up retry count"}, - {0x5D2C, "Controller impending failure drive calibration retry count"}, - {0x5D30, "Data channel impending failure general hard drive failure"}, - {0x5D31, "Data channel impending failure drive error rate too high"}, - {0x5D32, "Data channel impending failure data error rate too high"}, - {0x5D33, "Data channel impending failure seek error rate too high"}, - {0x5D34, "Data channel impending failure too many block reassigns"}, - {0x5D35, "Data channel impending failure access times too high"}, - {0x5D36, "Data channel impending failure start unit times too high"}, - {0x5D37, "Data channel impending failure channel parametrics"}, - {0x5D38, "Data channel impending failure controller detected"}, - {0x5D39, "Data channel impending failure throughput performance"}, - {0x5D3A, "Data channel impending failure seek time performance"}, - {0x5D3B, "Data channel impending failure spin-up retry count"}, - {0x5D3C, "Data channel impending failure drive calibration retry " - "count"}, - {0x5D40, "Servo impending failure general hard drive failure"}, - {0x5D41, "Servo impending failure drive error rate too high"}, - {0x5D42, "Servo impending failure data error rate too high"}, - {0x5D43, "Servo impending failure seek error rate too high"}, - {0x5D44, "Servo impending failure too many block reassigns"}, - {0x5D45, "Servo impending failure access times too high"}, - {0x5D46, "Servo impending failure start unit times too high"}, - {0x5D47, "Servo impending failure channel parametrics"}, - {0x5D48, "Servo impending failure controller detected"}, - {0x5D49, "Servo impending failure throughput performance"}, - {0x5D4A, "Servo impending failure seek time performance"}, - {0x5D4B, "Servo impending failure spin-up retry count"}, - {0x5D4C, "Servo impending failure drive calibration retry count"}, - {0x5D50, "Spindle impending failure general hard drive failure"}, - {0x5D51, "Spindle impending failure drive error rate too high"}, - {0x5D52, "Spindle impending failure data error rate too high"}, - {0x5D53, "Spindle impending failure seek error rate too high"}, - {0x5D54, "Spindle impending failure too many block reassigns"}, - {0x5D55, "Spindle impending failure access times too high"}, - {0x5D56, "Spindle impending failure start unit times too high"}, - {0x5D57, "Spindle impending failure channel parametrics"}, - {0x5D58, "Spindle impending failure controller detected"}, - {0x5D59, "Spindle impending failure throughput performance"}, - {0x5D5A, "Spindle impending failure seek time performance"}, - {0x5D5B, "Spindle impending failure spin-up retry count"}, - {0x5D5C, "Spindle impending failure drive calibration retry count"}, - {0x5D60, "Firmware impending failure general hard drive failure"}, - {0x5D61, "Firmware impending failure drive error rate too high"}, - {0x5D62, "Firmware impending failure data error rate too high"}, - {0x5D63, "Firmware impending failure seek error rate too high"}, - {0x5D64, "Firmware impending failure too many block reassigns"}, - {0x5D65, "Firmware impending failure access times too high"}, - {0x5D66, "Firmware impending failure start unit times too high"}, - {0x5D67, "Firmware impending failure channel parametrics"}, - {0x5D68, "Firmware impending failure controller detected"}, - {0x5D69, "Firmware impending failure throughput performance"}, - {0x5D6A, "Firmware impending failure seek time performance"}, - {0x5D6B, "Firmware impending failure spin-up retry count"}, - {0x5D6C, "Firmware impending failure drive calibration retry count"}, - {0x5DFF, "Failure prediction threshold exceeded (false)"}, - - {0x5E00, "Low power condition on"}, - {0x5E01, "Idle condition activated by timer"}, - {0x5E02, "Standby condition activated by timer"}, - {0x5E03, "Idle condition activated by command"}, - {0x5E04, "Standby condition activated by command"}, - {0x5E05, "Idle_b condition activated by timer"}, - {0x5E06, "Idle_b condition activated by command"}, - {0x5E07, "Idle_c condition activated by timer"}, - {0x5E08, "Idle_c condition activated by command"}, - {0x5E09, "Standby_y condition activated by timer"}, - {0x5E0A, "Standby_y condition activated by command"}, - {0x5E41, "Power state change to active"}, - {0x5E42, "Power state change to idle"}, - {0x5E43, "Power state change to standby"}, - {0x5E45, "Power state change to sleep"}, - {0x5E47, "Power state change to device control"}, - - {0x6000, "Lamp failure"}, - - {0x6100, "Video acquisition error"}, - {0x6101, "Unable to acquire video"}, - {0x6102, "Out of focus"}, - - {0x6200, "Scan head positioning error"}, - - {0x6300, "End of user area encountered on this track"}, - {0x6301, "Packet does not fit in available space"}, - - {0x6400, "Illegal mode for this track"}, - {0x6401, "Invalid packet size"}, - - {0x6500, "Voltage fault"}, - - {0x6600, "Automatic document feeder cover up"}, - {0x6601, "Automatic document feeder lift up"}, - {0x6602, "Document jam in automatic document feeder"}, - {0x6603, "Document miss feed automatic in document feeder"}, - - {0x6700, "Configuration failure"}, - {0x6701, "Configuration of incapable logical units failed"}, - {0x6702, "Add logical unit failed"}, - {0x6703, "Modification of logical unit failed"}, - {0x6704, "Exchange of logical unit failed"}, - {0x6705, "Remove of logical unit failed"}, - {0x6706, "Attachment of logical unit failed"}, - {0x6707, "Creation of logical unit failed"}, - {0x6708, "Assign failure occurred"}, - {0x6709, "Multiply assigned logical unit"}, - {0x670A, "Set target port groups command failed"}, - {0x670B, "ATA device feature not enabled"}, - - {0x6800, "Logical unit not configured"}, - - {0x6900, "Data loss on logical unit"}, - {0x6901, "Multiple logical unit failures"}, - {0x6902, "Parity/data mismatch"}, - - {0x6A00, "Informational, refer to log"}, - - {0x6B00, "State change has occurred"}, - {0x6B01, "Redundancy level got better"}, - {0x6B02, "Redundancy level got worse"}, - - {0x6C00, "Rebuild failure occurred"}, - - {0x6D00, "Recalculate failure occurred"}, - - {0x6E00, "Command to logical unit failed"}, - - {0x6F00, "Copy protection key exchange failure - authentication " - "failure"}, - {0x6F01, "Copy protection key exchange failure - key not present"}, - {0x6F02, "Copy protection key exchange failure - key not established"}, - {0x6F03, "Read of scrambled sector without authentication"}, - {0x6F04, "Media region code is mismatched to logical unit region"}, - {0x6F05, "Drive region must be permanent/region reset count error"}, - {0x6F06, "Insufficient block count for binding nonce recording"}, - {0x6F07, "Conflict in binding nonce recording"}, -/* - * {0x70NN, "Decompression exception short algorithm id of nn"}, - */ - {0x7100, "Decompression exception long algorithm id"}, - - {0x7200, "Session fixation error"}, - {0x7201, "Session fixation error writing lead-in"}, - {0x7202, "Session fixation error writing lead-out"}, - {0x7203, "Session fixation error - incomplete track in session"}, - {0x7204, "Empty or partially written reserved track"}, - {0x7205, "No more track reservations allowed"}, - {0x7206, "RMZ extension is not allowed"}, - {0x7207, "No more test zone extensions are allowed"}, - - {0x7300, "Cd control error"}, - {0x7301, "Power calibration area almost full"}, - {0x7302, "Power calibration area is full"}, - {0x7303, "Power calibration area error"}, - {0x7304, "Program memory area update failure"}, - {0x7305, "Program memory area is full"}, - {0x7306, "RMA/PMA is almost full"}, - {0x7310, "Current power calibration area almost full"}, - {0x7311, "Current power calibration area is full"}, - {0x7317, "RDZ is full"}, - - {0x7400, "Security error"}, - {0x7401, "Unable to decrypt data"}, - {0x7402, "Unencrypted data encountered while decrypting"}, - {0x7403, "Incorrect data encryption key"}, - {0x7404, "Cryptographic integrity validation failed"}, - {0x7405, "Error decrypting data"}, - {0x7406, "Unknown signature verification key"}, - {0x7407, "Encryption parameters not useable"}, - {0x7408, "Digital signature validation failure"}, - {0x7409, "Encryption mode mismatch on read"}, - {0x740A, "Encrypted block not raw read enabled"}, - {0x740B, "Incorrect Encryption parameters"}, - {0x740C, "Unable to decrypt parameter list"}, - {0x740D, "Encryption algorithm disabled"}, - {0x7410, "SA creation parameter value invalid"}, - {0x7411, "SA creation parameter value rejected"}, - {0x7412, "Invalid SA usage"}, - {0x7421, "Data Encryption configuration prevented"}, - {0x7430, "SA creation parameter not supported"}, - {0x7440, "Authentication failed"}, - {0x7461, "External data encryption key manager access error"}, - {0x7462, "External data encryption key manager error"}, - {0x7463, "External data encryption key not found"}, - {0x7464, "External data encryption request not authorized"}, - {0x746E, "External data encryption control timeout"}, - {0x746F, "External data encryption control error"}, - {0x7471, "Logical unit access not authorized"}, - {0x7479, "Security conflict in translated device"}, - - {0, NULL} -}; - -struct error_info2 { - unsigned char code1, code2_min, code2_max; - const char * fmt; -}; - -static const struct error_info2 additional2[] = -{ - {0x40, 0x00, 0x7f, "Ram failure (%x)"}, - {0x40, 0x80, 0xff, "Diagnostic failure on component (%x)"}, - {0x41, 0x00, 0xff, "Data path failure (%x)"}, - {0x42, 0x00, 0xff, "Power-on or self-test failure (%x)"}, - {0x4D, 0x00, 0xff, "Tagged overlapped commands (task tag %x)"}, - {0x70, 0x00, 0xff, "Decompression exception short algorithm id of %x"}, - {0, 0, 0, NULL} -}; - -/* description of the sense key values */ -static const char * const snstext[] = { - "No Sense", /* 0: There is no sense information */ - "Recovered Error", /* 1: The last command completed successfully - but used error correction */ - "Not Ready", /* 2: The addressed target is not ready */ - "Medium Error", /* 3: Data error detected on the medium */ - "Hardware Error", /* 4: Controller or device failure */ - "Illegal Request", /* 5: Error in request */ - "Unit Attention", /* 6: Removable medium was changed, or - the target has been reset, or ... */ - "Data Protect", /* 7: Access to the data is blocked */ - "Blank Check", /* 8: Reached unexpected written or unwritten - region of the medium */ - "Vendor Specific(9)", - "Copy Aborted", /* A: COPY or COMPARE was aborted */ - "Aborted Command", /* B: The target aborted the command */ - "Equal", /* C: A SEARCH DATA command found data equal */ - "Volume Overflow", /* D: Medium full with still data to be written */ - "Miscompare", /* E: Source data and data on the medium - do not agree */ -}; -#endif - -/* Get sense key string or NULL if not available */ -const char * -scsi_sense_key_string(unsigned char key) { -#ifdef CONFIG_SCSI_CONSTANTS - if (key <= 0xE) - return snstext[key]; -#endif - return NULL; -} -EXPORT_SYMBOL(scsi_sense_key_string); - -/* - * Get additional sense code string or NULL if not available. - * This string may contain a "%x" and should be printed with ascq as arg. - */ -const char * -scsi_extd_sense_format(unsigned char asc, unsigned char ascq) { -#ifdef CONFIG_SCSI_CONSTANTS - int i; - unsigned short code = ((asc << 8) | ascq); - - for (i = 0; additional[i].text; i++) - if (additional[i].code12 == code) - return additional[i].text; - for (i = 0; additional2[i].fmt; i++) { - if (additional2[i].code1 == asc && - ascq >= additional2[i].code2_min && - ascq <= additional2[i].code2_max) - return additional2[i].fmt; - } -#endif - return NULL; -} -EXPORT_SYMBOL(scsi_extd_sense_format); - -void -scsi_show_extd_sense(unsigned char asc, unsigned char ascq) -{ - const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq); - - if (extd_sense_fmt) { - if (strstr(extd_sense_fmt, "%x")) { - printk("Add. Sense: "); - printk(extd_sense_fmt, ascq); - } else - printk("Add. Sense: %s", extd_sense_fmt); - } else { - if (asc >= 0x80) - printk("<> ASC=0x%x ASCQ=0x%x", asc, - ascq); - if (ascq >= 0x80) - printk("ASC=0x%x <> ASCQ=0x%x", asc, - ascq); - else - printk("ASC=0x%x ASCQ=0x%x", asc, ascq); - } - - printk("\n"); -} -EXPORT_SYMBOL(scsi_show_extd_sense); - -void -scsi_show_sense_hdr(struct scsi_sense_hdr *sshdr) -{ - const char *sense_txt; - - sense_txt = scsi_sense_key_string(sshdr->sense_key); - if (sense_txt) - printk("Sense Key : %s ", sense_txt); - else - printk("Sense Key : 0x%x ", sshdr->sense_key); - - printk("%s", scsi_sense_is_deferred(sshdr) ? "[deferred] " : - "[current] "); - - if (sshdr->response_code >= 0x72) - printk("[descriptor]"); - - printk("\n"); -} -EXPORT_SYMBOL(scsi_show_sense_hdr); - -/* - * Print normalized SCSI sense header with a prefix. - */ -void -scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr) -{ - printk(KERN_INFO "%s: ", name); - scsi_show_sense_hdr(sshdr); - printk(KERN_INFO "%s: ", name); - scsi_show_extd_sense(sshdr->asc, sshdr->ascq); -} -EXPORT_SYMBOL(scsi_print_sense_hdr); - -/* - * Print normalized SCSI sense header with device information and a prefix. - */ -void -scsi_cmd_print_sense_hdr(struct scsi_cmnd *scmd, const char *desc, - struct scsi_sense_hdr *sshdr) -{ - scmd_printk(KERN_INFO, scmd, "%s: ", desc); - scsi_show_sense_hdr(sshdr); - scmd_printk(KERN_INFO, scmd, "%s: ", desc); - scsi_show_extd_sense(sshdr->asc, sshdr->ascq); -} -EXPORT_SYMBOL(scsi_cmd_print_sense_hdr); - -static void -scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len, - struct scsi_sense_hdr *sshdr) -{ - int k, num, res; - - res = scsi_normalize_sense(sense_buffer, sense_len, sshdr); - if (0 == res) { - /* this may be SCSI-1 sense data */ - num = (sense_len < 32) ? sense_len : 32; - printk("Unrecognized sense data (in hex):"); - for (k = 0; k < num; ++k) { - if (0 == (k % 16)) { - printk("\n"); - printk(KERN_INFO " "); - } - printk("%02x ", sense_buffer[k]); - } - printk("\n"); - return; - } -} - -static void -scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len, - struct scsi_sense_hdr *sshdr) -{ - int k, num, res; - - if (sshdr->response_code < 0x72) - { - /* only decode extras for "fixed" format now */ - char buff[80]; - int blen, fixed_valid; - unsigned int info; - - fixed_valid = sense_buffer[0] & 0x80; - info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) | - (sense_buffer[5] << 8) | sense_buffer[6]); - res = 0; - memset(buff, 0, sizeof(buff)); - blen = sizeof(buff) - 1; - if (fixed_valid) - res += snprintf(buff + res, blen - res, - "Info fld=0x%x", info); - if (sense_buffer[2] & 0x80) { - /* current command has read a filemark */ - if (res > 0) - res += snprintf(buff + res, blen - res, ", "); - res += snprintf(buff + res, blen - res, "FMK"); - } - if (sense_buffer[2] & 0x40) { - /* end-of-medium condition exists */ - if (res > 0) - res += snprintf(buff + res, blen - res, ", "); - res += snprintf(buff + res, blen - res, "EOM"); - } - if (sense_buffer[2] & 0x20) { - /* incorrect block length requested */ - if (res > 0) - res += snprintf(buff + res, blen - res, ", "); - res += snprintf(buff + res, blen - res, "ILI"); - } - if (res > 0) - printk("%s\n", buff); - } else if (sshdr->additional_length > 0) { - /* descriptor format with sense descriptors */ - num = 8 + sshdr->additional_length; - num = (sense_len < num) ? sense_len : num; - printk("Descriptor sense data with sense descriptors " - "(in hex):"); - for (k = 0; k < num; ++k) { - if (0 == (k % 16)) { - printk("\n"); - printk(KERN_INFO " "); - } - printk("%02x ", sense_buffer[k]); - } - - printk("\n"); - } - -} - -/* Normalize and print sense buffer with name prefix */ -void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, - int sense_len) -{ - struct scsi_sense_hdr sshdr; - - printk(KERN_INFO "%s: ", name); - scsi_decode_sense_buffer(sense_buffer, sense_len, &sshdr); - scsi_show_sense_hdr(&sshdr); - scsi_decode_sense_extras(sense_buffer, sense_len, &sshdr); - printk(KERN_INFO "%s: ", name); - scsi_show_extd_sense(sshdr.asc, sshdr.ascq); -} -EXPORT_SYMBOL(__scsi_print_sense); - -/* Normalize and print sense buffer in SCSI command */ -void scsi_print_sense(char *name, struct scsi_cmnd *cmd) -{ - struct scsi_sense_hdr sshdr; - - scmd_printk(KERN_INFO, cmd, " "); - scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, - &sshdr); - scsi_show_sense_hdr(&sshdr); - scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE, - &sshdr); - scmd_printk(KERN_INFO, cmd, " "); - scsi_show_extd_sense(sshdr.asc, sshdr.ascq); -} -EXPORT_SYMBOL(scsi_print_sense); - -#ifdef CONFIG_SCSI_CONSTANTS - -static const char * const hostbyte_table[]={ -"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", -"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR", -"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE", -"DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST" }; -#define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table) - -static const char * const driverbyte_table[]={ -"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR", -"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"}; -#define NUM_DRIVERBYTE_STRS ARRAY_SIZE(driverbyte_table) - -void scsi_show_result(int result) -{ - int hb = host_byte(result); - int db = driver_byte(result); - - printk("Result: hostbyte=%s driverbyte=%s\n", - (hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb] : "invalid"), - (db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid")); -} - -#else - -void scsi_show_result(int result) -{ - printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n", - host_byte(result), driver_byte(result)); -} - -#endif -EXPORT_SYMBOL(scsi_show_result); - - -void scsi_print_result(struct scsi_cmnd *cmd) -{ - scmd_printk(KERN_INFO, cmd, " "); - scsi_show_result(cmd->result); -} -EXPORT_SYMBOL(scsi_print_result); - - diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/Kconfig b/ANDROID_3.4.5/drivers/scsi/cxgbi/Kconfig deleted file mode 100644 index 17eb5d52..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -source "drivers/scsi/cxgbi/cxgb3i/Kconfig" -source "drivers/scsi/cxgbi/cxgb4i/Kconfig" diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/Makefile b/ANDROID_3.4.5/drivers/scsi/cxgbi/Makefile deleted file mode 100644 index 86007e34..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libcxgbi.o cxgb3i/ -obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libcxgbi.o cxgb4i/ diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kbuild b/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kbuild deleted file mode 100644 index 6f095e28..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kbuild +++ /dev/null @@ -1,3 +0,0 @@ -EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb3 - -obj-$(CONFIG_SCSI_CXGB3_ISCSI) += cxgb3i.o diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kconfig b/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kconfig deleted file mode 100644 index 6bbc36fb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config SCSI_CXGB3_ISCSI - tristate "Chelsio T3 iSCSI support" - depends on PCI && INET - select NETDEVICES - select ETHERNET - select NET_VENDOR_CHELSIO - select CHELSIO_T3 - select SCSI_ISCSI_ATTRS - ---help--- - This driver supports iSCSI offload for the Chelsio T3 devices. diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c deleted file mode 100644 index 36739da8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c +++ /dev/null @@ -1,1412 +0,0 @@ -/* - * cxgb3i_offload.c: Chelsio S3xx iscsi offloaded tcp connection management - * - * Copyright (C) 2003-2008 Chelsio Communications. All rights reserved. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this - * release for licensing terms and conditions. - * - * Written by: Dimitris Michailidis (dm@chelsio.com) - * Karen Xie (kxie@chelsio.com) - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include - -#include "common.h" -#include "t3_cpl.h" -#include "t3cdev.h" -#include "cxgb3_defs.h" -#include "cxgb3_ctl_defs.h" -#include "cxgb3_offload.h" -#include "firmware_exports.h" -#include "cxgb3i.h" - -static unsigned int dbg_level; -#include "../libcxgbi.h" - -#define DRV_MODULE_NAME "cxgb3i" -#define DRV_MODULE_DESC "Chelsio T3 iSCSI Driver" -#define DRV_MODULE_VERSION "2.0.0" -#define DRV_MODULE_RELDATE "Jun. 2010" - -static char version[] = - DRV_MODULE_DESC " " DRV_MODULE_NAME - " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; - -MODULE_AUTHOR("Chelsio Communications, Inc."); -MODULE_DESCRIPTION(DRV_MODULE_DESC); -MODULE_VERSION(DRV_MODULE_VERSION); -MODULE_LICENSE("GPL"); - -module_param(dbg_level, uint, 0644); -MODULE_PARM_DESC(dbg_level, "debug flag (default=0)"); - -static int cxgb3i_rcv_win = 256 * 1024; -module_param(cxgb3i_rcv_win, int, 0644); -MODULE_PARM_DESC(cxgb3i_rcv_win, "TCP receive window in bytes (default=256KB)"); - -static int cxgb3i_snd_win = 128 * 1024; -module_param(cxgb3i_snd_win, int, 0644); -MODULE_PARM_DESC(cxgb3i_snd_win, "TCP send window in bytes (default=128KB)"); - -static int cxgb3i_rx_credit_thres = 10 * 1024; -module_param(cxgb3i_rx_credit_thres, int, 0644); -MODULE_PARM_DESC(rx_credit_thres, - "RX credits return threshold in bytes (default=10KB)"); - -static unsigned int cxgb3i_max_connect = 8 * 1024; -module_param(cxgb3i_max_connect, uint, 0644); -MODULE_PARM_DESC(cxgb3i_max_connect, "Max. # of connections (default=8092)"); - -static unsigned int cxgb3i_sport_base = 20000; -module_param(cxgb3i_sport_base, uint, 0644); -MODULE_PARM_DESC(cxgb3i_sport_base, "starting port number (default=20000)"); - -static void cxgb3i_dev_open(struct t3cdev *); -static void cxgb3i_dev_close(struct t3cdev *); -static void cxgb3i_dev_event_handler(struct t3cdev *, u32, u32); - -static struct cxgb3_client t3_client = { - .name = DRV_MODULE_NAME, - .handlers = cxgb3i_cpl_handlers, - .add = cxgb3i_dev_open, - .remove = cxgb3i_dev_close, - .event_handler = cxgb3i_dev_event_handler, -}; - -static struct scsi_host_template cxgb3i_host_template = { - .module = THIS_MODULE, - .name = DRV_MODULE_NAME, - .proc_name = DRV_MODULE_NAME, - .can_queue = CXGB3I_SCSI_HOST_QDEPTH, - .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, - .sg_tablesize = SG_ALL, - .max_sectors = 0xFFFF, - .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, - .eh_abort_handler = iscsi_eh_abort, - .eh_device_reset_handler = iscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_recover_target, - .target_alloc = iscsi_target_alloc, - .use_clustering = DISABLE_CLUSTERING, - .this_id = -1, -}; - -static struct iscsi_transport cxgb3i_iscsi_transport = { - .owner = THIS_MODULE, - .name = DRV_MODULE_NAME, - /* owner and name should be set already */ - .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST - | CAP_DATADGST | CAP_DIGEST_OFFLOAD | - CAP_PADDING_OFFLOAD | CAP_TEXT_NEGO, - .attr_is_visible = cxgbi_attr_is_visible, - .get_host_param = cxgbi_get_host_param, - .set_host_param = cxgbi_set_host_param, - /* session management */ - .create_session = cxgbi_create_session, - .destroy_session = cxgbi_destroy_session, - .get_session_param = iscsi_session_get_param, - /* connection management */ - .create_conn = cxgbi_create_conn, - .bind_conn = cxgbi_bind_conn, - .destroy_conn = iscsi_tcp_conn_teardown, - .start_conn = iscsi_conn_start, - .stop_conn = iscsi_conn_stop, - .get_conn_param = iscsi_conn_get_param, - .set_param = cxgbi_set_conn_param, - .get_stats = cxgbi_get_conn_stats, - /* pdu xmit req from user space */ - .send_pdu = iscsi_conn_send_pdu, - /* task */ - .init_task = iscsi_tcp_task_init, - .xmit_task = iscsi_tcp_task_xmit, - .cleanup_task = cxgbi_cleanup_task, - /* pdu */ - .alloc_pdu = cxgbi_conn_alloc_pdu, - .init_pdu = cxgbi_conn_init_pdu, - .xmit_pdu = cxgbi_conn_xmit_pdu, - .parse_pdu_itt = cxgbi_parse_pdu_itt, - /* TCP connect/disconnect */ - .get_ep_param = cxgbi_get_ep_param, - .ep_connect = cxgbi_ep_connect, - .ep_poll = cxgbi_ep_poll, - .ep_disconnect = cxgbi_ep_disconnect, - /* Error recovery timeout call */ - .session_recovery_timedout = iscsi_session_recovery_timedout, -}; - -static struct scsi_transport_template *cxgb3i_stt; - -/* - * CPL (Chelsio Protocol Language) defines a message passing interface between - * the host driver and Chelsio asic. - * The section below implments CPLs that related to iscsi tcp connection - * open/close/abort and data send/receive. - */ - -static int push_tx_frames(struct cxgbi_sock *csk, int req_completion); - -static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, - const struct l2t_entry *e) -{ - unsigned int wscale = cxgbi_sock_compute_wscale(cxgb3i_rcv_win); - struct cpl_act_open_req *req = (struct cpl_act_open_req *)skb->head; - - skb->priority = CPL_PRIORITY_SETUP; - - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, csk->atid)); - req->local_port = csk->saddr.sin_port; - req->peer_port = csk->daddr.sin_port; - req->local_ip = csk->saddr.sin_addr.s_addr; - req->peer_ip = csk->daddr.sin_addr.s_addr; - - req->opt0h = htonl(V_KEEP_ALIVE(1) | F_TCAM_BYPASS | - V_WND_SCALE(wscale) | V_MSS_IDX(csk->mss_idx) | - V_L2T_IDX(e->idx) | V_TX_CHANNEL(e->smt_idx)); - req->opt0l = htonl(V_ULP_MODE(ULP2_MODE_ISCSI) | - V_RCV_BUFSIZ(cxgb3i_rcv_win>>10)); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, %pI4:%u-%pI4:%u, %u,%u,%u.\n", - csk, csk->state, csk->flags, csk->atid, - &req->local_ip, ntohs(req->local_port), - &req->peer_ip, ntohs(req->peer_port), - csk->mss_idx, e->idx, e->smt_idx); - - l2t_send(csk->cdev->lldev, skb, csk->l2t); -} - -static inline void act_open_arp_failure(struct t3cdev *dev, struct sk_buff *skb) -{ - cxgbi_sock_act_open_req_arp_failure(NULL, skb); -} - -/* - * CPL connection close request: host -> - * - * Close a connection by sending a CPL_CLOSE_CON_REQ message and queue it to - * the write queue (i.e., after any unsent txt data). - */ -static void send_close_req(struct cxgbi_sock *csk) -{ - struct sk_buff *skb = csk->cpl_close; - struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head; - unsigned int tid = csk->tid; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - - csk->cpl_close = NULL; - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_CLOSE_CON)); - req->wr.wr_lo = htonl(V_WR_TID(tid)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); - req->rsvd = htonl(csk->write_seq); - - cxgbi_sock_skb_entail(csk, skb); - if (csk->state >= CTP_ESTABLISHED) - push_tx_frames(csk, 1); -} - -/* - * CPL connection abort request: host -> - * - * Send an ABORT_REQ message. Makes sure we do not send multiple ABORT_REQs - * for the same connection and also that we do not try to send a message - * after the connection has closed. - */ -static void abort_arp_failure(struct t3cdev *tdev, struct sk_buff *skb) -{ - struct cpl_abort_req *req = cplhdr(skb); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "t3dev 0x%p, tid %u, skb 0x%p.\n", - tdev, GET_TID(req), skb); - req->cmd = CPL_ABORT_NO_RST; - cxgb3_ofld_send(tdev, skb); -} - -static void send_abort_req(struct cxgbi_sock *csk) -{ - struct sk_buff *skb = csk->cpl_abort_req; - struct cpl_abort_req *req; - - if (unlikely(csk->state == CTP_ABORTING || !skb)) - return; - cxgbi_sock_set_state(csk, CTP_ABORTING); - cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_PENDING); - /* Purge the send queue so we don't send anything after an abort. */ - cxgbi_sock_purge_write_queue(csk); - - csk->cpl_abort_req = NULL; - req = (struct cpl_abort_req *)skb->head; - skb->priority = CPL_PRIORITY_DATA; - set_arp_failure_handler(skb, abort_arp_failure); - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ)); - req->wr.wr_lo = htonl(V_WR_TID(csk->tid)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_ABORT_REQ, csk->tid)); - req->rsvd0 = htonl(csk->snd_nxt); - req->rsvd1 = !cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT); - req->cmd = CPL_ABORT_SEND_RST; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, snd_nxt %u, 0x%x.\n", - csk, csk->state, csk->flags, csk->tid, csk->snd_nxt, - req->rsvd1); - - l2t_send(csk->cdev->lldev, skb, csk->l2t); -} - -/* - * CPL connection abort reply: host -> - * - * Send an ABORT_RPL message in response of the ABORT_REQ received. - */ -static void send_abort_rpl(struct cxgbi_sock *csk, int rst_status) -{ - struct sk_buff *skb = csk->cpl_abort_rpl; - struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, status %d.\n", - csk, csk->state, csk->flags, csk->tid, rst_status); - - csk->cpl_abort_rpl = NULL; - skb->priority = CPL_PRIORITY_DATA; - rpl->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL)); - rpl->wr.wr_lo = htonl(V_WR_TID(csk->tid)); - OPCODE_TID(rpl) = htonl(MK_OPCODE_TID(CPL_ABORT_RPL, csk->tid)); - rpl->cmd = rst_status; - cxgb3_ofld_send(csk->cdev->lldev, skb); -} - -/* - * CPL connection rx data ack: host -> - * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of - * credits sent. - */ -static u32 send_rx_credits(struct cxgbi_sock *csk, u32 credits) -{ - struct sk_buff *skb; - struct cpl_rx_data_ack *req; - u32 dack = F_RX_DACK_CHANGE | V_RX_DACK_MODE(1); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lx,%u, credit %u, dack %u.\n", - csk, csk->state, csk->flags, csk->tid, credits, dack); - - skb = alloc_wr(sizeof(*req), 0, GFP_ATOMIC); - if (!skb) { - pr_info("csk 0x%p, credit %u, OOM.\n", csk, credits); - return 0; - } - req = (struct cpl_rx_data_ack *)skb->head; - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_RX_DATA_ACK, csk->tid)); - req->credit_dack = htonl(F_RX_DACK_CHANGE | V_RX_DACK_MODE(1) | - V_RX_CREDITS(credits)); - skb->priority = CPL_PRIORITY_ACK; - cxgb3_ofld_send(csk->cdev->lldev, skb); - return credits; -} - -/* - * CPL connection tx data: host -> - * - * Send iscsi PDU via TX_DATA CPL message. Returns the number of - * credits sent. - * Each TX_DATA consumes work request credit (wrs), so we need to keep track of - * how many we've used so far and how many are pending (i.e., yet ack'ed by T3). - */ - -static unsigned int wrlen __read_mostly; -static unsigned int skb_wrs[SKB_WR_LIST_SIZE] __read_mostly; - -static void init_wr_tab(unsigned int wr_len) -{ - int i; - - if (skb_wrs[1]) /* already initialized */ - return; - for (i = 1; i < SKB_WR_LIST_SIZE; i++) { - int sgl_len = (3 * i) / 2 + (i & 1); - - sgl_len += 3; - skb_wrs[i] = (sgl_len <= wr_len - ? 1 : 1 + (sgl_len - 2) / (wr_len - 1)); - } - wrlen = wr_len * 8; -} - -static inline void make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, - int len, int req_completion) -{ - struct tx_data_wr *req; - struct l2t_entry *l2t = csk->l2t; - - skb_reset_transport_header(skb); - req = (struct tx_data_wr *)__skb_push(skb, sizeof(*req)); - req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA) | - (req_completion ? F_WR_COMPL : 0)); - req->wr_lo = htonl(V_WR_TID(csk->tid)); - /* len includes the length of any HW ULP additions */ - req->len = htonl(len); - /* V_TX_ULP_SUBMODE sets both the mode and submode */ - req->flags = htonl(V_TX_ULP_SUBMODE(cxgbi_skcb_ulp_mode(skb)) | - V_TX_SHOVE((skb_peek(&csk->write_queue) ? 0 : 1))); - req->sndseq = htonl(csk->snd_nxt); - req->param = htonl(V_TX_PORT(l2t->smt_idx)); - - if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { - req->flags |= htonl(V_TX_ACK_PAGES(2) | F_TX_INIT | - V_TX_CPU_IDX(csk->rss_qid)); - /* sendbuffer is in units of 32KB. */ - req->param |= htonl(V_TX_SNDBUF(cxgb3i_snd_win >> 15)); - cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); - } -} - -/** - * push_tx_frames -- start transmit - * @c3cn: the offloaded connection - * @req_completion: request wr_ack or not - * - * Prepends TX_DATA_WR or CPL_CLOSE_CON_REQ headers to buffers waiting in a - * connection's send queue and sends them on to T3. Must be called with the - * connection's lock held. Returns the amount of send buffer space that was - * freed as a result of sending queued data to T3. - */ - -static void arp_failure_skb_discard(struct t3cdev *dev, struct sk_buff *skb) -{ - kfree_skb(skb); -} - -static int push_tx_frames(struct cxgbi_sock *csk, int req_completion) -{ - int total_size = 0; - struct sk_buff *skb; - - if (unlikely(csk->state < CTP_ESTABLISHED || - csk->state == CTP_CLOSE_WAIT_1 || csk->state >= CTP_ABORTING)) { - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, - "csk 0x%p,%u,0x%lx,%u, in closing state.\n", - csk, csk->state, csk->flags, csk->tid); - return 0; - } - - while (csk->wr_cred && (skb = skb_peek(&csk->write_queue)) != NULL) { - int len = skb->len; /* length before skb_push */ - int frags = skb_shinfo(skb)->nr_frags + (len != skb->data_len); - int wrs_needed = skb_wrs[frags]; - - if (wrs_needed > 1 && len + sizeof(struct tx_data_wr) <= wrlen) - wrs_needed = 1; - - WARN_ON(frags >= SKB_WR_LIST_SIZE || wrs_needed < 1); - - if (csk->wr_cred < wrs_needed) { - log_debug(1 << CXGBI_DBG_PDU_TX, - "csk 0x%p, skb len %u/%u, frag %u, wr %d<%u.\n", - csk, skb->len, skb->data_len, frags, - wrs_needed, csk->wr_cred); - break; - } - - __skb_unlink(skb, &csk->write_queue); - skb->priority = CPL_PRIORITY_DATA; - skb->csum = wrs_needed; /* remember this until the WR_ACK */ - csk->wr_cred -= wrs_needed; - csk->wr_una_cred += wrs_needed; - cxgbi_sock_enqueue_wr(csk, skb); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, - "csk 0x%p, enqueue, skb len %u/%u, frag %u, wr %d, " - "left %u, unack %u.\n", - csk, skb->len, skb->data_len, frags, skb->csum, - csk->wr_cred, csk->wr_una_cred); - - if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) { - if ((req_completion && - csk->wr_una_cred == wrs_needed) || - csk->wr_una_cred >= csk->wr_max_cred / 2) { - req_completion = 1; - csk->wr_una_cred = 0; - } - len += cxgbi_ulp_extra_len(cxgbi_skcb_ulp_mode(skb)); - make_tx_data_wr(csk, skb, len, req_completion); - csk->snd_nxt += len; - cxgbi_skcb_clear_flag(skb, SKCBF_TX_NEED_HDR); - } - total_size += skb->truesize; - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, - "csk 0x%p, tid 0x%x, send skb 0x%p.\n", - csk, csk->tid, skb); - set_arp_failure_handler(skb, arp_failure_skb_discard); - l2t_send(csk->cdev->lldev, skb, csk->l2t); - } - return total_size; -} - -/* - * Process a CPL_ACT_ESTABLISH message: -> host - * Updates connection state from an active establish CPL message. Runs with - * the connection lock held. - */ - -static inline void free_atid(struct cxgbi_sock *csk) -{ - if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) { - cxgb3_free_atid(csk->cdev->lldev, csk->atid); - cxgbi_sock_clear_flag(csk, CTPF_HAS_ATID); - cxgbi_sock_put(csk); - } -} - -static int do_act_establish(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) -{ - struct cxgbi_sock *csk = ctx; - struct cpl_act_establish *req = cplhdr(skb); - unsigned int tid = GET_TID(req); - unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid)); - u32 rcv_isn = ntohl(req->rcv_isn); /* real RCV_ISN + 1 */ - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "atid 0x%x,tid 0x%x, csk 0x%p,%u,0x%lx, isn %u.\n", - atid, atid, csk, csk->state, csk->flags, rcv_isn); - - cxgbi_sock_get(csk); - cxgbi_sock_set_flag(csk, CTPF_HAS_TID); - csk->tid = tid; - cxgb3_insert_tid(csk->cdev->lldev, &t3_client, csk, tid); - - free_atid(csk); - - csk->rss_qid = G_QNUM(ntohs(skb->csum)); - - spin_lock_bh(&csk->lock); - if (csk->retry_timer.function) { - del_timer(&csk->retry_timer); - csk->retry_timer.function = NULL; - } - - if (unlikely(csk->state != CTP_ACTIVE_OPEN)) - pr_info("csk 0x%p,%u,0x%lx,%u, got EST.\n", - csk, csk->state, csk->flags, csk->tid); - - csk->copied_seq = csk->rcv_wup = csk->rcv_nxt = rcv_isn; - if (cxgb3i_rcv_win > (M_RCV_BUFSIZ << 10)) - csk->rcv_wup -= cxgb3i_rcv_win - (M_RCV_BUFSIZ << 10); - - cxgbi_sock_established(csk, ntohl(req->snd_isn), ntohs(req->tcp_opt)); - - if (unlikely(cxgbi_sock_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED))) - /* upper layer has requested closing */ - send_abort_req(csk); - else { - if (skb_queue_len(&csk->write_queue)) - push_tx_frames(csk, 1); - cxgbi_conn_tx_open(csk); - } - - spin_unlock_bh(&csk->lock); - __kfree_skb(skb); - return 0; -} - -/* - * Process a CPL_ACT_OPEN_RPL message: -> host - * Handle active open failures. - */ -static int act_open_rpl_status_to_errno(int status) -{ - switch (status) { - case CPL_ERR_CONN_RESET: - return -ECONNREFUSED; - case CPL_ERR_ARP_MISS: - return -EHOSTUNREACH; - case CPL_ERR_CONN_TIMEDOUT: - return -ETIMEDOUT; - case CPL_ERR_TCAM_FULL: - return -ENOMEM; - case CPL_ERR_CONN_EXIST: - return -EADDRINUSE; - default: - return -EIO; - } -} - -static void act_open_retry_timer(unsigned long data) -{ - struct sk_buff *skb; - struct cxgbi_sock *csk = (struct cxgbi_sock *)data; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_ATOMIC); - if (!skb) - cxgbi_sock_fail_act_open(csk, -ENOMEM); - else { - skb->sk = (struct sock *)csk; - set_arp_failure_handler(skb, act_open_arp_failure); - send_act_open_req(csk, skb, csk->l2t); - } - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); -} - -static int do_act_open_rpl(struct t3cdev *tdev, struct sk_buff *skb, void *ctx) -{ - struct cxgbi_sock *csk = ctx; - struct cpl_act_open_rpl *rpl = cplhdr(skb); - - pr_info("csk 0x%p,%u,0x%lx,%u, status %u, %pI4:%u-%pI4:%u.\n", - csk, csk->state, csk->flags, csk->atid, rpl->status, - &csk->saddr.sin_addr.s_addr, ntohs(csk->saddr.sin_port), - &csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port)); - - if (rpl->status != CPL_ERR_TCAM_FULL && - rpl->status != CPL_ERR_CONN_EXIST && - rpl->status != CPL_ERR_ARP_MISS) - cxgb3_queue_tid_release(tdev, GET_TID(rpl)); - - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - if (rpl->status == CPL_ERR_CONN_EXIST && - csk->retry_timer.function != act_open_retry_timer) { - csk->retry_timer.function = act_open_retry_timer; - mod_timer(&csk->retry_timer, jiffies + HZ / 2); - } else - cxgbi_sock_fail_act_open(csk, - act_open_rpl_status_to_errno(rpl->status)); - - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); - __kfree_skb(skb); - return 0; -} - -/* - * Process PEER_CLOSE CPL messages: -> host - * Handle peer FIN. - */ -static int do_peer_close(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - struct cxgbi_sock *csk = ctx; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - - cxgbi_sock_rcv_peer_close(csk); - __kfree_skb(skb); - return 0; -} - -/* - * Process CLOSE_CONN_RPL CPL message: -> host - * Process a peer ACK to our FIN. - */ -static int do_close_con_rpl(struct t3cdev *cdev, struct sk_buff *skb, - void *ctx) -{ - struct cxgbi_sock *csk = ctx; - struct cpl_close_con_rpl *rpl = cplhdr(skb); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, snxt %u.\n", - csk, csk->state, csk->flags, csk->tid, ntohl(rpl->snd_nxt)); - - cxgbi_sock_rcv_close_conn_rpl(csk, ntohl(rpl->snd_nxt)); - __kfree_skb(skb); - return 0; -} - -/* - * Process ABORT_REQ_RSS CPL message: -> host - * Process abort requests. If we are waiting for an ABORT_RPL we ignore this - * request except that we need to reply to it. - */ - -static int abort_status_to_errno(struct cxgbi_sock *csk, int abort_reason, - int *need_rst) -{ - switch (abort_reason) { - case CPL_ERR_BAD_SYN: /* fall through */ - case CPL_ERR_CONN_RESET: - return csk->state > CTP_ESTABLISHED ? -EPIPE : -ECONNRESET; - case CPL_ERR_XMIT_TIMEDOUT: - case CPL_ERR_PERSIST_TIMEDOUT: - case CPL_ERR_FINWAIT2_TIMEDOUT: - case CPL_ERR_KEEPALIVE_TIMEDOUT: - return -ETIMEDOUT; - default: - return -EIO; - } -} - -static int do_abort_req(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - const struct cpl_abort_req_rss *req = cplhdr(skb); - struct cxgbi_sock *csk = ctx; - int rst_status = CPL_ABORT_NO_RST; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - - if (req->status == CPL_ERR_RTX_NEG_ADVICE || - req->status == CPL_ERR_PERSIST_NEG_ADVICE) { - goto done; - } - - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - - if (!cxgbi_sock_flag(csk, CTPF_ABORT_REQ_RCVD)) { - cxgbi_sock_set_flag(csk, CTPF_ABORT_REQ_RCVD); - cxgbi_sock_set_state(csk, CTP_ABORTING); - goto out; - } - - cxgbi_sock_clear_flag(csk, CTPF_ABORT_REQ_RCVD); - send_abort_rpl(csk, rst_status); - - if (!cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { - csk->err = abort_status_to_errno(csk, req->status, &rst_status); - cxgbi_sock_closed(csk); - } - -out: - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); -done: - __kfree_skb(skb); - return 0; -} - -/* - * Process ABORT_RPL_RSS CPL message: -> host - * Process abort replies. We only process these messages if we anticipate - * them as the coordination between SW and HW in this area is somewhat lacking - * and sometimes we get ABORT_RPLs after we are done with the connection that - * originated the ABORT_REQ. - */ -static int do_abort_rpl(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - struct cpl_abort_rpl_rss *rpl = cplhdr(skb); - struct cxgbi_sock *csk = ctx; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "status 0x%x, csk 0x%p, s %u, 0x%lx.\n", - rpl->status, csk, csk ? csk->state : 0, - csk ? csk->flags : 0UL); - /* - * Ignore replies to post-close aborts indicating that the abort was - * requested too late. These connections are terminated when we get - * PEER_CLOSE or CLOSE_CON_RPL and by the time the abort_rpl_rss - * arrives the TID is either no longer used or it has been recycled. - */ - if (rpl->status == CPL_ERR_ABORT_FAILED) - goto rel_skb; - /* - * Sometimes we've already closed the connection, e.g., a post-close - * abort races with ABORT_REQ_RSS, the latter frees the connection - * expecting the ABORT_REQ will fail with CPL_ERR_ABORT_FAILED, - * but FW turns the ABORT_REQ into a regular one and so we get - * ABORT_RPL_RSS with status 0 and no connection. - */ - if (csk) - cxgbi_sock_rcv_abort_rpl(csk); -rel_skb: - __kfree_skb(skb); - return 0; -} - -/* - * Process RX_ISCSI_HDR CPL message: -> host - * Handle received PDUs, the payload could be DDP'ed. If not, the payload - * follow after the bhs. - */ -static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx) -{ - struct cxgbi_sock *csk = ctx; - struct cpl_iscsi_hdr *hdr_cpl = cplhdr(skb); - struct cpl_iscsi_hdr_norss data_cpl; - struct cpl_rx_data_ddp_norss ddp_cpl; - unsigned int hdr_len, data_len, status; - unsigned int len; - int err; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lx,%u, skb 0x%p,%u.\n", - csk, csk->state, csk->flags, csk->tid, skb, skb->len); - - spin_lock_bh(&csk->lock); - - if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, bad state.\n", - csk, csk->state, csk->flags, csk->tid); - if (csk->state != CTP_ABORTING) - goto abort_conn; - else - goto discard; - } - - cxgbi_skcb_tcp_seq(skb) = ntohl(hdr_cpl->seq); - cxgbi_skcb_flags(skb) = 0; - - skb_reset_transport_header(skb); - __skb_pull(skb, sizeof(struct cpl_iscsi_hdr)); - - len = hdr_len = ntohs(hdr_cpl->len); - /* msg coalesce is off or not enough data received */ - if (skb->len <= hdr_len) { - pr_err("%s: tid %u, CPL_ISCSI_HDR, skb len %u < %u.\n", - csk->cdev->ports[csk->port_id]->name, csk->tid, - skb->len, hdr_len); - goto abort_conn; - } - cxgbi_skcb_set_flag(skb, SKCBF_RX_COALESCED); - - err = skb_copy_bits(skb, skb->len - sizeof(ddp_cpl), &ddp_cpl, - sizeof(ddp_cpl)); - if (err < 0) { - pr_err("%s: tid %u, copy cpl_ddp %u-%zu failed %d.\n", - csk->cdev->ports[csk->port_id]->name, csk->tid, - skb->len, sizeof(ddp_cpl), err); - goto abort_conn; - } - - cxgbi_skcb_set_flag(skb, SKCBF_RX_STATUS); - cxgbi_skcb_rx_pdulen(skb) = ntohs(ddp_cpl.len); - cxgbi_skcb_rx_ddigest(skb) = ntohl(ddp_cpl.ulp_crc); - status = ntohl(ddp_cpl.ddp_status); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, skb 0x%p,%u, pdulen %u, status 0x%x.\n", - csk, skb, skb->len, cxgbi_skcb_rx_pdulen(skb), status); - - if (status & (1 << CPL_RX_DDP_STATUS_HCRC_SHIFT)) - cxgbi_skcb_set_flag(skb, SKCBF_RX_HCRC_ERR); - if (status & (1 << CPL_RX_DDP_STATUS_DCRC_SHIFT)) - cxgbi_skcb_set_flag(skb, SKCBF_RX_DCRC_ERR); - if (status & (1 << CPL_RX_DDP_STATUS_PAD_SHIFT)) - cxgbi_skcb_set_flag(skb, SKCBF_RX_PAD_ERR); - - if (skb->len > (hdr_len + sizeof(ddp_cpl))) { - err = skb_copy_bits(skb, hdr_len, &data_cpl, sizeof(data_cpl)); - if (err < 0) { - pr_err("%s: tid %u, cp %zu/%u failed %d.\n", - csk->cdev->ports[csk->port_id]->name, - csk->tid, sizeof(data_cpl), skb->len, err); - goto abort_conn; - } - data_len = ntohs(data_cpl.len); - log_debug(1 << CXGBI_DBG_DDP | 1 << CXGBI_DBG_PDU_RX, - "skb 0x%p, pdu not ddp'ed %u/%u, status 0x%x.\n", - skb, data_len, cxgbi_skcb_rx_pdulen(skb), status); - len += sizeof(data_cpl) + data_len; - } else if (status & (1 << CPL_RX_DDP_STATUS_DDP_SHIFT)) - cxgbi_skcb_set_flag(skb, SKCBF_RX_DATA_DDPD); - - csk->rcv_nxt = ntohl(ddp_cpl.seq) + cxgbi_skcb_rx_pdulen(skb); - __pskb_trim(skb, len); - __skb_queue_tail(&csk->receive_queue, skb); - cxgbi_conn_pdu_ready(csk); - - spin_unlock_bh(&csk->lock); - return 0; - -abort_conn: - send_abort_req(csk); -discard: - spin_unlock_bh(&csk->lock); - __kfree_skb(skb); - return 0; -} - -/* - * Process TX_DATA_ACK CPL messages: -> host - * Process an acknowledgment of WR completion. Advance snd_una and send the - * next batch of work requests from the write queue. - */ -static int do_wr_ack(struct t3cdev *cdev, struct sk_buff *skb, void *ctx) -{ - struct cxgbi_sock *csk = ctx; - struct cpl_wr_ack *hdr = cplhdr(skb); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lx,%u, cr %u.\n", - csk, csk->state, csk->flags, csk->tid, ntohs(hdr->credits)); - - cxgbi_sock_rcv_wr_ack(csk, ntohs(hdr->credits), ntohl(hdr->snd_una), 1); - __kfree_skb(skb); - return 0; -} - -/* - * for each connection, pre-allocate skbs needed for close/abort requests. So - * that we can service the request right away. - */ -static int alloc_cpls(struct cxgbi_sock *csk) -{ - csk->cpl_close = alloc_wr(sizeof(struct cpl_close_con_req), 0, - GFP_KERNEL); - if (!csk->cpl_close) - return -ENOMEM; - csk->cpl_abort_req = alloc_wr(sizeof(struct cpl_abort_req), 0, - GFP_KERNEL); - if (!csk->cpl_abort_req) - goto free_cpl_skbs; - - csk->cpl_abort_rpl = alloc_wr(sizeof(struct cpl_abort_rpl), 0, - GFP_KERNEL); - if (!csk->cpl_abort_rpl) - goto free_cpl_skbs; - - return 0; - -free_cpl_skbs: - cxgbi_sock_free_cpl_skbs(csk); - return -ENOMEM; -} - -/** - * release_offload_resources - release offload resource - * @c3cn: the offloaded iscsi tcp connection. - * Release resources held by an offload connection (TID, L2T entry, etc.) - */ -static void l2t_put(struct cxgbi_sock *csk) -{ - struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev; - - if (csk->l2t) { - l2t_release(t3dev, csk->l2t); - csk->l2t = NULL; - cxgbi_sock_put(csk); - } -} - -static void release_offload_resources(struct cxgbi_sock *csk) -{ - struct t3cdev *t3dev = (struct t3cdev *)csk->cdev->lldev; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - - csk->rss_qid = 0; - cxgbi_sock_free_cpl_skbs(csk); - - if (csk->wr_cred != csk->wr_max_cred) { - cxgbi_sock_purge_wr_queue(csk); - cxgbi_sock_reset_wr_list(csk); - } - l2t_put(csk); - if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) - free_atid(csk); - else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) { - cxgb3_remove_tid(t3dev, (void *)csk, csk->tid); - cxgbi_sock_clear_flag(csk, CTPF_HAS_TID); - cxgbi_sock_put(csk); - } - csk->dst = NULL; - csk->cdev = NULL; -} - -static void update_address(struct cxgbi_hba *chba) -{ - if (chba->ipv4addr) { - if (chba->vdev && - chba->ipv4addr != cxgb3i_get_private_ipv4addr(chba->vdev)) { - cxgb3i_set_private_ipv4addr(chba->vdev, chba->ipv4addr); - cxgb3i_set_private_ipv4addr(chba->ndev, 0); - pr_info("%s set %pI4.\n", - chba->vdev->name, &chba->ipv4addr); - } else if (chba->ipv4addr != - cxgb3i_get_private_ipv4addr(chba->ndev)) { - cxgb3i_set_private_ipv4addr(chba->ndev, chba->ipv4addr); - pr_info("%s set %pI4.\n", - chba->ndev->name, &chba->ipv4addr); - } - } else if (cxgb3i_get_private_ipv4addr(chba->ndev)) { - if (chba->vdev) - cxgb3i_set_private_ipv4addr(chba->vdev, 0); - cxgb3i_set_private_ipv4addr(chba->ndev, 0); - } -} - -static int init_act_open(struct cxgbi_sock *csk) -{ - struct dst_entry *dst = csk->dst; - struct cxgbi_device *cdev = csk->cdev; - struct t3cdev *t3dev = (struct t3cdev *)cdev->lldev; - struct net_device *ndev = cdev->ports[csk->port_id]; - struct cxgbi_hba *chba = cdev->hbas[csk->port_id]; - struct sk_buff *skb = NULL; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx.\n", csk, csk->state, csk->flags); - - update_address(chba); - if (chba->ipv4addr) - csk->saddr.sin_addr.s_addr = chba->ipv4addr; - - csk->rss_qid = 0; - csk->l2t = t3_l2t_get(t3dev, dst, ndev); - if (!csk->l2t) { - pr_err("NO l2t available.\n"); - return -EINVAL; - } - cxgbi_sock_get(csk); - - csk->atid = cxgb3_alloc_atid(t3dev, &t3_client, csk); - if (csk->atid < 0) { - pr_err("NO atid available.\n"); - goto rel_resource; - } - cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); - cxgbi_sock_get(csk); - - skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_KERNEL); - if (!skb) - goto rel_resource; - skb->sk = (struct sock *)csk; - set_arp_failure_handler(skb, act_open_arp_failure); - - csk->wr_max_cred = csk->wr_cred = T3C_DATA(t3dev)->max_wrs - 1; - csk->wr_una_cred = 0; - csk->mss_idx = cxgbi_sock_select_mss(csk, dst_mtu(dst)); - cxgbi_sock_reset_wr_list(csk); - csk->err = 0; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, %pI4:%u-%pI4:%u.\n", - csk, csk->state, csk->flags, - &csk->saddr.sin_addr.s_addr, ntohs(csk->saddr.sin_port), - &csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port)); - - cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); - send_act_open_req(csk, skb, csk->l2t); - return 0; - -rel_resource: - if (skb) - __kfree_skb(skb); - return -EINVAL; -} - -cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS] = { - [CPL_ACT_ESTABLISH] = do_act_establish, - [CPL_ACT_OPEN_RPL] = do_act_open_rpl, - [CPL_PEER_CLOSE] = do_peer_close, - [CPL_ABORT_REQ_RSS] = do_abort_req, - [CPL_ABORT_RPL_RSS] = do_abort_rpl, - [CPL_CLOSE_CON_RPL] = do_close_con_rpl, - [CPL_TX_DMA_ACK] = do_wr_ack, - [CPL_ISCSI_HDR] = do_iscsi_hdr, -}; - -/** - * cxgb3i_ofld_init - allocate and initialize resources for each adapter found - * @cdev: cxgbi adapter - */ -int cxgb3i_ofld_init(struct cxgbi_device *cdev) -{ - struct t3cdev *t3dev = (struct t3cdev *)cdev->lldev; - struct adap_ports port; - struct ofld_page_info rx_page_info; - unsigned int wr_len; - int rc; - - if (t3dev->ctl(t3dev, GET_WR_LEN, &wr_len) < 0 || - t3dev->ctl(t3dev, GET_PORTS, &port) < 0 || - t3dev->ctl(t3dev, GET_RX_PAGE_INFO, &rx_page_info) < 0) { - pr_warn("t3 0x%p, offload up, ioctl failed.\n", t3dev); - return -EINVAL; - } - - if (cxgb3i_max_connect > CXGBI_MAX_CONN) - cxgb3i_max_connect = CXGBI_MAX_CONN; - - rc = cxgbi_device_portmap_create(cdev, cxgb3i_sport_base, - cxgb3i_max_connect); - if (rc < 0) - return rc; - - init_wr_tab(wr_len); - cdev->csk_release_offload_resources = release_offload_resources; - cdev->csk_push_tx_frames = push_tx_frames; - cdev->csk_send_abort_req = send_abort_req; - cdev->csk_send_close_req = send_close_req; - cdev->csk_send_rx_credits = send_rx_credits; - cdev->csk_alloc_cpls = alloc_cpls; - cdev->csk_init_act_open = init_act_open; - - pr_info("cdev 0x%p, offload up, added.\n", cdev); - return 0; -} - -/* - * functions to program the pagepod in h/w - */ -static inline void ulp_mem_io_set_hdr(struct sk_buff *skb, unsigned int addr) -{ - struct ulp_mem_io *req = (struct ulp_mem_io *)skb->head; - - memset(req, 0, sizeof(*req)); - - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_BYPASS)); - req->cmd_lock_addr = htonl(V_ULP_MEMIO_ADDR(addr >> 5) | - V_ULPTX_CMD(ULP_MEM_WRITE)); - req->len = htonl(V_ULP_MEMIO_DATA_LEN(PPOD_SIZE >> 5) | - V_ULPTX_NFLITS((PPOD_SIZE >> 3) + 1)); -} - -static int ddp_set_map(struct cxgbi_sock *csk, struct cxgbi_pagepod_hdr *hdr, - unsigned int idx, unsigned int npods, - struct cxgbi_gather_list *gl) -{ - struct cxgbi_device *cdev = csk->cdev; - struct cxgbi_ddp_info *ddp = cdev->ddp; - unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; - int i; - - log_debug(1 << CXGBI_DBG_DDP, - "csk 0x%p, idx %u, npods %u, gl 0x%p.\n", - csk, idx, npods, gl); - - for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { - struct sk_buff *skb = alloc_wr(sizeof(struct ulp_mem_io) + - PPOD_SIZE, 0, GFP_ATOMIC); - - if (!skb) - return -ENOMEM; - - ulp_mem_io_set_hdr(skb, pm_addr); - cxgbi_ddp_ppod_set((struct cxgbi_pagepod *)(skb->head + - sizeof(struct ulp_mem_io)), - hdr, gl, i * PPOD_PAGES_MAX); - skb->priority = CPL_PRIORITY_CONTROL; - cxgb3_ofld_send(cdev->lldev, skb); - } - return 0; -} - -static void ddp_clear_map(struct cxgbi_hba *chba, unsigned int tag, - unsigned int idx, unsigned int npods) -{ - struct cxgbi_device *cdev = chba->cdev; - struct cxgbi_ddp_info *ddp = cdev->ddp; - unsigned int pm_addr = (idx << PPOD_SIZE_SHIFT) + ddp->llimit; - int i; - - log_debug(1 << CXGBI_DBG_DDP, - "cdev 0x%p, idx %u, npods %u, tag 0x%x.\n", - cdev, idx, npods, tag); - - for (i = 0; i < npods; i++, idx++, pm_addr += PPOD_SIZE) { - struct sk_buff *skb = alloc_wr(sizeof(struct ulp_mem_io) + - PPOD_SIZE, 0, GFP_ATOMIC); - - if (!skb) { - pr_err("tag 0x%x, 0x%x, %d/%u, skb OOM.\n", - tag, idx, i, npods); - continue; - } - ulp_mem_io_set_hdr(skb, pm_addr); - skb->priority = CPL_PRIORITY_CONTROL; - cxgb3_ofld_send(cdev->lldev, skb); - } -} - -static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, - unsigned int tid, int pg_idx, bool reply) -{ - struct sk_buff *skb = alloc_wr(sizeof(struct cpl_set_tcb_field), 0, - GFP_KERNEL); - struct cpl_set_tcb_field *req; - u64 val = pg_idx < DDP_PGIDX_MAX ? pg_idx : 0; - - log_debug(1 << CXGBI_DBG_DDP, - "csk 0x%p, tid %u, pg_idx %d.\n", csk, tid, pg_idx); - if (!skb) - return -ENOMEM; - - /* set up ulp submode and page size */ - req = (struct cpl_set_tcb_field *)skb->head; - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); - req->reply = V_NO_REPLY(reply ? 0 : 1); - req->cpu_idx = 0; - req->word = htons(31); - req->mask = cpu_to_be64(0xF0000000); - req->val = cpu_to_be64(val << 28); - skb->priority = CPL_PRIORITY_CONTROL; - - cxgb3_ofld_send(csk->cdev->lldev, skb); - return 0; -} - -/** - * cxgb3i_setup_conn_digest - setup conn. digest setting - * @csk: cxgb tcp socket - * @tid: connection id - * @hcrc: header digest enabled - * @dcrc: data digest enabled - * @reply: request reply from h/w - * set up the iscsi digest settings for a connection identified by tid - */ -static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, - int hcrc, int dcrc, int reply) -{ - struct sk_buff *skb = alloc_wr(sizeof(struct cpl_set_tcb_field), 0, - GFP_KERNEL); - struct cpl_set_tcb_field *req; - u64 val = (hcrc ? 1 : 0) | (dcrc ? 2 : 0); - - log_debug(1 << CXGBI_DBG_DDP, - "csk 0x%p, tid %u, crc %d,%d.\n", csk, tid, hcrc, dcrc); - if (!skb) - return -ENOMEM; - - /* set up ulp submode and page size */ - req = (struct cpl_set_tcb_field *)skb->head; - req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD)); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); - req->reply = V_NO_REPLY(reply ? 0 : 1); - req->cpu_idx = 0; - req->word = htons(31); - req->mask = cpu_to_be64(0x0F000000); - req->val = cpu_to_be64(val << 24); - skb->priority = CPL_PRIORITY_CONTROL; - - cxgb3_ofld_send(csk->cdev->lldev, skb); - return 0; -} - -/** - * t3_ddp_cleanup - release the cxgb3 adapter's ddp resource - * @cdev: cxgb3i adapter - * release all the resource held by the ddp pagepod manager for a given - * adapter if needed - */ - -static void t3_ddp_cleanup(struct cxgbi_device *cdev) -{ - struct t3cdev *tdev = (struct t3cdev *)cdev->lldev; - - if (cxgbi_ddp_cleanup(cdev)) { - pr_info("t3dev 0x%p, ulp_iscsi no more user.\n", tdev); - tdev->ulp_iscsi = NULL; - } -} - -/** - * ddp_init - initialize the cxgb3 adapter's ddp resource - * @cdev: cxgb3i adapter - * initialize the ddp pagepod manager for a given adapter - */ -static int cxgb3i_ddp_init(struct cxgbi_device *cdev) -{ - struct t3cdev *tdev = (struct t3cdev *)cdev->lldev; - struct cxgbi_ddp_info *ddp = tdev->ulp_iscsi; - struct ulp_iscsi_info uinfo; - unsigned int pgsz_factor[4]; - int i, err; - - if (ddp) { - kref_get(&ddp->refcnt); - pr_warn("t3dev 0x%p, ddp 0x%p already set up.\n", - tdev, tdev->ulp_iscsi); - cdev->ddp = ddp; - return -EALREADY; - } - - err = tdev->ctl(tdev, ULP_ISCSI_GET_PARAMS, &uinfo); - if (err < 0) { - pr_err("%s, failed to get iscsi param err=%d.\n", - tdev->name, err); - return err; - } - - err = cxgbi_ddp_init(cdev, uinfo.llimit, uinfo.ulimit, - uinfo.max_txsz, uinfo.max_rxsz); - if (err < 0) - return err; - - ddp = cdev->ddp; - - uinfo.tagmask = ddp->idx_mask << PPOD_IDX_SHIFT; - cxgbi_ddp_page_size_factor(pgsz_factor); - for (i = 0; i < 4; i++) - uinfo.pgsz_factor[i] = pgsz_factor[i]; - uinfo.ulimit = uinfo.llimit + (ddp->nppods << PPOD_SIZE_SHIFT); - - err = tdev->ctl(tdev, ULP_ISCSI_SET_PARAMS, &uinfo); - if (err < 0) { - pr_warn("%s unable to set iscsi param err=%d, ddp disabled.\n", - tdev->name, err); - cxgbi_ddp_cleanup(cdev); - return err; - } - tdev->ulp_iscsi = ddp; - - cdev->csk_ddp_setup_digest = ddp_setup_conn_digest; - cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx; - cdev->csk_ddp_set = ddp_set_map; - cdev->csk_ddp_clear = ddp_clear_map; - - pr_info("tdev 0x%p, nppods %u, bits %u, mask 0x%x,0x%x pkt %u/%u, " - "%u/%u.\n", - tdev, ddp->nppods, ddp->idx_bits, ddp->idx_mask, - ddp->rsvd_tag_mask, ddp->max_txsz, uinfo.max_txsz, - ddp->max_rxsz, uinfo.max_rxsz); - return 0; -} - -static void cxgb3i_dev_close(struct t3cdev *t3dev) -{ - struct cxgbi_device *cdev = cxgbi_device_find_by_lldev(t3dev); - - if (!cdev || cdev->flags & CXGBI_FLAG_ADAPTER_RESET) { - pr_info("0x%p close, f 0x%x.\n", cdev, cdev ? cdev->flags : 0); - return; - } - - cxgbi_device_unregister(cdev); -} - -/** - * cxgb3i_dev_open - init a t3 adapter structure and any h/w settings - * @t3dev: t3cdev adapter - */ -static void cxgb3i_dev_open(struct t3cdev *t3dev) -{ - struct cxgbi_device *cdev = cxgbi_device_find_by_lldev(t3dev); - struct adapter *adapter = tdev2adap(t3dev); - int i, err; - - if (cdev) { - pr_info("0x%p, updating.\n", cdev); - return; - } - - cdev = cxgbi_device_register(0, adapter->params.nports); - if (!cdev) { - pr_warn("device 0x%p register failed.\n", t3dev); - return; - } - - cdev->flags = CXGBI_FLAG_DEV_T3 | CXGBI_FLAG_IPV4_SET; - cdev->lldev = t3dev; - cdev->pdev = adapter->pdev; - cdev->ports = adapter->port; - cdev->nports = adapter->params.nports; - cdev->mtus = adapter->params.mtus; - cdev->nmtus = NMTUS; - cdev->snd_win = cxgb3i_snd_win; - cdev->rcv_win = cxgb3i_rcv_win; - cdev->rx_credit_thres = cxgb3i_rx_credit_thres; - cdev->skb_tx_rsvd = CXGB3I_TX_HEADER_LEN; - cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr_norss); - cdev->dev_ddp_cleanup = t3_ddp_cleanup; - cdev->itp = &cxgb3i_iscsi_transport; - - err = cxgb3i_ddp_init(cdev); - if (err) { - pr_info("0x%p ddp init failed\n", cdev); - goto err_out; - } - - err = cxgb3i_ofld_init(cdev); - if (err) { - pr_info("0x%p offload init failed\n", cdev); - goto err_out; - } - - err = cxgbi_hbas_add(cdev, CXGB3I_MAX_LUN, CXGBI_MAX_CONN, - &cxgb3i_host_template, cxgb3i_stt); - if (err) - goto err_out; - - for (i = 0; i < cdev->nports; i++) - cdev->hbas[i]->ipv4addr = - cxgb3i_get_private_ipv4addr(cdev->ports[i]); - - pr_info("cdev 0x%p, f 0x%x, t3dev 0x%p open, err %d.\n", - cdev, cdev ? cdev->flags : 0, t3dev, err); - return; - -err_out: - cxgbi_device_unregister(cdev); -} - -static void cxgb3i_dev_event_handler(struct t3cdev *t3dev, u32 event, u32 port) -{ - struct cxgbi_device *cdev = cxgbi_device_find_by_lldev(t3dev); - - log_debug(1 << CXGBI_DBG_TOE, - "0x%p, cdev 0x%p, event 0x%x, port 0x%x.\n", - t3dev, cdev, event, port); - if (!cdev) - return; - - switch (event) { - case OFFLOAD_STATUS_DOWN: - cdev->flags |= CXGBI_FLAG_ADAPTER_RESET; - break; - case OFFLOAD_STATUS_UP: - cdev->flags &= ~CXGBI_FLAG_ADAPTER_RESET; - break; - } -} - -/** - * cxgb3i_init_module - module init entry point - * - * initialize any driver wide global data structures and register itself - * with the cxgb3 module - */ -static int __init cxgb3i_init_module(void) -{ - int rc; - - printk(KERN_INFO "%s", version); - - rc = cxgbi_iscsi_init(&cxgb3i_iscsi_transport, &cxgb3i_stt); - if (rc < 0) - return rc; - - cxgb3_register_client(&t3_client); - return 0; -} - -/** - * cxgb3i_exit_module - module cleanup/exit entry point - * - * go through the driver hba list and for each hba, release any resource held. - * and unregisters iscsi transport and the cxgb3 module - */ -static void __exit cxgb3i_exit_module(void) -{ - cxgb3_unregister_client(&t3_client); - cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T3); - cxgbi_iscsi_cleanup(&cxgb3i_iscsi_transport, &cxgb3i_stt); -} - -module_init(cxgb3i_init_module); -module_exit(cxgb3i_exit_module); diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h b/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h deleted file mode 100644 index 20593fd6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb3i/cxgb3i.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * cxgb3i.h: Chelsio S3xx iSCSI driver. - * - * Copyright (c) 2008 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - */ - -#ifndef __CXGB3I_H__ -#define __CXGB3I_H__ - -#define CXGB3I_SCSI_HOST_QDEPTH 1024 -#define CXGB3I_MAX_LUN 512 -#define ISCSI_PDU_NONPAYLOAD_MAX \ - (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE + 2*ISCSI_DIGEST_SIZE) - -/*for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ -#define CXGB3I_TX_HEADER_LEN \ - (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr)) - -extern cxgb3_cpl_handler_func cxgb3i_cpl_handlers[NUM_CPL_CMDS]; - -static inline unsigned int cxgb3i_get_private_ipv4addr(struct net_device *ndev) -{ - return ((struct port_info *)(netdev_priv(ndev)))->iscsi_ipv4addr; -} - -static inline void cxgb3i_set_private_ipv4addr(struct net_device *ndev, - unsigned int addr) -{ - struct port_info *pi = (struct port_info *)netdev_priv(ndev); - - pi->iscsic.flags = addr ? 1 : 0; - pi->iscsi_ipv4addr = addr; - if (addr) - memcpy(pi->iscsic.mac_addr, ndev->dev_addr, ETH_ALEN); -} - -struct cpl_iscsi_hdr_norss { - union opcode_tid ot; - u16 pdu_len_ddp; - u16 len; - u32 seq; - u16 urg; - u8 rsvd; - u8 status; -}; - -struct cpl_rx_data_ddp_norss { - union opcode_tid ot; - u16 urg; - u16 len; - u32 seq; - u32 nxt_seq; - u32 ulp_crc; - u32 ddp_status; -}; -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kbuild b/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kbuild deleted file mode 100644 index 8290cdaa..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kbuild +++ /dev/null @@ -1,3 +0,0 @@ -EXTRA_CFLAGS += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4 - -obj-$(CONFIG_SCSI_CXGB4_ISCSI) += cxgb4i.o diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kconfig b/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kconfig deleted file mode 100644 index 16b2c7d2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config SCSI_CXGB4_ISCSI - tristate "Chelsio T4 iSCSI support" - depends on PCI && INET - select NETDEVICES - select ETHERNET - select NET_VENDOR_CHELSIO - select CHELSIO_T4 - select SCSI_ISCSI_ATTRS - ---help--- - This driver supports iSCSI offload for the Chelsio T4 devices. diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c deleted file mode 100644 index 5a4a3bfc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ /dev/null @@ -1,1593 +0,0 @@ -/* - * cxgb4i.c: Chelsio T4 iSCSI driver. - * - * Copyright (c) 2010 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - * Rakesh Ranjan (rranjan@chelsio.com) - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include - -#include "t4_msg.h" -#include "cxgb4.h" -#include "cxgb4_uld.h" -#include "t4fw_api.h" -#include "l2t.h" -#include "cxgb4i.h" - -static unsigned int dbg_level; - -#include "../libcxgbi.h" - -#define DRV_MODULE_NAME "cxgb4i" -#define DRV_MODULE_DESC "Chelsio T4 iSCSI Driver" -#define DRV_MODULE_VERSION "0.9.1" -#define DRV_MODULE_RELDATE "Aug. 2010" - -static char version[] = - DRV_MODULE_DESC " " DRV_MODULE_NAME - " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; - -MODULE_AUTHOR("Chelsio Communications, Inc."); -MODULE_DESCRIPTION(DRV_MODULE_DESC); -MODULE_VERSION(DRV_MODULE_VERSION); -MODULE_LICENSE("GPL"); - -module_param(dbg_level, uint, 0644); -MODULE_PARM_DESC(dbg_level, "Debug flag (default=0)"); - -static int cxgb4i_rcv_win = 256 * 1024; -module_param(cxgb4i_rcv_win, int, 0644); -MODULE_PARM_DESC(cxgb4i_rcv_win, "TCP reveive window in bytes"); - -static int cxgb4i_snd_win = 128 * 1024; -module_param(cxgb4i_snd_win, int, 0644); -MODULE_PARM_DESC(cxgb4i_snd_win, "TCP send window in bytes"); - -static int cxgb4i_rx_credit_thres = 10 * 1024; -module_param(cxgb4i_rx_credit_thres, int, 0644); -MODULE_PARM_DESC(cxgb4i_rx_credit_thres, - "RX credits return threshold in bytes (default=10KB)"); - -static unsigned int cxgb4i_max_connect = (8 * 1024); -module_param(cxgb4i_max_connect, uint, 0644); -MODULE_PARM_DESC(cxgb4i_max_connect, "Maximum number of connections"); - -static unsigned short cxgb4i_sport_base = 20000; -module_param(cxgb4i_sport_base, ushort, 0644); -MODULE_PARM_DESC(cxgb4i_sport_base, "Starting port number (default 20000)"); - -typedef void (*cxgb4i_cplhandler_func)(struct cxgbi_device *, struct sk_buff *); - -static void *t4_uld_add(const struct cxgb4_lld_info *); -static int t4_uld_rx_handler(void *, const __be64 *, const struct pkt_gl *); -static int t4_uld_state_change(void *, enum cxgb4_state state); - -static const struct cxgb4_uld_info cxgb4i_uld_info = { - .name = DRV_MODULE_NAME, - .add = t4_uld_add, - .rx_handler = t4_uld_rx_handler, - .state_change = t4_uld_state_change, -}; - -static struct scsi_host_template cxgb4i_host_template = { - .module = THIS_MODULE, - .name = DRV_MODULE_NAME, - .proc_name = DRV_MODULE_NAME, - .can_queue = CXGB4I_SCSI_HOST_QDEPTH, - .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, - .sg_tablesize = SG_ALL, - .max_sectors = 0xFFFF, - .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, - .eh_abort_handler = iscsi_eh_abort, - .eh_device_reset_handler = iscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_recover_target, - .target_alloc = iscsi_target_alloc, - .use_clustering = DISABLE_CLUSTERING, - .this_id = -1, -}; - -static struct iscsi_transport cxgb4i_iscsi_transport = { - .owner = THIS_MODULE, - .name = DRV_MODULE_NAME, - .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST | - CAP_DATADGST | CAP_DIGEST_OFFLOAD | - CAP_PADDING_OFFLOAD | CAP_TEXT_NEGO, - .attr_is_visible = cxgbi_attr_is_visible, - .get_host_param = cxgbi_get_host_param, - .set_host_param = cxgbi_set_host_param, - /* session management */ - .create_session = cxgbi_create_session, - .destroy_session = cxgbi_destroy_session, - .get_session_param = iscsi_session_get_param, - /* connection management */ - .create_conn = cxgbi_create_conn, - .bind_conn = cxgbi_bind_conn, - .destroy_conn = iscsi_tcp_conn_teardown, - .start_conn = iscsi_conn_start, - .stop_conn = iscsi_conn_stop, - .get_conn_param = iscsi_conn_get_param, - .set_param = cxgbi_set_conn_param, - .get_stats = cxgbi_get_conn_stats, - /* pdu xmit req from user space */ - .send_pdu = iscsi_conn_send_pdu, - /* task */ - .init_task = iscsi_tcp_task_init, - .xmit_task = iscsi_tcp_task_xmit, - .cleanup_task = cxgbi_cleanup_task, - /* pdu */ - .alloc_pdu = cxgbi_conn_alloc_pdu, - .init_pdu = cxgbi_conn_init_pdu, - .xmit_pdu = cxgbi_conn_xmit_pdu, - .parse_pdu_itt = cxgbi_parse_pdu_itt, - /* TCP connect/disconnect */ - .get_ep_param = cxgbi_get_ep_param, - .ep_connect = cxgbi_ep_connect, - .ep_poll = cxgbi_ep_poll, - .ep_disconnect = cxgbi_ep_disconnect, - /* Error recovery timeout call */ - .session_recovery_timedout = iscsi_session_recovery_timedout, -}; - -static struct scsi_transport_template *cxgb4i_stt; - -/* - * CPL (Chelsio Protocol Language) defines a message passing interface between - * the host driver and Chelsio asic. - * The section below implments CPLs that related to iscsi tcp connection - * open/close/abort and data send/receive. - */ -#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) -#define RCV_BUFSIZ_MASK 0x3FFU -#define MAX_IMM_TX_PKT_LEN 128 - -static inline void set_queue(struct sk_buff *skb, unsigned int queue, - const struct cxgbi_sock *csk) -{ - skb->queue_mapping = queue; -} - -static int push_tx_frames(struct cxgbi_sock *, int); - -/* - * is_ofld_imm - check whether a packet can be sent as immediate data - * @skb: the packet - * - * Returns true if a packet can be sent as an offload WR with immediate - * data. We currently use the same limit as for Ethernet packets. - */ -static inline int is_ofld_imm(const struct sk_buff *skb) -{ - return skb->len <= (MAX_IMM_TX_PKT_LEN - - sizeof(struct fw_ofld_tx_data_wr)); -} - -static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, - struct l2t_entry *e) -{ - struct cpl_act_open_req *req; - int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); - unsigned long long opt0; - unsigned int opt2; - unsigned int qid_atid = ((unsigned int)csk->atid) | - (((unsigned int)csk->rss_qid) << 14); - - opt0 = KEEP_ALIVE(1) | - WND_SCALE(wscale) | - MSS_IDX(csk->mss_idx) | - L2T_IDX(((struct l2t_entry *)csk->l2t)->idx) | - TX_CHAN(csk->tx_chan) | - SMAC_SEL(csk->smac_idx) | - ULP_MODE(ULP_MODE_ISCSI) | - RCV_BUFSIZ(cxgb4i_rcv_win >> 10); - opt2 = RX_CHANNEL(0) | - RSS_QUEUE_VALID | - (1 << 20) | (1 << 22) | - RSS_QUEUE(csk->rss_qid); - - set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); - req = (struct cpl_act_open_req *)skb->head; - - INIT_TP_WR(req, 0); - OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, - qid_atid)); - req->local_port = csk->saddr.sin_port; - req->peer_port = csk->daddr.sin_port; - req->local_ip = csk->saddr.sin_addr.s_addr; - req->peer_ip = csk->daddr.sin_addr.s_addr; - req->opt0 = cpu_to_be64(opt0); - req->params = 0; - req->opt2 = cpu_to_be32(opt2); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", - csk, &req->local_ip, ntohs(req->local_port), - &req->peer_ip, ntohs(req->peer_port), - csk->atid, csk->rss_qid); - - cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); -} - -static void send_close_req(struct cxgbi_sock *csk) -{ - struct sk_buff *skb = csk->cpl_close; - struct cpl_close_con_req *req = (struct cpl_close_con_req *)skb->head; - unsigned int tid = csk->tid; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, tid %u.\n", - csk, csk->state, csk->flags, csk->tid); - csk->cpl_close = NULL; - set_wr_txq(skb, CPL_PRIORITY_DATA, csk->port_id); - INIT_TP_WR(req, tid); - OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_CLOSE_CON_REQ, tid)); - req->rsvd = 0; - - cxgbi_sock_skb_entail(csk, skb); - if (csk->state >= CTP_ESTABLISHED) - push_tx_frames(csk, 1); -} - -static void abort_arp_failure(void *handle, struct sk_buff *skb) -{ - struct cxgbi_sock *csk = (struct cxgbi_sock *)handle; - struct cpl_abort_req *req; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, tid %u, abort.\n", - csk, csk->state, csk->flags, csk->tid); - req = (struct cpl_abort_req *)skb->data; - req->cmd = CPL_ABORT_NO_RST; - cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); -} - -static void send_abort_req(struct cxgbi_sock *csk) -{ - struct cpl_abort_req *req; - struct sk_buff *skb = csk->cpl_abort_req; - - if (unlikely(csk->state == CTP_ABORTING) || !skb || !csk->cdev) - return; - cxgbi_sock_set_state(csk, CTP_ABORTING); - cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_PENDING); - cxgbi_sock_purge_write_queue(csk); - - csk->cpl_abort_req = NULL; - req = (struct cpl_abort_req *)skb->head; - set_queue(skb, CPL_PRIORITY_DATA, csk); - req->cmd = CPL_ABORT_SEND_RST; - t4_set_arp_err_handler(skb, csk, abort_arp_failure); - INIT_TP_WR(req, csk->tid); - OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_REQ, csk->tid)); - req->rsvd0 = htonl(csk->snd_nxt); - req->rsvd1 = !cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, snd_nxt %u, 0x%x.\n", - csk, csk->state, csk->flags, csk->tid, csk->snd_nxt, - req->rsvd1); - - cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); -} - -static void send_abort_rpl(struct cxgbi_sock *csk, int rst_status) -{ - struct sk_buff *skb = csk->cpl_abort_rpl; - struct cpl_abort_rpl *rpl = (struct cpl_abort_rpl *)skb->head; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, status %d.\n", - csk, csk->state, csk->flags, csk->tid, rst_status); - - csk->cpl_abort_rpl = NULL; - set_queue(skb, CPL_PRIORITY_DATA, csk); - INIT_TP_WR(rpl, csk->tid); - OPCODE_TID(rpl) = cpu_to_be32(MK_OPCODE_TID(CPL_ABORT_RPL, csk->tid)); - rpl->cmd = rst_status; - cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); -} - -/* - * CPL connection rx data ack: host -> - * Send RX credits through an RX_DATA_ACK CPL message. Returns the number of - * credits sent. - */ -static u32 send_rx_credits(struct cxgbi_sock *csk, u32 credits) -{ - struct sk_buff *skb; - struct cpl_rx_data_ack *req; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lx,%u, credit %u.\n", - csk, csk->state, csk->flags, csk->tid, credits); - - skb = alloc_wr(sizeof(*req), 0, GFP_ATOMIC); - if (!skb) { - pr_info("csk 0x%p, credit %u, OOM.\n", csk, credits); - return 0; - } - req = (struct cpl_rx_data_ack *)skb->head; - - set_wr_txq(skb, CPL_PRIORITY_ACK, csk->port_id); - INIT_TP_WR(req, csk->tid); - OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK, - csk->tid)); - req->credit_dack = cpu_to_be32(RX_CREDITS(credits) | RX_FORCE_ACK(1)); - cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); - return credits; -} - -/* - * sgl_len - calculates the size of an SGL of the given capacity - * @n: the number of SGL entries - * Calculates the number of flits needed for a scatter/gather list that - * can hold the given number of entries. - */ -static inline unsigned int sgl_len(unsigned int n) -{ - n--; - return (3 * n) / 2 + (n & 1) + 2; -} - -/* - * calc_tx_flits_ofld - calculate # of flits for an offload packet - * @skb: the packet - * - * Returns the number of flits needed for the given offload packet. - * These packets are already fully constructed and no additional headers - * will be added. - */ -static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) -{ - unsigned int flits, cnt; - - if (is_ofld_imm(skb)) - return DIV_ROUND_UP(skb->len, 8); - flits = skb_transport_offset(skb) / 8; - cnt = skb_shinfo(skb)->nr_frags; - if (skb->tail != skb->transport_header) - cnt++; - return flits + sgl_len(cnt); -} - -static inline void send_tx_flowc_wr(struct cxgbi_sock *csk) -{ - struct sk_buff *skb; - struct fw_flowc_wr *flowc; - int flowclen, i; - - flowclen = 80; - skb = alloc_wr(flowclen, 0, GFP_ATOMIC); - flowc = (struct fw_flowc_wr *)skb->head; - flowc->op_to_nparams = - htonl(FW_WR_OP(FW_FLOWC_WR) | FW_FLOWC_WR_NPARAMS(8)); - flowc->flowid_len16 = - htonl(FW_WR_LEN16(DIV_ROUND_UP(72, 16)) | - FW_WR_FLOWID(csk->tid)); - flowc->mnemval[0].mnemonic = FW_FLOWC_MNEM_PFNVFN; - flowc->mnemval[0].val = htonl(csk->cdev->pfvf); - flowc->mnemval[1].mnemonic = FW_FLOWC_MNEM_CH; - flowc->mnemval[1].val = htonl(csk->tx_chan); - flowc->mnemval[2].mnemonic = FW_FLOWC_MNEM_PORT; - flowc->mnemval[2].val = htonl(csk->tx_chan); - flowc->mnemval[3].mnemonic = FW_FLOWC_MNEM_IQID; - flowc->mnemval[3].val = htonl(csk->rss_qid); - flowc->mnemval[4].mnemonic = FW_FLOWC_MNEM_SNDNXT; - flowc->mnemval[4].val = htonl(csk->snd_nxt); - flowc->mnemval[5].mnemonic = FW_FLOWC_MNEM_RCVNXT; - flowc->mnemval[5].val = htonl(csk->rcv_nxt); - flowc->mnemval[6].mnemonic = FW_FLOWC_MNEM_SNDBUF; - flowc->mnemval[6].val = htonl(cxgb4i_snd_win); - flowc->mnemval[7].mnemonic = FW_FLOWC_MNEM_MSS; - flowc->mnemval[7].val = htonl(csk->advmss); - flowc->mnemval[8].mnemonic = 0; - flowc->mnemval[8].val = 0; - for (i = 0; i < 9; i++) { - flowc->mnemval[i].r4[0] = 0; - flowc->mnemval[i].r4[1] = 0; - flowc->mnemval[i].r4[2] = 0; - } - set_queue(skb, CPL_PRIORITY_DATA, csk); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p, tid 0x%x, %u,%u,%u,%u,%u,%u,%u.\n", - csk, csk->tid, 0, csk->tx_chan, csk->rss_qid, - csk->snd_nxt, csk->rcv_nxt, cxgb4i_snd_win, - csk->advmss); - - cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); -} - -static inline void make_tx_data_wr(struct cxgbi_sock *csk, struct sk_buff *skb, - int dlen, int len, u32 credits, int compl) -{ - struct fw_ofld_tx_data_wr *req; - unsigned int submode = cxgbi_skcb_ulp_mode(skb) & 3; - unsigned int wr_ulp_mode = 0; - - req = (struct fw_ofld_tx_data_wr *)__skb_push(skb, sizeof(*req)); - - if (is_ofld_imm(skb)) { - req->op_to_immdlen = htonl(FW_WR_OP(FW_OFLD_TX_DATA_WR) | - FW_WR_COMPL(1) | - FW_WR_IMMDLEN(dlen)); - req->flowid_len16 = htonl(FW_WR_FLOWID(csk->tid) | - FW_WR_LEN16(credits)); - } else { - req->op_to_immdlen = - cpu_to_be32(FW_WR_OP(FW_OFLD_TX_DATA_WR) | - FW_WR_COMPL(1) | - FW_WR_IMMDLEN(0)); - req->flowid_len16 = - cpu_to_be32(FW_WR_FLOWID(csk->tid) | - FW_WR_LEN16(credits)); - } - if (submode) - wr_ulp_mode = FW_OFLD_TX_DATA_WR_ULPMODE(ULP2_MODE_ISCSI) | - FW_OFLD_TX_DATA_WR_ULPSUBMODE(submode); - req->tunnel_to_proxy = htonl(wr_ulp_mode) | - FW_OFLD_TX_DATA_WR_SHOVE(skb_peek(&csk->write_queue) ? 0 : 1); - req->plen = htonl(len); - if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) - cxgbi_sock_set_flag(csk, CTPF_TX_DATA_SENT); -} - -static void arp_failure_skb_discard(void *handle, struct sk_buff *skb) -{ - kfree_skb(skb); -} - -static int push_tx_frames(struct cxgbi_sock *csk, int req_completion) -{ - int total_size = 0; - struct sk_buff *skb; - - if (unlikely(csk->state < CTP_ESTABLISHED || - csk->state == CTP_CLOSE_WAIT_1 || csk->state >= CTP_ABORTING)) { - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK | - 1 << CXGBI_DBG_PDU_TX, - "csk 0x%p,%u,0x%lx,%u, in closing state.\n", - csk, csk->state, csk->flags, csk->tid); - return 0; - } - - while (csk->wr_cred && (skb = skb_peek(&csk->write_queue)) != NULL) { - int dlen = skb->len; - int len = skb->len; - unsigned int credits_needed; - - skb_reset_transport_header(skb); - if (is_ofld_imm(skb)) - credits_needed = DIV_ROUND_UP(dlen + - sizeof(struct fw_ofld_tx_data_wr), 16); - else - credits_needed = DIV_ROUND_UP(8*calc_tx_flits_ofld(skb) - + sizeof(struct fw_ofld_tx_data_wr), - 16); - - if (csk->wr_cred < credits_needed) { - log_debug(1 << CXGBI_DBG_PDU_TX, - "csk 0x%p, skb %u/%u, wr %d < %u.\n", - csk, skb->len, skb->data_len, - credits_needed, csk->wr_cred); - break; - } - __skb_unlink(skb, &csk->write_queue); - set_queue(skb, CPL_PRIORITY_DATA, csk); - skb->csum = credits_needed; - csk->wr_cred -= credits_needed; - csk->wr_una_cred += credits_needed; - cxgbi_sock_enqueue_wr(csk, skb); - - log_debug(1 << CXGBI_DBG_PDU_TX, - "csk 0x%p, skb %u/%u, wr %d, left %u, unack %u.\n", - csk, skb->len, skb->data_len, credits_needed, - csk->wr_cred, csk->wr_una_cred); - - if (likely(cxgbi_skcb_test_flag(skb, SKCBF_TX_NEED_HDR))) { - if (!cxgbi_sock_flag(csk, CTPF_TX_DATA_SENT)) { - send_tx_flowc_wr(csk); - skb->csum += 5; - csk->wr_cred -= 5; - csk->wr_una_cred += 5; - } - len += cxgbi_ulp_extra_len(cxgbi_skcb_ulp_mode(skb)); - make_tx_data_wr(csk, skb, dlen, len, credits_needed, - req_completion); - csk->snd_nxt += len; - cxgbi_skcb_clear_flag(skb, SKCBF_TX_NEED_HDR); - } - total_size += skb->truesize; - t4_set_arp_err_handler(skb, csk, arp_failure_skb_discard); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_TX, - "csk 0x%p,%u,0x%lx,%u, skb 0x%p, %u.\n", - csk, csk->state, csk->flags, csk->tid, skb, len); - - cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); - } - return total_size; -} - -static inline void free_atid(struct cxgbi_sock *csk) -{ - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); - - if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) { - cxgb4_free_atid(lldi->tids, csk->atid); - cxgbi_sock_clear_flag(csk, CTPF_HAS_ATID); - cxgbi_sock_put(csk); - } -} - -static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct cpl_act_establish *req = (struct cpl_act_establish *)skb->data; - unsigned short tcp_opt = ntohs(req->tcp_opt); - unsigned int tid = GET_TID(req); - unsigned int atid = GET_TID_TID(ntohl(req->tos_atid)); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - u32 rcv_isn = be32_to_cpu(req->rcv_isn); - - csk = lookup_atid(t, atid); - if (unlikely(!csk)) { - pr_err("NO conn. for atid %u, cdev 0x%p.\n", atid, cdev); - goto rel_skb; - } - - if (csk->atid != atid) { - pr_err("bad conn atid %u, csk 0x%p,%u,0x%lx,tid %u, atid %u.\n", - atid, csk, csk->state, csk->flags, csk->tid, csk->atid); - goto rel_skb; - } - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, tid %u, atid %u, rseq %u.\n", - csk, csk->state, csk->flags, tid, atid, rcv_isn); - - cxgbi_sock_get(csk); - csk->tid = tid; - cxgb4_insert_tid(lldi->tids, csk, tid); - cxgbi_sock_set_flag(csk, CTPF_HAS_TID); - - free_atid(csk); - - spin_lock_bh(&csk->lock); - if (unlikely(csk->state != CTP_ACTIVE_OPEN)) - pr_info("csk 0x%p,%u,0x%lx,%u, got EST.\n", - csk, csk->state, csk->flags, csk->tid); - - if (csk->retry_timer.function) { - del_timer(&csk->retry_timer); - csk->retry_timer.function = NULL; - } - - csk->copied_seq = csk->rcv_wup = csk->rcv_nxt = rcv_isn; - /* - * Causes the first RX_DATA_ACK to supply any Rx credits we couldn't - * pass through opt0. - */ - if (cxgb4i_rcv_win > (RCV_BUFSIZ_MASK << 10)) - csk->rcv_wup -= cxgb4i_rcv_win - (RCV_BUFSIZ_MASK << 10); - - csk->advmss = lldi->mtus[GET_TCPOPT_MSS(tcp_opt)] - 40; - if (GET_TCPOPT_TSTAMP(tcp_opt)) - csk->advmss -= 12; - if (csk->advmss < 128) - csk->advmss = 128; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p, mss_idx %u, advmss %u.\n", - csk, GET_TCPOPT_MSS(tcp_opt), csk->advmss); - - cxgbi_sock_established(csk, ntohl(req->snd_isn), ntohs(req->tcp_opt)); - - if (unlikely(cxgbi_sock_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED))) - send_abort_req(csk); - else { - if (skb_queue_len(&csk->write_queue)) - push_tx_frames(csk, 0); - cxgbi_conn_tx_open(csk); - } - spin_unlock_bh(&csk->lock); - -rel_skb: - __kfree_skb(skb); -} - -static int act_open_rpl_status_to_errno(int status) -{ - switch (status) { - case CPL_ERR_CONN_RESET: - return -ECONNREFUSED; - case CPL_ERR_ARP_MISS: - return -EHOSTUNREACH; - case CPL_ERR_CONN_TIMEDOUT: - return -ETIMEDOUT; - case CPL_ERR_TCAM_FULL: - return -ENOMEM; - case CPL_ERR_CONN_EXIST: - return -EADDRINUSE; - default: - return -EIO; - } -} - -static void csk_act_open_retry_timer(unsigned long data) -{ - struct sk_buff *skb; - struct cxgbi_sock *csk = (struct cxgbi_sock *)data; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_ATOMIC); - if (!skb) - cxgbi_sock_fail_act_open(csk, -ENOMEM); - else { - skb->sk = (struct sock *)csk; - t4_set_arp_err_handler(skb, csk, - cxgbi_sock_act_open_req_arp_failure); - send_act_open_req(csk, skb, csk->l2t); - } - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); -} - -static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct cpl_act_open_rpl *rpl = (struct cpl_act_open_rpl *)skb->data; - unsigned int tid = GET_TID(rpl); - unsigned int atid = - GET_TID_TID(GET_AOPEN_ATID(be32_to_cpu(rpl->atid_status))); - unsigned int status = GET_AOPEN_STATUS(be32_to_cpu(rpl->atid_status)); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - - csk = lookup_atid(t, atid); - if (unlikely(!csk)) { - pr_err("NO matching conn. atid %u, tid %u.\n", atid, tid); - goto rel_skb; - } - - pr_info("%pI4:%u-%pI4:%u, atid %u,%u, status %u, csk 0x%p,%u,0x%lx.\n", - &csk->saddr.sin_addr.s_addr, ntohs(csk->saddr.sin_port), - &csk->daddr.sin_addr.s_addr, ntohs(csk->daddr.sin_port), - atid, tid, status, csk, csk->state, csk->flags); - - if (status == CPL_ERR_RTX_NEG_ADVICE) - goto rel_skb; - - if (status && status != CPL_ERR_TCAM_FULL && - status != CPL_ERR_CONN_EXIST && - status != CPL_ERR_ARP_MISS) - cxgb4_remove_tid(lldi->tids, csk->port_id, GET_TID(rpl)); - - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - - if (status == CPL_ERR_CONN_EXIST && - csk->retry_timer.function != csk_act_open_retry_timer) { - csk->retry_timer.function = csk_act_open_retry_timer; - mod_timer(&csk->retry_timer, jiffies + HZ / 2); - } else - cxgbi_sock_fail_act_open(csk, - act_open_rpl_status_to_errno(status)); - - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); -rel_skb: - __kfree_skb(skb); -} - -static void do_peer_close(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct cpl_peer_close *req = (struct cpl_peer_close *)skb->data; - unsigned int tid = GET_TID(req); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - - csk = lookup_tid(t, tid); - if (unlikely(!csk)) { - pr_err("can't find connection for tid %u.\n", tid); - goto rel_skb; - } - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - cxgbi_sock_rcv_peer_close(csk); -rel_skb: - __kfree_skb(skb); -} - -static void do_close_con_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct cpl_close_con_rpl *rpl = (struct cpl_close_con_rpl *)skb->data; - unsigned int tid = GET_TID(rpl); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - - csk = lookup_tid(t, tid); - if (unlikely(!csk)) { - pr_err("can't find connection for tid %u.\n", tid); - goto rel_skb; - } - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - cxgbi_sock_rcv_close_conn_rpl(csk, ntohl(rpl->snd_nxt)); -rel_skb: - __kfree_skb(skb); -} - -static int abort_status_to_errno(struct cxgbi_sock *csk, int abort_reason, - int *need_rst) -{ - switch (abort_reason) { - case CPL_ERR_BAD_SYN: /* fall through */ - case CPL_ERR_CONN_RESET: - return csk->state > CTP_ESTABLISHED ? - -EPIPE : -ECONNRESET; - case CPL_ERR_XMIT_TIMEDOUT: - case CPL_ERR_PERSIST_TIMEDOUT: - case CPL_ERR_FINWAIT2_TIMEDOUT: - case CPL_ERR_KEEPALIVE_TIMEDOUT: - return -ETIMEDOUT; - default: - return -EIO; - } -} - -static void do_abort_req_rss(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct cpl_abort_req_rss *req = (struct cpl_abort_req_rss *)skb->data; - unsigned int tid = GET_TID(req); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - int rst_status = CPL_ABORT_NO_RST; - - csk = lookup_tid(t, tid); - if (unlikely(!csk)) { - pr_err("can't find connection for tid %u.\n", tid); - goto rel_skb; - } - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, tid %u, status 0x%x.\n", - csk, csk->state, csk->flags, csk->tid, req->status); - - if (req->status == CPL_ERR_RTX_NEG_ADVICE || - req->status == CPL_ERR_PERSIST_NEG_ADVICE) - goto rel_skb; - - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - - if (!cxgbi_sock_flag(csk, CTPF_ABORT_REQ_RCVD)) { - cxgbi_sock_set_flag(csk, CTPF_ABORT_REQ_RCVD); - cxgbi_sock_set_state(csk, CTP_ABORTING); - goto done; - } - - cxgbi_sock_clear_flag(csk, CTPF_ABORT_REQ_RCVD); - send_abort_rpl(csk, rst_status); - - if (!cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { - csk->err = abort_status_to_errno(csk, req->status, &rst_status); - cxgbi_sock_closed(csk); - } -done: - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); -rel_skb: - __kfree_skb(skb); -} - -static void do_abort_rpl_rss(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct cpl_abort_rpl_rss *rpl = (struct cpl_abort_rpl_rss *)skb->data; - unsigned int tid = GET_TID(rpl); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - - csk = lookup_tid(t, tid); - if (!csk) - goto rel_skb; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "status 0x%x, csk 0x%p, s %u, 0x%lx.\n", - rpl->status, csk, csk ? csk->state : 0, - csk ? csk->flags : 0UL); - - if (rpl->status == CPL_ERR_ABORT_FAILED) - goto rel_skb; - - cxgbi_sock_rcv_abort_rpl(csk); -rel_skb: - __kfree_skb(skb); -} - -static void do_rx_iscsi_hdr(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)skb->data; - unsigned short pdu_len_ddp = be16_to_cpu(cpl->pdu_len_ddp); - unsigned int tid = GET_TID(cpl); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - - csk = lookup_tid(t, tid); - if (unlikely(!csk)) { - pr_err("can't find conn. for tid %u.\n", tid); - goto rel_skb; - } - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p,%u, 0x%x.\n", - csk, csk->state, csk->flags, csk->tid, skb, skb->len, - pdu_len_ddp); - - spin_lock_bh(&csk->lock); - - if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, bad state.\n", - csk, csk->state, csk->flags, csk->tid); - if (csk->state != CTP_ABORTING) - goto abort_conn; - else - goto discard; - } - - cxgbi_skcb_tcp_seq(skb) = ntohl(cpl->seq); - cxgbi_skcb_flags(skb) = 0; - - skb_reset_transport_header(skb); - __skb_pull(skb, sizeof(*cpl)); - __pskb_trim(skb, ntohs(cpl->len)); - - if (!csk->skb_ulp_lhdr) { - unsigned char *bhs; - unsigned int hlen, dlen; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p header.\n", - csk, csk->state, csk->flags, csk->tid, skb); - csk->skb_ulp_lhdr = skb; - cxgbi_skcb_set_flag(skb, SKCBF_RX_HDR); - - if (cxgbi_skcb_tcp_seq(skb) != csk->rcv_nxt) { - pr_info("tid %u, CPL_ISCSI_HDR, bad seq, 0x%x/0x%x.\n", - csk->tid, cxgbi_skcb_tcp_seq(skb), - csk->rcv_nxt); - goto abort_conn; - } - - bhs = skb->data; - hlen = ntohs(cpl->len); - dlen = ntohl(*(unsigned int *)(bhs + 4)) & 0xFFFFFF; - - if ((hlen + dlen) != ISCSI_PDU_LEN(pdu_len_ddp) - 40) { - pr_info("tid 0x%x, CPL_ISCSI_HDR, pdu len " - "mismatch %u != %u + %u, seq 0x%x.\n", - csk->tid, ISCSI_PDU_LEN(pdu_len_ddp) - 40, - hlen, dlen, cxgbi_skcb_tcp_seq(skb)); - goto abort_conn; - } - - cxgbi_skcb_rx_pdulen(skb) = (hlen + dlen + 3) & (~0x3); - if (dlen) - cxgbi_skcb_rx_pdulen(skb) += csk->dcrc_len; - csk->rcv_nxt += cxgbi_skcb_rx_pdulen(skb); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, skb 0x%p, 0x%x,%u+%u,0x%x,0x%x.\n", - csk, skb, *bhs, hlen, dlen, - ntohl(*((unsigned int *)(bhs + 16))), - ntohl(*((unsigned int *)(bhs + 24)))); - - } else { - struct sk_buff *lskb = csk->skb_ulp_lhdr; - - cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA); - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lx, skb 0x%p data, 0x%p.\n", - csk, csk->state, csk->flags, skb, lskb); - } - - __skb_queue_tail(&csk->receive_queue, skb); - spin_unlock_bh(&csk->lock); - return; - -abort_conn: - send_abort_req(csk); -discard: - spin_unlock_bh(&csk->lock); -rel_skb: - __kfree_skb(skb); -} - -static void do_rx_data_ddp(struct cxgbi_device *cdev, - struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct sk_buff *lskb; - struct cpl_rx_data_ddp *rpl = (struct cpl_rx_data_ddp *)skb->data; - unsigned int tid = GET_TID(rpl); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - unsigned int status = ntohl(rpl->ddpvld); - - csk = lookup_tid(t, tid); - if (unlikely(!csk)) { - pr_err("can't find connection for tid %u.\n", tid); - goto rel_skb; - } - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lx, skb 0x%p,0x%x, lhdr 0x%p.\n", - csk, csk->state, csk->flags, skb, status, csk->skb_ulp_lhdr); - - spin_lock_bh(&csk->lock); - - if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, bad state.\n", - csk, csk->state, csk->flags, csk->tid); - if (csk->state != CTP_ABORTING) - goto abort_conn; - else - goto discard; - } - - if (!csk->skb_ulp_lhdr) { - pr_err("tid 0x%x, rcv RX_DATA_DDP w/o pdu bhs.\n", csk->tid); - goto abort_conn; - } - - lskb = csk->skb_ulp_lhdr; - csk->skb_ulp_lhdr = NULL; - - cxgbi_skcb_rx_ddigest(lskb) = ntohl(rpl->ulp_crc); - - if (ntohs(rpl->len) != cxgbi_skcb_rx_pdulen(lskb)) - pr_info("tid 0x%x, RX_DATA_DDP pdulen %u != %u.\n", - csk->tid, ntohs(rpl->len), cxgbi_skcb_rx_pdulen(lskb)); - - if (status & (1 << CPL_RX_DDP_STATUS_HCRC_SHIFT)) { - pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, hcrc bad 0x%lx.\n", - csk, lskb, status, cxgbi_skcb_flags(lskb)); - cxgbi_skcb_set_flag(lskb, SKCBF_RX_HCRC_ERR); - } - if (status & (1 << CPL_RX_DDP_STATUS_DCRC_SHIFT)) { - pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, dcrc bad 0x%lx.\n", - csk, lskb, status, cxgbi_skcb_flags(lskb)); - cxgbi_skcb_set_flag(lskb, SKCBF_RX_DCRC_ERR); - } - if (status & (1 << CPL_RX_DDP_STATUS_PAD_SHIFT)) { - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, lhdr 0x%p, status 0x%x, pad bad.\n", - csk, lskb, status); - cxgbi_skcb_set_flag(lskb, SKCBF_RX_PAD_ERR); - } - if ((status & (1 << CPL_RX_DDP_STATUS_DDP_SHIFT)) && - !cxgbi_skcb_test_flag(lskb, SKCBF_RX_DATA)) { - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, lhdr 0x%p, 0x%x, data ddp'ed.\n", - csk, lskb, status); - cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA_DDPD); - } - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, lskb 0x%p, f 0x%lx.\n", - csk, lskb, cxgbi_skcb_flags(lskb)); - - cxgbi_skcb_set_flag(lskb, SKCBF_RX_STATUS); - cxgbi_conn_pdu_ready(csk); - spin_unlock_bh(&csk->lock); - goto rel_skb; - -abort_conn: - send_abort_req(csk); -discard: - spin_unlock_bh(&csk->lock); -rel_skb: - __kfree_skb(skb); -} - -static void do_fw4_ack(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cxgbi_sock *csk; - struct cpl_fw4_ack *rpl = (struct cpl_fw4_ack *)skb->data; - unsigned int tid = GET_TID(rpl); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - - csk = lookup_tid(t, tid); - if (unlikely(!csk)) - pr_err("can't find connection for tid %u.\n", tid); - else { - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - cxgbi_sock_rcv_wr_ack(csk, rpl->credits, ntohl(rpl->snd_una), - rpl->seq_vld); - } - __kfree_skb(skb); -} - -static void do_set_tcb_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) -{ - struct cpl_set_tcb_rpl *rpl = (struct cpl_set_tcb_rpl *)skb->data; - unsigned int tid = GET_TID(rpl); - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct tid_info *t = lldi->tids; - struct cxgbi_sock *csk; - - csk = lookup_tid(t, tid); - if (!csk) - pr_err("can't find conn. for tid %u.\n", tid); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,%lx,%u, status 0x%x.\n", - csk, csk->state, csk->flags, csk->tid, rpl->status); - - if (rpl->status != CPL_ERR_NONE) - pr_err("csk 0x%p,%u, SET_TCB_RPL status %u.\n", - csk, tid, rpl->status); - - __kfree_skb(skb); -} - -static int alloc_cpls(struct cxgbi_sock *csk) -{ - csk->cpl_close = alloc_wr(sizeof(struct cpl_close_con_req), - 0, GFP_KERNEL); - if (!csk->cpl_close) - return -ENOMEM; - - csk->cpl_abort_req = alloc_wr(sizeof(struct cpl_abort_req), - 0, GFP_KERNEL); - if (!csk->cpl_abort_req) - goto free_cpls; - - csk->cpl_abort_rpl = alloc_wr(sizeof(struct cpl_abort_rpl), - 0, GFP_KERNEL); - if (!csk->cpl_abort_rpl) - goto free_cpls; - return 0; - -free_cpls: - cxgbi_sock_free_cpl_skbs(csk); - return -ENOMEM; -} - -static inline void l2t_put(struct cxgbi_sock *csk) -{ - if (csk->l2t) { - cxgb4_l2t_release(csk->l2t); - csk->l2t = NULL; - cxgbi_sock_put(csk); - } -} - -static void release_offload_resources(struct cxgbi_sock *csk) -{ - struct cxgb4_lld_info *lldi; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - - cxgbi_sock_free_cpl_skbs(csk); - if (csk->wr_cred != csk->wr_max_cred) { - cxgbi_sock_purge_wr_queue(csk); - cxgbi_sock_reset_wr_list(csk); - } - - l2t_put(csk); - if (cxgbi_sock_flag(csk, CTPF_HAS_ATID)) - free_atid(csk); - else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) { - lldi = cxgbi_cdev_priv(csk->cdev); - cxgb4_remove_tid(lldi->tids, 0, csk->tid); - cxgbi_sock_clear_flag(csk, CTPF_HAS_TID); - cxgbi_sock_put(csk); - } - csk->dst = NULL; - csk->cdev = NULL; -} - -static int init_act_open(struct cxgbi_sock *csk) -{ - struct cxgbi_device *cdev = csk->cdev; - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct net_device *ndev = cdev->ports[csk->port_id]; - struct port_info *pi = netdev_priv(ndev); - struct sk_buff *skb = NULL; - struct neighbour *n; - unsigned int step; - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u.\n", - csk, csk->state, csk->flags, csk->tid); - - csk->atid = cxgb4_alloc_atid(lldi->tids, csk); - if (csk->atid < 0) { - pr_err("%s, NO atid available.\n", ndev->name); - return -EINVAL; - } - cxgbi_sock_set_flag(csk, CTPF_HAS_ATID); - cxgbi_sock_get(csk); - - n = dst_get_neighbour_noref(csk->dst); - if (!n) { - pr_err("%s, can't get neighbour of csk->dst.\n", ndev->name); - goto rel_resource; - } - csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0); - if (!csk->l2t) { - pr_err("%s, cannot alloc l2t.\n", ndev->name); - goto rel_resource; - } - cxgbi_sock_get(csk); - - skb = alloc_wr(sizeof(struct cpl_act_open_req), 0, GFP_KERNEL); - if (!skb) - goto rel_resource; - skb->sk = (struct sock *)csk; - t4_set_arp_err_handler(skb, csk, cxgbi_sock_act_open_req_arp_failure); - - if (!csk->mtu) - csk->mtu = dst_mtu(csk->dst); - cxgb4_best_mtu(lldi->mtus, csk->mtu, &csk->mss_idx); - csk->tx_chan = cxgb4_port_chan(ndev); - /* SMT two entries per row */ - csk->smac_idx = ((cxgb4_port_viid(ndev) & 0x7F)) << 1; - step = lldi->ntxq / lldi->nchan; - csk->txq_idx = cxgb4_port_idx(ndev) * step; - step = lldi->nrxq / lldi->nchan; - csk->rss_qid = lldi->rxq_ids[cxgb4_port_idx(ndev) * step]; - csk->wr_max_cred = csk->wr_cred = lldi->wr_cred; - csk->wr_una_cred = 0; - cxgbi_sock_reset_wr_list(csk); - csk->err = 0; - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,p%d,%s, %u,%u,%u, mss %u,%u, smac %u.\n", - csk, pi->port_id, ndev->name, csk->tx_chan, - csk->txq_idx, csk->rss_qid, csk->mtu, csk->mss_idx, - csk->smac_idx); - - cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); - send_act_open_req(csk, skb, csk->l2t); - return 0; - -rel_resource: - if (skb) - __kfree_skb(skb); - return -EINVAL; -} - -cxgb4i_cplhandler_func cxgb4i_cplhandlers[NUM_CPL_CMDS] = { - [CPL_ACT_ESTABLISH] = do_act_establish, - [CPL_ACT_OPEN_RPL] = do_act_open_rpl, - [CPL_PEER_CLOSE] = do_peer_close, - [CPL_ABORT_REQ_RSS] = do_abort_req_rss, - [CPL_ABORT_RPL_RSS] = do_abort_rpl_rss, - [CPL_CLOSE_CON_RPL] = do_close_con_rpl, - [CPL_FW4_ACK] = do_fw4_ack, - [CPL_ISCSI_HDR] = do_rx_iscsi_hdr, - [CPL_SET_TCB_RPL] = do_set_tcb_rpl, - [CPL_RX_DATA_DDP] = do_rx_data_ddp, -}; - -int cxgb4i_ofld_init(struct cxgbi_device *cdev) -{ - int rc; - - if (cxgb4i_max_connect > CXGB4I_MAX_CONN) - cxgb4i_max_connect = CXGB4I_MAX_CONN; - - rc = cxgbi_device_portmap_create(cdev, cxgb4i_sport_base, - cxgb4i_max_connect); - if (rc < 0) - return rc; - - cdev->csk_release_offload_resources = release_offload_resources; - cdev->csk_push_tx_frames = push_tx_frames; - cdev->csk_send_abort_req = send_abort_req; - cdev->csk_send_close_req = send_close_req; - cdev->csk_send_rx_credits = send_rx_credits; - cdev->csk_alloc_cpls = alloc_cpls; - cdev->csk_init_act_open = init_act_open; - - pr_info("cdev 0x%p, offload up, added.\n", cdev); - return 0; -} - -/* - * functions to program the pagepod in h/w - */ -#define ULPMEM_IDATA_MAX_NPPODS 4 /* 256/PPOD_SIZE */ -static inline void ulp_mem_io_set_hdr(struct ulp_mem_io *req, - unsigned int wr_len, unsigned int dlen, - unsigned int pm_addr) -{ - struct ulptx_idata *idata = (struct ulptx_idata *)(req + 1); - - INIT_ULPTX_WR(req, wr_len, 0, 0); - req->cmd = htonl(ULPTX_CMD(ULP_TX_MEM_WRITE) | (1 << 23)); - req->dlen = htonl(ULP_MEMIO_DATA_LEN(dlen >> 5)); - req->lock_addr = htonl(ULP_MEMIO_ADDR(pm_addr >> 5)); - req->len16 = htonl(DIV_ROUND_UP(wr_len - sizeof(req->wr), 16)); - - idata->cmd_more = htonl(ULPTX_CMD(ULP_TX_SC_IMM)); - idata->len = htonl(dlen); -} - -static int ddp_ppod_write_idata(struct cxgbi_device *cdev, unsigned int port_id, - struct cxgbi_pagepod_hdr *hdr, unsigned int idx, - unsigned int npods, - struct cxgbi_gather_list *gl, - unsigned int gl_pidx) -{ - struct cxgbi_ddp_info *ddp = cdev->ddp; - struct sk_buff *skb; - struct ulp_mem_io *req; - struct ulptx_idata *idata; - struct cxgbi_pagepod *ppod; - unsigned int pm_addr = idx * PPOD_SIZE + ddp->llimit; - unsigned int dlen = PPOD_SIZE * npods; - unsigned int wr_len = roundup(sizeof(struct ulp_mem_io) + - sizeof(struct ulptx_idata) + dlen, 16); - unsigned int i; - - skb = alloc_wr(wr_len, 0, GFP_ATOMIC); - if (!skb) { - pr_err("cdev 0x%p, idx %u, npods %u, OOM.\n", - cdev, idx, npods); - return -ENOMEM; - } - req = (struct ulp_mem_io *)skb->head; - set_queue(skb, CPL_PRIORITY_CONTROL, NULL); - - ulp_mem_io_set_hdr(req, wr_len, dlen, pm_addr); - idata = (struct ulptx_idata *)(req + 1); - ppod = (struct cxgbi_pagepod *)(idata + 1); - - for (i = 0; i < npods; i++, ppod++, gl_pidx += PPOD_PAGES_MAX) { - if (!hdr && !gl) - cxgbi_ddp_ppod_clear(ppod); - else - cxgbi_ddp_ppod_set(ppod, hdr, gl, gl_pidx); - } - - cxgb4_ofld_send(cdev->ports[port_id], skb); - return 0; -} - -static int ddp_set_map(struct cxgbi_sock *csk, struct cxgbi_pagepod_hdr *hdr, - unsigned int idx, unsigned int npods, - struct cxgbi_gather_list *gl) -{ - unsigned int i, cnt; - int err = 0; - - for (i = 0; i < npods; i += cnt, idx += cnt) { - cnt = npods - i; - if (cnt > ULPMEM_IDATA_MAX_NPPODS) - cnt = ULPMEM_IDATA_MAX_NPPODS; - err = ddp_ppod_write_idata(csk->cdev, csk->port_id, hdr, - idx, cnt, gl, 4 * i); - if (err < 0) - break; - } - return err; -} - -static void ddp_clear_map(struct cxgbi_hba *chba, unsigned int tag, - unsigned int idx, unsigned int npods) -{ - unsigned int i, cnt; - int err; - - for (i = 0; i < npods; i += cnt, idx += cnt) { - cnt = npods - i; - if (cnt > ULPMEM_IDATA_MAX_NPPODS) - cnt = ULPMEM_IDATA_MAX_NPPODS; - err = ddp_ppod_write_idata(chba->cdev, chba->port_id, NULL, - idx, cnt, NULL, 0); - if (err < 0) - break; - } -} - -static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid, - int pg_idx, bool reply) -{ - struct sk_buff *skb; - struct cpl_set_tcb_field *req; - - if (!pg_idx || pg_idx >= DDP_PGIDX_MAX) - return 0; - - skb = alloc_wr(sizeof(*req), 0, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - /* set up ulp page size */ - req = (struct cpl_set_tcb_field *)skb->head; - INIT_TP_WR(req, csk->tid); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid)); - req->reply_ctrl = htons(NO_REPLY(reply) | QUEUENO(csk->rss_qid)); - req->word_cookie = htons(0); - req->mask = cpu_to_be64(0x3 << 8); - req->val = cpu_to_be64(pg_idx << 8); - set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p, tid 0x%x, pg_idx %u.\n", csk, csk->tid, pg_idx); - - cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); - return 0; -} - -static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid, - int hcrc, int dcrc, int reply) -{ - struct sk_buff *skb; - struct cpl_set_tcb_field *req; - - if (!hcrc && !dcrc) - return 0; - - skb = alloc_wr(sizeof(*req), 0, GFP_KERNEL); - if (!skb) - return -ENOMEM; - - csk->hcrc_len = (hcrc ? 4 : 0); - csk->dcrc_len = (dcrc ? 4 : 0); - /* set up ulp submode */ - req = (struct cpl_set_tcb_field *)skb->head; - INIT_TP_WR(req, tid); - OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid)); - req->reply_ctrl = htons(NO_REPLY(reply) | QUEUENO(csk->rss_qid)); - req->word_cookie = htons(0); - req->mask = cpu_to_be64(0x3 << 4); - req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) | - (dcrc ? ULP_CRC_DATA : 0)) << 4); - set_wr_txq(skb, CPL_PRIORITY_CONTROL, csk->port_id); - - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p, tid 0x%x, crc %d,%d.\n", csk, csk->tid, hcrc, dcrc); - - cxgb4_ofld_send(csk->cdev->ports[csk->port_id], skb); - return 0; -} - -static int cxgb4i_ddp_init(struct cxgbi_device *cdev) -{ - struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); - struct cxgbi_ddp_info *ddp = cdev->ddp; - unsigned int tagmask, pgsz_factor[4]; - int err; - - if (ddp) { - kref_get(&ddp->refcnt); - pr_warn("cdev 0x%p, ddp 0x%p already set up.\n", - cdev, cdev->ddp); - return -EALREADY; - } - - err = cxgbi_ddp_init(cdev, lldi->vr->iscsi.start, - lldi->vr->iscsi.start + lldi->vr->iscsi.size - 1, - lldi->iscsi_iolen, lldi->iscsi_iolen); - if (err < 0) - return err; - - ddp = cdev->ddp; - - tagmask = ddp->idx_mask << PPOD_IDX_SHIFT; - cxgbi_ddp_page_size_factor(pgsz_factor); - cxgb4_iscsi_init(lldi->ports[0], tagmask, pgsz_factor); - - cdev->csk_ddp_setup_digest = ddp_setup_conn_digest; - cdev->csk_ddp_setup_pgidx = ddp_setup_conn_pgidx; - cdev->csk_ddp_set = ddp_set_map; - cdev->csk_ddp_clear = ddp_clear_map; - - pr_info("cxgb4i 0x%p tag: sw %u, rsvd %u,%u, mask 0x%x.\n", - cdev, cdev->tag_format.sw_bits, cdev->tag_format.rsvd_bits, - cdev->tag_format.rsvd_shift, cdev->tag_format.rsvd_mask); - pr_info("cxgb4i 0x%p, nppods %u, bits %u, mask 0x%x,0x%x pkt %u/%u, " - " %u/%u.\n", - cdev, ddp->nppods, ddp->idx_bits, ddp->idx_mask, - ddp->rsvd_tag_mask, ddp->max_txsz, lldi->iscsi_iolen, - ddp->max_rxsz, lldi->iscsi_iolen); - pr_info("cxgb4i 0x%p max payload size: %u/%u, %u/%u.\n", - cdev, cdev->tx_max_size, ddp->max_txsz, cdev->rx_max_size, - ddp->max_rxsz); - return 0; -} - -static void *t4_uld_add(const struct cxgb4_lld_info *lldi) -{ - struct cxgbi_device *cdev; - struct port_info *pi; - int i, rc; - - cdev = cxgbi_device_register(sizeof(*lldi), lldi->nports); - if (!cdev) { - pr_info("t4 device 0x%p, register failed.\n", lldi); - return NULL; - } - pr_info("0x%p,0x%x, ports %u,%s, chan %u, q %u,%u, wr %u.\n", - cdev, lldi->adapter_type, lldi->nports, - lldi->ports[0]->name, lldi->nchan, lldi->ntxq, - lldi->nrxq, lldi->wr_cred); - for (i = 0; i < lldi->nrxq; i++) - log_debug(1 << CXGBI_DBG_DEV, - "t4 0x%p, rxq id #%d: %u.\n", - cdev, i, lldi->rxq_ids[i]); - - memcpy(cxgbi_cdev_priv(cdev), lldi, sizeof(*lldi)); - cdev->flags = CXGBI_FLAG_DEV_T4; - cdev->pdev = lldi->pdev; - cdev->ports = lldi->ports; - cdev->nports = lldi->nports; - cdev->mtus = lldi->mtus; - cdev->nmtus = NMTUS; - cdev->snd_win = cxgb4i_snd_win; - cdev->rcv_win = cxgb4i_rcv_win; - cdev->rx_credit_thres = cxgb4i_rx_credit_thres; - cdev->skb_tx_rsvd = CXGB4I_TX_HEADER_LEN; - cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr); - cdev->itp = &cxgb4i_iscsi_transport; - - cdev->pfvf = FW_VIID_PFN_GET(cxgb4_port_viid(lldi->ports[0])) << 8; - pr_info("cdev 0x%p,%s, pfvf %u.\n", - cdev, lldi->ports[0]->name, cdev->pfvf); - - rc = cxgb4i_ddp_init(cdev); - if (rc) { - pr_info("t4 0x%p ddp init failed.\n", cdev); - goto err_out; - } - rc = cxgb4i_ofld_init(cdev); - if (rc) { - pr_info("t4 0x%p ofld init failed.\n", cdev); - goto err_out; - } - - rc = cxgbi_hbas_add(cdev, CXGB4I_MAX_LUN, CXGBI_MAX_CONN, - &cxgb4i_host_template, cxgb4i_stt); - if (rc) - goto err_out; - - for (i = 0; i < cdev->nports; i++) { - pi = netdev_priv(lldi->ports[i]); - cdev->hbas[i]->port_id = pi->port_id; - } - return cdev; - -err_out: - cxgbi_device_unregister(cdev); - return ERR_PTR(-ENOMEM); -} - -#define RX_PULL_LEN 128 -static int t4_uld_rx_handler(void *handle, const __be64 *rsp, - const struct pkt_gl *pgl) -{ - const struct cpl_act_establish *rpl; - struct sk_buff *skb; - unsigned int opc; - struct cxgbi_device *cdev = handle; - - if (pgl == NULL) { - unsigned int len = 64 - sizeof(struct rsp_ctrl) - 8; - - skb = alloc_wr(len, 0, GFP_ATOMIC); - if (!skb) - goto nomem; - skb_copy_to_linear_data(skb, &rsp[1], len); - } else { - if (unlikely(*(u8 *)rsp != *(u8 *)pgl->va)) { - pr_info("? FL 0x%p,RSS%#llx,FL %#llx,len %u.\n", - pgl->va, be64_to_cpu(*rsp), - be64_to_cpu(*(u64 *)pgl->va), - pgl->tot_len); - return 0; - } - skb = cxgb4_pktgl_to_skb(pgl, RX_PULL_LEN, RX_PULL_LEN); - if (unlikely(!skb)) - goto nomem; - } - - rpl = (struct cpl_act_establish *)skb->data; - opc = rpl->ot.opcode; - log_debug(1 << CXGBI_DBG_TOE, - "cdev %p, opcode 0x%x(0x%x,0x%x), skb %p.\n", - cdev, opc, rpl->ot.opcode_tid, ntohl(rpl->ot.opcode_tid), skb); - if (cxgb4i_cplhandlers[opc]) - cxgb4i_cplhandlers[opc](cdev, skb); - else { - pr_err("No handler for opcode 0x%x.\n", opc); - __kfree_skb(skb); - } - return 0; -nomem: - log_debug(1 << CXGBI_DBG_TOE, "OOM bailing out.\n"); - return 1; -} - -static int t4_uld_state_change(void *handle, enum cxgb4_state state) -{ - struct cxgbi_device *cdev = handle; - - switch (state) { - case CXGB4_STATE_UP: - pr_info("cdev 0x%p, UP.\n", cdev); - /* re-initialize */ - break; - case CXGB4_STATE_START_RECOVERY: - pr_info("cdev 0x%p, RECOVERY.\n", cdev); - /* close all connections */ - break; - case CXGB4_STATE_DOWN: - pr_info("cdev 0x%p, DOWN.\n", cdev); - break; - case CXGB4_STATE_DETACH: - pr_info("cdev 0x%p, DETACH.\n", cdev); - break; - default: - pr_info("cdev 0x%p, unknown state %d.\n", cdev, state); - break; - } - return 0; -} - -static int __init cxgb4i_init_module(void) -{ - int rc; - - printk(KERN_INFO "%s", version); - - rc = cxgbi_iscsi_init(&cxgb4i_iscsi_transport, &cxgb4i_stt); - if (rc < 0) - return rc; - cxgb4_register_uld(CXGB4_ULD_ISCSI, &cxgb4i_uld_info); - return 0; -} - -static void __exit cxgb4i_exit_module(void) -{ - cxgb4_unregister_uld(CXGB4_ULD_ISCSI); - cxgbi_device_unregister_all(CXGBI_FLAG_DEV_T4); - cxgbi_iscsi_cleanup(&cxgb4i_iscsi_transport, &cxgb4i_stt); -} - -module_init(cxgb4i_init_module); -module_exit(cxgb4i_exit_module); diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h b/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h deleted file mode 100644 index 1096026b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/cxgb4i/cxgb4i.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * cxgb4i.h: Chelsio T4 iSCSI driver. - * - * Copyright (c) 2010 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - * Written by: Rakesh Ranjan (rranjan@chelsio.com) - */ - -#ifndef __CXGB4I_H__ -#define __CXGB4I_H__ - -#define CXGB4I_SCSI_HOST_QDEPTH 1024 -#define CXGB4I_MAX_CONN 16384 -#define CXGB4I_MAX_TARGET CXGB4I_MAX_CONN -#define CXGB4I_MAX_LUN 0x1000 - -/* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */ -#define CXGB4I_TX_HEADER_LEN \ - (sizeof(struct fw_ofld_tx_data_wr) + sizeof(struct sge_opaque_hdr)) - -struct ulptx_idata { - __be32 cmd_more; - __be32 len; -}; - -struct cpl_rx_data_ddp { - union opcode_tid ot; - __be16 urg; - __be16 len; - __be32 seq; - union { - __be32 nxt_seq; - __be32 ddp_report; - }; - __be32 ulp_crc; - __be32 ddpvld; -}; -#endif /* __CXGB4I_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.c b/ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.c deleted file mode 100644 index d9253db1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.c +++ /dev/null @@ -1,2645 +0,0 @@ -/* - * libcxgbi.c: Chelsio common library for T3/T4 iSCSI driver. - * - * Copyright (c) 2010 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - * Written by: Rakesh Ranjan (rranjan@chelsio.com) - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* ip_dev_find */ -#include -#include - -static unsigned int dbg_level; - -#include "libcxgbi.h" - -#define DRV_MODULE_NAME "libcxgbi" -#define DRV_MODULE_DESC "Chelsio iSCSI driver library" -#define DRV_MODULE_VERSION "0.9.0" -#define DRV_MODULE_RELDATE "Jun. 2010" - -MODULE_AUTHOR("Chelsio Communications, Inc."); -MODULE_DESCRIPTION(DRV_MODULE_DESC); -MODULE_VERSION(DRV_MODULE_VERSION); -MODULE_LICENSE("GPL"); - -module_param(dbg_level, uint, 0644); -MODULE_PARM_DESC(dbg_level, "libiscsi debug level (default=0)"); - - -/* - * cxgbi device management - * maintains a list of the cxgbi devices - */ -static LIST_HEAD(cdev_list); -static DEFINE_MUTEX(cdev_mutex); - -int cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, - unsigned int max_conn) -{ - struct cxgbi_ports_map *pmap = &cdev->pmap; - - pmap->port_csk = cxgbi_alloc_big_mem(max_conn * - sizeof(struct cxgbi_sock *), - GFP_KERNEL); - if (!pmap->port_csk) { - pr_warn("cdev 0x%p, portmap OOM %u.\n", cdev, max_conn); - return -ENOMEM; - } - - pmap->max_connect = max_conn; - pmap->sport_base = base; - spin_lock_init(&pmap->lock); - return 0; -} -EXPORT_SYMBOL_GPL(cxgbi_device_portmap_create); - -void cxgbi_device_portmap_cleanup(struct cxgbi_device *cdev) -{ - struct cxgbi_ports_map *pmap = &cdev->pmap; - struct cxgbi_sock *csk; - int i; - - for (i = 0; i < pmap->max_connect; i++) { - if (pmap->port_csk[i]) { - csk = pmap->port_csk[i]; - pmap->port_csk[i] = NULL; - log_debug(1 << CXGBI_DBG_SOCK, - "csk 0x%p, cdev 0x%p, offload down.\n", - csk, cdev); - spin_lock_bh(&csk->lock); - cxgbi_sock_set_flag(csk, CTPF_OFFLOAD_DOWN); - cxgbi_sock_closed(csk); - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); - } - } -} -EXPORT_SYMBOL_GPL(cxgbi_device_portmap_cleanup); - -static inline void cxgbi_device_destroy(struct cxgbi_device *cdev) -{ - log_debug(1 << CXGBI_DBG_DEV, - "cdev 0x%p, p# %u.\n", cdev, cdev->nports); - cxgbi_hbas_remove(cdev); - cxgbi_device_portmap_cleanup(cdev); - if (cdev->dev_ddp_cleanup) - cdev->dev_ddp_cleanup(cdev); - else - cxgbi_ddp_cleanup(cdev); - if (cdev->ddp) - cxgbi_ddp_cleanup(cdev); - if (cdev->pmap.max_connect) - cxgbi_free_big_mem(cdev->pmap.port_csk); - kfree(cdev); -} - -struct cxgbi_device *cxgbi_device_register(unsigned int extra, - unsigned int nports) -{ - struct cxgbi_device *cdev; - - cdev = kzalloc(sizeof(*cdev) + extra + nports * - (sizeof(struct cxgbi_hba *) + - sizeof(struct net_device *)), - GFP_KERNEL); - if (!cdev) { - pr_warn("nport %d, OOM.\n", nports); - return NULL; - } - cdev->ports = (struct net_device **)(cdev + 1); - cdev->hbas = (struct cxgbi_hba **)(((char*)cdev->ports) + nports * - sizeof(struct net_device *)); - if (extra) - cdev->dd_data = ((char *)cdev->hbas) + - nports * sizeof(struct cxgbi_hba *); - spin_lock_init(&cdev->pmap.lock); - - mutex_lock(&cdev_mutex); - list_add_tail(&cdev->list_head, &cdev_list); - mutex_unlock(&cdev_mutex); - - log_debug(1 << CXGBI_DBG_DEV, - "cdev 0x%p, p# %u.\n", cdev, nports); - return cdev; -} -EXPORT_SYMBOL_GPL(cxgbi_device_register); - -void cxgbi_device_unregister(struct cxgbi_device *cdev) -{ - log_debug(1 << CXGBI_DBG_DEV, - "cdev 0x%p, p# %u,%s.\n", - cdev, cdev->nports, cdev->nports ? cdev->ports[0]->name : ""); - mutex_lock(&cdev_mutex); - list_del(&cdev->list_head); - mutex_unlock(&cdev_mutex); - cxgbi_device_destroy(cdev); -} -EXPORT_SYMBOL_GPL(cxgbi_device_unregister); - -void cxgbi_device_unregister_all(unsigned int flag) -{ - struct cxgbi_device *cdev, *tmp; - - mutex_lock(&cdev_mutex); - list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { - if ((cdev->flags & flag) == flag) { - log_debug(1 << CXGBI_DBG_DEV, - "cdev 0x%p, p# %u,%s.\n", - cdev, cdev->nports, cdev->nports ? - cdev->ports[0]->name : ""); - list_del(&cdev->list_head); - cxgbi_device_destroy(cdev); - } - } - mutex_unlock(&cdev_mutex); -} -EXPORT_SYMBOL_GPL(cxgbi_device_unregister_all); - -struct cxgbi_device *cxgbi_device_find_by_lldev(void *lldev) -{ - struct cxgbi_device *cdev, *tmp; - - mutex_lock(&cdev_mutex); - list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { - if (cdev->lldev == lldev) { - mutex_unlock(&cdev_mutex); - return cdev; - } - } - mutex_unlock(&cdev_mutex); - log_debug(1 << CXGBI_DBG_DEV, - "lldev 0x%p, NO match found.\n", lldev); - return NULL; -} -EXPORT_SYMBOL_GPL(cxgbi_device_find_by_lldev); - -static struct cxgbi_device *cxgbi_device_find_by_netdev(struct net_device *ndev, - int *port) -{ - struct net_device *vdev = NULL; - struct cxgbi_device *cdev, *tmp; - int i; - - if (ndev->priv_flags & IFF_802_1Q_VLAN) { - vdev = ndev; - ndev = vlan_dev_real_dev(ndev); - log_debug(1 << CXGBI_DBG_DEV, - "vlan dev %s -> %s.\n", vdev->name, ndev->name); - } - - mutex_lock(&cdev_mutex); - list_for_each_entry_safe(cdev, tmp, &cdev_list, list_head) { - for (i = 0; i < cdev->nports; i++) { - if (ndev == cdev->ports[i]) { - cdev->hbas[i]->vdev = vdev; - mutex_unlock(&cdev_mutex); - if (port) - *port = i; - return cdev; - } - } - } - mutex_unlock(&cdev_mutex); - log_debug(1 << CXGBI_DBG_DEV, - "ndev 0x%p, %s, NO match found.\n", ndev, ndev->name); - return NULL; -} - -void cxgbi_hbas_remove(struct cxgbi_device *cdev) -{ - int i; - struct cxgbi_hba *chba; - - log_debug(1 << CXGBI_DBG_DEV, - "cdev 0x%p, p#%u.\n", cdev, cdev->nports); - - for (i = 0; i < cdev->nports; i++) { - chba = cdev->hbas[i]; - if (chba) { - cdev->hbas[i] = NULL; - iscsi_host_remove(chba->shost); - pci_dev_put(cdev->pdev); - iscsi_host_free(chba->shost); - } - } -} -EXPORT_SYMBOL_GPL(cxgbi_hbas_remove); - -int cxgbi_hbas_add(struct cxgbi_device *cdev, unsigned int max_lun, - unsigned int max_id, struct scsi_host_template *sht, - struct scsi_transport_template *stt) -{ - struct cxgbi_hba *chba; - struct Scsi_Host *shost; - int i, err; - - log_debug(1 << CXGBI_DBG_DEV, "cdev 0x%p, p#%u.\n", cdev, cdev->nports); - - for (i = 0; i < cdev->nports; i++) { - shost = iscsi_host_alloc(sht, sizeof(*chba), 1); - if (!shost) { - pr_info("0x%p, p%d, %s, host alloc failed.\n", - cdev, i, cdev->ports[i]->name); - err = -ENOMEM; - goto err_out; - } - - shost->transportt = stt; - shost->max_lun = max_lun; - shost->max_id = max_id; - shost->max_channel = 0; - shost->max_cmd_len = 16; - - chba = iscsi_host_priv(shost); - chba->cdev = cdev; - chba->ndev = cdev->ports[i]; - chba->shost = shost; - - log_debug(1 << CXGBI_DBG_DEV, - "cdev 0x%p, p#%d %s: chba 0x%p.\n", - cdev, i, cdev->ports[i]->name, chba); - - pci_dev_get(cdev->pdev); - err = iscsi_host_add(shost, &cdev->pdev->dev); - if (err) { - pr_info("cdev 0x%p, p#%d %s, host add failed.\n", - cdev, i, cdev->ports[i]->name); - pci_dev_put(cdev->pdev); - scsi_host_put(shost); - goto err_out; - } - - cdev->hbas[i] = chba; - } - - return 0; - -err_out: - cxgbi_hbas_remove(cdev); - return err; -} -EXPORT_SYMBOL_GPL(cxgbi_hbas_add); - -/* - * iSCSI offload - * - * - source port management - * To find a free source port in the port allocation map we use a very simple - * rotor scheme to look for the next free port. - * - * If a source port has been specified make sure that it doesn't collide with - * our normal source port allocation map. If it's outside the range of our - * allocation/deallocation scheme just let them use it. - * - * If the source port is outside our allocation range, the caller is - * responsible for keeping track of their port usage. - */ -static int sock_get_port(struct cxgbi_sock *csk) -{ - struct cxgbi_device *cdev = csk->cdev; - struct cxgbi_ports_map *pmap = &cdev->pmap; - unsigned int start; - int idx; - - if (!pmap->max_connect) { - pr_err("cdev 0x%p, p#%u %s, NO port map.\n", - cdev, csk->port_id, cdev->ports[csk->port_id]->name); - return -EADDRNOTAVAIL; - } - - if (csk->saddr.sin_port) { - pr_err("source port NON-ZERO %u.\n", - ntohs(csk->saddr.sin_port)); - return -EADDRINUSE; - } - - spin_lock_bh(&pmap->lock); - if (pmap->used >= pmap->max_connect) { - spin_unlock_bh(&pmap->lock); - pr_info("cdev 0x%p, p#%u %s, ALL ports used.\n", - cdev, csk->port_id, cdev->ports[csk->port_id]->name); - return -EADDRNOTAVAIL; - } - - start = idx = pmap->next; - do { - if (++idx >= pmap->max_connect) - idx = 0; - if (!pmap->port_csk[idx]) { - pmap->used++; - csk->saddr.sin_port = - htons(pmap->sport_base + idx); - pmap->next = idx; - pmap->port_csk[idx] = csk; - spin_unlock_bh(&pmap->lock); - cxgbi_sock_get(csk); - log_debug(1 << CXGBI_DBG_SOCK, - "cdev 0x%p, p#%u %s, p %u, %u.\n", - cdev, csk->port_id, - cdev->ports[csk->port_id]->name, - pmap->sport_base + idx, pmap->next); - return 0; - } - } while (idx != start); - spin_unlock_bh(&pmap->lock); - - /* should not happen */ - pr_warn("cdev 0x%p, p#%u %s, next %u?\n", - cdev, csk->port_id, cdev->ports[csk->port_id]->name, - pmap->next); - return -EADDRNOTAVAIL; -} - -static void sock_put_port(struct cxgbi_sock *csk) -{ - struct cxgbi_device *cdev = csk->cdev; - struct cxgbi_ports_map *pmap = &cdev->pmap; - - if (csk->saddr.sin_port) { - int idx = ntohs(csk->saddr.sin_port) - pmap->sport_base; - - csk->saddr.sin_port = 0; - if (idx < 0 || idx >= pmap->max_connect) { - pr_err("cdev 0x%p, p#%u %s, port %u OOR.\n", - cdev, csk->port_id, - cdev->ports[csk->port_id]->name, - ntohs(csk->saddr.sin_port)); - return; - } - - spin_lock_bh(&pmap->lock); - pmap->port_csk[idx] = NULL; - pmap->used--; - spin_unlock_bh(&pmap->lock); - - log_debug(1 << CXGBI_DBG_SOCK, - "cdev 0x%p, p#%u %s, release %u.\n", - cdev, csk->port_id, cdev->ports[csk->port_id]->name, - pmap->sport_base + idx); - - cxgbi_sock_put(csk); - } -} - -/* - * iscsi tcp connection - */ -void cxgbi_sock_free_cpl_skbs(struct cxgbi_sock *csk) -{ - if (csk->cpl_close) { - kfree_skb(csk->cpl_close); - csk->cpl_close = NULL; - } - if (csk->cpl_abort_req) { - kfree_skb(csk->cpl_abort_req); - csk->cpl_abort_req = NULL; - } - if (csk->cpl_abort_rpl) { - kfree_skb(csk->cpl_abort_rpl); - csk->cpl_abort_rpl = NULL; - } -} -EXPORT_SYMBOL_GPL(cxgbi_sock_free_cpl_skbs); - -static struct cxgbi_sock *cxgbi_sock_create(struct cxgbi_device *cdev) -{ - struct cxgbi_sock *csk = kzalloc(sizeof(*csk), GFP_NOIO); - - if (!csk) { - pr_info("alloc csk %zu failed.\n", sizeof(*csk)); - return NULL; - } - - if (cdev->csk_alloc_cpls(csk) < 0) { - pr_info("csk 0x%p, alloc cpls failed.\n", csk); - kfree(csk); - return NULL; - } - - spin_lock_init(&csk->lock); - kref_init(&csk->refcnt); - skb_queue_head_init(&csk->receive_queue); - skb_queue_head_init(&csk->write_queue); - setup_timer(&csk->retry_timer, NULL, (unsigned long)csk); - rwlock_init(&csk->callback_lock); - csk->cdev = cdev; - csk->flags = 0; - cxgbi_sock_set_state(csk, CTP_CLOSED); - - log_debug(1 << CXGBI_DBG_SOCK, "cdev 0x%p, new csk 0x%p.\n", cdev, csk); - - return csk; -} - -static struct rtable *find_route_ipv4(struct flowi4 *fl4, - __be32 saddr, __be32 daddr, - __be16 sport, __be16 dport, u8 tos) -{ - struct rtable *rt; - - rt = ip_route_output_ports(&init_net, fl4, NULL, daddr, saddr, - dport, sport, IPPROTO_TCP, tos, 0); - if (IS_ERR(rt)) - return NULL; - - return rt; -} - -static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) -{ - struct sockaddr_in *daddr = (struct sockaddr_in *)dst_addr; - struct dst_entry *dst; - struct net_device *ndev; - struct cxgbi_device *cdev; - struct rtable *rt = NULL; - struct neighbour *n; - struct flowi4 fl4; - struct cxgbi_sock *csk = NULL; - unsigned int mtu = 0; - int port = 0xFFFF; - int err = 0; - - if (daddr->sin_family != AF_INET) { - pr_info("address family 0x%x NOT supported.\n", - daddr->sin_family); - err = -EAFNOSUPPORT; - goto err_out; - } - - rt = find_route_ipv4(&fl4, 0, daddr->sin_addr.s_addr, 0, daddr->sin_port, 0); - if (!rt) { - pr_info("no route to ipv4 0x%x, port %u.\n", - daddr->sin_addr.s_addr, daddr->sin_port); - err = -ENETUNREACH; - goto err_out; - } - dst = &rt->dst; - n = dst_get_neighbour_noref(dst); - if (!n) { - err = -ENODEV; - goto rel_rt; - } - ndev = n->dev; - - if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { - pr_info("multi-cast route %pI4, port %u, dev %s.\n", - &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), - ndev->name); - err = -ENETUNREACH; - goto rel_rt; - } - - if (ndev->flags & IFF_LOOPBACK) { - ndev = ip_dev_find(&init_net, daddr->sin_addr.s_addr); - mtu = ndev->mtu; - pr_info("rt dev %s, loopback -> %s, mtu %u.\n", - n->dev->name, ndev->name, mtu); - } - - cdev = cxgbi_device_find_by_netdev(ndev, &port); - if (!cdev) { - pr_info("dst %pI4, %s, NOT cxgbi device.\n", - &daddr->sin_addr.s_addr, ndev->name); - err = -ENETUNREACH; - goto rel_rt; - } - log_debug(1 << CXGBI_DBG_SOCK, - "route to %pI4 :%u, ndev p#%d,%s, cdev 0x%p.\n", - &daddr->sin_addr.s_addr, ntohs(daddr->sin_port), - port, ndev->name, cdev); - - csk = cxgbi_sock_create(cdev); - if (!csk) { - err = -ENOMEM; - goto rel_rt; - } - csk->cdev = cdev; - csk->port_id = port; - csk->mtu = mtu; - csk->dst = dst; - csk->daddr.sin_addr.s_addr = daddr->sin_addr.s_addr; - csk->daddr.sin_port = daddr->sin_port; - csk->daddr.sin_family = daddr->sin_family; - csk->saddr.sin_addr.s_addr = fl4.saddr; - - return csk; - -rel_rt: - ip_rt_put(rt); - if (csk) - cxgbi_sock_closed(csk); -err_out: - return ERR_PTR(err); -} - -void cxgbi_sock_established(struct cxgbi_sock *csk, unsigned int snd_isn, - unsigned int opt) -{ - csk->write_seq = csk->snd_nxt = csk->snd_una = snd_isn; - dst_confirm(csk->dst); - smp_mb(); - cxgbi_sock_set_state(csk, CTP_ESTABLISHED); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_established); - -static void cxgbi_inform_iscsi_conn_closing(struct cxgbi_sock *csk) -{ - log_debug(1 << CXGBI_DBG_SOCK, - "csk 0x%p, state %u, flags 0x%lx, conn 0x%p.\n", - csk, csk->state, csk->flags, csk->user_data); - - if (csk->state != CTP_ESTABLISHED) { - read_lock_bh(&csk->callback_lock); - if (csk->user_data) - iscsi_conn_failure(csk->user_data, - ISCSI_ERR_CONN_FAILED); - read_unlock_bh(&csk->callback_lock); - } -} - -void cxgbi_sock_closed(struct cxgbi_sock *csk) -{ - log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", - csk, (csk)->state, (csk)->flags, (csk)->tid); - cxgbi_sock_set_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED); - if (csk->state == CTP_ACTIVE_OPEN || csk->state == CTP_CLOSED) - return; - if (csk->saddr.sin_port) - sock_put_port(csk); - if (csk->dst) - dst_release(csk->dst); - csk->cdev->csk_release_offload_resources(csk); - cxgbi_sock_set_state(csk, CTP_CLOSED); - cxgbi_inform_iscsi_conn_closing(csk); - cxgbi_sock_put(csk); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_closed); - -static void need_active_close(struct cxgbi_sock *csk) -{ - int data_lost; - int close_req = 0; - - log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", - csk, (csk)->state, (csk)->flags, (csk)->tid); - spin_lock_bh(&csk->lock); - dst_confirm(csk->dst); - data_lost = skb_queue_len(&csk->receive_queue); - __skb_queue_purge(&csk->receive_queue); - - if (csk->state == CTP_ACTIVE_OPEN) - cxgbi_sock_set_flag(csk, CTPF_ACTIVE_CLOSE_NEEDED); - else if (csk->state == CTP_ESTABLISHED) { - close_req = 1; - cxgbi_sock_set_state(csk, CTP_ACTIVE_CLOSE); - } else if (csk->state == CTP_PASSIVE_CLOSE) { - close_req = 1; - cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_2); - } - - if (close_req) { - if (data_lost) - csk->cdev->csk_send_abort_req(csk); - else - csk->cdev->csk_send_close_req(csk); - } - - spin_unlock_bh(&csk->lock); -} - -void cxgbi_sock_fail_act_open(struct cxgbi_sock *csk, int errno) -{ - pr_info("csk 0x%p,%u,%lx, %pI4:%u-%pI4:%u, err %d.\n", - csk, csk->state, csk->flags, - &csk->saddr.sin_addr.s_addr, csk->saddr.sin_port, - &csk->daddr.sin_addr.s_addr, csk->daddr.sin_port, - errno); - - cxgbi_sock_set_state(csk, CTP_CONNECTING); - csk->err = errno; - cxgbi_sock_closed(csk); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_fail_act_open); - -void cxgbi_sock_act_open_req_arp_failure(void *handle, struct sk_buff *skb) -{ - struct cxgbi_sock *csk = (struct cxgbi_sock *)skb->sk; - - log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", - csk, (csk)->state, (csk)->flags, (csk)->tid); - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - if (csk->state == CTP_ACTIVE_OPEN) - cxgbi_sock_fail_act_open(csk, -EHOSTUNREACH); - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); - __kfree_skb(skb); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_act_open_req_arp_failure); - -void cxgbi_sock_rcv_abort_rpl(struct cxgbi_sock *csk) -{ - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) { - if (!cxgbi_sock_flag(csk, CTPF_ABORT_RPL_RCVD)) - cxgbi_sock_set_flag(csk, CTPF_ABORT_RPL_RCVD); - else { - cxgbi_sock_clear_flag(csk, CTPF_ABORT_RPL_RCVD); - cxgbi_sock_clear_flag(csk, CTPF_ABORT_RPL_PENDING); - if (cxgbi_sock_flag(csk, CTPF_ABORT_REQ_RCVD)) - pr_err("csk 0x%p,%u,0x%lx,%u,ABT_RPL_RSS.\n", - csk, csk->state, csk->flags, csk->tid); - cxgbi_sock_closed(csk); - } - } - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_rcv_abort_rpl); - -void cxgbi_sock_rcv_peer_close(struct cxgbi_sock *csk) -{ - log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", - csk, (csk)->state, (csk)->flags, (csk)->tid); - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - - if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) - goto done; - - switch (csk->state) { - case CTP_ESTABLISHED: - cxgbi_sock_set_state(csk, CTP_PASSIVE_CLOSE); - break; - case CTP_ACTIVE_CLOSE: - cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_2); - break; - case CTP_CLOSE_WAIT_1: - cxgbi_sock_closed(csk); - break; - case CTP_ABORTING: - break; - default: - pr_err("csk 0x%p,%u,0x%lx,%u, bad state.\n", - csk, csk->state, csk->flags, csk->tid); - } - cxgbi_inform_iscsi_conn_closing(csk); -done: - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_rcv_peer_close); - -void cxgbi_sock_rcv_close_conn_rpl(struct cxgbi_sock *csk, u32 snd_nxt) -{ - log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", - csk, (csk)->state, (csk)->flags, (csk)->tid); - cxgbi_sock_get(csk); - spin_lock_bh(&csk->lock); - - csk->snd_una = snd_nxt - 1; - if (cxgbi_sock_flag(csk, CTPF_ABORT_RPL_PENDING)) - goto done; - - switch (csk->state) { - case CTP_ACTIVE_CLOSE: - cxgbi_sock_set_state(csk, CTP_CLOSE_WAIT_1); - break; - case CTP_CLOSE_WAIT_1: - case CTP_CLOSE_WAIT_2: - cxgbi_sock_closed(csk); - break; - case CTP_ABORTING: - break; - default: - pr_err("csk 0x%p,%u,0x%lx,%u, bad state.\n", - csk, csk->state, csk->flags, csk->tid); - } -done: - spin_unlock_bh(&csk->lock); - cxgbi_sock_put(csk); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_rcv_close_conn_rpl); - -void cxgbi_sock_rcv_wr_ack(struct cxgbi_sock *csk, unsigned int credits, - unsigned int snd_una, int seq_chk) -{ - log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, snd_una %u,%d.\n", - csk, csk->state, csk->flags, csk->tid, credits, - csk->wr_cred, csk->wr_una_cred, snd_una, seq_chk); - - spin_lock_bh(&csk->lock); - - csk->wr_cred += credits; - if (csk->wr_una_cred > csk->wr_max_cred - csk->wr_cred) - csk->wr_una_cred = csk->wr_max_cred - csk->wr_cred; - - while (credits) { - struct sk_buff *p = cxgbi_sock_peek_wr(csk); - - if (unlikely(!p)) { - pr_err("csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, empty.\n", - csk, csk->state, csk->flags, csk->tid, credits, - csk->wr_cred, csk->wr_una_cred); - break; - } - - if (unlikely(credits < p->csum)) { - pr_warn("csk 0x%p,%u,0x%lx,%u, cr %u,%u+%u, < %u.\n", - csk, csk->state, csk->flags, csk->tid, - credits, csk->wr_cred, csk->wr_una_cred, - p->csum); - p->csum -= credits; - break; - } else { - cxgbi_sock_dequeue_wr(csk); - credits -= p->csum; - kfree_skb(p); - } - } - - cxgbi_sock_check_wr_invariants(csk); - - if (seq_chk) { - if (unlikely(before(snd_una, csk->snd_una))) { - pr_warn("csk 0x%p,%u,0x%lx,%u, snd_una %u/%u.", - csk, csk->state, csk->flags, csk->tid, snd_una, - csk->snd_una); - goto done; - } - - if (csk->snd_una != snd_una) { - csk->snd_una = snd_una; - dst_confirm(csk->dst); - } - } - - if (skb_queue_len(&csk->write_queue)) { - if (csk->cdev->csk_push_tx_frames(csk, 0)) - cxgbi_conn_tx_open(csk); - } else - cxgbi_conn_tx_open(csk); -done: - spin_unlock_bh(&csk->lock); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_rcv_wr_ack); - -static unsigned int cxgbi_sock_find_best_mtu(struct cxgbi_sock *csk, - unsigned short mtu) -{ - int i = 0; - - while (i < csk->cdev->nmtus - 1 && csk->cdev->mtus[i + 1] <= mtu) - ++i; - - return i; -} - -unsigned int cxgbi_sock_select_mss(struct cxgbi_sock *csk, unsigned int pmtu) -{ - unsigned int idx; - struct dst_entry *dst = csk->dst; - - csk->advmss = dst_metric_advmss(dst); - - if (csk->advmss > pmtu - 40) - csk->advmss = pmtu - 40; - if (csk->advmss < csk->cdev->mtus[0] - 40) - csk->advmss = csk->cdev->mtus[0] - 40; - idx = cxgbi_sock_find_best_mtu(csk, csk->advmss + 40); - - return idx; -} -EXPORT_SYMBOL_GPL(cxgbi_sock_select_mss); - -void cxgbi_sock_skb_entail(struct cxgbi_sock *csk, struct sk_buff *skb) -{ - cxgbi_skcb_tcp_seq(skb) = csk->write_seq; - __skb_queue_tail(&csk->write_queue, skb); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_skb_entail); - -void cxgbi_sock_purge_wr_queue(struct cxgbi_sock *csk) -{ - struct sk_buff *skb; - - while ((skb = cxgbi_sock_dequeue_wr(csk)) != NULL) - kfree_skb(skb); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_purge_wr_queue); - -void cxgbi_sock_check_wr_invariants(const struct cxgbi_sock *csk) -{ - int pending = cxgbi_sock_count_pending_wrs(csk); - - if (unlikely(csk->wr_cred + pending != csk->wr_max_cred)) - pr_err("csk 0x%p, tid %u, credit %u + %u != %u.\n", - csk, csk->tid, csk->wr_cred, pending, csk->wr_max_cred); -} -EXPORT_SYMBOL_GPL(cxgbi_sock_check_wr_invariants); - -static int cxgbi_sock_send_pdus(struct cxgbi_sock *csk, struct sk_buff *skb) -{ - struct cxgbi_device *cdev = csk->cdev; - struct sk_buff *next; - int err, copied = 0; - - spin_lock_bh(&csk->lock); - - if (csk->state != CTP_ESTABLISHED) { - log_debug(1 << CXGBI_DBG_PDU_TX, - "csk 0x%p,%u,0x%lx,%u, EAGAIN.\n", - csk, csk->state, csk->flags, csk->tid); - err = -EAGAIN; - goto out_err; - } - - if (csk->err) { - log_debug(1 << CXGBI_DBG_PDU_TX, - "csk 0x%p,%u,0x%lx,%u, EPIPE %d.\n", - csk, csk->state, csk->flags, csk->tid, csk->err); - err = -EPIPE; - goto out_err; - } - - if (csk->write_seq - csk->snd_una >= cdev->snd_win) { - log_debug(1 << CXGBI_DBG_PDU_TX, - "csk 0x%p,%u,0x%lx,%u, FULL %u-%u >= %u.\n", - csk, csk->state, csk->flags, csk->tid, csk->write_seq, - csk->snd_una, cdev->snd_win); - err = -ENOBUFS; - goto out_err; - } - - while (skb) { - int frags = skb_shinfo(skb)->nr_frags + - (skb->len != skb->data_len); - - if (unlikely(skb_headroom(skb) < cdev->skb_tx_rsvd)) { - pr_err("csk 0x%p, skb head %u < %u.\n", - csk, skb_headroom(skb), cdev->skb_tx_rsvd); - err = -EINVAL; - goto out_err; - } - - if (frags >= SKB_WR_LIST_SIZE) { - pr_err("csk 0x%p, frags %d, %u,%u >%u.\n", - csk, skb_shinfo(skb)->nr_frags, skb->len, - skb->data_len, (uint)(SKB_WR_LIST_SIZE)); - err = -EINVAL; - goto out_err; - } - - next = skb->next; - skb->next = NULL; - cxgbi_skcb_set_flag(skb, SKCBF_TX_NEED_HDR); - cxgbi_sock_skb_entail(csk, skb); - copied += skb->len; - csk->write_seq += skb->len + - cxgbi_ulp_extra_len(cxgbi_skcb_ulp_mode(skb)); - skb = next; - } -done: - if (likely(skb_queue_len(&csk->write_queue))) - cdev->csk_push_tx_frames(csk, 1); - spin_unlock_bh(&csk->lock); - return copied; - -out_err: - if (copied == 0 && err == -EPIPE) - copied = csk->err ? csk->err : -EPIPE; - else - copied = err; - goto done; -} - -/* - * Direct Data Placement - - * Directly place the iSCSI Data-In or Data-Out PDU's payload into pre-posted - * final destination host-memory buffers based on the Initiator Task Tag (ITT) - * in Data-In or Target Task Tag (TTT) in Data-Out PDUs. - * The host memory address is programmed into h/w in the format of pagepod - * entries. - * The location of the pagepod entry is encoded into ddp tag which is used as - * the base for ITT/TTT. - */ - -static unsigned char ddp_page_order[DDP_PGIDX_MAX] = {0, 1, 2, 4}; -static unsigned char ddp_page_shift[DDP_PGIDX_MAX] = {12, 13, 14, 16}; -static unsigned char page_idx = DDP_PGIDX_MAX; - -static unsigned char sw_tag_idx_bits; -static unsigned char sw_tag_age_bits; - -/* - * Direct-Data Placement page size adjustment - */ -static int ddp_adjust_page_table(void) -{ - int i; - unsigned int base_order, order; - - if (PAGE_SIZE < (1UL << ddp_page_shift[0])) { - pr_info("PAGE_SIZE 0x%lx too small, min 0x%lx\n", - PAGE_SIZE, 1UL << ddp_page_shift[0]); - return -EINVAL; - } - - base_order = get_order(1UL << ddp_page_shift[0]); - order = get_order(1UL << PAGE_SHIFT); - - for (i = 0; i < DDP_PGIDX_MAX; i++) { - /* first is the kernel page size, then just doubling */ - ddp_page_order[i] = order - base_order + i; - ddp_page_shift[i] = PAGE_SHIFT + i; - } - return 0; -} - -static int ddp_find_page_index(unsigned long pgsz) -{ - int i; - - for (i = 0; i < DDP_PGIDX_MAX; i++) { - if (pgsz == (1UL << ddp_page_shift[i])) - return i; - } - pr_info("ddp page size %lu not supported.\n", pgsz); - return DDP_PGIDX_MAX; -} - -static void ddp_setup_host_page_size(void) -{ - if (page_idx == DDP_PGIDX_MAX) { - page_idx = ddp_find_page_index(PAGE_SIZE); - - if (page_idx == DDP_PGIDX_MAX) { - pr_info("system PAGE %lu, update hw.\n", PAGE_SIZE); - if (ddp_adjust_page_table() < 0) { - pr_info("PAGE %lu, disable ddp.\n", PAGE_SIZE); - return; - } - page_idx = ddp_find_page_index(PAGE_SIZE); - } - pr_info("system PAGE %lu, ddp idx %u.\n", PAGE_SIZE, page_idx); - } -} - -void cxgbi_ddp_page_size_factor(int *pgsz_factor) -{ - int i; - - for (i = 0; i < DDP_PGIDX_MAX; i++) - pgsz_factor[i] = ddp_page_order[i]; -} -EXPORT_SYMBOL_GPL(cxgbi_ddp_page_size_factor); - -/* - * DDP setup & teardown - */ - -void cxgbi_ddp_ppod_set(struct cxgbi_pagepod *ppod, - struct cxgbi_pagepod_hdr *hdr, - struct cxgbi_gather_list *gl, unsigned int gidx) -{ - int i; - - memcpy(ppod, hdr, sizeof(*hdr)); - for (i = 0; i < (PPOD_PAGES_MAX + 1); i++, gidx++) { - ppod->addr[i] = gidx < gl->nelem ? - cpu_to_be64(gl->phys_addr[gidx]) : 0ULL; - } -} -EXPORT_SYMBOL_GPL(cxgbi_ddp_ppod_set); - -void cxgbi_ddp_ppod_clear(struct cxgbi_pagepod *ppod) -{ - memset(ppod, 0, sizeof(*ppod)); -} -EXPORT_SYMBOL_GPL(cxgbi_ddp_ppod_clear); - -static inline int ddp_find_unused_entries(struct cxgbi_ddp_info *ddp, - unsigned int start, unsigned int max, - unsigned int count, - struct cxgbi_gather_list *gl) -{ - unsigned int i, j, k; - - /* not enough entries */ - if ((max - start) < count) { - log_debug(1 << CXGBI_DBG_DDP, - "NOT enough entries %u+%u < %u.\n", start, count, max); - return -EBUSY; - } - - max -= count; - spin_lock(&ddp->map_lock); - for (i = start; i < max;) { - for (j = 0, k = i; j < count; j++, k++) { - if (ddp->gl_map[k]) - break; - } - if (j == count) { - for (j = 0, k = i; j < count; j++, k++) - ddp->gl_map[k] = gl; - spin_unlock(&ddp->map_lock); - return i; - } - i += j + 1; - } - spin_unlock(&ddp->map_lock); - log_debug(1 << CXGBI_DBG_DDP, - "NO suitable entries %u available.\n", count); - return -EBUSY; -} - -static inline void ddp_unmark_entries(struct cxgbi_ddp_info *ddp, - int start, int count) -{ - spin_lock(&ddp->map_lock); - memset(&ddp->gl_map[start], 0, - count * sizeof(struct cxgbi_gather_list *)); - spin_unlock(&ddp->map_lock); -} - -static inline void ddp_gl_unmap(struct pci_dev *pdev, - struct cxgbi_gather_list *gl) -{ - int i; - - for (i = 0; i < gl->nelem; i++) - dma_unmap_page(&pdev->dev, gl->phys_addr[i], PAGE_SIZE, - PCI_DMA_FROMDEVICE); -} - -static inline int ddp_gl_map(struct pci_dev *pdev, - struct cxgbi_gather_list *gl) -{ - int i; - - for (i = 0; i < gl->nelem; i++) { - gl->phys_addr[i] = dma_map_page(&pdev->dev, gl->pages[i], 0, - PAGE_SIZE, - PCI_DMA_FROMDEVICE); - if (unlikely(dma_mapping_error(&pdev->dev, gl->phys_addr[i]))) { - log_debug(1 << CXGBI_DBG_DDP, - "page %d 0x%p, 0x%p dma mapping err.\n", - i, gl->pages[i], pdev); - goto unmap; - } - } - return i; -unmap: - if (i) { - unsigned int nelem = gl->nelem; - - gl->nelem = i; - ddp_gl_unmap(pdev, gl); - gl->nelem = nelem; - } - return -EINVAL; -} - -static void ddp_release_gl(struct cxgbi_gather_list *gl, - struct pci_dev *pdev) -{ - ddp_gl_unmap(pdev, gl); - kfree(gl); -} - -static struct cxgbi_gather_list *ddp_make_gl(unsigned int xferlen, - struct scatterlist *sgl, - unsigned int sgcnt, - struct pci_dev *pdev, - gfp_t gfp) -{ - struct cxgbi_gather_list *gl; - struct scatterlist *sg = sgl; - struct page *sgpage = sg_page(sg); - unsigned int sglen = sg->length; - unsigned int sgoffset = sg->offset; - unsigned int npages = (xferlen + sgoffset + PAGE_SIZE - 1) >> - PAGE_SHIFT; - int i = 1, j = 0; - - if (xferlen < DDP_THRESHOLD) { - log_debug(1 << CXGBI_DBG_DDP, - "xfer %u < threshold %u, no ddp.\n", - xferlen, DDP_THRESHOLD); - return NULL; - } - - gl = kzalloc(sizeof(struct cxgbi_gather_list) + - npages * (sizeof(dma_addr_t) + - sizeof(struct page *)), gfp); - if (!gl) { - log_debug(1 << CXGBI_DBG_DDP, - "xfer %u, %u pages, OOM.\n", xferlen, npages); - return NULL; - } - - log_debug(1 << CXGBI_DBG_DDP, - "xfer %u, sgl %u, gl max %u.\n", xferlen, sgcnt, npages); - - gl->pages = (struct page **)&gl->phys_addr[npages]; - gl->nelem = npages; - gl->length = xferlen; - gl->offset = sgoffset; - gl->pages[0] = sgpage; - - for (i = 1, sg = sg_next(sgl), j = 0; i < sgcnt; - i++, sg = sg_next(sg)) { - struct page *page = sg_page(sg); - - if (sgpage == page && sg->offset == sgoffset + sglen) - sglen += sg->length; - else { - /* make sure the sgl is fit for ddp: - * each has the same page size, and - * all of the middle pages are used completely - */ - if ((j && sgoffset) || ((i != sgcnt - 1) && - ((sglen + sgoffset) & ~PAGE_MASK))) { - log_debug(1 << CXGBI_DBG_DDP, - "page %d/%u, %u + %u.\n", - i, sgcnt, sgoffset, sglen); - goto error_out; - } - - j++; - if (j == gl->nelem || sg->offset) { - log_debug(1 << CXGBI_DBG_DDP, - "page %d/%u, offset %u.\n", - j, gl->nelem, sg->offset); - goto error_out; - } - gl->pages[j] = page; - sglen = sg->length; - sgoffset = sg->offset; - sgpage = page; - } - } - gl->nelem = ++j; - - if (ddp_gl_map(pdev, gl) < 0) - goto error_out; - - return gl; - -error_out: - kfree(gl); - return NULL; -} - -static void ddp_tag_release(struct cxgbi_hba *chba, u32 tag) -{ - struct cxgbi_device *cdev = chba->cdev; - struct cxgbi_ddp_info *ddp = cdev->ddp; - u32 idx; - - idx = (tag >> PPOD_IDX_SHIFT) & ddp->idx_mask; - if (idx < ddp->nppods) { - struct cxgbi_gather_list *gl = ddp->gl_map[idx]; - unsigned int npods; - - if (!gl || !gl->nelem) { - pr_warn("tag 0x%x, idx %u, gl 0x%p, %u.\n", - tag, idx, gl, gl ? gl->nelem : 0); - return; - } - npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; - log_debug(1 << CXGBI_DBG_DDP, - "tag 0x%x, release idx %u, npods %u.\n", - tag, idx, npods); - cdev->csk_ddp_clear(chba, tag, idx, npods); - ddp_unmark_entries(ddp, idx, npods); - ddp_release_gl(gl, ddp->pdev); - } else - pr_warn("tag 0x%x, idx %u > max %u.\n", tag, idx, ddp->nppods); -} - -static int ddp_tag_reserve(struct cxgbi_sock *csk, unsigned int tid, - u32 sw_tag, u32 *tagp, struct cxgbi_gather_list *gl, - gfp_t gfp) -{ - struct cxgbi_device *cdev = csk->cdev; - struct cxgbi_ddp_info *ddp = cdev->ddp; - struct cxgbi_tag_format *tformat = &cdev->tag_format; - struct cxgbi_pagepod_hdr hdr; - unsigned int npods; - int idx = -1; - int err = -ENOMEM; - u32 tag; - - npods = (gl->nelem + PPOD_PAGES_MAX - 1) >> PPOD_PAGES_SHIFT; - if (ddp->idx_last == ddp->nppods) - idx = ddp_find_unused_entries(ddp, 0, ddp->nppods, - npods, gl); - else { - idx = ddp_find_unused_entries(ddp, ddp->idx_last + 1, - ddp->nppods, npods, - gl); - if (idx < 0 && ddp->idx_last >= npods) { - idx = ddp_find_unused_entries(ddp, 0, - min(ddp->idx_last + npods, ddp->nppods), - npods, gl); - } - } - if (idx < 0) { - log_debug(1 << CXGBI_DBG_DDP, - "xferlen %u, gl %u, npods %u NO DDP.\n", - gl->length, gl->nelem, npods); - return idx; - } - - tag = cxgbi_ddp_tag_base(tformat, sw_tag); - tag |= idx << PPOD_IDX_SHIFT; - - hdr.rsvd = 0; - hdr.vld_tid = htonl(PPOD_VALID_FLAG | PPOD_TID(tid)); - hdr.pgsz_tag_clr = htonl(tag & ddp->rsvd_tag_mask); - hdr.max_offset = htonl(gl->length); - hdr.page_offset = htonl(gl->offset); - - err = cdev->csk_ddp_set(csk, &hdr, idx, npods, gl); - if (err < 0) - goto unmark_entries; - - ddp->idx_last = idx; - log_debug(1 << CXGBI_DBG_DDP, - "xfer %u, gl %u,%u, tid 0x%x, tag 0x%x->0x%x(%u,%u).\n", - gl->length, gl->nelem, gl->offset, tid, sw_tag, tag, idx, - npods); - *tagp = tag; - return 0; - -unmark_entries: - ddp_unmark_entries(ddp, idx, npods); - return err; -} - -int cxgbi_ddp_reserve(struct cxgbi_sock *csk, unsigned int *tagp, - unsigned int sw_tag, unsigned int xferlen, - struct scatterlist *sgl, unsigned int sgcnt, gfp_t gfp) -{ - struct cxgbi_device *cdev = csk->cdev; - struct cxgbi_tag_format *tformat = &cdev->tag_format; - struct cxgbi_gather_list *gl; - int err; - - if (page_idx >= DDP_PGIDX_MAX || !cdev->ddp || - xferlen < DDP_THRESHOLD) { - log_debug(1 << CXGBI_DBG_DDP, - "pgidx %u, xfer %u, NO ddp.\n", page_idx, xferlen); - return -EINVAL; - } - - if (!cxgbi_sw_tag_usable(tformat, sw_tag)) { - log_debug(1 << CXGBI_DBG_DDP, - "sw_tag 0x%x NOT usable.\n", sw_tag); - return -EINVAL; - } - - gl = ddp_make_gl(xferlen, sgl, sgcnt, cdev->pdev, gfp); - if (!gl) - return -ENOMEM; - - err = ddp_tag_reserve(csk, csk->tid, sw_tag, tagp, gl, gfp); - if (err < 0) - ddp_release_gl(gl, cdev->pdev); - - return err; -} - -static void ddp_destroy(struct kref *kref) -{ - struct cxgbi_ddp_info *ddp = container_of(kref, - struct cxgbi_ddp_info, - refcnt); - struct cxgbi_device *cdev = ddp->cdev; - int i = 0; - - pr_info("kref 0, destroy ddp 0x%p, cdev 0x%p.\n", ddp, cdev); - - while (i < ddp->nppods) { - struct cxgbi_gather_list *gl = ddp->gl_map[i]; - - if (gl) { - int npods = (gl->nelem + PPOD_PAGES_MAX - 1) - >> PPOD_PAGES_SHIFT; - pr_info("cdev 0x%p, ddp %d + %d.\n", cdev, i, npods); - kfree(gl); - i += npods; - } else - i++; - } - cxgbi_free_big_mem(ddp); -} - -int cxgbi_ddp_cleanup(struct cxgbi_device *cdev) -{ - struct cxgbi_ddp_info *ddp = cdev->ddp; - - log_debug(1 << CXGBI_DBG_DDP, - "cdev 0x%p, release ddp 0x%p.\n", cdev, ddp); - cdev->ddp = NULL; - if (ddp) - return kref_put(&ddp->refcnt, ddp_destroy); - return 0; -} -EXPORT_SYMBOL_GPL(cxgbi_ddp_cleanup); - -int cxgbi_ddp_init(struct cxgbi_device *cdev, - unsigned int llimit, unsigned int ulimit, - unsigned int max_txsz, unsigned int max_rxsz) -{ - struct cxgbi_ddp_info *ddp; - unsigned int ppmax, bits; - - ppmax = (ulimit - llimit + 1) >> PPOD_SIZE_SHIFT; - bits = __ilog2_u32(ppmax) + 1; - if (bits > PPOD_IDX_MAX_SIZE) - bits = PPOD_IDX_MAX_SIZE; - ppmax = (1 << (bits - 1)) - 1; - - ddp = cxgbi_alloc_big_mem(sizeof(struct cxgbi_ddp_info) + - ppmax * (sizeof(struct cxgbi_gather_list *) + - sizeof(struct sk_buff *)), - GFP_KERNEL); - if (!ddp) { - pr_warn("cdev 0x%p, ddp ppmax %u OOM.\n", cdev, ppmax); - return -ENOMEM; - } - ddp->gl_map = (struct cxgbi_gather_list **)(ddp + 1); - cdev->ddp = ddp; - - spin_lock_init(&ddp->map_lock); - kref_init(&ddp->refcnt); - - ddp->cdev = cdev; - ddp->pdev = cdev->pdev; - ddp->llimit = llimit; - ddp->ulimit = ulimit; - ddp->max_txsz = min_t(unsigned int, max_txsz, ULP2_MAX_PKT_SIZE); - ddp->max_rxsz = min_t(unsigned int, max_rxsz, ULP2_MAX_PKT_SIZE); - ddp->nppods = ppmax; - ddp->idx_last = ppmax; - ddp->idx_bits = bits; - ddp->idx_mask = (1 << bits) - 1; - ddp->rsvd_tag_mask = (1 << (bits + PPOD_IDX_SHIFT)) - 1; - - cdev->tag_format.sw_bits = sw_tag_idx_bits + sw_tag_age_bits; - cdev->tag_format.rsvd_bits = ddp->idx_bits; - cdev->tag_format.rsvd_shift = PPOD_IDX_SHIFT; - cdev->tag_format.rsvd_mask = (1 << cdev->tag_format.rsvd_bits) - 1; - - pr_info("%s tag format, sw %u, rsvd %u,%u, mask 0x%x.\n", - cdev->ports[0]->name, cdev->tag_format.sw_bits, - cdev->tag_format.rsvd_bits, cdev->tag_format.rsvd_shift, - cdev->tag_format.rsvd_mask); - - cdev->tx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, - ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN); - cdev->rx_max_size = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD, - ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN); - - log_debug(1 << CXGBI_DBG_DDP, - "%s max payload size: %u/%u, %u/%u.\n", - cdev->ports[0]->name, cdev->tx_max_size, ddp->max_txsz, - cdev->rx_max_size, ddp->max_rxsz); - return 0; -} -EXPORT_SYMBOL_GPL(cxgbi_ddp_init); - -/* - * APIs interacting with open-iscsi libraries - */ - -static unsigned char padding[4]; - -static void task_release_itt(struct iscsi_task *task, itt_t hdr_itt) -{ - struct scsi_cmnd *sc = task->sc; - struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - struct cxgbi_hba *chba = cconn->chba; - struct cxgbi_tag_format *tformat = &chba->cdev->tag_format; - u32 tag = ntohl((__force u32)hdr_itt); - - log_debug(1 << CXGBI_DBG_DDP, - "cdev 0x%p, release tag 0x%x.\n", chba->cdev, tag); - if (sc && - (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_FROM_DEVICE) && - cxgbi_is_ddp_tag(tformat, tag)) - ddp_tag_release(chba, tag); -} - -static int task_reserve_itt(struct iscsi_task *task, itt_t *hdr_itt) -{ - struct scsi_cmnd *sc = task->sc; - struct iscsi_conn *conn = task->conn; - struct iscsi_session *sess = conn->session; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - struct cxgbi_hba *chba = cconn->chba; - struct cxgbi_tag_format *tformat = &chba->cdev->tag_format; - u32 sw_tag = (sess->age << cconn->task_idx_bits) | task->itt; - u32 tag = 0; - int err = -EINVAL; - - if (sc && - (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_FROM_DEVICE)) { - err = cxgbi_ddp_reserve(cconn->cep->csk, &tag, sw_tag, - scsi_in(sc)->length, - scsi_in(sc)->table.sgl, - scsi_in(sc)->table.nents, - GFP_ATOMIC); - if (err < 0) - log_debug(1 << CXGBI_DBG_DDP, - "csk 0x%p, R task 0x%p, %u,%u, no ddp.\n", - cconn->cep->csk, task, scsi_in(sc)->length, - scsi_in(sc)->table.nents); - } - - if (err < 0) - tag = cxgbi_set_non_ddp_tag(tformat, sw_tag); - /* the itt need to sent in big-endian order */ - *hdr_itt = (__force itt_t)htonl(tag); - - log_debug(1 << CXGBI_DBG_DDP, - "cdev 0x%p, task 0x%p, 0x%x(0x%x,0x%x)->0x%x/0x%x.\n", - chba->cdev, task, sw_tag, task->itt, sess->age, tag, *hdr_itt); - return 0; -} - -void cxgbi_parse_pdu_itt(struct iscsi_conn *conn, itt_t itt, int *idx, int *age) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - struct cxgbi_device *cdev = cconn->chba->cdev; - u32 tag = ntohl((__force u32) itt); - u32 sw_bits; - - sw_bits = cxgbi_tag_nonrsvd_bits(&cdev->tag_format, tag); - if (idx) - *idx = sw_bits & ((1 << cconn->task_idx_bits) - 1); - if (age) - *age = (sw_bits >> cconn->task_idx_bits) & ISCSI_AGE_MASK; - - log_debug(1 << CXGBI_DBG_DDP, - "cdev 0x%p, tag 0x%x/0x%x, -> 0x%x(0x%x,0x%x).\n", - cdev, tag, itt, sw_bits, idx ? *idx : 0xFFFFF, - age ? *age : 0xFF); -} -EXPORT_SYMBOL_GPL(cxgbi_parse_pdu_itt); - -void cxgbi_conn_tx_open(struct cxgbi_sock *csk) -{ - struct iscsi_conn *conn = csk->user_data; - - if (conn) { - log_debug(1 << CXGBI_DBG_SOCK, - "csk 0x%p, cid %d.\n", csk, conn->id); - iscsi_conn_queue_work(conn); - } -} -EXPORT_SYMBOL_GPL(cxgbi_conn_tx_open); - -/* - * pdu receive, interact with libiscsi_tcp - */ -static inline int read_pdu_skb(struct iscsi_conn *conn, - struct sk_buff *skb, - unsigned int offset, - int offloaded) -{ - int status = 0; - int bytes_read; - - bytes_read = iscsi_tcp_recv_skb(conn, skb, offset, offloaded, &status); - switch (status) { - case ISCSI_TCP_CONN_ERR: - pr_info("skb 0x%p, off %u, %d, TCP_ERR.\n", - skb, offset, offloaded); - return -EIO; - case ISCSI_TCP_SUSPENDED: - log_debug(1 << CXGBI_DBG_PDU_RX, - "skb 0x%p, off %u, %d, TCP_SUSPEND, rc %d.\n", - skb, offset, offloaded, bytes_read); - /* no transfer - just have caller flush queue */ - return bytes_read; - case ISCSI_TCP_SKB_DONE: - pr_info("skb 0x%p, off %u, %d, TCP_SKB_DONE.\n", - skb, offset, offloaded); - /* - * pdus should always fit in the skb and we should get - * segment done notifcation. - */ - iscsi_conn_printk(KERN_ERR, conn, "Invalid pdu or skb."); - return -EFAULT; - case ISCSI_TCP_SEGMENT_DONE: - log_debug(1 << CXGBI_DBG_PDU_RX, - "skb 0x%p, off %u, %d, TCP_SEG_DONE, rc %d.\n", - skb, offset, offloaded, bytes_read); - return bytes_read; - default: - pr_info("skb 0x%p, off %u, %d, invalid status %d.\n", - skb, offset, offloaded, status); - return -EINVAL; - } -} - -static int skb_read_pdu_bhs(struct iscsi_conn *conn, struct sk_buff *skb) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - - log_debug(1 << CXGBI_DBG_PDU_RX, - "conn 0x%p, skb 0x%p, len %u, flag 0x%lx.\n", - conn, skb, skb->len, cxgbi_skcb_flags(skb)); - - if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn)) { - pr_info("conn 0x%p, skb 0x%p, not hdr.\n", conn, skb); - iscsi_conn_failure(conn, ISCSI_ERR_PROTO); - return -EIO; - } - - if (conn->hdrdgst_en && - cxgbi_skcb_test_flag(skb, SKCBF_RX_HCRC_ERR)) { - pr_info("conn 0x%p, skb 0x%p, hcrc.\n", conn, skb); - iscsi_conn_failure(conn, ISCSI_ERR_HDR_DGST); - return -EIO; - } - - return read_pdu_skb(conn, skb, 0, 0); -} - -static int skb_read_pdu_data(struct iscsi_conn *conn, struct sk_buff *lskb, - struct sk_buff *skb, unsigned int offset) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - bool offloaded = 0; - int opcode = tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK; - - log_debug(1 << CXGBI_DBG_PDU_RX, - "conn 0x%p, skb 0x%p, len %u, flag 0x%lx.\n", - conn, skb, skb->len, cxgbi_skcb_flags(skb)); - - if (conn->datadgst_en && - cxgbi_skcb_test_flag(lskb, SKCBF_RX_DCRC_ERR)) { - pr_info("conn 0x%p, skb 0x%p, dcrc 0x%lx.\n", - conn, lskb, cxgbi_skcb_flags(lskb)); - iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST); - return -EIO; - } - - if (iscsi_tcp_recv_segment_is_hdr(tcp_conn)) - return 0; - - /* coalesced, add header digest length */ - if (lskb == skb && conn->hdrdgst_en) - offset += ISCSI_DIGEST_SIZE; - - if (cxgbi_skcb_test_flag(lskb, SKCBF_RX_DATA_DDPD)) - offloaded = 1; - - if (opcode == ISCSI_OP_SCSI_DATA_IN) - log_debug(1 << CXGBI_DBG_PDU_RX, - "skb 0x%p, op 0x%x, itt 0x%x, %u %s ddp'ed.\n", - skb, opcode, ntohl(tcp_conn->in.hdr->itt), - tcp_conn->in.datalen, offloaded ? "is" : "not"); - - return read_pdu_skb(conn, skb, offset, offloaded); -} - -static void csk_return_rx_credits(struct cxgbi_sock *csk, int copied) -{ - struct cxgbi_device *cdev = csk->cdev; - int must_send; - u32 credits; - - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p,%u,0x%lu,%u, seq %u, wup %u, thre %u, %u.\n", - csk, csk->state, csk->flags, csk->tid, csk->copied_seq, - csk->rcv_wup, cdev->rx_credit_thres, - cdev->rcv_win); - - if (csk->state != CTP_ESTABLISHED) - return; - - credits = csk->copied_seq - csk->rcv_wup; - if (unlikely(!credits)) - return; - if (unlikely(cdev->rx_credit_thres == 0)) - return; - - must_send = credits + 16384 >= cdev->rcv_win; - if (must_send || credits >= cdev->rx_credit_thres) - csk->rcv_wup += cdev->csk_send_rx_credits(csk, credits); -} - -void cxgbi_conn_pdu_ready(struct cxgbi_sock *csk) -{ - struct cxgbi_device *cdev = csk->cdev; - struct iscsi_conn *conn = csk->user_data; - struct sk_buff *skb; - unsigned int read = 0; - int err = 0; - - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, conn 0x%p.\n", csk, conn); - - if (unlikely(!conn || conn->suspend_rx)) { - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, conn 0x%p, id %d, suspend_rx %lu!\n", - csk, conn, conn ? conn->id : 0xFF, - conn ? conn->suspend_rx : 0xFF); - return; - } - - while (!err) { - skb = skb_peek(&csk->receive_queue); - if (!skb || - !(cxgbi_skcb_test_flag(skb, SKCBF_RX_STATUS))) { - if (skb) - log_debug(1 << CXGBI_DBG_PDU_RX, - "skb 0x%p, NOT ready 0x%lx.\n", - skb, cxgbi_skcb_flags(skb)); - break; - } - __skb_unlink(skb, &csk->receive_queue); - - read += cxgbi_skcb_rx_pdulen(skb); - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, skb 0x%p,%u,f 0x%lx, pdu len %u.\n", - csk, skb, skb->len, cxgbi_skcb_flags(skb), - cxgbi_skcb_rx_pdulen(skb)); - - if (cxgbi_skcb_test_flag(skb, SKCBF_RX_COALESCED)) { - err = skb_read_pdu_bhs(conn, skb); - if (err < 0) { - pr_err("coalesced bhs, csk 0x%p, skb 0x%p,%u, " - "f 0x%lx, plen %u.\n", - csk, skb, skb->len, - cxgbi_skcb_flags(skb), - cxgbi_skcb_rx_pdulen(skb)); - goto skb_done; - } - err = skb_read_pdu_data(conn, skb, skb, - err + cdev->skb_rx_extra); - if (err < 0) - pr_err("coalesced data, csk 0x%p, skb 0x%p,%u, " - "f 0x%lx, plen %u.\n", - csk, skb, skb->len, - cxgbi_skcb_flags(skb), - cxgbi_skcb_rx_pdulen(skb)); - } else { - err = skb_read_pdu_bhs(conn, skb); - if (err < 0) { - pr_err("bhs, csk 0x%p, skb 0x%p,%u, " - "f 0x%lx, plen %u.\n", - csk, skb, skb->len, - cxgbi_skcb_flags(skb), - cxgbi_skcb_rx_pdulen(skb)); - goto skb_done; - } - - if (cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) { - struct sk_buff *dskb; - - dskb = skb_peek(&csk->receive_queue); - if (!dskb) { - pr_err("csk 0x%p, skb 0x%p,%u, f 0x%lx," - " plen %u, NO data.\n", - csk, skb, skb->len, - cxgbi_skcb_flags(skb), - cxgbi_skcb_rx_pdulen(skb)); - err = -EIO; - goto skb_done; - } - __skb_unlink(dskb, &csk->receive_queue); - - err = skb_read_pdu_data(conn, skb, dskb, 0); - if (err < 0) - pr_err("data, csk 0x%p, skb 0x%p,%u, " - "f 0x%lx, plen %u, dskb 0x%p," - "%u.\n", - csk, skb, skb->len, - cxgbi_skcb_flags(skb), - cxgbi_skcb_rx_pdulen(skb), - dskb, dskb->len); - __kfree_skb(dskb); - } else - err = skb_read_pdu_data(conn, skb, skb, 0); - } -skb_done: - __kfree_skb(skb); - - if (err < 0) - break; - } - - log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, read %u.\n", csk, read); - if (read) { - csk->copied_seq += read; - csk_return_rx_credits(csk, read); - conn->rxdata_octets += read; - } - - if (err < 0) { - pr_info("csk 0x%p, 0x%p, rx failed %d, read %u.\n", - csk, conn, err, read); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - } -} -EXPORT_SYMBOL_GPL(cxgbi_conn_pdu_ready); - -static int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt, - unsigned int offset, unsigned int *off, - struct scatterlist **sgp) -{ - int i; - struct scatterlist *sg; - - for_each_sg(sgl, sg, sgcnt, i) { - if (offset < sg->length) { - *off = offset; - *sgp = sg; - return 0; - } - offset -= sg->length; - } - return -EFAULT; -} - -static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset, - unsigned int dlen, struct page_frag *frags, - int frag_max) -{ - unsigned int datalen = dlen; - unsigned int sglen = sg->length - sgoffset; - struct page *page = sg_page(sg); - int i; - - i = 0; - do { - unsigned int copy; - - if (!sglen) { - sg = sg_next(sg); - if (!sg) { - pr_warn("sg %d NULL, len %u/%u.\n", - i, datalen, dlen); - return -EINVAL; - } - sgoffset = 0; - sglen = sg->length; - page = sg_page(sg); - - } - copy = min(datalen, sglen); - if (i && page == frags[i - 1].page && - sgoffset + sg->offset == - frags[i - 1].offset + frags[i - 1].size) { - frags[i - 1].size += copy; - } else { - if (i >= frag_max) { - pr_warn("too many pages %u, dlen %u.\n", - frag_max, dlen); - return -EINVAL; - } - - frags[i].page = page; - frags[i].offset = sg->offset + sgoffset; - frags[i].size = copy; - i++; - } - datalen -= copy; - sgoffset += copy; - sglen -= copy; - } while (datalen); - - return i; -} - -int cxgbi_conn_alloc_pdu(struct iscsi_task *task, u8 opcode) -{ - struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - struct cxgbi_device *cdev = cconn->chba->cdev; - struct iscsi_conn *conn = task->conn; - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); - struct scsi_cmnd *sc = task->sc; - int headroom = SKB_TX_ISCSI_PDU_HEADER_MAX; - - tcp_task->dd_data = tdata; - task->hdr = NULL; - - if (SKB_MAX_HEAD(cdev->skb_tx_rsvd) > (512 * MAX_SKB_FRAGS) && - (opcode == ISCSI_OP_SCSI_DATA_OUT || - (opcode == ISCSI_OP_SCSI_CMD && - (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_TO_DEVICE)))) - /* data could goes into skb head */ - headroom += min_t(unsigned int, - SKB_MAX_HEAD(cdev->skb_tx_rsvd), - conn->max_xmit_dlength); - - tdata->skb = alloc_skb(cdev->skb_tx_rsvd + headroom, GFP_ATOMIC); - if (!tdata->skb) { - struct cxgbi_sock *csk = cconn->cep->csk; - struct net_device *ndev = cdev->ports[csk->port_id]; - ndev->stats.tx_dropped++; - return -ENOMEM; - } - - skb_reserve(tdata->skb, cdev->skb_tx_rsvd); - task->hdr = (struct iscsi_hdr *)tdata->skb->data; - task->hdr_max = SKB_TX_ISCSI_PDU_HEADER_MAX; /* BHS + AHS */ - - /* data_out uses scsi_cmd's itt */ - if (opcode != ISCSI_OP_SCSI_DATA_OUT) - task_reserve_itt(task, &task->hdr->itt); - - log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, - "task 0x%p, op 0x%x, skb 0x%p,%u+%u/%u, itt 0x%x.\n", - task, opcode, tdata->skb, cdev->skb_tx_rsvd, headroom, - conn->max_xmit_dlength, ntohl(task->hdr->itt)); - - return 0; -} -EXPORT_SYMBOL_GPL(cxgbi_conn_alloc_pdu); - -static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc) -{ - if (hcrc || dcrc) { - u8 submode = 0; - - if (hcrc) - submode |= 1; - if (dcrc) - submode |= 2; - cxgbi_skcb_ulp_mode(skb) = (ULP2_MODE_ISCSI << 4) | submode; - } else - cxgbi_skcb_ulp_mode(skb) = 0; -} - -int cxgbi_conn_init_pdu(struct iscsi_task *task, unsigned int offset, - unsigned int count) -{ - struct iscsi_conn *conn = task->conn; - struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); - struct sk_buff *skb = tdata->skb; - unsigned int datalen = count; - int i, padlen = iscsi_padding(count); - struct page *pg; - - log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, - "task 0x%p,0x%p, skb 0x%p, 0x%x,0x%x,0x%x, %u+%u.\n", - task, task->sc, skb, (*skb->data) & ISCSI_OPCODE_MASK, - ntohl(task->cmdsn), ntohl(task->hdr->itt), offset, count); - - skb_put(skb, task->hdr_len); - tx_skb_setmode(skb, conn->hdrdgst_en, datalen ? conn->datadgst_en : 0); - if (!count) - return 0; - - if (task->sc) { - struct scsi_data_buffer *sdb = scsi_out(task->sc); - struct scatterlist *sg = NULL; - int err; - - tdata->offset = offset; - tdata->count = count; - err = sgl_seek_offset( - sdb->table.sgl, sdb->table.nents, - tdata->offset, &tdata->sgoffset, &sg); - if (err < 0) { - pr_warn("tpdu, sgl %u, bad offset %u/%u.\n", - sdb->table.nents, tdata->offset, sdb->length); - return err; - } - err = sgl_read_to_frags(sg, tdata->sgoffset, tdata->count, - tdata->frags, MAX_PDU_FRAGS); - if (err < 0) { - pr_warn("tpdu, sgl %u, bad offset %u + %u.\n", - sdb->table.nents, tdata->offset, tdata->count); - return err; - } - tdata->nr_frags = err; - - if (tdata->nr_frags > MAX_SKB_FRAGS || - (padlen && tdata->nr_frags == MAX_SKB_FRAGS)) { - char *dst = skb->data + task->hdr_len; - struct page_frag *frag = tdata->frags; - - /* data fits in the skb's headroom */ - for (i = 0; i < tdata->nr_frags; i++, frag++) { - char *src = kmap_atomic(frag->page); - - memcpy(dst, src+frag->offset, frag->size); - dst += frag->size; - kunmap_atomic(src); - } - if (padlen) { - memset(dst, 0, padlen); - padlen = 0; - } - skb_put(skb, count + padlen); - } else { - /* data fit into frag_list */ - for (i = 0; i < tdata->nr_frags; i++) { - __skb_fill_page_desc(skb, i, - tdata->frags[i].page, - tdata->frags[i].offset, - tdata->frags[i].size); - skb_frag_ref(skb, i); - } - skb_shinfo(skb)->nr_frags = tdata->nr_frags; - skb->len += count; - skb->data_len += count; - skb->truesize += count; - } - - } else { - pg = virt_to_page(task->data); - - get_page(pg); - skb_fill_page_desc(skb, 0, pg, offset_in_page(task->data), - count); - skb->len += count; - skb->data_len += count; - skb->truesize += count; - } - - if (padlen) { - i = skb_shinfo(skb)->nr_frags; - skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, - virt_to_page(padding), offset_in_page(padding), - padlen); - - skb->data_len += padlen; - skb->truesize += padlen; - skb->len += padlen; - } - - return 0; -} -EXPORT_SYMBOL_GPL(cxgbi_conn_init_pdu); - -int cxgbi_conn_xmit_pdu(struct iscsi_task *task) -{ - struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); - struct sk_buff *skb = tdata->skb; - unsigned int datalen; - int err; - - if (!skb) { - log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, - "task 0x%p, skb NULL.\n", task); - return 0; - } - - datalen = skb->data_len; - tdata->skb = NULL; - err = cxgbi_sock_send_pdus(cconn->cep->csk, skb); - if (err > 0) { - int pdulen = err; - - log_debug(1 << CXGBI_DBG_PDU_TX, - "task 0x%p,0x%p, skb 0x%p, len %u/%u, rv %d.\n", - task, task->sc, skb, skb->len, skb->data_len, err); - - if (task->conn->hdrdgst_en) - pdulen += ISCSI_DIGEST_SIZE; - - if (datalen && task->conn->datadgst_en) - pdulen += ISCSI_DIGEST_SIZE; - - task->conn->txdata_octets += pdulen; - return 0; - } - - if (err == -EAGAIN || err == -ENOBUFS) { - log_debug(1 << CXGBI_DBG_PDU_TX, - "task 0x%p, skb 0x%p, len %u/%u, %d EAGAIN.\n", - task, skb, skb->len, skb->data_len, err); - /* reset skb to send when we are called again */ - tdata->skb = skb; - return err; - } - - kfree_skb(skb); - log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_PDU_TX, - "itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n", - task->itt, skb, skb->len, skb->data_len, err); - iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err); - iscsi_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED); - return err; -} -EXPORT_SYMBOL_GPL(cxgbi_conn_xmit_pdu); - -void cxgbi_cleanup_task(struct iscsi_task *task) -{ - struct cxgbi_task_data *tdata = iscsi_task_cxgbi_data(task); - - log_debug(1 << CXGBI_DBG_ISCSI, - "task 0x%p, skb 0x%p, itt 0x%x.\n", - task, tdata->skb, task->hdr_itt); - - /* never reached the xmit task callout */ - if (tdata->skb) - __kfree_skb(tdata->skb); - memset(tdata, 0, sizeof(*tdata)); - - task_release_itt(task, task->hdr_itt); - iscsi_tcp_cleanup_task(task); -} -EXPORT_SYMBOL_GPL(cxgbi_cleanup_task); - -void cxgbi_get_conn_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - - stats->txdata_octets = conn->txdata_octets; - stats->rxdata_octets = conn->rxdata_octets; - stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; - stats->dataout_pdus = conn->dataout_pdus_cnt; - stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; - stats->datain_pdus = conn->datain_pdus_cnt; - stats->r2t_pdus = conn->r2t_pdus_cnt; - stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; - stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->digest_err = 0; - stats->timeout_err = 0; - stats->custom_length = 1; - strcpy(stats->custom[0].desc, "eh_abort_cnt"); - stats->custom[0].value = conn->eh_abort_cnt; -} -EXPORT_SYMBOL_GPL(cxgbi_get_conn_stats); - -static int cxgbi_conn_max_xmit_dlength(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - struct cxgbi_device *cdev = cconn->chba->cdev; - unsigned int headroom = SKB_MAX_HEAD(cdev->skb_tx_rsvd); - unsigned int max_def = 512 * MAX_SKB_FRAGS; - unsigned int max = max(max_def, headroom); - - max = min(cconn->chba->cdev->tx_max_size, max); - if (conn->max_xmit_dlength) - conn->max_xmit_dlength = min(conn->max_xmit_dlength, max); - else - conn->max_xmit_dlength = max; - cxgbi_align_pdu_size(conn->max_xmit_dlength); - - return 0; -} - -static int cxgbi_conn_max_recv_dlength(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - unsigned int max = cconn->chba->cdev->rx_max_size; - - cxgbi_align_pdu_size(max); - - if (conn->max_recv_dlength) { - if (conn->max_recv_dlength > max) { - pr_err("MaxRecvDataSegmentLength %u > %u.\n", - conn->max_recv_dlength, max); - return -EINVAL; - } - conn->max_recv_dlength = min(conn->max_recv_dlength, max); - cxgbi_align_pdu_size(conn->max_recv_dlength); - } else - conn->max_recv_dlength = max; - - return 0; -} - -int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf, int buflen) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - struct cxgbi_sock *csk = cconn->cep->csk; - int err; - - log_debug(1 << CXGBI_DBG_ISCSI, - "cls_conn 0x%p, param %d, buf(%d) %s.\n", - cls_conn, param, buflen, buf); - - switch (param) { - case ISCSI_PARAM_HDRDGST_EN: - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err && conn->hdrdgst_en) - err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, - conn->hdrdgst_en, - conn->datadgst_en, 0); - break; - case ISCSI_PARAM_DATADGST_EN: - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err && conn->datadgst_en) - err = csk->cdev->csk_ddp_setup_digest(csk, csk->tid, - conn->hdrdgst_en, - conn->datadgst_en, 0); - break; - case ISCSI_PARAM_MAX_R2T: - return iscsi_tcp_set_max_r2t(conn, buf); - case ISCSI_PARAM_MAX_RECV_DLENGTH: - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err) - err = cxgbi_conn_max_recv_dlength(conn); - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - err = iscsi_set_param(cls_conn, param, buf, buflen); - if (!err) - err = cxgbi_conn_max_xmit_dlength(conn); - break; - default: - return iscsi_set_param(cls_conn, param, buf, buflen); - } - return err; -} -EXPORT_SYMBOL_GPL(cxgbi_set_conn_param); - -int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, - char *buf) -{ - struct cxgbi_endpoint *cep = ep->dd_data; - struct cxgbi_sock *csk; - int len; - - log_debug(1 << CXGBI_DBG_ISCSI, - "cls_conn 0x%p, param %d.\n", ep, param); - - switch (param) { - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_CONN_ADDRESS: - if (!cep) - return -ENOTCONN; - - csk = cep->csk; - if (!csk) - return -ENOTCONN; - - return iscsi_conn_get_addr_param((struct sockaddr_storage *) - &csk->daddr, param, buf); - default: - return -ENOSYS; - } - return len; -} -EXPORT_SYMBOL_GPL(cxgbi_get_ep_param); - -struct iscsi_cls_conn * -cxgbi_create_conn(struct iscsi_cls_session *cls_session, u32 cid) -{ - struct iscsi_cls_conn *cls_conn; - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; - struct cxgbi_conn *cconn; - - cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*cconn), cid); - if (!cls_conn) - return NULL; - - conn = cls_conn->dd_data; - tcp_conn = conn->dd_data; - cconn = tcp_conn->dd_data; - cconn->iconn = conn; - - log_debug(1 << CXGBI_DBG_ISCSI, - "cid %u(0x%x), cls 0x%p,0x%p, conn 0x%p,0x%p,0x%p.\n", - cid, cid, cls_session, cls_conn, conn, tcp_conn, cconn); - - return cls_conn; -} -EXPORT_SYMBOL_GPL(cxgbi_create_conn); - -int cxgbi_bind_conn(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, - u64 transport_eph, int is_leading) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct cxgbi_conn *cconn = tcp_conn->dd_data; - struct iscsi_endpoint *ep; - struct cxgbi_endpoint *cep; - struct cxgbi_sock *csk; - int err; - - ep = iscsi_lookup_endpoint(transport_eph); - if (!ep) - return -EINVAL; - - /* setup ddp pagesize */ - cep = ep->dd_data; - csk = cep->csk; - err = csk->cdev->csk_ddp_setup_pgidx(csk, csk->tid, page_idx, 0); - if (err < 0) - return err; - - err = iscsi_conn_bind(cls_session, cls_conn, is_leading); - if (err) - return -EINVAL; - - /* calculate the tag idx bits needed for this conn based on cmds_max */ - cconn->task_idx_bits = (__ilog2_u32(conn->session->cmds_max - 1)) + 1; - - write_lock_bh(&csk->callback_lock); - csk->user_data = conn; - cconn->chba = cep->chba; - cconn->cep = cep; - cep->cconn = cconn; - write_unlock_bh(&csk->callback_lock); - - cxgbi_conn_max_xmit_dlength(conn); - cxgbi_conn_max_recv_dlength(conn); - - log_debug(1 << CXGBI_DBG_ISCSI, - "cls 0x%p,0x%p, ep 0x%p, cconn 0x%p, csk 0x%p.\n", - cls_session, cls_conn, ep, cconn, csk); - /* init recv engine */ - iscsi_tcp_hdr_recv_prep(tcp_conn); - - return 0; -} -EXPORT_SYMBOL_GPL(cxgbi_bind_conn); - -struct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *ep, - u16 cmds_max, u16 qdepth, - u32 initial_cmdsn) -{ - struct cxgbi_endpoint *cep; - struct cxgbi_hba *chba; - struct Scsi_Host *shost; - struct iscsi_cls_session *cls_session; - struct iscsi_session *session; - - if (!ep) { - pr_err("missing endpoint.\n"); - return NULL; - } - - cep = ep->dd_data; - chba = cep->chba; - shost = chba->shost; - - BUG_ON(chba != iscsi_host_priv(shost)); - - cls_session = iscsi_session_setup(chba->cdev->itp, shost, - cmds_max, 0, - sizeof(struct iscsi_tcp_task) + - sizeof(struct cxgbi_task_data), - initial_cmdsn, ISCSI_MAX_TARGET); - if (!cls_session) - return NULL; - - session = cls_session->dd_data; - if (iscsi_tcp_r2tpool_alloc(session)) - goto remove_session; - - log_debug(1 << CXGBI_DBG_ISCSI, - "ep 0x%p, cls sess 0x%p.\n", ep, cls_session); - return cls_session; - -remove_session: - iscsi_session_teardown(cls_session); - return NULL; -} -EXPORT_SYMBOL_GPL(cxgbi_create_session); - -void cxgbi_destroy_session(struct iscsi_cls_session *cls_session) -{ - log_debug(1 << CXGBI_DBG_ISCSI, - "cls sess 0x%p.\n", cls_session); - - iscsi_tcp_r2tpool_free(cls_session->dd_data); - iscsi_session_teardown(cls_session); -} -EXPORT_SYMBOL_GPL(cxgbi_destroy_session); - -int cxgbi_set_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, - char *buf, int buflen) -{ - struct cxgbi_hba *chba = iscsi_host_priv(shost); - - if (!chba->ndev) { - shost_printk(KERN_ERR, shost, "Could not get host param. " - "netdev for host not set.\n"); - return -ENODEV; - } - - log_debug(1 << CXGBI_DBG_ISCSI, - "shost 0x%p, hba 0x%p,%s, param %d, buf(%d) %s.\n", - shost, chba, chba->ndev->name, param, buflen, buf); - - switch (param) { - case ISCSI_HOST_PARAM_IPADDRESS: - { - __be32 addr = in_aton(buf); - log_debug(1 << CXGBI_DBG_ISCSI, - "hba %s, req. ipv4 %pI4.\n", chba->ndev->name, &addr); - cxgbi_set_iscsi_ipv4(chba, addr); - return 0; - } - case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_NETDEV_NAME: - return 0; - default: - return iscsi_host_set_param(shost, param, buf, buflen); - } -} -EXPORT_SYMBOL_GPL(cxgbi_set_host_param); - -int cxgbi_get_host_param(struct Scsi_Host *shost, enum iscsi_host_param param, - char *buf) -{ - struct cxgbi_hba *chba = iscsi_host_priv(shost); - int len = 0; - - if (!chba->ndev) { - shost_printk(KERN_ERR, shost, "Could not get host param. " - "netdev for host not set.\n"); - return -ENODEV; - } - - log_debug(1 << CXGBI_DBG_ISCSI, - "shost 0x%p, hba 0x%p,%s, param %d.\n", - shost, chba, chba->ndev->name, param); - - switch (param) { - case ISCSI_HOST_PARAM_HWADDRESS: - len = sysfs_format_mac(buf, chba->ndev->dev_addr, 6); - break; - case ISCSI_HOST_PARAM_NETDEV_NAME: - len = sprintf(buf, "%s\n", chba->ndev->name); - break; - case ISCSI_HOST_PARAM_IPADDRESS: - { - __be32 addr; - - addr = cxgbi_get_iscsi_ipv4(chba); - len = sprintf(buf, "%pI4", &addr); - log_debug(1 << CXGBI_DBG_ISCSI, - "hba %s, ipv4 %pI4.\n", chba->ndev->name, &addr); - break; - } - default: - return iscsi_host_get_param(shost, param, buf); - } - - return len; -} -EXPORT_SYMBOL_GPL(cxgbi_get_host_param); - -struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *shost, - struct sockaddr *dst_addr, - int non_blocking) -{ - struct iscsi_endpoint *ep; - struct cxgbi_endpoint *cep; - struct cxgbi_hba *hba = NULL; - struct cxgbi_sock *csk; - int err = -EINVAL; - - log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, - "shost 0x%p, non_blocking %d, dst_addr 0x%p.\n", - shost, non_blocking, dst_addr); - - if (shost) { - hba = iscsi_host_priv(shost); - if (!hba) { - pr_info("shost 0x%p, priv NULL.\n", shost); - goto err_out; - } - } - - csk = cxgbi_check_route(dst_addr); - if (IS_ERR(csk)) - return (struct iscsi_endpoint *)csk; - cxgbi_sock_get(csk); - - if (!hba) - hba = csk->cdev->hbas[csk->port_id]; - else if (hba != csk->cdev->hbas[csk->port_id]) { - pr_info("Could not connect through requested host %u" - "hba 0x%p != 0x%p (%u).\n", - shost->host_no, hba, - csk->cdev->hbas[csk->port_id], csk->port_id); - err = -ENOSPC; - goto release_conn; - } - - err = sock_get_port(csk); - if (err) - goto release_conn; - - cxgbi_sock_set_state(csk, CTP_CONNECTING); - err = csk->cdev->csk_init_act_open(csk); - if (err) - goto release_conn; - - if (cxgbi_sock_is_closing(csk)) { - err = -ENOSPC; - pr_info("csk 0x%p is closing.\n", csk); - goto release_conn; - } - - ep = iscsi_create_endpoint(sizeof(*cep)); - if (!ep) { - err = -ENOMEM; - pr_info("iscsi alloc ep, OOM.\n"); - goto release_conn; - } - - cep = ep->dd_data; - cep->csk = csk; - cep->chba = hba; - - log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, - "ep 0x%p, cep 0x%p, csk 0x%p, hba 0x%p,%s.\n", - ep, cep, csk, hba, hba->ndev->name); - return ep; - -release_conn: - cxgbi_sock_put(csk); - cxgbi_sock_closed(csk); -err_out: - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(cxgbi_ep_connect); - -int cxgbi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) -{ - struct cxgbi_endpoint *cep = ep->dd_data; - struct cxgbi_sock *csk = cep->csk; - - if (!cxgbi_sock_is_established(csk)) - return 0; - return 1; -} -EXPORT_SYMBOL_GPL(cxgbi_ep_poll); - -void cxgbi_ep_disconnect(struct iscsi_endpoint *ep) -{ - struct cxgbi_endpoint *cep = ep->dd_data; - struct cxgbi_conn *cconn = cep->cconn; - struct cxgbi_sock *csk = cep->csk; - - log_debug(1 << CXGBI_DBG_ISCSI | 1 << CXGBI_DBG_SOCK, - "ep 0x%p, cep 0x%p, cconn 0x%p, csk 0x%p,%u,0x%lx.\n", - ep, cep, cconn, csk, csk->state, csk->flags); - - if (cconn && cconn->iconn) { - iscsi_suspend_tx(cconn->iconn); - write_lock_bh(&csk->callback_lock); - cep->csk->user_data = NULL; - cconn->cep = NULL; - write_unlock_bh(&csk->callback_lock); - } - iscsi_destroy_endpoint(ep); - - if (likely(csk->state >= CTP_ESTABLISHED)) - need_active_close(csk); - else - cxgbi_sock_closed(csk); - - cxgbi_sock_put(csk); -} -EXPORT_SYMBOL_GPL(cxgbi_ep_disconnect); - -int cxgbi_iscsi_init(struct iscsi_transport *itp, - struct scsi_transport_template **stt) -{ - *stt = iscsi_register_transport(itp); - if (*stt == NULL) { - pr_err("unable to register %s transport 0x%p.\n", - itp->name, itp); - return -ENODEV; - } - log_debug(1 << CXGBI_DBG_ISCSI, - "%s, registered iscsi transport 0x%p.\n", - itp->name, stt); - return 0; -} -EXPORT_SYMBOL_GPL(cxgbi_iscsi_init); - -void cxgbi_iscsi_cleanup(struct iscsi_transport *itp, - struct scsi_transport_template **stt) -{ - if (*stt) { - log_debug(1 << CXGBI_DBG_ISCSI, - "de-register transport 0x%p, %s, stt 0x%p.\n", - itp, itp->name, *stt); - *stt = NULL; - iscsi_unregister_transport(itp); - } -} -EXPORT_SYMBOL_GPL(cxgbi_iscsi_cleanup); - -umode_t cxgbi_attr_is_visible(int param_type, int param) -{ - switch (param_type) { - case ISCSI_HOST_PARAM: - switch (param) { - case ISCSI_HOST_PARAM_NETDEV_NAME: - case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_IPADDRESS: - case ISCSI_HOST_PARAM_INITIATOR_NAME: - return S_IRUGO; - default: - return 0; - } - case ISCSI_PARAM: - switch (param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - case ISCSI_PARAM_HDRDGST_EN: - case ISCSI_PARAM_DATADGST_EN: - case ISCSI_PARAM_CONN_ADDRESS: - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_EXP_STATSN: - case ISCSI_PARAM_PERSISTENT_ADDRESS: - case ISCSI_PARAM_PERSISTENT_PORT: - case ISCSI_PARAM_PING_TMO: - case ISCSI_PARAM_RECV_TMO: - case ISCSI_PARAM_INITIAL_R2T_EN: - case ISCSI_PARAM_MAX_R2T: - case ISCSI_PARAM_IMM_DATA_EN: - case ISCSI_PARAM_FIRST_BURST: - case ISCSI_PARAM_MAX_BURST: - case ISCSI_PARAM_PDU_INORDER_EN: - case ISCSI_PARAM_DATASEQ_INORDER_EN: - case ISCSI_PARAM_ERL: - case ISCSI_PARAM_TARGET_NAME: - case ISCSI_PARAM_TPGT: - case ISCSI_PARAM_USERNAME: - case ISCSI_PARAM_PASSWORD: - case ISCSI_PARAM_USERNAME_IN: - case ISCSI_PARAM_PASSWORD_IN: - case ISCSI_PARAM_FAST_ABORT: - case ISCSI_PARAM_ABORT_TMO: - case ISCSI_PARAM_LU_RESET_TMO: - case ISCSI_PARAM_TGT_RESET_TMO: - case ISCSI_PARAM_IFACE_NAME: - case ISCSI_PARAM_INITIATOR_NAME: - return S_IRUGO; - default: - return 0; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(cxgbi_attr_is_visible); - -static int __init libcxgbi_init_module(void) -{ - sw_tag_idx_bits = (__ilog2_u32(ISCSI_ITT_MASK)) + 1; - sw_tag_age_bits = (__ilog2_u32(ISCSI_AGE_MASK)) + 1; - - pr_info("tag itt 0x%x, %u bits, age 0x%x, %u bits.\n", - ISCSI_ITT_MASK, sw_tag_idx_bits, - ISCSI_AGE_MASK, sw_tag_age_bits); - - ddp_setup_host_page_size(); - return 0; -} - -static void __exit libcxgbi_exit_module(void) -{ - cxgbi_device_unregister_all(0xFF); - return; -} - -module_init(libcxgbi_init_module); -module_exit(libcxgbi_exit_module); diff --git a/ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.h b/ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.h deleted file mode 100644 index 80fa99b3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/cxgbi/libcxgbi.h +++ /dev/null @@ -1,743 +0,0 @@ -/* - * libcxgbi.h: Chelsio common library for T3/T4 iSCSI driver. - * - * Copyright (c) 2010 Chelsio Communications, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation. - * - * Written by: Karen Xie (kxie@chelsio.com) - * Written by: Rakesh Ranjan (rranjan@chelsio.com) - */ - -#ifndef __LIBCXGBI_H__ -#define __LIBCXGBI_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum cxgbi_dbg_flag { - CXGBI_DBG_ISCSI, - CXGBI_DBG_DDP, - CXGBI_DBG_TOE, - CXGBI_DBG_SOCK, - - CXGBI_DBG_PDU_TX, - CXGBI_DBG_PDU_RX, - CXGBI_DBG_DEV, -}; - -#define log_debug(level, fmt, ...) \ - do { \ - if (dbg_level & (level)) \ - pr_info(fmt, ##__VA_ARGS__); \ - } while (0) - -/* max. connections per adapter */ -#define CXGBI_MAX_CONN 16384 - -/* always allocate rooms for AHS */ -#define SKB_TX_ISCSI_PDU_HEADER_MAX \ - (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE) - -#define ISCSI_PDU_NONPAYLOAD_LEN 312 /* bhs(48) + ahs(256) + digest(8)*/ - -/* - * align pdu size to multiple of 512 for better performance - */ -#define cxgbi_align_pdu_size(n) do { n = (n) & (~511); } while (0) - -#define ULP2_MODE_ISCSI 2 - -#define ULP2_MAX_PKT_SIZE 16224 -#define ULP2_MAX_PDU_PAYLOAD \ - (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN) - -/* - * For iscsi connections HW may inserts digest bytes into the pdu. Those digest - * bytes are not sent by the host but are part of the TCP payload and therefore - * consume TCP sequence space. - */ -static const unsigned int ulp2_extra_len[] = { 0, 4, 4, 8 }; -static inline unsigned int cxgbi_ulp_extra_len(int submode) -{ - return ulp2_extra_len[submode & 3]; -} - -/* - * struct pagepod_hdr, pagepod - pagepod format - */ - -#define CPL_RX_DDP_STATUS_DDP_SHIFT 16 /* ddp'able */ -#define CPL_RX_DDP_STATUS_PAD_SHIFT 19 /* pad error */ -#define CPL_RX_DDP_STATUS_HCRC_SHIFT 20 /* hcrc error */ -#define CPL_RX_DDP_STATUS_DCRC_SHIFT 21 /* dcrc error */ - -struct cxgbi_pagepod_hdr { - u32 vld_tid; - u32 pgsz_tag_clr; - u32 max_offset; - u32 page_offset; - u64 rsvd; -}; - -#define PPOD_PAGES_MAX 4 -struct cxgbi_pagepod { - struct cxgbi_pagepod_hdr hdr; - u64 addr[PPOD_PAGES_MAX + 1]; -}; - -struct cxgbi_tag_format { - unsigned char sw_bits; - unsigned char rsvd_bits; - unsigned char rsvd_shift; - unsigned char filler[1]; - u32 rsvd_mask; -}; - -struct cxgbi_gather_list { - unsigned int tag; - unsigned int length; - unsigned int offset; - unsigned int nelem; - struct page **pages; - dma_addr_t phys_addr[0]; -}; - -struct cxgbi_ddp_info { - struct kref refcnt; - struct cxgbi_device *cdev; - struct pci_dev *pdev; - unsigned int max_txsz; - unsigned int max_rxsz; - unsigned int llimit; - unsigned int ulimit; - unsigned int nppods; - unsigned int idx_last; - unsigned char idx_bits; - unsigned char filler[3]; - unsigned int idx_mask; - unsigned int rsvd_tag_mask; - spinlock_t map_lock; - struct cxgbi_gather_list **gl_map; -}; - -#define DDP_PGIDX_MAX 4 -#define DDP_THRESHOLD 2048 - -#define PPOD_PAGES_SHIFT 2 /* 4 pages per pod */ - -#define PPOD_SIZE sizeof(struct cxgbi_pagepod) /* 64 */ -#define PPOD_SIZE_SHIFT 6 - -#define ULPMEM_DSGL_MAX_NPPODS 16 /* 1024/PPOD_SIZE */ -#define ULPMEM_IDATA_MAX_NPPODS 4 /* 256/PPOD_SIZE */ -#define PCIE_MEMWIN_MAX_NPPODS 16 /* 1024/PPOD_SIZE */ - -#define PPOD_COLOR_SHIFT 0 -#define PPOD_COLOR(x) ((x) << PPOD_COLOR_SHIFT) - -#define PPOD_IDX_SHIFT 6 -#define PPOD_IDX_MAX_SIZE 24 - -#define PPOD_TID_SHIFT 0 -#define PPOD_TID(x) ((x) << PPOD_TID_SHIFT) - -#define PPOD_TAG_SHIFT 6 -#define PPOD_TAG(x) ((x) << PPOD_TAG_SHIFT) - -#define PPOD_VALID_SHIFT 24 -#define PPOD_VALID(x) ((x) << PPOD_VALID_SHIFT) -#define PPOD_VALID_FLAG PPOD_VALID(1U) - -/* - * sge_opaque_hdr - - * Opaque version of structure the SGE stores at skb->head of TX_DATA packets - * and for which we must reserve space. - */ -struct sge_opaque_hdr { - void *dev; - dma_addr_t addr[MAX_SKB_FRAGS + 1]; -}; - -struct cxgbi_sock { - struct cxgbi_device *cdev; - - int tid; - int atid; - unsigned long flags; - unsigned int mtu; - unsigned short rss_qid; - unsigned short txq_idx; - unsigned short advmss; - unsigned int tx_chan; - unsigned int rx_chan; - unsigned int mss_idx; - unsigned int smac_idx; - unsigned char port_id; - int wr_max_cred; - int wr_cred; - int wr_una_cred; - unsigned char hcrc_len; - unsigned char dcrc_len; - - void *l2t; - struct sk_buff *wr_pending_head; - struct sk_buff *wr_pending_tail; - struct sk_buff *cpl_close; - struct sk_buff *cpl_abort_req; - struct sk_buff *cpl_abort_rpl; - struct sk_buff *skb_ulp_lhdr; - spinlock_t lock; - struct kref refcnt; - unsigned int state; - struct sockaddr_in saddr; - struct sockaddr_in daddr; - struct dst_entry *dst; - struct sk_buff_head receive_queue; - struct sk_buff_head write_queue; - struct timer_list retry_timer; - int err; - rwlock_t callback_lock; - void *user_data; - - u32 rcv_nxt; - u32 copied_seq; - u32 rcv_wup; - u32 snd_nxt; - u32 snd_una; - u32 write_seq; -}; - -/* - * connection states - */ -enum cxgbi_sock_states{ - CTP_CLOSED, - CTP_CONNECTING, - CTP_ACTIVE_OPEN, - CTP_ESTABLISHED, - CTP_ACTIVE_CLOSE, - CTP_PASSIVE_CLOSE, - CTP_CLOSE_WAIT_1, - CTP_CLOSE_WAIT_2, - CTP_ABORTING, -}; - -/* - * Connection flags -- many to track some close related events. - */ -enum cxgbi_sock_flags { - CTPF_ABORT_RPL_RCVD, /*received one ABORT_RPL_RSS message */ - CTPF_ABORT_REQ_RCVD, /*received one ABORT_REQ_RSS message */ - CTPF_ABORT_RPL_PENDING, /* expecting an abort reply */ - CTPF_TX_DATA_SENT, /* already sent a TX_DATA WR */ - CTPF_ACTIVE_CLOSE_NEEDED,/* need to be closed */ - CTPF_HAS_ATID, /* reserved atid */ - CTPF_HAS_TID, /* reserved hw tid */ - CTPF_OFFLOAD_DOWN, /* offload function off */ -}; - -struct cxgbi_skb_rx_cb { - __u32 ddigest; - __u32 pdulen; -}; - -struct cxgbi_skb_tx_cb { - void *l2t; - struct sk_buff *wr_next; -}; - -enum cxgbi_skcb_flags { - SKCBF_TX_NEED_HDR, /* packet needs a header */ - SKCBF_RX_COALESCED, /* received whole pdu */ - SKCBF_RX_HDR, /* received pdu header */ - SKCBF_RX_DATA, /* received pdu payload */ - SKCBF_RX_STATUS, /* received ddp status */ - SKCBF_RX_DATA_DDPD, /* pdu payload ddp'd */ - SKCBF_RX_HCRC_ERR, /* header digest error */ - SKCBF_RX_DCRC_ERR, /* data digest error */ - SKCBF_RX_PAD_ERR, /* padding byte error */ -}; - -struct cxgbi_skb_cb { - unsigned char ulp_mode; - unsigned long flags; - unsigned int seq; - union { - struct cxgbi_skb_rx_cb rx; - struct cxgbi_skb_tx_cb tx; - }; -}; - -#define CXGBI_SKB_CB(skb) ((struct cxgbi_skb_cb *)&((skb)->cb[0])) -#define cxgbi_skcb_flags(skb) (CXGBI_SKB_CB(skb)->flags) -#define cxgbi_skcb_ulp_mode(skb) (CXGBI_SKB_CB(skb)->ulp_mode) -#define cxgbi_skcb_tcp_seq(skb) (CXGBI_SKB_CB(skb)->seq) -#define cxgbi_skcb_rx_ddigest(skb) (CXGBI_SKB_CB(skb)->rx.ddigest) -#define cxgbi_skcb_rx_pdulen(skb) (CXGBI_SKB_CB(skb)->rx.pdulen) -#define cxgbi_skcb_tx_wr_next(skb) (CXGBI_SKB_CB(skb)->tx.wr_next) - -static inline void cxgbi_skcb_set_flag(struct sk_buff *skb, - enum cxgbi_skcb_flags flag) -{ - __set_bit(flag, &(cxgbi_skcb_flags(skb))); -} - -static inline void cxgbi_skcb_clear_flag(struct sk_buff *skb, - enum cxgbi_skcb_flags flag) -{ - __clear_bit(flag, &(cxgbi_skcb_flags(skb))); -} - -static inline int cxgbi_skcb_test_flag(struct sk_buff *skb, - enum cxgbi_skcb_flags flag) -{ - return test_bit(flag, &(cxgbi_skcb_flags(skb))); -} - -static inline void cxgbi_sock_set_flag(struct cxgbi_sock *csk, - enum cxgbi_sock_flags flag) -{ - __set_bit(flag, &csk->flags); - log_debug(1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, bit %d.\n", - csk, csk->state, csk->flags, flag); -} - -static inline void cxgbi_sock_clear_flag(struct cxgbi_sock *csk, - enum cxgbi_sock_flags flag) -{ - __clear_bit(flag, &csk->flags); - log_debug(1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, bit %d.\n", - csk, csk->state, csk->flags, flag); -} - -static inline int cxgbi_sock_flag(struct cxgbi_sock *csk, - enum cxgbi_sock_flags flag) -{ - if (csk == NULL) - return 0; - return test_bit(flag, &csk->flags); -} - -static inline void cxgbi_sock_set_state(struct cxgbi_sock *csk, int state) -{ - log_debug(1 << CXGBI_DBG_SOCK, - "csk 0x%p,%u,0x%lx, state -> %u.\n", - csk, csk->state, csk->flags, state); - csk->state = state; -} - -static inline void cxgbi_sock_free(struct kref *kref) -{ - struct cxgbi_sock *csk = container_of(kref, - struct cxgbi_sock, - refcnt); - if (csk) { - log_debug(1 << CXGBI_DBG_SOCK, - "free csk 0x%p, state %u, flags 0x%lx\n", - csk, csk->state, csk->flags); - kfree(csk); - } -} - -static inline void __cxgbi_sock_put(const char *fn, struct cxgbi_sock *csk) -{ - log_debug(1 << CXGBI_DBG_SOCK, - "%s, put csk 0x%p, ref %u-1.\n", - fn, csk, atomic_read(&csk->refcnt.refcount)); - kref_put(&csk->refcnt, cxgbi_sock_free); -} -#define cxgbi_sock_put(csk) __cxgbi_sock_put(__func__, csk) - -static inline void __cxgbi_sock_get(const char *fn, struct cxgbi_sock *csk) -{ - log_debug(1 << CXGBI_DBG_SOCK, - "%s, get csk 0x%p, ref %u+1.\n", - fn, csk, atomic_read(&csk->refcnt.refcount)); - kref_get(&csk->refcnt); -} -#define cxgbi_sock_get(csk) __cxgbi_sock_get(__func__, csk) - -static inline int cxgbi_sock_is_closing(struct cxgbi_sock *csk) -{ - return csk->state >= CTP_ACTIVE_CLOSE; -} - -static inline int cxgbi_sock_is_established(struct cxgbi_sock *csk) -{ - return csk->state == CTP_ESTABLISHED; -} - -static inline void cxgbi_sock_purge_write_queue(struct cxgbi_sock *csk) -{ - struct sk_buff *skb; - - while ((skb = __skb_dequeue(&csk->write_queue))) - __kfree_skb(skb); -} - -static inline unsigned int cxgbi_sock_compute_wscale(unsigned int win) -{ - unsigned int wscale = 0; - - while (wscale < 14 && (65535 << wscale) < win) - wscale++; - return wscale; -} - -static inline struct sk_buff *alloc_wr(int wrlen, int dlen, gfp_t gfp) -{ - struct sk_buff *skb = alloc_skb(wrlen + dlen, gfp); - - if (skb) { - __skb_put(skb, wrlen); - memset(skb->head, 0, wrlen + dlen); - } else - pr_info("alloc cpl wr skb %u+%u, OOM.\n", wrlen, dlen); - return skb; -} - - -/* - * The number of WRs needed for an skb depends on the number of fragments - * in the skb and whether it has any payload in its main body. This maps the - * length of the gather list represented by an skb into the # of necessary WRs. - * The extra two fragments are for iscsi bhs and payload padding. - */ -#define SKB_WR_LIST_SIZE (MAX_SKB_FRAGS + 2) - -static inline void cxgbi_sock_reset_wr_list(struct cxgbi_sock *csk) -{ - csk->wr_pending_head = csk->wr_pending_tail = NULL; -} - -static inline void cxgbi_sock_enqueue_wr(struct cxgbi_sock *csk, - struct sk_buff *skb) -{ - cxgbi_skcb_tx_wr_next(skb) = NULL; - /* - * We want to take an extra reference since both us and the driver - * need to free the packet before it's really freed. We know there's - * just one user currently so we use atomic_set rather than skb_get - * to avoid the atomic op. - */ - atomic_set(&skb->users, 2); - - if (!csk->wr_pending_head) - csk->wr_pending_head = skb; - else - cxgbi_skcb_tx_wr_next(csk->wr_pending_tail) = skb; - csk->wr_pending_tail = skb; -} - -static inline int cxgbi_sock_count_pending_wrs(const struct cxgbi_sock *csk) -{ - int n = 0; - const struct sk_buff *skb = csk->wr_pending_head; - - while (skb) { - n += skb->csum; - skb = cxgbi_skcb_tx_wr_next(skb); - } - return n; -} - -static inline struct sk_buff *cxgbi_sock_peek_wr(const struct cxgbi_sock *csk) -{ - return csk->wr_pending_head; -} - -static inline struct sk_buff *cxgbi_sock_dequeue_wr(struct cxgbi_sock *csk) -{ - struct sk_buff *skb = csk->wr_pending_head; - - if (likely(skb)) { - csk->wr_pending_head = cxgbi_skcb_tx_wr_next(skb); - cxgbi_skcb_tx_wr_next(skb) = NULL; - } - return skb; -} - -void cxgbi_sock_check_wr_invariants(const struct cxgbi_sock *); -void cxgbi_sock_purge_wr_queue(struct cxgbi_sock *); -void cxgbi_sock_skb_entail(struct cxgbi_sock *, struct sk_buff *); -void cxgbi_sock_fail_act_open(struct cxgbi_sock *, int); -void cxgbi_sock_act_open_req_arp_failure(void *, struct sk_buff *); -void cxgbi_sock_closed(struct cxgbi_sock *); -void cxgbi_sock_established(struct cxgbi_sock *, unsigned int, unsigned int); -void cxgbi_sock_rcv_abort_rpl(struct cxgbi_sock *); -void cxgbi_sock_rcv_peer_close(struct cxgbi_sock *); -void cxgbi_sock_rcv_close_conn_rpl(struct cxgbi_sock *, u32); -void cxgbi_sock_rcv_wr_ack(struct cxgbi_sock *, unsigned int, unsigned int, - int); -unsigned int cxgbi_sock_select_mss(struct cxgbi_sock *, unsigned int); -void cxgbi_sock_free_cpl_skbs(struct cxgbi_sock *); - -struct cxgbi_hba { - struct net_device *ndev; - struct net_device *vdev; /* vlan dev */ - struct Scsi_Host *shost; - struct cxgbi_device *cdev; - __be32 ipv4addr; - unsigned char port_id; -}; - -struct cxgbi_ports_map { - unsigned int max_connect; - unsigned int used; - unsigned short sport_base; - spinlock_t lock; - unsigned int next; - struct cxgbi_sock **port_csk; -}; - -#define CXGBI_FLAG_DEV_T3 0x1 -#define CXGBI_FLAG_DEV_T4 0x2 -#define CXGBI_FLAG_ADAPTER_RESET 0x4 -#define CXGBI_FLAG_IPV4_SET 0x10 -struct cxgbi_device { - struct list_head list_head; - unsigned int flags; - struct net_device **ports; - void *lldev; - struct cxgbi_hba **hbas; - const unsigned short *mtus; - unsigned char nmtus; - unsigned char nports; - struct pci_dev *pdev; - struct dentry *debugfs_root; - struct iscsi_transport *itp; - - unsigned int pfvf; - unsigned int snd_win; - unsigned int rcv_win; - unsigned int rx_credit_thres; - unsigned int skb_tx_rsvd; - unsigned int skb_rx_extra; /* for msg coalesced mode */ - unsigned int tx_max_size; - unsigned int rx_max_size; - struct cxgbi_ports_map pmap; - struct cxgbi_tag_format tag_format; - struct cxgbi_ddp_info *ddp; - - void (*dev_ddp_cleanup)(struct cxgbi_device *); - int (*csk_ddp_set)(struct cxgbi_sock *, struct cxgbi_pagepod_hdr *, - unsigned int, unsigned int, - struct cxgbi_gather_list *); - void (*csk_ddp_clear)(struct cxgbi_hba *, - unsigned int, unsigned int, unsigned int); - int (*csk_ddp_setup_digest)(struct cxgbi_sock *, - unsigned int, int, int, int); - int (*csk_ddp_setup_pgidx)(struct cxgbi_sock *, - unsigned int, int, bool); - - void (*csk_release_offload_resources)(struct cxgbi_sock *); - int (*csk_rx_pdu_ready)(struct cxgbi_sock *, struct sk_buff *); - u32 (*csk_send_rx_credits)(struct cxgbi_sock *, u32); - int (*csk_push_tx_frames)(struct cxgbi_sock *, int); - void (*csk_send_abort_req)(struct cxgbi_sock *); - void (*csk_send_close_req)(struct cxgbi_sock *); - int (*csk_alloc_cpls)(struct cxgbi_sock *); - int (*csk_init_act_open)(struct cxgbi_sock *); - - void *dd_data; -}; -#define cxgbi_cdev_priv(cdev) ((cdev)->dd_data) - -struct cxgbi_conn { - struct cxgbi_endpoint *cep; - struct iscsi_conn *iconn; - struct cxgbi_hba *chba; - u32 task_idx_bits; -}; - -struct cxgbi_endpoint { - struct cxgbi_conn *cconn; - struct cxgbi_hba *chba; - struct cxgbi_sock *csk; -}; - -#define MAX_PDU_FRAGS ((ULP2_MAX_PDU_PAYLOAD + 512 - 1) / 512) -struct cxgbi_task_data { - unsigned short nr_frags; - struct page_frag frags[MAX_PDU_FRAGS]; - struct sk_buff *skb; - unsigned int offset; - unsigned int count; - unsigned int sgoffset; -}; -#define iscsi_task_cxgbi_data(task) \ - ((task)->dd_data + sizeof(struct iscsi_tcp_task)) - -static inline int cxgbi_is_ddp_tag(struct cxgbi_tag_format *tformat, u32 tag) -{ - return !(tag & (1 << (tformat->rsvd_bits + tformat->rsvd_shift - 1))); -} - -static inline int cxgbi_sw_tag_usable(struct cxgbi_tag_format *tformat, - u32 sw_tag) -{ - sw_tag >>= (32 - tformat->rsvd_bits); - return !sw_tag; -} - -static inline u32 cxgbi_set_non_ddp_tag(struct cxgbi_tag_format *tformat, - u32 sw_tag) -{ - unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1; - u32 mask = (1 << shift) - 1; - - if (sw_tag && (sw_tag & ~mask)) { - u32 v1 = sw_tag & ((1 << shift) - 1); - u32 v2 = (sw_tag >> (shift - 1)) << shift; - - return v2 | v1 | 1 << shift; - } - - return sw_tag | 1 << shift; -} - -static inline u32 cxgbi_ddp_tag_base(struct cxgbi_tag_format *tformat, - u32 sw_tag) -{ - u32 mask = (1 << tformat->rsvd_shift) - 1; - - if (sw_tag && (sw_tag & ~mask)) { - u32 v1 = sw_tag & mask; - u32 v2 = sw_tag >> tformat->rsvd_shift; - - v2 <<= tformat->rsvd_bits + tformat->rsvd_shift; - - return v2 | v1; - } - - return sw_tag; -} - -static inline u32 cxgbi_tag_rsvd_bits(struct cxgbi_tag_format *tformat, - u32 tag) -{ - if (cxgbi_is_ddp_tag(tformat, tag)) - return (tag >> tformat->rsvd_shift) & tformat->rsvd_mask; - - return 0; -} - -static inline u32 cxgbi_tag_nonrsvd_bits(struct cxgbi_tag_format *tformat, - u32 tag) -{ - unsigned char shift = tformat->rsvd_bits + tformat->rsvd_shift - 1; - u32 v1, v2; - - if (cxgbi_is_ddp_tag(tformat, tag)) { - v1 = tag & ((1 << tformat->rsvd_shift) - 1); - v2 = (tag >> (shift + 1)) << tformat->rsvd_shift; - } else { - u32 mask = (1 << shift) - 1; - tag &= ~(1 << shift); - v1 = tag & mask; - v2 = (tag >> 1) & ~mask; - } - return v1 | v2; -} - -static inline void *cxgbi_alloc_big_mem(unsigned int size, - gfp_t gfp) -{ - void *p = kmalloc(size, gfp); - if (!p) - p = vmalloc(size); - if (p) - memset(p, 0, size); - return p; -} - -static inline void cxgbi_free_big_mem(void *addr) -{ - if (is_vmalloc_addr(addr)) - vfree(addr); - else - kfree(addr); -} - -static inline void cxgbi_set_iscsi_ipv4(struct cxgbi_hba *chba, __be32 ipaddr) -{ - if (chba->cdev->flags & CXGBI_FLAG_IPV4_SET) - chba->ipv4addr = ipaddr; - else - pr_info("set iscsi ipv4 NOT supported, using %s ipv4.\n", - chba->ndev->name); -} - -static inline __be32 cxgbi_get_iscsi_ipv4(struct cxgbi_hba *chba) -{ - return chba->ipv4addr; -} - -struct cxgbi_device *cxgbi_device_register(unsigned int, unsigned int); -void cxgbi_device_unregister(struct cxgbi_device *); -void cxgbi_device_unregister_all(unsigned int flag); -struct cxgbi_device *cxgbi_device_find_by_lldev(void *); -int cxgbi_hbas_add(struct cxgbi_device *, unsigned int, unsigned int, - struct scsi_host_template *, - struct scsi_transport_template *); -void cxgbi_hbas_remove(struct cxgbi_device *); - -int cxgbi_device_portmap_create(struct cxgbi_device *cdev, unsigned int base, - unsigned int max_conn); -void cxgbi_device_portmap_cleanup(struct cxgbi_device *cdev); - -void cxgbi_conn_tx_open(struct cxgbi_sock *); -void cxgbi_conn_pdu_ready(struct cxgbi_sock *); -int cxgbi_conn_alloc_pdu(struct iscsi_task *, u8); -int cxgbi_conn_init_pdu(struct iscsi_task *, unsigned int , unsigned int); -int cxgbi_conn_xmit_pdu(struct iscsi_task *); - -void cxgbi_cleanup_task(struct iscsi_task *task); - -umode_t cxgbi_attr_is_visible(int param_type, int param); -void cxgbi_get_conn_stats(struct iscsi_cls_conn *, struct iscsi_stats *); -int cxgbi_set_conn_param(struct iscsi_cls_conn *, - enum iscsi_param, char *, int); -int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param, char *); -struct iscsi_cls_conn *cxgbi_create_conn(struct iscsi_cls_session *, u32); -int cxgbi_bind_conn(struct iscsi_cls_session *, - struct iscsi_cls_conn *, u64, int); -void cxgbi_destroy_session(struct iscsi_cls_session *); -struct iscsi_cls_session *cxgbi_create_session(struct iscsi_endpoint *, - u16, u16, u32); -int cxgbi_set_host_param(struct Scsi_Host *, - enum iscsi_host_param, char *, int); -int cxgbi_get_host_param(struct Scsi_Host *, enum iscsi_host_param, char *); -struct iscsi_endpoint *cxgbi_ep_connect(struct Scsi_Host *, - struct sockaddr *, int); -int cxgbi_ep_poll(struct iscsi_endpoint *, int); -void cxgbi_ep_disconnect(struct iscsi_endpoint *); - -int cxgbi_iscsi_init(struct iscsi_transport *, - struct scsi_transport_template **); -void cxgbi_iscsi_cleanup(struct iscsi_transport *, - struct scsi_transport_template **); -void cxgbi_parse_pdu_itt(struct iscsi_conn *, itt_t, int *, int *); -int cxgbi_ddp_init(struct cxgbi_device *, unsigned int, unsigned int, - unsigned int, unsigned int); -int cxgbi_ddp_cleanup(struct cxgbi_device *); -void cxgbi_ddp_page_size_factor(int *); -void cxgbi_ddp_ppod_clear(struct cxgbi_pagepod *); -void cxgbi_ddp_ppod_set(struct cxgbi_pagepod *, struct cxgbi_pagepod_hdr *, - struct cxgbi_gather_list *, unsigned int); -#endif /*__LIBCXGBI_H__*/ diff --git a/ANDROID_3.4.5/drivers/scsi/dc395x.c b/ANDROID_3.4.5/drivers/scsi/dc395x.c deleted file mode 100644 index 13aeca3d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dc395x.c +++ /dev/null @@ -1,4924 +0,0 @@ -/* - * dc395x.c - * - * Device Driver for Tekram DC395(U/UW/F), DC315(U) - * PCI SCSI Bus Master Host Adapter - * (SCSI chip set used Tekram ASIC TRM-S1040) - * - * Authors: - * C.L. Huang - * Erich Chen - * (C) Copyright 1995-1999 Tekram Technology Co., Ltd. - * - * Kurt Garloff - * (C) 1999-2000 Kurt Garloff - * - * Oliver Neukum - * Ali Akcaagac - * Jamie Lenehan - * (C) 2003 - * - * License: GNU GPL - * - ************************************************************************* - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ************************************************************************ - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include /* needed for scsicam_bios_param */ -#include -#include -#include - -#include "dc395x.h" - -#define DC395X_NAME "dc395x" -#define DC395X_BANNER "Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040" -#define DC395X_VERSION "v2.05, 2004/03/08" - -/*--------------------------------------------------------------------------- - Features - ---------------------------------------------------------------------------*/ -/* - * Set to disable parts of the driver - */ -/*#define DC395x_NO_DISCONNECT*/ -/*#define DC395x_NO_TAGQ*/ -/*#define DC395x_NO_SYNC*/ -/*#define DC395x_NO_WIDE*/ - -/*--------------------------------------------------------------------------- - Debugging - ---------------------------------------------------------------------------*/ -/* - * Types of debugging that can be enabled and disabled - */ -#define DBG_KG 0x0001 -#define DBG_0 0x0002 -#define DBG_1 0x0004 -#define DBG_SG 0x0020 -#define DBG_FIFO 0x0040 -#define DBG_PIO 0x0080 - - -/* - * Set set of things to output debugging for. - * Undefine to remove all debugging - */ -/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/ -/*#define DEBUG_MASK DBG_0*/ - - -/* - * Output a kernel mesage at the specified level and append the - * driver name and a ": " to the start of the message - */ -#define dprintkl(level, format, arg...) \ - printk(level DC395X_NAME ": " format , ## arg) - - -#ifdef DEBUG_MASK -/* - * print a debug message - this is formated with KERN_DEBUG, then the - * driver name followed by a ": " and then the message is output. - * This also checks that the specified debug level is enabled before - * outputing the message - */ -#define dprintkdbg(type, format, arg...) \ - do { \ - if ((type) & (DEBUG_MASK)) \ - dprintkl(KERN_DEBUG , format , ## arg); \ - } while (0) - -/* - * Check if the specified type of debugging is enabled - */ -#define debug_enabled(type) ((DEBUG_MASK) & (type)) - -#else -/* - * No debugging. Do nothing - */ -#define dprintkdbg(type, format, arg...) \ - do {} while (0) -#define debug_enabled(type) (0) - -#endif - - -#ifndef PCI_VENDOR_ID_TEKRAM -#define PCI_VENDOR_ID_TEKRAM 0x1DE1 /* Vendor ID */ -#endif -#ifndef PCI_DEVICE_ID_TEKRAM_TRMS1040 -#define PCI_DEVICE_ID_TEKRAM_TRMS1040 0x0391 /* Device ID */ -#endif - - -#define DC395x_LOCK_IO(dev,flags) spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags) -#define DC395x_UNLOCK_IO(dev,flags) spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags) - -#define DC395x_read8(acb,address) (u8)(inb(acb->io_port_base + (address))) -#define DC395x_read16(acb,address) (u16)(inw(acb->io_port_base + (address))) -#define DC395x_read32(acb,address) (u32)(inl(acb->io_port_base + (address))) -#define DC395x_write8(acb,address,value) outb((value), acb->io_port_base + (address)) -#define DC395x_write16(acb,address,value) outw((value), acb->io_port_base + (address)) -#define DC395x_write32(acb,address,value) outl((value), acb->io_port_base + (address)) - -/* cmd->result */ -#define RES_TARGET 0x000000FF /* Target State */ -#define RES_TARGET_LNX STATUS_MASK /* Only official ... */ -#define RES_ENDMSG 0x0000FF00 /* End Message */ -#define RES_DID 0x00FF0000 /* DID_ codes */ -#define RES_DRV 0xFF000000 /* DRIVER_ codes */ - -#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)) -#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1) - -#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); } -#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } -#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; } -#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; } -#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; } - -#define TAG_NONE 255 - -/* - * srb->segement_x is the hw sg list. It is always allocated as a - * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not - * cross a page boundy. - */ -#define SEGMENTX_LEN (sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY) - - -struct SGentry { - u32 address; /* bus! address */ - u32 length; -}; - -/* The SEEPROM structure for TRM_S1040 */ -struct NVRamTarget { - u8 cfg0; /* Target configuration byte 0 */ - u8 period; /* Target period */ - u8 cfg2; /* Target configuration byte 2 */ - u8 cfg3; /* Target configuration byte 3 */ -}; - -struct NvRamType { - u8 sub_vendor_id[2]; /* 0,1 Sub Vendor ID */ - u8 sub_sys_id[2]; /* 2,3 Sub System ID */ - u8 sub_class; /* 4 Sub Class */ - u8 vendor_id[2]; /* 5,6 Vendor ID */ - u8 device_id[2]; /* 7,8 Device ID */ - u8 reserved; /* 9 Reserved */ - struct NVRamTarget target[DC395x_MAX_SCSI_ID]; - /** 10,11,12,13 - ** 14,15,16,17 - ** .... - ** .... - ** 70,71,72,73 - */ - u8 scsi_id; /* 74 Host Adapter SCSI ID */ - u8 channel_cfg; /* 75 Channel configuration */ - u8 delay_time; /* 76 Power on delay time */ - u8 max_tag; /* 77 Maximum tags */ - u8 reserved0; /* 78 */ - u8 boot_target; /* 79 */ - u8 boot_lun; /* 80 */ - u8 reserved1; /* 81 */ - u16 reserved2[22]; /* 82,..125 */ - u16 cksum; /* 126,127 */ -}; - -struct ScsiReqBlk { - struct list_head list; /* next/prev ptrs for srb lists */ - struct DeviceCtlBlk *dcb; - struct scsi_cmnd *cmd; - - struct SGentry *segment_x; /* Linear array of hw sg entries (up to 64 entries) */ - dma_addr_t sg_bus_addr; /* Bus address of sg list (ie, of segment_x) */ - - u8 sg_count; /* No of HW sg entries for this request */ - u8 sg_index; /* Index of HW sg entry for this request */ - size_t total_xfer_length; /* Total number of bytes remaining to be transferred */ - size_t request_length; /* Total number of bytes in this request */ - /* - * The sense buffer handling function, request_sense, uses - * the first hw sg entry (segment_x[0]) and the transfer - * length (total_xfer_length). While doing this it stores the - * original values into the last sg hw list - * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the - * total_xfer_length in xferred. These values are restored in - * pci_unmap_srb_sense. This is the only place xferred is used. - */ - size_t xferred; /* Saved copy of total_xfer_length */ - - u16 state; - - u8 msgin_buf[6]; - u8 msgout_buf[6]; - - u8 adapter_status; - u8 target_status; - u8 msg_count; - u8 end_message; - - u8 tag_number; - u8 status; - u8 retry_count; - u8 flag; - - u8 scsi_phase; -}; - -struct DeviceCtlBlk { - struct list_head list; /* next/prev ptrs for the dcb list */ - struct AdapterCtlBlk *acb; - struct list_head srb_going_list; /* head of going srb list */ - struct list_head srb_waiting_list; /* head of waiting srb list */ - - struct ScsiReqBlk *active_srb; - u32 tag_mask; - - u16 max_command; - - u8 target_id; /* SCSI Target ID (SCSI Only) */ - u8 target_lun; /* SCSI Log. Unit (SCSI Only) */ - u8 identify_msg; - u8 dev_mode; - - u8 inquiry7; /* To store Inquiry flags */ - u8 sync_mode; /* 0:async mode */ - u8 min_nego_period; /* for nego. */ - u8 sync_period; /* for reg. */ - - u8 sync_offset; /* for reg. and nego.(low nibble) */ - u8 flag; - u8 dev_type; - u8 init_tcq_flag; -}; - -struct AdapterCtlBlk { - struct Scsi_Host *scsi_host; - - unsigned long io_port_base; - unsigned long io_port_len; - - struct list_head dcb_list; /* head of going dcb list */ - struct DeviceCtlBlk *dcb_run_robin; - struct DeviceCtlBlk *active_dcb; - - struct list_head srb_free_list; /* head of free srb list */ - struct ScsiReqBlk *tmp_srb; - struct timer_list waiting_timer; - struct timer_list selto_timer; - - u16 srb_count; - - u8 sel_timeout; - - unsigned int irq_level; - u8 tag_max_num; - u8 acb_flag; - u8 gmode2; - - u8 config; - u8 lun_chk; - u8 scan_devices; - u8 hostid_bit; - - u8 dcb_map[DC395x_MAX_SCSI_ID]; - struct DeviceCtlBlk *children[DC395x_MAX_SCSI_ID][32]; - - struct pci_dev *dev; - - u8 msg_len; - - struct ScsiReqBlk srb_array[DC395x_MAX_SRB_CNT]; - struct ScsiReqBlk srb; - - struct NvRamType eeprom; /* eeprom settings for this adapter */ -}; - - -/*--------------------------------------------------------------------------- - Forward declarations - ---------------------------------------------------------------------------*/ -static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status); -static void set_basic_config(struct AdapterCtlBlk *acb); -static void cleanup_after_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); -static void reset_scsi_bus(struct AdapterCtlBlk *acb); -static void data_io_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, u16 io_dir); -static void disconnect(struct AdapterCtlBlk *acb); -static void reselect(struct AdapterCtlBlk *acb); -static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); -static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); -static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); -static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code, - struct scsi_cmnd *cmd, u8 force); -static void scsi_reset_detect(struct AdapterCtlBlk *acb); -static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb); -static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb); -static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); -static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb); -static void set_xfer_rate(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb); -static void waiting_timeout(unsigned long ptr); - - -/*--------------------------------------------------------------------------- - Static Data - ---------------------------------------------------------------------------*/ -static u16 current_sync_offset = 0; - -static void *dc395x_scsi_phase0[] = { - data_out_phase0,/* phase:0 */ - data_in_phase0, /* phase:1 */ - command_phase0, /* phase:2 */ - status_phase0, /* phase:3 */ - nop0, /* phase:4 PH_BUS_FREE .. initial phase */ - nop0, /* phase:5 PH_BUS_FREE .. initial phase */ - msgout_phase0, /* phase:6 */ - msgin_phase0, /* phase:7 */ -}; - -static void *dc395x_scsi_phase1[] = { - data_out_phase1,/* phase:0 */ - data_in_phase1, /* phase:1 */ - command_phase1, /* phase:2 */ - status_phase1, /* phase:3 */ - nop1, /* phase:4 PH_BUS_FREE .. initial phase */ - nop1, /* phase:5 PH_BUS_FREE .. initial phase */ - msgout_phase1, /* phase:6 */ - msgin_phase1, /* phase:7 */ -}; - -/* - *Fast20: 000 50ns, 20.0 MHz - * 001 75ns, 13.3 MHz - * 010 100ns, 10.0 MHz - * 011 125ns, 8.0 MHz - * 100 150ns, 6.6 MHz - * 101 175ns, 5.7 MHz - * 110 200ns, 5.0 MHz - * 111 250ns, 4.0 MHz - * - *Fast40(LVDS): 000 25ns, 40.0 MHz - * 001 50ns, 20.0 MHz - * 010 75ns, 13.3 MHz - * 011 100ns, 10.0 MHz - * 100 125ns, 8.0 MHz - * 101 150ns, 6.6 MHz - * 110 175ns, 5.7 MHz - * 111 200ns, 5.0 MHz - */ -/*static u8 clock_period[] = {12,19,25,31,37,44,50,62};*/ - -/* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */ -static u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 }; -static u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 }; - - -/*--------------------------------------------------------------------------- - Configuration - ---------------------------------------------------------------------------*/ -/* - * Module/boot parameters currently effect *all* instances of the - * card in the system. - */ - -/* - * Command line parameters are stored in a structure below. - * These are the index's into the structure for the various - * command line options. - */ -#define CFG_ADAPTER_ID 0 -#define CFG_MAX_SPEED 1 -#define CFG_DEV_MODE 2 -#define CFG_ADAPTER_MODE 3 -#define CFG_TAGS 4 -#define CFG_RESET_DELAY 5 - -#define CFG_NUM 6 /* number of configuration items */ - - -/* - * Value used to indicate that a command line override - * hasn't been used to modify the value. - */ -#define CFG_PARAM_UNSET -1 - - -/* - * Hold command line parameters. - */ -struct ParameterData { - int value; /* value of this setting */ - int min; /* minimum value */ - int max; /* maximum value */ - int def; /* default value */ - int safe; /* safe value */ -}; -static struct ParameterData __devinitdata cfg_data[] = { - { /* adapter id */ - CFG_PARAM_UNSET, - 0, - 15, - 7, - 7 - }, - { /* max speed */ - CFG_PARAM_UNSET, - 0, - 7, - 1, /* 13.3Mhz */ - 4, /* 6.7Hmz */ - }, - { /* dev mode */ - CFG_PARAM_UNSET, - 0, - 0x3f, - NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO | - NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING | - NTC_DO_SEND_START, - NTC_DO_PARITY_CHK | NTC_DO_SEND_START - }, - { /* adapter mode */ - CFG_PARAM_UNSET, - 0, - 0x2f, -#ifdef CONFIG_SCSI_MULTI_LUN - NAC_SCANLUN | -#endif - NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET - /*| NAC_ACTIVE_NEG*/, - NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET | 0x08 - }, - { /* tags */ - CFG_PARAM_UNSET, - 0, - 5, - 3, /* 16 tags (??) */ - 2, - }, - { /* reset delay */ - CFG_PARAM_UNSET, - 0, - 180, - 1, /* 1 second */ - 10, /* 10 seconds */ - } -}; - - -/* - * Safe settings. If set to zero the BIOS/default values with - * command line overrides will be used. If set to 1 then safe and - * slow settings will be used. - */ -static bool use_safe_settings = 0; -module_param_named(safe, use_safe_settings, bool, 0); -MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false"); - - -module_param_named(adapter_id, cfg_data[CFG_ADAPTER_ID].value, int, 0); -MODULE_PARM_DESC(adapter_id, "Adapter SCSI ID. Default 7 (0-15)"); - -module_param_named(max_speed, cfg_data[CFG_MAX_SPEED].value, int, 0); -MODULE_PARM_DESC(max_speed, "Maximum bus speed. Default 1 (0-7) Speeds: 0=20, 1=13.3, 2=10, 3=8, 4=6.7, 5=5.8, 6=5, 7=4 Mhz"); - -module_param_named(dev_mode, cfg_data[CFG_DEV_MODE].value, int, 0); -MODULE_PARM_DESC(dev_mode, "Device mode."); - -module_param_named(adapter_mode, cfg_data[CFG_ADAPTER_MODE].value, int, 0); -MODULE_PARM_DESC(adapter_mode, "Adapter mode."); - -module_param_named(tags, cfg_data[CFG_TAGS].value, int, 0); -MODULE_PARM_DESC(tags, "Number of tags (1< cfg_data[i].max) - cfg_data[i].value = cfg_data[i].def; - } -} - - - -/* - * Mapping from the eeprom delay index value (index into this array) - * to the number of actual seconds that the delay should be for. - */ -static char __devinitdata eeprom_index_to_delay_map[] = - { 1, 3, 5, 10, 16, 30, 60, 120 }; - - -/** - * eeprom_index_to_delay - Take the eeprom delay setting and convert it - * into a number of seconds. - * - * @eeprom: The eeprom structure in which we find the delay index to map. - **/ -static void __devinit eeprom_index_to_delay(struct NvRamType *eeprom) -{ - eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time]; -} - - -/** - * delay_to_eeprom_index - Take a delay in seconds and return the - * closest eeprom index which will delay for at least that amount of - * seconds. - * - * @delay: The delay, in seconds, to find the eeprom index for. - **/ -static int __devinit delay_to_eeprom_index(int delay) -{ - u8 idx = 0; - while (idx < 7 && eeprom_index_to_delay_map[idx] < delay) - idx++; - return idx; -} - - -/** - * eeprom_override - Override the eeprom settings, in the provided - * eeprom structure, with values that have been set on the command - * line. - * - * @eeprom: The eeprom data to override with command line options. - **/ -static void __devinit eeprom_override(struct NvRamType *eeprom) -{ - u8 id; - - /* Adapter Settings */ - if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET) - eeprom->scsi_id = (u8)cfg_data[CFG_ADAPTER_ID].value; - - if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET) - eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value; - - if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET) - eeprom->delay_time = delay_to_eeprom_index( - cfg_data[CFG_RESET_DELAY].value); - - if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET) - eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value; - - /* Device Settings */ - for (id = 0; id < DC395x_MAX_SCSI_ID; id++) { - if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET) - eeprom->target[id].cfg0 = - (u8)cfg_data[CFG_DEV_MODE].value; - - if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET) - eeprom->target[id].period = - (u8)cfg_data[CFG_MAX_SPEED].value; - - } -} - - -/*--------------------------------------------------------------------------- - ---------------------------------------------------------------------------*/ - -static unsigned int list_size(struct list_head *head) -{ - unsigned int count = 0; - struct list_head *pos; - list_for_each(pos, head) - count++; - return count; -} - - -static struct DeviceCtlBlk *dcb_get_next(struct list_head *head, - struct DeviceCtlBlk *pos) -{ - int use_next = 0; - struct DeviceCtlBlk* next = NULL; - struct DeviceCtlBlk* i; - - if (list_empty(head)) - return NULL; - - /* find supplied dcb and then select the next one */ - list_for_each_entry(i, head, list) - if (use_next) { - next = i; - break; - } else if (i == pos) { - use_next = 1; - } - /* if no next one take the head one (ie, wraparound) */ - if (!next) - list_for_each_entry(i, head, list) { - next = i; - break; - } - - return next; -} - - -static void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) -{ - if (srb->tag_number < 255) { - dcb->tag_mask &= ~(1 << srb->tag_number); /* free tag mask */ - srb->tag_number = 255; - } -} - - -/* Find cmd in SRB list */ -static inline struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd, - struct list_head *head) -{ - struct ScsiReqBlk *i; - list_for_each_entry(i, head, list) - if (i->cmd == cmd) - return i; - return NULL; -} - - -static struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb) -{ - struct list_head *head = &acb->srb_free_list; - struct ScsiReqBlk *srb = NULL; - - if (!list_empty(head)) { - srb = list_entry(head->next, struct ScsiReqBlk, list); - list_del(head->next); - dprintkdbg(DBG_0, "srb_get_free: srb=%p\n", srb); - } - return srb; -} - - -static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, "srb_free_insert: srb=%p\n", srb); - list_add_tail(&srb->list, &acb->srb_free_list); -} - - -static void srb_waiting_insert(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, "srb_waiting_insert: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_add(&srb->list, &dcb->srb_waiting_list); -} - - -static void srb_waiting_append(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, "srb_waiting_append: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_add_tail(&srb->list, &dcb->srb_waiting_list); -} - - -static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, "srb_going_append: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_add_tail(&srb->list, &dcb->srb_going_list); -} - - -static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) -{ - struct ScsiReqBlk *i; - struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_going_remove: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - - list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list) - if (i == srb) { - list_del(&srb->list); - break; - } -} - - -static void srb_waiting_remove(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - struct ScsiReqBlk *i; - struct ScsiReqBlk *tmp; - dprintkdbg(DBG_0, "srb_waiting_remove: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - - list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list) - if (i == srb) { - list_del(&srb->list); - break; - } -} - - -static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, - "srb_going_to_waiting_move: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_move(&srb->list, &dcb->srb_waiting_list); -} - - -static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - dprintkdbg(DBG_0, - "srb_waiting_to_going_move: (0x%p) <%02i-%i> srb=%p\n", - srb->cmd, dcb->target_id, dcb->target_lun, srb); - list_move(&srb->list, &dcb->srb_going_list); -} - - -/* Sets the timer to wake us up */ -static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to) -{ - if (timer_pending(&acb->waiting_timer)) - return; - init_timer(&acb->waiting_timer); - acb->waiting_timer.function = waiting_timeout; - acb->waiting_timer.data = (unsigned long) acb; - if (time_before(jiffies + to, acb->scsi_host->last_reset - HZ / 2)) - acb->waiting_timer.expires = - acb->scsi_host->last_reset - HZ / 2 + 1; - else - acb->waiting_timer.expires = jiffies + to + 1; - add_timer(&acb->waiting_timer); -} - - -/* Send the next command from the waiting list to the bus */ -static void waiting_process_next(struct AdapterCtlBlk *acb) -{ - struct DeviceCtlBlk *start = NULL; - struct DeviceCtlBlk *pos; - struct DeviceCtlBlk *dcb; - struct ScsiReqBlk *srb; - struct list_head *dcb_list_head = &acb->dcb_list; - - if (acb->active_dcb - || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) - return; - - if (timer_pending(&acb->waiting_timer)) - del_timer(&acb->waiting_timer); - - if (list_empty(dcb_list_head)) - return; - - /* - * Find the starting dcb. Need to find it again in the list - * since the list may have changed since we set the ptr to it - */ - list_for_each_entry(dcb, dcb_list_head, list) - if (dcb == acb->dcb_run_robin) { - start = dcb; - break; - } - if (!start) { - /* This can happen! */ - start = list_entry(dcb_list_head->next, typeof(*start), list); - acb->dcb_run_robin = start; - } - - - /* - * Loop over the dcb, but we start somewhere (potentially) in - * the middle of the loop so we need to manully do this. - */ - pos = start; - do { - struct list_head *waiting_list_head = &pos->srb_waiting_list; - - /* Make sure, the next another device gets scheduled ... */ - acb->dcb_run_robin = dcb_get_next(dcb_list_head, - acb->dcb_run_robin); - - if (list_empty(waiting_list_head) || - pos->max_command <= list_size(&pos->srb_going_list)) { - /* move to next dcb */ - pos = dcb_get_next(dcb_list_head, pos); - } else { - srb = list_entry(waiting_list_head->next, - struct ScsiReqBlk, list); - - /* Try to send to the bus */ - if (!start_scsi(acb, pos, srb)) - srb_waiting_to_going_move(pos, srb); - else - waiting_set_timer(acb, HZ/50); - break; - } - } while (pos != start); -} - - -/* Wake up waiting queue */ -static void waiting_timeout(unsigned long ptr) -{ - unsigned long flags; - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr; - dprintkdbg(DBG_1, - "waiting_timeout: Queue woken up by timer. acb=%p\n", acb); - DC395x_LOCK_IO(acb->scsi_host, flags); - waiting_process_next(acb); - DC395x_UNLOCK_IO(acb->scsi_host, flags); -} - - -/* Get the DCB for a given ID/LUN combination */ -static struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun) -{ - return acb->children[id][lun]; -} - - -/* Send SCSI Request Block (srb) to adapter (acb) */ -static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) -{ - struct DeviceCtlBlk *dcb = srb->dcb; - - if (dcb->max_command <= list_size(&dcb->srb_going_list) || - acb->active_dcb || - (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) { - srb_waiting_append(dcb, srb); - waiting_process_next(acb); - return; - } - - if (!start_scsi(acb, dcb, srb)) - srb_going_append(dcb, srb); - else { - srb_waiting_insert(dcb, srb); - waiting_set_timer(acb, HZ / 50); - } -} - -/* Prepare SRB for being sent to Device DCB w/ command *cmd */ -static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - int nseg; - enum dma_data_direction dir = cmd->sc_data_direction; - dprintkdbg(DBG_0, "build_srb: (0x%p) <%02i-%i>\n", - cmd, dcb->target_id, dcb->target_lun); - - srb->dcb = dcb; - srb->cmd = cmd; - srb->sg_count = 0; - srb->total_xfer_length = 0; - srb->sg_bus_addr = 0; - srb->sg_index = 0; - srb->adapter_status = 0; - srb->target_status = 0; - srb->msg_count = 0; - srb->status = 0; - srb->flag = 0; - srb->state = 0; - srb->retry_count = 0; - srb->tag_number = TAG_NONE; - srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - srb->end_message = 0; - - nseg = scsi_dma_map(cmd); - BUG_ON(nseg < 0); - - if (dir == PCI_DMA_NONE || !nseg) { - dprintkdbg(DBG_0, - "build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n", - cmd->bufflen, scsi_sglist(cmd), scsi_sg_count(cmd), - srb->segment_x[0].address); - } else { - int i; - u32 reqlen = scsi_bufflen(cmd); - struct scatterlist *sg; - struct SGentry *sgp = srb->segment_x; - - srb->sg_count = nseg; - - dprintkdbg(DBG_0, - "build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n", - reqlen, scsi_sglist(cmd), scsi_sg_count(cmd), - srb->sg_count); - - scsi_for_each_sg(cmd, sg, srb->sg_count, i) { - u32 busaddr = (u32)sg_dma_address(sg); - u32 seglen = (u32)sg->length; - sgp[i].address = busaddr; - sgp[i].length = seglen; - srb->total_xfer_length += seglen; - } - sgp += srb->sg_count - 1; - - /* - * adjust last page if too big as it is allocated - * on even page boundaries - */ - if (srb->total_xfer_length > reqlen) { - sgp->length -= (srb->total_xfer_length - reqlen); - srb->total_xfer_length = reqlen; - } - - /* Fixup for WIDE padding - make sure length is even */ - if (dcb->sync_period & WIDE_SYNC && - srb->total_xfer_length % 2) { - srb->total_xfer_length++; - sgp->length++; - } - - srb->sg_bus_addr = pci_map_single(dcb->acb->dev, - srb->segment_x, - SEGMENTX_LEN, - PCI_DMA_TODEVICE); - - dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n", - srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN); - } - - srb->request_length = srb->total_xfer_length; -} - - -/** - * dc395x_queue_command - queue scsi command passed from the mid - * layer, invoke 'done' on completion - * - * @cmd: pointer to scsi command object - * @done: function pointer to be invoked on completion - * - * Returns 1 if the adapter (host) is busy, else returns 0. One - * reason for an adapter to be busy is that the number - * of outstanding queued commands is already equal to - * struct Scsi_Host::can_queue . - * - * Required: if struct Scsi_Host::can_queue is ever non-zero - * then this function is required. - * - * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave") - * and is expected to be held on return. - * - **/ -static int dc395x_queue_command_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct DeviceCtlBlk *dcb; - struct ScsiReqBlk *srb; - struct AdapterCtlBlk *acb = - (struct AdapterCtlBlk *)cmd->device->host->hostdata; - dprintkdbg(DBG_0, "queue_command: (0x%p) <%02i-%i> cmnd=0x%02x\n", - cmd, cmd->device->id, cmd->device->lun, cmd->cmnd[0]); - - /* Assume BAD_TARGET; will be cleared later */ - cmd->result = DID_BAD_TARGET << 16; - - /* ignore invalid targets */ - if (cmd->device->id >= acb->scsi_host->max_id || - cmd->device->lun >= acb->scsi_host->max_lun || - cmd->device->lun >31) { - goto complete; - } - - /* does the specified lun on the specified device exist */ - if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) { - dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n", - cmd->device->id, cmd->device->lun); - goto complete; - } - - /* do we have a DCB for the device */ - dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); - if (!dcb) { - /* should never happen */ - dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>", - cmd->device->id, cmd->device->lun); - goto complete; - } - - /* set callback and clear result in the command */ - cmd->scsi_done = done; - cmd->result = 0; - - srb = srb_get_free(acb); - if (!srb) - { - /* - * Return 1 since we are unable to queue this command at this - * point in time. - */ - dprintkdbg(DBG_0, "queue_command: No free srb's\n"); - return 1; - } - - build_srb(cmd, dcb, srb); - - if (!list_empty(&dcb->srb_waiting_list)) { - /* append to waiting queue */ - srb_waiting_append(dcb, srb); - waiting_process_next(acb); - } else { - /* process immediately */ - send_srb(acb, srb); - } - dprintkdbg(DBG_1, "queue_command: (0x%p) done\n", cmd); - return 0; - -complete: - /* - * Complete the command immediatey, and then return 0 to - * indicate that we have handled the command. This is usually - * done when the commad is for things like non existent - * devices. - */ - done(cmd); - return 0; -} - -static DEF_SCSI_QCMD(dc395x_queue_command) - -/* - * Return the disk geometry for the given SCSI device. - */ -static int dc395x_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *info) -{ -#ifdef CONFIG_SCSI_DC395x_TRMS1040_TRADMAP - int heads, sectors, cylinders; - struct AdapterCtlBlk *acb; - int size = capacity; - - dprintkdbg(DBG_0, "dc395x_bios_param..............\n"); - acb = (struct AdapterCtlBlk *)sdev->host->hostdata; - heads = 64; - sectors = 32; - cylinders = size / (heads * sectors); - - if ((acb->gmode2 & NAC_GREATER_1G) && (cylinders > 1024)) { - heads = 255; - sectors = 63; - cylinders = size / (heads * sectors); - } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - return 0; -#else - return scsicam_bios_param(bdev, capacity, info); -#endif -} - - -static void dump_register_info(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb) -{ - u16 pstat; - struct pci_dev *dev = acb->dev; - pci_read_config_word(dev, PCI_STATUS, &pstat); - if (!dcb) - dcb = acb->active_dcb; - if (!srb && dcb) - srb = dcb->active_srb; - if (srb) { - if (!srb->cmd) - dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n", - srb, srb->cmd); - else - dprintkl(KERN_INFO, "dump: srb=%p cmd=%p " - "cmnd=0x%02x <%02i-%i>\n", - srb, srb->cmd, - srb->cmd->cmnd[0], srb->cmd->device->id, - srb->cmd->device->lun); - printk(" sglist=%p cnt=%i idx=%i len=%zu\n", - srb->segment_x, srb->sg_count, srb->sg_index, - srb->total_xfer_length); - printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n", - srb->state, srb->status, srb->scsi_phase, - (acb->active_dcb) ? "" : "not"); - } - dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x " - "signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x " - "rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x " - "config2=0x%02x cmd=0x%02x selto=0x%02x}\n", - DC395x_read16(acb, TRM_S1040_SCSI_STATUS), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL), - DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS), - DC395x_read8(acb, TRM_S1040_SCSI_SYNC), - DC395x_read8(acb, TRM_S1040_SCSI_TARGETID), - DC395x_read8(acb, TRM_S1040_SCSI_IDMSG), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), - DC395x_read8(acb, TRM_S1040_SCSI_INTEN), - DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0), - DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2), - DC395x_read8(acb, TRM_S1040_SCSI_COMMAND), - DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT)); - dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x " - "irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x " - "ctctr=0x%08x addr=0x%08x:0x%08x}\n", - DC395x_read16(acb, TRM_S1040_DMA_COMMAND), - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_DMA_STATUS), - DC395x_read8(acb, TRM_S1040_DMA_INTEN), - DC395x_read16(acb, TRM_S1040_DMA_CONFIG), - DC395x_read32(acb, TRM_S1040_DMA_XCNT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT), - DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR), - DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR)); - dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} " - "pci{status=0x%04x}\n", - DC395x_read8(acb, TRM_S1040_GEN_CONTROL), - DC395x_read8(acb, TRM_S1040_GEN_STATUS), - DC395x_read8(acb, TRM_S1040_GEN_TIMER), - pstat); -} - - -static inline void clear_fifo(struct AdapterCtlBlk *acb, char *txt) -{ -#if debug_enabled(DBG_FIFO) - u8 lines = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); - u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); - if (!(fifocnt & 0x40)) - dprintkdbg(DBG_FIFO, - "clear_fifo: (%i bytes) on phase %02x in %s\n", - fifocnt & 0x3f, lines, txt); -#endif - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); -} - - -static void reset_dev_param(struct AdapterCtlBlk *acb) -{ - struct DeviceCtlBlk *dcb; - struct NvRamType *eeprom = &acb->eeprom; - dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb); - - list_for_each_entry(dcb, &acb->dcb_list, list) { - u8 period_index; - - dcb->sync_mode &= ~(SYNC_NEGO_DONE + WIDE_NEGO_DONE); - dcb->sync_period = 0; - dcb->sync_offset = 0; - - dcb->dev_mode = eeprom->target[dcb->target_id].cfg0; - period_index = eeprom->target[dcb->target_id].period & 0x07; - dcb->min_nego_period = clock_period[period_index]; - if (!(dcb->dev_mode & NTC_DO_WIDE_NEGO) - || !(acb->config & HCC_WIDE_CARD)) - dcb->sync_mode &= ~WIDE_NEGO_ENABLE; - } -} - - -/* - * perform a hard reset on the SCSI bus - * @cmd - some command for this host (for fetching hooks) - * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003). - */ -static int __dc395x_eh_bus_reset(struct scsi_cmnd *cmd) -{ - struct AdapterCtlBlk *acb = - (struct AdapterCtlBlk *)cmd->device->host->hostdata; - dprintkl(KERN_INFO, - "eh_bus_reset: (0%p) target=<%02i-%i> cmd=%p\n", - cmd, cmd->device->id, cmd->device->lun, cmd); - - if (timer_pending(&acb->waiting_timer)) - del_timer(&acb->waiting_timer); - - /* - * disable interrupt - */ - DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00); - DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00); - DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE); - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE); - - reset_scsi_bus(acb); - udelay(500); - - /* We may be in serious trouble. Wait some seconds */ - acb->scsi_host->last_reset = - jiffies + 3 * HZ / 2 + - HZ * acb->eeprom.delay_time; - - /* - * re-enable interrupt - */ - /* Clear SCSI FIFO */ - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); - clear_fifo(acb, "eh_bus_reset"); - /* Delete pending IRQ */ - DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); - set_basic_config(acb); - - reset_dev_param(acb); - doing_srb_done(acb, DID_RESET, cmd, 0); - acb->active_dcb = NULL; - acb->acb_flag = 0; /* RESET_DETECT, RESET_DONE ,RESET_DEV */ - waiting_process_next(acb); - - return SUCCESS; -} - -static int dc395x_eh_bus_reset(struct scsi_cmnd *cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __dc395x_eh_bus_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - -/* - * abort an errant SCSI command - * @cmd - command to be aborted - * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003). - */ -static int dc395x_eh_abort(struct scsi_cmnd *cmd) -{ - /* - * Look into our command queues: If it has not been sent already, - * we remove it and return success. Otherwise fail. - */ - struct AdapterCtlBlk *acb = - (struct AdapterCtlBlk *)cmd->device->host->hostdata; - struct DeviceCtlBlk *dcb; - struct ScsiReqBlk *srb; - dprintkl(KERN_INFO, "eh_abort: (0x%p) target=<%02i-%i> cmd=%p\n", - cmd, cmd->device->id, cmd->device->lun, cmd); - - dcb = find_dcb(acb, cmd->device->id, cmd->device->lun); - if (!dcb) { - dprintkl(KERN_DEBUG, "eh_abort: No such device\n"); - return FAILED; - } - - srb = find_cmd(cmd, &dcb->srb_waiting_list); - if (srb) { - srb_waiting_remove(dcb, srb); - pci_unmap_srb_sense(acb, srb); - pci_unmap_srb(acb, srb); - free_tag(dcb, srb); - srb_free_insert(acb, srb); - dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n"); - cmd->result = DID_ABORT << 16; - return SUCCESS; - } - srb = find_cmd(cmd, &dcb->srb_going_list); - if (srb) { - dprintkl(KERN_DEBUG, "eh_abort: Command in progress\n"); - /* XXX: Should abort the command here */ - } else { - dprintkl(KERN_DEBUG, "eh_abort: Command not found\n"); - } - return FAILED; -} - - -/* SDTR */ -static void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - u8 *ptr = srb->msgout_buf + srb->msg_count; - if (srb->msg_count > 1) { - dprintkl(KERN_INFO, - "build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n", - srb->msg_count, srb->msgout_buf[0], - srb->msgout_buf[1]); - return; - } - if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) { - dcb->sync_offset = 0; - dcb->min_nego_period = 200 >> 2; - } else if (dcb->sync_offset == 0) - dcb->sync_offset = SYNC_NEGO_OFFSET; - - *ptr++ = MSG_EXTENDED; /* (01h) */ - *ptr++ = 3; /* length */ - *ptr++ = EXTENDED_SDTR; /* (01h) */ - *ptr++ = dcb->min_nego_period; /* Transfer period (in 4ns) */ - *ptr++ = dcb->sync_offset; /* Transfer period (max. REQ/ACK dist) */ - srb->msg_count += 5; - srb->state |= SRB_DO_SYNC_NEGO; -} - - -/* WDTR */ -static void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) & - (acb->config & HCC_WIDE_CARD)) ? 1 : 0; - u8 *ptr = srb->msgout_buf + srb->msg_count; - if (srb->msg_count > 1) { - dprintkl(KERN_INFO, - "build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n", - srb->msg_count, srb->msgout_buf[0], - srb->msgout_buf[1]); - return; - } - *ptr++ = MSG_EXTENDED; /* (01h) */ - *ptr++ = 2; /* length */ - *ptr++ = EXTENDED_WDTR; /* (03h) */ - *ptr++ = wide; - srb->msg_count += 4; - srb->state |= SRB_DO_WIDE_NEGO; -} - - -#if 0 -/* Timer to work around chip flaw: When selecting and the bus is - * busy, we sometimes miss a Selection timeout IRQ */ -void selection_timeout_missed(unsigned long ptr); -/* Sets the timer to wake us up */ -static void selto_timer(struct AdapterCtlBlk *acb) -{ - if (timer_pending(&acb->selto_timer)) - return; - acb->selto_timer.function = selection_timeout_missed; - acb->selto_timer.data = (unsigned long) acb; - if (time_before - (jiffies + HZ, acb->scsi_host->last_reset + HZ / 2)) - acb->selto_timer.expires = - acb->scsi_host->last_reset + HZ / 2 + 1; - else - acb->selto_timer.expires = jiffies + HZ + 1; - add_timer(&acb->selto_timer); -} - - -void selection_timeout_missed(unsigned long ptr) -{ - unsigned long flags; - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr; - struct ScsiReqBlk *srb; - dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n"); - if (!acb->active_dcb || !acb->active_dcb->active_srb) { - dprintkl(KERN_DEBUG, "... but no cmd pending? Oops!\n"); - return; - } - DC395x_LOCK_IO(acb->scsi_host, flags); - srb = acb->active_dcb->active_srb; - disconnect(acb); - DC395x_UNLOCK_IO(acb->scsi_host, flags); -} -#endif - - -static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, - struct ScsiReqBlk* srb) -{ - u16 s_stat2, return_code; - u8 s_stat, scsicommand, i, identify_message; - u8 *ptr; - dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> srb=%p\n", - dcb->target_id, dcb->target_lun, srb); - - srb->tag_number = TAG_NONE; /* acb->tag_max_num: had error read in eeprom */ - - s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); - s_stat2 = 0; - s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); -#if 1 - if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { - dprintkdbg(DBG_KG, "start_scsi: (0x%p) BUSY %02x %04x\n", - s_stat, s_stat2); - /* - * Try anyway? - * - * We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection - * Timeout, a Disconnect or a Reselection IRQ, so we would be screwed! - * (This is likely to be a bug in the hardware. Obviously, most people - * only have one initiator per SCSI bus.) - * Instead let this fail and have the timer make sure the command is - * tried again after a short time - */ - /*selto_timer (acb); */ - return 1; - } -#endif - if (acb->active_dcb) { - dprintkl(KERN_DEBUG, "start_scsi: (0x%p) Attempt to start a" - "command while another command (0x%p) is active.", - srb->cmd, - acb->active_dcb->active_srb ? - acb->active_dcb->active_srb->cmd : 0); - return 1; - } - if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { - dprintkdbg(DBG_KG, "start_scsi: (0x%p) Failed (busy)\n", srb->cmd); - return 1; - } - /* Allow starting of SCSI commands half a second before we allow the mid-level - * to queue them again after a reset */ - if (time_before(jiffies, acb->scsi_host->last_reset - HZ / 2)) { - dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n"); - return 1; - } - - /* Flush FIFO */ - clear_fifo(acb, "start_scsi"); - DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); - DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); - DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); - DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); - srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - - identify_message = dcb->identify_msg; - /*DC395x_TRM_write8(TRM_S1040_SCSI_IDMSG, identify_message); */ - /* Don't allow disconnection for AUTO_REQSENSE: Cont.All.Cond.! */ - if (srb->flag & AUTO_REQSENSE) - identify_message &= 0xBF; - - if (((srb->cmd->cmnd[0] == INQUIRY) - || (srb->cmd->cmnd[0] == REQUEST_SENSE) - || (srb->flag & AUTO_REQSENSE)) - && (((dcb->sync_mode & WIDE_NEGO_ENABLE) - && !(dcb->sync_mode & WIDE_NEGO_DONE)) - || ((dcb->sync_mode & SYNC_NEGO_ENABLE) - && !(dcb->sync_mode & SYNC_NEGO_DONE))) - && (dcb->target_lun == 0)) { - srb->msgout_buf[0] = identify_message; - srb->msg_count = 1; - scsicommand = SCMD_SEL_ATNSTOP; - srb->state = SRB_MSGOUT; -#ifndef SYNC_FIRST - if (dcb->sync_mode & WIDE_NEGO_ENABLE - && dcb->inquiry7 & SCSI_INQ_WBUS16) { - build_wdtr(acb, dcb, srb); - goto no_cmd; - } -#endif - if (dcb->sync_mode & SYNC_NEGO_ENABLE - && dcb->inquiry7 & SCSI_INQ_SYNC) { - build_sdtr(acb, dcb, srb); - goto no_cmd; - } - if (dcb->sync_mode & WIDE_NEGO_ENABLE - && dcb->inquiry7 & SCSI_INQ_WBUS16) { - build_wdtr(acb, dcb, srb); - goto no_cmd; - } - srb->msg_count = 0; - } - /* Send identify message */ - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, identify_message); - - scsicommand = SCMD_SEL_ATN; - srb->state = SRB_START_; -#ifndef DC395x_NO_TAGQ - if ((dcb->sync_mode & EN_TAG_QUEUEING) - && (identify_message & 0xC0)) { - /* Send Tag message */ - u32 tag_mask = 1; - u8 tag_number = 0; - while (tag_mask & dcb->tag_mask - && tag_number < dcb->max_command) { - tag_mask = tag_mask << 1; - tag_number++; - } - if (tag_number >= dcb->max_command) { - dprintkl(KERN_WARNING, "start_scsi: (0x%p) " - "Out of tags target=<%02i-%i>)\n", - srb->cmd, srb->cmd->device->id, - srb->cmd->device->lun); - srb->state = SRB_READY; - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, - DO_HWRESELECT); - return 1; - } - /* Send Tag id */ - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_SIMPLE_QTAG); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, tag_number); - dcb->tag_mask |= tag_mask; - srb->tag_number = tag_number; - scsicommand = SCMD_SEL_ATN3; - srb->state = SRB_START_; - } -#endif -/*polling:*/ - /* Send CDB ..command block ......... */ - dprintkdbg(DBG_KG, "start_scsi: (0x%p) <%02i-%i> cmnd=0x%02x tag=%i\n", - srb->cmd, srb->cmd->device->id, srb->cmd->device->lun, - srb->cmd->cmnd[0], srb->tag_number); - if (srb->flag & AUTO_REQSENSE) { - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - } else { - ptr = (u8 *)srb->cmd->cmnd; - for (i = 0; i < srb->cmd->cmd_len; i++) - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++); - } - no_cmd: - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, - DO_HWRESELECT | DO_DATALATCH); - if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { - /* - * If start_scsi return 1: - * we caught an interrupt (must be reset or reselection ... ) - * : Let's process it first! - */ - dprintkdbg(DBG_0, "start_scsi: (0x%p) <%02i-%i> Failed - busy\n", - srb->cmd, dcb->target_id, dcb->target_lun); - srb->state = SRB_READY; - free_tag(dcb, srb); - srb->msg_count = 0; - return_code = 1; - /* This IRQ should NOT get lost, as we did not acknowledge it */ - } else { - /* - * If start_scsi returns 0: - * we know that the SCSI processor is free - */ - srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - dcb->active_srb = srb; - acb->active_dcb = dcb; - return_code = 0; - /* it's important for atn stop */ - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, - DO_DATALATCH | DO_HWRESELECT); - /* SCSI command */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, scsicommand); - } - return return_code; -} - - -#define DC395x_ENABLE_MSGOUT \ - DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \ - srb->state |= SRB_MSGOUT - - -/* abort command */ -static inline void enable_msgout_abort(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) -{ - srb->msgout_buf[0] = ABORT; - srb->msg_count = 1; - DC395x_ENABLE_MSGOUT; - srb->state &= ~SRB_MSGIN; - srb->state |= SRB_MSGOUT; -} - - -/** - * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to - * have been triggered for this card. - * - * @acb: a pointer to the adpter control block - * @scsi_status: the status return when we checked the card - **/ -static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb, - u16 scsi_status) -{ - struct DeviceCtlBlk *dcb; - struct ScsiReqBlk *srb; - u16 phase; - u8 scsi_intstatus; - unsigned long flags; - void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *, - u16 *); - - DC395x_LOCK_IO(acb->scsi_host, flags); - - /* This acknowledges the IRQ */ - scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); - if ((scsi_status & 0x2007) == 0x2002) - dprintkl(KERN_DEBUG, - "COP after COP completed? %04x\n", scsi_status); - if (debug_enabled(DBG_KG)) { - if (scsi_intstatus & INT_SELTIMEOUT) - dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n"); - } - /*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */ - - if (timer_pending(&acb->selto_timer)) - del_timer(&acb->selto_timer); - - if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) { - disconnect(acb); /* bus free interrupt */ - goto out_unlock; - } - if (scsi_intstatus & INT_RESELECTED) { - reselect(acb); - goto out_unlock; - } - if (scsi_intstatus & INT_SELECT) { - dprintkl(KERN_INFO, "Host does not support target mode!\n"); - goto out_unlock; - } - if (scsi_intstatus & INT_SCSIRESET) { - scsi_reset_detect(acb); - goto out_unlock; - } - if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) { - dcb = acb->active_dcb; - if (!dcb) { - dprintkl(KERN_DEBUG, - "Oops: BusService (%04x %02x) w/o ActiveDCB!\n", - scsi_status, scsi_intstatus); - goto out_unlock; - } - srb = dcb->active_srb; - if (dcb->flag & ABORT_DEV_) { - dprintkdbg(DBG_0, "MsgOut Abort Device.....\n"); - enable_msgout_abort(acb, srb); - } - - /* software sequential machine */ - phase = (u16)srb->scsi_phase; - - /* - * 62037 or 62137 - * call dc395x_scsi_phase0[]... "phase entry" - * handle every phase before start transfer - */ - /* data_out_phase0, phase:0 */ - /* data_in_phase0, phase:1 */ - /* command_phase0, phase:2 */ - /* status_phase0, phase:3 */ - /* nop0, phase:4 PH_BUS_FREE .. initial phase */ - /* nop0, phase:5 PH_BUS_FREE .. initial phase */ - /* msgout_phase0, phase:6 */ - /* msgin_phase0, phase:7 */ - dc395x_statev = dc395x_scsi_phase0[phase]; - dc395x_statev(acb, srb, &scsi_status); - - /* - * if there were any exception occurred scsi_status - * will be modify to bus free phase new scsi_status - * transfer out from ... previous dc395x_statev - */ - srb->scsi_phase = scsi_status & PHASEMASK; - phase = (u16)scsi_status & PHASEMASK; - - /* - * call dc395x_scsi_phase1[]... "phase entry" handle - * every phase to do transfer - */ - /* data_out_phase1, phase:0 */ - /* data_in_phase1, phase:1 */ - /* command_phase1, phase:2 */ - /* status_phase1, phase:3 */ - /* nop1, phase:4 PH_BUS_FREE .. initial phase */ - /* nop1, phase:5 PH_BUS_FREE .. initial phase */ - /* msgout_phase1, phase:6 */ - /* msgin_phase1, phase:7 */ - dc395x_statev = dc395x_scsi_phase1[phase]; - dc395x_statev(acb, srb, &scsi_status); - } - out_unlock: - DC395x_UNLOCK_IO(acb->scsi_host, flags); -} - - -static irqreturn_t dc395x_interrupt(int irq, void *dev_id) -{ - struct AdapterCtlBlk *acb = dev_id; - u16 scsi_status; - u8 dma_status; - irqreturn_t handled = IRQ_NONE; - - /* - * Check for pending interrupt - */ - scsi_status = DC395x_read16(acb, TRM_S1040_SCSI_STATUS); - dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS); - if (scsi_status & SCSIINTERRUPT) { - /* interrupt pending - let's process it! */ - dc395x_handle_interrupt(acb, scsi_status); - handled = IRQ_HANDLED; - } - else if (dma_status & 0x20) { - /* Error from the DMA engine */ - dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status); -#if 0 - dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n"); - if (acb->active_dcb) { - acb->active_dcb-> flag |= ABORT_DEV_; - if (acb->active_dcb->active_srb) - enable_msgout_abort(acb, acb->active_dcb->active_srb); - } - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO); -#else - dprintkl(KERN_INFO, "Ignoring DMA error (probably a bad thing) ...\n"); - acb = NULL; -#endif - handled = IRQ_HANDLED; - } - - return handled; -} - - -static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - dprintkdbg(DBG_0, "msgout_phase0: (0x%p)\n", srb->cmd); - if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) - *pscsi_status = PH_BUS_FREE; /*.. initial phase */ - - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - srb->state &= ~SRB_MSGOUT; -} - - -static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - u16 i; - u8 *ptr; - dprintkdbg(DBG_0, "msgout_phase1: (0x%p)\n", srb->cmd); - - clear_fifo(acb, "msgout_phase1"); - if (!(srb->state & SRB_MSGOUT)) { - srb->state |= SRB_MSGOUT; - dprintkl(KERN_DEBUG, - "msgout_phase1: (0x%p) Phase unexpected\n", - srb->cmd); /* So what ? */ - } - if (!srb->msg_count) { - dprintkdbg(DBG_0, "msgout_phase1: (0x%p) NOP msg\n", - srb->cmd); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); - return; - } - ptr = (u8 *)srb->msgout_buf; - for (i = 0; i < srb->msg_count; i++) - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++); - srb->msg_count = 0; - if (srb->msgout_buf[0] == MSG_ABORT) - srb->state = SRB_ABORT_SENT; - - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); -} - - -static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - dprintkdbg(DBG_0, "command_phase0: (0x%p)\n", srb->cmd); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); -} - - -static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - struct DeviceCtlBlk *dcb; - u8 *ptr; - u16 i; - dprintkdbg(DBG_0, "command_phase1: (0x%p)\n", srb->cmd); - - clear_fifo(acb, "command_phase1"); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN); - if (!(srb->flag & AUTO_REQSENSE)) { - ptr = (u8 *)srb->cmd->cmnd; - for (i = 0; i < srb->cmd->cmd_len; i++) { - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr); - ptr++; - } - } else { - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE); - dcb = acb->active_dcb; - /* target id */ - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5)); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, SCSI_SENSE_BUFFERSIZE); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - } - srb->state |= SRB_COMMAND; - /* it's important for atn stop */ - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); - /* SCSI command */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); -} - - -/* - * Verify that the remaining space in the hw sg lists is the same as - * the count of remaining bytes in srb->total_xfer_length - */ -static void sg_verify_length(struct ScsiReqBlk *srb) -{ - if (debug_enabled(DBG_SG)) { - unsigned len = 0; - unsigned idx = srb->sg_index; - struct SGentry *psge = srb->segment_x + idx; - for (; idx < srb->sg_count; psge++, idx++) - len += psge->length; - if (len != srb->total_xfer_length) - dprintkdbg(DBG_SG, - "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n", - srb->total_xfer_length, len); - } -} - - -/* - * Compute the next Scatter Gather list index and adjust its length - * and address if necessary - */ -static void sg_update_list(struct ScsiReqBlk *srb, u32 left) -{ - u8 idx; - u32 xferred = srb->total_xfer_length - left; /* bytes transferred */ - struct SGentry *psge = srb->segment_x + srb->sg_index; - - dprintkdbg(DBG_0, - "sg_update_list: Transferred %i of %i bytes, %i remain\n", - xferred, srb->total_xfer_length, left); - if (xferred == 0) { - /* nothing to update since we did not transfer any data */ - return; - } - - sg_verify_length(srb); - srb->total_xfer_length = left; /* update remaining count */ - for (idx = srb->sg_index; idx < srb->sg_count; idx++) { - if (xferred >= psge->length) { - /* Complete SG entries done */ - xferred -= psge->length; - } else { - /* Partial SG entry done */ - psge->length -= xferred; - psge->address += xferred; - srb->sg_index = idx; - pci_dma_sync_single_for_device(srb->dcb-> - acb->dev, - srb->sg_bus_addr, - SEGMENTX_LEN, - PCI_DMA_TODEVICE); - break; - } - psge++; - } - sg_verify_length(srb); -} - - -/* - * We have transferred a single byte (PIO mode?) and need to update - * the count of bytes remaining (total_xfer_length) and update the sg - * entry to either point to next byte in the current sg entry, or of - * already at the end to point to the start of the next sg entry - */ -static void sg_subtract_one(struct ScsiReqBlk *srb) -{ - sg_update_list(srb, srb->total_xfer_length - 1); -} - - -/* - * cleanup_after_transfer - * - * Makes sure, DMA and SCSI engine are empty, after the transfer has finished - * KG: Currently called from StatusPhase1 () - * Should probably also be called from other places - * Best might be to call it in DataXXPhase0, if new phase will differ - */ -static void cleanup_after_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) -{ - /*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */ - if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) { /* read */ - if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) - clear_fifo(acb, "cleanup/in"); - if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); - } else { /* write */ - if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); - if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40)) - clear_fifo(acb, "cleanup/out"); - } - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); -} - - -/* - * Those no of bytes will be transferred w/ PIO through the SCSI FIFO - * Seems to be needed for unknown reasons; could be a hardware bug :-( - */ -#define DC395x_LASTPIO 4 - - -static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - struct DeviceCtlBlk *dcb = srb->dcb; - u16 scsi_status = *pscsi_status; - u32 d_left_counter = 0; - dprintkdbg(DBG_0, "data_out_phase0: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); - - /* - * KG: We need to drain the buffers before we draw any conclusions! - * This means telling the DMA to push the rest into SCSI, telling - * SCSI to push the rest to the bus. - * However, the device might have been the one to stop us (phase - * change), and the data in transit just needs to be accounted so - * it can be retransmitted.) - */ - /* - * KG: Stop DMA engine pushing more data into the SCSI FIFO - * If we need more data, the DMA SG list will be freshly set up, anyway - */ - dprintkdbg(DBG_PIO, "data_out_phase0: " - "DMA{fifocnt=0x%02x fifostat=0x%02x} " - "SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status, - srb->total_xfer_length); - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO); - - if (!(srb->state & SRB_XFERPAD)) { - if (scsi_status & PARITYERROR) - srb->status |= PARITY_ERROR; - - /* - * KG: Right, we can't just rely on the SCSI_COUNTER, because this - * is the no of bytes it got from the DMA engine not the no it - * transferred successfully to the device. (And the difference could - * be as much as the FIFO size, I guess ...) - */ - if (!(scsi_status & SCSIXFERDONE)) { - /* - * when data transfer from DMA FIFO to SCSI FIFO - * if there was some data left in SCSI FIFO - */ - d_left_counter = - (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & - 0x1F); - if (dcb->sync_period & WIDE_SYNC) - d_left_counter <<= 1; - - dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n" - "SCSI{fifocnt=0x%02x cnt=0x%08x} " - "DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - (dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", - DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT)); - } - /* - * calculate all the residue data that not yet tranfered - * SCSI transfer counter + left in SCSI FIFO data - * - * .....TRM_S1040_SCSI_COUNTER (24bits) - * The counter always decrement by one for every SCSI byte transfer. - * .....TRM_S1040_SCSI_FIFOCNT ( 5bits) - * The counter is SCSI FIFO offset counter (in units of bytes or! words) - */ - if (srb->total_xfer_length > DC395x_LASTPIO) - d_left_counter += - DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); - - /* Is this a good idea? */ - /*clear_fifo(acb, "DOP1"); */ - /* KG: What is this supposed to be useful for? WIDE padding stuff? */ - if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC - && scsi_bufflen(srb->cmd) % 2) { - d_left_counter = 0; - dprintkl(KERN_INFO, - "data_out_phase0: Discard 1 byte (0x%02x)\n", - scsi_status); - } - /* - * KG: Oops again. Same thinko as above: The SCSI might have been - * faster than the DMA engine, so that it ran out of data. - * In that case, we have to do just nothing! - * But: Why the interrupt: No phase change. No XFERCNT_2_ZERO. Or? - */ - /* - * KG: This is nonsense: We have been WRITING data to the bus - * If the SCSI engine has no bytes left, how should the DMA engine? - */ - if (d_left_counter == 0) { - srb->total_xfer_length = 0; - } else { - /* - * if transfer not yet complete - * there were some data residue in SCSI FIFO or - * SCSI transfer counter not empty - */ - long oldxferred = - srb->total_xfer_length - d_left_counter; - const int diff = - (dcb->sync_period & WIDE_SYNC) ? 2 : 1; - sg_update_list(srb, d_left_counter); - /* KG: Most ugly hack! Apparently, this works around a chip bug */ - if ((srb->segment_x[srb->sg_index].length == - diff && scsi_sg_count(srb->cmd)) - || ((oldxferred & ~PAGE_MASK) == - (PAGE_SIZE - diff)) - ) { - dprintkl(KERN_INFO, "data_out_phase0: " - "Work around chip bug (%i)?\n", diff); - d_left_counter = - srb->total_xfer_length - diff; - sg_update_list(srb, d_left_counter); - /*srb->total_xfer_length -= diff; */ - /*srb->virt_addr += diff; */ - /*if (srb->cmd->use_sg) */ - /* srb->sg_index++; */ - } - } - } - if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) { - cleanup_after_transfer(acb, srb); - } -} - - -static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - dprintkdbg(DBG_0, "data_out_phase1: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); - clear_fifo(acb, "data_out_phase1"); - /* do prepare before transfer when data out phase */ - data_io_transfer(acb, srb, XFERDATAOUT); -} - -static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - u16 scsi_status = *pscsi_status; - - dprintkdbg(DBG_0, "data_in_phase0: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); - - /* - * KG: DataIn is much more tricky than DataOut. When the device is finished - * and switches to another phase, the SCSI engine should be finished too. - * But: There might still be bytes left in its FIFO to be fetched by the DMA - * engine and transferred to memory. - * We should wait for the FIFOs to be emptied by that (is there any way to - * enforce this?) and then stop the DMA engine, because it might think, that - * there are more bytes to follow. Yes, the device might disconnect prior to - * having all bytes transferred! - * Also we should make sure that all data from the DMA engine buffer's really - * made its way to the system memory! Some documentation on this would not - * seem to be a bad idea, actually. - */ - if (!(srb->state & SRB_XFERPAD)) { - u32 d_left_counter; - unsigned int sc, fc; - - if (scsi_status & PARITYERROR) { - dprintkl(KERN_INFO, "data_in_phase0: (0x%p) " - "Parity Error\n", srb->cmd); - srb->status |= PARITY_ERROR; - } - /* - * KG: We should wait for the DMA FIFO to be empty ... - * but: it would be better to wait first for the SCSI FIFO and then the - * the DMA FIFO to become empty? How do we know, that the device not already - * sent data to the FIFO in a MsgIn phase, eg.? - */ - if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) { -#if 0 - int ctr = 6000000; - dprintkl(KERN_DEBUG, - "DIP0: Wait for DMA FIFO to flush ...\n"); - /*DC395x_write8 (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */ - /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */ - /*DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */ - while (! - (DC395x_read16(acb, TRM_S1040_DMA_FIFOSTAT) & - 0x80) && --ctr); - if (ctr < 6000000 - 1) - dprintkl(KERN_DEBUG - "DIP0: Had to wait for DMA ...\n"); - if (!ctr) - dprintkl(KERN_ERR, - "Deadlock in DIP0 waiting for DMA FIFO empty!!\n"); - /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */ -#endif - dprintkdbg(DBG_KG, "data_in_phase0: " - "DMA{fifocnt=0x%02x fifostat=0x%02x}\n", - DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT), - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT)); - } - /* Now: Check remainig data: The SCSI counters should tell us ... */ - sc = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER); - fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); - d_left_counter = sc + ((fc & 0x1f) - << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 : - 0)); - dprintkdbg(DBG_KG, "data_in_phase0: " - "SCSI{fifocnt=0x%02x%s ctr=0x%08x} " - "DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} " - "Remain{totxfer=%i scsi_fifo+ctr=%i}\n", - fc, - (srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes", - sc, - fc, - DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(acb, TRM_S1040_DMA_CXCNT), - srb->total_xfer_length, d_left_counter); -#if DC395x_LASTPIO - /* KG: Less than or equal to 4 bytes can not be transferred via DMA, it seems. */ - if (d_left_counter - && srb->total_xfer_length <= DC395x_LASTPIO) { - size_t left_io = srb->total_xfer_length; - - /*u32 addr = (srb->segment_x[srb->sg_index].address); */ - /*sg_update_list (srb, d_left_counter); */ - dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) " - "for remaining %i bytes:", - fc & 0x1f, - (srb->dcb->sync_period & WIDE_SYNC) ? - "words" : "bytes", - srb->total_xfer_length); - if (srb->dcb->sync_period & WIDE_SYNC) - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, - CFG2_WIDEFIFO); - while (left_io) { - unsigned char *virt, *base = NULL; - unsigned long flags = 0; - size_t len = left_io; - size_t offset = srb->request_length - left_io; - - local_irq_save(flags); - /* Assumption: it's inside one page as it's at most 4 bytes and - I just assume it's on a 4-byte boundary */ - base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd), - srb->sg_count, &offset, &len); - virt = base + offset; - - left_io -= len; - - while (len) { - u8 byte; - byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - *virt++ = byte; - - if (debug_enabled(DBG_PIO)) - printk(" %02x", byte); - - d_left_counter--; - sg_subtract_one(srb); - - len--; - - fc = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT); - - if (fc == 0x40) { - left_io = 0; - break; - } - } - - WARN_ON((fc != 0x40) == !d_left_counter); - - if (fc == 0x40 && (srb->dcb->sync_period & WIDE_SYNC)) { - /* Read the last byte ... */ - if (srb->total_xfer_length > 0) { - u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - - *virt++ = byte; - srb->total_xfer_length--; - if (debug_enabled(DBG_PIO)) - printk(" %02x", byte); - } - - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); - } - - scsi_kunmap_atomic_sg(base); - local_irq_restore(flags); - } - /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */ - /*srb->total_xfer_length = 0; */ - if (debug_enabled(DBG_PIO)) - printk("\n"); - } -#endif /* DC395x_LASTPIO */ - -#if 0 - /* - * KG: This was in DATAOUT. Does it also belong here? - * Nobody seems to know what counter and fifo_cnt count exactly ... - */ - if (!(scsi_status & SCSIXFERDONE)) { - /* - * when data transfer from DMA FIFO to SCSI FIFO - * if there was some data left in SCSI FIFO - */ - d_left_counter = - (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & - 0x1F); - if (srb->dcb->sync_period & WIDE_SYNC) - d_left_counter <<= 1; - /* - * if WIDE scsi SCSI FIFOCNT unit is word !!! - * so need to *= 2 - * KG: Seems to be correct ... - */ - } -#endif - /* KG: This should not be needed any more! */ - if (d_left_counter == 0 - || (scsi_status & SCSIXFERCNT_2_ZERO)) { -#if 0 - int ctr = 6000000; - u8 TempDMAstatus; - do { - TempDMAstatus = - DC395x_read8(acb, TRM_S1040_DMA_STATUS); - } while (!(TempDMAstatus & DMAXFERCOMP) && --ctr); - if (!ctr) - dprintkl(KERN_ERR, - "Deadlock in DataInPhase0 waiting for DMA!!\n"); - srb->total_xfer_length = 0; -#endif - srb->total_xfer_length = d_left_counter; - } else { /* phase changed */ - /* - * parsing the case: - * when a transfer not yet complete - * but be disconnected by target - * if transfer not yet complete - * there were some data residue in SCSI FIFO or - * SCSI transfer counter not empty - */ - sg_update_list(srb, d_left_counter); - } - } - /* KG: The target may decide to disconnect: Empty FIFO before! */ - if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) { - cleanup_after_transfer(acb, srb); - } -} - - -static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - dprintkdbg(DBG_0, "data_in_phase1: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); - data_io_transfer(acb, srb, XFERDATAIN); -} - - -static void data_io_transfer(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb, u16 io_dir) -{ - struct DeviceCtlBlk *dcb = srb->dcb; - u8 bval; - dprintkdbg(DBG_0, - "data_io_transfer: (0x%p) <%02i-%i> %c len=%i, sg=(%i/%i)\n", - srb->cmd, srb->cmd->device->id, srb->cmd->device->lun, - ((io_dir & DMACMD_DIR) ? 'r' : 'w'), - srb->total_xfer_length, srb->sg_index, srb->sg_count); - if (srb == acb->tmp_srb) - dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n"); - if (srb->sg_index >= srb->sg_count) { - /* can't happen? out of bounds error */ - return; - } - - if (srb->total_xfer_length > DC395x_LASTPIO) { - u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS); - /* - * KG: What should we do: Use SCSI Cmd 0x90/0x92? - * Maybe, even ABORTXFER would be appropriate - */ - if (dma_status & XFERPENDING) { - dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! " - "Expect trouble!\n"); - dump_register_info(acb, dcb, srb); - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO); - } - /* clear_fifo(acb, "IO"); */ - /* - * load what physical address of Scatter/Gather list table - * want to be transfer - */ - srb->state |= SRB_DATA_XFER; - DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0); - if (scsi_sg_count(srb->cmd)) { /* with S/G */ - io_dir |= DMACMD_SG; - DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, - srb->sg_bus_addr + - sizeof(struct SGentry) * - srb->sg_index); - /* load how many bytes in the sg list table */ - DC395x_write32(acb, TRM_S1040_DMA_XCNT, - ((u32)(srb->sg_count - - srb->sg_index) << 3)); - } else { /* without S/G */ - io_dir &= ~DMACMD_SG; - DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR, - srb->segment_x[0].address); - DC395x_write32(acb, TRM_S1040_DMA_XCNT, - srb->segment_x[0].length); - } - /* load total transfer length (24bits) max value 16Mbyte */ - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, - srb->total_xfer_length); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - if (io_dir & DMACMD_DIR) { /* read */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_DMA_IN); - DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir); - } else { - DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir); - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_DMA_OUT); - } - - } -#if DC395x_LASTPIO - else if (srb->total_xfer_length > 0) { /* The last four bytes: Do PIO */ - /* - * load what physical address of Scatter/Gather list table - * want to be transfer - */ - srb->state |= SRB_DATA_XFER; - /* load total transfer length (24bits) max value 16Mbyte */ - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, - srb->total_xfer_length); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - if (io_dir & DMACMD_DIR) { /* read */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_FIFO_IN); - } else { /* write */ - int ln = srb->total_xfer_length; - size_t left_io = srb->total_xfer_length; - - if (srb->dcb->sync_period & WIDE_SYNC) - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, - CFG2_WIDEFIFO); - - while (left_io) { - unsigned char *virt, *base = NULL; - unsigned long flags = 0; - size_t len = left_io; - size_t offset = srb->request_length - left_io; - - local_irq_save(flags); - /* Again, max 4 bytes */ - base = scsi_kmap_atomic_sg(scsi_sglist(srb->cmd), - srb->sg_count, &offset, &len); - virt = base + offset; - - left_io -= len; - - while (len--) { - if (debug_enabled(DBG_PIO)) - printk(" %02x", *virt); - - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *virt++); - - sg_subtract_one(srb); - } - - scsi_kunmap_atomic_sg(base); - local_irq_restore(flags); - } - if (srb->dcb->sync_period & WIDE_SYNC) { - if (ln % 2) { - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0); - if (debug_enabled(DBG_PIO)) - printk(" |00"); - } - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); - } - /*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */ - if (debug_enabled(DBG_PIO)) - printk("\n"); - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, - SCMD_FIFO_OUT); - } - } -#endif /* DC395x_LASTPIO */ - else { /* xfer pad */ - u8 data = 0, data2 = 0; - if (srb->sg_count) { - srb->adapter_status = H_OVER_UNDER_RUN; - srb->status |= OVER_RUN; - } - /* - * KG: despite the fact that we are using 16 bits I/O ops - * the SCSI FIFO is only 8 bits according to the docs - * (we can set bit 1 in 0x8f to serialize FIFO access ...) - */ - if (dcb->sync_period & WIDE_SYNC) { - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2); - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, - CFG2_WIDEFIFO); - if (io_dir & DMACMD_DIR) { - data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - } else { - /* Danger, Robinson: If you find KGs - * scattered over the wide disk, the driver - * or chip is to blame :-( */ - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G'); - } - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0); - } else { - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); - /* Danger, Robinson: If you find a collection of Ks on your disk - * something broke :-( */ - if (io_dir & DMACMD_DIR) - data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - else - DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K'); - } - srb->state |= SRB_XFERPAD; - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* SCSI command */ - bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT; - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval); - } -} - - -static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - dprintkdbg(DBG_0, "status_phase0: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); - srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); /* get message */ - srb->state = SRB_COMPLETED; - *pscsi_status = PH_BUS_FREE; /*.. initial phase */ - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); -} - - -static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - dprintkdbg(DBG_0, "status_phase1: (0x%p) <%02i-%i>\n", - srb->cmd, srb->cmd->device->id, srb->cmd->device->lun); - srb->state = SRB_STATUS; - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP); -} - - -/* Check if the message is complete */ -static inline u8 msgin_completed(u8 * msgbuf, u32 len) -{ - if (*msgbuf == EXTENDED_MESSAGE) { - if (len < 2) - return 0; - if (len < msgbuf[1] + 2) - return 0; - } else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) /* two byte messages */ - if (len < 2) - return 0; - return 1; -} - -/* reject_msg */ -static inline void msgin_reject(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) -{ - srb->msgout_buf[0] = MESSAGE_REJECT; - srb->msg_count = 1; - DC395x_ENABLE_MSGOUT; - srb->state &= ~SRB_MSGIN; - srb->state |= SRB_MSGOUT; - dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n", - srb->msgin_buf[0], - srb->dcb->target_id, srb->dcb->target_lun); -} - - -static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb, u8 tag) -{ - struct ScsiReqBlk *srb = NULL; - struct ScsiReqBlk *i; - dprintkdbg(DBG_0, "msgin_qtag: (0x%p) tag=%i srb=%p\n", - srb->cmd, tag, srb); - - if (!(dcb->tag_mask & (1 << tag))) - dprintkl(KERN_DEBUG, - "msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n", - dcb->tag_mask, tag); - - if (list_empty(&dcb->srb_going_list)) - goto mingx0; - list_for_each_entry(i, &dcb->srb_going_list, list) { - if (i->tag_number == tag) { - srb = i; - break; - } - } - if (!srb) - goto mingx0; - - dprintkdbg(DBG_0, "msgin_qtag: (0x%p) <%02i-%i>\n", - srb->cmd, srb->dcb->target_id, srb->dcb->target_lun); - if (dcb->flag & ABORT_DEV_) { - /*srb->state = SRB_ABORT_SENT; */ - enable_msgout_abort(acb, srb); - } - - if (!(srb->state & SRB_DISCONNECT)) - goto mingx0; - - memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len); - srb->state |= dcb->active_srb->state; - srb->state |= SRB_DATA_XFER; - dcb->active_srb = srb; - /* How can we make the DORS happy? */ - return srb; - - mingx0: - srb = acb->tmp_srb; - srb->state = SRB_UNEXPECT_RESEL; - dcb->active_srb = srb; - srb->msgout_buf[0] = MSG_ABORT_TAG; - srb->msg_count = 1; - DC395x_ENABLE_MSGOUT; - dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag); - return srb; -} - - -static inline void reprogram_regs(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb) -{ - DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); - DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); - DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); - set_xfer_rate(acb, dcb); -} - - -/* set async transfer mode */ -static void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) -{ - struct DeviceCtlBlk *dcb = srb->dcb; - dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n", - dcb->target_id, dcb->target_lun); - - dcb->sync_mode &= ~(SYNC_NEGO_ENABLE); - dcb->sync_mode |= SYNC_NEGO_DONE; - /*dcb->sync_period &= 0; */ - dcb->sync_offset = 0; - dcb->min_nego_period = 200 >> 2; /* 200ns <=> 5 MHz */ - srb->state &= ~SRB_DO_SYNC_NEGO; - reprogram_regs(acb, dcb); - if ((dcb->sync_mode & WIDE_NEGO_ENABLE) - && !(dcb->sync_mode & WIDE_NEGO_DONE)) { - build_wdtr(acb, dcb, srb); - DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n"); - } -} - - -/* set sync transfer mode */ -static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) -{ - struct DeviceCtlBlk *dcb = srb->dcb; - u8 bval; - int fact; - dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins " - "(%02i.%01i MHz) Offset %i\n", - dcb->target_id, srb->msgin_buf[3] << 2, - (250 / srb->msgin_buf[3]), - ((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3], - srb->msgin_buf[4]); - - if (srb->msgin_buf[4] > 15) - srb->msgin_buf[4] = 15; - if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) - dcb->sync_offset = 0; - else if (dcb->sync_offset == 0) - dcb->sync_offset = srb->msgin_buf[4]; - if (srb->msgin_buf[4] > dcb->sync_offset) - srb->msgin_buf[4] = dcb->sync_offset; - else - dcb->sync_offset = srb->msgin_buf[4]; - bval = 0; - while (bval < 7 && (srb->msgin_buf[3] > clock_period[bval] - || dcb->min_nego_period > - clock_period[bval])) - bval++; - if (srb->msgin_buf[3] < clock_period[bval]) - dprintkl(KERN_INFO, - "msgin_set_sync: Increase sync nego period to %ins\n", - clock_period[bval] << 2); - srb->msgin_buf[3] = clock_period[bval]; - dcb->sync_period &= 0xf0; - dcb->sync_period |= ALT_SYNC | bval; - dcb->min_nego_period = srb->msgin_buf[3]; - - if (dcb->sync_period & WIDE_SYNC) - fact = 500; - else - fact = 250; - - dprintkl(KERN_INFO, - "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", - dcb->target_id, (fact == 500) ? "Wide16" : "", - dcb->min_nego_period << 2, dcb->sync_offset, - (fact / dcb->min_nego_period), - ((fact % dcb->min_nego_period) * 10 + - dcb->min_nego_period / 2) / dcb->min_nego_period); - - if (!(srb->state & SRB_DO_SYNC_NEGO)) { - /* Reply with corrected SDTR Message */ - dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n", - srb->msgin_buf[3] << 2, srb->msgin_buf[4]); - - memcpy(srb->msgout_buf, srb->msgin_buf, 5); - srb->msg_count = 5; - DC395x_ENABLE_MSGOUT; - dcb->sync_mode |= SYNC_NEGO_DONE; - } else { - if ((dcb->sync_mode & WIDE_NEGO_ENABLE) - && !(dcb->sync_mode & WIDE_NEGO_DONE)) { - build_wdtr(acb, dcb, srb); - DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n"); - } - } - srb->state &= ~SRB_DO_SYNC_NEGO; - dcb->sync_mode |= SYNC_NEGO_DONE | SYNC_NEGO_ENABLE; - - reprogram_regs(acb, dcb); -} - - -static inline void msgin_set_nowide(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) -{ - struct DeviceCtlBlk *dcb = srb->dcb; - dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id); - - dcb->sync_period &= ~WIDE_SYNC; - dcb->sync_mode &= ~(WIDE_NEGO_ENABLE); - dcb->sync_mode |= WIDE_NEGO_DONE; - srb->state &= ~SRB_DO_WIDE_NEGO; - reprogram_regs(acb, dcb); - if ((dcb->sync_mode & SYNC_NEGO_ENABLE) - && !(dcb->sync_mode & SYNC_NEGO_DONE)) { - build_sdtr(acb, dcb, srb); - DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n"); - } -} - -static void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) -{ - struct DeviceCtlBlk *dcb = srb->dcb; - u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO - && acb->config & HCC_WIDE_CARD) ? 1 : 0; - dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id); - - if (srb->msgin_buf[3] > wide) - srb->msgin_buf[3] = wide; - /* Completed */ - if (!(srb->state & SRB_DO_WIDE_NEGO)) { - dprintkl(KERN_DEBUG, - "msgin_set_wide: Wide nego initiated <%02i>\n", - dcb->target_id); - memcpy(srb->msgout_buf, srb->msgin_buf, 4); - srb->msg_count = 4; - srb->state |= SRB_DO_WIDE_NEGO; - DC395x_ENABLE_MSGOUT; - } - - dcb->sync_mode |= (WIDE_NEGO_ENABLE | WIDE_NEGO_DONE); - if (srb->msgin_buf[3] > 0) - dcb->sync_period |= WIDE_SYNC; - else - dcb->sync_period &= ~WIDE_SYNC; - srb->state &= ~SRB_DO_WIDE_NEGO; - /*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */ - dprintkdbg(DBG_1, - "msgin_set_wide: Wide (%i bit) negotiated <%02i>\n", - (8 << srb->msgin_buf[3]), dcb->target_id); - reprogram_regs(acb, dcb); - if ((dcb->sync_mode & SYNC_NEGO_ENABLE) - && !(dcb->sync_mode & SYNC_NEGO_DONE)) { - build_sdtr(acb, dcb, srb); - DC395x_ENABLE_MSGOUT; - dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n"); - } -} - - -/* - * extended message codes: - * - * code description - * - * 02h Reserved - * 00h MODIFY DATA POINTER - * 01h SYNCHRONOUS DATA TRANSFER REQUEST - * 03h WIDE DATA TRANSFER REQUEST - * 04h - 7Fh Reserved - * 80h - FFh Vendor specific - */ -static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - struct DeviceCtlBlk *dcb = acb->active_dcb; - dprintkdbg(DBG_0, "msgin_phase0: (0x%p)\n", srb->cmd); - - srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO); - if (msgin_completed(srb->msgin_buf, acb->msg_len)) { - /* Now eval the msg */ - switch (srb->msgin_buf[0]) { - case DISCONNECT: - srb->state = SRB_DISCONNECT; - break; - - case SIMPLE_QUEUE_TAG: - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - srb = - msgin_qtag(acb, dcb, - srb->msgin_buf[1]); - break; - - case MESSAGE_REJECT: - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, - DO_CLRATN | DO_DATALATCH); - /* A sync nego message was rejected ! */ - if (srb->state & SRB_DO_SYNC_NEGO) { - msgin_set_async(acb, srb); - break; - } - /* A wide nego message was rejected ! */ - if (srb->state & SRB_DO_WIDE_NEGO) { - msgin_set_nowide(acb, srb); - break; - } - enable_msgout_abort(acb, srb); - /*srb->state |= SRB_ABORT_SENT */ - break; - - case EXTENDED_MESSAGE: - /* SDTR */ - if (srb->msgin_buf[1] == 3 - && srb->msgin_buf[2] == EXTENDED_SDTR) { - msgin_set_sync(acb, srb); - break; - } - /* WDTR */ - if (srb->msgin_buf[1] == 2 - && srb->msgin_buf[2] == EXTENDED_WDTR - && srb->msgin_buf[3] <= 2) { /* sanity check ... */ - msgin_set_wide(acb, srb); - break; - } - msgin_reject(acb, srb); - break; - - case MSG_IGNOREWIDE: - /* Discard wide residual */ - dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n"); - break; - - case COMMAND_COMPLETE: - /* nothing has to be done */ - break; - - case SAVE_POINTERS: - /* - * SAVE POINTER may be ignored as we have the struct - * ScsiReqBlk* associated with the scsi command. - */ - dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " - "SAVE POINTER rem=%i Ignore\n", - srb->cmd, srb->total_xfer_length); - break; - - case RESTORE_POINTERS: - dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n"); - break; - - case ABORT: - dprintkdbg(DBG_0, "msgin_phase0: (0x%p) " - "<%02i-%i> ABORT msg\n", - srb->cmd, dcb->target_id, - dcb->target_lun); - dcb->flag |= ABORT_DEV_; - enable_msgout_abort(acb, srb); - break; - - default: - /* reject unknown messages */ - if (srb->msgin_buf[0] & IDENTIFY_BASE) { - dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n"); - srb->msg_count = 1; - srb->msgout_buf[0] = dcb->identify_msg; - DC395x_ENABLE_MSGOUT; - srb->state |= SRB_MSGOUT; - /*break; */ - } - msgin_reject(acb, srb); - } - - /* Clear counter and MsgIn state */ - srb->state &= ~SRB_MSGIN; - acb->msg_len = 0; - } - *pscsi_status = PH_BUS_FREE; - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important ... you know! */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); -} - - -static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ - dprintkdbg(DBG_0, "msgin_phase1: (0x%p)\n", srb->cmd); - clear_fifo(acb, "msgin_phase1"); - DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1); - if (!(srb->state & SRB_MSGIN)) { - srb->state &= ~SRB_DISCONNECT; - srb->state |= SRB_MSGIN; - } - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* SCSI command */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN); -} - - -static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ -} - - -static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, - u16 *pscsi_status) -{ -} - - -static void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb) -{ - struct DeviceCtlBlk *i; - - /* set all lun device's period, offset */ - if (dcb->identify_msg & 0x07) - return; - - if (acb->scan_devices) { - current_sync_offset = dcb->sync_offset; - return; - } - - list_for_each_entry(i, &acb->dcb_list, list) - if (i->target_id == dcb->target_id) { - i->sync_period = dcb->sync_period; - i->sync_offset = dcb->sync_offset; - i->sync_mode = dcb->sync_mode; - i->min_nego_period = dcb->min_nego_period; - } -} - - -static void disconnect(struct AdapterCtlBlk *acb) -{ - struct DeviceCtlBlk *dcb = acb->active_dcb; - struct ScsiReqBlk *srb; - - if (!dcb) { - dprintkl(KERN_ERR, "disconnect: No such device\n"); - udelay(500); - /* Suspend queue for a while */ - acb->scsi_host->last_reset = - jiffies + HZ / 2 + - HZ * acb->eeprom.delay_time; - clear_fifo(acb, "disconnectEx"); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); - return; - } - srb = dcb->active_srb; - acb->active_dcb = NULL; - dprintkdbg(DBG_0, "disconnect: (0x%p)\n", srb->cmd); - - srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - clear_fifo(acb, "disconnect"); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); - if (srb->state & SRB_UNEXPECT_RESEL) { - dprintkl(KERN_ERR, - "disconnect: Unexpected reselection <%02i-%i>\n", - dcb->target_id, dcb->target_lun); - srb->state = 0; - waiting_process_next(acb); - } else if (srb->state & SRB_ABORT_SENT) { - dcb->flag &= ~ABORT_DEV_; - acb->scsi_host->last_reset = jiffies + HZ / 2 + 1; - dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n"); - doing_srb_done(acb, DID_ABORT, srb->cmd, 1); - waiting_process_next(acb); - } else { - if ((srb->state & (SRB_START_ + SRB_MSGOUT)) - || !(srb-> - state & (SRB_DISCONNECT + SRB_COMPLETED))) { - /* - * Selection time out - * SRB_START_ || SRB_MSGOUT || (!SRB_DISCONNECT && !SRB_COMPLETED) - */ - /* Unexp. Disc / Sel Timeout */ - if (srb->state != SRB_START_ - && srb->state != SRB_MSGOUT) { - srb->state = SRB_READY; - dprintkl(KERN_DEBUG, - "disconnect: (0x%p) Unexpected\n", - srb->cmd); - srb->target_status = SCSI_STAT_SEL_TIMEOUT; - goto disc1; - } else { - /* Normal selection timeout */ - dprintkdbg(DBG_KG, "disconnect: (0x%p) " - "<%02i-%i> SelTO\n", srb->cmd, - dcb->target_id, dcb->target_lun); - if (srb->retry_count++ > DC395x_MAX_RETRIES - || acb->scan_devices) { - srb->target_status = - SCSI_STAT_SEL_TIMEOUT; - goto disc1; - } - free_tag(dcb, srb); - srb_going_to_waiting_move(dcb, srb); - dprintkdbg(DBG_KG, - "disconnect: (0x%p) Retry\n", - srb->cmd); - waiting_set_timer(acb, HZ / 20); - } - } else if (srb->state & SRB_DISCONNECT) { - u8 bval = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL); - /* - * SRB_DISCONNECT (This is what we expect!) - */ - if (bval & 0x40) { - dprintkdbg(DBG_0, "disconnect: SCSI bus stat " - " 0x%02x: ACK set! Other controllers?\n", - bval); - /* It could come from another initiator, therefore don't do much ! */ - } else - waiting_process_next(acb); - } else if (srb->state & SRB_COMPLETED) { - disc1: - /* - ** SRB_COMPLETED - */ - free_tag(dcb, srb); - dcb->active_srb = NULL; - srb->state = SRB_FREE; - srb_done(acb, dcb, srb); - } - } -} - - -static void reselect(struct AdapterCtlBlk *acb) -{ - struct DeviceCtlBlk *dcb = acb->active_dcb; - struct ScsiReqBlk *srb = NULL; - u16 rsel_tar_lun_id; - u8 id, lun; - u8 arblostflag = 0; - dprintkdbg(DBG_0, "reselect: acb=%p\n", acb); - - clear_fifo(acb, "reselect"); - /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ - /* Read Reselected Target ID and LUN */ - rsel_tar_lun_id = DC395x_read16(acb, TRM_S1040_SCSI_TARGETID); - if (dcb) { /* Arbitration lost but Reselection win */ - srb = dcb->active_srb; - if (!srb) { - dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, " - "but active_srb == NULL\n"); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - return; - } - /* Why the if ? */ - if (!acb->scan_devices) { - dprintkdbg(DBG_KG, "reselect: (0x%p) <%02i-%i> " - "Arb lost but Resel win rsel=%i stat=0x%04x\n", - srb->cmd, dcb->target_id, - dcb->target_lun, rsel_tar_lun_id, - DC395x_read16(acb, TRM_S1040_SCSI_STATUS)); - arblostflag = 1; - /*srb->state |= SRB_DISCONNECT; */ - - srb->state = SRB_READY; - free_tag(dcb, srb); - srb_going_to_waiting_move(dcb, srb); - waiting_set_timer(acb, HZ / 20); - - /* return; */ - } - } - /* Read Reselected Target Id and LUN */ - if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8))) - dprintkl(KERN_DEBUG, "reselect: Expects identify msg. " - "Got %i!\n", rsel_tar_lun_id); - id = rsel_tar_lun_id & 0xff; - lun = (rsel_tar_lun_id >> 8) & 7; - dcb = find_dcb(acb, id, lun); - if (!dcb) { - dprintkl(KERN_ERR, "reselect: From non existent device " - "<%02i-%i>\n", id, lun); - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - return; - } - acb->active_dcb = dcb; - - if (!(dcb->dev_mode & NTC_DO_DISCONNECT)) - dprintkl(KERN_DEBUG, "reselect: in spite of forbidden " - "disconnection? <%02i-%i>\n", - dcb->target_id, dcb->target_lun); - - if (dcb->sync_mode & EN_TAG_QUEUEING /*&& !arblostflag */) { - srb = acb->tmp_srb; - dcb->active_srb = srb; - } else { - /* There can be only one! */ - srb = dcb->active_srb; - if (!srb || !(srb->state & SRB_DISCONNECT)) { - /* - * abort command - */ - dprintkl(KERN_DEBUG, - "reselect: w/o disconnected cmds <%02i-%i>\n", - dcb->target_id, dcb->target_lun); - srb = acb->tmp_srb; - srb->state = SRB_UNEXPECT_RESEL; - dcb->active_srb = srb; - enable_msgout_abort(acb, srb); - } else { - if (dcb->flag & ABORT_DEV_) { - /*srb->state = SRB_ABORT_SENT; */ - enable_msgout_abort(acb, srb); - } else - srb->state = SRB_DATA_XFER; - - } - } - srb->scsi_phase = PH_BUS_FREE; /* initial phase */ - - /* Program HA ID, target ID, period and offset */ - dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id); - DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); /* host ID */ - DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id); /* target ID */ - DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset); /* offset */ - DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period); /* sync period, wide */ - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ - /* SCSI command */ - DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT); -} - - -static inline u8 tagq_blacklist(char *name) -{ -#ifndef DC395x_NO_TAGQ -#if 0 - u8 i; - for (i = 0; i < BADDEVCNT; i++) - if (memcmp(name, DC395x_baddevname1[i], 28) == 0) - return 1; -#endif - return 0; -#else - return 1; -#endif -} - - -static void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr) -{ - /* Check for SCSI format (ANSI and Response data format) */ - if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) { - if ((ptr->Flags & SCSI_INQ_CMDQUEUE) - && (dcb->dev_mode & NTC_DO_TAG_QUEUEING) && - /*(dcb->dev_mode & NTC_DO_DISCONNECT) */ - /* ((dcb->dev_type == TYPE_DISK) - || (dcb->dev_type == TYPE_MOD)) && */ - !tagq_blacklist(((char *)ptr) + 8)) { - if (dcb->max_command == 1) - dcb->max_command = - dcb->acb->tag_max_num; - dcb->sync_mode |= EN_TAG_QUEUEING; - /*dcb->tag_mask = 0; */ - } else - dcb->max_command = 1; - } -} - - -static void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiInqData *ptr) -{ - u8 bval1 = ptr->DevType & SCSI_DEVTYPE; - dcb->dev_type = bval1; - /* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */ - disc_tagq_set(dcb, ptr); -} - - -/* unmap mapped pci regions from SRB */ -static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb) -{ - struct scsi_cmnd *cmd = srb->cmd; - enum dma_data_direction dir = cmd->sc_data_direction; - - if (scsi_sg_count(cmd) && dir != PCI_DMA_NONE) { - /* unmap DC395x SG list */ - dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n", - srb->sg_bus_addr, SEGMENTX_LEN); - pci_unmap_single(acb->dev, srb->sg_bus_addr, - SEGMENTX_LEN, - PCI_DMA_TODEVICE); - dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n", - scsi_sg_count(cmd), scsi_bufflen(cmd)); - /* unmap the sg segments */ - scsi_dma_unmap(cmd); - } -} - - -/* unmap mapped pci sense buffer from SRB */ -static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb, - struct ScsiReqBlk *srb) -{ - if (!(srb->flag & AUTO_REQSENSE)) - return; - /* Unmap sense buffer */ - dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n", - srb->segment_x[0].address); - pci_unmap_single(acb->dev, srb->segment_x[0].address, - srb->segment_x[0].length, PCI_DMA_FROMDEVICE); - /* Restore SG stuff */ - srb->total_xfer_length = srb->xferred; - srb->segment_x[0].address = - srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address; - srb->segment_x[0].length = - srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length; -} - - -/* - * Complete execution of a SCSI command - * Signal completion to the generic SCSI driver - */ -static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - u8 tempcnt, status; - struct scsi_cmnd *cmd = srb->cmd; - enum dma_data_direction dir = cmd->sc_data_direction; - int ckc_only = 1; - - dprintkdbg(DBG_1, "srb_done: (0x%p) <%02i-%i>\n", srb->cmd, - srb->cmd->device->id, srb->cmd->device->lun); - dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p\n", - srb, scsi_sg_count(cmd), srb->sg_index, srb->sg_count, - scsi_sgtalbe(cmd)); - status = srb->target_status; - if (srb->flag & AUTO_REQSENSE) { - dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n"); - pci_unmap_srb_sense(acb, srb); - /* - ** target status.......................... - */ - srb->flag &= ~AUTO_REQSENSE; - srb->adapter_status = 0; - srb->target_status = CHECK_CONDITION << 1; - if (debug_enabled(DBG_1)) { - switch (cmd->sense_buffer[2] & 0x0f) { - case NOT_READY: - dprintkl(KERN_DEBUG, - "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - case UNIT_ATTENTION: - dprintkl(KERN_DEBUG, - "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - case ILLEGAL_REQUEST: - dprintkl(KERN_DEBUG, - "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - case MEDIUM_ERROR: - dprintkl(KERN_DEBUG, - "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - case HARDWARE_ERROR: - dprintkl(KERN_DEBUG, - "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ", - cmd->cmnd[0], dcb->target_id, - dcb->target_lun, status, acb->scan_devices); - break; - } - if (cmd->sense_buffer[7] >= 6) - printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x " - "(0x%08x 0x%08x)\n", - cmd->sense_buffer[2], cmd->sense_buffer[12], - cmd->sense_buffer[13], - *((unsigned int *)(cmd->sense_buffer + 3)), - *((unsigned int *)(cmd->sense_buffer + 8))); - else - printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n", - cmd->sense_buffer[2], - *((unsigned int *)(cmd->sense_buffer + 3))); - } - - if (status == (CHECK_CONDITION << 1)) { - cmd->result = DID_BAD_TARGET << 16; - goto ckc_e; - } - dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n"); - - if (srb->total_xfer_length - && srb->total_xfer_length >= cmd->underflow) - cmd->result = - MK_RES_LNX(DRIVER_SENSE, DID_OK, - srb->end_message, CHECK_CONDITION); - /*SET_RES_DID(cmd->result,DID_OK) */ - else - cmd->result = - MK_RES_LNX(DRIVER_SENSE, DID_OK, - srb->end_message, CHECK_CONDITION); - - goto ckc_e; - } - -/*************************************************************/ - if (status) { - /* - * target status.......................... - */ - if (status_byte(status) == CHECK_CONDITION) { - request_sense(acb, dcb, srb); - return; - } else if (status_byte(status) == QUEUE_FULL) { - tempcnt = (u8)list_size(&dcb->srb_going_list); - dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n", - dcb->target_id, dcb->target_lun, tempcnt); - if (tempcnt > 1) - tempcnt--; - dcb->max_command = tempcnt; - free_tag(dcb, srb); - srb_going_to_waiting_move(dcb, srb); - waiting_set_timer(acb, HZ / 20); - srb->adapter_status = 0; - srb->target_status = 0; - return; - } else if (status == SCSI_STAT_SEL_TIMEOUT) { - srb->adapter_status = H_SEL_TIMEOUT; - srb->target_status = 0; - cmd->result = DID_NO_CONNECT << 16; - } else { - srb->adapter_status = 0; - SET_RES_DID(cmd->result, DID_ERROR); - SET_RES_MSG(cmd->result, srb->end_message); - SET_RES_TARGET(cmd->result, status); - - } - } else { - /* - ** process initiator status.......................... - */ - status = srb->adapter_status; - if (status & H_OVER_UNDER_RUN) { - srb->target_status = 0; - SET_RES_DID(cmd->result, DID_OK); - SET_RES_MSG(cmd->result, srb->end_message); - } else if (srb->status & PARITY_ERROR) { - SET_RES_DID(cmd->result, DID_PARITY); - SET_RES_MSG(cmd->result, srb->end_message); - } else { /* No error */ - - srb->adapter_status = 0; - srb->target_status = 0; - SET_RES_DID(cmd->result, DID_OK); - } - } - - if (dir != PCI_DMA_NONE && scsi_sg_count(cmd)) - pci_dma_sync_sg_for_cpu(acb->dev, scsi_sglist(cmd), - scsi_sg_count(cmd), dir); - - ckc_only = 0; -/* Check Error Conditions */ - ckc_e: - - if (cmd->cmnd[0] == INQUIRY) { - unsigned char *base = NULL; - struct ScsiInqData *ptr; - unsigned long flags = 0; - struct scatterlist* sg = scsi_sglist(cmd); - size_t offset = 0, len = sizeof(struct ScsiInqData); - - local_irq_save(flags); - base = scsi_kmap_atomic_sg(sg, scsi_sg_count(cmd), &offset, &len); - ptr = (struct ScsiInqData *)(base + offset); - - if (!ckc_only && (cmd->result & RES_DID) == 0 - && cmd->cmnd[2] == 0 && scsi_bufflen(cmd) >= 8 - && dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2) - dcb->inquiry7 = ptr->Flags; - - /*if( srb->cmd->cmnd[0] == INQUIRY && */ - /* (host_byte(cmd->result) == DID_OK || status_byte(cmd->result) & CHECK_CONDITION) ) */ - if ((cmd->result == (DID_OK << 16) - || status_byte(cmd->result) & - CHECK_CONDITION)) { - if (!dcb->init_tcq_flag) { - add_dev(acb, dcb, ptr); - dcb->init_tcq_flag = 1; - } - } - - scsi_kunmap_atomic_sg(base); - local_irq_restore(flags); - } - - /* Here is the info for Doug Gilbert's sg3 ... */ - scsi_set_resid(cmd, srb->total_xfer_length); - /* This may be interpreted by sb. or not ... */ - cmd->SCp.this_residual = srb->total_xfer_length; - cmd->SCp.buffers_residual = 0; - if (debug_enabled(DBG_KG)) { - if (srb->total_xfer_length) - dprintkdbg(DBG_KG, "srb_done: (0x%p) <%02i-%i> " - "cmnd=0x%02x Missed %i bytes\n", - cmd, cmd->device->id, cmd->device->lun, - cmd->cmnd[0], srb->total_xfer_length); - } - - srb_going_remove(dcb, srb); - /* Add to free list */ - if (srb == acb->tmp_srb) - dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n"); - else { - dprintkdbg(DBG_0, "srb_done: (0x%p) done result=0x%08x\n", - cmd, cmd->result); - srb_free_insert(acb, srb); - } - pci_unmap_srb(acb, srb); - - cmd->scsi_done(cmd); - waiting_process_next(acb); -} - - -/* abort all cmds in our queues */ -static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag, - struct scsi_cmnd *cmd, u8 force) -{ - struct DeviceCtlBlk *dcb; - dprintkl(KERN_INFO, "doing_srb_done: pids "); - - list_for_each_entry(dcb, &acb->dcb_list, list) { - struct ScsiReqBlk *srb; - struct ScsiReqBlk *tmp; - struct scsi_cmnd *p; - - list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) { - enum dma_data_direction dir; - int result; - - p = srb->cmd; - dir = p->sc_data_direction; - result = MK_RES(0, did_flag, 0, 0); - printk("G:%p(%02i-%i) ", p, - p->device->id, p->device->lun); - srb_going_remove(dcb, srb); - free_tag(dcb, srb); - srb_free_insert(acb, srb); - p->result = result; - pci_unmap_srb_sense(acb, srb); - pci_unmap_srb(acb, srb); - if (force) { - /* For new EH, we normally don't need to give commands back, - * as they all complete or all time out */ - p->scsi_done(p); - } - } - if (!list_empty(&dcb->srb_going_list)) - dprintkl(KERN_DEBUG, - "How could the ML send cmnds to the Going queue? <%02i-%i>\n", - dcb->target_id, dcb->target_lun); - if (dcb->tag_mask) - dprintkl(KERN_DEBUG, - "tag_mask for <%02i-%i> should be empty, is %08x!\n", - dcb->target_id, dcb->target_lun, - dcb->tag_mask); - - /* Waiting queue */ - list_for_each_entry_safe(srb, tmp, &dcb->srb_waiting_list, list) { - int result; - p = srb->cmd; - - result = MK_RES(0, did_flag, 0, 0); - printk("W:%p<%02i-%i>", p, p->device->id, - p->device->lun); - srb_waiting_remove(dcb, srb); - srb_free_insert(acb, srb); - p->result = result; - pci_unmap_srb_sense(acb, srb); - pci_unmap_srb(acb, srb); - if (force) { - /* For new EH, we normally don't need to give commands back, - * as they all complete or all time out */ - cmd->scsi_done(cmd); - } - } - if (!list_empty(&dcb->srb_waiting_list)) - dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n", - list_size(&dcb->srb_waiting_list), dcb->target_id, - dcb->target_lun); - dcb->flag &= ~ABORT_DEV_; - } - printk("\n"); -} - - -static void reset_scsi_bus(struct AdapterCtlBlk *acb) -{ - dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb); - acb->acb_flag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */ - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); - - while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET)) - /* nothing */; -} - - -static void set_basic_config(struct AdapterCtlBlk *acb) -{ - u8 bval; - u16 wval; - DC395x_write8(acb, TRM_S1040_SCSI_TIMEOUT, acb->sel_timeout); - if (acb->config & HCC_PARITY) - bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK; - else - bval = PHASELATCH | INITIATOR | BLOCKRST; - - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG0, bval); - - /* program configuration 1: Act_Neg (+ Act_Neg_Enh? + Fast_Filter? + DataDis?) */ - DC395x_write8(acb, TRM_S1040_SCSI_CONFIG1, 0x03); /* was 0x13: default */ - /* program Host ID */ - DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id); - /* set ansynchronous transfer */ - DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, 0x00); - /* Turn LED control off */ - wval = DC395x_read16(acb, TRM_S1040_GEN_CONTROL) & 0x7F; - DC395x_write16(acb, TRM_S1040_GEN_CONTROL, wval); - /* DMA config */ - wval = DC395x_read16(acb, TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL; - wval |= - DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ; - DC395x_write16(acb, TRM_S1040_DMA_CONFIG, wval); - /* Clear pending interrupt status */ - DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); - /* Enable SCSI interrupt */ - DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x7F); - DC395x_write8(acb, TRM_S1040_DMA_INTEN, EN_SCSIINTR | EN_DMAXFERERROR - /*| EN_DMAXFERABORT | EN_DMAXFERCOMP | EN_FORCEDMACOMP */ - ); -} - - -static void scsi_reset_detect(struct AdapterCtlBlk *acb) -{ - dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb); - /* delay half a second */ - if (timer_pending(&acb->waiting_timer)) - del_timer(&acb->waiting_timer); - - DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE); - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE); - /*DC395x_write8(acb, TRM_S1040_DMA_CONTROL,STOPDMAXFER); */ - udelay(500); - /* Maybe we locked up the bus? Then lets wait even longer ... */ - acb->scsi_host->last_reset = - jiffies + 5 * HZ / 2 + - HZ * acb->eeprom.delay_time; - - clear_fifo(acb, "scsi_reset_detect"); - set_basic_config(acb); - /*1.25 */ - /*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); */ - - if (acb->acb_flag & RESET_DEV) { /* RESET_DETECT, RESET_DONE, RESET_DEV */ - acb->acb_flag |= RESET_DONE; - } else { - acb->acb_flag |= RESET_DETECT; - reset_dev_param(acb); - doing_srb_done(acb, DID_RESET, NULL, 1); - /*DC395x_RecoverSRB( acb ); */ - acb->active_dcb = NULL; - acb->acb_flag = 0; - waiting_process_next(acb); - } -} - - -static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb, - struct ScsiReqBlk *srb) -{ - struct scsi_cmnd *cmd = srb->cmd; - dprintkdbg(DBG_1, "request_sense: (0x%p) <%02i-%i>\n", - cmd, cmd->device->id, cmd->device->lun); - - srb->flag |= AUTO_REQSENSE; - srb->adapter_status = 0; - srb->target_status = 0; - - /* KG: Can this prevent crap sense data ? */ - memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - - /* Save some data */ - srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address = - srb->segment_x[0].address; - srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length = - srb->segment_x[0].length; - srb->xferred = srb->total_xfer_length; - /* srb->segment_x : a one entry of S/G list table */ - srb->total_xfer_length = SCSI_SENSE_BUFFERSIZE; - srb->segment_x[0].length = SCSI_SENSE_BUFFERSIZE; - /* Map sense buffer */ - srb->segment_x[0].address = - pci_map_single(acb->dev, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); - dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n", - cmd->sense_buffer, srb->segment_x[0].address, - SCSI_SENSE_BUFFERSIZE); - srb->sg_count = 1; - srb->sg_index = 0; - - if (start_scsi(acb, dcb, srb)) { /* Should only happen, if sb. else grabs the bus */ - dprintkl(KERN_DEBUG, - "request_sense: (0x%p) failed <%02i-%i>\n", - srb->cmd, dcb->target_id, dcb->target_lun); - srb_going_to_waiting_move(dcb, srb); - waiting_set_timer(acb, HZ / 100); - } -} - - -/** - * device_alloc - Allocate a new device instance. This create the - * devices instance and sets up all the data items. The adapter - * instance is required to obtain confiuration information for this - * device. This does *not* add this device to the adapters device - * list. - * - * @acb: The adapter to obtain configuration information from. - * @target: The target for the new device. - * @lun: The lun for the new device. - * - * Return the new device if successful or NULL on failure. - **/ -static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb, - u8 target, u8 lun) -{ - struct NvRamType *eeprom = &acb->eeprom; - u8 period_index = eeprom->target[target].period & 0x07; - struct DeviceCtlBlk *dcb; - - dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); - dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun); - if (!dcb) - return NULL; - dcb->acb = NULL; - INIT_LIST_HEAD(&dcb->srb_going_list); - INIT_LIST_HEAD(&dcb->srb_waiting_list); - dcb->active_srb = NULL; - dcb->tag_mask = 0; - dcb->max_command = 1; - dcb->target_id = target; - dcb->target_lun = lun; -#ifndef DC395x_NO_DISCONNECT - dcb->identify_msg = - IDENTIFY(dcb->dev_mode & NTC_DO_DISCONNECT, lun); -#else - dcb->identify_msg = IDENTIFY(0, lun); -#endif - dcb->dev_mode = eeprom->target[target].cfg0; - dcb->inquiry7 = 0; - dcb->sync_mode = 0; - dcb->min_nego_period = clock_period[period_index]; - dcb->sync_period = 0; - dcb->sync_offset = 0; - dcb->flag = 0; - -#ifndef DC395x_NO_WIDE - if ((dcb->dev_mode & NTC_DO_WIDE_NEGO) - && (acb->config & HCC_WIDE_CARD)) - dcb->sync_mode |= WIDE_NEGO_ENABLE; -#endif -#ifndef DC395x_NO_SYNC - if (dcb->dev_mode & NTC_DO_SYNC_NEGO) - if (!(lun) || current_sync_offset) - dcb->sync_mode |= SYNC_NEGO_ENABLE; -#endif - if (dcb->target_lun != 0) { - /* Copy settings */ - struct DeviceCtlBlk *p; - list_for_each_entry(p, &acb->dcb_list, list) - if (p->target_id == dcb->target_id) - break; - dprintkdbg(DBG_1, - "device_alloc: <%02i-%i> copy from <%02i-%i>\n", - dcb->target_id, dcb->target_lun, - p->target_id, p->target_lun); - dcb->sync_mode = p->sync_mode; - dcb->sync_period = p->sync_period; - dcb->min_nego_period = p->min_nego_period; - dcb->sync_offset = p->sync_offset; - dcb->inquiry7 = p->inquiry7; - } - return dcb; -} - - -/** - * adapter_add_device - Adds the device instance to the adaptor instance. - * - * @acb: The adapter device to be updated - * @dcb: A newly created and initialised device instance to add. - **/ -static void adapter_add_device(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb) -{ - /* backpointer to adapter */ - dcb->acb = acb; - - /* set run_robin to this device if it is currently empty */ - if (list_empty(&acb->dcb_list)) - acb->dcb_run_robin = dcb; - - /* add device to list */ - list_add_tail(&dcb->list, &acb->dcb_list); - - /* update device maps */ - acb->dcb_map[dcb->target_id] |= (1 << dcb->target_lun); - acb->children[dcb->target_id][dcb->target_lun] = dcb; -} - - -/** - * adapter_remove_device - Removes the device instance from the adaptor - * instance. The device instance is not check in any way or freed by this. - * The caller is expected to take care of that. This will simply remove the - * device from the adapters data strcutures. - * - * @acb: The adapter device to be updated - * @dcb: A device that has previously been added to the adapter. - **/ -static void adapter_remove_device(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb) -{ - struct DeviceCtlBlk *i; - struct DeviceCtlBlk *tmp; - dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n", - dcb->target_id, dcb->target_lun); - - /* fix up any pointers to this device that we have in the adapter */ - if (acb->active_dcb == dcb) - acb->active_dcb = NULL; - if (acb->dcb_run_robin == dcb) - acb->dcb_run_robin = dcb_get_next(&acb->dcb_list, dcb); - - /* unlink from list */ - list_for_each_entry_safe(i, tmp, &acb->dcb_list, list) - if (dcb == i) { - list_del(&i->list); - break; - } - - /* clear map and children */ - acb->dcb_map[dcb->target_id] &= ~(1 << dcb->target_lun); - acb->children[dcb->target_id][dcb->target_lun] = NULL; - dcb->acb = NULL; -} - - -/** - * adapter_remove_and_free_device - Removes a single device from the adapter - * and then frees the device information. - * - * @acb: The adapter device to be updated - * @dcb: A device that has previously been added to the adapter. - */ -static void adapter_remove_and_free_device(struct AdapterCtlBlk *acb, - struct DeviceCtlBlk *dcb) -{ - if (list_size(&dcb->srb_going_list) > 1) { - dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> " - "Won't remove because of %i active requests.\n", - dcb->target_id, dcb->target_lun, - list_size(&dcb->srb_going_list)); - return; - } - adapter_remove_device(acb, dcb); - kfree(dcb); -} - - -/** - * adapter_remove_and_free_all_devices - Removes and frees all of the - * devices associated with the specified adapter. - * - * @acb: The adapter from which all devices should be removed. - **/ -static void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb) -{ - struct DeviceCtlBlk *dcb; - struct DeviceCtlBlk *tmp; - dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n", - list_size(&acb->dcb_list)); - - list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list) - adapter_remove_and_free_device(acb, dcb); -} - - -/** - * dc395x_slave_alloc - Called by the scsi mid layer to tell us about a new - * scsi device that we need to deal with. We allocate a new device and then - * insert that device into the adapters device list. - * - * @scsi_device: The new scsi device that we need to handle. - **/ -static int dc395x_slave_alloc(struct scsi_device *scsi_device) -{ - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; - struct DeviceCtlBlk *dcb; - - dcb = device_alloc(acb, scsi_device->id, scsi_device->lun); - if (!dcb) - return -ENOMEM; - adapter_add_device(acb, dcb); - - return 0; -} - - -/** - * dc395x_slave_destroy - Called by the scsi mid layer to tell us about a - * device that is going away. - * - * @scsi_device: The new scsi device that we need to handle. - **/ -static void dc395x_slave_destroy(struct scsi_device *scsi_device) -{ - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata; - struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun); - if (dcb) - adapter_remove_and_free_device(acb, dcb); -} - - - - -/** - * trms1040_wait_30us: wait for 30 us - * - * Waits for 30us (using the chip by the looks of it..) - * - * @io_port: base I/O address - **/ -static void __devinit trms1040_wait_30us(unsigned long io_port) -{ - /* ScsiPortStallExecution(30); wait 30 us */ - outb(5, io_port + TRM_S1040_GEN_TIMER); - while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT)) - /* nothing */ ; -} - - -/** - * trms1040_write_cmd - write the secified command and address to - * chip - * - * @io_port: base I/O address - * @cmd: SB + op code (command) to send - * @addr: address to send - **/ -static void __devinit trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr) -{ - int i; - u8 send_data; - - /* program SB + OP code */ - for (i = 0; i < 3; i++, cmd <<= 1) { - send_data = NVR_SELECT; - if (cmd & 0x04) /* Start from bit 2 */ - send_data |= NVR_BITOUT; - - outb(send_data, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - outb((send_data | NVR_CLOCK), - io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - } - - /* send address */ - for (i = 0; i < 7; i++, addr <<= 1) { - send_data = NVR_SELECT; - if (addr & 0x40) /* Start from bit 6 */ - send_data |= NVR_BITOUT; - - outb(send_data, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - outb((send_data | NVR_CLOCK), - io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - } - outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); -} - - -/** - * trms1040_set_data - store a single byte in the eeprom - * - * Called from write all to write a single byte into the SSEEPROM - * Which is done one bit at a time. - * - * @io_port: base I/O address - * @addr: offset into EEPROM - * @byte: bytes to write - **/ -static void __devinit trms1040_set_data(unsigned long io_port, u8 addr, u8 byte) -{ - int i; - u8 send_data; - - /* Send write command & address */ - trms1040_write_cmd(io_port, 0x05, addr); - - /* Write data */ - for (i = 0; i < 8; i++, byte <<= 1) { - send_data = NVR_SELECT; - if (byte & 0x80) /* Start from bit 7 */ - send_data |= NVR_BITOUT; - - outb(send_data, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - outb((send_data | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - } - outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - - /* Disable chip select */ - outb(0, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - - outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - - /* Wait for write ready */ - while (1) { - outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - - outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - - if (inb(io_port + TRM_S1040_GEN_NVRAM) & NVR_BITIN) - break; - } - - /* Disable chip select */ - outb(0, io_port + TRM_S1040_GEN_NVRAM); -} - - -/** - * trms1040_write_all - write 128 bytes to the eeprom - * - * Write the supplied 128 bytes to the chips SEEPROM - * - * @eeprom: the data to write - * @io_port: the base io port - **/ -static void __devinit trms1040_write_all(struct NvRamType *eeprom, unsigned long io_port) -{ - u8 *b_eeprom = (u8 *)eeprom; - u8 addr; - - /* Enable SEEPROM */ - outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM), - io_port + TRM_S1040_GEN_CONTROL); - - /* write enable */ - trms1040_write_cmd(io_port, 0x04, 0xFF); - outb(0, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - - /* write */ - for (addr = 0; addr < 128; addr++, b_eeprom++) - trms1040_set_data(io_port, addr, *b_eeprom); - - /* write disable */ - trms1040_write_cmd(io_port, 0x04, 0x00); - outb(0, io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - - /* Disable SEEPROM */ - outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM), - io_port + TRM_S1040_GEN_CONTROL); -} - - -/** - * trms1040_get_data - get a single byte from the eeprom - * - * Called from read all to read a single byte into the SSEEPROM - * Which is done one bit at a time. - * - * @io_port: base I/O address - * @addr: offset into SEEPROM - * - * Returns the byte read. - **/ -static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr) -{ - int i; - u8 read_byte; - u8 result = 0; - - /* Send read command & address */ - trms1040_write_cmd(io_port, 0x06, addr); - - /* read data */ - for (i = 0; i < 8; i++) { - outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM); - trms1040_wait_30us(io_port); - outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM); - - /* Get data bit while falling edge */ - read_byte = inb(io_port + TRM_S1040_GEN_NVRAM); - result <<= 1; - if (read_byte & NVR_BITIN) - result |= 1; - - trms1040_wait_30us(io_port); - } - - /* Disable chip select */ - outb(0, io_port + TRM_S1040_GEN_NVRAM); - return result; -} - - -/** - * trms1040_read_all - read all bytes from the eeprom - * - * Read the 128 bytes from the SEEPROM. - * - * @eeprom: where to store the data - * @io_port: the base io port - **/ -static void __devinit trms1040_read_all(struct NvRamType *eeprom, unsigned long io_port) -{ - u8 *b_eeprom = (u8 *)eeprom; - u8 addr; - - /* Enable SEEPROM */ - outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM), - io_port + TRM_S1040_GEN_CONTROL); - - /* read details */ - for (addr = 0; addr < 128; addr++, b_eeprom++) - *b_eeprom = trms1040_get_data(io_port, addr); - - /* Disable SEEPROM */ - outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM), - io_port + TRM_S1040_GEN_CONTROL); -} - - - -/** - * check_eeprom - get and check contents of the eeprom - * - * Read seeprom 128 bytes into the memory provider in eeprom. - * Checks the checksum and if it's not correct it uses a set of default - * values. - * - * @eeprom: caller allocated strcuture to read the eeprom data into - * @io_port: io port to read from - **/ -static void __devinit check_eeprom(struct NvRamType *eeprom, unsigned long io_port) -{ - u16 *w_eeprom = (u16 *)eeprom; - u16 w_addr; - u16 cksum; - u32 d_addr; - u32 *d_eeprom; - - trms1040_read_all(eeprom, io_port); /* read eeprom */ - - cksum = 0; - for (w_addr = 0, w_eeprom = (u16 *)eeprom; w_addr < 64; - w_addr++, w_eeprom++) - cksum += *w_eeprom; - if (cksum != 0x1234) { - /* - * Checksum is wrong. - * Load a set of defaults into the eeprom buffer - */ - dprintkl(KERN_WARNING, - "EEProm checksum error: using default values and options.\n"); - eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; - eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); - eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; - eeprom->sub_sys_id[1] = - (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); - eeprom->sub_class = 0x00; - eeprom->vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM; - eeprom->vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8); - eeprom->device_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040; - eeprom->device_id[1] = - (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8); - eeprom->reserved = 0x00; - - for (d_addr = 0, d_eeprom = (u32 *)eeprom->target; - d_addr < 16; d_addr++, d_eeprom++) - *d_eeprom = 0x00000077; /* cfg3,cfg2,period,cfg0 */ - - *d_eeprom++ = 0x04000F07; /* max_tag,delay_time,channel_cfg,scsi_id */ - *d_eeprom++ = 0x00000015; /* reserved1,boot_lun,boot_target,reserved0 */ - for (d_addr = 0; d_addr < 12; d_addr++, d_eeprom++) - *d_eeprom = 0x00; - - /* Now load defaults (maybe set by boot/module params) */ - set_safe_settings(); - fix_settings(); - eeprom_override(eeprom); - - eeprom->cksum = 0x00; - for (w_addr = 0, cksum = 0, w_eeprom = (u16 *)eeprom; - w_addr < 63; w_addr++, w_eeprom++) - cksum += *w_eeprom; - - *w_eeprom = 0x1234 - cksum; - trms1040_write_all(eeprom, io_port); - eeprom->delay_time = cfg_data[CFG_RESET_DELAY].value; - } else { - set_safe_settings(); - eeprom_index_to_delay(eeprom); - eeprom_override(eeprom); - } -} - - -/** - * print_eeprom_settings - output the eeprom settings - * to the kernel log so people can see what they were. - * - * @eeprom: The eeprom data strucutre to show details for. - **/ -static void __devinit print_eeprom_settings(struct NvRamType *eeprom) -{ - dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n", - eeprom->scsi_id, - eeprom->target[0].period, - clock_speed[eeprom->target[0].period] / 10, - clock_speed[eeprom->target[0].period] % 10, - eeprom->target[0].cfg0); - dprintkl(KERN_INFO, " AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n", - eeprom->channel_cfg, eeprom->max_tag, - 1 << eeprom->max_tag, eeprom->delay_time); -} - - -/* Free SG tables */ -static void adapter_sg_tables_free(struct AdapterCtlBlk *acb) -{ - int i; - const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; - - for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page) - kfree(acb->srb_array[i].segment_x); -} - - -/* - * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*) - * should never cross a page boundary */ -static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb) -{ - const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1) - *SEGMENTX_LEN; - int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE; - const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN; - int srb_idx = 0; - unsigned i = 0; - struct SGentry *uninitialized_var(ptr); - - for (i = 0; i < DC395x_MAX_SRB_CNT; i++) - acb->srb_array[i].segment_x = NULL; - - dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages); - while (pages--) { - ptr = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!ptr) { - adapter_sg_tables_free(acb); - return 1; - } - dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n", - PAGE_SIZE, ptr, srb_idx); - i = 0; - while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT) - acb->srb_array[srb_idx++].segment_x = - ptr + (i++ * DC395x_MAX_SG_LISTENTRY); - } - if (i < srbs_per_page) - acb->srb.segment_x = - ptr + (i * DC395x_MAX_SG_LISTENTRY); - else - dprintkl(KERN_DEBUG, "No space for tmsrb SG table reserved?!\n"); - return 0; -} - - - -/** - * adapter_print_config - print adapter connection and termination - * config - * - * The io port in the adapter needs to have been set before calling - * this function. - * - * @acb: The adapter to print the information for. - **/ -static void __devinit adapter_print_config(struct AdapterCtlBlk *acb) -{ - u8 bval; - - bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS); - dprintkl(KERN_INFO, "%sConnectors: ", - ((bval & WIDESCSI) ? "(Wide) " : "")); - if (!(bval & CON5068)) - printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50"); - if (!(bval & CON68)) - printk("int68%s ", !(bval & INT68HIGH) ? "" : "(50)"); - if (!(bval & CON50)) - printk("int50 "); - if ((bval & (CON5068 | CON50 | CON68)) == - 0 /*(CON5068 | CON50 | CON68) */ ) - printk(" Oops! (All 3?) "); - bval = DC395x_read8(acb, TRM_S1040_GEN_CONTROL); - printk(" Termination: "); - if (bval & DIS_TERM) - printk("Disabled\n"); - else { - if (bval & AUTOTERM) - printk("Auto "); - if (bval & LOW8TERM) - printk("Low "); - if (bval & UP8TERM) - printk("High "); - printk("\n"); - } -} - - -/** - * adapter_init_params - Initialize the various parameters in the - * adapter structure. Note that the pointer to the scsi_host is set - * early (when this instance is created) and the io_port and irq - * values are set later after they have been reserved. This just gets - * everything set to a good starting position. - * - * The eeprom structure in the adapter needs to have been set before - * calling this function. - * - * @acb: The adapter to initialize. - **/ -static void __devinit adapter_init_params(struct AdapterCtlBlk *acb) -{ - struct NvRamType *eeprom = &acb->eeprom; - int i; - - /* NOTE: acb->scsi_host is set at scsi_host/acb creation time */ - /* NOTE: acb->io_port_base is set at port registration time */ - /* NOTE: acb->io_port_len is set at port registration time */ - - INIT_LIST_HEAD(&acb->dcb_list); - acb->dcb_run_robin = NULL; - acb->active_dcb = NULL; - - INIT_LIST_HEAD(&acb->srb_free_list); - /* temp SRB for Q tag used or abort command used */ - acb->tmp_srb = &acb->srb; - init_timer(&acb->waiting_timer); - init_timer(&acb->selto_timer); - - acb->srb_count = DC395x_MAX_SRB_CNT; - - acb->sel_timeout = DC395x_SEL_TIMEOUT; /* timeout=250ms */ - /* NOTE: acb->irq_level is set at IRQ registration time */ - - acb->tag_max_num = 1 << eeprom->max_tag; - if (acb->tag_max_num > 30) - acb->tag_max_num = 30; - - acb->acb_flag = 0; /* RESET_DETECT, RESET_DONE, RESET_DEV */ - acb->gmode2 = eeprom->channel_cfg; - acb->config = 0; /* NOTE: actually set in adapter_init_chip */ - - if (eeprom->channel_cfg & NAC_SCANLUN) - acb->lun_chk = 1; - acb->scan_devices = 1; - - acb->scsi_host->this_id = eeprom->scsi_id; - acb->hostid_bit = (1 << acb->scsi_host->this_id); - - for (i = 0; i < DC395x_MAX_SCSI_ID; i++) - acb->dcb_map[i] = 0; - - acb->msg_len = 0; - - /* link static array of srbs into the srb free list */ - for (i = 0; i < acb->srb_count - 1; i++) - srb_free_insert(acb, &acb->srb_array[i]); -} - - -/** - * adapter_init_host - Initialize the scsi host instance based on - * values that we have already stored in the adapter instance. There's - * some mention that a lot of these are deprecated, so we won't use - * them (we'll use the ones in the adapter instance) but we'll fill - * them in in case something else needs them. - * - * The eeprom structure, irq and io ports in the adapter need to have - * been set before calling this function. - * - * @host: The scsi host instance to fill in the values for. - **/ -static void __devinit adapter_init_scsi_host(struct Scsi_Host *host) -{ - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; - struct NvRamType *eeprom = &acb->eeprom; - - host->max_cmd_len = 24; - host->can_queue = DC395x_MAX_CMD_QUEUE; - host->cmd_per_lun = DC395x_MAX_CMD_PER_LUN; - host->this_id = (int)eeprom->scsi_id; - host->io_port = acb->io_port_base; - host->n_io_port = acb->io_port_len; - host->dma_channel = -1; - host->unique_id = acb->io_port_base; - host->irq = acb->irq_level; - host->last_reset = jiffies; - - host->max_id = 16; - if (host->max_id - 1 == eeprom->scsi_id) - host->max_id--; - -#ifdef CONFIG_SCSI_MULTI_LUN - if (eeprom->channel_cfg & NAC_SCANLUN) - host->max_lun = 8; - else - host->max_lun = 1; -#else - host->max_lun = 1; -#endif - -} - - -/** - * adapter_init_chip - Get the chip into a know state and figure out - * some of the settings that apply to this adapter. - * - * The io port in the adapter needs to have been set before calling - * this function. The config will be configured correctly on return. - * - * @acb: The adapter which we are to init. - **/ -static void __devinit adapter_init_chip(struct AdapterCtlBlk *acb) -{ - struct NvRamType *eeprom = &acb->eeprom; - - /* Mask all the interrupt */ - DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00); - DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00); - - /* Reset SCSI module */ - DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE); - - /* Reset PCI/DMA module */ - DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE); - udelay(20); - - /* program configuration 0 */ - acb->config = HCC_AUTOTERM | HCC_PARITY; - if (DC395x_read8(acb, TRM_S1040_GEN_STATUS) & WIDESCSI) - acb->config |= HCC_WIDE_CARD; - - if (eeprom->channel_cfg & NAC_POWERON_SCSI_RESET) - acb->config |= HCC_SCSI_RESET; - - if (acb->config & HCC_SCSI_RESET) { - dprintkl(KERN_INFO, "Performing initial SCSI bus reset\n"); - DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); - - /*while (!( DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); */ - /*spin_unlock_irq (&io_request_lock); */ - udelay(500); - - acb->scsi_host->last_reset = - jiffies + HZ / 2 + - HZ * acb->eeprom.delay_time; - - /*spin_lock_irq (&io_request_lock); */ - } -} - - -/** - * init_adapter - Grab the resource for the card, setup the adapter - * information, set the card into a known state, create the various - * tables etc etc. This basically gets all adapter information all up - * to date, initialised and gets the chip in sync with it. - * - * @host: This hosts adapter structure - * @io_port: The base I/O port - * @irq: IRQ - * - * Returns 0 if the initialization succeeds, any other value on - * failure. - **/ -static int __devinit adapter_init(struct AdapterCtlBlk *acb, - unsigned long io_port, u32 io_port_len, unsigned int irq) -{ - if (!request_region(io_port, io_port_len, DC395X_NAME)) { - dprintkl(KERN_ERR, "Failed to reserve IO region 0x%lx\n", io_port); - goto failed; - } - /* store port base to indicate we have registered it */ - acb->io_port_base = io_port; - acb->io_port_len = io_port_len; - - if (request_irq(irq, dc395x_interrupt, IRQF_SHARED, DC395X_NAME, acb)) { - /* release the region we just claimed */ - dprintkl(KERN_INFO, "Failed to register IRQ\n"); - goto failed; - } - /* store irq to indicate we have registered it */ - acb->irq_level = irq; - - /* get eeprom configuration information and command line settings etc */ - check_eeprom(&acb->eeprom, io_port); - print_eeprom_settings(&acb->eeprom); - - /* setup adapter control block */ - adapter_init_params(acb); - - /* display card connectors/termination settings */ - adapter_print_config(acb); - - if (adapter_sg_tables_alloc(acb)) { - dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n"); - goto failed; - } - adapter_init_scsi_host(acb->scsi_host); - adapter_init_chip(acb); - set_basic_config(acb); - - dprintkdbg(DBG_0, - "adapter_init: acb=%p, pdcb_map=%p psrb_array=%p " - "size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n", - acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk), - sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk)); - return 0; - -failed: - if (acb->irq_level) - free_irq(acb->irq_level, acb); - if (acb->io_port_base) - release_region(acb->io_port_base, acb->io_port_len); - adapter_sg_tables_free(acb); - - return 1; -} - - -/** - * adapter_uninit_chip - cleanly shut down the scsi controller chip, - * stopping all operations and disabling interrupt generation on the - * card. - * - * @acb: The adapter which we are to shutdown. - **/ -static void adapter_uninit_chip(struct AdapterCtlBlk *acb) -{ - /* disable interrupts */ - DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0); - DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0); - - /* reset the scsi bus */ - if (acb->config & HCC_SCSI_RESET) - reset_scsi_bus(acb); - - /* clear any pending interrupt state */ - DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS); -} - - - -/** - * adapter_uninit - Shut down the chip and release any resources that - * we had allocated. Once this returns the adapter should not be used - * anymore. - * - * @acb: The adapter which we are to un-initialize. - **/ -static void adapter_uninit(struct AdapterCtlBlk *acb) -{ - unsigned long flags; - DC395x_LOCK_IO(acb->scsi_host, flags); - - /* remove timers */ - if (timer_pending(&acb->waiting_timer)) - del_timer(&acb->waiting_timer); - if (timer_pending(&acb->selto_timer)) - del_timer(&acb->selto_timer); - - adapter_uninit_chip(acb); - adapter_remove_and_free_all_devices(acb); - DC395x_UNLOCK_IO(acb->scsi_host, flags); - - if (acb->irq_level) - free_irq(acb->irq_level, acb); - if (acb->io_port_base) - release_region(acb->io_port_base, acb->io_port_len); - - adapter_sg_tables_free(acb); -} - - -#undef SPRINTF -#define SPRINTF(args...) pos += sprintf(pos, args) - -#undef YESNO -#define YESNO(YN) \ - if (YN) SPRINTF(" Yes ");\ - else SPRINTF(" No ") - -static int dc395x_proc_info(struct Scsi_Host *host, char *buffer, - char **start, off_t offset, int length, int inout) -{ - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata; - int spd, spd1; - char *pos = buffer; - struct DeviceCtlBlk *dcb; - unsigned long flags; - int dev; - - if (inout) /* Has data been written to the file ? */ - return -EPERM; - - SPRINTF(DC395X_BANNER " PCI SCSI Host Adapter\n"); - SPRINTF(" Driver Version " DC395X_VERSION "\n"); - - DC395x_LOCK_IO(acb->scsi_host, flags); - - SPRINTF("SCSI Host Nr %i, ", host->host_no); - SPRINTF("DC395U/UW/F DC315/U %s\n", - (acb->config & HCC_WIDE_CARD) ? "Wide" : ""); - SPRINTF("io_port_base 0x%04lx, ", acb->io_port_base); - SPRINTF("irq_level 0x%04x, ", acb->irq_level); - SPRINTF(" SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000); - - SPRINTF("MaxID %i, MaxLUN %i, ", host->max_id, host->max_lun); - SPRINTF("AdapterID %i\n", host->this_id); - - SPRINTF("tag_max_num %i", acb->tag_max_num); - /*SPRINTF(", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */ - SPRINTF(", FilterCfg 0x%02x", - DC395x_read8(acb, TRM_S1040_SCSI_CONFIG1)); - SPRINTF(", DelayReset %is\n", acb->eeprom.delay_time); - /*SPRINTF("\n"); */ - - SPRINTF("Nr of DCBs: %i\n", list_size(&acb->dcb_list)); - SPRINTF - ("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n", - acb->dcb_map[0], acb->dcb_map[1], acb->dcb_map[2], - acb->dcb_map[3], acb->dcb_map[4], acb->dcb_map[5], - acb->dcb_map[6], acb->dcb_map[7]); - SPRINTF - (" %02x %02x %02x %02x %02x %02x %02x %02x\n", - acb->dcb_map[8], acb->dcb_map[9], acb->dcb_map[10], - acb->dcb_map[11], acb->dcb_map[12], acb->dcb_map[13], - acb->dcb_map[14], acb->dcb_map[15]); - - SPRINTF - ("Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n"); - - dev = 0; - list_for_each_entry(dcb, &acb->dcb_list, list) { - int nego_period; - SPRINTF("%02i %02i %02i ", dev, dcb->target_id, - dcb->target_lun); - YESNO(dcb->dev_mode & NTC_DO_PARITY_CHK); - YESNO(dcb->sync_offset); - YESNO(dcb->sync_period & WIDE_SYNC); - YESNO(dcb->dev_mode & NTC_DO_DISCONNECT); - YESNO(dcb->dev_mode & NTC_DO_SEND_START); - YESNO(dcb->sync_mode & EN_TAG_QUEUEING); - nego_period = clock_period[dcb->sync_period & 0x07] << 2; - if (dcb->sync_offset) - SPRINTF(" %03i ns ", nego_period); - else - SPRINTF(" (%03i ns)", (dcb->min_nego_period << 2)); - - if (dcb->sync_offset & 0x0f) { - spd = 1000 / (nego_period); - spd1 = 1000 % (nego_period); - spd1 = (spd1 * 10 + nego_period / 2) / (nego_period); - SPRINTF(" %2i.%1i M %02i ", spd, spd1, - (dcb->sync_offset & 0x0f)); - } else - SPRINTF(" "); - - /* Add more info ... */ - SPRINTF(" %02i\n", dcb->max_command); - dev++; - } - - if (timer_pending(&acb->waiting_timer)) - SPRINTF("Waiting queue timer running\n"); - else - SPRINTF("\n"); - - list_for_each_entry(dcb, &acb->dcb_list, list) { - struct ScsiReqBlk *srb; - if (!list_empty(&dcb->srb_waiting_list)) - SPRINTF("DCB (%02i-%i): Waiting: %i:", - dcb->target_id, dcb->target_lun, - list_size(&dcb->srb_waiting_list)); - list_for_each_entry(srb, &dcb->srb_waiting_list, list) - SPRINTF(" %p", srb->cmd); - if (!list_empty(&dcb->srb_going_list)) - SPRINTF("\nDCB (%02i-%i): Going : %i:", - dcb->target_id, dcb->target_lun, - list_size(&dcb->srb_going_list)); - list_for_each_entry(srb, &dcb->srb_going_list, list) - SPRINTF(" %p", srb->cmd); - if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list)) - SPRINTF("\n"); - } - - if (debug_enabled(DBG_1)) { - SPRINTF("DCB list for ACB %p:\n", acb); - list_for_each_entry(dcb, &acb->dcb_list, list) { - SPRINTF("%p -> ", dcb); - } - SPRINTF("END\n"); - } - - *start = buffer + offset; - DC395x_UNLOCK_IO(acb->scsi_host, flags); - - if (pos - buffer < offset) - return 0; - else if (pos - buffer - offset < length) - return pos - buffer - offset; - else - return length; -} - - -static struct scsi_host_template dc395x_driver_template = { - .module = THIS_MODULE, - .proc_name = DC395X_NAME, - .proc_info = dc395x_proc_info, - .name = DC395X_BANNER " " DC395X_VERSION, - .queuecommand = dc395x_queue_command, - .bios_param = dc395x_bios_param, - .slave_alloc = dc395x_slave_alloc, - .slave_destroy = dc395x_slave_destroy, - .can_queue = DC395x_MAX_CAN_QUEUE, - .this_id = 7, - .sg_tablesize = DC395x_MAX_SG_TABLESIZE, - .cmd_per_lun = DC395x_MAX_CMD_PER_LUN, - .eh_abort_handler = dc395x_eh_abort, - .eh_bus_reset_handler = dc395x_eh_bus_reset, - .use_clustering = DISABLE_CLUSTERING, -}; - - -/** - * banner_display - Display banner on first instance of driver - * initialized. - **/ -static void banner_display(void) -{ - static int banner_done = 0; - if (!banner_done) - { - dprintkl(KERN_INFO, "%s %s\n", DC395X_BANNER, DC395X_VERSION); - banner_done = 1; - } -} - - -/** - * dc395x_init_one - Initialise a single instance of the adapter. - * - * The PCI layer will call this once for each instance of the adapter - * that it finds in the system. The pci_dev strcuture indicates which - * instance we are being called from. - * - * @dev: The PCI device to initialize. - * @id: Looks like a pointer to the entry in our pci device table - * that was actually matched by the PCI subsystem. - * - * Returns 0 on success, or an error code (-ve) on failure. - **/ -static int __devinit dc395x_init_one(struct pci_dev *dev, - const struct pci_device_id *id) -{ - struct Scsi_Host *scsi_host = NULL; - struct AdapterCtlBlk *acb = NULL; - unsigned long io_port_base; - unsigned int io_port_len; - unsigned int irq; - - dprintkdbg(DBG_0, "Init one instance (%s)\n", pci_name(dev)); - banner_display(); - - if (pci_enable_device(dev)) - { - dprintkl(KERN_INFO, "PCI Enable device failed.\n"); - return -ENODEV; - } - io_port_base = pci_resource_start(dev, 0) & PCI_BASE_ADDRESS_IO_MASK; - io_port_len = pci_resource_len(dev, 0); - irq = dev->irq; - dprintkdbg(DBG_0, "IO_PORT=0x%04lx, IRQ=0x%x\n", io_port_base, dev->irq); - - /* allocate scsi host information (includes out adapter) */ - scsi_host = scsi_host_alloc(&dc395x_driver_template, - sizeof(struct AdapterCtlBlk)); - if (!scsi_host) { - dprintkl(KERN_INFO, "scsi_host_alloc failed\n"); - goto fail; - } - acb = (struct AdapterCtlBlk*)scsi_host->hostdata; - acb->scsi_host = scsi_host; - acb->dev = dev; - - /* initialise the adapter and everything we need */ - if (adapter_init(acb, io_port_base, io_port_len, irq)) { - dprintkl(KERN_INFO, "adapter init failed\n"); - goto fail; - } - - pci_set_master(dev); - - /* get the scsi mid level to scan for new devices on the bus */ - if (scsi_add_host(scsi_host, &dev->dev)) { - dprintkl(KERN_ERR, "scsi_add_host failed\n"); - goto fail; - } - pci_set_drvdata(dev, scsi_host); - scsi_scan_host(scsi_host); - - return 0; - -fail: - if (acb != NULL) - adapter_uninit(acb); - if (scsi_host != NULL) - scsi_host_put(scsi_host); - pci_disable_device(dev); - return -ENODEV; -} - - -/** - * dc395x_remove_one - Called to remove a single instance of the - * adapter. - * - * @dev: The PCI device to initialize. - **/ -static void __devexit dc395x_remove_one(struct pci_dev *dev) -{ - struct Scsi_Host *scsi_host = pci_get_drvdata(dev); - struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata); - - dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb); - - scsi_remove_host(scsi_host); - adapter_uninit(acb); - pci_disable_device(dev); - scsi_host_put(scsi_host); - pci_set_drvdata(dev, NULL); -} - - -static struct pci_device_id dc395x_pci_table[] = { - { - .vendor = PCI_VENDOR_ID_TEKRAM, - .device = PCI_DEVICE_ID_TEKRAM_TRMS1040, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, dc395x_pci_table); - - -static struct pci_driver dc395x_driver = { - .name = DC395X_NAME, - .id_table = dc395x_pci_table, - .probe = dc395x_init_one, - .remove = __devexit_p(dc395x_remove_one), -}; - - -/** - * dc395x_module_init - Module initialization function - * - * Used by both module and built-in driver to initialise this driver. - **/ -static int __init dc395x_module_init(void) -{ - return pci_register_driver(&dc395x_driver); -} - - -/** - * dc395x_module_exit - Module cleanup function. - **/ -static void __exit dc395x_module_exit(void) -{ - pci_unregister_driver(&dc395x_driver); -} - - -module_init(dc395x_module_init); -module_exit(dc395x_module_exit); - -MODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff"); -MODULE_DESCRIPTION("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/dc395x.h b/ANDROID_3.4.5/drivers/scsi/dc395x.h deleted file mode 100644 index fbf35e37..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dc395x.h +++ /dev/null @@ -1,648 +0,0 @@ -/************************************************************************/ -/* */ -/* dc395x.h */ -/* */ -/* Device Driver for Tekram DC395(U/UW/F), DC315(U) */ -/* PCI SCSI Bus Master Host Adapter */ -/* (SCSI chip set used Tekram ASIC TRM-S1040) */ -/* */ -/************************************************************************/ -#ifndef DC395x_H -#define DC395x_H - -/************************************************************************/ -/* */ -/* Initial values */ -/* */ -/************************************************************************/ -#define DC395x_MAX_CMD_QUEUE 32 -/* #define DC395x_MAX_QTAGS 32 */ -#define DC395x_MAX_QTAGS 16 -#define DC395x_MAX_SCSI_ID 16 -#define DC395x_MAX_CMD_PER_LUN DC395x_MAX_QTAGS -#define DC395x_MAX_SG_TABLESIZE 64 /* HW limitation */ -#define DC395x_MAX_SG_LISTENTRY 64 /* Must be equal or lower to previous */ - /* item */ -#define DC395x_MAX_SRB_CNT 63 -/* #define DC395x_MAX_CAN_QUEUE 7 * DC395x_MAX_QTAGS */ -#define DC395x_MAX_CAN_QUEUE DC395x_MAX_SRB_CNT -#define DC395x_END_SCAN 2 -#define DC395x_SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ -#define DC395x_MAX_RETRIES 3 - -#if 0 -#define SYNC_FIRST -#endif - -#define NORM_REC_LVL 0 - -/************************************************************************/ -/* */ -/* Various definitions */ -/* */ -/************************************************************************/ -#define BIT31 0x80000000 -#define BIT30 0x40000000 -#define BIT29 0x20000000 -#define BIT28 0x10000000 -#define BIT27 0x08000000 -#define BIT26 0x04000000 -#define BIT25 0x02000000 -#define BIT24 0x01000000 -#define BIT23 0x00800000 -#define BIT22 0x00400000 -#define BIT21 0x00200000 -#define BIT20 0x00100000 -#define BIT19 0x00080000 -#define BIT18 0x00040000 -#define BIT17 0x00020000 -#define BIT16 0x00010000 -#define BIT15 0x00008000 -#define BIT14 0x00004000 -#define BIT13 0x00002000 -#define BIT12 0x00001000 -#define BIT11 0x00000800 -#define BIT10 0x00000400 -#define BIT9 0x00000200 -#define BIT8 0x00000100 -#define BIT7 0x00000080 -#define BIT6 0x00000040 -#define BIT5 0x00000020 -#define BIT4 0x00000010 -#define BIT3 0x00000008 -#define BIT2 0x00000004 -#define BIT1 0x00000002 -#define BIT0 0x00000001 - -/* UnitCtrlFlag */ -#define UNIT_ALLOCATED BIT0 -#define UNIT_INFO_CHANGED BIT1 -#define FORMATING_MEDIA BIT2 -#define UNIT_RETRY BIT3 - -/* UnitFlags */ -#define DASD_SUPPORT BIT0 -#define SCSI_SUPPORT BIT1 -#define ASPI_SUPPORT BIT2 - -/* SRBState machine definition */ -#define SRB_FREE 0x0000 -#define SRB_WAIT 0x0001 -#define SRB_READY 0x0002 -#define SRB_MSGOUT 0x0004 /* arbitration+msg_out 1st byte */ -#define SRB_MSGIN 0x0008 -#define SRB_EXTEND_MSGIN 0x0010 -#define SRB_COMMAND 0x0020 -#define SRB_START_ 0x0040 /* arbitration+msg_out+command_out */ -#define SRB_DISCONNECT 0x0080 -#define SRB_DATA_XFER 0x0100 -#define SRB_XFERPAD 0x0200 -#define SRB_STATUS 0x0400 -#define SRB_COMPLETED 0x0800 -#define SRB_ABORT_SENT 0x1000 -#define SRB_DO_SYNC_NEGO 0x2000 -#define SRB_DO_WIDE_NEGO 0x4000 -#define SRB_UNEXPECT_RESEL 0x8000 - -/************************************************************************/ -/* */ -/* ACB Config */ -/* */ -/************************************************************************/ -#define HCC_WIDE_CARD 0x20 -#define HCC_SCSI_RESET 0x10 -#define HCC_PARITY 0x08 -#define HCC_AUTOTERM 0x04 -#define HCC_LOW8TERM 0x02 -#define HCC_UP8TERM 0x01 - -/* ACBFlag */ -#define RESET_DEV BIT0 -#define RESET_DETECT BIT1 -#define RESET_DONE BIT2 - -/* DCBFlag */ -#define ABORT_DEV_ BIT0 - -/* SRBstatus */ -#define SRB_OK BIT0 -#define ABORTION BIT1 -#define OVER_RUN BIT2 -#define UNDER_RUN BIT3 -#define PARITY_ERROR BIT4 -#define SRB_ERROR BIT5 - -/* SRBFlag */ -#define DATAOUT BIT7 -#define DATAIN BIT6 -#define RESIDUAL_VALID BIT5 -#define ENABLE_TIMER BIT4 -#define RESET_DEV0 BIT2 -#define ABORT_DEV BIT1 -#define AUTO_REQSENSE BIT0 - -/* Adapter status */ -#define H_STATUS_GOOD 0 -#define H_SEL_TIMEOUT 0x11 -#define H_OVER_UNDER_RUN 0x12 -#define H_UNEXP_BUS_FREE 0x13 -#define H_TARGET_PHASE_F 0x14 -#define H_INVALID_CCB_OP 0x16 -#define H_LINK_CCB_BAD 0x17 -#define H_BAD_TARGET_DIR 0x18 -#define H_DUPLICATE_CCB 0x19 -#define H_BAD_CCB_OR_SG 0x1A -#define H_ABORT 0x0FF - -/* SCSI BUS Status byte codes */ -#define SCSI_STAT_GOOD 0x0 /* Good status */ -#define SCSI_STAT_CHECKCOND 0x02 /* SCSI Check Condition */ -#define SCSI_STAT_CONDMET 0x04 /* Condition Met */ -#define SCSI_STAT_BUSY 0x08 /* Target busy status */ -#define SCSI_STAT_INTER 0x10 /* Intermediate status */ -#define SCSI_STAT_INTERCONDMET 0x14 /* Intermediate condition met */ -#define SCSI_STAT_RESCONFLICT 0x18 /* Reservation conflict */ -#define SCSI_STAT_CMDTERM 0x22 /* Command Terminated */ -#define SCSI_STAT_QUEUEFULL 0x28 /* Queue Full */ -#define SCSI_STAT_UNEXP_BUS_F 0xFD /* Unexpect Bus Free */ -#define SCSI_STAT_BUS_RST_DETECT 0xFE /* Scsi Bus Reset detected */ -#define SCSI_STAT_SEL_TIMEOUT 0xFF /* Selection Time out */ - -/* Sync_Mode */ -#define SYNC_WIDE_TAG_ATNT_DISABLE 0 -#define SYNC_NEGO_ENABLE BIT0 -#define SYNC_NEGO_DONE BIT1 -#define WIDE_NEGO_ENABLE BIT2 -#define WIDE_NEGO_DONE BIT3 -#define WIDE_NEGO_STATE BIT4 -#define EN_TAG_QUEUEING BIT5 -#define EN_ATN_STOP BIT6 - -#define SYNC_NEGO_OFFSET 15 - -/* SCSI MSG BYTE */ -#define MSG_COMPLETE 0x00 -#define MSG_EXTENDED 0x01 -#define MSG_SAVE_PTR 0x02 -#define MSG_RESTORE_PTR 0x03 -#define MSG_DISCONNECT 0x04 -#define MSG_INITIATOR_ERROR 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJECT_ 0x07 -#define MSG_NOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define MSG_LINK_CMD_COMPL 0x0A -#define MSG_LINK_CMD_COMPL_FLG 0x0B -#define MSG_BUS_RESET 0x0C -#define MSG_ABORT_TAG 0x0D -#define MSG_SIMPLE_QTAG 0x20 -#define MSG_HEAD_QTAG 0x21 -#define MSG_ORDER_QTAG 0x22 -#define MSG_IGNOREWIDE 0x23 -#define MSG_IDENTIFY 0x80 -#define MSG_HOST_ID 0xC0 - -/* SCSI STATUS BYTE */ -#define STATUS_GOOD 0x00 -#define CHECK_CONDITION_ 0x02 -#define STATUS_BUSY 0x08 -#define STATUS_INTERMEDIATE 0x10 -#define RESERVE_CONFLICT 0x18 - -/* cmd->result */ -#define STATUS_MASK_ 0xFF -#define MSG_MASK 0xFF00 -#define RETURN_MASK 0xFF0000 - -/************************************************************************/ -/* */ -/* Inquiry Data format */ -/* */ -/************************************************************************/ -struct ScsiInqData -{ /* INQ */ - u8 DevType; /* Periph Qualifier & Periph Dev Type */ - u8 RMB_TypeMod; /* rem media bit & Dev Type Modifier */ - u8 Vers; /* ISO, ECMA, & ANSI versions */ - u8 RDF; /* AEN, TRMIOP, & response data format */ - u8 AddLen; /* length of additional data */ - u8 Res1; /* reserved */ - u8 Res2; /* reserved */ - u8 Flags; /* RelADr, Wbus32, Wbus16, Sync, etc. */ - u8 VendorID[8]; /* Vendor Identification */ - u8 ProductID[16]; /* Product Identification */ - u8 ProductRev[4]; /* Product Revision */ -}; - - /* Inquiry byte 0 masks */ -#define SCSI_DEVTYPE 0x1F /* Peripheral Device Type */ -#define SCSI_PERIPHQUAL 0xE0 /* Peripheral Qualifier */ - /* Inquiry byte 1 mask */ -#define SCSI_REMOVABLE_MEDIA 0x80 /* Removable Media bit (1=removable) */ - /* Peripheral Device Type definitions */ - /* See include/scsi/scsi.h */ -#define TYPE_NODEV SCSI_DEVTYPE /* Unknown or no device type */ -#ifndef TYPE_PRINTER /* */ -# define TYPE_PRINTER 0x02 /* Printer device */ -#endif /* */ -#ifndef TYPE_COMM /* */ -# define TYPE_COMM 0x09 /* Communications device */ -#endif - -/************************************************************************/ -/* */ -/* Inquiry flag definitions (Inq data byte 7) */ -/* */ -/************************************************************************/ -#define SCSI_INQ_RELADR 0x80 /* device supports relative addressing */ -#define SCSI_INQ_WBUS32 0x40 /* device supports 32 bit data xfers */ -#define SCSI_INQ_WBUS16 0x20 /* device supports 16 bit data xfers */ -#define SCSI_INQ_SYNC 0x10 /* device supports synchronous xfer */ -#define SCSI_INQ_LINKED 0x08 /* device supports linked commands */ -#define SCSI_INQ_CMDQUEUE 0x02 /* device supports command queueing */ -#define SCSI_INQ_SFTRE 0x01 /* device supports soft resets */ - -#define ENABLE_CE 1 -#define DISABLE_CE 0 -#define EEPROM_READ 0x80 - -/************************************************************************/ -/* */ -/* The PCI configuration register offset for TRM_S1040 */ -/* */ -/************************************************************************/ -#define TRM_S1040_ID 0x00 /* Vendor and Device ID */ -#define TRM_S1040_COMMAND 0x04 /* PCI command register */ -#define TRM_S1040_IOBASE 0x10 /* I/O Space base address */ -#define TRM_S1040_ROMBASE 0x30 /* Expansion ROM Base Address */ -#define TRM_S1040_INTLINE 0x3C /* Interrupt line */ - -/************************************************************************/ -/* */ -/* The SCSI register offset for TRM_S1040 */ -/* */ -/************************************************************************/ -#define TRM_S1040_SCSI_STATUS 0x80 /* SCSI Status (R) */ -#define COMMANDPHASEDONE 0x2000 /* SCSI command phase done */ -#define SCSIXFERDONE 0x0800 /* SCSI SCSI transfer done */ -#define SCSIXFERCNT_2_ZERO 0x0100 /* SCSI SCSI transfer count to zero */ -#define SCSIINTERRUPT 0x0080 /* SCSI interrupt pending */ -#define COMMANDABORT 0x0040 /* SCSI command abort */ -#define SEQUENCERACTIVE 0x0020 /* SCSI sequencer active */ -#define PHASEMISMATCH 0x0010 /* SCSI phase mismatch */ -#define PARITYERROR 0x0008 /* SCSI parity error */ - -#define PHASEMASK 0x0007 /* Phase MSG/CD/IO */ -#define PH_DATA_OUT 0x00 /* Data out phase */ -#define PH_DATA_IN 0x01 /* Data in phase */ -#define PH_COMMAND 0x02 /* Command phase */ -#define PH_STATUS 0x03 /* Status phase */ -#define PH_BUS_FREE 0x05 /* Invalid phase used as bus free */ -#define PH_MSG_OUT 0x06 /* Message out phase */ -#define PH_MSG_IN 0x07 /* Message in phase */ - -#define TRM_S1040_SCSI_CONTROL 0x80 /* SCSI Control (W) */ -#define DO_CLRATN 0x0400 /* Clear ATN */ -#define DO_SETATN 0x0200 /* Set ATN */ -#define DO_CMDABORT 0x0100 /* Abort SCSI command */ -#define DO_RSTMODULE 0x0010 /* Reset SCSI chip */ -#define DO_RSTSCSI 0x0008 /* Reset SCSI bus */ -#define DO_CLRFIFO 0x0004 /* Clear SCSI transfer FIFO */ -#define DO_DATALATCH 0x0002 /* Enable SCSI bus data input (latched) */ -/* #define DO_DATALATCH 0x0000 */ /* KG: DISable SCSI bus data latch */ -#define DO_HWRESELECT 0x0001 /* Enable hardware reselection */ - -#define TRM_S1040_SCSI_FIFOCNT 0x82 /* SCSI FIFO Counter 5bits(R) */ -#define TRM_S1040_SCSI_SIGNAL 0x83 /* SCSI low level signal (R/W) */ - -#define TRM_S1040_SCSI_INTSTATUS 0x84 /* SCSI Interrupt Status (R) */ -#define INT_SCAM 0x80 /* SCAM selection interrupt */ -#define INT_SELECT 0x40 /* Selection interrupt */ -#define INT_SELTIMEOUT 0x20 /* Selection timeout interrupt */ -#define INT_DISCONNECT 0x10 /* Bus disconnected interrupt */ -#define INT_RESELECTED 0x08 /* Reselected interrupt */ -#define INT_SCSIRESET 0x04 /* SCSI reset detected interrupt */ -#define INT_BUSSERVICE 0x02 /* Bus service interrupt */ -#define INT_CMDDONE 0x01 /* SCSI command done interrupt */ - -#define TRM_S1040_SCSI_OFFSET 0x84 /* SCSI Offset Count (W) */ - -/************************************************************************/ -/* */ -/* Bit Name Definition */ -/* --------- ------------- ---------------------------- */ -/* 07-05 0 RSVD Reversed. Always 0. */ -/* 04 0 OFFSET4 Reversed for LVDS. Always 0. */ -/* 03-00 0 OFFSET[03:00] Offset number from 0 to 15 */ -/* */ -/************************************************************************/ - -#define TRM_S1040_SCSI_SYNC 0x85 /* SCSI Synchronous Control (R/W) */ -#define LVDS_SYNC 0x20 /* Enable LVDS synchronous */ -#define WIDE_SYNC 0x10 /* Enable WIDE synchronous */ -#define ALT_SYNC 0x08 /* Enable Fast-20 alternate synchronous */ - -/************************************************************************/ -/* */ -/* SYNCM 7 6 5 4 3 2 1 0 */ -/* Name RSVD RSVD LVDS WIDE ALTPERD PERIOD2 PERIOD1 PERIOD0 */ -/* Default 0 0 0 0 0 0 0 0 */ -/* */ -/* Bit Name Definition */ -/* --------- ------------- --------------------------- */ -/* 07-06 0 RSVD Reversed. Always read 0 */ -/* 05 0 LVDS Reversed. Always read 0 */ -/* 04 0 WIDE/WSCSI Enable wide (16-bits) SCSI */ -/* transfer. */ -/* 03 0 ALTPERD/ALTPD Alternate (Sync./Period) mode. */ -/* */ -/* @@ When this bit is set, */ -/* the synchronous period bits 2:0 */ -/* in the Synchronous Mode register */ -/* are used to transfer data */ -/* at the Fast-20 rate. */ -/* @@ When this bit is unset, */ -/* the synchronous period bits 2:0 */ -/* in the Synchronous Mode Register */ -/* are used to transfer data */ -/* at the Fast-10 rate (or Fast-40 w/ LVDS). */ -/* */ -/* 02-00 0 PERIOD[2:0]/ Synchronous SCSI Transfer Rate. */ -/* SXPD[02:00] These 3 bits specify */ -/* the Synchronous SCSI Transfer */ -/* Rate for Fast-20 and Fast-10. */ -/* These bits are also reset */ -/* by a SCSI Bus reset. */ -/* */ -/* For Fast-10 bit ALTPD = 0 and LVDS = 0 */ -/* and bit2,bit1,bit0 is defined as follows : */ -/* */ -/* 000 100ns, 10.0 MHz */ -/* 001 150ns, 6.6 MHz */ -/* 010 200ns, 5.0 MHz */ -/* 011 250ns, 4.0 MHz */ -/* 100 300ns, 3.3 MHz */ -/* 101 350ns, 2.8 MHz */ -/* 110 400ns, 2.5 MHz */ -/* 111 450ns, 2.2 MHz */ -/* */ -/* For Fast-20 bit ALTPD = 1 and LVDS = 0 */ -/* and bit2,bit1,bit0 is defined as follows : */ -/* */ -/* 000 50ns, 20.0 MHz */ -/* 001 75ns, 13.3 MHz */ -/* 010 100ns, 10.0 MHz */ -/* 011 125ns, 8.0 MHz */ -/* 100 150ns, 6.6 MHz */ -/* 101 175ns, 5.7 MHz */ -/* 110 200ns, 5.0 MHz */ -/* 111 250ns, 4.0 MHz KG: Maybe 225ns, 4.4 MHz */ -/* */ -/* For Fast-40 bit ALTPD = 0 and LVDS = 1 */ -/* and bit2,bit1,bit0 is defined as follows : */ -/* */ -/* 000 25ns, 40.0 MHz */ -/* 001 50ns, 20.0 MHz */ -/* 010 75ns, 13.3 MHz */ -/* 011 100ns, 10.0 MHz */ -/* 100 125ns, 8.0 MHz */ -/* 101 150ns, 6.6 MHz */ -/* 110 175ns, 5.7 MHz */ -/* 111 200ns, 5.0 MHz */ -/* */ -/************************************************************************/ - -#define TRM_S1040_SCSI_TARGETID 0x86 /* SCSI Target ID (R/W) */ -#define TRM_S1040_SCSI_IDMSG 0x87 /* SCSI Identify Message (R) */ -#define TRM_S1040_SCSI_HOSTID 0x87 /* SCSI Host ID (W) */ -#define TRM_S1040_SCSI_COUNTER 0x88 /* SCSI Transfer Counter 24bits(R/W) */ - -#define TRM_S1040_SCSI_INTEN 0x8C /* SCSI Interrupt Enable (R/W) */ -#define EN_SCAM 0x80 /* Enable SCAM selection interrupt */ -#define EN_SELECT 0x40 /* Enable selection interrupt */ -#define EN_SELTIMEOUT 0x20 /* Enable selection timeout interrupt */ -#define EN_DISCONNECT 0x10 /* Enable bus disconnected interrupt */ -#define EN_RESELECTED 0x08 /* Enable reselected interrupt */ -#define EN_SCSIRESET 0x04 /* Enable SCSI reset detected interrupt */ -#define EN_BUSSERVICE 0x02 /* Enable bus service interrupt */ -#define EN_CMDDONE 0x01 /* Enable SCSI command done interrupt */ - -#define TRM_S1040_SCSI_CONFIG0 0x8D /* SCSI Configuration 0 (R/W) */ -#define PHASELATCH 0x40 /* Enable phase latch */ -#define INITIATOR 0x20 /* Enable initiator mode */ -#define PARITYCHECK 0x10 /* Enable parity check */ -#define BLOCKRST 0x01 /* Disable SCSI reset1 */ - -#define TRM_S1040_SCSI_CONFIG1 0x8E /* SCSI Configuration 1 (R/W) */ -#define ACTIVE_NEGPLUS 0x10 /* Enhance active negation */ -#define FILTER_DISABLE 0x08 /* Disable SCSI data filter */ -#define FAST_FILTER 0x04 /* ? */ -#define ACTIVE_NEG 0x02 /* Enable active negation */ - -#define TRM_S1040_SCSI_CONFIG2 0x8F /* SCSI Configuration 2 (R/W) */ -#define CFG2_WIDEFIFO 0x02 /* */ - -#define TRM_S1040_SCSI_COMMAND 0x90 /* SCSI Command (R/W) */ -#define SCMD_COMP 0x12 /* Command complete */ -#define SCMD_SEL_ATN 0x60 /* Selection with ATN */ -#define SCMD_SEL_ATN3 0x64 /* Selection with ATN3 */ -#define SCMD_SEL_ATNSTOP 0xB8 /* Selection with ATN and Stop */ -#define SCMD_FIFO_OUT 0xC0 /* SCSI FIFO transfer out */ -#define SCMD_DMA_OUT 0xC1 /* SCSI DMA transfer out */ -#define SCMD_FIFO_IN 0xC2 /* SCSI FIFO transfer in */ -#define SCMD_DMA_IN 0xC3 /* SCSI DMA transfer in */ -#define SCMD_MSGACCEPT 0xD8 /* Message accept */ - -/************************************************************************/ -/* */ -/* Code Command Description */ -/* ---- ---------------------------------------- */ -/* 02 Enable reselection with FIFO */ -/* 40 Select without ATN with FIFO */ -/* 60 Select with ATN with FIFO */ -/* 64 Select with ATN3 with FIFO */ -/* A0 Select with ATN and stop with FIFO */ -/* C0 Transfer information out with FIFO */ -/* C1 Transfer information out with DMA */ -/* C2 Transfer information in with FIFO */ -/* C3 Transfer information in with DMA */ -/* 12 Initiator command complete with FIFO */ -/* 50 Initiator transfer information out sequence without ATN */ -/* with FIFO */ -/* 70 Initiator transfer information out sequence with ATN */ -/* with FIFO */ -/* 74 Initiator transfer information out sequence with ATN3 */ -/* with FIFO */ -/* 52 Initiator transfer information in sequence without ATN */ -/* with FIFO */ -/* 72 Initiator transfer information in sequence with ATN */ -/* with FIFO */ -/* 76 Initiator transfer information in sequence with ATN3 */ -/* with FIFO */ -/* 90 Initiator transfer information out command complete */ -/* with FIFO */ -/* 92 Initiator transfer information in command complete */ -/* with FIFO */ -/* D2 Enable selection */ -/* 08 Reselection */ -/* 48 Disconnect command with FIFO */ -/* 88 Terminate command with FIFO */ -/* C8 Target command complete with FIFO */ -/* 18 SCAM Arbitration/ Selection */ -/* 5A Enable reselection */ -/* 98 Select without ATN with FIFO */ -/* B8 Select with ATN with FIFO */ -/* D8 Message Accepted */ -/* 58 NOP */ -/* */ -/************************************************************************/ - -#define TRM_S1040_SCSI_TIMEOUT 0x91 /* SCSI Time Out Value (R/W) */ -#define TRM_S1040_SCSI_FIFO 0x98 /* SCSI FIFO (R/W) */ - -#define TRM_S1040_SCSI_TCR0 0x9C /* SCSI Target Control 0 (R/W) */ -#define TCR0_WIDE_NEGO_DONE 0x8000 /* Wide nego done */ -#define TCR0_SYNC_NEGO_DONE 0x4000 /* Synchronous nego done */ -#define TCR0_ENABLE_LVDS 0x2000 /* Enable LVDS synchronous */ -#define TCR0_ENABLE_WIDE 0x1000 /* Enable WIDE synchronous */ -#define TCR0_ENABLE_ALT 0x0800 /* Enable alternate synchronous */ -#define TCR0_PERIOD_MASK 0x0700 /* Transfer rate */ - -#define TCR0_DO_WIDE_NEGO 0x0080 /* Do wide NEGO */ -#define TCR0_DO_SYNC_NEGO 0x0040 /* Do sync NEGO */ -#define TCR0_DISCONNECT_EN 0x0020 /* Disconnection enable */ -#define TCR0_OFFSET_MASK 0x001F /* Offset number */ - -#define TRM_S1040_SCSI_TCR1 0x9E /* SCSI Target Control 1 (R/W) */ -#define MAXTAG_MASK 0x7F00 /* Maximum tags (127) */ -#define NON_TAG_BUSY 0x0080 /* Non tag command active */ -#define ACTTAG_MASK 0x007F /* Active tags */ - -/************************************************************************/ -/* */ -/* The DMA register offset for TRM_S1040 */ -/* */ -/************************************************************************/ -#define TRM_S1040_DMA_COMMAND 0xA0 /* DMA Command (R/W) */ -#define DMACMD_SG 0x02 /* Enable HW S/G support */ -#define DMACMD_DIR 0x01 /* 1 = read from SCSI write to Host */ -#define XFERDATAIN_SG 0x0103 /* Transfer data in w/ SG */ -#define XFERDATAOUT_SG 0x0102 /* Transfer data out w/ SG */ -#define XFERDATAIN 0x0101 /* Transfer data in w/o SG */ -#define XFERDATAOUT 0x0100 /* Transfer data out w/o SG */ - -#define TRM_S1040_DMA_FIFOCNT 0xA1 /* DMA FIFO Counter (R) */ - -#define TRM_S1040_DMA_CONTROL 0xA1 /* DMA Control (W) */ -#define DMARESETMODULE 0x10 /* Reset PCI/DMA module */ -#define STOPDMAXFER 0x08 /* Stop DMA transfer */ -#define ABORTXFER 0x04 /* Abort DMA transfer */ -#define CLRXFIFO 0x02 /* Clear DMA transfer FIFO */ -#define STARTDMAXFER 0x01 /* Start DMA transfer */ - -#define TRM_S1040_DMA_FIFOSTAT 0xA2 /* DMA FIFO Status (R) */ - -#define TRM_S1040_DMA_STATUS 0xA3 /* DMA Interrupt Status (R/W) */ -#define XFERPENDING 0x80 /* Transfer pending */ -#define SCSIBUSY 0x40 /* SCSI busy */ -#define GLOBALINT 0x20 /* DMA_INTEN bit 0-4 set */ -#define FORCEDMACOMP 0x10 /* Force DMA transfer complete */ -#define DMAXFERERROR 0x08 /* DMA transfer error */ -#define DMAXFERABORT 0x04 /* DMA transfer abort */ -#define DMAXFERCOMP 0x02 /* Bus Master XFER Complete status */ -#define SCSICOMP 0x01 /* SCSI complete interrupt */ - -#define TRM_S1040_DMA_INTEN 0xA4 /* DMA Interrupt Enable (R/W) */ -#define EN_FORCEDMACOMP 0x10 /* Force DMA transfer complete */ -#define EN_DMAXFERERROR 0x08 /* DMA transfer error */ -#define EN_DMAXFERABORT 0x04 /* DMA transfer abort */ -#define EN_DMAXFERCOMP 0x02 /* Bus Master XFER Complete status */ -#define EN_SCSIINTR 0x01 /* Enable SCSI complete interrupt */ - -#define TRM_S1040_DMA_CONFIG 0xA6 /* DMA Configuration (R/W) */ -#define DMA_ENHANCE 0x8000 /* Enable DMA enhance feature (SG?) */ -#define DMA_PCI_DUAL_ADDR 0x4000 /* */ -#define DMA_CFG_RES 0x2000 /* Always 1 */ -#define DMA_AUTO_CLR_FIFO 0x1000 /* DISable DMA auto clear FIFO */ -#define DMA_MEM_MULTI_READ 0x0800 /* */ -#define DMA_MEM_WRITE_INVAL 0x0400 /* Memory write and invalidate */ -#define DMA_FIFO_CTRL 0x0300 /* Control FIFO operation with DMA */ -#define DMA_FIFO_HALF_HALF 0x0200 /* Keep half filled on both read/write */ - -#define TRM_S1040_DMA_XCNT 0xA8 /* DMA Transfer Counter (R/W), 24bits */ -#define TRM_S1040_DMA_CXCNT 0xAC /* DMA Current Transfer Counter (R) */ -#define TRM_S1040_DMA_XLOWADDR 0xB0 /* DMA Transfer Physical Low Address */ -#define TRM_S1040_DMA_XHIGHADDR 0xB4 /* DMA Transfer Physical High Address */ - -/************************************************************************/ -/* */ -/* The general register offset for TRM_S1040 */ -/* */ -/************************************************************************/ -#define TRM_S1040_GEN_CONTROL 0xD4 /* Global Control */ -#define CTRL_LED 0x80 /* Control onboard LED */ -#define EN_EEPROM 0x10 /* Enable EEPROM programming */ -#define DIS_TERM 0x08 /* Disable onboard termination */ -#define AUTOTERM 0x04 /* Enable Auto SCSI terminator */ -#define LOW8TERM 0x02 /* Enable Lower 8 bit SCSI terminator */ -#define UP8TERM 0x01 /* Enable Upper 8 bit SCSI terminator */ - -#define TRM_S1040_GEN_STATUS 0xD5 /* Global Status */ -#define GTIMEOUT 0x80 /* Global timer reach 0 */ -#define EXT68HIGH 0x40 /* Higher 8 bit connected externally */ -#define INT68HIGH 0x20 /* Higher 8 bit connected internally */ -#define CON5068 0x10 /* External 50/68 pin connected (low) */ -#define CON68 0x08 /* Internal 68 pin connected (low) */ -#define CON50 0x04 /* Internal 50 pin connected (low!) */ -#define WIDESCSI 0x02 /* Wide SCSI card */ -#define STATUS_LOAD_DEFAULT 0x01 /* */ - -#define TRM_S1040_GEN_NVRAM 0xD6 /* Serial NON-VOLATILE RAM port */ -#define NVR_BITOUT 0x08 /* Serial data out */ -#define NVR_BITIN 0x04 /* Serial data in */ -#define NVR_CLOCK 0x02 /* Serial clock */ -#define NVR_SELECT 0x01 /* Serial select */ - -#define TRM_S1040_GEN_EDATA 0xD7 /* Parallel EEPROM data port */ -#define TRM_S1040_GEN_EADDRESS 0xD8 /* Parallel EEPROM address */ -#define TRM_S1040_GEN_TIMER 0xDB /* Global timer */ - -/************************************************************************/ -/* */ -/* NvmTarCfg0: Target configuration byte 0 :..pDCB->DevMode */ -/* */ -/************************************************************************/ -#define NTC_DO_WIDE_NEGO 0x20 /* Wide negotiate */ -#define NTC_DO_TAG_QUEUEING 0x10 /* Enable SCSI tag queuing */ -#define NTC_DO_SEND_START 0x08 /* Send start command SPINUP */ -#define NTC_DO_DISCONNECT 0x04 /* Enable SCSI disconnect */ -#define NTC_DO_SYNC_NEGO 0x02 /* Sync negotiation */ -#define NTC_DO_PARITY_CHK 0x01 /* (it should define at NAC) */ - /* Parity check enable */ - -/************************************************************************/ -/* */ -/* Nvram Initiater bits definition */ -/* */ -/************************************************************************/ -#if 0 -#define MORE2_DRV BIT0 -#define GREATER_1G BIT1 -#define RST_SCSI_BUS BIT2 -#define ACTIVE_NEGATION BIT3 -#define NO_SEEK BIT4 -#define LUN_CHECK BIT5 -#endif - -/************************************************************************/ -/* */ -/* Nvram Adapter Cfg bits definition */ -/* */ -/************************************************************************/ -#define NAC_SCANLUN 0x20 /* Include LUN as BIOS device */ -#define NAC_POWERON_SCSI_RESET 0x04 /* Power on reset enable */ -#define NAC_GREATER_1G 0x02 /* > 1G support enable */ -#define NAC_GT2DRIVES 0x01 /* Support more than 2 drives */ -/* #define NAC_DO_PARITY_CHK 0x08 */ /* Parity check enable */ - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/device_handler/Kconfig b/ANDROID_3.4.5/drivers/scsi/device_handler/Kconfig deleted file mode 100644 index 67070257..00000000 --- a/ANDROID_3.4.5/drivers/scsi/device_handler/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# SCSI Device Handler configuration -# - -menuconfig SCSI_DH - tristate "SCSI Device Handlers" - depends on SCSI - default n - help - SCSI Device Handlers provide device specific support for - devices utilized in multipath configurations. Say Y here to - select support for specific hardware. - -config SCSI_DH_RDAC - tristate "LSI RDAC Device Handler" - depends on SCSI_DH - help - If you have a LSI RDAC select y. Otherwise, say N. - -config SCSI_DH_HP_SW - tristate "HP/COMPAQ MSA Device Handler" - depends on SCSI_DH - help - If you have a HP/COMPAQ MSA device that requires START_STOP to - be sent to start it and cannot upgrade the firmware then select y. - Otherwise, say N. - -config SCSI_DH_EMC - tristate "EMC CLARiiON Device Handler" - depends on SCSI_DH - help - If you have a EMC CLARiiON select y. Otherwise, say N. - -config SCSI_DH_ALUA - tristate "SPC-3 ALUA Device Handler (EXPERIMENTAL)" - depends on SCSI_DH && EXPERIMENTAL - help - SCSI Device handler for generic SPC-3 Asymmetric Logical Unit - Access (ALUA). - diff --git a/ANDROID_3.4.5/drivers/scsi/device_handler/Makefile b/ANDROID_3.4.5/drivers/scsi/device_handler/Makefile deleted file mode 100644 index e1d2ea08..00000000 --- a/ANDROID_3.4.5/drivers/scsi/device_handler/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# SCSI Device Handler -# -obj-$(CONFIG_SCSI_DH) += scsi_dh.o -obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o -obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o -obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o -obj-$(CONFIG_SCSI_DH_ALUA) += scsi_dh_alua.o diff --git a/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh.c b/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh.c deleted file mode 100644 index 48e46f5b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * SCSI device handler infrastruture. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2007 - * Authors: - * Chandra Seetharaman - * Mike Anderson - */ - -#include -#include -#include -#include "../scsi_priv.h" - -static DEFINE_SPINLOCK(list_lock); -static LIST_HEAD(scsi_dh_list); - -static struct scsi_device_handler *get_device_handler(const char *name) -{ - struct scsi_device_handler *tmp, *found = NULL; - - spin_lock(&list_lock); - list_for_each_entry(tmp, &scsi_dh_list, list) { - if (!strncmp(tmp->name, name, strlen(tmp->name))) { - found = tmp; - break; - } - } - spin_unlock(&list_lock); - return found; -} - -/* - * device_handler_match_function - Match a device handler to a device - * @sdev - SCSI device to be tested - * - * Tests @sdev against the match function of all registered device_handler. - * Returns the found device handler or NULL if not found. - */ -static struct scsi_device_handler * -device_handler_match_function(struct scsi_device *sdev) -{ - struct scsi_device_handler *tmp_dh, *found_dh = NULL; - - spin_lock(&list_lock); - list_for_each_entry(tmp_dh, &scsi_dh_list, list) { - if (tmp_dh->match && tmp_dh->match(sdev)) { - found_dh = tmp_dh; - break; - } - } - spin_unlock(&list_lock); - return found_dh; -} - -/* - * device_handler_match - Attach a device handler to a device - * @scsi_dh - The device handler to match against or NULL - * @sdev - SCSI device to be tested against @scsi_dh - * - * Tests @sdev against the device handler @scsi_dh or against - * all registered device_handler if @scsi_dh == NULL. - * Returns the found device handler or NULL if not found. - */ -static struct scsi_device_handler * -device_handler_match(struct scsi_device_handler *scsi_dh, - struct scsi_device *sdev) -{ - struct scsi_device_handler *found_dh; - - found_dh = device_handler_match_function(sdev); - - if (scsi_dh && found_dh != scsi_dh) - found_dh = NULL; - - return found_dh; -} - -/* - * scsi_dh_handler_attach - Attach a device handler to a device - * @sdev - SCSI device the device handler should attach to - * @scsi_dh - The device handler to attach - */ -static int scsi_dh_handler_attach(struct scsi_device *sdev, - struct scsi_device_handler *scsi_dh) -{ - int err = 0; - - if (sdev->scsi_dh_data) { - if (sdev->scsi_dh_data->scsi_dh != scsi_dh) - err = -EBUSY; - else - kref_get(&sdev->scsi_dh_data->kref); - } else if (scsi_dh->attach) { - err = scsi_dh->attach(sdev); - if (!err) { - kref_init(&sdev->scsi_dh_data->kref); - sdev->scsi_dh_data->sdev = sdev; - } - } - return err; -} - -static void __detach_handler (struct kref *kref) -{ - struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref); - scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev); -} - -/* - * scsi_dh_handler_detach - Detach a device handler from a device - * @sdev - SCSI device the device handler should be detached from - * @scsi_dh - Device handler to be detached - * - * Detach from a device handler. If a device handler is specified, - * only detach if the currently attached handler matches @scsi_dh. - */ -static void scsi_dh_handler_detach(struct scsi_device *sdev, - struct scsi_device_handler *scsi_dh) -{ - if (!sdev->scsi_dh_data) - return; - - if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh) - return; - - if (!scsi_dh) - scsi_dh = sdev->scsi_dh_data->scsi_dh; - - if (scsi_dh && scsi_dh->detach) - kref_put(&sdev->scsi_dh_data->kref, __detach_handler); -} - -/* - * Functions for sysfs attribute 'dh_state' - */ -static ssize_t -store_dh_state(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct scsi_device_handler *scsi_dh; - int err = -EINVAL; - - if (sdev->sdev_state == SDEV_CANCEL || - sdev->sdev_state == SDEV_DEL) - return -ENODEV; - - if (!sdev->scsi_dh_data) { - /* - * Attach to a device handler - */ - if (!(scsi_dh = get_device_handler(buf))) - return err; - err = scsi_dh_handler_attach(sdev, scsi_dh); - } else { - scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (!strncmp(buf, "detach", 6)) { - /* - * Detach from a device handler - */ - scsi_dh_handler_detach(sdev, scsi_dh); - err = 0; - } else if (!strncmp(buf, "activate", 8)) { - /* - * Activate a device handler - */ - if (scsi_dh->activate) - err = scsi_dh->activate(sdev, NULL, NULL); - else - err = 0; - } - } - - return err<0?err:count; -} - -static ssize_t -show_dh_state(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - - if (!sdev->scsi_dh_data) - return snprintf(buf, 20, "detached\n"); - - return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name); -} - -static struct device_attribute scsi_dh_state_attr = - __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state, - store_dh_state); - -/* - * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh - */ -static int scsi_dh_sysfs_attr_add(struct device *dev, void *data) -{ - struct scsi_device *sdev; - int err; - - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - err = device_create_file(&sdev->sdev_gendev, - &scsi_dh_state_attr); - - return 0; -} - -/* - * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh - */ -static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data) -{ - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - device_remove_file(&sdev->sdev_gendev, - &scsi_dh_state_attr); - - return 0; -} - -/* - * scsi_dh_notifier - notifier chain callback - */ -static int scsi_dh_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct scsi_device *sdev; - int err = 0; - struct scsi_device_handler *devinfo = NULL; - - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - if (action == BUS_NOTIFY_ADD_DEVICE) { - err = device_create_file(dev, &scsi_dh_state_attr); - /* don't care about err */ - devinfo = device_handler_match(NULL, sdev); - if (devinfo) - err = scsi_dh_handler_attach(sdev, devinfo); - } else if (action == BUS_NOTIFY_DEL_DEVICE) { - device_remove_file(dev, &scsi_dh_state_attr); - scsi_dh_handler_detach(sdev, NULL); - } - return err; -} - -/* - * scsi_dh_notifier_add - Callback for scsi_register_device_handler - */ -static int scsi_dh_notifier_add(struct device *dev, void *data) -{ - struct scsi_device_handler *scsi_dh = data; - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(dev)) - return 0; - - if (!get_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - if (device_handler_match(scsi_dh, sdev)) - scsi_dh_handler_attach(sdev, scsi_dh); - - put_device(dev); - - return 0; -} - -/* - * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler - */ -static int scsi_dh_notifier_remove(struct device *dev, void *data) -{ - struct scsi_device_handler *scsi_dh = data; - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(dev)) - return 0; - - if (!get_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - scsi_dh_handler_detach(sdev, scsi_dh); - - put_device(dev); - - return 0; -} - -/* - * scsi_register_device_handler - register a device handler personality - * module. - * @scsi_dh - device handler to be registered. - * - * Returns 0 on success, -EBUSY if handler already registered. - */ -int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) -{ - - if (get_device_handler(scsi_dh->name)) - return -EBUSY; - - spin_lock(&list_lock); - list_add(&scsi_dh->list, &scsi_dh_list); - spin_unlock(&list_lock); - - bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); - printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); - - return SCSI_DH_OK; -} -EXPORT_SYMBOL_GPL(scsi_register_device_handler); - -/* - * scsi_unregister_device_handler - register a device handler personality - * module. - * @scsi_dh - device handler to be unregistered. - * - * Returns 0 on success, -ENODEV if handler not registered. - */ -int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) -{ - - if (!get_device_handler(scsi_dh->name)) - return -ENODEV; - - bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, - scsi_dh_notifier_remove); - - spin_lock(&list_lock); - list_del(&scsi_dh->list); - spin_unlock(&list_lock); - printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name); - - return SCSI_DH_OK; -} -EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); - -/* - * scsi_dh_activate - activate the path associated with the scsi_device - * corresponding to the given request queue. - * Returns immediately without waiting for activation to be completed. - * @q - Request queue that is associated with the scsi_device to be - * activated. - * @fn - Function to be called upon completion of the activation. - * Function fn is called with data (below) and the error code. - * Function fn may be called from the same calling context. So, - * do not hold the lock in the caller which may be needed in fn. - * @data - data passed to the function fn upon completion. - * - */ -int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) -{ - int err = 0; - unsigned long flags; - struct scsi_device *sdev; - struct scsi_device_handler *scsi_dh = NULL; - struct device *dev = NULL; - - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (!sdev) { - spin_unlock_irqrestore(q->queue_lock, flags); - err = SCSI_DH_NOSYS; - if (fn) - fn(data, err); - return err; - } - - if (sdev->scsi_dh_data) - scsi_dh = sdev->scsi_dh_data->scsi_dh; - dev = get_device(&sdev->sdev_gendev); - if (!scsi_dh || !dev || - sdev->sdev_state == SDEV_CANCEL || - sdev->sdev_state == SDEV_DEL) - err = SCSI_DH_NOSYS; - if (sdev->sdev_state == SDEV_OFFLINE) - err = SCSI_DH_DEV_OFFLINED; - spin_unlock_irqrestore(q->queue_lock, flags); - - if (err) { - if (fn) - fn(data, err); - goto out; - } - - if (scsi_dh->activate) - err = scsi_dh->activate(sdev, fn, data); -out: - put_device(dev); - return err; -} -EXPORT_SYMBOL_GPL(scsi_dh_activate); - -/* - * scsi_dh_set_params - set the parameters for the device as per the - * string specified in params. - * @q - Request queue that is associated with the scsi_device for - * which the parameters to be set. - * @params - parameters in the following format - * "no_of_params\0param1\0param2\0param3\0...\0" - * for example, string for 2 parameters with value 10 and 21 - * is specified as "2\010\021\0". - */ -int scsi_dh_set_params(struct request_queue *q, const char *params) -{ - int err = -SCSI_DH_NOSYS; - unsigned long flags; - struct scsi_device *sdev; - struct scsi_device_handler *scsi_dh = NULL; - - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (sdev && sdev->scsi_dh_data) - scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev)) - err = 0; - spin_unlock_irqrestore(q->queue_lock, flags); - - if (err) - return err; - err = scsi_dh->set_params(sdev, params); - put_device(&sdev->sdev_gendev); - return err; -} -EXPORT_SYMBOL_GPL(scsi_dh_set_params); - -/* - * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for - * the given name. FALSE(0) otherwise. - * @name - name of the device handler. - */ -int scsi_dh_handler_exist(const char *name) -{ - return (get_device_handler(name) != NULL); -} -EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); - -/* - * scsi_dh_attach - Attach device handler - * @sdev - sdev the handler should be attached to - * @name - name of the handler to attach - */ -int scsi_dh_attach(struct request_queue *q, const char *name) -{ - unsigned long flags; - struct scsi_device *sdev; - struct scsi_device_handler *scsi_dh; - int err = 0; - - scsi_dh = get_device_handler(name); - if (!scsi_dh) - return -EINVAL; - - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (!sdev || !get_device(&sdev->sdev_gendev)) - err = -ENODEV; - spin_unlock_irqrestore(q->queue_lock, flags); - - if (!err) { - err = scsi_dh_handler_attach(sdev, scsi_dh); - put_device(&sdev->sdev_gendev); - } - return err; -} -EXPORT_SYMBOL_GPL(scsi_dh_attach); - -/* - * scsi_dh_detach - Detach device handler - * @sdev - sdev the handler should be detached from - * - * This function will detach the device handler only - * if the sdev is not part of the internal list, ie - * if it has been attached manually. - */ -void scsi_dh_detach(struct request_queue *q) -{ - unsigned long flags; - struct scsi_device *sdev; - struct scsi_device_handler *scsi_dh = NULL; - - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (!sdev || !get_device(&sdev->sdev_gendev)) - sdev = NULL; - spin_unlock_irqrestore(q->queue_lock, flags); - - if (!sdev) - return; - - if (sdev->scsi_dh_data) { - scsi_dh = sdev->scsi_dh_data->scsi_dh; - scsi_dh_handler_detach(sdev, scsi_dh); - } - put_device(&sdev->sdev_gendev); -} -EXPORT_SYMBOL_GPL(scsi_dh_detach); - -static struct notifier_block scsi_dh_nb = { - .notifier_call = scsi_dh_notifier -}; - -static int __init scsi_dh_init(void) -{ - int r; - - r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); - - if (!r) - bus_for_each_dev(&scsi_bus_type, NULL, NULL, - scsi_dh_sysfs_attr_add); - - return r; -} - -static void __exit scsi_dh_exit(void) -{ - bus_for_each_dev(&scsi_bus_type, NULL, NULL, - scsi_dh_sysfs_attr_remove); - bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); -} - -module_init(scsi_dh_init); -module_exit(scsi_dh_exit); - -MODULE_DESCRIPTION("SCSI device handler"); -MODULE_AUTHOR("Chandra Seetharaman "); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_alua.c b/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_alua.c deleted file mode 100644 index 04c5cea4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_alua.c +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Generic SCSI-3 ALUA SCSI Device Handler - * - * Copyright (C) 2007-2010 Hannes Reinecke, SUSE Linux Products GmbH. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ -#include -#include -#include -#include -#include -#include - -#define ALUA_DH_NAME "alua" -#define ALUA_DH_VER "1.3" - -#define TPGS_STATE_OPTIMIZED 0x0 -#define TPGS_STATE_NONOPTIMIZED 0x1 -#define TPGS_STATE_STANDBY 0x2 -#define TPGS_STATE_UNAVAILABLE 0x3 -#define TPGS_STATE_LBA_DEPENDENT 0x4 -#define TPGS_STATE_OFFLINE 0xe -#define TPGS_STATE_TRANSITIONING 0xf - -#define TPGS_SUPPORT_NONE 0x00 -#define TPGS_SUPPORT_OPTIMIZED 0x01 -#define TPGS_SUPPORT_NONOPTIMIZED 0x02 -#define TPGS_SUPPORT_STANDBY 0x04 -#define TPGS_SUPPORT_UNAVAILABLE 0x08 -#define TPGS_SUPPORT_LBA_DEPENDENT 0x10 -#define TPGS_SUPPORT_OFFLINE 0x40 -#define TPGS_SUPPORT_TRANSITION 0x80 - -#define TPGS_MODE_UNINITIALIZED -1 -#define TPGS_MODE_NONE 0x0 -#define TPGS_MODE_IMPLICIT 0x1 -#define TPGS_MODE_EXPLICIT 0x2 - -#define ALUA_INQUIRY_SIZE 36 -#define ALUA_FAILOVER_TIMEOUT (60 * HZ) -#define ALUA_FAILOVER_RETRIES 5 - -struct alua_dh_data { - int group_id; - int rel_port; - int tpgs; - int state; - unsigned char inq[ALUA_INQUIRY_SIZE]; - unsigned char *buff; - int bufflen; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - int senselen; - struct scsi_device *sdev; - activate_complete callback_fn; - void *callback_data; -}; - -#define ALUA_POLICY_SWITCH_CURRENT 0 -#define ALUA_POLICY_SWITCH_ALL 1 - -static char print_alua_state(int); -static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *); - -static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; - BUG_ON(scsi_dh_data == NULL); - return ((struct alua_dh_data *) scsi_dh_data->buf); -} - -static int realloc_buffer(struct alua_dh_data *h, unsigned len) -{ - if (h->buff && h->buff != h->inq) - kfree(h->buff); - - h->buff = kmalloc(len, GFP_NOIO); - if (!h->buff) { - h->buff = h->inq; - h->bufflen = ALUA_INQUIRY_SIZE; - return 1; - } - h->bufflen = len; - return 0; -} - -static struct request *get_alua_req(struct scsi_device *sdev, - void *buffer, unsigned buflen, int rw) -{ - struct request *rq; - struct request_queue *q = sdev->request_queue; - - rq = blk_get_request(q, rw, GFP_NOIO); - - if (!rq) { - sdev_printk(KERN_INFO, sdev, - "%s: blk_get_request failed\n", __func__); - return NULL; - } - - if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { - blk_put_request(rq); - sdev_printk(KERN_INFO, sdev, - "%s: blk_rq_map_kern failed\n", __func__); - return NULL; - } - - rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - rq->retries = ALUA_FAILOVER_RETRIES; - rq->timeout = ALUA_FAILOVER_TIMEOUT; - - return rq; -} - -/* - * submit_vpd_inquiry - Issue an INQUIRY VPD page 0x83 command - * @sdev: sdev the command should be sent to - */ -static int submit_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) -{ - struct request *rq; - int err = SCSI_DH_RES_TEMP_UNAVAIL; - - rq = get_alua_req(sdev, h->buff, h->bufflen, READ); - if (!rq) - goto done; - - /* Prepare the command. */ - rq->cmd[0] = INQUIRY; - rq->cmd[1] = 1; - rq->cmd[2] = 0x83; - rq->cmd[4] = h->bufflen; - rq->cmd_len = COMMAND_SIZE(INQUIRY); - - rq->sense = h->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = h->senselen = 0; - - err = blk_execute_rq(rq->q, NULL, rq, 1); - if (err == -EIO) { - sdev_printk(KERN_INFO, sdev, - "%s: evpd inquiry failed with %x\n", - ALUA_DH_NAME, rq->errors); - h->senselen = rq->sense_len; - err = SCSI_DH_IO; - } - blk_put_request(rq); -done: - return err; -} - -/* - * submit_rtpg - Issue a REPORT TARGET GROUP STATES command - * @sdev: sdev the command should be sent to - */ -static unsigned submit_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) -{ - struct request *rq; - int err = SCSI_DH_RES_TEMP_UNAVAIL; - - rq = get_alua_req(sdev, h->buff, h->bufflen, READ); - if (!rq) - goto done; - - /* Prepare the command. */ - rq->cmd[0] = MAINTENANCE_IN; - rq->cmd[1] = MI_REPORT_TARGET_PGS; - rq->cmd[6] = (h->bufflen >> 24) & 0xff; - rq->cmd[7] = (h->bufflen >> 16) & 0xff; - rq->cmd[8] = (h->bufflen >> 8) & 0xff; - rq->cmd[9] = h->bufflen & 0xff; - rq->cmd_len = COMMAND_SIZE(MAINTENANCE_IN); - - rq->sense = h->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = h->senselen = 0; - - err = blk_execute_rq(rq->q, NULL, rq, 1); - if (err == -EIO) { - sdev_printk(KERN_INFO, sdev, - "%s: rtpg failed with %x\n", - ALUA_DH_NAME, rq->errors); - h->senselen = rq->sense_len; - err = SCSI_DH_IO; - } - blk_put_request(rq); -done: - return err; -} - -/* - * alua_stpg - Evaluate SET TARGET GROUP STATES - * @sdev: the device to be evaluated - * @state: the new target group state - * - * Send a SET TARGET GROUP STATES command to the device. - * We only have to test here if we should resubmit the command; - * any other error is assumed as a failure. - */ -static void stpg_endio(struct request *req, int error) -{ - struct alua_dh_data *h = req->end_io_data; - struct scsi_sense_hdr sense_hdr; - unsigned err = SCSI_DH_OK; - - if (error || host_byte(req->errors) != DID_OK || - msg_byte(req->errors) != COMMAND_COMPLETE) { - err = SCSI_DH_IO; - goto done; - } - - if (h->senselen > 0) { - err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, - &sense_hdr); - if (!err) { - err = SCSI_DH_IO; - goto done; - } - err = alua_check_sense(h->sdev, &sense_hdr); - if (err == ADD_TO_MLQUEUE) { - err = SCSI_DH_RETRY; - goto done; - } - sdev_printk(KERN_INFO, h->sdev, - "%s: stpg sense code: %02x/%02x/%02x\n", - ALUA_DH_NAME, sense_hdr.sense_key, - sense_hdr.asc, sense_hdr.ascq); - err = SCSI_DH_IO; - } - if (err == SCSI_DH_OK) { - h->state = TPGS_STATE_OPTIMIZED; - sdev_printk(KERN_INFO, h->sdev, - "%s: port group %02x switched to state %c\n", - ALUA_DH_NAME, h->group_id, - print_alua_state(h->state)); - } -done: - req->end_io_data = NULL; - __blk_put_request(req->q, req); - if (h->callback_fn) { - h->callback_fn(h->callback_data, err); - h->callback_fn = h->callback_data = NULL; - } - return; -} - -/* - * submit_stpg - Issue a SET TARGET GROUP STATES command - * - * Currently we're only setting the current target port group state - * to 'active/optimized' and let the array firmware figure out - * the states of the remaining groups. - */ -static unsigned submit_stpg(struct alua_dh_data *h) -{ - struct request *rq; - int stpg_len = 8; - struct scsi_device *sdev = h->sdev; - - /* Prepare the data buffer */ - memset(h->buff, 0, stpg_len); - h->buff[4] = TPGS_STATE_OPTIMIZED & 0x0f; - h->buff[6] = (h->group_id >> 8) & 0xff; - h->buff[7] = h->group_id & 0xff; - - rq = get_alua_req(sdev, h->buff, stpg_len, WRITE); - if (!rq) - return SCSI_DH_RES_TEMP_UNAVAIL; - - /* Prepare the command. */ - rq->cmd[0] = MAINTENANCE_OUT; - rq->cmd[1] = MO_SET_TARGET_PGS; - rq->cmd[6] = (stpg_len >> 24) & 0xff; - rq->cmd[7] = (stpg_len >> 16) & 0xff; - rq->cmd[8] = (stpg_len >> 8) & 0xff; - rq->cmd[9] = stpg_len & 0xff; - rq->cmd_len = COMMAND_SIZE(MAINTENANCE_OUT); - - rq->sense = h->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = h->senselen = 0; - rq->end_io_data = h; - - blk_execute_rq_nowait(rq->q, NULL, rq, 1, stpg_endio); - return SCSI_DH_OK; -} - -/* - * alua_check_tpgs - Evaluate TPGS setting - * @sdev: device to be checked - * - * Examine the TPGS setting of the sdev to find out if ALUA - * is supported. - */ -static int alua_check_tpgs(struct scsi_device *sdev, struct alua_dh_data *h) -{ - int err = SCSI_DH_OK; - - h->tpgs = scsi_device_tpgs(sdev); - switch (h->tpgs) { - case TPGS_MODE_EXPLICIT|TPGS_MODE_IMPLICIT: - sdev_printk(KERN_INFO, sdev, - "%s: supports implicit and explicit TPGS\n", - ALUA_DH_NAME); - break; - case TPGS_MODE_EXPLICIT: - sdev_printk(KERN_INFO, sdev, "%s: supports explicit TPGS\n", - ALUA_DH_NAME); - break; - case TPGS_MODE_IMPLICIT: - sdev_printk(KERN_INFO, sdev, "%s: supports implicit TPGS\n", - ALUA_DH_NAME); - break; - default: - h->tpgs = TPGS_MODE_NONE; - sdev_printk(KERN_INFO, sdev, "%s: not supported\n", - ALUA_DH_NAME); - err = SCSI_DH_DEV_UNSUPP; - break; - } - - return err; -} - -/* - * alua_vpd_inquiry - Evaluate INQUIRY vpd page 0x83 - * @sdev: device to be checked - * - * Extract the relative target port and the target port group - * descriptor from the list of identificators. - */ -static int alua_vpd_inquiry(struct scsi_device *sdev, struct alua_dh_data *h) -{ - int len; - unsigned err; - unsigned char *d; - - retry: - err = submit_vpd_inquiry(sdev, h); - - if (err != SCSI_DH_OK) - return err; - - /* Check if vpd page exceeds initial buffer */ - len = (h->buff[2] << 8) + h->buff[3] + 4; - if (len > h->bufflen) { - /* Resubmit with the correct length */ - if (realloc_buffer(h, len)) { - sdev_printk(KERN_WARNING, sdev, - "%s: kmalloc buffer failed\n", - ALUA_DH_NAME); - /* Temporary failure, bypass */ - return SCSI_DH_DEV_TEMP_BUSY; - } - goto retry; - } - - /* - * Now look for the correct descriptor. - */ - d = h->buff + 4; - while (d < h->buff + len) { - switch (d[1] & 0xf) { - case 0x4: - /* Relative target port */ - h->rel_port = (d[6] << 8) + d[7]; - break; - case 0x5: - /* Target port group */ - h->group_id = (d[6] << 8) + d[7]; - break; - default: - break; - } - d += d[3] + 4; - } - - if (h->group_id == -1) { - /* - * Internal error; TPGS supported but required - * VPD identification descriptors not present. - * Disable ALUA support - */ - sdev_printk(KERN_INFO, sdev, - "%s: No target port descriptors found\n", - ALUA_DH_NAME); - h->state = TPGS_STATE_OPTIMIZED; - h->tpgs = TPGS_MODE_NONE; - err = SCSI_DH_DEV_UNSUPP; - } else { - sdev_printk(KERN_INFO, sdev, - "%s: port group %02x rel port %02x\n", - ALUA_DH_NAME, h->group_id, h->rel_port); - } - - return err; -} - -static char print_alua_state(int state) -{ - switch (state) { - case TPGS_STATE_OPTIMIZED: - return 'A'; - case TPGS_STATE_NONOPTIMIZED: - return 'N'; - case TPGS_STATE_STANDBY: - return 'S'; - case TPGS_STATE_UNAVAILABLE: - return 'U'; - case TPGS_STATE_LBA_DEPENDENT: - return 'L'; - case TPGS_STATE_OFFLINE: - return 'O'; - case TPGS_STATE_TRANSITIONING: - return 'T'; - default: - return 'X'; - } -} - -static int alua_check_sense(struct scsi_device *sdev, - struct scsi_sense_hdr *sense_hdr) -{ - switch (sense_hdr->sense_key) { - case NOT_READY: - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0a) - /* - * LUN Not Accessible - ALUA state transition - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0b) - /* - * LUN Not Accessible -- Target port in standby state - */ - return SUCCESS; - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x0c) - /* - * LUN Not Accessible -- Target port in unavailable state - */ - return SUCCESS; - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x12) - /* - * LUN Not Ready -- Offline - */ - return SUCCESS; - break; - case UNIT_ATTENTION: - if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) - /* - * Power On, Reset, or Bus Device Reset, just retry. - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x01) - /* - * Mode Parameters Changed - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x06) - /* - * ALUA state changed - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x2a && sense_hdr->ascq == 0x07) - /* - * Implicit ALUA state transition failed - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x03) - /* - * Inquiry data has changed - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x3f && sense_hdr->ascq == 0x0e) - /* - * REPORTED_LUNS_DATA_HAS_CHANGED is reported - * when switching controllers on targets like - * Intel Multi-Flex. We can just retry. - */ - return ADD_TO_MLQUEUE; - break; - } - - return SCSI_RETURN_NOT_HANDLED; -} - -/* - * alua_rtpg - Evaluate REPORT TARGET GROUP STATES - * @sdev: the device to be evaluated. - * - * Evaluate the Target Port Group State. - * Returns SCSI_DH_DEV_OFFLINED if the path is - * found to be unusable. - */ -static int alua_rtpg(struct scsi_device *sdev, struct alua_dh_data *h) -{ - struct scsi_sense_hdr sense_hdr; - int len, k, off, valid_states = 0; - unsigned char *ucp; - unsigned err; - unsigned long expiry, interval = 1000; - - expiry = round_jiffies_up(jiffies + ALUA_FAILOVER_TIMEOUT); - retry: - err = submit_rtpg(sdev, h); - - if (err == SCSI_DH_IO && h->senselen > 0) { - err = scsi_normalize_sense(h->sense, SCSI_SENSE_BUFFERSIZE, - &sense_hdr); - if (!err) - return SCSI_DH_IO; - - err = alua_check_sense(sdev, &sense_hdr); - if (err == ADD_TO_MLQUEUE && time_before(jiffies, expiry)) - goto retry; - sdev_printk(KERN_INFO, sdev, - "%s: rtpg sense code %02x/%02x/%02x\n", - ALUA_DH_NAME, sense_hdr.sense_key, - sense_hdr.asc, sense_hdr.ascq); - err = SCSI_DH_IO; - } - if (err != SCSI_DH_OK) - return err; - - len = (h->buff[0] << 24) + (h->buff[1] << 16) + - (h->buff[2] << 8) + h->buff[3] + 4; - - if (len > h->bufflen) { - /* Resubmit with the correct length */ - if (realloc_buffer(h, len)) { - sdev_printk(KERN_WARNING, sdev, - "%s: kmalloc buffer failed\n",__func__); - /* Temporary failure, bypass */ - return SCSI_DH_DEV_TEMP_BUSY; - } - goto retry; - } - - for (k = 4, ucp = h->buff + 4; k < len; k += off, ucp += off) { - if (h->group_id == (ucp[2] << 8) + ucp[3]) { - h->state = ucp[0] & 0x0f; - valid_states = ucp[1]; - } - off = 8 + (ucp[7] * 4); - } - - sdev_printk(KERN_INFO, sdev, - "%s: port group %02x state %c supports %c%c%c%c%c%c%c\n", - ALUA_DH_NAME, h->group_id, print_alua_state(h->state), - valid_states&TPGS_SUPPORT_TRANSITION?'T':'t', - valid_states&TPGS_SUPPORT_OFFLINE?'O':'o', - valid_states&TPGS_SUPPORT_LBA_DEPENDENT?'L':'l', - valid_states&TPGS_SUPPORT_UNAVAILABLE?'U':'u', - valid_states&TPGS_SUPPORT_STANDBY?'S':'s', - valid_states&TPGS_SUPPORT_NONOPTIMIZED?'N':'n', - valid_states&TPGS_SUPPORT_OPTIMIZED?'A':'a'); - - switch (h->state) { - case TPGS_STATE_TRANSITIONING: - if (time_before(jiffies, expiry)) { - /* State transition, retry */ - interval *= 2; - msleep(interval); - goto retry; - } - /* Transitioning time exceeded, set port to standby */ - err = SCSI_DH_RETRY; - h->state = TPGS_STATE_STANDBY; - break; - case TPGS_STATE_OFFLINE: - case TPGS_STATE_UNAVAILABLE: - /* Path unusable for unavailable/offline */ - err = SCSI_DH_DEV_OFFLINED; - break; - default: - /* Useable path if active */ - err = SCSI_DH_OK; - break; - } - return err; -} - -/* - * alua_initialize - Initialize ALUA state - * @sdev: the device to be initialized - * - * For the prep_fn to work correctly we have - * to initialize the ALUA state for the device. - */ -static int alua_initialize(struct scsi_device *sdev, struct alua_dh_data *h) -{ - int err; - - err = alua_check_tpgs(sdev, h); - if (err != SCSI_DH_OK) - goto out; - - err = alua_vpd_inquiry(sdev, h); - if (err != SCSI_DH_OK) - goto out; - - err = alua_rtpg(sdev, h); - if (err != SCSI_DH_OK) - goto out; - -out: - return err; -} - -/* - * alua_activate - activate a path - * @sdev: device on the path to be activated - * - * We're currently switching the port group to be activated only and - * let the array figure out the rest. - * There may be other arrays which require us to switch all port groups - * based on a certain policy. But until we actually encounter them it - * should be okay. - */ -static int alua_activate(struct scsi_device *sdev, - activate_complete fn, void *data) -{ - struct alua_dh_data *h = get_alua_data(sdev); - int err = SCSI_DH_OK; - - err = alua_rtpg(sdev, h); - if (err != SCSI_DH_OK) - goto out; - - if (h->tpgs & TPGS_MODE_EXPLICIT && - h->state != TPGS_STATE_OPTIMIZED && - h->state != TPGS_STATE_LBA_DEPENDENT) { - h->callback_fn = fn; - h->callback_data = data; - err = submit_stpg(h); - if (err == SCSI_DH_OK) - return 0; - h->callback_fn = h->callback_data = NULL; - } - -out: - if (fn) - fn(data, err); - return 0; -} - -/* - * alua_prep_fn - request callback - * - * Fail I/O to all paths not in state - * active/optimized or active/non-optimized. - */ -static int alua_prep_fn(struct scsi_device *sdev, struct request *req) -{ - struct alua_dh_data *h = get_alua_data(sdev); - int ret = BLKPREP_OK; - - if (h->state == TPGS_STATE_TRANSITIONING) - ret = BLKPREP_DEFER; - else if (h->state != TPGS_STATE_OPTIMIZED && - h->state != TPGS_STATE_NONOPTIMIZED && - h->state != TPGS_STATE_LBA_DEPENDENT) { - ret = BLKPREP_KILL; - req->cmd_flags |= REQ_QUIET; - } - return ret; - -} - -static bool alua_match(struct scsi_device *sdev) -{ - return (scsi_device_tpgs(sdev) != 0); -} - -static int alua_bus_attach(struct scsi_device *sdev); -static void alua_bus_detach(struct scsi_device *sdev); - -static struct scsi_device_handler alua_dh = { - .name = ALUA_DH_NAME, - .module = THIS_MODULE, - .attach = alua_bus_attach, - .detach = alua_bus_detach, - .prep_fn = alua_prep_fn, - .check_sense = alua_check_sense, - .activate = alua_activate, - .match = alua_match, -}; - -/* - * alua_bus_attach - Attach device handler - * @sdev: device to be attached to - */ -static int alua_bus_attach(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data; - struct alua_dh_data *h; - unsigned long flags; - int err = SCSI_DH_OK; - - scsi_dh_data = kzalloc(sizeof(*scsi_dh_data) - + sizeof(*h) , GFP_KERNEL); - if (!scsi_dh_data) { - sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n", - ALUA_DH_NAME); - return -ENOMEM; - } - - scsi_dh_data->scsi_dh = &alua_dh; - h = (struct alua_dh_data *) scsi_dh_data->buf; - h->tpgs = TPGS_MODE_UNINITIALIZED; - h->state = TPGS_STATE_OPTIMIZED; - h->group_id = -1; - h->rel_port = -1; - h->buff = h->inq; - h->bufflen = ALUA_INQUIRY_SIZE; - h->sdev = sdev; - - err = alua_initialize(sdev, h); - if ((err != SCSI_DH_OK) && (err != SCSI_DH_DEV_OFFLINED)) - goto failed; - - if (!try_module_get(THIS_MODULE)) - goto failed; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - sdev->scsi_dh_data = scsi_dh_data; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME); - - return 0; - -failed: - kfree(scsi_dh_data); - sdev_printk(KERN_ERR, sdev, "%s: not attached\n", ALUA_DH_NAME); - return -EINVAL; -} - -/* - * alua_bus_detach - Detach device handler - * @sdev: device to be detached from - */ -static void alua_bus_detach(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data; - struct alua_dh_data *h; - unsigned long flags; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - scsi_dh_data = sdev->scsi_dh_data; - sdev->scsi_dh_data = NULL; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - - h = (struct alua_dh_data *) scsi_dh_data->buf; - if (h->buff && h->inq != h->buff) - kfree(h->buff); - kfree(scsi_dh_data); - module_put(THIS_MODULE); - sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", ALUA_DH_NAME); -} - -static int __init alua_init(void) -{ - int r; - - r = scsi_register_device_handler(&alua_dh); - if (r != 0) - printk(KERN_ERR "%s: Failed to register scsi device handler", - ALUA_DH_NAME); - return r; -} - -static void __exit alua_exit(void) -{ - scsi_unregister_device_handler(&alua_dh); -} - -module_init(alua_init); -module_exit(alua_exit); - -MODULE_DESCRIPTION("DM Multipath ALUA support"); -MODULE_AUTHOR("Hannes Reinecke "); -MODULE_LICENSE("GPL"); -MODULE_VERSION(ALUA_DH_VER); diff --git a/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_emc.c b/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_emc.c deleted file mode 100644 index e1c8be06..00000000 --- a/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_emc.c +++ /dev/null @@ -1,755 +0,0 @@ -/* - * Target driver for EMC CLARiiON AX/CX-series hardware. - * Based on code from Lars Marowsky-Bree - * and Ed Goggin . - * - * Copyright (C) 2006 Red Hat, Inc. All rights reserved. - * Copyright (C) 2006 Mike Christie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include - -#define CLARIION_NAME "emc" - -#define CLARIION_TRESPASS_PAGE 0x22 -#define CLARIION_BUFFER_SIZE 0xFC -#define CLARIION_TIMEOUT (60 * HZ) -#define CLARIION_RETRIES 3 -#define CLARIION_UNBOUND_LU -1 -#define CLARIION_SP_A 0 -#define CLARIION_SP_B 1 - -/* Flags */ -#define CLARIION_SHORT_TRESPASS 1 -#define CLARIION_HONOR_RESERVATIONS 2 - -/* LUN states */ -#define CLARIION_LUN_UNINITIALIZED -1 -#define CLARIION_LUN_UNBOUND 0 -#define CLARIION_LUN_BOUND 1 -#define CLARIION_LUN_OWNED 2 - -static unsigned char long_trespass[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - CLARIION_TRESPASS_PAGE, /* Page code */ - 0x09, /* Page length - 2 */ - 0x01, /* Trespass code */ - 0xff, 0xff, /* Trespass target */ - 0, 0, 0, 0, 0, 0 /* Reserved bytes / unknown */ -}; - -static unsigned char short_trespass[] = { - 0, 0, 0, 0, - CLARIION_TRESPASS_PAGE, /* Page code */ - 0x02, /* Page length - 2 */ - 0x01, /* Trespass code */ - 0xff, /* Trespass target */ -}; - -static const char * lun_state[] = -{ - "not bound", - "bound", - "owned", -}; - -struct clariion_dh_data { - /* - * Flags: - * CLARIION_SHORT_TRESPASS - * Use short trespass command (FC-series) or the long version - * (default for AX/CX CLARiiON arrays). - * - * CLARIION_HONOR_RESERVATIONS - * Whether or not (default) to honor SCSI reservations when - * initiating a switch-over. - */ - unsigned flags; - /* - * I/O buffer for both MODE_SELECT and INQUIRY commands. - */ - unsigned char buffer[CLARIION_BUFFER_SIZE]; - /* - * SCSI sense buffer for commands -- assumes serial issuance - * and completion sequence of all commands for same multipath. - */ - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - unsigned int senselen; - /* - * LUN state - */ - int lun_state; - /* - * SP Port number - */ - int port; - /* - * which SP (A=0,B=1,UNBOUND=-1) is the default SP for this - * path's mapped LUN - */ - int default_sp; - /* - * which SP (A=0,B=1,UNBOUND=-1) is the active SP for this - * path's mapped LUN - */ - int current_sp; -}; - -static inline struct clariion_dh_data - *get_clariion_data(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; - BUG_ON(scsi_dh_data == NULL); - return ((struct clariion_dh_data *) scsi_dh_data->buf); -} - -/* - * Parse MODE_SELECT cmd reply. - */ -static int trespass_endio(struct scsi_device *sdev, char *sense) -{ - int err = SCSI_DH_IO; - struct scsi_sense_hdr sshdr; - - if (!scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { - sdev_printk(KERN_ERR, sdev, "%s: Found valid sense data 0x%2x, " - "0x%2x, 0x%2x while sending CLARiiON trespass " - "command.\n", CLARIION_NAME, sshdr.sense_key, - sshdr.asc, sshdr.ascq); - - if ((sshdr.sense_key == 0x05) && (sshdr.asc == 0x04) && - (sshdr.ascq == 0x00)) { - /* - * Array based copy in progress -- do not send - * mode_select or copy will be aborted mid-stream. - */ - sdev_printk(KERN_INFO, sdev, "%s: Array Based Copy in " - "progress while sending CLARiiON trespass " - "command.\n", CLARIION_NAME); - err = SCSI_DH_DEV_TEMP_BUSY; - } else if ((sshdr.sense_key == 0x02) && (sshdr.asc == 0x04) && - (sshdr.ascq == 0x03)) { - /* - * LUN Not Ready - Manual Intervention Required - * indicates in-progress ucode upgrade (NDU). - */ - sdev_printk(KERN_INFO, sdev, "%s: Detected in-progress " - "ucode upgrade NDU operation while sending " - "CLARiiON trespass command.\n", CLARIION_NAME); - err = SCSI_DH_DEV_TEMP_BUSY; - } else - err = SCSI_DH_DEV_FAILED; - } else { - sdev_printk(KERN_INFO, sdev, - "%s: failed to send MODE SELECT, no sense available\n", - CLARIION_NAME); - } - return err; -} - -static int parse_sp_info_reply(struct scsi_device *sdev, - struct clariion_dh_data *csdev) -{ - int err = SCSI_DH_OK; - - /* check for in-progress ucode upgrade (NDU) */ - if (csdev->buffer[48] != 0) { - sdev_printk(KERN_NOTICE, sdev, "%s: Detected in-progress " - "ucode upgrade NDU operation while finding " - "current active SP.", CLARIION_NAME); - err = SCSI_DH_DEV_TEMP_BUSY; - goto out; - } - if (csdev->buffer[4] > 2) { - /* Invalid buffer format */ - sdev_printk(KERN_NOTICE, sdev, - "%s: invalid VPD page 0xC0 format\n", - CLARIION_NAME); - err = SCSI_DH_NOSYS; - goto out; - } - switch (csdev->buffer[28] & 0x0f) { - case 6: - sdev_printk(KERN_NOTICE, sdev, - "%s: ALUA failover mode detected\n", - CLARIION_NAME); - break; - case 4: - /* Linux failover */ - break; - default: - sdev_printk(KERN_WARNING, sdev, - "%s: Invalid failover mode %d\n", - CLARIION_NAME, csdev->buffer[28] & 0x0f); - err = SCSI_DH_NOSYS; - goto out; - } - - csdev->default_sp = csdev->buffer[5]; - csdev->lun_state = csdev->buffer[4]; - csdev->current_sp = csdev->buffer[8]; - csdev->port = csdev->buffer[7]; - -out: - return err; -} - -#define emc_default_str "FC (Legacy)" - -static char * parse_sp_model(struct scsi_device *sdev, unsigned char *buffer) -{ - unsigned char len = buffer[4] + 5; - char *sp_model = NULL; - unsigned char sp_len, serial_len; - - if (len < 160) { - sdev_printk(KERN_WARNING, sdev, - "%s: Invalid information section length %d\n", - CLARIION_NAME, len); - /* Check for old FC arrays */ - if (!strncmp(buffer + 8, "DGC", 3)) { - /* Old FC array, not supporting extended information */ - sp_model = emc_default_str; - } - goto out; - } - - /* - * Parse extended information for SP model number - */ - serial_len = buffer[160]; - if (serial_len == 0 || serial_len + 161 > len) { - sdev_printk(KERN_WARNING, sdev, - "%s: Invalid array serial number length %d\n", - CLARIION_NAME, serial_len); - goto out; - } - sp_len = buffer[99]; - if (sp_len == 0 || serial_len + sp_len + 161 > len) { - sdev_printk(KERN_WARNING, sdev, - "%s: Invalid model number length %d\n", - CLARIION_NAME, sp_len); - goto out; - } - sp_model = &buffer[serial_len + 161]; - /* Strip whitespace at the end */ - while (sp_len > 1 && sp_model[sp_len - 1] == ' ') - sp_len--; - - sp_model[sp_len] = '\0'; - -out: - return sp_model; -} - -/* - * Get block request for REQ_BLOCK_PC command issued to path. Currently - * limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands. - * - * Uses data and sense buffers in hardware handler context structure and - * assumes serial servicing of commands, both issuance and completion. - */ -static struct request *get_req(struct scsi_device *sdev, int cmd, - unsigned char *buffer) -{ - struct request *rq; - int len = 0; - - rq = blk_get_request(sdev->request_queue, - (cmd != INQUIRY) ? WRITE : READ, GFP_NOIO); - if (!rq) { - sdev_printk(KERN_INFO, sdev, "get_req: blk_get_request failed"); - return NULL; - } - - rq->cmd_len = COMMAND_SIZE(cmd); - rq->cmd[0] = cmd; - - switch (cmd) { - case MODE_SELECT: - len = sizeof(short_trespass); - rq->cmd[1] = 0x10; - rq->cmd[4] = len; - break; - case MODE_SELECT_10: - len = sizeof(long_trespass); - rq->cmd[1] = 0x10; - rq->cmd[8] = len; - break; - case INQUIRY: - len = CLARIION_BUFFER_SIZE; - rq->cmd[4] = len; - memset(buffer, 0, len); - break; - default: - BUG_ON(1); - break; - } - - rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - rq->timeout = CLARIION_TIMEOUT; - rq->retries = CLARIION_RETRIES; - - if (blk_rq_map_kern(rq->q, rq, buffer, len, GFP_NOIO)) { - blk_put_request(rq); - return NULL; - } - - return rq; -} - -static int send_inquiry_cmd(struct scsi_device *sdev, int page, - struct clariion_dh_data *csdev) -{ - struct request *rq = get_req(sdev, INQUIRY, csdev->buffer); - int err; - - if (!rq) - return SCSI_DH_RES_TEMP_UNAVAIL; - - rq->sense = csdev->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = csdev->senselen = 0; - - rq->cmd[0] = INQUIRY; - if (page != 0) { - rq->cmd[1] = 1; - rq->cmd[2] = page; - } - err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); - if (err == -EIO) { - sdev_printk(KERN_INFO, sdev, - "%s: failed to send %s INQUIRY: %x\n", - CLARIION_NAME, page?"EVPD":"standard", - rq->errors); - csdev->senselen = rq->sense_len; - err = SCSI_DH_IO; - } - - blk_put_request(rq); - - return err; -} - -static int send_trespass_cmd(struct scsi_device *sdev, - struct clariion_dh_data *csdev) -{ - struct request *rq; - unsigned char *page22; - int err, len, cmd; - - if (csdev->flags & CLARIION_SHORT_TRESPASS) { - page22 = short_trespass; - if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) - /* Set Honor Reservations bit */ - page22[6] |= 0x80; - len = sizeof(short_trespass); - cmd = MODE_SELECT; - } else { - page22 = long_trespass; - if (!(csdev->flags & CLARIION_HONOR_RESERVATIONS)) - /* Set Honor Reservations bit */ - page22[10] |= 0x80; - len = sizeof(long_trespass); - cmd = MODE_SELECT_10; - } - BUG_ON((len > CLARIION_BUFFER_SIZE)); - memcpy(csdev->buffer, page22, len); - - rq = get_req(sdev, cmd, csdev->buffer); - if (!rq) - return SCSI_DH_RES_TEMP_UNAVAIL; - - rq->sense = csdev->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = csdev->senselen = 0; - - err = blk_execute_rq(sdev->request_queue, NULL, rq, 1); - if (err == -EIO) { - if (rq->sense_len) { - err = trespass_endio(sdev, csdev->sense); - } else { - sdev_printk(KERN_INFO, sdev, - "%s: failed to send MODE SELECT: %x\n", - CLARIION_NAME, rq->errors); - } - } - - blk_put_request(rq); - - return err; -} - -static int clariion_check_sense(struct scsi_device *sdev, - struct scsi_sense_hdr *sense_hdr) -{ - switch (sense_hdr->sense_key) { - case NOT_READY: - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x03) - /* - * LUN Not Ready - Manual Intervention Required - * indicates this is a passive path. - * - * FIXME: However, if this is seen and EVPD C0 - * indicates that this is due to a NDU in - * progress, we should set FAIL_PATH too. - * This indicates we might have to do a SCSI - * inquiry in the end_io path. Ugh. - * - * Can return FAILED only when we want the error - * recovery process to kick in. - */ - return SUCCESS; - break; - case ILLEGAL_REQUEST: - if (sense_hdr->asc == 0x25 && sense_hdr->ascq == 0x01) - /* - * An array based copy is in progress. Do not - * fail the path, do not bypass to another PG, - * do not retry. Fail the IO immediately. - * (Actually this is the same conclusion as in - * the default handler, but lets make sure.) - * - * Can return FAILED only when we want the error - * recovery process to kick in. - */ - return SUCCESS; - break; - case UNIT_ATTENTION: - if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) - /* - * Unit Attention Code. This is the first IO - * to the new path, so just retry. - */ - return ADD_TO_MLQUEUE; - break; - } - - return SCSI_RETURN_NOT_HANDLED; -} - -static int clariion_prep_fn(struct scsi_device *sdev, struct request *req) -{ - struct clariion_dh_data *h = get_clariion_data(sdev); - int ret = BLKPREP_OK; - - if (h->lun_state != CLARIION_LUN_OWNED) { - ret = BLKPREP_KILL; - req->cmd_flags |= REQ_QUIET; - } - return ret; - -} - -static int clariion_std_inquiry(struct scsi_device *sdev, - struct clariion_dh_data *csdev) -{ - int err; - char *sp_model; - - err = send_inquiry_cmd(sdev, 0, csdev); - if (err != SCSI_DH_OK && csdev->senselen) { - struct scsi_sense_hdr sshdr; - - if (scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, - &sshdr)) { - sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " - "%02x/%02x/%02x\n", CLARIION_NAME, - sshdr.sense_key, sshdr.asc, sshdr.ascq); - } - err = SCSI_DH_IO; - goto out; - } - - sp_model = parse_sp_model(sdev, csdev->buffer); - if (!sp_model) { - err = SCSI_DH_DEV_UNSUPP; - goto out; - } - - /* - * FC Series arrays do not support long trespass - */ - if (!strlen(sp_model) || !strncmp(sp_model, "FC",2)) - csdev->flags |= CLARIION_SHORT_TRESPASS; - - sdev_printk(KERN_INFO, sdev, - "%s: detected Clariion %s, flags %x\n", - CLARIION_NAME, sp_model, csdev->flags); -out: - return err; -} - -static int clariion_send_inquiry(struct scsi_device *sdev, - struct clariion_dh_data *csdev) -{ - int err, retry = CLARIION_RETRIES; - -retry: - err = send_inquiry_cmd(sdev, 0xC0, csdev); - if (err != SCSI_DH_OK && csdev->senselen) { - struct scsi_sense_hdr sshdr; - - err = scsi_normalize_sense(csdev->sense, SCSI_SENSE_BUFFERSIZE, - &sshdr); - if (!err) - return SCSI_DH_IO; - - err = clariion_check_sense(sdev, &sshdr); - if (retry > 0 && err == ADD_TO_MLQUEUE) { - retry--; - goto retry; - } - sdev_printk(KERN_ERR, sdev, "%s: INQUIRY sense code " - "%02x/%02x/%02x\n", CLARIION_NAME, - sshdr.sense_key, sshdr.asc, sshdr.ascq); - err = SCSI_DH_IO; - } else { - err = parse_sp_info_reply(sdev, csdev); - } - return err; -} - -static int clariion_activate(struct scsi_device *sdev, - activate_complete fn, void *data) -{ - struct clariion_dh_data *csdev = get_clariion_data(sdev); - int result; - - result = clariion_send_inquiry(sdev, csdev); - if (result != SCSI_DH_OK) - goto done; - - if (csdev->lun_state == CLARIION_LUN_OWNED) - goto done; - - result = send_trespass_cmd(sdev, csdev); - if (result != SCSI_DH_OK) - goto done; - sdev_printk(KERN_INFO, sdev,"%s: %s trespass command sent\n", - CLARIION_NAME, - csdev->flags&CLARIION_SHORT_TRESPASS?"short":"long" ); - - /* Update status */ - result = clariion_send_inquiry(sdev, csdev); - if (result != SCSI_DH_OK) - goto done; - -done: - sdev_printk(KERN_INFO, sdev, - "%s: at SP %c Port %d (%s, default SP %c)\n", - CLARIION_NAME, csdev->current_sp + 'A', - csdev->port, lun_state[csdev->lun_state], - csdev->default_sp + 'A'); - - if (fn) - fn(data, result); - return 0; -} -/* - * params - parameters in the following format - * "no_of_params\0param1\0param2\0param3\0...\0" - * for example, string for 2 parameters with value 10 and 21 - * is specified as "2\010\021\0". - */ -static int clariion_set_params(struct scsi_device *sdev, const char *params) -{ - struct clariion_dh_data *csdev = get_clariion_data(sdev); - unsigned int hr = 0, st = 0, argc; - const char *p = params; - int result = SCSI_DH_OK; - - if ((sscanf(params, "%u", &argc) != 1) || (argc != 2)) - return -EINVAL; - - while (*p++) - ; - if ((sscanf(p, "%u", &st) != 1) || (st > 1)) - return -EINVAL; - - while (*p++) - ; - if ((sscanf(p, "%u", &hr) != 1) || (hr > 1)) - return -EINVAL; - - if (st) - csdev->flags |= CLARIION_SHORT_TRESPASS; - else - csdev->flags &= ~CLARIION_SHORT_TRESPASS; - - if (hr) - csdev->flags |= CLARIION_HONOR_RESERVATIONS; - else - csdev->flags &= ~CLARIION_HONOR_RESERVATIONS; - - /* - * If this path is owned, we have to send a trespass command - * with the new parameters. If not, simply return. Next trespass - * command would use the parameters. - */ - if (csdev->lun_state != CLARIION_LUN_OWNED) - goto done; - - csdev->lun_state = CLARIION_LUN_UNINITIALIZED; - result = send_trespass_cmd(sdev, csdev); - if (result != SCSI_DH_OK) - goto done; - - /* Update status */ - result = clariion_send_inquiry(sdev, csdev); - -done: - return result; -} - -static const struct scsi_dh_devlist clariion_dev_list[] = { - {"DGC", "RAID"}, - {"DGC", "DISK"}, - {"DGC", "VRAID"}, - {NULL, NULL}, -}; - -static bool clariion_match(struct scsi_device *sdev) -{ - int i; - - if (scsi_device_tpgs(sdev)) - return false; - - for (i = 0; clariion_dev_list[i].vendor; i++) { - if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor, - strlen(clariion_dev_list[i].vendor)) && - !strncmp(sdev->model, clariion_dev_list[i].model, - strlen(clariion_dev_list[i].model))) { - return true; - } - } - return false; -} - -static int clariion_bus_attach(struct scsi_device *sdev); -static void clariion_bus_detach(struct scsi_device *sdev); - -static struct scsi_device_handler clariion_dh = { - .name = CLARIION_NAME, - .module = THIS_MODULE, - .devlist = clariion_dev_list, - .attach = clariion_bus_attach, - .detach = clariion_bus_detach, - .check_sense = clariion_check_sense, - .activate = clariion_activate, - .prep_fn = clariion_prep_fn, - .set_params = clariion_set_params, - .match = clariion_match, -}; - -static int clariion_bus_attach(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data; - struct clariion_dh_data *h; - unsigned long flags; - int err; - - scsi_dh_data = kzalloc(sizeof(*scsi_dh_data) - + sizeof(*h) , GFP_KERNEL); - if (!scsi_dh_data) { - sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n", - CLARIION_NAME); - return -ENOMEM; - } - - scsi_dh_data->scsi_dh = &clariion_dh; - h = (struct clariion_dh_data *) scsi_dh_data->buf; - h->lun_state = CLARIION_LUN_UNINITIALIZED; - h->default_sp = CLARIION_UNBOUND_LU; - h->current_sp = CLARIION_UNBOUND_LU; - - err = clariion_std_inquiry(sdev, h); - if (err != SCSI_DH_OK) - goto failed; - - err = clariion_send_inquiry(sdev, h); - if (err != SCSI_DH_OK) - goto failed; - - if (!try_module_get(THIS_MODULE)) - goto failed; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - sdev->scsi_dh_data = scsi_dh_data; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - - sdev_printk(KERN_INFO, sdev, - "%s: connected to SP %c Port %d (%s, default SP %c)\n", - CLARIION_NAME, h->current_sp + 'A', - h->port, lun_state[h->lun_state], - h->default_sp + 'A'); - - return 0; - -failed: - kfree(scsi_dh_data); - sdev_printk(KERN_ERR, sdev, "%s: not attached\n", - CLARIION_NAME); - return -EINVAL; -} - -static void clariion_bus_detach(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data; - unsigned long flags; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - scsi_dh_data = sdev->scsi_dh_data; - sdev->scsi_dh_data = NULL; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - - sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", - CLARIION_NAME); - - kfree(scsi_dh_data); - module_put(THIS_MODULE); -} - -static int __init clariion_init(void) -{ - int r; - - r = scsi_register_device_handler(&clariion_dh); - if (r != 0) - printk(KERN_ERR "%s: Failed to register scsi device handler.", - CLARIION_NAME); - return r; -} - -static void __exit clariion_exit(void) -{ - scsi_unregister_device_handler(&clariion_dh); -} - -module_init(clariion_init); -module_exit(clariion_exit); - -MODULE_DESCRIPTION("EMC CX/AX/FC-family driver"); -MODULE_AUTHOR("Mike Christie , Chandra Seetharaman "); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_hp_sw.c deleted file mode 100644 index 084062bb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * Basic HP/COMPAQ MSA 1000 support. This is only needed if your HW cannot be - * upgraded. - * - * Copyright (C) 2006 Red Hat, Inc. All rights reserved. - * Copyright (C) 2006 Mike Christie - * Copyright (C) 2008 Hannes Reinecke - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#define HP_SW_NAME "hp_sw" - -#define HP_SW_TIMEOUT (60 * HZ) -#define HP_SW_RETRIES 3 - -#define HP_SW_PATH_UNINITIALIZED -1 -#define HP_SW_PATH_ACTIVE 0 -#define HP_SW_PATH_PASSIVE 1 - -struct hp_sw_dh_data { - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - int path_state; - int retries; - int retry_cnt; - struct scsi_device *sdev; - activate_complete callback_fn; - void *callback_data; -}; - -static int hp_sw_start_stop(struct hp_sw_dh_data *); - -static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; - BUG_ON(scsi_dh_data == NULL); - return ((struct hp_sw_dh_data *) scsi_dh_data->buf); -} - -/* - * tur_done - Handle TEST UNIT READY return status - * @sdev: sdev the command has been sent to - * @errors: blk error code - * - * Returns SCSI_DH_DEV_OFFLINED if the sdev is on the passive path - */ -static int tur_done(struct scsi_device *sdev, unsigned char *sense) -{ - struct scsi_sense_hdr sshdr; - int ret; - - ret = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); - if (!ret) { - sdev_printk(KERN_WARNING, sdev, - "%s: sending tur failed, no sense available\n", - HP_SW_NAME); - ret = SCSI_DH_IO; - goto done; - } - switch (sshdr.sense_key) { - case UNIT_ATTENTION: - ret = SCSI_DH_IMM_RETRY; - break; - case NOT_READY: - if ((sshdr.asc == 0x04) && (sshdr.ascq == 2)) { - /* - * LUN not ready - Initialization command required - * - * This is the passive path - */ - ret = SCSI_DH_DEV_OFFLINED; - break; - } - /* Fallthrough */ - default: - sdev_printk(KERN_WARNING, sdev, - "%s: sending tur failed, sense %x/%x/%x\n", - HP_SW_NAME, sshdr.sense_key, sshdr.asc, - sshdr.ascq); - break; - } - -done: - return ret; -} - -/* - * hp_sw_tur - Send TEST UNIT READY - * @sdev: sdev command should be sent to - * - * Use the TEST UNIT READY command to determine - * the path state. - */ -static int hp_sw_tur(struct scsi_device *sdev, struct hp_sw_dh_data *h) -{ - struct request *req; - int ret; - -retry: - req = blk_get_request(sdev->request_queue, WRITE, GFP_NOIO); - if (!req) - return SCSI_DH_RES_TEMP_UNAVAIL; - - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - req->cmd_len = COMMAND_SIZE(TEST_UNIT_READY); - req->cmd[0] = TEST_UNIT_READY; - req->timeout = HP_SW_TIMEOUT; - req->sense = h->sense; - memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); - req->sense_len = 0; - - ret = blk_execute_rq(req->q, NULL, req, 1); - if (ret == -EIO) { - if (req->sense_len > 0) { - ret = tur_done(sdev, h->sense); - } else { - sdev_printk(KERN_WARNING, sdev, - "%s: sending tur failed with %x\n", - HP_SW_NAME, req->errors); - ret = SCSI_DH_IO; - } - } else { - h->path_state = HP_SW_PATH_ACTIVE; - ret = SCSI_DH_OK; - } - if (ret == SCSI_DH_IMM_RETRY) { - blk_put_request(req); - goto retry; - } - if (ret == SCSI_DH_DEV_OFFLINED) { - h->path_state = HP_SW_PATH_PASSIVE; - ret = SCSI_DH_OK; - } - - blk_put_request(req); - - return ret; -} - -/* - * start_done - Handle START STOP UNIT return status - * @sdev: sdev the command has been sent to - * @errors: blk error code - */ -static int start_done(struct scsi_device *sdev, unsigned char *sense) -{ - struct scsi_sense_hdr sshdr; - int rc; - - rc = scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr); - if (!rc) { - sdev_printk(KERN_WARNING, sdev, - "%s: sending start_stop_unit failed, " - "no sense available\n", - HP_SW_NAME); - return SCSI_DH_IO; - } - switch (sshdr.sense_key) { - case NOT_READY: - if ((sshdr.asc == 0x04) && (sshdr.ascq == 3)) { - /* - * LUN not ready - manual intervention required - * - * Switch-over in progress, retry. - */ - rc = SCSI_DH_RETRY; - break; - } - /* fall through */ - default: - sdev_printk(KERN_WARNING, sdev, - "%s: sending start_stop_unit failed, sense %x/%x/%x\n", - HP_SW_NAME, sshdr.sense_key, sshdr.asc, - sshdr.ascq); - rc = SCSI_DH_IO; - } - - return rc; -} - -static void start_stop_endio(struct request *req, int error) -{ - struct hp_sw_dh_data *h = req->end_io_data; - unsigned err = SCSI_DH_OK; - - if (error || host_byte(req->errors) != DID_OK || - msg_byte(req->errors) != COMMAND_COMPLETE) { - sdev_printk(KERN_WARNING, h->sdev, - "%s: sending start_stop_unit failed with %x\n", - HP_SW_NAME, req->errors); - err = SCSI_DH_IO; - goto done; - } - - if (req->sense_len > 0) { - err = start_done(h->sdev, h->sense); - if (err == SCSI_DH_RETRY) { - err = SCSI_DH_IO; - if (--h->retry_cnt) { - blk_put_request(req); - err = hp_sw_start_stop(h); - if (err == SCSI_DH_OK) - return; - } - } - } -done: - req->end_io_data = NULL; - __blk_put_request(req->q, req); - if (h->callback_fn) { - h->callback_fn(h->callback_data, err); - h->callback_fn = h->callback_data = NULL; - } - return; - -} - -/* - * hp_sw_start_stop - Send START STOP UNIT command - * @sdev: sdev command should be sent to - * - * Sending START STOP UNIT activates the SP. - */ -static int hp_sw_start_stop(struct hp_sw_dh_data *h) -{ - struct request *req; - - req = blk_get_request(h->sdev->request_queue, WRITE, GFP_ATOMIC); - if (!req) - return SCSI_DH_RES_TEMP_UNAVAIL; - - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - req->cmd_len = COMMAND_SIZE(START_STOP); - req->cmd[0] = START_STOP; - req->cmd[4] = 1; /* Start spin cycle */ - req->timeout = HP_SW_TIMEOUT; - req->sense = h->sense; - memset(req->sense, 0, SCSI_SENSE_BUFFERSIZE); - req->sense_len = 0; - req->end_io_data = h; - - blk_execute_rq_nowait(req->q, NULL, req, 1, start_stop_endio); - return SCSI_DH_OK; -} - -static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) -{ - struct hp_sw_dh_data *h = get_hp_sw_data(sdev); - int ret = BLKPREP_OK; - - if (h->path_state != HP_SW_PATH_ACTIVE) { - ret = BLKPREP_KILL; - req->cmd_flags |= REQ_QUIET; - } - return ret; - -} - -/* - * hp_sw_activate - Activate a path - * @sdev: sdev on the path to be activated - * - * The HP Active/Passive firmware is pretty simple; - * the passive path reports NOT READY with sense codes - * 0x04/0x02; a START STOP UNIT command will then - * activate the passive path (and deactivate the - * previously active one). - */ -static int hp_sw_activate(struct scsi_device *sdev, - activate_complete fn, void *data) -{ - int ret = SCSI_DH_OK; - struct hp_sw_dh_data *h = get_hp_sw_data(sdev); - - ret = hp_sw_tur(sdev, h); - - if (ret == SCSI_DH_OK && h->path_state == HP_SW_PATH_PASSIVE) { - h->retry_cnt = h->retries; - h->callback_fn = fn; - h->callback_data = data; - ret = hp_sw_start_stop(h); - if (ret == SCSI_DH_OK) - return 0; - h->callback_fn = h->callback_data = NULL; - } - - if (fn) - fn(data, ret); - return 0; -} - -static const struct scsi_dh_devlist hp_sw_dh_data_list[] = { - {"COMPAQ", "MSA1000 VOLUME"}, - {"COMPAQ", "HSV110"}, - {"HP", "HSV100"}, - {"DEC", "HSG80"}, - {NULL, NULL}, -}; - -static bool hp_sw_match(struct scsi_device *sdev) -{ - int i; - - if (scsi_device_tpgs(sdev)) - return false; - - for (i = 0; hp_sw_dh_data_list[i].vendor; i++) { - if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor, - strlen(hp_sw_dh_data_list[i].vendor)) && - !strncmp(sdev->model, hp_sw_dh_data_list[i].model, - strlen(hp_sw_dh_data_list[i].model))) { - return true; - } - } - return false; -} - -static int hp_sw_bus_attach(struct scsi_device *sdev); -static void hp_sw_bus_detach(struct scsi_device *sdev); - -static struct scsi_device_handler hp_sw_dh = { - .name = HP_SW_NAME, - .module = THIS_MODULE, - .devlist = hp_sw_dh_data_list, - .attach = hp_sw_bus_attach, - .detach = hp_sw_bus_detach, - .activate = hp_sw_activate, - .prep_fn = hp_sw_prep_fn, - .match = hp_sw_match, -}; - -static int hp_sw_bus_attach(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data; - struct hp_sw_dh_data *h; - unsigned long flags; - int ret; - - scsi_dh_data = kzalloc(sizeof(*scsi_dh_data) - + sizeof(*h) , GFP_KERNEL); - if (!scsi_dh_data) { - sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n", - HP_SW_NAME); - return 0; - } - - scsi_dh_data->scsi_dh = &hp_sw_dh; - h = (struct hp_sw_dh_data *) scsi_dh_data->buf; - h->path_state = HP_SW_PATH_UNINITIALIZED; - h->retries = HP_SW_RETRIES; - h->sdev = sdev; - - ret = hp_sw_tur(sdev, h); - if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED) - goto failed; - - if (!try_module_get(THIS_MODULE)) - goto failed; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - sdev->scsi_dh_data = scsi_dh_data; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - - sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n", - HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE? - "active":"passive"); - - return 0; - -failed: - kfree(scsi_dh_data); - sdev_printk(KERN_ERR, sdev, "%s: not attached\n", - HP_SW_NAME); - return -EINVAL; -} - -static void hp_sw_bus_detach( struct scsi_device *sdev ) -{ - struct scsi_dh_data *scsi_dh_data; - unsigned long flags; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - scsi_dh_data = sdev->scsi_dh_data; - sdev->scsi_dh_data = NULL; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - module_put(THIS_MODULE); - - sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME); - - kfree(scsi_dh_data); -} - -static int __init hp_sw_init(void) -{ - return scsi_register_device_handler(&hp_sw_dh); -} - -static void __exit hp_sw_exit(void) -{ - scsi_unregister_device_handler(&hp_sw_dh); -} - -module_init(hp_sw_init); -module_exit(hp_sw_exit); - -MODULE_DESCRIPTION("HP Active/Passive driver"); -MODULE_AUTHOR("Mike Christie -#include -#include -#include -#include -#include - -#define RDAC_NAME "rdac" -#define RDAC_RETRY_COUNT 5 - -/* - * LSI mode page stuff - * - * These struct definitions and the forming of the - * mode page were taken from the LSI RDAC 2.4 GPL'd - * driver, and then converted to Linux conventions. - */ -#define RDAC_QUIESCENCE_TIME 20 -/* - * Page Codes - */ -#define RDAC_PAGE_CODE_REDUNDANT_CONTROLLER 0x2c - -/* - * Controller modes definitions - */ -#define RDAC_MODE_TRANSFER_SPECIFIED_LUNS 0x02 - -/* - * RDAC Options field - */ -#define RDAC_FORCED_QUIESENCE 0x02 - -#define RDAC_TIMEOUT (60 * HZ) -#define RDAC_RETRIES 3 - -struct rdac_mode_6_hdr { - u8 data_len; - u8 medium_type; - u8 device_params; - u8 block_desc_len; -}; - -struct rdac_mode_10_hdr { - u16 data_len; - u8 medium_type; - u8 device_params; - u16 reserved; - u16 block_desc_len; -}; - -struct rdac_mode_common { - u8 controller_serial[16]; - u8 alt_controller_serial[16]; - u8 rdac_mode[2]; - u8 alt_rdac_mode[2]; - u8 quiescence_timeout; - u8 rdac_options; -}; - -struct rdac_pg_legacy { - struct rdac_mode_6_hdr hdr; - u8 page_code; - u8 page_len; - struct rdac_mode_common common; -#define MODE6_MAX_LUN 32 - u8 lun_table[MODE6_MAX_LUN]; - u8 reserved2[32]; - u8 reserved3; - u8 reserved4; -}; - -struct rdac_pg_expanded { - struct rdac_mode_10_hdr hdr; - u8 page_code; - u8 subpage_code; - u8 page_len[2]; - struct rdac_mode_common common; - u8 lun_table[256]; - u8 reserved3; - u8 reserved4; -}; - -struct c9_inquiry { - u8 peripheral_info; - u8 page_code; /* 0xC9 */ - u8 reserved1; - u8 page_len; - u8 page_id[4]; /* "vace" */ - u8 avte_cvp; - u8 path_prio; - u8 reserved2[38]; -}; - -#define SUBSYS_ID_LEN 16 -#define SLOT_ID_LEN 2 -#define ARRAY_LABEL_LEN 31 - -struct c4_inquiry { - u8 peripheral_info; - u8 page_code; /* 0xC4 */ - u8 reserved1; - u8 page_len; - u8 page_id[4]; /* "subs" */ - u8 subsys_id[SUBSYS_ID_LEN]; - u8 revision[4]; - u8 slot_id[SLOT_ID_LEN]; - u8 reserved[2]; -}; - -#define UNIQUE_ID_LEN 16 -struct c8_inquiry { - u8 peripheral_info; - u8 page_code; /* 0xC8 */ - u8 reserved1; - u8 page_len; - u8 page_id[4]; /* "edid" */ - u8 reserved2[3]; - u8 vol_uniq_id_len; - u8 vol_uniq_id[16]; - u8 vol_user_label_len; - u8 vol_user_label[60]; - u8 array_uniq_id_len; - u8 array_unique_id[UNIQUE_ID_LEN]; - u8 array_user_label_len; - u8 array_user_label[60]; - u8 lun[8]; -}; - -struct rdac_controller { - u8 array_id[UNIQUE_ID_LEN]; - int use_ms10; - struct kref kref; - struct list_head node; /* list of all controllers */ - union { - struct rdac_pg_legacy legacy; - struct rdac_pg_expanded expanded; - } mode_select; - u8 index; - u8 array_name[ARRAY_LABEL_LEN]; - struct Scsi_Host *host; - spinlock_t ms_lock; - int ms_queued; - struct work_struct ms_work; - struct scsi_device *ms_sdev; - struct list_head ms_head; -}; - -struct c2_inquiry { - u8 peripheral_info; - u8 page_code; /* 0xC2 */ - u8 reserved1; - u8 page_len; - u8 page_id[4]; /* "swr4" */ - u8 sw_version[3]; - u8 sw_date[3]; - u8 features_enabled; - u8 max_lun_supported; - u8 partitions[239]; /* Total allocation length should be 0xFF */ -}; - -struct rdac_dh_data { - struct rdac_controller *ctlr; -#define UNINITIALIZED_LUN (1 << 8) - unsigned lun; - -#define RDAC_MODE 0 -#define RDAC_MODE_AVT 1 -#define RDAC_MODE_IOSHIP 2 - unsigned char mode; - -#define RDAC_STATE_ACTIVE 0 -#define RDAC_STATE_PASSIVE 1 - unsigned char state; - -#define RDAC_LUN_UNOWNED 0 -#define RDAC_LUN_OWNED 1 - char lun_state; - -#define RDAC_PREFERRED 0 -#define RDAC_NON_PREFERRED 1 - char preferred; - - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - union { - struct c2_inquiry c2; - struct c4_inquiry c4; - struct c8_inquiry c8; - struct c9_inquiry c9; - } inq; -}; - -static const char *mode[] = { - "RDAC", - "AVT", - "IOSHIP", -}; -static const char *lun_state[] = -{ - "unowned", - "owned", -}; - -struct rdac_queue_data { - struct list_head entry; - struct rdac_dh_data *h; - activate_complete callback_fn; - void *callback_data; -}; - -static LIST_HEAD(ctlr_list); -static DEFINE_SPINLOCK(list_lock); -static struct workqueue_struct *kmpath_rdacd; -static void send_mode_select(struct work_struct *work); - -/* - * module parameter to enable rdac debug logging. - * 2 bits for each type of logging, only two types defined for now - * Can be enhanced if required at later point - */ -static int rdac_logging = 1; -module_param(rdac_logging, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(rdac_logging, "A bit mask of rdac logging levels, " - "Default is 1 - failover logging enabled, " - "set it to 0xF to enable all the logs"); - -#define RDAC_LOG_FAILOVER 0 -#define RDAC_LOG_SENSE 2 - -#define RDAC_LOG_BITS 2 - -#define RDAC_LOG_LEVEL(SHIFT) \ - ((rdac_logging >> (SHIFT)) & ((1 << (RDAC_LOG_BITS)) - 1)) - -#define RDAC_LOG(SHIFT, sdev, f, arg...) \ -do { \ - if (unlikely(RDAC_LOG_LEVEL(SHIFT))) \ - sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \ -} while (0); - -static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; - BUG_ON(scsi_dh_data == NULL); - return ((struct rdac_dh_data *) scsi_dh_data->buf); -} - -static struct request *get_rdac_req(struct scsi_device *sdev, - void *buffer, unsigned buflen, int rw) -{ - struct request *rq; - struct request_queue *q = sdev->request_queue; - - rq = blk_get_request(q, rw, GFP_NOIO); - - if (!rq) { - sdev_printk(KERN_INFO, sdev, - "get_rdac_req: blk_get_request failed.\n"); - return NULL; - } - - if (buflen && blk_rq_map_kern(q, rq, buffer, buflen, GFP_NOIO)) { - blk_put_request(rq); - sdev_printk(KERN_INFO, sdev, - "get_rdac_req: blk_rq_map_kern failed.\n"); - return NULL; - } - - rq->cmd_type = REQ_TYPE_BLOCK_PC; - rq->cmd_flags |= REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER; - rq->retries = RDAC_RETRIES; - rq->timeout = RDAC_TIMEOUT; - - return rq; -} - -static struct request *rdac_failover_get(struct scsi_device *sdev, - struct rdac_dh_data *h, struct list_head *list) -{ - struct request *rq; - struct rdac_mode_common *common; - unsigned data_size; - struct rdac_queue_data *qdata; - u8 *lun_table; - - if (h->ctlr->use_ms10) { - struct rdac_pg_expanded *rdac_pg; - - data_size = sizeof(struct rdac_pg_expanded); - rdac_pg = &h->ctlr->mode_select.expanded; - memset(rdac_pg, 0, data_size); - common = &rdac_pg->common; - rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER + 0x40; - rdac_pg->subpage_code = 0x1; - rdac_pg->page_len[0] = 0x01; - rdac_pg->page_len[1] = 0x28; - lun_table = rdac_pg->lun_table; - } else { - struct rdac_pg_legacy *rdac_pg; - - data_size = sizeof(struct rdac_pg_legacy); - rdac_pg = &h->ctlr->mode_select.legacy; - memset(rdac_pg, 0, data_size); - common = &rdac_pg->common; - rdac_pg->page_code = RDAC_PAGE_CODE_REDUNDANT_CONTROLLER; - rdac_pg->page_len = 0x68; - lun_table = rdac_pg->lun_table; - } - common->rdac_mode[1] = RDAC_MODE_TRANSFER_SPECIFIED_LUNS; - common->quiescence_timeout = RDAC_QUIESCENCE_TIME; - common->rdac_options = RDAC_FORCED_QUIESENCE; - - list_for_each_entry(qdata, list, entry) { - lun_table[qdata->h->lun] = 0x81; - } - - /* get request for block layer packet command */ - rq = get_rdac_req(sdev, &h->ctlr->mode_select, data_size, WRITE); - if (!rq) - return NULL; - - /* Prepare the command. */ - if (h->ctlr->use_ms10) { - rq->cmd[0] = MODE_SELECT_10; - rq->cmd[7] = data_size >> 8; - rq->cmd[8] = data_size & 0xff; - } else { - rq->cmd[0] = MODE_SELECT; - rq->cmd[4] = data_size; - } - rq->cmd_len = COMMAND_SIZE(rq->cmd[0]); - - rq->sense = h->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = 0; - - return rq; -} - -static void release_controller(struct kref *kref) -{ - struct rdac_controller *ctlr; - ctlr = container_of(kref, struct rdac_controller, kref); - - list_del(&ctlr->node); - kfree(ctlr); -} - -static struct rdac_controller *get_controller(int index, char *array_name, - u8 *array_id, struct scsi_device *sdev) -{ - struct rdac_controller *ctlr, *tmp; - - list_for_each_entry(tmp, &ctlr_list, node) { - if ((memcmp(tmp->array_id, array_id, UNIQUE_ID_LEN) == 0) && - (tmp->index == index) && - (tmp->host == sdev->host)) { - kref_get(&tmp->kref); - return tmp; - } - } - ctlr = kmalloc(sizeof(*ctlr), GFP_ATOMIC); - if (!ctlr) - return NULL; - - /* initialize fields of controller */ - memcpy(ctlr->array_id, array_id, UNIQUE_ID_LEN); - ctlr->index = index; - ctlr->host = sdev->host; - memcpy(ctlr->array_name, array_name, ARRAY_LABEL_LEN); - - kref_init(&ctlr->kref); - ctlr->use_ms10 = -1; - ctlr->ms_queued = 0; - ctlr->ms_sdev = NULL; - spin_lock_init(&ctlr->ms_lock); - INIT_WORK(&ctlr->ms_work, send_mode_select); - INIT_LIST_HEAD(&ctlr->ms_head); - list_add(&ctlr->node, &ctlr_list); - - return ctlr; -} - -static int submit_inquiry(struct scsi_device *sdev, int page_code, - unsigned int len, struct rdac_dh_data *h) -{ - struct request *rq; - struct request_queue *q = sdev->request_queue; - int err = SCSI_DH_RES_TEMP_UNAVAIL; - - rq = get_rdac_req(sdev, &h->inq, len, READ); - if (!rq) - goto done; - - /* Prepare the command. */ - rq->cmd[0] = INQUIRY; - rq->cmd[1] = 1; - rq->cmd[2] = page_code; - rq->cmd[4] = len; - rq->cmd_len = COMMAND_SIZE(INQUIRY); - - rq->sense = h->sense; - memset(rq->sense, 0, SCSI_SENSE_BUFFERSIZE); - rq->sense_len = 0; - - err = blk_execute_rq(q, NULL, rq, 1); - if (err == -EIO) - err = SCSI_DH_IO; - - blk_put_request(rq); -done: - return err; -} - -static int get_lun_info(struct scsi_device *sdev, struct rdac_dh_data *h, - char *array_name, u8 *array_id) -{ - int err, i; - struct c8_inquiry *inqp; - - err = submit_inquiry(sdev, 0xC8, sizeof(struct c8_inquiry), h); - if (err == SCSI_DH_OK) { - inqp = &h->inq.c8; - if (inqp->page_code != 0xc8) - return SCSI_DH_NOSYS; - if (inqp->page_id[0] != 'e' || inqp->page_id[1] != 'd' || - inqp->page_id[2] != 'i' || inqp->page_id[3] != 'd') - return SCSI_DH_NOSYS; - h->lun = inqp->lun[7]; /* Uses only the last byte */ - - for(i=0; iarray_user_label[(2*i)+1]; - - *(array_name+ARRAY_LABEL_LEN-1) = '\0'; - memset(array_id, 0, UNIQUE_ID_LEN); - memcpy(array_id, inqp->array_unique_id, inqp->array_uniq_id_len); - } - return err; -} - -static int check_ownership(struct scsi_device *sdev, struct rdac_dh_data *h) -{ - int err; - struct c9_inquiry *inqp; - - h->state = RDAC_STATE_ACTIVE; - err = submit_inquiry(sdev, 0xC9, sizeof(struct c9_inquiry), h); - if (err == SCSI_DH_OK) { - inqp = &h->inq.c9; - /* detect the operating mode */ - if ((inqp->avte_cvp >> 5) & 0x1) - h->mode = RDAC_MODE_IOSHIP; /* LUN in IOSHIP mode */ - else if (inqp->avte_cvp >> 7) - h->mode = RDAC_MODE_AVT; /* LUN in AVT mode */ - else - h->mode = RDAC_MODE; /* LUN in RDAC mode */ - - /* Update ownership */ - if (inqp->avte_cvp & 0x1) - h->lun_state = RDAC_LUN_OWNED; - else { - h->lun_state = RDAC_LUN_UNOWNED; - if (h->mode == RDAC_MODE) - h->state = RDAC_STATE_PASSIVE; - } - - /* Update path prio*/ - if (inqp->path_prio & 0x1) - h->preferred = RDAC_PREFERRED; - else - h->preferred = RDAC_NON_PREFERRED; - } - - return err; -} - -static int initialize_controller(struct scsi_device *sdev, - struct rdac_dh_data *h, char *array_name, u8 *array_id) -{ - int err, index; - struct c4_inquiry *inqp; - - err = submit_inquiry(sdev, 0xC4, sizeof(struct c4_inquiry), h); - if (err == SCSI_DH_OK) { - inqp = &h->inq.c4; - /* get the controller index */ - if (inqp->slot_id[1] == 0x31) - index = 0; - else - index = 1; - - spin_lock(&list_lock); - h->ctlr = get_controller(index, array_name, array_id, sdev); - if (!h->ctlr) - err = SCSI_DH_RES_TEMP_UNAVAIL; - spin_unlock(&list_lock); - } - return err; -} - -static int set_mode_select(struct scsi_device *sdev, struct rdac_dh_data *h) -{ - int err; - struct c2_inquiry *inqp; - - err = submit_inquiry(sdev, 0xC2, sizeof(struct c2_inquiry), h); - if (err == SCSI_DH_OK) { - inqp = &h->inq.c2; - /* - * If more than MODE6_MAX_LUN luns are supported, use - * mode select 10 - */ - if (inqp->max_lun_supported >= MODE6_MAX_LUN) - h->ctlr->use_ms10 = 1; - else - h->ctlr->use_ms10 = 0; - } - return err; -} - -static int mode_select_handle_sense(struct scsi_device *sdev, - unsigned char *sensebuf) -{ - struct scsi_sense_hdr sense_hdr; - int err = SCSI_DH_IO, ret; - struct rdac_dh_data *h = get_rdac_data(sdev); - - ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr); - if (!ret) - goto done; - - switch (sense_hdr.sense_key) { - case NO_SENSE: - case ABORTED_COMMAND: - case UNIT_ATTENTION: - err = SCSI_DH_RETRY; - break; - case NOT_READY: - if (sense_hdr.asc == 0x04 && sense_hdr.ascq == 0x01) - /* LUN Not Ready and is in the Process of Becoming - * Ready - */ - err = SCSI_DH_RETRY; - break; - case ILLEGAL_REQUEST: - if (sense_hdr.asc == 0x91 && sense_hdr.ascq == 0x36) - /* - * Command Lock contention - */ - err = SCSI_DH_RETRY; - break; - default: - break; - } - - RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " - "MODE_SELECT returned with sense %02x/%02x/%02x", - (char *) h->ctlr->array_name, h->ctlr->index, - sense_hdr.sense_key, sense_hdr.asc, sense_hdr.ascq); - -done: - return err; -} - -static void send_mode_select(struct work_struct *work) -{ - struct rdac_controller *ctlr = - container_of(work, struct rdac_controller, ms_work); - struct request *rq; - struct scsi_device *sdev = ctlr->ms_sdev; - struct rdac_dh_data *h = get_rdac_data(sdev); - struct request_queue *q = sdev->request_queue; - int err, retry_cnt = RDAC_RETRY_COUNT; - struct rdac_queue_data *tmp, *qdata; - LIST_HEAD(list); - - spin_lock(&ctlr->ms_lock); - list_splice_init(&ctlr->ms_head, &list); - ctlr->ms_queued = 0; - ctlr->ms_sdev = NULL; - spin_unlock(&ctlr->ms_lock); - -retry: - err = SCSI_DH_RES_TEMP_UNAVAIL; - rq = rdac_failover_get(sdev, h, &list); - if (!rq) - goto done; - - RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " - "%s MODE_SELECT command", - (char *) h->ctlr->array_name, h->ctlr->index, - (retry_cnt == RDAC_RETRY_COUNT) ? "queueing" : "retrying"); - - err = blk_execute_rq(q, NULL, rq, 1); - blk_put_request(rq); - if (err != SCSI_DH_OK) { - err = mode_select_handle_sense(sdev, h->sense); - if (err == SCSI_DH_RETRY && retry_cnt--) - goto retry; - } - if (err == SCSI_DH_OK) { - h->state = RDAC_STATE_ACTIVE; - RDAC_LOG(RDAC_LOG_FAILOVER, sdev, "array %s, ctlr %d, " - "MODE_SELECT completed", - (char *) h->ctlr->array_name, h->ctlr->index); - } - -done: - list_for_each_entry_safe(qdata, tmp, &list, entry) { - list_del(&qdata->entry); - if (err == SCSI_DH_OK) - qdata->h->state = RDAC_STATE_ACTIVE; - if (qdata->callback_fn) - qdata->callback_fn(qdata->callback_data, err); - kfree(qdata); - } - return; -} - -static int queue_mode_select(struct scsi_device *sdev, - activate_complete fn, void *data) -{ - struct rdac_queue_data *qdata; - struct rdac_controller *ctlr; - - qdata = kzalloc(sizeof(*qdata), GFP_KERNEL); - if (!qdata) - return SCSI_DH_RETRY; - - qdata->h = get_rdac_data(sdev); - qdata->callback_fn = fn; - qdata->callback_data = data; - - ctlr = qdata->h->ctlr; - spin_lock(&ctlr->ms_lock); - list_add_tail(&qdata->entry, &ctlr->ms_head); - if (!ctlr->ms_queued) { - ctlr->ms_queued = 1; - ctlr->ms_sdev = sdev; - queue_work(kmpath_rdacd, &ctlr->ms_work); - } - spin_unlock(&ctlr->ms_lock); - return SCSI_DH_OK; -} - -static int rdac_activate(struct scsi_device *sdev, - activate_complete fn, void *data) -{ - struct rdac_dh_data *h = get_rdac_data(sdev); - int err = SCSI_DH_OK; - int act = 0; - - err = check_ownership(sdev, h); - if (err != SCSI_DH_OK) - goto done; - - switch (h->mode) { - case RDAC_MODE: - if (h->lun_state == RDAC_LUN_UNOWNED) - act = 1; - break; - case RDAC_MODE_IOSHIP: - if ((h->lun_state == RDAC_LUN_UNOWNED) && - (h->preferred == RDAC_PREFERRED)) - act = 1; - break; - default: - break; - } - - if (act) { - err = queue_mode_select(sdev, fn, data); - if (err == SCSI_DH_OK) - return 0; - } -done: - if (fn) - fn(data, err); - return 0; -} - -static int rdac_prep_fn(struct scsi_device *sdev, struct request *req) -{ - struct rdac_dh_data *h = get_rdac_data(sdev); - int ret = BLKPREP_OK; - - if (h->state != RDAC_STATE_ACTIVE) { - ret = BLKPREP_KILL; - req->cmd_flags |= REQ_QUIET; - } - return ret; - -} - -static int rdac_check_sense(struct scsi_device *sdev, - struct scsi_sense_hdr *sense_hdr) -{ - struct rdac_dh_data *h = get_rdac_data(sdev); - - RDAC_LOG(RDAC_LOG_SENSE, sdev, "array %s, ctlr %d, " - "I/O returned with sense %02x/%02x/%02x", - (char *) h->ctlr->array_name, h->ctlr->index, - sense_hdr->sense_key, sense_hdr->asc, sense_hdr->ascq); - - switch (sense_hdr->sense_key) { - case NOT_READY: - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x01) - /* LUN Not Ready - Logical Unit Not Ready and is in - * the process of becoming ready - * Just retry. - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0x81) - /* LUN Not Ready - Storage firmware incompatible - * Manual code synchonisation required. - * - * Nothing we can do here. Try to bypass the path. - */ - return SUCCESS; - if (sense_hdr->asc == 0x04 && sense_hdr->ascq == 0xA1) - /* LUN Not Ready - Quiescense in progress - * - * Just retry and wait. - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0xA1 && sense_hdr->ascq == 0x02) - /* LUN Not Ready - Quiescense in progress - * or has been achieved - * Just retry. - */ - return ADD_TO_MLQUEUE; - break; - case ILLEGAL_REQUEST: - if (sense_hdr->asc == 0x94 && sense_hdr->ascq == 0x01) { - /* Invalid Request - Current Logical Unit Ownership. - * Controller is not the current owner of the LUN, - * Fail the path, so that the other path be used. - */ - h->state = RDAC_STATE_PASSIVE; - return SUCCESS; - } - break; - case UNIT_ATTENTION: - if (sense_hdr->asc == 0x29 && sense_hdr->ascq == 0x00) - /* - * Power On, Reset, or Bus Device Reset, just retry. - */ - return ADD_TO_MLQUEUE; - if (sense_hdr->asc == 0x8b && sense_hdr->ascq == 0x02) - /* - * Quiescence in progress , just retry. - */ - return ADD_TO_MLQUEUE; - break; - } - /* success just means we do not care what scsi-ml does */ - return SCSI_RETURN_NOT_HANDLED; -} - -static const struct scsi_dh_devlist rdac_dev_list[] = { - {"IBM", "1722"}, - {"IBM", "1724"}, - {"IBM", "1726"}, - {"IBM", "1742"}, - {"IBM", "1745"}, - {"IBM", "1746"}, - {"IBM", "1814"}, - {"IBM", "1815"}, - {"IBM", "1818"}, - {"IBM", "3526"}, - {"SGI", "TP9400"}, - {"SGI", "TP9500"}, - {"SGI", "TP9700"}, - {"SGI", "IS"}, - {"STK", "OPENstorage D280"}, - {"SUN", "CSM200_R"}, - {"SUN", "LCSM100_I"}, - {"SUN", "LCSM100_S"}, - {"SUN", "LCSM100_E"}, - {"SUN", "LCSM100_F"}, - {"DELL", "MD3000"}, - {"DELL", "MD3000i"}, - {"DELL", "MD32xx"}, - {"DELL", "MD32xxi"}, - {"DELL", "MD36xxi"}, - {"DELL", "MD36xxf"}, - {"LSI", "INF-01-00"}, - {"ENGENIO", "INF-01-00"}, - {"STK", "FLEXLINE 380"}, - {"SUN", "CSM100_R_FC"}, - {"SUN", "STK6580_6780"}, - {"SUN", "SUN_6180"}, - {"SUN", "ArrayStorage"}, - {NULL, NULL}, -}; - -static bool rdac_match(struct scsi_device *sdev) -{ - int i; - - if (scsi_device_tpgs(sdev)) - return false; - - for (i = 0; rdac_dev_list[i].vendor; i++) { - if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor, - strlen(rdac_dev_list[i].vendor)) && - !strncmp(sdev->model, rdac_dev_list[i].model, - strlen(rdac_dev_list[i].model))) { - return true; - } - } - return false; -} - -static int rdac_bus_attach(struct scsi_device *sdev); -static void rdac_bus_detach(struct scsi_device *sdev); - -static struct scsi_device_handler rdac_dh = { - .name = RDAC_NAME, - .module = THIS_MODULE, - .devlist = rdac_dev_list, - .prep_fn = rdac_prep_fn, - .check_sense = rdac_check_sense, - .attach = rdac_bus_attach, - .detach = rdac_bus_detach, - .activate = rdac_activate, - .match = rdac_match, -}; - -static int rdac_bus_attach(struct scsi_device *sdev) -{ - struct scsi_dh_data *scsi_dh_data; - struct rdac_dh_data *h; - unsigned long flags; - int err; - char array_name[ARRAY_LABEL_LEN]; - char array_id[UNIQUE_ID_LEN]; - - scsi_dh_data = kzalloc(sizeof(*scsi_dh_data) - + sizeof(*h) , GFP_KERNEL); - if (!scsi_dh_data) { - sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n", - RDAC_NAME); - return 0; - } - - scsi_dh_data->scsi_dh = &rdac_dh; - h = (struct rdac_dh_data *) scsi_dh_data->buf; - h->lun = UNINITIALIZED_LUN; - h->state = RDAC_STATE_ACTIVE; - - err = get_lun_info(sdev, h, array_name, array_id); - if (err != SCSI_DH_OK) - goto failed; - - err = initialize_controller(sdev, h, array_name, array_id); - if (err != SCSI_DH_OK) - goto failed; - - err = check_ownership(sdev, h); - if (err != SCSI_DH_OK) - goto clean_ctlr; - - err = set_mode_select(sdev, h); - if (err != SCSI_DH_OK) - goto clean_ctlr; - - if (!try_module_get(THIS_MODULE)) - goto clean_ctlr; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - sdev->scsi_dh_data = scsi_dh_data; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - - sdev_printk(KERN_NOTICE, sdev, - "%s: LUN %d (%s) (%s)\n", - RDAC_NAME, h->lun, mode[(int)h->mode], - lun_state[(int)h->lun_state]); - - return 0; - -clean_ctlr: - spin_lock(&list_lock); - kref_put(&h->ctlr->kref, release_controller); - spin_unlock(&list_lock); - -failed: - kfree(scsi_dh_data); - sdev_printk(KERN_ERR, sdev, "%s: not attached\n", - RDAC_NAME); - return -EINVAL; -} - -static void rdac_bus_detach( struct scsi_device *sdev ) -{ - struct scsi_dh_data *scsi_dh_data; - struct rdac_dh_data *h; - unsigned long flags; - - scsi_dh_data = sdev->scsi_dh_data; - h = (struct rdac_dh_data *) scsi_dh_data->buf; - if (h->ctlr && h->ctlr->ms_queued) - flush_workqueue(kmpath_rdacd); - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - sdev->scsi_dh_data = NULL; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); - - spin_lock(&list_lock); - if (h->ctlr) - kref_put(&h->ctlr->kref, release_controller); - spin_unlock(&list_lock); - kfree(scsi_dh_data); - module_put(THIS_MODULE); - sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME); -} - - - -static int __init rdac_init(void) -{ - int r; - - r = scsi_register_device_handler(&rdac_dh); - if (r != 0) { - printk(KERN_ERR "Failed to register scsi device handler."); - goto done; - } - - /* - * Create workqueue to handle mode selects for rdac - */ - kmpath_rdacd = create_singlethread_workqueue("kmpath_rdacd"); - if (!kmpath_rdacd) { - scsi_unregister_device_handler(&rdac_dh); - printk(KERN_ERR "kmpath_rdacd creation failed.\n"); - - r = -EINVAL; - } -done: - return r; -} - -static void __exit rdac_exit(void) -{ - destroy_workqueue(kmpath_rdacd); - scsi_unregister_device_handler(&rdac_dh); -} - -module_init(rdac_init); -module_exit(rdac_exit); - -MODULE_DESCRIPTION("Multipath LSI/Engenio/NetApp E-Series RDAC driver"); -MODULE_AUTHOR("Mike Christie, Chandra Seetharaman"); -MODULE_VERSION("01.00.0000.0000"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/dmx3191d.c b/ANDROID_3.4.5/drivers/scsi/dmx3191d.c deleted file mode 100644 index 207352cc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dmx3191d.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - dmx3191d.c - driver for the Domex DMX3191D SCSI card. - Copyright (C) 2000 by Massimo Piccioni - Portions Copyright (C) 2004 by Christoph Hellwig - - Based on the generic NCR5380 driver by Drew Eckhardt et al. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Definitions for the generic 5380 driver. - */ -#define AUTOSENSE - -#define NCR5380_read(reg) inb(port + reg) -#define NCR5380_write(reg, value) outb(value, port + reg) - -#define NCR5380_implementation_fields unsigned int port -#define NCR5380_local_declare() NCR5380_implementation_fields -#define NCR5380_setup(instance) port = instance->io_port - -/* - * Includes needed for NCR5380.[ch] (XXX: Move them to NCR5380.h) - */ -#include -#include "scsi.h" - -#include "NCR5380.h" -#include "NCR5380.c" - -#define DMX3191D_DRIVER_NAME "dmx3191d" -#define DMX3191D_REGION_LEN 8 - - -static struct scsi_host_template dmx3191d_driver_template = { - .proc_name = DMX3191D_DRIVER_NAME, - .name = "Domex DMX3191D", - .queuecommand = NCR5380_queue_command, - .eh_abort_handler = NCR5380_abort, - .eh_bus_reset_handler = NCR5380_bus_reset, - .can_queue = 32, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 2, - .use_clustering = DISABLE_CLUSTERING, -}; - -static int __devinit dmx3191d_probe_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct Scsi_Host *shost; - unsigned long io; - int error = -ENODEV; - - if (pci_enable_device(pdev)) - goto out; - - io = pci_resource_start(pdev, 0); - if (!request_region(io, DMX3191D_REGION_LEN, DMX3191D_DRIVER_NAME)) { - printk(KERN_ERR "dmx3191: region 0x%lx-0x%lx already reserved\n", - io, io + DMX3191D_REGION_LEN); - goto out_disable_device; - } - - shost = scsi_host_alloc(&dmx3191d_driver_template, - sizeof(struct NCR5380_hostdata)); - if (!shost) - goto out_release_region; - shost->io_port = io; - shost->irq = pdev->irq; - - NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E); - - if (request_irq(pdev->irq, NCR5380_intr, IRQF_SHARED, - DMX3191D_DRIVER_NAME, shost)) { - /* - * Steam powered scsi controllers run without an IRQ anyway - */ - printk(KERN_WARNING "dmx3191: IRQ %d not available - " - "switching to polled mode.\n", pdev->irq); - shost->irq = SCSI_IRQ_NONE; - } - - pci_set_drvdata(pdev, shost); - - error = scsi_add_host(shost, &pdev->dev); - if (error) - goto out_free_irq; - - scsi_scan_host(shost); - return 0; - - out_free_irq: - free_irq(shost->irq, shost); - out_release_region: - release_region(io, DMX3191D_REGION_LEN); - out_disable_device: - pci_disable_device(pdev); - out: - return error; -} - -static void __devexit dmx3191d_remove_one(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - - scsi_remove_host(shost); - - NCR5380_exit(shost); - - if (shost->irq != SCSI_IRQ_NONE) - free_irq(shost->irq, shost); - release_region(shost->io_port, DMX3191D_REGION_LEN); - pci_disable_device(pdev); - - scsi_host_put(shost); -} - -static struct pci_device_id dmx3191d_pci_tbl[] = { - {PCI_VENDOR_ID_DOMEX, PCI_DEVICE_ID_DOMEX_DMX3191D, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { } -}; -MODULE_DEVICE_TABLE(pci, dmx3191d_pci_tbl); - -static struct pci_driver dmx3191d_pci_driver = { - .name = DMX3191D_DRIVER_NAME, - .id_table = dmx3191d_pci_tbl, - .probe = dmx3191d_probe_one, - .remove = __devexit_p(dmx3191d_remove_one), -}; - -static int __init dmx3191d_init(void) -{ - return pci_register_driver(&dmx3191d_pci_driver); -} - -static void __exit dmx3191d_exit(void) -{ - pci_unregister_driver(&dmx3191d_pci_driver); -} - -module_init(dmx3191d_init); -module_exit(dmx3191d_exit); - -MODULE_AUTHOR("Massimo Piccioni "); -MODULE_DESCRIPTION("Domex DMX3191D SCSI driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/dpt/dpti_i2o.h b/ANDROID_3.4.5/drivers/scsi/dpt/dpti_i2o.h deleted file mode 100644 index bd9e31e1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dpt/dpti_i2o.h +++ /dev/null @@ -1,446 +0,0 @@ -#ifndef _SCSI_I2O_H -#define _SCSI_I2O_H - -/* I2O kernel space accessible structures/APIs - * - * (c) Copyright 1999, 2000 Red Hat Software - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - ************************************************************************* - * - * This header file defined the I2O APIs/structures for use by - * the I2O kernel modules. - * - */ - -#ifdef __KERNEL__ /* This file to be included by kernel only */ - -#include - -#include -#include - - -/* - * Tunable parameters first - */ - -/* How many different OSM's are we allowing */ -#define MAX_I2O_MODULES 64 - -#define I2O_EVT_CAPABILITY_OTHER 0x01 -#define I2O_EVT_CAPABILITY_CHANGED 0x02 - -#define I2O_EVT_SENSOR_STATE_CHANGED 0x01 - -//#ifdef __KERNEL__ /* ioctl stuff only thing exported to users */ - -#define I2O_MAX_MANAGERS 4 - -/* - * I2O Interface Objects - */ - -#include -typedef wait_queue_head_t adpt_wait_queue_head_t; -#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wait) -typedef wait_queue_t adpt_wait_queue_t; - -/* - * message structures - */ - -struct i2o_message -{ - u8 version_offset; - u8 flags; - u16 size; - u32 target_tid:12; - u32 init_tid:12; - u32 function:8; - u32 initiator_context; - /* List follows */ -}; - -struct adpt_device; -struct _adpt_hba; -struct i2o_device -{ - struct i2o_device *next; /* Chain */ - struct i2o_device *prev; - - char dev_name[8]; /* linux /dev name if available */ - i2o_lct_entry lct_data;/* Device LCT information */ - u32 flags; - struct proc_dir_entry* proc_entry; /* /proc dir */ - struct adpt_device *owner; - struct _adpt_hba *controller; /* Controlling IOP */ -}; - -/* - * Each I2O controller has one of these objects - */ - -struct i2o_controller -{ - char name[16]; - int unit; - int type; - int enabled; - - struct notifier_block *event_notifer; /* Events */ - atomic_t users; - struct i2o_device *devices; /* I2O device chain */ - struct i2o_controller *next; /* Controller chain */ - -}; - -/* - * I2O System table entry - */ -struct i2o_sys_tbl_entry -{ - u16 org_id; - u16 reserved1; - u32 iop_id:12; - u32 reserved2:20; - u16 seg_num:12; - u16 i2o_version:4; - u8 iop_state; - u8 msg_type; - u16 frame_size; - u16 reserved3; - u32 last_changed; - u32 iop_capabilities; - u32 inbound_low; - u32 inbound_high; -}; - -struct i2o_sys_tbl -{ - u8 num_entries; - u8 version; - u16 reserved1; - u32 change_ind; - u32 reserved2; - u32 reserved3; - struct i2o_sys_tbl_entry iops[0]; -}; - -/* - * I2O classes / subclasses - */ - -/* Class ID and Code Assignments - * (LCT.ClassID.Version field) - */ -#define I2O_CLASS_VERSION_10 0x00 -#define I2O_CLASS_VERSION_11 0x01 - -/* Class code names - * (from v1.5 Table 6-1 Class Code Assignments.) - */ - -#define I2O_CLASS_EXECUTIVE 0x000 -#define I2O_CLASS_DDM 0x001 -#define I2O_CLASS_RANDOM_BLOCK_STORAGE 0x010 -#define I2O_CLASS_SEQUENTIAL_STORAGE 0x011 -#define I2O_CLASS_LAN 0x020 -#define I2O_CLASS_WAN 0x030 -#define I2O_CLASS_FIBRE_CHANNEL_PORT 0x040 -#define I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL 0x041 -#define I2O_CLASS_SCSI_PERIPHERAL 0x051 -#define I2O_CLASS_ATE_PORT 0x060 -#define I2O_CLASS_ATE_PERIPHERAL 0x061 -#define I2O_CLASS_FLOPPY_CONTROLLER 0x070 -#define I2O_CLASS_FLOPPY_DEVICE 0x071 -#define I2O_CLASS_BUS_ADAPTER_PORT 0x080 -#define I2O_CLASS_PEER_TRANSPORT_AGENT 0x090 -#define I2O_CLASS_PEER_TRANSPORT 0x091 - -/* Rest of 0x092 - 0x09f reserved for peer-to-peer classes - */ - -#define I2O_CLASS_MATCH_ANYCLASS 0xffffffff - -/* Subclasses - */ - -#define I2O_SUBCLASS_i960 0x001 -#define I2O_SUBCLASS_HDM 0x020 -#define I2O_SUBCLASS_ISM 0x021 - -/* Operation functions */ - -#define I2O_PARAMS_FIELD_GET 0x0001 -#define I2O_PARAMS_LIST_GET 0x0002 -#define I2O_PARAMS_MORE_GET 0x0003 -#define I2O_PARAMS_SIZE_GET 0x0004 -#define I2O_PARAMS_TABLE_GET 0x0005 -#define I2O_PARAMS_FIELD_SET 0x0006 -#define I2O_PARAMS_LIST_SET 0x0007 -#define I2O_PARAMS_ROW_ADD 0x0008 -#define I2O_PARAMS_ROW_DELETE 0x0009 -#define I2O_PARAMS_TABLE_CLEAR 0x000A - -/* - * I2O serial number conventions / formats - * (circa v1.5) - */ - -#define I2O_SNFORMAT_UNKNOWN 0 -#define I2O_SNFORMAT_BINARY 1 -#define I2O_SNFORMAT_ASCII 2 -#define I2O_SNFORMAT_UNICODE 3 -#define I2O_SNFORMAT_LAN48_MAC 4 -#define I2O_SNFORMAT_WAN 5 - -/* Plus new in v2.0 (Yellowstone pdf doc) - */ - -#define I2O_SNFORMAT_LAN64_MAC 6 -#define I2O_SNFORMAT_DDM 7 -#define I2O_SNFORMAT_IEEE_REG64 8 -#define I2O_SNFORMAT_IEEE_REG128 9 -#define I2O_SNFORMAT_UNKNOWN2 0xff - -/* Transaction Reply Lists (TRL) Control Word structure */ - -#define TRL_SINGLE_FIXED_LENGTH 0x00 -#define TRL_SINGLE_VARIABLE_LENGTH 0x40 -#define TRL_MULTIPLE_FIXED_LENGTH 0x80 - -/* - * Messaging API values - */ - -#define I2O_CMD_ADAPTER_ASSIGN 0xB3 -#define I2O_CMD_ADAPTER_READ 0xB2 -#define I2O_CMD_ADAPTER_RELEASE 0xB5 -#define I2O_CMD_BIOS_INFO_SET 0xA5 -#define I2O_CMD_BOOT_DEVICE_SET 0xA7 -#define I2O_CMD_CONFIG_VALIDATE 0xBB -#define I2O_CMD_CONN_SETUP 0xCA -#define I2O_CMD_DDM_DESTROY 0xB1 -#define I2O_CMD_DDM_ENABLE 0xD5 -#define I2O_CMD_DDM_QUIESCE 0xC7 -#define I2O_CMD_DDM_RESET 0xD9 -#define I2O_CMD_DDM_SUSPEND 0xAF -#define I2O_CMD_DEVICE_ASSIGN 0xB7 -#define I2O_CMD_DEVICE_RELEASE 0xB9 -#define I2O_CMD_HRT_GET 0xA8 -#define I2O_CMD_ADAPTER_CLEAR 0xBE -#define I2O_CMD_ADAPTER_CONNECT 0xC9 -#define I2O_CMD_ADAPTER_RESET 0xBD -#define I2O_CMD_LCT_NOTIFY 0xA2 -#define I2O_CMD_OUTBOUND_INIT 0xA1 -#define I2O_CMD_PATH_ENABLE 0xD3 -#define I2O_CMD_PATH_QUIESCE 0xC5 -#define I2O_CMD_PATH_RESET 0xD7 -#define I2O_CMD_STATIC_MF_CREATE 0xDD -#define I2O_CMD_STATIC_MF_RELEASE 0xDF -#define I2O_CMD_STATUS_GET 0xA0 -#define I2O_CMD_SW_DOWNLOAD 0xA9 -#define I2O_CMD_SW_UPLOAD 0xAB -#define I2O_CMD_SW_REMOVE 0xAD -#define I2O_CMD_SYS_ENABLE 0xD1 -#define I2O_CMD_SYS_MODIFY 0xC1 -#define I2O_CMD_SYS_QUIESCE 0xC3 -#define I2O_CMD_SYS_TAB_SET 0xA3 - -#define I2O_CMD_UTIL_NOP 0x00 -#define I2O_CMD_UTIL_ABORT 0x01 -#define I2O_CMD_UTIL_CLAIM 0x09 -#define I2O_CMD_UTIL_RELEASE 0x0B -#define I2O_CMD_UTIL_PARAMS_GET 0x06 -#define I2O_CMD_UTIL_PARAMS_SET 0x05 -#define I2O_CMD_UTIL_EVT_REGISTER 0x13 -#define I2O_CMD_UTIL_EVT_ACK 0x14 -#define I2O_CMD_UTIL_CONFIG_DIALOG 0x10 -#define I2O_CMD_UTIL_DEVICE_RESERVE 0x0D -#define I2O_CMD_UTIL_DEVICE_RELEASE 0x0F -#define I2O_CMD_UTIL_LOCK 0x17 -#define I2O_CMD_UTIL_LOCK_RELEASE 0x19 -#define I2O_CMD_UTIL_REPLY_FAULT_NOTIFY 0x15 - -#define I2O_CMD_SCSI_EXEC 0x81 -#define I2O_CMD_SCSI_ABORT 0x83 -#define I2O_CMD_SCSI_BUSRESET 0x27 - -#define I2O_CMD_BLOCK_READ 0x30 -#define I2O_CMD_BLOCK_WRITE 0x31 -#define I2O_CMD_BLOCK_CFLUSH 0x37 -#define I2O_CMD_BLOCK_MLOCK 0x49 -#define I2O_CMD_BLOCK_MUNLOCK 0x4B -#define I2O_CMD_BLOCK_MMOUNT 0x41 -#define I2O_CMD_BLOCK_MEJECT 0x43 - -#define I2O_PRIVATE_MSG 0xFF - -/* - * Init Outbound Q status - */ - -#define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS 0x01 -#define I2O_CMD_OUTBOUND_INIT_REJECTED 0x02 -#define I2O_CMD_OUTBOUND_INIT_FAILED 0x03 -#define I2O_CMD_OUTBOUND_INIT_COMPLETE 0x04 - -/* - * I2O Get Status State values - */ - -#define ADAPTER_STATE_INITIALIZING 0x01 -#define ADAPTER_STATE_RESET 0x02 -#define ADAPTER_STATE_HOLD 0x04 -#define ADAPTER_STATE_READY 0x05 -#define ADAPTER_STATE_OPERATIONAL 0x08 -#define ADAPTER_STATE_FAILED 0x10 -#define ADAPTER_STATE_FAULTED 0x11 - -/* I2O API function return values */ - -#define I2O_RTN_NO_ERROR 0 -#define I2O_RTN_NOT_INIT 1 -#define I2O_RTN_FREE_Q_EMPTY 2 -#define I2O_RTN_TCB_ERROR 3 -#define I2O_RTN_TRANSACTION_ERROR 4 -#define I2O_RTN_ADAPTER_ALREADY_INIT 5 -#define I2O_RTN_MALLOC_ERROR 6 -#define I2O_RTN_ADPTR_NOT_REGISTERED 7 -#define I2O_RTN_MSG_REPLY_TIMEOUT 8 -#define I2O_RTN_NO_STATUS 9 -#define I2O_RTN_NO_FIRM_VER 10 -#define I2O_RTN_NO_LINK_SPEED 11 - -/* Reply message status defines for all messages */ - -#define I2O_REPLY_STATUS_SUCCESS 0x00 -#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01 -#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02 -#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03 -#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04 -#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05 -#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06 -#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x08 -#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x09 -#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x0A -#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0B -#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80 - -/* Status codes and Error Information for Parameter functions */ - -#define I2O_PARAMS_STATUS_SUCCESS 0x00 -#define I2O_PARAMS_STATUS_BAD_KEY_ABORT 0x01 -#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE 0x02 -#define I2O_PARAMS_STATUS_BUFFER_FULL 0x03 -#define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL 0x04 -#define I2O_PARAMS_STATUS_FIELD_UNREADABLE 0x05 -#define I2O_PARAMS_STATUS_FIELD_UNWRITEABLE 0x06 -#define I2O_PARAMS_STATUS_INSUFFICIENT_FIELDS 0x07 -#define I2O_PARAMS_STATUS_INVALID_GROUP_ID 0x08 -#define I2O_PARAMS_STATUS_INVALID_OPERATION 0x09 -#define I2O_PARAMS_STATUS_NO_KEY_FIELD 0x0A -#define I2O_PARAMS_STATUS_NO_SUCH_FIELD 0x0B -#define I2O_PARAMS_STATUS_NON_DYNAMIC_GROUP 0x0C -#define I2O_PARAMS_STATUS_OPERATION_ERROR 0x0D -#define I2O_PARAMS_STATUS_SCALAR_ERROR 0x0E -#define I2O_PARAMS_STATUS_TABLE_ERROR 0x0F -#define I2O_PARAMS_STATUS_WRONG_GROUP_TYPE 0x10 - -/* DetailedStatusCode defines for Executive, DDM, Util and Transaction error - * messages: Table 3-2 Detailed Status Codes.*/ - -#define I2O_DSC_SUCCESS 0x0000 -#define I2O_DSC_BAD_KEY 0x0002 -#define I2O_DSC_TCL_ERROR 0x0003 -#define I2O_DSC_REPLY_BUFFER_FULL 0x0004 -#define I2O_DSC_NO_SUCH_PAGE 0x0005 -#define I2O_DSC_INSUFFICIENT_RESOURCE_SOFT 0x0006 -#define I2O_DSC_INSUFFICIENT_RESOURCE_HARD 0x0007 -#define I2O_DSC_CHAIN_BUFFER_TOO_LARGE 0x0009 -#define I2O_DSC_UNSUPPORTED_FUNCTION 0x000A -#define I2O_DSC_DEVICE_LOCKED 0x000B -#define I2O_DSC_DEVICE_RESET 0x000C -#define I2O_DSC_INAPPROPRIATE_FUNCTION 0x000D -#define I2O_DSC_INVALID_INITIATOR_ADDRESS 0x000E -#define I2O_DSC_INVALID_MESSAGE_FLAGS 0x000F -#define I2O_DSC_INVALID_OFFSET 0x0010 -#define I2O_DSC_INVALID_PARAMETER 0x0011 -#define I2O_DSC_INVALID_REQUEST 0x0012 -#define I2O_DSC_INVALID_TARGET_ADDRESS 0x0013 -#define I2O_DSC_MESSAGE_TOO_LARGE 0x0014 -#define I2O_DSC_MESSAGE_TOO_SMALL 0x0015 -#define I2O_DSC_MISSING_PARAMETER 0x0016 -#define I2O_DSC_TIMEOUT 0x0017 -#define I2O_DSC_UNKNOWN_ERROR 0x0018 -#define I2O_DSC_UNKNOWN_FUNCTION 0x0019 -#define I2O_DSC_UNSUPPORTED_VERSION 0x001A -#define I2O_DSC_DEVICE_BUSY 0x001B -#define I2O_DSC_DEVICE_NOT_AVAILABLE 0x001C - -/* Device Claim Types */ -#define I2O_CLAIM_PRIMARY 0x01000000 -#define I2O_CLAIM_MANAGEMENT 0x02000000 -#define I2O_CLAIM_AUTHORIZED 0x03000000 -#define I2O_CLAIM_SECONDARY 0x04000000 - -/* Message header defines for VersionOffset */ -#define I2OVER15 0x0001 -#define I2OVER20 0x0002 -/* Default is 1.5, FIXME: Need support for both 1.5 and 2.0 */ -#define I2OVERSION I2OVER15 -#define SGL_OFFSET_0 I2OVERSION -#define SGL_OFFSET_4 (0x0040 | I2OVERSION) -#define SGL_OFFSET_5 (0x0050 | I2OVERSION) -#define SGL_OFFSET_6 (0x0060 | I2OVERSION) -#define SGL_OFFSET_7 (0x0070 | I2OVERSION) -#define SGL_OFFSET_8 (0x0080 | I2OVERSION) -#define SGL_OFFSET_9 (0x0090 | I2OVERSION) -#define SGL_OFFSET_10 (0x00A0 | I2OVERSION) -#define SGL_OFFSET_12 (0x00C0 | I2OVERSION) - -#define TRL_OFFSET_5 (0x0050 | I2OVERSION) -#define TRL_OFFSET_6 (0x0060 | I2OVERSION) - - /* msg header defines for MsgFlags */ -#define MSG_STATIC 0x0100 -#define MSG_64BIT_CNTXT 0x0200 -#define MSG_MULTI_TRANS 0x1000 -#define MSG_FAIL 0x2000 -#define MSG_LAST 0x4000 -#define MSG_REPLY 0x8000 - - /* minimum size msg */ -#define THREE_WORD_MSG_SIZE 0x00030000 -#define FOUR_WORD_MSG_SIZE 0x00040000 -#define FIVE_WORD_MSG_SIZE 0x00050000 -#define SIX_WORD_MSG_SIZE 0x00060000 -#define SEVEN_WORD_MSG_SIZE 0x00070000 -#define EIGHT_WORD_MSG_SIZE 0x00080000 -#define NINE_WORD_MSG_SIZE 0x00090000 -#define TEN_WORD_MSG_SIZE 0x000A0000 -#define I2O_MESSAGE_SIZE(x) ((x)<<16) - - -/* Special TID Assignments */ - -#define ADAPTER_TID 0 -#define HOST_TID 1 - -#define MSG_FRAME_SIZE 128 -#define NMBR_MSG_FRAMES 128 - -#define MSG_POOL_SIZE 16384 - -#define I2O_POST_WAIT_OK 0 -#define I2O_POST_WAIT_TIMEOUT -ETIMEDOUT - - -#endif /* __KERNEL__ */ - -#endif /* _SCSI_I2O_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/dpt/dpti_ioctl.h b/ANDROID_3.4.5/drivers/scsi/dpt/dpti_ioctl.h deleted file mode 100644 index f6023672..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dpt/dpti_ioctl.h +++ /dev/null @@ -1,139 +0,0 @@ -/*************************************************************************** - dpti_ioctl.h - description - ------------------- - begin : Thu Sep 7 2000 - copyright : (C) 2001 by Adaptec - - See Documentation/scsi/dpti.txt for history, notes, license info - and credits - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -/*************************************************************************** - * This file is generated from osd_unix.h * - * *************************************************************************/ - -#ifndef _dpti_ioctl_h -#define _dpti_ioctl_h - -// IOCTL interface commands - -#ifndef _IOWR -# define _IOWR(x,y,z) (((x)<<8)|y) -#endif -#ifndef _IOW -# define _IOW(x,y,z) (((x)<<8)|y) -#endif -#ifndef _IOR -# define _IOR(x,y,z) (((x)<<8)|y) -#endif -#ifndef _IO -# define _IO(x,y) (((x)<<8)|y) -#endif -/* EATA PassThrough Command */ -#define EATAUSRCMD _IOWR('D',65,EATA_CP) -/* Set Debug Level If Enabled */ -#define DPT_DEBUG _IOW('D',66,int) -/* Get Signature Structure */ -#define DPT_SIGNATURE _IOR('D',67,dpt_sig_S) -#if defined __bsdi__ -#define DPT_SIGNATURE_PACKED _IOR('D',67,dpt_sig_S_Packed) -#endif -/* Get Number Of DPT Adapters */ -#define DPT_NUMCTRLS _IOR('D',68,int) -/* Get Adapter Info Structure */ -#define DPT_CTRLINFO _IOR('D',69,CtrlInfo) -/* Get Statistics If Enabled */ -#define DPT_STATINFO _IO('D',70) -/* Clear Stats If Enabled */ -#define DPT_CLRSTAT _IO('D',71) -/* Get System Info Structure */ -#define DPT_SYSINFO _IOR('D',72,sysInfo_S) -/* Set Timeout Value */ -#define DPT_TIMEOUT _IO('D',73) -/* Get config Data */ -#define DPT_CONFIG _IO('D',74) -/* Get Blink LED Code */ -#define DPT_BLINKLED _IOR('D',75,int) -/* Get Statistical information (if available) */ -#define DPT_STATS_INFO _IOR('D',80,STATS_DATA) -/* Clear the statistical information */ -#define DPT_STATS_CLEAR _IO('D',81) -/* Get Performance metrics */ -#define DPT_PERF_INFO _IOR('D',82,dpt_perf_t) -/* Send an I2O command */ -#define I2OUSRCMD _IO('D',76) -/* Inform driver to re-acquire LCT information */ -#define I2ORESCANCMD _IO('D',77) -/* Inform driver to reset adapter */ -#define I2ORESETCMD _IO('D',78) -/* See if the target is mounted */ -#define DPT_TARGET_BUSY _IOR('D',79, TARGET_BUSY_T) - - - /* Structure Returned From Get Controller Info */ - -typedef struct { - uCHAR state; /* Operational state */ - uCHAR id; /* Host adapter SCSI id */ - int vect; /* Interrupt vector number */ - int base; /* Base I/O address */ - int njobs; /* # of jobs sent to HA */ - int qdepth; /* Controller queue depth. */ - int wakebase; /* mpx wakeup base index. */ - uINT SGsize; /* Scatter/Gather list size. */ - unsigned heads; /* heads for drives on cntlr. */ - unsigned sectors; /* sectors for drives on cntlr. */ - uCHAR do_drive32; /* Flag for Above 16 MB Ability */ - uCHAR BusQuiet; /* SCSI Bus Quiet Flag */ - char idPAL[4]; /* 4 Bytes Of The ID Pal */ - uCHAR primary; /* 1 For Primary, 0 For Secondary */ - uCHAR eataVersion; /* EATA Version */ - uINT cpLength; /* EATA Command Packet Length */ - uINT spLength; /* EATA Status Packet Length */ - uCHAR drqNum; /* DRQ Index (0,5,6,7) */ - uCHAR flag1; /* EATA Flags 1 (Byte 9) */ - uCHAR flag2; /* EATA Flags 2 (Byte 30) */ -} CtrlInfo; - -typedef struct { - uSHORT length; // Remaining length of this - uSHORT drvrHBAnum; // Relative HBA # used by the driver - uINT baseAddr; // Base I/O address - uSHORT blinkState; // Blink LED state (0=Not in blink LED) - uCHAR pciBusNum; // PCI Bus # (Optional) - uCHAR pciDeviceNum; // PCI Device # (Optional) - uSHORT hbaFlags; // Miscellaneous HBA flags - uSHORT Interrupt; // Interrupt set for this device. -# if (defined(_DPT_ARC)) - uINT baseLength; - ADAPTER_OBJECT *AdapterObject; - LARGE_INTEGER DmaLogicalAddress; - PVOID DmaVirtualAddress; - LARGE_INTEGER ReplyLogicalAddress; - PVOID ReplyVirtualAddress; -# else - uINT reserved1; // Reserved for future expansion - uINT reserved2; // Reserved for future expansion - uINT reserved3; // Reserved for future expansion -# endif -} drvrHBAinfo_S; - -typedef struct TARGET_BUSY -{ - uLONG channel; - uLONG id; - uLONG lun; - uLONG isBusy; -} TARGET_BUSY_T; - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/dpt/dptsig.h b/ANDROID_3.4.5/drivers/scsi/dpt/dptsig.h deleted file mode 100644 index a6644b33..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dpt/dptsig.h +++ /dev/null @@ -1,336 +0,0 @@ -/* BSDI dptsig.h,v 1.7 1998/06/03 19:15:00 karels Exp */ - -/* - * Copyright (c) 1996-1999 Distributed Processing Technology Corporation - * All rights reserved. - * - * Redistribution and use in source form, with or without modification, are - * permitted provided that redistributions of source code must retain the - * above copyright notice, this list of conditions and the following disclaimer. - * - * This software is provided `as is' by Distributed Processing Technology and - * any express or implied warranties, including, but not limited to, the - * implied warranties of merchantability and fitness for a particular purpose, - * are disclaimed. In no event shall Distributed Processing Technology be - * liable for any direct, indirect, incidental, special, exemplary or - * consequential damages (including, but not limited to, procurement of - * substitute goods or services; loss of use, data, or profits; or business - * interruptions) however caused and on any theory of liability, whether in - * contract, strict liability, or tort (including negligence or otherwise) - * arising in any way out of the use of this driver software, even if advised - * of the possibility of such damage. - * - */ - -#ifndef __DPTSIG_H_ -#define __DPTSIG_H_ -#ifdef _SINIX_ADDON -#include "dpt.h" -#endif -/* DPT SIGNATURE SPEC AND HEADER FILE */ -/* Signature Version 1 (sorry no 'A') */ - -/* to make sure we are talking the same size under all OS's */ -typedef unsigned char sigBYTE; -typedef unsigned short sigWORD; -typedef unsigned int sigINT; - -/* - * use sigWORDLittleEndian for: - * dsCapabilities - * dsDeviceSupp - * dsAdapterSupp - * dsApplication - * use sigLONGLittleEndian for: - * dsOS - * so that the sig can be standardised to Little Endian - */ -#if (defined(_DPT_BIG_ENDIAN)) -# define sigWORDLittleEndian(x) ((((x)&0xFF)<<8)|(((x)>>8)&0xFF)) -# define sigLONGLittleEndian(x) \ - ((((x)&0xFF)<<24) | \ - (((x)&0xFF00)<<8) | \ - (((x)&0xFF0000L)>>8) | \ - (((x)&0xFF000000L)>>24)) -#else -# define sigWORDLittleEndian(x) (x) -# define sigLONGLittleEndian(x) (x) -#endif - -/* must make sure the structure is not word or double-word aligned */ -/* --------------------------------------------------------------- */ -/* Borland will ignore the following pragma: */ -/* Word alignment is OFF by default. If in the, IDE make */ -/* sure that Options | Compiler | Code Generation | Word Alignment */ -/* is not checked. If using BCC, do not use the -a option. */ - -#ifndef NO_PACK -#if defined (_DPT_AIX) -#pragma options align=packed -#else -#pragma pack(1) -#endif /* aix */ -#endif -/* For the Macintosh */ -#ifdef STRUCTALIGNMENTSUPPORTED -#pragma options align=mac68k -#endif - - -/* Current Signature Version - sigBYTE dsSigVersion; */ -/* ------------------------------------------------------------------ */ -#define SIG_VERSION 1 - -/* Processor Family - sigBYTE dsProcessorFamily; DISTINCT VALUES */ -/* ------------------------------------------------------------------ */ -/* What type of processor the file is meant to run on. */ -/* This will let us know whether to read sigWORDs as high/low or low/high. */ -#define PROC_INTEL 0x00 /* Intel 80x86/ia64 */ -#define PROC_MOTOROLA 0x01 /* Motorola 68K */ -#define PROC_MIPS4000 0x02 /* MIPS RISC 4000 */ -#define PROC_ALPHA 0x03 /* DEC Alpha */ -#define PROC_POWERPC 0x04 /* IBM Power PC */ -#define PROC_i960 0x05 /* Intel i960 */ -#define PROC_ULTRASPARC 0x06 /* SPARC processor */ - -/* Specific Minimim Processor - sigBYTE dsProcessor; FLAG BITS */ -/* ------------------------------------------------------------------ */ -/* Different bit definitions dependent on processor_family */ - -/* PROC_INTEL: */ -#define PROC_8086 0x01 /* Intel 8086 */ -#define PROC_286 0x02 /* Intel 80286 */ -#define PROC_386 0x04 /* Intel 80386 */ -#define PROC_486 0x08 /* Intel 80486 */ -#define PROC_PENTIUM 0x10 /* Intel 586 aka P5 aka Pentium */ -#define PROC_SEXIUM 0x20 /* Intel 686 aka P6 aka Pentium Pro or MMX */ -#define PROC_IA64 0x40 /* Intel IA64 processor */ - -/* PROC_i960: */ -#define PROC_960RX 0x01 /* Intel 80960RC/RD */ -#define PROC_960HX 0x02 /* Intel 80960HA/HD/HT */ - -/* PROC_MOTOROLA: */ -#define PROC_68000 0x01 /* Motorola 68000 */ -#define PROC_68010 0x02 /* Motorola 68010 */ -#define PROC_68020 0x04 /* Motorola 68020 */ -#define PROC_68030 0x08 /* Motorola 68030 */ -#define PROC_68040 0x10 /* Motorola 68040 */ - -/* PROC_POWERPC */ -#define PROC_PPC601 0x01 /* PowerPC 601 */ -#define PROC_PPC603 0x02 /* PowerPC 603 */ -#define PROC_PPC604 0x04 /* PowerPC 604 */ - -/* PROC_MIPS4000: */ -#define PROC_R4000 0x01 /* MIPS R4000 */ - -/* Filetype - sigBYTE dsFiletype; DISTINCT VALUES */ -/* ------------------------------------------------------------------ */ -#define FT_EXECUTABLE 0 /* Executable Program */ -#define FT_SCRIPT 1 /* Script/Batch File??? */ -#define FT_HBADRVR 2 /* HBA Driver */ -#define FT_OTHERDRVR 3 /* Other Driver */ -#define FT_IFS 4 /* Installable Filesystem Driver */ -#define FT_ENGINE 5 /* DPT Engine */ -#define FT_COMPDRVR 6 /* Compressed Driver Disk */ -#define FT_LANGUAGE 7 /* Foreign Language file */ -#define FT_FIRMWARE 8 /* Downloadable or actual Firmware */ -#define FT_COMMMODL 9 /* Communications Module */ -#define FT_INT13 10 /* INT 13 style HBA Driver */ -#define FT_HELPFILE 11 /* Help file */ -#define FT_LOGGER 12 /* Event Logger */ -#define FT_INSTALL 13 /* An Install Program */ -#define FT_LIBRARY 14 /* Storage Manager Real-Mode Calls */ -#define FT_RESOURCE 15 /* Storage Manager Resource File */ -#define FT_MODEM_DB 16 /* Storage Manager Modem Database */ - -/* Filetype flags - sigBYTE dsFiletypeFlags; FLAG BITS */ -/* ------------------------------------------------------------------ */ -#define FTF_DLL 0x01 /* Dynamic Link Library */ -#define FTF_NLM 0x02 /* Netware Loadable Module */ -#define FTF_OVERLAYS 0x04 /* Uses overlays */ -#define FTF_DEBUG 0x08 /* Debug version */ -#define FTF_TSR 0x10 /* TSR */ -#define FTF_SYS 0x20 /* DOS Loadable driver */ -#define FTF_PROTECTED 0x40 /* Runs in protected mode */ -#define FTF_APP_SPEC 0x80 /* Application Specific */ -#define FTF_ROM (FTF_SYS|FTF_TSR) /* Special Case */ - -/* OEM - sigBYTE dsOEM; DISTINCT VALUES */ -/* ------------------------------------------------------------------ */ -#define OEM_DPT 0 /* DPT */ -#define OEM_ATT 1 /* ATT */ -#define OEM_NEC 2 /* NEC */ -#define OEM_ALPHA 3 /* Alphatronix */ -#define OEM_AST 4 /* AST */ -#define OEM_OLIVETTI 5 /* Olivetti */ -#define OEM_SNI 6 /* Siemens/Nixdorf */ -#define OEM_SUN 7 /* SUN Microsystems */ - -/* Operating System - sigLONG dsOS; FLAG BITS */ -/* ------------------------------------------------------------------ */ -#define OS_DOS 0x00000001 /* PC/MS-DOS */ -#define OS_WINDOWS 0x00000002 /* Microsoft Windows 3.x */ -#define OS_WINDOWS_NT 0x00000004 /* Microsoft Windows NT */ -#define OS_OS2M 0x00000008 /* OS/2 1.2.x,MS 1.3.0,IBM 1.3.x - Monolithic */ -#define OS_OS2L 0x00000010 /* Microsoft OS/2 1.301 - LADDR */ -#define OS_OS22x 0x00000020 /* IBM OS/2 2.x */ -#define OS_NW286 0x00000040 /* Novell NetWare 286 */ -#define OS_NW386 0x00000080 /* Novell NetWare 386 */ -#define OS_GEN_UNIX 0x00000100 /* Generic Unix */ -#define OS_SCO_UNIX 0x00000200 /* SCO Unix */ -#define OS_ATT_UNIX 0x00000400 /* ATT Unix */ -#define OS_UNIXWARE 0x00000800 /* USL Unix */ -#define OS_INT_UNIX 0x00001000 /* Interactive Unix */ -#define OS_SOLARIS 0x00002000 /* SunSoft Solaris */ -#define OS_QNX 0x00004000 /* QNX for Tom Moch */ -#define OS_NEXTSTEP 0x00008000 /* NeXTSTEP/OPENSTEP/MACH */ -#define OS_BANYAN 0x00010000 /* Banyan Vines */ -#define OS_OLIVETTI_UNIX 0x00020000/* Olivetti Unix */ -#define OS_MAC_OS 0x00040000 /* Mac OS */ -#define OS_WINDOWS_95 0x00080000 /* Microsoft Windows '95 */ -#define OS_NW4x 0x00100000 /* Novell Netware 4.x */ -#define OS_BSDI_UNIX 0x00200000 /* BSDi Unix BSD/OS 2.0 and up */ -#define OS_AIX_UNIX 0x00400000 /* AIX Unix */ -#define OS_FREE_BSD 0x00800000 /* FreeBSD Unix */ -#define OS_LINUX 0x01000000 /* Linux */ -#define OS_DGUX_UNIX 0x02000000 /* Data General Unix */ -#define OS_SINIX_N 0x04000000 /* SNI SINIX-N */ -#define OS_PLAN9 0x08000000 /* ATT Plan 9 */ -#define OS_TSX 0x10000000 /* SNH TSX-32 */ - -#define OS_OTHER 0x80000000 /* Other */ - -/* Capabilities - sigWORD dsCapabilities; FLAG BITS */ -/* ------------------------------------------------------------------ */ -#define CAP_RAID0 0x0001 /* RAID-0 */ -#define CAP_RAID1 0x0002 /* RAID-1 */ -#define CAP_RAID3 0x0004 /* RAID-3 */ -#define CAP_RAID5 0x0008 /* RAID-5 */ -#define CAP_SPAN 0x0010 /* Spanning */ -#define CAP_PASS 0x0020 /* Provides passthrough */ -#define CAP_OVERLAP 0x0040 /* Passthrough supports overlapped commands */ -#define CAP_ASPI 0x0080 /* Supports ASPI Command Requests */ -#define CAP_ABOVE16MB 0x0100 /* ISA Driver supports greater than 16MB */ -#define CAP_EXTEND 0x8000 /* Extended info appears after description */ -#ifdef SNI_MIPS -#define CAP_CACHEMODE 0x1000 /* dpt_force_cache is set in driver */ -#endif - -/* Devices Supported - sigWORD dsDeviceSupp; FLAG BITS */ -/* ------------------------------------------------------------------ */ -#define DEV_DASD 0x0001 /* DASD (hard drives) */ -#define DEV_TAPE 0x0002 /* Tape drives */ -#define DEV_PRINTER 0x0004 /* Printers */ -#define DEV_PROC 0x0008 /* Processors */ -#define DEV_WORM 0x0010 /* WORM drives */ -#define DEV_CDROM 0x0020 /* CD-ROM drives */ -#define DEV_SCANNER 0x0040 /* Scanners */ -#define DEV_OPTICAL 0x0080 /* Optical Drives */ -#define DEV_JUKEBOX 0x0100 /* Jukebox */ -#define DEV_COMM 0x0200 /* Communications Devices */ -#define DEV_OTHER 0x0400 /* Other Devices */ -#define DEV_ALL 0xFFFF /* All SCSI Devices */ - -/* Adapters Families Supported - sigWORD dsAdapterSupp; FLAG BITS */ -/* ------------------------------------------------------------------ */ -#define ADF_2001 0x0001 /* PM2001 */ -#define ADF_2012A 0x0002 /* PM2012A */ -#define ADF_PLUS_ISA 0x0004 /* PM2011,PM2021 */ -#define ADF_PLUS_EISA 0x0008 /* PM2012B,PM2022 */ -#define ADF_SC3_ISA 0x0010 /* PM2021 */ -#define ADF_SC3_EISA 0x0020 /* PM2022,PM2122, etc */ -#define ADF_SC3_PCI 0x0040 /* SmartCache III PCI */ -#define ADF_SC4_ISA 0x0080 /* SmartCache IV ISA */ -#define ADF_SC4_EISA 0x0100 /* SmartCache IV EISA */ -#define ADF_SC4_PCI 0x0200 /* SmartCache IV PCI */ -#define ADF_SC5_PCI 0x0400 /* Fifth Generation I2O products */ -/* - * Combinations of products - */ -#define ADF_ALL_2000 (ADF_2001|ADF_2012A) -#define ADF_ALL_PLUS (ADF_PLUS_ISA|ADF_PLUS_EISA) -#define ADF_ALL_SC3 (ADF_SC3_ISA|ADF_SC3_EISA|ADF_SC3_PCI) -#define ADF_ALL_SC4 (ADF_SC4_ISA|ADF_SC4_EISA|ADF_SC4_PCI) -#define ADF_ALL_SC5 (ADF_SC5_PCI) -/* All EATA Cacheing Products */ -#define ADF_ALL_CACHE (ADF_ALL_PLUS|ADF_ALL_SC3|ADF_ALL_SC4) -/* All EATA Bus Mastering Products */ -#define ADF_ALL_MASTER (ADF_2012A|ADF_ALL_CACHE) -/* All EATA Adapter Products */ -#define ADF_ALL_EATA (ADF_2001|ADF_ALL_MASTER) -#define ADF_ALL ADF_ALL_EATA - -/* Application - sigWORD dsApplication; FLAG BITS */ -/* ------------------------------------------------------------------ */ -#define APP_DPTMGR 0x0001 /* DPT Storage Manager */ -#define APP_ENGINE 0x0002 /* DPT Engine */ -#define APP_SYTOS 0x0004 /* Sytron Sytos Plus */ -#define APP_CHEYENNE 0x0008 /* Cheyenne ARCServe + ARCSolo */ -#define APP_MSCDEX 0x0010 /* Microsoft CD-ROM extensions */ -#define APP_NOVABACK 0x0020 /* NovaStor Novaback */ -#define APP_AIM 0x0040 /* Archive Information Manager */ - -/* Requirements - sigBYTE dsRequirements; FLAG BITS */ -/* ------------------------------------------------------------------ */ -#define REQ_SMARTROM 0x01 /* Requires SmartROM to be present */ -#define REQ_DPTDDL 0x02 /* Requires DPTDDL.SYS to be loaded */ -#define REQ_HBA_DRIVER 0x04 /* Requires an HBA driver to be loaded */ -#define REQ_ASPI_TRAN 0x08 /* Requires an ASPI Transport Modules */ -#define REQ_ENGINE 0x10 /* Requires a DPT Engine to be loaded */ -#define REQ_COMM_ENG 0x20 /* Requires a DPT Communications Engine */ - -/* - * You may adjust dsDescription_size with an override to a value less than - * 50 so that the structure allocates less real space. - */ -#if (!defined(dsDescription_size)) -# define dsDescription_size 50 -#endif - -typedef struct dpt_sig { - char dsSignature[6]; /* ALWAYS "dPtSiG" */ - sigBYTE dsSigVersion; /* signature version (currently 1) */ - sigBYTE dsProcessorFamily; /* what type of processor */ - sigBYTE dsProcessor; /* precise processor */ - sigBYTE dsFiletype; /* type of file */ - sigBYTE dsFiletypeFlags; /* flags to specify load type, etc. */ - sigBYTE dsOEM; /* OEM file was created for */ - sigINT dsOS; /* which Operating systems */ - sigWORD dsCapabilities; /* RAID levels, etc. */ - sigWORD dsDeviceSupp; /* Types of SCSI devices supported */ - sigWORD dsAdapterSupp; /* DPT adapter families supported */ - sigWORD dsApplication; /* applications file is for */ - sigBYTE dsRequirements; /* Other driver dependencies */ - sigBYTE dsVersion; /* 1 */ - sigBYTE dsRevision; /* 'J' */ - sigBYTE dsSubRevision; /* '9' ' ' if N/A */ - sigBYTE dsMonth; /* creation month */ - sigBYTE dsDay; /* creation day */ - sigBYTE dsYear; /* creation year since 1980 (1993=13) */ - /* description (NULL terminated) */ - char dsDescription[dsDescription_size]; -} dpt_sig_S; -/* 32 bytes minimum - with no description. Put NULL at description[0] */ -/* 81 bytes maximum - with 49 character description plus NULL. */ - -/* This line added at Roycroft's request */ -/* Microsoft's NT compiler gets confused if you do a pack and don't */ -/* restore it. */ - -#ifndef NO_UNPACK -#if defined (_DPT_AIX) -#pragma options align=reset -#elif defined (UNPACK_FOUR) -#pragma pack(4) -#else -#pragma pack() -#endif /* aix */ -#endif -/* For the Macintosh */ -#ifdef STRUCTALIGNMENTSUPPORTED -#pragma options align=reset -#endif - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/dpt/osd_defs.h b/ANDROID_3.4.5/drivers/scsi/dpt/osd_defs.h deleted file mode 100644 index de3ae572..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dpt/osd_defs.h +++ /dev/null @@ -1,79 +0,0 @@ -/* BSDI osd_defs.h,v 1.4 1998/06/03 19:14:58 karels Exp */ -/* - * Copyright (c) 1996-1999 Distributed Processing Technology Corporation - * All rights reserved. - * - * Redistribution and use in source form, with or without modification, are - * permitted provided that redistributions of source code must retain the - * above copyright notice, this list of conditions and the following disclaimer. - * - * This software is provided `as is' by Distributed Processing Technology and - * any express or implied warranties, including, but not limited to, the - * implied warranties of merchantability and fitness for a particular purpose, - * are disclaimed. In no event shall Distributed Processing Technology be - * liable for any direct, indirect, incidental, special, exemplary or - * consequential damages (including, but not limited to, procurement of - * substitute goods or services; loss of use, data, or profits; or business - * interruptions) however caused and on any theory of liability, whether in - * contract, strict liability, or tort (including negligence or otherwise) - * arising in any way out of the use of this driver software, even if advised - * of the possibility of such damage. - * - */ - -#ifndef _OSD_DEFS_H -#define _OSD_DEFS_H - -/*File - OSD_DEFS.H - **************************************************************************** - * - *Description: - * - * This file contains the OS dependent defines. This file is included - *in osd_util.h and provides the OS specific defines for that file. - * - *Copyright Distributed Processing Technology, Corp. - * 140 Candace Dr. - * Maitland, Fl. 32751 USA - * Phone: (407) 830-5522 Fax: (407) 260-5366 - * All Rights Reserved - * - *Author: Doug Anderson - *Date: 1/31/94 - * - *Editors: - * - *Remarks: - * - * - *****************************************************************************/ - - -/*Definitions - Defines & Constants ----------------------------------------- */ - - /* Define the operating system */ -#if (defined(__linux__)) -# define _DPT_LINUX -#elif (defined(__bsdi__)) -# define _DPT_BSDI -#elif (defined(__FreeBSD__)) -# define _DPT_FREE_BSD -#else -# define _DPT_SCO -#endif - -#if defined (ZIL_CURSES) -#define _DPT_CURSES -#else -#define _DPT_MOTIF -#endif - - /* Redefine 'far' to nothing - no far pointer type required in UNIX */ -#define far - - /* Define the mutually exclusive semaphore type */ -#define SEMAPHORE_T unsigned int * - /* Define a handle to a DLL */ -#define DLL_HANDLE_T unsigned int * - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/dpt/osd_util.h b/ANDROID_3.4.5/drivers/scsi/dpt/osd_util.h deleted file mode 100644 index b2613c2e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dpt/osd_util.h +++ /dev/null @@ -1,358 +0,0 @@ -/* BSDI osd_util.h,v 1.8 1998/06/03 19:14:58 karels Exp */ - -/* - * Copyright (c) 1996-1999 Distributed Processing Technology Corporation - * All rights reserved. - * - * Redistribution and use in source form, with or without modification, are - * permitted provided that redistributions of source code must retain the - * above copyright notice, this list of conditions and the following disclaimer. - * - * This software is provided `as is' by Distributed Processing Technology and - * any express or implied warranties, including, but not limited to, the - * implied warranties of merchantability and fitness for a particular purpose, - * are disclaimed. In no event shall Distributed Processing Technology be - * liable for any direct, indirect, incidental, special, exemplary or - * consequential damages (including, but not limited to, procurement of - * substitute goods or services; loss of use, data, or profits; or business - * interruptions) however caused and on any theory of liability, whether in - * contract, strict liability, or tort (including negligence or otherwise) - * arising in any way out of the use of this driver software, even if advised - * of the possibility of such damage. - * - */ - -#ifndef __OSD_UTIL_H -#define __OSD_UTIL_H - -/*File - OSD_UTIL.H - **************************************************************************** - * - *Description: - * - * This file contains defines and function prototypes that are - *operating system dependent. The resources defined in this file - *are not specific to any particular application. - * - *Copyright Distributed Processing Technology, Corp. - * 140 Candace Dr. - * Maitland, Fl. 32751 USA - * Phone: (407) 830-5522 Fax: (407) 260-5366 - * All Rights Reserved - * - *Author: Doug Anderson - *Date: 1/7/94 - * - *Editors: - * - *Remarks: - * - * - *****************************************************************************/ - - -/*Definitions - Defines & Constants ----------------------------------------- */ - -/*----------------------------- */ -/* Operating system selections: */ -/*----------------------------- */ - -/*#define _DPT_MSDOS */ -/*#define _DPT_WIN_3X */ -/*#define _DPT_WIN_4X */ -/*#define _DPT_WIN_NT */ -/*#define _DPT_NETWARE */ -/*#define _DPT_OS2 */ -/*#define _DPT_SCO */ -/*#define _DPT_UNIXWARE */ -/*#define _DPT_SOLARIS */ -/*#define _DPT_NEXTSTEP */ -/*#define _DPT_BANYAN */ - -/*-------------------------------- */ -/* Include the OS specific defines */ -/*-------------------------------- */ - -/*#define OS_SELECTION From Above List */ -/*#define SEMAPHORE_T ??? */ -/*#define DLL_HANDLE_T ??? */ - -#if (defined(KERNEL) && (defined(__FreeBSD__) || defined(__bsdi__))) -# include "i386/isa/dpt_osd_defs.h" -#else -# include "osd_defs.h" -#endif - -#ifndef DPT_UNALIGNED - #define DPT_UNALIGNED -#endif - -#ifndef DPT_EXPORT - #define DPT_EXPORT -#endif - -#ifndef DPT_IMPORT - #define DPT_IMPORT -#endif - -#ifndef DPT_RUNTIME_IMPORT - #define DPT_RUNTIME_IMPORT DPT_IMPORT -#endif - -/*--------------------- */ -/* OS dependent defines */ -/*--------------------- */ - -#if defined (_DPT_MSDOS) || defined (_DPT_WIN_3X) - #define _DPT_16_BIT -#else - #define _DPT_32_BIT -#endif - -#if defined (_DPT_SCO) || defined (_DPT_UNIXWARE) || defined (_DPT_SOLARIS) || defined (_DPT_AIX) || defined (SNI_MIPS) || defined (_DPT_BSDI) || defined (_DPT_FREE_BSD) || defined(_DPT_LINUX) - #define _DPT_UNIX -#endif - -#if defined (_DPT_WIN_3x) || defined (_DPT_WIN_4X) || defined (_DPT_WIN_NT) \ - || defined (_DPT_OS2) - #define _DPT_DLL_SUPPORT -#endif - -#if !defined (_DPT_MSDOS) && !defined (_DPT_WIN_3X) && !defined (_DPT_NETWARE) - #define _DPT_PREEMPTIVE -#endif - -#if !defined (_DPT_MSDOS) && !defined (_DPT_WIN_3X) - #define _DPT_MULTI_THREADED -#endif - -#if !defined (_DPT_MSDOS) - #define _DPT_MULTI_TASKING -#endif - - /* These exist for platforms that */ - /* chunk when accessing mis-aligned */ - /* data */ -#if defined (SNI_MIPS) || defined (_DPT_SOLARIS) - #if defined (_DPT_BIG_ENDIAN) - #if !defined (_DPT_STRICT_ALIGN) - #define _DPT_STRICT_ALIGN - #endif - #endif -#endif - - /* Determine if in C or C++ mode */ -#ifdef __cplusplus - #define _DPT_CPP -#else - #define _DPT_C -#endif - -/*-------------------------------------------------------------------*/ -/* Under Solaris the compiler refuses to accept code like: */ -/* { {"DPT"}, 0, NULL .... }, */ -/* and complains about the {"DPT"} part by saying "cannot use { } */ -/* to initialize char*". */ -/* */ -/* By defining these ugly macros we can get around this and also */ -/* not have to copy and #ifdef large sections of code. I know that */ -/* these macros are *really* ugly, but they should help reduce */ -/* maintenance in the long run. */ -/* */ -/*-------------------------------------------------------------------*/ -#if !defined (DPTSQO) - #if defined (_DPT_SOLARIS) - #define DPTSQO - #define DPTSQC - #else - #define DPTSQO { - #define DPTSQC } - #endif /* solaris */ -#endif /* DPTSQO */ - - -/*---------------------- */ -/* OS dependent typedefs */ -/*---------------------- */ - -#if defined (_DPT_MSDOS) || defined (_DPT_SCO) - #define BYTE unsigned char - #define WORD unsigned short -#endif - -#ifndef _DPT_TYPEDEFS - #define _DPT_TYPEDEFS - typedef unsigned char uCHAR; - typedef unsigned short uSHORT; - typedef unsigned int uINT; - typedef unsigned long uLONG; - - typedef union { - uCHAR u8[4]; - uSHORT u16[2]; - uLONG u32; - } access_U; -#endif - -#if !defined (NULL) - #define NULL 0 -#endif - - -/*Prototypes - function ----------------------------------------------------- */ - -#ifdef __cplusplus - extern "C" { /* Declare all these functions as "C" functions */ -#endif - -/*------------------------ */ -/* Byte reversal functions */ -/*------------------------ */ - - /* Reverses the byte ordering of a 2 byte variable */ -#if (!defined(osdSwap2)) - uSHORT osdSwap2(DPT_UNALIGNED uSHORT *); -#endif // !osdSwap2 - - /* Reverses the byte ordering of a 4 byte variable and shifts left 8 bits */ -#if (!defined(osdSwap3)) - uLONG osdSwap3(DPT_UNALIGNED uLONG *); -#endif // !osdSwap3 - - -#ifdef _DPT_NETWARE - #include "novpass.h" /* For DPT_Bswapl() prototype */ - /* Inline the byte swap */ - #ifdef __cplusplus - inline uLONG osdSwap4(uLONG *inLong) { - return *inLong = DPT_Bswapl(*inLong); - } - #else - #define osdSwap4(inLong) DPT_Bswapl(inLong) - #endif // cplusplus -#else - /* Reverses the byte ordering of a 4 byte variable */ -# if (!defined(osdSwap4)) - uLONG osdSwap4(DPT_UNALIGNED uLONG *); -# endif // !osdSwap4 - - /* The following functions ALWAYS swap regardless of the * - * presence of DPT_BIG_ENDIAN */ - - uSHORT trueSwap2(DPT_UNALIGNED uSHORT *); - uLONG trueSwap4(DPT_UNALIGNED uLONG *); - -#endif // netware - - -/*-------------------------------------* - * Network order swap functions * - * * - * These functions/macros will be used * - * by the structure insert()/extract() * - * functions. * - * - * We will enclose all structure * - * portability modifications inside * - * #ifdefs. When we are ready, we * - * will #define DPT_PORTABLE to begin * - * using the modifications. * - *-------------------------------------*/ -uLONG netSwap4(uLONG val); - -#if defined (_DPT_BIG_ENDIAN) - -// for big-endian we need to swap - -#ifndef NET_SWAP_2 -#define NET_SWAP_2(x) (((x) >> 8) | ((x) << 8)) -#endif // NET_SWAP_2 - -#ifndef NET_SWAP_4 -#define NET_SWAP_4(x) netSwap4((x)) -#endif // NET_SWAP_4 - -#else - -// for little-endian we don't need to do anything - -#ifndef NET_SWAP_2 -#define NET_SWAP_2(x) (x) -#endif // NET_SWAP_2 - -#ifndef NET_SWAP_4 -#define NET_SWAP_4(x) (x) -#endif // NET_SWAP_4 - -#endif // big endian - - - -/*----------------------------------- */ -/* Run-time loadable module functions */ -/*----------------------------------- */ - - /* Loads the specified run-time loadable DLL */ -DLL_HANDLE_T osdLoadModule(uCHAR *); - /* Unloads the specified run-time loadable DLL */ -uSHORT osdUnloadModule(DLL_HANDLE_T); - /* Returns a pointer to a function inside a run-time loadable DLL */ -void * osdGetFnAddr(DLL_HANDLE_T,uCHAR *); - -/*--------------------------------------- */ -/* Mutually exclusive semaphore functions */ -/*--------------------------------------- */ - - /* Create a named semaphore */ -SEMAPHORE_T osdCreateNamedSemaphore(char *); - /* Create a mutually exlusive semaphore */ -SEMAPHORE_T osdCreateSemaphore(void); - /* create an event semaphore */ -SEMAPHORE_T osdCreateEventSemaphore(void); - /* create a named event semaphore */ -SEMAPHORE_T osdCreateNamedEventSemaphore(char *); - - /* Destroy the specified mutually exclusive semaphore object */ -uSHORT osdDestroySemaphore(SEMAPHORE_T); - /* Request access to the specified mutually exclusive semaphore */ -uLONG osdRequestSemaphore(SEMAPHORE_T,uLONG); - /* Release access to the specified mutually exclusive semaphore */ -uSHORT osdReleaseSemaphore(SEMAPHORE_T); - /* wait for a event to happen */ -uLONG osdWaitForEventSemaphore(SEMAPHORE_T, uLONG); - /* signal an event */ -uLONG osdSignalEventSemaphore(SEMAPHORE_T); - /* reset the event */ -uLONG osdResetEventSemaphore(SEMAPHORE_T); - -/*----------------- */ -/* Thread functions */ -/*----------------- */ - - /* Releases control to the task switcher in non-preemptive */ - /* multitasking operating systems. */ -void osdSwitchThreads(void); - - /* Starts a thread function */ -uLONG osdStartThread(void *,void *); - -/* what is my thread id */ -uLONG osdGetThreadID(void); - -/* wakes up the specifed thread */ -void osdWakeThread(uLONG); - -/* osd sleep for x milliseconds */ -void osdSleep(uLONG); - -#define DPT_THREAD_PRIORITY_LOWEST 0x00 -#define DPT_THREAD_PRIORITY_NORMAL 0x01 -#define DPT_THREAD_PRIORITY_HIGHEST 0x02 - -uCHAR osdSetThreadPriority(uLONG tid, uCHAR priority); - -#ifdef __cplusplus - } /* end the xtern "C" declaration */ -#endif - -#endif /* osd_util_h */ diff --git a/ANDROID_3.4.5/drivers/scsi/dpt/sys_info.h b/ANDROID_3.4.5/drivers/scsi/dpt/sys_info.h deleted file mode 100644 index a4aa1c31..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dpt/sys_info.h +++ /dev/null @@ -1,417 +0,0 @@ -/* BSDI sys_info.h,v 1.6 1998/06/03 19:14:59 karels Exp */ - -/* - * Copyright (c) 1996-1999 Distributed Processing Technology Corporation - * All rights reserved. - * - * Redistribution and use in source form, with or without modification, are - * permitted provided that redistributions of source code must retain the - * above copyright notice, this list of conditions and the following disclaimer. - * - * This software is provided `as is' by Distributed Processing Technology and - * any express or implied warranties, including, but not limited to, the - * implied warranties of merchantability and fitness for a particular purpose, - * are disclaimed. In no event shall Distributed Processing Technology be - * liable for any direct, indirect, incidental, special, exemplary or - * consequential damages (including, but not limited to, procurement of - * substitute goods or services; loss of use, data, or profits; or business - * interruptions) however caused and on any theory of liability, whether in - * contract, strict liability, or tort (including negligence or otherwise) - * arising in any way out of the use of this driver software, even if advised - * of the possibility of such damage. - * - */ - -#ifndef __SYS_INFO_H -#define __SYS_INFO_H - -/*File - SYS_INFO.H - **************************************************************************** - * - *Description: - * - * This file contains structure definitions for the OS dependent - *layer system information buffers. - * - *Copyright Distributed Processing Technology, Corp. - * 140 Candace Dr. - * Maitland, Fl. 32751 USA - * Phone: (407) 830-5522 Fax: (407) 260-5366 - * All Rights Reserved - * - *Author: Don Kemper - *Date: 5/10/94 - * - *Editors: - * - *Remarks: - * - * - *****************************************************************************/ - - -/*Include Files ------------------------------------------------------------- */ - -#include "osd_util.h" - -#ifndef NO_PACK -#if defined (_DPT_AIX) -#pragma options align=packed -#else -#pragma pack(1) -#endif /* aix */ -#endif // no unpack - - -/*struct - driveParam_S - start - *=========================================================================== - * - *Description: - * - * This structure defines the drive parameters seen during - *booting. - * - *---------------------------------------------------------------------------*/ - -#ifdef __cplusplus - struct driveParam_S { -#else - typedef struct { -#endif - - uSHORT cylinders; /* Up to 1024 */ - uCHAR heads; /* Up to 255 */ - uCHAR sectors; /* Up to 63 */ - -#ifdef __cplusplus - -//---------- Portability Additions ----------- in sp_sinfo.cpp -#ifdef DPT_PORTABLE - uSHORT netInsert(dptBuffer_S *buffer); - uSHORT netExtract(dptBuffer_S *buffer); -#endif // DPT PORTABLE -//-------------------------------------------- - - }; -#else - } driveParam_S; -#endif -/*driveParam_S - end */ - - -/*struct - sysInfo_S - start - *=========================================================================== - * - *Description: - * - * This structure defines the command system information that - *should be returned by every OS dependent layer. - * - *---------------------------------------------------------------------------*/ - -/*flags - bit definitions */ -#define SI_CMOS_Valid 0x0001 -#define SI_NumDrivesValid 0x0002 -#define SI_ProcessorValid 0x0004 -#define SI_MemorySizeValid 0x0008 -#define SI_DriveParamsValid 0x0010 -#define SI_SmartROMverValid 0x0020 -#define SI_OSversionValid 0x0040 -#define SI_OSspecificValid 0x0080 /* 1 if OS structure returned */ -#define SI_BusTypeValid 0x0100 - -#define SI_ALL_VALID 0x0FFF /* All Std SysInfo is valid */ -#define SI_NO_SmartROM 0x8000 - -/*busType - definitions */ -#define SI_ISA_BUS 0x00 -#define SI_MCA_BUS 0x01 -#define SI_EISA_BUS 0x02 -#define SI_PCI_BUS 0x04 - -#ifdef __cplusplus - struct sysInfo_S { -#else - typedef struct { -#endif - - uCHAR drive0CMOS; /* CMOS Drive 0 Type */ - uCHAR drive1CMOS; /* CMOS Drive 1 Type */ - uCHAR numDrives; /* 0040:0075 contents */ - uCHAR processorFamily; /* Same as DPTSIG's definition */ - uCHAR processorType; /* Same as DPTSIG's definition */ - uCHAR smartROMMajorVersion; - uCHAR smartROMMinorVersion; /* SmartROM version */ - uCHAR smartROMRevision; - uSHORT flags; /* See bit definitions above */ - uSHORT conventionalMemSize; /* in KB */ - uINT extendedMemSize; /* in KB */ - uINT osType; /* Same as DPTSIG's definition */ - uCHAR osMajorVersion; - uCHAR osMinorVersion; /* The OS version */ - uCHAR osRevision; -#ifdef _SINIX_ADDON - uCHAR busType; /* See defininitions above */ - uSHORT osSubRevision; - uCHAR pad[2]; /* For alignment */ -#else - uCHAR osSubRevision; - uCHAR busType; /* See defininitions above */ - uCHAR pad[3]; /* For alignment */ -#endif - driveParam_S drives[16]; /* SmartROM Logical Drives */ - -#ifdef __cplusplus - -//---------- Portability Additions ----------- in sp_sinfo.cpp -#ifdef DPT_PORTABLE - uSHORT netInsert(dptBuffer_S *buffer); - uSHORT netExtract(dptBuffer_S *buffer); -#endif // DPT PORTABLE -//-------------------------------------------- - - }; -#else - } sysInfo_S; -#endif -/*sysInfo_S - end */ - - -/*struct - DOS_Info_S - start - *=========================================================================== - * - *Description: - * - * This structure defines the system information specific to a - *DOS workstation. - * - *---------------------------------------------------------------------------*/ - -/*flags - bit definitions */ -#define DI_DOS_HIGH 0x01 /* DOS is loaded high */ -#define DI_DPMI_VALID 0x02 /* DPMI version is valid */ - -#ifdef __cplusplus - struct DOS_Info_S { -#else - typedef struct { -#endif - - uCHAR flags; /* See bit definitions above */ - uSHORT driverLocation; /* SmartROM BIOS address */ - uSHORT DOS_version; - uSHORT DPMI_version; - -#ifdef __cplusplus - -//---------- Portability Additions ----------- in sp_sinfo.cpp -#ifdef DPT_PORTABLE - uSHORT netInsert(dptBuffer_S *buffer); - uSHORT netExtract(dptBuffer_S *buffer); -#endif // DPT PORTABLE -//-------------------------------------------- - - }; -#else - } DOS_Info_S; -#endif -/*DOS_Info_S - end */ - - -/*struct - Netware_Info_S - start - *=========================================================================== - * - *Description: - * - * This structure defines the system information specific to a - *Netware machine. - * - *---------------------------------------------------------------------------*/ - -#ifdef __cplusplus - struct Netware_Info_S { -#else - typedef struct { -#endif - - uCHAR driverName[13]; /* ie PM12NW31.DSK */ - uCHAR serverName[48]; - uCHAR netwareVersion; /* The Netware OS version */ - uCHAR netwareSubVersion; - uCHAR netwareRevision; - uSHORT maxConnections; /* Probably 250 or 1000 */ - uSHORT connectionsInUse; - uSHORT maxVolumes; - uCHAR unused; - uCHAR SFTlevel; - uCHAR TTSlevel; - - uCHAR clibMajorVersion; /* The CLIB.NLM version */ - uCHAR clibMinorVersion; - uCHAR clibRevision; - -#ifdef __cplusplus - -//---------- Portability Additions ----------- in sp_sinfo.cpp -#ifdef DPT_PORTABLE - uSHORT netInsert(dptBuffer_S *buffer); - uSHORT netExtract(dptBuffer_S *buffer); -#endif // DPT PORTABLE -//-------------------------------------------- - - }; -#else - } Netware_Info_S; -#endif -/*Netware_Info_S - end */ - - -/*struct - OS2_Info_S - start - *=========================================================================== - * - *Description: - * - * This structure defines the system information specific to an - *OS/2 machine. - * - *---------------------------------------------------------------------------*/ - -#ifdef __cplusplus - struct OS2_Info_S { -#else - typedef struct { -#endif - - uCHAR something; - -#ifdef __cplusplus - -//---------- Portability Additions ----------- in sp_sinfo.cpp -#ifdef DPT_PORTABLE - uSHORT netInsert(dptBuffer_S *buffer); - uSHORT netExtract(dptBuffer_S *buffer); -#endif // DPT PORTABLE -//-------------------------------------------- - - }; -#else - } OS2_Info_S; -#endif -/*OS2_Info_S - end */ - - -/*struct - WinNT_Info_S - start - *=========================================================================== - * - *Description: - * - * This structure defines the system information specific to a - *Windows NT machine. - * - *---------------------------------------------------------------------------*/ - -#ifdef __cplusplus - struct WinNT_Info_S { -#else - typedef struct { -#endif - - uCHAR something; - -#ifdef __cplusplus - -//---------- Portability Additions ----------- in sp_sinfo.cpp -#ifdef DPT_PORTABLE - uSHORT netInsert(dptBuffer_S *buffer); - uSHORT netExtract(dptBuffer_S *buffer); -#endif // DPT PORTABLE -//-------------------------------------------- - - }; -#else - } WinNT_Info_S; -#endif -/*WinNT_Info_S - end */ - - -/*struct - SCO_Info_S - start - *=========================================================================== - * - *Description: - * - * This structure defines the system information specific to an - *SCO UNIX machine. - * - *---------------------------------------------------------------------------*/ - -#ifdef __cplusplus - struct SCO_Info_S { -#else - typedef struct { -#endif - - uCHAR something; - -#ifdef __cplusplus - -//---------- Portability Additions ----------- in sp_sinfo.cpp -#ifdef DPT_PORTABLE - uSHORT netInsert(dptBuffer_S *buffer); - uSHORT netExtract(dptBuffer_S *buffer); -#endif // DPT PORTABLE -//-------------------------------------------- - - }; -#else - } SCO_Info_S; -#endif -/*SCO_Info_S - end */ - - -/*struct - USL_Info_S - start - *=========================================================================== - * - *Description: - * - * This structure defines the system information specific to a - *USL UNIX machine. - * - *---------------------------------------------------------------------------*/ - -#ifdef __cplusplus - struct USL_Info_S { -#else - typedef struct { -#endif - - uCHAR something; - -#ifdef __cplusplus - -//---------- Portability Additions ----------- in sp_sinfo.cpp -#ifdef DPT_PORTABLE - uSHORT netInsert(dptBuffer_S *buffer); - uSHORT netExtract(dptBuffer_S *buffer); -#endif // DPT PORTABLE -//-------------------------------------------- - - }; -#else - } USL_Info_S; -#endif -/*USL_Info_S - end */ - - - /* Restore default structure packing */ -#ifndef NO_UNPACK -#if defined (_DPT_AIX) -#pragma options align=reset -#elif defined (UNPACK_FOUR) -#pragma pack(4) -#else -#pragma pack() -#endif /* aix */ -#endif // no unpack - -#endif // __SYS_INFO_H - diff --git a/ANDROID_3.4.5/drivers/scsi/dpt_i2o.c b/ANDROID_3.4.5/drivers/scsi/dpt_i2o.c deleted file mode 100644 index b4f6c9a8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dpt_i2o.c +++ /dev/null @@ -1,3700 +0,0 @@ -/*************************************************************************** - dpti.c - description - ------------------- - begin : Thu Sep 7 2000 - copyright : (C) 2000 by Adaptec - - July 30, 2001 First version being submitted - for inclusion in the kernel. V2.4 - - See Documentation/scsi/dpti.txt for history, notes, license info - and credits - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -/*************************************************************************** - * Sat Dec 20 2003 Go Taniguchi - - Support 2.6 kernel and DMA-mapping - - ioctl fix for raid tools - - use schedule_timeout in long long loop - **************************************************************************/ - -/*#define DEBUG 1 */ -/*#define UARTDELAY 1 */ - -#include - -MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn"); -MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); - -//////////////////////////////////////////////////////////////// - -#include /* For SCSI-Passthrough */ -#include - -#include -#include /* for kmalloc() */ -#include /* for PCI support */ -#include -#include -#include /* for udelay */ -#include -#include /* for printk */ -#include -#include -#include -#include - -#include -#include -#include -#include - -#include /* for boot_cpu_data */ -#include -#include /* for virt_to_bus, etc. */ - -#include -#include -#include -#include -#include - -#include "dpt/dptsig.h" -#include "dpti.h" - -/*============================================================================ - * Create a binary signature - this is read by dptsig - * Needed for our management apps - *============================================================================ - */ -static DEFINE_MUTEX(adpt_mutex); -static dpt_sig_S DPTI_sig = { - {'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION, -#ifdef __i386__ - PROC_INTEL, PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM, -#elif defined(__ia64__) - PROC_INTEL, PROC_IA64, -#elif defined(__sparc__) - PROC_ULTRASPARC, PROC_ULTRASPARC, -#elif defined(__alpha__) - PROC_ALPHA, PROC_ALPHA, -#else - (-1),(-1), -#endif - FT_HBADRVR, 0, OEM_DPT, OS_LINUX, CAP_OVERLAP, DEV_ALL, - ADF_ALL_SC5, 0, 0, DPT_VERSION, DPT_REVISION, DPT_SUBREVISION, - DPT_MONTH, DPT_DAY, DPT_YEAR, "Adaptec Linux I2O RAID Driver" -}; - - - - -/*============================================================================ - * Globals - *============================================================================ - */ - -static DEFINE_MUTEX(adpt_configuration_lock); - -static struct i2o_sys_tbl *sys_tbl; -static dma_addr_t sys_tbl_pa; -static int sys_tbl_ind; -static int sys_tbl_len; - -static adpt_hba* hba_chain = NULL; -static int hba_count = 0; - -static struct class *adpt_sysfs_class; - -static long adpt_unlocked_ioctl(struct file *, unsigned int, unsigned long); -#ifdef CONFIG_COMPAT -static long compat_adpt_ioctl(struct file *, unsigned int, unsigned long); -#endif - -static const struct file_operations adpt_fops = { - .unlocked_ioctl = adpt_unlocked_ioctl, - .open = adpt_open, - .release = adpt_close, -#ifdef CONFIG_COMPAT - .compat_ioctl = compat_adpt_ioctl, -#endif - .llseek = noop_llseek, -}; - -/* Structures and definitions for synchronous message posting. - * See adpt_i2o_post_wait() for description - * */ -struct adpt_i2o_post_wait_data -{ - int status; - u32 id; - adpt_wait_queue_head_t *wq; - struct adpt_i2o_post_wait_data *next; -}; - -static struct adpt_i2o_post_wait_data *adpt_post_wait_queue = NULL; -static u32 adpt_post_wait_id = 0; -static DEFINE_SPINLOCK(adpt_post_wait_lock); - - -/*============================================================================ - * Functions - *============================================================================ - */ - -static inline int dpt_dma64(adpt_hba *pHba) -{ - return (sizeof(dma_addr_t) > 4 && (pHba)->dma64); -} - -static inline u32 dma_high(dma_addr_t addr) -{ - return upper_32_bits(addr); -} - -static inline u32 dma_low(dma_addr_t addr) -{ - return (u32)addr; -} - -static u8 adpt_read_blink_led(adpt_hba* host) -{ - if (host->FwDebugBLEDflag_P) { - if( readb(host->FwDebugBLEDflag_P) == 0xbc ){ - return readb(host->FwDebugBLEDvalue_P); - } - } - return 0; -} - -/*============================================================================ - * Scsi host template interface functions - *============================================================================ - */ - -static struct pci_device_id dptids[] = { - { PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, - { PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, - { 0, } -}; -MODULE_DEVICE_TABLE(pci,dptids); - -static int adpt_detect(struct scsi_host_template* sht) -{ - struct pci_dev *pDev = NULL; - adpt_hba *pHba; - adpt_hba *next; - - PINFO("Detecting Adaptec I2O RAID controllers...\n"); - - /* search for all Adatpec I2O RAID cards */ - while ((pDev = pci_get_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) { - if(pDev->device == PCI_DPT_DEVICE_ID || - pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){ - if(adpt_install_hba(sht, pDev) ){ - PERROR("Could not Init an I2O RAID device\n"); - PERROR("Will not try to detect others.\n"); - return hba_count-1; - } - pci_dev_get(pDev); - } - } - - /* In INIT state, Activate IOPs */ - for (pHba = hba_chain; pHba; pHba = next) { - next = pHba->next; - // Activate does get status , init outbound, and get hrt - if (adpt_i2o_activate_hba(pHba) < 0) { - adpt_i2o_delete_hba(pHba); - } - } - - - /* Active IOPs in HOLD state */ - -rebuild_sys_tab: - if (hba_chain == NULL) - return 0; - - /* - * If build_sys_table fails, we kill everything and bail - * as we can't init the IOPs w/o a system table - */ - if (adpt_i2o_build_sys_table() < 0) { - adpt_i2o_sys_shutdown(); - return 0; - } - - PDEBUG("HBA's in HOLD state\n"); - - /* If IOP don't get online, we need to rebuild the System table */ - for (pHba = hba_chain; pHba; pHba = pHba->next) { - if (adpt_i2o_online_hba(pHba) < 0) { - adpt_i2o_delete_hba(pHba); - goto rebuild_sys_tab; - } - } - - /* Active IOPs now in OPERATIONAL state */ - PDEBUG("HBA's in OPERATIONAL state\n"); - - printk("dpti: If you have a lot of devices this could take a few minutes.\n"); - for (pHba = hba_chain; pHba; pHba = next) { - next = pHba->next; - printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name); - if (adpt_i2o_lct_get(pHba) < 0){ - adpt_i2o_delete_hba(pHba); - continue; - } - - if (adpt_i2o_parse_lct(pHba) < 0){ - adpt_i2o_delete_hba(pHba); - continue; - } - adpt_inquiry(pHba); - } - - adpt_sysfs_class = class_create(THIS_MODULE, "dpt_i2o"); - if (IS_ERR(adpt_sysfs_class)) { - printk(KERN_WARNING"dpti: unable to create dpt_i2o class\n"); - adpt_sysfs_class = NULL; - } - - for (pHba = hba_chain; pHba; pHba = next) { - next = pHba->next; - if (adpt_scsi_host_alloc(pHba, sht) < 0){ - adpt_i2o_delete_hba(pHba); - continue; - } - pHba->initialized = TRUE; - pHba->state &= ~DPTI_STATE_RESET; - if (adpt_sysfs_class) { - struct device *dev = device_create(adpt_sysfs_class, - NULL, MKDEV(DPTI_I2O_MAJOR, pHba->unit), NULL, - "dpti%d", pHba->unit); - if (IS_ERR(dev)) { - printk(KERN_WARNING"dpti%d: unable to " - "create device in dpt_i2o class\n", - pHba->unit); - } - } - } - - // Register our control device node - // nodes will need to be created in /dev to access this - // the nodes can not be created from within the driver - if (hba_count && register_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER, &adpt_fops)) { - adpt_i2o_sys_shutdown(); - return 0; - } - return hba_count; -} - - -/* - * scsi_unregister will be called AFTER we return. - */ -static int adpt_release(struct Scsi_Host *host) -{ - adpt_hba* pHba = (adpt_hba*) host->hostdata[0]; -// adpt_i2o_quiesce_hba(pHba); - adpt_i2o_delete_hba(pHba); - scsi_unregister(host); - return 0; -} - - -static void adpt_inquiry(adpt_hba* pHba) -{ - u32 msg[17]; - u32 *mptr; - u32 *lenptr; - int direction; - int scsidir; - u32 len; - u32 reqlen; - u8* buf; - dma_addr_t addr; - u8 scb[16]; - s32 rcode; - - memset(msg, 0, sizeof(msg)); - buf = dma_alloc_coherent(&pHba->pDev->dev, 80, &addr, GFP_KERNEL); - if(!buf){ - printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name); - return; - } - memset((void*)buf, 0, 36); - - len = 36; - direction = 0x00000000; - scsidir =0x40000000; // DATA IN (iop<--dev) - - if (dpt_dma64(pHba)) - reqlen = 17; // SINGLE SGE, 64 bit - else - reqlen = 14; // SINGLE SGE, 32 bit - /* Stick the headers on */ - msg[0] = reqlen<<16 | SGL_OFFSET_12; - msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID); - msg[2] = 0; - msg[3] = 0; - // Adaptec/DPT Private stuff - msg[4] = I2O_CMD_SCSI_EXEC|DPT_ORGANIZATION_ID<<16; - msg[5] = ADAPTER_TID | 1<<16 /* Interpret*/; - /* Direction, disconnect ok | sense data | simple queue , CDBLen */ - // I2O_SCB_FLAG_ENABLE_DISCONNECT | - // I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | - // I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE; - msg[6] = scsidir|0x20a00000| 6 /* cmd len*/; - - mptr=msg+7; - - memset(scb, 0, sizeof(scb)); - // Write SCSI command into the message - always 16 byte block - scb[0] = INQUIRY; - scb[1] = 0; - scb[2] = 0; - scb[3] = 0; - scb[4] = 36; - scb[5] = 0; - // Don't care about the rest of scb - - memcpy(mptr, scb, sizeof(scb)); - mptr+=4; - lenptr=mptr++; /* Remember me - fill in when we know */ - - /* Now fill in the SGList and command */ - *lenptr = len; - if (dpt_dma64(pHba)) { - *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */ - *mptr++ = 1 << PAGE_SHIFT; - *mptr++ = 0xD0000000|direction|len; - *mptr++ = dma_low(addr); - *mptr++ = dma_high(addr); - } else { - *mptr++ = 0xD0000000|direction|len; - *mptr++ = addr; - } - - // Send it on it's way - rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120); - if (rcode != 0) { - sprintf(pHba->detail, "Adaptec I2O RAID"); - printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode); - if (rcode != -ETIME && rcode != -EINTR) - dma_free_coherent(&pHba->pDev->dev, 80, buf, addr); - } else { - memset(pHba->detail, 0, sizeof(pHba->detail)); - memcpy(&(pHba->detail), "Vendor: Adaptec ", 16); - memcpy(&(pHba->detail[16]), " Model: ", 8); - memcpy(&(pHba->detail[24]), (u8*) &buf[16], 16); - memcpy(&(pHba->detail[40]), " FW: ", 4); - memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4); - pHba->detail[48] = '\0'; /* precautionary */ - dma_free_coherent(&pHba->pDev->dev, 80, buf, addr); - } - adpt_i2o_status_get(pHba); - return ; -} - - -static int adpt_slave_configure(struct scsi_device * device) -{ - struct Scsi_Host *host = device->host; - adpt_hba* pHba; - - pHba = (adpt_hba *) host->hostdata[0]; - - if (host->can_queue && device->tagged_supported) { - scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, - host->can_queue - 1); - } else { - scsi_adjust_queue_depth(device, 0, 1); - } - return 0; -} - -static int adpt_queue_lck(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *)) -{ - adpt_hba* pHba = NULL; - struct adpt_device* pDev = NULL; /* dpt per device information */ - - cmd->scsi_done = done; - /* - * SCSI REQUEST_SENSE commands will be executed automatically by the - * Host Adapter for any errors, so they should not be executed - * explicitly unless the Sense Data is zero indicating that no error - * occurred. - */ - - if ((cmd->cmnd[0] == REQUEST_SENSE) && (cmd->sense_buffer[0] != 0)) { - cmd->result = (DID_OK << 16); - cmd->scsi_done(cmd); - return 0; - } - - pHba = (adpt_hba*)cmd->device->host->hostdata[0]; - if (!pHba) { - return FAILED; - } - - rmb(); - /* - * TODO: I need to block here if I am processing ioctl cmds - * but if the outstanding cmds all finish before the ioctl, - * the scsi-core will not know to start sending cmds to me again. - * I need to a way to restart the scsi-cores queues or should I block - * calling scsi_done on the outstanding cmds instead - * for now we don't set the IOCTL state - */ - if(((pHba->state) & DPTI_STATE_IOCTL) || ((pHba->state) & DPTI_STATE_RESET)) { - pHba->host->last_reset = jiffies; - pHba->host->resetting = 1; - return 1; - } - - // TODO if the cmd->device if offline then I may need to issue a bus rescan - // followed by a get_lct to see if the device is there anymore - if((pDev = (struct adpt_device*) (cmd->device->hostdata)) == NULL) { - /* - * First command request for this device. Set up a pointer - * to the device structure. This should be a TEST_UNIT_READY - * command from scan_scsis_single. - */ - if ((pDev = adpt_find_device(pHba, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun)) == NULL) { - // TODO: if any luns are at this bus, scsi id then fake a TEST_UNIT_READY and INQUIRY response - // with type 7F (for all luns less than the max for this bus,id) so the lun scan will continue. - cmd->result = (DID_NO_CONNECT << 16); - cmd->scsi_done(cmd); - return 0; - } - cmd->device->hostdata = pDev; - } - pDev->pScsi_dev = cmd->device; - - /* - * If we are being called from when the device is being reset, - * delay processing of the command until later. - */ - if (pDev->state & DPTI_DEV_RESET ) { - return FAILED; - } - return adpt_scsi_to_i2o(pHba, cmd, pDev); -} - -static DEF_SCSI_QCMD(adpt_queue) - -static int adpt_bios_param(struct scsi_device *sdev, struct block_device *dev, - sector_t capacity, int geom[]) -{ - int heads=-1; - int sectors=-1; - int cylinders=-1; - - // *** First lets set the default geometry **** - - // If the capacity is less than ox2000 - if (capacity < 0x2000 ) { // floppy - heads = 18; - sectors = 2; - } - // else if between 0x2000 and 0x20000 - else if (capacity < 0x20000) { - heads = 64; - sectors = 32; - } - // else if between 0x20000 and 0x40000 - else if (capacity < 0x40000) { - heads = 65; - sectors = 63; - } - // else if between 0x4000 and 0x80000 - else if (capacity < 0x80000) { - heads = 128; - sectors = 63; - } - // else if greater than 0x80000 - else { - heads = 255; - sectors = 63; - } - cylinders = sector_div(capacity, heads * sectors); - - // Special case if CDROM - if(sdev->type == 5) { // CDROM - heads = 252; - sectors = 63; - cylinders = 1111; - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - PDEBUG("adpt_bios_param: exit\n"); - return 0; -} - - -static const char *adpt_info(struct Scsi_Host *host) -{ - adpt_hba* pHba; - - pHba = (adpt_hba *) host->hostdata[0]; - return (char *) (pHba->detail); -} - -static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int inout) -{ - struct adpt_device* d; - int id; - int chan; - int len = 0; - int begin = 0; - int pos = 0; - adpt_hba* pHba; - int unit; - - *start = buffer; - if (inout == TRUE) { - /* - * The user has done a write and wants us to take the - * data in the buffer and do something with it. - * proc_scsiwrite calls us with inout = 1 - * - * Read data from buffer (writing to us) - NOT SUPPORTED - */ - return -EINVAL; - } - - /* - * inout = 0 means the user has done a read and wants information - * returned, so we write information about the cards into the buffer - * proc_scsiread() calls us with inout = 0 - */ - - // Find HBA (host bus adapter) we are looking for - mutex_lock(&adpt_configuration_lock); - for (pHba = hba_chain; pHba; pHba = pHba->next) { - if (pHba->host == host) { - break; /* found adapter */ - } - } - mutex_unlock(&adpt_configuration_lock); - if (pHba == NULL) { - return 0; - } - host = pHba->host; - - len = sprintf(buffer , "Adaptec I2O RAID Driver Version: %s\n\n", DPT_I2O_VERSION); - len += sprintf(buffer+len, "%s\n", pHba->detail); - len += sprintf(buffer+len, "SCSI Host=scsi%d Control Node=/dev/%s irq=%d\n", - pHba->host->host_no, pHba->name, host->irq); - len += sprintf(buffer+len, "\tpost fifo size = %d\n\treply fifo size = %d\n\tsg table size = %d\n\n", - host->can_queue, (int) pHba->reply_fifo_size , host->sg_tablesize); - - pos = begin + len; - - /* CHECKPOINT */ - if(pos > offset + length) { - goto stop_output; - } - if(pos <= offset) { - /* - * If we haven't even written to where we last left - * off (the last time we were called), reset the - * beginning pointer. - */ - len = 0; - begin = pos; - } - len += sprintf(buffer+len, "Devices:\n"); - for(chan = 0; chan < MAX_CHANNEL; chan++) { - for(id = 0; id < MAX_ID; id++) { - d = pHba->channel[chan].device[id]; - while(d){ - len += sprintf(buffer+len,"\t%-24.24s", d->pScsi_dev->vendor); - len += sprintf(buffer+len," Rev: %-8.8s\n", d->pScsi_dev->rev); - pos = begin + len; - - - /* CHECKPOINT */ - if(pos > offset + length) { - goto stop_output; - } - if(pos <= offset) { - len = 0; - begin = pos; - } - - unit = d->pI2o_dev->lct_data.tid; - len += sprintf(buffer+len, "\tTID=%d, (Channel=%d, Target=%d, Lun=%d) (%s)\n\n", - unit, (int)d->scsi_channel, (int)d->scsi_id, (int)d->scsi_lun, - scsi_device_online(d->pScsi_dev)? "online":"offline"); - pos = begin + len; - - /* CHECKPOINT */ - if(pos > offset + length) { - goto stop_output; - } - if(pos <= offset) { - len = 0; - begin = pos; - } - - d = d->next_lun; - } - } - } - - /* - * begin is where we last checked our position with regards to offset - * begin is always less than offset. len is relative to begin. It - * is the number of bytes written past begin - * - */ -stop_output: - /* stop the output and calculate the correct length */ - *(buffer + len) = '\0'; - - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); - if(len > length) { - len = length; - } else if(len < 0){ - len = 0; - **start = '\0'; - } - return len; -} - -/* - * Turn a struct scsi_cmnd * into a unique 32 bit 'context'. - */ -static u32 adpt_cmd_to_context(struct scsi_cmnd *cmd) -{ - return (u32)cmd->serial_number; -} - -/* - * Go from a u32 'context' to a struct scsi_cmnd * . - * This could probably be made more efficient. - */ -static struct scsi_cmnd * - adpt_cmd_from_context(adpt_hba * pHba, u32 context) -{ - struct scsi_cmnd * cmd; - struct scsi_device * d; - - if (context == 0) - return NULL; - - spin_unlock(pHba->host->host_lock); - shost_for_each_device(d, pHba->host) { - unsigned long flags; - spin_lock_irqsave(&d->list_lock, flags); - list_for_each_entry(cmd, &d->cmd_list, list) { - if (((u32)cmd->serial_number == context)) { - spin_unlock_irqrestore(&d->list_lock, flags); - scsi_device_put(d); - spin_lock(pHba->host->host_lock); - return cmd; - } - } - spin_unlock_irqrestore(&d->list_lock, flags); - } - spin_lock(pHba->host->host_lock); - - return NULL; -} - -/* - * Turn a pointer to ioctl reply data into an u32 'context' - */ -static u32 adpt_ioctl_to_context(adpt_hba * pHba, void *reply) -{ -#if BITS_PER_LONG == 32 - return (u32)(unsigned long)reply; -#else - ulong flags = 0; - u32 nr, i; - - spin_lock_irqsave(pHba->host->host_lock, flags); - nr = ARRAY_SIZE(pHba->ioctl_reply_context); - for (i = 0; i < nr; i++) { - if (pHba->ioctl_reply_context[i] == NULL) { - pHba->ioctl_reply_context[i] = reply; - break; - } - } - spin_unlock_irqrestore(pHba->host->host_lock, flags); - if (i >= nr) { - kfree (reply); - printk(KERN_WARNING"%s: Too many outstanding " - "ioctl commands\n", pHba->name); - return (u32)-1; - } - - return i; -#endif -} - -/* - * Go from an u32 'context' to a pointer to ioctl reply data. - */ -static void *adpt_ioctl_from_context(adpt_hba *pHba, u32 context) -{ -#if BITS_PER_LONG == 32 - return (void *)(unsigned long)context; -#else - void *p = pHba->ioctl_reply_context[context]; - pHba->ioctl_reply_context[context] = NULL; - - return p; -#endif -} - -/*=========================================================================== - * Error Handling routines - *=========================================================================== - */ - -static int adpt_abort(struct scsi_cmnd * cmd) -{ - adpt_hba* pHba = NULL; /* host bus adapter structure */ - struct adpt_device* dptdevice; /* dpt per device information */ - u32 msg[5]; - int rcode; - - if(cmd->serial_number == 0){ - return FAILED; - } - pHba = (adpt_hba*) cmd->device->host->hostdata[0]; - printk(KERN_INFO"%s: Trying to Abort\n",pHba->name); - if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) { - printk(KERN_ERR "%s: Unable to abort: No device in cmnd\n",pHba->name); - return FAILED; - } - - memset(msg, 0, sizeof(msg)); - msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid; - msg[2] = 0; - msg[3]= 0; - msg[4] = adpt_cmd_to_context(cmd); - if (pHba->host) - spin_lock_irq(pHba->host->host_lock); - rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER); - if (pHba->host) - spin_unlock_irq(pHba->host->host_lock); - if (rcode != 0) { - if(rcode == -EOPNOTSUPP ){ - printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name); - return FAILED; - } - printk(KERN_INFO"%s: Abort failed.\n",pHba->name); - return FAILED; - } - printk(KERN_INFO"%s: Abort complete.\n",pHba->name); - return SUCCESS; -} - - -#define I2O_DEVICE_RESET 0x27 -// This is the same for BLK and SCSI devices -// NOTE this is wrong in the i2o.h definitions -// This is not currently supported by our adapter but we issue it anyway -static int adpt_device_reset(struct scsi_cmnd* cmd) -{ - adpt_hba* pHba; - u32 msg[4]; - u32 rcode; - int old_state; - struct adpt_device* d = cmd->device->hostdata; - - pHba = (void*) cmd->device->host->hostdata[0]; - printk(KERN_INFO"%s: Trying to reset device\n",pHba->name); - if (!d) { - printk(KERN_INFO"%s: Reset Device: Device Not found\n",pHba->name); - return FAILED; - } - memset(msg, 0, sizeof(msg)); - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = (I2O_DEVICE_RESET<<24|HOST_TID<<12|d->tid); - msg[2] = 0; - msg[3] = 0; - - if (pHba->host) - spin_lock_irq(pHba->host->host_lock); - old_state = d->state; - d->state |= DPTI_DEV_RESET; - rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER); - d->state = old_state; - if (pHba->host) - spin_unlock_irq(pHba->host->host_lock); - if (rcode != 0) { - if(rcode == -EOPNOTSUPP ){ - printk(KERN_INFO"%s: Device reset not supported\n",pHba->name); - return FAILED; - } - printk(KERN_INFO"%s: Device reset failed\n",pHba->name); - return FAILED; - } else { - printk(KERN_INFO"%s: Device reset successful\n",pHba->name); - return SUCCESS; - } -} - - -#define I2O_HBA_BUS_RESET 0x87 -// This version of bus reset is called by the eh_error handler -static int adpt_bus_reset(struct scsi_cmnd* cmd) -{ - adpt_hba* pHba; - u32 msg[4]; - u32 rcode; - - pHba = (adpt_hba*)cmd->device->host->hostdata[0]; - memset(msg, 0, sizeof(msg)); - printk(KERN_WARNING"%s: Bus reset: SCSI Bus %d: tid: %d\n",pHba->name, cmd->device->channel,pHba->channel[cmd->device->channel].tid ); - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = (I2O_HBA_BUS_RESET<<24|HOST_TID<<12|pHba->channel[cmd->device->channel].tid); - msg[2] = 0; - msg[3] = 0; - if (pHba->host) - spin_lock_irq(pHba->host->host_lock); - rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER); - if (pHba->host) - spin_unlock_irq(pHba->host->host_lock); - if (rcode != 0) { - printk(KERN_WARNING"%s: Bus reset failed.\n",pHba->name); - return FAILED; - } else { - printk(KERN_WARNING"%s: Bus reset success.\n",pHba->name); - return SUCCESS; - } -} - -// This version of reset is called by the eh_error_handler -static int __adpt_reset(struct scsi_cmnd* cmd) -{ - adpt_hba* pHba; - int rcode; - pHba = (adpt_hba*)cmd->device->host->hostdata[0]; - printk(KERN_WARNING"%s: Hba Reset: scsi id %d: tid: %d\n",pHba->name,cmd->device->channel,pHba->channel[cmd->device->channel].tid ); - rcode = adpt_hba_reset(pHba); - if(rcode == 0){ - printk(KERN_WARNING"%s: HBA reset complete\n",pHba->name); - return SUCCESS; - } else { - printk(KERN_WARNING"%s: HBA reset failed (%x)\n",pHba->name, rcode); - return FAILED; - } -} - -static int adpt_reset(struct scsi_cmnd* cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __adpt_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - -// This version of reset is called by the ioctls and indirectly from eh_error_handler via adpt_reset -static int adpt_hba_reset(adpt_hba* pHba) -{ - int rcode; - - pHba->state |= DPTI_STATE_RESET; - - // Activate does get status , init outbound, and get hrt - if ((rcode=adpt_i2o_activate_hba(pHba)) < 0) { - printk(KERN_ERR "%s: Could not activate\n", pHba->name); - adpt_i2o_delete_hba(pHba); - return rcode; - } - - if ((rcode=adpt_i2o_build_sys_table()) < 0) { - adpt_i2o_delete_hba(pHba); - return rcode; - } - PDEBUG("%s: in HOLD state\n",pHba->name); - - if ((rcode=adpt_i2o_online_hba(pHba)) < 0) { - adpt_i2o_delete_hba(pHba); - return rcode; - } - PDEBUG("%s: in OPERATIONAL state\n",pHba->name); - - if ((rcode=adpt_i2o_lct_get(pHba)) < 0){ - adpt_i2o_delete_hba(pHba); - return rcode; - } - - if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0){ - adpt_i2o_delete_hba(pHba); - return rcode; - } - pHba->state &= ~DPTI_STATE_RESET; - - adpt_fail_posted_scbs(pHba); - return 0; /* return success */ -} - -/*=========================================================================== - * - *=========================================================================== - */ - - -static void adpt_i2o_sys_shutdown(void) -{ - adpt_hba *pHba, *pNext; - struct adpt_i2o_post_wait_data *p1, *old; - - printk(KERN_INFO"Shutting down Adaptec I2O controllers.\n"); - printk(KERN_INFO" This could take a few minutes if there are many devices attached\n"); - /* Delete all IOPs from the controller chain */ - /* They should have already been released by the - * scsi-core - */ - for (pHba = hba_chain; pHba; pHba = pNext) { - pNext = pHba->next; - adpt_i2o_delete_hba(pHba); - } - - /* Remove any timedout entries from the wait queue. */ -// spin_lock_irqsave(&adpt_post_wait_lock, flags); - /* Nothing should be outstanding at this point so just - * free them - */ - for(p1 = adpt_post_wait_queue; p1;) { - old = p1; - p1 = p1->next; - kfree(old); - } -// spin_unlock_irqrestore(&adpt_post_wait_lock, flags); - adpt_post_wait_queue = NULL; - - printk(KERN_INFO "Adaptec I2O controllers down.\n"); -} - -static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) -{ - - adpt_hba* pHba = NULL; - adpt_hba* p = NULL; - ulong base_addr0_phys = 0; - ulong base_addr1_phys = 0; - u32 hba_map0_area_size = 0; - u32 hba_map1_area_size = 0; - void __iomem *base_addr_virt = NULL; - void __iomem *msg_addr_virt = NULL; - int dma64 = 0; - - int raptorFlag = FALSE; - - if(pci_enable_device(pDev)) { - return -EINVAL; - } - - if (pci_request_regions(pDev, "dpt_i2o")) { - PERROR("dpti: adpt_config_hba: pci request region failed\n"); - return -EINVAL; - } - - pci_set_master(pDev); - - /* - * See if we should enable dma64 mode. - */ - if (sizeof(dma_addr_t) > 4 && - pci_set_dma_mask(pDev, DMA_BIT_MASK(64)) == 0) { - if (dma_get_required_mask(&pDev->dev) > DMA_BIT_MASK(32)) - dma64 = 1; - } - if (!dma64 && pci_set_dma_mask(pDev, DMA_BIT_MASK(32)) != 0) - return -EINVAL; - - /* adapter only supports message blocks below 4GB */ - pci_set_consistent_dma_mask(pDev, DMA_BIT_MASK(32)); - - base_addr0_phys = pci_resource_start(pDev,0); - hba_map0_area_size = pci_resource_len(pDev,0); - - // Check if standard PCI card or single BAR Raptor - if(pDev->device == PCI_DPT_DEVICE_ID){ - if(pDev->subsystem_device >=0xc032 && pDev->subsystem_device <= 0xc03b){ - // Raptor card with this device id needs 4M - hba_map0_area_size = 0x400000; - } else { // Not Raptor - it is a PCI card - if(hba_map0_area_size > 0x100000 ){ - hba_map0_area_size = 0x100000; - } - } - } else {// Raptor split BAR config - // Use BAR1 in this configuration - base_addr1_phys = pci_resource_start(pDev,1); - hba_map1_area_size = pci_resource_len(pDev,1); - raptorFlag = TRUE; - } - -#if BITS_PER_LONG == 64 - /* - * The original Adaptec 64 bit driver has this comment here: - * "x86_64 machines need more optimal mappings" - * - * I assume some HBAs report ridiculously large mappings - * and we need to limit them on platforms with IOMMUs. - */ - if (raptorFlag == TRUE) { - if (hba_map0_area_size > 128) - hba_map0_area_size = 128; - if (hba_map1_area_size > 524288) - hba_map1_area_size = 524288; - } else { - if (hba_map0_area_size > 524288) - hba_map0_area_size = 524288; - } -#endif - - base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size); - if (!base_addr_virt) { - pci_release_regions(pDev); - PERROR("dpti: adpt_config_hba: io remap failed\n"); - return -EINVAL; - } - - if(raptorFlag == TRUE) { - msg_addr_virt = ioremap(base_addr1_phys, hba_map1_area_size ); - if (!msg_addr_virt) { - PERROR("dpti: adpt_config_hba: io remap failed on BAR1\n"); - iounmap(base_addr_virt); - pci_release_regions(pDev); - return -EINVAL; - } - } else { - msg_addr_virt = base_addr_virt; - } - - // Allocate and zero the data structure - pHba = kzalloc(sizeof(adpt_hba), GFP_KERNEL); - if (!pHba) { - if (msg_addr_virt != base_addr_virt) - iounmap(msg_addr_virt); - iounmap(base_addr_virt); - pci_release_regions(pDev); - return -ENOMEM; - } - - mutex_lock(&adpt_configuration_lock); - - if(hba_chain != NULL){ - for(p = hba_chain; p->next; p = p->next); - p->next = pHba; - } else { - hba_chain = pHba; - } - pHba->next = NULL; - pHba->unit = hba_count; - sprintf(pHba->name, "dpti%d", hba_count); - hba_count++; - - mutex_unlock(&adpt_configuration_lock); - - pHba->pDev = pDev; - pHba->base_addr_phys = base_addr0_phys; - - // Set up the Virtual Base Address of the I2O Device - pHba->base_addr_virt = base_addr_virt; - pHba->msg_addr_virt = msg_addr_virt; - pHba->irq_mask = base_addr_virt+0x30; - pHba->post_port = base_addr_virt+0x40; - pHba->reply_port = base_addr_virt+0x44; - - pHba->hrt = NULL; - pHba->lct = NULL; - pHba->lct_size = 0; - pHba->status_block = NULL; - pHba->post_count = 0; - pHba->state = DPTI_STATE_RESET; - pHba->pDev = pDev; - pHba->devices = NULL; - pHba->dma64 = dma64; - - // Initializing the spinlocks - spin_lock_init(&pHba->state_lock); - spin_lock_init(&adpt_post_wait_lock); - - if(raptorFlag == 0){ - printk(KERN_INFO "Adaptec I2O RAID controller" - " %d at %p size=%x irq=%d%s\n", - hba_count-1, base_addr_virt, - hba_map0_area_size, pDev->irq, - dma64 ? " (64-bit DMA)" : ""); - } else { - printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d%s\n", - hba_count-1, pDev->irq, - dma64 ? " (64-bit DMA)" : ""); - printk(KERN_INFO" BAR0 %p - size= %x\n",base_addr_virt,hba_map0_area_size); - printk(KERN_INFO" BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size); - } - - if (request_irq (pDev->irq, adpt_isr, IRQF_SHARED, pHba->name, pHba)) { - printk(KERN_ERR"%s: Couldn't register IRQ %d\n", pHba->name, pDev->irq); - adpt_i2o_delete_hba(pHba); - return -EINVAL; - } - - return 0; -} - - -static void adpt_i2o_delete_hba(adpt_hba* pHba) -{ - adpt_hba* p1; - adpt_hba* p2; - struct i2o_device* d; - struct i2o_device* next; - int i; - int j; - struct adpt_device* pDev; - struct adpt_device* pNext; - - - mutex_lock(&adpt_configuration_lock); - // scsi_unregister calls our adpt_release which - // does a quiese - if(pHba->host){ - free_irq(pHba->host->irq, pHba); - } - p2 = NULL; - for( p1 = hba_chain; p1; p2 = p1,p1=p1->next){ - if(p1 == pHba) { - if(p2) { - p2->next = p1->next; - } else { - hba_chain = p1->next; - } - break; - } - } - - hba_count--; - mutex_unlock(&adpt_configuration_lock); - - iounmap(pHba->base_addr_virt); - pci_release_regions(pHba->pDev); - if(pHba->msg_addr_virt != pHba->base_addr_virt){ - iounmap(pHba->msg_addr_virt); - } - if(pHba->FwDebugBuffer_P) - iounmap(pHba->FwDebugBuffer_P); - if(pHba->hrt) { - dma_free_coherent(&pHba->pDev->dev, - pHba->hrt->num_entries * pHba->hrt->entry_len << 2, - pHba->hrt, pHba->hrt_pa); - } - if(pHba->lct) { - dma_free_coherent(&pHba->pDev->dev, pHba->lct_size, - pHba->lct, pHba->lct_pa); - } - if(pHba->status_block) { - dma_free_coherent(&pHba->pDev->dev, sizeof(i2o_status_block), - pHba->status_block, pHba->status_block_pa); - } - if(pHba->reply_pool) { - dma_free_coherent(&pHba->pDev->dev, - pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, - pHba->reply_pool, pHba->reply_pool_pa); - } - - for(d = pHba->devices; d ; d = next){ - next = d->next; - kfree(d); - } - for(i = 0 ; i < pHba->top_scsi_channel ; i++){ - for(j = 0; j < MAX_ID; j++){ - if(pHba->channel[i].device[j] != NULL){ - for(pDev = pHba->channel[i].device[j]; pDev; pDev = pNext){ - pNext = pDev->next_lun; - kfree(pDev); - } - } - } - } - pci_dev_put(pHba->pDev); - if (adpt_sysfs_class) - device_destroy(adpt_sysfs_class, - MKDEV(DPTI_I2O_MAJOR, pHba->unit)); - kfree(pHba); - - if(hba_count <= 0){ - unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER); - if (adpt_sysfs_class) { - class_destroy(adpt_sysfs_class); - adpt_sysfs_class = NULL; - } - } -} - -static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun) -{ - struct adpt_device* d; - - if(chan < 0 || chan >= MAX_CHANNEL) - return NULL; - - if( pHba->channel[chan].device == NULL){ - printk(KERN_DEBUG"Adaptec I2O RAID: Trying to find device before they are allocated\n"); - return NULL; - } - - d = pHba->channel[chan].device[id]; - if(!d || d->tid == 0) { - return NULL; - } - - /* If it is the only lun at that address then this should match*/ - if(d->scsi_lun == lun){ - return d; - } - - /* else we need to look through all the luns */ - for(d=d->next_lun ; d ; d = d->next_lun){ - if(d->scsi_lun == lun){ - return d; - } - } - return NULL; -} - - -static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout) -{ - // I used my own version of the WAIT_QUEUE_HEAD - // to handle some version differences - // When embedded in the kernel this could go back to the vanilla one - ADPT_DECLARE_WAIT_QUEUE_HEAD(adpt_wq_i2o_post); - int status = 0; - ulong flags = 0; - struct adpt_i2o_post_wait_data *p1, *p2; - struct adpt_i2o_post_wait_data *wait_data = - kmalloc(sizeof(struct adpt_i2o_post_wait_data), GFP_ATOMIC); - DECLARE_WAITQUEUE(wait, current); - - if (!wait_data) - return -ENOMEM; - - /* - * The spin locking is needed to keep anyone from playing - * with the queue pointers and id while we do the same - */ - spin_lock_irqsave(&adpt_post_wait_lock, flags); - // TODO we need a MORE unique way of getting ids - // to support async LCT get - wait_data->next = adpt_post_wait_queue; - adpt_post_wait_queue = wait_data; - adpt_post_wait_id++; - adpt_post_wait_id &= 0x7fff; - wait_data->id = adpt_post_wait_id; - spin_unlock_irqrestore(&adpt_post_wait_lock, flags); - - wait_data->wq = &adpt_wq_i2o_post; - wait_data->status = -ETIMEDOUT; - - add_wait_queue(&adpt_wq_i2o_post, &wait); - - msg[2] |= 0x80000000 | ((u32)wait_data->id); - timeout *= HZ; - if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){ - set_current_state(TASK_INTERRUPTIBLE); - if(pHba->host) - spin_unlock_irq(pHba->host->host_lock); - if (!timeout) - schedule(); - else{ - timeout = schedule_timeout(timeout); - if (timeout == 0) { - // I/O issued, but cannot get result in - // specified time. Freeing resorces is - // dangerous. - status = -ETIME; - } - } - if(pHba->host) - spin_lock_irq(pHba->host->host_lock); - } - remove_wait_queue(&adpt_wq_i2o_post, &wait); - - if(status == -ETIMEDOUT){ - printk(KERN_INFO"dpti%d: POST WAIT TIMEOUT\n",pHba->unit); - // We will have to free the wait_data memory during shutdown - return status; - } - - /* Remove the entry from the queue. */ - p2 = NULL; - spin_lock_irqsave(&adpt_post_wait_lock, flags); - for(p1 = adpt_post_wait_queue; p1; p2 = p1, p1 = p1->next) { - if(p1 == wait_data) { - if(p1->status == I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION ) { - status = -EOPNOTSUPP; - } - if(p2) { - p2->next = p1->next; - } else { - adpt_post_wait_queue = p1->next; - } - break; - } - } - spin_unlock_irqrestore(&adpt_post_wait_lock, flags); - - kfree(wait_data); - - return status; -} - - -static s32 adpt_i2o_post_this(adpt_hba* pHba, u32* data, int len) -{ - - u32 m = EMPTY_QUEUE; - u32 __iomem *msg; - ulong timeout = jiffies + 30*HZ; - do { - rmb(); - m = readl(pHba->post_port); - if (m != EMPTY_QUEUE) { - break; - } - if(time_after(jiffies,timeout)){ - printk(KERN_WARNING"dpti%d: Timeout waiting for message frame!\n", pHba->unit); - return -ETIMEDOUT; - } - schedule_timeout_uninterruptible(1); - } while(m == EMPTY_QUEUE); - - msg = pHba->msg_addr_virt + m; - memcpy_toio(msg, data, len); - wmb(); - - //post message - writel(m, pHba->post_port); - wmb(); - - return 0; -} - - -static void adpt_i2o_post_wait_complete(u32 context, int status) -{ - struct adpt_i2o_post_wait_data *p1 = NULL; - /* - * We need to search through the adpt_post_wait - * queue to see if the given message is still - * outstanding. If not, it means that the IOP - * took longer to respond to the message than we - * had allowed and timer has already expired. - * Not much we can do about that except log - * it for debug purposes, increase timeout, and recompile - * - * Lock needed to keep anyone from moving queue pointers - * around while we're looking through them. - */ - - context &= 0x7fff; - - spin_lock(&adpt_post_wait_lock); - for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) { - if(p1->id == context) { - p1->status = status; - spin_unlock(&adpt_post_wait_lock); - wake_up_interruptible(p1->wq); - return; - } - } - spin_unlock(&adpt_post_wait_lock); - // If this happens we lose commands that probably really completed - printk(KERN_DEBUG"dpti: Could Not find task %d in wait queue\n",context); - printk(KERN_DEBUG" Tasks in wait queue:\n"); - for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) { - printk(KERN_DEBUG" %d\n",p1->id); - } - return; -} - -static s32 adpt_i2o_reset_hba(adpt_hba* pHba) -{ - u32 msg[8]; - u8* status; - dma_addr_t addr; - u32 m = EMPTY_QUEUE ; - ulong timeout = jiffies + (TMOUT_IOPRESET*HZ); - - if(pHba->initialized == FALSE) { // First time reset should be quick - timeout = jiffies + (25*HZ); - } else { - adpt_i2o_quiesce_hba(pHba); - } - - do { - rmb(); - m = readl(pHba->post_port); - if (m != EMPTY_QUEUE) { - break; - } - if(time_after(jiffies,timeout)){ - printk(KERN_WARNING"Timeout waiting for message!\n"); - return -ETIMEDOUT; - } - schedule_timeout_uninterruptible(1); - } while (m == EMPTY_QUEUE); - - status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL); - if(status == NULL) { - adpt_send_nop(pHba, m); - printk(KERN_ERR"IOP reset failed - no free memory.\n"); - return -ENOMEM; - } - memset(status,0,4); - - msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]=0; - msg[3]=0; - msg[4]=0; - msg[5]=0; - msg[6]=dma_low(addr); - msg[7]=dma_high(addr); - - memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg)); - wmb(); - writel(m, pHba->post_port); - wmb(); - - while(*status == 0){ - if(time_after(jiffies,timeout)){ - printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name); - /* We lose 4 bytes of "status" here, but we cannot - free these because controller may awake and corrupt - those bytes at any time */ - /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */ - return -ETIMEDOUT; - } - rmb(); - schedule_timeout_uninterruptible(1); - } - - if(*status == 0x01 /*I2O_EXEC_IOP_RESET_IN_PROGRESS*/) { - PDEBUG("%s: Reset in progress...\n", pHba->name); - // Here we wait for message frame to become available - // indicated that reset has finished - do { - rmb(); - m = readl(pHba->post_port); - if (m != EMPTY_QUEUE) { - break; - } - if(time_after(jiffies,timeout)){ - printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name); - /* We lose 4 bytes of "status" here, but we - cannot free these because controller may - awake and corrupt those bytes at any time */ - /* dma_free_coherent(&pHba->pDev->dev, 4, buf, addr); */ - return -ETIMEDOUT; - } - schedule_timeout_uninterruptible(1); - } while (m == EMPTY_QUEUE); - // Flush the offset - adpt_send_nop(pHba, m); - } - adpt_i2o_status_get(pHba); - if(*status == 0x02 || - pHba->status_block->iop_state != ADAPTER_STATE_RESET) { - printk(KERN_WARNING"%s: Reset reject, trying to clear\n", - pHba->name); - } else { - PDEBUG("%s: Reset completed.\n", pHba->name); - } - - dma_free_coherent(&pHba->pDev->dev, 4, status, addr); -#ifdef UARTDELAY - // This delay is to allow someone attached to the card through the debug UART to - // set up the dump levels that they want before the rest of the initialization sequence - adpt_delay(20000); -#endif - return 0; -} - - -static int adpt_i2o_parse_lct(adpt_hba* pHba) -{ - int i; - int max; - int tid; - struct i2o_device *d; - i2o_lct *lct = pHba->lct; - u8 bus_no = 0; - s16 scsi_id; - s16 scsi_lun; - u32 buf[10]; // larger than 7, or 8 ... - struct adpt_device* pDev; - - if (lct == NULL) { - printk(KERN_ERR "%s: LCT is empty???\n",pHba->name); - return -1; - } - - max = lct->table_size; - max -= 3; - max /= 9; - - for(i=0;ilct_entry[i].user_tid != 0xfff){ - /* - * If we have hidden devices, we need to inform the upper layers about - * the possible maximum id reference to handle device access when - * an array is disassembled. This code has no other purpose but to - * allow us future access to devices that are currently hidden - * behind arrays, hotspares or have not been configured (JBOD mode). - */ - if( lct->lct_entry[i].class_id != I2O_CLASS_RANDOM_BLOCK_STORAGE && - lct->lct_entry[i].class_id != I2O_CLASS_SCSI_PERIPHERAL && - lct->lct_entry[i].class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){ - continue; - } - tid = lct->lct_entry[i].tid; - // I2O_DPT_DEVICE_INFO_GROUP_NO; - if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) { - continue; - } - bus_no = buf[0]>>16; - scsi_id = buf[1]; - scsi_lun = (buf[2]>>8 )&0xff; - if(bus_no >= MAX_CHANNEL) { // Something wrong skip it - printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no); - continue; - } - if (scsi_id >= MAX_ID){ - printk(KERN_WARNING"%s: SCSI ID %d out of range \n", pHba->name, bus_no); - continue; - } - if(bus_no > pHba->top_scsi_channel){ - pHba->top_scsi_channel = bus_no; - } - if(scsi_id > pHba->top_scsi_id){ - pHba->top_scsi_id = scsi_id; - } - if(scsi_lun > pHba->top_scsi_lun){ - pHba->top_scsi_lun = scsi_lun; - } - continue; - } - d = kmalloc(sizeof(struct i2o_device), GFP_KERNEL); - if(d==NULL) - { - printk(KERN_CRIT"%s: Out of memory for I2O device data.\n",pHba->name); - return -ENOMEM; - } - - d->controller = pHba; - d->next = NULL; - - memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); - - d->flags = 0; - tid = d->lct_data.tid; - adpt_i2o_report_hba_unit(pHba, d); - adpt_i2o_install_device(pHba, d); - } - bus_no = 0; - for(d = pHba->devices; d ; d = d->next) { - if(d->lct_data.class_id == I2O_CLASS_BUS_ADAPTER_PORT || - d->lct_data.class_id == I2O_CLASS_FIBRE_CHANNEL_PORT){ - tid = d->lct_data.tid; - // TODO get the bus_no from hrt-but for now they are in order - //bus_no = - if(bus_no > pHba->top_scsi_channel){ - pHba->top_scsi_channel = bus_no; - } - pHba->channel[bus_no].type = d->lct_data.class_id; - pHba->channel[bus_no].tid = tid; - if(adpt_i2o_query_scalar(pHba, tid, 0x0200, -1, buf, 28)>=0) - { - pHba->channel[bus_no].scsi_id = buf[1]; - PDEBUG("Bus %d - SCSI ID %d.\n", bus_no, buf[1]); - } - // TODO remove - this is just until we get from hrt - bus_no++; - if(bus_no >= MAX_CHANNEL) { // Something wrong skip it - printk(KERN_WARNING"%s: Channel number %d out of range - LCT\n", pHba->name, bus_no); - break; - } - } - } - - // Setup adpt_device table - for(d = pHba->devices; d ; d = d->next) { - if(d->lct_data.class_id == I2O_CLASS_RANDOM_BLOCK_STORAGE || - d->lct_data.class_id == I2O_CLASS_SCSI_PERIPHERAL || - d->lct_data.class_id == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){ - - tid = d->lct_data.tid; - scsi_id = -1; - // I2O_DPT_DEVICE_INFO_GROUP_NO; - if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)>=0) { - bus_no = buf[0]>>16; - scsi_id = buf[1]; - scsi_lun = (buf[2]>>8 )&0xff; - if(bus_no >= MAX_CHANNEL) { // Something wrong skip it - continue; - } - if (scsi_id >= MAX_ID) { - continue; - } - if( pHba->channel[bus_no].device[scsi_id] == NULL){ - pDev = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); - if(pDev == NULL) { - return -ENOMEM; - } - pHba->channel[bus_no].device[scsi_id] = pDev; - } else { - for( pDev = pHba->channel[bus_no].device[scsi_id]; - pDev->next_lun; pDev = pDev->next_lun){ - } - pDev->next_lun = kzalloc(sizeof(struct adpt_device),GFP_KERNEL); - if(pDev->next_lun == NULL) { - return -ENOMEM; - } - pDev = pDev->next_lun; - } - pDev->tid = tid; - pDev->scsi_channel = bus_no; - pDev->scsi_id = scsi_id; - pDev->scsi_lun = scsi_lun; - pDev->pI2o_dev = d; - d->owner = pDev; - pDev->type = (buf[0])&0xff; - pDev->flags = (buf[0]>>8)&0xff; - if(scsi_id > pHba->top_scsi_id){ - pHba->top_scsi_id = scsi_id; - } - if(scsi_lun > pHba->top_scsi_lun){ - pHba->top_scsi_lun = scsi_lun; - } - } - if(scsi_id == -1){ - printk(KERN_WARNING"Could not find SCSI ID for %s\n", - d->lct_data.identity_tag); - } - } - } - return 0; -} - - -/* - * Each I2O controller has a chain of devices on it - these match - * the useful parts of the LCT of the board. - */ - -static int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d) -{ - mutex_lock(&adpt_configuration_lock); - d->controller=pHba; - d->owner=NULL; - d->next=pHba->devices; - d->prev=NULL; - if (pHba->devices != NULL){ - pHba->devices->prev=d; - } - pHba->devices=d; - *d->dev_name = 0; - - mutex_unlock(&adpt_configuration_lock); - return 0; -} - -static int adpt_open(struct inode *inode, struct file *file) -{ - int minor; - adpt_hba* pHba; - - mutex_lock(&adpt_mutex); - //TODO check for root access - // - minor = iminor(inode); - if (minor >= hba_count) { - mutex_unlock(&adpt_mutex); - return -ENXIO; - } - mutex_lock(&adpt_configuration_lock); - for (pHba = hba_chain; pHba; pHba = pHba->next) { - if (pHba->unit == minor) { - break; /* found adapter */ - } - } - if (pHba == NULL) { - mutex_unlock(&adpt_configuration_lock); - mutex_unlock(&adpt_mutex); - return -ENXIO; - } - -// if(pHba->in_use){ - // mutex_unlock(&adpt_configuration_lock); -// return -EBUSY; -// } - - pHba->in_use = 1; - mutex_unlock(&adpt_configuration_lock); - mutex_unlock(&adpt_mutex); - - return 0; -} - -static int adpt_close(struct inode *inode, struct file *file) -{ - int minor; - adpt_hba* pHba; - - minor = iminor(inode); - if (minor >= hba_count) { - return -ENXIO; - } - mutex_lock(&adpt_configuration_lock); - for (pHba = hba_chain; pHba; pHba = pHba->next) { - if (pHba->unit == minor) { - break; /* found adapter */ - } - } - mutex_unlock(&adpt_configuration_lock); - if (pHba == NULL) { - return -ENXIO; - } - - pHba->in_use = 0; - - return 0; -} - - -static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg) -{ - u32 msg[MAX_MESSAGE_SIZE]; - u32* reply = NULL; - u32 size = 0; - u32 reply_size = 0; - u32 __user *user_msg = arg; - u32 __user * user_reply = NULL; - void *sg_list[pHba->sg_tablesize]; - u32 sg_offset = 0; - u32 sg_count = 0; - int sg_index = 0; - u32 i = 0; - u32 rcode = 0; - void *p = NULL; - dma_addr_t addr; - ulong flags = 0; - - memset(&msg, 0, MAX_MESSAGE_SIZE*4); - // get user msg size in u32s - if(get_user(size, &user_msg[0])){ - return -EFAULT; - } - size = size>>16; - - user_reply = &user_msg[size]; - if(size > MAX_MESSAGE_SIZE){ - return -EFAULT; - } - size *= 4; // Convert to bytes - - /* Copy in the user's I2O command */ - if(copy_from_user(msg, user_msg, size)) { - return -EFAULT; - } - get_user(reply_size, &user_reply[0]); - reply_size = reply_size>>16; - if(reply_size > REPLY_FRAME_SIZE){ - reply_size = REPLY_FRAME_SIZE; - } - reply_size *= 4; - reply = kzalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL); - if(reply == NULL) { - printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name); - return -ENOMEM; - } - sg_offset = (msg[0]>>4)&0xf; - msg[2] = 0x40000000; // IOCTL context - msg[3] = adpt_ioctl_to_context(pHba, reply); - if (msg[3] == (u32)-1) - return -EBUSY; - - memset(sg_list,0, sizeof(sg_list[0])*pHba->sg_tablesize); - if(sg_offset) { - // TODO add 64 bit API - struct sg_simple_element *sg = (struct sg_simple_element*) (msg+sg_offset); - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); - if (sg_count > pHba->sg_tablesize){ - printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", pHba->name,sg_count); - kfree (reply); - return -EINVAL; - } - - for(i = 0; i < sg_count; i++) { - int sg_size; - - if (!(sg[i].flag_count & 0x10000000 /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT*/)) { - printk(KERN_DEBUG"%s:Bad SG element %d - not simple (%x)\n",pHba->name,i, sg[i].flag_count); - rcode = -EINVAL; - goto cleanup; - } - sg_size = sg[i].flag_count & 0xffffff; - /* Allocate memory for the transfer */ - p = dma_alloc_coherent(&pHba->pDev->dev, sg_size, &addr, GFP_KERNEL); - if(!p) { - printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n", - pHba->name,sg_size,i,sg_count); - rcode = -ENOMEM; - goto cleanup; - } - sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame. - /* Copy in the user's SG buffer if necessary */ - if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) { - // sg_simple_element API is 32 bit - if (copy_from_user(p,(void __user *)(ulong)sg[i].addr_bus, sg_size)) { - printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i); - rcode = -EFAULT; - goto cleanup; - } - } - /* sg_simple_element API is 32 bit, but addr < 4GB */ - sg[i].addr_bus = addr; - } - } - - do { - if(pHba->host) - spin_lock_irqsave(pHba->host->host_lock, flags); - // This state stops any new commands from enterring the - // controller while processing the ioctl -// pHba->state |= DPTI_STATE_IOCTL; -// We can't set this now - The scsi subsystem sets host_blocked and -// the queue empties and stops. We need a way to restart the queue - rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER); - if (rcode != 0) - printk("adpt_i2o_passthru: post wait failed %d %p\n", - rcode, reply); -// pHba->state &= ~DPTI_STATE_IOCTL; - if(pHba->host) - spin_unlock_irqrestore(pHba->host->host_lock, flags); - } while(rcode == -ETIMEDOUT); - - if(rcode){ - goto cleanup; - } - - if(sg_offset) { - /* Copy back the Scatter Gather buffers back to user space */ - u32 j; - // TODO add 64 bit API - struct sg_simple_element* sg; - int sg_size; - - // re-acquire the original message to handle correctly the sg copy operation - memset(&msg, 0, MAX_MESSAGE_SIZE*4); - // get user msg size in u32s - if(get_user(size, &user_msg[0])){ - rcode = -EFAULT; - goto cleanup; - } - size = size>>16; - size *= 4; - if (size > MAX_MESSAGE_SIZE) { - rcode = -EINVAL; - goto cleanup; - } - /* Copy in the user's I2O command */ - if (copy_from_user (msg, user_msg, size)) { - rcode = -EFAULT; - goto cleanup; - } - sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element); - - // TODO add 64 bit API - sg = (struct sg_simple_element*)(msg + sg_offset); - for (j = 0; j < sg_count; j++) { - /* Copy out the SG list to user's buffer if necessary */ - if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) { - sg_size = sg[j].flag_count & 0xffffff; - // sg_simple_element API is 32 bit - if (copy_to_user((void __user *)(ulong)sg[j].addr_bus,sg_list[j], sg_size)) { - printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus); - rcode = -EFAULT; - goto cleanup; - } - } - } - } - - /* Copy back the reply to user space */ - if (reply_size) { - // we wrote our own values for context - now restore the user supplied ones - if(copy_from_user(reply+2, user_msg+2, sizeof(u32)*2)) { - printk(KERN_WARNING"%s: Could not copy message context FROM user\n",pHba->name); - rcode = -EFAULT; - } - if(copy_to_user(user_reply, reply, reply_size)) { - printk(KERN_WARNING"%s: Could not copy reply TO user\n",pHba->name); - rcode = -EFAULT; - } - } - - -cleanup: - if (rcode != -ETIME && rcode != -EINTR) { - struct sg_simple_element *sg = - (struct sg_simple_element*) (msg +sg_offset); - kfree (reply); - while(sg_index) { - if(sg_list[--sg_index]) { - dma_free_coherent(&pHba->pDev->dev, - sg[sg_index].flag_count & 0xffffff, - sg_list[sg_index], - sg[sg_index].addr_bus); - } - } - } - return rcode; -} - -#if defined __ia64__ -static void adpt_ia64_info(sysInfo_S* si) -{ - // This is all the info we need for now - // We will add more info as our new - // managmenent utility requires it - si->processorType = PROC_IA64; -} -#endif - -#if defined __sparc__ -static void adpt_sparc_info(sysInfo_S* si) -{ - // This is all the info we need for now - // We will add more info as our new - // managmenent utility requires it - si->processorType = PROC_ULTRASPARC; -} -#endif -#if defined __alpha__ -static void adpt_alpha_info(sysInfo_S* si) -{ - // This is all the info we need for now - // We will add more info as our new - // managmenent utility requires it - si->processorType = PROC_ALPHA; -} -#endif - -#if defined __i386__ -static void adpt_i386_info(sysInfo_S* si) -{ - // This is all the info we need for now - // We will add more info as our new - // managmenent utility requires it - switch (boot_cpu_data.x86) { - case CPU_386: - si->processorType = PROC_386; - break; - case CPU_486: - si->processorType = PROC_486; - break; - case CPU_586: - si->processorType = PROC_PENTIUM; - break; - default: // Just in case - si->processorType = PROC_PENTIUM; - break; - } -} -#endif - -/* - * This routine returns information about the system. This does not effect - * any logic and if the info is wrong - it doesn't matter. - */ - -/* Get all the info we can not get from kernel services */ -static int adpt_system_info(void __user *buffer) -{ - sysInfo_S si; - - memset(&si, 0, sizeof(si)); - - si.osType = OS_LINUX; - si.osMajorVersion = 0; - si.osMinorVersion = 0; - si.osRevision = 0; - si.busType = SI_PCI_BUS; - si.processorFamily = DPTI_sig.dsProcessorFamily; - -#if defined __i386__ - adpt_i386_info(&si); -#elif defined (__ia64__) - adpt_ia64_info(&si); -#elif defined(__sparc__) - adpt_sparc_info(&si); -#elif defined (__alpha__) - adpt_alpha_info(&si); -#else - si.processorType = 0xff ; -#endif - if (copy_to_user(buffer, &si, sizeof(si))){ - printk(KERN_WARNING"dpti: Could not copy buffer TO user\n"); - return -EFAULT; - } - - return 0; -} - -static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg) -{ - int minor; - int error = 0; - adpt_hba* pHba; - ulong flags = 0; - void __user *argp = (void __user *)arg; - - minor = iminor(inode); - if (minor >= DPTI_MAX_HBA){ - return -ENXIO; - } - mutex_lock(&adpt_configuration_lock); - for (pHba = hba_chain; pHba; pHba = pHba->next) { - if (pHba->unit == minor) { - break; /* found adapter */ - } - } - mutex_unlock(&adpt_configuration_lock); - if(pHba == NULL){ - return -ENXIO; - } - - while((volatile u32) pHba->state & DPTI_STATE_RESET ) - schedule_timeout_uninterruptible(2); - - switch (cmd) { - // TODO: handle 3 cases - case DPT_SIGNATURE: - if (copy_to_user(argp, &DPTI_sig, sizeof(DPTI_sig))) { - return -EFAULT; - } - break; - case I2OUSRCMD: - return adpt_i2o_passthru(pHba, argp); - - case DPT_CTRLINFO:{ - drvrHBAinfo_S HbaInfo; - -#define FLG_OSD_PCI_VALID 0x0001 -#define FLG_OSD_DMA 0x0002 -#define FLG_OSD_I2O 0x0004 - memset(&HbaInfo, 0, sizeof(HbaInfo)); - HbaInfo.drvrHBAnum = pHba->unit; - HbaInfo.baseAddr = (ulong) pHba->base_addr_phys; - HbaInfo.blinkState = adpt_read_blink_led(pHba); - HbaInfo.pciBusNum = pHba->pDev->bus->number; - HbaInfo.pciDeviceNum=PCI_SLOT(pHba->pDev->devfn); - HbaInfo.Interrupt = pHba->pDev->irq; - HbaInfo.hbaFlags = FLG_OSD_PCI_VALID | FLG_OSD_DMA | FLG_OSD_I2O; - if(copy_to_user(argp, &HbaInfo, sizeof(HbaInfo))){ - printk(KERN_WARNING"%s: Could not copy HbaInfo TO user\n",pHba->name); - return -EFAULT; - } - break; - } - case DPT_SYSINFO: - return adpt_system_info(argp); - case DPT_BLINKLED:{ - u32 value; - value = (u32)adpt_read_blink_led(pHba); - if (copy_to_user(argp, &value, sizeof(value))) { - return -EFAULT; - } - break; - } - case I2ORESETCMD: - if(pHba->host) - spin_lock_irqsave(pHba->host->host_lock, flags); - adpt_hba_reset(pHba); - if(pHba->host) - spin_unlock_irqrestore(pHba->host->host_lock, flags); - break; - case I2ORESCANCMD: - adpt_rescan(pHba); - break; - default: - return -EINVAL; - } - - return error; -} - -static long adpt_unlocked_ioctl(struct file *file, uint cmd, ulong arg) -{ - struct inode *inode; - long ret; - - inode = file->f_dentry->d_inode; - - mutex_lock(&adpt_mutex); - ret = adpt_ioctl(inode, file, cmd, arg); - mutex_unlock(&adpt_mutex); - - return ret; -} - -#ifdef CONFIG_COMPAT -static long compat_adpt_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct inode *inode; - long ret; - - inode = file->f_dentry->d_inode; - - mutex_lock(&adpt_mutex); - - switch(cmd) { - case DPT_SIGNATURE: - case I2OUSRCMD: - case DPT_CTRLINFO: - case DPT_SYSINFO: - case DPT_BLINKLED: - case I2ORESETCMD: - case I2ORESCANCMD: - case (DPT_TARGET_BUSY & 0xFFFF): - case DPT_TARGET_BUSY: - ret = adpt_ioctl(inode, file, cmd, arg); - break; - default: - ret = -ENOIOCTLCMD; - } - - mutex_unlock(&adpt_mutex); - - return ret; -} -#endif - -static irqreturn_t adpt_isr(int irq, void *dev_id) -{ - struct scsi_cmnd* cmd; - adpt_hba* pHba = dev_id; - u32 m; - void __iomem *reply; - u32 status=0; - u32 context; - ulong flags = 0; - int handled = 0; - - if (pHba == NULL){ - printk(KERN_WARNING"adpt_isr: NULL dev_id\n"); - return IRQ_NONE; - } - if(pHba->host) - spin_lock_irqsave(pHba->host->host_lock, flags); - - while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) { - m = readl(pHba->reply_port); - if(m == EMPTY_QUEUE){ - // Try twice then give up - rmb(); - m = readl(pHba->reply_port); - if(m == EMPTY_QUEUE){ - // This really should not happen - printk(KERN_ERR"dpti: Could not get reply frame\n"); - goto out; - } - } - if (pHba->reply_pool_pa <= m && - m < pHba->reply_pool_pa + - (pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4)) { - reply = (u8 *)pHba->reply_pool + - (m - pHba->reply_pool_pa); - } else { - /* Ick, we should *never* be here */ - printk(KERN_ERR "dpti: reply frame not from pool\n"); - reply = (u8 *)bus_to_virt(m); - } - - if (readl(reply) & MSG_FAIL) { - u32 old_m = readl(reply+28); - void __iomem *msg; - u32 old_context; - PDEBUG("%s: Failed message\n",pHba->name); - if(old_m >= 0x100000){ - printk(KERN_ERR"%s: Bad preserved MFA (%x)- dropping frame\n",pHba->name,old_m); - writel(m,pHba->reply_port); - continue; - } - // Transaction context is 0 in failed reply frame - msg = pHba->msg_addr_virt + old_m; - old_context = readl(msg+12); - writel(old_context, reply+12); - adpt_send_nop(pHba, old_m); - } - context = readl(reply+8); - if(context & 0x40000000){ // IOCTL - void *p = adpt_ioctl_from_context(pHba, readl(reply+12)); - if( p != NULL) { - memcpy_fromio(p, reply, REPLY_FRAME_SIZE * 4); - } - // All IOCTLs will also be post wait - } - if(context & 0x80000000){ // Post wait message - status = readl(reply+16); - if(status >> 24){ - status &= 0xffff; /* Get detail status */ - } else { - status = I2O_POST_WAIT_OK; - } - if(!(context & 0x40000000)) { - cmd = adpt_cmd_from_context(pHba, - readl(reply+12)); - if(cmd != NULL) { - printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context); - } - } - adpt_i2o_post_wait_complete(context, status); - } else { // SCSI message - cmd = adpt_cmd_from_context (pHba, readl(reply+12)); - if(cmd != NULL){ - scsi_dma_unmap(cmd); - if(cmd->serial_number != 0) { // If not timedout - adpt_i2o_to_scsi(reply, cmd); - } - } - } - writel(m, pHba->reply_port); - wmb(); - rmb(); - } - handled = 1; -out: if(pHba->host) - spin_unlock_irqrestore(pHba->host->host_lock, flags); - return IRQ_RETVAL(handled); -} - -static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* d) -{ - int i; - u32 msg[MAX_MESSAGE_SIZE]; - u32* mptr; - u32* lptr; - u32 *lenptr; - int direction; - int scsidir; - int nseg; - u32 len; - u32 reqlen; - s32 rcode; - dma_addr_t addr; - - memset(msg, 0 , sizeof(msg)); - len = scsi_bufflen(cmd); - direction = 0x00000000; - - scsidir = 0x00000000; // DATA NO XFER - if(len) { - /* - * Set SCBFlags to indicate if data is being transferred - * in or out, or no data transfer - * Note: Do not have to verify index is less than 0 since - * cmd->cmnd[0] is an unsigned char - */ - switch(cmd->sc_data_direction){ - case DMA_FROM_DEVICE: - scsidir =0x40000000; // DATA IN (iop<--dev) - break; - case DMA_TO_DEVICE: - direction=0x04000000; // SGL OUT - scsidir =0x80000000; // DATA OUT (iop-->dev) - break; - case DMA_NONE: - break; - case DMA_BIDIRECTIONAL: - scsidir =0x40000000; // DATA IN (iop<--dev) - // Assume In - and continue; - break; - default: - printk(KERN_WARNING"%s: scsi opcode 0x%x not supported.\n", - pHba->name, cmd->cmnd[0]); - cmd->result = (DID_OK <<16) | (INITIATOR_ERROR << 8); - cmd->scsi_done(cmd); - return 0; - } - } - // msg[0] is set later - // I2O_CMD_SCSI_EXEC - msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid); - msg[2] = 0; - msg[3] = adpt_cmd_to_context(cmd); /* Want SCSI control block back */ - // Our cards use the transaction context as the tag for queueing - // Adaptec/DPT Private stuff - msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16); - msg[5] = d->tid; - /* Direction, disconnect ok | sense data | simple queue , CDBLen */ - // I2O_SCB_FLAG_ENABLE_DISCONNECT | - // I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | - // I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE; - msg[6] = scsidir|0x20a00000|cmd->cmd_len; - - mptr=msg+7; - - // Write SCSI command into the message - always 16 byte block - memset(mptr, 0, 16); - memcpy(mptr, cmd->cmnd, cmd->cmd_len); - mptr+=4; - lenptr=mptr++; /* Remember me - fill in when we know */ - if (dpt_dma64(pHba)) { - reqlen = 16; // SINGLE SGE - *mptr++ = (0x7C<<24)+(2<<16)+0x02; /* Enable 64 bit */ - *mptr++ = 1 << PAGE_SHIFT; - } else { - reqlen = 14; // SINGLE SGE - } - /* Now fill in the SGList and command */ - - nseg = scsi_dma_map(cmd); - BUG_ON(nseg < 0); - if (nseg) { - struct scatterlist *sg; - - len = 0; - scsi_for_each_sg(cmd, sg, nseg, i) { - lptr = mptr; - *mptr++ = direction|0x10000000|sg_dma_len(sg); - len+=sg_dma_len(sg); - addr = sg_dma_address(sg); - *mptr++ = dma_low(addr); - if (dpt_dma64(pHba)) - *mptr++ = dma_high(addr); - /* Make this an end of list */ - if (i == nseg - 1) - *lptr = direction|0xD0000000|sg_dma_len(sg); - } - reqlen = mptr - msg; - *lenptr = len; - - if(cmd->underflow && len != cmd->underflow){ - printk(KERN_WARNING"Cmd len %08X Cmd underflow %08X\n", - len, cmd->underflow); - } - } else { - *lenptr = len = 0; - reqlen = 12; - } - - /* Stick the headers on */ - msg[0] = reqlen<<16 | ((reqlen > 12) ? SGL_OFFSET_12 : SGL_OFFSET_0); - - // Send it on it's way - rcode = adpt_i2o_post_this(pHba, msg, reqlen<<2); - if (rcode == 0) { - return 0; - } - return rcode; -} - - -static s32 adpt_scsi_host_alloc(adpt_hba* pHba, struct scsi_host_template *sht) -{ - struct Scsi_Host *host; - - host = scsi_host_alloc(sht, sizeof(adpt_hba*)); - if (host == NULL) { - printk("%s: scsi_host_alloc returned NULL\n", pHba->name); - return -1; - } - host->hostdata[0] = (unsigned long)pHba; - pHba->host = host; - - host->irq = pHba->pDev->irq; - /* no IO ports, so don't have to set host->io_port and - * host->n_io_port - */ - host->io_port = 0; - host->n_io_port = 0; - /* see comments in scsi_host.h */ - host->max_id = 16; - host->max_lun = 256; - host->max_channel = pHba->top_scsi_channel + 1; - host->cmd_per_lun = 1; - host->unique_id = (u32)sys_tbl_pa + pHba->unit; - host->sg_tablesize = pHba->sg_tablesize; - host->can_queue = pHba->post_fifo_size; - - return 0; -} - - -static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd) -{ - adpt_hba* pHba; - u32 hba_status; - u32 dev_status; - u32 reply_flags = readl(reply) & 0xff00; // Leave it shifted up 8 bits - // I know this would look cleaner if I just read bytes - // but the model I have been using for all the rest of the - // io is in 4 byte words - so I keep that model - u16 detailed_status = readl(reply+16) &0xffff; - dev_status = (detailed_status & 0xff); - hba_status = detailed_status >> 8; - - // calculate resid for sg - scsi_set_resid(cmd, scsi_bufflen(cmd) - readl(reply+20)); - - pHba = (adpt_hba*) cmd->device->host->hostdata[0]; - - cmd->sense_buffer[0] = '\0'; // initialize sense valid flag to false - - if(!(reply_flags & MSG_FAIL)) { - switch(detailed_status & I2O_SCSI_DSC_MASK) { - case I2O_SCSI_DSC_SUCCESS: - cmd->result = (DID_OK << 16); - // handle underflow - if (readl(reply+20) < cmd->underflow) { - cmd->result = (DID_ERROR <<16); - printk(KERN_WARNING"%s: SCSI CMD underflow\n",pHba->name); - } - break; - case I2O_SCSI_DSC_REQUEST_ABORTED: - cmd->result = (DID_ABORT << 16); - break; - case I2O_SCSI_DSC_PATH_INVALID: - case I2O_SCSI_DSC_DEVICE_NOT_PRESENT: - case I2O_SCSI_DSC_SELECTION_TIMEOUT: - case I2O_SCSI_DSC_COMMAND_TIMEOUT: - case I2O_SCSI_DSC_NO_ADAPTER: - case I2O_SCSI_DSC_RESOURCE_UNAVAILABLE: - printk(KERN_WARNING"%s: SCSI Timeout-Device (%d,%d,%d) hba status=0x%x, dev status=0x%x, cmd=0x%x\n", - pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun, hba_status, dev_status, cmd->cmnd[0]); - cmd->result = (DID_TIME_OUT << 16); - break; - case I2O_SCSI_DSC_ADAPTER_BUSY: - case I2O_SCSI_DSC_BUS_BUSY: - cmd->result = (DID_BUS_BUSY << 16); - break; - case I2O_SCSI_DSC_SCSI_BUS_RESET: - case I2O_SCSI_DSC_BDR_MESSAGE_SENT: - cmd->result = (DID_RESET << 16); - break; - case I2O_SCSI_DSC_PARITY_ERROR_FAILURE: - printk(KERN_WARNING"%s: SCSI CMD parity error\n",pHba->name); - cmd->result = (DID_PARITY << 16); - break; - case I2O_SCSI_DSC_UNABLE_TO_ABORT: - case I2O_SCSI_DSC_COMPLETE_WITH_ERROR: - case I2O_SCSI_DSC_UNABLE_TO_TERMINATE: - case I2O_SCSI_DSC_MR_MESSAGE_RECEIVED: - case I2O_SCSI_DSC_AUTOSENSE_FAILED: - case I2O_SCSI_DSC_DATA_OVERRUN: - case I2O_SCSI_DSC_UNEXPECTED_BUS_FREE: - case I2O_SCSI_DSC_SEQUENCE_FAILURE: - case I2O_SCSI_DSC_REQUEST_LENGTH_ERROR: - case I2O_SCSI_DSC_PROVIDE_FAILURE: - case I2O_SCSI_DSC_REQUEST_TERMINATED: - case I2O_SCSI_DSC_IDE_MESSAGE_SENT: - case I2O_SCSI_DSC_UNACKNOWLEDGED_EVENT: - case I2O_SCSI_DSC_MESSAGE_RECEIVED: - case I2O_SCSI_DSC_INVALID_CDB: - case I2O_SCSI_DSC_LUN_INVALID: - case I2O_SCSI_DSC_SCSI_TID_INVALID: - case I2O_SCSI_DSC_FUNCTION_UNAVAILABLE: - case I2O_SCSI_DSC_NO_NEXUS: - case I2O_SCSI_DSC_CDB_RECEIVED: - case I2O_SCSI_DSC_LUN_ALREADY_ENABLED: - case I2O_SCSI_DSC_QUEUE_FROZEN: - case I2O_SCSI_DSC_REQUEST_INVALID: - default: - printk(KERN_WARNING"%s: SCSI error %0x-Device(%d,%d,%d) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n", - pHba->name, detailed_status & I2O_SCSI_DSC_MASK, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun, - hba_status, dev_status, cmd->cmnd[0]); - cmd->result = (DID_ERROR << 16); - break; - } - - // copy over the request sense data if it was a check - // condition status - if (dev_status == SAM_STAT_CHECK_CONDITION) { - u32 len = min(SCSI_SENSE_BUFFERSIZE, 40); - // Copy over the sense data - memcpy_fromio(cmd->sense_buffer, (reply+28) , len); - if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && - cmd->sense_buffer[2] == DATA_PROTECT ){ - /* This is to handle an array failed */ - cmd->result = (DID_TIME_OUT << 16); - printk(KERN_WARNING"%s: SCSI Data Protect-Device (%d,%d,%d) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n", - pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun, - hba_status, dev_status, cmd->cmnd[0]); - - } - } - } else { - /* In this condtion we could not talk to the tid - * the card rejected it. We should signal a retry - * for a limitted number of retries. - */ - cmd->result = (DID_TIME_OUT << 16); - printk(KERN_WARNING"%s: I2O MSG_FAIL - Device (%d,%d,%d) tid=%d, cmd=0x%x\n", - pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun, - ((struct adpt_device*)(cmd->device->hostdata))->tid, cmd->cmnd[0]); - } - - cmd->result |= (dev_status); - - if(cmd->scsi_done != NULL){ - cmd->scsi_done(cmd); - } - return cmd->result; -} - - -static s32 adpt_rescan(adpt_hba* pHba) -{ - s32 rcode; - ulong flags = 0; - - if(pHba->host) - spin_lock_irqsave(pHba->host->host_lock, flags); - if ((rcode=adpt_i2o_lct_get(pHba)) < 0) - goto out; - if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0) - goto out; - rcode = 0; -out: if(pHba->host) - spin_unlock_irqrestore(pHba->host->host_lock, flags); - return rcode; -} - - -static s32 adpt_i2o_reparse_lct(adpt_hba* pHba) -{ - int i; - int max; - int tid; - struct i2o_device *d; - i2o_lct *lct = pHba->lct; - u8 bus_no = 0; - s16 scsi_id; - s16 scsi_lun; - u32 buf[10]; // at least 8 u32's - struct adpt_device* pDev = NULL; - struct i2o_device* pI2o_dev = NULL; - - if (lct == NULL) { - printk(KERN_ERR "%s: LCT is empty???\n",pHba->name); - return -1; - } - - max = lct->table_size; - max -= 3; - max /= 9; - - // Mark each drive as unscanned - for (d = pHba->devices; d; d = d->next) { - pDev =(struct adpt_device*) d->owner; - if(!pDev){ - continue; - } - pDev->state |= DPTI_DEV_UNSCANNED; - } - - printk(KERN_INFO "%s: LCT has %d entries.\n", pHba->name,max); - - for(i=0;ilct_entry[i].user_tid != 0xfff){ - continue; - } - - if( lct->lct_entry[i].class_id == I2O_CLASS_RANDOM_BLOCK_STORAGE || - lct->lct_entry[i].class_id == I2O_CLASS_SCSI_PERIPHERAL || - lct->lct_entry[i].class_id == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){ - tid = lct->lct_entry[i].tid; - if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) { - printk(KERN_ERR"%s: Could not query device\n",pHba->name); - continue; - } - bus_no = buf[0]>>16; - if (bus_no >= MAX_CHANNEL) { /* Something wrong skip it */ - printk(KERN_WARNING - "%s: Channel number %d out of range\n", - pHba->name, bus_no); - continue; - } - - scsi_id = buf[1]; - scsi_lun = (buf[2]>>8 )&0xff; - pDev = pHba->channel[bus_no].device[scsi_id]; - /* da lun */ - while(pDev) { - if(pDev->scsi_lun == scsi_lun) { - break; - } - pDev = pDev->next_lun; - } - if(!pDev ) { // Something new add it - d = kmalloc(sizeof(struct i2o_device), - GFP_ATOMIC); - if(d==NULL) - { - printk(KERN_CRIT "Out of memory for I2O device data.\n"); - return -ENOMEM; - } - - d->controller = pHba; - d->next = NULL; - - memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); - - d->flags = 0; - adpt_i2o_report_hba_unit(pHba, d); - adpt_i2o_install_device(pHba, d); - - pDev = pHba->channel[bus_no].device[scsi_id]; - if( pDev == NULL){ - pDev = - kzalloc(sizeof(struct adpt_device), - GFP_ATOMIC); - if(pDev == NULL) { - return -ENOMEM; - } - pHba->channel[bus_no].device[scsi_id] = pDev; - } else { - while (pDev->next_lun) { - pDev = pDev->next_lun; - } - pDev = pDev->next_lun = - kzalloc(sizeof(struct adpt_device), - GFP_ATOMIC); - if(pDev == NULL) { - return -ENOMEM; - } - } - pDev->tid = d->lct_data.tid; - pDev->scsi_channel = bus_no; - pDev->scsi_id = scsi_id; - pDev->scsi_lun = scsi_lun; - pDev->pI2o_dev = d; - d->owner = pDev; - pDev->type = (buf[0])&0xff; - pDev->flags = (buf[0]>>8)&0xff; - // Too late, SCSI system has made up it's mind, but what the hey ... - if(scsi_id > pHba->top_scsi_id){ - pHba->top_scsi_id = scsi_id; - } - if(scsi_lun > pHba->top_scsi_lun){ - pHba->top_scsi_lun = scsi_lun; - } - continue; - } // end of new i2o device - - // We found an old device - check it - while(pDev) { - if(pDev->scsi_lun == scsi_lun) { - if(!scsi_device_online(pDev->pScsi_dev)) { - printk(KERN_WARNING"%s: Setting device (%d,%d,%d) back online\n", - pHba->name,bus_no,scsi_id,scsi_lun); - if (pDev->pScsi_dev) { - scsi_device_set_state(pDev->pScsi_dev, SDEV_RUNNING); - } - } - d = pDev->pI2o_dev; - if(d->lct_data.tid != tid) { // something changed - pDev->tid = tid; - memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry)); - if (pDev->pScsi_dev) { - pDev->pScsi_dev->changed = TRUE; - pDev->pScsi_dev->removable = TRUE; - } - } - // Found it - mark it scanned - pDev->state = DPTI_DEV_ONLINE; - break; - } - pDev = pDev->next_lun; - } - } - } - for (pI2o_dev = pHba->devices; pI2o_dev; pI2o_dev = pI2o_dev->next) { - pDev =(struct adpt_device*) pI2o_dev->owner; - if(!pDev){ - continue; - } - // Drive offline drives that previously existed but could not be found - // in the LCT table - if (pDev->state & DPTI_DEV_UNSCANNED){ - pDev->state = DPTI_DEV_OFFLINE; - printk(KERN_WARNING"%s: Device (%d,%d,%d) offline\n",pHba->name,pDev->scsi_channel,pDev->scsi_id,pDev->scsi_lun); - if (pDev->pScsi_dev) { - scsi_device_set_state(pDev->pScsi_dev, SDEV_OFFLINE); - } - } - } - return 0; -} - -static void adpt_fail_posted_scbs(adpt_hba* pHba) -{ - struct scsi_cmnd* cmd = NULL; - struct scsi_device* d = NULL; - - shost_for_each_device(d, pHba->host) { - unsigned long flags; - spin_lock_irqsave(&d->list_lock, flags); - list_for_each_entry(cmd, &d->cmd_list, list) { - if(cmd->serial_number == 0){ - continue; - } - cmd->result = (DID_OK << 16) | (QUEUE_FULL <<1); - cmd->scsi_done(cmd); - } - spin_unlock_irqrestore(&d->list_lock, flags); - } -} - - -/*============================================================================ - * Routines from i2o subsystem - *============================================================================ - */ - - - -/* - * Bring an I2O controller into HOLD state. See the spec. - */ -static int adpt_i2o_activate_hba(adpt_hba* pHba) -{ - int rcode; - - if(pHba->initialized ) { - if (adpt_i2o_status_get(pHba) < 0) { - if((rcode = adpt_i2o_reset_hba(pHba)) != 0){ - printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name); - return rcode; - } - if (adpt_i2o_status_get(pHba) < 0) { - printk(KERN_INFO "HBA not responding.\n"); - return -1; - } - } - - if(pHba->status_block->iop_state == ADAPTER_STATE_FAULTED) { - printk(KERN_CRIT "%s: hardware fault\n", pHba->name); - return -1; - } - - if (pHba->status_block->iop_state == ADAPTER_STATE_READY || - pHba->status_block->iop_state == ADAPTER_STATE_OPERATIONAL || - pHba->status_block->iop_state == ADAPTER_STATE_HOLD || - pHba->status_block->iop_state == ADAPTER_STATE_FAILED) { - adpt_i2o_reset_hba(pHba); - if (adpt_i2o_status_get(pHba) < 0 || pHba->status_block->iop_state != ADAPTER_STATE_RESET) { - printk(KERN_ERR "%s: Failed to initialize.\n", pHba->name); - return -1; - } - } - } else { - if((rcode = adpt_i2o_reset_hba(pHba)) != 0){ - printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name); - return rcode; - } - - } - - if (adpt_i2o_init_outbound_q(pHba) < 0) { - return -1; - } - - /* In HOLD state */ - - if (adpt_i2o_hrt_get(pHba) < 0) { - return -1; - } - - return 0; -} - -/* - * Bring a controller online into OPERATIONAL state. - */ - -static int adpt_i2o_online_hba(adpt_hba* pHba) -{ - if (adpt_i2o_systab_send(pHba) < 0) { - adpt_i2o_delete_hba(pHba); - return -1; - } - /* In READY state */ - - if (adpt_i2o_enable_hba(pHba) < 0) { - adpt_i2o_delete_hba(pHba); - return -1; - } - - /* In OPERATIONAL state */ - return 0; -} - -static s32 adpt_send_nop(adpt_hba*pHba,u32 m) -{ - u32 __iomem *msg; - ulong timeout = jiffies + 5*HZ; - - while(m == EMPTY_QUEUE){ - rmb(); - m = readl(pHba->post_port); - if(m != EMPTY_QUEUE){ - break; - } - if(time_after(jiffies,timeout)){ - printk(KERN_ERR "%s: Timeout waiting for message frame!\n",pHba->name); - return 2; - } - schedule_timeout_uninterruptible(1); - } - msg = (u32 __iomem *)(pHba->msg_addr_virt + m); - writel( THREE_WORD_MSG_SIZE | SGL_OFFSET_0,&msg[0]); - writel( I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0,&msg[1]); - writel( 0,&msg[2]); - wmb(); - - writel(m, pHba->post_port); - wmb(); - return 0; -} - -static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba) -{ - u8 *status; - dma_addr_t addr; - u32 __iomem *msg = NULL; - int i; - ulong timeout = jiffies + TMOUT_INITOUTBOUND*HZ; - u32 m; - - do { - rmb(); - m = readl(pHba->post_port); - if (m != EMPTY_QUEUE) { - break; - } - - if(time_after(jiffies,timeout)){ - printk(KERN_WARNING"%s: Timeout waiting for message frame\n",pHba->name); - return -ETIMEDOUT; - } - schedule_timeout_uninterruptible(1); - } while(m == EMPTY_QUEUE); - - msg=(u32 __iomem *)(pHba->msg_addr_virt+m); - - status = dma_alloc_coherent(&pHba->pDev->dev, 4, &addr, GFP_KERNEL); - if (!status) { - adpt_send_nop(pHba, m); - printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n", - pHba->name); - return -ENOMEM; - } - memset(status, 0, 4); - - writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]); - writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]); - writel(0, &msg[2]); - writel(0x0106, &msg[3]); /* Transaction context */ - writel(4096, &msg[4]); /* Host page frame size */ - writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]); /* Outbound msg frame size and Initcode */ - writel(0xD0000004, &msg[6]); /* Simple SG LE, EOB */ - writel((u32)addr, &msg[7]); - - writel(m, pHba->post_port); - wmb(); - - // Wait for the reply status to come back - do { - if (*status) { - if (*status != 0x01 /*I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS*/) { - break; - } - } - rmb(); - if(time_after(jiffies,timeout)){ - printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name); - /* We lose 4 bytes of "status" here, but we - cannot free these because controller may - awake and corrupt those bytes at any time */ - /* dma_free_coherent(&pHba->pDev->dev, 4, status, addr); */ - return -ETIMEDOUT; - } - schedule_timeout_uninterruptible(1); - } while (1); - - // If the command was successful, fill the fifo with our reply - // message packets - if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) { - dma_free_coherent(&pHba->pDev->dev, 4, status, addr); - return -2; - } - dma_free_coherent(&pHba->pDev->dev, 4, status, addr); - - if(pHba->reply_pool != NULL) { - dma_free_coherent(&pHba->pDev->dev, - pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, - pHba->reply_pool, pHba->reply_pool_pa); - } - - pHba->reply_pool = dma_alloc_coherent(&pHba->pDev->dev, - pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, - &pHba->reply_pool_pa, GFP_KERNEL); - if (!pHba->reply_pool) { - printk(KERN_ERR "%s: Could not allocate reply pool\n", pHba->name); - return -ENOMEM; - } - memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4); - - for(i = 0; i < pHba->reply_fifo_size; i++) { - writel(pHba->reply_pool_pa + (i * REPLY_FRAME_SIZE * 4), - pHba->reply_port); - wmb(); - } - adpt_i2o_status_get(pHba); - return 0; -} - - -/* - * I2O System Table. Contains information about - * all the IOPs in the system. Used to inform IOPs - * about each other's existence. - * - * sys_tbl_ver is the CurrentChangeIndicator that is - * used by IOPs to track changes. - */ - - - -static s32 adpt_i2o_status_get(adpt_hba* pHba) -{ - ulong timeout; - u32 m; - u32 __iomem *msg; - u8 *status_block=NULL; - - if(pHba->status_block == NULL) { - pHba->status_block = dma_alloc_coherent(&pHba->pDev->dev, - sizeof(i2o_status_block), - &pHba->status_block_pa, GFP_KERNEL); - if(pHba->status_block == NULL) { - printk(KERN_ERR - "dpti%d: Get Status Block failed; Out of memory. \n", - pHba->unit); - return -ENOMEM; - } - } - memset(pHba->status_block, 0, sizeof(i2o_status_block)); - status_block = (u8*)(pHba->status_block); - timeout = jiffies+TMOUT_GETSTATUS*HZ; - do { - rmb(); - m = readl(pHba->post_port); - if (m != EMPTY_QUEUE) { - break; - } - if(time_after(jiffies,timeout)){ - printk(KERN_ERR "%s: Timeout waiting for message !\n", - pHba->name); - return -ETIMEDOUT; - } - schedule_timeout_uninterruptible(1); - } while(m==EMPTY_QUEUE); - - - msg=(u32 __iomem *)(pHba->msg_addr_virt+m); - - writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]); - writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]); - writel(1, &msg[2]); - writel(0, &msg[3]); - writel(0, &msg[4]); - writel(0, &msg[5]); - writel( dma_low(pHba->status_block_pa), &msg[6]); - writel( dma_high(pHba->status_block_pa), &msg[7]); - writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes - - //post message - writel(m, pHba->post_port); - wmb(); - - while(status_block[87]!=0xff){ - if(time_after(jiffies,timeout)){ - printk(KERN_ERR"dpti%d: Get status timeout.\n", - pHba->unit); - return -ETIMEDOUT; - } - rmb(); - schedule_timeout_uninterruptible(1); - } - - // Set up our number of outbound and inbound messages - pHba->post_fifo_size = pHba->status_block->max_inbound_frames; - if (pHba->post_fifo_size > MAX_TO_IOP_MESSAGES) { - pHba->post_fifo_size = MAX_TO_IOP_MESSAGES; - } - - pHba->reply_fifo_size = pHba->status_block->max_outbound_frames; - if (pHba->reply_fifo_size > MAX_FROM_IOP_MESSAGES) { - pHba->reply_fifo_size = MAX_FROM_IOP_MESSAGES; - } - - // Calculate the Scatter Gather list size - if (dpt_dma64(pHba)) { - pHba->sg_tablesize - = ((pHba->status_block->inbound_frame_size * 4 - - 14 * sizeof(u32)) - / (sizeof(struct sg_simple_element) + sizeof(u32))); - } else { - pHba->sg_tablesize - = ((pHba->status_block->inbound_frame_size * 4 - - 12 * sizeof(u32)) - / sizeof(struct sg_simple_element)); - } - if (pHba->sg_tablesize > SG_LIST_ELEMENTS) { - pHba->sg_tablesize = SG_LIST_ELEMENTS; - } - - -#ifdef DEBUG - printk("dpti%d: State = ",pHba->unit); - switch(pHba->status_block->iop_state) { - case 0x01: - printk("INIT\n"); - break; - case 0x02: - printk("RESET\n"); - break; - case 0x04: - printk("HOLD\n"); - break; - case 0x05: - printk("READY\n"); - break; - case 0x08: - printk("OPERATIONAL\n"); - break; - case 0x10: - printk("FAILED\n"); - break; - case 0x11: - printk("FAULTED\n"); - break; - default: - printk("%x (unknown!!)\n",pHba->status_block->iop_state); - } -#endif - return 0; -} - -/* - * Get the IOP's Logical Configuration Table - */ -static int adpt_i2o_lct_get(adpt_hba* pHba) -{ - u32 msg[8]; - int ret; - u32 buf[16]; - - if ((pHba->lct_size == 0) || (pHba->lct == NULL)){ - pHba->lct_size = pHba->status_block->expected_lct_size; - } - do { - if (pHba->lct == NULL) { - pHba->lct = dma_alloc_coherent(&pHba->pDev->dev, - pHba->lct_size, &pHba->lct_pa, - GFP_ATOMIC); - if(pHba->lct == NULL) { - printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n", - pHba->name); - return -ENOMEM; - } - } - memset(pHba->lct, 0, pHba->lct_size); - - msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6; - msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = 0; - msg[3] = 0; - msg[4] = 0xFFFFFFFF; /* All devices */ - msg[5] = 0x00000000; /* Report now */ - msg[6] = 0xD0000000|pHba->lct_size; - msg[7] = (u32)pHba->lct_pa; - - if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 360))) { - printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n", - pHba->name, ret); - printk(KERN_ERR"Adaptec: Error Reading Hardware.\n"); - return ret; - } - - if ((pHba->lct->table_size << 2) > pHba->lct_size) { - pHba->lct_size = pHba->lct->table_size << 2; - dma_free_coherent(&pHba->pDev->dev, pHba->lct_size, - pHba->lct, pHba->lct_pa); - pHba->lct = NULL; - } - } while (pHba->lct == NULL); - - PDEBUG("%s: Hardware resource table read.\n", pHba->name); - - - // I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO; - if(adpt_i2o_query_scalar(pHba, 0 , 0x8000, -1, buf, sizeof(buf))>=0) { - pHba->FwDebugBufferSize = buf[1]; - pHba->FwDebugBuffer_P = ioremap(pHba->base_addr_phys + buf[0], - pHba->FwDebugBufferSize); - if (pHba->FwDebugBuffer_P) { - pHba->FwDebugFlags_P = pHba->FwDebugBuffer_P + - FW_DEBUG_FLAGS_OFFSET; - pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P + - FW_DEBUG_BLED_OFFSET; - pHba->FwDebugBLEDflag_P = pHba->FwDebugBLEDvalue_P + 1; - pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P + - FW_DEBUG_STR_LENGTH_OFFSET; - pHba->FwDebugBuffer_P += buf[2]; - pHba->FwDebugFlags = 0; - } - } - - return 0; -} - -static int adpt_i2o_build_sys_table(void) -{ - adpt_hba* pHba = hba_chain; - int count = 0; - - if (sys_tbl) - dma_free_coherent(&pHba->pDev->dev, sys_tbl_len, - sys_tbl, sys_tbl_pa); - - sys_tbl_len = sizeof(struct i2o_sys_tbl) + // Header + IOPs - (hba_count) * sizeof(struct i2o_sys_tbl_entry); - - sys_tbl = dma_alloc_coherent(&pHba->pDev->dev, - sys_tbl_len, &sys_tbl_pa, GFP_KERNEL); - if (!sys_tbl) { - printk(KERN_WARNING "SysTab Set failed. Out of memory.\n"); - return -ENOMEM; - } - memset(sys_tbl, 0, sys_tbl_len); - - sys_tbl->num_entries = hba_count; - sys_tbl->version = I2OVERSION; - sys_tbl->change_ind = sys_tbl_ind++; - - for(pHba = hba_chain; pHba; pHba = pHba->next) { - u64 addr; - // Get updated Status Block so we have the latest information - if (adpt_i2o_status_get(pHba)) { - sys_tbl->num_entries--; - continue; // try next one - } - - sys_tbl->iops[count].org_id = pHba->status_block->org_id; - sys_tbl->iops[count].iop_id = pHba->unit + 2; - sys_tbl->iops[count].seg_num = 0; - sys_tbl->iops[count].i2o_version = pHba->status_block->i2o_version; - sys_tbl->iops[count].iop_state = pHba->status_block->iop_state; - sys_tbl->iops[count].msg_type = pHba->status_block->msg_type; - sys_tbl->iops[count].frame_size = pHba->status_block->inbound_frame_size; - sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ?? - sys_tbl->iops[count].iop_capabilities = pHba->status_block->iop_capabilities; - addr = pHba->base_addr_phys + 0x40; - sys_tbl->iops[count].inbound_low = dma_low(addr); - sys_tbl->iops[count].inbound_high = dma_high(addr); - - count++; - } - -#ifdef DEBUG -{ - u32 *table = (u32*)sys_tbl; - printk(KERN_DEBUG"sys_tbl_len=%d in 32bit words\n",(sys_tbl_len >>2)); - for(count = 0; count < (sys_tbl_len >>2); count++) { - printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", - count, table[count]); - } -} -#endif - - return 0; -} - - -/* - * Dump the information block associated with a given unit (TID) - */ - -static void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d) -{ - char buf[64]; - int unit = d->lct_data.tid; - - printk(KERN_INFO "TID %3.3d ", unit); - - if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 3, buf, 16)>=0) - { - buf[16]=0; - printk(" Vendor: %-12.12s", buf); - } - if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 4, buf, 16)>=0) - { - buf[16]=0; - printk(" Device: %-12.12s", buf); - } - if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 6, buf, 8)>=0) - { - buf[8]=0; - printk(" Rev: %-12.12s\n", buf); - } -#ifdef DEBUG - printk(KERN_INFO "\tClass: %.21s\n", adpt_i2o_get_class_name(d->lct_data.class_id)); - printk(KERN_INFO "\tSubclass: 0x%04X\n", d->lct_data.sub_class); - printk(KERN_INFO "\tFlags: "); - - if(d->lct_data.device_flags&(1<<0)) - printk("C"); // ConfigDialog requested - if(d->lct_data.device_flags&(1<<1)) - printk("U"); // Multi-user capable - if(!(d->lct_data.device_flags&(1<<4))) - printk("P"); // Peer service enabled! - if(!(d->lct_data.device_flags&(1<<5))) - printk("M"); // Mgmt service enabled! - printk("\n"); -#endif -} - -#ifdef DEBUG -/* - * Do i2o class name lookup - */ -static const char *adpt_i2o_get_class_name(int class) -{ - int idx = 16; - static char *i2o_class_name[] = { - "Executive", - "Device Driver Module", - "Block Device", - "Tape Device", - "LAN Interface", - "WAN Interface", - "Fibre Channel Port", - "Fibre Channel Device", - "SCSI Device", - "ATE Port", - "ATE Device", - "Floppy Controller", - "Floppy Device", - "Secondary Bus Port", - "Peer Transport Agent", - "Peer Transport", - "Unknown" - }; - - switch(class&0xFFF) { - case I2O_CLASS_EXECUTIVE: - idx = 0; break; - case I2O_CLASS_DDM: - idx = 1; break; - case I2O_CLASS_RANDOM_BLOCK_STORAGE: - idx = 2; break; - case I2O_CLASS_SEQUENTIAL_STORAGE: - idx = 3; break; - case I2O_CLASS_LAN: - idx = 4; break; - case I2O_CLASS_WAN: - idx = 5; break; - case I2O_CLASS_FIBRE_CHANNEL_PORT: - idx = 6; break; - case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL: - idx = 7; break; - case I2O_CLASS_SCSI_PERIPHERAL: - idx = 8; break; - case I2O_CLASS_ATE_PORT: - idx = 9; break; - case I2O_CLASS_ATE_PERIPHERAL: - idx = 10; break; - case I2O_CLASS_FLOPPY_CONTROLLER: - idx = 11; break; - case I2O_CLASS_FLOPPY_DEVICE: - idx = 12; break; - case I2O_CLASS_BUS_ADAPTER_PORT: - idx = 13; break; - case I2O_CLASS_PEER_TRANSPORT_AGENT: - idx = 14; break; - case I2O_CLASS_PEER_TRANSPORT: - idx = 15; break; - } - return i2o_class_name[idx]; -} -#endif - - -static s32 adpt_i2o_hrt_get(adpt_hba* pHba) -{ - u32 msg[6]; - int ret, size = sizeof(i2o_hrt); - - do { - if (pHba->hrt == NULL) { - pHba->hrt = dma_alloc_coherent(&pHba->pDev->dev, - size, &pHba->hrt_pa, GFP_KERNEL); - if (pHba->hrt == NULL) { - printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", pHba->name); - return -ENOMEM; - } - } - - msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4; - msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2]= 0; - msg[3]= 0; - msg[4]= (0xD0000000 | size); /* Simple transaction */ - msg[5]= (u32)pHba->hrt_pa; /* Dump it here */ - - if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg),20))) { - printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", pHba->name, ret); - return ret; - } - - if (pHba->hrt->num_entries * pHba->hrt->entry_len << 2 > size) { - int newsize = pHba->hrt->num_entries * pHba->hrt->entry_len << 2; - dma_free_coherent(&pHba->pDev->dev, size, - pHba->hrt, pHba->hrt_pa); - size = newsize; - pHba->hrt = NULL; - } - } while(pHba->hrt == NULL); - return 0; -} - -/* - * Query one scalar group value or a whole scalar group. - */ -static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid, - int group, int field, void *buf, int buflen) -{ - u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field }; - u8 *opblk_va; - dma_addr_t opblk_pa; - u8 *resblk_va; - dma_addr_t resblk_pa; - - int size; - - /* 8 bytes for header */ - resblk_va = dma_alloc_coherent(&pHba->pDev->dev, - sizeof(u8) * (8 + buflen), &resblk_pa, GFP_KERNEL); - if (resblk_va == NULL) { - printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name); - return -ENOMEM; - } - - opblk_va = dma_alloc_coherent(&pHba->pDev->dev, - sizeof(opblk), &opblk_pa, GFP_KERNEL); - if (opblk_va == NULL) { - dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen), - resblk_va, resblk_pa); - printk(KERN_CRIT "%s: query operatio failed; Out of memory.\n", - pHba->name); - return -ENOMEM; - } - if (field == -1) /* whole group */ - opblk[4] = -1; - - memcpy(opblk_va, opblk, sizeof(opblk)); - size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid, - opblk_va, opblk_pa, sizeof(opblk), - resblk_va, resblk_pa, sizeof(u8)*(8+buflen)); - dma_free_coherent(&pHba->pDev->dev, sizeof(opblk), opblk_va, opblk_pa); - if (size == -ETIME) { - dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen), - resblk_va, resblk_pa); - printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name); - return -ETIME; - } else if (size == -EINTR) { - dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen), - resblk_va, resblk_pa); - printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name); - return -EINTR; - } - - memcpy(buf, resblk_va+8, buflen); /* cut off header */ - - dma_free_coherent(&pHba->pDev->dev, sizeof(u8) * (8+buflen), - resblk_va, resblk_pa); - if (size < 0) - return size; - - return buflen; -} - - -/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET - * - * This function can be used for all UtilParamsGet/Set operations. - * The OperationBlock is given in opblk-buffer, - * and results are returned in resblk-buffer. - * Note that the minimum sized resblk is 8 bytes and contains - * ResultCount, ErrorInfoSize, BlockStatus and BlockSize. - */ -static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid, - void *opblk_va, dma_addr_t opblk_pa, int oplen, - void *resblk_va, dma_addr_t resblk_pa, int reslen) -{ - u32 msg[9]; - u32 *res = (u32 *)resblk_va; - int wait_status; - - msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5; - msg[1] = cmd << 24 | HOST_TID << 12 | tid; - msg[2] = 0; - msg[3] = 0; - msg[4] = 0; - msg[5] = 0x54000000 | oplen; /* OperationBlock */ - msg[6] = (u32)opblk_pa; - msg[7] = 0xD0000000 | reslen; /* ResultBlock */ - msg[8] = (u32)resblk_pa; - - if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) { - printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk_va); - return wait_status; /* -DetailedStatus */ - } - - if (res[1]&0x00FF0000) { /* BlockStatus != SUCCESS */ - printk(KERN_WARNING "%s: %s - Error:\n ErrorInfoSize = 0x%02x, " - "BlockStatus = 0x%02x, BlockSize = 0x%04x\n", - pHba->name, - (cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET" - : "PARAMS_GET", - res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF); - return -((res[1] >> 16) & 0xFF); /* -BlockStatus */ - } - - return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ -} - - -static s32 adpt_i2o_quiesce_hba(adpt_hba* pHba) -{ - u32 msg[4]; - int ret; - - adpt_i2o_status_get(pHba); - - /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */ - - if((pHba->status_block->iop_state != ADAPTER_STATE_READY) && - (pHba->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)){ - return 0; - } - - msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID; - msg[2] = 0; - msg[3] = 0; - - if((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 240))) { - printk(KERN_INFO"dpti%d: Unable to quiesce (status=%#x).\n", - pHba->unit, -ret); - } else { - printk(KERN_INFO"dpti%d: Quiesced.\n",pHba->unit); - } - - adpt_i2o_status_get(pHba); - return ret; -} - - -/* - * Enable IOP. Allows the IOP to resume external operations. - */ -static int adpt_i2o_enable_hba(adpt_hba* pHba) -{ - u32 msg[4]; - int ret; - - adpt_i2o_status_get(pHba); - if(!pHba->status_block){ - return -ENOMEM; - } - /* Enable only allowed on READY state */ - if(pHba->status_block->iop_state == ADAPTER_STATE_OPERATIONAL) - return 0; - - if(pHba->status_block->iop_state != ADAPTER_STATE_READY) - return -EINVAL; - - msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0; - msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID; - msg[2]= 0; - msg[3]= 0; - - if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 240))) { - printk(KERN_WARNING"%s: Could not enable (status=%#10x).\n", - pHba->name, ret); - } else { - PDEBUG("%s: Enabled.\n", pHba->name); - } - - adpt_i2o_status_get(pHba); - return ret; -} - - -static int adpt_i2o_systab_send(adpt_hba* pHba) -{ - u32 msg[12]; - int ret; - - msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6; - msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID; - msg[2] = 0; - msg[3] = 0; - msg[4] = (0<<16) | ((pHba->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */ - msg[5] = 0; /* Segment 0 */ - - /* - * Provide three SGL-elements: - * System table (SysTab), Private memory space declaration and - * Private i/o space declaration - */ - msg[6] = 0x54000000 | sys_tbl_len; - msg[7] = (u32)sys_tbl_pa; - msg[8] = 0x54000000 | 0; - msg[9] = 0; - msg[10] = 0xD4000000 | 0; - msg[11] = 0; - - if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 120))) { - printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", - pHba->name, ret); - } -#ifdef DEBUG - else { - PINFO("%s: SysTab set.\n", pHba->name); - } -#endif - - return ret; - } - - -/*============================================================================ - * - *============================================================================ - */ - - -#ifdef UARTDELAY - -static static void adpt_delay(int millisec) -{ - int i; - for (i = 0; i < millisec; i++) { - udelay(1000); /* delay for one millisecond */ - } -} - -#endif - -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = "dpt_i2o", - .proc_name = "dpt_i2o", - .proc_info = adpt_proc_info, - .info = adpt_info, - .queuecommand = adpt_queue, - .eh_abort_handler = adpt_abort, - .eh_device_reset_handler = adpt_device_reset, - .eh_bus_reset_handler = adpt_bus_reset, - .eh_host_reset_handler = adpt_reset, - .bios_param = adpt_bios_param, - .slave_configure = adpt_slave_configure, - .can_queue = MAX_TO_IOP_MESSAGES, - .this_id = 7, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -static int __init adpt_init(void) -{ - int error; - adpt_hba *pHba, *next; - - printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n"); - - error = adpt_detect(&driver_template); - if (error < 0) - return error; - if (hba_chain == NULL) - return -ENODEV; - - for (pHba = hba_chain; pHba; pHba = pHba->next) { - error = scsi_add_host(pHba->host, &pHba->pDev->dev); - if (error) - goto fail; - scsi_scan_host(pHba->host); - } - return 0; -fail: - for (pHba = hba_chain; pHba; pHba = next) { - next = pHba->next; - scsi_remove_host(pHba->host); - } - return error; -} - -static void __exit adpt_exit(void) -{ - adpt_hba *pHba, *next; - - for (pHba = hba_chain; pHba; pHba = pHba->next) - scsi_remove_host(pHba->host); - for (pHba = hba_chain; pHba; pHba = next) { - next = pHba->next; - adpt_release(pHba->host); - } -} - -module_init(adpt_init); -module_exit(adpt_exit); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/dpti.h b/ANDROID_3.4.5/drivers/scsi/dpti.h deleted file mode 100644 index beded716..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dpti.h +++ /dev/null @@ -1,337 +0,0 @@ -/*************************************************************************** - dpti.h - description - ------------------- - begin : Thu Sep 7 2000 - copyright : (C) 2001 by Adaptec - - See Documentation/scsi/dpti.txt for history, notes, license info - and credits - ***************************************************************************/ - -/*************************************************************************** - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ - -#ifndef _DPT_H -#define _DPT_H - -#define MAX_TO_IOP_MESSAGES (255) -#define MAX_FROM_IOP_MESSAGES (255) - - -/* - * SCSI interface function Prototypes - */ - -static int adpt_detect(struct scsi_host_template * sht); -static int adpt_queue(struct Scsi_Host *h, struct scsi_cmnd * cmd); -static int adpt_abort(struct scsi_cmnd * cmd); -static int adpt_reset(struct scsi_cmnd* cmd); -static int adpt_release(struct Scsi_Host *host); -static int adpt_slave_configure(struct scsi_device *); - -static const char *adpt_info(struct Scsi_Host *pSHost); -static int adpt_bios_param(struct scsi_device * sdev, struct block_device *dev, - sector_t, int geom[]); - -static int adpt_bus_reset(struct scsi_cmnd* cmd); -static int adpt_device_reset(struct scsi_cmnd* cmd); - - -/* - * struct scsi_host_template (see scsi/scsi_host.h) - */ - -#define DPT_DRIVER_NAME "Adaptec I2O RAID" - -#ifndef HOSTS_C - -#include "dpt/sys_info.h" -#include -#include "dpt/dpti_i2o.h" -#include "dpt/dpti_ioctl.h" - -#define DPT_I2O_VERSION "2.4 Build 5go" -#define DPT_VERSION 2 -#define DPT_REVISION '4' -#define DPT_SUBREVISION '5' -#define DPT_BETA "" -#define DPT_MONTH 8 -#define DPT_DAY 7 -#define DPT_YEAR (2001-1980) - -#define DPT_DRIVER "dpt_i2o" -#define DPTI_I2O_MAJOR (151) -#define DPT_ORGANIZATION_ID (0x1B) /* For Private Messages */ -#define DPTI_MAX_HBA (16) -#define MAX_CHANNEL (5) // Maximum Channel # Supported -#define MAX_ID (128) // Maximum Target ID Supported - -/* Sizes in 4 byte words */ -#define REPLY_FRAME_SIZE (17) -#define MAX_MESSAGE_SIZE (128) -#define SG_LIST_ELEMENTS (56) - -#define EMPTY_QUEUE 0xffffffff -#define I2O_INTERRUPT_PENDING_B (0x08) - -#define PCI_DPT_VENDOR_ID (0x1044) // DPT PCI Vendor ID -#define PCI_DPT_DEVICE_ID (0xA501) // DPT PCI I2O Device ID -#define PCI_DPT_RAPTOR_DEVICE_ID (0xA511) - -/* Debugging macro from Linux Device Drivers - Rubini */ -#undef PDEBUG -#ifdef DEBUG -//TODO add debug level switch -# define PDEBUG(fmt, args...) printk(KERN_DEBUG "dpti: " fmt, ##args) -# define PDEBUGV(fmt, args...) printk(KERN_DEBUG "dpti: " fmt, ##args) -#else -# define PDEBUG(fmt, args...) /* not debugging: nothing */ -# define PDEBUGV(fmt, args...) /* not debugging: nothing */ -#endif - -#define PERROR(fmt, args...) printk(KERN_ERR fmt, ##args) -#define PWARN(fmt, args...) printk(KERN_WARNING fmt, ##args) -#define PINFO(fmt, args...) printk(KERN_INFO fmt, ##args) -#define PCRIT(fmt, args...) printk(KERN_CRIT fmt, ##args) - -#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) - -// Command timeouts -#define FOREVER (0) -#define TMOUT_INQUIRY (20) -#define TMOUT_FLUSH (360/45) -#define TMOUT_ABORT (30) -#define TMOUT_SCSI (300) -#define TMOUT_IOPRESET (360) -#define TMOUT_GETSTATUS (15) -#define TMOUT_INITOUTBOUND (15) -#define TMOUT_LCT (360) - - -#define I2O_SCSI_DEVICE_DSC_MASK 0x00FF - -#define I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION 0x000A - -#define I2O_SCSI_DSC_MASK 0xFF00 -#define I2O_SCSI_DSC_SUCCESS 0x0000 -#define I2O_SCSI_DSC_REQUEST_ABORTED 0x0200 -#define I2O_SCSI_DSC_UNABLE_TO_ABORT 0x0300 -#define I2O_SCSI_DSC_COMPLETE_WITH_ERROR 0x0400 -#define I2O_SCSI_DSC_ADAPTER_BUSY 0x0500 -#define I2O_SCSI_DSC_REQUEST_INVALID 0x0600 -#define I2O_SCSI_DSC_PATH_INVALID 0x0700 -#define I2O_SCSI_DSC_DEVICE_NOT_PRESENT 0x0800 -#define I2O_SCSI_DSC_UNABLE_TO_TERMINATE 0x0900 -#define I2O_SCSI_DSC_SELECTION_TIMEOUT 0x0A00 -#define I2O_SCSI_DSC_COMMAND_TIMEOUT 0x0B00 -#define I2O_SCSI_DSC_MR_MESSAGE_RECEIVED 0x0D00 -#define I2O_SCSI_DSC_SCSI_BUS_RESET 0x0E00 -#define I2O_SCSI_DSC_PARITY_ERROR_FAILURE 0x0F00 -#define I2O_SCSI_DSC_AUTOSENSE_FAILED 0x1000 -#define I2O_SCSI_DSC_NO_ADAPTER 0x1100 -#define I2O_SCSI_DSC_DATA_OVERRUN 0x1200 -#define I2O_SCSI_DSC_UNEXPECTED_BUS_FREE 0x1300 -#define I2O_SCSI_DSC_SEQUENCE_FAILURE 0x1400 -#define I2O_SCSI_DSC_REQUEST_LENGTH_ERROR 0x1500 -#define I2O_SCSI_DSC_PROVIDE_FAILURE 0x1600 -#define I2O_SCSI_DSC_BDR_MESSAGE_SENT 0x1700 -#define I2O_SCSI_DSC_REQUEST_TERMINATED 0x1800 -#define I2O_SCSI_DSC_IDE_MESSAGE_SENT 0x3300 -#define I2O_SCSI_DSC_RESOURCE_UNAVAILABLE 0x3400 -#define I2O_SCSI_DSC_UNACKNOWLEDGED_EVENT 0x3500 -#define I2O_SCSI_DSC_MESSAGE_RECEIVED 0x3600 -#define I2O_SCSI_DSC_INVALID_CDB 0x3700 -#define I2O_SCSI_DSC_LUN_INVALID 0x3800 -#define I2O_SCSI_DSC_SCSI_TID_INVALID 0x3900 -#define I2O_SCSI_DSC_FUNCTION_UNAVAILABLE 0x3A00 -#define I2O_SCSI_DSC_NO_NEXUS 0x3B00 -#define I2O_SCSI_DSC_SCSI_IID_INVALID 0x3C00 -#define I2O_SCSI_DSC_CDB_RECEIVED 0x3D00 -#define I2O_SCSI_DSC_LUN_ALREADY_ENABLED 0x3E00 -#define I2O_SCSI_DSC_BUS_BUSY 0x3F00 -#define I2O_SCSI_DSC_QUEUE_FROZEN 0x4000 - - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -#define HBA_FLAGS_INSTALLED_B 0x00000001 // Adapter Was Installed -#define HBA_FLAGS_BLINKLED_B 0x00000002 // Adapter In Blink LED State -#define HBA_FLAGS_IN_RESET 0x00000040 /* in reset */ -#define HBA_HOSTRESET_FAILED 0x00000080 /* adpt_resethost failed */ - - -// Device state flags -#define DPTI_DEV_ONLINE 0x00 -#define DPTI_DEV_UNSCANNED 0x01 -#define DPTI_DEV_RESET 0x02 -#define DPTI_DEV_OFFLINE 0x04 - - -struct adpt_device { - struct adpt_device* next_lun; - u32 flags; - u32 type; - u32 capacity; - u32 block_size; - u8 scsi_channel; - u8 scsi_id; - u8 scsi_lun; - u8 state; - u16 tid; - struct i2o_device* pI2o_dev; - struct scsi_device *pScsi_dev; -}; - -struct adpt_channel { - struct adpt_device* device[MAX_ID]; /* used as an array of 128 scsi ids */ - u8 scsi_id; - u8 type; - u16 tid; - u32 state; - struct i2o_device* pI2o_dev; -}; - -// HBA state flags -#define DPTI_STATE_RESET (0x01) -#define DPTI_STATE_IOCTL (0x02) - -typedef struct _adpt_hba { - struct _adpt_hba *next; - struct pci_dev *pDev; - struct Scsi_Host *host; - u32 state; - spinlock_t state_lock; - int unit; - int host_no; /* SCSI host number */ - u8 initialized; - u8 in_use; /* is the management node open*/ - - char name[32]; - char detail[55]; - - void __iomem *base_addr_virt; - void __iomem *msg_addr_virt; - ulong base_addr_phys; - void __iomem *post_port; - void __iomem *reply_port; - void __iomem *irq_mask; - u16 post_count; - u32 post_fifo_size; - u32 reply_fifo_size; - u32* reply_pool; - dma_addr_t reply_pool_pa; - u32 sg_tablesize; // Scatter/Gather List Size. - u8 top_scsi_channel; - u8 top_scsi_id; - u8 top_scsi_lun; - u8 dma64; - - i2o_status_block* status_block; - dma_addr_t status_block_pa; - i2o_hrt* hrt; - dma_addr_t hrt_pa; - i2o_lct* lct; - dma_addr_t lct_pa; - uint lct_size; - struct i2o_device* devices; - struct adpt_channel channel[MAX_CHANNEL]; - struct proc_dir_entry* proc_entry; /* /proc dir */ - - void __iomem *FwDebugBuffer_P; // Virtual Address Of FW Debug Buffer - u32 FwDebugBufferSize; // FW Debug Buffer Size In Bytes - void __iomem *FwDebugStrLength_P;// Virtual Addr Of FW Debug String Len - void __iomem *FwDebugFlags_P; // Virtual Address Of FW Debug Flags - void __iomem *FwDebugBLEDflag_P;// Virtual Addr Of FW Debug BLED - void __iomem *FwDebugBLEDvalue_P;// Virtual Addr Of FW Debug BLED - u32 FwDebugFlags; - u32 *ioctl_reply_context[4]; -} adpt_hba; - -struct sg_simple_element { - u32 flag_count; - u32 addr_bus; -}; - -/* - * Function Prototypes - */ - -static void adpt_i2o_sys_shutdown(void); -static int adpt_init(void); -static int adpt_i2o_build_sys_table(void); -static irqreturn_t adpt_isr(int irq, void *dev_id); - -static void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d); -static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid, - int group, int field, void *buf, int buflen); -#ifdef DEBUG -static const char *adpt_i2o_get_class_name(int class); -#endif -static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid, - void *opblk, dma_addr_t opblk_pa, int oplen, - void *resblk, dma_addr_t resblk_pa, int reslen); -static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout); -static int adpt_i2o_lct_get(adpt_hba* pHba); -static int adpt_i2o_parse_lct(adpt_hba* pHba); -static int adpt_i2o_activate_hba(adpt_hba* pHba); -static int adpt_i2o_enable_hba(adpt_hba* pHba); -static int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d); -static s32 adpt_i2o_post_this(adpt_hba* pHba, u32* data, int len); -static s32 adpt_i2o_quiesce_hba(adpt_hba* pHba); -static s32 adpt_i2o_status_get(adpt_hba* pHba); -static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba); -static s32 adpt_i2o_hrt_get(adpt_hba* pHba); -static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice); -static s32 adpt_i2o_to_scsi(void __iomem *reply, struct scsi_cmnd* cmd); -static s32 adpt_scsi_host_alloc(adpt_hba* pHba,struct scsi_host_template * sht); -static s32 adpt_hba_reset(adpt_hba* pHba); -static s32 adpt_i2o_reset_hba(adpt_hba* pHba); -static s32 adpt_rescan(adpt_hba* pHba); -static s32 adpt_i2o_reparse_lct(adpt_hba* pHba); -static s32 adpt_send_nop(adpt_hba*pHba,u32 m); -static void adpt_i2o_delete_hba(adpt_hba* pHba); -static void adpt_inquiry(adpt_hba* pHba); -static void adpt_fail_posted_scbs(adpt_hba* pHba); -static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun); -static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) ; -static int adpt_i2o_online_hba(adpt_hba* pHba); -static void adpt_i2o_post_wait_complete(u32, int); -static int adpt_i2o_systab_send(adpt_hba* pHba); - -static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg); -static int adpt_open(struct inode *inode, struct file *file); -static int adpt_close(struct inode *inode, struct file *file); - - -#ifdef UARTDELAY -static void adpt_delay(int millisec); -#endif - -#define PRINT_BUFFER_SIZE 512 - -#define HBA_FLAGS_DBG_FLAGS_MASK 0xffff0000 // Mask for debug flags -#define HBA_FLAGS_DBG_KERNEL_PRINT_B 0x00010000 // Kernel Debugger Print -#define HBA_FLAGS_DBG_FW_PRINT_B 0x00020000 // Firmware Debugger Print -#define HBA_FLAGS_DBG_FUNCTION_ENTRY_B 0x00040000 // Function Entry Point -#define HBA_FLAGS_DBG_FUNCTION_EXIT_B 0x00080000 // Function Exit -#define HBA_FLAGS_DBG_ERROR_B 0x00100000 // Error Conditions -#define HBA_FLAGS_DBG_INIT_B 0x00200000 // Init Prints -#define HBA_FLAGS_DBG_OS_COMMANDS_B 0x00400000 // OS Command Info -#define HBA_FLAGS_DBG_SCAN_B 0x00800000 // Device Scan - -#define FW_DEBUG_STR_LENGTH_OFFSET 0 -#define FW_DEBUG_FLAGS_OFFSET 4 -#define FW_DEBUG_BLED_OFFSET 8 - -#define FW_DEBUG_FLAGS_NO_HEADERS_B 0x01 -#endif /* !HOSTS_C */ -#endif /* _DPT_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/dtc.c b/ANDROID_3.4.5/drivers/scsi/dtc.c deleted file mode 100644 index 4b11bb04..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dtc.c +++ /dev/null @@ -1,485 +0,0 @@ - -#define AUTOSENSE -#define PSEUDO_DMA -#define DONT_USE_INTR -#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */ -#define xNDEBUG (NDEBUG_INTR+NDEBUG_RESELECTION+\ - NDEBUG_SELECTION+NDEBUG_ARBITRATION) -#define DMA_WORKS_RIGHT - - -/* - * DTC 3180/3280 driver, by - * Ray Van Tassle rayvt@comm.mot.com - * - * taken from ... - * Trantor T128/T128F/T228 driver by... - * - * Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * DISTRIBUTION RELEASE 1. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook -*/ - -/* - * Options : - * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. - * - * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance - * increase compared to polled I/O. - * - * PARITY - enable parity checking. Not supported. - * - * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. - * You probably want this. - * - * The card is detected and initialized in one of several ways : - * 1. Autoprobe (default) - since the board is memory mapped, - * a BIOS signature is scanned for to locate the registers. - * An interrupt is triggered to autoprobe for the interrupt - * line. - * - * 2. With command line overrides - dtc=address,irq may be - * used on the LILO command line to override the defaults. - * -*/ - -/*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at */ -/* 1 = blue - 2 = green - 3 = cyan - 4 = red - 5 = magenta - 6 = yellow - 7 = white -*/ -#if 0 -#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);} -#else -#define rtrc(i) {} -#endif - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "scsi.h" -#include -#include "dtc.h" -#define AUTOPROBE_IRQ -#include "NCR5380.h" - - -#define DTC_PUBLIC_RELEASE 2 - -/* - * The DTC3180 & 3280 boards are memory mapped. - * - */ - -/* - */ -/* Offset from DTC_5380_OFFSET */ -#define DTC_CONTROL_REG 0x100 /* rw */ -#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ -#define CSR_DIR_READ 0x40 /* rw direction, 1 = read 0 = write */ - -#define CSR_RESET 0x80 /* wo Resets 53c400 */ -#define CSR_5380_REG 0x80 /* ro 5380 registers can be accessed */ -#define CSR_TRANS_DIR 0x40 /* rw Data transfer direction */ -#define CSR_SCSI_BUFF_INTR 0x20 /* rw Enable int on transfer ready */ -#define CSR_5380_INTR 0x10 /* rw Enable 5380 interrupts */ -#define CSR_SHARED_INTR 0x08 /* rw Interrupt sharing */ -#define CSR_HOST_BUF_NOT_RDY 0x04 /* ro Host buffer not ready */ -#define CSR_SCSI_BUF_RDY 0x02 /* ro SCSI buffer ready */ -#define CSR_GATED_5380_IRQ 0x01 /* ro Last block xferred */ -#define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR) - - -#define DTC_BLK_CNT 0x101 /* rw - * # of 128-byte blocks to transfer */ - - -#define D_CR_ACCESS 0x80 /* ro set=can access 3280 registers */ - -#define DTC_SWITCH_REG 0x3982 /* ro - DIP switches */ -#define DTC_RESUME_XFER 0x3982 /* wo - resume data xfer - * after disconnect/reconnect*/ - -#define DTC_5380_OFFSET 0x3880 /* 8 registers here, see NCR5380.h */ - -/*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */ -#define DTC_DATA_BUF 0x3900 /* rw 128 bytes long */ - -static struct override { - unsigned int address; - int irq; -} overrides -#ifdef OVERRIDE -[] __initdata = OVERRIDE; -#else -[4] __initdata = { - { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO }, { 0, IRQ_AUTO } -}; -#endif - -#define NO_OVERRIDES ARRAY_SIZE(overrides) - -static struct base { - unsigned long address; - int noauto; -} bases[] __initdata = { - { 0xcc000, 0 }, - { 0xc8000, 0 }, - { 0xdc000, 0 }, - { 0xd8000, 0 } -}; - -#define NO_BASES ARRAY_SIZE(bases) - -static const struct signature { - const char *string; - int offset; -} signatures[] = { - {"DATA TECHNOLOGY CORPORATION BIOS", 0x25}, -}; - -#define NO_SIGNATURES ARRAY_SIZE(signatures) - -#ifndef MODULE -/* - * Function : dtc_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. - * - */ - -static void __init dtc_setup(char *str, int *ints) -{ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("dtc_setup: usage dtc=address,irq\n"); - else if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; - } -} -#endif - -/* - * Function : int dtc_detect(struct scsi_host_template * tpnt) - * - * Purpose : detects and initializes DTC 3180/3280 controllers - * that were autoprobed, overridden on the LILO command line, - * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * -*/ - -static int __init dtc_detect(struct scsi_host_template * tpnt) -{ - static int current_override = 0, current_base = 0; - struct Scsi_Host *instance; - unsigned int addr; - void __iomem *base; - int sig, count; - - tpnt->proc_name = "dtc3x80"; - tpnt->proc_info = &dtc_proc_info; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - addr = 0; - base = NULL; - - if (overrides[current_override].address) { - addr = overrides[current_override].address; - base = ioremap(addr, 0x2000); - if (!base) - addr = 0; - } else - for (; !addr && (current_base < NO_BASES); ++current_base) { -#if (DTCDEBUG & DTCDEBUG_INIT) - printk(KERN_DEBUG "scsi-dtc : probing address %08x\n", bases[current_base].address); -#endif - if (bases[current_base].noauto) - continue; - base = ioremap(bases[current_base].address, 0x2000); - if (!base) - continue; - for (sig = 0; sig < NO_SIGNATURES; ++sig) { - if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) { - addr = bases[current_base].address; -#if (DTCDEBUG & DTCDEBUG_INIT) - printk(KERN_DEBUG "scsi-dtc : detected board.\n"); -#endif - goto found; - } - } - iounmap(base); - } - -#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk(KERN_DEBUG "scsi-dtc : base = %08x\n", addr); -#endif - - if (!addr) - break; - -found: - instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); - if (instance == NULL) - break; - - instance->base = addr; - ((struct NCR5380_hostdata *)(instance)->hostdata)->base = base; - - NCR5380_init(instance, 0); - - NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); /* Enable int's */ - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, DTC_IRQS); - -#ifndef DONT_USE_INTR - /* With interrupts enabled, it will sometimes hang when doing heavy - * reads. So better not enable them until I finger it out. */ - if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, dtc_intr, IRQF_DISABLED, - "dtc", instance)) { - printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); - instance->irq = SCSI_IRQ_NONE; - } - - if (instance->irq == SCSI_IRQ_NONE) { - printk(KERN_WARNING "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk(KERN_WARNING "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } -#else - if (instance->irq != SCSI_IRQ_NONE) - printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no); - instance->irq = SCSI_IRQ_NONE; -#endif -#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base); - if (instance->irq == SCSI_IRQ_NONE) - printk(" interrupts disabled"); - else - printk(" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; -} - -/* - * Function : int dtc_biosparam(Disk * disk, struct block_device *dev, int *ip) - * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for - * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * -*/ - -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. -*/ - -static int dtc_biosparam(struct scsi_device *sdev, struct block_device *dev, - sector_t capacity, int *ip) -{ - int size = capacity; - - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; - return 0; -} - - -/**************************************************************** - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. -*/ - -static int dtc_maxi = 0; -static int dtc_wmaxi = 0; - -static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) -{ - unsigned char *d = dst; - int i; /* For counting time spent in the poll-loop */ - NCR5380_local_declare(); - NCR5380_setup(instance); - - i = 0; - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); - if (instance->irq == SCSI_IRQ_NONE) - NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ); - else - NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE); - NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ - rtrc(1); - while (len > 0) { - rtrc(2); - while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) - ++i; - rtrc(3); - memcpy_fromio(d, base + DTC_DATA_BUF, 128); - d += 128; - len -= 128; - rtrc(7); - /*** with int's on, it sometimes hangs after here. - * Looks like something makes HBNR go away. */ - } - rtrc(4); - while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) - ++i; - NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ - rtrc(0); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - if (i > dtc_maxi) - dtc_maxi = i; - return (0); -} - -/**************************************************************** - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) - * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. -*/ - -static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) -{ - int i; - NCR5380_local_declare(); - NCR5380_setup(instance); - - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE); - /* set direction (write) */ - if (instance->irq == SCSI_IRQ_NONE) - NCR5380_write(DTC_CONTROL_REG, 0); - else - NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR); - NCR5380_write(DTC_BLK_CNT, len >> 7); /* Block count */ - for (i = 0; len > 0; ++i) { - rtrc(5); - /* Poll until the host buffer can accept data. */ - while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY) - ++i; - rtrc(3); - memcpy_toio(base + DTC_DATA_BUF, src, 128); - src += 128; - len -= 128; - } - rtrc(4); - while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS)) - ++i; - rtrc(6); - /* Wait until the last byte has been sent to the disk */ - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) - ++i; - rtrc(7); - /* Check for parity error here. fixme. */ - NCR5380_write(MODE_REG, 0); /* Clear the operating mode */ - rtrc(0); - if (i > dtc_wmaxi) - dtc_wmaxi = i; - return (0); -} - -MODULE_LICENSE("GPL"); - -#include "NCR5380.c" - -static int dtc_release(struct Scsi_Host *shost) -{ - NCR5380_local_declare(); - NCR5380_setup(shost); - if (shost->irq) - free_irq(shost->irq, shost); - NCR5380_exit(shost); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - iounmap(base); - return 0; -} - -static struct scsi_host_template driver_template = { - .name = "DTC 3180/3280 ", - .detect = dtc_detect, - .release = dtc_release, - .queuecommand = dtc_queue_command, - .eh_abort_handler = dtc_abort, - .eh_bus_reset_handler = dtc_bus_reset, - .bios_param = dtc_biosparam, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/dtc.h b/ANDROID_3.4.5/drivers/scsi/dtc.h deleted file mode 100644 index cdc62120..00000000 --- a/ANDROID_3.4.5/drivers/scsi/dtc.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * DTC controller, taken from T128 driver by... - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * DISTRIBUTION RELEASE 2. - * - * For more information, please consult - * - * - * - * and - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -#ifndef DTC3280_H -#define DTC3280_H - -#define DTCDEBUG 0 -#define DTCDEBUG_INIT 0x1 -#define DTCDEBUG_TRANSFER 0x2 - -static int dtc_abort(Scsi_Cmnd *); -static int dtc_biosparam(struct scsi_device *, struct block_device *, - sector_t, int*); -static int dtc_detect(struct scsi_host_template *); -static int dtc_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static int dtc_bus_reset(Scsi_Cmnd *); - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 32 -#endif - -#define NCR5380_implementation_fields \ - void __iomem *base - -#define NCR5380_local_declare() \ - void __iomem *base - -#define NCR5380_setup(instance) \ - base = ((struct NCR5380_hostdata *)(instance)->hostdata)->base - -#define DTC_address(reg) (base + DTC_5380_OFFSET + reg) - -#define dbNCR5380_read(reg) \ - (rval=readb(DTC_address(reg)), \ - (((unsigned char) printk("DTC : read register %d at addr %p is: %02x\n"\ - , (reg), DTC_address(reg), rval)), rval ) ) - -#define dbNCR5380_write(reg, value) do { \ - printk("DTC : write %02x to register %d at address %p\n", \ - (value), (reg), DTC_address(reg)); \ - writeb(value, DTC_address(reg));} while(0) - - -#if !(DTCDEBUG & DTCDEBUG_TRANSFER) -#define NCR5380_read(reg) (readb(DTC_address(reg))) -#define NCR5380_write(reg, value) (writeb(value, DTC_address(reg))) -#else -#define NCR5380_read(reg) (readb(DTC_address(reg))) -#define xNCR5380_read(reg) \ - (((unsigned char) printk("DTC : read register %d at address %p\n"\ - , (reg), DTC_address(reg))), readb(DTC_address(reg))) - -#define NCR5380_write(reg, value) do { \ - printk("DTC : write %02x to register %d at address %p\n", \ - (value), (reg), DTC_address(reg)); \ - writeb(value, DTC_address(reg));} while(0) -#endif - -#define NCR5380_intr dtc_intr -#define NCR5380_queue_command dtc_queue_command -#define NCR5380_abort dtc_abort -#define NCR5380_bus_reset dtc_bus_reset -#define NCR5380_proc_info dtc_proc_info - -/* 15 12 11 10 - 1001 1100 0000 0000 */ - -#define DTC_IRQS 0x9c00 - - -#endif /* DTC3280_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/eata.c b/ANDROID_3.4.5/drivers/scsi/eata.c deleted file mode 100644 index 94de8895..00000000 --- a/ANDROID_3.4.5/drivers/scsi/eata.c +++ /dev/null @@ -1,2590 +0,0 @@ -/* - * eata.c - Low-level driver for EATA/DMA SCSI host adapters. - * - * 03 Jun 2003 Rev. 8.10 for linux-2.5.70 - * + Update for new IRQ API. - * + Use "goto" when appropriate. - * + Drop eata.h. - * + Update for new module_param API. - * + Module parameters can now be specified only in the - * same format as the kernel boot options. - * - * boot option old module param - * ----------- ------------------ - * addr,... io_port=addr,... - * lc:[y|n] linked_comm=[1|0] - * mq:xx max_queue_depth=xx - * tm:[0|1|2] tag_mode=[0|1|2] - * et:[y|n] ext_tran=[1|0] - * rs:[y|n] rev_scan=[1|0] - * ip:[y|n] isa_probe=[1|0] - * ep:[y|n] eisa_probe=[1|0] - * pp:[y|n] pci_probe=[1|0] - * - * A valid example using the new parameter format is: - * modprobe eata "eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n" - * - * which is equivalent to the old format: - * modprobe eata io_port=0x7410,0x230 linked_comm=1 tag_mode=0 \ - * max_queue_depth=4 eisa_probe=0 - * - * 12 Feb 2003 Rev. 8.04 for linux 2.5.60 - * + Release irq before calling scsi_register. - * - * 12 Nov 2002 Rev. 8.02 for linux 2.5.47 - * + Release driver_lock before calling scsi_register. - * - * 11 Nov 2002 Rev. 8.01 for linux 2.5.47 - * + Fixed bios_param and scsicam_bios_param calling parameters. - * - * 28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4 - * + Use new tcq and adjust_queue_depth api. - * + New command line option (tm:[0-2]) to choose the type of tags: - * 0 -> disable tagging ; 1 -> simple tags ; 2 -> ordered tags. - * Default is tm:0 (tagged commands disabled). - * For compatibility the "tc:" option is an alias of the "tm:" - * option; tc:n is equivalent to tm:0 and tc:y is equivalent to - * tm:1. - * + The tagged_comm module parameter has been removed, use tag_mode - * instead, equivalent to the "tm:" boot option. - * - * 10 Oct 2002 Rev. 7.70 for linux 2.5.42 - * + Foreport from revision 6.70. - * - * 25 Jun 2002 Rev. 6.70 for linux 2.4.19 - * + This release is the first one tested on a Big Endian platform: - * fixed endian-ness problem due to bitfields; - * fixed endian-ness problem in read_pio. - * + Added new options for selectively probing ISA, EISA and PCI bus: - * - * Boot option Parameter name Default according to - * - * ip:[y|n] isa_probe=[1|0] CONFIG_ISA defined - * ep:[y|n] eisa_probe=[1|0] CONFIG_EISA defined - * pp:[y|n] pci_probe=[1|0] CONFIG_PCI defined - * - * The default action is to perform probing if the corresponding - * bus is configured and to skip probing otherwise. - * - * + If pci_probe is in effect and a list of I/O ports is specified - * as parameter or boot option, pci_enable_device() is performed - * on all pci devices matching PCI_CLASS_STORAGE_SCSI. - * - * 21 Feb 2002 Rev. 6.52 for linux 2.4.18 - * + Backport from rev. 7.22 (use io_request_lock). - * - * 20 Feb 2002 Rev. 7.22 for linux 2.5.5 - * + Remove any reference to virt_to_bus(). - * + Fix pio hang while detecting multiple HBAs. - * + Fixed a board detection bug: in a system with - * multiple ISA/EISA boards, all but the first one - * were erroneously detected as PCI. - * - * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 - * + Use the dynamic DMA mapping API. - * - * 19 Dec 2001 Rev. 7.02 for linux 2.5.1 - * + Use SCpnt->sc_data_direction if set. - * + Use sglist.page instead of sglist.address. - * - * 11 Dec 2001 Rev. 7.00 for linux 2.5.1 - * + Use host->host_lock instead of io_request_lock. - * - * 1 May 2001 Rev. 6.05 for linux 2.4.4 - * + Clean up all pci related routines. - * + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d) - * - * 30 Jan 2001 Rev. 6.04 for linux 2.4.1 - * + Call pci_resource_start after pci_enable_device. - * - * 25 Jan 2001 Rev. 6.03 for linux 2.4.0 - * + "check_region" call replaced by "request_region". - * - * 22 Nov 2000 Rev. 6.02 for linux 2.4.0-test11 - * + Return code checked when calling pci_enable_device. - * + Removed old scsi error handling support. - * + The obsolete boot option flag eh:n is silently ignored. - * + Removed error messages while a disk drive is powered up at - * boot time. - * + Improved boot messages: all tagged capable device are - * indicated as "tagged" or "soft-tagged" : - * - "soft-tagged" means that the driver is trying to do its - * own tagging (i.e. the tc:y option is in effect); - * - "tagged" means that the device supports tagged commands, - * but the driver lets the HBA be responsible for tagging - * support. - * - * 16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18 - * + Updated to the new __setup interface for boot command line options. - * + When loaded as a module, accepts the new parameter boot_options - * which value is a string with the same format of the kernel boot - * command line options. A valid example is: - * modprobe eata 'boot_options="0x7410,0x230,lc:y,tc:n,mq:4"' - * - * 9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17 - * + 64bit cleanup for Linux/Alpha platform support - * (contribution from H.J. Lu). - * - * 22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11 - * + Removed pre-2.2 source code compatibility. - * + Added call to pci_set_master. - * - * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111 - * + Added command line option (rs:[y|n]) to reverse the scan order - * of PCI boards. The default is rs:y, which reverses the BIOS order - * while registering PCI boards. The default value rs:y generates - * the same order of all previous revisions of this driver. - * Pls. note that "BIOS order" might have been reversed itself - * after the 2.1.9x PCI modifications in the linux kernel. - * The rs value is ignored when the explicit list of addresses - * is used by the "eata=port0,port1,..." command line option. - * + Added command line option (et:[y|n]) to force use of extended - * translation (255 heads, 63 sectors) as disk geometry. - * The default is et:n, which uses the disk geometry returned - * by scsicam_bios_param. The default value et:n is compatible with - * all previous revisions of this driver. - * - * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104 - * Increased busy timeout from 10 msec. to 200 msec. while - * processing interrupts. - * - * 16 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102 - * Improved abort handling during the eh recovery process. - * - * 13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101 - * The driver is now fully SMP safe, including the - * abort and reset routines. - * Added command line options (eh:[y|n]) to choose between - * new_eh_code and the old scsi code. - * If linux version >= 2.1.101 the default is eh:y, while the eh - * option is ignored for previous releases and the old scsi code - * is used. - * - * 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97 - * Reworked interrupt handler. - * - * 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95 - * Major reliability improvement: when a batch with overlapping - * requests is detected, requests are queued one at a time - * eliminating any possible board or drive reordering. - * - * 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95 - * Improved SMP support (if linux version >= 2.1.95). - * - * 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94 - * Added support for new PCI code and IO-APIC remapping of irqs. - * Performance improvement: when sequential i/o is detected, - * always use direct sort instead of reverse sort. - * - * 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92 - * io_port is now unsigned long. - * - * 17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88 - * Use new scsi error handling code (if linux version >= 2.1.88). - * Use new interrupt code. - * - * 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55 - * Use of udelay inside the wait loops to avoid timeout - * problems with fast cpus. - * Removed check about useless calls to the interrupt service - * routine (reported on SMP systems only). - * At initialization time "sorted/unsorted" is displayed instead - * of "linked/unlinked" to reinforce the fact that "linking" is - * nothing but "elevator sorting" in the actual implementation. - * - * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38 - * Use of serial_number_at_timeout in abort and reset processing. - * Use of the __initfunc and __initdata macro in setup code. - * Minor cleanups in the list_statistics code. - * Increased controller busy timeout in order to better support - * slow SCSI devices. - * - * 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26 - * When loading as a module, parameter passing is now supported - * both in 2.0 and in 2.1 style. - * Fixed data transfer direction for some SCSI opcodes. - * Immediate acknowledge to request sense commands. - * Linked commands to each disk device are now reordered by elevator - * sorting. Rare cases in which reordering of write requests could - * cause wrong results are managed. - * Fixed spurious timeouts caused by long simple queue tag sequences. - * New command line option (tm:[0-3]) to choose the type of tags: - * 0 -> mixed (default); 1 -> simple; 2 -> head; 3 -> ordered. - * - * 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28 - * Added command line options to enable/disable linked commands - * (lc:[y|n]), tagged commands (tc:[y|n]) and to set the max queue - * depth (mq:xx). Default is "eata=lc:n,tc:n,mq:16". - * Improved command linking. - * Documented how to setup RAID-0 with DPT SmartRAID boards. - * - * 8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27 - * Added linked command support. - * Improved detection of PCI boards using ISA base addresses. - * - * 3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27 - * Added support for tagged commands and queue depth adjustment. - * - * 22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26 - * When CONFIG_PCI is defined, BIOS32 is used to include in the - * list of i/o ports to be probed all the PCI SCSI controllers. - * The list of i/o ports to be probed can be overwritten by the - * "eata=port0,port1,...." boot command line option. - * Scatter/gather lists are now allocated by a number of kmalloc - * calls, in order to avoid the previous size limit of 64Kb. - * - * 16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25 - * Added support for EATA 2.0C, PCI, multichannel and wide SCSI. - * - * 27 Sep 1996 rev. 2.12 for linux 2.1.0 - * Portability cleanups (virtual/bus addressing, little/big endian - * support). - * - * 09 Jul 1996 rev. 2.11 for linux 2.0.4 - * Number of internal retries is now limited. - * - * 16 Apr 1996 rev. 2.10 for linux 1.3.90 - * New argument "reset_flags" to the reset routine. - * - * 6 Jul 1995 rev. 2.01 for linux 1.3.7 - * Update required by the new /proc/scsi support. - * - * 11 Mar 1995 rev. 2.00 for linux 1.2.0 - * Fixed a bug which prevented media change detection for removable - * disk drives. - * - * 23 Feb 1995 rev. 1.18 for linux 1.1.94 - * Added a check for scsi_register returning NULL. - * - * 11 Feb 1995 rev. 1.17 for linux 1.1.91 - * Now DEBUG_RESET is disabled by default. - * Register a board even if it does not assert DMA protocol support - * (DPT SK2011B does not report correctly the dmasup bit). - * - * 9 Feb 1995 rev. 1.16 for linux 1.1.90 - * Use host->wish_block instead of host->block. - * New list of Data Out SCSI commands. - * - * 8 Feb 1995 rev. 1.15 for linux 1.1.89 - * Cleared target_time_out counter while performing a reset. - * All external symbols renamed to avoid possible name conflicts. - * - * 28 Jan 1995 rev. 1.14 for linux 1.1.86 - * Added module support. - * Log and do a retry when a disk drive returns a target status - * different from zero on a recovered error. - * - * 24 Jan 1995 rev. 1.13 for linux 1.1.85 - * Use optimized board configuration, with a measured performance - * increase in the range 10%-20% on i/o throughput. - * - * 16 Jan 1995 rev. 1.12 for linux 1.1.81 - * Fix mscp structure comments (no functional change). - * Display a message if check_region detects a port address - * already in use. - * - * 17 Dec 1994 rev. 1.11 for linux 1.1.74 - * Use the scsicam_bios_param routine. This allows an easy - * migration path from disk partition tables created using - * different SCSI drivers and non optimal disk geometry. - * - * 15 Dec 1994 rev. 1.10 for linux 1.1.74 - * Added support for ISA EATA boards (DPT PM2011, DPT PM2021). - * The host->block flag is set for all the detected ISA boards. - * The detect routine no longer enforces LEVEL triggering - * for EISA boards, it just prints a warning message. - * - * 30 Nov 1994 rev. 1.09 for linux 1.1.68 - * Redo i/o on target status CHECK_CONDITION for TYPE_DISK only. - * Added optional support for using a single board at a time. - * - * 18 Nov 1994 rev. 1.08 for linux 1.1.64 - * Forces sg_tablesize = 64 and can_queue = 64 if these - * values are not correctly detected (DPT PM2012). - * - * 14 Nov 1994 rev. 1.07 for linux 1.1.63 Final BETA release. - * 04 Aug 1994 rev. 1.00 for linux 1.1.39 First BETA release. - * - * - * This driver is based on the CAM (Common Access Method Committee) - * EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol. - * - * Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com) - * - * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that redistributions of source - * code retain the above copyright notice and this comment without - * modification. - * - */ - -/* - * - * Here is a brief description of the DPT SCSI host adapters. - * All these boards provide an EATA/DMA compatible programming interface - * and are fully supported by this driver in any configuration, including - * multiple SCSI channels: - * - * PM2011B/9X - Entry Level ISA - * PM2021A/9X - High Performance ISA - * PM2012A Old EISA - * PM2012B Old EISA - * PM2022A/9X - Entry Level EISA - * PM2122A/9X - High Performance EISA - * PM2322A/9X - Extra High Performance EISA - * PM3021 - SmartRAID Adapter for ISA - * PM3222 - SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI) - * PM3224 - SmartRAID Adapter for PCI (PM3224W is 16-bit wide SCSI) - * PM33340UW - SmartRAID Adapter for PCI ultra wide multichannel - * - * The above list is just an indication: as a matter of fact all DPT - * boards using the EATA/DMA protocol are supported by this driver, - * since they use exactely the same programming interface. - * - * The DPT PM2001 provides only the EATA/PIO interface and hence is not - * supported by this driver. - * - * This code has been tested with up to 3 Distributed Processing Technology - * PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers, - * in any combination of private and shared IRQ. - * PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS - * v003.D0, firmware v07G.0). - * - * DPT SmartRAID boards support "Hardware Array" - a group of disk drives - * which are all members of the same RAID-0, RAID-1 or RAID-5 array implemented - * in host adapter hardware. Hardware Arrays are fully compatible with this - * driver, since they look to it as a single disk drive. - * - * WARNING: to create a RAID-0 "Hardware Array" you must select "Other Unix" - * as the current OS in the DPTMGR "Initial System Installation" menu. - * Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0), - * which is not supported by the actual SCSI subsystem. - * To get the "Array Group" functionality, the Linux MD driver must be used - * instead of the DPT "Array Group" feature. - * - * Multiple ISA, EISA and PCI boards can be configured in the same system. - * It is suggested to put all the EISA boards on the same IRQ level, all - * the PCI boards on another IRQ level, while ISA boards cannot share - * interrupts. - * - * If you configure multiple boards on the same IRQ, the interrupt must - * be _level_ triggered (not _edge_ triggered). - * - * This driver detects EATA boards by probes at fixed port addresses, - * so no BIOS32 or PCI BIOS support is required. - * The suggested way to detect a generic EATA PCI board is to force on it - * any unused EISA address, even if there are other controllers on the EISA - * bus, or even if you system has no EISA bus at all. - * Do not force any ISA address on EATA PCI boards. - * - * If PCI bios support is configured into the kernel, BIOS32 is used to - * include in the list of i/o ports to be probed all the PCI SCSI controllers. - * - * Due to a DPT BIOS "feature", it might not be possible to force an EISA - * address on more than a single DPT PCI board, so in this case you have to - * let the PCI BIOS assign the addresses. - * - * The sequence of detection probes is: - * - * - ISA 0x1F0; - * - PCI SCSI controllers (only if BIOS32 is available); - * - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15); - * - ISA 0x170, 0x230, 0x330. - * - * The above list of detection probes can be totally replaced by the - * boot command line option: "eata=port0,port1,port2,...", where the - * port0, port1... arguments are ISA/EISA/PCI addresses to be probed. - * For example using "eata=0x7410,0x7450,0x230", the driver probes - * only the two PCI addresses 0x7410 and 0x7450 and the ISA address 0x230, - * in this order; "eata=0" totally disables this driver. - * - * After the optional list of detection probes, other possible command line - * options are: - * - * et:y force use of extended translation (255 heads, 63 sectors); - * et:n use disk geometry detected by scsicam_bios_param; - * rs:y reverse scan order while detecting PCI boards; - * rs:n use BIOS order while detecting PCI boards; - * lc:y enables linked commands; - * lc:n disables linked commands; - * tm:0 disables tagged commands (same as tc:n); - * tm:1 use simple queue tags (same as tc:y); - * tm:2 use ordered queue tags (same as tc:2); - * mq:xx set the max queue depth to the value xx (2 <= xx <= 32). - * - * The default value is: "eata=lc:n,mq:16,tm:0,et:n,rs:n". - * An example using the list of detection probes could be: - * "eata=0x7410,0x230,lc:y,tm:2,mq:4,et:n". - * - * When loading as a module, parameters can be specified as well. - * The above example would be (use 1 in place of y and 0 in place of n): - * - * modprobe eata io_port=0x7410,0x230 linked_comm=1 \ - * max_queue_depth=4 ext_tran=0 tag_mode=2 \ - * rev_scan=1 - * - * ---------------------------------------------------------------------------- - * In this implementation, linked commands are designed to work with any DISK - * or CD-ROM, since this linking has only the intent of clustering (time-wise) - * and reordering by elevator sorting commands directed to each device, - * without any relation with the actual SCSI protocol between the controller - * and the device. - * If Q is the queue depth reported at boot time for each device (also named - * cmds/lun) and Q > 2, whenever there is already an active command to the - * device all other commands to the same device (up to Q-1) are kept waiting - * in the elevator sorting queue. When the active command completes, the - * commands in this queue are sorted by sector address. The sort is chosen - * between increasing or decreasing by minimizing the seek distance between - * the sector of the commands just completed and the sector of the first - * command in the list to be sorted. - * Trivial math assures that the unsorted average seek distance when doing - * random seeks over S sectors is S/3. - * When (Q-1) requests are uniformly distributed over S sectors, the average - * distance between two adjacent requests is S/((Q-1) + 1), so the sorted - * average seek distance for (Q-1) random requests over S sectors is S/Q. - * The elevator sorting hence divides the seek distance by a factor Q/3. - * The above pure geometric remarks are valid in all cases and the - * driver effectively reduces the seek distance by the predicted factor - * when there are Q concurrent read i/o operations on the device, but this - * does not necessarily results in a noticeable performance improvement: - * your mileage may vary.... - * - * Note: command reordering inside a batch of queued commands could cause - * wrong results only if there is at least one write request and the - * intersection (sector-wise) of all requests is not empty. - * When the driver detects a batch including overlapping requests - * (a really rare event) strict serial (pid) order is enforced. - * ---------------------------------------------------------------------------- - * The extended translation option (et:y) is useful when using large physical - * disks/arrays. It could also be useful when switching between Adaptec boards - * and DPT boards without reformatting the disk. - * When a boot disk is partitioned with extended translation, in order to - * be able to boot it with a DPT board is could be necessary to add to - * lilo.conf additional commands as in the following example: - * - * fix-table - * disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546 - * - * where the above geometry should be replaced with the one reported at - * power up by the DPT controller. - * ---------------------------------------------------------------------------- - * - * The boards are named EATA0, EATA1,... according to the detection order. - * - * In order to support multiple ISA boards in a reliable way, - * the driver sets host->wish_block = 1 for all ISA boards. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static int eata2x_detect(struct scsi_host_template *); -static int eata2x_release(struct Scsi_Host *); -static int eata2x_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static int eata2x_eh_abort(struct scsi_cmnd *); -static int eata2x_eh_host_reset(struct scsi_cmnd *); -static int eata2x_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static int eata2x_slave_configure(struct scsi_device *); - -static struct scsi_host_template driver_template = { - .name = "EATA/DMA 2.0x rev. 8.10.00 ", - .detect = eata2x_detect, - .release = eata2x_release, - .queuecommand = eata2x_queuecommand, - .eh_abort_handler = eata2x_eh_abort, - .eh_host_reset_handler = eata2x_eh_host_reset, - .bios_param = eata2x_bios_param, - .slave_configure = eata2x_slave_configure, - .this_id = 7, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) -#error "Adjust your defines" -#endif - -/* Subversion values */ -#define ISA 0 -#define ESA 1 - -#undef FORCE_CONFIG - -#undef DEBUG_LINKED_COMMANDS -#undef DEBUG_DETECT -#undef DEBUG_PCI_DETECT -#undef DEBUG_INTERRUPT -#undef DEBUG_RESET -#undef DEBUG_GENERATE_ERRORS -#undef DEBUG_GENERATE_ABORTS -#undef DEBUG_GEOMETRY - -#define MAX_ISA 4 -#define MAX_VESA 0 -#define MAX_EISA 15 -#define MAX_PCI 16 -#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI) -#define MAX_CHANNEL 4 -#define MAX_LUN 32 -#define MAX_TARGET 32 -#define MAX_MAILBOXES 64 -#define MAX_SGLIST 64 -#define MAX_LARGE_SGLIST 122 -#define MAX_INTERNAL_RETRIES 64 -#define MAX_CMD_PER_LUN 2 -#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN) - -#define SKIP ULONG_MAX -#define FREE 0 -#define IN_USE 1 -#define LOCKED 2 -#define IN_RESET 3 -#define IGNORE 4 -#define READY 5 -#define ABORTING 6 -#define NO_DMA 0xff -#define MAXLOOP 10000 -#define TAG_DISABLED 0 -#define TAG_SIMPLE 1 -#define TAG_ORDERED 2 - -#define REG_CMD 7 -#define REG_STATUS 7 -#define REG_AUX_STATUS 8 -#define REG_DATA 0 -#define REG_DATA2 1 -#define REG_SEE 6 -#define REG_LOW 2 -#define REG_LM 3 -#define REG_MID 4 -#define REG_MSB 5 -#define REGION_SIZE 9UL -#define MAX_ISA_ADDR 0x03ff -#define MIN_EISA_ADDR 0x1c88 -#define MAX_EISA_ADDR 0xfc88 -#define BSY_ASSERTED 0x80 -#define DRQ_ASSERTED 0x08 -#define ABSY_ASSERTED 0x01 -#define IRQ_ASSERTED 0x02 -#define READ_CONFIG_PIO 0xf0 -#define SET_CONFIG_PIO 0xf1 -#define SEND_CP_PIO 0xf2 -#define RECEIVE_SP_PIO 0xf3 -#define TRUNCATE_XFR_PIO 0xf4 -#define RESET_PIO 0xf9 -#define READ_CONFIG_DMA 0xfd -#define SET_CONFIG_DMA 0xfe -#define SEND_CP_DMA 0xff -#define ASOK 0x00 -#define ASST 0x01 - -#define YESNO(a) ((a) ? 'y' : 'n') -#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM) - -/* "EATA", in Big Endian format */ -#define EATA_SIG_BE 0x45415441 - -/* Number of valid bytes in the board config structure for EATA 2.0x */ -#define EATA_2_0A_SIZE 28 -#define EATA_2_0B_SIZE 30 -#define EATA_2_0C_SIZE 34 - -/* Board info structure */ -struct eata_info { - u_int32_t data_len; /* Number of valid bytes after this field */ - u_int32_t sign; /* ASCII "EATA" signature */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar version : 4, - : 4; - unchar haaval : 1, - ata : 1, - drqvld : 1, - dmasup : 1, - morsup : 1, - trnxfr : 1, - tarsup : 1, - ocsena : 1; -#else - unchar : 4, /* unused low nibble */ - version : 4; /* EATA version, should be 0x1 */ - unchar ocsena : 1, /* Overlap Command Support Enabled */ - tarsup : 1, /* Target Mode Supported */ - trnxfr : 1, /* Truncate Transfer Cmd NOT Necessary */ - morsup : 1, /* More Supported */ - dmasup : 1, /* DMA Supported */ - drqvld : 1, /* DRQ Index (DRQX) is valid */ - ata : 1, /* This is an ATA device */ - haaval : 1; /* Host Adapter Address Valid */ -#endif - - ushort cp_pad_len; /* Number of pad bytes after cp_len */ - unchar host_addr[4]; /* Host Adapter SCSI ID for channels 3, 2, 1, 0 */ - u_int32_t cp_len; /* Number of valid bytes in cp */ - u_int32_t sp_len; /* Number of valid bytes in sp */ - ushort queue_size; /* Max number of cp that can be queued */ - ushort unused; - ushort scatt_size; /* Max number of entries in scatter/gather table */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar drqx : 2, - second : 1, - irq_tr : 1, - irq : 4; - unchar sync; - unchar : 4, - res1 : 1, - large_sg : 1, - forcaddr : 1, - isaena : 1; - unchar max_chan : 3, - max_id : 5; - unchar max_lun; - unchar eisa : 1, - pci : 1, - idquest : 1, - m1 : 1, - : 4; -#else - unchar irq : 4, /* Interrupt Request assigned to this controller */ - irq_tr : 1, /* 0 for edge triggered, 1 for level triggered */ - second : 1, /* 1 if this is a secondary (not primary) controller */ - drqx : 2; /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */ - unchar sync; /* 1 if scsi target id 7...0 is running sync scsi */ - - /* Structure extension defined in EATA 2.0B */ - unchar isaena : 1, /* ISA i/o addressing is disabled/enabled */ - forcaddr : 1, /* Port address has been forced */ - large_sg : 1, /* 1 if large SG lists are supported */ - res1 : 1, - : 4; - unchar max_id : 5, /* Max SCSI target ID number */ - max_chan : 3; /* Max SCSI channel number on this board */ - - /* Structure extension defined in EATA 2.0C */ - unchar max_lun; /* Max SCSI LUN number */ - unchar - : 4, - m1 : 1, /* This is a PCI with an M1 chip installed */ - idquest : 1, /* RAIDNUM returned is questionable */ - pci : 1, /* This board is PCI */ - eisa : 1; /* This board is EISA */ -#endif - - unchar raidnum; /* Uniquely identifies this HBA in a system */ - unchar notused; - - ushort ipad[247]; -}; - -/* Board config structure */ -struct eata_config { - ushort len; /* Number of bytes following this field */ - -#if defined(__BIG_ENDIAN_BITFIELD) - unchar : 4, - tarena : 1, - mdpena : 1, - ocena : 1, - edis : 1; -#else - unchar edis : 1, /* Disable EATA interface after config command */ - ocena : 1, /* Overlapped Commands Enabled */ - mdpena : 1, /* Transfer all Modified Data Pointer Messages */ - tarena : 1, /* Target Mode Enabled for this controller */ - : 4; -#endif - unchar cpad[511]; -}; - -/* Returned status packet structure */ -struct mssp { -#if defined(__BIG_ENDIAN_BITFIELD) - unchar eoc : 1, - adapter_status : 7; -#else - unchar adapter_status : 7, /* State related to current command */ - eoc : 1; /* End Of Command (1 = command completed) */ -#endif - unchar target_status; /* SCSI status received after data transfer */ - unchar unused[2]; - u_int32_t inv_res_len; /* Number of bytes not transferred */ - u_int32_t cpp_index; /* Index of address set in cp */ - char mess[12]; -}; - -struct sg_list { - unsigned int address; /* Segment Address */ - unsigned int num_bytes; /* Segment Length */ -}; - -/* MailBox SCSI Command Packet */ -struct mscp { -#if defined(__BIG_ENDIAN_BITFIELD) - unchar din : 1, - dout : 1, - interp : 1, - : 1, - sg : 1, - reqsen :1, - init : 1, - sreset : 1; - unchar sense_len; - unchar unused[3]; - unchar : 7, - fwnest : 1; - unchar : 5, - hbaci : 1, - iat : 1, - phsunit : 1; - unchar channel : 3, - target : 5; - unchar one : 1, - dispri : 1, - luntar : 1, - lun : 5; -#else - unchar sreset :1, /* SCSI Bus Reset Signal should be asserted */ - init :1, /* Re-initialize controller and self test */ - reqsen :1, /* Transfer Request Sense Data to addr using DMA */ - sg :1, /* Use Scatter/Gather */ - :1, - interp :1, /* The controller interprets cp, not the target */ - dout :1, /* Direction of Transfer is Out (Host to Target) */ - din :1; /* Direction of Transfer is In (Target to Host) */ - unchar sense_len; /* Request Sense Length */ - unchar unused[3]; - unchar fwnest : 1, /* Send command to a component of an Array Group */ - : 7; - unchar phsunit : 1, /* Send to Target Physical Unit (bypass RAID) */ - iat : 1, /* Inhibit Address Translation */ - hbaci : 1, /* Inhibit HBA Caching for this command */ - : 5; - unchar target : 5, /* SCSI target ID */ - channel : 3; /* SCSI channel number */ - unchar lun : 5, /* SCSI logical unit number */ - luntar : 1, /* This cp is for Target (not LUN) */ - dispri : 1, /* Disconnect Privilege granted */ - one : 1; /* 1 */ -#endif - - unchar mess[3]; /* Massage to/from Target */ - unchar cdb[12]; /* Command Descriptor Block */ - u_int32_t data_len; /* If sg=0 Data Length, if sg=1 sglist length */ - u_int32_t cpp_index; /* Index of address to be returned in sp */ - u_int32_t data_address; /* If sg=0 Data Address, if sg=1 sglist address */ - u_int32_t sp_dma_addr; /* Address where sp is DMA'ed when cp completes */ - u_int32_t sense_addr; /* Address where Sense Data is DMA'ed on error */ - - /* Additional fields begin here. */ - struct scsi_cmnd *SCpnt; - - /* All the cp structure is zero filled by queuecommand except the - following CP_TAIL_SIZE bytes, initialized by detect */ - dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ - struct sg_list *sglist; /* pointer to the allocated SG list */ -}; - -#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t)) - -struct hostdata { - struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ - unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ - unsigned int last_cp_used; /* Index of last mailbox used */ - unsigned int iocount; /* Total i/o done for this board */ - int board_number; /* Number of this board */ - char board_name[16]; /* Name of this board */ - int in_reset; /* True if board is doing a reset */ - int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ - int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If 1 redo i/o on target */ - unsigned int retries; /* Number of internal retries */ - unsigned long last_retried_pid; /* Pid of last retried command */ - unsigned char subversion; /* Bus type, either ISA or EISA/PCI */ - unsigned char protocol_rev; /* EATA 2.0 rev., 'A' or 'B' or 'C' */ - unsigned char is_pci; /* 1 is bus type is PCI */ - struct pci_dev *pdev; /* pdev for PCI bus, NULL otherwise */ - struct mssp *sp_cpu_addr; /* cpu addr for DMA buffer sp */ - dma_addr_t sp_dma_addr; /* dma handle for DMA buffer sp */ - struct mssp sp; /* Local copy of sp buffer */ -}; - -static struct Scsi_Host *sh[MAX_BOARDS]; -static const char *driver_name = "EATA"; -static char sha[MAX_BOARDS]; -static DEFINE_SPINLOCK(driver_lock); - -/* Initialize num_boards so that ihdlr can work while detect is in progress */ -static unsigned int num_boards = MAX_BOARDS; - -static unsigned long io_port[] = { - - /* Space for MAX_INT_PARAM ports usable while loading as a module */ - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - SKIP, SKIP, - - /* First ISA */ - 0x1f0, - - /* Space for MAX_PCI ports possibly reported by PCI_BIOS */ - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - - /* MAX_EISA ports */ - 0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88, - 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, - - /* Other (MAX_ISA - 1) ports */ - 0x170, 0x230, 0x330, - - /* End of list */ - 0x0 -}; - -/* Device is Big Endian */ -#define H2DEV(x) cpu_to_be32(x) -#define DEV2H(x) be32_to_cpu(x) -#define H2DEV16(x) cpu_to_be16(x) -#define DEV2H16(x) be16_to_cpu(x) - -/* But transfer orientation from the 16 bit data register is Little Endian */ -#define REG2H(x) le16_to_cpu(x) - -static irqreturn_t do_interrupt_handler(int, void *); -static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *, - unsigned int); -static int do_trace = 0; -static int setup_done = 0; -static int link_statistics; -static int ext_tran = 0; -static int rev_scan = 1; - -#if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE) -static int tag_mode = TAG_SIMPLE; -#else -static int tag_mode = TAG_DISABLED; -#endif - -#if defined(CONFIG_SCSI_EATA_LINKED_COMMANDS) -static int linked_comm = 1; -#else -static int linked_comm = 0; -#endif - -#if defined(CONFIG_SCSI_EATA_MAX_TAGS) -static int max_queue_depth = CONFIG_SCSI_EATA_MAX_TAGS; -#else -static int max_queue_depth = MAX_CMD_PER_LUN; -#endif - -#if defined(CONFIG_ISA) -static int isa_probe = 1; -#else -static int isa_probe = 0; -#endif - -#if defined(CONFIG_EISA) -static int eisa_probe = 1; -#else -static int eisa_probe = 0; -#endif - -#if defined(CONFIG_PCI) -static int pci_probe = 1; -#else -static int pci_probe = 0; -#endif - -#define MAX_INT_PARAM 10 -#define MAX_BOOT_OPTIONS_SIZE 256 -static char boot_options[MAX_BOOT_OPTIONS_SIZE]; - -#if defined(MODULE) -#include -#include - -module_param_string(eata, boot_options, MAX_BOOT_OPTIONS_SIZE, 0); -MODULE_PARM_DESC(eata, " equivalent to the \"eata=...\" kernel boot option." - " Example: modprobe eata \"eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n\""); -MODULE_AUTHOR("Dario Ballabio"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("EATA/DMA SCSI Driver"); - -#endif - -static int eata2x_slave_configure(struct scsi_device *dev) -{ - int tqd, utqd; - char *tag_suffix, *link_suffix; - - utqd = MAX_CMD_PER_LUN; - tqd = max_queue_depth; - - if (TLDEV(dev->type) && dev->tagged_supported) { - if (tag_mode == TAG_SIMPLE) { - scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); - tag_suffix = ", simple tags"; - } else if (tag_mode == TAG_ORDERED) { - scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd); - tag_suffix = ", ordered tags"; - } else { - scsi_adjust_queue_depth(dev, 0, tqd); - tag_suffix = ", no tags"; - } - } else if (TLDEV(dev->type) && linked_comm) { - scsi_adjust_queue_depth(dev, 0, tqd); - tag_suffix = ", untagged"; - } else { - scsi_adjust_queue_depth(dev, 0, utqd); - tag_suffix = ""; - } - - if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2) - link_suffix = ", sorted"; - else if (TLDEV(dev->type)) - link_suffix = ", unsorted"; - else - link_suffix = ""; - - sdev_printk(KERN_INFO, dev, - "cmds/lun %d%s%s.\n", - dev->queue_depth, link_suffix, tag_suffix); - - return 0; -} - -static int wait_on_busy(unsigned long iobase, unsigned int loop) -{ - while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) { - udelay(1L); - if (--loop == 0) - return 1; - } - return 0; -} - -static int do_dma(unsigned long iobase, unsigned long addr, unchar cmd) -{ - unsigned char *byaddr; - unsigned long devaddr; - - if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP))) - return 1; - - if (addr) { - devaddr = H2DEV(addr); - byaddr = (unsigned char *)&devaddr; - outb(byaddr[3], iobase + REG_LOW); - outb(byaddr[2], iobase + REG_LM); - outb(byaddr[1], iobase + REG_MID); - outb(byaddr[0], iobase + REG_MSB); - } - - outb(cmd, iobase + REG_CMD); - return 0; -} - -static int read_pio(unsigned long iobase, ushort * start, ushort * end) -{ - unsigned int loop = MAXLOOP; - ushort *p; - - for (p = start; p <= end; p++) { - while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) { - udelay(1L); - if (--loop == 0) - return 1; - } - loop = MAXLOOP; - *p = REG2H(inw(iobase)); - } - - return 0; -} - -static struct pci_dev *get_pci_dev(unsigned long port_base) -{ -#if defined(CONFIG_PCI) - unsigned int addr; - struct pci_dev *dev = NULL; - - while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { - addr = pci_resource_start(dev, 0); - -#if defined(DEBUG_PCI_DETECT) - printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n", - driver_name, dev->bus->number, dev->devfn, addr); -#endif - - /* we are in so much trouble for a pci hotplug system with this driver - * anyway, so doing this at least lets people unload the driver and not - * cause memory problems, but in general this is a bad thing to do (this - * driver needs to be converted to the proper PCI api someday... */ - pci_dev_put(dev); - if (addr + PCI_BASE_ADDRESS_0 == port_base) - return dev; - } -#endif /* end CONFIG_PCI */ - return NULL; -} - -static void enable_pci_ports(void) -{ -#if defined(CONFIG_PCI) - struct pci_dev *dev = NULL; - - while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { -#if defined(DEBUG_PCI_DETECT) - printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n", - driver_name, dev->bus->number, dev->devfn); -#endif - - if (pci_enable_device(dev)) - printk - ("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n", - driver_name, dev->bus->number, dev->devfn); - } - -#endif /* end CONFIG_PCI */ -} - -static int port_detect(unsigned long port_base, unsigned int j, - struct scsi_host_template *tpnt) -{ - unsigned char irq, dma_channel, subversion, i, is_pci = 0; - unsigned char protocol_rev; - struct eata_info info; - char *bus_type, dma_name[16]; - struct pci_dev *pdev; - /* Allowed DMA channels for ISA (0 indicates reserved) */ - unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; - struct Scsi_Host *shost; - struct hostdata *ha; - char name[16]; - - sprintf(name, "%s%d", driver_name, j); - - if (!request_region(port_base, REGION_SIZE, driver_name)) { -#if defined(DEBUG_DETECT) - printk("%s: address 0x%03lx in use, skipping probe.\n", name, - port_base); -#endif - goto fail; - } - - spin_lock_irq(&driver_lock); - - if (do_dma(port_base, 0, READ_CONFIG_PIO)) { -#if defined(DEBUG_DETECT) - printk("%s: detect, do_dma failed at 0x%03lx.\n", name, - port_base); -#endif - goto freelock; - } - - /* Read the info structure */ - if (read_pio(port_base, (ushort *) & info, (ushort *) & info.ipad[0])) { -#if defined(DEBUG_DETECT) - printk("%s: detect, read_pio failed at 0x%03lx.\n", name, - port_base); -#endif - goto freelock; - } - - info.data_len = DEV2H(info.data_len); - info.sign = DEV2H(info.sign); - info.cp_pad_len = DEV2H16(info.cp_pad_len); - info.cp_len = DEV2H(info.cp_len); - info.sp_len = DEV2H(info.sp_len); - info.scatt_size = DEV2H16(info.scatt_size); - info.queue_size = DEV2H16(info.queue_size); - - /* Check the controller "EATA" signature */ - if (info.sign != EATA_SIG_BE) { -#if defined(DEBUG_DETECT) - printk("%s: signature 0x%04x discarded.\n", name, info.sign); -#endif - goto freelock; - } - - if (info.data_len < EATA_2_0A_SIZE) { - printk - ("%s: config structure size (%d bytes) too short, detaching.\n", - name, info.data_len); - goto freelock; - } else if (info.data_len == EATA_2_0A_SIZE) - protocol_rev = 'A'; - else if (info.data_len == EATA_2_0B_SIZE) - protocol_rev = 'B'; - else - protocol_rev = 'C'; - - if (protocol_rev != 'A' && info.forcaddr) { - printk("%s: warning, port address has been forced.\n", name); - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } else if (port_base > MAX_EISA_ADDR - || (protocol_rev == 'C' && info.pci)) { - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } else if (port_base >= MIN_EISA_ADDR - || (protocol_rev == 'C' && info.eisa)) { - bus_type = "EISA"; - subversion = ESA; - } else if (protocol_rev == 'C' && !info.eisa && !info.pci) { - bus_type = "ISA"; - subversion = ISA; - } else if (port_base > MAX_ISA_ADDR) { - bus_type = "PCI"; - is_pci = 1; - subversion = ESA; - } else { - bus_type = "ISA"; - subversion = ISA; - } - - if (!info.haaval || info.ata) { - printk - ("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n", - name, port_base, bus_type, info.haaval, info.ata); - goto freelock; - } - - if (info.drqvld) { - if (subversion == ESA) - printk("%s: warning, weird %s board using DMA.\n", name, - bus_type); - - subversion = ISA; - dma_channel = dma_channel_table[3 - info.drqx]; - } else { - if (subversion == ISA) - printk("%s: warning, weird %s board not using DMA.\n", - name, bus_type); - - subversion = ESA; - dma_channel = NO_DMA; - } - - if (!info.dmasup) - printk("%s: warning, DMA protocol support not asserted.\n", - name); - - irq = info.irq; - - if (subversion == ESA && !info.irq_tr) - printk - ("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", - name, irq); - - if (is_pci) { - pdev = get_pci_dev(port_base); - if (!pdev) - printk - ("%s: warning, failed to get pci_dev structure.\n", - name); - } else - pdev = NULL; - - if (pdev && (irq != pdev->irq)) { - printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, - pdev->irq); - irq = pdev->irq; - } - - /* Board detected, allocate its IRQ */ - if (request_irq(irq, do_interrupt_handler, - IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0), - driver_name, (void *)&sha[j])) { - printk("%s: unable to allocate IRQ %u, detaching.\n", name, - irq); - goto freelock; - } - - if (subversion == ISA && request_dma(dma_channel, driver_name)) { - printk("%s: unable to allocate DMA channel %u, detaching.\n", - name, dma_channel); - goto freeirq; - } -#if defined(FORCE_CONFIG) - { - struct eata_config *cf; - dma_addr_t cf_dma_addr; - - cf = pci_alloc_consistent(pdev, sizeof(struct eata_config), - &cf_dma_addr); - - if (!cf) { - printk - ("%s: config, pci_alloc_consistent failed, detaching.\n", - name); - goto freedma; - } - - /* Set board configuration */ - memset((char *)cf, 0, sizeof(struct eata_config)); - cf->len = (ushort) H2DEV16((ushort) 510); - cf->ocena = 1; - - if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) { - printk - ("%s: busy timeout sending configuration, detaching.\n", - name); - pci_free_consistent(pdev, sizeof(struct eata_config), - cf, cf_dma_addr); - goto freedma; - } - - } -#endif - - spin_unlock_irq(&driver_lock); - sh[j] = shost = scsi_register(tpnt, sizeof(struct hostdata)); - spin_lock_irq(&driver_lock); - - if (shost == NULL) { - printk("%s: unable to register host, detaching.\n", name); - goto freedma; - } - - shost->io_port = port_base; - shost->unique_id = port_base; - shost->n_io_port = REGION_SIZE; - shost->dma_channel = dma_channel; - shost->irq = irq; - shost->sg_tablesize = (ushort) info.scatt_size; - shost->this_id = (ushort) info.host_addr[3]; - shost->can_queue = (ushort) info.queue_size; - shost->cmd_per_lun = MAX_CMD_PER_LUN; - - ha = (struct hostdata *)shost->hostdata; - - memset(ha, 0, sizeof(struct hostdata)); - ha->subversion = subversion; - ha->protocol_rev = protocol_rev; - ha->is_pci = is_pci; - ha->pdev = pdev; - ha->board_number = j; - - if (ha->subversion == ESA) - shost->unchecked_isa_dma = 0; - else { - unsigned long flags; - shost->unchecked_isa_dma = 1; - - flags = claim_dma_lock(); - disable_dma(dma_channel); - clear_dma_ff(dma_channel); - set_dma_mode(dma_channel, DMA_MODE_CASCADE); - enable_dma(dma_channel); - release_dma_lock(flags); - - } - - strcpy(ha->board_name, name); - - /* DPT PM2012 does not allow to detect sg_tablesize correctly */ - if (shost->sg_tablesize > MAX_SGLIST || shost->sg_tablesize < 2) { - printk("%s: detect, wrong n. of SG lists %d, fixed.\n", - ha->board_name, shost->sg_tablesize); - shost->sg_tablesize = MAX_SGLIST; - } - - /* DPT PM2012 does not allow to detect can_queue correctly */ - if (shost->can_queue > MAX_MAILBOXES || shost->can_queue < 2) { - printk("%s: detect, wrong n. of mbox %d, fixed.\n", - ha->board_name, shost->can_queue); - shost->can_queue = MAX_MAILBOXES; - } - - if (protocol_rev != 'A') { - if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL) - shost->max_channel = info.max_chan; - - if (info.max_id > 7 && info.max_id < MAX_TARGET) - shost->max_id = info.max_id + 1; - - if (info.large_sg && shost->sg_tablesize == MAX_SGLIST) - shost->sg_tablesize = MAX_LARGE_SGLIST; - } - - if (protocol_rev == 'C') { - if (info.max_lun > 7 && info.max_lun < MAX_LUN) - shost->max_lun = info.max_lun + 1; - } - - if (dma_channel == NO_DMA) - sprintf(dma_name, "%s", "BMST"); - else - sprintf(dma_name, "DMA %u", dma_channel); - - spin_unlock_irq(&driver_lock); - - for (i = 0; i < shost->can_queue; i++) - ha->cp[i].cp_dma_addr = pci_map_single(ha->pdev, - &ha->cp[i], - sizeof(struct mscp), - PCI_DMA_BIDIRECTIONAL); - - for (i = 0; i < shost->can_queue; i++) { - size_t sz = shost->sg_tablesize *sizeof(struct sg_list); - gfp_t gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC; - ha->cp[i].sglist = kmalloc(sz, gfp_mask); - if (!ha->cp[i].sglist) { - printk - ("%s: kmalloc SGlist failed, mbox %d, detaching.\n", - ha->board_name, i); - goto release; - } - } - - if (!(ha->sp_cpu_addr = pci_alloc_consistent(ha->pdev, - sizeof(struct mssp), - &ha->sp_dma_addr))) { - printk("%s: pci_alloc_consistent failed, detaching.\n", ha->board_name); - goto release; - } - - if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) - max_queue_depth = MAX_TAGGED_CMD_PER_LUN; - - if (max_queue_depth < MAX_CMD_PER_LUN) - max_queue_depth = MAX_CMD_PER_LUN; - - if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE) - tag_mode = TAG_ORDERED; - - if (j == 0) { - printk - ("EATA/DMA 2.0x: Copyright (C) 1994-2003 Dario Ballabio.\n"); - printk - ("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, " - "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode, - YESNO(linked_comm), max_queue_depth, YESNO(rev_scan), - YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe), - YESNO(pci_probe)); - } - - printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n", - ha->board_name, ha->protocol_rev, bus_type, - (unsigned long)shost->io_port, shost->irq, dma_name, - shost->sg_tablesize, shost->can_queue); - - if (shost->max_id > 8 || shost->max_lun > 8) - printk - ("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n", - ha->board_name, shost->max_id, shost->max_lun); - - for (i = 0; i <= shost->max_channel; i++) - printk("%s: SCSI channel %u enabled, host target ID %d.\n", - ha->board_name, i, info.host_addr[3 - i]); - -#if defined(DEBUG_DETECT) - printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, " - "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version, - info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync, - info.second, info.data_len, info.cp_len, info.sp_len); - - if (protocol_rev == 'B' || protocol_rev == 'C') - printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, " - "large_sg %u, res1 %u.\n", name, info.isaena, - info.forcaddr, info.max_id, info.max_chan, info.large_sg, - info.res1); - - if (protocol_rev == 'C') - printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, " - "raidnum %u.\n", name, info.max_lun, info.m1, - info.idquest, info.pci, info.eisa, info.raidnum); -#endif - - if (ha->pdev) { - pci_set_master(ha->pdev); - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32))) - printk("%s: warning, pci_set_dma_mask failed.\n", - ha->board_name); - } - - return 1; - - freedma: - if (subversion == ISA) - free_dma(dma_channel); - freeirq: - free_irq(irq, &sha[j]); - freelock: - spin_unlock_irq(&driver_lock); - release_region(port_base, REGION_SIZE); - fail: - return 0; - - release: - eata2x_release(shost); - return 0; -} - -static void internal_setup(char *str, int *ints) -{ - int i, argc = ints[0]; - char *cur = str, *pc; - - if (argc > 0) { - if (argc > MAX_INT_PARAM) - argc = MAX_INT_PARAM; - - for (i = 0; i < argc; i++) - io_port[i] = ints[i + 1]; - - io_port[i] = 0; - setup_done = 1; - } - - while (cur && (pc = strchr(cur, ':'))) { - int val = 0, c = *++pc; - - if (c == 'n' || c == 'N') - val = 0; - else if (c == 'y' || c == 'Y') - val = 1; - else - val = (int)simple_strtoul(pc, NULL, 0); - - if (!strncmp(cur, "lc:", 3)) - linked_comm = val; - else if (!strncmp(cur, "tm:", 3)) - tag_mode = val; - else if (!strncmp(cur, "tc:", 3)) - tag_mode = val; - else if (!strncmp(cur, "mq:", 3)) - max_queue_depth = val; - else if (!strncmp(cur, "ls:", 3)) - link_statistics = val; - else if (!strncmp(cur, "et:", 3)) - ext_tran = val; - else if (!strncmp(cur, "rs:", 3)) - rev_scan = val; - else if (!strncmp(cur, "ip:", 3)) - isa_probe = val; - else if (!strncmp(cur, "ep:", 3)) - eisa_probe = val; - else if (!strncmp(cur, "pp:", 3)) - pci_probe = val; - - if ((cur = strchr(cur, ','))) - ++cur; - } - - return; -} - -static int option_setup(char *str) -{ - int ints[MAX_INT_PARAM]; - char *cur = str; - int i = 1; - - while (cur && isdigit(*cur) && i < MAX_INT_PARAM) { - ints[i++] = simple_strtoul(cur, NULL, 0); - - if ((cur = strchr(cur, ',')) != NULL) - cur++; - } - - ints[0] = i - 1; - internal_setup(cur, ints); - return 1; -} - -static void add_pci_ports(void) -{ -#if defined(CONFIG_PCI) - unsigned int addr, k; - struct pci_dev *dev = NULL; - - for (k = 0; k < MAX_PCI; k++) { - - if (!(dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) - break; - - if (pci_enable_device(dev)) { -#if defined(DEBUG_PCI_DETECT) - printk - ("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n", - driver_name, dev->bus->number, dev->devfn); -#endif - - continue; - } - - addr = pci_resource_start(dev, 0); - -#if defined(DEBUG_PCI_DETECT) - printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n", - driver_name, k, dev->bus->number, dev->devfn, addr); -#endif - - /* Order addresses according to rev_scan value */ - io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] = - addr + PCI_BASE_ADDRESS_0; - } - - pci_dev_put(dev); -#endif /* end CONFIG_PCI */ -} - -static int eata2x_detect(struct scsi_host_template *tpnt) -{ - unsigned int j = 0, k; - - tpnt->proc_name = "eata2x"; - - if (strlen(boot_options)) - option_setup(boot_options); - -#if defined(MODULE) - /* io_port could have been modified when loading as a module */ - if (io_port[0] != SKIP) { - setup_done = 1; - io_port[MAX_INT_PARAM] = 0; - } -#endif - - for (k = MAX_INT_PARAM; io_port[k]; k++) - if (io_port[k] == SKIP) - continue; - else if (io_port[k] <= MAX_ISA_ADDR) { - if (!isa_probe) - io_port[k] = SKIP; - } else if (io_port[k] >= MIN_EISA_ADDR - && io_port[k] <= MAX_EISA_ADDR) { - if (!eisa_probe) - io_port[k] = SKIP; - } - - if (pci_probe) { - if (!setup_done) - add_pci_ports(); - else - enable_pci_ports(); - } - - for (k = 0; io_port[k]; k++) { - - if (io_port[k] == SKIP) - continue; - - if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) - j++; - } - - num_boards = j; - return j; -} - -static void map_dma(unsigned int i, struct hostdata *ha) -{ - unsigned int k, pci_dir; - int count; - struct scatterlist *sg; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &ha->cp[i]; - SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (SCpnt->sense_buffer) - cpp->sense_addr = - H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE)); - - cpp->sense_len = SCSI_SENSE_BUFFERSIZE; - - if (!scsi_sg_count(SCpnt)) { - cpp->data_len = 0; - return; - } - - count = pci_map_sg(ha->pdev, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), - pci_dir); - BUG_ON(!count); - - scsi_for_each_sg(SCpnt, sg, count, k) { - cpp->sglist[k].address = H2DEV(sg_dma_address(sg)); - cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg)); - } - - cpp->sg = 1; - cpp->data_address = H2DEV(pci_map_single(ha->pdev, cpp->sglist, - scsi_sg_count(SCpnt) * - sizeof(struct sg_list), - pci_dir)); - cpp->data_len = H2DEV((scsi_sg_count(SCpnt) * sizeof(struct sg_list))); -} - -static void unmap_dma(unsigned int i, struct hostdata *ha) -{ - unsigned int pci_dir; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &ha->cp[i]; - SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (DEV2H(cpp->sense_addr)) - pci_unmap_single(ha->pdev, DEV2H(cpp->sense_addr), - DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - - if (scsi_sg_count(SCpnt)) - pci_unmap_sg(ha->pdev, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), - pci_dir); - - if (!DEV2H(cpp->data_len)) - pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (DEV2H(cpp->data_address)) - pci_unmap_single(ha->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); -} - -static void sync_dma(unsigned int i, struct hostdata *ha) -{ - unsigned int pci_dir; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &ha->cp[i]; - SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (DEV2H(cpp->sense_addr)) - pci_dma_sync_single_for_cpu(ha->pdev, DEV2H(cpp->sense_addr), - DEV2H(cpp->sense_len), - PCI_DMA_FROMDEVICE); - - if (scsi_sg_count(SCpnt)) - pci_dma_sync_sg_for_cpu(ha->pdev, scsi_sglist(SCpnt), - scsi_sg_count(SCpnt), pci_dir); - - if (!DEV2H(cpp->data_len)) - pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (DEV2H(cpp->data_address)) - pci_dma_sync_single_for_cpu(ha->pdev, - DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); -} - -static void scsi_to_dev_dir(unsigned int i, struct hostdata *ha) -{ - unsigned int k; - - static const unsigned char data_out_cmds[] = { - 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, - 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, - 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d - }; - - static const unsigned char data_none_cmds[] = { - 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, - 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, - 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 - }; - - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &ha->cp[i]; - SCpnt = cpp->SCpnt; - - if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { - cpp->din = 1; - cpp->dout = 0; - return; - } else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { - cpp->din = 0; - cpp->dout = 1; - return; - } else if (SCpnt->sc_data_direction == DMA_NONE) { - cpp->din = 0; - cpp->dout = 0; - return; - } - - if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL) - panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", - ha->board_name); - - for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->dout = 1; - break; - } - - if ((cpp->din = !cpp->dout)) - for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) - if (SCpnt->cmnd[0] == data_none_cmds[k]) { - cpp->din = 0; - break; - } - -} - -static int eata2x_queuecommand_lck(struct scsi_cmnd *SCpnt, - void (*done) (struct scsi_cmnd *)) -{ - struct Scsi_Host *shost = SCpnt->device->host; - struct hostdata *ha = (struct hostdata *)shost->hostdata; - unsigned int i, k; - struct mscp *cpp; - - if (SCpnt->host_scribble) - panic("%s: qcomm, SCpnt %p already active.\n", - ha->board_name, SCpnt); - - /* i is the mailbox number, look for the first free mailbox - starting from last_cp_used */ - i = ha->last_cp_used + 1; - - for (k = 0; k < shost->can_queue; k++, i++) { - if (i >= shost->can_queue) - i = 0; - if (ha->cp_stat[i] == FREE) { - ha->last_cp_used = i; - break; - } - } - - if (k == shost->can_queue) { - printk("%s: qcomm, no free mailbox.\n", ha->board_name); - return 1; - } - - /* Set pointer to control packet structure */ - cpp = &ha->cp[i]; - - memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); - - /* Set pointer to status packet structure, Big Endian format */ - cpp->sp_dma_addr = H2DEV(ha->sp_dma_addr); - - SCpnt->scsi_done = done; - cpp->cpp_index = i; - SCpnt->host_scribble = (unsigned char *)&cpp->cpp_index; - - if (do_trace) - scmd_printk(KERN_INFO, SCpnt, - "qcomm, mbox %d.\n", i); - - cpp->reqsen = 1; - cpp->dispri = 1; -#if 0 - if (SCpnt->device->type == TYPE_TAPE) - cpp->hbaci = 1; -#endif - cpp->one = 1; - cpp->channel = SCpnt->device->channel; - cpp->target = SCpnt->device->id; - cpp->lun = SCpnt->device->lun; - cpp->SCpnt = SCpnt; - memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - /* Use data transfer direction SCpnt->sc_data_direction */ - scsi_to_dev_dir(i, ha); - - /* Map DMA buffers and SG list */ - map_dma(i, ha); - - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) { - ha->cp_stat[i] = READY; - flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 0); - return 0; - } - - /* Send control packet to the board */ - if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { - unmap_dma(i, ha); - SCpnt->host_scribble = NULL; - scmd_printk(KERN_INFO, SCpnt, "qcomm, adapter busy.\n"); - return 1; - } - - ha->cp_stat[i] = IN_USE; - return 0; -} - -static DEF_SCSI_QCMD(eata2x_queuecommand) - -static int eata2x_eh_abort(struct scsi_cmnd *SCarg) -{ - struct Scsi_Host *shost = SCarg->device->host; - struct hostdata *ha = (struct hostdata *)shost->hostdata; - unsigned int i; - - if (SCarg->host_scribble == NULL) { - scmd_printk(KERN_INFO, SCarg, "abort, cmd inactive.\n"); - return SUCCESS; - } - - i = *(unsigned int *)SCarg->host_scribble; - scmd_printk(KERN_WARNING, SCarg, "abort, mbox %d.\n", i); - - if (i >= shost->can_queue) - panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name); - - if (wait_on_busy(shost->io_port, MAXLOOP)) { - printk("%s: abort, timeout error.\n", ha->board_name); - return FAILED; - } - - if (ha->cp_stat[i] == FREE) { - printk("%s: abort, mbox %d is free.\n", ha->board_name, i); - return SUCCESS; - } - - if (ha->cp_stat[i] == IN_USE) { - printk("%s: abort, mbox %d is in use.\n", ha->board_name, i); - - if (SCarg != ha->cp[i].SCpnt) - panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n", - ha->board_name, i, SCarg, ha->cp[i].SCpnt); - - if (inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED) - printk("%s: abort, mbox %d, interrupt pending.\n", - ha->board_name, i); - - return FAILED; - } - - if (ha->cp_stat[i] == IN_RESET) { - printk("%s: abort, mbox %d is in reset.\n", ha->board_name, i); - return FAILED; - } - - if (ha->cp_stat[i] == LOCKED) { - printk("%s: abort, mbox %d is locked.\n", ha->board_name, i); - return SUCCESS; - } - - if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { - unmap_dma(i, ha); - SCarg->result = DID_ABORT << 16; - SCarg->host_scribble = NULL; - ha->cp_stat[i] = FREE; - printk("%s, abort, mbox %d ready, DID_ABORT, done.\n", - ha->board_name, i); - SCarg->scsi_done(SCarg); - return SUCCESS; - } - - panic("%s: abort, mbox %d, invalid cp_stat.\n", ha->board_name, i); -} - -static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg) -{ - unsigned int i, time, k, c, limit = 0; - int arg_done = 0; - struct scsi_cmnd *SCpnt; - struct Scsi_Host *shost = SCarg->device->host; - struct hostdata *ha = (struct hostdata *)shost->hostdata; - - scmd_printk(KERN_INFO, SCarg, "reset, enter.\n"); - - spin_lock_irq(shost->host_lock); - - if (SCarg->host_scribble == NULL) - printk("%s: reset, inactive.\n", ha->board_name); - - if (ha->in_reset) { - printk("%s: reset, exit, already in reset.\n", ha->board_name); - spin_unlock_irq(shost->host_lock); - return FAILED; - } - - if (wait_on_busy(shost->io_port, MAXLOOP)) { - printk("%s: reset, exit, timeout error.\n", ha->board_name); - spin_unlock_irq(shost->host_lock); - return FAILED; - } - - ha->retries = 0; - - for (c = 0; c <= shost->max_channel; c++) - for (k = 0; k < shost->max_id; k++) { - ha->target_redo[k][c] = 1; - ha->target_to[k][c] = 0; - } - - for (i = 0; i < shost->can_queue; i++) { - - if (ha->cp_stat[i] == FREE) - continue; - - if (ha->cp_stat[i] == LOCKED) { - ha->cp_stat[i] = FREE; - printk("%s: reset, locked mbox %d forced free.\n", - ha->board_name, i); - continue; - } - - if (!(SCpnt = ha->cp[i].SCpnt)) - panic("%s: reset, mbox %d, SCpnt == NULL.\n", ha->board_name, i); - - if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) { - ha->cp_stat[i] = ABORTING; - printk("%s: reset, mbox %d aborting.\n", - ha->board_name, i); - } - - else { - ha->cp_stat[i] = IN_RESET; - printk("%s: reset, mbox %d in reset.\n", - ha->board_name, i); - } - - if (SCpnt->host_scribble == NULL) - panic("%s: reset, mbox %d, garbled SCpnt.\n", ha->board_name, i); - - if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: reset, mbox %d, index mismatch.\n", ha->board_name, i); - - if (SCpnt->scsi_done == NULL) - panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", - ha->board_name, i); - - if (SCpnt == SCarg) - arg_done = 1; - } - - if (do_dma(shost->io_port, 0, RESET_PIO)) { - printk("%s: reset, cannot reset, timeout error.\n", ha->board_name); - spin_unlock_irq(shost->host_lock); - return FAILED; - } - - printk("%s: reset, board reset done, enabling interrupts.\n", ha->board_name); - -#if defined(DEBUG_RESET) - do_trace = 1; -#endif - - ha->in_reset = 1; - - spin_unlock_irq(shost->host_lock); - - /* FIXME: use a sleep instead */ - time = jiffies; - while ((jiffies - time) < (10 * HZ) && limit++ < 200000) - udelay(100L); - - spin_lock_irq(shost->host_lock); - - printk("%s: reset, interrupts disabled, loops %d.\n", ha->board_name, limit); - - for (i = 0; i < shost->can_queue; i++) { - - if (ha->cp_stat[i] == IN_RESET) { - SCpnt = ha->cp[i].SCpnt; - unmap_dma(i, ha); - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; - - /* This mailbox is still waiting for its interrupt */ - ha->cp_stat[i] = LOCKED; - - printk - ("%s, reset, mbox %d locked, DID_RESET, done.\n", - ha->board_name, i); - } - - else if (ha->cp_stat[i] == ABORTING) { - SCpnt = ha->cp[i].SCpnt; - unmap_dma(i, ha); - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; - - /* This mailbox was never queued to the adapter */ - ha->cp_stat[i] = FREE; - - printk - ("%s, reset, mbox %d aborting, DID_RESET, done.\n", - ha->board_name, i); - } - - else - /* Any other mailbox has already been set free by interrupt */ - continue; - - SCpnt->scsi_done(SCpnt); - } - - ha->in_reset = 0; - do_trace = 0; - - if (arg_done) - printk("%s: reset, exit, done.\n", ha->board_name); - else - printk("%s: reset, exit.\n", ha->board_name); - - spin_unlock_irq(shost->host_lock); - return SUCCESS; -} - -int eata2x_bios_param(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int *dkinfo) -{ - unsigned int size = capacity; - - if (ext_tran || (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) { - dkinfo[0] = 255; - dkinfo[1] = 63; - dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); - } -#if defined (DEBUG_GEOMETRY) - printk("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name, - dkinfo[0], dkinfo[1], dkinfo[2]); -#endif - - return 0; -} - -static void sort(unsigned long sk[], unsigned int da[], unsigned int n, - unsigned int rev) -{ - unsigned int i, j, k, y; - unsigned long x; - - for (i = 0; i < n - 1; i++) { - k = i; - - for (j = k + 1; j < n; j++) - if (rev) { - if (sk[j] > sk[k]) - k = j; - } else { - if (sk[j] < sk[k]) - k = j; - } - - if (k != i) { - x = sk[k]; - sk[k] = sk[i]; - sk[i] = x; - y = da[k]; - da[k] = da[i]; - da[i] = y; - } - } - - return; -} - -static int reorder(struct hostdata *ha, unsigned long cursec, - unsigned int ihdlr, unsigned int il[], unsigned int n_ready) -{ - struct scsi_cmnd *SCpnt; - struct mscp *cpp; - unsigned int k, n; - unsigned int rev = 0, s = 1, r = 1; - unsigned int input_only = 1, overlap = 0; - unsigned long sl[n_ready], pl[n_ready], ll[n_ready]; - unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0; - unsigned long ioseek = 0; - - static unsigned int flushcount = 0, batchcount = 0, sortcount = 0; - static unsigned int readycount = 0, ovlcount = 0, inputcount = 0; - static unsigned int readysorted = 0, revcount = 0; - static unsigned long seeksorted = 0, seeknosort = 0; - - if (link_statistics && !(++flushcount % link_statistics)) - printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d" - " av %ldK as %ldK.\n", flushcount, batchcount, - inputcount, ovlcount, readycount, readysorted, sortcount, - revcount, seeknosort / (readycount + 1), - seeksorted / (readycount + 1)); - - if (n_ready <= 1) - return 0; - - for (n = 0; n < n_ready; n++) { - k = il[n]; - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - - if (!cpp->din) - input_only = 0; - - if (blk_rq_pos(SCpnt->request) < minsec) - minsec = blk_rq_pos(SCpnt->request); - if (blk_rq_pos(SCpnt->request) > maxsec) - maxsec = blk_rq_pos(SCpnt->request); - - sl[n] = blk_rq_pos(SCpnt->request); - ioseek += blk_rq_sectors(SCpnt->request); - - if (!n) - continue; - - if (sl[n] < sl[n - 1]) - s = 0; - if (sl[n] > sl[n - 1]) - r = 0; - - if (link_statistics) { - if (sl[n] > sl[n - 1]) - seek += sl[n] - sl[n - 1]; - else - seek += sl[n - 1] - sl[n]; - } - - } - - if (link_statistics) { - if (cursec > sl[0]) - seek += cursec - sl[0]; - else - seek += sl[0] - cursec; - } - - if (cursec > ((maxsec + minsec) / 2)) - rev = 1; - - if (ioseek > ((maxsec - minsec) / 2)) - rev = 0; - - if (!((rev && r) || (!rev && s))) - sort(sl, il, n_ready, rev); - - if (!input_only) - for (n = 0; n < n_ready; n++) { - k = il[n]; - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - ll[n] = blk_rq_sectors(SCpnt->request); - pl[n] = SCpnt->serial_number; - - if (!n) - continue; - - if ((sl[n] == sl[n - 1]) - || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n])) - || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) - overlap = 1; - } - - if (overlap) - sort(pl, il, n_ready, 0); - - if (link_statistics) { - if (cursec > sl[0]) - iseek = cursec - sl[0]; - else - iseek = sl[0] - cursec; - batchcount++; - readycount += n_ready; - seeknosort += seek / 1024; - if (input_only) - inputcount++; - if (overlap) { - ovlcount++; - seeksorted += iseek / 1024; - } else - seeksorted += (iseek + maxsec - minsec) / 1024; - if (rev && !r) { - revcount++; - readysorted += n_ready; - } - if (!rev && !s) { - sortcount++; - readysorted += n_ready; - } - } -#if defined(DEBUG_LINKED_COMMANDS) - if (link_statistics && (overlap || !(flushcount % link_statistics))) - for (n = 0; n < n_ready; n++) { - k = il[n]; - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - scmd_printk(KERN_INFO, SCpnt, - "%s mb %d fc %d nr %d sec %ld ns %u" - " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", - (ihdlr ? "ihdlr" : "qcomm"), - k, flushcount, - n_ready, blk_rq_pos(SCpnt->request), - blk_rq_sectors(SCpnt->request), cursec, YESNO(s), - YESNO(r), YESNO(rev), YESNO(input_only), - YESNO(overlap), cpp->din); - } -#endif - return overlap; -} - -static void flush_dev(struct scsi_device *dev, unsigned long cursec, - struct hostdata *ha, unsigned int ihdlr) -{ - struct scsi_cmnd *SCpnt; - struct mscp *cpp; - unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES]; - - for (k = 0; k < dev->host->can_queue; k++) { - - if (ha->cp_stat[k] != READY && ha->cp_stat[k] != IN_USE) - continue; - - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - - if (SCpnt->device != dev) - continue; - - if (ha->cp_stat[k] == IN_USE) - return; - - il[n_ready++] = k; - } - - if (reorder(ha, cursec, ihdlr, il, n_ready)) - n_ready = 1; - - for (n = 0; n < n_ready; n++) { - k = il[n]; - cpp = &ha->cp[k]; - SCpnt = cpp->SCpnt; - - if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) { - scmd_printk(KERN_INFO, SCpnt, - "%s, mbox %d, adapter" - " busy, will abort.\n", - (ihdlr ? "ihdlr" : "qcomm"), - k); - ha->cp_stat[k] = ABORTING; - continue; - } - - ha->cp_stat[k] = IN_USE; - } -} - -static irqreturn_t ihdlr(struct Scsi_Host *shost) -{ - struct scsi_cmnd *SCpnt; - unsigned int i, k, c, status, tstatus, reg; - struct mssp *spp; - struct mscp *cpp; - struct hostdata *ha = (struct hostdata *)shost->hostdata; - int irq = shost->irq; - - /* Check if this board need to be serviced */ - if (!(inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)) - goto none; - - ha->iocount++; - - if (do_trace) - printk("%s: ihdlr, enter, irq %d, count %d.\n", ha->board_name, irq, - ha->iocount); - - /* Check if this board is still busy */ - if (wait_on_busy(shost->io_port, 20 * MAXLOOP)) { - reg = inb(shost->io_port + REG_STATUS); - printk - ("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", - ha->board_name, irq, reg, ha->iocount); - goto none; - } - - spp = &ha->sp; - - /* Make a local copy just before clearing the interrupt indication */ - memcpy(spp, ha->sp_cpu_addr, sizeof(struct mssp)); - - /* Clear the completion flag and cp pointer on the dynamic copy of sp */ - memset(ha->sp_cpu_addr, 0, sizeof(struct mssp)); - - /* Read the status register to clear the interrupt indication */ - reg = inb(shost->io_port + REG_STATUS); - -#if defined (DEBUG_INTERRUPT) - { - unsigned char *bytesp; - int cnt; - bytesp = (unsigned char *)spp; - if (ha->iocount < 200) { - printk("sp[] ="); - for (cnt = 0; cnt < 15; cnt++) - printk(" 0x%x", bytesp[cnt]); - printk("\n"); - } - } -#endif - - /* Reject any sp with supspect data */ - if (spp->eoc == 0 && ha->iocount > 1) - printk - ("%s: ihdlr, spp->eoc == 0, irq %d, reg 0x%x, count %d.\n", - ha->board_name, irq, reg, ha->iocount); - if (spp->cpp_index < 0 || spp->cpp_index >= shost->can_queue) - printk - ("%s: ihdlr, bad spp->cpp_index %d, irq %d, reg 0x%x, count %d.\n", - ha->board_name, spp->cpp_index, irq, reg, ha->iocount); - if (spp->eoc == 0 || spp->cpp_index < 0 - || spp->cpp_index >= shost->can_queue) - goto handled; - - /* Find the mailbox to be serviced on this board */ - i = spp->cpp_index; - - cpp = &(ha->cp[i]); - -#if defined(DEBUG_GENERATE_ABORTS) - if ((ha->iocount > 500) && ((ha->iocount % 500) < 3)) - goto handled; -#endif - - if (ha->cp_stat[i] == IGNORE) { - ha->cp_stat[i] = FREE; - goto handled; - } else if (ha->cp_stat[i] == LOCKED) { - ha->cp_stat[i] = FREE; - printk("%s: ihdlr, mbox %d unlocked, count %d.\n", ha->board_name, i, - ha->iocount); - goto handled; - } else if (ha->cp_stat[i] == FREE) { - printk("%s: ihdlr, mbox %d is free, count %d.\n", ha->board_name, i, - ha->iocount); - goto handled; - } else if (ha->cp_stat[i] == IN_RESET) - printk("%s: ihdlr, mbox %d is in reset.\n", ha->board_name, i); - else if (ha->cp_stat[i] != IN_USE) - panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n", - ha->board_name, i, ha->cp_stat[i]); - - ha->cp_stat[i] = FREE; - SCpnt = cpp->SCpnt; - - if (SCpnt == NULL) - panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", ha->board_name, i); - - if (SCpnt->host_scribble == NULL) - panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", ha->board_name, - i, SCpnt); - - if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: ihdlr, mbox %d, index mismatch %d.\n", - ha->board_name, i, - *(unsigned int *)SCpnt->host_scribble); - - sync_dma(i, ha); - - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), ha, 1); - - tstatus = status_byte(spp->target_status); - -#if defined(DEBUG_GENERATE_ERRORS) - if ((ha->iocount > 500) && ((ha->iocount % 200) < 2)) - spp->adapter_status = 0x01; -#endif - - switch (spp->adapter_status) { - case ASOK: /* status OK */ - - /* Forces a reset if a disk drive keeps returning BUSY */ - if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) - status = DID_ERROR << 16; - - /* If there was a bus reset, redo operation on each target */ - else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK - && ha->target_redo[SCpnt->device->id][SCpnt-> - device-> - channel]) - status = DID_BUS_BUSY << 16; - - /* Works around a flaw in scsi.c */ - else if (tstatus == CHECK_CONDITION - && SCpnt->device->type == TYPE_DISK - && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR) - status = DID_BUS_BUSY << 16; - - else - status = DID_OK << 16; - - if (tstatus == GOOD) - ha->target_redo[SCpnt->device->id][SCpnt->device-> - channel] = 0; - - if (spp->target_status && SCpnt->device->type == TYPE_DISK && - (!(tstatus == CHECK_CONDITION && ha->iocount <= 1000 && - (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) - printk("%s: ihdlr, target %d.%d:%d, " - "target_status 0x%x, sense key 0x%x.\n", - ha->board_name, - SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun, - spp->target_status, SCpnt->sense_buffer[2]); - - ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0; - - if (ha->last_retried_pid == SCpnt->serial_number) - ha->retries = 0; - - break; - case ASST: /* Selection Time Out */ - case 0x02: /* Command Time Out */ - - if (ha->target_to[SCpnt->device->id][SCpnt->device->channel] > 1) - status = DID_ERROR << 16; - else { - status = DID_TIME_OUT << 16; - ha->target_to[SCpnt->device->id][SCpnt->device-> - channel]++; - } - - break; - - /* Perform a limited number of internal retries */ - case 0x03: /* SCSI Bus Reset Received */ - case 0x04: /* Initial Controller Power-up */ - - for (c = 0; c <= shost->max_channel; c++) - for (k = 0; k < shost->max_id; k++) - ha->target_redo[k][c] = 1; - - if (SCpnt->device->type != TYPE_TAPE - && ha->retries < MAX_INTERNAL_RETRIES) { - -#if defined(DID_SOFT_ERROR) - status = DID_SOFT_ERROR << 16; -#else - status = DID_BUS_BUSY << 16; -#endif - - ha->retries++; - ha->last_retried_pid = SCpnt->serial_number; - } else - status = DID_ERROR << 16; - - break; - case 0x05: /* Unexpected Bus Phase */ - case 0x06: /* Unexpected Bus Free */ - case 0x07: /* Bus Parity Error */ - case 0x08: /* SCSI Hung */ - case 0x09: /* Unexpected Message Reject */ - case 0x0a: /* SCSI Bus Reset Stuck */ - case 0x0b: /* Auto Request-Sense Failed */ - case 0x0c: /* Controller Ram Parity Error */ - default: - status = DID_ERROR << 16; - break; - } - - SCpnt->result = status | spp->target_status; - -#if defined(DEBUG_INTERRUPT) - if (SCpnt->result || do_trace) -#else - if ((spp->adapter_status != ASOK && ha->iocount > 1000) || - (spp->adapter_status != ASOK && - spp->adapter_status != ASST && ha->iocount <= 1000) || - do_trace || msg_byte(spp->target_status)) -#endif - scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x," - " reg 0x%x, count %d.\n", - i, spp->adapter_status, spp->target_status, - reg, ha->iocount); - - unmap_dma(i, ha); - - /* Set the command state to inactive */ - SCpnt->host_scribble = NULL; - - SCpnt->scsi_done(SCpnt); - - if (do_trace) - printk("%s: ihdlr, exit, irq %d, count %d.\n", ha->board_name, - irq, ha->iocount); - - handled: - return IRQ_HANDLED; - none: - return IRQ_NONE; -} - -static irqreturn_t do_interrupt_handler(int dummy, void *shap) -{ - struct Scsi_Host *shost; - unsigned int j; - unsigned long spin_flags; - irqreturn_t ret; - - /* Check if the interrupt must be processed by this handler */ - if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) - return IRQ_NONE; - shost = sh[j]; - - spin_lock_irqsave(shost->host_lock, spin_flags); - ret = ihdlr(shost); - spin_unlock_irqrestore(shost->host_lock, spin_flags); - return ret; -} - -static int eata2x_release(struct Scsi_Host *shost) -{ - struct hostdata *ha = (struct hostdata *)shost->hostdata; - unsigned int i; - - for (i = 0; i < shost->can_queue; i++) - kfree((&ha->cp[i])->sglist); - - for (i = 0; i < shost->can_queue; i++) - pci_unmap_single(ha->pdev, ha->cp[i].cp_dma_addr, - sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); - - if (ha->sp_cpu_addr) - pci_free_consistent(ha->pdev, sizeof(struct mssp), - ha->sp_cpu_addr, ha->sp_dma_addr); - - free_irq(shost->irq, &sha[ha->board_number]); - - if (shost->dma_channel != NO_DMA) - free_dma(shost->dma_channel); - - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -#include "scsi_module.c" - -#ifndef MODULE -__setup("eata=", option_setup); -#endif /* end MODULE */ diff --git a/ANDROID_3.4.5/drivers/scsi/eata_generic.h b/ANDROID_3.4.5/drivers/scsi/eata_generic.h deleted file mode 100644 index 5016af5c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/eata_generic.h +++ /dev/null @@ -1,400 +0,0 @@ -/******************************************************** -* Header file for eata_dma.c and eata_pio.c * -* Linux EATA SCSI drivers * -* (c) 1993-96 Michael Neuffer * -* mike@i-Connect.Net * -* neuffer@mail.uni-mainz.de * -********************************************************* -* last change: 96/08/14 * -********************************************************/ - - -#ifndef _EATA_GENERIC_H -#define _EATA_GENERIC_H - - - -/********************************************* - * Misc. definitions * - *********************************************/ - -#define R_LIMIT 0x20000 - -#define MAXISA 4 -#define MAXEISA 16 -#define MAXPCI 16 -#define MAXIRQ 16 -#define MAXTARGET 16 -#define MAXCHANNEL 3 - -#define IS_ISA 'I' -#define IS_EISA 'E' -#define IS_PCI 'P' - -#define BROKEN_INQUIRY 1 - -#define BUSMASTER 0xff -#define PIO 0xfe - -#define EATA_SIGNATURE 0x45415441 /* BIG ENDIAN coded "EATA" sig. */ - -#define DPT_ID1 0x12 -#define DPT_ID2 0x14 - -#define ATT_ID1 0x06 -#define ATT_ID2 0x94 -#define ATT_ID3 0x0 - -#define NEC_ID1 0x38 -#define NEC_ID2 0xa3 -#define NEC_ID3 0x82 - - -#define EATA_CP_SIZE 44 - -#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */ -#define MAX_METHOD_2 16 /* Max Devices For Method 2 */ -#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */ - -#define SG_SIZE 64 -#define SG_SIZE_BIG 252 /* max. 8096 elements, 64k */ - -#define UPPER_DEVICE_QUEUE_LIMIT 64 /* The limit we have to set for the - * device queue to keep the broken - * midlevel SCSI code from producing - * bogus timeouts - */ - -#define TYPE_DISK_QUEUE 16 -#define TYPE_TAPE_QUEUE 4 -#define TYPE_ROM_QUEUE 4 -#define TYPE_OTHER_QUEUE 2 - -#define FREE 0 -#define OK 0 -#define NO_TIMEOUT 0 -#define USED 1 -#define TIMEOUT 2 -#define RESET 4 -#define LOCKED 8 -#define ABORTED 16 - -#define READ 0 -#define WRITE 1 -#define OTHER 2 - -#define HD(cmd) ((hostdata *)&(cmd->device->host->hostdata)) -#define CD(cmd) ((struct eata_ccb *)(cmd->host_scribble)) -#define SD(host) ((hostdata *)&(host->hostdata)) - -/*********************************************** - * EATA Command & Register definitions * - ***********************************************/ -#define PCI_REG_DPTconfig 0x40 -#define PCI_REG_PumpModeAddress 0x44 -#define PCI_REG_PumpModeData 0x48 -#define PCI_REG_ConfigParam1 0x50 -#define PCI_REG_ConfigParam2 0x54 - - -#define EATA_CMD_PIO_SETUPTEST 0xc6 -#define EATA_CMD_PIO_READ_CONFIG 0xf0 -#define EATA_CMD_PIO_SET_CONFIG 0xf1 -#define EATA_CMD_PIO_SEND_CP 0xf2 -#define EATA_CMD_PIO_RECEIVE_SP 0xf3 -#define EATA_CMD_PIO_TRUNC 0xf4 - -#define EATA_CMD_RESET 0xf9 -#define EATA_CMD_IMMEDIATE 0xfa - -#define EATA_CMD_DMA_READ_CONFIG 0xfd -#define EATA_CMD_DMA_SET_CONFIG 0xfe -#define EATA_CMD_DMA_SEND_CP 0xff - -#define ECS_EMULATE_SENSE 0xd4 - -#define EATA_GENERIC_ABORT 0x00 -#define EATA_SPECIFIC_RESET 0x01 -#define EATA_BUS_RESET 0x02 -#define EATA_SPECIFIC_ABORT 0x03 -#define EATA_QUIET_INTR 0x04 -#define EATA_COLD_BOOT_HBA 0x06 /* Only as a last resort */ -#define EATA_FORCE_IO 0x07 - -#define HA_CTRLREG 0x206 /* control register for HBA */ -#define HA_CTRL_DISINT 0x02 /* CTRLREG: disable interrupts */ -#define HA_CTRL_RESCPU 0x04 /* CTRLREG: reset processor */ -#define HA_CTRL_8HEADS 0x08 /* CTRLREG: set for drives with* - * >=8 heads (WD1003 rudimentary :-) */ - -#define HA_WCOMMAND 0x07 /* command register offset */ -#define HA_WIFC 0x06 /* immediate command offset */ -#define HA_WCODE 0x05 -#define HA_WCODE2 0x04 -#define HA_WDMAADDR 0x02 /* DMA address LSB offset */ -#define HA_RAUXSTAT 0x08 /* aux status register offset*/ -#define HA_RSTATUS 0x07 /* status register offset */ -#define HA_RDATA 0x00 /* data register (16bit) */ -#define HA_WDATA 0x00 /* data register (16bit) */ - -#define HA_ABUSY 0x01 /* aux busy bit */ -#define HA_AIRQ 0x02 /* aux IRQ pending bit */ -#define HA_SERROR 0x01 /* pr. command ended in error*/ -#define HA_SMORE 0x02 /* more data soon to come */ -#define HA_SCORR 0x04 /* data corrected */ -#define HA_SDRQ 0x08 /* data request active */ -#define HA_SSC 0x10 /* seek complete */ -#define HA_SFAULT 0x20 /* write fault */ -#define HA_SREADY 0x40 /* drive ready */ -#define HA_SBUSY 0x80 /* drive busy */ -#define HA_SDRDY HA_SSC+HA_SREADY+HA_SDRQ - -/********************************************** - * Message definitions * - **********************************************/ - -#define HA_NO_ERROR 0x00 /* No Error */ -#define HA_ERR_SEL_TO 0x01 /* Selection Timeout */ -#define HA_ERR_CMD_TO 0x02 /* Command Timeout */ -#define HA_BUS_RESET 0x03 /* SCSI Bus Reset Received */ -#define HA_INIT_POWERUP 0x04 /* Initial Controller Power-up */ -#define HA_UNX_BUSPHASE 0x05 /* Unexpected Bus Phase */ -#define HA_UNX_BUS_FREE 0x06 /* Unexpected Bus Free */ -#define HA_BUS_PARITY 0x07 /* Bus Parity Error */ -#define HA_SCSI_HUNG 0x08 /* SCSI Hung */ -#define HA_UNX_MSGRJCT 0x09 /* Unexpected Message Rejected */ -#define HA_RESET_STUCK 0x0a /* SCSI Bus Reset Stuck */ -#define HA_RSENSE_FAIL 0x0b /* Auto Request-Sense Failed */ -#define HA_PARITY_ERR 0x0c /* Controller Ram Parity Error */ -#define HA_CP_ABORT_NA 0x0d /* Abort Message sent to non-active cmd */ -#define HA_CP_ABORTED 0x0e /* Abort Message sent to active cmd */ -#define HA_CP_RESET_NA 0x0f /* Reset Message sent to non-active cmd */ -#define HA_CP_RESET 0x10 /* Reset Message sent to active cmd */ -#define HA_ECC_ERR 0x11 /* Controller Ram ECC Error */ -#define HA_PCI_PARITY 0x12 /* PCI Parity Error */ -#define HA_PCI_MABORT 0x13 /* PCI Master Abort */ -#define HA_PCI_TABORT 0x14 /* PCI Target Abort */ -#define HA_PCI_STABORT 0x15 /* PCI Signaled Target Abort */ - -/********************************************** - * Other definitions * - **********************************************/ - -struct reg_bit { /* reading this one will clear the interrupt */ - __u8 error:1; /* previous command ended in an error */ - __u8 more:1; /* more DATA coming soon, poll BSY & DRQ (PIO) */ - __u8 corr:1; /* data read was successfully corrected with ECC*/ - __u8 drq:1; /* data request active */ - __u8 sc:1; /* seek complete */ - __u8 fault:1; /* write fault */ - __u8 ready:1; /* drive ready */ - __u8 busy:1; /* controller busy */ -}; - -struct reg_abit { /* reading this won't clear the interrupt */ - __u8 abusy:1; /* auxiliary busy */ - __u8 irq:1; /* set when drive interrupt is asserted */ - __u8 dummy:6; -}; - -struct eata_register { /* EATA register set */ - __u8 data_reg[2]; /* R, couldn't figure this one out */ - __u8 cp_addr[4]; /* W, CP address register */ - union { - __u8 command; /* W, command code: [read|set] conf, send CP*/ - struct reg_bit status; /* R, see register_bit1 */ - __u8 statusbyte; - } ovr; - struct reg_abit aux_stat; /* R, see register_bit2 */ -}; - -struct get_conf { /* Read Configuration Array */ - __u32 len; /* Should return 0x22, 0x24, etc */ - __u32 signature; /* Signature MUST be "EATA" */ - __u8 version2:4, - version:4; /* EATA Version level */ - __u8 OCS_enabled:1, /* Overlap Command Support enabled */ - TAR_support:1, /* SCSI Target Mode supported */ - TRNXFR:1, /* Truncate Transfer Cmd not necessary * - * Only used in PIO Mode */ - MORE_support:1, /* MORE supported (only PIO Mode) */ - DMA_support:1, /* DMA supported Driver uses only * - * this mode */ - DMA_valid:1, /* DRQ value in Byte 30 is valid */ - ATA:1, /* ATA device connected (not supported) */ - HAA_valid:1; /* Hostadapter Address is valid */ - - __u16 cppadlen; /* Number of pad bytes send after CD data * - * set to zero for DMA commands */ - __u8 scsi_id[4]; /* SCSI ID of controller 2-0 Byte 0 res. * - * if not, zero is returned */ - __u32 cplen; /* CP length: number of valid cp bytes */ - __u32 splen; /* Number of bytes returned after * - * Receive SP command */ - __u16 queuesiz; /* max number of queueable CPs */ - __u16 dummy; - __u16 SGsiz; /* max number of SG table entries */ - __u8 IRQ:4, /* IRQ used this HA */ - IRQ_TR:1, /* IRQ Trigger: 0=edge, 1=level */ - SECOND:1, /* This is a secondary controller */ - DMA_channel:2; /* DRQ index, DRQ is 2comp of DRQX */ - __u8 sync; /* device at ID 7 tru 0 is running in * - * synchronous mode, this will disappear */ - __u8 DSBLE:1, /* ISA i/o addressing is disabled */ - FORCADR:1, /* i/o address has been forced */ - SG_64K:1, - SG_UAE:1, - :4; - __u8 MAX_ID:5, /* Max number of SCSI target IDs */ - MAX_CHAN:3; /* Number of SCSI busses on HBA */ - __u8 MAX_LUN; /* Max number of LUNs */ - __u8 :3, - AUTOTRM:1, - M1_inst:1, - ID_qest:1, /* Raidnum ID is questionable */ - is_PCI:1, /* HBA is PCI */ - is_EISA:1; /* HBA is EISA */ - __u8 RAIDNUM; /* unique HBA identifier */ - __u8 unused[474]; -}; - -struct eata_sg_list -{ - __u32 data; - __u32 len; -}; - -struct eata_ccb { /* Send Command Packet structure */ - - __u8 SCSI_Reset:1, /* Cause a SCSI Bus reset on the cmd */ - HBA_Init:1, /* Cause Controller to reinitialize */ - Auto_Req_Sen:1, /* Do Auto Request Sense on errors */ - scatter:1, /* Data Ptr points to a SG Packet */ - Resrvd:1, /* RFU */ - Interpret:1, /* Interpret the SCSI cdb of own use */ - DataOut:1, /* Data Out phase with command */ - DataIn:1; /* Data In phase with command */ - __u8 reqlen; /* Request Sense Length * - * Valid if Auto_Req_Sen=1 */ - __u8 unused[3]; - __u8 FWNEST:1, /* send cmd to phys RAID component */ - unused2:7; - __u8 Phsunit:1, /* physical unit on mirrored pair */ - I_AT:1, /* inhibit address translation */ - I_HBA_C:1, /* HBA inhibit caching */ - unused3:5; - - __u8 cp_id:5, /* SCSI Device ID of target */ - cp_channel:3; /* SCSI Channel # of HBA */ - __u8 cp_lun:3, - :2, - cp_luntar:1, /* CP is for target ROUTINE */ - cp_dispri:1, /* Grant disconnect privilege */ - cp_identify:1; /* Always TRUE */ - __u8 cp_msg1; /* Message bytes 0-3 */ - __u8 cp_msg2; - __u8 cp_msg3; - __u8 cp_cdb[12]; /* Command Descriptor Block */ - __u32 cp_datalen; /* Data Transfer Length * - * If scatter=1 len of sg package */ - void *cp_viraddr; /* address of this ccb */ - __u32 cp_dataDMA; /* Data Address, if scatter=1 * - * address of scatter packet */ - __u32 cp_statDMA; /* address for Status Packet */ - __u32 cp_reqDMA; /* Request Sense Address, used if * - * CP command ends with error */ - /* Additional CP info begins here */ - __u32 timestamp; /* Needed to measure command latency */ - __u32 timeout; - __u8 sizeindex; - __u8 rw_latency; - __u8 retries; - __u8 status; /* status of this queueslot */ - struct scsi_cmnd *cmd; /* address of cmd */ - struct eata_sg_list *sg_list; -}; - - -struct eata_sp { - __u8 hba_stat:7, /* HBA status */ - EOC:1; /* True if command finished */ - __u8 scsi_stat; /* Target SCSI status */ - __u8 reserved[2]; - __u32 residue_len; /* Number of bytes not transferred */ - struct eata_ccb *ccb; /* Address set in COMMAND PACKET */ - __u8 msg[12]; -}; - -typedef struct hstd { - __u8 vendor[9]; - __u8 name[18]; - __u8 revision[6]; - __u8 EATA_revision; - __u32 firmware_revision; - __u8 HBA_number; - __u8 bustype; /* bustype of HBA */ - __u8 channel; /* # of avail. scsi channels */ - __u8 state; /* state of HBA */ - __u8 primary; /* true if primary */ - __u8 more_support:1, /* HBA supports MORE flag */ - immediate_support:1, /* HBA supports IMMEDIATE CMDs*/ - broken_INQUIRY:1; /* This is an EISA HBA with * - * broken INQUIRY */ - __u8 do_latency; /* Latency measurement flag */ - __u32 reads[13]; - __u32 writes[13]; - __u32 reads_lat[12][4]; - __u32 writes_lat[12][4]; - __u32 all_lat[4]; - __u8 resetlevel[MAXCHANNEL]; - __u32 last_ccb; /* Last used ccb */ - __u32 cplen; /* size of CP in words */ - __u16 cppadlen; /* pad length of cp in words */ - __u16 queuesize; - __u16 sgsize; /* # of entries in the SG list*/ - __u16 devflags; /* bits set for detected devices */ - __u8 hostid; /* SCSI ID of HBA */ - __u8 moresupport; /* HBA supports MORE flag */ - struct Scsi_Host *next; - struct Scsi_Host *prev; - struct pci_dev *pdev; /* PCI device or NULL for non PCI */ - struct eata_sp sp; /* status packet */ - struct eata_ccb ccb[0]; /* ccb array begins here */ -}hostdata; - -/* structure for max. 2 emulated drives */ -struct drive_geom_emul { - __u8 trans; /* translation flag 1=transl */ - __u8 channel; /* SCSI channel number */ - __u8 HBA; /* HBA number (prim/sec) */ - __u8 id; /* drive id */ - __u8 lun; /* drive lun */ - __u32 heads; /* number of heads */ - __u32 sectors; /* number of sectors */ - __u32 cylinder; /* number of cylinders */ -}; - -struct geom_emul { - __u8 bios_drives; /* number of emulated drives */ - struct drive_geom_emul drv[2]; /* drive structures */ -}; - -#endif /* _EATA_GENERIC_H */ - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 4 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -4 - * c-argdecl-indent: 4 - * c-label-offset: -4 - * c-continued-statement-offset: 4 - * c-continued-brace-offset: 0 - * tab-width: 8 - * End: - */ diff --git a/ANDROID_3.4.5/drivers/scsi/eata_pio.c b/ANDROID_3.4.5/drivers/scsi/eata_pio.c deleted file mode 100644 index d5f83623..00000000 --- a/ANDROID_3.4.5/drivers/scsi/eata_pio.c +++ /dev/null @@ -1,1001 +0,0 @@ -/************************************************************ - * * - * Linux EATA SCSI PIO driver * - * * - * based on the CAM document CAM/89-004 rev. 2.0c, * - * DPT's driver kit, some internal documents and source, * - * and several other Linux scsi drivers and kernel docs. * - * * - * The driver currently: * - * -supports all EATA-PIO boards * - * -only supports DASD devices * - * * - * (c)1993-96 Michael Neuffer, Alfred Arnold * - * neuffer@goofy.zdv.uni-mainz.de * - * a.arnold@kfa-juelich.de * - * * - * Updated 2002 by Alan Cox for * - * Linux 2.5.x and the newer locking and error handling * - * * - * This program is free software; you can redistribute it * - * and/or modify it under the terms of the GNU General * - * Public License as published by the Free Software * - * Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be * - * useful, but WITHOUT ANY WARRANTY; without even the * - * implied warranty of MERCHANTABILITY or FITNESS FOR A * - * PARTICULAR PURPOSE. See the GNU General Public License * - * for more details. * - * * - * You should have received a copy of the GNU General * - * Public License along with this kernel; if not, write to * - * the Free Software Foundation, Inc., 675 Mass Ave, * - * Cambridge, MA 02139, USA. * - * * - * For the avoidance of doubt the "preferred form" of this * - * code is one which is in an open non patent encumbered * - * format. Where cryptographic key signing forms part of * - * the process of creating an executable the information * - * including keys needed to generate an equivalently * - * functional executable are deemed to be part of the * - * source code are deemed to be part of the source code. * - * * - ************************************************************ - * last change: 2002/11/02 OS: Linux 2.5.45 * - ************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include "eata_generic.h" -#include "eata_pio.h" - - -static unsigned int ISAbases[MAXISA] = { - 0x1F0, 0x170, 0x330, 0x230 -}; - -static unsigned int ISAirqs[MAXISA] = { - 14, 12, 15, 11 -}; - -static unsigned char EISAbases[] = { - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1 -}; - -static unsigned int registered_HBAs; -static struct Scsi_Host *last_HBA; -static struct Scsi_Host *first_HBA; -static unsigned char reg_IRQ[16]; -static unsigned char reg_IRQL[16]; -static unsigned long int_counter; -static unsigned long queue_counter; - -static struct scsi_host_template driver_template; - -/* - * eata_proc_info - * inout : decides on the direction of the dataflow and the meaning of the - * variables - * buffer: If inout==FALSE data is being written to it else read from it - * *start: If inout==FALSE start of the valid data in the buffer - * offset: If inout==FALSE offset from the beginning of the imaginary file - * from which we start writing into the buffer - * length: If inout==FALSE max number of bytes to be written into the buffer - * else number of bytes in the buffer - */ -static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, - int length, int rw) -{ - int len = 0; - off_t begin = 0, pos = 0; - - if (rw) - return -ENOSYS; - - len += sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: " - "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB); - len += sprintf(buffer + len, "queued commands: %10ld\n" - "processed interrupts:%10ld\n", queue_counter, int_counter); - len += sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n", - shost->host_no, SD(shost)->name); - len += sprintf(buffer + len, "Firmware revision: v%s\n", - SD(shost)->revision); - len += sprintf(buffer + len, "IO: PIO\n"); - len += sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base); - len += sprintf(buffer + len, "Host Bus: %s\n", - (SD(shost)->bustype == 'P')?"PCI ": - (SD(shost)->bustype == 'E')?"EISA":"ISA "); - - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - -stop_output: - DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len)); - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - len = length; /* Ending slop */ - DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len)); - - return len; -} - -static int eata_pio_release(struct Scsi_Host *sh) -{ - hostdata *hd = SD(sh); - if (sh->irq && reg_IRQ[sh->irq] == 1) - free_irq(sh->irq, NULL); - else - reg_IRQ[sh->irq]--; - if (SD(sh)->channel == 0) { - if (sh->io_port && sh->n_io_port) - release_region(sh->io_port, sh->n_io_port); - } - /* At this point the PCI reference can go */ - if (hd->pdev) - pci_dev_put(hd->pdev); - return 1; -} - -static void IncStat(struct scsi_pointer *SCp, unsigned int Increment) -{ - SCp->ptr += Increment; - if ((SCp->this_residual -= Increment) == 0) { - if ((--SCp->buffers_residual) == 0) - SCp->Status = 0; - else { - SCp->buffer++; - SCp->ptr = sg_virt(SCp->buffer); - SCp->this_residual = SCp->buffer->length; - } - } -} - -static irqreturn_t eata_pio_int_handler(int irq, void *dev_id); - -static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - irqreturn_t ret; - - spin_lock_irqsave(dev->host_lock, flags); - ret = eata_pio_int_handler(irq, dev_id); - spin_unlock_irqrestore(dev->host_lock, flags); - return ret; -} - -static irqreturn_t eata_pio_int_handler(int irq, void *dev_id) -{ - unsigned int eata_stat = 0xfffff; - struct scsi_cmnd *cmd; - hostdata *hd; - struct eata_ccb *cp; - unsigned long base; - unsigned int x, z; - struct Scsi_Host *sh; - unsigned short zwickel = 0; - unsigned char stat, odd; - irqreturn_t ret = IRQ_NONE; - - for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) - { - if (sh->irq != irq) - continue; - if (inb(sh->base + HA_RSTATUS) & HA_SBUSY) - continue; - - int_counter++; - ret = IRQ_HANDLED; - - hd = SD(sh); - - cp = &hd->ccb[0]; - cmd = cp->cmd; - base = cmd->device->host->base; - - do { - stat = inb(base + HA_RSTATUS); - if (stat & HA_SDRQ) { - if (cp->DataIn) { - z = 256; - odd = 0; - while ((cmd->SCp.Status) && ((z > 0) || (odd))) { - if (odd) { - *(cmd->SCp.ptr) = zwickel >> 8; - IncStat(&cmd->SCp, 1); - odd = 0; - } - x = min_t(unsigned int, z, cmd->SCp.this_residual / 2); - insw(base + HA_RDATA, cmd->SCp.ptr, x); - z -= x; - IncStat(&cmd->SCp, 2 * x); - if ((z > 0) && (cmd->SCp.this_residual == 1)) { - zwickel = inw(base + HA_RDATA); - *(cmd->SCp.ptr) = zwickel & 0xff; - IncStat(&cmd->SCp, 1); - z--; - odd = 1; - } - } - while (z > 0) { - zwickel = inw(base + HA_RDATA); - z--; - } - } else { /* cp->DataOut */ - - odd = 0; - z = 256; - while ((cmd->SCp.Status) && ((z > 0) || (odd))) { - if (odd) { - zwickel += *(cmd->SCp.ptr) << 8; - IncStat(&cmd->SCp, 1); - outw(zwickel, base + HA_RDATA); - z--; - odd = 0; - } - x = min_t(unsigned int, z, cmd->SCp.this_residual / 2); - outsw(base + HA_RDATA, cmd->SCp.ptr, x); - z -= x; - IncStat(&cmd->SCp, 2 * x); - if ((z > 0) && (cmd->SCp.this_residual == 1)) { - zwickel = *(cmd->SCp.ptr); - zwickel &= 0xff; - IncStat(&cmd->SCp, 1); - odd = 1; - } - } - while (z > 0 || odd) { - outw(zwickel, base + HA_RDATA); - z--; - odd = 0; - } - } - } - } - while ((stat & HA_SDRQ) || ((stat & HA_SMORE) && hd->moresupport)); - - /* terminate handler if HBA goes busy again, i.e. transfers - * more data */ - - if (stat & HA_SBUSY) - break; - - /* OK, this is quite stupid, but I haven't found any correct - * way to get HBA&SCSI status so far */ - - if (!(inb(base + HA_RSTATUS) & HA_SERROR)) { - cmd->result = (DID_OK << 16); - hd->devflags |= (1 << cp->cp_id); - } else if (hd->devflags & (1 << cp->cp_id)) - cmd->result = (DID_OK << 16) + 0x02; - else - cmd->result = (DID_NO_CONNECT << 16); - - if (cp->status == LOCKED) { - cp->status = FREE; - eata_stat = inb(base + HA_RSTATUS); - printk(KERN_CRIT "eata_pio: int_handler, freeing locked " "queueslot\n"); - return ret; - } -#if DBG_INTR2 - if (stat != 0x50) - printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, cmd->result); -#endif - - cp->status = FREE; /* now we can release the slot */ - - cmd->scsi_done(cmd); - } - - return ret; -} - -static inline unsigned int eata_pio_send_command(unsigned long base, unsigned char command) -{ - unsigned int loop = 50; - - while (inb(base + HA_RSTATUS) & HA_SBUSY) - if (--loop == 0) - return 1; - - /* Enable interrupts for HBA. It is not the best way to do it at this - * place, but I hope that it doesn't interfere with the IDE driver - * initialization this way */ - - outb(HA_CTRL_8HEADS, base + HA_CTRLREG); - - outb(command, base + HA_WCOMMAND); - return 0; -} - -static int eata_pio_queue_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - unsigned int x, y; - unsigned long base; - - hostdata *hd; - struct Scsi_Host *sh; - struct eata_ccb *cp; - - queue_counter++; - - hd = HD(cmd); - sh = cmd->device->host; - base = sh->base; - - /* use only slot 0, as 2001 can handle only one cmd at a time */ - - y = x = 0; - - if (hd->ccb[y].status != FREE) { - - DBG(DBG_QUEUE, printk(KERN_EMERG "can_queue %d, x %d, y %d\n", sh->can_queue, x, y)); -#if DEBUG_EATA - panic(KERN_EMERG "eata_pio: run out of queue slots cmdno:%ld " "intrno: %ld\n", queue_counter, int_counter); -#else - panic(KERN_EMERG "eata_pio: run out of queue slots....\n"); -#endif - } - - cp = &hd->ccb[y]; - - memset(cp, 0, sizeof(struct eata_ccb)); - - cp->status = USED; /* claim free slot */ - - DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, - "eata_pio_queue 0x%p, y %d\n", cmd, y)); - - cmd->scsi_done = (void *) done; - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - cp->DataOut = 1; /* Output mode */ - else - cp->DataIn = 0; /* Input mode */ - - cp->Interpret = (cmd->device->id == hd->hostid); - cp->cp_datalen = cpu_to_be32(scsi_bufflen(cmd)); - cp->Auto_Req_Sen = 0; - cp->cp_reqDMA = 0; - cp->reqlen = 0; - - cp->cp_id = cmd->device->id; - cp->cp_lun = cmd->device->lun; - cp->cp_dispri = 0; - cp->cp_identify = 1; - memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd)); - - cp->cp_statDMA = 0; - - cp->cp_viraddr = cp; - cp->cmd = cmd; - cmd->host_scribble = (char *) &hd->ccb[y]; - - if (!scsi_bufflen(cmd)) { - cmd->SCp.buffers_residual = 1; - cmd->SCp.ptr = NULL; - cmd->SCp.this_residual = 0; - cmd->SCp.buffer = NULL; - } else { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd); - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - } - cmd->SCp.Status = (cmd->SCp.this_residual != 0); /* TRUE as long as bytes - * are to transfer */ - - if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) { - cmd->result = DID_BUS_BUSY << 16; - scmd_printk(KERN_NOTICE, cmd, - "eata_pio_queue pid 0x%p, HBA busy, " - "returning DID_BUS_BUSY, done.\n", cmd); - done(cmd); - cp->status = FREE; - return 0; - } - /* FIXME: timeout */ - while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - cpu_relax(); - outsw(base + HA_RDATA, cp, hd->cplen); - outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND); - for (x = 0; x < hd->cppadlen; x++) - outw(0, base + HA_RDATA); - - DBG(DBG_QUEUE, scmd_printk(KERN_DEBUG, cmd, - "Queued base %#.4lx cmd: 0x%p " - "slot %d irq %d\n", sh->base, cmd, y, sh->irq)); - - return 0; -} - -static DEF_SCSI_QCMD(eata_pio_queue) - -static int eata_pio_abort(struct scsi_cmnd *cmd) -{ - unsigned int loop = 100; - - DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, - "eata_pio_abort called pid: 0x%p\n", cmd)); - - while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY) - if (--loop == 0) { - printk(KERN_WARNING "eata_pio: abort, timeout error.\n"); - return FAILED; - } - if (CD(cmd)->status == FREE) { - DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_NOT_RUNNING\n")); - return FAILED; - } - if (CD(cmd)->status == USED) { - DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_BUSY\n")); - /* We want to sleep a bit more here */ - return FAILED; /* SNOOZE */ - } - if (CD(cmd)->status == RESET) { - printk(KERN_WARNING "eata_pio: abort, command reset error.\n"); - return FAILED; - } - if (CD(cmd)->status == LOCKED) { - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot " "locked.\n")); - return FAILED; - } - panic("eata_pio: abort: invalid slot status\n"); -} - -static int eata_pio_host_reset(struct scsi_cmnd *cmd) -{ - unsigned int x, limit = 0; - unsigned char success = 0; - struct scsi_cmnd *sp; - struct Scsi_Host *host = cmd->device->host; - - DBG(DBG_ABNORM, scmd_printk(KERN_WARNING, cmd, - "eata_pio_reset called\n")); - - spin_lock_irq(host->host_lock); - - if (HD(cmd)->state == RESET) { - printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n"); - spin_unlock_irq(host->host_lock); - return FAILED; - } - - /* force all slots to be free */ - - for (x = 0; x < cmd->device->host->can_queue; x++) { - - if (HD(cmd)->ccb[x].status == FREE) - continue; - - sp = HD(cmd)->ccb[x].cmd; - HD(cmd)->ccb[x].status = RESET; - printk(KERN_WARNING "eata_pio_reset: slot %d in reset.\n", x); - - if (sp == NULL) - panic("eata_pio_reset: slot %d, sp==NULL.\n", x); - } - - /* hard reset the HBA */ - outb(EATA_CMD_RESET, cmd->device->host->base + HA_WCOMMAND); - - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n")); - HD(cmd)->state = RESET; - - spin_unlock_irq(host->host_lock); - msleep(3000); - spin_lock_irq(host->host_lock); - - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, " "loops %d.\n", limit)); - - for (x = 0; x < cmd->device->host->can_queue; x++) { - - /* Skip slots already set free by interrupt */ - if (HD(cmd)->ccb[x].status != RESET) - continue; - - sp = HD(cmd)->ccb[x].cmd; - sp->result = DID_RESET << 16; - - /* This mailbox is terminated */ - printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n", x); - HD(cmd)->ccb[x].status = FREE; - - sp->scsi_done(sp); - } - - HD(cmd)->state = 0; - - spin_unlock_irq(host->host_lock); - - if (success) { /* hmmm... */ - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n")); - return SUCCESS; - } else { - DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n")); - return FAILED; - } -} - -static char *get_pio_board_data(unsigned long base, unsigned int irq, unsigned int id, unsigned long cplen, unsigned short cppadlen) -{ - struct eata_ccb cp; - static char buff[256]; - int z; - - memset(&cp, 0, sizeof(struct eata_ccb)); - memset(buff, 0, sizeof(buff)); - - cp.DataIn = 1; - cp.Interpret = 1; /* Interpret command */ - - cp.cp_datalen = cpu_to_be32(254); - cp.cp_dataDMA = cpu_to_be32(0); - - cp.cp_id = id; - cp.cp_lun = 0; - - cp.cp_cdb[0] = INQUIRY; - cp.cp_cdb[1] = 0; - cp.cp_cdb[2] = 0; - cp.cp_cdb[3] = 0; - cp.cp_cdb[4] = 254; - cp.cp_cdb[5] = 0; - - if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) - return NULL; - - while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - cpu_relax(); - - outsw(base + HA_RDATA, &cp, cplen); - outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND); - for (z = 0; z < cppadlen; z++) - outw(0, base + HA_RDATA); - - while (inb(base + HA_RSTATUS) & HA_SBUSY) - cpu_relax(); - - if (inb(base + HA_RSTATUS) & HA_SERROR) - return NULL; - else if (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - return NULL; - else { - insw(base + HA_RDATA, &buff, 127); - while (inb(base + HA_RSTATUS) & HA_SDRQ) - inw(base + HA_RDATA); - return buff; - } -} - -static int get_pio_conf_PIO(unsigned long base, struct get_conf *buf) -{ - unsigned long loop = HZ / 2; - int z; - unsigned short *p; - - if (!request_region(base, 9, "eata_pio")) - return 0; - - memset(buf, 0, sizeof(struct get_conf)); - - while (inb(base + HA_RSTATUS) & HA_SBUSY) - if (--loop == 0) - goto fail; - - DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#lx\n", base)); - eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG); - - loop = 50; - for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) { - while (!(inb(base + HA_RSTATUS) & HA_SDRQ)) - if (--loop == 0) - goto fail; - - loop = 50; - *p = inw(base + HA_RDATA); - } - if (inb(base + HA_RSTATUS) & HA_SERROR) { - DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during " - "transfer for HBA at %lx\n", base)); - goto fail; - } - - if (cpu_to_be32(EATA_SIGNATURE) != buf->signature) - goto fail; - - DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found " - "at %#4lx EATA Level: %x\n", - base, (unsigned int) (buf->version))); - - while (inb(base + HA_RSTATUS) & HA_SDRQ) - inw(base + HA_RDATA); - - if (!ALLOW_DMA_BOARDS) { - for (z = 0; z < MAXISA; z++) - if (base == ISAbases[z]) { - buf->IRQ = ISAirqs[z]; - break; - } - } - - return 1; - - fail: - release_region(base, 9); - return 0; -} - -static void print_pio_config(struct get_conf *gc) -{ - printk("Please check values: (read config data)\n"); - printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", be32_to_cpu(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support); - printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], be16_to_cpu(gc->queuesiz), be16_to_cpu(gc->SGsiz), gc->SECOND); - printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n", gc->IRQ, gc->IRQ_TR, gc->FORCADR, gc->MAX_CHAN, gc->ID_qest); -} - -static unsigned int print_selftest(unsigned int base) -{ - unsigned char buffer[512]; -#ifdef VERBOSE_SETUP - int z; -#endif - - printk("eata_pio: executing controller self test & setup...\n"); - while (inb(base + HA_RSTATUS) & HA_SBUSY); - outb(EATA_CMD_PIO_SETUPTEST, base + HA_WCOMMAND); - do { - while (inb(base + HA_RSTATUS) & HA_SBUSY) - /* nothing */ ; - if (inb(base + HA_RSTATUS) & HA_SDRQ) { - insw(base + HA_RDATA, &buffer, 256); -#ifdef VERBOSE_SETUP - /* no beeps please... */ - for (z = 0; z < 511 && buffer[z]; z++) - if (buffer[z] != 7) - printk("%c", buffer[z]); -#endif - } - } while (inb(base + HA_RSTATUS) & (HA_SBUSY | HA_SDRQ)); - - return (!(inb(base + HA_RSTATUS) & HA_SERROR)); -} - -static int register_pio_HBA(long base, struct get_conf *gc, struct pci_dev *pdev) -{ - unsigned long size = 0; - char *buff; - unsigned long cplen; - unsigned short cppadlen; - struct Scsi_Host *sh; - hostdata *hd; - - DBG(DBG_REGISTER, print_pio_config(gc)); - - if (gc->DMA_support) { - printk("HBA at %#.4lx supports DMA. Please use EATA-DMA driver.\n", base); - if (!ALLOW_DMA_BOARDS) - return 0; - } - - if ((buff = get_pio_board_data(base, gc->IRQ, gc->scsi_id[3], cplen = (cpu_to_be32(gc->cplen) + 1) / 2, cppadlen = (cpu_to_be16(gc->cppadlen) + 1) / 2)) == NULL) { - printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", base); - return 0; - } - - if (!print_selftest(base) && !ALLOW_DMA_BOARDS) { - printk("HBA at %#lx failed while performing self test & setup.\n", base); - return 0; - } - - size = sizeof(hostdata) + (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz)); - - sh = scsi_register(&driver_template, size); - if (sh == NULL) - return 0; - - if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */ - if (!request_irq(gc->IRQ, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", sh)) { - reg_IRQ[gc->IRQ]++; - if (!gc->IRQ_TR) - reg_IRQL[gc->IRQ] = 1; /* IRQ is edge triggered */ - } else { - printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ); - return 0; - } - } else { /* More than one HBA on this IRQ */ - if (reg_IRQL[gc->IRQ]) { - printk("Can't support more than one HBA on this IRQ,\n" " if the IRQ is edge triggered. Sorry.\n"); - return 0; - } else - reg_IRQ[gc->IRQ]++; - } - - hd = SD(sh); - - memset(hd->ccb, 0, (sizeof(struct eata_ccb) * be16_to_cpu(gc->queuesiz))); - memset(hd->reads, 0, sizeof(hd->reads)); - - strlcpy(SD(sh)->vendor, &buff[8], sizeof(SD(sh)->vendor)); - strlcpy(SD(sh)->name, &buff[16], sizeof(SD(sh)->name)); - SD(sh)->revision[0] = buff[32]; - SD(sh)->revision[1] = buff[33]; - SD(sh)->revision[2] = buff[34]; - SD(sh)->revision[3] = '.'; - SD(sh)->revision[4] = buff[35]; - SD(sh)->revision[5] = 0; - - switch (be32_to_cpu(gc->len)) { - case 0x1c: - SD(sh)->EATA_revision = 'a'; - break; - case 0x1e: - SD(sh)->EATA_revision = 'b'; - break; - case 0x22: - SD(sh)->EATA_revision = 'c'; - break; - case 0x24: - SD(sh)->EATA_revision = 'z'; - default: - SD(sh)->EATA_revision = '?'; - } - - if (be32_to_cpu(gc->len) >= 0x22) { - if (gc->is_PCI) - hd->bustype = IS_PCI; - else if (gc->is_EISA) - hd->bustype = IS_EISA; - else - hd->bustype = IS_ISA; - } else { - if (buff[21] == '4') - hd->bustype = IS_PCI; - else if (buff[21] == '2') - hd->bustype = IS_EISA; - else - hd->bustype = IS_ISA; - } - - SD(sh)->cplen = cplen; - SD(sh)->cppadlen = cppadlen; - SD(sh)->hostid = gc->scsi_id[3]; - SD(sh)->devflags = 1 << gc->scsi_id[3]; - SD(sh)->moresupport = gc->MORE_support; - sh->unique_id = base; - sh->base = base; - sh->io_port = base; - sh->n_io_port = 9; - sh->irq = gc->IRQ; - sh->dma_channel = PIO; - sh->this_id = gc->scsi_id[3]; - sh->can_queue = 1; - sh->cmd_per_lun = 1; - sh->sg_tablesize = SG_ALL; - - hd->channel = 0; - - hd->pdev = pci_dev_get(pdev); /* Keep a PCI reference */ - - sh->max_id = 8; - sh->max_lun = 8; - - if (gc->SECOND) - hd->primary = 0; - else - hd->primary = 1; - - hd->next = NULL; /* build a linked list of all HBAs */ - hd->prev = last_HBA; - if (hd->prev != NULL) - SD(hd->prev)->next = sh; - last_HBA = sh; - if (first_HBA == NULL) - first_HBA = sh; - registered_HBAs++; - return (1); -} - -static void find_pio_ISA(struct get_conf *buf) -{ - int i; - - for (i = 0; i < MAXISA; i++) { - if (!ISAbases[i]) - continue; - if (!get_pio_conf_PIO(ISAbases[i], buf)) - continue; - if (!register_pio_HBA(ISAbases[i], buf, NULL)) - release_region(ISAbases[i], 9); - else - ISAbases[i] = 0; - } - return; -} - -static void find_pio_EISA(struct get_conf *buf) -{ - u32 base; - int i; - -#ifdef CHECKPAL - u8 pal1, pal2, pal3; -#endif - - for (i = 0; i < MAXEISA; i++) { - if (EISAbases[i]) { /* Still a possibility ? */ - - base = 0x1c88 + (i * 0x1000); -#ifdef CHECKPAL - pal1 = inb((u16) base - 8); - pal2 = inb((u16) base - 7); - pal3 = inb((u16) base - 6); - - if (((pal1 == 0x12) && (pal2 == 0x14)) || ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) || ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) { - DBG(DBG_PROBE, printk(KERN_NOTICE "EISA EATA id tags found: " "%x %x %x \n", (int) pal1, (int) pal2, (int) pal3)); -#endif - if (get_pio_conf_PIO(base, buf)) { - DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf)); - if (buf->IRQ) { - if (!register_pio_HBA(base, buf, NULL)) - release_region(base, 9); - } else { - printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n"); - release_region(base, 9); - } - } - /* Nothing found here so we take it from the list */ - EISAbases[i] = 0; -#ifdef CHECKPAL - } -#endif - } - } - return; -} - -static void find_pio_PCI(struct get_conf *buf) -{ -#ifndef CONFIG_PCI - printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n"); -#else - struct pci_dev *dev = NULL; - unsigned long base, x; - - while ((dev = pci_get_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) { - DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", pci_name(dev))); - if (pci_enable_device(dev)) - continue; - pci_set_master(dev); - base = pci_resource_flags(dev, 0); - if (base & IORESOURCE_MEM) { - printk("eata_pio: invalid base address of device %s\n", pci_name(dev)); - continue; - } - base = pci_resource_start(dev, 0); - /* EISA tag there ? */ - if ((inb(base) == 0x12) && (inb(base + 1) == 0x14)) - continue; /* Jep, it's forced, so move on */ - base += 0x10; /* Now, THIS is the real address */ - if (base != 0x1f8) { - /* We didn't find it in the primary search */ - if (get_pio_conf_PIO(base, buf)) { - if (buf->FORCADR) { /* If the address is forced */ - release_region(base, 9); - continue; /* we'll find it later */ - } - - /* OK. We made it till here, so we can go now - * and register it. We only have to check and - * eventually remove it from the EISA and ISA list - */ - - if (!register_pio_HBA(base, buf, dev)) { - release_region(base, 9); - continue; - } - - if (base < 0x1000) { - for (x = 0; x < MAXISA; ++x) { - if (ISAbases[x] == base) { - ISAbases[x] = 0; - break; - } - } - } else if ((base & 0x0fff) == 0x0c88) { - x = (base >> 12) & 0x0f; - EISAbases[x] = 0; - } - } -#ifdef CHECK_BLINK - else if (check_blink_state(base)) { - printk("eata_pio: HBA is in BLINK state.\n" "Consult your HBAs manual to correct this.\n"); - } -#endif - } - } -#endif /* #ifndef CONFIG_PCI */ -} - -static int eata_pio_detect(struct scsi_host_template *tpnt) -{ - struct Scsi_Host *HBA_ptr; - struct get_conf gc; - int i; - - find_pio_PCI(&gc); - find_pio_EISA(&gc); - find_pio_ISA(&gc); - - for (i = 0; i <= MAXIRQ; i++) - if (reg_IRQ[i]) - request_irq(i, do_eata_pio_int_handler, IRQF_DISABLED, "EATA-PIO", NULL); - - HBA_ptr = first_HBA; - - if (registered_HBAs != 0) { - printk("EATA (Extended Attachment) PIO driver version: %d.%d%s\n" - "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n" " Alfred Arnold, a.arnold@kfa-juelich.de\n" "This release only supports DASD devices (harddisks)\n", VER_MAJOR, VER_MINOR, VER_SUB); - - printk("Registered HBAs:\n"); - printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:" " QS: SG: CPL:\n"); - for (i = 1; i <= registered_HBAs; i++) { - printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4lx %2d %d %d %c" - " %2d %2d %2d\n", - HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision, - SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P') ? - "PCI " : (SD(HBA_ptr)->bustype == 'E') ? "EISA" : "ISA ", - HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id, - SD(HBA_ptr)->primary ? 'Y' : 'N', HBA_ptr->can_queue, - HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun); - HBA_ptr = SD(HBA_ptr)->next; - } - } - return (registered_HBAs); -} - -static struct scsi_host_template driver_template = { - .proc_name = "eata_pio", - .name = "EATA (Extended Attachment) PIO driver", - .proc_info = eata_pio_proc_info, - .detect = eata_pio_detect, - .release = eata_pio_release, - .queuecommand = eata_pio_queue, - .eh_abort_handler = eata_pio_abort, - .eh_host_reset_handler = eata_pio_host_reset, - .use_clustering = ENABLE_CLUSTERING, -}; - -MODULE_AUTHOR("Michael Neuffer, Alfred Arnold"); -MODULE_DESCRIPTION("EATA SCSI PIO driver"); -MODULE_LICENSE("GPL"); - -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/eata_pio.h b/ANDROID_3.4.5/drivers/scsi/eata_pio.h deleted file mode 100644 index 7deeb935..00000000 --- a/ANDROID_3.4.5/drivers/scsi/eata_pio.h +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************** -* Header file for eata_pio.c Linux EATA-PIO SCSI driver * -* (c) 1993-96 Michael Neuffer * -********************************************************* -* last change: 2002/11/02 * -********************************************************/ - - -#ifndef _EATA_PIO_H -#define _EATA_PIO_H - -#define VER_MAJOR 0 -#define VER_MINOR 0 -#define VER_SUB "1b" - -/************************************************************************ - * Here you can switch parts of the code on and of * - ************************************************************************/ - -#define VERBOSE_SETUP /* show startup screen of 2001 */ -#define ALLOW_DMA_BOARDS 1 - -/************************************************************************ - * Debug options. * - * Enable DEBUG and whichever options you require. * - ************************************************************************/ -#define DEBUG_EATA 1 /* Enable debug code. */ -#define DPT_DEBUG 0 /* Bobs special */ -#define DBG_DELAY 0 /* Build in delays so debug messages can be - * be read before they vanish of the top of - * the screen! - */ -#define DBG_PROBE 0 /* Debug probe routines. */ -#define DBG_ISA 0 /* Trace ISA routines */ -#define DBG_EISA 0 /* Trace EISA routines */ -#define DBG_PCI 0 /* Trace PCI routines */ -#define DBG_PIO 0 /* Trace get_config_PIO */ -#define DBG_COM 0 /* Trace command call */ -#define DBG_QUEUE 0 /* Trace command queueing. */ -#define DBG_INTR 0 /* Trace interrupt service routine. */ -#define DBG_INTR2 0 /* Trace interrupt service routine. */ -#define DBG_PROC 0 /* Debug proc-fs related statistics */ -#define DBG_PROC_WRITE 0 -#define DBG_REGISTER 0 /* */ -#define DBG_ABNORM 1 /* Debug abnormal actions (reset, abort) */ - -#if DEBUG_EATA -#define DBG(x, y) if ((x)) {y;} -#else -#define DBG(x, y) -#endif - -#endif /* _EATA_PIO_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/esp_scsi.c b/ANDROID_3.4.5/drivers/scsi/esp_scsi.c deleted file mode 100644 index 394ed9e7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/esp_scsi.c +++ /dev/null @@ -1,2734 +0,0 @@ -/* esp_scsi.c: ESP SCSI driver. - * - * Copyright (C) 2007 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "esp_scsi.h" - -#define DRV_MODULE_NAME "esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "2.000" -#define DRV_MODULE_RELDATE "April 19, 2007" - -/* SCSI bus reset settle time in seconds. */ -static int esp_bus_reset_settle = 3; - -static u32 esp_debug; -#define ESP_DEBUG_INTR 0x00000001 -#define ESP_DEBUG_SCSICMD 0x00000002 -#define ESP_DEBUG_RESET 0x00000004 -#define ESP_DEBUG_MSGIN 0x00000008 -#define ESP_DEBUG_MSGOUT 0x00000010 -#define ESP_DEBUG_CMDDONE 0x00000020 -#define ESP_DEBUG_DISCONNECT 0x00000040 -#define ESP_DEBUG_DATASTART 0x00000080 -#define ESP_DEBUG_DATADONE 0x00000100 -#define ESP_DEBUG_RECONNECT 0x00000200 -#define ESP_DEBUG_AUTOSENSE 0x00000400 - -#define esp_log_intr(f, a...) \ -do { if (esp_debug & ESP_DEBUG_INTR) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_reset(f, a...) \ -do { if (esp_debug & ESP_DEBUG_RESET) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_msgin(f, a...) \ -do { if (esp_debug & ESP_DEBUG_MSGIN) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_msgout(f, a...) \ -do { if (esp_debug & ESP_DEBUG_MSGOUT) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_cmddone(f, a...) \ -do { if (esp_debug & ESP_DEBUG_CMDDONE) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_disconnect(f, a...) \ -do { if (esp_debug & ESP_DEBUG_DISCONNECT) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_datastart(f, a...) \ -do { if (esp_debug & ESP_DEBUG_DATASTART) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_datadone(f, a...) \ -do { if (esp_debug & ESP_DEBUG_DATADONE) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_reconnect(f, a...) \ -do { if (esp_debug & ESP_DEBUG_RECONNECT) \ - printk(f, ## a); \ -} while (0) - -#define esp_log_autosense(f, a...) \ -do { if (esp_debug & ESP_DEBUG_AUTOSENSE) \ - printk(f, ## a); \ -} while (0) - -#define esp_read8(REG) esp->ops->esp_read8(esp, REG) -#define esp_write8(VAL,REG) esp->ops->esp_write8(esp, VAL, REG) - -static void esp_log_fill_regs(struct esp *esp, - struct esp_event_ent *p) -{ - p->sreg = esp->sreg; - p->seqreg = esp->seqreg; - p->sreg2 = esp->sreg2; - p->ireg = esp->ireg; - p->select_state = esp->select_state; - p->event = esp->event; -} - -void scsi_esp_cmd(struct esp *esp, u8 val) -{ - struct esp_event_ent *p; - int idx = esp->esp_event_cur; - - p = &esp->esp_event_log[idx]; - p->type = ESP_EVENT_TYPE_CMD; - p->val = val; - esp_log_fill_regs(esp, p); - - esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); - - esp_write8(val, ESP_CMD); -} -EXPORT_SYMBOL(scsi_esp_cmd); - -static void esp_event(struct esp *esp, u8 val) -{ - struct esp_event_ent *p; - int idx = esp->esp_event_cur; - - p = &esp->esp_event_log[idx]; - p->type = ESP_EVENT_TYPE_EVENT; - p->val = val; - esp_log_fill_regs(esp, p); - - esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); - - esp->event = val; -} - -static void esp_dump_cmd_log(struct esp *esp) -{ - int idx = esp->esp_event_cur; - int stop = idx; - - printk(KERN_INFO PFX "esp%d: Dumping command log\n", - esp->host->unique_id); - do { - struct esp_event_ent *p = &esp->esp_event_log[idx]; - - printk(KERN_INFO PFX "esp%d: ent[%d] %s ", - esp->host->unique_id, idx, - p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT"); - - printk("val[%02x] sreg[%02x] seqreg[%02x] " - "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n", - p->val, p->sreg, p->seqreg, - p->sreg2, p->ireg, p->select_state, p->event); - - idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1); - } while (idx != stop); -} - -static void esp_flush_fifo(struct esp *esp) -{ - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - if (esp->rev == ESP236) { - int lim = 1000; - - while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES " - "will not clear!\n", - esp->host->unique_id); - break; - } - udelay(1); - } - } -} - -static void hme_read_fifo(struct esp *esp) -{ - int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - int idx = 0; - - while (fcnt--) { - esp->fifo[idx++] = esp_read8(ESP_FDATA); - esp->fifo[idx++] = esp_read8(ESP_FDATA); - } - if (esp->sreg2 & ESP_STAT2_F1BYTE) { - esp_write8(0, ESP_FDATA); - esp->fifo[idx++] = esp_read8(ESP_FDATA); - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - } - esp->fifo_cnt = idx; -} - -static void esp_set_all_config3(struct esp *esp, u8 val) -{ - int i; - - for (i = 0; i < ESP_MAX_TARGET; i++) - esp->target[i].esp_config3 = val; -} - -/* Reset the ESP chip, _not_ the SCSI bus. */ -static void esp_reset_esp(struct esp *esp) -{ - u8 family_code, version; - - /* Now reset the ESP chip */ - scsi_esp_cmd(esp, ESP_CMD_RC); - scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); - if (esp->rev == FAST) - esp_write8(ESP_CONFIG2_FENAB, ESP_CFG2); - scsi_esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA); - - /* This is the only point at which it is reliable to read - * the ID-code for a fast ESP chip variants. - */ - esp->max_period = ((35 * esp->ccycle) / 1000); - if (esp->rev == FAST) { - version = esp_read8(ESP_UID); - family_code = (version & 0xf8) >> 3; - if (family_code == 0x02) - esp->rev = FAS236; - else if (family_code == 0x0a) - esp->rev = FASHME; /* Version is usually '5'. */ - else - esp->rev = FAS100A; - esp->min_period = ((4 * esp->ccycle) / 1000); - } else { - esp->min_period = ((5 * esp->ccycle) / 1000); - } - esp->max_period = (esp->max_period + 3)>>2; - esp->min_period = (esp->min_period + 3)>>2; - - esp_write8(esp->config1, ESP_CFG1); - switch (esp->rev) { - case ESP100: - /* nothing to do */ - break; - - case ESP100A: - esp_write8(esp->config2, ESP_CFG2); - break; - - case ESP236: - /* Slow 236 */ - esp_write8(esp->config2, ESP_CFG2); - esp->prev_cfg3 = esp->target[0].esp_config3; - esp_write8(esp->prev_cfg3, ESP_CFG3); - break; - - case FASHME: - esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB); - /* fallthrough... */ - - case FAS236: - /* Fast 236 or HME */ - esp_write8(esp->config2, ESP_CFG2); - if (esp->rev == FASHME) { - u8 cfg3 = esp->target[0].esp_config3; - - cfg3 |= ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH; - if (esp->scsi_id >= 8) - cfg3 |= ESP_CONFIG3_IDBIT3; - esp_set_all_config3(esp, cfg3); - } else { - u32 cfg3 = esp->target[0].esp_config3; - - cfg3 |= ESP_CONFIG3_FCLK; - esp_set_all_config3(esp, cfg3); - } - esp->prev_cfg3 = esp->target[0].esp_config3; - esp_write8(esp->prev_cfg3, ESP_CFG3); - if (esp->rev == FASHME) { - esp->radelay = 80; - } else { - if (esp->flags & ESP_FLAG_DIFFERENTIAL) - esp->radelay = 0; - else - esp->radelay = 96; - } - break; - - case FAS100A: - /* Fast 100a */ - esp_write8(esp->config2, ESP_CFG2); - esp_set_all_config3(esp, - (esp->target[0].esp_config3 | - ESP_CONFIG3_FCLOCK)); - esp->prev_cfg3 = esp->target[0].esp_config3; - esp_write8(esp->prev_cfg3, ESP_CFG3); - esp->radelay = 32; - break; - - default: - break; - } - - /* Reload the configuration registers */ - esp_write8(esp->cfact, ESP_CFACT); - - esp->prev_stp = 0; - esp_write8(esp->prev_stp, ESP_STP); - - esp->prev_soff = 0; - esp_write8(esp->prev_soff, ESP_SOFF); - - esp_write8(esp->neg_defp, ESP_TIMEO); - - /* Eat any bitrot in the chip */ - esp_read8(ESP_INTRPT); - udelay(100); -} - -static void esp_map_dma(struct esp *esp, struct scsi_cmnd *cmd) -{ - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - struct scatterlist *sg = scsi_sglist(cmd); - int dir = cmd->sc_data_direction; - int total, i; - - if (dir == DMA_NONE) - return; - - spriv->u.num_sg = esp->ops->map_sg(esp, sg, scsi_sg_count(cmd), dir); - spriv->cur_residue = sg_dma_len(sg); - spriv->cur_sg = sg; - - total = 0; - for (i = 0; i < spriv->u.num_sg; i++) - total += sg_dma_len(&sg[i]); - spriv->tot_residue = total; -} - -static dma_addr_t esp_cur_dma_addr(struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd) -{ - struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - return ent->sense_dma + - (ent->sense_ptr - cmd->sense_buffer); - } - - return sg_dma_address(p->cur_sg) + - (sg_dma_len(p->cur_sg) - - p->cur_residue); -} - -static unsigned int esp_cur_dma_len(struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd) -{ - struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - return SCSI_SENSE_BUFFERSIZE - - (ent->sense_ptr - cmd->sense_buffer); - } - return p->cur_residue; -} - -static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd, unsigned int len) -{ - struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - ent->sense_ptr += len; - return; - } - - p->cur_residue -= len; - p->tot_residue -= len; - if (p->cur_residue < 0 || p->tot_residue < 0) { - printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n", - esp->host->unique_id); - printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] " - "len[%u]\n", - esp->host->unique_id, - p->cur_residue, p->tot_residue, len); - p->cur_residue = 0; - p->tot_residue = 0; - } - if (!p->cur_residue && p->tot_residue) { - p->cur_sg++; - p->cur_residue = sg_dma_len(p->cur_sg); - } -} - -static void esp_unmap_dma(struct esp *esp, struct scsi_cmnd *cmd) -{ - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - int dir = cmd->sc_data_direction; - - if (dir == DMA_NONE) - return; - - esp->ops->unmap_sg(esp, scsi_sglist(cmd), spriv->u.num_sg, dir); -} - -static void esp_save_pointers(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_cmnd *cmd = ent->cmd; - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - ent->saved_sense_ptr = ent->sense_ptr; - return; - } - ent->saved_cur_residue = spriv->cur_residue; - ent->saved_cur_sg = spriv->cur_sg; - ent->saved_tot_residue = spriv->tot_residue; -} - -static void esp_restore_pointers(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_cmnd *cmd = ent->cmd; - struct esp_cmd_priv *spriv = ESP_CMD_PRIV(cmd); - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - ent->sense_ptr = ent->saved_sense_ptr; - return; - } - spriv->cur_residue = ent->saved_cur_residue; - spriv->cur_sg = ent->saved_cur_sg; - spriv->tot_residue = ent->saved_tot_residue; -} - -static void esp_check_command_len(struct esp *esp, struct scsi_cmnd *cmd) -{ - if (cmd->cmd_len == 6 || - cmd->cmd_len == 10 || - cmd->cmd_len == 12) { - esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; - } else { - esp->flags |= ESP_FLAG_DOING_SLOWCMD; - } -} - -static void esp_write_tgt_config3(struct esp *esp, int tgt) -{ - if (esp->rev > ESP100A) { - u8 val = esp->target[tgt].esp_config3; - - if (val != esp->prev_cfg3) { - esp->prev_cfg3 = val; - esp_write8(val, ESP_CFG3); - } - } -} - -static void esp_write_tgt_sync(struct esp *esp, int tgt) -{ - u8 off = esp->target[tgt].esp_offset; - u8 per = esp->target[tgt].esp_period; - - if (off != esp->prev_soff) { - esp->prev_soff = off; - esp_write8(off, ESP_SOFF); - } - if (per != esp->prev_stp) { - esp->prev_stp = per; - esp_write8(per, ESP_STP); - } -} - -static u32 esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) -{ - if (esp->rev == FASHME) { - /* Arbitrary segment boundaries, 24-bit counts. */ - if (dma_len > (1U << 24)) - dma_len = (1U << 24); - } else { - u32 base, end; - - /* ESP chip limits other variants by 16-bits of transfer - * count. Actually on FAS100A and FAS236 we could get - * 24-bits of transfer count by enabling ESP_CONFIG2_FENAB - * in the ESP_CFG2 register but that causes other unwanted - * changes so we don't use it currently. - */ - if (dma_len > (1U << 16)) - dma_len = (1U << 16); - - /* All of the DMA variants hooked up to these chips - * cannot handle crossing a 24-bit address boundary. - */ - base = dma_addr & ((1U << 24) - 1U); - end = base + dma_len; - if (end > (1U << 24)) - end = (1U <<24); - dma_len = end - base; - } - return dma_len; -} - -static int esp_need_to_nego_wide(struct esp_target_data *tp) -{ - struct scsi_target *target = tp->starget; - - return spi_width(target) != tp->nego_goal_width; -} - -static int esp_need_to_nego_sync(struct esp_target_data *tp) -{ - struct scsi_target *target = tp->starget; - - /* When offset is zero, period is "don't care". */ - if (!spi_offset(target) && !tp->nego_goal_offset) - return 0; - - if (spi_offset(target) == tp->nego_goal_offset && - spi_period(target) == tp->nego_goal_period) - return 0; - - return 1; -} - -static int esp_alloc_lun_tag(struct esp_cmd_entry *ent, - struct esp_lun_data *lp) -{ - if (!ent->tag[0]) { - /* Non-tagged, slot already taken? */ - if (lp->non_tagged_cmd) - return -EBUSY; - - if (lp->hold) { - /* We are being held by active tagged - * commands. - */ - if (lp->num_tagged) - return -EBUSY; - - /* Tagged commands completed, we can unplug - * the queue and run this untagged command. - */ - lp->hold = 0; - } else if (lp->num_tagged) { - /* Plug the queue until num_tagged decreases - * to zero in esp_free_lun_tag. - */ - lp->hold = 1; - return -EBUSY; - } - - lp->non_tagged_cmd = ent; - return 0; - } else { - /* Tagged command, see if blocked by a - * non-tagged one. - */ - if (lp->non_tagged_cmd || lp->hold) - return -EBUSY; - } - - BUG_ON(lp->tagged_cmds[ent->tag[1]]); - - lp->tagged_cmds[ent->tag[1]] = ent; - lp->num_tagged++; - - return 0; -} - -static void esp_free_lun_tag(struct esp_cmd_entry *ent, - struct esp_lun_data *lp) -{ - if (ent->tag[0]) { - BUG_ON(lp->tagged_cmds[ent->tag[1]] != ent); - lp->tagged_cmds[ent->tag[1]] = NULL; - lp->num_tagged--; - } else { - BUG_ON(lp->non_tagged_cmd != ent); - lp->non_tagged_cmd = NULL; - } -} - -/* When a contingent allegiance conditon is created, we force feed a - * REQUEST_SENSE command to the device to fetch the sense data. I - * tried many other schemes, relying on the scsi error handling layer - * to send out the REQUEST_SENSE automatically, but this was difficult - * to get right especially in the presence of applications like smartd - * which use SG_IO to send out their own REQUEST_SENSE commands. - */ -static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_cmnd *cmd = ent->cmd; - struct scsi_device *dev = cmd->device; - int tgt, lun; - u8 *p, val; - - tgt = dev->id; - lun = dev->lun; - - - if (!ent->sense_ptr) { - esp_log_autosense("esp%d: Doing auto-sense for " - "tgt[%d] lun[%d]\n", - esp->host->unique_id, tgt, lun); - - ent->sense_ptr = cmd->sense_buffer; - ent->sense_dma = esp->ops->map_single(esp, - ent->sense_ptr, - SCSI_SENSE_BUFFERSIZE, - DMA_FROM_DEVICE); - } - ent->saved_sense_ptr = ent->sense_ptr; - - esp->active_cmd = ent; - - p = esp->command_block; - esp->msg_out_len = 0; - - *p++ = IDENTIFY(0, lun); - *p++ = REQUEST_SENSE; - *p++ = ((dev->scsi_level <= SCSI_2) ? - (lun << 5) : 0); - *p++ = 0; - *p++ = 0; - *p++ = SCSI_SENSE_BUFFERSIZE; - *p++ = 0; - - esp->select_state = ESP_SELECT_BASIC; - - val = tgt; - if (esp->rev == FASHME) - val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT; - esp_write8(val, ESP_BUSID); - - esp_write_tgt_sync(esp, tgt); - esp_write_tgt_config3(esp, tgt); - - val = (p - esp->command_block); - - if (esp->rev == FASHME) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - esp->ops->send_dma_cmd(esp, esp->command_block_dma, - val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA); -} - -static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp) -{ - struct esp_cmd_entry *ent; - - list_for_each_entry(ent, &esp->queued_cmds, list) { - struct scsi_cmnd *cmd = ent->cmd; - struct scsi_device *dev = cmd->device; - struct esp_lun_data *lp = dev->hostdata; - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - ent->tag[0] = 0; - ent->tag[1] = 0; - return ent; - } - - if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) { - ent->tag[0] = 0; - ent->tag[1] = 0; - } - - if (esp_alloc_lun_tag(ent, lp) < 0) - continue; - - return ent; - } - - return NULL; -} - -static void esp_maybe_execute_command(struct esp *esp) -{ - struct esp_target_data *tp; - struct esp_lun_data *lp; - struct scsi_device *dev; - struct scsi_cmnd *cmd; - struct esp_cmd_entry *ent; - int tgt, lun, i; - u32 val, start_cmd; - u8 *p; - - if (esp->active_cmd || - (esp->flags & ESP_FLAG_RESETTING)) - return; - - ent = find_and_prep_issuable_command(esp); - if (!ent) - return; - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp_autosense(esp, ent); - return; - } - - cmd = ent->cmd; - dev = cmd->device; - tgt = dev->id; - lun = dev->lun; - tp = &esp->target[tgt]; - lp = dev->hostdata; - - list_move(&ent->list, &esp->active_cmds); - - esp->active_cmd = ent; - - esp_map_dma(esp, cmd); - esp_save_pointers(esp, ent); - - esp_check_command_len(esp, cmd); - - p = esp->command_block; - - esp->msg_out_len = 0; - if (tp->flags & ESP_TGT_CHECK_NEGO) { - /* Need to negotiate. If the target is broken - * go for synchronous transfers and non-wide. - */ - if (tp->flags & ESP_TGT_BROKEN) { - tp->flags &= ~ESP_TGT_DISCONNECT; - tp->nego_goal_period = 0; - tp->nego_goal_offset = 0; - tp->nego_goal_width = 0; - tp->nego_goal_tags = 0; - } - - /* If the settings are not changing, skip this. */ - if (spi_width(tp->starget) == tp->nego_goal_width && - spi_period(tp->starget) == tp->nego_goal_period && - spi_offset(tp->starget) == tp->nego_goal_offset) { - tp->flags &= ~ESP_TGT_CHECK_NEGO; - goto build_identify; - } - - if (esp->rev == FASHME && esp_need_to_nego_wide(tp)) { - esp->msg_out_len = - spi_populate_width_msg(&esp->msg_out[0], - (tp->nego_goal_width ? - 1 : 0)); - tp->flags |= ESP_TGT_NEGO_WIDE; - } else if (esp_need_to_nego_sync(tp)) { - esp->msg_out_len = - spi_populate_sync_msg(&esp->msg_out[0], - tp->nego_goal_period, - tp->nego_goal_offset); - tp->flags |= ESP_TGT_NEGO_SYNC; - } else { - tp->flags &= ~ESP_TGT_CHECK_NEGO; - } - - /* Process it like a slow command. */ - if (tp->flags & (ESP_TGT_NEGO_WIDE | ESP_TGT_NEGO_SYNC)) - esp->flags |= ESP_FLAG_DOING_SLOWCMD; - } - -build_identify: - /* If we don't have a lun-data struct yet, we're probing - * so do not disconnect. Also, do not disconnect unless - * we have a tag on this command. - */ - if (lp && (tp->flags & ESP_TGT_DISCONNECT) && ent->tag[0]) - *p++ = IDENTIFY(1, lun); - else - *p++ = IDENTIFY(0, lun); - - if (ent->tag[0] && esp->rev == ESP100) { - /* ESP100 lacks select w/atn3 command, use select - * and stop instead. - */ - esp->flags |= ESP_FLAG_DOING_SLOWCMD; - } - - if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) { - start_cmd = ESP_CMD_DMA | ESP_CMD_SELA; - if (ent->tag[0]) { - *p++ = ent->tag[0]; - *p++ = ent->tag[1]; - - start_cmd = ESP_CMD_DMA | ESP_CMD_SA3; - } - - for (i = 0; i < cmd->cmd_len; i++) - *p++ = cmd->cmnd[i]; - - esp->select_state = ESP_SELECT_BASIC; - } else { - esp->cmd_bytes_left = cmd->cmd_len; - esp->cmd_bytes_ptr = &cmd->cmnd[0]; - - if (ent->tag[0]) { - for (i = esp->msg_out_len - 1; - i >= 0; i--) - esp->msg_out[i + 2] = esp->msg_out[i]; - esp->msg_out[0] = ent->tag[0]; - esp->msg_out[1] = ent->tag[1]; - esp->msg_out_len += 2; - } - - start_cmd = ESP_CMD_DMA | ESP_CMD_SELAS; - esp->select_state = ESP_SELECT_MSGOUT; - } - val = tgt; - if (esp->rev == FASHME) - val |= ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT; - esp_write8(val, ESP_BUSID); - - esp_write_tgt_sync(esp, tgt); - esp_write_tgt_config3(esp, tgt); - - val = (p - esp->command_block); - - if (esp_debug & ESP_DEBUG_SCSICMD) { - printk("ESP: tgt[%d] lun[%d] scsi_cmd [ ", tgt, lun); - for (i = 0; i < cmd->cmd_len; i++) - printk("%02x ", cmd->cmnd[i]); - printk("]\n"); - } - - if (esp->rev == FASHME) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - esp->ops->send_dma_cmd(esp, esp->command_block_dma, - val, 16, 0, start_cmd); -} - -static struct esp_cmd_entry *esp_get_ent(struct esp *esp) -{ - struct list_head *head = &esp->esp_cmd_pool; - struct esp_cmd_entry *ret; - - if (list_empty(head)) { - ret = kzalloc(sizeof(struct esp_cmd_entry), GFP_ATOMIC); - } else { - ret = list_entry(head->next, struct esp_cmd_entry, list); - list_del(&ret->list); - memset(ret, 0, sizeof(*ret)); - } - return ret; -} - -static void esp_put_ent(struct esp *esp, struct esp_cmd_entry *ent) -{ - list_add(&ent->list, &esp->esp_cmd_pool); -} - -static void esp_cmd_is_done(struct esp *esp, struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd, unsigned int result) -{ - struct scsi_device *dev = cmd->device; - int tgt = dev->id; - int lun = dev->lun; - - esp->active_cmd = NULL; - esp_unmap_dma(esp, cmd); - esp_free_lun_tag(ent, dev->hostdata); - cmd->result = result; - - if (ent->eh_done) { - complete(ent->eh_done); - ent->eh_done = NULL; - } - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - ent->sense_ptr = NULL; - - /* Restore the message/status bytes to what we actually - * saw originally. Also, report that we are providing - * the sense data. - */ - cmd->result = ((DRIVER_SENSE << 24) | - (DID_OK << 16) | - (COMMAND_COMPLETE << 8) | - (SAM_STAT_CHECK_CONDITION << 0)); - - ent->flags &= ~ESP_CMD_FLAG_AUTOSENSE; - if (esp_debug & ESP_DEBUG_AUTOSENSE) { - int i; - - printk("esp%d: tgt[%d] lun[%d] AUTO SENSE[ ", - esp->host->unique_id, tgt, lun); - for (i = 0; i < 18; i++) - printk("%02x ", cmd->sense_buffer[i]); - printk("]\n"); - } - } - - cmd->scsi_done(cmd); - - list_del(&ent->list); - esp_put_ent(esp, ent); - - esp_maybe_execute_command(esp); -} - -static unsigned int compose_result(unsigned int status, unsigned int message, - unsigned int driver_code) -{ - return (status | (message << 8) | (driver_code << 16)); -} - -static void esp_event_queue_full(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_device *dev = ent->cmd->device; - struct esp_lun_data *lp = dev->hostdata; - - scsi_track_queue_full(dev, lp->num_tagged - 1); -} - -static int esp_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct scsi_device *dev = cmd->device; - struct esp *esp = shost_priv(dev->host); - struct esp_cmd_priv *spriv; - struct esp_cmd_entry *ent; - - ent = esp_get_ent(esp); - if (!ent) - return SCSI_MLQUEUE_HOST_BUSY; - - ent->cmd = cmd; - - cmd->scsi_done = done; - - spriv = ESP_CMD_PRIV(cmd); - spriv->u.dma_addr = ~(dma_addr_t)0x0; - - list_add_tail(&ent->list, &esp->queued_cmds); - - esp_maybe_execute_command(esp); - - return 0; -} - -static DEF_SCSI_QCMD(esp_queuecommand) - -static int esp_check_gross_error(struct esp *esp) -{ - if (esp->sreg & ESP_STAT_SPAM) { - /* Gross Error, could be one of: - * - top of fifo overwritten - * - top of command register overwritten - * - DMA programmed with wrong direction - * - improper phase change - */ - printk(KERN_ERR PFX "esp%d: Gross error sreg[%02x]\n", - esp->host->unique_id, esp->sreg); - /* XXX Reset the chip. XXX */ - return 1; - } - return 0; -} - -static int esp_check_spur_intr(struct esp *esp) -{ - switch (esp->rev) { - case ESP100: - case ESP100A: - /* The interrupt pending bit of the status register cannot - * be trusted on these revisions. - */ - esp->sreg &= ~ESP_STAT_INTR; - break; - - default: - if (!(esp->sreg & ESP_STAT_INTR)) { - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_SR) - return 1; - - /* If the DMA is indicating interrupt pending and the - * ESP is not, the only possibility is a DMA error. - */ - if (!esp->ops->dma_error(esp)) { - printk(KERN_ERR PFX "esp%d: Spurious irq, " - "sreg=%02x.\n", - esp->host->unique_id, esp->sreg); - return -1; - } - - printk(KERN_ERR PFX "esp%d: DMA error\n", - esp->host->unique_id); - - /* XXX Reset the chip. XXX */ - return -1; - } - break; - } - - return 0; -} - -static void esp_schedule_reset(struct esp *esp) -{ - esp_log_reset("ESP: esp_schedule_reset() from %p\n", - __builtin_return_address(0)); - esp->flags |= ESP_FLAG_RESETTING; - esp_event(esp, ESP_EVENT_RESET); -} - -/* In order to avoid having to add a special half-reconnected state - * into the driver we just sit here and poll through the rest of - * the reselection process to get the tag message bytes. - */ -static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp, - struct esp_lun_data *lp) -{ - struct esp_cmd_entry *ent; - int i; - - if (!lp->num_tagged) { - printk(KERN_ERR PFX "esp%d: Reconnect w/num_tagged==0\n", - esp->host->unique_id); - return NULL; - } - - esp_log_reconnect("ESP: reconnect tag, "); - - for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) { - if (esp->ops->irq_pending(esp)) - break; - } - if (i == ESP_QUICKIRQ_LIMIT) { - printk(KERN_ERR PFX "esp%d: Reconnect IRQ1 timeout\n", - esp->host->unique_id); - return NULL; - } - - esp->sreg = esp_read8(ESP_STATUS); - esp->ireg = esp_read8(ESP_INTRPT); - - esp_log_reconnect("IRQ(%d:%x:%x), ", - i, esp->ireg, esp->sreg); - - if (esp->ireg & ESP_INTR_DC) { - printk(KERN_ERR PFX "esp%d: Reconnect, got disconnect.\n", - esp->host->unique_id); - return NULL; - } - - if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) { - printk(KERN_ERR PFX "esp%d: Reconnect, not MIP sreg[%02x].\n", - esp->host->unique_id, esp->sreg); - return NULL; - } - - /* DMA in the tag bytes... */ - esp->command_block[0] = 0xff; - esp->command_block[1] = 0xff; - esp->ops->send_dma_cmd(esp, esp->command_block_dma, - 2, 2, 1, ESP_CMD_DMA | ESP_CMD_TI); - - /* ACK the message. */ - scsi_esp_cmd(esp, ESP_CMD_MOK); - - for (i = 0; i < ESP_RESELECT_TAG_LIMIT; i++) { - if (esp->ops->irq_pending(esp)) { - esp->sreg = esp_read8(ESP_STATUS); - esp->ireg = esp_read8(ESP_INTRPT); - if (esp->ireg & ESP_INTR_FDONE) - break; - } - udelay(1); - } - if (i == ESP_RESELECT_TAG_LIMIT) { - printk(KERN_ERR PFX "esp%d: Reconnect IRQ2 timeout\n", - esp->host->unique_id); - return NULL; - } - esp->ops->dma_drain(esp); - esp->ops->dma_invalidate(esp); - - esp_log_reconnect("IRQ2(%d:%x:%x) tag[%x:%x]\n", - i, esp->ireg, esp->sreg, - esp->command_block[0], - esp->command_block[1]); - - if (esp->command_block[0] < SIMPLE_QUEUE_TAG || - esp->command_block[0] > ORDERED_QUEUE_TAG) { - printk(KERN_ERR PFX "esp%d: Reconnect, bad tag " - "type %02x.\n", - esp->host->unique_id, esp->command_block[0]); - return NULL; - } - - ent = lp->tagged_cmds[esp->command_block[1]]; - if (!ent) { - printk(KERN_ERR PFX "esp%d: Reconnect, no entry for " - "tag %02x.\n", - esp->host->unique_id, esp->command_block[1]); - return NULL; - } - - return ent; -} - -static int esp_reconnect(struct esp *esp) -{ - struct esp_cmd_entry *ent; - struct esp_target_data *tp; - struct esp_lun_data *lp; - struct scsi_device *dev; - int target, lun; - - BUG_ON(esp->active_cmd); - if (esp->rev == FASHME) { - /* FASHME puts the target and lun numbers directly - * into the fifo. - */ - target = esp->fifo[0]; - lun = esp->fifo[1] & 0x7; - } else { - u8 bits = esp_read8(ESP_FDATA); - - /* Older chips put the lun directly into the fifo, but - * the target is given as a sample of the arbitration - * lines on the bus at reselection time. So we should - * see the ID of the ESP and the one reconnecting target - * set in the bitmap. - */ - if (!(bits & esp->scsi_id_mask)) - goto do_reset; - bits &= ~esp->scsi_id_mask; - if (!bits || (bits & (bits - 1))) - goto do_reset; - - target = ffs(bits) - 1; - lun = (esp_read8(ESP_FDATA) & 0x7); - - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - if (esp->rev == ESP100) { - u8 ireg = esp_read8(ESP_INTRPT); - /* This chip has a bug during reselection that can - * cause a spurious illegal-command interrupt, which - * we simply ACK here. Another possibility is a bus - * reset so we must check for that. - */ - if (ireg & ESP_INTR_SR) - goto do_reset; - } - scsi_esp_cmd(esp, ESP_CMD_NULL); - } - - esp_write_tgt_sync(esp, target); - esp_write_tgt_config3(esp, target); - - scsi_esp_cmd(esp, ESP_CMD_MOK); - - if (esp->rev == FASHME) - esp_write8(target | ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT, - ESP_BUSID); - - tp = &esp->target[target]; - dev = __scsi_device_lookup_by_target(tp->starget, lun); - if (!dev) { - printk(KERN_ERR PFX "esp%d: Reconnect, no lp " - "tgt[%u] lun[%u]\n", - esp->host->unique_id, target, lun); - goto do_reset; - } - lp = dev->hostdata; - - ent = lp->non_tagged_cmd; - if (!ent) { - ent = esp_reconnect_with_tag(esp, lp); - if (!ent) - goto do_reset; - } - - esp->active_cmd = ent; - - if (ent->flags & ESP_CMD_FLAG_ABORT) { - esp->msg_out[0] = ABORT_TASK_SET; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); - } - - esp_event(esp, ESP_EVENT_CHECK_PHASE); - esp_restore_pointers(esp, ent); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - return 1; - -do_reset: - esp_schedule_reset(esp); - return 0; -} - -static int esp_finish_select(struct esp *esp) -{ - struct esp_cmd_entry *ent; - struct scsi_cmnd *cmd; - u8 orig_select_state; - - orig_select_state = esp->select_state; - - /* No longer selecting. */ - esp->select_state = ESP_SELECT_NONE; - - esp->seqreg = esp_read8(ESP_SSTEP) & ESP_STEP_VBITS; - ent = esp->active_cmd; - cmd = ent->cmd; - - if (esp->ops->dma_error(esp)) { - /* If we see a DMA error during or as a result of selection, - * all bets are off. - */ - esp_schedule_reset(esp); - esp_cmd_is_done(esp, ent, cmd, (DID_ERROR << 16)); - return 0; - } - - esp->ops->dma_invalidate(esp); - - if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) { - struct esp_target_data *tp = &esp->target[cmd->device->id]; - - /* Carefully back out of the selection attempt. Release - * resources (such as DMA mapping & TAG) and reset state (such - * as message out and command delivery variables). - */ - if (!(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) { - esp_unmap_dma(esp, cmd); - esp_free_lun_tag(ent, cmd->device->hostdata); - tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_NEGO_WIDE); - esp->flags &= ~ESP_FLAG_DOING_SLOWCMD; - esp->cmd_bytes_ptr = NULL; - esp->cmd_bytes_left = 0; - } else { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, - DMA_FROM_DEVICE); - ent->sense_ptr = NULL; - } - - /* Now that the state is unwound properly, put back onto - * the issue queue. This command is no longer active. - */ - list_move(&ent->list, &esp->queued_cmds); - esp->active_cmd = NULL; - - /* Return value ignored by caller, it directly invokes - * esp_reconnect(). - */ - return 0; - } - - if (esp->ireg == ESP_INTR_DC) { - struct scsi_device *dev = cmd->device; - - /* Disconnect. Make sure we re-negotiate sync and - * wide parameters if this target starts responding - * again in the future. - */ - esp->target[dev->id].flags |= ESP_TGT_CHECK_NEGO; - - scsi_esp_cmd(esp, ESP_CMD_ESEL); - esp_cmd_is_done(esp, ent, cmd, (DID_BAD_TARGET << 16)); - return 1; - } - - if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) { - /* Selection successful. On pre-FAST chips we have - * to do a NOP and possibly clean out the FIFO. - */ - if (esp->rev <= ESP236) { - int fcnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - - scsi_esp_cmd(esp, ESP_CMD_NULL); - - if (!fcnt && - (!esp->prev_soff || - ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP))) - esp_flush_fifo(esp); - } - - /* If we are doing a slow command, negotiation, etc. - * we'll do the right thing as we transition to the - * next phase. - */ - esp_event(esp, ESP_EVENT_CHECK_PHASE); - return 0; - } - - printk("ESP: Unexpected selection completion ireg[%x].\n", - esp->ireg); - esp_schedule_reset(esp); - return 0; -} - -static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent, - struct scsi_cmnd *cmd) -{ - int fifo_cnt, ecount, bytes_sent, flush_fifo; - - fifo_cnt = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE) - fifo_cnt <<= 1; - - ecount = 0; - if (!(esp->sreg & ESP_STAT_TCNT)) { - ecount = ((unsigned int)esp_read8(ESP_TCLOW) | - (((unsigned int)esp_read8(ESP_TCMED)) << 8)); - if (esp->rev == FASHME) - ecount |= ((unsigned int)esp_read8(FAS_RLO)) << 16; - } - - bytes_sent = esp->data_dma_len; - bytes_sent -= ecount; - - if (!(ent->flags & ESP_CMD_FLAG_WRITE)) - bytes_sent -= fifo_cnt; - - flush_fifo = 0; - if (!esp->prev_soff) { - /* Synchronous data transfer, always flush fifo. */ - flush_fifo = 1; - } else { - if (esp->rev == ESP100) { - u32 fflags, phase; - - /* ESP100 has a chip bug where in the synchronous data - * phase it can mistake a final long REQ pulse from the - * target as an extra data byte. Fun. - * - * To detect this case we resample the status register - * and fifo flags. If we're still in a data phase and - * we see spurious chunks in the fifo, we return error - * to the caller which should reset and set things up - * such that we only try future transfers to this - * target in synchronous mode. - */ - esp->sreg = esp_read8(ESP_STATUS); - phase = esp->sreg & ESP_STAT_PMASK; - fflags = esp_read8(ESP_FFLAGS); - - if ((phase == ESP_DOP && - (fflags & ESP_FF_ONOTZERO)) || - (phase == ESP_DIP && - (fflags & ESP_FF_FBYTES))) - return -1; - } - if (!(ent->flags & ESP_CMD_FLAG_WRITE)) - flush_fifo = 1; - } - - if (flush_fifo) - esp_flush_fifo(esp); - - return bytes_sent; -} - -static void esp_setsync(struct esp *esp, struct esp_target_data *tp, - u8 scsi_period, u8 scsi_offset, - u8 esp_stp, u8 esp_soff) -{ - spi_period(tp->starget) = scsi_period; - spi_offset(tp->starget) = scsi_offset; - spi_width(tp->starget) = (tp->flags & ESP_TGT_WIDE) ? 1 : 0; - - if (esp_soff) { - esp_stp &= 0x1f; - esp_soff |= esp->radelay; - if (esp->rev >= FAS236) { - u8 bit = ESP_CONFIG3_FSCSI; - if (esp->rev >= FAS100A) - bit = ESP_CONFIG3_FAST; - - if (scsi_period < 50) { - if (esp->rev == FASHME) - esp_soff &= ~esp->radelay; - tp->esp_config3 |= bit; - } else { - tp->esp_config3 &= ~bit; - } - esp->prev_cfg3 = tp->esp_config3; - esp_write8(esp->prev_cfg3, ESP_CFG3); - } - } - - tp->esp_period = esp->prev_stp = esp_stp; - tp->esp_offset = esp->prev_soff = esp_soff; - - esp_write8(esp_soff, ESP_SOFF); - esp_write8(esp_stp, ESP_STP); - - tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO); - - spi_display_xfer_agreement(tp->starget); -} - -static void esp_msgin_reject(struct esp *esp) -{ - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - struct esp_target_data *tp; - int tgt; - - tgt = cmd->device->id; - tp = &esp->target[tgt]; - - if (tp->flags & ESP_TGT_NEGO_WIDE) { - tp->flags &= ~(ESP_TGT_NEGO_WIDE | ESP_TGT_WIDE); - - if (!esp_need_to_nego_sync(tp)) { - tp->flags &= ~ESP_TGT_CHECK_NEGO; - scsi_esp_cmd(esp, ESP_CMD_RATN); - } else { - esp->msg_out_len = - spi_populate_sync_msg(&esp->msg_out[0], - tp->nego_goal_period, - tp->nego_goal_offset); - tp->flags |= ESP_TGT_NEGO_SYNC; - scsi_esp_cmd(esp, ESP_CMD_SATN); - } - return; - } - - if (tp->flags & ESP_TGT_NEGO_SYNC) { - tp->flags &= ~(ESP_TGT_NEGO_SYNC | ESP_TGT_CHECK_NEGO); - tp->esp_period = 0; - tp->esp_offset = 0; - esp_setsync(esp, tp, 0, 0, 0, 0); - scsi_esp_cmd(esp, ESP_CMD_RATN); - return; - } - - esp->msg_out[0] = ABORT_TASK_SET; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); -} - -static void esp_msgin_sdtr(struct esp *esp, struct esp_target_data *tp) -{ - u8 period = esp->msg_in[3]; - u8 offset = esp->msg_in[4]; - u8 stp; - - if (!(tp->flags & ESP_TGT_NEGO_SYNC)) - goto do_reject; - - if (offset > 15) - goto do_reject; - - if (offset) { - int one_clock; - - if (period > esp->max_period) { - period = offset = 0; - goto do_sdtr; - } - if (period < esp->min_period) - goto do_reject; - - one_clock = esp->ccycle / 1000; - stp = DIV_ROUND_UP(period << 2, one_clock); - if (stp && esp->rev >= FAS236) { - if (stp >= 50) - stp--; - } - } else { - stp = 0; - } - - esp_setsync(esp, tp, period, offset, stp, offset); - return; - -do_reject: - esp->msg_out[0] = MESSAGE_REJECT; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); - return; - -do_sdtr: - tp->nego_goal_period = period; - tp->nego_goal_offset = offset; - esp->msg_out_len = - spi_populate_sync_msg(&esp->msg_out[0], - tp->nego_goal_period, - tp->nego_goal_offset); - scsi_esp_cmd(esp, ESP_CMD_SATN); -} - -static void esp_msgin_wdtr(struct esp *esp, struct esp_target_data *tp) -{ - int size = 8 << esp->msg_in[3]; - u8 cfg3; - - if (esp->rev != FASHME) - goto do_reject; - - if (size != 8 && size != 16) - goto do_reject; - - if (!(tp->flags & ESP_TGT_NEGO_WIDE)) - goto do_reject; - - cfg3 = tp->esp_config3; - if (size == 16) { - tp->flags |= ESP_TGT_WIDE; - cfg3 |= ESP_CONFIG3_EWIDE; - } else { - tp->flags &= ~ESP_TGT_WIDE; - cfg3 &= ~ESP_CONFIG3_EWIDE; - } - tp->esp_config3 = cfg3; - esp->prev_cfg3 = cfg3; - esp_write8(cfg3, ESP_CFG3); - - tp->flags &= ~ESP_TGT_NEGO_WIDE; - - spi_period(tp->starget) = 0; - spi_offset(tp->starget) = 0; - if (!esp_need_to_nego_sync(tp)) { - tp->flags &= ~ESP_TGT_CHECK_NEGO; - scsi_esp_cmd(esp, ESP_CMD_RATN); - } else { - esp->msg_out_len = - spi_populate_sync_msg(&esp->msg_out[0], - tp->nego_goal_period, - tp->nego_goal_offset); - tp->flags |= ESP_TGT_NEGO_SYNC; - scsi_esp_cmd(esp, ESP_CMD_SATN); - } - return; - -do_reject: - esp->msg_out[0] = MESSAGE_REJECT; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); -} - -static void esp_msgin_extended(struct esp *esp) -{ - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - struct esp_target_data *tp; - int tgt = cmd->device->id; - - tp = &esp->target[tgt]; - if (esp->msg_in[2] == EXTENDED_SDTR) { - esp_msgin_sdtr(esp, tp); - return; - } - if (esp->msg_in[2] == EXTENDED_WDTR) { - esp_msgin_wdtr(esp, tp); - return; - } - - printk("ESP: Unexpected extended msg type %x\n", - esp->msg_in[2]); - - esp->msg_out[0] = ABORT_TASK_SET; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); -} - -/* Analyze msgin bytes received from target so far. Return non-zero - * if there are more bytes needed to complete the message. - */ -static int esp_msgin_process(struct esp *esp) -{ - u8 msg0 = esp->msg_in[0]; - int len = esp->msg_in_len; - - if (msg0 & 0x80) { - /* Identify */ - printk("ESP: Unexpected msgin identify\n"); - return 0; - } - - switch (msg0) { - case EXTENDED_MESSAGE: - if (len == 1) - return 1; - if (len < esp->msg_in[1] + 2) - return 1; - esp_msgin_extended(esp); - return 0; - - case IGNORE_WIDE_RESIDUE: { - struct esp_cmd_entry *ent; - struct esp_cmd_priv *spriv; - if (len == 1) - return 1; - - if (esp->msg_in[1] != 1) - goto do_reject; - - ent = esp->active_cmd; - spriv = ESP_CMD_PRIV(ent->cmd); - - if (spriv->cur_residue == sg_dma_len(spriv->cur_sg)) { - spriv->cur_sg--; - spriv->cur_residue = 1; - } else - spriv->cur_residue++; - spriv->tot_residue++; - return 0; - } - case NOP: - return 0; - case RESTORE_POINTERS: - esp_restore_pointers(esp, esp->active_cmd); - return 0; - case SAVE_POINTERS: - esp_save_pointers(esp, esp->active_cmd); - return 0; - - case COMMAND_COMPLETE: - case DISCONNECT: { - struct esp_cmd_entry *ent = esp->active_cmd; - - ent->message = msg0; - esp_event(esp, ESP_EVENT_FREE_BUS); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - return 0; - } - case MESSAGE_REJECT: - esp_msgin_reject(esp); - return 0; - - default: - do_reject: - esp->msg_out[0] = MESSAGE_REJECT; - esp->msg_out_len = 1; - scsi_esp_cmd(esp, ESP_CMD_SATN); - return 0; - } -} - -static int esp_process_event(struct esp *esp) -{ - int write; - -again: - write = 0; - switch (esp->event) { - case ESP_EVENT_CHECK_PHASE: - switch (esp->sreg & ESP_STAT_PMASK) { - case ESP_DOP: - esp_event(esp, ESP_EVENT_DATA_OUT); - break; - case ESP_DIP: - esp_event(esp, ESP_EVENT_DATA_IN); - break; - case ESP_STATP: - esp_flush_fifo(esp); - scsi_esp_cmd(esp, ESP_CMD_ICCSEQ); - esp_event(esp, ESP_EVENT_STATUS); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - return 1; - - case ESP_MOP: - esp_event(esp, ESP_EVENT_MSGOUT); - break; - - case ESP_MIP: - esp_event(esp, ESP_EVENT_MSGIN); - break; - - case ESP_CMDP: - esp_event(esp, ESP_EVENT_CMD_START); - break; - - default: - printk("ESP: Unexpected phase, sreg=%02x\n", - esp->sreg); - esp_schedule_reset(esp); - return 0; - } - goto again; - break; - - case ESP_EVENT_DATA_IN: - write = 1; - /* fallthru */ - - case ESP_EVENT_DATA_OUT: { - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - dma_addr_t dma_addr = esp_cur_dma_addr(ent, cmd); - unsigned int dma_len = esp_cur_dma_len(ent, cmd); - - if (esp->rev == ESP100) - scsi_esp_cmd(esp, ESP_CMD_NULL); - - if (write) - ent->flags |= ESP_CMD_FLAG_WRITE; - else - ent->flags &= ~ESP_CMD_FLAG_WRITE; - - if (esp->ops->dma_length_limit) - dma_len = esp->ops->dma_length_limit(esp, dma_addr, - dma_len); - else - dma_len = esp_dma_length_limit(esp, dma_addr, dma_len); - - esp->data_dma_len = dma_len; - - if (!dma_len) { - printk(KERN_ERR PFX "esp%d: DMA length is zero!\n", - esp->host->unique_id); - printk(KERN_ERR PFX "esp%d: cur adr[%08llx] len[%08x]\n", - esp->host->unique_id, - (unsigned long long)esp_cur_dma_addr(ent, cmd), - esp_cur_dma_len(ent, cmd)); - esp_schedule_reset(esp); - return 0; - } - - esp_log_datastart("ESP: start data addr[%08llx] len[%u] " - "write(%d)\n", - (unsigned long long)dma_addr, dma_len, write); - - esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len, - write, ESP_CMD_DMA | ESP_CMD_TI); - esp_event(esp, ESP_EVENT_DATA_DONE); - break; - } - case ESP_EVENT_DATA_DONE: { - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - int bytes_sent; - - if (esp->ops->dma_error(esp)) { - printk("ESP: data done, DMA error, resetting\n"); - esp_schedule_reset(esp); - return 0; - } - - if (ent->flags & ESP_CMD_FLAG_WRITE) { - /* XXX parity errors, etc. XXX */ - - esp->ops->dma_drain(esp); - } - esp->ops->dma_invalidate(esp); - - if (esp->ireg != ESP_INTR_BSERV) { - /* We should always see exactly a bus-service - * interrupt at the end of a successful transfer. - */ - printk("ESP: data done, not BSERV, resetting\n"); - esp_schedule_reset(esp); - return 0; - } - - bytes_sent = esp_data_bytes_sent(esp, ent, cmd); - - esp_log_datadone("ESP: data done flgs[%x] sent[%d]\n", - ent->flags, bytes_sent); - - if (bytes_sent < 0) { - /* XXX force sync mode for this target XXX */ - esp_schedule_reset(esp); - return 0; - } - - esp_advance_dma(esp, ent, cmd, bytes_sent); - esp_event(esp, ESP_EVENT_CHECK_PHASE); - goto again; - } - - case ESP_EVENT_STATUS: { - struct esp_cmd_entry *ent = esp->active_cmd; - - if (esp->ireg & ESP_INTR_FDONE) { - ent->status = esp_read8(ESP_FDATA); - ent->message = esp_read8(ESP_FDATA); - scsi_esp_cmd(esp, ESP_CMD_MOK); - } else if (esp->ireg == ESP_INTR_BSERV) { - ent->status = esp_read8(ESP_FDATA); - ent->message = 0xff; - esp_event(esp, ESP_EVENT_MSGIN); - return 0; - } - - if (ent->message != COMMAND_COMPLETE) { - printk("ESP: Unexpected message %x in status\n", - ent->message); - esp_schedule_reset(esp); - return 0; - } - - esp_event(esp, ESP_EVENT_FREE_BUS); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - break; - } - case ESP_EVENT_FREE_BUS: { - struct esp_cmd_entry *ent = esp->active_cmd; - struct scsi_cmnd *cmd = ent->cmd; - - if (ent->message == COMMAND_COMPLETE || - ent->message == DISCONNECT) - scsi_esp_cmd(esp, ESP_CMD_ESEL); - - if (ent->message == COMMAND_COMPLETE) { - esp_log_cmddone("ESP: Command done status[%x] " - "message[%x]\n", - ent->status, ent->message); - if (ent->status == SAM_STAT_TASK_SET_FULL) - esp_event_queue_full(esp, ent); - - if (ent->status == SAM_STAT_CHECK_CONDITION && - !(ent->flags & ESP_CMD_FLAG_AUTOSENSE)) { - ent->flags |= ESP_CMD_FLAG_AUTOSENSE; - esp_autosense(esp, ent); - } else { - esp_cmd_is_done(esp, ent, cmd, - compose_result(ent->status, - ent->message, - DID_OK)); - } - } else if (ent->message == DISCONNECT) { - esp_log_disconnect("ESP: Disconnecting tgt[%d] " - "tag[%x:%x]\n", - cmd->device->id, - ent->tag[0], ent->tag[1]); - - esp->active_cmd = NULL; - esp_maybe_execute_command(esp); - } else { - printk("ESP: Unexpected message %x in freebus\n", - ent->message); - esp_schedule_reset(esp); - return 0; - } - if (esp->active_cmd) - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - break; - } - case ESP_EVENT_MSGOUT: { - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - - if (esp_debug & ESP_DEBUG_MSGOUT) { - int i; - printk("ESP: Sending message [ "); - for (i = 0; i < esp->msg_out_len; i++) - printk("%02x ", esp->msg_out[i]); - printk("]\n"); - } - - if (esp->rev == FASHME) { - int i; - - /* Always use the fifo. */ - for (i = 0; i < esp->msg_out_len; i++) { - esp_write8(esp->msg_out[i], ESP_FDATA); - esp_write8(0, ESP_FDATA); - } - scsi_esp_cmd(esp, ESP_CMD_TI); - } else { - if (esp->msg_out_len == 1) { - esp_write8(esp->msg_out[0], ESP_FDATA); - scsi_esp_cmd(esp, ESP_CMD_TI); - } else { - /* Use DMA. */ - memcpy(esp->command_block, - esp->msg_out, - esp->msg_out_len); - - esp->ops->send_dma_cmd(esp, - esp->command_block_dma, - esp->msg_out_len, - esp->msg_out_len, - 0, - ESP_CMD_DMA|ESP_CMD_TI); - } - } - esp_event(esp, ESP_EVENT_MSGOUT_DONE); - break; - } - case ESP_EVENT_MSGOUT_DONE: - if (esp->rev == FASHME) { - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - } else { - if (esp->msg_out_len > 1) - esp->ops->dma_invalidate(esp); - } - - if (!(esp->ireg & ESP_INTR_DC)) { - if (esp->rev != FASHME) - scsi_esp_cmd(esp, ESP_CMD_NULL); - } - esp_event(esp, ESP_EVENT_CHECK_PHASE); - goto again; - case ESP_EVENT_MSGIN: - if (esp->ireg & ESP_INTR_BSERV) { - if (esp->rev == FASHME) { - if (!(esp_read8(ESP_STATUS2) & - ESP_STAT2_FEMPTY)) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - } else { - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - if (esp->rev == ESP100) - scsi_esp_cmd(esp, ESP_CMD_NULL); - } - scsi_esp_cmd(esp, ESP_CMD_TI); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - return 1; - } - if (esp->ireg & ESP_INTR_FDONE) { - u8 val; - - if (esp->rev == FASHME) - val = esp->fifo[0]; - else - val = esp_read8(ESP_FDATA); - esp->msg_in[esp->msg_in_len++] = val; - - esp_log_msgin("ESP: Got msgin byte %x\n", val); - - if (!esp_msgin_process(esp)) - esp->msg_in_len = 0; - - if (esp->rev == FASHME) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - - scsi_esp_cmd(esp, ESP_CMD_MOK); - - if (esp->event != ESP_EVENT_FREE_BUS) - esp_event(esp, ESP_EVENT_CHECK_PHASE); - } else { - printk("ESP: MSGIN neither BSERV not FDON, resetting"); - esp_schedule_reset(esp); - return 0; - } - break; - case ESP_EVENT_CMD_START: - memcpy(esp->command_block, esp->cmd_bytes_ptr, - esp->cmd_bytes_left); - if (esp->rev == FASHME) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - esp->ops->send_dma_cmd(esp, esp->command_block_dma, - esp->cmd_bytes_left, 16, 0, - ESP_CMD_DMA | ESP_CMD_TI); - esp_event(esp, ESP_EVENT_CMD_DONE); - esp->flags |= ESP_FLAG_QUICKIRQ_CHECK; - break; - case ESP_EVENT_CMD_DONE: - esp->ops->dma_invalidate(esp); - if (esp->ireg & ESP_INTR_BSERV) { - esp_event(esp, ESP_EVENT_CHECK_PHASE); - goto again; - } - esp_schedule_reset(esp); - return 0; - break; - - case ESP_EVENT_RESET: - scsi_esp_cmd(esp, ESP_CMD_RS); - break; - - default: - printk("ESP: Unexpected event %x, resetting\n", - esp->event); - esp_schedule_reset(esp); - return 0; - break; - } - return 1; -} - -static void esp_reset_cleanup_one(struct esp *esp, struct esp_cmd_entry *ent) -{ - struct scsi_cmnd *cmd = ent->cmd; - - esp_unmap_dma(esp, cmd); - esp_free_lun_tag(ent, cmd->device->hostdata); - cmd->result = DID_RESET << 16; - - if (ent->flags & ESP_CMD_FLAG_AUTOSENSE) { - esp->ops->unmap_single(esp, ent->sense_dma, - SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE); - ent->sense_ptr = NULL; - } - - cmd->scsi_done(cmd); - list_del(&ent->list); - esp_put_ent(esp, ent); -} - -static void esp_clear_hold(struct scsi_device *dev, void *data) -{ - struct esp_lun_data *lp = dev->hostdata; - - BUG_ON(lp->num_tagged); - lp->hold = 0; -} - -static void esp_reset_cleanup(struct esp *esp) -{ - struct esp_cmd_entry *ent, *tmp; - int i; - - list_for_each_entry_safe(ent, tmp, &esp->queued_cmds, list) { - struct scsi_cmnd *cmd = ent->cmd; - - list_del(&ent->list); - cmd->result = DID_RESET << 16; - cmd->scsi_done(cmd); - esp_put_ent(esp, ent); - } - - list_for_each_entry_safe(ent, tmp, &esp->active_cmds, list) { - if (ent == esp->active_cmd) - esp->active_cmd = NULL; - esp_reset_cleanup_one(esp, ent); - } - - BUG_ON(esp->active_cmd != NULL); - - /* Force renegotiation of sync/wide transfers. */ - for (i = 0; i < ESP_MAX_TARGET; i++) { - struct esp_target_data *tp = &esp->target[i]; - - tp->esp_period = 0; - tp->esp_offset = 0; - tp->esp_config3 &= ~(ESP_CONFIG3_EWIDE | - ESP_CONFIG3_FSCSI | - ESP_CONFIG3_FAST); - tp->flags &= ~ESP_TGT_WIDE; - tp->flags |= ESP_TGT_CHECK_NEGO; - - if (tp->starget) - __starget_for_each_device(tp->starget, NULL, - esp_clear_hold); - } - esp->flags &= ~ESP_FLAG_RESETTING; -} - -/* Runs under host->lock */ -static void __esp_interrupt(struct esp *esp) -{ - int finish_reset, intr_done; - u8 phase; - - esp->sreg = esp_read8(ESP_STATUS); - - if (esp->flags & ESP_FLAG_RESETTING) { - finish_reset = 1; - } else { - if (esp_check_gross_error(esp)) - return; - - finish_reset = esp_check_spur_intr(esp); - if (finish_reset < 0) - return; - } - - esp->ireg = esp_read8(ESP_INTRPT); - - if (esp->ireg & ESP_INTR_SR) - finish_reset = 1; - - if (finish_reset) { - esp_reset_cleanup(esp); - if (esp->eh_reset) { - complete(esp->eh_reset); - esp->eh_reset = NULL; - } - return; - } - - phase = (esp->sreg & ESP_STAT_PMASK); - if (esp->rev == FASHME) { - if (((phase != ESP_DIP && phase != ESP_DOP) && - esp->select_state == ESP_SELECT_NONE && - esp->event != ESP_EVENT_STATUS && - esp->event != ESP_EVENT_DATA_DONE) || - (esp->ireg & ESP_INTR_RSEL)) { - esp->sreg2 = esp_read8(ESP_STATUS2); - if (!(esp->sreg2 & ESP_STAT2_FEMPTY) || - (esp->sreg2 & ESP_STAT2_F1BYTE)) - hme_read_fifo(esp); - } - } - - esp_log_intr("ESP: intr sreg[%02x] seqreg[%02x] " - "sreg2[%02x] ireg[%02x]\n", - esp->sreg, esp->seqreg, esp->sreg2, esp->ireg); - - intr_done = 0; - - if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN | ESP_INTR_IC)) { - printk("ESP: unexpected IREG %02x\n", esp->ireg); - if (esp->ireg & ESP_INTR_IC) - esp_dump_cmd_log(esp); - - esp_schedule_reset(esp); - } else { - if (!(esp->ireg & ESP_INTR_RSEL)) { - /* Some combination of FDONE, BSERV, DC. */ - if (esp->select_state != ESP_SELECT_NONE) - intr_done = esp_finish_select(esp); - } else if (esp->ireg & ESP_INTR_RSEL) { - if (esp->active_cmd) - (void) esp_finish_select(esp); - intr_done = esp_reconnect(esp); - } - } - while (!intr_done) - intr_done = esp_process_event(esp); -} - -irqreturn_t scsi_esp_intr(int irq, void *dev_id) -{ - struct esp *esp = dev_id; - unsigned long flags; - irqreturn_t ret; - - spin_lock_irqsave(esp->host->host_lock, flags); - ret = IRQ_NONE; - if (esp->ops->irq_pending(esp)) { - ret = IRQ_HANDLED; - for (;;) { - int i; - - __esp_interrupt(esp); - if (!(esp->flags & ESP_FLAG_QUICKIRQ_CHECK)) - break; - esp->flags &= ~ESP_FLAG_QUICKIRQ_CHECK; - - for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) { - if (esp->ops->irq_pending(esp)) - break; - } - if (i == ESP_QUICKIRQ_LIMIT) - break; - } - } - spin_unlock_irqrestore(esp->host->host_lock, flags); - - return ret; -} -EXPORT_SYMBOL(scsi_esp_intr); - -static void esp_get_revision(struct esp *esp) -{ - u8 val; - - esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7)); - esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY); - esp_write8(esp->config2, ESP_CFG2); - - val = esp_read8(ESP_CFG2); - val &= ~ESP_CONFIG2_MAGIC; - if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) { - /* If what we write to cfg2 does not come back, cfg2 is not - * implemented, therefore this must be a plain esp100. - */ - esp->rev = ESP100; - } else { - esp->config2 = 0; - esp_set_all_config3(esp, 5); - esp->prev_cfg3 = 5; - esp_write8(esp->config2, ESP_CFG2); - esp_write8(0, ESP_CFG3); - esp_write8(esp->prev_cfg3, ESP_CFG3); - - val = esp_read8(ESP_CFG3); - if (val != 5) { - /* The cfg2 register is implemented, however - * cfg3 is not, must be esp100a. - */ - esp->rev = ESP100A; - } else { - esp_set_all_config3(esp, 0); - esp->prev_cfg3 = 0; - esp_write8(esp->prev_cfg3, ESP_CFG3); - - /* All of cfg{1,2,3} implemented, must be one of - * the fas variants, figure out which one. - */ - if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) { - esp->rev = FAST; - esp->sync_defp = SYNC_DEFP_FAST; - } else { - esp->rev = ESP236; - } - esp->config2 = 0; - esp_write8(esp->config2, ESP_CFG2); - } - } -} - -static void esp_init_swstate(struct esp *esp) -{ - int i; - - INIT_LIST_HEAD(&esp->queued_cmds); - INIT_LIST_HEAD(&esp->active_cmds); - INIT_LIST_HEAD(&esp->esp_cmd_pool); - - /* Start with a clear state, domain validation (via ->slave_configure, - * spi_dv_device()) will attempt to enable SYNC, WIDE, and tagged - * commands. - */ - for (i = 0 ; i < ESP_MAX_TARGET; i++) { - esp->target[i].flags = 0; - esp->target[i].nego_goal_period = 0; - esp->target[i].nego_goal_offset = 0; - esp->target[i].nego_goal_width = 0; - esp->target[i].nego_goal_tags = 0; - } -} - -/* This places the ESP into a known state at boot time. */ -static void esp_bootup_reset(struct esp *esp) -{ - u8 val; - - /* Reset the DMA */ - esp->ops->reset_dma(esp); - - /* Reset the ESP */ - esp_reset_esp(esp); - - /* Reset the SCSI bus, but tell ESP not to generate an irq */ - val = esp_read8(ESP_CFG1); - val |= ESP_CONFIG1_SRRDISAB; - esp_write8(val, ESP_CFG1); - - scsi_esp_cmd(esp, ESP_CMD_RS); - udelay(400); - - esp_write8(esp->config1, ESP_CFG1); - - /* Eat any bitrot in the chip and we are done... */ - esp_read8(ESP_INTRPT); -} - -static void esp_set_clock_params(struct esp *esp) -{ - int fhz; - u8 ccf; - - /* This is getting messy but it has to be done correctly or else - * you get weird behavior all over the place. We are trying to - * basically figure out three pieces of information. - * - * a) Clock Conversion Factor - * - * This is a representation of the input crystal clock frequency - * going into the ESP on this machine. Any operation whose timing - * is longer than 400ns depends on this value being correct. For - * example, you'll get blips for arbitration/selection during high - * load or with multiple targets if this is not set correctly. - * - * b) Selection Time-Out - * - * The ESP isn't very bright and will arbitrate for the bus and try - * to select a target forever if you let it. This value tells the - * ESP when it has taken too long to negotiate and that it should - * interrupt the CPU so we can see what happened. The value is - * computed as follows (from NCR/Symbios chip docs). - * - * (Time Out Period) * (Input Clock) - * STO = ---------------------------------- - * (8192) * (Clock Conversion Factor) - * - * We use a time out period of 250ms (ESP_BUS_TIMEOUT). - * - * c) Imperical constants for synchronous offset and transfer period - * register values - * - * This entails the smallest and largest sync period we could ever - * handle on this ESP. - */ - fhz = esp->cfreq; - - ccf = ((fhz / 1000000) + 4) / 5; - if (ccf == 1) - ccf = 2; - - /* If we can't find anything reasonable, just assume 20MHZ. - * This is the clock frequency of the older sun4c's where I've - * been unable to find the clock-frequency PROM property. All - * other machines provide useful values it seems. - */ - if (fhz <= 5000000 || ccf < 1 || ccf > 8) { - fhz = 20000000; - ccf = 4; - } - - esp->cfact = (ccf == 8 ? 0 : ccf); - esp->cfreq = fhz; - esp->ccycle = ESP_HZ_TO_CYCLE(fhz); - esp->ctick = ESP_TICK(ccf, esp->ccycle); - esp->neg_defp = ESP_NEG_DEFP(fhz, ccf); - esp->sync_defp = SYNC_DEFP_SLOW; -} - -static const char *esp_chip_names[] = { - "ESP100", - "ESP100A", - "ESP236", - "FAS236", - "FAS100A", - "FAST", - "FASHME", -}; - -static struct scsi_transport_template *esp_transport_template; - -int scsi_esp_register(struct esp *esp, struct device *dev) -{ - static int instance; - int err; - - esp->host->transportt = esp_transport_template; - esp->host->max_lun = ESP_MAX_LUN; - esp->host->cmd_per_lun = 2; - esp->host->unique_id = instance; - - esp_set_clock_params(esp); - - esp_get_revision(esp); - - esp_init_swstate(esp); - - esp_bootup_reset(esp); - - printk(KERN_INFO PFX "esp%u, regs[%1p:%1p] irq[%u]\n", - esp->host->unique_id, esp->regs, esp->dma_regs, - esp->host->irq); - printk(KERN_INFO PFX "esp%u is a %s, %u MHz (ccf=%u), SCSI ID %u\n", - esp->host->unique_id, esp_chip_names[esp->rev], - esp->cfreq / 1000000, esp->cfact, esp->scsi_id); - - /* Let the SCSI bus reset settle. */ - ssleep(esp_bus_reset_settle); - - err = scsi_add_host(esp->host, dev); - if (err) - return err; - - instance++; - - scsi_scan_host(esp->host); - - return 0; -} -EXPORT_SYMBOL(scsi_esp_register); - -void scsi_esp_unregister(struct esp *esp) -{ - scsi_remove_host(esp->host); -} -EXPORT_SYMBOL(scsi_esp_unregister); - -static int esp_target_alloc(struct scsi_target *starget) -{ - struct esp *esp = shost_priv(dev_to_shost(&starget->dev)); - struct esp_target_data *tp = &esp->target[starget->id]; - - tp->starget = starget; - - return 0; -} - -static void esp_target_destroy(struct scsi_target *starget) -{ - struct esp *esp = shost_priv(dev_to_shost(&starget->dev)); - struct esp_target_data *tp = &esp->target[starget->id]; - - tp->starget = NULL; -} - -static int esp_slave_alloc(struct scsi_device *dev) -{ - struct esp *esp = shost_priv(dev->host); - struct esp_target_data *tp = &esp->target[dev->id]; - struct esp_lun_data *lp; - - lp = kzalloc(sizeof(*lp), GFP_KERNEL); - if (!lp) - return -ENOMEM; - dev->hostdata = lp; - - spi_min_period(tp->starget) = esp->min_period; - spi_max_offset(tp->starget) = 15; - - if (esp->flags & ESP_FLAG_WIDE_CAPABLE) - spi_max_width(tp->starget) = 1; - else - spi_max_width(tp->starget) = 0; - - return 0; -} - -static int esp_slave_configure(struct scsi_device *dev) -{ - struct esp *esp = shost_priv(dev->host); - struct esp_target_data *tp = &esp->target[dev->id]; - int goal_tags, queue_depth; - - goal_tags = 0; - - if (dev->tagged_supported) { - /* XXX make this configurable somehow XXX */ - goal_tags = ESP_DEFAULT_TAGS; - - if (goal_tags > ESP_MAX_TAG) - goal_tags = ESP_MAX_TAG; - } - - queue_depth = goal_tags; - if (queue_depth < dev->host->cmd_per_lun) - queue_depth = dev->host->cmd_per_lun; - - if (goal_tags) { - scsi_set_tag_type(dev, MSG_ORDERED_TAG); - scsi_activate_tcq(dev, queue_depth); - } else { - scsi_deactivate_tcq(dev, queue_depth); - } - tp->flags |= ESP_TGT_DISCONNECT; - - if (!spi_initial_dv(dev->sdev_target)) - spi_dv_device(dev); - - return 0; -} - -static void esp_slave_destroy(struct scsi_device *dev) -{ - struct esp_lun_data *lp = dev->hostdata; - - kfree(lp); - dev->hostdata = NULL; -} - -static int esp_eh_abort_handler(struct scsi_cmnd *cmd) -{ - struct esp *esp = shost_priv(cmd->device->host); - struct esp_cmd_entry *ent, *tmp; - struct completion eh_done; - unsigned long flags; - - /* XXX This helps a lot with debugging but might be a bit - * XXX much for the final driver. - */ - spin_lock_irqsave(esp->host->host_lock, flags); - printk(KERN_ERR PFX "esp%d: Aborting command [%p:%02x]\n", - esp->host->unique_id, cmd, cmd->cmnd[0]); - ent = esp->active_cmd; - if (ent) - printk(KERN_ERR PFX "esp%d: Current command [%p:%02x]\n", - esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); - list_for_each_entry(ent, &esp->queued_cmds, list) { - printk(KERN_ERR PFX "esp%d: Queued command [%p:%02x]\n", - esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); - } - list_for_each_entry(ent, &esp->active_cmds, list) { - printk(KERN_ERR PFX "esp%d: Active command [%p:%02x]\n", - esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]); - } - esp_dump_cmd_log(esp); - spin_unlock_irqrestore(esp->host->host_lock, flags); - - spin_lock_irqsave(esp->host->host_lock, flags); - - ent = NULL; - list_for_each_entry(tmp, &esp->queued_cmds, list) { - if (tmp->cmd == cmd) { - ent = tmp; - break; - } - } - - if (ent) { - /* Easiest case, we didn't even issue the command - * yet so it is trivial to abort. - */ - list_del(&ent->list); - - cmd->result = DID_ABORT << 16; - cmd->scsi_done(cmd); - - esp_put_ent(esp, ent); - - goto out_success; - } - - init_completion(&eh_done); - - ent = esp->active_cmd; - if (ent && ent->cmd == cmd) { - /* Command is the currently active command on - * the bus. If we already have an output message - * pending, no dice. - */ - if (esp->msg_out_len) - goto out_failure; - - /* Send out an abort, encouraging the target to - * go to MSGOUT phase by asserting ATN. - */ - esp->msg_out[0] = ABORT_TASK_SET; - esp->msg_out_len = 1; - ent->eh_done = &eh_done; - - scsi_esp_cmd(esp, ESP_CMD_SATN); - } else { - /* The command is disconnected. This is not easy to - * abort. For now we fail and let the scsi error - * handling layer go try a scsi bus reset or host - * reset. - * - * What we could do is put together a scsi command - * solely for the purpose of sending an abort message - * to the target. Coming up with all the code to - * cook up scsi commands, special case them everywhere, - * etc. is for questionable gain and it would be better - * if the generic scsi error handling layer could do at - * least some of that for us. - * - * Anyways this is an area for potential future improvement - * in this driver. - */ - goto out_failure; - } - - spin_unlock_irqrestore(esp->host->host_lock, flags); - - if (!wait_for_completion_timeout(&eh_done, 5 * HZ)) { - spin_lock_irqsave(esp->host->host_lock, flags); - ent->eh_done = NULL; - spin_unlock_irqrestore(esp->host->host_lock, flags); - - return FAILED; - } - - return SUCCESS; - -out_success: - spin_unlock_irqrestore(esp->host->host_lock, flags); - return SUCCESS; - -out_failure: - /* XXX This might be a good location to set ESP_TGT_BROKEN - * XXX since we know which target/lun in particular is - * XXX causing trouble. - */ - spin_unlock_irqrestore(esp->host->host_lock, flags); - return FAILED; -} - -static int esp_eh_bus_reset_handler(struct scsi_cmnd *cmd) -{ - struct esp *esp = shost_priv(cmd->device->host); - struct completion eh_reset; - unsigned long flags; - - init_completion(&eh_reset); - - spin_lock_irqsave(esp->host->host_lock, flags); - - esp->eh_reset = &eh_reset; - - /* XXX This is too simple... We should add lots of - * XXX checks here so that if we find that the chip is - * XXX very wedged we return failure immediately so - * XXX that we can perform a full chip reset. - */ - esp->flags |= ESP_FLAG_RESETTING; - scsi_esp_cmd(esp, ESP_CMD_RS); - - spin_unlock_irqrestore(esp->host->host_lock, flags); - - ssleep(esp_bus_reset_settle); - - if (!wait_for_completion_timeout(&eh_reset, 5 * HZ)) { - spin_lock_irqsave(esp->host->host_lock, flags); - esp->eh_reset = NULL; - spin_unlock_irqrestore(esp->host->host_lock, flags); - - return FAILED; - } - - return SUCCESS; -} - -/* All bets are off, reset the entire device. */ -static int esp_eh_host_reset_handler(struct scsi_cmnd *cmd) -{ - struct esp *esp = shost_priv(cmd->device->host); - unsigned long flags; - - spin_lock_irqsave(esp->host->host_lock, flags); - esp_bootup_reset(esp); - esp_reset_cleanup(esp); - spin_unlock_irqrestore(esp->host->host_lock, flags); - - ssleep(esp_bus_reset_settle); - - return SUCCESS; -} - -static const char *esp_info(struct Scsi_Host *host) -{ - return "esp"; -} - -struct scsi_host_template scsi_esp_template = { - .module = THIS_MODULE, - .name = "esp", - .info = esp_info, - .queuecommand = esp_queuecommand, - .target_alloc = esp_target_alloc, - .target_destroy = esp_target_destroy, - .slave_alloc = esp_slave_alloc, - .slave_configure = esp_slave_configure, - .slave_destroy = esp_slave_destroy, - .eh_abort_handler = esp_eh_abort_handler, - .eh_bus_reset_handler = esp_eh_bus_reset_handler, - .eh_host_reset_handler = esp_eh_host_reset_handler, - .can_queue = 7, - .this_id = 7, - .sg_tablesize = SG_ALL, - .use_clustering = ENABLE_CLUSTERING, - .max_sectors = 0xffff, - .skip_settle_delay = 1, -}; -EXPORT_SYMBOL(scsi_esp_template); - -static void esp_get_signalling(struct Scsi_Host *host) -{ - struct esp *esp = shost_priv(host); - enum spi_signal_type type; - - if (esp->flags & ESP_FLAG_DIFFERENTIAL) - type = SPI_SIGNAL_HVD; - else - type = SPI_SIGNAL_SE; - - spi_signalling(host) = type; -} - -static void esp_set_offset(struct scsi_target *target, int offset) -{ - struct Scsi_Host *host = dev_to_shost(target->dev.parent); - struct esp *esp = shost_priv(host); - struct esp_target_data *tp = &esp->target[target->id]; - - if (esp->flags & ESP_FLAG_DISABLE_SYNC) - tp->nego_goal_offset = 0; - else - tp->nego_goal_offset = offset; - tp->flags |= ESP_TGT_CHECK_NEGO; -} - -static void esp_set_period(struct scsi_target *target, int period) -{ - struct Scsi_Host *host = dev_to_shost(target->dev.parent); - struct esp *esp = shost_priv(host); - struct esp_target_data *tp = &esp->target[target->id]; - - tp->nego_goal_period = period; - tp->flags |= ESP_TGT_CHECK_NEGO; -} - -static void esp_set_width(struct scsi_target *target, int width) -{ - struct Scsi_Host *host = dev_to_shost(target->dev.parent); - struct esp *esp = shost_priv(host); - struct esp_target_data *tp = &esp->target[target->id]; - - tp->nego_goal_width = (width ? 1 : 0); - tp->flags |= ESP_TGT_CHECK_NEGO; -} - -static struct spi_function_template esp_transport_ops = { - .set_offset = esp_set_offset, - .show_offset = 1, - .set_period = esp_set_period, - .show_period = 1, - .set_width = esp_set_width, - .show_width = 1, - .get_signalling = esp_get_signalling, -}; - -static int __init esp_init(void) -{ - BUILD_BUG_ON(sizeof(struct scsi_pointer) < - sizeof(struct esp_cmd_priv)); - - esp_transport_template = spi_attach_transport(&esp_transport_ops); - if (!esp_transport_template) - return -ENODEV; - - return 0; -} - -static void __exit esp_exit(void) -{ - spi_release_transport(esp_transport_template); -} - -MODULE_DESCRIPTION("ESP SCSI driver core"); -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -module_param(esp_bus_reset_settle, int, 0); -MODULE_PARM_DESC(esp_bus_reset_settle, - "ESP scsi bus reset delay in seconds"); - -module_param(esp_debug, int, 0); -MODULE_PARM_DESC(esp_debug, -"ESP bitmapped debugging message enable value:\n" -" 0x00000001 Log interrupt events\n" -" 0x00000002 Log scsi commands\n" -" 0x00000004 Log resets\n" -" 0x00000008 Log message in events\n" -" 0x00000010 Log message out events\n" -" 0x00000020 Log command completion\n" -" 0x00000040 Log disconnects\n" -" 0x00000080 Log data start\n" -" 0x00000100 Log data done\n" -" 0x00000200 Log reconnects\n" -" 0x00000400 Log auto-sense data\n" -); - -module_init(esp_init); -module_exit(esp_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/esp_scsi.h b/ANDROID_3.4.5/drivers/scsi/esp_scsi.h deleted file mode 100644 index 28e22acf..00000000 --- a/ANDROID_3.4.5/drivers/scsi/esp_scsi.h +++ /dev/null @@ -1,566 +0,0 @@ -/* esp_scsi.h: Defines and structures for the ESP drier. - * - * Copyright (C) 2007 David S. Miller (davem@davemloft.net) - */ - -#ifndef _ESP_SCSI_H -#define _ESP_SCSI_H - - /* Access Description Offset */ -#define ESP_TCLOW 0x00UL /* rw Low bits transfer count 0x00 */ -#define ESP_TCMED 0x01UL /* rw Mid bits transfer count 0x04 */ -#define ESP_FDATA 0x02UL /* rw FIFO data bits 0x08 */ -#define ESP_CMD 0x03UL /* rw SCSI command bits 0x0c */ -#define ESP_STATUS 0x04UL /* ro ESP status register 0x10 */ -#define ESP_BUSID ESP_STATUS /* wo BusID for sel/resel 0x10 */ -#define ESP_INTRPT 0x05UL /* ro Kind of interrupt 0x14 */ -#define ESP_TIMEO ESP_INTRPT /* wo Timeout for sel/resel 0x14 */ -#define ESP_SSTEP 0x06UL /* ro Sequence step register 0x18 */ -#define ESP_STP ESP_SSTEP /* wo Transfer period/sync 0x18 */ -#define ESP_FFLAGS 0x07UL /* ro Bits current FIFO info 0x1c */ -#define ESP_SOFF ESP_FFLAGS /* wo Sync offset 0x1c */ -#define ESP_CFG1 0x08UL /* rw First cfg register 0x20 */ -#define ESP_CFACT 0x09UL /* wo Clock conv factor 0x24 */ -#define ESP_STATUS2 ESP_CFACT /* ro HME status2 register 0x24 */ -#define ESP_CTEST 0x0aUL /* wo Chip test register 0x28 */ -#define ESP_CFG2 0x0bUL /* rw Second cfg register 0x2c */ -#define ESP_CFG3 0x0cUL /* rw Third cfg register 0x30 */ -#define ESP_TCHI 0x0eUL /* rw High bits transf count 0x38 */ -#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */ -#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */ -#define ESP_FGRND 0x0fUL /* rw Data base for fifo 0x3c */ -#define FAS_RHI ESP_FGRND /* rw HME extended counter 0x3c */ - -#define SBUS_ESP_REG_SIZE 0x40UL - -/* Bitfield meanings for the above registers. */ - -/* ESP config reg 1, read-write, found on all ESP chips */ -#define ESP_CONFIG1_ID 0x07 /* My BUS ID bits */ -#define ESP_CONFIG1_CHTEST 0x08 /* Enable ESP chip tests */ -#define ESP_CONFIG1_PENABLE 0x10 /* Enable parity checks */ -#define ESP_CONFIG1_PARTEST 0x20 /* Parity test mode enabled? */ -#define ESP_CONFIG1_SRRDISAB 0x40 /* Disable SCSI reset reports */ -#define ESP_CONFIG1_SLCABLE 0x80 /* Enable slow cable mode */ - -/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */ -#define ESP_CONFIG2_DMAPARITY 0x01 /* enable DMA Parity (200,236) */ -#define ESP_CONFIG2_REGPARITY 0x02 /* enable reg Parity (200,236) */ -#define ESP_CONFIG2_BADPARITY 0x04 /* Bad parity target abort */ -#define ESP_CONFIG2_SCSI2ENAB 0x08 /* Enable SCSI-2 features (tgtmode) */ -#define ESP_CONFIG2_HI 0x10 /* High Impedance DREQ ??? */ -#define ESP_CONFIG2_HMEFENAB 0x10 /* HME features enable */ -#define ESP_CONFIG2_BCM 0x20 /* Enable byte-ctrl (236) */ -#define ESP_CONFIG2_DISPINT 0x20 /* Disable pause irq (hme) */ -#define ESP_CONFIG2_FENAB 0x40 /* Enable features (fas100,216) */ -#define ESP_CONFIG2_SPL 0x40 /* Enable status-phase latch (236) */ -#define ESP_CONFIG2_MKDONE 0x40 /* HME magic feature */ -#define ESP_CONFIG2_HME32 0x80 /* HME 32 extended */ -#define ESP_CONFIG2_MAGIC 0xe0 /* Invalid bits... */ - -/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */ -#define ESP_CONFIG3_FCLOCK 0x01 /* FAST SCSI clock rate (esp100a/hme) */ -#define ESP_CONFIG3_TEM 0x01 /* Enable thresh-8 mode (esp/fas236) */ -#define ESP_CONFIG3_FAST 0x02 /* Enable FAST SCSI (esp100a/hme) */ -#define ESP_CONFIG3_ADMA 0x02 /* Enable alternate-dma (esp/fas236) */ -#define ESP_CONFIG3_TENB 0x04 /* group2 SCSI2 support (esp100a/hme) */ -#define ESP_CONFIG3_SRB 0x04 /* Save residual byte (esp/fas236) */ -#define ESP_CONFIG3_TMS 0x08 /* Three-byte msg's ok (esp100a/hme) */ -#define ESP_CONFIG3_FCLK 0x08 /* Fast SCSI clock rate (esp/fas236) */ -#define ESP_CONFIG3_IDMSG 0x10 /* ID message checking (esp100a/hme) */ -#define ESP_CONFIG3_FSCSI 0x10 /* Enable FAST SCSI (esp/fas236) */ -#define ESP_CONFIG3_GTM 0x20 /* group2 SCSI2 support (esp/fas236) */ -#define ESP_CONFIG3_IDBIT3 0x20 /* Bit 3 of HME SCSI-ID (hme) */ -#define ESP_CONFIG3_TBMS 0x40 /* Three-byte msg's ok (esp/fas236) */ -#define ESP_CONFIG3_EWIDE 0x40 /* Enable Wide-SCSI (hme) */ -#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */ -#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */ - -/* ESP command register read-write */ -/* Group 1 commands: These may be sent at any point in time to the ESP - * chip. None of them can generate interrupts 'cept - * the "SCSI bus reset" command if you have not disabled - * SCSI reset interrupts in the config1 ESP register. - */ -#define ESP_CMD_NULL 0x00 /* Null command, ie. a nop */ -#define ESP_CMD_FLUSH 0x01 /* FIFO Flush */ -#define ESP_CMD_RC 0x02 /* Chip reset */ -#define ESP_CMD_RS 0x03 /* SCSI bus reset */ - -/* Group 2 commands: ESP must be an initiator and connected to a target - * for these commands to work. - */ -#define ESP_CMD_TI 0x10 /* Transfer Information */ -#define ESP_CMD_ICCSEQ 0x11 /* Initiator cmd complete sequence */ -#define ESP_CMD_MOK 0x12 /* Message okie-dokie */ -#define ESP_CMD_TPAD 0x18 /* Transfer Pad */ -#define ESP_CMD_SATN 0x1a /* Set ATN */ -#define ESP_CMD_RATN 0x1b /* De-assert ATN */ - -/* Group 3 commands: ESP must be in the MSGOUT or MSGIN state and be connected - * to a target as the initiator for these commands to work. - */ -#define ESP_CMD_SMSG 0x20 /* Send message */ -#define ESP_CMD_SSTAT 0x21 /* Send status */ -#define ESP_CMD_SDATA 0x22 /* Send data */ -#define ESP_CMD_DSEQ 0x23 /* Discontinue Sequence */ -#define ESP_CMD_TSEQ 0x24 /* Terminate Sequence */ -#define ESP_CMD_TCCSEQ 0x25 /* Target cmd cmplt sequence */ -#define ESP_CMD_DCNCT 0x27 /* Disconnect */ -#define ESP_CMD_RMSG 0x28 /* Receive Message */ -#define ESP_CMD_RCMD 0x29 /* Receive Command */ -#define ESP_CMD_RDATA 0x2a /* Receive Data */ -#define ESP_CMD_RCSEQ 0x2b /* Receive cmd sequence */ - -/* Group 4 commands: The ESP must be in the disconnected state and must - * not be connected to any targets as initiator for - * these commands to work. - */ -#define ESP_CMD_RSEL 0x40 /* Reselect */ -#define ESP_CMD_SEL 0x41 /* Select w/o ATN */ -#define ESP_CMD_SELA 0x42 /* Select w/ATN */ -#define ESP_CMD_SELAS 0x43 /* Select w/ATN & STOP */ -#define ESP_CMD_ESEL 0x44 /* Enable selection */ -#define ESP_CMD_DSEL 0x45 /* Disable selections */ -#define ESP_CMD_SA3 0x46 /* Select w/ATN3 */ -#define ESP_CMD_RSEL3 0x47 /* Reselect3 */ - -/* This bit enables the ESP's DMA on the SBus */ -#define ESP_CMD_DMA 0x80 /* Do DMA? */ - -/* ESP status register read-only */ -#define ESP_STAT_PIO 0x01 /* IO phase bit */ -#define ESP_STAT_PCD 0x02 /* CD phase bit */ -#define ESP_STAT_PMSG 0x04 /* MSG phase bit */ -#define ESP_STAT_PMASK 0x07 /* Mask of phase bits */ -#define ESP_STAT_TDONE 0x08 /* Transfer Completed */ -#define ESP_STAT_TCNT 0x10 /* Transfer Counter Is Zero */ -#define ESP_STAT_PERR 0x20 /* Parity error */ -#define ESP_STAT_SPAM 0x40 /* Real bad error */ -/* This indicates the 'interrupt pending' condition on esp236, it is a reserved - * bit on other revs of the ESP. - */ -#define ESP_STAT_INTR 0x80 /* Interrupt */ - -/* The status register can be masked with ESP_STAT_PMASK and compared - * with the following values to determine the current phase the ESP - * (at least thinks it) is in. For our purposes we also add our own - * software 'done' bit for our phase management engine. - */ -#define ESP_DOP (0) /* Data Out */ -#define ESP_DIP (ESP_STAT_PIO) /* Data In */ -#define ESP_CMDP (ESP_STAT_PCD) /* Command */ -#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO) /* Status */ -#define ESP_MOP (ESP_STAT_PMSG|ESP_STAT_PCD) /* Message Out */ -#define ESP_MIP (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */ - -/* HME only: status 2 register */ -#define ESP_STAT2_SCHBIT 0x01 /* Upper bits 3-7 of sstep enabled */ -#define ESP_STAT2_FFLAGS 0x02 /* The fifo flags are now latched */ -#define ESP_STAT2_XCNT 0x04 /* The transfer counter is latched */ -#define ESP_STAT2_CREGA 0x08 /* The command reg is active now */ -#define ESP_STAT2_WIDE 0x10 /* Interface on this adapter is wide */ -#define ESP_STAT2_F1BYTE 0x20 /* There is one byte at top of fifo */ -#define ESP_STAT2_FMSB 0x40 /* Next byte in fifo is most significant */ -#define ESP_STAT2_FEMPTY 0x80 /* FIFO is empty */ - -/* ESP interrupt register read-only */ -#define ESP_INTR_S 0x01 /* Select w/o ATN */ -#define ESP_INTR_SATN 0x02 /* Select w/ATN */ -#define ESP_INTR_RSEL 0x04 /* Reselected */ -#define ESP_INTR_FDONE 0x08 /* Function done */ -#define ESP_INTR_BSERV 0x10 /* Bus service */ -#define ESP_INTR_DC 0x20 /* Disconnect */ -#define ESP_INTR_IC 0x40 /* Illegal command given */ -#define ESP_INTR_SR 0x80 /* SCSI bus reset detected */ - -/* ESP sequence step register read-only */ -#define ESP_STEP_VBITS 0x07 /* Valid bits */ -#define ESP_STEP_ASEL 0x00 /* Selection&Arbitrate cmplt */ -#define ESP_STEP_SID 0x01 /* One msg byte sent */ -#define ESP_STEP_NCMD 0x02 /* Was not in command phase */ -#define ESP_STEP_PPC 0x03 /* Early phase chg caused cmnd - * bytes to be lost - */ -#define ESP_STEP_FINI4 0x04 /* Command was sent ok */ - -/* Ho hum, some ESP's set the step register to this as well... */ -#define ESP_STEP_FINI5 0x05 -#define ESP_STEP_FINI6 0x06 -#define ESP_STEP_FINI7 0x07 - -/* ESP chip-test register read-write */ -#define ESP_TEST_TARG 0x01 /* Target test mode */ -#define ESP_TEST_INI 0x02 /* Initiator test mode */ -#define ESP_TEST_TS 0x04 /* Tristate test mode */ - -/* ESP unique ID register read-only, found on fas236+fas100a only */ -#define ESP_UID_F100A 0x00 /* ESP FAS100A */ -#define ESP_UID_F236 0x02 /* ESP FAS236 */ -#define ESP_UID_REV 0x07 /* ESP revision */ -#define ESP_UID_FAM 0xf8 /* ESP family */ - -/* ESP fifo flags register read-only */ -/* Note that the following implies a 16 byte FIFO on the ESP. */ -#define ESP_FF_FBYTES 0x1f /* Num bytes in FIFO */ -#define ESP_FF_ONOTZERO 0x20 /* offset ctr not zero (esp100) */ -#define ESP_FF_SSTEP 0xe0 /* Sequence step */ - -/* ESP clock conversion factor register write-only */ -#define ESP_CCF_F0 0x00 /* 35.01MHz - 40MHz */ -#define ESP_CCF_NEVER 0x01 /* Set it to this and die */ -#define ESP_CCF_F2 0x02 /* 10MHz */ -#define ESP_CCF_F3 0x03 /* 10.01MHz - 15MHz */ -#define ESP_CCF_F4 0x04 /* 15.01MHz - 20MHz */ -#define ESP_CCF_F5 0x05 /* 20.01MHz - 25MHz */ -#define ESP_CCF_F6 0x06 /* 25.01MHz - 30MHz */ -#define ESP_CCF_F7 0x07 /* 30.01MHz - 35MHz */ - -/* HME only... */ -#define ESP_BUSID_RESELID 0x10 -#define ESP_BUSID_CTR32BIT 0x40 - -#define ESP_BUS_TIMEOUT 250 /* In milli-seconds */ -#define ESP_TIMEO_CONST 8192 -#define ESP_NEG_DEFP(mhz, cfact) \ - ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact))) -#define ESP_HZ_TO_CYCLE(hertz) ((1000000000) / ((hertz) / 1000)) -#define ESP_TICK(ccf, cycle) ((7682 * (ccf) * (cycle) / 1000)) - -/* For slow to medium speed input clock rates we shoot for 5mb/s, but for high - * input clock rates we try to do 10mb/s although I don't think a transfer can - * even run that fast with an ESP even with DMA2 scatter gather pipelining. - */ -#define SYNC_DEFP_SLOW 0x32 /* 5mb/s */ -#define SYNC_DEFP_FAST 0x19 /* 10mb/s */ - -struct esp_cmd_priv { - union { - dma_addr_t dma_addr; - int num_sg; - } u; - - int cur_residue; - struct scatterlist *cur_sg; - int tot_residue; -}; -#define ESP_CMD_PRIV(CMD) ((struct esp_cmd_priv *)(&(CMD)->SCp)) - -enum esp_rev { - ESP100 = 0x00, /* NCR53C90 - very broken */ - ESP100A = 0x01, /* NCR53C90A */ - ESP236 = 0x02, - FAS236 = 0x03, - FAS100A = 0x04, - FAST = 0x05, - FASHME = 0x06, -}; - -struct esp_cmd_entry { - struct list_head list; - - struct scsi_cmnd *cmd; - - unsigned int saved_cur_residue; - struct scatterlist *saved_cur_sg; - unsigned int saved_tot_residue; - - u8 flags; -#define ESP_CMD_FLAG_WRITE 0x01 /* DMA is a write */ -#define ESP_CMD_FLAG_ABORT 0x02 /* being aborted */ -#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */ - - u8 tag[2]; - - u8 status; - u8 message; - - unsigned char *sense_ptr; - unsigned char *saved_sense_ptr; - dma_addr_t sense_dma; - - struct completion *eh_done; -}; - -/* XXX make this configurable somehow XXX */ -#define ESP_DEFAULT_TAGS 16 - -#define ESP_MAX_TARGET 16 -#define ESP_MAX_LUN 8 -#define ESP_MAX_TAG 256 - -struct esp_lun_data { - struct esp_cmd_entry *non_tagged_cmd; - int num_tagged; - int hold; - struct esp_cmd_entry *tagged_cmds[ESP_MAX_TAG]; -}; - -struct esp_target_data { - /* These are the ESP_STP, ESP_SOFF, and ESP_CFG3 register values which - * match the currently negotiated settings for this target. The SCSI - * protocol values are maintained in spi_{offset,period,wide}(starget). - */ - u8 esp_period; - u8 esp_offset; - u8 esp_config3; - - u8 flags; -#define ESP_TGT_WIDE 0x01 -#define ESP_TGT_DISCONNECT 0x02 -#define ESP_TGT_NEGO_WIDE 0x04 -#define ESP_TGT_NEGO_SYNC 0x08 -#define ESP_TGT_CHECK_NEGO 0x40 -#define ESP_TGT_BROKEN 0x80 - - /* When ESP_TGT_CHECK_NEGO is set, on the next scsi command to this - * device we will try to negotiate the following parameters. - */ - u8 nego_goal_period; - u8 nego_goal_offset; - u8 nego_goal_width; - u8 nego_goal_tags; - - struct scsi_target *starget; -}; - -struct esp_event_ent { - u8 type; -#define ESP_EVENT_TYPE_EVENT 0x01 -#define ESP_EVENT_TYPE_CMD 0x02 - u8 val; - - u8 sreg; - u8 seqreg; - u8 sreg2; - u8 ireg; - u8 select_state; - u8 event; - u8 __pad; -}; - -struct esp; -struct esp_driver_ops { - /* Read and write the ESP 8-bit registers. On some - * applications of the ESP chip the registers are at 4-byte - * instead of 1-byte intervals. - */ - void (*esp_write8)(struct esp *esp, u8 val, unsigned long reg); - u8 (*esp_read8)(struct esp *esp, unsigned long reg); - - /* Map and unmap DMA memory. Eventually the driver will be - * converted to the generic DMA API as soon as SBUS is able to - * cope with that. At such time we can remove this. - */ - dma_addr_t (*map_single)(struct esp *esp, void *buf, - size_t sz, int dir); - int (*map_sg)(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir); - void (*unmap_single)(struct esp *esp, dma_addr_t addr, - size_t sz, int dir); - void (*unmap_sg)(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir); - - /* Return non-zero if there is an IRQ pending. Usually this - * status bit lives in the DMA controller sitting in front of - * the ESP. This has to be accurate or else the ESP interrupt - * handler will not run. - */ - int (*irq_pending)(struct esp *esp); - - /* Return the maximum allowable size of a DMA transfer for a - * given buffer. - */ - u32 (*dma_length_limit)(struct esp *esp, u32 dma_addr, - u32 dma_len); - - /* Reset the DMA engine entirely. On return, ESP interrupts - * should be enabled. Often the interrupt enabling is - * controlled in the DMA engine. - */ - void (*reset_dma)(struct esp *esp); - - /* Drain any pending DMA in the DMA engine after a transfer. - * This is for writes to memory. - */ - void (*dma_drain)(struct esp *esp); - - /* Invalidate the DMA engine after a DMA transfer. */ - void (*dma_invalidate)(struct esp *esp); - - /* Setup an ESP command that will use a DMA transfer. - * The 'esp_count' specifies what transfer length should be - * programmed into the ESP transfer counter registers, whereas - * the 'dma_count' is the length that should be programmed into - * the DMA controller. Usually they are the same. If 'write' - * is non-zero, this transfer is a write into memory. 'cmd' - * holds the ESP command that should be issued by calling - * scsi_esp_cmd() at the appropriate time while programming - * the DMA hardware. - */ - void (*send_dma_cmd)(struct esp *esp, u32 dma_addr, u32 esp_count, - u32 dma_count, int write, u8 cmd); - - /* Return non-zero if the DMA engine is reporting an error - * currently. - */ - int (*dma_error)(struct esp *esp); -}; - -#define ESP_MAX_MSG_SZ 8 -#define ESP_EVENT_LOG_SZ 32 - -#define ESP_QUICKIRQ_LIMIT 100 -#define ESP_RESELECT_TAG_LIMIT 2500 - -struct esp { - void __iomem *regs; - void __iomem *dma_regs; - - const struct esp_driver_ops *ops; - - struct Scsi_Host *host; - void *dev; - - struct esp_cmd_entry *active_cmd; - - struct list_head queued_cmds; - struct list_head active_cmds; - - u8 *command_block; - dma_addr_t command_block_dma; - - unsigned int data_dma_len; - - /* The following are used to determine the cause of an IRQ. Upon every - * IRQ entry we synchronize these with the hardware registers. - */ - u8 sreg; - u8 seqreg; - u8 sreg2; - u8 ireg; - - u32 prev_hme_dmacsr; - u8 prev_soff; - u8 prev_stp; - u8 prev_cfg3; - u8 __pad; - - struct list_head esp_cmd_pool; - - struct esp_target_data target[ESP_MAX_TARGET]; - - int fifo_cnt; - u8 fifo[16]; - - struct esp_event_ent esp_event_log[ESP_EVENT_LOG_SZ]; - int esp_event_cur; - - u8 msg_out[ESP_MAX_MSG_SZ]; - int msg_out_len; - - u8 msg_in[ESP_MAX_MSG_SZ]; - int msg_in_len; - - u8 bursts; - u8 config1; - u8 config2; - - u8 scsi_id; - u32 scsi_id_mask; - - enum esp_rev rev; - - u32 flags; -#define ESP_FLAG_DIFFERENTIAL 0x00000001 -#define ESP_FLAG_RESETTING 0x00000002 -#define ESP_FLAG_DOING_SLOWCMD 0x00000004 -#define ESP_FLAG_WIDE_CAPABLE 0x00000008 -#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010 -#define ESP_FLAG_DISABLE_SYNC 0x00000020 - - u8 select_state; -#define ESP_SELECT_NONE 0x00 /* Not selecting */ -#define ESP_SELECT_BASIC 0x01 /* Select w/o MSGOUT phase */ -#define ESP_SELECT_MSGOUT 0x02 /* Select with MSGOUT */ - - /* When we are not selecting, we are expecting an event. */ - u8 event; -#define ESP_EVENT_NONE 0x00 -#define ESP_EVENT_CMD_START 0x01 -#define ESP_EVENT_CMD_DONE 0x02 -#define ESP_EVENT_DATA_IN 0x03 -#define ESP_EVENT_DATA_OUT 0x04 -#define ESP_EVENT_DATA_DONE 0x05 -#define ESP_EVENT_MSGIN 0x06 -#define ESP_EVENT_MSGIN_MORE 0x07 -#define ESP_EVENT_MSGIN_DONE 0x08 -#define ESP_EVENT_MSGOUT 0x09 -#define ESP_EVENT_MSGOUT_DONE 0x0a -#define ESP_EVENT_STATUS 0x0b -#define ESP_EVENT_FREE_BUS 0x0c -#define ESP_EVENT_CHECK_PHASE 0x0d -#define ESP_EVENT_RESET 0x10 - - /* Probed in esp_get_clock_params() */ - u32 cfact; - u32 cfreq; - u32 ccycle; - u32 ctick; - u32 neg_defp; - u32 sync_defp; - - /* Computed in esp_reset_esp() */ - u32 max_period; - u32 min_period; - u32 radelay; - - /* Slow command state. */ - u8 *cmd_bytes_ptr; - int cmd_bytes_left; - - struct completion *eh_reset; - - void *dma; - int dmarev; -}; - -/* A front-end driver for the ESP chip should do the following in - * it's device probe routine: - * 1) Allocate the host and private area using scsi_host_alloc() - * with size 'sizeof(struct esp)'. The first argument to - * scsi_host_alloc() should be &scsi_esp_template. - * 2) Set host->max_id as appropriate. - * 3) Set esp->host to the scsi_host itself, and esp->dev - * to the device object pointer. - * 4) Hook up esp->ops to the front-end implementation. - * 5) If the ESP chip supports wide transfers, set ESP_FLAG_WIDE_CAPABLE - * in esp->flags. - * 6) Map the DMA and ESP chip registers. - * 7) DMA map the ESP command block, store the DMA address - * in esp->command_block_dma. - * 8) Register the scsi_esp_intr() interrupt handler. - * 9) Probe for and provide the following chip properties: - * esp->scsi_id (assign to esp->host->this_id too) - * esp->scsi_id_mask - * If ESP bus is differential, set ESP_FLAG_DIFFERENTIAL - * esp->cfreq - * DMA burst bit mask in esp->bursts, if necessary - * 10) Perform any actions necessary before the ESP device can - * be programmed for the first time. On some configs, for - * example, the DMA engine has to be reset before ESP can - * be programmed. - * 11) If necessary, call dev_set_drvdata() as needed. - * 12) Call scsi_esp_register() with prepared 'esp' structure - * and a device pointer if possible. - * 13) Check scsi_esp_register() return value, release all resources - * if an error was returned. - */ -extern struct scsi_host_template scsi_esp_template; -extern int scsi_esp_register(struct esp *, struct device *); - -extern void scsi_esp_unregister(struct esp *); -extern irqreturn_t scsi_esp_intr(int, void *); -extern void scsi_esp_cmd(struct esp *, u8); - -#endif /* !(_ESP_SCSI_H) */ diff --git a/ANDROID_3.4.5/drivers/scsi/fcoe/Makefile b/ANDROID_3.4.5/drivers/scsi/fcoe/Makefile deleted file mode 100644 index f6d37d02..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fcoe/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-$(CONFIG_FCOE) += fcoe.o -obj-$(CONFIG_LIBFCOE) += libfcoe.o - -libfcoe-objs := fcoe_ctlr.o fcoe_transport.o diff --git a/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.c b/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.c deleted file mode 100644 index 335e8519..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.c +++ /dev/null @@ -1,2734 +0,0 @@ -/* - * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "fcoe.h" - -MODULE_AUTHOR("Open-FCoE.org"); -MODULE_DESCRIPTION("FCoE"); -MODULE_LICENSE("GPL v2"); - -/* Performance tuning parameters for fcoe */ -static unsigned int fcoe_ddp_min = 4096; -module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \ - "Direct Data Placement (DDP)."); - -unsigned int fcoe_debug_logging; -module_param_named(debug_logging, fcoe_debug_logging, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); - -static DEFINE_MUTEX(fcoe_config_mutex); - -static struct workqueue_struct *fcoe_wq; - -/* fcoe_percpu_clean completion. Waiter protected by fcoe_create_mutex */ -static DECLARE_COMPLETION(fcoe_flush_completion); - -/* fcoe host list */ -/* must only by accessed under the RTNL mutex */ -static LIST_HEAD(fcoe_hostlist); -static DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu); - -/* Function Prototypes */ -static int fcoe_reset(struct Scsi_Host *); -static int fcoe_xmit(struct fc_lport *, struct fc_frame *); -static int fcoe_rcv(struct sk_buff *, struct net_device *, - struct packet_type *, struct net_device *); -static int fcoe_percpu_receive_thread(void *); -static void fcoe_percpu_clean(struct fc_lport *); -static int fcoe_link_speed_update(struct fc_lport *); -static int fcoe_link_ok(struct fc_lport *); - -static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *); -static int fcoe_hostlist_add(const struct fc_lport *); - -static int fcoe_device_notification(struct notifier_block *, ulong, void *); -static void fcoe_dev_setup(void); -static void fcoe_dev_cleanup(void); -static struct fcoe_interface -*fcoe_hostlist_lookup_port(const struct net_device *); - -static int fcoe_fip_recv(struct sk_buff *, struct net_device *, - struct packet_type *, struct net_device *); - -static void fcoe_fip_send(struct fcoe_ctlr *, struct sk_buff *); -static void fcoe_update_src_mac(struct fc_lport *, u8 *); -static u8 *fcoe_get_src_mac(struct fc_lport *); -static void fcoe_destroy_work(struct work_struct *); - -static int fcoe_ddp_setup(struct fc_lport *, u16, struct scatterlist *, - unsigned int); -static int fcoe_ddp_done(struct fc_lport *, u16); -static int fcoe_ddp_target(struct fc_lport *, u16, struct scatterlist *, - unsigned int); -static int fcoe_cpu_callback(struct notifier_block *, unsigned long, void *); -static int fcoe_dcb_app_notification(struct notifier_block *notifier, - ulong event, void *ptr); - -static bool fcoe_match(struct net_device *netdev); -static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode); -static int fcoe_destroy(struct net_device *netdev); -static int fcoe_enable(struct net_device *netdev); -static int fcoe_disable(struct net_device *netdev); - -static struct fc_seq *fcoe_elsct_send(struct fc_lport *, - u32 did, struct fc_frame *, - unsigned int op, - void (*resp)(struct fc_seq *, - struct fc_frame *, - void *), - void *, u32 timeout); -static void fcoe_recv_frame(struct sk_buff *skb); - -static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *); - -/* notification function for packets from net device */ -static struct notifier_block fcoe_notifier = { - .notifier_call = fcoe_device_notification, -}; - -/* notification function for CPU hotplug events */ -static struct notifier_block fcoe_cpu_notifier = { - .notifier_call = fcoe_cpu_callback, -}; - -/* notification function for DCB events */ -static struct notifier_block dcb_notifier = { - .notifier_call = fcoe_dcb_app_notification, -}; - -static struct scsi_transport_template *fcoe_nport_scsi_transport; -static struct scsi_transport_template *fcoe_vport_scsi_transport; - -static int fcoe_vport_destroy(struct fc_vport *); -static int fcoe_vport_create(struct fc_vport *, bool disabled); -static int fcoe_vport_disable(struct fc_vport *, bool disable); -static void fcoe_set_vport_symbolic_name(struct fc_vport *); -static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *); - -static struct libfc_function_template fcoe_libfc_fcn_templ = { - .frame_send = fcoe_xmit, - .ddp_setup = fcoe_ddp_setup, - .ddp_done = fcoe_ddp_done, - .ddp_target = fcoe_ddp_target, - .elsct_send = fcoe_elsct_send, - .get_lesb = fcoe_get_lesb, - .lport_set_port_id = fcoe_set_port_id, -}; - -static struct fc_function_template fcoe_nport_fc_functions = { - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_active_fc4s = 1, - .show_host_maxframe_size = 1, - .show_host_serial_number = 1, - .show_host_manufacturer = 1, - .show_host_model = 1, - .show_host_model_description = 1, - .show_host_hardware_version = 1, - .show_host_driver_version = 1, - .show_host_firmware_version = 1, - .show_host_optionrom_version = 1, - - .show_host_port_id = 1, - .show_host_supported_speeds = 1, - .get_host_speed = fc_get_host_speed, - .show_host_speed = 1, - .show_host_port_type = 1, - .get_host_port_state = fc_get_host_port_state, - .show_host_port_state = 1, - .show_host_symbolic_name = 1, - - .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - - .show_host_fabric_name = 1, - .show_starget_node_name = 1, - .show_starget_port_name = 1, - .show_starget_port_id = 1, - .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - .get_fc_host_stats = fc_get_host_stats, - .issue_fc_host_lip = fcoe_reset, - - .terminate_rport_io = fc_rport_terminate_io, - - .vport_create = fcoe_vport_create, - .vport_delete = fcoe_vport_destroy, - .vport_disable = fcoe_vport_disable, - .set_vport_symbolic_name = fcoe_set_vport_symbolic_name, - - .bsg_request = fc_lport_bsg_request, -}; - -static struct fc_function_template fcoe_vport_fc_functions = { - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_active_fc4s = 1, - .show_host_maxframe_size = 1, - .show_host_serial_number = 1, - .show_host_manufacturer = 1, - .show_host_model = 1, - .show_host_model_description = 1, - .show_host_hardware_version = 1, - .show_host_driver_version = 1, - .show_host_firmware_version = 1, - .show_host_optionrom_version = 1, - - .show_host_port_id = 1, - .show_host_supported_speeds = 1, - .get_host_speed = fc_get_host_speed, - .show_host_speed = 1, - .show_host_port_type = 1, - .get_host_port_state = fc_get_host_port_state, - .show_host_port_state = 1, - .show_host_symbolic_name = 1, - - .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - - .show_host_fabric_name = 1, - .show_starget_node_name = 1, - .show_starget_port_name = 1, - .show_starget_port_id = 1, - .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - .get_fc_host_stats = fc_get_host_stats, - .issue_fc_host_lip = fcoe_reset, - - .terminate_rport_io = fc_rport_terminate_io, - - .bsg_request = fc_lport_bsg_request, -}; - -static struct scsi_host_template fcoe_shost_template = { - .module = THIS_MODULE, - .name = "FCoE Driver", - .proc_name = FCOE_NAME, - .queuecommand = fc_queuecommand, - .eh_abort_handler = fc_eh_abort, - .eh_device_reset_handler = fc_eh_device_reset, - .eh_host_reset_handler = fc_eh_host_reset, - .slave_alloc = fc_slave_alloc, - .change_queue_depth = fc_change_queue_depth, - .change_queue_type = fc_change_queue_type, - .this_id = -1, - .cmd_per_lun = 3, - .can_queue = FCOE_MAX_OUTSTANDING_COMMANDS, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = SG_ALL, - .max_sectors = 0xffff, -}; - -/** - * fcoe_interface_setup() - Setup a FCoE interface - * @fcoe: The new FCoE interface - * @netdev: The net device that the fcoe interface is on - * - * Returns : 0 for success - * Locking: must be called with the RTNL mutex held - */ -static int fcoe_interface_setup(struct fcoe_interface *fcoe, - struct net_device *netdev) -{ - struct fcoe_ctlr *fip = &fcoe->ctlr; - struct netdev_hw_addr *ha; - struct net_device *real_dev; - u8 flogi_maddr[ETH_ALEN]; - const struct net_device_ops *ops; - - fcoe->netdev = netdev; - - /* Let LLD initialize for FCoE */ - ops = netdev->netdev_ops; - if (ops->ndo_fcoe_enable) { - if (ops->ndo_fcoe_enable(netdev)) - FCOE_NETDEV_DBG(netdev, "Failed to enable FCoE" - " specific feature for LLD.\n"); - } - - /* Do not support for bonding device */ - if (netdev->priv_flags & IFF_BONDING && netdev->flags & IFF_MASTER) { - FCOE_NETDEV_DBG(netdev, "Bonded interfaces not supported\n"); - return -EOPNOTSUPP; - } - - /* look for SAN MAC address, if multiple SAN MACs exist, only - * use the first one for SPMA */ - real_dev = (netdev->priv_flags & IFF_802_1Q_VLAN) ? - vlan_dev_real_dev(netdev) : netdev; - fcoe->realdev = real_dev; - rcu_read_lock(); - for_each_dev_addr(real_dev, ha) { - if ((ha->type == NETDEV_HW_ADDR_T_SAN) && - (is_valid_ether_addr(ha->addr))) { - memcpy(fip->ctl_src_addr, ha->addr, ETH_ALEN); - fip->spma = 1; - break; - } - } - rcu_read_unlock(); - - /* setup Source Mac Address */ - if (!fip->spma) - memcpy(fip->ctl_src_addr, netdev->dev_addr, netdev->addr_len); - - /* - * Add FCoE MAC address as second unicast MAC address - * or enter promiscuous mode if not capable of listening - * for multiple unicast MACs. - */ - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_uc_add(netdev, flogi_maddr); - if (fip->spma) - dev_uc_add(netdev, fip->ctl_src_addr); - if (fip->mode == FIP_MODE_VN2VN) { - dev_mc_add(netdev, FIP_ALL_VN2VN_MACS); - dev_mc_add(netdev, FIP_ALL_P2P_MACS); - } else - dev_mc_add(netdev, FIP_ALL_ENODE_MACS); - - /* - * setup the receive function from ethernet driver - * on the ethertype for the given device - */ - fcoe->fcoe_packet_type.func = fcoe_rcv; - fcoe->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); - fcoe->fcoe_packet_type.dev = netdev; - dev_add_pack(&fcoe->fcoe_packet_type); - - fcoe->fip_packet_type.func = fcoe_fip_recv; - fcoe->fip_packet_type.type = htons(ETH_P_FIP); - fcoe->fip_packet_type.dev = netdev; - dev_add_pack(&fcoe->fip_packet_type); - - return 0; -} - -/** - * fcoe_interface_create() - Create a FCoE interface on a net device - * @netdev: The net device to create the FCoE interface on - * @fip_mode: The mode to use for FIP - * - * Returns: pointer to a struct fcoe_interface or NULL on error - */ -static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev, - enum fip_state fip_mode) -{ - struct fcoe_interface *fcoe; - int err; - - if (!try_module_get(THIS_MODULE)) { - FCOE_NETDEV_DBG(netdev, - "Could not get a reference to the module\n"); - fcoe = ERR_PTR(-EBUSY); - goto out; - } - - fcoe = kzalloc(sizeof(*fcoe), GFP_KERNEL); - if (!fcoe) { - FCOE_NETDEV_DBG(netdev, "Could not allocate fcoe structure\n"); - fcoe = ERR_PTR(-ENOMEM); - goto out_putmod; - } - - dev_hold(netdev); - - /* - * Initialize FIP. - */ - fcoe_ctlr_init(&fcoe->ctlr, fip_mode); - fcoe->ctlr.send = fcoe_fip_send; - fcoe->ctlr.update_mac = fcoe_update_src_mac; - fcoe->ctlr.get_src_addr = fcoe_get_src_mac; - - err = fcoe_interface_setup(fcoe, netdev); - if (err) { - fcoe_ctlr_destroy(&fcoe->ctlr); - kfree(fcoe); - dev_put(netdev); - fcoe = ERR_PTR(err); - goto out_putmod; - } - - goto out; - -out_putmod: - module_put(THIS_MODULE); -out: - return fcoe; -} - -/** - * fcoe_interface_cleanup() - Clean up a FCoE interface - * @fcoe: The FCoE interface to be cleaned up - * - * Caller must be holding the RTNL mutex - */ -static void fcoe_interface_cleanup(struct fcoe_interface *fcoe) -{ - struct net_device *netdev = fcoe->netdev; - struct fcoe_ctlr *fip = &fcoe->ctlr; - u8 flogi_maddr[ETH_ALEN]; - const struct net_device_ops *ops; - - rtnl_lock(); - - /* - * Don't listen for Ethernet packets anymore. - * synchronize_net() ensures that the packet handlers are not running - * on another CPU. dev_remove_pack() would do that, this calls the - * unsyncronized version __dev_remove_pack() to avoid multiple delays. - */ - __dev_remove_pack(&fcoe->fcoe_packet_type); - __dev_remove_pack(&fcoe->fip_packet_type); - synchronize_net(); - - /* Delete secondary MAC addresses */ - memcpy(flogi_maddr, (u8[6]) FC_FCOE_FLOGI_MAC, ETH_ALEN); - dev_uc_del(netdev, flogi_maddr); - if (fip->spma) - dev_uc_del(netdev, fip->ctl_src_addr); - if (fip->mode == FIP_MODE_VN2VN) { - dev_mc_del(netdev, FIP_ALL_VN2VN_MACS); - dev_mc_del(netdev, FIP_ALL_P2P_MACS); - } else - dev_mc_del(netdev, FIP_ALL_ENODE_MACS); - - /* Tell the LLD we are done w/ FCoE */ - ops = netdev->netdev_ops; - if (ops->ndo_fcoe_disable) { - if (ops->ndo_fcoe_disable(netdev)) - FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE" - " specific feature for LLD.\n"); - } - - rtnl_unlock(); - - /* Release the self-reference taken during fcoe_interface_create() */ - /* tear-down the FCoE controller */ - fcoe_ctlr_destroy(fip); - kfree(fcoe); - dev_put(netdev); - module_put(THIS_MODULE); -} - -/** - * fcoe_fip_recv() - Handler for received FIP frames - * @skb: The receive skb - * @netdev: The associated net device - * @ptype: The packet_type structure which was used to register this handler - * @orig_dev: The original net_device the the skb was received on. - * (in case dev is a bond) - * - * Returns: 0 for success - */ -static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *netdev, - struct packet_type *ptype, - struct net_device *orig_dev) -{ - struct fcoe_interface *fcoe; - - fcoe = container_of(ptype, struct fcoe_interface, fip_packet_type); - fcoe_ctlr_recv(&fcoe->ctlr, skb); - return 0; -} - -/** - * fcoe_port_send() - Send an Ethernet-encapsulated FIP/FCoE frame - * @port: The FCoE port - * @skb: The FIP/FCoE packet to be sent - */ -static void fcoe_port_send(struct fcoe_port *port, struct sk_buff *skb) -{ - if (port->fcoe_pending_queue.qlen) - fcoe_check_wait_queue(port->lport, skb); - else if (fcoe_start_io(skb)) - fcoe_check_wait_queue(port->lport, skb); -} - -/** - * fcoe_fip_send() - Send an Ethernet-encapsulated FIP frame - * @fip: The FCoE controller - * @skb: The FIP packet to be sent - */ -static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - skb->dev = fcoe_from_ctlr(fip)->netdev; - fcoe_port_send(lport_priv(fip->lp), skb); -} - -/** - * fcoe_update_src_mac() - Update the Ethernet MAC filters - * @lport: The local port to update the source MAC on - * @addr: Unicast MAC address to add - * - * Remove any previously-set unicast MAC filter. - * Add secondary FCoE MAC address filter for our OUI. - */ -static void fcoe_update_src_mac(struct fc_lport *lport, u8 *addr) -{ - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - - rtnl_lock(); - if (!is_zero_ether_addr(port->data_src_addr)) - dev_uc_del(fcoe->netdev, port->data_src_addr); - if (!is_zero_ether_addr(addr)) - dev_uc_add(fcoe->netdev, addr); - memcpy(port->data_src_addr, addr, ETH_ALEN); - rtnl_unlock(); -} - -/** - * fcoe_get_src_mac() - return the Ethernet source address for an lport - * @lport: libfc lport - */ -static u8 *fcoe_get_src_mac(struct fc_lport *lport) -{ - struct fcoe_port *port = lport_priv(lport); - - return port->data_src_addr; -} - -/** - * fcoe_lport_config() - Set up a local port - * @lport: The local port to be setup - * - * Returns: 0 for success - */ -static int fcoe_lport_config(struct fc_lport *lport) -{ - lport->link_up = 0; - lport->qfull = 0; - lport->max_retry_count = 3; - lport->max_rport_retry_count = 3; - lport->e_d_tov = 2 * 1000; /* FC-FS default */ - lport->r_a_tov = 2 * 2 * 1000; - lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | - FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL); - lport->does_npiv = 1; - - fc_lport_init_stats(lport); - - /* lport fc_lport related configuration */ - fc_lport_config(lport); - - /* offload related configuration */ - lport->crc_offload = 0; - lport->seq_offload = 0; - lport->lro_enabled = 0; - lport->lro_xid = 0; - lport->lso_max = 0; - - return 0; -} - -/** - * fcoe_netdev_features_change - Updates the lport's offload flags based - * on the LLD netdev's FCoE feature flags - */ -static void fcoe_netdev_features_change(struct fc_lport *lport, - struct net_device *netdev) -{ - mutex_lock(&lport->lp_mutex); - - if (netdev->features & NETIF_F_SG) - lport->sg_supp = 1; - else - lport->sg_supp = 0; - - if (netdev->features & NETIF_F_FCOE_CRC) { - lport->crc_offload = 1; - FCOE_NETDEV_DBG(netdev, "Supports FCCRC offload\n"); - } else { - lport->crc_offload = 0; - } - - if (netdev->features & NETIF_F_FSO) { - lport->seq_offload = 1; - lport->lso_max = netdev->gso_max_size; - FCOE_NETDEV_DBG(netdev, "Supports LSO for max len 0x%x\n", - lport->lso_max); - } else { - lport->seq_offload = 0; - lport->lso_max = 0; - } - - if (netdev->fcoe_ddp_xid) { - lport->lro_enabled = 1; - lport->lro_xid = netdev->fcoe_ddp_xid; - FCOE_NETDEV_DBG(netdev, "Supports LRO for max xid 0x%x\n", - lport->lro_xid); - } else { - lport->lro_enabled = 0; - lport->lro_xid = 0; - } - - mutex_unlock(&lport->lp_mutex); -} - -/** - * fcoe_netdev_config() - Set up net devive for SW FCoE - * @lport: The local port that is associated with the net device - * @netdev: The associated net device - * - * Must be called after fcoe_lport_config() as it will use local port mutex - * - * Returns: 0 for success - */ -static int fcoe_netdev_config(struct fc_lport *lport, struct net_device *netdev) -{ - u32 mfs; - u64 wwnn, wwpn; - struct fcoe_interface *fcoe; - struct fcoe_port *port; - - /* Setup lport private data to point to fcoe softc */ - port = lport_priv(lport); - fcoe = port->priv; - - /* - * Determine max frame size based on underlying device and optional - * user-configured limit. If the MFS is too low, fcoe_link_ok() - * will return 0, so do this first. - */ - mfs = netdev->mtu; - if (netdev->features & NETIF_F_FCOE_MTU) { - mfs = FCOE_MTU; - FCOE_NETDEV_DBG(netdev, "Supports FCOE_MTU of %d bytes\n", mfs); - } - mfs -= (sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof)); - if (fc_set_mfs(lport, mfs)) - return -EINVAL; - - /* offload features support */ - fcoe_netdev_features_change(lport, netdev); - - skb_queue_head_init(&port->fcoe_pending_queue); - port->fcoe_pending_queue_active = 0; - setup_timer(&port->timer, fcoe_queue_timer, (unsigned long)lport); - - fcoe_link_speed_update(lport); - - if (!lport->vport) { - if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN)) - wwnn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, 1, 0); - fc_set_wwnn(lport, wwnn); - if (fcoe_get_wwn(netdev, &wwpn, NETDEV_FCOE_WWPN)) - wwpn = fcoe_wwn_from_mac(fcoe->ctlr.ctl_src_addr, - 2, 0); - fc_set_wwpn(lport, wwpn); - } - - return 0; -} - -/** - * fcoe_shost_config() - Set up the SCSI host associated with a local port - * @lport: The local port - * @dev: The device associated with the SCSI host - * - * Must be called after fcoe_lport_config() and fcoe_netdev_config() - * - * Returns: 0 for success - */ -static int fcoe_shost_config(struct fc_lport *lport, struct device *dev) -{ - int rc = 0; - - /* lport scsi host config */ - lport->host->max_lun = FCOE_MAX_LUN; - lport->host->max_id = FCOE_MAX_FCP_TARGET; - lport->host->max_channel = 0; - lport->host->max_cmd_len = FCOE_MAX_CMD_LEN; - - if (lport->vport) - lport->host->transportt = fcoe_vport_scsi_transport; - else - lport->host->transportt = fcoe_nport_scsi_transport; - - /* add the new host to the SCSI-ml */ - rc = scsi_add_host(lport->host, dev); - if (rc) { - FCOE_NETDEV_DBG(fcoe_netdev(lport), "fcoe_shost_config: " - "error on scsi_add_host\n"); - return rc; - } - - if (!lport->vport) - fc_host_max_npiv_vports(lport->host) = USHRT_MAX; - - snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE, - "%s v%s over %s", FCOE_NAME, FCOE_VERSION, - fcoe_netdev(lport)->name); - - return 0; -} - - -/** - * fcoe_fdmi_info() - Get FDMI related info from net devive for SW FCoE - * @lport: The local port that is associated with the net device - * @netdev: The associated net device - * - * Must be called after fcoe_shost_config() as it will use local port mutex - * - */ -static void fcoe_fdmi_info(struct fc_lport *lport, struct net_device *netdev) -{ - struct fcoe_interface *fcoe; - struct fcoe_port *port; - struct net_device *realdev; - int rc; - struct netdev_fcoe_hbainfo fdmi; - - port = lport_priv(lport); - fcoe = port->priv; - realdev = fcoe->realdev; - - if (!realdev) - return; - - /* No FDMI state m/c for NPIV ports */ - if (lport->vport) - return; - - if (realdev->netdev_ops->ndo_fcoe_get_hbainfo) { - memset(&fdmi, 0, sizeof(fdmi)); - rc = realdev->netdev_ops->ndo_fcoe_get_hbainfo(realdev, - &fdmi); - if (rc) { - printk(KERN_INFO "fcoe: Failed to retrieve FDMI " - "information from netdev.\n"); - return; - } - - snprintf(fc_host_serial_number(lport->host), - FC_SERIAL_NUMBER_SIZE, - "%s", - fdmi.serial_number); - snprintf(fc_host_manufacturer(lport->host), - FC_SERIAL_NUMBER_SIZE, - "%s", - fdmi.manufacturer); - snprintf(fc_host_model(lport->host), - FC_SYMBOLIC_NAME_SIZE, - "%s", - fdmi.model); - snprintf(fc_host_model_description(lport->host), - FC_SYMBOLIC_NAME_SIZE, - "%s", - fdmi.model_description); - snprintf(fc_host_hardware_version(lport->host), - FC_VERSION_STRING_SIZE, - "%s", - fdmi.hardware_version); - snprintf(fc_host_driver_version(lport->host), - FC_VERSION_STRING_SIZE, - "%s", - fdmi.driver_version); - snprintf(fc_host_optionrom_version(lport->host), - FC_VERSION_STRING_SIZE, - "%s", - fdmi.optionrom_version); - snprintf(fc_host_firmware_version(lport->host), - FC_VERSION_STRING_SIZE, - "%s", - fdmi.firmware_version); - - /* Enable FDMI lport states */ - lport->fdmi_enabled = 1; - } else { - lport->fdmi_enabled = 0; - printk(KERN_INFO "fcoe: No FDMI support.\n"); - } -} - -/** - * fcoe_oem_match() - The match routine for the offloaded exchange manager - * @fp: The I/O frame - * - * This routine will be associated with an exchange manager (EM). When - * the libfc exchange handling code is looking for an EM to use it will - * call this routine and pass it the frame that it wishes to send. This - * routine will return True if the associated EM is to be used and False - * if the echange code should continue looking for an EM. - * - * The offload EM that this routine is associated with will handle any - * packets that are for SCSI read requests. - * - * This has been enhanced to work when FCoE stack is operating in target - * mode. - * - * Returns: True for read types I/O, otherwise returns false. - */ -static bool fcoe_oem_match(struct fc_frame *fp) -{ - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fcp_cmnd *fcp; - - if (fc_fcp_is_read(fr_fsp(fp)) && - (fr_fsp(fp)->data_len > fcoe_ddp_min)) - return true; - else if ((fr_fsp(fp) == NULL) && - (fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) && - (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN)) { - fcp = fc_frame_payload_get(fp, sizeof(*fcp)); - if ((fcp->fc_flags & FCP_CFL_WRDATA) && - (ntohl(fcp->fc_dl) > fcoe_ddp_min)) - return true; - } - return false; -} - -/** - * fcoe_em_config() - Allocate and configure an exchange manager - * @lport: The local port that the new EM will be associated with - * - * Returns: 0 on success - */ -static inline int fcoe_em_config(struct fc_lport *lport) -{ - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - struct fcoe_interface *oldfcoe = NULL; - struct net_device *old_real_dev, *cur_real_dev; - u16 min_xid = FCOE_MIN_XID; - u16 max_xid = FCOE_MAX_XID; - - /* - * Check if need to allocate an em instance for - * offload exchange ids to be shared across all VN_PORTs/lport. - */ - if (!lport->lro_enabled || !lport->lro_xid || - (lport->lro_xid >= max_xid)) { - lport->lro_xid = 0; - goto skip_oem; - } - - /* - * Reuse existing offload em instance in case - * it is already allocated on real eth device - */ - if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) - cur_real_dev = vlan_dev_real_dev(fcoe->netdev); - else - cur_real_dev = fcoe->netdev; - - list_for_each_entry(oldfcoe, &fcoe_hostlist, list) { - if (oldfcoe->netdev->priv_flags & IFF_802_1Q_VLAN) - old_real_dev = vlan_dev_real_dev(oldfcoe->netdev); - else - old_real_dev = oldfcoe->netdev; - - if (cur_real_dev == old_real_dev) { - fcoe->oem = oldfcoe->oem; - break; - } - } - - if (fcoe->oem) { - if (!fc_exch_mgr_add(lport, fcoe->oem, fcoe_oem_match)) { - printk(KERN_ERR "fcoe_em_config: failed to add " - "offload em:%p on interface:%s\n", - fcoe->oem, fcoe->netdev->name); - return -ENOMEM; - } - } else { - fcoe->oem = fc_exch_mgr_alloc(lport, FC_CLASS_3, - FCOE_MIN_XID, lport->lro_xid, - fcoe_oem_match); - if (!fcoe->oem) { - printk(KERN_ERR "fcoe_em_config: failed to allocate " - "em for offload exches on interface:%s\n", - fcoe->netdev->name); - return -ENOMEM; - } - } - - /* - * Exclude offload EM xid range from next EM xid range. - */ - min_xid += lport->lro_xid + 1; - -skip_oem: - if (!fc_exch_mgr_alloc(lport, FC_CLASS_3, min_xid, max_xid, NULL)) { - printk(KERN_ERR "fcoe_em_config: failed to " - "allocate em on interface %s\n", fcoe->netdev->name); - return -ENOMEM; - } - - return 0; -} - -/** - * fcoe_if_destroy() - Tear down a SW FCoE instance - * @lport: The local port to be destroyed - * - */ -static void fcoe_if_destroy(struct fc_lport *lport) -{ - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - struct net_device *netdev = fcoe->netdev; - - FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); - - /* Logout of the fabric */ - fc_fabric_logoff(lport); - - /* Cleanup the fc_lport */ - fc_lport_destroy(lport); - - /* Stop the transmit retry timer */ - del_timer_sync(&port->timer); - - /* Free existing transmit skbs */ - fcoe_clean_pending_queue(lport); - - rtnl_lock(); - if (!is_zero_ether_addr(port->data_src_addr)) - dev_uc_del(netdev, port->data_src_addr); - rtnl_unlock(); - - /* Free queued packets for the per-CPU receive threads */ - fcoe_percpu_clean(lport); - - /* Detach from the scsi-ml */ - fc_remove_host(lport->host); - scsi_remove_host(lport->host); - - /* Destroy lport scsi_priv */ - fc_fcp_destroy(lport); - - /* There are no more rports or I/O, free the EM */ - fc_exch_mgr_free(lport); - - /* Free memory used by statistical counters */ - fc_lport_free_stats(lport); - - /* Release the Scsi_Host */ - scsi_host_put(lport->host); -} - -/** - * fcoe_ddp_setup() - Call a LLD's ddp_setup through the net device - * @lport: The local port to setup DDP for - * @xid: The exchange ID for this DDP transfer - * @sgl: The scatterlist describing this transfer - * @sgc: The number of sg items - * - * Returns: 0 if the DDP context was not configured - */ -static int fcoe_ddp_setup(struct fc_lport *lport, u16 xid, - struct scatterlist *sgl, unsigned int sgc) -{ - struct net_device *netdev = fcoe_netdev(lport); - - if (netdev->netdev_ops->ndo_fcoe_ddp_setup) - return netdev->netdev_ops->ndo_fcoe_ddp_setup(netdev, - xid, sgl, - sgc); - - return 0; -} - -/** - * fcoe_ddp_target() - Call a LLD's ddp_target through the net device - * @lport: The local port to setup DDP for - * @xid: The exchange ID for this DDP transfer - * @sgl: The scatterlist describing this transfer - * @sgc: The number of sg items - * - * Returns: 0 if the DDP context was not configured - */ -static int fcoe_ddp_target(struct fc_lport *lport, u16 xid, - struct scatterlist *sgl, unsigned int sgc) -{ - struct net_device *netdev = fcoe_netdev(lport); - - if (netdev->netdev_ops->ndo_fcoe_ddp_target) - return netdev->netdev_ops->ndo_fcoe_ddp_target(netdev, xid, - sgl, sgc); - - return 0; -} - - -/** - * fcoe_ddp_done() - Call a LLD's ddp_done through the net device - * @lport: The local port to complete DDP on - * @xid: The exchange ID for this DDP transfer - * - * Returns: the length of data that have been completed by DDP - */ -static int fcoe_ddp_done(struct fc_lport *lport, u16 xid) -{ - struct net_device *netdev = fcoe_netdev(lport); - - if (netdev->netdev_ops->ndo_fcoe_ddp_done) - return netdev->netdev_ops->ndo_fcoe_ddp_done(netdev, xid); - return 0; -} - -/** - * fcoe_if_create() - Create a FCoE instance on an interface - * @fcoe: The FCoE interface to create a local port on - * @parent: The device pointer to be the parent in sysfs for the SCSI host - * @npiv: Indicates if the port is a vport or not - * - * Creates a fc_lport instance and a Scsi_Host instance and configure them. - * - * Returns: The allocated fc_lport or an error pointer - */ -static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, - struct device *parent, int npiv) -{ - struct net_device *netdev = fcoe->netdev; - struct fc_lport *lport, *n_port; - struct fcoe_port *port; - struct Scsi_Host *shost; - int rc; - /* - * parent is only a vport if npiv is 1, - * but we'll only use vport in that case so go ahead and set it - */ - struct fc_vport *vport = dev_to_vport(parent); - - FCOE_NETDEV_DBG(netdev, "Create Interface\n"); - - if (!npiv) - lport = libfc_host_alloc(&fcoe_shost_template, sizeof(*port)); - else - lport = libfc_vport_create(vport, sizeof(*port)); - - if (!lport) { - FCOE_NETDEV_DBG(netdev, "Could not allocate host structure\n"); - rc = -ENOMEM; - goto out; - } - port = lport_priv(lport); - port->lport = lport; - port->priv = fcoe; - port->max_queue_depth = FCOE_MAX_QUEUE_DEPTH; - port->min_queue_depth = FCOE_MIN_QUEUE_DEPTH; - INIT_WORK(&port->destroy_work, fcoe_destroy_work); - - /* configure a fc_lport including the exchange manager */ - rc = fcoe_lport_config(lport); - if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure lport for the " - "interface\n"); - goto out_host_put; - } - - if (npiv) { - FCOE_NETDEV_DBG(netdev, "Setting vport names, " - "%16.16llx %16.16llx\n", - vport->node_name, vport->port_name); - fc_set_wwnn(lport, vport->node_name); - fc_set_wwpn(lport, vport->port_name); - } - - /* configure lport network properties */ - rc = fcoe_netdev_config(lport, netdev); - if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure netdev for the " - "interface\n"); - goto out_lp_destroy; - } - - /* configure lport scsi host properties */ - rc = fcoe_shost_config(lport, parent); - if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure shost for the " - "interface\n"); - goto out_lp_destroy; - } - - /* Initialize the library */ - rc = fcoe_libfc_config(lport, &fcoe->ctlr, &fcoe_libfc_fcn_templ, 1); - if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure libfc for the " - "interface\n"); - goto out_lp_destroy; - } - - /* Initialized FDMI information */ - fcoe_fdmi_info(lport, netdev); - - /* - * fcoe_em_alloc() and fcoe_hostlist_add() both - * need to be atomic with respect to other changes to the - * hostlist since fcoe_em_alloc() looks for an existing EM - * instance on host list updated by fcoe_hostlist_add(). - * - * This is currently handled through the fcoe_config_mutex - * begin held. - */ - if (!npiv) - /* lport exch manager allocation */ - rc = fcoe_em_config(lport); - else { - shost = vport_to_shost(vport); - n_port = shost_priv(shost); - rc = fc_exch_mgr_list_clone(n_port, lport); - } - - if (rc) { - FCOE_NETDEV_DBG(netdev, "Could not configure the EM\n"); - goto out_lp_destroy; - } - - return lport; - -out_lp_destroy: - fc_exch_mgr_free(lport); -out_host_put: - scsi_host_put(lport->host); -out: - return ERR_PTR(rc); -} - -/** - * fcoe_if_init() - Initialization routine for fcoe.ko - * - * Attaches the SW FCoE transport to the FC transport - * - * Returns: 0 on success - */ -static int __init fcoe_if_init(void) -{ - /* attach to scsi transport */ - fcoe_nport_scsi_transport = - fc_attach_transport(&fcoe_nport_fc_functions); - fcoe_vport_scsi_transport = - fc_attach_transport(&fcoe_vport_fc_functions); - - if (!fcoe_nport_scsi_transport) { - printk(KERN_ERR "fcoe: Failed to attach to the FC transport\n"); - return -ENODEV; - } - - return 0; -} - -/** - * fcoe_if_exit() - Tear down fcoe.ko - * - * Detaches the SW FCoE transport from the FC transport - * - * Returns: 0 on success - */ -static int __exit fcoe_if_exit(void) -{ - fc_release_transport(fcoe_nport_scsi_transport); - fc_release_transport(fcoe_vport_scsi_transport); - fcoe_nport_scsi_transport = NULL; - fcoe_vport_scsi_transport = NULL; - return 0; -} - -/** - * fcoe_percpu_thread_create() - Create a receive thread for an online CPU - * @cpu: The CPU index of the CPU to create a receive thread for - */ -static void fcoe_percpu_thread_create(unsigned int cpu) -{ - struct fcoe_percpu_s *p; - struct task_struct *thread; - - p = &per_cpu(fcoe_percpu, cpu); - - thread = kthread_create_on_node(fcoe_percpu_receive_thread, - (void *)p, cpu_to_node(cpu), - "fcoethread/%d", cpu); - - if (likely(!IS_ERR(thread))) { - kthread_bind(thread, cpu); - wake_up_process(thread); - - spin_lock_bh(&p->fcoe_rx_list.lock); - p->thread = thread; - spin_unlock_bh(&p->fcoe_rx_list.lock); - } -} - -/** - * fcoe_percpu_thread_destroy() - Remove the receive thread of a CPU - * @cpu: The CPU index of the CPU whose receive thread is to be destroyed - * - * Destroys a per-CPU Rx thread. Any pending skbs are moved to the - * current CPU's Rx thread. If the thread being destroyed is bound to - * the CPU processing this context the skbs will be freed. - */ -static void fcoe_percpu_thread_destroy(unsigned int cpu) -{ - struct fcoe_percpu_s *p; - struct task_struct *thread; - struct page *crc_eof; - struct sk_buff *skb; -#ifdef CONFIG_SMP - struct fcoe_percpu_s *p0; - unsigned targ_cpu = get_cpu(); -#endif /* CONFIG_SMP */ - - FCOE_DBG("Destroying receive thread for CPU %d\n", cpu); - - /* Prevent any new skbs from being queued for this CPU. */ - p = &per_cpu(fcoe_percpu, cpu); - spin_lock_bh(&p->fcoe_rx_list.lock); - thread = p->thread; - p->thread = NULL; - crc_eof = p->crc_eof_page; - p->crc_eof_page = NULL; - p->crc_eof_offset = 0; - spin_unlock_bh(&p->fcoe_rx_list.lock); - -#ifdef CONFIG_SMP - /* - * Don't bother moving the skb's if this context is running - * on the same CPU that is having its thread destroyed. This - * can easily happen when the module is removed. - */ - if (cpu != targ_cpu) { - p0 = &per_cpu(fcoe_percpu, targ_cpu); - spin_lock_bh(&p0->fcoe_rx_list.lock); - if (p0->thread) { - FCOE_DBG("Moving frames from CPU %d to CPU %d\n", - cpu, targ_cpu); - - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - __skb_queue_tail(&p0->fcoe_rx_list, skb); - spin_unlock_bh(&p0->fcoe_rx_list.lock); - } else { - /* - * The targeted CPU is not initialized and cannot accept - * new skbs. Unlock the targeted CPU and drop the skbs - * on the CPU that is going offline. - */ - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - kfree_skb(skb); - spin_unlock_bh(&p0->fcoe_rx_list.lock); - } - } else { - /* - * This scenario occurs when the module is being removed - * and all threads are being destroyed. skbs will continue - * to be shifted from the CPU thread that is being removed - * to the CPU thread associated with the CPU that is processing - * the module removal. Once there is only one CPU Rx thread it - * will reach this case and we will drop all skbs and later - * stop the thread. - */ - spin_lock_bh(&p->fcoe_rx_list.lock); - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - kfree_skb(skb); - spin_unlock_bh(&p->fcoe_rx_list.lock); - } - put_cpu(); -#else - /* - * This a non-SMP scenario where the singular Rx thread is - * being removed. Free all skbs and stop the thread. - */ - spin_lock_bh(&p->fcoe_rx_list.lock); - while ((skb = __skb_dequeue(&p->fcoe_rx_list)) != NULL) - kfree_skb(skb); - spin_unlock_bh(&p->fcoe_rx_list.lock); -#endif - - if (thread) - kthread_stop(thread); - - if (crc_eof) - put_page(crc_eof); -} - -/** - * fcoe_cpu_callback() - Handler for CPU hotplug events - * @nfb: The callback data block - * @action: The event triggering the callback - * @hcpu: The index of the CPU that the event is for - * - * This creates or destroys per-CPU data for fcoe - * - * Returns NOTIFY_OK always. - */ -static int fcoe_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned cpu = (unsigned long)hcpu; - - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - FCOE_DBG("CPU %x online: Create Rx thread\n", cpu); - fcoe_percpu_thread_create(cpu); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - FCOE_DBG("CPU %x offline: Remove Rx thread\n", cpu); - fcoe_percpu_thread_destroy(cpu); - break; - default: - break; - } - return NOTIFY_OK; -} - -/** - * fcoe_select_cpu() - Selects CPU to handle post-processing of incoming - * command. - * - * This routine selects next CPU based on cpumask to distribute - * incoming requests in round robin. - * - * Returns: int CPU number - */ -static inline unsigned int fcoe_select_cpu(void) -{ - static unsigned int selected_cpu; - - selected_cpu = cpumask_next(selected_cpu, cpu_online_mask); - if (selected_cpu >= nr_cpu_ids) - selected_cpu = cpumask_first(cpu_online_mask); - - return selected_cpu; -} - -/** - * fcoe_rcv() - Receive packets from a net device - * @skb: The received packet - * @netdev: The net device that the packet was received on - * @ptype: The packet type context - * @olddev: The last device net device - * - * This routine is called by NET_RX_SOFTIRQ. It receives a packet, builds a - * FC frame and passes the frame to libfc. - * - * Returns: 0 for success - */ -static int fcoe_rcv(struct sk_buff *skb, struct net_device *netdev, - struct packet_type *ptype, struct net_device *olddev) -{ - struct fc_lport *lport; - struct fcoe_rcv_info *fr; - struct fcoe_interface *fcoe; - struct fc_frame_header *fh; - struct fcoe_percpu_s *fps; - struct ethhdr *eh; - unsigned int cpu; - - fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); - lport = fcoe->ctlr.lp; - if (unlikely(!lport)) { - FCOE_NETDEV_DBG(netdev, "Cannot find hba structure"); - goto err2; - } - if (!lport->link_up) - goto err2; - - FCOE_NETDEV_DBG(netdev, "skb_info: len:%d data_len:%d head:%p " - "data:%p tail:%p end:%p sum:%d dev:%s", - skb->len, skb->data_len, skb->head, skb->data, - skb_tail_pointer(skb), skb_end_pointer(skb), - skb->csum, skb->dev ? skb->dev->name : ""); - - eh = eth_hdr(skb); - - if (is_fip_mode(&fcoe->ctlr) && - compare_ether_addr(eh->h_source, fcoe->ctlr.dest_addr)) { - FCOE_NETDEV_DBG(netdev, "wrong source mac address:%pM\n", - eh->h_source); - goto err; - } - - /* - * Check for minimum frame length, and make sure required FCoE - * and FC headers are pulled into the linear data area. - */ - if (unlikely((skb->len < FCOE_MIN_FRAME) || - !pskb_may_pull(skb, FCOE_HEADER_LEN))) - goto err; - - skb_set_transport_header(skb, sizeof(struct fcoe_hdr)); - fh = (struct fc_frame_header *) skb_transport_header(skb); - - if (ntoh24(&eh->h_dest[3]) != ntoh24(fh->fh_d_id)) { - FCOE_NETDEV_DBG(netdev, "FC frame d_id mismatch with MAC:%pM\n", - eh->h_dest); - goto err; - } - - fr = fcoe_dev_from_skb(skb); - fr->fr_dev = lport; - - /* - * In case the incoming frame's exchange is originated from - * the initiator, then received frame's exchange id is ANDed - * with fc_cpu_mask bits to get the same cpu on which exchange - * was originated, otherwise select cpu using rx exchange id - * or fcoe_select_cpu(). - */ - if (ntoh24(fh->fh_f_ctl) & FC_FC_EX_CTX) - cpu = ntohs(fh->fh_ox_id) & fc_cpu_mask; - else { - if (ntohs(fh->fh_rx_id) == FC_XID_UNKNOWN) - cpu = fcoe_select_cpu(); - else - cpu = ntohs(fh->fh_rx_id) & fc_cpu_mask; - } - - if (cpu >= nr_cpu_ids) - goto err; - - fps = &per_cpu(fcoe_percpu, cpu); - spin_lock(&fps->fcoe_rx_list.lock); - if (unlikely(!fps->thread)) { - /* - * The targeted CPU is not ready, let's target - * the first CPU now. For non-SMP systems this - * will check the same CPU twice. - */ - FCOE_NETDEV_DBG(netdev, "CPU is online, but no receive thread " - "ready for incoming skb- using first online " - "CPU.\n"); - - spin_unlock(&fps->fcoe_rx_list.lock); - cpu = cpumask_first(cpu_online_mask); - fps = &per_cpu(fcoe_percpu, cpu); - spin_lock(&fps->fcoe_rx_list.lock); - if (!fps->thread) { - spin_unlock(&fps->fcoe_rx_list.lock); - goto err; - } - } - - /* - * We now have a valid CPU that we're targeting for - * this skb. We also have this receive thread locked, - * so we're free to queue skbs into it's queue. - */ - - /* - * Note: We used to have a set of conditions under which we would - * call fcoe_recv_frame directly, rather than queuing to the rx list - * as it could save a few cycles, but doing so is prohibited, as - * fcoe_recv_frame has several paths that may sleep, which is forbidden - * in softirq context. - */ - __skb_queue_tail(&fps->fcoe_rx_list, skb); - if (fps->thread->state == TASK_INTERRUPTIBLE) - wake_up_process(fps->thread); - spin_unlock(&fps->fcoe_rx_list.lock); - - return 0; -err: - per_cpu_ptr(lport->dev_stats, get_cpu())->ErrorFrames++; - put_cpu(); -err2: - kfree_skb(skb); - return -1; -} - -/** - * fcoe_alloc_paged_crc_eof() - Allocate a page to be used for the trailer CRC - * @skb: The packet to be transmitted - * @tlen: The total length of the trailer - * - * Returns: 0 for success - */ -static int fcoe_alloc_paged_crc_eof(struct sk_buff *skb, int tlen) -{ - struct fcoe_percpu_s *fps; - int rc; - - fps = &get_cpu_var(fcoe_percpu); - rc = fcoe_get_paged_crc_eof(skb, tlen, fps); - put_cpu_var(fcoe_percpu); - - return rc; -} - -/** - * fcoe_xmit() - Transmit a FCoE frame - * @lport: The local port that the frame is to be transmitted for - * @fp: The frame to be transmitted - * - * Return: 0 for success - */ -static int fcoe_xmit(struct fc_lport *lport, struct fc_frame *fp) -{ - int wlen; - u32 crc; - struct ethhdr *eh; - struct fcoe_crc_eof *cp; - struct sk_buff *skb; - struct fcoe_dev_stats *stats; - struct fc_frame_header *fh; - unsigned int hlen; /* header length implies the version */ - unsigned int tlen; /* trailer length */ - unsigned int elen; /* eth header, may include vlan */ - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - u8 sof, eof; - struct fcoe_hdr *hp; - - WARN_ON((fr_len(fp) % sizeof(u32)) != 0); - - fh = fc_frame_header_get(fp); - skb = fp_skb(fp); - wlen = skb->len / FCOE_WORD_TO_BYTE; - - if (!lport->link_up) { - kfree_skb(skb); - return 0; - } - - if (unlikely(fh->fh_type == FC_TYPE_ELS) && - fcoe_ctlr_els_send(&fcoe->ctlr, lport, skb)) - return 0; - - sof = fr_sof(fp); - eof = fr_eof(fp); - - elen = sizeof(struct ethhdr); - hlen = sizeof(struct fcoe_hdr); - tlen = sizeof(struct fcoe_crc_eof); - wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE; - - /* crc offload */ - if (likely(lport->crc_offload)) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->csum_start = skb_headroom(skb); - skb->csum_offset = skb->len; - crc = 0; - } else { - skb->ip_summed = CHECKSUM_NONE; - crc = fcoe_fc_crc(fp); - } - - /* copy port crc and eof to the skb buff */ - if (skb_is_nonlinear(skb)) { - skb_frag_t *frag; - if (fcoe_alloc_paged_crc_eof(skb, tlen)) { - kfree_skb(skb); - return -ENOMEM; - } - frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1]; - cp = kmap_atomic(skb_frag_page(frag)) - + frag->page_offset; - } else { - cp = (struct fcoe_crc_eof *)skb_put(skb, tlen); - } - - memset(cp, 0, sizeof(*cp)); - cp->fcoe_eof = eof; - cp->fcoe_crc32 = cpu_to_le32(~crc); - - if (skb_is_nonlinear(skb)) { - kunmap_atomic(cp); - cp = NULL; - } - - /* adjust skb network/transport offsets to match mac/fcoe/port */ - skb_push(skb, elen + hlen); - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - skb->mac_len = elen; - skb->protocol = htons(ETH_P_FCOE); - skb->priority = port->priority; - - if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN && - fcoe->realdev->features & NETIF_F_HW_VLAN_TX) { - skb->vlan_tci = VLAN_TAG_PRESENT | - vlan_dev_vlan_id(fcoe->netdev); - skb->dev = fcoe->realdev; - } else - skb->dev = fcoe->netdev; - - /* fill up mac and fcoe headers */ - eh = eth_hdr(skb); - eh->h_proto = htons(ETH_P_FCOE); - memcpy(eh->h_dest, fcoe->ctlr.dest_addr, ETH_ALEN); - if (fcoe->ctlr.map_dest) - memcpy(eh->h_dest + 3, fh->fh_d_id, 3); - - if (unlikely(fcoe->ctlr.flogi_oxid != FC_XID_UNKNOWN)) - memcpy(eh->h_source, fcoe->ctlr.ctl_src_addr, ETH_ALEN); - else - memcpy(eh->h_source, port->data_src_addr, ETH_ALEN); - - hp = (struct fcoe_hdr *)(eh + 1); - memset(hp, 0, sizeof(*hp)); - if (FC_FCOE_VER) - FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER); - hp->fcoe_sof = sof; - - /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ - if (lport->seq_offload && fr_max_payload(fp)) { - skb_shinfo(skb)->gso_type = SKB_GSO_FCOE; - skb_shinfo(skb)->gso_size = fr_max_payload(fp); - } else { - skb_shinfo(skb)->gso_type = 0; - skb_shinfo(skb)->gso_size = 0; - } - /* update tx stats: regardless if LLD fails */ - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - stats->TxFrames++; - stats->TxWords += wlen; - put_cpu(); - - /* send down to lld */ - fr_dev(fp) = lport; - fcoe_port_send(port, skb); - return 0; -} - -/** - * fcoe_percpu_flush_done() - Indicate per-CPU queue flush completion - * @skb: The completed skb (argument required by destructor) - */ -static void fcoe_percpu_flush_done(struct sk_buff *skb) -{ - complete(&fcoe_flush_completion); -} - -/** - * fcoe_filter_frames() - filter out bad fcoe frames, i.e. bad CRC - * @lport: The local port the frame was received on - * @fp: The received frame - * - * Return: 0 on passing filtering checks - */ -static inline int fcoe_filter_frames(struct fc_lport *lport, - struct fc_frame *fp) -{ - struct fcoe_interface *fcoe; - struct fc_frame_header *fh; - struct sk_buff *skb = (struct sk_buff *)fp; - struct fcoe_dev_stats *stats; - - /* - * We only check CRC if no offload is available and if it is - * it's solicited data, in which case, the FCP layer would - * check it during the copy. - */ - if (lport->crc_offload && skb->ip_summed == CHECKSUM_UNNECESSARY) - fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; - else - fr_flags(fp) |= FCPHF_CRC_UNCHECKED; - - fh = (struct fc_frame_header *) skb_transport_header(skb); - fh = fc_frame_header_get(fp); - if (fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA && fh->fh_type == FC_TYPE_FCP) - return 0; - - fcoe = ((struct fcoe_port *)lport_priv(lport))->priv; - if (is_fip_mode(&fcoe->ctlr) && fc_frame_payload_op(fp) == ELS_LOGO && - ntoh24(fh->fh_s_id) == FC_FID_FLOGI) { - FCOE_DBG("fcoe: dropping FCoE lport LOGO in fip mode\n"); - return -EINVAL; - } - - if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED) || - le32_to_cpu(fr_crc(fp)) == ~crc32(~0, skb->data, skb->len)) { - fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; - return 0; - } - - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - stats->InvalidCRCCount++; - if (stats->InvalidCRCCount < 5) - printk(KERN_WARNING "fcoe: dropping frame with CRC error\n"); - put_cpu(); - return -EINVAL; -} - -/** - * fcoe_recv_frame() - process a single received frame - * @skb: frame to process - */ -static void fcoe_recv_frame(struct sk_buff *skb) -{ - u32 fr_len; - struct fc_lport *lport; - struct fcoe_rcv_info *fr; - struct fcoe_dev_stats *stats; - struct fcoe_crc_eof crc_eof; - struct fc_frame *fp; - struct fcoe_port *port; - struct fcoe_hdr *hp; - - fr = fcoe_dev_from_skb(skb); - lport = fr->fr_dev; - if (unlikely(!lport)) { - if (skb->destructor != fcoe_percpu_flush_done) - FCOE_NETDEV_DBG(skb->dev, "NULL lport in skb"); - kfree_skb(skb); - return; - } - - FCOE_NETDEV_DBG(skb->dev, "skb_info: len:%d data_len:%d " - "head:%p data:%p tail:%p end:%p sum:%d dev:%s", - skb->len, skb->data_len, - skb->head, skb->data, skb_tail_pointer(skb), - skb_end_pointer(skb), skb->csum, - skb->dev ? skb->dev->name : ""); - - port = lport_priv(lport); - skb_linearize(skb); /* check for skb_is_nonlinear is within skb_linearize */ - - /* - * Frame length checks and setting up the header pointers - * was done in fcoe_rcv already. - */ - hp = (struct fcoe_hdr *) skb_network_header(skb); - - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) { - if (stats->ErrorFrames < 5) - printk(KERN_WARNING "fcoe: FCoE version " - "mismatch: The frame has " - "version %x, but the " - "initiator supports version " - "%x\n", FC_FCOE_DECAPS_VER(hp), - FC_FCOE_VER); - goto drop; - } - - skb_pull(skb, sizeof(struct fcoe_hdr)); - fr_len = skb->len - sizeof(struct fcoe_crc_eof); - - stats->RxFrames++; - stats->RxWords += fr_len / FCOE_WORD_TO_BYTE; - - fp = (struct fc_frame *)skb; - fc_frame_init(fp); - fr_dev(fp) = lport; - fr_sof(fp) = hp->fcoe_sof; - - /* Copy out the CRC and EOF trailer for access */ - if (skb_copy_bits(skb, fr_len, &crc_eof, sizeof(crc_eof))) - goto drop; - fr_eof(fp) = crc_eof.fcoe_eof; - fr_crc(fp) = crc_eof.fcoe_crc32; - if (pskb_trim(skb, fr_len)) - goto drop; - - if (!fcoe_filter_frames(lport, fp)) { - put_cpu(); - fc_exch_recv(lport, fp); - return; - } -drop: - stats->ErrorFrames++; - put_cpu(); - kfree_skb(skb); -} - -/** - * fcoe_percpu_receive_thread() - The per-CPU packet receive thread - * @arg: The per-CPU context - * - * Return: 0 for success - */ -static int fcoe_percpu_receive_thread(void *arg) -{ - struct fcoe_percpu_s *p = arg; - struct sk_buff *skb; - struct sk_buff_head tmp; - - skb_queue_head_init(&tmp); - - set_user_nice(current, -20); - - while (!kthread_should_stop()) { - - spin_lock_bh(&p->fcoe_rx_list.lock); - skb_queue_splice_init(&p->fcoe_rx_list, &tmp); - spin_unlock_bh(&p->fcoe_rx_list.lock); - - while ((skb = __skb_dequeue(&tmp)) != NULL) - fcoe_recv_frame(skb); - - spin_lock_bh(&p->fcoe_rx_list.lock); - if (!skb_queue_len(&p->fcoe_rx_list)) { - set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_bh(&p->fcoe_rx_list.lock); - schedule(); - set_current_state(TASK_RUNNING); - } else - spin_unlock_bh(&p->fcoe_rx_list.lock); - } - return 0; -} - -/** - * fcoe_dev_setup() - Setup the link change notification interface - */ -static void fcoe_dev_setup(void) -{ - register_dcbevent_notifier(&dcb_notifier); - register_netdevice_notifier(&fcoe_notifier); -} - -/** - * fcoe_dev_cleanup() - Cleanup the link change notification interface - */ -static void fcoe_dev_cleanup(void) -{ - unregister_dcbevent_notifier(&dcb_notifier); - unregister_netdevice_notifier(&fcoe_notifier); -} - -static struct fcoe_interface * -fcoe_hostlist_lookup_realdev_port(struct net_device *netdev) -{ - struct fcoe_interface *fcoe; - struct net_device *real_dev; - - list_for_each_entry(fcoe, &fcoe_hostlist, list) { - if (fcoe->netdev->priv_flags & IFF_802_1Q_VLAN) - real_dev = vlan_dev_real_dev(fcoe->netdev); - else - real_dev = fcoe->netdev; - - if (netdev == real_dev) - return fcoe; - } - return NULL; -} - -static int fcoe_dcb_app_notification(struct notifier_block *notifier, - ulong event, void *ptr) -{ - struct dcb_app_type *entry = ptr; - struct fcoe_interface *fcoe; - struct net_device *netdev; - struct fcoe_port *port; - int prio; - - if (entry->app.selector != DCB_APP_IDTYPE_ETHTYPE) - return NOTIFY_OK; - - netdev = dev_get_by_index(&init_net, entry->ifindex); - if (!netdev) - return NOTIFY_OK; - - fcoe = fcoe_hostlist_lookup_realdev_port(netdev); - dev_put(netdev); - if (!fcoe) - return NOTIFY_OK; - - if (entry->dcbx & DCB_CAP_DCBX_VER_CEE) - prio = ffs(entry->app.priority) - 1; - else - prio = entry->app.priority; - - if (prio < 0) - return NOTIFY_OK; - - if (entry->app.protocol == ETH_P_FIP || - entry->app.protocol == ETH_P_FCOE) - fcoe->ctlr.priority = prio; - - if (entry->app.protocol == ETH_P_FCOE) { - port = lport_priv(fcoe->ctlr.lp); - port->priority = prio; - } - - return NOTIFY_OK; -} - -/** - * fcoe_device_notification() - Handler for net device events - * @notifier: The context of the notification - * @event: The type of event - * @ptr: The net device that the event was on - * - * This function is called by the Ethernet driver in case of link change event. - * - * Returns: 0 for success - */ -static int fcoe_device_notification(struct notifier_block *notifier, - ulong event, void *ptr) -{ - struct fc_lport *lport = NULL; - struct net_device *netdev = ptr; - struct fcoe_interface *fcoe; - struct fcoe_port *port; - struct fcoe_dev_stats *stats; - u32 link_possible = 1; - u32 mfs; - int rc = NOTIFY_OK; - - list_for_each_entry(fcoe, &fcoe_hostlist, list) { - if (fcoe->netdev == netdev) { - lport = fcoe->ctlr.lp; - break; - } - } - if (!lport) { - rc = NOTIFY_DONE; - goto out; - } - - switch (event) { - case NETDEV_DOWN: - case NETDEV_GOING_DOWN: - link_possible = 0; - break; - case NETDEV_UP: - case NETDEV_CHANGE: - break; - case NETDEV_CHANGEMTU: - if (netdev->features & NETIF_F_FCOE_MTU) - break; - mfs = netdev->mtu - (sizeof(struct fcoe_hdr) + - sizeof(struct fcoe_crc_eof)); - if (mfs >= FC_MIN_MAX_FRAME) - fc_set_mfs(lport, mfs); - break; - case NETDEV_REGISTER: - break; - case NETDEV_UNREGISTER: - list_del(&fcoe->list); - port = lport_priv(fcoe->ctlr.lp); - queue_work(fcoe_wq, &port->destroy_work); - goto out; - break; - case NETDEV_FEAT_CHANGE: - fcoe_netdev_features_change(lport, netdev); - break; - default: - FCOE_NETDEV_DBG(netdev, "Unknown event %ld " - "from netdev netlink\n", event); - } - - fcoe_link_speed_update(lport); - - if (link_possible && !fcoe_link_ok(lport)) - fcoe_ctlr_link_up(&fcoe->ctlr); - else if (fcoe_ctlr_link_down(&fcoe->ctlr)) { - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - stats->LinkFailureCount++; - put_cpu(); - fcoe_clean_pending_queue(lport); - } -out: - return rc; -} - -/** - * fcoe_disable() - Disables a FCoE interface - * @netdev : The net_device object the Ethernet interface to create on - * - * Called from fcoe transport. - * - * Returns: 0 for success - */ -static int fcoe_disable(struct net_device *netdev) -{ - struct fcoe_interface *fcoe; - int rc = 0; - - mutex_lock(&fcoe_config_mutex); - - rtnl_lock(); - fcoe = fcoe_hostlist_lookup_port(netdev); - rtnl_unlock(); - - if (fcoe) { - fcoe_ctlr_link_down(&fcoe->ctlr); - fcoe_clean_pending_queue(fcoe->ctlr.lp); - } else - rc = -ENODEV; - - mutex_unlock(&fcoe_config_mutex); - return rc; -} - -/** - * fcoe_enable() - Enables a FCoE interface - * @netdev : The net_device object the Ethernet interface to create on - * - * Called from fcoe transport. - * - * Returns: 0 for success - */ -static int fcoe_enable(struct net_device *netdev) -{ - struct fcoe_interface *fcoe; - int rc = 0; - - mutex_lock(&fcoe_config_mutex); - rtnl_lock(); - fcoe = fcoe_hostlist_lookup_port(netdev); - rtnl_unlock(); - - if (!fcoe) - rc = -ENODEV; - else if (!fcoe_link_ok(fcoe->ctlr.lp)) - fcoe_ctlr_link_up(&fcoe->ctlr); - - mutex_unlock(&fcoe_config_mutex); - return rc; -} - -/** - * fcoe_destroy() - Destroy a FCoE interface - * @netdev : The net_device object the Ethernet interface to create on - * - * Called from fcoe transport - * - * Returns: 0 for success - */ -static int fcoe_destroy(struct net_device *netdev) -{ - struct fcoe_interface *fcoe; - struct fc_lport *lport; - struct fcoe_port *port; - int rc = 0; - - mutex_lock(&fcoe_config_mutex); - rtnl_lock(); - fcoe = fcoe_hostlist_lookup_port(netdev); - if (!fcoe) { - rc = -ENODEV; - goto out_nodev; - } - lport = fcoe->ctlr.lp; - port = lport_priv(lport); - list_del(&fcoe->list); - queue_work(fcoe_wq, &port->destroy_work); -out_nodev: - rtnl_unlock(); - mutex_unlock(&fcoe_config_mutex); - return rc; -} - -/** - * fcoe_destroy_work() - Destroy a FCoE port in a deferred work context - * @work: Handle to the FCoE port to be destroyed - */ -static void fcoe_destroy_work(struct work_struct *work) -{ - struct fcoe_port *port; - struct fcoe_interface *fcoe; - - port = container_of(work, struct fcoe_port, destroy_work); - mutex_lock(&fcoe_config_mutex); - - fcoe = port->priv; - fcoe_if_destroy(port->lport); - fcoe_interface_cleanup(fcoe); - - mutex_unlock(&fcoe_config_mutex); -} - -/** - * fcoe_match() - Check if the FCoE is supported on the given netdevice - * @netdev : The net_device object the Ethernet interface to create on - * - * Called from fcoe transport. - * - * Returns: always returns true as this is the default FCoE transport, - * i.e., support all netdevs. - */ -static bool fcoe_match(struct net_device *netdev) -{ - return true; -} - -/** - * fcoe_dcb_create() - Initialize DCB attributes and hooks - * @netdev: The net_device object of the L2 link that should be queried - * @port: The fcoe_port to bind FCoE APP priority with - * @ - */ -static void fcoe_dcb_create(struct fcoe_interface *fcoe) -{ -#ifdef CONFIG_DCB - int dcbx; - u8 fup, up; - struct net_device *netdev = fcoe->realdev; - struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); - struct dcb_app app = { - .priority = 0, - .protocol = ETH_P_FCOE - }; - - /* setup DCB priority attributes. */ - if (netdev && netdev->dcbnl_ops && netdev->dcbnl_ops->getdcbx) { - dcbx = netdev->dcbnl_ops->getdcbx(netdev); - - if (dcbx & DCB_CAP_DCBX_VER_IEEE) { - app.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE; - up = dcb_ieee_getapp_mask(netdev, &app); - app.protocol = ETH_P_FIP; - fup = dcb_ieee_getapp_mask(netdev, &app); - } else { - app.selector = DCB_APP_IDTYPE_ETHTYPE; - up = dcb_getapp(netdev, &app); - app.protocol = ETH_P_FIP; - fup = dcb_getapp(netdev, &app); - } - - port->priority = ffs(up) ? ffs(up) - 1 : 0; - fcoe->ctlr.priority = ffs(fup) ? ffs(fup) - 1 : port->priority; - } -#endif -} - -/** - * fcoe_create() - Create a fcoe interface - * @netdev : The net_device object the Ethernet interface to create on - * @fip_mode: The FIP mode for this creation - * - * Called from fcoe transport - * - * Returns: 0 for success - */ -static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode) -{ - int rc = 0; - struct fcoe_interface *fcoe; - struct fc_lport *lport; - - mutex_lock(&fcoe_config_mutex); - rtnl_lock(); - - /* look for existing lport */ - if (fcoe_hostlist_lookup(netdev)) { - rc = -EEXIST; - goto out_nodev; - } - - fcoe = fcoe_interface_create(netdev, fip_mode); - if (IS_ERR(fcoe)) { - rc = PTR_ERR(fcoe); - goto out_nodev; - } - - lport = fcoe_if_create(fcoe, &netdev->dev, 0); - if (IS_ERR(lport)) { - printk(KERN_ERR "fcoe: Failed to create interface (%s)\n", - netdev->name); - rc = -EIO; - rtnl_unlock(); - fcoe_interface_cleanup(fcoe); - goto out_nortnl; - } - - /* Make this the "master" N_Port */ - fcoe->ctlr.lp = lport; - - /* setup DCB priority attributes. */ - fcoe_dcb_create(fcoe); - - /* add to lports list */ - fcoe_hostlist_add(lport); - - /* start FIP Discovery and FLOGI */ - lport->boot_time = jiffies; - fc_fabric_login(lport); - if (!fcoe_link_ok(lport)) { - rtnl_unlock(); - fcoe_ctlr_link_up(&fcoe->ctlr); - mutex_unlock(&fcoe_config_mutex); - return rc; - } - -out_nodev: - rtnl_unlock(); -out_nortnl: - mutex_unlock(&fcoe_config_mutex); - return rc; -} - -/** - * fcoe_link_speed_update() - Update the supported and actual link speeds - * @lport: The local port to update speeds for - * - * Returns: 0 if the ethtool query was successful - * -1 if the ethtool query failed - */ -static int fcoe_link_speed_update(struct fc_lport *lport) -{ - struct net_device *netdev = fcoe_netdev(lport); - struct ethtool_cmd ecmd; - - if (!__ethtool_get_settings(netdev, &ecmd)) { - lport->link_supported_speeds &= - ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT); - if (ecmd.supported & (SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full)) - lport->link_supported_speeds |= FC_PORTSPEED_1GBIT; - if (ecmd.supported & SUPPORTED_10000baseT_Full) - lport->link_supported_speeds |= - FC_PORTSPEED_10GBIT; - switch (ethtool_cmd_speed(&ecmd)) { - case SPEED_1000: - lport->link_speed = FC_PORTSPEED_1GBIT; - break; - case SPEED_10000: - lport->link_speed = FC_PORTSPEED_10GBIT; - break; - } - return 0; - } - return -1; -} - -/** - * fcoe_link_ok() - Check if the link is OK for a local port - * @lport: The local port to check link on - * - * Returns: 0 if link is UP and OK, -1 if not - * - */ -static int fcoe_link_ok(struct fc_lport *lport) -{ - struct net_device *netdev = fcoe_netdev(lport); - - if (netif_oper_up(netdev)) - return 0; - return -1; -} - -/** - * fcoe_percpu_clean() - Clear all pending skbs for an local port - * @lport: The local port whose skbs are to be cleared - * - * Must be called with fcoe_create_mutex held to single-thread completion. - * - * This flushes the pending skbs by adding a new skb to each queue and - * waiting until they are all freed. This assures us that not only are - * there no packets that will be handled by the lport, but also that any - * threads already handling packet have returned. - */ -static void fcoe_percpu_clean(struct fc_lport *lport) -{ - struct fcoe_percpu_s *pp; - struct sk_buff *skb; - unsigned int cpu; - - for_each_possible_cpu(cpu) { - pp = &per_cpu(fcoe_percpu, cpu); - - if (!pp->thread || !cpu_online(cpu)) - continue; - - skb = dev_alloc_skb(0); - if (!skb) { - spin_unlock_bh(&pp->fcoe_rx_list.lock); - continue; - } - skb->destructor = fcoe_percpu_flush_done; - - spin_lock_bh(&pp->fcoe_rx_list.lock); - __skb_queue_tail(&pp->fcoe_rx_list, skb); - if (pp->fcoe_rx_list.qlen == 1) - wake_up_process(pp->thread); - spin_unlock_bh(&pp->fcoe_rx_list.lock); - - wait_for_completion(&fcoe_flush_completion); - } -} - -/** - * fcoe_reset() - Reset a local port - * @shost: The SCSI host associated with the local port to be reset - * - * Returns: Always 0 (return value required by FC transport template) - */ -static int fcoe_reset(struct Scsi_Host *shost) -{ - struct fc_lport *lport = shost_priv(shost); - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - - fcoe_ctlr_link_down(&fcoe->ctlr); - fcoe_clean_pending_queue(fcoe->ctlr.lp); - if (!fcoe_link_ok(fcoe->ctlr.lp)) - fcoe_ctlr_link_up(&fcoe->ctlr); - return 0; -} - -/** - * fcoe_hostlist_lookup_port() - Find the FCoE interface associated with a net device - * @netdev: The net device used as a key - * - * Locking: Must be called with the RNL mutex held. - * - * Returns: NULL or the FCoE interface - */ -static struct fcoe_interface * -fcoe_hostlist_lookup_port(const struct net_device *netdev) -{ - struct fcoe_interface *fcoe; - - list_for_each_entry(fcoe, &fcoe_hostlist, list) { - if (fcoe->netdev == netdev) - return fcoe; - } - return NULL; -} - -/** - * fcoe_hostlist_lookup() - Find the local port associated with a - * given net device - * @netdev: The netdevice used as a key - * - * Locking: Must be called with the RTNL mutex held - * - * Returns: NULL or the local port - */ -static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) -{ - struct fcoe_interface *fcoe; - - fcoe = fcoe_hostlist_lookup_port(netdev); - return (fcoe) ? fcoe->ctlr.lp : NULL; -} - -/** - * fcoe_hostlist_add() - Add the FCoE interface identified by a local - * port to the hostlist - * @lport: The local port that identifies the FCoE interface to be added - * - * Locking: must be called with the RTNL mutex held - * - * Returns: 0 for success - */ -static int fcoe_hostlist_add(const struct fc_lport *lport) -{ - struct fcoe_interface *fcoe; - struct fcoe_port *port; - - fcoe = fcoe_hostlist_lookup_port(fcoe_netdev(lport)); - if (!fcoe) { - port = lport_priv(lport); - fcoe = port->priv; - list_add_tail(&fcoe->list, &fcoe_hostlist); - } - return 0; -} - - -static struct fcoe_transport fcoe_sw_transport = { - .name = {FCOE_TRANSPORT_DEFAULT}, - .attached = false, - .list = LIST_HEAD_INIT(fcoe_sw_transport.list), - .match = fcoe_match, - .create = fcoe_create, - .destroy = fcoe_destroy, - .enable = fcoe_enable, - .disable = fcoe_disable, -}; - -/** - * fcoe_init() - Initialize fcoe.ko - * - * Returns: 0 on success, or a negative value on failure - */ -static int __init fcoe_init(void) -{ - struct fcoe_percpu_s *p; - unsigned int cpu; - int rc = 0; - - fcoe_wq = alloc_workqueue("fcoe", 0, 0); - if (!fcoe_wq) - return -ENOMEM; - - /* register as a fcoe transport */ - rc = fcoe_transport_attach(&fcoe_sw_transport); - if (rc) { - printk(KERN_ERR "failed to register an fcoe transport, check " - "if libfcoe is loaded\n"); - return rc; - } - - mutex_lock(&fcoe_config_mutex); - - for_each_possible_cpu(cpu) { - p = &per_cpu(fcoe_percpu, cpu); - skb_queue_head_init(&p->fcoe_rx_list); - } - - for_each_online_cpu(cpu) - fcoe_percpu_thread_create(cpu); - - /* Initialize per CPU interrupt thread */ - rc = register_hotcpu_notifier(&fcoe_cpu_notifier); - if (rc) - goto out_free; - - /* Setup link change notification */ - fcoe_dev_setup(); - - rc = fcoe_if_init(); - if (rc) - goto out_free; - - mutex_unlock(&fcoe_config_mutex); - return 0; - -out_free: - for_each_online_cpu(cpu) { - fcoe_percpu_thread_destroy(cpu); - } - mutex_unlock(&fcoe_config_mutex); - destroy_workqueue(fcoe_wq); - return rc; -} -module_init(fcoe_init); - -/** - * fcoe_exit() - Clean up fcoe.ko - * - * Returns: 0 on success or a negative value on failure - */ -static void __exit fcoe_exit(void) -{ - struct fcoe_interface *fcoe, *tmp; - struct fcoe_port *port; - unsigned int cpu; - - mutex_lock(&fcoe_config_mutex); - - fcoe_dev_cleanup(); - - /* releases the associated fcoe hosts */ - rtnl_lock(); - list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) { - list_del(&fcoe->list); - port = lport_priv(fcoe->ctlr.lp); - queue_work(fcoe_wq, &port->destroy_work); - } - rtnl_unlock(); - - unregister_hotcpu_notifier(&fcoe_cpu_notifier); - - for_each_online_cpu(cpu) - fcoe_percpu_thread_destroy(cpu); - - mutex_unlock(&fcoe_config_mutex); - - /* - * destroy_work's may be chained but destroy_workqueue() - * can take care of them. Just kill the fcoe_wq. - */ - destroy_workqueue(fcoe_wq); - - /* - * Detaching from the scsi transport must happen after all - * destroys are done on the fcoe_wq. destroy_workqueue will - * enusre the fcoe_wq is flushed. - */ - fcoe_if_exit(); - - /* detach from fcoe transport */ - fcoe_transport_detach(&fcoe_sw_transport); -} -module_exit(fcoe_exit); - -/** - * fcoe_flogi_resp() - FCoE specific FLOGI and FDISC response handler - * @seq: active sequence in the FLOGI or FDISC exchange - * @fp: response frame, or error encoded in a pointer (timeout) - * @arg: pointer the the fcoe_ctlr structure - * - * This handles MAC address management for FCoE, then passes control on to - * the libfc FLOGI response handler. - */ -static void fcoe_flogi_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) -{ - struct fcoe_ctlr *fip = arg; - struct fc_exch *exch = fc_seq_exch(seq); - struct fc_lport *lport = exch->lp; - u8 *mac; - - if (IS_ERR(fp)) - goto done; - - mac = fr_cb(fp)->granted_mac; - /* pre-FIP */ - if (is_zero_ether_addr(mac)) - fcoe_ctlr_recv_flogi(fip, lport, fp); - if (!is_zero_ether_addr(mac)) - fcoe_update_src_mac(lport, mac); -done: - fc_lport_flogi_resp(seq, fp, lport); -} - -/** - * fcoe_logo_resp() - FCoE specific LOGO response handler - * @seq: active sequence in the LOGO exchange - * @fp: response frame, or error encoded in a pointer (timeout) - * @arg: pointer the the fcoe_ctlr structure - * - * This handles MAC address management for FCoE, then passes control on to - * the libfc LOGO response handler. - */ -static void fcoe_logo_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) -{ - struct fc_lport *lport = arg; - static u8 zero_mac[ETH_ALEN] = { 0 }; - - if (!IS_ERR(fp)) - fcoe_update_src_mac(lport, zero_mac); - fc_lport_logo_resp(seq, fp, lport); -} - -/** - * fcoe_elsct_send - FCoE specific ELS handler - * - * This does special case handling of FIP encapsualted ELS exchanges for FCoE, - * using FCoE specific response handlers and passing the FIP controller as - * the argument (the lport is still available from the exchange). - * - * Most of the work here is just handed off to the libfc routine. - */ -static struct fc_seq *fcoe_elsct_send(struct fc_lport *lport, u32 did, - struct fc_frame *fp, unsigned int op, - void (*resp)(struct fc_seq *, - struct fc_frame *, - void *), - void *arg, u32 timeout) -{ - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - struct fcoe_ctlr *fip = &fcoe->ctlr; - struct fc_frame_header *fh = fc_frame_header_get(fp); - - switch (op) { - case ELS_FLOGI: - case ELS_FDISC: - if (lport->point_to_multipoint) - break; - return fc_elsct_send(lport, did, fp, op, fcoe_flogi_resp, - fip, timeout); - case ELS_LOGO: - /* only hook onto fabric logouts, not port logouts */ - if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) - break; - return fc_elsct_send(lport, did, fp, op, fcoe_logo_resp, - lport, timeout); - } - return fc_elsct_send(lport, did, fp, op, resp, arg, timeout); -} - -/** - * fcoe_vport_create() - create an fc_host/scsi_host for a vport - * @vport: fc_vport object to create a new fc_host for - * @disabled: start the new fc_host in a disabled state by default? - * - * Returns: 0 for success - */ -static int fcoe_vport_create(struct fc_vport *vport, bool disabled) -{ - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_lport *n_port = shost_priv(shost); - struct fcoe_port *port = lport_priv(n_port); - struct fcoe_interface *fcoe = port->priv; - struct net_device *netdev = fcoe->netdev; - struct fc_lport *vn_port; - int rc; - char buf[32]; - - rc = fcoe_validate_vport_create(vport); - if (rc) { - fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); - printk(KERN_ERR "fcoe: Failed to create vport, " - "WWPN (0x%s) already exists\n", - buf); - return rc; - } - - mutex_lock(&fcoe_config_mutex); - rtnl_lock(); - vn_port = fcoe_if_create(fcoe, &vport->dev, 1); - rtnl_unlock(); - mutex_unlock(&fcoe_config_mutex); - - if (IS_ERR(vn_port)) { - printk(KERN_ERR "fcoe: fcoe_vport_create(%s) failed\n", - netdev->name); - return -EIO; - } - - if (disabled) { - fc_vport_set_state(vport, FC_VPORT_DISABLED); - } else { - vn_port->boot_time = jiffies; - fc_fabric_login(vn_port); - fc_vport_setlink(vn_port); - } - return 0; -} - -/** - * fcoe_vport_destroy() - destroy the fc_host/scsi_host for a vport - * @vport: fc_vport object that is being destroyed - * - * Returns: 0 for success - */ -static int fcoe_vport_destroy(struct fc_vport *vport) -{ - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_lport *n_port = shost_priv(shost); - struct fc_lport *vn_port = vport->dd_data; - - mutex_lock(&n_port->lp_mutex); - list_del(&vn_port->list); - mutex_unlock(&n_port->lp_mutex); - - mutex_lock(&fcoe_config_mutex); - fcoe_if_destroy(vn_port); - mutex_unlock(&fcoe_config_mutex); - - return 0; -} - -/** - * fcoe_vport_disable() - change vport state - * @vport: vport to bring online/offline - * @disable: should the vport be disabled? - */ -static int fcoe_vport_disable(struct fc_vport *vport, bool disable) -{ - struct fc_lport *lport = vport->dd_data; - - if (disable) { - fc_vport_set_state(vport, FC_VPORT_DISABLED); - fc_fabric_logoff(lport); - } else { - lport->boot_time = jiffies; - fc_fabric_login(lport); - fc_vport_setlink(lport); - } - - return 0; -} - -/** - * fcoe_vport_set_symbolic_name() - append vport string to symbolic name - * @vport: fc_vport with a new symbolic name string - * - * After generating a new symbolic name string, a new RSPN_ID request is - * sent to the name server. There is no response handler, so if it fails - * for some reason it will not be retried. - */ -static void fcoe_set_vport_symbolic_name(struct fc_vport *vport) -{ - struct fc_lport *lport = vport->dd_data; - struct fc_frame *fp; - size_t len; - - snprintf(fc_host_symbolic_name(lport->host), FC_SYMBOLIC_NAME_SIZE, - "%s v%s over %s : %s", FCOE_NAME, FCOE_VERSION, - fcoe_netdev(lport)->name, vport->symbolic_name); - - if (lport->state != LPORT_ST_READY) - return; - - len = strnlen(fc_host_symbolic_name(lport->host), 255); - fp = fc_frame_alloc(lport, - sizeof(struct fc_ct_hdr) + - sizeof(struct fc_ns_rspn) + len); - if (!fp) - return; - lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, FC_NS_RSPN_ID, - NULL, NULL, 3 * lport->r_a_tov); -} - -/** - * fcoe_get_lesb() - Fill the FCoE Link Error Status Block - * @lport: the local port - * @fc_lesb: the link error status block - */ -static void fcoe_get_lesb(struct fc_lport *lport, - struct fc_els_lesb *fc_lesb) -{ - struct net_device *netdev = fcoe_netdev(lport); - - __fcoe_get_lesb(lport, fc_lesb, netdev); -} - -/** - * fcoe_set_port_id() - Callback from libfc when Port_ID is set. - * @lport: the local port - * @port_id: the port ID - * @fp: the received frame, if any, that caused the port_id to be set. - * - * This routine handles the case where we received a FLOGI and are - * entering point-to-point mode. We need to call fcoe_ctlr_recv_flogi() - * so it can set the non-mapped mode and gateway address. - * - * The FLOGI LS_ACC is handled by fcoe_flogi_resp(). - */ -static void fcoe_set_port_id(struct fc_lport *lport, - u32 port_id, struct fc_frame *fp) -{ - struct fcoe_port *port = lport_priv(lport); - struct fcoe_interface *fcoe = port->priv; - - if (fp && fc_frame_payload_op(fp) == ELS_FLOGI) - fcoe_ctlr_recv_flogi(&fcoe->ctlr, lport, fp); -} diff --git a/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.h b/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.h deleted file mode 100644 index 3c2733a1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#ifndef _FCOE_H_ -#define _FCOE_H_ - -#include -#include - -#define FCOE_MAX_QUEUE_DEPTH 256 -#define FCOE_MIN_QUEUE_DEPTH 32 - -#define FCOE_WORD_TO_BYTE 4 - -#define FCOE_VERSION "0.1" -#define FCOE_NAME "fcoe" -#define FCOE_VENDOR "Open-FCoE.org" - -#define FCOE_MAX_LUN 0xFFFF -#define FCOE_MAX_FCP_TARGET 256 - -#define FCOE_MAX_OUTSTANDING_COMMANDS 1024 - -#define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ -#define FCOE_MAX_XID 0x0FFF /* the max xid supported by fcoe_sw */ - -extern unsigned int fcoe_debug_logging; - -#define FCOE_LOGGING 0x01 /* General logging, not categorized */ -#define FCOE_NETDEV_LOGGING 0x02 /* Netdevice logging */ - -#define FCOE_CHECK_LOGGING(LEVEL, CMD) \ -do { \ - if (unlikely(fcoe_debug_logging & LEVEL)) \ - do { \ - CMD; \ - } while (0); \ -} while (0) - -#define FCOE_DBG(fmt, args...) \ - FCOE_CHECK_LOGGING(FCOE_LOGGING, \ - printk(KERN_INFO "fcoe: " fmt, ##args);) - -#define FCOE_NETDEV_DBG(netdev, fmt, args...) \ - FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING, \ - printk(KERN_INFO "fcoe: %s: " fmt, \ - netdev->name, ##args);) - -/** - * struct fcoe_interface - A FCoE interface - * @list: Handle for a list of FCoE interfaces - * @netdev: The associated net device - * @fcoe_packet_type: FCoE packet type - * @fip_packet_type: FIP packet type - * @ctlr: The FCoE controller (for FIP) - * @oem: The offload exchange manager for all local port - * instances associated with this port - * This structure is 1:1 with a net devive. - */ -struct fcoe_interface { - struct list_head list; - struct net_device *netdev; - struct net_device *realdev; - struct packet_type fcoe_packet_type; - struct packet_type fip_packet_type; - struct fcoe_ctlr ctlr; - struct fc_exch_mgr *oem; -}; - -#define fcoe_from_ctlr(fip) container_of(fip, struct fcoe_interface, ctlr) - -/** - * fcoe_netdev() - Return the net device associated with a local port - * @lport: The local port to get the net device from - */ -static inline struct net_device *fcoe_netdev(const struct fc_lport *lport) -{ - return ((struct fcoe_interface *) - ((struct fcoe_port *)lport_priv(lport))->priv)->netdev; -} - -#endif /* _FCOE_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_ctlr.c b/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_ctlr.c deleted file mode 100644 index 249a1068..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_ctlr.c +++ /dev/null @@ -1,2749 +0,0 @@ -/* - * Copyright (c) 2008-2009 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "libfcoe.h" - -#define FCOE_CTLR_MIN_FKA 500 /* min keep alive (mS) */ -#define FCOE_CTLR_DEF_FKA FIP_DEF_FKA /* default keep alive (mS) */ - -static void fcoe_ctlr_timeout(unsigned long); -static void fcoe_ctlr_timer_work(struct work_struct *); -static void fcoe_ctlr_recv_work(struct work_struct *); -static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *); - -static void fcoe_ctlr_vn_start(struct fcoe_ctlr *); -static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *); -static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *); -static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *, u32, u8 *); - -static u8 fcoe_all_fcfs[ETH_ALEN] = FIP_ALL_FCF_MACS; -static u8 fcoe_all_enode[ETH_ALEN] = FIP_ALL_ENODE_MACS; -static u8 fcoe_all_vn2vn[ETH_ALEN] = FIP_ALL_VN2VN_MACS; -static u8 fcoe_all_p2p[ETH_ALEN] = FIP_ALL_P2P_MACS; - -static const char * const fcoe_ctlr_states[] = { - [FIP_ST_DISABLED] = "DISABLED", - [FIP_ST_LINK_WAIT] = "LINK_WAIT", - [FIP_ST_AUTO] = "AUTO", - [FIP_ST_NON_FIP] = "NON_FIP", - [FIP_ST_ENABLED] = "ENABLED", - [FIP_ST_VNMP_START] = "VNMP_START", - [FIP_ST_VNMP_PROBE1] = "VNMP_PROBE1", - [FIP_ST_VNMP_PROBE2] = "VNMP_PROBE2", - [FIP_ST_VNMP_CLAIM] = "VNMP_CLAIM", - [FIP_ST_VNMP_UP] = "VNMP_UP", -}; - -static const char *fcoe_ctlr_state(enum fip_state state) -{ - const char *cp = "unknown"; - - if (state < ARRAY_SIZE(fcoe_ctlr_states)) - cp = fcoe_ctlr_states[state]; - if (!cp) - cp = "unknown"; - return cp; -} - -/** - * fcoe_ctlr_set_state() - Set and do debug printing for the new FIP state. - * @fip: The FCoE controller - * @state: The new state - */ -static void fcoe_ctlr_set_state(struct fcoe_ctlr *fip, enum fip_state state) -{ - if (state == fip->state) - return; - if (fip->lp) - LIBFCOE_FIP_DBG(fip, "state %s -> %s\n", - fcoe_ctlr_state(fip->state), fcoe_ctlr_state(state)); - fip->state = state; -} - -/** - * fcoe_ctlr_mtu_valid() - Check if a FCF's MTU is valid - * @fcf: The FCF to check - * - * Return non-zero if FCF fcoe_size has been validated. - */ -static inline int fcoe_ctlr_mtu_valid(const struct fcoe_fcf *fcf) -{ - return (fcf->flags & FIP_FL_SOL) != 0; -} - -/** - * fcoe_ctlr_fcf_usable() - Check if a FCF is usable - * @fcf: The FCF to check - * - * Return non-zero if the FCF is usable. - */ -static inline int fcoe_ctlr_fcf_usable(struct fcoe_fcf *fcf) -{ - u16 flags = FIP_FL_SOL | FIP_FL_AVAIL; - - return (fcf->flags & flags) == flags; -} - -/** - * fcoe_ctlr_map_dest() - Set flag and OUI for mapping destination addresses - * @fip: The FCoE controller - */ -static void fcoe_ctlr_map_dest(struct fcoe_ctlr *fip) -{ - if (fip->mode == FIP_MODE_VN2VN) - hton24(fip->dest_addr, FIP_VN_FC_MAP); - else - hton24(fip->dest_addr, FIP_DEF_FC_MAP); - hton24(fip->dest_addr + 3, 0); - fip->map_dest = 1; -} - -/** - * fcoe_ctlr_init() - Initialize the FCoE Controller instance - * @fip: The FCoE controller to initialize - */ -void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode) -{ - fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT); - fip->mode = mode; - INIT_LIST_HEAD(&fip->fcfs); - mutex_init(&fip->ctlr_mutex); - spin_lock_init(&fip->ctlr_lock); - fip->flogi_oxid = FC_XID_UNKNOWN; - setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip); - INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work); - INIT_WORK(&fip->recv_work, fcoe_ctlr_recv_work); - skb_queue_head_init(&fip->fip_recv_list); -} -EXPORT_SYMBOL(fcoe_ctlr_init); - -/** - * fcoe_ctlr_reset_fcfs() - Reset and free all FCFs for a controller - * @fip: The FCoE controller whose FCFs are to be reset - * - * Called with &fcoe_ctlr lock held. - */ -static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *fcf; - struct fcoe_fcf *next; - - fip->sel_fcf = NULL; - list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { - list_del(&fcf->list); - kfree(fcf); - } - fip->fcf_count = 0; - fip->sel_time = 0; -} - -/** - * fcoe_ctlr_destroy() - Disable and tear down a FCoE controller - * @fip: The FCoE controller to tear down - * - * This is called by FCoE drivers before freeing the &fcoe_ctlr. - * - * The receive handler will have been deleted before this to guarantee - * that no more recv_work will be scheduled. - * - * The timer routine will simply return once we set FIP_ST_DISABLED. - * This guarantees that no further timeouts or work will be scheduled. - */ -void fcoe_ctlr_destroy(struct fcoe_ctlr *fip) -{ - cancel_work_sync(&fip->recv_work); - skb_queue_purge(&fip->fip_recv_list); - - mutex_lock(&fip->ctlr_mutex); - fcoe_ctlr_set_state(fip, FIP_ST_DISABLED); - fcoe_ctlr_reset_fcfs(fip); - mutex_unlock(&fip->ctlr_mutex); - del_timer_sync(&fip->timer); - cancel_work_sync(&fip->timer_work); -} -EXPORT_SYMBOL(fcoe_ctlr_destroy); - -/** - * fcoe_ctlr_announce() - announce new FCF selection - * @fip: The FCoE controller - * - * Also sets the destination MAC for FCoE and control packets - * - * Called with neither ctlr_mutex nor ctlr_lock held. - */ -static void fcoe_ctlr_announce(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *sel; - struct fcoe_fcf *fcf; - - mutex_lock(&fip->ctlr_mutex); - spin_lock_bh(&fip->ctlr_lock); - - kfree_skb(fip->flogi_req); - fip->flogi_req = NULL; - list_for_each_entry(fcf, &fip->fcfs, list) - fcf->flogi_sent = 0; - - spin_unlock_bh(&fip->ctlr_lock); - sel = fip->sel_fcf; - - if (sel && !compare_ether_addr(sel->fcf_mac, fip->dest_addr)) - goto unlock; - if (!is_zero_ether_addr(fip->dest_addr)) { - printk(KERN_NOTICE "libfcoe: host%d: " - "FIP Fibre-Channel Forwarder MAC %pM deselected\n", - fip->lp->host->host_no, fip->dest_addr); - memset(fip->dest_addr, 0, ETH_ALEN); - } - if (sel) { - printk(KERN_INFO "libfcoe: host%d: FIP selected " - "Fibre-Channel Forwarder MAC %pM\n", - fip->lp->host->host_no, sel->fcf_mac); - memcpy(fip->dest_addr, sel->fcoe_mac, ETH_ALEN); - fip->map_dest = 0; - } -unlock: - mutex_unlock(&fip->ctlr_mutex); -} - -/** - * fcoe_ctlr_fcoe_size() - Return the maximum FCoE size required for VN_Port - * @fip: The FCoE controller to get the maximum FCoE size from - * - * Returns the maximum packet size including the FCoE header and trailer, - * but not including any Ethernet or VLAN headers. - */ -static inline u32 fcoe_ctlr_fcoe_size(struct fcoe_ctlr *fip) -{ - /* - * Determine the max FCoE frame size allowed, including - * FCoE header and trailer. - * Note: lp->mfs is currently the payload size, not the frame size. - */ - return fip->lp->mfs + sizeof(struct fc_frame_header) + - sizeof(struct fcoe_hdr) + sizeof(struct fcoe_crc_eof); -} - -/** - * fcoe_ctlr_solicit() - Send a FIP solicitation - * @fip: The FCoE controller to send the solicitation on - * @fcf: The destination FCF (if NULL, a multicast solicitation is sent) - */ -static void fcoe_ctlr_solicit(struct fcoe_ctlr *fip, struct fcoe_fcf *fcf) -{ - struct sk_buff *skb; - struct fip_sol { - struct ethhdr eth; - struct fip_header fip; - struct { - struct fip_mac_desc mac; - struct fip_wwn_desc wwnn; - struct fip_size_desc size; - } __packed desc; - } __packed * sol; - u32 fcoe_size; - - skb = dev_alloc_skb(sizeof(*sol)); - if (!skb) - return; - - sol = (struct fip_sol *)skb->data; - - memset(sol, 0, sizeof(*sol)); - memcpy(sol->eth.h_dest, fcf ? fcf->fcf_mac : fcoe_all_fcfs, ETH_ALEN); - memcpy(sol->eth.h_source, fip->ctl_src_addr, ETH_ALEN); - sol->eth.h_proto = htons(ETH_P_FIP); - - sol->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); - sol->fip.fip_op = htons(FIP_OP_DISC); - sol->fip.fip_subcode = FIP_SC_SOL; - sol->fip.fip_dl_len = htons(sizeof(sol->desc) / FIP_BPW); - sol->fip.fip_flags = htons(FIP_FL_FPMA); - if (fip->spma) - sol->fip.fip_flags |= htons(FIP_FL_SPMA); - - sol->desc.mac.fd_desc.fip_dtype = FIP_DT_MAC; - sol->desc.mac.fd_desc.fip_dlen = sizeof(sol->desc.mac) / FIP_BPW; - memcpy(sol->desc.mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); - - sol->desc.wwnn.fd_desc.fip_dtype = FIP_DT_NAME; - sol->desc.wwnn.fd_desc.fip_dlen = sizeof(sol->desc.wwnn) / FIP_BPW; - put_unaligned_be64(fip->lp->wwnn, &sol->desc.wwnn.fd_wwn); - - fcoe_size = fcoe_ctlr_fcoe_size(fip); - sol->desc.size.fd_desc.fip_dtype = FIP_DT_FCOE_SIZE; - sol->desc.size.fd_desc.fip_dlen = sizeof(sol->desc.size) / FIP_BPW; - sol->desc.size.fd_size = htons(fcoe_size); - - skb_put(skb, sizeof(*sol)); - skb->protocol = htons(ETH_P_FIP); - skb->priority = fip->priority; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - fip->send(fip, skb); - - if (!fcf) - fip->sol_time = jiffies; -} - -/** - * fcoe_ctlr_link_up() - Start FCoE controller - * @fip: The FCoE controller to start - * - * Called from the LLD when the network link is ready. - */ -void fcoe_ctlr_link_up(struct fcoe_ctlr *fip) -{ - mutex_lock(&fip->ctlr_mutex); - if (fip->state == FIP_ST_NON_FIP || fip->state == FIP_ST_AUTO) { - mutex_unlock(&fip->ctlr_mutex); - fc_linkup(fip->lp); - } else if (fip->state == FIP_ST_LINK_WAIT) { - fcoe_ctlr_set_state(fip, fip->mode); - switch (fip->mode) { - default: - LIBFCOE_FIP_DBG(fip, "invalid mode %d\n", fip->mode); - /* fall-through */ - case FIP_MODE_AUTO: - LIBFCOE_FIP_DBG(fip, "%s", "setting AUTO mode.\n"); - /* fall-through */ - case FIP_MODE_FABRIC: - case FIP_MODE_NON_FIP: - mutex_unlock(&fip->ctlr_mutex); - fc_linkup(fip->lp); - fcoe_ctlr_solicit(fip, NULL); - break; - case FIP_MODE_VN2VN: - fcoe_ctlr_vn_start(fip); - mutex_unlock(&fip->ctlr_mutex); - fc_linkup(fip->lp); - break; - } - } else - mutex_unlock(&fip->ctlr_mutex); -} -EXPORT_SYMBOL(fcoe_ctlr_link_up); - -/** - * fcoe_ctlr_reset() - Reset a FCoE controller - * @fip: The FCoE controller to reset - */ -static void fcoe_ctlr_reset(struct fcoe_ctlr *fip) -{ - fcoe_ctlr_reset_fcfs(fip); - del_timer(&fip->timer); - fip->ctlr_ka_time = 0; - fip->port_ka_time = 0; - fip->sol_time = 0; - fip->flogi_oxid = FC_XID_UNKNOWN; - fcoe_ctlr_map_dest(fip); -} - -/** - * fcoe_ctlr_link_down() - Stop a FCoE controller - * @fip: The FCoE controller to be stopped - * - * Returns non-zero if the link was up and now isn't. - * - * Called from the LLD when the network link is not ready. - * There may be multiple calls while the link is down. - */ -int fcoe_ctlr_link_down(struct fcoe_ctlr *fip) -{ - int link_dropped; - - LIBFCOE_FIP_DBG(fip, "link down.\n"); - mutex_lock(&fip->ctlr_mutex); - fcoe_ctlr_reset(fip); - link_dropped = fip->state != FIP_ST_LINK_WAIT; - fcoe_ctlr_set_state(fip, FIP_ST_LINK_WAIT); - mutex_unlock(&fip->ctlr_mutex); - - if (link_dropped) - fc_linkdown(fip->lp); - return link_dropped; -} -EXPORT_SYMBOL(fcoe_ctlr_link_down); - -/** - * fcoe_ctlr_send_keep_alive() - Send a keep-alive to the selected FCF - * @fip: The FCoE controller to send the FKA on - * @lport: libfc fc_lport to send from - * @ports: 0 for controller keep-alive, 1 for port keep-alive - * @sa: The source MAC address - * - * A controller keep-alive is sent every fka_period (typically 8 seconds). - * The source MAC is the native MAC address. - * - * A port keep-alive is sent every 90 seconds while logged in. - * The source MAC is the assigned mapped source address. - * The destination is the FCF's F-port. - */ -static void fcoe_ctlr_send_keep_alive(struct fcoe_ctlr *fip, - struct fc_lport *lport, - int ports, u8 *sa) -{ - struct sk_buff *skb; - struct fip_kal { - struct ethhdr eth; - struct fip_header fip; - struct fip_mac_desc mac; - } __packed * kal; - struct fip_vn_desc *vn; - u32 len; - struct fc_lport *lp; - struct fcoe_fcf *fcf; - - fcf = fip->sel_fcf; - lp = fip->lp; - if (!fcf || (ports && !lp->port_id)) - return; - - len = sizeof(*kal) + ports * sizeof(*vn); - skb = dev_alloc_skb(len); - if (!skb) - return; - - kal = (struct fip_kal *)skb->data; - memset(kal, 0, len); - memcpy(kal->eth.h_dest, fcf->fcf_mac, ETH_ALEN); - memcpy(kal->eth.h_source, sa, ETH_ALEN); - kal->eth.h_proto = htons(ETH_P_FIP); - - kal->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); - kal->fip.fip_op = htons(FIP_OP_CTRL); - kal->fip.fip_subcode = FIP_SC_KEEP_ALIVE; - kal->fip.fip_dl_len = htons((sizeof(kal->mac) + - ports * sizeof(*vn)) / FIP_BPW); - kal->fip.fip_flags = htons(FIP_FL_FPMA); - if (fip->spma) - kal->fip.fip_flags |= htons(FIP_FL_SPMA); - - kal->mac.fd_desc.fip_dtype = FIP_DT_MAC; - kal->mac.fd_desc.fip_dlen = sizeof(kal->mac) / FIP_BPW; - memcpy(kal->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); - if (ports) { - vn = (struct fip_vn_desc *)(kal + 1); - vn->fd_desc.fip_dtype = FIP_DT_VN_ID; - vn->fd_desc.fip_dlen = sizeof(*vn) / FIP_BPW; - memcpy(vn->fd_mac, fip->get_src_addr(lport), ETH_ALEN); - hton24(vn->fd_fc_id, lport->port_id); - put_unaligned_be64(lport->wwpn, &vn->fd_wwpn); - } - skb_put(skb, len); - skb->protocol = htons(ETH_P_FIP); - skb->priority = fip->priority; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - fip->send(fip, skb); -} - -/** - * fcoe_ctlr_encaps() - Encapsulate an ELS frame for FIP, without sending it - * @fip: The FCoE controller for the ELS frame - * @dtype: The FIP descriptor type for the frame - * @skb: The FCoE ELS frame including FC header but no FCoE headers - * @d_id: The destination port ID. - * - * Returns non-zero error code on failure. - * - * The caller must check that the length is a multiple of 4. - * - * The @skb must have enough headroom (28 bytes) and tailroom (8 bytes). - * Headroom includes the FIP encapsulation description, FIP header, and - * Ethernet header. The tailroom is for the FIP MAC descriptor. - */ -static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport, - u8 dtype, struct sk_buff *skb, u32 d_id) -{ - struct fip_encaps_head { - struct ethhdr eth; - struct fip_header fip; - struct fip_encaps encaps; - } __packed * cap; - struct fc_frame_header *fh; - struct fip_mac_desc *mac; - struct fcoe_fcf *fcf; - size_t dlen; - u16 fip_flags; - u8 op; - - fh = (struct fc_frame_header *)skb->data; - op = *(u8 *)(fh + 1); - dlen = sizeof(struct fip_encaps) + skb->len; /* len before push */ - cap = (struct fip_encaps_head *)skb_push(skb, sizeof(*cap)); - memset(cap, 0, sizeof(*cap)); - - if (lport->point_to_multipoint) { - if (fcoe_ctlr_vn_lookup(fip, d_id, cap->eth.h_dest)) - return -ENODEV; - fip_flags = 0; - } else { - fcf = fip->sel_fcf; - if (!fcf) - return -ENODEV; - fip_flags = fcf->flags; - fip_flags &= fip->spma ? FIP_FL_SPMA | FIP_FL_FPMA : - FIP_FL_FPMA; - if (!fip_flags) - return -ENODEV; - memcpy(cap->eth.h_dest, fcf->fcf_mac, ETH_ALEN); - } - memcpy(cap->eth.h_source, fip->ctl_src_addr, ETH_ALEN); - cap->eth.h_proto = htons(ETH_P_FIP); - - cap->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); - cap->fip.fip_op = htons(FIP_OP_LS); - if (op == ELS_LS_ACC || op == ELS_LS_RJT) - cap->fip.fip_subcode = FIP_SC_REP; - else - cap->fip.fip_subcode = FIP_SC_REQ; - cap->fip.fip_flags = htons(fip_flags); - - cap->encaps.fd_desc.fip_dtype = dtype; - cap->encaps.fd_desc.fip_dlen = dlen / FIP_BPW; - - if (op != ELS_LS_RJT) { - dlen += sizeof(*mac); - mac = (struct fip_mac_desc *)skb_put(skb, sizeof(*mac)); - memset(mac, 0, sizeof(*mac)); - mac->fd_desc.fip_dtype = FIP_DT_MAC; - mac->fd_desc.fip_dlen = sizeof(*mac) / FIP_BPW; - if (dtype != FIP_DT_FLOGI && dtype != FIP_DT_FDISC) { - memcpy(mac->fd_mac, fip->get_src_addr(lport), ETH_ALEN); - } else if (fip->mode == FIP_MODE_VN2VN) { - hton24(mac->fd_mac, FIP_VN_FC_MAP); - hton24(mac->fd_mac + 3, fip->port_id); - } else if (fip_flags & FIP_FL_SPMA) { - LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with SPMA\n"); - memcpy(mac->fd_mac, fip->ctl_src_addr, ETH_ALEN); - } else { - LIBFCOE_FIP_DBG(fip, "FLOGI/FDISC sent with FPMA\n"); - /* FPMA only FLOGI. Must leave the MAC desc zeroed. */ - } - } - cap->fip.fip_dl_len = htons(dlen / FIP_BPW); - - skb->protocol = htons(ETH_P_FIP); - skb->priority = fip->priority; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - return 0; -} - -/** - * fcoe_ctlr_els_send() - Send an ELS frame encapsulated by FIP if appropriate. - * @fip: FCoE controller. - * @lport: libfc fc_lport to send from - * @skb: FCoE ELS frame including FC header but no FCoE headers. - * - * Returns a non-zero error code if the frame should not be sent. - * Returns zero if the caller should send the frame with FCoE encapsulation. - * - * The caller must check that the length is a multiple of 4. - * The SKB must have enough headroom (28 bytes) and tailroom (8 bytes). - * The the skb must also be an fc_frame. - * - * This is called from the lower-level driver with spinlocks held, - * so we must not take a mutex here. - */ -int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport, - struct sk_buff *skb) -{ - struct fc_frame *fp; - struct fc_frame_header *fh; - u16 old_xid; - u8 op; - u8 mac[ETH_ALEN]; - - fp = container_of(skb, struct fc_frame, skb); - fh = (struct fc_frame_header *)skb->data; - op = *(u8 *)(fh + 1); - - if (op == ELS_FLOGI && fip->mode != FIP_MODE_VN2VN) { - old_xid = fip->flogi_oxid; - fip->flogi_oxid = ntohs(fh->fh_ox_id); - if (fip->state == FIP_ST_AUTO) { - if (old_xid == FC_XID_UNKNOWN) - fip->flogi_count = 0; - fip->flogi_count++; - if (fip->flogi_count < 3) - goto drop; - fcoe_ctlr_map_dest(fip); - return 0; - } - if (fip->state == FIP_ST_NON_FIP) - fcoe_ctlr_map_dest(fip); - } - - if (fip->state == FIP_ST_NON_FIP) - return 0; - if (!fip->sel_fcf && fip->mode != FIP_MODE_VN2VN) - goto drop; - switch (op) { - case ELS_FLOGI: - op = FIP_DT_FLOGI; - if (fip->mode == FIP_MODE_VN2VN) - break; - spin_lock_bh(&fip->ctlr_lock); - kfree_skb(fip->flogi_req); - fip->flogi_req = skb; - fip->flogi_req_send = 1; - spin_unlock_bh(&fip->ctlr_lock); - schedule_work(&fip->timer_work); - return -EINPROGRESS; - case ELS_FDISC: - if (ntoh24(fh->fh_s_id)) - return 0; - op = FIP_DT_FDISC; - break; - case ELS_LOGO: - if (fip->mode == FIP_MODE_VN2VN) { - if (fip->state != FIP_ST_VNMP_UP) - return -EINVAL; - if (ntoh24(fh->fh_d_id) == FC_FID_FLOGI) - return -EINVAL; - } else { - if (fip->state != FIP_ST_ENABLED) - return 0; - if (ntoh24(fh->fh_d_id) != FC_FID_FLOGI) - return 0; - } - op = FIP_DT_LOGO; - break; - case ELS_LS_ACC: - /* - * If non-FIP, we may have gotten an SID by accepting an FLOGI - * from a point-to-point connection. Switch to using - * the source mac based on the SID. The destination - * MAC in this case would have been set by receiving the - * FLOGI. - */ - if (fip->state == FIP_ST_NON_FIP) { - if (fip->flogi_oxid == FC_XID_UNKNOWN) - return 0; - fip->flogi_oxid = FC_XID_UNKNOWN; - fc_fcoe_set_mac(mac, fh->fh_d_id); - fip->update_mac(lport, mac); - } - /* fall through */ - case ELS_LS_RJT: - op = fr_encaps(fp); - if (op) - break; - return 0; - default: - if (fip->state != FIP_ST_ENABLED && - fip->state != FIP_ST_VNMP_UP) - goto drop; - return 0; - } - LIBFCOE_FIP_DBG(fip, "els_send op %u d_id %x\n", - op, ntoh24(fh->fh_d_id)); - if (fcoe_ctlr_encaps(fip, lport, op, skb, ntoh24(fh->fh_d_id))) - goto drop; - fip->send(fip, skb); - return -EINPROGRESS; -drop: - kfree_skb(skb); - return -EINVAL; -} -EXPORT_SYMBOL(fcoe_ctlr_els_send); - -/** - * fcoe_ctlr_age_fcfs() - Reset and free all old FCFs for a controller - * @fip: The FCoE controller to free FCFs on - * - * Called with lock held and preemption disabled. - * - * An FCF is considered old if we have missed two advertisements. - * That is, there have been no valid advertisement from it for 2.5 - * times its keep-alive period. - * - * In addition, determine the time when an FCF selection can occur. - * - * Also, increment the MissDiscAdvCount when no advertisement is received - * for the corresponding FCF for 1.5 * FKA_ADV_PERIOD (FC-BB-5 LESB). - * - * Returns the time in jiffies for the next call. - */ -static unsigned long fcoe_ctlr_age_fcfs(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *fcf; - struct fcoe_fcf *next; - unsigned long next_timer = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD); - unsigned long deadline; - unsigned long sel_time = 0; - struct fcoe_dev_stats *stats; - - stats = per_cpu_ptr(fip->lp->dev_stats, get_cpu()); - - list_for_each_entry_safe(fcf, next, &fip->fcfs, list) { - deadline = fcf->time + fcf->fka_period + fcf->fka_period / 2; - if (fip->sel_fcf == fcf) { - if (time_after(jiffies, deadline)) { - stats->MissDiscAdvCount++; - printk(KERN_INFO "libfcoe: host%d: " - "Missing Discovery Advertisement " - "for fab %16.16llx count %lld\n", - fip->lp->host->host_no, fcf->fabric_name, - stats->MissDiscAdvCount); - } else if (time_after(next_timer, deadline)) - next_timer = deadline; - } - - deadline += fcf->fka_period; - if (time_after_eq(jiffies, deadline)) { - if (fip->sel_fcf == fcf) - fip->sel_fcf = NULL; - list_del(&fcf->list); - WARN_ON(!fip->fcf_count); - fip->fcf_count--; - kfree(fcf); - stats->VLinkFailureCount++; - } else { - if (time_after(next_timer, deadline)) - next_timer = deadline; - if (fcoe_ctlr_mtu_valid(fcf) && - (!sel_time || time_before(sel_time, fcf->time))) - sel_time = fcf->time; - } - } - put_cpu(); - if (sel_time && !fip->sel_fcf && !fip->sel_time) { - sel_time += msecs_to_jiffies(FCOE_CTLR_START_DELAY); - fip->sel_time = sel_time; - } - - return next_timer; -} - -/** - * fcoe_ctlr_parse_adv() - Decode a FIP advertisement into a new FCF entry - * @fip: The FCoE controller receiving the advertisement - * @skb: The received FIP advertisement frame - * @fcf: The resulting FCF entry - * - * Returns zero on a valid parsed advertisement, - * otherwise returns non zero value. - */ -static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, - struct sk_buff *skb, struct fcoe_fcf *fcf) -{ - struct fip_header *fiph; - struct fip_desc *desc = NULL; - struct fip_wwn_desc *wwn; - struct fip_fab_desc *fab; - struct fip_fka_desc *fka; - unsigned long t; - size_t rlen; - size_t dlen; - u32 desc_mask; - - memset(fcf, 0, sizeof(*fcf)); - fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA); - - fiph = (struct fip_header *)skb->data; - fcf->flags = ntohs(fiph->fip_flags); - - /* - * mask of required descriptors. validating each one clears its bit. - */ - desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | - BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA); - - rlen = ntohs(fiph->fip_dl_len) * 4; - if (rlen + sizeof(*fiph) > skb->len) - return -EINVAL; - - desc = (struct fip_desc *)(fiph + 1); - while (rlen > 0) { - dlen = desc->fip_dlen * FIP_BPW; - if (dlen < sizeof(*desc) || dlen > rlen) - return -EINVAL; - /* Drop Adv if there are duplicate critical descriptors */ - if ((desc->fip_dtype < 32) && - !(desc_mask & 1U << desc->fip_dtype)) { - LIBFCOE_FIP_DBG(fip, "Duplicate Critical " - "Descriptors in FIP adv\n"); - return -EINVAL; - } - switch (desc->fip_dtype) { - case FIP_DT_PRI: - if (dlen != sizeof(struct fip_pri_desc)) - goto len_err; - fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri; - desc_mask &= ~BIT(FIP_DT_PRI); - break; - case FIP_DT_MAC: - if (dlen != sizeof(struct fip_mac_desc)) - goto len_err; - memcpy(fcf->fcf_mac, - ((struct fip_mac_desc *)desc)->fd_mac, - ETH_ALEN); - memcpy(fcf->fcoe_mac, fcf->fcf_mac, ETH_ALEN); - if (!is_valid_ether_addr(fcf->fcf_mac)) { - LIBFCOE_FIP_DBG(fip, - "Invalid MAC addr %pM in FIP adv\n", - fcf->fcf_mac); - return -EINVAL; - } - desc_mask &= ~BIT(FIP_DT_MAC); - break; - case FIP_DT_NAME: - if (dlen != sizeof(struct fip_wwn_desc)) - goto len_err; - wwn = (struct fip_wwn_desc *)desc; - fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn); - desc_mask &= ~BIT(FIP_DT_NAME); - break; - case FIP_DT_FAB: - if (dlen != sizeof(struct fip_fab_desc)) - goto len_err; - fab = (struct fip_fab_desc *)desc; - fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn); - fcf->vfid = ntohs(fab->fd_vfid); - fcf->fc_map = ntoh24(fab->fd_map); - desc_mask &= ~BIT(FIP_DT_FAB); - break; - case FIP_DT_FKA: - if (dlen != sizeof(struct fip_fka_desc)) - goto len_err; - fka = (struct fip_fka_desc *)desc; - if (fka->fd_flags & FIP_FKA_ADV_D) - fcf->fd_flags = 1; - t = ntohl(fka->fd_fka_period); - if (t >= FCOE_CTLR_MIN_FKA) - fcf->fka_period = msecs_to_jiffies(t); - desc_mask &= ~BIT(FIP_DT_FKA); - break; - case FIP_DT_MAP_OUI: - case FIP_DT_FCOE_SIZE: - case FIP_DT_FLOGI: - case FIP_DT_FDISC: - case FIP_DT_LOGO: - case FIP_DT_ELP: - default: - LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " - "in FIP adv\n", desc->fip_dtype); - /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) - return -EINVAL; - break; - } - desc = (struct fip_desc *)((char *)desc + dlen); - rlen -= dlen; - } - if (!fcf->fc_map || (fcf->fc_map & 0x10000)) - return -EINVAL; - if (!fcf->switch_name) - return -EINVAL; - if (desc_mask) { - LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n", - desc_mask); - return -EINVAL; - } - return 0; - -len_err: - LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n", - desc->fip_dtype, dlen); - return -EINVAL; -} - -/** - * fcoe_ctlr_recv_adv() - Handle an incoming advertisement - * @fip: The FCoE controller receiving the advertisement - * @skb: The received FIP packet - */ -static void fcoe_ctlr_recv_adv(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - struct fcoe_fcf *fcf; - struct fcoe_fcf new; - struct fcoe_fcf *found; - unsigned long sol_tov = msecs_to_jiffies(FCOE_CTRL_SOL_TOV); - int first = 0; - int mtu_valid; - - if (fcoe_ctlr_parse_adv(fip, skb, &new)) - return; - - mutex_lock(&fip->ctlr_mutex); - first = list_empty(&fip->fcfs); - found = NULL; - list_for_each_entry(fcf, &fip->fcfs, list) { - if (fcf->switch_name == new.switch_name && - fcf->fabric_name == new.fabric_name && - fcf->fc_map == new.fc_map && - compare_ether_addr(fcf->fcf_mac, new.fcf_mac) == 0) { - found = fcf; - break; - } - } - if (!found) { - if (fip->fcf_count >= FCOE_CTLR_FCF_LIMIT) - goto out; - - fcf = kmalloc(sizeof(*fcf), GFP_ATOMIC); - if (!fcf) - goto out; - - fip->fcf_count++; - memcpy(fcf, &new, sizeof(new)); - list_add(&fcf->list, &fip->fcfs); - } else { - /* - * Update the FCF's keep-alive descriptor flags. - * Other flag changes from new advertisements are - * ignored after a solicited advertisement is - * received and the FCF is selectable (usable). - */ - fcf->fd_flags = new.fd_flags; - if (!fcoe_ctlr_fcf_usable(fcf)) - fcf->flags = new.flags; - - if (fcf == fip->sel_fcf && !fcf->fd_flags) { - fip->ctlr_ka_time -= fcf->fka_period; - fip->ctlr_ka_time += new.fka_period; - if (time_before(fip->ctlr_ka_time, fip->timer.expires)) - mod_timer(&fip->timer, fip->ctlr_ka_time); - } - fcf->fka_period = new.fka_period; - memcpy(fcf->fcf_mac, new.fcf_mac, ETH_ALEN); - } - mtu_valid = fcoe_ctlr_mtu_valid(fcf); - fcf->time = jiffies; - if (!found) - LIBFCOE_FIP_DBG(fip, "New FCF fab %16.16llx mac %pM\n", - fcf->fabric_name, fcf->fcf_mac); - - /* - * If this advertisement is not solicited and our max receive size - * hasn't been verified, send a solicited advertisement. - */ - if (!mtu_valid) - fcoe_ctlr_solicit(fip, fcf); - - /* - * If its been a while since we did a solicit, and this is - * the first advertisement we've received, do a multicast - * solicitation to gather as many advertisements as we can - * before selection occurs. - */ - if (first && time_after(jiffies, fip->sol_time + sol_tov)) - fcoe_ctlr_solicit(fip, NULL); - - /* - * Put this FCF at the head of the list for priority among equals. - * This helps in the case of an NPV switch which insists we use - * the FCF that answers multicast solicitations, not the others that - * are sending periodic multicast advertisements. - */ - if (mtu_valid) - list_move(&fcf->list, &fip->fcfs); - - /* - * If this is the first validated FCF, note the time and - * set a timer to trigger selection. - */ - if (mtu_valid && !fip->sel_fcf && fcoe_ctlr_fcf_usable(fcf)) { - fip->sel_time = jiffies + - msecs_to_jiffies(FCOE_CTLR_START_DELAY); - if (!timer_pending(&fip->timer) || - time_before(fip->sel_time, fip->timer.expires)) - mod_timer(&fip->timer, fip->sel_time); - } -out: - mutex_unlock(&fip->ctlr_mutex); -} - -/** - * fcoe_ctlr_recv_els() - Handle an incoming FIP encapsulated ELS frame - * @fip: The FCoE controller which received the packet - * @skb: The received FIP packet - */ -static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - struct fc_lport *lport = fip->lp; - struct fip_header *fiph; - struct fc_frame *fp = (struct fc_frame *)skb; - struct fc_frame_header *fh = NULL; - struct fip_desc *desc; - struct fip_encaps *els; - struct fcoe_dev_stats *stats; - struct fcoe_fcf *sel; - enum fip_desc_type els_dtype = 0; - u8 els_op; - u8 sub; - u8 granted_mac[ETH_ALEN] = { 0 }; - size_t els_len = 0; - size_t rlen; - size_t dlen; - u32 desc_mask = 0; - u32 desc_cnt = 0; - - fiph = (struct fip_header *)skb->data; - sub = fiph->fip_subcode; - if (sub != FIP_SC_REQ && sub != FIP_SC_REP) - goto drop; - - rlen = ntohs(fiph->fip_dl_len) * 4; - if (rlen + sizeof(*fiph) > skb->len) - goto drop; - - desc = (struct fip_desc *)(fiph + 1); - while (rlen > 0) { - desc_cnt++; - dlen = desc->fip_dlen * FIP_BPW; - if (dlen < sizeof(*desc) || dlen > rlen) - goto drop; - /* Drop ELS if there are duplicate critical descriptors */ - if (desc->fip_dtype < 32) { - if ((desc->fip_dtype != FIP_DT_MAC) && - (desc_mask & 1U << desc->fip_dtype)) { - LIBFCOE_FIP_DBG(fip, "Duplicate Critical " - "Descriptors in FIP ELS\n"); - goto drop; - } - desc_mask |= (1 << desc->fip_dtype); - } - switch (desc->fip_dtype) { - case FIP_DT_MAC: - sel = fip->sel_fcf; - if (desc_cnt == 1) { - LIBFCOE_FIP_DBG(fip, "FIP descriptors " - "received out of order\n"); - goto drop; - } - /* - * Some switch implementations send two MAC descriptors, - * with first MAC(granted_mac) being the FPMA, and the - * second one(fcoe_mac) is used as destination address - * for sending/receiving FCoE packets. FIP traffic is - * sent using fip_mac. For regular switches, both - * fip_mac and fcoe_mac would be the same. - */ - if (desc_cnt == 2) - memcpy(granted_mac, - ((struct fip_mac_desc *)desc)->fd_mac, - ETH_ALEN); - - if (dlen != sizeof(struct fip_mac_desc)) - goto len_err; - - if ((desc_cnt == 3) && (sel)) - memcpy(sel->fcoe_mac, - ((struct fip_mac_desc *)desc)->fd_mac, - ETH_ALEN); - break; - case FIP_DT_FLOGI: - case FIP_DT_FDISC: - case FIP_DT_LOGO: - case FIP_DT_ELP: - if (desc_cnt != 1) { - LIBFCOE_FIP_DBG(fip, "FIP descriptors " - "received out of order\n"); - goto drop; - } - if (fh) - goto drop; - if (dlen < sizeof(*els) + sizeof(*fh) + 1) - goto len_err; - els_len = dlen - sizeof(*els); - els = (struct fip_encaps *)desc; - fh = (struct fc_frame_header *)(els + 1); - els_dtype = desc->fip_dtype; - break; - default: - LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " - "in FIP adv\n", desc->fip_dtype); - /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) - goto drop; - if (desc_cnt <= 2) { - LIBFCOE_FIP_DBG(fip, "FIP descriptors " - "received out of order\n"); - goto drop; - } - break; - } - desc = (struct fip_desc *)((char *)desc + dlen); - rlen -= dlen; - } - - if (!fh) - goto drop; - els_op = *(u8 *)(fh + 1); - - if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) && - sub == FIP_SC_REP && fip->mode != FIP_MODE_VN2VN) { - if (els_op == ELS_LS_ACC) { - if (!is_valid_ether_addr(granted_mac)) { - LIBFCOE_FIP_DBG(fip, - "Invalid MAC address %pM in FIP ELS\n", - granted_mac); - goto drop; - } - memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN); - - if (fip->flogi_oxid == ntohs(fh->fh_ox_id)) { - fip->flogi_oxid = FC_XID_UNKNOWN; - if (els_dtype == FIP_DT_FLOGI) - fcoe_ctlr_announce(fip); - } - } else if (els_dtype == FIP_DT_FLOGI && - !fcoe_ctlr_flogi_retry(fip)) - goto drop; /* retrying FLOGI so drop reject */ - } - - if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) && - (!(1U << FIP_DT_MAC & desc_mask)))) { - LIBFCOE_FIP_DBG(fip, "Missing critical descriptors " - "in FIP ELS\n"); - goto drop; - } - - /* - * Convert skb into an fc_frame containing only the ELS. - */ - skb_pull(skb, (u8 *)fh - skb->data); - skb_trim(skb, els_len); - fp = (struct fc_frame *)skb; - fc_frame_init(fp); - fr_sof(fp) = FC_SOF_I3; - fr_eof(fp) = FC_EOF_T; - fr_dev(fp) = lport; - fr_encaps(fp) = els_dtype; - - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - stats->RxFrames++; - stats->RxWords += skb->len / FIP_BPW; - put_cpu(); - - fc_exch_recv(lport, fp); - return; - -len_err: - LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n", - desc->fip_dtype, dlen); -drop: - kfree_skb(skb); -} - -/** - * fcoe_ctlr_recv_els() - Handle an incoming link reset frame - * @fip: The FCoE controller that received the frame - * @fh: The received FIP header - * - * There may be multiple VN_Port descriptors. - * The overall length has already been checked. - */ -static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip, - struct fip_header *fh) -{ - struct fip_desc *desc; - struct fip_mac_desc *mp; - struct fip_wwn_desc *wp; - struct fip_vn_desc *vp; - size_t rlen; - size_t dlen; - struct fcoe_fcf *fcf = fip->sel_fcf; - struct fc_lport *lport = fip->lp; - struct fc_lport *vn_port = NULL; - u32 desc_mask; - int num_vlink_desc; - int reset_phys_port = 0; - struct fip_vn_desc **vlink_desc_arr = NULL; - - LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n"); - - if (!fcf || !lport->port_id) - return; - - /* - * mask of required descriptors. Validating each one clears its bit. - */ - desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME); - - rlen = ntohs(fh->fip_dl_len) * FIP_BPW; - desc = (struct fip_desc *)(fh + 1); - - /* - * Actually need to subtract 'sizeof(*mp) - sizeof(*wp)' from 'rlen' - * before determining max Vx_Port descriptor but a buggy FCF could have - * omited either or both MAC Address and Name Identifier descriptors - */ - num_vlink_desc = rlen / sizeof(*vp); - if (num_vlink_desc) - vlink_desc_arr = kmalloc(sizeof(vp) * num_vlink_desc, - GFP_ATOMIC); - if (!vlink_desc_arr) - return; - num_vlink_desc = 0; - - while (rlen >= sizeof(*desc)) { - dlen = desc->fip_dlen * FIP_BPW; - if (dlen > rlen) - goto err; - /* Drop CVL if there are duplicate critical descriptors */ - if ((desc->fip_dtype < 32) && - (desc->fip_dtype != FIP_DT_VN_ID) && - !(desc_mask & 1U << desc->fip_dtype)) { - LIBFCOE_FIP_DBG(fip, "Duplicate Critical " - "Descriptors in FIP CVL\n"); - goto err; - } - switch (desc->fip_dtype) { - case FIP_DT_MAC: - mp = (struct fip_mac_desc *)desc; - if (dlen < sizeof(*mp)) - goto err; - if (compare_ether_addr(mp->fd_mac, fcf->fcf_mac)) - goto err; - desc_mask &= ~BIT(FIP_DT_MAC); - break; - case FIP_DT_NAME: - wp = (struct fip_wwn_desc *)desc; - if (dlen < sizeof(*wp)) - goto err; - if (get_unaligned_be64(&wp->fd_wwn) != fcf->switch_name) - goto err; - desc_mask &= ~BIT(FIP_DT_NAME); - break; - case FIP_DT_VN_ID: - vp = (struct fip_vn_desc *)desc; - if (dlen < sizeof(*vp)) - goto err; - vlink_desc_arr[num_vlink_desc++] = vp; - vn_port = fc_vport_id_lookup(lport, - ntoh24(vp->fd_fc_id)); - if (vn_port && (vn_port == lport)) { - mutex_lock(&fip->ctlr_mutex); - per_cpu_ptr(lport->dev_stats, - get_cpu())->VLinkFailureCount++; - put_cpu(); - fcoe_ctlr_reset(fip); - mutex_unlock(&fip->ctlr_mutex); - } - break; - default: - /* standard says ignore unknown descriptors >= 128 */ - if (desc->fip_dtype < FIP_DT_VENDOR_BASE) - goto err; - break; - } - desc = (struct fip_desc *)((char *)desc + dlen); - rlen -= dlen; - } - - /* - * reset only if all required descriptors were present and valid. - */ - if (desc_mask) - LIBFCOE_FIP_DBG(fip, "missing descriptors mask %x\n", - desc_mask); - else if (!num_vlink_desc) { - LIBFCOE_FIP_DBG(fip, "CVL: no Vx_Port descriptor found\n"); - /* - * No Vx_Port description. Clear all NPIV ports, - * followed by physical port - */ - mutex_lock(&fip->ctlr_mutex); - per_cpu_ptr(lport->dev_stats, - get_cpu())->VLinkFailureCount++; - put_cpu(); - fcoe_ctlr_reset(fip); - mutex_unlock(&fip->ctlr_mutex); - - mutex_lock(&lport->lp_mutex); - list_for_each_entry(vn_port, &lport->vports, list) - fc_lport_reset(vn_port); - mutex_unlock(&lport->lp_mutex); - - fc_lport_reset(fip->lp); - fcoe_ctlr_solicit(fip, NULL); - } else { - int i; - - LIBFCOE_FIP_DBG(fip, "performing Clear Virtual Link\n"); - for (i = 0; i < num_vlink_desc; i++) { - vp = vlink_desc_arr[i]; - vn_port = fc_vport_id_lookup(lport, - ntoh24(vp->fd_fc_id)); - if (!vn_port) - continue; - - /* - * 'port_id' is already validated, check MAC address and - * wwpn - */ - if (compare_ether_addr(fip->get_src_addr(vn_port), - vp->fd_mac) != 0 || - get_unaligned_be64(&vp->fd_wwpn) != - vn_port->wwpn) - continue; - - if (vn_port == lport) - /* - * Physical port, defer processing till all - * listed NPIV ports are cleared - */ - reset_phys_port = 1; - else /* NPIV port */ - fc_lport_reset(vn_port); - } - - if (reset_phys_port) { - fc_lport_reset(fip->lp); - fcoe_ctlr_solicit(fip, NULL); - } - } - -err: - kfree(vlink_desc_arr); -} - -/** - * fcoe_ctlr_recv() - Receive a FIP packet - * @fip: The FCoE controller that received the packet - * @skb: The received FIP packet - * - * This may be called from either NET_RX_SOFTIRQ or IRQ. - */ -void fcoe_ctlr_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - skb_queue_tail(&fip->fip_recv_list, skb); - schedule_work(&fip->recv_work); -} -EXPORT_SYMBOL(fcoe_ctlr_recv); - -/** - * fcoe_ctlr_recv_handler() - Receive a FIP frame - * @fip: The FCoE controller that received the frame - * @skb: The received FIP frame - * - * Returns non-zero if the frame is dropped. - */ -static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - struct fip_header *fiph; - struct ethhdr *eh; - enum fip_state state; - u16 op; - u8 sub; - - if (skb_linearize(skb)) - goto drop; - if (skb->len < sizeof(*fiph)) - goto drop; - eh = eth_hdr(skb); - if (fip->mode == FIP_MODE_VN2VN) { - if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && - compare_ether_addr(eh->h_dest, fcoe_all_vn2vn) && - compare_ether_addr(eh->h_dest, fcoe_all_p2p)) - goto drop; - } else if (compare_ether_addr(eh->h_dest, fip->ctl_src_addr) && - compare_ether_addr(eh->h_dest, fcoe_all_enode)) - goto drop; - fiph = (struct fip_header *)skb->data; - op = ntohs(fiph->fip_op); - sub = fiph->fip_subcode; - - if (FIP_VER_DECAPS(fiph->fip_ver) != FIP_VER) - goto drop; - if (ntohs(fiph->fip_dl_len) * FIP_BPW + sizeof(*fiph) > skb->len) - goto drop; - - mutex_lock(&fip->ctlr_mutex); - state = fip->state; - if (state == FIP_ST_AUTO) { - fip->map_dest = 0; - fcoe_ctlr_set_state(fip, FIP_ST_ENABLED); - state = FIP_ST_ENABLED; - LIBFCOE_FIP_DBG(fip, "Using FIP mode\n"); - } - mutex_unlock(&fip->ctlr_mutex); - - if (fip->mode == FIP_MODE_VN2VN && op == FIP_OP_VN2VN) - return fcoe_ctlr_vn_recv(fip, skb); - - if (state != FIP_ST_ENABLED && state != FIP_ST_VNMP_UP && - state != FIP_ST_VNMP_CLAIM) - goto drop; - - if (op == FIP_OP_LS) { - fcoe_ctlr_recv_els(fip, skb); /* consumes skb */ - return 0; - } - - if (state != FIP_ST_ENABLED) - goto drop; - - if (op == FIP_OP_DISC && sub == FIP_SC_ADV) - fcoe_ctlr_recv_adv(fip, skb); - else if (op == FIP_OP_CTRL && sub == FIP_SC_CLR_VLINK) - fcoe_ctlr_recv_clr_vlink(fip, fiph); - kfree_skb(skb); - return 0; -drop: - kfree_skb(skb); - return -1; -} - -/** - * fcoe_ctlr_select() - Select the best FCF (if possible) - * @fip: The FCoE controller - * - * Returns the selected FCF, or NULL if none are usable. - * - * If there are conflicting advertisements, no FCF can be chosen. - * - * If there is already a selected FCF, this will choose a better one or - * an equivalent one that hasn't already been sent a FLOGI. - * - * Called with lock held. - */ -static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *fcf; - struct fcoe_fcf *best = fip->sel_fcf; - struct fcoe_fcf *first; - - first = list_first_entry(&fip->fcfs, struct fcoe_fcf, list); - - list_for_each_entry(fcf, &fip->fcfs, list) { - LIBFCOE_FIP_DBG(fip, "consider FCF fab %16.16llx " - "VFID %d mac %pM map %x val %d " - "sent %u pri %u\n", - fcf->fabric_name, fcf->vfid, fcf->fcf_mac, - fcf->fc_map, fcoe_ctlr_mtu_valid(fcf), - fcf->flogi_sent, fcf->pri); - if (fcf->fabric_name != first->fabric_name || - fcf->vfid != first->vfid || - fcf->fc_map != first->fc_map) { - LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, " - "or FC-MAP\n"); - return NULL; - } - if (fcf->flogi_sent) - continue; - if (!fcoe_ctlr_fcf_usable(fcf)) { - LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx " - "map %x %svalid %savailable\n", - fcf->fabric_name, fcf->fc_map, - (fcf->flags & FIP_FL_SOL) ? "" : "in", - (fcf->flags & FIP_FL_AVAIL) ? - "" : "un"); - continue; - } - if (!best || fcf->pri < best->pri || best->flogi_sent) - best = fcf; - } - fip->sel_fcf = best; - if (best) { - LIBFCOE_FIP_DBG(fip, "using FCF mac %pM\n", best->fcf_mac); - fip->port_ka_time = jiffies + - msecs_to_jiffies(FIP_VN_KA_PERIOD); - fip->ctlr_ka_time = jiffies + best->fka_period; - if (time_before(fip->ctlr_ka_time, fip->timer.expires)) - mod_timer(&fip->timer, fip->ctlr_ka_time); - } - return best; -} - -/** - * fcoe_ctlr_flogi_send_locked() - send FIP-encapsulated FLOGI to current FCF - * @fip: The FCoE controller - * - * Returns non-zero error if it could not be sent. - * - * Called with ctlr_mutex and ctlr_lock held. - * Caller must verify that fip->sel_fcf is not NULL. - */ -static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip) -{ - struct sk_buff *skb; - struct sk_buff *skb_orig; - struct fc_frame_header *fh; - int error; - - skb_orig = fip->flogi_req; - if (!skb_orig) - return -EINVAL; - - /* - * Clone and send the FLOGI request. If clone fails, use original. - */ - skb = skb_clone(skb_orig, GFP_ATOMIC); - if (!skb) { - skb = skb_orig; - fip->flogi_req = NULL; - } - fh = (struct fc_frame_header *)skb->data; - error = fcoe_ctlr_encaps(fip, fip->lp, FIP_DT_FLOGI, skb, - ntoh24(fh->fh_d_id)); - if (error) { - kfree_skb(skb); - return error; - } - fip->send(fip, skb); - fip->sel_fcf->flogi_sent = 1; - return 0; -} - -/** - * fcoe_ctlr_flogi_retry() - resend FLOGI request to a new FCF if possible - * @fip: The FCoE controller - * - * Returns non-zero error code if there's no FLOGI request to retry or - * no alternate FCF available. - */ -static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *fcf; - int error; - - mutex_lock(&fip->ctlr_mutex); - spin_lock_bh(&fip->ctlr_lock); - LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n"); - fcf = fcoe_ctlr_select(fip); - if (!fcf || fcf->flogi_sent) { - kfree_skb(fip->flogi_req); - fip->flogi_req = NULL; - error = -ENOENT; - } else { - fcoe_ctlr_solicit(fip, NULL); - error = fcoe_ctlr_flogi_send_locked(fip); - } - spin_unlock_bh(&fip->ctlr_lock); - mutex_unlock(&fip->ctlr_mutex); - return error; -} - - -/** - * fcoe_ctlr_flogi_send() - Handle sending of FIP FLOGI. - * @fip: The FCoE controller that timed out - * - * Done here because fcoe_ctlr_els_send() can't get mutex. - * - * Called with ctlr_mutex held. The caller must not hold ctlr_lock. - */ -static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip) -{ - struct fcoe_fcf *fcf; - - spin_lock_bh(&fip->ctlr_lock); - fcf = fip->sel_fcf; - if (!fcf || !fip->flogi_req_send) - goto unlock; - - LIBFCOE_FIP_DBG(fip, "sending FLOGI\n"); - - /* - * If this FLOGI is being sent due to a timeout retry - * to the same FCF as before, select a different FCF if possible. - */ - if (fcf->flogi_sent) { - LIBFCOE_FIP_DBG(fip, "sending FLOGI - reselect\n"); - fcf = fcoe_ctlr_select(fip); - if (!fcf || fcf->flogi_sent) { - LIBFCOE_FIP_DBG(fip, "sending FLOGI - clearing\n"); - list_for_each_entry(fcf, &fip->fcfs, list) - fcf->flogi_sent = 0; - fcf = fcoe_ctlr_select(fip); - } - } - if (fcf) { - fcoe_ctlr_flogi_send_locked(fip); - fip->flogi_req_send = 0; - } else /* XXX */ - LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n"); -unlock: - spin_unlock_bh(&fip->ctlr_lock); -} - -/** - * fcoe_ctlr_timeout() - FIP timeout handler - * @arg: The FCoE controller that timed out - */ -static void fcoe_ctlr_timeout(unsigned long arg) -{ - struct fcoe_ctlr *fip = (struct fcoe_ctlr *)arg; - - schedule_work(&fip->timer_work); -} - -/** - * fcoe_ctlr_timer_work() - Worker thread function for timer work - * @work: Handle to a FCoE controller - * - * Ages FCFs. Triggers FCF selection if possible. - * Sends keep-alives and resets. - */ -static void fcoe_ctlr_timer_work(struct work_struct *work) -{ - struct fcoe_ctlr *fip; - struct fc_lport *vport; - u8 *mac; - u8 reset = 0; - u8 send_ctlr_ka = 0; - u8 send_port_ka = 0; - struct fcoe_fcf *sel; - struct fcoe_fcf *fcf; - unsigned long next_timer; - - fip = container_of(work, struct fcoe_ctlr, timer_work); - if (fip->mode == FIP_MODE_VN2VN) - return fcoe_ctlr_vn_timeout(fip); - mutex_lock(&fip->ctlr_mutex); - if (fip->state == FIP_ST_DISABLED) { - mutex_unlock(&fip->ctlr_mutex); - return; - } - - fcf = fip->sel_fcf; - next_timer = fcoe_ctlr_age_fcfs(fip); - - sel = fip->sel_fcf; - if (!sel && fip->sel_time) { - if (time_after_eq(jiffies, fip->sel_time)) { - sel = fcoe_ctlr_select(fip); - fip->sel_time = 0; - } else if (time_after(next_timer, fip->sel_time)) - next_timer = fip->sel_time; - } - - if (sel && fip->flogi_req_send) - fcoe_ctlr_flogi_send(fip); - else if (!sel && fcf) - reset = 1; - - if (sel && !sel->fd_flags) { - if (time_after_eq(jiffies, fip->ctlr_ka_time)) { - fip->ctlr_ka_time = jiffies + sel->fka_period; - send_ctlr_ka = 1; - } - if (time_after(next_timer, fip->ctlr_ka_time)) - next_timer = fip->ctlr_ka_time; - - if (time_after_eq(jiffies, fip->port_ka_time)) { - fip->port_ka_time = jiffies + - msecs_to_jiffies(FIP_VN_KA_PERIOD); - send_port_ka = 1; - } - if (time_after(next_timer, fip->port_ka_time)) - next_timer = fip->port_ka_time; - } - if (!list_empty(&fip->fcfs)) - mod_timer(&fip->timer, next_timer); - mutex_unlock(&fip->ctlr_mutex); - - if (reset) { - fc_lport_reset(fip->lp); - /* restart things with a solicitation */ - fcoe_ctlr_solicit(fip, NULL); - } - - if (send_ctlr_ka) - fcoe_ctlr_send_keep_alive(fip, NULL, 0, fip->ctl_src_addr); - - if (send_port_ka) { - mutex_lock(&fip->lp->lp_mutex); - mac = fip->get_src_addr(fip->lp); - fcoe_ctlr_send_keep_alive(fip, fip->lp, 1, mac); - list_for_each_entry(vport, &fip->lp->vports, list) { - mac = fip->get_src_addr(vport); - fcoe_ctlr_send_keep_alive(fip, vport, 1, mac); - } - mutex_unlock(&fip->lp->lp_mutex); - } -} - -/** - * fcoe_ctlr_recv_work() - Worker thread function for receiving FIP frames - * @recv_work: Handle to a FCoE controller - */ -static void fcoe_ctlr_recv_work(struct work_struct *recv_work) -{ - struct fcoe_ctlr *fip; - struct sk_buff *skb; - - fip = container_of(recv_work, struct fcoe_ctlr, recv_work); - while ((skb = skb_dequeue(&fip->fip_recv_list))) - fcoe_ctlr_recv_handler(fip, skb); -} - -/** - * fcoe_ctlr_recv_flogi() - Snoop pre-FIP receipt of FLOGI response - * @fip: The FCoE controller - * @fp: The FC frame to snoop - * - * Snoop potential response to FLOGI or even incoming FLOGI. - * - * The caller has checked that we are waiting for login as indicated - * by fip->flogi_oxid != FC_XID_UNKNOWN. - * - * The caller is responsible for freeing the frame. - * Fill in the granted_mac address. - * - * Return non-zero if the frame should not be delivered to libfc. - */ -int fcoe_ctlr_recv_flogi(struct fcoe_ctlr *fip, struct fc_lport *lport, - struct fc_frame *fp) -{ - struct fc_frame_header *fh; - u8 op; - u8 *sa; - - sa = eth_hdr(&fp->skb)->h_source; - fh = fc_frame_header_get(fp); - if (fh->fh_type != FC_TYPE_ELS) - return 0; - - op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC && fh->fh_r_ctl == FC_RCTL_ELS_REP && - fip->flogi_oxid == ntohs(fh->fh_ox_id)) { - - mutex_lock(&fip->ctlr_mutex); - if (fip->state != FIP_ST_AUTO && fip->state != FIP_ST_NON_FIP) { - mutex_unlock(&fip->ctlr_mutex); - return -EINVAL; - } - fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP); - LIBFCOE_FIP_DBG(fip, - "received FLOGI LS_ACC using non-FIP mode\n"); - - /* - * FLOGI accepted. - * If the src mac addr is FC_OUI-based, then we mark the - * address_mode flag to use FC_OUI-based Ethernet DA. - * Otherwise we use the FCoE gateway addr - */ - if (!compare_ether_addr(sa, (u8[6])FC_FCOE_FLOGI_MAC)) { - fcoe_ctlr_map_dest(fip); - } else { - memcpy(fip->dest_addr, sa, ETH_ALEN); - fip->map_dest = 0; - } - fip->flogi_oxid = FC_XID_UNKNOWN; - mutex_unlock(&fip->ctlr_mutex); - fc_fcoe_set_mac(fr_cb(fp)->granted_mac, fh->fh_d_id); - } else if (op == ELS_FLOGI && fh->fh_r_ctl == FC_RCTL_ELS_REQ && sa) { - /* - * Save source MAC for point-to-point responses. - */ - mutex_lock(&fip->ctlr_mutex); - if (fip->state == FIP_ST_AUTO || fip->state == FIP_ST_NON_FIP) { - memcpy(fip->dest_addr, sa, ETH_ALEN); - fip->map_dest = 0; - if (fip->state == FIP_ST_AUTO) - LIBFCOE_FIP_DBG(fip, "received non-FIP FLOGI. " - "Setting non-FIP mode\n"); - fcoe_ctlr_set_state(fip, FIP_ST_NON_FIP); - } - mutex_unlock(&fip->ctlr_mutex); - } - return 0; -} -EXPORT_SYMBOL(fcoe_ctlr_recv_flogi); - -/** - * fcoe_wwn_from_mac() - Converts a 48-bit IEEE MAC address to a 64-bit FC WWN - * @mac: The MAC address to convert - * @scheme: The scheme to use when converting - * @port: The port indicator for converting - * - * Returns: u64 fc world wide name - */ -u64 fcoe_wwn_from_mac(unsigned char mac[MAX_ADDR_LEN], - unsigned int scheme, unsigned int port) -{ - u64 wwn; - u64 host_mac; - - /* The MAC is in NO, so flip only the low 48 bits */ - host_mac = ((u64) mac[0] << 40) | - ((u64) mac[1] << 32) | - ((u64) mac[2] << 24) | - ((u64) mac[3] << 16) | - ((u64) mac[4] << 8) | - (u64) mac[5]; - - WARN_ON(host_mac >= (1ULL << 48)); - wwn = host_mac | ((u64) scheme << 60); - switch (scheme) { - case 1: - WARN_ON(port != 0); - break; - case 2: - WARN_ON(port >= 0xfff); - wwn |= (u64) port << 48; - break; - default: - WARN_ON(1); - break; - } - - return wwn; -} -EXPORT_SYMBOL_GPL(fcoe_wwn_from_mac); - -/** - * fcoe_ctlr_rport() - return the fcoe_rport for a given fc_rport_priv - * @rdata: libfc remote port - */ -static inline struct fcoe_rport *fcoe_ctlr_rport(struct fc_rport_priv *rdata) -{ - return (struct fcoe_rport *)(rdata + 1); -} - -/** - * fcoe_ctlr_vn_send() - Send a FIP VN2VN Probe Request or Reply. - * @fip: The FCoE controller - * @sub: sub-opcode for probe request, reply, or advertisement. - * @dest: The destination Ethernet MAC address - * @min_len: minimum size of the Ethernet payload to be sent - */ -static void fcoe_ctlr_vn_send(struct fcoe_ctlr *fip, - enum fip_vn2vn_subcode sub, - const u8 *dest, size_t min_len) -{ - struct sk_buff *skb; - struct fip_frame { - struct ethhdr eth; - struct fip_header fip; - struct fip_mac_desc mac; - struct fip_wwn_desc wwnn; - struct fip_vn_desc vn; - } __packed * frame; - struct fip_fc4_feat *ff; - struct fip_size_desc *size; - u32 fcp_feat; - size_t len; - size_t dlen; - - len = sizeof(*frame); - dlen = 0; - if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) { - dlen = sizeof(struct fip_fc4_feat) + - sizeof(struct fip_size_desc); - len += dlen; - } - dlen += sizeof(frame->mac) + sizeof(frame->wwnn) + sizeof(frame->vn); - len = max(len, min_len + sizeof(struct ethhdr)); - - skb = dev_alloc_skb(len); - if (!skb) - return; - - frame = (struct fip_frame *)skb->data; - memset(frame, 0, len); - memcpy(frame->eth.h_dest, dest, ETH_ALEN); - memcpy(frame->eth.h_source, fip->ctl_src_addr, ETH_ALEN); - frame->eth.h_proto = htons(ETH_P_FIP); - - frame->fip.fip_ver = FIP_VER_ENCAPS(FIP_VER); - frame->fip.fip_op = htons(FIP_OP_VN2VN); - frame->fip.fip_subcode = sub; - frame->fip.fip_dl_len = htons(dlen / FIP_BPW); - - frame->mac.fd_desc.fip_dtype = FIP_DT_MAC; - frame->mac.fd_desc.fip_dlen = sizeof(frame->mac) / FIP_BPW; - memcpy(frame->mac.fd_mac, fip->ctl_src_addr, ETH_ALEN); - - frame->wwnn.fd_desc.fip_dtype = FIP_DT_NAME; - frame->wwnn.fd_desc.fip_dlen = sizeof(frame->wwnn) / FIP_BPW; - put_unaligned_be64(fip->lp->wwnn, &frame->wwnn.fd_wwn); - - frame->vn.fd_desc.fip_dtype = FIP_DT_VN_ID; - frame->vn.fd_desc.fip_dlen = sizeof(frame->vn) / FIP_BPW; - hton24(frame->vn.fd_mac, FIP_VN_FC_MAP); - hton24(frame->vn.fd_mac + 3, fip->port_id); - hton24(frame->vn.fd_fc_id, fip->port_id); - put_unaligned_be64(fip->lp->wwpn, &frame->vn.fd_wwpn); - - /* - * For claims, add FC-4 features. - * TBD: Add interface to get fc-4 types and features from libfc. - */ - if (sub == FIP_SC_VN_CLAIM_NOTIFY || sub == FIP_SC_VN_CLAIM_REP) { - ff = (struct fip_fc4_feat *)(frame + 1); - ff->fd_desc.fip_dtype = FIP_DT_FC4F; - ff->fd_desc.fip_dlen = sizeof(*ff) / FIP_BPW; - ff->fd_fts = fip->lp->fcts; - - fcp_feat = 0; - if (fip->lp->service_params & FCP_SPPF_INIT_FCN) - fcp_feat |= FCP_FEAT_INIT; - if (fip->lp->service_params & FCP_SPPF_TARG_FCN) - fcp_feat |= FCP_FEAT_TARG; - fcp_feat <<= (FC_TYPE_FCP * 4) % 32; - ff->fd_ff.fd_feat[FC_TYPE_FCP * 4 / 32] = htonl(fcp_feat); - - size = (struct fip_size_desc *)(ff + 1); - size->fd_desc.fip_dtype = FIP_DT_FCOE_SIZE; - size->fd_desc.fip_dlen = sizeof(*size) / FIP_BPW; - size->fd_size = htons(fcoe_ctlr_fcoe_size(fip)); - } - - skb_put(skb, len); - skb->protocol = htons(ETH_P_FIP); - skb->priority = fip->priority; - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - - fip->send(fip, skb); -} - -/** - * fcoe_ctlr_vn_rport_callback - Event handler for rport events. - * @lport: The lport which is receiving the event - * @rdata: remote port private data - * @event: The event that occurred - * - * Locking Note: The rport lock must not be held when calling this function. - */ -static void fcoe_ctlr_vn_rport_callback(struct fc_lport *lport, - struct fc_rport_priv *rdata, - enum fc_rport_event event) -{ - struct fcoe_ctlr *fip = lport->disc.priv; - struct fcoe_rport *frport = fcoe_ctlr_rport(rdata); - - LIBFCOE_FIP_DBG(fip, "vn_rport_callback %x event %d\n", - rdata->ids.port_id, event); - - mutex_lock(&fip->ctlr_mutex); - switch (event) { - case RPORT_EV_READY: - frport->login_count = 0; - break; - case RPORT_EV_LOGO: - case RPORT_EV_FAILED: - case RPORT_EV_STOP: - frport->login_count++; - if (frport->login_count > FCOE_CTLR_VN2VN_LOGIN_LIMIT) { - LIBFCOE_FIP_DBG(fip, - "rport FLOGI limited port_id %6.6x\n", - rdata->ids.port_id); - lport->tt.rport_logoff(rdata); - } - break; - default: - break; - } - mutex_unlock(&fip->ctlr_mutex); -} - -static struct fc_rport_operations fcoe_ctlr_vn_rport_ops = { - .event_callback = fcoe_ctlr_vn_rport_callback, -}; - -/** - * fcoe_ctlr_disc_stop_locked() - stop discovery in VN2VN mode - * @fip: The FCoE controller - * - * Called with ctlr_mutex held. - */ -static void fcoe_ctlr_disc_stop_locked(struct fc_lport *lport) -{ - mutex_lock(&lport->disc.disc_mutex); - lport->disc.disc_callback = NULL; - mutex_unlock(&lport->disc.disc_mutex); -} - -/** - * fcoe_ctlr_disc_stop() - stop discovery in VN2VN mode - * @fip: The FCoE controller - * - * Called through the local port template for discovery. - * Called without the ctlr_mutex held. - */ -static void fcoe_ctlr_disc_stop(struct fc_lport *lport) -{ - struct fcoe_ctlr *fip = lport->disc.priv; - - mutex_lock(&fip->ctlr_mutex); - fcoe_ctlr_disc_stop_locked(lport); - mutex_unlock(&fip->ctlr_mutex); -} - -/** - * fcoe_ctlr_disc_stop_final() - stop discovery for shutdown in VN2VN mode - * @fip: The FCoE controller - * - * Called through the local port template for discovery. - * Called without the ctlr_mutex held. - */ -static void fcoe_ctlr_disc_stop_final(struct fc_lport *lport) -{ - fcoe_ctlr_disc_stop(lport); - lport->tt.rport_flush_queue(); - synchronize_rcu(); -} - -/** - * fcoe_ctlr_vn_restart() - VN2VN probe restart with new port_id - * @fip: The FCoE controller - * - * Called with fcoe_ctlr lock held. - */ -static void fcoe_ctlr_vn_restart(struct fcoe_ctlr *fip) -{ - unsigned long wait; - u32 port_id; - - fcoe_ctlr_disc_stop_locked(fip->lp); - - /* - * Get proposed port ID. - * If this is the first try after link up, use any previous port_id. - * If there was none, use the low bits of the port_name. - * On subsequent tries, get the next random one. - * Don't use reserved IDs, use another non-zero value, just as random. - */ - port_id = fip->port_id; - if (fip->probe_tries) - port_id = prandom32(&fip->rnd_state) & 0xffff; - else if (!port_id) - port_id = fip->lp->wwpn & 0xffff; - if (!port_id || port_id == 0xffff) - port_id = 1; - fip->port_id = port_id; - - if (fip->probe_tries < FIP_VN_RLIM_COUNT) { - fip->probe_tries++; - wait = random32() % FIP_VN_PROBE_WAIT; - } else - wait = FIP_VN_RLIM_INT; - mod_timer(&fip->timer, jiffies + msecs_to_jiffies(wait)); - fcoe_ctlr_set_state(fip, FIP_ST_VNMP_START); -} - -/** - * fcoe_ctlr_vn_start() - Start in VN2VN mode - * @fip: The FCoE controller - * - * Called with fcoe_ctlr lock held. - */ -static void fcoe_ctlr_vn_start(struct fcoe_ctlr *fip) -{ - fip->probe_tries = 0; - prandom32_seed(&fip->rnd_state, fip->lp->wwpn); - fcoe_ctlr_vn_restart(fip); -} - -/** - * fcoe_ctlr_vn_parse - parse probe request or response - * @fip: The FCoE controller - * @skb: incoming packet - * @rdata: buffer for resulting parsed VN entry plus fcoe_rport - * - * Returns non-zero error number on error. - * Does not consume the packet. - */ -static int fcoe_ctlr_vn_parse(struct fcoe_ctlr *fip, - struct sk_buff *skb, - struct fc_rport_priv *rdata) -{ - struct fip_header *fiph; - struct fip_desc *desc = NULL; - struct fip_mac_desc *macd = NULL; - struct fip_wwn_desc *wwn = NULL; - struct fip_vn_desc *vn = NULL; - struct fip_size_desc *size = NULL; - struct fcoe_rport *frport; - size_t rlen; - size_t dlen; - u32 desc_mask = 0; - u32 dtype; - u8 sub; - - memset(rdata, 0, sizeof(*rdata) + sizeof(*frport)); - frport = fcoe_ctlr_rport(rdata); - - fiph = (struct fip_header *)skb->data; - frport->flags = ntohs(fiph->fip_flags); - - sub = fiph->fip_subcode; - switch (sub) { - case FIP_SC_VN_PROBE_REQ: - case FIP_SC_VN_PROBE_REP: - case FIP_SC_VN_BEACON: - desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | - BIT(FIP_DT_VN_ID); - break; - case FIP_SC_VN_CLAIM_NOTIFY: - case FIP_SC_VN_CLAIM_REP: - desc_mask = BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) | - BIT(FIP_DT_VN_ID) | BIT(FIP_DT_FC4F) | - BIT(FIP_DT_FCOE_SIZE); - break; - default: - LIBFCOE_FIP_DBG(fip, "vn_parse unknown subcode %u\n", sub); - return -EINVAL; - } - - rlen = ntohs(fiph->fip_dl_len) * 4; - if (rlen + sizeof(*fiph) > skb->len) - return -EINVAL; - - desc = (struct fip_desc *)(fiph + 1); - while (rlen > 0) { - dlen = desc->fip_dlen * FIP_BPW; - if (dlen < sizeof(*desc) || dlen > rlen) - return -EINVAL; - - dtype = desc->fip_dtype; - if (dtype < 32) { - if (!(desc_mask & BIT(dtype))) { - LIBFCOE_FIP_DBG(fip, - "unexpected or duplicated desc " - "desc type %u in " - "FIP VN2VN subtype %u\n", - dtype, sub); - return -EINVAL; - } - desc_mask &= ~BIT(dtype); - } - - switch (dtype) { - case FIP_DT_MAC: - if (dlen != sizeof(struct fip_mac_desc)) - goto len_err; - macd = (struct fip_mac_desc *)desc; - if (!is_valid_ether_addr(macd->fd_mac)) { - LIBFCOE_FIP_DBG(fip, - "Invalid MAC addr %pM in FIP VN2VN\n", - macd->fd_mac); - return -EINVAL; - } - memcpy(frport->enode_mac, macd->fd_mac, ETH_ALEN); - break; - case FIP_DT_NAME: - if (dlen != sizeof(struct fip_wwn_desc)) - goto len_err; - wwn = (struct fip_wwn_desc *)desc; - rdata->ids.node_name = get_unaligned_be64(&wwn->fd_wwn); - break; - case FIP_DT_VN_ID: - if (dlen != sizeof(struct fip_vn_desc)) - goto len_err; - vn = (struct fip_vn_desc *)desc; - memcpy(frport->vn_mac, vn->fd_mac, ETH_ALEN); - rdata->ids.port_id = ntoh24(vn->fd_fc_id); - rdata->ids.port_name = get_unaligned_be64(&vn->fd_wwpn); - break; - case FIP_DT_FC4F: - if (dlen != sizeof(struct fip_fc4_feat)) - goto len_err; - break; - case FIP_DT_FCOE_SIZE: - if (dlen != sizeof(struct fip_size_desc)) - goto len_err; - size = (struct fip_size_desc *)desc; - frport->fcoe_len = ntohs(size->fd_size); - break; - default: - LIBFCOE_FIP_DBG(fip, "unexpected descriptor type %x " - "in FIP probe\n", dtype); - /* standard says ignore unknown descriptors >= 128 */ - if (dtype < FIP_DT_VENDOR_BASE) - return -EINVAL; - break; - } - desc = (struct fip_desc *)((char *)desc + dlen); - rlen -= dlen; - } - return 0; - -len_err: - LIBFCOE_FIP_DBG(fip, "FIP length error in descriptor type %x len %zu\n", - dtype, dlen); - return -EINVAL; -} - -/** - * fcoe_ctlr_vn_send_claim() - send multicast FIP VN2VN Claim Notification. - * @fip: The FCoE controller - * - * Called with ctlr_mutex held. - */ -static void fcoe_ctlr_vn_send_claim(struct fcoe_ctlr *fip) -{ - fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_NOTIFY, fcoe_all_vn2vn, 0); - fip->sol_time = jiffies; -} - -/** - * fcoe_ctlr_vn_probe_req() - handle incoming VN2VN probe request. - * @fip: The FCoE controller - * @rdata: parsed remote port with frport from the probe request - * - * Called with ctlr_mutex held. - */ -static void fcoe_ctlr_vn_probe_req(struct fcoe_ctlr *fip, - struct fc_rport_priv *rdata) -{ - struct fcoe_rport *frport = fcoe_ctlr_rport(rdata); - - if (rdata->ids.port_id != fip->port_id) - return; - - switch (fip->state) { - case FIP_ST_VNMP_CLAIM: - case FIP_ST_VNMP_UP: - fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP, - frport->enode_mac, 0); - break; - case FIP_ST_VNMP_PROBE1: - case FIP_ST_VNMP_PROBE2: - /* - * Decide whether to reply to the Probe. - * Our selected address is never a "recorded" one, so - * only reply if our WWPN is greater and the - * Probe's REC bit is not set. - * If we don't reply, we will change our address. - */ - if (fip->lp->wwpn > rdata->ids.port_name && - !(frport->flags & FIP_FL_REC_OR_P2P)) { - fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REP, - frport->enode_mac, 0); - break; - } - /* fall through */ - case FIP_ST_VNMP_START: - fcoe_ctlr_vn_restart(fip); - break; - default: - break; - } -} - -/** - * fcoe_ctlr_vn_probe_reply() - handle incoming VN2VN probe reply. - * @fip: The FCoE controller - * @rdata: parsed remote port with frport from the probe request - * - * Called with ctlr_mutex held. - */ -static void fcoe_ctlr_vn_probe_reply(struct fcoe_ctlr *fip, - struct fc_rport_priv *rdata) -{ - if (rdata->ids.port_id != fip->port_id) - return; - switch (fip->state) { - case FIP_ST_VNMP_START: - case FIP_ST_VNMP_PROBE1: - case FIP_ST_VNMP_PROBE2: - case FIP_ST_VNMP_CLAIM: - fcoe_ctlr_vn_restart(fip); - break; - case FIP_ST_VNMP_UP: - fcoe_ctlr_vn_send_claim(fip); - break; - default: - break; - } -} - -/** - * fcoe_ctlr_vn_add() - Add a VN2VN entry to the list, based on a claim reply. - * @fip: The FCoE controller - * @new: newly-parsed remote port with frport as a template for new rdata - * - * Called with ctlr_mutex held. - */ -static void fcoe_ctlr_vn_add(struct fcoe_ctlr *fip, struct fc_rport_priv *new) -{ - struct fc_lport *lport = fip->lp; - struct fc_rport_priv *rdata; - struct fc_rport_identifiers *ids; - struct fcoe_rport *frport; - u32 port_id; - - port_id = new->ids.port_id; - if (port_id == fip->port_id) - return; - - mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_create(lport, port_id); - if (!rdata) { - mutex_unlock(&lport->disc.disc_mutex); - return; - } - - rdata->ops = &fcoe_ctlr_vn_rport_ops; - rdata->disc_id = lport->disc.disc_id; - - ids = &rdata->ids; - if ((ids->port_name != -1 && ids->port_name != new->ids.port_name) || - (ids->node_name != -1 && ids->node_name != new->ids.node_name)) - lport->tt.rport_logoff(rdata); - ids->port_name = new->ids.port_name; - ids->node_name = new->ids.node_name; - mutex_unlock(&lport->disc.disc_mutex); - - frport = fcoe_ctlr_rport(rdata); - LIBFCOE_FIP_DBG(fip, "vn_add rport %6.6x %s\n", - port_id, frport->fcoe_len ? "old" : "new"); - *frport = *fcoe_ctlr_rport(new); - frport->time = 0; -} - -/** - * fcoe_ctlr_vn_lookup() - Find VN remote port's MAC address - * @fip: The FCoE controller - * @port_id: The port_id of the remote VN_node - * @mac: buffer which will hold the VN_NODE destination MAC address, if found. - * - * Returns non-zero error if no remote port found. - */ -static int fcoe_ctlr_vn_lookup(struct fcoe_ctlr *fip, u32 port_id, u8 *mac) -{ - struct fc_lport *lport = fip->lp; - struct fc_rport_priv *rdata; - struct fcoe_rport *frport; - int ret = -1; - - rcu_read_lock(); - rdata = lport->tt.rport_lookup(lport, port_id); - if (rdata) { - frport = fcoe_ctlr_rport(rdata); - memcpy(mac, frport->enode_mac, ETH_ALEN); - ret = 0; - } - rcu_read_unlock(); - return ret; -} - -/** - * fcoe_ctlr_vn_claim_notify() - handle received FIP VN2VN Claim Notification - * @fip: The FCoE controller - * @new: newly-parsed remote port with frport as a template for new rdata - * - * Called with ctlr_mutex held. - */ -static void fcoe_ctlr_vn_claim_notify(struct fcoe_ctlr *fip, - struct fc_rport_priv *new) -{ - struct fcoe_rport *frport = fcoe_ctlr_rport(new); - - if (frport->flags & FIP_FL_REC_OR_P2P) { - fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); - return; - } - switch (fip->state) { - case FIP_ST_VNMP_START: - case FIP_ST_VNMP_PROBE1: - case FIP_ST_VNMP_PROBE2: - if (new->ids.port_id == fip->port_id) - fcoe_ctlr_vn_restart(fip); - break; - case FIP_ST_VNMP_CLAIM: - case FIP_ST_VNMP_UP: - if (new->ids.port_id == fip->port_id) { - if (new->ids.port_name > fip->lp->wwpn) { - fcoe_ctlr_vn_restart(fip); - break; - } - fcoe_ctlr_vn_send_claim(fip); - break; - } - fcoe_ctlr_vn_send(fip, FIP_SC_VN_CLAIM_REP, frport->enode_mac, - min((u32)frport->fcoe_len, - fcoe_ctlr_fcoe_size(fip))); - fcoe_ctlr_vn_add(fip, new); - break; - default: - break; - } -} - -/** - * fcoe_ctlr_vn_claim_resp() - handle received Claim Response - * @fip: The FCoE controller that received the frame - * @new: newly-parsed remote port with frport from the Claim Response - * - * Called with ctlr_mutex held. - */ -static void fcoe_ctlr_vn_claim_resp(struct fcoe_ctlr *fip, - struct fc_rport_priv *new) -{ - LIBFCOE_FIP_DBG(fip, "claim resp from from rport %x - state %s\n", - new->ids.port_id, fcoe_ctlr_state(fip->state)); - if (fip->state == FIP_ST_VNMP_UP || fip->state == FIP_ST_VNMP_CLAIM) - fcoe_ctlr_vn_add(fip, new); -} - -/** - * fcoe_ctlr_vn_beacon() - handle received beacon. - * @fip: The FCoE controller that received the frame - * @new: newly-parsed remote port with frport from the Beacon - * - * Called with ctlr_mutex held. - */ -static void fcoe_ctlr_vn_beacon(struct fcoe_ctlr *fip, - struct fc_rport_priv *new) -{ - struct fc_lport *lport = fip->lp; - struct fc_rport_priv *rdata; - struct fcoe_rport *frport; - - frport = fcoe_ctlr_rport(new); - if (frport->flags & FIP_FL_REC_OR_P2P) { - fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); - return; - } - mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_lookup(lport, new->ids.port_id); - if (rdata) - kref_get(&rdata->kref); - mutex_unlock(&lport->disc.disc_mutex); - if (rdata) { - if (rdata->ids.node_name == new->ids.node_name && - rdata->ids.port_name == new->ids.port_name) { - frport = fcoe_ctlr_rport(rdata); - if (!frport->time && fip->state == FIP_ST_VNMP_UP) - lport->tt.rport_login(rdata); - frport->time = jiffies; - } - kref_put(&rdata->kref, lport->tt.rport_destroy); - return; - } - if (fip->state != FIP_ST_VNMP_UP) - return; - - /* - * Beacon from a new neighbor. - * Send a claim notify if one hasn't been sent recently. - * Don't add the neighbor yet. - */ - LIBFCOE_FIP_DBG(fip, "beacon from new rport %x. sending claim notify\n", - new->ids.port_id); - if (time_after(jiffies, - fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT))) - fcoe_ctlr_vn_send_claim(fip); -} - -/** - * fcoe_ctlr_vn_age() - Check for VN_ports without recent beacons - * @fip: The FCoE controller - * - * Called with ctlr_mutex held. - * Called only in state FIP_ST_VNMP_UP. - * Returns the soonest time for next age-out or a time far in the future. - */ -static unsigned long fcoe_ctlr_vn_age(struct fcoe_ctlr *fip) -{ - struct fc_lport *lport = fip->lp; - struct fc_rport_priv *rdata; - struct fcoe_rport *frport; - unsigned long next_time; - unsigned long deadline; - - next_time = jiffies + msecs_to_jiffies(FIP_VN_BEACON_INT * 10); - mutex_lock(&lport->disc.disc_mutex); - list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) { - frport = fcoe_ctlr_rport(rdata); - if (!frport->time) - continue; - deadline = frport->time + - msecs_to_jiffies(FIP_VN_BEACON_INT * 25 / 10); - if (time_after_eq(jiffies, deadline)) { - frport->time = 0; - LIBFCOE_FIP_DBG(fip, - "port %16.16llx fc_id %6.6x beacon expired\n", - rdata->ids.port_name, rdata->ids.port_id); - lport->tt.rport_logoff(rdata); - } else if (time_before(deadline, next_time)) - next_time = deadline; - } - mutex_unlock(&lport->disc.disc_mutex); - return next_time; -} - -/** - * fcoe_ctlr_vn_recv() - Receive a FIP frame - * @fip: The FCoE controller that received the frame - * @skb: The received FIP frame - * - * Returns non-zero if the frame is dropped. - * Always consumes the frame. - */ -static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - struct fip_header *fiph; - enum fip_vn2vn_subcode sub; - struct { - struct fc_rport_priv rdata; - struct fcoe_rport frport; - } buf; - int rc; - - fiph = (struct fip_header *)skb->data; - sub = fiph->fip_subcode; - - rc = fcoe_ctlr_vn_parse(fip, skb, &buf.rdata); - if (rc) { - LIBFCOE_FIP_DBG(fip, "vn_recv vn_parse error %d\n", rc); - goto drop; - } - - mutex_lock(&fip->ctlr_mutex); - switch (sub) { - case FIP_SC_VN_PROBE_REQ: - fcoe_ctlr_vn_probe_req(fip, &buf.rdata); - break; - case FIP_SC_VN_PROBE_REP: - fcoe_ctlr_vn_probe_reply(fip, &buf.rdata); - break; - case FIP_SC_VN_CLAIM_NOTIFY: - fcoe_ctlr_vn_claim_notify(fip, &buf.rdata); - break; - case FIP_SC_VN_CLAIM_REP: - fcoe_ctlr_vn_claim_resp(fip, &buf.rdata); - break; - case FIP_SC_VN_BEACON: - fcoe_ctlr_vn_beacon(fip, &buf.rdata); - break; - default: - LIBFCOE_FIP_DBG(fip, "vn_recv unknown subcode %d\n", sub); - rc = -1; - break; - } - mutex_unlock(&fip->ctlr_mutex); -drop: - kfree_skb(skb); - return rc; -} - -/** - * fcoe_ctlr_disc_recv - discovery receive handler for VN2VN mode. - * @lport: The local port - * @fp: The received frame - * - * This should never be called since we don't see RSCNs or other - * fabric-generated ELSes. - */ -static void fcoe_ctlr_disc_recv(struct fc_lport *lport, struct fc_frame *fp) -{ - struct fc_seq_els_data rjt_data; - - rjt_data.reason = ELS_RJT_UNSUP; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); -} - -/** - * fcoe_ctlr_disc_recv - start discovery for VN2VN mode. - * @fip: The FCoE controller - * - * This sets a flag indicating that remote ports should be created - * and started for the peers we discover. We use the disc_callback - * pointer as that flag. Peers already discovered are created here. - * - * The lport lock is held during this call. The callback must be done - * later, without holding either the lport or discovery locks. - * The fcoe_ctlr lock may also be held during this call. - */ -static void fcoe_ctlr_disc_start(void (*callback)(struct fc_lport *, - enum fc_disc_event), - struct fc_lport *lport) -{ - struct fc_disc *disc = &lport->disc; - struct fcoe_ctlr *fip = disc->priv; - - mutex_lock(&disc->disc_mutex); - disc->disc_callback = callback; - disc->disc_id = (disc->disc_id + 2) | 1; - disc->pending = 1; - schedule_work(&fip->timer_work); - mutex_unlock(&disc->disc_mutex); -} - -/** - * fcoe_ctlr_vn_disc() - report FIP VN_port discovery results after claim state. - * @fip: The FCoE controller - * - * Starts the FLOGI and PLOGI login process to each discovered rport for which - * we've received at least one beacon. - * Performs the discovery complete callback. - */ -static void fcoe_ctlr_vn_disc(struct fcoe_ctlr *fip) -{ - struct fc_lport *lport = fip->lp; - struct fc_disc *disc = &lport->disc; - struct fc_rport_priv *rdata; - struct fcoe_rport *frport; - void (*callback)(struct fc_lport *, enum fc_disc_event); - - mutex_lock(&disc->disc_mutex); - callback = disc->pending ? disc->disc_callback : NULL; - disc->pending = 0; - list_for_each_entry_rcu(rdata, &disc->rports, peers) { - frport = fcoe_ctlr_rport(rdata); - if (frport->time) - lport->tt.rport_login(rdata); - } - mutex_unlock(&disc->disc_mutex); - if (callback) - callback(lport, DISC_EV_SUCCESS); -} - -/** - * fcoe_ctlr_vn_timeout - timer work function for VN2VN mode. - * @fip: The FCoE controller - */ -static void fcoe_ctlr_vn_timeout(struct fcoe_ctlr *fip) -{ - unsigned long next_time; - u8 mac[ETH_ALEN]; - u32 new_port_id = 0; - - mutex_lock(&fip->ctlr_mutex); - switch (fip->state) { - case FIP_ST_VNMP_START: - fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE1); - fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); - next_time = jiffies + msecs_to_jiffies(FIP_VN_PROBE_WAIT); - break; - case FIP_ST_VNMP_PROBE1: - fcoe_ctlr_set_state(fip, FIP_ST_VNMP_PROBE2); - fcoe_ctlr_vn_send(fip, FIP_SC_VN_PROBE_REQ, fcoe_all_vn2vn, 0); - next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); - break; - case FIP_ST_VNMP_PROBE2: - fcoe_ctlr_set_state(fip, FIP_ST_VNMP_CLAIM); - new_port_id = fip->port_id; - hton24(mac, FIP_VN_FC_MAP); - hton24(mac + 3, new_port_id); - fcoe_ctlr_map_dest(fip); - fip->update_mac(fip->lp, mac); - fcoe_ctlr_vn_send_claim(fip); - next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); - break; - case FIP_ST_VNMP_CLAIM: - /* - * This may be invoked either by starting discovery so don't - * go to the next state unless it's been long enough. - */ - next_time = fip->sol_time + msecs_to_jiffies(FIP_VN_ANN_WAIT); - if (time_after_eq(jiffies, next_time)) { - fcoe_ctlr_set_state(fip, FIP_ST_VNMP_UP); - fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON, - fcoe_all_vn2vn, 0); - next_time = jiffies + msecs_to_jiffies(FIP_VN_ANN_WAIT); - fip->port_ka_time = next_time; - } - fcoe_ctlr_vn_disc(fip); - break; - case FIP_ST_VNMP_UP: - next_time = fcoe_ctlr_vn_age(fip); - if (time_after_eq(jiffies, fip->port_ka_time)) { - fcoe_ctlr_vn_send(fip, FIP_SC_VN_BEACON, - fcoe_all_vn2vn, 0); - fip->port_ka_time = jiffies + - msecs_to_jiffies(FIP_VN_BEACON_INT + - (random32() % FIP_VN_BEACON_FUZZ)); - } - if (time_before(fip->port_ka_time, next_time)) - next_time = fip->port_ka_time; - break; - case FIP_ST_LINK_WAIT: - goto unlock; - default: - WARN(1, "unexpected state %d\n", fip->state); - goto unlock; - } - mod_timer(&fip->timer, next_time); -unlock: - mutex_unlock(&fip->ctlr_mutex); - - /* If port ID is new, notify local port after dropping ctlr_mutex */ - if (new_port_id) - fc_lport_set_local_id(fip->lp, new_port_id); -} - -/** - * fcoe_libfc_config() - Sets up libfc related properties for local port - * @lp: The local port to configure libfc for - * @fip: The FCoE controller in use by the local port - * @tt: The libfc function template - * @init_fcp: If non-zero, the FCP portion of libfc should be initialized - * - * Returns : 0 for success - */ -int fcoe_libfc_config(struct fc_lport *lport, struct fcoe_ctlr *fip, - const struct libfc_function_template *tt, int init_fcp) -{ - /* Set the function pointers set by the LLDD */ - memcpy(&lport->tt, tt, sizeof(*tt)); - if (init_fcp && fc_fcp_init(lport)) - return -ENOMEM; - fc_exch_init(lport); - fc_elsct_init(lport); - fc_lport_init(lport); - if (fip->mode == FIP_MODE_VN2VN) - lport->rport_priv_size = sizeof(struct fcoe_rport); - fc_rport_init(lport); - if (fip->mode == FIP_MODE_VN2VN) { - lport->point_to_multipoint = 1; - lport->tt.disc_recv_req = fcoe_ctlr_disc_recv; - lport->tt.disc_start = fcoe_ctlr_disc_start; - lport->tt.disc_stop = fcoe_ctlr_disc_stop; - lport->tt.disc_stop_final = fcoe_ctlr_disc_stop_final; - mutex_init(&lport->disc.disc_mutex); - INIT_LIST_HEAD(&lport->disc.rports); - lport->disc.priv = fip; - } else { - fc_disc_init(lport); - } - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_libfc_config); diff --git a/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_transport.c b/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_transport.c deleted file mode 100644 index 710e149d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fcoe/fcoe_transport.c +++ /dev/null @@ -1,831 +0,0 @@ -/* - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "libfcoe.h" - -MODULE_AUTHOR("Open-FCoE.org"); -MODULE_DESCRIPTION("FIP discovery protocol and FCoE transport for FCoE HBAs"); -MODULE_LICENSE("GPL v2"); - -static int fcoe_transport_create(const char *, struct kernel_param *); -static int fcoe_transport_destroy(const char *, struct kernel_param *); -static int fcoe_transport_show(char *buffer, const struct kernel_param *kp); -static struct fcoe_transport *fcoe_transport_lookup(struct net_device *device); -static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *device); -static int fcoe_transport_enable(const char *, struct kernel_param *); -static int fcoe_transport_disable(const char *, struct kernel_param *); -static int libfcoe_device_notification(struct notifier_block *notifier, - ulong event, void *ptr); - -static LIST_HEAD(fcoe_transports); -static DEFINE_MUTEX(ft_mutex); -static LIST_HEAD(fcoe_netdevs); -static DEFINE_MUTEX(fn_mutex); - -unsigned int libfcoe_debug_logging; -module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); - -module_param_call(show, NULL, fcoe_transport_show, NULL, S_IRUSR); -__MODULE_PARM_TYPE(show, "string"); -MODULE_PARM_DESC(show, " Show attached FCoE transports"); - -module_param_call(create, fcoe_transport_create, NULL, - (void *)FIP_MODE_FABRIC, S_IWUSR); -__MODULE_PARM_TYPE(create, "string"); -MODULE_PARM_DESC(create, " Creates fcoe instance on a ethernet interface"); - -module_param_call(create_vn2vn, fcoe_transport_create, NULL, - (void *)FIP_MODE_VN2VN, S_IWUSR); -__MODULE_PARM_TYPE(create_vn2vn, "string"); -MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance " - "on an Ethernet interface"); - -module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR); -__MODULE_PARM_TYPE(destroy, "string"); -MODULE_PARM_DESC(destroy, " Destroys fcoe instance on a ethernet interface"); - -module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR); -__MODULE_PARM_TYPE(enable, "string"); -MODULE_PARM_DESC(enable, " Enables fcoe on a ethernet interface."); - -module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR); -__MODULE_PARM_TYPE(disable, "string"); -MODULE_PARM_DESC(disable, " Disables fcoe on a ethernet interface."); - -/* notification function for packets from net device */ -static struct notifier_block libfcoe_notifier = { - .notifier_call = libfcoe_device_notification, -}; - -void __fcoe_get_lesb(struct fc_lport *lport, - struct fc_els_lesb *fc_lesb, - struct net_device *netdev) -{ - unsigned int cpu; - u32 lfc, vlfc, mdac; - struct fcoe_dev_stats *devst; - struct fcoe_fc_els_lesb *lesb; - struct rtnl_link_stats64 temp; - - lfc = 0; - vlfc = 0; - mdac = 0; - lesb = (struct fcoe_fc_els_lesb *)fc_lesb; - memset(lesb, 0, sizeof(*lesb)); - for_each_possible_cpu(cpu) { - devst = per_cpu_ptr(lport->dev_stats, cpu); - lfc += devst->LinkFailureCount; - vlfc += devst->VLinkFailureCount; - mdac += devst->MissDiscAdvCount; - } - lesb->lesb_link_fail = htonl(lfc); - lesb->lesb_vlink_fail = htonl(vlfc); - lesb->lesb_miss_fka = htonl(mdac); - lesb->lesb_fcs_error = - htonl(dev_get_stats(netdev, &temp)->rx_crc_errors); -} -EXPORT_SYMBOL_GPL(__fcoe_get_lesb); - -void fcoe_wwn_to_str(u64 wwn, char *buf, int len) -{ - u8 wwpn[8]; - - u64_to_wwn(wwn, wwpn); - snprintf(buf, len, "%02x%02x%02x%02x%02x%02x%02x%02x", - wwpn[0], wwpn[1], wwpn[2], wwpn[3], - wwpn[4], wwpn[5], wwpn[6], wwpn[7]); -} -EXPORT_SYMBOL_GPL(fcoe_wwn_to_str); - -/** - * fcoe_validate_vport_create() - Validate a vport before creating it - * @vport: NPIV port to be created - * - * This routine is meant to add validation for a vport before creating it - * via fcoe_vport_create(). - * Current validations are: - * - WWPN supplied is unique for given lport - */ -int fcoe_validate_vport_create(struct fc_vport *vport) -{ - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_lport *n_port = shost_priv(shost); - struct fc_lport *vn_port; - int rc = 0; - char buf[32]; - - mutex_lock(&n_port->lp_mutex); - - fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); - /* Check if the wwpn is not same as that of the lport */ - if (!memcmp(&n_port->wwpn, &vport->port_name, sizeof(u64))) { - LIBFCOE_TRANSPORT_DBG("vport WWPN 0x%s is same as that of the " - "base port WWPN\n", buf); - rc = -EINVAL; - goto out; - } - - /* Check if there is any existing vport with same wwpn */ - list_for_each_entry(vn_port, &n_port->vports, list) { - if (!memcmp(&vn_port->wwpn, &vport->port_name, sizeof(u64))) { - LIBFCOE_TRANSPORT_DBG("vport with given WWPN 0x%s " - "already exists\n", buf); - rc = -EINVAL; - break; - } - } -out: - mutex_unlock(&n_port->lp_mutex); - return rc; -} -EXPORT_SYMBOL_GPL(fcoe_validate_vport_create); - -/** - * fcoe_get_wwn() - Get the world wide name from LLD if it supports it - * @netdev: the associated net device - * @wwn: the output WWN - * @type: the type of WWN (WWPN or WWNN) - * - * Returns: 0 for success - */ -int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) -{ - const struct net_device_ops *ops = netdev->netdev_ops; - - if (ops->ndo_fcoe_get_wwn) - return ops->ndo_fcoe_get_wwn(netdev, wwn, type); - return -EINVAL; -} -EXPORT_SYMBOL_GPL(fcoe_get_wwn); - -/** - * fcoe_fc_crc() - Calculates the CRC for a given frame - * @fp: The frame to be checksumed - * - * This uses crc32() routine to calculate the CRC for a frame - * - * Return: The 32 bit CRC value - */ -u32 fcoe_fc_crc(struct fc_frame *fp) -{ - struct sk_buff *skb = fp_skb(fp); - struct skb_frag_struct *frag; - unsigned char *data; - unsigned long off, len, clen; - u32 crc; - unsigned i; - - crc = crc32(~0, skb->data, skb_headlen(skb)); - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - frag = &skb_shinfo(skb)->frags[i]; - off = frag->page_offset; - len = skb_frag_size(frag); - while (len > 0) { - clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK)); - data = kmap_atomic( - skb_frag_page(frag) + (off >> PAGE_SHIFT)); - crc = crc32(crc, data + (off & ~PAGE_MASK), clen); - kunmap_atomic(data); - off += clen; - len -= clen; - } - } - return crc; -} -EXPORT_SYMBOL_GPL(fcoe_fc_crc); - -/** - * fcoe_start_io() - Start FCoE I/O - * @skb: The packet to be transmitted - * - * This routine is called from the net device to start transmitting - * FCoE packets. - * - * Returns: 0 for success - */ -int fcoe_start_io(struct sk_buff *skb) -{ - struct sk_buff *nskb; - int rc; - - nskb = skb_clone(skb, GFP_ATOMIC); - if (!nskb) - return -ENOMEM; - rc = dev_queue_xmit(nskb); - if (rc != 0) - return rc; - kfree_skb(skb); - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_start_io); - - -/** - * fcoe_clean_pending_queue() - Dequeue a skb and free it - * @lport: The local port to dequeue a skb on - */ -void fcoe_clean_pending_queue(struct fc_lport *lport) -{ - struct fcoe_port *port = lport_priv(lport); - struct sk_buff *skb; - - spin_lock_bh(&port->fcoe_pending_queue.lock); - while ((skb = __skb_dequeue(&port->fcoe_pending_queue)) != NULL) { - spin_unlock_bh(&port->fcoe_pending_queue.lock); - kfree_skb(skb); - spin_lock_bh(&port->fcoe_pending_queue.lock); - } - spin_unlock_bh(&port->fcoe_pending_queue.lock); -} -EXPORT_SYMBOL_GPL(fcoe_clean_pending_queue); - -/** - * fcoe_check_wait_queue() - Attempt to clear the transmit backlog - * @lport: The local port whose backlog is to be cleared - * - * This empties the wait_queue, dequeues the head of the wait_queue queue - * and calls fcoe_start_io() for each packet. If all skb have been - * transmitted it returns the qlen. If an error occurs it restores - * wait_queue (to try again later) and returns -1. - * - * The wait_queue is used when the skb transmit fails. The failed skb - * will go in the wait_queue which will be emptied by the timer function or - * by the next skb transmit. - */ -void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb) -{ - struct fcoe_port *port = lport_priv(lport); - int rc; - - spin_lock_bh(&port->fcoe_pending_queue.lock); - - if (skb) - __skb_queue_tail(&port->fcoe_pending_queue, skb); - - if (port->fcoe_pending_queue_active) - goto out; - port->fcoe_pending_queue_active = 1; - - while (port->fcoe_pending_queue.qlen) { - /* keep qlen > 0 until fcoe_start_io succeeds */ - port->fcoe_pending_queue.qlen++; - skb = __skb_dequeue(&port->fcoe_pending_queue); - - spin_unlock_bh(&port->fcoe_pending_queue.lock); - rc = fcoe_start_io(skb); - spin_lock_bh(&port->fcoe_pending_queue.lock); - - if (rc) { - __skb_queue_head(&port->fcoe_pending_queue, skb); - /* undo temporary increment above */ - port->fcoe_pending_queue.qlen--; - break; - } - /* undo temporary increment above */ - port->fcoe_pending_queue.qlen--; - } - - if (port->fcoe_pending_queue.qlen < port->min_queue_depth) - lport->qfull = 0; - if (port->fcoe_pending_queue.qlen && !timer_pending(&port->timer)) - mod_timer(&port->timer, jiffies + 2); - port->fcoe_pending_queue_active = 0; -out: - if (port->fcoe_pending_queue.qlen > port->max_queue_depth) - lport->qfull = 1; - spin_unlock_bh(&port->fcoe_pending_queue.lock); -} -EXPORT_SYMBOL_GPL(fcoe_check_wait_queue); - -/** - * fcoe_queue_timer() - The fcoe queue timer - * @lport: The local port - * - * Calls fcoe_check_wait_queue on timeout - */ -void fcoe_queue_timer(ulong lport) -{ - fcoe_check_wait_queue((struct fc_lport *)lport, NULL); -} -EXPORT_SYMBOL_GPL(fcoe_queue_timer); - -/** - * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC - * @skb: The packet to be transmitted - * @tlen: The total length of the trailer - * @fps: The fcoe context - * - * This routine allocates a page for frame trailers. The page is re-used if - * there is enough room left on it for the current trailer. If there isn't - * enough buffer left a new page is allocated for the trailer. Reference to - * the page from this function as well as the skbs using the page fragments - * ensure that the page is freed at the appropriate time. - * - * Returns: 0 for success - */ -int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, - struct fcoe_percpu_s *fps) -{ - struct page *page; - - page = fps->crc_eof_page; - if (!page) { - page = alloc_page(GFP_ATOMIC); - if (!page) - return -ENOMEM; - - fps->crc_eof_page = page; - fps->crc_eof_offset = 0; - } - - get_page(page); - skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, page, - fps->crc_eof_offset, tlen); - skb->len += tlen; - skb->data_len += tlen; - skb->truesize += tlen; - fps->crc_eof_offset += sizeof(struct fcoe_crc_eof); - - if (fps->crc_eof_offset >= PAGE_SIZE) { - fps->crc_eof_page = NULL; - fps->crc_eof_offset = 0; - put_page(page); - } - - return 0; -} -EXPORT_SYMBOL_GPL(fcoe_get_paged_crc_eof); - -/** - * fcoe_transport_lookup - find an fcoe transport that matches a netdev - * @netdev: The netdev to look for from all attached transports - * - * Returns : ptr to the fcoe transport that supports this netdev or NULL - * if not found. - * - * The ft_mutex should be held when this is called - */ -static struct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev) -{ - struct fcoe_transport *ft = NULL; - - list_for_each_entry(ft, &fcoe_transports, list) - if (ft->match && ft->match(netdev)) - return ft; - return NULL; -} - -/** - * fcoe_transport_attach - Attaches an FCoE transport - * @ft: The fcoe transport to be attached - * - * Returns : 0 for success - */ -int fcoe_transport_attach(struct fcoe_transport *ft) -{ - int rc = 0; - - mutex_lock(&ft_mutex); - if (ft->attached) { - LIBFCOE_TRANSPORT_DBG("transport %s already attached\n", - ft->name); - rc = -EEXIST; - goto out_attach; - } - - /* Add default transport to the tail */ - if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT)) - list_add(&ft->list, &fcoe_transports); - else - list_add_tail(&ft->list, &fcoe_transports); - - ft->attached = true; - LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name); - -out_attach: - mutex_unlock(&ft_mutex); - return rc; -} -EXPORT_SYMBOL(fcoe_transport_attach); - -/** - * fcoe_transport_detach - Detaches an FCoE transport - * @ft: The fcoe transport to be attached - * - * Returns : 0 for success - */ -int fcoe_transport_detach(struct fcoe_transport *ft) -{ - int rc = 0; - struct fcoe_netdev_mapping *nm = NULL, *tmp; - - mutex_lock(&ft_mutex); - if (!ft->attached) { - LIBFCOE_TRANSPORT_DBG("transport %s already detached\n", - ft->name); - rc = -ENODEV; - goto out_attach; - } - - /* remove netdev mapping for this transport as it is going away */ - mutex_lock(&fn_mutex); - list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { - if (nm->ft == ft) { - LIBFCOE_TRANSPORT_DBG("transport %s going away, " - "remove its netdev mapping for %s\n", - ft->name, nm->netdev->name); - list_del(&nm->list); - kfree(nm); - } - } - mutex_unlock(&fn_mutex); - - list_del(&ft->list); - ft->attached = false; - LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name); - -out_attach: - mutex_unlock(&ft_mutex); - return rc; - -} -EXPORT_SYMBOL(fcoe_transport_detach); - -static int fcoe_transport_show(char *buffer, const struct kernel_param *kp) -{ - int i, j; - struct fcoe_transport *ft = NULL; - - i = j = sprintf(buffer, "Attached FCoE transports:"); - mutex_lock(&ft_mutex); - list_for_each_entry(ft, &fcoe_transports, list) { - if (i >= PAGE_SIZE - IFNAMSIZ) - break; - i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name); - } - mutex_unlock(&ft_mutex); - if (i == j) - i += snprintf(&buffer[i], IFNAMSIZ, "none"); - return i; -} - -static int __init fcoe_transport_init(void) -{ - register_netdevice_notifier(&libfcoe_notifier); - return 0; -} - -static int __exit fcoe_transport_exit(void) -{ - struct fcoe_transport *ft; - - unregister_netdevice_notifier(&libfcoe_notifier); - mutex_lock(&ft_mutex); - list_for_each_entry(ft, &fcoe_transports, list) - printk(KERN_ERR "FCoE transport %s is still attached!\n", - ft->name); - mutex_unlock(&ft_mutex); - return 0; -} - - -static int fcoe_add_netdev_mapping(struct net_device *netdev, - struct fcoe_transport *ft) -{ - struct fcoe_netdev_mapping *nm; - - nm = kmalloc(sizeof(*nm), GFP_KERNEL); - if (!nm) { - printk(KERN_ERR "Unable to allocate netdev_mapping"); - return -ENOMEM; - } - - nm->netdev = netdev; - nm->ft = ft; - - mutex_lock(&fn_mutex); - list_add(&nm->list, &fcoe_netdevs); - mutex_unlock(&fn_mutex); - return 0; -} - - -static void fcoe_del_netdev_mapping(struct net_device *netdev) -{ - struct fcoe_netdev_mapping *nm = NULL, *tmp; - - mutex_lock(&fn_mutex); - list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { - if (nm->netdev == netdev) { - list_del(&nm->list); - kfree(nm); - mutex_unlock(&fn_mutex); - return; - } - } - mutex_unlock(&fn_mutex); -} - - -/** - * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which - * it was created - * - * Returns : ptr to the fcoe transport that supports this netdev or NULL - * if not found. - * - * The ft_mutex should be held when this is called - */ -static struct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev) -{ - struct fcoe_transport *ft = NULL; - struct fcoe_netdev_mapping *nm; - - mutex_lock(&fn_mutex); - list_for_each_entry(nm, &fcoe_netdevs, list) { - if (netdev == nm->netdev) { - ft = nm->ft; - mutex_unlock(&fn_mutex); - return ft; - } - } - - mutex_unlock(&fn_mutex); - return NULL; -} - -/** - * fcoe_if_to_netdev() - Parse a name buffer to get a net device - * @buffer: The name of the net device - * - * Returns: NULL or a ptr to net_device - */ -static struct net_device *fcoe_if_to_netdev(const char *buffer) -{ - char *cp; - char ifname[IFNAMSIZ + 2]; - - if (buffer) { - strlcpy(ifname, buffer, IFNAMSIZ); - cp = ifname + strlen(ifname); - while (--cp >= ifname && *cp == '\n') - *cp = '\0'; - return dev_get_by_name(&init_net, ifname); - } - return NULL; -} - -/** - * libfcoe_device_notification() - Handler for net device events - * @notifier: The context of the notification - * @event: The type of event - * @ptr: The net device that the event was on - * - * This function is called by the Ethernet driver in case of link change event. - * - * Returns: 0 for success - */ -static int libfcoe_device_notification(struct notifier_block *notifier, - ulong event, void *ptr) -{ - struct net_device *netdev = ptr; - - switch (event) { - case NETDEV_UNREGISTER: - LIBFCOE_TRANSPORT_DBG("NETDEV_UNREGISTER %s\n", - netdev->name); - fcoe_del_netdev_mapping(netdev); - break; - } - return NOTIFY_OK; -} - - -/** - * fcoe_transport_create() - Create a fcoe interface - * @buffer: The name of the Ethernet interface to create on - * @kp: The associated kernel param - * - * Called from sysfs. This holds the ft_mutex while calling the - * registered fcoe transport's create function. - * - * Returns: 0 for success - */ -static int fcoe_transport_create(const char *buffer, struct kernel_param *kp) -{ - int rc = -ENODEV; - struct net_device *netdev = NULL; - struct fcoe_transport *ft = NULL; - enum fip_state fip_mode = (enum fip_state)(long)kp->arg; - - mutex_lock(&ft_mutex); - - netdev = fcoe_if_to_netdev(buffer); - if (!netdev) { - LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buffer); - goto out_nodev; - } - - ft = fcoe_netdev_map_lookup(netdev); - if (ft) { - LIBFCOE_TRANSPORT_DBG("transport %s already has existing " - "FCoE instance on %s.\n", - ft->name, netdev->name); - rc = -EEXIST; - goto out_putdev; - } - - ft = fcoe_transport_lookup(netdev); - if (!ft) { - LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", - netdev->name); - goto out_putdev; - } - - rc = fcoe_add_netdev_mapping(netdev, ft); - if (rc) { - LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping " - "for FCoE transport %s for %s.\n", - ft->name, netdev->name); - goto out_putdev; - } - - /* pass to transport create */ - rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV; - if (rc) - fcoe_del_netdev_mapping(netdev); - - LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n", - ft->name, (rc) ? "failed" : "succeeded", - netdev->name); - -out_putdev: - dev_put(netdev); -out_nodev: - mutex_unlock(&ft_mutex); - return rc; -} - -/** - * fcoe_transport_destroy() - Destroy a FCoE interface - * @buffer: The name of the Ethernet interface to be destroyed - * @kp: The associated kernel parameter - * - * Called from sysfs. This holds the ft_mutex while calling the - * registered fcoe transport's destroy function. - * - * Returns: 0 for success - */ -static int fcoe_transport_destroy(const char *buffer, struct kernel_param *kp) -{ - int rc = -ENODEV; - struct net_device *netdev = NULL; - struct fcoe_transport *ft = NULL; - - mutex_lock(&ft_mutex); - - netdev = fcoe_if_to_netdev(buffer); - if (!netdev) { - LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buffer); - goto out_nodev; - } - - ft = fcoe_netdev_map_lookup(netdev); - if (!ft) { - LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n", - netdev->name); - goto out_putdev; - } - - /* pass to transport destroy */ - rc = ft->destroy ? ft->destroy(netdev) : -ENODEV; - fcoe_del_netdev_mapping(netdev); - LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n", - ft->name, (rc) ? "failed" : "succeeded", - netdev->name); - -out_putdev: - dev_put(netdev); -out_nodev: - mutex_unlock(&ft_mutex); - return rc; -} - -/** - * fcoe_transport_disable() - Disables a FCoE interface - * @buffer: The name of the Ethernet interface to be disabled - * @kp: The associated kernel parameter - * - * Called from sysfs. - * - * Returns: 0 for success - */ -static int fcoe_transport_disable(const char *buffer, struct kernel_param *kp) -{ - int rc = -ENODEV; - struct net_device *netdev = NULL; - struct fcoe_transport *ft = NULL; - - mutex_lock(&ft_mutex); - - netdev = fcoe_if_to_netdev(buffer); - if (!netdev) - goto out_nodev; - - ft = fcoe_netdev_map_lookup(netdev); - if (!ft) - goto out_putdev; - - rc = ft->disable ? ft->disable(netdev) : -ENODEV; - -out_putdev: - dev_put(netdev); -out_nodev: - mutex_unlock(&ft_mutex); - - if (rc == -ERESTARTSYS) - return restart_syscall(); - else - return rc; -} - -/** - * fcoe_transport_enable() - Enables a FCoE interface - * @buffer: The name of the Ethernet interface to be enabled - * @kp: The associated kernel parameter - * - * Called from sysfs. - * - * Returns: 0 for success - */ -static int fcoe_transport_enable(const char *buffer, struct kernel_param *kp) -{ - int rc = -ENODEV; - struct net_device *netdev = NULL; - struct fcoe_transport *ft = NULL; - - mutex_lock(&ft_mutex); - - netdev = fcoe_if_to_netdev(buffer); - if (!netdev) - goto out_nodev; - - ft = fcoe_netdev_map_lookup(netdev); - if (!ft) - goto out_putdev; - - rc = ft->enable ? ft->enable(netdev) : -ENODEV; - -out_putdev: - dev_put(netdev); -out_nodev: - mutex_unlock(&ft_mutex); - return rc; -} - -/** - * libfcoe_init() - Initialization routine for libfcoe.ko - */ -static int __init libfcoe_init(void) -{ - fcoe_transport_init(); - - return 0; -} -module_init(libfcoe_init); - -/** - * libfcoe_exit() - Tear down libfcoe.ko - */ -static void __exit libfcoe_exit(void) -{ - fcoe_transport_exit(); -} -module_exit(libfcoe_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/fcoe/libfcoe.h b/ANDROID_3.4.5/drivers/scsi/fcoe/libfcoe.h deleted file mode 100644 index 6af5fc3a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fcoe/libfcoe.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _FCOE_LIBFCOE_H_ -#define _FCOE_LIBFCOE_H_ - -extern unsigned int libfcoe_debug_logging; -#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */ -#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */ -#define LIBFCOE_TRANSPORT_LOGGING 0x04 /* FCoE transport logging */ - -#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \ -do { \ - if (unlikely(libfcoe_debug_logging & LEVEL)) \ - do { \ - CMD; \ - } while (0); \ -} while (0) - -#define LIBFCOE_DBG(fmt, args...) \ - LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \ - printk(KERN_INFO "libfcoe: " fmt, ##args);) - -#define LIBFCOE_FIP_DBG(fip, fmt, args...) \ - LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \ - printk(KERN_INFO "host%d: fip: " fmt, \ - (fip)->lp->host->host_no, ##args);) - -#define LIBFCOE_TRANSPORT_DBG(fmt, args...) \ - LIBFCOE_CHECK_LOGGING(LIBFCOE_TRANSPORT_LOGGING, \ - printk(KERN_INFO "%s: " fmt, \ - __func__, ##args);) - -#endif /* _FCOE_LIBFCOE_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fd_mcs.c b/ANDROID_3.4.5/drivers/scsi/fd_mcs.c deleted file mode 100644 index 53bfcaa8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fd_mcs.c +++ /dev/null @@ -1,1354 +0,0 @@ -/* fd_mcs.c -- Future Domain MCS 600/700 (or IBM OEM) driver - * - * FutureDomain MCS-600/700 v0.2 03/11/1998 by ZP Gu (zpg@castle.net) - * - * This driver is cloned from fdomain.* to specifically support - * the Future Domain MCS 600/700 MCA SCSI adapters. Some PS/2s - * also equipped with IBM Fast SCSI Adapter/A which is an OEM - * of MCS 700. - * - * This driver also supports Reply SB16/SCSI card (the SCSI part). - * - * What makes this driver different is that this driver is MCA only - * and it supports multiple adapters in the same system, IRQ - * sharing, some driver statistics, and maps highest SCSI id to sda. - * All cards are auto-detected. - * - * Assumptions: TMC-1800/18C50/18C30, BIOS >= 3.4 - * - * LILO command-line options: - * fd_mcs=[,] - * - * ******************************************************** - * Please see Copyrights/Comments in fdomain.* for credits. - * Following is from fdomain.c for acknowledgement: - * - * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu - * Revised: Wed Oct 2 11:10:55 1996 by r.faith@ieee.org - * Author: Rickard E. Faith, faith@cs.unc.edu - * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith - * - * $Id: fdomain.c,v 5.45 1996/10/02 15:13:06 root Exp $ - - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - - ************************************************************************** - - NOTES ON USER DEFINABLE OPTIONS: - - DEBUG: This turns on the printing of various debug information. - - ENABLE_PARITY: This turns on SCSI parity checking. With the current - driver, all attached devices must support SCSI parity. If none of your - devices support parity, then you can probably get the driver to work by - turning this option off. I have no way of testing this, however, and it - would appear that no one ever uses this option. - - FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the - 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by - the SCSI device, an interrupt will be raised. Therefore, this could be as - low as 0, or as high as 16. Note, however, that values which are too high - or too low seem to prevent any interrupts from occurring, and thereby lock - up the machine. I have found that 2 is a good number, but throughput may - be increased by changing this value to values which are close to 2. - Please let me know if you try any different values. - [*****Now a runtime option*****] - - RESELECTION: This is no longer an option, since I gave up trying to - implement it in version 4.x of this driver. It did not improve - performance at all and made the driver unstable (because I never found one - of the two race conditions which were introduced by the multiple - outstanding command code). The instability seems a very high price to pay - just so that you don't have to wait for the tape to rewind. If you want - this feature implemented, send me patches. I'll be happy to send a copy - of my (broken) driver to anyone who would like to see a copy. - - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "scsi.h" -#include - -#define DRIVER_VERSION "v0.2 by ZP Gu" - -/* START OF USER DEFINABLE OPTIONS */ - -#define DEBUG 0 /* Enable debugging output */ -#define ENABLE_PARITY 1 /* Enable SCSI Parity */ - -/* END OF USER DEFINABLE OPTIONS */ - -#if DEBUG -#define EVERY_ACCESS 0 /* Write a line on every scsi access */ -#define ERRORS_ONLY 1 /* Only write a line if there is an error */ -#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */ -#define DEBUG_ABORT 1 /* Debug abort() routine */ -#define DEBUG_RESET 1 /* Debug reset() routine */ -#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */ -#else -#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */ -#define ERRORS_ONLY 0 -#define DEBUG_MESSAGES 0 -#define DEBUG_ABORT 0 -#define DEBUG_RESET 0 -#define DEBUG_RACE 0 -#endif - -/* Errors are reported on the line, so we don't need to report them again */ -#if EVERY_ACCESS -#undef ERRORS_ONLY -#define ERRORS_ONLY 0 -#endif - -#if ENABLE_PARITY -#define PARITY_MASK 0x08 -#else -#define PARITY_MASK 0x00 -#endif - -enum chip_type { - unknown = 0x00, - tmc1800 = 0x01, - tmc18c50 = 0x02, - tmc18c30 = 0x03, -}; - -enum { - in_arbitration = 0x02, - in_selection = 0x04, - in_other = 0x08, - disconnect = 0x10, - aborted = 0x20, - sent_ident = 0x40, -}; - -enum in_port_type { - Read_SCSI_Data = 0, - SCSI_Status = 1, - TMC_Status = 2, - FIFO_Status = 3, /* tmc18c50/tmc18c30 only */ - Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */ - LSB_ID_Code = 5, - MSB_ID_Code = 6, - Read_Loopback = 7, - SCSI_Data_NoACK = 8, - Interrupt_Status = 9, - Configuration1 = 10, - Configuration2 = 11, /* tmc18c50/tmc18c30 only */ - Read_FIFO = 12, - FIFO_Data_Count = 14 -}; - -enum out_port_type { - Write_SCSI_Data = 0, - SCSI_Cntl = 1, - Interrupt_Cntl = 2, - SCSI_Mode_Cntl = 3, - TMC_Cntl = 4, - Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */ - Write_Loopback = 7, - IO_Control = 11, /* tmc18c30 only */ - Write_FIFO = 12 -}; - -struct fd_hostdata { - unsigned long _bios_base; - int _bios_major; - int _bios_minor; - volatile int _in_command; - Scsi_Cmnd *_current_SC; - enum chip_type _chip; - int _adapter_mask; - int _fifo_count; /* Number of 512 byte blocks before INTR */ - - char _adapter_name[64]; -#if DEBUG_RACE - volatile int _in_interrupt_flag; -#endif - - int _SCSI_Mode_Cntl_port; - int _FIFO_Data_Count_port; - int _Interrupt_Cntl_port; - int _Interrupt_Status_port; - int _Interrupt_Cond_port; - int _Read_FIFO_port; - int _Read_SCSI_Data_port; - int _SCSI_Cntl_port; - int _SCSI_Data_NoACK_port; - int _SCSI_Status_port; - int _TMC_Cntl_port; - int _TMC_Status_port; - int _Write_FIFO_port; - int _Write_SCSI_Data_port; - - int _FIFO_Size; /* = 0x2000; 8k FIFO for - pre-tmc18c30 chips */ - /* simple stats */ - int _Bytes_Read; - int _Bytes_Written; - int _INTR_Processed; -}; - -#define FD_MAX_HOSTS 3 /* enough? */ - -#define HOSTDATA(shpnt) ((struct fd_hostdata *) shpnt->hostdata) -#define bios_base (HOSTDATA(shpnt)->_bios_base) -#define bios_major (HOSTDATA(shpnt)->_bios_major) -#define bios_minor (HOSTDATA(shpnt)->_bios_minor) -#define in_command (HOSTDATA(shpnt)->_in_command) -#define current_SC (HOSTDATA(shpnt)->_current_SC) -#define chip (HOSTDATA(shpnt)->_chip) -#define adapter_mask (HOSTDATA(shpnt)->_adapter_mask) -#define FIFO_COUNT (HOSTDATA(shpnt)->_fifo_count) -#define adapter_name (HOSTDATA(shpnt)->_adapter_name) -#if DEBUG_RACE -#define in_interrupt_flag (HOSTDATA(shpnt)->_in_interrupt_flag) -#endif -#define SCSI_Mode_Cntl_port (HOSTDATA(shpnt)->_SCSI_Mode_Cntl_port) -#define FIFO_Data_Count_port (HOSTDATA(shpnt)->_FIFO_Data_Count_port) -#define Interrupt_Cntl_port (HOSTDATA(shpnt)->_Interrupt_Cntl_port) -#define Interrupt_Status_port (HOSTDATA(shpnt)->_Interrupt_Status_port) -#define Interrupt_Cond_port (HOSTDATA(shpnt)->_Interrupt_Cond_port) -#define Read_FIFO_port (HOSTDATA(shpnt)->_Read_FIFO_port) -#define Read_SCSI_Data_port (HOSTDATA(shpnt)->_Read_SCSI_Data_port) -#define SCSI_Cntl_port (HOSTDATA(shpnt)->_SCSI_Cntl_port) -#define SCSI_Data_NoACK_port (HOSTDATA(shpnt)->_SCSI_Data_NoACK_port) -#define SCSI_Status_port (HOSTDATA(shpnt)->_SCSI_Status_port) -#define TMC_Cntl_port (HOSTDATA(shpnt)->_TMC_Cntl_port) -#define TMC_Status_port (HOSTDATA(shpnt)->_TMC_Status_port) -#define Write_FIFO_port (HOSTDATA(shpnt)->_Write_FIFO_port) -#define Write_SCSI_Data_port (HOSTDATA(shpnt)->_Write_SCSI_Data_port) -#define FIFO_Size (HOSTDATA(shpnt)->_FIFO_Size) -#define Bytes_Read (HOSTDATA(shpnt)->_Bytes_Read) -#define Bytes_Written (HOSTDATA(shpnt)->_Bytes_Written) -#define INTR_Processed (HOSTDATA(shpnt)->_INTR_Processed) - -struct fd_mcs_adapters_struct { - char *name; - int id; - enum chip_type fd_chip; - int fifo_size; - int fifo_count; -}; - -#define REPLY_ID 0x5137 - -static struct fd_mcs_adapters_struct fd_mcs_adapters[] = { - {"Future Domain SCSI Adapter MCS-700(18C50)", - 0x60e9, - tmc18c50, - 0x2000, - 4}, - {"Future Domain SCSI Adapter MCS-600/700(TMC-1800)", - 0x6127, - tmc1800, - 0x2000, - 4}, - {"Reply Sound Blaster/SCSI Adapter", - REPLY_ID, - tmc18c30, - 0x800, - 2}, -}; - -#define FD_BRDS ARRAY_SIZE(fd_mcs_adapters) - -static irqreturn_t fd_mcs_intr(int irq, void *dev_id); - -static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 }; -static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; -static unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; - -/* host information */ -static int found = 0; -static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL }; - -static int user_fifo_count = 0; -static int user_fifo_size = 0; - -#ifndef MODULE -static int __init fd_mcs_setup(char *str) -{ - static int done_setup = 0; - int ints[3]; - - get_options(str, 3, ints); - if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) { - printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n"); - return 0; - } - - user_fifo_count = ints[0] >= 1 ? ints[1] : 0; - user_fifo_size = ints[0] >= 2 ? ints[2] : 0; - return 1; -} - -__setup("fd_mcs=", fd_mcs_setup); -#endif /* !MODULE */ - -static void print_banner(struct Scsi_Host *shpnt) -{ - printk("scsi%d : ", shpnt->host_no); - - if (bios_base) { - printk("BIOS at 0x%lX", bios_base); - } else { - printk("No BIOS"); - } - - printk(", HostID %d, %s Chip, IRQ %d, IO 0x%lX\n", shpnt->this_id, chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? "TMC-18C30" : (chip == tmc1800 ? "TMC-1800" : "Unknown")), shpnt->irq, shpnt->io_port); -} - - -static void do_pause(unsigned amount) -{ /* Pause for amount*10 milliseconds */ - do { - mdelay(10); - } while (--amount); -} - -static void fd_mcs_make_bus_idle(struct Scsi_Host *shpnt) -{ - outb(0, SCSI_Cntl_port); - outb(0, SCSI_Mode_Cntl_port); - if (chip == tmc18c50 || chip == tmc18c30) - outb(0x21 | PARITY_MASK, TMC_Cntl_port); /* Clear forced intr. */ - else - outb(0x01 | PARITY_MASK, TMC_Cntl_port); -} - -static int fd_mcs_detect(struct scsi_host_template * tpnt) -{ - int loop; - struct Scsi_Host *shpnt; - - /* get id, port, bios, irq */ - int slot; - u_char pos2, pos3, pos4; - int id, port, irq; - unsigned long bios; - - /* if not MCA machine, return */ - if (!MCA_bus) - return 0; - - /* changeable? */ - id = 7; - - for (loop = 0; loop < FD_BRDS; loop++) { - slot = 0; - while (MCA_NOTFOUND != (slot = mca_find_adapter(fd_mcs_adapters[loop].id, slot))) { - - /* if we get this far, an adapter has been detected and is - enabled */ - - printk(KERN_INFO "scsi : %s at slot %d\n", fd_mcs_adapters[loop].name, slot + 1); - - pos2 = mca_read_stored_pos(slot, 2); - pos3 = mca_read_stored_pos(slot, 3); - pos4 = mca_read_stored_pos(slot, 4); - - /* ready for next probe */ - slot++; - - if (fd_mcs_adapters[loop].id == REPLY_ID) { /* reply card */ - static int reply_irq[] = { 10, 11, 14, 15 }; - - bios = 0; /* no bios */ - - if (pos2 & 0x2) - port = ports[pos4 & 0x3]; - else - continue; - - /* can't really disable it, same as irq=10 */ - irq = reply_irq[((pos4 >> 2) & 0x1) + 2 * ((pos4 >> 4) & 0x1)]; - } else { - bios = addresses[pos2 >> 6]; - port = ports[(pos2 >> 4) & 0x03]; - irq = interrupts[(pos2 >> 1) & 0x07]; - } - - if (irq) { - /* claim the slot */ - mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name); - - /* check irq/region */ - if (request_irq(irq, fd_mcs_intr, IRQF_SHARED, "fd_mcs", hosts)) { - printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n"); - continue; - } - - /* request I/O region */ - if (request_region(port, 0x10, "fd_mcs")) { - printk(KERN_ERR "fd_mcs: I/O region is already in use, skipping...\n"); - continue; - } - /* register */ - if (!(shpnt = scsi_register(tpnt, sizeof(struct fd_hostdata)))) { - printk(KERN_ERR "fd_mcs: scsi_register() failed\n"); - release_region(port, 0x10); - free_irq(irq, hosts); - continue; - } - - - /* save name */ - strcpy(adapter_name, fd_mcs_adapters[loop].name); - - /* chip/fifo */ - chip = fd_mcs_adapters[loop].fd_chip; - /* use boot time value if available */ - FIFO_COUNT = user_fifo_count ? user_fifo_count : fd_mcs_adapters[loop].fifo_count; - FIFO_Size = user_fifo_size ? user_fifo_size : fd_mcs_adapters[loop].fifo_size; - -/* FIXME: Do we need to keep this bit of code inside NOT_USED around at all? */ -#ifdef NOT_USED - /* *************************************************** */ - /* Try to toggle 32-bit mode. This only - works on an 18c30 chip. (User reports - say this works, so we should switch to - it in the near future.) */ - outb(0x80, port + IO_Control); - if ((inb(port + Configuration2) & 0x80) == 0x80) { - outb(0x00, port + IO_Control); - if ((inb(port + Configuration2) & 0x80) == 0x00) { - chip = tmc18c30; - FIFO_Size = 0x800; /* 2k FIFO */ - - printk("FIRST: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size); - } - } - - /* That should have worked, but appears to - have problems. Let's assume it is an - 18c30 if the RAM is disabled. */ - - if (inb(port + Configuration2) & 0x02) { - chip = tmc18c30; - FIFO_Size = 0x800; /* 2k FIFO */ - - printk("SECOND: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size); - } - /* *************************************************** */ -#endif - - /* IBM/ANSI scsi scan ordering */ - /* Stick this back in when the scsi.c changes are there */ - shpnt->reverse_ordering = 1; - - - /* saving info */ - hosts[found++] = shpnt; - - shpnt->this_id = id; - shpnt->irq = irq; - shpnt->io_port = port; - shpnt->n_io_port = 0x10; - - /* save */ - bios_base = bios; - adapter_mask = (1 << id); - - /* save more */ - SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl; - FIFO_Data_Count_port = port + FIFO_Data_Count; - Interrupt_Cntl_port = port + Interrupt_Cntl; - Interrupt_Status_port = port + Interrupt_Status; - Interrupt_Cond_port = port + Interrupt_Cond; - Read_FIFO_port = port + Read_FIFO; - Read_SCSI_Data_port = port + Read_SCSI_Data; - SCSI_Cntl_port = port + SCSI_Cntl; - SCSI_Data_NoACK_port = port + SCSI_Data_NoACK; - SCSI_Status_port = port + SCSI_Status; - TMC_Cntl_port = port + TMC_Cntl; - TMC_Status_port = port + TMC_Status; - Write_FIFO_port = port + Write_FIFO; - Write_SCSI_Data_port = port + Write_SCSI_Data; - - Bytes_Read = 0; - Bytes_Written = 0; - INTR_Processed = 0; - - /* say something */ - print_banner(shpnt); - - /* reset */ - outb(1, SCSI_Cntl_port); - do_pause(2); - outb(0, SCSI_Cntl_port); - do_pause(115); - outb(0, SCSI_Mode_Cntl_port); - outb(PARITY_MASK, TMC_Cntl_port); - /* done reset */ - } - } - - if (found == FD_MAX_HOSTS) { - printk("fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS); - break; - } - } - - return found; -} - -static const char *fd_mcs_info(struct Scsi_Host *shpnt) -{ - return adapter_name; -} - -static int TOTAL_INTR = 0; - -/* - * inout : decides on the direction of the dataflow and the meaning of the - * variables - * buffer: If inout==FALSE data is being written to it else read from it - * *start: If inout==FALSE start of the valid data in the buffer - * offset: If inout==FALSE offset from the beginning of the imaginary file - * from which we start writing into the buffer - * length: If inout==FALSE max number of bytes to be written into the buffer - * else number of bytes in the buffer - */ -static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout) -{ - int len = 0; - - if (inout) - return (-ENOSYS); - - *start = buffer + offset; - - len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION); - len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name); - len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT); - len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written); - - if ((len -= offset) <= 0) - return 0; - if (len > length) - len = length; - return len; -} - -static int fd_mcs_select(struct Scsi_Host *shpnt, int target) -{ - int status; - unsigned long timeout; - - outb(0x82, SCSI_Cntl_port); /* Bus Enable + Select */ - outb(adapter_mask | (1 << target), SCSI_Data_NoACK_port); - - /* Stop arbitration and enable parity */ - outb(PARITY_MASK, TMC_Cntl_port); - - timeout = 350; /* 350mS -- because of timeouts - (was 250mS) */ - - do { - status = inb(SCSI_Status_port); /* Read adapter status */ - if (status & 1) { /* Busy asserted */ - /* Enable SCSI Bus (on error, should make bus idle with 0) */ - outb(0x80, SCSI_Cntl_port); - return 0; - } - udelay(1000); /* wait one msec */ - } while (--timeout); - - /* Make bus idle */ - fd_mcs_make_bus_idle(shpnt); -#if EVERY_ACCESS - if (!target) - printk("Selection failed\n"); -#endif -#if ERRORS_ONLY - if (!target) { - static int flag = 0; - - if (!flag) /* Skip first failure for all chips. */ - ++flag; - else - printk("fd_mcs: Selection failed\n"); - } -#endif - return 1; -} - -static void my_done(struct Scsi_Host *shpnt, int error) -{ - if (in_command) { - in_command = 0; - outb(0x00, Interrupt_Cntl_port); - fd_mcs_make_bus_idle(shpnt); - current_SC->result = error; - current_SC->scsi_done(current_SC); - } else { - panic("fd_mcs: my_done() called outside of command\n"); - } -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif -} - -/* only my_done needs to be protected */ -static irqreturn_t fd_mcs_intr(int irq, void *dev_id) -{ - unsigned long flags; - int status; - int done = 0; - unsigned data_count, tmp_count; - - int i = 0; - struct Scsi_Host *shpnt; - - TOTAL_INTR++; - - /* search for one adapter-response on shared interrupt */ - while ((shpnt = hosts[i++])) { - if ((inb(TMC_Status_port)) & 1) - break; - } - - /* return if some other device on this IRQ caused the interrupt */ - if (!shpnt) { - return IRQ_NONE; - } - - INTR_Processed++; - - outb(0x00, Interrupt_Cntl_port); - - /* Abort calls my_done, so we do nothing here. */ - if (current_SC->SCp.phase & aborted) { -#if DEBUG_ABORT - printk("Interrupt after abort, ignoring\n"); -#endif - /* return IRQ_HANDLED; */ - } -#if DEBUG_RACE - ++in_interrupt_flag; -#endif - - if (current_SC->SCp.phase & in_arbitration) { - status = inb(TMC_Status_port); /* Read adapter status */ - if (!(status & 0x02)) { -#if EVERY_ACCESS - printk(" AFAIL "); -#endif - spin_lock_irqsave(shpnt->host_lock, flags); - my_done(shpnt, DID_BUS_BUSY << 16); - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; - } - current_SC->SCp.phase = in_selection; - - outb(0x40 | FIFO_COUNT, Interrupt_Cntl_port); - - outb(0x82, SCSI_Cntl_port); /* Bus Enable + Select */ - outb(adapter_mask | (1 << scmd_id(current_SC)), SCSI_Data_NoACK_port); - - /* Stop arbitration and enable parity */ - outb(0x10 | PARITY_MASK, TMC_Cntl_port); -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; - } else if (current_SC->SCp.phase & in_selection) { - status = inb(SCSI_Status_port); - if (!(status & 0x01)) { - /* Try again, for slow devices */ - if (fd_mcs_select(shpnt, scmd_id(current_SC))) { -#if EVERY_ACCESS - printk(" SFAIL "); -#endif - spin_lock_irqsave(shpnt->host_lock, flags); - my_done(shpnt, DID_NO_CONNECT << 16); - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; - } else { -#if EVERY_ACCESS - printk(" AltSel "); -#endif - /* Stop arbitration and enable parity */ - outb(0x10 | PARITY_MASK, TMC_Cntl_port); - } - } - current_SC->SCp.phase = in_other; - outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port); - outb(0x80, SCSI_Cntl_port); -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; - } - - /* current_SC->SCp.phase == in_other: this is the body of the routine */ - - status = inb(SCSI_Status_port); - - if (status & 0x10) { /* REQ */ - - switch (status & 0x0e) { - - case 0x08: /* COMMAND OUT */ - outb(current_SC->cmnd[current_SC->SCp.sent_command++], Write_SCSI_Data_port); -#if EVERY_ACCESS - printk("CMD = %x,", current_SC->cmnd[current_SC->SCp.sent_command - 1]); -#endif - break; - case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */ - if (chip != tmc1800 && !current_SC->SCp.have_data_in) { - current_SC->SCp.have_data_in = -1; - outb(0xd0 | PARITY_MASK, TMC_Cntl_port); - } - break; - case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */ - if (chip != tmc1800 && !current_SC->SCp.have_data_in) { - current_SC->SCp.have_data_in = 1; - outb(0x90 | PARITY_MASK, TMC_Cntl_port); - } - break; - case 0x0c: /* STATUS IN */ - current_SC->SCp.Status = inb(Read_SCSI_Data_port); -#if EVERY_ACCESS - printk("Status = %x, ", current_SC->SCp.Status); -#endif -#if ERRORS_ONLY - if (current_SC->SCp.Status && current_SC->SCp.Status != 2 && current_SC->SCp.Status != 8) { - printk("ERROR fd_mcs: target = %d, command = %x, status = %x\n", current_SC->device->id, current_SC->cmnd[0], current_SC->SCp.Status); - } -#endif - break; - case 0x0a: /* MESSAGE OUT */ - outb(MESSAGE_REJECT, Write_SCSI_Data_port); /* Reject */ - break; - case 0x0e: /* MESSAGE IN */ - current_SC->SCp.Message = inb(Read_SCSI_Data_port); -#if EVERY_ACCESS - printk("Message = %x, ", current_SC->SCp.Message); -#endif - if (!current_SC->SCp.Message) - ++done; -#if DEBUG_MESSAGES || EVERY_ACCESS - if (current_SC->SCp.Message) { - printk("fd_mcs: message = %x\n", current_SC->SCp.Message); - } -#endif - break; - } - } - - if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command >= current_SC->cmd_len)) { - /* We have to get the FIFO direction - correct, so I've made a table based - on the SCSI Standard of which commands - appear to require a DATA OUT phase. - */ - /* - p. 94: Command for all device types - CHANGE DEFINITION 40 DATA OUT - COMPARE 39 DATA OUT - COPY 18 DATA OUT - COPY AND VERIFY 3a DATA OUT - INQUIRY 12 - LOG SELECT 4c DATA OUT - LOG SENSE 4d - MODE SELECT (6) 15 DATA OUT - MODE SELECT (10) 55 DATA OUT - MODE SENSE (6) 1a - MODE SENSE (10) 5a - READ BUFFER 3c - RECEIVE DIAGNOSTIC RESULTS 1c - REQUEST SENSE 03 - SEND DIAGNOSTIC 1d DATA OUT - TEST UNIT READY 00 - WRITE BUFFER 3b DATA OUT - - p.178: Commands for direct-access devices (not listed on p. 94) - FORMAT UNIT 04 DATA OUT - LOCK-UNLOCK CACHE 36 - PRE-FETCH 34 - PREVENT-ALLOW MEDIUM REMOVAL 1e - READ (6)/RECEIVE 08 - READ (10) 3c - READ CAPACITY 25 - READ DEFECT DATA (10) 37 - READ LONG 3e - REASSIGN BLOCKS 07 DATA OUT - RELEASE 17 - RESERVE 16 DATA OUT - REZERO UNIT/REWIND 01 - SEARCH DATA EQUAL (10) 31 DATA OUT - SEARCH DATA HIGH (10) 30 DATA OUT - SEARCH DATA LOW (10) 32 DATA OUT - SEEK (6) 0b - SEEK (10) 2b - SET LIMITS (10) 33 - START STOP UNIT 1b - SYNCHRONIZE CACHE 35 - VERIFY (10) 2f - WRITE (6)/PRINT/SEND 0a DATA OUT - WRITE (10)/SEND 2a DATA OUT - WRITE AND VERIFY (10) 2e DATA OUT - WRITE LONG 3f DATA OUT - WRITE SAME 41 DATA OUT ? - - p. 261: Commands for sequential-access devices (not previously listed) - ERASE 19 - LOAD UNLOAD 1b - LOCATE 2b - READ BLOCK LIMITS 05 - READ POSITION 34 - READ REVERSE 0f - RECOVER BUFFERED DATA 14 - SPACE 11 - WRITE FILEMARKS 10 ? - - p. 298: Commands for printer devices (not previously listed) - ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) ***** - SLEW AND PRINT 0b DATA OUT -- same as seek - STOP PRINT 1b - SYNCHRONIZE BUFFER 10 - - p. 315: Commands for processor devices (not previously listed) - - p. 321: Commands for write-once devices (not previously listed) - MEDIUM SCAN 38 - READ (12) a8 - SEARCH DATA EQUAL (12) b1 DATA OUT - SEARCH DATA HIGH (12) b0 DATA OUT - SEARCH DATA LOW (12) b2 DATA OUT - SET LIMITS (12) b3 - VERIFY (12) af - WRITE (12) aa DATA OUT - WRITE AND VERIFY (12) ae DATA OUT - - p. 332: Commands for CD-ROM devices (not previously listed) - PAUSE/RESUME 4b - PLAY AUDIO (10) 45 - PLAY AUDIO (12) a5 - PLAY AUDIO MSF 47 - PLAY TRACK RELATIVE (10) 49 - PLAY TRACK RELATIVE (12) a9 - READ HEADER 44 - READ SUB-CHANNEL 42 - READ TOC 43 - - p. 370: Commands for scanner devices (not previously listed) - GET DATA BUFFER STATUS 34 - GET WINDOW 25 - OBJECT POSITION 31 - SCAN 1b - SET WINDOW 24 DATA OUT - - p. 391: Commands for optical memory devices (not listed) - ERASE (10) 2c - ERASE (12) ac - MEDIUM SCAN 38 DATA OUT - READ DEFECT DATA (12) b7 - READ GENERATION 29 - READ UPDATED BLOCK 2d - UPDATE BLOCK 3d DATA OUT - - p. 419: Commands for medium changer devices (not listed) - EXCHANGE MEDIUM 46 - INITIALIZE ELEMENT STATUS 07 - MOVE MEDIUM a5 - POSITION TO ELEMENT 2b - READ ELEMENT STATUS b8 - REQUEST VOL. ELEMENT ADDRESS b5 - SEND VOLUME TAG b6 DATA OUT - - p. 454: Commands for communications devices (not listed previously) - GET MESSAGE (6) 08 - GET MESSAGE (10) 28 - GET MESSAGE (12) a8 - */ - - switch (current_SC->cmnd[0]) { - case CHANGE_DEFINITION: - case COMPARE: - case COPY: - case COPY_VERIFY: - case LOG_SELECT: - case MODE_SELECT: - case MODE_SELECT_10: - case SEND_DIAGNOSTIC: - case WRITE_BUFFER: - - case FORMAT_UNIT: - case REASSIGN_BLOCKS: - case RESERVE: - case SEARCH_EQUAL: - case SEARCH_HIGH: - case SEARCH_LOW: - case WRITE_6: - case WRITE_10: - case WRITE_VERIFY: - case 0x3f: - case 0x41: - - case 0xb1: - case 0xb0: - case 0xb2: - case 0xaa: - case 0xae: - - case 0x24: - - case 0x38: - case 0x3d: - - case 0xb6: - - case 0xea: /* alternate number for WRITE LONG */ - - current_SC->SCp.have_data_in = -1; - outb(0xd0 | PARITY_MASK, TMC_Cntl_port); - break; - - case 0x00: - default: - - current_SC->SCp.have_data_in = 1; - outb(0x90 | PARITY_MASK, TMC_Cntl_port); - break; - } - } - - if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */ - while ((data_count = FIFO_Size - inw(FIFO_Data_Count_port)) > 512) { -#if EVERY_ACCESS - printk("DC=%d, ", data_count); -#endif - if (data_count > current_SC->SCp.this_residual) - data_count = current_SC->SCp.this_residual; - if (data_count > 0) { -#if EVERY_ACCESS - printk("%d OUT, ", data_count); -#endif - if (data_count == 1) { - Bytes_Written++; - - outb(*current_SC->SCp.ptr++, Write_FIFO_port); - --current_SC->SCp.this_residual; - } else { - data_count >>= 1; - tmp_count = data_count << 1; - outsw(Write_FIFO_port, current_SC->SCp.ptr, data_count); - current_SC->SCp.ptr += tmp_count; - Bytes_Written += tmp_count; - current_SC->SCp.this_residual -= tmp_count; - } - } - if (!current_SC->SCp.this_residual) { - if (current_SC->SCp.buffers_residual) { - --current_SC->SCp.buffers_residual; - ++current_SC->SCp.buffer; - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - } else - break; - } - } - } else if (current_SC->SCp.have_data_in == 1) { /* DATA IN */ - while ((data_count = inw(FIFO_Data_Count_port)) > 0) { -#if EVERY_ACCESS - printk("DC=%d, ", data_count); -#endif - if (data_count > current_SC->SCp.this_residual) - data_count = current_SC->SCp.this_residual; - if (data_count) { -#if EVERY_ACCESS - printk("%d IN, ", data_count); -#endif - if (data_count == 1) { - Bytes_Read++; - *current_SC->SCp.ptr++ = inb(Read_FIFO_port); - --current_SC->SCp.this_residual; - } else { - data_count >>= 1; /* Number of words */ - tmp_count = data_count << 1; - insw(Read_FIFO_port, current_SC->SCp.ptr, data_count); - current_SC->SCp.ptr += tmp_count; - Bytes_Read += tmp_count; - current_SC->SCp.this_residual -= tmp_count; - } - } - if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) { - --current_SC->SCp.buffers_residual; - ++current_SC->SCp.buffer; - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - } - } - } - - if (done) { -#if EVERY_ACCESS - printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in); -#endif - -#if EVERY_ACCESS - printk("BEFORE MY_DONE. . ."); -#endif - spin_lock_irqsave(shpnt->host_lock, flags); - my_done(shpnt, (current_SC->SCp.Status & 0xff) - | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16)); - spin_unlock_irqrestore(shpnt->host_lock, flags); -#if EVERY_ACCESS - printk("RETURNING.\n"); -#endif - - } else { - if (current_SC->SCp.phase & disconnect) { - outb(0xd0 | FIFO_COUNT, Interrupt_Cntl_port); - outb(0x00, SCSI_Cntl_port); - } else { - outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port); - } - } -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; -} - -static int fd_mcs_release(struct Scsi_Host *shpnt) -{ - int i, this_host, irq_usage; - - release_region(shpnt->io_port, shpnt->n_io_port); - - this_host = -1; - irq_usage = 0; - for (i = 0; i < found; i++) { - if (shpnt == hosts[i]) - this_host = i; - if (shpnt->irq == hosts[i]->irq) - irq_usage++; - } - - /* only for the last one */ - if (1 == irq_usage) - free_irq(shpnt->irq, hosts); - - found--; - - for (i = this_host; i < found; i++) - hosts[i] = hosts[i + 1]; - - hosts[found] = NULL; - - return 0; -} - -static int fd_mcs_queue_lck(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *)) -{ - struct Scsi_Host *shpnt = SCpnt->device->host; - - if (in_command) { - panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n"); - } -#if EVERY_ACCESS - printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", - SCpnt->target, *(unsigned char *) SCpnt->cmnd, - scsi_sg_count(SCpnt), scsi_bufflen(SCpnt)); -#endif - - fd_mcs_make_bus_idle(shpnt); - - SCpnt->scsi_done = done; /* Save this for the done function */ - current_SC = SCpnt; - - /* Initialize static data */ - - if (scsi_bufflen(current_SC)) { - current_SC->SCp.buffer = scsi_sglist(current_SC); - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1; - } else { - current_SC->SCp.ptr = NULL; - current_SC->SCp.this_residual = 0; - current_SC->SCp.buffer = NULL; - current_SC->SCp.buffers_residual = 0; - } - - - current_SC->SCp.Status = 0; - current_SC->SCp.Message = 0; - current_SC->SCp.have_data_in = 0; - current_SC->SCp.sent_command = 0; - current_SC->SCp.phase = in_arbitration; - - /* Start arbitration */ - outb(0x00, Interrupt_Cntl_port); - outb(0x00, SCSI_Cntl_port); /* Disable data drivers */ - outb(adapter_mask, SCSI_Data_NoACK_port); /* Set our id bit */ - in_command = 1; - outb(0x20, Interrupt_Cntl_port); - outb(0x14 | PARITY_MASK, TMC_Cntl_port); /* Start arbitration */ - - return 0; -} - -static DEF_SCSI_QCMD(fd_mcs_queue) - -#if DEBUG_ABORT || DEBUG_RESET -static void fd_mcs_print_info(Scsi_Cmnd * SCpnt) -{ - unsigned int imr; - unsigned int irr; - unsigned int isr; - struct Scsi_Host *shpnt = SCpnt->host; - - if (!SCpnt || !SCpnt->host) { - printk("fd_mcs: cannot provide detailed information\n"); - } - - printk("%s\n", fd_mcs_info(SCpnt->host)); - print_banner(SCpnt->host); - switch (SCpnt->SCp.phase) { - case in_arbitration: - printk("arbitration "); - break; - case in_selection: - printk("selection "); - break; - case in_other: - printk("other "); - break; - default: - printk("unknown "); - break; - } - - printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", - SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, - scsi_sg_count(SCpnt), scsi_bufflen(SCpnt)); - printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout); -#if DEBUG_RACE - printk("in_interrupt_flag = %d\n", in_interrupt_flag); -#endif - - imr = (inb(0x0a1) << 8) + inb(0x21); - outb(0x0a, 0xa0); - irr = inb(0xa0) << 8; - outb(0x0a, 0x20); - irr += inb(0x20); - outb(0x0b, 0xa0); - isr = inb(0xa0) << 8; - outb(0x0b, 0x20); - isr += inb(0x20); - - /* Print out interesting information */ - printk("IMR = 0x%04x", imr); - if (imr & (1 << shpnt->irq)) - printk(" (masked)"); - printk(", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr); - - printk("SCSI Status = 0x%02x\n", inb(SCSI_Status_port)); - printk("TMC Status = 0x%02x", inb(TMC_Status_port)); - if (inb(TMC_Status_port) & 1) - printk(" (interrupt)"); - printk("\n"); - printk("Interrupt Status = 0x%02x", inb(Interrupt_Status_port)); - if (inb(Interrupt_Status_port) & 0x08) - printk(" (enabled)"); - printk("\n"); - if (chip == tmc18c50 || chip == tmc18c30) { - printk("FIFO Status = 0x%02x\n", inb(shpnt->io_port + FIFO_Status)); - printk("Int. Condition = 0x%02x\n", inb(shpnt->io_port + Interrupt_Cond)); - } - printk("Configuration 1 = 0x%02x\n", inb(shpnt->io_port + Configuration1)); - if (chip == tmc18c50 || chip == tmc18c30) - printk("Configuration 2 = 0x%02x\n", inb(shpnt->io_port + Configuration2)); -} -#endif - -static int fd_mcs_abort(Scsi_Cmnd * SCpnt) -{ - struct Scsi_Host *shpnt = SCpnt->device->host; - - unsigned long flags; -#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT - printk("fd_mcs: abort "); -#endif - - spin_lock_irqsave(shpnt->host_lock, flags); - if (!in_command) { -#if EVERY_ACCESS || ERRORS_ONLY - printk(" (not in command)\n"); -#endif - spin_unlock_irqrestore(shpnt->host_lock, flags); - return FAILED; - } else - printk("\n"); - -#if DEBUG_ABORT - fd_mcs_print_info(SCpnt); -#endif - - fd_mcs_make_bus_idle(shpnt); - - current_SC->SCp.phase |= aborted; - - current_SC->result = DID_ABORT << 16; - - /* Aborts are not done well. . . */ - my_done(shpnt, DID_ABORT << 16); - - spin_unlock_irqrestore(shpnt->host_lock, flags); - return SUCCESS; -} - -static int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) { - struct Scsi_Host *shpnt = SCpnt->device->host; - unsigned long flags; - -#if DEBUG_RESET - static int called_once = 0; -#endif - -#if ERRORS_ONLY - if (SCpnt) - printk("fd_mcs: SCSI Bus Reset\n"); -#endif - -#if DEBUG_RESET - if (called_once) - fd_mcs_print_info(current_SC); - called_once = 1; -#endif - - spin_lock_irqsave(shpnt->host_lock, flags); - - outb(1, SCSI_Cntl_port); - do_pause(2); - outb(0, SCSI_Cntl_port); - do_pause(115); - outb(0, SCSI_Mode_Cntl_port); - outb(PARITY_MASK, TMC_Cntl_port); - - spin_unlock_irqrestore(shpnt->host_lock, flags); - - /* Unless this is the very first call (i.e., SCPnt == NULL), everything - is probably hosed at this point. We will, however, try to keep - things going by informing the high-level code that we need help. */ - return SUCCESS; -} - -#include - -static int fd_mcs_biosparam(struct scsi_device * disk, struct block_device *bdev, - sector_t capacity, int *info_array) -{ - unsigned char *p = scsi_bios_ptable(bdev); - int size = capacity; - - /* BIOS >= 3.4 for MCA cards */ - /* This algorithm was provided by Future Domain (much thanks!). */ - - if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */ - && p[4]) { /* Partition type */ - /* The partition table layout is as follows: - - Start: 0x1b3h - Offset: 0 = partition status - 1 = starting head - 2 = starting sector and cylinder (word, encoded) - 4 = partition type - 5 = ending head - 6 = ending sector and cylinder (word, encoded) - 8 = starting absolute sector (double word) - c = number of sectors (double word) - Signature: 0x1fe = 0x55aa - - So, this algorithm assumes: - 1) the first partition table is in use, - 2) the data in the first entry is correct, and - 3) partitions never divide cylinders - - Note that (1) may be FALSE for NetBSD (and other BSD flavors), - as well as for Linux. Note also, that Linux doesn't pay any - attention to the fields that are used by this algorithm -- it - only uses the absolute sector data. Recent versions of Linux's - fdisk(1) will fill this data in correctly, and forthcoming - versions will check for consistency. - - Checking for a non-zero partition type is not part of the - Future Domain algorithm, but it seemed to be a reasonable thing - to do, especially in the Linux and BSD worlds. */ - - info_array[0] = p[5] + 1; /* heads */ - info_array[1] = p[6] & 0x3f; /* sectors */ - } else { - /* Note that this new method guarantees that there will always be - less than 1024 cylinders on a platter. This is good for drives - up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */ - if ((unsigned int) size >= 0x7e0000U) - { - info_array[0] = 0xff; /* heads = 255 */ - info_array[1] = 0x3f; /* sectors = 63 */ - } else if ((unsigned int) size >= 0x200000U) { - info_array[0] = 0x80; /* heads = 128 */ - info_array[1] = 0x3f; /* sectors = 63 */ - } else { - info_array[0] = 0x40; /* heads = 64 */ - info_array[1] = 0x20; /* sectors = 32 */ - } - } - /* For both methods, compute the cylinders */ - info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]); - kfree(p); - return 0; -} - -static struct scsi_host_template driver_template = { - .proc_name = "fd_mcs", - .proc_info = fd_mcs_proc_info, - .detect = fd_mcs_detect, - .release = fd_mcs_release, - .info = fd_mcs_info, - .queuecommand = fd_mcs_queue, - .eh_abort_handler = fd_mcs_abort, - .eh_bus_reset_handler = fd_mcs_bus_reset, - .bios_param = fd_mcs_biosparam, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = 64, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/fdomain.c b/ANDROID_3.4.5/drivers/scsi/fdomain.c deleted file mode 100644 index 1a2a1e58..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fdomain.c +++ /dev/null @@ -1,1784 +0,0 @@ -/* fdomain.c -- Future Domain TMC-16x0 SCSI driver - * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu - * Revised: Mon Dec 28 21:59:02 1998 by faith@acm.org - * Author: Rickard E. Faith, faith@cs.unc.edu - * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org) - * Shared IRQ supported added 7/7/2001 Alan Cox - - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - - ************************************************************************** - - SUMMARY: - - Future Domain BIOS versions supported for autodetect: - 2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61 - Chips are supported: - TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70 - Boards supported: - Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX - Future Domain TMC-3260 (PCI) - Quantum ISA-200S, ISA-250MG - Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead] - IBM ? - LILO/INSMOD command-line options: - fdomain=,[,] - - - - NOTE: - - The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it. - Use the aic7xxx driver for this board. - - The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right - driver for that card. Unfortunately, the boxes will probably just say - "2920", so you'll have to look on the card for a Future Domain logo, or a - letter after the 2920. - - - - THANKS: - - Thanks to Adaptec for providing PCI boards for testing. This finally - enabled me to test the PCI detection and correct it for PCI boards that do - not have a BIOS at a standard ISA location. For PCI boards, LILO/INSMOD - command-line options should no longer be needed. --RF 18Nov98 - - - - DESCRIPTION: - - This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680 - TMC-1650/1670, and TMC-3260 SCSI host adapters. The 1650 and 1670 have a - 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin - high-density external connector. The 1670 and 1680 have floppy disk - controllers built in. The TMC-3260 is a PCI bus card. - - Future Domain's older boards are based on the TMC-1800 chip, and this - driver was originally written for a TMC-1680 board with the TMC-1800 chip. - More recently, boards are being produced with the TMC-18C50 and TMC-18C30 - chips. The latest and greatest board may not work with this driver. If - you have to patch this driver so that it will recognize your board's BIOS - signature, then the driver may fail to function after the board is - detected. - - Please note that the drive ordering that Future Domain implemented in BIOS - versions 3.4 and 3.5 is the opposite of the order (currently) used by the - rest of the SCSI industry. If you have BIOS version 3.4 or 3.5, and have - more than one drive, then the drive ordering will be the reverse of that - which you see under DOS. For example, under DOS SCSI ID 0 will be D: and - SCSI ID 1 will be C: (the boot device). Under Linux, SCSI ID 0 will be - /dev/sda and SCSI ID 1 will be /dev/sdb. The Linux ordering is consistent - with that provided by all the other SCSI drivers for Linux. If you want - this changed, you will probably have to patch the higher level SCSI code. - If you do so, please send me patches that are protected by #ifdefs. - - If you have a TMC-8xx or TMC-9xx board, then this is not the driver for - your board. Please refer to the Seagate driver for more information and - possible support. - - - - HISTORY: - - Linux Driver Driver - Version Version Date Support/Notes - - 0.0 3 May 1992 V2.0 BIOS; 1800 chip - 0.97 1.9 28 Jul 1992 - 0.98.6 3.1 27 Nov 1992 - 0.99 3.2 9 Dec 1992 - - 0.99.3 3.3 10 Jan 1993 V3.0 BIOS - 0.99.5 3.5 18 Feb 1993 - 0.99.10 3.6 15 May 1993 V3.2 BIOS; 18C50 chip - 0.99.11 3.17 3 Jul 1993 (now under RCS) - 0.99.12 3.18 13 Aug 1993 - 0.99.14 5.6 31 Oct 1993 (reselection code removed) - - 0.99.15 5.9 23 Jan 1994 V3.4 BIOS (preliminary) - 1.0.8/1.1.1 5.15 1 Apr 1994 V3.4 BIOS; 18C30 chip (preliminary) - 1.0.9/1.1.3 5.16 7 Apr 1994 V3.4 BIOS; 18C30 chip - 1.1.38 5.18 30 Jul 1994 36C70 chip (PCI version of 18C30) - 1.1.62 5.20 2 Nov 1994 V3.5 BIOS - 1.1.73 5.22 7 Dec 1994 Quantum ISA-200S board; V2.0 BIOS - - 1.1.82 5.26 14 Jan 1995 V3.5 BIOS; TMC-1610M/MER/MEX board - 1.2.10 5.28 5 Jun 1995 Quantum ISA-250MG board; V2.0, V2.01 BIOS - 1.3.4 5.31 23 Jun 1995 PCI BIOS-32 detection (preliminary) - 1.3.7 5.33 4 Jul 1995 PCI BIOS-32 detection - 1.3.28 5.36 17 Sep 1995 V3.61 BIOS; LILO command-line support - 1.3.34 5.39 12 Oct 1995 V3.60 BIOS; /proc - 1.3.72 5.39 8 Feb 1996 Adaptec AHA-2920 board - 1.3.85 5.41 4 Apr 1996 - 2.0.12 5.44 8 Aug 1996 Use ID 7 for all PCI cards - 2.1.1 5.45 2 Oct 1996 Update ROM accesses for 2.1.x - 2.1.97 5.46 23 Apr 1998 Rewritten PCI detection routines [mj] - 2.1.11x 5.47 9 Aug 1998 Touched for 8 SCSI disk majors support - 5.48 18 Nov 1998 BIOS no longer needed for PCI detection - 2.2.0 5.50 28 Dec 1998 Support insmod parameters - - - REFERENCES USED: - - "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation, - 1990. - - "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain - Corporation, January 1992. - - "LXT SCSI Products: Specifications and OEM Technical Manual (Revision - B/September 1991)", Maxtor Corporation, 1991. - - "7213S product Manual (Revision P3)", Maxtor Corporation, 1992. - - "Draft Proposed American National Standard: Small Computer System - Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109, - revision 10h, October 17, 1991) - - Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric - Youngdale (ericy@cais.com), 1992. - - Private communication, Tuong Le (Future Domain Engineering department), - 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and - TMC-18C30 detection.) - - Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page - 60 (2.39: Disk Partition Table Layout). - - "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page - 6-1. - - - - NOTES ON REFERENCES: - - The Maxtor manuals were free. Maxtor telephone technical support is - great! - - The Future Domain manuals were $25 and $35. They document the chip, not - the TMC-16x0 boards, so some information I had to guess at. In 1992, - Future Domain sold DOS BIOS source for $250 and the UN*X driver source was - $750, but these required a non-disclosure agreement, so even if I could - have afforded them, they would *not* have been useful for writing this - publicly distributable driver. Future Domain technical support has - provided some information on the phone and have sent a few useful FAXs. - They have been much more helpful since they started to recognize that the - word "Linux" refers to an operating system :-). - - - - ALPHA TESTERS: - - There are many other alpha testers that come and go as the driver - develops. The people listed here were most helpful in times of greatest - need (mostly early on -- I've probably left out a few worthy people in - more recent times): - - Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken - Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@bruin@sterbbs.nl), Sakari - Aaltonen (sakaria@vipunen.hit.fi), John Rice (rice@xanth.cs.odu.edu), Brad - Yearwood (brad@optilink.com), and Ray Toy (toy@soho.crd.ge.com). - - Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me - his 18C50-based card for debugging. He is the sole reason that this - driver works with the 18C50 chip. - - Thanks to Dave Newman (dnewman@crl.com) for providing initial patches for - the version 3.4 BIOS. - - Thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for providing - patches that support the TMC-3260, a PCI bus card with the 36C70 chip. - The 36C70 chip appears to be "completely compatible" with the 18C30 chip. - - Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the - patch for the version 3.5 BIOS. - - Thanks for Stephen Henson (shenson@nyx10.cs.du.edu) for providing the - patch for the Quantum ISA-200S SCSI adapter. - - Thanks to Adam Bowen for the signature to the 1610M/MER/MEX scsi cards, to - Martin Andrews (andrewm@ccfadm.eeg.ccf.org) for the signature to some - random TMC-1680 repackaged by IBM; and to Mintak Ng (mintak@panix.com) for - the version 3.61 BIOS signature. - - Thanks for Mark Singer (elf@netcom.com) and Richard Simpson - (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective - work on the Quantum RAM layout. - - Special thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for - providing patches for proper PCI BIOS32-mediated detection of the TMC-3260 - card (a PCI bus card with the 36C70 chip). Please send James PCI-related - bug reports. - - Thanks to Tom Cavin (tec@usa1.com) for preliminary command-line option - patches. - - New PCI detection code written by Martin Mares - - Insmod parameter code based on patches from Daniel Graham - . - - All of the alpha testers deserve much thanks. - - - - NOTES ON USER DEFINABLE OPTIONS: - - DEBUG: This turns on the printing of various debug information. - - ENABLE_PARITY: This turns on SCSI parity checking. With the current - driver, all attached devices must support SCSI parity. If none of your - devices support parity, then you can probably get the driver to work by - turning this option off. I have no way of testing this, however, and it - would appear that no one ever uses this option. - - FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the - 18C30 chip have a 2k cache). When this many 512 byte blocks are filled by - the SCSI device, an interrupt will be raised. Therefore, this could be as - low as 0, or as high as 16. Note, however, that values which are too high - or too low seem to prevent any interrupts from occurring, and thereby lock - up the machine. I have found that 2 is a good number, but throughput may - be increased by changing this value to values which are close to 2. - Please let me know if you try any different values. - - RESELECTION: This is no longer an option, since I gave up trying to - implement it in version 4.x of this driver. It did not improve - performance at all and made the driver unstable (because I never found one - of the two race conditions which were introduced by the multiple - outstanding command code). The instability seems a very high price to pay - just so that you don't have to wait for the tape to rewind. If you want - this feature implemented, send me patches. I'll be happy to send a copy - of my (broken) driver to anyone who would like to see a copy. - - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include -#include "fdomain.h" - -#ifndef PCMCIA -MODULE_AUTHOR("Rickard E. Faith"); -MODULE_DESCRIPTION("Future domain SCSI driver"); -MODULE_LICENSE("GPL"); -#endif - - -#define VERSION "$Revision: 5.51 $" - -/* START OF USER DEFINABLE OPTIONS */ - -#define DEBUG 0 /* Enable debugging output */ -#define ENABLE_PARITY 1 /* Enable SCSI Parity */ -#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */ - -/* END OF USER DEFINABLE OPTIONS */ - -#if DEBUG -#define EVERY_ACCESS 0 /* Write a line on every scsi access */ -#define ERRORS_ONLY 1 /* Only write a line if there is an error */ -#define DEBUG_DETECT 0 /* Debug fdomain_16x0_detect() */ -#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */ -#define DEBUG_ABORT 1 /* Debug abort() routine */ -#define DEBUG_RESET 1 /* Debug reset() routine */ -#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */ -#else -#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */ -#define ERRORS_ONLY 0 -#define DEBUG_DETECT 0 -#define DEBUG_MESSAGES 0 -#define DEBUG_ABORT 0 -#define DEBUG_RESET 0 -#define DEBUG_RACE 0 -#endif - -/* Errors are reported on the line, so we don't need to report them again */ -#if EVERY_ACCESS -#undef ERRORS_ONLY -#define ERRORS_ONLY 0 -#endif - -#if ENABLE_PARITY -#define PARITY_MASK 0x08 -#else -#define PARITY_MASK 0x00 -#endif - -enum chip_type { - unknown = 0x00, - tmc1800 = 0x01, - tmc18c50 = 0x02, - tmc18c30 = 0x03, -}; - -enum { - in_arbitration = 0x02, - in_selection = 0x04, - in_other = 0x08, - disconnect = 0x10, - aborted = 0x20, - sent_ident = 0x40, -}; - -enum in_port_type { - Read_SCSI_Data = 0, - SCSI_Status = 1, - TMC_Status = 2, - FIFO_Status = 3, /* tmc18c50/tmc18c30 only */ - Interrupt_Cond = 4, /* tmc18c50/tmc18c30 only */ - LSB_ID_Code = 5, - MSB_ID_Code = 6, - Read_Loopback = 7, - SCSI_Data_NoACK = 8, - Interrupt_Status = 9, - Configuration1 = 10, - Configuration2 = 11, /* tmc18c50/tmc18c30 only */ - Read_FIFO = 12, - FIFO_Data_Count = 14 -}; - -enum out_port_type { - Write_SCSI_Data = 0, - SCSI_Cntl = 1, - Interrupt_Cntl = 2, - SCSI_Mode_Cntl = 3, - TMC_Cntl = 4, - Memory_Cntl = 5, /* tmc18c50/tmc18c30 only */ - Write_Loopback = 7, - IO_Control = 11, /* tmc18c30 only */ - Write_FIFO = 12 -}; - -/* .bss will zero all the static variables below */ -static int port_base; -static unsigned long bios_base; -static void __iomem * bios_mem; -static int bios_major; -static int bios_minor; -static int PCI_bus; -#ifdef CONFIG_PCI -static struct pci_dev *PCI_dev; -#endif -static int Quantum; /* Quantum board variant */ -static int interrupt_level; -static volatile int in_command; -static struct scsi_cmnd *current_SC; -static enum chip_type chip = unknown; -static int adapter_mask; -static int this_id; -static int setup_called; - -#if DEBUG_RACE -static volatile int in_interrupt_flag; -#endif - -static int FIFO_Size = 0x2000; /* 8k FIFO for - pre-tmc18c30 chips */ - -static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id ); -/* Allow insmod parameters to be like LILO parameters. For example: - insmod fdomain fdomain=0x140,11 */ -static char * fdomain = NULL; -module_param(fdomain, charp, 0); - -#ifndef PCMCIA - -static unsigned long addresses[] = { - 0xc8000, - 0xca000, - 0xce000, - 0xde000, - 0xcc000, /* Extra addresses for PCI boards */ - 0xd0000, - 0xe0000, -}; -#define ADDRESS_COUNT ARRAY_SIZE(addresses) - -static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; -#define PORT_COUNT ARRAY_SIZE(ports) - -static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; - -#endif /* !PCMCIA */ - -/* - - READ THIS BEFORE YOU ADD A SIGNATURE! - - READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME! - - READ EVERY WORD, ESPECIALLY THE WORD *NOT* - - This driver works *ONLY* for Future Domain cards using the TMC-1800, - TMC-18C50, or TMC-18C30 chip. This includes models TMC-1650, 1660, 1670, - and 1680. These are all 16-bit cards. - - The following BIOS signature signatures are for boards which do *NOT* - work with this driver (these TMC-8xx and TMC-9xx boards may work with the - Seagate driver): - - FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88 - FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89 - FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89 - FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90 - FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90 - FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90 - FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92 - - (The cards which do *NOT* work are all 8-bit cards -- although some of - them have a 16-bit form-factor, the upper 8-bits are used only for IRQs - and are *NOT* used for data. You can tell the difference by following - the tracings on the circuit board -- if only the IRQ lines are involved, - you have a "8-bit" card, and should *NOT* use this driver.) - -*/ - -#ifndef PCMCIA - -static struct signature { - const char *signature; - int sig_offset; - int sig_length; - int major_bios_version; - int minor_bios_version; - int flag; /* 1 == PCI_bus, 2 == ISA_200S, 3 == ISA_250MG, 4 == ISA_200S */ -} signatures[] = { - /* 1 2 3 4 5 6 */ - /* 123456789012345678901234567890123456789012345678901234567890 */ - { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0, 0 }, - { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 2, 0, 0 }, - { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50, 2, 0, 2 }, - { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0", 73, 43, 2, 0, 3 }, - { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.", 72, 39, 2, 0, 4 }, - { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0, 0 }, - { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2, 0 }, - { "IBM F1 P2 BIOS v1.0104/29/93", 5, 28, 3, -1, 0 }, - { "Future Domain Corp. V1.0008/18/93", 5, 33, 3, 4, 0 }, - { "Future Domain Corp. V1.0008/18/93", 26, 33, 3, 4, 1 }, - { "Adaptec AHA-2920 PCI-SCSI Card", 42, 31, 3, -1, 1 }, - { "IBM F1 P264/32", 5, 14, 3, -1, 1 }, - /* This next signature may not be a 3.5 bios */ - { "Future Domain Corp. V2.0108/18/93", 5, 33, 3, 5, 0 }, - { "FUTURE DOMAIN CORP. V3.5008/18/93", 5, 34, 3, 5, 0 }, - { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5", 5, 44, 3, 5, 0 }, - { "FUTURE DOMAIN CORP. V3.6008/18/93", 5, 34, 3, 6, 0 }, - { "FUTURE DOMAIN CORP. V3.6108/18/93", 5, 34, 3, 6, 0 }, - { "FUTURE DOMAIN TMC-18XX", 5, 22, -1, -1, 0 }, - - /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGNATURE - Also, fix the disk geometry code for your signature and send your - changes for faith@cs.unc.edu. Above all, do *NOT* change any old - signatures! - - Note that the last line will match a "generic" 18XX bios. Because - Future Domain has changed the host SCSI ID and/or the location of the - geometry information in the on-board RAM area for each of the first - three BIOS's, it is still important to enter a fully qualified - signature in the table for any new BIOS's (after the host SCSI ID and - geometry location are verified). */ -}; - -#define SIGNATURE_COUNT ARRAY_SIZE(signatures) - -#endif /* !PCMCIA */ - -static void print_banner( struct Scsi_Host *shpnt ) -{ - if (!shpnt) return; /* This won't ever happen */ - - if (bios_major < 0 && bios_minor < 0) { - printk(KERN_INFO "scsi%d: No BIOS; using scsi id %d\n", - shpnt->host_no, shpnt->this_id); - } else { - printk(KERN_INFO "scsi%d: BIOS version ", shpnt->host_no); - - if (bios_major >= 0) printk("%d.", bios_major); - else printk("?."); - - if (bios_minor >= 0) printk("%d", bios_minor); - else printk("?."); - - printk( " at 0x%lx using scsi id %d\n", - bios_base, shpnt->this_id ); - } - - /* If this driver works for later FD PCI - boards, we will have to modify banner - for additional PCI cards, but for now if - it's PCI it's a TMC-3260 - JTM */ - printk(KERN_INFO "scsi%d: %s chip at 0x%x irq ", - shpnt->host_no, - chip == tmc1800 ? "TMC-1800" : (chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30") : "Unknown")), - port_base); - - if (interrupt_level) - printk("%d", interrupt_level); - else - printk(""); - - printk( "\n" ); -} - -int fdomain_setup(char *str) -{ - int ints[4]; - - (void)get_options(str, ARRAY_SIZE(ints), ints); - - if (setup_called++ || ints[0] < 2 || ints[0] > 3) { - printk(KERN_INFO "scsi: Usage: fdomain=,[,]\n"); - printk(KERN_ERR "scsi: Bad LILO/INSMOD parameters?\n"); - return 0; - } - - port_base = ints[0] >= 1 ? ints[1] : 0; - interrupt_level = ints[0] >= 2 ? ints[2] : 0; - this_id = ints[0] >= 3 ? ints[3] : 0; - - bios_major = bios_minor = -1; /* Use geometry for BIOS version >= 3.4 */ - ++setup_called; - return 1; -} - -__setup("fdomain=", fdomain_setup); - - -static void do_pause(unsigned amount) /* Pause for amount*10 milliseconds */ -{ - mdelay(10*amount); -} - -static inline void fdomain_make_bus_idle( void ) -{ - outb(0, port_base + SCSI_Cntl); - outb(0, port_base + SCSI_Mode_Cntl); - if (chip == tmc18c50 || chip == tmc18c30) - outb(0x21 | PARITY_MASK, port_base + TMC_Cntl); /* Clear forced intr. */ - else - outb(0x01 | PARITY_MASK, port_base + TMC_Cntl); -} - -static int fdomain_is_valid_port( int port ) -{ -#if DEBUG_DETECT - printk( " (%x%x),", - inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) ); -#endif - - /* The MCA ID is a unique id for each MCA compatible board. We - are using ISA boards, but Future Domain provides the MCA ID - anyway. We can use this ID to ensure that this is a Future - Domain TMC-1660/TMC-1680. - */ - - if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */ - if (inb( port + LSB_ID_Code ) != 0x27) return 0; - if (inb( port + MSB_ID_Code ) != 0x61) return 0; - chip = tmc1800; - } else { /* test for 0xe960 id */ - if (inb( port + MSB_ID_Code ) != 0x60) return 0; - chip = tmc18c50; - - /* Try to toggle 32-bit mode. This only - works on an 18c30 chip. (User reports - say this works, so we should switch to - it in the near future.) */ - - outb( 0x80, port + IO_Control ); - if ((inb( port + Configuration2 ) & 0x80) == 0x80) { - outb( 0x00, port + IO_Control ); - if ((inb( port + Configuration2 ) & 0x80) == 0x00) { - chip = tmc18c30; - FIFO_Size = 0x800; /* 2k FIFO */ - } - } - /* If that failed, we are an 18c50. */ - } - - return 1; -} - -static int fdomain_test_loopback( void ) -{ - int i; - int result; - - for (i = 0; i < 255; i++) { - outb( i, port_base + Write_Loopback ); - result = inb( port_base + Read_Loopback ); - if (i != result) - return 1; - } - return 0; -} - -#ifndef PCMCIA - -/* fdomain_get_irq assumes that we have a valid MCA ID for a - TMC-1660/TMC-1680 Future Domain board. Now, check to be sure the - bios_base matches these ports. If someone was unlucky enough to have - purchased more than one Future Domain board, then they will have to - modify this code, as we only detect one board here. [The one with the - lowest bios_base.] - - Note that this routine is only used for systems without a PCI BIOS32 - (e.g., ISA bus). For PCI bus systems, this routine will likely fail - unless one of the IRQs listed in the ints array is used by the board. - Sometimes it is possible to use the computer's BIOS setup screen to - configure a PCI system so that one of these IRQs will be used by the - Future Domain card. */ - -static int fdomain_get_irq( int base ) -{ - int options = inb(base + Configuration1); - -#if DEBUG_DETECT - printk("scsi: Options = %x\n", options); -#endif - - /* Check for board with lowest bios_base -- - this isn't valid for the 18c30 or for - boards on the PCI bus, so just assume we - have the right board. */ - - if (chip != tmc18c30 && !PCI_bus && addresses[(options & 0xc0) >> 6 ] != bios_base) - return 0; - return ints[(options & 0x0e) >> 1]; -} - -static int fdomain_isa_detect( int *irq, int *iobase ) -{ - int i, j; - int base = 0xdeadbeef; - int flag = 0; - -#if DEBUG_DETECT - printk( "scsi: fdomain_isa_detect:" ); -#endif - - for (i = 0; i < ADDRESS_COUNT; i++) { - void __iomem *p = ioremap(addresses[i], 0x2000); - if (!p) - continue; -#if DEBUG_DETECT - printk( " %lx(%lx),", addresses[i], bios_base ); -#endif - for (j = 0; j < SIGNATURE_COUNT; j++) { - if (check_signature(p + signatures[j].sig_offset, - signatures[j].signature, - signatures[j].sig_length )) { - bios_major = signatures[j].major_bios_version; - bios_minor = signatures[j].minor_bios_version; - PCI_bus = (signatures[j].flag == 1); - Quantum = (signatures[j].flag > 1) ? signatures[j].flag : 0; - bios_base = addresses[i]; - bios_mem = p; - goto found; - } - } - iounmap(p); - } - -found: - if (bios_major == 2) { - /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM. - Assuming the ROM is enabled (otherwise we wouldn't have been - able to read the ROM signature :-), then the ROM sets up the - RAM area with some magic numbers, such as a list of port - base addresses and a list of the disk "geometry" reported to - DOS (this geometry has nothing to do with physical geometry). - */ - - switch (Quantum) { - case 2: /* ISA_200S */ - case 3: /* ISA_250MG */ - base = readb(bios_mem + 0x1fa2) + (readb(bios_mem + 0x1fa3) << 8); - break; - case 4: /* ISA_200S (another one) */ - base = readb(bios_mem + 0x1fa3) + (readb(bios_mem + 0x1fa4) << 8); - break; - default: - base = readb(bios_mem + 0x1fcc) + (readb(bios_mem + 0x1fcd) << 8); - break; - } - -#if DEBUG_DETECT - printk( " %x,", base ); -#endif - - for (i = 0; i < PORT_COUNT; i++) { - if (base == ports[i]) { - if (!request_region(base, 0x10, "fdomain")) - break; - if (!fdomain_is_valid_port(base)) { - release_region(base, 0x10); - break; - } - *irq = fdomain_get_irq( base ); - *iobase = base; - return 1; - } - } - - /* This is a bad sign. It usually means that someone patched the - BIOS signature list (the signatures variable) to contain a BIOS - signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */ - -#if DEBUG_DETECT - printk( " RAM FAILED, " ); -#endif - } - - /* Anyway, the alternative to finding the address in the RAM is to just - search through every possible port address for one that is attached - to the Future Domain card. Don't panic, though, about reading all - these random port addresses -- there are rumors that the Future - Domain BIOS does something very similar. - - Do not, however, check ports which the kernel knows are being used by - another driver. */ - - for (i = 0; i < PORT_COUNT; i++) { - base = ports[i]; - if (!request_region(base, 0x10, "fdomain")) { -#if DEBUG_DETECT - printk( " (%x inuse),", base ); -#endif - continue; - } -#if DEBUG_DETECT - printk( " %x,", base ); -#endif - flag = fdomain_is_valid_port(base); - if (flag) - break; - release_region(base, 0x10); - } - -#if DEBUG_DETECT - if (flag) printk( " SUCCESS\n" ); - else printk( " FAILURE\n" ); -#endif - - if (!flag) return 0; /* iobase not found */ - - *irq = fdomain_get_irq( base ); - *iobase = base; - - return 1; /* success */ -} - -#else /* PCMCIA */ - -static int fdomain_isa_detect( int *irq, int *iobase ) -{ - if (irq) - *irq = 0; - if (iobase) - *iobase = 0; - return 0; -} - -#endif /* !PCMCIA */ - - -/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int* - iobase) This function gets the Interrupt Level and I/O base address from - the PCI configuration registers. */ - -#ifdef CONFIG_PCI -static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_pdev ) -{ - unsigned int pci_irq; /* PCI interrupt line */ - unsigned long pci_base; /* PCI I/O base address */ - struct pci_dev *pdev = NULL; - -#if DEBUG_DETECT - /* Tell how to print a list of the known PCI devices from bios32 and - list vendor and device IDs being used if in debug mode. */ - - printk( "scsi: INFO: use lspci -v to see list of PCI devices\n" ); - printk( "scsi: TMC-3260 detect:" - " Using Vendor ID: 0x%x and Device ID: 0x%x\n", - PCI_VENDOR_ID_FD, - PCI_DEVICE_ID_FD_36C70 ); -#endif - - if ((pdev = pci_get_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL) - return 0; - if (pci_enable_device(pdev)) - goto fail; - -#if DEBUG_DETECT - printk( "scsi: TMC-3260 detect:" - " PCI bus %u, device %u, function %u\n", - pdev->bus->number, - PCI_SLOT(pdev->devfn), - PCI_FUNC(pdev->devfn)); -#endif - - /* We now have the appropriate device function for the FD board so we - just read the PCI config info from the registers. */ - - pci_base = pci_resource_start(pdev, 0); - pci_irq = pdev->irq; - - if (!request_region( pci_base, 0x10, "fdomain" )) - goto fail; - - /* Now we have the I/O base address and interrupt from the PCI - configuration registers. */ - - *irq = pci_irq; - *iobase = pci_base; - *ret_pdev = pdev; - -#if DEBUG_DETECT - printk( "scsi: TMC-3260 detect:" - " IRQ = %d, I/O base = 0x%x [0x%lx]\n", *irq, *iobase, pci_base ); -#endif - - if (!fdomain_is_valid_port(pci_base)) { - printk(KERN_ERR "scsi: PCI card detected, but driver not loaded (invalid port)\n" ); - release_region(pci_base, 0x10); - goto fail; - } - - /* Fill in a few global variables. Ugh. */ - bios_major = bios_minor = -1; - PCI_bus = 1; - PCI_dev = pdev; - Quantum = 0; - bios_base = 0; - - return 1; -fail: - pci_dev_put(pdev); - return 0; -} - -#endif - -struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt ) -{ - int retcode; - struct Scsi_Host *shpnt; - struct pci_dev *pdev = NULL; - - if (setup_called) { -#if DEBUG_DETECT - printk( "scsi: No BIOS, using port_base = 0x%x, irq = %d\n", - port_base, interrupt_level ); -#endif - if (!request_region(port_base, 0x10, "fdomain")) { - printk( "scsi: port 0x%x is busy\n", port_base ); - printk( "scsi: Bad LILO/INSMOD parameters?\n" ); - return NULL; - } - if (!fdomain_is_valid_port( port_base )) { - printk( "scsi: Cannot locate chip at port base 0x%x\n", - port_base ); - printk( "scsi: Bad LILO/INSMOD parameters?\n" ); - release_region(port_base, 0x10); - return NULL; - } - } else { - int flag = 0; - -#ifdef CONFIG_PCI - /* Try PCI detection first */ - flag = fdomain_pci_bios_detect( &interrupt_level, &port_base, &pdev ); -#endif - if (!flag) { - /* Then try ISA bus detection */ - flag = fdomain_isa_detect( &interrupt_level, &port_base ); - - if (!flag) { - printk( "scsi: Detection failed (no card)\n" ); - return NULL; - } - } - } - - fdomain_16x0_bus_reset(NULL); - - if (fdomain_test_loopback()) { - printk(KERN_ERR "scsi: Detection failed (loopback test failed at port base 0x%x)\n", port_base); - if (setup_called) { - printk(KERN_ERR "scsi: Bad LILO/INSMOD parameters?\n"); - } - goto fail; - } - - if (this_id) { - tpnt->this_id = (this_id & 0x07); - adapter_mask = (1 << tpnt->this_id); - } else { - if (PCI_bus || (bios_major == 3 && bios_minor >= 2) || bios_major < 0) { - tpnt->this_id = 7; - adapter_mask = 0x80; - } else { - tpnt->this_id = 6; - adapter_mask = 0x40; - } - } - -/* Print out a banner here in case we can't - get resources. */ - - shpnt = scsi_register( tpnt, 0 ); - if(shpnt == NULL) { - release_region(port_base, 0x10); - return NULL; - } - shpnt->irq = interrupt_level; - shpnt->io_port = port_base; - shpnt->n_io_port = 0x10; - print_banner( shpnt ); - - /* Log IRQ with kernel */ - if (!interrupt_level) { - printk(KERN_ERR "scsi: Card Detected, but driver not loaded (no IRQ)\n" ); - goto fail; - } else { - /* Register the IRQ with the kernel */ - - retcode = request_irq( interrupt_level, - do_fdomain_16x0_intr, pdev?IRQF_SHARED:0, "fdomain", shpnt); - - if (retcode < 0) { - if (retcode == -EINVAL) { - printk(KERN_ERR "scsi: IRQ %d is bad!\n", interrupt_level ); - printk(KERN_ERR " This shouldn't happen!\n" ); - printk(KERN_ERR " Send mail to faith@acm.org\n" ); - } else if (retcode == -EBUSY) { - printk(KERN_ERR "scsi: IRQ %d is already in use!\n", interrupt_level ); - printk(KERN_ERR " Please use another IRQ!\n" ); - } else { - printk(KERN_ERR "scsi: Error getting IRQ %d\n", interrupt_level ); - printk(KERN_ERR " This shouldn't happen!\n" ); - printk(KERN_ERR " Send mail to faith@acm.org\n" ); - } - printk(KERN_ERR "scsi: Detected, but driver not loaded (IRQ)\n" ); - goto fail; - } - } - return shpnt; -fail: - pci_dev_put(pdev); - release_region(port_base, 0x10); - return NULL; -} - -static int fdomain_16x0_detect(struct scsi_host_template *tpnt) -{ - if (fdomain) - fdomain_setup(fdomain); - return (__fdomain_16x0_detect(tpnt) != NULL); -} - -static const char *fdomain_16x0_info( struct Scsi_Host *ignore ) -{ - static char buffer[128]; - char *pt; - - strcpy( buffer, "Future Domain 16-bit SCSI Driver Version" ); - if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */ - strcat( buffer, strchr( VERSION, ':' ) + 1 ); - pt = strrchr( buffer, '$') - 1; - if (!pt) /* Stripped RCS Revision string? */ - pt = buffer + strlen( buffer ) - 1; - if (*pt != ' ') - ++pt; - *pt = '\0'; - } else { /* Assume VERSION is a number */ - strcat( buffer, " " VERSION ); - } - - return buffer; -} - -#if 0 -static int fdomain_arbitrate( void ) -{ - int status = 0; - unsigned long timeout; - -#if EVERY_ACCESS - printk( "fdomain_arbitrate()\n" ); -#endif - - outb(0x00, port_base + SCSI_Cntl); /* Disable data drivers */ - outb(adapter_mask, port_base + SCSI_Data_NoACK); /* Set our id bit */ - outb(0x04 | PARITY_MASK, port_base + TMC_Cntl); /* Start arbitration */ - - timeout = 500; - do { - status = inb(port_base + TMC_Status); /* Read adapter status */ - if (status & 0x02) /* Arbitration complete */ - return 0; - mdelay(1); /* Wait one millisecond */ - } while (--timeout); - - /* Make bus idle */ - fdomain_make_bus_idle(); - -#if EVERY_ACCESS - printk( "Arbitration failed, status = %x\n", status ); -#endif -#if ERRORS_ONLY - printk( "scsi: Arbitration failed, status = %x\n", status ); -#endif - return 1; -} -#endif - -static int fdomain_select( int target ) -{ - int status; - unsigned long timeout; -#if ERRORS_ONLY - static int flag = 0; -#endif - - outb(0x82, port_base + SCSI_Cntl); /* Bus Enable + Select */ - outb(adapter_mask | (1 << target), port_base + SCSI_Data_NoACK); - - /* Stop arbitration and enable parity */ - outb(PARITY_MASK, port_base + TMC_Cntl); - - timeout = 350; /* 350 msec */ - - do { - status = inb(port_base + SCSI_Status); /* Read adapter status */ - if (status & 1) { /* Busy asserted */ - /* Enable SCSI Bus (on error, should make bus idle with 0) */ - outb(0x80, port_base + SCSI_Cntl); - return 0; - } - mdelay(1); /* wait one msec */ - } while (--timeout); - /* Make bus idle */ - fdomain_make_bus_idle(); -#if EVERY_ACCESS - if (!target) printk( "Selection failed\n" ); -#endif -#if ERRORS_ONLY - if (!target) { - if (!flag) /* Skip first failure for all chips. */ - ++flag; - else - printk( "scsi: Selection failed\n" ); - } -#endif - return 1; -} - -static void my_done(int error) -{ - if (in_command) { - in_command = 0; - outb(0x00, port_base + Interrupt_Cntl); - fdomain_make_bus_idle(); - current_SC->result = error; - if (current_SC->scsi_done) - current_SC->scsi_done( current_SC ); - else panic( "scsi: current_SC->scsi_done() == NULL" ); - } else { - panic( "scsi: my_done() called outside of command\n" ); - } -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif -} - -static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id) -{ - unsigned long flags; - int status; - int done = 0; - unsigned data_count; - - /* The fdomain_16x0_intr is only called via - the interrupt handler. The goal of the - sti() here is to allow other - interruptions while this routine is - running. */ - - /* Check for other IRQ sources */ - if ((inb(port_base + TMC_Status) & 0x01) == 0) - return IRQ_NONE; - - /* It is our IRQ */ - outb(0x00, port_base + Interrupt_Cntl); - - /* We usually have one spurious interrupt after each command. Ignore it. */ - if (!in_command || !current_SC) { /* Spurious interrupt */ -#if EVERY_ACCESS - printk( "Spurious interrupt, in_command = %d, current_SC = %x\n", - in_command, current_SC ); -#endif - return IRQ_NONE; - } - - /* Abort calls my_done, so we do nothing here. */ - if (current_SC->SCp.phase & aborted) { -#if DEBUG_ABORT - printk( "scsi: Interrupt after abort, ignoring\n" ); -#endif - /* - return IRQ_HANDLED; */ - } - -#if DEBUG_RACE - ++in_interrupt_flag; -#endif - - if (current_SC->SCp.phase & in_arbitration) { - status = inb(port_base + TMC_Status); /* Read adapter status */ - if (!(status & 0x02)) { -#if EVERY_ACCESS - printk( " AFAIL " ); -#endif - spin_lock_irqsave(current_SC->device->host->host_lock, flags); - my_done( DID_BUS_BUSY << 16 ); - spin_unlock_irqrestore(current_SC->device->host->host_lock, flags); - return IRQ_HANDLED; - } - current_SC->SCp.phase = in_selection; - - outb(0x40 | FIFO_COUNT, port_base + Interrupt_Cntl); - - outb(0x82, port_base + SCSI_Cntl); /* Bus Enable + Select */ - outb(adapter_mask | (1 << scmd_id(current_SC)), port_base + SCSI_Data_NoACK); - - /* Stop arbitration and enable parity */ - outb(0x10 | PARITY_MASK, port_base + TMC_Cntl); -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; - } else if (current_SC->SCp.phase & in_selection) { - status = inb(port_base + SCSI_Status); - if (!(status & 0x01)) { - /* Try again, for slow devices */ - if (fdomain_select( scmd_id(current_SC) )) { -#if EVERY_ACCESS - printk( " SFAIL " ); -#endif - spin_lock_irqsave(current_SC->device->host->host_lock, flags); - my_done( DID_NO_CONNECT << 16 ); - spin_unlock_irqrestore(current_SC->device->host->host_lock, flags); - return IRQ_HANDLED; - } else { -#if EVERY_ACCESS - printk( " AltSel " ); -#endif - /* Stop arbitration and enable parity */ - outb(0x10 | PARITY_MASK, port_base + TMC_Cntl); - } - } - current_SC->SCp.phase = in_other; - outb(0x90 | FIFO_COUNT, port_base + Interrupt_Cntl); - outb(0x80, port_base + SCSI_Cntl); -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; - } - - /* current_SC->SCp.phase == in_other: this is the body of the routine */ - - status = inb(port_base + SCSI_Status); - - if (status & 0x10) { /* REQ */ - - switch (status & 0x0e) { - - case 0x08: /* COMMAND OUT */ - outb(current_SC->cmnd[current_SC->SCp.sent_command++], - port_base + Write_SCSI_Data); -#if EVERY_ACCESS - printk( "CMD = %x,", - current_SC->cmnd[ current_SC->SCp.sent_command - 1] ); -#endif - break; - case 0x00: /* DATA OUT -- tmc18c50/tmc18c30 only */ - if (chip != tmc1800 && !current_SC->SCp.have_data_in) { - current_SC->SCp.have_data_in = -1; - outb(0xd0 | PARITY_MASK, port_base + TMC_Cntl); - } - break; - case 0x04: /* DATA IN -- tmc18c50/tmc18c30 only */ - if (chip != tmc1800 && !current_SC->SCp.have_data_in) { - current_SC->SCp.have_data_in = 1; - outb(0x90 | PARITY_MASK, port_base + TMC_Cntl); - } - break; - case 0x0c: /* STATUS IN */ - current_SC->SCp.Status = inb(port_base + Read_SCSI_Data); -#if EVERY_ACCESS - printk( "Status = %x, ", current_SC->SCp.Status ); -#endif -#if ERRORS_ONLY - if (current_SC->SCp.Status - && current_SC->SCp.Status != 2 - && current_SC->SCp.Status != 8) { - printk( "scsi: target = %d, command = %x, status = %x\n", - current_SC->device->id, - current_SC->cmnd[0], - current_SC->SCp.Status ); - } -#endif - break; - case 0x0a: /* MESSAGE OUT */ - outb(MESSAGE_REJECT, port_base + Write_SCSI_Data); /* Reject */ - break; - case 0x0e: /* MESSAGE IN */ - current_SC->SCp.Message = inb(port_base + Read_SCSI_Data); -#if EVERY_ACCESS - printk( "Message = %x, ", current_SC->SCp.Message ); -#endif - if (!current_SC->SCp.Message) ++done; -#if DEBUG_MESSAGES || EVERY_ACCESS - if (current_SC->SCp.Message) { - printk( "scsi: message = %x\n", - current_SC->SCp.Message ); - } -#endif - break; - } - } - - if (chip == tmc1800 && !current_SC->SCp.have_data_in - && (current_SC->SCp.sent_command >= current_SC->cmd_len)) { - - if(current_SC->sc_data_direction == DMA_TO_DEVICE) - { - current_SC->SCp.have_data_in = -1; - outb(0xd0 | PARITY_MASK, port_base + TMC_Cntl); - } - else - { - current_SC->SCp.have_data_in = 1; - outb(0x90 | PARITY_MASK, port_base + TMC_Cntl); - } - } - - if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */ - while ((data_count = FIFO_Size - inw(port_base + FIFO_Data_Count)) > 512) { -#if EVERY_ACCESS - printk( "DC=%d, ", data_count ) ; -#endif - if (data_count > current_SC->SCp.this_residual) - data_count = current_SC->SCp.this_residual; - if (data_count > 0) { -#if EVERY_ACCESS - printk( "%d OUT, ", data_count ); -#endif - if (data_count == 1) { - outb(*current_SC->SCp.ptr++, port_base + Write_FIFO); - --current_SC->SCp.this_residual; - } else { - data_count >>= 1; - outsw(port_base + Write_FIFO, current_SC->SCp.ptr, data_count); - current_SC->SCp.ptr += 2 * data_count; - current_SC->SCp.this_residual -= 2 * data_count; - } - } - if (!current_SC->SCp.this_residual) { - if (current_SC->SCp.buffers_residual) { - --current_SC->SCp.buffers_residual; - ++current_SC->SCp.buffer; - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - } else - break; - } - } - } - - if (current_SC->SCp.have_data_in == 1) { /* DATA IN */ - while ((data_count = inw(port_base + FIFO_Data_Count)) > 0) { -#if EVERY_ACCESS - printk( "DC=%d, ", data_count ); -#endif - if (data_count > current_SC->SCp.this_residual) - data_count = current_SC->SCp.this_residual; - if (data_count) { -#if EVERY_ACCESS - printk( "%d IN, ", data_count ); -#endif - if (data_count == 1) { - *current_SC->SCp.ptr++ = inb(port_base + Read_FIFO); - --current_SC->SCp.this_residual; - } else { - data_count >>= 1; /* Number of words */ - insw(port_base + Read_FIFO, current_SC->SCp.ptr, data_count); - current_SC->SCp.ptr += 2 * data_count; - current_SC->SCp.this_residual -= 2 * data_count; - } - } - if (!current_SC->SCp.this_residual - && current_SC->SCp.buffers_residual) { - --current_SC->SCp.buffers_residual; - ++current_SC->SCp.buffer; - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - } - } - } - - if (done) { -#if EVERY_ACCESS - printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in ); -#endif - -#if ERRORS_ONLY - if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) { - char *buf = scsi_sglist(current_SC); - if ((unsigned char)(*(buf + 2)) & 0x0f) { - unsigned char key; - unsigned char code; - unsigned char qualifier; - - key = (unsigned char)(*(buf + 2)) & 0x0f; - code = (unsigned char)(*(buf + 12)); - qualifier = (unsigned char)(*(buf + 13)); - - if (key != UNIT_ATTENTION - && !(key == NOT_READY - && code == 0x04 - && (!qualifier || qualifier == 0x02 || qualifier == 0x01)) - && !(key == ILLEGAL_REQUEST && (code == 0x25 - || code == 0x24 - || !code))) - - printk( "scsi: REQUEST SENSE" - " Key = %x, Code = %x, Qualifier = %x\n", - key, code, qualifier ); - } - } -#endif -#if EVERY_ACCESS - printk( "BEFORE MY_DONE. . ." ); -#endif - spin_lock_irqsave(current_SC->device->host->host_lock, flags); - my_done( (current_SC->SCp.Status & 0xff) - | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) ); - spin_unlock_irqrestore(current_SC->device->host->host_lock, flags); -#if EVERY_ACCESS - printk( "RETURNING.\n" ); -#endif - - } else { - if (current_SC->SCp.phase & disconnect) { - outb(0xd0 | FIFO_COUNT, port_base + Interrupt_Cntl); - outb(0x00, port_base + SCSI_Cntl); - } else { - outb(0x90 | FIFO_COUNT, port_base + Interrupt_Cntl); - } - } -#if DEBUG_RACE - in_interrupt_flag = 0; -#endif - return IRQ_HANDLED; -} - -static int fdomain_16x0_queue_lck(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - if (in_command) { - panic( "scsi: fdomain_16x0_queue() NOT REENTRANT!\n" ); - } -#if EVERY_ACCESS - printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", - SCpnt->target, - *(unsigned char *)SCpnt->cmnd, - scsi_sg_count(SCpnt), - scsi_bufflen(SCpnt)); -#endif - - fdomain_make_bus_idle(); - - current_SC = SCpnt; /* Save this for the done function */ - current_SC->scsi_done = done; - - /* Initialize static data */ - - if (scsi_sg_count(current_SC)) { - current_SC->SCp.buffer = scsi_sglist(current_SC); - current_SC->SCp.ptr = sg_virt(current_SC->SCp.buffer); - current_SC->SCp.this_residual = current_SC->SCp.buffer->length; - current_SC->SCp.buffers_residual = scsi_sg_count(current_SC) - 1; - } else { - current_SC->SCp.ptr = NULL; - current_SC->SCp.this_residual = 0; - current_SC->SCp.buffer = NULL; - current_SC->SCp.buffers_residual = 0; - } - - current_SC->SCp.Status = 0; - current_SC->SCp.Message = 0; - current_SC->SCp.have_data_in = 0; - current_SC->SCp.sent_command = 0; - current_SC->SCp.phase = in_arbitration; - - /* Start arbitration */ - outb(0x00, port_base + Interrupt_Cntl); - outb(0x00, port_base + SCSI_Cntl); /* Disable data drivers */ - outb(adapter_mask, port_base + SCSI_Data_NoACK); /* Set our id bit */ - ++in_command; - outb(0x20, port_base + Interrupt_Cntl); - outb(0x14 | PARITY_MASK, port_base + TMC_Cntl); /* Start arbitration */ - - return 0; -} - -static DEF_SCSI_QCMD(fdomain_16x0_queue) - -#if DEBUG_ABORT -static void print_info(struct scsi_cmnd *SCpnt) -{ - unsigned int imr; - unsigned int irr; - unsigned int isr; - - if (!SCpnt || !SCpnt->device || !SCpnt->device->host) { - printk(KERN_WARNING "scsi: Cannot provide detailed information\n"); - return; - } - - printk(KERN_INFO "%s\n", fdomain_16x0_info( SCpnt->device->host ) ); - print_banner(SCpnt->device->host); - switch (SCpnt->SCp.phase) { - case in_arbitration: printk("arbitration"); break; - case in_selection: printk("selection"); break; - case in_other: printk("other"); break; - default: printk("unknown"); break; - } - - printk( " (%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", - SCpnt->SCp.phase, - SCpnt->device->id, - *(unsigned char *)SCpnt->cmnd, - scsi_sg_count(SCpnt), - scsi_bufflen(SCpnt)); - printk( "sent_command = %d, have_data_in = %d, timeout = %d\n", - SCpnt->SCp.sent_command, - SCpnt->SCp.have_data_in, - SCpnt->timeout ); -#if DEBUG_RACE - printk( "in_interrupt_flag = %d\n", in_interrupt_flag ); -#endif - - imr = (inb( 0x0a1 ) << 8) + inb( 0x21 ); - outb( 0x0a, 0xa0 ); - irr = inb( 0xa0 ) << 8; - outb( 0x0a, 0x20 ); - irr += inb( 0x20 ); - outb( 0x0b, 0xa0 ); - isr = inb( 0xa0 ) << 8; - outb( 0x0b, 0x20 ); - isr += inb( 0x20 ); - - /* Print out interesting information */ - printk( "IMR = 0x%04x", imr ); - if (imr & (1 << interrupt_level)) - printk( " (masked)" ); - printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr ); - - printk( "SCSI Status = 0x%02x\n", inb(port_base + SCSI_Status)); - printk( "TMC Status = 0x%02x", inb(port_base + TMC_Status)); - if (inb((port_base + TMC_Status) & 1)) - printk( " (interrupt)" ); - printk( "\n" ); - printk("Interrupt Status = 0x%02x", inb(port_base + Interrupt_Status)); - if (inb(port_base + Interrupt_Status) & 0x08) - printk( " (enabled)" ); - printk( "\n" ); - if (chip == tmc18c50 || chip == tmc18c30) { - printk("FIFO Status = 0x%02x\n", inb(port_base + FIFO_Status)); - printk( "Int. Condition = 0x%02x\n", - inb( port_base + Interrupt_Cond ) ); - } - printk( "Configuration 1 = 0x%02x\n", inb( port_base + Configuration1 ) ); - if (chip == tmc18c50 || chip == tmc18c30) - printk( "Configuration 2 = 0x%02x\n", - inb( port_base + Configuration2 ) ); -} -#endif - -static int fdomain_16x0_abort(struct scsi_cmnd *SCpnt) -{ -#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT - printk( "scsi: abort " ); -#endif - - if (!in_command) { -#if EVERY_ACCESS || ERRORS_ONLY - printk( " (not in command)\n" ); -#endif - return FAILED; - } else printk( "\n" ); - -#if DEBUG_ABORT - print_info( SCpnt ); -#endif - - fdomain_make_bus_idle(); - current_SC->SCp.phase |= aborted; - current_SC->result = DID_ABORT << 16; - - /* Aborts are not done well. . . */ - my_done(DID_ABORT << 16); - return SUCCESS; -} - -int fdomain_16x0_bus_reset(struct scsi_cmnd *SCpnt) -{ - unsigned long flags; - - local_irq_save(flags); - - outb(1, port_base + SCSI_Cntl); - do_pause( 2 ); - outb(0, port_base + SCSI_Cntl); - do_pause( 115 ); - outb(0, port_base + SCSI_Mode_Cntl); - outb(PARITY_MASK, port_base + TMC_Cntl); - - local_irq_restore(flags); - return SUCCESS; -} - -static int fdomain_16x0_biosparam(struct scsi_device *sdev, - struct block_device *bdev, - sector_t capacity, int *info_array) -{ - int drive; - int size = capacity; - unsigned long offset; - struct drive_info { - unsigned short cylinders; - unsigned char heads; - unsigned char sectors; - } i; - - /* NOTES: - The RAM area starts at 0x1f00 from the bios_base address. - - For BIOS Version 2.0: - - The drive parameter table seems to start at 0x1f30. - The first byte's purpose is not known. - Next is the cylinder, head, and sector information. - The last 4 bytes appear to be the drive's size in sectors. - The other bytes in the drive parameter table are unknown. - If anyone figures them out, please send me mail, and I will - update these notes. - - Tape drives do not get placed in this table. - - There is another table at 0x1fea: - If the byte is 0x01, then the SCSI ID is not in use. - If the byte is 0x18 or 0x48, then the SCSI ID is in use, - although tapes don't seem to be in this table. I haven't - seen any other numbers (in a limited sample). - - 0x1f2d is a drive count (i.e., not including tapes) - - The table at 0x1fcc are I/O ports addresses for the various - operations. I calculate these by hand in this driver code. - - - - For the ISA-200S version of BIOS Version 2.0: - - The drive parameter table starts at 0x1f33. - - WARNING: Assume that the table entry is 25 bytes long. Someone needs - to check this for the Quantum ISA-200S card. - - - - For BIOS Version 3.2: - - The drive parameter table starts at 0x1f70. Each entry is - 0x0a bytes long. Heads are one less than we need to report. - */ - - if (MAJOR(bdev->bd_dev) != SCSI_DISK0_MAJOR) { - printk("scsi: fdomain_16x0_biosparam: too many disks"); - return 0; - } - drive = MINOR(bdev->bd_dev) >> 4; - - if (bios_major == 2) { - switch (Quantum) { - case 2: /* ISA_200S */ - /* The value of 25 has never been verified. - It should probably be 15. */ - offset = 0x1f33 + drive * 25; - break; - case 3: /* ISA_250MG */ - offset = 0x1f36 + drive * 15; - break; - case 4: /* ISA_200S (another one) */ - offset = 0x1f34 + drive * 15; - break; - default: - offset = 0x1f31 + drive * 25; - break; - } - memcpy_fromio( &i, bios_mem + offset, sizeof( struct drive_info ) ); - info_array[0] = i.heads; - info_array[1] = i.sectors; - info_array[2] = i.cylinders; - } else if (bios_major == 3 - && bios_minor >= 0 - && bios_minor < 4) { /* 3.0 and 3.2 BIOS */ - memcpy_fromio( &i, bios_mem + 0x1f71 + drive * 10, - sizeof( struct drive_info ) ); - info_array[0] = i.heads + 1; - info_array[1] = i.sectors; - info_array[2] = i.cylinders; - } else { /* 3.4 BIOS (and up?) */ - /* This algorithm was provided by Future Domain (much thanks!). */ - unsigned char *p = scsi_bios_ptable(bdev); - - if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */ - && p[4]) { /* Partition type */ - - /* The partition table layout is as follows: - - Start: 0x1b3h - Offset: 0 = partition status - 1 = starting head - 2 = starting sector and cylinder (word, encoded) - 4 = partition type - 5 = ending head - 6 = ending sector and cylinder (word, encoded) - 8 = starting absolute sector (double word) - c = number of sectors (double word) - Signature: 0x1fe = 0x55aa - - So, this algorithm assumes: - 1) the first partition table is in use, - 2) the data in the first entry is correct, and - 3) partitions never divide cylinders - - Note that (1) may be FALSE for NetBSD (and other BSD flavors), - as well as for Linux. Note also, that Linux doesn't pay any - attention to the fields that are used by this algorithm -- it - only uses the absolute sector data. Recent versions of Linux's - fdisk(1) will fill this data in correctly, and forthcoming - versions will check for consistency. - - Checking for a non-zero partition type is not part of the - Future Domain algorithm, but it seemed to be a reasonable thing - to do, especially in the Linux and BSD worlds. */ - - info_array[0] = p[5] + 1; /* heads */ - info_array[1] = p[6] & 0x3f; /* sectors */ - } else { - - /* Note that this new method guarantees that there will always be - less than 1024 cylinders on a platter. This is good for drives - up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */ - - if ((unsigned int)size >= 0x7e0000U) { - info_array[0] = 0xff; /* heads = 255 */ - info_array[1] = 0x3f; /* sectors = 63 */ - } else if ((unsigned int)size >= 0x200000U) { - info_array[0] = 0x80; /* heads = 128 */ - info_array[1] = 0x3f; /* sectors = 63 */ - } else { - info_array[0] = 0x40; /* heads = 64 */ - info_array[1] = 0x20; /* sectors = 32 */ - } - } - /* For both methods, compute the cylinders */ - info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] ); - kfree(p); - } - - return 0; -} - -static int fdomain_16x0_release(struct Scsi_Host *shpnt) -{ - if (shpnt->irq) - free_irq(shpnt->irq, shpnt); - if (shpnt->io_port && shpnt->n_io_port) - release_region(shpnt->io_port, shpnt->n_io_port); - if (PCI_bus) - pci_dev_put(PCI_dev); - return 0; -} - -struct scsi_host_template fdomain_driver_template = { - .module = THIS_MODULE, - .name = "fdomain", - .proc_name = "fdomain", - .detect = fdomain_16x0_detect, - .info = fdomain_16x0_info, - .queuecommand = fdomain_16x0_queue, - .eh_abort_handler = fdomain_16x0_abort, - .eh_bus_reset_handler = fdomain_16x0_bus_reset, - .bios_param = fdomain_16x0_biosparam, - .release = fdomain_16x0_release, - .can_queue = 1, - .this_id = 6, - .sg_tablesize = 64, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; - -#ifndef PCMCIA -#ifdef CONFIG_PCI - -static struct pci_device_id fdomain_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { } -}; -MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl); -#endif -#define driver_template fdomain_driver_template -#include "scsi_module.c" - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/fdomain.h b/ANDROID_3.4.5/drivers/scsi/fdomain.h deleted file mode 100644 index 47021d9d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fdomain.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * fdomain.c -- Future Domain TMC-16x0 SCSI driver - * Author: Rickard E. Faith, faith@cs.unc.edu - * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -extern struct scsi_host_template fdomain_driver_template; -extern int fdomain_setup(char *str); -extern struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt ); -extern int fdomain_16x0_bus_reset(struct scsi_cmnd *SCpnt); diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/Makefile b/ANDROID_3.4.5/drivers/scsi/fnic/Makefile deleted file mode 100644 index 37c3440b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -obj-$(CONFIG_FCOE_FNIC) += fnic.o - -fnic-y := \ - fnic_attrs.o \ - fnic_isr.o \ - fnic_main.o \ - fnic_res.o \ - fnic_fcs.o \ - fnic_scsi.o \ - vnic_cq.o \ - vnic_dev.o \ - vnic_intr.o \ - vnic_rq.o \ - vnic_wq_copy.o \ - vnic_wq.o diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/cq_desc.h b/ANDROID_3.4.5/drivers/scsi/fnic/cq_desc.h deleted file mode 100644 index d1225cf6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/cq_desc.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _CQ_DESC_H_ -#define _CQ_DESC_H_ - -/* - * Completion queue descriptor types - */ -enum cq_desc_types { - CQ_DESC_TYPE_WQ_ENET = 0, - CQ_DESC_TYPE_DESC_COPY = 1, - CQ_DESC_TYPE_WQ_EXCH = 2, - CQ_DESC_TYPE_RQ_ENET = 3, - CQ_DESC_TYPE_RQ_FCP = 4, -}; - -/* Completion queue descriptor: 16B - * - * All completion queues have this basic layout. The - * type_specfic area is unique for each completion - * queue type. - */ -struct cq_desc { - __le16 completed_index; - __le16 q_number; - u8 type_specfic[11]; - u8 type_color; -}; - -#define CQ_DESC_TYPE_BITS 4 -#define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1) -#define CQ_DESC_COLOR_MASK 1 -#define CQ_DESC_COLOR_SHIFT 7 -#define CQ_DESC_Q_NUM_BITS 10 -#define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1) -#define CQ_DESC_COMP_NDX_BITS 12 -#define CQ_DESC_COMP_NDX_MASK ((1 << CQ_DESC_COMP_NDX_BITS) - 1) - -static inline void cq_desc_dec(const struct cq_desc *desc_arg, - u8 *type, u8 *color, u16 *q_number, u16 *completed_index) -{ - const struct cq_desc *desc = desc_arg; - const u8 type_color = desc->type_color; - - *color = (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK; - - /* - * Make sure color bit is read from desc *before* other fields - * are read from desc. Hardware guarantees color bit is last - * bit (byte) written. Adding the rmb() prevents the compiler - * and/or CPU from reordering the reads which would potentially - * result in reading stale values. - */ - - rmb(); - - *type = type_color & CQ_DESC_TYPE_MASK; - *q_number = le16_to_cpu(desc->q_number) & CQ_DESC_Q_NUM_MASK; - *completed_index = le16_to_cpu(desc->completed_index) & - CQ_DESC_COMP_NDX_MASK; -} - -#endif /* _CQ_DESC_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/cq_enet_desc.h b/ANDROID_3.4.5/drivers/scsi/fnic/cq_enet_desc.h deleted file mode 100644 index a9fa26f8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/cq_enet_desc.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _CQ_ENET_DESC_H_ -#define _CQ_ENET_DESC_H_ - -#include "cq_desc.h" - -/* Ethernet completion queue descriptor: 16B */ -struct cq_enet_wq_desc { - __le16 completed_index; - __le16 q_number; - u8 reserved[11]; - u8 type_color; -}; - -static inline void cq_enet_wq_desc_dec(struct cq_enet_wq_desc *desc, - u8 *type, u8 *color, u16 *q_number, u16 *completed_index) -{ - cq_desc_dec((struct cq_desc *)desc, type, - color, q_number, completed_index); -} - -/* Completion queue descriptor: Ethernet receive queue, 16B */ -struct cq_enet_rq_desc { - __le16 completed_index_flags; - __le16 q_number_rss_type_flags; - __le32 rss_hash; - __le16 bytes_written_flags; - __le16 vlan; - __le16 checksum_fcoe; - u8 flags; - u8 type_color; -}; - -#define CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT (0x1 << 12) -#define CQ_ENET_RQ_DESC_FLAGS_FCOE (0x1 << 13) -#define CQ_ENET_RQ_DESC_FLAGS_EOP (0x1 << 14) -#define CQ_ENET_RQ_DESC_FLAGS_SOP (0x1 << 15) - -#define CQ_ENET_RQ_DESC_RSS_TYPE_BITS 4 -#define CQ_ENET_RQ_DESC_RSS_TYPE_MASK \ - ((1 << CQ_ENET_RQ_DESC_RSS_TYPE_BITS) - 1) -#define CQ_ENET_RQ_DESC_RSS_TYPE_NONE 0 -#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv4 1 -#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4 2 -#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6 3 -#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6 4 -#define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6_EX 5 -#define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6_EX 6 - -#define CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC (0x1 << 14) - -#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS 14 -#define CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK \ - ((1 << CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS) - 1) -#define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED (0x1 << 14) -#define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED (0x1 << 15) - -#define CQ_ENET_RQ_DESC_FCOE_SOF_BITS 4 -#define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \ - ((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1) -#define CQ_ENET_RQ_DESC_FCOE_EOF_BITS 8 -#define CQ_ENET_RQ_DESC_FCOE_EOF_MASK \ - ((1 << CQ_ENET_RQ_DESC_FCOE_EOF_BITS) - 1) -#define CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT 8 - -#define CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK (0x1 << 0) -#define CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK (0x1 << 0) -#define CQ_ENET_RQ_DESC_FLAGS_UDP (0x1 << 1) -#define CQ_ENET_RQ_DESC_FCOE_ENC_ERROR (0x1 << 1) -#define CQ_ENET_RQ_DESC_FLAGS_TCP (0x1 << 2) -#define CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK (0x1 << 3) -#define CQ_ENET_RQ_DESC_FLAGS_IPV6 (0x1 << 4) -#define CQ_ENET_RQ_DESC_FLAGS_IPV4 (0x1 << 5) -#define CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT (0x1 << 6) -#define CQ_ENET_RQ_DESC_FLAGS_FCS_OK (0x1 << 7) - -static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc, - u8 *type, u8 *color, u16 *q_number, u16 *completed_index, - u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type, - u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error, - u8 *vlan_stripped, u16 *vlan, u16 *checksum, u8 *fcoe_sof, - u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof, - u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok, - u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok) -{ - u16 completed_index_flags = le16_to_cpu(desc->completed_index_flags); - u16 q_number_rss_type_flags = - le16_to_cpu(desc->q_number_rss_type_flags); - u16 bytes_written_flags = le16_to_cpu(desc->bytes_written_flags); - - cq_desc_dec((struct cq_desc *)desc, type, - color, q_number, completed_index); - - *ingress_port = (completed_index_flags & - CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT) ? 1 : 0; - *fcoe = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_FCOE) ? - 1 : 0; - *eop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_EOP) ? - 1 : 0; - *sop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_SOP) ? - 1 : 0; - - *rss_type = (u8)((q_number_rss_type_flags >> CQ_DESC_Q_NUM_BITS) & - CQ_ENET_RQ_DESC_RSS_TYPE_MASK); - *csum_not_calc = (q_number_rss_type_flags & - CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC) ? 1 : 0; - - *rss_hash = le32_to_cpu(desc->rss_hash); - - *bytes_written = bytes_written_flags & - CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK; - *packet_error = (bytes_written_flags & - CQ_ENET_RQ_DESC_FLAGS_TRUNCATED) ? 1 : 0; - *vlan_stripped = (bytes_written_flags & - CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0; - - *vlan = le16_to_cpu(desc->vlan); - - if (*fcoe) { - *fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) & - CQ_ENET_RQ_DESC_FCOE_SOF_MASK); - *fcoe_fc_crc_ok = (desc->flags & - CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK) ? 1 : 0; - *fcoe_enc_error = (desc->flags & - CQ_ENET_RQ_DESC_FCOE_ENC_ERROR) ? 1 : 0; - *fcoe_eof = (u8)((desc->checksum_fcoe >> - CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT) & - CQ_ENET_RQ_DESC_FCOE_EOF_MASK); - *checksum = 0; - } else { - *fcoe_sof = 0; - *fcoe_fc_crc_ok = 0; - *fcoe_enc_error = 0; - *fcoe_eof = 0; - *checksum = le16_to_cpu(desc->checksum_fcoe); - } - - *tcp_udp_csum_ok = - (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK) ? 1 : 0; - *udp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_UDP) ? 1 : 0; - *tcp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP) ? 1 : 0; - *ipv4_csum_ok = - (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK) ? 1 : 0; - *ipv6 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV6) ? 1 : 0; - *ipv4 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4) ? 1 : 0; - *ipv4_fragment = - (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT) ? 1 : 0; - *fcs_ok = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_FCS_OK) ? 1 : 0; -} - -#endif /* _CQ_ENET_DESC_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/cq_exch_desc.h b/ANDROID_3.4.5/drivers/scsi/fnic/cq_exch_desc.h deleted file mode 100644 index 501660cf..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/cq_exch_desc.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _CQ_EXCH_DESC_H_ -#define _CQ_EXCH_DESC_H_ - -#include "cq_desc.h" - -/* Exchange completion queue descriptor: 16B */ -struct cq_exch_wq_desc { - u16 completed_index; - u16 q_number; - u16 exchange_id; - u8 tmpl; - u8 reserved0; - u32 reserved1; - u8 exch_status; - u8 reserved2[2]; - u8 type_color; -}; - -#define CQ_EXCH_WQ_STATUS_BITS 2 -#define CQ_EXCH_WQ_STATUS_MASK ((1 << CQ_EXCH_WQ_STATUS_BITS) - 1) - -enum cq_exch_status_types { - CQ_EXCH_WQ_STATUS_TYPE_COMPLETE = 0, - CQ_EXCH_WQ_STATUS_TYPE_ABORT = 1, - CQ_EXCH_WQ_STATUS_TYPE_SGL_EOF = 2, - CQ_EXCH_WQ_STATUS_TYPE_TMPL_ERR = 3, -}; - -static inline void cq_exch_wq_desc_dec(struct cq_exch_wq_desc *desc_ptr, - u8 *type, - u8 *color, - u16 *q_number, - u16 *completed_index, - u8 *exch_status) -{ - cq_desc_dec((struct cq_desc *)desc_ptr, type, - color, q_number, completed_index); - *exch_status = desc_ptr->exch_status & CQ_EXCH_WQ_STATUS_MASK; -} - -struct cq_fcp_rq_desc { - u16 completed_index_eop_sop_prt; - u16 q_number; - u16 exchange_id; - u16 tmpl; - u16 bytes_written; - u16 vlan; - u8 sof; - u8 eof; - u8 fcs_fer_fck; - u8 type_color; -}; - -#define CQ_FCP_RQ_DESC_FLAGS_SOP (1 << 15) -#define CQ_FCP_RQ_DESC_FLAGS_EOP (1 << 14) -#define CQ_FCP_RQ_DESC_FLAGS_PRT (1 << 12) -#define CQ_FCP_RQ_DESC_TMPL_MASK 0x1f -#define CQ_FCP_RQ_DESC_BYTES_WRITTEN_MASK 0x3fff -#define CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT 14 -#define CQ_FCP_RQ_DESC_PACKET_ERR_MASK (1 << CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT) -#define CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT 15 -#define CQ_FCP_RQ_DESC_VS_STRIPPED_MASK (1 << CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT) -#define CQ_FCP_RQ_DESC_FC_CRC_OK_MASK 0x1 -#define CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT 1 -#define CQ_FCP_RQ_DESC_FCOE_ERR_MASK (1 << CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT) -#define CQ_FCP_RQ_DESC_FCS_OK_SHIFT 7 -#define CQ_FCP_RQ_DESC_FCS_OK_MASK (1 << CQ_FCP_RQ_DESC_FCS_OK_SHIFT) - -static inline void cq_fcp_rq_desc_dec(struct cq_fcp_rq_desc *desc_ptr, - u8 *type, - u8 *color, - u16 *q_number, - u16 *completed_index, - u8 *eop, - u8 *sop, - u8 *fck, - u16 *exchange_id, - u16 *tmpl, - u32 *bytes_written, - u8 *sof, - u8 *eof, - u8 *ingress_port, - u8 *packet_err, - u8 *fcoe_err, - u8 *fcs_ok, - u8 *vlan_stripped, - u16 *vlan) -{ - cq_desc_dec((struct cq_desc *)desc_ptr, type, - color, q_number, completed_index); - *eop = (desc_ptr->completed_index_eop_sop_prt & - CQ_FCP_RQ_DESC_FLAGS_EOP) ? 1 : 0; - *sop = (desc_ptr->completed_index_eop_sop_prt & - CQ_FCP_RQ_DESC_FLAGS_SOP) ? 1 : 0; - *ingress_port = - (desc_ptr->completed_index_eop_sop_prt & - CQ_FCP_RQ_DESC_FLAGS_PRT) ? 1 : 0; - *exchange_id = desc_ptr->exchange_id; - *tmpl = desc_ptr->tmpl & CQ_FCP_RQ_DESC_TMPL_MASK; - *bytes_written = - desc_ptr->bytes_written & CQ_FCP_RQ_DESC_BYTES_WRITTEN_MASK; - *packet_err = - (desc_ptr->bytes_written & CQ_FCP_RQ_DESC_PACKET_ERR_MASK) >> - CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT; - *vlan_stripped = - (desc_ptr->bytes_written & CQ_FCP_RQ_DESC_VS_STRIPPED_MASK) >> - CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT; - *vlan = desc_ptr->vlan; - *sof = desc_ptr->sof; - *fck = desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FC_CRC_OK_MASK; - *fcoe_err = (desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FCOE_ERR_MASK) >> - CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT; - *eof = desc_ptr->eof; - *fcs_ok = - (desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FCS_OK_MASK) >> - CQ_FCP_RQ_DESC_FCS_OK_SHIFT; -} - -struct cq_sgl_desc { - u16 exchange_id; - u16 q_number; - u32 active_burst_offset; - u32 tot_data_bytes; - u16 tmpl; - u8 sgl_err; - u8 type_color; -}; - -enum cq_sgl_err_types { - CQ_SGL_ERR_NO_ERROR = 0, - CQ_SGL_ERR_OVERFLOW, /* data ran beyond end of SGL */ - CQ_SGL_ERR_SGL_LCL_ADDR_ERR, /* sgl access to local vnic addr illegal*/ - CQ_SGL_ERR_ADDR_RSP_ERR, /* sgl address error */ - CQ_SGL_ERR_DATA_RSP_ERR, /* sgl data rsp error */ - CQ_SGL_ERR_CNT_ZERO_ERR, /* SGL count is 0 */ - CQ_SGL_ERR_CNT_MAX_ERR, /* SGL count is larger than supported */ - CQ_SGL_ERR_ORDER_ERR, /* frames recv on both ports, order err */ - CQ_SGL_ERR_DATA_LCL_ADDR_ERR,/* sgl data buf to local vnic addr ill */ - CQ_SGL_ERR_HOST_CQ_ERR, /* host cq entry to local vnic addr ill */ -}; - -#define CQ_SGL_SGL_ERR_MASK 0x1f -#define CQ_SGL_TMPL_MASK 0x1f - -static inline void cq_sgl_desc_dec(struct cq_sgl_desc *desc_ptr, - u8 *type, - u8 *color, - u16 *q_number, - u16 *exchange_id, - u32 *active_burst_offset, - u32 *tot_data_bytes, - u16 *tmpl, - u8 *sgl_err) -{ - /* Cheat a little by assuming exchange_id is the same as completed - index */ - cq_desc_dec((struct cq_desc *)desc_ptr, type, color, q_number, - exchange_id); - *active_burst_offset = desc_ptr->active_burst_offset; - *tot_data_bytes = desc_ptr->tot_data_bytes; - *tmpl = desc_ptr->tmpl & CQ_SGL_TMPL_MASK; - *sgl_err = desc_ptr->sgl_err & CQ_SGL_SGL_ERR_MASK; -} - -#endif /* _CQ_EXCH_DESC_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fcpio.h b/ANDROID_3.4.5/drivers/scsi/fnic/fcpio.h deleted file mode 100644 index 12d770d8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fcpio.h +++ /dev/null @@ -1,780 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _FCPIO_H_ -#define _FCPIO_H_ - -#include - -/* - * This header file includes all of the data structures used for - * communication by the host driver to the fcp firmware. - */ - -/* - * Exchange and sequence id space allocated to the host driver - */ -#define FCPIO_HOST_EXCH_RANGE_START 0x1000 -#define FCPIO_HOST_EXCH_RANGE_END 0x1fff -#define FCPIO_HOST_SEQ_ID_RANGE_START 0x80 -#define FCPIO_HOST_SEQ_ID_RANGE_END 0xff - -/* - * Command entry type - */ -enum fcpio_type { - /* - * Initiator request types - */ - FCPIO_ICMND_16 = 0x1, - FCPIO_ICMND_32, - FCPIO_ICMND_CMPL, - FCPIO_ITMF, - FCPIO_ITMF_CMPL, - - /* - * Target request types - */ - FCPIO_TCMND_16 = 0x11, - FCPIO_TCMND_32, - FCPIO_TDATA, - FCPIO_TXRDY, - FCPIO_TRSP, - FCPIO_TDRSP_CMPL, - FCPIO_TTMF, - FCPIO_TTMF_ACK, - FCPIO_TABORT, - FCPIO_TABORT_CMPL, - - /* - * Misc request types - */ - FCPIO_ACK = 0x20, - FCPIO_RESET, - FCPIO_RESET_CMPL, - FCPIO_FLOGI_REG, - FCPIO_FLOGI_REG_CMPL, - FCPIO_ECHO, - FCPIO_ECHO_CMPL, - FCPIO_LUNMAP_CHNG, - FCPIO_LUNMAP_REQ, - FCPIO_LUNMAP_REQ_CMPL, - FCPIO_FLOGI_FIP_REG, - FCPIO_FLOGI_FIP_REG_CMPL, -}; - -/* - * Header status codes from the firmware - */ -enum fcpio_status { - FCPIO_SUCCESS = 0, /* request was successful */ - - /* - * If a request to the firmware is rejected, the original request - * header will be returned with the status set to one of the following: - */ - FCPIO_INVALID_HEADER, /* header contains invalid data */ - FCPIO_OUT_OF_RESOURCE, /* out of resources to complete request */ - FCPIO_INVALID_PARAM, /* some parameter in request is invalid */ - FCPIO_REQ_NOT_SUPPORTED, /* request type is not supported */ - FCPIO_IO_NOT_FOUND, /* requested I/O was not found */ - - /* - * Once a request is processed, the firmware will usually return - * a cmpl message type. In cases where errors occurred, - * the header status field would be filled in with one of the following: - */ - FCPIO_ABORTED = 0x41, /* request was aborted */ - FCPIO_TIMEOUT, /* request was timed out */ - FCPIO_SGL_INVALID, /* request was aborted due to sgl error */ - FCPIO_MSS_INVALID, /* request was aborted due to mss error */ - FCPIO_DATA_CNT_MISMATCH, /* recv/sent more/less data than exp. */ - FCPIO_FW_ERR, /* request was terminated due to fw error */ - FCPIO_ITMF_REJECTED, /* itmf req was rejected by remote node */ - FCPIO_ITMF_FAILED, /* itmf req was failed by remote node */ - FCPIO_ITMF_INCORRECT_LUN, /* itmf req targeted incorrect LUN */ - FCPIO_CMND_REJECTED, /* request was invalid and rejected */ - FCPIO_NO_PATH_AVAIL, /* no paths to the lun was available */ - FCPIO_PATH_FAILED, /* i/o sent to current path failed */ - FCPIO_LUNMAP_CHNG_PEND, /* i/o rejected due to lunmap change */ -}; - -/* - * The header command tag. All host requests will use the "tag" field - * to mark commands with a unique tag. When the firmware responds to - * a host request, it will copy the tag field into the response. - * - * The only firmware requests that will use the rx_id/ox_id fields instead - * of the tag field will be the target command and target task management - * requests. These two requests do not have corresponding host requests - * since they come directly from the FC initiator on the network. - */ -struct fcpio_tag { - union { - u32 req_id; - struct { - u16 rx_id; - u16 ox_id; - } ex_id; - } u; -}; - -static inline void -fcpio_tag_id_enc(struct fcpio_tag *tag, u32 id) -{ - tag->u.req_id = id; -} - -static inline void -fcpio_tag_id_dec(struct fcpio_tag *tag, u32 *id) -{ - *id = tag->u.req_id; -} - -static inline void -fcpio_tag_exid_enc(struct fcpio_tag *tag, u16 ox_id, u16 rx_id) -{ - tag->u.ex_id.rx_id = rx_id; - tag->u.ex_id.ox_id = ox_id; -} - -static inline void -fcpio_tag_exid_dec(struct fcpio_tag *tag, u16 *ox_id, u16 *rx_id) -{ - *rx_id = tag->u.ex_id.rx_id; - *ox_id = tag->u.ex_id.ox_id; -} - -/* - * The header for an fcpio request, whether from the firmware or from the - * host driver - */ -struct fcpio_header { - u8 type; /* enum fcpio_type */ - u8 status; /* header status entry */ - u16 _resvd; /* reserved */ - struct fcpio_tag tag; /* header tag */ -}; - -static inline void -fcpio_header_enc(struct fcpio_header *hdr, - u8 type, u8 status, - struct fcpio_tag tag) -{ - hdr->type = type; - hdr->status = status; - hdr->_resvd = 0; - hdr->tag = tag; -} - -static inline void -fcpio_header_dec(struct fcpio_header *hdr, - u8 *type, u8 *status, - struct fcpio_tag *tag) -{ - *type = hdr->type; - *status = hdr->status; - *tag = hdr->tag; -} - -#define CDB_16 16 -#define CDB_32 32 -#define LUN_ADDRESS 8 - -/* - * fcpio_icmnd_16: host -> firmware request - * - * used for sending out an initiator SCSI 16-byte command - */ -struct fcpio_icmnd_16 { - u32 lunmap_id; /* index into lunmap table */ - u8 special_req_flags; /* special exchange request flags */ - u8 _resvd0[3]; /* reserved */ - u32 sgl_cnt; /* scatter-gather list count */ - u32 sense_len; /* sense buffer length */ - u64 sgl_addr; /* scatter-gather list addr */ - u64 sense_addr; /* sense buffer address */ - u8 crn; /* SCSI Command Reference No. */ - u8 pri_ta; /* SCSI Priority and Task attribute */ - u8 _resvd1; /* reserved: should be 0 */ - u8 flags; /* command flags */ - u8 scsi_cdb[CDB_16]; /* SCSI Cmnd Descriptor Block */ - u32 data_len; /* length of data expected */ - u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ - u8 _resvd2; /* reserved */ - u8 d_id[3]; /* FC vNIC only: Target D_ID */ - u16 mss; /* FC vNIC only: max burst */ - u16 _resvd3; /* reserved */ - u32 r_a_tov; /* FC vNIC only: Res. Alloc Timeout */ - u32 e_d_tov; /* FC vNIC only: Err Detect Timeout */ -}; - -/* - * Special request flags - */ -#define FCPIO_ICMND_SRFLAG_RETRY 0x01 /* Enable Retry handling on exchange */ - -/* - * Priority/Task Attribute settings - */ -#define FCPIO_ICMND_PTA_SIMPLE 0 /* simple task attribute */ -#define FCPIO_ICMND_PTA_HEADQ 1 /* head of queue task attribute */ -#define FCPIO_ICMND_PTA_ORDERED 2 /* ordered task attribute */ -#define FCPIO_ICMND_PTA_ACA 4 /* auto contingent allegiance */ -#define FCPIO_ICMND_PRI_SHIFT 3 /* priority field starts in bit 3 */ - -/* - * Command flags - */ -#define FCPIO_ICMND_RDDATA 0x02 /* read data */ -#define FCPIO_ICMND_WRDATA 0x01 /* write data */ - -/* - * fcpio_icmnd_32: host -> firmware request - * - * used for sending out an initiator SCSI 32-byte command - */ -struct fcpio_icmnd_32 { - u32 lunmap_id; /* index into lunmap table */ - u8 special_req_flags; /* special exchange request flags */ - u8 _resvd0[3]; /* reserved */ - u32 sgl_cnt; /* scatter-gather list count */ - u32 sense_len; /* sense buffer length */ - u64 sgl_addr; /* scatter-gather list addr */ - u64 sense_addr; /* sense buffer address */ - u8 crn; /* SCSI Command Reference No. */ - u8 pri_ta; /* SCSI Priority and Task attribute */ - u8 _resvd1; /* reserved: should be 0 */ - u8 flags; /* command flags */ - u8 scsi_cdb[CDB_32]; /* SCSI Cmnd Descriptor Block */ - u32 data_len; /* length of data expected */ - u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ - u8 _resvd2; /* reserved */ - u8 d_id[3]; /* FC vNIC only: Target D_ID */ - u16 mss; /* FC vNIC only: max burst */ - u16 _resvd3; /* reserved */ - u32 r_a_tov; /* FC vNIC only: Res. Alloc Timeout */ - u32 e_d_tov; /* FC vNIC only: Error Detect Timeout */ -}; - -/* - * fcpio_itmf: host -> firmware request - * - * used for requesting the firmware to abort a request and/or send out - * a task management function - * - * The t_tag field is only needed when the request type is ABT_TASK. - */ -struct fcpio_itmf { - u32 lunmap_id; /* index into lunmap table */ - u32 tm_req; /* SCSI Task Management request */ - u32 t_tag; /* header tag of fcpio to be aborted */ - u32 _resvd; /* _reserved */ - u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ - u8 _resvd1; /* reserved */ - u8 d_id[3]; /* FC vNIC only: Target D_ID */ - u32 r_a_tov; /* FC vNIC only: R_A_TOV in msec */ - u32 e_d_tov; /* FC vNIC only: E_D_TOV in msec */ -}; - -/* - * Task Management request - */ -enum fcpio_itmf_tm_req_type { - FCPIO_ITMF_ABT_TASK_TERM = 0x01, /* abort task and terminate */ - FCPIO_ITMF_ABT_TASK, /* abort task and issue abts */ - FCPIO_ITMF_ABT_TASK_SET, /* abort task set */ - FCPIO_ITMF_CLR_TASK_SET, /* clear task set */ - FCPIO_ITMF_LUN_RESET, /* logical unit reset task mgmt */ - FCPIO_ITMF_CLR_ACA, /* Clear ACA condition */ -}; - -/* - * fcpio_tdata: host -> firmware request - * - * used for requesting the firmware to send out a read data transfer for a - * target command - */ -struct fcpio_tdata { - u16 rx_id; /* FC rx_id of target command */ - u16 flags; /* command flags */ - u32 rel_offset; /* data sequence relative offset */ - u32 sgl_cnt; /* scatter-gather list count */ - u32 data_len; /* length of data expected to send */ - u64 sgl_addr; /* scatter-gather list address */ -}; - -/* - * Command flags - */ -#define FCPIO_TDATA_SCSI_RSP 0x01 /* send a scsi resp. after last frame */ - -/* - * fcpio_txrdy: host -> firmware request - * - * used for requesting the firmware to send out a write data transfer for a - * target command - */ -struct fcpio_txrdy { - u16 rx_id; /* FC rx_id of target command */ - u16 _resvd0; /* reserved */ - u32 rel_offset; /* data sequence relative offset */ - u32 sgl_cnt; /* scatter-gather list count */ - u32 data_len; /* length of data expected to send */ - u64 sgl_addr; /* scatter-gather list address */ -}; - -/* - * fcpio_trsp: host -> firmware request - * - * used for requesting the firmware to send out a response for a target - * command - */ -struct fcpio_trsp { - u16 rx_id; /* FC rx_id of target command */ - u16 _resvd0; /* reserved */ - u32 sense_len; /* sense data buffer length */ - u64 sense_addr; /* sense data buffer address */ - u16 _resvd1; /* reserved */ - u8 flags; /* response request flags */ - u8 scsi_status; /* SCSI status */ - u32 residual; /* SCSI data residual value of I/O */ -}; - -/* - * resposnse request flags - */ -#define FCPIO_TRSP_RESID_UNDER 0x08 /* residual is valid and is underflow */ -#define FCPIO_TRSP_RESID_OVER 0x04 /* residual is valid and is overflow */ - -/* - * fcpio_ttmf_ack: host -> firmware response - * - * used by the host to indicate to the firmware it has received and processed - * the target tmf request - */ -struct fcpio_ttmf_ack { - u16 rx_id; /* FC rx_id of target command */ - u16 _resvd0; /* reserved */ - u32 tmf_status; /* SCSI task management status */ -}; - -/* - * fcpio_tabort: host -> firmware request - * - * used by the host to request the firmware to abort a target request that was - * received by the firmware - */ -struct fcpio_tabort { - u16 rx_id; /* rx_id of the target request */ -}; - -/* - * fcpio_reset: host -> firmware request - * - * used by the host to signal a reset of the driver to the firmware - * and to request firmware to clean up all outstanding I/O - */ -struct fcpio_reset { - u32 _resvd; -}; - -enum fcpio_flogi_reg_format_type { - FCPIO_FLOGI_REG_DEF_DEST = 0, /* Use the oui | s_id mac format */ - FCPIO_FLOGI_REG_GW_DEST, /* Use the fixed gateway mac */ -}; - -/* - * fcpio_flogi_reg: host -> firmware request - * - * fc vnic only - * used by the host to notify the firmware of the lif's s_id - * and destination mac address format - */ -struct fcpio_flogi_reg { - u8 format; - u8 s_id[3]; /* FC vNIC only: Source S_ID */ - u8 gateway_mac[ETH_ALEN]; /* Destination gateway mac */ - u16 _resvd; - u32 r_a_tov; /* R_A_TOV in msec */ - u32 e_d_tov; /* E_D_TOV in msec */ -}; - -/* - * fcpio_echo: host -> firmware request - * - * sends a heartbeat echo request to the firmware - */ -struct fcpio_echo { - u32 _resvd; -}; - -/* - * fcpio_lunmap_req: host -> firmware request - * - * scsi vnic only - * sends a request to retrieve the lunmap table for scsi vnics - */ -struct fcpio_lunmap_req { - u64 addr; /* address of the buffer */ - u32 len; /* len of the buffer */ -}; - -/* - * fcpio_flogi_fip_reg: host -> firmware request - * - * fc vnic only - * used by the host to notify the firmware of the lif's s_id - * and destination mac address format - */ -struct fcpio_flogi_fip_reg { - u8 _resvd0; - u8 s_id[3]; /* FC vNIC only: Source S_ID */ - u8 fcf_mac[ETH_ALEN]; /* FCF Target destination mac */ - u16 _resvd1; - u32 r_a_tov; /* R_A_TOV in msec */ - u32 e_d_tov; /* E_D_TOV in msec */ - u8 ha_mac[ETH_ALEN]; /* Host adapter source mac */ - u16 _resvd2; -}; - -/* - * Basic structure for all fcpio structures that are sent from the host to the - * firmware. They are 128 bytes per structure. - */ -#define FCPIO_HOST_REQ_LEN 128 /* expected length of host requests */ - -struct fcpio_host_req { - struct fcpio_header hdr; - - union { - /* - * Defines space needed for request - */ - u8 buf[FCPIO_HOST_REQ_LEN - sizeof(struct fcpio_header)]; - - /* - * Initiator host requests - */ - struct fcpio_icmnd_16 icmnd_16; - struct fcpio_icmnd_32 icmnd_32; - struct fcpio_itmf itmf; - - /* - * Target host requests - */ - struct fcpio_tdata tdata; - struct fcpio_txrdy txrdy; - struct fcpio_trsp trsp; - struct fcpio_ttmf_ack ttmf_ack; - struct fcpio_tabort tabort; - - /* - * Misc requests - */ - struct fcpio_reset reset; - struct fcpio_flogi_reg flogi_reg; - struct fcpio_echo echo; - struct fcpio_lunmap_req lunmap_req; - struct fcpio_flogi_fip_reg flogi_fip_reg; - } u; -}; - -/* - * fcpio_icmnd_cmpl: firmware -> host response - * - * used for sending the host a response to an initiator command - */ -struct fcpio_icmnd_cmpl { - u8 _resvd0[6]; /* reserved */ - u8 flags; /* response flags */ - u8 scsi_status; /* SCSI status */ - u32 residual; /* SCSI data residual length */ - u32 sense_len; /* SCSI sense length */ -}; - -/* - * response flags - */ -#define FCPIO_ICMND_CMPL_RESID_UNDER 0x08 /* resid under and valid */ -#define FCPIO_ICMND_CMPL_RESID_OVER 0x04 /* resid over and valid */ - -/* - * fcpio_itmf_cmpl: firmware -> host response - * - * used for sending the host a response for a itmf request - */ -struct fcpio_itmf_cmpl { - u32 _resvd; /* reserved */ -}; - -/* - * fcpio_tcmnd_16: firmware -> host request - * - * used by the firmware to notify the host of an incoming target SCSI 16-Byte - * request - */ -struct fcpio_tcmnd_16 { - u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ - u8 crn; /* SCSI Command Reference No. */ - u8 pri_ta; /* SCSI Priority and Task attribute */ - u8 _resvd2; /* reserved: should be 0 */ - u8 flags; /* command flags */ - u8 scsi_cdb[CDB_16]; /* SCSI Cmnd Descriptor Block */ - u32 data_len; /* length of data expected */ - u8 _resvd1; /* reserved */ - u8 s_id[3]; /* FC vNIC only: Source S_ID */ -}; - -/* - * Priority/Task Attribute settings - */ -#define FCPIO_TCMND_PTA_SIMPLE 0 /* simple task attribute */ -#define FCPIO_TCMND_PTA_HEADQ 1 /* head of queue task attribute */ -#define FCPIO_TCMND_PTA_ORDERED 2 /* ordered task attribute */ -#define FCPIO_TCMND_PTA_ACA 4 /* auto contingent allegiance */ -#define FCPIO_TCMND_PRI_SHIFT 3 /* priority field starts in bit 3 */ - -/* - * Command flags - */ -#define FCPIO_TCMND_RDDATA 0x02 /* read data */ -#define FCPIO_TCMND_WRDATA 0x01 /* write data */ - -/* - * fcpio_tcmnd_32: firmware -> host request - * - * used by the firmware to notify the host of an incoming target SCSI 32-Byte - * request - */ -struct fcpio_tcmnd_32 { - u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ - u8 crn; /* SCSI Command Reference No. */ - u8 pri_ta; /* SCSI Priority and Task attribute */ - u8 _resvd2; /* reserved: should be 0 */ - u8 flags; /* command flags */ - u8 scsi_cdb[CDB_32]; /* SCSI Cmnd Descriptor Block */ - u32 data_len; /* length of data expected */ - u8 _resvd0; /* reserved */ - u8 s_id[3]; /* FC vNIC only: Source S_ID */ -}; - -/* - * fcpio_tdrsp_cmpl: firmware -> host response - * - * used by the firmware to notify the host of a response to a host target - * command - */ -struct fcpio_tdrsp_cmpl { - u16 rx_id; /* rx_id of the target request */ - u16 _resvd0; /* reserved */ -}; - -/* - * fcpio_ttmf: firmware -> host request - * - * used by the firmware to notify the host of an incoming task management - * function request - */ -struct fcpio_ttmf { - u8 _resvd0; /* reserved */ - u8 s_id[3]; /* FC vNIC only: Source S_ID */ - u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ - u8 crn; /* SCSI Command Reference No. */ - u8 _resvd2[3]; /* reserved */ - u32 tmf_type; /* task management request type */ -}; - -/* - * Task Management request - */ -#define FCPIO_TTMF_CLR_ACA 0x40 /* Clear ACA condition */ -#define FCPIO_TTMF_LUN_RESET 0x10 /* logical unit reset task mgmt */ -#define FCPIO_TTMF_CLR_TASK_SET 0x04 /* clear task set */ -#define FCPIO_TTMF_ABT_TASK_SET 0x02 /* abort task set */ -#define FCPIO_TTMF_ABT_TASK 0x01 /* abort task */ - -/* - * fcpio_tabort_cmpl: firmware -> host response - * - * used by the firmware to respond to a host's tabort request - */ -struct fcpio_tabort_cmpl { - u16 rx_id; /* rx_id of the target request */ - u16 _resvd0; /* reserved */ -}; - -/* - * fcpio_ack: firmware -> host response - * - * used by firmware to notify the host of the last work request received - */ -struct fcpio_ack { - u16 request_out; /* last host entry received */ - u16 _resvd; -}; - -/* - * fcpio_reset_cmpl: firmware -> host response - * - * use by firmware to respond to the host's reset request - */ -struct fcpio_reset_cmpl { - u16 vnic_id; -}; - -/* - * fcpio_flogi_reg_cmpl: firmware -> host response - * - * fc vnic only - * response to the fcpio_flogi_reg request - */ -struct fcpio_flogi_reg_cmpl { - u32 _resvd; -}; - -/* - * fcpio_echo_cmpl: firmware -> host response - * - * response to the fcpio_echo request - */ -struct fcpio_echo_cmpl { - u32 _resvd; -}; - -/* - * fcpio_lunmap_chng: firmware -> host notification - * - * scsi vnic only - * notifies the host that the lunmap tables have changed - */ -struct fcpio_lunmap_chng { - u32 _resvd; -}; - -/* - * fcpio_lunmap_req_cmpl: firmware -> host response - * - * scsi vnic only - * response for lunmap table request from the host - */ -struct fcpio_lunmap_req_cmpl { - u32 _resvd; -}; - -/* - * Basic structure for all fcpio structures that are sent from the firmware to - * the host. They are 64 bytes per structure. - */ -#define FCPIO_FW_REQ_LEN 64 /* expected length of fw requests */ -struct fcpio_fw_req { - struct fcpio_header hdr; - - union { - /* - * Defines space needed for request - */ - u8 buf[FCPIO_FW_REQ_LEN - sizeof(struct fcpio_header)]; - - /* - * Initiator firmware responses - */ - struct fcpio_icmnd_cmpl icmnd_cmpl; - struct fcpio_itmf_cmpl itmf_cmpl; - - /* - * Target firmware new requests - */ - struct fcpio_tcmnd_16 tcmnd_16; - struct fcpio_tcmnd_32 tcmnd_32; - - /* - * Target firmware responses - */ - struct fcpio_tdrsp_cmpl tdrsp_cmpl; - struct fcpio_ttmf ttmf; - struct fcpio_tabort_cmpl tabort_cmpl; - - /* - * Firmware response to work received - */ - struct fcpio_ack ack; - - /* - * Misc requests - */ - struct fcpio_reset_cmpl reset_cmpl; - struct fcpio_flogi_reg_cmpl flogi_reg_cmpl; - struct fcpio_echo_cmpl echo_cmpl; - struct fcpio_lunmap_chng lunmap_chng; - struct fcpio_lunmap_req_cmpl lunmap_req_cmpl; - } u; -}; - -/* - * Access routines to encode and decode the color bit, which is the most - * significant bit of the MSB of the structure - */ -static inline void fcpio_color_enc(struct fcpio_fw_req *fw_req, u8 color) -{ - u8 *c = ((u8 *) fw_req) + sizeof(struct fcpio_fw_req) - 1; - - if (color) - *c |= 0x80; - else - *c &= ~0x80; -} - -static inline void fcpio_color_dec(struct fcpio_fw_req *fw_req, u8 *color) -{ - u8 *c = ((u8 *) fw_req) + sizeof(struct fcpio_fw_req) - 1; - - *color = *c >> 7; - - /* - * Make sure color bit is read from desc *before* other fields - * are read from desc. Hardware guarantees color bit is last - * bit (byte) written. Adding the rmb() prevents the compiler - * and/or CPU from reordering the reads which would potentially - * result in reading stale values. - */ - - rmb(); - -} - -/* - * Lunmap table entry for scsi vnics - */ -#define FCPIO_LUNMAP_TABLE_SIZE 256 -#define FCPIO_FLAGS_LUNMAP_VALID 0x80 -#define FCPIO_FLAGS_BOOT 0x01 -struct fcpio_lunmap_entry { - u8 bus; - u8 target; - u8 lun; - u8 path_cnt; - u16 flags; - u16 update_cnt; -}; - -struct fcpio_lunmap_tbl { - u32 update_cnt; - struct fcpio_lunmap_entry lunmaps[FCPIO_LUNMAP_TABLE_SIZE]; -}; - -#endif /* _FCPIO_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic.h b/ANDROID_3.4.5/drivers/scsi/fnic/fnic.h deleted file mode 100644 index 95a5ba29..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _FNIC_H_ -#define _FNIC_H_ - -#include -#include -#include -#include -#include -#include -#include "fnic_io.h" -#include "fnic_res.h" -#include "vnic_dev.h" -#include "vnic_wq.h" -#include "vnic_rq.h" -#include "vnic_cq.h" -#include "vnic_wq_copy.h" -#include "vnic_intr.h" -#include "vnic_stats.h" -#include "vnic_scsi.h" - -#define DRV_NAME "fnic" -#define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.5.0.2" -#define PFX DRV_NAME ": " -#define DFX DRV_NAME "%d: " - -#define DESC_CLEAN_LOW_WATERMARK 8 -#define FNIC_MAX_IO_REQ 2048 /* scsi_cmnd tag map entries */ -#define FNIC_IO_LOCKS 64 /* IO locks: power of 2 */ -#define FNIC_DFLT_QUEUE_DEPTH 32 -#define FNIC_STATS_RATE_LIMIT 4 /* limit rate at which stats are pulled up */ - -/* - * Tag bits used for special requests. - */ -#define FNIC_TAG_ABORT BIT(30) /* tag bit indicating abort */ -#define FNIC_TAG_DEV_RST BIT(29) /* indicates device reset */ -#define FNIC_TAG_MASK (BIT(24) - 1) /* mask for lookup */ -#define FNIC_NO_TAG -1 - -/* - * Usage of the scsi_cmnd scratchpad. - * These fields are locked by the hashed io_req_lock. - */ -#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) -#define CMD_STATE(Cmnd) ((Cmnd)->SCp.phase) -#define CMD_ABTS_STATUS(Cmnd) ((Cmnd)->SCp.Message) -#define CMD_LR_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in) -#define CMD_TAG(Cmnd) ((Cmnd)->SCp.sent_command) - -#define FCPIO_INVALID_CODE 0x100 /* hdr_status value unused by firmware */ - -#define FNIC_LUN_RESET_TIMEOUT 10000 /* mSec */ -#define FNIC_HOST_RESET_TIMEOUT 10000 /* mSec */ -#define FNIC_RMDEVICE_TIMEOUT 1000 /* mSec */ -#define FNIC_HOST_RESET_SETTLE_TIME 30 /* Sec */ - -#define FNIC_MAX_FCP_TARGET 256 - -extern unsigned int fnic_log_level; - -#define FNIC_MAIN_LOGGING 0x01 -#define FNIC_FCS_LOGGING 0x02 -#define FNIC_SCSI_LOGGING 0x04 -#define FNIC_ISR_LOGGING 0x08 - -#define FNIC_CHECK_LOGGING(LEVEL, CMD) \ -do { \ - if (unlikely(fnic_log_level & LEVEL)) \ - do { \ - CMD; \ - } while (0); \ -} while (0) - -#define FNIC_MAIN_DBG(kern_level, host, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_MAIN_LOGGING, \ - shost_printk(kern_level, host, fmt, ##args);) - -#define FNIC_FCS_DBG(kern_level, host, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \ - shost_printk(kern_level, host, fmt, ##args);) - -#define FNIC_SCSI_DBG(kern_level, host, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_SCSI_LOGGING, \ - shost_printk(kern_level, host, fmt, ##args);) - -#define FNIC_ISR_DBG(kern_level, host, fmt, args...) \ - FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING, \ - shost_printk(kern_level, host, fmt, ##args);) - -extern const char *fnic_state_str[]; - -enum fnic_intx_intr_index { - FNIC_INTX_WQ_RQ_COPYWQ, - FNIC_INTX_ERR, - FNIC_INTX_NOTIFY, - FNIC_INTX_INTR_MAX, -}; - -enum fnic_msix_intr_index { - FNIC_MSIX_RQ, - FNIC_MSIX_WQ, - FNIC_MSIX_WQ_COPY, - FNIC_MSIX_ERR_NOTIFY, - FNIC_MSIX_INTR_MAX, -}; - -struct fnic_msix_entry { - int requested; - char devname[IFNAMSIZ]; - irqreturn_t (*isr)(int, void *); - void *devid; -}; - -enum fnic_state { - FNIC_IN_FC_MODE = 0, - FNIC_IN_FC_TRANS_ETH_MODE, - FNIC_IN_ETH_MODE, - FNIC_IN_ETH_TRANS_FC_MODE, -}; - -#define FNIC_WQ_COPY_MAX 1 -#define FNIC_WQ_MAX 1 -#define FNIC_RQ_MAX 1 -#define FNIC_CQ_MAX (FNIC_WQ_COPY_MAX + FNIC_WQ_MAX + FNIC_RQ_MAX) - -struct mempool; - -/* Per-instance private data structure */ -struct fnic { - struct fc_lport *lport; - struct fcoe_ctlr ctlr; /* FIP FCoE controller structure */ - struct vnic_dev_bar bar0; - - struct msix_entry msix_entry[FNIC_MSIX_INTR_MAX]; - struct fnic_msix_entry msix[FNIC_MSIX_INTR_MAX]; - - struct vnic_stats *stats; - unsigned long stats_time; /* time of stats update */ - struct vnic_nic_cfg *nic_cfg; - char name[IFNAMSIZ]; - struct timer_list notify_timer; /* used for MSI interrupts */ - - unsigned int err_intr_offset; - unsigned int link_intr_offset; - - unsigned int wq_count; - unsigned int cq_count; - - u32 vlan_hw_insert:1; /* let hw insert the tag */ - u32 in_remove:1; /* fnic device in removal */ - u32 stop_rx_link_events:1; /* stop proc. rx frames, link events */ - - struct completion *remove_wait; /* device remove thread blocks */ - - enum fnic_state state; - spinlock_t fnic_lock; - - u16 vlan_id; /* VLAN tag including priority */ - u8 data_src_addr[ETH_ALEN]; - u64 fcp_input_bytes; /* internal statistic */ - u64 fcp_output_bytes; /* internal statistic */ - u32 link_down_cnt; - int link_status; - - struct list_head list; - struct pci_dev *pdev; - struct vnic_fc_config config; - struct vnic_dev *vdev; - unsigned int raw_wq_count; - unsigned int wq_copy_count; - unsigned int rq_count; - int fw_ack_index[FNIC_WQ_COPY_MAX]; - unsigned short fw_ack_recd[FNIC_WQ_COPY_MAX]; - unsigned short wq_copy_desc_low[FNIC_WQ_COPY_MAX]; - unsigned int intr_count; - u32 __iomem *legacy_pba; - struct fnic_host_tag *tags; - mempool_t *io_req_pool; - mempool_t *io_sgl_pool[FNIC_SGL_NUM_CACHES]; - spinlock_t io_req_lock[FNIC_IO_LOCKS]; /* locks for scsi cmnds */ - - struct work_struct link_work; - struct work_struct frame_work; - struct sk_buff_head frame_queue; - struct sk_buff_head tx_queue; - - /* copy work queue cache line section */ - ____cacheline_aligned struct vnic_wq_copy wq_copy[FNIC_WQ_COPY_MAX]; - /* completion queue cache line section */ - ____cacheline_aligned struct vnic_cq cq[FNIC_CQ_MAX]; - - spinlock_t wq_copy_lock[FNIC_WQ_COPY_MAX]; - - /* work queue cache line section */ - ____cacheline_aligned struct vnic_wq wq[FNIC_WQ_MAX]; - spinlock_t wq_lock[FNIC_WQ_MAX]; - - /* receive queue cache line section */ - ____cacheline_aligned struct vnic_rq rq[FNIC_RQ_MAX]; - - /* interrupt resource cache line section */ - ____cacheline_aligned struct vnic_intr intr[FNIC_MSIX_INTR_MAX]; -}; - -static inline struct fnic *fnic_from_ctlr(struct fcoe_ctlr *fip) -{ - return container_of(fip, struct fnic, ctlr); -} - -extern struct workqueue_struct *fnic_event_queue; -extern struct device_attribute *fnic_attrs[]; - -void fnic_clear_intr_mode(struct fnic *fnic); -int fnic_set_intr_mode(struct fnic *fnic); -void fnic_free_intr(struct fnic *fnic); -int fnic_request_intr(struct fnic *fnic); - -int fnic_send(struct fc_lport *, struct fc_frame *); -void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf); -void fnic_handle_frame(struct work_struct *work); -void fnic_handle_link(struct work_struct *work); -int fnic_rq_cmpl_handler(struct fnic *fnic, int); -int fnic_alloc_rq_frame(struct vnic_rq *rq); -void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf); -void fnic_flush_tx(struct fnic *); -void fnic_eth_send(struct fcoe_ctlr *, struct sk_buff *skb); -void fnic_set_port_id(struct fc_lport *, u32, struct fc_frame *); -void fnic_update_mac(struct fc_lport *, u8 *new); -void fnic_update_mac_locked(struct fnic *, u8 *new); - -int fnic_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -int fnic_abort_cmd(struct scsi_cmnd *); -int fnic_device_reset(struct scsi_cmnd *); -int fnic_host_reset(struct scsi_cmnd *); -int fnic_reset(struct Scsi_Host *); -void fnic_scsi_cleanup(struct fc_lport *); -void fnic_scsi_abort_io(struct fc_lport *); -void fnic_empty_scsi_cleanup(struct fc_lport *); -void fnic_exch_mgr_reset(struct fc_lport *, u32, u32); -int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int); -int fnic_wq_cmpl_handler(struct fnic *fnic, int); -int fnic_flogi_reg_handler(struct fnic *fnic, u32); -void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, - struct fcpio_host_req *desc); -int fnic_fw_reset_handler(struct fnic *fnic); -void fnic_terminate_rport_io(struct fc_rport *); -const char *fnic_state_to_str(unsigned int state); - -void fnic_log_q_error(struct fnic *fnic); -void fnic_handle_link_event(struct fnic *fnic); - -#endif /* _FNIC_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_attrs.c b/ANDROID_3.4.5/drivers/scsi/fnic/fnic_attrs.c deleted file mode 100644 index aea0c3be..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_attrs.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include "fnic.h" - -static ssize_t fnic_show_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fc_lport *lp = shost_priv(class_to_shost(dev)); - struct fnic *fnic = lport_priv(lp); - - return snprintf(buf, PAGE_SIZE, "%s\n", fnic_state_str[fnic->state]); -} - -static ssize_t fnic_show_drv_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", DRV_VERSION); -} - -static ssize_t fnic_show_link_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fc_lport *lp = shost_priv(class_to_shost(dev)); - - return snprintf(buf, PAGE_SIZE, "%s\n", (lp->link_up) - ? "Link Up" : "Link Down"); -} - -static DEVICE_ATTR(fnic_state, S_IRUGO, fnic_show_state, NULL); -static DEVICE_ATTR(drv_version, S_IRUGO, fnic_show_drv_version, NULL); -static DEVICE_ATTR(link_state, S_IRUGO, fnic_show_link_state, NULL); - -struct device_attribute *fnic_attrs[] = { - &dev_attr_fnic_state, - &dev_attr_drv_version, - &dev_attr_link_state, - NULL, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_fcs.c b/ANDROID_3.4.5/drivers/scsi/fnic/fnic_fcs.c deleted file mode 100644 index 3c53c347..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_fcs.c +++ /dev/null @@ -1,720 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fnic_io.h" -#include "fnic.h" -#include "cq_enet_desc.h" -#include "cq_exch_desc.h" - -struct workqueue_struct *fnic_event_queue; - -static void fnic_set_eth_mode(struct fnic *); - -void fnic_handle_link(struct work_struct *work) -{ - struct fnic *fnic = container_of(work, struct fnic, link_work); - unsigned long flags; - int old_link_status; - u32 old_link_down_cnt; - - spin_lock_irqsave(&fnic->fnic_lock, flags); - - if (fnic->stop_rx_link_events) { - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - return; - } - - old_link_down_cnt = fnic->link_down_cnt; - old_link_status = fnic->link_status; - fnic->link_status = vnic_dev_link_status(fnic->vdev); - fnic->link_down_cnt = vnic_dev_link_down_cnt(fnic->vdev); - - if (old_link_status == fnic->link_status) { - if (!fnic->link_status) - /* DOWN -> DOWN */ - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - else { - if (old_link_down_cnt != fnic->link_down_cnt) { - /* UP -> DOWN -> UP */ - fnic->lport->host_stats.link_failure_count++; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "link down\n"); - fcoe_ctlr_link_down(&fnic->ctlr); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "link up\n"); - fcoe_ctlr_link_up(&fnic->ctlr); - } else - /* UP -> UP */ - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - } - } else if (fnic->link_status) { - /* DOWN -> UP */ - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link up\n"); - fcoe_ctlr_link_up(&fnic->ctlr); - } else { - /* UP -> DOWN */ - fnic->lport->host_stats.link_failure_count++; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link down\n"); - fcoe_ctlr_link_down(&fnic->ctlr); - } - -} - -/* - * This function passes incoming fabric frames to libFC - */ -void fnic_handle_frame(struct work_struct *work) -{ - struct fnic *fnic = container_of(work, struct fnic, frame_work); - struct fc_lport *lp = fnic->lport; - unsigned long flags; - struct sk_buff *skb; - struct fc_frame *fp; - - while ((skb = skb_dequeue(&fnic->frame_queue))) { - - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->stop_rx_link_events) { - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - dev_kfree_skb(skb); - return; - } - fp = (struct fc_frame *)skb; - - /* - * If we're in a transitional state, just re-queue and return. - * The queue will be serviced when we get to a stable state. - */ - if (fnic->state != FNIC_IN_FC_MODE && - fnic->state != FNIC_IN_ETH_MODE) { - skb_queue_head(&fnic->frame_queue, skb); - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - return; - } - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - fc_exch_recv(lp, fp); - } -} - -/** - * fnic_import_rq_eth_pkt() - handle received FCoE or FIP frame. - * @fnic: fnic instance. - * @skb: Ethernet Frame. - */ -static inline int fnic_import_rq_eth_pkt(struct fnic *fnic, struct sk_buff *skb) -{ - struct fc_frame *fp; - struct ethhdr *eh; - struct fcoe_hdr *fcoe_hdr; - struct fcoe_crc_eof *ft; - - /* - * Undo VLAN encapsulation if present. - */ - eh = (struct ethhdr *)skb->data; - if (eh->h_proto == htons(ETH_P_8021Q)) { - memmove((u8 *)eh + VLAN_HLEN, eh, ETH_ALEN * 2); - eh = (struct ethhdr *)skb_pull(skb, VLAN_HLEN); - skb_reset_mac_header(skb); - } - if (eh->h_proto == htons(ETH_P_FIP)) { - skb_pull(skb, sizeof(*eh)); - fcoe_ctlr_recv(&fnic->ctlr, skb); - return 1; /* let caller know packet was used */ - } - if (eh->h_proto != htons(ETH_P_FCOE)) - goto drop; - skb_set_network_header(skb, sizeof(*eh)); - skb_pull(skb, sizeof(*eh)); - - fcoe_hdr = (struct fcoe_hdr *)skb->data; - if (FC_FCOE_DECAPS_VER(fcoe_hdr) != FC_FCOE_VER) - goto drop; - - fp = (struct fc_frame *)skb; - fc_frame_init(fp); - fr_sof(fp) = fcoe_hdr->fcoe_sof; - skb_pull(skb, sizeof(struct fcoe_hdr)); - skb_reset_transport_header(skb); - - ft = (struct fcoe_crc_eof *)(skb->data + skb->len - sizeof(*ft)); - fr_eof(fp) = ft->fcoe_eof; - skb_trim(skb, skb->len - sizeof(*ft)); - return 0; -drop: - dev_kfree_skb_irq(skb); - return -1; -} - -/** - * fnic_update_mac_locked() - set data MAC address and filters. - * @fnic: fnic instance. - * @new: newly-assigned FCoE MAC address. - * - * Called with the fnic lock held. - */ -void fnic_update_mac_locked(struct fnic *fnic, u8 *new) -{ - u8 *ctl = fnic->ctlr.ctl_src_addr; - u8 *data = fnic->data_src_addr; - - if (is_zero_ether_addr(new)) - new = ctl; - if (!compare_ether_addr(data, new)) - return; - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "update_mac %pM\n", new); - if (!is_zero_ether_addr(data) && compare_ether_addr(data, ctl)) - vnic_dev_del_addr(fnic->vdev, data); - memcpy(data, new, ETH_ALEN); - if (compare_ether_addr(new, ctl)) - vnic_dev_add_addr(fnic->vdev, new); -} - -/** - * fnic_update_mac() - set data MAC address and filters. - * @lport: local port. - * @new: newly-assigned FCoE MAC address. - */ -void fnic_update_mac(struct fc_lport *lport, u8 *new) -{ - struct fnic *fnic = lport_priv(lport); - - spin_lock_irq(&fnic->fnic_lock); - fnic_update_mac_locked(fnic, new); - spin_unlock_irq(&fnic->fnic_lock); -} - -/** - * fnic_set_port_id() - set the port_ID after successful FLOGI. - * @lport: local port. - * @port_id: assigned FC_ID. - * @fp: received frame containing the FLOGI accept or NULL. - * - * This is called from libfc when a new FC_ID has been assigned. - * This causes us to reset the firmware to FC_MODE and setup the new MAC - * address and FC_ID. - * - * It is also called with FC_ID 0 when we're logged off. - * - * If the FC_ID is due to point-to-point, fp may be NULL. - */ -void fnic_set_port_id(struct fc_lport *lport, u32 port_id, struct fc_frame *fp) -{ - struct fnic *fnic = lport_priv(lport); - u8 *mac; - int ret; - - FNIC_FCS_DBG(KERN_DEBUG, lport->host, "set port_id %x fp %p\n", - port_id, fp); - - /* - * If we're clearing the FC_ID, change to use the ctl_src_addr. - * Set ethernet mode to send FLOGI. - */ - if (!port_id) { - fnic_update_mac(lport, fnic->ctlr.ctl_src_addr); - fnic_set_eth_mode(fnic); - return; - } - - if (fp) { - mac = fr_cb(fp)->granted_mac; - if (is_zero_ether_addr(mac)) { - /* non-FIP - FLOGI already accepted - ignore return */ - fcoe_ctlr_recv_flogi(&fnic->ctlr, lport, fp); - } - fnic_update_mac(lport, mac); - } - - /* Change state to reflect transition to FC mode */ - spin_lock_irq(&fnic->fnic_lock); - if (fnic->state == FNIC_IN_ETH_MODE || fnic->state == FNIC_IN_FC_MODE) - fnic->state = FNIC_IN_ETH_TRANS_FC_MODE; - else { - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "Unexpected fnic state %s while" - " processing flogi resp\n", - fnic_state_to_str(fnic->state)); - spin_unlock_irq(&fnic->fnic_lock); - return; - } - spin_unlock_irq(&fnic->fnic_lock); - - /* - * Send FLOGI registration to firmware to set up FC mode. - * The new address will be set up when registration completes. - */ - ret = fnic_flogi_reg_handler(fnic, port_id); - - if (ret < 0) { - spin_lock_irq(&fnic->fnic_lock); - if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) - fnic->state = FNIC_IN_ETH_MODE; - spin_unlock_irq(&fnic->fnic_lock); - } -} - -static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc - *cq_desc, struct vnic_rq_buf *buf, - int skipped __attribute__((unused)), - void *opaque) -{ - struct fnic *fnic = vnic_dev_priv(rq->vdev); - struct sk_buff *skb; - struct fc_frame *fp; - unsigned int eth_hdrs_stripped; - u8 type, color, eop, sop, ingress_port, vlan_stripped; - u8 fcoe = 0, fcoe_sof, fcoe_eof; - u8 fcoe_fc_crc_ok = 1, fcoe_enc_error = 0; - u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok; - u8 ipv6, ipv4, ipv4_fragment, rss_type, csum_not_calc; - u8 fcs_ok = 1, packet_error = 0; - u16 q_number, completed_index, bytes_written = 0, vlan, checksum; - u32 rss_hash; - u16 exchange_id, tmpl; - u8 sof = 0; - u8 eof = 0; - u32 fcp_bytes_written = 0; - unsigned long flags; - - pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len, - PCI_DMA_FROMDEVICE); - skb = buf->os_buf; - fp = (struct fc_frame *)skb; - buf->os_buf = NULL; - - cq_desc_dec(cq_desc, &type, &color, &q_number, &completed_index); - if (type == CQ_DESC_TYPE_RQ_FCP) { - cq_fcp_rq_desc_dec((struct cq_fcp_rq_desc *)cq_desc, - &type, &color, &q_number, &completed_index, - &eop, &sop, &fcoe_fc_crc_ok, &exchange_id, - &tmpl, &fcp_bytes_written, &sof, &eof, - &ingress_port, &packet_error, - &fcoe_enc_error, &fcs_ok, &vlan_stripped, - &vlan); - eth_hdrs_stripped = 1; - skb_trim(skb, fcp_bytes_written); - fr_sof(fp) = sof; - fr_eof(fp) = eof; - - } else if (type == CQ_DESC_TYPE_RQ_ENET) { - cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc, - &type, &color, &q_number, &completed_index, - &ingress_port, &fcoe, &eop, &sop, - &rss_type, &csum_not_calc, &rss_hash, - &bytes_written, &packet_error, - &vlan_stripped, &vlan, &checksum, - &fcoe_sof, &fcoe_fc_crc_ok, - &fcoe_enc_error, &fcoe_eof, - &tcp_udp_csum_ok, &udp, &tcp, - &ipv4_csum_ok, &ipv6, &ipv4, - &ipv4_fragment, &fcs_ok); - eth_hdrs_stripped = 0; - skb_trim(skb, bytes_written); - if (!fcs_ok) { - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "fcs error. dropping packet.\n"); - goto drop; - } - if (fnic_import_rq_eth_pkt(fnic, skb)) - return; - - } else { - /* wrong CQ type*/ - shost_printk(KERN_ERR, fnic->lport->host, - "fnic rq_cmpl wrong cq type x%x\n", type); - goto drop; - } - - if (!fcs_ok || packet_error || !fcoe_fc_crc_ok || fcoe_enc_error) { - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "fnic rq_cmpl fcoe x%x fcsok x%x" - " pkterr x%x fcoe_fc_crc_ok x%x, fcoe_enc_err" - " x%x\n", - fcoe, fcs_ok, packet_error, - fcoe_fc_crc_ok, fcoe_enc_error); - goto drop; - } - - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->stop_rx_link_events) { - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - goto drop; - } - fr_dev(fp) = fnic->lport; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - skb_queue_tail(&fnic->frame_queue, skb); - queue_work(fnic_event_queue, &fnic->frame_work); - - return; -drop: - dev_kfree_skb_irq(skb); -} - -static int fnic_rq_cmpl_handler_cont(struct vnic_dev *vdev, - struct cq_desc *cq_desc, u8 type, - u16 q_number, u16 completed_index, - void *opaque) -{ - struct fnic *fnic = vnic_dev_priv(vdev); - - vnic_rq_service(&fnic->rq[q_number], cq_desc, completed_index, - VNIC_RQ_RETURN_DESC, fnic_rq_cmpl_frame_recv, - NULL); - return 0; -} - -int fnic_rq_cmpl_handler(struct fnic *fnic, int rq_work_to_do) -{ - unsigned int tot_rq_work_done = 0, cur_work_done; - unsigned int i; - int err; - - for (i = 0; i < fnic->rq_count; i++) { - cur_work_done = vnic_cq_service(&fnic->cq[i], rq_work_to_do, - fnic_rq_cmpl_handler_cont, - NULL); - if (cur_work_done) { - err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); - if (err) - shost_printk(KERN_ERR, fnic->lport->host, - "fnic_alloc_rq_frame can't alloc" - " frame\n"); - } - tot_rq_work_done += cur_work_done; - } - - return tot_rq_work_done; -} - -/* - * This function is called once at init time to allocate and fill RQ - * buffers. Subsequently, it is called in the interrupt context after RQ - * buffer processing to replenish the buffers in the RQ - */ -int fnic_alloc_rq_frame(struct vnic_rq *rq) -{ - struct fnic *fnic = vnic_dev_priv(rq->vdev); - struct sk_buff *skb; - u16 len; - dma_addr_t pa; - - len = FC_FRAME_HEADROOM + FC_MAX_FRAME + FC_FRAME_TAILROOM; - skb = dev_alloc_skb(len); - if (!skb) { - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "Unable to allocate RQ sk_buff\n"); - return -ENOMEM; - } - skb_reset_mac_header(skb); - skb_reset_transport_header(skb); - skb_reset_network_header(skb); - skb_put(skb, len); - pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE); - fnic_queue_rq_desc(rq, skb, pa, len); - return 0; -} - -void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) -{ - struct fc_frame *fp = buf->os_buf; - struct fnic *fnic = vnic_dev_priv(rq->vdev); - - pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len, - PCI_DMA_FROMDEVICE); - - dev_kfree_skb(fp_skb(fp)); - buf->os_buf = NULL; -} - -/** - * fnic_eth_send() - Send Ethernet frame. - * @fip: fcoe_ctlr instance. - * @skb: Ethernet Frame, FIP, without VLAN encapsulation. - */ -void fnic_eth_send(struct fcoe_ctlr *fip, struct sk_buff *skb) -{ - struct fnic *fnic = fnic_from_ctlr(fip); - struct vnic_wq *wq = &fnic->wq[0]; - dma_addr_t pa; - struct ethhdr *eth_hdr; - struct vlan_ethhdr *vlan_hdr; - unsigned long flags; - - if (!fnic->vlan_hw_insert) { - eth_hdr = (struct ethhdr *)skb_mac_header(skb); - vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, - sizeof(*vlan_hdr) - sizeof(*eth_hdr)); - memcpy(vlan_hdr, eth_hdr, 2 * ETH_ALEN); - vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q); - vlan_hdr->h_vlan_encapsulated_proto = eth_hdr->h_proto; - vlan_hdr->h_vlan_TCI = htons(fnic->vlan_id); - } - - pa = pci_map_single(fnic->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - - spin_lock_irqsave(&fnic->wq_lock[0], flags); - if (!vnic_wq_desc_avail(wq)) { - pci_unmap_single(fnic->pdev, pa, skb->len, PCI_DMA_TODEVICE); - spin_unlock_irqrestore(&fnic->wq_lock[0], flags); - kfree_skb(skb); - return; - } - - fnic_queue_wq_eth_desc(wq, skb, pa, skb->len, - fnic->vlan_hw_insert, fnic->vlan_id, 1); - spin_unlock_irqrestore(&fnic->wq_lock[0], flags); -} - -/* - * Send FC frame. - */ -static int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) -{ - struct vnic_wq *wq = &fnic->wq[0]; - struct sk_buff *skb; - dma_addr_t pa; - struct ethhdr *eth_hdr; - struct vlan_ethhdr *vlan_hdr; - struct fcoe_hdr *fcoe_hdr; - struct fc_frame_header *fh; - u32 tot_len, eth_hdr_len; - int ret = 0; - unsigned long flags; - - fh = fc_frame_header_get(fp); - skb = fp_skb(fp); - - if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ) && - fcoe_ctlr_els_send(&fnic->ctlr, fnic->lport, skb)) - return 0; - - if (!fnic->vlan_hw_insert) { - eth_hdr_len = sizeof(*vlan_hdr) + sizeof(*fcoe_hdr); - vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, eth_hdr_len); - eth_hdr = (struct ethhdr *)vlan_hdr; - vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q); - vlan_hdr->h_vlan_encapsulated_proto = htons(ETH_P_FCOE); - vlan_hdr->h_vlan_TCI = htons(fnic->vlan_id); - fcoe_hdr = (struct fcoe_hdr *)(vlan_hdr + 1); - } else { - eth_hdr_len = sizeof(*eth_hdr) + sizeof(*fcoe_hdr); - eth_hdr = (struct ethhdr *)skb_push(skb, eth_hdr_len); - eth_hdr->h_proto = htons(ETH_P_FCOE); - fcoe_hdr = (struct fcoe_hdr *)(eth_hdr + 1); - } - - if (fnic->ctlr.map_dest) - fc_fcoe_set_mac(eth_hdr->h_dest, fh->fh_d_id); - else - memcpy(eth_hdr->h_dest, fnic->ctlr.dest_addr, ETH_ALEN); - memcpy(eth_hdr->h_source, fnic->data_src_addr, ETH_ALEN); - - tot_len = skb->len; - BUG_ON(tot_len % 4); - - memset(fcoe_hdr, 0, sizeof(*fcoe_hdr)); - fcoe_hdr->fcoe_sof = fr_sof(fp); - if (FC_FCOE_VER) - FC_FCOE_ENCAPS_VER(fcoe_hdr, FC_FCOE_VER); - - pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE); - - spin_lock_irqsave(&fnic->wq_lock[0], flags); - - if (!vnic_wq_desc_avail(wq)) { - pci_unmap_single(fnic->pdev, pa, - tot_len, PCI_DMA_TODEVICE); - ret = -1; - goto fnic_send_frame_end; - } - - fnic_queue_wq_desc(wq, skb, pa, tot_len, fr_eof(fp), - fnic->vlan_hw_insert, fnic->vlan_id, 1, 1, 1); -fnic_send_frame_end: - spin_unlock_irqrestore(&fnic->wq_lock[0], flags); - - if (ret) - dev_kfree_skb_any(fp_skb(fp)); - - return ret; -} - -/* - * fnic_send - * Routine to send a raw frame - */ -int fnic_send(struct fc_lport *lp, struct fc_frame *fp) -{ - struct fnic *fnic = lport_priv(lp); - unsigned long flags; - - if (fnic->in_remove) { - dev_kfree_skb(fp_skb(fp)); - return -1; - } - - /* - * Queue frame if in a transitional state. - * This occurs while registering the Port_ID / MAC address after FLOGI. - */ - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->state != FNIC_IN_FC_MODE && fnic->state != FNIC_IN_ETH_MODE) { - skb_queue_tail(&fnic->tx_queue, fp_skb(fp)); - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - return 0; - } - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - return fnic_send_frame(fnic, fp); -} - -/** - * fnic_flush_tx() - send queued frames. - * @fnic: fnic device - * - * Send frames that were waiting to go out in FC or Ethernet mode. - * Whenever changing modes we purge queued frames, so these frames should - * be queued for the stable mode that we're in, either FC or Ethernet. - * - * Called without fnic_lock held. - */ -void fnic_flush_tx(struct fnic *fnic) -{ - struct sk_buff *skb; - struct fc_frame *fp; - - while ((skb = skb_dequeue(&fnic->tx_queue))) { - fp = (struct fc_frame *)skb; - fnic_send_frame(fnic, fp); - } -} - -/** - * fnic_set_eth_mode() - put fnic into ethernet mode. - * @fnic: fnic device - * - * Called without fnic lock held. - */ -static void fnic_set_eth_mode(struct fnic *fnic) -{ - unsigned long flags; - enum fnic_state old_state; - int ret; - - spin_lock_irqsave(&fnic->fnic_lock, flags); -again: - old_state = fnic->state; - switch (old_state) { - case FNIC_IN_FC_MODE: - case FNIC_IN_ETH_TRANS_FC_MODE: - default: - fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - ret = fnic_fw_reset_handler(fnic); - - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->state != FNIC_IN_FC_TRANS_ETH_MODE) - goto again; - if (ret) - fnic->state = old_state; - break; - - case FNIC_IN_FC_TRANS_ETH_MODE: - case FNIC_IN_ETH_MODE: - break; - } - spin_unlock_irqrestore(&fnic->fnic_lock, flags); -} - -static void fnic_wq_complete_frame_send(struct vnic_wq *wq, - struct cq_desc *cq_desc, - struct vnic_wq_buf *buf, void *opaque) -{ - struct sk_buff *skb = buf->os_buf; - struct fc_frame *fp = (struct fc_frame *)skb; - struct fnic *fnic = vnic_dev_priv(wq->vdev); - - pci_unmap_single(fnic->pdev, buf->dma_addr, - buf->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(fp_skb(fp)); - buf->os_buf = NULL; -} - -static int fnic_wq_cmpl_handler_cont(struct vnic_dev *vdev, - struct cq_desc *cq_desc, u8 type, - u16 q_number, u16 completed_index, - void *opaque) -{ - struct fnic *fnic = vnic_dev_priv(vdev); - unsigned long flags; - - spin_lock_irqsave(&fnic->wq_lock[q_number], flags); - vnic_wq_service(&fnic->wq[q_number], cq_desc, completed_index, - fnic_wq_complete_frame_send, NULL); - spin_unlock_irqrestore(&fnic->wq_lock[q_number], flags); - - return 0; -} - -int fnic_wq_cmpl_handler(struct fnic *fnic, int work_to_do) -{ - unsigned int wq_work_done = 0; - unsigned int i; - - for (i = 0; i < fnic->raw_wq_count; i++) { - wq_work_done += vnic_cq_service(&fnic->cq[fnic->rq_count+i], - work_to_do, - fnic_wq_cmpl_handler_cont, - NULL); - } - - return wq_work_done; -} - - -void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) -{ - struct fc_frame *fp = buf->os_buf; - struct fnic *fnic = vnic_dev_priv(wq->vdev); - - pci_unmap_single(fnic->pdev, buf->dma_addr, - buf->len, PCI_DMA_TODEVICE); - - dev_kfree_skb(fp_skb(fp)); - buf->os_buf = NULL; -} diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_io.h b/ANDROID_3.4.5/drivers/scsi/fnic/fnic_io.h deleted file mode 100644 index f0b89698..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_io.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _FNIC_IO_H_ -#define _FNIC_IO_H_ - -#include - -#define FNIC_DFLT_SG_DESC_CNT 32 -#define FNIC_MAX_SG_DESC_CNT 1024 /* Maximum descriptors per sgl */ -#define FNIC_SG_DESC_ALIGN 16 /* Descriptor address alignment */ - -struct host_sg_desc { - __le64 addr; - __le32 len; - u32 _resvd; -}; - -struct fnic_dflt_sgl_list { - struct host_sg_desc sg_desc[FNIC_DFLT_SG_DESC_CNT]; -}; - -struct fnic_sgl_list { - struct host_sg_desc sg_desc[FNIC_MAX_SG_DESC_CNT]; -}; - -enum fnic_sgl_list_type { - FNIC_SGL_CACHE_DFLT = 0, /* cache with default size sgl */ - FNIC_SGL_CACHE_MAX, /* cache with max size sgl */ - FNIC_SGL_NUM_CACHES /* number of sgl caches */ -}; - -enum fnic_ioreq_state { - FNIC_IOREQ_CMD_PENDING = 0, - FNIC_IOREQ_ABTS_PENDING, - FNIC_IOREQ_ABTS_COMPLETE, - FNIC_IOREQ_CMD_COMPLETE, -}; - -struct fnic_io_req { - struct host_sg_desc *sgl_list; /* sgl list */ - void *sgl_list_alloc; /* sgl list address used for free */ - dma_addr_t sense_buf_pa; /* dma address for sense buffer*/ - dma_addr_t sgl_list_pa; /* dma address for sgl list */ - u16 sgl_cnt; - u8 sgl_type; /* device DMA descriptor list type */ - u8 io_completed:1; /* set to 1 when fw completes IO */ - u32 port_id; /* remote port DID */ - struct completion *abts_done; /* completion for abts */ - struct completion *dr_done; /* completion for device reset */ -}; - -#endif /* _FNIC_IO_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_isr.c b/ANDROID_3.4.5/drivers/scsi/fnic/fnic_isr.c deleted file mode 100644 index 5c1f223c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_isr.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include "vnic_dev.h" -#include "vnic_intr.h" -#include "vnic_stats.h" -#include "fnic_io.h" -#include "fnic.h" - -static irqreturn_t fnic_isr_legacy(int irq, void *data) -{ - struct fnic *fnic = data; - u32 pba; - unsigned long work_done = 0; - - pba = vnic_intr_legacy_pba(fnic->legacy_pba); - if (!pba) - return IRQ_NONE; - - if (pba & (1 << FNIC_INTX_NOTIFY)) { - vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_NOTIFY]); - fnic_handle_link_event(fnic); - } - - if (pba & (1 << FNIC_INTX_ERR)) { - vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_ERR]); - fnic_log_q_error(fnic); - } - - if (pba & (1 << FNIC_INTX_WQ_RQ_COPYWQ)) { - work_done += fnic_wq_copy_cmpl_handler(fnic, -1); - work_done += fnic_wq_cmpl_handler(fnic, -1); - work_done += fnic_rq_cmpl_handler(fnic, -1); - - vnic_intr_return_credits(&fnic->intr[FNIC_INTX_WQ_RQ_COPYWQ], - work_done, - 1 /* unmask intr */, - 1 /* reset intr timer */); - } - - return IRQ_HANDLED; -} - -static irqreturn_t fnic_isr_msi(int irq, void *data) -{ - struct fnic *fnic = data; - unsigned long work_done = 0; - - work_done += fnic_wq_copy_cmpl_handler(fnic, -1); - work_done += fnic_wq_cmpl_handler(fnic, -1); - work_done += fnic_rq_cmpl_handler(fnic, -1); - - vnic_intr_return_credits(&fnic->intr[0], - work_done, - 1 /* unmask intr */, - 1 /* reset intr timer */); - - return IRQ_HANDLED; -} - -static irqreturn_t fnic_isr_msix_rq(int irq, void *data) -{ - struct fnic *fnic = data; - unsigned long rq_work_done = 0; - - rq_work_done = fnic_rq_cmpl_handler(fnic, -1); - vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_RQ], - rq_work_done, - 1 /* unmask intr */, - 1 /* reset intr timer */); - - return IRQ_HANDLED; -} - -static irqreturn_t fnic_isr_msix_wq(int irq, void *data) -{ - struct fnic *fnic = data; - unsigned long wq_work_done = 0; - - wq_work_done = fnic_wq_cmpl_handler(fnic, -1); - vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ], - wq_work_done, - 1 /* unmask intr */, - 1 /* reset intr timer */); - return IRQ_HANDLED; -} - -static irqreturn_t fnic_isr_msix_wq_copy(int irq, void *data) -{ - struct fnic *fnic = data; - unsigned long wq_copy_work_done = 0; - - wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, -1); - vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ_COPY], - wq_copy_work_done, - 1 /* unmask intr */, - 1 /* reset intr timer */); - return IRQ_HANDLED; -} - -static irqreturn_t fnic_isr_msix_err_notify(int irq, void *data) -{ - struct fnic *fnic = data; - - vnic_intr_return_all_credits(&fnic->intr[FNIC_MSIX_ERR_NOTIFY]); - fnic_log_q_error(fnic); - fnic_handle_link_event(fnic); - - return IRQ_HANDLED; -} - -void fnic_free_intr(struct fnic *fnic) -{ - int i; - - switch (vnic_dev_get_intr_mode(fnic->vdev)) { - case VNIC_DEV_INTR_MODE_INTX: - case VNIC_DEV_INTR_MODE_MSI: - free_irq(fnic->pdev->irq, fnic); - break; - - case VNIC_DEV_INTR_MODE_MSIX: - for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) - if (fnic->msix[i].requested) - free_irq(fnic->msix_entry[i].vector, - fnic->msix[i].devid); - break; - - default: - break; - } -} - -int fnic_request_intr(struct fnic *fnic) -{ - int err = 0; - int i; - - switch (vnic_dev_get_intr_mode(fnic->vdev)) { - - case VNIC_DEV_INTR_MODE_INTX: - err = request_irq(fnic->pdev->irq, &fnic_isr_legacy, - IRQF_SHARED, DRV_NAME, fnic); - break; - - case VNIC_DEV_INTR_MODE_MSI: - err = request_irq(fnic->pdev->irq, &fnic_isr_msi, - 0, fnic->name, fnic); - break; - - case VNIC_DEV_INTR_MODE_MSIX: - - sprintf(fnic->msix[FNIC_MSIX_RQ].devname, - "%.11s-fcs-rq", fnic->name); - fnic->msix[FNIC_MSIX_RQ].isr = fnic_isr_msix_rq; - fnic->msix[FNIC_MSIX_RQ].devid = fnic; - - sprintf(fnic->msix[FNIC_MSIX_WQ].devname, - "%.11s-fcs-wq", fnic->name); - fnic->msix[FNIC_MSIX_WQ].isr = fnic_isr_msix_wq; - fnic->msix[FNIC_MSIX_WQ].devid = fnic; - - sprintf(fnic->msix[FNIC_MSIX_WQ_COPY].devname, - "%.11s-scsi-wq", fnic->name); - fnic->msix[FNIC_MSIX_WQ_COPY].isr = fnic_isr_msix_wq_copy; - fnic->msix[FNIC_MSIX_WQ_COPY].devid = fnic; - - sprintf(fnic->msix[FNIC_MSIX_ERR_NOTIFY].devname, - "%.11s-err-notify", fnic->name); - fnic->msix[FNIC_MSIX_ERR_NOTIFY].isr = - fnic_isr_msix_err_notify; - fnic->msix[FNIC_MSIX_ERR_NOTIFY].devid = fnic; - - for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) { - err = request_irq(fnic->msix_entry[i].vector, - fnic->msix[i].isr, 0, - fnic->msix[i].devname, - fnic->msix[i].devid); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "MSIX: request_irq" - " failed %d\n", err); - fnic_free_intr(fnic); - break; - } - fnic->msix[i].requested = 1; - } - break; - - default: - break; - } - - return err; -} - -int fnic_set_intr_mode(struct fnic *fnic) -{ - unsigned int n = ARRAY_SIZE(fnic->rq); - unsigned int m = ARRAY_SIZE(fnic->wq); - unsigned int o = ARRAY_SIZE(fnic->wq_copy); - unsigned int i; - - /* - * Set interrupt mode (INTx, MSI, MSI-X) depending - * system capabilities. - * - * Try MSI-X first - * - * We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs - * (last INTR is used for WQ/RQ errors and notification area) - */ - - BUG_ON(ARRAY_SIZE(fnic->msix_entry) < n + m + o + 1); - for (i = 0; i < n + m + o + 1; i++) - fnic->msix_entry[i].entry = i; - - if (fnic->rq_count >= n && - fnic->raw_wq_count >= m && - fnic->wq_copy_count >= o && - fnic->cq_count >= n + m + o) { - if (!pci_enable_msix(fnic->pdev, fnic->msix_entry, - n + m + o + 1)) { - fnic->rq_count = n; - fnic->raw_wq_count = m; - fnic->wq_copy_count = o; - fnic->wq_count = m + o; - fnic->cq_count = n + m + o; - fnic->intr_count = n + m + o + 1; - fnic->err_intr_offset = FNIC_MSIX_ERR_NOTIFY; - - FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, - "Using MSI-X Interrupts\n"); - vnic_dev_set_intr_mode(fnic->vdev, - VNIC_DEV_INTR_MODE_MSIX); - return 0; - } - } - - /* - * Next try MSI - * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 1 INTR - */ - if (fnic->rq_count >= 1 && - fnic->raw_wq_count >= 1 && - fnic->wq_copy_count >= 1 && - fnic->cq_count >= 3 && - fnic->intr_count >= 1 && - !pci_enable_msi(fnic->pdev)) { - - fnic->rq_count = 1; - fnic->raw_wq_count = 1; - fnic->wq_copy_count = 1; - fnic->wq_count = 2; - fnic->cq_count = 3; - fnic->intr_count = 1; - fnic->err_intr_offset = 0; - - FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, - "Using MSI Interrupts\n"); - vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI); - - return 0; - } - - /* - * Next try INTx - * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 3 INTRs - * 1 INTR is used for all 3 queues, 1 INTR for queue errors - * 1 INTR for notification area - */ - - if (fnic->rq_count >= 1 && - fnic->raw_wq_count >= 1 && - fnic->wq_copy_count >= 1 && - fnic->cq_count >= 3 && - fnic->intr_count >= 3) { - - fnic->rq_count = 1; - fnic->raw_wq_count = 1; - fnic->wq_copy_count = 1; - fnic->cq_count = 3; - fnic->intr_count = 3; - - FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, - "Using Legacy Interrupts\n"); - vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX); - - return 0; - } - - vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); - - return -EINVAL; -} - -void fnic_clear_intr_mode(struct fnic *fnic) -{ - switch (vnic_dev_get_intr_mode(fnic->vdev)) { - case VNIC_DEV_INTR_MODE_MSIX: - pci_disable_msix(fnic->pdev); - break; - case VNIC_DEV_INTR_MODE_MSI: - pci_disable_msi(fnic->pdev); - break; - default: - break; - } - - vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_main.c b/ANDROID_3.4.5/drivers/scsi/fnic/fnic_main.c deleted file mode 100644 index fc98eb61..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_main.c +++ /dev/null @@ -1,947 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vnic_dev.h" -#include "vnic_intr.h" -#include "vnic_stats.h" -#include "fnic_io.h" -#include "fnic.h" - -#define PCI_DEVICE_ID_CISCO_FNIC 0x0045 - -/* Timer to poll notification area for events. Used for MSI interrupts */ -#define FNIC_NOTIFY_TIMER_PERIOD (2 * HZ) - -static struct kmem_cache *fnic_sgl_cache[FNIC_SGL_NUM_CACHES]; -static struct kmem_cache *fnic_io_req_cache; -LIST_HEAD(fnic_list); -DEFINE_SPINLOCK(fnic_list_lock); - -/* Supported devices by fnic module */ -static struct pci_device_id fnic_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_CISCO_FNIC) }, - { 0, } -}; - -MODULE_DESCRIPTION(DRV_DESCRIPTION); -MODULE_AUTHOR("Abhijeet Joglekar , " - "Joseph R. Eykholt "); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(DRV_VERSION); -MODULE_DEVICE_TABLE(pci, fnic_id_table); - -unsigned int fnic_log_level; -module_param(fnic_log_level, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels"); - - -static struct libfc_function_template fnic_transport_template = { - .frame_send = fnic_send, - .lport_set_port_id = fnic_set_port_id, - .fcp_abort_io = fnic_empty_scsi_cleanup, - .fcp_cleanup = fnic_empty_scsi_cleanup, - .exch_mgr_reset = fnic_exch_mgr_reset -}; - -static int fnic_slave_alloc(struct scsi_device *sdev) -{ - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - - sdev->tagged_supported = 1; - - if (!rport || fc_remote_port_chkready(rport)) - return -ENXIO; - - scsi_activate_tcq(sdev, FNIC_DFLT_QUEUE_DEPTH); - return 0; -} - -static struct scsi_host_template fnic_host_template = { - .module = THIS_MODULE, - .name = DRV_NAME, - .queuecommand = fnic_queuecommand, - .eh_abort_handler = fnic_abort_cmd, - .eh_device_reset_handler = fnic_device_reset, - .eh_host_reset_handler = fnic_host_reset, - .slave_alloc = fnic_slave_alloc, - .change_queue_depth = fc_change_queue_depth, - .change_queue_type = fc_change_queue_type, - .this_id = -1, - .cmd_per_lun = 3, - .can_queue = FNIC_MAX_IO_REQ, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = FNIC_MAX_SG_DESC_CNT, - .max_sectors = 0xffff, - .shost_attrs = fnic_attrs, -}; - -static void -fnic_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) -{ - if (timeout) - rport->dev_loss_tmo = timeout; - else - rport->dev_loss_tmo = 1; -} - -static void fnic_get_host_speed(struct Scsi_Host *shost); -static struct scsi_transport_template *fnic_fc_transport; -static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *); - -static struct fc_function_template fnic_fc_functions = { - - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_active_fc4s = 1, - .show_host_maxframe_size = 1, - .show_host_port_id = 1, - .show_host_supported_speeds = 1, - .get_host_speed = fnic_get_host_speed, - .show_host_speed = 1, - .show_host_port_type = 1, - .get_host_port_state = fc_get_host_port_state, - .show_host_port_state = 1, - .show_host_symbolic_name = 1, - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - .show_host_fabric_name = 1, - .show_starget_node_name = 1, - .show_starget_port_name = 1, - .show_starget_port_id = 1, - .show_rport_dev_loss_tmo = 1, - .set_rport_dev_loss_tmo = fnic_set_rport_dev_loss_tmo, - .issue_fc_host_lip = fnic_reset, - .get_fc_host_stats = fnic_get_stats, - .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), - .terminate_rport_io = fnic_terminate_rport_io, - .bsg_request = fc_lport_bsg_request, -}; - -static void fnic_get_host_speed(struct Scsi_Host *shost) -{ - struct fc_lport *lp = shost_priv(shost); - struct fnic *fnic = lport_priv(lp); - u32 port_speed = vnic_dev_port_speed(fnic->vdev); - - /* Add in other values as they get defined in fw */ - switch (port_speed) { - case 10000: - fc_host_speed(shost) = FC_PORTSPEED_10GBIT; - break; - default: - fc_host_speed(shost) = FC_PORTSPEED_10GBIT; - break; - } -} - -static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host) -{ - int ret; - struct fc_lport *lp = shost_priv(host); - struct fnic *fnic = lport_priv(lp); - struct fc_host_statistics *stats = &lp->host_stats; - struct vnic_stats *vs; - unsigned long flags; - - if (time_before(jiffies, fnic->stats_time + HZ / FNIC_STATS_RATE_LIMIT)) - return stats; - fnic->stats_time = jiffies; - - spin_lock_irqsave(&fnic->fnic_lock, flags); - ret = vnic_dev_stats_dump(fnic->vdev, &fnic->stats); - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - if (ret) { - FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, - "fnic: Get vnic stats failed" - " 0x%x", ret); - return stats; - } - vs = fnic->stats; - stats->tx_frames = vs->tx.tx_unicast_frames_ok; - stats->tx_words = vs->tx.tx_unicast_bytes_ok / 4; - stats->rx_frames = vs->rx.rx_unicast_frames_ok; - stats->rx_words = vs->rx.rx_unicast_bytes_ok / 4; - stats->error_frames = vs->tx.tx_errors + vs->rx.rx_errors; - stats->dumped_frames = vs->tx.tx_drops + vs->rx.rx_drop; - stats->invalid_crc_count = vs->rx.rx_crc_errors; - stats->seconds_since_last_reset = (jiffies - lp->boot_time) / HZ; - stats->fcp_input_megabytes = div_u64(fnic->fcp_input_bytes, 1000000); - stats->fcp_output_megabytes = div_u64(fnic->fcp_output_bytes, 1000000); - - return stats; -} - -void fnic_log_q_error(struct fnic *fnic) -{ - unsigned int i; - u32 error_status; - - for (i = 0; i < fnic->raw_wq_count; i++) { - error_status = ioread32(&fnic->wq[i].ctrl->error_status); - if (error_status) - shost_printk(KERN_ERR, fnic->lport->host, - "WQ[%d] error_status" - " %d\n", i, error_status); - } - - for (i = 0; i < fnic->rq_count; i++) { - error_status = ioread32(&fnic->rq[i].ctrl->error_status); - if (error_status) - shost_printk(KERN_ERR, fnic->lport->host, - "RQ[%d] error_status" - " %d\n", i, error_status); - } - - for (i = 0; i < fnic->wq_copy_count; i++) { - error_status = ioread32(&fnic->wq_copy[i].ctrl->error_status); - if (error_status) - shost_printk(KERN_ERR, fnic->lport->host, - "CWQ[%d] error_status" - " %d\n", i, error_status); - } -} - -void fnic_handle_link_event(struct fnic *fnic) -{ - unsigned long flags; - - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->stop_rx_link_events) { - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - return; - } - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - queue_work(fnic_event_queue, &fnic->link_work); - -} - -static int fnic_notify_set(struct fnic *fnic) -{ - int err; - - switch (vnic_dev_get_intr_mode(fnic->vdev)) { - case VNIC_DEV_INTR_MODE_INTX: - err = vnic_dev_notify_set(fnic->vdev, FNIC_INTX_NOTIFY); - break; - case VNIC_DEV_INTR_MODE_MSI: - err = vnic_dev_notify_set(fnic->vdev, -1); - break; - case VNIC_DEV_INTR_MODE_MSIX: - err = vnic_dev_notify_set(fnic->vdev, FNIC_MSIX_ERR_NOTIFY); - break; - default: - shost_printk(KERN_ERR, fnic->lport->host, - "Interrupt mode should be set up" - " before devcmd notify set %d\n", - vnic_dev_get_intr_mode(fnic->vdev)); - err = -1; - break; - } - - return err; -} - -static void fnic_notify_timer(unsigned long data) -{ - struct fnic *fnic = (struct fnic *)data; - - fnic_handle_link_event(fnic); - mod_timer(&fnic->notify_timer, - round_jiffies(jiffies + FNIC_NOTIFY_TIMER_PERIOD)); -} - -static void fnic_notify_timer_start(struct fnic *fnic) -{ - switch (vnic_dev_get_intr_mode(fnic->vdev)) { - case VNIC_DEV_INTR_MODE_MSI: - /* - * Schedule first timeout immediately. The driver is - * initiatialized and ready to look for link up notification - */ - mod_timer(&fnic->notify_timer, jiffies); - break; - default: - /* Using intr for notification for INTx/MSI-X */ - break; - }; -} - -static int fnic_dev_wait(struct vnic_dev *vdev, - int (*start)(struct vnic_dev *, int), - int (*finished)(struct vnic_dev *, int *), - int arg) -{ - unsigned long time; - int done; - int err; - - err = start(vdev, arg); - if (err) - return err; - - /* Wait for func to complete...2 seconds max */ - time = jiffies + (HZ * 2); - do { - err = finished(vdev, &done); - if (err) - return err; - if (done) - return 0; - schedule_timeout_uninterruptible(HZ / 10); - } while (time_after(time, jiffies)); - - return -ETIMEDOUT; -} - -static int fnic_cleanup(struct fnic *fnic) -{ - unsigned int i; - int err; - - vnic_dev_disable(fnic->vdev); - for (i = 0; i < fnic->intr_count; i++) - vnic_intr_mask(&fnic->intr[i]); - - for (i = 0; i < fnic->rq_count; i++) { - err = vnic_rq_disable(&fnic->rq[i]); - if (err) - return err; - } - for (i = 0; i < fnic->raw_wq_count; i++) { - err = vnic_wq_disable(&fnic->wq[i]); - if (err) - return err; - } - for (i = 0; i < fnic->wq_copy_count; i++) { - err = vnic_wq_copy_disable(&fnic->wq_copy[i]); - if (err) - return err; - } - - /* Clean up completed IOs and FCS frames */ - fnic_wq_copy_cmpl_handler(fnic, -1); - fnic_wq_cmpl_handler(fnic, -1); - fnic_rq_cmpl_handler(fnic, -1); - - /* Clean up the IOs and FCS frames that have not completed */ - for (i = 0; i < fnic->raw_wq_count; i++) - vnic_wq_clean(&fnic->wq[i], fnic_free_wq_buf); - for (i = 0; i < fnic->rq_count; i++) - vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); - for (i = 0; i < fnic->wq_copy_count; i++) - vnic_wq_copy_clean(&fnic->wq_copy[i], - fnic_wq_copy_cleanup_handler); - - for (i = 0; i < fnic->cq_count; i++) - vnic_cq_clean(&fnic->cq[i]); - for (i = 0; i < fnic->intr_count; i++) - vnic_intr_clean(&fnic->intr[i]); - - mempool_destroy(fnic->io_req_pool); - for (i = 0; i < FNIC_SGL_NUM_CACHES; i++) - mempool_destroy(fnic->io_sgl_pool[i]); - - return 0; -} - -static void fnic_iounmap(struct fnic *fnic) -{ - if (fnic->bar0.vaddr) - iounmap(fnic->bar0.vaddr); -} - -/** - * fnic_get_mac() - get assigned data MAC address for FIP code. - * @lport: local port. - */ -static u8 *fnic_get_mac(struct fc_lport *lport) -{ - struct fnic *fnic = lport_priv(lport); - - return fnic->data_src_addr; -} - -static int __devinit fnic_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct Scsi_Host *host; - struct fc_lport *lp; - struct fnic *fnic; - mempool_t *pool; - int err; - int i; - unsigned long flags; - - /* - * Allocate SCSI Host and set up association between host, - * local port, and fnic - */ - lp = libfc_host_alloc(&fnic_host_template, sizeof(struct fnic)); - if (!lp) { - printk(KERN_ERR PFX "Unable to alloc libfc local port\n"); - err = -ENOMEM; - goto err_out; - } - host = lp->host; - fnic = lport_priv(lp); - fnic->lport = lp; - fnic->ctlr.lp = lp; - - snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME, - host->host_no); - - host->transportt = fnic_fc_transport; - - err = scsi_init_shared_tag_map(host, FNIC_MAX_IO_REQ); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to alloc shared tag map\n"); - goto err_out_free_hba; - } - - /* Setup PCI resources */ - pci_set_drvdata(pdev, fnic); - - fnic->pdev = pdev; - - err = pci_enable_device(pdev); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Cannot enable PCI device, aborting.\n"); - goto err_out_free_hba; - } - - err = pci_request_regions(pdev, DRV_NAME); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Cannot enable PCI resources, aborting\n"); - goto err_out_disable_device; - } - - pci_set_master(pdev); - - /* Query PCI controller on system for DMA addressing - * limitation for the device. Try 40-bit first, and - * fail to 32-bit. - */ - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(40)); - if (err) { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "No usable DMA configuration " - "aborting\n"); - goto err_out_release_regions; - } - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to obtain 32-bit DMA " - "for consistent allocations, aborting.\n"); - goto err_out_release_regions; - } - } else { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(40)); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to obtain 40-bit DMA " - "for consistent allocations, aborting.\n"); - goto err_out_release_regions; - } - } - - /* Map vNIC resources from BAR0 */ - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - shost_printk(KERN_ERR, fnic->lport->host, - "BAR0 not memory-map'able, aborting.\n"); - err = -ENODEV; - goto err_out_release_regions; - } - - fnic->bar0.vaddr = pci_iomap(pdev, 0, 0); - fnic->bar0.bus_addr = pci_resource_start(pdev, 0); - fnic->bar0.len = pci_resource_len(pdev, 0); - - if (!fnic->bar0.vaddr) { - shost_printk(KERN_ERR, fnic->lport->host, - "Cannot memory-map BAR0 res hdr, " - "aborting.\n"); - err = -ENODEV; - goto err_out_release_regions; - } - - fnic->vdev = vnic_dev_register(NULL, fnic, pdev, &fnic->bar0); - if (!fnic->vdev) { - shost_printk(KERN_ERR, fnic->lport->host, - "vNIC registration failed, " - "aborting.\n"); - err = -ENODEV; - goto err_out_iounmap; - } - - err = fnic_dev_wait(fnic->vdev, vnic_dev_open, - vnic_dev_open_done, 0); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "vNIC dev open failed, aborting.\n"); - goto err_out_vnic_unregister; - } - - err = vnic_dev_init(fnic->vdev, 0); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "vNIC dev init failed, aborting.\n"); - goto err_out_dev_close; - } - - err = vnic_dev_mac_addr(fnic->vdev, fnic->ctlr.ctl_src_addr); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "vNIC get MAC addr failed \n"); - goto err_out_dev_close; - } - /* set data_src for point-to-point mode and to keep it non-zero */ - memcpy(fnic->data_src_addr, fnic->ctlr.ctl_src_addr, ETH_ALEN); - - /* Get vNIC configuration */ - err = fnic_get_vnic_config(fnic); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Get vNIC configuration failed, " - "aborting.\n"); - goto err_out_dev_close; - } - host->max_lun = fnic->config.luns_per_tgt; - host->max_id = FNIC_MAX_FCP_TARGET; - host->max_cmd_len = FCOE_MAX_CMD_LEN; - - fnic_get_res_counts(fnic); - - err = fnic_set_intr_mode(fnic); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Failed to set intr mode, " - "aborting.\n"); - goto err_out_dev_close; - } - - err = fnic_alloc_vnic_resources(fnic); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Failed to alloc vNIC resources, " - "aborting.\n"); - goto err_out_clear_intr; - } - - - /* initialize all fnic locks */ - spin_lock_init(&fnic->fnic_lock); - - for (i = 0; i < FNIC_WQ_MAX; i++) - spin_lock_init(&fnic->wq_lock[i]); - - for (i = 0; i < FNIC_WQ_COPY_MAX; i++) { - spin_lock_init(&fnic->wq_copy_lock[i]); - fnic->wq_copy_desc_low[i] = DESC_CLEAN_LOW_WATERMARK; - fnic->fw_ack_recd[i] = 0; - fnic->fw_ack_index[i] = -1; - } - - for (i = 0; i < FNIC_IO_LOCKS; i++) - spin_lock_init(&fnic->io_req_lock[i]); - - fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache); - if (!fnic->io_req_pool) - goto err_out_free_resources; - - pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); - if (!pool) - goto err_out_free_ioreq_pool; - fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT] = pool; - - pool = mempool_create_slab_pool(2, fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); - if (!pool) - goto err_out_free_dflt_pool; - fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX] = pool; - - /* setup vlan config, hw inserts vlan header */ - fnic->vlan_hw_insert = 1; - fnic->vlan_id = 0; - - /* Initialize the FIP fcoe_ctrl struct */ - fnic->ctlr.send = fnic_eth_send; - fnic->ctlr.update_mac = fnic_update_mac; - fnic->ctlr.get_src_addr = fnic_get_mac; - if (fnic->config.flags & VFCF_FIP_CAPABLE) { - shost_printk(KERN_INFO, fnic->lport->host, - "firmware supports FIP\n"); - /* enable directed and multicast */ - vnic_dev_packet_filter(fnic->vdev, 1, 1, 0, 0, 0); - vnic_dev_add_addr(fnic->vdev, FIP_ALL_ENODE_MACS); - vnic_dev_add_addr(fnic->vdev, fnic->ctlr.ctl_src_addr); - fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_AUTO); - } else { - shost_printk(KERN_INFO, fnic->lport->host, - "firmware uses non-FIP mode\n"); - fcoe_ctlr_init(&fnic->ctlr, FIP_MODE_NON_FIP); - } - fnic->state = FNIC_IN_FC_MODE; - - /* Enable hardware stripping of vlan header on ingress */ - fnic_set_nic_config(fnic, 0, 0, 0, 0, 0, 0, 1); - - /* Setup notification buffer area */ - err = fnic_notify_set(fnic); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Failed to alloc notify buffer, aborting.\n"); - goto err_out_free_max_pool; - } - - /* Setup notify timer when using MSI interrupts */ - if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) - setup_timer(&fnic->notify_timer, - fnic_notify_timer, (unsigned long)fnic); - - /* allocate RQ buffers and post them to RQ*/ - for (i = 0; i < fnic->rq_count; i++) { - err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "fnic_alloc_rq_frame can't alloc " - "frame\n"); - goto err_out_free_rq_buf; - } - } - - /* - * Initialization done with PCI system, hardware, firmware. - * Add host to SCSI - */ - err = scsi_add_host(lp->host, &pdev->dev); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "fnic: scsi_add_host failed...exiting\n"); - goto err_out_free_rq_buf; - } - - /* Start local port initiatialization */ - - lp->link_up = 0; - - lp->max_retry_count = fnic->config.flogi_retries; - lp->max_rport_retry_count = fnic->config.plogi_retries; - lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | - FCP_SPPF_CONF_COMPL); - if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) - lp->service_params |= FCP_SPPF_RETRY; - - lp->boot_time = jiffies; - lp->e_d_tov = fnic->config.ed_tov; - lp->r_a_tov = fnic->config.ra_tov; - lp->link_supported_speeds = FC_PORTSPEED_10GBIT; - fc_set_wwnn(lp, fnic->config.node_wwn); - fc_set_wwpn(lp, fnic->config.port_wwn); - - fcoe_libfc_config(lp, &fnic->ctlr, &fnic_transport_template, 0); - - if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START, - FCPIO_HOST_EXCH_RANGE_END, NULL)) { - err = -ENOMEM; - goto err_out_remove_scsi_host; - } - - fc_lport_init_stats(lp); - - fc_lport_config(lp); - - if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + - sizeof(struct fc_frame_header))) { - err = -EINVAL; - goto err_out_free_exch_mgr; - } - fc_host_maxframe_size(lp->host) = lp->mfs; - fc_host_dev_loss_tmo(lp->host) = fnic->config.port_down_timeout / 1000; - - sprintf(fc_host_symbolic_name(lp->host), - DRV_NAME " v" DRV_VERSION " over %s", fnic->name); - - spin_lock_irqsave(&fnic_list_lock, flags); - list_add_tail(&fnic->list, &fnic_list); - spin_unlock_irqrestore(&fnic_list_lock, flags); - - INIT_WORK(&fnic->link_work, fnic_handle_link); - INIT_WORK(&fnic->frame_work, fnic_handle_frame); - skb_queue_head_init(&fnic->frame_queue); - skb_queue_head_init(&fnic->tx_queue); - - /* Enable all queues */ - for (i = 0; i < fnic->raw_wq_count; i++) - vnic_wq_enable(&fnic->wq[i]); - for (i = 0; i < fnic->rq_count; i++) - vnic_rq_enable(&fnic->rq[i]); - for (i = 0; i < fnic->wq_copy_count; i++) - vnic_wq_copy_enable(&fnic->wq_copy[i]); - - fc_fabric_login(lp); - - vnic_dev_enable(fnic->vdev); - - err = fnic_request_intr(fnic); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to request irq.\n"); - goto err_out_free_exch_mgr; - } - - for (i = 0; i < fnic->intr_count; i++) - vnic_intr_unmask(&fnic->intr[i]); - - fnic_notify_timer_start(fnic); - - return 0; - -err_out_free_exch_mgr: - fc_exch_mgr_free(lp); -err_out_remove_scsi_host: - fc_remove_host(lp->host); - scsi_remove_host(lp->host); -err_out_free_rq_buf: - for (i = 0; i < fnic->rq_count; i++) - vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); - vnic_dev_notify_unset(fnic->vdev); -err_out_free_max_pool: - mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX]); -err_out_free_dflt_pool: - mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT]); -err_out_free_ioreq_pool: - mempool_destroy(fnic->io_req_pool); -err_out_free_resources: - fnic_free_vnic_resources(fnic); -err_out_clear_intr: - fnic_clear_intr_mode(fnic); -err_out_dev_close: - vnic_dev_close(fnic->vdev); -err_out_vnic_unregister: - vnic_dev_unregister(fnic->vdev); -err_out_iounmap: - fnic_iounmap(fnic); -err_out_release_regions: - pci_release_regions(pdev); -err_out_disable_device: - pci_disable_device(pdev); -err_out_free_hba: - scsi_host_put(lp->host); -err_out: - return err; -} - -static void __devexit fnic_remove(struct pci_dev *pdev) -{ - struct fnic *fnic = pci_get_drvdata(pdev); - struct fc_lport *lp = fnic->lport; - unsigned long flags; - - /* - * Mark state so that the workqueue thread stops forwarding - * received frames and link events to the local port. ISR and - * other threads that can queue work items will also stop - * creating work items on the fnic workqueue - */ - spin_lock_irqsave(&fnic->fnic_lock, flags); - fnic->stop_rx_link_events = 1; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) - del_timer_sync(&fnic->notify_timer); - - /* - * Flush the fnic event queue. After this call, there should - * be no event queued for this fnic device in the workqueue - */ - flush_workqueue(fnic_event_queue); - skb_queue_purge(&fnic->frame_queue); - skb_queue_purge(&fnic->tx_queue); - - /* - * Log off the fabric. This stops all remote ports, dns port, - * logs off the fabric. This flushes all rport, disc, lport work - * before returning - */ - fc_fabric_logoff(fnic->lport); - - spin_lock_irqsave(&fnic->fnic_lock, flags); - fnic->in_remove = 1; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - fcoe_ctlr_destroy(&fnic->ctlr); - fc_lport_destroy(lp); - - /* - * This stops the fnic device, masks all interrupts. Completed - * CQ entries are drained. Posted WQ/RQ/Copy-WQ entries are - * cleaned up - */ - fnic_cleanup(fnic); - - BUG_ON(!skb_queue_empty(&fnic->frame_queue)); - BUG_ON(!skb_queue_empty(&fnic->tx_queue)); - - spin_lock_irqsave(&fnic_list_lock, flags); - list_del(&fnic->list); - spin_unlock_irqrestore(&fnic_list_lock, flags); - - fc_remove_host(fnic->lport->host); - scsi_remove_host(fnic->lport->host); - fc_exch_mgr_free(fnic->lport); - vnic_dev_notify_unset(fnic->vdev); - fnic_free_intr(fnic); - fnic_free_vnic_resources(fnic); - fnic_clear_intr_mode(fnic); - vnic_dev_close(fnic->vdev); - vnic_dev_unregister(fnic->vdev); - fnic_iounmap(fnic); - pci_release_regions(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); - scsi_host_put(lp->host); -} - -static struct pci_driver fnic_driver = { - .name = DRV_NAME, - .id_table = fnic_id_table, - .probe = fnic_probe, - .remove = __devexit_p(fnic_remove), -}; - -static int __init fnic_init_module(void) -{ - size_t len; - int err = 0; - - printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION); - - /* Create a cache for allocation of default size sgls */ - len = sizeof(struct fnic_dflt_sgl_list); - fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create - ("fnic_sgl_dflt", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, - SLAB_HWCACHE_ALIGN, - NULL); - if (!fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]) { - printk(KERN_ERR PFX "failed to create fnic dflt sgl slab\n"); - err = -ENOMEM; - goto err_create_fnic_sgl_slab_dflt; - } - - /* Create a cache for allocation of max size sgls*/ - len = sizeof(struct fnic_sgl_list); - fnic_sgl_cache[FNIC_SGL_CACHE_MAX] = kmem_cache_create - ("fnic_sgl_max", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, - SLAB_HWCACHE_ALIGN, - NULL); - if (!fnic_sgl_cache[FNIC_SGL_CACHE_MAX]) { - printk(KERN_ERR PFX "failed to create fnic max sgl slab\n"); - err = -ENOMEM; - goto err_create_fnic_sgl_slab_max; - } - - /* Create a cache of io_req structs for use via mempool */ - fnic_io_req_cache = kmem_cache_create("fnic_io_req", - sizeof(struct fnic_io_req), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!fnic_io_req_cache) { - printk(KERN_ERR PFX "failed to create fnic io_req slab\n"); - err = -ENOMEM; - goto err_create_fnic_ioreq_slab; - } - - fnic_event_queue = create_singlethread_workqueue("fnic_event_wq"); - if (!fnic_event_queue) { - printk(KERN_ERR PFX "fnic work queue create failed\n"); - err = -ENOMEM; - goto err_create_fnic_workq; - } - - spin_lock_init(&fnic_list_lock); - INIT_LIST_HEAD(&fnic_list); - - fnic_fc_transport = fc_attach_transport(&fnic_fc_functions); - if (!fnic_fc_transport) { - printk(KERN_ERR PFX "fc_attach_transport error\n"); - err = -ENOMEM; - goto err_fc_transport; - } - - /* register the driver with PCI system */ - err = pci_register_driver(&fnic_driver); - if (err < 0) { - printk(KERN_ERR PFX "pci register error\n"); - goto err_pci_register; - } - return err; - -err_pci_register: - fc_release_transport(fnic_fc_transport); -err_fc_transport: - destroy_workqueue(fnic_event_queue); -err_create_fnic_workq: - kmem_cache_destroy(fnic_io_req_cache); -err_create_fnic_ioreq_slab: - kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); -err_create_fnic_sgl_slab_max: - kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); -err_create_fnic_sgl_slab_dflt: - return err; -} - -static void __exit fnic_cleanup_module(void) -{ - pci_unregister_driver(&fnic_driver); - destroy_workqueue(fnic_event_queue); - kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); - kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); - kmem_cache_destroy(fnic_io_req_cache); - fc_release_transport(fnic_fc_transport); -} - -module_init(fnic_init_module); -module_exit(fnic_cleanup_module); - diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.c b/ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.c deleted file mode 100644 index 50488f8e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include "wq_enet_desc.h" -#include "rq_enet_desc.h" -#include "cq_enet_desc.h" -#include "vnic_resource.h" -#include "vnic_dev.h" -#include "vnic_wq.h" -#include "vnic_rq.h" -#include "vnic_cq.h" -#include "vnic_intr.h" -#include "vnic_stats.h" -#include "vnic_nic.h" -#include "fnic.h" - -int fnic_get_vnic_config(struct fnic *fnic) -{ - struct vnic_fc_config *c = &fnic->config; - int err; - -#define GET_CONFIG(m) \ - do { \ - err = vnic_dev_spec(fnic->vdev, \ - offsetof(struct vnic_fc_config, m), \ - sizeof(c->m), &c->m); \ - if (err) { \ - shost_printk(KERN_ERR, fnic->lport->host, \ - "Error getting %s, %d\n", #m, \ - err); \ - return err; \ - } \ - } while (0); - - GET_CONFIG(node_wwn); - GET_CONFIG(port_wwn); - GET_CONFIG(wq_enet_desc_count); - GET_CONFIG(wq_copy_desc_count); - GET_CONFIG(rq_desc_count); - GET_CONFIG(maxdatafieldsize); - GET_CONFIG(ed_tov); - GET_CONFIG(ra_tov); - GET_CONFIG(intr_timer); - GET_CONFIG(intr_timer_type); - GET_CONFIG(flags); - GET_CONFIG(flogi_retries); - GET_CONFIG(flogi_timeout); - GET_CONFIG(plogi_retries); - GET_CONFIG(plogi_timeout); - GET_CONFIG(io_throttle_count); - GET_CONFIG(link_down_timeout); - GET_CONFIG(port_down_timeout); - GET_CONFIG(port_down_io_retries); - GET_CONFIG(luns_per_tgt); - - c->wq_enet_desc_count = - min_t(u32, VNIC_FNIC_WQ_DESCS_MAX, - max_t(u32, VNIC_FNIC_WQ_DESCS_MIN, - c->wq_enet_desc_count)); - c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16); - - c->wq_copy_desc_count = - min_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MAX, - max_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MIN, - c->wq_copy_desc_count)); - c->wq_copy_desc_count = ALIGN(c->wq_copy_desc_count, 16); - - c->rq_desc_count = - min_t(u32, VNIC_FNIC_RQ_DESCS_MAX, - max_t(u32, VNIC_FNIC_RQ_DESCS_MIN, - c->rq_desc_count)); - c->rq_desc_count = ALIGN(c->rq_desc_count, 16); - - c->maxdatafieldsize = - min_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MAX, - max_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MIN, - c->maxdatafieldsize)); - c->ed_tov = - min_t(u32, VNIC_FNIC_EDTOV_MAX, - max_t(u32, VNIC_FNIC_EDTOV_MIN, - c->ed_tov)); - - c->ra_tov = - min_t(u32, VNIC_FNIC_RATOV_MAX, - max_t(u32, VNIC_FNIC_RATOV_MIN, - c->ra_tov)); - - c->flogi_retries = - min_t(u32, VNIC_FNIC_FLOGI_RETRIES_MAX, c->flogi_retries); - - c->flogi_timeout = - min_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MAX, - max_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MIN, - c->flogi_timeout)); - - c->plogi_retries = - min_t(u32, VNIC_FNIC_PLOGI_RETRIES_MAX, c->plogi_retries); - - c->plogi_timeout = - min_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MAX, - max_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MIN, - c->plogi_timeout)); - - c->io_throttle_count = - min_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MAX, - max_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MIN, - c->io_throttle_count)); - - c->link_down_timeout = - min_t(u32, VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX, - c->link_down_timeout); - - c->port_down_timeout = - min_t(u32, VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX, - c->port_down_timeout); - - c->port_down_io_retries = - min_t(u32, VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX, - c->port_down_io_retries); - - c->luns_per_tgt = - min_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MAX, - max_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MIN, - c->luns_per_tgt)); - - c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); - c->intr_timer_type = c->intr_timer_type; - - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC MAC addr %pM " - "wq/wq_copy/rq %d/%d/%d\n", - fnic->ctlr.ctl_src_addr, - c->wq_enet_desc_count, c->wq_copy_desc_count, - c->rq_desc_count); - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC node wwn %llx port wwn %llx\n", - c->node_wwn, c->port_wwn); - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC ed_tov %d ra_tov %d\n", - c->ed_tov, c->ra_tov); - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC mtu %d intr timer %d\n", - c->maxdatafieldsize, c->intr_timer); - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC flags 0x%x luns per tgt %d\n", - c->flags, c->luns_per_tgt); - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC flogi_retries %d flogi timeout %d\n", - c->flogi_retries, c->flogi_timeout); - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC plogi retries %d plogi timeout %d\n", - c->plogi_retries, c->plogi_timeout); - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC io throttle count %d link dn timeout %d\n", - c->io_throttle_count, c->link_down_timeout); - shost_printk(KERN_INFO, fnic->lport->host, - "vNIC port dn io retries %d port dn timeout %d\n", - c->port_down_io_retries, c->port_down_timeout); - - return 0; -} - -int fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu, - u8 rss_hash_type, - u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, - u8 tso_ipid_split_en, u8 ig_vlan_strip_en) -{ - u64 a0, a1; - u32 nic_cfg; - int wait = 1000; - - vnic_set_nic_cfg(&nic_cfg, rss_default_cpu, - rss_hash_type, rss_hash_bits, rss_base_cpu, - rss_enable, tso_ipid_split_en, ig_vlan_strip_en); - - a0 = nic_cfg; - a1 = 0; - - return vnic_dev_cmd(fnic->vdev, CMD_NIC_CFG, &a0, &a1, wait); -} - -void fnic_get_res_counts(struct fnic *fnic) -{ - fnic->wq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_WQ); - fnic->raw_wq_count = fnic->wq_count - 1; - fnic->wq_copy_count = fnic->wq_count - fnic->raw_wq_count; - fnic->rq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_RQ); - fnic->cq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_CQ); - fnic->intr_count = vnic_dev_get_res_count(fnic->vdev, - RES_TYPE_INTR_CTRL); -} - -void fnic_free_vnic_resources(struct fnic *fnic) -{ - unsigned int i; - - for (i = 0; i < fnic->raw_wq_count; i++) - vnic_wq_free(&fnic->wq[i]); - - for (i = 0; i < fnic->wq_copy_count; i++) - vnic_wq_copy_free(&fnic->wq_copy[i]); - - for (i = 0; i < fnic->rq_count; i++) - vnic_rq_free(&fnic->rq[i]); - - for (i = 0; i < fnic->cq_count; i++) - vnic_cq_free(&fnic->cq[i]); - - for (i = 0; i < fnic->intr_count; i++) - vnic_intr_free(&fnic->intr[i]); -} - -int fnic_alloc_vnic_resources(struct fnic *fnic) -{ - enum vnic_dev_intr_mode intr_mode; - unsigned int mask_on_assertion; - unsigned int interrupt_offset; - unsigned int error_interrupt_enable; - unsigned int error_interrupt_offset; - unsigned int i, cq_index; - unsigned int wq_copy_cq_desc_count; - int err; - - intr_mode = vnic_dev_get_intr_mode(fnic->vdev); - - shost_printk(KERN_INFO, fnic->lport->host, "vNIC interrupt mode: %s\n", - intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" : - intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" : - intr_mode == VNIC_DEV_INTR_MODE_MSIX ? - "MSI-X" : "unknown"); - - shost_printk(KERN_INFO, fnic->lport->host, "vNIC resources avail: " - "wq %d cp_wq %d raw_wq %d rq %d cq %d intr %d\n", - fnic->wq_count, fnic->wq_copy_count, fnic->raw_wq_count, - fnic->rq_count, fnic->cq_count, fnic->intr_count); - - /* Allocate Raw WQ used for FCS frames */ - for (i = 0; i < fnic->raw_wq_count; i++) { - err = vnic_wq_alloc(fnic->vdev, &fnic->wq[i], i, - fnic->config.wq_enet_desc_count, - sizeof(struct wq_enet_desc)); - if (err) - goto err_out_cleanup; - } - - /* Allocate Copy WQs used for SCSI IOs */ - for (i = 0; i < fnic->wq_copy_count; i++) { - err = vnic_wq_copy_alloc(fnic->vdev, &fnic->wq_copy[i], - (fnic->raw_wq_count + i), - fnic->config.wq_copy_desc_count, - sizeof(struct fcpio_host_req)); - if (err) - goto err_out_cleanup; - } - - /* RQ for receiving FCS frames */ - for (i = 0; i < fnic->rq_count; i++) { - err = vnic_rq_alloc(fnic->vdev, &fnic->rq[i], i, - fnic->config.rq_desc_count, - sizeof(struct rq_enet_desc)); - if (err) - goto err_out_cleanup; - } - - /* CQ for each RQ */ - for (i = 0; i < fnic->rq_count; i++) { - cq_index = i; - err = vnic_cq_alloc(fnic->vdev, - &fnic->cq[cq_index], cq_index, - fnic->config.rq_desc_count, - sizeof(struct cq_enet_rq_desc)); - if (err) - goto err_out_cleanup; - } - - /* CQ for each WQ */ - for (i = 0; i < fnic->raw_wq_count; i++) { - cq_index = fnic->rq_count + i; - err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index], cq_index, - fnic->config.wq_enet_desc_count, - sizeof(struct cq_enet_wq_desc)); - if (err) - goto err_out_cleanup; - } - - /* CQ for each COPY WQ */ - wq_copy_cq_desc_count = (fnic->config.wq_copy_desc_count * 3); - for (i = 0; i < fnic->wq_copy_count; i++) { - cq_index = fnic->raw_wq_count + fnic->rq_count + i; - err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index], - cq_index, - wq_copy_cq_desc_count, - sizeof(struct fcpio_fw_req)); - if (err) - goto err_out_cleanup; - } - - for (i = 0; i < fnic->intr_count; i++) { - err = vnic_intr_alloc(fnic->vdev, &fnic->intr[i], i); - if (err) - goto err_out_cleanup; - } - - fnic->legacy_pba = vnic_dev_get_res(fnic->vdev, - RES_TYPE_INTR_PBA_LEGACY, 0); - - if (!fnic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) { - shost_printk(KERN_ERR, fnic->lport->host, - "Failed to hook legacy pba resource\n"); - err = -ENODEV; - goto err_out_cleanup; - } - - /* - * Init RQ/WQ resources. - * - * RQ[0 to n-1] point to CQ[0 to n-1] - * WQ[0 to m-1] point to CQ[n to n+m-1] - * WQ_COPY[0 to k-1] points to CQ[n+m to n+m+k-1] - * - * Note for copy wq we always initialize with cq_index = 0 - * - * Error interrupt is not enabled for MSI. - */ - - switch (intr_mode) { - case VNIC_DEV_INTR_MODE_INTX: - case VNIC_DEV_INTR_MODE_MSIX: - error_interrupt_enable = 1; - error_interrupt_offset = fnic->err_intr_offset; - break; - default: - error_interrupt_enable = 0; - error_interrupt_offset = 0; - break; - } - - for (i = 0; i < fnic->rq_count; i++) { - cq_index = i; - vnic_rq_init(&fnic->rq[i], - cq_index, - error_interrupt_enable, - error_interrupt_offset); - } - - for (i = 0; i < fnic->raw_wq_count; i++) { - cq_index = i + fnic->rq_count; - vnic_wq_init(&fnic->wq[i], - cq_index, - error_interrupt_enable, - error_interrupt_offset); - } - - for (i = 0; i < fnic->wq_copy_count; i++) { - vnic_wq_copy_init(&fnic->wq_copy[i], - 0 /* cq_index 0 - always */, - error_interrupt_enable, - error_interrupt_offset); - } - - for (i = 0; i < fnic->cq_count; i++) { - - switch (intr_mode) { - case VNIC_DEV_INTR_MODE_MSIX: - interrupt_offset = i; - break; - default: - interrupt_offset = 0; - break; - } - - vnic_cq_init(&fnic->cq[i], - 0 /* flow_control_enable */, - 1 /* color_enable */, - 0 /* cq_head */, - 0 /* cq_tail */, - 1 /* cq_tail_color */, - 1 /* interrupt_enable */, - 1 /* cq_entry_enable */, - 0 /* cq_message_enable */, - interrupt_offset, - 0 /* cq_message_addr */); - } - - /* - * Init INTR resources - * - * mask_on_assertion is not used for INTx due to the level- - * triggered nature of INTx - */ - - switch (intr_mode) { - case VNIC_DEV_INTR_MODE_MSI: - case VNIC_DEV_INTR_MODE_MSIX: - mask_on_assertion = 1; - break; - default: - mask_on_assertion = 0; - break; - } - - for (i = 0; i < fnic->intr_count; i++) { - vnic_intr_init(&fnic->intr[i], - fnic->config.intr_timer, - fnic->config.intr_timer_type, - mask_on_assertion); - } - - /* init the stats memory by making the first call here */ - err = vnic_dev_stats_dump(fnic->vdev, &fnic->stats); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "vnic_dev_stats_dump failed - x%x\n", err); - goto err_out_cleanup; - } - - /* Clear LIF stats */ - vnic_dev_stats_clear(fnic->vdev); - - return 0; - -err_out_cleanup: - fnic_free_vnic_resources(fnic); - - return err; -} diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.h b/ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.h deleted file mode 100644 index ef8aaf21..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_res.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _FNIC_RES_H_ -#define _FNIC_RES_H_ - -#include "wq_enet_desc.h" -#include "rq_enet_desc.h" -#include "vnic_wq.h" -#include "vnic_rq.h" -#include "fnic_io.h" -#include "fcpio.h" -#include "vnic_wq_copy.h" -#include "vnic_cq_copy.h" - -static inline void fnic_queue_wq_desc(struct vnic_wq *wq, - void *os_buf, dma_addr_t dma_addr, - unsigned int len, unsigned int fc_eof, - int vlan_tag_insert, - unsigned int vlan_tag, - int cq_entry, int sop, int eop) -{ - struct wq_enet_desc *desc = vnic_wq_next_desc(wq); - - wq_enet_desc_enc(desc, - (u64)dma_addr | VNIC_PADDR_TARGET, - (u16)len, - 0, /* mss_or_csum_offset */ - (u16)fc_eof, - 0, /* offload_mode */ - (u8)eop, (u8)cq_entry, - 1, /* fcoe_encap */ - (u8)vlan_tag_insert, - (u16)vlan_tag, - 0 /* loopback */); - - vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop); -} - -static inline void fnic_queue_wq_eth_desc(struct vnic_wq *wq, - void *os_buf, dma_addr_t dma_addr, - unsigned int len, - int vlan_tag_insert, - unsigned int vlan_tag, - int cq_entry) -{ - struct wq_enet_desc *desc = vnic_wq_next_desc(wq); - - wq_enet_desc_enc(desc, - (u64)dma_addr | VNIC_PADDR_TARGET, - (u16)len, - 0, /* mss_or_csum_offset */ - 0, /* fc_eof */ - 0, /* offload_mode */ - 1, /* eop */ - (u8)cq_entry, - 0, /* fcoe_encap */ - (u8)vlan_tag_insert, - (u16)vlan_tag, - 0 /* loopback */); - - vnic_wq_post(wq, os_buf, dma_addr, len, 1, 1); -} - -static inline void fnic_queue_wq_copy_desc_icmnd_16(struct vnic_wq_copy *wq, - u32 req_id, - u32 lunmap_id, u8 spl_flags, - u32 sgl_cnt, u32 sense_len, - u64 sgl_addr, u64 sns_addr, - u8 crn, u8 pri_ta, - u8 flags, u8 *scsi_cdb, - u8 cdb_len, - u32 data_len, u8 *lun, - u32 d_id, u16 mss, - u32 ratov, u32 edtov) -{ - struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); - - desc->hdr.type = FCPIO_ICMND_16; /* enum fcpio_type */ - desc->hdr.status = 0; /* header status entry */ - desc->hdr._resvd = 0; /* reserved */ - desc->hdr.tag.u.req_id = req_id; /* id for this request */ - - desc->u.icmnd_16.lunmap_id = lunmap_id; /* index into lunmap table */ - desc->u.icmnd_16.special_req_flags = spl_flags; /* exch req flags */ - desc->u.icmnd_16._resvd0[0] = 0; /* reserved */ - desc->u.icmnd_16._resvd0[1] = 0; /* reserved */ - desc->u.icmnd_16._resvd0[2] = 0; /* reserved */ - desc->u.icmnd_16.sgl_cnt = sgl_cnt; /* scatter-gather list count */ - desc->u.icmnd_16.sense_len = sense_len; /* sense buffer length */ - desc->u.icmnd_16.sgl_addr = sgl_addr; /* scatter-gather list addr */ - desc->u.icmnd_16.sense_addr = sns_addr; /* sense buffer address */ - desc->u.icmnd_16.crn = crn; /* SCSI Command Reference No.*/ - desc->u.icmnd_16.pri_ta = pri_ta; /* SCSI Pri & Task attribute */ - desc->u.icmnd_16._resvd1 = 0; /* reserved: should be 0 */ - desc->u.icmnd_16.flags = flags; /* command flags */ - memset(desc->u.icmnd_16.scsi_cdb, 0, CDB_16); - memcpy(desc->u.icmnd_16.scsi_cdb, scsi_cdb, cdb_len); /* SCSI CDB */ - desc->u.icmnd_16.data_len = data_len; /* length of data expected */ - memcpy(desc->u.icmnd_16.lun, lun, LUN_ADDRESS); /* LUN address */ - desc->u.icmnd_16._resvd2 = 0; /* reserved */ - hton24(desc->u.icmnd_16.d_id, d_id); /* FC vNIC only: Target D_ID */ - desc->u.icmnd_16.mss = mss; /* FC vNIC only: max burst */ - desc->u.icmnd_16.r_a_tov = ratov; /*FC vNIC only: Res. Alloc Timeout */ - desc->u.icmnd_16.e_d_tov = edtov; /*FC vNIC only: Err Detect Timeout */ - - vnic_wq_copy_post(wq); -} - -static inline void fnic_queue_wq_copy_desc_itmf(struct vnic_wq_copy *wq, - u32 req_id, u32 lunmap_id, - u32 tm_req, u32 tm_id, u8 *lun, - u32 d_id, u32 r_a_tov, - u32 e_d_tov) -{ - struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); - - desc->hdr.type = FCPIO_ITMF; /* enum fcpio_type */ - desc->hdr.status = 0; /* header status entry */ - desc->hdr._resvd = 0; /* reserved */ - desc->hdr.tag.u.req_id = req_id; /* id for this request */ - - desc->u.itmf.lunmap_id = lunmap_id; /* index into lunmap table */ - desc->u.itmf.tm_req = tm_req; /* SCSI Task Management request */ - desc->u.itmf.t_tag = tm_id; /* tag of fcpio to be aborted */ - desc->u.itmf._resvd = 0; - memcpy(desc->u.itmf.lun, lun, LUN_ADDRESS); /* LUN address */ - desc->u.itmf._resvd1 = 0; - hton24(desc->u.itmf.d_id, d_id); /* FC vNIC only: Target D_ID */ - desc->u.itmf.r_a_tov = r_a_tov; /* FC vNIC only: R_A_TOV in msec */ - desc->u.itmf.e_d_tov = e_d_tov; /* FC vNIC only: E_D_TOV in msec */ - - vnic_wq_copy_post(wq); -} - -static inline void fnic_queue_wq_copy_desc_flogi_reg(struct vnic_wq_copy *wq, - u32 req_id, u8 format, - u32 s_id, u8 *gw_mac) -{ - struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); - - desc->hdr.type = FCPIO_FLOGI_REG; /* enum fcpio_type */ - desc->hdr.status = 0; /* header status entry */ - desc->hdr._resvd = 0; /* reserved */ - desc->hdr.tag.u.req_id = req_id; /* id for this request */ - - desc->u.flogi_reg.format = format; - desc->u.flogi_reg._resvd = 0; - hton24(desc->u.flogi_reg.s_id, s_id); - memcpy(desc->u.flogi_reg.gateway_mac, gw_mac, ETH_ALEN); - - vnic_wq_copy_post(wq); -} - -static inline void fnic_queue_wq_copy_desc_fip_reg(struct vnic_wq_copy *wq, - u32 req_id, u32 s_id, - u8 *fcf_mac, u8 *ha_mac, - u32 r_a_tov, u32 e_d_tov) -{ - struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); - - desc->hdr.type = FCPIO_FLOGI_FIP_REG; /* enum fcpio_type */ - desc->hdr.status = 0; /* header status entry */ - desc->hdr._resvd = 0; /* reserved */ - desc->hdr.tag.u.req_id = req_id; /* id for this request */ - - desc->u.flogi_fip_reg._resvd0 = 0; - hton24(desc->u.flogi_fip_reg.s_id, s_id); - memcpy(desc->u.flogi_fip_reg.fcf_mac, fcf_mac, ETH_ALEN); - desc->u.flogi_fip_reg._resvd1 = 0; - desc->u.flogi_fip_reg.r_a_tov = r_a_tov; - desc->u.flogi_fip_reg.e_d_tov = e_d_tov; - memcpy(desc->u.flogi_fip_reg.ha_mac, ha_mac, ETH_ALEN); - desc->u.flogi_fip_reg._resvd2 = 0; - - vnic_wq_copy_post(wq); -} - -static inline void fnic_queue_wq_copy_desc_fw_reset(struct vnic_wq_copy *wq, - u32 req_id) -{ - struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); - - desc->hdr.type = FCPIO_RESET; /* enum fcpio_type */ - desc->hdr.status = 0; /* header status entry */ - desc->hdr._resvd = 0; /* reserved */ - desc->hdr.tag.u.req_id = req_id; /* id for this request */ - - vnic_wq_copy_post(wq); -} - -static inline void fnic_queue_wq_copy_desc_lunmap(struct vnic_wq_copy *wq, - u32 req_id, u64 lunmap_addr, - u32 lunmap_len) -{ - struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); - - desc->hdr.type = FCPIO_LUNMAP_REQ; /* enum fcpio_type */ - desc->hdr.status = 0; /* header status entry */ - desc->hdr._resvd = 0; /* reserved */ - desc->hdr.tag.u.req_id = req_id; /* id for this request */ - - desc->u.lunmap_req.addr = lunmap_addr; /* address of the buffer */ - desc->u.lunmap_req.len = lunmap_len; /* len of the buffer */ - - vnic_wq_copy_post(wq); -} - -static inline void fnic_queue_rq_desc(struct vnic_rq *rq, - void *os_buf, dma_addr_t dma_addr, - u16 len) -{ - struct rq_enet_desc *desc = vnic_rq_next_desc(rq); - - rq_enet_desc_enc(desc, - (u64)dma_addr | VNIC_PADDR_TARGET, - RQ_ENET_TYPE_ONLY_SOP, - (u16)len); - - vnic_rq_post(rq, os_buf, 0, dma_addr, len); -} - - -struct fnic; - -int fnic_get_vnic_config(struct fnic *); -int fnic_alloc_vnic_resources(struct fnic *); -void fnic_free_vnic_resources(struct fnic *); -void fnic_get_res_counts(struct fnic *); -int fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu, - u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, - u8 rss_enable, u8 tso_ipid_split_en, - u8 ig_vlan_strip_en); - -#endif /* _FNIC_RES_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_scsi.c b/ANDROID_3.4.5/drivers/scsi/fnic/fnic_scsi.c deleted file mode 100644 index c40ce52e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/fnic_scsi.c +++ /dev/null @@ -1,1824 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fnic_io.h" -#include "fnic.h" - -const char *fnic_state_str[] = { - [FNIC_IN_FC_MODE] = "FNIC_IN_FC_MODE", - [FNIC_IN_FC_TRANS_ETH_MODE] = "FNIC_IN_FC_TRANS_ETH_MODE", - [FNIC_IN_ETH_MODE] = "FNIC_IN_ETH_MODE", - [FNIC_IN_ETH_TRANS_FC_MODE] = "FNIC_IN_ETH_TRANS_FC_MODE", -}; - -static const char *fnic_ioreq_state_str[] = { - [FNIC_IOREQ_CMD_PENDING] = "FNIC_IOREQ_CMD_PENDING", - [FNIC_IOREQ_ABTS_PENDING] = "FNIC_IOREQ_ABTS_PENDING", - [FNIC_IOREQ_ABTS_COMPLETE] = "FNIC_IOREQ_ABTS_COMPLETE", - [FNIC_IOREQ_CMD_COMPLETE] = "FNIC_IOREQ_CMD_COMPLETE", -}; - -static const char *fcpio_status_str[] = { - [FCPIO_SUCCESS] = "FCPIO_SUCCESS", /*0x0*/ - [FCPIO_INVALID_HEADER] = "FCPIO_INVALID_HEADER", - [FCPIO_OUT_OF_RESOURCE] = "FCPIO_OUT_OF_RESOURCE", - [FCPIO_INVALID_PARAM] = "FCPIO_INVALID_PARAM]", - [FCPIO_REQ_NOT_SUPPORTED] = "FCPIO_REQ_NOT_SUPPORTED", - [FCPIO_IO_NOT_FOUND] = "FCPIO_IO_NOT_FOUND", - [FCPIO_ABORTED] = "FCPIO_ABORTED", /*0x41*/ - [FCPIO_TIMEOUT] = "FCPIO_TIMEOUT", - [FCPIO_SGL_INVALID] = "FCPIO_SGL_INVALID", - [FCPIO_MSS_INVALID] = "FCPIO_MSS_INVALID", - [FCPIO_DATA_CNT_MISMATCH] = "FCPIO_DATA_CNT_MISMATCH", - [FCPIO_FW_ERR] = "FCPIO_FW_ERR", - [FCPIO_ITMF_REJECTED] = "FCPIO_ITMF_REJECTED", - [FCPIO_ITMF_FAILED] = "FCPIO_ITMF_FAILED", - [FCPIO_ITMF_INCORRECT_LUN] = "FCPIO_ITMF_INCORRECT_LUN", - [FCPIO_CMND_REJECTED] = "FCPIO_CMND_REJECTED", - [FCPIO_NO_PATH_AVAIL] = "FCPIO_NO_PATH_AVAIL", - [FCPIO_PATH_FAILED] = "FCPIO_PATH_FAILED", - [FCPIO_LUNMAP_CHNG_PEND] = "FCPIO_LUNHMAP_CHNG_PEND", -}; - -const char *fnic_state_to_str(unsigned int state) -{ - if (state >= ARRAY_SIZE(fnic_state_str) || !fnic_state_str[state]) - return "unknown"; - - return fnic_state_str[state]; -} - -static const char *fnic_ioreq_state_to_str(unsigned int state) -{ - if (state >= ARRAY_SIZE(fnic_ioreq_state_str) || - !fnic_ioreq_state_str[state]) - return "unknown"; - - return fnic_ioreq_state_str[state]; -} - -static const char *fnic_fcpio_status_to_str(unsigned int status) -{ - if (status >= ARRAY_SIZE(fcpio_status_str) || !fcpio_status_str[status]) - return "unknown"; - - return fcpio_status_str[status]; -} - -static void fnic_cleanup_io(struct fnic *fnic, int exclude_id); - -static inline spinlock_t *fnic_io_lock_hash(struct fnic *fnic, - struct scsi_cmnd *sc) -{ - u32 hash = sc->request->tag & (FNIC_IO_LOCKS - 1); - - return &fnic->io_req_lock[hash]; -} - -/* - * Unmap the data buffer and sense buffer for an io_req, - * also unmap and free the device-private scatter/gather list. - */ -static void fnic_release_ioreq_buf(struct fnic *fnic, - struct fnic_io_req *io_req, - struct scsi_cmnd *sc) -{ - if (io_req->sgl_list_pa) - pci_unmap_single(fnic->pdev, io_req->sgl_list_pa, - sizeof(io_req->sgl_list[0]) * io_req->sgl_cnt, - PCI_DMA_TODEVICE); - scsi_dma_unmap(sc); - - if (io_req->sgl_cnt) - mempool_free(io_req->sgl_list_alloc, - fnic->io_sgl_pool[io_req->sgl_type]); - if (io_req->sense_buf_pa) - pci_unmap_single(fnic->pdev, io_req->sense_buf_pa, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); -} - -/* Free up Copy Wq descriptors. Called with copy_wq lock held */ -static int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq) -{ - /* if no Ack received from firmware, then nothing to clean */ - if (!fnic->fw_ack_recd[0]) - return 1; - - /* - * Update desc_available count based on number of freed descriptors - * Account for wraparound - */ - if (wq->to_clean_index <= fnic->fw_ack_index[0]) - wq->ring.desc_avail += (fnic->fw_ack_index[0] - - wq->to_clean_index + 1); - else - wq->ring.desc_avail += (wq->ring.desc_count - - wq->to_clean_index - + fnic->fw_ack_index[0] + 1); - - /* - * just bump clean index to ack_index+1 accounting for wraparound - * this will essentially free up all descriptors between - * to_clean_index and fw_ack_index, both inclusive - */ - wq->to_clean_index = - (fnic->fw_ack_index[0] + 1) % wq->ring.desc_count; - - /* we have processed the acks received so far */ - fnic->fw_ack_recd[0] = 0; - return 0; -} - - -/* - * fnic_fw_reset_handler - * Routine to send reset msg to fw - */ -int fnic_fw_reset_handler(struct fnic *fnic) -{ - struct vnic_wq_copy *wq = &fnic->wq_copy[0]; - int ret = 0; - unsigned long flags; - - skb_queue_purge(&fnic->frame_queue); - skb_queue_purge(&fnic->tx_queue); - - spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); - - if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); - - if (!vnic_wq_copy_desc_avail(wq)) - ret = -EAGAIN; - else - fnic_queue_wq_copy_desc_fw_reset(wq, SCSI_NO_TAG); - - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); - - if (!ret) - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Issued fw reset\n"); - else - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Failed to issue fw reset\n"); - return ret; -} - - -/* - * fnic_flogi_reg_handler - * Routine to send flogi register msg to fw - */ -int fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id) -{ - struct vnic_wq_copy *wq = &fnic->wq_copy[0]; - enum fcpio_flogi_reg_format_type format; - struct fc_lport *lp = fnic->lport; - u8 gw_mac[ETH_ALEN]; - int ret = 0; - unsigned long flags; - - spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); - - if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); - - if (!vnic_wq_copy_desc_avail(wq)) { - ret = -EAGAIN; - goto flogi_reg_ioreq_end; - } - - if (fnic->ctlr.map_dest) { - memset(gw_mac, 0xff, ETH_ALEN); - format = FCPIO_FLOGI_REG_DEF_DEST; - } else { - memcpy(gw_mac, fnic->ctlr.dest_addr, ETH_ALEN); - format = FCPIO_FLOGI_REG_GW_DEST; - } - - if ((fnic->config.flags & VFCF_FIP_CAPABLE) && !fnic->ctlr.map_dest) { - fnic_queue_wq_copy_desc_fip_reg(wq, SCSI_NO_TAG, - fc_id, gw_mac, - fnic->data_src_addr, - lp->r_a_tov, lp->e_d_tov); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "FLOGI FIP reg issued fcid %x src %pM dest %pM\n", - fc_id, fnic->data_src_addr, gw_mac); - } else { - fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG, - format, fc_id, gw_mac); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "FLOGI reg issued fcid %x map %d dest %pM\n", - fc_id, fnic->ctlr.map_dest, gw_mac); - } - -flogi_reg_ioreq_end: - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); - return ret; -} - -/* - * fnic_queue_wq_copy_desc - * Routine to enqueue a wq copy desc - */ -static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, - struct vnic_wq_copy *wq, - struct fnic_io_req *io_req, - struct scsi_cmnd *sc, - int sg_count) -{ - struct scatterlist *sg; - struct fc_rport *rport = starget_to_rport(scsi_target(sc->device)); - struct fc_rport_libfc_priv *rp = rport->dd_data; - struct host_sg_desc *desc; - u8 pri_tag = 0; - unsigned int i; - unsigned long intr_flags; - int flags; - u8 exch_flags; - struct scsi_lun fc_lun; - char msg[2]; - - if (sg_count) { - /* For each SGE, create a device desc entry */ - desc = io_req->sgl_list; - for_each_sg(scsi_sglist(sc), sg, sg_count, i) { - desc->addr = cpu_to_le64(sg_dma_address(sg)); - desc->len = cpu_to_le32(sg_dma_len(sg)); - desc->_resvd = 0; - desc++; - } - - io_req->sgl_list_pa = pci_map_single - (fnic->pdev, - io_req->sgl_list, - sizeof(io_req->sgl_list[0]) * sg_count, - PCI_DMA_TODEVICE); - } - - io_req->sense_buf_pa = pci_map_single(fnic->pdev, - sc->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); - - int_to_scsilun(sc->device->lun, &fc_lun); - - pri_tag = FCPIO_ICMND_PTA_SIMPLE; - msg[0] = MSG_SIMPLE_TAG; - scsi_populate_tag_msg(sc, msg); - if (msg[0] == MSG_ORDERED_TAG) - pri_tag = FCPIO_ICMND_PTA_ORDERED; - - /* Enqueue the descriptor in the Copy WQ */ - spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); - - if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); - - if (unlikely(!vnic_wq_copy_desc_avail(wq))) { - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); - return SCSI_MLQUEUE_HOST_BUSY; - } - - flags = 0; - if (sc->sc_data_direction == DMA_FROM_DEVICE) - flags = FCPIO_ICMND_RDDATA; - else if (sc->sc_data_direction == DMA_TO_DEVICE) - flags = FCPIO_ICMND_WRDATA; - - exch_flags = 0; - if ((fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) && - (rp->flags & FC_RP_FLAGS_RETRY)) - exch_flags |= FCPIO_ICMND_SRFLAG_RETRY; - - fnic_queue_wq_copy_desc_icmnd_16(wq, sc->request->tag, - 0, exch_flags, io_req->sgl_cnt, - SCSI_SENSE_BUFFERSIZE, - io_req->sgl_list_pa, - io_req->sense_buf_pa, - 0, /* scsi cmd ref, always 0 */ - pri_tag, /* scsi pri and tag */ - flags, /* command flags */ - sc->cmnd, sc->cmd_len, - scsi_bufflen(sc), - fc_lun.scsi_lun, io_req->port_id, - rport->maxframe_size, rp->r_a_tov, - rp->e_d_tov); - - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); - return 0; -} - -/* - * fnic_queuecommand - * Routine to send a scsi cdb - * Called with host_lock held and interrupts disabled. - */ -static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) -{ - struct fc_lport *lp; - struct fc_rport *rport; - struct fnic_io_req *io_req; - struct fnic *fnic; - struct vnic_wq_copy *wq; - int ret; - int sg_count; - unsigned long flags; - unsigned long ptr; - - rport = starget_to_rport(scsi_target(sc->device)); - ret = fc_remote_port_chkready(rport); - if (ret) { - sc->result = ret; - done(sc); - return 0; - } - - lp = shost_priv(sc->device->host); - if (lp->state != LPORT_ST_READY || !(lp->link_up)) - return SCSI_MLQUEUE_HOST_BUSY; - - /* - * Release host lock, use driver resource specific locks from here. - * Don't re-enable interrupts in case they were disabled prior to the - * caller disabling them. - */ - spin_unlock(lp->host->host_lock); - - /* Get a new io_req for this SCSI IO */ - fnic = lport_priv(lp); - - io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); - if (!io_req) { - ret = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - memset(io_req, 0, sizeof(*io_req)); - - /* Map the data buffer */ - sg_count = scsi_dma_map(sc); - if (sg_count < 0) { - mempool_free(io_req, fnic->io_req_pool); - goto out; - } - - /* Determine the type of scatter/gather list we need */ - io_req->sgl_cnt = sg_count; - io_req->sgl_type = FNIC_SGL_CACHE_DFLT; - if (sg_count > FNIC_DFLT_SG_DESC_CNT) - io_req->sgl_type = FNIC_SGL_CACHE_MAX; - - if (sg_count) { - io_req->sgl_list = - mempool_alloc(fnic->io_sgl_pool[io_req->sgl_type], - GFP_ATOMIC); - if (!io_req->sgl_list) { - ret = SCSI_MLQUEUE_HOST_BUSY; - scsi_dma_unmap(sc); - mempool_free(io_req, fnic->io_req_pool); - goto out; - } - - /* Cache sgl list allocated address before alignment */ - io_req->sgl_list_alloc = io_req->sgl_list; - ptr = (unsigned long) io_req->sgl_list; - if (ptr % FNIC_SG_DESC_ALIGN) { - io_req->sgl_list = (struct host_sg_desc *) - (((unsigned long) ptr - + FNIC_SG_DESC_ALIGN - 1) - & ~(FNIC_SG_DESC_ALIGN - 1)); - } - } - - /* initialize rest of io_req */ - io_req->port_id = rport->port_id; - CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING; - CMD_SP(sc) = (char *)io_req; - sc->scsi_done = done; - - /* create copy wq desc and enqueue it */ - wq = &fnic->wq_copy[0]; - ret = fnic_queue_wq_copy_desc(fnic, wq, io_req, sc, sg_count); - if (ret) { - /* - * In case another thread cancelled the request, - * refetch the pointer under the lock. - */ - spinlock_t *io_lock = fnic_io_lock_hash(fnic, sc); - - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - CMD_SP(sc) = NULL; - CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; - spin_unlock_irqrestore(io_lock, flags); - if (io_req) { - fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - } - } -out: - /* acquire host lock before returning to SCSI */ - spin_lock(lp->host->host_lock); - return ret; -} - -DEF_SCSI_QCMD(fnic_queuecommand) - -/* - * fnic_fcpio_fw_reset_cmpl_handler - * Routine to handle fw reset completion - */ -static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, - struct fcpio_fw_req *desc) -{ - u8 type; - u8 hdr_status; - struct fcpio_tag tag; - int ret = 0; - unsigned long flags; - - fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); - - /* Clean up all outstanding io requests */ - fnic_cleanup_io(fnic, SCSI_NO_TAG); - - spin_lock_irqsave(&fnic->fnic_lock, flags); - - /* fnic should be in FC_TRANS_ETH_MODE */ - if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) { - /* Check status of reset completion */ - if (!hdr_status) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "reset cmpl success\n"); - /* Ready to send flogi out */ - fnic->state = FNIC_IN_ETH_MODE; - } else { - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "fnic fw_reset : failed %s\n", - fnic_fcpio_status_to_str(hdr_status)); - - /* - * Unable to change to eth mode, cannot send out flogi - * Change state to fc mode, so that subsequent Flogi - * requests from libFC will cause more attempts to - * reset the firmware. Free the cached flogi - */ - fnic->state = FNIC_IN_FC_MODE; - ret = -1; - } - } else { - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "Unexpected state %s while processing" - " reset cmpl\n", fnic_state_to_str(fnic->state)); - ret = -1; - } - - /* Thread removing device blocks till firmware reset is complete */ - if (fnic->remove_wait) - complete(fnic->remove_wait); - - /* - * If fnic is being removed, or fw reset failed - * free the flogi frame. Else, send it out - */ - if (fnic->remove_wait || ret) { - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - skb_queue_purge(&fnic->tx_queue); - goto reset_cmpl_handler_end; - } - - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - fnic_flush_tx(fnic); - - reset_cmpl_handler_end: - return ret; -} - -/* - * fnic_fcpio_flogi_reg_cmpl_handler - * Routine to handle flogi register completion - */ -static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic, - struct fcpio_fw_req *desc) -{ - u8 type; - u8 hdr_status; - struct fcpio_tag tag; - int ret = 0; - unsigned long flags; - - fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); - - /* Update fnic state based on status of flogi reg completion */ - spin_lock_irqsave(&fnic->fnic_lock, flags); - - if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) { - - /* Check flogi registration completion status */ - if (!hdr_status) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "flog reg succeeded\n"); - fnic->state = FNIC_IN_FC_MODE; - } else { - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "fnic flogi reg :failed %s\n", - fnic_fcpio_status_to_str(hdr_status)); - fnic->state = FNIC_IN_ETH_MODE; - ret = -1; - } - } else { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Unexpected fnic state %s while" - " processing flogi reg completion\n", - fnic_state_to_str(fnic->state)); - ret = -1; - } - - if (!ret) { - if (fnic->stop_rx_link_events) { - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - goto reg_cmpl_handler_end; - } - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - fnic_flush_tx(fnic); - queue_work(fnic_event_queue, &fnic->frame_work); - } else { - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - } - -reg_cmpl_handler_end: - return ret; -} - -static inline int is_ack_index_in_range(struct vnic_wq_copy *wq, - u16 request_out) -{ - if (wq->to_clean_index <= wq->to_use_index) { - /* out of range, stale request_out index */ - if (request_out < wq->to_clean_index || - request_out >= wq->to_use_index) - return 0; - } else { - /* out of range, stale request_out index */ - if (request_out < wq->to_clean_index && - request_out >= wq->to_use_index) - return 0; - } - /* request_out index is in range */ - return 1; -} - - -/* - * Mark that ack received and store the Ack index. If there are multiple - * acks received before Tx thread cleans it up, the latest value will be - * used which is correct behavior. This state should be in the copy Wq - * instead of in the fnic - */ -static inline void fnic_fcpio_ack_handler(struct fnic *fnic, - unsigned int cq_index, - struct fcpio_fw_req *desc) -{ - struct vnic_wq_copy *wq; - u16 request_out = desc->u.ack.request_out; - unsigned long flags; - - /* mark the ack state */ - wq = &fnic->wq_copy[cq_index - fnic->raw_wq_count - fnic->rq_count]; - spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); - - if (is_ack_index_in_range(wq, request_out)) { - fnic->fw_ack_index[0] = request_out; - fnic->fw_ack_recd[0] = 1; - } - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); -} - -/* - * fnic_fcpio_icmnd_cmpl_handler - * Routine to handle icmnd completions - */ -static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, - struct fcpio_fw_req *desc) -{ - u8 type; - u8 hdr_status; - struct fcpio_tag tag; - u32 id; - u64 xfer_len = 0; - struct fcpio_icmnd_cmpl *icmnd_cmpl; - struct fnic_io_req *io_req; - struct scsi_cmnd *sc; - unsigned long flags; - spinlock_t *io_lock; - - /* Decode the cmpl description to get the io_req id */ - fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); - fcpio_tag_id_dec(&tag, &id); - - if (id >= FNIC_MAX_IO_REQ) - return; - - sc = scsi_host_find_tag(fnic->lport->host, id); - WARN_ON_ONCE(!sc); - if (!sc) - return; - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - WARN_ON_ONCE(!io_req); - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - return; - } - - /* firmware completed the io */ - io_req->io_completed = 1; - - /* - * if SCSI-ML has already issued abort on this command, - * ignore completion of the IO. The abts path will clean it up - */ - if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); - return; - } - - /* Mark the IO as complete */ - CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; - - icmnd_cmpl = &desc->u.icmnd_cmpl; - - switch (hdr_status) { - case FCPIO_SUCCESS: - sc->result = (DID_OK << 16) | icmnd_cmpl->scsi_status; - xfer_len = scsi_bufflen(sc); - scsi_set_resid(sc, icmnd_cmpl->residual); - - if (icmnd_cmpl->flags & FCPIO_ICMND_CMPL_RESID_UNDER) - xfer_len -= icmnd_cmpl->residual; - - /* - * If queue_full, then try to reduce queue depth for all - * LUNS on the target. Todo: this should be accompanied - * by a periodic queue_depth rampup based on successful - * IO completion. - */ - if (icmnd_cmpl->scsi_status == QUEUE_FULL) { - struct scsi_device *t_sdev; - int qd = 0; - - shost_for_each_device(t_sdev, sc->device->host) { - if (t_sdev->id != sc->device->id) - continue; - - if (t_sdev->queue_depth > 1) { - qd = scsi_track_queue_full - (t_sdev, - t_sdev->queue_depth - 1); - if (qd == -1) - qd = t_sdev->host->cmd_per_lun; - shost_printk(KERN_INFO, - fnic->lport->host, - "scsi[%d:%d:%d:%d" - "] queue full detected," - "new depth = %d\n", - t_sdev->host->host_no, - t_sdev->channel, - t_sdev->id, t_sdev->lun, - t_sdev->queue_depth); - } - } - } - break; - - case FCPIO_TIMEOUT: /* request was timed out */ - sc->result = (DID_TIME_OUT << 16) | icmnd_cmpl->scsi_status; - break; - - case FCPIO_ABORTED: /* request was aborted */ - sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; - break; - - case FCPIO_DATA_CNT_MISMATCH: /* recv/sent more/less data than exp. */ - scsi_set_resid(sc, icmnd_cmpl->residual); - sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; - break; - - case FCPIO_OUT_OF_RESOURCE: /* out of resources to complete request */ - sc->result = (DID_REQUEUE << 16) | icmnd_cmpl->scsi_status; - break; - case FCPIO_INVALID_HEADER: /* header contains invalid data */ - case FCPIO_INVALID_PARAM: /* some parameter in request invalid */ - case FCPIO_REQ_NOT_SUPPORTED:/* request type is not supported */ - case FCPIO_IO_NOT_FOUND: /* requested I/O was not found */ - case FCPIO_SGL_INVALID: /* request was aborted due to sgl error */ - case FCPIO_MSS_INVALID: /* request was aborted due to mss error */ - case FCPIO_FW_ERR: /* request was terminated due fw error */ - default: - shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n", - fnic_fcpio_status_to_str(hdr_status)); - sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; - break; - } - - /* Break link with the SCSI command */ - CMD_SP(sc) = NULL; - - spin_unlock_irqrestore(io_lock, flags); - - fnic_release_ioreq_buf(fnic, io_req, sc); - - mempool_free(io_req, fnic->io_req_pool); - - if (sc->sc_data_direction == DMA_FROM_DEVICE) { - fnic->lport->host_stats.fcp_input_requests++; - fnic->fcp_input_bytes += xfer_len; - } else if (sc->sc_data_direction == DMA_TO_DEVICE) { - fnic->lport->host_stats.fcp_output_requests++; - fnic->fcp_output_bytes += xfer_len; - } else - fnic->lport->host_stats.fcp_control_requests++; - - /* Call SCSI completion function to complete the IO */ - if (sc->scsi_done) - sc->scsi_done(sc); - -} - -/* fnic_fcpio_itmf_cmpl_handler - * Routine to handle itmf completions - */ -static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, - struct fcpio_fw_req *desc) -{ - u8 type; - u8 hdr_status; - struct fcpio_tag tag; - u32 id; - struct scsi_cmnd *sc; - struct fnic_io_req *io_req; - unsigned long flags; - spinlock_t *io_lock; - - fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); - fcpio_tag_id_dec(&tag, &id); - - if ((id & FNIC_TAG_MASK) >= FNIC_MAX_IO_REQ) - return; - - sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK); - WARN_ON_ONCE(!sc); - if (!sc) - return; - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - WARN_ON_ONCE(!io_req); - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - return; - } - - if (id & FNIC_TAG_ABORT) { - /* Completion of abort cmd */ - if (CMD_STATE(sc) != FNIC_IOREQ_ABTS_PENDING) { - /* This is a late completion. Ignore it */ - spin_unlock_irqrestore(io_lock, flags); - return; - } - CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE; - CMD_ABTS_STATUS(sc) = hdr_status; - - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "abts cmpl recd. id %d status %s\n", - (int)(id & FNIC_TAG_MASK), - fnic_fcpio_status_to_str(hdr_status)); - - /* - * If scsi_eh thread is blocked waiting for abts to complete, - * signal completion to it. IO will be cleaned in the thread - * else clean it in this context - */ - if (io_req->abts_done) { - complete(io_req->abts_done); - spin_unlock_irqrestore(io_lock, flags); - } else { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "abts cmpl, completing IO\n"); - CMD_SP(sc) = NULL; - sc->result = (DID_ERROR << 16); - - spin_unlock_irqrestore(io_lock, flags); - - fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - if (sc->scsi_done) - sc->scsi_done(sc); - } - - } else if (id & FNIC_TAG_DEV_RST) { - /* Completion of device reset */ - CMD_LR_STATUS(sc) = hdr_status; - CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "dev reset cmpl recd. id %d status %s\n", - (int)(id & FNIC_TAG_MASK), - fnic_fcpio_status_to_str(hdr_status)); - if (io_req->dr_done) - complete(io_req->dr_done); - spin_unlock_irqrestore(io_lock, flags); - - } else { - shost_printk(KERN_ERR, fnic->lport->host, - "Unexpected itmf io state %s tag %x\n", - fnic_ioreq_state_to_str(CMD_STATE(sc)), id); - spin_unlock_irqrestore(io_lock, flags); - } - -} - -/* - * fnic_fcpio_cmpl_handler - * Routine to service the cq for wq_copy - */ -static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev, - unsigned int cq_index, - struct fcpio_fw_req *desc) -{ - struct fnic *fnic = vnic_dev_priv(vdev); - int ret = 0; - - switch (desc->hdr.type) { - case FCPIO_ACK: /* fw copied copy wq desc to its queue */ - fnic_fcpio_ack_handler(fnic, cq_index, desc); - break; - - case FCPIO_ICMND_CMPL: /* fw completed a command */ - fnic_fcpio_icmnd_cmpl_handler(fnic, desc); - break; - - case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/ - fnic_fcpio_itmf_cmpl_handler(fnic, desc); - break; - - case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */ - case FCPIO_FLOGI_FIP_REG_CMPL: /* fw completed flogi_fip_reg */ - ret = fnic_fcpio_flogi_reg_cmpl_handler(fnic, desc); - break; - - case FCPIO_RESET_CMPL: /* fw completed reset */ - ret = fnic_fcpio_fw_reset_cmpl_handler(fnic, desc); - break; - - default: - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "firmware completion type %d\n", - desc->hdr.type); - break; - } - - return ret; -} - -/* - * fnic_wq_copy_cmpl_handler - * Routine to process wq copy - */ -int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do) -{ - unsigned int wq_work_done = 0; - unsigned int i, cq_index; - unsigned int cur_work_done; - - for (i = 0; i < fnic->wq_copy_count; i++) { - cq_index = i + fnic->raw_wq_count + fnic->rq_count; - cur_work_done = vnic_cq_copy_service(&fnic->cq[cq_index], - fnic_fcpio_cmpl_handler, - copy_work_to_do); - wq_work_done += cur_work_done; - } - return wq_work_done; -} - -static void fnic_cleanup_io(struct fnic *fnic, int exclude_id) -{ - unsigned int i; - struct fnic_io_req *io_req; - unsigned long flags = 0; - struct scsi_cmnd *sc; - spinlock_t *io_lock; - - for (i = 0; i < FNIC_MAX_IO_REQ; i++) { - if (i == exclude_id) - continue; - - sc = scsi_host_find_tag(fnic->lport->host, i); - if (!sc) - continue; - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - goto cleanup_scsi_cmd; - } - - CMD_SP(sc) = NULL; - - spin_unlock_irqrestore(io_lock, flags); - - /* - * If there is a scsi_cmnd associated with this io_req, then - * free the corresponding state - */ - fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - -cleanup_scsi_cmd: - sc->result = DID_TRANSPORT_DISRUPTED << 16; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "fnic_cleanup_io:" - " DID_TRANSPORT_DISRUPTED\n"); - - /* Complete the command to SCSI */ - if (sc->scsi_done) - sc->scsi_done(sc); - } -} - -void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, - struct fcpio_host_req *desc) -{ - u32 id; - struct fnic *fnic = vnic_dev_priv(wq->vdev); - struct fnic_io_req *io_req; - struct scsi_cmnd *sc; - unsigned long flags; - spinlock_t *io_lock; - - /* get the tag reference */ - fcpio_tag_id_dec(&desc->hdr.tag, &id); - id &= FNIC_TAG_MASK; - - if (id >= FNIC_MAX_IO_REQ) - return; - - sc = scsi_host_find_tag(fnic->lport->host, id); - if (!sc) - return; - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - - /* Get the IO context which this desc refers to */ - io_req = (struct fnic_io_req *)CMD_SP(sc); - - /* fnic interrupts are turned off by now */ - - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - goto wq_copy_cleanup_scsi_cmd; - } - - CMD_SP(sc) = NULL; - - spin_unlock_irqrestore(io_lock, flags); - - fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - -wq_copy_cleanup_scsi_cmd: - sc->result = DID_NO_CONNECT << 16; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "wq_copy_cleanup_handler:" - " DID_NO_CONNECT\n"); - - if (sc->scsi_done) - sc->scsi_done(sc); -} - -static inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, - u32 task_req, u8 *fc_lun, - struct fnic_io_req *io_req) -{ - struct vnic_wq_copy *wq = &fnic->wq_copy[0]; - unsigned long flags; - - spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); - - if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); - - if (!vnic_wq_copy_desc_avail(wq)) { - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); - return 1; - } - fnic_queue_wq_copy_desc_itmf(wq, tag | FNIC_TAG_ABORT, - 0, task_req, tag, fc_lun, io_req->port_id, - fnic->config.ra_tov, fnic->config.ed_tov); - - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); - return 0; -} - -void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) -{ - int tag; - struct fnic_io_req *io_req; - spinlock_t *io_lock; - unsigned long flags; - struct scsi_cmnd *sc; - struct scsi_lun fc_lun; - enum fnic_ioreq_state old_ioreq_state; - - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "fnic_rport_reset_exch called portid 0x%06x\n", - port_id); - - if (fnic->in_remove) - return; - - for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { - sc = scsi_host_find_tag(fnic->lport->host, tag); - if (!sc) - continue; - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - - io_req = (struct fnic_io_req *)CMD_SP(sc); - - if (!io_req || io_req->port_id != port_id) { - spin_unlock_irqrestore(io_lock, flags); - continue; - } - - /* - * Found IO that is still pending with firmware and - * belongs to rport that went away - */ - if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); - continue; - } - old_ioreq_state = CMD_STATE(sc); - CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; - CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; - - BUG_ON(io_req->abts_done); - - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "fnic_rport_reset_exch: Issuing abts\n"); - - spin_unlock_irqrestore(io_lock, flags); - - /* Now queue the abort command to firmware */ - int_to_scsilun(sc->device->lun, &fc_lun); - - if (fnic_queue_abort_io_req(fnic, tag, - FCPIO_ITMF_ABT_TASK_TERM, - fc_lun.scsi_lun, io_req)) { - /* - * Revert the cmd state back to old state, if - * it hasn't changed in between. This cmd will get - * aborted later by scsi_eh, or cleaned up during - * lun reset - */ - io_lock = fnic_io_lock_hash(fnic, sc); - - spin_lock_irqsave(io_lock, flags); - if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) - CMD_STATE(sc) = old_ioreq_state; - spin_unlock_irqrestore(io_lock, flags); - } - } - -} - -void fnic_terminate_rport_io(struct fc_rport *rport) -{ - int tag; - struct fnic_io_req *io_req; - spinlock_t *io_lock; - unsigned long flags; - struct scsi_cmnd *sc; - struct scsi_lun fc_lun; - struct fc_rport_libfc_priv *rdata = rport->dd_data; - struct fc_lport *lport = rdata->local_port; - struct fnic *fnic = lport_priv(lport); - struct fc_rport *cmd_rport; - enum fnic_ioreq_state old_ioreq_state; - - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, "fnic_terminate_rport_io called" - " wwpn 0x%llx, wwnn0x%llx, portid 0x%06x\n", - rport->port_name, rport->node_name, - rport->port_id); - - if (fnic->in_remove) - return; - - for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { - sc = scsi_host_find_tag(fnic->lport->host, tag); - if (!sc) - continue; - - cmd_rport = starget_to_rport(scsi_target(sc->device)); - if (rport != cmd_rport) - continue; - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - - io_req = (struct fnic_io_req *)CMD_SP(sc); - - if (!io_req || rport != cmd_rport) { - spin_unlock_irqrestore(io_lock, flags); - continue; - } - - /* - * Found IO that is still pending with firmware and - * belongs to rport that went away - */ - if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); - continue; - } - old_ioreq_state = CMD_STATE(sc); - CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; - CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; - - BUG_ON(io_req->abts_done); - - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "fnic_terminate_rport_io: Issuing abts\n"); - - spin_unlock_irqrestore(io_lock, flags); - - /* Now queue the abort command to firmware */ - int_to_scsilun(sc->device->lun, &fc_lun); - - if (fnic_queue_abort_io_req(fnic, tag, - FCPIO_ITMF_ABT_TASK_TERM, - fc_lun.scsi_lun, io_req)) { - /* - * Revert the cmd state back to old state, if - * it hasn't changed in between. This cmd will get - * aborted later by scsi_eh, or cleaned up during - * lun reset - */ - io_lock = fnic_io_lock_hash(fnic, sc); - - spin_lock_irqsave(io_lock, flags); - if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) - CMD_STATE(sc) = old_ioreq_state; - spin_unlock_irqrestore(io_lock, flags); - } - } - -} - -/* - * This function is exported to SCSI for sending abort cmnds. - * A SCSI IO is represented by a io_req in the driver. - * The ioreq is linked to the SCSI Cmd, thus a link with the ULP's IO. - */ -int fnic_abort_cmd(struct scsi_cmnd *sc) -{ - struct fc_lport *lp; - struct fnic *fnic; - struct fnic_io_req *io_req; - struct fc_rport *rport; - spinlock_t *io_lock; - unsigned long flags; - int ret = SUCCESS; - u32 task_req; - struct scsi_lun fc_lun; - DECLARE_COMPLETION_ONSTACK(tm_done); - - /* Wait for rport to unblock */ - fc_block_scsi_eh(sc); - - /* Get local-port, check ready and link up */ - lp = shost_priv(sc->device->host); - - fnic = lport_priv(lp); - rport = starget_to_rport(scsi_target(sc->device)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n", - rport->port_id, sc->device->lun, sc->request->tag); - - if (lp->state != LPORT_ST_READY || !(lp->link_up)) { - ret = FAILED; - goto fnic_abort_cmd_end; - } - - /* - * Avoid a race between SCSI issuing the abort and the device - * completing the command. - * - * If the command is already completed by the fw cmpl code, - * we just return SUCCESS from here. This means that the abort - * succeeded. In the SCSI ML, since the timeout for command has - * happened, the completion wont actually complete the command - * and it will be considered as an aborted command - * - * The CMD_SP will not be cleared except while holding io_req_lock. - */ - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - goto fnic_abort_cmd_end; - } - - io_req->abts_done = &tm_done; - - if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); - goto wait_pending; - } - /* - * Command is still pending, need to abort it - * If the firmware completes the command after this point, - * the completion wont be done till mid-layer, since abort - * has already started. - */ - CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; - CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; - - spin_unlock_irqrestore(io_lock, flags); - - /* - * Check readiness of the remote port. If the path to remote - * port is up, then send abts to the remote port to terminate - * the IO. Else, just locally terminate the IO in the firmware - */ - if (fc_remote_port_chkready(rport) == 0) - task_req = FCPIO_ITMF_ABT_TASK; - else - task_req = FCPIO_ITMF_ABT_TASK_TERM; - - /* Now queue the abort command to firmware */ - int_to_scsilun(sc->device->lun, &fc_lun); - - if (fnic_queue_abort_io_req(fnic, sc->request->tag, task_req, - fc_lun.scsi_lun, io_req)) { - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (io_req) - io_req->abts_done = NULL; - spin_unlock_irqrestore(io_lock, flags); - ret = FAILED; - goto fnic_abort_cmd_end; - } - - /* - * We queued an abort IO, wait for its completion. - * Once the firmware completes the abort command, it will - * wake up this thread. - */ - wait_pending: - wait_for_completion_timeout(&tm_done, - msecs_to_jiffies - (2 * fnic->config.ra_tov + - fnic->config.ed_tov)); - - /* Check the abort status */ - spin_lock_irqsave(io_lock, flags); - - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - ret = FAILED; - goto fnic_abort_cmd_end; - } - io_req->abts_done = NULL; - - /* fw did not complete abort, timed out */ - if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); - ret = FAILED; - goto fnic_abort_cmd_end; - } - - /* - * firmware completed the abort, check the status, - * free the io_req irrespective of failure or success - */ - if (CMD_ABTS_STATUS(sc) != FCPIO_SUCCESS) - ret = FAILED; - - CMD_SP(sc) = NULL; - - spin_unlock_irqrestore(io_lock, flags); - - fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - -fnic_abort_cmd_end: - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Returning from abort cmd %s\n", - (ret == SUCCESS) ? - "SUCCESS" : "FAILED"); - return ret; -} - -static inline int fnic_queue_dr_io_req(struct fnic *fnic, - struct scsi_cmnd *sc, - struct fnic_io_req *io_req) -{ - struct vnic_wq_copy *wq = &fnic->wq_copy[0]; - struct scsi_lun fc_lun; - int ret = 0; - unsigned long intr_flags; - - spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); - - if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); - - if (!vnic_wq_copy_desc_avail(wq)) { - ret = -EAGAIN; - goto lr_io_req_end; - } - - /* fill in the lun info */ - int_to_scsilun(sc->device->lun, &fc_lun); - - fnic_queue_wq_copy_desc_itmf(wq, sc->request->tag | FNIC_TAG_DEV_RST, - 0, FCPIO_ITMF_LUN_RESET, SCSI_NO_TAG, - fc_lun.scsi_lun, io_req->port_id, - fnic->config.ra_tov, fnic->config.ed_tov); - -lr_io_req_end: - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); - - return ret; -} - -/* - * Clean up any pending aborts on the lun - * For each outstanding IO on this lun, whose abort is not completed by fw, - * issue a local abort. Wait for abort to complete. Return 0 if all commands - * successfully aborted, 1 otherwise - */ -static int fnic_clean_pending_aborts(struct fnic *fnic, - struct scsi_cmnd *lr_sc) -{ - int tag; - struct fnic_io_req *io_req; - spinlock_t *io_lock; - unsigned long flags; - int ret = 0; - struct scsi_cmnd *sc; - struct scsi_lun fc_lun; - struct scsi_device *lun_dev = lr_sc->device; - DECLARE_COMPLETION_ONSTACK(tm_done); - - for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { - sc = scsi_host_find_tag(fnic->lport->host, tag); - /* - * ignore this lun reset cmd or cmds that do not belong to - * this lun - */ - if (!sc || sc == lr_sc || sc->device != lun_dev) - continue; - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - - io_req = (struct fnic_io_req *)CMD_SP(sc); - - if (!io_req || sc->device != lun_dev) { - spin_unlock_irqrestore(io_lock, flags); - continue; - } - - /* - * Found IO that is still pending with firmware and - * belongs to the LUN that we are resetting - */ - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Found IO in %s on lun\n", - fnic_ioreq_state_to_str(CMD_STATE(sc))); - - BUG_ON(CMD_STATE(sc) != FNIC_IOREQ_ABTS_PENDING); - - CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; - io_req->abts_done = &tm_done; - spin_unlock_irqrestore(io_lock, flags); - - /* Now queue the abort command to firmware */ - int_to_scsilun(sc->device->lun, &fc_lun); - - if (fnic_queue_abort_io_req(fnic, tag, - FCPIO_ITMF_ABT_TASK_TERM, - fc_lun.scsi_lun, io_req)) { - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (io_req) - io_req->abts_done = NULL; - spin_unlock_irqrestore(io_lock, flags); - ret = 1; - goto clean_pending_aborts_end; - } - - wait_for_completion_timeout(&tm_done, - msecs_to_jiffies - (fnic->config.ed_tov)); - - /* Recheck cmd state to check if it is now aborted */ - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - ret = 1; - goto clean_pending_aborts_end; - } - - io_req->abts_done = NULL; - - /* if abort is still pending with fw, fail */ - if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); - ret = 1; - goto clean_pending_aborts_end; - } - CMD_SP(sc) = NULL; - spin_unlock_irqrestore(io_lock, flags); - - fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - } - -clean_pending_aborts_end: - return ret; -} - -/* - * SCSI Eh thread issues a Lun Reset when one or more commands on a LUN - * fail to get aborted. It calls driver's eh_device_reset with a SCSI command - * on the LUN. - */ -int fnic_device_reset(struct scsi_cmnd *sc) -{ - struct fc_lport *lp; - struct fnic *fnic; - struct fnic_io_req *io_req; - struct fc_rport *rport; - int status; - int ret = FAILED; - spinlock_t *io_lock; - unsigned long flags; - DECLARE_COMPLETION_ONSTACK(tm_done); - - /* Wait for rport to unblock */ - fc_block_scsi_eh(sc); - - /* Get local-port, check ready and link up */ - lp = shost_priv(sc->device->host); - - fnic = lport_priv(lp); - - rport = starget_to_rport(scsi_target(sc->device)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Device reset called FCID 0x%x, LUN 0x%x\n", - rport->port_id, sc->device->lun); - - if (lp->state != LPORT_ST_READY || !(lp->link_up)) - goto fnic_device_reset_end; - - /* Check if remote port up */ - if (fc_remote_port_chkready(rport)) - goto fnic_device_reset_end; - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - - /* - * If there is a io_req attached to this command, then use it, - * else allocate a new one. - */ - if (!io_req) { - io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - goto fnic_device_reset_end; - } - memset(io_req, 0, sizeof(*io_req)); - io_req->port_id = rport->port_id; - CMD_SP(sc) = (char *)io_req; - } - io_req->dr_done = &tm_done; - CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING; - CMD_LR_STATUS(sc) = FCPIO_INVALID_CODE; - spin_unlock_irqrestore(io_lock, flags); - - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "TAG %d\n", - sc->request->tag); - - /* - * issue the device reset, if enqueue failed, clean up the ioreq - * and break assoc with scsi cmd - */ - if (fnic_queue_dr_io_req(fnic, sc, io_req)) { - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (io_req) - io_req->dr_done = NULL; - goto fnic_device_reset_clean; - } - - /* - * Wait on the local completion for LUN reset. The io_req may be - * freed while we wait since we hold no lock. - */ - wait_for_completion_timeout(&tm_done, - msecs_to_jiffies(FNIC_LUN_RESET_TIMEOUT)); - - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - goto fnic_device_reset_end; - } - io_req->dr_done = NULL; - - status = CMD_LR_STATUS(sc); - spin_unlock_irqrestore(io_lock, flags); - - /* - * If lun reset not completed, bail out with failed. io_req - * gets cleaned up during higher levels of EH - */ - if (status == FCPIO_INVALID_CODE) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Device reset timed out\n"); - goto fnic_device_reset_end; - } - - /* Completed, but not successful, clean up the io_req, return fail */ - if (status != FCPIO_SUCCESS) { - spin_lock_irqsave(io_lock, flags); - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "Device reset completed - failed\n"); - io_req = (struct fnic_io_req *)CMD_SP(sc); - goto fnic_device_reset_clean; - } - - /* - * Clean up any aborts on this lun that have still not - * completed. If any of these fail, then LUN reset fails. - * clean_pending_aborts cleans all cmds on this lun except - * the lun reset cmd. If all cmds get cleaned, the lun reset - * succeeds - */ - if (fnic_clean_pending_aborts(fnic, sc)) { - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Device reset failed" - " since could not abort all IOs\n"); - goto fnic_device_reset_clean; - } - - /* Clean lun reset command */ - spin_lock_irqsave(io_lock, flags); - io_req = (struct fnic_io_req *)CMD_SP(sc); - if (io_req) - /* Completed, and successful */ - ret = SUCCESS; - -fnic_device_reset_clean: - if (io_req) - CMD_SP(sc) = NULL; - - spin_unlock_irqrestore(io_lock, flags); - - if (io_req) { - fnic_release_ioreq_buf(fnic, io_req, sc); - mempool_free(io_req, fnic->io_req_pool); - } - -fnic_device_reset_end: - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Returning from device reset %s\n", - (ret == SUCCESS) ? - "SUCCESS" : "FAILED"); - return ret; -} - -/* Clean up all IOs, clean up libFC local port */ -int fnic_reset(struct Scsi_Host *shost) -{ - struct fc_lport *lp; - struct fnic *fnic; - int ret = SUCCESS; - - lp = shost_priv(shost); - fnic = lport_priv(lp); - - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "fnic_reset called\n"); - - /* - * Reset local port, this will clean up libFC exchanges, - * reset remote port sessions, and if link is up, begin flogi - */ - if (lp->tt.lport_reset(lp)) - ret = FAILED; - - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Returning from fnic reset %s\n", - (ret == SUCCESS) ? - "SUCCESS" : "FAILED"); - - return ret; -} - -/* - * SCSI Error handling calls driver's eh_host_reset if all prior - * error handling levels return FAILED. If host reset completes - * successfully, and if link is up, then Fabric login begins. - * - * Host Reset is the highest level of error recovery. If this fails, then - * host is offlined by SCSI. - * - */ -int fnic_host_reset(struct scsi_cmnd *sc) -{ - int ret; - unsigned long wait_host_tmo; - struct Scsi_Host *shost = sc->device->host; - struct fc_lport *lp = shost_priv(shost); - - /* - * If fnic_reset is successful, wait for fabric login to complete - * scsi-ml tries to send a TUR to every device if host reset is - * successful, so before returning to scsi, fabric should be up - */ - ret = fnic_reset(shost); - if (ret == SUCCESS) { - wait_host_tmo = jiffies + FNIC_HOST_RESET_SETTLE_TIME * HZ; - ret = FAILED; - while (time_before(jiffies, wait_host_tmo)) { - if ((lp->state == LPORT_ST_READY) && - (lp->link_up)) { - ret = SUCCESS; - break; - } - ssleep(1); - } - } - - return ret; -} - -/* - * This fxn is called from libFC when host is removed - */ -void fnic_scsi_abort_io(struct fc_lport *lp) -{ - int err = 0; - unsigned long flags; - enum fnic_state old_state; - struct fnic *fnic = lport_priv(lp); - DECLARE_COMPLETION_ONSTACK(remove_wait); - - /* Issue firmware reset for fnic, wait for reset to complete */ - spin_lock_irqsave(&fnic->fnic_lock, flags); - fnic->remove_wait = &remove_wait; - old_state = fnic->state; - fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; - fnic_update_mac_locked(fnic, fnic->ctlr.ctl_src_addr); - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - err = fnic_fw_reset_handler(fnic); - if (err) { - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) - fnic->state = old_state; - fnic->remove_wait = NULL; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - return; - } - - /* Wait for firmware reset to complete */ - wait_for_completion_timeout(&remove_wait, - msecs_to_jiffies(FNIC_RMDEVICE_TIMEOUT)); - - spin_lock_irqsave(&fnic->fnic_lock, flags); - fnic->remove_wait = NULL; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "fnic_scsi_abort_io %s\n", - (fnic->state == FNIC_IN_ETH_MODE) ? - "SUCCESS" : "FAILED"); - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - -} - -/* - * This fxn called from libFC to clean up driver IO state on link down - */ -void fnic_scsi_cleanup(struct fc_lport *lp) -{ - unsigned long flags; - enum fnic_state old_state; - struct fnic *fnic = lport_priv(lp); - - /* issue fw reset */ - spin_lock_irqsave(&fnic->fnic_lock, flags); - old_state = fnic->state; - fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; - fnic_update_mac_locked(fnic, fnic->ctlr.ctl_src_addr); - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - - if (fnic_fw_reset_handler(fnic)) { - spin_lock_irqsave(&fnic->fnic_lock, flags); - if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) - fnic->state = old_state; - spin_unlock_irqrestore(&fnic->fnic_lock, flags); - } - -} - -void fnic_empty_scsi_cleanup(struct fc_lport *lp) -{ -} - -void fnic_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) -{ - struct fnic *fnic = lport_priv(lp); - - /* Non-zero sid, nothing to do */ - if (sid) - goto call_fc_exch_mgr_reset; - - if (did) { - fnic_rport_exch_reset(fnic, did); - goto call_fc_exch_mgr_reset; - } - - /* - * sid = 0, did = 0 - * link down or device being removed - */ - if (!fnic->in_remove) - fnic_scsi_cleanup(lp); - else - fnic_scsi_abort_io(lp); - - /* call libFC exch mgr reset to reset its exchanges */ -call_fc_exch_mgr_reset: - fc_exch_mgr_reset(lp, sid, did); - -} diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/rq_enet_desc.h b/ANDROID_3.4.5/drivers/scsi/fnic/rq_enet_desc.h deleted file mode 100644 index 92e80ae6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/rq_enet_desc.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _RQ_ENET_DESC_H_ -#define _RQ_ENET_DESC_H_ - -/* Ethernet receive queue descriptor: 16B */ -struct rq_enet_desc { - __le64 address; - __le16 length_type; - u8 reserved[6]; -}; - -enum rq_enet_type_types { - RQ_ENET_TYPE_ONLY_SOP = 0, - RQ_ENET_TYPE_NOT_SOP = 1, - RQ_ENET_TYPE_RESV2 = 2, - RQ_ENET_TYPE_RESV3 = 3, -}; - -#define RQ_ENET_ADDR_BITS 64 -#define RQ_ENET_LEN_BITS 14 -#define RQ_ENET_LEN_MASK ((1 << RQ_ENET_LEN_BITS) - 1) -#define RQ_ENET_TYPE_BITS 2 -#define RQ_ENET_TYPE_MASK ((1 << RQ_ENET_TYPE_BITS) - 1) - -static inline void rq_enet_desc_enc(struct rq_enet_desc *desc, - u64 address, u8 type, u16 length) -{ - desc->address = cpu_to_le64(address); - desc->length_type = cpu_to_le16((length & RQ_ENET_LEN_MASK) | - ((type & RQ_ENET_TYPE_MASK) << RQ_ENET_LEN_BITS)); -} - -static inline void rq_enet_desc_dec(struct rq_enet_desc *desc, - u64 *address, u8 *type, u16 *length) -{ - *address = le64_to_cpu(desc->address); - *length = le16_to_cpu(desc->length_type) & RQ_ENET_LEN_MASK; - *type = (u8)((le16_to_cpu(desc->length_type) >> RQ_ENET_LEN_BITS) & - RQ_ENET_TYPE_MASK); -} - -#endif /* _RQ_ENET_DESC_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.c b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.c deleted file mode 100644 index c5db32ed..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#include -#include -#include -#include "vnic_dev.h" -#include "vnic_cq.h" - -void vnic_cq_free(struct vnic_cq *cq) -{ - vnic_dev_free_desc_ring(cq->vdev, &cq->ring); - - cq->ctrl = NULL; -} - -int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index, - unsigned int desc_count, unsigned int desc_size) -{ - int err; - - cq->index = index; - cq->vdev = vdev; - - cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index); - if (!cq->ctrl) { - printk(KERN_ERR "Failed to hook CQ[%d] resource\n", index); - return -EINVAL; - } - - err = vnic_dev_alloc_desc_ring(vdev, &cq->ring, desc_count, desc_size); - if (err) - return err; - - return 0; -} - -void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, - unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, - unsigned int cq_tail_color, unsigned int interrupt_enable, - unsigned int cq_entry_enable, unsigned int cq_message_enable, - unsigned int interrupt_offset, u64 cq_message_addr) -{ - u64 paddr; - - paddr = (u64)cq->ring.base_addr | VNIC_PADDR_TARGET; - writeq(paddr, &cq->ctrl->ring_base); - iowrite32(cq->ring.desc_count, &cq->ctrl->ring_size); - iowrite32(flow_control_enable, &cq->ctrl->flow_control_enable); - iowrite32(color_enable, &cq->ctrl->color_enable); - iowrite32(cq_head, &cq->ctrl->cq_head); - iowrite32(cq_tail, &cq->ctrl->cq_tail); - iowrite32(cq_tail_color, &cq->ctrl->cq_tail_color); - iowrite32(interrupt_enable, &cq->ctrl->interrupt_enable); - iowrite32(cq_entry_enable, &cq->ctrl->cq_entry_enable); - iowrite32(cq_message_enable, &cq->ctrl->cq_message_enable); - iowrite32(interrupt_offset, &cq->ctrl->interrupt_offset); - writeq(cq_message_addr, &cq->ctrl->cq_message_addr); -} - -void vnic_cq_clean(struct vnic_cq *cq) -{ - cq->to_clean = 0; - cq->last_color = 0; - - iowrite32(0, &cq->ctrl->cq_head); - iowrite32(0, &cq->ctrl->cq_tail); - iowrite32(1, &cq->ctrl->cq_tail_color); - - vnic_dev_clear_desc_ring(&cq->ring); -} diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.h deleted file mode 100644 index 4ede6809..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_CQ_H_ -#define _VNIC_CQ_H_ - -#include "cq_desc.h" -#include "vnic_dev.h" - -/* - * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth - * Driver) when both are built with CONFIG options =y - */ -#define vnic_cq_service fnic_cq_service -#define vnic_cq_free fnic_cq_free -#define vnic_cq_alloc fnic_cq_alloc -#define vnic_cq_init fnic_cq_init -#define vnic_cq_clean fnic_cq_clean - -/* Completion queue control */ -struct vnic_cq_ctrl { - u64 ring_base; /* 0x00 */ - u32 ring_size; /* 0x08 */ - u32 pad0; - u32 flow_control_enable; /* 0x10 */ - u32 pad1; - u32 color_enable; /* 0x18 */ - u32 pad2; - u32 cq_head; /* 0x20 */ - u32 pad3; - u32 cq_tail; /* 0x28 */ - u32 pad4; - u32 cq_tail_color; /* 0x30 */ - u32 pad5; - u32 interrupt_enable; /* 0x38 */ - u32 pad6; - u32 cq_entry_enable; /* 0x40 */ - u32 pad7; - u32 cq_message_enable; /* 0x48 */ - u32 pad8; - u32 interrupt_offset; /* 0x50 */ - u32 pad9; - u64 cq_message_addr; /* 0x58 */ - u32 pad10; -}; - -struct vnic_cq { - unsigned int index; - struct vnic_dev *vdev; - struct vnic_cq_ctrl __iomem *ctrl; /* memory-mapped */ - struct vnic_dev_ring ring; - unsigned int to_clean; - unsigned int last_color; -}; - -static inline unsigned int vnic_cq_service(struct vnic_cq *cq, - unsigned int work_to_do, - int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc, - u8 type, u16 q_number, u16 completed_index, void *opaque), - void *opaque) -{ - struct cq_desc *cq_desc; - unsigned int work_done = 0; - u16 q_number, completed_index; - u8 type, color; - - cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + - cq->ring.desc_size * cq->to_clean); - cq_desc_dec(cq_desc, &type, &color, - &q_number, &completed_index); - - while (color != cq->last_color) { - - if ((*q_service)(cq->vdev, cq_desc, type, - q_number, completed_index, opaque)) - break; - - cq->to_clean++; - if (cq->to_clean == cq->ring.desc_count) { - cq->to_clean = 0; - cq->last_color = cq->last_color ? 0 : 1; - } - - cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + - cq->ring.desc_size * cq->to_clean); - cq_desc_dec(cq_desc, &type, &color, - &q_number, &completed_index); - - work_done++; - if (work_done >= work_to_do) - break; - } - - return work_done; -} - -void vnic_cq_free(struct vnic_cq *cq); -int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index, - unsigned int desc_count, unsigned int desc_size); -void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, - unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, - unsigned int cq_tail_color, unsigned int interrupt_enable, - unsigned int cq_entry_enable, unsigned int message_enable, - unsigned int interrupt_offset, u64 message_addr); -void vnic_cq_clean(struct vnic_cq *cq); - -#endif /* _VNIC_CQ_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq_copy.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq_copy.h deleted file mode 100644 index 7901ce25..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_cq_copy.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_CQ_COPY_H_ -#define _VNIC_CQ_COPY_H_ - -#include "fcpio.h" - -static inline unsigned int vnic_cq_copy_service( - struct vnic_cq *cq, - int (*q_service)(struct vnic_dev *vdev, - unsigned int index, - struct fcpio_fw_req *desc), - unsigned int work_to_do) - -{ - struct fcpio_fw_req *desc; - unsigned int work_done = 0; - u8 color; - - desc = (struct fcpio_fw_req *)((u8 *)cq->ring.descs + - cq->ring.desc_size * cq->to_clean); - fcpio_color_dec(desc, &color); - - while (color != cq->last_color) { - - if ((*q_service)(cq->vdev, cq->index, desc)) - break; - - cq->to_clean++; - if (cq->to_clean == cq->ring.desc_count) { - cq->to_clean = 0; - cq->last_color = cq->last_color ? 0 : 1; - } - - desc = (struct fcpio_fw_req *)((u8 *)cq->ring.descs + - cq->ring.desc_size * cq->to_clean); - fcpio_color_dec(desc, &color); - - work_done++; - if (work_done >= work_to_do) - break; - } - - return work_done; -} - -#endif /* _VNIC_CQ_COPY_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.c b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.c deleted file mode 100644 index b576be73..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "vnic_resource.h" -#include "vnic_devcmd.h" -#include "vnic_dev.h" -#include "vnic_stats.h" - -struct vnic_res { - void __iomem *vaddr; - unsigned int count; -}; - -struct vnic_dev { - void *priv; - struct pci_dev *pdev; - struct vnic_res res[RES_TYPE_MAX]; - enum vnic_dev_intr_mode intr_mode; - struct vnic_devcmd __iomem *devcmd; - struct vnic_devcmd_notify *notify; - struct vnic_devcmd_notify notify_copy; - dma_addr_t notify_pa; - u32 *linkstatus; - dma_addr_t linkstatus_pa; - struct vnic_stats *stats; - dma_addr_t stats_pa; - struct vnic_devcmd_fw_info *fw_info; - dma_addr_t fw_info_pa; -}; - -#define VNIC_MAX_RES_HDR_SIZE \ - (sizeof(struct vnic_resource_header) + \ - sizeof(struct vnic_resource) * RES_TYPE_MAX) -#define VNIC_RES_STRIDE 128 - -void *vnic_dev_priv(struct vnic_dev *vdev) -{ - return vdev->priv; -} - -static int vnic_dev_discover_res(struct vnic_dev *vdev, - struct vnic_dev_bar *bar) -{ - struct vnic_resource_header __iomem *rh; - struct vnic_resource __iomem *r; - u8 type; - - if (bar->len < VNIC_MAX_RES_HDR_SIZE) { - printk(KERN_ERR "vNIC BAR0 res hdr length error\n"); - return -EINVAL; - } - - rh = bar->vaddr; - if (!rh) { - printk(KERN_ERR "vNIC BAR0 res hdr not mem-mapped\n"); - return -EINVAL; - } - - if (ioread32(&rh->magic) != VNIC_RES_MAGIC || - ioread32(&rh->version) != VNIC_RES_VERSION) { - printk(KERN_ERR "vNIC BAR0 res magic/version error " - "exp (%lx/%lx) curr (%x/%x)\n", - VNIC_RES_MAGIC, VNIC_RES_VERSION, - ioread32(&rh->magic), ioread32(&rh->version)); - return -EINVAL; - } - - r = (struct vnic_resource __iomem *)(rh + 1); - - while ((type = ioread8(&r->type)) != RES_TYPE_EOL) { - - u8 bar_num = ioread8(&r->bar); - u32 bar_offset = ioread32(&r->bar_offset); - u32 count = ioread32(&r->count); - u32 len; - - r++; - - if (bar_num != 0) /* only mapping in BAR0 resources */ - continue; - - switch (type) { - case RES_TYPE_WQ: - case RES_TYPE_RQ: - case RES_TYPE_CQ: - case RES_TYPE_INTR_CTRL: - /* each count is stride bytes long */ - len = count * VNIC_RES_STRIDE; - if (len + bar_offset > bar->len) { - printk(KERN_ERR "vNIC BAR0 resource %d " - "out-of-bounds, offset 0x%x + " - "size 0x%x > bar len 0x%lx\n", - type, bar_offset, - len, - bar->len); - return -EINVAL; - } - break; - case RES_TYPE_INTR_PBA_LEGACY: - case RES_TYPE_DEVCMD: - len = count; - break; - default: - continue; - } - - vdev->res[type].count = count; - vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset; - } - - return 0; -} - -unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, - enum vnic_res_type type) -{ - return vdev->res[type].count; -} - -void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, - unsigned int index) -{ - if (!vdev->res[type].vaddr) - return NULL; - - switch (type) { - case RES_TYPE_WQ: - case RES_TYPE_RQ: - case RES_TYPE_CQ: - case RES_TYPE_INTR_CTRL: - return (char __iomem *)vdev->res[type].vaddr + - index * VNIC_RES_STRIDE; - default: - return (char __iomem *)vdev->res[type].vaddr; - } -} - -unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, - unsigned int desc_count, - unsigned int desc_size) -{ - /* The base address of the desc rings must be 512 byte aligned. - * Descriptor count is aligned to groups of 32 descriptors. A - * count of 0 means the maximum 4096 descriptors. Descriptor - * size is aligned to 16 bytes. - */ - - unsigned int count_align = 32; - unsigned int desc_align = 16; - - ring->base_align = 512; - - if (desc_count == 0) - desc_count = 4096; - - ring->desc_count = ALIGN(desc_count, count_align); - - ring->desc_size = ALIGN(desc_size, desc_align); - - ring->size = ring->desc_count * ring->desc_size; - ring->size_unaligned = ring->size + ring->base_align; - - return ring->size_unaligned; -} - -void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring) -{ - memset(ring->descs, 0, ring->size); -} - -int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, - unsigned int desc_count, unsigned int desc_size) -{ - vnic_dev_desc_ring_size(ring, desc_count, desc_size); - - ring->descs_unaligned = pci_alloc_consistent(vdev->pdev, - ring->size_unaligned, - &ring->base_addr_unaligned); - - if (!ring->descs_unaligned) { - printk(KERN_ERR - "Failed to allocate ring (size=%d), aborting\n", - (int)ring->size); - return -ENOMEM; - } - - ring->base_addr = ALIGN(ring->base_addr_unaligned, - ring->base_align); - ring->descs = (u8 *)ring->descs_unaligned + - (ring->base_addr - ring->base_addr_unaligned); - - vnic_dev_clear_desc_ring(ring); - - ring->desc_avail = ring->desc_count - 1; - - return 0; -} - -void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring) -{ - if (ring->descs) { - pci_free_consistent(vdev->pdev, - ring->size_unaligned, - ring->descs_unaligned, - ring->base_addr_unaligned); - ring->descs = NULL; - } -} - -int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, - u64 *a0, u64 *a1, int wait) -{ - struct vnic_devcmd __iomem *devcmd = vdev->devcmd; - int delay; - u32 status; - int dev_cmd_err[] = { - /* convert from fw's version of error.h to host's version */ - 0, /* ERR_SUCCESS */ - EINVAL, /* ERR_EINVAL */ - EFAULT, /* ERR_EFAULT */ - EPERM, /* ERR_EPERM */ - EBUSY, /* ERR_EBUSY */ - }; - int err; - - status = ioread32(&devcmd->status); - if (status & STAT_BUSY) { - printk(KERN_ERR "Busy devcmd %d\n", _CMD_N(cmd)); - return -EBUSY; - } - - if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) { - writeq(*a0, &devcmd->args[0]); - writeq(*a1, &devcmd->args[1]); - wmb(); - } - - iowrite32(cmd, &devcmd->cmd); - - if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) - return 0; - - for (delay = 0; delay < wait; delay++) { - - udelay(100); - - status = ioread32(&devcmd->status); - if (!(status & STAT_BUSY)) { - - if (status & STAT_ERROR) { - err = dev_cmd_err[(int)readq(&devcmd->args[0])]; - printk(KERN_ERR "Error %d devcmd %d\n", - err, _CMD_N(cmd)); - return -err; - } - - if (_CMD_DIR(cmd) & _CMD_DIR_READ) { - rmb(); - *a0 = readq(&devcmd->args[0]); - *a1 = readq(&devcmd->args[1]); - } - - return 0; - } - } - - printk(KERN_ERR "Timedout devcmd %d\n", _CMD_N(cmd)); - return -ETIMEDOUT; -} - -int vnic_dev_fw_info(struct vnic_dev *vdev, - struct vnic_devcmd_fw_info **fw_info) -{ - u64 a0, a1 = 0; - int wait = 1000; - int err = 0; - - if (!vdev->fw_info) { - vdev->fw_info = pci_alloc_consistent(vdev->pdev, - sizeof(struct vnic_devcmd_fw_info), - &vdev->fw_info_pa); - if (!vdev->fw_info) - return -ENOMEM; - - a0 = vdev->fw_info_pa; - - /* only get fw_info once and cache it */ - err = vnic_dev_cmd(vdev, CMD_MCPU_FW_INFO, &a0, &a1, wait); - } - - *fw_info = vdev->fw_info; - - return err; -} - -int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, - void *value) -{ - u64 a0, a1; - int wait = 1000; - int err; - - a0 = offset; - a1 = size; - - err = vnic_dev_cmd(vdev, CMD_DEV_SPEC, &a0, &a1, wait); - - switch (size) { - case 1: - *(u8 *)value = (u8)a0; - break; - case 2: - *(u16 *)value = (u16)a0; - break; - case 4: - *(u32 *)value = (u32)a0; - break; - case 8: - *(u64 *)value = a0; - break; - default: - BUG(); - break; - } - - return err; -} - -int vnic_dev_stats_clear(struct vnic_dev *vdev) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - return vnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait); -} - -int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) -{ - u64 a0, a1; - int wait = 1000; - - if (!vdev->stats) { - vdev->stats = pci_alloc_consistent(vdev->pdev, - sizeof(struct vnic_stats), &vdev->stats_pa); - if (!vdev->stats) - return -ENOMEM; - } - - *stats = vdev->stats; - a0 = vdev->stats_pa; - a1 = sizeof(struct vnic_stats); - - return vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait); -} - -int vnic_dev_close(struct vnic_dev *vdev) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - return vnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait); -} - -int vnic_dev_enable(struct vnic_dev *vdev) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait); -} - -int vnic_dev_disable(struct vnic_dev *vdev) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - return vnic_dev_cmd(vdev, CMD_DISABLE, &a0, &a1, wait); -} - -int vnic_dev_open(struct vnic_dev *vdev, int arg) -{ - u64 a0 = (u32)arg, a1 = 0; - int wait = 1000; - return vnic_dev_cmd(vdev, CMD_OPEN, &a0, &a1, wait); -} - -int vnic_dev_open_done(struct vnic_dev *vdev, int *done) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - int err; - - *done = 0; - - err = vnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait); - if (err) - return err; - - *done = (a0 == 0); - - return 0; -} - -int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg) -{ - u64 a0 = (u32)arg, a1 = 0; - int wait = 1000; - return vnic_dev_cmd(vdev, CMD_SOFT_RESET, &a0, &a1, wait); -} - -int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - int err; - - *done = 0; - - err = vnic_dev_cmd(vdev, CMD_SOFT_RESET_STATUS, &a0, &a1, wait); - if (err) - return err; - - *done = (a0 == 0); - - return 0; -} - -int vnic_dev_hang_notify(struct vnic_dev *vdev) -{ - u64 a0, a1; - int wait = 1000; - return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait); -} - -int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) -{ - u64 a0, a1; - int wait = 1000; - int err, i; - - for (i = 0; i < ETH_ALEN; i++) - mac_addr[i] = 0; - - err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); - if (err) - return err; - - for (i = 0; i < ETH_ALEN; i++) - mac_addr[i] = ((u8 *)&a0)[i]; - - return 0; -} - -void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, - int broadcast, int promisc, int allmulti) -{ - u64 a0, a1 = 0; - int wait = 1000; - int err; - - a0 = (directed ? CMD_PFILTER_DIRECTED : 0) | - (multicast ? CMD_PFILTER_MULTICAST : 0) | - (broadcast ? CMD_PFILTER_BROADCAST : 0) | - (promisc ? CMD_PFILTER_PROMISCUOUS : 0) | - (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0); - - err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait); - if (err) - printk(KERN_ERR "Can't set packet filter\n"); -} - -void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - int err; - int i; - - for (i = 0; i < ETH_ALEN; i++) - ((u8 *)&a0)[i] = addr[i]; - - err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); - if (err) - printk(KERN_ERR - "Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - err); -} - -void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) -{ - u64 a0 = 0, a1 = 0; - int wait = 1000; - int err; - int i; - - for (i = 0; i < ETH_ALEN; i++) - ((u8 *)&a0)[i] = addr[i]; - - err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); - if (err) - printk(KERN_ERR - "Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - err); -} - -int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) -{ - u64 a0, a1; - int wait = 1000; - - if (!vdev->notify) { - vdev->notify = pci_alloc_consistent(vdev->pdev, - sizeof(struct vnic_devcmd_notify), - &vdev->notify_pa); - if (!vdev->notify) - return -ENOMEM; - } - - a0 = vdev->notify_pa; - a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; - a1 += sizeof(struct vnic_devcmd_notify); - - return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); -} - -void vnic_dev_notify_unset(struct vnic_dev *vdev) -{ - u64 a0, a1; - int wait = 1000; - - a0 = 0; /* paddr = 0 to unset notify buffer */ - a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */ - a1 += sizeof(struct vnic_devcmd_notify); - - vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); -} - -static int vnic_dev_notify_ready(struct vnic_dev *vdev) -{ - u32 *words; - unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4; - unsigned int i; - u32 csum; - - if (!vdev->notify) - return 0; - - do { - csum = 0; - memcpy(&vdev->notify_copy, vdev->notify, - sizeof(struct vnic_devcmd_notify)); - words = (u32 *)&vdev->notify_copy; - for (i = 1; i < nwords; i++) - csum += words[i]; - } while (csum != words[0]); - - return 1; -} - -int vnic_dev_init(struct vnic_dev *vdev, int arg) -{ - u64 a0 = (u32)arg, a1 = 0; - int wait = 1000; - return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); -} - -int vnic_dev_link_status(struct vnic_dev *vdev) -{ - if (vdev->linkstatus) - return *vdev->linkstatus; - - if (!vnic_dev_notify_ready(vdev)) - return 0; - - return vdev->notify_copy.link_state; -} - -u32 vnic_dev_port_speed(struct vnic_dev *vdev) -{ - if (!vnic_dev_notify_ready(vdev)) - return 0; - - return vdev->notify_copy.port_speed; -} - -u32 vnic_dev_msg_lvl(struct vnic_dev *vdev) -{ - if (!vnic_dev_notify_ready(vdev)) - return 0; - - return vdev->notify_copy.msglvl; -} - -u32 vnic_dev_mtu(struct vnic_dev *vdev) -{ - if (!vnic_dev_notify_ready(vdev)) - return 0; - - return vdev->notify_copy.mtu; -} - -u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev) -{ - if (!vnic_dev_notify_ready(vdev)) - return 0; - - return vdev->notify_copy.link_down_cnt; -} - -void vnic_dev_set_intr_mode(struct vnic_dev *vdev, - enum vnic_dev_intr_mode intr_mode) -{ - vdev->intr_mode = intr_mode; -} - -enum vnic_dev_intr_mode vnic_dev_get_intr_mode( - struct vnic_dev *vdev) -{ - return vdev->intr_mode; -} - -void vnic_dev_unregister(struct vnic_dev *vdev) -{ - if (vdev) { - if (vdev->notify) - pci_free_consistent(vdev->pdev, - sizeof(struct vnic_devcmd_notify), - vdev->notify, - vdev->notify_pa); - if (vdev->linkstatus) - pci_free_consistent(vdev->pdev, - sizeof(u32), - vdev->linkstatus, - vdev->linkstatus_pa); - if (vdev->stats) - pci_free_consistent(vdev->pdev, - sizeof(struct vnic_stats), - vdev->stats, vdev->stats_pa); - if (vdev->fw_info) - pci_free_consistent(vdev->pdev, - sizeof(struct vnic_devcmd_fw_info), - vdev->fw_info, vdev->fw_info_pa); - kfree(vdev); - } -} - -struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, - void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar) -{ - if (!vdev) { - vdev = kzalloc(sizeof(struct vnic_dev), GFP_KERNEL); - if (!vdev) - return NULL; - } - - vdev->priv = priv; - vdev->pdev = pdev; - - if (vnic_dev_discover_res(vdev, bar)) - goto err_out; - - vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); - if (!vdev->devcmd) - goto err_out; - - return vdev; - -err_out: - vnic_dev_unregister(vdev); - return NULL; -} diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.h deleted file mode 100644 index f9935a8a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_dev.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_DEV_H_ -#define _VNIC_DEV_H_ - -#include "vnic_resource.h" -#include "vnic_devcmd.h" - -/* - * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth - * Driver) when both are built with CONFIG options =y - */ -#define vnic_dev_priv fnic_dev_priv -#define vnic_dev_get_res_count fnic_dev_get_res_count -#define vnic_dev_get_res fnic_dev_get_res -#define vnic_dev_desc_ring_size fnic_dev_desc_ring_siz -#define vnic_dev_clear_desc_ring fnic_dev_clear_desc_ring -#define vnic_dev_alloc_desc_ring fnic_dev_alloc_desc_ring -#define vnic_dev_free_desc_ring fnic_dev_free_desc_ring -#define vnic_dev_cmd fnic_dev_cmd -#define vnic_dev_fw_info fnic_dev_fw_info -#define vnic_dev_spec fnic_dev_spec -#define vnic_dev_stats_clear fnic_dev_stats_clear -#define vnic_dev_stats_dump fnic_dev_stats_dump -#define vnic_dev_hang_notify fnic_dev_hang_notify -#define vnic_dev_packet_filter fnic_dev_packet_filter -#define vnic_dev_add_addr fnic_dev_add_addr -#define vnic_dev_del_addr fnic_dev_del_addr -#define vnic_dev_mac_addr fnic_dev_mac_addr -#define vnic_dev_notify_set fnic_dev_notify_set -#define vnic_dev_notify_unset fnic_dev_notify_unset -#define vnic_dev_link_status fnic_dev_link_status -#define vnic_dev_port_speed fnic_dev_port_speed -#define vnic_dev_msg_lvl fnic_dev_msg_lvl -#define vnic_dev_mtu fnic_dev_mtu -#define vnic_dev_link_down_cnt fnic_dev_link_down_cnt -#define vnic_dev_close fnic_dev_close -#define vnic_dev_enable fnic_dev_enable -#define vnic_dev_disable fnic_dev_disable -#define vnic_dev_open fnic_dev_open -#define vnic_dev_open_done fnic_dev_open_done -#define vnic_dev_init fnic_dev_init -#define vnic_dev_soft_reset fnic_dev_soft_reset -#define vnic_dev_soft_reset_done fnic_dev_soft_reset_done -#define vnic_dev_set_intr_mode fnic_dev_set_intr_mode -#define vnic_dev_get_intr_mode fnic_dev_get_intr_mode -#define vnic_dev_unregister fnic_dev_unregister -#define vnic_dev_register fnic_dev_register - -#ifndef VNIC_PADDR_TARGET -#define VNIC_PADDR_TARGET 0x0000000000000000ULL -#endif - -#ifndef readq -static inline u64 readq(void __iomem *reg) -{ - return ((u64)readl(reg + 0x4UL) << 32) | (u64)readl(reg); -} - -static inline void writeq(u64 val, void __iomem *reg) -{ - writel(val & 0xffffffff, reg); - writel(val >> 32, reg + 0x4UL); -} -#endif - -enum vnic_dev_intr_mode { - VNIC_DEV_INTR_MODE_UNKNOWN, - VNIC_DEV_INTR_MODE_INTX, - VNIC_DEV_INTR_MODE_MSI, - VNIC_DEV_INTR_MODE_MSIX, -}; - -struct vnic_dev_bar { - void __iomem *vaddr; - dma_addr_t bus_addr; - unsigned long len; -}; - -struct vnic_dev_ring { - void *descs; - size_t size; - dma_addr_t base_addr; - size_t base_align; - void *descs_unaligned; - size_t size_unaligned; - dma_addr_t base_addr_unaligned; - unsigned int desc_size; - unsigned int desc_count; - unsigned int desc_avail; -}; - -struct vnic_dev; -struct vnic_stats; - -void *vnic_dev_priv(struct vnic_dev *vdev); -unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, - enum vnic_res_type type); -void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, - unsigned int index); -unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, - unsigned int desc_count, - unsigned int desc_size); -void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring); -int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, - unsigned int desc_count, unsigned int desc_size); -void vnic_dev_free_desc_ring(struct vnic_dev *vdev, - struct vnic_dev_ring *ring); -int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, - u64 *a0, u64 *a1, int wait); -int vnic_dev_fw_info(struct vnic_dev *vdev, - struct vnic_devcmd_fw_info **fw_info); -int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, - unsigned int size, void *value); -int vnic_dev_stats_clear(struct vnic_dev *vdev); -int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats); -int vnic_dev_hang_notify(struct vnic_dev *vdev); -void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, - int broadcast, int promisc, int allmulti); -void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr); -void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr); -int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); -int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr); -void vnic_dev_notify_unset(struct vnic_dev *vdev); -int vnic_dev_link_status(struct vnic_dev *vdev); -u32 vnic_dev_port_speed(struct vnic_dev *vdev); -u32 vnic_dev_msg_lvl(struct vnic_dev *vdev); -u32 vnic_dev_mtu(struct vnic_dev *vdev); -u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev); -int vnic_dev_close(struct vnic_dev *vdev); -int vnic_dev_enable(struct vnic_dev *vdev); -int vnic_dev_disable(struct vnic_dev *vdev); -int vnic_dev_open(struct vnic_dev *vdev, int arg); -int vnic_dev_open_done(struct vnic_dev *vdev, int *done); -int vnic_dev_init(struct vnic_dev *vdev, int arg); -int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg); -int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done); -void vnic_dev_set_intr_mode(struct vnic_dev *vdev, - enum vnic_dev_intr_mode intr_mode); -enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); -void vnic_dev_unregister(struct vnic_dev *vdev); -struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, - void *priv, struct pci_dev *pdev, - struct vnic_dev_bar *bar); - -#endif /* _VNIC_DEV_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_devcmd.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_devcmd.h deleted file mode 100644 index 7c9ccbd4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_devcmd.h +++ /dev/null @@ -1,281 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_DEVCMD_H_ -#define _VNIC_DEVCMD_H_ - -#define _CMD_NBITS 14 -#define _CMD_VTYPEBITS 10 -#define _CMD_FLAGSBITS 6 -#define _CMD_DIRBITS 2 - -#define _CMD_NMASK ((1 << _CMD_NBITS)-1) -#define _CMD_VTYPEMASK ((1 << _CMD_VTYPEBITS)-1) -#define _CMD_FLAGSMASK ((1 << _CMD_FLAGSBITS)-1) -#define _CMD_DIRMASK ((1 << _CMD_DIRBITS)-1) - -#define _CMD_NSHIFT 0 -#define _CMD_VTYPESHIFT (_CMD_NSHIFT+_CMD_NBITS) -#define _CMD_FLAGSSHIFT (_CMD_VTYPESHIFT+_CMD_VTYPEBITS) -#define _CMD_DIRSHIFT (_CMD_FLAGSSHIFT+_CMD_FLAGSBITS) - -/* - * Direction bits (from host perspective). - */ -#define _CMD_DIR_NONE 0U -#define _CMD_DIR_WRITE 1U -#define _CMD_DIR_READ 2U -#define _CMD_DIR_RW (_CMD_DIR_WRITE | _CMD_DIR_READ) - -/* - * Flag bits. - */ -#define _CMD_FLAGS_NONE 0U -#define _CMD_FLAGS_NOWAIT 1U - -/* - * vNIC type bits. - */ -#define _CMD_VTYPE_NONE 0U -#define _CMD_VTYPE_ENET 1U -#define _CMD_VTYPE_FC 2U -#define _CMD_VTYPE_SCSI 4U -#define _CMD_VTYPE_ALL (_CMD_VTYPE_ENET | _CMD_VTYPE_FC | _CMD_VTYPE_SCSI) - -/* - * Used to create cmds.. -*/ -#define _CMDCF(dir, flags, vtype, nr) \ - (((dir) << _CMD_DIRSHIFT) | \ - ((flags) << _CMD_FLAGSSHIFT) | \ - ((vtype) << _CMD_VTYPESHIFT) | \ - ((nr) << _CMD_NSHIFT)) -#define _CMDC(dir, vtype, nr) _CMDCF(dir, 0, vtype, nr) -#define _CMDCNW(dir, vtype, nr) _CMDCF(dir, _CMD_FLAGS_NOWAIT, vtype, nr) - -/* - * Used to decode cmds.. -*/ -#define _CMD_DIR(cmd) (((cmd) >> _CMD_DIRSHIFT) & _CMD_DIRMASK) -#define _CMD_FLAGS(cmd) (((cmd) >> _CMD_FLAGSSHIFT) & _CMD_FLAGSMASK) -#define _CMD_VTYPE(cmd) (((cmd) >> _CMD_VTYPESHIFT) & _CMD_VTYPEMASK) -#define _CMD_N(cmd) (((cmd) >> _CMD_NSHIFT) & _CMD_NMASK) - -enum vnic_devcmd_cmd { - CMD_NONE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_NONE, 0), - - /* mcpu fw info in mem: (u64)a0=paddr to struct vnic_devcmd_fw_info */ - CMD_MCPU_FW_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 1), - - /* dev-specific block member: - * in: (u16)a0=offset,(u8)a1=size - * out: a0=value */ - CMD_DEV_SPEC = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 2), - - /* stats clear */ - CMD_STATS_CLEAR = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 3), - - /* stats dump in mem: (u64)a0=paddr to stats area, - * (u16)a1=sizeof stats area */ - CMD_STATS_DUMP = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 4), - - /* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */ - CMD_PACKET_FILTER = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 7), - - /* hang detection notification */ - CMD_HANG_NOTIFY = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8), - - /* MAC address in (u48)a0 */ - CMD_MAC_ADDR = _CMDC(_CMD_DIR_READ, - _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9), - - /* disable/enable promisc mode: (u8)a0=0/1 */ -/***** XXX DEPRECATED *****/ - CMD_PROMISC_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 10), - - /* disable/enable all-multi mode: (u8)a0=0/1 */ -/***** XXX DEPRECATED *****/ - CMD_ALLMULTI_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 11), - - /* add addr from (u48)a0 */ - CMD_ADDR_ADD = _CMDCNW(_CMD_DIR_WRITE, - _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 12), - - /* del addr from (u48)a0 */ - CMD_ADDR_DEL = _CMDCNW(_CMD_DIR_WRITE, - _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 13), - - /* add VLAN id in (u16)a0 */ - CMD_VLAN_ADD = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 14), - - /* del VLAN id in (u16)a0 */ - CMD_VLAN_DEL = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 15), - - /* nic_cfg in (u32)a0 */ - CMD_NIC_CFG = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 16), - - /* union vnic_rss_key in mem: (u64)a0=paddr, (u16)a1=len */ - CMD_RSS_KEY = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 17), - - /* union vnic_rss_cpu in mem: (u64)a0=paddr, (u16)a1=len */ - CMD_RSS_CPU = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 18), - - /* initiate softreset */ - CMD_SOFT_RESET = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 19), - - /* softreset status: - * out: a0=0 reset complete, a0=1 reset in progress */ - CMD_SOFT_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 20), - - /* set struct vnic_devcmd_notify buffer in mem: - * in: - * (u64)a0=paddr to notify (set paddr=0 to unset) - * (u32)a1 & 0x00000000ffffffff=sizeof(struct vnic_devcmd_notify) - * (u16)a1 & 0x0000ffff00000000=intr num (-1 for no intr) - * out: - * (u32)a1 = effective size - */ - CMD_NOTIFY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 21), - - /* UNDI API: (u64)a0=paddr to s_PXENV_UNDI_ struct, - * (u8)a1=PXENV_UNDI_xxx */ - CMD_UNDI = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 22), - - /* initiate open sequence (u32)a0=flags (see CMD_OPENF_*) */ - CMD_OPEN = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 23), - - /* open status: - * out: a0=0 open complete, a0=1 open in progress */ - CMD_OPEN_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 24), - - /* close vnic */ - CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25), - - /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ - CMD_INIT = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), - - /* variant of CMD_INIT, with provisioning info - * (u64)a0=paddr of vnic_devcmd_provinfo - * (u32)a1=sizeof provision info */ - CMD_INIT_PROV_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 27), - - /* enable virtual link */ - CMD_ENABLE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28), - - /* disable virtual link */ - CMD_DISABLE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29), - - /* stats dump all vnics on uplink in mem: (u64)a0=paddr (u32)a1=uif */ - CMD_STATS_DUMP_ALL = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 30), - - /* init status: - * out: a0=0 init complete, a0=1 init in progress - * if a0=0, a1=errno */ - CMD_INIT_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 31), - - /* INT13 API: (u64)a0=paddr to vnic_int13_params struct - * (u8)a1=INT13_CMD_xxx */ - CMD_INT13 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_FC, 32), - - /* logical uplink enable/disable: (u64)a0: 0/1=disable/enable */ - CMD_LOGICAL_UPLINK = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 33), - - /* undo initialize of virtual link */ - CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34), -}; - -/* flags for CMD_OPEN */ -#define CMD_OPENF_OPROM 0x1 /* open coming from option rom */ - -/* flags for CMD_INIT */ -#define CMD_INITF_DEFAULT_MAC 0x1 /* init with default mac addr */ - -/* flags for CMD_PACKET_FILTER */ -#define CMD_PFILTER_DIRECTED 0x01 -#define CMD_PFILTER_MULTICAST 0x02 -#define CMD_PFILTER_BROADCAST 0x04 -#define CMD_PFILTER_PROMISCUOUS 0x08 -#define CMD_PFILTER_ALL_MULTICAST 0x10 - -enum vnic_devcmd_status { - STAT_NONE = 0, - STAT_BUSY = 1 << 0, /* cmd in progress */ - STAT_ERROR = 1 << 1, /* last cmd caused error (code in a0) */ -}; - -enum vnic_devcmd_error { - ERR_SUCCESS = 0, - ERR_EINVAL = 1, - ERR_EFAULT = 2, - ERR_EPERM = 3, - ERR_EBUSY = 4, - ERR_ECMDUNKNOWN = 5, - ERR_EBADSTATE = 6, - ERR_ENOMEM = 7, - ERR_ETIMEDOUT = 8, - ERR_ELINKDOWN = 9, -}; - -struct vnic_devcmd_fw_info { - char fw_version[32]; - char fw_build[32]; - char hw_version[32]; - char hw_serial_number[32]; -}; - -struct vnic_devcmd_notify { - u32 csum; /* checksum over following words */ - - u32 link_state; /* link up == 1 */ - u32 port_speed; /* effective port speed (rate limit) */ - u32 mtu; /* MTU */ - u32 msglvl; /* requested driver msg lvl */ - u32 uif; /* uplink interface */ - u32 status; /* status bits (see VNIC_STF_*) */ - u32 error; /* error code (see ERR_*) for first ERR */ - u32 link_down_cnt; /* running count of link down transitions */ -}; -#define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */ - -struct vnic_devcmd_provinfo { - u8 oui[3]; - u8 type; - u8 data[0]; -}; - -/* - * Writing cmd register causes STAT_BUSY to get set in status register. - * When cmd completes, STAT_BUSY will be cleared. - * - * If cmd completed successfully STAT_ERROR will be clear - * and args registers contain cmd-specific results. - * - * If cmd error, STAT_ERROR will be set and args[0] contains error code. - * - * status register is read-only. While STAT_BUSY is set, - * all other register contents are read-only. - */ - -/* Make sizeof(vnic_devcmd) a power-of-2 for I/O BAR. */ -#define VNIC_DEVCMD_NARGS 15 -struct vnic_devcmd { - u32 status; /* RO */ - u32 cmd; /* RW */ - u64 args[VNIC_DEVCMD_NARGS]; /* RW cmd args (little-endian) */ -}; - -#endif /* _VNIC_DEVCMD_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.c b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.c deleted file mode 100644 index 4f4dc879..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include "vnic_dev.h" -#include "vnic_intr.h" - -void vnic_intr_free(struct vnic_intr *intr) -{ - intr->ctrl = NULL; -} - -int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, - unsigned int index) -{ - intr->index = index; - intr->vdev = vdev; - - intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index); - if (!intr->ctrl) { - printk(KERN_ERR "Failed to hook INTR[%d].ctrl resource\n", - index); - return -EINVAL; - } - - return 0; -} - -void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, - unsigned int coalescing_type, unsigned int mask_on_assertion) -{ - iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); - iowrite32(coalescing_type, &intr->ctrl->coalescing_type); - iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion); - iowrite32(0, &intr->ctrl->int_credits); -} - -void vnic_intr_clean(struct vnic_intr *intr) -{ - iowrite32(0, &intr->ctrl->int_credits); -} diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.h deleted file mode 100644 index d5fb40e7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_intr.h +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_INTR_H_ -#define _VNIC_INTR_H_ - -#include -#include "vnic_dev.h" - -/* - * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth - * Driver) when both are built with CONFIG options =y - */ -#define vnic_intr_unmask fnic_intr_unmask -#define vnic_intr_mask fnic_intr_mask -#define vnic_intr_return_credits fnic_intr_return_credits -#define vnic_intr_credits fnic_intr_credits -#define vnic_intr_return_all_credits fnic_intr_return_all_credits -#define vnic_intr_legacy_pba fnic_intr_legacy_pba -#define vnic_intr_free fnic_intr_free -#define vnic_intr_alloc fnic_intr_alloc -#define vnic_intr_init fnic_intr_init -#define vnic_intr_clean fnic_intr_clean - -#define VNIC_INTR_TIMER_MAX 0xffff - -#define VNIC_INTR_TIMER_TYPE_ABS 0 -#define VNIC_INTR_TIMER_TYPE_QUIET 1 - -/* Interrupt control */ -struct vnic_intr_ctrl { - u32 coalescing_timer; /* 0x00 */ - u32 pad0; - u32 coalescing_value; /* 0x08 */ - u32 pad1; - u32 coalescing_type; /* 0x10 */ - u32 pad2; - u32 mask_on_assertion; /* 0x18 */ - u32 pad3; - u32 mask; /* 0x20 */ - u32 pad4; - u32 int_credits; /* 0x28 */ - u32 pad5; - u32 int_credit_return; /* 0x30 */ - u32 pad6; -}; - -struct vnic_intr { - unsigned int index; - struct vnic_dev *vdev; - struct vnic_intr_ctrl __iomem *ctrl; /* memory-mapped */ -}; - -static inline void vnic_intr_unmask(struct vnic_intr *intr) -{ - iowrite32(0, &intr->ctrl->mask); -} - -static inline void vnic_intr_mask(struct vnic_intr *intr) -{ - iowrite32(1, &intr->ctrl->mask); -} - -static inline void vnic_intr_return_credits(struct vnic_intr *intr, - unsigned int credits, int unmask, int reset_timer) -{ -#define VNIC_INTR_UNMASK_SHIFT 16 -#define VNIC_INTR_RESET_TIMER_SHIFT 17 - - u32 int_credit_return = (credits & 0xffff) | - (unmask ? (1 << VNIC_INTR_UNMASK_SHIFT) : 0) | - (reset_timer ? (1 << VNIC_INTR_RESET_TIMER_SHIFT) : 0); - - iowrite32(int_credit_return, &intr->ctrl->int_credit_return); -} - -static inline unsigned int vnic_intr_credits(struct vnic_intr *intr) -{ - return ioread32(&intr->ctrl->int_credits); -} - -static inline void vnic_intr_return_all_credits(struct vnic_intr *intr) -{ - unsigned int credits = vnic_intr_credits(intr); - int unmask = 1; - int reset_timer = 1; - - vnic_intr_return_credits(intr, credits, unmask, reset_timer); -} - -static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba) -{ - /* read PBA without clearing */ - return ioread32(legacy_pba); -} - -void vnic_intr_free(struct vnic_intr *intr); -int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, - unsigned int index); -void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, - unsigned int coalescing_type, unsigned int mask_on_assertion); -void vnic_intr_clean(struct vnic_intr *intr); - -#endif /* _VNIC_INTR_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_nic.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_nic.h deleted file mode 100644 index f15b83ee..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_nic.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_NIC_H_ -#define _VNIC_NIC_H_ - -/* - * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth - * Driver) when both are built with CONFIG options =y - */ -#define vnic_set_nic_cfg fnic_set_nic_cfg - -#define NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD 0xffUL -#define NIC_CFG_RSS_DEFAULT_CPU_SHIFT 0 -#define NIC_CFG_RSS_HASH_TYPE (0xffUL << 8) -#define NIC_CFG_RSS_HASH_TYPE_MASK_FIELD 0xffUL -#define NIC_CFG_RSS_HASH_TYPE_SHIFT 8 -#define NIC_CFG_RSS_HASH_BITS (7UL << 16) -#define NIC_CFG_RSS_HASH_BITS_MASK_FIELD 7UL -#define NIC_CFG_RSS_HASH_BITS_SHIFT 16 -#define NIC_CFG_RSS_BASE_CPU (7UL << 19) -#define NIC_CFG_RSS_BASE_CPU_MASK_FIELD 7UL -#define NIC_CFG_RSS_BASE_CPU_SHIFT 19 -#define NIC_CFG_RSS_ENABLE (1UL << 22) -#define NIC_CFG_RSS_ENABLE_MASK_FIELD 1UL -#define NIC_CFG_RSS_ENABLE_SHIFT 22 -#define NIC_CFG_TSO_IPID_SPLIT_EN (1UL << 23) -#define NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD 1UL -#define NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT 23 -#define NIC_CFG_IG_VLAN_STRIP_EN (1UL << 24) -#define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL -#define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24 - -static inline void vnic_set_nic_cfg(u32 *nic_cfg, - u8 rss_default_cpu, u8 rss_hash_type, - u8 rss_hash_bits, u8 rss_base_cpu, - u8 rss_enable, u8 tso_ipid_split_en, - u8 ig_vlan_strip_en) -{ - *nic_cfg = (rss_default_cpu & NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD) | - ((rss_hash_type & NIC_CFG_RSS_HASH_TYPE_MASK_FIELD) - << NIC_CFG_RSS_HASH_TYPE_SHIFT) | - ((rss_hash_bits & NIC_CFG_RSS_HASH_BITS_MASK_FIELD) - << NIC_CFG_RSS_HASH_BITS_SHIFT) | - ((rss_base_cpu & NIC_CFG_RSS_BASE_CPU_MASK_FIELD) - << NIC_CFG_RSS_BASE_CPU_SHIFT) | - ((rss_enable & NIC_CFG_RSS_ENABLE_MASK_FIELD) - << NIC_CFG_RSS_ENABLE_SHIFT) | - ((tso_ipid_split_en & NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD) - << NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT) | - ((ig_vlan_strip_en & NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD) - << NIC_CFG_IG_VLAN_STRIP_EN_SHIFT); -} - -#endif /* _VNIC_NIC_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_resource.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_resource.h deleted file mode 100644 index 2d842f79..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_resource.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_RESOURCE_H_ -#define _VNIC_RESOURCE_H_ - -#define VNIC_RES_MAGIC 0x766E6963L /* 'vnic' */ -#define VNIC_RES_VERSION 0x00000000L - -/* vNIC resource types */ -enum vnic_res_type { - RES_TYPE_EOL, /* End-of-list */ - RES_TYPE_WQ, /* Work queues */ - RES_TYPE_RQ, /* Receive queues */ - RES_TYPE_CQ, /* Completion queues */ - RES_TYPE_RSVD1, - RES_TYPE_NIC_CFG, /* Enet NIC config registers */ - RES_TYPE_RSVD2, - RES_TYPE_RSVD3, - RES_TYPE_RSVD4, - RES_TYPE_RSVD5, - RES_TYPE_INTR_CTRL, /* Interrupt ctrl table */ - RES_TYPE_INTR_TABLE, /* MSI/MSI-X Interrupt table */ - RES_TYPE_INTR_PBA, /* MSI/MSI-X PBA table */ - RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status */ - RES_TYPE_RSVD6, - RES_TYPE_RSVD7, - RES_TYPE_DEVCMD, /* Device command region */ - RES_TYPE_PASS_THRU_PAGE, /* Pass-thru page */ - - RES_TYPE_MAX, /* Count of resource types */ -}; - -struct vnic_resource_header { - u32 magic; - u32 version; -}; - -struct vnic_resource { - u8 type; - u8 bar; - u8 pad[2]; - u32 bar_offset; - u32 count; -}; - -#endif /* _VNIC_RESOURCE_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.c b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.c deleted file mode 100644 index fd2068f5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include "vnic_dev.h" -#include "vnic_rq.h" - -static int vnic_rq_alloc_bufs(struct vnic_rq *rq) -{ - struct vnic_rq_buf *buf; - struct vnic_dev *vdev; - unsigned int i, j, count = rq->ring.desc_count; - unsigned int blks = VNIC_RQ_BUF_BLKS_NEEDED(count); - - vdev = rq->vdev; - - for (i = 0; i < blks; i++) { - rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ, GFP_ATOMIC); - if (!rq->bufs[i]) { - printk(KERN_ERR "Failed to alloc rq_bufs\n"); - return -ENOMEM; - } - } - - for (i = 0; i < blks; i++) { - buf = rq->bufs[i]; - for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES; j++) { - buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES + j; - buf->desc = (u8 *)rq->ring.descs + - rq->ring.desc_size * buf->index; - if (buf->index + 1 == count) { - buf->next = rq->bufs[0]; - break; - } else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES) { - buf->next = rq->bufs[i + 1]; - } else { - buf->next = buf + 1; - buf++; - } - } - } - - rq->to_use = rq->to_clean = rq->bufs[0]; - rq->buf_index = 0; - - return 0; -} - -void vnic_rq_free(struct vnic_rq *rq) -{ - struct vnic_dev *vdev; - unsigned int i; - - vdev = rq->vdev; - - vnic_dev_free_desc_ring(vdev, &rq->ring); - - for (i = 0; i < VNIC_RQ_BUF_BLKS_MAX; i++) { - kfree(rq->bufs[i]); - rq->bufs[i] = NULL; - } - - rq->ctrl = NULL; -} - -int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, - unsigned int desc_count, unsigned int desc_size) -{ - int err; - - rq->index = index; - rq->vdev = vdev; - - rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index); - if (!rq->ctrl) { - printk(KERN_ERR "Failed to hook RQ[%d] resource\n", index); - return -EINVAL; - } - - vnic_rq_disable(rq); - - err = vnic_dev_alloc_desc_ring(vdev, &rq->ring, desc_count, desc_size); - if (err) - return err; - - err = vnic_rq_alloc_bufs(rq); - if (err) { - vnic_rq_free(rq); - return err; - } - - return 0; -} - -void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, - unsigned int error_interrupt_enable, - unsigned int error_interrupt_offset) -{ - u64 paddr; - u32 fetch_index; - - paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET; - writeq(paddr, &rq->ctrl->ring_base); - iowrite32(rq->ring.desc_count, &rq->ctrl->ring_size); - iowrite32(cq_index, &rq->ctrl->cq_index); - iowrite32(error_interrupt_enable, &rq->ctrl->error_interrupt_enable); - iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset); - iowrite32(0, &rq->ctrl->dropped_packet_count); - iowrite32(0, &rq->ctrl->error_status); - - /* Use current fetch_index as the ring starting point */ - fetch_index = ioread32(&rq->ctrl->fetch_index); - rq->to_use = rq->to_clean = - &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES] - [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; - iowrite32(fetch_index, &rq->ctrl->posted_index); - - rq->buf_index = 0; -} - -unsigned int vnic_rq_error_status(struct vnic_rq *rq) -{ - return ioread32(&rq->ctrl->error_status); -} - -void vnic_rq_enable(struct vnic_rq *rq) -{ - iowrite32(1, &rq->ctrl->enable); -} - -int vnic_rq_disable(struct vnic_rq *rq) -{ - unsigned int wait; - - iowrite32(0, &rq->ctrl->enable); - - /* Wait for HW to ACK disable request */ - for (wait = 0; wait < 100; wait++) { - if (!(ioread32(&rq->ctrl->running))) - return 0; - udelay(1); - } - - printk(KERN_ERR "Failed to disable RQ[%d]\n", rq->index); - - return -ETIMEDOUT; -} - -void vnic_rq_clean(struct vnic_rq *rq, - void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf)) -{ - struct vnic_rq_buf *buf; - u32 fetch_index; - - BUG_ON(ioread32(&rq->ctrl->enable)); - - buf = rq->to_clean; - - while (vnic_rq_desc_used(rq) > 0) { - - (*buf_clean)(rq, buf); - - buf = rq->to_clean = buf->next; - rq->ring.desc_avail++; - } - - /* Use current fetch_index as the ring starting point */ - fetch_index = ioread32(&rq->ctrl->fetch_index); - rq->to_use = rq->to_clean = - &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES] - [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; - iowrite32(fetch_index, &rq->ctrl->posted_index); - - rq->buf_index = 0; - - vnic_dev_clear_desc_ring(&rq->ring); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.h deleted file mode 100644 index aebdfbd6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_rq.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_RQ_H_ -#define _VNIC_RQ_H_ - -#include -#include "vnic_dev.h" -#include "vnic_cq.h" - -/* - * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth - * Driver) when both are built with CONFIG options =y - */ -#define vnic_rq_desc_avail fnic_rq_desc_avail -#define vnic_rq_desc_used fnic_rq_desc_used -#define vnic_rq_next_desc fnic_rq_next_desc -#define vnic_rq_next_index fnic_rq_next_index -#define vnic_rq_next_buf_index fnic_rq_next_buf_index -#define vnic_rq_post fnic_rq_post -#define vnic_rq_posting_soon fnic_rq_posting_soon -#define vnic_rq_return_descs fnic_rq_return_descs -#define vnic_rq_service fnic_rq_service -#define vnic_rq_fill fnic_rq_fill -#define vnic_rq_free fnic_rq_free -#define vnic_rq_alloc fnic_rq_alloc -#define vnic_rq_init fnic_rq_init -#define vnic_rq_error_status fnic_rq_error_status -#define vnic_rq_enable fnic_rq_enable -#define vnic_rq_disable fnic_rq_disable -#define vnic_rq_clean fnic_rq_clean - -/* Receive queue control */ -struct vnic_rq_ctrl { - u64 ring_base; /* 0x00 */ - u32 ring_size; /* 0x08 */ - u32 pad0; - u32 posted_index; /* 0x10 */ - u32 pad1; - u32 cq_index; /* 0x18 */ - u32 pad2; - u32 enable; /* 0x20 */ - u32 pad3; - u32 running; /* 0x28 */ - u32 pad4; - u32 fetch_index; /* 0x30 */ - u32 pad5; - u32 error_interrupt_enable; /* 0x38 */ - u32 pad6; - u32 error_interrupt_offset; /* 0x40 */ - u32 pad7; - u32 error_status; /* 0x48 */ - u32 pad8; - u32 dropped_packet_count; /* 0x50 */ - u32 pad9; - u32 dropped_packet_count_rc; /* 0x58 */ - u32 pad10; -}; - -/* Break the vnic_rq_buf allocations into blocks of 64 entries */ -#define VNIC_RQ_BUF_BLK_ENTRIES 64 -#define VNIC_RQ_BUF_BLK_SZ \ - (VNIC_RQ_BUF_BLK_ENTRIES * sizeof(struct vnic_rq_buf)) -#define VNIC_RQ_BUF_BLKS_NEEDED(entries) \ - DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES) -#define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096) - -struct vnic_rq_buf { - struct vnic_rq_buf *next; - dma_addr_t dma_addr; - void *os_buf; - unsigned int os_buf_index; - unsigned int len; - unsigned int index; - void *desc; -}; - -struct vnic_rq { - unsigned int index; - struct vnic_dev *vdev; - struct vnic_rq_ctrl __iomem *ctrl; /* memory-mapped */ - struct vnic_dev_ring ring; - struct vnic_rq_buf *bufs[VNIC_RQ_BUF_BLKS_MAX]; - struct vnic_rq_buf *to_use; - struct vnic_rq_buf *to_clean; - void *os_buf_head; - unsigned int buf_index; - unsigned int pkts_outstanding; -}; - -static inline unsigned int vnic_rq_desc_avail(struct vnic_rq *rq) -{ - /* how many does SW own? */ - return rq->ring.desc_avail; -} - -static inline unsigned int vnic_rq_desc_used(struct vnic_rq *rq) -{ - /* how many does HW own? */ - return rq->ring.desc_count - rq->ring.desc_avail - 1; -} - -static inline void *vnic_rq_next_desc(struct vnic_rq *rq) -{ - return rq->to_use->desc; -} - -static inline unsigned int vnic_rq_next_index(struct vnic_rq *rq) -{ - return rq->to_use->index; -} - -static inline unsigned int vnic_rq_next_buf_index(struct vnic_rq *rq) -{ - return rq->buf_index++; -} - -static inline void vnic_rq_post(struct vnic_rq *rq, - void *os_buf, unsigned int os_buf_index, - dma_addr_t dma_addr, unsigned int len) -{ - struct vnic_rq_buf *buf = rq->to_use; - - buf->os_buf = os_buf; - buf->os_buf_index = os_buf_index; - buf->dma_addr = dma_addr; - buf->len = len; - - buf = buf->next; - rq->to_use = buf; - rq->ring.desc_avail--; - - /* Move the posted_index every nth descriptor - */ - -#ifndef VNIC_RQ_RETURN_RATE -#define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */ -#endif - - if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) { - /* Adding write memory barrier prevents compiler and/or CPU - * reordering, thus avoiding descriptor posting before - * descriptor is initialized. Otherwise, hardware can read - * stale descriptor fields. - */ - wmb(); - iowrite32(buf->index, &rq->ctrl->posted_index); - } -} - -static inline int vnic_rq_posting_soon(struct vnic_rq *rq) -{ - return (rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0; -} - -static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) -{ - rq->ring.desc_avail += count; -} - -enum desc_return_options { - VNIC_RQ_RETURN_DESC, - VNIC_RQ_DEFER_RETURN_DESC, -}; - -static inline void vnic_rq_service(struct vnic_rq *rq, - struct cq_desc *cq_desc, u16 completed_index, - int desc_return, void (*buf_service)(struct vnic_rq *rq, - struct cq_desc *cq_desc, struct vnic_rq_buf *buf, - int skipped, void *opaque), void *opaque) -{ - struct vnic_rq_buf *buf; - int skipped; - - buf = rq->to_clean; - while (1) { - - skipped = (buf->index != completed_index); - - (*buf_service)(rq, cq_desc, buf, skipped, opaque); - - if (desc_return == VNIC_RQ_RETURN_DESC) - rq->ring.desc_avail++; - - rq->to_clean = buf->next; - - if (!skipped) - break; - - buf = rq->to_clean; - } -} - -static inline int vnic_rq_fill(struct vnic_rq *rq, - int (*buf_fill)(struct vnic_rq *rq)) -{ - int err; - - while (vnic_rq_desc_avail(rq) > 1) { - - err = (*buf_fill)(rq); - if (err) - return err; - } - - return 0; -} - -void vnic_rq_free(struct vnic_rq *rq); -int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, - unsigned int desc_count, unsigned int desc_size); -void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, - unsigned int error_interrupt_enable, - unsigned int error_interrupt_offset); -unsigned int vnic_rq_error_status(struct vnic_rq *rq); -void vnic_rq_enable(struct vnic_rq *rq); -int vnic_rq_disable(struct vnic_rq *rq); -void vnic_rq_clean(struct vnic_rq *rq, - void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf)); - -#endif /* _VNIC_RQ_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_scsi.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_scsi.h deleted file mode 100644 index fbb55364..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_scsi.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_SCSI_H_ -#define _VNIC_SCSI_H_ - -#define VNIC_FNIC_WQ_COPY_COUNT_MIN 1 -#define VNIC_FNIC_WQ_COPY_COUNT_MAX 1 - -#define VNIC_FNIC_WQ_DESCS_MIN 64 -#define VNIC_FNIC_WQ_DESCS_MAX 128 - -#define VNIC_FNIC_WQ_COPY_DESCS_MIN 64 -#define VNIC_FNIC_WQ_COPY_DESCS_MAX 512 - -#define VNIC_FNIC_RQ_DESCS_MIN 64 -#define VNIC_FNIC_RQ_DESCS_MAX 128 - -#define VNIC_FNIC_EDTOV_MIN 1000 -#define VNIC_FNIC_EDTOV_MAX 255000 -#define VNIC_FNIC_EDTOV_DEF 2000 - -#define VNIC_FNIC_RATOV_MIN 1000 -#define VNIC_FNIC_RATOV_MAX 255000 - -#define VNIC_FNIC_MAXDATAFIELDSIZE_MIN 256 -#define VNIC_FNIC_MAXDATAFIELDSIZE_MAX 2112 - -#define VNIC_FNIC_FLOGI_RETRIES_MIN 0 -#define VNIC_FNIC_FLOGI_RETRIES_MAX 0xffffffff -#define VNIC_FNIC_FLOGI_RETRIES_DEF 0xffffffff - -#define VNIC_FNIC_FLOGI_TIMEOUT_MIN 1000 -#define VNIC_FNIC_FLOGI_TIMEOUT_MAX 255000 - -#define VNIC_FNIC_PLOGI_RETRIES_MIN 0 -#define VNIC_FNIC_PLOGI_RETRIES_MAX 255 -#define VNIC_FNIC_PLOGI_RETRIES_DEF 8 - -#define VNIC_FNIC_PLOGI_TIMEOUT_MIN 1000 -#define VNIC_FNIC_PLOGI_TIMEOUT_MAX 255000 - -#define VNIC_FNIC_IO_THROTTLE_COUNT_MIN 256 -#define VNIC_FNIC_IO_THROTTLE_COUNT_MAX 4096 - -#define VNIC_FNIC_LINK_DOWN_TIMEOUT_MIN 0 -#define VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX 240000 - -#define VNIC_FNIC_PORT_DOWN_TIMEOUT_MIN 0 -#define VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX 240000 - -#define VNIC_FNIC_PORT_DOWN_IO_RETRIES_MIN 0 -#define VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX 255 - -#define VNIC_FNIC_LUNS_PER_TARGET_MIN 1 -#define VNIC_FNIC_LUNS_PER_TARGET_MAX 1024 - -/* Device-specific region: scsi configuration */ -struct vnic_fc_config { - u64 node_wwn; - u64 port_wwn; - u32 flags; - u32 wq_enet_desc_count; - u32 wq_copy_desc_count; - u32 rq_desc_count; - u32 flogi_retries; - u32 flogi_timeout; - u32 plogi_retries; - u32 plogi_timeout; - u32 io_throttle_count; - u32 link_down_timeout; - u32 port_down_timeout; - u32 port_down_io_retries; - u32 luns_per_tgt; - u16 maxdatafieldsize; - u16 ed_tov; - u16 ra_tov; - u16 intr_timer; - u8 intr_timer_type; -}; - -#define VFCF_FCP_SEQ_LVL_ERR 0x1 /* Enable FCP-2 Error Recovery */ -#define VFCF_PERBI 0x2 /* persistent binding info available */ -#define VFCF_FIP_CAPABLE 0x4 /* firmware can handle FIP */ - -#endif /* _VNIC_SCSI_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_stats.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_stats.h deleted file mode 100644 index 5372e23c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_stats.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_STATS_H_ -#define _VNIC_STATS_H_ - -/* Tx statistics */ -struct vnic_tx_stats { - u64 tx_frames_ok; - u64 tx_unicast_frames_ok; - u64 tx_multicast_frames_ok; - u64 tx_broadcast_frames_ok; - u64 tx_bytes_ok; - u64 tx_unicast_bytes_ok; - u64 tx_multicast_bytes_ok; - u64 tx_broadcast_bytes_ok; - u64 tx_drops; - u64 tx_errors; - u64 tx_tso; - u64 rsvd[16]; -}; - -/* Rx statistics */ -struct vnic_rx_stats { - u64 rx_frames_ok; - u64 rx_frames_total; - u64 rx_unicast_frames_ok; - u64 rx_multicast_frames_ok; - u64 rx_broadcast_frames_ok; - u64 rx_bytes_ok; - u64 rx_unicast_bytes_ok; - u64 rx_multicast_bytes_ok; - u64 rx_broadcast_bytes_ok; - u64 rx_drop; - u64 rx_no_bufs; - u64 rx_errors; - u64 rx_rss; - u64 rx_crc_errors; - u64 rx_frames_64; - u64 rx_frames_127; - u64 rx_frames_255; - u64 rx_frames_511; - u64 rx_frames_1023; - u64 rx_frames_1518; - u64 rx_frames_to_max; - u64 rsvd[16]; -}; - -struct vnic_stats { - struct vnic_tx_stats tx; - struct vnic_rx_stats rx; -}; - -#endif /* _VNIC_STATS_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.c b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.c deleted file mode 100644 index a4141354..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include "vnic_dev.h" -#include "vnic_wq.h" - -static int vnic_wq_alloc_bufs(struct vnic_wq *wq) -{ - struct vnic_wq_buf *buf; - struct vnic_dev *vdev; - unsigned int i, j, count = wq->ring.desc_count; - unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count); - - vdev = wq->vdev; - - for (i = 0; i < blks; i++) { - wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC); - if (!wq->bufs[i]) { - printk(KERN_ERR "Failed to alloc wq_bufs\n"); - return -ENOMEM; - } - } - - for (i = 0; i < blks; i++) { - buf = wq->bufs[i]; - for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES; j++) { - buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES + j; - buf->desc = (u8 *)wq->ring.descs + - wq->ring.desc_size * buf->index; - if (buf->index + 1 == count) { - buf->next = wq->bufs[0]; - break; - } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES) { - buf->next = wq->bufs[i + 1]; - } else { - buf->next = buf + 1; - buf++; - } - } - } - - wq->to_use = wq->to_clean = wq->bufs[0]; - - return 0; -} - -void vnic_wq_free(struct vnic_wq *wq) -{ - struct vnic_dev *vdev; - unsigned int i; - - vdev = wq->vdev; - - vnic_dev_free_desc_ring(vdev, &wq->ring); - - for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) { - kfree(wq->bufs[i]); - wq->bufs[i] = NULL; - } - - wq->ctrl = NULL; - -} - -int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, - unsigned int desc_count, unsigned int desc_size) -{ - int err; - - wq->index = index; - wq->vdev = vdev; - - wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index); - if (!wq->ctrl) { - printk(KERN_ERR "Failed to hook WQ[%d] resource\n", index); - return -EINVAL; - } - - vnic_wq_disable(wq); - - err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); - if (err) - return err; - - err = vnic_wq_alloc_bufs(wq); - if (err) { - vnic_wq_free(wq); - return err; - } - - return 0; -} - -void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, - unsigned int error_interrupt_enable, - unsigned int error_interrupt_offset) -{ - u64 paddr; - - paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; - writeq(paddr, &wq->ctrl->ring_base); - iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size); - iowrite32(0, &wq->ctrl->fetch_index); - iowrite32(0, &wq->ctrl->posted_index); - iowrite32(cq_index, &wq->ctrl->cq_index); - iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); - iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); - iowrite32(0, &wq->ctrl->error_status); -} - -unsigned int vnic_wq_error_status(struct vnic_wq *wq) -{ - return ioread32(&wq->ctrl->error_status); -} - -void vnic_wq_enable(struct vnic_wq *wq) -{ - iowrite32(1, &wq->ctrl->enable); -} - -int vnic_wq_disable(struct vnic_wq *wq) -{ - unsigned int wait; - - iowrite32(0, &wq->ctrl->enable); - - /* Wait for HW to ACK disable request */ - for (wait = 0; wait < 100; wait++) { - if (!(ioread32(&wq->ctrl->running))) - return 0; - udelay(1); - } - - printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index); - - return -ETIMEDOUT; -} - -void vnic_wq_clean(struct vnic_wq *wq, - void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)) -{ - struct vnic_wq_buf *buf; - - BUG_ON(ioread32(&wq->ctrl->enable)); - - buf = wq->to_clean; - - while (vnic_wq_desc_used(wq) > 0) { - - (*buf_clean)(wq, buf); - - buf = wq->to_clean = buf->next; - wq->ring.desc_avail++; - } - - wq->to_use = wq->to_clean = wq->bufs[0]; - - iowrite32(0, &wq->ctrl->fetch_index); - iowrite32(0, &wq->ctrl->posted_index); - iowrite32(0, &wq->ctrl->error_status); - - vnic_dev_clear_desc_ring(&wq->ring); -} diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.h deleted file mode 100644 index 5cd094f7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_WQ_H_ -#define _VNIC_WQ_H_ - -#include -#include "vnic_dev.h" -#include "vnic_cq.h" - -/* - * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth - * Driver) when both are built with CONFIG options =y - */ -#define vnic_wq_desc_avail fnic_wq_desc_avail -#define vnic_wq_desc_used fnic_wq_desc_used -#define vnic_wq_next_desc fni_cwq_next_desc -#define vnic_wq_post fnic_wq_post -#define vnic_wq_service fnic_wq_service -#define vnic_wq_free fnic_wq_free -#define vnic_wq_alloc fnic_wq_alloc -#define vnic_wq_init fnic_wq_init -#define vnic_wq_error_status fnic_wq_error_status -#define vnic_wq_enable fnic_wq_enable -#define vnic_wq_disable fnic_wq_disable -#define vnic_wq_clean fnic_wq_clean - -/* Work queue control */ -struct vnic_wq_ctrl { - u64 ring_base; /* 0x00 */ - u32 ring_size; /* 0x08 */ - u32 pad0; - u32 posted_index; /* 0x10 */ - u32 pad1; - u32 cq_index; /* 0x18 */ - u32 pad2; - u32 enable; /* 0x20 */ - u32 pad3; - u32 running; /* 0x28 */ - u32 pad4; - u32 fetch_index; /* 0x30 */ - u32 pad5; - u32 dca_value; /* 0x38 */ - u32 pad6; - u32 error_interrupt_enable; /* 0x40 */ - u32 pad7; - u32 error_interrupt_offset; /* 0x48 */ - u32 pad8; - u32 error_status; /* 0x50 */ - u32 pad9; -}; - -struct vnic_wq_buf { - struct vnic_wq_buf *next; - dma_addr_t dma_addr; - void *os_buf; - unsigned int len; - unsigned int index; - int sop; - void *desc; -}; - -/* Break the vnic_wq_buf allocations into blocks of 64 entries */ -#define VNIC_WQ_BUF_BLK_ENTRIES 64 -#define VNIC_WQ_BUF_BLK_SZ \ - (VNIC_WQ_BUF_BLK_ENTRIES * sizeof(struct vnic_wq_buf)) -#define VNIC_WQ_BUF_BLKS_NEEDED(entries) \ - DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES) -#define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096) - -struct vnic_wq { - unsigned int index; - struct vnic_dev *vdev; - struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */ - struct vnic_dev_ring ring; - struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX]; - struct vnic_wq_buf *to_use; - struct vnic_wq_buf *to_clean; - unsigned int pkts_outstanding; -}; - -static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq) -{ - /* how many does SW own? */ - return wq->ring.desc_avail; -} - -static inline unsigned int vnic_wq_desc_used(struct vnic_wq *wq) -{ - /* how many does HW own? */ - return wq->ring.desc_count - wq->ring.desc_avail - 1; -} - -static inline void *vnic_wq_next_desc(struct vnic_wq *wq) -{ - return wq->to_use->desc; -} - -static inline void vnic_wq_post(struct vnic_wq *wq, - void *os_buf, dma_addr_t dma_addr, - unsigned int len, int sop, int eop) -{ - struct vnic_wq_buf *buf = wq->to_use; - - buf->sop = sop; - buf->os_buf = eop ? os_buf : NULL; - buf->dma_addr = dma_addr; - buf->len = len; - - buf = buf->next; - if (eop) { - /* Adding write memory barrier prevents compiler and/or CPU - * reordering, thus avoiding descriptor posting before - * descriptor is initialized. Otherwise, hardware can read - * stale descriptor fields. - */ - wmb(); - iowrite32(buf->index, &wq->ctrl->posted_index); - } - wq->to_use = buf; - - wq->ring.desc_avail--; -} - -static inline void vnic_wq_service(struct vnic_wq *wq, - struct cq_desc *cq_desc, u16 completed_index, - void (*buf_service)(struct vnic_wq *wq, - struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque), - void *opaque) -{ - struct vnic_wq_buf *buf; - - buf = wq->to_clean; - while (1) { - - (*buf_service)(wq, cq_desc, buf, opaque); - - wq->ring.desc_avail++; - - wq->to_clean = buf->next; - - if (buf->index == completed_index) - break; - - buf = wq->to_clean; - } -} - -void vnic_wq_free(struct vnic_wq *wq); -int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, - unsigned int desc_count, unsigned int desc_size); -void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, - unsigned int error_interrupt_enable, - unsigned int error_interrupt_offset); -unsigned int vnic_wq_error_status(struct vnic_wq *wq); -void vnic_wq_enable(struct vnic_wq *wq); -int vnic_wq_disable(struct vnic_wq *wq); -void vnic_wq_clean(struct vnic_wq *wq, - void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)); - -#endif /* _VNIC_WQ_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.c b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.c deleted file mode 100644 index 9eab7e7c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include "vnic_wq_copy.h" - -void vnic_wq_copy_enable(struct vnic_wq_copy *wq) -{ - iowrite32(1, &wq->ctrl->enable); -} - -int vnic_wq_copy_disable(struct vnic_wq_copy *wq) -{ - unsigned int wait; - - iowrite32(0, &wq->ctrl->enable); - - /* Wait for HW to ACK disable request */ - for (wait = 0; wait < 100; wait++) { - if (!(ioread32(&wq->ctrl->running))) - return 0; - udelay(1); - } - - printk(KERN_ERR "Failed to disable Copy WQ[%d]," - " fetch index=%d, posted_index=%d\n", - wq->index, ioread32(&wq->ctrl->fetch_index), - ioread32(&wq->ctrl->posted_index)); - - return -ENODEV; -} - -void vnic_wq_copy_clean(struct vnic_wq_copy *wq, - void (*q_clean)(struct vnic_wq_copy *wq, - struct fcpio_host_req *wq_desc)) -{ - BUG_ON(ioread32(&wq->ctrl->enable)); - - if (vnic_wq_copy_desc_in_use(wq)) - vnic_wq_copy_service(wq, -1, q_clean); - - wq->to_use_index = wq->to_clean_index = 0; - - iowrite32(0, &wq->ctrl->fetch_index); - iowrite32(0, &wq->ctrl->posted_index); - iowrite32(0, &wq->ctrl->error_status); - - vnic_dev_clear_desc_ring(&wq->ring); -} - -void vnic_wq_copy_free(struct vnic_wq_copy *wq) -{ - struct vnic_dev *vdev; - - vdev = wq->vdev; - vnic_dev_free_desc_ring(vdev, &wq->ring); - wq->ctrl = NULL; -} - -int vnic_wq_copy_alloc(struct vnic_dev *vdev, struct vnic_wq_copy *wq, - unsigned int index, unsigned int desc_count, - unsigned int desc_size) -{ - int err; - - wq->index = index; - wq->vdev = vdev; - wq->to_use_index = wq->to_clean_index = 0; - wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index); - if (!wq->ctrl) { - printk(KERN_ERR "Failed to hook COPY WQ[%d] resource\n", index); - return -EINVAL; - } - - vnic_wq_copy_disable(wq); - - err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); - if (err) - return err; - - return 0; -} - -void vnic_wq_copy_init(struct vnic_wq_copy *wq, unsigned int cq_index, - unsigned int error_interrupt_enable, - unsigned int error_interrupt_offset) -{ - u64 paddr; - - paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; - writeq(paddr, &wq->ctrl->ring_base); - iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size); - iowrite32(0, &wq->ctrl->fetch_index); - iowrite32(0, &wq->ctrl->posted_index); - iowrite32(cq_index, &wq->ctrl->cq_index); - iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); - iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.h b/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.h deleted file mode 100644 index 6aff9740..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/vnic_wq_copy.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _VNIC_WQ_COPY_H_ -#define _VNIC_WQ_COPY_H_ - -#include -#include "vnic_wq.h" -#include "fcpio.h" - -#define VNIC_WQ_COPY_MAX 1 - -struct vnic_wq_copy { - unsigned int index; - struct vnic_dev *vdev; - struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */ - struct vnic_dev_ring ring; - unsigned to_use_index; - unsigned to_clean_index; -}; - -static inline unsigned int vnic_wq_copy_desc_avail(struct vnic_wq_copy *wq) -{ - return wq->ring.desc_avail; -} - -static inline unsigned int vnic_wq_copy_desc_in_use(struct vnic_wq_copy *wq) -{ - return wq->ring.desc_count - 1 - wq->ring.desc_avail; -} - -static inline void *vnic_wq_copy_next_desc(struct vnic_wq_copy *wq) -{ - struct fcpio_host_req *desc = wq->ring.descs; - return &desc[wq->to_use_index]; -} - -static inline void vnic_wq_copy_post(struct vnic_wq_copy *wq) -{ - - ((wq->to_use_index + 1) == wq->ring.desc_count) ? - (wq->to_use_index = 0) : (wq->to_use_index++); - wq->ring.desc_avail--; - - /* Adding write memory barrier prevents compiler and/or CPU - * reordering, thus avoiding descriptor posting before - * descriptor is initialized. Otherwise, hardware can read - * stale descriptor fields. - */ - wmb(); - - iowrite32(wq->to_use_index, &wq->ctrl->posted_index); -} - -static inline void vnic_wq_copy_desc_process(struct vnic_wq_copy *wq, u16 index) -{ - unsigned int cnt; - - if (wq->to_clean_index <= index) - cnt = (index - wq->to_clean_index) + 1; - else - cnt = wq->ring.desc_count - wq->to_clean_index + index + 1; - - wq->to_clean_index = ((index + 1) % wq->ring.desc_count); - wq->ring.desc_avail += cnt; - -} - -static inline void vnic_wq_copy_service(struct vnic_wq_copy *wq, - u16 completed_index, - void (*q_service)(struct vnic_wq_copy *wq, - struct fcpio_host_req *wq_desc)) -{ - struct fcpio_host_req *wq_desc = wq->ring.descs; - unsigned int curr_index; - - while (1) { - - if (q_service) - (*q_service)(wq, &wq_desc[wq->to_clean_index]); - - wq->ring.desc_avail++; - - curr_index = wq->to_clean_index; - - /* increment the to-clean index so that we start - * with an unprocessed index next time we enter the loop - */ - ((wq->to_clean_index + 1) == wq->ring.desc_count) ? - (wq->to_clean_index = 0) : (wq->to_clean_index++); - - if (curr_index == completed_index) - break; - - /* we have cleaned all the entries */ - if ((completed_index == (u16)-1) && - (wq->to_clean_index == wq->to_use_index)) - break; - } -} - -void vnic_wq_copy_enable(struct vnic_wq_copy *wq); -int vnic_wq_copy_disable(struct vnic_wq_copy *wq); -void vnic_wq_copy_free(struct vnic_wq_copy *wq); -int vnic_wq_copy_alloc(struct vnic_dev *vdev, struct vnic_wq_copy *wq, - unsigned int index, unsigned int desc_count, unsigned int desc_size); -void vnic_wq_copy_init(struct vnic_wq_copy *wq, unsigned int cq_index, - unsigned int error_interrupt_enable, - unsigned int error_interrupt_offset); -void vnic_wq_copy_clean(struct vnic_wq_copy *wq, - void (*q_clean)(struct vnic_wq_copy *wq, - struct fcpio_host_req *wq_desc)); - -#endif /* _VNIC_WQ_COPY_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/fnic/wq_enet_desc.h b/ANDROID_3.4.5/drivers/scsi/fnic/wq_enet_desc.h deleted file mode 100644 index b121cbad..00000000 --- a/ANDROID_3.4.5/drivers/scsi/fnic/wq_enet_desc.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2008 Cisco Systems, Inc. All rights reserved. - * Copyright 2007 Nuova Systems, Inc. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef _WQ_ENET_DESC_H_ -#define _WQ_ENET_DESC_H_ - -/* Ethernet work queue descriptor: 16B */ -struct wq_enet_desc { - __le64 address; - __le16 length; - __le16 mss_loopback; - __le16 header_length_flags; - __le16 vlan_tag; -}; - -#define WQ_ENET_ADDR_BITS 64 -#define WQ_ENET_LEN_BITS 14 -#define WQ_ENET_LEN_MASK ((1 << WQ_ENET_LEN_BITS) - 1) -#define WQ_ENET_MSS_BITS 14 -#define WQ_ENET_MSS_MASK ((1 << WQ_ENET_MSS_BITS) - 1) -#define WQ_ENET_MSS_SHIFT 2 -#define WQ_ENET_LOOPBACK_SHIFT 1 -#define WQ_ENET_HDRLEN_BITS 10 -#define WQ_ENET_HDRLEN_MASK ((1 << WQ_ENET_HDRLEN_BITS) - 1) -#define WQ_ENET_FLAGS_OM_BITS 2 -#define WQ_ENET_FLAGS_OM_MASK ((1 << WQ_ENET_FLAGS_OM_BITS) - 1) -#define WQ_ENET_FLAGS_EOP_SHIFT 12 -#define WQ_ENET_FLAGS_CQ_ENTRY_SHIFT 13 -#define WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT 14 -#define WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT 15 - -#define WQ_ENET_OFFLOAD_MODE_CSUM 0 -#define WQ_ENET_OFFLOAD_MODE_RESERVED 1 -#define WQ_ENET_OFFLOAD_MODE_CSUM_L4 2 -#define WQ_ENET_OFFLOAD_MODE_TSO 3 - -static inline void wq_enet_desc_enc(struct wq_enet_desc *desc, - u64 address, u16 length, u16 mss, u16 header_length, - u8 offload_mode, u8 eop, u8 cq_entry, u8 fcoe_encap, - u8 vlan_tag_insert, u16 vlan_tag, u8 loopback) -{ - desc->address = cpu_to_le64(address); - desc->length = cpu_to_le16(length & WQ_ENET_LEN_MASK); - desc->mss_loopback = cpu_to_le16((mss & WQ_ENET_MSS_MASK) << - WQ_ENET_MSS_SHIFT | (loopback & 1) << WQ_ENET_LOOPBACK_SHIFT); - desc->header_length_flags = cpu_to_le16( - (header_length & WQ_ENET_HDRLEN_MASK) | - (offload_mode & WQ_ENET_FLAGS_OM_MASK) << WQ_ENET_HDRLEN_BITS | - (eop & 1) << WQ_ENET_FLAGS_EOP_SHIFT | - (cq_entry & 1) << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT | - (fcoe_encap & 1) << WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT | - (vlan_tag_insert & 1) << WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT); - desc->vlan_tag = cpu_to_le16(vlan_tag); -} - -static inline void wq_enet_desc_dec(struct wq_enet_desc *desc, - u64 *address, u16 *length, u16 *mss, u16 *header_length, - u8 *offload_mode, u8 *eop, u8 *cq_entry, u8 *fcoe_encap, - u8 *vlan_tag_insert, u16 *vlan_tag, u8 *loopback) -{ - *address = le64_to_cpu(desc->address); - *length = le16_to_cpu(desc->length) & WQ_ENET_LEN_MASK; - *mss = (le16_to_cpu(desc->mss_loopback) >> WQ_ENET_MSS_SHIFT) & - WQ_ENET_MSS_MASK; - *loopback = (u8)((le16_to_cpu(desc->mss_loopback) >> - WQ_ENET_LOOPBACK_SHIFT) & 1); - *header_length = le16_to_cpu(desc->header_length_flags) & - WQ_ENET_HDRLEN_MASK; - *offload_mode = (u8)((le16_to_cpu(desc->header_length_flags) >> - WQ_ENET_HDRLEN_BITS) & WQ_ENET_FLAGS_OM_MASK); - *eop = (u8)((le16_to_cpu(desc->header_length_flags) >> - WQ_ENET_FLAGS_EOP_SHIFT) & 1); - *cq_entry = (u8)((le16_to_cpu(desc->header_length_flags) >> - WQ_ENET_FLAGS_CQ_ENTRY_SHIFT) & 1); - *fcoe_encap = (u8)((le16_to_cpu(desc->header_length_flags) >> - WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT) & 1); - *vlan_tag_insert = (u8)((le16_to_cpu(desc->header_length_flags) >> - WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT) & 1); - *vlan_tag = le16_to_cpu(desc->vlan_tag); -} - -#endif /* _WQ_ENET_DESC_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/g_NCR5380.c b/ANDROID_3.4.5/drivers/scsi/g_NCR5380.c deleted file mode 100644 index 1a5954f0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/g_NCR5380.c +++ /dev/null @@ -1,956 +0,0 @@ -/* - * Generic Generic NCR5380 driver - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin - * K.Lentin@cs.monash.edu.au - * - * NCR53C400A extensions (c) 1996, Ingmar Baumgart - * ingmar@gonzo.schwaben.de - * - * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg - * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl - * - * Added ISAPNP support for DTC436 adapters, - * Thomas Sailer, sailer@ife.ee.ethz.ch - * - * ALPHA RELEASE 1. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * TODO : flesh out DMA support, find some one actually using this (I have - * a memory mapped Trantor board that works fine) - */ - -/* - * Options : - * - * PARITY - enable parity checking. Not supported. - * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * - * USLEEP - enable support for devices that don't disconnect. Untested. - * - * The card is detected and initialized in one of several ways : - * 1. With command line overrides - NCR5380=port,irq may be - * used on the LILO command line to override the defaults. - * - * 2. With the GENERIC_NCR5380_OVERRIDE compile time define. This is - * specified as an array of address, irq, dma, board tuples. Ie, for - * one board at 0x350, IRQ5, no dma, I could say - * -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE, BOARD_NCR5380}} - * - * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an - * IRQ line if overridden on the command line. - * - * 3. When included as a module, with arguments passed on the command line: - * ncr_irq=xx the interrupt - * ncr_addr=xx the port or base address (for port or memory - * mapped, resp.) - * ncr_dma=xx the DMA - * ncr_5380=1 to set up for a NCR5380 board - * ncr_53c400=1 to set up for a NCR53C400 board - * e.g. - * modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 - * for a port mapped NCR5380 board or - * modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 - * for a memory mapped NCR53C400 board with interrupts disabled. - * - * 255 should be specified for no or DMA interrupt, 254 to autoprobe for an - * IRQ line if overridden on the command line. - * - */ - -/* - * $Log: generic_NCR5380.c,v $ - */ - -/* settings for DTC3181E card with only Mustek scanner attached */ -#define USLEEP -#define USLEEP_POLL 1 -#define USLEEP_SLEEP 20 -#define USLEEP_WAITLONG 500 - -#define AUTOPROBE_IRQ -#define AUTOSENSE - - -#ifdef CONFIG_SCSI_GENERIC_NCR53C400 -#define NCR53C400_PSEUDO_DMA 1 -#define PSEUDO_DMA -#define NCR53C400 -#define NCR5380_STATS -#undef NCR5380_STAT_LIMIT -#endif - -#include -#include -#include -#include "scsi.h" -#include -#include "g_NCR5380.h" -#include "NCR5380.h" -#include -#include -#include -#include -#include -#include - -#define NCR_NOT_SET 0 -static int ncr_irq = NCR_NOT_SET; -static int ncr_dma = NCR_NOT_SET; -static int ncr_addr = NCR_NOT_SET; -static int ncr_5380 = NCR_NOT_SET; -static int ncr_53c400 = NCR_NOT_SET; -static int ncr_53c400a = NCR_NOT_SET; -static int dtc_3181e = NCR_NOT_SET; - -static struct override { - NCR5380_map_type NCR5380_map_name; - int irq; - int dma; - int board; /* Use NCR53c400, Ricoh, etc. extensions ? */ -} overrides -#ifdef GENERIC_NCR5380_OVERRIDE -[] __initdata = GENERIC_NCR5380_OVERRIDE; -#else -[1] __initdata = { { 0,},}; -#endif - -#define NO_OVERRIDES ARRAY_SIZE(overrides) - -#ifndef MODULE - -/** - * internal_setup - handle lilo command string override - * @board: BOARD_* identifier for the board - * @str: unused - * @ints: numeric parameters - * - * Do LILO command line initialization of the overrides array. Display - * errors when needed - * - * Locks: none - */ - -static void __init internal_setup(int board, char *str, int *ints) -{ - static int commandline_current = 0; - switch (board) { - case BOARD_NCR5380: - if (ints[0] != 2 && ints[0] != 3) { - printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n"); - return; - } - break; - case BOARD_NCR53C400: - if (ints[0] != 2) { - printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_NCR53C400A: - if (ints[0] != 2) { - printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - case BOARD_DTC3181E: - if (ints[0] != 2) { - printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n"); - return; - } - break; - } - - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1]; - overrides[commandline_current].irq = ints[2]; - if (ints[0] == 3) - overrides[commandline_current].dma = ints[3]; - else - overrides[commandline_current].dma = DMA_NONE; - overrides[commandline_current].board = board; - ++commandline_current; - } -} - - -/** - * do_NCR53C80_setup - set up entry point - * @str: unused - * - * Setup function invoked at boot to parse the ncr5380= command - * line. - */ - -static int __init do_NCR5380_setup(char *str) -{ - int ints[10]; - - get_options(str, ARRAY_SIZE(ints), ints); - internal_setup(BOARD_NCR5380, str, ints); - return 1; -} - -/** - * do_NCR53C400_setup - set up entry point - * @str: unused - * @ints: integer parameters from kernel setup code - * - * Setup function invoked at boot to parse the ncr53c400= command - * line. - */ - -static int __init do_NCR53C400_setup(char *str) -{ - int ints[10]; - - get_options(str, ARRAY_SIZE(ints), ints); - internal_setup(BOARD_NCR53C400, str, ints); - return 1; -} - -/** - * do_NCR53C400A_setup - set up entry point - * @str: unused - * @ints: integer parameters from kernel setup code - * - * Setup function invoked at boot to parse the ncr53c400a= command - * line. - */ - -static int __init do_NCR53C400A_setup(char *str) -{ - int ints[10]; - - get_options(str, ARRAY_SIZE(ints), ints); - internal_setup(BOARD_NCR53C400A, str, ints); - return 1; -} - -/** - * do_DTC3181E_setup - set up entry point - * @str: unused - * @ints: integer parameters from kernel setup code - * - * Setup function invoked at boot to parse the dtc3181e= command - * line. - */ - -static int __init do_DTC3181E_setup(char *str) -{ - int ints[10]; - - get_options(str, ARRAY_SIZE(ints), ints); - internal_setup(BOARD_DTC3181E, str, ints); - return 1; -} - -#endif - -/** - * generic_NCR5380_detect - look for NCR5380 controllers - * @tpnt: the scsi template - * - * Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E - * and DTC436(ISAPnP) controllers. If overrides have been set we use - * them. - * - * The caller supplied NCR5380_init function is invoked from here, before - * the interrupt line is taken. - * - * Locks: none - */ - -int __init generic_NCR5380_detect(struct scsi_host_template * tpnt) -{ - static int current_override = 0; - int count; - unsigned int *ports; -#ifndef SCSI_G_NCR5380_MEM - int i; - unsigned long region_size = 16; -#endif - static unsigned int __initdata ncr_53c400a_ports[] = { - 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 - }; - static unsigned int __initdata dtc_3181e_ports[] = { - 0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0 - }; - int flags = 0; - struct Scsi_Host *instance; -#ifdef SCSI_G_NCR5380_MEM - unsigned long base; - void __iomem *iomem; -#endif - - if (ncr_irq != NCR_NOT_SET) - overrides[0].irq = ncr_irq; - if (ncr_dma != NCR_NOT_SET) - overrides[0].dma = ncr_dma; - if (ncr_addr != NCR_NOT_SET) - overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr; - if (ncr_5380 != NCR_NOT_SET) - overrides[0].board = BOARD_NCR5380; - else if (ncr_53c400 != NCR_NOT_SET) - overrides[0].board = BOARD_NCR53C400; - else if (ncr_53c400a != NCR_NOT_SET) - overrides[0].board = BOARD_NCR53C400A; - else if (dtc_3181e != NCR_NOT_SET) - overrides[0].board = BOARD_DTC3181E; -#ifndef SCSI_G_NCR5380_MEM - if (!current_override && isapnp_present()) { - struct pnp_dev *dev = NULL; - count = 0; - while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) { - if (count >= NO_OVERRIDES) - break; - if (pnp_device_attach(dev) < 0) - continue; - if (pnp_activate_dev(dev) < 0) { - printk(KERN_ERR "dtc436e probe: activate failed\n"); - pnp_device_detach(dev); - continue; - } - if (!pnp_port_valid(dev, 0)) { - printk(KERN_ERR "dtc436e probe: no valid port\n"); - pnp_device_detach(dev); - continue; - } - if (pnp_irq_valid(dev, 0)) - overrides[count].irq = pnp_irq(dev, 0); - else - overrides[count].irq = SCSI_IRQ_NONE; - if (pnp_dma_valid(dev, 0)) - overrides[count].dma = pnp_dma(dev, 0); - else - overrides[count].dma = DMA_NONE; - overrides[count].NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0); - overrides[count].board = BOARD_DTC3181E; - count++; - } - } -#endif - tpnt->proc_name = "g_NCR5380"; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - if (!(overrides[current_override].NCR5380_map_name)) - continue; - - ports = NULL; - switch (overrides[current_override].board) { - case BOARD_NCR5380: - flags = FLAG_NO_PSEUDO_DMA; - break; - case BOARD_NCR53C400: - flags = FLAG_NCR53C400; - break; - case BOARD_NCR53C400A: - flags = FLAG_NO_PSEUDO_DMA; - ports = ncr_53c400a_ports; - break; - case BOARD_DTC3181E: - flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E; - ports = dtc_3181e_ports; - break; - } - -#ifndef SCSI_G_NCR5380_MEM - if (ports) { - /* wakeup sequence for the NCR53C400A and DTC3181E */ - - /* Disable the adapter and look for a free io port */ - outb(0x59, 0x779); - outb(0xb9, 0x379); - outb(0xc5, 0x379); - outb(0xae, 0x379); - outb(0xa6, 0x379); - outb(0x00, 0x379); - - if (overrides[current_override].NCR5380_map_name != PORT_AUTO) - for (i = 0; ports[i]; i++) { - if (!request_region(ports[i], 16, "ncr53c80")) - continue; - if (overrides[current_override].NCR5380_map_name == ports[i]) - break; - release_region(ports[i], 16); - } else - for (i = 0; ports[i]; i++) { - if (!request_region(ports[i], 16, "ncr53c80")) - continue; - if (inb(ports[i]) == 0xff) - break; - release_region(ports[i], 16); - } - if (ports[i]) { - /* At this point we have our region reserved */ - outb(0x59, 0x779); - outb(0xb9, 0x379); - outb(0xc5, 0x379); - outb(0xae, 0x379); - outb(0xa6, 0x379); - outb(0x80 | i, 0x379); /* set io port to be used */ - outb(0xc0, ports[i] + 9); - if (inb(ports[i] + 9) != 0x80) - continue; - else - overrides[current_override].NCR5380_map_name = ports[i]; - } else - continue; - } - else - { - /* Not a 53C400A style setup - just grab */ - if(!(request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"))) - continue; - region_size = NCR5380_region_size; - } -#else - base = overrides[current_override].NCR5380_map_name; - if (!request_mem_region(base, NCR5380_region_size, "ncr5380")) - continue; - iomem = ioremap(base, NCR5380_region_size); - if (!iomem) { - release_mem_region(base, NCR5380_region_size); - continue; - } -#endif - instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); - if (instance == NULL) { -#ifndef SCSI_G_NCR5380_MEM - release_region(overrides[current_override].NCR5380_map_name, region_size); -#else - iounmap(iomem); - release_mem_region(base, NCR5380_region_size); -#endif - continue; - } - - instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name; -#ifndef SCSI_G_NCR5380_MEM - instance->n_io_port = region_size; -#else - ((struct NCR5380_hostdata *)instance->hostdata)->iomem = iomem; -#endif - - NCR5380_init(instance, flags); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, 0xffff); - - if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, generic_NCR5380_intr, - IRQF_DISABLED, "NCR5380", instance)) { - printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); - instance->irq = SCSI_IRQ_NONE; - } - - if (instance->irq == SCSI_IRQ_NONE) { - printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } - - printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name); - if (instance->irq == SCSI_IRQ_NONE) - printk(" interrupts disabled"); - else - printk(" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; -} - -/** - * generic_NCR5380_info - reporting string - * @host: NCR5380 to report on - * - * Report driver information for the NCR5380 - */ - -const char *generic_NCR5380_info(struct Scsi_Host *host) -{ - static const char string[] = "Generic NCR5380/53C400 Driver"; - return string; -} - -/** - * generic_NCR5380_release_resources - free resources - * @instance: host adapter to clean up - * - * Free the generic interface resources from this adapter. - * - * Locks: none - */ - -int generic_NCR5380_release_resources(struct Scsi_Host *instance) -{ - NCR5380_local_declare(); - NCR5380_setup(instance); - - if (instance->irq != SCSI_IRQ_NONE) - free_irq(instance->irq, instance); - NCR5380_exit(instance); - -#ifndef SCSI_G_NCR5380_MEM - release_region(instance->NCR5380_instance_name, instance->n_io_port); -#else - iounmap(((struct NCR5380_hostdata *)instance->hostdata)->iomem); - release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size); -#endif - - - return 0; -} - -#ifdef BIOSPARAM -/** - * generic_NCR5380_biosparam - * @disk: disk to compute geometry for - * @dev: device identifier for this disk - * @ip: sizes to fill in - * - * Generates a BIOS / DOS compatible H-C-S mapping for the specified - * device / size. - * - * XXX Most SCSI boards use this mapping, I could be incorrect. Someone - * using hard disks on a trantor should verify that this mapping - * corresponds to that used by the BIOS / ASPI driver by running the linux - * fdisk program and matching the H_C_S coordinates to what DOS uses. - * - * Locks: none - */ - -static int -generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int *ip) -{ - ip[0] = 64; - ip[1] = 32; - ip[2] = capacity >> 11; - return 0; -} -#endif - -#ifdef NCR53C400_PSEUDO_DMA - -/** - * NCR5380_pread - pseudo DMA read - * @instance: adapter to read from - * @dst: buffer to read into - * @len: buffer length - * - * Perform a pseudo DMA mode read from an NCR53C400 or equivalent - * controller - */ - -static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len) -{ - int blocks = len / 128; - int start = 0; - int bl; - - NCR5380_local_declare(); - NCR5380_setup(instance); - - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR); - NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); - while (1) { - if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { - break; - } - if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { - printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); - return -1; - } - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY); - -#ifndef SCSI_G_NCR5380_MEM - { - int i; - for (i = 0; i < 128; i++) - dst[start + i] = NCR5380_read(C400_HOST_BUFFER); - } -#else - /* implies SCSI_G_NCR5380_MEM */ - memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128); -#endif - start += 128; - blocks--; - } - - if (blocks) { - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - { - // FIXME - no timeout - } - -#ifndef SCSI_G_NCR5380_MEM - { - int i; - for (i = 0; i < 128; i++) - dst[start + i] = NCR5380_read(C400_HOST_BUFFER); - } -#else - /* implies SCSI_G_NCR5380_MEM */ - memcpy_fromio(dst + start, iomem + NCR53C400_host_buffer, 128); -#endif - start += 128; - blocks--; - } - - if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) - printk("53C400r: no 53C80 gated irq after transfer"); - -#if 0 - /* - * DON'T DO THIS - THEY NEVER ARRIVE! - */ - printk("53C400r: Waiting for 53C80 registers\n"); - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG) - ; -#endif - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) - printk(KERN_ERR "53C400r: no end dma signal\n"); - - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - return 0; -} - -/** - * NCR5380_write - pseudo DMA write - * @instance: adapter to read from - * @dst: buffer to read into - * @len: buffer length - * - * Perform a pseudo DMA mode read from an NCR53C400 or equivalent - * controller - */ - -static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len) -{ - int blocks = len / 128; - int start = 0; - int bl; - int i; - - NCR5380_local_declare(); - NCR5380_setup(instance); - - NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE); - NCR5380_write(C400_BLOCK_COUNTER_REG, blocks); - while (1) { - if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) { - printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks); - return -1; - } - - if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) { - break; - } - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; // FIXME - timeout -#ifndef SCSI_G_NCR5380_MEM - { - for (i = 0; i < 128; i++) - NCR5380_write(C400_HOST_BUFFER, src[start + i]); - } -#else - /* implies SCSI_G_NCR5380_MEM */ - memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128); -#endif - start += 128; - blocks--; - } - if (blocks) { - while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY) - ; // FIXME - no timeout - -#ifndef SCSI_G_NCR5380_MEM - { - for (i = 0; i < 128; i++) - NCR5380_write(C400_HOST_BUFFER, src[start + i]); - } -#else - /* implies SCSI_G_NCR5380_MEM */ - memcpy_toio(iomem + NCR53C400_host_buffer, src + start, 128); -#endif - start += 128; - blocks--; - } - -#if 0 - printk("53C400w: waiting for registers to be available\n"); - THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG); - printk("53C400w: Got em\n"); -#endif - - /* Let's wait for this instead - could be ugly */ - /* All documentation says to check for this. Maybe my hardware is too - * fast. Waiting for it seems to work fine! KLL - */ - while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ)) - ; // FIXME - no timeout - - /* - * I know. i is certainly != 0 here but the loop is new. See previous - * comment. - */ - if (i) { - if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER)) - printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i); - } else - printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n"); - -#if 0 - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) { - printk(KERN_ERR "53C400w: no end dma signal\n"); - } -#endif - while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)) - ; // TIMEOUT - return 0; -} -#endif /* PSEUDO_DMA */ - -/* - * Include the NCR5380 core code that we build our driver around - */ - -#include "NCR5380.c" - -#define PRINTP(x) len += sprintf(buffer+len, x) -#define ANDP , - -static int sprint_opcode(char *buffer, int len, int opcode) -{ - int start = len; - PRINTP("0x%02x " ANDP opcode); - return len - start; -} - -static int sprint_command(char *buffer, int len, unsigned char *command) -{ - int i, s, start = len; - len += sprint_opcode(buffer, len, command[0]); - for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - PRINTP("%02x " ANDP command[i]); - PRINTP("\n"); - return len - start; -} - -/** - * sprintf_Scsi_Cmnd - print a scsi command - * @buffer: buffr to print into - * @len: buffer length - * @cmd: SCSI command block - * - * Print out the target and command data in hex - */ - -static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd) -{ - int start = len; - PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->device->host->host_no ANDP cmd->device->id ANDP cmd->device->lun); - PRINTP(" command = "); - len += sprint_command(buffer, len, cmd->cmnd); - return len - start; -} - -/** - * generic_NCR5380_proc_info - /proc for NCR5380 driver - * @buffer: buffer to print into - * @start: start position - * @offset: offset into buffer - * @len: length - * @hostno: instance to affect - * @inout: read/write - * - * Provide the procfs information for the 5380 controller. We fill - * this with useful debugging information including the commands - * being executed, disconnected command queue and the statistical - * data - * - * Locks: global cli/lock for queue walk - */ - -static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, char **start, off_t offset, int length, int inout) -{ - int len = 0; - NCR5380_local_declare(); - unsigned long flags; - unsigned char status; - int i; - Scsi_Cmnd *ptr; - struct NCR5380_hostdata *hostdata; -#ifdef NCR5380_STATS - struct scsi_device *dev; -#endif - - NCR5380_setup(scsi_ptr); - hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata; - - spin_lock_irqsave(scsi_ptr->host_lock, flags); - PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name); - PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE); - PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE); -#ifdef NCR53C400 - PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE); - PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not"); -# if NCR53C400_PSEUDO_DMA - PRINTP("NCR53C400 pseudo DMA used\n"); -# endif -#else - PRINTP("NO NCR53C400 driver extensions\n"); -#endif - PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name); - if (scsi_ptr->irq == SCSI_IRQ_NONE) - PRINTP("no interrupt\n"); - else - PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq); - -#ifdef NCR5380_STATS - if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue) - PRINTP("There are commands pending, transfer rates may be crud\n"); - if (hostdata->pendingr) - PRINTP(" %d pending reads" ANDP hostdata->pendingr); - if (hostdata->pendingw) - PRINTP(" %d pending writes" ANDP hostdata->pendingw); - if (hostdata->pendingr || hostdata->pendingw) - PRINTP("\n"); - shost_for_each_device(dev, scsi_ptr) { - unsigned long br = hostdata->bytes_read[dev->id]; - unsigned long bw = hostdata->bytes_write[dev->id]; - long tr = hostdata->time_read[dev->id] / HZ; - long tw = hostdata->time_write[dev->id] / HZ; - - PRINTP(" T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type)); - for (i = 0; i < 8; i++) - if (dev->vendor[i] >= 0x20) - *(buffer + (len++)) = dev->vendor[i]; - *(buffer + (len++)) = ' '; - for (i = 0; i < 16; i++) - if (dev->model[i] >= 0x20) - *(buffer + (len++)) = dev->model[i]; - *(buffer + (len++)) = ' '; - for (i = 0; i < 4; i++) - if (dev->rev[i] >= 0x20) - *(buffer + (len++)) = dev->rev[i]; - *(buffer + (len++)) = ' '; - - PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr); - if (tr) - PRINTP(" @ %5ld bps" ANDP br / tr); - - PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw); - if (tw) - PRINTP(" @ %5ld bps" ANDP bw / tw); - PRINTP("\n"); - } -#endif - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - PRINTP("REQ not asserted, phase unknown.\n"); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i); - PRINTP("Phase %s\n" ANDP phases[i].name); - } - - if (!hostdata->connected) { - PRINTP("No currently connected command\n"); - } else { - len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected); - } - - PRINTP("issue_queue\n"); - - for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - len += sprint_Scsi_Cmnd(buffer, len, ptr); - - PRINTP("disconnected_queue\n"); - - for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble) - len += sprint_Scsi_Cmnd(buffer, len, ptr); - - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - spin_unlock_irqrestore(scsi_ptr->host_lock, flags); - return len; -} - -#undef PRINTP -#undef ANDP - -static struct scsi_host_template driver_template = { - .proc_info = generic_NCR5380_proc_info, - .name = "Generic NCR5380/NCR53C400 Scsi Driver", - .detect = generic_NCR5380_detect, - .release = generic_NCR5380_release_resources, - .info = generic_NCR5380_info, - .queuecommand = generic_NCR5380_queue_command, - .eh_abort_handler = generic_NCR5380_abort, - .eh_bus_reset_handler = generic_NCR5380_bus_reset, - .bios_param = NCR5380_BIOSPARAM, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING, -}; -#include -#include "scsi_module.c" - -module_param(ncr_irq, int, 0); -module_param(ncr_dma, int, 0); -module_param(ncr_addr, int, 0); -module_param(ncr_5380, int, 0); -module_param(ncr_53c400, int, 0); -module_param(ncr_53c400a, int, 0); -module_param(dtc_3181e, int, 0); -MODULE_LICENSE("GPL"); - -#ifndef SCSI_G_NCR5380_MEM -static struct isapnp_device_id id_table[] __devinitdata = { - { - ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), - 0}, - {0} -}; - -MODULE_DEVICE_TABLE(isapnp, id_table); -#endif - -__setup("ncr5380=", do_NCR5380_setup); -__setup("ncr53c400=", do_NCR53C400_setup); -__setup("ncr53c400a=", do_NCR53C400A_setup); -__setup("dtc3181e=", do_DTC3181E_setup); diff --git a/ANDROID_3.4.5/drivers/scsi/g_NCR5380.h b/ANDROID_3.4.5/drivers/scsi/g_NCR5380.h deleted file mode 100644 index 1bcdb7be..00000000 --- a/ANDROID_3.4.5/drivers/scsi/g_NCR5380.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Generic Generic NCR5380 driver defines - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin - * K.Lentin@cs.monash.edu.au - * - * ALPHA RELEASE 1. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * $Log: generic_NCR5380.h,v $ - */ - -#ifndef GENERIC_NCR5380_H -#define GENERIC_NCR5380_H - - -#define GENERIC_NCR5380_PUBLIC_RELEASE 1 - -#ifdef NCR53C400 -#define BIOSPARAM -#define NCR5380_BIOSPARAM generic_NCR5380_biosparam -#else -#define NCR5380_BIOSPARAM NULL -#endif - -#ifndef ASM -static int generic_NCR5380_abort(Scsi_Cmnd *); -static int generic_NCR5380_detect(struct scsi_host_template *); -static int generic_NCR5380_release_resources(struct Scsi_Host *); -static int generic_NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static int generic_NCR5380_bus_reset(Scsi_Cmnd *); -static const char* generic_NCR5380_info(struct Scsi_Host *); - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 16 -#endif - -#ifndef HOSTS_C - -#define __STRVAL(x) #x -#define STRVAL(x) __STRVAL(x) - -#ifndef SCSI_G_NCR5380_MEM - -#define NCR5380_map_config port -#define NCR5380_map_type int -#define NCR5380_map_name port -#define NCR5380_instance_name io_port -#define NCR53C400_register_offset 0 -#define NCR53C400_address_adjust 8 - -#ifdef NCR53C400 -#define NCR5380_region_size 16 -#else -#define NCR5380_region_size 8 -#endif - -#define NCR5380_read(reg) (inb(NCR5380_map_name + (reg))) -#define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg)))) - -#define NCR5380_implementation_fields \ - NCR5380_map_type NCR5380_map_name - -#define NCR5380_local_declare() \ - register NCR5380_implementation_fields - -#define NCR5380_setup(instance) \ - NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name) - -#else -/* therefore SCSI_G_NCR5380_MEM */ - -#define NCR5380_map_config memory -#define NCR5380_map_type unsigned long -#define NCR5380_map_name base -#define NCR5380_instance_name base -#define NCR53C400_register_offset 0x108 -#define NCR53C400_address_adjust 0 -#define NCR53C400_mem_base 0x3880 -#define NCR53C400_host_buffer 0x3900 -#define NCR5380_region_size 0x3a00 - -#define NCR5380_read(reg) readb(iomem + NCR53C400_mem_base + (reg)) -#define NCR5380_write(reg, value) writeb(value, iomem + NCR53C400_mem_base + (reg)) - -#define NCR5380_implementation_fields \ - NCR5380_map_type NCR5380_map_name; \ - void __iomem *iomem; - -#define NCR5380_local_declare() \ - register void __iomem *iomem - -#define NCR5380_setup(instance) \ - iomem = (((struct NCR5380_hostdata *)(instance)->hostdata)->iomem) - -#endif - -#define NCR5380_intr generic_NCR5380_intr -#define NCR5380_queue_command generic_NCR5380_queue_command -#define NCR5380_abort generic_NCR5380_abort -#define NCR5380_bus_reset generic_NCR5380_bus_reset -#define NCR5380_pread generic_NCR5380_pread -#define NCR5380_pwrite generic_NCR5380_pwrite -#define NCR5380_proc_info notyet_generic_proc_info - -#define BOARD_NCR5380 0 -#define BOARD_NCR53C400 1 -#define BOARD_NCR53C400A 2 -#define BOARD_DTC3181E 3 - -#endif /* else def HOSTS_C */ -#endif /* ndef ASM */ -#endif /* GENERIC_NCR5380_H */ - diff --git a/ANDROID_3.4.5/drivers/scsi/g_NCR5380_mmio.c b/ANDROID_3.4.5/drivers/scsi/g_NCR5380_mmio.c deleted file mode 100644 index 8cdde71b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/g_NCR5380_mmio.c +++ /dev/null @@ -1,10 +0,0 @@ -/* - * There is probably a nicer way to do this but this one makes - * pretty obvious what is happening. We rebuild the same file with - * different options for mmio versus pio. - */ - -#define SCSI_G_NCR5380_MEM - -#include "g_NCR5380.c" - diff --git a/ANDROID_3.4.5/drivers/scsi/gdth.c b/ANDROID_3.4.5/drivers/scsi/gdth.c deleted file mode 100644 index 5d72274c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/gdth.c +++ /dev/null @@ -1,5243 +0,0 @@ -/************************************************************************ - * Linux driver for * - * ICP vortex GmbH: GDT ISA/EISA/PCI Disk Array Controllers * - * Intel Corporation: Storage RAID Controllers * - * * - * gdth.c * - * Copyright (C) 1995-06 ICP vortex GmbH, Achim Leubner * - * Copyright (C) 2002-04 Intel Corporation * - * Copyright (C) 2003-06 Adaptec Inc. * - * * - * * - * Additions/Fixes: * - * Boji Tony Kannanthanam * - * Johannes Dinner * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published * - * by the Free Software Foundation; either version 2 of the License, * - * or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this kernel; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * * - * Linux kernel 2.6.x supported * - * * - ************************************************************************/ - -/* All GDT Disk Array Controllers are fully supported by this driver. - * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the - * PCI Fibre Channel Disk Array Controllers. See gdth.h for a complete - * list of all controller types. - * - * If you have one or more GDT3000/3020 EISA controllers with - * controller BIOS disabled, you have to set the IRQ values with the - * command line option "gdth=irq1,irq2,...", where the irq1,irq2,... are - * the IRQ values for the EISA controllers. - * - * After the optional list of IRQ values, other possible - * command line options are: - * disable:Y disable driver - * disable:N enable driver - * reserve_mode:0 reserve no drives for the raw service - * reserve_mode:1 reserve all not init., removable drives - * reserve_mode:2 reserve all not init. drives - * reserve_list:h,b,t,l,h,b,t,l,... reserve particular drive(s) with - * h- controller no., b- channel no., - * t- target ID, l- LUN - * reverse_scan:Y reverse scan order for PCI controllers - * reverse_scan:N scan PCI controllers like BIOS - * max_ids:x x - target ID count per channel (1..MAXID) - * rescan:Y rescan all channels/IDs - * rescan:N use all devices found until now - * hdr_channel:x x - number of virtual bus for host drives - * shared_access:Y disable driver reserve/release protocol to - * access a shared resource from several nodes, - * appropriate controller firmware required - * shared_access:N enable driver reserve/release protocol - * probe_eisa_isa:Y scan for EISA/ISA controllers - * probe_eisa_isa:N do not scan for EISA/ISA controllers - * force_dma32:Y use only 32 bit DMA mode - * force_dma32:N use 64 bit DMA mode, if supported - * - * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N, - * max_ids:127,rescan:N,hdr_channel:0, - * shared_access:Y,probe_eisa_isa:N,force_dma32:N". - * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y". - * - * When loading the gdth driver as a module, the same options are available. - * You can set the IRQs with "IRQ=...". However, the syntax to specify the - * options changes slightly. You must replace all ',' between options - * with ' ' and all ':' with '=' and you must use - * '1' in place of 'Y' and '0' in place of 'N'. - * - * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0 - * max_ids=127 rescan=0 hdr_channel=0 shared_access=0 - * probe_eisa_isa=0 force_dma32=0" - * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1". - */ - -/* The meaning of the Scsi_Pointer members in this driver is as follows: - * ptr: Chaining - * this_residual: unused - * buffer: unused - * dma_handle: unused - * buffers_residual: unused - * Status: unused - * Message: unused - * have_data_in: unused - * sent_command: unused - * phase: unused - */ - - -/* interrupt coalescing */ -/* #define INT_COAL */ - -/* statistics */ -#define GDTH_STATISTICS - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef GDTH_RTC -#include -#endif -#include - -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include "gdth.h" - -static DEFINE_MUTEX(gdth_mutex); -static void gdth_delay(int milliseconds); -static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs); -static irqreturn_t gdth_interrupt(int irq, void *dev_id); -static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, - int gdth_from_wait, int* pIndex); -static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, - Scsi_Cmnd *scp); -static int gdth_async_event(gdth_ha_str *ha); -static void gdth_log_event(gdth_evt_data *dvr, char *buffer); - -static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority); -static void gdth_next(gdth_ha_str *ha); -static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b); -static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); -static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source, - u16 idx, gdth_evt_data *evt); -static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr); -static void gdth_readapp_event(gdth_ha_str *ha, u8 application, - gdth_evt_str *estr); -static void gdth_clear_events(void); - -static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, u16 count); -static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp); -static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive); - -static void gdth_enable_int(gdth_ha_str *ha); -static int gdth_test_busy(gdth_ha_str *ha); -static int gdth_get_cmd_index(gdth_ha_str *ha); -static void gdth_release_event(gdth_ha_str *ha); -static int gdth_wait(gdth_ha_str *ha, int index,u32 time); -static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode, - u32 p1, u64 p2,u64 p3); -static int gdth_search_drives(gdth_ha_str *ha); -static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive); - -static const char *gdth_ctr_name(gdth_ha_str *ha); - -static int gdth_open(struct inode *inode, struct file *filep); -static int gdth_close(struct inode *inode, struct file *filep); -static long gdth_unlocked_ioctl(struct file *filep, unsigned int cmd, - unsigned long arg); - -static void gdth_flush(gdth_ha_str *ha); -static int gdth_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); -static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, - struct gdth_cmndinfo *cmndinfo); -static void gdth_scsi_done(struct scsi_cmnd *scp); - -#ifdef DEBUG_GDTH -static u8 DebugState = DEBUG_GDTH; - -#ifdef __SERIAL__ -#define MAX_SERBUF 160 -static void ser_init(void); -static void ser_puts(char *str); -static void ser_putc(char c); -static int ser_printk(const char *fmt, ...); -static char strbuf[MAX_SERBUF+1]; -#ifdef __COM2__ -#define COM_BASE 0x2f8 -#else -#define COM_BASE 0x3f8 -#endif -static void ser_init() -{ - unsigned port=COM_BASE; - - outb(0x80,port+3); - outb(0,port+1); - /* 19200 Baud, if 9600: outb(12,port) */ - outb(6, port); - outb(3,port+3); - outb(0,port+1); - /* - ser_putc('I'); - ser_putc(' '); - */ -} - -static void ser_puts(char *str) -{ - char *ptr; - - ser_init(); - for (ptr=str;*ptr;++ptr) - ser_putc(*ptr); -} - -static void ser_putc(char c) -{ - unsigned port=COM_BASE; - - while ((inb(port+5) & 0x20)==0); - outb(c,port); - if (c==0x0a) - { - while ((inb(port+5) & 0x20)==0); - outb(0x0d,port); - } -} - -static int ser_printk(const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args,fmt); - i = vsprintf(strbuf,fmt,args); - ser_puts(strbuf); - va_end(args); - return i; -} - -#define TRACE(a) {if (DebugState==1) {ser_printk a;}} -#define TRACE2(a) {if (DebugState==1 || DebugState==2) {ser_printk a;}} -#define TRACE3(a) {if (DebugState!=0) {ser_printk a;}} - -#else /* !__SERIAL__ */ -#define TRACE(a) {if (DebugState==1) {printk a;}} -#define TRACE2(a) {if (DebugState==1 || DebugState==2) {printk a;}} -#define TRACE3(a) {if (DebugState!=0) {printk a;}} -#endif - -#else /* !DEBUG */ -#define TRACE(a) -#define TRACE2(a) -#define TRACE3(a) -#endif - -#ifdef GDTH_STATISTICS -static u32 max_rq=0, max_index=0, max_sg=0; -#ifdef INT_COAL -static u32 max_int_coal=0; -#endif -static u32 act_ints=0, act_ios=0, act_stats=0, act_rq=0; -static struct timer_list gdth_timer; -#endif - -#define PTR2USHORT(a) (u16)(unsigned long)(a) -#define GDTOFFSOF(a,b) (size_t)&(((a*)0)->b) -#define INDEX_OK(i,t) ((i)(a)->virt_bus ? (b-1):(b)) - -#ifdef CONFIG_ISA -static u8 gdth_drq_tab[4] = {5,6,7,7}; /* DRQ table */ -#endif -#if defined(CONFIG_EISA) || defined(CONFIG_ISA) -static u8 gdth_irq_tab[6] = {0,10,11,12,14,0}; /* IRQ table */ -#endif -static u8 gdth_polling; /* polling if TRUE */ -static int gdth_ctr_count = 0; /* controller count */ -static LIST_HEAD(gdth_instances); /* controller list */ -static u8 gdth_write_through = FALSE; /* write through */ -static gdth_evt_str ebuffer[MAX_EVENTS]; /* event buffer */ -static int elastidx; -static int eoldidx; -static int major; - -#define DIN 1 /* IN data direction */ -#define DOU 2 /* OUT data direction */ -#define DNO DIN /* no data transfer */ -#define DUN DIN /* unknown data direction */ -static u8 gdth_direction_tab[0x100] = { - DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN, - DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN, - DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU, - DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU, - DOU,DOU,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN, - DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU, - DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN, - DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN -}; - -/* LILO and modprobe/insmod parameters */ -/* IRQ list for GDT3000/3020 EISA controllers */ -static int irq[MAXHA] __initdata = -{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; -/* disable driver flag */ -static int disable __initdata = 0; -/* reserve flag */ -static int reserve_mode = 1; -/* reserve list */ -static int reserve_list[MAX_RES_ARGS] = -{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, - 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}; -/* scan order for PCI controllers */ -static int reverse_scan = 0; -/* virtual channel for the host drives */ -static int hdr_channel = 0; -/* max. IDs per channel */ -static int max_ids = MAXID; -/* rescan all IDs */ -static int rescan = 0; -/* shared access */ -static int shared_access = 1; -/* enable support for EISA and ISA controllers */ -static int probe_eisa_isa = 0; -/* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */ -static int force_dma32 = 0; - -/* parameters for modprobe/insmod */ -module_param_array(irq, int, NULL, 0); -module_param(disable, int, 0); -module_param(reserve_mode, int, 0); -module_param_array(reserve_list, int, NULL, 0); -module_param(reverse_scan, int, 0); -module_param(hdr_channel, int, 0); -module_param(max_ids, int, 0); -module_param(rescan, int, 0); -module_param(shared_access, int, 0); -module_param(probe_eisa_isa, int, 0); -module_param(force_dma32, int, 0); -MODULE_AUTHOR("Achim Leubner"); -MODULE_LICENSE("GPL"); - -/* ioctl interface */ -static const struct file_operations gdth_fops = { - .unlocked_ioctl = gdth_unlocked_ioctl, - .open = gdth_open, - .release = gdth_close, - .llseek = noop_llseek, -}; - -#include "gdth_proc.h" -#include "gdth_proc.c" - -static gdth_ha_str *gdth_find_ha(int hanum) -{ - gdth_ha_str *ha; - - list_for_each_entry(ha, &gdth_instances, list) - if (hanum == ha->hanum) - return ha; - - return NULL; -} - -static struct gdth_cmndinfo *gdth_get_cmndinfo(gdth_ha_str *ha) -{ - struct gdth_cmndinfo *priv = NULL; - unsigned long flags; - int i; - - spin_lock_irqsave(&ha->smp_lock, flags); - - for (i=0; icmndinfo[i].index == 0) { - priv = &ha->cmndinfo[i]; - memset(priv, 0, sizeof(*priv)); - priv->index = i+1; - break; - } - } - - spin_unlock_irqrestore(&ha->smp_lock, flags); - - return priv; -} - -static void gdth_put_cmndinfo(struct gdth_cmndinfo *priv) -{ - BUG_ON(!priv); - priv->index = 0; -} - -static void gdth_delay(int milliseconds) -{ - if (milliseconds == 0) { - udelay(1); - } else { - mdelay(milliseconds); - } -} - -static void gdth_scsi_done(struct scsi_cmnd *scp) -{ - struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - int internal_command = cmndinfo->internal_command; - - TRACE2(("gdth_scsi_done()\n")); - - gdth_put_cmndinfo(cmndinfo); - scp->host_scribble = NULL; - - if (internal_command) - complete((struct completion *)scp->request); - else - scp->scsi_done(scp); -} - -int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd, - int timeout, u32 *info) -{ - gdth_ha_str *ha = shost_priv(sdev->host); - Scsi_Cmnd *scp; - struct gdth_cmndinfo cmndinfo; - DECLARE_COMPLETION_ONSTACK(wait); - int rval; - - scp = kzalloc(sizeof(*scp), GFP_KERNEL); - if (!scp) - return -ENOMEM; - - scp->sense_buffer = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); - if (!scp->sense_buffer) { - kfree(scp); - return -ENOMEM; - } - - scp->device = sdev; - memset(&cmndinfo, 0, sizeof(cmndinfo)); - - /* use request field to save the ptr. to completion struct. */ - scp->request = (struct request *)&wait; - scp->cmd_len = 12; - scp->cmnd = cmnd; - cmndinfo.priority = IOCTL_PRI; - cmndinfo.internal_cmd_str = gdtcmd; - cmndinfo.internal_command = 1; - - TRACE(("__gdth_execute() cmd 0x%x\n", scp->cmnd[0])); - __gdth_queuecommand(ha, scp, &cmndinfo); - - wait_for_completion(&wait); - - rval = cmndinfo.status; - if (info) - *info = cmndinfo.info; - kfree(scp->sense_buffer); - kfree(scp); - return rval; -} - -int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd, - int timeout, u32 *info) -{ - struct scsi_device *sdev = scsi_get_host_dev(shost); - int rval = __gdth_execute(sdev, gdtcmd, cmnd, timeout, info); - - scsi_free_host_dev(sdev); - return rval; -} - -static void gdth_eval_mapping(u32 size, u32 *cyls, int *heads, int *secs) -{ - *cyls = size /HEADS/SECS; - if (*cyls <= MAXCYLS) { - *heads = HEADS; - *secs = SECS; - } else { /* too high for 64*32 */ - *cyls = size /MEDHEADS/MEDSECS; - if (*cyls <= MAXCYLS) { - *heads = MEDHEADS; - *secs = MEDSECS; - } else { /* too high for 127*63 */ - *cyls = size /BIGHEADS/BIGSECS; - *heads = BIGHEADS; - *secs = BIGSECS; - } - } -} - -/* controller search and initialization functions */ -#ifdef CONFIG_EISA -static int __init gdth_search_eisa(u16 eisa_adr) -{ - u32 id; - - TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr)); - id = inl(eisa_adr+ID0REG); - if (id == GDT3A_ID || id == GDT3B_ID) { /* GDT3000A or GDT3000B */ - if ((inb(eisa_adr+EISAREG) & 8) == 0) - return 0; /* not EISA configured */ - return 1; - } - if (id == GDT3_ID) /* GDT3000 */ - return 1; - - return 0; -} -#endif /* CONFIG_EISA */ - -#ifdef CONFIG_ISA -static int __init gdth_search_isa(u32 bios_adr) -{ - void __iomem *addr; - u32 id; - - TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr)); - if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(u32))) != NULL) { - id = readl(addr); - iounmap(addr); - if (id == GDT2_ID) /* GDT2000 */ - return 1; - } - return 0; -} -#endif /* CONFIG_ISA */ - -#ifdef CONFIG_PCI - -static bool gdth_search_vortex(u16 device) -{ - if (device <= PCI_DEVICE_ID_VORTEX_GDT6555) - return true; - if (device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP && - device <= PCI_DEVICE_ID_VORTEX_GDTMAXRP) - return true; - if (device == PCI_DEVICE_ID_VORTEX_GDTNEWRX || - device == PCI_DEVICE_ID_VORTEX_GDTNEWRX2) - return true; - return false; -} - -static int gdth_pci_probe_one(gdth_pci_str *pcistr, gdth_ha_str **ha_out); -static int gdth_pci_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent); -static void gdth_pci_remove_one(struct pci_dev *pdev); -static void gdth_remove_one(gdth_ha_str *ha); - -/* Vortex only makes RAID controllers. - * We do not really want to specify all 550 ids here, so wildcard match. - */ -static const struct pci_device_id gdthtable[] = { - { PCI_VDEVICE(VORTEX, PCI_ANY_ID) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SRC) }, - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SRC_XSCALE) }, - { } /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, gdthtable); - -static struct pci_driver gdth_pci_driver = { - .name = "gdth", - .id_table = gdthtable, - .probe = gdth_pci_init_one, - .remove = gdth_pci_remove_one, -}; - -static void __devexit gdth_pci_remove_one(struct pci_dev *pdev) -{ - gdth_ha_str *ha = pci_get_drvdata(pdev); - - pci_set_drvdata(pdev, NULL); - - list_del(&ha->list); - gdth_remove_one(ha); - - pci_disable_device(pdev); -} - -static int __devinit gdth_pci_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - u16 vendor = pdev->vendor; - u16 device = pdev->device; - unsigned long base0, base1, base2; - int rc; - gdth_pci_str gdth_pcistr; - gdth_ha_str *ha = NULL; - - TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n", - gdth_ctr_count, vendor, device)); - - memset(&gdth_pcistr, 0, sizeof(gdth_pcistr)); - - if (vendor == PCI_VENDOR_ID_VORTEX && !gdth_search_vortex(device)) - return -ENODEV; - - rc = pci_enable_device(pdev); - if (rc) - return rc; - - if (gdth_ctr_count >= MAXHA) - return -EBUSY; - - /* GDT PCI controller found, resources are already in pdev */ - gdth_pcistr.pdev = pdev; - base0 = pci_resource_flags(pdev, 0); - base1 = pci_resource_flags(pdev, 1); - base2 = pci_resource_flags(pdev, 2); - if (device <= PCI_DEVICE_ID_VORTEX_GDT6000B || /* GDT6000/B */ - device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) { /* MPR */ - if (!(base0 & IORESOURCE_MEM)) - return -ENODEV; - gdth_pcistr.dpmem = pci_resource_start(pdev, 0); - } else { /* GDT6110, GDT6120, .. */ - if (!(base0 & IORESOURCE_MEM) || - !(base2 & IORESOURCE_MEM) || - !(base1 & IORESOURCE_IO)) - return -ENODEV; - gdth_pcistr.dpmem = pci_resource_start(pdev, 2); - gdth_pcistr.io = pci_resource_start(pdev, 1); - } - TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n", - gdth_pcistr.pdev->bus->number, - PCI_SLOT(gdth_pcistr.pdev->devfn), - gdth_pcistr.irq, - gdth_pcistr.dpmem)); - - rc = gdth_pci_probe_one(&gdth_pcistr, &ha); - if (rc) - return rc; - - return 0; -} -#endif /* CONFIG_PCI */ - -#ifdef CONFIG_EISA -static int __init gdth_init_eisa(u16 eisa_adr,gdth_ha_str *ha) -{ - u32 retries,id; - u8 prot_ver,eisacf,i,irq_found; - - TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr)); - - /* disable board interrupts, deinitialize services */ - outb(0xff,eisa_adr+EDOORREG); - outb(0x00,eisa_adr+EDENABREG); - outb(0x00,eisa_adr+EINTENABREG); - - outb(0xff,eisa_adr+LDOORREG); - retries = INIT_RETRIES; - gdth_delay(20); - while (inb(eisa_adr+EDOORREG) != 0xff) { - if (--retries == 0) { - printk("GDT-EISA: Initialization error (DEINIT failed)\n"); - return 0; - } - gdth_delay(1); - TRACE2(("wait for DEINIT: retries=%d\n",retries)); - } - prot_ver = inb(eisa_adr+MAILBOXREG); - outb(0xff,eisa_adr+EDOORREG); - if (prot_ver != PROTOCOL_VERSION) { - printk("GDT-EISA: Illegal protocol version\n"); - return 0; - } - ha->bmic = eisa_adr; - ha->brd_phys = (u32)eisa_adr >> 12; - - outl(0,eisa_adr+MAILBOXREG); - outl(0,eisa_adr+MAILBOXREG+4); - outl(0,eisa_adr+MAILBOXREG+8); - outl(0,eisa_adr+MAILBOXREG+12); - - /* detect IRQ */ - if ((id = inl(eisa_adr+ID0REG)) == GDT3_ID) { - ha->oem_id = OEM_ID_ICP; - ha->type = GDT_EISA; - ha->stype = id; - outl(1,eisa_adr+MAILBOXREG+8); - outb(0xfe,eisa_adr+LDOORREG); - retries = INIT_RETRIES; - gdth_delay(20); - while (inb(eisa_adr+EDOORREG) != 0xfe) { - if (--retries == 0) { - printk("GDT-EISA: Initialization error (get IRQ failed)\n"); - return 0; - } - gdth_delay(1); - } - ha->irq = inb(eisa_adr+MAILBOXREG); - outb(0xff,eisa_adr+EDOORREG); - TRACE2(("GDT3000/3020: IRQ=%d\n",ha->irq)); - /* check the result */ - if (ha->irq == 0) { - TRACE2(("Unknown IRQ, use IRQ table from cmd line !\n")); - for (i = 0, irq_found = FALSE; - i < MAXHA && irq[i] != 0xff; ++i) { - if (irq[i]==10 || irq[i]==11 || irq[i]==12 || irq[i]==14) { - irq_found = TRUE; - break; - } - } - if (irq_found) { - ha->irq = irq[i]; - irq[i] = 0; - printk("GDT-EISA: Can not detect controller IRQ,\n"); - printk("Use IRQ setting from command line (IRQ = %d)\n", - ha->irq); - } else { - printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n"); - printk("the controller BIOS or use command line parameters\n"); - return 0; - } - } - } else { - eisacf = inb(eisa_adr+EISAREG) & 7; - if (eisacf > 4) /* level triggered */ - eisacf -= 4; - ha->irq = gdth_irq_tab[eisacf]; - ha->oem_id = OEM_ID_ICP; - ha->type = GDT_EISA; - ha->stype = id; - } - - ha->dma64_support = 0; - return 1; -} -#endif /* CONFIG_EISA */ - -#ifdef CONFIG_ISA -static int __init gdth_init_isa(u32 bios_adr,gdth_ha_str *ha) -{ - register gdt2_dpram_str __iomem *dp2_ptr; - int i; - u8 irq_drq,prot_ver; - u32 retries; - - TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr)); - - ha->brd = ioremap(bios_adr, sizeof(gdt2_dpram_str)); - if (ha->brd == NULL) { - printk("GDT-ISA: Initialization error (DPMEM remap error)\n"); - return 0; - } - dp2_ptr = ha->brd; - writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */ - /* reset interface area */ - memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u)); - if (readl(&dp2_ptr->u) != 0) { - printk("GDT-ISA: Initialization error (DPMEM write error)\n"); - iounmap(ha->brd); - return 0; - } - - /* disable board interrupts, read DRQ and IRQ */ - writeb(0xff, &dp2_ptr->io.irqdel); - writeb(0x00, &dp2_ptr->io.irqen); - writeb(0x00, &dp2_ptr->u.ic.S_Status); - writeb(0x00, &dp2_ptr->u.ic.Cmd_Index); - - irq_drq = readb(&dp2_ptr->io.rq); - for (i=0; i<3; ++i) { - if ((irq_drq & 1)==0) - break; - irq_drq >>= 1; - } - ha->drq = gdth_drq_tab[i]; - - irq_drq = readb(&dp2_ptr->io.rq) >> 3; - for (i=1; i<5; ++i) { - if ((irq_drq & 1)==0) - break; - irq_drq >>= 1; - } - ha->irq = gdth_irq_tab[i]; - - /* deinitialize services */ - writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]); - writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx); - writeb(0, &dp2_ptr->io.event); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp2_ptr->u.ic.S_Status) != 0xff) { - if (--retries == 0) { - printk("GDT-ISA: Initialization error (DEINIT failed)\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - prot_ver = (u8)readl(&dp2_ptr->u.ic.S_Info[0]); - writeb(0, &dp2_ptr->u.ic.Status); - writeb(0xff, &dp2_ptr->io.irqdel); - if (prot_ver != PROTOCOL_VERSION) { - printk("GDT-ISA: Illegal protocol version\n"); - iounmap(ha->brd); - return 0; - } - - ha->oem_id = OEM_ID_ICP; - ha->type = GDT_ISA; - ha->ic_all_size = sizeof(dp2_ptr->u); - ha->stype= GDT2_ID; - ha->brd_phys = bios_adr >> 4; - - /* special request to controller BIOS */ - writel(0x00, &dp2_ptr->u.ic.S_Info[0]); - writel(0x00, &dp2_ptr->u.ic.S_Info[1]); - writel(0x01, &dp2_ptr->u.ic.S_Info[2]); - writel(0x00, &dp2_ptr->u.ic.S_Info[3]); - writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx); - writeb(0, &dp2_ptr->io.event); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp2_ptr->u.ic.S_Status) != 0xfe) { - if (--retries == 0) { - printk("GDT-ISA: Initialization error\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - writeb(0, &dp2_ptr->u.ic.Status); - writeb(0xff, &dp2_ptr->io.irqdel); - - ha->dma64_support = 0; - return 1; -} -#endif /* CONFIG_ISA */ - -#ifdef CONFIG_PCI -static int __devinit gdth_init_pci(struct pci_dev *pdev, gdth_pci_str *pcistr, - gdth_ha_str *ha) -{ - register gdt6_dpram_str __iomem *dp6_ptr; - register gdt6c_dpram_str __iomem *dp6c_ptr; - register gdt6m_dpram_str __iomem *dp6m_ptr; - u32 retries; - u8 prot_ver; - u16 command; - int i, found = FALSE; - - TRACE(("gdth_init_pci()\n")); - - if (pdev->vendor == PCI_VENDOR_ID_INTEL) - ha->oem_id = OEM_ID_INTEL; - else - ha->oem_id = OEM_ID_ICP; - ha->brd_phys = (pdev->bus->number << 8) | (pdev->devfn & 0xf8); - ha->stype = (u32)pdev->device; - ha->irq = pdev->irq; - ha->pdev = pdev; - - if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6000B) { /* GDT6000/B */ - TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq)); - ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - return 0; - } - /* check and reset interface area */ - dp6_ptr = ha->brd; - writel(DPMEM_MAGIC, &dp6_ptr->u); - if (readl(&dp6_ptr->u) != DPMEM_MAGIC) { - printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", - pcistr->dpmem); - found = FALSE; - for (i = 0xC8000; i < 0xE8000; i += 0x4000) { - iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(u16)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - return 0; - } - if (readw(ha->brd) != 0xffff) { - TRACE2(("init_pci_old() address 0x%x busy\n", i)); - continue; - } - iounmap(ha->brd); - pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, i); - ha->brd = ioremap(i, sizeof(gdt6_dpram_str)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - return 0; - } - dp6_ptr = ha->brd; - writel(DPMEM_MAGIC, &dp6_ptr->u); - if (readl(&dp6_ptr->u) == DPMEM_MAGIC) { - printk("GDT-PCI: Use free address at 0x%x\n", i); - found = TRUE; - break; - } - } - if (!found) { - printk("GDT-PCI: No free address found!\n"); - iounmap(ha->brd); - return 0; - } - } - memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u)); - if (readl(&dp6_ptr->u) != 0) { - printk("GDT-PCI: Initialization error (DPMEM write error)\n"); - iounmap(ha->brd); - return 0; - } - - /* disable board interrupts, deinit services */ - writeb(0xff, &dp6_ptr->io.irqdel); - writeb(0x00, &dp6_ptr->io.irqen); - writeb(0x00, &dp6_ptr->u.ic.S_Status); - writeb(0x00, &dp6_ptr->u.ic.Cmd_Index); - - writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]); - writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx); - writeb(0, &dp6_ptr->io.event); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp6_ptr->u.ic.S_Status) != 0xff) { - if (--retries == 0) { - printk("GDT-PCI: Initialization error (DEINIT failed)\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - prot_ver = (u8)readl(&dp6_ptr->u.ic.S_Info[0]); - writeb(0, &dp6_ptr->u.ic.S_Status); - writeb(0xff, &dp6_ptr->io.irqdel); - if (prot_ver != PROTOCOL_VERSION) { - printk("GDT-PCI: Illegal protocol version\n"); - iounmap(ha->brd); - return 0; - } - - ha->type = GDT_PCI; - ha->ic_all_size = sizeof(dp6_ptr->u); - - /* special command to controller BIOS */ - writel(0x00, &dp6_ptr->u.ic.S_Info[0]); - writel(0x00, &dp6_ptr->u.ic.S_Info[1]); - writel(0x00, &dp6_ptr->u.ic.S_Info[2]); - writel(0x00, &dp6_ptr->u.ic.S_Info[3]); - writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx); - writeb(0, &dp6_ptr->io.event); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp6_ptr->u.ic.S_Status) != 0xfe) { - if (--retries == 0) { - printk("GDT-PCI: Initialization error\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - writeb(0, &dp6_ptr->u.ic.S_Status); - writeb(0xff, &dp6_ptr->io.irqdel); - - ha->dma64_support = 0; - - } else if (ha->pdev->device <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */ - ha->plx = (gdt6c_plx_regs *)pcistr->io; - TRACE2(("init_pci_new() dpmem %lx irq %d\n", - pcistr->dpmem,ha->irq)); - ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6c_dpram_str)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - iounmap(ha->brd); - return 0; - } - /* check and reset interface area */ - dp6c_ptr = ha->brd; - writel(DPMEM_MAGIC, &dp6c_ptr->u); - if (readl(&dp6c_ptr->u) != DPMEM_MAGIC) { - printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", - pcistr->dpmem); - found = FALSE; - for (i = 0xC8000; i < 0xE8000; i += 0x4000) { - iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(u16)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - return 0; - } - if (readw(ha->brd) != 0xffff) { - TRACE2(("init_pci_plx() address 0x%x busy\n", i)); - continue; - } - iounmap(ha->brd); - pci_write_config_dword(pdev, PCI_BASE_ADDRESS_2, i); - ha->brd = ioremap(i, sizeof(gdt6c_dpram_str)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - return 0; - } - dp6c_ptr = ha->brd; - writel(DPMEM_MAGIC, &dp6c_ptr->u); - if (readl(&dp6c_ptr->u) == DPMEM_MAGIC) { - printk("GDT-PCI: Use free address at 0x%x\n", i); - found = TRUE; - break; - } - } - if (!found) { - printk("GDT-PCI: No free address found!\n"); - iounmap(ha->brd); - return 0; - } - } - memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u)); - if (readl(&dp6c_ptr->u) != 0) { - printk("GDT-PCI: Initialization error (DPMEM write error)\n"); - iounmap(ha->brd); - return 0; - } - - /* disable board interrupts, deinit services */ - outb(0x00,PTR2USHORT(&ha->plx->control1)); - outb(0xff,PTR2USHORT(&ha->plx->edoor_reg)); - - writeb(0x00, &dp6c_ptr->u.ic.S_Status); - writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index); - - writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]); - writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx); - - outb(1,PTR2USHORT(&ha->plx->ldoor_reg)); - - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp6c_ptr->u.ic.S_Status) != 0xff) { - if (--retries == 0) { - printk("GDT-PCI: Initialization error (DEINIT failed)\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - prot_ver = (u8)readl(&dp6c_ptr->u.ic.S_Info[0]); - writeb(0, &dp6c_ptr->u.ic.Status); - if (prot_ver != PROTOCOL_VERSION) { - printk("GDT-PCI: Illegal protocol version\n"); - iounmap(ha->brd); - return 0; - } - - ha->type = GDT_PCINEW; - ha->ic_all_size = sizeof(dp6c_ptr->u); - - /* special command to controller BIOS */ - writel(0x00, &dp6c_ptr->u.ic.S_Info[0]); - writel(0x00, &dp6c_ptr->u.ic.S_Info[1]); - writel(0x00, &dp6c_ptr->u.ic.S_Info[2]); - writel(0x00, &dp6c_ptr->u.ic.S_Info[3]); - writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx); - - outb(1,PTR2USHORT(&ha->plx->ldoor_reg)); - - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) { - if (--retries == 0) { - printk("GDT-PCI: Initialization error\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - writeb(0, &dp6c_ptr->u.ic.S_Status); - - ha->dma64_support = 0; - - } else { /* MPR */ - TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq)); - ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6m_dpram_str)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - return 0; - } - - /* manipulate config. space to enable DPMEM, start RP controller */ - pci_read_config_word(pdev, PCI_COMMAND, &command); - command |= 6; - pci_write_config_word(pdev, PCI_COMMAND, command); - if (pci_resource_start(pdev, 8) == 1UL) - pci_resource_start(pdev, 8) = 0UL; - i = 0xFEFF0001UL; - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, i); - gdth_delay(1); - pci_write_config_dword(pdev, PCI_ROM_ADDRESS, - pci_resource_start(pdev, 8)); - - dp6m_ptr = ha->brd; - - /* Ensure that it is safe to access the non HW portions of DPMEM. - * Aditional check needed for Xscale based RAID controllers */ - while( ((int)readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 ) - gdth_delay(1); - - /* check and reset interface area */ - writel(DPMEM_MAGIC, &dp6m_ptr->u); - if (readl(&dp6m_ptr->u) != DPMEM_MAGIC) { - printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", - pcistr->dpmem); - found = FALSE; - for (i = 0xC8000; i < 0xE8000; i += 0x4000) { - iounmap(ha->brd); - ha->brd = ioremap(i, sizeof(u16)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - return 0; - } - if (readw(ha->brd) != 0xffff) { - TRACE2(("init_pci_mpr() address 0x%x busy\n", i)); - continue; - } - iounmap(ha->brd); - pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, i); - ha->brd = ioremap(i, sizeof(gdt6m_dpram_str)); - if (ha->brd == NULL) { - printk("GDT-PCI: Initialization error (DPMEM remap error)\n"); - return 0; - } - dp6m_ptr = ha->brd; - writel(DPMEM_MAGIC, &dp6m_ptr->u); - if (readl(&dp6m_ptr->u) == DPMEM_MAGIC) { - printk("GDT-PCI: Use free address at 0x%x\n", i); - found = TRUE; - break; - } - } - if (!found) { - printk("GDT-PCI: No free address found!\n"); - iounmap(ha->brd); - return 0; - } - } - memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u)); - - /* disable board interrupts, deinit services */ - writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) | 4, - &dp6m_ptr->i960r.edoor_en_reg); - writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - writeb(0x00, &dp6m_ptr->u.ic.S_Status); - writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index); - - writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]); - writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx); - writeb(1, &dp6m_ptr->i960r.ldoor_reg); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp6m_ptr->u.ic.S_Status) != 0xff) { - if (--retries == 0) { - printk("GDT-PCI: Initialization error (DEINIT failed)\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - prot_ver = (u8)readl(&dp6m_ptr->u.ic.S_Info[0]); - writeb(0, &dp6m_ptr->u.ic.S_Status); - if (prot_ver != PROTOCOL_VERSION) { - printk("GDT-PCI: Illegal protocol version\n"); - iounmap(ha->brd); - return 0; - } - - ha->type = GDT_PCIMPR; - ha->ic_all_size = sizeof(dp6m_ptr->u); - - /* special command to controller BIOS */ - writel(0x00, &dp6m_ptr->u.ic.S_Info[0]); - writel(0x00, &dp6m_ptr->u.ic.S_Info[1]); - writel(0x00, &dp6m_ptr->u.ic.S_Info[2]); - writel(0x00, &dp6m_ptr->u.ic.S_Info[3]); - writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx); - writeb(1, &dp6m_ptr->i960r.ldoor_reg); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) { - if (--retries == 0) { - printk("GDT-PCI: Initialization error\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - writeb(0, &dp6m_ptr->u.ic.S_Status); - - /* read FW version to detect 64-bit DMA support */ - writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx); - writeb(1, &dp6m_ptr->i960r.ldoor_reg); - retries = INIT_RETRIES; - gdth_delay(20); - while (readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) { - if (--retries == 0) { - printk("GDT-PCI: Initialization error (DEINIT failed)\n"); - iounmap(ha->brd); - return 0; - } - gdth_delay(1); - } - prot_ver = (u8)(readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16); - writeb(0, &dp6m_ptr->u.ic.S_Status); - if (prot_ver < 0x2b) /* FW < x.43: no 64-bit DMA support */ - ha->dma64_support = 0; - else - ha->dma64_support = 1; - } - - return 1; -} -#endif /* CONFIG_PCI */ - -/* controller protocol functions */ - -static void __devinit gdth_enable_int(gdth_ha_str *ha) -{ - unsigned long flags; - gdt2_dpram_str __iomem *dp2_ptr; - gdt6_dpram_str __iomem *dp6_ptr; - gdt6m_dpram_str __iomem *dp6m_ptr; - - TRACE(("gdth_enable_int() hanum %d\n",ha->hanum)); - spin_lock_irqsave(&ha->smp_lock, flags); - - if (ha->type == GDT_EISA) { - outb(0xff, ha->bmic + EDOORREG); - outb(0xff, ha->bmic + EDENABREG); - outb(0x01, ha->bmic + EINTENABREG); - } else if (ha->type == GDT_ISA) { - dp2_ptr = ha->brd; - writeb(1, &dp2_ptr->io.irqdel); - writeb(0, &dp2_ptr->u.ic.Cmd_Index); - writeb(1, &dp2_ptr->io.irqen); - } else if (ha->type == GDT_PCI) { - dp6_ptr = ha->brd; - writeb(1, &dp6_ptr->io.irqdel); - writeb(0, &dp6_ptr->u.ic.Cmd_Index); - writeb(1, &dp6_ptr->io.irqen); - } else if (ha->type == GDT_PCINEW) { - outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); - outb(0x03, PTR2USHORT(&ha->plx->control1)); - } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = ha->brd; - writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - writeb(readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4, - &dp6m_ptr->i960r.edoor_en_reg); - } - spin_unlock_irqrestore(&ha->smp_lock, flags); -} - -/* return IStatus if interrupt was from this card else 0 */ -static u8 gdth_get_status(gdth_ha_str *ha) -{ - u8 IStatus = 0; - - TRACE(("gdth_get_status() irq %d ctr_count %d\n", ha->irq, gdth_ctr_count)); - - if (ha->type == GDT_EISA) - IStatus = inb((u16)ha->bmic + EDOORREG); - else if (ha->type == GDT_ISA) - IStatus = - readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); - else if (ha->type == GDT_PCI) - IStatus = - readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index); - else if (ha->type == GDT_PCINEW) - IStatus = inb(PTR2USHORT(&ha->plx->edoor_reg)); - else if (ha->type == GDT_PCIMPR) - IStatus = - readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg); - - return IStatus; -} - -static int gdth_test_busy(gdth_ha_str *ha) -{ - register int gdtsema0 = 0; - - TRACE(("gdth_test_busy() hanum %d\n", ha->hanum)); - - if (ha->type == GDT_EISA) - gdtsema0 = (int)inb(ha->bmic + SEMA0REG); - else if (ha->type == GDT_ISA) - gdtsema0 = (int)readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); - else if (ha->type == GDT_PCI) - gdtsema0 = (int)readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); - else if (ha->type == GDT_PCINEW) - gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg)); - else if (ha->type == GDT_PCIMPR) - gdtsema0 = - (int)readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); - - return (gdtsema0 & 1); -} - - -static int gdth_get_cmd_index(gdth_ha_str *ha) -{ - int i; - - TRACE(("gdth_get_cmd_index() hanum %d\n", ha->hanum)); - - for (i=0; icmd_tab[i].cmnd == UNUSED_CMND) { - ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer; - ha->cmd_tab[i].service = ha->pccb->Service; - ha->pccb->CommandIndex = (u32)i+2; - return (i+2); - } - } - return 0; -} - - -static void gdth_set_sema0(gdth_ha_str *ha) -{ - TRACE(("gdth_set_sema0() hanum %d\n", ha->hanum)); - - if (ha->type == GDT_EISA) { - outb(1, ha->bmic + SEMA0REG); - } else if (ha->type == GDT_ISA) { - writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0); - } else if (ha->type == GDT_PCI) { - writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0); - } else if (ha->type == GDT_PCINEW) { - outb(1, PTR2USHORT(&ha->plx->sema0_reg)); - } else if (ha->type == GDT_PCIMPR) { - writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg); - } -} - - -static void gdth_copy_command(gdth_ha_str *ha) -{ - register gdth_cmd_str *cmd_ptr; - register gdt6m_dpram_str __iomem *dp6m_ptr; - register gdt6c_dpram_str __iomem *dp6c_ptr; - gdt6_dpram_str __iomem *dp6_ptr; - gdt2_dpram_str __iomem *dp2_ptr; - u16 cp_count,dp_offset,cmd_no; - - TRACE(("gdth_copy_command() hanum %d\n", ha->hanum)); - - cp_count = ha->cmd_len; - dp_offset= ha->cmd_offs_dpmem; - cmd_no = ha->cmd_cnt; - cmd_ptr = ha->pccb; - - ++ha->cmd_cnt; - if (ha->type == GDT_EISA) - return; /* no DPMEM, no copy */ - - /* set cpcount dword aligned */ - if (cp_count & 3) - cp_count += (4 - (cp_count & 3)); - - ha->cmd_offs_dpmem += cp_count; - - /* set offset and service, copy command to DPMEM */ - if (ha->type == GDT_ISA) { - dp2_ptr = ha->brd; - writew(dp_offset + DPMEM_COMMAND_OFFSET, - &dp2_ptr->u.ic.comm_queue[cmd_no].offset); - writew((u16)cmd_ptr->Service, - &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id); - memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); - } else if (ha->type == GDT_PCI) { - dp6_ptr = ha->brd; - writew(dp_offset + DPMEM_COMMAND_OFFSET, - &dp6_ptr->u.ic.comm_queue[cmd_no].offset); - writew((u16)cmd_ptr->Service, - &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id); - memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); - } else if (ha->type == GDT_PCINEW) { - dp6c_ptr = ha->brd; - writew(dp_offset + DPMEM_COMMAND_OFFSET, - &dp6c_ptr->u.ic.comm_queue[cmd_no].offset); - writew((u16)cmd_ptr->Service, - &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id); - memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); - } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = ha->brd; - writew(dp_offset + DPMEM_COMMAND_OFFSET, - &dp6m_ptr->u.ic.comm_queue[cmd_no].offset); - writew((u16)cmd_ptr->Service, - &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id); - memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count); - } -} - - -static void gdth_release_event(gdth_ha_str *ha) -{ - TRACE(("gdth_release_event() hanum %d\n", ha->hanum)); - -#ifdef GDTH_STATISTICS - { - u32 i,j; - for (i=0,j=0; jcmd_tab[j].cmnd != UNUSED_CMND) - ++i; - } - if (max_index < i) { - max_index = i; - TRACE3(("GDT: max_index = %d\n",(u16)i)); - } - } -#endif - - if (ha->pccb->OpCode == GDT_INIT) - ha->pccb->Service |= 0x80; - - if (ha->type == GDT_EISA) { - if (ha->pccb->OpCode == GDT_INIT) /* store DMA buffer */ - outl(ha->ccb_phys, ha->bmic + MAILBOXREG); - outb(ha->pccb->Service, ha->bmic + LDOORREG); - } else if (ha->type == GDT_ISA) { - writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event); - } else if (ha->type == GDT_PCI) { - writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event); - } else if (ha->type == GDT_PCINEW) { - outb(1, PTR2USHORT(&ha->plx->ldoor_reg)); - } else if (ha->type == GDT_PCIMPR) { - writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg); - } -} - -static int gdth_wait(gdth_ha_str *ha, int index, u32 time) -{ - int answer_found = FALSE; - int wait_index = 0; - - TRACE(("gdth_wait() hanum %d index %d time %d\n", ha->hanum, index, time)); - - if (index == 0) - return 1; /* no wait required */ - - do { - __gdth_interrupt(ha, true, &wait_index); - if (wait_index == index) { - answer_found = TRUE; - break; - } - gdth_delay(1); - } while (--time); - - while (gdth_test_busy(ha)) - gdth_delay(0); - - return (answer_found); -} - - -static int gdth_internal_cmd(gdth_ha_str *ha, u8 service, u16 opcode, - u32 p1, u64 p2, u64 p3) -{ - register gdth_cmd_str *cmd_ptr; - int retries,index; - - TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode)); - - cmd_ptr = ha->pccb; - memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str)); - - /* make command */ - for (retries = INIT_RETRIES;;) { - cmd_ptr->Service = service; - cmd_ptr->RequestBuffer = INTERNAL_CMND; - if (!(index=gdth_get_cmd_index(ha))) { - TRACE(("GDT: No free command index found\n")); - return 0; - } - gdth_set_sema0(ha); - cmd_ptr->OpCode = opcode; - cmd_ptr->BoardNode = LOCALBOARD; - if (service == CACHESERVICE) { - if (opcode == GDT_IOCTL) { - cmd_ptr->u.ioctl.subfunc = p1; - cmd_ptr->u.ioctl.channel = (u32)p2; - cmd_ptr->u.ioctl.param_size = (u16)p3; - cmd_ptr->u.ioctl.p_param = ha->scratch_phys; - } else { - if (ha->cache_feat & GDT_64BIT) { - cmd_ptr->u.cache64.DeviceNo = (u16)p1; - cmd_ptr->u.cache64.BlockNo = p2; - } else { - cmd_ptr->u.cache.DeviceNo = (u16)p1; - cmd_ptr->u.cache.BlockNo = (u32)p2; - } - } - } else if (service == SCSIRAWSERVICE) { - if (ha->raw_feat & GDT_64BIT) { - cmd_ptr->u.raw64.direction = p1; - cmd_ptr->u.raw64.bus = (u8)p2; - cmd_ptr->u.raw64.target = (u8)p3; - cmd_ptr->u.raw64.lun = (u8)(p3 >> 8); - } else { - cmd_ptr->u.raw.direction = p1; - cmd_ptr->u.raw.bus = (u8)p2; - cmd_ptr->u.raw.target = (u8)p3; - cmd_ptr->u.raw.lun = (u8)(p3 >> 8); - } - } else if (service == SCREENSERVICE) { - if (opcode == GDT_REALTIME) { - *(u32 *)&cmd_ptr->u.screen.su.data[0] = p1; - *(u32 *)&cmd_ptr->u.screen.su.data[4] = (u32)p2; - *(u32 *)&cmd_ptr->u.screen.su.data[8] = (u32)p3; - } - } - ha->cmd_len = sizeof(gdth_cmd_str); - ha->cmd_offs_dpmem = 0; - ha->cmd_cnt = 0; - gdth_copy_command(ha); - gdth_release_event(ha); - gdth_delay(20); - if (!gdth_wait(ha, index, INIT_TIMEOUT)) { - printk("GDT: Initialization error (timeout service %d)\n",service); - return 0; - } - if (ha->status != S_BSY || --retries == 0) - break; - gdth_delay(1); - } - - return (ha->status != S_OK ? 0:1); -} - - -/* search for devices */ - -static int __devinit gdth_search_drives(gdth_ha_str *ha) -{ - u16 cdev_cnt, i; - int ok; - u32 bus_no, drv_cnt, drv_no, j; - gdth_getch_str *chn; - gdth_drlist_str *drl; - gdth_iochan_str *ioc; - gdth_raw_iochan_str *iocr; - gdth_arcdl_str *alst; - gdth_alist_str *alst2; - gdth_oem_str_ioctl *oemstr; -#ifdef INT_COAL - gdth_perf_modes *pmod; -#endif - -#ifdef GDTH_RTC - u8 rtc[12]; - unsigned long flags; -#endif - - TRACE(("gdth_search_drives() hanum %d\n", ha->hanum)); - ok = 0; - - /* initialize controller services, at first: screen service */ - ha->screen_feat = 0; - if (!force_dma32) { - ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_X_INIT_SCR, 0, 0, 0); - if (ok) - ha->screen_feat = GDT_64BIT; - } - if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) - ok = gdth_internal_cmd(ha, SCREENSERVICE, GDT_INIT, 0, 0, 0); - if (!ok) { - printk("GDT-HA %d: Initialization error screen service (code %d)\n", - ha->hanum, ha->status); - return 0; - } - TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n")); - -#ifdef GDTH_RTC - /* read realtime clock info, send to controller */ - /* 1. wait for the falling edge of update flag */ - spin_lock_irqsave(&rtc_lock, flags); - for (j = 0; j < 1000000; ++j) - if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) - break; - for (j = 0; j < 1000000; ++j) - if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)) - break; - /* 2. read info */ - do { - for (j = 0; j < 12; ++j) - rtc[j] = CMOS_READ(j); - } while (rtc[0] != CMOS_READ(0)); - spin_unlock_irqrestore(&rtc_lock, flags); - TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(u32 *)&rtc[0], - *(u32 *)&rtc[4], *(u32 *)&rtc[8])); - /* 3. send to controller firmware */ - gdth_internal_cmd(ha, SCREENSERVICE, GDT_REALTIME, *(u32 *)&rtc[0], - *(u32 *)&rtc[4], *(u32 *)&rtc[8]); -#endif - - /* unfreeze all IOs */ - gdth_internal_cmd(ha, CACHESERVICE, GDT_UNFREEZE_IO, 0, 0, 0); - - /* initialize cache service */ - ha->cache_feat = 0; - if (!force_dma32) { - ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INIT_HOST, LINUX_OS, - 0, 0); - if (ok) - ha->cache_feat = GDT_64BIT; - } - if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) - ok = gdth_internal_cmd(ha, CACHESERVICE, GDT_INIT, LINUX_OS, 0, 0); - if (!ok) { - printk("GDT-HA %d: Initialization error cache service (code %d)\n", - ha->hanum, ha->status); - return 0; - } - TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n")); - cdev_cnt = (u16)ha->info; - ha->fw_vers = ha->service; - -#ifdef INT_COAL - if (ha->type == GDT_PCIMPR) { - /* set perf. modes */ - pmod = (gdth_perf_modes *)ha->pscratch; - pmod->version = 1; - pmod->st_mode = 1; /* enable one status buffer */ - *((u64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys; - pmod->st_buff_indx1 = COALINDEX; - pmod->st_buff_addr2 = 0; - pmod->st_buff_u_addr2 = 0; - pmod->st_buff_indx2 = 0; - pmod->st_buff_size = sizeof(gdth_coal_status) * MAXOFFSETS; - pmod->cmd_mode = 0; // disable all cmd buffers - pmod->cmd_buff_addr1 = 0; - pmod->cmd_buff_u_addr1 = 0; - pmod->cmd_buff_indx1 = 0; - pmod->cmd_buff_addr2 = 0; - pmod->cmd_buff_u_addr2 = 0; - pmod->cmd_buff_indx2 = 0; - pmod->cmd_buff_size = 0; - pmod->reserved1 = 0; - pmod->reserved2 = 0; - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, SET_PERF_MODES, - INVALID_CHANNEL,sizeof(gdth_perf_modes))) { - printk("GDT-HA %d: Interrupt coalescing activated\n", ha->hanum); - } - } -#endif - - /* detect number of buses - try new IOCTL */ - iocr = (gdth_raw_iochan_str *)ha->pscratch; - iocr->hdr.version = 0xffffffff; - iocr->hdr.list_entries = MAXBUS; - iocr->hdr.first_chan = 0; - iocr->hdr.last_chan = MAXBUS-1; - iocr->hdr.list_offset = GDTOFFSOF(gdth_raw_iochan_str, list[0]); - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_RAW_DESC, - INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) { - TRACE2(("IOCHAN_RAW_DESC supported!\n")); - ha->bus_cnt = iocr->hdr.chan_count; - for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { - if (iocr->list[bus_no].proc_id < MAXID) - ha->bus_id[bus_no] = iocr->list[bus_no].proc_id; - else - ha->bus_id[bus_no] = 0xff; - } - } else { - /* old method */ - chn = (gdth_getch_str *)ha->pscratch; - for (bus_no = 0; bus_no < MAXBUS; ++bus_no) { - chn->channel_no = bus_no; - if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, - SCSI_CHAN_CNT | L_CTRL_PATTERN, - IO_CHANNEL | INVALID_CHANNEL, - sizeof(gdth_getch_str))) { - if (bus_no == 0) { - printk("GDT-HA %d: Error detecting channel count (0x%x)\n", - ha->hanum, ha->status); - return 0; - } - break; - } - if (chn->siop_id < MAXID) - ha->bus_id[bus_no] = chn->siop_id; - else - ha->bus_id[bus_no] = 0xff; - } - ha->bus_cnt = (u8)bus_no; - } - TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt)); - - /* read cache configuration */ - if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_INFO, - INVALID_CHANNEL,sizeof(gdth_cinfo_str))) { - printk("GDT-HA %d: Initialization error cache service (code %d)\n", - ha->hanum, ha->status); - return 0; - } - ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar; - TRACE2(("gdth_search_drives() cinfo: vs %x sta %d str %d dw %d b %d\n", - ha->cpar.version,ha->cpar.state,ha->cpar.strategy, - ha->cpar.write_back,ha->cpar.block_size)); - - /* read board info and features */ - ha->more_proc = FALSE; - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_INFO, - INVALID_CHANNEL,sizeof(gdth_binfo_str))) { - memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch, - sizeof(gdth_binfo_str)); - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, BOARD_FEATURES, - INVALID_CHANNEL,sizeof(gdth_bfeat_str))) { - TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n")); - ha->bfeat = *(gdth_bfeat_str *)ha->pscratch; - ha->more_proc = TRUE; - } - } else { - TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n")); - strcpy(ha->binfo.type_string, gdth_ctr_name(ha)); - } - TRACE2(("Controller name: %s\n",ha->binfo.type_string)); - - /* read more informations */ - if (ha->more_proc) { - /* physical drives, channel addresses */ - ioc = (gdth_iochan_str *)ha->pscratch; - ioc->hdr.version = 0xffffffff; - ioc->hdr.list_entries = MAXBUS; - ioc->hdr.first_chan = 0; - ioc->hdr.last_chan = MAXBUS-1; - ioc->hdr.list_offset = GDTOFFSOF(gdth_iochan_str, list[0]); - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, IOCHAN_DESC, - INVALID_CHANNEL,sizeof(gdth_iochan_str))) { - for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { - ha->raw[bus_no].address = ioc->list[bus_no].address; - ha->raw[bus_no].local_no = ioc->list[bus_no].local_no; - } - } else { - for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { - ha->raw[bus_no].address = IO_CHANNEL; - ha->raw[bus_no].local_no = bus_no; - } - } - for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) { - chn = (gdth_getch_str *)ha->pscratch; - chn->channel_no = ha->raw[bus_no].local_no; - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, - SCSI_CHAN_CNT | L_CTRL_PATTERN, - ha->raw[bus_no].address | INVALID_CHANNEL, - sizeof(gdth_getch_str))) { - ha->raw[bus_no].pdev_cnt = chn->drive_cnt; - TRACE2(("Channel %d: %d phys. drives\n", - bus_no,chn->drive_cnt)); - } - if (ha->raw[bus_no].pdev_cnt > 0) { - drl = (gdth_drlist_str *)ha->pscratch; - drl->sc_no = ha->raw[bus_no].local_no; - drl->sc_cnt = ha->raw[bus_no].pdev_cnt; - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, - SCSI_DR_LIST | L_CTRL_PATTERN, - ha->raw[bus_no].address | INVALID_CHANNEL, - sizeof(gdth_drlist_str))) { - for (j = 0; j < ha->raw[bus_no].pdev_cnt; ++j) - ha->raw[bus_no].id_list[j] = drl->sc_list[j]; - } else { - ha->raw[bus_no].pdev_cnt = 0; - } - } - } - - /* logical drives */ - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_CNT, - INVALID_CHANNEL,sizeof(u32))) { - drv_cnt = *(u32 *)ha->pscratch; - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, CACHE_DRV_LIST, - INVALID_CHANNEL,drv_cnt * sizeof(u32))) { - for (j = 0; j < drv_cnt; ++j) { - drv_no = ((u32 *)ha->pscratch)[j]; - if (drv_no < MAX_LDRIVES) { - ha->hdr[drv_no].is_logdrv = TRUE; - TRACE2(("Drive %d is log. drive\n",drv_no)); - } - } - } - alst = (gdth_arcdl_str *)ha->pscratch; - alst->entries_avail = MAX_LDRIVES; - alst->first_entry = 0; - alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]); - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, - ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, - INVALID_CHANNEL, sizeof(gdth_arcdl_str) + - (alst->entries_avail-1) * sizeof(gdth_alist_str))) { - for (j = 0; j < alst->entries_init; ++j) { - ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd; - ha->hdr[j].is_master = alst->list[j].is_master; - ha->hdr[j].is_parity = alst->list[j].is_parity; - ha->hdr[j].is_hotfix = alst->list[j].is_hotfix; - ha->hdr[j].master_no = alst->list[j].cd_handle; - } - } else if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, - ARRAY_DRV_LIST | LA_CTRL_PATTERN, - 0, 35 * sizeof(gdth_alist_str))) { - for (j = 0; j < 35; ++j) { - alst2 = &((gdth_alist_str *)ha->pscratch)[j]; - ha->hdr[j].is_arraydrv = alst2->is_arrayd; - ha->hdr[j].is_master = alst2->is_master; - ha->hdr[j].is_parity = alst2->is_parity; - ha->hdr[j].is_hotfix = alst2->is_hotfix; - ha->hdr[j].master_no = alst2->cd_handle; - } - } - } - } - - /* initialize raw service */ - ha->raw_feat = 0; - if (!force_dma32) { - ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_X_INIT_RAW, 0, 0, 0); - if (ok) - ha->raw_feat = GDT_64BIT; - } - if (force_dma32 || (!ok && ha->status == (u16)S_NOFUNC)) - ok = gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_INIT, 0, 0, 0); - if (!ok) { - printk("GDT-HA %d: Initialization error raw service (code %d)\n", - ha->hanum, ha->status); - return 0; - } - TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n")); - - /* set/get features raw service (scatter/gather) */ - if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_SET_FEAT, SCATTER_GATHER, - 0, 0)) { - TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n")); - if (gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_GET_FEAT, 0, 0, 0)) { - TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n", - ha->info)); - ha->raw_feat |= (u16)ha->info; - } - } - - /* set/get features cache service (equal to raw service) */ - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_SET_FEAT, 0, - SCATTER_GATHER,0)) { - TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n")); - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_GET_FEAT, 0, 0, 0)) { - TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n", - ha->info)); - ha->cache_feat |= (u16)ha->info; - } - } - - /* reserve drives for raw service */ - if (reserve_mode != 0) { - gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE_ALL, - reserve_mode == 1 ? 1 : 3, 0, 0); - TRACE2(("gdth_search_drives(): RESERVE_ALL code %d\n", - ha->status)); - } - for (i = 0; i < MAX_RES_ARGS; i += 4) { - if (reserve_list[i] == ha->hanum && reserve_list[i+1] < ha->bus_cnt && - reserve_list[i+2] < ha->tid_cnt && reserve_list[i+3] < MAXLUN) { - TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d lun %d\n", - reserve_list[i], reserve_list[i+1], - reserve_list[i+2], reserve_list[i+3])); - if (!gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESERVE, 0, - reserve_list[i+1], reserve_list[i+2] | - (reserve_list[i+3] << 8))) { - printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n", - ha->hanum, ha->status); - } - } - } - - /* Determine OEM string using IOCTL */ - oemstr = (gdth_oem_str_ioctl *)ha->pscratch; - oemstr->params.ctl_version = 0x01; - oemstr->params.buffer_size = sizeof(oemstr->text); - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_IOCTL, - CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL, - sizeof(gdth_oem_str_ioctl))) { - TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n")); - printk("GDT-HA %d: Vendor: %s Name: %s\n", - ha->hanum, oemstr->text.oem_company_name, ha->binfo.type_string); - /* Save the Host Drive inquiry data */ - strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id, - sizeof(ha->oem_name)); - } else { - /* Old method, based on PCI ID */ - TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n")); - printk("GDT-HA %d: Name: %s\n", - ha->hanum, ha->binfo.type_string); - if (ha->oem_id == OEM_ID_INTEL) - strlcpy(ha->oem_name,"Intel ", sizeof(ha->oem_name)); - else - strlcpy(ha->oem_name,"ICP ", sizeof(ha->oem_name)); - } - - /* scanning for host drives */ - for (i = 0; i < cdev_cnt; ++i) - gdth_analyse_hdrive(ha, i); - - TRACE(("gdth_search_drives() OK\n")); - return 1; -} - -static int gdth_analyse_hdrive(gdth_ha_str *ha, u16 hdrive) -{ - u32 drv_cyls; - int drv_hds, drv_secs; - - TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n", ha->hanum, hdrive)); - if (hdrive >= MAX_HDRIVES) - return 0; - - if (!gdth_internal_cmd(ha, CACHESERVICE, GDT_INFO, hdrive, 0, 0)) - return 0; - ha->hdr[hdrive].present = TRUE; - ha->hdr[hdrive].size = ha->info; - - /* evaluate mapping (sectors per head, heads per cylinder) */ - ha->hdr[hdrive].size &= ~SECS32; - if (ha->info2 == 0) { - gdth_eval_mapping(ha->hdr[hdrive].size,&drv_cyls,&drv_hds,&drv_secs); - } else { - drv_hds = ha->info2 & 0xff; - drv_secs = (ha->info2 >> 8) & 0xff; - drv_cyls = (u32)ha->hdr[hdrive].size / drv_hds / drv_secs; - } - ha->hdr[hdrive].heads = (u8)drv_hds; - ha->hdr[hdrive].secs = (u8)drv_secs; - /* round size */ - ha->hdr[hdrive].size = drv_cyls * drv_hds * drv_secs; - - if (ha->cache_feat & GDT_64BIT) { - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_X_INFO, hdrive, 0, 0) - && ha->info2 != 0) { - ha->hdr[hdrive].size = ((u64)ha->info2 << 32) | ha->info; - } - } - TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n", - hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs)); - - /* get informations about device */ - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_DEVTYPE, hdrive, 0, 0)) { - TRACE2(("gdth_search_dr() cache drive %d devtype %d\n", - hdrive,ha->info)); - ha->hdr[hdrive].devtype = (u16)ha->info; - } - - /* cluster info */ - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_CLUST_INFO, hdrive, 0, 0)) { - TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n", - hdrive,ha->info)); - if (!shared_access) - ha->hdr[hdrive].cluster_type = (u8)ha->info; - } - - /* R/W attributes */ - if (gdth_internal_cmd(ha, CACHESERVICE, GDT_RW_ATTRIBS, hdrive, 0, 0)) { - TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n", - hdrive,ha->info)); - ha->hdr[hdrive].rw_attribs = (u8)ha->info; - } - - return 1; -} - - -/* command queueing/sending functions */ - -static void gdth_putq(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 priority) -{ - struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - register Scsi_Cmnd *pscp; - register Scsi_Cmnd *nscp; - unsigned long flags; - - TRACE(("gdth_putq() priority %d\n",priority)); - spin_lock_irqsave(&ha->smp_lock, flags); - - if (!cmndinfo->internal_command) - cmndinfo->priority = priority; - - if (ha->req_first==NULL) { - ha->req_first = scp; /* queue was empty */ - scp->SCp.ptr = NULL; - } else { /* queue not empty */ - pscp = ha->req_first; - nscp = (Scsi_Cmnd *)pscp->SCp.ptr; - /* priority: 0-highest,..,0xff-lowest */ - while (nscp && gdth_cmnd_priv(nscp)->priority <= priority) { - pscp = nscp; - nscp = (Scsi_Cmnd *)pscp->SCp.ptr; - } - pscp->SCp.ptr = (char *)scp; - scp->SCp.ptr = (char *)nscp; - } - spin_unlock_irqrestore(&ha->smp_lock, flags); - -#ifdef GDTH_STATISTICS - flags = 0; - for (nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr) - ++flags; - if (max_rq < flags) { - max_rq = flags; - TRACE3(("GDT: max_rq = %d\n",(u16)max_rq)); - } -#endif -} - -static void gdth_next(gdth_ha_str *ha) -{ - register Scsi_Cmnd *pscp; - register Scsi_Cmnd *nscp; - u8 b, t, l, firsttime; - u8 this_cmd, next_cmd; - unsigned long flags = 0; - int cmd_index; - - TRACE(("gdth_next() hanum %d\n", ha->hanum)); - if (!gdth_polling) - spin_lock_irqsave(&ha->smp_lock, flags); - - ha->cmd_cnt = ha->cmd_offs_dpmem = 0; - this_cmd = firsttime = TRUE; - next_cmd = gdth_polling ? FALSE:TRUE; - cmd_index = 0; - - for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) { - struct gdth_cmndinfo *nscp_cmndinfo = gdth_cmnd_priv(nscp); - if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr) - pscp = (Scsi_Cmnd *)pscp->SCp.ptr; - if (!nscp_cmndinfo->internal_command) { - b = nscp->device->channel; - t = nscp->device->id; - l = nscp->device->lun; - if (nscp_cmndinfo->priority >= DEFAULT_PRI) { - if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) || - (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) - continue; - } - } else - b = t = l = 0; - - if (firsttime) { - if (gdth_test_busy(ha)) { /* controller busy ? */ - TRACE(("gdth_next() controller %d busy !\n", ha->hanum)); - if (!gdth_polling) { - spin_unlock_irqrestore(&ha->smp_lock, flags); - return; - } - while (gdth_test_busy(ha)) - gdth_delay(1); - } - firsttime = FALSE; - } - - if (!nscp_cmndinfo->internal_command) { - if (nscp_cmndinfo->phase == -1) { - nscp_cmndinfo->phase = CACHESERVICE; /* default: cache svc. */ - if (nscp->cmnd[0] == TEST_UNIT_READY) { - TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", - b, t, l)); - /* TEST_UNIT_READY -> set scan mode */ - if ((ha->scan_mode & 0x0f) == 0) { - if (b == 0 && t == 0 && l == 0) { - ha->scan_mode |= 1; - TRACE2(("Scan mode: 0x%x\n", ha->scan_mode)); - } - } else if ((ha->scan_mode & 0x0f) == 1) { - if (b == 0 && ((t == 0 && l == 1) || - (t == 1 && l == 0))) { - nscp_cmndinfo->OpCode = GDT_SCAN_START; - nscp_cmndinfo->phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) - | SCSIRAWSERVICE; - ha->scan_mode = 0x12; - TRACE2(("Scan mode: 0x%x (SCAN_START)\n", - ha->scan_mode)); - } else { - ha->scan_mode &= 0x10; - TRACE2(("Scan mode: 0x%x\n", ha->scan_mode)); - } - } else if (ha->scan_mode == 0x12) { - if (b == ha->bus_cnt && t == ha->tid_cnt-1) { - nscp_cmndinfo->phase = SCSIRAWSERVICE; - nscp_cmndinfo->OpCode = GDT_SCAN_END; - ha->scan_mode &= 0x10; - TRACE2(("Scan mode: 0x%x (SCAN_END)\n", - ha->scan_mode)); - } - } - } - if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY && - nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE && - (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) { - /* always GDT_CLUST_INFO! */ - nscp_cmndinfo->OpCode = GDT_CLUST_INFO; - } - } - } - - if (nscp_cmndinfo->OpCode != -1) { - if ((nscp_cmndinfo->phase & 0xff) == CACHESERVICE) { - if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) - this_cmd = FALSE; - next_cmd = FALSE; - } else if ((nscp_cmndinfo->phase & 0xff) == SCSIRAWSERVICE) { - if (!(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b)))) - this_cmd = FALSE; - next_cmd = FALSE; - } else { - memset((char*)nscp->sense_buffer,0,16); - nscp->sense_buffer[0] = 0x70; - nscp->sense_buffer[2] = NOT_READY; - nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - if (!nscp_cmndinfo->wait_for_completion) - nscp_cmndinfo->wait_for_completion++; - else - gdth_scsi_done(nscp); - } - } else if (gdth_cmnd_priv(nscp)->internal_command) { - if (!(cmd_index=gdth_special_cmd(ha, nscp))) - this_cmd = FALSE; - next_cmd = FALSE; - } else if (b != ha->virt_bus) { - if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW || - !(cmd_index=gdth_fill_raw_cmd(ha, nscp, BUS_L2P(ha, b)))) - this_cmd = FALSE; - else - ha->raw[BUS_L2P(ha,b)].io_cnt[t]++; - } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || l != 0) { - TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n", - nscp->cmnd[0], b, t, l)); - nscp->result = DID_BAD_TARGET << 16; - if (!nscp_cmndinfo->wait_for_completion) - nscp_cmndinfo->wait_for_completion++; - else - gdth_scsi_done(nscp); - } else { - switch (nscp->cmnd[0]) { - case TEST_UNIT_READY: - case INQUIRY: - case REQUEST_SENSE: - case READ_CAPACITY: - case VERIFY: - case START_STOP: - case MODE_SENSE: - case SERVICE_ACTION_IN: - TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0], - nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], - nscp->cmnd[4],nscp->cmnd[5])); - if (ha->hdr[t].media_changed && nscp->cmnd[0] != INQUIRY) { - /* return UNIT_ATTENTION */ - TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", - nscp->cmnd[0], t)); - ha->hdr[t].media_changed = FALSE; - memset((char*)nscp->sense_buffer,0,16); - nscp->sense_buffer[0] = 0x70; - nscp->sense_buffer[2] = UNIT_ATTENTION; - nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - if (!nscp_cmndinfo->wait_for_completion) - nscp_cmndinfo->wait_for_completion++; - else - gdth_scsi_done(nscp); - } else if (gdth_internal_cache_cmd(ha, nscp)) - gdth_scsi_done(nscp); - break; - - case ALLOW_MEDIUM_REMOVAL: - TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0], - nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], - nscp->cmnd[4],nscp->cmnd[5])); - if ( (nscp->cmnd[4]&1) && !(ha->hdr[t].devtype&1) ) { - TRACE(("Prevent r. nonremov. drive->do nothing\n")); - nscp->result = DID_OK << 16; - nscp->sense_buffer[0] = 0; - if (!nscp_cmndinfo->wait_for_completion) - nscp_cmndinfo->wait_for_completion++; - else - gdth_scsi_done(nscp); - } else { - nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0; - TRACE(("Prevent/allow r. %d rem. drive %d\n", - nscp->cmnd[4],nscp->cmnd[3])); - if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) - this_cmd = FALSE; - } - break; - - case RESERVE: - case RELEASE: - TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ? - "RESERVE" : "RELEASE")); - if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) - this_cmd = FALSE; - break; - - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_16: - case WRITE_16: - if (ha->hdr[t].media_changed) { - /* return UNIT_ATTENTION */ - TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n", - nscp->cmnd[0], t)); - ha->hdr[t].media_changed = FALSE; - memset((char*)nscp->sense_buffer,0,16); - nscp->sense_buffer[0] = 0x70; - nscp->sense_buffer[2] = UNIT_ATTENTION; - nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - if (!nscp_cmndinfo->wait_for_completion) - nscp_cmndinfo->wait_for_completion++; - else - gdth_scsi_done(nscp); - } else if (!(cmd_index=gdth_fill_cache_cmd(ha, nscp, t))) - this_cmd = FALSE; - break; - - default: - TRACE2(("cache cmd %x/%x/%x/%x/%x/%x unknown\n",nscp->cmnd[0], - nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3], - nscp->cmnd[4],nscp->cmnd[5])); - printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n", - ha->hanum, nscp->cmnd[0]); - nscp->result = DID_ABORT << 16; - if (!nscp_cmndinfo->wait_for_completion) - nscp_cmndinfo->wait_for_completion++; - else - gdth_scsi_done(nscp); - break; - } - } - - if (!this_cmd) - break; - if (nscp == ha->req_first) - ha->req_first = pscp = (Scsi_Cmnd *)nscp->SCp.ptr; - else - pscp->SCp.ptr = nscp->SCp.ptr; - if (!next_cmd) - break; - } - - if (ha->cmd_cnt > 0) { - gdth_release_event(ha); - } - - if (!gdth_polling) - spin_unlock_irqrestore(&ha->smp_lock, flags); - - if (gdth_polling && ha->cmd_cnt > 0) { - if (!gdth_wait(ha, cmd_index, POLL_TIMEOUT)) - printk("GDT-HA %d: Command %d timed out !\n", - ha->hanum, cmd_index); - } -} - -/* - * gdth_copy_internal_data() - copy to/from a buffer onto a scsi_cmnd's - * buffers, kmap_atomic() as needed. - */ -static void gdth_copy_internal_data(gdth_ha_str *ha, Scsi_Cmnd *scp, - char *buffer, u16 count) -{ - u16 cpcount,i, max_sg = scsi_sg_count(scp); - u16 cpsum,cpnow; - struct scatterlist *sl; - char *address; - - cpcount = min_t(u16, count, scsi_bufflen(scp)); - - if (cpcount) { - cpsum=0; - scsi_for_each_sg(scp, sl, max_sg, i) { - unsigned long flags; - cpnow = (u16)sl->length; - TRACE(("copy_internal() now %d sum %d count %d %d\n", - cpnow, cpsum, cpcount, scsi_bufflen(scp))); - if (cpsum+cpnow > cpcount) - cpnow = cpcount - cpsum; - cpsum += cpnow; - if (!sg_page(sl)) { - printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n", - ha->hanum); - return; - } - local_irq_save(flags); - address = kmap_atomic(sg_page(sl)) + sl->offset; - memcpy(address, buffer, cpnow); - flush_dcache_page(sg_page(sl)); - kunmap_atomic(address); - local_irq_restore(flags); - if (cpsum == cpcount) - break; - buffer += cpnow; - } - } else if (count) { - printk("GDT-HA %d: SCSI command with no buffers but data transfer expected!\n", - ha->hanum); - WARN_ON(1); - } -} - -static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) -{ - u8 t; - gdth_inq_data inq; - gdth_rdcap_data rdc; - gdth_sense_data sd; - gdth_modep_data mpd; - struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - - t = scp->device->id; - TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n", - scp->cmnd[0],t)); - - scp->result = DID_OK << 16; - scp->sense_buffer[0] = 0; - - switch (scp->cmnd[0]) { - case TEST_UNIT_READY: - case VERIFY: - case START_STOP: - TRACE2(("Test/Verify/Start hdrive %d\n",t)); - break; - - case INQUIRY: - TRACE2(("Inquiry hdrive %d devtype %d\n", - t,ha->hdr[t].devtype)); - inq.type_qual = (ha->hdr[t].devtype&4) ? TYPE_ROM:TYPE_DISK; - /* you can here set all disks to removable, if you want to do - a flush using the ALLOW_MEDIUM_REMOVAL command */ - inq.modif_rmb = 0x00; - if ((ha->hdr[t].devtype & 1) || - (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) - inq.modif_rmb = 0x80; - inq.version = 2; - inq.resp_aenc = 2; - inq.add_length= 32; - strcpy(inq.vendor,ha->oem_name); - sprintf(inq.product,"Host Drive #%02d",t); - strcpy(inq.revision," "); - gdth_copy_internal_data(ha, scp, (char*)&inq, sizeof(gdth_inq_data)); - break; - - case REQUEST_SENSE: - TRACE2(("Request sense hdrive %d\n",t)); - sd.errorcode = 0x70; - sd.segno = 0x00; - sd.key = NO_SENSE; - sd.info = 0; - sd.add_length= 0; - gdth_copy_internal_data(ha, scp, (char*)&sd, sizeof(gdth_sense_data)); - break; - - case MODE_SENSE: - TRACE2(("Mode sense hdrive %d\n",t)); - memset((char*)&mpd,0,sizeof(gdth_modep_data)); - mpd.hd.data_length = sizeof(gdth_modep_data); - mpd.hd.dev_par = (ha->hdr[t].devtype&2) ? 0x80:0; - mpd.hd.bd_length = sizeof(mpd.bd); - mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16; - mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8; - mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff); - gdth_copy_internal_data(ha, scp, (char*)&mpd, sizeof(gdth_modep_data)); - break; - - case READ_CAPACITY: - TRACE2(("Read capacity hdrive %d\n",t)); - if (ha->hdr[t].size > (u64)0xffffffff) - rdc.last_block_no = 0xffffffff; - else - rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1); - rdc.block_length = cpu_to_be32(SECTOR_SIZE); - gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data)); - break; - - case SERVICE_ACTION_IN: - if ((scp->cmnd[1] & 0x1f) == SAI_READ_CAPACITY_16 && - (ha->cache_feat & GDT_64BIT)) { - gdth_rdcap16_data rdc16; - - TRACE2(("Read capacity (16) hdrive %d\n",t)); - rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1); - rdc16.block_length = cpu_to_be32(SECTOR_SIZE); - gdth_copy_internal_data(ha, scp, (char*)&rdc16, - sizeof(gdth_rdcap16_data)); - } else { - scp->result = DID_ABORT << 16; - } - break; - - default: - TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0])); - break; - } - - if (!cmndinfo->wait_for_completion) - cmndinfo->wait_for_completion++; - else - return 1; - - return 0; -} - -static int gdth_fill_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u16 hdrive) -{ - register gdth_cmd_str *cmdp; - struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - u32 cnt, blockcnt; - u64 no, blockno; - int i, cmd_index, read_write, sgcnt, mode64; - - cmdp = ha->pccb; - TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n", - scp->cmnd[0],scp->cmd_len,hdrive)); - - if (ha->type==GDT_EISA && ha->cmd_cnt>0) - return 0; - - mode64 = (ha->cache_feat & GDT_64BIT) ? TRUE : FALSE; - /* test for READ_16, WRITE_16 if !mode64 ? --- - not required, should not occur due to error return on - READ_CAPACITY_16 */ - - cmdp->Service = CACHESERVICE; - cmdp->RequestBuffer = scp; - /* search free command index */ - if (!(cmd_index=gdth_get_cmd_index(ha))) { - TRACE(("GDT: No free command index found\n")); - return 0; - } - /* if it's the first command, set command semaphore */ - if (ha->cmd_cnt == 0) - gdth_set_sema0(ha); - - /* fill command */ - read_write = 0; - if (cmndinfo->OpCode != -1) - cmdp->OpCode = cmndinfo->OpCode; /* special cache cmd. */ - else if (scp->cmnd[0] == RESERVE) - cmdp->OpCode = GDT_RESERVE_DRV; - else if (scp->cmnd[0] == RELEASE) - cmdp->OpCode = GDT_RELEASE_DRV; - else if (scp->cmnd[0] == ALLOW_MEDIUM_REMOVAL) { - if (scp->cmnd[4] & 1) /* prevent ? */ - cmdp->OpCode = GDT_MOUNT; - else if (scp->cmnd[3] & 1) /* removable drive ? */ - cmdp->OpCode = GDT_UNMOUNT; - else - cmdp->OpCode = GDT_FLUSH; - } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10 || - scp->cmnd[0] == WRITE_12 || scp->cmnd[0] == WRITE_16 - ) { - read_write = 1; - if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && - (ha->cache_feat & GDT_WR_THROUGH))) - cmdp->OpCode = GDT_WRITE_THR; - else - cmdp->OpCode = GDT_WRITE; - } else { - read_write = 2; - cmdp->OpCode = GDT_READ; - } - - cmdp->BoardNode = LOCALBOARD; - if (mode64) { - cmdp->u.cache64.DeviceNo = hdrive; - cmdp->u.cache64.BlockNo = 1; - cmdp->u.cache64.sg_canz = 0; - } else { - cmdp->u.cache.DeviceNo = hdrive; - cmdp->u.cache.BlockNo = 1; - cmdp->u.cache.sg_canz = 0; - } - - if (read_write) { - if (scp->cmd_len == 16) { - memcpy(&no, &scp->cmnd[2], sizeof(u64)); - blockno = be64_to_cpu(no); - memcpy(&cnt, &scp->cmnd[10], sizeof(u32)); - blockcnt = be32_to_cpu(cnt); - } else if (scp->cmd_len == 10) { - memcpy(&no, &scp->cmnd[2], sizeof(u32)); - blockno = be32_to_cpu(no); - memcpy(&cnt, &scp->cmnd[7], sizeof(u16)); - blockcnt = be16_to_cpu(cnt); - } else { - memcpy(&no, &scp->cmnd[0], sizeof(u32)); - blockno = be32_to_cpu(no) & 0x001fffffUL; - blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4]; - } - if (mode64) { - cmdp->u.cache64.BlockNo = blockno; - cmdp->u.cache64.BlockCnt = blockcnt; - } else { - cmdp->u.cache.BlockNo = (u32)blockno; - cmdp->u.cache.BlockCnt = blockcnt; - } - - if (scsi_bufflen(scp)) { - cmndinfo->dma_dir = (read_write == 1 ? - PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - sgcnt = pci_map_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), - cmndinfo->dma_dir); - if (mode64) { - struct scatterlist *sl; - - cmdp->u.cache64.DestAddr= (u64)-1; - cmdp->u.cache64.sg_canz = sgcnt; - scsi_for_each_sg(scp, sl, sgcnt, i) { - cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl); -#ifdef GDTH_DMA_STATISTICS - if (cmdp->u.cache64.sg_lst[i].sg_ptr > (u64)0xffffffff) - ha->dma64_cnt++; - else - ha->dma32_cnt++; -#endif - cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl); - } - } else { - struct scatterlist *sl; - - cmdp->u.cache.DestAddr= 0xffffffff; - cmdp->u.cache.sg_canz = sgcnt; - scsi_for_each_sg(scp, sl, sgcnt, i) { - cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl); -#ifdef GDTH_DMA_STATISTICS - ha->dma32_cnt++; -#endif - cmdp->u.cache.sg_lst[i].sg_len = sg_dma_len(sl); - } - } - -#ifdef GDTH_STATISTICS - if (max_sg < (u32)sgcnt) { - max_sg = (u32)sgcnt; - TRACE3(("GDT: max_sg = %d\n",max_sg)); - } -#endif - - } - } - /* evaluate command size, check space */ - if (mode64) { - TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", - cmdp->u.cache64.DestAddr,cmdp->u.cache64.sg_canz, - cmdp->u.cache64.sg_lst[0].sg_ptr, - cmdp->u.cache64.sg_lst[0].sg_len)); - TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", - cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt)); - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + - (u16)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str); - } else { - TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", - cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz, - cmdp->u.cache.sg_lst[0].sg_ptr, - cmdp->u.cache.sg_lst[0].sg_len)); - TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n", - cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt)); - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + - (u16)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str); - } - if (ha->cmd_len & 3) - ha->cmd_len += (4 - (ha->cmd_len & 3)); - - if (ha->cmd_cnt > 0) { - if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) > - ha->ic_all_size) { - TRACE2(("gdth_fill_cache() DPMEM overflow\n")); - ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND; - return 0; - } - } - - /* copy command */ - gdth_copy_command(ha); - return cmd_index; -} - -static int gdth_fill_raw_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp, u8 b) -{ - register gdth_cmd_str *cmdp; - u16 i; - dma_addr_t sense_paddr; - int cmd_index, sgcnt, mode64; - u8 t,l; - struct page *page; - unsigned long offset; - struct gdth_cmndinfo *cmndinfo; - - t = scp->device->id; - l = scp->device->lun; - cmdp = ha->pccb; - TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n", - scp->cmnd[0],b,t,l)); - - if (ha->type==GDT_EISA && ha->cmd_cnt>0) - return 0; - - mode64 = (ha->raw_feat & GDT_64BIT) ? TRUE : FALSE; - - cmdp->Service = SCSIRAWSERVICE; - cmdp->RequestBuffer = scp; - /* search free command index */ - if (!(cmd_index=gdth_get_cmd_index(ha))) { - TRACE(("GDT: No free command index found\n")); - return 0; - } - /* if it's the first command, set command semaphore */ - if (ha->cmd_cnt == 0) - gdth_set_sema0(ha); - - cmndinfo = gdth_cmnd_priv(scp); - /* fill command */ - if (cmndinfo->OpCode != -1) { - cmdp->OpCode = cmndinfo->OpCode; /* special raw cmd. */ - cmdp->BoardNode = LOCALBOARD; - if (mode64) { - cmdp->u.raw64.direction = (cmndinfo->phase >> 8); - TRACE2(("special raw cmd 0x%x param 0x%x\n", - cmdp->OpCode, cmdp->u.raw64.direction)); - /* evaluate command size */ - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst); - } else { - cmdp->u.raw.direction = (cmndinfo->phase >> 8); - TRACE2(("special raw cmd 0x%x param 0x%x\n", - cmdp->OpCode, cmdp->u.raw.direction)); - /* evaluate command size */ - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst); - } - - } else { - page = virt_to_page(scp->sense_buffer); - offset = (unsigned long)scp->sense_buffer & ~PAGE_MASK; - sense_paddr = pci_map_page(ha->pdev,page,offset, - 16,PCI_DMA_FROMDEVICE); - - cmndinfo->sense_paddr = sense_paddr; - cmdp->OpCode = GDT_WRITE; /* always */ - cmdp->BoardNode = LOCALBOARD; - if (mode64) { - cmdp->u.raw64.reserved = 0; - cmdp->u.raw64.mdisc_time = 0; - cmdp->u.raw64.mcon_time = 0; - cmdp->u.raw64.clen = scp->cmd_len; - cmdp->u.raw64.target = t; - cmdp->u.raw64.lun = l; - cmdp->u.raw64.bus = b; - cmdp->u.raw64.priority = 0; - cmdp->u.raw64.sdlen = scsi_bufflen(scp); - cmdp->u.raw64.sense_len = 16; - cmdp->u.raw64.sense_data = sense_paddr; - cmdp->u.raw64.direction = - gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN; - memcpy(cmdp->u.raw64.cmd,scp->cmnd,16); - cmdp->u.raw64.sg_ranz = 0; - } else { - cmdp->u.raw.reserved = 0; - cmdp->u.raw.mdisc_time = 0; - cmdp->u.raw.mcon_time = 0; - cmdp->u.raw.clen = scp->cmd_len; - cmdp->u.raw.target = t; - cmdp->u.raw.lun = l; - cmdp->u.raw.bus = b; - cmdp->u.raw.priority = 0; - cmdp->u.raw.link_p = 0; - cmdp->u.raw.sdlen = scsi_bufflen(scp); - cmdp->u.raw.sense_len = 16; - cmdp->u.raw.sense_data = sense_paddr; - cmdp->u.raw.direction = - gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN; - memcpy(cmdp->u.raw.cmd,scp->cmnd,12); - cmdp->u.raw.sg_ranz = 0; - } - - if (scsi_bufflen(scp)) { - cmndinfo->dma_dir = PCI_DMA_BIDIRECTIONAL; - sgcnt = pci_map_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), - cmndinfo->dma_dir); - if (mode64) { - struct scatterlist *sl; - - cmdp->u.raw64.sdata = (u64)-1; - cmdp->u.raw64.sg_ranz = sgcnt; - scsi_for_each_sg(scp, sl, sgcnt, i) { - cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl); -#ifdef GDTH_DMA_STATISTICS - if (cmdp->u.raw64.sg_lst[i].sg_ptr > (u64)0xffffffff) - ha->dma64_cnt++; - else - ha->dma32_cnt++; -#endif - cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl); - } - } else { - struct scatterlist *sl; - - cmdp->u.raw.sdata = 0xffffffff; - cmdp->u.raw.sg_ranz = sgcnt; - scsi_for_each_sg(scp, sl, sgcnt, i) { - cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl); -#ifdef GDTH_DMA_STATISTICS - ha->dma32_cnt++; -#endif - cmdp->u.raw.sg_lst[i].sg_len = sg_dma_len(sl); - } - } - -#ifdef GDTH_STATISTICS - if (max_sg < sgcnt) { - max_sg = sgcnt; - TRACE3(("GDT: max_sg = %d\n",sgcnt)); - } -#endif - - } - if (mode64) { - TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", - cmdp->u.raw64.sdata,cmdp->u.raw64.sg_ranz, - cmdp->u.raw64.sg_lst[0].sg_ptr, - cmdp->u.raw64.sg_lst[0].sg_len)); - /* evaluate command size */ - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + - (u16)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str); - } else { - TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n", - cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz, - cmdp->u.raw.sg_lst[0].sg_ptr, - cmdp->u.raw.sg_lst[0].sg_len)); - /* evaluate command size */ - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + - (u16)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str); - } - } - /* check space */ - if (ha->cmd_len & 3) - ha->cmd_len += (4 - (ha->cmd_len & 3)); - - if (ha->cmd_cnt > 0) { - if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) > - ha->ic_all_size) { - TRACE2(("gdth_fill_raw() DPMEM overflow\n")); - ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND; - return 0; - } - } - - /* copy command */ - gdth_copy_command(ha); - return cmd_index; -} - -static int gdth_special_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp) -{ - register gdth_cmd_str *cmdp; - struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - int cmd_index; - - cmdp= ha->pccb; - TRACE2(("gdth_special_cmd(): ")); - - if (ha->type==GDT_EISA && ha->cmd_cnt>0) - return 0; - - *cmdp = *cmndinfo->internal_cmd_str; - cmdp->RequestBuffer = scp; - - /* search free command index */ - if (!(cmd_index=gdth_get_cmd_index(ha))) { - TRACE(("GDT: No free command index found\n")); - return 0; - } - - /* if it's the first command, set command semaphore */ - if (ha->cmd_cnt == 0) - gdth_set_sema0(ha); - - /* evaluate command size, check space */ - if (cmdp->OpCode == GDT_IOCTL) { - TRACE2(("IOCTL\n")); - ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(u64); - } else if (cmdp->Service == CACHESERVICE) { - TRACE2(("cache command %d\n",cmdp->OpCode)); - if (ha->cache_feat & GDT_64BIT) - ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + sizeof(gdth_sg64_str); - else - ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str); - } else if (cmdp->Service == SCSIRAWSERVICE) { - TRACE2(("raw command %d\n",cmdp->OpCode)); - if (ha->raw_feat & GDT_64BIT) - ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + sizeof(gdth_sg64_str); - else - ha->cmd_len = - GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str); - } - - if (ha->cmd_len & 3) - ha->cmd_len += (4 - (ha->cmd_len & 3)); - - if (ha->cmd_cnt > 0) { - if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) > - ha->ic_all_size) { - TRACE2(("gdth_special_cmd() DPMEM overflow\n")); - ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND; - return 0; - } - } - - /* copy command */ - gdth_copy_command(ha); - return cmd_index; -} - - -/* Controller event handling functions */ -static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, u16 source, - u16 idx, gdth_evt_data *evt) -{ - gdth_evt_str *e; - struct timeval tv; - - /* no GDTH_LOCK_HA() ! */ - TRACE2(("gdth_store_event() source %d idx %d\n", source, idx)); - if (source == 0) /* no source -> no event */ - return NULL; - - if (ebuffer[elastidx].event_source == source && - ebuffer[elastidx].event_idx == idx && - ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 && - !memcmp((char *)&ebuffer[elastidx].event_data.eu, - (char *)&evt->eu, evt->size)) || - (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 && - !strcmp((char *)&ebuffer[elastidx].event_data.event_string, - (char *)&evt->event_string)))) { - e = &ebuffer[elastidx]; - do_gettimeofday(&tv); - e->last_stamp = tv.tv_sec; - ++e->same_count; - } else { - if (ebuffer[elastidx].event_source != 0) { /* entry not free ? */ - ++elastidx; - if (elastidx == MAX_EVENTS) - elastidx = 0; - if (elastidx == eoldidx) { /* reached mark ? */ - ++eoldidx; - if (eoldidx == MAX_EVENTS) - eoldidx = 0; - } - } - e = &ebuffer[elastidx]; - e->event_source = source; - e->event_idx = idx; - do_gettimeofday(&tv); - e->first_stamp = e->last_stamp = tv.tv_sec; - e->same_count = 1; - e->event_data = *evt; - e->application = 0; - } - return e; -} - -static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr) -{ - gdth_evt_str *e; - int eindex; - unsigned long flags; - - TRACE2(("gdth_read_event() handle %d\n", handle)); - spin_lock_irqsave(&ha->smp_lock, flags); - if (handle == -1) - eindex = eoldidx; - else - eindex = handle; - estr->event_source = 0; - - if (eindex < 0 || eindex >= MAX_EVENTS) { - spin_unlock_irqrestore(&ha->smp_lock, flags); - return eindex; - } - e = &ebuffer[eindex]; - if (e->event_source != 0) { - if (eindex != elastidx) { - if (++eindex == MAX_EVENTS) - eindex = 0; - } else { - eindex = -1; - } - memcpy(estr, e, sizeof(gdth_evt_str)); - } - spin_unlock_irqrestore(&ha->smp_lock, flags); - return eindex; -} - -static void gdth_readapp_event(gdth_ha_str *ha, - u8 application, gdth_evt_str *estr) -{ - gdth_evt_str *e; - int eindex; - unsigned long flags; - u8 found = FALSE; - - TRACE2(("gdth_readapp_event() app. %d\n", application)); - spin_lock_irqsave(&ha->smp_lock, flags); - eindex = eoldidx; - for (;;) { - e = &ebuffer[eindex]; - if (e->event_source == 0) - break; - if ((e->application & application) == 0) { - e->application |= application; - found = TRUE; - break; - } - if (eindex == elastidx) - break; - if (++eindex == MAX_EVENTS) - eindex = 0; - } - if (found) - memcpy(estr, e, sizeof(gdth_evt_str)); - else - estr->event_source = 0; - spin_unlock_irqrestore(&ha->smp_lock, flags); -} - -static void gdth_clear_events(void) -{ - TRACE(("gdth_clear_events()")); - - eoldidx = elastidx = 0; - ebuffer[0].event_source = 0; -} - - -/* SCSI interface functions */ - -static irqreturn_t __gdth_interrupt(gdth_ha_str *ha, - int gdth_from_wait, int* pIndex) -{ - gdt6m_dpram_str __iomem *dp6m_ptr = NULL; - gdt6_dpram_str __iomem *dp6_ptr; - gdt2_dpram_str __iomem *dp2_ptr; - Scsi_Cmnd *scp; - int rval, i; - u8 IStatus; - u16 Service; - unsigned long flags = 0; -#ifdef INT_COAL - int coalesced = FALSE; - int next = FALSE; - gdth_coal_status *pcs = NULL; - int act_int_coal = 0; -#endif - - TRACE(("gdth_interrupt() IRQ %d\n", ha->irq)); - - /* if polling and not from gdth_wait() -> return */ - if (gdth_polling) { - if (!gdth_from_wait) { - return IRQ_HANDLED; - } - } - - if (!gdth_polling) - spin_lock_irqsave(&ha->smp_lock, flags); - - /* search controller */ - IStatus = gdth_get_status(ha); - if (IStatus == 0) { - /* spurious interrupt */ - if (!gdth_polling) - spin_unlock_irqrestore(&ha->smp_lock, flags); - return IRQ_HANDLED; - } - -#ifdef GDTH_STATISTICS - ++act_ints; -#endif - -#ifdef INT_COAL - /* See if the fw is returning coalesced status */ - if (IStatus == COALINDEX) { - /* Coalesced status. Setup the initial status - buffer pointer and flags */ - pcs = ha->coal_stat; - coalesced = TRUE; - next = TRUE; - } - - do { - if (coalesced) { - /* For coalesced requests all status - information is found in the status buffer */ - IStatus = (u8)(pcs->status & 0xff); - } -#endif - - if (ha->type == GDT_EISA) { - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = inw(ha->bmic + MAILBOXREG+8); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = inl(ha->bmic + MAILBOXREG+12); - ha->service = inw(ha->bmic + MAILBOXREG+10); - ha->info2 = inl(ha->bmic + MAILBOXREG+4); - - outb(0xff, ha->bmic + EDOORREG); /* acknowledge interrupt */ - outb(0x00, ha->bmic + SEMA1REG); /* reset status semaphore */ - } else if (ha->type == GDT_ISA) { - dp2_ptr = ha->brd; - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = readw(&dp2_ptr->u.ic.Status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = readl(&dp2_ptr->u.ic.Info[0]); - ha->service = readw(&dp2_ptr->u.ic.Service); - ha->info2 = readl(&dp2_ptr->u.ic.Info[1]); - - writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */ - writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */ - writeb(0, &dp2_ptr->io.Sema1); /* reset status semaphore */ - } else if (ha->type == GDT_PCI) { - dp6_ptr = ha->brd; - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = readw(&dp6_ptr->u.ic.Status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; - ha->info = readl(&dp6_ptr->u.ic.Info[0]); - ha->service = readw(&dp6_ptr->u.ic.Service); - ha->info2 = readl(&dp6_ptr->u.ic.Info[1]); - - writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */ - writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */ - writeb(0, &dp6_ptr->io.Sema1); /* reset status semaphore */ - } else if (ha->type == GDT_PCINEW) { - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; - ha->status = inw(PTR2USHORT(&ha->plx->status)); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else - ha->status = S_OK; - ha->info = inl(PTR2USHORT(&ha->plx->info[0])); - ha->service = inw(PTR2USHORT(&ha->plx->service)); - ha->info2 = inl(PTR2USHORT(&ha->plx->info[1])); - - outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); - outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); - } else if (ha->type == GDT_PCIMPR) { - dp6m_ptr = ha->brd; - if (IStatus & 0x80) { /* error flag */ - IStatus &= ~0x80; -#ifdef INT_COAL - if (coalesced) - ha->status = pcs->ext_status & 0xffff; - else -#endif - ha->status = readw(&dp6m_ptr->i960r.status); - TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status)); - } else /* no error */ - ha->status = S_OK; -#ifdef INT_COAL - /* get information */ - if (coalesced) { - ha->info = pcs->info0; - ha->info2 = pcs->info1; - ha->service = (pcs->ext_status >> 16) & 0xffff; - } else -#endif - { - ha->info = readl(&dp6m_ptr->i960r.info[0]); - ha->service = readw(&dp6m_ptr->i960r.service); - ha->info2 = readl(&dp6m_ptr->i960r.info[1]); - } - /* event string */ - if (IStatus == ASYNCINDEX) { - if (ha->service != SCREENSERVICE && - (ha->fw_vers & 0xff) >= 0x1a) { - ha->dvr.severity = readb - (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity); - for (i = 0; i < 256; ++i) { - ha->dvr.event_string[i] = readb - (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]); - if (ha->dvr.event_string[i] == 0) - break; - } - } - } -#ifdef INT_COAL - /* Make sure that non coalesced interrupts get cleared - before being handled by gdth_async_event/gdth_sync_event */ - if (!coalesced) -#endif - { - writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - writeb(0, &dp6m_ptr->i960r.sema1_reg); - } - } else { - TRACE2(("gdth_interrupt() unknown controller type\n")); - if (!gdth_polling) - spin_unlock_irqrestore(&ha->smp_lock, flags); - return IRQ_HANDLED; - } - - TRACE(("gdth_interrupt() index %d stat %d info %d\n", - IStatus,ha->status,ha->info)); - - if (gdth_from_wait) { - *pIndex = (int)IStatus; - } - - if (IStatus == ASYNCINDEX) { - TRACE2(("gdth_interrupt() async. event\n")); - gdth_async_event(ha); - if (!gdth_polling) - spin_unlock_irqrestore(&ha->smp_lock, flags); - gdth_next(ha); - return IRQ_HANDLED; - } - - if (IStatus == SPEZINDEX) { - TRACE2(("Service unknown or not initialized !\n")); - ha->dvr.size = sizeof(ha->dvr.eu.driver); - ha->dvr.eu.driver.ionode = ha->hanum; - gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr); - if (!gdth_polling) - spin_unlock_irqrestore(&ha->smp_lock, flags); - return IRQ_HANDLED; - } - scp = ha->cmd_tab[IStatus-2].cmnd; - Service = ha->cmd_tab[IStatus-2].service; - ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND; - if (scp == UNUSED_CMND) { - TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus)); - ha->dvr.size = sizeof(ha->dvr.eu.driver); - ha->dvr.eu.driver.ionode = ha->hanum; - ha->dvr.eu.driver.index = IStatus; - gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr); - if (!gdth_polling) - spin_unlock_irqrestore(&ha->smp_lock, flags); - return IRQ_HANDLED; - } - if (scp == INTERNAL_CMND) { - TRACE(("gdth_interrupt() answer to internal command\n")); - if (!gdth_polling) - spin_unlock_irqrestore(&ha->smp_lock, flags); - return IRQ_HANDLED; - } - - TRACE(("gdth_interrupt() sync. status\n")); - rval = gdth_sync_event(ha,Service,IStatus,scp); - if (!gdth_polling) - spin_unlock_irqrestore(&ha->smp_lock, flags); - if (rval == 2) { - gdth_putq(ha, scp, gdth_cmnd_priv(scp)->priority); - } else if (rval == 1) { - gdth_scsi_done(scp); - } - -#ifdef INT_COAL - if (coalesced) { - /* go to the next status in the status buffer */ - ++pcs; -#ifdef GDTH_STATISTICS - ++act_int_coal; - if (act_int_coal > max_int_coal) { - max_int_coal = act_int_coal; - printk("GDT: max_int_coal = %d\n",(u16)max_int_coal); - } -#endif - /* see if there is another status */ - if (pcs->status == 0) - /* Stop the coalesce loop */ - next = FALSE; - } - } while (next); - - /* coalescing only for new GDT_PCIMPR controllers available */ - if (ha->type == GDT_PCIMPR && coalesced) { - writeb(0xff, &dp6m_ptr->i960r.edoor_reg); - writeb(0, &dp6m_ptr->i960r.sema1_reg); - } -#endif - - gdth_next(ha); - return IRQ_HANDLED; -} - -static irqreturn_t gdth_interrupt(int irq, void *dev_id) -{ - gdth_ha_str *ha = dev_id; - - return __gdth_interrupt(ha, false, NULL); -} - -static int gdth_sync_event(gdth_ha_str *ha, int service, u8 index, - Scsi_Cmnd *scp) -{ - gdth_msg_str *msg; - gdth_cmd_str *cmdp; - u8 b, t; - struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - - cmdp = ha->pccb; - TRACE(("gdth_sync_event() serv %d status %d\n", - service,ha->status)); - - if (service == SCREENSERVICE) { - msg = ha->pmsg; - TRACE(("len: %d, answer: %d, ext: %d, alen: %d\n", - msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen)); - if (msg->msg_len > MSGLEN+1) - msg->msg_len = MSGLEN+1; - if (msg->msg_len) - if (!(msg->msg_answer && msg->msg_ext)) { - msg->msg_text[msg->msg_len] = '\0'; - printk("%s",msg->msg_text); - } - - if (msg->msg_ext && !msg->msg_answer) { - while (gdth_test_busy(ha)) - gdth_delay(0); - cmdp->Service = SCREENSERVICE; - cmdp->RequestBuffer = SCREEN_CMND; - gdth_get_cmd_index(ha); - gdth_set_sema0(ha); - cmdp->OpCode = GDT_READ; - cmdp->BoardNode = LOCALBOARD; - cmdp->u.screen.reserved = 0; - cmdp->u.screen.su.msg.msg_handle= msg->msg_handle; - cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; - ha->cmd_offs_dpmem = 0; - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(u64); - ha->cmd_cnt = 0; - gdth_copy_command(ha); - gdth_release_event(ha); - return 0; - } - - if (msg->msg_answer && msg->msg_alen) { - /* default answers (getchar() not possible) */ - if (msg->msg_alen == 1) { - msg->msg_alen = 0; - msg->msg_len = 1; - msg->msg_text[0] = 0; - } else { - msg->msg_alen -= 2; - msg->msg_len = 2; - msg->msg_text[0] = 1; - msg->msg_text[1] = 0; - } - msg->msg_ext = 0; - msg->msg_answer = 0; - while (gdth_test_busy(ha)) - gdth_delay(0); - cmdp->Service = SCREENSERVICE; - cmdp->RequestBuffer = SCREEN_CMND; - gdth_get_cmd_index(ha); - gdth_set_sema0(ha); - cmdp->OpCode = GDT_WRITE; - cmdp->BoardNode = LOCALBOARD; - cmdp->u.screen.reserved = 0; - cmdp->u.screen.su.msg.msg_handle= msg->msg_handle; - cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; - ha->cmd_offs_dpmem = 0; - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(u64); - ha->cmd_cnt = 0; - gdth_copy_command(ha); - gdth_release_event(ha); - return 0; - } - printk("\n"); - - } else { - b = scp->device->channel; - t = scp->device->id; - if (cmndinfo->OpCode == -1 && b != ha->virt_bus) { - ha->raw[BUS_L2P(ha,b)].io_cnt[t]--; - } - /* cache or raw service */ - if (ha->status == S_BSY) { - TRACE2(("Controller busy -> retry !\n")); - if (cmndinfo->OpCode == GDT_MOUNT) - cmndinfo->OpCode = GDT_CLUST_INFO; - /* retry */ - return 2; - } - if (scsi_bufflen(scp)) - pci_unmap_sg(ha->pdev, scsi_sglist(scp), scsi_sg_count(scp), - cmndinfo->dma_dir); - - if (cmndinfo->sense_paddr) - pci_unmap_page(ha->pdev, cmndinfo->sense_paddr, 16, - PCI_DMA_FROMDEVICE); - - if (ha->status == S_OK) { - cmndinfo->status = S_OK; - cmndinfo->info = ha->info; - if (cmndinfo->OpCode != -1) { - TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n", - cmndinfo->OpCode)); - /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */ - if (cmndinfo->OpCode == GDT_CLUST_INFO) { - ha->hdr[t].cluster_type = (u8)ha->info; - if (!(ha->hdr[t].cluster_type & - CLUSTER_MOUNTED)) { - /* NOT MOUNTED -> MOUNT */ - cmndinfo->OpCode = GDT_MOUNT; - if (ha->hdr[t].cluster_type & - CLUSTER_RESERVED) { - /* cluster drive RESERVED (on the other node) */ - cmndinfo->phase = -2; /* reservation conflict */ - } - } else { - cmndinfo->OpCode = -1; - } - } else { - if (cmndinfo->OpCode == GDT_MOUNT) { - ha->hdr[t].cluster_type |= CLUSTER_MOUNTED; - ha->hdr[t].media_changed = TRUE; - } else if (cmndinfo->OpCode == GDT_UNMOUNT) { - ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED; - ha->hdr[t].media_changed = TRUE; - } - cmndinfo->OpCode = -1; - } - /* retry */ - cmndinfo->priority = HIGH_PRI; - return 2; - } else { - /* RESERVE/RELEASE ? */ - if (scp->cmnd[0] == RESERVE) { - ha->hdr[t].cluster_type |= CLUSTER_RESERVED; - } else if (scp->cmnd[0] == RELEASE) { - ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED; - } - scp->result = DID_OK << 16; - scp->sense_buffer[0] = 0; - } - } else { - cmndinfo->status = ha->status; - cmndinfo->info = ha->info; - - if (cmndinfo->OpCode != -1) { - TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n", - cmndinfo->OpCode, ha->status)); - if (cmndinfo->OpCode == GDT_SCAN_START || - cmndinfo->OpCode == GDT_SCAN_END) { - cmndinfo->OpCode = -1; - /* retry */ - cmndinfo->priority = HIGH_PRI; - return 2; - } - memset((char*)scp->sense_buffer,0,16); - scp->sense_buffer[0] = 0x70; - scp->sense_buffer[2] = NOT_READY; - scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - } else if (service == CACHESERVICE) { - if (ha->status == S_CACHE_UNKNOWN && - (ha->hdr[t].cluster_type & - CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) { - /* bus reset -> force GDT_CLUST_INFO */ - ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED; - } - memset((char*)scp->sense_buffer,0,16); - if (ha->status == (u16)S_CACHE_RESERV) { - scp->result = (DID_OK << 16) | (RESERVATION_CONFLICT << 1); - } else { - scp->sense_buffer[0] = 0x70; - scp->sense_buffer[2] = NOT_READY; - scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1); - } - if (!cmndinfo->internal_command) { - ha->dvr.size = sizeof(ha->dvr.eu.sync); - ha->dvr.eu.sync.ionode = ha->hanum; - ha->dvr.eu.sync.service = service; - ha->dvr.eu.sync.status = ha->status; - ha->dvr.eu.sync.info = ha->info; - ha->dvr.eu.sync.hostdrive = t; - if (ha->status >= 0x8000) - gdth_store_event(ha, ES_SYNC, 0, &ha->dvr); - else - gdth_store_event(ha, ES_SYNC, service, &ha->dvr); - } - } else { - /* sense buffer filled from controller firmware (DMA) */ - if (ha->status != S_RAW_SCSI || ha->info >= 0x100) { - scp->result = DID_BAD_TARGET << 16; - } else { - scp->result = (DID_OK << 16) | ha->info; - } - } - } - if (!cmndinfo->wait_for_completion) - cmndinfo->wait_for_completion++; - else - return 1; - } - - return 0; -} - -static char *async_cache_tab[] = { -/* 0*/ "\011\000\002\002\002\004\002\006\004" - "GDT HA %u, service %u, async. status %u/%lu unknown", -/* 1*/ "\011\000\002\002\002\004\002\006\004" - "GDT HA %u, service %u, async. status %u/%lu unknown", -/* 2*/ "\005\000\002\006\004" - "GDT HA %u, Host Drive %lu not ready", -/* 3*/ "\005\000\002\006\004" - "GDT HA %u, Host Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced", -/* 4*/ "\005\000\002\006\004" - "GDT HA %u, mirror update on Host Drive %lu failed", -/* 5*/ "\005\000\002\006\004" - "GDT HA %u, Mirror Drive %lu failed", -/* 6*/ "\005\000\002\006\004" - "GDT HA %u, Mirror Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced", -/* 7*/ "\005\000\002\006\004" - "GDT HA %u, Host Drive %lu write protected", -/* 8*/ "\005\000\002\006\004" - "GDT HA %u, media changed in Host Drive %lu", -/* 9*/ "\005\000\002\006\004" - "GDT HA %u, Host Drive %lu is offline", -/*10*/ "\005\000\002\006\004" - "GDT HA %u, media change of Mirror Drive %lu", -/*11*/ "\005\000\002\006\004" - "GDT HA %u, Mirror Drive %lu is write protected", -/*12*/ "\005\000\002\006\004" - "GDT HA %u, general error on Host Drive %lu. Please check the devices of this drive!", -/*13*/ "\007\000\002\006\002\010\002" - "GDT HA %u, Array Drive %u: Cache Drive %u failed", -/*14*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: FAIL state entered", -/*15*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: error", -/*16*/ "\007\000\002\006\002\010\002" - "GDT HA %u, Array Drive %u: failed drive replaced by Cache Drive %u", -/*17*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: parity build failed", -/*18*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: drive rebuild failed", -/*19*/ "\005\000\002\010\002" - "GDT HA %u, Test of Hot Fix %u failed", -/*20*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: drive build finished successfully", -/*21*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: drive rebuild finished successfully", -/*22*/ "\007\000\002\006\002\010\002" - "GDT HA %u, Array Drive %u: Hot Fix %u activated", -/*23*/ "\005\000\002\006\002" - "GDT HA %u, Host Drive %u: processing of i/o aborted due to serious drive error", -/*24*/ "\005\000\002\010\002" - "GDT HA %u, mirror update on Cache Drive %u completed", -/*25*/ "\005\000\002\010\002" - "GDT HA %u, mirror update on Cache Drive %lu failed", -/*26*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: drive rebuild started", -/*27*/ "\005\000\002\012\001" - "GDT HA %u, Fault bus %u: SHELF OK detected", -/*28*/ "\005\000\002\012\001" - "GDT HA %u, Fault bus %u: SHELF not OK detected", -/*29*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug started", -/*30*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: new disk detected", -/*31*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: old disk detected", -/*32*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is invalid", -/*33*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: invalid device detected", -/*34*/ "\011\000\002\012\001\013\001\006\004" - "GDT HA %u, Fault bus %u, ID %u: insufficient disk capacity (%lu MB required)", -/*35*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: disk write protected", -/*36*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: disk not available", -/*37*/ "\007\000\002\012\001\006\004" - "GDT HA %u, Fault bus %u: swap detected (%lu)", -/*38*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug finished successfully", -/*39*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted due to user Hot Plug", -/*40*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted", -/*41*/ "\007\000\002\012\001\013\001" - "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug for Hot Fix started", -/*42*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: drive build started", -/*43*/ "\003\000\002" - "GDT HA %u, DRAM parity error detected", -/*44*/ "\005\000\002\006\002" - "GDT HA %u, Mirror Drive %u: update started", -/*45*/ "\007\000\002\006\002\010\002" - "GDT HA %u, Mirror Drive %u: Hot Fix %u activated", -/*46*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: no matching Pool Hot Fix Drive available", -/*47*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: Pool Hot Fix Drive available", -/*48*/ "\005\000\002\006\002" - "GDT HA %u, Mirror Drive %u: no matching Pool Hot Fix Drive available", -/*49*/ "\005\000\002\006\002" - "GDT HA %u, Mirror Drive %u: Pool Hot Fix Drive available", -/*50*/ "\007\000\002\012\001\013\001" - "GDT HA %u, SCSI bus %u, ID %u: IGNORE_WIDE_RESIDUE message received", -/*51*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: expand started", -/*52*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: expand finished successfully", -/*53*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: expand failed", -/*54*/ "\003\000\002" - "GDT HA %u, CPU temperature critical", -/*55*/ "\003\000\002" - "GDT HA %u, CPU temperature OK", -/*56*/ "\005\000\002\006\004" - "GDT HA %u, Host drive %lu created", -/*57*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: expand restarted", -/*58*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: expand stopped", -/*59*/ "\005\000\002\010\002" - "GDT HA %u, Mirror Drive %u: drive build quited", -/*60*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: parity build quited", -/*61*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: drive rebuild quited", -/*62*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: parity verify started", -/*63*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: parity verify done", -/*64*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: parity verify failed", -/*65*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: parity error detected", -/*66*/ "\005\000\002\006\002" - "GDT HA %u, Array Drive %u: parity verify quited", -/*67*/ "\005\000\002\006\002" - "GDT HA %u, Host Drive %u reserved", -/*68*/ "\005\000\002\006\002" - "GDT HA %u, Host Drive %u mounted and released", -/*69*/ "\005\000\002\006\002" - "GDT HA %u, Host Drive %u released", -/*70*/ "\003\000\002" - "GDT HA %u, DRAM error detected and corrected with ECC", -/*71*/ "\003\000\002" - "GDT HA %u, Uncorrectable DRAM error detected with ECC", -/*72*/ "\011\000\002\012\001\013\001\014\001" - "GDT HA %u, SCSI bus %u, ID %u, LUN %u: reassigning block", -/*73*/ "\005\000\002\006\002" - "GDT HA %u, Host drive %u resetted locally", -/*74*/ "\005\000\002\006\002" - "GDT HA %u, Host drive %u resetted remotely", -/*75*/ "\003\000\002" - "GDT HA %u, async. status 75 unknown", -}; - - -static int gdth_async_event(gdth_ha_str *ha) -{ - gdth_cmd_str *cmdp; - int cmd_index; - - cmdp= ha->pccb; - TRACE2(("gdth_async_event() ha %d serv %d\n", - ha->hanum, ha->service)); - - if (ha->service == SCREENSERVICE) { - if (ha->status == MSG_REQUEST) { - while (gdth_test_busy(ha)) - gdth_delay(0); - cmdp->Service = SCREENSERVICE; - cmdp->RequestBuffer = SCREEN_CMND; - cmd_index = gdth_get_cmd_index(ha); - gdth_set_sema0(ha); - cmdp->OpCode = GDT_READ; - cmdp->BoardNode = LOCALBOARD; - cmdp->u.screen.reserved = 0; - cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE; - cmdp->u.screen.su.msg.msg_addr = ha->msg_phys; - ha->cmd_offs_dpmem = 0; - ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) - + sizeof(u64); - ha->cmd_cnt = 0; - gdth_copy_command(ha); - if (ha->type == GDT_EISA) - printk("[EISA slot %d] ",(u16)ha->brd_phys); - else if (ha->type == GDT_ISA) - printk("[DPMEM 0x%4X] ",(u16)ha->brd_phys); - else - printk("[PCI %d/%d] ",(u16)(ha->brd_phys>>8), - (u16)((ha->brd_phys>>3)&0x1f)); - gdth_release_event(ha); - } - - } else { - if (ha->type == GDT_PCIMPR && - (ha->fw_vers & 0xff) >= 0x1a) { - ha->dvr.size = 0; - ha->dvr.eu.async.ionode = ha->hanum; - ha->dvr.eu.async.status = ha->status; - /* severity and event_string already set! */ - } else { - ha->dvr.size = sizeof(ha->dvr.eu.async); - ha->dvr.eu.async.ionode = ha->hanum; - ha->dvr.eu.async.service = ha->service; - ha->dvr.eu.async.status = ha->status; - ha->dvr.eu.async.info = ha->info; - *(u32 *)ha->dvr.eu.async.scsi_coord = ha->info2; - } - gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr ); - gdth_log_event( &ha->dvr, NULL ); - - /* new host drive from expand? */ - if (ha->service == CACHESERVICE && ha->status == 56) { - TRACE2(("gdth_async_event(): new host drive %d created\n", - (u16)ha->info)); - /* gdth_analyse_hdrive(hanum, (u16)ha->info); */ - } - } - return 1; -} - -static void gdth_log_event(gdth_evt_data *dvr, char *buffer) -{ - gdth_stackframe stack; - char *f = NULL; - int i,j; - - TRACE2(("gdth_log_event()\n")); - if (dvr->size == 0) { - if (buffer == NULL) { - printk("Adapter %d: %s\n",dvr->eu.async.ionode,dvr->event_string); - } else { - sprintf(buffer,"Adapter %d: %s\n", - dvr->eu.async.ionode,dvr->event_string); - } - } else if (dvr->eu.async.service == CACHESERVICE && - INDEX_OK(dvr->eu.async.status, async_cache_tab)) { - TRACE2(("GDT: Async. event cache service, event no.: %d\n", - dvr->eu.async.status)); - - f = async_cache_tab[dvr->eu.async.status]; - - /* i: parameter to push, j: stack element to fill */ - for (j=0,i=1; i < f[0]; i+=2) { - switch (f[i+1]) { - case 4: - stack.b[j++] = *(u32*)&dvr->eu.stream[(int)f[i]]; - break; - case 2: - stack.b[j++] = *(u16*)&dvr->eu.stream[(int)f[i]]; - break; - case 1: - stack.b[j++] = *(u8*)&dvr->eu.stream[(int)f[i]]; - break; - default: - break; - } - } - - if (buffer == NULL) { - printk(&f[(int)f[0]],stack); - printk("\n"); - } else { - sprintf(buffer,&f[(int)f[0]],stack); - } - - } else { - if (buffer == NULL) { - printk("GDT HA %u, Unknown async. event service %d event no. %d\n", - dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status); - } else { - sprintf(buffer,"GDT HA %u, Unknown async. event service %d event no. %d", - dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status); - } - } -} - -#ifdef GDTH_STATISTICS -static u8 gdth_timer_running; - -static void gdth_timeout(unsigned long data) -{ - u32 i; - Scsi_Cmnd *nscp; - gdth_ha_str *ha; - unsigned long flags; - - if(unlikely(list_empty(&gdth_instances))) { - gdth_timer_running = 0; - return; - } - - ha = list_first_entry(&gdth_instances, gdth_ha_str, list); - spin_lock_irqsave(&ha->smp_lock, flags); - - for (act_stats=0,i=0; icmd_tab[i].cmnd != UNUSED_CMND) - ++act_stats; - - for (act_rq=0,nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr) - ++act_rq; - - TRACE2(("gdth_to(): ints %d, ios %d, act_stats %d, act_rq %d\n", - act_ints, act_ios, act_stats, act_rq)); - act_ints = act_ios = 0; - - gdth_timer.expires = jiffies + 30 * HZ; - add_timer(&gdth_timer); - spin_unlock_irqrestore(&ha->smp_lock, flags); -} - -static void gdth_timer_init(void) -{ - if (gdth_timer_running) - return; - gdth_timer_running = 1; - TRACE2(("gdth_detect(): Initializing timer !\n")); - gdth_timer.expires = jiffies + HZ; - gdth_timer.data = 0L; - gdth_timer.function = gdth_timeout; - add_timer(&gdth_timer); -} -#else -static inline void gdth_timer_init(void) -{ -} -#endif - -static void __init internal_setup(char *str,int *ints) -{ - int i, argc; - char *cur_str, *argv; - - TRACE2(("internal_setup() str %s ints[0] %d\n", - str ? str:"NULL", ints ? ints[0]:0)); - - /* read irq[] from ints[] */ - if (ints) { - argc = ints[0]; - if (argc > 0) { - if (argc > MAXHA) - argc = MAXHA; - for (i = 0; i < argc; ++i) - irq[i] = ints[i+1]; - } - } - - /* analyse string */ - argv = str; - while (argv && (cur_str = strchr(argv, ':'))) { - int val = 0, c = *++cur_str; - - if (c == 'n' || c == 'N') - val = 0; - else if (c == 'y' || c == 'Y') - val = 1; - else - val = (int)simple_strtoul(cur_str, NULL, 0); - - if (!strncmp(argv, "disable:", 8)) - disable = val; - else if (!strncmp(argv, "reserve_mode:", 13)) - reserve_mode = val; - else if (!strncmp(argv, "reverse_scan:", 13)) - reverse_scan = val; - else if (!strncmp(argv, "hdr_channel:", 12)) - hdr_channel = val; - else if (!strncmp(argv, "max_ids:", 8)) - max_ids = val; - else if (!strncmp(argv, "rescan:", 7)) - rescan = val; - else if (!strncmp(argv, "shared_access:", 14)) - shared_access = val; - else if (!strncmp(argv, "probe_eisa_isa:", 15)) - probe_eisa_isa = val; - else if (!strncmp(argv, "reserve_list:", 13)) { - reserve_list[0] = val; - for (i = 1; i < MAX_RES_ARGS; i++) { - cur_str = strchr(cur_str, ','); - if (!cur_str) - break; - if (!isdigit((int)*++cur_str)) { - --cur_str; - break; - } - reserve_list[i] = - (int)simple_strtoul(cur_str, NULL, 0); - } - if (!cur_str) - break; - argv = ++cur_str; - continue; - } - - if ((argv = strchr(argv, ','))) - ++argv; - } -} - -int __init option_setup(char *str) -{ - int ints[MAXHA]; - char *cur = str; - int i = 1; - - TRACE2(("option_setup() str %s\n", str ? str:"NULL")); - - while (cur && isdigit(*cur) && i < MAXHA) { - ints[i++] = simple_strtoul(cur, NULL, 0); - if ((cur = strchr(cur, ',')) != NULL) cur++; - } - - ints[0] = i - 1; - internal_setup(cur, ints); - return 1; -} - -static const char *gdth_ctr_name(gdth_ha_str *ha) -{ - TRACE2(("gdth_ctr_name()\n")); - - if (ha->type == GDT_EISA) { - switch (ha->stype) { - case GDT3_ID: - return("GDT3000/3020"); - case GDT3A_ID: - return("GDT3000A/3020A/3050A"); - case GDT3B_ID: - return("GDT3000B/3010A"); - } - } else if (ha->type == GDT_ISA) { - return("GDT2000/2020"); - } else if (ha->type == GDT_PCI) { - switch (ha->pdev->device) { - case PCI_DEVICE_ID_VORTEX_GDT60x0: - return("GDT6000/6020/6050"); - case PCI_DEVICE_ID_VORTEX_GDT6000B: - return("GDT6000B/6010"); - } - } - /* new controllers (GDT_PCINEW, GDT_PCIMPR, ..) use board_info IOCTL! */ - - return(""); -} - -static const char *gdth_info(struct Scsi_Host *shp) -{ - gdth_ha_str *ha = shost_priv(shp); - - TRACE2(("gdth_info()\n")); - return ((const char *)ha->binfo.type_string); -} - -static enum blk_eh_timer_return gdth_timed_out(struct scsi_cmnd *scp) -{ - gdth_ha_str *ha = shost_priv(scp->device->host); - struct gdth_cmndinfo *cmndinfo = gdth_cmnd_priv(scp); - u8 b, t; - unsigned long flags; - enum blk_eh_timer_return retval = BLK_EH_NOT_HANDLED; - - TRACE(("%s() cmd 0x%x\n", scp->cmnd[0], __func__)); - b = scp->device->channel; - t = scp->device->id; - - /* - * We don't really honor the command timeout, but we try to - * honor 6 times of the actual command timeout! So reset the - * timer if this is less than 6th timeout on this command! - */ - if (++cmndinfo->timeout_count < 6) - retval = BLK_EH_RESET_TIMER; - - /* Reset the timeout if it is locked IO */ - spin_lock_irqsave(&ha->smp_lock, flags); - if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha, b)].lock) || - (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) { - TRACE2(("%s(): locked IO, reset timeout\n", __func__)); - retval = BLK_EH_RESET_TIMER; - } - spin_unlock_irqrestore(&ha->smp_lock, flags); - - return retval; -} - - -static int gdth_eh_bus_reset(Scsi_Cmnd *scp) -{ - gdth_ha_str *ha = shost_priv(scp->device->host); - int i; - unsigned long flags; - Scsi_Cmnd *cmnd; - u8 b; - - TRACE2(("gdth_eh_bus_reset()\n")); - - b = scp->device->channel; - - /* clear command tab */ - spin_lock_irqsave(&ha->smp_lock, flags); - for (i = 0; i < GDTH_MAXCMDS; ++i) { - cmnd = ha->cmd_tab[i].cmnd; - if (!SPECIAL_SCP(cmnd) && cmnd->device->channel == b) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - } - spin_unlock_irqrestore(&ha->smp_lock, flags); - - if (b == ha->virt_bus) { - /* host drives */ - for (i = 0; i < MAX_HDRIVES; ++i) { - if (ha->hdr[i].present) { - spin_lock_irqsave(&ha->smp_lock, flags); - gdth_polling = TRUE; - while (gdth_test_busy(ha)) - gdth_delay(0); - if (gdth_internal_cmd(ha, CACHESERVICE, - GDT_CLUST_RESET, i, 0, 0)) - ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED; - gdth_polling = FALSE; - spin_unlock_irqrestore(&ha->smp_lock, flags); - } - } - } else { - /* raw devices */ - spin_lock_irqsave(&ha->smp_lock, flags); - for (i = 0; i < MAXID; ++i) - ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0; - gdth_polling = TRUE; - while (gdth_test_busy(ha)) - gdth_delay(0); - gdth_internal_cmd(ha, SCSIRAWSERVICE, GDT_RESET_BUS, - BUS_L2P(ha,b), 0, 0); - gdth_polling = FALSE; - spin_unlock_irqrestore(&ha->smp_lock, flags); - } - return SUCCESS; -} - -static int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip) -{ - u8 b, t; - gdth_ha_str *ha = shost_priv(sdev->host); - struct scsi_device *sd; - unsigned capacity; - - sd = sdev; - capacity = cap; - b = sd->channel; - t = sd->id; - TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", ha->hanum, b, t)); - - if (b != ha->virt_bus || ha->hdr[t].heads == 0) { - /* raw device or host drive without mapping information */ - TRACE2(("Evaluate mapping\n")); - gdth_eval_mapping(capacity,&ip[2],&ip[0],&ip[1]); - } else { - ip[0] = ha->hdr[t].heads; - ip[1] = ha->hdr[t].secs; - ip[2] = capacity / ip[0] / ip[1]; - } - - TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n", - ip[0],ip[1],ip[2])); - return 0; -} - - -static int gdth_queuecommand_lck(struct scsi_cmnd *scp, - void (*done)(struct scsi_cmnd *)) -{ - gdth_ha_str *ha = shost_priv(scp->device->host); - struct gdth_cmndinfo *cmndinfo; - - TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0])); - - cmndinfo = gdth_get_cmndinfo(ha); - BUG_ON(!cmndinfo); - - scp->scsi_done = done; - cmndinfo->timeout_count = 0; - cmndinfo->priority = DEFAULT_PRI; - - return __gdth_queuecommand(ha, scp, cmndinfo); -} - -static DEF_SCSI_QCMD(gdth_queuecommand) - -static int __gdth_queuecommand(gdth_ha_str *ha, struct scsi_cmnd *scp, - struct gdth_cmndinfo *cmndinfo) -{ - scp->host_scribble = (unsigned char *)cmndinfo; - cmndinfo->wait_for_completion = 1; - cmndinfo->phase = -1; - cmndinfo->OpCode = -1; - -#ifdef GDTH_STATISTICS - ++act_ios; -#endif - - gdth_putq(ha, scp, cmndinfo->priority); - gdth_next(ha); - return 0; -} - - -static int gdth_open(struct inode *inode, struct file *filep) -{ - gdth_ha_str *ha; - - mutex_lock(&gdth_mutex); - list_for_each_entry(ha, &gdth_instances, list) { - if (!ha->sdev) - ha->sdev = scsi_get_host_dev(ha->shost); - } - mutex_unlock(&gdth_mutex); - - TRACE(("gdth_open()\n")); - return 0; -} - -static int gdth_close(struct inode *inode, struct file *filep) -{ - TRACE(("gdth_close()\n")); - return 0; -} - -static int ioc_event(void __user *arg) -{ - gdth_ioctl_event evt; - gdth_ha_str *ha; - unsigned long flags; - - if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event))) - return -EFAULT; - ha = gdth_find_ha(evt.ionode); - if (!ha) - return -EFAULT; - - if (evt.erase == 0xff) { - if (evt.event.event_source == ES_TEST) - evt.event.event_data.size=sizeof(evt.event.event_data.eu.test); - else if (evt.event.event_source == ES_DRIVER) - evt.event.event_data.size=sizeof(evt.event.event_data.eu.driver); - else if (evt.event.event_source == ES_SYNC) - evt.event.event_data.size=sizeof(evt.event.event_data.eu.sync); - else - evt.event.event_data.size=sizeof(evt.event.event_data.eu.async); - spin_lock_irqsave(&ha->smp_lock, flags); - gdth_store_event(ha, evt.event.event_source, evt.event.event_idx, - &evt.event.event_data); - spin_unlock_irqrestore(&ha->smp_lock, flags); - } else if (evt.erase == 0xfe) { - gdth_clear_events(); - } else if (evt.erase == 0) { - evt.handle = gdth_read_event(ha, evt.handle, &evt.event); - } else { - gdth_readapp_event(ha, evt.erase, &evt.event); - } - if (copy_to_user(arg, &evt, sizeof(gdth_ioctl_event))) - return -EFAULT; - return 0; -} - -static int ioc_lockdrv(void __user *arg) -{ - gdth_ioctl_lockdrv ldrv; - u8 i, j; - unsigned long flags; - gdth_ha_str *ha; - - if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv))) - return -EFAULT; - ha = gdth_find_ha(ldrv.ionode); - if (!ha) - return -EFAULT; - - for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) { - j = ldrv.drives[i]; - if (j >= MAX_HDRIVES || !ha->hdr[j].present) - continue; - if (ldrv.lock) { - spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[j].lock = 1; - spin_unlock_irqrestore(&ha->smp_lock, flags); - gdth_wait_completion(ha, ha->bus_cnt, j); - } else { - spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[j].lock = 0; - spin_unlock_irqrestore(&ha->smp_lock, flags); - gdth_next(ha); - } - } - return 0; -} - -static int ioc_resetdrv(void __user *arg, char *cmnd) -{ - gdth_ioctl_reset res; - gdth_cmd_str cmd; - gdth_ha_str *ha; - int rval; - - if (copy_from_user(&res, arg, sizeof(gdth_ioctl_reset)) || - res.number >= MAX_HDRIVES) - return -EFAULT; - ha = gdth_find_ha(res.ionode); - if (!ha) - return -EFAULT; - - if (!ha->hdr[res.number].present) - return 0; - memset(&cmd, 0, sizeof(gdth_cmd_str)); - cmd.Service = CACHESERVICE; - cmd.OpCode = GDT_CLUST_RESET; - if (ha->cache_feat & GDT_64BIT) - cmd.u.cache64.DeviceNo = res.number; - else - cmd.u.cache.DeviceNo = res.number; - - rval = __gdth_execute(ha->sdev, &cmd, cmnd, 30, NULL); - if (rval < 0) - return rval; - res.status = rval; - - if (copy_to_user(arg, &res, sizeof(gdth_ioctl_reset))) - return -EFAULT; - return 0; -} - -static int ioc_general(void __user *arg, char *cmnd) -{ - gdth_ioctl_general gen; - char *buf = NULL; - u64 paddr; - gdth_ha_str *ha; - int rval; - - if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general))) - return -EFAULT; - ha = gdth_find_ha(gen.ionode); - if (!ha) - return -EFAULT; - - if (gen.data_len > INT_MAX) - return -EINVAL; - if (gen.sense_len > INT_MAX) - return -EINVAL; - if (gen.data_len + gen.sense_len > INT_MAX) - return -EINVAL; - - if (gen.data_len + gen.sense_len != 0) { - if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len, - FALSE, &paddr))) - return -EFAULT; - if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general), - gen.data_len + gen.sense_len)) { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return -EFAULT; - } - - if (gen.command.OpCode == GDT_IOCTL) { - gen.command.u.ioctl.p_param = paddr; - } else if (gen.command.Service == CACHESERVICE) { - if (ha->cache_feat & GDT_64BIT) { - /* copy elements from 32-bit IOCTL structure */ - gen.command.u.cache64.BlockCnt = gen.command.u.cache.BlockCnt; - gen.command.u.cache64.BlockNo = gen.command.u.cache.BlockNo; - gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo; - /* addresses */ - if (ha->cache_feat & SCATTER_GATHER) { - gen.command.u.cache64.DestAddr = (u64)-1; - gen.command.u.cache64.sg_canz = 1; - gen.command.u.cache64.sg_lst[0].sg_ptr = paddr; - gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len; - gen.command.u.cache64.sg_lst[1].sg_len = 0; - } else { - gen.command.u.cache64.DestAddr = paddr; - gen.command.u.cache64.sg_canz = 0; - } - } else { - if (ha->cache_feat & SCATTER_GATHER) { - gen.command.u.cache.DestAddr = 0xffffffff; - gen.command.u.cache.sg_canz = 1; - gen.command.u.cache.sg_lst[0].sg_ptr = (u32)paddr; - gen.command.u.cache.sg_lst[0].sg_len = gen.data_len; - gen.command.u.cache.sg_lst[1].sg_len = 0; - } else { - gen.command.u.cache.DestAddr = paddr; - gen.command.u.cache.sg_canz = 0; - } - } - } else if (gen.command.Service == SCSIRAWSERVICE) { - if (ha->raw_feat & GDT_64BIT) { - /* copy elements from 32-bit IOCTL structure */ - char cmd[16]; - gen.command.u.raw64.sense_len = gen.command.u.raw.sense_len; - gen.command.u.raw64.bus = gen.command.u.raw.bus; - gen.command.u.raw64.lun = gen.command.u.raw.lun; - gen.command.u.raw64.target = gen.command.u.raw.target; - memcpy(cmd, gen.command.u.raw.cmd, 16); - memcpy(gen.command.u.raw64.cmd, cmd, 16); - gen.command.u.raw64.clen = gen.command.u.raw.clen; - gen.command.u.raw64.sdlen = gen.command.u.raw.sdlen; - gen.command.u.raw64.direction = gen.command.u.raw.direction; - /* addresses */ - if (ha->raw_feat & SCATTER_GATHER) { - gen.command.u.raw64.sdata = (u64)-1; - gen.command.u.raw64.sg_ranz = 1; - gen.command.u.raw64.sg_lst[0].sg_ptr = paddr; - gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len; - gen.command.u.raw64.sg_lst[1].sg_len = 0; - } else { - gen.command.u.raw64.sdata = paddr; - gen.command.u.raw64.sg_ranz = 0; - } - gen.command.u.raw64.sense_data = paddr + gen.data_len; - } else { - if (ha->raw_feat & SCATTER_GATHER) { - gen.command.u.raw.sdata = 0xffffffff; - gen.command.u.raw.sg_ranz = 1; - gen.command.u.raw.sg_lst[0].sg_ptr = (u32)paddr; - gen.command.u.raw.sg_lst[0].sg_len = gen.data_len; - gen.command.u.raw.sg_lst[1].sg_len = 0; - } else { - gen.command.u.raw.sdata = paddr; - gen.command.u.raw.sg_ranz = 0; - } - gen.command.u.raw.sense_data = (u32)paddr + gen.data_len; - } - } else { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return -EFAULT; - } - } - - rval = __gdth_execute(ha->sdev, &gen.command, cmnd, gen.timeout, &gen.info); - if (rval < 0) { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return rval; - } - gen.status = rval; - - if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf, - gen.data_len + gen.sense_len)) { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return -EFAULT; - } - if (copy_to_user(arg, &gen, - sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) { - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return -EFAULT; - } - gdth_ioctl_free(ha, gen.data_len+gen.sense_len, buf, paddr); - return 0; -} - -static int ioc_hdrlist(void __user *arg, char *cmnd) -{ - gdth_ioctl_rescan *rsc; - gdth_cmd_str *cmd; - gdth_ha_str *ha; - u8 i; - int rc = -ENOMEM; - u32 cluster_type = 0; - - rsc = kmalloc(sizeof(*rsc), GFP_KERNEL); - cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); - if (!rsc || !cmd) - goto free_fail; - - if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) || - (NULL == (ha = gdth_find_ha(rsc->ionode)))) { - rc = -EFAULT; - goto free_fail; - } - memset(cmd, 0, sizeof(gdth_cmd_str)); - - for (i = 0; i < MAX_HDRIVES; ++i) { - if (!ha->hdr[i].present) { - rsc->hdr_list[i].bus = 0xff; - continue; - } - rsc->hdr_list[i].bus = ha->virt_bus; - rsc->hdr_list[i].target = i; - rsc->hdr_list[i].lun = 0; - rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type; - if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { - cmd->Service = CACHESERVICE; - cmd->OpCode = GDT_CLUST_INFO; - if (ha->cache_feat & GDT_64BIT) - cmd->u.cache64.DeviceNo = i; - else - cmd->u.cache.DeviceNo = i; - if (__gdth_execute(ha->sdev, cmd, cmnd, 30, &cluster_type) == S_OK) - rsc->hdr_list[i].cluster_type = cluster_type; - } - } - - if (copy_to_user(arg, rsc, sizeof(gdth_ioctl_rescan))) - rc = -EFAULT; - else - rc = 0; - -free_fail: - kfree(rsc); - kfree(cmd); - return rc; -} - -static int ioc_rescan(void __user *arg, char *cmnd) -{ - gdth_ioctl_rescan *rsc; - gdth_cmd_str *cmd; - u16 i, status, hdr_cnt; - u32 info; - int cyls, hds, secs; - int rc = -ENOMEM; - unsigned long flags; - gdth_ha_str *ha; - - rsc = kmalloc(sizeof(*rsc), GFP_KERNEL); - cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd || !rsc) - goto free_fail; - - if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) || - (NULL == (ha = gdth_find_ha(rsc->ionode)))) { - rc = -EFAULT; - goto free_fail; - } - memset(cmd, 0, sizeof(gdth_cmd_str)); - - if (rsc->flag == 0) { - /* old method: re-init. cache service */ - cmd->Service = CACHESERVICE; - if (ha->cache_feat & GDT_64BIT) { - cmd->OpCode = GDT_X_INIT_HOST; - cmd->u.cache64.DeviceNo = LINUX_OS; - } else { - cmd->OpCode = GDT_INIT; - cmd->u.cache.DeviceNo = LINUX_OS; - } - - status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); - i = 0; - hdr_cnt = (status == S_OK ? (u16)info : 0); - } else { - i = rsc->hdr_no; - hdr_cnt = i + 1; - } - - for (; i < hdr_cnt && i < MAX_HDRIVES; ++i) { - cmd->Service = CACHESERVICE; - cmd->OpCode = GDT_INFO; - if (ha->cache_feat & GDT_64BIT) - cmd->u.cache64.DeviceNo = i; - else - cmd->u.cache.DeviceNo = i; - - status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); - - spin_lock_irqsave(&ha->smp_lock, flags); - rsc->hdr_list[i].bus = ha->virt_bus; - rsc->hdr_list[i].target = i; - rsc->hdr_list[i].lun = 0; - if (status != S_OK) { - ha->hdr[i].present = FALSE; - } else { - ha->hdr[i].present = TRUE; - ha->hdr[i].size = info; - /* evaluate mapping */ - ha->hdr[i].size &= ~SECS32; - gdth_eval_mapping(ha->hdr[i].size,&cyls,&hds,&secs); - ha->hdr[i].heads = hds; - ha->hdr[i].secs = secs; - /* round size */ - ha->hdr[i].size = cyls * hds * secs; - } - spin_unlock_irqrestore(&ha->smp_lock, flags); - if (status != S_OK) - continue; - - /* extended info, if GDT_64BIT, for drives > 2 TB */ - /* but we need ha->info2, not yet stored in scp->SCp */ - - /* devtype, cluster info, R/W attribs */ - cmd->Service = CACHESERVICE; - cmd->OpCode = GDT_DEVTYPE; - if (ha->cache_feat & GDT_64BIT) - cmd->u.cache64.DeviceNo = i; - else - cmd->u.cache.DeviceNo = i; - - status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); - - spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[i].devtype = (status == S_OK ? (u16)info : 0); - spin_unlock_irqrestore(&ha->smp_lock, flags); - - cmd->Service = CACHESERVICE; - cmd->OpCode = GDT_CLUST_INFO; - if (ha->cache_feat & GDT_64BIT) - cmd->u.cache64.DeviceNo = i; - else - cmd->u.cache.DeviceNo = i; - - status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); - - spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[i].cluster_type = - ((status == S_OK && !shared_access) ? (u16)info : 0); - spin_unlock_irqrestore(&ha->smp_lock, flags); - rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type; - - cmd->Service = CACHESERVICE; - cmd->OpCode = GDT_RW_ATTRIBS; - if (ha->cache_feat & GDT_64BIT) - cmd->u.cache64.DeviceNo = i; - else - cmd->u.cache.DeviceNo = i; - - status = __gdth_execute(ha->sdev, cmd, cmnd, 30, &info); - - spin_lock_irqsave(&ha->smp_lock, flags); - ha->hdr[i].rw_attribs = (status == S_OK ? (u16)info : 0); - spin_unlock_irqrestore(&ha->smp_lock, flags); - } - - if (copy_to_user(arg, rsc, sizeof(gdth_ioctl_rescan))) - rc = -EFAULT; - else - rc = 0; - -free_fail: - kfree(rsc); - kfree(cmd); - return rc; -} - -static int gdth_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - gdth_ha_str *ha; - Scsi_Cmnd *scp; - unsigned long flags; - char cmnd[MAX_COMMAND_SIZE]; - void __user *argp = (void __user *)arg; - - memset(cmnd, 0xff, 12); - - TRACE(("gdth_ioctl() cmd 0x%x\n", cmd)); - - switch (cmd) { - case GDTIOCTL_CTRCNT: - { - int cnt = gdth_ctr_count; - if (put_user(cnt, (int __user *)argp)) - return -EFAULT; - break; - } - - case GDTIOCTL_DRVERS: - { - int ver = (GDTH_VERSION<<8) | GDTH_SUBVERSION; - if (put_user(ver, (int __user *)argp)) - return -EFAULT; - break; - } - - case GDTIOCTL_OSVERS: - { - gdth_ioctl_osvers osv; - - osv.version = (u8)(LINUX_VERSION_CODE >> 16); - osv.subversion = (u8)(LINUX_VERSION_CODE >> 8); - osv.revision = (u16)(LINUX_VERSION_CODE & 0xff); - if (copy_to_user(argp, &osv, sizeof(gdth_ioctl_osvers))) - return -EFAULT; - break; - } - - case GDTIOCTL_CTRTYPE: - { - gdth_ioctl_ctrtype ctrt; - - if (copy_from_user(&ctrt, argp, sizeof(gdth_ioctl_ctrtype)) || - (NULL == (ha = gdth_find_ha(ctrt.ionode)))) - return -EFAULT; - - if (ha->type == GDT_ISA || ha->type == GDT_EISA) { - ctrt.type = (u8)((ha->stype>>20) - 0x10); - } else { - if (ha->type != GDT_PCIMPR) { - ctrt.type = (u8)((ha->stype<<4) + 6); - } else { - ctrt.type = - (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); - if (ha->stype >= 0x300) - ctrt.ext_type = 0x6000 | ha->pdev->subsystem_device; - else - ctrt.ext_type = 0x6000 | ha->stype; - } - ctrt.device_id = ha->pdev->device; - ctrt.sub_device_id = ha->pdev->subsystem_device; - } - ctrt.info = ha->brd_phys; - ctrt.oem_id = ha->oem_id; - if (copy_to_user(argp, &ctrt, sizeof(gdth_ioctl_ctrtype))) - return -EFAULT; - break; - } - - case GDTIOCTL_GENERAL: - return ioc_general(argp, cmnd); - - case GDTIOCTL_EVENT: - return ioc_event(argp); - - case GDTIOCTL_LOCKDRV: - return ioc_lockdrv(argp); - - case GDTIOCTL_LOCKCHN: - { - gdth_ioctl_lockchn lchn; - u8 i, j; - - if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) || - (NULL == (ha = gdth_find_ha(lchn.ionode)))) - return -EFAULT; - - i = lchn.channel; - if (i < ha->bus_cnt) { - if (lchn.lock) { - spin_lock_irqsave(&ha->smp_lock, flags); - ha->raw[i].lock = 1; - spin_unlock_irqrestore(&ha->smp_lock, flags); - for (j = 0; j < ha->tid_cnt; ++j) - gdth_wait_completion(ha, i, j); - } else { - spin_lock_irqsave(&ha->smp_lock, flags); - ha->raw[i].lock = 0; - spin_unlock_irqrestore(&ha->smp_lock, flags); - for (j = 0; j < ha->tid_cnt; ++j) - gdth_next(ha); - } - } - break; - } - - case GDTIOCTL_RESCAN: - return ioc_rescan(argp, cmnd); - - case GDTIOCTL_HDRLIST: - return ioc_hdrlist(argp, cmnd); - - case GDTIOCTL_RESET_BUS: - { - gdth_ioctl_reset res; - int rval; - - if (copy_from_user(&res, argp, sizeof(gdth_ioctl_reset)) || - (NULL == (ha = gdth_find_ha(res.ionode)))) - return -EFAULT; - - scp = kzalloc(sizeof(*scp), GFP_KERNEL); - if (!scp) - return -ENOMEM; - scp->device = ha->sdev; - scp->cmd_len = 12; - scp->device->channel = res.number; - rval = gdth_eh_bus_reset(scp); - res.status = (rval == SUCCESS ? S_OK : S_GENERR); - kfree(scp); - - if (copy_to_user(argp, &res, sizeof(gdth_ioctl_reset))) - return -EFAULT; - break; - } - - case GDTIOCTL_RESET_DRV: - return ioc_resetdrv(argp, cmnd); - - default: - break; - } - return 0; -} - -static long gdth_unlocked_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - int ret; - - mutex_lock(&gdth_mutex); - ret = gdth_ioctl(file, cmd, arg); - mutex_unlock(&gdth_mutex); - - return ret; -} - -/* flush routine */ -static void gdth_flush(gdth_ha_str *ha) -{ - int i; - gdth_cmd_str gdtcmd; - char cmnd[MAX_COMMAND_SIZE]; - memset(cmnd, 0xff, MAX_COMMAND_SIZE); - - TRACE2(("gdth_flush() hanum %d\n", ha->hanum)); - - for (i = 0; i < MAX_HDRIVES; ++i) { - if (ha->hdr[i].present) { - gdtcmd.BoardNode = LOCALBOARD; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_FLUSH; - if (ha->cache_feat & GDT_64BIT) { - gdtcmd.u.cache64.DeviceNo = i; - gdtcmd.u.cache64.BlockNo = 1; - gdtcmd.u.cache64.sg_canz = 0; - } else { - gdtcmd.u.cache.DeviceNo = i; - gdtcmd.u.cache.BlockNo = 1; - gdtcmd.u.cache.sg_canz = 0; - } - TRACE2(("gdth_flush(): flush ha %d drive %d\n", ha->hanum, i)); - - gdth_execute(ha->shost, &gdtcmd, cmnd, 30, NULL); - } - } -} - -/* configure lun */ -static int gdth_slave_configure(struct scsi_device *sdev) -{ - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); - sdev->skip_ms_page_3f = 1; - sdev->skip_ms_page_8 = 1; - return 0; -} - -static struct scsi_host_template gdth_template = { - .name = "GDT SCSI Disk Array Controller", - .info = gdth_info, - .queuecommand = gdth_queuecommand, - .eh_bus_reset_handler = gdth_eh_bus_reset, - .slave_configure = gdth_slave_configure, - .bios_param = gdth_bios_param, - .proc_info = gdth_proc_info, - .eh_timed_out = gdth_timed_out, - .proc_name = "gdth", - .can_queue = GDTH_MAXCMDS, - .this_id = -1, - .sg_tablesize = GDTH_MAXSG, - .cmd_per_lun = GDTH_MAXC_P_L, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -#ifdef CONFIG_ISA -static int __init gdth_isa_probe_one(u32 isa_bios) -{ - struct Scsi_Host *shp; - gdth_ha_str *ha; - dma_addr_t scratch_dma_handle = 0; - int error, i; - - if (!gdth_search_isa(isa_bios)) - return -ENXIO; - - shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); - if (!shp) - return -ENOMEM; - ha = shost_priv(shp); - - error = -ENODEV; - if (!gdth_init_isa(isa_bios,ha)) - goto out_host_put; - - /* controller found and initialized */ - printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n", - isa_bios, ha->irq, ha->drq); - - error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha); - if (error) { - printk("GDT-ISA: Unable to allocate IRQ\n"); - goto out_host_put; - } - - error = request_dma(ha->drq, "gdth"); - if (error) { - printk("GDT-ISA: Unable to allocate DMA channel\n"); - goto out_free_irq; - } - - set_dma_mode(ha->drq,DMA_MODE_CASCADE); - enable_dma(ha->drq); - shp->unchecked_isa_dma = 1; - shp->irq = ha->irq; - shp->dma_channel = ha->drq; - - ha->hanum = gdth_ctr_count++; - ha->shost = shp; - - ha->pccb = &ha->cmdext; - ha->ccb_phys = 0L; - ha->pdev = NULL; - - error = -ENOMEM; - - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); - if (!ha->pscratch) - goto out_dec_counters; - ha->scratch_phys = scratch_dma_handle; - - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); - if (!ha->pmsg) - goto out_free_pscratch; - ha->msg_phys = scratch_dma_handle; - -#ifdef INT_COAL - ha->coal_stat = pci_alloc_consistent(ha->pdev, - sizeof(gdth_coal_status) * MAXOFFSETS, - &scratch_dma_handle); - if (!ha->coal_stat) - goto out_free_pmsg; - ha->coal_stat_phys = scratch_dma_handle; -#endif - - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i = 0; i < GDTH_MAXCMDS; ++i) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - error = -ENODEV; - if (!gdth_search_drives(ha)) { - printk("GDT-ISA: Error during device scan\n"); - goto out_free_coal_stat; - } - - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; - - if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) - shp->max_cmd_len = 16; - - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = ha->bus_cnt; - - spin_lock_init(&ha->smp_lock); - gdth_enable_int(ha); - - error = scsi_add_host(shp, NULL); - if (error) - goto out_free_coal_stat; - list_add_tail(&ha->list, &gdth_instances); - gdth_timer_init(); - - scsi_scan_host(shp); - - return 0; - - out_free_coal_stat: -#ifdef INT_COAL - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, - ha->coal_stat, ha->coal_stat_phys); - out_free_pmsg: -#endif - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - out_free_pscratch: - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - out_dec_counters: - gdth_ctr_count--; - out_free_irq: - free_irq(ha->irq, ha); - out_host_put: - scsi_host_put(shp); - return error; -} -#endif /* CONFIG_ISA */ - -#ifdef CONFIG_EISA -static int __init gdth_eisa_probe_one(u16 eisa_slot) -{ - struct Scsi_Host *shp; - gdth_ha_str *ha; - dma_addr_t scratch_dma_handle = 0; - int error, i; - - if (!gdth_search_eisa(eisa_slot)) - return -ENXIO; - - shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); - if (!shp) - return -ENOMEM; - ha = shost_priv(shp); - - error = -ENODEV; - if (!gdth_init_eisa(eisa_slot,ha)) - goto out_host_put; - - /* controller found and initialized */ - printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n", - eisa_slot >> 12, ha->irq); - - error = request_irq(ha->irq, gdth_interrupt, IRQF_DISABLED, "gdth", ha); - if (error) { - printk("GDT-EISA: Unable to allocate IRQ\n"); - goto out_host_put; - } - - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - - ha->hanum = gdth_ctr_count++; - ha->shost = shp; - - TRACE2(("EISA detect Bus 0: hanum %d\n", ha->hanum)); - - ha->pccb = &ha->cmdext; - ha->ccb_phys = 0L; - - error = -ENOMEM; - - ha->pdev = NULL; - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); - if (!ha->pscratch) - goto out_free_irq; - ha->scratch_phys = scratch_dma_handle; - - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); - if (!ha->pmsg) - goto out_free_pscratch; - ha->msg_phys = scratch_dma_handle; - -#ifdef INT_COAL - ha->coal_stat = pci_alloc_consistent(ha->pdev, - sizeof(gdth_coal_status) * MAXOFFSETS, - &scratch_dma_handle); - if (!ha->coal_stat) - goto out_free_pmsg; - ha->coal_stat_phys = scratch_dma_handle; -#endif - - ha->ccb_phys = pci_map_single(ha->pdev,ha->pccb, - sizeof(gdth_cmd_str), PCI_DMA_BIDIRECTIONAL); - if (!ha->ccb_phys) - goto out_free_coal_stat; - - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i = 0; i < GDTH_MAXCMDS; ++i) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - if (!gdth_search_drives(ha)) { - printk("GDT-EISA: Error during device scan\n"); - error = -ENODEV; - goto out_free_ccb_phys; - } - - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; - - if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) - shp->max_cmd_len = 16; - - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = ha->bus_cnt; - - spin_lock_init(&ha->smp_lock); - gdth_enable_int(ha); - - error = scsi_add_host(shp, NULL); - if (error) - goto out_free_ccb_phys; - list_add_tail(&ha->list, &gdth_instances); - gdth_timer_init(); - - scsi_scan_host(shp); - - return 0; - - out_free_ccb_phys: - pci_unmap_single(ha->pdev,ha->ccb_phys, sizeof(gdth_cmd_str), - PCI_DMA_BIDIRECTIONAL); - out_free_coal_stat: -#ifdef INT_COAL - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, - ha->coal_stat, ha->coal_stat_phys); - out_free_pmsg: -#endif - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - out_free_pscratch: - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - out_free_irq: - free_irq(ha->irq, ha); - gdth_ctr_count--; - out_host_put: - scsi_host_put(shp); - return error; -} -#endif /* CONFIG_EISA */ - -#ifdef CONFIG_PCI -static int __devinit gdth_pci_probe_one(gdth_pci_str *pcistr, - gdth_ha_str **ha_out) -{ - struct Scsi_Host *shp; - gdth_ha_str *ha; - dma_addr_t scratch_dma_handle = 0; - int error, i; - struct pci_dev *pdev = pcistr->pdev; - - *ha_out = NULL; - - shp = scsi_host_alloc(&gdth_template, sizeof(gdth_ha_str)); - if (!shp) - return -ENOMEM; - ha = shost_priv(shp); - - error = -ENODEV; - if (!gdth_init_pci(pdev, pcistr, ha)) - goto out_host_put; - - /* controller found and initialized */ - printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n", - pdev->bus->number, - PCI_SLOT(pdev->devfn), - ha->irq); - - error = request_irq(ha->irq, gdth_interrupt, - IRQF_DISABLED|IRQF_SHARED, "gdth", ha); - if (error) { - printk("GDT-PCI: Unable to allocate IRQ\n"); - goto out_host_put; - } - - shp->unchecked_isa_dma = 0; - shp->irq = ha->irq; - shp->dma_channel = 0xff; - - ha->hanum = gdth_ctr_count++; - ha->shost = shp; - - ha->pccb = &ha->cmdext; - ha->ccb_phys = 0L; - - error = -ENOMEM; - - ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, - &scratch_dma_handle); - if (!ha->pscratch) - goto out_free_irq; - ha->scratch_phys = scratch_dma_handle; - - ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), - &scratch_dma_handle); - if (!ha->pmsg) - goto out_free_pscratch; - ha->msg_phys = scratch_dma_handle; - -#ifdef INT_COAL - ha->coal_stat = pci_alloc_consistent(ha->pdev, - sizeof(gdth_coal_status) * MAXOFFSETS, - &scratch_dma_handle); - if (!ha->coal_stat) - goto out_free_pmsg; - ha->coal_stat_phys = scratch_dma_handle; -#endif - - ha->scratch_busy = FALSE; - ha->req_first = NULL; - ha->tid_cnt = pdev->device >= 0x200 ? MAXID : MAX_HDRIVES; - if (max_ids > 0 && max_ids < ha->tid_cnt) - ha->tid_cnt = max_ids; - for (i = 0; i < GDTH_MAXCMDS; ++i) - ha->cmd_tab[i].cmnd = UNUSED_CMND; - ha->scan_mode = rescan ? 0x10 : 0; - - error = -ENODEV; - if (!gdth_search_drives(ha)) { - printk("GDT-PCI %d: Error during device scan\n", ha->hanum); - goto out_free_coal_stat; - } - - if (hdr_channel < 0 || hdr_channel > ha->bus_cnt) - hdr_channel = ha->bus_cnt; - ha->virt_bus = hdr_channel; - - /* 64-bit DMA only supported from FW >= x.43 */ - if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) || - !ha->dma64_support) { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "GDT-PCI %d: " - "Unable to set 32-bit DMA\n", ha->hanum); - goto out_free_coal_stat; - } - } else { - shp->max_cmd_len = 16; - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - printk("GDT-PCI %d: 64-bit DMA enabled\n", ha->hanum); - } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "GDT-PCI %d: " - "Unable to set 64/32-bit DMA\n", ha->hanum); - goto out_free_coal_stat; - } - } - - shp->max_id = ha->tid_cnt; - shp->max_lun = MAXLUN; - shp->max_channel = ha->bus_cnt; - - spin_lock_init(&ha->smp_lock); - gdth_enable_int(ha); - - error = scsi_add_host(shp, &pdev->dev); - if (error) - goto out_free_coal_stat; - list_add_tail(&ha->list, &gdth_instances); - - pci_set_drvdata(ha->pdev, ha); - gdth_timer_init(); - - scsi_scan_host(shp); - - *ha_out = ha; - - return 0; - - out_free_coal_stat: -#ifdef INT_COAL - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * MAXOFFSETS, - ha->coal_stat, ha->coal_stat_phys); - out_free_pmsg: -#endif - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - out_free_pscratch: - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - out_free_irq: - free_irq(ha->irq, ha); - gdth_ctr_count--; - out_host_put: - scsi_host_put(shp); - return error; -} -#endif /* CONFIG_PCI */ - -static void gdth_remove_one(gdth_ha_str *ha) -{ - struct Scsi_Host *shp = ha->shost; - - TRACE2(("gdth_remove_one()\n")); - - scsi_remove_host(shp); - - gdth_flush(ha); - - if (ha->sdev) { - scsi_free_host_dev(ha->sdev); - ha->sdev = NULL; - } - - if (shp->irq) - free_irq(shp->irq,ha); - -#ifdef CONFIG_ISA - if (shp->dma_channel != 0xff) - free_dma(shp->dma_channel); -#endif -#ifdef INT_COAL - if (ha->coal_stat) - pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) * - MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys); -#endif - if (ha->pscratch) - pci_free_consistent(ha->pdev, GDTH_SCRATCH, - ha->pscratch, ha->scratch_phys); - if (ha->pmsg) - pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), - ha->pmsg, ha->msg_phys); - if (ha->ccb_phys) - pci_unmap_single(ha->pdev,ha->ccb_phys, - sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL); - - scsi_host_put(shp); -} - -static int gdth_halt(struct notifier_block *nb, unsigned long event, void *buf) -{ - gdth_ha_str *ha; - - TRACE2(("gdth_halt() event %d\n", (int)event)); - if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) - return NOTIFY_DONE; - - list_for_each_entry(ha, &gdth_instances, list) - gdth_flush(ha); - - return NOTIFY_OK; -} - -static struct notifier_block gdth_notifier = { - gdth_halt, NULL, 0 -}; - -static int __init gdth_init(void) -{ - if (disable) { - printk("GDT-HA: Controller driver disabled from" - " command line !\n"); - return 0; - } - - printk("GDT-HA: Storage RAID Controller Driver. Version: %s\n", - GDTH_VERSION_STR); - - /* initializations */ - gdth_polling = TRUE; - gdth_clear_events(); - init_timer(&gdth_timer); - - /* As default we do not probe for EISA or ISA controllers */ - if (probe_eisa_isa) { - /* scanning for controllers, at first: ISA controller */ -#ifdef CONFIG_ISA - u32 isa_bios; - for (isa_bios = 0xc8000UL; isa_bios <= 0xd8000UL; - isa_bios += 0x8000UL) - gdth_isa_probe_one(isa_bios); -#endif -#ifdef CONFIG_EISA - { - u16 eisa_slot; - for (eisa_slot = 0x1000; eisa_slot <= 0x8000; - eisa_slot += 0x1000) - gdth_eisa_probe_one(eisa_slot); - } -#endif - } - -#ifdef CONFIG_PCI - /* scanning for PCI controllers */ - if (pci_register_driver(&gdth_pci_driver)) { - gdth_ha_str *ha; - - list_for_each_entry(ha, &gdth_instances, list) - gdth_remove_one(ha); - return -ENODEV; - } -#endif /* CONFIG_PCI */ - - TRACE2(("gdth_detect() %d controller detected\n", gdth_ctr_count)); - - major = register_chrdev(0,"gdth", &gdth_fops); - register_reboot_notifier(&gdth_notifier); - gdth_polling = FALSE; - return 0; -} - -static void __exit gdth_exit(void) -{ - gdth_ha_str *ha; - - unregister_chrdev(major, "gdth"); - unregister_reboot_notifier(&gdth_notifier); - -#ifdef GDTH_STATISTICS - del_timer_sync(&gdth_timer); -#endif - -#ifdef CONFIG_PCI - pci_unregister_driver(&gdth_pci_driver); -#endif - - list_for_each_entry(ha, &gdth_instances, list) - gdth_remove_one(ha); -} - -module_init(gdth_init); -module_exit(gdth_exit); - -#ifndef MODULE -__setup("gdth=", option_setup); -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/gdth.h b/ANDROID_3.4.5/drivers/scsi/gdth.h deleted file mode 100644 index d3e4d7c6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/gdth.h +++ /dev/null @@ -1,1021 +0,0 @@ -#ifndef _GDTH_H -#define _GDTH_H - -/* - * Header file for the GDT Disk Array/Storage RAID controllers driver for Linux - * - * gdth.h Copyright (C) 1995-06 ICP vortex, Achim Leubner - * See gdth.c for further informations and - * below for supported controller types - * - * - * - * $Id: gdth.h,v 1.58 2006/01/11 16:14:09 achim Exp $ - */ - -#include - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -/* defines, macros */ - -/* driver version */ -#define GDTH_VERSION_STR "3.05" -#define GDTH_VERSION 3 -#define GDTH_SUBVERSION 5 - -/* protocol version */ -#define PROTOCOL_VERSION 1 - -/* OEM IDs */ -#define OEM_ID_ICP 0x941c -#define OEM_ID_INTEL 0x8000 - -/* controller classes */ -#define GDT_ISA 0x01 /* ISA controller */ -#define GDT_EISA 0x02 /* EISA controller */ -#define GDT_PCI 0x03 /* PCI controller */ -#define GDT_PCINEW 0x04 /* new PCI controller */ -#define GDT_PCIMPR 0x05 /* PCI MPR controller */ -/* GDT_EISA, controller subtypes EISA */ -#define GDT3_ID 0x0130941c /* GDT3000/3020 */ -#define GDT3A_ID 0x0230941c /* GDT3000A/3020A/3050A */ -#define GDT3B_ID 0x0330941c /* GDT3000B/3010A */ -/* GDT_ISA */ -#define GDT2_ID 0x0120941c /* GDT2000/2020 */ - -/* vendor ID, device IDs (PCI) */ -/* these defines should already exist in */ -#ifndef PCI_VENDOR_ID_VORTEX -#define PCI_VENDOR_ID_VORTEX 0x1119 /* PCI controller vendor ID */ -#endif -#ifndef PCI_VENDOR_ID_INTEL -#define PCI_VENDOR_ID_INTEL 0x8086 -#endif - -#ifndef PCI_DEVICE_ID_VORTEX_GDT60x0 -/* GDT_PCI */ -#define PCI_DEVICE_ID_VORTEX_GDT60x0 0 /* GDT6000/6020/6050 */ -#define PCI_DEVICE_ID_VORTEX_GDT6000B 1 /* GDT6000B/6010 */ -/* GDT_PCINEW */ -#define PCI_DEVICE_ID_VORTEX_GDT6x10 2 /* GDT6110/6510 */ -#define PCI_DEVICE_ID_VORTEX_GDT6x20 3 /* GDT6120/6520 */ -#define PCI_DEVICE_ID_VORTEX_GDT6530 4 /* GDT6530 */ -#define PCI_DEVICE_ID_VORTEX_GDT6550 5 /* GDT6550 */ -/* GDT_PCINEW, wide/ultra SCSI controllers */ -#define PCI_DEVICE_ID_VORTEX_GDT6x17 6 /* GDT6117/6517 */ -#define PCI_DEVICE_ID_VORTEX_GDT6x27 7 /* GDT6127/6527 */ -#define PCI_DEVICE_ID_VORTEX_GDT6537 8 /* GDT6537 */ -#define PCI_DEVICE_ID_VORTEX_GDT6557 9 /* GDT6557/6557-ECC */ -/* GDT_PCINEW, wide SCSI controllers */ -#define PCI_DEVICE_ID_VORTEX_GDT6x15 10 /* GDT6115/6515 */ -#define PCI_DEVICE_ID_VORTEX_GDT6x25 11 /* GDT6125/6525 */ -#define PCI_DEVICE_ID_VORTEX_GDT6535 12 /* GDT6535 */ -#define PCI_DEVICE_ID_VORTEX_GDT6555 13 /* GDT6555/6555-ECC */ -#endif - -#ifndef PCI_DEVICE_ID_VORTEX_GDT6x17RP -/* GDT_MPR, RP series, wide/ultra SCSI */ -#define PCI_DEVICE_ID_VORTEX_GDT6x17RP 0x100 /* GDT6117RP/GDT6517RP */ -#define PCI_DEVICE_ID_VORTEX_GDT6x27RP 0x101 /* GDT6127RP/GDT6527RP */ -#define PCI_DEVICE_ID_VORTEX_GDT6537RP 0x102 /* GDT6537RP */ -#define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x103 /* GDT6557RP */ -/* GDT_MPR, RP series, narrow/ultra SCSI */ -#define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x104 /* GDT6111RP/GDT6511RP */ -#define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x105 /* GDT6121RP/GDT6521RP */ -#endif -#ifndef PCI_DEVICE_ID_VORTEX_GDT6x17RD -/* GDT_MPR, RD series, wide/ultra SCSI */ -#define PCI_DEVICE_ID_VORTEX_GDT6x17RD 0x110 /* GDT6117RD/GDT6517RD */ -#define PCI_DEVICE_ID_VORTEX_GDT6x27RD 0x111 /* GDT6127RD/GDT6527RD */ -#define PCI_DEVICE_ID_VORTEX_GDT6537RD 0x112 /* GDT6537RD */ -#define PCI_DEVICE_ID_VORTEX_GDT6557RD 0x113 /* GDT6557RD */ -/* GDT_MPR, RD series, narrow/ultra SCSI */ -#define PCI_DEVICE_ID_VORTEX_GDT6x11RD 0x114 /* GDT6111RD/GDT6511RD */ -#define PCI_DEVICE_ID_VORTEX_GDT6x21RD 0x115 /* GDT6121RD/GDT6521RD */ -/* GDT_MPR, RD series, wide/ultra2 SCSI */ -#define PCI_DEVICE_ID_VORTEX_GDT6x18RD 0x118 /* GDT6118RD/GDT6518RD/ - GDT6618RD */ -#define PCI_DEVICE_ID_VORTEX_GDT6x28RD 0x119 /* GDT6128RD/GDT6528RD/ - GDT6628RD */ -#define PCI_DEVICE_ID_VORTEX_GDT6x38RD 0x11A /* GDT6538RD/GDT6638RD */ -#define PCI_DEVICE_ID_VORTEX_GDT6x58RD 0x11B /* GDT6558RD/GDT6658RD */ -/* GDT_MPR, RN series (64-bit PCI), wide/ultra2 SCSI */ -#define PCI_DEVICE_ID_VORTEX_GDT7x18RN 0x168 /* GDT7118RN/GDT7518RN/ - GDT7618RN */ -#define PCI_DEVICE_ID_VORTEX_GDT7x28RN 0x169 /* GDT7128RN/GDT7528RN/ - GDT7628RN */ -#define PCI_DEVICE_ID_VORTEX_GDT7x38RN 0x16A /* GDT7538RN/GDT7638RN */ -#define PCI_DEVICE_ID_VORTEX_GDT7x58RN 0x16B /* GDT7558RN/GDT7658RN */ -#endif - -#ifndef PCI_DEVICE_ID_VORTEX_GDT6x19RD -/* GDT_MPR, RD series, Fibre Channel */ -#define PCI_DEVICE_ID_VORTEX_GDT6x19RD 0x210 /* GDT6519RD/GDT6619RD */ -#define PCI_DEVICE_ID_VORTEX_GDT6x29RD 0x211 /* GDT6529RD/GDT6629RD */ -/* GDT_MPR, RN series (64-bit PCI), Fibre Channel */ -#define PCI_DEVICE_ID_VORTEX_GDT7x19RN 0x260 /* GDT7519RN/GDT7619RN */ -#define PCI_DEVICE_ID_VORTEX_GDT7x29RN 0x261 /* GDT7529RN/GDT7629RN */ -#endif - -#ifndef PCI_DEVICE_ID_VORTEX_GDTMAXRP -/* GDT_MPR, last device ID */ -#define PCI_DEVICE_ID_VORTEX_GDTMAXRP 0x2ff -#endif - -#ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX -/* new GDT Rx Controller */ -#define PCI_DEVICE_ID_VORTEX_GDTNEWRX 0x300 -#endif - -#ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX2 -/* new(2) GDT Rx Controller */ -#define PCI_DEVICE_ID_VORTEX_GDTNEWRX2 0x301 -#endif - -#ifndef PCI_DEVICE_ID_INTEL_SRC -/* Intel Storage RAID Controller */ -#define PCI_DEVICE_ID_INTEL_SRC 0x600 -#endif - -#ifndef PCI_DEVICE_ID_INTEL_SRC_XSCALE -/* Intel Storage RAID Controller */ -#define PCI_DEVICE_ID_INTEL_SRC_XSCALE 0x601 -#endif - -/* limits */ -#define GDTH_SCRATCH PAGE_SIZE /* 4KB scratch buffer */ -#define GDTH_MAXCMDS 120 -#define GDTH_MAXC_P_L 16 /* max. cmds per lun */ -#define GDTH_MAX_RAW 2 /* max. cmds per raw device */ -#define MAXOFFSETS 128 -#define MAXHA 16 -#define MAXID 127 -#define MAXLUN 8 -#define MAXBUS 6 -#define MAX_EVENTS 100 /* event buffer count */ -#define MAX_RES_ARGS 40 /* device reservation, - must be a multiple of 4 */ -#define MAXCYLS 1024 -#define HEADS 64 -#define SECS 32 /* mapping 64*32 */ -#define MEDHEADS 127 -#define MEDSECS 63 /* mapping 127*63 */ -#define BIGHEADS 255 -#define BIGSECS 63 /* mapping 255*63 */ - -/* special command ptr. */ -#define UNUSED_CMND ((Scsi_Cmnd *)-1) -#define INTERNAL_CMND ((Scsi_Cmnd *)-2) -#define SCREEN_CMND ((Scsi_Cmnd *)-3) -#define SPECIAL_SCP(p) (p==UNUSED_CMND || p==INTERNAL_CMND || p==SCREEN_CMND) - -/* controller services */ -#define SCSIRAWSERVICE 3 -#define CACHESERVICE 9 -#define SCREENSERVICE 11 - -/* screenservice defines */ -#define MSG_INV_HANDLE -1 /* special message handle */ -#define MSGLEN 16 /* size of message text */ -#define MSG_SIZE 34 /* size of message structure */ -#define MSG_REQUEST 0 /* async. event: message */ - -/* cacheservice defines */ -#define SECTOR_SIZE 0x200 /* always 512 bytes per sec. */ - -/* DPMEM constants */ -#define DPMEM_MAGIC 0xC0FFEE11 -#define IC_HEADER_BYTES 48 -#define IC_QUEUE_BYTES 4 -#define DPMEM_COMMAND_OFFSET IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS - -/* cluster_type constants */ -#define CLUSTER_DRIVE 1 -#define CLUSTER_MOUNTED 2 -#define CLUSTER_RESERVED 4 -#define CLUSTER_RESERVE_STATE (CLUSTER_DRIVE|CLUSTER_MOUNTED|CLUSTER_RESERVED) - -/* commands for all services, cache service */ -#define GDT_INIT 0 /* service initialization */ -#define GDT_READ 1 /* read command */ -#define GDT_WRITE 2 /* write command */ -#define GDT_INFO 3 /* information about devices */ -#define GDT_FLUSH 4 /* flush dirty cache buffers */ -#define GDT_IOCTL 5 /* ioctl command */ -#define GDT_DEVTYPE 9 /* additional information */ -#define GDT_MOUNT 10 /* mount cache device */ -#define GDT_UNMOUNT 11 /* unmount cache device */ -#define GDT_SET_FEAT 12 /* set feat. (scatter/gather) */ -#define GDT_GET_FEAT 13 /* get features */ -#define GDT_WRITE_THR 16 /* write through */ -#define GDT_READ_THR 17 /* read through */ -#define GDT_EXT_INFO 18 /* extended info */ -#define GDT_RESET 19 /* controller reset */ -#define GDT_RESERVE_DRV 20 /* reserve host drive */ -#define GDT_RELEASE_DRV 21 /* release host drive */ -#define GDT_CLUST_INFO 22 /* cluster info */ -#define GDT_RW_ATTRIBS 23 /* R/W attribs (write thru,..)*/ -#define GDT_CLUST_RESET 24 /* releases the cluster drives*/ -#define GDT_FREEZE_IO 25 /* freezes all IOs */ -#define GDT_UNFREEZE_IO 26 /* unfreezes all IOs */ -#define GDT_X_INIT_HOST 29 /* ext. init: 64 bit support */ -#define GDT_X_INFO 30 /* ext. info for drives>2TB */ - -/* raw service commands */ -#define GDT_RESERVE 14 /* reserve dev. to raw serv. */ -#define GDT_RELEASE 15 /* release device */ -#define GDT_RESERVE_ALL 16 /* reserve all devices */ -#define GDT_RELEASE_ALL 17 /* release all devices */ -#define GDT_RESET_BUS 18 /* reset bus */ -#define GDT_SCAN_START 19 /* start device scan */ -#define GDT_SCAN_END 20 /* stop device scan */ -#define GDT_X_INIT_RAW 21 /* ext. init: 64 bit support */ - -/* screen service commands */ -#define GDT_REALTIME 3 /* realtime clock to screens. */ -#define GDT_X_INIT_SCR 4 /* ext. init: 64 bit support */ - -/* IOCTL command defines */ -#define SCSI_DR_INFO 0x00 /* SCSI drive info */ -#define SCSI_CHAN_CNT 0x05 /* SCSI channel count */ -#define SCSI_DR_LIST 0x06 /* SCSI drive list */ -#define SCSI_DEF_CNT 0x15 /* grown/primary defects */ -#define DSK_STATISTICS 0x4b /* SCSI disk statistics */ -#define IOCHAN_DESC 0x5d /* description of IO channel */ -#define IOCHAN_RAW_DESC 0x5e /* description of raw IO chn. */ -#define L_CTRL_PATTERN 0x20000000L /* SCSI IOCTL mask */ -#define ARRAY_INFO 0x12 /* array drive info */ -#define ARRAY_DRV_LIST 0x0f /* array drive list */ -#define ARRAY_DRV_LIST2 0x34 /* array drive list (new) */ -#define LA_CTRL_PATTERN 0x10000000L /* array IOCTL mask */ -#define CACHE_DRV_CNT 0x01 /* cache drive count */ -#define CACHE_DRV_LIST 0x02 /* cache drive list */ -#define CACHE_INFO 0x04 /* cache info */ -#define CACHE_CONFIG 0x05 /* cache configuration */ -#define CACHE_DRV_INFO 0x07 /* cache drive info */ -#define BOARD_FEATURES 0x15 /* controller features */ -#define BOARD_INFO 0x28 /* controller info */ -#define SET_PERF_MODES 0x82 /* set mode (coalescing,..) */ -#define GET_PERF_MODES 0x83 /* get mode */ -#define CACHE_READ_OEM_STRING_RECORD 0x84 /* read OEM string record */ -#define HOST_GET 0x10001L /* get host drive list */ -#define IO_CHANNEL 0x00020000L /* default IO channel */ -#define INVALID_CHANNEL 0x0000ffffL /* invalid channel */ - -/* service errors */ -#define S_OK 1 /* no error */ -#define S_GENERR 6 /* general error */ -#define S_BSY 7 /* controller busy */ -#define S_CACHE_UNKNOWN 12 /* cache serv.: drive unknown */ -#define S_RAW_SCSI 12 /* raw serv.: target error */ -#define S_RAW_ILL 0xff /* raw serv.: illegal */ -#define S_NOFUNC -2 /* unknown function */ -#define S_CACHE_RESERV -24 /* cache: reserv. conflict */ - -/* timeout values */ -#define INIT_RETRIES 100000 /* 100000 * 1ms = 100s */ -#define INIT_TIMEOUT 100000 /* 100000 * 1ms = 100s */ -#define POLL_TIMEOUT 10000 /* 10000 * 1ms = 10s */ - -/* priorities */ -#define DEFAULT_PRI 0x20 -#define IOCTL_PRI 0x10 -#define HIGH_PRI 0x08 - -/* data directions */ -#define GDTH_DATA_IN 0x01000000L /* data from target */ -#define GDTH_DATA_OUT 0x00000000L /* data to target */ - -/* BMIC registers (EISA controllers) */ -#define ID0REG 0x0c80 /* board ID */ -#define EINTENABREG 0x0c89 /* interrupt enable */ -#define SEMA0REG 0x0c8a /* command semaphore */ -#define SEMA1REG 0x0c8b /* status semaphore */ -#define LDOORREG 0x0c8d /* local doorbell */ -#define EDENABREG 0x0c8e /* EISA system doorbell enab. */ -#define EDOORREG 0x0c8f /* EISA system doorbell */ -#define MAILBOXREG 0x0c90 /* mailbox reg. (16 bytes) */ -#define EISAREG 0x0cc0 /* EISA configuration */ - -/* other defines */ -#define LINUX_OS 8 /* used for cache optim. */ -#define SECS32 0x1f /* round capacity */ -#define BIOS_ID_OFFS 0x10 /* offset contr-ID in ISABIOS */ -#define LOCALBOARD 0 /* board node always 0 */ -#define ASYNCINDEX 0 /* cmd index async. event */ -#define SPEZINDEX 1 /* cmd index unknown service */ -#define COALINDEX (GDTH_MAXCMDS + 2) - -/* features */ -#define SCATTER_GATHER 1 /* s/g feature */ -#define GDT_WR_THROUGH 0x100 /* WRITE_THROUGH supported */ -#define GDT_64BIT 0x200 /* 64bit / drv>2TB support */ - -#include "gdth_ioctl.h" - -/* screenservice message */ -typedef struct { - u32 msg_handle; /* message handle */ - u32 msg_len; /* size of message */ - u32 msg_alen; /* answer length */ - u8 msg_answer; /* answer flag */ - u8 msg_ext; /* more messages */ - u8 msg_reserved[2]; - char msg_text[MSGLEN+2]; /* the message text */ -} __attribute__((packed)) gdth_msg_str; - - -/* IOCTL data structures */ - -/* Status coalescing buffer for returning multiple requests per interrupt */ -typedef struct { - u32 status; - u32 ext_status; - u32 info0; - u32 info1; -} __attribute__((packed)) gdth_coal_status; - -/* performance mode data structure */ -typedef struct { - u32 version; /* The version of this IOCTL structure. */ - u32 st_mode; /* 0=dis., 1=st_buf_addr1 valid, 2=both */ - u32 st_buff_addr1; /* physical address of status buffer 1 */ - u32 st_buff_u_addr1; /* reserved for 64 bit addressing */ - u32 st_buff_indx1; /* reserved command idx. for this buffer */ - u32 st_buff_addr2; /* physical address of status buffer 1 */ - u32 st_buff_u_addr2; /* reserved for 64 bit addressing */ - u32 st_buff_indx2; /* reserved command idx. for this buffer */ - u32 st_buff_size; /* size of each buffer in bytes */ - u32 cmd_mode; /* 0 = mode disabled, 1 = cmd_buff_addr1 */ - u32 cmd_buff_addr1; /* physical address of cmd buffer 1 */ - u32 cmd_buff_u_addr1; /* reserved for 64 bit addressing */ - u32 cmd_buff_indx1; /* cmd buf addr1 unique identifier */ - u32 cmd_buff_addr2; /* physical address of cmd buffer 1 */ - u32 cmd_buff_u_addr2; /* reserved for 64 bit addressing */ - u32 cmd_buff_indx2; /* cmd buf addr1 unique identifier */ - u32 cmd_buff_size; /* size of each cmd buffer in bytes */ - u32 reserved1; - u32 reserved2; -} __attribute__((packed)) gdth_perf_modes; - -/* SCSI drive info */ -typedef struct { - u8 vendor[8]; /* vendor string */ - u8 product[16]; /* product string */ - u8 revision[4]; /* revision */ - u32 sy_rate; /* current rate for sync. tr. */ - u32 sy_max_rate; /* max. rate for sync. tr. */ - u32 no_ldrive; /* belongs to this log. drv.*/ - u32 blkcnt; /* number of blocks */ - u16 blksize; /* size of block in bytes */ - u8 available; /* flag: access is available */ - u8 init; /* medium is initialized */ - u8 devtype; /* SCSI devicetype */ - u8 rm_medium; /* medium is removable */ - u8 wp_medium; /* medium is write protected */ - u8 ansi; /* SCSI I/II or III? */ - u8 protocol; /* same as ansi */ - u8 sync; /* flag: sync. transfer enab. */ - u8 disc; /* flag: disconnect enabled */ - u8 queueing; /* flag: command queing enab. */ - u8 cached; /* flag: caching enabled */ - u8 target_id; /* target ID of device */ - u8 lun; /* LUN id of device */ - u8 orphan; /* flag: drive fragment */ - u32 last_error; /* sense key or drive state */ - u32 last_result; /* result of last command */ - u32 check_errors; /* err. in last surface check */ - u8 percent; /* progress for surface check */ - u8 last_check; /* IOCTRL operation */ - u8 res[2]; - u32 flags; /* from 1.19/2.19: raw reserv.*/ - u8 multi_bus; /* multi bus dev? (fibre ch.) */ - u8 mb_status; /* status: available? */ - u8 res2[2]; - u8 mb_alt_status; /* status on second bus */ - u8 mb_alt_bid; /* number of second bus */ - u8 mb_alt_tid; /* target id on second bus */ - u8 res3; - u8 fc_flag; /* from 1.22/2.22: info valid?*/ - u8 res4; - u16 fc_frame_size; /* frame size (bytes) */ - char wwn[8]; /* world wide name */ -} __attribute__((packed)) gdth_diskinfo_str; - -/* get SCSI channel count */ -typedef struct { - u32 channel_no; /* number of channel */ - u32 drive_cnt; /* drive count */ - u8 siop_id; /* SCSI processor ID */ - u8 siop_state; /* SCSI processor state */ -} __attribute__((packed)) gdth_getch_str; - -/* get SCSI drive numbers */ -typedef struct { - u32 sc_no; /* SCSI channel */ - u32 sc_cnt; /* sc_list[] elements */ - u32 sc_list[MAXID]; /* minor device numbers */ -} __attribute__((packed)) gdth_drlist_str; - -/* get grown/primary defect count */ -typedef struct { - u8 sddc_type; /* 0x08: grown, 0x10: prim. */ - u8 sddc_format; /* list entry format */ - u8 sddc_len; /* list entry length */ - u8 sddc_res; - u32 sddc_cnt; /* entry count */ -} __attribute__((packed)) gdth_defcnt_str; - -/* disk statistics */ -typedef struct { - u32 bid; /* SCSI channel */ - u32 first; /* first SCSI disk */ - u32 entries; /* number of elements */ - u32 count; /* (R) number of init. el. */ - u32 mon_time; /* time stamp */ - struct { - u8 tid; /* target ID */ - u8 lun; /* LUN */ - u8 res[2]; - u32 blk_size; /* block size in bytes */ - u32 rd_count; /* bytes read */ - u32 wr_count; /* bytes written */ - u32 rd_blk_count; /* blocks read */ - u32 wr_blk_count; /* blocks written */ - u32 retries; /* retries */ - u32 reassigns; /* reassigns */ - } __attribute__((packed)) list[1]; -} __attribute__((packed)) gdth_dskstat_str; - -/* IO channel header */ -typedef struct { - u32 version; /* version (-1UL: newest) */ - u8 list_entries; /* list entry count */ - u8 first_chan; /* first channel number */ - u8 last_chan; /* last channel number */ - u8 chan_count; /* (R) channel count */ - u32 list_offset; /* offset of list[0] */ -} __attribute__((packed)) gdth_iochan_header; - -/* get IO channel description */ -typedef struct { - gdth_iochan_header hdr; - struct { - u32 address; /* channel address */ - u8 type; /* type (SCSI, FCAL) */ - u8 local_no; /* local number */ - u16 features; /* channel features */ - } __attribute__((packed)) list[MAXBUS]; -} __attribute__((packed)) gdth_iochan_str; - -/* get raw IO channel description */ -typedef struct { - gdth_iochan_header hdr; - struct { - u8 proc_id; /* processor id */ - u8 proc_defect; /* defect ? */ - u8 reserved[2]; - } __attribute__((packed)) list[MAXBUS]; -} __attribute__((packed)) gdth_raw_iochan_str; - -/* array drive component */ -typedef struct { - u32 al_controller; /* controller ID */ - u8 al_cache_drive; /* cache drive number */ - u8 al_status; /* cache drive state */ - u8 al_res[2]; -} __attribute__((packed)) gdth_arraycomp_str; - -/* array drive information */ -typedef struct { - u8 ai_type; /* array type (RAID0,4,5) */ - u8 ai_cache_drive_cnt; /* active cachedrives */ - u8 ai_state; /* array drive state */ - u8 ai_master_cd; /* master cachedrive */ - u32 ai_master_controller; /* ID of master controller */ - u32 ai_size; /* user capacity [sectors] */ - u32 ai_striping_size; /* striping size [sectors] */ - u32 ai_secsize; /* sector size [bytes] */ - u32 ai_err_info; /* failed cache drive */ - u8 ai_name[8]; /* name of the array drive */ - u8 ai_controller_cnt; /* number of controllers */ - u8 ai_removable; /* flag: removable */ - u8 ai_write_protected; /* flag: write protected */ - u8 ai_devtype; /* type: always direct access */ - gdth_arraycomp_str ai_drives[35]; /* drive components: */ - u8 ai_drive_entries; /* number of drive components */ - u8 ai_protected; /* protection flag */ - u8 ai_verify_state; /* state of a parity verify */ - u8 ai_ext_state; /* extended array drive state */ - u8 ai_expand_state; /* array expand state (>=2.18)*/ - u8 ai_reserved[3]; -} __attribute__((packed)) gdth_arrayinf_str; - -/* get array drive list */ -typedef struct { - u32 controller_no; /* controller no. */ - u8 cd_handle; /* master cachedrive */ - u8 is_arrayd; /* Flag: is array drive? */ - u8 is_master; /* Flag: is array master? */ - u8 is_parity; /* Flag: is parity drive? */ - u8 is_hotfix; /* Flag: is hotfix drive? */ - u8 res[3]; -} __attribute__((packed)) gdth_alist_str; - -typedef struct { - u32 entries_avail; /* allocated entries */ - u32 entries_init; /* returned entries */ - u32 first_entry; /* first entry number */ - u32 list_offset; /* offset of following list */ - gdth_alist_str list[1]; /* list */ -} __attribute__((packed)) gdth_arcdl_str; - -/* cache info/config IOCTL */ -typedef struct { - u32 version; /* firmware version */ - u16 state; /* cache state (on/off) */ - u16 strategy; /* cache strategy */ - u16 write_back; /* write back state (on/off) */ - u16 block_size; /* cache block size */ -} __attribute__((packed)) gdth_cpar_str; - -typedef struct { - u32 csize; /* cache size */ - u32 read_cnt; /* read/write counter */ - u32 write_cnt; - u32 tr_hits; /* hits */ - u32 sec_hits; - u32 sec_miss; /* misses */ -} __attribute__((packed)) gdth_cstat_str; - -typedef struct { - gdth_cpar_str cpar; - gdth_cstat_str cstat; -} __attribute__((packed)) gdth_cinfo_str; - -/* cache drive info */ -typedef struct { - u8 cd_name[8]; /* cache drive name */ - u32 cd_devtype; /* SCSI devicetype */ - u32 cd_ldcnt; /* number of log. drives */ - u32 cd_last_error; /* last error */ - u8 cd_initialized; /* drive is initialized */ - u8 cd_removable; /* media is removable */ - u8 cd_write_protected; /* write protected */ - u8 cd_flags; /* Pool Hot Fix? */ - u32 ld_blkcnt; /* number of blocks */ - u32 ld_blksize; /* blocksize */ - u32 ld_dcnt; /* number of disks */ - u32 ld_slave; /* log. drive index */ - u32 ld_dtype; /* type of logical drive */ - u32 ld_last_error; /* last error */ - u8 ld_name[8]; /* log. drive name */ - u8 ld_error; /* error */ -} __attribute__((packed)) gdth_cdrinfo_str; - -/* OEM string */ -typedef struct { - u32 ctl_version; - u32 file_major_version; - u32 file_minor_version; - u32 buffer_size; - u32 cpy_count; - u32 ext_error; - u32 oem_id; - u32 board_id; -} __attribute__((packed)) gdth_oem_str_params; - -typedef struct { - u8 product_0_1_name[16]; - u8 product_4_5_name[16]; - u8 product_cluster_name[16]; - u8 product_reserved[16]; - u8 scsi_cluster_target_vendor_id[16]; - u8 cluster_raid_fw_name[16]; - u8 oem_brand_name[16]; - u8 oem_raid_type[16]; - u8 bios_type[13]; - u8 bios_title[50]; - u8 oem_company_name[37]; - u32 pci_id_1; - u32 pci_id_2; - u8 validation_status[80]; - u8 reserved_1[4]; - u8 scsi_host_drive_inquiry_vendor_id[16]; - u8 library_file_template[16]; - u8 reserved_2[16]; - u8 tool_name_1[32]; - u8 tool_name_2[32]; - u8 tool_name_3[32]; - u8 oem_contact_1[84]; - u8 oem_contact_2[84]; - u8 oem_contact_3[84]; -} __attribute__((packed)) gdth_oem_str; - -typedef struct { - gdth_oem_str_params params; - gdth_oem_str text; -} __attribute__((packed)) gdth_oem_str_ioctl; - -/* board features */ -typedef struct { - u8 chaining; /* Chaining supported */ - u8 striping; /* Striping (RAID-0) supp. */ - u8 mirroring; /* Mirroring (RAID-1) supp. */ - u8 raid; /* RAID-4/5/10 supported */ -} __attribute__((packed)) gdth_bfeat_str; - -/* board info IOCTL */ -typedef struct { - u32 ser_no; /* serial no. */ - u8 oem_id[2]; /* OEM ID */ - u16 ep_flags; /* eprom flags */ - u32 proc_id; /* processor ID */ - u32 memsize; /* memory size (bytes) */ - u8 mem_banks; /* memory banks */ - u8 chan_type; /* channel type */ - u8 chan_count; /* channel count */ - u8 rdongle_pres; /* dongle present? */ - u32 epr_fw_ver; /* (eprom) firmware version */ - u32 upd_fw_ver; /* (update) firmware version */ - u32 upd_revision; /* update revision */ - char type_string[16]; /* controller name */ - char raid_string[16]; /* RAID firmware name */ - u8 update_pres; /* update present? */ - u8 xor_pres; /* XOR engine present? */ - u8 prom_type; /* ROM type (eprom/flash) */ - u8 prom_count; /* number of ROM devices */ - u32 dup_pres; /* duplexing module present? */ - u32 chan_pres; /* number of expansion chn. */ - u32 mem_pres; /* memory expansion inst. ? */ - u8 ft_bus_system; /* fault bus supported? */ - u8 subtype_valid; /* board_subtype valid? */ - u8 board_subtype; /* subtype/hardware level */ - u8 ramparity_pres; /* RAM parity check hardware? */ -} __attribute__((packed)) gdth_binfo_str; - -/* get host drive info */ -typedef struct { - char name[8]; /* host drive name */ - u32 size; /* size (sectors) */ - u8 host_drive; /* host drive number */ - u8 log_drive; /* log. drive (master) */ - u8 reserved; - u8 rw_attribs; /* r/w attribs */ - u32 start_sec; /* start sector */ -} __attribute__((packed)) gdth_hentry_str; - -typedef struct { - u32 entries; /* entry count */ - u32 offset; /* offset of entries */ - u8 secs_p_head; /* sectors/head */ - u8 heads_p_cyl; /* heads/cylinder */ - u8 reserved; - u8 clust_drvtype; /* cluster drive type */ - u32 location; /* controller number */ - gdth_hentry_str entry[MAX_HDRIVES]; /* entries */ -} __attribute__((packed)) gdth_hget_str; - - -/* DPRAM structures */ - -/* interface area ISA/PCI */ -typedef struct { - u8 S_Cmd_Indx; /* special command */ - u8 volatile S_Status; /* status special command */ - u16 reserved1; - u32 S_Info[4]; /* add. info special command */ - u8 volatile Sema0; /* command semaphore */ - u8 reserved2[3]; - u8 Cmd_Index; /* command number */ - u8 reserved3[3]; - u16 volatile Status; /* command status */ - u16 Service; /* service(for async.events) */ - u32 Info[2]; /* additional info */ - struct { - u16 offset; /* command offs. in the DPRAM*/ - u16 serv_id; /* service */ - } __attribute__((packed)) comm_queue[MAXOFFSETS]; /* command queue */ - u32 bios_reserved[2]; - u8 gdt_dpr_cmd[1]; /* commands */ -} __attribute__((packed)) gdt_dpr_if; - -/* SRAM structure PCI controllers */ -typedef struct { - u32 magic; /* controller ID from BIOS */ - u16 need_deinit; /* switch betw. BIOS/driver */ - u8 switch_support; /* see need_deinit */ - u8 padding[9]; - u8 os_used[16]; /* OS code per service */ - u8 unused[28]; - u8 fw_magic; /* contr. ID from firmware */ -} __attribute__((packed)) gdt_pci_sram; - -/* SRAM structure EISA controllers (but NOT GDT3000/3020) */ -typedef struct { - u8 os_used[16]; /* OS code per service */ - u16 need_deinit; /* switch betw. BIOS/driver */ - u8 switch_support; /* see need_deinit */ - u8 padding; -} __attribute__((packed)) gdt_eisa_sram; - - -/* DPRAM ISA controllers */ -typedef struct { - union { - struct { - u8 bios_used[0x3c00-32]; /* 15KB - 32Bytes BIOS */ - u32 magic; /* controller (EISA) ID */ - u16 need_deinit; /* switch betw. BIOS/driver */ - u8 switch_support; /* see need_deinit */ - u8 padding[9]; - u8 os_used[16]; /* OS code per service */ - } __attribute__((packed)) dp_sram; - u8 bios_area[0x4000]; /* 16KB reserved for BIOS */ - } bu; - union { - gdt_dpr_if ic; /* interface area */ - u8 if_area[0x3000]; /* 12KB for interface */ - } u; - struct { - u8 memlock; /* write protection DPRAM */ - u8 event; /* release event */ - u8 irqen; /* board interrupts enable */ - u8 irqdel; /* acknowledge board int. */ - u8 volatile Sema1; /* status semaphore */ - u8 rq; /* IRQ/DRQ configuration */ - } __attribute__((packed)) io; -} __attribute__((packed)) gdt2_dpram_str; - -/* DPRAM PCI controllers */ -typedef struct { - union { - gdt_dpr_if ic; /* interface area */ - u8 if_area[0xff0-sizeof(gdt_pci_sram)]; - } u; - gdt_pci_sram gdt6sr; /* SRAM structure */ - struct { - u8 unused0[1]; - u8 volatile Sema1; /* command semaphore */ - u8 unused1[3]; - u8 irqen; /* board interrupts enable */ - u8 unused2[2]; - u8 event; /* release event */ - u8 unused3[3]; - u8 irqdel; /* acknowledge board int. */ - u8 unused4[3]; - } __attribute__((packed)) io; -} __attribute__((packed)) gdt6_dpram_str; - -/* PLX register structure (new PCI controllers) */ -typedef struct { - u8 cfg_reg; /* DPRAM cfg.(2:below 1MB,0:anywhere)*/ - u8 unused1[0x3f]; - u8 volatile sema0_reg; /* command semaphore */ - u8 volatile sema1_reg; /* status semaphore */ - u8 unused2[2]; - u16 volatile status; /* command status */ - u16 service; /* service */ - u32 info[2]; /* additional info */ - u8 unused3[0x10]; - u8 ldoor_reg; /* PCI to local doorbell */ - u8 unused4[3]; - u8 volatile edoor_reg; /* local to PCI doorbell */ - u8 unused5[3]; - u8 control0; /* control0 register(unused) */ - u8 control1; /* board interrupts enable */ - u8 unused6[0x16]; -} __attribute__((packed)) gdt6c_plx_regs; - -/* DPRAM new PCI controllers */ -typedef struct { - union { - gdt_dpr_if ic; /* interface area */ - u8 if_area[0x4000-sizeof(gdt_pci_sram)]; - } u; - gdt_pci_sram gdt6sr; /* SRAM structure */ -} __attribute__((packed)) gdt6c_dpram_str; - -/* i960 register structure (PCI MPR controllers) */ -typedef struct { - u8 unused1[16]; - u8 volatile sema0_reg; /* command semaphore */ - u8 unused2; - u8 volatile sema1_reg; /* status semaphore */ - u8 unused3; - u16 volatile status; /* command status */ - u16 service; /* service */ - u32 info[2]; /* additional info */ - u8 ldoor_reg; /* PCI to local doorbell */ - u8 unused4[11]; - u8 volatile edoor_reg; /* local to PCI doorbell */ - u8 unused5[7]; - u8 edoor_en_reg; /* board interrupts enable */ - u8 unused6[27]; - u32 unused7[939]; - u32 severity; - char evt_str[256]; /* event string */ -} __attribute__((packed)) gdt6m_i960_regs; - -/* DPRAM PCI MPR controllers */ -typedef struct { - gdt6m_i960_regs i960r; /* 4KB i960 registers */ - union { - gdt_dpr_if ic; /* interface area */ - u8 if_area[0x3000-sizeof(gdt_pci_sram)]; - } u; - gdt_pci_sram gdt6sr; /* SRAM structure */ -} __attribute__((packed)) gdt6m_dpram_str; - - -/* PCI resources */ -typedef struct { - struct pci_dev *pdev; - unsigned long dpmem; /* DPRAM address */ - unsigned long io; /* IO address */ -} gdth_pci_str; - - -/* controller information structure */ -typedef struct { - struct Scsi_Host *shost; - struct list_head list; - u16 hanum; - u16 oem_id; /* OEM */ - u16 type; /* controller class */ - u32 stype; /* subtype (PCI: device ID) */ - u16 fw_vers; /* firmware version */ - u16 cache_feat; /* feat. cache serv. (s/g,..)*/ - u16 raw_feat; /* feat. raw service (s/g,..)*/ - u16 screen_feat; /* feat. raw service (s/g,..)*/ - u16 bmic; /* BMIC address (EISA) */ - void __iomem *brd; /* DPRAM address */ - u32 brd_phys; /* slot number/BIOS address */ - gdt6c_plx_regs *plx; /* PLX regs (new PCI contr.) */ - gdth_cmd_str cmdext; - gdth_cmd_str *pccb; /* address command structure */ - u32 ccb_phys; /* phys. address */ -#ifdef INT_COAL - gdth_coal_status *coal_stat; /* buffer for coalescing int.*/ - u64 coal_stat_phys; /* phys. address */ -#endif - char *pscratch; /* scratch (DMA) buffer */ - u64 scratch_phys; /* phys. address */ - u8 scratch_busy; /* in use? */ - u8 dma64_support; /* 64-bit DMA supported? */ - gdth_msg_str *pmsg; /* message buffer */ - u64 msg_phys; /* phys. address */ - u8 scan_mode; /* current scan mode */ - u8 irq; /* IRQ */ - u8 drq; /* DRQ (ISA controllers) */ - u16 status; /* command status */ - u16 service; /* service/firmware ver./.. */ - u32 info; - u32 info2; /* additional info */ - Scsi_Cmnd *req_first; /* top of request queue */ - struct { - u8 present; /* Flag: host drive present? */ - u8 is_logdrv; /* Flag: log. drive (master)? */ - u8 is_arraydrv; /* Flag: array drive? */ - u8 is_master; /* Flag: array drive master? */ - u8 is_parity; /* Flag: parity drive? */ - u8 is_hotfix; /* Flag: hotfix drive? */ - u8 master_no; /* number of master drive */ - u8 lock; /* drive locked? (hot plug) */ - u8 heads; /* mapping */ - u8 secs; - u16 devtype; /* further information */ - u64 size; /* capacity */ - u8 ldr_no; /* log. drive no. */ - u8 rw_attribs; /* r/w attributes */ - u8 cluster_type; /* cluster properties */ - u8 media_changed; /* Flag:MOUNT/UNMOUNT occurred */ - u32 start_sec; /* start sector */ - } hdr[MAX_LDRIVES]; /* host drives */ - struct { - u8 lock; /* channel locked? (hot plug) */ - u8 pdev_cnt; /* physical device count */ - u8 local_no; /* local channel number */ - u8 io_cnt[MAXID]; /* current IO count */ - u32 address; /* channel address */ - u32 id_list[MAXID]; /* IDs of the phys. devices */ - } raw[MAXBUS]; /* SCSI channels */ - struct { - Scsi_Cmnd *cmnd; /* pending request */ - u16 service; /* service */ - } cmd_tab[GDTH_MAXCMDS]; /* table of pend. requests */ - struct gdth_cmndinfo { /* per-command private info */ - int index; - int internal_command; /* don't call scsi_done */ - gdth_cmd_str *internal_cmd_str; /* crier for internal messages*/ - dma_addr_t sense_paddr; /* sense dma-addr */ - u8 priority; - int timeout_count; /* # of timeout calls */ - volatile int wait_for_completion; - u16 status; - u32 info; - enum dma_data_direction dma_dir; - int phase; /* ???? */ - int OpCode; - } cmndinfo[GDTH_MAXCMDS]; /* index==0 is free */ - u8 bus_cnt; /* SCSI bus count */ - u8 tid_cnt; /* Target ID count */ - u8 bus_id[MAXBUS]; /* IOP IDs */ - u8 virt_bus; /* number of virtual bus */ - u8 more_proc; /* more /proc info supported */ - u16 cmd_cnt; /* command count in DPRAM */ - u16 cmd_len; /* length of actual command */ - u16 cmd_offs_dpmem; /* actual offset in DPRAM */ - u16 ic_all_size; /* sizeof DPRAM interf. area */ - gdth_cpar_str cpar; /* controller cache par. */ - gdth_bfeat_str bfeat; /* controller features */ - gdth_binfo_str binfo; /* controller info */ - gdth_evt_data dvr; /* event structure */ - spinlock_t smp_lock; - struct pci_dev *pdev; - char oem_name[8]; -#ifdef GDTH_DMA_STATISTICS - unsigned long dma32_cnt, dma64_cnt; /* statistics: DMA buffer */ -#endif - struct scsi_device *sdev; -} gdth_ha_str; - -static inline struct gdth_cmndinfo *gdth_cmnd_priv(struct scsi_cmnd* cmd) -{ - return (struct gdth_cmndinfo *)cmd->host_scribble; -} - -/* INQUIRY data format */ -typedef struct { - u8 type_qual; - u8 modif_rmb; - u8 version; - u8 resp_aenc; - u8 add_length; - u8 reserved1; - u8 reserved2; - u8 misc; - u8 vendor[8]; - u8 product[16]; - u8 revision[4]; -} __attribute__((packed)) gdth_inq_data; - -/* READ_CAPACITY data format */ -typedef struct { - u32 last_block_no; - u32 block_length; -} __attribute__((packed)) gdth_rdcap_data; - -/* READ_CAPACITY (16) data format */ -typedef struct { - u64 last_block_no; - u32 block_length; -} __attribute__((packed)) gdth_rdcap16_data; - -/* REQUEST_SENSE data format */ -typedef struct { - u8 errorcode; - u8 segno; - u8 key; - u32 info; - u8 add_length; - u32 cmd_info; - u8 adsc; - u8 adsq; - u8 fruc; - u8 key_spec[3]; -} __attribute__((packed)) gdth_sense_data; - -/* MODE_SENSE data format */ -typedef struct { - struct { - u8 data_length; - u8 med_type; - u8 dev_par; - u8 bd_length; - } __attribute__((packed)) hd; - struct { - u8 dens_code; - u8 block_count[3]; - u8 reserved; - u8 block_length[3]; - } __attribute__((packed)) bd; -} __attribute__((packed)) gdth_modep_data; - -/* stack frame */ -typedef struct { - unsigned long b[10]; /* 32/64 bit compiler ! */ -} __attribute__((packed)) gdth_stackframe; - - -/* function prototyping */ - -int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/gdth_ioctl.h b/ANDROID_3.4.5/drivers/scsi/gdth_ioctl.h deleted file mode 100644 index b004c616..00000000 --- a/ANDROID_3.4.5/drivers/scsi/gdth_ioctl.h +++ /dev/null @@ -1,339 +0,0 @@ -#ifndef _GDTH_IOCTL_H -#define _GDTH_IOCTL_H - -/* gdth_ioctl.h - * $Id: gdth_ioctl.h,v 1.14 2004/02/19 15:43:15 achim Exp $ - */ - -/* IOCTLs */ -#define GDTIOCTL_MASK ('J'<<8) -#define GDTIOCTL_GENERAL (GDTIOCTL_MASK | 0) /* general IOCTL */ -#define GDTIOCTL_DRVERS (GDTIOCTL_MASK | 1) /* get driver version */ -#define GDTIOCTL_CTRTYPE (GDTIOCTL_MASK | 2) /* get controller type */ -#define GDTIOCTL_OSVERS (GDTIOCTL_MASK | 3) /* get OS version */ -#define GDTIOCTL_HDRLIST (GDTIOCTL_MASK | 4) /* get host drive list */ -#define GDTIOCTL_CTRCNT (GDTIOCTL_MASK | 5) /* get controller count */ -#define GDTIOCTL_LOCKDRV (GDTIOCTL_MASK | 6) /* lock host drive */ -#define GDTIOCTL_LOCKCHN (GDTIOCTL_MASK | 7) /* lock channel */ -#define GDTIOCTL_EVENT (GDTIOCTL_MASK | 8) /* read controller events */ -#define GDTIOCTL_SCSI (GDTIOCTL_MASK | 9) /* SCSI command */ -#define GDTIOCTL_RESET_BUS (GDTIOCTL_MASK |10) /* reset SCSI bus */ -#define GDTIOCTL_RESCAN (GDTIOCTL_MASK |11) /* rescan host drives */ -#define GDTIOCTL_RESET_DRV (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */ - -#define GDTIOCTL_MAGIC 0xaffe0004 -#define EVENT_SIZE 294 -#define GDTH_MAXSG 32 /* max. s/g elements */ - -#define MAX_LDRIVES 255 /* max. log. drive count */ -#ifdef GDTH_IOCTL_PROC -#define MAX_HDRIVES 100 /* max. host drive count */ -#else -#define MAX_HDRIVES MAX_LDRIVES /* max. host drive count */ -#endif - -/* scatter/gather element */ -typedef struct { - u32 sg_ptr; /* address */ - u32 sg_len; /* length */ -} __attribute__((packed)) gdth_sg_str; - -/* scatter/gather element - 64bit addresses */ -typedef struct { - u64 sg_ptr; /* address */ - u32 sg_len; /* length */ -} __attribute__((packed)) gdth_sg64_str; - -/* command structure */ -typedef struct { - u32 BoardNode; /* board node (always 0) */ - u32 CommandIndex; /* command number */ - u16 OpCode; /* the command (READ,..) */ - union { - struct { - u16 DeviceNo; /* number of cache drive */ - u32 BlockNo; /* block number */ - u32 BlockCnt; /* block count */ - u32 DestAddr; /* dest. addr. (if s/g: -1) */ - u32 sg_canz; /* s/g element count */ - gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } __attribute__((packed)) cache; /* cache service cmd. str. */ - struct { - u16 DeviceNo; /* number of cache drive */ - u64 BlockNo; /* block number */ - u32 BlockCnt; /* block count */ - u64 DestAddr; /* dest. addr. (if s/g: -1) */ - u32 sg_canz; /* s/g element count */ - gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } __attribute__((packed)) cache64; /* cache service cmd. str. */ - struct { - u16 param_size; /* size of p_param buffer */ - u32 subfunc; /* IOCTL function */ - u32 channel; /* device */ - u64 p_param; /* buffer */ - } __attribute__((packed)) ioctl; /* IOCTL command structure */ - struct { - u16 reserved; - union { - struct { - u32 msg_handle; /* message handle */ - u64 msg_addr; /* message buffer address */ - } __attribute__((packed)) msg; - u8 data[12]; /* buffer for rtc data, ... */ - } su; - } __attribute__((packed)) screen; /* screen service cmd. str. */ - struct { - u16 reserved; - u32 direction; /* data direction */ - u32 mdisc_time; /* disc. time (0: no timeout)*/ - u32 mcon_time; /* connect time(0: no to.) */ - u32 sdata; /* dest. addr. (if s/g: -1) */ - u32 sdlen; /* data length (bytes) */ - u32 clen; /* SCSI cmd. length(6,10,12) */ - u8 cmd[12]; /* SCSI command */ - u8 target; /* target ID */ - u8 lun; /* LUN */ - u8 bus; /* SCSI bus number */ - u8 priority; /* only 0 used */ - u32 sense_len; /* sense data length */ - u32 sense_data; /* sense data addr. */ - u32 link_p; /* linked cmds (not supp.) */ - u32 sg_ranz; /* s/g element count */ - gdth_sg_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } __attribute__((packed)) raw; /* raw service cmd. struct. */ - struct { - u16 reserved; - u32 direction; /* data direction */ - u32 mdisc_time; /* disc. time (0: no timeout)*/ - u32 mcon_time; /* connect time(0: no to.) */ - u64 sdata; /* dest. addr. (if s/g: -1) */ - u32 sdlen; /* data length (bytes) */ - u32 clen; /* SCSI cmd. length(6,..,16) */ - u8 cmd[16]; /* SCSI command */ - u8 target; /* target ID */ - u8 lun; /* LUN */ - u8 bus; /* SCSI bus number */ - u8 priority; /* only 0 used */ - u32 sense_len; /* sense data length */ - u64 sense_data; /* sense data addr. */ - u32 sg_ranz; /* s/g element count */ - gdth_sg64_str sg_lst[GDTH_MAXSG]; /* s/g list */ - } __attribute__((packed)) raw64; /* raw service cmd. struct. */ - } u; - /* additional variables */ - u8 Service; /* controller service */ - u8 reserved; - u16 Status; /* command result */ - u32 Info; /* additional information */ - void *RequestBuffer; /* request buffer */ -} __attribute__((packed)) gdth_cmd_str; - -/* controller event structure */ -#define ES_ASYNC 1 -#define ES_DRIVER 2 -#define ES_TEST 3 -#define ES_SYNC 4 -typedef struct { - u16 size; /* size of structure */ - union { - char stream[16]; - struct { - u16 ionode; - u16 service; - u32 index; - } __attribute__((packed)) driver; - struct { - u16 ionode; - u16 service; - u16 status; - u32 info; - u8 scsi_coord[3]; - } __attribute__((packed)) async; - struct { - u16 ionode; - u16 service; - u16 status; - u32 info; - u16 hostdrive; - u8 scsi_coord[3]; - u8 sense_key; - } __attribute__((packed)) sync; - struct { - u32 l1, l2, l3, l4; - } __attribute__((packed)) test; - } eu; - u32 severity; - u8 event_string[256]; -} __attribute__((packed)) gdth_evt_data; - -typedef struct { - u32 first_stamp; - u32 last_stamp; - u16 same_count; - u16 event_source; - u16 event_idx; - u8 application; - u8 reserved; - gdth_evt_data event_data; -} __attribute__((packed)) gdth_evt_str; - - -#ifdef GDTH_IOCTL_PROC -/* IOCTL structure (write) */ -typedef struct { - u32 magic; /* IOCTL magic */ - u16 ioctl; /* IOCTL */ - u16 ionode; /* controller number */ - u16 service; /* controller service */ - u16 timeout; /* timeout */ - union { - struct { - u8 command[512]; /* controller command */ - u8 data[1]; /* add. data */ - } general; - struct { - u8 lock; /* lock/unlock */ - u8 drive_cnt; /* drive count */ - u16 drives[MAX_HDRIVES];/* drives */ - } lockdrv; - struct { - u8 lock; /* lock/unlock */ - u8 channel; /* channel */ - } lockchn; - struct { - int erase; /* erase event ? */ - int handle; - u8 evt[EVENT_SIZE]; /* event structure */ - } event; - struct { - u8 bus; /* SCSI bus */ - u8 target; /* target ID */ - u8 lun; /* LUN */ - u8 cmd_len; /* command length */ - u8 cmd[12]; /* SCSI command */ - } scsi; - struct { - u16 hdr_no; /* host drive number */ - u8 flag; /* old meth./add/remove */ - } rescan; - } iu; -} gdth_iowr_str; - -/* IOCTL structure (read) */ -typedef struct { - u32 size; /* buffer size */ - u32 status; /* IOCTL error code */ - union { - struct { - u8 data[1]; /* data */ - } general; - struct { - u16 version; /* driver version */ - } drvers; - struct { - u8 type; /* controller type */ - u16 info; /* slot etc. */ - u16 oem_id; /* OEM ID */ - u16 bios_ver; /* not used */ - u16 access; /* not used */ - u16 ext_type; /* extended type */ - u16 device_id; /* device ID */ - u16 sub_device_id; /* sub device ID */ - } ctrtype; - struct { - u8 version; /* OS version */ - u8 subversion; /* OS subversion */ - u16 revision; /* revision */ - } osvers; - struct { - u16 count; /* controller count */ - } ctrcnt; - struct { - int handle; - u8 evt[EVENT_SIZE]; /* event structure */ - } event; - struct { - u8 bus; /* SCSI bus, 0xff: invalid */ - u8 target; /* target ID */ - u8 lun; /* LUN */ - u8 cluster_type; /* cluster properties */ - } hdr_list[MAX_HDRIVES]; /* index is host drive number */ - } iu; -} gdth_iord_str; -#endif - -/* GDTIOCTL_GENERAL */ -typedef struct { - u16 ionode; /* controller number */ - u16 timeout; /* timeout */ - u32 info; /* error info */ - u16 status; /* status */ - unsigned long data_len; /* data buffer size */ - unsigned long sense_len; /* sense buffer size */ - gdth_cmd_str command; /* command */ -} gdth_ioctl_general; - -/* GDTIOCTL_LOCKDRV */ -typedef struct { - u16 ionode; /* controller number */ - u8 lock; /* lock/unlock */ - u8 drive_cnt; /* drive count */ - u16 drives[MAX_HDRIVES]; /* drives */ -} gdth_ioctl_lockdrv; - -/* GDTIOCTL_LOCKCHN */ -typedef struct { - u16 ionode; /* controller number */ - u8 lock; /* lock/unlock */ - u8 channel; /* channel */ -} gdth_ioctl_lockchn; - -/* GDTIOCTL_OSVERS */ -typedef struct { - u8 version; /* OS version */ - u8 subversion; /* OS subversion */ - u16 revision; /* revision */ -} gdth_ioctl_osvers; - -/* GDTIOCTL_CTRTYPE */ -typedef struct { - u16 ionode; /* controller number */ - u8 type; /* controller type */ - u16 info; /* slot etc. */ - u16 oem_id; /* OEM ID */ - u16 bios_ver; /* not used */ - u16 access; /* not used */ - u16 ext_type; /* extended type */ - u16 device_id; /* device ID */ - u16 sub_device_id; /* sub device ID */ -} gdth_ioctl_ctrtype; - -/* GDTIOCTL_EVENT */ -typedef struct { - u16 ionode; - int erase; /* erase event? */ - int handle; /* event handle */ - gdth_evt_str event; -} gdth_ioctl_event; - -/* GDTIOCTL_RESCAN/GDTIOCTL_HDRLIST */ -typedef struct { - u16 ionode; /* controller number */ - u8 flag; /* add/remove */ - u16 hdr_no; /* drive no. */ - struct { - u8 bus; /* SCSI bus */ - u8 target; /* target ID */ - u8 lun; /* LUN */ - u8 cluster_type; /* cluster properties */ - } hdr_list[MAX_HDRIVES]; /* index is host drive number */ -} gdth_ioctl_rescan; - -/* GDTIOCTL_RESET_BUS/GDTIOCTL_RESET_DRV */ -typedef struct { - u16 ionode; /* controller number */ - u16 number; /* bus/host drive number */ - u16 status; /* status */ -} gdth_ioctl_reset; - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/gdth_proc.c b/ANDROID_3.4.5/drivers/scsi/gdth_proc.c deleted file mode 100644 index 65275431..00000000 --- a/ANDROID_3.4.5/drivers/scsi/gdth_proc.c +++ /dev/null @@ -1,760 +0,0 @@ -/* gdth_proc.c - * $Id: gdth_proc.c,v 1.43 2006/01/11 16:15:00 achim Exp $ - */ - -#include -#include - -int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length, - int inout) -{ - gdth_ha_str *ha = shost_priv(host); - - TRACE2(("gdth_proc_info() length %d offs %d inout %d\n", - length,(int)offset,inout)); - - if (inout) - return(gdth_set_info(buffer,length,host,ha)); - else - return(gdth_get_info(buffer,start,offset,length,host,ha)); -} - -static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host, - gdth_ha_str *ha) -{ - int ret_val = -EINVAL; - - TRACE2(("gdth_set_info() ha %d\n",ha->hanum,)); - - if (length >= 4) { - if (strncmp(buffer,"gdth",4) == 0) { - buffer += 5; - length -= 5; - ret_val = gdth_set_asc_info(host, buffer, length, ha); - } - } - - return ret_val; -} - -static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, - int length, gdth_ha_str *ha) -{ - int orig_length, drive, wb_mode; - int i, found; - gdth_cmd_str gdtcmd; - gdth_cpar_str *pcpar; - u64 paddr; - - char cmnd[MAX_COMMAND_SIZE]; - memset(cmnd, 0xff, 12); - memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); - - TRACE2(("gdth_set_asc_info() ha %d\n",ha->hanum)); - orig_length = length + 5; - drive = -1; - wb_mode = 0; - found = FALSE; - - if (length >= 5 && strncmp(buffer,"flush",5)==0) { - buffer += 6; - length -= 6; - if (length && *buffer>='0' && *buffer<='9') { - drive = (int)(*buffer-'0'); - ++buffer; --length; - if (length && *buffer>='0' && *buffer<='9') { - drive = drive*10 + (int)(*buffer-'0'); - ++buffer; --length; - } - printk("GDT: Flushing host drive %d .. ",drive); - } else { - printk("GDT: Flushing all host drives .. "); - } - for (i = 0; i < MAX_HDRIVES; ++i) { - if (ha->hdr[i].present) { - if (drive != -1 && i != drive) - continue; - found = TRUE; - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_FLUSH; - if (ha->cache_feat & GDT_64BIT) { - gdtcmd.u.cache64.DeviceNo = i; - gdtcmd.u.cache64.BlockNo = 1; - } else { - gdtcmd.u.cache.DeviceNo = i; - gdtcmd.u.cache.BlockNo = 1; - } - - gdth_execute(host, &gdtcmd, cmnd, 30, NULL); - } - } - if (!found) - printk("\nNo host drive found !\n"); - else - printk("Done.\n"); - return(orig_length); - } - - if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) { - buffer += 8; - length -= 8; - printk("GDT: Disabling write back permanently .. "); - wb_mode = 1; - } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) { - buffer += 7; - length -= 7; - printk("GDT: Enabling write back permanently .. "); - wb_mode = 2; - } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) { - buffer += 7; - length -= 7; - printk("GDT: Disabling write back commands .. "); - if (ha->cache_feat & GDT_WR_THROUGH) { - gdth_write_through = TRUE; - printk("Done.\n"); - } else { - printk("Not supported !\n"); - } - return(orig_length); - } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) { - buffer += 6; - length -= 6; - printk("GDT: Enabling write back commands .. "); - gdth_write_through = FALSE; - printk("Done.\n"); - return(orig_length); - } - - if (wb_mode) { - if (!gdth_ioctl_alloc(ha, sizeof(gdth_cpar_str), TRUE, &paddr)) - return(-EBUSY); - pcpar = (gdth_cpar_str *)ha->pscratch; - memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) ); - gdtcmd.Service = CACHESERVICE; - gdtcmd.OpCode = GDT_IOCTL; - gdtcmd.u.ioctl.p_param = paddr; - gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str); - gdtcmd.u.ioctl.subfunc = CACHE_CONFIG; - gdtcmd.u.ioctl.channel = INVALID_CHANNEL; - pcpar->write_back = wb_mode==1 ? 0:1; - - gdth_execute(host, &gdtcmd, cmnd, 30, NULL); - - gdth_ioctl_free(ha, GDTH_SCRATCH, ha->pscratch, paddr); - printk("Done.\n"); - return(orig_length); - } - - printk("GDT: Unknown command: %s Length: %d\n",buffer,length); - return(-EINVAL); -} - -static int gdth_get_info(char *buffer,char **start,off_t offset,int length, - struct Scsi_Host *host, gdth_ha_str *ha) -{ - int size = 0,len = 0; - int hlen; - off_t begin = 0,pos = 0; - int id, i, j, k, sec, flag; - int no_mdrv = 0, drv_no, is_mirr; - u32 cnt; - u64 paddr; - int rc = -ENOMEM; - - gdth_cmd_str *gdtcmd; - gdth_evt_str *estr; - char hrec[161]; - struct timeval tv; - - char *buf; - gdth_dskstat_str *pds; - gdth_diskinfo_str *pdi; - gdth_arrayinf_str *pai; - gdth_defcnt_str *pdef; - gdth_cdrinfo_str *pcdi; - gdth_hget_str *phg; - char cmnd[MAX_COMMAND_SIZE]; - - gdtcmd = kmalloc(sizeof(*gdtcmd), GFP_KERNEL); - estr = kmalloc(sizeof(*estr), GFP_KERNEL); - if (!gdtcmd || !estr) - goto free_fail; - - memset(cmnd, 0xff, 12); - memset(gdtcmd, 0, sizeof(gdth_cmd_str)); - - TRACE2(("gdth_get_info() ha %d\n",ha->hanum)); - - - /* request is i.e. "cat /proc/scsi/gdth/0" */ - /* format: %-15s\t%-10s\t%-15s\t%s */ - /* driver parameters */ - size = sprintf(buffer+len,"Driver Parameters:\n"); - len += size; pos = begin + len; - if (reserve_list[0] == 0xff) - strcpy(hrec, "--"); - else { - hlen = sprintf(hrec, "%d", reserve_list[0]); - for (i = 1; i < MAX_RES_ARGS; i++) { - if (reserve_list[i] == 0xff) - break; - hlen += snprintf(hrec + hlen , 161 - hlen, ",%d", reserve_list[i]); - } - } - size = sprintf(buffer+len, - " reserve_mode: \t%d \treserve_list: \t%s\n", - reserve_mode, hrec); - len += size; pos = begin + len; - size = sprintf(buffer+len, - " max_ids: \t%-3d \thdr_channel: \t%d\n", - max_ids, hdr_channel); - len += size; pos = begin + len; - - /* controller information */ - size = sprintf(buffer+len,"\nDisk Array Controller Information:\n"); - len += size; pos = begin + len; - strcpy(hrec, ha->binfo.type_string); - size = sprintf(buffer+len, - " Number: \t%d \tName: \t%s\n", - ha->hanum, hrec); - len += size; pos = begin + len; - - if (ha->more_proc) - sprintf(hrec, "%d.%02d.%02d-%c%03X", - (u8)(ha->binfo.upd_fw_ver>>24), - (u8)(ha->binfo.upd_fw_ver>>16), - (u8)(ha->binfo.upd_fw_ver), - ha->bfeat.raid ? 'R':'N', - ha->binfo.upd_revision); - else - sprintf(hrec, "%d.%02d", (u8)(ha->cpar.version>>8), - (u8)(ha->cpar.version)); - - size = sprintf(buffer+len, - " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n", - GDTH_VERSION_STR, hrec); - len += size; pos = begin + len; - - if (ha->more_proc) { - /* more information: 1. about controller */ - size = sprintf(buffer+len, - " Serial No.: \t0x%8X\tCache RAM size:\t%d KB\n", - ha->binfo.ser_no, ha->binfo.memsize / 1024); - len += size; pos = begin + len; - } - -#ifdef GDTH_DMA_STATISTICS - /* controller statistics */ - size = sprintf(buffer+len,"\nController Statistics:\n"); - len += size; pos = begin + len; - size = sprintf(buffer+len, - " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n", - ha->dma32_cnt, ha->dma64_cnt); - len += size; pos = begin + len; -#endif - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - - if (ha->more_proc) { - /* more information: 2. about physical devices */ - size = sprintf(buffer+len,"\nPhysical Devices:"); - len += size; pos = begin + len; - flag = FALSE; - - buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); - if (!buf) - goto stop_output; - for (i = 0; i < ha->bus_cnt; ++i) { - /* 2.a statistics (and retries/reassigns) */ - TRACE2(("pdr_statistics() chn %d\n",i)); - pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4); - gdtcmd->Service = CACHESERVICE; - gdtcmd->OpCode = GDT_IOCTL; - gdtcmd->u.ioctl.p_param = paddr + GDTH_SCRATCH/4; - gdtcmd->u.ioctl.param_size = 3*GDTH_SCRATCH/4; - gdtcmd->u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN; - gdtcmd->u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL; - pds->bid = ha->raw[i].local_no; - pds->first = 0; - pds->entries = ha->raw[i].pdev_cnt; - cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(u32)) / - sizeof(pds->list[0]); - if (pds->entries > cnt) - pds->entries = cnt; - - if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) != S_OK) - pds->count = 0; - - /* other IOCTLs must fit into area GDTH_SCRATCH/4 */ - for (j = 0; j < ha->raw[i].pdev_cnt; ++j) { - /* 2.b drive info */ - TRACE2(("scsi_drv_info() chn %d dev %d\n", - i, ha->raw[i].id_list[j])); - pdi = (gdth_diskinfo_str *)buf; - gdtcmd->Service = CACHESERVICE; - gdtcmd->OpCode = GDT_IOCTL; - gdtcmd->u.ioctl.p_param = paddr; - gdtcmd->u.ioctl.param_size = sizeof(gdth_diskinfo_str); - gdtcmd->u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN; - gdtcmd->u.ioctl.channel = - ha->raw[i].address | ha->raw[i].id_list[j]; - - if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) { - strncpy(hrec,pdi->vendor,8); - strncpy(hrec+8,pdi->product,16); - strncpy(hrec+24,pdi->revision,4); - hrec[28] = 0; - size = sprintf(buffer+len, - "\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n", - 'A'+i,pdi->target_id,pdi->lun,hrec); - len += size; pos = begin + len; - flag = TRUE; - pdi->no_ldrive &= 0xffff; - if (pdi->no_ldrive == 0xffff) - strcpy(hrec,"--"); - else - sprintf(hrec,"%d",pdi->no_ldrive); - size = sprintf(buffer+len, - " Capacity [MB]:\t%-6d \tTo Log. Drive: \t%s\n", - pdi->blkcnt/(1024*1024/pdi->blksize), - hrec); - len += size; pos = begin + len; - } else { - pdi->devtype = 0xff; - } - - if (pdi->devtype == 0) { - /* search retries/reassigns */ - for (k = 0; k < pds->count; ++k) { - if (pds->list[k].tid == pdi->target_id && - pds->list[k].lun == pdi->lun) { - size = sprintf(buffer+len, - " Retries: \t%-6d \tReassigns: \t%d\n", - pds->list[k].retries, - pds->list[k].reassigns); - len += size; pos = begin + len; - break; - } - } - /* 2.c grown defects */ - TRACE2(("scsi_drv_defcnt() chn %d dev %d\n", - i, ha->raw[i].id_list[j])); - pdef = (gdth_defcnt_str *)buf; - gdtcmd->Service = CACHESERVICE; - gdtcmd->OpCode = GDT_IOCTL; - gdtcmd->u.ioctl.p_param = paddr; - gdtcmd->u.ioctl.param_size = sizeof(gdth_defcnt_str); - gdtcmd->u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN; - gdtcmd->u.ioctl.channel = - ha->raw[i].address | ha->raw[i].id_list[j]; - pdef->sddc_type = 0x08; - - if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) { - size = sprintf(buffer+len, - " Grown Defects:\t%d\n", - pdef->sddc_cnt); - len += size; pos = begin + len; - } - } - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) { - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); - goto stop_output; - } - } - } - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); - - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - - /* 3. about logical drives */ - size = sprintf(buffer+len,"\nLogical Drives:"); - len += size; pos = begin + len; - flag = FALSE; - - buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); - if (!buf) - goto stop_output; - for (i = 0; i < MAX_LDRIVES; ++i) { - if (!ha->hdr[i].is_logdrv) - continue; - drv_no = i; - j = k = 0; - is_mirr = FALSE; - do { - /* 3.a log. drive info */ - TRACE2(("cache_drv_info() drive no %d\n",drv_no)); - pcdi = (gdth_cdrinfo_str *)buf; - gdtcmd->Service = CACHESERVICE; - gdtcmd->OpCode = GDT_IOCTL; - gdtcmd->u.ioctl.p_param = paddr; - gdtcmd->u.ioctl.param_size = sizeof(gdth_cdrinfo_str); - gdtcmd->u.ioctl.subfunc = CACHE_DRV_INFO; - gdtcmd->u.ioctl.channel = drv_no; - if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) != S_OK) - break; - pcdi->ld_dtype >>= 16; - j++; - if (pcdi->ld_dtype > 2) { - strcpy(hrec, "missing"); - } else if (pcdi->ld_error & 1) { - strcpy(hrec, "fault"); - } else if (pcdi->ld_error & 2) { - strcpy(hrec, "invalid"); - k++; j--; - } else { - strcpy(hrec, "ok"); - } - - if (drv_no == i) { - size = sprintf(buffer+len, - "\n Number: \t%-2d \tStatus: \t%s\n", - drv_no, hrec); - len += size; pos = begin + len; - flag = TRUE; - no_mdrv = pcdi->cd_ldcnt; - if (no_mdrv > 1 || pcdi->ld_slave != -1) { - is_mirr = TRUE; - strcpy(hrec, "RAID-1"); - } else if (pcdi->ld_dtype == 0) { - strcpy(hrec, "Disk"); - } else if (pcdi->ld_dtype == 1) { - strcpy(hrec, "RAID-0"); - } else if (pcdi->ld_dtype == 2) { - strcpy(hrec, "Chain"); - } else { - strcpy(hrec, "???"); - } - size = sprintf(buffer+len, - " Capacity [MB]:\t%-6d \tType: \t%s\n", - pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize), - hrec); - len += size; pos = begin + len; - } else { - size = sprintf(buffer+len, - " Slave Number: \t%-2d \tStatus: \t%s\n", - drv_no & 0x7fff, hrec); - len += size; pos = begin + len; - } - drv_no = pcdi->ld_slave; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) { - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); - goto stop_output; - } - } while (drv_no != -1); - - if (is_mirr) { - size = sprintf(buffer+len, - " Missing Drv.: \t%-2d \tInvalid Drv.: \t%d\n", - no_mdrv - j - k, k); - len += size; pos = begin + len; - } - - if (!ha->hdr[i].is_arraydrv) - strcpy(hrec, "--"); - else - sprintf(hrec, "%d", ha->hdr[i].master_no); - size = sprintf(buffer+len, - " To Array Drv.:\t%s\n", hrec); - len += size; pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) { - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); - goto stop_output; - } - } - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); - - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - - /* 4. about array drives */ - size = sprintf(buffer+len,"\nArray Drives:"); - len += size; pos = begin + len; - flag = FALSE; - - buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr); - if (!buf) - goto stop_output; - for (i = 0; i < MAX_LDRIVES; ++i) { - if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master)) - continue; - /* 4.a array drive info */ - TRACE2(("array_info() drive no %d\n",i)); - pai = (gdth_arrayinf_str *)buf; - gdtcmd->Service = CACHESERVICE; - gdtcmd->OpCode = GDT_IOCTL; - gdtcmd->u.ioctl.p_param = paddr; - gdtcmd->u.ioctl.param_size = sizeof(gdth_arrayinf_str); - gdtcmd->u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN; - gdtcmd->u.ioctl.channel = i; - if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) { - if (pai->ai_state == 0) - strcpy(hrec, "idle"); - else if (pai->ai_state == 2) - strcpy(hrec, "build"); - else if (pai->ai_state == 4) - strcpy(hrec, "ready"); - else if (pai->ai_state == 6) - strcpy(hrec, "fail"); - else if (pai->ai_state == 8 || pai->ai_state == 10) - strcpy(hrec, "rebuild"); - else - strcpy(hrec, "error"); - if (pai->ai_ext_state & 0x10) - strcat(hrec, "/expand"); - else if (pai->ai_ext_state & 0x1) - strcat(hrec, "/patch"); - size = sprintf(buffer+len, - "\n Number: \t%-2d \tStatus: \t%s\n", - i,hrec); - len += size; pos = begin + len; - flag = TRUE; - - if (pai->ai_type == 0) - strcpy(hrec, "RAID-0"); - else if (pai->ai_type == 4) - strcpy(hrec, "RAID-4"); - else if (pai->ai_type == 5) - strcpy(hrec, "RAID-5"); - else - strcpy(hrec, "RAID-10"); - size = sprintf(buffer+len, - " Capacity [MB]:\t%-6d \tType: \t%s\n", - pai->ai_size/(1024*1024/pai->ai_secsize), - hrec); - len += size; pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) { - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); - goto stop_output; - } - } - } - gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr); - - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - - /* 5. about host drives */ - size = sprintf(buffer+len,"\nHost Drives:"); - len += size; pos = begin + len; - flag = FALSE; - - buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr); - if (!buf) - goto stop_output; - for (i = 0; i < MAX_LDRIVES; ++i) { - if (!ha->hdr[i].is_logdrv || - (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master)) - continue; - /* 5.a get host drive list */ - TRACE2(("host_get() drv_no %d\n",i)); - phg = (gdth_hget_str *)buf; - gdtcmd->Service = CACHESERVICE; - gdtcmd->OpCode = GDT_IOCTL; - gdtcmd->u.ioctl.p_param = paddr; - gdtcmd->u.ioctl.param_size = sizeof(gdth_hget_str); - gdtcmd->u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN; - gdtcmd->u.ioctl.channel = i; - phg->entries = MAX_HDRIVES; - phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); - if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) { - ha->hdr[i].ldr_no = i; - ha->hdr[i].rw_attribs = 0; - ha->hdr[i].start_sec = 0; - } else { - for (j = 0; j < phg->entries; ++j) { - k = phg->entry[j].host_drive; - if (k >= MAX_LDRIVES) - continue; - ha->hdr[k].ldr_no = phg->entry[j].log_drive; - ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs; - ha->hdr[k].start_sec = phg->entry[j].start_sec; - } - } - } - gdth_ioctl_free(ha, sizeof(gdth_hget_str), buf, paddr); - - for (i = 0; i < MAX_HDRIVES; ++i) { - if (!(ha->hdr[i].present)) - continue; - - size = sprintf(buffer+len, - "\n Number: \t%-2d \tArr/Log. Drive:\t%d\n", - i, ha->hdr[i].ldr_no); - len += size; pos = begin + len; - flag = TRUE; - - size = sprintf(buffer+len, - " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", - (u32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec); - len += size; pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } - - if (!flag) { - size = sprintf(buffer+len, "\n --\n"); - len += size; pos = begin + len; - } - } - - /* controller events */ - size = sprintf(buffer+len,"\nController Events:\n"); - len += size; pos = begin + len; - - for (id = -1;;) { - id = gdth_read_event(ha, id, estr); - if (estr->event_source == 0) - break; - if (estr->event_data.eu.driver.ionode == ha->hanum && - estr->event_source == ES_ASYNC) { - gdth_log_event(&estr->event_data, hrec); - do_gettimeofday(&tv); - sec = (int)(tv.tv_sec - estr->first_stamp); - if (sec < 0) sec = 0; - size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n", - sec/3600, sec%3600/60, sec%60, hrec); - len += size; pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } - if (id == -1) - break; - } - -stop_output: - *start = buffer +(offset-begin); - len -= (offset-begin); - if (len > length) - len = length; - TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n", - len,(int)pos,(int)begin,(int)offset,length,size)); - rc = len; - -free_fail: - kfree(gdtcmd); - kfree(estr); - return rc; -} - -static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, - u64 *paddr) -{ - unsigned long flags; - char *ret_val; - - if (size == 0) - return NULL; - - spin_lock_irqsave(&ha->smp_lock, flags); - - if (!ha->scratch_busy && size <= GDTH_SCRATCH) { - ha->scratch_busy = TRUE; - ret_val = ha->pscratch; - *paddr = ha->scratch_phys; - } else if (scratch) { - ret_val = NULL; - } else { - dma_addr_t dma_addr; - - ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr); - *paddr = dma_addr; - } - - spin_unlock_irqrestore(&ha->smp_lock, flags); - return ret_val; -} - -static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr) -{ - unsigned long flags; - - if (buf == ha->pscratch) { - spin_lock_irqsave(&ha->smp_lock, flags); - ha->scratch_busy = FALSE; - spin_unlock_irqrestore(&ha->smp_lock, flags); - } else { - pci_free_consistent(ha->pdev, size, buf, paddr); - } -} - -#ifdef GDTH_IOCTL_PROC -static int gdth_ioctl_check_bin(gdth_ha_str *ha, u16 size) -{ - unsigned long flags; - int ret_val; - - spin_lock_irqsave(&ha->smp_lock, flags); - - ret_val = FALSE; - if (ha->scratch_busy) { - if (((gdth_iord_str *)ha->pscratch)->size == (u32)size) - ret_val = TRUE; - } - spin_unlock_irqrestore(&ha->smp_lock, flags); - return ret_val; -} -#endif - -static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id) -{ - unsigned long flags; - int i; - Scsi_Cmnd *scp; - struct gdth_cmndinfo *cmndinfo; - u8 b, t; - - spin_lock_irqsave(&ha->smp_lock, flags); - - for (i = 0; i < GDTH_MAXCMDS; ++i) { - scp = ha->cmd_tab[i].cmnd; - cmndinfo = gdth_cmnd_priv(scp); - - b = scp->device->channel; - t = scp->device->id; - if (!SPECIAL_SCP(scp) && t == (u8)id && - b == (u8)busnum) { - cmndinfo->wait_for_completion = 0; - spin_unlock_irqrestore(&ha->smp_lock, flags); - while (!cmndinfo->wait_for_completion) - barrier(); - spin_lock_irqsave(&ha->smp_lock, flags); - } - } - spin_unlock_irqrestore(&ha->smp_lock, flags); -} diff --git a/ANDROID_3.4.5/drivers/scsi/gdth_proc.h b/ANDROID_3.4.5/drivers/scsi/gdth_proc.h deleted file mode 100644 index dab15f59..00000000 --- a/ANDROID_3.4.5/drivers/scsi/gdth_proc.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _GDTH_PROC_H -#define _GDTH_PROC_H - -/* gdth_proc.h - * $Id: gdth_proc.h,v 1.16 2004/01/14 13:09:01 achim Exp $ - */ - -int gdth_execute(struct Scsi_Host *shost, gdth_cmd_str *gdtcmd, char *cmnd, - int timeout, u32 *info); - -static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host, - gdth_ha_str *ha); -static int gdth_get_info(char *buffer,char **start,off_t offset,int length, - struct Scsi_Host *host, gdth_ha_str *ha); - -static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer, - int length, gdth_ha_str *ha); - -static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, - u64 *paddr); -static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr); -static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id); - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/gvp11.c b/ANDROID_3.4.5/drivers/scsi/gvp11.c deleted file mode 100644 index 488fbc64..00000000 --- a/ANDROID_3.4.5/drivers/scsi/gvp11.c +++ /dev/null @@ -1,433 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "scsi.h" -#include "wd33c93.h" -#include "gvp11.h" - - -#define CHECK_WD33C93 - -struct gvp11_hostdata { - struct WD33C93_hostdata wh; - struct gvp11_scsiregs *regs; -}; - -static irqreturn_t gvp11_intr(int irq, void *data) -{ - struct Scsi_Host *instance = data; - struct gvp11_hostdata *hdata = shost_priv(instance); - unsigned int status = hdata->regs->CNTR; - unsigned long flags; - - if (!(status & GVP11_DMAC_INT_PENDING)) - return IRQ_NONE; - - spin_lock_irqsave(instance->host_lock, flags); - wd33c93_intr(instance); - spin_unlock_irqrestore(instance->host_lock, flags); - return IRQ_HANDLED; -} - -static int gvp11_xfer_mask = 0; - -void gvp11_setup(char *str, int *ints) -{ - gvp11_xfer_mask = ints[1]; -} - -static int dma_setup(struct scsi_cmnd *cmd, int dir_in) -{ - struct Scsi_Host *instance = cmd->device->host; - struct gvp11_hostdata *hdata = shost_priv(instance); - struct WD33C93_hostdata *wh = &hdata->wh; - struct gvp11_scsiregs *regs = hdata->regs; - unsigned short cntr = GVP11_DMAC_INT_ENABLE; - unsigned long addr = virt_to_bus(cmd->SCp.ptr); - int bank_mask; - static int scsi_alloc_out_of_range = 0; - - /* use bounce buffer if the physical address is bad */ - if (addr & wh->dma_xfer_mask) { - wh->dma_bounce_len = (cmd->SCp.this_residual + 511) & ~0x1ff; - - if (!scsi_alloc_out_of_range) { - wh->dma_bounce_buffer = - kmalloc(wh->dma_bounce_len, GFP_KERNEL); - wh->dma_buffer_pool = BUF_SCSI_ALLOCED; - } - - if (scsi_alloc_out_of_range || - !wh->dma_bounce_buffer) { - wh->dma_bounce_buffer = - amiga_chip_alloc(wh->dma_bounce_len, - "GVP II SCSI Bounce Buffer"); - - if (!wh->dma_bounce_buffer) { - wh->dma_bounce_len = 0; - return 1; - } - - wh->dma_buffer_pool = BUF_CHIP_ALLOCED; - } - - /* check if the address of the bounce buffer is OK */ - addr = virt_to_bus(wh->dma_bounce_buffer); - - if (addr & wh->dma_xfer_mask) { - /* fall back to Chip RAM if address out of range */ - if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) { - kfree(wh->dma_bounce_buffer); - scsi_alloc_out_of_range = 1; - } else { - amiga_chip_free(wh->dma_bounce_buffer); - } - - wh->dma_bounce_buffer = - amiga_chip_alloc(wh->dma_bounce_len, - "GVP II SCSI Bounce Buffer"); - - if (!wh->dma_bounce_buffer) { - wh->dma_bounce_len = 0; - return 1; - } - - addr = virt_to_bus(wh->dma_bounce_buffer); - wh->dma_buffer_pool = BUF_CHIP_ALLOCED; - } - - if (!dir_in) { - /* copy to bounce buffer for a write */ - memcpy(wh->dma_bounce_buffer, cmd->SCp.ptr, - cmd->SCp.this_residual); - } - } - - /* setup dma direction */ - if (!dir_in) - cntr |= GVP11_DMAC_DIR_WRITE; - - wh->dma_dir = dir_in; - regs->CNTR = cntr; - - /* setup DMA *physical* address */ - regs->ACR = addr; - - if (dir_in) { - /* invalidate any cache */ - cache_clear(addr, cmd->SCp.this_residual); - } else { - /* push any dirty cache */ - cache_push(addr, cmd->SCp.this_residual); - } - - bank_mask = (~wh->dma_xfer_mask >> 18) & 0x01c0; - if (bank_mask) - regs->BANK = bank_mask & (addr >> 18); - - /* start DMA */ - regs->ST_DMA = 1; - - /* return success */ - return 0; -} - -static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, - int status) -{ - struct gvp11_hostdata *hdata = shost_priv(instance); - struct WD33C93_hostdata *wh = &hdata->wh; - struct gvp11_scsiregs *regs = hdata->regs; - - /* stop DMA */ - regs->SP_DMA = 1; - /* remove write bit from CONTROL bits */ - regs->CNTR = GVP11_DMAC_INT_ENABLE; - - /* copy from a bounce buffer, if necessary */ - if (status && wh->dma_bounce_buffer) { - if (wh->dma_dir && SCpnt) - memcpy(SCpnt->SCp.ptr, wh->dma_bounce_buffer, - SCpnt->SCp.this_residual); - - if (wh->dma_buffer_pool == BUF_SCSI_ALLOCED) - kfree(wh->dma_bounce_buffer); - else - amiga_chip_free(wh->dma_bounce_buffer); - - wh->dma_bounce_buffer = NULL; - wh->dma_bounce_len = 0; - } -} - -static int gvp11_bus_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *instance = cmd->device->host; - - /* FIXME perform bus-specific reset */ - - /* FIXME 2: shouldn't we no-op this function (return - FAILED), and fall back to host reset function, - wd33c93_host_reset ? */ - - spin_lock_irq(instance->host_lock); - wd33c93_host_reset(cmd); - spin_unlock_irq(instance->host_lock); - - return SUCCESS; -} - -static struct scsi_host_template gvp11_scsi_template = { - .module = THIS_MODULE, - .name = "GVP Series II SCSI", - .proc_info = wd33c93_proc_info, - .proc_name = "GVP11", - .queuecommand = wd33c93_queuecommand, - .eh_abort_handler = wd33c93_abort, - .eh_bus_reset_handler = gvp11_bus_reset, - .eh_host_reset_handler = wd33c93_host_reset, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING -}; - -static int __devinit check_wd33c93(struct gvp11_scsiregs *regs) -{ -#ifdef CHECK_WD33C93 - volatile unsigned char *sasr_3393, *scmd_3393; - unsigned char save_sasr; - unsigned char q, qq; - - /* - * These darn GVP boards are a problem - it can be tough to tell - * whether or not they include a SCSI controller. This is the - * ultimate Yet-Another-GVP-Detection-Hack in that it actually - * probes for a WD33c93 chip: If we find one, it's extremely - * likely that this card supports SCSI, regardless of Product_ - * Code, Board_Size, etc. - */ - - /* Get pointers to the presumed register locations and save contents */ - - sasr_3393 = ®s->SASR; - scmd_3393 = ®s->SCMD; - save_sasr = *sasr_3393; - - /* First test the AuxStatus Reg */ - - q = *sasr_3393; /* read it */ - if (q & 0x08) /* bit 3 should always be clear */ - return -ENODEV; - *sasr_3393 = WD_AUXILIARY_STATUS; /* setup indirect address */ - if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */ - *sasr_3393 = save_sasr; /* Oops - restore this byte */ - return -ENODEV; - } - if (*sasr_3393 != q) { /* should still read the same */ - *sasr_3393 = save_sasr; /* Oops - restore this byte */ - return -ENODEV; - } - if (*scmd_3393 != q) /* and so should the image at 0x1f */ - return -ENODEV; - - /* - * Ok, we probably have a wd33c93, but let's check a few other places - * for good measure. Make sure that this works for both 'A and 'B - * chip versions. - */ - - *sasr_3393 = WD_SCSI_STATUS; - q = *scmd_3393; - *sasr_3393 = WD_SCSI_STATUS; - *scmd_3393 = ~q; - *sasr_3393 = WD_SCSI_STATUS; - qq = *scmd_3393; - *sasr_3393 = WD_SCSI_STATUS; - *scmd_3393 = q; - if (qq != q) /* should be read only */ - return -ENODEV; - *sasr_3393 = 0x1e; /* this register is unimplemented */ - q = *scmd_3393; - *sasr_3393 = 0x1e; - *scmd_3393 = ~q; - *sasr_3393 = 0x1e; - qq = *scmd_3393; - *sasr_3393 = 0x1e; - *scmd_3393 = q; - if (qq != q || qq != 0xff) /* should be read only, all 1's */ - return -ENODEV; - *sasr_3393 = WD_TIMEOUT_PERIOD; - q = *scmd_3393; - *sasr_3393 = WD_TIMEOUT_PERIOD; - *scmd_3393 = ~q; - *sasr_3393 = WD_TIMEOUT_PERIOD; - qq = *scmd_3393; - *sasr_3393 = WD_TIMEOUT_PERIOD; - *scmd_3393 = q; - if (qq != (~q & 0xff)) /* should be read/write */ - return -ENODEV; -#endif /* CHECK_WD33C93 */ - - return 0; -} - -static int __devinit gvp11_probe(struct zorro_dev *z, - const struct zorro_device_id *ent) -{ - struct Scsi_Host *instance; - unsigned long address; - int error; - unsigned int epc; - unsigned int default_dma_xfer_mask; - struct gvp11_hostdata *hdata; - struct gvp11_scsiregs *regs; - wd33c93_regs wdregs; - - default_dma_xfer_mask = ent->driver_data; - - /* - * Rumors state that some GVP ram boards use the same product - * code as the SCSI controllers. Therefore if the board-size - * is not 64KB we assume it is a ram board and bail out. - */ - if (zorro_resource_len(z) != 0x10000) - return -ENODEV; - - address = z->resource.start; - if (!request_mem_region(address, 256, "wd33c93")) - return -EBUSY; - - regs = (struct gvp11_scsiregs *)(ZTWO_VADDR(address)); - - error = check_wd33c93(regs); - if (error) - goto fail_check_or_alloc; - - instance = scsi_host_alloc(&gvp11_scsi_template, - sizeof(struct gvp11_hostdata)); - if (!instance) { - error = -ENOMEM; - goto fail_check_or_alloc; - } - - instance->irq = IRQ_AMIGA_PORTS; - instance->unique_id = z->slotaddr; - - regs->secret2 = 1; - regs->secret1 = 0; - regs->secret3 = 15; - while (regs->CNTR & GVP11_DMAC_BUSY) - ; - regs->CNTR = 0; - regs->BANK = 0; - - wdregs.SASR = ®s->SASR; - wdregs.SCMD = ®s->SCMD; - - hdata = shost_priv(instance); - if (gvp11_xfer_mask) - hdata->wh.dma_xfer_mask = gvp11_xfer_mask; - else - hdata->wh.dma_xfer_mask = default_dma_xfer_mask; - - hdata->wh.no_sync = 0xff; - hdata->wh.fast = 0; - hdata->wh.dma_mode = CTRL_DMA; - hdata->regs = regs; - - /* - * Check for 14MHz SCSI clock - */ - epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000); - wd33c93_init(instance, wdregs, dma_setup, dma_stop, - (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10 - : WD33C93_FS_12_15); - - error = request_irq(IRQ_AMIGA_PORTS, gvp11_intr, IRQF_SHARED, - "GVP11 SCSI", instance); - if (error) - goto fail_irq; - - regs->CNTR = GVP11_DMAC_INT_ENABLE; - - error = scsi_add_host(instance, NULL); - if (error) - goto fail_host; - - zorro_set_drvdata(z, instance); - scsi_scan_host(instance); - return 0; - -fail_host: - free_irq(IRQ_AMIGA_PORTS, instance); -fail_irq: - scsi_host_put(instance); -fail_check_or_alloc: - release_mem_region(address, 256); - return error; -} - -static void __devexit gvp11_remove(struct zorro_dev *z) -{ - struct Scsi_Host *instance = zorro_get_drvdata(z); - struct gvp11_hostdata *hdata = shost_priv(instance); - - hdata->regs->CNTR = 0; - scsi_remove_host(instance); - free_irq(IRQ_AMIGA_PORTS, instance); - scsi_host_put(instance); - release_mem_region(z->resource.start, 256); -} - - /* - * This should (hopefully) be the correct way to identify - * all the different GVP SCSI controllers (except for the - * SERIES I though). - */ - -static struct zorro_device_id gvp11_zorro_tbl[] __devinitdata = { - { ZORRO_PROD_GVP_COMBO_030_R3_SCSI, ~0x00ffffff }, - { ZORRO_PROD_GVP_SERIES_II, ~0x00ffffff }, - { ZORRO_PROD_GVP_GFORCE_030_SCSI, ~0x01ffffff }, - { ZORRO_PROD_GVP_A530_SCSI, ~0x01ffffff }, - { ZORRO_PROD_GVP_COMBO_030_R4_SCSI, ~0x01ffffff }, - { ZORRO_PROD_GVP_A1291, ~0x07ffffff }, - { ZORRO_PROD_GVP_GFORCE_040_SCSI_1, ~0x07ffffff }, - { 0 } -}; -MODULE_DEVICE_TABLE(zorro, gvp11_zorro_tbl); - -static struct zorro_driver gvp11_driver = { - .name = "gvp11", - .id_table = gvp11_zorro_tbl, - .probe = gvp11_probe, - .remove = __devexit_p(gvp11_remove), -}; - -static int __init gvp11_init(void) -{ - return zorro_register_driver(&gvp11_driver); -} -module_init(gvp11_init); - -static void __exit gvp11_exit(void) -{ - zorro_unregister_driver(&gvp11_driver); -} -module_exit(gvp11_exit); - -MODULE_DESCRIPTION("GVP Series II SCSI"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/gvp11.h b/ANDROID_3.4.5/drivers/scsi/gvp11.h deleted file mode 100644 index 852913cd..00000000 --- a/ANDROID_3.4.5/drivers/scsi/gvp11.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef GVP11_H - -/* $Id: gvp11.h,v 1.4 1997/01/19 23:07:12 davem Exp $ - * - * Header file for the GVP Series II SCSI controller for Linux - * - * Written and (C) 1993, Ralf Baechle, see gvp11.c for more info - * based on a2091.h (C) 1993 by Hamish Macdonald - * - */ - -#include - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 16 -#endif - -/* - * if the transfer address ANDed with this results in a non-zero - * result, then we can't use DMA. - */ -#define GVP11_XFER_MASK (0xff000001) - -struct gvp11_scsiregs { - unsigned char pad1[64]; - volatile unsigned short CNTR; - unsigned char pad2[31]; - volatile unsigned char SASR; - unsigned char pad3; - volatile unsigned char SCMD; - unsigned char pad4[4]; - volatile unsigned short BANK; - unsigned char pad5[6]; - volatile unsigned long ACR; - volatile unsigned short secret1; /* store 0 here */ - volatile unsigned short ST_DMA; - volatile unsigned short SP_DMA; - volatile unsigned short secret2; /* store 1 here */ - volatile unsigned short secret3; /* store 15 here */ -}; - -/* bits in CNTR */ -#define GVP11_DMAC_BUSY (1<<0) -#define GVP11_DMAC_INT_PENDING (1<<1) -#define GVP11_DMAC_INT_ENABLE (1<<3) -#define GVP11_DMAC_DIR_WRITE (1<<4) - -#endif /* GVP11_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/hosts.c b/ANDROID_3.4.5/drivers/scsi/hosts.c deleted file mode 100644 index a3a056a9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/hosts.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * hosts.c Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995 Eric Youngdale - * Copyright (C) 2002-2003 Christoph Hellwig - * - * mid to lowlevel SCSI driver interface - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * - * - * - * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli - * Added QLOGIC QLA1280 SCSI controller kernel host support. - * August 4, 1999 Fred Lewis, Intel DuPont - * - * Updated to reflect the new initialization scheme for the higher - * level of scsi drivers (sd/sr/st) - * September 17, 2000 Torben Mathiasen - * - * Restructured scsi_host lists and associated functions. - * September 04, 2002 Mike Anderson (andmike@us.ibm.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "scsi_priv.h" -#include "scsi_logging.h" - - -static atomic_t scsi_host_next_hn; /* host_no for next new host */ - - -static void scsi_host_cls_release(struct device *dev) -{ - put_device(&class_to_shost(dev)->shost_gendev); -} - -static struct class shost_class = { - .name = "scsi_host", - .dev_release = scsi_host_cls_release, -}; - -/** - * scsi_host_set_state - Take the given host through the host state model. - * @shost: scsi host to change the state of. - * @state: state to change to. - * - * Returns zero if unsuccessful or an error if the requested - * transition is illegal. - **/ -int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state) -{ - enum scsi_host_state oldstate = shost->shost_state; - - if (state == oldstate) - return 0; - - switch (state) { - case SHOST_CREATED: - /* There are no legal states that come back to - * created. This is the manually initialised start - * state */ - goto illegal; - - case SHOST_RUNNING: - switch (oldstate) { - case SHOST_CREATED: - case SHOST_RECOVERY: - break; - default: - goto illegal; - } - break; - - case SHOST_RECOVERY: - switch (oldstate) { - case SHOST_RUNNING: - break; - default: - goto illegal; - } - break; - - case SHOST_CANCEL: - switch (oldstate) { - case SHOST_CREATED: - case SHOST_RUNNING: - case SHOST_CANCEL_RECOVERY: - break; - default: - goto illegal; - } - break; - - case SHOST_DEL: - switch (oldstate) { - case SHOST_CANCEL: - case SHOST_DEL_RECOVERY: - break; - default: - goto illegal; - } - break; - - case SHOST_CANCEL_RECOVERY: - switch (oldstate) { - case SHOST_CANCEL: - case SHOST_RECOVERY: - break; - default: - goto illegal; - } - break; - - case SHOST_DEL_RECOVERY: - switch (oldstate) { - case SHOST_CANCEL_RECOVERY: - break; - default: - goto illegal; - } - break; - } - shost->shost_state = state; - return 0; - - illegal: - SCSI_LOG_ERROR_RECOVERY(1, - shost_printk(KERN_ERR, shost, - "Illegal host state transition" - "%s->%s\n", - scsi_host_state_name(oldstate), - scsi_host_state_name(state))); - return -EINVAL; -} -EXPORT_SYMBOL(scsi_host_set_state); - -/** - * scsi_remove_host - remove a scsi host - * @shost: a pointer to a scsi host to remove - **/ -void scsi_remove_host(struct Scsi_Host *shost) -{ - unsigned long flags; - - mutex_lock(&shost->scan_mutex); - spin_lock_irqsave(shost->host_lock, flags); - if (scsi_host_set_state(shost, SHOST_CANCEL)) - if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) { - spin_unlock_irqrestore(shost->host_lock, flags); - mutex_unlock(&shost->scan_mutex); - return; - } - spin_unlock_irqrestore(shost->host_lock, flags); - - scsi_autopm_get_host(shost); - scsi_forget_host(shost); - mutex_unlock(&shost->scan_mutex); - scsi_proc_host_rm(shost); - - spin_lock_irqsave(shost->host_lock, flags); - if (scsi_host_set_state(shost, SHOST_DEL)) - BUG_ON(scsi_host_set_state(shost, SHOST_DEL_RECOVERY)); - spin_unlock_irqrestore(shost->host_lock, flags); - - transport_unregister_device(&shost->shost_gendev); - device_unregister(&shost->shost_dev); - device_del(&shost->shost_gendev); -} -EXPORT_SYMBOL(scsi_remove_host); - -/** - * scsi_add_host_with_dma - add a scsi host with dma device - * @shost: scsi host pointer to add - * @dev: a struct device of type scsi class - * @dma_dev: dma device for the host - * - * Note: You rarely need to worry about this unless you're in a - * virtualised host environments, so use the simpler scsi_add_host() - * function instead. - * - * Return value: - * 0 on success / != 0 for error - **/ -int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev, - struct device *dma_dev) -{ - struct scsi_host_template *sht = shost->hostt; - int error = -EINVAL; - - printk(KERN_INFO "scsi%d : %s\n", shost->host_no, - sht->info ? sht->info(shost) : sht->name); - - if (!shost->can_queue) { - printk(KERN_ERR "%s: can_queue = 0 no longer supported\n", - sht->name); - goto fail; - } - - error = scsi_setup_command_freelist(shost); - if (error) - goto fail; - - if (!shost->shost_gendev.parent) - shost->shost_gendev.parent = dev ? dev : &platform_bus; - if (!dma_dev) - dma_dev = shost->shost_gendev.parent; - - shost->dma_dev = dma_dev; - - error = device_add(&shost->shost_gendev); - if (error) - goto out; - - pm_runtime_set_active(&shost->shost_gendev); - pm_runtime_enable(&shost->shost_gendev); - device_enable_async_suspend(&shost->shost_gendev); - - scsi_host_set_state(shost, SHOST_RUNNING); - get_device(shost->shost_gendev.parent); - - device_enable_async_suspend(&shost->shost_dev); - - error = device_add(&shost->shost_dev); - if (error) - goto out_del_gendev; - - get_device(&shost->shost_gendev); - - if (shost->transportt->host_size) { - shost->shost_data = kzalloc(shost->transportt->host_size, - GFP_KERNEL); - if (shost->shost_data == NULL) { - error = -ENOMEM; - goto out_del_dev; - } - } - - if (shost->transportt->create_work_queue) { - snprintf(shost->work_q_name, sizeof(shost->work_q_name), - "scsi_wq_%d", shost->host_no); - shost->work_q = create_singlethread_workqueue( - shost->work_q_name); - if (!shost->work_q) { - error = -EINVAL; - goto out_free_shost_data; - } - } - - error = scsi_sysfs_add_host(shost); - if (error) - goto out_destroy_host; - - scsi_proc_host_add(shost); - return error; - - out_destroy_host: - if (shost->work_q) - destroy_workqueue(shost->work_q); - out_free_shost_data: - kfree(shost->shost_data); - out_del_dev: - device_del(&shost->shost_dev); - out_del_gendev: - device_del(&shost->shost_gendev); - out: - scsi_destroy_command_freelist(shost); - fail: - return error; -} -EXPORT_SYMBOL(scsi_add_host_with_dma); - -static void scsi_host_dev_release(struct device *dev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct device *parent = dev->parent; - struct request_queue *q; - - scsi_proc_hostdir_rm(shost->hostt); - - if (shost->ehandler) - kthread_stop(shost->ehandler); - if (shost->work_q) - destroy_workqueue(shost->work_q); - q = shost->uspace_req_q; - if (q) { - kfree(q->queuedata); - q->queuedata = NULL; - scsi_free_queue(q); - } - - scsi_destroy_command_freelist(shost); - if (shost->bqt) - blk_free_tags(shost->bqt); - - kfree(shost->shost_data); - - if (parent) - put_device(parent); - kfree(shost); -} - -static struct device_type scsi_host_type = { - .name = "scsi_host", - .release = scsi_host_dev_release, -}; - -/** - * scsi_host_alloc - register a scsi host adapter instance. - * @sht: pointer to scsi host template - * @privsize: extra bytes to allocate for driver - * - * Note: - * Allocate a new Scsi_Host and perform basic initialization. - * The host is not published to the scsi midlayer until scsi_add_host - * is called. - * - * Return value: - * Pointer to a new Scsi_Host - **/ -struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) -{ - struct Scsi_Host *shost; - gfp_t gfp_mask = GFP_KERNEL; - - if (sht->unchecked_isa_dma && privsize) - gfp_mask |= __GFP_DMA; - - shost = kzalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask); - if (!shost) - return NULL; - - shost->host_lock = &shost->default_lock; - spin_lock_init(shost->host_lock); - shost->shost_state = SHOST_CREATED; - INIT_LIST_HEAD(&shost->__devices); - INIT_LIST_HEAD(&shost->__targets); - INIT_LIST_HEAD(&shost->eh_cmd_q); - INIT_LIST_HEAD(&shost->starved_list); - init_waitqueue_head(&shost->host_wait); - - mutex_init(&shost->scan_mutex); - - /* - * subtract one because we increment first then return, but we need to - * know what the next host number was before increment - */ - shost->host_no = atomic_inc_return(&scsi_host_next_hn) - 1; - shost->dma_channel = 0xff; - - /* These three are default values which can be overridden */ - shost->max_channel = 0; - shost->max_id = 8; - shost->max_lun = 8; - - /* Give each shost a default transportt */ - shost->transportt = &blank_transport_template; - - /* - * All drivers right now should be able to handle 12 byte - * commands. Every so often there are requests for 16 byte - * commands, but individual low-level drivers need to certify that - * they actually do something sensible with such commands. - */ - shost->max_cmd_len = 12; - shost->hostt = sht; - shost->this_id = sht->this_id; - shost->can_queue = sht->can_queue; - shost->sg_tablesize = sht->sg_tablesize; - shost->sg_prot_tablesize = sht->sg_prot_tablesize; - shost->cmd_per_lun = sht->cmd_per_lun; - shost->unchecked_isa_dma = sht->unchecked_isa_dma; - shost->use_clustering = sht->use_clustering; - shost->ordered_tag = sht->ordered_tag; - - if (sht->supported_mode == MODE_UNKNOWN) - /* means we didn't set it ... default to INITIATOR */ - shost->active_mode = MODE_INITIATOR; - else - shost->active_mode = sht->supported_mode; - - if (sht->max_host_blocked) - shost->max_host_blocked = sht->max_host_blocked; - else - shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED; - - /* - * If the driver imposes no hard sector transfer limit, start at - * machine infinity initially. - */ - if (sht->max_sectors) - shost->max_sectors = sht->max_sectors; - else - shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS; - - /* - * assume a 4GB boundary, if not set - */ - if (sht->dma_boundary) - shost->dma_boundary = sht->dma_boundary; - else - shost->dma_boundary = 0xffffffff; - - device_initialize(&shost->shost_gendev); - dev_set_name(&shost->shost_gendev, "host%d", shost->host_no); - shost->shost_gendev.bus = &scsi_bus_type; - shost->shost_gendev.type = &scsi_host_type; - - device_initialize(&shost->shost_dev); - shost->shost_dev.parent = &shost->shost_gendev; - shost->shost_dev.class = &shost_class; - dev_set_name(&shost->shost_dev, "host%d", shost->host_no); - shost->shost_dev.groups = scsi_sysfs_shost_attr_groups; - - shost->ehandler = kthread_run(scsi_error_handler, shost, - "scsi_eh_%d", shost->host_no); - if (IS_ERR(shost->ehandler)) { - printk(KERN_WARNING "scsi%d: error handler thread failed to spawn, error = %ld\n", - shost->host_no, PTR_ERR(shost->ehandler)); - goto fail_kfree; - } - - scsi_proc_hostdir_add(shost->hostt); - return shost; - - fail_kfree: - kfree(shost); - return NULL; -} -EXPORT_SYMBOL(scsi_host_alloc); - -struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize) -{ - struct Scsi_Host *shost = scsi_host_alloc(sht, privsize); - - if (!sht->detect) { - printk(KERN_WARNING "scsi_register() called on new-style " - "template for driver %s\n", sht->name); - dump_stack(); - } - - if (shost) - list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts); - return shost; -} -EXPORT_SYMBOL(scsi_register); - -void scsi_unregister(struct Scsi_Host *shost) -{ - list_del(&shost->sht_legacy_list); - scsi_host_put(shost); -} -EXPORT_SYMBOL(scsi_unregister); - -static int __scsi_host_match(struct device *dev, void *data) -{ - struct Scsi_Host *p; - unsigned short *hostnum = (unsigned short *)data; - - p = class_to_shost(dev); - return p->host_no == *hostnum; -} - -/** - * scsi_host_lookup - get a reference to a Scsi_Host by host no - * @hostnum: host number to locate - * - * Return value: - * A pointer to located Scsi_Host or NULL. - * - * The caller must do a scsi_host_put() to drop the reference - * that scsi_host_get() took. The put_device() below dropped - * the reference from class_find_device(). - **/ -struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) -{ - struct device *cdev; - struct Scsi_Host *shost = NULL; - - cdev = class_find_device(&shost_class, NULL, &hostnum, - __scsi_host_match); - if (cdev) { - shost = scsi_host_get(class_to_shost(cdev)); - put_device(cdev); - } - return shost; -} -EXPORT_SYMBOL(scsi_host_lookup); - -/** - * scsi_host_get - inc a Scsi_Host ref count - * @shost: Pointer to Scsi_Host to inc. - **/ -struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost) -{ - if ((shost->shost_state == SHOST_DEL) || - !get_device(&shost->shost_gendev)) - return NULL; - return shost; -} -EXPORT_SYMBOL(scsi_host_get); - -/** - * scsi_host_put - dec a Scsi_Host ref count - * @shost: Pointer to Scsi_Host to dec. - **/ -void scsi_host_put(struct Scsi_Host *shost) -{ - put_device(&shost->shost_gendev); -} -EXPORT_SYMBOL(scsi_host_put); - -int scsi_init_hosts(void) -{ - return class_register(&shost_class); -} - -void scsi_exit_hosts(void) -{ - class_unregister(&shost_class); -} - -int scsi_is_host_device(const struct device *dev) -{ - return dev->type == &scsi_host_type; -} -EXPORT_SYMBOL(scsi_is_host_device); - -/** - * scsi_queue_work - Queue work to the Scsi_Host workqueue. - * @shost: Pointer to Scsi_Host. - * @work: Work to queue for execution. - * - * Return value: - * 1 - work queued for execution - * 0 - work is already queued - * -EINVAL - work queue doesn't exist - **/ -int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work) -{ - if (unlikely(!shost->work_q)) { - printk(KERN_ERR - "ERROR: Scsi host '%s' attempted to queue scsi-work, " - "when no workqueue created.\n", shost->hostt->name); - dump_stack(); - - return -EINVAL; - } - - return queue_work(shost->work_q, work); -} -EXPORT_SYMBOL_GPL(scsi_queue_work); - -/** - * scsi_flush_work - Flush a Scsi_Host's workqueue. - * @shost: Pointer to Scsi_Host. - **/ -void scsi_flush_work(struct Scsi_Host *shost) -{ - if (!shost->work_q) { - printk(KERN_ERR - "ERROR: Scsi host '%s' attempted to flush scsi-work, " - "when no workqueue created.\n", shost->hostt->name); - dump_stack(); - return; - } - - flush_workqueue(shost->work_q); -} -EXPORT_SYMBOL_GPL(scsi_flush_work); diff --git a/ANDROID_3.4.5/drivers/scsi/hpsa.c b/ANDROID_3.4.5/drivers/scsi/hpsa.c deleted file mode 100644 index 500e20dd..00000000 --- a/ANDROID_3.4.5/drivers/scsi/hpsa.c +++ /dev/null @@ -1,4716 +0,0 @@ -/* - * Disk Array driver for HP Smart Array SAS controllers - * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Questions/Comments/Bugfixes to iss_storagedev@hp.com - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hpsa_cmd.h" -#include "hpsa.h" - -/* HPSA_DRIVER_VERSION must be 3 byte values (0-255) separated by '.' */ -#define HPSA_DRIVER_VERSION "2.0.2-1" -#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")" -#define HPSA "hpsa" - -/* How long to wait (in milliseconds) for board to go into simple mode */ -#define MAX_CONFIG_WAIT 30000 -#define MAX_IOCTL_CONFIG_WAIT 1000 - -/*define how many times we will try a command because of bus resets */ -#define MAX_CMD_RETRIES 3 - -/* Embedded module documentation macros - see modules.h */ -MODULE_AUTHOR("Hewlett-Packard Company"); -MODULE_DESCRIPTION("Driver for HP Smart Array Controller version " \ - HPSA_DRIVER_VERSION); -MODULE_SUPPORTED_DEVICE("HP Smart Array Controllers"); -MODULE_VERSION(HPSA_DRIVER_VERSION); -MODULE_LICENSE("GPL"); - -static int hpsa_allow_any; -module_param(hpsa_allow_any, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(hpsa_allow_any, - "Allow hpsa driver to access unknown HP Smart Array hardware"); -static int hpsa_simple_mode; -module_param(hpsa_simple_mode, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(hpsa_simple_mode, - "Use 'simple mode' rather than 'performant mode'"); - -/* define the PCI info for the cards we can control */ -static const struct pci_device_id hpsa_pci_device_id[] = { - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3241}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3243}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3245}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3247}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3249}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324a}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x324b}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSE, 0x103C, 0x3233}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3350}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3351}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3352}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3353}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3354}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3355}, - {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSF, 0x103C, 0x3356}, - {PCI_VENDOR_ID_HP, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_STORAGE_RAID << 8, 0xffff << 8, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, hpsa_pci_device_id); - -/* board_id = Subsystem Device ID & Vendor ID - * product = Marketing Name for the board - * access = Address of the struct of function pointers - */ -static struct board_type products[] = { - {0x3241103C, "Smart Array P212", &SA5_access}, - {0x3243103C, "Smart Array P410", &SA5_access}, - {0x3245103C, "Smart Array P410i", &SA5_access}, - {0x3247103C, "Smart Array P411", &SA5_access}, - {0x3249103C, "Smart Array P812", &SA5_access}, - {0x324a103C, "Smart Array P712m", &SA5_access}, - {0x324b103C, "Smart Array P711m", &SA5_access}, - {0x3350103C, "Smart Array", &SA5_access}, - {0x3351103C, "Smart Array", &SA5_access}, - {0x3352103C, "Smart Array", &SA5_access}, - {0x3353103C, "Smart Array", &SA5_access}, - {0x3354103C, "Smart Array", &SA5_access}, - {0x3355103C, "Smart Array", &SA5_access}, - {0x3356103C, "Smart Array", &SA5_access}, - {0xFFFF103C, "Unknown Smart Array", &SA5_access}, -}; - -static int number_of_controllers; - -static struct list_head hpsa_ctlr_list = LIST_HEAD_INIT(hpsa_ctlr_list); -static spinlock_t lockup_detector_lock; -static struct task_struct *hpsa_lockup_detector; - -static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id); -static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id); -static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg); -static void start_io(struct ctlr_info *h); - -#ifdef CONFIG_COMPAT -static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg); -#endif - -static void cmd_free(struct ctlr_info *h, struct CommandList *c); -static void cmd_special_free(struct ctlr_info *h, struct CommandList *c); -static struct CommandList *cmd_alloc(struct ctlr_info *h); -static struct CommandList *cmd_special_alloc(struct ctlr_info *h); -static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, - void *buff, size_t size, u8 page_code, unsigned char *scsi3addr, - int cmd_type); - -static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd); -static void hpsa_scan_start(struct Scsi_Host *); -static int hpsa_scan_finished(struct Scsi_Host *sh, - unsigned long elapsed_time); -static int hpsa_change_queue_depth(struct scsi_device *sdev, - int qdepth, int reason); - -static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd); -static int hpsa_slave_alloc(struct scsi_device *sdev); -static void hpsa_slave_destroy(struct scsi_device *sdev); - -static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno); -static int check_for_unit_attention(struct ctlr_info *h, - struct CommandList *c); -static void check_ioctl_unit_attention(struct ctlr_info *h, - struct CommandList *c); -/* performant mode helper functions */ -static void calc_bucket_map(int *bucket, int num_buckets, - int nsgs, int *bucket_map); -static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h); -static inline u32 next_command(struct ctlr_info *h); -static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev, - void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, - u64 *cfg_offset); -static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev, - unsigned long *memory_bar); -static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id); -static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev, - void __iomem *vaddr, int wait_for_ready); -#define BOARD_NOT_READY 0 -#define BOARD_READY 1 - -static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) -{ - unsigned long *priv = shost_priv(sdev->host); - return (struct ctlr_info *) *priv; -} - -static inline struct ctlr_info *shost_to_hba(struct Scsi_Host *sh) -{ - unsigned long *priv = shost_priv(sh); - return (struct ctlr_info *) *priv; -} - -static int check_for_unit_attention(struct ctlr_info *h, - struct CommandList *c) -{ - if (c->err_info->SenseInfo[2] != UNIT_ATTENTION) - return 0; - - switch (c->err_info->SenseInfo[12]) { - case STATE_CHANGED: - dev_warn(&h->pdev->dev, HPSA "%d: a state change " - "detected, command retried\n", h->ctlr); - break; - case LUN_FAILED: - dev_warn(&h->pdev->dev, HPSA "%d: LUN failure " - "detected, action required\n", h->ctlr); - break; - case REPORT_LUNS_CHANGED: - dev_warn(&h->pdev->dev, HPSA "%d: report LUN data " - "changed, action required\n", h->ctlr); - /* - * Note: this REPORT_LUNS_CHANGED condition only occurs on the external - * target (array) devices. - */ - break; - case POWER_OR_RESET: - dev_warn(&h->pdev->dev, HPSA "%d: a power on " - "or device reset detected\n", h->ctlr); - break; - case UNIT_ATTENTION_CLEARED: - dev_warn(&h->pdev->dev, HPSA "%d: unit attention " - "cleared by another initiator\n", h->ctlr); - break; - default: - dev_warn(&h->pdev->dev, HPSA "%d: unknown " - "unit attention detected\n", h->ctlr); - break; - } - return 1; -} - -static ssize_t host_store_rescan(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ctlr_info *h; - struct Scsi_Host *shost = class_to_shost(dev); - h = shost_to_hba(shost); - hpsa_scan_start(h->scsi_host); - return count; -} - -static ssize_t host_show_firmware_revision(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ctlr_info *h; - struct Scsi_Host *shost = class_to_shost(dev); - unsigned char *fwrev; - - h = shost_to_hba(shost); - if (!h->hba_inquiry_data) - return 0; - fwrev = &h->hba_inquiry_data[32]; - return snprintf(buf, 20, "%c%c%c%c\n", - fwrev[0], fwrev[1], fwrev[2], fwrev[3]); -} - -static ssize_t host_show_commands_outstanding(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ctlr_info *h = shost_to_hba(shost); - - return snprintf(buf, 20, "%d\n", h->commands_outstanding); -} - -static ssize_t host_show_transport_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ctlr_info *h; - struct Scsi_Host *shost = class_to_shost(dev); - - h = shost_to_hba(shost); - return snprintf(buf, 20, "%s\n", - h->transMethod & CFGTBL_Trans_Performant ? - "performant" : "simple"); -} - -/* List of controllers which cannot be hard reset on kexec with reset_devices */ -static u32 unresettable_controller[] = { - 0x324a103C, /* Smart Array P712m */ - 0x324b103C, /* SmartArray P711m */ - 0x3223103C, /* Smart Array P800 */ - 0x3234103C, /* Smart Array P400 */ - 0x3235103C, /* Smart Array P400i */ - 0x3211103C, /* Smart Array E200i */ - 0x3212103C, /* Smart Array E200 */ - 0x3213103C, /* Smart Array E200i */ - 0x3214103C, /* Smart Array E200i */ - 0x3215103C, /* Smart Array E200i */ - 0x3237103C, /* Smart Array E500 */ - 0x323D103C, /* Smart Array P700m */ - 0x40800E11, /* Smart Array 5i */ - 0x409C0E11, /* Smart Array 6400 */ - 0x409D0E11, /* Smart Array 6400 EM */ - 0x40700E11, /* Smart Array 5300 */ - 0x40820E11, /* Smart Array 532 */ - 0x40830E11, /* Smart Array 5312 */ - 0x409A0E11, /* Smart Array 641 */ - 0x409B0E11, /* Smart Array 642 */ - 0x40910E11, /* Smart Array 6i */ -}; - -/* List of controllers which cannot even be soft reset */ -static u32 soft_unresettable_controller[] = { - 0x40800E11, /* Smart Array 5i */ - 0x40700E11, /* Smart Array 5300 */ - 0x40820E11, /* Smart Array 532 */ - 0x40830E11, /* Smart Array 5312 */ - 0x409A0E11, /* Smart Array 641 */ - 0x409B0E11, /* Smart Array 642 */ - 0x40910E11, /* Smart Array 6i */ - /* Exclude 640x boards. These are two pci devices in one slot - * which share a battery backed cache module. One controls the - * cache, the other accesses the cache through the one that controls - * it. If we reset the one controlling the cache, the other will - * likely not be happy. Just forbid resetting this conjoined mess. - * The 640x isn't really supported by hpsa anyway. - */ - 0x409C0E11, /* Smart Array 6400 */ - 0x409D0E11, /* Smart Array 6400 EM */ -}; - -static int ctlr_is_hard_resettable(u32 board_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(unresettable_controller); i++) - if (unresettable_controller[i] == board_id) - return 0; - return 1; -} - -static int ctlr_is_soft_resettable(u32 board_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(soft_unresettable_controller); i++) - if (soft_unresettable_controller[i] == board_id) - return 0; - return 1; -} - -static int ctlr_is_resettable(u32 board_id) -{ - return ctlr_is_hard_resettable(board_id) || - ctlr_is_soft_resettable(board_id); -} - -static ssize_t host_show_resettable(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ctlr_info *h; - struct Scsi_Host *shost = class_to_shost(dev); - - h = shost_to_hba(shost); - return snprintf(buf, 20, "%d\n", ctlr_is_resettable(h->board_id)); -} - -static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[]) -{ - return (scsi3addr[3] & 0xC0) == 0x40; -} - -static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG", - "UNKNOWN" -}; -#define RAID_UNKNOWN (ARRAY_SIZE(raid_label) - 1) - -static ssize_t raid_level_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t l = 0; - unsigned char rlevel; - struct ctlr_info *h; - struct scsi_device *sdev; - struct hpsa_scsi_dev_t *hdev; - unsigned long flags; - - sdev = to_scsi_device(dev); - h = sdev_to_hba(sdev); - spin_lock_irqsave(&h->lock, flags); - hdev = sdev->hostdata; - if (!hdev) { - spin_unlock_irqrestore(&h->lock, flags); - return -ENODEV; - } - - /* Is this even a logical drive? */ - if (!is_logical_dev_addr_mode(hdev->scsi3addr)) { - spin_unlock_irqrestore(&h->lock, flags); - l = snprintf(buf, PAGE_SIZE, "N/A\n"); - return l; - } - - rlevel = hdev->raid_level; - spin_unlock_irqrestore(&h->lock, flags); - if (rlevel > RAID_UNKNOWN) - rlevel = RAID_UNKNOWN; - l = snprintf(buf, PAGE_SIZE, "RAID %s\n", raid_label[rlevel]); - return l; -} - -static ssize_t lunid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ctlr_info *h; - struct scsi_device *sdev; - struct hpsa_scsi_dev_t *hdev; - unsigned long flags; - unsigned char lunid[8]; - - sdev = to_scsi_device(dev); - h = sdev_to_hba(sdev); - spin_lock_irqsave(&h->lock, flags); - hdev = sdev->hostdata; - if (!hdev) { - spin_unlock_irqrestore(&h->lock, flags); - return -ENODEV; - } - memcpy(lunid, hdev->scsi3addr, sizeof(lunid)); - spin_unlock_irqrestore(&h->lock, flags); - return snprintf(buf, 20, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", - lunid[0], lunid[1], lunid[2], lunid[3], - lunid[4], lunid[5], lunid[6], lunid[7]); -} - -static ssize_t unique_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ctlr_info *h; - struct scsi_device *sdev; - struct hpsa_scsi_dev_t *hdev; - unsigned long flags; - unsigned char sn[16]; - - sdev = to_scsi_device(dev); - h = sdev_to_hba(sdev); - spin_lock_irqsave(&h->lock, flags); - hdev = sdev->hostdata; - if (!hdev) { - spin_unlock_irqrestore(&h->lock, flags); - return -ENODEV; - } - memcpy(sn, hdev->device_id, sizeof(sn)); - spin_unlock_irqrestore(&h->lock, flags); - return snprintf(buf, 16 * 2 + 2, - "%02X%02X%02X%02X%02X%02X%02X%02X" - "%02X%02X%02X%02X%02X%02X%02X%02X\n", - sn[0], sn[1], sn[2], sn[3], - sn[4], sn[5], sn[6], sn[7], - sn[8], sn[9], sn[10], sn[11], - sn[12], sn[13], sn[14], sn[15]); -} - -static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); -static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); -static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL); -static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); -static DEVICE_ATTR(firmware_revision, S_IRUGO, - host_show_firmware_revision, NULL); -static DEVICE_ATTR(commands_outstanding, S_IRUGO, - host_show_commands_outstanding, NULL); -static DEVICE_ATTR(transport_mode, S_IRUGO, - host_show_transport_mode, NULL); -static DEVICE_ATTR(resettable, S_IRUGO, - host_show_resettable, NULL); - -static struct device_attribute *hpsa_sdev_attrs[] = { - &dev_attr_raid_level, - &dev_attr_lunid, - &dev_attr_unique_id, - NULL, -}; - -static struct device_attribute *hpsa_shost_attrs[] = { - &dev_attr_rescan, - &dev_attr_firmware_revision, - &dev_attr_commands_outstanding, - &dev_attr_transport_mode, - &dev_attr_resettable, - NULL, -}; - -static struct scsi_host_template hpsa_driver_template = { - .module = THIS_MODULE, - .name = HPSA, - .proc_name = HPSA, - .queuecommand = hpsa_scsi_queue_command, - .scan_start = hpsa_scan_start, - .scan_finished = hpsa_scan_finished, - .change_queue_depth = hpsa_change_queue_depth, - .this_id = -1, - .use_clustering = ENABLE_CLUSTERING, - .eh_device_reset_handler = hpsa_eh_device_reset_handler, - .ioctl = hpsa_ioctl, - .slave_alloc = hpsa_slave_alloc, - .slave_destroy = hpsa_slave_destroy, -#ifdef CONFIG_COMPAT - .compat_ioctl = hpsa_compat_ioctl, -#endif - .sdev_attrs = hpsa_sdev_attrs, - .shost_attrs = hpsa_shost_attrs, - .max_sectors = 8192, -}; - - -/* Enqueuing and dequeuing functions for cmdlists. */ -static inline void addQ(struct list_head *list, struct CommandList *c) -{ - list_add_tail(&c->list, list); -} - -static inline u32 next_command(struct ctlr_info *h) -{ - u32 a; - - if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) - return h->access.command_completed(h); - - if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { - a = *(h->reply_pool_head); /* Next cmd in ring buffer */ - (h->reply_pool_head)++; - h->commands_outstanding--; - } else { - a = FIFO_EMPTY; - } - /* Check for wraparound */ - if (h->reply_pool_head == (h->reply_pool + h->max_commands)) { - h->reply_pool_head = h->reply_pool; - h->reply_pool_wraparound ^= 1; - } - return a; -} - -/* set_performant_mode: Modify the tag for cciss performant - * set bit 0 for pull model, bits 3-1 for block fetch - * register number - */ -static void set_performant_mode(struct ctlr_info *h, struct CommandList *c) -{ - if (likely(h->transMethod & CFGTBL_Trans_Performant)) - c->busaddr |= 1 | (h->blockFetchTable[c->Header.SGList] << 1); -} - -static void enqueue_cmd_and_start_io(struct ctlr_info *h, - struct CommandList *c) -{ - unsigned long flags; - - set_performant_mode(h, c); - spin_lock_irqsave(&h->lock, flags); - addQ(&h->reqQ, c); - h->Qdepth++; - start_io(h); - spin_unlock_irqrestore(&h->lock, flags); -} - -static inline void removeQ(struct CommandList *c) -{ - if (WARN_ON(list_empty(&c->list))) - return; - list_del_init(&c->list); -} - -static inline int is_hba_lunid(unsigned char scsi3addr[]) -{ - return memcmp(scsi3addr, RAID_CTLR_LUNID, 8) == 0; -} - -static inline int is_scsi_rev_5(struct ctlr_info *h) -{ - if (!h->hba_inquiry_data) - return 0; - if ((h->hba_inquiry_data[2] & 0x07) == 5) - return 1; - return 0; -} - -static int hpsa_find_target_lun(struct ctlr_info *h, - unsigned char scsi3addr[], int bus, int *target, int *lun) -{ - /* finds an unused bus, target, lun for a new physical device - * assumes h->devlock is held - */ - int i, found = 0; - DECLARE_BITMAP(lun_taken, HPSA_MAX_DEVICES); - - bitmap_zero(lun_taken, HPSA_MAX_DEVICES); - - for (i = 0; i < h->ndevices; i++) { - if (h->dev[i]->bus == bus && h->dev[i]->target != -1) - __set_bit(h->dev[i]->target, lun_taken); - } - - i = find_first_zero_bit(lun_taken, HPSA_MAX_DEVICES); - if (i < HPSA_MAX_DEVICES) { - /* *bus = 1; */ - *target = i; - *lun = 0; - found = 1; - } - return !found; -} - -/* Add an entry into h->dev[] array. */ -static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, - struct hpsa_scsi_dev_t *device, - struct hpsa_scsi_dev_t *added[], int *nadded) -{ - /* assumes h->devlock is held */ - int n = h->ndevices; - int i; - unsigned char addr1[8], addr2[8]; - struct hpsa_scsi_dev_t *sd; - - if (n >= HPSA_MAX_DEVICES) { - dev_err(&h->pdev->dev, "too many devices, some will be " - "inaccessible.\n"); - return -1; - } - - /* physical devices do not have lun or target assigned until now. */ - if (device->lun != -1) - /* Logical device, lun is already assigned. */ - goto lun_assigned; - - /* If this device a non-zero lun of a multi-lun device - * byte 4 of the 8-byte LUN addr will contain the logical - * unit no, zero otherise. - */ - if (device->scsi3addr[4] == 0) { - /* This is not a non-zero lun of a multi-lun device */ - if (hpsa_find_target_lun(h, device->scsi3addr, - device->bus, &device->target, &device->lun) != 0) - return -1; - goto lun_assigned; - } - - /* This is a non-zero lun of a multi-lun device. - * Search through our list and find the device which - * has the same 8 byte LUN address, excepting byte 4. - * Assign the same bus and target for this new LUN. - * Use the logical unit number from the firmware. - */ - memcpy(addr1, device->scsi3addr, 8); - addr1[4] = 0; - for (i = 0; i < n; i++) { - sd = h->dev[i]; - memcpy(addr2, sd->scsi3addr, 8); - addr2[4] = 0; - /* differ only in byte 4? */ - if (memcmp(addr1, addr2, 8) == 0) { - device->bus = sd->bus; - device->target = sd->target; - device->lun = device->scsi3addr[4]; - break; - } - } - if (device->lun == -1) { - dev_warn(&h->pdev->dev, "physical device with no LUN=0," - " suspect firmware bug or unsupported hardware " - "configuration.\n"); - return -1; - } - -lun_assigned: - - h->dev[n] = device; - h->ndevices++; - added[*nadded] = device; - (*nadded)++; - - /* initially, (before registering with scsi layer) we don't - * know our hostno and we don't want to print anything first - * time anyway (the scsi layer's inquiries will show that info) - */ - /* if (hostno != -1) */ - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d added.\n", - scsi_device_type(device->devtype), hostno, - device->bus, device->target, device->lun); - return 0; -} - -/* Update an entry in h->dev[] array. */ -static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno, - int entry, struct hpsa_scsi_dev_t *new_entry) -{ - /* assumes h->devlock is held */ - BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES); - - /* Raid level changed. */ - h->dev[entry]->raid_level = new_entry->raid_level; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n", - scsi_device_type(new_entry->devtype), hostno, new_entry->bus, - new_entry->target, new_entry->lun); -} - -/* Replace an entry from h->dev[] array. */ -static void hpsa_scsi_replace_entry(struct ctlr_info *h, int hostno, - int entry, struct hpsa_scsi_dev_t *new_entry, - struct hpsa_scsi_dev_t *added[], int *nadded, - struct hpsa_scsi_dev_t *removed[], int *nremoved) -{ - /* assumes h->devlock is held */ - BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES); - removed[*nremoved] = h->dev[entry]; - (*nremoved)++; - - /* - * New physical devices won't have target/lun assigned yet - * so we need to preserve the values in the slot we are replacing. - */ - if (new_entry->target == -1) { - new_entry->target = h->dev[entry]->target; - new_entry->lun = h->dev[entry]->lun; - } - - h->dev[entry] = new_entry; - added[*nadded] = new_entry; - (*nadded)++; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d changed.\n", - scsi_device_type(new_entry->devtype), hostno, new_entry->bus, - new_entry->target, new_entry->lun); -} - -/* Remove an entry from h->dev[] array. */ -static void hpsa_scsi_remove_entry(struct ctlr_info *h, int hostno, int entry, - struct hpsa_scsi_dev_t *removed[], int *nremoved) -{ - /* assumes h->devlock is held */ - int i; - struct hpsa_scsi_dev_t *sd; - - BUG_ON(entry < 0 || entry >= HPSA_MAX_DEVICES); - - sd = h->dev[entry]; - removed[*nremoved] = h->dev[entry]; - (*nremoved)++; - - for (i = entry; i < h->ndevices-1; i++) - h->dev[i] = h->dev[i+1]; - h->ndevices--; - dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d removed.\n", - scsi_device_type(sd->devtype), hostno, sd->bus, sd->target, - sd->lun); -} - -#define SCSI3ADDR_EQ(a, b) ( \ - (a)[7] == (b)[7] && \ - (a)[6] == (b)[6] && \ - (a)[5] == (b)[5] && \ - (a)[4] == (b)[4] && \ - (a)[3] == (b)[3] && \ - (a)[2] == (b)[2] && \ - (a)[1] == (b)[1] && \ - (a)[0] == (b)[0]) - -static void fixup_botched_add(struct ctlr_info *h, - struct hpsa_scsi_dev_t *added) -{ - /* called when scsi_add_device fails in order to re-adjust - * h->dev[] to match the mid layer's view. - */ - unsigned long flags; - int i, j; - - spin_lock_irqsave(&h->lock, flags); - for (i = 0; i < h->ndevices; i++) { - if (h->dev[i] == added) { - for (j = i; j < h->ndevices-1; j++) - h->dev[j] = h->dev[j+1]; - h->ndevices--; - break; - } - } - spin_unlock_irqrestore(&h->lock, flags); - kfree(added); -} - -static inline int device_is_the_same(struct hpsa_scsi_dev_t *dev1, - struct hpsa_scsi_dev_t *dev2) -{ - /* we compare everything except lun and target as these - * are not yet assigned. Compare parts likely - * to differ first - */ - if (memcmp(dev1->scsi3addr, dev2->scsi3addr, - sizeof(dev1->scsi3addr)) != 0) - return 0; - if (memcmp(dev1->device_id, dev2->device_id, - sizeof(dev1->device_id)) != 0) - return 0; - if (memcmp(dev1->model, dev2->model, sizeof(dev1->model)) != 0) - return 0; - if (memcmp(dev1->vendor, dev2->vendor, sizeof(dev1->vendor)) != 0) - return 0; - if (dev1->devtype != dev2->devtype) - return 0; - if (dev1->bus != dev2->bus) - return 0; - return 1; -} - -static inline int device_updated(struct hpsa_scsi_dev_t *dev1, - struct hpsa_scsi_dev_t *dev2) -{ - /* Device attributes that can change, but don't mean - * that the device is a different device, nor that the OS - * needs to be told anything about the change. - */ - if (dev1->raid_level != dev2->raid_level) - return 1; - return 0; -} - -/* Find needle in haystack. If exact match found, return DEVICE_SAME, - * and return needle location in *index. If scsi3addr matches, but not - * vendor, model, serial num, etc. return DEVICE_CHANGED, and return needle - * location in *index. - * In the case of a minor device attribute change, such as RAID level, just - * return DEVICE_UPDATED, along with the updated device's location in index. - * If needle not found, return DEVICE_NOT_FOUND. - */ -static int hpsa_scsi_find_entry(struct hpsa_scsi_dev_t *needle, - struct hpsa_scsi_dev_t *haystack[], int haystack_size, - int *index) -{ - int i; -#define DEVICE_NOT_FOUND 0 -#define DEVICE_CHANGED 1 -#define DEVICE_SAME 2 -#define DEVICE_UPDATED 3 - for (i = 0; i < haystack_size; i++) { - if (haystack[i] == NULL) /* previously removed. */ - continue; - if (SCSI3ADDR_EQ(needle->scsi3addr, haystack[i]->scsi3addr)) { - *index = i; - if (device_is_the_same(needle, haystack[i])) { - if (device_updated(needle, haystack[i])) - return DEVICE_UPDATED; - return DEVICE_SAME; - } else { - return DEVICE_CHANGED; - } - } - } - *index = -1; - return DEVICE_NOT_FOUND; -} - -static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, - struct hpsa_scsi_dev_t *sd[], int nsds) -{ - /* sd contains scsi3 addresses and devtypes, and inquiry - * data. This function takes what's in sd to be the current - * reality and updates h->dev[] to reflect that reality. - */ - int i, entry, device_change, changes = 0; - struct hpsa_scsi_dev_t *csd; - unsigned long flags; - struct hpsa_scsi_dev_t **added, **removed; - int nadded, nremoved; - struct Scsi_Host *sh = NULL; - - added = kzalloc(sizeof(*added) * HPSA_MAX_DEVICES, GFP_KERNEL); - removed = kzalloc(sizeof(*removed) * HPSA_MAX_DEVICES, GFP_KERNEL); - - if (!added || !removed) { - dev_warn(&h->pdev->dev, "out of memory in " - "adjust_hpsa_scsi_table\n"); - goto free_and_out; - } - - spin_lock_irqsave(&h->devlock, flags); - - /* find any devices in h->dev[] that are not in - * sd[] and remove them from h->dev[], and for any - * devices which have changed, remove the old device - * info and add the new device info. - * If minor device attributes change, just update - * the existing device structure. - */ - i = 0; - nremoved = 0; - nadded = 0; - while (i < h->ndevices) { - csd = h->dev[i]; - device_change = hpsa_scsi_find_entry(csd, sd, nsds, &entry); - if (device_change == DEVICE_NOT_FOUND) { - changes++; - hpsa_scsi_remove_entry(h, hostno, i, - removed, &nremoved); - continue; /* remove ^^^, hence i not incremented */ - } else if (device_change == DEVICE_CHANGED) { - changes++; - hpsa_scsi_replace_entry(h, hostno, i, sd[entry], - added, &nadded, removed, &nremoved); - /* Set it to NULL to prevent it from being freed - * at the bottom of hpsa_update_scsi_devices() - */ - sd[entry] = NULL; - } else if (device_change == DEVICE_UPDATED) { - hpsa_scsi_update_entry(h, hostno, i, sd[entry]); - } - i++; - } - - /* Now, make sure every device listed in sd[] is also - * listed in h->dev[], adding them if they aren't found - */ - - for (i = 0; i < nsds; i++) { - if (!sd[i]) /* if already added above. */ - continue; - device_change = hpsa_scsi_find_entry(sd[i], h->dev, - h->ndevices, &entry); - if (device_change == DEVICE_NOT_FOUND) { - changes++; - if (hpsa_scsi_add_entry(h, hostno, sd[i], - added, &nadded) != 0) - break; - sd[i] = NULL; /* prevent from being freed later. */ - } else if (device_change == DEVICE_CHANGED) { - /* should never happen... */ - changes++; - dev_warn(&h->pdev->dev, - "device unexpectedly changed.\n"); - /* but if it does happen, we just ignore that device */ - } - } - spin_unlock_irqrestore(&h->devlock, flags); - - /* Don't notify scsi mid layer of any changes the first time through - * (or if there are no changes) scsi_scan_host will do it later the - * first time through. - */ - if (hostno == -1 || !changes) - goto free_and_out; - - sh = h->scsi_host; - /* Notify scsi mid layer of any removed devices */ - for (i = 0; i < nremoved; i++) { - struct scsi_device *sdev = - scsi_device_lookup(sh, removed[i]->bus, - removed[i]->target, removed[i]->lun); - if (sdev != NULL) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } else { - /* We don't expect to get here. - * future cmds to this device will get selection - * timeout as if the device was gone. - */ - dev_warn(&h->pdev->dev, "didn't find c%db%dt%dl%d " - " for removal.", hostno, removed[i]->bus, - removed[i]->target, removed[i]->lun); - } - kfree(removed[i]); - removed[i] = NULL; - } - - /* Notify scsi mid layer of any added devices */ - for (i = 0; i < nadded; i++) { - if (scsi_add_device(sh, added[i]->bus, - added[i]->target, added[i]->lun) == 0) - continue; - dev_warn(&h->pdev->dev, "scsi_add_device c%db%dt%dl%d failed, " - "device not added.\n", hostno, added[i]->bus, - added[i]->target, added[i]->lun); - /* now we have to remove it from h->dev, - * since it didn't get added to scsi mid layer - */ - fixup_botched_add(h, added[i]); - } - -free_and_out: - kfree(added); - kfree(removed); -} - -/* - * Lookup bus/target/lun and retrun corresponding struct hpsa_scsi_dev_t * - * Assume's h->devlock is held. - */ -static struct hpsa_scsi_dev_t *lookup_hpsa_scsi_dev(struct ctlr_info *h, - int bus, int target, int lun) -{ - int i; - struct hpsa_scsi_dev_t *sd; - - for (i = 0; i < h->ndevices; i++) { - sd = h->dev[i]; - if (sd->bus == bus && sd->target == target && sd->lun == lun) - return sd; - } - return NULL; -} - -/* link sdev->hostdata to our per-device structure. */ -static int hpsa_slave_alloc(struct scsi_device *sdev) -{ - struct hpsa_scsi_dev_t *sd; - unsigned long flags; - struct ctlr_info *h; - - h = sdev_to_hba(sdev); - spin_lock_irqsave(&h->devlock, flags); - sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), - sdev_id(sdev), sdev->lun); - if (sd != NULL) - sdev->hostdata = sd; - spin_unlock_irqrestore(&h->devlock, flags); - return 0; -} - -static void hpsa_slave_destroy(struct scsi_device *sdev) -{ - /* nothing to do. */ -} - -static void hpsa_free_sg_chain_blocks(struct ctlr_info *h) -{ - int i; - - if (!h->cmd_sg_list) - return; - for (i = 0; i < h->nr_cmds; i++) { - kfree(h->cmd_sg_list[i]); - h->cmd_sg_list[i] = NULL; - } - kfree(h->cmd_sg_list); - h->cmd_sg_list = NULL; -} - -static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h) -{ - int i; - - if (h->chainsize <= 0) - return 0; - - h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds, - GFP_KERNEL); - if (!h->cmd_sg_list) - return -ENOMEM; - for (i = 0; i < h->nr_cmds; i++) { - h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) * - h->chainsize, GFP_KERNEL); - if (!h->cmd_sg_list[i]) - goto clean; - } - return 0; - -clean: - hpsa_free_sg_chain_blocks(h); - return -ENOMEM; -} - -static void hpsa_map_sg_chain_block(struct ctlr_info *h, - struct CommandList *c) -{ - struct SGDescriptor *chain_sg, *chain_block; - u64 temp64; - - chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; - chain_block = h->cmd_sg_list[c->cmdindex]; - chain_sg->Ext = HPSA_SG_CHAIN; - chain_sg->Len = sizeof(*chain_sg) * - (c->Header.SGTotal - h->max_cmd_sg_entries); - temp64 = pci_map_single(h->pdev, chain_block, chain_sg->Len, - PCI_DMA_TODEVICE); - chain_sg->Addr.lower = (u32) (temp64 & 0x0FFFFFFFFULL); - chain_sg->Addr.upper = (u32) ((temp64 >> 32) & 0x0FFFFFFFFULL); -} - -static void hpsa_unmap_sg_chain_block(struct ctlr_info *h, - struct CommandList *c) -{ - struct SGDescriptor *chain_sg; - union u64bit temp64; - - if (c->Header.SGTotal <= h->max_cmd_sg_entries) - return; - - chain_sg = &c->SG[h->max_cmd_sg_entries - 1]; - temp64.val32.lower = chain_sg->Addr.lower; - temp64.val32.upper = chain_sg->Addr.upper; - pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE); -} - -static void complete_scsi_command(struct CommandList *cp) -{ - struct scsi_cmnd *cmd; - struct ctlr_info *h; - struct ErrorInfo *ei; - - unsigned char sense_key; - unsigned char asc; /* additional sense code */ - unsigned char ascq; /* additional sense code qualifier */ - unsigned long sense_data_size; - - ei = cp->err_info; - cmd = (struct scsi_cmnd *) cp->scsi_cmd; - h = cp->h; - - scsi_dma_unmap(cmd); /* undo the DMA mappings */ - if (cp->Header.SGTotal > h->max_cmd_sg_entries) - hpsa_unmap_sg_chain_block(h, cp); - - cmd->result = (DID_OK << 16); /* host byte */ - cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */ - cmd->result |= ei->ScsiStatus; - - /* copy the sense data whether we need to or not. */ - if (SCSI_SENSE_BUFFERSIZE < sizeof(ei->SenseInfo)) - sense_data_size = SCSI_SENSE_BUFFERSIZE; - else - sense_data_size = sizeof(ei->SenseInfo); - if (ei->SenseLen < sense_data_size) - sense_data_size = ei->SenseLen; - - memcpy(cmd->sense_buffer, ei->SenseInfo, sense_data_size); - scsi_set_resid(cmd, ei->ResidualCnt); - - if (ei->CommandStatus == 0) { - cmd->scsi_done(cmd); - cmd_free(h, cp); - return; - } - - /* an error has occurred */ - switch (ei->CommandStatus) { - - case CMD_TARGET_STATUS: - if (ei->ScsiStatus) { - /* Get sense key */ - sense_key = 0xf & ei->SenseInfo[2]; - /* Get additional sense code */ - asc = ei->SenseInfo[12]; - /* Get addition sense code qualifier */ - ascq = ei->SenseInfo[13]; - } - - if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) { - if (check_for_unit_attention(h, cp)) { - cmd->result = DID_SOFT_ERROR << 16; - break; - } - if (sense_key == ILLEGAL_REQUEST) { - /* - * SCSI REPORT_LUNS is commonly unsupported on - * Smart Array. Suppress noisy complaint. - */ - if (cp->Request.CDB[0] == REPORT_LUNS) - break; - - /* If ASC/ASCQ indicate Logical Unit - * Not Supported condition, - */ - if ((asc == 0x25) && (ascq == 0x0)) { - dev_warn(&h->pdev->dev, "cp %p " - "has check condition\n", cp); - break; - } - } - - if (sense_key == NOT_READY) { - /* If Sense is Not Ready, Logical Unit - * Not ready, Manual Intervention - * required - */ - if ((asc == 0x04) && (ascq == 0x03)) { - dev_warn(&h->pdev->dev, "cp %p " - "has check condition: unit " - "not ready, manual " - "intervention required\n", cp); - break; - } - } - if (sense_key == ABORTED_COMMAND) { - /* Aborted command is retryable */ - dev_warn(&h->pdev->dev, "cp %p " - "has check condition: aborted command: " - "ASC: 0x%x, ASCQ: 0x%x\n", - cp, asc, ascq); - cmd->result = DID_SOFT_ERROR << 16; - break; - } - /* Must be some other type of check condition */ - dev_warn(&h->pdev->dev, "cp %p has check condition: " - "unknown type: " - "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, " - "Returning result: 0x%x, " - "cmd=[%02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x]\n", - cp, sense_key, asc, ascq, - cmd->result, - cmd->cmnd[0], cmd->cmnd[1], - cmd->cmnd[2], cmd->cmnd[3], - cmd->cmnd[4], cmd->cmnd[5], - cmd->cmnd[6], cmd->cmnd[7], - cmd->cmnd[8], cmd->cmnd[9], - cmd->cmnd[10], cmd->cmnd[11], - cmd->cmnd[12], cmd->cmnd[13], - cmd->cmnd[14], cmd->cmnd[15]); - break; - } - - - /* Problem was not a check condition - * Pass it up to the upper layers... - */ - if (ei->ScsiStatus) { - dev_warn(&h->pdev->dev, "cp %p has status 0x%x " - "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, " - "Returning result: 0x%x\n", - cp, ei->ScsiStatus, - sense_key, asc, ascq, - cmd->result); - } else { /* scsi status is zero??? How??? */ - dev_warn(&h->pdev->dev, "cp %p SCSI status was 0. " - "Returning no connection.\n", cp), - - /* Ordinarily, this case should never happen, - * but there is a bug in some released firmware - * revisions that allows it to happen if, for - * example, a 4100 backplane loses power and - * the tape drive is in it. We assume that - * it's a fatal error of some kind because we - * can't show that it wasn't. We will make it - * look like selection timeout since that is - * the most common reason for this to occur, - * and it's severe enough. - */ - - cmd->result = DID_NO_CONNECT << 16; - } - break; - - case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ - break; - case CMD_DATA_OVERRUN: - dev_warn(&h->pdev->dev, "cp %p has" - " completed with data overrun " - "reported\n", cp); - break; - case CMD_INVALID: { - /* print_bytes(cp, sizeof(*cp), 1, 0); - print_cmd(cp); */ - /* We get CMD_INVALID if you address a non-existent device - * instead of a selection timeout (no response). You will - * see this if you yank out a drive, then try to access it. - * This is kind of a shame because it means that any other - * CMD_INVALID (e.g. driver bug) will get interpreted as a - * missing target. */ - cmd->result = DID_NO_CONNECT << 16; - } - break; - case CMD_PROTOCOL_ERR: - dev_warn(&h->pdev->dev, "cp %p has " - "protocol error \n", cp); - break; - case CMD_HARDWARE_ERR: - cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p had hardware error\n", cp); - break; - case CMD_CONNECTION_LOST: - cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p had connection lost\n", cp); - break; - case CMD_ABORTED: - cmd->result = DID_ABORT << 16; - dev_warn(&h->pdev->dev, "cp %p was aborted with status 0x%x\n", - cp, ei->ScsiStatus); - break; - case CMD_ABORT_FAILED: - cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp); - break; - case CMD_UNSOLICITED_ABORT: - cmd->result = DID_SOFT_ERROR << 16; /* retry the command */ - dev_warn(&h->pdev->dev, "cp %p aborted due to an unsolicited " - "abort\n", cp); - break; - case CMD_TIMEOUT: - cmd->result = DID_TIME_OUT << 16; - dev_warn(&h->pdev->dev, "cp %p timedout\n", cp); - break; - case CMD_UNABORTABLE: - cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "Command unabortable\n"); - break; - default: - cmd->result = DID_ERROR << 16; - dev_warn(&h->pdev->dev, "cp %p returned unknown status %x\n", - cp, ei->CommandStatus); - } - cmd->scsi_done(cmd); - cmd_free(h, cp); -} - -static void hpsa_pci_unmap(struct pci_dev *pdev, - struct CommandList *c, int sg_used, int data_direction) -{ - int i; - union u64bit addr64; - - for (i = 0; i < sg_used; i++) { - addr64.val32.lower = c->SG[i].Addr.lower; - addr64.val32.upper = c->SG[i].Addr.upper; - pci_unmap_single(pdev, (dma_addr_t) addr64.val, c->SG[i].Len, - data_direction); - } -} - -static void hpsa_map_one(struct pci_dev *pdev, - struct CommandList *cp, - unsigned char *buf, - size_t buflen, - int data_direction) -{ - u64 addr64; - - if (buflen == 0 || data_direction == PCI_DMA_NONE) { - cp->Header.SGList = 0; - cp->Header.SGTotal = 0; - return; - } - - addr64 = (u64) pci_map_single(pdev, buf, buflen, data_direction); - cp->SG[0].Addr.lower = - (u32) (addr64 & (u64) 0x00000000FFFFFFFF); - cp->SG[0].Addr.upper = - (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF); - cp->SG[0].Len = buflen; - cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */ - cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */ -} - -static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h, - struct CommandList *c) -{ - DECLARE_COMPLETION_ONSTACK(wait); - - c->waiting = &wait; - enqueue_cmd_and_start_io(h, c); - wait_for_completion(&wait); -} - -static void hpsa_scsi_do_simple_cmd_core_if_no_lockup(struct ctlr_info *h, - struct CommandList *c) -{ - unsigned long flags; - - /* If controller lockup detected, fake a hardware error. */ - spin_lock_irqsave(&h->lock, flags); - if (unlikely(h->lockup_detected)) { - spin_unlock_irqrestore(&h->lock, flags); - c->err_info->CommandStatus = CMD_HARDWARE_ERR; - } else { - spin_unlock_irqrestore(&h->lock, flags); - hpsa_scsi_do_simple_cmd_core(h, c); - } -} - -static void hpsa_scsi_do_simple_cmd_with_retry(struct ctlr_info *h, - struct CommandList *c, int data_direction) -{ - int retry_count = 0; - - do { - memset(c->err_info, 0, sizeof(*c->err_info)); - hpsa_scsi_do_simple_cmd_core(h, c); - retry_count++; - } while (check_for_unit_attention(h, c) && retry_count <= 3); - hpsa_pci_unmap(h->pdev, c, 1, data_direction); -} - -static void hpsa_scsi_interpret_error(struct CommandList *cp) -{ - struct ErrorInfo *ei; - struct device *d = &cp->h->pdev->dev; - - ei = cp->err_info; - switch (ei->CommandStatus) { - case CMD_TARGET_STATUS: - dev_warn(d, "cmd %p has completed with errors\n", cp); - dev_warn(d, "cmd %p has SCSI Status = %x\n", cp, - ei->ScsiStatus); - if (ei->ScsiStatus == 0) - dev_warn(d, "SCSI status is abnormally zero. " - "(probably indicates selection timeout " - "reported incorrectly due to a known " - "firmware bug, circa July, 2001.)\n"); - break; - case CMD_DATA_UNDERRUN: /* let mid layer handle it. */ - dev_info(d, "UNDERRUN\n"); - break; - case CMD_DATA_OVERRUN: - dev_warn(d, "cp %p has completed with data overrun\n", cp); - break; - case CMD_INVALID: { - /* controller unfortunately reports SCSI passthru's - * to non-existent targets as invalid commands. - */ - dev_warn(d, "cp %p is reported invalid (probably means " - "target device no longer present)\n", cp); - /* print_bytes((unsigned char *) cp, sizeof(*cp), 1, 0); - print_cmd(cp); */ - } - break; - case CMD_PROTOCOL_ERR: - dev_warn(d, "cp %p has protocol error \n", cp); - break; - case CMD_HARDWARE_ERR: - /* cmd->result = DID_ERROR << 16; */ - dev_warn(d, "cp %p had hardware error\n", cp); - break; - case CMD_CONNECTION_LOST: - dev_warn(d, "cp %p had connection lost\n", cp); - break; - case CMD_ABORTED: - dev_warn(d, "cp %p was aborted\n", cp); - break; - case CMD_ABORT_FAILED: - dev_warn(d, "cp %p reports abort failed\n", cp); - break; - case CMD_UNSOLICITED_ABORT: - dev_warn(d, "cp %p aborted due to an unsolicited abort\n", cp); - break; - case CMD_TIMEOUT: - dev_warn(d, "cp %p timed out\n", cp); - break; - case CMD_UNABORTABLE: - dev_warn(d, "Command unabortable\n"); - break; - default: - dev_warn(d, "cp %p returned unknown status %x\n", cp, - ei->CommandStatus); - } -} - -static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr, - unsigned char page, unsigned char *buf, - unsigned char bufsize) -{ - int rc = IO_OK; - struct CommandList *c; - struct ErrorInfo *ei; - - c = cmd_special_alloc(h); - - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); - return -ENOMEM; - } - - fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize, page, scsi3addr, TYPE_CMD); - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); - ei = c->err_info; - if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { - hpsa_scsi_interpret_error(c); - rc = -1; - } - cmd_special_free(h, c); - return rc; -} - -static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr) -{ - int rc = IO_OK; - struct CommandList *c; - struct ErrorInfo *ei; - - c = cmd_special_alloc(h); - - if (c == NULL) { /* trouble... */ - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); - return -ENOMEM; - } - - fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG); - hpsa_scsi_do_simple_cmd_core(h, c); - /* no unmap needed here because no data xfer. */ - - ei = c->err_info; - if (ei->CommandStatus != 0) { - hpsa_scsi_interpret_error(c); - rc = -1; - } - cmd_special_free(h, c); - return rc; -} - -static void hpsa_get_raid_level(struct ctlr_info *h, - unsigned char *scsi3addr, unsigned char *raid_level) -{ - int rc; - unsigned char *buf; - - *raid_level = RAID_UNKNOWN; - buf = kzalloc(64, GFP_KERNEL); - if (!buf) - return; - rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0xC1, buf, 64); - if (rc == 0) - *raid_level = buf[8]; - if (*raid_level > RAID_UNKNOWN) - *raid_level = RAID_UNKNOWN; - kfree(buf); - return; -} - -/* Get the device id from inquiry page 0x83 */ -static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr, - unsigned char *device_id, int buflen) -{ - int rc; - unsigned char *buf; - - if (buflen > 16) - buflen = 16; - buf = kzalloc(64, GFP_KERNEL); - if (!buf) - return -1; - rc = hpsa_scsi_do_inquiry(h, scsi3addr, 0x83, buf, 64); - if (rc == 0) - memcpy(device_id, &buf[8], buflen); - kfree(buf); - return rc != 0; -} - -static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical, - struct ReportLUNdata *buf, int bufsize, - int extended_response) -{ - int rc = IO_OK; - struct CommandList *c; - unsigned char scsi3addr[8]; - struct ErrorInfo *ei; - - c = cmd_special_alloc(h); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); - return -1; - } - /* address the controller */ - memset(scsi3addr, 0, sizeof(scsi3addr)); - fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h, - buf, bufsize, 0, scsi3addr, TYPE_CMD); - if (extended_response) - c->Request.CDB[1] = extended_response; - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE); - ei = c->err_info; - if (ei->CommandStatus != 0 && - ei->CommandStatus != CMD_DATA_UNDERRUN) { - hpsa_scsi_interpret_error(c); - rc = -1; - } - cmd_special_free(h, c); - return rc; -} - -static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, - struct ReportLUNdata *buf, - int bufsize, int extended_response) -{ - return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, extended_response); -} - -static inline int hpsa_scsi_do_report_log_luns(struct ctlr_info *h, - struct ReportLUNdata *buf, int bufsize) -{ - return hpsa_scsi_do_report_luns(h, 1, buf, bufsize, 0); -} - -static inline void hpsa_set_bus_target_lun(struct hpsa_scsi_dev_t *device, - int bus, int target, int lun) -{ - device->bus = bus; - device->target = target; - device->lun = lun; -} - -static int hpsa_update_device_info(struct ctlr_info *h, - unsigned char scsi3addr[], struct hpsa_scsi_dev_t *this_device, - unsigned char *is_OBDR_device) -{ - -#define OBDR_SIG_OFFSET 43 -#define OBDR_TAPE_SIG "$DR-10" -#define OBDR_SIG_LEN (sizeof(OBDR_TAPE_SIG) - 1) -#define OBDR_TAPE_INQ_SIZE (OBDR_SIG_OFFSET + OBDR_SIG_LEN) - - unsigned char *inq_buff; - unsigned char *obdr_sig; - - inq_buff = kzalloc(OBDR_TAPE_INQ_SIZE, GFP_KERNEL); - if (!inq_buff) - goto bail_out; - - /* Do an inquiry to the device to see what it is. */ - if (hpsa_scsi_do_inquiry(h, scsi3addr, 0, inq_buff, - (unsigned char) OBDR_TAPE_INQ_SIZE) != 0) { - /* Inquiry failed (msg printed already) */ - dev_err(&h->pdev->dev, - "hpsa_update_device_info: inquiry failed\n"); - goto bail_out; - } - - this_device->devtype = (inq_buff[0] & 0x1f); - memcpy(this_device->scsi3addr, scsi3addr, 8); - memcpy(this_device->vendor, &inq_buff[8], - sizeof(this_device->vendor)); - memcpy(this_device->model, &inq_buff[16], - sizeof(this_device->model)); - memset(this_device->device_id, 0, - sizeof(this_device->device_id)); - hpsa_get_device_id(h, scsi3addr, this_device->device_id, - sizeof(this_device->device_id)); - - if (this_device->devtype == TYPE_DISK && - is_logical_dev_addr_mode(scsi3addr)) - hpsa_get_raid_level(h, scsi3addr, &this_device->raid_level); - else - this_device->raid_level = RAID_UNKNOWN; - - if (is_OBDR_device) { - /* See if this is a One-Button-Disaster-Recovery device - * by looking for "$DR-10" at offset 43 in inquiry data. - */ - obdr_sig = &inq_buff[OBDR_SIG_OFFSET]; - *is_OBDR_device = (this_device->devtype == TYPE_ROM && - strncmp(obdr_sig, OBDR_TAPE_SIG, - OBDR_SIG_LEN) == 0); - } - - kfree(inq_buff); - return 0; - -bail_out: - kfree(inq_buff); - return 1; -} - -static unsigned char *ext_target_model[] = { - "MSA2012", - "MSA2024", - "MSA2312", - "MSA2324", - "P2000 G3 SAS", - NULL, -}; - -static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) -{ - int i; - - for (i = 0; ext_target_model[i]; i++) - if (strncmp(device->model, ext_target_model[i], - strlen(ext_target_model[i])) == 0) - return 1; - return 0; -} - -/* Helper function to assign bus, target, lun mapping of devices. - * Puts non-external target logical volumes on bus 0, external target logical - * volumes on bus 1, physical devices on bus 2. and the hba on bus 3. - * Logical drive target and lun are assigned at this time, but - * physical device lun and target assignment are deferred (assigned - * in hpsa_find_target_lun, called by hpsa_scsi_add_entry.) - */ -static void figure_bus_target_lun(struct ctlr_info *h, - u8 *lunaddrbytes, struct hpsa_scsi_dev_t *device) -{ - u32 lunid = le32_to_cpu(*((__le32 *) lunaddrbytes)); - - if (!is_logical_dev_addr_mode(lunaddrbytes)) { - /* physical device, target and lun filled in later */ - if (is_hba_lunid(lunaddrbytes)) - hpsa_set_bus_target_lun(device, 3, 0, lunid & 0x3fff); - else - /* defer target, lun assignment for physical devices */ - hpsa_set_bus_target_lun(device, 2, -1, -1); - return; - } - /* It's a logical device */ - if (is_ext_target(h, device)) { - /* external target way, put logicals on bus 1 - * and match target/lun numbers box - * reports, other smart array, bus 0, target 0, match lunid - */ - hpsa_set_bus_target_lun(device, - 1, (lunid >> 16) & 0x3fff, lunid & 0x00ff); - return; - } - hpsa_set_bus_target_lun(device, 0, 0, lunid & 0x3fff); -} - -/* - * If there is no lun 0 on a target, linux won't find any devices. - * For the external targets (arrays), we have to manually detect the enclosure - * which is at lun zero, as CCISS_REPORT_PHYSICAL_LUNS doesn't report - * it for some reason. *tmpdevice is the target we're adding, - * this_device is a pointer into the current element of currentsd[] - * that we're building up in update_scsi_devices(), below. - * lunzerobits is a bitmap that tracks which targets already have a - * lun 0 assigned. - * Returns 1 if an enclosure was added, 0 if not. - */ -static int add_ext_target_dev(struct ctlr_info *h, - struct hpsa_scsi_dev_t *tmpdevice, - struct hpsa_scsi_dev_t *this_device, u8 *lunaddrbytes, - unsigned long lunzerobits[], int *n_ext_target_devs) -{ - unsigned char scsi3addr[8]; - - if (test_bit(tmpdevice->target, lunzerobits)) - return 0; /* There is already a lun 0 on this target. */ - - if (!is_logical_dev_addr_mode(lunaddrbytes)) - return 0; /* It's the logical targets that may lack lun 0. */ - - if (!is_ext_target(h, tmpdevice)) - return 0; /* Only external target devices have this problem. */ - - if (tmpdevice->lun == 0) /* if lun is 0, then we have a lun 0. */ - return 0; - - memset(scsi3addr, 0, 8); - scsi3addr[3] = tmpdevice->target; - if (is_hba_lunid(scsi3addr)) - return 0; /* Don't add the RAID controller here. */ - - if (is_scsi_rev_5(h)) - return 0; /* p1210m doesn't need to do this. */ - - if (*n_ext_target_devs >= MAX_EXT_TARGETS) { - dev_warn(&h->pdev->dev, "Maximum number of external " - "target devices exceeded. Check your hardware " - "configuration."); - return 0; - } - - if (hpsa_update_device_info(h, scsi3addr, this_device, NULL)) - return 0; - (*n_ext_target_devs)++; - hpsa_set_bus_target_lun(this_device, - tmpdevice->bus, tmpdevice->target, 0); - set_bit(tmpdevice->target, lunzerobits); - return 1; -} - -/* - * Do CISS_REPORT_PHYS and CISS_REPORT_LOG. Data is returned in physdev, - * logdev. The number of luns in physdev and logdev are returned in - * *nphysicals and *nlogicals, respectively. - * Returns 0 on success, -1 otherwise. - */ -static int hpsa_gather_lun_info(struct ctlr_info *h, - int reportlunsize, - struct ReportLUNdata *physdev, u32 *nphysicals, - struct ReportLUNdata *logdev, u32 *nlogicals) -{ - if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize, 0)) { - dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); - return -1; - } - *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 8; - if (*nphysicals > HPSA_MAX_PHYS_LUN) { - dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded." - " %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN, - *nphysicals - HPSA_MAX_PHYS_LUN); - *nphysicals = HPSA_MAX_PHYS_LUN; - } - if (hpsa_scsi_do_report_log_luns(h, logdev, reportlunsize)) { - dev_err(&h->pdev->dev, "report logical LUNs failed.\n"); - return -1; - } - *nlogicals = be32_to_cpu(*((__be32 *) logdev->LUNListLength)) / 8; - /* Reject Logicals in excess of our max capability. */ - if (*nlogicals > HPSA_MAX_LUN) { - dev_warn(&h->pdev->dev, - "maximum logical LUNs (%d) exceeded. " - "%d LUNs ignored.\n", HPSA_MAX_LUN, - *nlogicals - HPSA_MAX_LUN); - *nlogicals = HPSA_MAX_LUN; - } - if (*nlogicals + *nphysicals > HPSA_MAX_PHYS_LUN) { - dev_warn(&h->pdev->dev, - "maximum logical + physical LUNs (%d) exceeded. " - "%d LUNs ignored.\n", HPSA_MAX_PHYS_LUN, - *nphysicals + *nlogicals - HPSA_MAX_PHYS_LUN); - *nlogicals = HPSA_MAX_PHYS_LUN - *nphysicals; - } - return 0; -} - -u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i, - int nphysicals, int nlogicals, struct ReportLUNdata *physdev_list, - struct ReportLUNdata *logdev_list) -{ - /* Helper function, figure out where the LUN ID info is coming from - * given index i, lists of physical and logical devices, where in - * the list the raid controller is supposed to appear (first or last) - */ - - int logicals_start = nphysicals + (raid_ctlr_position == 0); - int last_device = nphysicals + nlogicals + (raid_ctlr_position == 0); - - if (i == raid_ctlr_position) - return RAID_CTLR_LUNID; - - if (i < logicals_start) - return &physdev_list->LUN[i - (raid_ctlr_position == 0)][0]; - - if (i < last_device) - return &logdev_list->LUN[i - nphysicals - - (raid_ctlr_position == 0)][0]; - BUG(); - return NULL; -} - -static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) -{ - /* the idea here is we could get notified - * that some devices have changed, so we do a report - * physical luns and report logical luns cmd, and adjust - * our list of devices accordingly. - * - * The scsi3addr's of devices won't change so long as the - * adapter is not reset. That means we can rescan and - * tell which devices we already know about, vs. new - * devices, vs. disappearing devices. - */ - struct ReportLUNdata *physdev_list = NULL; - struct ReportLUNdata *logdev_list = NULL; - u32 nphysicals = 0; - u32 nlogicals = 0; - u32 ndev_allocated = 0; - struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice; - int ncurrent = 0; - int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 8; - int i, n_ext_target_devs, ndevs_to_allocate; - int raid_ctlr_position; - DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); - - currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL); - physdev_list = kzalloc(reportlunsize, GFP_KERNEL); - logdev_list = kzalloc(reportlunsize, GFP_KERNEL); - tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL); - - if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) { - dev_err(&h->pdev->dev, "out of memory\n"); - goto out; - } - memset(lunzerobits, 0, sizeof(lunzerobits)); - - if (hpsa_gather_lun_info(h, reportlunsize, physdev_list, &nphysicals, - logdev_list, &nlogicals)) - goto out; - - /* We might see up to the maximum number of logical and physical disks - * plus external target devices, and a device for the local RAID - * controller. - */ - ndevs_to_allocate = nphysicals + nlogicals + MAX_EXT_TARGETS + 1; - - /* Allocate the per device structures */ - for (i = 0; i < ndevs_to_allocate; i++) { - if (i >= HPSA_MAX_DEVICES) { - dev_warn(&h->pdev->dev, "maximum devices (%d) exceeded." - " %d devices ignored.\n", HPSA_MAX_DEVICES, - ndevs_to_allocate - HPSA_MAX_DEVICES); - break; - } - - currentsd[i] = kzalloc(sizeof(*currentsd[i]), GFP_KERNEL); - if (!currentsd[i]) { - dev_warn(&h->pdev->dev, "out of memory at %s:%d\n", - __FILE__, __LINE__); - goto out; - } - ndev_allocated++; - } - - if (unlikely(is_scsi_rev_5(h))) - raid_ctlr_position = 0; - else - raid_ctlr_position = nphysicals + nlogicals; - - /* adjust our table of devices */ - n_ext_target_devs = 0; - for (i = 0; i < nphysicals + nlogicals + 1; i++) { - u8 *lunaddrbytes, is_OBDR = 0; - - /* Figure out where the LUN ID info is coming from */ - lunaddrbytes = figure_lunaddrbytes(h, raid_ctlr_position, - i, nphysicals, nlogicals, physdev_list, logdev_list); - /* skip masked physical devices. */ - if (lunaddrbytes[3] & 0xC0 && - i < nphysicals + (raid_ctlr_position == 0)) - continue; - - /* Get device type, vendor, model, device id */ - if (hpsa_update_device_info(h, lunaddrbytes, tmpdevice, - &is_OBDR)) - continue; /* skip it if we can't talk to it. */ - figure_bus_target_lun(h, lunaddrbytes, tmpdevice); - this_device = currentsd[ncurrent]; - - /* - * For external target devices, we have to insert a LUN 0 which - * doesn't show up in CCISS_REPORT_PHYSICAL data, but there - * is nonetheless an enclosure device there. We have to - * present that otherwise linux won't find anything if - * there is no lun 0. - */ - if (add_ext_target_dev(h, tmpdevice, this_device, - lunaddrbytes, lunzerobits, - &n_ext_target_devs)) { - ncurrent++; - this_device = currentsd[ncurrent]; - } - - *this_device = *tmpdevice; - - switch (this_device->devtype) { - case TYPE_ROM: - /* We don't *really* support actual CD-ROM devices, - * just "One Button Disaster Recovery" tape drive - * which temporarily pretends to be a CD-ROM drive. - * So we check that the device is really an OBDR tape - * device by checking for "$DR-10" in bytes 43-48 of - * the inquiry data. - */ - if (is_OBDR) - ncurrent++; - break; - case TYPE_DISK: - if (i < nphysicals) - break; - ncurrent++; - break; - case TYPE_TAPE: - case TYPE_MEDIUM_CHANGER: - ncurrent++; - break; - case TYPE_RAID: - /* Only present the Smartarray HBA as a RAID controller. - * If it's a RAID controller other than the HBA itself - * (an external RAID controller, MSA500 or similar) - * don't present it. - */ - if (!is_hba_lunid(lunaddrbytes)) - break; - ncurrent++; - break; - default: - break; - } - if (ncurrent >= HPSA_MAX_DEVICES) - break; - } - adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); -out: - kfree(tmpdevice); - for (i = 0; i < ndev_allocated; i++) - kfree(currentsd[i]); - kfree(currentsd); - kfree(physdev_list); - kfree(logdev_list); -} - -/* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci - * dma mapping and fills in the scatter gather entries of the - * hpsa command, cp. - */ -static int hpsa_scatter_gather(struct ctlr_info *h, - struct CommandList *cp, - struct scsi_cmnd *cmd) -{ - unsigned int len; - struct scatterlist *sg; - u64 addr64; - int use_sg, i, sg_index, chained; - struct SGDescriptor *curr_sg; - - BUG_ON(scsi_sg_count(cmd) > h->maxsgentries); - - use_sg = scsi_dma_map(cmd); - if (use_sg < 0) - return use_sg; - - if (!use_sg) - goto sglist_finished; - - curr_sg = cp->SG; - chained = 0; - sg_index = 0; - scsi_for_each_sg(cmd, sg, use_sg, i) { - if (i == h->max_cmd_sg_entries - 1 && - use_sg > h->max_cmd_sg_entries) { - chained = 1; - curr_sg = h->cmd_sg_list[cp->cmdindex]; - sg_index = 0; - } - addr64 = (u64) sg_dma_address(sg); - len = sg_dma_len(sg); - curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL); - curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL); - curr_sg->Len = len; - curr_sg->Ext = 0; /* we are not chaining */ - curr_sg++; - } - - if (use_sg + chained > h->maxSG) - h->maxSG = use_sg + chained; - - if (chained) { - cp->Header.SGList = h->max_cmd_sg_entries; - cp->Header.SGTotal = (u16) (use_sg + 1); - hpsa_map_sg_chain_block(h, cp); - return 0; - } - -sglist_finished: - - cp->Header.SGList = (u8) use_sg; /* no. SGs contig in this cmd */ - cp->Header.SGTotal = (u16) use_sg; /* total sgs in this cmd list */ - return 0; -} - - -static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - struct ctlr_info *h; - struct hpsa_scsi_dev_t *dev; - unsigned char scsi3addr[8]; - struct CommandList *c; - unsigned long flags; - - /* Get the ptr to our adapter structure out of cmd->host. */ - h = sdev_to_hba(cmd->device); - dev = cmd->device->hostdata; - if (!dev) { - cmd->result = DID_NO_CONNECT << 16; - done(cmd); - return 0; - } - memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr)); - - spin_lock_irqsave(&h->lock, flags); - if (unlikely(h->lockup_detected)) { - spin_unlock_irqrestore(&h->lock, flags); - cmd->result = DID_ERROR << 16; - done(cmd); - return 0; - } - /* Need a lock as this is being allocated from the pool */ - c = cmd_alloc(h); - spin_unlock_irqrestore(&h->lock, flags); - if (c == NULL) { /* trouble... */ - dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - - /* Fill in the command list header */ - - cmd->scsi_done = done; /* save this for use by completion code */ - - /* save c in case we have to abort it */ - cmd->host_scribble = (unsigned char *) c; - - c->cmd_type = CMD_SCSI; - c->scsi_cmd = cmd; - c->Header.ReplyQueue = 0; /* unused in simple mode */ - memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8); - c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT); - c->Header.Tag.lower |= DIRECT_LOOKUP_BIT; - - /* Fill in the request block... */ - - c->Request.Timeout = 0; - memset(c->Request.CDB, 0, sizeof(c->Request.CDB)); - BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB)); - c->Request.CDBLen = cmd->cmd_len; - memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len); - c->Request.Type.Type = TYPE_CMD; - c->Request.Type.Attribute = ATTR_SIMPLE; - switch (cmd->sc_data_direction) { - case DMA_TO_DEVICE: - c->Request.Type.Direction = XFER_WRITE; - break; - case DMA_FROM_DEVICE: - c->Request.Type.Direction = XFER_READ; - break; - case DMA_NONE: - c->Request.Type.Direction = XFER_NONE; - break; - case DMA_BIDIRECTIONAL: - /* This can happen if a buggy application does a scsi passthru - * and sets both inlen and outlen to non-zero. ( see - * ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() ) - */ - - c->Request.Type.Direction = XFER_RSVD; - /* This is technically wrong, and hpsa controllers should - * reject it with CMD_INVALID, which is the most correct - * response, but non-fibre backends appear to let it - * slide by, and give the same results as if this field - * were set correctly. Either way is acceptable for - * our purposes here. - */ - - break; - - default: - dev_err(&h->pdev->dev, "unknown data direction: %d\n", - cmd->sc_data_direction); - BUG(); - break; - } - - if (hpsa_scatter_gather(h, c, cmd) < 0) { /* Fill SG list */ - cmd_free(h, c); - return SCSI_MLQUEUE_HOST_BUSY; - } - enqueue_cmd_and_start_io(h, c); - /* the cmd'll come back via intr handler in complete_scsi_command() */ - return 0; -} - -static DEF_SCSI_QCMD(hpsa_scsi_queue_command) - -static void hpsa_scan_start(struct Scsi_Host *sh) -{ - struct ctlr_info *h = shost_to_hba(sh); - unsigned long flags; - - /* wait until any scan already in progress is finished. */ - while (1) { - spin_lock_irqsave(&h->scan_lock, flags); - if (h->scan_finished) - break; - spin_unlock_irqrestore(&h->scan_lock, flags); - wait_event(h->scan_wait_queue, h->scan_finished); - /* Note: We don't need to worry about a race between this - * thread and driver unload because the midlayer will - * have incremented the reference count, so unload won't - * happen if we're in here. - */ - } - h->scan_finished = 0; /* mark scan as in progress */ - spin_unlock_irqrestore(&h->scan_lock, flags); - - hpsa_update_scsi_devices(h, h->scsi_host->host_no); - - spin_lock_irqsave(&h->scan_lock, flags); - h->scan_finished = 1; /* mark scan as finished. */ - wake_up_all(&h->scan_wait_queue); - spin_unlock_irqrestore(&h->scan_lock, flags); -} - -static int hpsa_scan_finished(struct Scsi_Host *sh, - unsigned long elapsed_time) -{ - struct ctlr_info *h = shost_to_hba(sh); - unsigned long flags; - int finished; - - spin_lock_irqsave(&h->scan_lock, flags); - finished = h->scan_finished; - spin_unlock_irqrestore(&h->scan_lock, flags); - return finished; -} - -static int hpsa_change_queue_depth(struct scsi_device *sdev, - int qdepth, int reason) -{ - struct ctlr_info *h = sdev_to_hba(sdev); - - if (reason != SCSI_QDEPTH_DEFAULT) - return -ENOTSUPP; - - if (qdepth < 1) - qdepth = 1; - else - if (qdepth > h->nr_cmds) - qdepth = h->nr_cmds; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); - return sdev->queue_depth; -} - -static void hpsa_unregister_scsi(struct ctlr_info *h) -{ - /* we are being forcibly unloaded, and may not refuse. */ - scsi_remove_host(h->scsi_host); - scsi_host_put(h->scsi_host); - h->scsi_host = NULL; -} - -static int hpsa_register_scsi(struct ctlr_info *h) -{ - struct Scsi_Host *sh; - int error; - - sh = scsi_host_alloc(&hpsa_driver_template, sizeof(h)); - if (sh == NULL) - goto fail; - - sh->io_port = 0; - sh->n_io_port = 0; - sh->this_id = -1; - sh->max_channel = 3; - sh->max_cmd_len = MAX_COMMAND_SIZE; - sh->max_lun = HPSA_MAX_LUN; - sh->max_id = HPSA_MAX_LUN; - sh->can_queue = h->nr_cmds; - sh->cmd_per_lun = h->nr_cmds; - sh->sg_tablesize = h->maxsgentries; - h->scsi_host = sh; - sh->hostdata[0] = (unsigned long) h; - sh->irq = h->intr[h->intr_mode]; - sh->unique_id = sh->irq; - error = scsi_add_host(sh, &h->pdev->dev); - if (error) - goto fail_host_put; - scsi_scan_host(sh); - return 0; - - fail_host_put: - dev_err(&h->pdev->dev, "%s: scsi_add_host" - " failed for controller %d\n", __func__, h->ctlr); - scsi_host_put(sh); - return error; - fail: - dev_err(&h->pdev->dev, "%s: scsi_host_alloc" - " failed for controller %d\n", __func__, h->ctlr); - return -ENOMEM; -} - -static int wait_for_device_to_become_ready(struct ctlr_info *h, - unsigned char lunaddr[]) -{ - int rc = 0; - int count = 0; - int waittime = 1; /* seconds */ - struct CommandList *c; - - c = cmd_special_alloc(h); - if (!c) { - dev_warn(&h->pdev->dev, "out of memory in " - "wait_for_device_to_become_ready.\n"); - return IO_ERROR; - } - - /* Send test unit ready until device ready, or give up. */ - while (count < HPSA_TUR_RETRY_LIMIT) { - - /* Wait for a bit. do this first, because if we send - * the TUR right away, the reset will just abort it. - */ - msleep(1000 * waittime); - count++; - - /* Increase wait time with each try, up to a point. */ - if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS) - waittime = waittime * 2; - - /* Send the Test Unit Ready */ - fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, lunaddr, TYPE_CMD); - hpsa_scsi_do_simple_cmd_core(h, c); - /* no unmap needed here because no data xfer. */ - - if (c->err_info->CommandStatus == CMD_SUCCESS) - break; - - if (c->err_info->CommandStatus == CMD_TARGET_STATUS && - c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION && - (c->err_info->SenseInfo[2] == NO_SENSE || - c->err_info->SenseInfo[2] == UNIT_ATTENTION)) - break; - - dev_warn(&h->pdev->dev, "waiting %d secs " - "for device to become ready.\n", waittime); - rc = 1; /* device not ready. */ - } - - if (rc) - dev_warn(&h->pdev->dev, "giving up on device.\n"); - else - dev_warn(&h->pdev->dev, "device is ready.\n"); - - cmd_special_free(h, c); - return rc; -} - -/* Need at least one of these error handlers to keep ../scsi/hosts.c from - * complaining. Doing a host- or bus-reset can't do anything good here. - */ -static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd) -{ - int rc; - struct ctlr_info *h; - struct hpsa_scsi_dev_t *dev; - - /* find the controller to which the command to be aborted was sent */ - h = sdev_to_hba(scsicmd->device); - if (h == NULL) /* paranoia */ - return FAILED; - dev = scsicmd->device->hostdata; - if (!dev) { - dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: " - "device lookup failed.\n"); - return FAILED; - } - dev_warn(&h->pdev->dev, "resetting device %d:%d:%d:%d\n", - h->scsi_host->host_no, dev->bus, dev->target, dev->lun); - /* send a reset to the SCSI LUN which the command was sent to */ - rc = hpsa_send_reset(h, dev->scsi3addr); - if (rc == 0 && wait_for_device_to_become_ready(h, dev->scsi3addr) == 0) - return SUCCESS; - - dev_warn(&h->pdev->dev, "resetting device failed.\n"); - return FAILED; -} - -/* - * For operations that cannot sleep, a command block is allocated at init, - * and managed by cmd_alloc() and cmd_free() using a simple bitmap to track - * which ones are free or in use. Lock must be held when calling this. - * cmd_free() is the complement. - */ -static struct CommandList *cmd_alloc(struct ctlr_info *h) -{ - struct CommandList *c; - int i; - union u64bit temp64; - dma_addr_t cmd_dma_handle, err_dma_handle; - - do { - i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds); - if (i == h->nr_cmds) - return NULL; - } while (test_and_set_bit - (i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0); - c = h->cmd_pool + i; - memset(c, 0, sizeof(*c)); - cmd_dma_handle = h->cmd_pool_dhandle - + i * sizeof(*c); - c->err_info = h->errinfo_pool + i; - memset(c->err_info, 0, sizeof(*c->err_info)); - err_dma_handle = h->errinfo_pool_dhandle - + i * sizeof(*c->err_info); - h->nr_allocs++; - - c->cmdindex = i; - - INIT_LIST_HEAD(&c->list); - c->busaddr = (u32) cmd_dma_handle; - temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr.lower = temp64.val32.lower; - c->ErrDesc.Addr.upper = temp64.val32.upper; - c->ErrDesc.Len = sizeof(*c->err_info); - - c->h = h; - return c; -} - -/* For operations that can wait for kmalloc to possibly sleep, - * this routine can be called. Lock need not be held to call - * cmd_special_alloc. cmd_special_free() is the complement. - */ -static struct CommandList *cmd_special_alloc(struct ctlr_info *h) -{ - struct CommandList *c; - union u64bit temp64; - dma_addr_t cmd_dma_handle, err_dma_handle; - - c = pci_alloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle); - if (c == NULL) - return NULL; - memset(c, 0, sizeof(*c)); - - c->cmdindex = -1; - - c->err_info = pci_alloc_consistent(h->pdev, sizeof(*c->err_info), - &err_dma_handle); - - if (c->err_info == NULL) { - pci_free_consistent(h->pdev, - sizeof(*c), c, cmd_dma_handle); - return NULL; - } - memset(c->err_info, 0, sizeof(*c->err_info)); - - INIT_LIST_HEAD(&c->list); - c->busaddr = (u32) cmd_dma_handle; - temp64.val = (u64) err_dma_handle; - c->ErrDesc.Addr.lower = temp64.val32.lower; - c->ErrDesc.Addr.upper = temp64.val32.upper; - c->ErrDesc.Len = sizeof(*c->err_info); - - c->h = h; - return c; -} - -static void cmd_free(struct ctlr_info *h, struct CommandList *c) -{ - int i; - - i = c - h->cmd_pool; - clear_bit(i & (BITS_PER_LONG - 1), - h->cmd_pool_bits + (i / BITS_PER_LONG)); - h->nr_frees++; -} - -static void cmd_special_free(struct ctlr_info *h, struct CommandList *c) -{ - union u64bit temp64; - - temp64.val32.lower = c->ErrDesc.Addr.lower; - temp64.val32.upper = c->ErrDesc.Addr.upper; - pci_free_consistent(h->pdev, sizeof(*c->err_info), - c->err_info, (dma_addr_t) temp64.val); - pci_free_consistent(h->pdev, sizeof(*c), - c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK)); -} - -#ifdef CONFIG_COMPAT - -static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg) -{ - IOCTL32_Command_struct __user *arg32 = - (IOCTL32_Command_struct __user *) arg; - IOCTL_Command_struct arg64; - IOCTL_Command_struct __user *p = compat_alloc_user_space(sizeof(arg64)); - int err; - u32 cp; - - memset(&arg64, 0, sizeof(arg64)); - err = 0; - err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, - sizeof(arg64.LUN_info)); - err |= copy_from_user(&arg64.Request, &arg32->Request, - sizeof(arg64.Request)); - err |= copy_from_user(&arg64.error_info, &arg32->error_info, - sizeof(arg64.error_info)); - err |= get_user(arg64.buf_size, &arg32->buf_size); - err |= get_user(cp, &arg32->buf); - arg64.buf = compat_ptr(cp); - err |= copy_to_user(p, &arg64, sizeof(arg64)); - - if (err) - return -EFAULT; - - err = hpsa_ioctl(dev, CCISS_PASSTHRU, (void *)p); - if (err) - return err; - err |= copy_in_user(&arg32->error_info, &p->error_info, - sizeof(arg32->error_info)); - if (err) - return -EFAULT; - return err; -} - -static int hpsa_ioctl32_big_passthru(struct scsi_device *dev, - int cmd, void *arg) -{ - BIG_IOCTL32_Command_struct __user *arg32 = - (BIG_IOCTL32_Command_struct __user *) arg; - BIG_IOCTL_Command_struct arg64; - BIG_IOCTL_Command_struct __user *p = - compat_alloc_user_space(sizeof(arg64)); - int err; - u32 cp; - - memset(&arg64, 0, sizeof(arg64)); - err = 0; - err |= copy_from_user(&arg64.LUN_info, &arg32->LUN_info, - sizeof(arg64.LUN_info)); - err |= copy_from_user(&arg64.Request, &arg32->Request, - sizeof(arg64.Request)); - err |= copy_from_user(&arg64.error_info, &arg32->error_info, - sizeof(arg64.error_info)); - err |= get_user(arg64.buf_size, &arg32->buf_size); - err |= get_user(arg64.malloc_size, &arg32->malloc_size); - err |= get_user(cp, &arg32->buf); - arg64.buf = compat_ptr(cp); - err |= copy_to_user(p, &arg64, sizeof(arg64)); - - if (err) - return -EFAULT; - - err = hpsa_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p); - if (err) - return err; - err |= copy_in_user(&arg32->error_info, &p->error_info, - sizeof(arg32->error_info)); - if (err) - return -EFAULT; - return err; -} - -static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg) -{ - switch (cmd) { - case CCISS_GETPCIINFO: - case CCISS_GETINTINFO: - case CCISS_SETINTINFO: - case CCISS_GETNODENAME: - case CCISS_SETNODENAME: - case CCISS_GETHEARTBEAT: - case CCISS_GETBUSTYPES: - case CCISS_GETFIRMVER: - case CCISS_GETDRIVVER: - case CCISS_REVALIDVOLS: - case CCISS_DEREGDISK: - case CCISS_REGNEWDISK: - case CCISS_REGNEWD: - case CCISS_RESCANDISK: - case CCISS_GETLUNINFO: - return hpsa_ioctl(dev, cmd, arg); - - case CCISS_PASSTHRU32: - return hpsa_ioctl32_passthru(dev, cmd, arg); - case CCISS_BIG_PASSTHRU32: - return hpsa_ioctl32_big_passthru(dev, cmd, arg); - - default: - return -ENOIOCTLCMD; - } -} -#endif - -static int hpsa_getpciinfo_ioctl(struct ctlr_info *h, void __user *argp) -{ - struct hpsa_pci_info pciinfo; - - if (!argp) - return -EINVAL; - pciinfo.domain = pci_domain_nr(h->pdev->bus); - pciinfo.bus = h->pdev->bus->number; - pciinfo.dev_fn = h->pdev->devfn; - pciinfo.board_id = h->board_id; - if (copy_to_user(argp, &pciinfo, sizeof(pciinfo))) - return -EFAULT; - return 0; -} - -static int hpsa_getdrivver_ioctl(struct ctlr_info *h, void __user *argp) -{ - DriverVer_type DriverVer; - unsigned char vmaj, vmin, vsubmin; - int rc; - - rc = sscanf(HPSA_DRIVER_VERSION, "%hhu.%hhu.%hhu", - &vmaj, &vmin, &vsubmin); - if (rc != 3) { - dev_info(&h->pdev->dev, "driver version string '%s' " - "unrecognized.", HPSA_DRIVER_VERSION); - vmaj = 0; - vmin = 0; - vsubmin = 0; - } - DriverVer = (vmaj << 16) | (vmin << 8) | vsubmin; - if (!argp) - return -EINVAL; - if (copy_to_user(argp, &DriverVer, sizeof(DriverVer_type))) - return -EFAULT; - return 0; -} - -static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp) -{ - IOCTL_Command_struct iocommand; - struct CommandList *c; - char *buff = NULL; - union u64bit temp64; - - if (!argp) - return -EINVAL; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - if (copy_from_user(&iocommand, argp, sizeof(iocommand))) - return -EFAULT; - if ((iocommand.buf_size < 1) && - (iocommand.Request.Type.Direction != XFER_NONE)) { - return -EINVAL; - } - if (iocommand.buf_size > 0) { - buff = kmalloc(iocommand.buf_size, GFP_KERNEL); - if (buff == NULL) - return -EFAULT; - if (iocommand.Request.Type.Direction == XFER_WRITE) { - /* Copy the data into the buffer we created */ - if (copy_from_user(buff, iocommand.buf, - iocommand.buf_size)) { - kfree(buff); - return -EFAULT; - } - } else { - memset(buff, 0, iocommand.buf_size); - } - } - c = cmd_special_alloc(h); - if (c == NULL) { - kfree(buff); - return -ENOMEM; - } - /* Fill in the command type */ - c->cmd_type = CMD_IOCTL_PEND; - /* Fill in Command Header */ - c->Header.ReplyQueue = 0; /* unused in simple mode */ - if (iocommand.buf_size > 0) { /* buffer to fill */ - c->Header.SGList = 1; - c->Header.SGTotal = 1; - } else { /* no buffers to fill */ - c->Header.SGList = 0; - c->Header.SGTotal = 0; - } - memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN)); - /* use the kernel address the cmd block for tag */ - c->Header.Tag.lower = c->busaddr; - - /* Fill in Request block */ - memcpy(&c->Request, &iocommand.Request, - sizeof(c->Request)); - - /* Fill in the scatter gather information */ - if (iocommand.buf_size > 0) { - temp64.val = pci_map_single(h->pdev, buff, - iocommand.buf_size, PCI_DMA_BIDIRECTIONAL); - c->SG[0].Addr.lower = temp64.val32.lower; - c->SG[0].Addr.upper = temp64.val32.upper; - c->SG[0].Len = iocommand.buf_size; - c->SG[0].Ext = 0; /* we are not chaining*/ - } - hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); - if (iocommand.buf_size > 0) - hpsa_pci_unmap(h->pdev, c, 1, PCI_DMA_BIDIRECTIONAL); - check_ioctl_unit_attention(h, c); - - /* Copy the error information out */ - memcpy(&iocommand.error_info, c->err_info, - sizeof(iocommand.error_info)); - if (copy_to_user(argp, &iocommand, sizeof(iocommand))) { - kfree(buff); - cmd_special_free(h, c); - return -EFAULT; - } - if (iocommand.Request.Type.Direction == XFER_READ && - iocommand.buf_size > 0) { - /* Copy the data out of the buffer we created */ - if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) { - kfree(buff); - cmd_special_free(h, c); - return -EFAULT; - } - } - kfree(buff); - cmd_special_free(h, c); - return 0; -} - -static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp) -{ - BIG_IOCTL_Command_struct *ioc; - struct CommandList *c; - unsigned char **buff = NULL; - int *buff_size = NULL; - union u64bit temp64; - BYTE sg_used = 0; - int status = 0; - int i; - u32 left; - u32 sz; - BYTE __user *data_ptr; - - if (!argp) - return -EINVAL; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - ioc = (BIG_IOCTL_Command_struct *) - kmalloc(sizeof(*ioc), GFP_KERNEL); - if (!ioc) { - status = -ENOMEM; - goto cleanup1; - } - if (copy_from_user(ioc, argp, sizeof(*ioc))) { - status = -EFAULT; - goto cleanup1; - } - if ((ioc->buf_size < 1) && - (ioc->Request.Type.Direction != XFER_NONE)) { - status = -EINVAL; - goto cleanup1; - } - /* Check kmalloc limits using all SGs */ - if (ioc->malloc_size > MAX_KMALLOC_SIZE) { - status = -EINVAL; - goto cleanup1; - } - if (ioc->buf_size > ioc->malloc_size * SG_ENTRIES_IN_CMD) { - status = -EINVAL; - goto cleanup1; - } - buff = kzalloc(SG_ENTRIES_IN_CMD * sizeof(char *), GFP_KERNEL); - if (!buff) { - status = -ENOMEM; - goto cleanup1; - } - buff_size = kmalloc(SG_ENTRIES_IN_CMD * sizeof(int), GFP_KERNEL); - if (!buff_size) { - status = -ENOMEM; - goto cleanup1; - } - left = ioc->buf_size; - data_ptr = ioc->buf; - while (left) { - sz = (left > ioc->malloc_size) ? ioc->malloc_size : left; - buff_size[sg_used] = sz; - buff[sg_used] = kmalloc(sz, GFP_KERNEL); - if (buff[sg_used] == NULL) { - status = -ENOMEM; - goto cleanup1; - } - if (ioc->Request.Type.Direction == XFER_WRITE) { - if (copy_from_user(buff[sg_used], data_ptr, sz)) { - status = -ENOMEM; - goto cleanup1; - } - } else - memset(buff[sg_used], 0, sz); - left -= sz; - data_ptr += sz; - sg_used++; - } - c = cmd_special_alloc(h); - if (c == NULL) { - status = -ENOMEM; - goto cleanup1; - } - c->cmd_type = CMD_IOCTL_PEND; - c->Header.ReplyQueue = 0; - c->Header.SGList = c->Header.SGTotal = sg_used; - memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN)); - c->Header.Tag.lower = c->busaddr; - memcpy(&c->Request, &ioc->Request, sizeof(c->Request)); - if (ioc->buf_size > 0) { - int i; - for (i = 0; i < sg_used; i++) { - temp64.val = pci_map_single(h->pdev, buff[i], - buff_size[i], PCI_DMA_BIDIRECTIONAL); - c->SG[i].Addr.lower = temp64.val32.lower; - c->SG[i].Addr.upper = temp64.val32.upper; - c->SG[i].Len = buff_size[i]; - /* we are not chaining */ - c->SG[i].Ext = 0; - } - } - hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c); - if (sg_used) - hpsa_pci_unmap(h->pdev, c, sg_used, PCI_DMA_BIDIRECTIONAL); - check_ioctl_unit_attention(h, c); - /* Copy the error information out */ - memcpy(&ioc->error_info, c->err_info, sizeof(ioc->error_info)); - if (copy_to_user(argp, ioc, sizeof(*ioc))) { - cmd_special_free(h, c); - status = -EFAULT; - goto cleanup1; - } - if (ioc->Request.Type.Direction == XFER_READ && ioc->buf_size > 0) { - /* Copy the data out of the buffer we created */ - BYTE __user *ptr = ioc->buf; - for (i = 0; i < sg_used; i++) { - if (copy_to_user(ptr, buff[i], buff_size[i])) { - cmd_special_free(h, c); - status = -EFAULT; - goto cleanup1; - } - ptr += buff_size[i]; - } - } - cmd_special_free(h, c); - status = 0; -cleanup1: - if (buff) { - for (i = 0; i < sg_used; i++) - kfree(buff[i]); - kfree(buff); - } - kfree(buff_size); - kfree(ioc); - return status; -} - -static void check_ioctl_unit_attention(struct ctlr_info *h, - struct CommandList *c) -{ - if (c->err_info->CommandStatus == CMD_TARGET_STATUS && - c->err_info->ScsiStatus != SAM_STAT_CHECK_CONDITION) - (void) check_for_unit_attention(h, c); -} -/* - * ioctl - */ -static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg) -{ - struct ctlr_info *h; - void __user *argp = (void __user *)arg; - - h = sdev_to_hba(dev); - - switch (cmd) { - case CCISS_DEREGDISK: - case CCISS_REGNEWDISK: - case CCISS_REGNEWD: - hpsa_scan_start(h->scsi_host); - return 0; - case CCISS_GETPCIINFO: - return hpsa_getpciinfo_ioctl(h, argp); - case CCISS_GETDRIVVER: - return hpsa_getdrivver_ioctl(h, argp); - case CCISS_PASSTHRU: - return hpsa_passthru_ioctl(h, argp); - case CCISS_BIG_PASSTHRU: - return hpsa_big_passthru_ioctl(h, argp); - default: - return -ENOTTY; - } -} - -static int __devinit hpsa_send_host_reset(struct ctlr_info *h, - unsigned char *scsi3addr, u8 reset_type) -{ - struct CommandList *c; - - c = cmd_alloc(h); - if (!c) - return -ENOMEM; - fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, - RAID_CTLR_LUNID, TYPE_MSG); - c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */ - c->waiting = NULL; - enqueue_cmd_and_start_io(h, c); - /* Don't wait for completion, the reset won't complete. Don't free - * the command either. This is the last command we will send before - * re-initializing everything, so it doesn't matter and won't leak. - */ - return 0; -} - -static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, - void *buff, size_t size, u8 page_code, unsigned char *scsi3addr, - int cmd_type) -{ - int pci_dir = XFER_NONE; - - c->cmd_type = CMD_IOCTL_PEND; - c->Header.ReplyQueue = 0; - if (buff != NULL && size > 0) { - c->Header.SGList = 1; - c->Header.SGTotal = 1; - } else { - c->Header.SGList = 0; - c->Header.SGTotal = 0; - } - c->Header.Tag.lower = c->busaddr; - memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8); - - c->Request.Type.Type = cmd_type; - if (cmd_type == TYPE_CMD) { - switch (cmd) { - case HPSA_INQUIRY: - /* are we trying to read a vital product page */ - if (page_code != 0) { - c->Request.CDB[1] = 0x01; - c->Request.CDB[2] = page_code; - } - c->Request.CDBLen = 6; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; - c->Request.Timeout = 0; - c->Request.CDB[0] = HPSA_INQUIRY; - c->Request.CDB[4] = size & 0xFF; - break; - case HPSA_REPORT_LOG: - case HPSA_REPORT_PHYS: - /* Talking to controller so It's a physical command - mode = 00 target = 0. Nothing to write. - */ - c->Request.CDBLen = 12; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_READ; - c->Request.Timeout = 0; - c->Request.CDB[0] = cmd; - c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */ - c->Request.CDB[7] = (size >> 16) & 0xFF; - c->Request.CDB[8] = (size >> 8) & 0xFF; - c->Request.CDB[9] = size & 0xFF; - break; - case HPSA_CACHE_FLUSH: - c->Request.CDBLen = 12; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_WRITE; - c->Request.Timeout = 0; - c->Request.CDB[0] = BMIC_WRITE; - c->Request.CDB[6] = BMIC_CACHE_FLUSH; - c->Request.CDB[7] = (size >> 8) & 0xFF; - c->Request.CDB[8] = size & 0xFF; - break; - case TEST_UNIT_READY: - c->Request.CDBLen = 6; - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_NONE; - c->Request.Timeout = 0; - break; - default: - dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd); - BUG(); - return; - } - } else if (cmd_type == TYPE_MSG) { - switch (cmd) { - - case HPSA_DEVICE_RESET_MSG: - c->Request.CDBLen = 16; - c->Request.Type.Type = 1; /* It is a MSG not a CMD */ - c->Request.Type.Attribute = ATTR_SIMPLE; - c->Request.Type.Direction = XFER_NONE; - c->Request.Timeout = 0; /* Don't time out */ - memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB)); - c->Request.CDB[0] = cmd; - c->Request.CDB[1] = 0x03; /* Reset target above */ - /* If bytes 4-7 are zero, it means reset the */ - /* LunID device */ - c->Request.CDB[4] = 0x00; - c->Request.CDB[5] = 0x00; - c->Request.CDB[6] = 0x00; - c->Request.CDB[7] = 0x00; - break; - - default: - dev_warn(&h->pdev->dev, "unknown message type %d\n", - cmd); - BUG(); - } - } else { - dev_warn(&h->pdev->dev, "unknown command type %d\n", cmd_type); - BUG(); - } - - switch (c->Request.Type.Direction) { - case XFER_READ: - pci_dir = PCI_DMA_FROMDEVICE; - break; - case XFER_WRITE: - pci_dir = PCI_DMA_TODEVICE; - break; - case XFER_NONE: - pci_dir = PCI_DMA_NONE; - break; - default: - pci_dir = PCI_DMA_BIDIRECTIONAL; - } - - hpsa_map_one(h->pdev, c, buff, size, pci_dir); - - return; -} - -/* - * Map (physical) PCI mem into (virtual) kernel space - */ -static void __iomem *remap_pci_mem(ulong base, ulong size) -{ - ulong page_base = ((ulong) base) & PAGE_MASK; - ulong page_offs = ((ulong) base) - page_base; - void __iomem *page_remapped = ioremap(page_base, page_offs + size); - - return page_remapped ? (page_remapped + page_offs) : NULL; -} - -/* Takes cmds off the submission queue and sends them to the hardware, - * then puts them on the queue of cmds waiting for completion. - */ -static void start_io(struct ctlr_info *h) -{ - struct CommandList *c; - - while (!list_empty(&h->reqQ)) { - c = list_entry(h->reqQ.next, struct CommandList, list); - /* can't do anything if fifo is full */ - if ((h->access.fifo_full(h))) { - dev_warn(&h->pdev->dev, "fifo full\n"); - break; - } - - /* Get the first entry from the Request Q */ - removeQ(c); - h->Qdepth--; - - /* Tell the controller execute command */ - h->access.submit_command(h, c); - - /* Put job onto the completed Q */ - addQ(&h->cmpQ, c); - } -} - -static inline unsigned long get_next_completion(struct ctlr_info *h) -{ - return h->access.command_completed(h); -} - -static inline bool interrupt_pending(struct ctlr_info *h) -{ - return h->access.intr_pending(h); -} - -static inline long interrupt_not_for_us(struct ctlr_info *h) -{ - return (h->access.intr_pending(h) == 0) || - (h->interrupts_enabled == 0); -} - -static inline int bad_tag(struct ctlr_info *h, u32 tag_index, - u32 raw_tag) -{ - if (unlikely(tag_index >= h->nr_cmds)) { - dev_warn(&h->pdev->dev, "bad tag 0x%08x ignored.\n", raw_tag); - return 1; - } - return 0; -} - -static inline void finish_cmd(struct CommandList *c, u32 raw_tag) -{ - removeQ(c); - if (likely(c->cmd_type == CMD_SCSI)) - complete_scsi_command(c); - else if (c->cmd_type == CMD_IOCTL_PEND) - complete(c->waiting); -} - -static inline u32 hpsa_tag_contains_index(u32 tag) -{ - return tag & DIRECT_LOOKUP_BIT; -} - -static inline u32 hpsa_tag_to_index(u32 tag) -{ - return tag >> DIRECT_LOOKUP_SHIFT; -} - - -static inline u32 hpsa_tag_discard_error_bits(struct ctlr_info *h, u32 tag) -{ -#define HPSA_PERF_ERROR_BITS ((1 << DIRECT_LOOKUP_SHIFT) - 1) -#define HPSA_SIMPLE_ERROR_BITS 0x03 - if (unlikely(!(h->transMethod & CFGTBL_Trans_Performant))) - return tag & ~HPSA_SIMPLE_ERROR_BITS; - return tag & ~HPSA_PERF_ERROR_BITS; -} - -/* process completion of an indexed ("direct lookup") command */ -static inline u32 process_indexed_cmd(struct ctlr_info *h, - u32 raw_tag) -{ - u32 tag_index; - struct CommandList *c; - - tag_index = hpsa_tag_to_index(raw_tag); - if (bad_tag(h, tag_index, raw_tag)) - return next_command(h); - c = h->cmd_pool + tag_index; - finish_cmd(c, raw_tag); - return next_command(h); -} - -/* process completion of a non-indexed command */ -static inline u32 process_nonindexed_cmd(struct ctlr_info *h, - u32 raw_tag) -{ - u32 tag; - struct CommandList *c = NULL; - - tag = hpsa_tag_discard_error_bits(h, raw_tag); - list_for_each_entry(c, &h->cmpQ, list) { - if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) { - finish_cmd(c, raw_tag); - return next_command(h); - } - } - bad_tag(h, h->nr_cmds + 1, raw_tag); - return next_command(h); -} - -/* Some controllers, like p400, will give us one interrupt - * after a soft reset, even if we turned interrupts off. - * Only need to check for this in the hpsa_xxx_discard_completions - * functions. - */ -static int ignore_bogus_interrupt(struct ctlr_info *h) -{ - if (likely(!reset_devices)) - return 0; - - if (likely(h->interrupts_enabled)) - return 0; - - dev_info(&h->pdev->dev, "Received interrupt while interrupts disabled " - "(known firmware bug.) Ignoring.\n"); - - return 1; -} - -static irqreturn_t hpsa_intx_discard_completions(int irq, void *dev_id) -{ - struct ctlr_info *h = dev_id; - unsigned long flags; - u32 raw_tag; - - if (ignore_bogus_interrupt(h)) - return IRQ_NONE; - - if (interrupt_not_for_us(h)) - return IRQ_NONE; - spin_lock_irqsave(&h->lock, flags); - h->last_intr_timestamp = get_jiffies_64(); - while (interrupt_pending(h)) { - raw_tag = get_next_completion(h); - while (raw_tag != FIFO_EMPTY) - raw_tag = next_command(h); - } - spin_unlock_irqrestore(&h->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t hpsa_msix_discard_completions(int irq, void *dev_id) -{ - struct ctlr_info *h = dev_id; - unsigned long flags; - u32 raw_tag; - - if (ignore_bogus_interrupt(h)) - return IRQ_NONE; - - spin_lock_irqsave(&h->lock, flags); - h->last_intr_timestamp = get_jiffies_64(); - raw_tag = get_next_completion(h); - while (raw_tag != FIFO_EMPTY) - raw_tag = next_command(h); - spin_unlock_irqrestore(&h->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id) -{ - struct ctlr_info *h = dev_id; - unsigned long flags; - u32 raw_tag; - - if (interrupt_not_for_us(h)) - return IRQ_NONE; - spin_lock_irqsave(&h->lock, flags); - h->last_intr_timestamp = get_jiffies_64(); - while (interrupt_pending(h)) { - raw_tag = get_next_completion(h); - while (raw_tag != FIFO_EMPTY) { - if (hpsa_tag_contains_index(raw_tag)) - raw_tag = process_indexed_cmd(h, raw_tag); - else - raw_tag = process_nonindexed_cmd(h, raw_tag); - } - } - spin_unlock_irqrestore(&h->lock, flags); - return IRQ_HANDLED; -} - -static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id) -{ - struct ctlr_info *h = dev_id; - unsigned long flags; - u32 raw_tag; - - spin_lock_irqsave(&h->lock, flags); - h->last_intr_timestamp = get_jiffies_64(); - raw_tag = get_next_completion(h); - while (raw_tag != FIFO_EMPTY) { - if (hpsa_tag_contains_index(raw_tag)) - raw_tag = process_indexed_cmd(h, raw_tag); - else - raw_tag = process_nonindexed_cmd(h, raw_tag); - } - spin_unlock_irqrestore(&h->lock, flags); - return IRQ_HANDLED; -} - -/* Send a message CDB to the firmware. Careful, this only works - * in simple mode, not performant mode due to the tag lookup. - * We only ever use this immediately after a controller reset. - */ -static __devinit int hpsa_message(struct pci_dev *pdev, unsigned char opcode, - unsigned char type) -{ - struct Command { - struct CommandListHeader CommandHeader; - struct RequestBlock Request; - struct ErrDescriptor ErrorDescriptor; - }; - struct Command *cmd; - static const size_t cmd_sz = sizeof(*cmd) + - sizeof(cmd->ErrorDescriptor); - dma_addr_t paddr64; - uint32_t paddr32, tag; - void __iomem *vaddr; - int i, err; - - vaddr = pci_ioremap_bar(pdev, 0); - if (vaddr == NULL) - return -ENOMEM; - - /* The Inbound Post Queue only accepts 32-bit physical addresses for the - * CCISS commands, so they must be allocated from the lower 4GiB of - * memory. - */ - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) { - iounmap(vaddr); - return -ENOMEM; - } - - cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64); - if (cmd == NULL) { - iounmap(vaddr); - return -ENOMEM; - } - - /* This must fit, because of the 32-bit consistent DMA mask. Also, - * although there's no guarantee, we assume that the address is at - * least 4-byte aligned (most likely, it's page-aligned). - */ - paddr32 = paddr64; - - cmd->CommandHeader.ReplyQueue = 0; - cmd->CommandHeader.SGList = 0; - cmd->CommandHeader.SGTotal = 0; - cmd->CommandHeader.Tag.lower = paddr32; - cmd->CommandHeader.Tag.upper = 0; - memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8); - - cmd->Request.CDBLen = 16; - cmd->Request.Type.Type = TYPE_MSG; - cmd->Request.Type.Attribute = ATTR_HEADOFQUEUE; - cmd->Request.Type.Direction = XFER_NONE; - cmd->Request.Timeout = 0; /* Don't time out */ - cmd->Request.CDB[0] = opcode; - cmd->Request.CDB[1] = type; - memset(&cmd->Request.CDB[2], 0, 14); /* rest of the CDB is reserved */ - cmd->ErrorDescriptor.Addr.lower = paddr32 + sizeof(*cmd); - cmd->ErrorDescriptor.Addr.upper = 0; - cmd->ErrorDescriptor.Len = sizeof(struct ErrorInfo); - - writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET); - - for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) { - tag = readl(vaddr + SA5_REPLY_PORT_OFFSET); - if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr32) - break; - msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS); - } - - iounmap(vaddr); - - /* we leak the DMA buffer here ... no choice since the controller could - * still complete the command. - */ - if (i == HPSA_MSG_SEND_RETRY_LIMIT) { - dev_err(&pdev->dev, "controller message %02x:%02x timed out\n", - opcode, type); - return -ETIMEDOUT; - } - - pci_free_consistent(pdev, cmd_sz, cmd, paddr64); - - if (tag & HPSA_ERROR_BIT) { - dev_err(&pdev->dev, "controller message %02x:%02x failed\n", - opcode, type); - return -EIO; - } - - dev_info(&pdev->dev, "controller message %02x:%02x succeeded\n", - opcode, type); - return 0; -} - -#define hpsa_noop(p) hpsa_message(p, 3, 0) - -static int hpsa_controller_hard_reset(struct pci_dev *pdev, - void * __iomem vaddr, u32 use_doorbell) -{ - u16 pmcsr; - int pos; - - if (use_doorbell) { - /* For everything after the P600, the PCI power state method - * of resetting the controller doesn't work, so we have this - * other way using the doorbell register. - */ - dev_info(&pdev->dev, "using doorbell to reset controller\n"); - writel(use_doorbell, vaddr + SA5_DOORBELL); - } else { /* Try to do it the PCI power state way */ - - /* Quoting from the Open CISS Specification: "The Power - * Management Control/Status Register (CSR) controls the power - * state of the device. The normal operating state is D0, - * CSR=00h. The software off state is D3, CSR=03h. To reset - * the controller, place the interface device in D3 then to D0, - * this causes a secondary PCI reset which will reset the - * controller." */ - - pos = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pos == 0) { - dev_err(&pdev->dev, - "hpsa_reset_controller: " - "PCI PM not supported\n"); - return -ENODEV; - } - dev_info(&pdev->dev, "using PCI PM to reset controller\n"); - /* enter the D3hot power management state */ - pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr); - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= PCI_D3hot; - pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); - - msleep(500); - - /* enter the D0 power management state */ - pmcsr &= ~PCI_PM_CTRL_STATE_MASK; - pmcsr |= PCI_D0; - pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr); - - /* - * The P600 requires a small delay when changing states. - * Otherwise we may think the board did not reset and we bail. - * This for kdump only and is particular to the P600. - */ - msleep(500); - } - return 0; -} - -static __devinit void init_driver_version(char *driver_version, int len) -{ - memset(driver_version, 0, len); - strncpy(driver_version, HPSA " " HPSA_DRIVER_VERSION, len - 1); -} - -static __devinit int write_driver_ver_to_cfgtable( - struct CfgTable __iomem *cfgtable) -{ - char *driver_version; - int i, size = sizeof(cfgtable->driver_version); - - driver_version = kmalloc(size, GFP_KERNEL); - if (!driver_version) - return -ENOMEM; - - init_driver_version(driver_version, size); - for (i = 0; i < size; i++) - writeb(driver_version[i], &cfgtable->driver_version[i]); - kfree(driver_version); - return 0; -} - -static __devinit void read_driver_ver_from_cfgtable( - struct CfgTable __iomem *cfgtable, unsigned char *driver_ver) -{ - int i; - - for (i = 0; i < sizeof(cfgtable->driver_version); i++) - driver_ver[i] = readb(&cfgtable->driver_version[i]); -} - -static __devinit int controller_reset_failed( - struct CfgTable __iomem *cfgtable) -{ - - char *driver_ver, *old_driver_ver; - int rc, size = sizeof(cfgtable->driver_version); - - old_driver_ver = kmalloc(2 * size, GFP_KERNEL); - if (!old_driver_ver) - return -ENOMEM; - driver_ver = old_driver_ver + size; - - /* After a reset, the 32 bytes of "driver version" in the cfgtable - * should have been changed, otherwise we know the reset failed. - */ - init_driver_version(old_driver_ver, size); - read_driver_ver_from_cfgtable(cfgtable, driver_ver); - rc = !memcmp(driver_ver, old_driver_ver, size); - kfree(old_driver_ver); - return rc; -} -/* This does a hard reset of the controller using PCI power management - * states or the using the doorbell register. - */ -static __devinit int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev) -{ - u64 cfg_offset; - u32 cfg_base_addr; - u64 cfg_base_addr_index; - void __iomem *vaddr; - unsigned long paddr; - u32 misc_fw_support; - int rc; - struct CfgTable __iomem *cfgtable; - u32 use_doorbell; - u32 board_id; - u16 command_register; - - /* For controllers as old as the P600, this is very nearly - * the same thing as - * - * pci_save_state(pci_dev); - * pci_set_power_state(pci_dev, PCI_D3hot); - * pci_set_power_state(pci_dev, PCI_D0); - * pci_restore_state(pci_dev); - * - * For controllers newer than the P600, the pci power state - * method of resetting doesn't work so we have another way - * using the doorbell register. - */ - - rc = hpsa_lookup_board_id(pdev, &board_id); - if (rc < 0 || !ctlr_is_resettable(board_id)) { - dev_warn(&pdev->dev, "Not resetting device.\n"); - return -ENODEV; - } - - /* if controller is soft- but not hard resettable... */ - if (!ctlr_is_hard_resettable(board_id)) - return -ENOTSUPP; /* try soft reset later. */ - - /* Save the PCI command register */ - pci_read_config_word(pdev, 4, &command_register); - /* Turn the board off. This is so that later pci_restore_state() - * won't turn the board on before the rest of config space is ready. - */ - pci_disable_device(pdev); - pci_save_state(pdev); - - /* find the first memory BAR, so we can find the cfg table */ - rc = hpsa_pci_find_memory_BAR(pdev, &paddr); - if (rc) - return rc; - vaddr = remap_pci_mem(paddr, 0x250); - if (!vaddr) - return -ENOMEM; - - /* find cfgtable in order to check if reset via doorbell is supported */ - rc = hpsa_find_cfg_addrs(pdev, vaddr, &cfg_base_addr, - &cfg_base_addr_index, &cfg_offset); - if (rc) - goto unmap_vaddr; - cfgtable = remap_pci_mem(pci_resource_start(pdev, - cfg_base_addr_index) + cfg_offset, sizeof(*cfgtable)); - if (!cfgtable) { - rc = -ENOMEM; - goto unmap_vaddr; - } - rc = write_driver_ver_to_cfgtable(cfgtable); - if (rc) - goto unmap_vaddr; - - /* If reset via doorbell register is supported, use that. - * There are two such methods. Favor the newest method. - */ - misc_fw_support = readl(&cfgtable->misc_fw_support); - use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET2; - if (use_doorbell) { - use_doorbell = DOORBELL_CTLR_RESET2; - } else { - use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET; - if (use_doorbell) { - dev_warn(&pdev->dev, "Soft reset not supported. " - "Firmware update is required.\n"); - rc = -ENOTSUPP; /* try soft reset */ - goto unmap_cfgtable; - } - } - - rc = hpsa_controller_hard_reset(pdev, vaddr, use_doorbell); - if (rc) - goto unmap_cfgtable; - - pci_restore_state(pdev); - rc = pci_enable_device(pdev); - if (rc) { - dev_warn(&pdev->dev, "failed to enable device.\n"); - goto unmap_cfgtable; - } - pci_write_config_word(pdev, 4, command_register); - - /* Some devices (notably the HP Smart Array 5i Controller) - need a little pause here */ - msleep(HPSA_POST_RESET_PAUSE_MSECS); - - /* Wait for board to become not ready, then ready. */ - dev_info(&pdev->dev, "Waiting for board to reset.\n"); - rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_NOT_READY); - if (rc) { - dev_warn(&pdev->dev, - "failed waiting for board to reset." - " Will try soft reset.\n"); - rc = -ENOTSUPP; /* Not expected, but try soft reset later */ - goto unmap_cfgtable; - } - rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY); - if (rc) { - dev_warn(&pdev->dev, - "failed waiting for board to become ready " - "after hard reset\n"); - goto unmap_cfgtable; - } - - rc = controller_reset_failed(vaddr); - if (rc < 0) - goto unmap_cfgtable; - if (rc) { - dev_warn(&pdev->dev, "Unable to successfully reset " - "controller. Will try soft reset.\n"); - rc = -ENOTSUPP; - } else { - dev_info(&pdev->dev, "board ready after hard reset.\n"); - } - -unmap_cfgtable: - iounmap(cfgtable); - -unmap_vaddr: - iounmap(vaddr); - return rc; -} - -/* - * We cannot read the structure directly, for portability we must use - * the io functions. - * This is for debug only. - */ -static void print_cfg_table(struct device *dev, struct CfgTable *tb) -{ -#ifdef HPSA_DEBUG - int i; - char temp_name[17]; - - dev_info(dev, "Controller Configuration information\n"); - dev_info(dev, "------------------------------------\n"); - for (i = 0; i < 4; i++) - temp_name[i] = readb(&(tb->Signature[i])); - temp_name[4] = '\0'; - dev_info(dev, " Signature = %s\n", temp_name); - dev_info(dev, " Spec Number = %d\n", readl(&(tb->SpecValence))); - dev_info(dev, " Transport methods supported = 0x%x\n", - readl(&(tb->TransportSupport))); - dev_info(dev, " Transport methods active = 0x%x\n", - readl(&(tb->TransportActive))); - dev_info(dev, " Requested transport Method = 0x%x\n", - readl(&(tb->HostWrite.TransportRequest))); - dev_info(dev, " Coalesce Interrupt Delay = 0x%x\n", - readl(&(tb->HostWrite.CoalIntDelay))); - dev_info(dev, " Coalesce Interrupt Count = 0x%x\n", - readl(&(tb->HostWrite.CoalIntCount))); - dev_info(dev, " Max outstanding commands = 0x%d\n", - readl(&(tb->CmdsOutMax))); - dev_info(dev, " Bus Types = 0x%x\n", readl(&(tb->BusTypes))); - for (i = 0; i < 16; i++) - temp_name[i] = readb(&(tb->ServerName[i])); - temp_name[16] = '\0'; - dev_info(dev, " Server Name = %s\n", temp_name); - dev_info(dev, " Heartbeat Counter = 0x%x\n\n\n", - readl(&(tb->HeartBeat))); -#endif /* HPSA_DEBUG */ -} - -static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr) -{ - int i, offset, mem_type, bar_type; - - if (pci_bar_addr == PCI_BASE_ADDRESS_0) /* looking for BAR zero? */ - return 0; - offset = 0; - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - bar_type = pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE; - if (bar_type == PCI_BASE_ADDRESS_SPACE_IO) - offset += 4; - else { - mem_type = pci_resource_flags(pdev, i) & - PCI_BASE_ADDRESS_MEM_TYPE_MASK; - switch (mem_type) { - case PCI_BASE_ADDRESS_MEM_TYPE_32: - case PCI_BASE_ADDRESS_MEM_TYPE_1M: - offset += 4; /* 32 bit */ - break; - case PCI_BASE_ADDRESS_MEM_TYPE_64: - offset += 8; - break; - default: /* reserved in PCI 2.2 */ - dev_warn(&pdev->dev, - "base address is invalid\n"); - return -1; - break; - } - } - if (offset == pci_bar_addr - PCI_BASE_ADDRESS_0) - return i + 1; - } - return -1; -} - -/* If MSI/MSI-X is supported by the kernel we will try to enable it on - * controllers that are capable. If not, we use IO-APIC mode. - */ - -static void __devinit hpsa_interrupt_mode(struct ctlr_info *h) -{ -#ifdef CONFIG_PCI_MSI - int err; - struct msix_entry hpsa_msix_entries[4] = { {0, 0}, {0, 1}, - {0, 2}, {0, 3} - }; - - /* Some boards advertise MSI but don't really support it */ - if ((h->board_id == 0x40700E11) || (h->board_id == 0x40800E11) || - (h->board_id == 0x40820E11) || (h->board_id == 0x40830E11)) - goto default_int_mode; - if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) { - dev_info(&h->pdev->dev, "MSIX\n"); - err = pci_enable_msix(h->pdev, hpsa_msix_entries, 4); - if (!err) { - h->intr[0] = hpsa_msix_entries[0].vector; - h->intr[1] = hpsa_msix_entries[1].vector; - h->intr[2] = hpsa_msix_entries[2].vector; - h->intr[3] = hpsa_msix_entries[3].vector; - h->msix_vector = 1; - return; - } - if (err > 0) { - dev_warn(&h->pdev->dev, "only %d MSI-X vectors " - "available\n", err); - goto default_int_mode; - } else { - dev_warn(&h->pdev->dev, "MSI-X init failed %d\n", - err); - goto default_int_mode; - } - } - if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) { - dev_info(&h->pdev->dev, "MSI\n"); - if (!pci_enable_msi(h->pdev)) - h->msi_vector = 1; - else - dev_warn(&h->pdev->dev, "MSI init failed\n"); - } -default_int_mode: -#endif /* CONFIG_PCI_MSI */ - /* if we get here we're going to use the default interrupt mode */ - h->intr[h->intr_mode] = h->pdev->irq; -} - -static int __devinit hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id) -{ - int i; - u32 subsystem_vendor_id, subsystem_device_id; - - subsystem_vendor_id = pdev->subsystem_vendor; - subsystem_device_id = pdev->subsystem_device; - *board_id = ((subsystem_device_id << 16) & 0xffff0000) | - subsystem_vendor_id; - - for (i = 0; i < ARRAY_SIZE(products); i++) - if (*board_id == products[i].board_id) - return i; - - if ((subsystem_vendor_id != PCI_VENDOR_ID_HP && - subsystem_vendor_id != PCI_VENDOR_ID_COMPAQ) || - !hpsa_allow_any) { - dev_warn(&pdev->dev, "unrecognized board ID: " - "0x%08x, ignoring.\n", *board_id); - return -ENODEV; - } - return ARRAY_SIZE(products) - 1; /* generic unknown smart array */ -} - -static inline bool hpsa_board_disabled(struct pci_dev *pdev) -{ - u16 command; - - (void) pci_read_config_word(pdev, PCI_COMMAND, &command); - return ((command & PCI_COMMAND_MEMORY) == 0); -} - -static int __devinit hpsa_pci_find_memory_BAR(struct pci_dev *pdev, - unsigned long *memory_bar) -{ - int i; - - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) - if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { - /* addressing mode bits already removed */ - *memory_bar = pci_resource_start(pdev, i); - dev_dbg(&pdev->dev, "memory BAR = %lx\n", - *memory_bar); - return 0; - } - dev_warn(&pdev->dev, "no memory BAR found\n"); - return -ENODEV; -} - -static int __devinit hpsa_wait_for_board_state(struct pci_dev *pdev, - void __iomem *vaddr, int wait_for_ready) -{ - int i, iterations; - u32 scratchpad; - if (wait_for_ready) - iterations = HPSA_BOARD_READY_ITERATIONS; - else - iterations = HPSA_BOARD_NOT_READY_ITERATIONS; - - for (i = 0; i < iterations; i++) { - scratchpad = readl(vaddr + SA5_SCRATCHPAD_OFFSET); - if (wait_for_ready) { - if (scratchpad == HPSA_FIRMWARE_READY) - return 0; - } else { - if (scratchpad != HPSA_FIRMWARE_READY) - return 0; - } - msleep(HPSA_BOARD_READY_POLL_INTERVAL_MSECS); - } - dev_warn(&pdev->dev, "board not ready, timed out.\n"); - return -ENODEV; -} - -static int __devinit hpsa_find_cfg_addrs(struct pci_dev *pdev, - void __iomem *vaddr, u32 *cfg_base_addr, u64 *cfg_base_addr_index, - u64 *cfg_offset) -{ - *cfg_base_addr = readl(vaddr + SA5_CTCFG_OFFSET); - *cfg_offset = readl(vaddr + SA5_CTMEM_OFFSET); - *cfg_base_addr &= (u32) 0x0000ffff; - *cfg_base_addr_index = find_PCI_BAR_index(pdev, *cfg_base_addr); - if (*cfg_base_addr_index == -1) { - dev_warn(&pdev->dev, "cannot find cfg_base_addr_index\n"); - return -ENODEV; - } - return 0; -} - -static int __devinit hpsa_find_cfgtables(struct ctlr_info *h) -{ - u64 cfg_offset; - u32 cfg_base_addr; - u64 cfg_base_addr_index; - u32 trans_offset; - int rc; - - rc = hpsa_find_cfg_addrs(h->pdev, h->vaddr, &cfg_base_addr, - &cfg_base_addr_index, &cfg_offset); - if (rc) - return rc; - h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev, - cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable)); - if (!h->cfgtable) - return -ENOMEM; - rc = write_driver_ver_to_cfgtable(h->cfgtable); - if (rc) - return rc; - /* Find performant mode table. */ - trans_offset = readl(&h->cfgtable->TransMethodOffset); - h->transtable = remap_pci_mem(pci_resource_start(h->pdev, - cfg_base_addr_index)+cfg_offset+trans_offset, - sizeof(*h->transtable)); - if (!h->transtable) - return -ENOMEM; - return 0; -} - -static void __devinit hpsa_get_max_perf_mode_cmds(struct ctlr_info *h) -{ - h->max_commands = readl(&(h->cfgtable->MaxPerformantModeCommands)); - - /* Limit commands in memory limited kdump scenario. */ - if (reset_devices && h->max_commands > 32) - h->max_commands = 32; - - if (h->max_commands < 16) { - dev_warn(&h->pdev->dev, "Controller reports " - "max supported commands of %d, an obvious lie. " - "Using 16. Ensure that firmware is up to date.\n", - h->max_commands); - h->max_commands = 16; - } -} - -/* Interrogate the hardware for some limits: - * max commands, max SG elements without chaining, and with chaining, - * SG chain block size, etc. - */ -static void __devinit hpsa_find_board_params(struct ctlr_info *h) -{ - hpsa_get_max_perf_mode_cmds(h); - h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */ - h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements)); - /* - * Limit in-command s/g elements to 32 save dma'able memory. - * Howvever spec says if 0, use 31 - */ - h->max_cmd_sg_entries = 31; - if (h->maxsgentries > 512) { - h->max_cmd_sg_entries = 32; - h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1; - h->maxsgentries--; /* save one for chain pointer */ - } else { - h->maxsgentries = 31; /* default to traditional values */ - h->chainsize = 0; - } -} - -static inline bool hpsa_CISS_signature_present(struct ctlr_info *h) -{ - if ((readb(&h->cfgtable->Signature[0]) != 'C') || - (readb(&h->cfgtable->Signature[1]) != 'I') || - (readb(&h->cfgtable->Signature[2]) != 'S') || - (readb(&h->cfgtable->Signature[3]) != 'S')) { - dev_warn(&h->pdev->dev, "not a valid CISS config table\n"); - return false; - } - return true; -} - -/* Need to enable prefetch in the SCSI core for 6400 in x86 */ -static inline void hpsa_enable_scsi_prefetch(struct ctlr_info *h) -{ -#ifdef CONFIG_X86 - u32 prefetch; - - prefetch = readl(&(h->cfgtable->SCSI_Prefetch)); - prefetch |= 0x100; - writel(prefetch, &(h->cfgtable->SCSI_Prefetch)); -#endif -} - -/* Disable DMA prefetch for the P600. Otherwise an ASIC bug may result - * in a prefetch beyond physical memory. - */ -static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h) -{ - u32 dma_prefetch; - - if (h->board_id != 0x3225103C) - return; - dma_prefetch = readl(h->vaddr + I2O_DMA1_CFG); - dma_prefetch |= 0x8000; - writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG); -} - -static void __devinit hpsa_wait_for_mode_change_ack(struct ctlr_info *h) -{ - int i; - u32 doorbell_value; - unsigned long flags; - - /* under certain very rare conditions, this can take awhile. - * (e.g.: hot replace a failed 144GB drive in a RAID 5 set right - * as we enter this code.) - */ - for (i = 0; i < MAX_CONFIG_WAIT; i++) { - spin_lock_irqsave(&h->lock, flags); - doorbell_value = readl(h->vaddr + SA5_DOORBELL); - spin_unlock_irqrestore(&h->lock, flags); - if (!(doorbell_value & CFGTBL_ChangeReq)) - break; - /* delay and try again */ - usleep_range(10000, 20000); - } -} - -static int __devinit hpsa_enter_simple_mode(struct ctlr_info *h) -{ - u32 trans_support; - - trans_support = readl(&(h->cfgtable->TransportSupport)); - if (!(trans_support & SIMPLE_MODE)) - return -ENOTSUPP; - - h->max_commands = readl(&(h->cfgtable->CmdsOutMax)); - /* Update the field, and then ring the doorbell */ - writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest)); - writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); - print_cfg_table(&h->pdev->dev, h->cfgtable); - if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple)) { - dev_warn(&h->pdev->dev, - "unable to get board into simple mode\n"); - return -ENODEV; - } - h->transMethod = CFGTBL_Trans_Simple; - return 0; -} - -static int __devinit hpsa_pci_init(struct ctlr_info *h) -{ - int prod_index, err; - - prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id); - if (prod_index < 0) - return -ENODEV; - h->product_name = products[prod_index].product_name; - h->access = *(products[prod_index].access); - - if (hpsa_board_disabled(h->pdev)) { - dev_warn(&h->pdev->dev, "controller appears to be disabled\n"); - return -ENODEV; - } - - pci_disable_link_state(h->pdev, PCIE_LINK_STATE_L0S | - PCIE_LINK_STATE_L1 | PCIE_LINK_STATE_CLKPM); - - err = pci_enable_device(h->pdev); - if (err) { - dev_warn(&h->pdev->dev, "unable to enable PCI device\n"); - return err; - } - - err = pci_request_regions(h->pdev, HPSA); - if (err) { - dev_err(&h->pdev->dev, - "cannot obtain PCI resources, aborting\n"); - return err; - } - hpsa_interrupt_mode(h); - err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr); - if (err) - goto err_out_free_res; - h->vaddr = remap_pci_mem(h->paddr, 0x250); - if (!h->vaddr) { - err = -ENOMEM; - goto err_out_free_res; - } - err = hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY); - if (err) - goto err_out_free_res; - err = hpsa_find_cfgtables(h); - if (err) - goto err_out_free_res; - hpsa_find_board_params(h); - - if (!hpsa_CISS_signature_present(h)) { - err = -ENODEV; - goto err_out_free_res; - } - hpsa_enable_scsi_prefetch(h); - hpsa_p600_dma_prefetch_quirk(h); - err = hpsa_enter_simple_mode(h); - if (err) - goto err_out_free_res; - return 0; - -err_out_free_res: - if (h->transtable) - iounmap(h->transtable); - if (h->cfgtable) - iounmap(h->cfgtable); - if (h->vaddr) - iounmap(h->vaddr); - /* - * Deliberately omit pci_disable_device(): it does something nasty to - * Smart Array controllers that pci_enable_device does not undo - */ - pci_release_regions(h->pdev); - return err; -} - -static void __devinit hpsa_hba_inquiry(struct ctlr_info *h) -{ - int rc; - -#define HBA_INQUIRY_BYTE_COUNT 64 - h->hba_inquiry_data = kmalloc(HBA_INQUIRY_BYTE_COUNT, GFP_KERNEL); - if (!h->hba_inquiry_data) - return; - rc = hpsa_scsi_do_inquiry(h, RAID_CTLR_LUNID, 0, - h->hba_inquiry_data, HBA_INQUIRY_BYTE_COUNT); - if (rc != 0) { - kfree(h->hba_inquiry_data); - h->hba_inquiry_data = NULL; - } -} - -static __devinit int hpsa_init_reset_devices(struct pci_dev *pdev) -{ - int rc, i; - - if (!reset_devices) - return 0; - - /* Reset the controller with a PCI power-cycle or via doorbell */ - rc = hpsa_kdump_hard_reset_controller(pdev); - - /* -ENOTSUPP here means we cannot reset the controller - * but it's already (and still) up and running in - * "performant mode". Or, it might be 640x, which can't reset - * due to concerns about shared bbwc between 6402/6404 pair. - */ - if (rc == -ENOTSUPP) - return rc; /* just try to do the kdump anyhow. */ - if (rc) - return -ENODEV; - - /* Now try to get the controller to respond to a no-op */ - dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n"); - for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) { - if (hpsa_noop(pdev) == 0) - break; - else - dev_warn(&pdev->dev, "no-op failed%s\n", - (i < 11 ? "; re-trying" : "")); - } - return 0; -} - -static __devinit int hpsa_allocate_cmd_pool(struct ctlr_info *h) -{ - h->cmd_pool_bits = kzalloc( - DIV_ROUND_UP(h->nr_cmds, BITS_PER_LONG) * - sizeof(unsigned long), GFP_KERNEL); - h->cmd_pool = pci_alloc_consistent(h->pdev, - h->nr_cmds * sizeof(*h->cmd_pool), - &(h->cmd_pool_dhandle)); - h->errinfo_pool = pci_alloc_consistent(h->pdev, - h->nr_cmds * sizeof(*h->errinfo_pool), - &(h->errinfo_pool_dhandle)); - if ((h->cmd_pool_bits == NULL) - || (h->cmd_pool == NULL) - || (h->errinfo_pool == NULL)) { - dev_err(&h->pdev->dev, "out of memory in %s", __func__); - return -ENOMEM; - } - return 0; -} - -static void hpsa_free_cmd_pool(struct ctlr_info *h) -{ - kfree(h->cmd_pool_bits); - if (h->cmd_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct CommandList), - h->cmd_pool, h->cmd_pool_dhandle); - if (h->errinfo_pool) - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct ErrorInfo), - h->errinfo_pool, - h->errinfo_pool_dhandle); -} - -static int hpsa_request_irq(struct ctlr_info *h, - irqreturn_t (*msixhandler)(int, void *), - irqreturn_t (*intxhandler)(int, void *)) -{ - int rc; - - if (h->msix_vector || h->msi_vector) - rc = request_irq(h->intr[h->intr_mode], msixhandler, - 0, h->devname, h); - else - rc = request_irq(h->intr[h->intr_mode], intxhandler, - IRQF_SHARED, h->devname, h); - if (rc) { - dev_err(&h->pdev->dev, "unable to get irq %d for %s\n", - h->intr[h->intr_mode], h->devname); - return -ENODEV; - } - return 0; -} - -static int __devinit hpsa_kdump_soft_reset(struct ctlr_info *h) -{ - if (hpsa_send_host_reset(h, RAID_CTLR_LUNID, - HPSA_RESET_TYPE_CONTROLLER)) { - dev_warn(&h->pdev->dev, "Resetting array controller failed.\n"); - return -EIO; - } - - dev_info(&h->pdev->dev, "Waiting for board to soft reset.\n"); - if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_NOT_READY)) { - dev_warn(&h->pdev->dev, "Soft reset had no effect.\n"); - return -1; - } - - dev_info(&h->pdev->dev, "Board reset, awaiting READY status.\n"); - if (hpsa_wait_for_board_state(h->pdev, h->vaddr, BOARD_READY)) { - dev_warn(&h->pdev->dev, "Board failed to become ready " - "after soft reset.\n"); - return -1; - } - - return 0; -} - -static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h) -{ - free_irq(h->intr[h->intr_mode], h); -#ifdef CONFIG_PCI_MSI - if (h->msix_vector) - pci_disable_msix(h->pdev); - else if (h->msi_vector) - pci_disable_msi(h->pdev); -#endif /* CONFIG_PCI_MSI */ - hpsa_free_sg_chain_blocks(h); - hpsa_free_cmd_pool(h); - kfree(h->blockFetchTable); - pci_free_consistent(h->pdev, h->reply_pool_size, - h->reply_pool, h->reply_pool_dhandle); - if (h->vaddr) - iounmap(h->vaddr); - if (h->transtable) - iounmap(h->transtable); - if (h->cfgtable) - iounmap(h->cfgtable); - pci_release_regions(h->pdev); - kfree(h); -} - -static void remove_ctlr_from_lockup_detector_list(struct ctlr_info *h) -{ - assert_spin_locked(&lockup_detector_lock); - if (!hpsa_lockup_detector) - return; - if (h->lockup_detected) - return; /* already stopped the lockup detector */ - list_del(&h->lockup_list); -} - -/* Called when controller lockup detected. */ -static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list) -{ - struct CommandList *c = NULL; - - assert_spin_locked(&h->lock); - /* Mark all outstanding commands as failed and complete them. */ - while (!list_empty(list)) { - c = list_entry(list->next, struct CommandList, list); - c->err_info->CommandStatus = CMD_HARDWARE_ERR; - finish_cmd(c, c->Header.Tag.lower); - } -} - -static void controller_lockup_detected(struct ctlr_info *h) -{ - unsigned long flags; - - assert_spin_locked(&lockup_detector_lock); - remove_ctlr_from_lockup_detector_list(h); - h->access.set_intr_mask(h, HPSA_INTR_OFF); - spin_lock_irqsave(&h->lock, flags); - h->lockup_detected = readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); - spin_unlock_irqrestore(&h->lock, flags); - dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n", - h->lockup_detected); - pci_disable_device(h->pdev); - spin_lock_irqsave(&h->lock, flags); - fail_all_cmds_on_list(h, &h->cmpQ); - fail_all_cmds_on_list(h, &h->reqQ); - spin_unlock_irqrestore(&h->lock, flags); -} - -#define HEARTBEAT_SAMPLE_INTERVAL (10 * HZ) -#define HEARTBEAT_CHECK_MINIMUM_INTERVAL (HEARTBEAT_SAMPLE_INTERVAL / 2) - -static void detect_controller_lockup(struct ctlr_info *h) -{ - u64 now; - u32 heartbeat; - unsigned long flags; - - assert_spin_locked(&lockup_detector_lock); - now = get_jiffies_64(); - /* If we've received an interrupt recently, we're ok. */ - if (time_after64(h->last_intr_timestamp + - (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now)) - return; - - /* - * If we've already checked the heartbeat recently, we're ok. - * This could happen if someone sends us a signal. We - * otherwise don't care about signals in this thread. - */ - if (time_after64(h->last_heartbeat_timestamp + - (HEARTBEAT_CHECK_MINIMUM_INTERVAL), now)) - return; - - /* If heartbeat has not changed since we last looked, we're not ok. */ - spin_lock_irqsave(&h->lock, flags); - heartbeat = readl(&h->cfgtable->HeartBeat); - spin_unlock_irqrestore(&h->lock, flags); - if (h->last_heartbeat == heartbeat) { - controller_lockup_detected(h); - return; - } - - /* We're ok. */ - h->last_heartbeat = heartbeat; - h->last_heartbeat_timestamp = now; -} - -static int detect_controller_lockup_thread(void *notused) -{ - struct ctlr_info *h; - unsigned long flags; - - while (1) { - struct list_head *this, *tmp; - - schedule_timeout_interruptible(HEARTBEAT_SAMPLE_INTERVAL); - if (kthread_should_stop()) - break; - spin_lock_irqsave(&lockup_detector_lock, flags); - list_for_each_safe(this, tmp, &hpsa_ctlr_list) { - h = list_entry(this, struct ctlr_info, lockup_list); - detect_controller_lockup(h); - } - spin_unlock_irqrestore(&lockup_detector_lock, flags); - } - return 0; -} - -static void add_ctlr_to_lockup_detector_list(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&lockup_detector_lock, flags); - list_add_tail(&h->lockup_list, &hpsa_ctlr_list); - spin_unlock_irqrestore(&lockup_detector_lock, flags); -} - -static void start_controller_lockup_detector(struct ctlr_info *h) -{ - /* Start the lockup detector thread if not already started */ - if (!hpsa_lockup_detector) { - spin_lock_init(&lockup_detector_lock); - hpsa_lockup_detector = - kthread_run(detect_controller_lockup_thread, - NULL, HPSA); - } - if (!hpsa_lockup_detector) { - dev_warn(&h->pdev->dev, - "Could not start lockup detector thread\n"); - return; - } - add_ctlr_to_lockup_detector_list(h); -} - -static void stop_controller_lockup_detector(struct ctlr_info *h) -{ - unsigned long flags; - - spin_lock_irqsave(&lockup_detector_lock, flags); - remove_ctlr_from_lockup_detector_list(h); - /* If the list of ctlr's to monitor is empty, stop the thread */ - if (list_empty(&hpsa_ctlr_list)) { - spin_unlock_irqrestore(&lockup_detector_lock, flags); - kthread_stop(hpsa_lockup_detector); - spin_lock_irqsave(&lockup_detector_lock, flags); - hpsa_lockup_detector = NULL; - } - spin_unlock_irqrestore(&lockup_detector_lock, flags); -} - -static int __devinit hpsa_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int dac, rc; - struct ctlr_info *h; - int try_soft_reset = 0; - unsigned long flags; - - if (number_of_controllers == 0) - printk(KERN_INFO DRIVER_NAME "\n"); - - rc = hpsa_init_reset_devices(pdev); - if (rc) { - if (rc != -ENOTSUPP) - return rc; - /* If the reset fails in a particular way (it has no way to do - * a proper hard reset, so returns -ENOTSUPP) we can try to do - * a soft reset once we get the controller configured up to the - * point that it can accept a command. - */ - try_soft_reset = 1; - rc = 0; - } - -reinit_after_soft_reset: - - /* Command structures must be aligned on a 32-byte boundary because - * the 5 lower bits of the address are used by the hardware. and by - * the driver. See comments in hpsa.h for more info. - */ -#define COMMANDLIST_ALIGNMENT 32 - BUILD_BUG_ON(sizeof(struct CommandList) % COMMANDLIST_ALIGNMENT); - h = kzalloc(sizeof(*h), GFP_KERNEL); - if (!h) - return -ENOMEM; - - h->pdev = pdev; - h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT; - INIT_LIST_HEAD(&h->cmpQ); - INIT_LIST_HEAD(&h->reqQ); - spin_lock_init(&h->lock); - spin_lock_init(&h->scan_lock); - rc = hpsa_pci_init(h); - if (rc != 0) - goto clean1; - - sprintf(h->devname, HPSA "%d", number_of_controllers); - h->ctlr = number_of_controllers; - number_of_controllers++; - - /* configure PCI DMA stuff */ - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc == 0) { - dac = 1; - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc == 0) { - dac = 0; - } else { - dev_err(&pdev->dev, "no suitable DMA available\n"); - goto clean1; - } - } - - /* make sure the board interrupts are off */ - h->access.set_intr_mask(h, HPSA_INTR_OFF); - - if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx)) - goto clean2; - dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n", - h->devname, pdev->device, - h->intr[h->intr_mode], dac ? "" : " not"); - if (hpsa_allocate_cmd_pool(h)) - goto clean4; - if (hpsa_allocate_sg_chain_blocks(h)) - goto clean4; - init_waitqueue_head(&h->scan_wait_queue); - h->scan_finished = 1; /* no scan currently in progress */ - - pci_set_drvdata(pdev, h); - h->ndevices = 0; - h->scsi_host = NULL; - spin_lock_init(&h->devlock); - hpsa_put_ctlr_into_performant_mode(h); - - /* At this point, the controller is ready to take commands. - * Now, if reset_devices and the hard reset didn't work, try - * the soft reset and see if that works. - */ - if (try_soft_reset) { - - /* This is kind of gross. We may or may not get a completion - * from the soft reset command, and if we do, then the value - * from the fifo may or may not be valid. So, we wait 10 secs - * after the reset throwing away any completions we get during - * that time. Unregister the interrupt handler and register - * fake ones to scoop up any residual completions. - */ - spin_lock_irqsave(&h->lock, flags); - h->access.set_intr_mask(h, HPSA_INTR_OFF); - spin_unlock_irqrestore(&h->lock, flags); - free_irq(h->intr[h->intr_mode], h); - rc = hpsa_request_irq(h, hpsa_msix_discard_completions, - hpsa_intx_discard_completions); - if (rc) { - dev_warn(&h->pdev->dev, "Failed to request_irq after " - "soft reset.\n"); - goto clean4; - } - - rc = hpsa_kdump_soft_reset(h); - if (rc) - /* Neither hard nor soft reset worked, we're hosed. */ - goto clean4; - - dev_info(&h->pdev->dev, "Board READY.\n"); - dev_info(&h->pdev->dev, - "Waiting for stale completions to drain.\n"); - h->access.set_intr_mask(h, HPSA_INTR_ON); - msleep(10000); - h->access.set_intr_mask(h, HPSA_INTR_OFF); - - rc = controller_reset_failed(h->cfgtable); - if (rc) - dev_info(&h->pdev->dev, - "Soft reset appears to have failed.\n"); - - /* since the controller's reset, we have to go back and re-init - * everything. Easiest to just forget what we've done and do it - * all over again. - */ - hpsa_undo_allocations_after_kdump_soft_reset(h); - try_soft_reset = 0; - if (rc) - /* don't go to clean4, we already unallocated */ - return -ENODEV; - - goto reinit_after_soft_reset; - } - - /* Turn the interrupts on so we can service requests */ - h->access.set_intr_mask(h, HPSA_INTR_ON); - - hpsa_hba_inquiry(h); - hpsa_register_scsi(h); /* hook ourselves into SCSI subsystem */ - start_controller_lockup_detector(h); - return 1; - -clean4: - hpsa_free_sg_chain_blocks(h); - hpsa_free_cmd_pool(h); - free_irq(h->intr[h->intr_mode], h); -clean2: -clean1: - kfree(h); - return rc; -} - -static void hpsa_flush_cache(struct ctlr_info *h) -{ - char *flush_buf; - struct CommandList *c; - - flush_buf = kzalloc(4, GFP_KERNEL); - if (!flush_buf) - return; - - c = cmd_special_alloc(h); - if (!c) { - dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n"); - goto out_of_memory; - } - fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0, - RAID_CTLR_LUNID, TYPE_CMD); - hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_TODEVICE); - if (c->err_info->CommandStatus != 0) - dev_warn(&h->pdev->dev, - "error flushing cache on controller\n"); - cmd_special_free(h, c); -out_of_memory: - kfree(flush_buf); -} - -static void hpsa_shutdown(struct pci_dev *pdev) -{ - struct ctlr_info *h; - - h = pci_get_drvdata(pdev); - /* Turn board interrupts off and send the flush cache command - * sendcmd will turn off interrupt, and send the flush... - * To write all data in the battery backed cache to disks - */ - hpsa_flush_cache(h); - h->access.set_intr_mask(h, HPSA_INTR_OFF); - free_irq(h->intr[h->intr_mode], h); -#ifdef CONFIG_PCI_MSI - if (h->msix_vector) - pci_disable_msix(h->pdev); - else if (h->msi_vector) - pci_disable_msi(h->pdev); -#endif /* CONFIG_PCI_MSI */ -} - -static void __devexit hpsa_free_device_info(struct ctlr_info *h) -{ - int i; - - for (i = 0; i < h->ndevices; i++) - kfree(h->dev[i]); -} - -static void __devexit hpsa_remove_one(struct pci_dev *pdev) -{ - struct ctlr_info *h; - - if (pci_get_drvdata(pdev) == NULL) { - dev_err(&pdev->dev, "unable to remove device\n"); - return; - } - h = pci_get_drvdata(pdev); - stop_controller_lockup_detector(h); - hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */ - hpsa_shutdown(pdev); - iounmap(h->vaddr); - iounmap(h->transtable); - iounmap(h->cfgtable); - hpsa_free_device_info(h); - hpsa_free_sg_chain_blocks(h); - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct CommandList), - h->cmd_pool, h->cmd_pool_dhandle); - pci_free_consistent(h->pdev, - h->nr_cmds * sizeof(struct ErrorInfo), - h->errinfo_pool, h->errinfo_pool_dhandle); - pci_free_consistent(h->pdev, h->reply_pool_size, - h->reply_pool, h->reply_pool_dhandle); - kfree(h->cmd_pool_bits); - kfree(h->blockFetchTable); - kfree(h->hba_inquiry_data); - /* - * Deliberately omit pci_disable_device(): it does something nasty to - * Smart Array controllers that pci_enable_device does not undo - */ - pci_release_regions(pdev); - pci_set_drvdata(pdev, NULL); - kfree(h); -} - -static int hpsa_suspend(__attribute__((unused)) struct pci_dev *pdev, - __attribute__((unused)) pm_message_t state) -{ - return -ENOSYS; -} - -static int hpsa_resume(__attribute__((unused)) struct pci_dev *pdev) -{ - return -ENOSYS; -} - -static struct pci_driver hpsa_pci_driver = { - .name = HPSA, - .probe = hpsa_init_one, - .remove = __devexit_p(hpsa_remove_one), - .id_table = hpsa_pci_device_id, /* id_table */ - .shutdown = hpsa_shutdown, - .suspend = hpsa_suspend, - .resume = hpsa_resume, -}; - -/* Fill in bucket_map[], given nsgs (the max number of - * scatter gather elements supported) and bucket[], - * which is an array of 8 integers. The bucket[] array - * contains 8 different DMA transfer sizes (in 16 - * byte increments) which the controller uses to fetch - * commands. This function fills in bucket_map[], which - * maps a given number of scatter gather elements to one of - * the 8 DMA transfer sizes. The point of it is to allow the - * controller to only do as much DMA as needed to fetch the - * command, with the DMA transfer size encoded in the lower - * bits of the command address. - */ -static void calc_bucket_map(int bucket[], int num_buckets, - int nsgs, int *bucket_map) -{ - int i, j, b, size; - - /* even a command with 0 SGs requires 4 blocks */ -#define MINIMUM_TRANSFER_BLOCKS 4 -#define NUM_BUCKETS 8 - /* Note, bucket_map must have nsgs+1 entries. */ - for (i = 0; i <= nsgs; i++) { - /* Compute size of a command with i SG entries */ - size = i + MINIMUM_TRANSFER_BLOCKS; - b = num_buckets; /* Assume the biggest bucket */ - /* Find the bucket that is just big enough */ - for (j = 0; j < 8; j++) { - if (bucket[j] >= size) { - b = j; - break; - } - } - /* for a command with i SG entries, use bucket b. */ - bucket_map[i] = b; - } -} - -static __devinit void hpsa_enter_performant_mode(struct ctlr_info *h, - u32 use_short_tags) -{ - int i; - unsigned long register_value; - - /* This is a bit complicated. There are 8 registers on - * the controller which we write to to tell it 8 different - * sizes of commands which there may be. It's a way of - * reducing the DMA done to fetch each command. Encoded into - * each command's tag are 3 bits which communicate to the controller - * which of the eight sizes that command fits within. The size of - * each command depends on how many scatter gather entries there are. - * Each SG entry requires 16 bytes. The eight registers are programmed - * with the number of 16-byte blocks a command of that size requires. - * The smallest command possible requires 5 such 16 byte blocks. - * the largest command possible requires SG_ENTRIES_IN_CMD + 4 16-byte - * blocks. Note, this only extends to the SG entries contained - * within the command block, and does not extend to chained blocks - * of SG elements. bft[] contains the eight values we write to - * the registers. They are not evenly distributed, but have more - * sizes for small commands, and fewer sizes for larger commands. - */ - int bft[8] = {5, 6, 8, 10, 12, 20, 28, SG_ENTRIES_IN_CMD + 4}; - BUILD_BUG_ON(28 > SG_ENTRIES_IN_CMD + 4); - /* 5 = 1 s/g entry or 4k - * 6 = 2 s/g entry or 8k - * 8 = 4 s/g entry or 16k - * 10 = 6 s/g entry or 24k - */ - - h->reply_pool_wraparound = 1; /* spec: init to 1 */ - - /* Controller spec: zero out this buffer. */ - memset(h->reply_pool, 0, h->reply_pool_size); - h->reply_pool_head = h->reply_pool; - - bft[7] = SG_ENTRIES_IN_CMD + 4; - calc_bucket_map(bft, ARRAY_SIZE(bft), - SG_ENTRIES_IN_CMD, h->blockFetchTable); - for (i = 0; i < 8; i++) - writel(bft[i], &h->transtable->BlockFetch[i]); - - /* size of controller ring buffer */ - writel(h->max_commands, &h->transtable->RepQSize); - writel(1, &h->transtable->RepQCount); - writel(0, &h->transtable->RepQCtrAddrLow32); - writel(0, &h->transtable->RepQCtrAddrHigh32); - writel(h->reply_pool_dhandle, &h->transtable->RepQAddr0Low32); - writel(0, &h->transtable->RepQAddr0High32); - writel(CFGTBL_Trans_Performant | use_short_tags, - &(h->cfgtable->HostWrite.TransportRequest)); - writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL); - hpsa_wait_for_mode_change_ack(h); - register_value = readl(&(h->cfgtable->TransportActive)); - if (!(register_value & CFGTBL_Trans_Performant)) { - dev_warn(&h->pdev->dev, "unable to get board into" - " performant mode\n"); - return; - } - /* Change the access methods to the performant access methods */ - h->access = SA5_performant_access; - h->transMethod = CFGTBL_Trans_Performant; -} - -static __devinit void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h) -{ - u32 trans_support; - - if (hpsa_simple_mode) - return; - - trans_support = readl(&(h->cfgtable->TransportSupport)); - if (!(trans_support & PERFORMANT_MODE)) - return; - - hpsa_get_max_perf_mode_cmds(h); - /* Performant mode ring buffer and supporting data structures */ - h->reply_pool_size = h->max_commands * sizeof(u64); - h->reply_pool = pci_alloc_consistent(h->pdev, h->reply_pool_size, - &(h->reply_pool_dhandle)); - - /* Need a block fetch table for performant mode */ - h->blockFetchTable = kmalloc(((SG_ENTRIES_IN_CMD + 1) * - sizeof(u32)), GFP_KERNEL); - - if ((h->reply_pool == NULL) - || (h->blockFetchTable == NULL)) - goto clean_up; - - hpsa_enter_performant_mode(h, - trans_support & CFGTBL_Trans_use_short_tags); - - return; - -clean_up: - if (h->reply_pool) - pci_free_consistent(h->pdev, h->reply_pool_size, - h->reply_pool, h->reply_pool_dhandle); - kfree(h->blockFetchTable); -} - -/* - * This is it. Register the PCI driver information for the cards we control - * the OS will call our registered routines when it finds one of our cards. - */ -static int __init hpsa_init(void) -{ - return pci_register_driver(&hpsa_pci_driver); -} - -static void __exit hpsa_cleanup(void) -{ - pci_unregister_driver(&hpsa_pci_driver); -} - -module_init(hpsa_init); -module_exit(hpsa_cleanup); diff --git a/ANDROID_3.4.5/drivers/scsi/hpsa.h b/ANDROID_3.4.5/drivers/scsi/hpsa.h deleted file mode 100644 index 7b28d54f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/hpsa.h +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Disk Array driver for HP Smart Array SAS controllers - * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Questions/Comments/Bugfixes to iss_storagedev@hp.com - * - */ -#ifndef HPSA_H -#define HPSA_H - -#include - -#define IO_OK 0 -#define IO_ERROR 1 - -struct ctlr_info; - -struct access_method { - void (*submit_command)(struct ctlr_info *h, - struct CommandList *c); - void (*set_intr_mask)(struct ctlr_info *h, unsigned long val); - unsigned long (*fifo_full)(struct ctlr_info *h); - bool (*intr_pending)(struct ctlr_info *h); - unsigned long (*command_completed)(struct ctlr_info *h); -}; - -struct hpsa_scsi_dev_t { - int devtype; - int bus, target, lun; /* as presented to the OS */ - unsigned char scsi3addr[8]; /* as presented to the HW */ -#define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" - unsigned char device_id[16]; /* from inquiry pg. 0x83 */ - unsigned char vendor[8]; /* bytes 8-15 of inquiry data */ - unsigned char model[16]; /* bytes 16-31 of inquiry data */ - unsigned char raid_level; /* from inquiry page 0xC1 */ -}; - -struct ctlr_info { - int ctlr; - char devname[8]; - char *product_name; - struct pci_dev *pdev; - u32 board_id; - void __iomem *vaddr; - unsigned long paddr; - int nr_cmds; /* Number of commands allowed on this controller */ - struct CfgTable __iomem *cfgtable; - int interrupts_enabled; - int major; - int max_commands; - int commands_outstanding; - int max_outstanding; /* Debug */ - int usage_count; /* number of opens all all minor devices */ -# define PERF_MODE_INT 0 -# define DOORBELL_INT 1 -# define SIMPLE_MODE_INT 2 -# define MEMQ_MODE_INT 3 - unsigned int intr[4]; - unsigned int msix_vector; - unsigned int msi_vector; - int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */ - struct access_method access; - - /* queue and queue Info */ - struct list_head reqQ; - struct list_head cmpQ; - unsigned int Qdepth; - unsigned int maxQsinceinit; - unsigned int maxSG; - spinlock_t lock; - int maxsgentries; - u8 max_cmd_sg_entries; - int chainsize; - struct SGDescriptor **cmd_sg_list; - - /* pointers to command and error info pool */ - struct CommandList *cmd_pool; - dma_addr_t cmd_pool_dhandle; - struct ErrorInfo *errinfo_pool; - dma_addr_t errinfo_pool_dhandle; - unsigned long *cmd_pool_bits; - int nr_allocs; - int nr_frees; - int scan_finished; - spinlock_t scan_lock; - wait_queue_head_t scan_wait_queue; - - struct Scsi_Host *scsi_host; - spinlock_t devlock; /* to protect hba[ctlr]->dev[]; */ - int ndevices; /* number of used elements in .dev[] array. */ - struct hpsa_scsi_dev_t *dev[HPSA_MAX_DEVICES]; - /* - * Performant mode tables. - */ - u32 trans_support; - u32 trans_offset; - struct TransTable_struct *transtable; - unsigned long transMethod; - - /* - * Performant mode completion buffer - */ - u64 *reply_pool; - dma_addr_t reply_pool_dhandle; - u64 *reply_pool_head; - size_t reply_pool_size; - unsigned char reply_pool_wraparound; - u32 *blockFetchTable; - unsigned char *hba_inquiry_data; - u64 last_intr_timestamp; - u32 last_heartbeat; - u64 last_heartbeat_timestamp; - u32 lockup_detected; - struct list_head lockup_list; -}; -#define HPSA_ABORT_MSG 0 -#define HPSA_DEVICE_RESET_MSG 1 -#define HPSA_RESET_TYPE_CONTROLLER 0x00 -#define HPSA_RESET_TYPE_BUS 0x01 -#define HPSA_RESET_TYPE_TARGET 0x03 -#define HPSA_RESET_TYPE_LUN 0x04 -#define HPSA_MSG_SEND_RETRY_LIMIT 10 -#define HPSA_MSG_SEND_RETRY_INTERVAL_MSECS (10000) - -/* Maximum time in seconds driver will wait for command completions - * when polling before giving up. - */ -#define HPSA_MAX_POLL_TIME_SECS (20) - -/* During SCSI error recovery, HPSA_TUR_RETRY_LIMIT defines - * how many times to retry TEST UNIT READY on a device - * while waiting for it to become ready before giving up. - * HPSA_MAX_WAIT_INTERVAL_SECS is the max wait interval - * between sending TURs while waiting for a device - * to become ready. - */ -#define HPSA_TUR_RETRY_LIMIT (20) -#define HPSA_MAX_WAIT_INTERVAL_SECS (30) - -/* HPSA_BOARD_READY_WAIT_SECS is how long to wait for a board - * to become ready, in seconds, before giving up on it. - * HPSA_BOARD_READY_POLL_INTERVAL_MSECS * is how long to wait - * between polling the board to see if it is ready, in - * milliseconds. HPSA_BOARD_READY_POLL_INTERVAL and - * HPSA_BOARD_READY_ITERATIONS are derived from those. - */ -#define HPSA_BOARD_READY_WAIT_SECS (120) -#define HPSA_BOARD_NOT_READY_WAIT_SECS (100) -#define HPSA_BOARD_READY_POLL_INTERVAL_MSECS (100) -#define HPSA_BOARD_READY_POLL_INTERVAL \ - ((HPSA_BOARD_READY_POLL_INTERVAL_MSECS * HZ) / 1000) -#define HPSA_BOARD_READY_ITERATIONS \ - ((HPSA_BOARD_READY_WAIT_SECS * 1000) / \ - HPSA_BOARD_READY_POLL_INTERVAL_MSECS) -#define HPSA_BOARD_NOT_READY_ITERATIONS \ - ((HPSA_BOARD_NOT_READY_WAIT_SECS * 1000) / \ - HPSA_BOARD_READY_POLL_INTERVAL_MSECS) -#define HPSA_POST_RESET_PAUSE_MSECS (3000) -#define HPSA_POST_RESET_NOOP_RETRIES (12) - -/* Defining the diffent access_menthods */ -/* - * Memory mapped FIFO interface (SMART 53xx cards) - */ -#define SA5_DOORBELL 0x20 -#define SA5_REQUEST_PORT_OFFSET 0x40 -#define SA5_REPLY_INTR_MASK_OFFSET 0x34 -#define SA5_REPLY_PORT_OFFSET 0x44 -#define SA5_INTR_STATUS 0x30 -#define SA5_SCRATCHPAD_OFFSET 0xB0 - -#define SA5_CTCFG_OFFSET 0xB4 -#define SA5_CTMEM_OFFSET 0xB8 - -#define SA5_INTR_OFF 0x08 -#define SA5B_INTR_OFF 0x04 -#define SA5_INTR_PENDING 0x08 -#define SA5B_INTR_PENDING 0x04 -#define FIFO_EMPTY 0xffffffff -#define HPSA_FIRMWARE_READY 0xffff0000 /* value in scratchpad register */ - -#define HPSA_ERROR_BIT 0x02 - -/* Performant mode flags */ -#define SA5_PERF_INTR_PENDING 0x04 -#define SA5_PERF_INTR_OFF 0x05 -#define SA5_OUTDB_STATUS_PERF_BIT 0x01 -#define SA5_OUTDB_CLEAR_PERF_BIT 0x01 -#define SA5_OUTDB_CLEAR 0xA0 -#define SA5_OUTDB_CLEAR_PERF_BIT 0x01 -#define SA5_OUTDB_STATUS 0x9C - - -#define HPSA_INTR_ON 1 -#define HPSA_INTR_OFF 0 -/* - Send the command to the hardware -*/ -static void SA5_submit_command(struct ctlr_info *h, - struct CommandList *c) -{ - dev_dbg(&h->pdev->dev, "Sending %x, tag = %x\n", c->busaddr, - c->Header.Tag.lower); - writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET); - (void) readl(h->vaddr + SA5_SCRATCHPAD_OFFSET); - h->commands_outstanding++; - if (h->commands_outstanding > h->max_outstanding) - h->max_outstanding = h->commands_outstanding; -} - -/* - * This card is the opposite of the other cards. - * 0 turns interrupts on... - * 0x08 turns them off... - */ -static void SA5_intr_mask(struct ctlr_info *h, unsigned long val) -{ - if (val) { /* Turn interrupts on */ - h->interrupts_enabled = 1; - writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); - (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); - } else { /* Turn them off */ - h->interrupts_enabled = 0; - writel(SA5_INTR_OFF, - h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); - (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); - } -} - -static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val) -{ - if (val) { /* turn on interrupts */ - h->interrupts_enabled = 1; - writel(0, h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); - (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); - } else { - h->interrupts_enabled = 0; - writel(SA5_PERF_INTR_OFF, - h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); - (void) readl(h->vaddr + SA5_REPLY_INTR_MASK_OFFSET); - } -} - -static unsigned long SA5_performant_completed(struct ctlr_info *h) -{ - unsigned long register_value = FIFO_EMPTY; - - /* flush the controller write of the reply queue by reading - * outbound doorbell status register. - */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); - /* msi auto clears the interrupt pending bit. */ - if (!(h->msi_vector || h->msix_vector)) { - writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR); - /* Do a read in order to flush the write to the controller - * (as per spec.) - */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); - } - - if ((*(h->reply_pool_head) & 1) == (h->reply_pool_wraparound)) { - register_value = *(h->reply_pool_head); - (h->reply_pool_head)++; - h->commands_outstanding--; - } else { - register_value = FIFO_EMPTY; - } - /* Check for wraparound */ - if (h->reply_pool_head == (h->reply_pool + h->max_commands)) { - h->reply_pool_head = h->reply_pool; - h->reply_pool_wraparound ^= 1; - } - - return register_value; -} - -/* - * Returns true if fifo is full. - * - */ -static unsigned long SA5_fifo_full(struct ctlr_info *h) -{ - if (h->commands_outstanding >= h->max_commands) - return 1; - else - return 0; - -} -/* - * returns value read from hardware. - * returns FIFO_EMPTY if there is nothing to read - */ -static unsigned long SA5_completed(struct ctlr_info *h) -{ - unsigned long register_value - = readl(h->vaddr + SA5_REPLY_PORT_OFFSET); - - if (register_value != FIFO_EMPTY) - h->commands_outstanding--; - -#ifdef HPSA_DEBUG - if (register_value != FIFO_EMPTY) - dev_dbg(&h->pdev->dev, "Read %lx back from board\n", - register_value); - else - dev_dbg(&h->pdev->dev, "FIFO Empty read\n"); -#endif - - return register_value; -} -/* - * Returns true if an interrupt is pending.. - */ -static bool SA5_intr_pending(struct ctlr_info *h) -{ - unsigned long register_value = - readl(h->vaddr + SA5_INTR_STATUS); - dev_dbg(&h->pdev->dev, "intr_pending %lx\n", register_value); - return register_value & SA5_INTR_PENDING; -} - -static bool SA5_performant_intr_pending(struct ctlr_info *h) -{ - unsigned long register_value = readl(h->vaddr + SA5_INTR_STATUS); - - if (!register_value) - return false; - - if (h->msi_vector || h->msix_vector) - return true; - - /* Read outbound doorbell to flush */ - register_value = readl(h->vaddr + SA5_OUTDB_STATUS); - return register_value & SA5_OUTDB_STATUS_PERF_BIT; -} - -static struct access_method SA5_access = { - SA5_submit_command, - SA5_intr_mask, - SA5_fifo_full, - SA5_intr_pending, - SA5_completed, -}; - -static struct access_method SA5_performant_access = { - SA5_submit_command, - SA5_performant_intr_mask, - SA5_fifo_full, - SA5_performant_intr_pending, - SA5_performant_completed, -}; - -struct board_type { - u32 board_id; - char *product_name; - struct access_method *access; -}; - -#endif /* HPSA_H */ - diff --git a/ANDROID_3.4.5/drivers/scsi/hpsa_cmd.h b/ANDROID_3.4.5/drivers/scsi/hpsa_cmd.h deleted file mode 100644 index 8049815d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/hpsa_cmd.h +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Disk Array driver for HP Smart Array SAS controllers - * Copyright 2000, 2009 Hewlett-Packard Development Company, L.P. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Questions/Comments/Bugfixes to iss_storagedev@hp.com - * - */ -#ifndef HPSA_CMD_H -#define HPSA_CMD_H - -/* general boundary defintions */ -#define SENSEINFOBYTES 32 /* may vary between hbas */ -#define SG_ENTRIES_IN_CMD 32 /* Max SG entries excluding chain blocks */ -#define HPSA_SG_CHAIN 0x80000000 -#define MAXREPLYQS 256 - -/* Command Status value */ -#define CMD_SUCCESS 0x0000 -#define CMD_TARGET_STATUS 0x0001 -#define CMD_DATA_UNDERRUN 0x0002 -#define CMD_DATA_OVERRUN 0x0003 -#define CMD_INVALID 0x0004 -#define CMD_PROTOCOL_ERR 0x0005 -#define CMD_HARDWARE_ERR 0x0006 -#define CMD_CONNECTION_LOST 0x0007 -#define CMD_ABORTED 0x0008 -#define CMD_ABORT_FAILED 0x0009 -#define CMD_UNSOLICITED_ABORT 0x000A -#define CMD_TIMEOUT 0x000B -#define CMD_UNABORTABLE 0x000C - -/* Unit Attentions ASC's as defined for the MSA2012sa */ -#define POWER_OR_RESET 0x29 -#define STATE_CHANGED 0x2a -#define UNIT_ATTENTION_CLEARED 0x2f -#define LUN_FAILED 0x3e -#define REPORT_LUNS_CHANGED 0x3f - -/* Unit Attentions ASCQ's as defined for the MSA2012sa */ - - /* These ASCQ's defined for ASC = POWER_OR_RESET */ -#define POWER_ON_RESET 0x00 -#define POWER_ON_REBOOT 0x01 -#define SCSI_BUS_RESET 0x02 -#define MSA_TARGET_RESET 0x03 -#define CONTROLLER_FAILOVER 0x04 -#define TRANSCEIVER_SE 0x05 -#define TRANSCEIVER_LVD 0x06 - - /* These ASCQ's defined for ASC = STATE_CHANGED */ -#define RESERVATION_PREEMPTED 0x03 -#define ASYM_ACCESS_CHANGED 0x06 -#define LUN_CAPACITY_CHANGED 0x09 - -/* transfer direction */ -#define XFER_NONE 0x00 -#define XFER_WRITE 0x01 -#define XFER_READ 0x02 -#define XFER_RSVD 0x03 - -/* task attribute */ -#define ATTR_UNTAGGED 0x00 -#define ATTR_SIMPLE 0x04 -#define ATTR_HEADOFQUEUE 0x05 -#define ATTR_ORDERED 0x06 -#define ATTR_ACA 0x07 - -/* cdb type */ -#define TYPE_CMD 0x00 -#define TYPE_MSG 0x01 - -/* config space register offsets */ -#define CFG_VENDORID 0x00 -#define CFG_DEVICEID 0x02 -#define CFG_I2OBAR 0x10 -#define CFG_MEM1BAR 0x14 - -/* i2o space register offsets */ -#define I2O_IBDB_SET 0x20 -#define I2O_IBDB_CLEAR 0x70 -#define I2O_INT_STATUS 0x30 -#define I2O_INT_MASK 0x34 -#define I2O_IBPOST_Q 0x40 -#define I2O_OBPOST_Q 0x44 -#define I2O_DMA1_CFG 0x214 - -/* Configuration Table */ -#define CFGTBL_ChangeReq 0x00000001l -#define CFGTBL_AccCmds 0x00000001l -#define DOORBELL_CTLR_RESET 0x00000004l -#define DOORBELL_CTLR_RESET2 0x00000020l - -#define CFGTBL_Trans_Simple 0x00000002l -#define CFGTBL_Trans_Performant 0x00000004l -#define CFGTBL_Trans_use_short_tags 0x20000000l - -#define CFGTBL_BusType_Ultra2 0x00000001l -#define CFGTBL_BusType_Ultra3 0x00000002l -#define CFGTBL_BusType_Fibre1G 0x00000100l -#define CFGTBL_BusType_Fibre2G 0x00000200l -struct vals32 { - u32 lower; - u32 upper; -}; - -union u64bit { - struct vals32 val32; - u64 val; -}; - -/* FIXME this is a per controller value (barf!) */ -#define HPSA_MAX_LUN 1024 -#define HPSA_MAX_PHYS_LUN 1024 -#define MAX_EXT_TARGETS 32 -#define HPSA_MAX_DEVICES (HPSA_MAX_PHYS_LUN + HPSA_MAX_LUN + \ - MAX_EXT_TARGETS + 1) /* + 1 is for the controller itself */ - -/* SCSI-3 Commands */ -#pragma pack(1) - -#define HPSA_INQUIRY 0x12 -struct InquiryData { - u8 data_byte[36]; -}; - -#define HPSA_REPORT_LOG 0xc2 /* Report Logical LUNs */ -#define HPSA_REPORT_PHYS 0xc3 /* Report Physical LUNs */ -struct ReportLUNdata { - u8 LUNListLength[4]; - u32 reserved; - u8 LUN[HPSA_MAX_LUN][8]; -}; - -struct ReportExtendedLUNdata { - u8 LUNListLength[4]; - u8 extended_response_flag; - u8 reserved[3]; - u8 LUN[HPSA_MAX_LUN][24]; -}; - -struct SenseSubsystem_info { - u8 reserved[36]; - u8 portname[8]; - u8 reserved1[1108]; -}; - -/* BMIC commands */ -#define BMIC_READ 0x26 -#define BMIC_WRITE 0x27 -#define BMIC_CACHE_FLUSH 0xc2 -#define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */ - -/* Command List Structure */ -union SCSI3Addr { - struct { - u8 Dev; - u8 Bus:6; - u8 Mode:2; /* b00 */ - } PeripDev; - struct { - u8 DevLSB; - u8 DevMSB:6; - u8 Mode:2; /* b01 */ - } LogDev; - struct { - u8 Dev:5; - u8 Bus:3; - u8 Targ:6; - u8 Mode:2; /* b10 */ - } LogUnit; -}; - -struct PhysDevAddr { - u32 TargetId:24; - u32 Bus:6; - u32 Mode:2; - /* 2 level target device addr */ - union SCSI3Addr Target[2]; -}; - -struct LogDevAddr { - u32 VolId:30; - u32 Mode:2; - u8 reserved[4]; -}; - -union LUNAddr { - u8 LunAddrBytes[8]; - union SCSI3Addr SCSI3Lun[4]; - struct PhysDevAddr PhysDev; - struct LogDevAddr LogDev; -}; - -struct CommandListHeader { - u8 ReplyQueue; - u8 SGList; - u16 SGTotal; - struct vals32 Tag; - union LUNAddr LUN; -}; - -struct RequestBlock { - u8 CDBLen; - struct { - u8 Type:3; - u8 Attribute:3; - u8 Direction:2; - } Type; - u16 Timeout; - u8 CDB[16]; -}; - -struct ErrDescriptor { - struct vals32 Addr; - u32 Len; -}; - -struct SGDescriptor { - struct vals32 Addr; - u32 Len; - u32 Ext; -}; - -union MoreErrInfo { - struct { - u8 Reserved[3]; - u8 Type; - u32 ErrorInfo; - } Common_Info; - struct { - u8 Reserved[2]; - u8 offense_size; /* size of offending entry */ - u8 offense_num; /* byte # of offense 0-base */ - u32 offense_value; - } Invalid_Cmd; -}; -struct ErrorInfo { - u8 ScsiStatus; - u8 SenseLen; - u16 CommandStatus; - u32 ResidualCnt; - union MoreErrInfo MoreErrInfo; - u8 SenseInfo[SENSEINFOBYTES]; -}; -/* Command types */ -#define CMD_IOCTL_PEND 0x01 -#define CMD_SCSI 0x03 - -#define DIRECT_LOOKUP_SHIFT 5 -#define DIRECT_LOOKUP_BIT 0x10 -#define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1)) - -#define HPSA_ERROR_BIT 0x02 -struct ctlr_info; /* defined in hpsa.h */ -/* The size of this structure needs to be divisible by 32 - * on all architectures because low 5 bits of the addresses - * are used as follows: - * - * bit 0: to device, used to indicate "performant mode" command - * from device, indidcates error status. - * bit 1-3: to device, indicates block fetch table entry for - * reducing DMA in fetching commands from host memory. - * bit 4: used to indicate whether tag is "direct lookup" (index), - * or a bus address. - */ - -struct CommandList { - struct CommandListHeader Header; - struct RequestBlock Request; - struct ErrDescriptor ErrDesc; - struct SGDescriptor SG[SG_ENTRIES_IN_CMD]; - /* information associated with the command */ - u32 busaddr; /* physical addr of this record */ - struct ErrorInfo *err_info; /* pointer to the allocated mem */ - struct ctlr_info *h; - int cmd_type; - long cmdindex; - struct list_head list; - struct request *rq; - struct completion *waiting; - void *scsi_cmd; - -/* on 64 bit architectures, to get this to be 32-byte-aligned - * it so happens we need PAD_64 bytes of padding, on 32 bit systems, - * we need PAD_32 bytes of padding (see below). This does that. - * If it happens that 64 bit and 32 bit systems need different - * padding, PAD_32 and PAD_64 can be set independently, and. - * the code below will do the right thing. - */ -#define IS_32_BIT ((8 - sizeof(long))/4) -#define IS_64_BIT (!IS_32_BIT) -#define PAD_32 (4) -#define PAD_64 (4) -#define COMMANDLIST_PAD (IS_32_BIT * PAD_32 + IS_64_BIT * PAD_64) - u8 pad[COMMANDLIST_PAD]; -}; - -/* Configuration Table Structure */ -struct HostWrite { - u32 TransportRequest; - u32 Reserved; - u32 CoalIntDelay; - u32 CoalIntCount; -}; - -#define SIMPLE_MODE 0x02 -#define PERFORMANT_MODE 0x04 -#define MEMQ_MODE 0x08 - -struct CfgTable { - u8 Signature[4]; - u32 SpecValence; - u32 TransportSupport; - u32 TransportActive; - struct HostWrite HostWrite; - u32 CmdsOutMax; - u32 BusTypes; - u32 TransMethodOffset; - u8 ServerName[16]; - u32 HeartBeat; - u32 SCSI_Prefetch; - u32 MaxScatterGatherElements; - u32 MaxLogicalUnits; - u32 MaxPhysicalDevices; - u32 MaxPhysicalDrivesPerLogicalUnit; - u32 MaxPerformantModeCommands; - u8 reserved[0x78 - 0x58]; - u32 misc_fw_support; /* offset 0x78 */ -#define MISC_FW_DOORBELL_RESET (0x02) -#define MISC_FW_DOORBELL_RESET2 (0x010) - u8 driver_version[32]; -}; - -#define NUM_BLOCKFETCH_ENTRIES 8 -struct TransTable_struct { - u32 BlockFetch[NUM_BLOCKFETCH_ENTRIES]; - u32 RepQSize; - u32 RepQCount; - u32 RepQCtrAddrLow32; - u32 RepQCtrAddrHigh32; - u32 RepQAddr0Low32; - u32 RepQAddr0High32; -}; - -struct hpsa_pci_info { - unsigned char bus; - unsigned char dev_fn; - unsigned short domain; - u32 board_id; -}; - -#pragma pack() -#endif /* HPSA_CMD_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/hptiop.c b/ANDROID_3.4.5/drivers/scsi/hptiop.c deleted file mode 100644 index 10b65556..00000000 --- a/ANDROID_3.4.5/drivers/scsi/hptiop.c +++ /dev/null @@ -1,1311 +0,0 @@ -/* - * HighPoint RR3xxx/4xxx controller driver for Linux - * Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Please report bugs/comments/suggestions to linux@highpoint-tech.com - * - * For more information, visit http://www.highpoint-tech.com - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "hptiop.h" - -MODULE_AUTHOR("HighPoint Technologies, Inc."); -MODULE_DESCRIPTION("HighPoint RocketRAID 3xxx/4xxx Controller Driver"); - -static char driver_name[] = "hptiop"; -static const char driver_name_long[] = "RocketRAID 3xxx/4xxx Controller driver"; -static const char driver_ver[] = "v1.6 (090910)"; - -static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec); -static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag, - struct hpt_iop_request_scsi_command *req); -static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 tag); -static void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag); -static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg); - -static int iop_wait_ready_itl(struct hptiop_hba *hba, u32 millisec) -{ - u32 req = 0; - int i; - - for (i = 0; i < millisec; i++) { - req = readl(&hba->u.itl.iop->inbound_queue); - if (req != IOPMU_QUEUE_EMPTY) - break; - msleep(1); - } - - if (req != IOPMU_QUEUE_EMPTY) { - writel(req, &hba->u.itl.iop->outbound_queue); - readl(&hba->u.itl.iop->outbound_intstatus); - return 0; - } - - return -1; -} - -static int iop_wait_ready_mv(struct hptiop_hba *hba, u32 millisec) -{ - return iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_NOP, millisec); -} - -static void hptiop_request_callback_itl(struct hptiop_hba *hba, u32 tag) -{ - if (tag & IOPMU_QUEUE_ADDR_HOST_BIT) - hptiop_host_request_callback_itl(hba, - tag & ~IOPMU_QUEUE_ADDR_HOST_BIT); - else - hptiop_iop_request_callback_itl(hba, tag); -} - -static void hptiop_drain_outbound_queue_itl(struct hptiop_hba *hba) -{ - u32 req; - - while ((req = readl(&hba->u.itl.iop->outbound_queue)) != - IOPMU_QUEUE_EMPTY) { - - if (req & IOPMU_QUEUE_MASK_HOST_BITS) - hptiop_request_callback_itl(hba, req); - else { - struct hpt_iop_request_header __iomem * p; - - p = (struct hpt_iop_request_header __iomem *) - ((char __iomem *)hba->u.itl.iop + req); - - if (readl(&p->flags) & IOP_REQUEST_FLAG_SYNC_REQUEST) { - if (readl(&p->context)) - hptiop_request_callback_itl(hba, req); - else - writel(1, &p->context); - } - else - hptiop_request_callback_itl(hba, req); - } - } -} - -static int iop_intr_itl(struct hptiop_hba *hba) -{ - struct hpt_iopmu_itl __iomem *iop = hba->u.itl.iop; - void __iomem *plx = hba->u.itl.plx; - u32 status; - int ret = 0; - - if (plx && readl(plx + 0x11C5C) & 0xf) - writel(1, plx + 0x11C60); - - status = readl(&iop->outbound_intstatus); - - if (status & IOPMU_OUTBOUND_INT_MSG0) { - u32 msg = readl(&iop->outbound_msgaddr0); - - dprintk("received outbound msg %x\n", msg); - writel(IOPMU_OUTBOUND_INT_MSG0, &iop->outbound_intstatus); - hptiop_message_callback(hba, msg); - ret = 1; - } - - if (status & IOPMU_OUTBOUND_INT_POSTQUEUE) { - hptiop_drain_outbound_queue_itl(hba); - ret = 1; - } - - return ret; -} - -static u64 mv_outbound_read(struct hpt_iopmu_mv __iomem *mu) -{ - u32 outbound_tail = readl(&mu->outbound_tail); - u32 outbound_head = readl(&mu->outbound_head); - - if (outbound_tail != outbound_head) { - u64 p; - - memcpy_fromio(&p, &mu->outbound_q[mu->outbound_tail], 8); - outbound_tail++; - - if (outbound_tail == MVIOP_QUEUE_LEN) - outbound_tail = 0; - writel(outbound_tail, &mu->outbound_tail); - return p; - } else - return 0; -} - -static void mv_inbound_write(u64 p, struct hptiop_hba *hba) -{ - u32 inbound_head = readl(&hba->u.mv.mu->inbound_head); - u32 head = inbound_head + 1; - - if (head == MVIOP_QUEUE_LEN) - head = 0; - - memcpy_toio(&hba->u.mv.mu->inbound_q[inbound_head], &p, 8); - writel(head, &hba->u.mv.mu->inbound_head); - writel(MVIOP_MU_INBOUND_INT_POSTQUEUE, - &hba->u.mv.regs->inbound_doorbell); -} - -static void hptiop_request_callback_mv(struct hptiop_hba *hba, u64 tag) -{ - u32 req_type = (tag >> 5) & 0x7; - struct hpt_iop_request_scsi_command *req; - - dprintk("hptiop_request_callback_mv: tag=%llx\n", tag); - - BUG_ON((tag & MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT) == 0); - - switch (req_type) { - case IOP_REQUEST_TYPE_GET_CONFIG: - case IOP_REQUEST_TYPE_SET_CONFIG: - hba->msg_done = 1; - break; - - case IOP_REQUEST_TYPE_SCSI_COMMAND: - req = hba->reqs[tag >> 8].req_virt; - if (likely(tag & MVIOP_MU_QUEUE_REQUEST_RESULT_BIT)) - req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS); - - hptiop_finish_scsi_req(hba, tag>>8, req); - break; - - default: - break; - } -} - -static int iop_intr_mv(struct hptiop_hba *hba) -{ - u32 status; - int ret = 0; - - status = readl(&hba->u.mv.regs->outbound_doorbell); - writel(~status, &hba->u.mv.regs->outbound_doorbell); - - if (status & MVIOP_MU_OUTBOUND_INT_MSG) { - u32 msg; - msg = readl(&hba->u.mv.mu->outbound_msg); - dprintk("received outbound msg %x\n", msg); - hptiop_message_callback(hba, msg); - ret = 1; - } - - if (status & MVIOP_MU_OUTBOUND_INT_POSTQUEUE) { - u64 tag; - - while ((tag = mv_outbound_read(hba->u.mv.mu))) - hptiop_request_callback_mv(hba, tag); - ret = 1; - } - - return ret; -} - -static int iop_send_sync_request_itl(struct hptiop_hba *hba, - void __iomem *_req, u32 millisec) -{ - struct hpt_iop_request_header __iomem *req = _req; - u32 i; - - writel(readl(&req->flags) | IOP_REQUEST_FLAG_SYNC_REQUEST, &req->flags); - writel(0, &req->context); - writel((unsigned long)req - (unsigned long)hba->u.itl.iop, - &hba->u.itl.iop->inbound_queue); - readl(&hba->u.itl.iop->outbound_intstatus); - - for (i = 0; i < millisec; i++) { - iop_intr_itl(hba); - if (readl(&req->context)) - return 0; - msleep(1); - } - - return -1; -} - -static int iop_send_sync_request_mv(struct hptiop_hba *hba, - u32 size_bits, u32 millisec) -{ - struct hpt_iop_request_header *reqhdr = hba->u.mv.internal_req; - u32 i; - - hba->msg_done = 0; - reqhdr->flags |= cpu_to_le32(IOP_REQUEST_FLAG_SYNC_REQUEST); - mv_inbound_write(hba->u.mv.internal_req_phy | - MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bits, hba); - - for (i = 0; i < millisec; i++) { - iop_intr_mv(hba); - if (hba->msg_done) - return 0; - msleep(1); - } - return -1; -} - -static void hptiop_post_msg_itl(struct hptiop_hba *hba, u32 msg) -{ - writel(msg, &hba->u.itl.iop->inbound_msgaddr0); - readl(&hba->u.itl.iop->outbound_intstatus); -} - -static void hptiop_post_msg_mv(struct hptiop_hba *hba, u32 msg) -{ - writel(msg, &hba->u.mv.mu->inbound_msg); - writel(MVIOP_MU_INBOUND_INT_MSG, &hba->u.mv.regs->inbound_doorbell); - readl(&hba->u.mv.regs->inbound_doorbell); -} - -static int iop_send_sync_msg(struct hptiop_hba *hba, u32 msg, u32 millisec) -{ - u32 i; - - hba->msg_done = 0; - hba->ops->post_msg(hba, msg); - - for (i = 0; i < millisec; i++) { - spin_lock_irq(hba->host->host_lock); - hba->ops->iop_intr(hba); - spin_unlock_irq(hba->host->host_lock); - if (hba->msg_done) - break; - msleep(1); - } - - return hba->msg_done? 0 : -1; -} - -static int iop_get_config_itl(struct hptiop_hba *hba, - struct hpt_iop_request_get_config *config) -{ - u32 req32; - struct hpt_iop_request_get_config __iomem *req; - - req32 = readl(&hba->u.itl.iop->inbound_queue); - if (req32 == IOPMU_QUEUE_EMPTY) - return -1; - - req = (struct hpt_iop_request_get_config __iomem *) - ((unsigned long)hba->u.itl.iop + req32); - - writel(0, &req->header.flags); - writel(IOP_REQUEST_TYPE_GET_CONFIG, &req->header.type); - writel(sizeof(struct hpt_iop_request_get_config), &req->header.size); - writel(IOP_RESULT_PENDING, &req->header.result); - - if (iop_send_sync_request_itl(hba, req, 20000)) { - dprintk("Get config send cmd failed\n"); - return -1; - } - - memcpy_fromio(config, req, sizeof(*config)); - writel(req32, &hba->u.itl.iop->outbound_queue); - return 0; -} - -static int iop_get_config_mv(struct hptiop_hba *hba, - struct hpt_iop_request_get_config *config) -{ - struct hpt_iop_request_get_config *req = hba->u.mv.internal_req; - - req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT); - req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG); - req->header.size = - cpu_to_le32(sizeof(struct hpt_iop_request_get_config)); - req->header.result = cpu_to_le32(IOP_RESULT_PENDING); - req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_GET_CONFIG<<5); - req->header.context_hi32 = 0; - - if (iop_send_sync_request_mv(hba, 0, 20000)) { - dprintk("Get config send cmd failed\n"); - return -1; - } - - memcpy(config, req, sizeof(struct hpt_iop_request_get_config)); - return 0; -} - -static int iop_set_config_itl(struct hptiop_hba *hba, - struct hpt_iop_request_set_config *config) -{ - u32 req32; - struct hpt_iop_request_set_config __iomem *req; - - req32 = readl(&hba->u.itl.iop->inbound_queue); - if (req32 == IOPMU_QUEUE_EMPTY) - return -1; - - req = (struct hpt_iop_request_set_config __iomem *) - ((unsigned long)hba->u.itl.iop + req32); - - memcpy_toio((u8 __iomem *)req + sizeof(struct hpt_iop_request_header), - (u8 *)config + sizeof(struct hpt_iop_request_header), - sizeof(struct hpt_iop_request_set_config) - - sizeof(struct hpt_iop_request_header)); - - writel(0, &req->header.flags); - writel(IOP_REQUEST_TYPE_SET_CONFIG, &req->header.type); - writel(sizeof(struct hpt_iop_request_set_config), &req->header.size); - writel(IOP_RESULT_PENDING, &req->header.result); - - if (iop_send_sync_request_itl(hba, req, 20000)) { - dprintk("Set config send cmd failed\n"); - return -1; - } - - writel(req32, &hba->u.itl.iop->outbound_queue); - return 0; -} - -static int iop_set_config_mv(struct hptiop_hba *hba, - struct hpt_iop_request_set_config *config) -{ - struct hpt_iop_request_set_config *req = hba->u.mv.internal_req; - - memcpy(req, config, sizeof(struct hpt_iop_request_set_config)); - req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT); - req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG); - req->header.size = - cpu_to_le32(sizeof(struct hpt_iop_request_set_config)); - req->header.result = cpu_to_le32(IOP_RESULT_PENDING); - req->header.context = cpu_to_le32(IOP_REQUEST_TYPE_SET_CONFIG<<5); - req->header.context_hi32 = 0; - - if (iop_send_sync_request_mv(hba, 0, 20000)) { - dprintk("Set config send cmd failed\n"); - return -1; - } - - return 0; -} - -static void hptiop_enable_intr_itl(struct hptiop_hba *hba) -{ - writel(~(IOPMU_OUTBOUND_INT_POSTQUEUE | IOPMU_OUTBOUND_INT_MSG0), - &hba->u.itl.iop->outbound_intmask); -} - -static void hptiop_enable_intr_mv(struct hptiop_hba *hba) -{ - writel(MVIOP_MU_OUTBOUND_INT_POSTQUEUE | MVIOP_MU_OUTBOUND_INT_MSG, - &hba->u.mv.regs->outbound_intmask); -} - -static int hptiop_initialize_iop(struct hptiop_hba *hba) -{ - /* enable interrupts */ - hba->ops->enable_intr(hba); - - hba->initialized = 1; - - /* start background tasks */ - if (iop_send_sync_msg(hba, - IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) { - printk(KERN_ERR "scsi%d: fail to start background task\n", - hba->host->host_no); - return -1; - } - return 0; -} - -static void __iomem *hptiop_map_pci_bar(struct hptiop_hba *hba, int index) -{ - u32 mem_base_phy, length; - void __iomem *mem_base_virt; - - struct pci_dev *pcidev = hba->pcidev; - - - if (!(pci_resource_flags(pcidev, index) & IORESOURCE_MEM)) { - printk(KERN_ERR "scsi%d: pci resource invalid\n", - hba->host->host_no); - return NULL; - } - - mem_base_phy = pci_resource_start(pcidev, index); - length = pci_resource_len(pcidev, index); - mem_base_virt = ioremap(mem_base_phy, length); - - if (!mem_base_virt) { - printk(KERN_ERR "scsi%d: Fail to ioremap memory space\n", - hba->host->host_no); - return NULL; - } - return mem_base_virt; -} - -static int hptiop_map_pci_bar_itl(struct hptiop_hba *hba) -{ - struct pci_dev *pcidev = hba->pcidev; - hba->u.itl.iop = hptiop_map_pci_bar(hba, 0); - if (hba->u.itl.iop == NULL) - return -1; - if ((pcidev->device & 0xff00) == 0x4400) { - hba->u.itl.plx = hba->u.itl.iop; - hba->u.itl.iop = hptiop_map_pci_bar(hba, 2); - if (hba->u.itl.iop == NULL) { - iounmap(hba->u.itl.plx); - return -1; - } - } - return 0; -} - -static void hptiop_unmap_pci_bar_itl(struct hptiop_hba *hba) -{ - if (hba->u.itl.plx) - iounmap(hba->u.itl.plx); - iounmap(hba->u.itl.iop); -} - -static int hptiop_map_pci_bar_mv(struct hptiop_hba *hba) -{ - hba->u.mv.regs = hptiop_map_pci_bar(hba, 0); - if (hba->u.mv.regs == NULL) - return -1; - - hba->u.mv.mu = hptiop_map_pci_bar(hba, 2); - if (hba->u.mv.mu == NULL) { - iounmap(hba->u.mv.regs); - return -1; - } - - return 0; -} - -static void hptiop_unmap_pci_bar_mv(struct hptiop_hba *hba) -{ - iounmap(hba->u.mv.regs); - iounmap(hba->u.mv.mu); -} - -static void hptiop_message_callback(struct hptiop_hba *hba, u32 msg) -{ - dprintk("iop message 0x%x\n", msg); - - if (msg == IOPMU_INBOUND_MSG0_NOP) - hba->msg_done = 1; - - if (!hba->initialized) - return; - - if (msg == IOPMU_INBOUND_MSG0_RESET) { - atomic_set(&hba->resetting, 0); - wake_up(&hba->reset_wq); - } - else if (msg <= IOPMU_INBOUND_MSG0_MAX) - hba->msg_done = 1; -} - -static struct hptiop_request *get_req(struct hptiop_hba *hba) -{ - struct hptiop_request *ret; - - dprintk("get_req : req=%p\n", hba->req_list); - - ret = hba->req_list; - if (ret) - hba->req_list = ret->next; - - return ret; -} - -static void free_req(struct hptiop_hba *hba, struct hptiop_request *req) -{ - dprintk("free_req(%d, %p)\n", req->index, req); - req->next = hba->req_list; - hba->req_list = req; -} - -static void hptiop_finish_scsi_req(struct hptiop_hba *hba, u32 tag, - struct hpt_iop_request_scsi_command *req) -{ - struct scsi_cmnd *scp; - - dprintk("hptiop_finish_scsi_req: req=%p, type=%d, " - "result=%d, context=0x%x tag=%d\n", - req, req->header.type, req->header.result, - req->header.context, tag); - - BUG_ON(!req->header.result); - BUG_ON(req->header.type != cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND)); - - scp = hba->reqs[tag].scp; - - if (HPT_SCP(scp)->mapped) - scsi_dma_unmap(scp); - - switch (le32_to_cpu(req->header.result)) { - case IOP_RESULT_SUCCESS: - scsi_set_resid(scp, - scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length)); - scp->result = (DID_OK<<16); - break; - case IOP_RESULT_BAD_TARGET: - scp->result = (DID_BAD_TARGET<<16); - break; - case IOP_RESULT_BUSY: - scp->result = (DID_BUS_BUSY<<16); - break; - case IOP_RESULT_RESET: - scp->result = (DID_RESET<<16); - break; - case IOP_RESULT_FAIL: - scp->result = (DID_ERROR<<16); - break; - case IOP_RESULT_INVALID_REQUEST: - scp->result = (DID_ABORT<<16); - break; - case IOP_RESULT_CHECK_CONDITION: - scsi_set_resid(scp, - scsi_bufflen(scp) - le32_to_cpu(req->dataxfer_length)); - scp->result = SAM_STAT_CHECK_CONDITION; - memcpy(scp->sense_buffer, &req->sg_list, - min_t(size_t, SCSI_SENSE_BUFFERSIZE, - le32_to_cpu(req->dataxfer_length))); - break; - - default: - scp->result = DRIVER_INVALID << 24 | DID_ABORT << 16; - break; - } - - dprintk("scsi_done(%p)\n", scp); - scp->scsi_done(scp); - free_req(hba, &hba->reqs[tag]); -} - -static void hptiop_host_request_callback_itl(struct hptiop_hba *hba, u32 _tag) -{ - struct hpt_iop_request_scsi_command *req; - u32 tag; - - if (hba->iopintf_v2) { - tag = _tag & ~IOPMU_QUEUE_REQUEST_RESULT_BIT; - req = hba->reqs[tag].req_virt; - if (likely(_tag & IOPMU_QUEUE_REQUEST_RESULT_BIT)) - req->header.result = cpu_to_le32(IOP_RESULT_SUCCESS); - } else { - tag = _tag; - req = hba->reqs[tag].req_virt; - } - - hptiop_finish_scsi_req(hba, tag, req); -} - -void hptiop_iop_request_callback_itl(struct hptiop_hba *hba, u32 tag) -{ - struct hpt_iop_request_header __iomem *req; - struct hpt_iop_request_ioctl_command __iomem *p; - struct hpt_ioctl_k *arg; - - req = (struct hpt_iop_request_header __iomem *) - ((unsigned long)hba->u.itl.iop + tag); - dprintk("hptiop_iop_request_callback_itl: req=%p, type=%d, " - "result=%d, context=0x%x tag=%d\n", - req, readl(&req->type), readl(&req->result), - readl(&req->context), tag); - - BUG_ON(!readl(&req->result)); - BUG_ON(readl(&req->type) != IOP_REQUEST_TYPE_IOCTL_COMMAND); - - p = (struct hpt_iop_request_ioctl_command __iomem *)req; - arg = (struct hpt_ioctl_k *)(unsigned long) - (readl(&req->context) | - ((u64)readl(&req->context_hi32)<<32)); - - if (readl(&req->result) == IOP_RESULT_SUCCESS) { - arg->result = HPT_IOCTL_RESULT_OK; - - if (arg->outbuf_size) - memcpy_fromio(arg->outbuf, - &p->buf[(readl(&p->inbuf_size) + 3)& ~3], - arg->outbuf_size); - - if (arg->bytes_returned) - *arg->bytes_returned = arg->outbuf_size; - } - else - arg->result = HPT_IOCTL_RESULT_FAILED; - - arg->done(arg); - writel(tag, &hba->u.itl.iop->outbound_queue); -} - -static irqreturn_t hptiop_intr(int irq, void *dev_id) -{ - struct hptiop_hba *hba = dev_id; - int handled; - unsigned long flags; - - spin_lock_irqsave(hba->host->host_lock, flags); - handled = hba->ops->iop_intr(hba); - spin_unlock_irqrestore(hba->host->host_lock, flags); - - return handled; -} - -static int hptiop_buildsgl(struct scsi_cmnd *scp, struct hpt_iopsg *psg) -{ - struct Scsi_Host *host = scp->device->host; - struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; - struct scatterlist *sg; - int idx, nseg; - - nseg = scsi_dma_map(scp); - BUG_ON(nseg < 0); - if (!nseg) - return 0; - - HPT_SCP(scp)->sgcnt = nseg; - HPT_SCP(scp)->mapped = 1; - - BUG_ON(HPT_SCP(scp)->sgcnt > hba->max_sg_descriptors); - - scsi_for_each_sg(scp, sg, HPT_SCP(scp)->sgcnt, idx) { - psg[idx].pci_address = cpu_to_le64(sg_dma_address(sg)); - psg[idx].size = cpu_to_le32(sg_dma_len(sg)); - psg[idx].eot = (idx == HPT_SCP(scp)->sgcnt - 1) ? - cpu_to_le32(1) : 0; - } - return HPT_SCP(scp)->sgcnt; -} - -static void hptiop_post_req_itl(struct hptiop_hba *hba, - struct hptiop_request *_req) -{ - struct hpt_iop_request_header *reqhdr = _req->req_virt; - - reqhdr->context = cpu_to_le32(IOPMU_QUEUE_ADDR_HOST_BIT | - (u32)_req->index); - reqhdr->context_hi32 = 0; - - if (hba->iopintf_v2) { - u32 size, size_bits; - - size = le32_to_cpu(reqhdr->size); - if (size < 256) - size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT; - else if (size < 512) - size_bits = IOPMU_QUEUE_ADDR_HOST_BIT; - else - size_bits = IOPMU_QUEUE_REQUEST_SIZE_BIT | - IOPMU_QUEUE_ADDR_HOST_BIT; - writel(_req->req_shifted_phy | size_bits, - &hba->u.itl.iop->inbound_queue); - } else - writel(_req->req_shifted_phy | IOPMU_QUEUE_ADDR_HOST_BIT, - &hba->u.itl.iop->inbound_queue); -} - -static void hptiop_post_req_mv(struct hptiop_hba *hba, - struct hptiop_request *_req) -{ - struct hpt_iop_request_header *reqhdr = _req->req_virt; - u32 size, size_bit; - - reqhdr->context = cpu_to_le32(_req->index<<8 | - IOP_REQUEST_TYPE_SCSI_COMMAND<<5); - reqhdr->context_hi32 = 0; - size = le32_to_cpu(reqhdr->size); - - if (size <= 256) - size_bit = 0; - else if (size <= 256*2) - size_bit = 1; - else if (size <= 256*3) - size_bit = 2; - else - size_bit = 3; - - mv_inbound_write((_req->req_shifted_phy << 5) | - MVIOP_MU_QUEUE_ADDR_HOST_BIT | size_bit, hba); -} - -static int hptiop_queuecommand_lck(struct scsi_cmnd *scp, - void (*done)(struct scsi_cmnd *)) -{ - struct Scsi_Host *host = scp->device->host; - struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; - struct hpt_iop_request_scsi_command *req; - int sg_count = 0; - struct hptiop_request *_req; - - BUG_ON(!done); - scp->scsi_done = done; - - _req = get_req(hba); - if (_req == NULL) { - dprintk("hptiop_queuecmd : no free req\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - - _req->scp = scp; - - dprintk("hptiop_queuecmd(scp=%p) %d/%d/%d/%d cdb=(%x-%x-%x) " - "req_index=%d, req=%p\n", - scp, - host->host_no, scp->device->channel, - scp->device->id, scp->device->lun, - ((u32 *)scp->cmnd)[0], - ((u32 *)scp->cmnd)[1], - ((u32 *)scp->cmnd)[2], - _req->index, _req->req_virt); - - scp->result = 0; - - if (scp->device->channel || scp->device->lun || - scp->device->id > hba->max_devices) { - scp->result = DID_BAD_TARGET << 16; - free_req(hba, _req); - goto cmd_done; - } - - req = _req->req_virt; - - /* build S/G table */ - sg_count = hptiop_buildsgl(scp, req->sg_list); - if (!sg_count) - HPT_SCP(scp)->mapped = 0; - - req->header.flags = cpu_to_le32(IOP_REQUEST_FLAG_OUTPUT_CONTEXT); - req->header.type = cpu_to_le32(IOP_REQUEST_TYPE_SCSI_COMMAND); - req->header.result = cpu_to_le32(IOP_RESULT_PENDING); - req->dataxfer_length = cpu_to_le32(scsi_bufflen(scp)); - req->channel = scp->device->channel; - req->target = scp->device->id; - req->lun = scp->device->lun; - req->header.size = cpu_to_le32( - sizeof(struct hpt_iop_request_scsi_command) - - sizeof(struct hpt_iopsg) - + sg_count * sizeof(struct hpt_iopsg)); - - memcpy(req->cdb, scp->cmnd, sizeof(req->cdb)); - hba->ops->post_req(hba, _req); - return 0; - -cmd_done: - dprintk("scsi_done(scp=%p)\n", scp); - scp->scsi_done(scp); - return 0; -} - -static DEF_SCSI_QCMD(hptiop_queuecommand) - -static const char *hptiop_info(struct Scsi_Host *host) -{ - return driver_name_long; -} - -static int hptiop_reset_hba(struct hptiop_hba *hba) -{ - if (atomic_xchg(&hba->resetting, 1) == 0) { - atomic_inc(&hba->reset_count); - hba->ops->post_msg(hba, IOPMU_INBOUND_MSG0_RESET); - } - - wait_event_timeout(hba->reset_wq, - atomic_read(&hba->resetting) == 0, 60 * HZ); - - if (atomic_read(&hba->resetting)) { - /* IOP is in unknown state, abort reset */ - printk(KERN_ERR "scsi%d: reset failed\n", hba->host->host_no); - return -1; - } - - if (iop_send_sync_msg(hba, - IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, 5000)) { - dprintk("scsi%d: fail to start background task\n", - hba->host->host_no); - } - - return 0; -} - -static int hptiop_reset(struct scsi_cmnd *scp) -{ - struct Scsi_Host * host = scp->device->host; - struct hptiop_hba * hba = (struct hptiop_hba *)host->hostdata; - - printk(KERN_WARNING "hptiop_reset(%d/%d/%d) scp=%p\n", - scp->device->host->host_no, scp->device->channel, - scp->device->id, scp); - - return hptiop_reset_hba(hba)? FAILED : SUCCESS; -} - -static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev, - int queue_depth, int reason) -{ - struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata; - - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (queue_depth > hba->max_requests) - queue_depth = hba->max_requests; - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth); - return queue_depth; -} - -static ssize_t hptiop_show_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", driver_ver); -} - -static ssize_t hptiop_show_fw_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; - - return snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n", - hba->firmware_version >> 24, - (hba->firmware_version >> 16) & 0xff, - (hba->firmware_version >> 8) & 0xff, - hba->firmware_version & 0xff); -} - -static struct device_attribute hptiop_attr_version = { - .attr = { - .name = "driver-version", - .mode = S_IRUGO, - }, - .show = hptiop_show_version, -}; - -static struct device_attribute hptiop_attr_fw_version = { - .attr = { - .name = "firmware-version", - .mode = S_IRUGO, - }, - .show = hptiop_show_fw_version, -}; - -static struct device_attribute *hptiop_attrs[] = { - &hptiop_attr_version, - &hptiop_attr_fw_version, - NULL -}; - -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = driver_name, - .queuecommand = hptiop_queuecommand, - .eh_device_reset_handler = hptiop_reset, - .eh_bus_reset_handler = hptiop_reset, - .info = hptiop_info, - .emulated = 0, - .use_clustering = ENABLE_CLUSTERING, - .proc_name = driver_name, - .shost_attrs = hptiop_attrs, - .this_id = -1, - .change_queue_depth = hptiop_adjust_disk_queue_depth, -}; - -static int hptiop_internal_memalloc_mv(struct hptiop_hba *hba) -{ - hba->u.mv.internal_req = dma_alloc_coherent(&hba->pcidev->dev, - 0x800, &hba->u.mv.internal_req_phy, GFP_KERNEL); - if (hba->u.mv.internal_req) - return 0; - else - return -1; -} - -static int hptiop_internal_memfree_mv(struct hptiop_hba *hba) -{ - if (hba->u.mv.internal_req) { - dma_free_coherent(&hba->pcidev->dev, 0x800, - hba->u.mv.internal_req, hba->u.mv.internal_req_phy); - return 0; - } else - return -1; -} - -static int __devinit hptiop_probe(struct pci_dev *pcidev, - const struct pci_device_id *id) -{ - struct Scsi_Host *host = NULL; - struct hptiop_hba *hba; - struct hpt_iop_request_get_config iop_config; - struct hpt_iop_request_set_config set_config; - dma_addr_t start_phy; - void *start_virt; - u32 offset, i, req_size; - - dprintk("hptiop_probe(%p)\n", pcidev); - - if (pci_enable_device(pcidev)) { - printk(KERN_ERR "hptiop: fail to enable pci device\n"); - return -ENODEV; - } - - printk(KERN_INFO "adapter at PCI %d:%d:%d, IRQ %d\n", - pcidev->bus->number, pcidev->devfn >> 3, pcidev->devfn & 7, - pcidev->irq); - - pci_set_master(pcidev); - - /* Enable 64bit DMA if possible */ - if (pci_set_dma_mask(pcidev, DMA_BIT_MASK(64))) { - if (pci_set_dma_mask(pcidev, DMA_BIT_MASK(32))) { - printk(KERN_ERR "hptiop: fail to set dma_mask\n"); - goto disable_pci_device; - } - } - - if (pci_request_regions(pcidev, driver_name)) { - printk(KERN_ERR "hptiop: pci_request_regions failed\n"); - goto disable_pci_device; - } - - host = scsi_host_alloc(&driver_template, sizeof(struct hptiop_hba)); - if (!host) { - printk(KERN_ERR "hptiop: fail to alloc scsi host\n"); - goto free_pci_regions; - } - - hba = (struct hptiop_hba *)host->hostdata; - - hba->ops = (struct hptiop_adapter_ops *)id->driver_data; - hba->pcidev = pcidev; - hba->host = host; - hba->initialized = 0; - hba->iopintf_v2 = 0; - - atomic_set(&hba->resetting, 0); - atomic_set(&hba->reset_count, 0); - - init_waitqueue_head(&hba->reset_wq); - init_waitqueue_head(&hba->ioctl_wq); - - host->max_lun = 1; - host->max_channel = 0; - host->io_port = 0; - host->n_io_port = 0; - host->irq = pcidev->irq; - - if (hba->ops->map_pci_bar(hba)) - goto free_scsi_host; - - if (hba->ops->iop_wait_ready(hba, 20000)) { - printk(KERN_ERR "scsi%d: firmware not ready\n", - hba->host->host_no); - goto unmap_pci_bar; - } - - if (hba->ops->internal_memalloc) { - if (hba->ops->internal_memalloc(hba)) { - printk(KERN_ERR "scsi%d: internal_memalloc failed\n", - hba->host->host_no); - goto unmap_pci_bar; - } - } - - if (hba->ops->get_config(hba, &iop_config)) { - printk(KERN_ERR "scsi%d: get config failed\n", - hba->host->host_no); - goto unmap_pci_bar; - } - - hba->max_requests = min(le32_to_cpu(iop_config.max_requests), - HPTIOP_MAX_REQUESTS); - hba->max_devices = le32_to_cpu(iop_config.max_devices); - hba->max_request_size = le32_to_cpu(iop_config.request_size); - hba->max_sg_descriptors = le32_to_cpu(iop_config.max_sg_count); - hba->firmware_version = le32_to_cpu(iop_config.firmware_version); - hba->interface_version = le32_to_cpu(iop_config.interface_version); - hba->sdram_size = le32_to_cpu(iop_config.sdram_size); - - if (hba->firmware_version > 0x01020000 || - hba->interface_version > 0x01020000) - hba->iopintf_v2 = 1; - - host->max_sectors = le32_to_cpu(iop_config.data_transfer_length) >> 9; - host->max_id = le32_to_cpu(iop_config.max_devices); - host->sg_tablesize = le32_to_cpu(iop_config.max_sg_count); - host->can_queue = le32_to_cpu(iop_config.max_requests); - host->cmd_per_lun = le32_to_cpu(iop_config.max_requests); - host->max_cmd_len = 16; - - req_size = sizeof(struct hpt_iop_request_scsi_command) - + sizeof(struct hpt_iopsg) * (hba->max_sg_descriptors - 1); - if ((req_size & 0x1f) != 0) - req_size = (req_size + 0x1f) & ~0x1f; - - memset(&set_config, 0, sizeof(struct hpt_iop_request_set_config)); - set_config.iop_id = cpu_to_le32(host->host_no); - set_config.vbus_id = cpu_to_le16(host->host_no); - set_config.max_host_request_size = cpu_to_le16(req_size); - - if (hba->ops->set_config(hba, &set_config)) { - printk(KERN_ERR "scsi%d: set config failed\n", - hba->host->host_no); - goto unmap_pci_bar; - } - - pci_set_drvdata(pcidev, host); - - if (request_irq(pcidev->irq, hptiop_intr, IRQF_SHARED, - driver_name, hba)) { - printk(KERN_ERR "scsi%d: request irq %d failed\n", - hba->host->host_no, pcidev->irq); - goto unmap_pci_bar; - } - - /* Allocate request mem */ - - dprintk("req_size=%d, max_requests=%d\n", req_size, hba->max_requests); - - hba->req_size = req_size; - start_virt = dma_alloc_coherent(&pcidev->dev, - hba->req_size*hba->max_requests + 0x20, - &start_phy, GFP_KERNEL); - - if (!start_virt) { - printk(KERN_ERR "scsi%d: fail to alloc request mem\n", - hba->host->host_no); - goto free_request_irq; - } - - hba->dma_coherent = start_virt; - hba->dma_coherent_handle = start_phy; - - if ((start_phy & 0x1f) != 0) - { - offset = ((start_phy + 0x1f) & ~0x1f) - start_phy; - start_phy += offset; - start_virt += offset; - } - - hba->req_list = start_virt; - for (i = 0; i < hba->max_requests; i++) { - hba->reqs[i].next = NULL; - hba->reqs[i].req_virt = start_virt; - hba->reqs[i].req_shifted_phy = start_phy >> 5; - hba->reqs[i].index = i; - free_req(hba, &hba->reqs[i]); - start_virt = (char *)start_virt + hba->req_size; - start_phy = start_phy + hba->req_size; - } - - /* Enable Interrupt and start background task */ - if (hptiop_initialize_iop(hba)) - goto free_request_mem; - - if (scsi_add_host(host, &pcidev->dev)) { - printk(KERN_ERR "scsi%d: scsi_add_host failed\n", - hba->host->host_no); - goto free_request_mem; - } - - - scsi_scan_host(host); - - dprintk("scsi%d: hptiop_probe successfully\n", hba->host->host_no); - return 0; - -free_request_mem: - dma_free_coherent(&hba->pcidev->dev, - hba->req_size * hba->max_requests + 0x20, - hba->dma_coherent, hba->dma_coherent_handle); - -free_request_irq: - free_irq(hba->pcidev->irq, hba); - -unmap_pci_bar: - if (hba->ops->internal_memfree) - hba->ops->internal_memfree(hba); - - hba->ops->unmap_pci_bar(hba); - -free_scsi_host: - scsi_host_put(host); - -free_pci_regions: - pci_release_regions(pcidev); - -disable_pci_device: - pci_disable_device(pcidev); - - dprintk("scsi%d: hptiop_probe fail\n", host ? host->host_no : 0); - return -ENODEV; -} - -static void hptiop_shutdown(struct pci_dev *pcidev) -{ - struct Scsi_Host *host = pci_get_drvdata(pcidev); - struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; - - dprintk("hptiop_shutdown(%p)\n", hba); - - /* stop the iop */ - if (iop_send_sync_msg(hba, IOPMU_INBOUND_MSG0_SHUTDOWN, 60000)) - printk(KERN_ERR "scsi%d: shutdown the iop timeout\n", - hba->host->host_no); - - /* disable all outbound interrupts */ - hba->ops->disable_intr(hba); -} - -static void hptiop_disable_intr_itl(struct hptiop_hba *hba) -{ - u32 int_mask; - - int_mask = readl(&hba->u.itl.iop->outbound_intmask); - writel(int_mask | - IOPMU_OUTBOUND_INT_MSG0 | IOPMU_OUTBOUND_INT_POSTQUEUE, - &hba->u.itl.iop->outbound_intmask); - readl(&hba->u.itl.iop->outbound_intmask); -} - -static void hptiop_disable_intr_mv(struct hptiop_hba *hba) -{ - writel(0, &hba->u.mv.regs->outbound_intmask); - readl(&hba->u.mv.regs->outbound_intmask); -} - -static void hptiop_remove(struct pci_dev *pcidev) -{ - struct Scsi_Host *host = pci_get_drvdata(pcidev); - struct hptiop_hba *hba = (struct hptiop_hba *)host->hostdata; - - dprintk("scsi%d: hptiop_remove\n", hba->host->host_no); - - scsi_remove_host(host); - - hptiop_shutdown(pcidev); - - free_irq(hba->pcidev->irq, hba); - - dma_free_coherent(&hba->pcidev->dev, - hba->req_size * hba->max_requests + 0x20, - hba->dma_coherent, - hba->dma_coherent_handle); - - if (hba->ops->internal_memfree) - hba->ops->internal_memfree(hba); - - hba->ops->unmap_pci_bar(hba); - - pci_release_regions(hba->pcidev); - pci_set_drvdata(hba->pcidev, NULL); - pci_disable_device(hba->pcidev); - - scsi_host_put(host); -} - -static struct hptiop_adapter_ops hptiop_itl_ops = { - .iop_wait_ready = iop_wait_ready_itl, - .internal_memalloc = NULL, - .internal_memfree = NULL, - .map_pci_bar = hptiop_map_pci_bar_itl, - .unmap_pci_bar = hptiop_unmap_pci_bar_itl, - .enable_intr = hptiop_enable_intr_itl, - .disable_intr = hptiop_disable_intr_itl, - .get_config = iop_get_config_itl, - .set_config = iop_set_config_itl, - .iop_intr = iop_intr_itl, - .post_msg = hptiop_post_msg_itl, - .post_req = hptiop_post_req_itl, -}; - -static struct hptiop_adapter_ops hptiop_mv_ops = { - .iop_wait_ready = iop_wait_ready_mv, - .internal_memalloc = hptiop_internal_memalloc_mv, - .internal_memfree = hptiop_internal_memfree_mv, - .map_pci_bar = hptiop_map_pci_bar_mv, - .unmap_pci_bar = hptiop_unmap_pci_bar_mv, - .enable_intr = hptiop_enable_intr_mv, - .disable_intr = hptiop_disable_intr_mv, - .get_config = iop_get_config_mv, - .set_config = iop_set_config_mv, - .iop_intr = iop_intr_mv, - .post_msg = hptiop_post_msg_mv, - .post_req = hptiop_post_req_mv, -}; - -static struct pci_device_id hptiop_id_table[] = { - { PCI_VDEVICE(TTI, 0x3220), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3320), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3410), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3510), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3511), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3520), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3521), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3522), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3540), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x4311), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x4320), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x4400), (kernel_ulong_t)&hptiop_itl_ops }, - { PCI_VDEVICE(TTI, 0x3120), (kernel_ulong_t)&hptiop_mv_ops }, - { PCI_VDEVICE(TTI, 0x3122), (kernel_ulong_t)&hptiop_mv_ops }, - { PCI_VDEVICE(TTI, 0x3020), (kernel_ulong_t)&hptiop_mv_ops }, - {}, -}; - -MODULE_DEVICE_TABLE(pci, hptiop_id_table); - -static struct pci_driver hptiop_pci_driver = { - .name = driver_name, - .id_table = hptiop_id_table, - .probe = hptiop_probe, - .remove = hptiop_remove, - .shutdown = hptiop_shutdown, -}; - -static int __init hptiop_module_init(void) -{ - printk(KERN_INFO "%s %s\n", driver_name_long, driver_ver); - return pci_register_driver(&hptiop_pci_driver); -} - -static void __exit hptiop_module_exit(void) -{ - pci_unregister_driver(&hptiop_pci_driver); -} - - -module_init(hptiop_module_init); -module_exit(hptiop_module_exit); - -MODULE_LICENSE("GPL"); - diff --git a/ANDROID_3.4.5/drivers/scsi/hptiop.h b/ANDROID_3.4.5/drivers/scsi/hptiop.h deleted file mode 100644 index 0b871c0a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/hptiop.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * HighPoint RR3xxx/4xxx controller driver for Linux - * Copyright (C) 2006-2009 HighPoint Technologies, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Please report bugs/comments/suggestions to linux@highpoint-tech.com - * - * For more information, visit http://www.highpoint-tech.com - */ -#ifndef _HPTIOP_H_ -#define _HPTIOP_H_ - -struct hpt_iopmu_itl { - __le32 resrved0[4]; - __le32 inbound_msgaddr0; - __le32 inbound_msgaddr1; - __le32 outbound_msgaddr0; - __le32 outbound_msgaddr1; - __le32 inbound_doorbell; - __le32 inbound_intstatus; - __le32 inbound_intmask; - __le32 outbound_doorbell; - __le32 outbound_intstatus; - __le32 outbound_intmask; - __le32 reserved1[2]; - __le32 inbound_queue; - __le32 outbound_queue; -}; - -#define IOPMU_QUEUE_EMPTY 0xffffffff -#define IOPMU_QUEUE_MASK_HOST_BITS 0xf0000000 -#define IOPMU_QUEUE_ADDR_HOST_BIT 0x80000000 -#define IOPMU_QUEUE_REQUEST_SIZE_BIT 0x40000000 -#define IOPMU_QUEUE_REQUEST_RESULT_BIT 0x40000000 - -#define IOPMU_OUTBOUND_INT_MSG0 1 -#define IOPMU_OUTBOUND_INT_MSG1 2 -#define IOPMU_OUTBOUND_INT_DOORBELL 4 -#define IOPMU_OUTBOUND_INT_POSTQUEUE 8 -#define IOPMU_OUTBOUND_INT_PCI 0x10 - -#define IOPMU_INBOUND_INT_MSG0 1 -#define IOPMU_INBOUND_INT_MSG1 2 -#define IOPMU_INBOUND_INT_DOORBELL 4 -#define IOPMU_INBOUND_INT_ERROR 8 -#define IOPMU_INBOUND_INT_POSTQUEUE 0x10 - -#define MVIOP_QUEUE_LEN 512 - -struct hpt_iopmu_mv { - __le32 inbound_head; - __le32 inbound_tail; - __le32 outbound_head; - __le32 outbound_tail; - __le32 inbound_msg; - __le32 outbound_msg; - __le32 reserve[10]; - __le64 inbound_q[MVIOP_QUEUE_LEN]; - __le64 outbound_q[MVIOP_QUEUE_LEN]; -}; - -struct hpt_iopmv_regs { - __le32 reserved[0x20400 / 4]; - __le32 inbound_doorbell; - __le32 inbound_intmask; - __le32 outbound_doorbell; - __le32 outbound_intmask; -}; - -#define MVIOP_MU_QUEUE_ADDR_HOST_MASK (~(0x1full)) -#define MVIOP_MU_QUEUE_ADDR_HOST_BIT 4 - -#define MVIOP_MU_QUEUE_ADDR_IOP_HIGH32 0xffffffff -#define MVIOP_MU_QUEUE_REQUEST_RESULT_BIT 1 -#define MVIOP_MU_QUEUE_REQUEST_RETURN_CONTEXT 2 - -#define MVIOP_MU_INBOUND_INT_MSG 1 -#define MVIOP_MU_INBOUND_INT_POSTQUEUE 2 -#define MVIOP_MU_OUTBOUND_INT_MSG 1 -#define MVIOP_MU_OUTBOUND_INT_POSTQUEUE 2 - -enum hpt_iopmu_message { - /* host-to-iop messages */ - IOPMU_INBOUND_MSG0_NOP = 0, - IOPMU_INBOUND_MSG0_RESET, - IOPMU_INBOUND_MSG0_FLUSH, - IOPMU_INBOUND_MSG0_SHUTDOWN, - IOPMU_INBOUND_MSG0_STOP_BACKGROUND_TASK, - IOPMU_INBOUND_MSG0_START_BACKGROUND_TASK, - IOPMU_INBOUND_MSG0_MAX = 0xff, - /* iop-to-host messages */ - IOPMU_OUTBOUND_MSG0_REGISTER_DEVICE_0 = 0x100, - IOPMU_OUTBOUND_MSG0_REGISTER_DEVICE_MAX = 0x1ff, - IOPMU_OUTBOUND_MSG0_UNREGISTER_DEVICE_0 = 0x200, - IOPMU_OUTBOUND_MSG0_UNREGISTER_DEVICE_MAX = 0x2ff, - IOPMU_OUTBOUND_MSG0_REVALIDATE_DEVICE_0 = 0x300, - IOPMU_OUTBOUND_MSG0_REVALIDATE_DEVICE_MAX = 0x3ff, -}; - -struct hpt_iop_request_header { - __le32 size; - __le32 type; - __le32 flags; - __le32 result; - __le32 context; /* host context */ - __le32 context_hi32; -}; - -#define IOP_REQUEST_FLAG_SYNC_REQUEST 1 -#define IOP_REQUEST_FLAG_BIST_REQUEST 2 -#define IOP_REQUEST_FLAG_REMAPPED 4 -#define IOP_REQUEST_FLAG_OUTPUT_CONTEXT 8 - -enum hpt_iop_request_type { - IOP_REQUEST_TYPE_GET_CONFIG = 0, - IOP_REQUEST_TYPE_SET_CONFIG, - IOP_REQUEST_TYPE_BLOCK_COMMAND, - IOP_REQUEST_TYPE_SCSI_COMMAND, - IOP_REQUEST_TYPE_IOCTL_COMMAND, - IOP_REQUEST_TYPE_MAX -}; - -enum hpt_iop_result_type { - IOP_RESULT_PENDING = 0, - IOP_RESULT_SUCCESS, - IOP_RESULT_FAIL, - IOP_RESULT_BUSY, - IOP_RESULT_RESET, - IOP_RESULT_INVALID_REQUEST, - IOP_RESULT_BAD_TARGET, - IOP_RESULT_CHECK_CONDITION, -}; - -struct hpt_iop_request_get_config { - struct hpt_iop_request_header header; - __le32 interface_version; - __le32 firmware_version; - __le32 max_requests; - __le32 request_size; - __le32 max_sg_count; - __le32 data_transfer_length; - __le32 alignment_mask; - __le32 max_devices; - __le32 sdram_size; -}; - -struct hpt_iop_request_set_config { - struct hpt_iop_request_header header; - __le32 iop_id; - __le16 vbus_id; - __le16 max_host_request_size; - __le32 reserve[6]; -}; - -struct hpt_iopsg { - __le32 size; - __le32 eot; /* non-zero: end of table */ - __le64 pci_address; -}; - -struct hpt_iop_request_block_command { - struct hpt_iop_request_header header; - u8 channel; - u8 target; - u8 lun; - u8 pad1; - __le16 command; /* IOP_BLOCK_COMMAND_{READ,WRITE} */ - __le16 sectors; - __le64 lba; - struct hpt_iopsg sg_list[1]; -}; - -#define IOP_BLOCK_COMMAND_READ 1 -#define IOP_BLOCK_COMMAND_WRITE 2 -#define IOP_BLOCK_COMMAND_VERIFY 3 -#define IOP_BLOCK_COMMAND_FLUSH 4 -#define IOP_BLOCK_COMMAND_SHUTDOWN 5 - -struct hpt_iop_request_scsi_command { - struct hpt_iop_request_header header; - u8 channel; - u8 target; - u8 lun; - u8 pad1; - u8 cdb[16]; - __le32 dataxfer_length; - struct hpt_iopsg sg_list[1]; -}; - -struct hpt_iop_request_ioctl_command { - struct hpt_iop_request_header header; - __le32 ioctl_code; - __le32 inbuf_size; - __le32 outbuf_size; - __le32 bytes_returned; - u8 buf[1]; - /* out data should be put at buf[(inbuf_size+3)&~3] */ -}; - -#define HPTIOP_MAX_REQUESTS 256u - -struct hptiop_request { - struct hptiop_request *next; - void *req_virt; - u32 req_shifted_phy; - struct scsi_cmnd *scp; - int index; -}; - -struct hpt_scsi_pointer { - int mapped; - int sgcnt; - dma_addr_t dma_handle; -}; - -#define HPT_SCP(scp) ((struct hpt_scsi_pointer *)&(scp)->SCp) - -struct hptiop_hba { - struct hptiop_adapter_ops *ops; - union { - struct { - struct hpt_iopmu_itl __iomem *iop; - void __iomem *plx; - } itl; - struct { - struct hpt_iopmv_regs *regs; - struct hpt_iopmu_mv __iomem *mu; - void *internal_req; - dma_addr_t internal_req_phy; - } mv; - } u; - - struct Scsi_Host *host; - struct pci_dev *pcidev; - - /* IOP config info */ - u32 interface_version; - u32 firmware_version; - u32 sdram_size; - u32 max_devices; - u32 max_requests; - u32 max_request_size; - u32 max_sg_descriptors; - - u32 req_size; /* host-allocated request buffer size */ - - u32 iopintf_v2: 1; - u32 initialized: 1; - u32 msg_done: 1; - - struct hptiop_request * req_list; - struct hptiop_request reqs[HPTIOP_MAX_REQUESTS]; - - /* used to free allocated dma area */ - void *dma_coherent; - dma_addr_t dma_coherent_handle; - - atomic_t reset_count; - atomic_t resetting; - - wait_queue_head_t reset_wq; - wait_queue_head_t ioctl_wq; -}; - -struct hpt_ioctl_k { - struct hptiop_hba * hba; - u32 ioctl_code; - u32 inbuf_size; - u32 outbuf_size; - void *inbuf; - void *outbuf; - u32 *bytes_returned; - void (*done)(struct hpt_ioctl_k *); - int result; /* HPT_IOCTL_RESULT_ */ -}; - -struct hptiop_adapter_ops { - int (*iop_wait_ready)(struct hptiop_hba *hba, u32 millisec); - int (*internal_memalloc)(struct hptiop_hba *hba); - int (*internal_memfree)(struct hptiop_hba *hba); - int (*map_pci_bar)(struct hptiop_hba *hba); - void (*unmap_pci_bar)(struct hptiop_hba *hba); - void (*enable_intr)(struct hptiop_hba *hba); - void (*disable_intr)(struct hptiop_hba *hba); - int (*get_config)(struct hptiop_hba *hba, - struct hpt_iop_request_get_config *config); - int (*set_config)(struct hptiop_hba *hba, - struct hpt_iop_request_set_config *config); - int (*iop_intr)(struct hptiop_hba *hba); - void (*post_msg)(struct hptiop_hba *hba, u32 msg); - void (*post_req)(struct hptiop_hba *hba, struct hptiop_request *_req); -}; - -#define HPT_IOCTL_RESULT_OK 0 -#define HPT_IOCTL_RESULT_FAILED (-1) - -#if 0 -#define dprintk(fmt, args...) do { printk(fmt, ##args); } while(0) -#else -#define dprintk(fmt, args...) -#endif - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/ibmmca.c b/ANDROID_3.4.5/drivers/scsi/ibmmca.c deleted file mode 100644 index cd09132d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmmca.c +++ /dev/null @@ -1,2379 +0,0 @@ -/* - Low Level Linux Driver for the IBM Microchannel SCSI Subsystem for - Linux Kernel >= 2.4.0. - Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU - General Public License. Written by Martin Kolinek, December 1995. - Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang - See the file Documentation/scsi/ibmmca.txt for a detailed description - of this driver, the commandline arguments and the history of its - development. - See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest - updates, info and ADF-files for adapters supported by this driver. - - Alan Cox - Updated for Linux 2.5.45 to use the new error handler, cleaned up the - lock macros and did a few unavoidable locking tweaks, plus one locking - fix in the irq and completion path. - - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "scsi.h" -#include - -/* Common forward declarations for all Linux-versions: */ -static int ibmmca_queuecommand (struct Scsi_Host *, struct scsi_cmnd *); -static int ibmmca_abort (Scsi_Cmnd *); -static int ibmmca_host_reset (Scsi_Cmnd *); -static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *); -static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout); - - - -/* current version of this driver-source: */ -#define IBMMCA_SCSI_DRIVER_VERSION "4.0b-ac" - -/* driver configuration */ -#define IM_MAX_HOSTS 8 /* maximum number of host adapters */ -#define IM_RESET_DELAY 60 /* seconds allowed for a reset */ - -/* driver debugging - #undef all for normal operation */ -/* if defined: count interrupts and ignore this special one: */ -#undef IM_DEBUG_TIMEOUT //50 -#define TIMEOUT_PUN 0 -#define TIMEOUT_LUN 0 -/* verbose interrupt: */ -#undef IM_DEBUG_INT -/* verbose queuecommand: */ -#undef IM_DEBUG_CMD -/* verbose queucommand for specific SCSI-device type: */ -#undef IM_DEBUG_CMD_SPEC_DEV -/* verbose device probing */ -#undef IM_DEBUG_PROBE - -/* device type that shall be displayed on syslog (only during debugging): */ -#define IM_DEBUG_CMD_DEVICE TYPE_TAPE - -/* relative addresses of hardware registers on a subsystem */ -#define IM_CMD_REG(h) ((h)->io_port) /*Command Interface, (4 bytes long) */ -#define IM_ATTN_REG(h) ((h)->io_port+4) /*Attention (1 byte) */ -#define IM_CTR_REG(h) ((h)->io_port+5) /*Basic Control (1 byte) */ -#define IM_INTR_REG(h) ((h)->io_port+6) /*Interrupt Status (1 byte, r/o) */ -#define IM_STAT_REG(h) ((h)->io_port+7) /*Basic Status (1 byte, read only) */ - -/* basic I/O-port of first adapter */ -#define IM_IO_PORT 0x3540 -/* maximum number of hosts that can be found */ -#define IM_N_IO_PORT 8 - -/*requests going into the upper nibble of the Attention register */ -/*note: the lower nibble specifies the device(0-14), or subsystem(15) */ -#define IM_IMM_CMD 0x10 /*immediate command */ -#define IM_SCB 0x30 /*Subsystem Control Block command */ -#define IM_LONG_SCB 0x40 /*long Subsystem Control Block command */ -#define IM_EOI 0xe0 /*end-of-interrupt request */ - -/*values for bits 7,1,0 of Basic Control reg. (bits 6-2 reserved) */ -#define IM_HW_RESET 0x80 /*hardware reset */ -#define IM_ENABLE_DMA 0x02 /*enable subsystem's busmaster DMA */ -#define IM_ENABLE_INTR 0x01 /*enable interrupts to the system */ - -/*to interpret the upper nibble of Interrupt Status register */ -/*note: the lower nibble specifies the device(0-14), or subsystem(15) */ -#define IM_SCB_CMD_COMPLETED 0x10 -#define IM_SCB_CMD_COMPLETED_WITH_RETRIES 0x50 -#define IM_LOOP_SCATTER_BUFFER_FULL 0x60 -#define IM_ADAPTER_HW_FAILURE 0x70 -#define IM_IMMEDIATE_CMD_COMPLETED 0xa0 -#define IM_CMD_COMPLETED_WITH_FAILURE 0xc0 -#define IM_CMD_ERROR 0xe0 -#define IM_SOFTWARE_SEQUENCING_ERROR 0xf0 - -/*to interpret bits 3-0 of Basic Status register (bits 7-4 reserved) */ -#define IM_CMD_REG_FULL 0x08 -#define IM_CMD_REG_EMPTY 0x04 -#define IM_INTR_REQUEST 0x02 -#define IM_BUSY 0x01 - -/*immediate commands (word written into low 2 bytes of command reg) */ -#define IM_RESET_IMM_CMD 0x0400 -#define IM_FEATURE_CTR_IMM_CMD 0x040c -#define IM_DMA_PACING_IMM_CMD 0x040d -#define IM_ASSIGN_IMM_CMD 0x040e -#define IM_ABORT_IMM_CMD 0x040f -#define IM_FORMAT_PREP_IMM_CMD 0x0417 - -/*SCB (Subsystem Control Block) structure */ -struct im_scb { - unsigned short command; /*command word (read, etc.) */ - unsigned short enable; /*enable word, modifies cmd */ - union { - unsigned long log_blk_adr; /*block address on SCSI device */ - unsigned char scsi_cmd_length; /*6,10,12, for other scsi cmd */ - } u1; - unsigned long sys_buf_adr; /*physical system memory adr */ - unsigned long sys_buf_length; /*size of sys mem buffer */ - unsigned long tsb_adr; /*Termination Status Block adr */ - unsigned long scb_chain_adr; /*optional SCB chain address */ - union { - struct { - unsigned short count; /*block count, on SCSI device */ - unsigned short length; /*block length, on SCSI device */ - } blk; - unsigned char scsi_command[12]; /*other scsi command */ - } u2; -}; - -/*structure scatter-gather element (for list of system memory areas) */ -struct im_sge { - void *address; - unsigned long byte_length; -}; - -/*structure returned by a get_pos_info command: */ -struct im_pos_info { - unsigned short pos_id; /* adapter id */ - unsigned char pos_3a; /* pos 3 (if pos 6 = 0) */ - unsigned char pos_2; /* pos 2 */ - unsigned char int_level; /* interrupt level IRQ 11 or 14 */ - unsigned char pos_4a; /* pos 4 (if pos 6 = 0) */ - unsigned short connector_size; /* MCA connector size: 16 or 32 Bit */ - unsigned char num_luns; /* number of supported luns per device */ - unsigned char num_puns; /* number of supported puns */ - unsigned char pacing_factor; /* pacing factor */ - unsigned char num_ldns; /* number of ldns available */ - unsigned char eoi_off; /* time EOI and interrupt inactive */ - unsigned char max_busy; /* time between reset and busy on */ - unsigned short cache_stat; /* ldn cachestat. Bit=1 = not cached */ - unsigned short retry_stat; /* retry status of ldns. Bit=1=disabled */ - unsigned char pos_4b; /* pos 4 (if pos 6 = 1) */ - unsigned char pos_3b; /* pos 3 (if pos 6 = 1) */ - unsigned char pos_6; /* pos 6 */ - unsigned char pos_5; /* pos 5 */ - unsigned short max_overlap; /* maximum overlapping requests */ - unsigned short num_bus; /* number of SCSI-busses */ -}; - -/*values for SCB command word */ -#define IM_NO_SYNCHRONOUS 0x0040 /*flag for any command */ -#define IM_NO_DISCONNECT 0x0080 /*flag for any command */ -#define IM_READ_DATA_CMD 0x1c01 -#define IM_WRITE_DATA_CMD 0x1c02 -#define IM_READ_VERIFY_CMD 0x1c03 -#define IM_WRITE_VERIFY_CMD 0x1c04 -#define IM_REQUEST_SENSE_CMD 0x1c08 -#define IM_READ_CAPACITY_CMD 0x1c09 -#define IM_DEVICE_INQUIRY_CMD 0x1c0b -#define IM_READ_LOGICAL_CMD 0x1c2a -#define IM_OTHER_SCSI_CMD_CMD 0x241f - -/* unused, but supported, SCB commands */ -#define IM_GET_COMMAND_COMPLETE_STATUS_CMD 0x1c07 /* command status */ -#define IM_GET_POS_INFO_CMD 0x1c0a /* returns neat stuff */ -#define IM_READ_PREFETCH_CMD 0x1c31 /* caching controller only */ -#define IM_FOMAT_UNIT_CMD 0x1c16 /* format unit */ -#define IM_REASSIGN_BLOCK_CMD 0x1c18 /* in case of error */ - -/*values to set bits in the enable word of SCB */ -#define IM_READ_CONTROL 0x8000 -#define IM_REPORT_TSB_ONLY_ON_ERROR 0x4000 -#define IM_RETRY_ENABLE 0x2000 -#define IM_POINTER_TO_LIST 0x1000 -#define IM_SUPRESS_EXCEPTION_SHORT 0x0400 -#define IM_BYPASS_BUFFER 0x0200 -#define IM_CHAIN_ON_NO_ERROR 0x0001 - -/*TSB (Termination Status Block) structure */ -struct im_tsb { - unsigned short end_status; - unsigned short reserved1; - unsigned long residual_byte_count; - unsigned long sg_list_element_adr; - unsigned short status_length; - unsigned char dev_status; - unsigned char cmd_status; - unsigned char dev_error; - unsigned char cmd_error; - unsigned short reserved2; - unsigned short reserved3; - unsigned short low_of_last_scb_adr; - unsigned short high_of_last_scb_adr; -}; - -/*subsystem uses interrupt request level 14 */ -#define IM_IRQ 14 -/*SCSI-2 F/W may evade to interrupt 11 */ -#define IM_IRQ_FW 11 - -/* Model 95 has an additional alphanumeric display, which can be used - to display SCSI-activities. 8595 models do not have any disk led, which - makes this feature quite useful. - The regular PS/2 disk led is turned on/off by bits 6,7 of system - control port. */ - -/* LED display-port (actually, last LED on display) */ -#define MOD95_LED_PORT 0x108 -/* system-control-register of PS/2s with diskindicator */ -#define PS2_SYS_CTR 0x92 -/* activity displaying methods */ -#define LED_DISP 1 -#define LED_ADISP 2 -#define LED_ACTIVITY 4 -/* failed intr */ -#define CMD_FAIL 255 - -/* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED - displays. ldn is no longer displayed here, because the ldn mapping is now - done dynamically and the ldn <-> pun,lun maps can be looked-up at boottime - or during uptime in /proc/scsi/ibmmca/ in case of trouble, - interest, debugging or just for having fun. The left number gives the - host-adapter number and the right shows the accessed SCSI-ID. */ - -/* display_mode is set by the ibmmcascsi= command line arg */ -static int display_mode = 0; -/* set default adapter timeout */ -static unsigned int adapter_timeout = 45; -/* for probing on feature-command: */ -static unsigned int global_command_error_excuse = 0; -/* global setting by command line for adapter_speed */ -static int global_adapter_speed = 0; /* full speed by default */ - -/* Panel / LED on, do it right for F/W addressin, too. adisplay will - * just ignore ids>7, as the panel has only 7 digits available */ -#define PS2_DISK_LED_ON(ad,id) { if (display_mode & LED_DISP) { if (id>9) \ - outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); else \ - outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } else \ - if (display_mode & LED_ADISP) { if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \ - outb((char)(ad+48), MOD95_LED_PORT); } \ - if ((display_mode & LED_ACTIVITY)||(!display_mode)) \ - outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); } - -/* Panel / LED off */ -/* bug fixed, Dec 15, 1997, where | was replaced by & here */ -#define PS2_DISK_LED_OFF() { if (display_mode & LED_DISP) \ - outw(0x2020, MOD95_LED_PORT ); else if (display_mode & LED_ADISP) { \ - outl(0x20202020,MOD95_LED_PORT); outl(0x20202020,MOD95_LED_PORT+4); } \ - if ((display_mode & LED_ACTIVITY)||(!display_mode)) \ - outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); } - -/* types of different supported hardware that goes to hostdata special */ -#define IBM_SCSI2_FW 0 -#define IBM_7568_WCACHE 1 -#define IBM_EXP_UNIT 2 -#define IBM_SCSI_WCACHE 3 -#define IBM_SCSI 4 -#define IBM_INTEGSCSI 5 - -/* other special flags for hostdata structure */ -#define FORCED_DETECTION 100 -#define INTEGRATED_SCSI 101 - -/* List of possible IBM-SCSI-adapters */ -static short ibmmca_id_table[] = { - 0x8efc, - 0x8efd, - 0x8ef8, - 0x8eff, - 0x8efe, - /* No entry for integrated SCSI, that's part of the register */ - 0 -}; - -static const char *ibmmca_description[] = { - "IBM SCSI-2 F/W Adapter", /* special = 0 */ - "IBM 7568 Industrial Computer SCSI Adapter w/Cache", /* special = 1 */ - "IBM Expansion Unit SCSI Controller", /* special = 2 */ - "IBM SCSI Adapter w/Cache", /* special = 3 */ - "IBM SCSI Adapter", /* special = 4 */ - "IBM Integrated SCSI Controller", /* special = 5 */ -}; - -/* Max number of logical devices (can be up from 0 to 14). 15 is the address -of the adapter itself. */ -#define MAX_LOG_DEV 15 - -/*local data for a logical device */ -struct logical_device { - struct im_scb scb; /* SCSI-subsystem-control-block structure */ - struct im_tsb tsb; /* SCSI command complete status block structure */ - struct im_sge sge[16]; /* scatter gather list structure */ - unsigned char buf[256]; /* SCSI command return data buffer */ - Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */ - int device_type; /* type of the SCSI-device. See include/scsi/scsi.h - for interpretation of the possible values */ - int block_length; /* blocksize of a particular logical SCSI-device */ - int cache_flag; /* 1 if this is uncached, 0 if cache is present for ldn */ - int retry_flag; /* 1 if adapter retry is disabled, 0 if enabled */ -}; - -/* statistics of the driver during operations (for proc_info) */ -struct Driver_Statistics { - /* SCSI statistics on the adapter */ - int ldn_access[MAX_LOG_DEV + 1]; /* total accesses on a ldn */ - int ldn_read_access[MAX_LOG_DEV + 1]; /* total read-access on a ldn */ - int ldn_write_access[MAX_LOG_DEV + 1]; /* total write-access on a ldn */ - int ldn_inquiry_access[MAX_LOG_DEV + 1]; /* total inquiries on a ldn */ - int ldn_modeselect_access[MAX_LOG_DEV + 1]; /* total mode selects on ldn */ - int scbs; /* short SCBs queued */ - int long_scbs; /* long SCBs queued */ - int total_accesses; /* total accesses on all ldns */ - int total_interrupts; /* total interrupts (should be - same as total_accesses) */ - int total_errors; /* command completed with error */ - /* dynamical assignment statistics */ - int total_scsi_devices; /* number of physical pun,lun */ - int dyn_flag; /* flag showing dynamical mode */ - int dynamical_assignments; /* number of remappings of ldns */ - int ldn_assignments[MAX_LOG_DEV + 1]; /* number of remappings of each - ldn */ -}; - -/* data structure for each host adapter */ -struct ibmmca_hostdata { - /* array of logical devices: */ - struct logical_device _ld[MAX_LOG_DEV + 1]; - /* array to convert (pun, lun) into logical device number: */ - unsigned char _get_ldn[16][8]; - /*array that contains the information about the physical SCSI-devices - attached to this host adapter: */ - unsigned char _get_scsi[16][8]; - /* used only when checking logical devices: */ - int _local_checking_phase_flag; - /* report received interrupt: */ - int _got_interrupt; - /* report termination-status of SCSI-command: */ - int _stat_result; - /* reset status (used only when doing reset): */ - int _reset_status; - /* code of the last SCSI command (needed for panic info): */ - int _last_scsi_command[MAX_LOG_DEV + 1]; - /* identifier of the last SCSI-command type */ - int _last_scsi_type[MAX_LOG_DEV + 1]; - /* last blockcount */ - int _last_scsi_blockcount[MAX_LOG_DEV + 1]; - /* last locgical block address */ - unsigned long _last_scsi_logical_block[MAX_LOG_DEV + 1]; - /* Counter that points on the next reassignable ldn for dynamical - remapping. The default value is 7, that is the first reassignable - number in the list at boottime: */ - int _next_ldn; - /* Statistics-structure for this IBM-SCSI-host: */ - struct Driver_Statistics _IBM_DS; - /* This hostadapters pos-registers pos2 until pos6 */ - unsigned int _pos[8]; - /* assign a special variable, that contains dedicated info about the - adaptertype */ - int _special; - /* connector size on the MCA bus */ - int _connector_size; - /* synchronous SCSI transfer rate bitpattern */ - int _adapter_speed; -}; - -/* macros to access host data structure */ -#define subsystem_pun(h) ((h)->this_id) -#define subsystem_maxid(h) ((h)->max_id) -#define ld(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_ld) -#define get_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_ldn) -#define get_scsi(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_get_scsi) -#define local_checking_phase_flag(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_local_checking_phase_flag) -#define got_interrupt(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_got_interrupt) -#define stat_result(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_stat_result) -#define reset_status(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_reset_status) -#define last_scsi_command(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_command) -#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type) -#define last_scsi_blockcount(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_blockcount) -#define last_scsi_logical_block(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_logical_block) -#define last_scsi_type(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_last_scsi_type) -#define next_ldn(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_next_ldn) -#define IBM_DS(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_IBM_DS) -#define special(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_special) -#define subsystem_connector_size(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_connector_size) -#define adapter_speed(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_adapter_speed) -#define pos2(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[2]) -#define pos3(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[3]) -#define pos4(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[4]) -#define pos5(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[5]) -#define pos6(h) (((struct ibmmca_hostdata *) (h)->hostdata)->_pos[6]) - -/* Define a arbitrary number as subsystem-marker-type. This number is, as - described in the ANSI-SCSI-standard, not occupied by other device-types. */ -#define TYPE_IBM_SCSI_ADAPTER 0x2F - -/* Define 0xFF for no device type, because this type is not defined within - the ANSI-SCSI-standard, therefore, it can be used and should not cause any - harm. */ -#define TYPE_NO_DEVICE 0xFF - -/* define medium-changer. If this is not defined previously, e.g. Linux - 2.0.x, define this type here. */ -#ifndef TYPE_MEDIUM_CHANGER -#define TYPE_MEDIUM_CHANGER 0x08 -#endif - -/* define possible operations for the immediate_assign command */ -#define SET_LDN 0 -#define REMOVE_LDN 1 - -/* ldn which is used to probe the SCSI devices */ -#define PROBE_LDN 0 - -/* reset status flag contents */ -#define IM_RESET_NOT_IN_PROGRESS 0 -#define IM_RESET_IN_PROGRESS 1 -#define IM_RESET_FINISHED_OK 2 -#define IM_RESET_FINISHED_FAIL 3 -#define IM_RESET_NOT_IN_PROGRESS_NO_INT 4 -#define IM_RESET_FINISHED_OK_NO_INT 5 - -/* define undefined SCSI-command */ -#define NO_SCSI 0xffff - -/*-----------------------------------------------------------------------*/ - -/* if this is nonzero, ibmmcascsi option has been passed to the kernel */ -static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 }; -static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 }; - -/* fill module-parameters only, when this define is present. - (that is kernel version 2.1.x) */ -#if defined(MODULE) -static char *boot_options = NULL; -module_param(boot_options, charp, 0); -module_param_array(io_port, int, NULL, 0); -module_param_array(scsi_id, int, NULL, 0); - -MODULE_LICENSE("GPL"); -#endif -/*counter of concurrent disk read/writes, to turn on/off disk led */ -static int disk_rw_in_progress = 0; - -static unsigned int pos[8]; /* whole pos register-line for diagnosis */ -/* Taking into account the additions, made by ZP Gu. - * This selects now the preset value from the configfile and - * offers the 'normal' commandline option to be accepted */ -#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD -static char ibm_ansi_order = 1; -#else -static char ibm_ansi_order = 0; -#endif - -static void issue_cmd(struct Scsi_Host *, unsigned long, unsigned char); -static void internal_done(Scsi_Cmnd * cmd); -static void check_devices(struct Scsi_Host *, int); -static int immediate_assign(struct Scsi_Host *, unsigned int, unsigned int, unsigned int, unsigned int); -static int immediate_feature(struct Scsi_Host *, unsigned int, unsigned int); -#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET -static int immediate_reset(struct Scsi_Host *, unsigned int); -#endif -static int device_inquiry(struct Scsi_Host *, int); -static int read_capacity(struct Scsi_Host *, int); -static int get_pos_info(struct Scsi_Host *); -static char *ti_p(int); -static char *ti_l(int); -static char *ibmrate(unsigned int, int); -static int probe_display(int); -static int probe_bus_mode(struct Scsi_Host *); -static int device_exists(struct Scsi_Host *, int, int *, int *); -static int option_setup(char *); -/* local functions needed for proc_info */ -static int ldn_access_load(struct Scsi_Host *, int); -static int ldn_access_total_read_write(struct Scsi_Host *); - -static irqreturn_t interrupt_handler(int irq, void *dev_id) -{ - unsigned int intr_reg; - unsigned int cmd_result; - unsigned int ldn; - unsigned long flags; - Scsi_Cmnd *cmd; - int lastSCSI; - struct device *dev = dev_id; - struct Scsi_Host *shpnt = dev_get_drvdata(dev); - - spin_lock_irqsave(shpnt->host_lock, flags); - - if(!(inb(IM_STAT_REG(shpnt)) & IM_INTR_REQUEST)) { - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_NONE; - } - - /* the reset-function already did all the job, even ints got - renabled on the subsystem, so just return */ - if ((reset_status(shpnt) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(shpnt) == IM_RESET_FINISHED_OK_NO_INT)) { - reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS; - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; - } - - /*must wait for attention reg not busy, then send EOI to subsystem */ - while (1) { - if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY)) - break; - cpu_relax(); - } - - /*get command result and logical device */ - intr_reg = (unsigned char) (inb(IM_INTR_REG(shpnt))); - cmd_result = intr_reg & 0xf0; - ldn = intr_reg & 0x0f; - /* get the last_scsi_command here */ - lastSCSI = last_scsi_command(shpnt)[ldn]; - outb(IM_EOI | ldn, IM_ATTN_REG(shpnt)); - - /*these should never happen (hw fails, or a local programming bug) */ - if (!global_command_error_excuse) { - switch (cmd_result) { - /* Prevent from Ooopsing on error to show the real reason */ - case IM_ADAPTER_HW_FAILURE: - case IM_SOFTWARE_SEQUENCING_ERROR: - case IM_CMD_ERROR: - printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n"); - printk(KERN_ERR " Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(shpnt)[ldn].scb.enable); - if (ld(shpnt)[ldn].cmd) - printk("%ld/%ld,", (long) (scsi_bufflen(ld(shpnt)[ldn].cmd)), (long) (ld(shpnt)[ldn].scb.sys_buf_length)); - else - printk("none,"); - if (ld(shpnt)[ldn].cmd) - printk("Blocksize=%d", ld(shpnt)[ldn].scb.u2.blk.length); - else - printk("Blocksize=none"); - printk(", host=%p, ldn=0x%x\n", shpnt, ldn); - if (ld(shpnt)[ldn].cmd) { - printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(shpnt)[ldn], ld(shpnt)[ldn].scb.u2.blk.count); - printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(shpnt)[ldn], ld(shpnt)[ldn].scb.u1.log_blk_adr); - } - printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN"); - /* if errors appear, enter this section to give detailed info */ - printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n"); - printk(KERN_ERR " Command Type................: %x\n", last_scsi_type(shpnt)[ldn]); - printk(KERN_ERR " Attention Register..........: %x\n", inb(IM_ATTN_REG(shpnt))); - printk(KERN_ERR " Basic Control Register......: %x\n", inb(IM_CTR_REG(shpnt))); - printk(KERN_ERR " Interrupt Status Register...: %x\n", intr_reg); - printk(KERN_ERR " Basic Status Register.......: %x\n", inb(IM_STAT_REG(shpnt))); - if ((last_scsi_type(shpnt)[ldn] == IM_SCB) || (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB)) { - printk(KERN_ERR " SCB-Command.................: %x\n", ld(shpnt)[ldn].scb.command); - printk(KERN_ERR " SCB-Enable..................: %x\n", ld(shpnt)[ldn].scb.enable); - printk(KERN_ERR " SCB-logical block address...: %lx\n", ld(shpnt)[ldn].scb.u1.log_blk_adr); - printk(KERN_ERR " SCB-system buffer address...: %lx\n", ld(shpnt)[ldn].scb.sys_buf_adr); - printk(KERN_ERR " SCB-system buffer length....: %lx\n", ld(shpnt)[ldn].scb.sys_buf_length); - printk(KERN_ERR " SCB-tsb address.............: %lx\n", ld(shpnt)[ldn].scb.tsb_adr); - printk(KERN_ERR " SCB-Chain address...........: %lx\n", ld(shpnt)[ldn].scb.scb_chain_adr); - printk(KERN_ERR " SCB-block count.............: %x\n", ld(shpnt)[ldn].scb.u2.blk.count); - printk(KERN_ERR " SCB-block length............: %x\n", ld(shpnt)[ldn].scb.u2.blk.length); - } - printk(KERN_ERR " Send this report to the maintainer.\n"); - panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result); - break; - } - } else { - /* The command error handling is made silent, but we tell the - * calling function, that there is a reported error from the - * adapter. */ - switch (cmd_result) { - case IM_ADAPTER_HW_FAILURE: - case IM_SOFTWARE_SEQUENCING_ERROR: - case IM_CMD_ERROR: - global_command_error_excuse = CMD_FAIL; - break; - default: - global_command_error_excuse = 0; - break; - } - } - /* if no panic appeared, increase the interrupt-counter */ - IBM_DS(shpnt).total_interrupts++; - /*only for local checking phase */ - if (local_checking_phase_flag(shpnt)) { - stat_result(shpnt) = cmd_result; - got_interrupt(shpnt) = 1; - reset_status(shpnt) = IM_RESET_FINISHED_OK; - last_scsi_command(shpnt)[ldn] = NO_SCSI; - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; - } - /* handling of commands coming from upper level of scsi driver */ - if (last_scsi_type(shpnt)[ldn] == IM_IMM_CMD) { - /* verify ldn, and may handle rare reset immediate command */ - if ((reset_status(shpnt) == IM_RESET_IN_PROGRESS) && (last_scsi_command(shpnt)[ldn] == IM_RESET_IMM_CMD)) { - if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) { - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF(); - reset_status(shpnt) = IM_RESET_FINISHED_FAIL; - } else { - /*reset disk led counter, turn off disk led */ - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF(); - reset_status(shpnt) = IM_RESET_FINISHED_OK; - } - stat_result(shpnt) = cmd_result; - last_scsi_command(shpnt)[ldn] = NO_SCSI; - last_scsi_type(shpnt)[ldn] = 0; - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; - } else if (last_scsi_command(shpnt)[ldn] == IM_ABORT_IMM_CMD) { - /* react on SCSI abort command */ -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n"); -#endif - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF(); - cmd = ld(shpnt)[ldn].cmd; - ld(shpnt)[ldn].cmd = NULL; - if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) - cmd->result = DID_NO_CONNECT << 16; - else - cmd->result = DID_ABORT << 16; - stat_result(shpnt) = cmd_result; - last_scsi_command(shpnt)[ldn] = NO_SCSI; - last_scsi_type(shpnt)[ldn] = 0; - if (cmd->scsi_done) - (cmd->scsi_done) (cmd); /* should be the internal_done */ - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; - } else { - disk_rw_in_progress = 0; - PS2_DISK_LED_OFF(); - reset_status(shpnt) = IM_RESET_FINISHED_OK; - stat_result(shpnt) = cmd_result; - last_scsi_command(shpnt)[ldn] = NO_SCSI; - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; - } - } - last_scsi_command(shpnt)[ldn] = NO_SCSI; - last_scsi_type(shpnt)[ldn] = 0; - cmd = ld(shpnt)[ldn].cmd; - ld(shpnt)[ldn].cmd = NULL; -#ifdef IM_DEBUG_TIMEOUT - if (cmd) { - if ((cmd->target == TIMEOUT_PUN) && (cmd->device->lun == TIMEOUT_LUN)) { - spin_unlock_irqsave(shpnt->host_lock, flags); - printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->device->lun); - return IRQ_HANDLED; - } - } -#endif - /*if no command structure, just return, else clear cmd */ - if (!cmd) - { - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; - } - -#ifdef IM_DEBUG_INT - printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(shpnt)[ldn].tsb.dev_status, ld(shpnt)[ldn].tsb.cmd_status, ld(shpnt)[ldn].tsb.dev_error, ld(shpnt)[ldn].tsb.cmd_error); -#endif - /*if this is end of media read/write, may turn off PS/2 disk led */ - if ((ld(shpnt)[ldn].device_type != TYPE_NO_LUN) && (ld(shpnt)[ldn].device_type != TYPE_NO_DEVICE)) { - /* only access this, if there was a valid device addressed */ - if (--disk_rw_in_progress == 0) - PS2_DISK_LED_OFF(); - } - - /* IBM describes the status-mask to be 0x1e, but this is not conform - * with SCSI-definition, I suppose, the reason for it is that IBM - * adapters do not support CMD_TERMINATED, TASK_SET_FULL and - * ACA_ACTIVE as returning statusbyte information. (ML) */ - if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) { - cmd->result = (unsigned char) (ld(shpnt)[ldn].tsb.dev_status & 0x1e); - IBM_DS(shpnt).total_errors++; - } else - cmd->result = 0; - /* write device status into cmd->result, and call done function */ - if (lastSCSI == NO_SCSI) { /* unexpected interrupt :-( */ - cmd->result |= DID_BAD_INTR << 16; - printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n"); - } else /* things went right :-) */ - cmd->result |= DID_OK << 16; - if (cmd->scsi_done) - (cmd->scsi_done) (cmd); - spin_unlock_irqrestore(shpnt->host_lock, flags); - return IRQ_HANDLED; -} - -static void issue_cmd(struct Scsi_Host *shpnt, unsigned long cmd_reg, - unsigned char attn_reg) -{ - unsigned long flags; - /* must wait for attention reg not busy */ - while (1) { - spin_lock_irqsave(shpnt->host_lock, flags); - if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY)) - break; - spin_unlock_irqrestore(shpnt->host_lock, flags); - } - /* write registers and enable system interrupts */ - outl(cmd_reg, IM_CMD_REG(shpnt)); - outb(attn_reg, IM_ATTN_REG(shpnt)); - spin_unlock_irqrestore(shpnt->host_lock, flags); -} - -static void internal_done(Scsi_Cmnd * cmd) -{ - cmd->SCp.Status++; - return; -} - -/* SCSI-SCB-command for device_inquiry */ -static int device_inquiry(struct Scsi_Host *shpnt, int ldn) -{ - int retr; - struct im_scb *scb; - struct im_tsb *tsb; - unsigned char *buf; - - scb = &(ld(shpnt)[ldn].scb); - tsb = &(ld(shpnt)[ldn].tsb); - buf = (unsigned char *) (&(ld(shpnt)[ldn].buf)); - ld(shpnt)[ldn].tsb.dev_status = 0; /* prepare statusblock */ - for (retr = 0; retr < 3; retr++) { - /* fill scb with inquiry command */ - scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT; - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; - last_scsi_command(shpnt)[ldn] = IM_DEVICE_INQUIRY_CMD; - last_scsi_type(shpnt)[ldn] = IM_SCB; - scb->sys_buf_adr = isa_virt_to_bus(buf); - scb->sys_buf_length = 255; /* maximum bufferlength gives max info */ - scb->tsb_adr = isa_virt_to_bus(tsb); - /* issue scb to passed ldn, and busy wait for interrupt */ - got_interrupt(shpnt) = 0; - issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn); - while (!got_interrupt(shpnt)) - barrier(); - - /*if command successful, break */ - if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) - return 1; - } - /*if all three retries failed, return "no device at this ldn" */ - if (retr >= 3) - return 0; - else - return 1; -} - -static int read_capacity(struct Scsi_Host *shpnt, int ldn) -{ - int retr; - struct im_scb *scb; - struct im_tsb *tsb; - unsigned char *buf; - - scb = &(ld(shpnt)[ldn].scb); - tsb = &(ld(shpnt)[ldn].tsb); - buf = (unsigned char *) (&(ld(shpnt)[ldn].buf)); - ld(shpnt)[ldn].tsb.dev_status = 0; - for (retr = 0; retr < 3; retr++) { - /*fill scb with read capacity command */ - scb->command = IM_READ_CAPACITY_CMD; - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; - last_scsi_command(shpnt)[ldn] = IM_READ_CAPACITY_CMD; - last_scsi_type(shpnt)[ldn] = IM_SCB; - scb->sys_buf_adr = isa_virt_to_bus(buf); - scb->sys_buf_length = 8; - scb->tsb_adr = isa_virt_to_bus(tsb); - /*issue scb to passed ldn, and busy wait for interrupt */ - got_interrupt(shpnt) = 0; - issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn); - while (!got_interrupt(shpnt)) - barrier(); - - /*if got capacity, get block length and return one device found */ - if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) - return 1; - } - /*if all three retries failed, return "no device at this ldn" */ - if (retr >= 3) - return 0; - else - return 1; -} - -static int get_pos_info(struct Scsi_Host *shpnt) -{ - int retr; - struct im_scb *scb; - struct im_tsb *tsb; - unsigned char *buf; - - scb = &(ld(shpnt)[MAX_LOG_DEV].scb); - tsb = &(ld(shpnt)[MAX_LOG_DEV].tsb); - buf = (unsigned char *) (&(ld(shpnt)[MAX_LOG_DEV].buf)); - ld(shpnt)[MAX_LOG_DEV].tsb.dev_status = 0; - for (retr = 0; retr < 3; retr++) { - /*fill scb with get_pos_info command */ - scb->command = IM_GET_POS_INFO_CMD; - scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER; - last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD; - last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_SCB; - scb->sys_buf_adr = isa_virt_to_bus(buf); - if (special(shpnt) == IBM_SCSI2_FW) - scb->sys_buf_length = 256; /* get all info from F/W adapter */ - else - scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */ - scb->tsb_adr = isa_virt_to_bus(tsb); - /*issue scb to ldn=15, and busy wait for interrupt */ - got_interrupt(shpnt) = 0; - issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV); - - /* FIXME: timeout */ - while (!got_interrupt(shpnt)) - barrier(); - - /*if got POS-stuff, get block length and return one device found */ - if ((stat_result(shpnt) == IM_SCB_CMD_COMPLETED) || (stat_result(shpnt) == IM_SCB_CMD_COMPLETED_WITH_RETRIES)) - return 1; - } - /* if all three retries failed, return "no device at this ldn" */ - if (retr >= 3) - return 0; - else - return 1; -} - -/* SCSI-immediate-command for assign. This functions maps/unmaps specific - ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the - subsystem and for dynamical remapping od ldns. */ -static int immediate_assign(struct Scsi_Host *shpnt, unsigned int pun, - unsigned int lun, unsigned int ldn, - unsigned int operation) -{ - int retr; - unsigned long imm_cmd; - - for (retr = 0; retr < 3; retr++) { - /* select mutation level of the SCSI-adapter */ - switch (special(shpnt)) { - case IBM_SCSI2_FW: - imm_cmd = (unsigned long) (IM_ASSIGN_IMM_CMD); - imm_cmd |= (unsigned long) ((lun & 7) << 24); - imm_cmd |= (unsigned long) ((operation & 1) << 23); - imm_cmd |= (unsigned long) ((pun & 7) << 20) | ((pun & 8) << 24); - imm_cmd |= (unsigned long) ((ldn & 15) << 16); - break; - default: - imm_cmd = inl(IM_CMD_REG(shpnt)); - imm_cmd &= (unsigned long) (0xF8000000); /* keep reserved bits */ - imm_cmd |= (unsigned long) (IM_ASSIGN_IMM_CMD); - imm_cmd |= (unsigned long) ((lun & 7) << 24); - imm_cmd |= (unsigned long) ((operation & 1) << 23); - imm_cmd |= (unsigned long) ((pun & 7) << 20); - imm_cmd |= (unsigned long) ((ldn & 15) << 16); - break; - } - last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD; - last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD; - got_interrupt(shpnt) = 0; - issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV); - while (!got_interrupt(shpnt)) - barrier(); - - /*if command successful, break */ - if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED) - return 1; - } - if (retr >= 3) - return 0; - else - return 1; -} - -static int immediate_feature(struct Scsi_Host *shpnt, unsigned int speed, unsigned int timeout) -{ - int retr; - unsigned long imm_cmd; - - for (retr = 0; retr < 3; retr++) { - /* select mutation level of the SCSI-adapter */ - imm_cmd = IM_FEATURE_CTR_IMM_CMD; - imm_cmd |= (unsigned long) ((speed & 0x7) << 29); - imm_cmd |= (unsigned long) ((timeout & 0x1fff) << 16); - last_scsi_command(shpnt)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD; - last_scsi_type(shpnt)[MAX_LOG_DEV] = IM_IMM_CMD; - got_interrupt(shpnt) = 0; - /* we need to run into command errors in order to probe for the - * right speed! */ - global_command_error_excuse = 1; - issue_cmd(shpnt, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV); - - /* FIXME: timeout */ - while (!got_interrupt(shpnt)) - barrier(); - if (global_command_error_excuse == CMD_FAIL) { - global_command_error_excuse = 0; - return 2; - } else - global_command_error_excuse = 0; - /*if command successful, break */ - if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED) - return 1; - } - if (retr >= 3) - return 0; - else - return 1; -} - -#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET -static int immediate_reset(struct Scsi_Host *shpnt, unsigned int ldn) -{ - int retries; - int ticks; - unsigned long imm_command; - - for (retries = 0; retries < 3; retries++) { - imm_command = inl(IM_CMD_REG(shpnt)); - imm_command &= (unsigned long) (0xFFFF0000); /* keep reserved bits */ - imm_command |= (unsigned long) (IM_RESET_IMM_CMD); - last_scsi_command(shpnt)[ldn] = IM_RESET_IMM_CMD; - last_scsi_type(shpnt)[ldn] = IM_IMM_CMD; - got_interrupt(shpnt) = 0; - reset_status(shpnt) = IM_RESET_IN_PROGRESS; - issue_cmd(shpnt, (unsigned long) (imm_command), IM_IMM_CMD | ldn); - ticks = IM_RESET_DELAY * HZ; - while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks) { - udelay((1 + 999 / HZ) * 1000); - barrier(); - } - /* if reset did not complete, just complain */ - if (!ticks) { - printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY); - reset_status(shpnt) = IM_RESET_FINISHED_OK; - /* did not work, finish */ - return 1; - } - /*if command successful, break */ - if (stat_result(shpnt) == IM_IMMEDIATE_CMD_COMPLETED) - return 1; - } - if (retries >= 3) - return 0; - else - return 1; -} -#endif - -/* type-interpreter for physical device numbers */ -static char *ti_p(int dev) -{ - switch (dev) { - case TYPE_IBM_SCSI_ADAPTER: - return ("A"); - case TYPE_DISK: - return ("D"); - case TYPE_TAPE: - return ("T"); - case TYPE_PROCESSOR: - return ("P"); - case TYPE_WORM: - return ("W"); - case TYPE_ROM: - return ("R"); - case TYPE_SCANNER: - return ("S"); - case TYPE_MOD: - return ("M"); - case TYPE_MEDIUM_CHANGER: - return ("C"); - case TYPE_NO_LUN: - return ("+"); /* show NO_LUN */ - } - return ("-"); /* TYPE_NO_DEVICE and others */ -} - -/* interpreter for logical device numbers (ldn) */ -static char *ti_l(int val) -{ - const char hex[16] = "0123456789abcdef"; - static char answer[2]; - - answer[1] = (char) (0x0); - if (val <= MAX_LOG_DEV) - answer[0] = hex[val]; - else - answer[0] = '-'; - return (char *) &answer; -} - -/* transfers bitpattern of the feature command to values in MHz */ -static char *ibmrate(unsigned int speed, int i) -{ - switch (speed) { - case 0: - return i ? "5.00" : "10.00"; - case 1: - return i ? "4.00" : "8.00"; - case 2: - return i ? "3.33" : "6.66"; - case 3: - return i ? "2.86" : "5.00"; - case 4: - return i ? "2.50" : "4.00"; - case 5: - return i ? "2.22" : "3.10"; - case 6: - return i ? "2.00" : "2.50"; - case 7: - return i ? "1.82" : "2.00"; - } - return "---"; -} - -static int probe_display(int what) -{ - static int rotator = 0; - const char rotor[] = "|/-\\"; - - if (!(display_mode & LED_DISP)) - return 0; - if (!what) { - outl(0x20202020, MOD95_LED_PORT); - outl(0x20202020, MOD95_LED_PORT + 4); - } else { - outb('S', MOD95_LED_PORT + 7); - outb('C', MOD95_LED_PORT + 6); - outb('S', MOD95_LED_PORT + 5); - outb('I', MOD95_LED_PORT + 4); - outb('i', MOD95_LED_PORT + 3); - outb('n', MOD95_LED_PORT + 2); - outb('i', MOD95_LED_PORT + 1); - outb((char) (rotor[rotator]), MOD95_LED_PORT); - rotator++; - if (rotator > 3) - rotator = 0; - } - return 0; -} - -static int probe_bus_mode(struct Scsi_Host *shpnt) -{ - struct im_pos_info *info; - int num_bus = 0; - int ldn; - - info = (struct im_pos_info *) (&(ld(shpnt)[MAX_LOG_DEV].buf)); - if (get_pos_info(shpnt)) { - if (info->connector_size & 0xf000) - subsystem_connector_size(shpnt) = 16; - else - subsystem_connector_size(shpnt) = 32; - num_bus |= (info->pos_4b & 8) >> 3; - for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) { - if ((special(shpnt) == IBM_SCSI_WCACHE) || (special(shpnt) == IBM_7568_WCACHE)) { - if (!((info->cache_stat >> ldn) & 1)) - ld(shpnt)[ldn].cache_flag = 0; - } - if (!((info->retry_stat >> ldn) & 1)) - ld(shpnt)[ldn].retry_flag = 0; - } -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: SCSI-Cache bits: "); - for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) { - printk("%d", ld(shpnt)[ldn].cache_flag); - } - printk("\nIBM MCA SCSI: SCSI-Retry bits: "); - for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) { - printk("%d", ld(shpnt)[ldn].retry_flag); - } - printk("\n"); -#endif - } - return num_bus; -} - -/* probing scsi devices */ -static void check_devices(struct Scsi_Host *shpnt, int adaptertype) -{ - int id, lun, ldn, ticks; - int count_devices; /* local counter for connected device */ - int max_pun; - int num_bus; - int speedrun; /* local adapter_speed check variable */ - - /* assign default values to certain variables */ - ticks = 0; - count_devices = 0; - IBM_DS(shpnt).dyn_flag = 0; /* normally no need for dynamical ldn management */ - IBM_DS(shpnt).total_errors = 0; /* set errorcounter to 0 */ - next_ldn(shpnt) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired' */ - - /* initialize the very important driver-informational arrays/structs */ - memset(ld(shpnt), 0, sizeof(ld(shpnt))); - for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) { - last_scsi_command(shpnt)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */ - last_scsi_type(shpnt)[ldn] = 0; - ld(shpnt)[ldn].cache_flag = 1; - ld(shpnt)[ldn].retry_flag = 1; - } - memset(get_ldn(shpnt), TYPE_NO_DEVICE, sizeof(get_ldn(shpnt))); /* this is essential ! */ - memset(get_scsi(shpnt), TYPE_NO_DEVICE, sizeof(get_scsi(shpnt))); /* this is essential ! */ - for (lun = 0; lun < 8; lun++) { - /* mark the adapter at its pun on all luns */ - get_scsi(shpnt)[subsystem_pun(shpnt)][lun] = TYPE_IBM_SCSI_ADAPTER; - get_ldn(shpnt)[subsystem_pun(shpnt)][lun] = MAX_LOG_DEV; /* make sure, the subsystem - ldn is active for all - luns. */ - } - probe_display(0); /* Supercool display usage during SCSI-probing. */ - /* This makes sense, when booting without any */ - /* monitor connected on model XX95. */ - - /* STEP 1: */ - adapter_speed(shpnt) = global_adapter_speed; - speedrun = adapter_speed(shpnt); - while (immediate_feature(shpnt, speedrun, adapter_timeout) == 2) { - probe_display(1); - if (speedrun == 7) - panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n"); - speedrun++; - if (speedrun > 7) - speedrun = 7; - } - adapter_speed(shpnt) = speedrun; - /* Get detailed information about the current adapter, necessary for - * device operations: */ - num_bus = probe_bus_mode(shpnt); - - /* num_bus contains only valid data for the F/W adapter! */ - if (adaptertype == IBM_SCSI2_FW) { /* F/W SCSI adapter: */ - /* F/W adapter PUN-space extension evaluation: */ - if (num_bus) { - printk(KERN_INFO "IBM MCA SCSI: Separate bus mode (wide-addressing enabled)\n"); - subsystem_maxid(shpnt) = 16; - } else { - printk(KERN_INFO "IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n"); - subsystem_maxid(shpnt) = 8; - } - printk(KERN_INFO "IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", ibmrate(speedrun, adaptertype)); - } else /* all other IBM SCSI adapters: */ - printk(KERN_INFO "IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", ibmrate(speedrun, adaptertype)); - - /* assign correct PUN device space */ - max_pun = subsystem_maxid(shpnt); - -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Current SCSI-host index: %d\n", shpnt); - printk("IBM MCA SCSI: Removing default logical SCSI-device mapping."); -#else - printk(KERN_INFO "IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ", (ibm_ansi_order) ? "ANSI" : "New"); -#endif - for (ldn = 0; ldn < MAX_LOG_DEV; ldn++) { - probe_display(1); -#ifdef IM_DEBUG_PROBE - printk("."); -#endif - immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN); /* remove ldn (wherever) */ - } - lun = 0; /* default lun is 0 */ -#ifndef IM_DEBUG_PROBE - printk("cleared,"); -#endif - /* STEP 2: */ -#ifdef IM_DEBUG_PROBE - printk("\nIBM MCA SCSI: Scanning SCSI-devices."); -#endif - for (id = 0; id < max_pun; id++) -#ifdef CONFIG_SCSI_MULTI_LUN - for (lun = 0; lun < 8; lun++) -#endif - { - probe_display(1); -#ifdef IM_DEBUG_PROBE - printk("."); -#endif - if (id != subsystem_pun(shpnt)) { - /* if pun is not the adapter: */ - /* set ldn=0 to pun,lun */ - immediate_assign(shpnt, id, lun, PROBE_LDN, SET_LDN); - if (device_inquiry(shpnt, PROBE_LDN)) { /* probe device */ - get_scsi(shpnt)[id][lun] = (unsigned char) (ld(shpnt)[PROBE_LDN].buf[0]); - /* entry, even for NO_LUN */ - if (ld(shpnt)[PROBE_LDN].buf[0] != TYPE_NO_LUN) - count_devices++; /* a existing device is found */ - } - /* remove ldn */ - immediate_assign(shpnt, id, lun, PROBE_LDN, REMOVE_LDN); - } - } -#ifndef IM_DEBUG_PROBE - printk("scanned,"); -#endif - /* STEP 3: */ -#ifdef IM_DEBUG_PROBE - printk("\nIBM MCA SCSI: Mapping SCSI-devices."); -#endif - ldn = 0; - lun = 0; -#ifdef CONFIG_SCSI_MULTI_LUN - for (lun = 0; lun < 8 && ldn < MAX_LOG_DEV; lun++) -#endif - for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) { - probe_display(1); -#ifdef IM_DEBUG_PROBE - printk("."); -#endif - if (id != subsystem_pun(shpnt)) { - if (get_scsi(shpnt)[id][lun] != TYPE_NO_LUN && get_scsi(shpnt)[id][lun] != TYPE_NO_DEVICE) { - /* Only map if accepted type. Always enter for - lun == 0 to get no gaps into ldn-mapping for ldn<7. */ - immediate_assign(shpnt, id, lun, ldn, SET_LDN); - get_ldn(shpnt)[id][lun] = ldn; /* map ldn */ - if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) { -#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET - printk("resetting device at ldn=%x ... ", ldn); - immediate_reset(shpnt, ldn); -#endif - ldn++; - } else { - /* device vanished, probably because we don't know how to - * handle it or because it has problems */ - if (lun > 0) { - /* remove mapping */ - get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE; - immediate_assign(shpnt, 0, 0, ldn, REMOVE_LDN); - } else - ldn++; - } - } else if (lun == 0) { - /* map lun == 0, even if no device exists */ - immediate_assign(shpnt, id, lun, ldn, SET_LDN); - get_ldn(shpnt)[id][lun] = ldn; /* map ldn */ - ldn++; - } - } - } - /* STEP 4: */ - - /* map remaining ldns to non-existing devices */ - for (lun = 1; lun < 8 && ldn < MAX_LOG_DEV; lun++) - for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) { - if (get_scsi(shpnt)[id][lun] == TYPE_NO_LUN || get_scsi(shpnt)[id][lun] == TYPE_NO_DEVICE) { - probe_display(1); - /* Map remaining ldns only to NON-existing pun,lun - combinations to make sure an inquiry will fail. - For MULTI_LUN, it is needed to avoid adapter autonome - SCSI-remapping. */ - immediate_assign(shpnt, id, lun, ldn, SET_LDN); - get_ldn(shpnt)[id][lun] = ldn; - ldn++; - } - } -#ifndef IM_DEBUG_PROBE - printk("mapped."); -#endif - printk("\n"); -#ifdef IM_DEBUG_PROBE - if (ibm_ansi_order) - printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n"); - else - printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n"); -#endif - -#ifdef IM_DEBUG_PROBE - /* Show the physical and logical mapping during boot. */ - printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n"); - printk(" Physical SCSI-Device Map Logical SCSI-Device Map\n"); - printk("ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n"); - for (id = 0; id < max_pun; id++) { - printk("%2d ", id); - for (lun = 0; lun < 8; lun++) - printk("%2s ", ti_p(get_scsi(shpnt)[id][lun])); - printk(" %2d ", id); - for (lun = 0; lun < 8; lun++) - printk("%2s ", ti_l(get_ldn(shpnt)[id][lun])); - printk("\n"); - } -#endif - - /* assign total number of found SCSI-devices to the statistics struct */ - IBM_DS(shpnt).total_scsi_devices = count_devices; - - /* decide for output in /proc-filesystem, if the configuration of - SCSI-devices makes dynamical reassignment of devices necessary */ - if (count_devices >= MAX_LOG_DEV) - IBM_DS(shpnt).dyn_flag = 1; /* dynamical assignment is necessary */ - else - IBM_DS(shpnt).dyn_flag = 0; /* dynamical assignment is not necessary */ - - /* If no SCSI-devices are assigned, return 1 in order to cause message. */ - if (ldn == 0) - printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n"); - - /* reset the counters for statistics on the current adapter */ - IBM_DS(shpnt).scbs = 0; - IBM_DS(shpnt).long_scbs = 0; - IBM_DS(shpnt).total_accesses = 0; - IBM_DS(shpnt).total_interrupts = 0; - IBM_DS(shpnt).dynamical_assignments = 0; - memset(IBM_DS(shpnt).ldn_access, 0x0, sizeof(IBM_DS(shpnt).ldn_access)); - memset(IBM_DS(shpnt).ldn_read_access, 0x0, sizeof(IBM_DS(shpnt).ldn_read_access)); - memset(IBM_DS(shpnt).ldn_write_access, 0x0, sizeof(IBM_DS(shpnt).ldn_write_access)); - memset(IBM_DS(shpnt).ldn_inquiry_access, 0x0, sizeof(IBM_DS(shpnt).ldn_inquiry_access)); - memset(IBM_DS(shpnt).ldn_modeselect_access, 0x0, sizeof(IBM_DS(shpnt).ldn_modeselect_access)); - memset(IBM_DS(shpnt).ldn_assignments, 0x0, sizeof(IBM_DS(shpnt).ldn_assignments)); - probe_display(0); - return; -} - -static int device_exists(struct Scsi_Host *shpnt, int ldn, int *block_length, int *device_type) -{ - unsigned char *buf; - /* if no valid device found, return immediately with 0 */ - if (!(device_inquiry(shpnt, ldn))) - return 0; - buf = (unsigned char *) (&(ld(shpnt)[ldn].buf)); - if (*buf == TYPE_ROM) { - *device_type = TYPE_ROM; - *block_length = 2048; /* (standard blocksize for yellow-/red-book) */ - return 1; - } - if (*buf == TYPE_WORM) { - *device_type = TYPE_WORM; - *block_length = 2048; - return 1; - } - if (*buf == TYPE_DISK) { - *device_type = TYPE_DISK; - if (read_capacity(shpnt, ldn)) { - *block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24); - return 1; - } else - return 0; - } - if (*buf == TYPE_MOD) { - *device_type = TYPE_MOD; - if (read_capacity(shpnt, ldn)) { - *block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24); - return 1; - } else - return 0; - } - if (*buf == TYPE_TAPE) { - *device_type = TYPE_TAPE; - *block_length = 0; /* not in use (setting by mt and mtst in op.) */ - return 1; - } - if (*buf == TYPE_PROCESSOR) { - *device_type = TYPE_PROCESSOR; - *block_length = 0; /* they set their stuff on drivers */ - return 1; - } - if (*buf == TYPE_SCANNER) { - *device_type = TYPE_SCANNER; - *block_length = 0; /* they set their stuff on drivers */ - return 1; - } - if (*buf == TYPE_MEDIUM_CHANGER) { - *device_type = TYPE_MEDIUM_CHANGER; - *block_length = 0; /* One never knows, what to expect on a medium - changer device. */ - return 1; - } - return 0; -} - -static void internal_ibmmca_scsi_setup(char *str, int *ints) -{ - int i, j, io_base, id_base; - char *token; - - io_base = 0; - id_base = 0; - if (str) { - j = 0; - while ((token = strsep(&str, ",")) != NULL) { - if (!strcmp(token, "activity")) - display_mode |= LED_ACTIVITY; - if (!strcmp(token, "display")) - display_mode |= LED_DISP; - if (!strcmp(token, "adisplay")) - display_mode |= LED_ADISP; - if (!strcmp(token, "normal")) - ibm_ansi_order = 0; - if (!strcmp(token, "ansi")) - ibm_ansi_order = 1; - if (!strcmp(token, "fast")) - global_adapter_speed = 0; - if (!strcmp(token, "medium")) - global_adapter_speed = 4; - if (!strcmp(token, "slow")) - global_adapter_speed = 7; - if ((*token == '-') || (isdigit(*token))) { - if (!(j % 2) && (io_base < IM_MAX_HOSTS)) - io_port[io_base++] = simple_strtoul(token, NULL, 0); - if ((j % 2) && (id_base < IM_MAX_HOSTS)) - scsi_id[id_base++] = simple_strtoul(token, NULL, 0); - j++; - } - } - } else if (ints) { - for (i = 0; i < IM_MAX_HOSTS && 2 * i + 2 < ints[0]; i++) { - io_port[i] = ints[2 * i + 2]; - scsi_id[i] = ints[2 * i + 2]; - } - } - return; -} - -#if 0 - FIXME NEED TO MOVE TO SYSFS - -static int ibmmca_getinfo(char *buf, int slot, void *dev_id) -{ - struct Scsi_Host *shpnt; - int len, speciale, connectore, k; - unsigned int pos[8]; - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave(dev->host_lock, flags); - - shpnt = dev; /* assign host-structure to local pointer */ - len = 0; /* set filled text-buffer index to 0 */ - /* get the _special contents of the hostdata structure */ - speciale = ((struct ibmmca_hostdata *) shpnt->hostdata)->_special; - connectore = ((struct ibmmca_hostdata *) shpnt->hostdata)->_connector_size; - for (k = 2; k < 4; k++) - pos[k] = ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k]; - if (speciale == FORCED_DETECTION) { /* forced detection */ - len += sprintf(buf + len, - "Adapter category: forced detected\n" "***************************************\n" "*** Forced detected SCSI Adapter ***\n" "*** No chip-information available ***\n" "***************************************\n"); - } else if (speciale == INTEGRATED_SCSI) { - /* if the integrated subsystem has been found automatically: */ - len += sprintf(buf + len, - "Adapter category: integrated\n" "Chip revision level: %d\n" "Chip status: %s\n" "8 kByte NVRAM status: %s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 1) ? "enabled" : "disabled", (pos[2] & 2) ? "locked" : "accessible"); - } else if ((speciale >= 0) && (speciale < ARRAY_SIZE(subsys_list))) { - /* if the subsystem is a slot adapter */ - len += sprintf(buf + len, "Adapter category: slot-card\n" "ROM Segment Address: "); - if ((pos[2] & 0xf0) == 0xf0) - len += sprintf(buf + len, "off\n"); - else - len += sprintf(buf + len, "0x%x\n", ((pos[2] & 0xf0) << 13) + 0xc0000); - len += sprintf(buf + len, "Chip status: %s\n", (pos[2] & 1) ? "enabled" : "disabled"); - len += sprintf(buf + len, "Adapter I/O Offset: 0x%x\n", ((pos[2] & 0x0e) << 2)); - } else { - len += sprintf(buf + len, "Adapter category: unknown\n"); - } - /* common subsystem information to write to the slotn file */ - len += sprintf(buf + len, "Subsystem PUN: %d\n", shpnt->this_id); - len += sprintf(buf + len, "I/O base address range: 0x%x-0x%x\n", (unsigned int) (shpnt->io_port), (unsigned int) (shpnt->io_port + 7)); - len += sprintf(buf + len, "MCA-slot size: %d bits", connectore); - /* Now make sure, the bufferlength is devidable by 4 to avoid - * paging problems of the buffer. */ - while (len % sizeof(int) != (sizeof(int) - 1)) - len += sprintf(buf + len, " "); - len += sprintf(buf + len, "\n"); - - spin_unlock_irqrestore(shpnt->host_lock, flags); - - return len; -} -#endif - -static struct scsi_host_template ibmmca_driver_template = { - .proc_name = "ibmmca", - .proc_info = ibmmca_proc_info, - .name = "IBM SCSI-Subsystem", - .queuecommand = ibmmca_queuecommand, - .eh_abort_handler = ibmmca_abort, - .eh_host_reset_handler = ibmmca_host_reset, - .bios_param = ibmmca_biosparam, - .can_queue = 16, - .this_id = 7, - .sg_tablesize = 16, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -static int ibmmca_probe(struct device *dev) -{ - struct Scsi_Host *shpnt; - int port, id, i, j, k, irq, enabled, ret = -EINVAL; - struct mca_device *mca_dev = to_mca_device(dev); - const char *description = ibmmca_description[mca_dev->index]; - - /* First of all, print the version number of the driver. This is - * important to allow better user bugreports in case of already - * having problems with the MCA_bus probing. */ - printk(KERN_INFO "IBM MCA SCSI: Version %s\n", IBMMCA_SCSI_DRIVER_VERSION); - /* The POS2-register of all PS/2 model SCSI-subsystems has the following - * interpretation of bits: - * Bit 7 - 4 : Chip Revision ID (Release) - * Bit 3 - 2 : Reserved - * Bit 1 : 8k NVRAM Disabled - * Bit 0 : Chip Enable (EN-Signal) - * The POS3-register is interpreted as follows: - * Bit 7 - 5 : SCSI ID - * Bit 4 : Reserved = 0 - * Bit 3 - 0 : Reserved = 0 - * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common - * Interfaces (1991)"). - * In short words, this means, that IBM PS/2 machines only support - * 1 single subsystem by default. The slot-adapters must have another - * configuration on pos2. Here, one has to assume the following - * things for POS2-register: - * Bit 7 - 4 : Chip Revision ID (Release) - * Bit 3 - 1 : port offset factor - * Bit 0 : Chip Enable (EN-Signal) - * As I found a patch here, setting the IO-registers to 0x3540 forced, - * as there was a 0x05 in POS2 on a model 56, I assume, that the - * port 0x3540 must be fix for integrated SCSI-controllers. - * Ok, this discovery leads to the following implementation: (M.Lang) */ - - /* first look for the IBM SCSI integrated subsystem on the motherboard */ - for (j = 0; j < 8; j++) /* read the pos-information */ - pos[j] = mca_device_read_pos(mca_dev, j); - id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */ - enabled = (pos[2] &0x01); - if (!enabled) { - printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"); - printk(KERN_WARNING " SCSI-operations may not work.\n"); - } - - /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but - * if we ignore the settings of all surrounding pos registers, it is not - * completely sufficient to only check pos2 and pos3. */ - /* Therefore, now the following if statement is used to - * make sure, we see a real integrated onboard SCSI-interface and no - * internal system information, which gets mapped to some pos registers - * on models 95xx. */ - if (mca_dev->slot == MCA_INTEGSCSI && - ((!pos[0] && !pos[1] && pos[2] > 0 && - pos[3] > 0 && !pos[4] && !pos[5] && - !pos[6] && !pos[7]) || - (pos[0] == 0xff && pos[1] == 0xff && - pos[2] < 0xff && pos[3] < 0xff && - pos[4] == 0xff && pos[5] == 0xff && - pos[6] == 0xff && pos[7] == 0xff))) { - irq = IM_IRQ; - port = IM_IO_PORT; - } else { - irq = IM_IRQ; - port = IM_IO_PORT + ((pos[2] &0x0e) << 2); - if ((mca_dev->index == IBM_SCSI2_FW) && (pos[6] != 0)) { - printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n"); - printk(KERN_ERR " Impossible to determine adapter PUN!\n"); - printk(KERN_ERR " Guessing adapter PUN = 7.\n"); - id = 7; - } else { - id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */ - if (mca_dev->index == IBM_SCSI2_FW) { - id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit - * for F/W adapters */ - } - } - if ((mca_dev->index == IBM_SCSI2_FW) && - (pos[4] & 0x01) && (pos[6] == 0)) { - /* IRQ11 is used by SCSI-2 F/W Adapter/A */ - printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n"); - irq = IM_IRQ_FW; - } - } - - - - /* give detailed information on the subsystem. This helps me - * additionally during debugging and analyzing bug-reports. */ - printk(KERN_INFO "IBM MCA SCSI: %s found, io=0x%x, scsi id=%d,\n", - description, port, id); - if (mca_dev->slot == MCA_INTEGSCSI) - printk(KERN_INFO " chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", (pos[2] & 1) ? "enabled." : "disabled."); - else { - if ((pos[2] & 0xf0) == 0xf0) - printk(KERN_DEBUG " ROM Addr.=off,"); - else - printk(KERN_DEBUG " ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000); - - printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled."); - } - - /* check I/O region */ - if (!request_region(port, IM_N_IO_PORT, description)) { - printk(KERN_ERR "IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT); - goto out_fail; - } - - /* register host */ - shpnt = scsi_host_alloc(&ibmmca_driver_template, - sizeof(struct ibmmca_hostdata)); - if (!shpnt) { - printk(KERN_ERR "IBM MCA SCSI: Unable to register host.\n"); - goto out_release; - } - - dev_set_drvdata(dev, shpnt); - if(request_irq(irq, interrupt_handler, IRQF_SHARED, description, dev)) { - printk(KERN_ERR "IBM MCA SCSI: failed to request interrupt %d\n", irq); - goto out_free_host; - } - - /* request I/O region */ - special(shpnt) = mca_dev->index; /* important assignment or else crash! */ - subsystem_connector_size(shpnt) = 0; /* preset slot-size */ - shpnt->irq = irq; /* assign necessary stuff for the adapter */ - shpnt->io_port = port; - shpnt->n_io_port = IM_N_IO_PORT; - shpnt->this_id = id; - shpnt->max_id = 8; /* 8 PUNs are default */ - /* now, the SCSI-subsystem is connected to Linux */ - -#ifdef IM_DEBUG_PROBE - ctrl = (unsigned int) (inb(IM_CTR_REG(found))); /* get control-register status */ - printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", ctrl, inb(IM_STAT_REG(found))); - printk("IBM MCA SCSI: This adapters' POS-registers: "); - for (i = 0; i < 8; i++) - printk("%x ", pos[i]); - printk("\n"); -#endif - reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS; - - for (i = 0; i < 16; i++) /* reset the tables */ - for (j = 0; j < 8; j++) - get_ldn(shpnt)[i][j] = MAX_LOG_DEV; - - /* check which logical devices exist */ - /* after this line, local interrupting is possible: */ - local_checking_phase_flag(shpnt) = 1; - check_devices(shpnt, mca_dev->index); /* call by value, using the global variable hosts */ - local_checking_phase_flag(shpnt) = 0; - - /* an ibm mca subsystem has been detected */ - - for (k = 2; k < 7; k++) - ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k]; - ((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI; - mca_device_set_name(mca_dev, description); - /* FIXME: NEED TO REPLUMB TO SYSFS - mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt); - */ - mca_device_set_claim(mca_dev, 1); - if (scsi_add_host(shpnt, dev)) { - dev_printk(KERN_ERR, dev, "IBM MCA SCSI: scsi_add_host failed\n"); - goto out_free_host; - } - scsi_scan_host(shpnt); - - return 0; - out_free_host: - scsi_host_put(shpnt); - out_release: - release_region(port, IM_N_IO_PORT); - out_fail: - return ret; -} - -static int __devexit ibmmca_remove(struct device *dev) -{ - struct Scsi_Host *shpnt = dev_get_drvdata(dev); - scsi_remove_host(shpnt); - release_region(shpnt->io_port, shpnt->n_io_port); - free_irq(shpnt->irq, dev); - scsi_host_put(shpnt); - return 0; -} - -/* The following routine is the SCSI command queue for the midlevel driver */ -static int ibmmca_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) -{ - unsigned int ldn; - unsigned int scsi_cmd; - struct im_scb *scb; - struct Scsi_Host *shpnt; - int current_ldn; - int id, lun; - int target; - int max_pun; - int i; - struct scatterlist *sg; - - shpnt = cmd->device->host; - - max_pun = subsystem_maxid(shpnt); - if (ibm_ansi_order) { - target = max_pun - 1 - cmd->device->id; - if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt))) - target--; - else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt))) - target++; - } else - target = cmd->device->id; - - /* if (target,lun) is NO LUN or not existing at all, return error */ - if ((get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_LUN) || (get_scsi(shpnt)[target][cmd->device->lun] == TYPE_NO_DEVICE)) { - cmd->result = DID_NO_CONNECT << 16; - if (done) - done(cmd); - return 0; - } - - /*if (target,lun) unassigned, do further checks... */ - ldn = get_ldn(shpnt)[target][cmd->device->lun]; - if (ldn >= MAX_LOG_DEV) { /* on invalid ldn do special stuff */ - if (ldn > MAX_LOG_DEV) { /* dynamical remapping if ldn unassigned */ - current_ldn = next_ldn(shpnt); /* stop-value for one circle */ - while (ld(shpnt)[next_ldn(shpnt)].cmd) { /* search for a occupied, but not in */ - /* command-processing ldn. */ - next_ldn(shpnt)++; - if (next_ldn(shpnt) >= MAX_LOG_DEV) - next_ldn(shpnt) = 7; - if (current_ldn == next_ldn(shpnt)) { /* One circle done ? */ - /* no non-processing ldn found */ - scmd_printk(KERN_WARNING, cmd, - "IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n" - " On ldn 7-14 SCSI-commands everywhere in progress.\n" - " Reporting DID_NO_CONNECT for device.\n"); - cmd->result = DID_NO_CONNECT << 16; /* return no connect */ - if (done) - done(cmd); - return 0; - } - } - - /* unmap non-processing ldn */ - for (id = 0; id < max_pun; id++) - for (lun = 0; lun < 8; lun++) { - if (get_ldn(shpnt)[id][lun] == next_ldn(shpnt)) { - get_ldn(shpnt)[id][lun] = TYPE_NO_DEVICE; - get_scsi(shpnt)[id][lun] = TYPE_NO_DEVICE; - /* unmap entry */ - } - } - /* set reduced interrupt_handler-mode for checking */ - local_checking_phase_flag(shpnt) = 1; - /* map found ldn to pun,lun */ - get_ldn(shpnt)[target][cmd->device->lun] = next_ldn(shpnt); - /* change ldn to the right value, that is now next_ldn */ - ldn = next_ldn(shpnt); - /* unassign all ldns (pun,lun,ldn does not matter for remove) */ - immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN); - /* set only LDN for remapped device */ - immediate_assign(shpnt, target, cmd->device->lun, ldn, SET_LDN); - /* get device information for ld[ldn] */ - if (device_exists(shpnt, ldn, &ld(shpnt)[ldn].block_length, &ld(shpnt)[ldn].device_type)) { - ld(shpnt)[ldn].cmd = NULL; /* To prevent panic set 0, because - devices that were not assigned, - should have nothing in progress. */ - get_scsi(shpnt)[target][cmd->device->lun] = ld(shpnt)[ldn].device_type; - /* increase assignment counters for statistics in /proc */ - IBM_DS(shpnt).dynamical_assignments++; - IBM_DS(shpnt).ldn_assignments[ldn]++; - } else - /* panic here, because a device, found at boottime has - vanished */ - panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", ldn, target, cmd->device->lun); - /* unassign again all ldns (pun,lun,ldn does not matter for remove) */ - immediate_assign(shpnt, 0, 0, 0, REMOVE_LDN); - /* remap all ldns, as written in the pun/lun table */ - lun = 0; -#ifdef CONFIG_SCSI_MULTI_LUN - for (lun = 0; lun < 8; lun++) -#endif - for (id = 0; id < max_pun; id++) { - if (get_ldn(shpnt)[id][lun] <= MAX_LOG_DEV) - immediate_assign(shpnt, id, lun, get_ldn(shpnt)[id][lun], SET_LDN); - } - /* set back to normal interrupt_handling */ - local_checking_phase_flag(shpnt) = 0; -#ifdef IM_DEBUG_PROBE - /* Information on syslog terminal */ - printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", ldn, target, cmd->device->lun); -#endif - /* increase next_ldn for next dynamical assignment */ - next_ldn(shpnt)++; - if (next_ldn(shpnt) >= MAX_LOG_DEV) - next_ldn(shpnt) = 7; - } else { /* wall against Linux accesses to the subsystem adapter */ - cmd->result = DID_BAD_TARGET << 16; - if (done) - done(cmd); - return 0; - } - } - - /*verify there is no command already in progress for this log dev */ - if (ld(shpnt)[ldn].cmd) - panic("IBM MCA SCSI: cmd already in progress for this ldn.\n"); - - /*save done in cmd, and save cmd for the interrupt handler */ - cmd->scsi_done = done; - ld(shpnt)[ldn].cmd = cmd; - - /*fill scb information independent of the scsi command */ - scb = &(ld(shpnt)[ldn].scb); - ld(shpnt)[ldn].tsb.dev_status = 0; - scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE; - scb->tsb_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].tsb)); - scsi_cmd = cmd->cmnd[0]; - - if (scsi_sg_count(cmd)) { - BUG_ON(scsi_sg_count(cmd) > 16); - - scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) { - ld(shpnt)[ldn].sge[i].address = (void *) (isa_page_to_bus(sg_page(sg)) + sg->offset); - ld(shpnt)[ldn].sge[i].byte_length = sg->length; - } - scb->enable |= IM_POINTER_TO_LIST; - scb->sys_buf_adr = isa_virt_to_bus(&(ld(shpnt)[ldn].sge[0])); - scb->sys_buf_length = scsi_sg_count(cmd) * sizeof(struct im_sge); - } else { - scb->sys_buf_adr = isa_virt_to_bus(scsi_sglist(cmd)); - /* recent Linux midlevel SCSI places 1024 byte for inquiry - * command. Far too much for old PS/2 hardware. */ - switch (scsi_cmd) { - /* avoid command errors by setting bufferlengths to - * ANSI-standard. Beware of forcing it to 255, - * this could SEGV the kernel!!! */ - case INQUIRY: - case REQUEST_SENSE: - case MODE_SENSE: - case MODE_SELECT: - if (scsi_bufflen(cmd) > 255) - scb->sys_buf_length = 255; - else - scb->sys_buf_length = scsi_bufflen(cmd); - break; - case TEST_UNIT_READY: - scb->sys_buf_length = 0; - break; - default: - scb->sys_buf_length = scsi_bufflen(cmd); - break; - } - } - /*fill scb information dependent on scsi command */ - -#ifdef IM_DEBUG_CMD - printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn); -#endif - - /* for specific device-type debugging: */ -#ifdef IM_DEBUG_CMD_SPEC_DEV - if (ld(shpnt)[ldn].device_type == IM_DEBUG_CMD_DEVICE) - printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(shpnt)[ldn].device_type, scsi_cmd, ldn); -#endif - - /* for possible panics store current command */ - last_scsi_command(shpnt)[ldn] = scsi_cmd; - last_scsi_type(shpnt)[ldn] = IM_SCB; - /* update statistical info */ - IBM_DS(shpnt).total_accesses++; - IBM_DS(shpnt).ldn_access[ldn]++; - - switch (scsi_cmd) { - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - /* Distinguish between disk and other devices. Only disks (that are the - most frequently accessed devices) should be supported by the - IBM-SCSI-Subsystem commands. */ - switch (ld(shpnt)[ldn].device_type) { - case TYPE_DISK: /* for harddisks enter here ... */ - case TYPE_MOD: /* ... try it also for MO-drives (send flames as */ - /* you like, if this won't work.) */ - if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) { - /* read command preparations */ - scb->enable |= IM_READ_CONTROL; - IBM_DS(shpnt).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */ - scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT; - } else { /* write command preparations */ - IBM_DS(shpnt).ldn_write_access[ldn]++; /* increase write-count on ldn stat. */ - scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT; - } - if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) { - scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | (((unsigned) cmd->cmnd[2]) << 8) | ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16); - scb->u2.blk.count = (unsigned) cmd->cmnd[4]; - } else { - scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | (((unsigned) cmd->cmnd[4]) << 8) | (((unsigned) cmd->cmnd[3]) << 16) | (((unsigned) cmd->cmnd[2]) << 24); - scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | (((unsigned) cmd->cmnd[7]) << 8); - } - last_scsi_logical_block(shpnt)[ldn] = scb->u1.log_blk_adr; - last_scsi_blockcount(shpnt)[ldn] = scb->u2.blk.count; - scb->u2.blk.length = ld(shpnt)[ldn].block_length; - break; - /* for other devices, enter here. Other types are not known by - Linux! TYPE_NO_LUN is forbidden as valid device. */ - case TYPE_ROM: - case TYPE_TAPE: - case TYPE_PROCESSOR: - case TYPE_WORM: - case TYPE_SCANNER: - case TYPE_MEDIUM_CHANGER: - /* If there is a sequential-device, IBM recommends to use - IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE. - This includes CD-ROM devices, too, due to the partial sequential - read capabilities. */ - scb->command = IM_OTHER_SCSI_CMD_CMD; - if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) - /* enable READ */ - scb->enable |= IM_READ_CONTROL; - scb->enable |= IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(shpnt)[ldn] = IM_LONG_SCB; - /* Read/write on this non-disk devices is also displayworthy, - so flash-up the LED/display. */ - break; - } - break; - case INQUIRY: - IBM_DS(shpnt).ldn_inquiry_access[ldn]++; - scb->command = IM_DEVICE_INQUIRY_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.log_blk_adr = 0; - break; - case TEST_UNIT_READY: - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.log_blk_adr = 0; - scb->u1.scsi_cmd_length = 6; - memcpy(scb->u2.scsi_command, cmd->cmnd, 6); - last_scsi_type(shpnt)[ldn] = IM_LONG_SCB; - break; - case READ_CAPACITY: - /* the length of system memory buffer must be exactly 8 bytes */ - scb->command = IM_READ_CAPACITY_CMD; - scb->enable |= IM_READ_CONTROL | IM_BYPASS_BUFFER; - if (scb->sys_buf_length > 8) - scb->sys_buf_length = 8; - break; - /* Commands that need read-only-mode (system <- device): */ - case REQUEST_SENSE: - scb->command = IM_REQUEST_SENSE_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - break; - /* Commands that need write-only-mode (system -> device): */ - case MODE_SELECT: - case MODE_SELECT_10: - IBM_DS(shpnt).ldn_modeselect_access[ldn]++; - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled */ - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(shpnt)[ldn] = IM_LONG_SCB; - break; - /* For other commands, read-only is useful. Most other commands are - running without an input-data-block. */ - default: - scb->command = IM_OTHER_SCSI_CMD_CMD; - scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; - scb->u1.scsi_cmd_length = cmd->cmd_len; - memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len); - last_scsi_type(shpnt)[ldn] = IM_LONG_SCB; - break; - } - /*issue scb command, and return */ - if (++disk_rw_in_progress == 1) - PS2_DISK_LED_ON(shpnt->host_no, target); - - if (last_scsi_type(shpnt)[ldn] == IM_LONG_SCB) { - issue_cmd(shpnt, isa_virt_to_bus(scb), IM_LONG_SCB | ldn); - IBM_DS(shpnt).long_scbs++; - } else { - issue_cmd(shpnt, isa_virt_to_bus(scb), IM_SCB | ldn); - IBM_DS(shpnt).scbs++; - } - return 0; -} - -static DEF_SCSI_QCMD(ibmmca_queuecommand) - -static int __ibmmca_abort(Scsi_Cmnd * cmd) -{ - /* Abort does not work, as the adapter never generates an interrupt on - * whatever situation is simulated, even when really pending commands - * are running on the adapters' hardware ! */ - - struct Scsi_Host *shpnt; - unsigned int ldn; - void (*saved_done) (Scsi_Cmnd *); - int target; - int max_pun; - unsigned long imm_command; - -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Abort subroutine called...\n"); -#endif - - shpnt = cmd->device->host; - - max_pun = subsystem_maxid(shpnt); - if (ibm_ansi_order) { - target = max_pun - 1 - cmd->device->id; - if ((target <= subsystem_pun(shpnt)) && (cmd->device->id <= subsystem_pun(shpnt))) - target--; - else if ((target >= subsystem_pun(shpnt)) && (cmd->device->id >= subsystem_pun(shpnt))) - target++; - } else - target = cmd->device->id; - - /* get logical device number, and disable system interrupts */ - printk(KERN_WARNING "IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", target, cmd->device->lun); - ldn = get_ldn(shpnt)[target][cmd->device->lun]; - - /*if cmd for this ldn has already finished, no need to abort */ - if (!ld(shpnt)[ldn].cmd) { - return SUCCESS; - } - - /* Clear ld.cmd, save done function, install internal done, - * send abort immediate command (this enables sys. interrupts), - * and wait until the interrupt arrives. - */ - saved_done = cmd->scsi_done; - cmd->scsi_done = internal_done; - cmd->SCp.Status = 0; - last_scsi_command(shpnt)[ldn] = IM_ABORT_IMM_CMD; - last_scsi_type(shpnt)[ldn] = IM_IMM_CMD; - imm_command = inl(IM_CMD_REG(shpnt)); - imm_command &= (unsigned long) (0xffff0000); /* mask reserved stuff */ - imm_command |= (unsigned long) (IM_ABORT_IMM_CMD); - /* must wait for attention reg not busy */ - /* FIXME - timeout, politeness */ - while (1) { - if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY)) - break; - } - /* write registers and enable system interrupts */ - outl(imm_command, IM_CMD_REG(shpnt)); - outb(IM_IMM_CMD | ldn, IM_ATTN_REG(shpnt)); -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Abort queued to adapter...\n"); -#endif - spin_unlock_irq(shpnt->host_lock); - while (!cmd->SCp.Status) - yield(); - spin_lock_irq(shpnt->host_lock); - cmd->scsi_done = saved_done; -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Abort returned with adapter response...\n"); -#endif - - /*if abort went well, call saved done, then return success or error */ - if (cmd->result == (DID_ABORT << 16)) - { - cmd->result |= DID_ABORT << 16; - if (cmd->scsi_done) - (cmd->scsi_done) (cmd); - ld(shpnt)[ldn].cmd = NULL; -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Abort finished with success.\n"); -#endif - return SUCCESS; - } else { - cmd->result |= DID_NO_CONNECT << 16; - if (cmd->scsi_done) - (cmd->scsi_done) (cmd); - ld(shpnt)[ldn].cmd = NULL; -#ifdef IM_DEBUG_PROBE - printk("IBM MCA SCSI: Abort failed.\n"); -#endif - return FAILED; - } -} - -static int ibmmca_abort(Scsi_Cmnd * cmd) -{ - struct Scsi_Host *shpnt = cmd->device->host; - int rc; - - spin_lock_irq(shpnt->host_lock); - rc = __ibmmca_abort(cmd); - spin_unlock_irq(shpnt->host_lock); - - return rc; -} - -static int __ibmmca_host_reset(Scsi_Cmnd * cmd) -{ - struct Scsi_Host *shpnt; - Scsi_Cmnd *cmd_aid; - int ticks, i; - unsigned long imm_command; - - BUG_ON(cmd == NULL); - - ticks = IM_RESET_DELAY * HZ; - shpnt = cmd->device->host; - - if (local_checking_phase_flag(shpnt)) { - printk(KERN_WARNING "IBM MCA SCSI: unable to reset while checking devices.\n"); - return FAILED; - } - - /* issue reset immediate command to subsystem, and wait for interrupt */ - printk("IBM MCA SCSI: resetting all devices.\n"); - reset_status(shpnt) = IM_RESET_IN_PROGRESS; - last_scsi_command(shpnt)[0xf] = IM_RESET_IMM_CMD; - last_scsi_type(shpnt)[0xf] = IM_IMM_CMD; - imm_command = inl(IM_CMD_REG(shpnt)); - imm_command &= (unsigned long) (0xffff0000); /* mask reserved stuff */ - imm_command |= (unsigned long) (IM_RESET_IMM_CMD); - /* must wait for attention reg not busy */ - while (1) { - if (!(inb(IM_STAT_REG(shpnt)) & IM_BUSY)) - break; - spin_unlock_irq(shpnt->host_lock); - yield(); - spin_lock_irq(shpnt->host_lock); - } - /*write registers and enable system interrupts */ - outl(imm_command, IM_CMD_REG(shpnt)); - outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(shpnt)); - /* wait for interrupt finished or intr_stat register to be set, as the - * interrupt will not be executed, while we are in here! */ - - /* FIXME: This is really really icky we so want a sleeping version of this ! */ - while (reset_status(shpnt) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(shpnt)) & 0x8f) != 0x8f)) { - udelay((1 + 999 / HZ) * 1000); - barrier(); - } - /* if reset did not complete, just return an error */ - if (!ticks) { - printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY); - reset_status(shpnt) = IM_RESET_FINISHED_FAIL; - return FAILED; - } - - if ((inb(IM_INTR_REG(shpnt)) & 0x8f) == 0x8f) { - /* analysis done by this routine and not by the intr-routine */ - if (inb(IM_INTR_REG(shpnt)) == 0xaf) - reset_status(shpnt) = IM_RESET_FINISHED_OK_NO_INT; - else if (inb(IM_INTR_REG(shpnt)) == 0xcf) - reset_status(shpnt) = IM_RESET_FINISHED_FAIL; - else /* failed, 4get it */ - reset_status(shpnt) = IM_RESET_NOT_IN_PROGRESS_NO_INT; - outb(IM_EOI | 0xf, IM_ATTN_REG(shpnt)); - } - - /* if reset failed, just return an error */ - if (reset_status(shpnt) == IM_RESET_FINISHED_FAIL) { - printk(KERN_ERR "IBM MCA SCSI: reset failed.\n"); - return FAILED; - } - - /* so reset finished ok - call outstanding done's, and return success */ - printk(KERN_INFO "IBM MCA SCSI: Reset successfully completed.\n"); - for (i = 0; i < MAX_LOG_DEV; i++) { - cmd_aid = ld(shpnt)[i].cmd; - if (cmd_aid && cmd_aid->scsi_done) { - ld(shpnt)[i].cmd = NULL; - cmd_aid->result = DID_RESET << 16; - } - } - return SUCCESS; -} - -static int ibmmca_host_reset(Scsi_Cmnd * cmd) -{ - struct Scsi_Host *shpnt = cmd->device->host; - int rc; - - spin_lock_irq(shpnt->host_lock); - rc = __ibmmca_host_reset(cmd); - spin_unlock_irq(shpnt->host_lock); - - return rc; -} - -static int ibmmca_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *info) -{ - int size = capacity; - info[0] = 64; - info[1] = 32; - info[2] = size / (info[0] * info[1]); - if (info[2] >= 1024) { - info[0] = 128; - info[1] = 63; - info[2] = size / (info[0] * info[1]); - if (info[2] >= 1024) { - info[0] = 255; - info[1] = 63; - info[2] = size / (info[0] * info[1]); - if (info[2] >= 1024) - info[2] = 1023; - } - } - return 0; -} - -/* calculate percentage of total accesses on a ldn */ -static int ldn_access_load(struct Scsi_Host *shpnt, int ldn) -{ - if (IBM_DS(shpnt).total_accesses == 0) - return (0); - if (IBM_DS(shpnt).ldn_access[ldn] == 0) - return (0); - return (IBM_DS(shpnt).ldn_access[ldn] * 100) / IBM_DS(shpnt).total_accesses; -} - -/* calculate total amount of r/w-accesses */ -static int ldn_access_total_read_write(struct Scsi_Host *shpnt) -{ - int a; - int i; - - a = 0; - for (i = 0; i <= MAX_LOG_DEV; i++) - a += IBM_DS(shpnt).ldn_read_access[i] + IBM_DS(shpnt).ldn_write_access[i]; - return (a); -} - -static int ldn_access_total_inquiry(struct Scsi_Host *shpnt) -{ - int a; - int i; - - a = 0; - for (i = 0; i <= MAX_LOG_DEV; i++) - a += IBM_DS(shpnt).ldn_inquiry_access[i]; - return (a); -} - -static int ldn_access_total_modeselect(struct Scsi_Host *shpnt) -{ - int a; - int i; - - a = 0; - for (i = 0; i <= MAX_LOG_DEV; i++) - a += IBM_DS(shpnt).ldn_modeselect_access[i]; - return (a); -} - -/* routine to display info in the proc-fs-structure (a deluxe feature) */ -static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout) -{ - int len = 0; - int i, id, lun; - unsigned long flags; - int max_pun; - - - spin_lock_irqsave(shpnt->host_lock, flags); /* Check it */ - - max_pun = subsystem_maxid(shpnt); - - len += sprintf(buffer + len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", IBMMCA_SCSI_DRIVER_VERSION); - len += sprintf(buffer + len, " SCSI Access-Statistics:\n"); - len += sprintf(buffer + len, " Device Scanning Order....: %s\n", (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard"); -#ifdef CONFIG_SCSI_MULTI_LUN - len += sprintf(buffer + len, " Multiple LUN probing.....: Yes\n"); -#else - len += sprintf(buffer + len, " Multiple LUN probing.....: No\n"); -#endif - len += sprintf(buffer + len, " This Hostnumber..........: %d\n", shpnt->host_no); - len += sprintf(buffer + len, " Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(shpnt))); - len += sprintf(buffer + len, " (Shared) IRQ.............: %d\n", IM_IRQ); - len += sprintf(buffer + len, " Total Interrupts.........: %d\n", IBM_DS(shpnt).total_interrupts); - len += sprintf(buffer + len, " Total SCSI Accesses......: %d\n", IBM_DS(shpnt).total_accesses); - len += sprintf(buffer + len, " Total short SCBs.........: %d\n", IBM_DS(shpnt).scbs); - len += sprintf(buffer + len, " Total long SCBs..........: %d\n", IBM_DS(shpnt).long_scbs); - len += sprintf(buffer + len, " Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(shpnt)); - len += sprintf(buffer + len, " Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(shpnt)); - len += sprintf(buffer + len, " Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(shpnt)); - len += sprintf(buffer + len, " Total SCSI other cmds..: %d\n", IBM_DS(shpnt).total_accesses - ldn_access_total_read_write(shpnt) - - ldn_access_total_modeselect(shpnt) - - ldn_access_total_inquiry(shpnt)); - len += sprintf(buffer + len, " Total SCSI command fails.: %d\n\n", IBM_DS(shpnt).total_errors); - len += sprintf(buffer + len, " Logical-Device-Number (LDN) Access-Statistics:\n"); - len += sprintf(buffer + len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n"); - len += sprintf(buffer + len, " -----|--------------|-----------|-----------|--------------\n"); - for (i = 0; i <= MAX_LOG_DEV; i++) - len += sprintf(buffer + len, " %2X | %3d | %8d | %8d | %8d\n", i, ldn_access_load(shpnt, i), IBM_DS(shpnt).ldn_read_access[i], IBM_DS(shpnt).ldn_write_access[i], IBM_DS(shpnt).ldn_assignments[i]); - len += sprintf(buffer + len, " -----------------------------------------------------------\n\n"); - len += sprintf(buffer + len, " Dynamical-LDN-Assignment-Statistics:\n"); - len += sprintf(buffer + len, " Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(shpnt).total_scsi_devices); - len += sprintf(buffer + len, " Dynamical Assignment necessary...: %s\n", IBM_DS(shpnt).dyn_flag ? "Yes" : "No "); - len += sprintf(buffer + len, " Next LDN to be assigned..........: 0x%x\n", next_ldn(shpnt)); - len += sprintf(buffer + len, " Dynamical assignments done yet...: %d\n", IBM_DS(shpnt).dynamical_assignments); - len += sprintf(buffer + len, "\n Current SCSI-Device-Mapping:\n"); - len += sprintf(buffer + len, " Physical SCSI-Device Map Logical SCSI-Device Map\n"); - len += sprintf(buffer + len, " ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n"); - for (id = 0; id < max_pun; id++) { - len += sprintf(buffer + len, " %2d ", id); - for (lun = 0; lun < 8; lun++) - len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(shpnt)[id][lun])); - len += sprintf(buffer + len, " %2d ", id); - for (lun = 0; lun < 8; lun++) - len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(shpnt)[id][lun])); - len += sprintf(buffer + len, "\n"); - } - - len += sprintf(buffer + len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n"); - len += sprintf(buffer + len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n"); - len += sprintf(buffer + len, " - = nothing found, nothing assigned or unprobed LUN)\n\n"); - - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - spin_unlock_irqrestore(shpnt->host_lock, flags); - return len; -} - -static int option_setup(char *str) -{ - int ints[IM_MAX_HOSTS]; - char *cur = str; - int i = 1; - - while (cur && isdigit(*cur) && i < IM_MAX_HOSTS) { - ints[i++] = simple_strtoul(cur, NULL, 0); - if ((cur = strchr(cur, ',')) != NULL) - cur++; - } - ints[0] = i - 1; - internal_ibmmca_scsi_setup(cur, ints); - return 1; -} - -__setup("ibmmcascsi=", option_setup); - -static struct mca_driver ibmmca_driver = { - .id_table = ibmmca_id_table, - .driver = { - .name = "ibmmca", - .bus = &mca_bus_type, - .probe = ibmmca_probe, - .remove = __devexit_p(ibmmca_remove), - }, -}; - -static int __init ibmmca_init(void) -{ -#ifdef MODULE - /* If the driver is run as module, read from conf.modules or cmd-line */ - if (boot_options) - option_setup(boot_options); -#endif - - return mca_register_driver_integrated(&ibmmca_driver, MCA_INTEGSCSI); -} - -static void __exit ibmmca_exit(void) -{ - mca_unregister_driver(&ibmmca_driver); -} - -module_init(ibmmca_init); -module_exit(ibmmca_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/Makefile b/ANDROID_3.4.5/drivers/scsi/ibmvscsi/Makefile deleted file mode 100644 index ff5b5c55..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsic.o - -ibmvscsic-y += ibmvscsi.o -ibmvscsic-$(CONFIG_PPC_PSERIES) += rpa_vscsi.o - -obj-$(CONFIG_SCSI_IBMVSCSIS) += ibmvstgt.o -obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o diff --git a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.c b/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.c deleted file mode 100644 index 134a0ae8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.c +++ /dev/null @@ -1,4973 +0,0 @@ -/* - * ibmvfc.c -- driver for IBM Power Virtual Fibre Channel Adapter - * - * Written By: Brian King , IBM Corporation - * - * Copyright (C) IBM Corporation, 2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ibmvfc.h" - -static unsigned int init_timeout = IBMVFC_INIT_TIMEOUT; -static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT; -static unsigned int max_lun = IBMVFC_MAX_LUN; -static unsigned int max_targets = IBMVFC_MAX_TARGETS; -static unsigned int max_requests = IBMVFC_MAX_REQUESTS_DEFAULT; -static unsigned int disc_threads = IBMVFC_MAX_DISC_THREADS; -static unsigned int ibmvfc_debug = IBMVFC_DEBUG; -static unsigned int log_level = IBMVFC_DEFAULT_LOG_LEVEL; -static LIST_HEAD(ibmvfc_head); -static DEFINE_SPINLOCK(ibmvfc_driver_lock); -static struct scsi_transport_template *ibmvfc_transport_template; - -MODULE_DESCRIPTION("IBM Virtual Fibre Channel Driver"); -MODULE_AUTHOR("Brian King "); -MODULE_LICENSE("GPL"); -MODULE_VERSION(IBMVFC_DRIVER_VERSION); - -module_param_named(init_timeout, init_timeout, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds. " - "[Default=" __stringify(IBMVFC_INIT_TIMEOUT) "]"); -module_param_named(default_timeout, default_timeout, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(default_timeout, - "Default timeout in seconds for initialization and EH commands. " - "[Default=" __stringify(IBMVFC_DEFAULT_TIMEOUT) "]"); -module_param_named(max_requests, max_requests, uint, S_IRUGO); -MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter. " - "[Default=" __stringify(IBMVFC_MAX_REQUESTS_DEFAULT) "]"); -module_param_named(max_lun, max_lun, uint, S_IRUGO); -MODULE_PARM_DESC(max_lun, "Maximum allowed LUN. " - "[Default=" __stringify(IBMVFC_MAX_LUN) "]"); -module_param_named(max_targets, max_targets, uint, S_IRUGO); -MODULE_PARM_DESC(max_targets, "Maximum allowed targets. " - "[Default=" __stringify(IBMVFC_MAX_TARGETS) "]"); -module_param_named(disc_threads, disc_threads, uint, S_IRUGO); -MODULE_PARM_DESC(disc_threads, "Number of device discovery threads to use. " - "[Default=" __stringify(IBMVFC_MAX_DISC_THREADS) "]"); -module_param_named(debug, ibmvfc_debug, uint, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable driver debug information. " - "[Default=" __stringify(IBMVFC_DEBUG) "]"); -module_param_named(log_level, log_level, uint, 0); -MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver. " - "[Default=" __stringify(IBMVFC_DEFAULT_LOG_LEVEL) "]"); - -static const struct { - u16 status; - u16 error; - u8 result; - u8 retry; - int log; - char *name; -} cmd_status [] = { - { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_ESTABLISH, DID_ERROR, 1, 1, "unable to establish" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_FAULT, DID_OK, 1, 0, "transport fault" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_CMD_TIMEOUT, DID_TIME_OUT, 1, 1, "command timeout" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_ENETDOWN, DID_TRANSPORT_DISRUPTED, 1, 1, "network down" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_HW_FAILURE, DID_ERROR, 1, 1, "hardware failure" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DOWN_ERR, DID_REQUEUE, 0, 0, "link down" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_DEAD_ERR, DID_ERROR, 0, 0, "link dead" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_UNABLE_TO_REGISTER, DID_ERROR, 1, 1, "unable to register" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_BUSY, DID_BUS_BUSY, 1, 0, "transport busy" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_DEAD, DID_ERROR, 0, 1, "transport dead" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_CONFIG_ERROR, DID_ERROR, 1, 1, "configuration error" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_NAME_SERVER_FAIL, DID_ERROR, 1, 1, "name server failure" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_LINK_HALTED, DID_REQUEUE, 1, 0, "link halted" }, - { IBMVFC_FABRIC_MAPPED, IBMVFC_XPORT_GENERAL, DID_OK, 1, 0, "general transport error" }, - - { IBMVFC_VIOS_FAILURE, IBMVFC_CRQ_FAILURE, DID_REQUEUE, 1, 1, "CRQ failure" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_SW_FAILURE, DID_ERROR, 0, 1, "software failure" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_INVALID_PARAMETER, DID_ERROR, 0, 1, "invalid parameter" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_MISSING_PARAMETER, DID_ERROR, 0, 1, "missing parameter" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_HOST_IO_BUS, DID_ERROR, 1, 1, "host I/O bus failure" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED, DID_ERROR, 0, 1, "transaction cancelled" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_TRANS_CANCELLED_IMPLICIT, DID_ERROR, 0, 1, "transaction cancelled implicit" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_INSUFFICIENT_RESOURCE, DID_REQUEUE, 1, 1, "insufficient resources" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_PLOGI_REQUIRED, DID_ERROR, 0, 1, "port login required" }, - { IBMVFC_VIOS_FAILURE, IBMVFC_COMMAND_FAILED, DID_ERROR, 1, 1, "command failed" }, - - { IBMVFC_FC_FAILURE, IBMVFC_INVALID_ELS_CMD_CODE, DID_ERROR, 0, 1, "invalid ELS command code" }, - { IBMVFC_FC_FAILURE, IBMVFC_INVALID_VERSION, DID_ERROR, 0, 1, "invalid version level" }, - { IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_ERROR, DID_ERROR, 1, 1, "logical error" }, - { IBMVFC_FC_FAILURE, IBMVFC_INVALID_CT_IU_SIZE, DID_ERROR, 0, 1, "invalid CT_IU size" }, - { IBMVFC_FC_FAILURE, IBMVFC_LOGICAL_BUSY, DID_REQUEUE, 1, 0, "logical busy" }, - { IBMVFC_FC_FAILURE, IBMVFC_PROTOCOL_ERROR, DID_ERROR, 1, 1, "protocol error" }, - { IBMVFC_FC_FAILURE, IBMVFC_UNABLE_TO_PERFORM_REQ, DID_ERROR, 1, 1, "unable to perform request" }, - { IBMVFC_FC_FAILURE, IBMVFC_CMD_NOT_SUPPORTED, DID_ERROR, 0, 0, "command not supported" }, - { IBMVFC_FC_FAILURE, IBMVFC_SERVER_NOT_AVAIL, DID_ERROR, 0, 1, "server not available" }, - { IBMVFC_FC_FAILURE, IBMVFC_CMD_IN_PROGRESS, DID_ERROR, 0, 1, "command already in progress" }, - { IBMVFC_FC_FAILURE, IBMVFC_VENDOR_SPECIFIC, DID_ERROR, 1, 1, "vendor specific" }, - - { IBMVFC_FC_SCSI_ERROR, 0, DID_OK, 1, 0, "SCSI error" }, -}; - -static void ibmvfc_npiv_login(struct ibmvfc_host *); -static void ibmvfc_tgt_send_prli(struct ibmvfc_target *); -static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *); -static void ibmvfc_tgt_query_target(struct ibmvfc_target *); -static void ibmvfc_npiv_logout(struct ibmvfc_host *); - -static const char *unknown_error = "unknown error"; - -#ifdef CONFIG_SCSI_IBMVFC_TRACE -/** - * ibmvfc_trc_start - Log a start trace entry - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_trc_start(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd; - struct ibmvfc_mad_common *mad = &evt->iu.mad_common; - struct ibmvfc_trace_entry *entry; - - entry = &vhost->trace[vhost->trace_index++]; - entry->evt = evt; - entry->time = jiffies; - entry->fmt = evt->crq.format; - entry->type = IBMVFC_TRC_START; - - switch (entry->fmt) { - case IBMVFC_CMD_FORMAT: - entry->op_code = vfc_cmd->iu.cdb[0]; - entry->scsi_id = vfc_cmd->tgt_scsi_id; - entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); - entry->tmf_flags = vfc_cmd->iu.tmf_flags; - entry->u.start.xfer_len = vfc_cmd->iu.xfer_len; - break; - case IBMVFC_MAD_FORMAT: - entry->op_code = mad->opcode; - break; - default: - break; - }; -} - -/** - * ibmvfc_trc_end - Log an end trace entry - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_trc_end(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; - struct ibmvfc_mad_common *mad = &evt->xfer_iu->mad_common; - struct ibmvfc_trace_entry *entry = &vhost->trace[vhost->trace_index++]; - - entry->evt = evt; - entry->time = jiffies; - entry->fmt = evt->crq.format; - entry->type = IBMVFC_TRC_END; - - switch (entry->fmt) { - case IBMVFC_CMD_FORMAT: - entry->op_code = vfc_cmd->iu.cdb[0]; - entry->scsi_id = vfc_cmd->tgt_scsi_id; - entry->lun = scsilun_to_int(&vfc_cmd->iu.lun); - entry->tmf_flags = vfc_cmd->iu.tmf_flags; - entry->u.end.status = vfc_cmd->status; - entry->u.end.error = vfc_cmd->error; - entry->u.end.fcp_rsp_flags = vfc_cmd->rsp.flags; - entry->u.end.rsp_code = vfc_cmd->rsp.data.info.rsp_code; - entry->u.end.scsi_status = vfc_cmd->rsp.scsi_status; - break; - case IBMVFC_MAD_FORMAT: - entry->op_code = mad->opcode; - entry->u.end.status = mad->status; - break; - default: - break; - - }; -} - -#else -#define ibmvfc_trc_start(evt) do { } while (0) -#define ibmvfc_trc_end(evt) do { } while (0) -#endif - -/** - * ibmvfc_get_err_index - Find the index into cmd_status for the fcp response - * @status: status / error class - * @error: error - * - * Return value: - * index into cmd_status / -EINVAL on failure - **/ -static int ibmvfc_get_err_index(u16 status, u16 error) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(cmd_status); i++) - if ((cmd_status[i].status & status) == cmd_status[i].status && - cmd_status[i].error == error) - return i; - - return -EINVAL; -} - -/** - * ibmvfc_get_cmd_error - Find the error description for the fcp response - * @status: status / error class - * @error: error - * - * Return value: - * error description string - **/ -static const char *ibmvfc_get_cmd_error(u16 status, u16 error) -{ - int rc = ibmvfc_get_err_index(status, error); - if (rc >= 0) - return cmd_status[rc].name; - return unknown_error; -} - -/** - * ibmvfc_get_err_result - Find the scsi status to return for the fcp response - * @vfc_cmd: ibmvfc command struct - * - * Return value: - * SCSI result value to return for completed command - **/ -static int ibmvfc_get_err_result(struct ibmvfc_cmd *vfc_cmd) -{ - int err; - struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; - int fc_rsp_len = rsp->fcp_rsp_len; - - if ((rsp->flags & FCP_RSP_LEN_VALID) && - ((fc_rsp_len && fc_rsp_len != 4 && fc_rsp_len != 8) || - rsp->data.info.rsp_code)) - return DID_ERROR << 16; - - err = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); - if (err >= 0) - return rsp->scsi_status | (cmd_status[err].result << 16); - return rsp->scsi_status | (DID_ERROR << 16); -} - -/** - * ibmvfc_retry_cmd - Determine if error status is retryable - * @status: status / error class - * @error: error - * - * Return value: - * 1 if error should be retried / 0 if it should not - **/ -static int ibmvfc_retry_cmd(u16 status, u16 error) -{ - int rc = ibmvfc_get_err_index(status, error); - - if (rc >= 0) - return cmd_status[rc].retry; - return 1; -} - -static const char *unknown_fc_explain = "unknown fc explain"; - -static const struct { - u16 fc_explain; - char *name; -} ls_explain [] = { - { 0x00, "no additional explanation" }, - { 0x01, "service parameter error - options" }, - { 0x03, "service parameter error - initiator control" }, - { 0x05, "service parameter error - recipient control" }, - { 0x07, "service parameter error - received data field size" }, - { 0x09, "service parameter error - concurrent seq" }, - { 0x0B, "service parameter error - credit" }, - { 0x0D, "invalid N_Port/F_Port_Name" }, - { 0x0E, "invalid node/Fabric Name" }, - { 0x0F, "invalid common service parameters" }, - { 0x11, "invalid association header" }, - { 0x13, "association header required" }, - { 0x15, "invalid originator S_ID" }, - { 0x17, "invalid OX_ID-RX-ID combination" }, - { 0x19, "command (request) already in progress" }, - { 0x1E, "N_Port Login requested" }, - { 0x1F, "Invalid N_Port_ID" }, -}; - -static const struct { - u16 fc_explain; - char *name; -} gs_explain [] = { - { 0x00, "no additional explanation" }, - { 0x01, "port identifier not registered" }, - { 0x02, "port name not registered" }, - { 0x03, "node name not registered" }, - { 0x04, "class of service not registered" }, - { 0x06, "initial process associator not registered" }, - { 0x07, "FC-4 TYPEs not registered" }, - { 0x08, "symbolic port name not registered" }, - { 0x09, "symbolic node name not registered" }, - { 0x0A, "port type not registered" }, - { 0xF0, "authorization exception" }, - { 0xF1, "authentication exception" }, - { 0xF2, "data base full" }, - { 0xF3, "data base empty" }, - { 0xF4, "processing request" }, - { 0xF5, "unable to verify connection" }, - { 0xF6, "devices not in a common zone" }, -}; - -/** - * ibmvfc_get_ls_explain - Return the FC Explain description text - * @status: FC Explain status - * - * Returns: - * error string - **/ -static const char *ibmvfc_get_ls_explain(u16 status) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ls_explain); i++) - if (ls_explain[i].fc_explain == status) - return ls_explain[i].name; - - return unknown_fc_explain; -} - -/** - * ibmvfc_get_gs_explain - Return the FC Explain description text - * @status: FC Explain status - * - * Returns: - * error string - **/ -static const char *ibmvfc_get_gs_explain(u16 status) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(gs_explain); i++) - if (gs_explain[i].fc_explain == status) - return gs_explain[i].name; - - return unknown_fc_explain; -} - -static const struct { - enum ibmvfc_fc_type fc_type; - char *name; -} fc_type [] = { - { IBMVFC_FABRIC_REJECT, "fabric reject" }, - { IBMVFC_PORT_REJECT, "port reject" }, - { IBMVFC_LS_REJECT, "ELS reject" }, - { IBMVFC_FABRIC_BUSY, "fabric busy" }, - { IBMVFC_PORT_BUSY, "port busy" }, - { IBMVFC_BASIC_REJECT, "basic reject" }, -}; - -static const char *unknown_fc_type = "unknown fc type"; - -/** - * ibmvfc_get_fc_type - Return the FC Type description text - * @status: FC Type error status - * - * Returns: - * error string - **/ -static const char *ibmvfc_get_fc_type(u16 status) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(fc_type); i++) - if (fc_type[i].fc_type == status) - return fc_type[i].name; - - return unknown_fc_type; -} - -/** - * ibmvfc_set_tgt_action - Set the next init action for the target - * @tgt: ibmvfc target struct - * @action: action to perform - * - **/ -static void ibmvfc_set_tgt_action(struct ibmvfc_target *tgt, - enum ibmvfc_target_action action) -{ - switch (tgt->action) { - case IBMVFC_TGT_ACTION_DEL_RPORT: - if (action == IBMVFC_TGT_ACTION_DELETED_RPORT) - tgt->action = action; - case IBMVFC_TGT_ACTION_DELETED_RPORT: - break; - default: - if (action == IBMVFC_TGT_ACTION_DEL_RPORT) - tgt->add_rport = 0; - tgt->action = action; - break; - } -} - -/** - * ibmvfc_set_host_state - Set the state for the host - * @vhost: ibmvfc host struct - * @state: state to set host to - * - * Returns: - * 0 if state changed / non-zero if not changed - **/ -static int ibmvfc_set_host_state(struct ibmvfc_host *vhost, - enum ibmvfc_host_state state) -{ - int rc = 0; - - switch (vhost->state) { - case IBMVFC_HOST_OFFLINE: - rc = -EINVAL; - break; - default: - vhost->state = state; - break; - }; - - return rc; -} - -/** - * ibmvfc_set_host_action - Set the next init action for the host - * @vhost: ibmvfc host struct - * @action: action to perform - * - **/ -static void ibmvfc_set_host_action(struct ibmvfc_host *vhost, - enum ibmvfc_host_action action) -{ - switch (action) { - case IBMVFC_HOST_ACTION_ALLOC_TGTS: - if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) - vhost->action = action; - break; - case IBMVFC_HOST_ACTION_LOGO_WAIT: - if (vhost->action == IBMVFC_HOST_ACTION_LOGO) - vhost->action = action; - break; - case IBMVFC_HOST_ACTION_INIT_WAIT: - if (vhost->action == IBMVFC_HOST_ACTION_INIT) - vhost->action = action; - break; - case IBMVFC_HOST_ACTION_QUERY: - switch (vhost->action) { - case IBMVFC_HOST_ACTION_INIT_WAIT: - case IBMVFC_HOST_ACTION_NONE: - case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: - vhost->action = action; - break; - default: - break; - }; - break; - case IBMVFC_HOST_ACTION_TGT_INIT: - if (vhost->action == IBMVFC_HOST_ACTION_ALLOC_TGTS) - vhost->action = action; - break; - case IBMVFC_HOST_ACTION_INIT: - case IBMVFC_HOST_ACTION_TGT_DEL: - switch (vhost->action) { - case IBMVFC_HOST_ACTION_RESET: - case IBMVFC_HOST_ACTION_REENABLE: - break; - default: - vhost->action = action; - break; - }; - break; - case IBMVFC_HOST_ACTION_LOGO: - case IBMVFC_HOST_ACTION_QUERY_TGTS: - case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: - case IBMVFC_HOST_ACTION_NONE: - case IBMVFC_HOST_ACTION_RESET: - case IBMVFC_HOST_ACTION_REENABLE: - default: - vhost->action = action; - break; - }; -} - -/** - * ibmvfc_reinit_host - Re-start host initialization (no NPIV Login) - * @vhost: ibmvfc host struct - * - * Return value: - * nothing - **/ -static void ibmvfc_reinit_host(struct ibmvfc_host *vhost) -{ - if (vhost->action == IBMVFC_HOST_ACTION_NONE) { - if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { - scsi_block_requests(vhost->host); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); - } - } else - vhost->reinit = 1; - - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_link_down - Handle a link down event from the adapter - * @vhost: ibmvfc host struct - * @state: ibmvfc host state to enter - * - **/ -static void ibmvfc_link_down(struct ibmvfc_host *vhost, - enum ibmvfc_host_state state) -{ - struct ibmvfc_target *tgt; - - ENTER; - scsi_block_requests(vhost->host); - list_for_each_entry(tgt, &vhost->targets, queue) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - ibmvfc_set_host_state(vhost, state); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); - vhost->events_to_log |= IBMVFC_AE_LINKDOWN; - wake_up(&vhost->work_wait_q); - LEAVE; -} - -/** - * ibmvfc_init_host - Start host initialization - * @vhost: ibmvfc host struct - * - * Return value: - * nothing - **/ -static void ibmvfc_init_host(struct ibmvfc_host *vhost) -{ - struct ibmvfc_target *tgt; - - if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { - if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { - dev_err(vhost->dev, - "Host initialization retries exceeded. Taking adapter offline\n"); - ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); - return; - } - } - - if (!ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { - memset(vhost->async_crq.msgs, 0, PAGE_SIZE); - vhost->async_crq.cur = 0; - - list_for_each_entry(tgt, &vhost->targets, queue) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - scsi_block_requests(vhost->host); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); - vhost->job_step = ibmvfc_npiv_login; - wake_up(&vhost->work_wait_q); - } -} - -/** - * ibmvfc_send_crq - Send a CRQ - * @vhost: ibmvfc host struct - * @word1: the first 64 bits of the data - * @word2: the second 64 bits of the data - * - * Return value: - * 0 on success / other on failure - **/ -static int ibmvfc_send_crq(struct ibmvfc_host *vhost, u64 word1, u64 word2) -{ - struct vio_dev *vdev = to_vio_dev(vhost->dev); - return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); -} - -/** - * ibmvfc_send_crq_init - Send a CRQ init message - * @vhost: ibmvfc host struct - * - * Return value: - * 0 on success / other on failure - **/ -static int ibmvfc_send_crq_init(struct ibmvfc_host *vhost) -{ - ibmvfc_dbg(vhost, "Sending CRQ init\n"); - return ibmvfc_send_crq(vhost, 0xC001000000000000LL, 0); -} - -/** - * ibmvfc_send_crq_init_complete - Send a CRQ init complete message - * @vhost: ibmvfc host struct - * - * Return value: - * 0 on success / other on failure - **/ -static int ibmvfc_send_crq_init_complete(struct ibmvfc_host *vhost) -{ - ibmvfc_dbg(vhost, "Sending CRQ init complete\n"); - return ibmvfc_send_crq(vhost, 0xC002000000000000LL, 0); -} - -/** - * ibmvfc_release_crq_queue - Deallocates data and unregisters CRQ - * @vhost: ibmvfc host struct - * - * Frees irq, deallocates a page for messages, unmaps dma, and unregisters - * the crq with the hypervisor. - **/ -static void ibmvfc_release_crq_queue(struct ibmvfc_host *vhost) -{ - long rc = 0; - struct vio_dev *vdev = to_vio_dev(vhost->dev); - struct ibmvfc_crq_queue *crq = &vhost->crq; - - ibmvfc_dbg(vhost, "Releasing CRQ\n"); - free_irq(vdev->irq, vhost); - tasklet_kill(&vhost->tasklet); - do { - if (rc) - msleep(100); - rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); - - vhost->state = IBMVFC_NO_CRQ; - vhost->logged_in = 0; - dma_unmap_single(vhost->dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); - free_page((unsigned long)crq->msgs); -} - -/** - * ibmvfc_reenable_crq_queue - reenables the CRQ - * @vhost: ibmvfc host struct - * - * Return value: - * 0 on success / other on failure - **/ -static int ibmvfc_reenable_crq_queue(struct ibmvfc_host *vhost) -{ - int rc = 0; - struct vio_dev *vdev = to_vio_dev(vhost->dev); - - /* Re-enable the CRQ */ - do { - if (rc) - msleep(100); - rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); - } while (rc == H_IN_PROGRESS || rc == H_BUSY || H_IS_LONG_BUSY(rc)); - - if (rc) - dev_err(vhost->dev, "Error enabling adapter (rc=%d)\n", rc); - - return rc; -} - -/** - * ibmvfc_reset_crq - resets a crq after a failure - * @vhost: ibmvfc host struct - * - * Return value: - * 0 on success / other on failure - **/ -static int ibmvfc_reset_crq(struct ibmvfc_host *vhost) -{ - int rc = 0; - unsigned long flags; - struct vio_dev *vdev = to_vio_dev(vhost->dev); - struct ibmvfc_crq_queue *crq = &vhost->crq; - - /* Close the CRQ */ - do { - if (rc) - msleep(100); - rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); - - spin_lock_irqsave(vhost->host->host_lock, flags); - vhost->state = IBMVFC_NO_CRQ; - vhost->logged_in = 0; - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); - - /* Clean out the queue */ - memset(crq->msgs, 0, PAGE_SIZE); - crq->cur = 0; - - /* And re-open it again */ - rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, - crq->msg_token, PAGE_SIZE); - - if (rc == H_CLOSED) - /* Adapter is good, but other end is not ready */ - dev_warn(vhost->dev, "Partner adapter not ready\n"); - else if (rc != 0) - dev_warn(vhost->dev, "Couldn't register crq (rc=%d)\n", rc); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - return rc; -} - -/** - * ibmvfc_valid_event - Determines if event is valid. - * @pool: event_pool that contains the event - * @evt: ibmvfc event to be checked for validity - * - * Return value: - * 1 if event is valid / 0 if event is not valid - **/ -static int ibmvfc_valid_event(struct ibmvfc_event_pool *pool, - struct ibmvfc_event *evt) -{ - int index = evt - pool->events; - if (index < 0 || index >= pool->size) /* outside of bounds */ - return 0; - if (evt != pool->events + index) /* unaligned */ - return 0; - return 1; -} - -/** - * ibmvfc_free_event - Free the specified event - * @evt: ibmvfc_event to be freed - * - **/ -static void ibmvfc_free_event(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_event_pool *pool = &vhost->pool; - - BUG_ON(!ibmvfc_valid_event(pool, evt)); - BUG_ON(atomic_inc_return(&evt->free) != 1); - list_add_tail(&evt->queue, &vhost->free); -} - -/** - * ibmvfc_scsi_eh_done - EH done function for queuecommand commands - * @evt: ibmvfc event struct - * - * This function does not setup any error status, that must be done - * before this function gets called. - **/ -static void ibmvfc_scsi_eh_done(struct ibmvfc_event *evt) -{ - struct scsi_cmnd *cmnd = evt->cmnd; - - if (cmnd) { - scsi_dma_unmap(cmnd); - cmnd->scsi_done(cmnd); - } - - if (evt->eh_comp) - complete(evt->eh_comp); - - ibmvfc_free_event(evt); -} - -/** - * ibmvfc_fail_request - Fail request with specified error code - * @evt: ibmvfc event struct - * @error_code: error code to fail request with - * - * Return value: - * none - **/ -static void ibmvfc_fail_request(struct ibmvfc_event *evt, int error_code) -{ - if (evt->cmnd) { - evt->cmnd->result = (error_code << 16); - evt->done = ibmvfc_scsi_eh_done; - } else - evt->xfer_iu->mad_common.status = IBMVFC_MAD_DRIVER_FAILED; - - list_del(&evt->queue); - del_timer(&evt->timer); - ibmvfc_trc_end(evt); - evt->done(evt); -} - -/** - * ibmvfc_purge_requests - Our virtual adapter just shut down. Purge any sent requests - * @vhost: ibmvfc host struct - * @error_code: error code to fail requests with - * - * Return value: - * none - **/ -static void ibmvfc_purge_requests(struct ibmvfc_host *vhost, int error_code) -{ - struct ibmvfc_event *evt, *pos; - - ibmvfc_dbg(vhost, "Purging all requests\n"); - list_for_each_entry_safe(evt, pos, &vhost->sent, queue) - ibmvfc_fail_request(evt, error_code); -} - -/** - * ibmvfc_hard_reset_host - Reset the connection to the server by breaking the CRQ - * @vhost: struct ibmvfc host to reset - **/ -static void ibmvfc_hard_reset_host(struct ibmvfc_host *vhost) -{ - ibmvfc_purge_requests(vhost, DID_ERROR); - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET); -} - -/** - * __ibmvfc_reset_host - Reset the connection to the server (no locking) - * @vhost: struct ibmvfc host to reset - **/ -static void __ibmvfc_reset_host(struct ibmvfc_host *vhost) -{ - if (vhost->logged_in && vhost->action != IBMVFC_HOST_ACTION_LOGO_WAIT && - !ibmvfc_set_host_state(vhost, IBMVFC_INITIALIZING)) { - scsi_block_requests(vhost->host); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO); - vhost->job_step = ibmvfc_npiv_logout; - wake_up(&vhost->work_wait_q); - } else - ibmvfc_hard_reset_host(vhost); -} - -/** - * ibmvfc_reset_host - Reset the connection to the server - * @vhost: ibmvfc host struct - **/ -static void ibmvfc_reset_host(struct ibmvfc_host *vhost) -{ - unsigned long flags; - - spin_lock_irqsave(vhost->host->host_lock, flags); - __ibmvfc_reset_host(vhost); - spin_unlock_irqrestore(vhost->host->host_lock, flags); -} - -/** - * ibmvfc_retry_host_init - Retry host initialization if allowed - * @vhost: ibmvfc host struct - * - * Returns: 1 if init will be retried / 0 if not - * - **/ -static int ibmvfc_retry_host_init(struct ibmvfc_host *vhost) -{ - int retry = 0; - - if (vhost->action == IBMVFC_HOST_ACTION_INIT_WAIT) { - vhost->delay_init = 1; - if (++vhost->init_retries > IBMVFC_MAX_HOST_INIT_RETRIES) { - dev_err(vhost->dev, - "Host initialization retries exceeded. Taking adapter offline\n"); - ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); - } else if (vhost->init_retries == IBMVFC_MAX_HOST_INIT_RETRIES) - __ibmvfc_reset_host(vhost); - else { - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); - retry = 1; - } - } - - wake_up(&vhost->work_wait_q); - return retry; -} - -/** - * __ibmvfc_get_target - Find the specified scsi_target (no locking) - * @starget: scsi target struct - * - * Return value: - * ibmvfc_target struct / NULL if not found - **/ -static struct ibmvfc_target *__ibmvfc_get_target(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ibmvfc_host *vhost = shost_priv(shost); - struct ibmvfc_target *tgt; - - list_for_each_entry(tgt, &vhost->targets, queue) - if (tgt->target_id == starget->id) { - kref_get(&tgt->kref); - return tgt; - } - return NULL; -} - -/** - * ibmvfc_get_target - Find the specified scsi_target - * @starget: scsi target struct - * - * Return value: - * ibmvfc_target struct / NULL if not found - **/ -static struct ibmvfc_target *ibmvfc_get_target(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ibmvfc_target *tgt; - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - tgt = __ibmvfc_get_target(starget); - spin_unlock_irqrestore(shost->host_lock, flags); - return tgt; -} - -/** - * ibmvfc_get_host_speed - Get host port speed - * @shost: scsi host struct - * - * Return value: - * none - **/ -static void ibmvfc_get_host_speed(struct Scsi_Host *shost) -{ - struct ibmvfc_host *vhost = shost_priv(shost); - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - if (vhost->state == IBMVFC_ACTIVE) { - switch (vhost->login_buf->resp.link_speed / 100) { - case 1: - fc_host_speed(shost) = FC_PORTSPEED_1GBIT; - break; - case 2: - fc_host_speed(shost) = FC_PORTSPEED_2GBIT; - break; - case 4: - fc_host_speed(shost) = FC_PORTSPEED_4GBIT; - break; - case 8: - fc_host_speed(shost) = FC_PORTSPEED_8GBIT; - break; - case 10: - fc_host_speed(shost) = FC_PORTSPEED_10GBIT; - break; - case 16: - fc_host_speed(shost) = FC_PORTSPEED_16GBIT; - break; - default: - ibmvfc_log(vhost, 3, "Unknown port speed: %lld Gbit\n", - vhost->login_buf->resp.link_speed / 100); - fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - break; - } - } else - fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - spin_unlock_irqrestore(shost->host_lock, flags); -} - -/** - * ibmvfc_get_host_port_state - Get host port state - * @shost: scsi host struct - * - * Return value: - * none - **/ -static void ibmvfc_get_host_port_state(struct Scsi_Host *shost) -{ - struct ibmvfc_host *vhost = shost_priv(shost); - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - switch (vhost->state) { - case IBMVFC_INITIALIZING: - case IBMVFC_ACTIVE: - fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; - break; - case IBMVFC_LINK_DOWN: - fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; - break; - case IBMVFC_LINK_DEAD: - case IBMVFC_HOST_OFFLINE: - fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; - break; - case IBMVFC_HALTED: - fc_host_port_state(shost) = FC_PORTSTATE_BLOCKED; - break; - case IBMVFC_NO_CRQ: - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - break; - default: - ibmvfc_log(vhost, 3, "Unknown port state: %d\n", vhost->state); - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - break; - } - spin_unlock_irqrestore(shost->host_lock, flags); -} - -/** - * ibmvfc_set_rport_dev_loss_tmo - Set rport's device loss timeout - * @rport: rport struct - * @timeout: timeout value - * - * Return value: - * none - **/ -static void ibmvfc_set_rport_dev_loss_tmo(struct fc_rport *rport, u32 timeout) -{ - if (timeout) - rport->dev_loss_tmo = timeout; - else - rport->dev_loss_tmo = 1; -} - -/** - * ibmvfc_release_tgt - Free memory allocated for a target - * @kref: kref struct - * - **/ -static void ibmvfc_release_tgt(struct kref *kref) -{ - struct ibmvfc_target *tgt = container_of(kref, struct ibmvfc_target, kref); - kfree(tgt); -} - -/** - * ibmvfc_get_starget_node_name - Get SCSI target's node name - * @starget: scsi target struct - * - * Return value: - * none - **/ -static void ibmvfc_get_starget_node_name(struct scsi_target *starget) -{ - struct ibmvfc_target *tgt = ibmvfc_get_target(starget); - fc_starget_port_name(starget) = tgt ? tgt->ids.node_name : 0; - if (tgt) - kref_put(&tgt->kref, ibmvfc_release_tgt); -} - -/** - * ibmvfc_get_starget_port_name - Get SCSI target's port name - * @starget: scsi target struct - * - * Return value: - * none - **/ -static void ibmvfc_get_starget_port_name(struct scsi_target *starget) -{ - struct ibmvfc_target *tgt = ibmvfc_get_target(starget); - fc_starget_port_name(starget) = tgt ? tgt->ids.port_name : 0; - if (tgt) - kref_put(&tgt->kref, ibmvfc_release_tgt); -} - -/** - * ibmvfc_get_starget_port_id - Get SCSI target's port ID - * @starget: scsi target struct - * - * Return value: - * none - **/ -static void ibmvfc_get_starget_port_id(struct scsi_target *starget) -{ - struct ibmvfc_target *tgt = ibmvfc_get_target(starget); - fc_starget_port_id(starget) = tgt ? tgt->scsi_id : -1; - if (tgt) - kref_put(&tgt->kref, ibmvfc_release_tgt); -} - -/** - * ibmvfc_wait_while_resetting - Wait while the host resets - * @vhost: ibmvfc host struct - * - * Return value: - * 0 on success / other on failure - **/ -static int ibmvfc_wait_while_resetting(struct ibmvfc_host *vhost) -{ - long timeout = wait_event_timeout(vhost->init_wait_q, - ((vhost->state == IBMVFC_ACTIVE || - vhost->state == IBMVFC_HOST_OFFLINE || - vhost->state == IBMVFC_LINK_DEAD) && - vhost->action == IBMVFC_HOST_ACTION_NONE), - (init_timeout * HZ)); - - return timeout ? 0 : -EIO; -} - -/** - * ibmvfc_issue_fc_host_lip - Re-initiate link initialization - * @shost: scsi host struct - * - * Return value: - * 0 on success / other on failure - **/ -static int ibmvfc_issue_fc_host_lip(struct Scsi_Host *shost) -{ - struct ibmvfc_host *vhost = shost_priv(shost); - - dev_err(vhost->dev, "Initiating host LIP. Resetting connection\n"); - ibmvfc_reset_host(vhost); - return ibmvfc_wait_while_resetting(vhost); -} - -/** - * ibmvfc_gather_partition_info - Gather info about the LPAR - * - * Return value: - * none - **/ -static void ibmvfc_gather_partition_info(struct ibmvfc_host *vhost) -{ - struct device_node *rootdn; - const char *name; - const unsigned int *num; - - rootdn = of_find_node_by_path("/"); - if (!rootdn) - return; - - name = of_get_property(rootdn, "ibm,partition-name", NULL); - if (name) - strncpy(vhost->partition_name, name, sizeof(vhost->partition_name)); - num = of_get_property(rootdn, "ibm,partition-no", NULL); - if (num) - vhost->partition_number = *num; - of_node_put(rootdn); -} - -/** - * ibmvfc_set_login_info - Setup info for NPIV login - * @vhost: ibmvfc host struct - * - * Return value: - * none - **/ -static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) -{ - struct ibmvfc_npiv_login *login_info = &vhost->login_info; - struct device_node *of_node = vhost->dev->of_node; - const char *location; - - memset(login_info, 0, sizeof(*login_info)); - - login_info->ostype = IBMVFC_OS_LINUX; - login_info->max_dma_len = IBMVFC_MAX_SECTORS << 9; - login_info->max_payload = sizeof(struct ibmvfc_fcp_cmd_iu); - login_info->max_response = sizeof(struct ibmvfc_fcp_rsp); - login_info->partition_num = vhost->partition_number; - login_info->vfc_frame_version = 1; - login_info->fcp_version = 3; - login_info->flags = IBMVFC_FLUSH_ON_HALT; - if (vhost->client_migrated) - login_info->flags |= IBMVFC_CLIENT_MIGRATED; - - login_info->max_cmds = max_requests + IBMVFC_NUM_INTERNAL_REQ; - login_info->capabilities = IBMVFC_CAN_MIGRATE; - login_info->async.va = vhost->async_crq.msg_token; - login_info->async.len = vhost->async_crq.size * sizeof(*vhost->async_crq.msgs); - strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); - strncpy(login_info->device_name, - dev_name(&vhost->host->shost_gendev), IBMVFC_MAX_NAME); - - location = of_get_property(of_node, "ibm,loc-code", NULL); - location = location ? location : dev_name(vhost->dev); - strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME); -} - -/** - * ibmvfc_init_event_pool - Allocates and initializes the event pool for a host - * @vhost: ibmvfc host who owns the event pool - * - * Returns zero on success. - **/ -static int ibmvfc_init_event_pool(struct ibmvfc_host *vhost) -{ - int i; - struct ibmvfc_event_pool *pool = &vhost->pool; - - ENTER; - pool->size = max_requests + IBMVFC_NUM_INTERNAL_REQ; - pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL); - if (!pool->events) - return -ENOMEM; - - pool->iu_storage = dma_alloc_coherent(vhost->dev, - pool->size * sizeof(*pool->iu_storage), - &pool->iu_token, 0); - - if (!pool->iu_storage) { - kfree(pool->events); - return -ENOMEM; - } - - for (i = 0; i < pool->size; ++i) { - struct ibmvfc_event *evt = &pool->events[i]; - atomic_set(&evt->free, 1); - evt->crq.valid = 0x80; - evt->crq.ioba = pool->iu_token + (sizeof(*evt->xfer_iu) * i); - evt->xfer_iu = pool->iu_storage + i; - evt->vhost = vhost; - evt->ext_list = NULL; - list_add_tail(&evt->queue, &vhost->free); - } - - LEAVE; - return 0; -} - -/** - * ibmvfc_free_event_pool - Frees memory of the event pool of a host - * @vhost: ibmvfc host who owns the event pool - * - **/ -static void ibmvfc_free_event_pool(struct ibmvfc_host *vhost) -{ - int i; - struct ibmvfc_event_pool *pool = &vhost->pool; - - ENTER; - for (i = 0; i < pool->size; ++i) { - list_del(&pool->events[i].queue); - BUG_ON(atomic_read(&pool->events[i].free) != 1); - if (pool->events[i].ext_list) - dma_pool_free(vhost->sg_pool, - pool->events[i].ext_list, - pool->events[i].ext_list_token); - } - - kfree(pool->events); - dma_free_coherent(vhost->dev, - pool->size * sizeof(*pool->iu_storage), - pool->iu_storage, pool->iu_token); - LEAVE; -} - -/** - * ibmvfc_get_event - Gets the next free event in pool - * @vhost: ibmvfc host struct - * - * Returns a free event from the pool. - **/ -static struct ibmvfc_event *ibmvfc_get_event(struct ibmvfc_host *vhost) -{ - struct ibmvfc_event *evt; - - BUG_ON(list_empty(&vhost->free)); - evt = list_entry(vhost->free.next, struct ibmvfc_event, queue); - atomic_set(&evt->free, 0); - list_del(&evt->queue); - return evt; -} - -/** - * ibmvfc_init_event - Initialize fields in an event struct that are always - * required. - * @evt: The event - * @done: Routine to call when the event is responded to - * @format: SRP or MAD format - **/ -static void ibmvfc_init_event(struct ibmvfc_event *evt, - void (*done) (struct ibmvfc_event *), u8 format) -{ - evt->cmnd = NULL; - evt->sync_iu = NULL; - evt->crq.format = format; - evt->done = done; - evt->eh_comp = NULL; -} - -/** - * ibmvfc_map_sg_list - Initialize scatterlist - * @scmd: scsi command struct - * @nseg: number of scatterlist segments - * @md: memory descriptor list to initialize - **/ -static void ibmvfc_map_sg_list(struct scsi_cmnd *scmd, int nseg, - struct srp_direct_buf *md) -{ - int i; - struct scatterlist *sg; - - scsi_for_each_sg(scmd, sg, nseg, i) { - md[i].va = sg_dma_address(sg); - md[i].len = sg_dma_len(sg); - md[i].key = 0; - } -} - -/** - * ibmvfc_map_sg_data - Maps dma for a scatterlist and initializes decriptor fields - * @scmd: Scsi_Cmnd with the scatterlist - * @evt: ibmvfc event struct - * @vfc_cmd: vfc_cmd that contains the memory descriptor - * @dev: device for which to map dma memory - * - * Returns: - * 0 on success / non-zero on failure - **/ -static int ibmvfc_map_sg_data(struct scsi_cmnd *scmd, - struct ibmvfc_event *evt, - struct ibmvfc_cmd *vfc_cmd, struct device *dev) -{ - - int sg_mapped; - struct srp_direct_buf *data = &vfc_cmd->ioba; - struct ibmvfc_host *vhost = dev_get_drvdata(dev); - - sg_mapped = scsi_dma_map(scmd); - if (!sg_mapped) { - vfc_cmd->flags |= IBMVFC_NO_MEM_DESC; - return 0; - } else if (unlikely(sg_mapped < 0)) { - if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) - scmd_printk(KERN_ERR, scmd, "Failed to map DMA buffer for command\n"); - return sg_mapped; - } - - if (scmd->sc_data_direction == DMA_TO_DEVICE) { - vfc_cmd->flags |= IBMVFC_WRITE; - vfc_cmd->iu.add_cdb_len |= IBMVFC_WRDATA; - } else { - vfc_cmd->flags |= IBMVFC_READ; - vfc_cmd->iu.add_cdb_len |= IBMVFC_RDDATA; - } - - if (sg_mapped == 1) { - ibmvfc_map_sg_list(scmd, sg_mapped, data); - return 0; - } - - vfc_cmd->flags |= IBMVFC_SCATTERLIST; - - if (!evt->ext_list) { - evt->ext_list = dma_pool_alloc(vhost->sg_pool, GFP_ATOMIC, - &evt->ext_list_token); - - if (!evt->ext_list) { - scsi_dma_unmap(scmd); - if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) - scmd_printk(KERN_ERR, scmd, "Can't allocate memory for scatterlist\n"); - return -ENOMEM; - } - } - - ibmvfc_map_sg_list(scmd, sg_mapped, evt->ext_list); - - data->va = evt->ext_list_token; - data->len = sg_mapped * sizeof(struct srp_direct_buf); - data->key = 0; - return 0; -} - -/** - * ibmvfc_timeout - Internal command timeout handler - * @evt: struct ibmvfc_event that timed out - * - * Called when an internally generated command times out - **/ -static void ibmvfc_timeout(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - dev_err(vhost->dev, "Command timed out (%p). Resetting connection\n", evt); - ibmvfc_reset_host(vhost); -} - -/** - * ibmvfc_send_event - Transforms event to u64 array and calls send_crq() - * @evt: event to be sent - * @vhost: ibmvfc host struct - * @timeout: timeout in seconds - 0 means do not time command - * - * Returns the value returned from ibmvfc_send_crq(). (Zero for success) - **/ -static int ibmvfc_send_event(struct ibmvfc_event *evt, - struct ibmvfc_host *vhost, unsigned long timeout) -{ - u64 *crq_as_u64 = (u64 *) &evt->crq; - int rc; - - /* Copy the IU into the transfer area */ - *evt->xfer_iu = evt->iu; - if (evt->crq.format == IBMVFC_CMD_FORMAT) - evt->xfer_iu->cmd.tag = (u64)evt; - else if (evt->crq.format == IBMVFC_MAD_FORMAT) - evt->xfer_iu->mad_common.tag = (u64)evt; - else - BUG(); - - list_add_tail(&evt->queue, &vhost->sent); - init_timer(&evt->timer); - - if (timeout) { - evt->timer.data = (unsigned long) evt; - evt->timer.expires = jiffies + (timeout * HZ); - evt->timer.function = (void (*)(unsigned long))ibmvfc_timeout; - add_timer(&evt->timer); - } - - mb(); - - if ((rc = ibmvfc_send_crq(vhost, crq_as_u64[0], crq_as_u64[1]))) { - list_del(&evt->queue); - del_timer(&evt->timer); - - /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. - * Firmware will send a CRQ with a transport event (0xFF) to - * tell this client what has happened to the transport. This - * will be handled in ibmvfc_handle_crq() - */ - if (rc == H_CLOSED) { - if (printk_ratelimit()) - dev_warn(vhost->dev, "Send warning. Receive queue closed, will retry.\n"); - if (evt->cmnd) - scsi_dma_unmap(evt->cmnd); - ibmvfc_free_event(evt); - return SCSI_MLQUEUE_HOST_BUSY; - } - - dev_err(vhost->dev, "Send error (rc=%d)\n", rc); - if (evt->cmnd) { - evt->cmnd->result = DID_ERROR << 16; - evt->done = ibmvfc_scsi_eh_done; - } else - evt->xfer_iu->mad_common.status = IBMVFC_MAD_CRQ_ERROR; - - evt->done(evt); - } else - ibmvfc_trc_start(evt); - - return 0; -} - -/** - * ibmvfc_log_error - Log an error for the failed command if appropriate - * @evt: ibmvfc event to log - * - **/ -static void ibmvfc_log_error(struct ibmvfc_event *evt) -{ - struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; - struct scsi_cmnd *cmnd = evt->cmnd; - const char *err = unknown_error; - int index = ibmvfc_get_err_index(vfc_cmd->status, vfc_cmd->error); - int logerr = 0; - int rsp_code = 0; - - if (index >= 0) { - logerr = cmd_status[index].log; - err = cmd_status[index].name; - } - - if (!logerr && (vhost->log_level <= (IBMVFC_DEFAULT_LOG_LEVEL + 1))) - return; - - if (rsp->flags & FCP_RSP_LEN_VALID) - rsp_code = rsp->data.info.rsp_code; - - scmd_printk(KERN_ERR, cmnd, "Command (%02X) failed: %s (%x:%x) " - "flags: %x fcp_rsp: %x, resid=%d, scsi_status: %x\n", - cmnd->cmnd[0], err, vfc_cmd->status, vfc_cmd->error, - rsp->flags, rsp_code, scsi_get_resid(cmnd), rsp->scsi_status); -} - -/** - * ibmvfc_relogin - Log back into the specified device - * @sdev: scsi device struct - * - **/ -static void ibmvfc_relogin(struct scsi_device *sdev) -{ - struct ibmvfc_host *vhost = shost_priv(sdev->host); - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - struct ibmvfc_target *tgt; - - list_for_each_entry(tgt, &vhost->targets, queue) { - if (rport == tgt->rport) { - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - break; - } - } - - ibmvfc_reinit_host(vhost); -} - -/** - * ibmvfc_scsi_done - Handle responses from commands - * @evt: ibmvfc event to be handled - * - * Used as a callback when sending scsi cmds. - **/ -static void ibmvfc_scsi_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd; - struct ibmvfc_fcp_rsp *rsp = &vfc_cmd->rsp; - struct scsi_cmnd *cmnd = evt->cmnd; - u32 rsp_len = 0; - u32 sense_len = rsp->fcp_sense_len; - - if (cmnd) { - if (vfc_cmd->response_flags & IBMVFC_ADAPTER_RESID_VALID) - scsi_set_resid(cmnd, vfc_cmd->adapter_resid); - else if (rsp->flags & FCP_RESID_UNDER) - scsi_set_resid(cmnd, rsp->fcp_resid); - else - scsi_set_resid(cmnd, 0); - - if (vfc_cmd->status) { - cmnd->result = ibmvfc_get_err_result(vfc_cmd); - - if (rsp->flags & FCP_RSP_LEN_VALID) - rsp_len = rsp->fcp_rsp_len; - if ((sense_len + rsp_len) > SCSI_SENSE_BUFFERSIZE) - sense_len = SCSI_SENSE_BUFFERSIZE - rsp_len; - if ((rsp->flags & FCP_SNS_LEN_VALID) && rsp->fcp_sense_len && rsp_len <= 8) - memcpy(cmnd->sense_buffer, rsp->data.sense + rsp_len, sense_len); - if ((vfc_cmd->status & IBMVFC_VIOS_FAILURE) && (vfc_cmd->error == IBMVFC_PLOGI_REQUIRED)) - ibmvfc_relogin(cmnd->device); - - if (!cmnd->result && (!scsi_get_resid(cmnd) || (rsp->flags & FCP_RESID_OVER))) - cmnd->result = (DID_ERROR << 16); - - ibmvfc_log_error(evt); - } - - if (!cmnd->result && - (scsi_bufflen(cmnd) - scsi_get_resid(cmnd) < cmnd->underflow)) - cmnd->result = (DID_ERROR << 16); - - scsi_dma_unmap(cmnd); - cmnd->scsi_done(cmnd); - } - - if (evt->eh_comp) - complete(evt->eh_comp); - - ibmvfc_free_event(evt); -} - -/** - * ibmvfc_host_chkready - Check if the host can accept commands - * @vhost: struct ibmvfc host - * - * Returns: - * 1 if host can accept command / 0 if not - **/ -static inline int ibmvfc_host_chkready(struct ibmvfc_host *vhost) -{ - int result = 0; - - switch (vhost->state) { - case IBMVFC_LINK_DEAD: - case IBMVFC_HOST_OFFLINE: - result = DID_NO_CONNECT << 16; - break; - case IBMVFC_NO_CRQ: - case IBMVFC_INITIALIZING: - case IBMVFC_HALTED: - case IBMVFC_LINK_DOWN: - result = DID_REQUEUE << 16; - break; - case IBMVFC_ACTIVE: - result = 0; - break; - }; - - return result; -} - -/** - * ibmvfc_queuecommand - The queuecommand function of the scsi template - * @cmnd: struct scsi_cmnd to be executed - * @done: Callback function to be called when cmnd is completed - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_queuecommand_lck(struct scsi_cmnd *cmnd, - void (*done) (struct scsi_cmnd *)) -{ - struct ibmvfc_host *vhost = shost_priv(cmnd->device->host); - struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); - struct ibmvfc_cmd *vfc_cmd; - struct ibmvfc_event *evt; - u8 tag[2]; - int rc; - - if (unlikely((rc = fc_remote_port_chkready(rport))) || - unlikely((rc = ibmvfc_host_chkready(vhost)))) { - cmnd->result = rc; - done(cmnd); - return 0; - } - - cmnd->result = (DID_OK << 16); - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT); - evt->cmnd = cmnd; - cmnd->scsi_done = done; - vfc_cmd = &evt->iu.cmd; - memset(vfc_cmd, 0, sizeof(*vfc_cmd)); - vfc_cmd->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); - vfc_cmd->resp.len = sizeof(vfc_cmd->rsp); - vfc_cmd->frame_type = IBMVFC_SCSI_FCP_TYPE; - vfc_cmd->payload_len = sizeof(vfc_cmd->iu); - vfc_cmd->resp_len = sizeof(vfc_cmd->rsp); - vfc_cmd->cancel_key = (unsigned long)cmnd->device->hostdata; - vfc_cmd->tgt_scsi_id = rport->port_id; - vfc_cmd->iu.xfer_len = scsi_bufflen(cmnd); - int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun); - memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len); - - if (scsi_populate_tag_msg(cmnd, tag)) { - vfc_cmd->task_tag = tag[1]; - switch (tag[0]) { - case MSG_SIMPLE_TAG: - vfc_cmd->iu.pri_task_attr = IBMVFC_SIMPLE_TASK; - break; - case MSG_HEAD_TAG: - vfc_cmd->iu.pri_task_attr = IBMVFC_HEAD_OF_QUEUE; - break; - case MSG_ORDERED_TAG: - vfc_cmd->iu.pri_task_attr = IBMVFC_ORDERED_TASK; - break; - }; - } - - if (likely(!(rc = ibmvfc_map_sg_data(cmnd, evt, vfc_cmd, vhost->dev)))) - return ibmvfc_send_event(evt, vhost, 0); - - ibmvfc_free_event(evt); - if (rc == -ENOMEM) - return SCSI_MLQUEUE_HOST_BUSY; - - if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) - scmd_printk(KERN_ERR, cmnd, - "Failed to map DMA buffer for command. rc=%d\n", rc); - - cmnd->result = DID_ERROR << 16; - done(cmnd); - return 0; -} - -static DEF_SCSI_QCMD(ibmvfc_queuecommand) - -/** - * ibmvfc_sync_completion - Signal that a synchronous command has completed - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_sync_completion(struct ibmvfc_event *evt) -{ - /* copy the response back */ - if (evt->sync_iu) - *evt->sync_iu = *evt->xfer_iu; - - complete(&evt->comp); -} - -/** - * ibmvfc_bsg_timeout_done - Completion handler for cancelling BSG commands - * @evt: struct ibmvfc_event - * - **/ -static void ibmvfc_bsg_timeout_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - - ibmvfc_free_event(evt); - vhost->aborting_passthru = 0; - dev_info(vhost->dev, "Passthru command cancelled\n"); -} - -/** - * ibmvfc_bsg_timeout - Handle a BSG timeout - * @job: struct fc_bsg_job that timed out - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_bsg_timeout(struct fc_bsg_job *job) -{ - struct ibmvfc_host *vhost = shost_priv(job->shost); - unsigned long port_id = (unsigned long)job->dd_data; - struct ibmvfc_event *evt; - struct ibmvfc_tmf *tmf; - unsigned long flags; - int rc; - - ENTER; - spin_lock_irqsave(vhost->host->host_lock, flags); - if (vhost->aborting_passthru || vhost->state != IBMVFC_ACTIVE) { - __ibmvfc_reset_host(vhost); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return 0; - } - - vhost->aborting_passthru = 1; - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_bsg_timeout_done, IBMVFC_MAD_FORMAT); - - tmf = &evt->iu.tmf; - memset(tmf, 0, sizeof(*tmf)); - tmf->common.version = 1; - tmf->common.opcode = IBMVFC_TMF_MAD; - tmf->common.length = sizeof(*tmf); - tmf->scsi_id = port_id; - tmf->cancel_key = IBMVFC_PASSTHRU_CANCEL_KEY; - tmf->my_cancel_key = IBMVFC_INTERNAL_CANCEL_KEY; - rc = ibmvfc_send_event(evt, vhost, default_timeout); - - if (rc != 0) { - vhost->aborting_passthru = 0; - dev_err(vhost->dev, "Failed to send cancel event. rc=%d\n", rc); - rc = -EIO; - } else - dev_info(vhost->dev, "Cancelling passthru command to port id 0x%lx\n", - port_id); - - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - LEAVE; - return rc; -} - -/** - * ibmvfc_bsg_plogi - PLOGI into a target to handle a BSG command - * @vhost: struct ibmvfc_host to send command - * @port_id: port ID to send command - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_bsg_plogi(struct ibmvfc_host *vhost, unsigned int port_id) -{ - struct ibmvfc_port_login *plogi; - struct ibmvfc_target *tgt; - struct ibmvfc_event *evt; - union ibmvfc_iu rsp_iu; - unsigned long flags; - int rc = 0, issue_login = 1; - - ENTER; - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry(tgt, &vhost->targets, queue) { - if (tgt->scsi_id == port_id) { - issue_login = 0; - break; - } - } - - if (!issue_login) - goto unlock_out; - if (unlikely((rc = ibmvfc_host_chkready(vhost)))) - goto unlock_out; - - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); - plogi = &evt->iu.plogi; - memset(plogi, 0, sizeof(*plogi)); - plogi->common.version = 1; - plogi->common.opcode = IBMVFC_PORT_LOGIN; - plogi->common.length = sizeof(*plogi); - plogi->scsi_id = port_id; - evt->sync_iu = &rsp_iu; - init_completion(&evt->comp); - - rc = ibmvfc_send_event(evt, vhost, default_timeout); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - if (rc) - return -EIO; - - wait_for_completion(&evt->comp); - - if (rsp_iu.plogi.common.status) - rc = -EIO; - - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_free_event(evt); -unlock_out: - spin_unlock_irqrestore(vhost->host->host_lock, flags); - LEAVE; - return rc; -} - -/** - * ibmvfc_bsg_request - Handle a BSG request - * @job: struct fc_bsg_job to be executed - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_bsg_request(struct fc_bsg_job *job) -{ - struct ibmvfc_host *vhost = shost_priv(job->shost); - struct fc_rport *rport = job->rport; - struct ibmvfc_passthru_mad *mad; - struct ibmvfc_event *evt; - union ibmvfc_iu rsp_iu; - unsigned long flags, port_id = -1; - unsigned int code = job->request->msgcode; - int rc = 0, req_seg, rsp_seg, issue_login = 0; - u32 fc_flags, rsp_len; - - ENTER; - job->reply->reply_payload_rcv_len = 0; - if (rport) - port_id = rport->port_id; - - switch (code) { - case FC_BSG_HST_ELS_NOLOGIN: - port_id = (job->request->rqst_data.h_els.port_id[0] << 16) | - (job->request->rqst_data.h_els.port_id[1] << 8) | - job->request->rqst_data.h_els.port_id[2]; - case FC_BSG_RPT_ELS: - fc_flags = IBMVFC_FC_ELS; - break; - case FC_BSG_HST_CT: - issue_login = 1; - port_id = (job->request->rqst_data.h_ct.port_id[0] << 16) | - (job->request->rqst_data.h_ct.port_id[1] << 8) | - job->request->rqst_data.h_ct.port_id[2]; - case FC_BSG_RPT_CT: - fc_flags = IBMVFC_FC_CT_IU; - break; - default: - return -ENOTSUPP; - }; - - if (port_id == -1) - return -EINVAL; - if (!mutex_trylock(&vhost->passthru_mutex)) - return -EBUSY; - - job->dd_data = (void *)port_id; - req_seg = dma_map_sg(vhost->dev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - - if (!req_seg) { - mutex_unlock(&vhost->passthru_mutex); - return -ENOMEM; - } - - rsp_seg = dma_map_sg(vhost->dev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - - if (!rsp_seg) { - dma_unmap_sg(vhost->dev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - mutex_unlock(&vhost->passthru_mutex); - return -ENOMEM; - } - - if (req_seg > 1 || rsp_seg > 1) { - rc = -EINVAL; - goto out; - } - - if (issue_login) - rc = ibmvfc_bsg_plogi(vhost, port_id); - - spin_lock_irqsave(vhost->host->host_lock, flags); - - if (unlikely(rc || (rport && (rc = fc_remote_port_chkready(rport)))) || - unlikely((rc = ibmvfc_host_chkready(vhost)))) { - spin_unlock_irqrestore(vhost->host->host_lock, flags); - goto out; - } - - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); - mad = &evt->iu.passthru; - - memset(mad, 0, sizeof(*mad)); - mad->common.version = 1; - mad->common.opcode = IBMVFC_PASSTHRU; - mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu); - - mad->cmd_ioba.va = (u64)evt->crq.ioba + - offsetof(struct ibmvfc_passthru_mad, iu); - mad->cmd_ioba.len = sizeof(mad->iu); - - mad->iu.cmd_len = job->request_payload.payload_len; - mad->iu.rsp_len = job->reply_payload.payload_len; - mad->iu.flags = fc_flags; - mad->iu.cancel_key = IBMVFC_PASSTHRU_CANCEL_KEY; - - mad->iu.cmd.va = sg_dma_address(job->request_payload.sg_list); - mad->iu.cmd.len = sg_dma_len(job->request_payload.sg_list); - mad->iu.rsp.va = sg_dma_address(job->reply_payload.sg_list); - mad->iu.rsp.len = sg_dma_len(job->reply_payload.sg_list); - mad->iu.scsi_id = port_id; - mad->iu.tag = (u64)evt; - rsp_len = mad->iu.rsp.len; - - evt->sync_iu = &rsp_iu; - init_completion(&evt->comp); - rc = ibmvfc_send_event(evt, vhost, 0); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - if (rc) { - rc = -EIO; - goto out; - } - - wait_for_completion(&evt->comp); - - if (rsp_iu.passthru.common.status) - rc = -EIO; - else - job->reply->reply_payload_rcv_len = rsp_len; - - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_free_event(evt); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - job->reply->result = rc; - job->job_done(job); - rc = 0; -out: - dma_unmap_sg(vhost->dev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - dma_unmap_sg(vhost->dev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - mutex_unlock(&vhost->passthru_mutex); - LEAVE; - return rc; -} - -/** - * ibmvfc_reset_device - Reset the device with the specified reset type - * @sdev: scsi device to reset - * @type: reset type - * @desc: reset type description for log messages - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc) -{ - struct ibmvfc_host *vhost = shost_priv(sdev->host); - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - struct ibmvfc_cmd *tmf; - struct ibmvfc_event *evt = NULL; - union ibmvfc_iu rsp_iu; - struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; - int rsp_rc = -EBUSY; - unsigned long flags; - int rsp_code = 0; - - spin_lock_irqsave(vhost->host->host_lock, flags); - if (vhost->state == IBMVFC_ACTIVE) { - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); - - tmf = &evt->iu.cmd; - memset(tmf, 0, sizeof(*tmf)); - tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); - tmf->resp.len = sizeof(tmf->rsp); - tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; - tmf->payload_len = sizeof(tmf->iu); - tmf->resp_len = sizeof(tmf->rsp); - tmf->cancel_key = (unsigned long)sdev->hostdata; - tmf->tgt_scsi_id = rport->port_id; - int_to_scsilun(sdev->lun, &tmf->iu.lun); - tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); - tmf->iu.tmf_flags = type; - evt->sync_iu = &rsp_iu; - - init_completion(&evt->comp); - rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); - } - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - if (rsp_rc != 0) { - sdev_printk(KERN_ERR, sdev, "Failed to send %s reset event. rc=%d\n", - desc, rsp_rc); - return -EIO; - } - - sdev_printk(KERN_INFO, sdev, "Resetting %s\n", desc); - wait_for_completion(&evt->comp); - - if (rsp_iu.cmd.status) - rsp_code = ibmvfc_get_err_result(&rsp_iu.cmd); - - if (rsp_code) { - if (fc_rsp->flags & FCP_RSP_LEN_VALID) - rsp_code = fc_rsp->data.info.rsp_code; - - sdev_printk(KERN_ERR, sdev, "%s reset failed: %s (%x:%x) " - "flags: %x fcp_rsp: %x, scsi_status: %x\n", - desc, ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), - rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, - fc_rsp->scsi_status); - rsp_rc = -EIO; - } else - sdev_printk(KERN_INFO, sdev, "%s reset successful\n", desc); - - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_free_event(evt); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return rsp_rc; -} - -/** - * ibmvfc_match_rport - Match function for specified remote port - * @evt: ibmvfc event struct - * @device: device to match (rport) - * - * Returns: - * 1 if event matches rport / 0 if event does not match rport - **/ -static int ibmvfc_match_rport(struct ibmvfc_event *evt, void *rport) -{ - struct fc_rport *cmd_rport; - - if (evt->cmnd) { - cmd_rport = starget_to_rport(scsi_target(evt->cmnd->device)); - if (cmd_rport == rport) - return 1; - } - return 0; -} - -/** - * ibmvfc_match_target - Match function for specified target - * @evt: ibmvfc event struct - * @device: device to match (starget) - * - * Returns: - * 1 if event matches starget / 0 if event does not match starget - **/ -static int ibmvfc_match_target(struct ibmvfc_event *evt, void *device) -{ - if (evt->cmnd && scsi_target(evt->cmnd->device) == device) - return 1; - return 0; -} - -/** - * ibmvfc_match_lun - Match function for specified LUN - * @evt: ibmvfc event struct - * @device: device to match (sdev) - * - * Returns: - * 1 if event matches sdev / 0 if event does not match sdev - **/ -static int ibmvfc_match_lun(struct ibmvfc_event *evt, void *device) -{ - if (evt->cmnd && evt->cmnd->device == device) - return 1; - return 0; -} - -/** - * ibmvfc_wait_for_ops - Wait for ops to complete - * @vhost: ibmvfc host struct - * @device: device to match (starget or sdev) - * @match: match function - * - * Returns: - * SUCCESS / FAILED - **/ -static int ibmvfc_wait_for_ops(struct ibmvfc_host *vhost, void *device, - int (*match) (struct ibmvfc_event *, void *)) -{ - struct ibmvfc_event *evt; - DECLARE_COMPLETION_ONSTACK(comp); - int wait; - unsigned long flags; - signed long timeout = IBMVFC_ABORT_WAIT_TIMEOUT * HZ; - - ENTER; - do { - wait = 0; - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry(evt, &vhost->sent, queue) { - if (match(evt, device)) { - evt->eh_comp = ∁ - wait++; - } - } - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - if (wait) { - timeout = wait_for_completion_timeout(&comp, timeout); - - if (!timeout) { - wait = 0; - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry(evt, &vhost->sent, queue) { - if (match(evt, device)) { - evt->eh_comp = NULL; - wait++; - } - } - spin_unlock_irqrestore(vhost->host->host_lock, flags); - if (wait) - dev_err(vhost->dev, "Timed out waiting for aborted commands\n"); - LEAVE; - return wait ? FAILED : SUCCESS; - } - } - } while (wait); - - LEAVE; - return SUCCESS; -} - -/** - * ibmvfc_cancel_all - Cancel all outstanding commands to the device - * @sdev: scsi device to cancel commands - * @type: type of error recovery being performed - * - * This sends a cancel to the VIOS for the specified device. This does - * NOT send any abort to the actual device. That must be done separately. - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_cancel_all(struct scsi_device *sdev, int type) -{ - struct ibmvfc_host *vhost = shost_priv(sdev->host); - struct scsi_target *starget = scsi_target(sdev); - struct fc_rport *rport = starget_to_rport(starget); - struct ibmvfc_tmf *tmf; - struct ibmvfc_event *evt, *found_evt; - union ibmvfc_iu rsp; - int rsp_rc = -EBUSY; - unsigned long flags; - u16 status; - - ENTER; - spin_lock_irqsave(vhost->host->host_lock, flags); - found_evt = NULL; - list_for_each_entry(evt, &vhost->sent, queue) { - if (evt->cmnd && evt->cmnd->device == sdev) { - found_evt = evt; - break; - } - } - - if (!found_evt) { - if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) - sdev_printk(KERN_INFO, sdev, "No events found to cancel\n"); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return 0; - } - - if (vhost->state == IBMVFC_ACTIVE) { - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT); - - tmf = &evt->iu.tmf; - memset(tmf, 0, sizeof(*tmf)); - tmf->common.version = 1; - tmf->common.opcode = IBMVFC_TMF_MAD; - tmf->common.length = sizeof(*tmf); - tmf->scsi_id = rport->port_id; - int_to_scsilun(sdev->lun, &tmf->lun); - tmf->flags = (type | IBMVFC_TMF_LUA_VALID); - tmf->cancel_key = (unsigned long)sdev->hostdata; - tmf->my_cancel_key = (unsigned long)starget->hostdata; - - evt->sync_iu = &rsp; - init_completion(&evt->comp); - rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); - } - - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - if (rsp_rc != 0) { - sdev_printk(KERN_ERR, sdev, "Failed to send cancel event. rc=%d\n", rsp_rc); - return -EIO; - } - - sdev_printk(KERN_INFO, sdev, "Cancelling outstanding commands.\n"); - - wait_for_completion(&evt->comp); - status = rsp.mad_common.status; - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_free_event(evt); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - if (status != IBMVFC_MAD_SUCCESS) { - sdev_printk(KERN_WARNING, sdev, "Cancel failed with rc=%x\n", status); - return -EIO; - } - - sdev_printk(KERN_INFO, sdev, "Successfully cancelled outstanding commands\n"); - return 0; -} - -/** - * ibmvfc_match_key - Match function for specified cancel key - * @evt: ibmvfc event struct - * @key: cancel key to match - * - * Returns: - * 1 if event matches key / 0 if event does not match key - **/ -static int ibmvfc_match_key(struct ibmvfc_event *evt, void *key) -{ - unsigned long cancel_key = (unsigned long)key; - - if (evt->crq.format == IBMVFC_CMD_FORMAT && - evt->iu.cmd.cancel_key == cancel_key) - return 1; - return 0; -} - -/** - * ibmvfc_abort_task_set - Abort outstanding commands to the device - * @sdev: scsi device to abort commands - * - * This sends an Abort Task Set to the VIOS for the specified device. This does - * NOT send any cancel to the VIOS. That must be done separately. - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_abort_task_set(struct scsi_device *sdev) -{ - struct ibmvfc_host *vhost = shost_priv(sdev->host); - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - struct ibmvfc_cmd *tmf; - struct ibmvfc_event *evt, *found_evt; - union ibmvfc_iu rsp_iu; - struct ibmvfc_fcp_rsp *fc_rsp = &rsp_iu.cmd.rsp; - int rc, rsp_rc = -EBUSY; - unsigned long flags, timeout = IBMVFC_ABORT_TIMEOUT; - int rsp_code = 0; - - spin_lock_irqsave(vhost->host->host_lock, flags); - found_evt = NULL; - list_for_each_entry(evt, &vhost->sent, queue) { - if (evt->cmnd && evt->cmnd->device == sdev) { - found_evt = evt; - break; - } - } - - if (!found_evt) { - if (vhost->log_level > IBMVFC_DEFAULT_LOG_LEVEL) - sdev_printk(KERN_INFO, sdev, "No events found to abort\n"); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return 0; - } - - if (vhost->state == IBMVFC_ACTIVE) { - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT); - - tmf = &evt->iu.cmd; - memset(tmf, 0, sizeof(*tmf)); - tmf->resp.va = (u64)evt->crq.ioba + offsetof(struct ibmvfc_cmd, rsp); - tmf->resp.len = sizeof(tmf->rsp); - tmf->frame_type = IBMVFC_SCSI_FCP_TYPE; - tmf->payload_len = sizeof(tmf->iu); - tmf->resp_len = sizeof(tmf->rsp); - tmf->cancel_key = (unsigned long)sdev->hostdata; - tmf->tgt_scsi_id = rport->port_id; - int_to_scsilun(sdev->lun, &tmf->iu.lun); - tmf->flags = (IBMVFC_NO_MEM_DESC | IBMVFC_TMF); - tmf->iu.tmf_flags = IBMVFC_ABORT_TASK_SET; - evt->sync_iu = &rsp_iu; - - init_completion(&evt->comp); - rsp_rc = ibmvfc_send_event(evt, vhost, default_timeout); - } - - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - if (rsp_rc != 0) { - sdev_printk(KERN_ERR, sdev, "Failed to send abort. rc=%d\n", rsp_rc); - return -EIO; - } - - sdev_printk(KERN_INFO, sdev, "Aborting outstanding commands\n"); - timeout = wait_for_completion_timeout(&evt->comp, timeout); - - if (!timeout) { - rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); - if (!rc) { - rc = ibmvfc_wait_for_ops(vhost, sdev->hostdata, ibmvfc_match_key); - if (rc == SUCCESS) - rc = 0; - } - - if (rc) { - sdev_printk(KERN_INFO, sdev, "Cancel failed, resetting host\n"); - ibmvfc_reset_host(vhost); - rsp_rc = 0; - goto out; - } - } - - if (rsp_iu.cmd.status) - rsp_code = ibmvfc_get_err_result(&rsp_iu.cmd); - - if (rsp_code) { - if (fc_rsp->flags & FCP_RSP_LEN_VALID) - rsp_code = fc_rsp->data.info.rsp_code; - - sdev_printk(KERN_ERR, sdev, "Abort failed: %s (%x:%x) " - "flags: %x fcp_rsp: %x, scsi_status: %x\n", - ibmvfc_get_cmd_error(rsp_iu.cmd.status, rsp_iu.cmd.error), - rsp_iu.cmd.status, rsp_iu.cmd.error, fc_rsp->flags, rsp_code, - fc_rsp->scsi_status); - rsp_rc = -EIO; - } else - sdev_printk(KERN_INFO, sdev, "Abort successful\n"); - -out: - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_free_event(evt); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return rsp_rc; -} - -/** - * ibmvfc_eh_abort_handler - Abort a command - * @cmd: scsi command to abort - * - * Returns: - * SUCCESS / FAILED - **/ -static int ibmvfc_eh_abort_handler(struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct ibmvfc_host *vhost = shost_priv(sdev->host); - int cancel_rc, abort_rc; - int rc = FAILED; - - ENTER; - fc_block_scsi_eh(cmd); - ibmvfc_wait_while_resetting(vhost); - cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); - abort_rc = ibmvfc_abort_task_set(sdev); - - if (!cancel_rc && !abort_rc) - rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); - - LEAVE; - return rc; -} - -/** - * ibmvfc_eh_device_reset_handler - Reset a single LUN - * @cmd: scsi command struct - * - * Returns: - * SUCCESS / FAILED - **/ -static int ibmvfc_eh_device_reset_handler(struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct ibmvfc_host *vhost = shost_priv(sdev->host); - int cancel_rc, reset_rc; - int rc = FAILED; - - ENTER; - fc_block_scsi_eh(cmd); - ibmvfc_wait_while_resetting(vhost); - cancel_rc = ibmvfc_cancel_all(sdev, IBMVFC_TMF_LUN_RESET); - reset_rc = ibmvfc_reset_device(sdev, IBMVFC_LUN_RESET, "LUN"); - - if (!cancel_rc && !reset_rc) - rc = ibmvfc_wait_for_ops(vhost, sdev, ibmvfc_match_lun); - - LEAVE; - return rc; -} - -/** - * ibmvfc_dev_cancel_all_reset - Device iterated cancel all function - * @sdev: scsi device struct - * @data: return code - * - **/ -static void ibmvfc_dev_cancel_all_reset(struct scsi_device *sdev, void *data) -{ - unsigned long *rc = data; - *rc |= ibmvfc_cancel_all(sdev, IBMVFC_TMF_TGT_RESET); -} - -/** - * ibmvfc_eh_target_reset_handler - Reset the target - * @cmd: scsi command struct - * - * Returns: - * SUCCESS / FAILED - **/ -static int ibmvfc_eh_target_reset_handler(struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct ibmvfc_host *vhost = shost_priv(sdev->host); - struct scsi_target *starget = scsi_target(sdev); - int reset_rc; - int rc = FAILED; - unsigned long cancel_rc = 0; - - ENTER; - fc_block_scsi_eh(cmd); - ibmvfc_wait_while_resetting(vhost); - starget_for_each_device(starget, &cancel_rc, ibmvfc_dev_cancel_all_reset); - reset_rc = ibmvfc_reset_device(sdev, IBMVFC_TARGET_RESET, "target"); - - if (!cancel_rc && !reset_rc) - rc = ibmvfc_wait_for_ops(vhost, starget, ibmvfc_match_target); - - LEAVE; - return rc; -} - -/** - * ibmvfc_eh_host_reset_handler - Reset the connection to the server - * @cmd: struct scsi_cmnd having problems - * - **/ -static int ibmvfc_eh_host_reset_handler(struct scsi_cmnd *cmd) -{ - int rc; - struct ibmvfc_host *vhost = shost_priv(cmd->device->host); - - fc_block_scsi_eh(cmd); - dev_err(vhost->dev, "Resetting connection due to error recovery\n"); - rc = ibmvfc_issue_fc_host_lip(vhost->host); - return rc ? FAILED : SUCCESS; -} - -/** - * ibmvfc_terminate_rport_io - Terminate all pending I/O to the rport. - * @rport: rport struct - * - * Return value: - * none - **/ -static void ibmvfc_terminate_rport_io(struct fc_rport *rport) -{ - struct Scsi_Host *shost = rport_to_shost(rport); - struct ibmvfc_host *vhost = shost_priv(shost); - struct fc_rport *dev_rport; - struct scsi_device *sdev; - unsigned long rc; - - ENTER; - shost_for_each_device(sdev, shost) { - dev_rport = starget_to_rport(scsi_target(sdev)); - if (dev_rport != rport) - continue; - ibmvfc_cancel_all(sdev, IBMVFC_TMF_ABORT_TASK_SET); - ibmvfc_abort_task_set(sdev); - } - - rc = ibmvfc_wait_for_ops(vhost, rport, ibmvfc_match_rport); - - if (rc == FAILED) - ibmvfc_issue_fc_host_lip(shost); - LEAVE; -} - -static const struct ibmvfc_async_desc ae_desc [] = { - { "PLOGI", IBMVFC_AE_ELS_PLOGI, IBMVFC_DEFAULT_LOG_LEVEL + 1 }, - { "LOGO", IBMVFC_AE_ELS_LOGO, IBMVFC_DEFAULT_LOG_LEVEL + 1 }, - { "PRLO", IBMVFC_AE_ELS_PRLO, IBMVFC_DEFAULT_LOG_LEVEL + 1 }, - { "N-Port SCN", IBMVFC_AE_SCN_NPORT, IBMVFC_DEFAULT_LOG_LEVEL + 1 }, - { "Group SCN", IBMVFC_AE_SCN_GROUP, IBMVFC_DEFAULT_LOG_LEVEL + 1 }, - { "Domain SCN", IBMVFC_AE_SCN_DOMAIN, IBMVFC_DEFAULT_LOG_LEVEL }, - { "Fabric SCN", IBMVFC_AE_SCN_FABRIC, IBMVFC_DEFAULT_LOG_LEVEL }, - { "Link Up", IBMVFC_AE_LINK_UP, IBMVFC_DEFAULT_LOG_LEVEL }, - { "Link Down", IBMVFC_AE_LINK_DOWN, IBMVFC_DEFAULT_LOG_LEVEL }, - { "Link Dead", IBMVFC_AE_LINK_DEAD, IBMVFC_DEFAULT_LOG_LEVEL }, - { "Halt", IBMVFC_AE_HALT, IBMVFC_DEFAULT_LOG_LEVEL }, - { "Resume", IBMVFC_AE_RESUME, IBMVFC_DEFAULT_LOG_LEVEL }, - { "Adapter Failed", IBMVFC_AE_ADAPTER_FAILED, IBMVFC_DEFAULT_LOG_LEVEL }, -}; - -static const struct ibmvfc_async_desc unknown_ae = { - "Unknown async", 0, IBMVFC_DEFAULT_LOG_LEVEL -}; - -/** - * ibmvfc_get_ae_desc - Get text description for async event - * @ae: async event - * - **/ -static const struct ibmvfc_async_desc *ibmvfc_get_ae_desc(u64 ae) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ae_desc); i++) - if (ae_desc[i].ae == ae) - return &ae_desc[i]; - - return &unknown_ae; -} - -static const struct { - enum ibmvfc_ae_link_state state; - const char *desc; -} link_desc [] = { - { IBMVFC_AE_LS_LINK_UP, " link up" }, - { IBMVFC_AE_LS_LINK_BOUNCED, " link bounced" }, - { IBMVFC_AE_LS_LINK_DOWN, " link down" }, - { IBMVFC_AE_LS_LINK_DEAD, " link dead" }, -}; - -/** - * ibmvfc_get_link_state - Get text description for link state - * @state: link state - * - **/ -static const char *ibmvfc_get_link_state(enum ibmvfc_ae_link_state state) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(link_desc); i++) - if (link_desc[i].state == state) - return link_desc[i].desc; - - return ""; -} - -/** - * ibmvfc_handle_async - Handle an async event from the adapter - * @crq: crq to process - * @vhost: ibmvfc host struct - * - **/ -static void ibmvfc_handle_async(struct ibmvfc_async_crq *crq, - struct ibmvfc_host *vhost) -{ - const struct ibmvfc_async_desc *desc = ibmvfc_get_ae_desc(crq->event); - struct ibmvfc_target *tgt; - - ibmvfc_log(vhost, desc->log_level, "%s event received. scsi_id: %llx, wwpn: %llx," - " node_name: %llx%s\n", desc->desc, crq->scsi_id, crq->wwpn, crq->node_name, - ibmvfc_get_link_state(crq->link_state)); - - switch (crq->event) { - case IBMVFC_AE_RESUME: - switch (crq->link_state) { - case IBMVFC_AE_LS_LINK_DOWN: - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); - break; - case IBMVFC_AE_LS_LINK_DEAD: - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - break; - case IBMVFC_AE_LS_LINK_UP: - case IBMVFC_AE_LS_LINK_BOUNCED: - default: - vhost->events_to_log |= IBMVFC_AE_LINKUP; - vhost->delay_init = 1; - __ibmvfc_reset_host(vhost); - break; - }; - - break; - case IBMVFC_AE_LINK_UP: - vhost->events_to_log |= IBMVFC_AE_LINKUP; - vhost->delay_init = 1; - __ibmvfc_reset_host(vhost); - break; - case IBMVFC_AE_SCN_FABRIC: - case IBMVFC_AE_SCN_DOMAIN: - vhost->events_to_log |= IBMVFC_AE_RSCN; - vhost->delay_init = 1; - __ibmvfc_reset_host(vhost); - break; - case IBMVFC_AE_SCN_NPORT: - case IBMVFC_AE_SCN_GROUP: - vhost->events_to_log |= IBMVFC_AE_RSCN; - ibmvfc_reinit_host(vhost); - break; - case IBMVFC_AE_ELS_LOGO: - case IBMVFC_AE_ELS_PRLO: - case IBMVFC_AE_ELS_PLOGI: - list_for_each_entry(tgt, &vhost->targets, queue) { - if (!crq->scsi_id && !crq->wwpn && !crq->node_name) - break; - if (crq->scsi_id && tgt->scsi_id != crq->scsi_id) - continue; - if (crq->wwpn && tgt->ids.port_name != crq->wwpn) - continue; - if (crq->node_name && tgt->ids.node_name != crq->node_name) - continue; - if (tgt->need_login && crq->event == IBMVFC_AE_ELS_LOGO) - tgt->logo_rcvd = 1; - if (!tgt->need_login || crq->event == IBMVFC_AE_ELS_PLOGI) { - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - ibmvfc_reinit_host(vhost); - } - } - break; - case IBMVFC_AE_LINK_DOWN: - case IBMVFC_AE_ADAPTER_FAILED: - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); - break; - case IBMVFC_AE_LINK_DEAD: - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - break; - case IBMVFC_AE_HALT: - ibmvfc_link_down(vhost, IBMVFC_HALTED); - break; - default: - dev_err(vhost->dev, "Unknown async event received: %lld\n", crq->event); - break; - }; -} - -/** - * ibmvfc_handle_crq - Handles and frees received events in the CRQ - * @crq: Command/Response queue - * @vhost: ibmvfc host struct - * - **/ -static void ibmvfc_handle_crq(struct ibmvfc_crq *crq, struct ibmvfc_host *vhost) -{ - long rc; - struct ibmvfc_event *evt = (struct ibmvfc_event *)crq->ioba; - - switch (crq->valid) { - case IBMVFC_CRQ_INIT_RSP: - switch (crq->format) { - case IBMVFC_CRQ_INIT: - dev_info(vhost->dev, "Partner initialized\n"); - /* Send back a response */ - rc = ibmvfc_send_crq_init_complete(vhost); - if (rc == 0) - ibmvfc_init_host(vhost); - else - dev_err(vhost->dev, "Unable to send init rsp. rc=%ld\n", rc); - break; - case IBMVFC_CRQ_INIT_COMPLETE: - dev_info(vhost->dev, "Partner initialization complete\n"); - ibmvfc_init_host(vhost); - break; - default: - dev_err(vhost->dev, "Unknown crq message type: %d\n", crq->format); - } - return; - case IBMVFC_CRQ_XPORT_EVENT: - vhost->state = IBMVFC_NO_CRQ; - vhost->logged_in = 0; - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); - if (crq->format == IBMVFC_PARTITION_MIGRATED) { - /* We need to re-setup the interpartition connection */ - dev_info(vhost->dev, "Re-enabling adapter\n"); - vhost->client_migrated = 1; - ibmvfc_purge_requests(vhost, DID_REQUEUE); - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_REENABLE); - } else { - dev_err(vhost->dev, "Virtual adapter failed (rc=%d)\n", crq->format); - ibmvfc_purge_requests(vhost, DID_ERROR); - ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_RESET); - } - return; - case IBMVFC_CRQ_CMD_RSP: - break; - default: - dev_err(vhost->dev, "Got an invalid message type 0x%02x\n", crq->valid); - return; - } - - if (crq->format == IBMVFC_ASYNC_EVENT) - return; - - /* The only kind of payload CRQs we should get are responses to - * things we send. Make sure this response is to something we - * actually sent - */ - if (unlikely(!ibmvfc_valid_event(&vhost->pool, evt))) { - dev_err(vhost->dev, "Returned correlation_token 0x%08llx is invalid!\n", - crq->ioba); - return; - } - - if (unlikely(atomic_read(&evt->free))) { - dev_err(vhost->dev, "Received duplicate correlation_token 0x%08llx!\n", - crq->ioba); - return; - } - - del_timer(&evt->timer); - list_del(&evt->queue); - ibmvfc_trc_end(evt); - evt->done(evt); -} - -/** - * ibmvfc_scan_finished - Check if the device scan is done. - * @shost: scsi host struct - * @time: current elapsed time - * - * Returns: - * 0 if scan is not done / 1 if scan is done - **/ -static int ibmvfc_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - unsigned long flags; - struct ibmvfc_host *vhost = shost_priv(shost); - int done = 0; - - spin_lock_irqsave(shost->host_lock, flags); - if (time >= (init_timeout * HZ)) { - dev_info(vhost->dev, "Scan taking longer than %d seconds, " - "continuing initialization\n", init_timeout); - done = 1; - } - - if (vhost->scan_complete) - done = 1; - spin_unlock_irqrestore(shost->host_lock, flags); - return done; -} - -/** - * ibmvfc_slave_alloc - Setup the device's task set value - * @sdev: struct scsi_device device to configure - * - * Set the device's task set value so that error handling works as - * expected. - * - * Returns: - * 0 on success / -ENXIO if device does not exist - **/ -static int ibmvfc_slave_alloc(struct scsi_device *sdev) -{ - struct Scsi_Host *shost = sdev->host; - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - struct ibmvfc_host *vhost = shost_priv(shost); - unsigned long flags = 0; - - if (!rport || fc_remote_port_chkready(rport)) - return -ENXIO; - - spin_lock_irqsave(shost->host_lock, flags); - sdev->hostdata = (void *)(unsigned long)vhost->task_set++; - spin_unlock_irqrestore(shost->host_lock, flags); - return 0; -} - -/** - * ibmvfc_target_alloc - Setup the target's task set value - * @starget: struct scsi_target - * - * Set the target's task set value so that error handling works as - * expected. - * - * Returns: - * 0 on success / -ENXIO if device does not exist - **/ -static int ibmvfc_target_alloc(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ibmvfc_host *vhost = shost_priv(shost); - unsigned long flags = 0; - - spin_lock_irqsave(shost->host_lock, flags); - starget->hostdata = (void *)(unsigned long)vhost->task_set++; - spin_unlock_irqrestore(shost->host_lock, flags); - return 0; -} - -/** - * ibmvfc_slave_configure - Configure the device - * @sdev: struct scsi_device device to configure - * - * Enable allow_restart for a device if it is a disk. Adjust the - * queue_depth here also. - * - * Returns: - * 0 - **/ -static int ibmvfc_slave_configure(struct scsi_device *sdev) -{ - struct Scsi_Host *shost = sdev->host; - unsigned long flags = 0; - - spin_lock_irqsave(shost->host_lock, flags); - if (sdev->type == TYPE_DISK) - sdev->allow_restart = 1; - - if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); - scsi_activate_tcq(sdev, sdev->queue_depth); - } else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - spin_unlock_irqrestore(shost->host_lock, flags); - return 0; -} - -/** - * ibmvfc_change_queue_depth - Change the device's queue depth - * @sdev: scsi device struct - * @qdepth: depth to set - * @reason: calling context - * - * Return value: - * actual depth set - **/ -static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (qdepth > IBMVFC_MAX_CMDS_PER_LUN) - qdepth = IBMVFC_MAX_CMDS_PER_LUN; - - scsi_adjust_queue_depth(sdev, 0, qdepth); - return sdev->queue_depth; -} - -/** - * ibmvfc_change_queue_type - Change the device's queue type - * @sdev: scsi device struct - * @tag_type: type of tags to use - * - * Return value: - * actual queue type set - **/ -static int ibmvfc_change_queue_type(struct scsi_device *sdev, int tag_type) -{ - if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, tag_type); - - if (tag_type) - scsi_activate_tcq(sdev, sdev->queue_depth); - else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - } else - tag_type = 0; - - return tag_type; -} - -static ssize_t ibmvfc_show_host_partition_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%s\n", - vhost->login_buf->resp.partition_name); -} - -static ssize_t ibmvfc_show_host_device_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%s\n", - vhost->login_buf->resp.device_name); -} - -static ssize_t ibmvfc_show_host_loc_code(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%s\n", - vhost->login_buf->resp.port_loc_code); -} - -static ssize_t ibmvfc_show_host_drc_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%s\n", - vhost->login_buf->resp.drc_name); -} - -static ssize_t ibmvfc_show_host_npiv_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%d\n", vhost->login_buf->resp.version); -} - -static ssize_t ibmvfc_show_host_capabilities(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - return snprintf(buf, PAGE_SIZE, "%llx\n", vhost->login_buf->resp.capabilities); -} - -/** - * ibmvfc_show_log_level - Show the adapter's error logging level - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ibmvfc_show_log_level(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - unsigned long flags = 0; - int len; - - spin_lock_irqsave(shost->host_lock, flags); - len = snprintf(buf, PAGE_SIZE, "%d\n", vhost->log_level); - spin_unlock_irqrestore(shost->host_lock, flags); - return len; -} - -/** - * ibmvfc_store_log_level - Change the adapter's error logging level - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ibmvfc_store_log_level(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - unsigned long flags = 0; - - spin_lock_irqsave(shost->host_lock, flags); - vhost->log_level = simple_strtoul(buf, NULL, 10); - spin_unlock_irqrestore(shost->host_lock, flags); - return strlen(buf); -} - -static DEVICE_ATTR(partition_name, S_IRUGO, ibmvfc_show_host_partition_name, NULL); -static DEVICE_ATTR(device_name, S_IRUGO, ibmvfc_show_host_device_name, NULL); -static DEVICE_ATTR(port_loc_code, S_IRUGO, ibmvfc_show_host_loc_code, NULL); -static DEVICE_ATTR(drc_name, S_IRUGO, ibmvfc_show_host_drc_name, NULL); -static DEVICE_ATTR(npiv_version, S_IRUGO, ibmvfc_show_host_npiv_version, NULL); -static DEVICE_ATTR(capabilities, S_IRUGO, ibmvfc_show_host_capabilities, NULL); -static DEVICE_ATTR(log_level, S_IRUGO | S_IWUSR, - ibmvfc_show_log_level, ibmvfc_store_log_level); - -#ifdef CONFIG_SCSI_IBMVFC_TRACE -/** - * ibmvfc_read_trace - Dump the adapter trace - * @filp: open sysfs file - * @kobj: kobject struct - * @bin_attr: bin_attribute struct - * @buf: buffer - * @off: offset - * @count: buffer size - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ibmvfc_read_trace(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvfc_host *vhost = shost_priv(shost); - unsigned long flags = 0; - int size = IBMVFC_TRACE_SIZE; - char *src = (char *)vhost->trace; - - if (off > size) - return 0; - if (off + count > size) { - size -= off; - count = size; - } - - spin_lock_irqsave(shost->host_lock, flags); - memcpy(buf, &src[off], count); - spin_unlock_irqrestore(shost->host_lock, flags); - return count; -} - -static struct bin_attribute ibmvfc_trace_attr = { - .attr = { - .name = "trace", - .mode = S_IRUGO, - }, - .size = 0, - .read = ibmvfc_read_trace, -}; -#endif - -static struct device_attribute *ibmvfc_attrs[] = { - &dev_attr_partition_name, - &dev_attr_device_name, - &dev_attr_port_loc_code, - &dev_attr_drc_name, - &dev_attr_npiv_version, - &dev_attr_capabilities, - &dev_attr_log_level, - NULL -}; - -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = "IBM POWER Virtual FC Adapter", - .proc_name = IBMVFC_NAME, - .queuecommand = ibmvfc_queuecommand, - .eh_abort_handler = ibmvfc_eh_abort_handler, - .eh_device_reset_handler = ibmvfc_eh_device_reset_handler, - .eh_target_reset_handler = ibmvfc_eh_target_reset_handler, - .eh_host_reset_handler = ibmvfc_eh_host_reset_handler, - .slave_alloc = ibmvfc_slave_alloc, - .slave_configure = ibmvfc_slave_configure, - .target_alloc = ibmvfc_target_alloc, - .scan_finished = ibmvfc_scan_finished, - .change_queue_depth = ibmvfc_change_queue_depth, - .change_queue_type = ibmvfc_change_queue_type, - .cmd_per_lun = 16, - .can_queue = IBMVFC_MAX_REQUESTS_DEFAULT, - .this_id = -1, - .sg_tablesize = SG_ALL, - .max_sectors = IBMVFC_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = ibmvfc_attrs, -}; - -/** - * ibmvfc_next_async_crq - Returns the next entry in async queue - * @vhost: ibmvfc host struct - * - * Returns: - * Pointer to next entry in queue / NULL if empty - **/ -static struct ibmvfc_async_crq *ibmvfc_next_async_crq(struct ibmvfc_host *vhost) -{ - struct ibmvfc_async_crq_queue *async_crq = &vhost->async_crq; - struct ibmvfc_async_crq *crq; - - crq = &async_crq->msgs[async_crq->cur]; - if (crq->valid & 0x80) { - if (++async_crq->cur == async_crq->size) - async_crq->cur = 0; - rmb(); - } else - crq = NULL; - - return crq; -} - -/** - * ibmvfc_next_crq - Returns the next entry in message queue - * @vhost: ibmvfc host struct - * - * Returns: - * Pointer to next entry in queue / NULL if empty - **/ -static struct ibmvfc_crq *ibmvfc_next_crq(struct ibmvfc_host *vhost) -{ - struct ibmvfc_crq_queue *queue = &vhost->crq; - struct ibmvfc_crq *crq; - - crq = &queue->msgs[queue->cur]; - if (crq->valid & 0x80) { - if (++queue->cur == queue->size) - queue->cur = 0; - rmb(); - } else - crq = NULL; - - return crq; -} - -/** - * ibmvfc_interrupt - Interrupt handler - * @irq: number of irq to handle, not used - * @dev_instance: ibmvfc_host that received interrupt - * - * Returns: - * IRQ_HANDLED - **/ -static irqreturn_t ibmvfc_interrupt(int irq, void *dev_instance) -{ - struct ibmvfc_host *vhost = (struct ibmvfc_host *)dev_instance; - unsigned long flags; - - spin_lock_irqsave(vhost->host->host_lock, flags); - vio_disable_interrupts(to_vio_dev(vhost->dev)); - tasklet_schedule(&vhost->tasklet); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return IRQ_HANDLED; -} - -/** - * ibmvfc_tasklet - Interrupt handler tasklet - * @data: ibmvfc host struct - * - * Returns: - * Nothing - **/ -static void ibmvfc_tasklet(void *data) -{ - struct ibmvfc_host *vhost = data; - struct vio_dev *vdev = to_vio_dev(vhost->dev); - struct ibmvfc_crq *crq; - struct ibmvfc_async_crq *async; - unsigned long flags; - int done = 0; - - spin_lock_irqsave(vhost->host->host_lock, flags); - while (!done) { - /* Pull all the valid messages off the async CRQ */ - while ((async = ibmvfc_next_async_crq(vhost)) != NULL) { - ibmvfc_handle_async(async, vhost); - async->valid = 0; - wmb(); - } - - /* Pull all the valid messages off the CRQ */ - while ((crq = ibmvfc_next_crq(vhost)) != NULL) { - ibmvfc_handle_crq(crq, vhost); - crq->valid = 0; - wmb(); - } - - vio_enable_interrupts(vdev); - if ((async = ibmvfc_next_async_crq(vhost)) != NULL) { - vio_disable_interrupts(vdev); - ibmvfc_handle_async(async, vhost); - async->valid = 0; - wmb(); - } else if ((crq = ibmvfc_next_crq(vhost)) != NULL) { - vio_disable_interrupts(vdev); - ibmvfc_handle_crq(crq, vhost); - crq->valid = 0; - wmb(); - } else - done = 1; - } - - spin_unlock_irqrestore(vhost->host->host_lock, flags); -} - -/** - * ibmvfc_init_tgt - Set the next init job step for the target - * @tgt: ibmvfc target struct - * @job_step: job step to perform - * - **/ -static void ibmvfc_init_tgt(struct ibmvfc_target *tgt, - void (*job_step) (struct ibmvfc_target *)) -{ - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT); - tgt->job_step = job_step; - wake_up(&tgt->vhost->work_wait_q); -} - -/** - * ibmvfc_retry_tgt_init - Attempt to retry a step in target initialization - * @tgt: ibmvfc target struct - * @job_step: initialization job step - * - * Returns: 1 if step will be retried / 0 if not - * - **/ -static int ibmvfc_retry_tgt_init(struct ibmvfc_target *tgt, - void (*job_step) (struct ibmvfc_target *)) -{ - if (++tgt->init_retries > IBMVFC_MAX_TGT_INIT_RETRIES) { - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - wake_up(&tgt->vhost->work_wait_q); - return 0; - } else - ibmvfc_init_tgt(tgt, job_step); - return 1; -} - -/* Defined in FC-LS */ -static const struct { - int code; - int retry; - int logged_in; -} prli_rsp [] = { - { 0, 1, 0 }, - { 1, 0, 1 }, - { 2, 1, 0 }, - { 3, 1, 0 }, - { 4, 0, 0 }, - { 5, 0, 0 }, - { 6, 0, 1 }, - { 7, 0, 0 }, - { 8, 1, 0 }, -}; - -/** - * ibmvfc_get_prli_rsp - Find PRLI response index - * @flags: PRLI response flags - * - **/ -static int ibmvfc_get_prli_rsp(u16 flags) -{ - int i; - int code = (flags & 0x0f00) >> 8; - - for (i = 0; i < ARRAY_SIZE(prli_rsp); i++) - if (prli_rsp[i].code == code) - return i; - - return 0; -} - -/** - * ibmvfc_tgt_prli_done - Completion handler for Process Login - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_tgt_prli_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_target *tgt = evt->tgt; - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_process_login *rsp = &evt->xfer_iu->prli; - struct ibmvfc_prli_svc_parms *parms = &rsp->parms; - u32 status = rsp->common.status; - int index, level = IBMVFC_DEFAULT_LOG_LEVEL; - - vhost->discovery_threads--; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - switch (status) { - case IBMVFC_MAD_SUCCESS: - tgt_dbg(tgt, "Process Login succeeded: %X %02X %04X\n", - parms->type, parms->flags, parms->service_parms); - - if (parms->type == IBMVFC_SCSI_FCP_TYPE) { - index = ibmvfc_get_prli_rsp(parms->flags); - if (prli_rsp[index].logged_in) { - if (parms->flags & IBMVFC_PRLI_EST_IMG_PAIR) { - tgt->need_login = 0; - tgt->ids.roles = 0; - if (parms->service_parms & IBMVFC_PRLI_TARGET_FUNC) - tgt->ids.roles |= FC_PORT_ROLE_FCP_TARGET; - if (parms->service_parms & IBMVFC_PRLI_INITIATOR_FUNC) - tgt->ids.roles |= FC_PORT_ROLE_FCP_INITIATOR; - tgt->add_rport = 1; - } else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - } else if (prli_rsp[index].retry) - ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); - else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - } else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - break; - case IBMVFC_MAD_DRIVER_FAILED: - break; - case IBMVFC_MAD_CRQ_ERROR: - ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); - break; - case IBMVFC_MAD_FAILED: - default: - if ((rsp->status & IBMVFC_VIOS_FAILURE) && rsp->error == IBMVFC_PLOGI_REQUIRED) - level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); - else if (tgt->logo_rcvd) - level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); - else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) - level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_prli); - else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - - tgt_log(tgt, level, "Process Login failed: %s (%x:%x) rc=0x%02X\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), - rsp->status, rsp->error, status); - break; - }; - - kref_put(&tgt->kref, ibmvfc_release_tgt); - ibmvfc_free_event(evt); - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_tgt_send_prli - Send a process login - * @tgt: ibmvfc target struct - * - **/ -static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt) -{ - struct ibmvfc_process_login *prli; - struct ibmvfc_host *vhost = tgt->vhost; - struct ibmvfc_event *evt; - - if (vhost->discovery_threads >= disc_threads) - return; - - kref_get(&tgt->kref); - evt = ibmvfc_get_event(vhost); - vhost->discovery_threads++; - ibmvfc_init_event(evt, ibmvfc_tgt_prli_done, IBMVFC_MAD_FORMAT); - evt->tgt = tgt; - prli = &evt->iu.prli; - memset(prli, 0, sizeof(*prli)); - prli->common.version = 1; - prli->common.opcode = IBMVFC_PROCESS_LOGIN; - prli->common.length = sizeof(*prli); - prli->scsi_id = tgt->scsi_id; - - prli->parms.type = IBMVFC_SCSI_FCP_TYPE; - prli->parms.flags = IBMVFC_PRLI_EST_IMG_PAIR; - prli->parms.service_parms = IBMVFC_PRLI_INITIATOR_FUNC; - - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); - if (ibmvfc_send_event(evt, vhost, default_timeout)) { - vhost->discovery_threads--; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - kref_put(&tgt->kref, ibmvfc_release_tgt); - } else - tgt_dbg(tgt, "Sent process login\n"); -} - -/** - * ibmvfc_tgt_plogi_done - Completion handler for Port Login - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_tgt_plogi_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_target *tgt = evt->tgt; - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_port_login *rsp = &evt->xfer_iu->plogi; - u32 status = rsp->common.status; - int level = IBMVFC_DEFAULT_LOG_LEVEL; - - vhost->discovery_threads--; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - switch (status) { - case IBMVFC_MAD_SUCCESS: - tgt_dbg(tgt, "Port Login succeeded\n"); - if (tgt->ids.port_name && - tgt->ids.port_name != wwn_to_u64(rsp->service_parms.port_name)) { - vhost->reinit = 1; - tgt_dbg(tgt, "Port re-init required\n"); - break; - } - tgt->ids.node_name = wwn_to_u64(rsp->service_parms.node_name); - tgt->ids.port_name = wwn_to_u64(rsp->service_parms.port_name); - tgt->ids.port_id = tgt->scsi_id; - memcpy(&tgt->service_parms, &rsp->service_parms, - sizeof(tgt->service_parms)); - memcpy(&tgt->service_parms_change, &rsp->service_parms_change, - sizeof(tgt->service_parms_change)); - ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_prli); - break; - case IBMVFC_MAD_DRIVER_FAILED: - break; - case IBMVFC_MAD_CRQ_ERROR: - ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); - break; - case IBMVFC_MAD_FAILED: - default: - if (ibmvfc_retry_cmd(rsp->status, rsp->error)) - level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_send_plogi); - else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - - tgt_log(tgt, level, "Port Login failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, - ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, - ibmvfc_get_ls_explain(rsp->fc_explain), rsp->fc_explain, status); - break; - }; - - kref_put(&tgt->kref, ibmvfc_release_tgt); - ibmvfc_free_event(evt); - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_tgt_send_plogi - Send PLOGI to the specified target - * @tgt: ibmvfc target struct - * - **/ -static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt) -{ - struct ibmvfc_port_login *plogi; - struct ibmvfc_host *vhost = tgt->vhost; - struct ibmvfc_event *evt; - - if (vhost->discovery_threads >= disc_threads) - return; - - kref_get(&tgt->kref); - tgt->logo_rcvd = 0; - evt = ibmvfc_get_event(vhost); - vhost->discovery_threads++; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); - ibmvfc_init_event(evt, ibmvfc_tgt_plogi_done, IBMVFC_MAD_FORMAT); - evt->tgt = tgt; - plogi = &evt->iu.plogi; - memset(plogi, 0, sizeof(*plogi)); - plogi->common.version = 1; - plogi->common.opcode = IBMVFC_PORT_LOGIN; - plogi->common.length = sizeof(*plogi); - plogi->scsi_id = tgt->scsi_id; - - if (ibmvfc_send_event(evt, vhost, default_timeout)) { - vhost->discovery_threads--; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - kref_put(&tgt->kref, ibmvfc_release_tgt); - } else - tgt_dbg(tgt, "Sent port login\n"); -} - -/** - * ibmvfc_tgt_implicit_logout_done - Completion handler for Implicit Logout MAD - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_tgt_implicit_logout_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_target *tgt = evt->tgt; - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_implicit_logout *rsp = &evt->xfer_iu->implicit_logout; - u32 status = rsp->common.status; - - vhost->discovery_threads--; - ibmvfc_free_event(evt); - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - - switch (status) { - case IBMVFC_MAD_SUCCESS: - tgt_dbg(tgt, "Implicit Logout succeeded\n"); - break; - case IBMVFC_MAD_DRIVER_FAILED: - kref_put(&tgt->kref, ibmvfc_release_tgt); - wake_up(&vhost->work_wait_q); - return; - case IBMVFC_MAD_FAILED: - default: - tgt_err(tgt, "Implicit Logout failed: rc=0x%02X\n", status); - break; - }; - - if (vhost->action == IBMVFC_HOST_ACTION_TGT_INIT) - ibmvfc_init_tgt(tgt, ibmvfc_tgt_send_plogi); - else if (vhost->action == IBMVFC_HOST_ACTION_QUERY_TGTS && - tgt->scsi_id != tgt->new_scsi_id) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - kref_put(&tgt->kref, ibmvfc_release_tgt); - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_tgt_implicit_logout - Initiate an Implicit Logout for specified target - * @tgt: ibmvfc target struct - * - **/ -static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt) -{ - struct ibmvfc_implicit_logout *mad; - struct ibmvfc_host *vhost = tgt->vhost; - struct ibmvfc_event *evt; - - if (vhost->discovery_threads >= disc_threads) - return; - - kref_get(&tgt->kref); - evt = ibmvfc_get_event(vhost); - vhost->discovery_threads++; - ibmvfc_init_event(evt, ibmvfc_tgt_implicit_logout_done, IBMVFC_MAD_FORMAT); - evt->tgt = tgt; - mad = &evt->iu.implicit_logout; - memset(mad, 0, sizeof(*mad)); - mad->common.version = 1; - mad->common.opcode = IBMVFC_IMPLICIT_LOGOUT; - mad->common.length = sizeof(*mad); - mad->old_scsi_id = tgt->scsi_id; - - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); - if (ibmvfc_send_event(evt, vhost, default_timeout)) { - vhost->discovery_threads--; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - kref_put(&tgt->kref, ibmvfc_release_tgt); - } else - tgt_dbg(tgt, "Sent Implicit Logout\n"); -} - -/** - * ibmvfc_adisc_needs_plogi - Does device need PLOGI? - * @mad: ibmvfc passthru mad struct - * @tgt: ibmvfc target struct - * - * Returns: - * 1 if PLOGI needed / 0 if PLOGI not needed - **/ -static int ibmvfc_adisc_needs_plogi(struct ibmvfc_passthru_mad *mad, - struct ibmvfc_target *tgt) -{ - if (memcmp(&mad->fc_iu.response[2], &tgt->ids.port_name, - sizeof(tgt->ids.port_name))) - return 1; - if (memcmp(&mad->fc_iu.response[4], &tgt->ids.node_name, - sizeof(tgt->ids.node_name))) - return 1; - if (mad->fc_iu.response[6] != tgt->scsi_id) - return 1; - return 0; -} - -/** - * ibmvfc_tgt_adisc_done - Completion handler for ADISC - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_tgt_adisc_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_target *tgt = evt->tgt; - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru; - u32 status = mad->common.status; - u8 fc_reason, fc_explain; - - vhost->discovery_threads--; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - del_timer(&tgt->timer); - - switch (status) { - case IBMVFC_MAD_SUCCESS: - tgt_dbg(tgt, "ADISC succeeded\n"); - if (ibmvfc_adisc_needs_plogi(mad, tgt)) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - break; - case IBMVFC_MAD_DRIVER_FAILED: - break; - case IBMVFC_MAD_FAILED: - default: - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - fc_reason = (mad->fc_iu.response[1] & 0x00ff0000) >> 16; - fc_explain = (mad->fc_iu.response[1] & 0x0000ff00) >> 8; - tgt_info(tgt, "ADISC failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", - ibmvfc_get_cmd_error(mad->iu.status, mad->iu.error), - mad->iu.status, mad->iu.error, - ibmvfc_get_fc_type(fc_reason), fc_reason, - ibmvfc_get_ls_explain(fc_explain), fc_explain, status); - break; - }; - - kref_put(&tgt->kref, ibmvfc_release_tgt); - ibmvfc_free_event(evt); - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_init_passthru - Initialize an event struct for FC passthru - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_init_passthru(struct ibmvfc_event *evt) -{ - struct ibmvfc_passthru_mad *mad = &evt->iu.passthru; - - memset(mad, 0, sizeof(*mad)); - mad->common.version = 1; - mad->common.opcode = IBMVFC_PASSTHRU; - mad->common.length = sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu); - mad->cmd_ioba.va = (u64)evt->crq.ioba + - offsetof(struct ibmvfc_passthru_mad, iu); - mad->cmd_ioba.len = sizeof(mad->iu); - mad->iu.cmd_len = sizeof(mad->fc_iu.payload); - mad->iu.rsp_len = sizeof(mad->fc_iu.response); - mad->iu.cmd.va = (u64)evt->crq.ioba + - offsetof(struct ibmvfc_passthru_mad, fc_iu) + - offsetof(struct ibmvfc_passthru_fc_iu, payload); - mad->iu.cmd.len = sizeof(mad->fc_iu.payload); - mad->iu.rsp.va = (u64)evt->crq.ioba + - offsetof(struct ibmvfc_passthru_mad, fc_iu) + - offsetof(struct ibmvfc_passthru_fc_iu, response); - mad->iu.rsp.len = sizeof(mad->fc_iu.response); -} - -/** - * ibmvfc_tgt_adisc_cancel_done - Completion handler when cancelling an ADISC - * @evt: ibmvfc event struct - * - * Just cleanup this event struct. Everything else is handled by - * the ADISC completion handler. If the ADISC never actually comes - * back, we still have the timer running on the ADISC event struct - * which will fire and cause the CRQ to get reset. - * - **/ -static void ibmvfc_tgt_adisc_cancel_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_target *tgt = evt->tgt; - - tgt_dbg(tgt, "ADISC cancel complete\n"); - vhost->abort_threads--; - ibmvfc_free_event(evt); - kref_put(&tgt->kref, ibmvfc_release_tgt); - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_adisc_timeout - Handle an ADISC timeout - * @tgt: ibmvfc target struct - * - * If an ADISC times out, send a cancel. If the cancel times - * out, reset the CRQ. When the ADISC comes back as cancelled, - * log back into the target. - **/ -static void ibmvfc_adisc_timeout(struct ibmvfc_target *tgt) -{ - struct ibmvfc_host *vhost = tgt->vhost; - struct ibmvfc_event *evt; - struct ibmvfc_tmf *tmf; - unsigned long flags; - int rc; - - tgt_dbg(tgt, "ADISC timeout\n"); - spin_lock_irqsave(vhost->host->host_lock, flags); - if (vhost->abort_threads >= disc_threads || - tgt->action != IBMVFC_TGT_ACTION_INIT_WAIT || - vhost->state != IBMVFC_INITIALIZING || - vhost->action != IBMVFC_HOST_ACTION_QUERY_TGTS) { - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return; - } - - vhost->abort_threads++; - kref_get(&tgt->kref); - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_tgt_adisc_cancel_done, IBMVFC_MAD_FORMAT); - - evt->tgt = tgt; - tmf = &evt->iu.tmf; - memset(tmf, 0, sizeof(*tmf)); - tmf->common.version = 1; - tmf->common.opcode = IBMVFC_TMF_MAD; - tmf->common.length = sizeof(*tmf); - tmf->scsi_id = tgt->scsi_id; - tmf->cancel_key = tgt->cancel_key; - - rc = ibmvfc_send_event(evt, vhost, default_timeout); - - if (rc) { - tgt_err(tgt, "Failed to send cancel event for ADISC. rc=%d\n", rc); - vhost->abort_threads--; - kref_put(&tgt->kref, ibmvfc_release_tgt); - __ibmvfc_reset_host(vhost); - } else - tgt_dbg(tgt, "Attempting to cancel ADISC\n"); - spin_unlock_irqrestore(vhost->host->host_lock, flags); -} - -/** - * ibmvfc_tgt_adisc - Initiate an ADISC for specified target - * @tgt: ibmvfc target struct - * - * When sending an ADISC we end up with two timers running. The - * first timer is the timer in the ibmvfc target struct. If this - * fires, we send a cancel to the target. The second timer is the - * timer on the ibmvfc event for the ADISC, which is longer. If that - * fires, it means the ADISC timed out and our attempt to cancel it - * also failed, so we need to reset the CRQ. - **/ -static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt) -{ - struct ibmvfc_passthru_mad *mad; - struct ibmvfc_host *vhost = tgt->vhost; - struct ibmvfc_event *evt; - - if (vhost->discovery_threads >= disc_threads) - return; - - kref_get(&tgt->kref); - evt = ibmvfc_get_event(vhost); - vhost->discovery_threads++; - ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT); - evt->tgt = tgt; - - ibmvfc_init_passthru(evt); - mad = &evt->iu.passthru; - mad->iu.flags = IBMVFC_FC_ELS; - mad->iu.scsi_id = tgt->scsi_id; - mad->iu.cancel_key = tgt->cancel_key; - - mad->fc_iu.payload[0] = IBMVFC_ADISC; - memcpy(&mad->fc_iu.payload[2], &vhost->login_buf->resp.port_name, - sizeof(vhost->login_buf->resp.port_name)); - memcpy(&mad->fc_iu.payload[4], &vhost->login_buf->resp.node_name, - sizeof(vhost->login_buf->resp.node_name)); - mad->fc_iu.payload[6] = vhost->login_buf->resp.scsi_id & 0x00ffffff; - - if (timer_pending(&tgt->timer)) - mod_timer(&tgt->timer, jiffies + (IBMVFC_ADISC_TIMEOUT * HZ)); - else { - tgt->timer.data = (unsigned long) tgt; - tgt->timer.expires = jiffies + (IBMVFC_ADISC_TIMEOUT * HZ); - tgt->timer.function = (void (*)(unsigned long))ibmvfc_adisc_timeout; - add_timer(&tgt->timer); - } - - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); - if (ibmvfc_send_event(evt, vhost, IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT)) { - vhost->discovery_threads--; - del_timer(&tgt->timer); - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - kref_put(&tgt->kref, ibmvfc_release_tgt); - } else - tgt_dbg(tgt, "Sent ADISC\n"); -} - -/** - * ibmvfc_tgt_query_target_done - Completion handler for Query Target MAD - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_tgt_query_target_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_target *tgt = evt->tgt; - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_query_tgt *rsp = &evt->xfer_iu->query_tgt; - u32 status = rsp->common.status; - int level = IBMVFC_DEFAULT_LOG_LEVEL; - - vhost->discovery_threads--; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - switch (status) { - case IBMVFC_MAD_SUCCESS: - tgt_dbg(tgt, "Query Target succeeded\n"); - tgt->new_scsi_id = rsp->scsi_id; - if (rsp->scsi_id != tgt->scsi_id) - ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); - else - ibmvfc_init_tgt(tgt, ibmvfc_tgt_adisc); - break; - case IBMVFC_MAD_DRIVER_FAILED: - break; - case IBMVFC_MAD_CRQ_ERROR: - ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); - break; - case IBMVFC_MAD_FAILED: - default: - if ((rsp->status & IBMVFC_FABRIC_MAPPED) == IBMVFC_FABRIC_MAPPED && - rsp->error == IBMVFC_UNABLE_TO_PERFORM_REQ && - rsp->fc_explain == IBMVFC_PORT_NAME_NOT_REG) - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - else if (ibmvfc_retry_cmd(rsp->status, rsp->error)) - level += ibmvfc_retry_tgt_init(tgt, ibmvfc_tgt_query_target); - else - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT); - - tgt_log(tgt, level, "Query Target failed: %s (%x:%x) %s (%x) %s (%x) rc=0x%02X\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error, - ibmvfc_get_fc_type(rsp->fc_type), rsp->fc_type, - ibmvfc_get_gs_explain(rsp->fc_explain), rsp->fc_explain, status); - break; - }; - - kref_put(&tgt->kref, ibmvfc_release_tgt); - ibmvfc_free_event(evt); - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_tgt_query_target - Initiate a Query Target for specified target - * @tgt: ibmvfc target struct - * - **/ -static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt) -{ - struct ibmvfc_query_tgt *query_tgt; - struct ibmvfc_host *vhost = tgt->vhost; - struct ibmvfc_event *evt; - - if (vhost->discovery_threads >= disc_threads) - return; - - kref_get(&tgt->kref); - evt = ibmvfc_get_event(vhost); - vhost->discovery_threads++; - evt->tgt = tgt; - ibmvfc_init_event(evt, ibmvfc_tgt_query_target_done, IBMVFC_MAD_FORMAT); - query_tgt = &evt->iu.query_tgt; - memset(query_tgt, 0, sizeof(*query_tgt)); - query_tgt->common.version = 1; - query_tgt->common.opcode = IBMVFC_QUERY_TARGET; - query_tgt->common.length = sizeof(*query_tgt); - query_tgt->wwpn = tgt->ids.port_name; - - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT); - if (ibmvfc_send_event(evt, vhost, default_timeout)) { - vhost->discovery_threads--; - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE); - kref_put(&tgt->kref, ibmvfc_release_tgt); - } else - tgt_dbg(tgt, "Sent Query Target\n"); -} - -/** - * ibmvfc_alloc_target - Allocate and initialize an ibmvfc target - * @vhost: ibmvfc host struct - * @scsi_id: SCSI ID to allocate target for - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id) -{ - struct ibmvfc_target *tgt; - unsigned long flags; - - spin_lock_irqsave(vhost->host->host_lock, flags); - list_for_each_entry(tgt, &vhost->targets, queue) { - if (tgt->scsi_id == scsi_id) { - if (tgt->need_login) - ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); - goto unlock_out; - } - } - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - tgt = mempool_alloc(vhost->tgt_pool, GFP_NOIO); - if (!tgt) { - dev_err(vhost->dev, "Target allocation failure for scsi id %08llx\n", - scsi_id); - return -ENOMEM; - } - - memset(tgt, 0, sizeof(*tgt)); - tgt->scsi_id = scsi_id; - tgt->new_scsi_id = scsi_id; - tgt->vhost = vhost; - tgt->need_login = 1; - tgt->cancel_key = vhost->task_set++; - init_timer(&tgt->timer); - kref_init(&tgt->kref); - ibmvfc_init_tgt(tgt, ibmvfc_tgt_implicit_logout); - spin_lock_irqsave(vhost->host->host_lock, flags); - list_add_tail(&tgt->queue, &vhost->targets); - -unlock_out: - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return 0; -} - -/** - * ibmvfc_alloc_targets - Allocate and initialize ibmvfc targets - * @vhost: ibmvfc host struct - * - * Returns: - * 0 on success / other on failure - **/ -static int ibmvfc_alloc_targets(struct ibmvfc_host *vhost) -{ - int i, rc; - - for (i = 0, rc = 0; !rc && i < vhost->num_targets; i++) - rc = ibmvfc_alloc_target(vhost, - vhost->disc_buf->scsi_id[i] & IBMVFC_DISC_TGT_SCSI_ID_MASK); - - return rc; -} - -/** - * ibmvfc_discover_targets_done - Completion handler for discover targets MAD - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_discover_targets_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - struct ibmvfc_discover_targets *rsp = &evt->xfer_iu->discover_targets; - u32 mad_status = rsp->common.status; - int level = IBMVFC_DEFAULT_LOG_LEVEL; - - switch (mad_status) { - case IBMVFC_MAD_SUCCESS: - ibmvfc_dbg(vhost, "Discover Targets succeeded\n"); - vhost->num_targets = rsp->num_written; - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_ALLOC_TGTS); - break; - case IBMVFC_MAD_FAILED: - level += ibmvfc_retry_host_init(vhost); - ibmvfc_log(vhost, level, "Discover Targets failed: %s (%x:%x)\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); - break; - case IBMVFC_MAD_DRIVER_FAILED: - break; - default: - dev_err(vhost->dev, "Invalid Discover Targets response: 0x%x\n", mad_status); - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - break; - } - - ibmvfc_free_event(evt); - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_discover_targets - Send Discover Targets MAD - * @vhost: ibmvfc host struct - * - **/ -static void ibmvfc_discover_targets(struct ibmvfc_host *vhost) -{ - struct ibmvfc_discover_targets *mad; - struct ibmvfc_event *evt = ibmvfc_get_event(vhost); - - ibmvfc_init_event(evt, ibmvfc_discover_targets_done, IBMVFC_MAD_FORMAT); - mad = &evt->iu.discover_targets; - memset(mad, 0, sizeof(*mad)); - mad->common.version = 1; - mad->common.opcode = IBMVFC_DISC_TARGETS; - mad->common.length = sizeof(*mad); - mad->bufflen = vhost->disc_buf_sz; - mad->buffer.va = vhost->disc_buf_dma; - mad->buffer.len = vhost->disc_buf_sz; - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); - - if (!ibmvfc_send_event(evt, vhost, default_timeout)) - ibmvfc_dbg(vhost, "Sent discover targets\n"); - else - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); -} - -/** - * ibmvfc_npiv_login_done - Completion handler for NPIV Login - * @evt: ibmvfc event struct - * - **/ -static void ibmvfc_npiv_login_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - u32 mad_status = evt->xfer_iu->npiv_login.common.status; - struct ibmvfc_npiv_login_resp *rsp = &vhost->login_buf->resp; - unsigned int npiv_max_sectors; - int level = IBMVFC_DEFAULT_LOG_LEVEL; - - switch (mad_status) { - case IBMVFC_MAD_SUCCESS: - ibmvfc_free_event(evt); - break; - case IBMVFC_MAD_FAILED: - if (ibmvfc_retry_cmd(rsp->status, rsp->error)) - level += ibmvfc_retry_host_init(vhost); - else - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - ibmvfc_log(vhost, level, "NPIV Login failed: %s (%x:%x)\n", - ibmvfc_get_cmd_error(rsp->status, rsp->error), rsp->status, rsp->error); - ibmvfc_free_event(evt); - return; - case IBMVFC_MAD_CRQ_ERROR: - ibmvfc_retry_host_init(vhost); - case IBMVFC_MAD_DRIVER_FAILED: - ibmvfc_free_event(evt); - return; - default: - dev_err(vhost->dev, "Invalid NPIV Login response: 0x%x\n", mad_status); - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - ibmvfc_free_event(evt); - return; - } - - vhost->client_migrated = 0; - - if (!(rsp->flags & IBMVFC_NATIVE_FC)) { - dev_err(vhost->dev, "Virtual adapter does not support FC. %x\n", - rsp->flags); - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - wake_up(&vhost->work_wait_q); - return; - } - - if (rsp->max_cmds <= IBMVFC_NUM_INTERNAL_REQ) { - dev_err(vhost->dev, "Virtual adapter supported queue depth too small: %d\n", - rsp->max_cmds); - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - wake_up(&vhost->work_wait_q); - return; - } - - vhost->logged_in = 1; - npiv_max_sectors = min((uint)(rsp->max_dma_len >> 9), IBMVFC_MAX_SECTORS); - dev_info(vhost->dev, "Host partition: %s, device: %s %s %s max sectors %u\n", - rsp->partition_name, rsp->device_name, rsp->port_loc_code, - rsp->drc_name, npiv_max_sectors); - - fc_host_fabric_name(vhost->host) = rsp->node_name; - fc_host_node_name(vhost->host) = rsp->node_name; - fc_host_port_name(vhost->host) = rsp->port_name; - fc_host_port_id(vhost->host) = rsp->scsi_id; - fc_host_port_type(vhost->host) = FC_PORTTYPE_NPIV; - fc_host_supported_classes(vhost->host) = 0; - if (rsp->service_parms.class1_parms[0] & 0x80000000) - fc_host_supported_classes(vhost->host) |= FC_COS_CLASS1; - if (rsp->service_parms.class2_parms[0] & 0x80000000) - fc_host_supported_classes(vhost->host) |= FC_COS_CLASS2; - if (rsp->service_parms.class3_parms[0] & 0x80000000) - fc_host_supported_classes(vhost->host) |= FC_COS_CLASS3; - fc_host_maxframe_size(vhost->host) = - rsp->service_parms.common.bb_rcv_sz & 0x0fff; - - vhost->host->can_queue = rsp->max_cmds - IBMVFC_NUM_INTERNAL_REQ; - vhost->host->max_sectors = npiv_max_sectors; - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); - wake_up(&vhost->work_wait_q); -} - -/** - * ibmvfc_npiv_login - Sends NPIV login - * @vhost: ibmvfc host struct - * - **/ -static void ibmvfc_npiv_login(struct ibmvfc_host *vhost) -{ - struct ibmvfc_npiv_login_mad *mad; - struct ibmvfc_event *evt = ibmvfc_get_event(vhost); - - ibmvfc_gather_partition_info(vhost); - ibmvfc_set_login_info(vhost); - ibmvfc_init_event(evt, ibmvfc_npiv_login_done, IBMVFC_MAD_FORMAT); - - memcpy(vhost->login_buf, &vhost->login_info, sizeof(vhost->login_info)); - mad = &evt->iu.npiv_login; - memset(mad, 0, sizeof(struct ibmvfc_npiv_login_mad)); - mad->common.version = 1; - mad->common.opcode = IBMVFC_NPIV_LOGIN; - mad->common.length = sizeof(struct ibmvfc_npiv_login_mad); - mad->buffer.va = vhost->login_buf_dma; - mad->buffer.len = sizeof(*vhost->login_buf); - - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT); - - if (!ibmvfc_send_event(evt, vhost, default_timeout)) - ibmvfc_dbg(vhost, "Sent NPIV login\n"); - else - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); -}; - -/** - * ibmvfc_npiv_logout_done - Completion handler for NPIV Logout - * @vhost: ibmvfc host struct - * - **/ -static void ibmvfc_npiv_logout_done(struct ibmvfc_event *evt) -{ - struct ibmvfc_host *vhost = evt->vhost; - u32 mad_status = evt->xfer_iu->npiv_logout.common.status; - - ibmvfc_free_event(evt); - - switch (mad_status) { - case IBMVFC_MAD_SUCCESS: - if (list_empty(&vhost->sent) && - vhost->action == IBMVFC_HOST_ACTION_LOGO_WAIT) { - ibmvfc_init_host(vhost); - return; - } - break; - case IBMVFC_MAD_FAILED: - case IBMVFC_MAD_NOT_SUPPORTED: - case IBMVFC_MAD_CRQ_ERROR: - case IBMVFC_MAD_DRIVER_FAILED: - default: - ibmvfc_dbg(vhost, "NPIV Logout failed. 0x%X\n", mad_status); - break; - } - - ibmvfc_hard_reset_host(vhost); -} - -/** - * ibmvfc_npiv_logout - Issue an NPIV Logout - * @vhost: ibmvfc host struct - * - **/ -static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost) -{ - struct ibmvfc_npiv_logout_mad *mad; - struct ibmvfc_event *evt; - - evt = ibmvfc_get_event(vhost); - ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT); - - mad = &evt->iu.npiv_logout; - memset(mad, 0, sizeof(*mad)); - mad->common.version = 1; - mad->common.opcode = IBMVFC_NPIV_LOGOUT; - mad->common.length = sizeof(struct ibmvfc_npiv_logout_mad); - - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_LOGO_WAIT); - - if (!ibmvfc_send_event(evt, vhost, default_timeout)) - ibmvfc_dbg(vhost, "Sent NPIV logout\n"); - else - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); -} - -/** - * ibmvfc_dev_init_to_do - Is there target initialization work to do? - * @vhost: ibmvfc host struct - * - * Returns: - * 1 if work to do / 0 if not - **/ -static int ibmvfc_dev_init_to_do(struct ibmvfc_host *vhost) -{ - struct ibmvfc_target *tgt; - - list_for_each_entry(tgt, &vhost->targets, queue) { - if (tgt->action == IBMVFC_TGT_ACTION_INIT || - tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) - return 1; - } - - return 0; -} - -/** - * __ibmvfc_work_to_do - Is there task level work to do? (no locking) - * @vhost: ibmvfc host struct - * - * Returns: - * 1 if work to do / 0 if not - **/ -static int __ibmvfc_work_to_do(struct ibmvfc_host *vhost) -{ - struct ibmvfc_target *tgt; - - if (kthread_should_stop()) - return 1; - switch (vhost->action) { - case IBMVFC_HOST_ACTION_NONE: - case IBMVFC_HOST_ACTION_INIT_WAIT: - case IBMVFC_HOST_ACTION_LOGO_WAIT: - return 0; - case IBMVFC_HOST_ACTION_TGT_INIT: - case IBMVFC_HOST_ACTION_QUERY_TGTS: - if (vhost->discovery_threads == disc_threads) - return 0; - list_for_each_entry(tgt, &vhost->targets, queue) - if (tgt->action == IBMVFC_TGT_ACTION_INIT) - return 1; - list_for_each_entry(tgt, &vhost->targets, queue) - if (tgt->action == IBMVFC_TGT_ACTION_INIT_WAIT) - return 0; - return 1; - case IBMVFC_HOST_ACTION_LOGO: - case IBMVFC_HOST_ACTION_INIT: - case IBMVFC_HOST_ACTION_ALLOC_TGTS: - case IBMVFC_HOST_ACTION_TGT_DEL: - case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: - case IBMVFC_HOST_ACTION_QUERY: - case IBMVFC_HOST_ACTION_RESET: - case IBMVFC_HOST_ACTION_REENABLE: - default: - break; - }; - - return 1; -} - -/** - * ibmvfc_work_to_do - Is there task level work to do? - * @vhost: ibmvfc host struct - * - * Returns: - * 1 if work to do / 0 if not - **/ -static int ibmvfc_work_to_do(struct ibmvfc_host *vhost) -{ - unsigned long flags; - int rc; - - spin_lock_irqsave(vhost->host->host_lock, flags); - rc = __ibmvfc_work_to_do(vhost); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return rc; -} - -/** - * ibmvfc_log_ae - Log async events if necessary - * @vhost: ibmvfc host struct - * @events: events to log - * - **/ -static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events) -{ - if (events & IBMVFC_AE_RSCN) - fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_RSCN, 0); - if ((events & IBMVFC_AE_LINKDOWN) && - vhost->state >= IBMVFC_HALTED) - fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); - if ((events & IBMVFC_AE_LINKUP) && - vhost->state == IBMVFC_INITIALIZING) - fc_host_post_event(vhost->host, fc_get_event_number(), FCH_EVT_LINKUP, 0); -} - -/** - * ibmvfc_tgt_add_rport - Tell the FC transport about a new remote port - * @tgt: ibmvfc target struct - * - **/ -static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt) -{ - struct ibmvfc_host *vhost = tgt->vhost; - struct fc_rport *rport; - unsigned long flags; - - tgt_dbg(tgt, "Adding rport\n"); - rport = fc_remote_port_add(vhost->host, 0, &tgt->ids); - spin_lock_irqsave(vhost->host->host_lock, flags); - - if (rport && tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { - tgt_dbg(tgt, "Deleting rport\n"); - list_del(&tgt->queue); - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - fc_remote_port_delete(rport); - del_timer_sync(&tgt->timer); - kref_put(&tgt->kref, ibmvfc_release_tgt); - return; - } else if (rport && tgt->action == IBMVFC_TGT_ACTION_DELETED_RPORT) { - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return; - } - - if (rport) { - tgt_dbg(tgt, "rport add succeeded\n"); - tgt->rport = rport; - rport->maxframe_size = tgt->service_parms.common.bb_rcv_sz & 0x0fff; - rport->supported_classes = 0; - tgt->target_id = rport->scsi_target_id; - if (tgt->service_parms.class1_parms[0] & 0x80000000) - rport->supported_classes |= FC_COS_CLASS1; - if (tgt->service_parms.class2_parms[0] & 0x80000000) - rport->supported_classes |= FC_COS_CLASS2; - if (tgt->service_parms.class3_parms[0] & 0x80000000) - rport->supported_classes |= FC_COS_CLASS3; - if (rport->rqst_q) - blk_queue_max_segments(rport->rqst_q, 1); - } else - tgt_dbg(tgt, "rport add failed\n"); - spin_unlock_irqrestore(vhost->host->host_lock, flags); -} - -/** - * ibmvfc_do_work - Do task level work - * @vhost: ibmvfc host struct - * - **/ -static void ibmvfc_do_work(struct ibmvfc_host *vhost) -{ - struct ibmvfc_target *tgt; - unsigned long flags; - struct fc_rport *rport; - int rc; - - ibmvfc_log_ae(vhost, vhost->events_to_log); - spin_lock_irqsave(vhost->host->host_lock, flags); - vhost->events_to_log = 0; - switch (vhost->action) { - case IBMVFC_HOST_ACTION_NONE: - case IBMVFC_HOST_ACTION_LOGO_WAIT: - case IBMVFC_HOST_ACTION_INIT_WAIT: - break; - case IBMVFC_HOST_ACTION_RESET: - vhost->action = IBMVFC_HOST_ACTION_TGT_DEL; - spin_unlock_irqrestore(vhost->host->host_lock, flags); - rc = ibmvfc_reset_crq(vhost); - spin_lock_irqsave(vhost->host->host_lock, flags); - if (rc == H_CLOSED) - vio_enable_interrupts(to_vio_dev(vhost->dev)); - if (rc || (rc = ibmvfc_send_crq_init(vhost)) || - (rc = vio_enable_interrupts(to_vio_dev(vhost->dev)))) { - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - dev_err(vhost->dev, "Error after reset (rc=%d)\n", rc); - } - break; - case IBMVFC_HOST_ACTION_REENABLE: - vhost->action = IBMVFC_HOST_ACTION_TGT_DEL; - spin_unlock_irqrestore(vhost->host->host_lock, flags); - rc = ibmvfc_reenable_crq_queue(vhost); - spin_lock_irqsave(vhost->host->host_lock, flags); - if (rc || (rc = ibmvfc_send_crq_init(vhost))) { - ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD); - dev_err(vhost->dev, "Error after enable (rc=%d)\n", rc); - } - break; - case IBMVFC_HOST_ACTION_LOGO: - vhost->job_step(vhost); - break; - case IBMVFC_HOST_ACTION_INIT: - BUG_ON(vhost->state != IBMVFC_INITIALIZING); - if (vhost->delay_init) { - vhost->delay_init = 0; - spin_unlock_irqrestore(vhost->host->host_lock, flags); - ssleep(15); - return; - } else - vhost->job_step(vhost); - break; - case IBMVFC_HOST_ACTION_QUERY: - list_for_each_entry(tgt, &vhost->targets, queue) - ibmvfc_init_tgt(tgt, ibmvfc_tgt_query_target); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY_TGTS); - break; - case IBMVFC_HOST_ACTION_QUERY_TGTS: - list_for_each_entry(tgt, &vhost->targets, queue) { - if (tgt->action == IBMVFC_TGT_ACTION_INIT) { - tgt->job_step(tgt); - break; - } - } - - if (!ibmvfc_dev_init_to_do(vhost)) - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL); - break; - case IBMVFC_HOST_ACTION_TGT_DEL: - case IBMVFC_HOST_ACTION_TGT_DEL_FAILED: - list_for_each_entry(tgt, &vhost->targets, queue) { - if (tgt->action == IBMVFC_TGT_ACTION_DEL_RPORT) { - tgt_dbg(tgt, "Deleting rport\n"); - rport = tgt->rport; - tgt->rport = NULL; - list_del(&tgt->queue); - ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DELETED_RPORT); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - if (rport) - fc_remote_port_delete(rport); - del_timer_sync(&tgt->timer); - kref_put(&tgt->kref, ibmvfc_release_tgt); - return; - } - } - - if (vhost->state == IBMVFC_INITIALIZING) { - if (vhost->action == IBMVFC_HOST_ACTION_TGT_DEL_FAILED) { - if (vhost->reinit) { - vhost->reinit = 0; - scsi_block_requests(vhost->host); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - } else { - ibmvfc_set_host_state(vhost, IBMVFC_ACTIVE); - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); - wake_up(&vhost->init_wait_q); - schedule_work(&vhost->rport_add_work_q); - vhost->init_retries = 0; - spin_unlock_irqrestore(vhost->host->host_lock, flags); - scsi_unblock_requests(vhost->host); - } - - return; - } else { - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT); - vhost->job_step = ibmvfc_discover_targets; - } - } else { - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_NONE); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - scsi_unblock_requests(vhost->host); - wake_up(&vhost->init_wait_q); - return; - } - break; - case IBMVFC_HOST_ACTION_ALLOC_TGTS: - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_INIT); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - ibmvfc_alloc_targets(vhost); - spin_lock_irqsave(vhost->host->host_lock, flags); - break; - case IBMVFC_HOST_ACTION_TGT_INIT: - list_for_each_entry(tgt, &vhost->targets, queue) { - if (tgt->action == IBMVFC_TGT_ACTION_INIT) { - tgt->job_step(tgt); - break; - } - } - - if (!ibmvfc_dev_init_to_do(vhost)) - ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_TGT_DEL_FAILED); - break; - default: - break; - }; - - spin_unlock_irqrestore(vhost->host->host_lock, flags); -} - -/** - * ibmvfc_work - Do task level work - * @data: ibmvfc host struct - * - * Returns: - * zero - **/ -static int ibmvfc_work(void *data) -{ - struct ibmvfc_host *vhost = data; - int rc; - - set_user_nice(current, -20); - - while (1) { - rc = wait_event_interruptible(vhost->work_wait_q, - ibmvfc_work_to_do(vhost)); - - BUG_ON(rc); - - if (kthread_should_stop()) - break; - - ibmvfc_do_work(vhost); - } - - ibmvfc_dbg(vhost, "ibmvfc kthread exiting...\n"); - return 0; -} - -/** - * ibmvfc_init_crq - Initializes and registers CRQ with hypervisor - * @vhost: ibmvfc host struct - * - * Allocates a page for messages, maps it for dma, and registers - * the crq with the hypervisor. - * - * Return value: - * zero on success / other on failure - **/ -static int ibmvfc_init_crq(struct ibmvfc_host *vhost) -{ - int rc, retrc = -ENOMEM; - struct device *dev = vhost->dev; - struct vio_dev *vdev = to_vio_dev(dev); - struct ibmvfc_crq_queue *crq = &vhost->crq; - - ENTER; - crq->msgs = (struct ibmvfc_crq *)get_zeroed_page(GFP_KERNEL); - - if (!crq->msgs) - return -ENOMEM; - - crq->size = PAGE_SIZE / sizeof(*crq->msgs); - crq->msg_token = dma_map_single(dev, crq->msgs, - PAGE_SIZE, DMA_BIDIRECTIONAL); - - if (dma_mapping_error(dev, crq->msg_token)) - goto map_failed; - - retrc = rc = plpar_hcall_norets(H_REG_CRQ, vdev->unit_address, - crq->msg_token, PAGE_SIZE); - - if (rc == H_RESOURCE) - /* maybe kexecing and resource is busy. try a reset */ - retrc = rc = ibmvfc_reset_crq(vhost); - - if (rc == H_CLOSED) - dev_warn(dev, "Partner adapter not ready\n"); - else if (rc) { - dev_warn(dev, "Error %d opening adapter\n", rc); - goto reg_crq_failed; - } - - retrc = 0; - - tasklet_init(&vhost->tasklet, (void *)ibmvfc_tasklet, (unsigned long)vhost); - - if ((rc = request_irq(vdev->irq, ibmvfc_interrupt, 0, IBMVFC_NAME, vhost))) { - dev_err(dev, "Couldn't register irq 0x%x. rc=%d\n", vdev->irq, rc); - goto req_irq_failed; - } - - if ((rc = vio_enable_interrupts(vdev))) { - dev_err(dev, "Error %d enabling interrupts\n", rc); - goto req_irq_failed; - } - - crq->cur = 0; - LEAVE; - return retrc; - -req_irq_failed: - tasklet_kill(&vhost->tasklet); - do { - rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while (rc == H_BUSY || H_IS_LONG_BUSY(rc)); -reg_crq_failed: - dma_unmap_single(dev, crq->msg_token, PAGE_SIZE, DMA_BIDIRECTIONAL); -map_failed: - free_page((unsigned long)crq->msgs); - return retrc; -} - -/** - * ibmvfc_free_mem - Free memory for vhost - * @vhost: ibmvfc host struct - * - * Return value: - * none - **/ -static void ibmvfc_free_mem(struct ibmvfc_host *vhost) -{ - struct ibmvfc_async_crq_queue *async_q = &vhost->async_crq; - - ENTER; - mempool_destroy(vhost->tgt_pool); - kfree(vhost->trace); - dma_free_coherent(vhost->dev, vhost->disc_buf_sz, vhost->disc_buf, - vhost->disc_buf_dma); - dma_free_coherent(vhost->dev, sizeof(*vhost->login_buf), - vhost->login_buf, vhost->login_buf_dma); - dma_pool_destroy(vhost->sg_pool); - dma_unmap_single(vhost->dev, async_q->msg_token, - async_q->size * sizeof(*async_q->msgs), DMA_BIDIRECTIONAL); - free_page((unsigned long)async_q->msgs); - LEAVE; -} - -/** - * ibmvfc_alloc_mem - Allocate memory for vhost - * @vhost: ibmvfc host struct - * - * Return value: - * 0 on success / non-zero on failure - **/ -static int ibmvfc_alloc_mem(struct ibmvfc_host *vhost) -{ - struct ibmvfc_async_crq_queue *async_q = &vhost->async_crq; - struct device *dev = vhost->dev; - - ENTER; - async_q->msgs = (struct ibmvfc_async_crq *)get_zeroed_page(GFP_KERNEL); - if (!async_q->msgs) { - dev_err(dev, "Couldn't allocate async queue.\n"); - goto nomem; - } - - async_q->size = PAGE_SIZE / sizeof(struct ibmvfc_async_crq); - async_q->msg_token = dma_map_single(dev, async_q->msgs, - async_q->size * sizeof(*async_q->msgs), - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(dev, async_q->msg_token)) { - dev_err(dev, "Failed to map async queue\n"); - goto free_async_crq; - } - - vhost->sg_pool = dma_pool_create(IBMVFC_NAME, dev, - SG_ALL * sizeof(struct srp_direct_buf), - sizeof(struct srp_direct_buf), 0); - - if (!vhost->sg_pool) { - dev_err(dev, "Failed to allocate sg pool\n"); - goto unmap_async_crq; - } - - vhost->login_buf = dma_alloc_coherent(dev, sizeof(*vhost->login_buf), - &vhost->login_buf_dma, GFP_KERNEL); - - if (!vhost->login_buf) { - dev_err(dev, "Couldn't allocate NPIV login buffer\n"); - goto free_sg_pool; - } - - vhost->disc_buf_sz = sizeof(vhost->disc_buf->scsi_id[0]) * max_targets; - vhost->disc_buf = dma_alloc_coherent(dev, vhost->disc_buf_sz, - &vhost->disc_buf_dma, GFP_KERNEL); - - if (!vhost->disc_buf) { - dev_err(dev, "Couldn't allocate Discover Targets buffer\n"); - goto free_login_buffer; - } - - vhost->trace = kcalloc(IBMVFC_NUM_TRACE_ENTRIES, - sizeof(struct ibmvfc_trace_entry), GFP_KERNEL); - - if (!vhost->trace) - goto free_disc_buffer; - - vhost->tgt_pool = mempool_create_kmalloc_pool(IBMVFC_TGT_MEMPOOL_SZ, - sizeof(struct ibmvfc_target)); - - if (!vhost->tgt_pool) { - dev_err(dev, "Couldn't allocate target memory pool\n"); - goto free_trace; - } - - LEAVE; - return 0; - -free_trace: - kfree(vhost->trace); -free_disc_buffer: - dma_free_coherent(dev, vhost->disc_buf_sz, vhost->disc_buf, - vhost->disc_buf_dma); -free_login_buffer: - dma_free_coherent(dev, sizeof(*vhost->login_buf), - vhost->login_buf, vhost->login_buf_dma); -free_sg_pool: - dma_pool_destroy(vhost->sg_pool); -unmap_async_crq: - dma_unmap_single(dev, async_q->msg_token, - async_q->size * sizeof(*async_q->msgs), DMA_BIDIRECTIONAL); -free_async_crq: - free_page((unsigned long)async_q->msgs); -nomem: - LEAVE; - return -ENOMEM; -} - -/** - * ibmvfc_rport_add_thread - Worker thread for rport adds - * @work: work struct - * - **/ -static void ibmvfc_rport_add_thread(struct work_struct *work) -{ - struct ibmvfc_host *vhost = container_of(work, struct ibmvfc_host, - rport_add_work_q); - struct ibmvfc_target *tgt; - struct fc_rport *rport; - unsigned long flags; - int did_work; - - ENTER; - spin_lock_irqsave(vhost->host->host_lock, flags); - do { - did_work = 0; - if (vhost->state != IBMVFC_ACTIVE) - break; - - list_for_each_entry(tgt, &vhost->targets, queue) { - if (tgt->add_rport) { - did_work = 1; - tgt->add_rport = 0; - kref_get(&tgt->kref); - rport = tgt->rport; - if (!rport) { - spin_unlock_irqrestore(vhost->host->host_lock, flags); - ibmvfc_tgt_add_rport(tgt); - } else if (get_device(&rport->dev)) { - spin_unlock_irqrestore(vhost->host->host_lock, flags); - tgt_dbg(tgt, "Setting rport roles\n"); - fc_remote_port_rolechg(rport, tgt->ids.roles); - put_device(&rport->dev); - } - - kref_put(&tgt->kref, ibmvfc_release_tgt); - spin_lock_irqsave(vhost->host->host_lock, flags); - break; - } - } - } while(did_work); - - if (vhost->state == IBMVFC_ACTIVE) - vhost->scan_complete = 1; - spin_unlock_irqrestore(vhost->host->host_lock, flags); - LEAVE; -} - -/** - * ibmvfc_probe - Adapter hot plug add entry point - * @vdev: vio device struct - * @id: vio device id struct - * - * Return value: - * 0 on success / non-zero on failure - **/ -static int ibmvfc_probe(struct vio_dev *vdev, const struct vio_device_id *id) -{ - struct ibmvfc_host *vhost; - struct Scsi_Host *shost; - struct device *dev = &vdev->dev; - int rc = -ENOMEM; - - ENTER; - shost = scsi_host_alloc(&driver_template, sizeof(*vhost)); - if (!shost) { - dev_err(dev, "Couldn't allocate host data\n"); - goto out; - } - - shost->transportt = ibmvfc_transport_template; - shost->can_queue = max_requests; - shost->max_lun = max_lun; - shost->max_id = max_targets; - shost->max_sectors = IBMVFC_MAX_SECTORS; - shost->max_cmd_len = IBMVFC_MAX_CDB_LEN; - shost->unique_id = shost->host_no; - - vhost = shost_priv(shost); - INIT_LIST_HEAD(&vhost->sent); - INIT_LIST_HEAD(&vhost->free); - INIT_LIST_HEAD(&vhost->targets); - sprintf(vhost->name, IBMVFC_NAME); - vhost->host = shost; - vhost->dev = dev; - vhost->partition_number = -1; - vhost->log_level = log_level; - vhost->task_set = 1; - strcpy(vhost->partition_name, "UNKNOWN"); - init_waitqueue_head(&vhost->work_wait_q); - init_waitqueue_head(&vhost->init_wait_q); - INIT_WORK(&vhost->rport_add_work_q, ibmvfc_rport_add_thread); - mutex_init(&vhost->passthru_mutex); - - if ((rc = ibmvfc_alloc_mem(vhost))) - goto free_scsi_host; - - vhost->work_thread = kthread_run(ibmvfc_work, vhost, "%s_%d", IBMVFC_NAME, - shost->host_no); - - if (IS_ERR(vhost->work_thread)) { - dev_err(dev, "Couldn't create kernel thread: %ld\n", - PTR_ERR(vhost->work_thread)); - goto free_host_mem; - } - - if ((rc = ibmvfc_init_crq(vhost))) { - dev_err(dev, "Couldn't initialize crq. rc=%d\n", rc); - goto kill_kthread; - } - - if ((rc = ibmvfc_init_event_pool(vhost))) { - dev_err(dev, "Couldn't initialize event pool. rc=%d\n", rc); - goto release_crq; - } - - if ((rc = scsi_add_host(shost, dev))) - goto release_event_pool; - - fc_host_dev_loss_tmo(shost) = IBMVFC_DEV_LOSS_TMO; - - if ((rc = ibmvfc_create_trace_file(&shost->shost_dev.kobj, - &ibmvfc_trace_attr))) { - dev_err(dev, "Failed to create trace file. rc=%d\n", rc); - goto remove_shost; - } - - if (shost_to_fc_host(shost)->rqst_q) - blk_queue_max_segments(shost_to_fc_host(shost)->rqst_q, 1); - dev_set_drvdata(dev, vhost); - spin_lock(&ibmvfc_driver_lock); - list_add_tail(&vhost->queue, &ibmvfc_head); - spin_unlock(&ibmvfc_driver_lock); - - ibmvfc_send_crq_init(vhost); - scsi_scan_host(shost); - return 0; - -remove_shost: - scsi_remove_host(shost); -release_event_pool: - ibmvfc_free_event_pool(vhost); -release_crq: - ibmvfc_release_crq_queue(vhost); -kill_kthread: - kthread_stop(vhost->work_thread); -free_host_mem: - ibmvfc_free_mem(vhost); -free_scsi_host: - scsi_host_put(shost); -out: - LEAVE; - return rc; -} - -/** - * ibmvfc_remove - Adapter hot plug remove entry point - * @vdev: vio device struct - * - * Return value: - * 0 - **/ -static int ibmvfc_remove(struct vio_dev *vdev) -{ - struct ibmvfc_host *vhost = dev_get_drvdata(&vdev->dev); - unsigned long flags; - - ENTER; - ibmvfc_remove_trace_file(&vhost->host->shost_dev.kobj, &ibmvfc_trace_attr); - - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_link_down(vhost, IBMVFC_HOST_OFFLINE); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - ibmvfc_wait_while_resetting(vhost); - ibmvfc_release_crq_queue(vhost); - kthread_stop(vhost->work_thread); - fc_remove_host(vhost->host); - scsi_remove_host(vhost->host); - - spin_lock_irqsave(vhost->host->host_lock, flags); - ibmvfc_purge_requests(vhost, DID_ERROR); - ibmvfc_free_event_pool(vhost); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - - ibmvfc_free_mem(vhost); - spin_lock(&ibmvfc_driver_lock); - list_del(&vhost->queue); - spin_unlock(&ibmvfc_driver_lock); - scsi_host_put(vhost->host); - LEAVE; - return 0; -} - -/** - * ibmvfc_resume - Resume from suspend - * @dev: device struct - * - * We may have lost an interrupt across suspend/resume, so kick the - * interrupt handler - * - */ -static int ibmvfc_resume(struct device *dev) -{ - unsigned long flags; - struct ibmvfc_host *vhost = dev_get_drvdata(dev); - struct vio_dev *vdev = to_vio_dev(dev); - - spin_lock_irqsave(vhost->host->host_lock, flags); - vio_disable_interrupts(vdev); - tasklet_schedule(&vhost->tasklet); - spin_unlock_irqrestore(vhost->host->host_lock, flags); - return 0; -} - -/** - * ibmvfc_get_desired_dma - Calculate DMA resources needed by the driver - * @vdev: vio device struct - * - * Return value: - * Number of bytes the driver will need to DMA map at the same time in - * order to perform well. - */ -static unsigned long ibmvfc_get_desired_dma(struct vio_dev *vdev) -{ - unsigned long pool_dma = max_requests * sizeof(union ibmvfc_iu); - return pool_dma + ((512 * 1024) * driver_template.cmd_per_lun); -} - -static struct vio_device_id ibmvfc_device_table[] __devinitdata = { - {"fcp", "IBM,vfc-client"}, - { "", "" } -}; -MODULE_DEVICE_TABLE(vio, ibmvfc_device_table); - -static struct dev_pm_ops ibmvfc_pm_ops = { - .resume = ibmvfc_resume -}; - -static struct vio_driver ibmvfc_driver = { - .id_table = ibmvfc_device_table, - .probe = ibmvfc_probe, - .remove = ibmvfc_remove, - .get_desired_dma = ibmvfc_get_desired_dma, - .name = IBMVFC_NAME, - .pm = &ibmvfc_pm_ops, -}; - -static struct fc_function_template ibmvfc_transport_functions = { - .show_host_fabric_name = 1, - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_port_type = 1, - .show_host_port_id = 1, - .show_host_maxframe_size = 1, - - .get_host_port_state = ibmvfc_get_host_port_state, - .show_host_port_state = 1, - - .get_host_speed = ibmvfc_get_host_speed, - .show_host_speed = 1, - - .issue_fc_host_lip = ibmvfc_issue_fc_host_lip, - .terminate_rport_io = ibmvfc_terminate_rport_io, - - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - - .set_rport_dev_loss_tmo = ibmvfc_set_rport_dev_loss_tmo, - .show_rport_dev_loss_tmo = 1, - - .get_starget_node_name = ibmvfc_get_starget_node_name, - .show_starget_node_name = 1, - - .get_starget_port_name = ibmvfc_get_starget_port_name, - .show_starget_port_name = 1, - - .get_starget_port_id = ibmvfc_get_starget_port_id, - .show_starget_port_id = 1, - - .bsg_request = ibmvfc_bsg_request, - .bsg_timeout = ibmvfc_bsg_timeout, -}; - -/** - * ibmvfc_module_init - Initialize the ibmvfc module - * - * Return value: - * 0 on success / other on failure - **/ -static int __init ibmvfc_module_init(void) -{ - int rc; - - if (!firmware_has_feature(FW_FEATURE_VIO)) - return -ENODEV; - - printk(KERN_INFO IBMVFC_NAME": IBM Virtual Fibre Channel Driver version: %s %s\n", - IBMVFC_DRIVER_VERSION, IBMVFC_DRIVER_DATE); - - ibmvfc_transport_template = fc_attach_transport(&ibmvfc_transport_functions); - if (!ibmvfc_transport_template) - return -ENOMEM; - - rc = vio_register_driver(&ibmvfc_driver); - if (rc) - fc_release_transport(ibmvfc_transport_template); - return rc; -} - -/** - * ibmvfc_module_exit - Teardown the ibmvfc module - * - * Return value: - * nothing - **/ -static void __exit ibmvfc_module_exit(void) -{ - vio_unregister_driver(&ibmvfc_driver); - fc_release_transport(ibmvfc_transport_template); -} - -module_init(ibmvfc_module_init); -module_exit(ibmvfc_module_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.h b/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.h deleted file mode 100644 index 834c37fc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvfc.h +++ /dev/null @@ -1,774 +0,0 @@ -/* - * ibmvfc.h -- driver for IBM Power Virtual Fibre Channel Adapter - * - * Written By: Brian King , IBM Corporation - * - * Copyright (C) IBM Corporation, 2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifndef _IBMVFC_H -#define _IBMVFC_H - -#include -#include -#include "viosrp.h" - -#define IBMVFC_NAME "ibmvfc" -#define IBMVFC_DRIVER_VERSION "1.0.9" -#define IBMVFC_DRIVER_DATE "(August 5, 2010)" - -#define IBMVFC_DEFAULT_TIMEOUT 60 -#define IBMVFC_ADISC_CANCEL_TIMEOUT 45 -#define IBMVFC_ADISC_TIMEOUT 15 -#define IBMVFC_ADISC_PLUS_CANCEL_TIMEOUT \ - (IBMVFC_ADISC_TIMEOUT + IBMVFC_ADISC_CANCEL_TIMEOUT) -#define IBMVFC_INIT_TIMEOUT 120 -#define IBMVFC_ABORT_TIMEOUT 8 -#define IBMVFC_ABORT_WAIT_TIMEOUT 40 -#define IBMVFC_MAX_REQUESTS_DEFAULT 100 - -#define IBMVFC_DEBUG 0 -#define IBMVFC_MAX_TARGETS 1024 -#define IBMVFC_MAX_LUN 0xffffffff -#define IBMVFC_MAX_SECTORS 0xffffu -#define IBMVFC_MAX_DISC_THREADS 4 -#define IBMVFC_TGT_MEMPOOL_SZ 64 -#define IBMVFC_MAX_CMDS_PER_LUN 64 -#define IBMVFC_MAX_HOST_INIT_RETRIES 6 -#define IBMVFC_MAX_TGT_INIT_RETRIES 3 -#define IBMVFC_DEV_LOSS_TMO (5 * 60) -#define IBMVFC_DEFAULT_LOG_LEVEL 2 -#define IBMVFC_MAX_CDB_LEN 16 - -/* - * Ensure we have resources for ERP and initialization: - * 1 for ERP - * 1 for initialization - * 1 for NPIV Logout - * 2 for BSG passthru - * 2 for each discovery thread - */ -#define IBMVFC_NUM_INTERNAL_REQ (1 + 1 + 1 + 2 + (disc_threads * 2)) - -#define IBMVFC_MAD_SUCCESS 0x00 -#define IBMVFC_MAD_NOT_SUPPORTED 0xF1 -#define IBMVFC_MAD_FAILED 0xF7 -#define IBMVFC_MAD_DRIVER_FAILED 0xEE -#define IBMVFC_MAD_CRQ_ERROR 0xEF - -enum ibmvfc_crq_valid { - IBMVFC_CRQ_CMD_RSP = 0x80, - IBMVFC_CRQ_INIT_RSP = 0xC0, - IBMVFC_CRQ_XPORT_EVENT = 0xFF, -}; - -enum ibmvfc_crq_format { - IBMVFC_CRQ_INIT = 0x01, - IBMVFC_CRQ_INIT_COMPLETE = 0x02, - IBMVFC_PARTITION_MIGRATED = 0x06, -}; - -enum ibmvfc_cmd_status_flags { - IBMVFC_FABRIC_MAPPED = 0x0001, - IBMVFC_VIOS_FAILURE = 0x0002, - IBMVFC_FC_FAILURE = 0x0004, - IBMVFC_FC_SCSI_ERROR = 0x0008, - IBMVFC_HW_EVENT_LOGGED = 0x0010, - IBMVFC_VIOS_LOGGED = 0x0020, -}; - -enum ibmvfc_fabric_mapped_errors { - IBMVFC_UNABLE_TO_ESTABLISH = 0x0001, - IBMVFC_XPORT_FAULT = 0x0002, - IBMVFC_CMD_TIMEOUT = 0x0003, - IBMVFC_ENETDOWN = 0x0004, - IBMVFC_HW_FAILURE = 0x0005, - IBMVFC_LINK_DOWN_ERR = 0x0006, - IBMVFC_LINK_DEAD_ERR = 0x0007, - IBMVFC_UNABLE_TO_REGISTER = 0x0008, - IBMVFC_XPORT_BUSY = 0x000A, - IBMVFC_XPORT_DEAD = 0x000B, - IBMVFC_CONFIG_ERROR = 0x000C, - IBMVFC_NAME_SERVER_FAIL = 0x000D, - IBMVFC_LINK_HALTED = 0x000E, - IBMVFC_XPORT_GENERAL = 0x8000, -}; - -enum ibmvfc_vios_errors { - IBMVFC_CRQ_FAILURE = 0x0001, - IBMVFC_SW_FAILURE = 0x0002, - IBMVFC_INVALID_PARAMETER = 0x0003, - IBMVFC_MISSING_PARAMETER = 0x0004, - IBMVFC_HOST_IO_BUS = 0x0005, - IBMVFC_TRANS_CANCELLED = 0x0006, - IBMVFC_TRANS_CANCELLED_IMPLICIT = 0x0007, - IBMVFC_INSUFFICIENT_RESOURCE = 0x0008, - IBMVFC_PLOGI_REQUIRED = 0x0010, - IBMVFC_COMMAND_FAILED = 0x8000, -}; - -enum ibmvfc_mad_types { - IBMVFC_NPIV_LOGIN = 0x0001, - IBMVFC_DISC_TARGETS = 0x0002, - IBMVFC_PORT_LOGIN = 0x0004, - IBMVFC_PROCESS_LOGIN = 0x0008, - IBMVFC_QUERY_TARGET = 0x0010, - IBMVFC_IMPLICIT_LOGOUT = 0x0040, - IBMVFC_PASSTHRU = 0x0200, - IBMVFC_TMF_MAD = 0x0100, - IBMVFC_NPIV_LOGOUT = 0x0800, -}; - -struct ibmvfc_mad_common { - u32 version; - u32 reserved; - u32 opcode; - u16 status; - u16 length; - u64 tag; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_npiv_login_mad { - struct ibmvfc_mad_common common; - struct srp_direct_buf buffer; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_npiv_logout_mad { - struct ibmvfc_mad_common common; -}__attribute__((packed, aligned (8))); - -#define IBMVFC_MAX_NAME 256 - -struct ibmvfc_npiv_login { - u32 ostype; -#define IBMVFC_OS_LINUX 0x02 - u32 pad; - u64 max_dma_len; - u32 max_payload; - u32 max_response; - u32 partition_num; - u32 vfc_frame_version; - u16 fcp_version; - u16 flags; -#define IBMVFC_CLIENT_MIGRATED 0x01 -#define IBMVFC_FLUSH_ON_HALT 0x02 - u32 max_cmds; - u64 capabilities; -#define IBMVFC_CAN_MIGRATE 0x01 - u64 node_name; - struct srp_direct_buf async; - u8 partition_name[IBMVFC_MAX_NAME]; - u8 device_name[IBMVFC_MAX_NAME]; - u8 drc_name[IBMVFC_MAX_NAME]; - u64 reserved2[2]; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_common_svc_parms { - u16 fcph_version; - u16 b2b_credit; - u16 features; - u16 bb_rcv_sz; /* upper nibble is BB_SC_N */ - u32 ratov; - u32 edtov; -}__attribute__((packed, aligned (4))); - -struct ibmvfc_service_parms { - struct ibmvfc_common_svc_parms common; - u8 port_name[8]; - u8 node_name[8]; - u32 class1_parms[4]; - u32 class2_parms[4]; - u32 class3_parms[4]; - u32 obsolete[4]; - u32 vendor_version[4]; - u32 services_avail[2]; - u32 ext_len; - u32 reserved[30]; - u32 clk_sync_qos[2]; -}__attribute__((packed, aligned (4))); - -struct ibmvfc_npiv_login_resp { - u32 version; - u16 status; - u16 error; - u32 flags; -#define IBMVFC_NATIVE_FC 0x01 -#define IBMVFC_CAN_FLUSH_ON_HALT 0x08 - u32 reserved; - u64 capabilities; -#define IBMVFC_CAN_FLUSH_ON_HALT 0x08 - u32 max_cmds; - u32 scsi_id_sz; - u64 max_dma_len; - u64 scsi_id; - u64 port_name; - u64 node_name; - u64 link_speed; - u8 partition_name[IBMVFC_MAX_NAME]; - u8 device_name[IBMVFC_MAX_NAME]; - u8 port_loc_code[IBMVFC_MAX_NAME]; - u8 drc_name[IBMVFC_MAX_NAME]; - struct ibmvfc_service_parms service_parms; - u64 reserved2; -}__attribute__((packed, aligned (8))); - -union ibmvfc_npiv_login_data { - struct ibmvfc_npiv_login login; - struct ibmvfc_npiv_login_resp resp; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_discover_targets_buf { - u32 scsi_id[1]; -#define IBMVFC_DISC_TGT_SCSI_ID_MASK 0x00ffffff -}; - -struct ibmvfc_discover_targets { - struct ibmvfc_mad_common common; - struct srp_direct_buf buffer; - u32 flags; - u16 status; - u16 error; - u32 bufflen; - u32 num_avail; - u32 num_written; - u64 reserved[2]; -}__attribute__((packed, aligned (8))); - -enum ibmvfc_fc_reason { - IBMVFC_INVALID_ELS_CMD_CODE = 0x01, - IBMVFC_INVALID_VERSION = 0x02, - IBMVFC_LOGICAL_ERROR = 0x03, - IBMVFC_INVALID_CT_IU_SIZE = 0x04, - IBMVFC_LOGICAL_BUSY = 0x05, - IBMVFC_PROTOCOL_ERROR = 0x07, - IBMVFC_UNABLE_TO_PERFORM_REQ = 0x09, - IBMVFC_CMD_NOT_SUPPORTED = 0x0B, - IBMVFC_SERVER_NOT_AVAIL = 0x0D, - IBMVFC_CMD_IN_PROGRESS = 0x0E, - IBMVFC_VENDOR_SPECIFIC = 0xFF, -}; - -enum ibmvfc_fc_type { - IBMVFC_FABRIC_REJECT = 0x01, - IBMVFC_PORT_REJECT = 0x02, - IBMVFC_LS_REJECT = 0x03, - IBMVFC_FABRIC_BUSY = 0x04, - IBMVFC_PORT_BUSY = 0x05, - IBMVFC_BASIC_REJECT = 0x06, -}; - -enum ibmvfc_gs_explain { - IBMVFC_PORT_NAME_NOT_REG = 0x02, -}; - -struct ibmvfc_port_login { - struct ibmvfc_mad_common common; - u64 scsi_id; - u16 reserved; - u16 fc_service_class; - u32 blksz; - u32 hdr_per_blk; - u16 status; - u16 error; /* also fc_reason */ - u16 fc_explain; - u16 fc_type; - u32 reserved2; - struct ibmvfc_service_parms service_parms; - struct ibmvfc_service_parms service_parms_change; - u64 reserved3[2]; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_prli_svc_parms { - u8 type; -#define IBMVFC_SCSI_FCP_TYPE 0x08 - u8 type_ext; - u16 flags; -#define IBMVFC_PRLI_ORIG_PA_VALID 0x8000 -#define IBMVFC_PRLI_RESP_PA_VALID 0x4000 -#define IBMVFC_PRLI_EST_IMG_PAIR 0x2000 - u32 orig_pa; - u32 resp_pa; - u32 service_parms; -#define IBMVFC_PRLI_TASK_RETRY 0x00000200 -#define IBMVFC_PRLI_RETRY 0x00000100 -#define IBMVFC_PRLI_DATA_OVERLAY 0x00000040 -#define IBMVFC_PRLI_INITIATOR_FUNC 0x00000020 -#define IBMVFC_PRLI_TARGET_FUNC 0x00000010 -#define IBMVFC_PRLI_READ_FCP_XFER_RDY_DISABLED 0x00000002 -#define IBMVFC_PRLI_WR_FCP_XFER_RDY_DISABLED 0x00000001 -}__attribute__((packed, aligned (4))); - -struct ibmvfc_process_login { - struct ibmvfc_mad_common common; - u64 scsi_id; - struct ibmvfc_prli_svc_parms parms; - u8 reserved[48]; - u16 status; - u16 error; /* also fc_reason */ - u32 reserved2; - u64 reserved3[2]; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_query_tgt { - struct ibmvfc_mad_common common; - u64 wwpn; - u64 scsi_id; - u16 status; - u16 error; - u16 fc_explain; - u16 fc_type; - u64 reserved[2]; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_implicit_logout { - struct ibmvfc_mad_common common; - u64 old_scsi_id; - u64 reserved[2]; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_tmf { - struct ibmvfc_mad_common common; - u64 scsi_id; - struct scsi_lun lun; - u32 flags; -#define IBMVFC_TMF_ABORT_TASK 0x02 -#define IBMVFC_TMF_ABORT_TASK_SET 0x04 -#define IBMVFC_TMF_LUN_RESET 0x10 -#define IBMVFC_TMF_TGT_RESET 0x20 -#define IBMVFC_TMF_LUA_VALID 0x40 - u32 cancel_key; - u32 my_cancel_key; - u32 pad; - u64 reserved[2]; -}__attribute__((packed, aligned (8))); - -enum ibmvfc_fcp_rsp_info_codes { - RSP_NO_FAILURE = 0x00, - RSP_TMF_REJECTED = 0x04, - RSP_TMF_FAILED = 0x05, - RSP_TMF_INVALID_LUN = 0x09, -}; - -struct ibmvfc_fcp_rsp_info { - u16 reserved; - u8 rsp_code; - u8 reserved2[4]; -}__attribute__((packed, aligned (2))); - -enum ibmvfc_fcp_rsp_flags { - FCP_BIDI_RSP = 0x80, - FCP_BIDI_READ_RESID_UNDER = 0x40, - FCP_BIDI_READ_RESID_OVER = 0x20, - FCP_CONF_REQ = 0x10, - FCP_RESID_UNDER = 0x08, - FCP_RESID_OVER = 0x04, - FCP_SNS_LEN_VALID = 0x02, - FCP_RSP_LEN_VALID = 0x01, -}; - -union ibmvfc_fcp_rsp_data { - struct ibmvfc_fcp_rsp_info info; - u8 sense[SCSI_SENSE_BUFFERSIZE + sizeof(struct ibmvfc_fcp_rsp_info)]; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_fcp_rsp { - u64 reserved; - u16 retry_delay_timer; - u8 flags; - u8 scsi_status; - u32 fcp_resid; - u32 fcp_sense_len; - u32 fcp_rsp_len; - union ibmvfc_fcp_rsp_data data; -}__attribute__((packed, aligned (8))); - -enum ibmvfc_cmd_flags { - IBMVFC_SCATTERLIST = 0x0001, - IBMVFC_NO_MEM_DESC = 0x0002, - IBMVFC_READ = 0x0004, - IBMVFC_WRITE = 0x0008, - IBMVFC_TMF = 0x0080, - IBMVFC_CLASS_3_ERR = 0x0100, -}; - -enum ibmvfc_fc_task_attr { - IBMVFC_SIMPLE_TASK = 0x00, - IBMVFC_HEAD_OF_QUEUE = 0x01, - IBMVFC_ORDERED_TASK = 0x02, - IBMVFC_ACA_TASK = 0x04, -}; - -enum ibmvfc_fc_tmf_flags { - IBMVFC_ABORT_TASK_SET = 0x02, - IBMVFC_LUN_RESET = 0x10, - IBMVFC_TARGET_RESET = 0x20, -}; - -struct ibmvfc_fcp_cmd_iu { - struct scsi_lun lun; - u8 crn; - u8 pri_task_attr; - u8 tmf_flags; - u8 add_cdb_len; -#define IBMVFC_RDDATA 0x02 -#define IBMVFC_WRDATA 0x01 - u8 cdb[IBMVFC_MAX_CDB_LEN]; - u32 xfer_len; -}__attribute__((packed, aligned (4))); - -struct ibmvfc_cmd { - u64 task_tag; - u32 frame_type; - u32 payload_len; - u32 resp_len; - u32 adapter_resid; - u16 status; - u16 error; - u16 flags; - u16 response_flags; -#define IBMVFC_ADAPTER_RESID_VALID 0x01 - u32 cancel_key; - u32 exchange_id; - struct srp_direct_buf ext_func; - struct srp_direct_buf ioba; - struct srp_direct_buf resp; - u64 correlation; - u64 tgt_scsi_id; - u64 tag; - u64 reserved3[2]; - struct ibmvfc_fcp_cmd_iu iu; - struct ibmvfc_fcp_rsp rsp; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_passthru_fc_iu { - u32 payload[7]; -#define IBMVFC_ADISC 0x52000000 - u32 response[7]; -}; - -struct ibmvfc_passthru_iu { - u64 task_tag; - u32 cmd_len; - u32 rsp_len; - u16 status; - u16 error; - u32 flags; -#define IBMVFC_FC_ELS 0x01 -#define IBMVFC_FC_CT_IU 0x02 - u32 cancel_key; -#define IBMVFC_PASSTHRU_CANCEL_KEY 0x80000000 -#define IBMVFC_INTERNAL_CANCEL_KEY 0x80000001 - u32 reserved; - struct srp_direct_buf cmd; - struct srp_direct_buf rsp; - u64 correlation; - u64 scsi_id; - u64 tag; - u64 reserved2[2]; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_passthru_mad { - struct ibmvfc_mad_common common; - struct srp_direct_buf cmd_ioba; - struct ibmvfc_passthru_iu iu; - struct ibmvfc_passthru_fc_iu fc_iu; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_trace_start_entry { - u32 xfer_len; -}__attribute__((packed)); - -struct ibmvfc_trace_end_entry { - u16 status; - u16 error; - u8 fcp_rsp_flags; - u8 rsp_code; - u8 scsi_status; - u8 reserved; -}__attribute__((packed)); - -struct ibmvfc_trace_entry { - struct ibmvfc_event *evt; - u32 time; - u32 scsi_id; - u32 lun; - u8 fmt; - u8 op_code; - u8 tmf_flags; - u8 type; -#define IBMVFC_TRC_START 0x00 -#define IBMVFC_TRC_END 0xff - union { - struct ibmvfc_trace_start_entry start; - struct ibmvfc_trace_end_entry end; - } u; -}__attribute__((packed, aligned (8))); - -enum ibmvfc_crq_formats { - IBMVFC_CMD_FORMAT = 0x01, - IBMVFC_ASYNC_EVENT = 0x02, - IBMVFC_MAD_FORMAT = 0x04, -}; - -enum ibmvfc_async_event { - IBMVFC_AE_ELS_PLOGI = 0x0001, - IBMVFC_AE_ELS_LOGO = 0x0002, - IBMVFC_AE_ELS_PRLO = 0x0004, - IBMVFC_AE_SCN_NPORT = 0x0008, - IBMVFC_AE_SCN_GROUP = 0x0010, - IBMVFC_AE_SCN_DOMAIN = 0x0020, - IBMVFC_AE_SCN_FABRIC = 0x0040, - IBMVFC_AE_LINK_UP = 0x0080, - IBMVFC_AE_LINK_DOWN = 0x0100, - IBMVFC_AE_LINK_DEAD = 0x0200, - IBMVFC_AE_HALT = 0x0400, - IBMVFC_AE_RESUME = 0x0800, - IBMVFC_AE_ADAPTER_FAILED = 0x1000, -}; - -struct ibmvfc_async_desc { - const char *desc; - enum ibmvfc_async_event ae; - int log_level; -}; - -struct ibmvfc_crq { - volatile u8 valid; - volatile u8 format; - u8 reserved[6]; - volatile u64 ioba; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_crq_queue { - struct ibmvfc_crq *msgs; - int size, cur; - dma_addr_t msg_token; -}; - -enum ibmvfc_ae_link_state { - IBMVFC_AE_LS_LINK_UP = 0x01, - IBMVFC_AE_LS_LINK_BOUNCED = 0x02, - IBMVFC_AE_LS_LINK_DOWN = 0x04, - IBMVFC_AE_LS_LINK_DEAD = 0x08, -}; - -struct ibmvfc_async_crq { - volatile u8 valid; - u8 link_state; - u8 pad[2]; - u32 pad2; - volatile u64 event; - volatile u64 scsi_id; - volatile u64 wwpn; - volatile u64 node_name; - u64 reserved; -}__attribute__((packed, aligned (8))); - -struct ibmvfc_async_crq_queue { - struct ibmvfc_async_crq *msgs; - int size, cur; - dma_addr_t msg_token; -}; - -union ibmvfc_iu { - struct ibmvfc_mad_common mad_common; - struct ibmvfc_npiv_login_mad npiv_login; - struct ibmvfc_npiv_logout_mad npiv_logout; - struct ibmvfc_discover_targets discover_targets; - struct ibmvfc_port_login plogi; - struct ibmvfc_process_login prli; - struct ibmvfc_query_tgt query_tgt; - struct ibmvfc_implicit_logout implicit_logout; - struct ibmvfc_tmf tmf; - struct ibmvfc_cmd cmd; - struct ibmvfc_passthru_mad passthru; -}__attribute__((packed, aligned (8))); - -enum ibmvfc_target_action { - IBMVFC_TGT_ACTION_NONE = 0, - IBMVFC_TGT_ACTION_INIT, - IBMVFC_TGT_ACTION_INIT_WAIT, - IBMVFC_TGT_ACTION_DEL_RPORT, - IBMVFC_TGT_ACTION_DELETED_RPORT, -}; - -struct ibmvfc_target { - struct list_head queue; - struct ibmvfc_host *vhost; - u64 scsi_id; - u64 new_scsi_id; - struct fc_rport *rport; - int target_id; - enum ibmvfc_target_action action; - int need_login; - int add_rport; - int init_retries; - int logo_rcvd; - u32 cancel_key; - struct ibmvfc_service_parms service_parms; - struct ibmvfc_service_parms service_parms_change; - struct fc_rport_identifiers ids; - void (*job_step) (struct ibmvfc_target *); - struct timer_list timer; - struct kref kref; -}; - -/* a unit of work for the hosting partition */ -struct ibmvfc_event { - struct list_head queue; - struct ibmvfc_host *vhost; - struct ibmvfc_target *tgt; - struct scsi_cmnd *cmnd; - atomic_t free; - union ibmvfc_iu *xfer_iu; - void (*done) (struct ibmvfc_event *); - struct ibmvfc_crq crq; - union ibmvfc_iu iu; - union ibmvfc_iu *sync_iu; - struct srp_direct_buf *ext_list; - dma_addr_t ext_list_token; - struct completion comp; - struct completion *eh_comp; - struct timer_list timer; -}; - -/* a pool of event structs for use */ -struct ibmvfc_event_pool { - struct ibmvfc_event *events; - u32 size; - union ibmvfc_iu *iu_storage; - dma_addr_t iu_token; -}; - -enum ibmvfc_host_action { - IBMVFC_HOST_ACTION_NONE = 0, - IBMVFC_HOST_ACTION_RESET, - IBMVFC_HOST_ACTION_REENABLE, - IBMVFC_HOST_ACTION_LOGO, - IBMVFC_HOST_ACTION_LOGO_WAIT, - IBMVFC_HOST_ACTION_INIT, - IBMVFC_HOST_ACTION_INIT_WAIT, - IBMVFC_HOST_ACTION_QUERY, - IBMVFC_HOST_ACTION_QUERY_TGTS, - IBMVFC_HOST_ACTION_TGT_DEL, - IBMVFC_HOST_ACTION_ALLOC_TGTS, - IBMVFC_HOST_ACTION_TGT_INIT, - IBMVFC_HOST_ACTION_TGT_DEL_FAILED, -}; - -enum ibmvfc_host_state { - IBMVFC_NO_CRQ = 0, - IBMVFC_INITIALIZING, - IBMVFC_ACTIVE, - IBMVFC_HALTED, - IBMVFC_LINK_DOWN, - IBMVFC_LINK_DEAD, - IBMVFC_HOST_OFFLINE, -}; - -struct ibmvfc_host { - char name[8]; - struct list_head queue; - struct Scsi_Host *host; - enum ibmvfc_host_state state; - enum ibmvfc_host_action action; -#define IBMVFC_NUM_TRACE_INDEX_BITS 8 -#define IBMVFC_NUM_TRACE_ENTRIES (1 << IBMVFC_NUM_TRACE_INDEX_BITS) -#define IBMVFC_TRACE_SIZE (sizeof(struct ibmvfc_trace_entry) * IBMVFC_NUM_TRACE_ENTRIES) - struct ibmvfc_trace_entry *trace; - u32 trace_index:IBMVFC_NUM_TRACE_INDEX_BITS; - int num_targets; - struct list_head targets; - struct list_head sent; - struct list_head free; - struct device *dev; - struct ibmvfc_event_pool pool; - struct dma_pool *sg_pool; - mempool_t *tgt_pool; - struct ibmvfc_crq_queue crq; - struct ibmvfc_async_crq_queue async_crq; - struct ibmvfc_npiv_login login_info; - union ibmvfc_npiv_login_data *login_buf; - dma_addr_t login_buf_dma; - int disc_buf_sz; - int log_level; - struct ibmvfc_discover_targets_buf *disc_buf; - struct mutex passthru_mutex; - int task_set; - int init_retries; - int discovery_threads; - int abort_threads; - int client_migrated; - int reinit; - int delay_init; - int scan_complete; - int logged_in; - int aborting_passthru; - int events_to_log; -#define IBMVFC_AE_LINKUP 0x0001 -#define IBMVFC_AE_LINKDOWN 0x0002 -#define IBMVFC_AE_RSCN 0x0004 - dma_addr_t disc_buf_dma; - unsigned int partition_number; - char partition_name[97]; - void (*job_step) (struct ibmvfc_host *); - struct task_struct *work_thread; - struct tasklet_struct tasklet; - struct work_struct rport_add_work_q; - wait_queue_head_t init_wait_q; - wait_queue_head_t work_wait_q; -}; - -#define DBG_CMD(CMD) do { if (ibmvfc_debug) CMD; } while (0) - -#define tgt_dbg(t, fmt, ...) \ - DBG_CMD(dev_info((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__)) - -#define tgt_info(t, fmt, ...) \ - dev_info((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__) - -#define tgt_err(t, fmt, ...) \ - dev_err((t)->vhost->dev, "%llX: " fmt, (t)->scsi_id, ##__VA_ARGS__) - -#define tgt_log(t, level, fmt, ...) \ - do { \ - if ((t)->vhost->log_level >= level) \ - tgt_err(t, fmt, ##__VA_ARGS__); \ - } while (0) - -#define ibmvfc_dbg(vhost, ...) \ - DBG_CMD(dev_info((vhost)->dev, ##__VA_ARGS__)) - -#define ibmvfc_log(vhost, level, ...) \ - do { \ - if ((vhost)->log_level >= level) \ - dev_err((vhost)->dev, ##__VA_ARGS__); \ - } while (0) - -#define ENTER DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Entering %s\n", __func__)) -#define LEAVE DBG_CMD(printk(KERN_INFO IBMVFC_NAME": Leaving %s\n", __func__)) - -#ifdef CONFIG_SCSI_IBMVFC_TRACE -#define ibmvfc_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr) -#define ibmvfc_remove_trace_file(kobj, attr) sysfs_remove_bin_file(kobj, attr) -#else -#define ibmvfc_create_trace_file(kobj, attr) 0 -#define ibmvfc_remove_trace_file(kobj, attr) do { } while (0) -#endif - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.c b/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.c deleted file mode 100644 index 3a6c4742..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.c +++ /dev/null @@ -1,2102 +0,0 @@ -/* ------------------------------------------------------------ - * ibmvscsi.c - * (C) Copyright IBM Corporation 1994, 2004 - * Authors: Colin DeVilbiss (devilbis@us.ibm.com) - * Santiago Leon (santil@us.ibm.com) - * Dave Boutcher (sleddog@us.ibm.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - * ------------------------------------------------------------ - * Emulation of a SCSI host adapter for Virtual I/O devices - * - * This driver supports the SCSI adapter implemented by the IBM - * Power5 firmware. That SCSI adapter is not a physical adapter, - * but allows Linux SCSI peripheral drivers to directly - * access devices in another logical partition on the physical system. - * - * The virtual adapter(s) are present in the open firmware device - * tree just like real adapters. - * - * One of the capabilities provided on these systems is the ability - * to DMA between partitions. The architecture states that for VSCSI, - * the server side is allowed to DMA to and from the client. The client - * is never trusted to DMA to or from the server directly. - * - * Messages are sent between partitions on a "Command/Response Queue" - * (CRQ), which is just a buffer of 16 byte entries in the receiver's - * Senders cannot access the buffer directly, but send messages by - * making a hypervisor call and passing in the 16 bytes. The hypervisor - * puts the message in the next 16 byte space in round-robin fashion, - * turns on the high order bit of the message (the valid bit), and - * generates an interrupt to the receiver (if interrupts are turned on.) - * The receiver just turns off the valid bit when they have copied out - * the message. - * - * The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit - * (IU) (as defined in the T10 standard available at www.t10.org), gets - * a DMA address for the message, and sends it to the server as the - * payload of a CRQ message. The server DMAs the SRP IU and processes it, - * including doing any additional data transfers. When it is done, it - * DMAs the SRP response back to the same address as the request came from, - * and sends a CRQ message back to inform the client that the request has - * completed. - * - * TODO: This is currently pretty tied to the IBM pSeries hypervisor - * interfaces. It would be really nice to abstract this above an RDMA - * layer. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ibmvscsi.h" - -/* The values below are somewhat arbitrary default values, but - * OS/400 will use 3 busses (disks, CDs, tapes, I think.) - * Note that there are 3 bits of channel value, 6 bits of id, and - * 5 bits of LUN. - */ -static int max_id = 64; -static int max_channel = 3; -static int init_timeout = 300; -static int login_timeout = 60; -static int info_timeout = 30; -static int abort_timeout = 60; -static int reset_timeout = 60; -static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; -static int max_events = IBMVSCSI_MAX_REQUESTS_DEFAULT + 2; -static int fast_fail = 1; -static int client_reserve = 1; - -static struct scsi_transport_template *ibmvscsi_transport_template; - -#define IBMVSCSI_VERSION "1.5.9" - -static struct ibmvscsi_ops *ibmvscsi_ops; - -MODULE_DESCRIPTION("IBM Virtual SCSI"); -MODULE_AUTHOR("Dave Boutcher"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(IBMVSCSI_VERSION); - -module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_id, "Largest ID value for each channel"); -module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(max_channel, "Largest channel value"); -module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds"); -module_param_named(max_requests, max_requests, int, S_IRUGO); -MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter"); -module_param_named(fast_fail, fast_fail, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(fast_fail, "Enable fast fail. [Default=1]"); -module_param_named(client_reserve, client_reserve, int, S_IRUGO ); -MODULE_PARM_DESC(client_reserve, "Attempt client managed reserve/release"); - -/* ------------------------------------------------------------ - * Routines for the event pool and event structs - */ -/** - * initialize_event_pool: - Allocates and initializes the event pool for a host - * @pool: event_pool to be initialized - * @size: Number of events in pool - * @hostdata: ibmvscsi_host_data who owns the event pool - * - * Returns zero on success. -*/ -static int initialize_event_pool(struct event_pool *pool, - int size, struct ibmvscsi_host_data *hostdata) -{ - int i; - - pool->size = size; - pool->next = 0; - pool->events = kcalloc(pool->size, sizeof(*pool->events), GFP_KERNEL); - if (!pool->events) - return -ENOMEM; - - pool->iu_storage = - dma_alloc_coherent(hostdata->dev, - pool->size * sizeof(*pool->iu_storage), - &pool->iu_token, 0); - if (!pool->iu_storage) { - kfree(pool->events); - return -ENOMEM; - } - - for (i = 0; i < pool->size; ++i) { - struct srp_event_struct *evt = &pool->events[i]; - memset(&evt->crq, 0x00, sizeof(evt->crq)); - atomic_set(&evt->free, 1); - evt->crq.valid = 0x80; - evt->crq.IU_length = sizeof(*evt->xfer_iu); - evt->crq.IU_data_ptr = pool->iu_token + - sizeof(*evt->xfer_iu) * i; - evt->xfer_iu = pool->iu_storage + i; - evt->hostdata = hostdata; - evt->ext_list = NULL; - evt->ext_list_token = 0; - } - - return 0; -} - -/** - * release_event_pool: - Frees memory of an event pool of a host - * @pool: event_pool to be released - * @hostdata: ibmvscsi_host_data who owns the even pool - * - * Returns zero on success. -*/ -static void release_event_pool(struct event_pool *pool, - struct ibmvscsi_host_data *hostdata) -{ - int i, in_use = 0; - for (i = 0; i < pool->size; ++i) { - if (atomic_read(&pool->events[i].free) != 1) - ++in_use; - if (pool->events[i].ext_list) { - dma_free_coherent(hostdata->dev, - SG_ALL * sizeof(struct srp_direct_buf), - pool->events[i].ext_list, - pool->events[i].ext_list_token); - } - } - if (in_use) - dev_warn(hostdata->dev, "releasing event pool with %d " - "events still in use?\n", in_use); - kfree(pool->events); - dma_free_coherent(hostdata->dev, - pool->size * sizeof(*pool->iu_storage), - pool->iu_storage, pool->iu_token); -} - -/** - * valid_event_struct: - Determines if event is valid. - * @pool: event_pool that contains the event - * @evt: srp_event_struct to be checked for validity - * - * Returns zero if event is invalid, one otherwise. -*/ -static int valid_event_struct(struct event_pool *pool, - struct srp_event_struct *evt) -{ - int index = evt - pool->events; - if (index < 0 || index >= pool->size) /* outside of bounds */ - return 0; - if (evt != pool->events + index) /* unaligned */ - return 0; - return 1; -} - -/** - * ibmvscsi_free-event_struct: - Changes status of event to "free" - * @pool: event_pool that contains the event - * @evt: srp_event_struct to be modified - * -*/ -static void free_event_struct(struct event_pool *pool, - struct srp_event_struct *evt) -{ - if (!valid_event_struct(pool, evt)) { - dev_err(evt->hostdata->dev, "Freeing invalid event_struct %p " - "(not in pool %p)\n", evt, pool->events); - return; - } - if (atomic_inc_return(&evt->free) != 1) { - dev_err(evt->hostdata->dev, "Freeing event_struct %p " - "which is not in use!\n", evt); - return; - } -} - -/** - * get_evt_struct: - Gets the next free event in pool - * @pool: event_pool that contains the events to be searched - * - * Returns the next event in "free" state, and NULL if none are free. - * Note that no synchronization is done here, we assume the host_lock - * will syncrhonze things. -*/ -static struct srp_event_struct *get_event_struct(struct event_pool *pool) -{ - int i; - int poolsize = pool->size; - int offset = pool->next; - - for (i = 0; i < poolsize; i++) { - offset = (offset + 1) % poolsize; - if (!atomic_dec_if_positive(&pool->events[offset].free)) { - pool->next = offset; - return &pool->events[offset]; - } - } - - printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n"); - return NULL; -} - -/** - * init_event_struct: Initialize fields in an event struct that are always - * required. - * @evt: The event - * @done: Routine to call when the event is responded to - * @format: SRP or MAD format - * @timeout: timeout value set in the CRQ - */ -static void init_event_struct(struct srp_event_struct *evt_struct, - void (*done) (struct srp_event_struct *), - u8 format, - int timeout) -{ - evt_struct->cmnd = NULL; - evt_struct->cmnd_done = NULL; - evt_struct->sync_srp = NULL; - evt_struct->crq.format = format; - evt_struct->crq.timeout = timeout; - evt_struct->done = done; -} - -/* ------------------------------------------------------------ - * Routines for receiving SCSI responses from the hosting partition - */ - -/** - * set_srp_direction: Set the fields in the srp related to data - * direction and number of buffers based on the direction in - * the scsi_cmnd and the number of buffers - */ -static void set_srp_direction(struct scsi_cmnd *cmd, - struct srp_cmd *srp_cmd, - int numbuf) -{ - u8 fmt; - - if (numbuf == 0) - return; - - if (numbuf == 1) - fmt = SRP_DATA_DESC_DIRECT; - else { - fmt = SRP_DATA_DESC_INDIRECT; - numbuf = min(numbuf, MAX_INDIRECT_BUFS); - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - srp_cmd->data_out_desc_cnt = numbuf; - else - srp_cmd->data_in_desc_cnt = numbuf; - } - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - srp_cmd->buf_fmt = fmt << 4; - else - srp_cmd->buf_fmt = fmt; -} - -/** - * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format - * @cmd: srp_cmd whose additional_data member will be unmapped - * @dev: device for which the memory is mapped - * -*/ -static void unmap_cmd_data(struct srp_cmd *cmd, - struct srp_event_struct *evt_struct, - struct device *dev) -{ - u8 out_fmt, in_fmt; - - out_fmt = cmd->buf_fmt >> 4; - in_fmt = cmd->buf_fmt & ((1U << 4) - 1); - - if (out_fmt == SRP_NO_DATA_DESC && in_fmt == SRP_NO_DATA_DESC) - return; - - if (evt_struct->cmnd) - scsi_dma_unmap(evt_struct->cmnd); -} - -static int map_sg_list(struct scsi_cmnd *cmd, int nseg, - struct srp_direct_buf *md) -{ - int i; - struct scatterlist *sg; - u64 total_length = 0; - - scsi_for_each_sg(cmd, sg, nseg, i) { - struct srp_direct_buf *descr = md + i; - descr->va = sg_dma_address(sg); - descr->len = sg_dma_len(sg); - descr->key = 0; - total_length += sg_dma_len(sg); - } - return total_length; -} - -/** - * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields - * @cmd: Scsi_Cmnd with the scatterlist - * @srp_cmd: srp_cmd that contains the memory descriptor - * @dev: device for which to map dma memory - * - * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd. - * Returns 1 on success. -*/ -static int map_sg_data(struct scsi_cmnd *cmd, - struct srp_event_struct *evt_struct, - struct srp_cmd *srp_cmd, struct device *dev) -{ - - int sg_mapped; - u64 total_length = 0; - struct srp_direct_buf *data = - (struct srp_direct_buf *) srp_cmd->add_data; - struct srp_indirect_buf *indirect = - (struct srp_indirect_buf *) data; - - sg_mapped = scsi_dma_map(cmd); - if (!sg_mapped) - return 1; - else if (sg_mapped < 0) - return 0; - - set_srp_direction(cmd, srp_cmd, sg_mapped); - - /* special case; we can use a single direct descriptor */ - if (sg_mapped == 1) { - map_sg_list(cmd, sg_mapped, data); - return 1; - } - - indirect->table_desc.va = 0; - indirect->table_desc.len = sg_mapped * sizeof(struct srp_direct_buf); - indirect->table_desc.key = 0; - - if (sg_mapped <= MAX_INDIRECT_BUFS) { - total_length = map_sg_list(cmd, sg_mapped, - &indirect->desc_list[0]); - indirect->len = total_length; - return 1; - } - - /* get indirect table */ - if (!evt_struct->ext_list) { - evt_struct->ext_list = (struct srp_direct_buf *) - dma_alloc_coherent(dev, - SG_ALL * sizeof(struct srp_direct_buf), - &evt_struct->ext_list_token, 0); - if (!evt_struct->ext_list) { - if (!firmware_has_feature(FW_FEATURE_CMO)) - sdev_printk(KERN_ERR, cmd->device, - "Can't allocate memory " - "for indirect table\n"); - scsi_dma_unmap(cmd); - return 0; - } - } - - total_length = map_sg_list(cmd, sg_mapped, evt_struct->ext_list); - - indirect->len = total_length; - indirect->table_desc.va = evt_struct->ext_list_token; - indirect->table_desc.len = sg_mapped * sizeof(indirect->desc_list[0]); - memcpy(indirect->desc_list, evt_struct->ext_list, - MAX_INDIRECT_BUFS * sizeof(struct srp_direct_buf)); - return 1; -} - -/** - * map_data_for_srp_cmd: - Calls functions to map data for srp cmds - * @cmd: struct scsi_cmnd with the memory to be mapped - * @srp_cmd: srp_cmd that contains the memory descriptor - * @dev: dma device for which to map dma memory - * - * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds - * Returns 1 on success. -*/ -static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, - struct srp_event_struct *evt_struct, - struct srp_cmd *srp_cmd, struct device *dev) -{ - switch (cmd->sc_data_direction) { - case DMA_FROM_DEVICE: - case DMA_TO_DEVICE: - break; - case DMA_NONE: - return 1; - case DMA_BIDIRECTIONAL: - sdev_printk(KERN_ERR, cmd->device, - "Can't map DMA_BIDIRECTIONAL to read/write\n"); - return 0; - default: - sdev_printk(KERN_ERR, cmd->device, - "Unknown data direction 0x%02x; can't map!\n", - cmd->sc_data_direction); - return 0; - } - - return map_sg_data(cmd, evt_struct, srp_cmd, dev); -} - -/** - * purge_requests: Our virtual adapter just shut down. purge any sent requests - * @hostdata: the adapter - */ -static void purge_requests(struct ibmvscsi_host_data *hostdata, int error_code) -{ - struct srp_event_struct *evt; - unsigned long flags; - - spin_lock_irqsave(hostdata->host->host_lock, flags); - while (!list_empty(&hostdata->sent)) { - evt = list_first_entry(&hostdata->sent, struct srp_event_struct, list); - list_del(&evt->list); - del_timer(&evt->timer); - - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - if (evt->cmnd) { - evt->cmnd->result = (error_code << 16); - unmap_cmd_data(&evt->iu.srp.cmd, evt, - evt->hostdata->dev); - if (evt->cmnd_done) - evt->cmnd_done(evt->cmnd); - } else if (evt->done) - evt->done(evt); - free_event_struct(&evt->hostdata->pool, evt); - spin_lock_irqsave(hostdata->host->host_lock, flags); - } - spin_unlock_irqrestore(hostdata->host->host_lock, flags); -} - -/** - * ibmvscsi_reset_host - Reset the connection to the server - * @hostdata: struct ibmvscsi_host_data to reset -*/ -static void ibmvscsi_reset_host(struct ibmvscsi_host_data *hostdata) -{ - scsi_block_requests(hostdata->host); - atomic_set(&hostdata->request_limit, 0); - - purge_requests(hostdata, DID_ERROR); - hostdata->reset_crq = 1; - wake_up(&hostdata->work_wait_q); -} - -/** - * ibmvscsi_timeout - Internal command timeout handler - * @evt_struct: struct srp_event_struct that timed out - * - * Called when an internally generated command times out -*/ -static void ibmvscsi_timeout(struct srp_event_struct *evt_struct) -{ - struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; - - dev_err(hostdata->dev, "Command timed out (%x). Resetting connection\n", - evt_struct->iu.srp.cmd.opcode); - - ibmvscsi_reset_host(hostdata); -} - - -/* ------------------------------------------------------------ - * Routines for sending and receiving SRPs - */ -/** - * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq() - * @evt_struct: evt_struct to be sent - * @hostdata: ibmvscsi_host_data of host - * @timeout: timeout in seconds - 0 means do not time command - * - * Returns the value returned from ibmvscsi_send_crq(). (Zero for success) - * Note that this routine assumes that host_lock is held for synchronization -*/ -static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, - struct ibmvscsi_host_data *hostdata, - unsigned long timeout) -{ - u64 *crq_as_u64 = (u64 *) &evt_struct->crq; - int request_status = 0; - int rc; - int srp_req = 0; - - /* If we have exhausted our request limit, just fail this request, - * unless it is for a reset or abort. - * Note that there are rare cases involving driver generated requests - * (such as task management requests) that the mid layer may think we - * can handle more requests (can_queue) when we actually can't - */ - if (evt_struct->crq.format == VIOSRP_SRP_FORMAT) { - srp_req = 1; - request_status = - atomic_dec_if_positive(&hostdata->request_limit); - /* If request limit was -1 when we started, it is now even - * less than that - */ - if (request_status < -1) - goto send_error; - /* Otherwise, we may have run out of requests. */ - /* If request limit was 0 when we started the adapter is in the - * process of performing a login with the server adapter, or - * we may have run out of requests. - */ - else if (request_status == -1 && - evt_struct->iu.srp.login_req.opcode != SRP_LOGIN_REQ) - goto send_busy; - /* Abort and reset calls should make it through. - * Nothing except abort and reset should use the last two - * slots unless we had two or less to begin with. - */ - else if (request_status < 2 && - evt_struct->iu.srp.cmd.opcode != SRP_TSK_MGMT) { - /* In the case that we have less than two requests - * available, check the server limit as a combination - * of the request limit and the number of requests - * in-flight (the size of the send list). If the - * server limit is greater than 2, return busy so - * that the last two are reserved for reset and abort. - */ - int server_limit = request_status; - struct srp_event_struct *tmp_evt; - - list_for_each_entry(tmp_evt, &hostdata->sent, list) { - server_limit++; - } - - if (server_limit > 2) - goto send_busy; - } - } - - /* Copy the IU into the transfer area */ - *evt_struct->xfer_iu = evt_struct->iu; - evt_struct->xfer_iu->srp.rsp.tag = (u64)evt_struct; - - /* Add this to the sent list. We need to do this - * before we actually send - * in case it comes back REALLY fast - */ - list_add_tail(&evt_struct->list, &hostdata->sent); - - init_timer(&evt_struct->timer); - if (timeout) { - evt_struct->timer.data = (unsigned long) evt_struct; - evt_struct->timer.expires = jiffies + (timeout * HZ); - evt_struct->timer.function = (void (*)(unsigned long))ibmvscsi_timeout; - add_timer(&evt_struct->timer); - } - - if ((rc = - ibmvscsi_ops->send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) { - list_del(&evt_struct->list); - del_timer(&evt_struct->timer); - - /* If send_crq returns H_CLOSED, return SCSI_MLQUEUE_HOST_BUSY. - * Firmware will send a CRQ with a transport event (0xFF) to - * tell this client what has happened to the transport. This - * will be handled in ibmvscsi_handle_crq() - */ - if (rc == H_CLOSED) { - dev_warn(hostdata->dev, "send warning. " - "Receive queue closed, will retry.\n"); - goto send_busy; - } - dev_err(hostdata->dev, "send error %d\n", rc); - if (srp_req) - atomic_inc(&hostdata->request_limit); - goto send_error; - } - - return 0; - - send_busy: - unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); - - free_event_struct(&hostdata->pool, evt_struct); - if (srp_req && request_status != -1) - atomic_inc(&hostdata->request_limit); - return SCSI_MLQUEUE_HOST_BUSY; - - send_error: - unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); - - if (evt_struct->cmnd != NULL) { - evt_struct->cmnd->result = DID_ERROR << 16; - evt_struct->cmnd_done(evt_struct->cmnd); - } else if (evt_struct->done) - evt_struct->done(evt_struct); - - free_event_struct(&hostdata->pool, evt_struct); - return 0; -} - -/** - * handle_cmd_rsp: - Handle responses from commands - * @evt_struct: srp_event_struct to be handled - * - * Used as a callback by when sending scsi cmds. - * Gets called by ibmvscsi_handle_crq() -*/ -static void handle_cmd_rsp(struct srp_event_struct *evt_struct) -{ - struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp; - struct scsi_cmnd *cmnd = evt_struct->cmnd; - - if (unlikely(rsp->opcode != SRP_RSP)) { - if (printk_ratelimit()) - dev_warn(evt_struct->hostdata->dev, - "bad SRP RSP type %d\n", rsp->opcode); - } - - if (cmnd) { - cmnd->result |= rsp->status; - if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION) - memcpy(cmnd->sense_buffer, - rsp->data, - rsp->sense_data_len); - unmap_cmd_data(&evt_struct->iu.srp.cmd, - evt_struct, - evt_struct->hostdata->dev); - - if (rsp->flags & SRP_RSP_FLAG_DOOVER) - scsi_set_resid(cmnd, rsp->data_out_res_cnt); - else if (rsp->flags & SRP_RSP_FLAG_DIOVER) - scsi_set_resid(cmnd, rsp->data_in_res_cnt); - } - - if (evt_struct->cmnd_done) - evt_struct->cmnd_done(cmnd); -} - -/** - * lun_from_dev: - Returns the lun of the scsi device - * @dev: struct scsi_device - * -*/ -static inline u16 lun_from_dev(struct scsi_device *dev) -{ - return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun; -} - -/** - * ibmvscsi_queue: - The queuecommand function of the scsi template - * @cmd: struct scsi_cmnd to be executed - * @done: Callback function to be called when cmd is completed -*/ -static int ibmvscsi_queuecommand_lck(struct scsi_cmnd *cmnd, - void (*done) (struct scsi_cmnd *)) -{ - struct srp_cmd *srp_cmd; - struct srp_event_struct *evt_struct; - struct srp_indirect_buf *indirect; - struct ibmvscsi_host_data *hostdata = shost_priv(cmnd->device->host); - u16 lun = lun_from_dev(cmnd->device); - u8 out_fmt, in_fmt; - - cmnd->result = (DID_OK << 16); - evt_struct = get_event_struct(&hostdata->pool); - if (!evt_struct) - return SCSI_MLQUEUE_HOST_BUSY; - - /* Set up the actual SRP IU */ - srp_cmd = &evt_struct->iu.srp.cmd; - memset(srp_cmd, 0x00, SRP_MAX_IU_LEN); - srp_cmd->opcode = SRP_CMD; - memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(srp_cmd->cdb)); - srp_cmd->lun = ((u64) lun) << 48; - - if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) { - if (!firmware_has_feature(FW_FEATURE_CMO)) - sdev_printk(KERN_ERR, cmnd->device, - "couldn't convert cmd to srp_cmd\n"); - free_event_struct(&hostdata->pool, evt_struct); - return SCSI_MLQUEUE_HOST_BUSY; - } - - init_event_struct(evt_struct, - handle_cmd_rsp, - VIOSRP_SRP_FORMAT, - cmnd->request->timeout/HZ); - - evt_struct->cmnd = cmnd; - evt_struct->cmnd_done = done; - - /* Fix up dma address of the buffer itself */ - indirect = (struct srp_indirect_buf *) srp_cmd->add_data; - out_fmt = srp_cmd->buf_fmt >> 4; - in_fmt = srp_cmd->buf_fmt & ((1U << 4) - 1); - if ((in_fmt == SRP_DATA_DESC_INDIRECT || - out_fmt == SRP_DATA_DESC_INDIRECT) && - indirect->table_desc.va == 0) { - indirect->table_desc.va = evt_struct->crq.IU_data_ptr + - offsetof(struct srp_cmd, add_data) + - offsetof(struct srp_indirect_buf, desc_list); - } - - return ibmvscsi_send_srp_event(evt_struct, hostdata, 0); -} - -static DEF_SCSI_QCMD(ibmvscsi_queuecommand) - -/* ------------------------------------------------------------ - * Routines for driver initialization - */ - -/** - * map_persist_bufs: - Pre-map persistent data for adapter logins - * @hostdata: ibmvscsi_host_data of host - * - * Map the capabilities and adapter info DMA buffers to avoid runtime failures. - * Return 1 on error, 0 on success. - */ -static int map_persist_bufs(struct ibmvscsi_host_data *hostdata) -{ - - hostdata->caps_addr = dma_map_single(hostdata->dev, &hostdata->caps, - sizeof(hostdata->caps), DMA_BIDIRECTIONAL); - - if (dma_mapping_error(hostdata->dev, hostdata->caps_addr)) { - dev_err(hostdata->dev, "Unable to map capabilities buffer!\n"); - return 1; - } - - hostdata->adapter_info_addr = dma_map_single(hostdata->dev, - &hostdata->madapter_info, - sizeof(hostdata->madapter_info), - DMA_BIDIRECTIONAL); - if (dma_mapping_error(hostdata->dev, hostdata->adapter_info_addr)) { - dev_err(hostdata->dev, "Unable to map adapter info buffer!\n"); - dma_unmap_single(hostdata->dev, hostdata->caps_addr, - sizeof(hostdata->caps), DMA_BIDIRECTIONAL); - return 1; - } - - return 0; -} - -/** - * unmap_persist_bufs: - Unmap persistent data needed for adapter logins - * @hostdata: ibmvscsi_host_data of host - * - * Unmap the capabilities and adapter info DMA buffers - */ -static void unmap_persist_bufs(struct ibmvscsi_host_data *hostdata) -{ - dma_unmap_single(hostdata->dev, hostdata->caps_addr, - sizeof(hostdata->caps), DMA_BIDIRECTIONAL); - - dma_unmap_single(hostdata->dev, hostdata->adapter_info_addr, - sizeof(hostdata->madapter_info), DMA_BIDIRECTIONAL); -} - -/** - * login_rsp: - Handle response to SRP login request - * @evt_struct: srp_event_struct with the response - * - * Used as a "done" callback by when sending srp_login. Gets called - * by ibmvscsi_handle_crq() -*/ -static void login_rsp(struct srp_event_struct *evt_struct) -{ - struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; - switch (evt_struct->xfer_iu->srp.login_rsp.opcode) { - case SRP_LOGIN_RSP: /* it worked! */ - break; - case SRP_LOGIN_REJ: /* refused! */ - dev_info(hostdata->dev, "SRP_LOGIN_REJ reason %u\n", - evt_struct->xfer_iu->srp.login_rej.reason); - /* Login failed. */ - atomic_set(&hostdata->request_limit, -1); - return; - default: - dev_err(hostdata->dev, "Invalid login response typecode 0x%02x!\n", - evt_struct->xfer_iu->srp.login_rsp.opcode); - /* Login failed. */ - atomic_set(&hostdata->request_limit, -1); - return; - } - - dev_info(hostdata->dev, "SRP_LOGIN succeeded\n"); - hostdata->client_migrated = 0; - - /* Now we know what the real request-limit is. - * This value is set rather than added to request_limit because - * request_limit could have been set to -1 by this client. - */ - atomic_set(&hostdata->request_limit, - evt_struct->xfer_iu->srp.login_rsp.req_lim_delta); - - /* If we had any pending I/Os, kick them */ - scsi_unblock_requests(hostdata->host); -} - -/** - * send_srp_login: - Sends the srp login - * @hostdata: ibmvscsi_host_data of host - * - * Returns zero if successful. -*/ -static int send_srp_login(struct ibmvscsi_host_data *hostdata) -{ - int rc; - unsigned long flags; - struct srp_login_req *login; - struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool); - - BUG_ON(!evt_struct); - init_event_struct(evt_struct, login_rsp, - VIOSRP_SRP_FORMAT, login_timeout); - - login = &evt_struct->iu.srp.login_req; - memset(login, 0, sizeof(*login)); - login->opcode = SRP_LOGIN_REQ; - login->req_it_iu_len = sizeof(union srp_iu); - login->req_buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT; - - spin_lock_irqsave(hostdata->host->host_lock, flags); - /* Start out with a request limit of 0, since this is negotiated in - * the login request we are just sending and login requests always - * get sent by the driver regardless of request_limit. - */ - atomic_set(&hostdata->request_limit, 0); - - rc = ibmvscsi_send_srp_event(evt_struct, hostdata, login_timeout * 2); - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - dev_info(hostdata->dev, "sent SRP login\n"); - return rc; -}; - -/** - * capabilities_rsp: - Handle response to MAD adapter capabilities request - * @evt_struct: srp_event_struct with the response - * - * Used as a "done" callback by when sending adapter_info. - */ -static void capabilities_rsp(struct srp_event_struct *evt_struct) -{ - struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; - - if (evt_struct->xfer_iu->mad.capabilities.common.status) { - dev_err(hostdata->dev, "error 0x%X getting capabilities info\n", - evt_struct->xfer_iu->mad.capabilities.common.status); - } else { - if (hostdata->caps.migration.common.server_support != SERVER_SUPPORTS_CAP) - dev_info(hostdata->dev, "Partition migration not supported\n"); - - if (client_reserve) { - if (hostdata->caps.reserve.common.server_support == - SERVER_SUPPORTS_CAP) - dev_info(hostdata->dev, "Client reserve enabled\n"); - else - dev_info(hostdata->dev, "Client reserve not supported\n"); - } - } - - send_srp_login(hostdata); -} - -/** - * send_mad_capabilities: - Sends the mad capabilities request - * and stores the result so it can be retrieved with - * @hostdata: ibmvscsi_host_data of host - */ -static void send_mad_capabilities(struct ibmvscsi_host_data *hostdata) -{ - struct viosrp_capabilities *req; - struct srp_event_struct *evt_struct; - unsigned long flags; - struct device_node *of_node = hostdata->dev->of_node; - const char *location; - - evt_struct = get_event_struct(&hostdata->pool); - BUG_ON(!evt_struct); - - init_event_struct(evt_struct, capabilities_rsp, - VIOSRP_MAD_FORMAT, info_timeout); - - req = &evt_struct->iu.mad.capabilities; - memset(req, 0, sizeof(*req)); - - hostdata->caps.flags = CAP_LIST_SUPPORTED; - if (hostdata->client_migrated) - hostdata->caps.flags |= CLIENT_MIGRATED; - - strncpy(hostdata->caps.name, dev_name(&hostdata->host->shost_gendev), - sizeof(hostdata->caps.name)); - hostdata->caps.name[sizeof(hostdata->caps.name) - 1] = '\0'; - - location = of_get_property(of_node, "ibm,loc-code", NULL); - location = location ? location : dev_name(hostdata->dev); - strncpy(hostdata->caps.loc, location, sizeof(hostdata->caps.loc)); - hostdata->caps.loc[sizeof(hostdata->caps.loc) - 1] = '\0'; - - req->common.type = VIOSRP_CAPABILITIES_TYPE; - req->buffer = hostdata->caps_addr; - - hostdata->caps.migration.common.cap_type = MIGRATION_CAPABILITIES; - hostdata->caps.migration.common.length = sizeof(hostdata->caps.migration); - hostdata->caps.migration.common.server_support = SERVER_SUPPORTS_CAP; - hostdata->caps.migration.ecl = 1; - - if (client_reserve) { - hostdata->caps.reserve.common.cap_type = RESERVATION_CAPABILITIES; - hostdata->caps.reserve.common.length = sizeof(hostdata->caps.reserve); - hostdata->caps.reserve.common.server_support = SERVER_SUPPORTS_CAP; - hostdata->caps.reserve.type = CLIENT_RESERVE_SCSI_2; - req->common.length = sizeof(hostdata->caps); - } else - req->common.length = sizeof(hostdata->caps) - sizeof(hostdata->caps.reserve); - - spin_lock_irqsave(hostdata->host->host_lock, flags); - if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2)) - dev_err(hostdata->dev, "couldn't send CAPABILITIES_REQ!\n"); - spin_unlock_irqrestore(hostdata->host->host_lock, flags); -}; - -/** - * fast_fail_rsp: - Handle response to MAD enable fast fail - * @evt_struct: srp_event_struct with the response - * - * Used as a "done" callback by when sending enable fast fail. Gets called - * by ibmvscsi_handle_crq() - */ -static void fast_fail_rsp(struct srp_event_struct *evt_struct) -{ - struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; - u8 status = evt_struct->xfer_iu->mad.fast_fail.common.status; - - if (status == VIOSRP_MAD_NOT_SUPPORTED) - dev_err(hostdata->dev, "fast_fail not supported in server\n"); - else if (status == VIOSRP_MAD_FAILED) - dev_err(hostdata->dev, "fast_fail request failed\n"); - else if (status != VIOSRP_MAD_SUCCESS) - dev_err(hostdata->dev, "error 0x%X enabling fast_fail\n", status); - - send_mad_capabilities(hostdata); -} - -/** - * init_host - Start host initialization - * @hostdata: ibmvscsi_host_data of host - * - * Returns zero if successful. - */ -static int enable_fast_fail(struct ibmvscsi_host_data *hostdata) -{ - int rc; - unsigned long flags; - struct viosrp_fast_fail *fast_fail_mad; - struct srp_event_struct *evt_struct; - - if (!fast_fail) { - send_mad_capabilities(hostdata); - return 0; - } - - evt_struct = get_event_struct(&hostdata->pool); - BUG_ON(!evt_struct); - - init_event_struct(evt_struct, fast_fail_rsp, VIOSRP_MAD_FORMAT, info_timeout); - - fast_fail_mad = &evt_struct->iu.mad.fast_fail; - memset(fast_fail_mad, 0, sizeof(*fast_fail_mad)); - fast_fail_mad->common.type = VIOSRP_ENABLE_FAST_FAIL; - fast_fail_mad->common.length = sizeof(*fast_fail_mad); - - spin_lock_irqsave(hostdata->host->host_lock, flags); - rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2); - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - return rc; -} - -/** - * adapter_info_rsp: - Handle response to MAD adapter info request - * @evt_struct: srp_event_struct with the response - * - * Used as a "done" callback by when sending adapter_info. Gets called - * by ibmvscsi_handle_crq() -*/ -static void adapter_info_rsp(struct srp_event_struct *evt_struct) -{ - struct ibmvscsi_host_data *hostdata = evt_struct->hostdata; - - if (evt_struct->xfer_iu->mad.adapter_info.common.status) { - dev_err(hostdata->dev, "error %d getting adapter info\n", - evt_struct->xfer_iu->mad.adapter_info.common.status); - } else { - dev_info(hostdata->dev, "host srp version: %s, " - "host partition %s (%d), OS %d, max io %u\n", - hostdata->madapter_info.srp_version, - hostdata->madapter_info.partition_name, - hostdata->madapter_info.partition_number, - hostdata->madapter_info.os_type, - hostdata->madapter_info.port_max_txu[0]); - - if (hostdata->madapter_info.port_max_txu[0]) - hostdata->host->max_sectors = - hostdata->madapter_info.port_max_txu[0] >> 9; - - if (hostdata->madapter_info.os_type == 3 && - strcmp(hostdata->madapter_info.srp_version, "1.6a") <= 0) { - dev_err(hostdata->dev, "host (Ver. %s) doesn't support large transfers\n", - hostdata->madapter_info.srp_version); - dev_err(hostdata->dev, "limiting scatterlists to %d\n", - MAX_INDIRECT_BUFS); - hostdata->host->sg_tablesize = MAX_INDIRECT_BUFS; - } - - if (hostdata->madapter_info.os_type == 3) { - enable_fast_fail(hostdata); - return; - } - } - - send_srp_login(hostdata); -} - -/** - * send_mad_adapter_info: - Sends the mad adapter info request - * and stores the result so it can be retrieved with - * sysfs. We COULD consider causing a failure if the - * returned SRP version doesn't match ours. - * @hostdata: ibmvscsi_host_data of host - * - * Returns zero if successful. -*/ -static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata) -{ - struct viosrp_adapter_info *req; - struct srp_event_struct *evt_struct; - unsigned long flags; - - evt_struct = get_event_struct(&hostdata->pool); - BUG_ON(!evt_struct); - - init_event_struct(evt_struct, - adapter_info_rsp, - VIOSRP_MAD_FORMAT, - info_timeout); - - req = &evt_struct->iu.mad.adapter_info; - memset(req, 0x00, sizeof(*req)); - - req->common.type = VIOSRP_ADAPTER_INFO_TYPE; - req->common.length = sizeof(hostdata->madapter_info); - req->buffer = hostdata->adapter_info_addr; - - spin_lock_irqsave(hostdata->host->host_lock, flags); - if (ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2)) - dev_err(hostdata->dev, "couldn't send ADAPTER_INFO_REQ!\n"); - spin_unlock_irqrestore(hostdata->host->host_lock, flags); -}; - -/** - * init_adapter: Start virtual adapter initialization sequence - * - */ -static void init_adapter(struct ibmvscsi_host_data *hostdata) -{ - send_mad_adapter_info(hostdata); -} - -/** - * sync_completion: Signal that a synchronous command has completed - * Note that after returning from this call, the evt_struct is freed. - * the caller waiting on this completion shouldn't touch the evt_struct - * again. - */ -static void sync_completion(struct srp_event_struct *evt_struct) -{ - /* copy the response back */ - if (evt_struct->sync_srp) - *evt_struct->sync_srp = *evt_struct->xfer_iu; - - complete(&evt_struct->comp); -} - -/** - * ibmvscsi_abort: Abort a command...from scsi host template - * send this over to the server and wait synchronously for the response - */ -static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) -{ - struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host); - struct srp_tsk_mgmt *tsk_mgmt; - struct srp_event_struct *evt; - struct srp_event_struct *tmp_evt, *found_evt; - union viosrp_iu srp_rsp; - int rsp_rc; - unsigned long flags; - u16 lun = lun_from_dev(cmd->device); - unsigned long wait_switch = 0; - - /* First, find this command in our sent list so we can figure - * out the correct tag - */ - spin_lock_irqsave(hostdata->host->host_lock, flags); - wait_switch = jiffies + (init_timeout * HZ); - do { - found_evt = NULL; - list_for_each_entry(tmp_evt, &hostdata->sent, list) { - if (tmp_evt->cmnd == cmd) { - found_evt = tmp_evt; - break; - } - } - - if (!found_evt) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - return SUCCESS; - } - - evt = get_event_struct(&hostdata->pool); - if (evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_ERR, cmd->device, - "failed to allocate abort event\n"); - return FAILED; - } - - init_event_struct(evt, - sync_completion, - VIOSRP_SRP_FORMAT, - abort_timeout); - - tsk_mgmt = &evt->iu.srp.tsk_mgmt; - - /* Set up an abort SRP command */ - memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->tsk_mgmt_func = SRP_TSK_ABORT_TASK; - tsk_mgmt->task_tag = (u64) found_evt; - - evt->sync_srp = &srp_rsp; - - init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, abort_timeout * 2); - - if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) - break; - - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - msleep(10); - spin_lock_irqsave(hostdata->host->host_lock, flags); - } while (time_before(jiffies, wait_switch)); - - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - - if (rsp_rc != 0) { - sdev_printk(KERN_ERR, cmd->device, - "failed to send abort() event. rc=%d\n", rsp_rc); - return FAILED; - } - - sdev_printk(KERN_INFO, cmd->device, - "aborting command. lun 0x%llx, tag 0x%llx\n", - (((u64) lun) << 48), (u64) found_evt); - - wait_for_completion(&evt->comp); - - /* make sure we got a good response */ - if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) { - if (printk_ratelimit()) - sdev_printk(KERN_WARNING, cmd->device, "abort bad SRP RSP type %d\n", - srp_rsp.srp.rsp.opcode); - return FAILED; - } - - if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID) - rsp_rc = *((int *)srp_rsp.srp.rsp.data); - else - rsp_rc = srp_rsp.srp.rsp.status; - - if (rsp_rc) { - if (printk_ratelimit()) - sdev_printk(KERN_WARNING, cmd->device, - "abort code %d for task tag 0x%llx\n", - rsp_rc, tsk_mgmt->task_tag); - return FAILED; - } - - /* Because we dropped the spinlock above, it's possible - * The event is no longer in our list. Make sure it didn't - * complete while we were aborting - */ - spin_lock_irqsave(hostdata->host->host_lock, flags); - found_evt = NULL; - list_for_each_entry(tmp_evt, &hostdata->sent, list) { - if (tmp_evt->cmnd == cmd) { - found_evt = tmp_evt; - break; - } - } - - if (found_evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_INFO, cmd->device, "aborted task tag 0x%llx completed\n", - tsk_mgmt->task_tag); - return SUCCESS; - } - - sdev_printk(KERN_INFO, cmd->device, "successfully aborted task tag 0x%llx\n", - tsk_mgmt->task_tag); - - cmd->result = (DID_ABORT << 16); - list_del(&found_evt->list); - unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt, - found_evt->hostdata->dev); - free_event_struct(&found_evt->hostdata->pool, found_evt); - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - atomic_inc(&hostdata->request_limit); - return SUCCESS; -} - -/** - * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host - * template send this over to the server and wait synchronously for the - * response - */ -static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) -{ - struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host); - struct srp_tsk_mgmt *tsk_mgmt; - struct srp_event_struct *evt; - struct srp_event_struct *tmp_evt, *pos; - union viosrp_iu srp_rsp; - int rsp_rc; - unsigned long flags; - u16 lun = lun_from_dev(cmd->device); - unsigned long wait_switch = 0; - - spin_lock_irqsave(hostdata->host->host_lock, flags); - wait_switch = jiffies + (init_timeout * HZ); - do { - evt = get_event_struct(&hostdata->pool); - if (evt == NULL) { - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - sdev_printk(KERN_ERR, cmd->device, - "failed to allocate reset event\n"); - return FAILED; - } - - init_event_struct(evt, - sync_completion, - VIOSRP_SRP_FORMAT, - reset_timeout); - - tsk_mgmt = &evt->iu.srp.tsk_mgmt; - - /* Set up a lun reset SRP command */ - memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt)); - tsk_mgmt->opcode = SRP_TSK_MGMT; - tsk_mgmt->lun = ((u64) lun) << 48; - tsk_mgmt->tsk_mgmt_func = SRP_TSK_LUN_RESET; - - evt->sync_srp = &srp_rsp; - - init_completion(&evt->comp); - rsp_rc = ibmvscsi_send_srp_event(evt, hostdata, reset_timeout * 2); - - if (rsp_rc != SCSI_MLQUEUE_HOST_BUSY) - break; - - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - msleep(10); - spin_lock_irqsave(hostdata->host->host_lock, flags); - } while (time_before(jiffies, wait_switch)); - - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - - if (rsp_rc != 0) { - sdev_printk(KERN_ERR, cmd->device, - "failed to send reset event. rc=%d\n", rsp_rc); - return FAILED; - } - - sdev_printk(KERN_INFO, cmd->device, "resetting device. lun 0x%llx\n", - (((u64) lun) << 48)); - - wait_for_completion(&evt->comp); - - /* make sure we got a good response */ - if (unlikely(srp_rsp.srp.rsp.opcode != SRP_RSP)) { - if (printk_ratelimit()) - sdev_printk(KERN_WARNING, cmd->device, "reset bad SRP RSP type %d\n", - srp_rsp.srp.rsp.opcode); - return FAILED; - } - - if (srp_rsp.srp.rsp.flags & SRP_RSP_FLAG_RSPVALID) - rsp_rc = *((int *)srp_rsp.srp.rsp.data); - else - rsp_rc = srp_rsp.srp.rsp.status; - - if (rsp_rc) { - if (printk_ratelimit()) - sdev_printk(KERN_WARNING, cmd->device, - "reset code %d for task tag 0x%llx\n", - rsp_rc, tsk_mgmt->task_tag); - return FAILED; - } - - /* We need to find all commands for this LUN that have not yet been - * responded to, and fail them with DID_RESET - */ - spin_lock_irqsave(hostdata->host->host_lock, flags); - list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { - if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) { - if (tmp_evt->cmnd) - tmp_evt->cmnd->result = (DID_RESET << 16); - list_del(&tmp_evt->list); - unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt, - tmp_evt->hostdata->dev); - free_event_struct(&tmp_evt->hostdata->pool, - tmp_evt); - atomic_inc(&hostdata->request_limit); - if (tmp_evt->cmnd_done) - tmp_evt->cmnd_done(tmp_evt->cmnd); - else if (tmp_evt->done) - tmp_evt->done(tmp_evt); - } - } - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - return SUCCESS; -} - -/** - * ibmvscsi_eh_host_reset_handler - Reset the connection to the server - * @cmd: struct scsi_cmnd having problems -*/ -static int ibmvscsi_eh_host_reset_handler(struct scsi_cmnd *cmd) -{ - unsigned long wait_switch = 0; - struct ibmvscsi_host_data *hostdata = shost_priv(cmd->device->host); - - dev_err(hostdata->dev, "Resetting connection due to error recovery\n"); - - ibmvscsi_reset_host(hostdata); - - for (wait_switch = jiffies + (init_timeout * HZ); - time_before(jiffies, wait_switch) && - atomic_read(&hostdata->request_limit) < 2;) { - - msleep(10); - } - - if (atomic_read(&hostdata->request_limit) <= 0) - return FAILED; - - return SUCCESS; -} - -/** - * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ - * @crq: Command/Response queue - * @hostdata: ibmvscsi_host_data of host - * -*/ -void ibmvscsi_handle_crq(struct viosrp_crq *crq, - struct ibmvscsi_host_data *hostdata) -{ - long rc; - unsigned long flags; - struct srp_event_struct *evt_struct = - (struct srp_event_struct *)crq->IU_data_ptr; - switch (crq->valid) { - case 0xC0: /* initialization */ - switch (crq->format) { - case 0x01: /* Initialization message */ - dev_info(hostdata->dev, "partner initialized\n"); - /* Send back a response */ - if ((rc = ibmvscsi_ops->send_crq(hostdata, - 0xC002000000000000LL, 0)) == 0) { - /* Now login */ - init_adapter(hostdata); - } else { - dev_err(hostdata->dev, "Unable to send init rsp. rc=%ld\n", rc); - } - - break; - case 0x02: /* Initialization response */ - dev_info(hostdata->dev, "partner initialization complete\n"); - - /* Now login */ - init_adapter(hostdata); - break; - default: - dev_err(hostdata->dev, "unknown crq message type: %d\n", crq->format); - } - return; - case 0xFF: /* Hypervisor telling us the connection is closed */ - scsi_block_requests(hostdata->host); - atomic_set(&hostdata->request_limit, 0); - if (crq->format == 0x06) { - /* We need to re-setup the interpartition connection */ - dev_info(hostdata->dev, "Re-enabling adapter!\n"); - hostdata->client_migrated = 1; - hostdata->reenable_crq = 1; - purge_requests(hostdata, DID_REQUEUE); - wake_up(&hostdata->work_wait_q); - } else { - dev_err(hostdata->dev, "Virtual adapter failed rc %d!\n", - crq->format); - ibmvscsi_reset_host(hostdata); - } - return; - case 0x80: /* real payload */ - break; - default: - dev_err(hostdata->dev, "got an invalid message type 0x%02x\n", - crq->valid); - return; - } - - /* The only kind of payload CRQs we should get are responses to - * things we send. Make sure this response is to something we - * actually sent - */ - if (!valid_event_struct(&hostdata->pool, evt_struct)) { - dev_err(hostdata->dev, "returned correlation_token 0x%p is invalid!\n", - (void *)crq->IU_data_ptr); - return; - } - - if (atomic_read(&evt_struct->free)) { - dev_err(hostdata->dev, "received duplicate correlation_token 0x%p!\n", - (void *)crq->IU_data_ptr); - return; - } - - if (crq->format == VIOSRP_SRP_FORMAT) - atomic_add(evt_struct->xfer_iu->srp.rsp.req_lim_delta, - &hostdata->request_limit); - - del_timer(&evt_struct->timer); - - if ((crq->status != VIOSRP_OK && crq->status != VIOSRP_OK2) && evt_struct->cmnd) - evt_struct->cmnd->result = DID_ERROR << 16; - if (evt_struct->done) - evt_struct->done(evt_struct); - else - dev_err(hostdata->dev, "returned done() is NULL; not running it!\n"); - - /* - * Lock the host_lock before messing with these structures, since we - * are running in a task context - */ - spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags); - list_del(&evt_struct->list); - free_event_struct(&evt_struct->hostdata->pool, evt_struct); - spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags); -} - -/** - * ibmvscsi_get_host_config: Send the command to the server to get host - * configuration data. The data is opaque to us. - */ -static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata, - unsigned char *buffer, int length) -{ - struct viosrp_host_config *host_config; - struct srp_event_struct *evt_struct; - unsigned long flags; - dma_addr_t addr; - int rc; - - evt_struct = get_event_struct(&hostdata->pool); - if (!evt_struct) { - dev_err(hostdata->dev, "couldn't allocate event for HOST_CONFIG!\n"); - return -1; - } - - init_event_struct(evt_struct, - sync_completion, - VIOSRP_MAD_FORMAT, - info_timeout); - - host_config = &evt_struct->iu.mad.host_config; - - /* Set up a lun reset SRP command */ - memset(host_config, 0x00, sizeof(*host_config)); - host_config->common.type = VIOSRP_HOST_CONFIG_TYPE; - host_config->common.length = length; - host_config->buffer = addr = dma_map_single(hostdata->dev, buffer, - length, - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(hostdata->dev, host_config->buffer)) { - if (!firmware_has_feature(FW_FEATURE_CMO)) - dev_err(hostdata->dev, - "dma_mapping error getting host config\n"); - free_event_struct(&hostdata->pool, evt_struct); - return -1; - } - - init_completion(&evt_struct->comp); - spin_lock_irqsave(hostdata->host->host_lock, flags); - rc = ibmvscsi_send_srp_event(evt_struct, hostdata, info_timeout * 2); - spin_unlock_irqrestore(hostdata->host->host_lock, flags); - if (rc == 0) - wait_for_completion(&evt_struct->comp); - dma_unmap_single(hostdata->dev, addr, length, DMA_BIDIRECTIONAL); - - return rc; -} - -/** - * ibmvscsi_slave_configure: Set the "allow_restart" flag for each disk. - * @sdev: struct scsi_device device to configure - * - * Enable allow_restart for a device if it is a disk. Adjust the - * queue_depth here also as is required by the documentation for - * struct scsi_host_template. - */ -static int ibmvscsi_slave_configure(struct scsi_device *sdev) -{ - struct Scsi_Host *shost = sdev->host; - unsigned long lock_flags = 0; - - spin_lock_irqsave(shost->host_lock, lock_flags); - if (sdev->type == TYPE_DISK) { - sdev->allow_restart = 1; - blk_queue_rq_timeout(sdev->request_queue, 120 * HZ); - } - scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun); - spin_unlock_irqrestore(shost->host_lock, lock_flags); - return 0; -} - -/** - * ibmvscsi_change_queue_depth - Change the device's queue depth - * @sdev: scsi device struct - * @qdepth: depth to set - * @reason: calling context - * - * Return value: - * actual depth set - **/ -static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN) - qdepth = IBMVSCSI_MAX_CMDS_PER_LUN; - - scsi_adjust_queue_depth(sdev, 0, qdepth); - return sdev->queue_depth; -} - -/* ------------------------------------------------------------ - * sysfs attributes - */ -static ssize_t show_host_vhost_loc(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvscsi_host_data *hostdata = shost_priv(shost); - int len; - - len = snprintf(buf, sizeof(hostdata->caps.loc), "%s\n", - hostdata->caps.loc); - return len; -} - -static struct device_attribute ibmvscsi_host_vhost_loc = { - .attr = { - .name = "vhost_loc", - .mode = S_IRUGO, - }, - .show = show_host_vhost_loc, -}; - -static ssize_t show_host_vhost_name(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvscsi_host_data *hostdata = shost_priv(shost); - int len; - - len = snprintf(buf, sizeof(hostdata->caps.name), "%s\n", - hostdata->caps.name); - return len; -} - -static struct device_attribute ibmvscsi_host_vhost_name = { - .attr = { - .name = "vhost_name", - .mode = S_IRUGO, - }, - .show = show_host_vhost_name, -}; - -static ssize_t show_host_srp_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvscsi_host_data *hostdata = shost_priv(shost); - int len; - - len = snprintf(buf, PAGE_SIZE, "%s\n", - hostdata->madapter_info.srp_version); - return len; -} - -static struct device_attribute ibmvscsi_host_srp_version = { - .attr = { - .name = "srp_version", - .mode = S_IRUGO, - }, - .show = show_host_srp_version, -}; - -static ssize_t show_host_partition_name(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvscsi_host_data *hostdata = shost_priv(shost); - int len; - - len = snprintf(buf, PAGE_SIZE, "%s\n", - hostdata->madapter_info.partition_name); - return len; -} - -static struct device_attribute ibmvscsi_host_partition_name = { - .attr = { - .name = "partition_name", - .mode = S_IRUGO, - }, - .show = show_host_partition_name, -}; - -static ssize_t show_host_partition_number(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvscsi_host_data *hostdata = shost_priv(shost); - int len; - - len = snprintf(buf, PAGE_SIZE, "%d\n", - hostdata->madapter_info.partition_number); - return len; -} - -static struct device_attribute ibmvscsi_host_partition_number = { - .attr = { - .name = "partition_number", - .mode = S_IRUGO, - }, - .show = show_host_partition_number, -}; - -static ssize_t show_host_mad_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvscsi_host_data *hostdata = shost_priv(shost); - int len; - - len = snprintf(buf, PAGE_SIZE, "%d\n", - hostdata->madapter_info.mad_version); - return len; -} - -static struct device_attribute ibmvscsi_host_mad_version = { - .attr = { - .name = "mad_version", - .mode = S_IRUGO, - }, - .show = show_host_mad_version, -}; - -static ssize_t show_host_os_type(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvscsi_host_data *hostdata = shost_priv(shost); - int len; - - len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type); - return len; -} - -static struct device_attribute ibmvscsi_host_os_type = { - .attr = { - .name = "os_type", - .mode = S_IRUGO, - }, - .show = show_host_os_type, -}; - -static ssize_t show_host_config(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ibmvscsi_host_data *hostdata = shost_priv(shost); - - /* returns null-terminated host config data */ - if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0) - return strlen(buf); - else - return 0; -} - -static struct device_attribute ibmvscsi_host_config = { - .attr = { - .name = "config", - .mode = S_IRUGO, - }, - .show = show_host_config, -}; - -static struct device_attribute *ibmvscsi_attrs[] = { - &ibmvscsi_host_vhost_loc, - &ibmvscsi_host_vhost_name, - &ibmvscsi_host_srp_version, - &ibmvscsi_host_partition_name, - &ibmvscsi_host_partition_number, - &ibmvscsi_host_mad_version, - &ibmvscsi_host_os_type, - &ibmvscsi_host_config, - NULL -}; - -/* ------------------------------------------------------------ - * SCSI driver registration - */ -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION, - .proc_name = "ibmvscsi", - .queuecommand = ibmvscsi_queuecommand, - .eh_abort_handler = ibmvscsi_eh_abort_handler, - .eh_device_reset_handler = ibmvscsi_eh_device_reset_handler, - .eh_host_reset_handler = ibmvscsi_eh_host_reset_handler, - .slave_configure = ibmvscsi_slave_configure, - .change_queue_depth = ibmvscsi_change_queue_depth, - .cmd_per_lun = IBMVSCSI_CMDS_PER_LUN_DEFAULT, - .can_queue = IBMVSCSI_MAX_REQUESTS_DEFAULT, - .this_id = -1, - .sg_tablesize = SG_ALL, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = ibmvscsi_attrs, -}; - -/** - * ibmvscsi_get_desired_dma - Calculate IO memory desired by the driver - * - * @vdev: struct vio_dev for the device whose desired IO mem is to be returned - * - * Return value: - * Number of bytes of IO data the driver will need to perform well. - */ -static unsigned long ibmvscsi_get_desired_dma(struct vio_dev *vdev) -{ - /* iu_storage data allocated in initialize_event_pool */ - unsigned long desired_io = max_events * sizeof(union viosrp_iu); - - /* add io space for sg data */ - desired_io += (IBMVSCSI_MAX_SECTORS_DEFAULT * 512 * - IBMVSCSI_CMDS_PER_LUN_DEFAULT); - - return desired_io; -} - -static void ibmvscsi_do_work(struct ibmvscsi_host_data *hostdata) -{ - int rc; - char *action = "reset"; - - if (hostdata->reset_crq) { - smp_rmb(); - hostdata->reset_crq = 0; - - rc = ibmvscsi_ops->reset_crq_queue(&hostdata->queue, hostdata); - if (!rc) - rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0); - vio_enable_interrupts(to_vio_dev(hostdata->dev)); - } else if (hostdata->reenable_crq) { - smp_rmb(); - action = "enable"; - rc = ibmvscsi_ops->reenable_crq_queue(&hostdata->queue, hostdata); - hostdata->reenable_crq = 0; - if (!rc) - rc = ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0); - } else - return; - - if (rc) { - atomic_set(&hostdata->request_limit, -1); - dev_err(hostdata->dev, "error after %s\n", action); - } - - scsi_unblock_requests(hostdata->host); -} - -static int ibmvscsi_work_to_do(struct ibmvscsi_host_data *hostdata) -{ - if (kthread_should_stop()) - return 1; - else if (hostdata->reset_crq) { - smp_rmb(); - return 1; - } else if (hostdata->reenable_crq) { - smp_rmb(); - return 1; - } - - return 0; -} - -static int ibmvscsi_work(void *data) -{ - struct ibmvscsi_host_data *hostdata = data; - int rc; - - set_user_nice(current, -20); - - while (1) { - rc = wait_event_interruptible(hostdata->work_wait_q, - ibmvscsi_work_to_do(hostdata)); - - BUG_ON(rc); - - if (kthread_should_stop()) - break; - - ibmvscsi_do_work(hostdata); - } - - return 0; -} - -/** - * Called by bus code for each adapter - */ -static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) -{ - struct ibmvscsi_host_data *hostdata; - struct Scsi_Host *host; - struct device *dev = &vdev->dev; - struct srp_rport_identifiers ids; - struct srp_rport *rport; - unsigned long wait_switch = 0; - int rc; - - dev_set_drvdata(&vdev->dev, NULL); - - host = scsi_host_alloc(&driver_template, sizeof(*hostdata)); - if (!host) { - dev_err(&vdev->dev, "couldn't allocate host data\n"); - goto scsi_host_alloc_failed; - } - - host->transportt = ibmvscsi_transport_template; - hostdata = shost_priv(host); - memset(hostdata, 0x00, sizeof(*hostdata)); - INIT_LIST_HEAD(&hostdata->sent); - init_waitqueue_head(&hostdata->work_wait_q); - hostdata->host = host; - hostdata->dev = dev; - atomic_set(&hostdata->request_limit, -1); - hostdata->host->max_sectors = IBMVSCSI_MAX_SECTORS_DEFAULT; - - if (map_persist_bufs(hostdata)) { - dev_err(&vdev->dev, "couldn't map persistent buffers\n"); - goto persist_bufs_failed; - } - - hostdata->work_thread = kthread_run(ibmvscsi_work, hostdata, "%s_%d", - "ibmvscsi", host->host_no); - - if (IS_ERR(hostdata->work_thread)) { - dev_err(&vdev->dev, "couldn't initialize kthread. rc=%ld\n", - PTR_ERR(hostdata->work_thread)); - goto init_crq_failed; - } - - rc = ibmvscsi_ops->init_crq_queue(&hostdata->queue, hostdata, max_events); - if (rc != 0 && rc != H_RESOURCE) { - dev_err(&vdev->dev, "couldn't initialize crq. rc=%d\n", rc); - goto kill_kthread; - } - if (initialize_event_pool(&hostdata->pool, max_events, hostdata) != 0) { - dev_err(&vdev->dev, "couldn't initialize event pool\n"); - goto init_pool_failed; - } - - host->max_lun = 8; - host->max_id = max_id; - host->max_channel = max_channel; - host->max_cmd_len = 16; - - if (scsi_add_host(hostdata->host, hostdata->dev)) - goto add_host_failed; - - /* we don't have a proper target_port_id so let's use the fake one */ - memcpy(ids.port_id, hostdata->madapter_info.partition_name, - sizeof(ids.port_id)); - ids.roles = SRP_RPORT_ROLE_TARGET; - rport = srp_rport_add(host, &ids); - if (IS_ERR(rport)) - goto add_srp_port_failed; - - /* Try to send an initialization message. Note that this is allowed - * to fail if the other end is not acive. In that case we don't - * want to scan - */ - if (ibmvscsi_ops->send_crq(hostdata, 0xC001000000000000LL, 0) == 0 - || rc == H_RESOURCE) { - /* - * Wait around max init_timeout secs for the adapter to finish - * initializing. When we are done initializing, we will have a - * valid request_limit. We don't want Linux scanning before - * we are ready. - */ - for (wait_switch = jiffies + (init_timeout * HZ); - time_before(jiffies, wait_switch) && - atomic_read(&hostdata->request_limit) < 2;) { - - msleep(10); - } - - /* if we now have a valid request_limit, initiate a scan */ - if (atomic_read(&hostdata->request_limit) > 0) - scsi_scan_host(host); - } - - dev_set_drvdata(&vdev->dev, hostdata); - return 0; - - add_srp_port_failed: - scsi_remove_host(hostdata->host); - add_host_failed: - release_event_pool(&hostdata->pool, hostdata); - init_pool_failed: - ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, max_events); - kill_kthread: - kthread_stop(hostdata->work_thread); - init_crq_failed: - unmap_persist_bufs(hostdata); - persist_bufs_failed: - scsi_host_put(host); - scsi_host_alloc_failed: - return -1; -} - -static int ibmvscsi_remove(struct vio_dev *vdev) -{ - struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev); - unmap_persist_bufs(hostdata); - release_event_pool(&hostdata->pool, hostdata); - ibmvscsi_ops->release_crq_queue(&hostdata->queue, hostdata, - max_events); - - kthread_stop(hostdata->work_thread); - srp_remove_host(hostdata->host); - scsi_remove_host(hostdata->host); - scsi_host_put(hostdata->host); - - return 0; -} - -/** - * ibmvscsi_resume: Resume from suspend - * @dev: device struct - * - * We may have lost an interrupt across suspend/resume, so kick the - * interrupt handler - */ -static int ibmvscsi_resume(struct device *dev) -{ - struct ibmvscsi_host_data *hostdata = dev_get_drvdata(dev); - return ibmvscsi_ops->resume(hostdata); -} - -/** - * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we - * support. - */ -static struct vio_device_id ibmvscsi_device_table[] __devinitdata = { - {"vscsi", "IBM,v-scsi"}, - { "", "" } -}; -MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table); - -static struct dev_pm_ops ibmvscsi_pm_ops = { - .resume = ibmvscsi_resume -}; - -static struct vio_driver ibmvscsi_driver = { - .id_table = ibmvscsi_device_table, - .probe = ibmvscsi_probe, - .remove = ibmvscsi_remove, - .get_desired_dma = ibmvscsi_get_desired_dma, - .name = "ibmvscsi", - .pm = &ibmvscsi_pm_ops, -}; - -static struct srp_function_template ibmvscsi_transport_functions = { -}; - -int __init ibmvscsi_module_init(void) -{ - int ret; - - /* Ensure we have two requests to do error recovery */ - driver_template.can_queue = max_requests; - max_events = max_requests + 2; - - if (firmware_has_feature(FW_FEATURE_VIO)) - ibmvscsi_ops = &rpavscsi_ops; - else - return -ENODEV; - - ibmvscsi_transport_template = - srp_attach_transport(&ibmvscsi_transport_functions); - if (!ibmvscsi_transport_template) - return -ENOMEM; - - ret = vio_register_driver(&ibmvscsi_driver); - if (ret) - srp_release_transport(ibmvscsi_transport_template); - return ret; -} - -void __exit ibmvscsi_module_exit(void) -{ - vio_unregister_driver(&ibmvscsi_driver); - srp_release_transport(ibmvscsi_transport_template); -} - -module_init(ibmvscsi_module_init); -module_exit(ibmvscsi_module_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.h b/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.h deleted file mode 100644 index c503e177..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvscsi.h +++ /dev/null @@ -1,132 +0,0 @@ -/* ------------------------------------------------------------ - * ibmvscsi.h - * (C) Copyright IBM Corporation 1994, 2003 - * Authors: Colin DeVilbiss (devilbis@us.ibm.com) - * Santiago Leon (santil@us.ibm.com) - * Dave Boutcher (sleddog@us.ibm.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - * ------------------------------------------------------------ - * Emulation of a SCSI host adapter for Virtual I/O devices - * - * This driver allows the Linux SCSI peripheral drivers to directly - * access devices in the hosting partition, either on an iSeries - * hypervisor system or a converged hypervisor system. - */ -#ifndef IBMVSCSI_H -#define IBMVSCSI_H -#include -#include -#include -#include -#include "viosrp.h" - -struct scsi_cmnd; -struct Scsi_Host; - -/* Number of indirect bufs...the list of these has to fit in the - * additional data of the srp_cmd struct along with the indirect - * descriptor - */ -#define MAX_INDIRECT_BUFS 10 - -#define IBMVSCSI_MAX_REQUESTS_DEFAULT 100 -#define IBMVSCSI_CMDS_PER_LUN_DEFAULT 16 -#define IBMVSCSI_MAX_SECTORS_DEFAULT 256 /* 32 * 8 = default max I/O 32 pages */ -#define IBMVSCSI_MAX_CMDS_PER_LUN 64 - -/* ------------------------------------------------------------ - * Data Structures - */ -/* an RPA command/response transport queue */ -struct crq_queue { - struct viosrp_crq *msgs; - int size, cur; - dma_addr_t msg_token; - spinlock_t lock; -}; - -/* a unit of work for the hosting partition */ -struct srp_event_struct { - union viosrp_iu *xfer_iu; - struct scsi_cmnd *cmnd; - struct list_head list; - void (*done) (struct srp_event_struct *); - struct viosrp_crq crq; - struct ibmvscsi_host_data *hostdata; - atomic_t free; - union viosrp_iu iu; - void (*cmnd_done) (struct scsi_cmnd *); - struct completion comp; - struct timer_list timer; - union viosrp_iu *sync_srp; - struct srp_direct_buf *ext_list; - dma_addr_t ext_list_token; -}; - -/* a pool of event structs for use */ -struct event_pool { - struct srp_event_struct *events; - u32 size; - int next; - union viosrp_iu *iu_storage; - dma_addr_t iu_token; -}; - -/* all driver data associated with a host adapter */ -struct ibmvscsi_host_data { - atomic_t request_limit; - int client_migrated; - int reset_crq; - int reenable_crq; - struct device *dev; - struct event_pool pool; - struct crq_queue queue; - struct tasklet_struct srp_task; - struct list_head sent; - struct Scsi_Host *host; - struct task_struct *work_thread; - wait_queue_head_t work_wait_q; - struct mad_adapter_info_data madapter_info; - struct capabilities caps; - dma_addr_t caps_addr; - dma_addr_t adapter_info_addr; -}; - -/* routines for managing a command/response queue */ -void ibmvscsi_handle_crq(struct viosrp_crq *crq, - struct ibmvscsi_host_data *hostdata); - -struct ibmvscsi_ops { - int (*init_crq_queue)(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests); - void (*release_crq_queue)(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests); - int (*reset_crq_queue)(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata); - int (*reenable_crq_queue)(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata); - int (*send_crq)(struct ibmvscsi_host_data *hostdata, - u64 word1, u64 word2); - int (*resume) (struct ibmvscsi_host_data *hostdata); -}; - -extern struct ibmvscsi_ops rpavscsi_ops; - -#endif /* IBMVSCSI_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvstgt.c b/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvstgt.c deleted file mode 100644 index aa7ed81e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/ibmvstgt.c +++ /dev/null @@ -1,1001 +0,0 @@ -/* - * IBM eServer i/pSeries Virtual SCSI Target Driver - * Copyright (C) 2003-2005 Dave Boutcher (boutcher@us.ibm.com) IBM Corp. - * Santiago Leon (santil@us.ibm.com) IBM Corp. - * Linda Xie (lxie@us.ibm.com) IBM Corp. - * - * Copyright (C) 2005-2006 FUJITA Tomonori - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ibmvscsi.h" - -#define INITIAL_SRP_LIMIT 16 -#define DEFAULT_MAX_SECTORS 256 - -#define TGT_NAME "ibmvstgt" - -/* - * Hypervisor calls. - */ -#define h_copy_rdma(l, sa, sb, da, db) \ - plpar_hcall_norets(H_COPY_RDMA, l, sa, sb, da, db) -#define h_send_crq(ua, l, h) \ - plpar_hcall_norets(H_SEND_CRQ, ua, l, h) -#define h_reg_crq(ua, tok, sz)\ - plpar_hcall_norets(H_REG_CRQ, ua, tok, sz); -#define h_free_crq(ua) \ - plpar_hcall_norets(H_FREE_CRQ, ua); - -/* tmp - will replace with SCSI logging stuff */ -#define eprintk(fmt, args...) \ -do { \ - printk("%s(%d) " fmt, __func__, __LINE__, ##args); \ -} while (0) -/* #define dprintk eprintk */ -#define dprintk(fmt, args...) - -struct vio_port { - struct vio_dev *dma_dev; - - struct crq_queue crq_queue; - struct work_struct crq_work; - - unsigned long liobn; - unsigned long riobn; - struct srp_target *target; - - struct srp_rport *rport; -}; - -static struct workqueue_struct *vtgtd; -static struct scsi_transport_template *ibmvstgt_transport_template; - -/* - * These are fixed for the system and come from the Open Firmware device tree. - * We just store them here to save getting them every time. - */ -static char system_id[64] = ""; -static char partition_name[97] = "UNKNOWN"; -static unsigned int partition_number = -1; - -static struct vio_port *target_to_port(struct srp_target *target) -{ - return (struct vio_port *) target->ldata; -} - -static inline union viosrp_iu *vio_iu(struct iu_entry *iue) -{ - return (union viosrp_iu *) (iue->sbuf->buf); -} - -static int send_iu(struct iu_entry *iue, uint64_t length, uint8_t format) -{ - struct srp_target *target = iue->target; - struct vio_port *vport = target_to_port(target); - long rc, rc1; - union { - struct viosrp_crq cooked; - uint64_t raw[2]; - } crq; - - /* First copy the SRP */ - rc = h_copy_rdma(length, vport->liobn, iue->sbuf->dma, - vport->riobn, iue->remote_token); - - if (rc) - eprintk("Error %ld transferring data\n", rc); - - crq.cooked.valid = 0x80; - crq.cooked.format = format; - crq.cooked.reserved = 0x00; - crq.cooked.timeout = 0x00; - crq.cooked.IU_length = length; - crq.cooked.IU_data_ptr = vio_iu(iue)->srp.rsp.tag; - - if (rc == 0) - crq.cooked.status = 0x99; /* Just needs to be non-zero */ - else - crq.cooked.status = 0x00; - - rc1 = h_send_crq(vport->dma_dev->unit_address, crq.raw[0], crq.raw[1]); - - if (rc1) { - eprintk("%ld sending response\n", rc1); - return rc1; - } - - return rc; -} - -#define SRP_RSP_SENSE_DATA_LEN 18 - -static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc, - unsigned char status, unsigned char asc) -{ - union viosrp_iu *iu = vio_iu(iue); - uint64_t tag = iu->srp.rsp.tag; - - /* If the linked bit is on and status is good */ - if (test_bit(V_LINKED, &iue->flags) && (status == NO_SENSE)) - status = 0x10; - - memset(iu, 0, sizeof(struct srp_rsp)); - iu->srp.rsp.opcode = SRP_RSP; - iu->srp.rsp.req_lim_delta = 1; - iu->srp.rsp.tag = tag; - - if (test_bit(V_DIOVER, &iue->flags)) - iu->srp.rsp.flags |= SRP_RSP_FLAG_DIOVER; - - iu->srp.rsp.data_in_res_cnt = 0; - iu->srp.rsp.data_out_res_cnt = 0; - - iu->srp.rsp.flags &= ~SRP_RSP_FLAG_RSPVALID; - - iu->srp.rsp.resp_data_len = 0; - iu->srp.rsp.status = status; - if (status) { - uint8_t *sense = iu->srp.rsp.data; - - if (sc) { - iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; - iu->srp.rsp.sense_data_len = SCSI_SENSE_BUFFERSIZE; - memcpy(sense, sc->sense_buffer, SCSI_SENSE_BUFFERSIZE); - } else { - iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION; - iu->srp.rsp.flags |= SRP_RSP_FLAG_SNSVALID; - iu->srp.rsp.sense_data_len = SRP_RSP_SENSE_DATA_LEN; - - /* Valid bit and 'current errors' */ - sense[0] = (0x1 << 7 | 0x70); - /* Sense key */ - sense[2] = status; - /* Additional sense length */ - sense[7] = 0xa; /* 10 bytes */ - /* Additional sense code */ - sense[12] = asc; - } - } - - send_iu(iue, sizeof(iu->srp.rsp) + SRP_RSP_SENSE_DATA_LEN, - VIOSRP_SRP_FORMAT); - - return 0; -} - -static void handle_cmd_queue(struct srp_target *target) -{ - struct Scsi_Host *shost = target->shost; - struct srp_rport *rport = target_to_port(target)->rport; - struct iu_entry *iue; - struct srp_cmd *cmd; - unsigned long flags; - int err; - -retry: - spin_lock_irqsave(&target->lock, flags); - - list_for_each_entry(iue, &target->cmd_queue, ilist) { - if (!test_and_set_bit(V_FLYING, &iue->flags)) { - spin_unlock_irqrestore(&target->lock, flags); - cmd = iue->sbuf->buf; - err = srp_cmd_queue(shost, cmd, iue, - (unsigned long)rport, 0); - if (err) { - eprintk("cannot queue cmd %p %d\n", cmd, err); - srp_iu_put(iue); - } - goto retry; - } - } - - spin_unlock_irqrestore(&target->lock, flags); -} - -static int ibmvstgt_rdma(struct scsi_cmnd *sc, struct scatterlist *sg, int nsg, - struct srp_direct_buf *md, int nmd, - enum dma_data_direction dir, unsigned int rest) -{ - struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; - struct srp_target *target = iue->target; - struct vio_port *vport = target_to_port(target); - dma_addr_t token; - long err; - unsigned int done = 0; - int i, sidx, soff; - - sidx = soff = 0; - token = sg_dma_address(sg + sidx); - - for (i = 0; i < nmd && rest; i++) { - unsigned int mdone, mlen; - - mlen = min(rest, md[i].len); - for (mdone = 0; mlen;) { - int slen = min(sg_dma_len(sg + sidx) - soff, mlen); - - if (dir == DMA_TO_DEVICE) - err = h_copy_rdma(slen, - vport->riobn, - md[i].va + mdone, - vport->liobn, - token + soff); - else - err = h_copy_rdma(slen, - vport->liobn, - token + soff, - vport->riobn, - md[i].va + mdone); - - if (err != H_SUCCESS) { - eprintk("rdma error %d %d %ld\n", dir, slen, err); - return -EIO; - } - - mlen -= slen; - mdone += slen; - soff += slen; - done += slen; - - if (soff == sg_dma_len(sg + sidx)) { - sidx++; - soff = 0; - token = sg_dma_address(sg + sidx); - - if (sidx > nsg) { - eprintk("out of sg %p %d %d\n", - iue, sidx, nsg); - return -EIO; - } - } - }; - - rest -= mlen; - } - return 0; -} - -static int ibmvstgt_cmd_done(struct scsi_cmnd *sc, - void (*done)(struct scsi_cmnd *)) -{ - unsigned long flags; - struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; - struct srp_target *target = iue->target; - int err = 0; - - dprintk("%p %p %x %u\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0], - scsi_sg_count(sc)); - - if (scsi_sg_count(sc)) - err = srp_transfer_data(sc, &vio_iu(iue)->srp.cmd, ibmvstgt_rdma, 1, 1); - - spin_lock_irqsave(&target->lock, flags); - list_del(&iue->ilist); - spin_unlock_irqrestore(&target->lock, flags); - - if (err|| sc->result != SAM_STAT_GOOD) { - eprintk("operation failed %p %d %x\n", - iue, sc->result, vio_iu(iue)->srp.cmd.cdb[0]); - send_rsp(iue, sc, HARDWARE_ERROR, 0x00); - } else - send_rsp(iue, sc, NO_SENSE, 0x00); - - done(sc); - srp_iu_put(iue); - return 0; -} - -int send_adapter_info(struct iu_entry *iue, - dma_addr_t remote_buffer, uint16_t length) -{ - struct srp_target *target = iue->target; - struct vio_port *vport = target_to_port(target); - struct Scsi_Host *shost = target->shost; - dma_addr_t data_token; - struct mad_adapter_info_data *info; - int err; - - info = dma_alloc_coherent(target->dev, sizeof(*info), &data_token, - GFP_KERNEL); - if (!info) { - eprintk("bad dma_alloc_coherent %p\n", target); - return 1; - } - - /* Get remote info */ - err = h_copy_rdma(sizeof(*info), vport->riobn, remote_buffer, - vport->liobn, data_token); - if (err == H_SUCCESS) { - dprintk("Client connect: %s (%d)\n", - info->partition_name, info->partition_number); - } - - memset(info, 0, sizeof(*info)); - - strcpy(info->srp_version, "16.a"); - strncpy(info->partition_name, partition_name, - sizeof(info->partition_name)); - info->partition_number = partition_number; - info->mad_version = 1; - info->os_type = 2; - info->port_max_txu[0] = shost->hostt->max_sectors << 9; - - /* Send our info to remote */ - err = h_copy_rdma(sizeof(*info), vport->liobn, data_token, - vport->riobn, remote_buffer); - - dma_free_coherent(target->dev, sizeof(*info), info, data_token); - - if (err != H_SUCCESS) { - eprintk("Error sending adapter info %d\n", err); - return 1; - } - - return 0; -} - -static void process_login(struct iu_entry *iue) -{ - union viosrp_iu *iu = vio_iu(iue); - struct srp_login_rsp *rsp = &iu->srp.login_rsp; - uint64_t tag = iu->srp.rsp.tag; - struct Scsi_Host *shost = iue->target->shost; - struct srp_target *target = host_to_srp_target(shost); - struct vio_port *vport = target_to_port(target); - struct srp_rport_identifiers ids; - - memset(&ids, 0, sizeof(ids)); - sprintf(ids.port_id, "%x", vport->dma_dev->unit_address); - ids.roles = SRP_RPORT_ROLE_INITIATOR; - if (!vport->rport) - vport->rport = srp_rport_add(shost, &ids); - - /* TODO handle case that requested size is wrong and - * buffer format is wrong - */ - memset(iu, 0, sizeof(struct srp_login_rsp)); - rsp->opcode = SRP_LOGIN_RSP; - rsp->req_lim_delta = INITIAL_SRP_LIMIT; - rsp->tag = tag; - rsp->max_it_iu_len = sizeof(union srp_iu); - rsp->max_ti_iu_len = sizeof(union srp_iu); - /* direct and indirect */ - rsp->buf_fmt = SRP_BUF_FORMAT_DIRECT | SRP_BUF_FORMAT_INDIRECT; - - send_iu(iue, sizeof(*rsp), VIOSRP_SRP_FORMAT); -} - -static inline void queue_cmd(struct iu_entry *iue) -{ - struct srp_target *target = iue->target; - unsigned long flags; - - spin_lock_irqsave(&target->lock, flags); - list_add_tail(&iue->ilist, &target->cmd_queue); - spin_unlock_irqrestore(&target->lock, flags); -} - -static int process_tsk_mgmt(struct iu_entry *iue) -{ - union viosrp_iu *iu = vio_iu(iue); - int fn; - - dprintk("%p %u\n", iue, iu->srp.tsk_mgmt.tsk_mgmt_func); - - switch (iu->srp.tsk_mgmt.tsk_mgmt_func) { - case SRP_TSK_ABORT_TASK: - fn = ABORT_TASK; - break; - case SRP_TSK_ABORT_TASK_SET: - fn = ABORT_TASK_SET; - break; - case SRP_TSK_CLEAR_TASK_SET: - fn = CLEAR_TASK_SET; - break; - case SRP_TSK_LUN_RESET: - fn = LOGICAL_UNIT_RESET; - break; - case SRP_TSK_CLEAR_ACA: - fn = CLEAR_ACA; - break; - default: - fn = 0; - } - if (fn) - scsi_tgt_tsk_mgmt_request(iue->target->shost, - (unsigned long)iue->target->shost, - fn, - iu->srp.tsk_mgmt.task_tag, - (struct scsi_lun *) &iu->srp.tsk_mgmt.lun, - iue); - else - send_rsp(iue, NULL, ILLEGAL_REQUEST, 0x20); - - return !fn; -} - -static int process_mad_iu(struct iu_entry *iue) -{ - union viosrp_iu *iu = vio_iu(iue); - struct viosrp_adapter_info *info; - struct viosrp_host_config *conf; - - switch (iu->mad.empty_iu.common.type) { - case VIOSRP_EMPTY_IU_TYPE: - eprintk("%s\n", "Unsupported EMPTY MAD IU"); - break; - case VIOSRP_ERROR_LOG_TYPE: - eprintk("%s\n", "Unsupported ERROR LOG MAD IU"); - iu->mad.error_log.common.status = 1; - send_iu(iue, sizeof(iu->mad.error_log), VIOSRP_MAD_FORMAT); - break; - case VIOSRP_ADAPTER_INFO_TYPE: - info = &iu->mad.adapter_info; - info->common.status = send_adapter_info(iue, info->buffer, - info->common.length); - send_iu(iue, sizeof(*info), VIOSRP_MAD_FORMAT); - break; - case VIOSRP_HOST_CONFIG_TYPE: - conf = &iu->mad.host_config; - conf->common.status = 1; - send_iu(iue, sizeof(*conf), VIOSRP_MAD_FORMAT); - break; - default: - eprintk("Unknown type %u\n", iu->srp.rsp.opcode); - } - - return 1; -} - -static int process_srp_iu(struct iu_entry *iue) -{ - union viosrp_iu *iu = vio_iu(iue); - int done = 1; - u8 opcode = iu->srp.rsp.opcode; - - switch (opcode) { - case SRP_LOGIN_REQ: - process_login(iue); - break; - case SRP_TSK_MGMT: - done = process_tsk_mgmt(iue); - break; - case SRP_CMD: - queue_cmd(iue); - done = 0; - break; - case SRP_LOGIN_RSP: - case SRP_I_LOGOUT: - case SRP_T_LOGOUT: - case SRP_RSP: - case SRP_CRED_REQ: - case SRP_CRED_RSP: - case SRP_AER_REQ: - case SRP_AER_RSP: - eprintk("Unsupported type %u\n", opcode); - break; - default: - eprintk("Unknown type %u\n", opcode); - } - - return done; -} - -static void process_iu(struct viosrp_crq *crq, struct srp_target *target) -{ - struct vio_port *vport = target_to_port(target); - struct iu_entry *iue; - long err; - int done = 1; - - iue = srp_iu_get(target); - if (!iue) { - eprintk("Error getting IU from pool, %p\n", target); - return; - } - - iue->remote_token = crq->IU_data_ptr; - - err = h_copy_rdma(crq->IU_length, vport->riobn, - iue->remote_token, vport->liobn, iue->sbuf->dma); - - if (err != H_SUCCESS) { - eprintk("%ld transferring data error %p\n", err, iue); - goto out; - } - - if (crq->format == VIOSRP_MAD_FORMAT) - done = process_mad_iu(iue); - else - done = process_srp_iu(iue); -out: - if (done) - srp_iu_put(iue); -} - -static irqreturn_t ibmvstgt_interrupt(int dummy, void *data) -{ - struct srp_target *target = data; - struct vio_port *vport = target_to_port(target); - - vio_disable_interrupts(vport->dma_dev); - queue_work(vtgtd, &vport->crq_work); - - return IRQ_HANDLED; -} - -static int crq_queue_create(struct crq_queue *queue, struct srp_target *target) -{ - int err; - struct vio_port *vport = target_to_port(target); - - queue->msgs = (struct viosrp_crq *) get_zeroed_page(GFP_KERNEL); - if (!queue->msgs) - goto malloc_failed; - queue->size = PAGE_SIZE / sizeof(*queue->msgs); - - queue->msg_token = dma_map_single(target->dev, queue->msgs, - queue->size * sizeof(*queue->msgs), - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(target->dev, queue->msg_token)) - goto map_failed; - - err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token, - PAGE_SIZE); - - /* If the adapter was left active for some reason (like kexec) - * try freeing and re-registering - */ - if (err == H_RESOURCE) { - do { - err = h_free_crq(vport->dma_dev->unit_address); - } while (err == H_BUSY || H_IS_LONG_BUSY(err)); - - err = h_reg_crq(vport->dma_dev->unit_address, queue->msg_token, - PAGE_SIZE); - } - - if (err != H_SUCCESS && err != 2) { - eprintk("Error 0x%x opening virtual adapter\n", err); - goto reg_crq_failed; - } - - err = request_irq(vport->dma_dev->irq, &ibmvstgt_interrupt, - IRQF_DISABLED, "ibmvstgt", target); - if (err) - goto req_irq_failed; - - vio_enable_interrupts(vport->dma_dev); - - h_send_crq(vport->dma_dev->unit_address, 0xC001000000000000, 0); - - queue->cur = 0; - spin_lock_init(&queue->lock); - - return 0; - -req_irq_failed: - do { - err = h_free_crq(vport->dma_dev->unit_address); - } while (err == H_BUSY || H_IS_LONG_BUSY(err)); - -reg_crq_failed: - dma_unmap_single(target->dev, queue->msg_token, - queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); -map_failed: - free_page((unsigned long) queue->msgs); - -malloc_failed: - return -ENOMEM; -} - -static void crq_queue_destroy(struct srp_target *target) -{ - struct vio_port *vport = target_to_port(target); - struct crq_queue *queue = &vport->crq_queue; - int err; - - free_irq(vport->dma_dev->irq, target); - do { - err = h_free_crq(vport->dma_dev->unit_address); - } while (err == H_BUSY || H_IS_LONG_BUSY(err)); - - dma_unmap_single(target->dev, queue->msg_token, - queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); - - free_page((unsigned long) queue->msgs); -} - -static void process_crq(struct viosrp_crq *crq, struct srp_target *target) -{ - struct vio_port *vport = target_to_port(target); - dprintk("%x %x\n", crq->valid, crq->format); - - switch (crq->valid) { - case 0xC0: - /* initialization */ - switch (crq->format) { - case 0x01: - h_send_crq(vport->dma_dev->unit_address, - 0xC002000000000000, 0); - break; - case 0x02: - break; - default: - eprintk("Unknown format %u\n", crq->format); - } - break; - case 0xFF: - /* transport event */ - break; - case 0x80: - /* real payload */ - switch (crq->format) { - case VIOSRP_SRP_FORMAT: - case VIOSRP_MAD_FORMAT: - process_iu(crq, target); - break; - case VIOSRP_OS400_FORMAT: - case VIOSRP_AIX_FORMAT: - case VIOSRP_LINUX_FORMAT: - case VIOSRP_INLINE_FORMAT: - eprintk("Unsupported format %u\n", crq->format); - break; - default: - eprintk("Unknown format %u\n", crq->format); - } - break; - default: - eprintk("unknown message type 0x%02x!?\n", crq->valid); - } -} - -static inline struct viosrp_crq *next_crq(struct crq_queue *queue) -{ - struct viosrp_crq *crq; - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - crq = &queue->msgs[queue->cur]; - if (crq->valid & 0x80) { - if (++queue->cur == queue->size) - queue->cur = 0; - } else - crq = NULL; - spin_unlock_irqrestore(&queue->lock, flags); - - return crq; -} - -static void handle_crq(struct work_struct *work) -{ - struct vio_port *vport = container_of(work, struct vio_port, crq_work); - struct srp_target *target = vport->target; - struct viosrp_crq *crq; - int done = 0; - - while (!done) { - while ((crq = next_crq(&vport->crq_queue)) != NULL) { - process_crq(crq, target); - crq->valid = 0x00; - } - - vio_enable_interrupts(vport->dma_dev); - - crq = next_crq(&vport->crq_queue); - if (crq) { - vio_disable_interrupts(vport->dma_dev); - process_crq(crq, target); - crq->valid = 0x00; - } else - done = 1; - } - - handle_cmd_queue(target); -} - - -static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc) -{ - unsigned long flags; - struct iu_entry *iue = (struct iu_entry *) sc->SCp.ptr; - struct srp_target *target = iue->target; - - dprintk("%p %p %x\n", iue, target, vio_iu(iue)->srp.cmd.cdb[0]); - - spin_lock_irqsave(&target->lock, flags); - list_del(&iue->ilist); - spin_unlock_irqrestore(&target->lock, flags); - - srp_iu_put(iue); - - return 0; -} - -static int ibmvstgt_tsk_mgmt_response(struct Scsi_Host *shost, - u64 itn_id, u64 mid, int result) -{ - struct iu_entry *iue = (struct iu_entry *) ((void *) mid); - union viosrp_iu *iu = vio_iu(iue); - unsigned char status, asc; - - eprintk("%p %d\n", iue, result); - status = NO_SENSE; - asc = 0; - - switch (iu->srp.tsk_mgmt.tsk_mgmt_func) { - case SRP_TSK_ABORT_TASK: - asc = 0x14; - if (result) - status = ABORTED_COMMAND; - break; - default: - break; - } - - send_rsp(iue, NULL, status, asc); - srp_iu_put(iue); - - return 0; -} - -static int ibmvstgt_it_nexus_response(struct Scsi_Host *shost, u64 itn_id, - int result) -{ - struct srp_target *target = host_to_srp_target(shost); - struct vio_port *vport = target_to_port(target); - - if (result) { - eprintk("%p %d\n", shost, result); - srp_rport_del(vport->rport); - vport->rport = NULL; - } - return 0; -} - -static ssize_t system_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", system_id); -} - -static ssize_t partition_number_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%x\n", partition_number); -} - -static ssize_t unit_address_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct srp_target *target = host_to_srp_target(shost); - struct vio_port *vport = target_to_port(target); - return snprintf(buf, PAGE_SIZE, "%x\n", vport->dma_dev->unit_address); -} - -static DEVICE_ATTR(system_id, S_IRUGO, system_id_show, NULL); -static DEVICE_ATTR(partition_number, S_IRUGO, partition_number_show, NULL); -static DEVICE_ATTR(unit_address, S_IRUGO, unit_address_show, NULL); - -static struct device_attribute *ibmvstgt_attrs[] = { - &dev_attr_system_id, - &dev_attr_partition_number, - &dev_attr_unit_address, - NULL, -}; - -static struct scsi_host_template ibmvstgt_sht = { - .name = TGT_NAME, - .module = THIS_MODULE, - .can_queue = INITIAL_SRP_LIMIT, - .sg_tablesize = SG_ALL, - .use_clustering = DISABLE_CLUSTERING, - .max_sectors = DEFAULT_MAX_SECTORS, - .transfer_response = ibmvstgt_cmd_done, - .eh_abort_handler = ibmvstgt_eh_abort_handler, - .shost_attrs = ibmvstgt_attrs, - .proc_name = TGT_NAME, - .supported_mode = MODE_TARGET, -}; - -static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) -{ - struct Scsi_Host *shost; - struct srp_target *target; - struct vio_port *vport; - unsigned int *dma, dma_size; - int err = -ENOMEM; - - vport = kzalloc(sizeof(struct vio_port), GFP_KERNEL); - if (!vport) - return err; - shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target)); - if (!shost) - goto free_vport; - shost->transportt = ibmvstgt_transport_template; - - target = host_to_srp_target(shost); - target->shost = shost; - vport->dma_dev = dev; - target->ldata = vport; - vport->target = target; - err = srp_target_alloc(target, &dev->dev, INITIAL_SRP_LIMIT, - SRP_MAX_IU_LEN); - if (err) - goto put_host; - - dma = (unsigned int *) vio_get_attribute(dev, "ibm,my-dma-window", - &dma_size); - if (!dma || dma_size != 40) { - eprintk("Couldn't get window property %d\n", dma_size); - err = -EIO; - goto free_srp_target; - } - vport->liobn = dma[0]; - vport->riobn = dma[5]; - - INIT_WORK(&vport->crq_work, handle_crq); - - err = scsi_add_host(shost, target->dev); - if (err) - goto free_srp_target; - - err = scsi_tgt_alloc_queue(shost); - if (err) - goto remove_host; - - err = crq_queue_create(&vport->crq_queue, target); - if (err) - goto free_queue; - - return 0; -free_queue: - scsi_tgt_free_queue(shost); -remove_host: - scsi_remove_host(shost); -free_srp_target: - srp_target_free(target); -put_host: - scsi_host_put(shost); -free_vport: - kfree(vport); - return err; -} - -static int ibmvstgt_remove(struct vio_dev *dev) -{ - struct srp_target *target = dev_get_drvdata(&dev->dev); - struct Scsi_Host *shost = target->shost; - struct vio_port *vport = target->ldata; - - crq_queue_destroy(target); - srp_remove_host(shost); - scsi_remove_host(shost); - scsi_tgt_free_queue(shost); - srp_target_free(target); - kfree(vport); - scsi_host_put(shost); - return 0; -} - -static struct vio_device_id ibmvstgt_device_table[] __devinitdata = { - {"v-scsi-host", "IBM,v-scsi-host"}, - {"",""} -}; - -MODULE_DEVICE_TABLE(vio, ibmvstgt_device_table); - -static struct vio_driver ibmvstgt_driver = { - .id_table = ibmvstgt_device_table, - .probe = ibmvstgt_probe, - .remove = ibmvstgt_remove, - .name = "ibmvscsis", -}; - -static int get_system_info(void) -{ - struct device_node *rootdn; - const char *id, *model, *name; - const unsigned int *num; - - rootdn = of_find_node_by_path("/"); - if (!rootdn) - return -ENOENT; - - model = of_get_property(rootdn, "model", NULL); - id = of_get_property(rootdn, "system-id", NULL); - if (model && id) - snprintf(system_id, sizeof(system_id), "%s-%s", model, id); - - name = of_get_property(rootdn, "ibm,partition-name", NULL); - if (name) - strncpy(partition_name, name, sizeof(partition_name)); - - num = of_get_property(rootdn, "ibm,partition-no", NULL); - if (num) - partition_number = *num; - - of_node_put(rootdn); - return 0; -} - -static struct srp_function_template ibmvstgt_transport_functions = { - .tsk_mgmt_response = ibmvstgt_tsk_mgmt_response, - .it_nexus_response = ibmvstgt_it_nexus_response, -}; - -static int __init ibmvstgt_init(void) -{ - int err = -ENOMEM; - - printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n"); - - ibmvstgt_transport_template = - srp_attach_transport(&ibmvstgt_transport_functions); - if (!ibmvstgt_transport_template) - return err; - - vtgtd = create_workqueue("ibmvtgtd"); - if (!vtgtd) - goto release_transport; - - err = get_system_info(); - if (err) - goto destroy_wq; - - err = vio_register_driver(&ibmvstgt_driver); - if (err) - goto destroy_wq; - - return 0; -destroy_wq: - destroy_workqueue(vtgtd); -release_transport: - srp_release_transport(ibmvstgt_transport_template); - return err; -} - -static void __exit ibmvstgt_exit(void) -{ - printk("Unregister IBM virtual SCSI driver\n"); - - destroy_workqueue(vtgtd); - vio_unregister_driver(&ibmvstgt_driver); - srp_release_transport(ibmvstgt_transport_template); -} - -MODULE_DESCRIPTION("IBM Virtual SCSI Target"); -MODULE_AUTHOR("Santiago Leon"); -MODULE_LICENSE("GPL"); - -module_init(ibmvstgt_init); -module_exit(ibmvstgt_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/rpa_vscsi.c b/ANDROID_3.4.5/drivers/scsi/ibmvscsi/rpa_vscsi.c deleted file mode 100644 index f48ae019..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/rpa_vscsi.c +++ /dev/null @@ -1,368 +0,0 @@ -/* ------------------------------------------------------------ - * rpa_vscsi.c - * (C) Copyright IBM Corporation 1994, 2003 - * Authors: Colin DeVilbiss (devilbis@us.ibm.com) - * Santiago Leon (santil@us.ibm.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - * ------------------------------------------------------------ - * RPA-specific functions of the SCSI host adapter for Virtual I/O devices - * - * This driver allows the Linux SCSI peripheral drivers to directly - * access devices in the hosting partition, either on an iSeries - * hypervisor system or a converged hypervisor system. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "ibmvscsi.h" - -static char partition_name[97] = "UNKNOWN"; -static unsigned int partition_number = -1; - -/* ------------------------------------------------------------ - * Routines for managing the command/response queue - */ -/** - * rpavscsi_handle_event: - Interrupt handler for crq events - * @irq: number of irq to handle, not used - * @dev_instance: ibmvscsi_host_data of host that received interrupt - * - * Disables interrupts and schedules srp_task - * Always returns IRQ_HANDLED - */ -static irqreturn_t rpavscsi_handle_event(int irq, void *dev_instance) -{ - struct ibmvscsi_host_data *hostdata = - (struct ibmvscsi_host_data *)dev_instance; - vio_disable_interrupts(to_vio_dev(hostdata->dev)); - tasklet_schedule(&hostdata->srp_task); - return IRQ_HANDLED; -} - -/** - * release_crq_queue: - Deallocates data and unregisters CRQ - * @queue: crq_queue to initialize and register - * @host_data: ibmvscsi_host_data of host - * - * Frees irq, deallocates a page for messages, unmaps dma, and unregisters - * the crq with the hypervisor. - */ -static void rpavscsi_release_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests) -{ - long rc = 0; - struct vio_dev *vdev = to_vio_dev(hostdata->dev); - free_irq(vdev->irq, (void *)hostdata); - tasklet_kill(&hostdata->srp_task); - do { - if (rc) - msleep(100); - rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); - dma_unmap_single(hostdata->dev, - queue->msg_token, - queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); - free_page((unsigned long)queue->msgs); -} - -/** - * crq_queue_next_crq: - Returns the next entry in message queue - * @queue: crq_queue to use - * - * Returns pointer to next entry in queue, or NULL if there are no new - * entried in the CRQ. - */ -static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue) -{ - struct viosrp_crq *crq; - unsigned long flags; - - spin_lock_irqsave(&queue->lock, flags); - crq = &queue->msgs[queue->cur]; - if (crq->valid & 0x80) { - if (++queue->cur == queue->size) - queue->cur = 0; - } else - crq = NULL; - spin_unlock_irqrestore(&queue->lock, flags); - - return crq; -} - -/** - * rpavscsi_send_crq: - Send a CRQ - * @hostdata: the adapter - * @word1: the first 64 bits of the data - * @word2: the second 64 bits of the data - */ -static int rpavscsi_send_crq(struct ibmvscsi_host_data *hostdata, - u64 word1, u64 word2) -{ - struct vio_dev *vdev = to_vio_dev(hostdata->dev); - - return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2); -} - -/** - * rpavscsi_task: - Process srps asynchronously - * @data: ibmvscsi_host_data of host - */ -static void rpavscsi_task(void *data) -{ - struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data; - struct vio_dev *vdev = to_vio_dev(hostdata->dev); - struct viosrp_crq *crq; - int done = 0; - - while (!done) { - /* Pull all the valid messages off the CRQ */ - while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { - ibmvscsi_handle_crq(crq, hostdata); - crq->valid = 0x00; - } - - vio_enable_interrupts(vdev); - if ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { - vio_disable_interrupts(vdev); - ibmvscsi_handle_crq(crq, hostdata); - crq->valid = 0x00; - } else { - done = 1; - } - } -} - -static void gather_partition_info(void) -{ - struct device_node *rootdn; - - const char *ppartition_name; - const unsigned int *p_number_ptr; - - /* Retrieve information about this partition */ - rootdn = of_find_node_by_path("/"); - if (!rootdn) { - return; - } - - ppartition_name = of_get_property(rootdn, "ibm,partition-name", NULL); - if (ppartition_name) - strncpy(partition_name, ppartition_name, - sizeof(partition_name)); - p_number_ptr = of_get_property(rootdn, "ibm,partition-no", NULL); - if (p_number_ptr) - partition_number = *p_number_ptr; - of_node_put(rootdn); -} - -static void set_adapter_info(struct ibmvscsi_host_data *hostdata) -{ - memset(&hostdata->madapter_info, 0x00, - sizeof(hostdata->madapter_info)); - - dev_info(hostdata->dev, "SRP_VERSION: %s\n", SRP_VERSION); - strcpy(hostdata->madapter_info.srp_version, SRP_VERSION); - - strncpy(hostdata->madapter_info.partition_name, partition_name, - sizeof(hostdata->madapter_info.partition_name)); - - hostdata->madapter_info.partition_number = partition_number; - - hostdata->madapter_info.mad_version = 1; - hostdata->madapter_info.os_type = 2; -} - -/** - * reset_crq_queue: - resets a crq after a failure - * @queue: crq_queue to initialize and register - * @hostdata: ibmvscsi_host_data of host - * - */ -static int rpavscsi_reset_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata) -{ - int rc = 0; - struct vio_dev *vdev = to_vio_dev(hostdata->dev); - - /* Close the CRQ */ - do { - if (rc) - msleep(100); - rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); - - /* Clean out the queue */ - memset(queue->msgs, 0x00, PAGE_SIZE); - queue->cur = 0; - - set_adapter_info(hostdata); - - /* And re-open it again */ - rc = plpar_hcall_norets(H_REG_CRQ, - vdev->unit_address, - queue->msg_token, PAGE_SIZE); - if (rc == 2) { - /* Adapter is good, but other end is not ready */ - dev_warn(hostdata->dev, "Partner adapter not ready\n"); - } else if (rc != 0) { - dev_warn(hostdata->dev, "couldn't register crq--rc 0x%x\n", rc); - } - return rc; -} - -/** - * initialize_crq_queue: - Initializes and registers CRQ with hypervisor - * @queue: crq_queue to initialize and register - * @hostdata: ibmvscsi_host_data of host - * - * Allocates a page for messages, maps it for dma, and registers - * the crq with the hypervisor. - * Returns zero on success. - */ -static int rpavscsi_init_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata, - int max_requests) -{ - int rc; - int retrc; - struct vio_dev *vdev = to_vio_dev(hostdata->dev); - - queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL); - - if (!queue->msgs) - goto malloc_failed; - queue->size = PAGE_SIZE / sizeof(*queue->msgs); - - queue->msg_token = dma_map_single(hostdata->dev, queue->msgs, - queue->size * sizeof(*queue->msgs), - DMA_BIDIRECTIONAL); - - if (dma_mapping_error(hostdata->dev, queue->msg_token)) - goto map_failed; - - gather_partition_info(); - set_adapter_info(hostdata); - - retrc = rc = plpar_hcall_norets(H_REG_CRQ, - vdev->unit_address, - queue->msg_token, PAGE_SIZE); - if (rc == H_RESOURCE) - /* maybe kexecing and resource is busy. try a reset */ - rc = rpavscsi_reset_crq_queue(queue, - hostdata); - - if (rc == 2) { - /* Adapter is good, but other end is not ready */ - dev_warn(hostdata->dev, "Partner adapter not ready\n"); - retrc = 0; - } else if (rc != 0) { - dev_warn(hostdata->dev, "Error %d opening adapter\n", rc); - goto reg_crq_failed; - } - - queue->cur = 0; - spin_lock_init(&queue->lock); - - tasklet_init(&hostdata->srp_task, (void *)rpavscsi_task, - (unsigned long)hostdata); - - if (request_irq(vdev->irq, - rpavscsi_handle_event, - 0, "ibmvscsi", (void *)hostdata) != 0) { - dev_err(hostdata->dev, "couldn't register irq 0x%x\n", - vdev->irq); - goto req_irq_failed; - } - - rc = vio_enable_interrupts(vdev); - if (rc != 0) { - dev_err(hostdata->dev, "Error %d enabling interrupts!!!\n", rc); - goto req_irq_failed; - } - - return retrc; - - req_irq_failed: - tasklet_kill(&hostdata->srp_task); - rc = 0; - do { - if (rc) - msleep(100); - rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address); - } while ((rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); - reg_crq_failed: - dma_unmap_single(hostdata->dev, - queue->msg_token, - queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL); - map_failed: - free_page((unsigned long)queue->msgs); - malloc_failed: - return -1; -} - -/** - * reenable_crq_queue: - reenables a crq after - * @queue: crq_queue to initialize and register - * @hostdata: ibmvscsi_host_data of host - * - */ -static int rpavscsi_reenable_crq_queue(struct crq_queue *queue, - struct ibmvscsi_host_data *hostdata) -{ - int rc = 0; - struct vio_dev *vdev = to_vio_dev(hostdata->dev); - - /* Re-enable the CRQ */ - do { - if (rc) - msleep(100); - rc = plpar_hcall_norets(H_ENABLE_CRQ, vdev->unit_address); - } while ((rc == H_IN_PROGRESS) || (rc == H_BUSY) || (H_IS_LONG_BUSY(rc))); - - if (rc) - dev_err(hostdata->dev, "Error %d enabling adapter\n", rc); - return rc; -} - -/** - * rpavscsi_resume: - resume after suspend - * @hostdata: ibmvscsi_host_data of host - * - */ -static int rpavscsi_resume(struct ibmvscsi_host_data *hostdata) -{ - vio_disable_interrupts(to_vio_dev(hostdata->dev)); - tasklet_schedule(&hostdata->srp_task); - return 0; -} - -struct ibmvscsi_ops rpavscsi_ops = { - .init_crq_queue = rpavscsi_init_crq_queue, - .release_crq_queue = rpavscsi_release_crq_queue, - .reset_crq_queue = rpavscsi_reset_crq_queue, - .reenable_crq_queue = rpavscsi_reenable_crq_queue, - .send_crq = rpavscsi_send_crq, - .resume = rpavscsi_resume, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/viosrp.h b/ANDROID_3.4.5/drivers/scsi/ibmvscsi/viosrp.h deleted file mode 100644 index 2cd735d1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ibmvscsi/viosrp.h +++ /dev/null @@ -1,217 +0,0 @@ -/*****************************************************************************/ -/* srp.h -- SCSI RDMA Protocol definitions */ -/* */ -/* Written By: Colin Devilbis, IBM Corporation */ -/* */ -/* Copyright (C) 2003 IBM Corporation */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* */ -/* */ -/* This file contains structures and definitions for IBM RPA (RS/6000 */ -/* platform architecture) implementation of the SRP (SCSI RDMA Protocol) */ -/* standard. SRP is used on IBM iSeries and pSeries platforms to send SCSI */ -/* commands between logical partitions. */ -/* */ -/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ) */ -/* between partitions. The definitions in this file are architected, */ -/* and cannot be changed without breaking compatibility with other versions */ -/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/ -/* between logical partitions */ -/*****************************************************************************/ -#ifndef VIOSRP_H -#define VIOSRP_H -#include - -#define SRP_VERSION "16.a" -#define SRP_MAX_IU_LEN 256 -#define SRP_MAX_LOC_LEN 32 - -union srp_iu { - struct srp_login_req login_req; - struct srp_login_rsp login_rsp; - struct srp_login_rej login_rej; - struct srp_i_logout i_logout; - struct srp_t_logout t_logout; - struct srp_tsk_mgmt tsk_mgmt; - struct srp_cmd cmd; - struct srp_rsp rsp; - u8 reserved[SRP_MAX_IU_LEN]; -}; - -enum viosrp_crq_formats { - VIOSRP_SRP_FORMAT = 0x01, - VIOSRP_MAD_FORMAT = 0x02, - VIOSRP_OS400_FORMAT = 0x03, - VIOSRP_AIX_FORMAT = 0x04, - VIOSRP_LINUX_FORMAT = 0x06, - VIOSRP_INLINE_FORMAT = 0x07 -}; - -enum viosrp_crq_status { - VIOSRP_OK = 0x0, - VIOSRP_NONRECOVERABLE_ERR = 0x1, - VIOSRP_VIOLATES_MAX_XFER = 0x2, - VIOSRP_PARTNER_PANIC = 0x3, - VIOSRP_DEVICE_BUSY = 0x8, - VIOSRP_ADAPTER_FAIL = 0x10, - VIOSRP_OK2 = 0x99, -}; - -struct viosrp_crq { - u8 valid; /* used by RPA */ - u8 format; /* SCSI vs out-of-band */ - u8 reserved; - u8 status; /* non-scsi failure? (e.g. DMA failure) */ - u16 timeout; /* in seconds */ - u16 IU_length; /* in bytes */ - u64 IU_data_ptr; /* the TCE for transferring data */ -}; - -/* MADs are Management requests above and beyond the IUs defined in the SRP - * standard. - */ -enum viosrp_mad_types { - VIOSRP_EMPTY_IU_TYPE = 0x01, - VIOSRP_ERROR_LOG_TYPE = 0x02, - VIOSRP_ADAPTER_INFO_TYPE = 0x03, - VIOSRP_HOST_CONFIG_TYPE = 0x04, - VIOSRP_CAPABILITIES_TYPE = 0x05, - VIOSRP_ENABLE_FAST_FAIL = 0x08, -}; - -enum viosrp_mad_status { - VIOSRP_MAD_SUCCESS = 0x00, - VIOSRP_MAD_NOT_SUPPORTED = 0xF1, - VIOSRP_MAD_FAILED = 0xF7, -}; - -enum viosrp_capability_type { - MIGRATION_CAPABILITIES = 0x01, - RESERVATION_CAPABILITIES = 0x02, -}; - -enum viosrp_capability_support { - SERVER_DOES_NOT_SUPPORTS_CAP = 0x0, - SERVER_SUPPORTS_CAP = 0x01, - SERVER_CAP_DATA = 0x02, -}; - -enum viosrp_reserve_type { - CLIENT_RESERVE_SCSI_2 = 0x01, -}; - -enum viosrp_capability_flag { - CLIENT_MIGRATED = 0x01, - CLIENT_RECONNECT = 0x02, - CAP_LIST_SUPPORTED = 0x04, - CAP_LIST_DATA = 0x08, -}; - -/* - * Common MAD header - */ -struct mad_common { - u32 type; - u16 status; - u16 length; - u64 tag; -}; - -/* - * All SRP (and MAD) requests normally flow from the - * client to the server. There is no way for the server to send - * an asynchronous message back to the client. The Empty IU is used - * to hang out a meaningless request to the server so that it can respond - * asynchrouously with something like a SCSI AER - */ -struct viosrp_empty_iu { - struct mad_common common; - u64 buffer; - u32 port; -}; - -struct viosrp_error_log { - struct mad_common common; - u64 buffer; -}; - -struct viosrp_adapter_info { - struct mad_common common; - u64 buffer; -}; - -struct viosrp_host_config { - struct mad_common common; - u64 buffer; -}; - -struct viosrp_fast_fail { - struct mad_common common; -}; - -struct viosrp_capabilities { - struct mad_common common; - u64 buffer; -}; - -struct mad_capability_common { - u32 cap_type; - u16 length; - u16 server_support; -}; - -struct mad_reserve_cap { - struct mad_capability_common common; - u32 type; -}; - -struct mad_migration_cap { - struct mad_capability_common common; - u32 ecl; -}; - -struct capabilities{ - u32 flags; - char name[SRP_MAX_LOC_LEN]; - char loc[SRP_MAX_LOC_LEN]; - struct mad_migration_cap migration; - struct mad_reserve_cap reserve; -}; - -union mad_iu { - struct viosrp_empty_iu empty_iu; - struct viosrp_error_log error_log; - struct viosrp_adapter_info adapter_info; - struct viosrp_host_config host_config; - struct viosrp_fast_fail fast_fail; - struct viosrp_capabilities capabilities; -}; - -union viosrp_iu { - union srp_iu srp; - union mad_iu mad; -}; - -struct mad_adapter_info_data { - char srp_version[8]; - char partition_name[96]; - u32 partition_number; - u32 mad_version; - u32 os_type; - u32 port_max_txu[8]; /* per-port maximum transfer */ -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/imm.c b/ANDROID_3.4.5/drivers/scsi/imm.c deleted file mode 100644 index 26cd9d1d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/imm.c +++ /dev/null @@ -1,1286 +0,0 @@ -/* imm.c -- low level driver for the IOMEGA MatchMaker - * parallel port SCSI host adapter. - * - * (The IMM is the embedded controller in the ZIP Plus drive.) - * - * My unofficial company acronym list is 21 pages long: - * FLA: Four letter acronym with built in facility for - * future expansion to five letters. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* The following #define is to avoid a clash with hosts.c */ -#define IMM_PROBE_SPP 0x0001 -#define IMM_PROBE_PS2 0x0002 -#define IMM_PROBE_ECR 0x0010 -#define IMM_PROBE_EPP17 0x0100 -#define IMM_PROBE_EPP19 0x0200 - - -typedef struct { - struct pardevice *dev; /* Parport device entry */ - int base; /* Actual port address */ - int base_hi; /* Hi Base address for ECP-ISA chipset */ - int mode; /* Transfer mode */ - struct scsi_cmnd *cur_cmd; /* Current queued command */ - struct delayed_work imm_tq; /* Polling interrupt stuff */ - unsigned long jstart; /* Jiffies at start */ - unsigned failed:1; /* Failure flag */ - unsigned dp:1; /* Data phase present */ - unsigned rd:1; /* Read data in data phase */ - unsigned wanted:1; /* Parport sharing busy flag */ - wait_queue_head_t *waiting; - struct Scsi_Host *host; - struct list_head list; -} imm_struct; - -static void imm_reset_pulse(unsigned int base); -static int device_check(imm_struct *dev); - -#include "imm.h" - -static inline imm_struct *imm_dev(struct Scsi_Host *host) -{ - return *(imm_struct **)&host->hostdata; -} - -static DEFINE_SPINLOCK(arbitration_lock); - -static void got_it(imm_struct *dev) -{ - dev->base = dev->dev->port->base; - if (dev->cur_cmd) - dev->cur_cmd->SCp.phase = 1; - else - wake_up(dev->waiting); -} - -static void imm_wakeup(void *ref) -{ - imm_struct *dev = (imm_struct *) ref; - unsigned long flags; - - spin_lock_irqsave(&arbitration_lock, flags); - if (dev->wanted) { - parport_claim(dev->dev); - got_it(dev); - dev->wanted = 0; - } - spin_unlock_irqrestore(&arbitration_lock, flags); -} - -static int imm_pb_claim(imm_struct *dev) -{ - unsigned long flags; - int res = 1; - spin_lock_irqsave(&arbitration_lock, flags); - if (parport_claim(dev->dev) == 0) { - got_it(dev); - res = 0; - } - dev->wanted = res; - spin_unlock_irqrestore(&arbitration_lock, flags); - return res; -} - -static void imm_pb_dismiss(imm_struct *dev) -{ - unsigned long flags; - int wanted; - spin_lock_irqsave(&arbitration_lock, flags); - wanted = dev->wanted; - dev->wanted = 0; - spin_unlock_irqrestore(&arbitration_lock, flags); - if (!wanted) - parport_release(dev->dev); -} - -static inline void imm_pb_release(imm_struct *dev) -{ - parport_release(dev->dev); -} - -/* This is to give the imm driver a way to modify the timings (and other - * parameters) by writing to the /proc/scsi/imm/0 file. - * Very simple method really... (Too simple, no error checking :( ) - * Reason: Kernel hackers HATE having to unload and reload modules for - * testing... - * Also gives a method to use a script to obtain optimum timings (TODO) - */ -static inline int imm_proc_write(imm_struct *dev, char *buffer, int length) -{ - unsigned long x; - - if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) { - x = simple_strtoul(buffer + 5, NULL, 0); - dev->mode = x; - return length; - } - printk("imm /proc: invalid variable\n"); - return (-EINVAL); -} - -static int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start, - off_t offset, int length, int inout) -{ - imm_struct *dev = imm_dev(host); - int len = 0; - - if (inout) - return imm_proc_write(dev, buffer, length); - - len += sprintf(buffer + len, "Version : %s\n", IMM_VERSION); - len += - sprintf(buffer + len, "Parport : %s\n", - dev->dev->port->name); - len += - sprintf(buffer + len, "Mode : %s\n", - IMM_MODE_STRING[dev->mode]); - - /* Request for beyond end of buffer */ - if (offset > len) - return 0; - - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - return len; -} - -#if IMM_DEBUG > 0 -#define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\ - y, __func__, __LINE__); imm_fail_func(x,y); -static inline void -imm_fail_func(imm_struct *dev, int error_code) -#else -static inline void -imm_fail(imm_struct *dev, int error_code) -#endif -{ - /* If we fail a device then we trash status / message bytes */ - if (dev->cur_cmd) { - dev->cur_cmd->result = error_code << 16; - dev->failed = 1; - } -} - -/* - * Wait for the high bit to be set. - * - * In principle, this could be tied to an interrupt, but the adapter - * doesn't appear to be designed to support interrupts. We spin on - * the 0x80 ready bit. - */ -static unsigned char imm_wait(imm_struct *dev) -{ - int k; - unsigned short ppb = dev->base; - unsigned char r; - - w_ctr(ppb, 0x0c); - - k = IMM_SPIN_TMO; - do { - r = r_str(ppb); - k--; - udelay(1); - } - while (!(r & 0x80) && (k)); - - /* - * STR register (LPT base+1) to SCSI mapping: - * - * STR imm imm - * =================================== - * 0x80 S_REQ S_REQ - * 0x40 !S_BSY (????) - * 0x20 !S_CD !S_CD - * 0x10 !S_IO !S_IO - * 0x08 (????) !S_BSY - * - * imm imm meaning - * ================================== - * 0xf0 0xb8 Bit mask - * 0xc0 0x88 ZIP wants more data - * 0xd0 0x98 ZIP wants to send more data - * 0xe0 0xa8 ZIP is expecting SCSI command data - * 0xf0 0xb8 end of transfer, ZIP is sending status - */ - w_ctr(ppb, 0x04); - if (k) - return (r & 0xb8); - - /* Counter expired - Time out occurred */ - imm_fail(dev, DID_TIME_OUT); - printk("imm timeout in imm_wait\n"); - return 0; /* command timed out */ -} - -static int imm_negotiate(imm_struct * tmp) -{ - /* - * The following is supposedly the IEEE 1284-1994 negotiate - * sequence. I have yet to obtain a copy of the above standard - * so this is a bit of a guess... - * - * A fair chunk of this is based on the Linux parport implementation - * of IEEE 1284. - * - * Return 0 if data available - * 1 if no data available - */ - - unsigned short base = tmp->base; - unsigned char a, mode; - - switch (tmp->mode) { - case IMM_NIBBLE: - mode = 0x00; - break; - case IMM_PS2: - mode = 0x01; - break; - default: - return 0; - } - - w_ctr(base, 0x04); - udelay(5); - w_dtr(base, mode); - udelay(100); - w_ctr(base, 0x06); - udelay(5); - a = (r_str(base) & 0x20) ? 0 : 1; - udelay(5); - w_ctr(base, 0x07); - udelay(5); - w_ctr(base, 0x06); - - if (a) { - printk - ("IMM: IEEE1284 negotiate indicates no data available.\n"); - imm_fail(tmp, DID_ERROR); - } - return a; -} - -/* - * Clear EPP timeout bit. - */ -static inline void epp_reset(unsigned short ppb) -{ - int i; - - i = r_str(ppb); - w_str(ppb, i); - w_str(ppb, i & 0xfe); -} - -/* - * Wait for empty ECP fifo (if we are in ECP fifo mode only) - */ -static inline void ecp_sync(imm_struct *dev) -{ - int i, ppb_hi = dev->base_hi; - - if (ppb_hi == 0) - return; - - if ((r_ecr(ppb_hi) & 0xe0) == 0x60) { /* mode 011 == ECP fifo mode */ - for (i = 0; i < 100; i++) { - if (r_ecr(ppb_hi) & 0x01) - return; - udelay(5); - } - printk("imm: ECP sync failed as data still present in FIFO.\n"); - } -} - -static int imm_byte_out(unsigned short base, const char *buffer, int len) -{ - int i; - - w_ctr(base, 0x4); /* apparently a sane mode */ - for (i = len >> 1; i; i--) { - w_dtr(base, *buffer++); - w_ctr(base, 0x5); /* Drop STROBE low */ - w_dtr(base, *buffer++); - w_ctr(base, 0x0); /* STROBE high + INIT low */ - } - w_ctr(base, 0x4); /* apparently a sane mode */ - return 1; /* All went well - we hope! */ -} - -static int imm_nibble_in(unsigned short base, char *buffer, int len) -{ - unsigned char l; - int i; - - /* - * The following is based on documented timing signals - */ - w_ctr(base, 0x4); - for (i = len; i; i--) { - w_ctr(base, 0x6); - l = (r_str(base) & 0xf0) >> 4; - w_ctr(base, 0x5); - *buffer++ = (r_str(base) & 0xf0) | l; - w_ctr(base, 0x4); - } - return 1; /* All went well - we hope! */ -} - -static int imm_byte_in(unsigned short base, char *buffer, int len) -{ - int i; - - /* - * The following is based on documented timing signals - */ - w_ctr(base, 0x4); - for (i = len; i; i--) { - w_ctr(base, 0x26); - *buffer++ = r_dtr(base); - w_ctr(base, 0x25); - } - return 1; /* All went well - we hope! */ -} - -static int imm_out(imm_struct *dev, char *buffer, int len) -{ - unsigned short ppb = dev->base; - int r = imm_wait(dev); - - /* - * Make sure that: - * a) the SCSI bus is BUSY (device still listening) - * b) the device is listening - */ - if ((r & 0x18) != 0x08) { - imm_fail(dev, DID_ERROR); - printk("IMM: returned SCSI status %2x\n", r); - return 0; - } - switch (dev->mode) { - case IMM_EPP_32: - case IMM_EPP_16: - case IMM_EPP_8: - epp_reset(ppb); - w_ctr(ppb, 0x4); -#ifdef CONFIG_SCSI_IZIP_EPP16 - if (!(((long) buffer | len) & 0x01)) - outsw(ppb + 4, buffer, len >> 1); -#else - if (!(((long) buffer | len) & 0x03)) - outsl(ppb + 4, buffer, len >> 2); -#endif - else - outsb(ppb + 4, buffer, len); - w_ctr(ppb, 0xc); - r = !(r_str(ppb) & 0x01); - w_ctr(ppb, 0xc); - ecp_sync(dev); - break; - - case IMM_NIBBLE: - case IMM_PS2: - /* 8 bit output, with a loop */ - r = imm_byte_out(ppb, buffer, len); - break; - - default: - printk("IMM: bug in imm_out()\n"); - r = 0; - } - return r; -} - -static int imm_in(imm_struct *dev, char *buffer, int len) -{ - unsigned short ppb = dev->base; - int r = imm_wait(dev); - - /* - * Make sure that: - * a) the SCSI bus is BUSY (device still listening) - * b) the device is sending data - */ - if ((r & 0x18) != 0x18) { - imm_fail(dev, DID_ERROR); - return 0; - } - switch (dev->mode) { - case IMM_NIBBLE: - /* 4 bit input, with a loop */ - r = imm_nibble_in(ppb, buffer, len); - w_ctr(ppb, 0xc); - break; - - case IMM_PS2: - /* 8 bit input, with a loop */ - r = imm_byte_in(ppb, buffer, len); - w_ctr(ppb, 0xc); - break; - - case IMM_EPP_32: - case IMM_EPP_16: - case IMM_EPP_8: - epp_reset(ppb); - w_ctr(ppb, 0x24); -#ifdef CONFIG_SCSI_IZIP_EPP16 - if (!(((long) buffer | len) & 0x01)) - insw(ppb + 4, buffer, len >> 1); -#else - if (!(((long) buffer | len) & 0x03)) - insl(ppb + 4, buffer, len >> 2); -#endif - else - insb(ppb + 4, buffer, len); - w_ctr(ppb, 0x2c); - r = !(r_str(ppb) & 0x01); - w_ctr(ppb, 0x2c); - ecp_sync(dev); - break; - - default: - printk("IMM: bug in imm_ins()\n"); - r = 0; - break; - } - return r; -} - -static int imm_cpp(unsigned short ppb, unsigned char b) -{ - /* - * Comments on udelay values refer to the - * Command Packet Protocol (CPP) timing diagram. - */ - - unsigned char s1, s2, s3; - w_ctr(ppb, 0x0c); - udelay(2); /* 1 usec - infinite */ - w_dtr(ppb, 0xaa); - udelay(10); /* 7 usec - infinite */ - w_dtr(ppb, 0x55); - udelay(10); /* 7 usec - infinite */ - w_dtr(ppb, 0x00); - udelay(10); /* 7 usec - infinite */ - w_dtr(ppb, 0xff); - udelay(10); /* 7 usec - infinite */ - s1 = r_str(ppb) & 0xb8; - w_dtr(ppb, 0x87); - udelay(10); /* 7 usec - infinite */ - s2 = r_str(ppb) & 0xb8; - w_dtr(ppb, 0x78); - udelay(10); /* 7 usec - infinite */ - s3 = r_str(ppb) & 0x38; - /* - * Values for b are: - * 0000 00aa Assign address aa to current device - * 0010 00aa Select device aa in EPP Winbond mode - * 0010 10aa Select device aa in EPP mode - * 0011 xxxx Deselect all devices - * 0110 00aa Test device aa - * 1101 00aa Select device aa in ECP mode - * 1110 00aa Select device aa in Compatible mode - */ - w_dtr(ppb, b); - udelay(2); /* 1 usec - infinite */ - w_ctr(ppb, 0x0c); - udelay(10); /* 7 usec - infinite */ - w_ctr(ppb, 0x0d); - udelay(2); /* 1 usec - infinite */ - w_ctr(ppb, 0x0c); - udelay(10); /* 7 usec - infinite */ - w_dtr(ppb, 0xff); - udelay(10); /* 7 usec - infinite */ - - /* - * The following table is electrical pin values. - * (BSY is inverted at the CTR register) - * - * BSY ACK POut SEL Fault - * S1 0 X 1 1 1 - * S2 1 X 0 1 1 - * S3 L X 1 1 S - * - * L => Last device in chain - * S => Selected - * - * Observered values for S1,S2,S3 are: - * Disconnect => f8/58/78 - * Connect => f8/58/70 - */ - if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x30)) - return 1; /* Connected */ - if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x38)) - return 0; /* Disconnected */ - - return -1; /* No device present */ -} - -static inline int imm_connect(imm_struct *dev, int flag) -{ - unsigned short ppb = dev->base; - - imm_cpp(ppb, 0xe0); /* Select device 0 in compatible mode */ - imm_cpp(ppb, 0x30); /* Disconnect all devices */ - - if ((dev->mode == IMM_EPP_8) || - (dev->mode == IMM_EPP_16) || - (dev->mode == IMM_EPP_32)) - return imm_cpp(ppb, 0x28); /* Select device 0 in EPP mode */ - return imm_cpp(ppb, 0xe0); /* Select device 0 in compatible mode */ -} - -static void imm_disconnect(imm_struct *dev) -{ - imm_cpp(dev->base, 0x30); /* Disconnect all devices */ -} - -static int imm_select(imm_struct *dev, int target) -{ - int k; - unsigned short ppb = dev->base; - - /* - * Firstly we want to make sure there is nothing - * holding onto the SCSI bus. - */ - w_ctr(ppb, 0xc); - - k = IMM_SELECT_TMO; - do { - k--; - } while ((r_str(ppb) & 0x08) && (k)); - - if (!k) - return 0; - - /* - * Now assert the SCSI ID (HOST and TARGET) on the data bus - */ - w_ctr(ppb, 0x4); - w_dtr(ppb, 0x80 | (1 << target)); - udelay(1); - - /* - * Deassert SELIN first followed by STROBE - */ - w_ctr(ppb, 0xc); - w_ctr(ppb, 0xd); - - /* - * ACK should drop low while SELIN is deasserted. - * FAULT should drop low when the SCSI device latches the bus. - */ - k = IMM_SELECT_TMO; - do { - k--; - } - while (!(r_str(ppb) & 0x08) && (k)); - - /* - * Place the interface back into a sane state (status mode) - */ - w_ctr(ppb, 0xc); - return (k) ? 1 : 0; -} - -static int imm_init(imm_struct *dev) -{ - if (imm_connect(dev, 0) != 1) - return -EIO; - imm_reset_pulse(dev->base); - mdelay(1); /* Delay to allow devices to settle */ - imm_disconnect(dev); - mdelay(1); /* Another delay to allow devices to settle */ - return device_check(dev); -} - -static inline int imm_send_command(struct scsi_cmnd *cmd) -{ - imm_struct *dev = imm_dev(cmd->device->host); - int k; - - /* NOTE: IMM uses byte pairs */ - for (k = 0; k < cmd->cmd_len; k += 2) - if (!imm_out(dev, &cmd->cmnd[k], 2)) - return 0; - return 1; -} - -/* - * The bulk flag enables some optimisations in the data transfer loops, - * it should be true for any command that transfers data in integral - * numbers of sectors. - * - * The driver appears to remain stable if we speed up the parallel port - * i/o in this function, but not elsewhere. - */ -static int imm_completion(struct scsi_cmnd *cmd) -{ - /* Return codes: - * -1 Error - * 0 Told to schedule - * 1 Finished data transfer - */ - imm_struct *dev = imm_dev(cmd->device->host); - unsigned short ppb = dev->base; - unsigned long start_jiffies = jiffies; - - unsigned char r, v; - int fast, bulk, status; - - v = cmd->cmnd[0]; - bulk = ((v == READ_6) || - (v == READ_10) || (v == WRITE_6) || (v == WRITE_10)); - - /* - * We only get here if the drive is ready to comunicate, - * hence no need for a full imm_wait. - */ - w_ctr(ppb, 0x0c); - r = (r_str(ppb) & 0xb8); - - /* - * while (device is not ready to send status byte) - * loop; - */ - while (r != (unsigned char) 0xb8) { - /* - * If we have been running for more than a full timer tick - * then take a rest. - */ - if (time_after(jiffies, start_jiffies + 1)) - return 0; - - /* - * FAIL if: - * a) Drive status is screwy (!ready && !present) - * b) Drive is requesting/sending more data than expected - */ - if (((r & 0x88) != 0x88) || (cmd->SCp.this_residual <= 0)) { - imm_fail(dev, DID_ERROR); - return -1; /* ERROR_RETURN */ - } - /* determine if we should use burst I/O */ - if (dev->rd == 0) { - fast = (bulk - && (cmd->SCp.this_residual >= - IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 2; - status = imm_out(dev, cmd->SCp.ptr, fast); - } else { - fast = (bulk - && (cmd->SCp.this_residual >= - IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 1; - status = imm_in(dev, cmd->SCp.ptr, fast); - } - - cmd->SCp.ptr += fast; - cmd->SCp.this_residual -= fast; - - if (!status) { - imm_fail(dev, DID_BUS_BUSY); - return -1; /* ERROR_RETURN */ - } - if (cmd->SCp.buffer && !cmd->SCp.this_residual) { - /* if scatter/gather, advance to the next segment */ - if (cmd->SCp.buffers_residual--) { - cmd->SCp.buffer++; - cmd->SCp.this_residual = - cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - - /* - * Make sure that we transfer even number of bytes - * otherwise it makes imm_byte_out() messy. - */ - if (cmd->SCp.this_residual & 0x01) - cmd->SCp.this_residual++; - } - } - /* Now check to see if the drive is ready to comunicate */ - w_ctr(ppb, 0x0c); - r = (r_str(ppb) & 0xb8); - - /* If not, drop back down to the scheduler and wait a timer tick */ - if (!(r & 0x80)) - return 0; - } - return 1; /* FINISH_RETURN */ -} - -/* - * Since the IMM itself doesn't generate interrupts, we use - * the scheduler's task queue to generate a stream of call-backs and - * complete the request when the drive is ready. - */ -static void imm_interrupt(struct work_struct *work) -{ - imm_struct *dev = container_of(work, imm_struct, imm_tq.work); - struct scsi_cmnd *cmd = dev->cur_cmd; - struct Scsi_Host *host = cmd->device->host; - unsigned long flags; - - if (imm_engine(dev, cmd)) { - schedule_delayed_work(&dev->imm_tq, 1); - return; - } - /* Command must of completed hence it is safe to let go... */ -#if IMM_DEBUG > 0 - switch ((cmd->result >> 16) & 0xff) { - case DID_OK: - break; - case DID_NO_CONNECT: - printk("imm: no device at SCSI ID %i\n", cmd->device->id); - break; - case DID_BUS_BUSY: - printk("imm: BUS BUSY - EPP timeout detected\n"); - break; - case DID_TIME_OUT: - printk("imm: unknown timeout\n"); - break; - case DID_ABORT: - printk("imm: told to abort\n"); - break; - case DID_PARITY: - printk("imm: parity error (???)\n"); - break; - case DID_ERROR: - printk("imm: internal driver error\n"); - break; - case DID_RESET: - printk("imm: told to reset device\n"); - break; - case DID_BAD_INTR: - printk("imm: bad interrupt (???)\n"); - break; - default: - printk("imm: bad return code (%02x)\n", - (cmd->result >> 16) & 0xff); - } -#endif - - if (cmd->SCp.phase > 1) - imm_disconnect(dev); - - imm_pb_dismiss(dev); - - spin_lock_irqsave(host->host_lock, flags); - dev->cur_cmd = NULL; - cmd->scsi_done(cmd); - spin_unlock_irqrestore(host->host_lock, flags); - return; -} - -static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd) -{ - unsigned short ppb = dev->base; - unsigned char l = 0, h = 0; - int retv, x; - - /* First check for any errors that may have occurred - * Here we check for internal errors - */ - if (dev->failed) - return 0; - - switch (cmd->SCp.phase) { - case 0: /* Phase 0 - Waiting for parport */ - if (time_after(jiffies, dev->jstart + HZ)) { - /* - * We waited more than a second - * for parport to call us - */ - imm_fail(dev, DID_BUS_BUSY); - return 0; - } - return 1; /* wait until imm_wakeup claims parport */ - /* Phase 1 - Connected */ - case 1: - imm_connect(dev, CONNECT_EPP_MAYBE); - cmd->SCp.phase++; - - /* Phase 2 - We are now talking to the scsi bus */ - case 2: - if (!imm_select(dev, scmd_id(cmd))) { - imm_fail(dev, DID_NO_CONNECT); - return 0; - } - cmd->SCp.phase++; - - /* Phase 3 - Ready to accept a command */ - case 3: - w_ctr(ppb, 0x0c); - if (!(r_str(ppb) & 0x80)) - return 1; - - if (!imm_send_command(cmd)) - return 0; - cmd->SCp.phase++; - - /* Phase 4 - Setup scatter/gather buffers */ - case 4: - if (scsi_bufflen(cmd)) { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.this_residual = 0; - cmd->SCp.ptr = NULL; - } - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; - cmd->SCp.phase++; - if (cmd->SCp.this_residual & 0x01) - cmd->SCp.this_residual++; - /* Phase 5 - Pre-Data transfer stage */ - case 5: - /* Spin lock for BUSY */ - w_ctr(ppb, 0x0c); - if (!(r_str(ppb) & 0x80)) - return 1; - - /* Require negotiation for read requests */ - x = (r_str(ppb) & 0xb8); - dev->rd = (x & 0x10) ? 1 : 0; - dev->dp = (x & 0x20) ? 0 : 1; - - if ((dev->dp) && (dev->rd)) - if (imm_negotiate(dev)) - return 0; - cmd->SCp.phase++; - - /* Phase 6 - Data transfer stage */ - case 6: - /* Spin lock for BUSY */ - w_ctr(ppb, 0x0c); - if (!(r_str(ppb) & 0x80)) - return 1; - - if (dev->dp) { - retv = imm_completion(cmd); - if (retv == -1) - return 0; - if (retv == 0) - return 1; - } - cmd->SCp.phase++; - - /* Phase 7 - Post data transfer stage */ - case 7: - if ((dev->dp) && (dev->rd)) { - if ((dev->mode == IMM_NIBBLE) || (dev->mode == IMM_PS2)) { - w_ctr(ppb, 0x4); - w_ctr(ppb, 0xc); - w_ctr(ppb, 0xe); - w_ctr(ppb, 0x4); - } - } - cmd->SCp.phase++; - - /* Phase 8 - Read status/message */ - case 8: - /* Check for data overrun */ - if (imm_wait(dev) != (unsigned char) 0xb8) { - imm_fail(dev, DID_ERROR); - return 0; - } - if (imm_negotiate(dev)) - return 0; - if (imm_in(dev, &l, 1)) { /* read status byte */ - /* Check for optional message byte */ - if (imm_wait(dev) == (unsigned char) 0xb8) - imm_in(dev, &h, 1); - cmd->result = (DID_OK << 16) + (l & STATUS_MASK); - } - if ((dev->mode == IMM_NIBBLE) || (dev->mode == IMM_PS2)) { - w_ctr(ppb, 0x4); - w_ctr(ppb, 0xc); - w_ctr(ppb, 0xe); - w_ctr(ppb, 0x4); - } - return 0; /* Finished */ - break; - - default: - printk("imm: Invalid scsi phase\n"); - } - return 0; -} - -static int imm_queuecommand_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - imm_struct *dev = imm_dev(cmd->device->host); - - if (dev->cur_cmd) { - printk("IMM: bug in imm_queuecommand\n"); - return 0; - } - dev->failed = 0; - dev->jstart = jiffies; - dev->cur_cmd = cmd; - cmd->scsi_done = done; - cmd->result = DID_ERROR << 16; /* default return code */ - cmd->SCp.phase = 0; /* bus free */ - - schedule_delayed_work(&dev->imm_tq, 0); - - imm_pb_claim(dev); - - return 0; -} - -static DEF_SCSI_QCMD(imm_queuecommand) - -/* - * Apparently the disk->capacity attribute is off by 1 sector - * for all disk drives. We add the one here, but it should really - * be done in sd.c. Even if it gets fixed there, this will still - * work. - */ -static int imm_biosparam(struct scsi_device *sdev, struct block_device *dev, - sector_t capacity, int ip[]) -{ - ip[0] = 0x40; - ip[1] = 0x20; - ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]); - if (ip[2] > 1024) { - ip[0] = 0xff; - ip[1] = 0x3f; - ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]); - } - return 0; -} - -static int imm_abort(struct scsi_cmnd *cmd) -{ - imm_struct *dev = imm_dev(cmd->device->host); - /* - * There is no method for aborting commands since Iomega - * have tied the SCSI_MESSAGE line high in the interface - */ - - switch (cmd->SCp.phase) { - case 0: /* Do not have access to parport */ - case 1: /* Have not connected to interface */ - dev->cur_cmd = NULL; /* Forget the problem */ - return SUCCESS; - break; - default: /* SCSI command sent, can not abort */ - return FAILED; - break; - } -} - -static void imm_reset_pulse(unsigned int base) -{ - w_ctr(base, 0x04); - w_dtr(base, 0x40); - udelay(1); - w_ctr(base, 0x0c); - w_ctr(base, 0x0d); - udelay(50); - w_ctr(base, 0x0c); - w_ctr(base, 0x04); -} - -static int imm_reset(struct scsi_cmnd *cmd) -{ - imm_struct *dev = imm_dev(cmd->device->host); - - if (cmd->SCp.phase) - imm_disconnect(dev); - dev->cur_cmd = NULL; /* Forget the problem */ - - imm_connect(dev, CONNECT_NORMAL); - imm_reset_pulse(dev->base); - mdelay(1); /* device settle delay */ - imm_disconnect(dev); - mdelay(1); /* device settle delay */ - return SUCCESS; -} - -static int device_check(imm_struct *dev) -{ - /* This routine looks for a device and then attempts to use EPP - to send a command. If all goes as planned then EPP is available. */ - - static char cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - int loop, old_mode, status, k, ppb = dev->base; - unsigned char l; - - old_mode = dev->mode; - for (loop = 0; loop < 8; loop++) { - /* Attempt to use EPP for Test Unit Ready */ - if ((ppb & 0x0007) == 0x0000) - dev->mode = IMM_EPP_32; - - second_pass: - imm_connect(dev, CONNECT_EPP_MAYBE); - /* Select SCSI device */ - if (!imm_select(dev, loop)) { - imm_disconnect(dev); - continue; - } - printk("imm: Found device at ID %i, Attempting to use %s\n", - loop, IMM_MODE_STRING[dev->mode]); - - /* Send SCSI command */ - status = 1; - w_ctr(ppb, 0x0c); - for (l = 0; (l < 3) && (status); l++) - status = imm_out(dev, &cmd[l << 1], 2); - - if (!status) { - imm_disconnect(dev); - imm_connect(dev, CONNECT_EPP_MAYBE); - imm_reset_pulse(dev->base); - udelay(1000); - imm_disconnect(dev); - udelay(1000); - if (dev->mode == IMM_EPP_32) { - dev->mode = old_mode; - goto second_pass; - } - printk("imm: Unable to establish communication\n"); - return -EIO; - } - w_ctr(ppb, 0x0c); - - k = 1000000; /* 1 Second */ - do { - l = r_str(ppb); - k--; - udelay(1); - } while (!(l & 0x80) && (k)); - - l &= 0xb8; - - if (l != 0xb8) { - imm_disconnect(dev); - imm_connect(dev, CONNECT_EPP_MAYBE); - imm_reset_pulse(dev->base); - udelay(1000); - imm_disconnect(dev); - udelay(1000); - if (dev->mode == IMM_EPP_32) { - dev->mode = old_mode; - goto second_pass; - } - printk - ("imm: Unable to establish communication\n"); - return -EIO; - } - imm_disconnect(dev); - printk - ("imm: Communication established at 0x%x with ID %i using %s\n", - ppb, loop, IMM_MODE_STRING[dev->mode]); - imm_connect(dev, CONNECT_EPP_MAYBE); - imm_reset_pulse(dev->base); - udelay(1000); - imm_disconnect(dev); - udelay(1000); - return 0; - } - printk("imm: No devices found\n"); - return -ENODEV; -} - -/* - * imm cannot deal with highmem, so this causes all IO pages for this host - * to reside in low memory (hence mapped) - */ -static int imm_adjust_queue(struct scsi_device *device) -{ - blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH); - return 0; -} - -static struct scsi_host_template imm_template = { - .module = THIS_MODULE, - .proc_name = "imm", - .proc_info = imm_proc_info, - .name = "Iomega VPI2 (imm) interface", - .queuecommand = imm_queuecommand, - .eh_abort_handler = imm_abort, - .eh_bus_reset_handler = imm_reset, - .eh_host_reset_handler = imm_reset, - .bios_param = imm_biosparam, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, - .can_queue = 1, - .slave_alloc = imm_adjust_queue, -}; - -/*************************************************************************** - * Parallel port probing routines * - ***************************************************************************/ - -static LIST_HEAD(imm_hosts); - -static int __imm_attach(struct parport *pb) -{ - struct Scsi_Host *host; - imm_struct *dev; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); - DEFINE_WAIT(wait); - int ports; - int modes, ppb; - int err = -ENOMEM; - - init_waitqueue_head(&waiting); - - dev = kzalloc(sizeof(imm_struct), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - - dev->base = -1; - dev->mode = IMM_AUTODETECT; - INIT_LIST_HEAD(&dev->list); - - dev->dev = parport_register_device(pb, "imm", NULL, imm_wakeup, - NULL, 0, dev); - - if (!dev->dev) - goto out; - - - /* Claim the bus so it remembers what we do to the control - * registers. [ CTR and ECP ] - */ - err = -EBUSY; - dev->waiting = &waiting; - prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE); - if (imm_pb_claim(dev)) - schedule_timeout(3 * HZ); - if (dev->wanted) { - printk(KERN_ERR "imm%d: failed to claim parport because " - "a pardevice is owning the port for too long " - "time!\n", pb->number); - imm_pb_dismiss(dev); - dev->waiting = NULL; - finish_wait(&waiting, &wait); - goto out1; - } - dev->waiting = NULL; - finish_wait(&waiting, &wait); - ppb = dev->base = dev->dev->port->base; - dev->base_hi = dev->dev->port->base_hi; - w_ctr(ppb, 0x0c); - modes = dev->dev->port->modes; - - /* Mode detection works up the chain of speed - * This avoids a nasty if-then-else-if-... tree - */ - dev->mode = IMM_NIBBLE; - - if (modes & PARPORT_MODE_TRISTATE) - dev->mode = IMM_PS2; - - /* Done configuration */ - - err = imm_init(dev); - - imm_pb_release(dev); - - if (err) - goto out1; - - /* now the glue ... */ - if (dev->mode == IMM_NIBBLE || dev->mode == IMM_PS2) - ports = 3; - else - ports = 8; - - INIT_DELAYED_WORK(&dev->imm_tq, imm_interrupt); - - err = -ENOMEM; - host = scsi_host_alloc(&imm_template, sizeof(imm_struct *)); - if (!host) - goto out1; - host->io_port = pb->base; - host->n_io_port = ports; - host->dma_channel = -1; - host->unique_id = pb->number; - *(imm_struct **)&host->hostdata = dev; - dev->host = host; - list_add_tail(&dev->list, &imm_hosts); - err = scsi_add_host(host, NULL); - if (err) - goto out2; - scsi_scan_host(host); - return 0; - -out2: - list_del_init(&dev->list); - scsi_host_put(host); -out1: - parport_unregister_device(dev->dev); -out: - kfree(dev); - return err; -} - -static void imm_attach(struct parport *pb) -{ - __imm_attach(pb); -} - -static void imm_detach(struct parport *pb) -{ - imm_struct *dev; - list_for_each_entry(dev, &imm_hosts, list) { - if (dev->dev->port == pb) { - list_del_init(&dev->list); - scsi_remove_host(dev->host); - scsi_host_put(dev->host); - parport_unregister_device(dev->dev); - kfree(dev); - break; - } - } -} - -static struct parport_driver imm_driver = { - .name = "imm", - .attach = imm_attach, - .detach = imm_detach, -}; - -static int __init imm_driver_init(void) -{ - printk("imm: Version %s\n", IMM_VERSION); - return parport_register_driver(&imm_driver); -} - -static void __exit imm_driver_exit(void) -{ - parport_unregister_driver(&imm_driver); -} - -module_init(imm_driver_init); -module_exit(imm_driver_exit); - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/imm.h b/ANDROID_3.4.5/drivers/scsi/imm.h deleted file mode 100644 index 8f6f32fc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/imm.h +++ /dev/null @@ -1,143 +0,0 @@ - -/* Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in - * the Iomega ZIP Plus drive - * - * (c) 1998 David Campbell - * - * Please note that I live in Perth, Western Australia. GMT+0800 - */ - -#ifndef _IMM_H -#define _IMM_H - -#define IMM_VERSION "2.05 (for Linux 2.4.0)" - -/* - * 10 Apr 1998 (Good Friday) - Received EN144302 by email from Iomega. - * Scarry thing is the level of support from one of their managers. - * The onus is now on us (the developers) to shut up and start coding. - * 11Apr98 [ 0.10 ] - * - * --- SNIP --- - * - * It manages to find the drive which is a good start. Writing data during - * data phase is known to be broken (due to requirements of two byte writes). - * Removing "Phase" debug messages. - * - * PS: Took four hours of coding after I bought a drive. - * ANZAC Day (Aus "War Veterans Holiday") 25Apr98 [ 0.14 ] - * - * Ten minutes later after a few fixes.... (LITERALLY!!!) - * Have mounted disk, copied file, dismounted disk, remount disk, diff file - * ----- It actually works!!! ----- - * 25Apr98 [ 0.15 ] - * - * Twenty minutes of mucking around, rearanged the IEEE negotiate mechanism. - * Now have byte mode working (only EPP and ECP to go now... :=) - * 26Apr98 [ 0.16 ] - * - * Thirty minutes of further coding results in EPP working on my machine. - * 27Apr98 [ 0.17 ] - * - * Due to work commitments and inability to get a "true" ECP mode functioning - * I have decided to code the parport support into imm. - * 09Jun98 [ 0.18 ] - * - * Driver is now out of beta testing. - * Support for parport has been added. - * Now distributed with the ppa driver. - * 12Jun98 [ 2.00 ] - * - * Err.. It appears that imm-2.00 was broken.... - * 18Jun98 [ 2.01 ] - * - * Patch applied to sync this against the Linux 2.1.x kernel code - * Included qboot_zip.sh - * 21Jun98 [ 2.02 ] - * - * Other clean ups include the follow changes: - * CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16 - * added CONFIG_SCSI_IZIP_SLOW_CTR option - * [2.03] - * Fix kernel panic on scsi timeout. 20Aug00 [2.04] - * - * Avoid io_request_lock problems. - * John Cavan 16Nov00 [2.05] - */ -/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -/* batteries not included :-) */ - -/* - * modes in which the driver can operate - */ -#define IMM_AUTODETECT 0 /* Autodetect mode */ -#define IMM_NIBBLE 1 /* work in standard 4 bit mode */ -#define IMM_PS2 2 /* PS/2 byte mode */ -#define IMM_EPP_8 3 /* EPP mode, 8 bit */ -#define IMM_EPP_16 4 /* EPP mode, 16 bit */ -#define IMM_EPP_32 5 /* EPP mode, 32 bit */ -#define IMM_UNKNOWN 6 /* Just in case... */ - -static char *IMM_MODE_STRING[] = -{ - [IMM_AUTODETECT] = "Autodetect", - [IMM_NIBBLE] = "SPP", - [IMM_PS2] = "PS/2", - [IMM_EPP_8] = "EPP 8 bit", - [IMM_EPP_16] = "EPP 16 bit", -#ifdef CONFIG_SCSI_IZIP_EPP16 - [IMM_EPP_32] = "EPP 16 bit", -#else - [IMM_EPP_32] = "EPP 32 bit", -#endif - [IMM_UNKNOWN] = "Unknown", -}; - -/* other options */ -#define IMM_BURST_SIZE 512 /* data burst size */ -#define IMM_SELECT_TMO 500 /* 500 how long to wait for target ? */ -#define IMM_SPIN_TMO 5000 /* 50000 imm_wait loop limiter */ -#define IMM_DEBUG 0 /* debugging option */ -#define IN_EPP_MODE(x) (x == IMM_EPP_8 || x == IMM_EPP_16 || x == IMM_EPP_32) - -/* args to imm_connect */ -#define CONNECT_EPP_MAYBE 1 -#define CONNECT_NORMAL 0 - -#define r_dtr(x) (unsigned char)inb((x)) -#define r_str(x) (unsigned char)inb((x)+1) -#define r_ctr(x) (unsigned char)inb((x)+2) -#define r_epp(x) (unsigned char)inb((x)+4) -#define r_fifo(x) (unsigned char)inb((x)) /* x must be base_hi */ - /* On PCI is: base+0x400 != base_hi */ -#define r_ecr(x) (unsigned char)inb((x)+2) /* x must be base_hi */ - -#define w_dtr(x,y) outb(y, (x)) -#define w_str(x,y) outb(y, (x)+1) -#define w_epp(x,y) outb(y, (x)+4) -#define w_fifo(x,y) outb(y, (x)) /* x must be base_hi */ -#define w_ecr(x,y) outb(y, (x)+0x2) /* x must be base_hi */ - -#ifdef CONFIG_SCSI_IZIP_SLOW_CTR -#define w_ctr(x,y) outb_p(y, (x)+2) -#else -#define w_ctr(x,y) outb(y, (x)+2) -#endif - -static int imm_engine(imm_struct *, struct scsi_cmnd *); - -#endif /* _IMM_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/in2000.c b/ANDROID_3.4.5/drivers/scsi/in2000.c deleted file mode 100644 index deb5b6d8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/in2000.c +++ /dev/null @@ -1,2336 +0,0 @@ -/* - * in2000.c - Linux device driver for the - * Always IN2000 ISA SCSI card. - * - * Copyright (c) 1996 John Shifflett, GeoLog Consulting - * john@geolog.com - * jshiffle@netcom.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open non patent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - * - * Drew Eckhardt's excellent 'Generic NCR5380' sources provided - * much of the inspiration and some of the code for this driver. - * The Linux IN2000 driver distributed in the Linux kernels through - * version 1.2.13 was an extremely valuable reference on the arcane - * (and still mysterious) workings of the IN2000's fifo. It also - * is where I lifted in2000_biosparam(), the gist of the card - * detection scheme, and other bits of code. Many thanks to the - * talented and courageous people who wrote, contributed to, and - * maintained that driver (including Brad McLean, Shaun Savage, - * Bill Earnest, Larry Doolittle, Roger Sunshine, John Luckey, - * Matt Postiff, Peter Lu, zerucha@shell.portal.com, and Eric - * Youngdale). I should also mention the driver written by - * Hamish Macdonald for the (GASP!) Amiga A2091 card, included - * in the Linux-m68k distribution; it gave me a good initial - * understanding of the proper way to run a WD33c93 chip, and I - * ended up stealing lots of code from it. - * - * _This_ driver is (I feel) an improvement over the old one in - * several respects: - * - All problems relating to the data size of a SCSI request are - * gone (as far as I know). The old driver couldn't handle - * swapping to partitions because that involved 4k blocks, nor - * could it deal with the st.c tape driver unmodified, because - * that usually involved 4k - 32k blocks. The old driver never - * quite got away from a morbid dependence on 2k block sizes - - * which of course is the size of the card's fifo. - * - * - Target Disconnection/Reconnection is now supported. Any - * system with more than one device active on the SCSI bus - * will benefit from this. The driver defaults to what I'm - * calling 'adaptive disconnect' - meaning that each command - * is evaluated individually as to whether or not it should - * be run with the option to disconnect/reselect (if the - * device chooses), or as a "SCSI-bus-hog". - * - * - Synchronous data transfers are now supported. Because there - * are a few devices (and many improperly terminated systems) - * that choke when doing sync, the default is sync DISABLED - * for all devices. This faster protocol can (and should!) - * be enabled on selected devices via the command-line. - * - * - Runtime operating parameters can now be specified through - * either the LILO or the 'insmod' command line. For LILO do: - * "in2000=blah,blah,blah" - * and with insmod go like: - * "insmod /usr/src/linux/modules/in2000.o setup_strings=blah,blah" - * The defaults should be good for most people. See the comment - * for 'setup_strings' below for more details. - * - * - The old driver relied exclusively on what the Western Digital - * docs call "Combination Level 2 Commands", which are a great - * idea in that the CPU is relieved of a lot of interrupt - * overhead. However, by accepting a certain (user-settable) - * amount of additional interrupts, this driver achieves - * better control over the SCSI bus, and data transfers are - * almost as fast while being much easier to define, track, - * and debug. - * - * - You can force detection of a card whose BIOS has been disabled. - * - * - Multiple IN2000 cards might almost be supported. I've tried to - * keep it in mind, but have no way to test... - * - * - * TODO: - * tagged queuing. multiple cards. - * - * - * NOTE: - * When using this or any other SCSI driver as a module, you'll - * find that with the stock kernel, at most _two_ SCSI hard - * drives will be linked into the device list (ie, usable). - * If your IN2000 card has more than 2 disks on its bus, you - * might want to change the define of 'SD_EXTRA_DEVS' in the - * 'hosts.h' file from 2 to whatever is appropriate. It took - * me a while to track down this surprisingly obscure and - * undocumented little "feature". - * - * - * People with bug reports, wish-lists, complaints, comments, - * or improvements are asked to pah-leeez email me (John Shifflett) - * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get - * this thing into as good a shape as possible, and I'm positive - * there are lots of lurking bugs and "Stupid Places". - * - * Updated for Linux 2.5 by Alan Cox - * - Using new_eh handler - * - Hopefully got all the locking right again - * See "FIXME" notes for items that could do with more work - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "scsi.h" -#include - -#define IN2000_VERSION "1.33-2.5" -#define IN2000_DATE "2002/11/03" - -#include "in2000.h" - - -/* - * 'setup_strings' is a single string used to pass operating parameters and - * settings from the kernel/module command-line to the driver. 'setup_args[]' - * is an array of strings that define the compile-time default values for - * these settings. If Linux boots with a LILO or insmod command-line, those - * settings are combined with 'setup_args[]'. Note that LILO command-lines - * are prefixed with "in2000=" while insmod uses a "setup_strings=" prefix. - * The driver recognizes the following keywords (lower case required) and - * arguments: - * - * - ioport:addr -Where addr is IO address of a (usually ROM-less) card. - * - noreset -No optional args. Prevents SCSI bus reset at boot time. - * - nosync:x -x is a bitmask where the 1st 7 bits correspond with - * the 7 possible SCSI devices (bit 0 for device #0, etc). - * Set a bit to PREVENT sync negotiation on that device. - * The driver default is sync DISABLED on all devices. - * - period:ns -ns is the minimum # of nanoseconds in a SCSI data transfer - * period. Default is 500; acceptable values are 250 - 1000. - * - disconnect:x -x = 0 to never allow disconnects, 2 to always allow them. - * x = 1 does 'adaptive' disconnects, which is the default - * and generally the best choice. - * - debug:x -If 'DEBUGGING_ON' is defined, x is a bitmask that causes - * various types of debug output to printed - see the DB_xxx - * defines in in2000.h - * - proc:x -If 'PROC_INTERFACE' is defined, x is a bitmask that - * determines how the /proc interface works and what it - * does - see the PR_xxx defines in in2000.h - * - * Syntax Notes: - * - Numeric arguments can be decimal or the '0x' form of hex notation. There - * _must_ be a colon between a keyword and its numeric argument, with no - * spaces. - * - Keywords are separated by commas, no spaces, in the standard kernel - * command-line manner. - * - A keyword in the 'nth' comma-separated command-line member will overwrite - * the 'nth' element of setup_args[]. A blank command-line member (in - * other words, a comma with no preceding keyword) will _not_ overwrite - * the corresponding setup_args[] element. - * - * A few LILO examples (for insmod, use 'setup_strings' instead of 'in2000'): - * - in2000=ioport:0x220,noreset - * - in2000=period:250,disconnect:2,nosync:0x03 - * - in2000=debug:0x1e - * - in2000=proc:3 - */ - -/* Normally, no defaults are specified... */ -static char *setup_args[] = { "", "", "", "", "", "", "", "", "" }; - -/* filled in by 'insmod' */ -static char *setup_strings; - -module_param(setup_strings, charp, 0); - -static inline uchar read_3393(struct IN2000_hostdata *hostdata, uchar reg_num) -{ - write1_io(reg_num, IO_WD_ADDR); - return read1_io(IO_WD_DATA); -} - - -#define READ_AUX_STAT() read1_io(IO_WD_ASR) - - -static inline void write_3393(struct IN2000_hostdata *hostdata, uchar reg_num, uchar value) -{ - write1_io(reg_num, IO_WD_ADDR); - write1_io(value, IO_WD_DATA); -} - - -static inline void write_3393_cmd(struct IN2000_hostdata *hostdata, uchar cmd) -{ -/* while (READ_AUX_STAT() & ASR_CIP) - printk("|");*/ - write1_io(WD_COMMAND, IO_WD_ADDR); - write1_io(cmd, IO_WD_DATA); -} - - -static uchar read_1_byte(struct IN2000_hostdata *hostdata) -{ - uchar asr, x = 0; - - write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_3393_cmd(hostdata, WD_CMD_TRANS_INFO | 0x80); - do { - asr = READ_AUX_STAT(); - if (asr & ASR_DBR) - x = read_3393(hostdata, WD_DATA); - } while (!(asr & ASR_INT)); - return x; -} - - -static void write_3393_count(struct IN2000_hostdata *hostdata, unsigned long value) -{ - write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR); - write1_io((value >> 16), IO_WD_DATA); - write1_io((value >> 8), IO_WD_DATA); - write1_io(value, IO_WD_DATA); -} - - -static unsigned long read_3393_count(struct IN2000_hostdata *hostdata) -{ - unsigned long value; - - write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR); - value = read1_io(IO_WD_DATA) << 16; - value |= read1_io(IO_WD_DATA) << 8; - value |= read1_io(IO_WD_DATA); - return value; -} - - -/* The 33c93 needs to be told which direction a command transfers its - * data; we use this function to figure it out. Returns true if there - * will be a DATA_OUT phase with this command, false otherwise. - * (Thanks to Joerg Dorchain for the research and suggestion.) - */ -static int is_dir_out(Scsi_Cmnd * cmd) -{ - switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_LONG: - case WRITE_SAME: - case WRITE_BUFFER: - case WRITE_VERIFY: - case WRITE_VERIFY_12: - case COMPARE: - case COPY: - case COPY_VERIFY: - case SEARCH_EQUAL: - case SEARCH_HIGH: - case SEARCH_LOW: - case SEARCH_EQUAL_12: - case SEARCH_HIGH_12: - case SEARCH_LOW_12: - case FORMAT_UNIT: - case REASSIGN_BLOCKS: - case RESERVE: - case MODE_SELECT: - case MODE_SELECT_10: - case LOG_SELECT: - case SEND_DIAGNOSTIC: - case CHANGE_DEFINITION: - case UPDATE_BLOCK: - case SET_WINDOW: - case MEDIUM_SCAN: - case SEND_VOLUME_TAG: - case 0xea: - return 1; - default: - return 0; - } -} - - - -static struct sx_period sx_table[] = { - {1, 0x20}, - {252, 0x20}, - {376, 0x30}, - {500, 0x40}, - {624, 0x50}, - {752, 0x60}, - {876, 0x70}, - {1000, 0x00}, - {0, 0} -}; - -static int round_period(unsigned int period) -{ - int x; - - for (x = 1; sx_table[x].period_ns; x++) { - if ((period <= sx_table[x - 0].period_ns) && (period > sx_table[x - 1].period_ns)) { - return x; - } - } - return 7; -} - -static uchar calc_sync_xfer(unsigned int period, unsigned int offset) -{ - uchar result; - - period *= 4; /* convert SDTR code to ns */ - result = sx_table[round_period(period)].reg_value; - result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF; - return result; -} - - - -static void in2000_execute(struct Scsi_Host *instance); - -static int in2000_queuecommand_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) -{ - struct Scsi_Host *instance; - struct IN2000_hostdata *hostdata; - Scsi_Cmnd *tmp; - - instance = cmd->device->host; - hostdata = (struct IN2000_hostdata *) instance->hostdata; - - DB(DB_QUEUE_COMMAND, scmd_printk(KERN_DEBUG, cmd, "Q-%02x(", cmd->cmnd[0])) - -/* Set up a few fields in the Scsi_Cmnd structure for our own use: - * - host_scribble is the pointer to the next cmd in the input queue - * - scsi_done points to the routine we call when a cmd is finished - * - result is what you'd expect - */ - cmd->host_scribble = NULL; - cmd->scsi_done = done; - cmd->result = 0; - -/* We use the Scsi_Pointer structure that's included with each command - * as a scratchpad (as it's intended to be used!). The handy thing about - * the SCp.xxx fields is that they're always associated with a given - * cmd, and are preserved across disconnect-reselect. This means we - * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages - * if we keep all the critical pointers and counters in SCp: - * - SCp.ptr is the pointer into the RAM buffer - * - SCp.this_residual is the size of that buffer - * - SCp.buffer points to the current scatter-gather buffer - * - SCp.buffers_residual tells us how many S.G. buffers there are - * - SCp.have_data_in helps keep track of >2048 byte transfers - * - SCp.sent_command is not used - * - SCp.phase records this command's SRCID_ER bit setting - */ - - if (scsi_bufflen(cmd)) { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = NULL; - cmd->SCp.this_residual = 0; - } - cmd->SCp.have_data_in = 0; - -/* We don't set SCp.phase here - that's done in in2000_execute() */ - -/* WD docs state that at the conclusion of a "LEVEL2" command, the - * status byte can be retrieved from the LUN register. Apparently, - * this is the case only for *uninterrupted* LEVEL2 commands! If - * there are any unexpected phases entered, even if they are 100% - * legal (different devices may choose to do things differently), - * the LEVEL2 command sequence is exited. This often occurs prior - * to receiving the status byte, in which case the driver does a - * status phase interrupt and gets the status byte on its own. - * While such a command can then be "resumed" (ie restarted to - * finish up as a LEVEL2 command), the LUN register will NOT be - * a valid status byte at the command's conclusion, and we must - * use the byte obtained during the earlier interrupt. Here, we - * preset SCp.Status to an illegal value (0xff) so that when - * this command finally completes, we can tell where the actual - * status byte is stored. - */ - - cmd->SCp.Status = ILLEGAL_STATUS_BYTE; - -/* We need to disable interrupts before messing with the input - * queue and calling in2000_execute(). - */ - - /* - * Add the cmd to the end of 'input_Q'. Note that REQUEST_SENSE - * commands are added to the head of the queue so that the desired - * sense data is not lost before REQUEST_SENSE executes. - */ - - if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) { - cmd->host_scribble = (uchar *) hostdata->input_Q; - hostdata->input_Q = cmd; - } else { /* find the end of the queue */ - for (tmp = (Scsi_Cmnd *) hostdata->input_Q; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble); - tmp->host_scribble = (uchar *) cmd; - } - -/* We know that there's at least one command in 'input_Q' now. - * Go see if any of them are runnable! - */ - - in2000_execute(cmd->device->host); - - DB(DB_QUEUE_COMMAND, printk(")Q ")) - return 0; -} - -static DEF_SCSI_QCMD(in2000_queuecommand) - - - -/* - * This routine attempts to start a scsi command. If the host_card is - * already connected, we give up immediately. Otherwise, look through - * the input_Q, using the first command we find that's intended - * for a currently non-busy target/lun. - * Note that this function is always called with interrupts already - * disabled (either from in2000_queuecommand() or in2000_intr()). - */ -static void in2000_execute(struct Scsi_Host *instance) -{ - struct IN2000_hostdata *hostdata; - Scsi_Cmnd *cmd, *prev; - int i; - unsigned short *sp; - unsigned short f; - unsigned short flushbuf[16]; - - - hostdata = (struct IN2000_hostdata *) instance->hostdata; - - DB(DB_EXECUTE, printk("EX(")) - - if (hostdata->selecting || hostdata->connected) { - - DB(DB_EXECUTE, printk(")EX-0 ")) - - return; - } - - /* - * Search through the input_Q for a command destined - * for an idle target/lun. - */ - - cmd = (Scsi_Cmnd *) hostdata->input_Q; - prev = NULL; - while (cmd) { - if (!(hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))) - break; - prev = cmd; - cmd = (Scsi_Cmnd *) cmd->host_scribble; - } - - /* quit if queue empty or all possible targets are busy */ - - if (!cmd) { - - DB(DB_EXECUTE, printk(")EX-1 ")) - - return; - } - - /* remove command from queue */ - - if (prev) - prev->host_scribble = cmd->host_scribble; - else - hostdata->input_Q = (Scsi_Cmnd *) cmd->host_scribble; - -#ifdef PROC_STATISTICS - hostdata->cmd_cnt[cmd->device->id]++; -#endif - -/* - * Start the selection process - */ - - if (is_dir_out(cmd)) - write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id); - else - write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD); - -/* Now we need to figure out whether or not this command is a good - * candidate for disconnect/reselect. We guess to the best of our - * ability, based on a set of hierarchical rules. When several - * devices are operating simultaneously, disconnects are usually - * an advantage. In a single device system, or if only 1 device - * is being accessed, transfers usually go faster if disconnects - * are not allowed: - * - * + Commands should NEVER disconnect if hostdata->disconnect = - * DIS_NEVER (this holds for tape drives also), and ALWAYS - * disconnect if hostdata->disconnect = DIS_ALWAYS. - * + Tape drive commands should always be allowed to disconnect. - * + Disconnect should be allowed if disconnected_Q isn't empty. - * + Commands should NOT disconnect if input_Q is empty. - * + Disconnect should be allowed if there are commands in input_Q - * for a different target/lun. In this case, the other commands - * should be made disconnect-able, if not already. - * - * I know, I know - this code would flunk me out of any - * "C Programming 101" class ever offered. But it's easy - * to change around and experiment with for now. - */ - - cmd->SCp.phase = 0; /* assume no disconnect */ - if (hostdata->disconnect == DIS_NEVER) - goto no; - if (hostdata->disconnect == DIS_ALWAYS) - goto yes; - if (cmd->device->type == 1) /* tape drive? */ - goto yes; - if (hostdata->disconnected_Q) /* other commands disconnected? */ - goto yes; - if (!(hostdata->input_Q)) /* input_Q empty? */ - goto no; - for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev; prev = (Scsi_Cmnd *) prev->host_scribble) { - if ((prev->device->id != cmd->device->id) || (prev->device->lun != cmd->device->lun)) { - for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev; prev = (Scsi_Cmnd *) prev->host_scribble) - prev->SCp.phase = 1; - goto yes; - } - } - goto no; - - yes: - cmd->SCp.phase = 1; - -#ifdef PROC_STATISTICS - hostdata->disc_allowed_cnt[cmd->device->id]++; -#endif - - no: - write_3393(hostdata, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0)); - - write_3393(hostdata, WD_TARGET_LUN, cmd->device->lun); - write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->device->id]); - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - - if ((hostdata->level2 <= L2_NONE) || (hostdata->sync_stat[cmd->device->id] == SS_UNSET)) { - - /* - * Do a 'Select-With-ATN' command. This will end with - * one of the following interrupts: - * CSR_RESEL_AM: failure - can try again later. - * CSR_TIMEOUT: failure - give up. - * CSR_SELECT: success - proceed. - */ - - hostdata->selecting = cmd; - -/* Every target has its own synchronous transfer setting, kept in - * the sync_xfer array, and a corresponding status byte in sync_stat[]. - * Each target's sync_stat[] entry is initialized to SS_UNSET, and its - * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET - * means that the parameters are undetermined as yet, and that we - * need to send an SDTR message to this device after selection is - * complete. We set SS_FIRST to tell the interrupt routine to do so, - * unless we don't want to even _try_ synchronous transfers: In this - * case we set SS_SET to make the defaults final. - */ - if (hostdata->sync_stat[cmd->device->id] == SS_UNSET) { - if (hostdata->sync_off & (1 << cmd->device->id)) - hostdata->sync_stat[cmd->device->id] = SS_SET; - else - hostdata->sync_stat[cmd->device->id] = SS_FIRST; - } - hostdata->state = S_SELECTING; - write_3393_count(hostdata, 0); /* this guarantees a DATA_PHASE interrupt */ - write_3393_cmd(hostdata, WD_CMD_SEL_ATN); - } - - else { - - /* - * Do a 'Select-With-ATN-Xfer' command. This will end with - * one of the following interrupts: - * CSR_RESEL_AM: failure - can try again later. - * CSR_TIMEOUT: failure - give up. - * anything else: success - proceed. - */ - - hostdata->connected = cmd; - write_3393(hostdata, WD_COMMAND_PHASE, 0); - - /* copy command_descriptor_block into WD chip - * (take advantage of auto-incrementing) - */ - - write1_io(WD_CDB_1, IO_WD_ADDR); - for (i = 0; i < cmd->cmd_len; i++) - write1_io(cmd->cmnd[i], IO_WD_DATA); - - /* The wd33c93 only knows about Group 0, 1, and 5 commands when - * it's doing a 'select-and-transfer'. To be safe, we write the - * size of the CDB into the OWN_ID register for every case. This - * way there won't be problems with vendor-unique, audio, etc. - */ - - write_3393(hostdata, WD_OWN_ID, cmd->cmd_len); - - /* When doing a non-disconnect command, we can save ourselves a DATA - * phase interrupt later by setting everything up now. With writes we - * need to pre-fill the fifo; if there's room for the 32 flush bytes, - * put them in there too - that'll avoid a fifo interrupt. Reads are - * somewhat simpler. - * KLUDGE NOTE: It seems that you can't completely fill the fifo here: - * This results in the IO_FIFO_COUNT register rolling over to zero, - * and apparently the gate array logic sees this as empty, not full, - * so the 3393 chip is never signalled to start reading from the - * fifo. Or maybe it's seen as a permanent fifo interrupt condition. - * Regardless, we fix this by temporarily pretending that the fifo - * is 16 bytes smaller. (I see now that the old driver has a comment - * about "don't fill completely" in an analogous place - must be the - * same deal.) This results in CDROM, swap partitions, and tape drives - * needing an extra interrupt per write command - I think we can live - * with that! - */ - - if (!(cmd->SCp.phase)) { - write_3393_count(hostdata, cmd->SCp.this_residual); - write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS); - write1_io(0, IO_FIFO_WRITE); /* clear fifo counter, write mode */ - - if (is_dir_out(cmd)) { - hostdata->fifo = FI_FIFO_WRITING; - if ((i = cmd->SCp.this_residual) > (IN2000_FIFO_SIZE - 16)) - i = IN2000_FIFO_SIZE - 16; - cmd->SCp.have_data_in = i; /* this much data in fifo */ - i >>= 1; /* Gulp. Assuming modulo 2. */ - sp = (unsigned short *) cmd->SCp.ptr; - f = hostdata->io_base + IO_FIFO; - -#ifdef FAST_WRITE_IO - - FAST_WRITE2_IO(); -#else - while (i--) - write2_io(*sp++, IO_FIFO); - -#endif - - /* Is there room for the flush bytes? */ - - if (cmd->SCp.have_data_in <= ((IN2000_FIFO_SIZE - 16) - 32)) { - sp = flushbuf; - i = 16; - -#ifdef FAST_WRITE_IO - - FAST_WRITE2_IO(); -#else - while (i--) - write2_io(0, IO_FIFO); - -#endif - - } - } - - else { - write1_io(0, IO_FIFO_READ); /* put fifo in read mode */ - hostdata->fifo = FI_FIFO_READING; - cmd->SCp.have_data_in = 0; /* nothing transferred yet */ - } - - } else { - write_3393_count(hostdata, 0); /* this guarantees a DATA_PHASE interrupt */ - } - hostdata->state = S_RUNNING_LEVEL2; - write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER); - } - - /* - * Since the SCSI bus can handle only 1 connection at a time, - * we get out of here now. If the selection fails, or when - * the command disconnects, we'll come back to this routine - * to search the input_Q again... - */ - - DB(DB_EXECUTE, printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : "")) - -} - - - -static void transfer_pio(uchar * buf, int cnt, int data_in_dir, struct IN2000_hostdata *hostdata) -{ - uchar asr; - - DB(DB_TRANSFER, printk("(%p,%d,%s)", buf, cnt, data_in_dir ? "in" : "out")) - - write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_3393_count(hostdata, cnt); - write_3393_cmd(hostdata, WD_CMD_TRANS_INFO); - if (data_in_dir) { - do { - asr = READ_AUX_STAT(); - if (asr & ASR_DBR) - *buf++ = read_3393(hostdata, WD_DATA); - } while (!(asr & ASR_INT)); - } else { - do { - asr = READ_AUX_STAT(); - if (asr & ASR_DBR) - write_3393(hostdata, WD_DATA, *buf++); - } while (!(asr & ASR_INT)); - } - - /* Note: we are returning with the interrupt UN-cleared. - * Since (presumably) an entire I/O operation has - * completed, the bus phase is probably different, and - * the interrupt routine will discover this when it - * responds to the uncleared int. - */ - -} - - - -static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir) -{ - struct IN2000_hostdata *hostdata; - unsigned short *sp; - unsigned short f; - int i; - - hostdata = (struct IN2000_hostdata *) cmd->device->host->hostdata; - -/* Normally, you'd expect 'this_residual' to be non-zero here. - * In a series of scatter-gather transfers, however, this - * routine will usually be called with 'this_residual' equal - * to 0 and 'buffers_residual' non-zero. This means that a - * previous transfer completed, clearing 'this_residual', and - * now we need to setup the next scatter-gather buffer as the - * source or destination for THIS transfer. - */ - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - } - -/* Set up hardware registers */ - - write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->device->id]); - write_3393_count(hostdata, cmd->SCp.this_residual); - write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS); - write1_io(0, IO_FIFO_WRITE); /* zero counter, assume write */ - -/* Reading is easy. Just issue the command and return - we'll - * get an interrupt later when we have actual data to worry about. - */ - - if (data_in_dir) { - write1_io(0, IO_FIFO_READ); - if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) { - write_3393(hostdata, WD_COMMAND_PHASE, 0x45); - write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } else - write_3393_cmd(hostdata, WD_CMD_TRANS_INFO); - hostdata->fifo = FI_FIFO_READING; - cmd->SCp.have_data_in = 0; - return; - } - -/* Writing is more involved - we'll start the WD chip and write as - * much data to the fifo as we can right now. Later interrupts will - * write any bytes that don't make it at this stage. - */ - - if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) { - write_3393(hostdata, WD_COMMAND_PHASE, 0x45); - write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } else - write_3393_cmd(hostdata, WD_CMD_TRANS_INFO); - hostdata->fifo = FI_FIFO_WRITING; - sp = (unsigned short *) cmd->SCp.ptr; - - if ((i = cmd->SCp.this_residual) > IN2000_FIFO_SIZE) - i = IN2000_FIFO_SIZE; - cmd->SCp.have_data_in = i; - i >>= 1; /* Gulp. We assume this_residual is modulo 2 */ - f = hostdata->io_base + IO_FIFO; - -#ifdef FAST_WRITE_IO - - FAST_WRITE2_IO(); -#else - while (i--) - write2_io(*sp++, IO_FIFO); - -#endif - -} - - -/* We need to use spin_lock_irqsave() & spin_unlock_irqrestore() in this - * function in order to work in an SMP environment. (I'd be surprised - * if the driver is ever used by anyone on a real multi-CPU motherboard, - * but it _does_ need to be able to compile and run in an SMP kernel.) - */ - -static irqreturn_t in2000_intr(int irqnum, void *dev_id) -{ - struct Scsi_Host *instance = dev_id; - struct IN2000_hostdata *hostdata; - Scsi_Cmnd *patch, *cmd; - uchar asr, sr, phs, id, lun, *ucp, msg; - int i, j; - unsigned long length; - unsigned short *sp; - unsigned short f; - unsigned long flags; - - hostdata = (struct IN2000_hostdata *) instance->hostdata; - -/* Get the spin_lock and disable further ints, for SMP */ - - spin_lock_irqsave(instance->host_lock, flags); - -#ifdef PROC_STATISTICS - hostdata->int_cnt++; -#endif - -/* The IN2000 card has 2 interrupt sources OR'ed onto its IRQ line - the - * WD3393 chip and the 2k fifo (which is actually a dual-port RAM combined - * with a big logic array, so it's a little different than what you might - * expect). As far as I know, there's no reason that BOTH can't be active - * at the same time, but there's a problem: while we can read the 3393 - * to tell if _it_ wants an interrupt, I don't know of a way to ask the - * fifo the same question. The best we can do is check the 3393 and if - * it _isn't_ the source of the interrupt, then we can be pretty sure - * that the fifo is the culprit. - * UPDATE: I have it on good authority (Bill Earnest) that bit 0 of the - * IO_FIFO_COUNT register mirrors the fifo interrupt state. I - * assume that bit clear means interrupt active. As it turns - * out, the driver really doesn't need to check for this after - * all, so my remarks above about a 'problem' can safely be - * ignored. The way the logic is set up, there's no advantage - * (that I can see) to worrying about it. - * - * It seems that the fifo interrupt signal is negated when we extract - * bytes during read or write bytes during write. - * - fifo will interrupt when data is moving from it to the 3393, and - * there are 31 (or less?) bytes left to go. This is sort of short- - * sighted: what if you don't WANT to do more? In any case, our - * response is to push more into the fifo - either actual data or - * dummy bytes if need be. Note that we apparently have to write at - * least 32 additional bytes to the fifo after an interrupt in order - * to get it to release the ones it was holding on to - writing fewer - * than 32 will result in another fifo int. - * UPDATE: Again, info from Bill Earnest makes this more understandable: - * 32 bytes = two counts of the fifo counter register. He tells - * me that the fifo interrupt is a non-latching signal derived - * from a straightforward boolean interpretation of the 7 - * highest bits of the fifo counter and the fifo-read/fifo-write - * state. Who'd a thought? - */ - - write1_io(0, IO_LED_ON); - asr = READ_AUX_STAT(); - if (!(asr & ASR_INT)) { /* no WD33c93 interrupt? */ - -/* Ok. This is definitely a FIFO-only interrupt. - * - * If FI_FIFO_READING is set, there are up to 2048 bytes waiting to be read, - * maybe more to come from the SCSI bus. Read as many as we can out of the - * fifo and into memory at the location of SCp.ptr[SCp.have_data_in], and - * update have_data_in afterwards. - * - * If we have FI_FIFO_WRITING, the FIFO has almost run out of bytes to move - * into the WD3393 chip (I think the interrupt happens when there are 31 - * bytes left, but it may be fewer...). The 3393 is still waiting, so we - * shove some more into the fifo, which gets things moving again. If the - * original SCSI command specified more than 2048 bytes, there may still - * be some of that data left: fine - use it (from SCp.ptr[SCp.have_data_in]). - * Don't forget to update have_data_in. If we've already written out the - * entire buffer, feed 32 dummy bytes to the fifo - they're needed to - * push out the remaining real data. - * (Big thanks to Bill Earnest for getting me out of the mud in here.) - */ - - cmd = (Scsi_Cmnd *) hostdata->connected; /* assume we're connected */ - CHECK_NULL(cmd, "fifo_int") - - if (hostdata->fifo == FI_FIFO_READING) { - - DB(DB_FIFO, printk("{R:%02x} ", read1_io(IO_FIFO_COUNT))) - - sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in); - i = read1_io(IO_FIFO_COUNT) & 0xfe; - i <<= 2; /* # of words waiting in the fifo */ - f = hostdata->io_base + IO_FIFO; - -#ifdef FAST_READ_IO - - FAST_READ2_IO(); -#else - while (i--) - *sp++ = read2_io(IO_FIFO); - -#endif - - i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in); - i <<= 1; - cmd->SCp.have_data_in += i; - } - - else if (hostdata->fifo == FI_FIFO_WRITING) { - - DB(DB_FIFO, printk("{W:%02x} ", read1_io(IO_FIFO_COUNT))) - -/* If all bytes have been written to the fifo, flush out the stragglers. - * Note that while writing 16 dummy words seems arbitrary, we don't - * have another choice that I can see. What we really want is to read - * the 3393 transfer count register (that would tell us how many bytes - * needed flushing), but the TRANSFER_INFO command hasn't completed - * yet (not enough bytes!) and that register won't be accessible. So, - * we use 16 words - a number obtained through trial and error. - * UPDATE: Bill says this is exactly what Always does, so there. - * More thanks due him for help in this section. - */ - if (cmd->SCp.this_residual == cmd->SCp.have_data_in) { - i = 16; - while (i--) /* write 32 dummy bytes */ - write2_io(0, IO_FIFO); - } - -/* If there are still bytes left in the SCSI buffer, write as many as we - * can out to the fifo. - */ - - else { - sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in); - i = cmd->SCp.this_residual - cmd->SCp.have_data_in; /* bytes yet to go */ - j = read1_io(IO_FIFO_COUNT) & 0xfe; - j <<= 2; /* how many words the fifo has room for */ - if ((j << 1) > i) - j = (i >> 1); - while (j--) - write2_io(*sp++, IO_FIFO); - - i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in); - i <<= 1; - cmd->SCp.have_data_in += i; - } - } - - else { - printk("*** Spurious FIFO interrupt ***"); - } - - write1_io(0, IO_LED_OFF); - -/* release the SMP spin_lock and restore irq state */ - spin_unlock_irqrestore(instance->host_lock, flags); - return IRQ_HANDLED; - } - -/* This interrupt was triggered by the WD33c93 chip. The fifo interrupt - * may also be asserted, but we don't bother to check it: we get more - * detailed info from FIFO_READING and FIFO_WRITING (see below). - */ - - cmd = (Scsi_Cmnd *) hostdata->connected; /* assume we're connected */ - sr = read_3393(hostdata, WD_SCSI_STATUS); /* clear the interrupt */ - phs = read_3393(hostdata, WD_COMMAND_PHASE); - - if (!cmd && (sr != CSR_RESEL_AM && sr != CSR_TIMEOUT && sr != CSR_SELECT)) { - printk("\nNR:wd-intr-1\n"); - write1_io(0, IO_LED_OFF); - -/* release the SMP spin_lock and restore irq state */ - spin_unlock_irqrestore(instance->host_lock, flags); - return IRQ_HANDLED; - } - - DB(DB_INTR, printk("{%02x:%02x-", asr, sr)) - -/* After starting a FIFO-based transfer, the next _WD3393_ interrupt is - * guaranteed to be in response to the completion of the transfer. - * If we were reading, there's probably data in the fifo that needs - * to be copied into RAM - do that here. Also, we have to update - * 'this_residual' and 'ptr' based on the contents of the - * TRANSFER_COUNT register, in case the device decided to do an - * intermediate disconnect (a device may do this if it has to - * do a seek, or just to be nice and let other devices have - * some bus time during long transfers). - * After doing whatever is necessary with the fifo, we go on and - * service the WD3393 interrupt normally. - */ - if (hostdata->fifo == FI_FIFO_READING) { - -/* buffer index = start-of-buffer + #-of-bytes-already-read */ - - sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in); - -/* bytes remaining in fifo = (total-wanted - #-not-got) - #-already-read */ - - i = (cmd->SCp.this_residual - read_3393_count(hostdata)) - cmd->SCp.have_data_in; - i >>= 1; /* Gulp. We assume this will always be modulo 2 */ - f = hostdata->io_base + IO_FIFO; - -#ifdef FAST_READ_IO - - FAST_READ2_IO(); -#else - while (i--) - *sp++ = read2_io(IO_FIFO); - -#endif - - hostdata->fifo = FI_FIFO_UNUSED; - length = cmd->SCp.this_residual; - cmd->SCp.this_residual = read_3393_count(hostdata); - cmd->SCp.ptr += (length - cmd->SCp.this_residual); - - DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual)) - - } - - else if (hostdata->fifo == FI_FIFO_WRITING) { - hostdata->fifo = FI_FIFO_UNUSED; - length = cmd->SCp.this_residual; - cmd->SCp.this_residual = read_3393_count(hostdata); - cmd->SCp.ptr += (length - cmd->SCp.this_residual); - - DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual)) - - } - -/* Respond to the specific WD3393 interrupt - there are quite a few! */ - - switch (sr) { - - case CSR_TIMEOUT: - DB(DB_INTR, printk("TIMEOUT")) - - if (hostdata->state == S_RUNNING_LEVEL2) - hostdata->connected = NULL; - else { - cmd = (Scsi_Cmnd *) hostdata->selecting; /* get a valid cmd */ - CHECK_NULL(cmd, "csr_timeout") - hostdata->selecting = NULL; - } - - cmd->result = DID_NO_CONNECT << 16; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->state = S_UNCONNECTED; - cmd->scsi_done(cmd); - -/* We are not connected to a target - check to see if there - * are commands waiting to be executed. - */ - - in2000_execute(instance); - break; - - -/* Note: this interrupt should not occur in a LEVEL2 command */ - - case CSR_SELECT: - DB(DB_INTR, printk("SELECT")) - hostdata->connected = cmd = (Scsi_Cmnd *) hostdata->selecting; - CHECK_NULL(cmd, "csr_select") - hostdata->selecting = NULL; - - /* construct an IDENTIFY message with correct disconnect bit */ - - hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun); - if (cmd->SCp.phase) - hostdata->outgoing_msg[0] |= 0x40; - - if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) { -#ifdef SYNC_DEBUG - printk(" sending SDTR "); -#endif - - hostdata->sync_stat[cmd->device->id] = SS_WAITING; - - /* tack on a 2nd message to ask about synchronous transfers */ - - hostdata->outgoing_msg[1] = EXTENDED_MESSAGE; - hostdata->outgoing_msg[2] = 3; - hostdata->outgoing_msg[3] = EXTENDED_SDTR; - hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4; - hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF; - hostdata->outgoing_len = 6; - } else - hostdata->outgoing_len = 1; - - hostdata->state = S_CONNECTED; - break; - - - case CSR_XFER_DONE | PHS_DATA_IN: - case CSR_UNEXP | PHS_DATA_IN: - case CSR_SRV_REQ | PHS_DATA_IN: - DB(DB_INTR, printk("IN-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual)) - transfer_bytes(cmd, DATA_IN_DIR); - if (hostdata->state != S_RUNNING_LEVEL2) - hostdata->state = S_CONNECTED; - break; - - - case CSR_XFER_DONE | PHS_DATA_OUT: - case CSR_UNEXP | PHS_DATA_OUT: - case CSR_SRV_REQ | PHS_DATA_OUT: - DB(DB_INTR, printk("OUT-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual)) - transfer_bytes(cmd, DATA_OUT_DIR); - if (hostdata->state != S_RUNNING_LEVEL2) - hostdata->state = S_CONNECTED; - break; - - -/* Note: this interrupt should not occur in a LEVEL2 command */ - - case CSR_XFER_DONE | PHS_COMMAND: - case CSR_UNEXP | PHS_COMMAND: - case CSR_SRV_REQ | PHS_COMMAND: - DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0])) - transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); - hostdata->state = S_CONNECTED; - break; - - - case CSR_XFER_DONE | PHS_STATUS: - case CSR_UNEXP | PHS_STATUS: - case CSR_SRV_REQ | PHS_STATUS: - DB(DB_INTR, printk("STATUS=")) - - cmd->SCp.Status = read_1_byte(hostdata); - DB(DB_INTR, printk("%02x", cmd->SCp.Status)) - if (hostdata->level2 >= L2_BASIC) { - sr = read_3393(hostdata, WD_SCSI_STATUS); /* clear interrupt */ - hostdata->state = S_RUNNING_LEVEL2; - write_3393(hostdata, WD_COMMAND_PHASE, 0x50); - write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER); - } else { - hostdata->state = S_CONNECTED; - } - break; - - - case CSR_XFER_DONE | PHS_MESS_IN: - case CSR_UNEXP | PHS_MESS_IN: - case CSR_SRV_REQ | PHS_MESS_IN: - DB(DB_INTR, printk("MSG_IN=")) - - msg = read_1_byte(hostdata); - sr = read_3393(hostdata, WD_SCSI_STATUS); /* clear interrupt */ - - hostdata->incoming_msg[hostdata->incoming_ptr] = msg; - if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE) - msg = EXTENDED_MESSAGE; - else - hostdata->incoming_ptr = 0; - - cmd->SCp.Message = msg; - switch (msg) { - - case COMMAND_COMPLETE: - DB(DB_INTR, printk("CCMP")) - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_PRE_CMP_DISC; - break; - - case SAVE_POINTERS: - DB(DB_INTR, printk("SDP")) - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - - case RESTORE_POINTERS: - DB(DB_INTR, printk("RDP")) - if (hostdata->level2 >= L2_BASIC) { - write_3393(hostdata, WD_COMMAND_PHASE, 0x45); - write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } else { - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - break; - - case DISCONNECT: - DB(DB_INTR, printk("DIS")) - cmd->device->disconnect = 1; - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_PRE_TMP_DISC; - break; - - case MESSAGE_REJECT: - DB(DB_INTR, printk("REJ")) -#ifdef SYNC_DEBUG - printk("-REJ-"); -#endif - if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) - hostdata->sync_stat[cmd->device->id] = SS_SET; - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - - case EXTENDED_MESSAGE: - DB(DB_INTR, printk("EXT")) - - ucp = hostdata->incoming_msg; - -#ifdef SYNC_DEBUG - printk("%02x", ucp[hostdata->incoming_ptr]); -#endif - /* Is this the last byte of the extended message? */ - - if ((hostdata->incoming_ptr >= 2) && (hostdata->incoming_ptr == (ucp[1] + 1))) { - - switch (ucp[2]) { /* what's the EXTENDED code? */ - case EXTENDED_SDTR: - id = calc_sync_xfer(ucp[3], ucp[4]); - if (hostdata->sync_stat[cmd->device->id] != SS_WAITING) { - -/* A device has sent an unsolicited SDTR message; rather than go - * through the effort of decoding it and then figuring out what - * our reply should be, we're just gonna say that we have a - * synchronous fifo depth of 0. This will result in asynchronous - * transfers - not ideal but so much easier. - * Actually, this is OK because it assures us that if we don't - * specifically ask for sync transfers, we won't do any. - */ - - write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; - hostdata->outgoing_msg[1] = 3; - hostdata->outgoing_msg[2] = EXTENDED_SDTR; - hostdata->outgoing_msg[3] = hostdata->default_sx_per / 4; - hostdata->outgoing_msg[4] = 0; - hostdata->outgoing_len = 5; - hostdata->sync_xfer[cmd->device->id] = calc_sync_xfer(hostdata->default_sx_per / 4, 0); - } else { - hostdata->sync_xfer[cmd->device->id] = id; - } -#ifdef SYNC_DEBUG - printk("sync_xfer=%02x", hostdata->sync_xfer[cmd->device->id]); -#endif - hostdata->sync_stat[cmd->device->id] = SS_SET; - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - case EXTENDED_WDTR: - write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - printk("sending WDTR "); - hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; - hostdata->outgoing_msg[1] = 2; - hostdata->outgoing_msg[2] = EXTENDED_WDTR; - hostdata->outgoing_msg[3] = 0; /* 8 bit transfer width */ - hostdata->outgoing_len = 4; - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - default: - write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - printk("Rejecting Unknown Extended Message(%02x). ", ucp[2]); - hostdata->outgoing_msg[0] = MESSAGE_REJECT; - hostdata->outgoing_len = 1; - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - } - hostdata->incoming_ptr = 0; - } - - /* We need to read more MESS_IN bytes for the extended message */ - - else { - hostdata->incoming_ptr++; - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - break; - - default: - printk("Rejecting Unknown Message(%02x) ", msg); - write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - hostdata->outgoing_msg[0] = MESSAGE_REJECT; - hostdata->outgoing_len = 1; - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - break; - - -/* Note: this interrupt will occur only after a LEVEL2 command */ - - case CSR_SEL_XFER_DONE: - -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ - - write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); - if (phs == 0x60) { - DB(DB_INTR, printk("SX-DONE")) - cmd->SCp.Message = COMMAND_COMPLETE; - lun = read_3393(hostdata, WD_TARGET_LUN); - DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) - hostdata->connected = NULL; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->state = S_UNCONNECTED; - if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE) - cmd->SCp.Status = lun; - if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - else - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - cmd->scsi_done(cmd); - -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ - - in2000_execute(instance); - } else { - printk("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs); - } - break; - - -/* Note: this interrupt will occur only after a LEVEL2 command */ - - case CSR_SDP: - DB(DB_INTR, printk("SDP")) - hostdata->state = S_RUNNING_LEVEL2; - write_3393(hostdata, WD_COMMAND_PHASE, 0x41); - write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER); - break; - - - case CSR_XFER_DONE | PHS_MESS_OUT: - case CSR_UNEXP | PHS_MESS_OUT: - case CSR_SRV_REQ | PHS_MESS_OUT: - DB(DB_INTR, printk("MSG_OUT=")) - -/* To get here, we've probably requested MESSAGE_OUT and have - * already put the correct bytes in outgoing_msg[] and filled - * in outgoing_len. We simply send them out to the SCSI bus. - * Sometimes we get MESSAGE_OUT phase when we're not expecting - * it - like when our SDTR message is rejected by a target. Some - * targets send the REJECT before receiving all of the extended - * message, and then seem to go back to MESSAGE_OUT for a byte - * or two. Not sure why, or if I'm doing something wrong to - * cause this to happen. Regardless, it seems that sending - * NOP messages in these situations results in no harm and - * makes everyone happy. - */ - if (hostdata->outgoing_len == 0) { - hostdata->outgoing_len = 1; - hostdata->outgoing_msg[0] = NOP; - } - transfer_pio(hostdata->outgoing_msg, hostdata->outgoing_len, DATA_OUT_DIR, hostdata); - DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0])) - hostdata->outgoing_len = 0; - hostdata->state = S_CONNECTED; - break; - - - case CSR_UNEXP_DISC: - -/* I think I've seen this after a request-sense that was in response - * to an error condition, but not sure. We certainly need to do - * something when we get this interrupt - the question is 'what?'. - * Let's think positively, and assume some command has finished - * in a legal manner (like a command that provokes a request-sense), - * so we treat it as a normal command-complete-disconnect. - */ - - -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ - - write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); - if (cmd == NULL) { - printk(" - Already disconnected! "); - hostdata->state = S_UNCONNECTED; - -/* release the SMP spin_lock and restore irq state */ - spin_unlock_irqrestore(instance->host_lock, flags); - return IRQ_HANDLED; - } - DB(DB_INTR, printk("UNEXP_DISC")) - hostdata->connected = NULL; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->state = S_UNCONNECTED; - if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - else - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - cmd->scsi_done(cmd); - -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ - - in2000_execute(instance); - break; - - - case CSR_DISC: - -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ - - write_3393(hostdata, WD_SOURCE_ID, SRCID_ER); - DB(DB_INTR, printk("DISC")) - if (cmd == NULL) { - printk(" - Already disconnected! "); - hostdata->state = S_UNCONNECTED; - } - switch (hostdata->state) { - case S_PRE_CMP_DISC: - hostdata->connected = NULL; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->state = S_UNCONNECTED; - DB(DB_INTR, printk(":%d", cmd->SCp.Status)) - if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - else - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - cmd->scsi_done(cmd); - break; - case S_PRE_TMP_DISC: - case S_RUNNING_LEVEL2: - cmd->host_scribble = (uchar *) hostdata->disconnected_Q; - hostdata->disconnected_Q = cmd; - hostdata->connected = NULL; - hostdata->state = S_UNCONNECTED; - -#ifdef PROC_STATISTICS - hostdata->disc_done_cnt[cmd->device->id]++; -#endif - - break; - default: - printk("*** Unexpected DISCONNECT interrupt! ***"); - hostdata->state = S_UNCONNECTED; - } - -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ - - in2000_execute(instance); - break; - - - case CSR_RESEL_AM: - DB(DB_INTR, printk("RESEL")) - - /* First we have to make sure this reselection didn't */ - /* happen during Arbitration/Selection of some other device. */ - /* If yes, put losing command back on top of input_Q. */ - if (hostdata->level2 <= L2_NONE) { - - if (hostdata->selecting) { - cmd = (Scsi_Cmnd *) hostdata->selecting; - hostdata->selecting = NULL; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - cmd->host_scribble = (uchar *) hostdata->input_Q; - hostdata->input_Q = cmd; - } - } - - else { - - if (cmd) { - if (phs == 0x00) { - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - cmd->host_scribble = (uchar *) hostdata->input_Q; - hostdata->input_Q = cmd; - } else { - printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---", asr, sr, phs); - while (1) - printk("\r"); - } - } - - } - - /* OK - find out which device reselected us. */ - - id = read_3393(hostdata, WD_SOURCE_ID); - id &= SRCID_MASK; - - /* and extract the lun from the ID message. (Note that we don't - * bother to check for a valid message here - I guess this is - * not the right way to go, but....) - */ - - lun = read_3393(hostdata, WD_DATA); - if (hostdata->level2 < L2_RESELECT) - write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK); - lun &= 7; - - /* Now we look for the command that's reconnecting. */ - - cmd = (Scsi_Cmnd *) hostdata->disconnected_Q; - patch = NULL; - while (cmd) { - if (id == cmd->device->id && lun == cmd->device->lun) - break; - patch = cmd; - cmd = (Scsi_Cmnd *) cmd->host_scribble; - } - - /* Hmm. Couldn't find a valid command.... What to do? */ - - if (!cmd) { - printk("---TROUBLE: target %d.%d not in disconnect queue---", id, lun); - break; - } - - /* Ok, found the command - now start it up again. */ - - if (patch) - patch->host_scribble = cmd->host_scribble; - else - hostdata->disconnected_Q = (Scsi_Cmnd *) cmd->host_scribble; - hostdata->connected = cmd; - - /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]' - * because these things are preserved over a disconnect. - * But we DO need to fix the DPD bit so it's correct for this command. - */ - - if (is_dir_out(cmd)) - write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id); - else - write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD); - if (hostdata->level2 >= L2_RESELECT) { - write_3393_count(hostdata, 0); /* we want a DATA_PHASE interrupt */ - write_3393(hostdata, WD_COMMAND_PHASE, 0x45); - write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } else - hostdata->state = S_CONNECTED; - - break; - - default: - printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs); - } - - write1_io(0, IO_LED_OFF); - - DB(DB_INTR, printk("} ")) - -/* release the SMP spin_lock and restore irq state */ - spin_unlock_irqrestore(instance->host_lock, flags); - return IRQ_HANDLED; -} - - - -#define RESET_CARD 0 -#define RESET_CARD_AND_BUS 1 -#define B_FLAG 0x80 - -/* - * Caller must hold instance lock! - */ - -static int reset_hardware(struct Scsi_Host *instance, int type) -{ - struct IN2000_hostdata *hostdata; - int qt, x; - - hostdata = (struct IN2000_hostdata *) instance->hostdata; - - write1_io(0, IO_LED_ON); - if (type == RESET_CARD_AND_BUS) { - write1_io(0, IO_CARD_RESET); - x = read1_io(IO_HARDWARE); - } - x = read_3393(hostdata, WD_SCSI_STATUS); /* clear any WD intrpt */ - write_3393(hostdata, WD_OWN_ID, instance->this_id | OWNID_EAF | OWNID_RAF | OWNID_FS_8); - write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, calc_sync_xfer(hostdata->default_sx_per / 4, DEFAULT_SX_OFF)); - - write1_io(0, IO_FIFO_WRITE); /* clear fifo counter */ - write1_io(0, IO_FIFO_READ); /* start fifo out in read mode */ - write_3393(hostdata, WD_COMMAND, WD_CMD_RESET); - /* FIXME: timeout ?? */ - while (!(READ_AUX_STAT() & ASR_INT)) - cpu_relax(); /* wait for RESET to complete */ - - x = read_3393(hostdata, WD_SCSI_STATUS); /* clear interrupt */ - - write_3393(hostdata, WD_QUEUE_TAG, 0xa5); /* any random number */ - qt = read_3393(hostdata, WD_QUEUE_TAG); - if (qt == 0xa5) { - x |= B_FLAG; - write_3393(hostdata, WD_QUEUE_TAG, 0); - } - write_3393(hostdata, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); - write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write1_io(0, IO_LED_OFF); - return x; -} - - - -static int in2000_bus_reset(Scsi_Cmnd * cmd) -{ - struct Scsi_Host *instance; - struct IN2000_hostdata *hostdata; - int x; - unsigned long flags; - - instance = cmd->device->host; - hostdata = (struct IN2000_hostdata *) instance->hostdata; - - printk(KERN_WARNING "scsi%d: Reset. ", instance->host_no); - - spin_lock_irqsave(instance->host_lock, flags); - - /* do scsi-reset here */ - reset_hardware(instance, RESET_CARD_AND_BUS); - for (x = 0; x < 8; x++) { - hostdata->busy[x] = 0; - hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF); - hostdata->sync_stat[x] = SS_UNSET; /* using default sync values */ - } - hostdata->input_Q = NULL; - hostdata->selecting = NULL; - hostdata->connected = NULL; - hostdata->disconnected_Q = NULL; - hostdata->state = S_UNCONNECTED; - hostdata->fifo = FI_FIFO_UNUSED; - hostdata->incoming_ptr = 0; - hostdata->outgoing_len = 0; - - cmd->result = DID_RESET << 16; - - spin_unlock_irqrestore(instance->host_lock, flags); - return SUCCESS; -} - -static int __in2000_abort(Scsi_Cmnd * cmd) -{ - struct Scsi_Host *instance; - struct IN2000_hostdata *hostdata; - Scsi_Cmnd *tmp, *prev; - uchar sr, asr; - unsigned long timeout; - - instance = cmd->device->host; - hostdata = (struct IN2000_hostdata *) instance->hostdata; - - printk(KERN_DEBUG "scsi%d: Abort-", instance->host_no); - printk("(asr=%02x,count=%ld,resid=%d,buf_resid=%d,have_data=%d,FC=%02x)- ", READ_AUX_STAT(), read_3393_count(hostdata), cmd->SCp.this_residual, cmd->SCp.buffers_residual, cmd->SCp.have_data_in, read1_io(IO_FIFO_COUNT)); - -/* - * Case 1 : If the command hasn't been issued yet, we simply remove it - * from the inout_Q. - */ - - tmp = (Scsi_Cmnd *) hostdata->input_Q; - prev = NULL; - while (tmp) { - if (tmp == cmd) { - if (prev) - prev->host_scribble = cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->result = DID_ABORT << 16; - printk(KERN_WARNING "scsi%d: Abort - removing command from input_Q. ", instance->host_no); - cmd->scsi_done(cmd); - return SUCCESS; - } - prev = tmp; - tmp = (Scsi_Cmnd *) tmp->host_scribble; - } - -/* - * Case 2 : If the command is connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. - * - * Timeouts, and therefore aborted commands, will be highly unlikely - * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. - */ - - if (hostdata->connected == cmd) { - - printk(KERN_WARNING "scsi%d: Aborting connected command - ", instance->host_no); - - printk("sending wd33c93 ABORT command - "); - write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_3393_cmd(hostdata, WD_CMD_ABORT); - -/* Now we have to attempt to flush out the FIFO... */ - - printk("flushing fifo - "); - timeout = 1000000; - do { - asr = READ_AUX_STAT(); - if (asr & ASR_DBR) - read_3393(hostdata, WD_DATA); - } while (!(asr & ASR_INT) && timeout-- > 0); - sr = read_3393(hostdata, WD_SCSI_STATUS); - printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", asr, sr, read_3393_count(hostdata), timeout); - - /* - * Abort command processed. - * Still connected. - * We must disconnect. - */ - - printk("sending wd33c93 DISCONNECT command - "); - write_3393_cmd(hostdata, WD_CMD_DISCONNECT); - - timeout = 1000000; - asr = READ_AUX_STAT(); - while ((asr & ASR_CIP) && timeout-- > 0) - asr = READ_AUX_STAT(); - sr = read_3393(hostdata, WD_SCSI_STATUS); - printk("asr=%02x, sr=%02x.", asr, sr); - - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->connected = NULL; - hostdata->state = S_UNCONNECTED; - cmd->result = DID_ABORT << 16; - cmd->scsi_done(cmd); - - in2000_execute(instance); - - return SUCCESS; - } - -/* - * Case 3: If the command is currently disconnected from the bus, - * we're not going to expend much effort here: Let's just return - * an ABORT_SNOOZE and hope for the best... - */ - - for (tmp = (Scsi_Cmnd *) hostdata->disconnected_Q; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble) - if (cmd == tmp) { - printk(KERN_DEBUG "scsi%d: unable to abort disconnected command.\n", instance->host_no); - return FAILED; - } - -/* - * Case 4 : If we reached this point, the command was not found in any of - * the queues. - * - * We probably reached this point because of an unlikely race condition - * between the command completing successfully and the abortion code, - * so we won't panic, but we will notify the user in case something really - * broke. - */ - - in2000_execute(instance); - - printk("scsi%d: warning : SCSI command probably completed successfully" " before abortion. ", instance->host_no); - return SUCCESS; -} - -static int in2000_abort(Scsi_Cmnd * cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __in2000_abort(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - - -#define MAX_IN2000_HOSTS 3 -#define MAX_SETUP_ARGS ARRAY_SIZE(setup_args) -#define SETUP_BUFFER_SIZE 200 -static char setup_buffer[SETUP_BUFFER_SIZE]; -static char setup_used[MAX_SETUP_ARGS]; -static int done_setup = 0; - -static void __init in2000_setup(char *str, int *ints) -{ - int i; - char *p1, *p2; - - strlcpy(setup_buffer, str, SETUP_BUFFER_SIZE); - p1 = setup_buffer; - i = 0; - while (*p1 && (i < MAX_SETUP_ARGS)) { - p2 = strchr(p1, ','); - if (p2) { - *p2 = '\0'; - if (p1 != p2) - setup_args[i] = p1; - p1 = p2 + 1; - i++; - } else { - setup_args[i] = p1; - break; - } - } - for (i = 0; i < MAX_SETUP_ARGS; i++) - setup_used[i] = 0; - done_setup = 1; -} - - -/* check_setup_args() returns index if key found, 0 if not - */ - -static int __init check_setup_args(char *key, int *val, char *buf) -{ - int x; - char *cp; - - for (x = 0; x < MAX_SETUP_ARGS; x++) { - if (setup_used[x]) - continue; - if (!strncmp(setup_args[x], key, strlen(key))) - break; - } - if (x == MAX_SETUP_ARGS) - return 0; - setup_used[x] = 1; - cp = setup_args[x] + strlen(key); - *val = -1; - if (*cp != ':') - return ++x; - cp++; - if ((*cp >= '0') && (*cp <= '9')) { - *val = simple_strtoul(cp, NULL, 0); - } - return ++x; -} - - - -/* The "correct" (ie portable) way to access memory-mapped hardware - * such as the IN2000 EPROM and dip switch is through the use of - * special macros declared in 'asm/io.h'. We use readb() and readl() - * when reading from the card's BIOS area in in2000_detect(). - */ -static u32 bios_tab[] in2000__INITDATA = { - 0xc8000, - 0xd0000, - 0xd8000, - 0 -}; - -static unsigned short base_tab[] in2000__INITDATA = { - 0x220, - 0x200, - 0x110, - 0x100, -}; - -static int int_tab[] in2000__INITDATA = { - 15, - 14, - 11, - 10 -}; - -static int probe_bios(u32 addr, u32 *s1, uchar *switches) -{ - void __iomem *p = ioremap(addr, 0x34); - if (!p) - return 0; - *s1 = readl(p + 0x10); - if (*s1 == 0x41564f4e || readl(p + 0x30) == 0x61776c41) { - /* Read the switch image that's mapped into EPROM space */ - *switches = ~readb(p + 0x20); - iounmap(p); - return 1; - } - iounmap(p); - return 0; -} - -static int __init in2000_detect(struct scsi_host_template * tpnt) -{ - struct Scsi_Host *instance; - struct IN2000_hostdata *hostdata; - int detect_count; - int bios; - int x; - unsigned short base; - uchar switches; - uchar hrev; - unsigned long flags; - int val; - char buf[32]; - -/* Thanks to help from Bill Earnest, probing for IN2000 cards is a - * pretty straightforward and fool-proof operation. There are 3 - * possible locations for the IN2000 EPROM in memory space - if we - * find a BIOS signature, we can read the dip switch settings from - * the byte at BIOS+32 (shadowed in by logic on the card). From 2 - * of the switch bits we get the card's address in IO space. There's - * an image of the dip switch there, also, so we have a way to back- - * check that this really is an IN2000 card. Very nifty. Use the - * 'ioport:xx' command-line parameter if your BIOS EPROM is absent - * or disabled. - */ - - if (!done_setup && setup_strings) - in2000_setup(setup_strings, NULL); - - detect_count = 0; - for (bios = 0; bios_tab[bios]; bios++) { - u32 s1 = 0; - if (check_setup_args("ioport", &val, buf)) { - base = val; - switches = ~inb(base + IO_SWITCHES) & 0xff; - printk("Forcing IN2000 detection at IOport 0x%x ", base); - bios = 2; - } -/* - * There have been a couple of BIOS versions with different layouts - * for the obvious ID strings. We look for the 2 most common ones and - * hope that they cover all the cases... - */ - else if (probe_bios(bios_tab[bios], &s1, &switches)) { - printk("Found IN2000 BIOS at 0x%x ", (unsigned int) bios_tab[bios]); - -/* Find out where the IO space is */ - - x = switches & (SW_ADDR0 | SW_ADDR1); - base = base_tab[x]; - -/* Check for the IN2000 signature in IO space. */ - - x = ~inb(base + IO_SWITCHES) & 0xff; - if (x != switches) { - printk("Bad IO signature: %02x vs %02x.\n", x, switches); - continue; - } - } else - continue; - -/* OK. We have a base address for the IO ports - run a few safety checks */ - - if (!(switches & SW_BIT7)) { /* I _think_ all cards do this */ - printk("There is no IN-2000 SCSI card at IOport 0x%03x!\n", base); - continue; - } - -/* Let's assume any hardware version will work, although the driver - * has only been tested on 0x21, 0x22, 0x25, 0x26, and 0x27. We'll - * print out the rev number for reference later, but accept them all. - */ - - hrev = inb(base + IO_HARDWARE); - - /* Bit 2 tells us if interrupts are disabled */ - if (switches & SW_DISINT) { - printk("The IN-2000 SCSI card at IOport 0x%03x ", base); - printk("is not configured for interrupt operation!\n"); - printk("This driver requires an interrupt: cancelling detection.\n"); - continue; - } - -/* Ok. We accept that there's an IN2000 at ioaddr 'base'. Now - * initialize it. - */ - - tpnt->proc_name = "in2000"; - instance = scsi_register(tpnt, sizeof(struct IN2000_hostdata)); - if (instance == NULL) - continue; - detect_count++; - hostdata = (struct IN2000_hostdata *) instance->hostdata; - instance->io_port = hostdata->io_base = base; - hostdata->dip_switch = switches; - hostdata->hrev = hrev; - - write1_io(0, IO_FIFO_WRITE); /* clear fifo counter */ - write1_io(0, IO_FIFO_READ); /* start fifo out in read mode */ - write1_io(0, IO_INTR_MASK); /* allow all ints */ - x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT]; - if (request_irq(x, in2000_intr, IRQF_DISABLED, "in2000", instance)) { - printk("in2000_detect: Unable to allocate IRQ.\n"); - detect_count--; - continue; - } - instance->irq = x; - instance->n_io_port = 13; - request_region(base, 13, "in2000"); /* lock in this IO space for our use */ - - for (x = 0; x < 8; x++) { - hostdata->busy[x] = 0; - hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF); - hostdata->sync_stat[x] = SS_UNSET; /* using default sync values */ -#ifdef PROC_STATISTICS - hostdata->cmd_cnt[x] = 0; - hostdata->disc_allowed_cnt[x] = 0; - hostdata->disc_done_cnt[x] = 0; -#endif - } - hostdata->input_Q = NULL; - hostdata->selecting = NULL; - hostdata->connected = NULL; - hostdata->disconnected_Q = NULL; - hostdata->state = S_UNCONNECTED; - hostdata->fifo = FI_FIFO_UNUSED; - hostdata->level2 = L2_BASIC; - hostdata->disconnect = DIS_ADAPTIVE; - hostdata->args = DEBUG_DEFAULTS; - hostdata->incoming_ptr = 0; - hostdata->outgoing_len = 0; - hostdata->default_sx_per = DEFAULT_SX_PER; - -/* Older BIOS's had a 'sync on/off' switch - use its setting */ - - if (s1 == 0x41564f4e && (switches & SW_SYNC_DOS5)) - hostdata->sync_off = 0x00; /* sync defaults to on */ - else - hostdata->sync_off = 0xff; /* sync defaults to off */ - -#ifdef PROC_INTERFACE - hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP; -#ifdef PROC_STATISTICS - hostdata->int_cnt = 0; -#endif -#endif - - if (check_setup_args("nosync", &val, buf)) - hostdata->sync_off = val; - - if (check_setup_args("period", &val, buf)) - hostdata->default_sx_per = sx_table[round_period((unsigned int) val)].period_ns; - - if (check_setup_args("disconnect", &val, buf)) { - if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) - hostdata->disconnect = val; - else - hostdata->disconnect = DIS_ADAPTIVE; - } - - if (check_setup_args("noreset", &val, buf)) - hostdata->args ^= A_NO_SCSI_RESET; - - if (check_setup_args("level2", &val, buf)) - hostdata->level2 = val; - - if (check_setup_args("debug", &val, buf)) - hostdata->args = (val & DB_MASK); - -#ifdef PROC_INTERFACE - if (check_setup_args("proc", &val, buf)) - hostdata->proc = val; -#endif - - - /* FIXME: not strictly needed I think but the called code expects - to be locked */ - spin_lock_irqsave(instance->host_lock, flags); - x = reset_hardware(instance, (hostdata->args & A_NO_SCSI_RESET) ? RESET_CARD : RESET_CARD_AND_BUS); - spin_unlock_irqrestore(instance->host_lock, flags); - - hostdata->microcode = read_3393(hostdata, WD_CDB_1); - if (x & 0x01) { - if (x & B_FLAG) - hostdata->chip = C_WD33C93B; - else - hostdata->chip = C_WD33C93A; - } else - hostdata->chip = C_WD33C93; - - printk("dip_switch=%02x irq=%d ioport=%02x floppy=%s sync/DOS5=%s ", (switches & 0x7f), instance->irq, hostdata->io_base, (switches & SW_FLOPPY) ? "Yes" : "No", (switches & SW_SYNC_DOS5) ? "Yes" : "No"); - printk("hardware_ver=%02x chip=%s microcode=%02x\n", hrev, (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip == C_WD33C93A) ? "WD33c93A" : (hostdata->chip == C_WD33C93B) ? "WD33c93B" : "unknown", hostdata->microcode); -#ifdef DEBUGGING_ON - printk("setup_args = "); - for (x = 0; x < MAX_SETUP_ARGS; x++) - printk("%s,", setup_args[x]); - printk("\n"); -#endif - if (hostdata->sync_off == 0xff) - printk("Sync-transfer DISABLED on all devices: ENABLE from command-line\n"); - printk("IN2000 driver version %s - %s\n", IN2000_VERSION, IN2000_DATE); - } - - return detect_count; -} - -static int in2000_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, shost); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - return 0; -} - -/* NOTE: I lifted this function straight out of the old driver, - * and have not tested it. Presumably it does what it's - * supposed to do... - */ - -static int in2000_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *iinfo) -{ - int size; - - size = capacity; - iinfo[0] = 64; - iinfo[1] = 32; - iinfo[2] = size >> 11; - -/* This should approximate the large drive handling that the DOS ASPI manager - uses. Drives very near the boundaries may not be handled correctly (i.e. - near 2.0 Gb and 4.0 Gb) */ - - if (iinfo[2] > 1024) { - iinfo[0] = 64; - iinfo[1] = 63; - iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]); - } - if (iinfo[2] > 1024) { - iinfo[0] = 128; - iinfo[1] = 63; - iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]); - } - if (iinfo[2] > 1024) { - iinfo[0] = 255; - iinfo[1] = 63; - iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]); - } - return 0; -} - - -static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in) -{ - -#ifdef PROC_INTERFACE - - char *bp; - char tbuf[128]; - unsigned long flags; - struct IN2000_hostdata *hd; - Scsi_Cmnd *cmd; - int x, i; - static int stop = 0; - - hd = (struct IN2000_hostdata *) instance->hostdata; - -/* If 'in' is TRUE we need to _read_ the proc file. We accept the following - * keywords (same format as command-line, but only ONE per read): - * debug - * disconnect - * period - * resync - * proc - */ - - if (in) { - buf[len] = '\0'; - bp = buf; - if (!strncmp(bp, "debug:", 6)) { - bp += 6; - hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK; - } else if (!strncmp(bp, "disconnect:", 11)) { - bp += 11; - x = simple_strtoul(bp, NULL, 0); - if (x < DIS_NEVER || x > DIS_ALWAYS) - x = DIS_ADAPTIVE; - hd->disconnect = x; - } else if (!strncmp(bp, "period:", 7)) { - bp += 7; - x = simple_strtoul(bp, NULL, 0); - hd->default_sx_per = sx_table[round_period((unsigned int) x)].period_ns; - } else if (!strncmp(bp, "resync:", 7)) { - bp += 7; - x = simple_strtoul(bp, NULL, 0); - for (i = 0; i < 7; i++) - if (x & (1 << i)) - hd->sync_stat[i] = SS_UNSET; - } else if (!strncmp(bp, "proc:", 5)) { - bp += 5; - hd->proc = simple_strtoul(bp, NULL, 0); - } else if (!strncmp(bp, "level2:", 7)) { - bp += 7; - hd->level2 = simple_strtoul(bp, NULL, 0); - } - return len; - } - - spin_lock_irqsave(instance->host_lock, flags); - bp = buf; - *bp = '\0'; - if (hd->proc & PR_VERSION) { - sprintf(tbuf, "\nVersion %s - %s.", IN2000_VERSION, IN2000_DATE); - strcat(bp, tbuf); - } - if (hd->proc & PR_INFO) { - sprintf(tbuf, "\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s", (hd->dip_switch & 0x7f), instance->irq, hd->io_base, (hd->dip_switch & 0x40) ? "Yes" : "No", (hd->dip_switch & 0x20) ? "Yes" : "No"); - strcat(bp, tbuf); - strcat(bp, "\nsync_xfer[] = "); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%02x", hd->sync_xfer[x]); - strcat(bp, tbuf); - } - strcat(bp, "\nsync_stat[] = "); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%02x", hd->sync_stat[x]); - strcat(bp, tbuf); - } - } -#ifdef PROC_STATISTICS - if (hd->proc & PR_STATISTICS) { - strcat(bp, "\ncommands issued: "); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]); - strcat(bp, tbuf); - } - strcat(bp, "\ndisconnects allowed:"); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]); - strcat(bp, tbuf); - } - strcat(bp, "\ndisconnects done: "); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]); - strcat(bp, tbuf); - } - sprintf(tbuf, "\ninterrupts: \t%ld", hd->int_cnt); - strcat(bp, tbuf); - } -#endif - if (hd->proc & PR_CONNECTED) { - strcat(bp, "\nconnected: "); - if (hd->connected) { - cmd = (Scsi_Cmnd *) hd->connected; - sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); - strcat(bp, tbuf); - } - } - if (hd->proc & PR_INPUTQ) { - strcat(bp, "\ninput_Q: "); - cmd = (Scsi_Cmnd *) hd->input_Q; - while (cmd) { - sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); - strcat(bp, tbuf); - cmd = (Scsi_Cmnd *) cmd->host_scribble; - } - } - if (hd->proc & PR_DISCQ) { - strcat(bp, "\ndisconnected_Q:"); - cmd = (Scsi_Cmnd *) hd->disconnected_Q; - while (cmd) { - sprintf(tbuf, " %d:%d(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]); - strcat(bp, tbuf); - cmd = (Scsi_Cmnd *) cmd->host_scribble; - } - } - if (hd->proc & PR_TEST) { - ; /* insert your own custom function here */ - } - strcat(bp, "\n"); - spin_unlock_irqrestore(instance->host_lock, flags); - *start = buf; - if (stop) { - stop = 0; - return 0; /* return 0 to signal end-of-file */ - } - if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */ - stop = 1; - if (hd->proc & PR_STOP) /* stop every other time */ - stop = 1; - return strlen(bp); - -#else /* PROC_INTERFACE */ - - return 0; - -#endif /* PROC_INTERFACE */ - -} - -MODULE_LICENSE("GPL"); - - -static struct scsi_host_template driver_template = { - .proc_name = "in2000", - .proc_info = in2000_proc_info, - .name = "Always IN2000", - .detect = in2000_detect, - .release = in2000_release, - .queuecommand = in2000_queuecommand, - .eh_abort_handler = in2000_abort, - .eh_bus_reset_handler = in2000_bus_reset, - .bios_param = in2000_biosparam, - .can_queue = IN2000_CAN_Q, - .this_id = IN2000_HOST_ID, - .sg_tablesize = IN2000_SG, - .cmd_per_lun = IN2000_CPL, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/in2000.h b/ANDROID_3.4.5/drivers/scsi/in2000.h deleted file mode 100644 index 5821e1fb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/in2000.h +++ /dev/null @@ -1,412 +0,0 @@ -/* - * in2000.h - Linux device driver definitions for the - * Always IN2000 ISA SCSI card. - * - * IMPORTANT: This file is for version 1.33 - 26/Aug/1998 - * - * Copyright (c) 1996 John Shifflett, GeoLog Consulting - * john@geolog.com - * jshiffle@netcom.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef IN2000_H -#define IN2000_H - -#include - -#define PROC_INTERFACE /* add code for /proc/scsi/in2000/xxx interface */ -#ifdef PROC_INTERFACE -#define PROC_STATISTICS /* add code for keeping various real time stats */ -#endif - -#define SYNC_DEBUG /* extra info on sync negotiation printed */ -#define DEBUGGING_ON /* enable command-line debugging bitmask */ -#define DEBUG_DEFAULTS 0 /* default bitmask - change from command-line */ - -#ifdef __i386__ -#define FAST_READ_IO /* No problems with these on my machine */ -#define FAST_WRITE_IO -#endif - -#ifdef DEBUGGING_ON -#define DB(f,a) if (hostdata->args & (f)) a; -#define CHECK_NULL(p,s) /* if (!(p)) {printk("\n"); while (1) printk("NP:%s\r",(s));} */ -#else -#define DB(f,a) -#define CHECK_NULL(p,s) -#endif - -#define uchar unsigned char - -#define read1_io(a) (inb(hostdata->io_base+(a))) -#define read2_io(a) (inw(hostdata->io_base+(a))) -#define write1_io(b,a) (outb((b),hostdata->io_base+(a))) -#define write2_io(w,a) (outw((w),hostdata->io_base+(a))) - -#ifdef __i386__ -/* These inline assembly defines are derived from a patch - * sent to me by Bill Earnest. He's done a lot of very - * valuable thinking, testing, and coding during his effort - * to squeeze more speed out of this driver. I really think - * that we are doing IO at close to the maximum now with - * the fifo. (And yes, insw uses 'edi' while outsw uses - * 'esi'. Thanks Bill!) - */ - -#define FAST_READ2_IO() \ -({ \ -int __dummy_1,__dummy_2; \ - __asm__ __volatile__ ("\n \ - cld \n \ - orl %%ecx, %%ecx \n \ - jz 1f \n \ - rep \n \ - insw (%%dx),%%es:(%%edi) \n \ -1: " \ - : "=D" (sp) ,"=c" (__dummy_1) ,"=d" (__dummy_2) /* output */ \ - : "2" (f), "0" (sp), "1" (i) /* input */ \ - ); /* trashed */ \ -}) - -#define FAST_WRITE2_IO() \ -({ \ -int __dummy_1,__dummy_2; \ - __asm__ __volatile__ ("\n \ - cld \n \ - orl %%ecx, %%ecx \n \ - jz 1f \n \ - rep \n \ - outsw %%ds:(%%esi),(%%dx) \n \ -1: " \ - : "=S" (sp) ,"=c" (__dummy_1) ,"=d" (__dummy_2)/* output */ \ - : "2" (f), "0" (sp), "1" (i) /* input */ \ - ); /* trashed */ \ -}) -#endif - -/* IN2000 io_port offsets */ -#define IO_WD_ASR 0x00 /* R - 3393 auxstat reg */ -#define ASR_INT 0x80 -#define ASR_LCI 0x40 -#define ASR_BSY 0x20 -#define ASR_CIP 0x10 -#define ASR_PE 0x02 -#define ASR_DBR 0x01 -#define IO_WD_ADDR 0x00 /* W - 3393 address reg */ -#define IO_WD_DATA 0x01 /* R/W - rest of 3393 regs */ -#define IO_FIFO 0x02 /* R/W - in2000 dual-port fifo (16 bits) */ -#define IN2000_FIFO_SIZE 2048 /* fifo capacity in bytes */ -#define IO_CARD_RESET 0x03 /* W - in2000 start master reset */ -#define IO_FIFO_COUNT 0x04 /* R - in2000 fifo counter */ -#define IO_FIFO_WRITE 0x05 /* W - clear fifo counter, start write */ -#define IO_FIFO_READ 0x07 /* W - start fifo read */ -#define IO_LED_OFF 0x08 /* W - turn off in2000 activity LED */ -#define IO_SWITCHES 0x08 /* R - read in2000 dip switch */ -#define SW_ADDR0 0x01 /* bit 0 = bit 0 of index to io addr */ -#define SW_ADDR1 0x02 /* bit 1 = bit 1 of index io addr */ -#define SW_DISINT 0x04 /* bit 2 true if ints disabled */ -#define SW_INT0 0x08 /* bit 3 = bit 0 of index to interrupt */ -#define SW_INT1 0x10 /* bit 4 = bit 1 of index to interrupt */ -#define SW_INT_SHIFT 3 /* shift right this amount to right justify int bits */ -#define SW_SYNC_DOS5 0x20 /* bit 5 used by Always BIOS */ -#define SW_FLOPPY 0x40 /* bit 6 true if floppy enabled */ -#define SW_BIT7 0x80 /* bit 7 hardwired true (ground) */ -#define IO_LED_ON 0x09 /* W - turn on in2000 activity LED */ -#define IO_HARDWARE 0x0a /* R - read in2000 hardware rev, stop reset */ -#define IO_INTR_MASK 0x0c /* W - in2000 interrupt mask reg */ -#define IMASK_WD 0x01 /* WD33c93 interrupt mask */ -#define IMASK_FIFO 0x02 /* FIFO interrupt mask */ - -/* wd register names */ -#define WD_OWN_ID 0x00 -#define WD_CONTROL 0x01 -#define WD_TIMEOUT_PERIOD 0x02 -#define WD_CDB_1 0x03 -#define WD_CDB_2 0x04 -#define WD_CDB_3 0x05 -#define WD_CDB_4 0x06 -#define WD_CDB_5 0x07 -#define WD_CDB_6 0x08 -#define WD_CDB_7 0x09 -#define WD_CDB_8 0x0a -#define WD_CDB_9 0x0b -#define WD_CDB_10 0x0c -#define WD_CDB_11 0x0d -#define WD_CDB_12 0x0e -#define WD_TARGET_LUN 0x0f -#define WD_COMMAND_PHASE 0x10 -#define WD_SYNCHRONOUS_TRANSFER 0x11 -#define WD_TRANSFER_COUNT_MSB 0x12 -#define WD_TRANSFER_COUNT 0x13 -#define WD_TRANSFER_COUNT_LSB 0x14 -#define WD_DESTINATION_ID 0x15 -#define WD_SOURCE_ID 0x16 -#define WD_SCSI_STATUS 0x17 -#define WD_COMMAND 0x18 -#define WD_DATA 0x19 -#define WD_QUEUE_TAG 0x1a -#define WD_AUXILIARY_STATUS 0x1f - -/* WD commands */ -#define WD_CMD_RESET 0x00 -#define WD_CMD_ABORT 0x01 -#define WD_CMD_ASSERT_ATN 0x02 -#define WD_CMD_NEGATE_ACK 0x03 -#define WD_CMD_DISCONNECT 0x04 -#define WD_CMD_RESELECT 0x05 -#define WD_CMD_SEL_ATN 0x06 -#define WD_CMD_SEL 0x07 -#define WD_CMD_SEL_ATN_XFER 0x08 -#define WD_CMD_SEL_XFER 0x09 -#define WD_CMD_RESEL_RECEIVE 0x0a -#define WD_CMD_RESEL_SEND 0x0b -#define WD_CMD_WAIT_SEL_RECEIVE 0x0c -#define WD_CMD_TRANS_ADDR 0x18 -#define WD_CMD_TRANS_INFO 0x20 -#define WD_CMD_TRANSFER_PAD 0x21 -#define WD_CMD_SBT_MODE 0x80 - -/* SCSI Bus Phases */ -#define PHS_DATA_OUT 0x00 -#define PHS_DATA_IN 0x01 -#define PHS_COMMAND 0x02 -#define PHS_STATUS 0x03 -#define PHS_MESS_OUT 0x06 -#define PHS_MESS_IN 0x07 - -/* Command Status Register definitions */ - - /* reset state interrupts */ -#define CSR_RESET 0x00 -#define CSR_RESET_AF 0x01 - - /* successful completion interrupts */ -#define CSR_RESELECT 0x10 -#define CSR_SELECT 0x11 -#define CSR_SEL_XFER_DONE 0x16 -#define CSR_XFER_DONE 0x18 - - /* paused or aborted interrupts */ -#define CSR_MSGIN 0x20 -#define CSR_SDP 0x21 -#define CSR_SEL_ABORT 0x22 -#define CSR_RESEL_ABORT 0x25 -#define CSR_RESEL_ABORT_AM 0x27 -#define CSR_ABORT 0x28 - - /* terminated interrupts */ -#define CSR_INVALID 0x40 -#define CSR_UNEXP_DISC 0x41 -#define CSR_TIMEOUT 0x42 -#define CSR_PARITY 0x43 -#define CSR_PARITY_ATN 0x44 -#define CSR_BAD_STATUS 0x45 -#define CSR_UNEXP 0x48 - - /* service required interrupts */ -#define CSR_RESEL 0x80 -#define CSR_RESEL_AM 0x81 -#define CSR_DISC 0x85 -#define CSR_SRV_REQ 0x88 - - /* Own ID/CDB Size register */ -#define OWNID_EAF 0x08 -#define OWNID_EHP 0x10 -#define OWNID_RAF 0x20 -#define OWNID_FS_8 0x00 -#define OWNID_FS_12 0x40 -#define OWNID_FS_16 0x80 - - /* Control register */ -#define CTRL_HSP 0x01 -#define CTRL_HA 0x02 -#define CTRL_IDI 0x04 -#define CTRL_EDI 0x08 -#define CTRL_HHP 0x10 -#define CTRL_POLLED 0x00 -#define CTRL_BURST 0x20 -#define CTRL_BUS 0x40 -#define CTRL_DMA 0x80 - - /* Timeout Period register */ -#define TIMEOUT_PERIOD_VALUE 20 /* results in 200 ms. */ - - /* Synchronous Transfer Register */ -#define STR_FSS 0x80 - - /* Destination ID register */ -#define DSTID_DPD 0x40 -#define DATA_OUT_DIR 0 -#define DATA_IN_DIR 1 -#define DSTID_SCC 0x80 - - /* Source ID register */ -#define SRCID_MASK 0x07 -#define SRCID_SIV 0x08 -#define SRCID_DSP 0x20 -#define SRCID_ES 0x40 -#define SRCID_ER 0x80 - - - -#define ILLEGAL_STATUS_BYTE 0xff - - -#define DEFAULT_SX_PER 500 /* (ns) fairly safe */ -#define DEFAULT_SX_OFF 0 /* aka async */ - -#define OPTIMUM_SX_PER 252 /* (ns) best we can do (mult-of-4) */ -#define OPTIMUM_SX_OFF 12 /* size of in2000 fifo */ - -struct sx_period { - unsigned int period_ns; - uchar reg_value; - }; - - -struct IN2000_hostdata { - struct Scsi_Host *next; - uchar chip; /* what kind of wd33c93 chip? */ - uchar microcode; /* microcode rev if 'B' */ - unsigned short io_base; /* IO port base */ - unsigned int dip_switch; /* dip switch settings */ - unsigned int hrev; /* hardware revision of card */ - volatile uchar busy[8]; /* index = target, bit = lun */ - volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */ - volatile Scsi_Cmnd *selecting; /* trying to select this command */ - volatile Scsi_Cmnd *connected; /* currently connected command */ - volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */ - uchar state; /* what we are currently doing */ - uchar fifo; /* what the FIFO is up to */ - uchar level2; /* extent to which Level-2 commands are used */ - uchar disconnect; /* disconnect/reselect policy */ - unsigned int args; /* set from command-line argument */ - uchar incoming_msg[8]; /* filled during message_in phase */ - int incoming_ptr; /* mainly used with EXTENDED messages */ - uchar outgoing_msg[8]; /* send this during next message_out */ - int outgoing_len; /* length of outgoing message */ - unsigned int default_sx_per; /* default transfer period for SCSI bus */ - uchar sync_xfer[8]; /* sync_xfer reg settings per target */ - uchar sync_stat[8]; /* status of sync negotiation per target */ - uchar sync_off; /* bit mask: don't use sync with these targets */ -#ifdef PROC_INTERFACE - uchar proc; /* bit mask: what's in proc output */ -#ifdef PROC_STATISTICS - unsigned long cmd_cnt[8]; /* # of commands issued per target */ - unsigned long int_cnt; /* # of interrupts serviced */ - unsigned long disc_allowed_cnt[8]; /* # of disconnects allowed per target */ - unsigned long disc_done_cnt[8]; /* # of disconnects done per target*/ -#endif -#endif - }; - - -/* defines for hostdata->chip */ - -#define C_WD33C93 0 -#define C_WD33C93A 1 -#define C_WD33C93B 2 -#define C_UNKNOWN_CHIP 100 - -/* defines for hostdata->state */ - -#define S_UNCONNECTED 0 -#define S_SELECTING 1 -#define S_RUNNING_LEVEL2 2 -#define S_CONNECTED 3 -#define S_PRE_TMP_DISC 4 -#define S_PRE_CMP_DISC 5 - -/* defines for hostdata->fifo */ - -#define FI_FIFO_UNUSED 0 -#define FI_FIFO_READING 1 -#define FI_FIFO_WRITING 2 - -/* defines for hostdata->level2 */ -/* NOTE: only the first 3 are trustworthy at this point - - * having trouble when more than 1 device is reading/writing - * at the same time... - */ - -#define L2_NONE 0 /* no combination commands - we get lots of ints */ -#define L2_SELECT 1 /* start with SEL_ATN_XFER, but never resume it */ -#define L2_BASIC 2 /* resume after STATUS ints & RDP messages */ -#define L2_DATA 3 /* resume after DATA_IN/OUT ints */ -#define L2_MOST 4 /* resume after anything except a RESELECT int */ -#define L2_RESELECT 5 /* resume after everything, including RESELECT ints */ -#define L2_ALL 6 /* always resume */ - -/* defines for hostdata->disconnect */ - -#define DIS_NEVER 0 -#define DIS_ADAPTIVE 1 -#define DIS_ALWAYS 2 - -/* defines for hostdata->args */ - -#define DB_TEST 1<<0 -#define DB_FIFO 1<<1 -#define DB_QUEUE_COMMAND 1<<2 -#define DB_EXECUTE 1<<3 -#define DB_INTR 1<<4 -#define DB_TRANSFER 1<<5 -#define DB_MASK 0x3f - -#define A_NO_SCSI_RESET 1<<15 - - -/* defines for hostdata->sync_xfer[] */ - -#define SS_UNSET 0 -#define SS_FIRST 1 -#define SS_WAITING 2 -#define SS_SET 3 - -/* defines for hostdata->proc */ - -#define PR_VERSION 1<<0 -#define PR_INFO 1<<1 -#define PR_STATISTICS 1<<2 -#define PR_CONNECTED 1<<3 -#define PR_INPUTQ 1<<4 -#define PR_DISCQ 1<<5 -#define PR_TEST 1<<6 -#define PR_STOP 1<<7 - - -# include -# include -# define in2000__INITFUNC(function) __initfunc(function) -# define in2000__INIT __init -# define in2000__INITDATA __initdata -# define CLISPIN_LOCK(host,flags) spin_lock_irqsave(host->host_lock, flags) -# define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(host->host_lock, \ - flags) - -static int in2000_detect(struct scsi_host_template *) in2000__INIT; -static int in2000_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static int in2000_abort(Scsi_Cmnd *); -static void in2000_setup(char *, int *) in2000__INIT; -static int in2000_biosparam(struct scsi_device *, struct block_device *, - sector_t, int *); -static int in2000_bus_reset(Scsi_Cmnd *); - - -#define IN2000_CAN_Q 16 -#define IN2000_SG SG_ALL -#define IN2000_CPL 2 -#define IN2000_HOST_ID 7 - -#endif /* IN2000_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/initio.c b/ANDROID_3.4.5/drivers/scsi/initio.c deleted file mode 100644 index dd741bcd..00000000 --- a/ANDROID_3.4.5/drivers/scsi/initio.c +++ /dev/null @@ -1,3013 +0,0 @@ -/************************************************************************** - * Initio 9100 device driver for Linux. - * - * Copyright (c) 1994-1998 Initio Corporation - * Copyright (c) 1998 Bas Vermeulen - * Copyright (c) 2004 Christoph Hellwig - * Copyright (c) 2007 Red Hat - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - ************************************************************************* - * - * DESCRIPTION: - * - * This is the Linux low-level SCSI driver for Initio INI-9X00U/UW SCSI host - * adapters - * - * 08/06/97 hc - v1.01h - * - Support inic-940 and inic-935 - * 09/26/97 hc - v1.01i - * - Make correction from J.W. Schultz suggestion - * 10/13/97 hc - Support reset function - * 10/21/97 hc - v1.01j - * - Support 32 LUN (SCSI 3) - * 01/14/98 hc - v1.01k - * - Fix memory allocation problem - * 03/04/98 hc - v1.01l - * - Fix tape rewind which will hang the system problem - * - Set can_queue to initio_num_scb - * 06/25/98 hc - v1.01m - * - Get it work for kernel version >= 2.1.75 - * - Dynamic assign SCSI bus reset holding time in initio_init() - * 07/02/98 hc - v1.01n - * - Support 0002134A - * 08/07/98 hc - v1.01o - * - Change the initio_abort_srb routine to use scsi_done. <01> - * 09/07/98 hl - v1.02 - * - Change the INI9100U define and proc_dir_entry to - * reflect the newer Kernel 2.1.118, but the v1.o1o - * should work with Kernel 2.1.118. - * 09/20/98 wh - v1.02a - * - Support Abort command. - * - Handle reset routine. - * 09/21/98 hl - v1.03 - * - remove comments. - * 12/09/98 bv - v1.03a - * - Removed unused code - * 12/13/98 bv - v1.03b - * - Remove cli() locking for kernels >= 2.1.95. This uses - * spinlocks to serialize access to the pSRB_head and - * pSRB_tail members of the HCS structure. - * 09/01/99 bv - v1.03d - * - Fixed a deadlock problem in SMP. - * 21/01/99 bv - v1.03e - * - Add support for the Domex 3192U PCI SCSI - * This is a slightly modified patch by - * Brian Macy - * 22/02/99 bv - v1.03f - * - Didn't detect the INIC-950 in 2.0.x correctly. - * Now fixed. - * 05/07/99 bv - v1.03g - * - Changed the assumption that HZ = 100 - * 10/17/03 mc - v1.04 - * - added new DMA API support - * 06/01/04 jmd - v1.04a - * - Re-add reset_bus support - **************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "initio.h" - -#define SENSE_SIZE 14 - -#define i91u_MAXQUEUE 2 -#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a" - -#define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */ -#define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */ -#define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */ -#define I920_DEVICE_ID 0x0002 /* Initio's other product ID */ - -#ifdef DEBUG_i91u -static unsigned int i91u_debug = DEBUG_DEFAULT; -#endif - -static int initio_tag_enable = 1; - -#ifdef DEBUG_i91u -static int setup_debug = 0; -#endif - -static void i91uSCBPost(u8 * pHcb, u8 * pScb); - -/* PCI Devices supported by this driver */ -static struct pci_device_id i91u_pci_devices[] = { - { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { } -}; -MODULE_DEVICE_TABLE(pci, i91u_pci_devices); - -#define DEBUG_INTERRUPT 0 -#define DEBUG_QUEUE 0 -#define DEBUG_STATE 0 -#define INT_DISC 0 - -/*--- forward references ---*/ -static struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun); -static struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host); - -static int tulip_main(struct initio_host * host); - -static int initio_next_state(struct initio_host * host); -static int initio_state_1(struct initio_host * host); -static int initio_state_2(struct initio_host * host); -static int initio_state_3(struct initio_host * host); -static int initio_state_4(struct initio_host * host); -static int initio_state_5(struct initio_host * host); -static int initio_state_6(struct initio_host * host); -static int initio_state_7(struct initio_host * host); -static int initio_xfer_data_in(struct initio_host * host); -static int initio_xfer_data_out(struct initio_host * host); -static int initio_xpad_in(struct initio_host * host); -static int initio_xpad_out(struct initio_host * host); -static int initio_status_msg(struct initio_host * host); - -static int initio_msgin(struct initio_host * host); -static int initio_msgin_sync(struct initio_host * host); -static int initio_msgin_accept(struct initio_host * host); -static int initio_msgout_reject(struct initio_host * host); -static int initio_msgin_extend(struct initio_host * host); - -static int initio_msgout_ide(struct initio_host * host); -static int initio_msgout_abort_targ(struct initio_host * host); -static int initio_msgout_abort_tag(struct initio_host * host); - -static int initio_bus_device_reset(struct initio_host * host); -static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb); -static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb); -static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb); -static int int_initio_busfree(struct initio_host * host); -static int int_initio_scsi_rst(struct initio_host * host); -static int int_initio_bad_seq(struct initio_host * host); -static int int_initio_resel(struct initio_host * host); -static int initio_sync_done(struct initio_host * host); -static int wdtr_done(struct initio_host * host); -static int wait_tulip(struct initio_host * host); -static int initio_wait_done_disc(struct initio_host * host); -static int initio_wait_disc(struct initio_host * host); -static void tulip_scsi(struct initio_host * host); -static int initio_post_scsi_rst(struct initio_host * host); - -static void initio_se2_ew_en(unsigned long base); -static void initio_se2_ew_ds(unsigned long base); -static int initio_se2_rd_all(unsigned long base); -static void initio_se2_update_all(unsigned long base); /* setup default pattern */ -static void initio_read_eeprom(unsigned long base); - -/* ---- INTERNAL VARIABLES ---- */ - -static NVRAM i91unvram; -static NVRAM *i91unvramp; - -static u8 i91udftNvRam[64] = -{ - /*----------- header -----------*/ - 0x25, 0xc9, /* Signature */ - 0x40, /* Size */ - 0x01, /* Revision */ - /* -- Host Adapter Structure -- */ - 0x95, /* ModelByte0 */ - 0x00, /* ModelByte1 */ - 0x00, /* ModelInfo */ - 0x01, /* NumOfCh */ - NBC1_DEFAULT, /* BIOSConfig1 */ - 0, /* BIOSConfig2 */ - 0, /* HAConfig1 */ - 0, /* HAConfig2 */ - /* SCSI channel 0 and target Structure */ - 7, /* SCSIid */ - NCC1_DEFAULT, /* SCSIconfig1 */ - 0, /* SCSIconfig2 */ - 0x10, /* NumSCSItarget */ - - NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, - NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, - NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, - NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, - - /* SCSI channel 1 and target Structure */ - 7, /* SCSIid */ - NCC1_DEFAULT, /* SCSIconfig1 */ - 0, /* SCSIconfig2 */ - 0x10, /* NumSCSItarget */ - - NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, - NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, - NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, - NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0}; /* - CheckSum - */ - - -static u8 initio_rate_tbl[8] = /* fast 20 */ -{ - /* nanosecond divide by 4 */ - 12, /* 50ns, 20M */ - 18, /* 75ns, 13.3M */ - 25, /* 100ns, 10M */ - 31, /* 125ns, 8M */ - 37, /* 150ns, 6.6M */ - 43, /* 175ns, 5.7M */ - 50, /* 200ns, 5M */ - 62 /* 250ns, 4M */ -}; - -static void initio_do_pause(unsigned amount) -{ - /* Pause for amount jiffies */ - unsigned long the_time = jiffies + amount; - - while (time_before_eq(jiffies, the_time)) - cpu_relax(); -} - -/*-- forward reference --*/ - -/****************************************************************** - Input: instruction for Serial E2PROM - - EX: se2_rd(0 call se2_instr() to send address and read command - - StartBit OP_Code Address Data - --------- -------- ------------------ ------- - 1 1 , 0 A5,A4,A3,A2,A1,A0 D15-D0 - - +----------------------------------------------------- - | - CS -----+ - +--+ +--+ +--+ +--+ +--+ - ^ | ^ | ^ | ^ | ^ | - | | | | | | | | | | - CLK -------+ +--+ +--+ +--+ +--+ +-- - (leading edge trigger) - - +--1-----1--+ - | SB OP | OP A5 A4 - DI ----+ +--0------------------ - (address and cmd sent to nvram) - - -------------------------------------------+ - | - DO +--- - (data sent from nvram) - - -******************************************************************/ - -/** - * initio_se2_instr - bitbang an instruction - * @base: Base of InitIO controller - * @instr: Instruction for serial E2PROM - * - * Bitbang an instruction out to the serial E2Prom - */ - -static void initio_se2_instr(unsigned long base, u8 instr) -{ - int i; - u8 b; - - outb(SE2CS | SE2DO, base + TUL_NVRAM); /* cs+start bit */ - udelay(30); - outb(SE2CS | SE2CLK | SE2DO, base + TUL_NVRAM); /* +CLK */ - udelay(30); - - for (i = 0; i < 8; i++) { - if (instr & 0x80) - b = SE2CS | SE2DO; /* -CLK+dataBit */ - else - b = SE2CS; /* -CLK */ - outb(b, base + TUL_NVRAM); - udelay(30); - outb(b | SE2CLK, base + TUL_NVRAM); /* +CLK */ - udelay(30); - instr <<= 1; - } - outb(SE2CS, base + TUL_NVRAM); /* -CLK */ - udelay(30); -} - - -/** - * initio_se2_ew_en - Enable erase/write - * @base: Base address of InitIO controller - * - * Enable erase/write state of serial EEPROM - */ -void initio_se2_ew_en(unsigned long base) -{ - initio_se2_instr(base, 0x30); /* EWEN */ - outb(0, base + TUL_NVRAM); /* -CS */ - udelay(30); -} - - -/** - * initio_se2_ew_ds - Disable erase/write - * @base: Base address of InitIO controller - * - * Disable erase/write state of serial EEPROM - */ -void initio_se2_ew_ds(unsigned long base) -{ - initio_se2_instr(base, 0); /* EWDS */ - outb(0, base + TUL_NVRAM); /* -CS */ - udelay(30); -} - - -/** - * initio_se2_rd - read E2PROM word - * @base: Base of InitIO controller - * @addr: Address of word in E2PROM - * - * Read a word from the NV E2PROM device - */ -static u16 initio_se2_rd(unsigned long base, u8 addr) -{ - u8 instr, rb; - u16 val = 0; - int i; - - instr = (u8) (addr | 0x80); - initio_se2_instr(base, instr); /* READ INSTR */ - - for (i = 15; i >= 0; i--) { - outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */ - udelay(30); - outb(SE2CS, base + TUL_NVRAM); /* -CLK */ - - /* sample data after the following edge of clock */ - rb = inb(base + TUL_NVRAM); - rb &= SE2DI; - val += (rb << i); - udelay(30); /* 6/20/95 */ - } - - outb(0, base + TUL_NVRAM); /* no chip select */ - udelay(30); - return val; -} - -/** - * initio_se2_wr - read E2PROM word - * @base: Base of InitIO controller - * @addr: Address of word in E2PROM - * @val: Value to write - * - * Write a word to the NV E2PROM device. Used when recovering from - * a problem with the NV. - */ -static void initio_se2_wr(unsigned long base, u8 addr, u16 val) -{ - u8 rb; - u8 instr; - int i; - - instr = (u8) (addr | 0x40); - initio_se2_instr(base, instr); /* WRITE INSTR */ - for (i = 15; i >= 0; i--) { - if (val & 0x8000) - outb(SE2CS | SE2DO, base + TUL_NVRAM); /* -CLK+dataBit 1 */ - else - outb(SE2CS, base + TUL_NVRAM); /* -CLK+dataBit 0 */ - udelay(30); - outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */ - udelay(30); - val <<= 1; - } - outb(SE2CS, base + TUL_NVRAM); /* -CLK */ - udelay(30); - outb(0, base + TUL_NVRAM); /* -CS */ - udelay(30); - - outb(SE2CS, base + TUL_NVRAM); /* +CS */ - udelay(30); - - for (;;) { - outb(SE2CS | SE2CLK, base + TUL_NVRAM); /* +CLK */ - udelay(30); - outb(SE2CS, base + TUL_NVRAM); /* -CLK */ - udelay(30); - if ((rb = inb(base + TUL_NVRAM)) & SE2DI) - break; /* write complete */ - } - outb(0, base + TUL_NVRAM); /* -CS */ -} - -/** - * initio_se2_rd_all - read hostadapter NV configuration - * @base: Base address of InitIO controller - * - * Reads the E2PROM data into main memory. Ensures that the checksum - * and header marker are valid. Returns 1 on success -1 on error. - */ - -static int initio_se2_rd_all(unsigned long base) -{ - int i; - u16 chksum = 0; - u16 *np; - - i91unvramp = &i91unvram; - np = (u16 *) i91unvramp; - for (i = 0; i < 32; i++) - *np++ = initio_se2_rd(base, i); - - /* Is signature "ini" ok ? */ - if (i91unvramp->NVM_Signature != INI_SIGNATURE) - return -1; - /* Is ckecksum ok ? */ - np = (u16 *) i91unvramp; - for (i = 0; i < 31; i++) - chksum += *np++; - if (i91unvramp->NVM_CheckSum != chksum) - return -1; - return 1; -} - -/** - * initio_se2_update_all - Update E2PROM - * @base: Base of InitIO controller - * - * Update the E2PROM by wrting any changes into the E2PROM - * chip, rewriting the checksum. - */ -static void initio_se2_update_all(unsigned long base) -{ /* setup default pattern */ - int i; - u16 chksum = 0; - u16 *np, *np1; - - i91unvramp = &i91unvram; - /* Calculate checksum first */ - np = (u16 *) i91udftNvRam; - for (i = 0; i < 31; i++) - chksum += *np++; - *np = chksum; - initio_se2_ew_en(base); /* Enable write */ - - np = (u16 *) i91udftNvRam; - np1 = (u16 *) i91unvramp; - for (i = 0; i < 32; i++, np++, np1++) { - if (*np != *np1) - initio_se2_wr(base, i, *np); - } - initio_se2_ew_ds(base); /* Disable write */ -} - -/** - * initio_read_eeprom - Retrieve configuration - * @base: Base of InitIO Host Adapter - * - * Retrieve the host adapter configuration data from E2Prom. If the - * data is invalid then the defaults are used and are also restored - * into the E2PROM. This forms the access point for the SCSI driver - * into the E2PROM layer, the other functions for the E2PROM are all - * internal use. - * - * Must be called single threaded, uses a shared global area. - */ - -static void initio_read_eeprom(unsigned long base) -{ - u8 gctrl; - - i91unvramp = &i91unvram; - /* Enable EEProm programming */ - gctrl = inb(base + TUL_GCTRL); - outb(gctrl | TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL); - if (initio_se2_rd_all(base) != 1) { - initio_se2_update_all(base); /* setup default pattern */ - initio_se2_rd_all(base); /* load again */ - } - /* Disable EEProm programming */ - gctrl = inb(base + TUL_GCTRL); - outb(gctrl & ~TUL_GCTRL_EEPROM_BIT, base + TUL_GCTRL); -} - -/** - * initio_stop_bm - stop bus master - * @host: InitIO we are stopping - * - * Stop any pending DMA operation, aborting the DMA if necessary - */ - -static void initio_stop_bm(struct initio_host * host) -{ - - if (inb(host->addr + TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */ - outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd); - /* wait Abort DMA xfer done */ - while ((inb(host->addr + TUL_Int) & XABT) == 0) - cpu_relax(); - } - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); -} - -/** - * initio_reset_scsi - Reset SCSI host controller - * @host: InitIO host to reset - * @seconds: Recovery time - * - * Perform a full reset of the SCSI subsystem. - */ - -static int initio_reset_scsi(struct initio_host * host, int seconds) -{ - outb(TSC_RST_BUS, host->addr + TUL_SCtrl0); - - while (!((host->jsint = inb(host->addr + TUL_SInt)) & TSS_SCSIRST_INT)) - cpu_relax(); - - /* reset tulip chip */ - outb(0, host->addr + TUL_SSignal); - - /* Stall for a while, wait for target's firmware ready,make it 2 sec ! */ - /* SONY 5200 tape drive won't work if only stall for 1 sec */ - /* FIXME: this is a very long busy wait right now */ - initio_do_pause(seconds * HZ); - - inb(host->addr + TUL_SInt); - return SCSI_RESET_SUCCESS; -} - -/** - * initio_init - set up an InitIO host adapter - * @host: InitIO host adapter - * @num_scbs: Number of SCBS - * @bios_addr: BIOS address - * - * Set up the host adapter and devices according to the configuration - * retrieved from the E2PROM. - * - * Locking: Calls E2PROM layer code which is not re-enterable so must - * run single threaded for now. - */ - -static void initio_init(struct initio_host * host, u8 *bios_addr) -{ - int i; - u8 *flags; - u8 *heads; - - /* Get E2Prom configuration */ - initio_read_eeprom(host->addr); - if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8) - host->max_tar = 8; - else - host->max_tar = 16; - - host->config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1; - - host->scsi_id = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID; - host->idmask = ~(1 << host->scsi_id); - -#ifdef CHK_PARITY - /* Enable parity error response */ - outb(inb(host->addr + TUL_PCMD) | 0x40, host->addr + TUL_PCMD); -#endif - - /* Mask all the interrupt */ - outb(0x1F, host->addr + TUL_Mask); - - initio_stop_bm(host); - /* --- Initialize the tulip --- */ - outb(TSC_RST_CHIP, host->addr + TUL_SCtrl0); - - /* program HBA's SCSI ID */ - outb(host->scsi_id << 4, host->addr + TUL_SScsiId); - - /* Enable Initiator Mode ,phase latch,alternate sync period mode, - disable SCSI reset */ - if (host->config & HCC_EN_PAR) - host->sconf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR); - else - host->sconf1 = (TSC_INITDEFAULT); - outb(host->sconf1, host->addr + TUL_SConfig); - - /* Enable HW reselect */ - outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); - - outb(0, host->addr + TUL_SPeriod); - - /* selection time out = 250 ms */ - outb(153, host->addr + TUL_STimeOut); - - /* Enable SCSI terminator */ - outb((host->config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)), - host->addr + TUL_XCtrl); - outb(((host->config & HCC_AUTO_TERM) >> 4) | - (inb(host->addr + TUL_GCTRL1) & 0xFE), - host->addr + TUL_GCTRL1); - - for (i = 0, - flags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config), - heads = bios_addr + 0x180; - i < host->max_tar; - i++, flags++) { - host->targets[i].flags = *flags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE); - if (host->targets[i].flags & TCF_EN_255) - host->targets[i].drv_flags = TCF_DRV_255_63; - else - host->targets[i].drv_flags = 0; - host->targets[i].js_period = 0; - host->targets[i].sconfig0 = host->sconf1; - host->targets[i].heads = *heads++; - if (host->targets[i].heads == 255) - host->targets[i].drv_flags = TCF_DRV_255_63; - else - host->targets[i].drv_flags = 0; - host->targets[i].sectors = *heads++; - host->targets[i].flags &= ~TCF_BUSY; - host->act_tags[i] = 0; - host->max_tags[i] = 0xFF; - } /* for */ - printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n", - host->addr, host->pci_dev->irq, - host->bios_addr, host->scsi_id); - /* Reset SCSI Bus */ - if (host->config & HCC_SCSI_RESET) { - printk(KERN_INFO "i91u: Reset SCSI Bus ... \n"); - initio_reset_scsi(host, 10); - } - outb(0x17, host->addr + TUL_SCFG1); - outb(0xE9, host->addr + TUL_SIntEnable); -} - -/** - * initio_alloc_scb - Allocate an SCB - * @host: InitIO host we are allocating for - * - * Walk the SCB list for the controller and allocate a free SCB if - * one exists. - */ -static struct scsi_ctrl_blk *initio_alloc_scb(struct initio_host *host) -{ - struct scsi_ctrl_blk *scb; - unsigned long flags; - - spin_lock_irqsave(&host->avail_lock, flags); - if ((scb = host->first_avail) != NULL) { -#if DEBUG_QUEUE - printk("find scb at %p\n", scb); -#endif - if ((host->first_avail = scb->next) == NULL) - host->last_avail = NULL; - scb->next = NULL; - scb->status = SCB_RENT; - } - spin_unlock_irqrestore(&host->avail_lock, flags); - return scb; -} - -/** - * initio_release_scb - Release an SCB - * @host: InitIO host that owns the SCB - * @cmnd: SCB command block being returned - * - * Return an allocated SCB to the host free list - */ - -static void initio_release_scb(struct initio_host * host, struct scsi_ctrl_blk * cmnd) -{ - unsigned long flags; - -#if DEBUG_QUEUE - printk("Release SCB %p; ", cmnd); -#endif - spin_lock_irqsave(&(host->avail_lock), flags); - cmnd->srb = NULL; - cmnd->status = 0; - cmnd->next = NULL; - if (host->last_avail != NULL) { - host->last_avail->next = cmnd; - host->last_avail = cmnd; - } else { - host->first_avail = cmnd; - host->last_avail = cmnd; - } - spin_unlock_irqrestore(&(host->avail_lock), flags); -} - -/***************************************************************************/ -static void initio_append_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp) -{ - -#if DEBUG_QUEUE - printk("Append pend SCB %p; ", scbp); -#endif - scbp->status = SCB_PEND; - scbp->next = NULL; - if (host->last_pending != NULL) { - host->last_pending->next = scbp; - host->last_pending = scbp; - } else { - host->first_pending = scbp; - host->last_pending = scbp; - } -} - -/***************************************************************************/ -static void initio_push_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp) -{ - -#if DEBUG_QUEUE - printk("Push pend SCB %p; ", scbp); -#endif - scbp->status = SCB_PEND; - if ((scbp->next = host->first_pending) != NULL) { - host->first_pending = scbp; - } else { - host->first_pending = scbp; - host->last_pending = scbp; - } -} - -static struct scsi_ctrl_blk *initio_find_first_pend_scb(struct initio_host * host) -{ - struct scsi_ctrl_blk *first; - - - first = host->first_pending; - while (first != NULL) { - if (first->opcode != ExecSCSI) - return first; - if (first->tagmsg == 0) { - if ((host->act_tags[first->target] == 0) && - !(host->targets[first->target].flags & TCF_BUSY)) - return first; - } else { - if ((host->act_tags[first->target] >= - host->max_tags[first->target]) | - (host->targets[first->target].flags & TCF_BUSY)) { - first = first->next; - continue; - } - return first; - } - first = first->next; - } - return first; -} - -static void initio_unlink_pend_scb(struct initio_host * host, struct scsi_ctrl_blk * scb) -{ - struct scsi_ctrl_blk *tmp, *prev; - -#if DEBUG_QUEUE - printk("unlink pend SCB %p; ", scb); -#endif - - prev = tmp = host->first_pending; - while (tmp != NULL) { - if (scb == tmp) { /* Unlink this SCB */ - if (tmp == host->first_pending) { - if ((host->first_pending = tmp->next) == NULL) - host->last_pending = NULL; - } else { - prev->next = tmp->next; - if (tmp == host->last_pending) - host->last_pending = prev; - } - tmp->next = NULL; - break; - } - prev = tmp; - tmp = tmp->next; - } -} - -static void initio_append_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp) -{ - -#if DEBUG_QUEUE - printk("append busy SCB %p; ", scbp); -#endif - if (scbp->tagmsg) - host->act_tags[scbp->target]++; - else - host->targets[scbp->target].flags |= TCF_BUSY; - scbp->status = SCB_BUSY; - scbp->next = NULL; - if (host->last_busy != NULL) { - host->last_busy->next = scbp; - host->last_busy = scbp; - } else { - host->first_busy = scbp; - host->last_busy = scbp; - } -} - -/***************************************************************************/ -static struct scsi_ctrl_blk *initio_pop_busy_scb(struct initio_host * host) -{ - struct scsi_ctrl_blk *tmp; - - - if ((tmp = host->first_busy) != NULL) { - if ((host->first_busy = tmp->next) == NULL) - host->last_busy = NULL; - tmp->next = NULL; - if (tmp->tagmsg) - host->act_tags[tmp->target]--; - else - host->targets[tmp->target].flags &= ~TCF_BUSY; - } -#if DEBUG_QUEUE - printk("Pop busy SCB %p; ", tmp); -#endif - return tmp; -} - -/***************************************************************************/ -static void initio_unlink_busy_scb(struct initio_host * host, struct scsi_ctrl_blk * scb) -{ - struct scsi_ctrl_blk *tmp, *prev; - -#if DEBUG_QUEUE - printk("unlink busy SCB %p; ", scb); -#endif - - prev = tmp = host->first_busy; - while (tmp != NULL) { - if (scb == tmp) { /* Unlink this SCB */ - if (tmp == host->first_busy) { - if ((host->first_busy = tmp->next) == NULL) - host->last_busy = NULL; - } else { - prev->next = tmp->next; - if (tmp == host->last_busy) - host->last_busy = prev; - } - tmp->next = NULL; - if (tmp->tagmsg) - host->act_tags[tmp->target]--; - else - host->targets[tmp->target].flags &= ~TCF_BUSY; - break; - } - prev = tmp; - tmp = tmp->next; - } - return; -} - -struct scsi_ctrl_blk *initio_find_busy_scb(struct initio_host * host, u16 tarlun) -{ - struct scsi_ctrl_blk *tmp, *prev; - u16 scbp_tarlun; - - - prev = tmp = host->first_busy; - while (tmp != NULL) { - scbp_tarlun = (tmp->lun << 8) | (tmp->target); - if (scbp_tarlun == tarlun) { /* Unlink this SCB */ - break; - } - prev = tmp; - tmp = tmp->next; - } -#if DEBUG_QUEUE - printk("find busy SCB %p; ", tmp); -#endif - return tmp; -} - -static void initio_append_done_scb(struct initio_host * host, struct scsi_ctrl_blk * scbp) -{ -#if DEBUG_QUEUE - printk("append done SCB %p; ", scbp); -#endif - - scbp->status = SCB_DONE; - scbp->next = NULL; - if (host->last_done != NULL) { - host->last_done->next = scbp; - host->last_done = scbp; - } else { - host->first_done = scbp; - host->last_done = scbp; - } -} - -struct scsi_ctrl_blk *initio_find_done_scb(struct initio_host * host) -{ - struct scsi_ctrl_blk *tmp; - - if ((tmp = host->first_done) != NULL) { - if ((host->first_done = tmp->next) == NULL) - host->last_done = NULL; - tmp->next = NULL; - } -#if DEBUG_QUEUE - printk("find done SCB %p; ",tmp); -#endif - return tmp; -} - -static int initio_abort_srb(struct initio_host * host, struct scsi_cmnd *srbp) -{ - unsigned long flags; - struct scsi_ctrl_blk *tmp, *prev; - - spin_lock_irqsave(&host->semaph_lock, flags); - - if ((host->semaph == 0) && (host->active == NULL)) { - /* disable Jasmin SCSI Int */ - outb(0x1F, host->addr + TUL_Mask); - spin_unlock_irqrestore(&host->semaph_lock, flags); - /* FIXME: synchronize_irq needed ? */ - tulip_main(host); - spin_lock_irqsave(&host->semaph_lock, flags); - host->semaph = 1; - outb(0x0F, host->addr + TUL_Mask); - spin_unlock_irqrestore(&host->semaph_lock, flags); - return SCSI_ABORT_SNOOZE; - } - prev = tmp = host->first_pending; /* Check Pend queue */ - while (tmp != NULL) { - /* 07/27/98 */ - if (tmp->srb == srbp) { - if (tmp == host->active) { - spin_unlock_irqrestore(&host->semaph_lock, flags); - return SCSI_ABORT_BUSY; - } else if (tmp == host->first_pending) { - if ((host->first_pending = tmp->next) == NULL) - host->last_pending = NULL; - } else { - prev->next = tmp->next; - if (tmp == host->last_pending) - host->last_pending = prev; - } - tmp->hastat = HOST_ABORTED; - tmp->flags |= SCF_DONE; - if (tmp->flags & SCF_POST) - (*tmp->post) ((u8 *) host, (u8 *) tmp); - spin_unlock_irqrestore(&host->semaph_lock, flags); - return SCSI_ABORT_SUCCESS; - } - prev = tmp; - tmp = tmp->next; - } - - prev = tmp = host->first_busy; /* Check Busy queue */ - while (tmp != NULL) { - if (tmp->srb == srbp) { - if (tmp == host->active) { - spin_unlock_irqrestore(&host->semaph_lock, flags); - return SCSI_ABORT_BUSY; - } else if (tmp->tagmsg == 0) { - spin_unlock_irqrestore(&host->semaph_lock, flags); - return SCSI_ABORT_BUSY; - } else { - host->act_tags[tmp->target]--; - if (tmp == host->first_busy) { - if ((host->first_busy = tmp->next) == NULL) - host->last_busy = NULL; - } else { - prev->next = tmp->next; - if (tmp == host->last_busy) - host->last_busy = prev; - } - tmp->next = NULL; - - - tmp->hastat = HOST_ABORTED; - tmp->flags |= SCF_DONE; - if (tmp->flags & SCF_POST) - (*tmp->post) ((u8 *) host, (u8 *) tmp); - spin_unlock_irqrestore(&host->semaph_lock, flags); - return SCSI_ABORT_SUCCESS; - } - } - prev = tmp; - tmp = tmp->next; - } - spin_unlock_irqrestore(&host->semaph_lock, flags); - return SCSI_ABORT_NOT_RUNNING; -} - -/***************************************************************************/ -static int initio_bad_seq(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb; - - printk("initio_bad_seg c=%d\n", host->index); - - if ((scb = host->active) != NULL) { - initio_unlink_busy_scb(host, scb); - scb->hastat = HOST_BAD_PHAS; - scb->tastat = 0; - initio_append_done_scb(host, scb); - } - initio_stop_bm(host); - initio_reset_scsi(host, 8); /* 7/29/98 */ - return initio_post_scsi_rst(host); -} - - -/************************************************************************/ -static void initio_exec_scb(struct initio_host * host, struct scsi_ctrl_blk * scb) -{ - unsigned long flags; - - scb->mode = 0; - - scb->sgidx = 0; - scb->sgmax = scb->sglen; - - spin_lock_irqsave(&host->semaph_lock, flags); - - initio_append_pend_scb(host, scb); /* Append this SCB to Pending queue */ - -/* VVVVV 07/21/98 */ - if (host->semaph == 1) { - /* Disable Jasmin SCSI Int */ - outb(0x1F, host->addr + TUL_Mask); - host->semaph = 0; - spin_unlock_irqrestore(&host->semaph_lock, flags); - - tulip_main(host); - - spin_lock_irqsave(&host->semaph_lock, flags); - host->semaph = 1; - outb(0x0F, host->addr + TUL_Mask); - } - spin_unlock_irqrestore(&host->semaph_lock, flags); - return; -} - -/***************************************************************************/ -static int initio_isr(struct initio_host * host) -{ - if (inb(host->addr + TUL_Int) & TSS_INT_PENDING) { - if (host->semaph == 1) { - outb(0x1F, host->addr + TUL_Mask); - /* Disable Tulip SCSI Int */ - host->semaph = 0; - - tulip_main(host); - - host->semaph = 1; - outb(0x0F, host->addr + TUL_Mask); - return 1; - } - } - return 0; -} - -static int tulip_main(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb; - - for (;;) { - tulip_scsi(host); /* Call tulip_scsi */ - - /* Walk the list of completed SCBs */ - while ((scb = initio_find_done_scb(host)) != NULL) { /* find done entry */ - if (scb->tastat == INI_QUEUE_FULL) { - host->max_tags[scb->target] = - host->act_tags[scb->target] - 1; - scb->tastat = 0; - initio_append_pend_scb(host, scb); - continue; - } - if (!(scb->mode & SCM_RSENS)) { /* not in auto req. sense mode */ - if (scb->tastat == 2) { - - /* clr sync. nego flag */ - - if (scb->flags & SCF_SENSE) { - u8 len; - len = scb->senselen; - if (len == 0) - len = 1; - scb->buflen = scb->senselen; - scb->bufptr = scb->senseptr; - scb->flags &= ~(SCF_SG | SCF_DIR); /* for xfer_data_in */ - /* so, we won't report wrong direction in xfer_data_in, - and won't report HOST_DO_DU in state_6 */ - scb->mode = SCM_RSENS; - scb->ident &= 0xBF; /* Disable Disconnect */ - scb->tagmsg = 0; - scb->tastat = 0; - scb->cdblen = 6; - scb->cdb[0] = SCSICMD_RequestSense; - scb->cdb[1] = 0; - scb->cdb[2] = 0; - scb->cdb[3] = 0; - scb->cdb[4] = len; - scb->cdb[5] = 0; - initio_push_pend_scb(host, scb); - break; - } - } - } else { /* in request sense mode */ - - if (scb->tastat == 2) { /* check contition status again after sending - requset sense cmd 0x3 */ - scb->hastat = HOST_BAD_PHAS; - } - scb->tastat = 2; - } - scb->flags |= SCF_DONE; - if (scb->flags & SCF_POST) { - /* FIXME: only one post method and lose casts */ - (*scb->post) ((u8 *) host, (u8 *) scb); - } - } /* while */ - /* find_active: */ - if (inb(host->addr + TUL_SStatus0) & TSS_INT_PENDING) - continue; - if (host->active) /* return to OS and wait for xfer_done_ISR/Selected_ISR */ - return 1; /* return to OS, enable interrupt */ - /* Check pending SCB */ - if (initio_find_first_pend_scb(host) == NULL) - return 1; /* return to OS, enable interrupt */ - } /* End of for loop */ - /* statement won't reach here */ -} - -static void tulip_scsi(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb; - struct target_control *active_tc; - - /* make sure to service interrupt asap */ - if ((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) & TSS_INT_PENDING) { - host->phase = host->jsstatus0 & TSS_PH_MASK; - host->jsstatus1 = inb(host->addr + TUL_SStatus1); - host->jsint = inb(host->addr + TUL_SInt); - if (host->jsint & TSS_SCSIRST_INT) { /* SCSI bus reset detected */ - int_initio_scsi_rst(host); - return; - } - if (host->jsint & TSS_RESEL_INT) { /* if selected/reselected interrupt */ - if (int_initio_resel(host) == 0) - initio_next_state(host); - return; - } - if (host->jsint & TSS_SEL_TIMEOUT) { - int_initio_busfree(host); - return; - } - if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */ - int_initio_busfree(host); /* unexpected bus free or sel timeout */ - return; - } - if (host->jsint & (TSS_FUNC_COMP | TSS_BUS_SERV)) { /* func complete or Bus service */ - if ((scb = host->active) != NULL) - initio_next_state(host); - return; - } - } - if (host->active != NULL) - return; - - if ((scb = initio_find_first_pend_scb(host)) == NULL) - return; - - /* program HBA's SCSI ID & target SCSI ID */ - outb((host->scsi_id << 4) | (scb->target & 0x0F), - host->addr + TUL_SScsiId); - if (scb->opcode == ExecSCSI) { - active_tc = &host->targets[scb->target]; - - if (scb->tagmsg) - active_tc->drv_flags |= TCF_DRV_EN_TAG; - else - active_tc->drv_flags &= ~TCF_DRV_EN_TAG; - - outb(active_tc->js_period, host->addr + TUL_SPeriod); - if ((active_tc->flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) { /* do wdtr negotiation */ - initio_select_atn_stop(host, scb); - } else { - if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { /* do sync negotiation */ - initio_select_atn_stop(host, scb); - } else { - if (scb->tagmsg) - initio_select_atn3(host, scb); - else - initio_select_atn(host, scb); - } - } - if (scb->flags & SCF_POLL) { - while (wait_tulip(host) != -1) { - if (initio_next_state(host) == -1) - break; - } - } - } else if (scb->opcode == BusDevRst) { - initio_select_atn_stop(host, scb); - scb->next_state = 8; - if (scb->flags & SCF_POLL) { - while (wait_tulip(host) != -1) { - if (initio_next_state(host) == -1) - break; - } - } - } else if (scb->opcode == AbortCmd) { - if (initio_abort_srb(host, scb->srb) != 0) { - initio_unlink_pend_scb(host, scb); - initio_release_scb(host, scb); - } else { - scb->opcode = BusDevRst; - initio_select_atn_stop(host, scb); - scb->next_state = 8; - } - } else { - initio_unlink_pend_scb(host, scb); - scb->hastat = 0x16; /* bad command */ - initio_append_done_scb(host, scb); - } - return; -} - -/** - * initio_next_state - Next SCSI state - * @host: InitIO host we are processing - * - * Progress the active command block along the state machine - * until we hit a state which we must wait for activity to occur. - * - * Returns zero or a negative code. - */ - -static int initio_next_state(struct initio_host * host) -{ - int next; - - next = host->active->next_state; - for (;;) { - switch (next) { - case 1: - next = initio_state_1(host); - break; - case 2: - next = initio_state_2(host); - break; - case 3: - next = initio_state_3(host); - break; - case 4: - next = initio_state_4(host); - break; - case 5: - next = initio_state_5(host); - break; - case 6: - next = initio_state_6(host); - break; - case 7: - next = initio_state_7(host); - break; - case 8: - return initio_bus_device_reset(host); - default: - return initio_bad_seq(host); - } - if (next <= 0) - return next; - } -} - - -/** - * initio_state_1 - SCSI state machine - * @host: InitIO host we are controlling - * - * Perform SCSI state processing for Select/Attention/Stop - */ - -static int initio_state_1(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - struct target_control *active_tc = host->active_tc; -#if DEBUG_STATE - printk("-s1-"); -#endif - - /* Move the SCB from pending to busy */ - initio_unlink_pend_scb(host, scb); - initio_append_busy_scb(host, scb); - - outb(active_tc->sconfig0, host->addr + TUL_SConfig ); - /* ATN on */ - if (host->phase == MSG_OUT) { - outb(TSC_EN_BUS_IN | TSC_HW_RESELECT, host->addr + TUL_SCtrl1); - outb(scb->ident, host->addr + TUL_SFifo); - - if (scb->tagmsg) { - outb(scb->tagmsg, host->addr + TUL_SFifo); - outb(scb->tagid, host->addr + TUL_SFifo); - } - if ((active_tc->flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) { - active_tc->flags |= TCF_WDTR_DONE; - outb(MSG_EXTEND, host->addr + TUL_SFifo); - outb(2, host->addr + TUL_SFifo); /* Extended msg length */ - outb(3, host->addr + TUL_SFifo); /* Sync request */ - outb(1, host->addr + TUL_SFifo); /* Start from 16 bits */ - } else if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) { - active_tc->flags |= TCF_SYNC_DONE; - outb(MSG_EXTEND, host->addr + TUL_SFifo); - outb(3, host->addr + TUL_SFifo); /* extended msg length */ - outb(1, host->addr + TUL_SFifo); /* sync request */ - outb(initio_rate_tbl[active_tc->flags & TCF_SCSI_RATE], host->addr + TUL_SFifo); - outb(MAX_OFFSET, host->addr + TUL_SFifo); /* REQ/ACK offset */ - } - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - } - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), host->addr + TUL_SSignal); - /* Into before CDB xfer */ - return 3; -} - - -/** - * initio_state_2 - SCSI state machine - * @host: InitIO host we are controlling - * - * state after selection with attention - * state after selection with attention3 - */ - -static int initio_state_2(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - struct target_control *active_tc = host->active_tc; -#if DEBUG_STATE - printk("-s2-"); -#endif - - initio_unlink_pend_scb(host, scb); - initio_append_busy_scb(host, scb); - - outb(active_tc->sconfig0, host->addr + TUL_SConfig); - - if (host->jsstatus1 & TSS_CMD_PH_CMP) - return 4; - - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), host->addr + TUL_SSignal); - /* Into before CDB xfer */ - return 3; -} - -/** - * initio_state_3 - SCSI state machine - * @host: InitIO host we are controlling - * - * state before CDB xfer is done - */ - -static int initio_state_3(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - struct target_control *active_tc = host->active_tc; - int i; - -#if DEBUG_STATE - printk("-s3-"); -#endif - for (;;) { - switch (host->phase) { - case CMD_OUT: /* Command out phase */ - for (i = 0; i < (int) scb->cdblen; i++) - outb(scb->cdb[i], host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - if (host->phase == CMD_OUT) - return initio_bad_seq(host); - return 4; - - case MSG_IN: /* Message in phase */ - scb->next_state = 3; - if (initio_msgin(host) == -1) - return -1; - break; - - case STATUS_IN: /* Status phase */ - if (initio_status_msg(host) == -1) - return -1; - break; - - case MSG_OUT: /* Message out phase */ - if (active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) { - outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */ - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - } else { - active_tc->flags |= TCF_SYNC_DONE; - - outb(MSG_EXTEND, host->addr + TUL_SFifo); - outb(3, host->addr + TUL_SFifo); /* ext. msg len */ - outb(1, host->addr + TUL_SFifo); /* sync request */ - outb(initio_rate_tbl[active_tc->flags & TCF_SCSI_RATE], host->addr + TUL_SFifo); - outb(MAX_OFFSET, host->addr + TUL_SFifo); /* REQ/ACK offset */ - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - outb(inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7), host->addr + TUL_SSignal); - - } - break; - default: - return initio_bad_seq(host); - } - } -} - -/** - * initio_state_4 - SCSI state machine - * @host: InitIO host we are controlling - * - * SCSI state machine. State 4 - */ - -static int initio_state_4(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - -#if DEBUG_STATE - printk("-s4-"); -#endif - if ((scb->flags & SCF_DIR) == SCF_NO_XF) { - return 6; /* Go to state 6 (After data) */ - } - for (;;) { - if (scb->buflen == 0) - return 6; - - switch (host->phase) { - - case STATUS_IN: /* Status phase */ - if ((scb->flags & SCF_DIR) != 0) /* if direction bit set then report data underrun */ - scb->hastat = HOST_DO_DU; - if ((initio_status_msg(host)) == -1) - return -1; - break; - - case MSG_IN: /* Message in phase */ - scb->next_state = 0x4; - if (initio_msgin(host) == -1) - return -1; - break; - - case MSG_OUT: /* Message out phase */ - if (host->jsstatus0 & TSS_PAR_ERROR) { - scb->buflen = 0; - scb->hastat = HOST_DO_DU; - if (initio_msgout_ide(host) == -1) - return -1; - return 6; - } else { - outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */ - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - } - break; - - case DATA_IN: /* Data in phase */ - return initio_xfer_data_in(host); - - case DATA_OUT: /* Data out phase */ - return initio_xfer_data_out(host); - - default: - return initio_bad_seq(host); - } - } -} - - -/** - * initio_state_5 - SCSI state machine - * @host: InitIO host we are controlling - * - * State after dma xfer done or phase change before xfer done - */ - -static int initio_state_5(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - long cnt, xcnt; /* cannot use unsigned !! code: if (xcnt < 0) */ - -#if DEBUG_STATE - printk("-s5-"); -#endif - /*------ get remaining count -------*/ - cnt = inl(host->addr + TUL_SCnt0) & 0x0FFFFFF; - - if (inb(host->addr + TUL_XCmd) & 0x20) { - /* ----------------------- DATA_IN ----------------------------- */ - /* check scsi parity error */ - if (host->jsstatus0 & TSS_PAR_ERROR) - scb->hastat = HOST_DO_DU; - if (inb(host->addr + TUL_XStatus) & XPEND) { /* DMA xfer pending, Send STOP */ - /* tell Hardware scsi xfer has been terminated */ - outb(inb(host->addr + TUL_XCtrl) | 0x80, host->addr + TUL_XCtrl); - /* wait until DMA xfer not pending */ - while (inb(host->addr + TUL_XStatus) & XPEND) - cpu_relax(); - } - } else { - /*-------- DATA OUT -----------*/ - if ((inb(host->addr + TUL_SStatus1) & TSS_XFER_CMP) == 0) { - if (host->active_tc->js_period & TSC_WIDE_SCSI) - cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F) << 1; - else - cnt += (inb(host->addr + TUL_SFifoCnt) & 0x1F); - } - if (inb(host->addr + TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */ - outb(TAX_X_ABT, host->addr + TUL_XCmd); - /* wait Abort DMA xfer done */ - while ((inb(host->addr + TUL_Int) & XABT) == 0) - cpu_relax(); - } - if ((cnt == 1) && (host->phase == DATA_OUT)) { - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - cnt = 0; - } else { - if ((inb(host->addr + TUL_SStatus1) & TSS_XFER_CMP) == 0) - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - } - } - if (cnt == 0) { - scb->buflen = 0; - return 6; /* After Data */ - } - /* Update active data pointer */ - xcnt = (long) scb->buflen - cnt; /* xcnt== bytes already xferred */ - scb->buflen = (u32) cnt; /* cnt == bytes left to be xferred */ - if (scb->flags & SCF_SG) { - struct sg_entry *sgp; - unsigned long i; - - sgp = &scb->sglist[scb->sgidx]; - for (i = scb->sgidx; i < scb->sgmax; sgp++, i++) { - xcnt -= (long) sgp->len; - if (xcnt < 0) { /* this sgp xfer half done */ - xcnt += (long) sgp->len; /* xcnt == bytes xferred in this sgp */ - sgp->data += (u32) xcnt; /* new ptr to be xfer */ - sgp->len -= (u32) xcnt; /* new len to be xfer */ - scb->bufptr += ((u32) (i - scb->sgidx) << 3); - /* new SG table ptr */ - scb->sglen = (u8) (scb->sgmax - i); - /* new SG table len */ - scb->sgidx = (u16) i; - /* for next disc and come in this loop */ - return 4; /* Go to state 4 */ - } - /* else (xcnt >= 0 , i.e. this sgp already xferred */ - } /* for */ - return 6; /* Go to state 6 */ - } else { - scb->bufptr += (u32) xcnt; - } - return 4; /* Go to state 4 */ -} - -/** - * initio_state_6 - SCSI state machine - * @host: InitIO host we are controlling - * - * State after Data phase - */ - -static int initio_state_6(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - -#if DEBUG_STATE - printk("-s6-"); -#endif - for (;;) { - switch (host->phase) { - case STATUS_IN: /* Status phase */ - if ((initio_status_msg(host)) == -1) - return -1; - break; - - case MSG_IN: /* Message in phase */ - scb->next_state = 6; - if ((initio_msgin(host)) == -1) - return -1; - break; - - case MSG_OUT: /* Message out phase */ - outb(MSG_NOP, host->addr + TUL_SFifo); /* msg nop */ - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - break; - - case DATA_IN: /* Data in phase */ - return initio_xpad_in(host); - - case DATA_OUT: /* Data out phase */ - return initio_xpad_out(host); - - default: - return initio_bad_seq(host); - } - } -} - -/** - * initio_state_7 - SCSI state machine - * @host: InitIO host we are controlling - * - */ - -int initio_state_7(struct initio_host * host) -{ - int cnt, i; - -#if DEBUG_STATE - printk("-s7-"); -#endif - /* flush SCSI FIFO */ - cnt = inb(host->addr + TUL_SFifoCnt) & 0x1F; - if (cnt) { - for (i = 0; i < cnt; i++) - inb(host->addr + TUL_SFifo); - } - switch (host->phase) { - case DATA_IN: /* Data in phase */ - case DATA_OUT: /* Data out phase */ - return initio_bad_seq(host); - default: - return 6; /* Go to state 6 */ - } -} - -/** - * initio_xfer_data_in - Commence data input - * @host: InitIO host in use - * - * Commence a block of data transfer. The transfer itself will - * be managed by the controller and we will get a completion (or - * failure) interrupt. - */ -static int initio_xfer_data_in(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - - if ((scb->flags & SCF_DIR) == SCF_DOUT) - return 6; /* wrong direction */ - - outl(scb->buflen, host->addr + TUL_SCnt0); - outb(TSC_XF_DMA_IN, host->addr + TUL_SCmd); /* 7/25/95 */ - - if (scb->flags & SCF_SG) { /* S/G xfer */ - outl(((u32) scb->sglen) << 3, host->addr + TUL_XCntH); - outl(scb->bufptr, host->addr + TUL_XAddH); - outb(TAX_SG_IN, host->addr + TUL_XCmd); - } else { - outl(scb->buflen, host->addr + TUL_XCntH); - outl(scb->bufptr, host->addr + TUL_XAddH); - outb(TAX_X_IN, host->addr + TUL_XCmd); - } - scb->next_state = 0x5; - return 0; /* return to OS, wait xfer done , let jas_isr come in */ -} - -/** - * initio_xfer_data_out - Commence data output - * @host: InitIO host in use - * - * Commence a block of data transfer. The transfer itself will - * be managed by the controller and we will get a completion (or - * failure) interrupt. - */ - -static int initio_xfer_data_out(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - - if ((scb->flags & SCF_DIR) == SCF_DIN) - return 6; /* wrong direction */ - - outl(scb->buflen, host->addr + TUL_SCnt0); - outb(TSC_XF_DMA_OUT, host->addr + TUL_SCmd); - - if (scb->flags & SCF_SG) { /* S/G xfer */ - outl(((u32) scb->sglen) << 3, host->addr + TUL_XCntH); - outl(scb->bufptr, host->addr + TUL_XAddH); - outb(TAX_SG_OUT, host->addr + TUL_XCmd); - } else { - outl(scb->buflen, host->addr + TUL_XCntH); - outl(scb->bufptr, host->addr + TUL_XAddH); - outb(TAX_X_OUT, host->addr + TUL_XCmd); - } - - scb->next_state = 0x5; - return 0; /* return to OS, wait xfer done , let jas_isr come in */ -} - -int initio_xpad_in(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - struct target_control *active_tc = host->active_tc; - - if ((scb->flags & SCF_DIR) != SCF_NO_DCHK) - scb->hastat = HOST_DO_DU; /* over run */ - for (;;) { - if (active_tc->js_period & TSC_WIDE_SCSI) - outl(2, host->addr + TUL_SCnt0); - else - outl(1, host->addr + TUL_SCnt0); - - outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - if (host->phase != DATA_IN) { - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - return 6; - } - inb(host->addr + TUL_SFifo); - } -} - -int initio_xpad_out(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - struct target_control *active_tc = host->active_tc; - - if ((scb->flags & SCF_DIR) != SCF_NO_DCHK) - scb->hastat = HOST_DO_DU; /* over run */ - for (;;) { - if (active_tc->js_period & TSC_WIDE_SCSI) - outl(2, host->addr + TUL_SCnt0); - else - outl(1, host->addr + TUL_SCnt0); - - outb(0, host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - if ((wait_tulip(host)) == -1) - return -1; - if (host->phase != DATA_OUT) { /* Disable wide CPU to allow read 16 bits */ - outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - return 6; - } - } -} - -int initio_status_msg(struct initio_host * host) -{ /* status & MSG_IN */ - struct scsi_ctrl_blk *scb = host->active; - u8 msg; - - outb(TSC_CMD_COMP, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - - /* get status */ - scb->tastat = inb(host->addr + TUL_SFifo); - - if (host->phase == MSG_OUT) { - if (host->jsstatus0 & TSS_PAR_ERROR) - outb(MSG_PARITY, host->addr + TUL_SFifo); - else - outb(MSG_NOP, host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - return wait_tulip(host); - } - if (host->phase == MSG_IN) { - msg = inb(host->addr + TUL_SFifo); - if (host->jsstatus0 & TSS_PAR_ERROR) { /* Parity error */ - if ((initio_msgin_accept(host)) == -1) - return -1; - if (host->phase != MSG_OUT) - return initio_bad_seq(host); - outb(MSG_PARITY, host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - return wait_tulip(host); - } - if (msg == 0) { /* Command complete */ - - if ((scb->tastat & 0x18) == 0x10) /* No link support */ - return initio_bad_seq(host); - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd); - return initio_wait_done_disc(host); - - } - if (msg == MSG_LINK_COMP || msg == MSG_LINK_FLAG) { - if ((scb->tastat & 0x18) == 0x10) - return initio_msgin_accept(host); - } - } - return initio_bad_seq(host); -} - - -/* scsi bus free */ -int int_initio_busfree(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - - if (scb != NULL) { - if (scb->status & SCB_SELECT) { /* selection timeout */ - initio_unlink_pend_scb(host, scb); - scb->hastat = HOST_SEL_TOUT; - initio_append_done_scb(host, scb); - } else { /* Unexpected bus free */ - initio_unlink_busy_scb(host, scb); - scb->hastat = HOST_BUS_FREE; - initio_append_done_scb(host, scb); - } - host->active = NULL; - host->active_tc = NULL; - } - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */ - outb(TSC_INITDEFAULT, host->addr + TUL_SConfig); - outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */ - return -1; -} - - -/** - * int_initio_scsi_rst - SCSI reset occurred - * @host: Host seeing the reset - * - * A SCSI bus reset has occurred. Clean up any pending transfer - * the hardware is doing by DMA and then abort all active and - * disconnected commands. The mid layer should sort the rest out - * for us - */ - -static int int_initio_scsi_rst(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb; - int i; - - /* if DMA xfer is pending, abort DMA xfer */ - if (inb(host->addr + TUL_XStatus) & 0x01) { - outb(TAX_X_ABT | TAX_X_CLR_FIFO, host->addr + TUL_XCmd); - /* wait Abort DMA xfer done */ - while ((inb(host->addr + TUL_Int) & 0x04) == 0) - cpu_relax(); - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - } - /* Abort all active & disconnected scb */ - while ((scb = initio_pop_busy_scb(host)) != NULL) { - scb->hastat = HOST_BAD_PHAS; - initio_append_done_scb(host, scb); - } - host->active = NULL; - host->active_tc = NULL; - - /* clr sync nego. done flag */ - for (i = 0; i < host->max_tar; i++) - host->targets[i].flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE); - return -1; -} - -/** - * int_initio_scsi_resel - Reselection occurred - * @host: InitIO host adapter - * - * A SCSI reselection event has been signalled and the interrupt - * is now being processed. Work out which command block needs attention - * and continue processing that command. - */ - -int int_initio_resel(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb; - struct target_control *active_tc; - u8 tag, msg = 0; - u8 tar, lun; - - if ((scb = host->active) != NULL) { - /* FIXME: Why check and not just clear ? */ - if (scb->status & SCB_SELECT) /* if waiting for selection complete */ - scb->status &= ~SCB_SELECT; - host->active = NULL; - } - /* --------- get target id---------------------- */ - tar = inb(host->addr + TUL_SBusId); - /* ------ get LUN from Identify message----------- */ - lun = inb(host->addr + TUL_SIdent) & 0x0F; - /* 07/22/98 from 0x1F -> 0x0F */ - active_tc = &host->targets[tar]; - host->active_tc = active_tc; - outb(active_tc->sconfig0, host->addr + TUL_SConfig); - outb(active_tc->js_period, host->addr + TUL_SPeriod); - - /* ------------- tag queueing ? ------------------- */ - if (active_tc->drv_flags & TCF_DRV_EN_TAG) { - if ((initio_msgin_accept(host)) == -1) - return -1; - if (host->phase != MSG_IN) - goto no_tag; - outl(1, host->addr + TUL_SCnt0); - outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - msg = inb(host->addr + TUL_SFifo); /* Read Tag Message */ - - if (msg < MSG_STAG || msg > MSG_OTAG) /* Is simple Tag */ - goto no_tag; - - if (initio_msgin_accept(host) == -1) - return -1; - - if (host->phase != MSG_IN) - goto no_tag; - - outl(1, host->addr + TUL_SCnt0); - outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - tag = inb(host->addr + TUL_SFifo); /* Read Tag ID */ - scb = host->scb + tag; - if (scb->target != tar || scb->lun != lun) { - return initio_msgout_abort_tag(host); - } - if (scb->status != SCB_BUSY) { /* 03/24/95 */ - return initio_msgout_abort_tag(host); - } - host->active = scb; - if ((initio_msgin_accept(host)) == -1) - return -1; - } else { /* No tag */ - no_tag: - if ((scb = initio_find_busy_scb(host, tar | (lun << 8))) == NULL) { - return initio_msgout_abort_targ(host); - } - host->active = scb; - if (!(active_tc->drv_flags & TCF_DRV_EN_TAG)) { - if ((initio_msgin_accept(host)) == -1) - return -1; - } - } - return 0; -} - -/** - * int_initio_bad_seq - out of phase - * @host: InitIO host flagging event - * - * We have ended up out of phase somehow. Reset the host controller - * and throw all our toys out of the pram. Let the midlayer clean up - */ - -static int int_initio_bad_seq(struct initio_host * host) -{ /* target wrong phase */ - struct scsi_ctrl_blk *scb; - int i; - - initio_reset_scsi(host, 10); - - while ((scb = initio_pop_busy_scb(host)) != NULL) { - scb->hastat = HOST_BAD_PHAS; - initio_append_done_scb(host, scb); - } - for (i = 0; i < host->max_tar; i++) - host->targets[i].flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE); - return -1; -} - - -/** - * initio_msgout_abort_targ - abort a tag - * @host: InitIO host - * - * Abort when the target/lun does not match or when our SCB is not - * busy. Used by untagged commands. - */ - -static int initio_msgout_abort_targ(struct initio_host * host) -{ - - outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal); - if (initio_msgin_accept(host) == -1) - return -1; - if (host->phase != MSG_OUT) - return initio_bad_seq(host); - - outb(MSG_ABORT, host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - - return initio_wait_disc(host); -} - -/** - * initio_msgout_abort_tag - abort a tag - * @host: InitIO host - * - * Abort when the target/lun does not match or when our SCB is not - * busy. Used for tagged commands. - */ - -static int initio_msgout_abort_tag(struct initio_host * host) -{ - - outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal); - if (initio_msgin_accept(host) == -1) - return -1; - if (host->phase != MSG_OUT) - return initio_bad_seq(host); - - outb(MSG_ABORT_TAG, host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - - return initio_wait_disc(host); - -} - -/** - * initio_msgin - Message in - * @host: InitIO Host - * - * Process incoming message - */ -static int initio_msgin(struct initio_host * host) -{ - struct target_control *active_tc; - - for (;;) { - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - - outl(1, host->addr + TUL_SCnt0); - outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - - switch (inb(host->addr + TUL_SFifo)) { - case MSG_DISC: /* Disconnect msg */ - outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd); - return initio_wait_disc(host); - case MSG_SDP: - case MSG_RESTORE: - case MSG_NOP: - initio_msgin_accept(host); - break; - case MSG_REJ: /* Clear ATN first */ - outb((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)), - host->addr + TUL_SSignal); - active_tc = host->active_tc; - if ((active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) /* do sync nego */ - outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), - host->addr + TUL_SSignal); - initio_msgin_accept(host); - break; - case MSG_EXTEND: /* extended msg */ - initio_msgin_extend(host); - break; - case MSG_IGNOREWIDE: - initio_msgin_accept(host); - break; - case MSG_COMP: - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd); - return initio_wait_done_disc(host); - default: - initio_msgout_reject(host); - break; - } - if (host->phase != MSG_IN) - return host->phase; - } - /* statement won't reach here */ -} - -static int initio_msgout_reject(struct initio_host * host) -{ - outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal); - - if (initio_msgin_accept(host) == -1) - return -1; - - if (host->phase == MSG_OUT) { - outb(MSG_REJ, host->addr + TUL_SFifo); /* Msg reject */ - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - return wait_tulip(host); - } - return host->phase; -} - -static int initio_msgout_ide(struct initio_host * host) -{ - outb(MSG_IDE, host->addr + TUL_SFifo); /* Initiator Detected Error */ - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - return wait_tulip(host); -} - -static int initio_msgin_extend(struct initio_host * host) -{ - u8 len, idx; - - if (initio_msgin_accept(host) != MSG_IN) - return host->phase; - - /* Get extended msg length */ - outl(1, host->addr + TUL_SCnt0); - outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - - len = inb(host->addr + TUL_SFifo); - host->msg[0] = len; - for (idx = 1; len != 0; len--) { - - if ((initio_msgin_accept(host)) != MSG_IN) - return host->phase; - outl(1, host->addr + TUL_SCnt0); - outb(TSC_XF_FIFO_IN, host->addr + TUL_SCmd); - if (wait_tulip(host) == -1) - return -1; - host->msg[idx++] = inb(host->addr + TUL_SFifo); - } - if (host->msg[1] == 1) { /* if it's synchronous data transfer request */ - u8 r; - if (host->msg[0] != 3) /* if length is not right */ - return initio_msgout_reject(host); - if (host->active_tc->flags & TCF_NO_SYNC_NEGO) { /* Set OFFSET=0 to do async, nego back */ - host->msg[3] = 0; - } else { - if (initio_msgin_sync(host) == 0 && - (host->active_tc->flags & TCF_SYNC_DONE)) { - initio_sync_done(host); - return initio_msgin_accept(host); - } - } - - r = inb(host->addr + TUL_SSignal); - outb((r & (TSC_SET_ACK | 7)) | TSC_SET_ATN, - host->addr + TUL_SSignal); - if (initio_msgin_accept(host) != MSG_OUT) - return host->phase; - /* sync msg out */ - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); - - initio_sync_done(host); - - outb(MSG_EXTEND, host->addr + TUL_SFifo); - outb(3, host->addr + TUL_SFifo); - outb(1, host->addr + TUL_SFifo); - outb(host->msg[2], host->addr + TUL_SFifo); - outb(host->msg[3], host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - return wait_tulip(host); - } - if (host->msg[0] != 2 || host->msg[1] != 3) - return initio_msgout_reject(host); - /* if it's WIDE DATA XFER REQ */ - if (host->active_tc->flags & TCF_NO_WDTR) { - host->msg[2] = 0; - } else { - if (host->msg[2] > 2) /* > 32 bits */ - return initio_msgout_reject(host); - if (host->msg[2] == 2) { /* == 32 */ - host->msg[2] = 1; - } else { - if ((host->active_tc->flags & TCF_NO_WDTR) == 0) { - wdtr_done(host); - if ((host->active_tc->flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) - outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal); - return initio_msgin_accept(host); - } - } - } - outb(((inb(host->addr + TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN), host->addr + TUL_SSignal); - - if (initio_msgin_accept(host) != MSG_OUT) - return host->phase; - /* WDTR msg out */ - outb(MSG_EXTEND, host->addr + TUL_SFifo); - outb(2, host->addr + TUL_SFifo); - outb(3, host->addr + TUL_SFifo); - outb(host->msg[2], host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - return wait_tulip(host); -} - -static int initio_msgin_sync(struct initio_host * host) -{ - char default_period; - - default_period = initio_rate_tbl[host->active_tc->flags & TCF_SCSI_RATE]; - if (host->msg[3] > MAX_OFFSET) { - host->msg[3] = MAX_OFFSET; - if (host->msg[2] < default_period) { - host->msg[2] = default_period; - return 1; - } - if (host->msg[2] >= 59) /* Change to async */ - host->msg[3] = 0; - return 1; - } - /* offset requests asynchronous transfers ? */ - if (host->msg[3] == 0) { - return 0; - } - if (host->msg[2] < default_period) { - host->msg[2] = default_period; - return 1; - } - if (host->msg[2] >= 59) { - host->msg[3] = 0; - return 1; - } - return 0; -} - -static int wdtr_done(struct initio_host * host) -{ - host->active_tc->flags &= ~TCF_SYNC_DONE; - host->active_tc->flags |= TCF_WDTR_DONE; - - host->active_tc->js_period = 0; - if (host->msg[2]) /* if 16 bit */ - host->active_tc->js_period |= TSC_WIDE_SCSI; - host->active_tc->sconfig0 &= ~TSC_ALT_PERIOD; - outb(host->active_tc->sconfig0, host->addr + TUL_SConfig); - outb(host->active_tc->js_period, host->addr + TUL_SPeriod); - - return 1; -} - -static int initio_sync_done(struct initio_host * host) -{ - int i; - - host->active_tc->flags |= TCF_SYNC_DONE; - - if (host->msg[3]) { - host->active_tc->js_period |= host->msg[3]; - for (i = 0; i < 8; i++) { - if (initio_rate_tbl[i] >= host->msg[2]) /* pick the big one */ - break; - } - host->active_tc->js_period |= (i << 4); - host->active_tc->sconfig0 |= TSC_ALT_PERIOD; - } - outb(host->active_tc->sconfig0, host->addr + TUL_SConfig); - outb(host->active_tc->js_period, host->addr + TUL_SPeriod); - - return -1; -} - - -static int initio_post_scsi_rst(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb; - struct target_control *active_tc; - int i; - - host->active = NULL; - host->active_tc = NULL; - host->flags = 0; - - while ((scb = initio_pop_busy_scb(host)) != NULL) { - scb->hastat = HOST_BAD_PHAS; - initio_append_done_scb(host, scb); - } - /* clear sync done flag */ - active_tc = &host->targets[0]; - for (i = 0; i < host->max_tar; active_tc++, i++) { - active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE); - /* Initialize the sync. xfer register values to an asyn xfer */ - active_tc->js_period = 0; - active_tc->sconfig0 = host->sconf1; - host->act_tags[0] = 0; /* 07/22/98 */ - host->targets[i].flags &= ~TCF_BUSY; /* 07/22/98 */ - } /* for */ - - return -1; -} - -static void initio_select_atn_stop(struct initio_host * host, struct scsi_ctrl_blk * scb) -{ - scb->status |= SCB_SELECT; - scb->next_state = 0x1; - host->active = scb; - host->active_tc = &host->targets[scb->target]; - outb(TSC_SELATNSTOP, host->addr + TUL_SCmd); -} - - -static void initio_select_atn(struct initio_host * host, struct scsi_ctrl_blk * scb) -{ - int i; - - scb->status |= SCB_SELECT; - scb->next_state = 0x2; - - outb(scb->ident, host->addr + TUL_SFifo); - for (i = 0; i < (int) scb->cdblen; i++) - outb(scb->cdb[i], host->addr + TUL_SFifo); - host->active_tc = &host->targets[scb->target]; - host->active = scb; - outb(TSC_SEL_ATN, host->addr + TUL_SCmd); -} - -static void initio_select_atn3(struct initio_host * host, struct scsi_ctrl_blk * scb) -{ - int i; - - scb->status |= SCB_SELECT; - scb->next_state = 0x2; - - outb(scb->ident, host->addr + TUL_SFifo); - outb(scb->tagmsg, host->addr + TUL_SFifo); - outb(scb->tagid, host->addr + TUL_SFifo); - for (i = 0; i < scb->cdblen; i++) - outb(scb->cdb[i], host->addr + TUL_SFifo); - host->active_tc = &host->targets[scb->target]; - host->active = scb; - outb(TSC_SEL_ATN3, host->addr + TUL_SCmd); -} - -/** - * initio_bus_device_reset - SCSI Bus Device Reset - * @host: InitIO host to reset - * - * Perform a device reset and abort all pending SCBs for the - * victim device - */ -int initio_bus_device_reset(struct initio_host * host) -{ - struct scsi_ctrl_blk *scb = host->active; - struct target_control *active_tc = host->active_tc; - struct scsi_ctrl_blk *tmp, *prev; - u8 tar; - - if (host->phase != MSG_OUT) - return int_initio_bad_seq(host); /* Unexpected phase */ - - initio_unlink_pend_scb(host, scb); - initio_release_scb(host, scb); - - - tar = scb->target; /* target */ - active_tc->flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY); - /* clr sync. nego & WDTR flags 07/22/98 */ - - /* abort all SCB with same target */ - prev = tmp = host->first_busy; /* Check Busy queue */ - while (tmp != NULL) { - if (tmp->target == tar) { - /* unlink it */ - if (tmp == host->first_busy) { - if ((host->first_busy = tmp->next) == NULL) - host->last_busy = NULL; - } else { - prev->next = tmp->next; - if (tmp == host->last_busy) - host->last_busy = prev; - } - tmp->hastat = HOST_ABORTED; - initio_append_done_scb(host, tmp); - } - /* Previous haven't change */ - else { - prev = tmp; - } - tmp = tmp->next; - } - outb(MSG_DEVRST, host->addr + TUL_SFifo); - outb(TSC_XF_FIFO_OUT, host->addr + TUL_SCmd); - return initio_wait_disc(host); - -} - -static int initio_msgin_accept(struct initio_host * host) -{ - outb(TSC_MSG_ACCEPT, host->addr + TUL_SCmd); - return wait_tulip(host); -} - -static int wait_tulip(struct initio_host * host) -{ - - while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) - & TSS_INT_PENDING)) - cpu_relax(); - - host->jsint = inb(host->addr + TUL_SInt); - host->phase = host->jsstatus0 & TSS_PH_MASK; - host->jsstatus1 = inb(host->addr + TUL_SStatus1); - - if (host->jsint & TSS_RESEL_INT) /* if SCSI bus reset detected */ - return int_initio_resel(host); - if (host->jsint & TSS_SEL_TIMEOUT) /* if selected/reselected timeout interrupt */ - return int_initio_busfree(host); - if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */ - return int_initio_scsi_rst(host); - - if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */ - if (host->flags & HCF_EXPECT_DONE_DISC) { - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */ - initio_unlink_busy_scb(host, host->active); - host->active->hastat = 0; - initio_append_done_scb(host, host->active); - host->active = NULL; - host->active_tc = NULL; - host->flags &= ~HCF_EXPECT_DONE_DISC; - outb(TSC_INITDEFAULT, host->addr + TUL_SConfig); - outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */ - return -1; - } - if (host->flags & HCF_EXPECT_DISC) { - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */ - host->active = NULL; - host->active_tc = NULL; - host->flags &= ~HCF_EXPECT_DISC; - outb(TSC_INITDEFAULT, host->addr + TUL_SConfig); - outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */ - return -1; - } - return int_initio_busfree(host); - } - /* The old code really does the below. Can probably be removed */ - if (host->jsint & (TSS_FUNC_COMP | TSS_BUS_SERV)) - return host->phase; - return host->phase; -} - -static int initio_wait_disc(struct initio_host * host) -{ - while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) & TSS_INT_PENDING)) - cpu_relax(); - - host->jsint = inb(host->addr + TUL_SInt); - - if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */ - return int_initio_scsi_rst(host); - if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */ - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */ - outb(TSC_INITDEFAULT, host->addr + TUL_SConfig); - outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */ - host->active = NULL; - return -1; - } - return initio_bad_seq(host); -} - -static int initio_wait_done_disc(struct initio_host * host) -{ - while (!((host->jsstatus0 = inb(host->addr + TUL_SStatus0)) - & TSS_INT_PENDING)) - cpu_relax(); - - host->jsint = inb(host->addr + TUL_SInt); - - if (host->jsint & TSS_SCSIRST_INT) /* if SCSI bus reset detected */ - return int_initio_scsi_rst(host); - if (host->jsint & TSS_DISC_INT) { /* BUS disconnection */ - outb(TSC_FLUSH_FIFO, host->addr + TUL_SCtrl0); /* Flush SCSI FIFO */ - outb(TSC_INITDEFAULT, host->addr + TUL_SConfig); - outb(TSC_HW_RESELECT, host->addr + TUL_SCtrl1); /* Enable HW reselect */ - initio_unlink_busy_scb(host, host->active); - - initio_append_done_scb(host, host->active); - host->active = NULL; - return -1; - } - return initio_bad_seq(host); -} - -/** - * i91u_intr - IRQ handler - * @irqno: IRQ number - * @dev_id: IRQ identifier - * - * Take the relevant locks and then invoke the actual isr processing - * code under the lock. - */ - -static irqreturn_t i91u_intr(int irqno, void *dev_id) -{ - struct Scsi_Host *dev = dev_id; - unsigned long flags; - int r; - - spin_lock_irqsave(dev->host_lock, flags); - r = initio_isr((struct initio_host *)dev->hostdata); - spin_unlock_irqrestore(dev->host_lock, flags); - if (r) - return IRQ_HANDLED; - else - return IRQ_NONE; -} - - -/** - * initio_build_scb - Build the mappings and SCB - * @host: InitIO host taking the command - * @cblk: Firmware command block - * @cmnd: SCSI midlayer command block - * - * Translate the abstract SCSI command into a firmware command block - * suitable for feeding to the InitIO host controller. This also requires - * we build the scatter gather lists and ensure they are mapped properly. - */ - -static void initio_build_scb(struct initio_host * host, struct scsi_ctrl_blk * cblk, struct scsi_cmnd * cmnd) -{ /* Create corresponding SCB */ - struct scatterlist *sglist; - struct sg_entry *sg; /* Pointer to SG list */ - int i, nseg; - long total_len; - dma_addr_t dma_addr; - - /* Fill in the command headers */ - cblk->post = i91uSCBPost; /* i91u's callback routine */ - cblk->srb = cmnd; - cblk->opcode = ExecSCSI; - cblk->flags = SCF_POST; /* After SCSI done, call post routine */ - cblk->target = cmnd->device->id; - cblk->lun = cmnd->device->lun; - cblk->ident = cmnd->device->lun | DISC_ALLOW; - - cblk->flags |= SCF_SENSE; /* Turn on auto request sense */ - - /* Map the sense buffer into bus memory */ - dma_addr = dma_map_single(&host->pci_dev->dev, cmnd->sense_buffer, - SENSE_SIZE, DMA_FROM_DEVICE); - cblk->senseptr = (u32)dma_addr; - cblk->senselen = SENSE_SIZE; - cmnd->SCp.ptr = (char *)(unsigned long)dma_addr; - cblk->cdblen = cmnd->cmd_len; - - /* Clear the returned status */ - cblk->hastat = 0; - cblk->tastat = 0; - /* Command the command */ - memcpy(cblk->cdb, cmnd->cmnd, cmnd->cmd_len); - - /* Set up tags */ - if (cmnd->device->tagged_supported) { /* Tag Support */ - cblk->tagmsg = SIMPLE_QUEUE_TAG; /* Do simple tag only */ - } else { - cblk->tagmsg = 0; /* No tag support */ - } - - /* todo handle map_sg error */ - nseg = scsi_dma_map(cmnd); - BUG_ON(nseg < 0); - if (nseg) { - dma_addr = dma_map_single(&host->pci_dev->dev, &cblk->sglist[0], - sizeof(struct sg_entry) * TOTAL_SG_ENTRY, - DMA_BIDIRECTIONAL); - cblk->bufptr = (u32)dma_addr; - cmnd->SCp.dma_handle = dma_addr; - - cblk->sglen = nseg; - - cblk->flags |= SCF_SG; /* Turn on SG list flag */ - total_len = 0; - sg = &cblk->sglist[0]; - scsi_for_each_sg(cmnd, sglist, cblk->sglen, i) { - sg->data = cpu_to_le32((u32)sg_dma_address(sglist)); - sg->len = cpu_to_le32((u32)sg_dma_len(sglist)); - total_len += sg_dma_len(sglist); - ++sg; - } - - cblk->buflen = (scsi_bufflen(cmnd) > total_len) ? - total_len : scsi_bufflen(cmnd); - } else { /* No data transfer required */ - cblk->buflen = 0; - cblk->sglen = 0; - } -} - -/** - * i91u_queuecommand - Queue a new command if possible - * @cmd: SCSI command block from the mid layer - * @done: Completion handler - * - * Attempts to queue a new command with the host adapter. Will return - * zero if successful or indicate a host busy condition if not (which - * will cause the mid layer to call us again later with the command) - */ - -static int i91u_queuecommand_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - struct initio_host *host = (struct initio_host *) cmd->device->host->hostdata; - struct scsi_ctrl_blk *cmnd; - - cmd->scsi_done = done; - - cmnd = initio_alloc_scb(host); - if (!cmnd) - return SCSI_MLQUEUE_HOST_BUSY; - - initio_build_scb(host, cmnd, cmd); - initio_exec_scb(host, cmnd); - return 0; -} - -static DEF_SCSI_QCMD(i91u_queuecommand) - -/** - * i91u_bus_reset - reset the SCSI bus - * @cmnd: Command block we want to trigger the reset for - * - * Initiate a SCSI bus reset sequence - */ - -static int i91u_bus_reset(struct scsi_cmnd * cmnd) -{ - struct initio_host *host; - - host = (struct initio_host *) cmnd->device->host->hostdata; - - spin_lock_irq(cmnd->device->host->host_lock); - initio_reset_scsi(host, 0); - spin_unlock_irq(cmnd->device->host->host_lock); - - return SUCCESS; -} - -/** - * i91u_biospararm - return the "logical geometry - * @sdev: SCSI device - * @dev; Matching block device - * @capacity: Sector size of drive - * @info_array: Return space for BIOS geometry - * - * Map the device geometry in a manner compatible with the host - * controller BIOS behaviour. - * - * FIXME: limited to 2^32 sector devices. - */ - -static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev, - sector_t capacity, int *info_array) -{ - struct initio_host *host; /* Point to Host adapter control block */ - struct target_control *tc; - - host = (struct initio_host *) sdev->host->hostdata; - tc = &host->targets[sdev->id]; - - if (tc->heads) { - info_array[0] = tc->heads; - info_array[1] = tc->sectors; - info_array[2] = (unsigned long)capacity / tc->heads / tc->sectors; - } else { - if (tc->drv_flags & TCF_DRV_255_63) { - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = (unsigned long)capacity / 255 / 63; - } else { - info_array[0] = 64; - info_array[1] = 32; - info_array[2] = (unsigned long)capacity >> 11; - } - } - -#if defined(DEBUG_BIOSPARAM) - if (i91u_debug & debug_biosparam) { - printk("bios geometry: head=%d, sec=%d, cyl=%d\n", - info_array[0], info_array[1], info_array[2]); - printk("WARNING: check, if the bios geometry is correct.\n"); - } -#endif - - return 0; -} - -/** - * i91u_unmap_scb - Unmap a command - * @pci_dev: PCI device the command is for - * @cmnd: The command itself - * - * Unmap any PCI mapping/IOMMU resources allocated when the command - * was mapped originally as part of initio_build_scb - */ - -static void i91u_unmap_scb(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd) -{ - /* auto sense buffer */ - if (cmnd->SCp.ptr) { - dma_unmap_single(&pci_dev->dev, - (dma_addr_t)((unsigned long)cmnd->SCp.ptr), - SENSE_SIZE, DMA_FROM_DEVICE); - cmnd->SCp.ptr = NULL; - } - - /* request buffer */ - if (scsi_sg_count(cmnd)) { - dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle, - sizeof(struct sg_entry) * TOTAL_SG_ENTRY, - DMA_BIDIRECTIONAL); - - scsi_dma_unmap(cmnd); - } -} - -/** - * i91uSCBPost - SCSI callback - * @host: Pointer to host adapter control block. - * @cmnd: Pointer to SCSI control block. - * - * This is callback routine be called when tulip finish one - * SCSI command. - */ - -static void i91uSCBPost(u8 * host_mem, u8 * cblk_mem) -{ - struct scsi_cmnd *cmnd; /* Pointer to SCSI request block */ - struct initio_host *host; - struct scsi_ctrl_blk *cblk; - - host = (struct initio_host *) host_mem; - cblk = (struct scsi_ctrl_blk *) cblk_mem; - if ((cmnd = cblk->srb) == NULL) { - printk(KERN_ERR "i91uSCBPost: SRB pointer is empty\n"); - WARN_ON(1); - initio_release_scb(host, cblk); /* Release SCB for current channel */ - return; - } - - /* - * Remap the firmware error status into a mid layer one - */ - switch (cblk->hastat) { - case 0x0: - case 0xa: /* Linked command complete without error and linked normally */ - case 0xb: /* Linked command complete without error interrupt generated */ - cblk->hastat = 0; - break; - - case 0x11: /* Selection time out-The initiator selection or target - reselection was not complete within the SCSI Time out period */ - cblk->hastat = DID_TIME_OUT; - break; - - case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus - phase sequence was requested by the target. The host adapter - will generate a SCSI Reset Condition, notifying the host with - a SCRD interrupt */ - cblk->hastat = DID_RESET; - break; - - case 0x1a: /* SCB Aborted. 07/21/98 */ - cblk->hastat = DID_ABORT; - break; - - case 0x12: /* Data overrun/underrun-The target attempted to transfer more data - than was allocated by the Data Length field or the sum of the - Scatter / Gather Data Length fields. */ - case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ - case 0x16: /* Invalid SCB Operation Code. */ - - default: - printk("ini9100u: %x %x\n", cblk->hastat, cblk->tastat); - cblk->hastat = DID_ERROR; /* Couldn't find any better */ - break; - } - - cmnd->result = cblk->tastat | (cblk->hastat << 16); - i91u_unmap_scb(host->pci_dev, cmnd); - cmnd->scsi_done(cmnd); /* Notify system DONE */ - initio_release_scb(host, cblk); /* Release SCB for current channel */ -} - -static struct scsi_host_template initio_template = { - .proc_name = "INI9100U", - .name = "Initio INI-9X00U/UW SCSI device driver", - .queuecommand = i91u_queuecommand, - .eh_bus_reset_handler = i91u_bus_reset, - .bios_param = i91u_biosparam, - .can_queue = MAX_TARGETS * i91u_MAXQUEUE, - .this_id = 1, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -static int initio_probe_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct Scsi_Host *shost; - struct initio_host *host; - u32 reg; - u16 bios_seg; - struct scsi_ctrl_blk *scb, *tmp, *prev = NULL /* silence gcc */; - int num_scb, i, error; - - error = pci_enable_device(pdev); - if (error) - return error; - - pci_read_config_dword(pdev, 0x44, (u32 *) & reg); - bios_seg = (u16) (reg & 0xFF); - if (((reg & 0xFF00) >> 8) == 0xFF) - reg = 0; - bios_seg = (bios_seg << 8) + ((u16) ((reg & 0xFF00) >> 8)); - - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "i91u: Could not set 32 bit DMA mask\n"); - error = -ENODEV; - goto out_disable_device; - } - shost = scsi_host_alloc(&initio_template, sizeof(struct initio_host)); - if (!shost) { - printk(KERN_WARNING "initio: Could not allocate host structure.\n"); - error = -ENOMEM; - goto out_disable_device; - } - host = (struct initio_host *)shost->hostdata; - memset(host, 0, sizeof(struct initio_host)); - host->addr = pci_resource_start(pdev, 0); - host->bios_addr = bios_seg; - - if (!request_region(host->addr, 256, "i91u")) { - printk(KERN_WARNING "initio: I/O port range 0x%x is busy.\n", host->addr); - error = -ENODEV; - goto out_host_put; - } - - if (initio_tag_enable) /* 1.01i */ - num_scb = MAX_TARGETS * i91u_MAXQUEUE; - else - num_scb = MAX_TARGETS + 3; /* 1-tape, 1-CD_ROM, 1- extra */ - - for (; num_scb >= MAX_TARGETS + 3; num_scb--) { - i = num_scb * sizeof(struct scsi_ctrl_blk); - if ((scb = kzalloc(i, GFP_DMA)) != NULL) - break; - } - - if (!scb) { - printk(KERN_WARNING "initio: Cannot allocate SCB array.\n"); - error = -ENOMEM; - goto out_release_region; - } - - host->pci_dev = pdev; - - host->semaph = 1; - spin_lock_init(&host->semaph_lock); - host->num_scbs = num_scb; - host->scb = scb; - host->next_pending = scb; - host->next_avail = scb; - for (i = 0, tmp = scb; i < num_scb; i++, tmp++) { - tmp->tagid = i; - if (i != 0) - prev->next = tmp; - prev = tmp; - } - prev->next = NULL; - host->scb_end = tmp; - host->first_avail = scb; - host->last_avail = prev; - spin_lock_init(&host->avail_lock); - - initio_init(host, phys_to_virt(((u32)bios_seg << 4))); - - host->jsstatus0 = 0; - - shost->io_port = host->addr; - shost->n_io_port = 0xff; - shost->can_queue = num_scb; /* 03/05/98 */ - shost->unique_id = host->addr; - shost->max_id = host->max_tar; - shost->max_lun = 32; /* 10/21/97 */ - shost->irq = pdev->irq; - shost->this_id = host->scsi_id; /* Assign HCS index */ - shost->base = host->addr; - shost->sg_tablesize = TOTAL_SG_ENTRY; - - error = request_irq(pdev->irq, i91u_intr, IRQF_DISABLED|IRQF_SHARED, "i91u", shost); - if (error < 0) { - printk(KERN_WARNING "initio: Unable to request IRQ %d\n", pdev->irq); - goto out_free_scbs; - } - - pci_set_drvdata(pdev, shost); - - error = scsi_add_host(shost, &pdev->dev); - if (error) - goto out_free_irq; - scsi_scan_host(shost); - return 0; -out_free_irq: - free_irq(pdev->irq, shost); -out_free_scbs: - kfree(host->scb); -out_release_region: - release_region(host->addr, 256); -out_host_put: - scsi_host_put(shost); -out_disable_device: - pci_disable_device(pdev); - return error; -} - -/** - * initio_remove_one - control shutdown - * @pdev: PCI device being released - * - * Release the resources assigned to this adapter after it has - * finished being used. - */ - -static void initio_remove_one(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - struct initio_host *s = (struct initio_host *)host->hostdata; - scsi_remove_host(host); - free_irq(pdev->irq, host); - release_region(s->addr, 256); - scsi_host_put(host); - pci_disable_device(pdev); -} - -MODULE_LICENSE("GPL"); - -static struct pci_device_id initio_pci_tbl[] = { - {PCI_VENDOR_ID_INIT, 0x9500, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_INIT, 0x9400, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_INIT, 0x9401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_INIT, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_DOMEX, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; -MODULE_DEVICE_TABLE(pci, initio_pci_tbl); - -static struct pci_driver initio_pci_driver = { - .name = "initio", - .id_table = initio_pci_tbl, - .probe = initio_probe_one, - .remove = __devexit_p(initio_remove_one), -}; - -static int __init initio_init_driver(void) -{ - return pci_register_driver(&initio_pci_driver); -} - -static void __exit initio_exit_driver(void) -{ - pci_unregister_driver(&initio_pci_driver); -} - -MODULE_DESCRIPTION("Initio INI-9X00U/UW SCSI device driver"); -MODULE_AUTHOR("Initio Corporation"); -MODULE_LICENSE("GPL"); - -module_init(initio_init_driver); -module_exit(initio_exit_driver); diff --git a/ANDROID_3.4.5/drivers/scsi/initio.h b/ANDROID_3.4.5/drivers/scsi/initio.h deleted file mode 100644 index 219b901b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/initio.h +++ /dev/null @@ -1,667 +0,0 @@ -/************************************************************************** - * Initio 9100 device driver for Linux. - * - * Copyright (c) 1994-1998 Initio Corporation - * All rights reserved. - * - * Cleanups (c) Copyright 2007 Red Hat - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - **************************************************************************/ - - -#include - -#define TOTAL_SG_ENTRY 32 -#define MAX_SUPPORTED_ADAPTERS 8 -#define MAX_OFFSET 15 -#define MAX_TARGETS 16 - -typedef struct { - unsigned short base; - unsigned short vec; -} i91u_config; - -/***************************************/ -/* Tulip Configuration Register Set */ -/***************************************/ -#define TUL_PVID 0x00 /* Vendor ID */ -#define TUL_PDID 0x02 /* Device ID */ -#define TUL_PCMD 0x04 /* Command */ -#define TUL_PSTUS 0x06 /* Status */ -#define TUL_PRID 0x08 /* Revision number */ -#define TUL_PPI 0x09 /* Programming interface */ -#define TUL_PSC 0x0A /* Sub Class */ -#define TUL_PBC 0x0B /* Base Class */ -#define TUL_PCLS 0x0C /* Cache line size */ -#define TUL_PLTR 0x0D /* Latency timer */ -#define TUL_PHDT 0x0E /* Header type */ -#define TUL_PBIST 0x0F /* BIST */ -#define TUL_PBAD 0x10 /* Base address */ -#define TUL_PBAD1 0x14 /* Base address */ -#define TUL_PBAD2 0x18 /* Base address */ -#define TUL_PBAD3 0x1C /* Base address */ -#define TUL_PBAD4 0x20 /* Base address */ -#define TUL_PBAD5 0x24 /* Base address */ -#define TUL_PRSVD 0x28 /* Reserved */ -#define TUL_PRSVD1 0x2C /* Reserved */ -#define TUL_PRAD 0x30 /* Expansion ROM base address */ -#define TUL_PRSVD2 0x34 /* Reserved */ -#define TUL_PRSVD3 0x38 /* Reserved */ -#define TUL_PINTL 0x3C /* Interrupt line */ -#define TUL_PINTP 0x3D /* Interrupt pin */ -#define TUL_PIGNT 0x3E /* MIN_GNT */ -#define TUL_PMGNT 0x3F /* MAX_GNT */ - -/************************/ -/* Jasmin Register Set */ -/************************/ -#define TUL_HACFG0 0x40 /* H/A Configuration Register 0 */ -#define TUL_HACFG1 0x41 /* H/A Configuration Register 1 */ -#define TUL_HACFG2 0x42 /* H/A Configuration Register 2 */ - -#define TUL_SDCFG0 0x44 /* SCSI Device Configuration 0 */ -#define TUL_SDCFG1 0x45 /* SCSI Device Configuration 1 */ -#define TUL_SDCFG2 0x46 /* SCSI Device Configuration 2 */ -#define TUL_SDCFG3 0x47 /* SCSI Device Configuration 3 */ - -#define TUL_GINTS 0x50 /* Global Interrupt Status Register */ -#define TUL_GIMSK 0x52 /* Global Interrupt MASK Register */ -#define TUL_GCTRL 0x54 /* Global Control Register */ -#define TUL_GCTRL_EEPROM_BIT 0x04 -#define TUL_GCTRL1 0x55 /* Global Control Register */ -#define TUL_DMACFG 0x5B /* DMA configuration */ -#define TUL_NVRAM 0x5D /* Non-volatile RAM port */ - -#define TUL_SCnt0 0x80 /* 00 R/W Transfer Counter Low */ -#define TUL_SCnt1 0x81 /* 01 R/W Transfer Counter Mid */ -#define TUL_SCnt2 0x82 /* 02 R/W Transfer Count High */ -#define TUL_SFifoCnt 0x83 /* 03 R FIFO counter */ -#define TUL_SIntEnable 0x84 /* 03 W Interrupt enble */ -#define TUL_SInt 0x84 /* 04 R Interrupt Register */ -#define TUL_SCtrl0 0x85 /* 05 W Control 0 */ -#define TUL_SStatus0 0x85 /* 05 R Status 0 */ -#define TUL_SCtrl1 0x86 /* 06 W Control 1 */ -#define TUL_SStatus1 0x86 /* 06 R Status 1 */ -#define TUL_SConfig 0x87 /* 07 W Configuration */ -#define TUL_SStatus2 0x87 /* 07 R Status 2 */ -#define TUL_SPeriod 0x88 /* 08 W Sync. Transfer Period & Offset */ -#define TUL_SOffset 0x88 /* 08 R Offset */ -#define TUL_SScsiId 0x89 /* 09 W SCSI ID */ -#define TUL_SBusId 0x89 /* 09 R SCSI BUS ID */ -#define TUL_STimeOut 0x8A /* 0A W Sel/Resel Time Out Register */ -#define TUL_SIdent 0x8A /* 0A R Identify Message Register */ -#define TUL_SAvail 0x8A /* 0A R Available Counter Register */ -#define TUL_SData 0x8B /* 0B R/W SCSI data in/out */ -#define TUL_SFifo 0x8C /* 0C R/W FIFO */ -#define TUL_SSignal 0x90 /* 10 R/W SCSI signal in/out */ -#define TUL_SCmd 0x91 /* 11 R/W Command */ -#define TUL_STest0 0x92 /* 12 R/W Test0 */ -#define TUL_STest1 0x93 /* 13 R/W Test1 */ -#define TUL_SCFG1 0x94 /* 14 R/W Configuration */ - -#define TUL_XAddH 0xC0 /*DMA Transfer Physical Address */ -#define TUL_XAddW 0xC8 /*DMA Current Transfer Physical Address */ -#define TUL_XCntH 0xD0 /*DMA Transfer Counter */ -#define TUL_XCntW 0xD4 /*DMA Current Transfer Counter */ -#define TUL_XCmd 0xD8 /*DMA Command Register */ -#define TUL_Int 0xDC /*Interrupt Register */ -#define TUL_XStatus 0xDD /*DMA status Register */ -#define TUL_Mask 0xE0 /*Interrupt Mask Register */ -#define TUL_XCtrl 0xE4 /*DMA Control Register */ -#define TUL_XCtrl1 0xE5 /*DMA Control Register 1 */ -#define TUL_XFifo 0xE8 /*DMA FIFO */ - -#define TUL_WCtrl 0xF7 /*Bus master wait state control */ -#define TUL_DCtrl 0xFB /*DMA delay control */ - -/*----------------------------------------------------------------------*/ -/* bit definition for Command register of Configuration Space Header */ -/*----------------------------------------------------------------------*/ -#define BUSMS 0x04 /* BUS MASTER Enable */ -#define IOSPA 0x01 /* IO Space Enable */ - -/*----------------------------------------------------------------------*/ -/* Command Codes of Tulip SCSI Command register */ -/*----------------------------------------------------------------------*/ -#define TSC_EN_RESEL 0x80 /* Enable Reselection */ -#define TSC_CMD_COMP 0x84 /* Command Complete Sequence */ -#define TSC_SEL 0x01 /* Select Without ATN Sequence */ -#define TSC_SEL_ATN 0x11 /* Select With ATN Sequence */ -#define TSC_SEL_ATN_DMA 0x51 /* Select With ATN Sequence with DMA */ -#define TSC_SEL_ATN3 0x31 /* Select With ATN3 Sequence */ -#define TSC_SEL_ATNSTOP 0x12 /* Select With ATN and Stop Sequence */ -#define TSC_SELATNSTOP 0x1E /* Select With ATN and Stop Sequence */ - -#define TSC_SEL_ATN_DIRECT_IN 0x95 /* Select With ATN Sequence */ -#define TSC_SEL_ATN_DIRECT_OUT 0x15 /* Select With ATN Sequence */ -#define TSC_SEL_ATN3_DIRECT_IN 0xB5 /* Select With ATN3 Sequence */ -#define TSC_SEL_ATN3_DIRECT_OUT 0x35 /* Select With ATN3 Sequence */ -#define TSC_XF_DMA_OUT_DIRECT 0x06 /* DMA Xfer Information out */ -#define TSC_XF_DMA_IN_DIRECT 0x86 /* DMA Xfer Information in */ - -#define TSC_XF_DMA_OUT 0x43 /* DMA Xfer Information out */ -#define TSC_XF_DMA_IN 0xC3 /* DMA Xfer Information in */ -#define TSC_XF_FIFO_OUT 0x03 /* FIFO Xfer Information out */ -#define TSC_XF_FIFO_IN 0x83 /* FIFO Xfer Information in */ - -#define TSC_MSG_ACCEPT 0x0F /* Message Accept */ - -/*----------------------------------------------------------------------*/ -/* bit definition for Tulip SCSI Control 0 Register */ -/*----------------------------------------------------------------------*/ -#define TSC_RST_SEQ 0x20 /* Reset sequence counter */ -#define TSC_FLUSH_FIFO 0x10 /* Flush FIFO */ -#define TSC_ABT_CMD 0x04 /* Abort command (sequence) */ -#define TSC_RST_CHIP 0x02 /* Reset SCSI Chip */ -#define TSC_RST_BUS 0x01 /* Reset SCSI Bus */ - -/*----------------------------------------------------------------------*/ -/* bit definition for Tulip SCSI Control 1 Register */ -/*----------------------------------------------------------------------*/ -#define TSC_EN_SCAM 0x80 /* Enable SCAM */ -#define TSC_TIMER 0x40 /* Select timeout unit */ -#define TSC_EN_SCSI2 0x20 /* SCSI-2 mode */ -#define TSC_PWDN 0x10 /* Power down mode */ -#define TSC_WIDE_CPU 0x08 /* Wide CPU */ -#define TSC_HW_RESELECT 0x04 /* Enable HW reselect */ -#define TSC_EN_BUS_OUT 0x02 /* Enable SCSI data bus out latch */ -#define TSC_EN_BUS_IN 0x01 /* Enable SCSI data bus in latch */ - -/*----------------------------------------------------------------------*/ -/* bit definition for Tulip SCSI Configuration Register */ -/*----------------------------------------------------------------------*/ -#define TSC_EN_LATCH 0x80 /* Enable phase latch */ -#define TSC_INITIATOR 0x40 /* Initiator mode */ -#define TSC_EN_SCSI_PAR 0x20 /* Enable SCSI parity */ -#define TSC_DMA_8BIT 0x10 /* Alternate dma 8-bits mode */ -#define TSC_DMA_16BIT 0x08 /* Alternate dma 16-bits mode */ -#define TSC_EN_WDACK 0x04 /* Enable DACK while wide SCSI xfer */ -#define TSC_ALT_PERIOD 0x02 /* Alternate sync period mode */ -#define TSC_DIS_SCSIRST 0x01 /* Disable SCSI bus reset us */ - -#define TSC_INITDEFAULT (TSC_INITIATOR | TSC_EN_LATCH | TSC_ALT_PERIOD | TSC_DIS_SCSIRST) - -#define TSC_WIDE_SCSI 0x80 /* Enable Wide SCSI */ - -/*----------------------------------------------------------------------*/ -/* bit definition for Tulip SCSI signal Register */ -/*----------------------------------------------------------------------*/ -#define TSC_RST_ACK 0x00 /* Release ACK signal */ -#define TSC_RST_ATN 0x00 /* Release ATN signal */ -#define TSC_RST_BSY 0x00 /* Release BSY signal */ - -#define TSC_SET_ACK 0x40 /* ACK signal */ -#define TSC_SET_ATN 0x08 /* ATN signal */ - -#define TSC_REQI 0x80 /* REQ signal */ -#define TSC_ACKI 0x40 /* ACK signal */ -#define TSC_BSYI 0x20 /* BSY signal */ -#define TSC_SELI 0x10 /* SEL signal */ -#define TSC_ATNI 0x08 /* ATN signal */ -#define TSC_MSGI 0x04 /* MSG signal */ -#define TSC_CDI 0x02 /* C/D signal */ -#define TSC_IOI 0x01 /* I/O signal */ - - -/*----------------------------------------------------------------------*/ -/* bit definition for Tulip SCSI Status 0 Register */ -/*----------------------------------------------------------------------*/ -#define TSS_INT_PENDING 0x80 /* Interrupt pending */ -#define TSS_SEQ_ACTIVE 0x40 /* Sequencer active */ -#define TSS_XFER_CNT 0x20 /* Transfer counter zero */ -#define TSS_FIFO_EMPTY 0x10 /* FIFO empty */ -#define TSS_PAR_ERROR 0x08 /* SCSI parity error */ -#define TSS_PH_MASK 0x07 /* SCSI phase mask */ - -/*----------------------------------------------------------------------*/ -/* bit definition for Tulip SCSI Status 1 Register */ -/*----------------------------------------------------------------------*/ -#define TSS_STATUS_RCV 0x08 /* Status received */ -#define TSS_MSG_SEND 0x40 /* Message sent */ -#define TSS_CMD_PH_CMP 0x20 /* command phase done */ -#define TSS_DATA_PH_CMP 0x10 /* Data phase done */ -#define TSS_STATUS_SEND 0x08 /* Status sent */ -#define TSS_XFER_CMP 0x04 /* Transfer completed */ -#define TSS_SEL_CMP 0x02 /* Selection completed */ -#define TSS_ARB_CMP 0x01 /* Arbitration completed */ - -/*----------------------------------------------------------------------*/ -/* bit definition for Tulip SCSI Status 2 Register */ -/*----------------------------------------------------------------------*/ -#define TSS_CMD_ABTED 0x80 /* Command aborted */ -#define TSS_OFFSET_0 0x40 /* Offset counter zero */ -#define TSS_FIFO_FULL 0x20 /* FIFO full */ -#define TSS_TIMEOUT_0 0x10 /* Timeout counter zero */ -#define TSS_BUSY_RLS 0x08 /* Busy release */ -#define TSS_PH_MISMATCH 0x04 /* Phase mismatch */ -#define TSS_SCSI_BUS_EN 0x02 /* SCSI data bus enable */ -#define TSS_SCSIRST 0x01 /* SCSI bus reset in progress */ - -/*----------------------------------------------------------------------*/ -/* bit definition for Tulip SCSI Interrupt Register */ -/*----------------------------------------------------------------------*/ -#define TSS_RESEL_INT 0x80 /* Reselected interrupt */ -#define TSS_SEL_TIMEOUT 0x40 /* Selected/reselected timeout */ -#define TSS_BUS_SERV 0x20 -#define TSS_SCSIRST_INT 0x10 /* SCSI bus reset detected */ -#define TSS_DISC_INT 0x08 /* Disconnected interrupt */ -#define TSS_SEL_INT 0x04 /* Select interrupt */ -#define TSS_SCAM_SEL 0x02 /* SCAM selected */ -#define TSS_FUNC_COMP 0x01 - -/*----------------------------------------------------------------------*/ -/* SCSI Phase Codes. */ -/*----------------------------------------------------------------------*/ -#define DATA_OUT 0 -#define DATA_IN 1 /* 4 */ -#define CMD_OUT 2 -#define STATUS_IN 3 /* 6 */ -#define MSG_OUT 6 /* 3 */ -#define MSG_IN 7 - - - -/*----------------------------------------------------------------------*/ -/* Command Codes of Tulip xfer Command register */ -/*----------------------------------------------------------------------*/ -#define TAX_X_FORC 0x02 -#define TAX_X_ABT 0x04 -#define TAX_X_CLR_FIFO 0x08 - -#define TAX_X_IN 0x21 -#define TAX_X_OUT 0x01 -#define TAX_SG_IN 0xA1 -#define TAX_SG_OUT 0x81 - -/*----------------------------------------------------------------------*/ -/* Tulip Interrupt Register */ -/*----------------------------------------------------------------------*/ -#define XCMP 0x01 -#define FCMP 0x02 -#define XABT 0x04 -#define XERR 0x08 -#define SCMP 0x10 -#define IPEND 0x80 - -/*----------------------------------------------------------------------*/ -/* Tulip DMA Status Register */ -/*----------------------------------------------------------------------*/ -#define XPEND 0x01 /* Transfer pending */ -#define FEMPTY 0x02 /* FIFO empty */ - - - -/*----------------------------------------------------------------------*/ -/* bit definition for TUL_GCTRL */ -/*----------------------------------------------------------------------*/ -#define EXTSG 0x80 -#define EXTAD 0x60 -#define SEG4K 0x08 -#define EEPRG 0x04 -#define MRMUL 0x02 - -/*----------------------------------------------------------------------*/ -/* bit definition for TUL_NVRAM */ -/*----------------------------------------------------------------------*/ -#define SE2CS 0x08 -#define SE2CLK 0x04 -#define SE2DO 0x02 -#define SE2DI 0x01 - - -/************************************************************************/ -/* Scatter-Gather Element Structure */ -/************************************************************************/ -struct sg_entry { - u32 data; /* Data Pointer */ - u32 len; /* Data Length */ -}; - -/*********************************************************************** - SCSI Control Block -************************************************************************/ -struct scsi_ctrl_blk { - struct scsi_ctrl_blk *next; - u8 status; /*4 */ - u8 next_state; /*5 */ - u8 mode; /*6 */ - u8 msgin; /*7 SCB_Res0 */ - u16 sgidx; /*8 */ - u16 sgmax; /*A */ -#ifdef ALPHA - u32 reserved[2]; /*C */ -#else - u32 reserved[3]; /*C */ -#endif - - u32 xferlen; /*18 Current xfer len */ - u32 totxlen; /*1C Total xfer len */ - u32 paddr; /*20 SCB phy. Addr. */ - - u8 opcode; /*24 SCB command code */ - u8 flags; /*25 SCB Flags */ - u8 target; /*26 Target Id */ - u8 lun; /*27 Lun */ - u32 bufptr; /*28 Data Buffer Pointer */ - u32 buflen; /*2C Data Allocation Length */ - u8 sglen; /*30 SG list # */ - u8 senselen; /*31 Sense Allocation Length */ - u8 hastat; /*32 */ - u8 tastat; /*33 */ - u8 cdblen; /*34 CDB Length */ - u8 ident; /*35 Identify */ - u8 tagmsg; /*36 Tag Message */ - u8 tagid; /*37 Queue Tag */ - u8 cdb[12]; /*38 */ - u32 sgpaddr; /*44 SG List/Sense Buf phy. Addr. */ - u32 senseptr; /*48 Sense data pointer */ - void (*post) (u8 *, u8 *); /*4C POST routine */ - struct scsi_cmnd *srb; /*50 SRB Pointer */ - struct sg_entry sglist[TOTAL_SG_ENTRY]; /*54 Start of SG list */ -}; - -/* Bit Definition for status */ -#define SCB_RENT 0x01 -#define SCB_PEND 0x02 -#define SCB_CONTIG 0x04 /* Contingent Allegiance */ -#define SCB_SELECT 0x08 -#define SCB_BUSY 0x10 -#define SCB_DONE 0x20 - - -/* Opcodes for opcode */ -#define ExecSCSI 0x1 -#define BusDevRst 0x2 -#define AbortCmd 0x3 - - -/* Bit Definition for mode */ -#define SCM_RSENS 0x01 /* request sense mode */ - - -/* Bit Definition for flags */ -#define SCF_DONE 0x01 -#define SCF_POST 0x02 -#define SCF_SENSE 0x04 -#define SCF_DIR 0x18 -#define SCF_NO_DCHK 0x00 -#define SCF_DIN 0x08 -#define SCF_DOUT 0x10 -#define SCF_NO_XF 0x18 -#define SCF_WR_VF 0x20 /* Write verify turn on */ -#define SCF_POLL 0x40 -#define SCF_SG 0x80 - -/* Error Codes for SCB_HaStat */ -#define HOST_SEL_TOUT 0x11 -#define HOST_DO_DU 0x12 -#define HOST_BUS_FREE 0x13 -#define HOST_BAD_PHAS 0x14 -#define HOST_INV_CMD 0x16 -#define HOST_ABORTED 0x1A /* 07/21/98 */ -#define HOST_SCSI_RST 0x1B -#define HOST_DEV_RST 0x1C - -/* Error Codes for SCB_TaStat */ -#define TARGET_CHKCOND 0x02 -#define TARGET_BUSY 0x08 -#define INI_QUEUE_FULL 0x28 - -/* SCSI MESSAGE */ -#define MSG_COMP 0x00 -#define MSG_EXTEND 0x01 -#define MSG_SDP 0x02 -#define MSG_RESTORE 0x03 -#define MSG_DISC 0x04 -#define MSG_IDE 0x05 -#define MSG_ABORT 0x06 -#define MSG_REJ 0x07 -#define MSG_NOP 0x08 -#define MSG_PARITY 0x09 -#define MSG_LINK_COMP 0x0A -#define MSG_LINK_FLAG 0x0B -#define MSG_DEVRST 0x0C -#define MSG_ABORT_TAG 0x0D - -/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */ -#define MSG_STAG 0x20 -#define MSG_HTAG 0x21 -#define MSG_OTAG 0x22 - -#define MSG_IGNOREWIDE 0x23 - -#define MSG_IDENT 0x80 - -/*********************************************************************** - Target Device Control Structure -**********************************************************************/ - -struct target_control { - u16 flags; - u8 js_period; - u8 sconfig0; - u16 drv_flags; - u8 heads; - u8 sectors; -}; - -/*********************************************************************** - Target Device Control Structure -**********************************************************************/ - -/* Bit Definition for TCF_Flags */ -#define TCF_SCSI_RATE 0x0007 -#define TCF_EN_DISC 0x0008 -#define TCF_NO_SYNC_NEGO 0x0010 -#define TCF_NO_WDTR 0x0020 -#define TCF_EN_255 0x0040 -#define TCF_EN_START 0x0080 -#define TCF_WDTR_DONE 0x0100 -#define TCF_SYNC_DONE 0x0200 -#define TCF_BUSY 0x0400 - - -/* Bit Definition for TCF_DrvFlags */ -#define TCF_DRV_BUSY 0x01 /* Indicate target busy(driver) */ -#define TCF_DRV_EN_TAG 0x0800 -#define TCF_DRV_255_63 0x0400 - -/*********************************************************************** - Host Adapter Control Structure -************************************************************************/ -struct initio_host { - u16 addr; /* 00 */ - u16 bios_addr; /* 02 */ - u8 irq; /* 04 */ - u8 scsi_id; /* 05 */ - u8 max_tar; /* 06 */ - u8 num_scbs; /* 07 */ - - u8 flags; /* 08 */ - u8 index; /* 09 */ - u8 ha_id; /* 0A */ - u8 config; /* 0B */ - u16 idmask; /* 0C */ - u8 semaph; /* 0E */ - u8 phase; /* 0F */ - u8 jsstatus0; /* 10 */ - u8 jsint; /* 11 */ - u8 jsstatus1; /* 12 */ - u8 sconf1; /* 13 */ - - u8 msg[8]; /* 14 */ - struct scsi_ctrl_blk *next_avail; /* 1C */ - struct scsi_ctrl_blk *scb; /* 20 */ - struct scsi_ctrl_blk *scb_end; /* 24 */ /*UNUSED*/ - struct scsi_ctrl_blk *next_pending; /* 28 */ - struct scsi_ctrl_blk *next_contig; /* 2C */ /*UNUSED*/ - struct scsi_ctrl_blk *active; /* 30 */ - struct target_control *active_tc; /* 34 */ - - struct scsi_ctrl_blk *first_avail; /* 38 */ - struct scsi_ctrl_blk *last_avail; /* 3C */ - struct scsi_ctrl_blk *first_pending; /* 40 */ - struct scsi_ctrl_blk *last_pending; /* 44 */ - struct scsi_ctrl_blk *first_busy; /* 48 */ - struct scsi_ctrl_blk *last_busy; /* 4C */ - struct scsi_ctrl_blk *first_done; /* 50 */ - struct scsi_ctrl_blk *last_done; /* 54 */ - u8 max_tags[16]; /* 58 */ - u8 act_tags[16]; /* 68 */ - struct target_control targets[MAX_TARGETS]; /* 78 */ - spinlock_t avail_lock; - spinlock_t semaph_lock; - struct pci_dev *pci_dev; -}; - -/* Bit Definition for HCB_Config */ -#define HCC_SCSI_RESET 0x01 -#define HCC_EN_PAR 0x02 -#define HCC_ACT_TERM1 0x04 -#define HCC_ACT_TERM2 0x08 -#define HCC_AUTO_TERM 0x10 -#define HCC_EN_PWR 0x80 - -/* Bit Definition for HCB_Flags */ -#define HCF_EXPECT_DISC 0x01 -#define HCF_EXPECT_SELECT 0x02 -#define HCF_EXPECT_RESET 0x10 -#define HCF_EXPECT_DONE_DISC 0x20 - -/****************************************************************** - Serial EEProm -*******************************************************************/ - -typedef struct _NVRAM_SCSI { /* SCSI channel configuration */ - u8 NVM_ChSCSIID; /* 0Ch -> Channel SCSI ID */ - u8 NVM_ChConfig1; /* 0Dh -> Channel config 1 */ - u8 NVM_ChConfig2; /* 0Eh -> Channel config 2 */ - u8 NVM_NumOfTarg; /* 0Fh -> Number of SCSI target */ - /* SCSI target configuration */ - u8 NVM_Targ0Config; /* 10h -> Target 0 configuration */ - u8 NVM_Targ1Config; /* 11h -> Target 1 configuration */ - u8 NVM_Targ2Config; /* 12h -> Target 2 configuration */ - u8 NVM_Targ3Config; /* 13h -> Target 3 configuration */ - u8 NVM_Targ4Config; /* 14h -> Target 4 configuration */ - u8 NVM_Targ5Config; /* 15h -> Target 5 configuration */ - u8 NVM_Targ6Config; /* 16h -> Target 6 configuration */ - u8 NVM_Targ7Config; /* 17h -> Target 7 configuration */ - u8 NVM_Targ8Config; /* 18h -> Target 8 configuration */ - u8 NVM_Targ9Config; /* 19h -> Target 9 configuration */ - u8 NVM_TargAConfig; /* 1Ah -> Target A configuration */ - u8 NVM_TargBConfig; /* 1Bh -> Target B configuration */ - u8 NVM_TargCConfig; /* 1Ch -> Target C configuration */ - u8 NVM_TargDConfig; /* 1Dh -> Target D configuration */ - u8 NVM_TargEConfig; /* 1Eh -> Target E configuration */ - u8 NVM_TargFConfig; /* 1Fh -> Target F configuration */ -} NVRAM_SCSI; - -typedef struct _NVRAM { -/*----------header ---------------*/ - u16 NVM_Signature; /* 0,1: Signature */ - u8 NVM_Size; /* 2: Size of data structure */ - u8 NVM_Revision; /* 3: Revision of data structure */ - /* ----Host Adapter Structure ---- */ - u8 NVM_ModelByte0; /* 4: Model number (byte 0) */ - u8 NVM_ModelByte1; /* 5: Model number (byte 1) */ - u8 NVM_ModelInfo; /* 6: Model information */ - u8 NVM_NumOfCh; /* 7: Number of SCSI channel */ - u8 NVM_BIOSConfig1; /* 8: BIOS configuration 1 */ - u8 NVM_BIOSConfig2; /* 9: BIOS configuration 2 */ - u8 NVM_HAConfig1; /* A: Hoat adapter configuration 1 */ - u8 NVM_HAConfig2; /* B: Hoat adapter configuration 2 */ - NVRAM_SCSI NVM_SCSIInfo[2]; - u8 NVM_reserved[10]; - /* ---------- CheckSum ---------- */ - u16 NVM_CheckSum; /* 0x3E, 0x3F: Checksum of NVRam */ -} NVRAM, *PNVRAM; - -/* Bios Configuration for nvram->BIOSConfig1 */ -#define NBC1_ENABLE 0x01 /* BIOS enable */ -#define NBC1_8DRIVE 0x02 /* Support more than 2 drives */ -#define NBC1_REMOVABLE 0x04 /* Support removable drive */ -#define NBC1_INT19 0x08 /* Intercept int 19h */ -#define NBC1_BIOSSCAN 0x10 /* Dynamic BIOS scan */ -#define NBC1_LUNSUPPORT 0x40 /* Support LUN */ - -/* HA Configuration Byte 1 */ -#define NHC1_BOOTIDMASK 0x0F /* Boot ID number */ -#define NHC1_LUNMASK 0x70 /* Boot LUN number */ -#define NHC1_CHANMASK 0x80 /* Boot Channel number */ - -/* Bit definition for nvram->SCSIconfig1 */ -#define NCC1_BUSRESET 0x01 /* Reset SCSI bus at power up */ -#define NCC1_PARITYCHK 0x02 /* SCSI parity enable */ -#define NCC1_ACTTERM1 0x04 /* Enable active terminator 1 */ -#define NCC1_ACTTERM2 0x08 /* Enable active terminator 2 */ -#define NCC1_AUTOTERM 0x10 /* Enable auto terminator */ -#define NCC1_PWRMGR 0x80 /* Enable power management */ - -/* Bit definition for SCSI Target configuration byte */ -#define NTC_DISCONNECT 0x08 /* Enable SCSI disconnect */ -#define NTC_SYNC 0x10 /* SYNC_NEGO */ -#define NTC_NO_WDTR 0x20 /* SYNC_NEGO */ -#define NTC_1GIGA 0x40 /* 255 head / 63 sectors (64/32) */ -#define NTC_SPINUP 0x80 /* Start disk drive */ - -/* Default NVRam values */ -#define INI_SIGNATURE 0xC925 -#define NBC1_DEFAULT (NBC1_ENABLE) -#define NCC1_DEFAULT (NCC1_BUSRESET | NCC1_AUTOTERM | NCC1_PARITYCHK) -#define NTC_DEFAULT (NTC_NO_WDTR | NTC_1GIGA | NTC_DISCONNECT) - -/* SCSI related definition */ -#define DISC_NOT_ALLOW 0x80 /* Disconnect is not allowed */ -#define DISC_ALLOW 0xC0 /* Disconnect is allowed */ -#define SCSICMD_RequestSense 0x03 - -#define SCSI_ABORT_SNOOZE 0 -#define SCSI_ABORT_SUCCESS 1 -#define SCSI_ABORT_PENDING 2 -#define SCSI_ABORT_BUSY 3 -#define SCSI_ABORT_NOT_RUNNING 4 -#define SCSI_ABORT_ERROR 5 - -#define SCSI_RESET_SNOOZE 0 -#define SCSI_RESET_PUNT 1 -#define SCSI_RESET_SUCCESS 2 -#define SCSI_RESET_PENDING 3 -#define SCSI_RESET_WAKEUP 4 -#define SCSI_RESET_NOT_RUNNING 5 -#define SCSI_RESET_ERROR 6 - -#define SCSI_RESET_SYNCHRONOUS 0x01 -#define SCSI_RESET_ASYNCHRONOUS 0x02 -#define SCSI_RESET_SUGGEST_BUS_RESET 0x04 -#define SCSI_RESET_SUGGEST_HOST_RESET 0x08 - -#define SCSI_RESET_BUS_RESET 0x100 -#define SCSI_RESET_HOST_RESET 0x200 -#define SCSI_RESET_ACTION 0xff - diff --git a/ANDROID_3.4.5/drivers/scsi/ipr.c b/ANDROID_3.4.5/drivers/scsi/ipr.c deleted file mode 100644 index 467dc382..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ipr.c +++ /dev/null @@ -1,9330 +0,0 @@ -/* - * ipr.c -- driver for IBM Power Linux RAID adapters - * - * Written By: Brian King , IBM Corporation - * - * Copyright (C) 2003, 2004 IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -/* - * Notes: - * - * This driver is used to control the following SCSI adapters: - * - * IBM iSeries: 5702, 5703, 2780, 5709, 570A, 570B - * - * IBM pSeries: PCI-X Dual Channel Ultra 320 SCSI RAID Adapter - * PCI-X Dual Channel Ultra 320 SCSI Adapter - * PCI-X Dual Channel Ultra 320 SCSI RAID Enablement Card - * Embedded SCSI adapter on p615 and p655 systems - * - * Supported Hardware Features: - * - Ultra 320 SCSI controller - * - PCI-X host interface - * - Embedded PowerPC RISC Processor and Hardware XOR DMA Engine - * - Non-Volatile Write Cache - * - Supports attachment of non-RAID disks, tape, and optical devices - * - RAID Levels 0, 5, 10 - * - Hot spare - * - Background Parity Checking - * - Background Data Scrubbing - * - Ability to increase the capacity of an existing RAID 5 disk array - * by adding disks - * - * Driver Features: - * - Tagged command queuing - * - Adapter microcode download - * - PCI hot plug - * - SCSI device hot plug - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ipr.h" - -/* - * Global Data - */ -static LIST_HEAD(ipr_ioa_head); -static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL; -static unsigned int ipr_max_speed = 1; -static int ipr_testmode = 0; -static unsigned int ipr_fastfail = 0; -static unsigned int ipr_transop_timeout = 0; -static unsigned int ipr_debug = 0; -static unsigned int ipr_max_devs = IPR_DEFAULT_SIS64_DEVS; -static unsigned int ipr_dual_ioa_raid = 1; -static DEFINE_SPINLOCK(ipr_driver_lock); - -/* This table describes the differences between DMA controller chips */ -static const struct ipr_chip_cfg_t ipr_chip_cfg[] = { - { /* Gemstone, Citrine, Obsidian, and Obsidian-E */ - .mailbox = 0x0042C, - .max_cmds = 100, - .cache_line_size = 0x20, - .clear_isr = 1, - { - .set_interrupt_mask_reg = 0x0022C, - .clr_interrupt_mask_reg = 0x00230, - .clr_interrupt_mask_reg32 = 0x00230, - .sense_interrupt_mask_reg = 0x0022C, - .sense_interrupt_mask_reg32 = 0x0022C, - .clr_interrupt_reg = 0x00228, - .clr_interrupt_reg32 = 0x00228, - .sense_interrupt_reg = 0x00224, - .sense_interrupt_reg32 = 0x00224, - .ioarrin_reg = 0x00404, - .sense_uproc_interrupt_reg = 0x00214, - .sense_uproc_interrupt_reg32 = 0x00214, - .set_uproc_interrupt_reg = 0x00214, - .set_uproc_interrupt_reg32 = 0x00214, - .clr_uproc_interrupt_reg = 0x00218, - .clr_uproc_interrupt_reg32 = 0x00218 - } - }, - { /* Snipe and Scamp */ - .mailbox = 0x0052C, - .max_cmds = 100, - .cache_line_size = 0x20, - .clear_isr = 1, - { - .set_interrupt_mask_reg = 0x00288, - .clr_interrupt_mask_reg = 0x0028C, - .clr_interrupt_mask_reg32 = 0x0028C, - .sense_interrupt_mask_reg = 0x00288, - .sense_interrupt_mask_reg32 = 0x00288, - .clr_interrupt_reg = 0x00284, - .clr_interrupt_reg32 = 0x00284, - .sense_interrupt_reg = 0x00280, - .sense_interrupt_reg32 = 0x00280, - .ioarrin_reg = 0x00504, - .sense_uproc_interrupt_reg = 0x00290, - .sense_uproc_interrupt_reg32 = 0x00290, - .set_uproc_interrupt_reg = 0x00290, - .set_uproc_interrupt_reg32 = 0x00290, - .clr_uproc_interrupt_reg = 0x00294, - .clr_uproc_interrupt_reg32 = 0x00294 - } - }, - { /* CRoC */ - .mailbox = 0x00044, - .max_cmds = 1000, - .cache_line_size = 0x20, - .clear_isr = 0, - { - .set_interrupt_mask_reg = 0x00010, - .clr_interrupt_mask_reg = 0x00018, - .clr_interrupt_mask_reg32 = 0x0001C, - .sense_interrupt_mask_reg = 0x00010, - .sense_interrupt_mask_reg32 = 0x00014, - .clr_interrupt_reg = 0x00008, - .clr_interrupt_reg32 = 0x0000C, - .sense_interrupt_reg = 0x00000, - .sense_interrupt_reg32 = 0x00004, - .ioarrin_reg = 0x00070, - .sense_uproc_interrupt_reg = 0x00020, - .sense_uproc_interrupt_reg32 = 0x00024, - .set_uproc_interrupt_reg = 0x00020, - .set_uproc_interrupt_reg32 = 0x00024, - .clr_uproc_interrupt_reg = 0x00028, - .clr_uproc_interrupt_reg32 = 0x0002C, - .init_feedback_reg = 0x0005C, - .dump_addr_reg = 0x00064, - .dump_data_reg = 0x00068, - .endian_swap_reg = 0x00084 - } - }, -}; - -static const struct ipr_chip_t ipr_chip[] = { - { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] } -}; - -static int ipr_max_bus_speeds [] = { - IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE -}; - -MODULE_AUTHOR("Brian King "); -MODULE_DESCRIPTION("IBM Power RAID SCSI Adapter Driver"); -module_param_named(max_speed, ipr_max_speed, uint, 0); -MODULE_PARM_DESC(max_speed, "Maximum bus speed (0-2). Default: 1=U160. Speeds: 0=80 MB/s, 1=U160, 2=U320"); -module_param_named(log_level, ipr_log_level, uint, 0); -MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver"); -module_param_named(testmode, ipr_testmode, int, 0); -MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations"); -module_param_named(fastfail, ipr_fastfail, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries"); -module_param_named(transop_timeout, ipr_transop_timeout, int, 0); -MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)"); -module_param_named(debug, ipr_debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)"); -module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0); -MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)"); -module_param_named(max_devs, ipr_max_devs, int, 0); -MODULE_PARM_DESC(max_devs, "Specify the maximum number of physical devices. " - "[Default=" __stringify(IPR_DEFAULT_SIS64_DEVS) "]"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(IPR_DRIVER_VERSION); - -/* A constant array of IOASCs/URCs/Error Messages */ -static const -struct ipr_error_table_t ipr_error_table[] = { - {0x00000000, 1, IPR_DEFAULT_LOG_LEVEL, - "8155: An unknown error was received"}, - {0x00330000, 0, 0, - "Soft underlength error"}, - {0x005A0000, 0, 0, - "Command to be cancelled not found"}, - {0x00808000, 0, 0, - "Qualified success"}, - {0x01080000, 1, IPR_DEFAULT_LOG_LEVEL, - "FFFE: Soft device bus error recovered by the IOA"}, - {0x01088100, 0, IPR_DEFAULT_LOG_LEVEL, - "4101: Soft device bus fabric error"}, - {0x01100100, 0, IPR_DEFAULT_LOG_LEVEL, - "FFFC: Logical block guard error recovered by the device"}, - {0x01100300, 0, IPR_DEFAULT_LOG_LEVEL, - "FFFC: Logical block reference tag error recovered by the device"}, - {0x01108300, 0, IPR_DEFAULT_LOG_LEVEL, - "4171: Recovered scatter list tag / sequence number error"}, - {0x01109000, 0, IPR_DEFAULT_LOG_LEVEL, - "FF3D: Recovered logical block CRC error on IOA to Host transfer"}, - {0x01109200, 0, IPR_DEFAULT_LOG_LEVEL, - "4171: Recovered logical block sequence number error on IOA to Host transfer"}, - {0x0110A000, 0, IPR_DEFAULT_LOG_LEVEL, - "FFFD: Recovered logical block reference tag error detected by the IOA"}, - {0x0110A100, 0, IPR_DEFAULT_LOG_LEVEL, - "FFFD: Logical block guard error recovered by the IOA"}, - {0x01170600, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF9: Device sector reassign successful"}, - {0x01170900, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF7: Media error recovered by device rewrite procedures"}, - {0x01180200, 0, IPR_DEFAULT_LOG_LEVEL, - "7001: IOA sector reassignment successful"}, - {0x01180500, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF9: Soft media error. Sector reassignment recommended"}, - {0x01180600, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF7: Media error recovered by IOA rewrite procedures"}, - {0x01418000, 0, IPR_DEFAULT_LOG_LEVEL, - "FF3D: Soft PCI bus error recovered by the IOA"}, - {0x01440000, 1, IPR_DEFAULT_LOG_LEVEL, - "FFF6: Device hardware error recovered by the IOA"}, - {0x01448100, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF6: Device hardware error recovered by the device"}, - {0x01448200, 1, IPR_DEFAULT_LOG_LEVEL, - "FF3D: Soft IOA error recovered by the IOA"}, - {0x01448300, 0, IPR_DEFAULT_LOG_LEVEL, - "FFFA: Undefined device response recovered by the IOA"}, - {0x014A0000, 1, IPR_DEFAULT_LOG_LEVEL, - "FFF6: Device bus error, message or command phase"}, - {0x014A8000, 0, IPR_DEFAULT_LOG_LEVEL, - "FFFE: Task Management Function failed"}, - {0x015D0000, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF6: Failure prediction threshold exceeded"}, - {0x015D9200, 0, IPR_DEFAULT_LOG_LEVEL, - "8009: Impending cache battery pack failure"}, - {0x02040400, 0, 0, - "34FF: Disk device format in progress"}, - {0x02048000, 0, IPR_DEFAULT_LOG_LEVEL, - "9070: IOA requested reset"}, - {0x023F0000, 0, 0, - "Synchronization required"}, - {0x024E0000, 0, 0, - "No ready, IOA shutdown"}, - {0x025A0000, 0, 0, - "Not ready, IOA has been shutdown"}, - {0x02670100, 0, IPR_DEFAULT_LOG_LEVEL, - "3020: Storage subsystem configuration error"}, - {0x03110B00, 0, 0, - "FFF5: Medium error, data unreadable, recommend reassign"}, - {0x03110C00, 0, 0, - "7000: Medium error, data unreadable, do not reassign"}, - {0x03310000, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF3: Disk media format bad"}, - {0x04050000, 0, IPR_DEFAULT_LOG_LEVEL, - "3002: Addressed device failed to respond to selection"}, - {0x04080000, 1, IPR_DEFAULT_LOG_LEVEL, - "3100: Device bus error"}, - {0x04080100, 0, IPR_DEFAULT_LOG_LEVEL, - "3109: IOA timed out a device command"}, - {0x04088000, 0, 0, - "3120: SCSI bus is not operational"}, - {0x04088100, 0, IPR_DEFAULT_LOG_LEVEL, - "4100: Hard device bus fabric error"}, - {0x04100100, 0, IPR_DEFAULT_LOG_LEVEL, - "310C: Logical block guard error detected by the device"}, - {0x04100300, 0, IPR_DEFAULT_LOG_LEVEL, - "310C: Logical block reference tag error detected by the device"}, - {0x04108300, 1, IPR_DEFAULT_LOG_LEVEL, - "4170: Scatter list tag / sequence number error"}, - {0x04109000, 1, IPR_DEFAULT_LOG_LEVEL, - "8150: Logical block CRC error on IOA to Host transfer"}, - {0x04109200, 1, IPR_DEFAULT_LOG_LEVEL, - "4170: Logical block sequence number error on IOA to Host transfer"}, - {0x0410A000, 0, IPR_DEFAULT_LOG_LEVEL, - "310D: Logical block reference tag error detected by the IOA"}, - {0x0410A100, 0, IPR_DEFAULT_LOG_LEVEL, - "310D: Logical block guard error detected by the IOA"}, - {0x04118000, 0, IPR_DEFAULT_LOG_LEVEL, - "9000: IOA reserved area data check"}, - {0x04118100, 0, IPR_DEFAULT_LOG_LEVEL, - "9001: IOA reserved area invalid data pattern"}, - {0x04118200, 0, IPR_DEFAULT_LOG_LEVEL, - "9002: IOA reserved area LRC error"}, - {0x04118300, 1, IPR_DEFAULT_LOG_LEVEL, - "Hardware Error, IOA metadata access error"}, - {0x04320000, 0, IPR_DEFAULT_LOG_LEVEL, - "102E: Out of alternate sectors for disk storage"}, - {0x04330000, 1, IPR_DEFAULT_LOG_LEVEL, - "FFF4: Data transfer underlength error"}, - {0x04338000, 1, IPR_DEFAULT_LOG_LEVEL, - "FFF4: Data transfer overlength error"}, - {0x043E0100, 0, IPR_DEFAULT_LOG_LEVEL, - "3400: Logical unit failure"}, - {0x04408500, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF4: Device microcode is corrupt"}, - {0x04418000, 1, IPR_DEFAULT_LOG_LEVEL, - "8150: PCI bus error"}, - {0x04430000, 1, 0, - "Unsupported device bus message received"}, - {0x04440000, 1, IPR_DEFAULT_LOG_LEVEL, - "FFF4: Disk device problem"}, - {0x04448200, 1, IPR_DEFAULT_LOG_LEVEL, - "8150: Permanent IOA failure"}, - {0x04448300, 0, IPR_DEFAULT_LOG_LEVEL, - "3010: Disk device returned wrong response to IOA"}, - {0x04448400, 0, IPR_DEFAULT_LOG_LEVEL, - "8151: IOA microcode error"}, - {0x04448500, 0, 0, - "Device bus status error"}, - {0x04448600, 0, IPR_DEFAULT_LOG_LEVEL, - "8157: IOA error requiring IOA reset to recover"}, - {0x04448700, 0, 0, - "ATA device status error"}, - {0x04490000, 0, 0, - "Message reject received from the device"}, - {0x04449200, 0, IPR_DEFAULT_LOG_LEVEL, - "8008: A permanent cache battery pack failure occurred"}, - {0x0444A000, 0, IPR_DEFAULT_LOG_LEVEL, - "9090: Disk unit has been modified after the last known status"}, - {0x0444A200, 0, IPR_DEFAULT_LOG_LEVEL, - "9081: IOA detected device error"}, - {0x0444A300, 0, IPR_DEFAULT_LOG_LEVEL, - "9082: IOA detected device error"}, - {0x044A0000, 1, IPR_DEFAULT_LOG_LEVEL, - "3110: Device bus error, message or command phase"}, - {0x044A8000, 1, IPR_DEFAULT_LOG_LEVEL, - "3110: SAS Command / Task Management Function failed"}, - {0x04670400, 0, IPR_DEFAULT_LOG_LEVEL, - "9091: Incorrect hardware configuration change has been detected"}, - {0x04678000, 0, IPR_DEFAULT_LOG_LEVEL, - "9073: Invalid multi-adapter configuration"}, - {0x04678100, 0, IPR_DEFAULT_LOG_LEVEL, - "4010: Incorrect connection between cascaded expanders"}, - {0x04678200, 0, IPR_DEFAULT_LOG_LEVEL, - "4020: Connections exceed IOA design limits"}, - {0x04678300, 0, IPR_DEFAULT_LOG_LEVEL, - "4030: Incorrect multipath connection"}, - {0x04679000, 0, IPR_DEFAULT_LOG_LEVEL, - "4110: Unsupported enclosure function"}, - {0x046E0000, 0, IPR_DEFAULT_LOG_LEVEL, - "FFF4: Command to logical unit failed"}, - {0x05240000, 1, 0, - "Illegal request, invalid request type or request packet"}, - {0x05250000, 0, 0, - "Illegal request, invalid resource handle"}, - {0x05258000, 0, 0, - "Illegal request, commands not allowed to this device"}, - {0x05258100, 0, 0, - "Illegal request, command not allowed to a secondary adapter"}, - {0x05258200, 0, 0, - "Illegal request, command not allowed to a non-optimized resource"}, - {0x05260000, 0, 0, - "Illegal request, invalid field in parameter list"}, - {0x05260100, 0, 0, - "Illegal request, parameter not supported"}, - {0x05260200, 0, 0, - "Illegal request, parameter value invalid"}, - {0x052C0000, 0, 0, - "Illegal request, command sequence error"}, - {0x052C8000, 1, 0, - "Illegal request, dual adapter support not enabled"}, - {0x06040500, 0, IPR_DEFAULT_LOG_LEVEL, - "9031: Array protection temporarily suspended, protection resuming"}, - {0x06040600, 0, IPR_DEFAULT_LOG_LEVEL, - "9040: Array protection temporarily suspended, protection resuming"}, - {0x06288000, 0, IPR_DEFAULT_LOG_LEVEL, - "3140: Device bus not ready to ready transition"}, - {0x06290000, 0, IPR_DEFAULT_LOG_LEVEL, - "FFFB: SCSI bus was reset"}, - {0x06290500, 0, 0, - "FFFE: SCSI bus transition to single ended"}, - {0x06290600, 0, 0, - "FFFE: SCSI bus transition to LVD"}, - {0x06298000, 0, IPR_DEFAULT_LOG_LEVEL, - "FFFB: SCSI bus was reset by another initiator"}, - {0x063F0300, 0, IPR_DEFAULT_LOG_LEVEL, - "3029: A device replacement has occurred"}, - {0x064C8000, 0, IPR_DEFAULT_LOG_LEVEL, - "9051: IOA cache data exists for a missing or failed device"}, - {0x064C8100, 0, IPR_DEFAULT_LOG_LEVEL, - "9055: Auxiliary cache IOA contains cache data needed by the primary IOA"}, - {0x06670100, 0, IPR_DEFAULT_LOG_LEVEL, - "9025: Disk unit is not supported at its physical location"}, - {0x06670600, 0, IPR_DEFAULT_LOG_LEVEL, - "3020: IOA detected a SCSI bus configuration error"}, - {0x06678000, 0, IPR_DEFAULT_LOG_LEVEL, - "3150: SCSI bus configuration error"}, - {0x06678100, 0, IPR_DEFAULT_LOG_LEVEL, - "9074: Asymmetric advanced function disk configuration"}, - {0x06678300, 0, IPR_DEFAULT_LOG_LEVEL, - "4040: Incomplete multipath connection between IOA and enclosure"}, - {0x06678400, 0, IPR_DEFAULT_LOG_LEVEL, - "4041: Incomplete multipath connection between enclosure and device"}, - {0x06678500, 0, IPR_DEFAULT_LOG_LEVEL, - "9075: Incomplete multipath connection between IOA and remote IOA"}, - {0x06678600, 0, IPR_DEFAULT_LOG_LEVEL, - "9076: Configuration error, missing remote IOA"}, - {0x06679100, 0, IPR_DEFAULT_LOG_LEVEL, - "4050: Enclosure does not support a required multipath function"}, - {0x06690000, 0, IPR_DEFAULT_LOG_LEVEL, - "4070: Logically bad block written on device"}, - {0x06690200, 0, IPR_DEFAULT_LOG_LEVEL, - "9041: Array protection temporarily suspended"}, - {0x06698200, 0, IPR_DEFAULT_LOG_LEVEL, - "9042: Corrupt array parity detected on specified device"}, - {0x066B0200, 0, IPR_DEFAULT_LOG_LEVEL, - "9030: Array no longer protected due to missing or failed disk unit"}, - {0x066B8000, 0, IPR_DEFAULT_LOG_LEVEL, - "9071: Link operational transition"}, - {0x066B8100, 0, IPR_DEFAULT_LOG_LEVEL, - "9072: Link not operational transition"}, - {0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL, - "9032: Array exposed but still protected"}, - {0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1, - "70DD: Device forced failed by disrupt device command"}, - {0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL, - "4061: Multipath redundancy level got better"}, - {0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL, - "4060: Multipath redundancy level got worse"}, - {0x07270000, 0, 0, - "Failure due to other device"}, - {0x07278000, 0, IPR_DEFAULT_LOG_LEVEL, - "9008: IOA does not support functions expected by devices"}, - {0x07278100, 0, IPR_DEFAULT_LOG_LEVEL, - "9010: Cache data associated with attached devices cannot be found"}, - {0x07278200, 0, IPR_DEFAULT_LOG_LEVEL, - "9011: Cache data belongs to devices other than those attached"}, - {0x07278400, 0, IPR_DEFAULT_LOG_LEVEL, - "9020: Array missing 2 or more devices with only 1 device present"}, - {0x07278500, 0, IPR_DEFAULT_LOG_LEVEL, - "9021: Array missing 2 or more devices with 2 or more devices present"}, - {0x07278600, 0, IPR_DEFAULT_LOG_LEVEL, - "9022: Exposed array is missing a required device"}, - {0x07278700, 0, IPR_DEFAULT_LOG_LEVEL, - "9023: Array member(s) not at required physical locations"}, - {0x07278800, 0, IPR_DEFAULT_LOG_LEVEL, - "9024: Array not functional due to present hardware configuration"}, - {0x07278900, 0, IPR_DEFAULT_LOG_LEVEL, - "9026: Array not functional due to present hardware configuration"}, - {0x07278A00, 0, IPR_DEFAULT_LOG_LEVEL, - "9027: Array is missing a device and parity is out of sync"}, - {0x07278B00, 0, IPR_DEFAULT_LOG_LEVEL, - "9028: Maximum number of arrays already exist"}, - {0x07278C00, 0, IPR_DEFAULT_LOG_LEVEL, - "9050: Required cache data cannot be located for a disk unit"}, - {0x07278D00, 0, IPR_DEFAULT_LOG_LEVEL, - "9052: Cache data exists for a device that has been modified"}, - {0x07278F00, 0, IPR_DEFAULT_LOG_LEVEL, - "9054: IOA resources not available due to previous problems"}, - {0x07279100, 0, IPR_DEFAULT_LOG_LEVEL, - "9092: Disk unit requires initialization before use"}, - {0x07279200, 0, IPR_DEFAULT_LOG_LEVEL, - "9029: Incorrect hardware configuration change has been detected"}, - {0x07279600, 0, IPR_DEFAULT_LOG_LEVEL, - "9060: One or more disk pairs are missing from an array"}, - {0x07279700, 0, IPR_DEFAULT_LOG_LEVEL, - "9061: One or more disks are missing from an array"}, - {0x07279800, 0, IPR_DEFAULT_LOG_LEVEL, - "9062: One or more disks are missing from an array"}, - {0x07279900, 0, IPR_DEFAULT_LOG_LEVEL, - "9063: Maximum number of functional arrays has been exceeded"}, - {0x0B260000, 0, 0, - "Aborted command, invalid descriptor"}, - {0x0B5A0000, 0, 0, - "Command terminated by host"} -}; - -static const struct ipr_ses_table_entry ipr_ses_table[] = { - { "2104-DL1 ", "XXXXXXXXXXXXXXXX", 80 }, - { "2104-TL1 ", "XXXXXXXXXXXXXXXX", 80 }, - { "HSBP07M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 7 slot */ - { "HSBP05M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 5 slot */ - { "HSBP05M S U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Bowtie */ - { "HSBP06E ASU2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* MartinFenning */ - { "2104-DU3 ", "XXXXXXXXXXXXXXXX", 160 }, - { "2104-TU3 ", "XXXXXXXXXXXXXXXX", 160 }, - { "HSBP04C RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 }, - { "HSBP06E RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 }, - { "St V1S2 ", "XXXXXXXXXXXXXXXX", 160 }, - { "HSBPD4M PU3SCSI", "XXXXXXX*XXXXXXXX", 160 }, - { "VSBPD1H U3SCSI", "XXXXXXX*XXXXXXXX", 160 } -}; - -/* - * Function Prototypes - */ -static int ipr_reset_alert(struct ipr_cmnd *); -static void ipr_process_ccn(struct ipr_cmnd *); -static void ipr_process_error(struct ipr_cmnd *); -static void ipr_reset_ioa_job(struct ipr_cmnd *); -static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *, - enum ipr_shutdown_type); - -#ifdef CONFIG_SCSI_IPR_TRACE -/** - * ipr_trc_hook - Add a trace entry to the driver trace - * @ipr_cmd: ipr command struct - * @type: trace type - * @add_data: additional data - * - * Return value: - * none - **/ -static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd, - u8 type, u32 add_data) -{ - struct ipr_trace_entry *trace_entry; - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - trace_entry = &ioa_cfg->trace[ioa_cfg->trace_index++]; - trace_entry->time = jiffies; - trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0]; - trace_entry->type = type; - if (ipr_cmd->ioa_cfg->sis64) - trace_entry->ata_op_code = ipr_cmd->i.ata_ioadl.regs.command; - else - trace_entry->ata_op_code = ipr_cmd->ioarcb.u.add_data.u.regs.command; - trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff; - trace_entry->res_handle = ipr_cmd->ioarcb.res_handle; - trace_entry->u.add_data = add_data; -} -#else -#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0) -#endif - -/** - * ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse - * @ipr_cmd: ipr command struct - * - * Return value: - * none - **/ -static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa; - struct ipr_ioasa64 *ioasa64 = &ipr_cmd->s.ioasa64; - dma_addr_t dma_addr = ipr_cmd->dma_addr; - - memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); - ioarcb->data_transfer_length = 0; - ioarcb->read_data_transfer_length = 0; - ioarcb->ioadl_len = 0; - ioarcb->read_ioadl_len = 0; - - if (ipr_cmd->ioa_cfg->sis64) { - ioarcb->u.sis64_addr_data.data_ioadl_addr = - cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64)); - ioasa64->u.gata.status = 0; - } else { - ioarcb->write_ioadl_addr = - cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl)); - ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; - ioasa->u.gata.status = 0; - } - - ioasa->hdr.ioasc = 0; - ioasa->hdr.residual_data_len = 0; - ipr_cmd->scsi_cmd = NULL; - ipr_cmd->qc = NULL; - ipr_cmd->sense_buffer[0] = 0; - ipr_cmd->dma_use_sg = 0; -} - -/** - * ipr_init_ipr_cmnd - Initialize an IPR Cmnd block - * @ipr_cmd: ipr command struct - * - * Return value: - * none - **/ -static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd) -{ - ipr_reinit_ipr_cmnd(ipr_cmd); - ipr_cmd->u.scratch = 0; - ipr_cmd->sibling = NULL; - init_timer(&ipr_cmd->timer); -} - -/** - * ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block - * @ioa_cfg: ioa config struct - * - * Return value: - * pointer to ipr command struct - **/ -static -struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg) -{ - struct ipr_cmnd *ipr_cmd; - - ipr_cmd = list_entry(ioa_cfg->free_q.next, struct ipr_cmnd, queue); - list_del(&ipr_cmd->queue); - ipr_init_ipr_cmnd(ipr_cmd); - - return ipr_cmd; -} - -/** - * ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts - * @ioa_cfg: ioa config struct - * @clr_ints: interrupts to clear - * - * This function masks all interrupts on the adapter, then clears the - * interrupts specified in the mask - * - * Return value: - * none - **/ -static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg, - u32 clr_ints) -{ - volatile u32 int_reg; - - /* Stop new interrupts */ - ioa_cfg->allow_interrupts = 0; - - /* Set interrupt mask to stop all new interrupts */ - if (ioa_cfg->sis64) - writeq(~0, ioa_cfg->regs.set_interrupt_mask_reg); - else - writel(~0, ioa_cfg->regs.set_interrupt_mask_reg); - - /* Clear any pending interrupts */ - if (ioa_cfg->sis64) - writel(~0, ioa_cfg->regs.clr_interrupt_reg); - writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); -} - -/** - * ipr_save_pcix_cmd_reg - Save PCI-X command register - * @ioa_cfg: ioa config struct - * - * Return value: - * 0 on success / -EIO on failure - **/ -static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) -{ - int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); - - if (pcix_cmd_reg == 0) - return 0; - - if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD, - &ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { - dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n"); - return -EIO; - } - - ioa_cfg->saved_pcix_cmd_reg |= PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO; - return 0; -} - -/** - * ipr_set_pcix_cmd_reg - Setup PCI-X command register - * @ioa_cfg: ioa config struct - * - * Return value: - * 0 on success / -EIO on failure - **/ -static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg) -{ - int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX); - - if (pcix_cmd_reg) { - if (pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD, - ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) { - dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n"); - return -EIO; - } - } - - return 0; -} - -/** - * ipr_sata_eh_done - done function for aborted SATA commands - * @ipr_cmd: ipr command struct - * - * This function is invoked for ops generated to SATA - * devices which are being aborted. - * - * Return value: - * none - **/ -static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ata_queued_cmd *qc = ipr_cmd->qc; - struct ipr_sata_port *sata_port = qc->ap->private_data; - - qc->err_mask |= AC_ERR_OTHER; - sata_port->ioasa.status |= ATA_BUSY; - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - ata_qc_complete(qc); -} - -/** - * ipr_scsi_eh_done - mid-layer done function for aborted ops - * @ipr_cmd: ipr command struct - * - * This function is invoked by the interrupt handler for - * ops generated by the SCSI mid-layer which are being aborted. - * - * Return value: - * none - **/ -static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; - - scsi_cmd->result |= (DID_ERROR << 16); - - scsi_dma_unmap(ipr_cmd->scsi_cmd); - scsi_cmd->scsi_done(scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); -} - -/** - * ipr_fail_all_ops - Fails all outstanding ops. - * @ioa_cfg: ioa config struct - * - * This function fails all outstanding ops. - * - * Return value: - * none - **/ -static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg) -{ - struct ipr_cmnd *ipr_cmd, *temp; - - ENTER; - list_for_each_entry_safe(ipr_cmd, temp, &ioa_cfg->pending_q, queue) { - list_del(&ipr_cmd->queue); - - ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET); - ipr_cmd->s.ioasa.hdr.ilid = cpu_to_be32(IPR_DRIVER_ILID); - - if (ipr_cmd->scsi_cmd) - ipr_cmd->done = ipr_scsi_eh_done; - else if (ipr_cmd->qc) - ipr_cmd->done = ipr_sata_eh_done; - - ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET); - del_timer(&ipr_cmd->timer); - ipr_cmd->done(ipr_cmd); - } - - LEAVE; -} - -/** - * ipr_send_command - Send driver initiated requests. - * @ipr_cmd: ipr command struct - * - * This function sends a command to the adapter using the correct write call. - * In the case of sis64, calculate the ioarcb size required. Then or in the - * appropriate bits. - * - * Return value: - * none - **/ -static void ipr_send_command(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - dma_addr_t send_dma_addr = ipr_cmd->dma_addr; - - if (ioa_cfg->sis64) { - /* The default size is 256 bytes */ - send_dma_addr |= 0x1; - - /* If the number of ioadls * size of ioadl > 128 bytes, - then use a 512 byte ioarcb */ - if (ipr_cmd->dma_use_sg * sizeof(struct ipr_ioadl64_desc) > 128 ) - send_dma_addr |= 0x4; - writeq(send_dma_addr, ioa_cfg->regs.ioarrin_reg); - } else - writel(send_dma_addr, ioa_cfg->regs.ioarrin_reg); -} - -/** - * ipr_do_req - Send driver initiated requests. - * @ipr_cmd: ipr command struct - * @done: done function - * @timeout_func: timeout function - * @timeout: timeout value - * - * This function sends the specified command to the adapter with the - * timeout given. The done function is invoked on command completion. - * - * Return value: - * none - **/ -static void ipr_do_req(struct ipr_cmnd *ipr_cmd, - void (*done) (struct ipr_cmnd *), - void (*timeout_func) (struct ipr_cmnd *), u32 timeout) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); - - ipr_cmd->done = done; - - ipr_cmd->timer.data = (unsigned long) ipr_cmd; - ipr_cmd->timer.expires = jiffies + timeout; - ipr_cmd->timer.function = (void (*)(unsigned long))timeout_func; - - add_timer(&ipr_cmd->timer); - - ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0); - - ipr_send_command(ipr_cmd); -} - -/** - * ipr_internal_cmd_done - Op done function for an internally generated op. - * @ipr_cmd: ipr command struct - * - * This function is the op done function for an internally generated, - * blocking op. It simply wakes the sleeping thread. - * - * Return value: - * none - **/ -static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd) -{ - if (ipr_cmd->sibling) - ipr_cmd->sibling = NULL; - else - complete(&ipr_cmd->completion); -} - -/** - * ipr_init_ioadl - initialize the ioadl for the correct SIS type - * @ipr_cmd: ipr command struct - * @dma_addr: dma address - * @len: transfer length - * @flags: ioadl flag value - * - * This function initializes an ioadl in the case where there is only a single - * descriptor. - * - * Return value: - * nothing - **/ -static void ipr_init_ioadl(struct ipr_cmnd *ipr_cmd, dma_addr_t dma_addr, - u32 len, int flags) -{ - struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl; - struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64; - - ipr_cmd->dma_use_sg = 1; - - if (ipr_cmd->ioa_cfg->sis64) { - ioadl64->flags = cpu_to_be32(flags); - ioadl64->data_len = cpu_to_be32(len); - ioadl64->address = cpu_to_be64(dma_addr); - - ipr_cmd->ioarcb.ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl64_desc)); - ipr_cmd->ioarcb.data_transfer_length = cpu_to_be32(len); - } else { - ioadl->flags_and_data_len = cpu_to_be32(flags | len); - ioadl->address = cpu_to_be32(dma_addr); - - if (flags == IPR_IOADL_FLAGS_READ_LAST) { - ipr_cmd->ioarcb.read_ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc)); - ipr_cmd->ioarcb.read_data_transfer_length = cpu_to_be32(len); - } else { - ipr_cmd->ioarcb.ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc)); - ipr_cmd->ioarcb.data_transfer_length = cpu_to_be32(len); - } - } -} - -/** - * ipr_send_blocking_cmd - Send command and sleep on its completion. - * @ipr_cmd: ipr command struct - * @timeout_func: function to invoke if command times out - * @timeout: timeout - * - * Return value: - * none - **/ -static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd, - void (*timeout_func) (struct ipr_cmnd *ipr_cmd), - u32 timeout) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - init_completion(&ipr_cmd->completion); - ipr_do_req(ipr_cmd, ipr_internal_cmd_done, timeout_func, timeout); - - spin_unlock_irq(ioa_cfg->host->host_lock); - wait_for_completion(&ipr_cmd->completion); - spin_lock_irq(ioa_cfg->host->host_lock); -} - -/** - * ipr_send_hcam - Send an HCAM to the adapter. - * @ioa_cfg: ioa config struct - * @type: HCAM type - * @hostrcb: hostrcb struct - * - * This function will send a Host Controlled Async command to the adapter. - * If HCAMs are currently not allowed to be issued to the adapter, it will - * place the hostrcb on the free queue. - * - * Return value: - * none - **/ -static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type, - struct ipr_hostrcb *hostrcb) -{ - struct ipr_cmnd *ipr_cmd; - struct ipr_ioarcb *ioarcb; - - if (ioa_cfg->allow_cmds) { - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); - list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_pending_q); - - ipr_cmd->u.hostrcb = hostrcb; - ioarcb = &ipr_cmd->ioarcb; - - ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_HCAM; - ioarcb->cmd_pkt.cdb[0] = IPR_HOST_CONTROLLED_ASYNC; - ioarcb->cmd_pkt.cdb[1] = type; - ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff; - ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff; - - ipr_init_ioadl(ipr_cmd, hostrcb->hostrcb_dma, - sizeof(hostrcb->hcam), IPR_IOADL_FLAGS_READ_LAST); - - if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE) - ipr_cmd->done = ipr_process_ccn; - else - ipr_cmd->done = ipr_process_error; - - ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR); - - ipr_send_command(ipr_cmd); - } else { - list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); - } -} - -/** - * ipr_update_ata_class - Update the ata class in the resource entry - * @res: resource entry struct - * @proto: cfgte device bus protocol value - * - * Return value: - * none - **/ -static void ipr_update_ata_class(struct ipr_resource_entry *res, unsigned int proto) -{ - switch(proto) { - case IPR_PROTO_SATA: - case IPR_PROTO_SAS_STP: - res->ata_class = ATA_DEV_ATA; - break; - case IPR_PROTO_SATA_ATAPI: - case IPR_PROTO_SAS_STP_ATAPI: - res->ata_class = ATA_DEV_ATAPI; - break; - default: - res->ata_class = ATA_DEV_UNKNOWN; - break; - }; -} - -/** - * ipr_init_res_entry - Initialize a resource entry struct. - * @res: resource entry struct - * @cfgtew: config table entry wrapper struct - * - * Return value: - * none - **/ -static void ipr_init_res_entry(struct ipr_resource_entry *res, - struct ipr_config_table_entry_wrapper *cfgtew) -{ - int found = 0; - unsigned int proto; - struct ipr_ioa_cfg *ioa_cfg = res->ioa_cfg; - struct ipr_resource_entry *gscsi_res = NULL; - - res->needs_sync_complete = 0; - res->in_erp = 0; - res->add_to_ml = 0; - res->del_from_ml = 0; - res->resetting_device = 0; - res->sdev = NULL; - res->sata_port = NULL; - - if (ioa_cfg->sis64) { - proto = cfgtew->u.cfgte64->proto; - res->res_flags = cfgtew->u.cfgte64->res_flags; - res->qmodel = IPR_QUEUEING_MODEL64(res); - res->type = cfgtew->u.cfgte64->res_type; - - memcpy(res->res_path, &cfgtew->u.cfgte64->res_path, - sizeof(res->res_path)); - - res->bus = 0; - memcpy(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun, - sizeof(res->dev_lun.scsi_lun)); - res->lun = scsilun_to_int(&res->dev_lun); - - if (res->type == IPR_RES_TYPE_GENERIC_SCSI) { - list_for_each_entry(gscsi_res, &ioa_cfg->used_res_q, queue) { - if (gscsi_res->dev_id == cfgtew->u.cfgte64->dev_id) { - found = 1; - res->target = gscsi_res->target; - break; - } - } - if (!found) { - res->target = find_first_zero_bit(ioa_cfg->target_ids, - ioa_cfg->max_devs_supported); - set_bit(res->target, ioa_cfg->target_ids); - } - } else if (res->type == IPR_RES_TYPE_IOAFP) { - res->bus = IPR_IOAFP_VIRTUAL_BUS; - res->target = 0; - } else if (res->type == IPR_RES_TYPE_ARRAY) { - res->bus = IPR_ARRAY_VIRTUAL_BUS; - res->target = find_first_zero_bit(ioa_cfg->array_ids, - ioa_cfg->max_devs_supported); - set_bit(res->target, ioa_cfg->array_ids); - } else if (res->type == IPR_RES_TYPE_VOLUME_SET) { - res->bus = IPR_VSET_VIRTUAL_BUS; - res->target = find_first_zero_bit(ioa_cfg->vset_ids, - ioa_cfg->max_devs_supported); - set_bit(res->target, ioa_cfg->vset_ids); - } else { - res->target = find_first_zero_bit(ioa_cfg->target_ids, - ioa_cfg->max_devs_supported); - set_bit(res->target, ioa_cfg->target_ids); - } - } else { - proto = cfgtew->u.cfgte->proto; - res->qmodel = IPR_QUEUEING_MODEL(res); - res->flags = cfgtew->u.cfgte->flags; - if (res->flags & IPR_IS_IOA_RESOURCE) - res->type = IPR_RES_TYPE_IOAFP; - else - res->type = cfgtew->u.cfgte->rsvd_subtype & 0x0f; - - res->bus = cfgtew->u.cfgte->res_addr.bus; - res->target = cfgtew->u.cfgte->res_addr.target; - res->lun = cfgtew->u.cfgte->res_addr.lun; - res->lun_wwn = get_unaligned_be64(cfgtew->u.cfgte->lun_wwn); - } - - ipr_update_ata_class(res, proto); -} - -/** - * ipr_is_same_device - Determine if two devices are the same. - * @res: resource entry struct - * @cfgtew: config table entry wrapper struct - * - * Return value: - * 1 if the devices are the same / 0 otherwise - **/ -static int ipr_is_same_device(struct ipr_resource_entry *res, - struct ipr_config_table_entry_wrapper *cfgtew) -{ - if (res->ioa_cfg->sis64) { - if (!memcmp(&res->dev_id, &cfgtew->u.cfgte64->dev_id, - sizeof(cfgtew->u.cfgte64->dev_id)) && - !memcmp(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun, - sizeof(cfgtew->u.cfgte64->lun))) { - return 1; - } - } else { - if (res->bus == cfgtew->u.cfgte->res_addr.bus && - res->target == cfgtew->u.cfgte->res_addr.target && - res->lun == cfgtew->u.cfgte->res_addr.lun) - return 1; - } - - return 0; -} - -/** - * ipr_format_res_path - Format the resource path for printing. - * @res_path: resource path - * @buf: buffer - * - * Return value: - * pointer to buffer - **/ -static char *ipr_format_res_path(u8 *res_path, char *buffer, int len) -{ - int i; - char *p = buffer; - - *p = '\0'; - p += snprintf(p, buffer + len - p, "%02X", res_path[0]); - for (i = 1; res_path[i] != 0xff && ((i * 3) < len); i++) - p += snprintf(p, buffer + len - p, "-%02X", res_path[i]); - - return buffer; -} - -/** - * ipr_update_res_entry - Update the resource entry. - * @res: resource entry struct - * @cfgtew: config table entry wrapper struct - * - * Return value: - * none - **/ -static void ipr_update_res_entry(struct ipr_resource_entry *res, - struct ipr_config_table_entry_wrapper *cfgtew) -{ - char buffer[IPR_MAX_RES_PATH_LENGTH]; - unsigned int proto; - int new_path = 0; - - if (res->ioa_cfg->sis64) { - res->flags = cfgtew->u.cfgte64->flags; - res->res_flags = cfgtew->u.cfgte64->res_flags; - res->type = cfgtew->u.cfgte64->res_type; - - memcpy(&res->std_inq_data, &cfgtew->u.cfgte64->std_inq_data, - sizeof(struct ipr_std_inq_data)); - - res->qmodel = IPR_QUEUEING_MODEL64(res); - proto = cfgtew->u.cfgte64->proto; - res->res_handle = cfgtew->u.cfgte64->res_handle; - res->dev_id = cfgtew->u.cfgte64->dev_id; - - memcpy(&res->dev_lun.scsi_lun, &cfgtew->u.cfgte64->lun, - sizeof(res->dev_lun.scsi_lun)); - - if (memcmp(res->res_path, &cfgtew->u.cfgte64->res_path, - sizeof(res->res_path))) { - memcpy(res->res_path, &cfgtew->u.cfgte64->res_path, - sizeof(res->res_path)); - new_path = 1; - } - - if (res->sdev && new_path) - sdev_printk(KERN_INFO, res->sdev, "Resource path: %s\n", - ipr_format_res_path(res->res_path, buffer, - sizeof(buffer))); - } else { - res->flags = cfgtew->u.cfgte->flags; - if (res->flags & IPR_IS_IOA_RESOURCE) - res->type = IPR_RES_TYPE_IOAFP; - else - res->type = cfgtew->u.cfgte->rsvd_subtype & 0x0f; - - memcpy(&res->std_inq_data, &cfgtew->u.cfgte->std_inq_data, - sizeof(struct ipr_std_inq_data)); - - res->qmodel = IPR_QUEUEING_MODEL(res); - proto = cfgtew->u.cfgte->proto; - res->res_handle = cfgtew->u.cfgte->res_handle; - } - - ipr_update_ata_class(res, proto); -} - -/** - * ipr_clear_res_target - Clear the bit in the bit map representing the target - * for the resource. - * @res: resource entry struct - * @cfgtew: config table entry wrapper struct - * - * Return value: - * none - **/ -static void ipr_clear_res_target(struct ipr_resource_entry *res) -{ - struct ipr_resource_entry *gscsi_res = NULL; - struct ipr_ioa_cfg *ioa_cfg = res->ioa_cfg; - - if (!ioa_cfg->sis64) - return; - - if (res->bus == IPR_ARRAY_VIRTUAL_BUS) - clear_bit(res->target, ioa_cfg->array_ids); - else if (res->bus == IPR_VSET_VIRTUAL_BUS) - clear_bit(res->target, ioa_cfg->vset_ids); - else if (res->bus == 0 && res->type == IPR_RES_TYPE_GENERIC_SCSI) { - list_for_each_entry(gscsi_res, &ioa_cfg->used_res_q, queue) - if (gscsi_res->dev_id == res->dev_id && gscsi_res != res) - return; - clear_bit(res->target, ioa_cfg->target_ids); - - } else if (res->bus == 0) - clear_bit(res->target, ioa_cfg->target_ids); -} - -/** - * ipr_handle_config_change - Handle a config change from the adapter - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb - * - * Return value: - * none - **/ -static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - struct ipr_resource_entry *res = NULL; - struct ipr_config_table_entry_wrapper cfgtew; - __be32 cc_res_handle; - - u32 is_ndn = 1; - - if (ioa_cfg->sis64) { - cfgtew.u.cfgte64 = &hostrcb->hcam.u.ccn.u.cfgte64; - cc_res_handle = cfgtew.u.cfgte64->res_handle; - } else { - cfgtew.u.cfgte = &hostrcb->hcam.u.ccn.u.cfgte; - cc_res_handle = cfgtew.u.cfgte->res_handle; - } - - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if (res->res_handle == cc_res_handle) { - is_ndn = 0; - break; - } - } - - if (is_ndn) { - if (list_empty(&ioa_cfg->free_res_q)) { - ipr_send_hcam(ioa_cfg, - IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, - hostrcb); - return; - } - - res = list_entry(ioa_cfg->free_res_q.next, - struct ipr_resource_entry, queue); - - list_del(&res->queue); - ipr_init_res_entry(res, &cfgtew); - list_add_tail(&res->queue, &ioa_cfg->used_res_q); - } - - ipr_update_res_entry(res, &cfgtew); - - if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) { - if (res->sdev) { - res->del_from_ml = 1; - res->res_handle = IPR_INVALID_RES_HANDLE; - if (ioa_cfg->allow_ml_add_del) - schedule_work(&ioa_cfg->work_q); - } else { - ipr_clear_res_target(res); - list_move_tail(&res->queue, &ioa_cfg->free_res_q); - } - } else if (!res->sdev || res->del_from_ml) { - res->add_to_ml = 1; - if (ioa_cfg->allow_ml_add_del) - schedule_work(&ioa_cfg->work_q); - } - - ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); -} - -/** - * ipr_process_ccn - Op done function for a CCN. - * @ipr_cmd: ipr command struct - * - * This function is the op done function for a configuration - * change notification host controlled async from the adapter. - * - * Return value: - * none - **/ -static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - list_del(&hostrcb->queue); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - - if (ioasc) { - if (ioasc != IPR_IOASC_IOA_WAS_RESET) - dev_err(&ioa_cfg->pdev->dev, - "Host RCB failed with IOASC: 0x%08X\n", ioasc); - - ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); - } else { - ipr_handle_config_change(ioa_cfg, hostrcb); - } -} - -/** - * strip_and_pad_whitespace - Strip and pad trailing whitespace. - * @i: index into buffer - * @buf: string to modify - * - * This function will strip all trailing whitespace, pad the end - * of the string with a single space, and NULL terminate the string. - * - * Return value: - * new length of string - **/ -static int strip_and_pad_whitespace(int i, char *buf) -{ - while (i && buf[i] == ' ') - i--; - buf[i+1] = ' '; - buf[i+2] = '\0'; - return i + 2; -} - -/** - * ipr_log_vpd_compact - Log the passed extended VPD compactly. - * @prefix: string to print at start of printk - * @hostrcb: hostrcb pointer - * @vpd: vendor/product id/sn struct - * - * Return value: - * none - **/ -static void ipr_log_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb, - struct ipr_vpd *vpd) -{ - char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN + IPR_SERIAL_NUM_LEN + 3]; - int i = 0; - - memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); - i = strip_and_pad_whitespace(IPR_VENDOR_ID_LEN - 1, buffer); - - memcpy(&buffer[i], vpd->vpids.product_id, IPR_PROD_ID_LEN); - i = strip_and_pad_whitespace(i + IPR_PROD_ID_LEN - 1, buffer); - - memcpy(&buffer[i], vpd->sn, IPR_SERIAL_NUM_LEN); - buffer[IPR_SERIAL_NUM_LEN + i] = '\0'; - - ipr_hcam_err(hostrcb, "%s VPID/SN: %s\n", prefix, buffer); -} - -/** - * ipr_log_vpd - Log the passed VPD to the error log. - * @vpd: vendor/product id/sn struct - * - * Return value: - * none - **/ -static void ipr_log_vpd(struct ipr_vpd *vpd) -{ - char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN - + IPR_SERIAL_NUM_LEN]; - - memcpy(buffer, vpd->vpids.vendor_id, IPR_VENDOR_ID_LEN); - memcpy(buffer + IPR_VENDOR_ID_LEN, vpd->vpids.product_id, - IPR_PROD_ID_LEN); - buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN] = '\0'; - ipr_err("Vendor/Product ID: %s\n", buffer); - - memcpy(buffer, vpd->sn, IPR_SERIAL_NUM_LEN); - buffer[IPR_SERIAL_NUM_LEN] = '\0'; - ipr_err(" Serial Number: %s\n", buffer); -} - -/** - * ipr_log_ext_vpd_compact - Log the passed extended VPD compactly. - * @prefix: string to print at start of printk - * @hostrcb: hostrcb pointer - * @vpd: vendor/product id/sn/wwn struct - * - * Return value: - * none - **/ -static void ipr_log_ext_vpd_compact(char *prefix, struct ipr_hostrcb *hostrcb, - struct ipr_ext_vpd *vpd) -{ - ipr_log_vpd_compact(prefix, hostrcb, &vpd->vpd); - ipr_hcam_err(hostrcb, "%s WWN: %08X%08X\n", prefix, - be32_to_cpu(vpd->wwid[0]), be32_to_cpu(vpd->wwid[1])); -} - -/** - * ipr_log_ext_vpd - Log the passed extended VPD to the error log. - * @vpd: vendor/product id/sn/wwn struct - * - * Return value: - * none - **/ -static void ipr_log_ext_vpd(struct ipr_ext_vpd *vpd) -{ - ipr_log_vpd(&vpd->vpd); - ipr_err(" WWN: %08X%08X\n", be32_to_cpu(vpd->wwid[0]), - be32_to_cpu(vpd->wwid[1])); -} - -/** - * ipr_log_enhanced_cache_error - Log a cache error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_enhanced_cache_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - struct ipr_hostrcb_type_12_error *error; - - if (ioa_cfg->sis64) - error = &hostrcb->hcam.u.error64.u.type_12_error; - else - error = &hostrcb->hcam.u.error.u.type_12_error; - - ipr_err("-----Current Configuration-----\n"); - ipr_err("Cache Directory Card Information:\n"); - ipr_log_ext_vpd(&error->ioa_vpd); - ipr_err("Adapter Card Information:\n"); - ipr_log_ext_vpd(&error->cfc_vpd); - - ipr_err("-----Expected Configuration-----\n"); - ipr_err("Cache Directory Card Information:\n"); - ipr_log_ext_vpd(&error->ioa_last_attached_to_cfc_vpd); - ipr_err("Adapter Card Information:\n"); - ipr_log_ext_vpd(&error->cfc_last_attached_to_ioa_vpd); - - ipr_err("Additional IOA Data: %08X %08X %08X\n", - be32_to_cpu(error->ioa_data[0]), - be32_to_cpu(error->ioa_data[1]), - be32_to_cpu(error->ioa_data[2])); -} - -/** - * ipr_log_cache_error - Log a cache error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_cache_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - struct ipr_hostrcb_type_02_error *error = - &hostrcb->hcam.u.error.u.type_02_error; - - ipr_err("-----Current Configuration-----\n"); - ipr_err("Cache Directory Card Information:\n"); - ipr_log_vpd(&error->ioa_vpd); - ipr_err("Adapter Card Information:\n"); - ipr_log_vpd(&error->cfc_vpd); - - ipr_err("-----Expected Configuration-----\n"); - ipr_err("Cache Directory Card Information:\n"); - ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpd); - ipr_err("Adapter Card Information:\n"); - ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpd); - - ipr_err("Additional IOA Data: %08X %08X %08X\n", - be32_to_cpu(error->ioa_data[0]), - be32_to_cpu(error->ioa_data[1]), - be32_to_cpu(error->ioa_data[2])); -} - -/** - * ipr_log_enhanced_config_error - Log a configuration error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_enhanced_config_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - int errors_logged, i; - struct ipr_hostrcb_device_data_entry_enhanced *dev_entry; - struct ipr_hostrcb_type_13_error *error; - - error = &hostrcb->hcam.u.error.u.type_13_error; - errors_logged = be32_to_cpu(error->errors_logged); - - ipr_err("Device Errors Detected/Logged: %d/%d\n", - be32_to_cpu(error->errors_detected), errors_logged); - - dev_entry = error->dev; - - for (i = 0; i < errors_logged; i++, dev_entry++) { - ipr_err_separator; - - ipr_phys_res_err(ioa_cfg, dev_entry->dev_res_addr, "Device %d", i + 1); - ipr_log_ext_vpd(&dev_entry->vpd); - - ipr_err("-----New Device Information-----\n"); - ipr_log_ext_vpd(&dev_entry->new_vpd); - - ipr_err("Cache Directory Card Information:\n"); - ipr_log_ext_vpd(&dev_entry->ioa_last_with_dev_vpd); - - ipr_err("Adapter Card Information:\n"); - ipr_log_ext_vpd(&dev_entry->cfc_last_with_dev_vpd); - } -} - -/** - * ipr_log_sis64_config_error - Log a device error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_sis64_config_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - int errors_logged, i; - struct ipr_hostrcb64_device_data_entry_enhanced *dev_entry; - struct ipr_hostrcb_type_23_error *error; - char buffer[IPR_MAX_RES_PATH_LENGTH]; - - error = &hostrcb->hcam.u.error64.u.type_23_error; - errors_logged = be32_to_cpu(error->errors_logged); - - ipr_err("Device Errors Detected/Logged: %d/%d\n", - be32_to_cpu(error->errors_detected), errors_logged); - - dev_entry = error->dev; - - for (i = 0; i < errors_logged; i++, dev_entry++) { - ipr_err_separator; - - ipr_err("Device %d : %s", i + 1, - ipr_format_res_path(dev_entry->res_path, buffer, - sizeof(buffer))); - ipr_log_ext_vpd(&dev_entry->vpd); - - ipr_err("-----New Device Information-----\n"); - ipr_log_ext_vpd(&dev_entry->new_vpd); - - ipr_err("Cache Directory Card Information:\n"); - ipr_log_ext_vpd(&dev_entry->ioa_last_with_dev_vpd); - - ipr_err("Adapter Card Information:\n"); - ipr_log_ext_vpd(&dev_entry->cfc_last_with_dev_vpd); - } -} - -/** - * ipr_log_config_error - Log a configuration error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_config_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - int errors_logged, i; - struct ipr_hostrcb_device_data_entry *dev_entry; - struct ipr_hostrcb_type_03_error *error; - - error = &hostrcb->hcam.u.error.u.type_03_error; - errors_logged = be32_to_cpu(error->errors_logged); - - ipr_err("Device Errors Detected/Logged: %d/%d\n", - be32_to_cpu(error->errors_detected), errors_logged); - - dev_entry = error->dev; - - for (i = 0; i < errors_logged; i++, dev_entry++) { - ipr_err_separator; - - ipr_phys_res_err(ioa_cfg, dev_entry->dev_res_addr, "Device %d", i + 1); - ipr_log_vpd(&dev_entry->vpd); - - ipr_err("-----New Device Information-----\n"); - ipr_log_vpd(&dev_entry->new_vpd); - - ipr_err("Cache Directory Card Information:\n"); - ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpd); - - ipr_err("Adapter Card Information:\n"); - ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpd); - - ipr_err("Additional IOA Data: %08X %08X %08X %08X %08X\n", - be32_to_cpu(dev_entry->ioa_data[0]), - be32_to_cpu(dev_entry->ioa_data[1]), - be32_to_cpu(dev_entry->ioa_data[2]), - be32_to_cpu(dev_entry->ioa_data[3]), - be32_to_cpu(dev_entry->ioa_data[4])); - } -} - -/** - * ipr_log_enhanced_array_error - Log an array configuration error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_enhanced_array_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - int i, num_entries; - struct ipr_hostrcb_type_14_error *error; - struct ipr_hostrcb_array_data_entry_enhanced *array_entry; - const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' }; - - error = &hostrcb->hcam.u.error.u.type_14_error; - - ipr_err_separator; - - ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n", - error->protection_level, - ioa_cfg->host->host_no, - error->last_func_vset_res_addr.bus, - error->last_func_vset_res_addr.target, - error->last_func_vset_res_addr.lun); - - ipr_err_separator; - - array_entry = error->array_member; - num_entries = min_t(u32, be32_to_cpu(error->num_entries), - ARRAY_SIZE(error->array_member)); - - for (i = 0; i < num_entries; i++, array_entry++) { - if (!memcmp(array_entry->vpd.vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN)) - continue; - - if (be32_to_cpu(error->exposed_mode_adn) == i) - ipr_err("Exposed Array Member %d:\n", i); - else - ipr_err("Array Member %d:\n", i); - - ipr_log_ext_vpd(&array_entry->vpd); - ipr_phys_res_err(ioa_cfg, array_entry->dev_res_addr, "Current Location"); - ipr_phys_res_err(ioa_cfg, array_entry->expected_dev_res_addr, - "Expected Location"); - - ipr_err_separator; - } -} - -/** - * ipr_log_array_error - Log an array configuration error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - int i; - struct ipr_hostrcb_type_04_error *error; - struct ipr_hostrcb_array_data_entry *array_entry; - const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' }; - - error = &hostrcb->hcam.u.error.u.type_04_error; - - ipr_err_separator; - - ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n", - error->protection_level, - ioa_cfg->host->host_no, - error->last_func_vset_res_addr.bus, - error->last_func_vset_res_addr.target, - error->last_func_vset_res_addr.lun); - - ipr_err_separator; - - array_entry = error->array_member; - - for (i = 0; i < 18; i++) { - if (!memcmp(array_entry->vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN)) - continue; - - if (be32_to_cpu(error->exposed_mode_adn) == i) - ipr_err("Exposed Array Member %d:\n", i); - else - ipr_err("Array Member %d:\n", i); - - ipr_log_vpd(&array_entry->vpd); - - ipr_phys_res_err(ioa_cfg, array_entry->dev_res_addr, "Current Location"); - ipr_phys_res_err(ioa_cfg, array_entry->expected_dev_res_addr, - "Expected Location"); - - ipr_err_separator; - - if (i == 9) - array_entry = error->array_member2; - else - array_entry++; - } -} - -/** - * ipr_log_hex_data - Log additional hex IOA error data. - * @ioa_cfg: ioa config struct - * @data: IOA error data - * @len: data length - * - * Return value: - * none - **/ -static void ipr_log_hex_data(struct ipr_ioa_cfg *ioa_cfg, u32 *data, int len) -{ - int i; - - if (len == 0) - return; - - if (ioa_cfg->log_level <= IPR_DEFAULT_LOG_LEVEL) - len = min_t(int, len, IPR_DEFAULT_MAX_ERROR_DUMP); - - for (i = 0; i < len / 4; i += 4) { - ipr_err("%08X: %08X %08X %08X %08X\n", i*4, - be32_to_cpu(data[i]), - be32_to_cpu(data[i+1]), - be32_to_cpu(data[i+2]), - be32_to_cpu(data[i+3])); - } -} - -/** - * ipr_log_enhanced_dual_ioa_error - Log an enhanced dual adapter error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_enhanced_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - struct ipr_hostrcb_type_17_error *error; - - if (ioa_cfg->sis64) - error = &hostrcb->hcam.u.error64.u.type_17_error; - else - error = &hostrcb->hcam.u.error.u.type_17_error; - - error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; - strim(error->failure_reason); - - ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason, - be32_to_cpu(hostrcb->hcam.u.error.prc)); - ipr_log_ext_vpd_compact("Remote IOA", hostrcb, &error->vpd); - ipr_log_hex_data(ioa_cfg, error->data, - be32_to_cpu(hostrcb->hcam.length) - - (offsetof(struct ipr_hostrcb_error, u) + - offsetof(struct ipr_hostrcb_type_17_error, data))); -} - -/** - * ipr_log_dual_ioa_error - Log a dual adapter error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_dual_ioa_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - struct ipr_hostrcb_type_07_error *error; - - error = &hostrcb->hcam.u.error.u.type_07_error; - error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; - strim(error->failure_reason); - - ipr_hcam_err(hostrcb, "%s [PRC: %08X]\n", error->failure_reason, - be32_to_cpu(hostrcb->hcam.u.error.prc)); - ipr_log_vpd_compact("Remote IOA", hostrcb, &error->vpd); - ipr_log_hex_data(ioa_cfg, error->data, - be32_to_cpu(hostrcb->hcam.length) - - (offsetof(struct ipr_hostrcb_error, u) + - offsetof(struct ipr_hostrcb_type_07_error, data))); -} - -static const struct { - u8 active; - char *desc; -} path_active_desc[] = { - { IPR_PATH_NO_INFO, "Path" }, - { IPR_PATH_ACTIVE, "Active path" }, - { IPR_PATH_NOT_ACTIVE, "Inactive path" } -}; - -static const struct { - u8 state; - char *desc; -} path_state_desc[] = { - { IPR_PATH_STATE_NO_INFO, "has no path state information available" }, - { IPR_PATH_HEALTHY, "is healthy" }, - { IPR_PATH_DEGRADED, "is degraded" }, - { IPR_PATH_FAILED, "is failed" } -}; - -/** - * ipr_log_fabric_path - Log a fabric path error - * @hostrcb: hostrcb struct - * @fabric: fabric descriptor - * - * Return value: - * none - **/ -static void ipr_log_fabric_path(struct ipr_hostrcb *hostrcb, - struct ipr_hostrcb_fabric_desc *fabric) -{ - int i, j; - u8 path_state = fabric->path_state; - u8 active = path_state & IPR_PATH_ACTIVE_MASK; - u8 state = path_state & IPR_PATH_STATE_MASK; - - for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) { - if (path_active_desc[i].active != active) - continue; - - for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) { - if (path_state_desc[j].state != state) - continue; - - if (fabric->cascaded_expander == 0xff && fabric->phy == 0xff) { - ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d\n", - path_active_desc[i].desc, path_state_desc[j].desc, - fabric->ioa_port); - } else if (fabric->cascaded_expander == 0xff) { - ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Phy=%d\n", - path_active_desc[i].desc, path_state_desc[j].desc, - fabric->ioa_port, fabric->phy); - } else if (fabric->phy == 0xff) { - ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d\n", - path_active_desc[i].desc, path_state_desc[j].desc, - fabric->ioa_port, fabric->cascaded_expander); - } else { - ipr_hcam_err(hostrcb, "%s %s: IOA Port=%d, Cascade=%d, Phy=%d\n", - path_active_desc[i].desc, path_state_desc[j].desc, - fabric->ioa_port, fabric->cascaded_expander, fabric->phy); - } - return; - } - } - - ipr_err("Path state=%02X IOA Port=%d Cascade=%d Phy=%d\n", path_state, - fabric->ioa_port, fabric->cascaded_expander, fabric->phy); -} - -/** - * ipr_log64_fabric_path - Log a fabric path error - * @hostrcb: hostrcb struct - * @fabric: fabric descriptor - * - * Return value: - * none - **/ -static void ipr_log64_fabric_path(struct ipr_hostrcb *hostrcb, - struct ipr_hostrcb64_fabric_desc *fabric) -{ - int i, j; - u8 path_state = fabric->path_state; - u8 active = path_state & IPR_PATH_ACTIVE_MASK; - u8 state = path_state & IPR_PATH_STATE_MASK; - char buffer[IPR_MAX_RES_PATH_LENGTH]; - - for (i = 0; i < ARRAY_SIZE(path_active_desc); i++) { - if (path_active_desc[i].active != active) - continue; - - for (j = 0; j < ARRAY_SIZE(path_state_desc); j++) { - if (path_state_desc[j].state != state) - continue; - - ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s\n", - path_active_desc[i].desc, path_state_desc[j].desc, - ipr_format_res_path(fabric->res_path, buffer, - sizeof(buffer))); - return; - } - } - - ipr_err("Path state=%02X Resource Path=%s\n", path_state, - ipr_format_res_path(fabric->res_path, buffer, sizeof(buffer))); -} - -static const struct { - u8 type; - char *desc; -} path_type_desc[] = { - { IPR_PATH_CFG_IOA_PORT, "IOA port" }, - { IPR_PATH_CFG_EXP_PORT, "Expander port" }, - { IPR_PATH_CFG_DEVICE_PORT, "Device port" }, - { IPR_PATH_CFG_DEVICE_LUN, "Device LUN" } -}; - -static const struct { - u8 status; - char *desc; -} path_status_desc[] = { - { IPR_PATH_CFG_NO_PROB, "Functional" }, - { IPR_PATH_CFG_DEGRADED, "Degraded" }, - { IPR_PATH_CFG_FAILED, "Failed" }, - { IPR_PATH_CFG_SUSPECT, "Suspect" }, - { IPR_PATH_NOT_DETECTED, "Missing" }, - { IPR_PATH_INCORRECT_CONN, "Incorrectly connected" } -}; - -static const char *link_rate[] = { - "unknown", - "disabled", - "phy reset problem", - "spinup hold", - "port selector", - "unknown", - "unknown", - "unknown", - "1.5Gbps", - "3.0Gbps", - "unknown", - "unknown", - "unknown", - "unknown", - "unknown", - "unknown" -}; - -/** - * ipr_log_path_elem - Log a fabric path element. - * @hostrcb: hostrcb struct - * @cfg: fabric path element struct - * - * Return value: - * none - **/ -static void ipr_log_path_elem(struct ipr_hostrcb *hostrcb, - struct ipr_hostrcb_config_element *cfg) -{ - int i, j; - u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK; - u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK; - - if (type == IPR_PATH_CFG_NOT_EXIST) - return; - - for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) { - if (path_type_desc[i].type != type) - continue; - - for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) { - if (path_status_desc[j].status != status) - continue; - - if (type == IPR_PATH_CFG_IOA_PORT) { - ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, WWN=%08X%08X\n", - path_status_desc[j].desc, path_type_desc[i].desc, - cfg->phy, link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], - be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); - } else { - if (cfg->cascaded_expander == 0xff && cfg->phy == 0xff) { - ipr_hcam_err(hostrcb, "%s %s: Link rate=%s, WWN=%08X%08X\n", - path_status_desc[j].desc, path_type_desc[i].desc, - link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], - be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); - } else if (cfg->cascaded_expander == 0xff) { - ipr_hcam_err(hostrcb, "%s %s: Phy=%d, Link rate=%s, " - "WWN=%08X%08X\n", path_status_desc[j].desc, - path_type_desc[i].desc, cfg->phy, - link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], - be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); - } else if (cfg->phy == 0xff) { - ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Link rate=%s, " - "WWN=%08X%08X\n", path_status_desc[j].desc, - path_type_desc[i].desc, cfg->cascaded_expander, - link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], - be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); - } else { - ipr_hcam_err(hostrcb, "%s %s: Cascade=%d, Phy=%d, Link rate=%s " - "WWN=%08X%08X\n", path_status_desc[j].desc, - path_type_desc[i].desc, cfg->cascaded_expander, cfg->phy, - link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], - be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); - } - } - return; - } - } - - ipr_hcam_err(hostrcb, "Path element=%02X: Cascade=%d Phy=%d Link rate=%s " - "WWN=%08X%08X\n", cfg->type_status, cfg->cascaded_expander, cfg->phy, - link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], - be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); -} - -/** - * ipr_log64_path_elem - Log a fabric path element. - * @hostrcb: hostrcb struct - * @cfg: fabric path element struct - * - * Return value: - * none - **/ -static void ipr_log64_path_elem(struct ipr_hostrcb *hostrcb, - struct ipr_hostrcb64_config_element *cfg) -{ - int i, j; - u8 desc_id = cfg->descriptor_id & IPR_DESCRIPTOR_MASK; - u8 type = cfg->type_status & IPR_PATH_CFG_TYPE_MASK; - u8 status = cfg->type_status & IPR_PATH_CFG_STATUS_MASK; - char buffer[IPR_MAX_RES_PATH_LENGTH]; - - if (type == IPR_PATH_CFG_NOT_EXIST || desc_id != IPR_DESCRIPTOR_SIS64) - return; - - for (i = 0; i < ARRAY_SIZE(path_type_desc); i++) { - if (path_type_desc[i].type != type) - continue; - - for (j = 0; j < ARRAY_SIZE(path_status_desc); j++) { - if (path_status_desc[j].status != status) - continue; - - ipr_hcam_err(hostrcb, "%s %s: Resource Path=%s, Link rate=%s, WWN=%08X%08X\n", - path_status_desc[j].desc, path_type_desc[i].desc, - ipr_format_res_path(cfg->res_path, buffer, - sizeof(buffer)), - link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], - be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); - return; - } - } - ipr_hcam_err(hostrcb, "Path element=%02X: Resource Path=%s, Link rate=%s " - "WWN=%08X%08X\n", cfg->type_status, - ipr_format_res_path(cfg->res_path, buffer, sizeof(buffer)), - link_rate[cfg->link_rate & IPR_PHY_LINK_RATE_MASK], - be32_to_cpu(cfg->wwid[0]), be32_to_cpu(cfg->wwid[1])); -} - -/** - * ipr_log_fabric_error - Log a fabric error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_fabric_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - struct ipr_hostrcb_type_20_error *error; - struct ipr_hostrcb_fabric_desc *fabric; - struct ipr_hostrcb_config_element *cfg; - int i, add_len; - - error = &hostrcb->hcam.u.error.u.type_20_error; - error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; - ipr_hcam_err(hostrcb, "%s\n", error->failure_reason); - - add_len = be32_to_cpu(hostrcb->hcam.length) - - (offsetof(struct ipr_hostrcb_error, u) + - offsetof(struct ipr_hostrcb_type_20_error, desc)); - - for (i = 0, fabric = error->desc; i < error->num_entries; i++) { - ipr_log_fabric_path(hostrcb, fabric); - for_each_fabric_cfg(fabric, cfg) - ipr_log_path_elem(hostrcb, cfg); - - add_len -= be16_to_cpu(fabric->length); - fabric = (struct ipr_hostrcb_fabric_desc *) - ((unsigned long)fabric + be16_to_cpu(fabric->length)); - } - - ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len); -} - -/** - * ipr_log_sis64_array_error - Log a sis64 array error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_sis64_array_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - int i, num_entries; - struct ipr_hostrcb_type_24_error *error; - struct ipr_hostrcb64_array_data_entry *array_entry; - char buffer[IPR_MAX_RES_PATH_LENGTH]; - const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' }; - - error = &hostrcb->hcam.u.error64.u.type_24_error; - - ipr_err_separator; - - ipr_err("RAID %s Array Configuration: %s\n", - error->protection_level, - ipr_format_res_path(error->last_res_path, buffer, sizeof(buffer))); - - ipr_err_separator; - - array_entry = error->array_member; - num_entries = min_t(u32, error->num_entries, - ARRAY_SIZE(error->array_member)); - - for (i = 0; i < num_entries; i++, array_entry++) { - - if (!memcmp(array_entry->vpd.vpd.sn, zero_sn, IPR_SERIAL_NUM_LEN)) - continue; - - if (error->exposed_mode_adn == i) - ipr_err("Exposed Array Member %d:\n", i); - else - ipr_err("Array Member %d:\n", i); - - ipr_err("Array Member %d:\n", i); - ipr_log_ext_vpd(&array_entry->vpd); - ipr_err("Current Location: %s\n", - ipr_format_res_path(array_entry->res_path, buffer, - sizeof(buffer))); - ipr_err("Expected Location: %s\n", - ipr_format_res_path(array_entry->expected_res_path, - buffer, sizeof(buffer))); - - ipr_err_separator; - } -} - -/** - * ipr_log_sis64_fabric_error - Log a sis64 fabric error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_sis64_fabric_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - struct ipr_hostrcb_type_30_error *error; - struct ipr_hostrcb64_fabric_desc *fabric; - struct ipr_hostrcb64_config_element *cfg; - int i, add_len; - - error = &hostrcb->hcam.u.error64.u.type_30_error; - - error->failure_reason[sizeof(error->failure_reason) - 1] = '\0'; - ipr_hcam_err(hostrcb, "%s\n", error->failure_reason); - - add_len = be32_to_cpu(hostrcb->hcam.length) - - (offsetof(struct ipr_hostrcb64_error, u) + - offsetof(struct ipr_hostrcb_type_30_error, desc)); - - for (i = 0, fabric = error->desc; i < error->num_entries; i++) { - ipr_log64_fabric_path(hostrcb, fabric); - for_each_fabric_cfg(fabric, cfg) - ipr_log64_path_elem(hostrcb, cfg); - - add_len -= be16_to_cpu(fabric->length); - fabric = (struct ipr_hostrcb64_fabric_desc *) - ((unsigned long)fabric + be16_to_cpu(fabric->length)); - } - - ipr_log_hex_data(ioa_cfg, (u32 *)fabric, add_len); -} - -/** - * ipr_log_generic_error - Log an adapter error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * Return value: - * none - **/ -static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - ipr_log_hex_data(ioa_cfg, hostrcb->hcam.u.raw.data, - be32_to_cpu(hostrcb->hcam.length)); -} - -/** - * ipr_get_error - Find the specfied IOASC in the ipr_error_table. - * @ioasc: IOASC - * - * This function will return the index of into the ipr_error_table - * for the specified IOASC. If the IOASC is not in the table, - * 0 will be returned, which points to the entry used for unknown errors. - * - * Return value: - * index into the ipr_error_table - **/ -static u32 ipr_get_error(u32 ioasc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++) - if (ipr_error_table[i].ioasc == (ioasc & IPR_IOASC_IOASC_MASK)) - return i; - - return 0; -} - -/** - * ipr_handle_log_data - Log an adapter error. - * @ioa_cfg: ioa config struct - * @hostrcb: hostrcb struct - * - * This function logs an adapter error to the system. - * - * Return value: - * none - **/ -static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_hostrcb *hostrcb) -{ - u32 ioasc; - int error_index; - - if (hostrcb->hcam.notify_type != IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY) - return; - - if (hostrcb->hcam.notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST) - dev_err(&ioa_cfg->pdev->dev, "Error notifications lost\n"); - - if (ioa_cfg->sis64) - ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc); - else - ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc); - - if (!ioa_cfg->sis64 && (ioasc == IPR_IOASC_BUS_WAS_RESET || - ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER)) { - /* Tell the midlayer we had a bus reset so it will handle the UA properly */ - scsi_report_bus_reset(ioa_cfg->host, - hostrcb->hcam.u.error.fd_res_addr.bus); - } - - error_index = ipr_get_error(ioasc); - - if (!ipr_error_table[error_index].log_hcam) - return; - - ipr_hcam_err(hostrcb, "%s\n", ipr_error_table[error_index].error); - - /* Set indication we have logged an error */ - ioa_cfg->errors_logged++; - - if (ioa_cfg->log_level < ipr_error_table[error_index].log_hcam) - return; - if (be32_to_cpu(hostrcb->hcam.length) > sizeof(hostrcb->hcam.u.raw)) - hostrcb->hcam.length = cpu_to_be32(sizeof(hostrcb->hcam.u.raw)); - - switch (hostrcb->hcam.overlay_id) { - case IPR_HOST_RCB_OVERLAY_ID_2: - ipr_log_cache_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_3: - ipr_log_config_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_4: - case IPR_HOST_RCB_OVERLAY_ID_6: - ipr_log_array_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_7: - ipr_log_dual_ioa_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_12: - ipr_log_enhanced_cache_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_13: - ipr_log_enhanced_config_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_14: - case IPR_HOST_RCB_OVERLAY_ID_16: - ipr_log_enhanced_array_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_17: - ipr_log_enhanced_dual_ioa_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_20: - ipr_log_fabric_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_23: - ipr_log_sis64_config_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_24: - case IPR_HOST_RCB_OVERLAY_ID_26: - ipr_log_sis64_array_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_30: - ipr_log_sis64_fabric_error(ioa_cfg, hostrcb); - break; - case IPR_HOST_RCB_OVERLAY_ID_1: - case IPR_HOST_RCB_OVERLAY_ID_DEFAULT: - default: - ipr_log_generic_error(ioa_cfg, hostrcb); - break; - } -} - -/** - * ipr_process_error - Op done function for an adapter error log. - * @ipr_cmd: ipr command struct - * - * This function is the op done function for an error log host - * controlled async from the adapter. It will log the error and - * send the HCAM back to the adapter. - * - * Return value: - * none - **/ -static void ipr_process_error(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - u32 fd_ioasc; - - if (ioa_cfg->sis64) - fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error64.fd_ioasc); - else - fd_ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc); - - list_del(&hostrcb->queue); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - - if (!ioasc) { - ipr_handle_log_data(ioa_cfg, hostrcb); - if (fd_ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED) - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_ABBREV); - } else if (ioasc != IPR_IOASC_IOA_WAS_RESET) { - dev_err(&ioa_cfg->pdev->dev, - "Host RCB failed with IOASC: 0x%08X\n", ioasc); - } - - ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); -} - -/** - * ipr_timeout - An internally generated op has timed out. - * @ipr_cmd: ipr command struct - * - * This function blocks host requests and initiates an - * adapter reset. - * - * Return value: - * none - **/ -static void ipr_timeout(struct ipr_cmnd *ipr_cmd) -{ - unsigned long lock_flags = 0; - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - ioa_cfg->errors_logged++; - dev_err(&ioa_cfg->pdev->dev, - "Adapter being reset due to command timeout.\n"); - - if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) - ioa_cfg->sdt_state = GET_DUMP; - - if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd) - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - LEAVE; -} - -/** - * ipr_oper_timeout - Adapter timed out transitioning to operational - * @ipr_cmd: ipr command struct - * - * This function blocks host requests and initiates an - * adapter reset. - * - * Return value: - * none - **/ -static void ipr_oper_timeout(struct ipr_cmnd *ipr_cmd) -{ - unsigned long lock_flags = 0; - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - ioa_cfg->errors_logged++; - dev_err(&ioa_cfg->pdev->dev, - "Adapter timed out transitioning to operational.\n"); - - if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) - ioa_cfg->sdt_state = GET_DUMP; - - if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd) { - if (ipr_fastfail) - ioa_cfg->reset_retries += IPR_NUM_RESET_RELOAD_RETRIES; - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - } - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - LEAVE; -} - -/** - * ipr_reset_reload - Reset/Reload the IOA - * @ioa_cfg: ioa config struct - * @shutdown_type: shutdown type - * - * This function resets the adapter and re-initializes it. - * This function assumes that all new host commands have been stopped. - * Return value: - * SUCCESS / FAILED - **/ -static int ipr_reset_reload(struct ipr_ioa_cfg *ioa_cfg, - enum ipr_shutdown_type shutdown_type) -{ - if (!ioa_cfg->in_reset_reload) - ipr_initiate_ioa_reset(ioa_cfg, shutdown_type); - - spin_unlock_irq(ioa_cfg->host->host_lock); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irq(ioa_cfg->host->host_lock); - - /* If we got hit with a host reset while we were already resetting - the adapter for some reason, and the reset failed. */ - if (ioa_cfg->ioa_is_dead) { - ipr_trace; - return FAILED; - } - - return SUCCESS; -} - -/** - * ipr_find_ses_entry - Find matching SES in SES table - * @res: resource entry struct of SES - * - * Return value: - * pointer to SES table entry / NULL on failure - **/ -static const struct ipr_ses_table_entry * -ipr_find_ses_entry(struct ipr_resource_entry *res) -{ - int i, j, matches; - struct ipr_std_inq_vpids *vpids; - const struct ipr_ses_table_entry *ste = ipr_ses_table; - - for (i = 0; i < ARRAY_SIZE(ipr_ses_table); i++, ste++) { - for (j = 0, matches = 0; j < IPR_PROD_ID_LEN; j++) { - if (ste->compare_product_id_byte[j] == 'X') { - vpids = &res->std_inq_data.vpids; - if (vpids->product_id[j] == ste->product_id[j]) - matches++; - else - break; - } else - matches++; - } - - if (matches == IPR_PROD_ID_LEN) - return ste; - } - - return NULL; -} - -/** - * ipr_get_max_scsi_speed - Determine max SCSI speed for a given bus - * @ioa_cfg: ioa config struct - * @bus: SCSI bus - * @bus_width: bus width - * - * Return value: - * SCSI bus speed in units of 100KHz, 1600 is 160 MHz - * For a 2-byte wide SCSI bus, the maximum transfer speed is - * twice the maximum transfer rate (e.g. for a wide enabled bus, - * max 160MHz = max 320MB/sec). - **/ -static u32 ipr_get_max_scsi_speed(struct ipr_ioa_cfg *ioa_cfg, u8 bus, u8 bus_width) -{ - struct ipr_resource_entry *res; - const struct ipr_ses_table_entry *ste; - u32 max_xfer_rate = IPR_MAX_SCSI_RATE(bus_width); - - /* Loop through each config table entry in the config table buffer */ - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if (!(IPR_IS_SES_DEVICE(res->std_inq_data))) - continue; - - if (bus != res->bus) - continue; - - if (!(ste = ipr_find_ses_entry(res))) - continue; - - max_xfer_rate = (ste->max_bus_speed_limit * 10) / (bus_width / 8); - } - - return max_xfer_rate; -} - -/** - * ipr_wait_iodbg_ack - Wait for an IODEBUG ACK from the IOA - * @ioa_cfg: ioa config struct - * @max_delay: max delay in micro-seconds to wait - * - * Waits for an IODEBUG ACK from the IOA, doing busy looping. - * - * Return value: - * 0 on success / other on failure - **/ -static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay) -{ - volatile u32 pcii_reg; - int delay = 1; - - /* Read interrupt reg until IOA signals IO Debug Acknowledge */ - while (delay < max_delay) { - pcii_reg = readl(ioa_cfg->regs.sense_interrupt_reg); - - if (pcii_reg & IPR_PCII_IO_DEBUG_ACKNOWLEDGE) - return 0; - - /* udelay cannot be used if delay is more than a few milliseconds */ - if ((delay / 1000) > MAX_UDELAY_MS) - mdelay(delay / 1000); - else - udelay(delay); - - delay += delay; - } - return -EIO; -} - -/** - * ipr_get_sis64_dump_data_section - Dump IOA memory - * @ioa_cfg: ioa config struct - * @start_addr: adapter address to dump - * @dest: destination kernel buffer - * @length_in_words: length to dump in 4 byte words - * - * Return value: - * 0 on success - **/ -static int ipr_get_sis64_dump_data_section(struct ipr_ioa_cfg *ioa_cfg, - u32 start_addr, - __be32 *dest, u32 length_in_words) -{ - int i; - - for (i = 0; i < length_in_words; i++) { - writel(start_addr+(i*4), ioa_cfg->regs.dump_addr_reg); - *dest = cpu_to_be32(readl(ioa_cfg->regs.dump_data_reg)); - dest++; - } - - return 0; -} - -/** - * ipr_get_ldump_data_section - Dump IOA memory - * @ioa_cfg: ioa config struct - * @start_addr: adapter address to dump - * @dest: destination kernel buffer - * @length_in_words: length to dump in 4 byte words - * - * Return value: - * 0 on success / -EIO on failure - **/ -static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg, - u32 start_addr, - __be32 *dest, u32 length_in_words) -{ - volatile u32 temp_pcii_reg; - int i, delay = 0; - - if (ioa_cfg->sis64) - return ipr_get_sis64_dump_data_section(ioa_cfg, start_addr, - dest, length_in_words); - - /* Write IOA interrupt reg starting LDUMP state */ - writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT), - ioa_cfg->regs.set_uproc_interrupt_reg32); - - /* Wait for IO debug acknowledge */ - if (ipr_wait_iodbg_ack(ioa_cfg, - IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC)) { - dev_err(&ioa_cfg->pdev->dev, - "IOA dump long data transfer timeout\n"); - return -EIO; - } - - /* Signal LDUMP interlocked - clear IO debug ack */ - writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, - ioa_cfg->regs.clr_interrupt_reg); - - /* Write Mailbox with starting address */ - writel(start_addr, ioa_cfg->ioa_mailbox); - - /* Signal address valid - clear IOA Reset alert */ - writel(IPR_UPROCI_RESET_ALERT, - ioa_cfg->regs.clr_uproc_interrupt_reg32); - - for (i = 0; i < length_in_words; i++) { - /* Wait for IO debug acknowledge */ - if (ipr_wait_iodbg_ack(ioa_cfg, - IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC)) { - dev_err(&ioa_cfg->pdev->dev, - "IOA dump short data transfer timeout\n"); - return -EIO; - } - - /* Read data from mailbox and increment destination pointer */ - *dest = cpu_to_be32(readl(ioa_cfg->ioa_mailbox)); - dest++; - - /* For all but the last word of data, signal data received */ - if (i < (length_in_words - 1)) { - /* Signal dump data received - Clear IO debug Ack */ - writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, - ioa_cfg->regs.clr_interrupt_reg); - } - } - - /* Signal end of block transfer. Set reset alert then clear IO debug ack */ - writel(IPR_UPROCI_RESET_ALERT, - ioa_cfg->regs.set_uproc_interrupt_reg32); - - writel(IPR_UPROCI_IO_DEBUG_ALERT, - ioa_cfg->regs.clr_uproc_interrupt_reg32); - - /* Signal dump data received - Clear IO debug Ack */ - writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, - ioa_cfg->regs.clr_interrupt_reg); - - /* Wait for IOA to signal LDUMP exit - IOA reset alert will be cleared */ - while (delay < IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC) { - temp_pcii_reg = - readl(ioa_cfg->regs.sense_uproc_interrupt_reg32); - - if (!(temp_pcii_reg & IPR_UPROCI_RESET_ALERT)) - return 0; - - udelay(10); - delay += 10; - } - - return 0; -} - -#ifdef CONFIG_SCSI_IPR_DUMP -/** - * ipr_sdt_copy - Copy Smart Dump Table to kernel buffer - * @ioa_cfg: ioa config struct - * @pci_address: adapter address - * @length: length of data to copy - * - * Copy data from PCI adapter to kernel buffer. - * Note: length MUST be a 4 byte multiple - * Return value: - * 0 on success / other on failure - **/ -static int ipr_sdt_copy(struct ipr_ioa_cfg *ioa_cfg, - unsigned long pci_address, u32 length) -{ - int bytes_copied = 0; - int cur_len, rc, rem_len, rem_page_len, max_dump_size; - __be32 *page; - unsigned long lock_flags = 0; - struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump; - - if (ioa_cfg->sis64) - max_dump_size = IPR_FMT3_MAX_IOA_DUMP_SIZE; - else - max_dump_size = IPR_FMT2_MAX_IOA_DUMP_SIZE; - - while (bytes_copied < length && - (ioa_dump->hdr.len + bytes_copied) < max_dump_size) { - if (ioa_dump->page_offset >= PAGE_SIZE || - ioa_dump->page_offset == 0) { - page = (__be32 *)__get_free_page(GFP_ATOMIC); - - if (!page) { - ipr_trace; - return bytes_copied; - } - - ioa_dump->page_offset = 0; - ioa_dump->ioa_data[ioa_dump->next_page_index] = page; - ioa_dump->next_page_index++; - } else - page = ioa_dump->ioa_data[ioa_dump->next_page_index - 1]; - - rem_len = length - bytes_copied; - rem_page_len = PAGE_SIZE - ioa_dump->page_offset; - cur_len = min(rem_len, rem_page_len); - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - if (ioa_cfg->sdt_state == ABORT_DUMP) { - rc = -EIO; - } else { - rc = ipr_get_ldump_data_section(ioa_cfg, - pci_address + bytes_copied, - &page[ioa_dump->page_offset / 4], - (cur_len / sizeof(u32))); - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - if (!rc) { - ioa_dump->page_offset += cur_len; - bytes_copied += cur_len; - } else { - ipr_trace; - break; - } - schedule(); - } - - return bytes_copied; -} - -/** - * ipr_init_dump_entry_hdr - Initialize a dump entry header. - * @hdr: dump entry header struct - * - * Return value: - * nothing - **/ -static void ipr_init_dump_entry_hdr(struct ipr_dump_entry_header *hdr) -{ - hdr->eye_catcher = IPR_DUMP_EYE_CATCHER; - hdr->num_elems = 1; - hdr->offset = sizeof(*hdr); - hdr->status = IPR_DUMP_STATUS_SUCCESS; -} - -/** - * ipr_dump_ioa_type_data - Fill in the adapter type in the dump. - * @ioa_cfg: ioa config struct - * @driver_dump: driver dump struct - * - * Return value: - * nothing - **/ -static void ipr_dump_ioa_type_data(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_driver_dump *driver_dump) -{ - struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; - - ipr_init_dump_entry_hdr(&driver_dump->ioa_type_entry.hdr); - driver_dump->ioa_type_entry.hdr.len = - sizeof(struct ipr_dump_ioa_type_entry) - - sizeof(struct ipr_dump_entry_header); - driver_dump->ioa_type_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; - driver_dump->ioa_type_entry.hdr.id = IPR_DUMP_DRIVER_TYPE_ID; - driver_dump->ioa_type_entry.type = ioa_cfg->type; - driver_dump->ioa_type_entry.fw_version = (ucode_vpd->major_release << 24) | - (ucode_vpd->card_type << 16) | (ucode_vpd->minor_release[0] << 8) | - ucode_vpd->minor_release[1]; - driver_dump->hdr.num_entries++; -} - -/** - * ipr_dump_version_data - Fill in the driver version in the dump. - * @ioa_cfg: ioa config struct - * @driver_dump: driver dump struct - * - * Return value: - * nothing - **/ -static void ipr_dump_version_data(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_driver_dump *driver_dump) -{ - ipr_init_dump_entry_hdr(&driver_dump->version_entry.hdr); - driver_dump->version_entry.hdr.len = - sizeof(struct ipr_dump_version_entry) - - sizeof(struct ipr_dump_entry_header); - driver_dump->version_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII; - driver_dump->version_entry.hdr.id = IPR_DUMP_DRIVER_VERSION_ID; - strcpy(driver_dump->version_entry.version, IPR_DRIVER_VERSION); - driver_dump->hdr.num_entries++; -} - -/** - * ipr_dump_trace_data - Fill in the IOA trace in the dump. - * @ioa_cfg: ioa config struct - * @driver_dump: driver dump struct - * - * Return value: - * nothing - **/ -static void ipr_dump_trace_data(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_driver_dump *driver_dump) -{ - ipr_init_dump_entry_hdr(&driver_dump->trace_entry.hdr); - driver_dump->trace_entry.hdr.len = - sizeof(struct ipr_dump_trace_entry) - - sizeof(struct ipr_dump_entry_header); - driver_dump->trace_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; - driver_dump->trace_entry.hdr.id = IPR_DUMP_TRACE_ID; - memcpy(driver_dump->trace_entry.trace, ioa_cfg->trace, IPR_TRACE_SIZE); - driver_dump->hdr.num_entries++; -} - -/** - * ipr_dump_location_data - Fill in the IOA location in the dump. - * @ioa_cfg: ioa config struct - * @driver_dump: driver dump struct - * - * Return value: - * nothing - **/ -static void ipr_dump_location_data(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_driver_dump *driver_dump) -{ - ipr_init_dump_entry_hdr(&driver_dump->location_entry.hdr); - driver_dump->location_entry.hdr.len = - sizeof(struct ipr_dump_location_entry) - - sizeof(struct ipr_dump_entry_header); - driver_dump->location_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII; - driver_dump->location_entry.hdr.id = IPR_DUMP_LOCATION_ID; - strcpy(driver_dump->location_entry.location, dev_name(&ioa_cfg->pdev->dev)); - driver_dump->hdr.num_entries++; -} - -/** - * ipr_get_ioa_dump - Perform a dump of the driver and adapter. - * @ioa_cfg: ioa config struct - * @dump: dump struct - * - * Return value: - * nothing - **/ -static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump) -{ - unsigned long start_addr, sdt_word; - unsigned long lock_flags = 0; - struct ipr_driver_dump *driver_dump = &dump->driver_dump; - struct ipr_ioa_dump *ioa_dump = &dump->ioa_dump; - u32 num_entries, max_num_entries, start_off, end_off; - u32 max_dump_size, bytes_to_copy, bytes_copied, rc; - struct ipr_sdt *sdt; - int valid = 1; - int i; - - ENTER; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - if (ioa_cfg->sdt_state != READ_DUMP) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return; - } - - if (ioa_cfg->sis64) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - ssleep(IPR_DUMP_DELAY_SECONDS); - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - } - - start_addr = readl(ioa_cfg->ioa_mailbox); - - if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(start_addr)) { - dev_err(&ioa_cfg->pdev->dev, - "Invalid dump table format: %lx\n", start_addr); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return; - } - - dev_err(&ioa_cfg->pdev->dev, "Dump of IOA initiated\n"); - - driver_dump->hdr.eye_catcher = IPR_DUMP_EYE_CATCHER; - - /* Initialize the overall dump header */ - driver_dump->hdr.len = sizeof(struct ipr_driver_dump); - driver_dump->hdr.num_entries = 1; - driver_dump->hdr.first_entry_offset = sizeof(struct ipr_dump_header); - driver_dump->hdr.status = IPR_DUMP_STATUS_SUCCESS; - driver_dump->hdr.os = IPR_DUMP_OS_LINUX; - driver_dump->hdr.driver_name = IPR_DUMP_DRIVER_NAME; - - ipr_dump_version_data(ioa_cfg, driver_dump); - ipr_dump_location_data(ioa_cfg, driver_dump); - ipr_dump_ioa_type_data(ioa_cfg, driver_dump); - ipr_dump_trace_data(ioa_cfg, driver_dump); - - /* Update dump_header */ - driver_dump->hdr.len += sizeof(struct ipr_dump_entry_header); - - /* IOA Dump entry */ - ipr_init_dump_entry_hdr(&ioa_dump->hdr); - ioa_dump->hdr.len = 0; - ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY; - ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID; - - /* First entries in sdt are actually a list of dump addresses and - lengths to gather the real dump data. sdt represents the pointer - to the ioa generated dump table. Dump data will be extracted based - on entries in this table */ - sdt = &ioa_dump->sdt; - - if (ioa_cfg->sis64) { - max_num_entries = IPR_FMT3_NUM_SDT_ENTRIES; - max_dump_size = IPR_FMT3_MAX_IOA_DUMP_SIZE; - } else { - max_num_entries = IPR_FMT2_NUM_SDT_ENTRIES; - max_dump_size = IPR_FMT2_MAX_IOA_DUMP_SIZE; - } - - bytes_to_copy = offsetof(struct ipr_sdt, entry) + - (max_num_entries * sizeof(struct ipr_sdt_entry)); - rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (__be32 *)sdt, - bytes_to_copy / sizeof(__be32)); - - /* Smart Dump table is ready to use and the first entry is valid */ - if (rc || ((be32_to_cpu(sdt->hdr.state) != IPR_FMT3_SDT_READY_TO_USE) && - (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE))) { - dev_err(&ioa_cfg->pdev->dev, - "Dump of IOA failed. Dump table not valid: %d, %X.\n", - rc, be32_to_cpu(sdt->hdr.state)); - driver_dump->hdr.status = IPR_DUMP_STATUS_FAILED; - ioa_cfg->sdt_state = DUMP_OBTAINED; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return; - } - - num_entries = be32_to_cpu(sdt->hdr.num_entries_used); - - if (num_entries > max_num_entries) - num_entries = max_num_entries; - - /* Update dump length to the actual data to be copied */ - dump->driver_dump.hdr.len += sizeof(struct ipr_sdt_header); - if (ioa_cfg->sis64) - dump->driver_dump.hdr.len += num_entries * sizeof(struct ipr_sdt_entry); - else - dump->driver_dump.hdr.len += max_num_entries * sizeof(struct ipr_sdt_entry); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - for (i = 0; i < num_entries; i++) { - if (ioa_dump->hdr.len > max_dump_size) { - driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS; - break; - } - - if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) { - sdt_word = be32_to_cpu(sdt->entry[i].start_token); - if (ioa_cfg->sis64) - bytes_to_copy = be32_to_cpu(sdt->entry[i].end_token); - else { - start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK; - end_off = be32_to_cpu(sdt->entry[i].end_token); - - if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) - bytes_to_copy = end_off - start_off; - else - valid = 0; - } - if (valid) { - if (bytes_to_copy > max_dump_size) { - sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY; - continue; - } - - /* Copy data from adapter to driver buffers */ - bytes_copied = ipr_sdt_copy(ioa_cfg, sdt_word, - bytes_to_copy); - - ioa_dump->hdr.len += bytes_copied; - - if (bytes_copied != bytes_to_copy) { - driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS; - break; - } - } - } - } - - dev_err(&ioa_cfg->pdev->dev, "Dump of IOA completed.\n"); - - /* Update dump_header */ - driver_dump->hdr.len += ioa_dump->hdr.len; - wmb(); - ioa_cfg->sdt_state = DUMP_OBTAINED; - LEAVE; -} - -#else -#define ipr_get_ioa_dump(ioa_cfg, dump) do { } while(0) -#endif - -/** - * ipr_release_dump - Free adapter dump memory - * @kref: kref struct - * - * Return value: - * nothing - **/ -static void ipr_release_dump(struct kref *kref) -{ - struct ipr_dump *dump = container_of(kref,struct ipr_dump,kref); - struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg; - unsigned long lock_flags = 0; - int i; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - ioa_cfg->dump = NULL; - ioa_cfg->sdt_state = INACTIVE; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - for (i = 0; i < dump->ioa_dump.next_page_index; i++) - free_page((unsigned long) dump->ioa_dump.ioa_data[i]); - - vfree(dump->ioa_dump.ioa_data); - kfree(dump); - LEAVE; -} - -/** - * ipr_worker_thread - Worker thread - * @work: ioa config struct - * - * Called at task level from a work thread. This function takes care - * of adding and removing device from the mid-layer as configuration - * changes are detected by the adapter. - * - * Return value: - * nothing - **/ -static void ipr_worker_thread(struct work_struct *work) -{ - unsigned long lock_flags; - struct ipr_resource_entry *res; - struct scsi_device *sdev; - struct ipr_dump *dump; - struct ipr_ioa_cfg *ioa_cfg = - container_of(work, struct ipr_ioa_cfg, work_q); - u8 bus, target, lun; - int did_work; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - if (ioa_cfg->sdt_state == READ_DUMP) { - dump = ioa_cfg->dump; - if (!dump) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return; - } - kref_get(&dump->kref); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - ipr_get_ioa_dump(ioa_cfg, dump); - kref_put(&dump->kref, ipr_release_dump); - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - if (ioa_cfg->sdt_state == DUMP_OBTAINED && !ioa_cfg->dump_timeout) - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return; - } - -restart: - do { - did_work = 0; - if (!ioa_cfg->allow_cmds || !ioa_cfg->allow_ml_add_del) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return; - } - - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if (res->del_from_ml && res->sdev) { - did_work = 1; - sdev = res->sdev; - if (!scsi_device_get(sdev)) { - if (!res->add_to_ml) - list_move_tail(&res->queue, &ioa_cfg->free_res_q); - else - res->del_from_ml = 0; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - scsi_remove_device(sdev); - scsi_device_put(sdev); - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - } - break; - } - } - } while(did_work); - - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if (res->add_to_ml) { - bus = res->bus; - target = res->target; - lun = res->lun; - res->add_to_ml = 0; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - scsi_add_device(ioa_cfg->host, bus, target, lun); - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - goto restart; - } - } - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - kobject_uevent(&ioa_cfg->host->shost_dev.kobj, KOBJ_CHANGE); - LEAVE; -} - -#ifdef CONFIG_SCSI_IPR_TRACE -/** - * ipr_read_trace - Dump the adapter trace - * @filp: open sysfs file - * @kobj: kobject struct - * @bin_attr: bin_attribute struct - * @buf: buffer - * @off: offset - * @count: buffer size - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_read_trace(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - unsigned long lock_flags = 0; - ssize_t ret; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - ret = memory_read_from_buffer(buf, count, &off, ioa_cfg->trace, - IPR_TRACE_SIZE); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - return ret; -} - -static struct bin_attribute ipr_trace_attr = { - .attr = { - .name = "trace", - .mode = S_IRUGO, - }, - .size = 0, - .read = ipr_read_trace, -}; -#endif - -/** - * ipr_show_fw_version - Show the firmware version - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_show_fw_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; - unsigned long lock_flags = 0; - int len; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - len = snprintf(buf, PAGE_SIZE, "%02X%02X%02X%02X\n", - ucode_vpd->major_release, ucode_vpd->card_type, - ucode_vpd->minor_release[0], - ucode_vpd->minor_release[1]); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return len; -} - -static struct device_attribute ipr_fw_version_attr = { - .attr = { - .name = "fw_version", - .mode = S_IRUGO, - }, - .show = ipr_show_fw_version, -}; - -/** - * ipr_show_log_level - Show the adapter's error logging level - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_show_log_level(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - unsigned long lock_flags = 0; - int len; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->log_level); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return len; -} - -/** - * ipr_store_log_level - Change the adapter's error logging level - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_store_log_level(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - unsigned long lock_flags = 0; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - ioa_cfg->log_level = simple_strtoul(buf, NULL, 10); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return strlen(buf); -} - -static struct device_attribute ipr_log_level_attr = { - .attr = { - .name = "log_level", - .mode = S_IRUGO | S_IWUSR, - }, - .show = ipr_show_log_level, - .store = ipr_store_log_level -}; - -/** - * ipr_store_diagnostics - IOA Diagnostics interface - * @dev: device struct - * @buf: buffer - * @count: buffer size - * - * This function will reset the adapter and wait a reasonable - * amount of time for any errors that the adapter might log. - * - * Return value: - * count on success / other on failure - **/ -static ssize_t ipr_store_diagnostics(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - unsigned long lock_flags = 0; - int rc = count; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - while(ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - } - - ioa_cfg->errors_logged = 0; - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); - - if (ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - - /* Wait for a second for any errors to be logged */ - msleep(1000); - } else { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return -EIO; - } - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - if (ioa_cfg->in_reset_reload || ioa_cfg->errors_logged) - rc = -EIO; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - return rc; -} - -static struct device_attribute ipr_diagnostics_attr = { - .attr = { - .name = "run_diagnostics", - .mode = S_IWUSR, - }, - .store = ipr_store_diagnostics -}; - -/** - * ipr_show_adapter_state - Show the adapter's state - * @class_dev: device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_show_adapter_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - unsigned long lock_flags = 0; - int len; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - if (ioa_cfg->ioa_is_dead) - len = snprintf(buf, PAGE_SIZE, "offline\n"); - else - len = snprintf(buf, PAGE_SIZE, "online\n"); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return len; -} - -/** - * ipr_store_adapter_state - Change adapter state - * @dev: device struct - * @buf: buffer - * @count: buffer size - * - * This function will change the adapter's state. - * - * Return value: - * count on success / other on failure - **/ -static ssize_t ipr_store_adapter_state(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - unsigned long lock_flags; - int result = count; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - if (ioa_cfg->ioa_is_dead && !strncmp(buf, "online", 6)) { - ioa_cfg->ioa_is_dead = 0; - ioa_cfg->reset_retries = 0; - ioa_cfg->in_ioa_bringdown = 0; - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - - return result; -} - -static struct device_attribute ipr_ioa_state_attr = { - .attr = { - .name = "online_state", - .mode = S_IRUGO | S_IWUSR, - }, - .show = ipr_show_adapter_state, - .store = ipr_store_adapter_state -}; - -/** - * ipr_store_reset_adapter - Reset the adapter - * @dev: device struct - * @buf: buffer - * @count: buffer size - * - * This function will reset the adapter. - * - * Return value: - * count on success / other on failure - **/ -static ssize_t ipr_store_reset_adapter(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - unsigned long lock_flags; - int result = count; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - if (!ioa_cfg->in_reset_reload) - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - - return result; -} - -static struct device_attribute ipr_ioa_reset_attr = { - .attr = { - .name = "reset_host", - .mode = S_IWUSR, - }, - .store = ipr_store_reset_adapter -}; - -/** - * ipr_alloc_ucode_buffer - Allocates a microcode download buffer - * @buf_len: buffer length - * - * Allocates a DMA'able buffer in chunks and assembles a scatter/gather - * list to use for microcode download - * - * Return value: - * pointer to sglist / NULL on failure - **/ -static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len) -{ - int sg_size, order, bsize_elem, num_elem, i, j; - struct ipr_sglist *sglist; - struct scatterlist *scatterlist; - struct page *page; - - /* Get the minimum size per scatter/gather element */ - sg_size = buf_len / (IPR_MAX_SGLIST - 1); - - /* Get the actual size per element */ - order = get_order(sg_size); - - /* Determine the actual number of bytes per element */ - bsize_elem = PAGE_SIZE * (1 << order); - - /* Determine the actual number of sg entries needed */ - if (buf_len % bsize_elem) - num_elem = (buf_len / bsize_elem) + 1; - else - num_elem = buf_len / bsize_elem; - - /* Allocate a scatter/gather list for the DMA */ - sglist = kzalloc(sizeof(struct ipr_sglist) + - (sizeof(struct scatterlist) * (num_elem - 1)), - GFP_KERNEL); - - if (sglist == NULL) { - ipr_trace; - return NULL; - } - - scatterlist = sglist->scatterlist; - sg_init_table(scatterlist, num_elem); - - sglist->order = order; - sglist->num_sg = num_elem; - - /* Allocate a bunch of sg elements */ - for (i = 0; i < num_elem; i++) { - page = alloc_pages(GFP_KERNEL, order); - if (!page) { - ipr_trace; - - /* Free up what we already allocated */ - for (j = i - 1; j >= 0; j--) - __free_pages(sg_page(&scatterlist[j]), order); - kfree(sglist); - return NULL; - } - - sg_set_page(&scatterlist[i], page, 0, 0); - } - - return sglist; -} - -/** - * ipr_free_ucode_buffer - Frees a microcode download buffer - * @p_dnld: scatter/gather list pointer - * - * Free a DMA'able ucode download buffer previously allocated with - * ipr_alloc_ucode_buffer - * - * Return value: - * nothing - **/ -static void ipr_free_ucode_buffer(struct ipr_sglist *sglist) -{ - int i; - - for (i = 0; i < sglist->num_sg; i++) - __free_pages(sg_page(&sglist->scatterlist[i]), sglist->order); - - kfree(sglist); -} - -/** - * ipr_copy_ucode_buffer - Copy user buffer to kernel buffer - * @sglist: scatter/gather list pointer - * @buffer: buffer pointer - * @len: buffer length - * - * Copy a microcode image from a user buffer into a buffer allocated by - * ipr_alloc_ucode_buffer - * - * Return value: - * 0 on success / other on failure - **/ -static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist, - u8 *buffer, u32 len) -{ - int bsize_elem, i, result = 0; - struct scatterlist *scatterlist; - void *kaddr; - - /* Determine the actual number of bytes per element */ - bsize_elem = PAGE_SIZE * (1 << sglist->order); - - scatterlist = sglist->scatterlist; - - for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); - - kaddr = kmap(page); - memcpy(kaddr, buffer, bsize_elem); - kunmap(page); - - scatterlist[i].length = bsize_elem; - - if (result != 0) { - ipr_trace; - return result; - } - } - - if (len % bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); - - kaddr = kmap(page); - memcpy(kaddr, buffer, len % bsize_elem); - kunmap(page); - - scatterlist[i].length = len % bsize_elem; - } - - sglist->buffer_len = len; - return result; -} - -/** - * ipr_build_ucode_ioadl64 - Build a microcode download IOADL - * @ipr_cmd: ipr command struct - * @sglist: scatter/gather list - * - * Builds a microcode download IOA data list (IOADL). - * - **/ -static void ipr_build_ucode_ioadl64(struct ipr_cmnd *ipr_cmd, - struct ipr_sglist *sglist) -{ - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64; - struct scatterlist *scatterlist = sglist->scatterlist; - int i; - - ipr_cmd->dma_use_sg = sglist->num_dma_sg; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->data_transfer_length = cpu_to_be32(sglist->buffer_len); - - ioarcb->ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg); - for (i = 0; i < ipr_cmd->dma_use_sg; i++) { - ioadl64[i].flags = cpu_to_be32(IPR_IOADL_FLAGS_WRITE); - ioadl64[i].data_len = cpu_to_be32(sg_dma_len(&scatterlist[i])); - ioadl64[i].address = cpu_to_be64(sg_dma_address(&scatterlist[i])); - } - - ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); -} - -/** - * ipr_build_ucode_ioadl - Build a microcode download IOADL - * @ipr_cmd: ipr command struct - * @sglist: scatter/gather list - * - * Builds a microcode download IOA data list (IOADL). - * - **/ -static void ipr_build_ucode_ioadl(struct ipr_cmnd *ipr_cmd, - struct ipr_sglist *sglist) -{ - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl; - struct scatterlist *scatterlist = sglist->scatterlist; - int i; - - ipr_cmd->dma_use_sg = sglist->num_dma_sg; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->data_transfer_length = cpu_to_be32(sglist->buffer_len); - - ioarcb->ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - - for (i = 0; i < ipr_cmd->dma_use_sg; i++) { - ioadl[i].flags_and_data_len = - cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i])); - ioadl[i].address = - cpu_to_be32(sg_dma_address(&scatterlist[i])); - } - - ioadl[i-1].flags_and_data_len |= - cpu_to_be32(IPR_IOADL_FLAGS_LAST); -} - -/** - * ipr_update_ioa_ucode - Update IOA's microcode - * @ioa_cfg: ioa config struct - * @sglist: scatter/gather list - * - * Initiate an adapter reset to update the IOA's microcode - * - * Return value: - * 0 on success / -EIO on failure - **/ -static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_sglist *sglist) -{ - unsigned long lock_flags; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - while(ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - } - - if (ioa_cfg->ucode_sglist) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - dev_err(&ioa_cfg->pdev->dev, - "Microcode download already in progress\n"); - return -EIO; - } - - sglist->num_dma_sg = pci_map_sg(ioa_cfg->pdev, sglist->scatterlist, - sglist->num_sg, DMA_TO_DEVICE); - - if (!sglist->num_dma_sg) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - dev_err(&ioa_cfg->pdev->dev, - "Failed to map microcode download buffer!\n"); - return -EIO; - } - - ioa_cfg->ucode_sglist = sglist; - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - ioa_cfg->ucode_sglist = NULL; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return 0; -} - -/** - * ipr_store_update_fw - Update the firmware on the adapter - * @class_dev: device struct - * @buf: buffer - * @count: buffer size - * - * This function will update the firmware on the adapter. - * - * Return value: - * count on success / other on failure - **/ -static ssize_t ipr_store_update_fw(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - struct ipr_ucode_image_header *image_hdr; - const struct firmware *fw_entry; - struct ipr_sglist *sglist; - char fname[100]; - char *src; - int len, result, dnld_size; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - len = snprintf(fname, 99, "%s", buf); - fname[len-1] = '\0'; - - if(request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) { - dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname); - return -EIO; - } - - image_hdr = (struct ipr_ucode_image_header *)fw_entry->data; - - src = (u8 *)image_hdr + be32_to_cpu(image_hdr->header_length); - dnld_size = fw_entry->size - be32_to_cpu(image_hdr->header_length); - sglist = ipr_alloc_ucode_buffer(dnld_size); - - if (!sglist) { - dev_err(&ioa_cfg->pdev->dev, "Microcode buffer allocation failed\n"); - release_firmware(fw_entry); - return -ENOMEM; - } - - result = ipr_copy_ucode_buffer(sglist, src, dnld_size); - - if (result) { - dev_err(&ioa_cfg->pdev->dev, - "Microcode buffer copy to DMA buffer failed\n"); - goto out; - } - - ipr_info("Updating microcode, please be patient. This may take up to 30 minutes.\n"); - - result = ipr_update_ioa_ucode(ioa_cfg, sglist); - - if (!result) - result = count; -out: - ipr_free_ucode_buffer(sglist); - release_firmware(fw_entry); - return result; -} - -static struct device_attribute ipr_update_fw_attr = { - .attr = { - .name = "update_fw", - .mode = S_IWUSR, - }, - .store = ipr_store_update_fw -}; - -/** - * ipr_show_fw_type - Show the adapter's firmware type. - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_show_fw_type(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - unsigned long lock_flags = 0; - int len; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->sis64); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return len; -} - -static struct device_attribute ipr_ioa_fw_type_attr = { - .attr = { - .name = "fw_type", - .mode = S_IRUGO, - }, - .show = ipr_show_fw_type -}; - -static struct device_attribute *ipr_ioa_attrs[] = { - &ipr_fw_version_attr, - &ipr_log_level_attr, - &ipr_diagnostics_attr, - &ipr_ioa_state_attr, - &ipr_ioa_reset_attr, - &ipr_update_fw_attr, - &ipr_ioa_fw_type_attr, - NULL, -}; - -#ifdef CONFIG_SCSI_IPR_DUMP -/** - * ipr_read_dump - Dump the adapter - * @filp: open sysfs file - * @kobj: kobject struct - * @bin_attr: bin_attribute struct - * @buf: buffer - * @off: offset - * @count: buffer size - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_read_dump(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *cdev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(cdev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - struct ipr_dump *dump; - unsigned long lock_flags = 0; - char *src; - int len, sdt_end; - size_t rc = count; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - dump = ioa_cfg->dump; - - if (ioa_cfg->sdt_state != DUMP_OBTAINED || !dump) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return 0; - } - kref_get(&dump->kref); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - if (off > dump->driver_dump.hdr.len) { - kref_put(&dump->kref, ipr_release_dump); - return 0; - } - - if (off + count > dump->driver_dump.hdr.len) { - count = dump->driver_dump.hdr.len - off; - rc = count; - } - - if (count && off < sizeof(dump->driver_dump)) { - if (off + count > sizeof(dump->driver_dump)) - len = sizeof(dump->driver_dump) - off; - else - len = count; - src = (u8 *)&dump->driver_dump + off; - memcpy(buf, src, len); - buf += len; - off += len; - count -= len; - } - - off -= sizeof(dump->driver_dump); - - if (ioa_cfg->sis64) - sdt_end = offsetof(struct ipr_ioa_dump, sdt.entry) + - (be32_to_cpu(dump->ioa_dump.sdt.hdr.num_entries_used) * - sizeof(struct ipr_sdt_entry)); - else - sdt_end = offsetof(struct ipr_ioa_dump, sdt.entry) + - (IPR_FMT2_NUM_SDT_ENTRIES * sizeof(struct ipr_sdt_entry)); - - if (count && off < sdt_end) { - if (off + count > sdt_end) - len = sdt_end - off; - else - len = count; - src = (u8 *)&dump->ioa_dump + off; - memcpy(buf, src, len); - buf += len; - off += len; - count -= len; - } - - off -= sdt_end; - - while (count) { - if ((off & PAGE_MASK) != ((off + count) & PAGE_MASK)) - len = PAGE_ALIGN(off) - off; - else - len = count; - src = (u8 *)dump->ioa_dump.ioa_data[(off & PAGE_MASK) >> PAGE_SHIFT]; - src += off & ~PAGE_MASK; - memcpy(buf, src, len); - buf += len; - off += len; - count -= len; - } - - kref_put(&dump->kref, ipr_release_dump); - return rc; -} - -/** - * ipr_alloc_dump - Prepare for adapter dump - * @ioa_cfg: ioa config struct - * - * Return value: - * 0 on success / other on failure - **/ -static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg) -{ - struct ipr_dump *dump; - __be32 **ioa_data; - unsigned long lock_flags = 0; - - dump = kzalloc(sizeof(struct ipr_dump), GFP_KERNEL); - - if (!dump) { - ipr_err("Dump memory allocation failed\n"); - return -ENOMEM; - } - - if (ioa_cfg->sis64) - ioa_data = vmalloc(IPR_FMT3_MAX_NUM_DUMP_PAGES * sizeof(__be32 *)); - else - ioa_data = vmalloc(IPR_FMT2_MAX_NUM_DUMP_PAGES * sizeof(__be32 *)); - - if (!ioa_data) { - ipr_err("Dump memory allocation failed\n"); - kfree(dump); - return -ENOMEM; - } - - dump->ioa_dump.ioa_data = ioa_data; - - kref_init(&dump->kref); - dump->ioa_cfg = ioa_cfg; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - if (INACTIVE != ioa_cfg->sdt_state) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - vfree(dump->ioa_dump.ioa_data); - kfree(dump); - return 0; - } - - ioa_cfg->dump = dump; - ioa_cfg->sdt_state = WAIT_FOR_DUMP; - if (ioa_cfg->ioa_is_dead && !ioa_cfg->dump_taken) { - ioa_cfg->dump_taken = 1; - schedule_work(&ioa_cfg->work_q); - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - return 0; -} - -/** - * ipr_free_dump - Free adapter dump memory - * @ioa_cfg: ioa config struct - * - * Return value: - * 0 on success / other on failure - **/ -static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) -{ - struct ipr_dump *dump; - unsigned long lock_flags = 0; - - ENTER; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - dump = ioa_cfg->dump; - if (!dump) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return 0; - } - - ioa_cfg->dump = NULL; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - kref_put(&dump->kref, ipr_release_dump); - - LEAVE; - return 0; -} - -/** - * ipr_write_dump - Setup dump state of adapter - * @filp: open sysfs file - * @kobj: kobject struct - * @bin_attr: bin_attribute struct - * @buf: buffer - * @off: offset - * @count: buffer size - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_write_dump(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *cdev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(cdev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata; - int rc; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (buf[0] == '1') - rc = ipr_alloc_dump(ioa_cfg); - else if (buf[0] == '0') - rc = ipr_free_dump(ioa_cfg); - else - return -EINVAL; - - if (rc) - return rc; - else - return count; -} - -static struct bin_attribute ipr_dump_attr = { - .attr = { - .name = "dump", - .mode = S_IRUSR | S_IWUSR, - }, - .size = 0, - .read = ipr_read_dump, - .write = ipr_write_dump -}; -#else -static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; }; -#endif - -/** - * ipr_change_queue_depth - Change the device's queue depth - * @sdev: scsi device struct - * @qdepth: depth to set - * @reason: calling context - * - * Return value: - * actual depth set - **/ -static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) -{ - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *)sdev->hostdata; - - if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN) - qdepth = IPR_MAX_CMD_PER_ATA_LUN; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); - return sdev->queue_depth; -} - -/** - * ipr_change_queue_type - Change the device's queue type - * @dsev: scsi device struct - * @tag_type: type of tags to use - * - * Return value: - * actual queue type set - **/ -static int ipr_change_queue_type(struct scsi_device *sdev, int tag_type) -{ - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *)sdev->hostdata; - - if (res) { - if (ipr_is_gscsi(res) && sdev->tagged_supported) { - /* - * We don't bother quiescing the device here since the - * adapter firmware does it for us. - */ - scsi_set_tag_type(sdev, tag_type); - - if (tag_type) - scsi_activate_tcq(sdev, sdev->queue_depth); - else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - } else - tag_type = 0; - } else - tag_type = 0; - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return tag_type; -} - -/** - * ipr_show_adapter_handle - Show the adapter's resource handle for this device - * @dev: device struct - * @attr: device attribute structure - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_show_adapter_handle(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - ssize_t len = -ENXIO; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *)sdev->hostdata; - if (res) - len = snprintf(buf, PAGE_SIZE, "%08X\n", res->res_handle); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return len; -} - -static struct device_attribute ipr_adapter_handle_attr = { - .attr = { - .name = "adapter_handle", - .mode = S_IRUSR, - }, - .show = ipr_show_adapter_handle -}; - -/** - * ipr_show_resource_path - Show the resource path or the resource address for - * this device. - * @dev: device struct - * @attr: device attribute structure - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_show_resource_path(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - ssize_t len = -ENXIO; - char buffer[IPR_MAX_RES_PATH_LENGTH]; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *)sdev->hostdata; - if (res && ioa_cfg->sis64) - len = snprintf(buf, PAGE_SIZE, "%s\n", - ipr_format_res_path(res->res_path, buffer, - sizeof(buffer))); - else if (res) - len = snprintf(buf, PAGE_SIZE, "%d:%d:%d:%d\n", ioa_cfg->host->host_no, - res->bus, res->target, res->lun); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return len; -} - -static struct device_attribute ipr_resource_path_attr = { - .attr = { - .name = "resource_path", - .mode = S_IRUGO, - }, - .show = ipr_show_resource_path -}; - -/** - * ipr_show_device_id - Show the device_id for this device. - * @dev: device struct - * @attr: device attribute structure - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_show_device_id(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - ssize_t len = -ENXIO; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *)sdev->hostdata; - if (res && ioa_cfg->sis64) - len = snprintf(buf, PAGE_SIZE, "0x%llx\n", res->dev_id); - else if (res) - len = snprintf(buf, PAGE_SIZE, "0x%llx\n", res->lun_wwn); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return len; -} - -static struct device_attribute ipr_device_id_attr = { - .attr = { - .name = "device_id", - .mode = S_IRUGO, - }, - .show = ipr_show_device_id -}; - -/** - * ipr_show_resource_type - Show the resource type for this device. - * @dev: device struct - * @attr: device attribute structure - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - **/ -static ssize_t ipr_show_resource_type(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - ssize_t len = -ENXIO; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *)sdev->hostdata; - - if (res) - len = snprintf(buf, PAGE_SIZE, "%x\n", res->type); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return len; -} - -static struct device_attribute ipr_resource_type_attr = { - .attr = { - .name = "resource_type", - .mode = S_IRUGO, - }, - .show = ipr_show_resource_type -}; - -static struct device_attribute *ipr_dev_attrs[] = { - &ipr_adapter_handle_attr, - &ipr_resource_path_attr, - &ipr_device_id_attr, - &ipr_resource_type_attr, - NULL, -}; - -/** - * ipr_biosparam - Return the HSC mapping - * @sdev: scsi device struct - * @block_device: block device pointer - * @capacity: capacity of the device - * @parm: Array containing returned HSC values. - * - * This function generates the HSC parms that fdisk uses. - * We want to make sure we return something that places partitions - * on 4k boundaries for best performance with the IOA. - * - * Return value: - * 0 on success - **/ -static int ipr_biosparam(struct scsi_device *sdev, - struct block_device *block_device, - sector_t capacity, int *parm) -{ - int heads, sectors; - sector_t cylinders; - - heads = 128; - sectors = 32; - - cylinders = capacity; - sector_div(cylinders, (128 * 32)); - - /* return result */ - parm[0] = heads; - parm[1] = sectors; - parm[2] = cylinders; - - return 0; -} - -/** - * ipr_find_starget - Find target based on bus/target. - * @starget: scsi target struct - * - * Return value: - * resource entry pointer if found / NULL if not found - **/ -static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; - struct ipr_resource_entry *res; - - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if ((res->bus == starget->channel) && - (res->target == starget->id)) { - return res; - } - } - - return NULL; -} - -static struct ata_port_info sata_port_info; - -/** - * ipr_target_alloc - Prepare for commands to a SCSI target - * @starget: scsi target struct - * - * If the device is a SATA device, this function allocates an - * ATA port with libata, else it does nothing. - * - * Return value: - * 0 on success / non-0 on failure - **/ -static int ipr_target_alloc(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; - struct ipr_sata_port *sata_port; - struct ata_port *ap; - struct ipr_resource_entry *res; - unsigned long lock_flags; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = ipr_find_starget(starget); - starget->hostdata = NULL; - - if (res && ipr_is_gata(res)) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL); - if (!sata_port) - return -ENOMEM; - - ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost); - if (ap) { - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - sata_port->ioa_cfg = ioa_cfg; - sata_port->ap = ap; - sata_port->res = res; - - res->sata_port = sata_port; - ap->private_data = sata_port; - starget->hostdata = sata_port; - } else { - kfree(sata_port); - return -ENOMEM; - } - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - return 0; -} - -/** - * ipr_target_destroy - Destroy a SCSI target - * @starget: scsi target struct - * - * If the device was a SATA device, this function frees the libata - * ATA port, else it does nothing. - * - **/ -static void ipr_target_destroy(struct scsi_target *starget) -{ - struct ipr_sata_port *sata_port = starget->hostdata; - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata; - - if (ioa_cfg->sis64) { - if (!ipr_find_starget(starget)) { - if (starget->channel == IPR_ARRAY_VIRTUAL_BUS) - clear_bit(starget->id, ioa_cfg->array_ids); - else if (starget->channel == IPR_VSET_VIRTUAL_BUS) - clear_bit(starget->id, ioa_cfg->vset_ids); - else if (starget->channel == 0) - clear_bit(starget->id, ioa_cfg->target_ids); - } - } - - if (sata_port) { - starget->hostdata = NULL; - ata_sas_port_destroy(sata_port->ap); - kfree(sata_port); - } -} - -/** - * ipr_find_sdev - Find device based on bus/target/lun. - * @sdev: scsi device struct - * - * Return value: - * resource entry pointer if found / NULL if not found - **/ -static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev) -{ - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; - struct ipr_resource_entry *res; - - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if ((res->bus == sdev->channel) && - (res->target == sdev->id) && - (res->lun == sdev->lun)) - return res; - } - - return NULL; -} - -/** - * ipr_slave_destroy - Unconfigure a SCSI device - * @sdev: scsi device struct - * - * Return value: - * nothing - **/ -static void ipr_slave_destroy(struct scsi_device *sdev) -{ - struct ipr_resource_entry *res; - struct ipr_ioa_cfg *ioa_cfg; - unsigned long lock_flags = 0; - - ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = (struct ipr_resource_entry *) sdev->hostdata; - if (res) { - if (res->sata_port) - res->sata_port->ap->link.device[0].class = ATA_DEV_NONE; - sdev->hostdata = NULL; - res->sdev = NULL; - res->sata_port = NULL; - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); -} - -/** - * ipr_slave_configure - Configure a SCSI device - * @sdev: scsi device struct - * - * This function configures the specified scsi device. - * - * Return value: - * 0 on success - **/ -static int ipr_slave_configure(struct scsi_device *sdev) -{ - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; - struct ipr_resource_entry *res; - struct ata_port *ap = NULL; - unsigned long lock_flags = 0; - char buffer[IPR_MAX_RES_PATH_LENGTH]; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - res = sdev->hostdata; - if (res) { - if (ipr_is_af_dasd_device(res)) - sdev->type = TYPE_RAID; - if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res)) { - sdev->scsi_level = 4; - sdev->no_uld_attach = 1; - } - if (ipr_is_vset_device(res)) { - blk_queue_rq_timeout(sdev->request_queue, - IPR_VSET_RW_TIMEOUT); - blk_queue_max_hw_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS); - } - if (ipr_is_gata(res) && res->sata_port) - ap = res->sata_port->ap; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - if (ap) { - scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN); - ata_sas_slave_configure(sdev, ap); - } else - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); - if (ioa_cfg->sis64) - sdev_printk(KERN_INFO, sdev, "Resource path: %s\n", - ipr_format_res_path(res->res_path, buffer, - sizeof(buffer))); - return 0; - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return 0; -} - -/** - * ipr_ata_slave_alloc - Prepare for commands to a SATA device - * @sdev: scsi device struct - * - * This function initializes an ATA port so that future commands - * sent through queuecommand will work. - * - * Return value: - * 0 on success - **/ -static int ipr_ata_slave_alloc(struct scsi_device *sdev) -{ - struct ipr_sata_port *sata_port = NULL; - int rc = -ENXIO; - - ENTER; - if (sdev->sdev_target) - sata_port = sdev->sdev_target->hostdata; - if (sata_port) { - rc = ata_sas_port_init(sata_port->ap); - if (rc == 0) - rc = ata_sas_sync_probe(sata_port->ap); - } - - if (rc) - ipr_slave_destroy(sdev); - - LEAVE; - return rc; -} - -/** - * ipr_slave_alloc - Prepare for commands to a device. - * @sdev: scsi device struct - * - * This function saves a pointer to the resource entry - * in the scsi device struct if the device exists. We - * can then use this pointer in ipr_queuecommand when - * handling new commands. - * - * Return value: - * 0 on success / -ENXIO if device does not exist - **/ -static int ipr_slave_alloc(struct scsi_device *sdev) -{ - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata; - struct ipr_resource_entry *res; - unsigned long lock_flags; - int rc = -ENXIO; - - sdev->hostdata = NULL; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - res = ipr_find_sdev(sdev); - if (res) { - res->sdev = sdev; - res->add_to_ml = 0; - res->in_erp = 0; - sdev->hostdata = res; - if (!ipr_is_naca_model(res)) - res->needs_sync_complete = 1; - rc = 0; - if (ipr_is_gata(res)) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return ipr_ata_slave_alloc(sdev); - } - } - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - return rc; -} - -/** - * ipr_eh_host_reset - Reset the host adapter - * @scsi_cmd: scsi command struct - * - * Return value: - * SUCCESS / FAILED - **/ -static int __ipr_eh_host_reset(struct scsi_cmnd * scsi_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg; - int rc; - - ENTER; - ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; - - if (!ioa_cfg->in_reset_reload) { - dev_err(&ioa_cfg->pdev->dev, - "Adapter being reset as a result of error recovery.\n"); - - if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) - ioa_cfg->sdt_state = GET_DUMP; - } - - rc = ipr_reset_reload(ioa_cfg, IPR_SHUTDOWN_ABBREV); - - LEAVE; - return rc; -} - -static int ipr_eh_host_reset(struct scsi_cmnd * cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __ipr_eh_host_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - -/** - * ipr_device_reset - Reset the device - * @ioa_cfg: ioa config struct - * @res: resource entry struct - * - * This function issues a device reset to the affected device. - * If the device is a SCSI device, a LUN reset will be sent - * to the device first. If that does not work, a target reset - * will be sent. If the device is a SATA device, a PHY reset will - * be sent. - * - * Return value: - * 0 on success / non-zero on failure - **/ -static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_resource_entry *res) -{ - struct ipr_cmnd *ipr_cmd; - struct ipr_ioarcb *ioarcb; - struct ipr_cmd_pkt *cmd_pkt; - struct ipr_ioarcb_ata_regs *regs; - u32 ioasc; - - ENTER; - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - ioarcb = &ipr_cmd->ioarcb; - cmd_pkt = &ioarcb->cmd_pkt; - - if (ipr_cmd->ioa_cfg->sis64) { - regs = &ipr_cmd->i.ata_ioadl.regs; - ioarcb->add_cmd_parms_offset = cpu_to_be16(sizeof(*ioarcb)); - } else - regs = &ioarcb->u.add_data.u.regs; - - ioarcb->res_handle = res->res_handle; - cmd_pkt->request_type = IPR_RQTYPE_IOACMD; - cmd_pkt->cdb[0] = IPR_RESET_DEVICE; - if (ipr_is_gata(res)) { - cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET; - ioarcb->add_cmd_parms_len = cpu_to_be16(sizeof(regs->flags)); - regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; - } - - ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); - ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET) { - if (ipr_cmd->ioa_cfg->sis64) - memcpy(&res->sata_port->ioasa, &ipr_cmd->s.ioasa64.u.gata, - sizeof(struct ipr_ioasa_gata)); - else - memcpy(&res->sata_port->ioasa, &ipr_cmd->s.ioasa.u.gata, - sizeof(struct ipr_ioasa_gata)); - } - - LEAVE; - return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0); -} - -/** - * ipr_sata_reset - Reset the SATA port - * @link: SATA link to reset - * @classes: class of the attached device - * - * This function issues a SATA phy reset to the affected ATA link. - * - * Return value: - * 0 on success / non-zero on failure - **/ -static int ipr_sata_reset(struct ata_link *link, unsigned int *classes, - unsigned long deadline) -{ - struct ipr_sata_port *sata_port = link->ap->private_data; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - struct ipr_resource_entry *res; - unsigned long lock_flags = 0; - int rc = -ENXIO; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - while(ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - } - - res = sata_port->res; - if (res) { - rc = ipr_device_reset(ioa_cfg, res); - *classes = res->ata_class; - } - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - LEAVE; - return rc; -} - -/** - * ipr_eh_dev_reset - Reset the device - * @scsi_cmd: scsi command struct - * - * This function issues a device reset to the affected device. - * A LUN reset will be sent to the device first. If that does - * not work, a target reset will be sent. - * - * Return value: - * SUCCESS / FAILED - **/ -static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) -{ - struct ipr_cmnd *ipr_cmd; - struct ipr_ioa_cfg *ioa_cfg; - struct ipr_resource_entry *res; - struct ata_port *ap; - int rc = 0; - - ENTER; - ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata; - res = scsi_cmd->device->hostdata; - - if (!res) - return FAILED; - - /* - * If we are currently going through reset/reload, return failed. This will force the - * mid-layer to call ipr_eh_host_reset, which will then go to sleep and wait for the - * reset to complete - */ - if (ioa_cfg->in_reset_reload) - return FAILED; - if (ioa_cfg->ioa_is_dead) - return FAILED; - - list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { - if (ipr_cmd->ioarcb.res_handle == res->res_handle) { - if (ipr_cmd->scsi_cmd) - ipr_cmd->done = ipr_scsi_eh_done; - if (ipr_cmd->qc) - ipr_cmd->done = ipr_sata_eh_done; - if (ipr_cmd->qc && !(ipr_cmd->qc->flags & ATA_QCFLAG_FAILED)) { - ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT; - ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED; - } - } - } - - res->resetting_device = 1; - scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n"); - - if (ipr_is_gata(res) && res->sata_port) { - ap = res->sata_port->ap; - spin_unlock_irq(scsi_cmd->device->host->host_lock); - ata_std_error_handler(ap); - spin_lock_irq(scsi_cmd->device->host->host_lock); - - list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { - if (ipr_cmd->ioarcb.res_handle == res->res_handle) { - rc = -EIO; - break; - } - } - } else - rc = ipr_device_reset(ioa_cfg, res); - res->resetting_device = 0; - - LEAVE; - return (rc ? FAILED : SUCCESS); -} - -static int ipr_eh_dev_reset(struct scsi_cmnd * cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = __ipr_eh_dev_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - -/** - * ipr_bus_reset_done - Op done function for bus reset. - * @ipr_cmd: ipr command struct - * - * This function is the op done function for a bus reset - * - * Return value: - * none - **/ -static void ipr_bus_reset_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_resource_entry *res; - - ENTER; - if (!ioa_cfg->sis64) - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if (res->res_handle == ipr_cmd->ioarcb.res_handle) { - scsi_report_bus_reset(ioa_cfg->host, res->bus); - break; - } - } - - /* - * If abort has not completed, indicate the reset has, else call the - * abort's done function to wake the sleeping eh thread - */ - if (ipr_cmd->sibling->sibling) - ipr_cmd->sibling->sibling = NULL; - else - ipr_cmd->sibling->done(ipr_cmd->sibling); - - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - LEAVE; -} - -/** - * ipr_abort_timeout - An abort task has timed out - * @ipr_cmd: ipr command struct - * - * This function handles when an abort task times out. If this - * happens we issue a bus reset since we have resources tied - * up that must be freed before returning to the midlayer. - * - * Return value: - * none - **/ -static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_cmnd *reset_cmd; - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_cmd_pkt *cmd_pkt; - unsigned long lock_flags = 0; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - if (ipr_cmd->completion.done || ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return; - } - - sdev_printk(KERN_ERR, ipr_cmd->u.sdev, "Abort timed out. Resetting bus.\n"); - reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - ipr_cmd->sibling = reset_cmd; - reset_cmd->sibling = ipr_cmd; - reset_cmd->ioarcb.res_handle = ipr_cmd->ioarcb.res_handle; - cmd_pkt = &reset_cmd->ioarcb.cmd_pkt; - cmd_pkt->request_type = IPR_RQTYPE_IOACMD; - cmd_pkt->cdb[0] = IPR_RESET_DEVICE; - cmd_pkt->cdb[2] = IPR_RESET_TYPE_SELECT | IPR_BUS_RESET; - - ipr_do_req(reset_cmd, ipr_bus_reset_done, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - LEAVE; -} - -/** - * ipr_cancel_op - Cancel specified op - * @scsi_cmd: scsi command struct - * - * This function cancels specified op. - * - * Return value: - * SUCCESS / FAILED - **/ -static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd) -{ - struct ipr_cmnd *ipr_cmd; - struct ipr_ioa_cfg *ioa_cfg; - struct ipr_resource_entry *res; - struct ipr_cmd_pkt *cmd_pkt; - u32 ioasc, int_reg; - int op_found = 0; - - ENTER; - ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata; - res = scsi_cmd->device->hostdata; - - /* If we are currently going through reset/reload, return failed. - * This will force the mid-layer to call ipr_eh_host_reset, - * which will then go to sleep and wait for the reset to complete - */ - if (ioa_cfg->in_reset_reload || ioa_cfg->ioa_is_dead) - return FAILED; - if (!res) - return FAILED; - - /* - * If we are aborting a timed out op, chances are that the timeout was caused - * by a still not detected EEH error. In such cases, reading a register will - * trigger the EEH recovery infrastructure. - */ - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); - - if (!ipr_is_gscsi(res)) - return FAILED; - - list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { - if (ipr_cmd->scsi_cmd == scsi_cmd) { - ipr_cmd->done = ipr_scsi_eh_done; - op_found = 1; - break; - } - } - - if (!op_found) - return SUCCESS; - - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - ipr_cmd->ioarcb.res_handle = res->res_handle; - cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; - cmd_pkt->request_type = IPR_RQTYPE_IOACMD; - cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; - ipr_cmd->u.sdev = scsi_cmd->device; - - scmd_printk(KERN_ERR, scsi_cmd, "Aborting command: %02X\n", - scsi_cmd->cmnd[0]); - ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT); - ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - /* - * If the abort task timed out and we sent a bus reset, we will get - * one the following responses to the abort - */ - if (ioasc == IPR_IOASC_BUS_WAS_RESET || ioasc == IPR_IOASC_SYNC_REQUIRED) { - ioasc = 0; - ipr_trace; - } - - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - if (!ipr_is_naca_model(res)) - res->needs_sync_complete = 1; - - LEAVE; - return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS); -} - -/** - * ipr_eh_abort - Abort a single op - * @scsi_cmd: scsi command struct - * - * Return value: - * SUCCESS / FAILED - **/ -static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd) -{ - unsigned long flags; - int rc; - - ENTER; - - spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags); - rc = ipr_cancel_op(scsi_cmd); - spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags); - - LEAVE; - return rc; -} - -/** - * ipr_handle_other_interrupt - Handle "other" interrupts - * @ioa_cfg: ioa config struct - * @int_reg: interrupt register - * - * Return value: - * IRQ_NONE / IRQ_HANDLED - **/ -static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg, - u32 int_reg) -{ - irqreturn_t rc = IRQ_HANDLED; - u32 int_mask_reg; - - int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg32); - int_reg &= ~int_mask_reg; - - /* If an interrupt on the adapter did not occur, ignore it. - * Or in the case of SIS 64, check for a stage change interrupt. - */ - if ((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0) { - if (ioa_cfg->sis64) { - int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; - if (int_reg & IPR_PCII_IPL_STAGE_CHANGE) { - - /* clear stage change */ - writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.clr_interrupt_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg; - list_del(&ioa_cfg->reset_cmd->queue); - del_timer(&ioa_cfg->reset_cmd->timer); - ipr_reset_ioa_job(ioa_cfg->reset_cmd); - return IRQ_HANDLED; - } - } - - return IRQ_NONE; - } - - if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { - /* Mask the interrupt */ - writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.set_interrupt_mask_reg); - - /* Clear the interrupt */ - writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.clr_interrupt_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); - - list_del(&ioa_cfg->reset_cmd->queue); - del_timer(&ioa_cfg->reset_cmd->timer); - ipr_reset_ioa_job(ioa_cfg->reset_cmd); - } else if ((int_reg & IPR_PCII_HRRQ_UPDATED) == int_reg) { - if (ioa_cfg->clear_isr) { - if (ipr_debug && printk_ratelimit()) - dev_err(&ioa_cfg->pdev->dev, - "Spurious interrupt detected. 0x%08X\n", int_reg); - writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); - return IRQ_NONE; - } - } else { - if (int_reg & IPR_PCII_IOA_UNIT_CHECKED) - ioa_cfg->ioa_unit_checked = 1; - else - dev_err(&ioa_cfg->pdev->dev, - "Permanent IOA failure. 0x%08X\n", int_reg); - - if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) - ioa_cfg->sdt_state = GET_DUMP; - - ipr_mask_and_clear_interrupts(ioa_cfg, ~0); - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - } - - return rc; -} - -/** - * ipr_isr_eh - Interrupt service routine error handler - * @ioa_cfg: ioa config struct - * @msg: message to log - * - * Return value: - * none - **/ -static void ipr_isr_eh(struct ipr_ioa_cfg *ioa_cfg, char *msg) -{ - ioa_cfg->errors_logged++; - dev_err(&ioa_cfg->pdev->dev, "%s\n", msg); - - if (WAIT_FOR_DUMP == ioa_cfg->sdt_state) - ioa_cfg->sdt_state = GET_DUMP; - - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); -} - -/** - * ipr_isr - Interrupt service routine - * @irq: irq number - * @devp: pointer to ioa config struct - * - * Return value: - * IRQ_NONE / IRQ_HANDLED - **/ -static irqreturn_t ipr_isr(int irq, void *devp) -{ - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; - unsigned long lock_flags = 0; - u32 int_reg = 0; - u32 ioasc; - u16 cmd_index; - int num_hrrq = 0; - int irq_none = 0; - struct ipr_cmnd *ipr_cmd; - irqreturn_t rc = IRQ_NONE; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - /* If interrupts are disabled, ignore the interrupt */ - if (!ioa_cfg->allow_interrupts) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return IRQ_NONE; - } - - while (1) { - ipr_cmd = NULL; - - while ((be32_to_cpu(*ioa_cfg->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) == - ioa_cfg->toggle_bit) { - - cmd_index = (be32_to_cpu(*ioa_cfg->hrrq_curr) & - IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT; - - if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) { - ipr_isr_eh(ioa_cfg, "Invalid response handle from IOA"); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return IRQ_HANDLED; - } - - ipr_cmd = ioa_cfg->ipr_cmnd_list[cmd_index]; - - ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, ioasc); - - list_del(&ipr_cmd->queue); - del_timer(&ipr_cmd->timer); - ipr_cmd->done(ipr_cmd); - - rc = IRQ_HANDLED; - - if (ioa_cfg->hrrq_curr < ioa_cfg->hrrq_end) { - ioa_cfg->hrrq_curr++; - } else { - ioa_cfg->hrrq_curr = ioa_cfg->hrrq_start; - ioa_cfg->toggle_bit ^= 1u; - } - } - - if (ipr_cmd && !ioa_cfg->clear_isr) - break; - - if (ipr_cmd != NULL) { - /* Clear the PCI interrupt */ - num_hrrq = 0; - do { - writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); - } while (int_reg & IPR_PCII_HRRQ_UPDATED && - num_hrrq++ < IPR_MAX_HRRQ_RETRIES); - - } else if (rc == IRQ_NONE && irq_none == 0) { - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); - irq_none++; - } else if (num_hrrq == IPR_MAX_HRRQ_RETRIES && - int_reg & IPR_PCII_HRRQ_UPDATED) { - ipr_isr_eh(ioa_cfg, "Error clearing HRRQ"); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return IRQ_HANDLED; - } else - break; - } - - if (unlikely(rc == IRQ_NONE)) - rc = ipr_handle_other_interrupt(ioa_cfg, int_reg); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return rc; -} - -/** - * ipr_build_ioadl64 - Build a scatter/gather list and map the buffer - * @ioa_cfg: ioa config struct - * @ipr_cmd: ipr command struct - * - * Return value: - * 0 on success / -1 on failure - **/ -static int ipr_build_ioadl64(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_cmnd *ipr_cmd) -{ - int i, nseg; - struct scatterlist *sg; - u32 length; - u32 ioadl_flags = 0; - struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64; - - length = scsi_bufflen(scsi_cmd); - if (!length) - return 0; - - nseg = scsi_dma_map(scsi_cmd); - if (nseg < 0) { - if (printk_ratelimit()) - dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); - return -1; - } - - ipr_cmd->dma_use_sg = nseg; - - ioarcb->data_transfer_length = cpu_to_be32(length); - ioarcb->ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg); - - if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_WRITE; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) - ioadl_flags = IPR_IOADL_FLAGS_READ; - - scsi_for_each_sg(scsi_cmd, sg, ipr_cmd->dma_use_sg, i) { - ioadl64[i].flags = cpu_to_be32(ioadl_flags); - ioadl64[i].data_len = cpu_to_be32(sg_dma_len(sg)); - ioadl64[i].address = cpu_to_be64(sg_dma_address(sg)); - } - - ioadl64[i-1].flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); - return 0; -} - -/** - * ipr_build_ioadl - Build a scatter/gather list and map the buffer - * @ioa_cfg: ioa config struct - * @ipr_cmd: ipr command struct - * - * Return value: - * 0 on success / -1 on failure - **/ -static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_cmnd *ipr_cmd) -{ - int i, nseg; - struct scatterlist *sg; - u32 length; - u32 ioadl_flags = 0; - struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl; - - length = scsi_bufflen(scsi_cmd); - if (!length) - return 0; - - nseg = scsi_dma_map(scsi_cmd); - if (nseg < 0) { - dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n"); - return -1; - } - - ipr_cmd->dma_use_sg = nseg; - - if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_WRITE; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->data_transfer_length = cpu_to_be32(length); - ioarcb->ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - } else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_READ; - ioarcb->read_data_transfer_length = cpu_to_be32(length); - ioarcb->read_ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - } - - if (ipr_cmd->dma_use_sg <= ARRAY_SIZE(ioarcb->u.add_data.u.ioadl)) { - ioadl = ioarcb->u.add_data.u.ioadl; - ioarcb->write_ioadl_addr = cpu_to_be32((ipr_cmd->dma_addr) + - offsetof(struct ipr_ioarcb, u.add_data)); - ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; - } - - scsi_for_each_sg(scsi_cmd, sg, ipr_cmd->dma_use_sg, i) { - ioadl[i].flags_and_data_len = - cpu_to_be32(ioadl_flags | sg_dma_len(sg)); - ioadl[i].address = cpu_to_be32(sg_dma_address(sg)); - } - - ioadl[i-1].flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); - return 0; -} - -/** - * ipr_get_task_attributes - Translate SPI Q-Tag to task attributes - * @scsi_cmd: scsi command struct - * - * Return value: - * task attributes - **/ -static u8 ipr_get_task_attributes(struct scsi_cmnd *scsi_cmd) -{ - u8 tag[2]; - u8 rc = IPR_FLAGS_LO_UNTAGGED_TASK; - - if (scsi_populate_tag_msg(scsi_cmd, tag)) { - switch (tag[0]) { - case MSG_SIMPLE_TAG: - rc = IPR_FLAGS_LO_SIMPLE_TASK; - break; - case MSG_HEAD_TAG: - rc = IPR_FLAGS_LO_HEAD_OF_Q_TASK; - break; - case MSG_ORDERED_TAG: - rc = IPR_FLAGS_LO_ORDERED_TASK; - break; - }; - } - - return rc; -} - -/** - * ipr_erp_done - Process completion of ERP for a device - * @ipr_cmd: ipr command struct - * - * This function copies the sense buffer into the scsi_cmd - * struct and pushes the scsi_done function. - * - * Return value: - * nothing - **/ -static void ipr_erp_done(struct ipr_cmnd *ipr_cmd) -{ - struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; - struct ipr_resource_entry *res = scsi_cmd->device->hostdata; - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { - scsi_cmd->result |= (DID_ERROR << 16); - scmd_printk(KERN_ERR, scsi_cmd, - "Request Sense failed with IOASC: 0x%08X\n", ioasc); - } else { - memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE); - } - - if (res) { - if (!ipr_is_naca_model(res)) - res->needs_sync_complete = 1; - res->in_erp = 0; - } - scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - scsi_cmd->scsi_done(scsi_cmd); -} - -/** - * ipr_reinit_ipr_cmnd_for_erp - Re-initialize a cmnd block to be used for ERP - * @ipr_cmd: ipr command struct - * - * Return value: - * none - **/ -static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa; - dma_addr_t dma_addr = ipr_cmd->dma_addr; - - memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt)); - ioarcb->data_transfer_length = 0; - ioarcb->read_data_transfer_length = 0; - ioarcb->ioadl_len = 0; - ioarcb->read_ioadl_len = 0; - ioasa->hdr.ioasc = 0; - ioasa->hdr.residual_data_len = 0; - - if (ipr_cmd->ioa_cfg->sis64) - ioarcb->u.sis64_addr_data.data_ioadl_addr = - cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64)); - else { - ioarcb->write_ioadl_addr = - cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl)); - ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; - } -} - -/** - * ipr_erp_request_sense - Send request sense to a device - * @ipr_cmd: ipr command struct - * - * This function sends a request sense to a device as a result - * of a check condition. - * - * Return value: - * nothing - **/ -static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - if (IPR_IOASC_SENSE_KEY(ioasc) > 0) { - ipr_erp_done(ipr_cmd); - return; - } - - ipr_reinit_ipr_cmnd_for_erp(ipr_cmd); - - cmd_pkt->request_type = IPR_RQTYPE_SCSICDB; - cmd_pkt->cdb[0] = REQUEST_SENSE; - cmd_pkt->cdb[4] = SCSI_SENSE_BUFFERSIZE; - cmd_pkt->flags_hi |= IPR_FLAGS_HI_SYNC_OVERRIDE; - cmd_pkt->flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; - cmd_pkt->timeout = cpu_to_be16(IPR_REQUEST_SENSE_TIMEOUT / HZ); - - ipr_init_ioadl(ipr_cmd, ipr_cmd->sense_buffer_dma, - SCSI_SENSE_BUFFERSIZE, IPR_IOADL_FLAGS_READ_LAST); - - ipr_do_req(ipr_cmd, ipr_erp_done, ipr_timeout, - IPR_REQUEST_SENSE_TIMEOUT * 2); -} - -/** - * ipr_erp_cancel_all - Send cancel all to a device - * @ipr_cmd: ipr command struct - * - * This function sends a cancel all to a device to clear the - * queue. If we are running TCQ on the device, QERR is set to 1, - * which means all outstanding ops have been dropped on the floor. - * Cancel all will return them to us. - * - * Return value: - * nothing - **/ -static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd) -{ - struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; - struct ipr_resource_entry *res = scsi_cmd->device->hostdata; - struct ipr_cmd_pkt *cmd_pkt; - - res->in_erp = 1; - - ipr_reinit_ipr_cmnd_for_erp(ipr_cmd); - - if (!scsi_get_tag_type(scsi_cmd->device)) { - ipr_erp_request_sense(ipr_cmd); - return; - } - - cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt; - cmd_pkt->request_type = IPR_RQTYPE_IOACMD; - cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS; - - ipr_do_req(ipr_cmd, ipr_erp_request_sense, ipr_timeout, - IPR_CANCEL_ALL_TIMEOUT); -} - -/** - * ipr_dump_ioasa - Dump contents of IOASA - * @ioa_cfg: ioa config struct - * @ipr_cmd: ipr command struct - * @res: resource entry struct - * - * This function is invoked by the interrupt handler when ops - * fail. It will log the IOASA if appropriate. Only called - * for GPDD ops. - * - * Return value: - * none - **/ -static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_cmnd *ipr_cmd, struct ipr_resource_entry *res) -{ - int i; - u16 data_len; - u32 ioasc, fd_ioasc; - struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa; - __be32 *ioasa_data = (__be32 *)ioasa; - int error_index; - - ioasc = be32_to_cpu(ioasa->hdr.ioasc) & IPR_IOASC_IOASC_MASK; - fd_ioasc = be32_to_cpu(ioasa->hdr.fd_ioasc) & IPR_IOASC_IOASC_MASK; - - if (0 == ioasc) - return; - - if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL) - return; - - if (ioasc == IPR_IOASC_BUS_WAS_RESET && fd_ioasc) - error_index = ipr_get_error(fd_ioasc); - else - error_index = ipr_get_error(ioasc); - - if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) { - /* Don't log an error if the IOA already logged one */ - if (ioasa->hdr.ilid != 0) - return; - - if (!ipr_is_gscsi(res)) - return; - - if (ipr_error_table[error_index].log_ioasa == 0) - return; - } - - ipr_res_err(ioa_cfg, res, "%s\n", ipr_error_table[error_index].error); - - data_len = be16_to_cpu(ioasa->hdr.ret_stat_len); - if (ioa_cfg->sis64 && sizeof(struct ipr_ioasa64) < data_len) - data_len = sizeof(struct ipr_ioasa64); - else if (!ioa_cfg->sis64 && sizeof(struct ipr_ioasa) < data_len) - data_len = sizeof(struct ipr_ioasa); - - ipr_err("IOASA Dump:\n"); - - for (i = 0; i < data_len / 4; i += 4) { - ipr_err("%08X: %08X %08X %08X %08X\n", i*4, - be32_to_cpu(ioasa_data[i]), - be32_to_cpu(ioasa_data[i+1]), - be32_to_cpu(ioasa_data[i+2]), - be32_to_cpu(ioasa_data[i+3])); - } -} - -/** - * ipr_gen_sense - Generate SCSI sense data from an IOASA - * @ioasa: IOASA - * @sense_buf: sense data buffer - * - * Return value: - * none - **/ -static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd) -{ - u32 failing_lba; - u8 *sense_buf = ipr_cmd->scsi_cmd->sense_buffer; - struct ipr_resource_entry *res = ipr_cmd->scsi_cmd->device->hostdata; - struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa; - u32 ioasc = be32_to_cpu(ioasa->hdr.ioasc); - - memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); - - if (ioasc >= IPR_FIRST_DRIVER_IOASC) - return; - - ipr_cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; - - if (ipr_is_vset_device(res) && - ioasc == IPR_IOASC_MED_DO_NOT_REALLOC && - ioasa->u.vset.failing_lba_hi != 0) { - sense_buf[0] = 0x72; - sense_buf[1] = IPR_IOASC_SENSE_KEY(ioasc); - sense_buf[2] = IPR_IOASC_SENSE_CODE(ioasc); - sense_buf[3] = IPR_IOASC_SENSE_QUAL(ioasc); - - sense_buf[7] = 12; - sense_buf[8] = 0; - sense_buf[9] = 0x0A; - sense_buf[10] = 0x80; - - failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_hi); - - sense_buf[12] = (failing_lba & 0xff000000) >> 24; - sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; - sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; - sense_buf[15] = failing_lba & 0x000000ff; - - failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo); - - sense_buf[16] = (failing_lba & 0xff000000) >> 24; - sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; - sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; - sense_buf[19] = failing_lba & 0x000000ff; - } else { - sense_buf[0] = 0x70; - sense_buf[2] = IPR_IOASC_SENSE_KEY(ioasc); - sense_buf[12] = IPR_IOASC_SENSE_CODE(ioasc); - sense_buf[13] = IPR_IOASC_SENSE_QUAL(ioasc); - - /* Illegal request */ - if ((IPR_IOASC_SENSE_KEY(ioasc) == 0x05) && - (be32_to_cpu(ioasa->hdr.ioasc_specific) & IPR_FIELD_POINTER_VALID)) { - sense_buf[7] = 10; /* additional length */ - - /* IOARCB was in error */ - if (IPR_IOASC_SENSE_CODE(ioasc) == 0x24) - sense_buf[15] = 0xC0; - else /* Parameter data was invalid */ - sense_buf[15] = 0x80; - - sense_buf[16] = - ((IPR_FIELD_POINTER_MASK & - be32_to_cpu(ioasa->hdr.ioasc_specific)) >> 8) & 0xff; - sense_buf[17] = - (IPR_FIELD_POINTER_MASK & - be32_to_cpu(ioasa->hdr.ioasc_specific)) & 0xff; - } else { - if (ioasc == IPR_IOASC_MED_DO_NOT_REALLOC) { - if (ipr_is_vset_device(res)) - failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo); - else - failing_lba = be32_to_cpu(ioasa->u.dasd.failing_lba); - - sense_buf[0] |= 0x80; /* Or in the Valid bit */ - sense_buf[3] = (failing_lba & 0xff000000) >> 24; - sense_buf[4] = (failing_lba & 0x00ff0000) >> 16; - sense_buf[5] = (failing_lba & 0x0000ff00) >> 8; - sense_buf[6] = failing_lba & 0x000000ff; - } - - sense_buf[7] = 6; /* additional length */ - } - } -} - -/** - * ipr_get_autosense - Copy autosense data to sense buffer - * @ipr_cmd: ipr command struct - * - * This function copies the autosense buffer to the buffer - * in the scsi_cmd, if there is autosense available. - * - * Return value: - * 1 if autosense was available / 0 if not - **/ -static int ipr_get_autosense(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa; - struct ipr_ioasa64 *ioasa64 = &ipr_cmd->s.ioasa64; - - if ((be32_to_cpu(ioasa->hdr.ioasc_specific) & IPR_AUTOSENSE_VALID) == 0) - return 0; - - if (ipr_cmd->ioa_cfg->sis64) - memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa64->auto_sense.data, - min_t(u16, be16_to_cpu(ioasa64->auto_sense.auto_sense_len), - SCSI_SENSE_BUFFERSIZE)); - else - memcpy(ipr_cmd->scsi_cmd->sense_buffer, ioasa->auto_sense.data, - min_t(u16, be16_to_cpu(ioasa->auto_sense.auto_sense_len), - SCSI_SENSE_BUFFERSIZE)); - return 1; -} - -/** - * ipr_erp_start - Process an error response for a SCSI op - * @ioa_cfg: ioa config struct - * @ipr_cmd: ipr command struct - * - * This function determines whether or not to initiate ERP - * on the affected device. - * - * Return value: - * nothing - **/ -static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_cmnd *ipr_cmd) -{ - struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; - struct ipr_resource_entry *res = scsi_cmd->device->hostdata; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - u32 masked_ioasc = ioasc & IPR_IOASC_IOASC_MASK; - - if (!res) { - ipr_scsi_eh_done(ipr_cmd); - return; - } - - if (!ipr_is_gscsi(res) && masked_ioasc != IPR_IOASC_HW_DEV_BUS_STATUS) - ipr_gen_sense(ipr_cmd); - - ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); - - switch (masked_ioasc) { - case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST: - if (ipr_is_naca_model(res)) - scsi_cmd->result |= (DID_ABORT << 16); - else - scsi_cmd->result |= (DID_IMM_RETRY << 16); - break; - case IPR_IOASC_IR_RESOURCE_HANDLE: - case IPR_IOASC_IR_NO_CMDS_TO_2ND_IOA: - scsi_cmd->result |= (DID_NO_CONNECT << 16); - break; - case IPR_IOASC_HW_SEL_TIMEOUT: - scsi_cmd->result |= (DID_NO_CONNECT << 16); - if (!ipr_is_naca_model(res)) - res->needs_sync_complete = 1; - break; - case IPR_IOASC_SYNC_REQUIRED: - if (!res->in_erp) - res->needs_sync_complete = 1; - scsi_cmd->result |= (DID_IMM_RETRY << 16); - break; - case IPR_IOASC_MED_DO_NOT_REALLOC: /* prevent retries */ - case IPR_IOASA_IR_DUAL_IOA_DISABLED: - scsi_cmd->result |= (DID_PASSTHROUGH << 16); - break; - case IPR_IOASC_BUS_WAS_RESET: - case IPR_IOASC_BUS_WAS_RESET_BY_OTHER: - /* - * Report the bus reset and ask for a retry. The device - * will give CC/UA the next command. - */ - if (!res->resetting_device) - scsi_report_bus_reset(ioa_cfg->host, scsi_cmd->device->channel); - scsi_cmd->result |= (DID_ERROR << 16); - if (!ipr_is_naca_model(res)) - res->needs_sync_complete = 1; - break; - case IPR_IOASC_HW_DEV_BUS_STATUS: - scsi_cmd->result |= IPR_IOASC_SENSE_STATUS(ioasc); - if (IPR_IOASC_SENSE_STATUS(ioasc) == SAM_STAT_CHECK_CONDITION) { - if (!ipr_get_autosense(ipr_cmd)) { - if (!ipr_is_naca_model(res)) { - ipr_erp_cancel_all(ipr_cmd); - return; - } - } - } - if (!ipr_is_naca_model(res)) - res->needs_sync_complete = 1; - break; - case IPR_IOASC_NR_INIT_CMD_REQUIRED: - break; - default: - if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) - scsi_cmd->result |= (DID_ERROR << 16); - if (!ipr_is_vset_device(res) && !ipr_is_naca_model(res)) - res->needs_sync_complete = 1; - break; - } - - scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - scsi_cmd->scsi_done(scsi_cmd); -} - -/** - * ipr_scsi_done - mid-layer done function - * @ipr_cmd: ipr command struct - * - * This function is invoked by the interrupt handler for - * ops generated by the SCSI mid-layer - * - * Return value: - * none - **/ -static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - scsi_set_resid(scsi_cmd, be32_to_cpu(ipr_cmd->s.ioasa.hdr.residual_data_len)); - - if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) { - scsi_dma_unmap(ipr_cmd->scsi_cmd); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - scsi_cmd->scsi_done(scsi_cmd); - } else - ipr_erp_start(ioa_cfg, ipr_cmd); -} - -/** - * ipr_queuecommand - Queue a mid-layer request - * @scsi_cmd: scsi command struct - * @done: done function - * - * This function queues a request generated by the mid-layer. - * - * Return value: - * 0 on success - * SCSI_MLQUEUE_DEVICE_BUSY if device is busy - * SCSI_MLQUEUE_HOST_BUSY if host is busy - **/ -static int ipr_queuecommand_lck(struct scsi_cmnd *scsi_cmd, - void (*done) (struct scsi_cmnd *)) -{ - struct ipr_ioa_cfg *ioa_cfg; - struct ipr_resource_entry *res; - struct ipr_ioarcb *ioarcb; - struct ipr_cmnd *ipr_cmd; - int rc = 0; - - scsi_cmd->scsi_done = done; - ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata; - res = scsi_cmd->device->hostdata; - scsi_cmd->result = (DID_OK << 16); - - /* - * We are currently blocking all devices due to a host reset - * We have told the host to stop giving us new requests, but - * ERP ops don't count. FIXME - */ - if (unlikely(!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead)) - return SCSI_MLQUEUE_HOST_BUSY; - - /* - * FIXME - Create scsi_set_host_offline interface - * and the ioa_is_dead check can be removed - */ - if (unlikely(ioa_cfg->ioa_is_dead || !res)) { - memset(scsi_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - scsi_cmd->result = (DID_NO_CONNECT << 16); - scsi_cmd->scsi_done(scsi_cmd); - return 0; - } - - if (ipr_is_gata(res) && res->sata_port) - return ata_sas_queuecmd(scsi_cmd, res->sata_port->ap); - - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - ioarcb = &ipr_cmd->ioarcb; - list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); - - memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); - ipr_cmd->scsi_cmd = scsi_cmd; - ioarcb->res_handle = res->res_handle; - ipr_cmd->done = ipr_scsi_done; - ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res)); - - if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) { - if (scsi_cmd->underflow == 0) - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; - - if (res->needs_sync_complete) { - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE; - res->needs_sync_complete = 0; - } - - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; - if (ipr_is_gscsi(res)) - ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST; - ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR; - ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd); - } - - if (scsi_cmd->cmnd[0] >= 0xC0 && - (!ipr_is_gscsi(res) || scsi_cmd->cmnd[0] == IPR_QUERY_RSRC_STATE)) - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; - - if (likely(rc == 0)) { - if (ioa_cfg->sis64) - rc = ipr_build_ioadl64(ioa_cfg, ipr_cmd); - else - rc = ipr_build_ioadl(ioa_cfg, ipr_cmd); - } - - if (unlikely(rc != 0)) { - list_move_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - return SCSI_MLQUEUE_HOST_BUSY; - } - - ipr_send_command(ipr_cmd); - return 0; -} - -static DEF_SCSI_QCMD(ipr_queuecommand) - -/** - * ipr_ioctl - IOCTL handler - * @sdev: scsi device struct - * @cmd: IOCTL cmd - * @arg: IOCTL arg - * - * Return value: - * 0 on success / other on failure - **/ -static int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) -{ - struct ipr_resource_entry *res; - - res = (struct ipr_resource_entry *)sdev->hostdata; - if (res && ipr_is_gata(res)) { - if (cmd == HDIO_GET_IDENTITY) - return -ENOTTY; - return ata_sas_scsi_ioctl(res->sata_port->ap, sdev, cmd, arg); - } - - return -EINVAL; -} - -/** - * ipr_info - Get information about the card/driver - * @scsi_host: scsi host struct - * - * Return value: - * pointer to buffer with description string - **/ -static const char * ipr_ioa_info(struct Scsi_Host *host) -{ - static char buffer[512]; - struct ipr_ioa_cfg *ioa_cfg; - unsigned long lock_flags = 0; - - ioa_cfg = (struct ipr_ioa_cfg *) host->hostdata; - - spin_lock_irqsave(host->host_lock, lock_flags); - sprintf(buffer, "IBM %X Storage Adapter", ioa_cfg->type); - spin_unlock_irqrestore(host->host_lock, lock_flags); - - return buffer; -} - -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = "IPR", - .info = ipr_ioa_info, - .ioctl = ipr_ioctl, - .queuecommand = ipr_queuecommand, - .eh_abort_handler = ipr_eh_abort, - .eh_device_reset_handler = ipr_eh_dev_reset, - .eh_host_reset_handler = ipr_eh_host_reset, - .slave_alloc = ipr_slave_alloc, - .slave_configure = ipr_slave_configure, - .slave_destroy = ipr_slave_destroy, - .target_alloc = ipr_target_alloc, - .target_destroy = ipr_target_destroy, - .change_queue_depth = ipr_change_queue_depth, - .change_queue_type = ipr_change_queue_type, - .bios_param = ipr_biosparam, - .can_queue = IPR_MAX_COMMANDS, - .this_id = -1, - .sg_tablesize = IPR_MAX_SGLIST, - .max_sectors = IPR_IOA_MAX_SECTORS, - .cmd_per_lun = IPR_MAX_CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = ipr_ioa_attrs, - .sdev_attrs = ipr_dev_attrs, - .proc_name = IPR_NAME -}; - -/** - * ipr_ata_phy_reset - libata phy_reset handler - * @ap: ata port to reset - * - **/ -static void ipr_ata_phy_reset(struct ata_port *ap) -{ - unsigned long flags; - struct ipr_sata_port *sata_port = ap->private_data; - struct ipr_resource_entry *res = sata_port->res; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - int rc; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - while(ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - } - - if (!ioa_cfg->allow_cmds) - goto out_unlock; - - rc = ipr_device_reset(ioa_cfg, res); - - if (rc) { - ap->link.device[0].class = ATA_DEV_NONE; - goto out_unlock; - } - - ap->link.device[0].class = res->ata_class; - if (ap->link.device[0].class == ATA_DEV_UNKNOWN) - ap->link.device[0].class = ATA_DEV_NONE; - -out_unlock: - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - LEAVE; -} - -/** - * ipr_ata_post_internal - Cleanup after an internal command - * @qc: ATA queued command - * - * Return value: - * none - **/ -static void ipr_ata_post_internal(struct ata_queued_cmd *qc) -{ - struct ipr_sata_port *sata_port = qc->ap->private_data; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - struct ipr_cmnd *ipr_cmd; - unsigned long flags; - - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - while(ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - } - - list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { - if (ipr_cmd->qc == qc) { - ipr_device_reset(ioa_cfg, sata_port->res); - break; - } - } - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); -} - -/** - * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure - * @regs: destination - * @tf: source ATA taskfile - * - * Return value: - * none - **/ -static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs, - struct ata_taskfile *tf) -{ - regs->feature = tf->feature; - regs->nsect = tf->nsect; - regs->lbal = tf->lbal; - regs->lbam = tf->lbam; - regs->lbah = tf->lbah; - regs->device = tf->device; - regs->command = tf->command; - regs->hob_feature = tf->hob_feature; - regs->hob_nsect = tf->hob_nsect; - regs->hob_lbal = tf->hob_lbal; - regs->hob_lbam = tf->hob_lbam; - regs->hob_lbah = tf->hob_lbah; - regs->ctl = tf->ctl; -} - -/** - * ipr_sata_done - done function for SATA commands - * @ipr_cmd: ipr command struct - * - * This function is invoked by the interrupt handler for - * ops generated by the SCSI mid-layer to SATA devices - * - * Return value: - * none - **/ -static void ipr_sata_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ata_queued_cmd *qc = ipr_cmd->qc; - struct ipr_sata_port *sata_port = qc->ap->private_data; - struct ipr_resource_entry *res = sata_port->res; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - if (ipr_cmd->ioa_cfg->sis64) - memcpy(&sata_port->ioasa, &ipr_cmd->s.ioasa64.u.gata, - sizeof(struct ipr_ioasa_gata)); - else - memcpy(&sata_port->ioasa, &ipr_cmd->s.ioasa.u.gata, - sizeof(struct ipr_ioasa_gata)); - ipr_dump_ioasa(ioa_cfg, ipr_cmd, res); - - if (be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET) - scsi_report_device_reset(ioa_cfg->host, res->bus, res->target); - - if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) - qc->err_mask |= __ac_err_mask(sata_port->ioasa.status); - else - qc->err_mask |= ac_err_mask(sata_port->ioasa.status); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - ata_qc_complete(qc); -} - -/** - * ipr_build_ata_ioadl64 - Build an ATA scatter/gather list - * @ipr_cmd: ipr command struct - * @qc: ATA queued command - * - **/ -static void ipr_build_ata_ioadl64(struct ipr_cmnd *ipr_cmd, - struct ata_queued_cmd *qc) -{ - u32 ioadl_flags = 0; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64; - struct ipr_ioadl64_desc *last_ioadl64 = NULL; - int len = qc->nbytes; - struct scatterlist *sg; - unsigned int si; - dma_addr_t dma_addr = ipr_cmd->dma_addr; - - if (len == 0) - return; - - if (qc->dma_dir == DMA_TO_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_WRITE; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - } else if (qc->dma_dir == DMA_FROM_DEVICE) - ioadl_flags = IPR_IOADL_FLAGS_READ; - - ioarcb->data_transfer_length = cpu_to_be32(len); - ioarcb->ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl64_desc) * ipr_cmd->dma_use_sg); - ioarcb->u.sis64_addr_data.data_ioadl_addr = - cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ata_ioadl)); - - for_each_sg(qc->sg, sg, qc->n_elem, si) { - ioadl64->flags = cpu_to_be32(ioadl_flags); - ioadl64->data_len = cpu_to_be32(sg_dma_len(sg)); - ioadl64->address = cpu_to_be64(sg_dma_address(sg)); - - last_ioadl64 = ioadl64; - ioadl64++; - } - - if (likely(last_ioadl64)) - last_ioadl64->flags |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); -} - -/** - * ipr_build_ata_ioadl - Build an ATA scatter/gather list - * @ipr_cmd: ipr command struct - * @qc: ATA queued command - * - **/ -static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd, - struct ata_queued_cmd *qc) -{ - u32 ioadl_flags = 0; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl; - struct ipr_ioadl_desc *last_ioadl = NULL; - int len = qc->nbytes; - struct scatterlist *sg; - unsigned int si; - - if (len == 0) - return; - - if (qc->dma_dir == DMA_TO_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_WRITE; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->data_transfer_length = cpu_to_be32(len); - ioarcb->ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - } else if (qc->dma_dir == DMA_FROM_DEVICE) { - ioadl_flags = IPR_IOADL_FLAGS_READ; - ioarcb->read_data_transfer_length = cpu_to_be32(len); - ioarcb->read_ioadl_len = - cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg); - } - - for_each_sg(qc->sg, sg, qc->n_elem, si) { - ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg)); - ioadl->address = cpu_to_be32(sg_dma_address(sg)); - - last_ioadl = ioadl; - ioadl++; - } - - if (likely(last_ioadl)) - last_ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST); -} - -/** - * ipr_qc_issue - Issue a SATA qc to a device - * @qc: queued command - * - * Return value: - * 0 if success - **/ -static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc) -{ - struct ata_port *ap = qc->ap; - struct ipr_sata_port *sata_port = ap->private_data; - struct ipr_resource_entry *res = sata_port->res; - struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg; - struct ipr_cmnd *ipr_cmd; - struct ipr_ioarcb *ioarcb; - struct ipr_ioarcb_ata_regs *regs; - - if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead)) - return AC_ERR_SYSTEM; - - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - ioarcb = &ipr_cmd->ioarcb; - - if (ioa_cfg->sis64) { - regs = &ipr_cmd->i.ata_ioadl.regs; - ioarcb->add_cmd_parms_offset = cpu_to_be16(sizeof(*ioarcb)); - } else - regs = &ioarcb->u.add_data.u.regs; - - memset(regs, 0, sizeof(*regs)); - ioarcb->add_cmd_parms_len = cpu_to_be16(sizeof(*regs)); - - list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); - ipr_cmd->qc = qc; - ipr_cmd->done = ipr_sata_done; - ipr_cmd->ioarcb.res_handle = res->res_handle; - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; - ipr_cmd->dma_use_sg = qc->n_elem; - - if (ioa_cfg->sis64) - ipr_build_ata_ioadl64(ipr_cmd, qc); - else - ipr_build_ata_ioadl(ipr_cmd, qc); - - regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION; - ipr_copy_sata_tf(regs, &qc->tf); - memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN); - ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_RES_PHYS_LOC(res)); - - switch (qc->tf.protocol) { - case ATA_PROT_NODATA: - case ATA_PROT_PIO: - break; - - case ATA_PROT_DMA: - regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; - break; - - case ATAPI_PROT_PIO: - case ATAPI_PROT_NODATA: - regs->flags |= IPR_ATA_FLAG_PACKET_CMD; - break; - - case ATAPI_PROT_DMA: - regs->flags |= IPR_ATA_FLAG_PACKET_CMD; - regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA; - break; - - default: - WARN_ON(1); - return AC_ERR_INVALID; - } - - ipr_send_command(ipr_cmd); - - return 0; -} - -/** - * ipr_qc_fill_rtf - Read result TF - * @qc: ATA queued command - * - * Return value: - * true - **/ -static bool ipr_qc_fill_rtf(struct ata_queued_cmd *qc) -{ - struct ipr_sata_port *sata_port = qc->ap->private_data; - struct ipr_ioasa_gata *g = &sata_port->ioasa; - struct ata_taskfile *tf = &qc->result_tf; - - tf->feature = g->error; - tf->nsect = g->nsect; - tf->lbal = g->lbal; - tf->lbam = g->lbam; - tf->lbah = g->lbah; - tf->device = g->device; - tf->command = g->status; - tf->hob_nsect = g->hob_nsect; - tf->hob_lbal = g->hob_lbal; - tf->hob_lbam = g->hob_lbam; - tf->hob_lbah = g->hob_lbah; - tf->ctl = g->alt_status; - - return true; -} - -static struct ata_port_operations ipr_sata_ops = { - .phy_reset = ipr_ata_phy_reset, - .hardreset = ipr_sata_reset, - .post_internal_cmd = ipr_ata_post_internal, - .qc_prep = ata_noop_qc_prep, - .qc_issue = ipr_qc_issue, - .qc_fill_rtf = ipr_qc_fill_rtf, - .port_start = ata_sas_port_start, - .port_stop = ata_sas_port_stop -}; - -static struct ata_port_info sata_port_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA, - .pio_mask = ATA_PIO4_ONLY, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA6, - .port_ops = &ipr_sata_ops -}; - -#ifdef CONFIG_PPC_PSERIES -static const u16 ipr_blocked_processors[] = { - PV_NORTHSTAR, - PV_PULSAR, - PV_POWER4, - PV_ICESTAR, - PV_SSTAR, - PV_POWER4p, - PV_630, - PV_630p -}; - -/** - * ipr_invalid_adapter - Determine if this adapter is supported on this hardware - * @ioa_cfg: ioa cfg struct - * - * Adapters that use Gemstone revision < 3.1 do not work reliably on - * certain pSeries hardware. This function determines if the given - * adapter is in one of these confgurations or not. - * - * Return value: - * 1 if adapter is not supported / 0 if adapter is supported - **/ -static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg) -{ - int i; - - if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) { - for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){ - if (__is_processor(ipr_blocked_processors[i])) - return 1; - } - } - return 0; -} -#else -#define ipr_invalid_adapter(ioa_cfg) 0 -#endif - -/** - * ipr_ioa_bringdown_done - IOA bring down completion. - * @ipr_cmd: ipr command struct - * - * This function processes the completion of an adapter bring down. - * It wakes any reset sleepers. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioa_bringdown_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - ioa_cfg->in_reset_reload = 0; - ioa_cfg->reset_retries = 0; - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - wake_up_all(&ioa_cfg->reset_wait_q); - - spin_unlock_irq(ioa_cfg->host->host_lock); - scsi_unblock_requests(ioa_cfg->host); - spin_lock_irq(ioa_cfg->host->host_lock); - LEAVE; - - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_ioa_reset_done - IOA reset completion. - * @ipr_cmd: ipr command struct - * - * This function processes the completion of an adapter reset. - * It schedules any necessary mid-layer add/removes and - * wakes any reset sleepers. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_resource_entry *res; - struct ipr_hostrcb *hostrcb, *temp; - int i = 0; - - ENTER; - ioa_cfg->in_reset_reload = 0; - ioa_cfg->allow_cmds = 1; - ioa_cfg->reset_cmd = NULL; - ioa_cfg->doorbell |= IPR_RUNTIME_RESET; - - list_for_each_entry(res, &ioa_cfg->used_res_q, queue) { - if (ioa_cfg->allow_ml_add_del && (res->add_to_ml || res->del_from_ml)) { - ipr_trace; - break; - } - } - schedule_work(&ioa_cfg->work_q); - - list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) { - list_del(&hostrcb->queue); - if (i++ < IPR_NUM_LOG_HCAMS) - ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb); - else - ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb); - } - - scsi_report_bus_reset(ioa_cfg->host, IPR_VSET_BUS); - dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n"); - - ioa_cfg->reset_retries = 0; - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - wake_up_all(&ioa_cfg->reset_wait_q); - - spin_unlock(ioa_cfg->host->host_lock); - scsi_unblock_requests(ioa_cfg->host); - spin_lock(ioa_cfg->host->host_lock); - - if (!ioa_cfg->allow_cmds) - scsi_block_requests(ioa_cfg->host); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_set_sup_dev_dflt - Initialize a Set Supported Device buffer - * @supported_dev: supported device struct - * @vpids: vendor product id struct - * - * Return value: - * none - **/ -static void ipr_set_sup_dev_dflt(struct ipr_supported_device *supported_dev, - struct ipr_std_inq_vpids *vpids) -{ - memset(supported_dev, 0, sizeof(struct ipr_supported_device)); - memcpy(&supported_dev->vpids, vpids, sizeof(struct ipr_std_inq_vpids)); - supported_dev->num_records = 1; - supported_dev->data_length = - cpu_to_be16(sizeof(struct ipr_supported_device)); - supported_dev->reserved = 0; -} - -/** - * ipr_set_supported_devs - Send Set Supported Devices for a device - * @ipr_cmd: ipr command struct - * - * This function sends a Set Supported Devices to the adapter - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_supported_device *supp_dev = &ioa_cfg->vpd_cbs->supp_dev; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_resource_entry *res = ipr_cmd->u.res; - - ipr_cmd->job_step = ipr_ioa_reset_done; - - list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) { - if (!ipr_is_scsi_disk(res)) - continue; - - ipr_cmd->u.res = res; - ipr_set_sup_dev_dflt(supp_dev, &res->std_inq_data.vpids); - - ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; - - ioarcb->cmd_pkt.cdb[0] = IPR_SET_SUPPORTED_DEVICES; - ioarcb->cmd_pkt.cdb[1] = IPR_SET_ALL_SUPPORTED_DEVICES; - ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_supported_device) >> 8) & 0xff; - ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_supported_device) & 0xff; - - ipr_init_ioadl(ipr_cmd, - ioa_cfg->vpd_cbs_dma + - offsetof(struct ipr_misc_cbs, supp_dev), - sizeof(struct ipr_supported_device), - IPR_IOADL_FLAGS_WRITE_LAST); - - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, - IPR_SET_SUP_DEVICE_TIMEOUT); - - if (!ioa_cfg->sis64) - ipr_cmd->job_step = ipr_set_supported_devs; - return IPR_RC_JOB_RETURN; - } - - return IPR_RC_JOB_CONTINUE; -} - -/** - * ipr_get_mode_page - Locate specified mode page - * @mode_pages: mode page buffer - * @page_code: page code to find - * @len: minimum required length for mode page - * - * Return value: - * pointer to mode page / NULL on failure - **/ -static void *ipr_get_mode_page(struct ipr_mode_pages *mode_pages, - u32 page_code, u32 len) -{ - struct ipr_mode_page_hdr *mode_hdr; - u32 page_length; - u32 length; - - if (!mode_pages || (mode_pages->hdr.length == 0)) - return NULL; - - length = (mode_pages->hdr.length + 1) - 4 - mode_pages->hdr.block_desc_len; - mode_hdr = (struct ipr_mode_page_hdr *) - (mode_pages->data + mode_pages->hdr.block_desc_len); - - while (length) { - if (IPR_GET_MODE_PAGE_CODE(mode_hdr) == page_code) { - if (mode_hdr->page_length >= (len - sizeof(struct ipr_mode_page_hdr))) - return mode_hdr; - break; - } else { - page_length = (sizeof(struct ipr_mode_page_hdr) + - mode_hdr->page_length); - length -= page_length; - mode_hdr = (struct ipr_mode_page_hdr *) - ((unsigned long)mode_hdr + page_length); - } - } - return NULL; -} - -/** - * ipr_check_term_power - Check for term power errors - * @ioa_cfg: ioa config struct - * @mode_pages: IOAFP mode pages buffer - * - * Check the IOAFP's mode page 28 for term power errors - * - * Return value: - * nothing - **/ -static void ipr_check_term_power(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_mode_pages *mode_pages) -{ - int i; - int entry_length; - struct ipr_dev_bus_entry *bus; - struct ipr_mode_page28 *mode_page; - - mode_page = ipr_get_mode_page(mode_pages, 0x28, - sizeof(struct ipr_mode_page28)); - - entry_length = mode_page->entry_length; - - bus = mode_page->bus; - - for (i = 0; i < mode_page->num_entries; i++) { - if (bus->flags & IPR_SCSI_ATTR_NO_TERM_PWR) { - dev_err(&ioa_cfg->pdev->dev, - "Term power is absent on scsi bus %d\n", - bus->res_addr.bus); - } - - bus = (struct ipr_dev_bus_entry *)((char *)bus + entry_length); - } -} - -/** - * ipr_scsi_bus_speed_limit - Limit the SCSI speed based on SES table - * @ioa_cfg: ioa config struct - * - * Looks through the config table checking for SES devices. If - * the SES device is in the SES table indicating a maximum SCSI - * bus speed, the speed is limited for the bus. - * - * Return value: - * none - **/ -static void ipr_scsi_bus_speed_limit(struct ipr_ioa_cfg *ioa_cfg) -{ - u32 max_xfer_rate; - int i; - - for (i = 0; i < IPR_MAX_NUM_BUSES; i++) { - max_xfer_rate = ipr_get_max_scsi_speed(ioa_cfg, i, - ioa_cfg->bus_attr[i].bus_width); - - if (max_xfer_rate < ioa_cfg->bus_attr[i].max_xfer_rate) - ioa_cfg->bus_attr[i].max_xfer_rate = max_xfer_rate; - } -} - -/** - * ipr_modify_ioafp_mode_page_28 - Modify IOAFP Mode Page 28 - * @ioa_cfg: ioa config struct - * @mode_pages: mode page 28 buffer - * - * Updates mode page 28 based on driver configuration - * - * Return value: - * none - **/ -static void ipr_modify_ioafp_mode_page_28(struct ipr_ioa_cfg *ioa_cfg, - struct ipr_mode_pages *mode_pages) -{ - int i, entry_length; - struct ipr_dev_bus_entry *bus; - struct ipr_bus_attributes *bus_attr; - struct ipr_mode_page28 *mode_page; - - mode_page = ipr_get_mode_page(mode_pages, 0x28, - sizeof(struct ipr_mode_page28)); - - entry_length = mode_page->entry_length; - - /* Loop for each device bus entry */ - for (i = 0, bus = mode_page->bus; - i < mode_page->num_entries; - i++, bus = (struct ipr_dev_bus_entry *)((u8 *)bus + entry_length)) { - if (bus->res_addr.bus > IPR_MAX_NUM_BUSES) { - dev_err(&ioa_cfg->pdev->dev, - "Invalid resource address reported: 0x%08X\n", - IPR_GET_PHYS_LOC(bus->res_addr)); - continue; - } - - bus_attr = &ioa_cfg->bus_attr[i]; - bus->extended_reset_delay = IPR_EXTENDED_RESET_DELAY; - bus->bus_width = bus_attr->bus_width; - bus->max_xfer_rate = cpu_to_be32(bus_attr->max_xfer_rate); - bus->flags &= ~IPR_SCSI_ATTR_QAS_MASK; - if (bus_attr->qas_enabled) - bus->flags |= IPR_SCSI_ATTR_ENABLE_QAS; - else - bus->flags |= IPR_SCSI_ATTR_DISABLE_QAS; - } -} - -/** - * ipr_build_mode_select - Build a mode select command - * @ipr_cmd: ipr command struct - * @res_handle: resource handle to send command to - * @parm: Byte 2 of Mode Sense command - * @dma_addr: DMA buffer address - * @xfer_len: data transfer length - * - * Return value: - * none - **/ -static void ipr_build_mode_select(struct ipr_cmnd *ipr_cmd, - __be32 res_handle, u8 parm, - dma_addr_t dma_addr, u8 xfer_len) -{ - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - - ioarcb->res_handle = res_handle; - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; - ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ; - ioarcb->cmd_pkt.cdb[0] = MODE_SELECT; - ioarcb->cmd_pkt.cdb[1] = parm; - ioarcb->cmd_pkt.cdb[4] = xfer_len; - - ipr_init_ioadl(ipr_cmd, dma_addr, xfer_len, IPR_IOADL_FLAGS_WRITE_LAST); -} - -/** - * ipr_ioafp_mode_select_page28 - Issue Mode Select Page 28 to IOA - * @ipr_cmd: ipr command struct - * - * This function sets up the SCSI bus attributes and sends - * a Mode Select for Page 28 to activate them. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_mode_select_page28(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages; - int length; - - ENTER; - ipr_scsi_bus_speed_limit(ioa_cfg); - ipr_check_term_power(ioa_cfg, mode_pages); - ipr_modify_ioafp_mode_page_28(ioa_cfg, mode_pages); - length = mode_pages->hdr.length + 1; - mode_pages->hdr.length = 0; - - ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11, - ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages), - length); - - ipr_cmd->job_step = ipr_set_supported_devs; - ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next, - struct ipr_resource_entry, queue); - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_build_mode_sense - Builds a mode sense command - * @ipr_cmd: ipr command struct - * @res: resource entry struct - * @parm: Byte 2 of mode sense command - * @dma_addr: DMA address of mode sense buffer - * @xfer_len: Size of DMA buffer - * - * Return value: - * none - **/ -static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd, - __be32 res_handle, - u8 parm, dma_addr_t dma_addr, u8 xfer_len) -{ - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - - ioarcb->res_handle = res_handle; - ioarcb->cmd_pkt.cdb[0] = MODE_SENSE; - ioarcb->cmd_pkt.cdb[2] = parm; - ioarcb->cmd_pkt.cdb[4] = xfer_len; - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; - - ipr_init_ioadl(ipr_cmd, dma_addr, xfer_len, IPR_IOADL_FLAGS_READ_LAST); -} - -/** - * ipr_reset_cmd_failed - Handle failure of IOA reset command - * @ipr_cmd: ipr command struct - * - * This function handles the failure of an IOA bringup command. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_reset_cmd_failed(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - dev_err(&ioa_cfg->pdev->dev, - "0x%02X failed with IOASC: 0x%08X\n", - ipr_cmd->ioarcb.cmd_pkt.cdb[0], ioasc); - - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_mode_sense_failed - Handle failure of IOAFP mode sense - * @ipr_cmd: ipr command struct - * - * This function handles the failure of a Mode Sense to the IOAFP. - * Some adapters do not handle all mode pages. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_mode_sense_failed(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) { - ipr_cmd->job_step = ipr_set_supported_devs; - ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next, - struct ipr_resource_entry, queue); - return IPR_RC_JOB_CONTINUE; - } - - return ipr_reset_cmd_failed(ipr_cmd); -} - -/** - * ipr_ioafp_mode_sense_page28 - Issue Mode Sense Page 28 to IOA - * @ipr_cmd: ipr command struct - * - * This function send a Page 28 mode sense to the IOA to - * retrieve SCSI bus attributes. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), - 0x28, ioa_cfg->vpd_cbs_dma + - offsetof(struct ipr_misc_cbs, mode_pages), - sizeof(struct ipr_mode_pages)); - - ipr_cmd->job_step = ipr_ioafp_mode_select_page28; - ipr_cmd->job_step_failed = ipr_reset_mode_sense_failed; - - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_ioafp_mode_select_page24 - Issue Mode Select to IOA - * @ipr_cmd: ipr command struct - * - * This function enables dual IOA RAID support if possible. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_mode_select_page24(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages; - struct ipr_mode_page24 *mode_page; - int length; - - ENTER; - mode_page = ipr_get_mode_page(mode_pages, 0x24, - sizeof(struct ipr_mode_page24)); - - if (mode_page) - mode_page->flags |= IPR_ENABLE_DUAL_IOA_AF; - - length = mode_pages->hdr.length + 1; - mode_pages->hdr.length = 0; - - ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11, - ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages), - length); - - ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_mode_sense_page24_failed - Handle failure of IOAFP mode sense - * @ipr_cmd: ipr command struct - * - * This function handles the failure of a Mode Sense to the IOAFP. - * Some adapters do not handle all mode pages. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_mode_sense_page24_failed(struct ipr_cmnd *ipr_cmd) -{ - u32 ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - if (ioasc == IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT) { - ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; - return IPR_RC_JOB_CONTINUE; - } - - return ipr_reset_cmd_failed(ipr_cmd); -} - -/** - * ipr_ioafp_mode_sense_page24 - Issue Page 24 Mode Sense to IOA - * @ipr_cmd: ipr command struct - * - * This function send a mode sense to the IOA to retrieve - * the IOA Advanced Function Control mode page. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_mode_sense_page24(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), - 0x24, ioa_cfg->vpd_cbs_dma + - offsetof(struct ipr_misc_cbs, mode_pages), - sizeof(struct ipr_mode_pages)); - - ipr_cmd->job_step = ipr_ioafp_mode_select_page24; - ipr_cmd->job_step_failed = ipr_reset_mode_sense_page24_failed; - - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_init_res_table - Initialize the resource table - * @ipr_cmd: ipr command struct - * - * This function looks through the existing resource table, comparing - * it with the config table. This function will take care of old/new - * devices and schedule adding/removing them from the mid-layer - * as appropriate. - * - * Return value: - * IPR_RC_JOB_CONTINUE - **/ -static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_resource_entry *res, *temp; - struct ipr_config_table_entry_wrapper cfgtew; - int entries, found, flag, i; - LIST_HEAD(old_res); - - ENTER; - if (ioa_cfg->sis64) - flag = ioa_cfg->u.cfg_table64->hdr64.flags; - else - flag = ioa_cfg->u.cfg_table->hdr.flags; - - if (flag & IPR_UCODE_DOWNLOAD_REQ) - dev_err(&ioa_cfg->pdev->dev, "Microcode download required\n"); - - list_for_each_entry_safe(res, temp, &ioa_cfg->used_res_q, queue) - list_move_tail(&res->queue, &old_res); - - if (ioa_cfg->sis64) - entries = be16_to_cpu(ioa_cfg->u.cfg_table64->hdr64.num_entries); - else - entries = ioa_cfg->u.cfg_table->hdr.num_entries; - - for (i = 0; i < entries; i++) { - if (ioa_cfg->sis64) - cfgtew.u.cfgte64 = &ioa_cfg->u.cfg_table64->dev[i]; - else - cfgtew.u.cfgte = &ioa_cfg->u.cfg_table->dev[i]; - found = 0; - - list_for_each_entry_safe(res, temp, &old_res, queue) { - if (ipr_is_same_device(res, &cfgtew)) { - list_move_tail(&res->queue, &ioa_cfg->used_res_q); - found = 1; - break; - } - } - - if (!found) { - if (list_empty(&ioa_cfg->free_res_q)) { - dev_err(&ioa_cfg->pdev->dev, "Too many devices attached\n"); - break; - } - - found = 1; - res = list_entry(ioa_cfg->free_res_q.next, - struct ipr_resource_entry, queue); - list_move_tail(&res->queue, &ioa_cfg->used_res_q); - ipr_init_res_entry(res, &cfgtew); - res->add_to_ml = 1; - } else if (res->sdev && (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))) - res->sdev->allow_restart = 1; - - if (found) - ipr_update_res_entry(res, &cfgtew); - } - - list_for_each_entry_safe(res, temp, &old_res, queue) { - if (res->sdev) { - res->del_from_ml = 1; - res->res_handle = IPR_INVALID_RES_HANDLE; - list_move_tail(&res->queue, &ioa_cfg->used_res_q); - } - } - - list_for_each_entry_safe(res, temp, &old_res, queue) { - ipr_clear_res_target(res); - list_move_tail(&res->queue, &ioa_cfg->free_res_q); - } - - if (ioa_cfg->dual_raid && ipr_dual_ioa_raid) - ipr_cmd->job_step = ipr_ioafp_mode_sense_page24; - else - ipr_cmd->job_step = ipr_ioafp_mode_sense_page28; - - LEAVE; - return IPR_RC_JOB_CONTINUE; -} - -/** - * ipr_ioafp_query_ioa_cfg - Send a Query IOA Config to the adapter. - * @ipr_cmd: ipr command struct - * - * This function sends a Query IOA Configuration command - * to the adapter to retrieve the IOA configuration table. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data; - struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap; - - ENTER; - if (cap->cap & IPR_CAP_DUAL_IOA_RAID) - ioa_cfg->dual_raid = 1; - dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n", - ucode_vpd->major_release, ucode_vpd->card_type, - ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]); - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; - ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); - - ioarcb->cmd_pkt.cdb[0] = IPR_QUERY_IOA_CONFIG; - ioarcb->cmd_pkt.cdb[6] = (ioa_cfg->cfg_table_size >> 16) & 0xff; - ioarcb->cmd_pkt.cdb[7] = (ioa_cfg->cfg_table_size >> 8) & 0xff; - ioarcb->cmd_pkt.cdb[8] = ioa_cfg->cfg_table_size & 0xff; - - ipr_init_ioadl(ipr_cmd, ioa_cfg->cfg_table_dma, ioa_cfg->cfg_table_size, - IPR_IOADL_FLAGS_READ_LAST); - - ipr_cmd->job_step = ipr_init_res_table; - - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_ioafp_inquiry - Send an Inquiry to the adapter. - * @ipr_cmd: ipr command struct - * - * This utility function sends an inquiry to the adapter. - * - * Return value: - * none - **/ -static void ipr_ioafp_inquiry(struct ipr_cmnd *ipr_cmd, u8 flags, u8 page, - dma_addr_t dma_addr, u8 xfer_len) -{ - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - - ENTER; - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; - ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); - - ioarcb->cmd_pkt.cdb[0] = INQUIRY; - ioarcb->cmd_pkt.cdb[1] = flags; - ioarcb->cmd_pkt.cdb[2] = page; - ioarcb->cmd_pkt.cdb[4] = xfer_len; - - ipr_init_ioadl(ipr_cmd, dma_addr, xfer_len, IPR_IOADL_FLAGS_READ_LAST); - - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); - LEAVE; -} - -/** - * ipr_inquiry_page_supported - Is the given inquiry page supported - * @page0: inquiry page 0 buffer - * @page: page code. - * - * This function determines if the specified inquiry page is supported. - * - * Return value: - * 1 if page is supported / 0 if not - **/ -static int ipr_inquiry_page_supported(struct ipr_inquiry_page0 *page0, u8 page) -{ - int i; - - for (i = 0; i < min_t(u8, page0->len, IPR_INQUIRY_PAGE0_ENTRIES); i++) - if (page0->page[i] == page) - return 1; - - return 0; -} - -/** - * ipr_ioafp_cap_inquiry - Send a Page 0xD0 Inquiry to the adapter. - * @ipr_cmd: ipr command struct - * - * This function sends a Page 0xD0 inquiry to the adapter - * to retrieve adapter capabilities. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_cap_inquiry(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_inquiry_page0 *page0 = &ioa_cfg->vpd_cbs->page0_data; - struct ipr_inquiry_cap *cap = &ioa_cfg->vpd_cbs->cap; - - ENTER; - ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg; - memset(cap, 0, sizeof(*cap)); - - if (ipr_inquiry_page_supported(page0, 0xD0)) { - ipr_ioafp_inquiry(ipr_cmd, 1, 0xD0, - ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, cap), - sizeof(struct ipr_inquiry_cap)); - return IPR_RC_JOB_RETURN; - } - - LEAVE; - return IPR_RC_JOB_CONTINUE; -} - -/** - * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter. - * @ipr_cmd: ipr command struct - * - * This function sends a Page 3 inquiry to the adapter - * to retrieve software VPD information. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - - ipr_cmd->job_step = ipr_ioafp_cap_inquiry; - - ipr_ioafp_inquiry(ipr_cmd, 1, 3, - ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data), - sizeof(struct ipr_inquiry_page3)); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_ioafp_page0_inquiry - Send a Page 0 Inquiry to the adapter. - * @ipr_cmd: ipr command struct - * - * This function sends a Page 0 inquiry to the adapter - * to retrieve supported inquiry pages. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_page0_inquiry(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - char type[5]; - - ENTER; - - /* Grab the type out of the VPD and store it away */ - memcpy(type, ioa_cfg->vpd_cbs->ioa_vpd.std_inq_data.vpids.product_id, 4); - type[4] = '\0'; - ioa_cfg->type = simple_strtoul((char *)type, NULL, 16); - - ipr_cmd->job_step = ipr_ioafp_page3_inquiry; - - ipr_ioafp_inquiry(ipr_cmd, 1, 0, - ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page0_data), - sizeof(struct ipr_inquiry_page0)); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_ioafp_std_inquiry - Send a Standard Inquiry to the adapter. - * @ipr_cmd: ipr command struct - * - * This function sends a standard inquiry to the adapter. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_std_inquiry(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - ipr_cmd->job_step = ipr_ioafp_page0_inquiry; - - ipr_ioafp_inquiry(ipr_cmd, 0, 0, - ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, ioa_vpd), - sizeof(struct ipr_ioa_vpd)); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_ioafp_identify_hrrq - Send Identify Host RRQ. - * @ipr_cmd: ipr command struct - * - * This function send an Identify Host Request Response Queue - * command to establish the HRRQ with the adapter. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_ioafp_identify_hrrq(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb; - - ENTER; - dev_info(&ioa_cfg->pdev->dev, "Starting IOA initialization sequence.\n"); - - ioarcb->cmd_pkt.cdb[0] = IPR_ID_HOST_RR_Q; - ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); - - ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; - if (ioa_cfg->sis64) - ioarcb->cmd_pkt.cdb[1] = 0x1; - ioarcb->cmd_pkt.cdb[2] = - ((u64) ioa_cfg->host_rrq_dma >> 24) & 0xff; - ioarcb->cmd_pkt.cdb[3] = - ((u64) ioa_cfg->host_rrq_dma >> 16) & 0xff; - ioarcb->cmd_pkt.cdb[4] = - ((u64) ioa_cfg->host_rrq_dma >> 8) & 0xff; - ioarcb->cmd_pkt.cdb[5] = - ((u64) ioa_cfg->host_rrq_dma) & 0xff; - ioarcb->cmd_pkt.cdb[7] = - ((sizeof(u32) * IPR_NUM_CMD_BLKS) >> 8) & 0xff; - ioarcb->cmd_pkt.cdb[8] = - (sizeof(u32) * IPR_NUM_CMD_BLKS) & 0xff; - - if (ioa_cfg->sis64) { - ioarcb->cmd_pkt.cdb[10] = - ((u64) ioa_cfg->host_rrq_dma >> 56) & 0xff; - ioarcb->cmd_pkt.cdb[11] = - ((u64) ioa_cfg->host_rrq_dma >> 48) & 0xff; - ioarcb->cmd_pkt.cdb[12] = - ((u64) ioa_cfg->host_rrq_dma >> 40) & 0xff; - ioarcb->cmd_pkt.cdb[13] = - ((u64) ioa_cfg->host_rrq_dma >> 32) & 0xff; - } - - ipr_cmd->job_step = ipr_ioafp_std_inquiry; - - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_timer_done - Adapter reset timer function - * @ipr_cmd: ipr command struct - * - * Description: This function is used in adapter reset processing - * for timing events. If the reset_cmd pointer in the IOA - * config struct is not this adapter's we are doing nested - * resets and fail_all_ops will take care of freeing the - * command block. - * - * Return value: - * none - **/ -static void ipr_reset_timer_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - unsigned long lock_flags = 0; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - if (ioa_cfg->reset_cmd == ipr_cmd) { - list_del(&ipr_cmd->queue); - ipr_cmd->done(ipr_cmd); - } - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); -} - -/** - * ipr_reset_start_timer - Start a timer for adapter reset job - * @ipr_cmd: ipr command struct - * @timeout: timeout value - * - * Description: This function is used in adapter reset processing - * for timing events. If the reset_cmd pointer in the IOA - * config struct is not this adapter's we are doing nested - * resets and fail_all_ops will take care of freeing the - * command block. - * - * Return value: - * none - **/ -static void ipr_reset_start_timer(struct ipr_cmnd *ipr_cmd, - unsigned long timeout) -{ - list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q); - ipr_cmd->done = ipr_reset_ioa_job; - - ipr_cmd->timer.data = (unsigned long) ipr_cmd; - ipr_cmd->timer.expires = jiffies + timeout; - ipr_cmd->timer.function = (void (*)(unsigned long))ipr_reset_timer_done; - add_timer(&ipr_cmd->timer); -} - -/** - * ipr_init_ioa_mem - Initialize ioa_cfg control block - * @ioa_cfg: ioa cfg struct - * - * Return value: - * nothing - **/ -static void ipr_init_ioa_mem(struct ipr_ioa_cfg *ioa_cfg) -{ - memset(ioa_cfg->host_rrq, 0, sizeof(u32) * IPR_NUM_CMD_BLKS); - - /* Initialize Host RRQ pointers */ - ioa_cfg->hrrq_start = ioa_cfg->host_rrq; - ioa_cfg->hrrq_end = &ioa_cfg->host_rrq[IPR_NUM_CMD_BLKS - 1]; - ioa_cfg->hrrq_curr = ioa_cfg->hrrq_start; - ioa_cfg->toggle_bit = 1; - - /* Zero out config table */ - memset(ioa_cfg->u.cfg_table, 0, ioa_cfg->cfg_table_size); -} - -/** - * ipr_reset_next_stage - Process IPL stage change based on feedback register. - * @ipr_cmd: ipr command struct - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_next_stage(struct ipr_cmnd *ipr_cmd) -{ - unsigned long stage, stage_time; - u32 feedback; - volatile u32 int_reg; - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - u64 maskval = 0; - - feedback = readl(ioa_cfg->regs.init_feedback_reg); - stage = feedback & IPR_IPL_INIT_STAGE_MASK; - stage_time = feedback & IPR_IPL_INIT_STAGE_TIME_MASK; - - ipr_dbg("IPL stage = 0x%lx, IPL stage time = %ld\n", stage, stage_time); - - /* sanity check the stage_time value */ - if (stage_time == 0) - stage_time = IPR_IPL_INIT_DEFAULT_STAGE_TIME; - else if (stage_time < IPR_IPL_INIT_MIN_STAGE_TIME) - stage_time = IPR_IPL_INIT_MIN_STAGE_TIME; - else if (stage_time > IPR_LONG_OPERATIONAL_TIMEOUT) - stage_time = IPR_LONG_OPERATIONAL_TIMEOUT; - - if (stage == IPR_IPL_INIT_STAGE_UNKNOWN) { - writel(IPR_PCII_IPL_STAGE_CHANGE, ioa_cfg->regs.set_interrupt_mask_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - stage_time = ioa_cfg->transop_timeout; - ipr_cmd->job_step = ipr_ioafp_identify_hrrq; - } else if (stage == IPR_IPL_INIT_STAGE_TRANSOP) { - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); - if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { - ipr_cmd->job_step = ipr_ioafp_identify_hrrq; - maskval = IPR_PCII_IPL_STAGE_CHANGE; - maskval = (maskval << 32) | IPR_PCII_IOA_TRANS_TO_OPER; - writeq(maskval, ioa_cfg->regs.set_interrupt_mask_reg); - int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - return IPR_RC_JOB_CONTINUE; - } - } - - ipr_cmd->timer.data = (unsigned long) ipr_cmd; - ipr_cmd->timer.expires = jiffies + stage_time * HZ; - ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout; - ipr_cmd->done = ipr_reset_ioa_job; - add_timer(&ipr_cmd->timer); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); - - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_enable_ioa - Enable the IOA following a reset. - * @ipr_cmd: ipr command struct - * - * This function reinitializes some control blocks and - * enables destructive diagnostics on the adapter. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - volatile u32 int_reg; - volatile u64 maskval; - - ENTER; - ipr_cmd->job_step = ipr_ioafp_identify_hrrq; - ipr_init_ioa_mem(ioa_cfg); - - ioa_cfg->allow_interrupts = 1; - if (ioa_cfg->sis64) { - /* Set the adapter to the correct endian mode. */ - writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg); - int_reg = readl(ioa_cfg->regs.endian_swap_reg); - } - - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg32); - - if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) { - writel((IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED), - ioa_cfg->regs.clr_interrupt_mask_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - return IPR_RC_JOB_CONTINUE; - } - - /* Enable destructive diagnostics on IOA */ - writel(ioa_cfg->doorbell, ioa_cfg->regs.set_uproc_interrupt_reg32); - - if (ioa_cfg->sis64) { - maskval = IPR_PCII_IPL_STAGE_CHANGE; - maskval = (maskval << 32) | IPR_PCII_OPER_INTERRUPTS; - writeq(maskval, ioa_cfg->regs.clr_interrupt_mask_reg); - } else - writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg32); - - int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - - dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n"); - - if (ioa_cfg->sis64) { - ipr_cmd->job_step = ipr_reset_next_stage; - return IPR_RC_JOB_CONTINUE; - } - - ipr_cmd->timer.data = (unsigned long) ipr_cmd; - ipr_cmd->timer.expires = jiffies + (ioa_cfg->transop_timeout * HZ); - ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout; - ipr_cmd->done = ipr_reset_ioa_job; - add_timer(&ipr_cmd->timer); - list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_wait_for_dump - Wait for a dump to timeout. - * @ipr_cmd: ipr command struct - * - * This function is invoked when an adapter dump has run out - * of processing time. - * - * Return value: - * IPR_RC_JOB_CONTINUE - **/ -static int ipr_reset_wait_for_dump(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - if (ioa_cfg->sdt_state == GET_DUMP) - ioa_cfg->sdt_state = WAIT_FOR_DUMP; - else if (ioa_cfg->sdt_state == READ_DUMP) - ioa_cfg->sdt_state = ABORT_DUMP; - - ioa_cfg->dump_timeout = 1; - ipr_cmd->job_step = ipr_reset_alert; - - return IPR_RC_JOB_CONTINUE; -} - -/** - * ipr_unit_check_no_data - Log a unit check/no data error log - * @ioa_cfg: ioa config struct - * - * Logs an error indicating the adapter unit checked, but for some - * reason, we were unable to fetch the unit check buffer. - * - * Return value: - * nothing - **/ -static void ipr_unit_check_no_data(struct ipr_ioa_cfg *ioa_cfg) -{ - ioa_cfg->errors_logged++; - dev_err(&ioa_cfg->pdev->dev, "IOA unit check with no data\n"); -} - -/** - * ipr_get_unit_check_buffer - Get the unit check buffer from the IOA - * @ioa_cfg: ioa config struct - * - * Fetches the unit check buffer from the adapter by clocking the data - * through the mailbox register. - * - * Return value: - * nothing - **/ -static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg) -{ - unsigned long mailbox; - struct ipr_hostrcb *hostrcb; - struct ipr_uc_sdt sdt; - int rc, length; - u32 ioasc; - - mailbox = readl(ioa_cfg->ioa_mailbox); - - if (!ioa_cfg->sis64 && !ipr_sdt_is_fmt2(mailbox)) { - ipr_unit_check_no_data(ioa_cfg); - return; - } - - memset(&sdt, 0, sizeof(struct ipr_uc_sdt)); - rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt, - (sizeof(struct ipr_uc_sdt)) / sizeof(__be32)); - - if (rc || !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY) || - ((be32_to_cpu(sdt.hdr.state) != IPR_FMT3_SDT_READY_TO_USE) && - (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE))) { - ipr_unit_check_no_data(ioa_cfg); - return; - } - - /* Find length of the first sdt entry (UC buffer) */ - if (be32_to_cpu(sdt.hdr.state) == IPR_FMT3_SDT_READY_TO_USE) - length = be32_to_cpu(sdt.entry[0].end_token); - else - length = (be32_to_cpu(sdt.entry[0].end_token) - - be32_to_cpu(sdt.entry[0].start_token)) & - IPR_FMT2_MBX_ADDR_MASK; - - hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next, - struct ipr_hostrcb, queue); - list_del(&hostrcb->queue); - memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam)); - - rc = ipr_get_ldump_data_section(ioa_cfg, - be32_to_cpu(sdt.entry[0].start_token), - (__be32 *)&hostrcb->hcam, - min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32)); - - if (!rc) { - ipr_handle_log_data(ioa_cfg, hostrcb); - ioasc = be32_to_cpu(hostrcb->hcam.u.error.fd_ioasc); - if (ioasc == IPR_IOASC_NR_IOA_RESET_REQUIRED && - ioa_cfg->sdt_state == GET_DUMP) - ioa_cfg->sdt_state = WAIT_FOR_DUMP; - } else - ipr_unit_check_no_data(ioa_cfg); - - list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q); -} - -/** - * ipr_reset_get_unit_check_job - Call to get the unit check buffer. - * @ipr_cmd: ipr command struct - * - * Description: This function will call to get the unit check buffer. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_reset_get_unit_check_job(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - ioa_cfg->ioa_unit_checked = 0; - ipr_get_unit_check_buffer(ioa_cfg); - ipr_cmd->job_step = ipr_reset_alert; - ipr_reset_start_timer(ipr_cmd, 0); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_restore_cfg_space - Restore PCI config space. - * @ipr_cmd: ipr command struct - * - * Description: This function restores the saved PCI config space of - * the adapter, fails all outstanding ops back to the callers, and - * fetches the dump/unit check if applicable to this reset. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - u32 int_reg; - - ENTER; - ioa_cfg->pdev->state_saved = true; - pci_restore_state(ioa_cfg->pdev); - - if (ipr_set_pcix_cmd_reg(ioa_cfg)) { - ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); - return IPR_RC_JOB_CONTINUE; - } - - ipr_fail_all_ops(ioa_cfg); - - if (ioa_cfg->sis64) { - /* Set the adapter to the correct endian mode. */ - writel(IPR_ENDIAN_SWAP_KEY, ioa_cfg->regs.endian_swap_reg); - int_reg = readl(ioa_cfg->regs.endian_swap_reg); - } - - if (ioa_cfg->ioa_unit_checked) { - if (ioa_cfg->sis64) { - ipr_cmd->job_step = ipr_reset_get_unit_check_job; - ipr_reset_start_timer(ipr_cmd, IPR_DUMP_DELAY_TIMEOUT); - return IPR_RC_JOB_RETURN; - } else { - ioa_cfg->ioa_unit_checked = 0; - ipr_get_unit_check_buffer(ioa_cfg); - ipr_cmd->job_step = ipr_reset_alert; - ipr_reset_start_timer(ipr_cmd, 0); - return IPR_RC_JOB_RETURN; - } - } - - if (ioa_cfg->in_ioa_bringdown) { - ipr_cmd->job_step = ipr_ioa_bringdown_done; - } else { - ipr_cmd->job_step = ipr_reset_enable_ioa; - - if (GET_DUMP == ioa_cfg->sdt_state) { - ioa_cfg->sdt_state = READ_DUMP; - ioa_cfg->dump_timeout = 0; - if (ioa_cfg->sis64) - ipr_reset_start_timer(ipr_cmd, IPR_SIS64_DUMP_TIMEOUT); - else - ipr_reset_start_timer(ipr_cmd, IPR_SIS32_DUMP_TIMEOUT); - ipr_cmd->job_step = ipr_reset_wait_for_dump; - schedule_work(&ioa_cfg->work_q); - return IPR_RC_JOB_RETURN; - } - } - - LEAVE; - return IPR_RC_JOB_CONTINUE; -} - -/** - * ipr_reset_bist_done - BIST has completed on the adapter. - * @ipr_cmd: ipr command struct - * - * Description: Unblock config space and resume the reset process. - * - * Return value: - * IPR_RC_JOB_CONTINUE - **/ -static int ipr_reset_bist_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - ENTER; - if (ioa_cfg->cfg_locked) - pci_cfg_access_unlock(ioa_cfg->pdev); - ioa_cfg->cfg_locked = 0; - ipr_cmd->job_step = ipr_reset_restore_cfg_space; - LEAVE; - return IPR_RC_JOB_CONTINUE; -} - -/** - * ipr_reset_start_bist - Run BIST on the adapter. - * @ipr_cmd: ipr command struct - * - * Description: This function runs BIST on the adapter, then delays 2 seconds. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - int rc = PCIBIOS_SUCCESSFUL; - - ENTER; - if (ioa_cfg->ipr_chip->bist_method == IPR_MMIO) - writel(IPR_UPROCI_SIS64_START_BIST, - ioa_cfg->regs.set_uproc_interrupt_reg32); - else - rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START); - - if (rc == PCIBIOS_SUCCESSFUL) { - ipr_cmd->job_step = ipr_reset_bist_done; - ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); - rc = IPR_RC_JOB_RETURN; - } else { - if (ioa_cfg->cfg_locked) - pci_cfg_access_unlock(ipr_cmd->ioa_cfg->pdev); - ioa_cfg->cfg_locked = 0; - ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR); - rc = IPR_RC_JOB_CONTINUE; - } - - LEAVE; - return rc; -} - -/** - * ipr_reset_slot_reset_done - Clear PCI reset to the adapter - * @ipr_cmd: ipr command struct - * - * Description: This clears PCI reset to the adapter and delays two seconds. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_reset_slot_reset_done(struct ipr_cmnd *ipr_cmd) -{ - ENTER; - pci_set_pcie_reset_state(ipr_cmd->ioa_cfg->pdev, pcie_deassert_reset); - ipr_cmd->job_step = ipr_reset_bist_done; - ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT); - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_slot_reset - Reset the PCI slot of the adapter. - * @ipr_cmd: ipr command struct - * - * Description: This asserts PCI reset to the adapter. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_reset_slot_reset(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct pci_dev *pdev = ioa_cfg->pdev; - - ENTER; - pci_set_pcie_reset_state(pdev, pcie_warm_reset); - ipr_cmd->job_step = ipr_reset_slot_reset_done; - ipr_reset_start_timer(ipr_cmd, IPR_PCI_RESET_TIMEOUT); - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_block_config_access_wait - Wait for permission to block config access - * @ipr_cmd: ipr command struct - * - * Description: This attempts to block config access to the IOA. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_block_config_access_wait(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - int rc = IPR_RC_JOB_CONTINUE; - - if (pci_cfg_access_trylock(ioa_cfg->pdev)) { - ioa_cfg->cfg_locked = 1; - ipr_cmd->job_step = ioa_cfg->reset; - } else { - if (ipr_cmd->u.time_left) { - rc = IPR_RC_JOB_RETURN; - ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; - ipr_reset_start_timer(ipr_cmd, - IPR_CHECK_FOR_RESET_TIMEOUT); - } else { - ipr_cmd->job_step = ioa_cfg->reset; - dev_err(&ioa_cfg->pdev->dev, - "Timed out waiting to lock config access. Resetting anyway.\n"); - } - } - - return rc; -} - -/** - * ipr_reset_block_config_access - Block config access to the IOA - * @ipr_cmd: ipr command struct - * - * Description: This attempts to block config access to the IOA - * - * Return value: - * IPR_RC_JOB_CONTINUE - **/ -static int ipr_reset_block_config_access(struct ipr_cmnd *ipr_cmd) -{ - ipr_cmd->ioa_cfg->cfg_locked = 0; - ipr_cmd->job_step = ipr_reset_block_config_access_wait; - ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; - return IPR_RC_JOB_CONTINUE; -} - -/** - * ipr_reset_allowed - Query whether or not IOA can be reset - * @ioa_cfg: ioa config struct - * - * Return value: - * 0 if reset not allowed / non-zero if reset is allowed - **/ -static int ipr_reset_allowed(struct ipr_ioa_cfg *ioa_cfg) -{ - volatile u32 temp_reg; - - temp_reg = readl(ioa_cfg->regs.sense_interrupt_reg); - return ((temp_reg & IPR_PCII_CRITICAL_OPERATION) == 0); -} - -/** - * ipr_reset_wait_to_start_bist - Wait for permission to reset IOA. - * @ipr_cmd: ipr command struct - * - * Description: This function waits for adapter permission to run BIST, - * then runs BIST. If the adapter does not give permission after a - * reasonable time, we will reset the adapter anyway. The impact of - * resetting the adapter without warning the adapter is the risk of - * losing the persistent error log on the adapter. If the adapter is - * reset while it is writing to the flash on the adapter, the flash - * segment will have bad ECC and be zeroed. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - int rc = IPR_RC_JOB_RETURN; - - if (!ipr_reset_allowed(ioa_cfg) && ipr_cmd->u.time_left) { - ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT; - ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); - } else { - ipr_cmd->job_step = ipr_reset_block_config_access; - rc = IPR_RC_JOB_CONTINUE; - } - - return rc; -} - -/** - * ipr_reset_alert - Alert the adapter of a pending reset - * @ipr_cmd: ipr command struct - * - * Description: This function alerts the adapter that it will be reset. - * If memory space is not currently enabled, proceed directly - * to running BIST on the adapter. The timer must always be started - * so we guarantee we do not run BIST from ipr_isr. - * - * Return value: - * IPR_RC_JOB_RETURN - **/ -static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - u16 cmd_reg; - int rc; - - ENTER; - rc = pci_read_config_word(ioa_cfg->pdev, PCI_COMMAND, &cmd_reg); - - if ((rc == PCIBIOS_SUCCESSFUL) && (cmd_reg & PCI_COMMAND_MEMORY)) { - ipr_mask_and_clear_interrupts(ioa_cfg, ~0); - writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg32); - ipr_cmd->job_step = ipr_reset_wait_to_start_bist; - } else { - ipr_cmd->job_step = ipr_reset_block_config_access; - } - - ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT; - ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_ucode_download_done - Microcode download completion - * @ipr_cmd: ipr command struct - * - * Description: This function unmaps the microcode download buffer. - * - * Return value: - * IPR_RC_JOB_CONTINUE - **/ -static int ipr_reset_ucode_download_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_sglist *sglist = ioa_cfg->ucode_sglist; - - pci_unmap_sg(ioa_cfg->pdev, sglist->scatterlist, - sglist->num_sg, DMA_TO_DEVICE); - - ipr_cmd->job_step = ipr_reset_alert; - return IPR_RC_JOB_CONTINUE; -} - -/** - * ipr_reset_ucode_download - Download microcode to the adapter - * @ipr_cmd: ipr command struct - * - * Description: This function checks to see if it there is microcode - * to download to the adapter. If there is, a download is performed. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_ucode_download(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - struct ipr_sglist *sglist = ioa_cfg->ucode_sglist; - - ENTER; - ipr_cmd->job_step = ipr_reset_alert; - - if (!sglist) - return IPR_RC_JOB_CONTINUE; - - ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); - ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_SCSICDB; - ipr_cmd->ioarcb.cmd_pkt.cdb[0] = WRITE_BUFFER; - ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_WR_BUF_DOWNLOAD_AND_SAVE; - ipr_cmd->ioarcb.cmd_pkt.cdb[6] = (sglist->buffer_len & 0xff0000) >> 16; - ipr_cmd->ioarcb.cmd_pkt.cdb[7] = (sglist->buffer_len & 0x00ff00) >> 8; - ipr_cmd->ioarcb.cmd_pkt.cdb[8] = sglist->buffer_len & 0x0000ff; - - if (ioa_cfg->sis64) - ipr_build_ucode_ioadl64(ipr_cmd, sglist); - else - ipr_build_ucode_ioadl(ipr_cmd, sglist); - ipr_cmd->job_step = ipr_reset_ucode_download_done; - - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, - IPR_WRITE_BUFFER_TIMEOUT); - - LEAVE; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_reset_shutdown_ioa - Shutdown the adapter - * @ipr_cmd: ipr command struct - * - * Description: This function issues an adapter shutdown of the - * specified type to the specified adapter as part of the - * adapter reset job. - * - * Return value: - * IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN - **/ -static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - enum ipr_shutdown_type shutdown_type = ipr_cmd->u.shutdown_type; - unsigned long timeout; - int rc = IPR_RC_JOB_CONTINUE; - - ENTER; - if (shutdown_type != IPR_SHUTDOWN_NONE && !ioa_cfg->ioa_is_dead) { - ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); - ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD; - ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN; - ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type; - - if (shutdown_type == IPR_SHUTDOWN_NORMAL) - timeout = IPR_SHUTDOWN_TIMEOUT; - else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL) - timeout = IPR_INTERNAL_TIMEOUT; - else if (ioa_cfg->dual_raid && ipr_dual_ioa_raid) - timeout = IPR_DUAL_IOA_ABBR_SHUTDOWN_TO; - else - timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT; - - ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout); - - rc = IPR_RC_JOB_RETURN; - ipr_cmd->job_step = ipr_reset_ucode_download; - } else - ipr_cmd->job_step = ipr_reset_alert; - - LEAVE; - return rc; -} - -/** - * ipr_reset_ioa_job - Adapter reset job - * @ipr_cmd: ipr command struct - * - * Description: This function is the job router for the adapter reset job. - * - * Return value: - * none - **/ -static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd) -{ - u32 rc, ioasc; - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - do { - ioasc = be32_to_cpu(ipr_cmd->s.ioasa.hdr.ioasc); - - if (ioa_cfg->reset_cmd != ipr_cmd) { - /* - * We are doing nested adapter resets and this is - * not the current reset job. - */ - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - return; - } - - if (IPR_IOASC_SENSE_KEY(ioasc)) { - rc = ipr_cmd->job_step_failed(ipr_cmd); - if (rc == IPR_RC_JOB_RETURN) - return; - } - - ipr_reinit_ipr_cmnd(ipr_cmd); - ipr_cmd->job_step_failed = ipr_reset_cmd_failed; - rc = ipr_cmd->job_step(ipr_cmd); - } while(rc == IPR_RC_JOB_CONTINUE); -} - -/** - * _ipr_initiate_ioa_reset - Initiate an adapter reset - * @ioa_cfg: ioa config struct - * @job_step: first job step of reset job - * @shutdown_type: shutdown type - * - * Description: This function will initiate the reset of the given adapter - * starting at the selected job step. - * If the caller needs to wait on the completion of the reset, - * the caller must sleep on the reset_wait_q. - * - * Return value: - * none - **/ -static void _ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg, - int (*job_step) (struct ipr_cmnd *), - enum ipr_shutdown_type shutdown_type) -{ - struct ipr_cmnd *ipr_cmd; - - ioa_cfg->in_reset_reload = 1; - ioa_cfg->allow_cmds = 0; - scsi_block_requests(ioa_cfg->host); - - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - ioa_cfg->reset_cmd = ipr_cmd; - ipr_cmd->job_step = job_step; - ipr_cmd->u.shutdown_type = shutdown_type; - - ipr_reset_ioa_job(ipr_cmd); -} - -/** - * ipr_initiate_ioa_reset - Initiate an adapter reset - * @ioa_cfg: ioa config struct - * @shutdown_type: shutdown type - * - * Description: This function will initiate the reset of the given adapter. - * If the caller needs to wait on the completion of the reset, - * the caller must sleep on the reset_wait_q. - * - * Return value: - * none - **/ -static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg, - enum ipr_shutdown_type shutdown_type) -{ - if (ioa_cfg->ioa_is_dead) - return; - - if (ioa_cfg->in_reset_reload) { - if (ioa_cfg->sdt_state == GET_DUMP) - ioa_cfg->sdt_state = WAIT_FOR_DUMP; - else if (ioa_cfg->sdt_state == READ_DUMP) - ioa_cfg->sdt_state = ABORT_DUMP; - } - - if (ioa_cfg->reset_retries++ >= IPR_NUM_RESET_RELOAD_RETRIES) { - dev_err(&ioa_cfg->pdev->dev, - "IOA taken offline - error recovery failed\n"); - - ioa_cfg->reset_retries = 0; - ioa_cfg->ioa_is_dead = 1; - - if (ioa_cfg->in_ioa_bringdown) { - ioa_cfg->reset_cmd = NULL; - ioa_cfg->in_reset_reload = 0; - ipr_fail_all_ops(ioa_cfg); - wake_up_all(&ioa_cfg->reset_wait_q); - - spin_unlock_irq(ioa_cfg->host->host_lock); - scsi_unblock_requests(ioa_cfg->host); - spin_lock_irq(ioa_cfg->host->host_lock); - return; - } else { - ioa_cfg->in_ioa_bringdown = 1; - shutdown_type = IPR_SHUTDOWN_NONE; - } - } - - _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_shutdown_ioa, - shutdown_type); -} - -/** - * ipr_reset_freeze - Hold off all I/O activity - * @ipr_cmd: ipr command struct - * - * Description: If the PCI slot is frozen, hold off all I/O - * activity; then, as soon as the slot is available again, - * initiate an adapter reset. - */ -static int ipr_reset_freeze(struct ipr_cmnd *ipr_cmd) -{ - /* Disallow new interrupts, avoid loop */ - ipr_cmd->ioa_cfg->allow_interrupts = 0; - list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q); - ipr_cmd->done = ipr_reset_ioa_job; - return IPR_RC_JOB_RETURN; -} - -/** - * ipr_pci_frozen - Called when slot has experienced a PCI bus error. - * @pdev: PCI device struct - * - * Description: This routine is called to tell us that the PCI bus - * is down. Can't do anything here, except put the device driver - * into a holding pattern, waiting for the PCI bus to come back. - */ -static void ipr_pci_frozen(struct pci_dev *pdev) -{ - unsigned long flags = 0; - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); - - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_freeze, IPR_SHUTDOWN_NONE); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); -} - -/** - * ipr_pci_slot_reset - Called when PCI slot has been reset. - * @pdev: PCI device struct - * - * Description: This routine is called by the pci error recovery - * code after the PCI slot has been reset, just before we - * should resume normal operations. - */ -static pci_ers_result_t ipr_pci_slot_reset(struct pci_dev *pdev) -{ - unsigned long flags = 0; - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); - - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - if (ioa_cfg->needs_warm_reset) - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - else - _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_restore_cfg_space, - IPR_SHUTDOWN_NONE); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - return PCI_ERS_RESULT_RECOVERED; -} - -/** - * ipr_pci_perm_failure - Called when PCI slot is dead for good. - * @pdev: PCI device struct - * - * Description: This routine is called when the PCI bus has - * permanently failed. - */ -static void ipr_pci_perm_failure(struct pci_dev *pdev) -{ - unsigned long flags = 0; - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); - - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - if (ioa_cfg->sdt_state == WAIT_FOR_DUMP) - ioa_cfg->sdt_state = ABORT_DUMP; - ioa_cfg->reset_retries = IPR_NUM_RESET_RELOAD_RETRIES; - ioa_cfg->in_ioa_bringdown = 1; - ioa_cfg->allow_cmds = 0; - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); -} - -/** - * ipr_pci_error_detected - Called when a PCI error is detected. - * @pdev: PCI device struct - * @state: PCI channel state - * - * Description: Called when a PCI error is detected. - * - * Return value: - * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT - */ -static pci_ers_result_t ipr_pci_error_detected(struct pci_dev *pdev, - pci_channel_state_t state) -{ - switch (state) { - case pci_channel_io_frozen: - ipr_pci_frozen(pdev); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - ipr_pci_perm_failure(pdev); - return PCI_ERS_RESULT_DISCONNECT; - break; - default: - break; - } - return PCI_ERS_RESULT_NEED_RESET; -} - -/** - * ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..) - * @ioa_cfg: ioa cfg struct - * - * Description: This is the second phase of adapter intialization - * This function takes care of initilizing the adapter to the point - * where it can accept new commands. - - * Return value: - * 0 on success / -EIO on failure - **/ -static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg) -{ - int rc = 0; - unsigned long host_lock_flags = 0; - - ENTER; - spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); - dev_dbg(&ioa_cfg->pdev->dev, "ioa_cfg adx: 0x%p\n", ioa_cfg); - if (ioa_cfg->needs_hard_reset) { - ioa_cfg->needs_hard_reset = 0; - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - } else - _ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_enable_ioa, - IPR_SHUTDOWN_NONE); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); - - if (ioa_cfg->ioa_is_dead) { - rc = -EIO; - } else if (ipr_invalid_adapter(ioa_cfg)) { - if (!ipr_testmode) - rc = -EIO; - - dev_err(&ioa_cfg->pdev->dev, - "Adapter not supported in this hardware configuration.\n"); - } - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); - - LEAVE; - return rc; -} - -/** - * ipr_free_cmd_blks - Frees command blocks allocated for an adapter - * @ioa_cfg: ioa config struct - * - * Return value: - * none - **/ -static void ipr_free_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) -{ - int i; - - for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { - if (ioa_cfg->ipr_cmnd_list[i]) - pci_pool_free(ioa_cfg->ipr_cmd_pool, - ioa_cfg->ipr_cmnd_list[i], - ioa_cfg->ipr_cmnd_list_dma[i]); - - ioa_cfg->ipr_cmnd_list[i] = NULL; - } - - if (ioa_cfg->ipr_cmd_pool) - pci_pool_destroy (ioa_cfg->ipr_cmd_pool); - - kfree(ioa_cfg->ipr_cmnd_list); - kfree(ioa_cfg->ipr_cmnd_list_dma); - ioa_cfg->ipr_cmnd_list = NULL; - ioa_cfg->ipr_cmnd_list_dma = NULL; - ioa_cfg->ipr_cmd_pool = NULL; -} - -/** - * ipr_free_mem - Frees memory allocated for an adapter - * @ioa_cfg: ioa cfg struct - * - * Return value: - * nothing - **/ -static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg) -{ - int i; - - kfree(ioa_cfg->res_entries); - pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_misc_cbs), - ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma); - ipr_free_cmd_blks(ioa_cfg); - pci_free_consistent(ioa_cfg->pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, - ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma); - pci_free_consistent(ioa_cfg->pdev, ioa_cfg->cfg_table_size, - ioa_cfg->u.cfg_table, - ioa_cfg->cfg_table_dma); - - for (i = 0; i < IPR_NUM_HCAMS; i++) { - pci_free_consistent(ioa_cfg->pdev, - sizeof(struct ipr_hostrcb), - ioa_cfg->hostrcb[i], - ioa_cfg->hostrcb_dma[i]); - } - - ipr_free_dump(ioa_cfg); - kfree(ioa_cfg->trace); -} - -/** - * ipr_free_all_resources - Free all allocated resources for an adapter. - * @ipr_cmd: ipr command struct - * - * This function frees all allocated resources for the - * specified adapter. - * - * Return value: - * none - **/ -static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg) -{ - struct pci_dev *pdev = ioa_cfg->pdev; - - ENTER; - free_irq(pdev->irq, ioa_cfg); - pci_disable_msi(pdev); - iounmap(ioa_cfg->hdw_dma_regs); - pci_release_regions(pdev); - ipr_free_mem(ioa_cfg); - scsi_host_put(ioa_cfg->host); - pci_disable_device(pdev); - LEAVE; -} - -/** - * ipr_alloc_cmd_blks - Allocate command blocks for an adapter - * @ioa_cfg: ioa config struct - * - * Return value: - * 0 on success / -ENOMEM on allocation failure - **/ -static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg) -{ - struct ipr_cmnd *ipr_cmd; - struct ipr_ioarcb *ioarcb; - dma_addr_t dma_addr; - int i; - - ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev, - sizeof(struct ipr_cmnd), 512, 0); - - if (!ioa_cfg->ipr_cmd_pool) - return -ENOMEM; - - ioa_cfg->ipr_cmnd_list = kcalloc(IPR_NUM_CMD_BLKS, sizeof(struct ipr_cmnd *), GFP_KERNEL); - ioa_cfg->ipr_cmnd_list_dma = kcalloc(IPR_NUM_CMD_BLKS, sizeof(dma_addr_t), GFP_KERNEL); - - if (!ioa_cfg->ipr_cmnd_list || !ioa_cfg->ipr_cmnd_list_dma) { - ipr_free_cmd_blks(ioa_cfg); - return -ENOMEM; - } - - for (i = 0; i < IPR_NUM_CMD_BLKS; i++) { - ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr); - - if (!ipr_cmd) { - ipr_free_cmd_blks(ioa_cfg); - return -ENOMEM; - } - - memset(ipr_cmd, 0, sizeof(*ipr_cmd)); - ioa_cfg->ipr_cmnd_list[i] = ipr_cmd; - ioa_cfg->ipr_cmnd_list_dma[i] = dma_addr; - - ioarcb = &ipr_cmd->ioarcb; - ipr_cmd->dma_addr = dma_addr; - if (ioa_cfg->sis64) - ioarcb->a.ioarcb_host_pci_addr64 = cpu_to_be64(dma_addr); - else - ioarcb->a.ioarcb_host_pci_addr = cpu_to_be32(dma_addr); - - ioarcb->host_response_handle = cpu_to_be32(i << 2); - if (ioa_cfg->sis64) { - ioarcb->u.sis64_addr_data.data_ioadl_addr = - cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64)); - ioarcb->u.sis64_addr_data.ioasa_host_pci_addr = - cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, s.ioasa64)); - } else { - ioarcb->write_ioadl_addr = - cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl)); - ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr; - ioarcb->ioasa_host_pci_addr = - cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, s.ioasa)); - } - ioarcb->ioasa_len = cpu_to_be16(sizeof(struct ipr_ioasa)); - ipr_cmd->cmd_index = i; - ipr_cmd->ioa_cfg = ioa_cfg; - ipr_cmd->sense_buffer_dma = dma_addr + - offsetof(struct ipr_cmnd, sense_buffer); - - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); - } - - return 0; -} - -/** - * ipr_alloc_mem - Allocate memory for an adapter - * @ioa_cfg: ioa config struct - * - * Return value: - * 0 on success / non-zero for error - **/ -static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg) -{ - struct pci_dev *pdev = ioa_cfg->pdev; - int i, rc = -ENOMEM; - - ENTER; - ioa_cfg->res_entries = kzalloc(sizeof(struct ipr_resource_entry) * - ioa_cfg->max_devs_supported, GFP_KERNEL); - - if (!ioa_cfg->res_entries) - goto out; - - if (ioa_cfg->sis64) { - ioa_cfg->target_ids = kzalloc(sizeof(unsigned long) * - BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL); - ioa_cfg->array_ids = kzalloc(sizeof(unsigned long) * - BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL); - ioa_cfg->vset_ids = kzalloc(sizeof(unsigned long) * - BITS_TO_LONGS(ioa_cfg->max_devs_supported), GFP_KERNEL); - } - - for (i = 0; i < ioa_cfg->max_devs_supported; i++) { - list_add_tail(&ioa_cfg->res_entries[i].queue, &ioa_cfg->free_res_q); - ioa_cfg->res_entries[i].ioa_cfg = ioa_cfg; - } - - ioa_cfg->vpd_cbs = pci_alloc_consistent(ioa_cfg->pdev, - sizeof(struct ipr_misc_cbs), - &ioa_cfg->vpd_cbs_dma); - - if (!ioa_cfg->vpd_cbs) - goto out_free_res_entries; - - if (ipr_alloc_cmd_blks(ioa_cfg)) - goto out_free_vpd_cbs; - - ioa_cfg->host_rrq = pci_alloc_consistent(ioa_cfg->pdev, - sizeof(u32) * IPR_NUM_CMD_BLKS, - &ioa_cfg->host_rrq_dma); - - if (!ioa_cfg->host_rrq) - goto out_ipr_free_cmd_blocks; - - ioa_cfg->u.cfg_table = pci_alloc_consistent(ioa_cfg->pdev, - ioa_cfg->cfg_table_size, - &ioa_cfg->cfg_table_dma); - - if (!ioa_cfg->u.cfg_table) - goto out_free_host_rrq; - - for (i = 0; i < IPR_NUM_HCAMS; i++) { - ioa_cfg->hostrcb[i] = pci_alloc_consistent(ioa_cfg->pdev, - sizeof(struct ipr_hostrcb), - &ioa_cfg->hostrcb_dma[i]); - - if (!ioa_cfg->hostrcb[i]) - goto out_free_hostrcb_dma; - - ioa_cfg->hostrcb[i]->hostrcb_dma = - ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam); - ioa_cfg->hostrcb[i]->ioa_cfg = ioa_cfg; - list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q); - } - - ioa_cfg->trace = kzalloc(sizeof(struct ipr_trace_entry) * - IPR_NUM_TRACE_ENTRIES, GFP_KERNEL); - - if (!ioa_cfg->trace) - goto out_free_hostrcb_dma; - - rc = 0; -out: - LEAVE; - return rc; - -out_free_hostrcb_dma: - while (i-- > 0) { - pci_free_consistent(pdev, sizeof(struct ipr_hostrcb), - ioa_cfg->hostrcb[i], - ioa_cfg->hostrcb_dma[i]); - } - pci_free_consistent(pdev, ioa_cfg->cfg_table_size, - ioa_cfg->u.cfg_table, - ioa_cfg->cfg_table_dma); -out_free_host_rrq: - pci_free_consistent(pdev, sizeof(u32) * IPR_NUM_CMD_BLKS, - ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma); -out_ipr_free_cmd_blocks: - ipr_free_cmd_blks(ioa_cfg); -out_free_vpd_cbs: - pci_free_consistent(pdev, sizeof(struct ipr_misc_cbs), - ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma); -out_free_res_entries: - kfree(ioa_cfg->res_entries); - goto out; -} - -/** - * ipr_initialize_bus_attr - Initialize SCSI bus attributes to default values - * @ioa_cfg: ioa config struct - * - * Return value: - * none - **/ -static void __devinit ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg) -{ - int i; - - for (i = 0; i < IPR_MAX_NUM_BUSES; i++) { - ioa_cfg->bus_attr[i].bus = i; - ioa_cfg->bus_attr[i].qas_enabled = 0; - ioa_cfg->bus_attr[i].bus_width = IPR_DEFAULT_BUS_WIDTH; - if (ipr_max_speed < ARRAY_SIZE(ipr_max_bus_speeds)) - ioa_cfg->bus_attr[i].max_xfer_rate = ipr_max_bus_speeds[ipr_max_speed]; - else - ioa_cfg->bus_attr[i].max_xfer_rate = IPR_U160_SCSI_RATE; - } -} - -/** - * ipr_init_ioa_cfg - Initialize IOA config struct - * @ioa_cfg: ioa config struct - * @host: scsi host struct - * @pdev: PCI dev struct - * - * Return value: - * none - **/ -static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg, - struct Scsi_Host *host, struct pci_dev *pdev) -{ - const struct ipr_interrupt_offsets *p; - struct ipr_interrupts *t; - void __iomem *base; - - ioa_cfg->host = host; - ioa_cfg->pdev = pdev; - ioa_cfg->log_level = ipr_log_level; - ioa_cfg->doorbell = IPR_DOORBELL; - sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER); - sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL); - sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL); - sprintf(ioa_cfg->ipr_pending_label, IPR_PENDQ_LABEL); - sprintf(ioa_cfg->cfg_table_start, IPR_CFG_TBL_START); - sprintf(ioa_cfg->resource_table_label, IPR_RES_TABLE_LABEL); - sprintf(ioa_cfg->ipr_hcam_label, IPR_HCAM_LABEL); - sprintf(ioa_cfg->ipr_cmd_label, IPR_CMD_LABEL); - - INIT_LIST_HEAD(&ioa_cfg->free_q); - INIT_LIST_HEAD(&ioa_cfg->pending_q); - INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q); - INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q); - INIT_LIST_HEAD(&ioa_cfg->free_res_q); - INIT_LIST_HEAD(&ioa_cfg->used_res_q); - INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread); - init_waitqueue_head(&ioa_cfg->reset_wait_q); - init_waitqueue_head(&ioa_cfg->msi_wait_q); - ioa_cfg->sdt_state = INACTIVE; - - ipr_initialize_bus_attr(ioa_cfg); - ioa_cfg->max_devs_supported = ipr_max_devs; - - if (ioa_cfg->sis64) { - host->max_id = IPR_MAX_SIS64_TARGETS_PER_BUS; - host->max_lun = IPR_MAX_SIS64_LUNS_PER_TARGET; - if (ipr_max_devs > IPR_MAX_SIS64_DEVS) - ioa_cfg->max_devs_supported = IPR_MAX_SIS64_DEVS; - } else { - host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS; - host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET; - if (ipr_max_devs > IPR_MAX_PHYSICAL_DEVS) - ioa_cfg->max_devs_supported = IPR_MAX_PHYSICAL_DEVS; - } - host->max_channel = IPR_MAX_BUS_TO_SCAN; - host->unique_id = host->host_no; - host->max_cmd_len = IPR_MAX_CDB_LEN; - host->can_queue = ioa_cfg->max_cmds; - pci_set_drvdata(pdev, ioa_cfg); - - p = &ioa_cfg->chip_cfg->regs; - t = &ioa_cfg->regs; - base = ioa_cfg->hdw_dma_regs; - - t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg; - t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg; - t->clr_interrupt_mask_reg32 = base + p->clr_interrupt_mask_reg32; - t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg; - t->sense_interrupt_mask_reg32 = base + p->sense_interrupt_mask_reg32; - t->clr_interrupt_reg = base + p->clr_interrupt_reg; - t->clr_interrupt_reg32 = base + p->clr_interrupt_reg32; - t->sense_interrupt_reg = base + p->sense_interrupt_reg; - t->sense_interrupt_reg32 = base + p->sense_interrupt_reg32; - t->ioarrin_reg = base + p->ioarrin_reg; - t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg; - t->sense_uproc_interrupt_reg32 = base + p->sense_uproc_interrupt_reg32; - t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg; - t->set_uproc_interrupt_reg32 = base + p->set_uproc_interrupt_reg32; - t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg; - t->clr_uproc_interrupt_reg32 = base + p->clr_uproc_interrupt_reg32; - - if (ioa_cfg->sis64) { - t->init_feedback_reg = base + p->init_feedback_reg; - t->dump_addr_reg = base + p->dump_addr_reg; - t->dump_data_reg = base + p->dump_data_reg; - t->endian_swap_reg = base + p->endian_swap_reg; - } -} - -/** - * ipr_get_chip_info - Find adapter chip information - * @dev_id: PCI device id struct - * - * Return value: - * ptr to chip information on success / NULL on failure - **/ -static const struct ipr_chip_t * __devinit -ipr_get_chip_info(const struct pci_device_id *dev_id) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(ipr_chip); i++) - if (ipr_chip[i].vendor == dev_id->vendor && - ipr_chip[i].device == dev_id->device) - return &ipr_chip[i]; - return NULL; -} - -/** - * ipr_test_intr - Handle the interrupt generated in ipr_test_msi(). - * @pdev: PCI device struct - * - * Description: Simply set the msi_received flag to 1 indicating that - * Message Signaled Interrupts are supported. - * - * Return value: - * 0 on success / non-zero on failure - **/ -static irqreturn_t __devinit ipr_test_intr(int irq, void *devp) -{ - struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp; - unsigned long lock_flags = 0; - irqreturn_t rc = IRQ_HANDLED; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - - ioa_cfg->msi_received = 1; - wake_up(&ioa_cfg->msi_wait_q); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - return rc; -} - -/** - * ipr_test_msi - Test for Message Signaled Interrupt (MSI) support. - * @pdev: PCI device struct - * - * Description: The return value from pci_enable_msi() can not always be - * trusted. This routine sets up and initiates a test interrupt to determine - * if the interrupt is received via the ipr_test_intr() service routine. - * If the tests fails, the driver will fall back to LSI. - * - * Return value: - * 0 on success / non-zero on failure - **/ -static int __devinit ipr_test_msi(struct ipr_ioa_cfg *ioa_cfg, - struct pci_dev *pdev) -{ - int rc; - volatile u32 int_reg; - unsigned long lock_flags = 0; - - ENTER; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - init_waitqueue_head(&ioa_cfg->msi_wait_q); - ioa_cfg->msi_received = 0; - ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); - writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.clr_interrupt_mask_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - rc = request_irq(pdev->irq, ipr_test_intr, 0, IPR_NAME, ioa_cfg); - if (rc) { - dev_err(&pdev->dev, "Can not assign irq %d\n", pdev->irq); - return rc; - } else if (ipr_debug) - dev_info(&pdev->dev, "IRQ assigned: %d\n", pdev->irq); - - writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE, ioa_cfg->regs.sense_interrupt_reg32); - int_reg = readl(ioa_cfg->regs.sense_interrupt_reg); - wait_event_timeout(ioa_cfg->msi_wait_q, ioa_cfg->msi_received, HZ); - ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - if (!ioa_cfg->msi_received) { - /* MSI test failed */ - dev_info(&pdev->dev, "MSI test failed. Falling back to LSI.\n"); - rc = -EOPNOTSUPP; - } else if (ipr_debug) - dev_info(&pdev->dev, "MSI test succeeded.\n"); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - - free_irq(pdev->irq, ioa_cfg); - - LEAVE; - - return rc; -} - -/** - * ipr_probe_ioa - Allocates memory and does first stage of initialization - * @pdev: PCI device struct - * @dev_id: PCI device id struct - * - * Return value: - * 0 on success / non-zero on failure - **/ -static int __devinit ipr_probe_ioa(struct pci_dev *pdev, - const struct pci_device_id *dev_id) -{ - struct ipr_ioa_cfg *ioa_cfg; - struct Scsi_Host *host; - unsigned long ipr_regs_pci; - void __iomem *ipr_regs; - int rc = PCIBIOS_SUCCESSFUL; - volatile u32 mask, uproc, interrupts; - - ENTER; - - if ((rc = pci_enable_device(pdev))) { - dev_err(&pdev->dev, "Cannot enable adapter\n"); - goto out; - } - - dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq); - - host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg)); - - if (!host) { - dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n"); - rc = -ENOMEM; - goto out_disable; - } - - ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata; - memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg)); - ata_host_init(&ioa_cfg->ata_host, &pdev->dev, - sata_port_info.flags, &ipr_sata_ops); - - ioa_cfg->ipr_chip = ipr_get_chip_info(dev_id); - - if (!ioa_cfg->ipr_chip) { - dev_err(&pdev->dev, "Unknown adapter chipset 0x%04X 0x%04X\n", - dev_id->vendor, dev_id->device); - goto out_scsi_host_put; - } - - /* set SIS 32 or SIS 64 */ - ioa_cfg->sis64 = ioa_cfg->ipr_chip->sis_type == IPR_SIS64 ? 1 : 0; - ioa_cfg->chip_cfg = ioa_cfg->ipr_chip->cfg; - ioa_cfg->clear_isr = ioa_cfg->chip_cfg->clear_isr; - ioa_cfg->max_cmds = ioa_cfg->chip_cfg->max_cmds; - - if (ipr_transop_timeout) - ioa_cfg->transop_timeout = ipr_transop_timeout; - else if (dev_id->driver_data & IPR_USE_LONG_TRANSOP_TIMEOUT) - ioa_cfg->transop_timeout = IPR_LONG_OPERATIONAL_TIMEOUT; - else - ioa_cfg->transop_timeout = IPR_OPERATIONAL_TIMEOUT; - - ioa_cfg->revid = pdev->revision; - - ipr_regs_pci = pci_resource_start(pdev, 0); - - rc = pci_request_regions(pdev, IPR_NAME); - if (rc < 0) { - dev_err(&pdev->dev, - "Couldn't register memory range of registers\n"); - goto out_scsi_host_put; - } - - ipr_regs = pci_ioremap_bar(pdev, 0); - - if (!ipr_regs) { - dev_err(&pdev->dev, - "Couldn't map memory range of registers\n"); - rc = -ENOMEM; - goto out_release_regions; - } - - ioa_cfg->hdw_dma_regs = ipr_regs; - ioa_cfg->hdw_dma_regs_pci = ipr_regs_pci; - ioa_cfg->ioa_mailbox = ioa_cfg->chip_cfg->mailbox + ipr_regs; - - ipr_init_ioa_cfg(ioa_cfg, host, pdev); - - pci_set_master(pdev); - - if (ioa_cfg->sis64) { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc < 0) { - dev_dbg(&pdev->dev, "Failed to set 64 bit PCI DMA mask\n"); - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - } - - } else - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - - if (rc < 0) { - dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); - goto cleanup_nomem; - } - - rc = pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, - ioa_cfg->chip_cfg->cache_line_size); - - if (rc != PCIBIOS_SUCCESSFUL) { - dev_err(&pdev->dev, "Write of cache line size failed\n"); - rc = -EIO; - goto cleanup_nomem; - } - - /* Enable MSI style interrupts if they are supported. */ - if (ioa_cfg->ipr_chip->intr_type == IPR_USE_MSI && !pci_enable_msi(pdev)) { - rc = ipr_test_msi(ioa_cfg, pdev); - if (rc == -EOPNOTSUPP) - pci_disable_msi(pdev); - else if (rc) - goto out_msi_disable; - else - dev_info(&pdev->dev, "MSI enabled with IRQ: %d\n", pdev->irq); - } else if (ipr_debug) - dev_info(&pdev->dev, "Cannot enable MSI.\n"); - - /* Save away PCI config space for use following IOA reset */ - rc = pci_save_state(pdev); - - if (rc != PCIBIOS_SUCCESSFUL) { - dev_err(&pdev->dev, "Failed to save PCI config space\n"); - rc = -EIO; - goto out_msi_disable; - } - - if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg))) - goto out_msi_disable; - - if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg))) - goto out_msi_disable; - - if (ioa_cfg->sis64) - ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr64) - + ((sizeof(struct ipr_config_table_entry64) - * ioa_cfg->max_devs_supported))); - else - ioa_cfg->cfg_table_size = (sizeof(struct ipr_config_table_hdr) - + ((sizeof(struct ipr_config_table_entry) - * ioa_cfg->max_devs_supported))); - - rc = ipr_alloc_mem(ioa_cfg); - if (rc < 0) { - dev_err(&pdev->dev, - "Couldn't allocate enough memory for device driver!\n"); - goto out_msi_disable; - } - - /* - * If HRRQ updated interrupt is not masked, or reset alert is set, - * the card is in an unknown state and needs a hard reset - */ - mask = readl(ioa_cfg->regs.sense_interrupt_mask_reg32); - interrupts = readl(ioa_cfg->regs.sense_interrupt_reg32); - uproc = readl(ioa_cfg->regs.sense_uproc_interrupt_reg32); - if ((mask & IPR_PCII_HRRQ_UPDATED) == 0 || (uproc & IPR_UPROCI_RESET_ALERT)) - ioa_cfg->needs_hard_reset = 1; - if ((interrupts & IPR_PCII_ERROR_INTERRUPTS) || reset_devices) - ioa_cfg->needs_hard_reset = 1; - if (interrupts & IPR_PCII_IOA_UNIT_CHECKED) - ioa_cfg->ioa_unit_checked = 1; - - ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER); - rc = request_irq(pdev->irq, ipr_isr, - ioa_cfg->msi_received ? 0 : IRQF_SHARED, - IPR_NAME, ioa_cfg); - - if (rc) { - dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n", - pdev->irq, rc); - goto cleanup_nolog; - } - - if ((dev_id->driver_data & IPR_USE_PCI_WARM_RESET) || - (dev_id->device == PCI_DEVICE_ID_IBM_OBSIDIAN_E && !ioa_cfg->revid)) { - ioa_cfg->needs_warm_reset = 1; - ioa_cfg->reset = ipr_reset_slot_reset; - } else - ioa_cfg->reset = ipr_reset_start_bist; - - spin_lock(&ipr_driver_lock); - list_add_tail(&ioa_cfg->queue, &ipr_ioa_head); - spin_unlock(&ipr_driver_lock); - - LEAVE; -out: - return rc; - -cleanup_nolog: - ipr_free_mem(ioa_cfg); -out_msi_disable: - pci_disable_msi(pdev); -cleanup_nomem: - iounmap(ipr_regs); -out_release_regions: - pci_release_regions(pdev); -out_scsi_host_put: - scsi_host_put(host); -out_disable: - pci_disable_device(pdev); - goto out; -} - -/** - * ipr_scan_vsets - Scans for VSET devices - * @ioa_cfg: ioa config struct - * - * Description: Since the VSET resources do not follow SAM in that we can have - * sparse LUNs with no LUN 0, we have to scan for these ourselves. - * - * Return value: - * none - **/ -static void ipr_scan_vsets(struct ipr_ioa_cfg *ioa_cfg) -{ - int target, lun; - - for (target = 0; target < IPR_MAX_NUM_TARGETS_PER_BUS; target++) - for (lun = 0; lun < IPR_MAX_NUM_VSET_LUNS_PER_TARGET; lun++ ) - scsi_add_device(ioa_cfg->host, IPR_VSET_BUS, target, lun); -} - -/** - * ipr_initiate_ioa_bringdown - Bring down an adapter - * @ioa_cfg: ioa config struct - * @shutdown_type: shutdown type - * - * Description: This function will initiate bringing down the adapter. - * This consists of issuing an IOA shutdown to the adapter - * to flush the cache, and running BIST. - * If the caller needs to wait on the completion of the reset, - * the caller must sleep on the reset_wait_q. - * - * Return value: - * none - **/ -static void ipr_initiate_ioa_bringdown(struct ipr_ioa_cfg *ioa_cfg, - enum ipr_shutdown_type shutdown_type) -{ - ENTER; - if (ioa_cfg->sdt_state == WAIT_FOR_DUMP) - ioa_cfg->sdt_state = ABORT_DUMP; - ioa_cfg->reset_retries = 0; - ioa_cfg->in_ioa_bringdown = 1; - ipr_initiate_ioa_reset(ioa_cfg, shutdown_type); - LEAVE; -} - -/** - * __ipr_remove - Remove a single adapter - * @pdev: pci device struct - * - * Adapter hot plug remove entry point. - * - * Return value: - * none - **/ -static void __ipr_remove(struct pci_dev *pdev) -{ - unsigned long host_lock_flags = 0; - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); - ENTER; - - spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); - while(ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); - } - - ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); - - spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - flush_work_sync(&ioa_cfg->work_q); - spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags); - - spin_lock(&ipr_driver_lock); - list_del(&ioa_cfg->queue); - spin_unlock(&ipr_driver_lock); - - if (ioa_cfg->sdt_state == ABORT_DUMP) - ioa_cfg->sdt_state = WAIT_FOR_DUMP; - spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags); - - ipr_free_all_resources(ioa_cfg); - - LEAVE; -} - -/** - * ipr_remove - IOA hot plug remove entry point - * @pdev: pci device struct - * - * Adapter hot plug remove entry point. - * - * Return value: - * none - **/ -static void __devexit ipr_remove(struct pci_dev *pdev) -{ - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); - - ENTER; - - ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj, - &ipr_trace_attr); - ipr_remove_dump_file(&ioa_cfg->host->shost_dev.kobj, - &ipr_dump_attr); - scsi_remove_host(ioa_cfg->host); - - __ipr_remove(pdev); - - LEAVE; -} - -/** - * ipr_probe - Adapter hot plug add entry point - * - * Return value: - * 0 on success / non-zero on failure - **/ -static int __devinit ipr_probe(struct pci_dev *pdev, - const struct pci_device_id *dev_id) -{ - struct ipr_ioa_cfg *ioa_cfg; - int rc; - - rc = ipr_probe_ioa(pdev, dev_id); - - if (rc) - return rc; - - ioa_cfg = pci_get_drvdata(pdev); - rc = ipr_probe_ioa_part2(ioa_cfg); - - if (rc) { - __ipr_remove(pdev); - return rc; - } - - rc = scsi_add_host(ioa_cfg->host, &pdev->dev); - - if (rc) { - __ipr_remove(pdev); - return rc; - } - - rc = ipr_create_trace_file(&ioa_cfg->host->shost_dev.kobj, - &ipr_trace_attr); - - if (rc) { - scsi_remove_host(ioa_cfg->host); - __ipr_remove(pdev); - return rc; - } - - rc = ipr_create_dump_file(&ioa_cfg->host->shost_dev.kobj, - &ipr_dump_attr); - - if (rc) { - ipr_remove_trace_file(&ioa_cfg->host->shost_dev.kobj, - &ipr_trace_attr); - scsi_remove_host(ioa_cfg->host); - __ipr_remove(pdev); - return rc; - } - - scsi_scan_host(ioa_cfg->host); - ipr_scan_vsets(ioa_cfg); - scsi_add_device(ioa_cfg->host, IPR_IOA_BUS, IPR_IOA_TARGET, IPR_IOA_LUN); - ioa_cfg->allow_ml_add_del = 1; - ioa_cfg->host->max_channel = IPR_VSET_BUS; - schedule_work(&ioa_cfg->work_q); - return 0; -} - -/** - * ipr_shutdown - Shutdown handler. - * @pdev: pci device struct - * - * This function is invoked upon system shutdown/reboot. It will issue - * an adapter shutdown to the adapter to flush the write cache. - * - * Return value: - * none - **/ -static void ipr_shutdown(struct pci_dev *pdev) -{ - struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev); - unsigned long lock_flags = 0; - - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - while(ioa_cfg->in_reset_reload) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); - spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); - } - - ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags); - wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload); -} - -static struct pci_device_id ipr_pci_table[] __devinitdata = { - { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702, 0, 0, 0 }, - { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703, 0, 0, 0 }, - { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D, 0, 0, 0 }, - { PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575B, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572A, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572B, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT}, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574E, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B3, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57CC, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT | IPR_USE_PCI_WARM_RESET }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780, 0, 0, 0 }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E, 0, 0, 0 }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571F, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572F, 0, 0, - IPR_USE_LONG_TRANSOP_TIMEOUT }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B5, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_574D, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B2, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C3, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C4, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B4, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B1, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C6, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57C8, 0, 0, 0 }, - { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROCODILE, - PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57CE, 0, 0, 0 }, - { } -}; -MODULE_DEVICE_TABLE(pci, ipr_pci_table); - -static struct pci_error_handlers ipr_err_handler = { - .error_detected = ipr_pci_error_detected, - .slot_reset = ipr_pci_slot_reset, -}; - -static struct pci_driver ipr_driver = { - .name = IPR_NAME, - .id_table = ipr_pci_table, - .probe = ipr_probe, - .remove = __devexit_p(ipr_remove), - .shutdown = ipr_shutdown, - .err_handler = &ipr_err_handler, -}; - -/** - * ipr_halt_done - Shutdown prepare completion - * - * Return value: - * none - **/ -static void ipr_halt_done(struct ipr_cmnd *ipr_cmd) -{ - struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg; - - list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q); -} - -/** - * ipr_halt - Issue shutdown prepare to all adapters - * - * Return value: - * NOTIFY_OK on success / NOTIFY_DONE on failure - **/ -static int ipr_halt(struct notifier_block *nb, ulong event, void *buf) -{ - struct ipr_cmnd *ipr_cmd; - struct ipr_ioa_cfg *ioa_cfg; - unsigned long flags = 0; - - if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF) - return NOTIFY_DONE; - - spin_lock(&ipr_driver_lock); - - list_for_each_entry(ioa_cfg, &ipr_ioa_head, queue) { - spin_lock_irqsave(ioa_cfg->host->host_lock, flags); - if (!ioa_cfg->allow_cmds) { - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - continue; - } - - ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg); - ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE); - ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD; - ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN; - ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_SHUTDOWN_PREPARE_FOR_NORMAL; - - ipr_do_req(ipr_cmd, ipr_halt_done, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT); - spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags); - } - spin_unlock(&ipr_driver_lock); - - return NOTIFY_OK; -} - -static struct notifier_block ipr_notifier = { - ipr_halt, NULL, 0 -}; - -/** - * ipr_init - Module entry point - * - * Return value: - * 0 on success / negative value on failure - **/ -static int __init ipr_init(void) -{ - ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n", - IPR_DRIVER_VERSION, IPR_DRIVER_DATE); - - register_reboot_notifier(&ipr_notifier); - return pci_register_driver(&ipr_driver); -} - -/** - * ipr_exit - Module unload - * - * Module unload entry point. - * - * Return value: - * none - **/ -static void __exit ipr_exit(void) -{ - unregister_reboot_notifier(&ipr_notifier); - pci_unregister_driver(&ipr_driver); -} - -module_init(ipr_init); -module_exit(ipr_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/ipr.h b/ANDROID_3.4.5/drivers/scsi/ipr.h deleted file mode 100644 index 153b8bd9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ipr.h +++ /dev/null @@ -1,1898 +0,0 @@ -/* - * ipr.h -- driver for IBM Power Linux RAID adapters - * - * Written By: Brian King , IBM Corporation - * - * Copyright (C) 2003, 2004 IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Alan Cox - Removed several careless u32/dma_addr_t errors - * that broke 64bit platforms. - */ - -#ifndef _IPR_H -#define _IPR_H - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Literals - */ -#define IPR_DRIVER_VERSION "2.5.3" -#define IPR_DRIVER_DATE "(March 10, 2012)" - -/* - * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding - * ops per device for devices not running tagged command queuing. - * This can be adjusted at runtime through sysfs device attributes. - */ -#define IPR_MAX_CMD_PER_LUN 6 -#define IPR_MAX_CMD_PER_ATA_LUN 1 - -/* - * IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of - * ops the mid-layer can send to the adapter. - */ -#define IPR_NUM_BASE_CMD_BLKS (ioa_cfg->max_cmds) - -#define PCI_DEVICE_ID_IBM_OBSIDIAN_E 0x0339 - -#define PCI_DEVICE_ID_IBM_CROC_FPGA_E2 0x033D -#define PCI_DEVICE_ID_IBM_CROCODILE 0x034A - -#define IPR_SUBS_DEV_ID_2780 0x0264 -#define IPR_SUBS_DEV_ID_5702 0x0266 -#define IPR_SUBS_DEV_ID_5703 0x0278 -#define IPR_SUBS_DEV_ID_572E 0x028D -#define IPR_SUBS_DEV_ID_573E 0x02D3 -#define IPR_SUBS_DEV_ID_573D 0x02D4 -#define IPR_SUBS_DEV_ID_571A 0x02C0 -#define IPR_SUBS_DEV_ID_571B 0x02BE -#define IPR_SUBS_DEV_ID_571E 0x02BF -#define IPR_SUBS_DEV_ID_571F 0x02D5 -#define IPR_SUBS_DEV_ID_572A 0x02C1 -#define IPR_SUBS_DEV_ID_572B 0x02C2 -#define IPR_SUBS_DEV_ID_572F 0x02C3 -#define IPR_SUBS_DEV_ID_574E 0x030A -#define IPR_SUBS_DEV_ID_575B 0x030D -#define IPR_SUBS_DEV_ID_575C 0x0338 -#define IPR_SUBS_DEV_ID_57B3 0x033A -#define IPR_SUBS_DEV_ID_57B7 0x0360 -#define IPR_SUBS_DEV_ID_57B8 0x02C2 - -#define IPR_SUBS_DEV_ID_57B4 0x033B -#define IPR_SUBS_DEV_ID_57B2 0x035F -#define IPR_SUBS_DEV_ID_57C3 0x0353 -#define IPR_SUBS_DEV_ID_57C4 0x0354 -#define IPR_SUBS_DEV_ID_57C6 0x0357 -#define IPR_SUBS_DEV_ID_57CC 0x035C - -#define IPR_SUBS_DEV_ID_57B5 0x033C -#define IPR_SUBS_DEV_ID_57CE 0x035E -#define IPR_SUBS_DEV_ID_57B1 0x0355 - -#define IPR_SUBS_DEV_ID_574D 0x0356 -#define IPR_SUBS_DEV_ID_57C8 0x035D - -#define IPR_NAME "ipr" - -/* - * Return codes - */ -#define IPR_RC_JOB_CONTINUE 1 -#define IPR_RC_JOB_RETURN 2 - -/* - * IOASCs - */ -#define IPR_IOASC_NR_INIT_CMD_REQUIRED 0x02040200 -#define IPR_IOASC_NR_IOA_RESET_REQUIRED 0x02048000 -#define IPR_IOASC_SYNC_REQUIRED 0x023f0000 -#define IPR_IOASC_MED_DO_NOT_REALLOC 0x03110C00 -#define IPR_IOASC_HW_SEL_TIMEOUT 0x04050000 -#define IPR_IOASC_HW_DEV_BUS_STATUS 0x04448500 -#define IPR_IOASC_IOASC_MASK 0xFFFFFF00 -#define IPR_IOASC_SCSI_STATUS_MASK 0x000000FF -#define IPR_IOASC_IR_INVALID_REQ_TYPE_OR_PKT 0x05240000 -#define IPR_IOASC_IR_RESOURCE_HANDLE 0x05250000 -#define IPR_IOASC_IR_NO_CMDS_TO_2ND_IOA 0x05258100 -#define IPR_IOASA_IR_DUAL_IOA_DISABLED 0x052C8000 -#define IPR_IOASC_BUS_WAS_RESET 0x06290000 -#define IPR_IOASC_BUS_WAS_RESET_BY_OTHER 0x06298000 -#define IPR_IOASC_ABORTED_CMD_TERM_BY_HOST 0x0B5A0000 - -#define IPR_FIRST_DRIVER_IOASC 0x10000000 -#define IPR_IOASC_IOA_WAS_RESET 0x10000001 -#define IPR_IOASC_PCI_ACCESS_ERROR 0x10000002 - -/* Driver data flags */ -#define IPR_USE_LONG_TRANSOP_TIMEOUT 0x00000001 -#define IPR_USE_PCI_WARM_RESET 0x00000002 - -#define IPR_DEFAULT_MAX_ERROR_DUMP 984 -#define IPR_NUM_LOG_HCAMS 2 -#define IPR_NUM_CFG_CHG_HCAMS 2 -#define IPR_NUM_HCAMS (IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS) - -#define IPR_MAX_SIS64_TARGETS_PER_BUS 1024 -#define IPR_MAX_SIS64_LUNS_PER_TARGET 0xffffffff - -#define IPR_MAX_NUM_TARGETS_PER_BUS 256 -#define IPR_MAX_NUM_LUNS_PER_TARGET 256 -#define IPR_MAX_NUM_VSET_LUNS_PER_TARGET 8 -#define IPR_VSET_BUS 0xff -#define IPR_IOA_BUS 0xff -#define IPR_IOA_TARGET 0xff -#define IPR_IOA_LUN 0xff -#define IPR_MAX_NUM_BUSES 16 -#define IPR_MAX_BUS_TO_SCAN IPR_MAX_NUM_BUSES - -#define IPR_NUM_RESET_RELOAD_RETRIES 3 - -/* We need resources for HCAMS, IOA reset, IOA bringdown, and ERP */ -#define IPR_NUM_INTERNAL_CMD_BLKS (IPR_NUM_HCAMS + \ - ((IPR_NUM_RESET_RELOAD_RETRIES + 1) * 2) + 4) - -#define IPR_MAX_COMMANDS 100 -#define IPR_NUM_CMD_BLKS (IPR_NUM_BASE_CMD_BLKS + \ - IPR_NUM_INTERNAL_CMD_BLKS) - -#define IPR_MAX_PHYSICAL_DEVS 192 -#define IPR_DEFAULT_SIS64_DEVS 1024 -#define IPR_MAX_SIS64_DEVS 4096 - -#define IPR_MAX_SGLIST 64 -#define IPR_IOA_MAX_SECTORS 32767 -#define IPR_VSET_MAX_SECTORS 512 -#define IPR_MAX_CDB_LEN 16 -#define IPR_MAX_HRRQ_RETRIES 3 - -#define IPR_DEFAULT_BUS_WIDTH 16 -#define IPR_80MBs_SCSI_RATE ((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8)) -#define IPR_U160_SCSI_RATE ((160 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8)) -#define IPR_U320_SCSI_RATE ((320 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8)) -#define IPR_MAX_SCSI_RATE(width) ((320 * 10) / ((width) / 8)) - -#define IPR_IOA_RES_HANDLE 0xffffffff -#define IPR_INVALID_RES_HANDLE 0 -#define IPR_IOA_RES_ADDR 0x00ffffff - -/* - * Adapter Commands - */ -#define IPR_QUERY_RSRC_STATE 0xC2 -#define IPR_RESET_DEVICE 0xC3 -#define IPR_RESET_TYPE_SELECT 0x80 -#define IPR_LUN_RESET 0x40 -#define IPR_TARGET_RESET 0x20 -#define IPR_BUS_RESET 0x10 -#define IPR_ATA_PHY_RESET 0x80 -#define IPR_ID_HOST_RR_Q 0xC4 -#define IPR_QUERY_IOA_CONFIG 0xC5 -#define IPR_CANCEL_ALL_REQUESTS 0xCE -#define IPR_HOST_CONTROLLED_ASYNC 0xCF -#define IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE 0x01 -#define IPR_HCAM_CDB_OP_CODE_LOG_DATA 0x02 -#define IPR_SET_SUPPORTED_DEVICES 0xFB -#define IPR_SET_ALL_SUPPORTED_DEVICES 0x80 -#define IPR_IOA_SHUTDOWN 0xF7 -#define IPR_WR_BUF_DOWNLOAD_AND_SAVE 0x05 - -/* - * Timeouts - */ -#define IPR_SHUTDOWN_TIMEOUT (ipr_fastfail ? 60 * HZ : 10 * 60 * HZ) -#define IPR_VSET_RW_TIMEOUT (ipr_fastfail ? 30 * HZ : 2 * 60 * HZ) -#define IPR_ABBREV_SHUTDOWN_TIMEOUT (10 * HZ) -#define IPR_DUAL_IOA_ABBR_SHUTDOWN_TO (2 * 60 * HZ) -#define IPR_DEVICE_RESET_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ) -#define IPR_CANCEL_ALL_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ) -#define IPR_ABORT_TASK_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ) -#define IPR_INTERNAL_TIMEOUT (ipr_fastfail ? 10 * HZ : 30 * HZ) -#define IPR_WRITE_BUFFER_TIMEOUT (30 * 60 * HZ) -#define IPR_SET_SUP_DEVICE_TIMEOUT (2 * 60 * HZ) -#define IPR_REQUEST_SENSE_TIMEOUT (10 * HZ) -#define IPR_OPERATIONAL_TIMEOUT (5 * 60) -#define IPR_LONG_OPERATIONAL_TIMEOUT (12 * 60) -#define IPR_WAIT_FOR_RESET_TIMEOUT (2 * HZ) -#define IPR_CHECK_FOR_RESET_TIMEOUT (HZ / 10) -#define IPR_WAIT_FOR_BIST_TIMEOUT (2 * HZ) -#define IPR_PCI_RESET_TIMEOUT (HZ / 2) -#define IPR_SIS32_DUMP_TIMEOUT (15 * HZ) -#define IPR_SIS64_DUMP_TIMEOUT (40 * HZ) -#define IPR_DUMP_DELAY_SECONDS 4 -#define IPR_DUMP_DELAY_TIMEOUT (IPR_DUMP_DELAY_SECONDS * HZ) - -/* - * SCSI Literals - */ -#define IPR_VENDOR_ID_LEN 8 -#define IPR_PROD_ID_LEN 16 -#define IPR_SERIAL_NUM_LEN 8 - -/* - * Hardware literals - */ -#define IPR_FMT2_MBX_ADDR_MASK 0x0fffffff -#define IPR_FMT2_MBX_BAR_SEL_MASK 0xf0000000 -#define IPR_FMT2_MKR_BAR_SEL_SHIFT 28 -#define IPR_GET_FMT2_BAR_SEL(mbx) \ -(((mbx) & IPR_FMT2_MBX_BAR_SEL_MASK) >> IPR_FMT2_MKR_BAR_SEL_SHIFT) -#define IPR_SDT_FMT2_BAR0_SEL 0x0 -#define IPR_SDT_FMT2_BAR1_SEL 0x1 -#define IPR_SDT_FMT2_BAR2_SEL 0x2 -#define IPR_SDT_FMT2_BAR3_SEL 0x3 -#define IPR_SDT_FMT2_BAR4_SEL 0x4 -#define IPR_SDT_FMT2_BAR5_SEL 0x5 -#define IPR_SDT_FMT2_EXP_ROM_SEL 0x8 -#define IPR_FMT2_SDT_READY_TO_USE 0xC4D4E3F2 -#define IPR_FMT3_SDT_READY_TO_USE 0xC4D4E3F3 -#define IPR_DOORBELL 0x82800000 -#define IPR_RUNTIME_RESET 0x40000000 - -#define IPR_IPL_INIT_MIN_STAGE_TIME 5 -#define IPR_IPL_INIT_DEFAULT_STAGE_TIME 15 -#define IPR_IPL_INIT_STAGE_UNKNOWN 0x0 -#define IPR_IPL_INIT_STAGE_TRANSOP 0xB0000000 -#define IPR_IPL_INIT_STAGE_MASK 0xff000000 -#define IPR_IPL_INIT_STAGE_TIME_MASK 0x0000ffff -#define IPR_PCII_IPL_STAGE_CHANGE (0x80000000 >> 0) - -#define IPR_PCII_IOA_TRANS_TO_OPER (0x80000000 >> 0) -#define IPR_PCII_IOARCB_XFER_FAILED (0x80000000 >> 3) -#define IPR_PCII_IOA_UNIT_CHECKED (0x80000000 >> 4) -#define IPR_PCII_NO_HOST_RRQ (0x80000000 >> 5) -#define IPR_PCII_CRITICAL_OPERATION (0x80000000 >> 6) -#define IPR_PCII_IO_DEBUG_ACKNOWLEDGE (0x80000000 >> 7) -#define IPR_PCII_IOARRIN_LOST (0x80000000 >> 27) -#define IPR_PCII_MMIO_ERROR (0x80000000 >> 28) -#define IPR_PCII_PROC_ERR_STATE (0x80000000 >> 29) -#define IPR_PCII_HRRQ_UPDATED (0x80000000 >> 30) -#define IPR_PCII_CORE_ISSUED_RST_REQ (0x80000000 >> 31) - -#define IPR_PCII_ERROR_INTERRUPTS \ -(IPR_PCII_IOARCB_XFER_FAILED | IPR_PCII_IOA_UNIT_CHECKED | \ -IPR_PCII_NO_HOST_RRQ | IPR_PCII_IOARRIN_LOST | IPR_PCII_MMIO_ERROR) - -#define IPR_PCII_OPER_INTERRUPTS \ -(IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED | IPR_PCII_IOA_TRANS_TO_OPER) - -#define IPR_UPROCI_RESET_ALERT (0x80000000 >> 7) -#define IPR_UPROCI_IO_DEBUG_ALERT (0x80000000 >> 9) -#define IPR_UPROCI_SIS64_START_BIST (0x80000000 >> 23) - -#define IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC 200000 /* 200 ms */ -#define IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC 200000 /* 200 ms */ - -/* - * Dump literals - */ -#define IPR_FMT2_MAX_IOA_DUMP_SIZE (4 * 1024 * 1024) -#define IPR_FMT3_MAX_IOA_DUMP_SIZE (32 * 1024 * 1024) -#define IPR_FMT2_NUM_SDT_ENTRIES 511 -#define IPR_FMT3_NUM_SDT_ENTRIES 0xFFF -#define IPR_FMT2_MAX_NUM_DUMP_PAGES ((IPR_FMT2_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) -#define IPR_FMT3_MAX_NUM_DUMP_PAGES ((IPR_FMT3_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1) - -/* - * Misc literals - */ -#define IPR_NUM_IOADL_ENTRIES IPR_MAX_SGLIST - -/* - * Adapter interface types - */ - -struct ipr_res_addr { - u8 reserved; - u8 bus; - u8 target; - u8 lun; -#define IPR_GET_PHYS_LOC(res_addr) \ - (((res_addr).bus << 16) | ((res_addr).target << 8) | (res_addr).lun) -}__attribute__((packed, aligned (4))); - -struct ipr_std_inq_vpids { - u8 vendor_id[IPR_VENDOR_ID_LEN]; - u8 product_id[IPR_PROD_ID_LEN]; -}__attribute__((packed)); - -struct ipr_vpd { - struct ipr_std_inq_vpids vpids; - u8 sn[IPR_SERIAL_NUM_LEN]; -}__attribute__((packed)); - -struct ipr_ext_vpd { - struct ipr_vpd vpd; - __be32 wwid[2]; -}__attribute__((packed)); - -struct ipr_ext_vpd64 { - struct ipr_vpd vpd; - __be32 wwid[4]; -}__attribute__((packed)); - -struct ipr_std_inq_data { - u8 peri_qual_dev_type; -#define IPR_STD_INQ_PERI_QUAL(peri) ((peri) >> 5) -#define IPR_STD_INQ_PERI_DEV_TYPE(peri) ((peri) & 0x1F) - - u8 removeable_medium_rsvd; -#define IPR_STD_INQ_REMOVEABLE_MEDIUM 0x80 - -#define IPR_IS_DASD_DEVICE(std_inq) \ -((IPR_STD_INQ_PERI_DEV_TYPE((std_inq).peri_qual_dev_type) == TYPE_DISK) && \ -!(((std_inq).removeable_medium_rsvd) & IPR_STD_INQ_REMOVEABLE_MEDIUM)) - -#define IPR_IS_SES_DEVICE(std_inq) \ -(IPR_STD_INQ_PERI_DEV_TYPE((std_inq).peri_qual_dev_type) == TYPE_ENCLOSURE) - - u8 version; - u8 aen_naca_fmt; - u8 additional_len; - u8 sccs_rsvd; - u8 bq_enc_multi; - u8 sync_cmdq_flags; - - struct ipr_std_inq_vpids vpids; - - u8 ros_rsvd_ram_rsvd[4]; - - u8 serial_num[IPR_SERIAL_NUM_LEN]; -}__attribute__ ((packed)); - -#define IPR_RES_TYPE_AF_DASD 0x00 -#define IPR_RES_TYPE_GENERIC_SCSI 0x01 -#define IPR_RES_TYPE_VOLUME_SET 0x02 -#define IPR_RES_TYPE_REMOTE_AF_DASD 0x03 -#define IPR_RES_TYPE_GENERIC_ATA 0x04 -#define IPR_RES_TYPE_ARRAY 0x05 -#define IPR_RES_TYPE_IOAFP 0xff - -struct ipr_config_table_entry { - u8 proto; -#define IPR_PROTO_SATA 0x02 -#define IPR_PROTO_SATA_ATAPI 0x03 -#define IPR_PROTO_SAS_STP 0x06 -#define IPR_PROTO_SAS_STP_ATAPI 0x07 - u8 array_id; - u8 flags; -#define IPR_IS_IOA_RESOURCE 0x80 - u8 rsvd_subtype; - -#define IPR_QUEUEING_MODEL(res) ((((res)->flags) & 0x70) >> 4) -#define IPR_QUEUE_FROZEN_MODEL 0 -#define IPR_QUEUE_NACA_MODEL 1 - - struct ipr_res_addr res_addr; - __be32 res_handle; - __be32 lun_wwn[2]; - struct ipr_std_inq_data std_inq_data; -}__attribute__ ((packed, aligned (4))); - -struct ipr_config_table_entry64 { - u8 res_type; - u8 proto; - u8 vset_num; - u8 array_id; - __be16 flags; - __be16 res_flags; -#define IPR_QUEUEING_MODEL64(res) ((((res)->res_flags) & 0x7000) >> 12) - __be32 res_handle; - u8 dev_id_type; - u8 reserved[3]; - __be64 dev_id; - __be64 lun; - __be64 lun_wwn[2]; -#define IPR_MAX_RES_PATH_LENGTH 24 - __be64 res_path; - struct ipr_std_inq_data std_inq_data; - u8 reserved2[4]; - __be64 reserved3[2]; - u8 reserved4[8]; -}__attribute__ ((packed, aligned (8))); - -struct ipr_config_table_hdr { - u8 num_entries; - u8 flags; -#define IPR_UCODE_DOWNLOAD_REQ 0x10 - __be16 reserved; -}__attribute__((packed, aligned (4))); - -struct ipr_config_table_hdr64 { - __be16 num_entries; - __be16 reserved; - u8 flags; - u8 reserved2[11]; -}__attribute__((packed, aligned (4))); - -struct ipr_config_table { - struct ipr_config_table_hdr hdr; - struct ipr_config_table_entry dev[0]; -}__attribute__((packed, aligned (4))); - -struct ipr_config_table64 { - struct ipr_config_table_hdr64 hdr64; - struct ipr_config_table_entry64 dev[0]; -}__attribute__((packed, aligned (8))); - -struct ipr_config_table_entry_wrapper { - union { - struct ipr_config_table_entry *cfgte; - struct ipr_config_table_entry64 *cfgte64; - } u; -}; - -struct ipr_hostrcb_cfg_ch_not { - union { - struct ipr_config_table_entry cfgte; - struct ipr_config_table_entry64 cfgte64; - } u; - u8 reserved[936]; -}__attribute__((packed, aligned (4))); - -struct ipr_supported_device { - __be16 data_length; - u8 reserved; - u8 num_records; - struct ipr_std_inq_vpids vpids; - u8 reserved2[16]; -}__attribute__((packed, aligned (4))); - -/* Command packet structure */ -struct ipr_cmd_pkt { - __be16 reserved; /* Reserved by IOA */ - u8 request_type; -#define IPR_RQTYPE_SCSICDB 0x00 -#define IPR_RQTYPE_IOACMD 0x01 -#define IPR_RQTYPE_HCAM 0x02 -#define IPR_RQTYPE_ATA_PASSTHRU 0x04 - - u8 reserved2; - - u8 flags_hi; -#define IPR_FLAGS_HI_WRITE_NOT_READ 0x80 -#define IPR_FLAGS_HI_NO_ULEN_CHK 0x20 -#define IPR_FLAGS_HI_SYNC_OVERRIDE 0x10 -#define IPR_FLAGS_HI_SYNC_COMPLETE 0x08 -#define IPR_FLAGS_HI_NO_LINK_DESC 0x04 - - u8 flags_lo; -#define IPR_FLAGS_LO_ALIGNED_BFR 0x20 -#define IPR_FLAGS_LO_DELAY_AFTER_RST 0x10 -#define IPR_FLAGS_LO_UNTAGGED_TASK 0x00 -#define IPR_FLAGS_LO_SIMPLE_TASK 0x02 -#define IPR_FLAGS_LO_ORDERED_TASK 0x04 -#define IPR_FLAGS_LO_HEAD_OF_Q_TASK 0x06 -#define IPR_FLAGS_LO_ACA_TASK 0x08 - - u8 cdb[16]; - __be16 timeout; -}__attribute__ ((packed, aligned(4))); - -struct ipr_ioarcb_ata_regs { /* 22 bytes */ - u8 flags; -#define IPR_ATA_FLAG_PACKET_CMD 0x80 -#define IPR_ATA_FLAG_XFER_TYPE_DMA 0x40 -#define IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION 0x20 - u8 reserved[3]; - - __be16 data; - u8 feature; - u8 nsect; - u8 lbal; - u8 lbam; - u8 lbah; - u8 device; - u8 command; - u8 reserved2[3]; - u8 hob_feature; - u8 hob_nsect; - u8 hob_lbal; - u8 hob_lbam; - u8 hob_lbah; - u8 ctl; -}__attribute__ ((packed, aligned(4))); - -struct ipr_ioadl_desc { - __be32 flags_and_data_len; -#define IPR_IOADL_FLAGS_MASK 0xff000000 -#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK) -#define IPR_IOADL_DATA_LEN_MASK 0x00ffffff -#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK) -#define IPR_IOADL_FLAGS_READ 0x48000000 -#define IPR_IOADL_FLAGS_READ_LAST 0x49000000 -#define IPR_IOADL_FLAGS_WRITE 0x68000000 -#define IPR_IOADL_FLAGS_WRITE_LAST 0x69000000 -#define IPR_IOADL_FLAGS_LAST 0x01000000 - - __be32 address; -}__attribute__((packed, aligned (8))); - -struct ipr_ioadl64_desc { - __be32 flags; - __be32 data_len; - __be64 address; -}__attribute__((packed, aligned (16))); - -struct ipr_ata64_ioadl { - struct ipr_ioarcb_ata_regs regs; - u16 reserved[5]; - struct ipr_ioadl64_desc ioadl64[IPR_NUM_IOADL_ENTRIES]; -}__attribute__((packed, aligned (16))); - -struct ipr_ioarcb_add_data { - union { - struct ipr_ioarcb_ata_regs regs; - struct ipr_ioadl_desc ioadl[5]; - __be32 add_cmd_parms[10]; - } u; -}__attribute__ ((packed, aligned (4))); - -struct ipr_ioarcb_sis64_add_addr_ecb { - __be64 ioasa_host_pci_addr; - __be64 data_ioadl_addr; - __be64 reserved; - __be32 ext_control_buf[4]; -}__attribute__((packed, aligned (8))); - -/* IOA Request Control Block 128 bytes */ -struct ipr_ioarcb { - union { - __be32 ioarcb_host_pci_addr; - __be64 ioarcb_host_pci_addr64; - } a; - __be32 res_handle; - __be32 host_response_handle; - __be32 reserved1; - __be32 reserved2; - __be32 reserved3; - - __be32 data_transfer_length; - __be32 read_data_transfer_length; - __be32 write_ioadl_addr; - __be32 ioadl_len; - __be32 read_ioadl_addr; - __be32 read_ioadl_len; - - __be32 ioasa_host_pci_addr; - __be16 ioasa_len; - __be16 reserved4; - - struct ipr_cmd_pkt cmd_pkt; - - __be16 add_cmd_parms_offset; - __be16 add_cmd_parms_len; - - union { - struct ipr_ioarcb_add_data add_data; - struct ipr_ioarcb_sis64_add_addr_ecb sis64_addr_data; - } u; - -}__attribute__((packed, aligned (4))); - -struct ipr_ioasa_vset { - __be32 failing_lba_hi; - __be32 failing_lba_lo; - __be32 reserved; -}__attribute__((packed, aligned (4))); - -struct ipr_ioasa_af_dasd { - __be32 failing_lba; - __be32 reserved[2]; -}__attribute__((packed, aligned (4))); - -struct ipr_ioasa_gpdd { - u8 end_state; - u8 bus_phase; - __be16 reserved; - __be32 ioa_data[2]; -}__attribute__((packed, aligned (4))); - -struct ipr_ioasa_gata { - u8 error; - u8 nsect; /* Interrupt reason */ - u8 lbal; - u8 lbam; - u8 lbah; - u8 device; - u8 status; - u8 alt_status; /* ATA CTL */ - u8 hob_nsect; - u8 hob_lbal; - u8 hob_lbam; - u8 hob_lbah; -}__attribute__((packed, aligned (4))); - -struct ipr_auto_sense { - __be16 auto_sense_len; - __be16 ioa_data_len; - __be32 data[SCSI_SENSE_BUFFERSIZE/sizeof(__be32)]; -}; - -struct ipr_ioasa_hdr { - __be32 ioasc; -#define IPR_IOASC_SENSE_KEY(ioasc) ((ioasc) >> 24) -#define IPR_IOASC_SENSE_CODE(ioasc) (((ioasc) & 0x00ff0000) >> 16) -#define IPR_IOASC_SENSE_QUAL(ioasc) (((ioasc) & 0x0000ff00) >> 8) -#define IPR_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff) - - __be16 ret_stat_len; /* Length of the returned IOASA */ - - __be16 avail_stat_len; /* Total Length of status available. */ - - __be32 residual_data_len; /* number of bytes in the host data */ - /* buffers that were not used by the IOARCB command. */ - - __be32 ilid; -#define IPR_NO_ILID 0 -#define IPR_DRIVER_ILID 0xffffffff - - __be32 fd_ioasc; - - __be32 fd_phys_locator; - - __be32 fd_res_handle; - - __be32 ioasc_specific; /* status code specific field */ -#define IPR_ADDITIONAL_STATUS_FMT 0x80000000 -#define IPR_AUTOSENSE_VALID 0x40000000 -#define IPR_ATA_DEVICE_WAS_RESET 0x20000000 -#define IPR_IOASC_SPECIFIC_MASK 0x00ffffff -#define IPR_FIELD_POINTER_VALID (0x80000000 >> 8) -#define IPR_FIELD_POINTER_MASK 0x0000ffff - -}__attribute__((packed, aligned (4))); - -struct ipr_ioasa { - struct ipr_ioasa_hdr hdr; - - union { - struct ipr_ioasa_vset vset; - struct ipr_ioasa_af_dasd dasd; - struct ipr_ioasa_gpdd gpdd; - struct ipr_ioasa_gata gata; - } u; - - struct ipr_auto_sense auto_sense; -}__attribute__((packed, aligned (4))); - -struct ipr_ioasa64 { - struct ipr_ioasa_hdr hdr; - u8 fd_res_path[8]; - - union { - struct ipr_ioasa_vset vset; - struct ipr_ioasa_af_dasd dasd; - struct ipr_ioasa_gpdd gpdd; - struct ipr_ioasa_gata gata; - } u; - - struct ipr_auto_sense auto_sense; -}__attribute__((packed, aligned (4))); - -struct ipr_mode_parm_hdr { - u8 length; - u8 medium_type; - u8 device_spec_parms; - u8 block_desc_len; -}__attribute__((packed)); - -struct ipr_mode_pages { - struct ipr_mode_parm_hdr hdr; - u8 data[255 - sizeof(struct ipr_mode_parm_hdr)]; -}__attribute__((packed)); - -struct ipr_mode_page_hdr { - u8 ps_page_code; -#define IPR_MODE_PAGE_PS 0x80 -#define IPR_GET_MODE_PAGE_CODE(hdr) ((hdr)->ps_page_code & 0x3F) - u8 page_length; -}__attribute__ ((packed)); - -struct ipr_dev_bus_entry { - struct ipr_res_addr res_addr; - u8 flags; -#define IPR_SCSI_ATTR_ENABLE_QAS 0x80 -#define IPR_SCSI_ATTR_DISABLE_QAS 0x40 -#define IPR_SCSI_ATTR_QAS_MASK 0xC0 -#define IPR_SCSI_ATTR_ENABLE_TM 0x20 -#define IPR_SCSI_ATTR_NO_TERM_PWR 0x10 -#define IPR_SCSI_ATTR_TM_SUPPORTED 0x08 -#define IPR_SCSI_ATTR_LVD_TO_SE_NOT_ALLOWED 0x04 - - u8 scsi_id; - u8 bus_width; - u8 extended_reset_delay; -#define IPR_EXTENDED_RESET_DELAY 7 - - __be32 max_xfer_rate; - - u8 spinup_delay; - u8 reserved3; - __be16 reserved4; -}__attribute__((packed, aligned (4))); - -struct ipr_mode_page28 { - struct ipr_mode_page_hdr hdr; - u8 num_entries; - u8 entry_length; - struct ipr_dev_bus_entry bus[0]; -}__attribute__((packed)); - -struct ipr_mode_page24 { - struct ipr_mode_page_hdr hdr; - u8 flags; -#define IPR_ENABLE_DUAL_IOA_AF 0x80 -}__attribute__((packed)); - -struct ipr_ioa_vpd { - struct ipr_std_inq_data std_inq_data; - u8 ascii_part_num[12]; - u8 reserved[40]; - u8 ascii_plant_code[4]; -}__attribute__((packed)); - -struct ipr_inquiry_page3 { - u8 peri_qual_dev_type; - u8 page_code; - u8 reserved1; - u8 page_length; - u8 ascii_len; - u8 reserved2[3]; - u8 load_id[4]; - u8 major_release; - u8 card_type; - u8 minor_release[2]; - u8 ptf_number[4]; - u8 patch_number[4]; -}__attribute__((packed)); - -struct ipr_inquiry_cap { - u8 peri_qual_dev_type; - u8 page_code; - u8 reserved1; - u8 page_length; - u8 ascii_len; - u8 reserved2; - u8 sis_version[2]; - u8 cap; -#define IPR_CAP_DUAL_IOA_RAID 0x80 - u8 reserved3[15]; -}__attribute__((packed)); - -#define IPR_INQUIRY_PAGE0_ENTRIES 20 -struct ipr_inquiry_page0 { - u8 peri_qual_dev_type; - u8 page_code; - u8 reserved1; - u8 len; - u8 page[IPR_INQUIRY_PAGE0_ENTRIES]; -}__attribute__((packed)); - -struct ipr_hostrcb_device_data_entry { - struct ipr_vpd vpd; - struct ipr_res_addr dev_res_addr; - struct ipr_vpd new_vpd; - struct ipr_vpd ioa_last_with_dev_vpd; - struct ipr_vpd cfc_last_with_dev_vpd; - __be32 ioa_data[5]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_device_data_entry_enhanced { - struct ipr_ext_vpd vpd; - u8 ccin[4]; - struct ipr_res_addr dev_res_addr; - struct ipr_ext_vpd new_vpd; - u8 new_ccin[4]; - struct ipr_ext_vpd ioa_last_with_dev_vpd; - struct ipr_ext_vpd cfc_last_with_dev_vpd; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb64_device_data_entry_enhanced { - struct ipr_ext_vpd vpd; - u8 ccin[4]; - u8 res_path[8]; - struct ipr_ext_vpd new_vpd; - u8 new_ccin[4]; - struct ipr_ext_vpd ioa_last_with_dev_vpd; - struct ipr_ext_vpd cfc_last_with_dev_vpd; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_array_data_entry { - struct ipr_vpd vpd; - struct ipr_res_addr expected_dev_res_addr; - struct ipr_res_addr dev_res_addr; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb64_array_data_entry { - struct ipr_ext_vpd vpd; - u8 ccin[4]; - u8 expected_res_path[8]; - u8 res_path[8]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_array_data_entry_enhanced { - struct ipr_ext_vpd vpd; - u8 ccin[4]; - struct ipr_res_addr expected_dev_res_addr; - struct ipr_res_addr dev_res_addr; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_ff_error { - __be32 ioa_data[758]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_01_error { - __be32 seek_counter; - __be32 read_counter; - u8 sense_data[32]; - __be32 ioa_data[236]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_02_error { - struct ipr_vpd ioa_vpd; - struct ipr_vpd cfc_vpd; - struct ipr_vpd ioa_last_attached_to_cfc_vpd; - struct ipr_vpd cfc_last_attached_to_ioa_vpd; - __be32 ioa_data[3]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_12_error { - struct ipr_ext_vpd ioa_vpd; - struct ipr_ext_vpd cfc_vpd; - struct ipr_ext_vpd ioa_last_attached_to_cfc_vpd; - struct ipr_ext_vpd cfc_last_attached_to_ioa_vpd; - __be32 ioa_data[3]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_03_error { - struct ipr_vpd ioa_vpd; - struct ipr_vpd cfc_vpd; - __be32 errors_detected; - __be32 errors_logged; - u8 ioa_data[12]; - struct ipr_hostrcb_device_data_entry dev[3]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_13_error { - struct ipr_ext_vpd ioa_vpd; - struct ipr_ext_vpd cfc_vpd; - __be32 errors_detected; - __be32 errors_logged; - struct ipr_hostrcb_device_data_entry_enhanced dev[3]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_23_error { - struct ipr_ext_vpd ioa_vpd; - struct ipr_ext_vpd cfc_vpd; - __be32 errors_detected; - __be32 errors_logged; - struct ipr_hostrcb64_device_data_entry_enhanced dev[3]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_04_error { - struct ipr_vpd ioa_vpd; - struct ipr_vpd cfc_vpd; - u8 ioa_data[12]; - struct ipr_hostrcb_array_data_entry array_member[10]; - __be32 exposed_mode_adn; - __be32 array_id; - struct ipr_vpd incomp_dev_vpd; - __be32 ioa_data2; - struct ipr_hostrcb_array_data_entry array_member2[8]; - struct ipr_res_addr last_func_vset_res_addr; - u8 vset_serial_num[IPR_SERIAL_NUM_LEN]; - u8 protection_level[8]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_14_error { - struct ipr_ext_vpd ioa_vpd; - struct ipr_ext_vpd cfc_vpd; - __be32 exposed_mode_adn; - __be32 array_id; - struct ipr_res_addr last_func_vset_res_addr; - u8 vset_serial_num[IPR_SERIAL_NUM_LEN]; - u8 protection_level[8]; - __be32 num_entries; - struct ipr_hostrcb_array_data_entry_enhanced array_member[18]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_24_error { - struct ipr_ext_vpd ioa_vpd; - struct ipr_ext_vpd cfc_vpd; - u8 reserved[2]; - u8 exposed_mode_adn; -#define IPR_INVALID_ARRAY_DEV_NUM 0xff - u8 array_id; - u8 last_res_path[8]; - u8 protection_level[8]; - struct ipr_ext_vpd64 array_vpd; - u8 description[16]; - u8 reserved2[3]; - u8 num_entries; - struct ipr_hostrcb64_array_data_entry array_member[32]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_07_error { - u8 failure_reason[64]; - struct ipr_vpd vpd; - u32 data[222]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_17_error { - u8 failure_reason[64]; - struct ipr_ext_vpd vpd; - u32 data[476]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_config_element { - u8 type_status; -#define IPR_PATH_CFG_TYPE_MASK 0xF0 -#define IPR_PATH_CFG_NOT_EXIST 0x00 -#define IPR_PATH_CFG_IOA_PORT 0x10 -#define IPR_PATH_CFG_EXP_PORT 0x20 -#define IPR_PATH_CFG_DEVICE_PORT 0x30 -#define IPR_PATH_CFG_DEVICE_LUN 0x40 - -#define IPR_PATH_CFG_STATUS_MASK 0x0F -#define IPR_PATH_CFG_NO_PROB 0x00 -#define IPR_PATH_CFG_DEGRADED 0x01 -#define IPR_PATH_CFG_FAILED 0x02 -#define IPR_PATH_CFG_SUSPECT 0x03 -#define IPR_PATH_NOT_DETECTED 0x04 -#define IPR_PATH_INCORRECT_CONN 0x05 - - u8 cascaded_expander; - u8 phy; - u8 link_rate; -#define IPR_PHY_LINK_RATE_MASK 0x0F - - __be32 wwid[2]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb64_config_element { - __be16 length; - u8 descriptor_id; -#define IPR_DESCRIPTOR_MASK 0xC0 -#define IPR_DESCRIPTOR_SIS64 0x00 - - u8 reserved; - u8 type_status; - - u8 reserved2[2]; - u8 link_rate; - - u8 res_path[8]; - __be32 wwid[2]; -}__attribute__((packed, aligned (8))); - -struct ipr_hostrcb_fabric_desc { - __be16 length; - u8 ioa_port; - u8 cascaded_expander; - u8 phy; - u8 path_state; -#define IPR_PATH_ACTIVE_MASK 0xC0 -#define IPR_PATH_NO_INFO 0x00 -#define IPR_PATH_ACTIVE 0x40 -#define IPR_PATH_NOT_ACTIVE 0x80 - -#define IPR_PATH_STATE_MASK 0x0F -#define IPR_PATH_STATE_NO_INFO 0x00 -#define IPR_PATH_HEALTHY 0x01 -#define IPR_PATH_DEGRADED 0x02 -#define IPR_PATH_FAILED 0x03 - - __be16 num_entries; - struct ipr_hostrcb_config_element elem[1]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb64_fabric_desc { - __be16 length; - u8 descriptor_id; - - u8 reserved[2]; - u8 path_state; - - u8 reserved2[2]; - u8 res_path[8]; - u8 reserved3[6]; - __be16 num_entries; - struct ipr_hostrcb64_config_element elem[1]; -}__attribute__((packed, aligned (8))); - -#define for_each_fabric_cfg(fabric, cfg) \ - for (cfg = (fabric)->elem; \ - cfg < ((fabric)->elem + be16_to_cpu((fabric)->num_entries)); \ - cfg++) - -struct ipr_hostrcb_type_20_error { - u8 failure_reason[64]; - u8 reserved[3]; - u8 num_entries; - struct ipr_hostrcb_fabric_desc desc[1]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_type_30_error { - u8 failure_reason[64]; - u8 reserved[3]; - u8 num_entries; - struct ipr_hostrcb64_fabric_desc desc[1]; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb_error { - __be32 fd_ioasc; - struct ipr_res_addr fd_res_addr; - __be32 fd_res_handle; - __be32 prc; - union { - struct ipr_hostrcb_type_ff_error type_ff_error; - struct ipr_hostrcb_type_01_error type_01_error; - struct ipr_hostrcb_type_02_error type_02_error; - struct ipr_hostrcb_type_03_error type_03_error; - struct ipr_hostrcb_type_04_error type_04_error; - struct ipr_hostrcb_type_07_error type_07_error; - struct ipr_hostrcb_type_12_error type_12_error; - struct ipr_hostrcb_type_13_error type_13_error; - struct ipr_hostrcb_type_14_error type_14_error; - struct ipr_hostrcb_type_17_error type_17_error; - struct ipr_hostrcb_type_20_error type_20_error; - } u; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb64_error { - __be32 fd_ioasc; - __be32 ioa_fw_level; - __be32 fd_res_handle; - __be32 prc; - __be64 fd_dev_id; - __be64 fd_lun; - u8 fd_res_path[8]; - __be64 time_stamp; - u8 reserved[16]; - union { - struct ipr_hostrcb_type_ff_error type_ff_error; - struct ipr_hostrcb_type_12_error type_12_error; - struct ipr_hostrcb_type_17_error type_17_error; - struct ipr_hostrcb_type_23_error type_23_error; - struct ipr_hostrcb_type_24_error type_24_error; - struct ipr_hostrcb_type_30_error type_30_error; - } u; -}__attribute__((packed, aligned (8))); - -struct ipr_hostrcb_raw { - __be32 data[sizeof(struct ipr_hostrcb_error)/sizeof(__be32)]; -}__attribute__((packed, aligned (4))); - -struct ipr_hcam { - u8 op_code; -#define IPR_HOST_RCB_OP_CODE_CONFIG_CHANGE 0xE1 -#define IPR_HOST_RCB_OP_CODE_LOG_DATA 0xE2 - - u8 notify_type; -#define IPR_HOST_RCB_NOTIF_TYPE_EXISTING_CHANGED 0x00 -#define IPR_HOST_RCB_NOTIF_TYPE_NEW_ENTRY 0x01 -#define IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY 0x02 -#define IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY 0x10 -#define IPR_HOST_RCB_NOTIF_TYPE_INFORMATION_ENTRY 0x11 - - u8 notifications_lost; -#define IPR_HOST_RCB_NO_NOTIFICATIONS_LOST 0 -#define IPR_HOST_RCB_NOTIFICATIONS_LOST 0x80 - - u8 flags; -#define IPR_HOSTRCB_INTERNAL_OPER 0x80 -#define IPR_HOSTRCB_ERR_RESP_SENT 0x40 - - u8 overlay_id; -#define IPR_HOST_RCB_OVERLAY_ID_1 0x01 -#define IPR_HOST_RCB_OVERLAY_ID_2 0x02 -#define IPR_HOST_RCB_OVERLAY_ID_3 0x03 -#define IPR_HOST_RCB_OVERLAY_ID_4 0x04 -#define IPR_HOST_RCB_OVERLAY_ID_6 0x06 -#define IPR_HOST_RCB_OVERLAY_ID_7 0x07 -#define IPR_HOST_RCB_OVERLAY_ID_12 0x12 -#define IPR_HOST_RCB_OVERLAY_ID_13 0x13 -#define IPR_HOST_RCB_OVERLAY_ID_14 0x14 -#define IPR_HOST_RCB_OVERLAY_ID_16 0x16 -#define IPR_HOST_RCB_OVERLAY_ID_17 0x17 -#define IPR_HOST_RCB_OVERLAY_ID_20 0x20 -#define IPR_HOST_RCB_OVERLAY_ID_23 0x23 -#define IPR_HOST_RCB_OVERLAY_ID_24 0x24 -#define IPR_HOST_RCB_OVERLAY_ID_26 0x26 -#define IPR_HOST_RCB_OVERLAY_ID_30 0x30 -#define IPR_HOST_RCB_OVERLAY_ID_DEFAULT 0xFF - - u8 reserved1[3]; - __be32 ilid; - __be32 time_since_last_ioa_reset; - __be32 reserved2; - __be32 length; - - union { - struct ipr_hostrcb_error error; - struct ipr_hostrcb64_error error64; - struct ipr_hostrcb_cfg_ch_not ccn; - struct ipr_hostrcb_raw raw; - } u; -}__attribute__((packed, aligned (4))); - -struct ipr_hostrcb { - struct ipr_hcam hcam; - dma_addr_t hostrcb_dma; - struct list_head queue; - struct ipr_ioa_cfg *ioa_cfg; - char rp_buffer[IPR_MAX_RES_PATH_LENGTH]; -}; - -/* IPR smart dump table structures */ -struct ipr_sdt_entry { - __be32 start_token; - __be32 end_token; - u8 reserved[4]; - - u8 flags; -#define IPR_SDT_ENDIAN 0x80 -#define IPR_SDT_VALID_ENTRY 0x20 - - u8 resv; - __be16 priority; -}__attribute__((packed, aligned (4))); - -struct ipr_sdt_header { - __be32 state; - __be32 num_entries; - __be32 num_entries_used; - __be32 dump_size; -}__attribute__((packed, aligned (4))); - -struct ipr_sdt { - struct ipr_sdt_header hdr; - struct ipr_sdt_entry entry[IPR_FMT3_NUM_SDT_ENTRIES]; -}__attribute__((packed, aligned (4))); - -struct ipr_uc_sdt { - struct ipr_sdt_header hdr; - struct ipr_sdt_entry entry[1]; -}__attribute__((packed, aligned (4))); - -/* - * Driver types - */ -struct ipr_bus_attributes { - u8 bus; - u8 qas_enabled; - u8 bus_width; - u8 reserved; - u32 max_xfer_rate; -}; - -struct ipr_sata_port { - struct ipr_ioa_cfg *ioa_cfg; - struct ata_port *ap; - struct ipr_resource_entry *res; - struct ipr_ioasa_gata ioasa; -}; - -struct ipr_resource_entry { - u8 needs_sync_complete:1; - u8 in_erp:1; - u8 add_to_ml:1; - u8 del_from_ml:1; - u8 resetting_device:1; - - u32 bus; /* AKA channel */ - u32 target; /* AKA id */ - u32 lun; -#define IPR_ARRAY_VIRTUAL_BUS 0x1 -#define IPR_VSET_VIRTUAL_BUS 0x2 -#define IPR_IOAFP_VIRTUAL_BUS 0x3 - -#define IPR_GET_RES_PHYS_LOC(res) \ - (((res)->bus << 24) | ((res)->target << 8) | (res)->lun) - - u8 ata_class; - - u8 flags; - __be16 res_flags; - - u8 type; - - u8 qmodel; - struct ipr_std_inq_data std_inq_data; - - __be32 res_handle; - __be64 dev_id; - __be64 lun_wwn; - struct scsi_lun dev_lun; - u8 res_path[8]; - - struct ipr_ioa_cfg *ioa_cfg; - struct scsi_device *sdev; - struct ipr_sata_port *sata_port; - struct list_head queue; -}; /* struct ipr_resource_entry */ - -struct ipr_resource_hdr { - u16 num_entries; - u16 reserved; -}; - -struct ipr_misc_cbs { - struct ipr_ioa_vpd ioa_vpd; - struct ipr_inquiry_page0 page0_data; - struct ipr_inquiry_page3 page3_data; - struct ipr_inquiry_cap cap; - struct ipr_mode_pages mode_pages; - struct ipr_supported_device supp_dev; -}; - -struct ipr_interrupt_offsets { - unsigned long set_interrupt_mask_reg; - unsigned long clr_interrupt_mask_reg; - unsigned long clr_interrupt_mask_reg32; - unsigned long sense_interrupt_mask_reg; - unsigned long sense_interrupt_mask_reg32; - unsigned long clr_interrupt_reg; - unsigned long clr_interrupt_reg32; - - unsigned long sense_interrupt_reg; - unsigned long sense_interrupt_reg32; - unsigned long ioarrin_reg; - unsigned long sense_uproc_interrupt_reg; - unsigned long sense_uproc_interrupt_reg32; - unsigned long set_uproc_interrupt_reg; - unsigned long set_uproc_interrupt_reg32; - unsigned long clr_uproc_interrupt_reg; - unsigned long clr_uproc_interrupt_reg32; - - unsigned long init_feedback_reg; - - unsigned long dump_addr_reg; - unsigned long dump_data_reg; - -#define IPR_ENDIAN_SWAP_KEY 0x00080800 - unsigned long endian_swap_reg; -}; - -struct ipr_interrupts { - void __iomem *set_interrupt_mask_reg; - void __iomem *clr_interrupt_mask_reg; - void __iomem *clr_interrupt_mask_reg32; - void __iomem *sense_interrupt_mask_reg; - void __iomem *sense_interrupt_mask_reg32; - void __iomem *clr_interrupt_reg; - void __iomem *clr_interrupt_reg32; - - void __iomem *sense_interrupt_reg; - void __iomem *sense_interrupt_reg32; - void __iomem *ioarrin_reg; - void __iomem *sense_uproc_interrupt_reg; - void __iomem *sense_uproc_interrupt_reg32; - void __iomem *set_uproc_interrupt_reg; - void __iomem *set_uproc_interrupt_reg32; - void __iomem *clr_uproc_interrupt_reg; - void __iomem *clr_uproc_interrupt_reg32; - - void __iomem *init_feedback_reg; - - void __iomem *dump_addr_reg; - void __iomem *dump_data_reg; - - void __iomem *endian_swap_reg; -}; - -struct ipr_chip_cfg_t { - u32 mailbox; - u16 max_cmds; - u8 cache_line_size; - u8 clear_isr; - struct ipr_interrupt_offsets regs; -}; - -struct ipr_chip_t { - u16 vendor; - u16 device; - u16 intr_type; -#define IPR_USE_LSI 0x00 -#define IPR_USE_MSI 0x01 - u16 sis_type; -#define IPR_SIS32 0x00 -#define IPR_SIS64 0x01 - u16 bist_method; -#define IPR_PCI_CFG 0x00 -#define IPR_MMIO 0x01 - const struct ipr_chip_cfg_t *cfg; -}; - -enum ipr_shutdown_type { - IPR_SHUTDOWN_NORMAL = 0x00, - IPR_SHUTDOWN_PREPARE_FOR_NORMAL = 0x40, - IPR_SHUTDOWN_ABBREV = 0x80, - IPR_SHUTDOWN_NONE = 0x100 -}; - -struct ipr_trace_entry { - u32 time; - - u8 op_code; - u8 ata_op_code; - u8 type; -#define IPR_TRACE_START 0x00 -#define IPR_TRACE_FINISH 0xff - u8 cmd_index; - - __be32 res_handle; - union { - u32 ioasc; - u32 add_data; - u32 res_addr; - } u; -}; - -struct ipr_sglist { - u32 order; - u32 num_sg; - u32 num_dma_sg; - u32 buffer_len; - struct scatterlist scatterlist[1]; -}; - -enum ipr_sdt_state { - INACTIVE, - WAIT_FOR_DUMP, - GET_DUMP, - READ_DUMP, - ABORT_DUMP, - DUMP_OBTAINED -}; - -/* Per-controller data */ -struct ipr_ioa_cfg { - char eye_catcher[8]; -#define IPR_EYECATCHER "iprcfg" - - struct list_head queue; - - u8 allow_interrupts:1; - u8 in_reset_reload:1; - u8 in_ioa_bringdown:1; - u8 ioa_unit_checked:1; - u8 ioa_is_dead:1; - u8 dump_taken:1; - u8 allow_cmds:1; - u8 allow_ml_add_del:1; - u8 needs_hard_reset:1; - u8 dual_raid:1; - u8 needs_warm_reset:1; - u8 msi_received:1; - u8 sis64:1; - u8 dump_timeout:1; - u8 cfg_locked:1; - u8 clear_isr:1; - - u8 revid; - - /* - * Bitmaps for SIS64 generated target values - */ - unsigned long *target_ids; - unsigned long *array_ids; - unsigned long *vset_ids; - - u16 type; /* CCIN of the card */ - - u8 log_level; -#define IPR_MAX_LOG_LEVEL 4 -#define IPR_DEFAULT_LOG_LEVEL 2 - -#define IPR_NUM_TRACE_INDEX_BITS 8 -#define IPR_NUM_TRACE_ENTRIES (1 << IPR_NUM_TRACE_INDEX_BITS) -#define IPR_TRACE_SIZE (sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES) - char trace_start[8]; -#define IPR_TRACE_START_LABEL "trace" - struct ipr_trace_entry *trace; - u32 trace_index:IPR_NUM_TRACE_INDEX_BITS; - - /* - * Queue for free command blocks - */ - char ipr_free_label[8]; -#define IPR_FREEQ_LABEL "free-q" - struct list_head free_q; - - /* - * Queue for command blocks outstanding to the adapter - */ - char ipr_pending_label[8]; -#define IPR_PENDQ_LABEL "pend-q" - struct list_head pending_q; - - char cfg_table_start[8]; -#define IPR_CFG_TBL_START "cfg" - union { - struct ipr_config_table *cfg_table; - struct ipr_config_table64 *cfg_table64; - } u; - dma_addr_t cfg_table_dma; - u32 cfg_table_size; - u32 max_devs_supported; - - char resource_table_label[8]; -#define IPR_RES_TABLE_LABEL "res_tbl" - struct ipr_resource_entry *res_entries; - struct list_head free_res_q; - struct list_head used_res_q; - - char ipr_hcam_label[8]; -#define IPR_HCAM_LABEL "hcams" - struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS]; - dma_addr_t hostrcb_dma[IPR_NUM_HCAMS]; - struct list_head hostrcb_free_q; - struct list_head hostrcb_pending_q; - - __be32 *host_rrq; - dma_addr_t host_rrq_dma; -#define IPR_HRRQ_REQ_RESP_HANDLE_MASK 0xfffffffc -#define IPR_HRRQ_RESP_BIT_SET 0x00000002 -#define IPR_HRRQ_TOGGLE_BIT 0x00000001 -#define IPR_HRRQ_REQ_RESP_HANDLE_SHIFT 2 - volatile __be32 *hrrq_start; - volatile __be32 *hrrq_end; - volatile __be32 *hrrq_curr; - volatile u32 toggle_bit; - - struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES]; - - unsigned int transop_timeout; - const struct ipr_chip_cfg_t *chip_cfg; - const struct ipr_chip_t *ipr_chip; - - void __iomem *hdw_dma_regs; /* iomapped PCI memory space */ - unsigned long hdw_dma_regs_pci; /* raw PCI memory space */ - void __iomem *ioa_mailbox; - struct ipr_interrupts regs; - - u16 saved_pcix_cmd_reg; - u16 reset_retries; - - u32 errors_logged; - u32 doorbell; - - struct Scsi_Host *host; - struct pci_dev *pdev; - struct ipr_sglist *ucode_sglist; - u8 saved_mode_page_len; - - struct work_struct work_q; - - wait_queue_head_t reset_wait_q; - wait_queue_head_t msi_wait_q; - - struct ipr_dump *dump; - enum ipr_sdt_state sdt_state; - - struct ipr_misc_cbs *vpd_cbs; - dma_addr_t vpd_cbs_dma; - - struct pci_pool *ipr_cmd_pool; - - struct ipr_cmnd *reset_cmd; - int (*reset) (struct ipr_cmnd *); - - struct ata_host ata_host; - char ipr_cmd_label[8]; -#define IPR_CMD_LABEL "ipr_cmd" - u32 max_cmds; - struct ipr_cmnd **ipr_cmnd_list; - dma_addr_t *ipr_cmnd_list_dma; -}; /* struct ipr_ioa_cfg */ - -struct ipr_cmnd { - struct ipr_ioarcb ioarcb; - union { - struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES]; - struct ipr_ioadl64_desc ioadl64[IPR_NUM_IOADL_ENTRIES]; - struct ipr_ata64_ioadl ata_ioadl; - } i; - union { - struct ipr_ioasa ioasa; - struct ipr_ioasa64 ioasa64; - } s; - struct list_head queue; - struct scsi_cmnd *scsi_cmd; - struct ata_queued_cmd *qc; - struct completion completion; - struct timer_list timer; - void (*done) (struct ipr_cmnd *); - int (*job_step) (struct ipr_cmnd *); - int (*job_step_failed) (struct ipr_cmnd *); - u16 cmd_index; - u8 sense_buffer[SCSI_SENSE_BUFFERSIZE]; - dma_addr_t sense_buffer_dma; - unsigned short dma_use_sg; - dma_addr_t dma_addr; - struct ipr_cmnd *sibling; - union { - enum ipr_shutdown_type shutdown_type; - struct ipr_hostrcb *hostrcb; - unsigned long time_left; - unsigned long scratch; - struct ipr_resource_entry *res; - struct scsi_device *sdev; - } u; - - struct ipr_ioa_cfg *ioa_cfg; -}; - -struct ipr_ses_table_entry { - char product_id[17]; - char compare_product_id_byte[17]; - u32 max_bus_speed_limit; /* MB/sec limit for this backplane */ -}; - -struct ipr_dump_header { - u32 eye_catcher; -#define IPR_DUMP_EYE_CATCHER 0xC5D4E3F2 - u32 len; - u32 num_entries; - u32 first_entry_offset; - u32 status; -#define IPR_DUMP_STATUS_SUCCESS 0 -#define IPR_DUMP_STATUS_QUAL_SUCCESS 2 -#define IPR_DUMP_STATUS_FAILED 0xffffffff - u32 os; -#define IPR_DUMP_OS_LINUX 0x4C4E5558 - u32 driver_name; -#define IPR_DUMP_DRIVER_NAME 0x49505232 -}__attribute__((packed, aligned (4))); - -struct ipr_dump_entry_header { - u32 eye_catcher; -#define IPR_DUMP_EYE_CATCHER 0xC5D4E3F2 - u32 len; - u32 num_elems; - u32 offset; - u32 data_type; -#define IPR_DUMP_DATA_TYPE_ASCII 0x41534349 -#define IPR_DUMP_DATA_TYPE_BINARY 0x42494E41 - u32 id; -#define IPR_DUMP_IOA_DUMP_ID 0x494F4131 -#define IPR_DUMP_LOCATION_ID 0x4C4F4341 -#define IPR_DUMP_TRACE_ID 0x54524143 -#define IPR_DUMP_DRIVER_VERSION_ID 0x44525652 -#define IPR_DUMP_DRIVER_TYPE_ID 0x54595045 -#define IPR_DUMP_IOA_CTRL_BLK 0x494F4342 -#define IPR_DUMP_PEND_OPS 0x414F5053 - u32 status; -}__attribute__((packed, aligned (4))); - -struct ipr_dump_location_entry { - struct ipr_dump_entry_header hdr; - u8 location[20]; -}__attribute__((packed)); - -struct ipr_dump_trace_entry { - struct ipr_dump_entry_header hdr; - u32 trace[IPR_TRACE_SIZE / sizeof(u32)]; -}__attribute__((packed, aligned (4))); - -struct ipr_dump_version_entry { - struct ipr_dump_entry_header hdr; - u8 version[sizeof(IPR_DRIVER_VERSION)]; -}; - -struct ipr_dump_ioa_type_entry { - struct ipr_dump_entry_header hdr; - u32 type; - u32 fw_version; -}; - -struct ipr_driver_dump { - struct ipr_dump_header hdr; - struct ipr_dump_version_entry version_entry; - struct ipr_dump_location_entry location_entry; - struct ipr_dump_ioa_type_entry ioa_type_entry; - struct ipr_dump_trace_entry trace_entry; -}__attribute__((packed)); - -struct ipr_ioa_dump { - struct ipr_dump_entry_header hdr; - struct ipr_sdt sdt; - __be32 **ioa_data; - u32 reserved; - u32 next_page_index; - u32 page_offset; - u32 format; -}__attribute__((packed, aligned (4))); - -struct ipr_dump { - struct kref kref; - struct ipr_ioa_cfg *ioa_cfg; - struct ipr_driver_dump driver_dump; - struct ipr_ioa_dump ioa_dump; -}; - -struct ipr_error_table_t { - u32 ioasc; - int log_ioasa; - int log_hcam; - char *error; -}; - -struct ipr_software_inq_lid_info { - __be32 load_id; - __be32 timestamp[3]; -}__attribute__((packed, aligned (4))); - -struct ipr_ucode_image_header { - __be32 header_length; - __be32 lid_table_offset; - u8 major_release; - u8 card_type; - u8 minor_release[2]; - u8 reserved[20]; - char eyecatcher[16]; - __be32 num_lids; - struct ipr_software_inq_lid_info lid[1]; -}__attribute__((packed, aligned (4))); - -/* - * Macros - */ -#define IPR_DBG_CMD(CMD) if (ipr_debug) { CMD; } - -#ifdef CONFIG_SCSI_IPR_TRACE -#define ipr_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr) -#define ipr_remove_trace_file(kobj, attr) sysfs_remove_bin_file(kobj, attr) -#else -#define ipr_create_trace_file(kobj, attr) 0 -#define ipr_remove_trace_file(kobj, attr) do { } while(0) -#endif - -#ifdef CONFIG_SCSI_IPR_DUMP -#define ipr_create_dump_file(kobj, attr) sysfs_create_bin_file(kobj, attr) -#define ipr_remove_dump_file(kobj, attr) sysfs_remove_bin_file(kobj, attr) -#else -#define ipr_create_dump_file(kobj, attr) 0 -#define ipr_remove_dump_file(kobj, attr) do { } while(0) -#endif - -/* - * Error logging macros - */ -#define ipr_err(...) printk(KERN_ERR IPR_NAME ": "__VA_ARGS__) -#define ipr_info(...) printk(KERN_INFO IPR_NAME ": "__VA_ARGS__) -#define ipr_dbg(...) IPR_DBG_CMD(printk(KERN_INFO IPR_NAME ": "__VA_ARGS__)) - -#define ipr_res_printk(level, ioa_cfg, bus, target, lun, fmt, ...) \ - printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, (ioa_cfg)->host->host_no, \ - bus, target, lun, ##__VA_ARGS__) - -#define ipr_res_err(ioa_cfg, res, fmt, ...) \ - ipr_res_printk(KERN_ERR, ioa_cfg, (res)->bus, (res)->target, (res)->lun, fmt, ##__VA_ARGS__) - -#define ipr_ra_printk(level, ioa_cfg, ra, fmt, ...) \ - printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, (ioa_cfg)->host->host_no, \ - (ra).bus, (ra).target, (ra).lun, ##__VA_ARGS__) - -#define ipr_ra_err(ioa_cfg, ra, fmt, ...) \ - ipr_ra_printk(KERN_ERR, ioa_cfg, ra, fmt, ##__VA_ARGS__) - -#define ipr_phys_res_err(ioa_cfg, res, fmt, ...) \ -{ \ - if ((res).bus >= IPR_MAX_NUM_BUSES) { \ - ipr_err(fmt": unknown\n", ##__VA_ARGS__); \ - } else { \ - ipr_err(fmt": %d:%d:%d:%d\n", \ - ##__VA_ARGS__, (ioa_cfg)->host->host_no, \ - (res).bus, (res).target, (res).lun); \ - } \ -} - -#define ipr_hcam_err(hostrcb, fmt, ...) \ -{ \ - if (ipr_is_device(hostrcb)) { \ - if ((hostrcb)->ioa_cfg->sis64) { \ - printk(KERN_ERR IPR_NAME ": %s: " fmt, \ - ipr_format_res_path(hostrcb->hcam.u.error64.fd_res_path, \ - hostrcb->rp_buffer, \ - sizeof(hostrcb->rp_buffer)), \ - __VA_ARGS__); \ - } else { \ - ipr_ra_err((hostrcb)->ioa_cfg, \ - (hostrcb)->hcam.u.error.fd_res_addr, \ - fmt, __VA_ARGS__); \ - } \ - } else { \ - dev_err(&(hostrcb)->ioa_cfg->pdev->dev, fmt, __VA_ARGS__); \ - } \ -} - -#define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\ - __FILE__, __func__, __LINE__) - -#define ENTER IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Entering %s\n", __func__)) -#define LEAVE IPR_DBG_CMD(printk(KERN_INFO IPR_NAME": Leaving %s\n", __func__)) - -#define ipr_err_separator \ -ipr_err("----------------------------------------------------------\n") - - -/* - * Inlines - */ - -/** - * ipr_is_ioa_resource - Determine if a resource is the IOA - * @res: resource entry struct - * - * Return value: - * 1 if IOA / 0 if not IOA - **/ -static inline int ipr_is_ioa_resource(struct ipr_resource_entry *res) -{ - return res->type == IPR_RES_TYPE_IOAFP; -} - -/** - * ipr_is_af_dasd_device - Determine if a resource is an AF DASD - * @res: resource entry struct - * - * Return value: - * 1 if AF DASD / 0 if not AF DASD - **/ -static inline int ipr_is_af_dasd_device(struct ipr_resource_entry *res) -{ - return res->type == IPR_RES_TYPE_AF_DASD || - res->type == IPR_RES_TYPE_REMOTE_AF_DASD; -} - -/** - * ipr_is_vset_device - Determine if a resource is a VSET - * @res: resource entry struct - * - * Return value: - * 1 if VSET / 0 if not VSET - **/ -static inline int ipr_is_vset_device(struct ipr_resource_entry *res) -{ - return res->type == IPR_RES_TYPE_VOLUME_SET; -} - -/** - * ipr_is_gscsi - Determine if a resource is a generic scsi resource - * @res: resource entry struct - * - * Return value: - * 1 if GSCSI / 0 if not GSCSI - **/ -static inline int ipr_is_gscsi(struct ipr_resource_entry *res) -{ - return res->type == IPR_RES_TYPE_GENERIC_SCSI; -} - -/** - * ipr_is_scsi_disk - Determine if a resource is a SCSI disk - * @res: resource entry struct - * - * Return value: - * 1 if SCSI disk / 0 if not SCSI disk - **/ -static inline int ipr_is_scsi_disk(struct ipr_resource_entry *res) -{ - if (ipr_is_af_dasd_device(res) || - (ipr_is_gscsi(res) && IPR_IS_DASD_DEVICE(res->std_inq_data))) - return 1; - else - return 0; -} - -/** - * ipr_is_gata - Determine if a resource is a generic ATA resource - * @res: resource entry struct - * - * Return value: - * 1 if GATA / 0 if not GATA - **/ -static inline int ipr_is_gata(struct ipr_resource_entry *res) -{ - return res->type == IPR_RES_TYPE_GENERIC_ATA; -} - -/** - * ipr_is_naca_model - Determine if a resource is using NACA queueing model - * @res: resource entry struct - * - * Return value: - * 1 if NACA queueing model / 0 if not NACA queueing model - **/ -static inline int ipr_is_naca_model(struct ipr_resource_entry *res) -{ - if (ipr_is_gscsi(res) && res->qmodel == IPR_QUEUE_NACA_MODEL) - return 1; - return 0; -} - -/** - * ipr_is_device - Determine if the hostrcb structure is related to a device - * @hostrcb: host resource control blocks struct - * - * Return value: - * 1 if AF / 0 if not AF - **/ -static inline int ipr_is_device(struct ipr_hostrcb *hostrcb) -{ - struct ipr_res_addr *res_addr; - u8 *res_path; - - if (hostrcb->ioa_cfg->sis64) { - res_path = &hostrcb->hcam.u.error64.fd_res_path[0]; - if ((res_path[0] == 0x00 || res_path[0] == 0x80 || - res_path[0] == 0x81) && res_path[2] != 0xFF) - return 1; - } else { - res_addr = &hostrcb->hcam.u.error.fd_res_addr; - - if ((res_addr->bus < IPR_MAX_NUM_BUSES) && - (res_addr->target < (IPR_MAX_NUM_TARGETS_PER_BUS - 1))) - return 1; - } - return 0; -} - -/** - * ipr_sdt_is_fmt2 - Determine if a SDT address is in format 2 - * @sdt_word: SDT address - * - * Return value: - * 1 if format 2 / 0 if not - **/ -static inline int ipr_sdt_is_fmt2(u32 sdt_word) -{ - u32 bar_sel = IPR_GET_FMT2_BAR_SEL(sdt_word); - - switch (bar_sel) { - case IPR_SDT_FMT2_BAR0_SEL: - case IPR_SDT_FMT2_BAR1_SEL: - case IPR_SDT_FMT2_BAR2_SEL: - case IPR_SDT_FMT2_BAR3_SEL: - case IPR_SDT_FMT2_BAR4_SEL: - case IPR_SDT_FMT2_BAR5_SEL: - case IPR_SDT_FMT2_EXP_ROM_SEL: - return 1; - }; - - return 0; -} - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(((u32) (val >> 32)), addr); - writel(((u32) (val)), (addr + 4)); -} -#endif - -#endif /* _IPR_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/ips.c b/ANDROID_3.4.5/drivers/scsi/ips.c deleted file mode 100644 index b6d7a5c2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ips.c +++ /dev/null @@ -1,7247 +0,0 @@ -/*****************************************************************************/ -/* ips.c -- driver for the Adaptec / IBM ServeRAID controller */ -/* */ -/* Written By: Keith Mitchell, IBM Corporation */ -/* Jack Hammer, Adaptec, Inc. */ -/* David Jeffery, Adaptec, Inc. */ -/* */ -/* Copyright (C) 2000 IBM Corporation */ -/* Copyright (C) 2002,2003 Adaptec, Inc. */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* NO WARRANTY */ -/* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR */ -/* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT */ -/* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, */ -/* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is */ -/* solely responsible for determining the appropriateness of using and */ -/* distributing the Program and assumes all risks associated with its */ -/* exercise of rights under this Agreement, including but not limited to */ -/* the risks and costs of program errors, damage to or loss of data, */ -/* programs or equipment, and unavailability or interruption of operations. */ -/* */ -/* DISCLAIMER OF LIABILITY */ -/* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY */ -/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */ -/* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND */ -/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR */ -/* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE */ -/* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED */ -/* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* */ -/* Bugs/Comments/Suggestions about this driver should be mailed to: */ -/* ipslinux@adaptec.com */ -/* */ -/* For system support issues, contact your local IBM Customer support. */ -/* Directions to find IBM Customer Support for each country can be found at: */ -/* http://www.ibm.com/planetwide/ */ -/* */ -/*****************************************************************************/ - -/*****************************************************************************/ -/* Change Log */ -/* */ -/* 0.99.02 - Breakup commands that are bigger than 8 * the stripe size */ -/* 0.99.03 - Make interrupt routine handle all completed request on the */ -/* adapter not just the first one */ -/* - Make sure passthru commands get woken up if we run out of */ -/* SCBs */ -/* - Send all of the commands on the queue at once rather than */ -/* one at a time since the card will support it. */ -/* 0.99.04 - Fix race condition in the passthru mechanism -- this required */ -/* the interface to the utilities to change */ -/* - Fix error recovery code */ -/* 0.99.05 - Fix an oops when we get certain passthru commands */ -/* 1.00.00 - Initial Public Release */ -/* Functionally equivalent to 0.99.05 */ -/* 3.60.00 - Bump max commands to 128 for use with firmware 3.60 */ -/* - Change version to 3.60 to coincide with release numbering. */ -/* 3.60.01 - Remove bogus error check in passthru routine */ -/* 3.60.02 - Make DCDB direction based on lookup table */ -/* - Only allow one DCDB command to a SCSI ID at a time */ -/* 4.00.00 - Add support for ServeRAID 4 */ -/* 4.00.01 - Add support for First Failure Data Capture */ -/* 4.00.02 - Fix problem with PT DCDB with no buffer */ -/* 4.00.03 - Add alternative passthru interface */ -/* - Add ability to flash BIOS */ -/* 4.00.04 - Rename structures/constants to be prefixed with IPS_ */ -/* 4.00.05 - Remove wish_block from init routine */ -/* - Use linux/spinlock.h instead of asm/spinlock.h for kernels */ -/* 2.3.18 and later */ -/* - Sync with other changes from the 2.3 kernels */ -/* 4.00.06 - Fix timeout with initial FFDC command */ -/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig */ -/* 4.10.00 - Add support for ServeRAID 4M/4L */ -/* 4.10.13 - Fix for dynamic unload and proc file system */ -/* 4.20.03 - Rename version to coincide with new release schedules */ -/* Performance fixes */ -/* Fix truncation of /proc files with cat */ -/* Merge in changes through kernel 2.4.0test1ac21 */ -/* 4.20.13 - Fix some failure cases / reset code */ -/* - Hook into the reboot_notifier to flush the controller cache */ -/* 4.50.01 - Fix problem when there is a hole in logical drive numbering */ -/* 4.70.09 - Use a Common ( Large Buffer ) for Flashing from the JCRM CD */ -/* - Add IPSSEND Flash Support */ -/* - Set Sense Data for Unknown SCSI Command */ -/* - Use Slot Number from NVRAM Page 5 */ -/* - Restore caller's DCDB Structure */ -/* 4.70.12 - Corrective actions for bad controller ( during initialization )*/ -/* 4.70.13 - Don't Send CDB's if we already know the device is not present */ -/* - Don't release HA Lock in ips_next() until SC taken off queue */ -/* - Unregister SCSI device in ips_release() */ -/* 4.70.15 - Fix Breakup for very large ( non-SG ) requests in ips_done() */ -/* 4.71.00 - Change all memory allocations to not use GFP_DMA flag */ -/* Code Clean-Up for 2.4.x kernel */ -/* 4.72.00 - Allow for a Scatter-Gather Element to exceed MAX_XFER Size */ -/* 4.72.01 - I/O Mapped Memory release ( so "insmod ips" does not Fail ) */ -/* - Don't Issue Internal FFDC Command if there are Active Commands */ -/* - Close Window for getting too many IOCTL's active */ -/* 4.80.00 - Make ia64 Safe */ -/* 4.80.04 - Eliminate calls to strtok() if 2.4.x or greater */ -/* - Adjustments to Device Queue Depth */ -/* 4.80.14 - Take all semaphores off stack */ -/* - Clean Up New_IOCTL path */ -/* 4.80.20 - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel ) */ -/* - 5 second delay needed after resetting an i960 adapter */ -/* 4.80.26 - Clean up potential code problems ( Arjan's recommendations ) */ -/* 4.90.01 - Version Matching for FirmWare, BIOS, and Driver */ -/* 4.90.05 - Use New PCI Architecture to facilitate Hot Plug Development */ -/* 4.90.08 - Increase Delays in Flashing ( Trombone Only - 4H ) */ -/* 4.90.08 - Data Corruption if First Scatter Gather Element is > 64K */ -/* 4.90.11 - Don't actually RESET unless it's physically required */ -/* - Remove unused compile options */ -/* 5.00.01 - Sarasota ( 5i ) adapters must always be scanned first */ -/* - Get rid on IOCTL_NEW_COMMAND code */ -/* - Add Extended DCDB Commands for Tape Support in 5I */ -/* 5.10.12 - use pci_dma interfaces, update for 2.5 kernel changes */ -/* 5.10.15 - remove unused code (sem, macros, etc.) */ -/* 5.30.00 - use __devexit_p() */ -/* 6.00.00 - Add 6x Adapters and Battery Flash */ -/* 6.10.00 - Remove 1G Addressing Limitations */ -/* 6.11.xx - Get VersionInfo buffer off the stack ! DDTS 60401 */ -/* 6.11.xx - Make Logical Drive Info structure safe for DMA DDTS 60639 */ -/* 7.10.18 - Add highmem_io flag in SCSI Templete for 2.4 kernels */ -/* - Fix path/name for scsi_hosts.h include for 2.6 kernels */ -/* - Fix sort order of 7k */ -/* - Remove 3 unused "inline" functions */ -/* 7.12.xx - Use STATIC functions wherever possible */ -/* - Clean up deprecated MODULE_PARM calls */ -/* 7.12.05 - Remove Version Matching per IBM request */ -/*****************************************************************************/ - -/* - * Conditional Compilation directives for this driver: - * - * IPS_DEBUG - Turn on debugging info - * - * Parameters: - * - * debug: - Set debug level to - * NOTE: only works when IPS_DEBUG compile directive is used. - * 1 - Normal debug messages - * 2 - Verbose debug messages - * 11 - Method trace (non interrupt) - * 12 - Method trace (includes interrupt) - * - * noi2o - Don't use I2O Queues (ServeRAID 4 only) - * nommap - Don't use memory mapped I/O - * ioctlsize - Initial size of the IOCTL buffer - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include "scsi.h" -#include - -#include "ips.h" - -#include - -#include - -#include -#include - -#include - -#ifdef MODULE -static char *ips = NULL; -module_param(ips, charp, 0); -#endif - -/* - * DRIVER_VER - */ -#define IPS_VERSION_HIGH IPS_VER_MAJOR_STRING "." IPS_VER_MINOR_STRING -#define IPS_VERSION_LOW "." IPS_VER_BUILD_STRING " " - -#if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__) -#warning "This driver has only been tested on the x86/ia64/x86_64 platforms" -#endif - -#define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \ - DMA_NONE == scb->scsi_cmd->sc_data_direction) ? \ - PCI_DMA_BIDIRECTIONAL : \ - scb->scsi_cmd->sc_data_direction) - -#ifdef IPS_DEBUG -#define METHOD_TRACE(s, i) if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n"); -#define DEBUG(i, s) if (ips_debug >= i) printk(KERN_NOTICE s "\n"); -#define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v); -#else -#define METHOD_TRACE(s, i) -#define DEBUG(i, s) -#define DEBUG_VAR(i, s, v...) -#endif - -/* - * Function prototypes - */ -static int ips_detect(struct scsi_host_template *); -static int ips_release(struct Scsi_Host *); -static int ips_eh_abort(struct scsi_cmnd *); -static int ips_eh_reset(struct scsi_cmnd *); -static int ips_queue(struct Scsi_Host *, struct scsi_cmnd *); -static const char *ips_info(struct Scsi_Host *); -static irqreturn_t do_ipsintr(int, void *); -static int ips_hainit(ips_ha_t *); -static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *); -static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int); -static int ips_send_cmd(ips_ha_t *, ips_scb_t *); -static int ips_online(ips_ha_t *, ips_scb_t *); -static int ips_inquiry(ips_ha_t *, ips_scb_t *); -static int ips_rdcap(ips_ha_t *, ips_scb_t *); -static int ips_msense(ips_ha_t *, ips_scb_t *); -static int ips_reqsen(ips_ha_t *, ips_scb_t *); -static int ips_deallocatescbs(ips_ha_t *, int); -static int ips_allocatescbs(ips_ha_t *); -static int ips_reset_copperhead(ips_ha_t *); -static int ips_reset_copperhead_memio(ips_ha_t *); -static int ips_reset_morpheus(ips_ha_t *); -static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *); -static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *); -static int ips_issue_i2o(ips_ha_t *, ips_scb_t *); -static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *); -static int ips_isintr_copperhead(ips_ha_t *); -static int ips_isintr_copperhead_memio(ips_ha_t *); -static int ips_isintr_morpheus(ips_ha_t *); -static int ips_wait(ips_ha_t *, int, int); -static int ips_write_driver_status(ips_ha_t *, int); -static int ips_read_adapter_status(ips_ha_t *, int); -static int ips_read_subsystem_parameters(ips_ha_t *, int); -static int ips_read_config(ips_ha_t *, int); -static int ips_clear_adapter(ips_ha_t *, int); -static int ips_readwrite_page5(ips_ha_t *, int, int); -static int ips_init_copperhead(ips_ha_t *); -static int ips_init_copperhead_memio(ips_ha_t *); -static int ips_init_morpheus(ips_ha_t *); -static int ips_isinit_copperhead(ips_ha_t *); -static int ips_isinit_copperhead_memio(ips_ha_t *); -static int ips_isinit_morpheus(ips_ha_t *); -static int ips_erase_bios(ips_ha_t *); -static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t); -static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t); -static int ips_erase_bios_memio(ips_ha_t *); -static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); -static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t); -static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *); -static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *); -static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *); -static void ips_free_flash_copperhead(ips_ha_t * ha); -static void ips_get_bios_version(ips_ha_t *, int); -static void ips_identify_controller(ips_ha_t *); -static void ips_chkstatus(ips_ha_t *, IPS_STATUS *); -static void ips_enable_int_copperhead(ips_ha_t *); -static void ips_enable_int_copperhead_memio(ips_ha_t *); -static void ips_enable_int_morpheus(ips_ha_t *); -static int ips_intr_copperhead(ips_ha_t *); -static int ips_intr_morpheus(ips_ha_t *); -static void ips_next(ips_ha_t *, int); -static void ipsintr_blocking(ips_ha_t *, struct ips_scb *); -static void ipsintr_done(ips_ha_t *, struct ips_scb *); -static void ips_done(ips_ha_t *, ips_scb_t *); -static void ips_free(ips_ha_t *); -static void ips_init_scb(ips_ha_t *, ips_scb_t *); -static void ips_freescb(ips_ha_t *, ips_scb_t *); -static void ips_setup_funclist(ips_ha_t *); -static void ips_statinit(ips_ha_t *); -static void ips_statinit_memio(ips_ha_t *); -static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t); -static void ips_ffdc_reset(ips_ha_t *, int); -static void ips_ffdc_time(ips_ha_t *); -static uint32_t ips_statupd_copperhead(ips_ha_t *); -static uint32_t ips_statupd_copperhead_memio(ips_ha_t *); -static uint32_t ips_statupd_morpheus(ips_ha_t *); -static ips_scb_t *ips_getscb(ips_ha_t *); -static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *); -static void ips_putq_wait_tail(ips_wait_queue_t *, struct scsi_cmnd *); -static void ips_putq_copp_tail(ips_copp_queue_t *, - ips_copp_wait_item_t *); -static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *); -static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *); -static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *); -static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *, - struct scsi_cmnd *); -static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *, - ips_copp_wait_item_t *); -static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *); - -static int ips_is_passthru(struct scsi_cmnd *); -static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int); -static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *); -static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *); -static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data, - unsigned int count); -static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data, - unsigned int count); - -static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); -static int ips_host_info(ips_ha_t *, char *, off_t, int); -static void copy_mem_info(IPS_INFOSTR *, char *, int); -static int copy_info(IPS_INFOSTR *, char *, ...); -static int ips_abort_init(ips_ha_t * ha, int index); -static int ips_init_phase2(int index); - -static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr); -static int ips_register_scsi(int index); - -static int ips_poll_for_flush_complete(ips_ha_t * ha); -static void ips_flush_and_reset(ips_ha_t *ha); - -/* - * global variables - */ -static const char ips_name[] = "ips"; -static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS]; /* Array of host controller structures */ -static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS]; /* Array of HA structures */ -static unsigned int ips_next_controller; -static unsigned int ips_num_controllers; -static unsigned int ips_released_controllers; -static int ips_hotplug; -static int ips_cmd_timeout = 60; -static int ips_reset_timeout = 60 * 5; -static int ips_force_memio = 1; /* Always use Memory Mapped I/O */ -static int ips_force_i2o = 1; /* Always use I2O command delivery */ -static int ips_ioctlsize = IPS_IOCTL_SIZE; /* Size of the ioctl buffer */ -static int ips_cd_boot; /* Booting from Manager CD */ -static char *ips_FlashData = NULL; /* CD Boot - Flash Data Buffer */ -static dma_addr_t ips_flashbusaddr; -static long ips_FlashDataInUse; /* CD Boot - Flash Data In Use Flag */ -static uint32_t MaxLiteCmds = 32; /* Max Active Cmds for a Lite Adapter */ -static struct scsi_host_template ips_driver_template = { - .detect = ips_detect, - .release = ips_release, - .info = ips_info, - .queuecommand = ips_queue, - .eh_abort_handler = ips_eh_abort, - .eh_host_reset_handler = ips_eh_reset, - .proc_name = "ips", - .proc_info = ips_proc_info, - .slave_configure = ips_slave_configure, - .bios_param = ips_biosparam, - .this_id = -1, - .sg_tablesize = IPS_MAX_SG, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, -}; - - -/* This table describes all ServeRAID Adapters */ -static struct pci_device_id ips_pci_table[] = { - { 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 }, - { 0, } -}; - -MODULE_DEVICE_TABLE( pci, ips_pci_table ); - -static char ips_hot_plug_name[] = "ips"; - -static int __devinit ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent); -static void __devexit ips_remove_device(struct pci_dev *pci_dev); - -static struct pci_driver ips_pci_driver = { - .name = ips_hot_plug_name, - .id_table = ips_pci_table, - .probe = ips_insert_device, - .remove = __devexit_p(ips_remove_device), -}; - - -/* - * Necessary forward function protoypes - */ -static int ips_halt(struct notifier_block *nb, ulong event, void *buf); - -#define MAX_ADAPTER_NAME 15 - -static char ips_adapter_name[][30] = { - "ServeRAID", - "ServeRAID II", - "ServeRAID on motherboard", - "ServeRAID on motherboard", - "ServeRAID 3H", - "ServeRAID 3L", - "ServeRAID 4H", - "ServeRAID 4M", - "ServeRAID 4L", - "ServeRAID 4Mx", - "ServeRAID 4Lx", - "ServeRAID 5i", - "ServeRAID 5i", - "ServeRAID 6M", - "ServeRAID 6i", - "ServeRAID 7t", - "ServeRAID 7k", - "ServeRAID 7M" -}; - -static struct notifier_block ips_notifier = { - ips_halt, NULL, 0 -}; - -/* - * Direction table - */ -static char ips_command_direction[] = { - IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, - IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, - IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, - IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT, - IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT, - IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN, - IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK, - IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, - IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, - IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, - IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, - IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE, - IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, - IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE, - IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT, - IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE, - IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, - IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK -}; - - -/****************************************************************************/ -/* */ -/* Routine Name: ips_setup */ -/* */ -/* Routine Description: */ -/* */ -/* setup parameters to the driver */ -/* */ -/****************************************************************************/ -static int -ips_setup(char *ips_str) -{ - - int i; - char *key; - char *value; - IPS_OPTION options[] = { - {"noi2o", &ips_force_i2o, 0}, - {"nommap", &ips_force_memio, 0}, - {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE}, - {"cdboot", &ips_cd_boot, 0}, - {"maxcmds", &MaxLiteCmds, 32}, - }; - - /* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */ - /* Search for value */ - while ((key = strsep(&ips_str, ",."))) { - if (!*key) - continue; - value = strchr(key, ':'); - if (value) - *value++ = '\0'; - /* - * We now have key/value pairs. - * Update the variables - */ - for (i = 0; i < ARRAY_SIZE(options); i++) { - if (strnicmp - (key, options[i].option_name, - strlen(options[i].option_name)) == 0) { - if (value) - *options[i].option_flag = - simple_strtoul(value, NULL, 0); - else - *options[i].option_flag = - options[i].option_value; - break; - } - } - } - - return (1); -} - -__setup("ips=", ips_setup); - -/****************************************************************************/ -/* */ -/* Routine Name: ips_detect */ -/* */ -/* Routine Description: */ -/* */ -/* Detect and initialize the driver */ -/* */ -/* NOTE: this routine is called under the io_request_lock spinlock */ -/* */ -/****************************************************************************/ -static int -ips_detect(struct scsi_host_template * SHT) -{ - int i; - - METHOD_TRACE("ips_detect", 1); - -#ifdef MODULE - if (ips) - ips_setup(ips); -#endif - - for (i = 0; i < ips_num_controllers; i++) { - if (ips_register_scsi(i)) - ips_free(ips_ha[i]); - ips_released_controllers++; - } - ips_hotplug = 1; - return (ips_num_controllers); -} - -/****************************************************************************/ -/* configure the function pointers to use the functions that will work */ -/* with the found version of the adapter */ -/****************************************************************************/ -static void -ips_setup_funclist(ips_ha_t * ha) -{ - - /* - * Setup Functions - */ - if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) { - /* morpheus / marco / sebring */ - ha->func.isintr = ips_isintr_morpheus; - ha->func.isinit = ips_isinit_morpheus; - ha->func.issue = ips_issue_i2o_memio; - ha->func.init = ips_init_morpheus; - ha->func.statupd = ips_statupd_morpheus; - ha->func.reset = ips_reset_morpheus; - ha->func.intr = ips_intr_morpheus; - ha->func.enableint = ips_enable_int_morpheus; - } else if (IPS_USE_MEMIO(ha)) { - /* copperhead w/MEMIO */ - ha->func.isintr = ips_isintr_copperhead_memio; - ha->func.isinit = ips_isinit_copperhead_memio; - ha->func.init = ips_init_copperhead_memio; - ha->func.statupd = ips_statupd_copperhead_memio; - ha->func.statinit = ips_statinit_memio; - ha->func.reset = ips_reset_copperhead_memio; - ha->func.intr = ips_intr_copperhead; - ha->func.erasebios = ips_erase_bios_memio; - ha->func.programbios = ips_program_bios_memio; - ha->func.verifybios = ips_verify_bios_memio; - ha->func.enableint = ips_enable_int_copperhead_memio; - if (IPS_USE_I2O_DELIVER(ha)) - ha->func.issue = ips_issue_i2o_memio; - else - ha->func.issue = ips_issue_copperhead_memio; - } else { - /* copperhead */ - ha->func.isintr = ips_isintr_copperhead; - ha->func.isinit = ips_isinit_copperhead; - ha->func.init = ips_init_copperhead; - ha->func.statupd = ips_statupd_copperhead; - ha->func.statinit = ips_statinit; - ha->func.reset = ips_reset_copperhead; - ha->func.intr = ips_intr_copperhead; - ha->func.erasebios = ips_erase_bios; - ha->func.programbios = ips_program_bios; - ha->func.verifybios = ips_verify_bios; - ha->func.enableint = ips_enable_int_copperhead; - - if (IPS_USE_I2O_DELIVER(ha)) - ha->func.issue = ips_issue_i2o; - else - ha->func.issue = ips_issue_copperhead; - } -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_release */ -/* */ -/* Routine Description: */ -/* */ -/* Remove a driver */ -/* */ -/****************************************************************************/ -static int -ips_release(struct Scsi_Host *sh) -{ - ips_scb_t *scb; - ips_ha_t *ha; - int i; - - METHOD_TRACE("ips_release", 1); - - scsi_remove_host(sh); - - for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ; - - if (i == IPS_MAX_ADAPTERS) { - printk(KERN_WARNING - "(%s) release, invalid Scsi_Host pointer.\n", ips_name); - BUG(); - return (FALSE); - } - - ha = IPS_HA(sh); - - if (!ha) - return (FALSE); - - /* flush the cache on the controller */ - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_FLUSH; - - scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; - scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.flush_cache.state = IPS_NORM_STATE; - scb->cmd.flush_cache.reserved = 0; - scb->cmd.flush_cache.reserved2 = 0; - scb->cmd.flush_cache.reserved3 = 0; - scb->cmd.flush_cache.reserved4 = 0; - - IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); - - /* send command */ - if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE) - IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n"); - - IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n"); - - ips_sh[i] = NULL; - ips_ha[i] = NULL; - - /* free extra memory */ - ips_free(ha); - - /* free IRQ */ - free_irq(ha->pcidev->irq, ha); - - scsi_host_put(sh); - - ips_released_controllers++; - - return (FALSE); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_halt */ -/* */ -/* Routine Description: */ -/* */ -/* Perform cleanup when the system reboots */ -/* */ -/****************************************************************************/ -static int -ips_halt(struct notifier_block *nb, ulong event, void *buf) -{ - ips_scb_t *scb; - ips_ha_t *ha; - int i; - - if ((event != SYS_RESTART) && (event != SYS_HALT) && - (event != SYS_POWER_OFF)) - return (NOTIFY_DONE); - - for (i = 0; i < ips_next_controller; i++) { - ha = (ips_ha_t *) ips_ha[i]; - - if (!ha) - continue; - - if (!ha->active) - continue; - - /* flush the cache on the controller */ - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_FLUSH; - - scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; - scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.flush_cache.state = IPS_NORM_STATE; - scb->cmd.flush_cache.reserved = 0; - scb->cmd.flush_cache.reserved2 = 0; - scb->cmd.flush_cache.reserved3 = 0; - scb->cmd.flush_cache.reserved4 = 0; - - IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n"); - - /* send command */ - if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == - IPS_FAILURE) - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Incomplete Flush.\n"); - else - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Flushing Complete.\n"); - } - - return (NOTIFY_OK); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_eh_abort */ -/* */ -/* Routine Description: */ -/* */ -/* Abort a command (using the new error code stuff) */ -/* Note: this routine is called under the io_request_lock */ -/****************************************************************************/ -int ips_eh_abort(struct scsi_cmnd *SC) -{ - ips_ha_t *ha; - ips_copp_wait_item_t *item; - int ret; - struct Scsi_Host *host; - - METHOD_TRACE("ips_eh_abort", 1); - - if (!SC) - return (FAILED); - - host = SC->device->host; - ha = (ips_ha_t *) SC->device->host->hostdata; - - if (!ha) - return (FAILED); - - if (!ha->active) - return (FAILED); - - spin_lock(host->host_lock); - - /* See if the command is on the copp queue */ - item = ha->copp_waitlist.head; - while ((item) && (item->scsi_cmd != SC)) - item = item->next; - - if (item) { - /* Found it */ - ips_removeq_copp(&ha->copp_waitlist, item); - ret = (SUCCESS); - - /* See if the command is on the wait queue */ - } else if (ips_removeq_wait(&ha->scb_waitlist, SC)) { - /* command not sent yet */ - ret = (SUCCESS); - } else { - /* command must have already been sent */ - ret = (FAILED); - } - - spin_unlock(host->host_lock); - return ret; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_eh_reset */ -/* */ -/* Routine Description: */ -/* */ -/* Reset the controller (with new eh error code) */ -/* */ -/* NOTE: this routine is called under the io_request_lock spinlock */ -/* */ -/****************************************************************************/ -static int __ips_eh_reset(struct scsi_cmnd *SC) -{ - int ret; - int i; - ips_ha_t *ha; - ips_scb_t *scb; - ips_copp_wait_item_t *item; - - METHOD_TRACE("ips_eh_reset", 1); - -#ifdef NO_IPS_RESET - return (FAILED); -#else - - if (!SC) { - DEBUG(1, "Reset called with NULL scsi command"); - - return (FAILED); - } - - ha = (ips_ha_t *) SC->device->host->hostdata; - - if (!ha) { - DEBUG(1, "Reset called with NULL ha struct"); - - return (FAILED); - } - - if (!ha->active) - return (FAILED); - - /* See if the command is on the copp queue */ - item = ha->copp_waitlist.head; - while ((item) && (item->scsi_cmd != SC)) - item = item->next; - - if (item) { - /* Found it */ - ips_removeq_copp(&ha->copp_waitlist, item); - return (SUCCESS); - } - - /* See if the command is on the wait queue */ - if (ips_removeq_wait(&ha->scb_waitlist, SC)) { - /* command not sent yet */ - return (SUCCESS); - } - - /* An explanation for the casual observer: */ - /* Part of the function of a RAID controller is automatic error */ - /* detection and recovery. As such, the only problem that physically */ - /* resetting an adapter will ever fix is when, for some reason, */ - /* the driver is not successfully communicating with the adapter. */ - /* Therefore, we will attempt to flush this adapter. If that succeeds, */ - /* then there's no real purpose in a physical reset. This will complete */ - /* much faster and avoids any problems that might be caused by a */ - /* physical reset ( such as having to fail all the outstanding I/O's ). */ - - if (ha->ioctl_reset == 0) { /* IF Not an IOCTL Requested Reset */ - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_FLUSH; - - scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; - scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.flush_cache.state = IPS_NORM_STATE; - scb->cmd.flush_cache.reserved = 0; - scb->cmd.flush_cache.reserved2 = 0; - scb->cmd.flush_cache.reserved3 = 0; - scb->cmd.flush_cache.reserved4 = 0; - - /* Attempt the flush command */ - ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL); - if (ret == IPS_SUCCESS) { - IPS_PRINTK(KERN_NOTICE, ha->pcidev, - "Reset Request - Flushed Cache\n"); - return (SUCCESS); - } - } - - /* Either we can't communicate with the adapter or it's an IOCTL request */ - /* from a utility. A physical reset is needed at this point. */ - - ha->ioctl_reset = 0; /* Reset the IOCTL Requested Reset Flag */ - - /* - * command must have already been sent - * reset the controller - */ - IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n"); - ret = (*ha->func.reset) (ha); - - if (!ret) { - struct scsi_cmnd *scsi_cmd; - - IPS_PRINTK(KERN_NOTICE, ha->pcidev, - "Controller reset failed - controller now offline.\n"); - - /* Now fail all of the active commands */ - DEBUG_VAR(1, "(%s%d) Failing active commands", - ips_name, ha->host_num); - - while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { - scb->scsi_cmd->result = DID_ERROR << 16; - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - ips_freescb(ha, scb); - } - - /* Now fail all of the pending commands */ - DEBUG_VAR(1, "(%s%d) Failing pending commands", - ips_name, ha->host_num); - - while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { - scsi_cmd->result = DID_ERROR; - scsi_cmd->scsi_done(scsi_cmd); - } - - ha->active = FALSE; - return (FAILED); - } - - if (!ips_clear_adapter(ha, IPS_INTR_IORL)) { - struct scsi_cmnd *scsi_cmd; - - IPS_PRINTK(KERN_NOTICE, ha->pcidev, - "Controller reset failed - controller now offline.\n"); - - /* Now fail all of the active commands */ - DEBUG_VAR(1, "(%s%d) Failing active commands", - ips_name, ha->host_num); - - while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { - scb->scsi_cmd->result = DID_ERROR << 16; - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - ips_freescb(ha, scb); - } - - /* Now fail all of the pending commands */ - DEBUG_VAR(1, "(%s%d) Failing pending commands", - ips_name, ha->host_num); - - while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) { - scsi_cmd->result = DID_ERROR << 16; - scsi_cmd->scsi_done(scsi_cmd); - } - - ha->active = FALSE; - return (FAILED); - } - - /* FFDC */ - if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) { - struct timeval tv; - - do_gettimeofday(&tv); - ha->last_ffdc = tv.tv_sec; - ha->reset_count++; - ips_ffdc_reset(ha, IPS_INTR_IORL); - } - - /* Now fail all of the active commands */ - DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num); - - while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) { - scb->scsi_cmd->result = DID_RESET << 16; - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - ips_freescb(ha, scb); - } - - /* Reset DCDB active command bits */ - for (i = 1; i < ha->nbus; i++) - ha->dcdb_active[i - 1] = 0; - - /* Reset the number of active IOCTLs */ - ha->num_ioctl = 0; - - ips_next(ha, IPS_INTR_IORL); - - return (SUCCESS); -#endif /* NO_IPS_RESET */ - -} - -static int ips_eh_reset(struct scsi_cmnd *SC) -{ - int rc; - - spin_lock_irq(SC->device->host->host_lock); - rc = __ips_eh_reset(SC); - spin_unlock_irq(SC->device->host->host_lock); - - return rc; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_queue */ -/* */ -/* Routine Description: */ -/* */ -/* Send a command to the controller */ -/* */ -/* NOTE: */ -/* Linux obtains io_request_lock before calling this function */ -/* */ -/****************************************************************************/ -static int ips_queue_lck(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *)) -{ - ips_ha_t *ha; - ips_passthru_t *pt; - - METHOD_TRACE("ips_queue", 1); - - ha = (ips_ha_t *) SC->device->host->hostdata; - - if (!ha) - return (1); - - if (!ha->active) - return (DID_ERROR); - - if (ips_is_passthru(SC)) { - if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) { - SC->result = DID_BUS_BUSY << 16; - done(SC); - - return (0); - } - } else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) { - SC->result = DID_BUS_BUSY << 16; - done(SC); - - return (0); - } - - SC->scsi_done = done; - - DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)", - ips_name, - ha->host_num, - SC->cmnd[0], - SC->device->channel, SC->device->id, SC->device->lun); - - /* Check for command to initiator IDs */ - if ((scmd_channel(SC) > 0) - && (scmd_id(SC) == ha->ha_id[scmd_channel(SC)])) { - SC->result = DID_NO_CONNECT << 16; - done(SC); - - return (0); - } - - if (ips_is_passthru(SC)) { - - ips_copp_wait_item_t *scratch; - - /* A Reset IOCTL is only sent by the boot CD in extreme cases. */ - /* There can never be any system activity ( network or disk ), but check */ - /* anyway just as a good practice. */ - pt = (ips_passthru_t *) scsi_sglist(SC); - if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) && - (pt->CoppCP.cmd.reset.adapter_flag == 1)) { - if (ha->scb_activelist.count != 0) { - SC->result = DID_BUS_BUSY << 16; - done(SC); - return (0); - } - ha->ioctl_reset = 1; /* This reset request is from an IOCTL */ - __ips_eh_reset(SC); - SC->result = DID_OK << 16; - SC->scsi_done(SC); - return (0); - } - - /* allocate space for the scribble */ - scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC); - - if (!scratch) { - SC->result = DID_ERROR << 16; - done(SC); - - return (0); - } - - scratch->scsi_cmd = SC; - scratch->next = NULL; - - ips_putq_copp_tail(&ha->copp_waitlist, scratch); - } else { - ips_putq_wait_tail(&ha->scb_waitlist, SC); - } - - ips_next(ha, IPS_INTR_IORL); - - return (0); -} - -static DEF_SCSI_QCMD(ips_queue) - -/****************************************************************************/ -/* */ -/* Routine Name: ips_biosparam */ -/* */ -/* Routine Description: */ -/* */ -/* Set bios geometry for the controller */ -/* */ -/****************************************************************************/ -static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata; - int heads; - int sectors; - int cylinders; - - METHOD_TRACE("ips_biosparam", 1); - - if (!ha) - /* ?!?! host adater info invalid */ - return (0); - - if (!ha->active) - return (0); - - if (!ips_read_adapter_status(ha, IPS_INTR_ON)) - /* ?!?! Enquiry command failed */ - return (0); - - if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) { - heads = IPS_NORM_HEADS; - sectors = IPS_NORM_SECTORS; - } else { - heads = IPS_COMP_HEADS; - sectors = IPS_COMP_SECTORS; - } - - cylinders = (unsigned long) capacity / (heads * sectors); - - DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d", - heads, sectors, cylinders); - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_slave_configure */ -/* */ -/* Routine Description: */ -/* */ -/* Set queue depths on devices once scan is complete */ -/* */ -/****************************************************************************/ -static int -ips_slave_configure(struct scsi_device * SDptr) -{ - ips_ha_t *ha; - int min; - - ha = IPS_HA(SDptr->host); - if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) { - min = ha->max_cmds / 2; - if (ha->enq->ucLogDriveCount <= 2) - min = ha->max_cmds - 1; - scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min); - } - - SDptr->skip_ms_page_8 = 1; - SDptr->skip_ms_page_3f = 1; - return 0; -} - -/****************************************************************************/ -/* */ -/* Routine Name: do_ipsintr */ -/* */ -/* Routine Description: */ -/* */ -/* Wrapper for the interrupt handler */ -/* */ -/****************************************************************************/ -static irqreturn_t -do_ipsintr(int irq, void *dev_id) -{ - ips_ha_t *ha; - struct Scsi_Host *host; - int irqstatus; - - METHOD_TRACE("do_ipsintr", 2); - - ha = (ips_ha_t *) dev_id; - if (!ha) - return IRQ_NONE; - host = ips_sh[ha->host_num]; - /* interrupt during initialization */ - if (!host) { - (*ha->func.intr) (ha); - return IRQ_HANDLED; - } - - spin_lock(host->host_lock); - - if (!ha->active) { - spin_unlock(host->host_lock); - return IRQ_HANDLED; - } - - irqstatus = (*ha->func.intr) (ha); - - spin_unlock(host->host_lock); - - /* start the next command */ - ips_next(ha, IPS_INTR_ON); - return IRQ_RETVAL(irqstatus); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_intr_copperhead */ -/* */ -/* Routine Description: */ -/* */ -/* Polling interrupt handler */ -/* */ -/* ASSUMES interrupts are disabled */ -/* */ -/****************************************************************************/ -int -ips_intr_copperhead(ips_ha_t * ha) -{ - ips_stat_t *sp; - ips_scb_t *scb; - IPS_STATUS cstatus; - int intrstatus; - - METHOD_TRACE("ips_intr", 2); - - if (!ha) - return 0; - - if (!ha->active) - return 0; - - intrstatus = (*ha->func.isintr) (ha); - - if (!intrstatus) { - /* - * Unexpected/Shared interrupt - */ - - return 0; - } - - while (TRUE) { - sp = &ha->sp; - - intrstatus = (*ha->func.isintr) (ha); - - if (!intrstatus) - break; - else - cstatus.value = (*ha->func.statupd) (ha); - - if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { - /* Spurious Interrupt ? */ - continue; - } - - ips_chkstatus(ha, &cstatus); - scb = (ips_scb_t *) sp->scb_addr; - - /* - * use the callback function to finish things up - * NOTE: interrupts are OFF for this - */ - (*scb->callback) (ha, scb); - } /* end while */ - return 1; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_intr_morpheus */ -/* */ -/* Routine Description: */ -/* */ -/* Polling interrupt handler */ -/* */ -/* ASSUMES interrupts are disabled */ -/* */ -/****************************************************************************/ -int -ips_intr_morpheus(ips_ha_t * ha) -{ - ips_stat_t *sp; - ips_scb_t *scb; - IPS_STATUS cstatus; - int intrstatus; - - METHOD_TRACE("ips_intr_morpheus", 2); - - if (!ha) - return 0; - - if (!ha->active) - return 0; - - intrstatus = (*ha->func.isintr) (ha); - - if (!intrstatus) { - /* - * Unexpected/Shared interrupt - */ - - return 0; - } - - while (TRUE) { - sp = &ha->sp; - - intrstatus = (*ha->func.isintr) (ha); - - if (!intrstatus) - break; - else - cstatus.value = (*ha->func.statupd) (ha); - - if (cstatus.value == 0xffffffff) - /* No more to process */ - break; - - if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Spurious interrupt; no ccb.\n"); - - continue; - } - - ips_chkstatus(ha, &cstatus); - scb = (ips_scb_t *) sp->scb_addr; - - /* - * use the callback function to finish things up - * NOTE: interrupts are OFF for this - */ - (*scb->callback) (ha, scb); - } /* end while */ - return 1; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_info */ -/* */ -/* Routine Description: */ -/* */ -/* Return info about the driver */ -/* */ -/****************************************************************************/ -static const char * -ips_info(struct Scsi_Host *SH) -{ - static char buffer[256]; - char *bp; - ips_ha_t *ha; - - METHOD_TRACE("ips_info", 1); - - ha = IPS_HA(SH); - - if (!ha) - return (NULL); - - bp = &buffer[0]; - memset(bp, 0, sizeof (buffer)); - - sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ", - IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT); - - if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) { - strcat(bp, " <"); - strcat(bp, ips_adapter_name[ha->ad_type - 1]); - strcat(bp, ">"); - } - - return (bp); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_proc_info */ -/* */ -/* Routine Description: */ -/* */ -/* The passthru interface for the driver */ -/* */ -/****************************************************************************/ -static int -ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int func) -{ - int i; - int ret; - ips_ha_t *ha = NULL; - - METHOD_TRACE("ips_proc_info", 1); - - /* Find our host structure */ - for (i = 0; i < ips_next_controller; i++) { - if (ips_sh[i]) { - if (ips_sh[i] == host) { - ha = (ips_ha_t *) ips_sh[i]->hostdata; - break; - } - } - } - - if (!ha) - return (-EINVAL); - - if (func) { - /* write */ - return (0); - } else { - /* read */ - if (start) - *start = buffer; - - ret = ips_host_info(ha, buffer, offset, length); - - return (ret); - } -} - -/*--------------------------------------------------------------------------*/ -/* Helper Functions */ -/*--------------------------------------------------------------------------*/ - -/****************************************************************************/ -/* */ -/* Routine Name: ips_is_passthru */ -/* */ -/* Routine Description: */ -/* */ -/* Determine if the specified SCSI command is really a passthru command */ -/* */ -/****************************************************************************/ -static int ips_is_passthru(struct scsi_cmnd *SC) -{ - unsigned long flags; - - METHOD_TRACE("ips_is_passthru", 1); - - if (!SC) - return (0); - - if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) && - (SC->device->channel == 0) && - (SC->device->id == IPS_ADAPTER_ID) && - (SC->device->lun == 0) && scsi_sglist(SC)) { - struct scatterlist *sg = scsi_sglist(SC); - char *buffer; - - /* kmap_atomic() ensures addressability of the user buffer.*/ - /* local_irq_save() protects the KM_IRQ0 address slot. */ - local_irq_save(flags); - buffer = kmap_atomic(sg_page(sg)) + sg->offset; - if (buffer && buffer[0] == 'C' && buffer[1] == 'O' && - buffer[2] == 'P' && buffer[3] == 'P') { - kunmap_atomic(buffer - sg->offset); - local_irq_restore(flags); - return 1; - } - kunmap_atomic(buffer - sg->offset); - local_irq_restore(flags); - } - return 0; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_alloc_passthru_buffer */ -/* */ -/* Routine Description: */ -/* allocate a buffer large enough for the ioctl data if the ioctl buffer */ -/* is too small or doesn't exist */ -/****************************************************************************/ -static int -ips_alloc_passthru_buffer(ips_ha_t * ha, int length) -{ - void *bigger_buf; - dma_addr_t dma_busaddr; - - if (ha->ioctl_data && length <= ha->ioctl_len) - return 0; - /* there is no buffer or it's not big enough, allocate a new one */ - bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr); - if (bigger_buf) { - /* free the old memory */ - pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data, - ha->ioctl_busaddr); - /* use the new memory */ - ha->ioctl_data = (char *) bigger_buf; - ha->ioctl_len = length; - ha->ioctl_busaddr = dma_busaddr; - } else { - return -1; - } - return 0; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_make_passthru */ -/* */ -/* Routine Description: */ -/* */ -/* Make a passthru command out of the info in the Scsi block */ -/* */ -/****************************************************************************/ -static int -ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr) -{ - ips_passthru_t *pt; - int length = 0; - int i, ret; - struct scatterlist *sg = scsi_sglist(SC); - - METHOD_TRACE("ips_make_passthru", 1); - - scsi_for_each_sg(SC, sg, scsi_sg_count(SC), i) - length += sg->length; - - if (length < sizeof (ips_passthru_t)) { - /* wrong size */ - DEBUG_VAR(1, "(%s%d) Passthru structure wrong size", - ips_name, ha->host_num); - return (IPS_FAILURE); - } - if (ips_alloc_passthru_buffer(ha, length)) { - /* allocation failure! If ha->ioctl_data exists, use it to return - some error codes. Return a failed command to the scsi layer. */ - if (ha->ioctl_data) { - pt = (ips_passthru_t *) ha->ioctl_data; - ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t)); - pt->BasicStatus = 0x0B; - pt->ExtendedStatus = 0x00; - ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t)); - } - return IPS_FAILURE; - } - ha->ioctl_datasize = length; - - ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize); - pt = (ips_passthru_t *) ha->ioctl_data; - - /* - * Some notes about the passthru interface used - * - * IF the scsi op_code == 0x0d then we assume - * that the data came along with/goes with the - * packet we received from the sg driver. In this - * case the CmdBSize field of the pt structure is - * used for the size of the buffer. - */ - - switch (pt->CoppCmd) { - case IPS_NUMCTRLS: - memcpy(ha->ioctl_data + sizeof (ips_passthru_t), - &ips_num_controllers, sizeof (int)); - ips_scmd_buf_write(SC, ha->ioctl_data, - sizeof (ips_passthru_t) + sizeof (int)); - SC->result = DID_OK << 16; - - return (IPS_SUCCESS_IMM); - - case IPS_COPPUSRCMD: - case IPS_COPPIOCCMD: - if (SC->cmnd[0] == IPS_IOCTL_COMMAND) { - if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) { - /* wrong size */ - DEBUG_VAR(1, - "(%s%d) Passthru structure wrong size", - ips_name, ha->host_num); - - return (IPS_FAILURE); - } - - if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD && - pt->CoppCP.cmd.flashfw.op_code == - IPS_CMD_RW_BIOSFW) { - ret = ips_flash_copperhead(ha, pt, scb); - ips_scmd_buf_write(SC, ha->ioctl_data, - sizeof (ips_passthru_t)); - return ret; - } - if (ips_usrcmd(ha, pt, scb)) - return (IPS_SUCCESS); - else - return (IPS_FAILURE); - } - - break; - - } /* end switch */ - - return (IPS_FAILURE); -} - -/****************************************************************************/ -/* Routine Name: ips_flash_copperhead */ -/* Routine Description: */ -/* Flash the BIOS/FW on a Copperhead style controller */ -/****************************************************************************/ -static int -ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) -{ - int datasize; - - /* Trombone is the only copperhead that can do packet flash, but only - * for firmware. No one said it had to make sense. */ - if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) { - if (ips_usrcmd(ha, pt, scb)) - return IPS_SUCCESS; - else - return IPS_FAILURE; - } - pt->BasicStatus = 0x0B; - pt->ExtendedStatus = 0; - scb->scsi_cmd->result = DID_OK << 16; - /* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can */ - /* avoid allocating a huge buffer per adapter ( which can fail ). */ - if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && - pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { - pt->BasicStatus = 0; - return ips_flash_bios(ha, pt, scb); - } else if (pt->CoppCP.cmd.flashfw.packet_num == 0) { - if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){ - ha->flash_data = ips_FlashData; - ha->flash_busaddr = ips_flashbusaddr; - ha->flash_len = PAGE_SIZE << 7; - ha->flash_datasize = 0; - } else if (!ha->flash_data) { - datasize = pt->CoppCP.cmd.flashfw.total_packets * - pt->CoppCP.cmd.flashfw.count; - ha->flash_data = pci_alloc_consistent(ha->pcidev, - datasize, - &ha->flash_busaddr); - if (!ha->flash_data){ - printk(KERN_WARNING "Unable to allocate a flash buffer\n"); - return IPS_FAILURE; - } - ha->flash_datasize = 0; - ha->flash_len = datasize; - } else - return IPS_FAILURE; - } else { - if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize > - ha->flash_len) { - ips_free_flash_copperhead(ha); - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "failed size sanity check\n"); - return IPS_FAILURE; - } - } - if (!ha->flash_data) - return IPS_FAILURE; - pt->BasicStatus = 0; - memcpy(&ha->flash_data[ha->flash_datasize], pt + 1, - pt->CoppCP.cmd.flashfw.count); - ha->flash_datasize += pt->CoppCP.cmd.flashfw.count; - if (pt->CoppCP.cmd.flashfw.packet_num == - pt->CoppCP.cmd.flashfw.total_packets - 1) { - if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE) - return ips_flash_bios(ha, pt, scb); - else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) - return ips_flash_firmware(ha, pt, scb); - } - return IPS_SUCCESS_IMM; -} - -/****************************************************************************/ -/* Routine Name: ips_flash_bios */ -/* Routine Description: */ -/* flashes the bios of a copperhead adapter */ -/****************************************************************************/ -static int -ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) -{ - - if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && - pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) { - if ((!ha->func.programbios) || (!ha->func.erasebios) || - (!ha->func.verifybios)) - goto error; - if ((*ha->func.erasebios) (ha)) { - DEBUG_VAR(1, - "(%s%d) flash bios failed - unable to erase flash", - ips_name, ha->host_num); - goto error; - } else - if ((*ha->func.programbios) (ha, - ha->flash_data + - IPS_BIOS_HEADER, - ha->flash_datasize - - IPS_BIOS_HEADER, 0)) { - DEBUG_VAR(1, - "(%s%d) flash bios failed - unable to flash", - ips_name, ha->host_num); - goto error; - } else - if ((*ha->func.verifybios) (ha, - ha->flash_data + - IPS_BIOS_HEADER, - ha->flash_datasize - - IPS_BIOS_HEADER, 0)) { - DEBUG_VAR(1, - "(%s%d) flash bios failed - unable to verify flash", - ips_name, ha->host_num); - goto error; - } - ips_free_flash_copperhead(ha); - return IPS_SUCCESS_IMM; - } else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE && - pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) { - if (!ha->func.erasebios) - goto error; - if ((*ha->func.erasebios) (ha)) { - DEBUG_VAR(1, - "(%s%d) flash bios failed - unable to erase flash", - ips_name, ha->host_num); - goto error; - } - return IPS_SUCCESS_IMM; - } - error: - pt->BasicStatus = 0x0B; - pt->ExtendedStatus = 0x00; - ips_free_flash_copperhead(ha); - return IPS_FAILURE; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_fill_scb_sg_single */ -/* */ -/* Routine Description: */ -/* Fill in a single scb sg_list element from an address */ -/* return a -1 if a breakup occurred */ -/****************************************************************************/ -static int -ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr, - ips_scb_t * scb, int indx, unsigned int e_len) -{ - - int ret_val = 0; - - if ((scb->data_len + e_len) > ha->max_xfer) { - e_len = ha->max_xfer - scb->data_len; - scb->breakup = indx; - ++scb->sg_break; - ret_val = -1; - } else { - scb->breakup = 0; - scb->sg_break = 0; - } - if (IPS_USE_ENH_SGLIST(ha)) { - scb->sg_list.enh_list[indx].address_lo = - cpu_to_le32(pci_dma_lo32(busaddr)); - scb->sg_list.enh_list[indx].address_hi = - cpu_to_le32(pci_dma_hi32(busaddr)); - scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len); - } else { - scb->sg_list.std_list[indx].address = - cpu_to_le32(pci_dma_lo32(busaddr)); - scb->sg_list.std_list[indx].length = cpu_to_le32(e_len); - } - - ++scb->sg_len; - scb->data_len += e_len; - return ret_val; -} - -/****************************************************************************/ -/* Routine Name: ips_flash_firmware */ -/* Routine Description: */ -/* flashes the firmware of a copperhead adapter */ -/****************************************************************************/ -static int -ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) -{ - IPS_SG_LIST sg_list; - uint32_t cmd_busaddr; - - if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE && - pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) { - memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND)); - pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD; - pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize); - } else { - pt->BasicStatus = 0x0B; - pt->ExtendedStatus = 0x00; - ips_free_flash_copperhead(ha); - return IPS_FAILURE; - } - /* Save the S/G list pointer so it doesn't get clobbered */ - sg_list.list = scb->sg_list.list; - cmd_busaddr = scb->scb_busaddr; - /* copy in the CP */ - memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); - /* FIX stuff that might be wrong */ - scb->sg_list.list = sg_list.list; - scb->scb_busaddr = cmd_busaddr; - scb->bus = scb->scsi_cmd->device->channel; - scb->target_id = scb->scsi_cmd->device->id; - scb->lun = scb->scsi_cmd->device->lun; - scb->sg_len = 0; - scb->data_len = 0; - scb->flags = 0; - scb->op_code = 0; - scb->callback = ipsintr_done; - scb->timeout = ips_cmd_timeout; - - scb->data_len = ha->flash_datasize; - scb->data_busaddr = - pci_map_single(ha->pcidev, ha->flash_data, scb->data_len, - IPS_DMA_DIR(scb)); - scb->flags |= IPS_SCB_MAP_SINGLE; - scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr); - if (pt->TimeOut) - scb->timeout = pt->TimeOut; - scb->scsi_cmd->result = DID_OK << 16; - return IPS_SUCCESS; -} - -/****************************************************************************/ -/* Routine Name: ips_free_flash_copperhead */ -/* Routine Description: */ -/* release the memory resources used to hold the flash image */ -/****************************************************************************/ -static void -ips_free_flash_copperhead(ips_ha_t * ha) -{ - if (ha->flash_data == ips_FlashData) - test_and_clear_bit(0, &ips_FlashDataInUse); - else if (ha->flash_data) - pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data, - ha->flash_busaddr); - ha->flash_data = NULL; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_usrcmd */ -/* */ -/* Routine Description: */ -/* */ -/* Process a user command and make it ready to send */ -/* */ -/****************************************************************************/ -static int -ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb) -{ - IPS_SG_LIST sg_list; - uint32_t cmd_busaddr; - - METHOD_TRACE("ips_usrcmd", 1); - - if ((!scb) || (!pt) || (!ha)) - return (0); - - /* Save the S/G list pointer so it doesn't get clobbered */ - sg_list.list = scb->sg_list.list; - cmd_busaddr = scb->scb_busaddr; - /* copy in the CP */ - memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD)); - memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE)); - - /* FIX stuff that might be wrong */ - scb->sg_list.list = sg_list.list; - scb->scb_busaddr = cmd_busaddr; - scb->bus = scb->scsi_cmd->device->channel; - scb->target_id = scb->scsi_cmd->device->id; - scb->lun = scb->scsi_cmd->device->lun; - scb->sg_len = 0; - scb->data_len = 0; - scb->flags = 0; - scb->op_code = 0; - scb->callback = ipsintr_done; - scb->timeout = ips_cmd_timeout; - scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); - - /* we don't support DCDB/READ/WRITE Scatter Gather */ - if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) || - (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) || - (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG)) - return (0); - - if (pt->CmdBSize) { - scb->data_len = pt->CmdBSize; - scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t); - } else { - scb->data_busaddr = 0L; - } - - if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) - scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + - (unsigned long) &scb-> - dcdb - - (unsigned long) scb); - - if (pt->CmdBSize) { - if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) - scb->dcdb.buffer_pointer = - cpu_to_le32(scb->data_busaddr); - else - scb->cmd.basic_io.sg_addr = - cpu_to_le32(scb->data_busaddr); - } - - /* set timeouts */ - if (pt->TimeOut) { - scb->timeout = pt->TimeOut; - - if (pt->TimeOut <= 10) - scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; - else if (pt->TimeOut <= 60) - scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; - else - scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; - } - - /* assume success */ - scb->scsi_cmd->result = DID_OK << 16; - - /* success */ - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_cleanup_passthru */ -/* */ -/* Routine Description: */ -/* */ -/* Cleanup after a passthru command */ -/* */ -/****************************************************************************/ -static void -ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb) -{ - ips_passthru_t *pt; - - METHOD_TRACE("ips_cleanup_passthru", 1); - - if ((!scb) || (!scb->scsi_cmd) || (!scsi_sglist(scb->scsi_cmd))) { - DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru", - ips_name, ha->host_num); - - return; - } - pt = (ips_passthru_t *) ha->ioctl_data; - - /* Copy data back to the user */ - if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB) /* Copy DCDB Back to Caller's Area */ - memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE)); - - pt->BasicStatus = scb->basic_status; - pt->ExtendedStatus = scb->extended_status; - pt->AdapterType = ha->ad_type; - - if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD && - (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD || - scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW)) - ips_free_flash_copperhead(ha); - - ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_host_info */ -/* */ -/* Routine Description: */ -/* */ -/* The passthru interface for the driver */ -/* */ -/****************************************************************************/ -static int -ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len) -{ - IPS_INFOSTR info; - - METHOD_TRACE("ips_host_info", 1); - - info.buffer = ptr; - info.length = len; - info.offset = offset; - info.pos = 0; - info.localpos = 0; - - copy_info(&info, "\nIBM ServeRAID General Information:\n\n"); - - if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) && - (le16_to_cpu(ha->nvram->adapter_type) != 0)) - copy_info(&info, "\tController Type : %s\n", - ips_adapter_name[ha->ad_type - 1]); - else - copy_info(&info, - "\tController Type : Unknown\n"); - - if (ha->io_addr) - copy_info(&info, - "\tIO region : 0x%lx (%d bytes)\n", - ha->io_addr, ha->io_len); - - if (ha->mem_addr) { - copy_info(&info, - "\tMemory region : 0x%lx (%d bytes)\n", - ha->mem_addr, ha->mem_len); - copy_info(&info, - "\tShared memory address : 0x%lx\n", - ha->mem_ptr); - } - - copy_info(&info, "\tIRQ number : %d\n", ha->pcidev->irq); - - /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */ - /* That keeps everything happy for "text" operations on the proc file. */ - - if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) { - if (ha->nvram->bios_low[3] == 0) { - copy_info(&info, - "\tBIOS Version : %c%c%c%c%c%c%c\n", - ha->nvram->bios_high[0], ha->nvram->bios_high[1], - ha->nvram->bios_high[2], ha->nvram->bios_high[3], - ha->nvram->bios_low[0], ha->nvram->bios_low[1], - ha->nvram->bios_low[2]); - - } else { - copy_info(&info, - "\tBIOS Version : %c%c%c%c%c%c%c%c\n", - ha->nvram->bios_high[0], ha->nvram->bios_high[1], - ha->nvram->bios_high[2], ha->nvram->bios_high[3], - ha->nvram->bios_low[0], ha->nvram->bios_low[1], - ha->nvram->bios_low[2], ha->nvram->bios_low[3]); - } - - } - - if (ha->enq->CodeBlkVersion[7] == 0) { - copy_info(&info, - "\tFirmware Version : %c%c%c%c%c%c%c\n", - ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], - ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], - ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], - ha->enq->CodeBlkVersion[6]); - } else { - copy_info(&info, - "\tFirmware Version : %c%c%c%c%c%c%c%c\n", - ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1], - ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3], - ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5], - ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]); - } - - if (ha->enq->BootBlkVersion[7] == 0) { - copy_info(&info, - "\tBoot Block Version : %c%c%c%c%c%c%c\n", - ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], - ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], - ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], - ha->enq->BootBlkVersion[6]); - } else { - copy_info(&info, - "\tBoot Block Version : %c%c%c%c%c%c%c%c\n", - ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1], - ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3], - ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5], - ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]); - } - - copy_info(&info, "\tDriver Version : %s%s\n", - IPS_VERSION_HIGH, IPS_VERSION_LOW); - - copy_info(&info, "\tDriver Build : %d\n", - IPS_BUILD_IDENT); - - copy_info(&info, "\tMax Physical Devices : %d\n", - ha->enq->ucMaxPhysicalDevices); - copy_info(&info, "\tMax Active Commands : %d\n", - ha->max_cmds); - copy_info(&info, "\tCurrent Queued Commands : %d\n", - ha->scb_waitlist.count); - copy_info(&info, "\tCurrent Active Commands : %d\n", - ha->scb_activelist.count - ha->num_ioctl); - copy_info(&info, "\tCurrent Queued PT Commands : %d\n", - ha->copp_waitlist.count); - copy_info(&info, "\tCurrent Active PT Commands : %d\n", - ha->num_ioctl); - - copy_info(&info, "\n"); - - return (info.localpos); -} - -/****************************************************************************/ -/* */ -/* Routine Name: copy_mem_info */ -/* */ -/* Routine Description: */ -/* */ -/* Copy data into an IPS_INFOSTR structure */ -/* */ -/****************************************************************************/ -static void -copy_mem_info(IPS_INFOSTR * info, char *data, int len) -{ - METHOD_TRACE("copy_mem_info", 1); - - if (info->pos + len < info->offset) { - info->pos += len; - return; - } - - if (info->pos < info->offset) { - data += (info->offset - info->pos); - len -= (info->offset - info->pos); - info->pos += (info->offset - info->pos); - } - - if (info->localpos + len > info->length) - len = info->length - info->localpos; - - if (len > 0) { - memcpy(info->buffer + info->localpos, data, len); - info->pos += len; - info->localpos += len; - } -} - -/****************************************************************************/ -/* */ -/* Routine Name: copy_info */ -/* */ -/* Routine Description: */ -/* */ -/* printf style wrapper for an info structure */ -/* */ -/****************************************************************************/ -static int -copy_info(IPS_INFOSTR * info, char *fmt, ...) -{ - va_list args; - char buf[128]; - int len; - - METHOD_TRACE("copy_info", 1); - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - copy_mem_info(info, buf, len); - - return (len); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_identify_controller */ -/* */ -/* Routine Description: */ -/* */ -/* Identify this controller */ -/* */ -/****************************************************************************/ -static void -ips_identify_controller(ips_ha_t * ha) -{ - METHOD_TRACE("ips_identify_controller", 1); - - switch (ha->pcidev->device) { - case IPS_DEVICEID_COPPERHEAD: - if (ha->pcidev->revision <= IPS_REVID_SERVERAID) { - ha->ad_type = IPS_ADTYPE_SERVERAID; - } else if (ha->pcidev->revision == IPS_REVID_SERVERAID2) { - ha->ad_type = IPS_ADTYPE_SERVERAID2; - } else if (ha->pcidev->revision == IPS_REVID_NAVAJO) { - ha->ad_type = IPS_ADTYPE_NAVAJO; - } else if ((ha->pcidev->revision == IPS_REVID_SERVERAID2) - && (ha->slot_num == 0)) { - ha->ad_type = IPS_ADTYPE_KIOWA; - } else if ((ha->pcidev->revision >= IPS_REVID_CLARINETP1) && - (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) { - if (ha->enq->ucMaxPhysicalDevices == 15) - ha->ad_type = IPS_ADTYPE_SERVERAID3L; - else - ha->ad_type = IPS_ADTYPE_SERVERAID3; - } else if ((ha->pcidev->revision >= IPS_REVID_TROMBONE32) && - (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) { - ha->ad_type = IPS_ADTYPE_SERVERAID4H; - } - break; - - case IPS_DEVICEID_MORPHEUS: - switch (ha->pcidev->subsystem_device) { - case IPS_SUBDEVICEID_4L: - ha->ad_type = IPS_ADTYPE_SERVERAID4L; - break; - - case IPS_SUBDEVICEID_4M: - ha->ad_type = IPS_ADTYPE_SERVERAID4M; - break; - - case IPS_SUBDEVICEID_4MX: - ha->ad_type = IPS_ADTYPE_SERVERAID4MX; - break; - - case IPS_SUBDEVICEID_4LX: - ha->ad_type = IPS_ADTYPE_SERVERAID4LX; - break; - - case IPS_SUBDEVICEID_5I2: - ha->ad_type = IPS_ADTYPE_SERVERAID5I2; - break; - - case IPS_SUBDEVICEID_5I1: - ha->ad_type = IPS_ADTYPE_SERVERAID5I1; - break; - } - - break; - - case IPS_DEVICEID_MARCO: - switch (ha->pcidev->subsystem_device) { - case IPS_SUBDEVICEID_6M: - ha->ad_type = IPS_ADTYPE_SERVERAID6M; - break; - case IPS_SUBDEVICEID_6I: - ha->ad_type = IPS_ADTYPE_SERVERAID6I; - break; - case IPS_SUBDEVICEID_7k: - ha->ad_type = IPS_ADTYPE_SERVERAID7k; - break; - case IPS_SUBDEVICEID_7M: - ha->ad_type = IPS_ADTYPE_SERVERAID7M; - break; - } - break; - } -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_get_bios_version */ -/* */ -/* Routine Description: */ -/* */ -/* Get the BIOS revision number */ -/* */ -/****************************************************************************/ -static void -ips_get_bios_version(ips_ha_t * ha, int intr) -{ - ips_scb_t *scb; - int ret; - uint8_t major; - uint8_t minor; - uint8_t subminor; - uint8_t *buffer; - char hexDigits[] = - { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', - 'D', 'E', 'F' }; - - METHOD_TRACE("ips_get_bios_version", 1); - - major = 0; - minor = 0; - - strncpy(ha->bios_version, " ?", 8); - - if (ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) { - if (IPS_USE_MEMIO(ha)) { - /* Memory Mapped I/O */ - - /* test 1st byte */ - writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) - return; - - writel(1, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) - return; - - /* Get Major version */ - writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - major = readb(ha->mem_ptr + IPS_REG_FLDP); - - /* Get Minor version */ - writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - minor = readb(ha->mem_ptr + IPS_REG_FLDP); - - /* Get SubMinor version */ - writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - subminor = readb(ha->mem_ptr + IPS_REG_FLDP); - - } else { - /* Programmed I/O */ - - /* test 1st byte */ - outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) - return; - - outl(1, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) - return; - - /* Get Major version */ - outl(0x1FF, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - major = inb(ha->io_addr + IPS_REG_FLDP); - - /* Get Minor version */ - outl(0x1FE, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - minor = inb(ha->io_addr + IPS_REG_FLDP); - - /* Get SubMinor version */ - outl(0x1FD, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - subminor = inb(ha->io_addr + IPS_REG_FLDP); - - } - } else { - /* Morpheus Family - Send Command to the card */ - - buffer = ha->ioctl_data; - - memset(buffer, 0, 0x1000); - - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_RW_BIOSFW; - - scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW; - scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.flashfw.type = 1; - scb->cmd.flashfw.direction = 0; - scb->cmd.flashfw.count = cpu_to_le32(0x800); - scb->cmd.flashfw.total_packets = 1; - scb->cmd.flashfw.packet_num = 0; - scb->data_len = 0x1000; - scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr; - - /* issue the command */ - if (((ret = - ips_send_wait(ha, scb, ips_cmd_timeout, - intr)) == IPS_FAILURE) - || (ret == IPS_SUCCESS_IMM) - || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { - /* Error occurred */ - - return; - } - - if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) { - major = buffer[0x1ff + 0xC0]; /* Offset 0x1ff after the header (0xc0) */ - minor = buffer[0x1fe + 0xC0]; /* Offset 0x1fe after the header (0xc0) */ - subminor = buffer[0x1fd + 0xC0]; /* Offset 0x1fd after the header (0xc0) */ - } else { - return; - } - } - - ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4]; - ha->bios_version[1] = '.'; - ha->bios_version[2] = hexDigits[major & 0x0F]; - ha->bios_version[3] = hexDigits[subminor]; - ha->bios_version[4] = '.'; - ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4]; - ha->bios_version[6] = hexDigits[minor & 0x0F]; - ha->bios_version[7] = 0; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_hainit */ -/* */ -/* Routine Description: */ -/* */ -/* Initialize the controller */ -/* */ -/* NOTE: Assumes to be called from with a lock */ -/* */ -/****************************************************************************/ -static int -ips_hainit(ips_ha_t * ha) -{ - int i; - struct timeval tv; - - METHOD_TRACE("ips_hainit", 1); - - if (!ha) - return (0); - - if (ha->func.statinit) - (*ha->func.statinit) (ha); - - if (ha->func.enableint) - (*ha->func.enableint) (ha); - - /* Send FFDC */ - ha->reset_count = 1; - do_gettimeofday(&tv); - ha->last_ffdc = tv.tv_sec; - ips_ffdc_reset(ha, IPS_INTR_IORL); - - if (!ips_read_config(ha, IPS_INTR_IORL)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "unable to read config from controller.\n"); - - return (0); - } - /* end if */ - if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "unable to read controller status.\n"); - - return (0); - } - - /* Identify this controller */ - ips_identify_controller(ha); - - if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "unable to read subsystem parameters.\n"); - - return (0); - } - - /* write nvram user page 5 */ - if (!ips_write_driver_status(ha, IPS_INTR_IORL)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "unable to write driver info to controller.\n"); - - return (0); - } - - /* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */ - if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1)) - ips_clear_adapter(ha, IPS_INTR_IORL); - - /* set limits on SID, LUN, BUS */ - ha->ntargets = IPS_MAX_TARGETS + 1; - ha->nlun = 1; - ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1; - - switch (ha->conf->logical_drive[0].ucStripeSize) { - case 4: - ha->max_xfer = 0x10000; - break; - - case 5: - ha->max_xfer = 0x20000; - break; - - case 6: - ha->max_xfer = 0x40000; - break; - - case 7: - default: - ha->max_xfer = 0x80000; - break; - } - - /* setup max concurrent commands */ - if (le32_to_cpu(ha->subsys->param[4]) & 0x1) { - /* Use the new method */ - ha->max_cmds = ha->enq->ucConcurrentCmdCount; - } else { - /* use the old method */ - switch (ha->conf->logical_drive[0].ucStripeSize) { - case 4: - ha->max_cmds = 32; - break; - - case 5: - ha->max_cmds = 16; - break; - - case 6: - ha->max_cmds = 8; - break; - - case 7: - default: - ha->max_cmds = 4; - break; - } - } - - /* Limit the Active Commands on a Lite Adapter */ - if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) || - (ha->ad_type == IPS_ADTYPE_SERVERAID4L) || - (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) { - if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds)) - ha->max_cmds = MaxLiteCmds; - } - - /* set controller IDs */ - ha->ha_id[0] = IPS_ADAPTER_ID; - for (i = 1; i < ha->nbus; i++) { - ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f; - ha->dcdb_active[i - 1] = 0; - } - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_next */ -/* */ -/* Routine Description: */ -/* */ -/* Take the next command off the queue and send it to the controller */ -/* */ -/****************************************************************************/ -static void -ips_next(ips_ha_t * ha, int intr) -{ - ips_scb_t *scb; - struct scsi_cmnd *SC; - struct scsi_cmnd *p; - struct scsi_cmnd *q; - ips_copp_wait_item_t *item; - int ret; - struct Scsi_Host *host; - METHOD_TRACE("ips_next", 1); - - if (!ha) - return; - host = ips_sh[ha->host_num]; - /* - * Block access to the queue function so - * this command won't time out - */ - if (intr == IPS_INTR_ON) - spin_lock(host->host_lock); - - if ((ha->subsys->param[3] & 0x300000) - && (ha->scb_activelist.count == 0)) { - struct timeval tv; - - do_gettimeofday(&tv); - - if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) { - ha->last_ffdc = tv.tv_sec; - ips_ffdc_time(ha); - } - } - - /* - * Send passthru commands - * These have priority over normal I/O - * but shouldn't affect performance too much - * since we limit the number that can be active - * on the card at any one time - */ - while ((ha->num_ioctl < IPS_MAX_IOCTL) && - (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) { - - item = ips_removeq_copp_head(&ha->copp_waitlist); - ha->num_ioctl++; - if (intr == IPS_INTR_ON) - spin_unlock(host->host_lock); - scb->scsi_cmd = item->scsi_cmd; - kfree(item); - - ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr); - - if (intr == IPS_INTR_ON) - spin_lock(host->host_lock); - switch (ret) { - case IPS_FAILURE: - if (scb->scsi_cmd) { - scb->scsi_cmd->result = DID_ERROR << 16; - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - } - - ips_freescb(ha, scb); - break; - case IPS_SUCCESS_IMM: - if (scb->scsi_cmd) { - scb->scsi_cmd->result = DID_OK << 16; - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - } - - ips_freescb(ha, scb); - break; - default: - break; - } /* end case */ - - if (ret != IPS_SUCCESS) { - ha->num_ioctl--; - continue; - } - - ret = ips_send_cmd(ha, scb); - - if (ret == IPS_SUCCESS) - ips_putq_scb_head(&ha->scb_activelist, scb); - else - ha->num_ioctl--; - - switch (ret) { - case IPS_FAILURE: - if (scb->scsi_cmd) { - scb->scsi_cmd->result = DID_ERROR << 16; - } - - ips_freescb(ha, scb); - break; - case IPS_SUCCESS_IMM: - ips_freescb(ha, scb); - break; - default: - break; - } /* end case */ - - } - - /* - * Send "Normal" I/O commands - */ - - p = ha->scb_waitlist.head; - while ((p) && (scb = ips_getscb(ha))) { - if ((scmd_channel(p) > 0) - && (ha-> - dcdb_active[scmd_channel(p) - - 1] & (1 << scmd_id(p)))) { - ips_freescb(ha, scb); - p = (struct scsi_cmnd *) p->host_scribble; - continue; - } - - q = p; - SC = ips_removeq_wait(&ha->scb_waitlist, q); - - if (intr == IPS_INTR_ON) - spin_unlock(host->host_lock); /* Unlock HA after command is taken off queue */ - - SC->result = DID_OK; - SC->host_scribble = NULL; - - scb->target_id = SC->device->id; - scb->lun = SC->device->lun; - scb->bus = SC->device->channel; - scb->scsi_cmd = SC; - scb->breakup = 0; - scb->data_len = 0; - scb->callback = ipsintr_done; - scb->timeout = ips_cmd_timeout; - memset(&scb->cmd, 0, 16); - - /* copy in the CDB */ - memcpy(scb->cdb, SC->cmnd, SC->cmd_len); - - scb->sg_count = scsi_dma_map(SC); - BUG_ON(scb->sg_count < 0); - if (scb->sg_count) { - struct scatterlist *sg; - int i; - - scb->flags |= IPS_SCB_MAP_SG; - - scsi_for_each_sg(SC, sg, scb->sg_count, i) { - if (ips_fill_scb_sg_single - (ha, sg_dma_address(sg), scb, i, - sg_dma_len(sg)) < 0) - break; - } - scb->dcdb.transfer_length = scb->data_len; - } else { - scb->data_busaddr = 0L; - scb->sg_len = 0; - scb->data_len = 0; - scb->dcdb.transfer_length = 0; - } - - scb->dcdb.cmd_attribute = - ips_command_direction[scb->scsi_cmd->cmnd[0]]; - - /* Allow a WRITE BUFFER Command to Have no Data */ - /* This is Used by Tape Flash Utilites */ - if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && - (scb->data_len == 0)) - scb->dcdb.cmd_attribute = 0; - - if (!(scb->dcdb.cmd_attribute & 0x3)) - scb->dcdb.transfer_length = 0; - - if (scb->data_len >= IPS_MAX_XFER) { - scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; - scb->dcdb.transfer_length = 0; - } - if (intr == IPS_INTR_ON) - spin_lock(host->host_lock); - - ret = ips_send_cmd(ha, scb); - - switch (ret) { - case IPS_SUCCESS: - ips_putq_scb_head(&ha->scb_activelist, scb); - break; - case IPS_FAILURE: - if (scb->scsi_cmd) { - scb->scsi_cmd->result = DID_ERROR << 16; - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - } - - if (scb->bus) - ha->dcdb_active[scb->bus - 1] &= - ~(1 << scb->target_id); - - ips_freescb(ha, scb); - break; - case IPS_SUCCESS_IMM: - if (scb->scsi_cmd) - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - - if (scb->bus) - ha->dcdb_active[scb->bus - 1] &= - ~(1 << scb->target_id); - - ips_freescb(ha, scb); - break; - default: - break; - } /* end case */ - - p = (struct scsi_cmnd *) p->host_scribble; - - } /* end while */ - - if (intr == IPS_INTR_ON) - spin_unlock(host->host_lock); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_putq_scb_head */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static void -ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item) -{ - METHOD_TRACE("ips_putq_scb_head", 1); - - if (!item) - return; - - item->q_next = queue->head; - queue->head = item; - - if (!queue->tail) - queue->tail = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_removeq_scb_head */ -/* */ -/* Routine Description: */ -/* */ -/* Remove the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static ips_scb_t * -ips_removeq_scb_head(ips_scb_queue_t * queue) -{ - ips_scb_t *item; - - METHOD_TRACE("ips_removeq_scb_head", 1); - - item = queue->head; - - if (!item) { - return (NULL); - } - - queue->head = item->q_next; - item->q_next = NULL; - - if (queue->tail == item) - queue->tail = NULL; - - queue->count--; - - return (item); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_removeq_scb */ -/* */ -/* Routine Description: */ -/* */ -/* Remove an item from a queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static ips_scb_t * -ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item) -{ - ips_scb_t *p; - - METHOD_TRACE("ips_removeq_scb", 1); - - if (!item) - return (NULL); - - if (item == queue->head) { - return (ips_removeq_scb_head(queue)); - } - - p = queue->head; - - while ((p) && (item != p->q_next)) - p = p->q_next; - - if (p) { - /* found a match */ - p->q_next = item->q_next; - - if (!item->q_next) - queue->tail = p; - - item->q_next = NULL; - queue->count--; - - return (item); - } - - return (NULL); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_putq_wait_tail */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the tail of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static void ips_putq_wait_tail(ips_wait_queue_t *queue, struct scsi_cmnd *item) -{ - METHOD_TRACE("ips_putq_wait_tail", 1); - - if (!item) - return; - - item->host_scribble = NULL; - - if (queue->tail) - queue->tail->host_scribble = (char *) item; - - queue->tail = item; - - if (!queue->head) - queue->head = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_removeq_wait_head */ -/* */ -/* Routine Description: */ -/* */ -/* Remove the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *queue) -{ - struct scsi_cmnd *item; - - METHOD_TRACE("ips_removeq_wait_head", 1); - - item = queue->head; - - if (!item) { - return (NULL); - } - - queue->head = (struct scsi_cmnd *) item->host_scribble; - item->host_scribble = NULL; - - if (queue->tail == item) - queue->tail = NULL; - - queue->count--; - - return (item); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_removeq_wait */ -/* */ -/* Routine Description: */ -/* */ -/* Remove an item from a queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *queue, - struct scsi_cmnd *item) -{ - struct scsi_cmnd *p; - - METHOD_TRACE("ips_removeq_wait", 1); - - if (!item) - return (NULL); - - if (item == queue->head) { - return (ips_removeq_wait_head(queue)); - } - - p = queue->head; - - while ((p) && (item != (struct scsi_cmnd *) p->host_scribble)) - p = (struct scsi_cmnd *) p->host_scribble; - - if (p) { - /* found a match */ - p->host_scribble = item->host_scribble; - - if (!item->host_scribble) - queue->tail = p; - - item->host_scribble = NULL; - queue->count--; - - return (item); - } - - return (NULL); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_putq_copp_tail */ -/* */ -/* Routine Description: */ -/* */ -/* Add an item to the tail of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static void -ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) -{ - METHOD_TRACE("ips_putq_copp_tail", 1); - - if (!item) - return; - - item->next = NULL; - - if (queue->tail) - queue->tail->next = item; - - queue->tail = item; - - if (!queue->head) - queue->head = item; - - queue->count++; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_removeq_copp_head */ -/* */ -/* Routine Description: */ -/* */ -/* Remove the head of the queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static ips_copp_wait_item_t * -ips_removeq_copp_head(ips_copp_queue_t * queue) -{ - ips_copp_wait_item_t *item; - - METHOD_TRACE("ips_removeq_copp_head", 1); - - item = queue->head; - - if (!item) { - return (NULL); - } - - queue->head = item->next; - item->next = NULL; - - if (queue->tail == item) - queue->tail = NULL; - - queue->count--; - - return (item); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_removeq_copp */ -/* */ -/* Routine Description: */ -/* */ -/* Remove an item from a queue */ -/* */ -/* ASSUMED to be called from within the HA lock */ -/* */ -/****************************************************************************/ -static ips_copp_wait_item_t * -ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item) -{ - ips_copp_wait_item_t *p; - - METHOD_TRACE("ips_removeq_copp", 1); - - if (!item) - return (NULL); - - if (item == queue->head) { - return (ips_removeq_copp_head(queue)); - } - - p = queue->head; - - while ((p) && (item != p->next)) - p = p->next; - - if (p) { - /* found a match */ - p->next = item->next; - - if (!item->next) - queue->tail = p; - - item->next = NULL; - queue->count--; - - return (item); - } - - return (NULL); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ipsintr_blocking */ -/* */ -/* Routine Description: */ -/* */ -/* Finalize an interrupt for internal commands */ -/* */ -/****************************************************************************/ -static void -ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb) -{ - METHOD_TRACE("ipsintr_blocking", 2); - - ips_freescb(ha, scb); - if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) { - ha->waitflag = FALSE; - - return; - } -} - -/****************************************************************************/ -/* */ -/* Routine Name: ipsintr_done */ -/* */ -/* Routine Description: */ -/* */ -/* Finalize an interrupt for non-internal commands */ -/* */ -/****************************************************************************/ -static void -ipsintr_done(ips_ha_t * ha, ips_scb_t * scb) -{ - METHOD_TRACE("ipsintr_done", 2); - - if (!scb) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Spurious interrupt; scb NULL.\n"); - - return; - } - - if (scb->scsi_cmd == NULL) { - /* unexpected interrupt */ - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Spurious interrupt; scsi_cmd not set.\n"); - - return; - } - - ips_done(ha, scb); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_done */ -/* */ -/* Routine Description: */ -/* */ -/* Do housekeeping on completed commands */ -/* ASSUMED to be called form within the request lock */ -/****************************************************************************/ -static void -ips_done(ips_ha_t * ha, ips_scb_t * scb) -{ - int ret; - - METHOD_TRACE("ips_done", 1); - - if (!scb) - return; - - if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) { - ips_cleanup_passthru(ha, scb); - ha->num_ioctl--; - } else { - /* - * Check to see if this command had too much - * data and had to be broke up. If so, queue - * the rest of the data and continue. - */ - if ((scb->breakup) || (scb->sg_break)) { - struct scatterlist *sg; - int i, sg_dma_index, ips_sg_index = 0; - - /* we had a data breakup */ - scb->data_len = 0; - - sg = scsi_sglist(scb->scsi_cmd); - - /* Spin forward to last dma chunk */ - sg_dma_index = scb->breakup; - for (i = 0; i < scb->breakup; i++) - sg = sg_next(sg); - - /* Take care of possible partial on last chunk */ - ips_fill_scb_sg_single(ha, - sg_dma_address(sg), - scb, ips_sg_index++, - sg_dma_len(sg)); - - for (; sg_dma_index < scsi_sg_count(scb->scsi_cmd); - sg_dma_index++, sg = sg_next(sg)) { - if (ips_fill_scb_sg_single - (ha, - sg_dma_address(sg), - scb, ips_sg_index++, - sg_dma_len(sg)) < 0) - break; - } - - scb->dcdb.transfer_length = scb->data_len; - scb->dcdb.cmd_attribute |= - ips_command_direction[scb->scsi_cmd->cmnd[0]]; - - if (!(scb->dcdb.cmd_attribute & 0x3)) - scb->dcdb.transfer_length = 0; - - if (scb->data_len >= IPS_MAX_XFER) { - scb->dcdb.cmd_attribute |= IPS_TRANSFER64K; - scb->dcdb.transfer_length = 0; - } - - ret = ips_send_cmd(ha, scb); - - switch (ret) { - case IPS_FAILURE: - if (scb->scsi_cmd) { - scb->scsi_cmd->result = DID_ERROR << 16; - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - } - - ips_freescb(ha, scb); - break; - case IPS_SUCCESS_IMM: - if (scb->scsi_cmd) { - scb->scsi_cmd->result = DID_ERROR << 16; - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - } - - ips_freescb(ha, scb); - break; - default: - break; - } /* end case */ - - return; - } - } /* end if passthru */ - - if (scb->bus) { - ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id); - } - - scb->scsi_cmd->scsi_done(scb->scsi_cmd); - - ips_freescb(ha, scb); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_map_status */ -/* */ -/* Routine Description: */ -/* */ -/* Map Controller Error codes to Linux Error Codes */ -/* */ -/****************************************************************************/ -static int -ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp) -{ - int errcode; - int device_error; - uint32_t transfer_len; - IPS_DCDB_TABLE_TAPE *tapeDCDB; - IPS_SCSI_INQ_DATA inquiryData; - - METHOD_TRACE("ips_map_status", 1); - - if (scb->bus) { - DEBUG_VAR(2, - "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x", - ips_name, ha->host_num, - scb->scsi_cmd->device->channel, - scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun, - scb->basic_status, scb->extended_status, - scb->extended_status == - IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0, - scb->extended_status == - IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0, - scb->extended_status == - IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0); - } - - /* default driver error */ - errcode = DID_ERROR; - device_error = 0; - - switch (scb->basic_status & IPS_GSC_STATUS_MASK) { - case IPS_CMD_TIMEOUT: - errcode = DID_TIME_OUT; - break; - - case IPS_INVAL_OPCO: - case IPS_INVAL_CMD_BLK: - case IPS_INVAL_PARM_BLK: - case IPS_LD_ERROR: - case IPS_CMD_CMPLT_WERROR: - break; - - case IPS_PHYS_DRV_ERROR: - switch (scb->extended_status) { - case IPS_ERR_SEL_TO: - if (scb->bus) - errcode = DID_NO_CONNECT; - - break; - - case IPS_ERR_OU_RUN: - if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) || - (scb->cmd.dcdb.op_code == - IPS_CMD_EXTENDED_DCDB_SG)) { - tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; - transfer_len = tapeDCDB->transfer_length; - } else { - transfer_len = - (uint32_t) scb->dcdb.transfer_length; - } - - if ((scb->bus) && (transfer_len < scb->data_len)) { - /* Underrun - set default to no error */ - errcode = DID_OK; - - /* Restrict access to physical DASD */ - if (scb->scsi_cmd->cmnd[0] == INQUIRY) { - ips_scmd_buf_read(scb->scsi_cmd, - &inquiryData, sizeof (inquiryData)); - if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) { - errcode = DID_TIME_OUT; - break; - } - } - } else - errcode = DID_ERROR; - - break; - - case IPS_ERR_RECOVERY: - /* don't fail recovered errors */ - if (scb->bus) - errcode = DID_OK; - - break; - - case IPS_ERR_HOST_RESET: - case IPS_ERR_DEV_RESET: - errcode = DID_RESET; - break; - - case IPS_ERR_CKCOND: - if (scb->bus) { - if ((scb->cmd.dcdb.op_code == - IPS_CMD_EXTENDED_DCDB) - || (scb->cmd.dcdb.op_code == - IPS_CMD_EXTENDED_DCDB_SG)) { - tapeDCDB = - (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; - memcpy(scb->scsi_cmd->sense_buffer, - tapeDCDB->sense_info, - SCSI_SENSE_BUFFERSIZE); - } else { - memcpy(scb->scsi_cmd->sense_buffer, - scb->dcdb.sense_info, - SCSI_SENSE_BUFFERSIZE); - } - device_error = 2; /* check condition */ - } - - errcode = DID_OK; - - break; - - default: - errcode = DID_ERROR; - break; - - } /* end switch */ - } /* end switch */ - - scb->scsi_cmd->result = device_error | (errcode << 16); - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_send_wait */ -/* */ -/* Routine Description: */ -/* */ -/* Send a command to the controller and wait for it to return */ -/* */ -/* The FFDC Time Stamp use this function for the callback, but doesn't */ -/* actually need to wait. */ -/****************************************************************************/ -static int -ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr) -{ - int ret; - - METHOD_TRACE("ips_send_wait", 1); - - if (intr != IPS_FFDC) { /* Won't be Waiting if this is a Time Stamp */ - ha->waitflag = TRUE; - ha->cmd_in_progress = scb->cdb[0]; - } - scb->callback = ipsintr_blocking; - ret = ips_send_cmd(ha, scb); - - if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM)) - return (ret); - - if (intr != IPS_FFDC) /* Don't Wait around if this is a Time Stamp */ - ret = ips_wait(ha, timeout, intr); - - return (ret); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_scmd_buf_write */ -/* */ -/* Routine Description: */ -/* Write data to struct scsi_cmnd request_buffer at proper offsets */ -/****************************************************************************/ -static void -ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count) -{ - unsigned long flags; - - local_irq_save(flags); - scsi_sg_copy_from_buffer(scmd, data, count); - local_irq_restore(flags); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_scmd_buf_read */ -/* */ -/* Routine Description: */ -/* Copy data from a struct scsi_cmnd to a new, linear buffer */ -/****************************************************************************/ -static void -ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count) -{ - unsigned long flags; - - local_irq_save(flags); - scsi_sg_copy_to_buffer(scmd, data, count); - local_irq_restore(flags); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_send_cmd */ -/* */ -/* Routine Description: */ -/* */ -/* Map SCSI commands to ServeRAID commands for logical drives */ -/* */ -/****************************************************************************/ -static int -ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb) -{ - int ret; - char *sp; - int device_error; - IPS_DCDB_TABLE_TAPE *tapeDCDB; - int TimeOut; - - METHOD_TRACE("ips_send_cmd", 1); - - ret = IPS_SUCCESS; - - if (!scb->scsi_cmd) { - /* internal command */ - - if (scb->bus > 0) { - /* Controller commands can't be issued */ - /* to real devices -- fail them */ - if ((ha->waitflag == TRUE) && - (ha->cmd_in_progress == scb->cdb[0])) { - ha->waitflag = FALSE; - } - - return (1); - } - } else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) { - /* command to logical bus -- interpret */ - ret = IPS_SUCCESS_IMM; - - switch (scb->scsi_cmd->cmnd[0]) { - case ALLOW_MEDIUM_REMOVAL: - case REZERO_UNIT: - case ERASE: - case WRITE_FILEMARKS: - case SPACE: - scb->scsi_cmd->result = DID_ERROR << 16; - break; - - case START_STOP: - scb->scsi_cmd->result = DID_OK << 16; - - case TEST_UNIT_READY: - case INQUIRY: - if (scb->target_id == IPS_ADAPTER_ID) { - /* - * Either we have a TUR - * or we have a SCSI inquiry - */ - if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY) - scb->scsi_cmd->result = DID_OK << 16; - - if (scb->scsi_cmd->cmnd[0] == INQUIRY) { - IPS_SCSI_INQ_DATA inquiry; - - memset(&inquiry, 0, - sizeof (IPS_SCSI_INQ_DATA)); - - inquiry.DeviceType = - IPS_SCSI_INQ_TYPE_PROCESSOR; - inquiry.DeviceTypeQualifier = - IPS_SCSI_INQ_LU_CONNECTED; - inquiry.Version = IPS_SCSI_INQ_REV2; - inquiry.ResponseDataFormat = - IPS_SCSI_INQ_RD_REV2; - inquiry.AdditionalLength = 31; - inquiry.Flags[0] = - IPS_SCSI_INQ_Address16; - inquiry.Flags[1] = - IPS_SCSI_INQ_WBus16 | - IPS_SCSI_INQ_Sync; - strncpy(inquiry.VendorId, "IBM ", - 8); - strncpy(inquiry.ProductId, - "SERVERAID ", 16); - strncpy(inquiry.ProductRevisionLevel, - "1.00", 4); - - ips_scmd_buf_write(scb->scsi_cmd, - &inquiry, - sizeof (inquiry)); - - scb->scsi_cmd->result = DID_OK << 16; - } - } else { - scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; - scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.logical_info.reserved = 0; - scb->cmd.logical_info.reserved2 = 0; - scb->data_len = sizeof (IPS_LD_INFO); - scb->data_busaddr = ha->logical_drive_info_dma_addr; - scb->flags = 0; - scb->cmd.logical_info.buffer_addr = scb->data_busaddr; - ret = IPS_SUCCESS; - } - - break; - - case REQUEST_SENSE: - ips_reqsen(ha, scb); - scb->scsi_cmd->result = DID_OK << 16; - break; - - case READ_6: - case WRITE_6: - if (!scb->sg_len) { - scb->cmd.basic_io.op_code = - (scb->scsi_cmd->cmnd[0] == - READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE; - scb->cmd.basic_io.enhanced_sg = 0; - scb->cmd.basic_io.sg_addr = - cpu_to_le32(scb->data_busaddr); - } else { - scb->cmd.basic_io.op_code = - (scb->scsi_cmd->cmnd[0] == - READ_6) ? IPS_CMD_READ_SG : - IPS_CMD_WRITE_SG; - scb->cmd.basic_io.enhanced_sg = - IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; - scb->cmd.basic_io.sg_addr = - cpu_to_le32(scb->sg_busaddr); - } - - scb->cmd.basic_io.segment_4G = 0; - scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.basic_io.log_drv = scb->target_id; - scb->cmd.basic_io.sg_count = scb->sg_len; - - if (scb->cmd.basic_io.lba) - le32_add_cpu(&scb->cmd.basic_io.lba, - le16_to_cpu(scb->cmd.basic_io. - sector_count)); - else - scb->cmd.basic_io.lba = - (((scb->scsi_cmd-> - cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd-> - cmnd[2] << 8) | - (scb->scsi_cmd->cmnd[3])); - - scb->cmd.basic_io.sector_count = - cpu_to_le16(scb->data_len / IPS_BLKSIZE); - - if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0) - scb->cmd.basic_io.sector_count = - cpu_to_le16(256); - - ret = IPS_SUCCESS; - break; - - case READ_10: - case WRITE_10: - if (!scb->sg_len) { - scb->cmd.basic_io.op_code = - (scb->scsi_cmd->cmnd[0] == - READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE; - scb->cmd.basic_io.enhanced_sg = 0; - scb->cmd.basic_io.sg_addr = - cpu_to_le32(scb->data_busaddr); - } else { - scb->cmd.basic_io.op_code = - (scb->scsi_cmd->cmnd[0] == - READ_10) ? IPS_CMD_READ_SG : - IPS_CMD_WRITE_SG; - scb->cmd.basic_io.enhanced_sg = - IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; - scb->cmd.basic_io.sg_addr = - cpu_to_le32(scb->sg_busaddr); - } - - scb->cmd.basic_io.segment_4G = 0; - scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.basic_io.log_drv = scb->target_id; - scb->cmd.basic_io.sg_count = scb->sg_len; - - if (scb->cmd.basic_io.lba) - le32_add_cpu(&scb->cmd.basic_io.lba, - le16_to_cpu(scb->cmd.basic_io. - sector_count)); - else - scb->cmd.basic_io.lba = - ((scb->scsi_cmd->cmnd[2] << 24) | (scb-> - scsi_cmd-> - cmnd[3] - << 16) | - (scb->scsi_cmd->cmnd[4] << 8) | scb-> - scsi_cmd->cmnd[5]); - - scb->cmd.basic_io.sector_count = - cpu_to_le16(scb->data_len / IPS_BLKSIZE); - - if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) { - /* - * This is a null condition - * we don't have to do anything - * so just return - */ - scb->scsi_cmd->result = DID_OK << 16; - } else - ret = IPS_SUCCESS; - - break; - - case RESERVE: - case RELEASE: - scb->scsi_cmd->result = DID_OK << 16; - break; - - case MODE_SENSE: - scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; - scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.basic_io.segment_4G = 0; - scb->cmd.basic_io.enhanced_sg = 0; - scb->data_len = sizeof (*ha->enq); - scb->cmd.basic_io.sg_addr = ha->enq_busaddr; - ret = IPS_SUCCESS; - break; - - case READ_CAPACITY: - scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO; - scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.logical_info.reserved = 0; - scb->cmd.logical_info.reserved2 = 0; - scb->cmd.logical_info.reserved3 = 0; - scb->data_len = sizeof (IPS_LD_INFO); - scb->data_busaddr = ha->logical_drive_info_dma_addr; - scb->flags = 0; - scb->cmd.logical_info.buffer_addr = scb->data_busaddr; - ret = IPS_SUCCESS; - break; - - case SEND_DIAGNOSTIC: - case REASSIGN_BLOCKS: - case FORMAT_UNIT: - case SEEK_10: - case VERIFY: - case READ_DEFECT_DATA: - case READ_BUFFER: - case WRITE_BUFFER: - scb->scsi_cmd->result = DID_OK << 16; - break; - - default: - /* Set the Return Info to appear like the Command was */ - /* attempted, a Check Condition occurred, and Sense */ - /* Data indicating an Invalid CDB OpCode is returned. */ - sp = (char *) scb->scsi_cmd->sense_buffer; - - sp[0] = 0x70; /* Error Code */ - sp[2] = ILLEGAL_REQUEST; /* Sense Key 5 Illegal Req. */ - sp[7] = 0x0A; /* Additional Sense Length */ - sp[12] = 0x20; /* ASC = Invalid OpCode */ - sp[13] = 0x00; /* ASCQ */ - - device_error = 2; /* Indicate Check Condition */ - scb->scsi_cmd->result = device_error | (DID_OK << 16); - break; - } /* end switch */ - } - /* end if */ - if (ret == IPS_SUCCESS_IMM) - return (ret); - - /* setup DCDB */ - if (scb->bus > 0) { - - /* If we already know the Device is Not there, no need to attempt a Command */ - /* This also protects an NT FailOver Controller from getting CDB's sent to it */ - if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) { - scb->scsi_cmd->result = DID_NO_CONNECT << 16; - return (IPS_SUCCESS_IMM); - } - - ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id); - scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr + - (unsigned long) &scb-> - dcdb - - (unsigned long) scb); - scb->cmd.dcdb.reserved = 0; - scb->cmd.dcdb.reserved2 = 0; - scb->cmd.dcdb.reserved3 = 0; - scb->cmd.dcdb.segment_4G = 0; - scb->cmd.dcdb.enhanced_sg = 0; - - TimeOut = scb->scsi_cmd->request->timeout; - - if (ha->subsys->param[4] & 0x00100000) { /* If NEW Tape DCDB is Supported */ - if (!scb->sg_len) { - scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB; - } else { - scb->cmd.dcdb.op_code = - IPS_CMD_EXTENDED_DCDB_SG; - scb->cmd.dcdb.enhanced_sg = - IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; - } - - tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb; /* Use Same Data Area as Old DCDB Struct */ - tapeDCDB->device_address = - ((scb->bus - 1) << 4) | scb->target_id; - tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED; - tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K; /* Always Turn OFF 64K Size Flag */ - - if (TimeOut) { - if (TimeOut < (10 * HZ)) - tapeDCDB->cmd_attribute |= IPS_TIMEOUT10; /* TimeOut is 10 Seconds */ - else if (TimeOut < (60 * HZ)) - tapeDCDB->cmd_attribute |= IPS_TIMEOUT60; /* TimeOut is 60 Seconds */ - else if (TimeOut < (1200 * HZ)) - tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M; /* TimeOut is 20 Minutes */ - } - - tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len; - tapeDCDB->reserved_for_LUN = 0; - tapeDCDB->transfer_length = scb->data_len; - if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG) - tapeDCDB->buffer_pointer = - cpu_to_le32(scb->sg_busaddr); - else - tapeDCDB->buffer_pointer = - cpu_to_le32(scb->data_busaddr); - tapeDCDB->sg_count = scb->sg_len; - tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info); - tapeDCDB->scsi_status = 0; - tapeDCDB->reserved = 0; - memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd, - scb->scsi_cmd->cmd_len); - } else { - if (!scb->sg_len) { - scb->cmd.dcdb.op_code = IPS_CMD_DCDB; - } else { - scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG; - scb->cmd.dcdb.enhanced_sg = - IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0; - } - - scb->dcdb.device_address = - ((scb->bus - 1) << 4) | scb->target_id; - scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED; - - if (TimeOut) { - if (TimeOut < (10 * HZ)) - scb->dcdb.cmd_attribute |= IPS_TIMEOUT10; /* TimeOut is 10 Seconds */ - else if (TimeOut < (60 * HZ)) - scb->dcdb.cmd_attribute |= IPS_TIMEOUT60; /* TimeOut is 60 Seconds */ - else if (TimeOut < (1200 * HZ)) - scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M; /* TimeOut is 20 Minutes */ - } - - scb->dcdb.transfer_length = scb->data_len; - if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K) - scb->dcdb.transfer_length = 0; - if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG) - scb->dcdb.buffer_pointer = - cpu_to_le32(scb->sg_busaddr); - else - scb->dcdb.buffer_pointer = - cpu_to_le32(scb->data_busaddr); - scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len; - scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info); - scb->dcdb.sg_count = scb->sg_len; - scb->dcdb.reserved = 0; - memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd, - scb->scsi_cmd->cmd_len); - scb->dcdb.scsi_status = 0; - scb->dcdb.reserved2[0] = 0; - scb->dcdb.reserved2[1] = 0; - scb->dcdb.reserved2[2] = 0; - } - } - - return ((*ha->func.issue) (ha, scb)); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_chk_status */ -/* */ -/* Routine Description: */ -/* */ -/* Check the status of commands to logical drives */ -/* Assumed to be called with the HA lock */ -/****************************************************************************/ -static void -ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus) -{ - ips_scb_t *scb; - ips_stat_t *sp; - uint8_t basic_status; - uint8_t ext_status; - int errcode; - IPS_SCSI_INQ_DATA inquiryData; - - METHOD_TRACE("ips_chkstatus", 1); - - scb = &ha->scbs[pstatus->fields.command_id]; - scb->basic_status = basic_status = - pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK; - scb->extended_status = ext_status = pstatus->fields.extended_status; - - sp = &ha->sp; - sp->residue_len = 0; - sp->scb_addr = (void *) scb; - - /* Remove the item from the active queue */ - ips_removeq_scb(&ha->scb_activelist, scb); - - if (!scb->scsi_cmd) - /* internal commands are handled in do_ipsintr */ - return; - - DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)", - ips_name, - ha->host_num, - scb->cdb[0], - scb->cmd.basic_io.command_id, - scb->bus, scb->target_id, scb->lun); - - if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) - /* passthru - just returns the raw result */ - return; - - errcode = DID_OK; - - if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) || - ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) { - - if (scb->bus == 0) { - if ((basic_status & IPS_GSC_STATUS_MASK) == - IPS_CMD_RECOVERED_ERROR) { - DEBUG_VAR(1, - "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", - ips_name, ha->host_num, - scb->cmd.basic_io.op_code, - basic_status, ext_status); - } - - switch (scb->scsi_cmd->cmnd[0]) { - case ALLOW_MEDIUM_REMOVAL: - case REZERO_UNIT: - case ERASE: - case WRITE_FILEMARKS: - case SPACE: - errcode = DID_ERROR; - break; - - case START_STOP: - break; - - case TEST_UNIT_READY: - if (!ips_online(ha, scb)) { - errcode = DID_TIME_OUT; - } - break; - - case INQUIRY: - if (ips_online(ha, scb)) { - ips_inquiry(ha, scb); - } else { - errcode = DID_TIME_OUT; - } - break; - - case REQUEST_SENSE: - ips_reqsen(ha, scb); - break; - - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case RESERVE: - case RELEASE: - break; - - case MODE_SENSE: - if (!ips_online(ha, scb) - || !ips_msense(ha, scb)) { - errcode = DID_ERROR; - } - break; - - case READ_CAPACITY: - if (ips_online(ha, scb)) - ips_rdcap(ha, scb); - else { - errcode = DID_TIME_OUT; - } - break; - - case SEND_DIAGNOSTIC: - case REASSIGN_BLOCKS: - break; - - case FORMAT_UNIT: - errcode = DID_ERROR; - break; - - case SEEK_10: - case VERIFY: - case READ_DEFECT_DATA: - case READ_BUFFER: - case WRITE_BUFFER: - break; - - default: - errcode = DID_ERROR; - } /* end switch */ - - scb->scsi_cmd->result = errcode << 16; - } else { /* bus == 0 */ - /* restrict access to physical drives */ - if (scb->scsi_cmd->cmnd[0] == INQUIRY) { - ips_scmd_buf_read(scb->scsi_cmd, - &inquiryData, sizeof (inquiryData)); - if ((inquiryData.DeviceType & 0x1f) == TYPE_DISK) - scb->scsi_cmd->result = DID_TIME_OUT << 16; - } - } /* else */ - } else { /* recovered error / success */ - if (scb->bus == 0) { - DEBUG_VAR(1, - "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x", - ips_name, ha->host_num, - scb->cmd.basic_io.op_code, basic_status, - ext_status); - } - - ips_map_status(ha, scb, sp); - } /* else */ -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_online */ -/* */ -/* Routine Description: */ -/* */ -/* Determine if a logical drive is online */ -/* */ -/****************************************************************************/ -static int -ips_online(ips_ha_t * ha, ips_scb_t * scb) -{ - METHOD_TRACE("ips_online", 1); - - if (scb->target_id >= IPS_MAX_LD) - return (0); - - if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) { - memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO)); - return (0); - } - - if (ha->logical_drive_info->drive_info[scb->target_id].state != - IPS_LD_OFFLINE - && ha->logical_drive_info->drive_info[scb->target_id].state != - IPS_LD_FREE - && ha->logical_drive_info->drive_info[scb->target_id].state != - IPS_LD_CRS - && ha->logical_drive_info->drive_info[scb->target_id].state != - IPS_LD_SYS) - return (1); - else - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_inquiry */ -/* */ -/* Routine Description: */ -/* */ -/* Simulate an inquiry command to a logical drive */ -/* */ -/****************************************************************************/ -static int -ips_inquiry(ips_ha_t * ha, ips_scb_t * scb) -{ - IPS_SCSI_INQ_DATA inquiry; - - METHOD_TRACE("ips_inquiry", 1); - - memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA)); - - inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD; - inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED; - inquiry.Version = IPS_SCSI_INQ_REV2; - inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2; - inquiry.AdditionalLength = 31; - inquiry.Flags[0] = IPS_SCSI_INQ_Address16; - inquiry.Flags[1] = - IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue; - strncpy(inquiry.VendorId, "IBM ", 8); - strncpy(inquiry.ProductId, "SERVERAID ", 16); - strncpy(inquiry.ProductRevisionLevel, "1.00", 4); - - ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry)); - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_rdcap */ -/* */ -/* Routine Description: */ -/* */ -/* Simulate a read capacity command to a logical drive */ -/* */ -/****************************************************************************/ -static int -ips_rdcap(ips_ha_t * ha, ips_scb_t * scb) -{ - IPS_SCSI_CAPACITY cap; - - METHOD_TRACE("ips_rdcap", 1); - - if (scsi_bufflen(scb->scsi_cmd) < 8) - return (0); - - cap.lba = - cpu_to_be32(le32_to_cpu - (ha->logical_drive_info-> - drive_info[scb->target_id].sector_count) - 1); - cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE); - - ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap)); - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_msense */ -/* */ -/* Routine Description: */ -/* */ -/* Simulate a mode sense command to a logical drive */ -/* */ -/****************************************************************************/ -static int -ips_msense(ips_ha_t * ha, ips_scb_t * scb) -{ - uint16_t heads; - uint16_t sectors; - uint32_t cylinders; - IPS_SCSI_MODE_PAGE_DATA mdata; - - METHOD_TRACE("ips_msense", 1); - - if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 && - (ha->enq->ucMiscFlag & 0x8) == 0) { - heads = IPS_NORM_HEADS; - sectors = IPS_NORM_SECTORS; - } else { - heads = IPS_COMP_HEADS; - sectors = IPS_COMP_SECTORS; - } - - cylinders = - (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) - - 1) / (heads * sectors); - - memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA)); - - mdata.hdr.BlockDescLength = 8; - - switch (scb->scsi_cmd->cmnd[2] & 0x3f) { - case 0x03: /* page 3 */ - mdata.pdata.pg3.PageCode = 3; - mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3); - mdata.hdr.DataLength = - 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength; - mdata.pdata.pg3.TracksPerZone = 0; - mdata.pdata.pg3.AltSectorsPerZone = 0; - mdata.pdata.pg3.AltTracksPerZone = 0; - mdata.pdata.pg3.AltTracksPerVolume = 0; - mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors); - mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE); - mdata.pdata.pg3.Interleave = cpu_to_be16(1); - mdata.pdata.pg3.TrackSkew = 0; - mdata.pdata.pg3.CylinderSkew = 0; - mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector; - break; - - case 0x4: - mdata.pdata.pg4.PageCode = 4; - mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4); - mdata.hdr.DataLength = - 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength; - mdata.pdata.pg4.CylindersHigh = - cpu_to_be16((cylinders >> 8) & 0xFFFF); - mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF); - mdata.pdata.pg4.Heads = heads; - mdata.pdata.pg4.WritePrecompHigh = 0; - mdata.pdata.pg4.WritePrecompLow = 0; - mdata.pdata.pg4.ReducedWriteCurrentHigh = 0; - mdata.pdata.pg4.ReducedWriteCurrentLow = 0; - mdata.pdata.pg4.StepRate = cpu_to_be16(1); - mdata.pdata.pg4.LandingZoneHigh = 0; - mdata.pdata.pg4.LandingZoneLow = 0; - mdata.pdata.pg4.flags = 0; - mdata.pdata.pg4.RotationalOffset = 0; - mdata.pdata.pg4.MediumRotationRate = 0; - break; - case 0x8: - mdata.pdata.pg8.PageCode = 8; - mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8); - mdata.hdr.DataLength = - 3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength; - /* everything else is left set to 0 */ - break; - - default: - return (0); - } /* end switch */ - - ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata)); - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_reqsen */ -/* */ -/* Routine Description: */ -/* */ -/* Simulate a request sense command to a logical drive */ -/* */ -/****************************************************************************/ -static int -ips_reqsen(ips_ha_t * ha, ips_scb_t * scb) -{ - IPS_SCSI_REQSEN reqsen; - - METHOD_TRACE("ips_reqsen", 1); - - memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN)); - - reqsen.ResponseCode = - IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR; - reqsen.AdditionalLength = 10; - reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE; - reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE; - - ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen)); - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_free */ -/* */ -/* Routine Description: */ -/* */ -/* Free any allocated space for this controller */ -/* */ -/****************************************************************************/ -static void -ips_free(ips_ha_t * ha) -{ - - METHOD_TRACE("ips_free", 1); - - if (ha) { - if (ha->enq) { - pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ), - ha->enq, ha->enq_busaddr); - ha->enq = NULL; - } - - kfree(ha->conf); - ha->conf = NULL; - - if (ha->adapt) { - pci_free_consistent(ha->pcidev, - sizeof (IPS_ADAPTER) + - sizeof (IPS_IO_CMD), ha->adapt, - ha->adapt->hw_status_start); - ha->adapt = NULL; - } - - if (ha->logical_drive_info) { - pci_free_consistent(ha->pcidev, - sizeof (IPS_LD_INFO), - ha->logical_drive_info, - ha->logical_drive_info_dma_addr); - ha->logical_drive_info = NULL; - } - - kfree(ha->nvram); - ha->nvram = NULL; - - kfree(ha->subsys); - ha->subsys = NULL; - - if (ha->ioctl_data) { - pci_free_consistent(ha->pcidev, ha->ioctl_len, - ha->ioctl_data, ha->ioctl_busaddr); - ha->ioctl_data = NULL; - ha->ioctl_datasize = 0; - ha->ioctl_len = 0; - } - ips_deallocatescbs(ha, ha->max_cmds); - - /* free memory mapped (if applicable) */ - if (ha->mem_ptr) { - iounmap(ha->ioremap_ptr); - ha->ioremap_ptr = NULL; - ha->mem_ptr = NULL; - } - - ha->mem_addr = 0; - - } -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_deallocatescbs */ -/* */ -/* Routine Description: */ -/* */ -/* Free the command blocks */ -/* */ -/****************************************************************************/ -static int -ips_deallocatescbs(ips_ha_t * ha, int cmds) -{ - if (ha->scbs) { - pci_free_consistent(ha->pcidev, - IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds, - ha->scbs->sg_list.list, - ha->scbs->sg_busaddr); - pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds, - ha->scbs, ha->scbs->scb_busaddr); - ha->scbs = NULL; - } /* end if */ - return 1; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_allocatescbs */ -/* */ -/* Routine Description: */ -/* */ -/* Allocate the command blocks */ -/* */ -/****************************************************************************/ -static int -ips_allocatescbs(ips_ha_t * ha) -{ - ips_scb_t *scb_p; - IPS_SG_LIST ips_sg; - int i; - dma_addr_t command_dma, sg_dma; - - METHOD_TRACE("ips_allocatescbs", 1); - - /* Allocate memory for the SCBs */ - ha->scbs = - pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t), - &command_dma); - if (ha->scbs == NULL) - return 0; - ips_sg.list = - pci_alloc_consistent(ha->pcidev, - IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * - ha->max_cmds, &sg_dma); - if (ips_sg.list == NULL) { - pci_free_consistent(ha->pcidev, - ha->max_cmds * sizeof (ips_scb_t), ha->scbs, - command_dma); - return 0; - } - - memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t)); - - for (i = 0; i < ha->max_cmds; i++) { - scb_p = &ha->scbs[i]; - scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i; - /* set up S/G list */ - if (IPS_USE_ENH_SGLIST(ha)) { - scb_p->sg_list.enh_list = - ips_sg.enh_list + i * IPS_MAX_SG; - scb_p->sg_busaddr = - sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; - } else { - scb_p->sg_list.std_list = - ips_sg.std_list + i * IPS_MAX_SG; - scb_p->sg_busaddr = - sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i; - } - - /* add to the free list */ - if (i < ha->max_cmds - 1) { - scb_p->q_next = ha->scb_freelist; - ha->scb_freelist = scb_p; - } - } - - /* success */ - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_init_scb */ -/* */ -/* Routine Description: */ -/* */ -/* Initialize a CCB to default values */ -/* */ -/****************************************************************************/ -static void -ips_init_scb(ips_ha_t * ha, ips_scb_t * scb) -{ - IPS_SG_LIST sg_list; - uint32_t cmd_busaddr, sg_busaddr; - METHOD_TRACE("ips_init_scb", 1); - - if (scb == NULL) - return; - - sg_list.list = scb->sg_list.list; - cmd_busaddr = scb->scb_busaddr; - sg_busaddr = scb->sg_busaddr; - /* zero fill */ - memset(scb, 0, sizeof (ips_scb_t)); - memset(ha->dummy, 0, sizeof (IPS_IO_CMD)); - - /* Initialize dummy command bucket */ - ha->dummy->op_code = 0xFF; - ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start - + sizeof (IPS_ADAPTER)); - ha->dummy->command_id = IPS_MAX_CMDS; - - /* set bus address of scb */ - scb->scb_busaddr = cmd_busaddr; - scb->sg_busaddr = sg_busaddr; - scb->sg_list.list = sg_list.list; - - /* Neptune Fix */ - scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE); - scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start - + sizeof (IPS_ADAPTER)); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_get_scb */ -/* */ -/* Routine Description: */ -/* */ -/* Initialize a CCB to default values */ -/* */ -/* ASSUMED to be called from within a lock */ -/* */ -/****************************************************************************/ -static ips_scb_t * -ips_getscb(ips_ha_t * ha) -{ - ips_scb_t *scb; - - METHOD_TRACE("ips_getscb", 1); - - if ((scb = ha->scb_freelist) == NULL) { - - return (NULL); - } - - ha->scb_freelist = scb->q_next; - scb->flags = 0; - scb->q_next = NULL; - - ips_init_scb(ha, scb); - - return (scb); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_free_scb */ -/* */ -/* Routine Description: */ -/* */ -/* Return an unused CCB back to the free list */ -/* */ -/* ASSUMED to be called from within a lock */ -/* */ -/****************************************************************************/ -static void -ips_freescb(ips_ha_t * ha, ips_scb_t * scb) -{ - - METHOD_TRACE("ips_freescb", 1); - if (scb->flags & IPS_SCB_MAP_SG) - scsi_dma_unmap(scb->scsi_cmd); - else if (scb->flags & IPS_SCB_MAP_SINGLE) - pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len, - IPS_DMA_DIR(scb)); - - /* check to make sure this is not our "special" scb */ - if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) { - scb->q_next = ha->scb_freelist; - ha->scb_freelist = scb; - } -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_isinit_copperhead */ -/* */ -/* Routine Description: */ -/* */ -/* Is controller initialized ? */ -/* */ -/****************************************************************************/ -static int -ips_isinit_copperhead(ips_ha_t * ha) -{ - uint8_t scpr; - uint8_t isr; - - METHOD_TRACE("ips_isinit_copperhead", 1); - - isr = inb(ha->io_addr + IPS_REG_HISR); - scpr = inb(ha->io_addr + IPS_REG_SCPR); - - if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) - return (0); - else - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_isinit_copperhead_memio */ -/* */ -/* Routine Description: */ -/* */ -/* Is controller initialized ? */ -/* */ -/****************************************************************************/ -static int -ips_isinit_copperhead_memio(ips_ha_t * ha) -{ - uint8_t isr = 0; - uint8_t scpr; - - METHOD_TRACE("ips_is_init_copperhead_memio", 1); - - isr = readb(ha->mem_ptr + IPS_REG_HISR); - scpr = readb(ha->mem_ptr + IPS_REG_SCPR); - - if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0)) - return (0); - else - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_isinit_morpheus */ -/* */ -/* Routine Description: */ -/* */ -/* Is controller initialized ? */ -/* */ -/****************************************************************************/ -static int -ips_isinit_morpheus(ips_ha_t * ha) -{ - uint32_t post; - uint32_t bits; - - METHOD_TRACE("ips_is_init_morpheus", 1); - - if (ips_isintr_morpheus(ha)) - ips_flush_and_reset(ha); - - post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); - bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR); - - if (post == 0) - return (0); - else if (bits & 0x3) - return (0); - else - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_flush_and_reset */ -/* */ -/* Routine Description: */ -/* */ -/* Perform cleanup ( FLUSH and RESET ) when the adapter is in an unknown */ -/* state ( was trying to INIT and an interrupt was already pending ) ... */ -/* */ -/****************************************************************************/ -static void -ips_flush_and_reset(ips_ha_t *ha) -{ - ips_scb_t *scb; - int ret; - int time; - int done; - dma_addr_t command_dma; - - /* Create a usuable SCB */ - scb = pci_alloc_consistent(ha->pcidev, sizeof(ips_scb_t), &command_dma); - if (scb) { - memset(scb, 0, sizeof(ips_scb_t)); - ips_init_scb(ha, scb); - scb->scb_busaddr = command_dma; - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_FLUSH; - - scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH; - scb->cmd.flush_cache.command_id = IPS_MAX_CMDS; /* Use an ID that would otherwise not exist */ - scb->cmd.flush_cache.state = IPS_NORM_STATE; - scb->cmd.flush_cache.reserved = 0; - scb->cmd.flush_cache.reserved2 = 0; - scb->cmd.flush_cache.reserved3 = 0; - scb->cmd.flush_cache.reserved4 = 0; - - ret = ips_send_cmd(ha, scb); /* Send the Flush Command */ - - if (ret == IPS_SUCCESS) { - time = 60 * IPS_ONE_SEC; /* Max Wait time is 60 seconds */ - done = 0; - - while ((time > 0) && (!done)) { - done = ips_poll_for_flush_complete(ha); - /* This may look evil, but it's only done during extremely rare start-up conditions ! */ - udelay(1000); - time--; - } - } - } - - /* Now RESET and INIT the adapter */ - (*ha->func.reset) (ha); - - pci_free_consistent(ha->pcidev, sizeof(ips_scb_t), scb, command_dma); - return; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_poll_for_flush_complete */ -/* */ -/* Routine Description: */ -/* */ -/* Poll for the Flush Command issued by ips_flush_and_reset() to complete */ -/* All other responses are just taken off the queue and ignored */ -/* */ -/****************************************************************************/ -static int -ips_poll_for_flush_complete(ips_ha_t * ha) -{ - IPS_STATUS cstatus; - - while (TRUE) { - cstatus.value = (*ha->func.statupd) (ha); - - if (cstatus.value == 0xffffffff) /* If No Interrupt to process */ - break; - - /* Success is when we see the Flush Command ID */ - if (cstatus.fields.command_id == IPS_MAX_CMDS) - return 1; - } - - return 0; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_enable_int_copperhead */ -/* */ -/* Routine Description: */ -/* Turn on interrupts */ -/* */ -/****************************************************************************/ -static void -ips_enable_int_copperhead(ips_ha_t * ha) -{ - METHOD_TRACE("ips_enable_int_copperhead", 1); - - outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI); - inb(ha->io_addr + IPS_REG_HISR); /*Ensure PCI Posting Completes*/ -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_enable_int_copperhead_memio */ -/* */ -/* Routine Description: */ -/* Turn on interrupts */ -/* */ -/****************************************************************************/ -static void -ips_enable_int_copperhead_memio(ips_ha_t * ha) -{ - METHOD_TRACE("ips_enable_int_copperhead_memio", 1); - - writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); - readb(ha->mem_ptr + IPS_REG_HISR); /*Ensure PCI Posting Completes*/ -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_enable_int_morpheus */ -/* */ -/* Routine Description: */ -/* Turn on interrupts */ -/* */ -/****************************************************************************/ -static void -ips_enable_int_morpheus(ips_ha_t * ha) -{ - uint32_t Oimr; - - METHOD_TRACE("ips_enable_int_morpheus", 1); - - Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); - Oimr &= ~0x08; - writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); - readl(ha->mem_ptr + IPS_REG_I960_OIMR); /*Ensure PCI Posting Completes*/ -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_init_copperhead */ -/* */ -/* Routine Description: */ -/* */ -/* Initialize a copperhead controller */ -/* */ -/****************************************************************************/ -static int -ips_init_copperhead(ips_ha_t * ha) -{ - uint8_t Isr; - uint8_t Cbsp; - uint8_t PostByte[IPS_MAX_POST_BYTES]; - uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; - int i, j; - - METHOD_TRACE("ips_init_copperhead", 1); - - for (i = 0; i < IPS_MAX_POST_BYTES; i++) { - for (j = 0; j < 45; j++) { - Isr = inb(ha->io_addr + IPS_REG_HISR); - if (Isr & IPS_BIT_GHI) - break; - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (j >= 45) - /* error occurred */ - return (0); - - PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR); - outb(Isr, ha->io_addr + IPS_REG_HISR); - } - - if (PostByte[0] < IPS_GOOD_POST_STATUS) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "reset controller fails (post status %x %x).\n", - PostByte[0], PostByte[1]); - - return (0); - } - - for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { - for (j = 0; j < 240; j++) { - Isr = inb(ha->io_addr + IPS_REG_HISR); - if (Isr & IPS_BIT_GHI) - break; - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (j >= 240) - /* error occurred */ - return (0); - - ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR); - outb(Isr, ha->io_addr + IPS_REG_HISR); - } - - for (i = 0; i < 240; i++) { - Cbsp = inb(ha->io_addr + IPS_REG_CBSP); - - if ((Cbsp & IPS_BIT_OP) == 0) - break; - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (i >= 240) - /* reset failed */ - return (0); - - /* setup CCCR */ - outl(0x1010, ha->io_addr + IPS_REG_CCCR); - - /* Enable busmastering */ - outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR); - - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - /* fix for anaconda64 */ - outl(0, ha->io_addr + IPS_REG_NDAE); - - /* Enable interrupts */ - outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR); - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_init_copperhead_memio */ -/* */ -/* Routine Description: */ -/* */ -/* Initialize a copperhead controller with memory mapped I/O */ -/* */ -/****************************************************************************/ -static int -ips_init_copperhead_memio(ips_ha_t * ha) -{ - uint8_t Isr = 0; - uint8_t Cbsp; - uint8_t PostByte[IPS_MAX_POST_BYTES]; - uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES]; - int i, j; - - METHOD_TRACE("ips_init_copperhead_memio", 1); - - for (i = 0; i < IPS_MAX_POST_BYTES; i++) { - for (j = 0; j < 45; j++) { - Isr = readb(ha->mem_ptr + IPS_REG_HISR); - if (Isr & IPS_BIT_GHI) - break; - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (j >= 45) - /* error occurred */ - return (0); - - PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); - writeb(Isr, ha->mem_ptr + IPS_REG_HISR); - } - - if (PostByte[0] < IPS_GOOD_POST_STATUS) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "reset controller fails (post status %x %x).\n", - PostByte[0], PostByte[1]); - - return (0); - } - - for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) { - for (j = 0; j < 240; j++) { - Isr = readb(ha->mem_ptr + IPS_REG_HISR); - if (Isr & IPS_BIT_GHI) - break; - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (j >= 240) - /* error occurred */ - return (0); - - ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR); - writeb(Isr, ha->mem_ptr + IPS_REG_HISR); - } - - for (i = 0; i < 240; i++) { - Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP); - - if ((Cbsp & IPS_BIT_OP) == 0) - break; - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (i >= 240) - /* error occurred */ - return (0); - - /* setup CCCR */ - writel(0x1010, ha->mem_ptr + IPS_REG_CCCR); - - /* Enable busmastering */ - writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR); - - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - /* fix for anaconda64 */ - writel(0, ha->mem_ptr + IPS_REG_NDAE); - - /* Enable interrupts */ - writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR); - - /* if we get here then everything went OK */ - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_init_morpheus */ -/* */ -/* Routine Description: */ -/* */ -/* Initialize a morpheus controller */ -/* */ -/****************************************************************************/ -static int -ips_init_morpheus(ips_ha_t * ha) -{ - uint32_t Post; - uint32_t Config; - uint32_t Isr; - uint32_t Oimr; - int i; - - METHOD_TRACE("ips_init_morpheus", 1); - - /* Wait up to 45 secs for Post */ - for (i = 0; i < 45; i++) { - Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); - - if (Isr & IPS_BIT_I960_MSG0I) - break; - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (i >= 45) { - /* error occurred */ - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "timeout waiting for post.\n"); - - return (0); - } - - Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); - - if (Post == 0x4F00) { /* If Flashing the Battery PIC */ - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Flashing Battery PIC, Please wait ...\n"); - - /* Clear the interrupt bit */ - Isr = (uint32_t) IPS_BIT_I960_MSG0I; - writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); - - for (i = 0; i < 120; i++) { /* Wait Up to 2 Min. for Completion */ - Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0); - if (Post != 0x4F00) - break; - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (i >= 120) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "timeout waiting for Battery PIC Flash\n"); - return (0); - } - - } - - /* Clear the interrupt bit */ - Isr = (uint32_t) IPS_BIT_I960_MSG0I; - writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); - - if (Post < (IPS_GOOD_POST_STATUS << 8)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "reset controller fails (post status %x).\n", Post); - - return (0); - } - - /* Wait up to 240 secs for config bytes */ - for (i = 0; i < 240; i++) { - Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); - - if (Isr & IPS_BIT_I960_MSG1I) - break; - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - } - - if (i >= 240) { - /* error occurred */ - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "timeout waiting for config.\n"); - - return (0); - } - - Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1); - - /* Clear interrupt bit */ - Isr = (uint32_t) IPS_BIT_I960_MSG1I; - writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR); - - /* Turn on the interrupts */ - Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR); - Oimr &= ~0x8; - writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR); - - /* if we get here then everything went OK */ - - /* Since we did a RESET, an EraseStripeLock may be needed */ - if (Post == 0xEF10) { - if ((Config == 0x000F) || (Config == 0x0009)) - ha->requires_esl = 1; - } - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_reset_copperhead */ -/* */ -/* Routine Description: */ -/* */ -/* Reset the controller */ -/* */ -/****************************************************************************/ -static int -ips_reset_copperhead(ips_ha_t * ha) -{ - int reset_counter; - - METHOD_TRACE("ips_reset_copperhead", 1); - - DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d", - ips_name, ha->host_num, ha->io_addr, ha->pcidev->irq); - - reset_counter = 0; - - while (reset_counter < 2) { - reset_counter++; - - outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR); - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - - outb(0, ha->io_addr + IPS_REG_SCPR); - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - - if ((*ha->func.init) (ha)) - break; - else if (reset_counter >= 2) { - - return (0); - } - } - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_reset_copperhead_memio */ -/* */ -/* Routine Description: */ -/* */ -/* Reset the controller */ -/* */ -/****************************************************************************/ -static int -ips_reset_copperhead_memio(ips_ha_t * ha) -{ - int reset_counter; - - METHOD_TRACE("ips_reset_copperhead_memio", 1); - - DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d", - ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq); - - reset_counter = 0; - - while (reset_counter < 2) { - reset_counter++; - - writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR); - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - - writeb(0, ha->mem_ptr + IPS_REG_SCPR); - - /* Delay for 1 Second */ - MDELAY(IPS_ONE_SEC); - - if ((*ha->func.init) (ha)) - break; - else if (reset_counter >= 2) { - - return (0); - } - } - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_reset_morpheus */ -/* */ -/* Routine Description: */ -/* */ -/* Reset the controller */ -/* */ -/****************************************************************************/ -static int -ips_reset_morpheus(ips_ha_t * ha) -{ - int reset_counter; - uint8_t junk; - - METHOD_TRACE("ips_reset_morpheus", 1); - - DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d", - ips_name, ha->host_num, ha->mem_addr, ha->pcidev->irq); - - reset_counter = 0; - - while (reset_counter < 2) { - reset_counter++; - - writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR); - - /* Delay for 5 Seconds */ - MDELAY(5 * IPS_ONE_SEC); - - /* Do a PCI config read to wait for adapter */ - pci_read_config_byte(ha->pcidev, 4, &junk); - - if ((*ha->func.init) (ha)) - break; - else if (reset_counter >= 2) { - - return (0); - } - } - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_statinit */ -/* */ -/* Routine Description: */ -/* */ -/* Initialize the status queues on the controller */ -/* */ -/****************************************************************************/ -static void -ips_statinit(ips_ha_t * ha) -{ - uint32_t phys_status_start; - - METHOD_TRACE("ips_statinit", 1); - - ha->adapt->p_status_start = ha->adapt->status; - ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; - ha->adapt->p_status_tail = ha->adapt->status; - - phys_status_start = ha->adapt->hw_status_start; - outl(phys_status_start, ha->io_addr + IPS_REG_SQSR); - outl(phys_status_start + IPS_STATUS_Q_SIZE, - ha->io_addr + IPS_REG_SQER); - outl(phys_status_start + IPS_STATUS_SIZE, - ha->io_addr + IPS_REG_SQHR); - outl(phys_status_start, ha->io_addr + IPS_REG_SQTR); - - ha->adapt->hw_status_tail = phys_status_start; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_statinit_memio */ -/* */ -/* Routine Description: */ -/* */ -/* Initialize the status queues on the controller */ -/* */ -/****************************************************************************/ -static void -ips_statinit_memio(ips_ha_t * ha) -{ - uint32_t phys_status_start; - - METHOD_TRACE("ips_statinit_memio", 1); - - ha->adapt->p_status_start = ha->adapt->status; - ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS; - ha->adapt->p_status_tail = ha->adapt->status; - - phys_status_start = ha->adapt->hw_status_start; - writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR); - writel(phys_status_start + IPS_STATUS_Q_SIZE, - ha->mem_ptr + IPS_REG_SQER); - writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR); - writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR); - - ha->adapt->hw_status_tail = phys_status_start; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_statupd_copperhead */ -/* */ -/* Routine Description: */ -/* */ -/* Remove an element from the status queue */ -/* */ -/****************************************************************************/ -static uint32_t -ips_statupd_copperhead(ips_ha_t * ha) -{ - METHOD_TRACE("ips_statupd_copperhead", 1); - - if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { - ha->adapt->p_status_tail++; - ha->adapt->hw_status_tail += sizeof (IPS_STATUS); - } else { - ha->adapt->p_status_tail = ha->adapt->p_status_start; - ha->adapt->hw_status_tail = ha->adapt->hw_status_start; - } - - outl(ha->adapt->hw_status_tail, - ha->io_addr + IPS_REG_SQTR); - - return (ha->adapt->p_status_tail->value); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_statupd_copperhead_memio */ -/* */ -/* Routine Description: */ -/* */ -/* Remove an element from the status queue */ -/* */ -/****************************************************************************/ -static uint32_t -ips_statupd_copperhead_memio(ips_ha_t * ha) -{ - METHOD_TRACE("ips_statupd_copperhead_memio", 1); - - if (ha->adapt->p_status_tail != ha->adapt->p_status_end) { - ha->adapt->p_status_tail++; - ha->adapt->hw_status_tail += sizeof (IPS_STATUS); - } else { - ha->adapt->p_status_tail = ha->adapt->p_status_start; - ha->adapt->hw_status_tail = ha->adapt->hw_status_start; - } - - writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR); - - return (ha->adapt->p_status_tail->value); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_statupd_morpheus */ -/* */ -/* Routine Description: */ -/* */ -/* Remove an element from the status queue */ -/* */ -/****************************************************************************/ -static uint32_t -ips_statupd_morpheus(ips_ha_t * ha) -{ - uint32_t val; - - METHOD_TRACE("ips_statupd_morpheus", 1); - - val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ); - - return (val); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_issue_copperhead */ -/* */ -/* Routine Description: */ -/* */ -/* Send a command down to the controller */ -/* */ -/****************************************************************************/ -static int -ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb) -{ - uint32_t TimeOut; - uint32_t val; - - METHOD_TRACE("ips_issue_copperhead", 1); - - if (scb->scsi_cmd) { - DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", - ips_name, - ha->host_num, - scb->cdb[0], - scb->cmd.basic_io.command_id, - scb->bus, scb->target_id, scb->lun); - } else { - DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d", - ips_name, ha->host_num, scb->cmd.basic_io.command_id); - } - - TimeOut = 0; - - while ((val = - le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) { - udelay(1000); - - if (++TimeOut >= IPS_SEM_TIMEOUT) { - if (!(val & IPS_BIT_START_STOP)) - break; - - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "ips_issue val [0x%x].\n", val); - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "ips_issue semaphore chk timeout.\n"); - - return (IPS_FAILURE); - } /* end if */ - } /* end while */ - - outl(scb->scb_busaddr, ha->io_addr + IPS_REG_CCSAR); - outw(IPS_BIT_START_CMD, ha->io_addr + IPS_REG_CCCR); - - return (IPS_SUCCESS); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_issue_copperhead_memio */ -/* */ -/* Routine Description: */ -/* */ -/* Send a command down to the controller */ -/* */ -/****************************************************************************/ -static int -ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb) -{ - uint32_t TimeOut; - uint32_t val; - - METHOD_TRACE("ips_issue_copperhead_memio", 1); - - if (scb->scsi_cmd) { - DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", - ips_name, - ha->host_num, - scb->cdb[0], - scb->cmd.basic_io.command_id, - scb->bus, scb->target_id, scb->lun); - } else { - DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", - ips_name, ha->host_num, scb->cmd.basic_io.command_id); - } - - TimeOut = 0; - - while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) { - udelay(1000); - - if (++TimeOut >= IPS_SEM_TIMEOUT) { - if (!(val & IPS_BIT_START_STOP)) - break; - - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "ips_issue val [0x%x].\n", val); - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "ips_issue semaphore chk timeout.\n"); - - return (IPS_FAILURE); - } /* end if */ - } /* end while */ - - writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR); - writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR); - - return (IPS_SUCCESS); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_issue_i2o */ -/* */ -/* Routine Description: */ -/* */ -/* Send a command down to the controller */ -/* */ -/****************************************************************************/ -static int -ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb) -{ - - METHOD_TRACE("ips_issue_i2o", 1); - - if (scb->scsi_cmd) { - DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", - ips_name, - ha->host_num, - scb->cdb[0], - scb->cmd.basic_io.command_id, - scb->bus, scb->target_id, scb->lun); - } else { - DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", - ips_name, ha->host_num, scb->cmd.basic_io.command_id); - } - - outl(scb->scb_busaddr, ha->io_addr + IPS_REG_I2O_INMSGQ); - - return (IPS_SUCCESS); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_issue_i2o_memio */ -/* */ -/* Routine Description: */ -/* */ -/* Send a command down to the controller */ -/* */ -/****************************************************************************/ -static int -ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb) -{ - - METHOD_TRACE("ips_issue_i2o_memio", 1); - - if (scb->scsi_cmd) { - DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)", - ips_name, - ha->host_num, - scb->cdb[0], - scb->cmd.basic_io.command_id, - scb->bus, scb->target_id, scb->lun); - } else { - DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d", - ips_name, ha->host_num, scb->cmd.basic_io.command_id); - } - - writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ); - - return (IPS_SUCCESS); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_isintr_copperhead */ -/* */ -/* Routine Description: */ -/* */ -/* Test to see if an interrupt is for us */ -/* */ -/****************************************************************************/ -static int -ips_isintr_copperhead(ips_ha_t * ha) -{ - uint8_t Isr; - - METHOD_TRACE("ips_isintr_copperhead", 2); - - Isr = inb(ha->io_addr + IPS_REG_HISR); - - if (Isr == 0xFF) - /* ?!?! Nothing really there */ - return (0); - - if (Isr & IPS_BIT_SCE) - return (1); - else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { - /* status queue overflow or GHI */ - /* just clear the interrupt */ - outb(Isr, ha->io_addr + IPS_REG_HISR); - } - - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_isintr_copperhead_memio */ -/* */ -/* Routine Description: */ -/* */ -/* Test to see if an interrupt is for us */ -/* */ -/****************************************************************************/ -static int -ips_isintr_copperhead_memio(ips_ha_t * ha) -{ - uint8_t Isr; - - METHOD_TRACE("ips_isintr_memio", 2); - - Isr = readb(ha->mem_ptr + IPS_REG_HISR); - - if (Isr == 0xFF) - /* ?!?! Nothing really there */ - return (0); - - if (Isr & IPS_BIT_SCE) - return (1); - else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) { - /* status queue overflow or GHI */ - /* just clear the interrupt */ - writeb(Isr, ha->mem_ptr + IPS_REG_HISR); - } - - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_isintr_morpheus */ -/* */ -/* Routine Description: */ -/* */ -/* Test to see if an interrupt is for us */ -/* */ -/****************************************************************************/ -static int -ips_isintr_morpheus(ips_ha_t * ha) -{ - uint32_t Isr; - - METHOD_TRACE("ips_isintr_morpheus", 2); - - Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR); - - if (Isr & IPS_BIT_I2O_OPQI) - return (1); - else - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_wait */ -/* */ -/* Routine Description: */ -/* */ -/* Wait for a command to complete */ -/* */ -/****************************************************************************/ -static int -ips_wait(ips_ha_t * ha, int time, int intr) -{ - int ret; - int done; - - METHOD_TRACE("ips_wait", 1); - - ret = IPS_FAILURE; - done = FALSE; - - time *= IPS_ONE_SEC; /* convert seconds */ - - while ((time > 0) && (!done)) { - if (intr == IPS_INTR_ON) { - if (ha->waitflag == FALSE) { - ret = IPS_SUCCESS; - done = TRUE; - break; - } - } else if (intr == IPS_INTR_IORL) { - if (ha->waitflag == FALSE) { - /* - * controller generated an interrupt to - * acknowledge completion of the command - * and ips_intr() has serviced the interrupt. - */ - ret = IPS_SUCCESS; - done = TRUE; - break; - } - - /* - * NOTE: we already have the io_request_lock so - * even if we get an interrupt it won't get serviced - * until after we finish. - */ - - (*ha->func.intr) (ha); - } - - /* This looks like a very evil loop, but it only does this during start-up */ - udelay(1000); - time--; - } - - return (ret); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_write_driver_status */ -/* */ -/* Routine Description: */ -/* */ -/* Write OS/Driver version to Page 5 of the nvram on the controller */ -/* */ -/****************************************************************************/ -static int -ips_write_driver_status(ips_ha_t * ha, int intr) -{ - METHOD_TRACE("ips_write_driver_status", 1); - - if (!ips_readwrite_page5(ha, FALSE, intr)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "unable to read NVRAM page 5.\n"); - - return (0); - } - - /* check to make sure the page has a valid */ - /* signature */ - if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) { - DEBUG_VAR(1, - "(%s%d) NVRAM page 5 has an invalid signature: %X.", - ips_name, ha->host_num, ha->nvram->signature); - ha->nvram->signature = IPS_NVRAM_P5_SIG; - } - - DEBUG_VAR(2, - "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.", - ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type), - ha->nvram->adapter_slot, ha->nvram->bios_high[0], - ha->nvram->bios_high[1], ha->nvram->bios_high[2], - ha->nvram->bios_high[3], ha->nvram->bios_low[0], - ha->nvram->bios_low[1], ha->nvram->bios_low[2], - ha->nvram->bios_low[3]); - - ips_get_bios_version(ha, intr); - - /* change values (as needed) */ - ha->nvram->operating_system = IPS_OS_LINUX; - ha->nvram->adapter_type = ha->ad_type; - strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4); - strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4); - strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4); - strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4); - - ha->nvram->versioning = 0; /* Indicate the Driver Does Not Support Versioning */ - - /* now update the page */ - if (!ips_readwrite_page5(ha, TRUE, intr)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "unable to write NVRAM page 5.\n"); - - return (0); - } - - /* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */ - ha->slot_num = ha->nvram->adapter_slot; - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_read_adapter_status */ -/* */ -/* Routine Description: */ -/* */ -/* Do an Inquiry command to the adapter */ -/* */ -/****************************************************************************/ -static int -ips_read_adapter_status(ips_ha_t * ha, int intr) -{ - ips_scb_t *scb; - int ret; - - METHOD_TRACE("ips_read_adapter_status", 1); - - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_ENQUIRY; - - scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY; - scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.basic_io.sg_count = 0; - scb->cmd.basic_io.lba = 0; - scb->cmd.basic_io.sector_count = 0; - scb->cmd.basic_io.log_drv = 0; - scb->data_len = sizeof (*ha->enq); - scb->cmd.basic_io.sg_addr = ha->enq_busaddr; - - /* send command */ - if (((ret = - ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) - || (ret == IPS_SUCCESS_IMM) - || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) - return (0); - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_read_subsystem_parameters */ -/* */ -/* Routine Description: */ -/* */ -/* Read subsystem parameters from the adapter */ -/* */ -/****************************************************************************/ -static int -ips_read_subsystem_parameters(ips_ha_t * ha, int intr) -{ - ips_scb_t *scb; - int ret; - - METHOD_TRACE("ips_read_subsystem_parameters", 1); - - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_GET_SUBSYS; - - scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS; - scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.basic_io.sg_count = 0; - scb->cmd.basic_io.lba = 0; - scb->cmd.basic_io.sector_count = 0; - scb->cmd.basic_io.log_drv = 0; - scb->data_len = sizeof (*ha->subsys); - scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; - - /* send command */ - if (((ret = - ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) - || (ret == IPS_SUCCESS_IMM) - || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) - return (0); - - memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys)); - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_read_config */ -/* */ -/* Routine Description: */ -/* */ -/* Read the configuration on the adapter */ -/* */ -/****************************************************************************/ -static int -ips_read_config(ips_ha_t * ha, int intr) -{ - ips_scb_t *scb; - int i; - int ret; - - METHOD_TRACE("ips_read_config", 1); - - /* set defaults for initiator IDs */ - for (i = 0; i < 4; i++) - ha->conf->init_id[i] = 7; - - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_READ_CONF; - - scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF; - scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb); - scb->data_len = sizeof (*ha->conf); - scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr; - - /* send command */ - if (((ret = - ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) - || (ret == IPS_SUCCESS_IMM) - || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { - - memset(ha->conf, 0, sizeof (IPS_CONF)); - - /* reset initiator IDs */ - for (i = 0; i < 4; i++) - ha->conf->init_id[i] = 7; - - /* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */ - if ((scb->basic_status & IPS_GSC_STATUS_MASK) == - IPS_CMD_CMPLT_WERROR) - return (1); - - return (0); - } - - memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf)); - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_readwrite_page5 */ -/* */ -/* Routine Description: */ -/* */ -/* Read nvram page 5 from the adapter */ -/* */ -/****************************************************************************/ -static int -ips_readwrite_page5(ips_ha_t * ha, int write, int intr) -{ - ips_scb_t *scb; - int ret; - - METHOD_TRACE("ips_readwrite_page5", 1); - - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE; - - scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE; - scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.nvram.page = 5; - scb->cmd.nvram.write = write; - scb->cmd.nvram.reserved = 0; - scb->cmd.nvram.reserved2 = 0; - scb->data_len = sizeof (*ha->nvram); - scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr; - if (write) - memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram)); - - /* issue the command */ - if (((ret = - ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) - || (ret == IPS_SUCCESS_IMM) - || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) { - - memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5)); - - return (0); - } - if (!write) - memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram)); - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_clear_adapter */ -/* */ -/* Routine Description: */ -/* */ -/* Clear the stripe lock tables */ -/* */ -/****************************************************************************/ -static int -ips_clear_adapter(ips_ha_t * ha, int intr) -{ - ips_scb_t *scb; - int ret; - - METHOD_TRACE("ips_clear_adapter", 1); - - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_reset_timeout; - scb->cdb[0] = IPS_CMD_CONFIG_SYNC; - - scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC; - scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.config_sync.channel = 0; - scb->cmd.config_sync.source_target = IPS_POCL; - scb->cmd.config_sync.reserved = 0; - scb->cmd.config_sync.reserved2 = 0; - scb->cmd.config_sync.reserved3 = 0; - - /* issue command */ - if (((ret = - ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE) - || (ret == IPS_SUCCESS_IMM) - || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) - return (0); - - /* send unlock stripe command */ - ips_init_scb(ha, scb); - - scb->cdb[0] = IPS_CMD_ERROR_TABLE; - scb->timeout = ips_reset_timeout; - - scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE; - scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.unlock_stripe.log_drv = 0; - scb->cmd.unlock_stripe.control = IPS_CSL; - scb->cmd.unlock_stripe.reserved = 0; - scb->cmd.unlock_stripe.reserved2 = 0; - scb->cmd.unlock_stripe.reserved3 = 0; - - /* issue command */ - if (((ret = - ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE) - || (ret == IPS_SUCCESS_IMM) - || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) - return (0); - - return (1); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_ffdc_reset */ -/* */ -/* Routine Description: */ -/* */ -/* FFDC: write reset info */ -/* */ -/****************************************************************************/ -static void -ips_ffdc_reset(ips_ha_t * ha, int intr) -{ - ips_scb_t *scb; - - METHOD_TRACE("ips_ffdc_reset", 1); - - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_FFDC; - scb->cmd.ffdc.op_code = IPS_CMD_FFDC; - scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.ffdc.reset_count = ha->reset_count; - scb->cmd.ffdc.reset_type = 0x80; - - /* convert time to what the card wants */ - ips_fix_ffdc_time(ha, scb, ha->last_ffdc); - - /* issue command */ - ips_send_wait(ha, scb, ips_cmd_timeout, intr); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_ffdc_time */ -/* */ -/* Routine Description: */ -/* */ -/* FFDC: write time info */ -/* */ -/****************************************************************************/ -static void -ips_ffdc_time(ips_ha_t * ha) -{ - ips_scb_t *scb; - - METHOD_TRACE("ips_ffdc_time", 1); - - DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num); - - scb = &ha->scbs[ha->max_cmds - 1]; - - ips_init_scb(ha, scb); - - scb->timeout = ips_cmd_timeout; - scb->cdb[0] = IPS_CMD_FFDC; - scb->cmd.ffdc.op_code = IPS_CMD_FFDC; - scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb); - scb->cmd.ffdc.reset_count = 0; - scb->cmd.ffdc.reset_type = 0; - - /* convert time to what the card wants */ - ips_fix_ffdc_time(ha, scb, ha->last_ffdc); - - /* issue command */ - ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_fix_ffdc_time */ -/* */ -/* Routine Description: */ -/* Adjust time_t to what the card wants */ -/* */ -/****************************************************************************/ -static void -ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time) -{ - long days; - long rem; - int i; - int year; - int yleap; - int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR }; - int month_lengths[12][2] = { {31, 31}, - {28, 29}, - {31, 31}, - {30, 30}, - {31, 31}, - {30, 30}, - {31, 31}, - {31, 31}, - {30, 30}, - {31, 31}, - {30, 30}, - {31, 31} - }; - - METHOD_TRACE("ips_fix_ffdc_time", 1); - - days = current_time / IPS_SECS_DAY; - rem = current_time % IPS_SECS_DAY; - - scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR); - rem = rem % IPS_SECS_HOUR; - scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN); - scb->cmd.ffdc.second = (rem % IPS_SECS_MIN); - - year = IPS_EPOCH_YEAR; - while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) { - int newy; - - newy = year + (days / IPS_DAYS_NORMAL_YEAR); - if (days < 0) - --newy; - days -= (newy - year) * IPS_DAYS_NORMAL_YEAR + - IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) - - IPS_NUM_LEAP_YEARS_THROUGH(year - 1); - year = newy; - } - - scb->cmd.ffdc.yearH = year / 100; - scb->cmd.ffdc.yearL = year % 100; - - for (i = 0; days >= month_lengths[i][yleap]; ++i) - days -= month_lengths[i][yleap]; - - scb->cmd.ffdc.month = i + 1; - scb->cmd.ffdc.day = days + 1; -} - -/**************************************************************************** - * BIOS Flash Routines * - ****************************************************************************/ - -/****************************************************************************/ -/* */ -/* Routine Name: ips_erase_bios */ -/* */ -/* Routine Description: */ -/* Erase the BIOS on the adapter */ -/* */ -/****************************************************************************/ -static int -ips_erase_bios(ips_ha_t * ha) -{ - int timeout; - uint8_t status = 0; - - METHOD_TRACE("ips_erase_bios", 1); - - status = 0; - - /* Clear the status register */ - outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - outb(0x50, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* Erase Setup */ - outb(0x20, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* Erase Confirm */ - outb(0xD0, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* Erase Status */ - outb(0x70, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - timeout = 80000; /* 80 seconds */ - - while (timeout > 0) { - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { - outl(0, ha->io_addr + IPS_REG_FLAP); - udelay(25); /* 25 us */ - } - - status = inb(ha->io_addr + IPS_REG_FLDP); - - if (status & 0x80) - break; - - MDELAY(1); - timeout--; - } - - /* check for timeout */ - if (timeout <= 0) { - /* timeout */ - - /* try to suspend the erase */ - outb(0xB0, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* wait for 10 seconds */ - timeout = 10000; - while (timeout > 0) { - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { - outl(0, ha->io_addr + IPS_REG_FLAP); - udelay(25); /* 25 us */ - } - - status = inb(ha->io_addr + IPS_REG_FLDP); - - if (status & 0xC0) - break; - - MDELAY(1); - timeout--; - } - - return (1); - } - - /* check for valid VPP */ - if (status & 0x08) - /* VPP failure */ - return (1); - - /* check for successful flash */ - if (status & 0x30) - /* sequence error */ - return (1); - - /* Otherwise, we were successful */ - /* clear status */ - outb(0x50, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* enable reads */ - outb(0xFF, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_erase_bios_memio */ -/* */ -/* Routine Description: */ -/* Erase the BIOS on the adapter */ -/* */ -/****************************************************************************/ -static int -ips_erase_bios_memio(ips_ha_t * ha) -{ - int timeout; - uint8_t status; - - METHOD_TRACE("ips_erase_bios_memio", 1); - - status = 0; - - /* Clear the status register */ - writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* Erase Setup */ - writeb(0x20, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* Erase Confirm */ - writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* Erase Status */ - writeb(0x70, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - timeout = 80000; /* 80 seconds */ - - while (timeout > 0) { - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { - writel(0, ha->mem_ptr + IPS_REG_FLAP); - udelay(25); /* 25 us */ - } - - status = readb(ha->mem_ptr + IPS_REG_FLDP); - - if (status & 0x80) - break; - - MDELAY(1); - timeout--; - } - - /* check for timeout */ - if (timeout <= 0) { - /* timeout */ - - /* try to suspend the erase */ - writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* wait for 10 seconds */ - timeout = 10000; - while (timeout > 0) { - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { - writel(0, ha->mem_ptr + IPS_REG_FLAP); - udelay(25); /* 25 us */ - } - - status = readb(ha->mem_ptr + IPS_REG_FLDP); - - if (status & 0xC0) - break; - - MDELAY(1); - timeout--; - } - - return (1); - } - - /* check for valid VPP */ - if (status & 0x08) - /* VPP failure */ - return (1); - - /* check for successful flash */ - if (status & 0x30) - /* sequence error */ - return (1); - - /* Otherwise, we were successful */ - /* clear status */ - writeb(0x50, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* enable reads */ - writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_program_bios */ -/* */ -/* Routine Description: */ -/* Program the BIOS on the adapter */ -/* */ -/****************************************************************************/ -static int -ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, - uint32_t offset) -{ - int i; - int timeout; - uint8_t status = 0; - - METHOD_TRACE("ips_program_bios", 1); - - status = 0; - - for (i = 0; i < buffersize; i++) { - /* write a byte */ - outl(i + offset, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - outb(0x40, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - outb(buffer[i], ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* wait up to one second */ - timeout = 1000; - while (timeout > 0) { - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { - outl(0, ha->io_addr + IPS_REG_FLAP); - udelay(25); /* 25 us */ - } - - status = inb(ha->io_addr + IPS_REG_FLDP); - - if (status & 0x80) - break; - - MDELAY(1); - timeout--; - } - - if (timeout == 0) { - /* timeout error */ - outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - outb(0xFF, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - return (1); - } - - /* check the status */ - if (status & 0x18) { - /* programming error */ - outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - outb(0xFF, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - return (1); - } - } /* end for */ - - /* Enable reading */ - outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - outb(0xFF, ha->io_addr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_program_bios_memio */ -/* */ -/* Routine Description: */ -/* Program the BIOS on the adapter */ -/* */ -/****************************************************************************/ -static int -ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, - uint32_t offset) -{ - int i; - int timeout; - uint8_t status = 0; - - METHOD_TRACE("ips_program_bios_memio", 1); - - status = 0; - - for (i = 0; i < buffersize; i++) { - /* write a byte */ - writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - writeb(0x40, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - /* wait up to one second */ - timeout = 1000; - while (timeout > 0) { - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) { - writel(0, ha->mem_ptr + IPS_REG_FLAP); - udelay(25); /* 25 us */ - } - - status = readb(ha->mem_ptr + IPS_REG_FLDP); - - if (status & 0x80) - break; - - MDELAY(1); - timeout--; - } - - if (timeout == 0) { - /* timeout error */ - writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - return (1); - } - - /* check the status */ - if (status & 0x18) { - /* programming error */ - writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - return (1); - } - } /* end for */ - - /* Enable reading */ - writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_verify_bios */ -/* */ -/* Routine Description: */ -/* Verify the BIOS on the adapter */ -/* */ -/****************************************************************************/ -static int -ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize, - uint32_t offset) -{ - uint8_t checksum; - int i; - - METHOD_TRACE("ips_verify_bios", 1); - - /* test 1st byte */ - outl(0, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55) - return (1); - - outl(1, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA) - return (1); - - checksum = 0xff; - for (i = 2; i < buffersize; i++) { - - outl(i + offset, ha->io_addr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP); - } - - if (checksum != 0) - /* failure */ - return (1); - else - /* success */ - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_verify_bios_memio */ -/* */ -/* Routine Description: */ -/* Verify the BIOS on the adapter */ -/* */ -/****************************************************************************/ -static int -ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize, - uint32_t offset) -{ - uint8_t checksum; - int i; - - METHOD_TRACE("ips_verify_bios_memio", 1); - - /* test 1st byte */ - writel(0, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55) - return (1); - - writel(1, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA) - return (1); - - checksum = 0xff; - for (i = 2; i < buffersize; i++) { - - writel(i + offset, ha->mem_ptr + IPS_REG_FLAP); - if (ha->pcidev->revision == IPS_REVID_TROMBONE64) - udelay(25); /* 25 us */ - - checksum = - (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP); - } - - if (checksum != 0) - /* failure */ - return (1); - else - /* success */ - return (0); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_abort_init */ -/* */ -/* Routine Description: */ -/* cleanup routine for a failed adapter initialization */ -/****************************************************************************/ -static int -ips_abort_init(ips_ha_t * ha, int index) -{ - ha->active = 0; - ips_free(ha); - ips_ha[index] = NULL; - ips_sh[index] = NULL; - return -1; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_shift_controllers */ -/* */ -/* Routine Description: */ -/* helper function for ordering adapters */ -/****************************************************************************/ -static void -ips_shift_controllers(int lowindex, int highindex) -{ - ips_ha_t *ha_sav = ips_ha[highindex]; - struct Scsi_Host *sh_sav = ips_sh[highindex]; - int i; - - for (i = highindex; i > lowindex; i--) { - ips_ha[i] = ips_ha[i - 1]; - ips_sh[i] = ips_sh[i - 1]; - ips_ha[i]->host_num = i; - } - ha_sav->host_num = lowindex; - ips_ha[lowindex] = ha_sav; - ips_sh[lowindex] = sh_sav; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_order_controllers */ -/* */ -/* Routine Description: */ -/* place controllers is the "proper" boot order */ -/****************************************************************************/ -static void -ips_order_controllers(void) -{ - int i, j, tmp, position = 0; - IPS_NVRAM_P5 *nvram; - if (!ips_ha[0]) - return; - nvram = ips_ha[0]->nvram; - - if (nvram->adapter_order[0]) { - for (i = 1; i <= nvram->adapter_order[0]; i++) { - for (j = position; j < ips_num_controllers; j++) { - switch (ips_ha[j]->ad_type) { - case IPS_ADTYPE_SERVERAID6M: - case IPS_ADTYPE_SERVERAID7M: - if (nvram->adapter_order[i] == 'M') { - ips_shift_controllers(position, - j); - position++; - } - break; - case IPS_ADTYPE_SERVERAID4L: - case IPS_ADTYPE_SERVERAID4M: - case IPS_ADTYPE_SERVERAID4MX: - case IPS_ADTYPE_SERVERAID4LX: - if (nvram->adapter_order[i] == 'N') { - ips_shift_controllers(position, - j); - position++; - } - break; - case IPS_ADTYPE_SERVERAID6I: - case IPS_ADTYPE_SERVERAID5I2: - case IPS_ADTYPE_SERVERAID5I1: - case IPS_ADTYPE_SERVERAID7k: - if (nvram->adapter_order[i] == 'S') { - ips_shift_controllers(position, - j); - position++; - } - break; - case IPS_ADTYPE_SERVERAID: - case IPS_ADTYPE_SERVERAID2: - case IPS_ADTYPE_NAVAJO: - case IPS_ADTYPE_KIOWA: - case IPS_ADTYPE_SERVERAID3L: - case IPS_ADTYPE_SERVERAID3: - case IPS_ADTYPE_SERVERAID4H: - if (nvram->adapter_order[i] == 'A') { - ips_shift_controllers(position, - j); - position++; - } - break; - default: - break; - } - } - } - /* if adapter_order[0], then ordering is complete */ - return; - } - /* old bios, use older ordering */ - tmp = 0; - for (i = position; i < ips_num_controllers; i++) { - if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 || - ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) { - ips_shift_controllers(position, i); - position++; - tmp = 1; - } - } - /* if there were no 5I cards, then don't do any extra ordering */ - if (!tmp) - return; - for (i = position; i < ips_num_controllers; i++) { - if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L || - ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M || - ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX || - ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) { - ips_shift_controllers(position, i); - position++; - } - } - - return; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_register_scsi */ -/* */ -/* Routine Description: */ -/* perform any registration and setup with the scsi layer */ -/****************************************************************************/ -static int -ips_register_scsi(int index) -{ - struct Scsi_Host *sh; - ips_ha_t *ha, *oldha = ips_ha[index]; - sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t)); - if (!sh) { - IPS_PRINTK(KERN_WARNING, oldha->pcidev, - "Unable to register controller with SCSI subsystem\n"); - return -1; - } - ha = IPS_HA(sh); - memcpy(ha, oldha, sizeof (ips_ha_t)); - free_irq(oldha->pcidev->irq, oldha); - /* Install the interrupt handler with the new ha */ - if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Unable to install interrupt handler\n"); - goto err_out_sh; - } - - kfree(oldha); - - /* Store away needed values for later use */ - sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr; - sh->sg_tablesize = sh->hostt->sg_tablesize; - sh->can_queue = sh->hostt->can_queue; - sh->cmd_per_lun = sh->hostt->cmd_per_lun; - sh->use_clustering = sh->hostt->use_clustering; - sh->max_sectors = 128; - - sh->max_id = ha->ntargets; - sh->max_lun = ha->nlun; - sh->max_channel = ha->nbus - 1; - sh->can_queue = ha->max_cmds - 1; - - if (scsi_add_host(sh, &ha->pcidev->dev)) - goto err_out; - - ips_sh[index] = sh; - ips_ha[index] = ha; - - scsi_scan_host(sh); - - return 0; - -err_out: - free_irq(ha->pcidev->irq, ha); -err_out_sh: - scsi_host_put(sh); - return -1; -} - -/*---------------------------------------------------------------------------*/ -/* Routine Name: ips_remove_device */ -/* */ -/* Routine Description: */ -/* Remove one Adapter ( Hot Plugging ) */ -/*---------------------------------------------------------------------------*/ -static void __devexit -ips_remove_device(struct pci_dev *pci_dev) -{ - struct Scsi_Host *sh = pci_get_drvdata(pci_dev); - - pci_set_drvdata(pci_dev, NULL); - - ips_release(sh); - - pci_release_regions(pci_dev); - pci_disable_device(pci_dev); -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_module_init */ -/* */ -/* Routine Description: */ -/* function called on module load */ -/****************************************************************************/ -static int __init -ips_module_init(void) -{ - if (pci_register_driver(&ips_pci_driver) < 0) - return -ENODEV; - ips_driver_template.module = THIS_MODULE; - ips_order_controllers(); - if (!ips_detect(&ips_driver_template)) { - pci_unregister_driver(&ips_pci_driver); - return -ENODEV; - } - register_reboot_notifier(&ips_notifier); - return 0; -} - -/****************************************************************************/ -/* */ -/* Routine Name: ips_module_exit */ -/* */ -/* Routine Description: */ -/* function called on module unload */ -/****************************************************************************/ -static void __exit -ips_module_exit(void) -{ - pci_unregister_driver(&ips_pci_driver); - unregister_reboot_notifier(&ips_notifier); -} - -module_init(ips_module_init); -module_exit(ips_module_exit); - -/*---------------------------------------------------------------------------*/ -/* Routine Name: ips_insert_device */ -/* */ -/* Routine Description: */ -/* Add One Adapter ( Hot Plug ) */ -/* */ -/* Return Value: */ -/* 0 if Successful, else non-zero */ -/*---------------------------------------------------------------------------*/ -static int __devinit -ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent) -{ - int index = -1; - int rc; - - METHOD_TRACE("ips_insert_device", 1); - rc = pci_enable_device(pci_dev); - if (rc) - return rc; - - rc = pci_request_regions(pci_dev, "ips"); - if (rc) - goto err_out; - - rc = ips_init_phase1(pci_dev, &index); - if (rc == SUCCESS) - rc = ips_init_phase2(index); - - if (ips_hotplug) - if (ips_register_scsi(index)) { - ips_free(ips_ha[index]); - rc = -1; - } - - if (rc == SUCCESS) - ips_num_controllers++; - - ips_next_controller = ips_num_controllers; - - if (rc < 0) { - rc = -ENODEV; - goto err_out_regions; - } - - pci_set_drvdata(pci_dev, ips_sh[index]); - return 0; - -err_out_regions: - pci_release_regions(pci_dev); -err_out: - pci_disable_device(pci_dev); - return rc; -} - -/*---------------------------------------------------------------------------*/ -/* Routine Name: ips_init_phase1 */ -/* */ -/* Routine Description: */ -/* Adapter Initialization */ -/* */ -/* Return Value: */ -/* 0 if Successful, else non-zero */ -/*---------------------------------------------------------------------------*/ -static int -ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr) -{ - ips_ha_t *ha; - uint32_t io_addr; - uint32_t mem_addr; - uint32_t io_len; - uint32_t mem_len; - uint8_t bus; - uint8_t func; - int j; - int index; - dma_addr_t dma_address; - char __iomem *ioremap_ptr; - char __iomem *mem_ptr; - uint32_t IsDead; - - METHOD_TRACE("ips_init_phase1", 1); - index = IPS_MAX_ADAPTERS; - for (j = 0; j < IPS_MAX_ADAPTERS; j++) { - if (ips_ha[j] == NULL) { - index = j; - break; - } - } - - if (index >= IPS_MAX_ADAPTERS) - return -1; - - /* stuff that we get in dev */ - bus = pci_dev->bus->number; - func = pci_dev->devfn; - - /* Init MEM/IO addresses to 0 */ - mem_addr = 0; - io_addr = 0; - mem_len = 0; - io_len = 0; - - for (j = 0; j < 2; j++) { - if (!pci_resource_start(pci_dev, j)) - break; - - if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) { - io_addr = pci_resource_start(pci_dev, j); - io_len = pci_resource_len(pci_dev, j); - } else { - mem_addr = pci_resource_start(pci_dev, j); - mem_len = pci_resource_len(pci_dev, j); - } - } - - /* setup memory mapped area (if applicable) */ - if (mem_addr) { - uint32_t base; - uint32_t offs; - - base = mem_addr & PAGE_MASK; - offs = mem_addr - base; - ioremap_ptr = ioremap(base, PAGE_SIZE); - if (!ioremap_ptr) - return -1; - mem_ptr = ioremap_ptr + offs; - } else { - ioremap_ptr = NULL; - mem_ptr = NULL; - } - - /* found a controller */ - ha = kzalloc(sizeof (ips_ha_t), GFP_KERNEL); - if (ha == NULL) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to allocate temporary ha struct\n"); - return -1; - } - - ips_sh[index] = NULL; - ips_ha[index] = ha; - ha->active = 1; - - /* Store info in HA structure */ - ha->io_addr = io_addr; - ha->io_len = io_len; - ha->mem_addr = mem_addr; - ha->mem_len = mem_len; - ha->mem_ptr = mem_ptr; - ha->ioremap_ptr = ioremap_ptr; - ha->host_num = (uint32_t) index; - ha->slot_num = PCI_SLOT(pci_dev->devfn); - ha->pcidev = pci_dev; - - /* - * Set the pci_dev's dma_mask. Not all adapters support 64bit - * addressing so don't enable it if the adapter can't support - * it! Also, don't use 64bit addressing if dma addresses - * are guaranteed to be < 4G. - */ - if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) && - !pci_set_dma_mask(ha->pcidev, DMA_BIT_MASK(64))) { - (ha)->flags |= IPS_HA_ENH_SG; - } else { - if (pci_set_dma_mask(ha->pcidev, DMA_BIT_MASK(32)) != 0) { - printk(KERN_WARNING "Unable to set DMA Mask\n"); - return ips_abort_init(ha, index); - } - } - if(ips_cd_boot && !ips_FlashData){ - ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7, - &ips_flashbusaddr); - } - - ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ), - &ha->enq_busaddr); - if (!ha->enq) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to allocate host inquiry structure\n"); - return ips_abort_init(ha, index); - } - - ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) + - sizeof (IPS_IO_CMD), &dma_address); - if (!ha->adapt) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to allocate host adapt & dummy structures\n"); - return ips_abort_init(ha, index); - } - ha->adapt->hw_status_start = dma_address; - ha->dummy = (void *) (ha->adapt + 1); - - - - ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address); - if (!ha->logical_drive_info) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to allocate logical drive info structure\n"); - return ips_abort_init(ha, index); - } - ha->logical_drive_info_dma_addr = dma_address; - - - ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL); - - if (!ha->conf) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to allocate host conf structure\n"); - return ips_abort_init(ha, index); - } - - ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL); - - if (!ha->nvram) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to allocate host NVRAM structure\n"); - return ips_abort_init(ha, index); - } - - ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL); - - if (!ha->subsys) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to allocate host subsystem structure\n"); - return ips_abort_init(ha, index); - } - - /* the ioctl buffer is now used during adapter initialization, so its - * successful allocation is now required */ - if (ips_ioctlsize < PAGE_SIZE) - ips_ioctlsize = PAGE_SIZE; - - ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize, - &ha->ioctl_busaddr); - ha->ioctl_len = ips_ioctlsize; - if (!ha->ioctl_data) { - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to allocate IOCTL data\n"); - return ips_abort_init(ha, index); - } - - /* - * Setup Functions - */ - ips_setup_funclist(ha); - - if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) { - /* If Morpheus appears dead, reset it */ - IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1); - if (IsDead == 0xDEADBEEF) { - ips_reset_morpheus(ha); - } - } - - /* - * Initialize the card if it isn't already - */ - - if (!(*ha->func.isinit) (ha)) { - if (!(*ha->func.init) (ha)) { - /* - * Initialization failed - */ - IPS_PRINTK(KERN_WARNING, pci_dev, - "Unable to initialize controller\n"); - return ips_abort_init(ha, index); - } - } - - *indexPtr = index; - return SUCCESS; -} - -/*---------------------------------------------------------------------------*/ -/* Routine Name: ips_init_phase2 */ -/* */ -/* Routine Description: */ -/* Adapter Initialization Phase 2 */ -/* */ -/* Return Value: */ -/* 0 if Successful, else non-zero */ -/*---------------------------------------------------------------------------*/ -static int -ips_init_phase2(int index) -{ - ips_ha_t *ha; - - ha = ips_ha[index]; - - METHOD_TRACE("ips_init_phase2", 1); - if (!ha->active) { - ips_ha[index] = NULL; - return -1; - } - - /* Install the interrupt handler */ - if (request_irq(ha->pcidev->irq, do_ipsintr, IRQF_SHARED, ips_name, ha)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Unable to install interrupt handler\n"); - return ips_abort_init(ha, index); - } - - /* - * Allocate a temporary SCB for initialization - */ - ha->max_cmds = 1; - if (!ips_allocatescbs(ha)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Unable to allocate a CCB\n"); - free_irq(ha->pcidev->irq, ha); - return ips_abort_init(ha, index); - } - - if (!ips_hainit(ha)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Unable to initialize controller\n"); - free_irq(ha->pcidev->irq, ha); - return ips_abort_init(ha, index); - } - /* Free the temporary SCB */ - ips_deallocatescbs(ha, 1); - - /* allocate CCBs */ - if (!ips_allocatescbs(ha)) { - IPS_PRINTK(KERN_WARNING, ha->pcidev, - "Unable to allocate CCBs\n"); - free_irq(ha->pcidev->irq, ha); - return ips_abort_init(ha, index); - } - - return SUCCESS; -} - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING); -MODULE_VERSION(IPS_VER_STRING); - - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/ANDROID_3.4.5/drivers/scsi/ips.h b/ANDROID_3.4.5/drivers/scsi/ips.h deleted file mode 100644 index f2df0593..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ips.h +++ /dev/null @@ -1,1260 +0,0 @@ -/*****************************************************************************/ -/* ips.h -- driver for the Adaptec / IBM ServeRAID controller */ -/* */ -/* Written By: Keith Mitchell, IBM Corporation */ -/* Jack Hammer, Adaptec, Inc. */ -/* David Jeffery, Adaptec, Inc. */ -/* */ -/* Copyright (C) 1999 IBM Corporation */ -/* Copyright (C) 2003 Adaptec, Inc. */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ -/* GNU General Public License for more details. */ -/* */ -/* NO WARRANTY */ -/* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR */ -/* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT */ -/* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, */ -/* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is */ -/* solely responsible for determining the appropriateness of using and */ -/* distributing the Program and assumes all risks associated with its */ -/* exercise of rights under this Agreement, including but not limited to */ -/* the risks and costs of program errors, damage to or loss of data, */ -/* programs or equipment, and unavailability or interruption of operations. */ -/* */ -/* DISCLAIMER OF LIABILITY */ -/* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY */ -/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */ -/* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND */ -/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR */ -/* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE */ -/* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED */ -/* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* */ -/* Bugs/Comments/Suggestions should be mailed to: */ -/* ipslinux@adaptec.com */ -/* */ -/*****************************************************************************/ - -#ifndef _IPS_H_ - #define _IPS_H_ - -#include - #include - #include - - /* - * Some handy macros - */ - #define IPS_HA(x) ((ips_ha_t *) x->hostdata) - #define IPS_COMMAND_ID(ha, scb) (int) (scb - ha->scbs) - #define IPS_IS_TROMBONE(ha) (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \ - (ha->pcidev->revision >= IPS_REVID_TROMBONE32) && \ - (ha->pcidev->revision <= IPS_REVID_TROMBONE64)) ? 1 : 0) - #define IPS_IS_CLARINET(ha) (((ha->pcidev->device == IPS_DEVICEID_COPPERHEAD) && \ - (ha->pcidev->revision >= IPS_REVID_CLARINETP1) && \ - (ha->pcidev->revision <= IPS_REVID_CLARINETP3)) ? 1 : 0) - #define IPS_IS_MORPHEUS(ha) (ha->pcidev->device == IPS_DEVICEID_MORPHEUS) - #define IPS_IS_MARCO(ha) (ha->pcidev->device == IPS_DEVICEID_MARCO) - #define IPS_USE_I2O_DELIVER(ha) ((IPS_IS_MORPHEUS(ha) || \ - (IPS_IS_TROMBONE(ha) && \ - (ips_force_i2o))) ? 1 : 0) - #define IPS_USE_MEMIO(ha) ((IPS_IS_MORPHEUS(ha) || \ - ((IPS_IS_TROMBONE(ha) || IPS_IS_CLARINET(ha)) && \ - (ips_force_memio))) ? 1 : 0) - - #define IPS_HAS_ENH_SGLIST(ha) (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) - #define IPS_USE_ENH_SGLIST(ha) ((ha)->flags & IPS_HA_ENH_SG) - #define IPS_SGLIST_SIZE(ha) (IPS_USE_ENH_SGLIST(ha) ? \ - sizeof(IPS_ENH_SG_LIST) : sizeof(IPS_STD_SG_LIST)) - - #define IPS_PRINTK(level, pcidev, format, arg...) \ - dev_printk(level , &((pcidev)->dev) , format , ## arg) - - #define MDELAY(n) \ - do { \ - mdelay(n); \ - touch_nmi_watchdog(); \ - } while (0) - - #ifndef min - #define min(x,y) ((x) < (y) ? x : y) - #endif - - #ifndef __iomem /* For clean compiles in earlier kernels without __iomem annotations */ - #define __iomem - #endif - - #define pci_dma_hi32(a) ((a >> 16) >> 16) - #define pci_dma_lo32(a) (a & 0xffffffff) - - #if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G) - #define IPS_ENABLE_DMA64 (1) - #else - #define IPS_ENABLE_DMA64 (0) - #endif - - /* - * Adapter address map equates - */ - #define IPS_REG_HISR 0x08 /* Host Interrupt Status Reg */ - #define IPS_REG_CCSAR 0x10 /* Cmd Channel System Addr Reg */ - #define IPS_REG_CCCR 0x14 /* Cmd Channel Control Reg */ - #define IPS_REG_SQHR 0x20 /* Status Q Head Reg */ - #define IPS_REG_SQTR 0x24 /* Status Q Tail Reg */ - #define IPS_REG_SQER 0x28 /* Status Q End Reg */ - #define IPS_REG_SQSR 0x2C /* Status Q Start Reg */ - #define IPS_REG_SCPR 0x05 /* Subsystem control port reg */ - #define IPS_REG_ISPR 0x06 /* interrupt status port reg */ - #define IPS_REG_CBSP 0x07 /* CBSP register */ - #define IPS_REG_FLAP 0x18 /* Flash address port */ - #define IPS_REG_FLDP 0x1C /* Flash data port */ - #define IPS_REG_NDAE 0x38 /* Anaconda 64 NDAE Register */ - #define IPS_REG_I2O_INMSGQ 0x40 /* I2O Inbound Message Queue */ - #define IPS_REG_I2O_OUTMSGQ 0x44 /* I2O Outbound Message Queue */ - #define IPS_REG_I2O_HIR 0x30 /* I2O Interrupt Status */ - #define IPS_REG_I960_IDR 0x20 /* i960 Inbound Doorbell */ - #define IPS_REG_I960_MSG0 0x18 /* i960 Outbound Reg 0 */ - #define IPS_REG_I960_MSG1 0x1C /* i960 Outbound Reg 1 */ - #define IPS_REG_I960_OIMR 0x34 /* i960 Oubound Int Mask Reg */ - - /* - * Adapter register bit equates - */ - #define IPS_BIT_GHI 0x04 /* HISR General Host Interrupt */ - #define IPS_BIT_SQO 0x02 /* HISR Status Q Overflow */ - #define IPS_BIT_SCE 0x01 /* HISR Status Channel Enqueue */ - #define IPS_BIT_SEM 0x08 /* CCCR Semaphore Bit */ - #define IPS_BIT_ILE 0x10 /* CCCR ILE Bit */ - #define IPS_BIT_START_CMD 0x101A /* CCCR Start Command Channel */ - #define IPS_BIT_START_STOP 0x0002 /* CCCR Start/Stop Bit */ - #define IPS_BIT_RST 0x80 /* SCPR Reset Bit */ - #define IPS_BIT_EBM 0x02 /* SCPR Enable Bus Master */ - #define IPS_BIT_EI 0x80 /* HISR Enable Interrupts */ - #define IPS_BIT_OP 0x01 /* OP bit in CBSP */ - #define IPS_BIT_I2O_OPQI 0x08 /* General Host Interrupt */ - #define IPS_BIT_I960_MSG0I 0x01 /* Message Register 0 Interrupt*/ - #define IPS_BIT_I960_MSG1I 0x02 /* Message Register 1 Interrupt*/ - - /* - * Adapter Command ID Equates - */ - #define IPS_CMD_GET_LD_INFO 0x19 - #define IPS_CMD_GET_SUBSYS 0x40 - #define IPS_CMD_READ_CONF 0x38 - #define IPS_CMD_RW_NVRAM_PAGE 0xBC - #define IPS_CMD_READ 0x02 - #define IPS_CMD_WRITE 0x03 - #define IPS_CMD_FFDC 0xD7 - #define IPS_CMD_ENQUIRY 0x05 - #define IPS_CMD_FLUSH 0x0A - #define IPS_CMD_READ_SG 0x82 - #define IPS_CMD_WRITE_SG 0x83 - #define IPS_CMD_DCDB 0x04 - #define IPS_CMD_DCDB_SG 0x84 - #define IPS_CMD_EXTENDED_DCDB 0x95 - #define IPS_CMD_EXTENDED_DCDB_SG 0x96 - #define IPS_CMD_CONFIG_SYNC 0x58 - #define IPS_CMD_ERROR_TABLE 0x17 - #define IPS_CMD_DOWNLOAD 0x20 - #define IPS_CMD_RW_BIOSFW 0x22 - #define IPS_CMD_GET_VERSION_INFO 0xC6 - #define IPS_CMD_RESET_CHANNEL 0x1A - - /* - * Adapter Equates - */ - #define IPS_CSL 0xFF - #define IPS_POCL 0x30 - #define IPS_NORM_STATE 0x00 - #define IPS_MAX_ADAPTER_TYPES 3 - #define IPS_MAX_ADAPTERS 16 - #define IPS_MAX_IOCTL 1 - #define IPS_MAX_IOCTL_QUEUE 8 - #define IPS_MAX_QUEUE 128 - #define IPS_BLKSIZE 512 - #define IPS_MAX_SG 17 - #define IPS_MAX_LD 8 - #define IPS_MAX_CHANNELS 4 - #define IPS_MAX_TARGETS 15 - #define IPS_MAX_CHUNKS 16 - #define IPS_MAX_CMDS 128 - #define IPS_MAX_XFER 0x10000 - #define IPS_NVRAM_P5_SIG 0xFFDDBB99 - #define IPS_MAX_POST_BYTES 0x02 - #define IPS_MAX_CONFIG_BYTES 0x02 - #define IPS_GOOD_POST_STATUS 0x80 - #define IPS_SEM_TIMEOUT 2000 - #define IPS_IOCTL_COMMAND 0x0D - #define IPS_INTR_ON 0 - #define IPS_INTR_IORL 1 - #define IPS_FFDC 99 - #define IPS_ADAPTER_ID 0xF - #define IPS_VENDORID_IBM 0x1014 - #define IPS_VENDORID_ADAPTEC 0x9005 - #define IPS_DEVICEID_COPPERHEAD 0x002E - #define IPS_DEVICEID_MORPHEUS 0x01BD - #define IPS_DEVICEID_MARCO 0x0250 - #define IPS_SUBDEVICEID_4M 0x01BE - #define IPS_SUBDEVICEID_4L 0x01BF - #define IPS_SUBDEVICEID_4MX 0x0208 - #define IPS_SUBDEVICEID_4LX 0x020E - #define IPS_SUBDEVICEID_5I2 0x0259 - #define IPS_SUBDEVICEID_5I1 0x0258 - #define IPS_SUBDEVICEID_6M 0x0279 - #define IPS_SUBDEVICEID_6I 0x028C - #define IPS_SUBDEVICEID_7k 0x028E - #define IPS_SUBDEVICEID_7M 0x028F - #define IPS_IOCTL_SIZE 8192 - #define IPS_STATUS_SIZE 4 - #define IPS_STATUS_Q_SIZE (IPS_MAX_CMDS+1) * IPS_STATUS_SIZE - #define IPS_IMAGE_SIZE 500 * 1024 - #define IPS_MEMMAP_SIZE 128 - #define IPS_ONE_MSEC 1 - #define IPS_ONE_SEC 1000 - - /* - * Geometry Settings - */ - #define IPS_COMP_HEADS 128 - #define IPS_COMP_SECTORS 32 - #define IPS_NORM_HEADS 254 - #define IPS_NORM_SECTORS 63 - - /* - * Adapter Basic Status Codes - */ - #define IPS_BASIC_STATUS_MASK 0xFF - #define IPS_GSC_STATUS_MASK 0x0F - #define IPS_CMD_SUCCESS 0x00 - #define IPS_CMD_RECOVERED_ERROR 0x01 - #define IPS_INVAL_OPCO 0x03 - #define IPS_INVAL_CMD_BLK 0x04 - #define IPS_INVAL_PARM_BLK 0x05 - #define IPS_BUSY 0x08 - #define IPS_CMD_CMPLT_WERROR 0x0C - #define IPS_LD_ERROR 0x0D - #define IPS_CMD_TIMEOUT 0x0E - #define IPS_PHYS_DRV_ERROR 0x0F - - /* - * Adapter Extended Status Equates - */ - #define IPS_ERR_SEL_TO 0xF0 - #define IPS_ERR_OU_RUN 0xF2 - #define IPS_ERR_HOST_RESET 0xF7 - #define IPS_ERR_DEV_RESET 0xF8 - #define IPS_ERR_RECOVERY 0xFC - #define IPS_ERR_CKCOND 0xFF - - /* - * Operating System Defines - */ - #define IPS_OS_WINDOWS_NT 0x01 - #define IPS_OS_NETWARE 0x02 - #define IPS_OS_OPENSERVER 0x03 - #define IPS_OS_UNIXWARE 0x04 - #define IPS_OS_SOLARIS 0x05 - #define IPS_OS_OS2 0x06 - #define IPS_OS_LINUX 0x07 - #define IPS_OS_FREEBSD 0x08 - - /* - * Adapter Revision ID's - */ - #define IPS_REVID_SERVERAID 0x02 - #define IPS_REVID_NAVAJO 0x03 - #define IPS_REVID_SERVERAID2 0x04 - #define IPS_REVID_CLARINETP1 0x05 - #define IPS_REVID_CLARINETP2 0x07 - #define IPS_REVID_CLARINETP3 0x0D - #define IPS_REVID_TROMBONE32 0x0F - #define IPS_REVID_TROMBONE64 0x10 - - /* - * NVRAM Page 5 Adapter Defines - */ - #define IPS_ADTYPE_SERVERAID 0x01 - #define IPS_ADTYPE_SERVERAID2 0x02 - #define IPS_ADTYPE_NAVAJO 0x03 - #define IPS_ADTYPE_KIOWA 0x04 - #define IPS_ADTYPE_SERVERAID3 0x05 - #define IPS_ADTYPE_SERVERAID3L 0x06 - #define IPS_ADTYPE_SERVERAID4H 0x07 - #define IPS_ADTYPE_SERVERAID4M 0x08 - #define IPS_ADTYPE_SERVERAID4L 0x09 - #define IPS_ADTYPE_SERVERAID4MX 0x0A - #define IPS_ADTYPE_SERVERAID4LX 0x0B - #define IPS_ADTYPE_SERVERAID5I2 0x0C - #define IPS_ADTYPE_SERVERAID5I1 0x0D - #define IPS_ADTYPE_SERVERAID6M 0x0E - #define IPS_ADTYPE_SERVERAID6I 0x0F - #define IPS_ADTYPE_SERVERAID7t 0x10 - #define IPS_ADTYPE_SERVERAID7k 0x11 - #define IPS_ADTYPE_SERVERAID7M 0x12 - - /* - * Adapter Command/Status Packet Definitions - */ - #define IPS_SUCCESS 0x01 /* Successfully completed */ - #define IPS_SUCCESS_IMM 0x02 /* Success - Immediately */ - #define IPS_FAILURE 0x04 /* Completed with Error */ - - /* - * Logical Drive Equates - */ - #define IPS_LD_OFFLINE 0x02 - #define IPS_LD_OKAY 0x03 - #define IPS_LD_FREE 0x00 - #define IPS_LD_SYS 0x06 - #define IPS_LD_CRS 0x24 - - /* - * DCDB Table Equates - */ - #define IPS_NO_DISCONNECT 0x00 - #define IPS_DISCONNECT_ALLOWED 0x80 - #define IPS_NO_AUTO_REQSEN 0x40 - #define IPS_DATA_NONE 0x00 - #define IPS_DATA_UNK 0x00 - #define IPS_DATA_IN 0x01 - #define IPS_DATA_OUT 0x02 - #define IPS_TRANSFER64K 0x08 - #define IPS_NOTIMEOUT 0x00 - #define IPS_TIMEOUT10 0x10 - #define IPS_TIMEOUT60 0x20 - #define IPS_TIMEOUT20M 0x30 - - /* - * SCSI Inquiry Data Flags - */ - #define IPS_SCSI_INQ_TYPE_DASD 0x00 - #define IPS_SCSI_INQ_TYPE_PROCESSOR 0x03 - #define IPS_SCSI_INQ_LU_CONNECTED 0x00 - #define IPS_SCSI_INQ_RD_REV2 0x02 - #define IPS_SCSI_INQ_REV2 0x02 - #define IPS_SCSI_INQ_REV3 0x03 - #define IPS_SCSI_INQ_Address16 0x01 - #define IPS_SCSI_INQ_Address32 0x02 - #define IPS_SCSI_INQ_MedChanger 0x08 - #define IPS_SCSI_INQ_MultiPort 0x10 - #define IPS_SCSI_INQ_EncServ 0x40 - #define IPS_SCSI_INQ_SoftReset 0x01 - #define IPS_SCSI_INQ_CmdQue 0x02 - #define IPS_SCSI_INQ_Linked 0x08 - #define IPS_SCSI_INQ_Sync 0x10 - #define IPS_SCSI_INQ_WBus16 0x20 - #define IPS_SCSI_INQ_WBus32 0x40 - #define IPS_SCSI_INQ_RelAdr 0x80 - - /* - * SCSI Request Sense Data Flags - */ - #define IPS_SCSI_REQSEN_VALID 0x80 - #define IPS_SCSI_REQSEN_CURRENT_ERR 0x70 - #define IPS_SCSI_REQSEN_NO_SENSE 0x00 - - /* - * SCSI Mode Page Equates - */ - #define IPS_SCSI_MP3_SoftSector 0x01 - #define IPS_SCSI_MP3_HardSector 0x02 - #define IPS_SCSI_MP3_Removeable 0x04 - #define IPS_SCSI_MP3_AllocateSurface 0x08 - - /* - * HA Flags - */ - - #define IPS_HA_ENH_SG 0x1 - - /* - * SCB Flags - */ - #define IPS_SCB_MAP_SG 0x00008 - #define IPS_SCB_MAP_SINGLE 0X00010 - - /* - * Passthru stuff - */ - #define IPS_COPPUSRCMD (('C'<<8) | 65) - #define IPS_COPPIOCCMD (('C'<<8) | 66) - #define IPS_NUMCTRLS (('C'<<8) | 68) - #define IPS_CTRLINFO (('C'<<8) | 69) - - /* flashing defines */ - #define IPS_FW_IMAGE 0x00 - #define IPS_BIOS_IMAGE 0x01 - #define IPS_WRITE_FW 0x01 - #define IPS_WRITE_BIOS 0x02 - #define IPS_ERASE_BIOS 0x03 - #define IPS_BIOS_HEADER 0xC0 - - /* time oriented stuff */ - #define IPS_IS_LEAP_YEAR(y) (((y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0))) ? 1 : 0) - #define IPS_NUM_LEAP_YEARS_THROUGH(y) ((y) / 4 - (y) / 100 + (y) / 400) - - #define IPS_SECS_MIN 60 - #define IPS_SECS_HOUR 3600 - #define IPS_SECS_8HOURS 28800 - #define IPS_SECS_DAY 86400 - #define IPS_DAYS_NORMAL_YEAR 365 - #define IPS_DAYS_LEAP_YEAR 366 - #define IPS_EPOCH_YEAR 1970 - - /* - * Scsi_Host Template - */ - static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); - static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]); - static int ips_slave_configure(struct scsi_device *SDptr); - -/* - * Raid Command Formats - */ -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t log_drv; - uint8_t sg_count; - uint32_t lba; - uint32_t sg_addr; - uint16_t sector_count; - uint8_t segment_4G; - uint8_t enhanced_sg; - uint32_t ccsar; - uint32_t cccr; -} IPS_IO_CMD, *PIPS_IO_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint16_t reserved; - uint32_t reserved2; - uint32_t buffer_addr; - uint32_t reserved3; - uint32_t ccsar; - uint32_t cccr; -} IPS_LD_CMD, *PIPS_LD_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t reserved; - uint8_t reserved2; - uint32_t reserved3; - uint32_t buffer_addr; - uint32_t reserved4; -} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t channel; - uint8_t reserved3; - uint8_t reserved4; - uint8_t reserved5; - uint8_t reserved6; - uint8_t reserved7; - uint8_t reserved8; - uint8_t reserved9; - uint8_t reserved10; - uint8_t reserved11; - uint8_t reserved12; - uint8_t reserved13; - uint8_t reserved14; - uint8_t adapter_flag; -} IPS_RESET_CMD, *PIPS_RESET_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint16_t reserved; - uint32_t reserved2; - uint32_t dcdb_address; - uint16_t reserved3; - uint8_t segment_4G; - uint8_t enhanced_sg; - uint32_t ccsar; - uint32_t cccr; -} IPS_DCDB_CMD, *PIPS_DCDB_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t channel; - uint8_t source_target; - uint32_t reserved; - uint32_t reserved2; - uint32_t reserved3; - uint32_t ccsar; - uint32_t cccr; -} IPS_CS_CMD, *PIPS_CS_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t log_drv; - uint8_t control; - uint32_t reserved; - uint32_t reserved2; - uint32_t reserved3; - uint32_t ccsar; - uint32_t cccr; -} IPS_US_CMD, *PIPS_US_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t reserved; - uint8_t state; - uint32_t reserved2; - uint32_t reserved3; - uint32_t reserved4; - uint32_t ccsar; - uint32_t cccr; -} IPS_FC_CMD, *PIPS_FC_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t reserved; - uint8_t desc; - uint32_t reserved2; - uint32_t buffer_addr; - uint32_t reserved3; - uint32_t ccsar; - uint32_t cccr; -} IPS_STATUS_CMD, *PIPS_STATUS_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t page; - uint8_t write; - uint32_t reserved; - uint32_t buffer_addr; - uint32_t reserved2; - uint32_t ccsar; - uint32_t cccr; -} IPS_NVRAM_CMD, *PIPS_NVRAM_CMD; - -typedef struct -{ - uint8_t op_code; - uint8_t command_id; - uint16_t reserved; - uint32_t count; - uint32_t buffer_addr; - uint32_t reserved2; -} IPS_VERSION_INFO, *PIPS_VERSION_INFO; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t reset_count; - uint8_t reset_type; - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t day; - uint8_t reserved1[4]; - uint8_t month; - uint8_t yearH; - uint8_t yearL; - uint8_t reserved2; -} IPS_FFDC_CMD, *PIPS_FFDC_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t type; - uint8_t direction; - uint32_t count; - uint32_t buffer_addr; - uint8_t total_packets; - uint8_t packet_num; - uint16_t reserved; -} IPS_FLASHFW_CMD, *PIPS_FLASHFW_CMD; - -typedef struct { - uint8_t op_code; - uint8_t command_id; - uint8_t type; - uint8_t direction; - uint32_t count; - uint32_t buffer_addr; - uint32_t offset; -} IPS_FLASHBIOS_CMD, *PIPS_FLASHBIOS_CMD; - -typedef union { - IPS_IO_CMD basic_io; - IPS_LD_CMD logical_info; - IPS_IOCTL_CMD ioctl_info; - IPS_DCDB_CMD dcdb; - IPS_CS_CMD config_sync; - IPS_US_CMD unlock_stripe; - IPS_FC_CMD flush_cache; - IPS_STATUS_CMD status; - IPS_NVRAM_CMD nvram; - IPS_FFDC_CMD ffdc; - IPS_FLASHFW_CMD flashfw; - IPS_FLASHBIOS_CMD flashbios; - IPS_VERSION_INFO version_info; - IPS_RESET_CMD reset; -} IPS_HOST_COMMAND, *PIPS_HOST_COMMAND; - -typedef struct { - uint8_t logical_id; - uint8_t reserved; - uint8_t raid_level; - uint8_t state; - uint32_t sector_count; -} IPS_DRIVE_INFO, *PIPS_DRIVE_INFO; - -typedef struct { - uint8_t no_of_log_drive; - uint8_t reserved[3]; - IPS_DRIVE_INFO drive_info[IPS_MAX_LD]; -} IPS_LD_INFO, *PIPS_LD_INFO; - -typedef struct { - uint8_t device_address; - uint8_t cmd_attribute; - uint16_t transfer_length; - uint32_t buffer_pointer; - uint8_t cdb_length; - uint8_t sense_length; - uint8_t sg_count; - uint8_t reserved; - uint8_t scsi_cdb[12]; - uint8_t sense_info[64]; - uint8_t scsi_status; - uint8_t reserved2[3]; -} IPS_DCDB_TABLE, *PIPS_DCDB_TABLE; - -typedef struct { - uint8_t device_address; - uint8_t cmd_attribute; - uint8_t cdb_length; - uint8_t reserved_for_LUN; - uint32_t transfer_length; - uint32_t buffer_pointer; - uint16_t sg_count; - uint8_t sense_length; - uint8_t scsi_status; - uint32_t reserved; - uint8_t scsi_cdb[16]; - uint8_t sense_info[56]; -} IPS_DCDB_TABLE_TAPE, *PIPS_DCDB_TABLE_TAPE; - -typedef union { - struct { - volatile uint8_t reserved; - volatile uint8_t command_id; - volatile uint8_t basic_status; - volatile uint8_t extended_status; - } fields; - - volatile uint32_t value; -} IPS_STATUS, *PIPS_STATUS; - -typedef struct { - IPS_STATUS status[IPS_MAX_CMDS + 1]; - volatile PIPS_STATUS p_status_start; - volatile PIPS_STATUS p_status_end; - volatile PIPS_STATUS p_status_tail; - volatile uint32_t hw_status_start; - volatile uint32_t hw_status_tail; -} IPS_ADAPTER, *PIPS_ADAPTER; - -typedef struct { - uint8_t ucLogDriveCount; - uint8_t ucMiscFlag; - uint8_t ucSLTFlag; - uint8_t ucBSTFlag; - uint8_t ucPwrChgCnt; - uint8_t ucWrongAdrCnt; - uint8_t ucUnidentCnt; - uint8_t ucNVramDevChgCnt; - uint8_t CodeBlkVersion[8]; - uint8_t BootBlkVersion[8]; - uint32_t ulDriveSize[IPS_MAX_LD]; - uint8_t ucConcurrentCmdCount; - uint8_t ucMaxPhysicalDevices; - uint16_t usFlashRepgmCount; - uint8_t ucDefunctDiskCount; - uint8_t ucRebuildFlag; - uint8_t ucOfflineLogDrvCount; - uint8_t ucCriticalDrvCount; - uint16_t usConfigUpdateCount; - uint8_t ucBlkFlag; - uint8_t reserved; - uint16_t usAddrDeadDisk[IPS_MAX_CHANNELS * (IPS_MAX_TARGETS + 1)]; -} IPS_ENQ, *PIPS_ENQ; - -typedef struct { - uint8_t ucInitiator; - uint8_t ucParameters; - uint8_t ucMiscFlag; - uint8_t ucState; - uint32_t ulBlockCount; - uint8_t ucDeviceId[28]; -} IPS_DEVSTATE, *PIPS_DEVSTATE; - -typedef struct { - uint8_t ucChn; - uint8_t ucTgt; - uint16_t ucReserved; - uint32_t ulStartSect; - uint32_t ulNoOfSects; -} IPS_CHUNK, *PIPS_CHUNK; - -typedef struct { - uint16_t ucUserField; - uint8_t ucState; - uint8_t ucRaidCacheParam; - uint8_t ucNoOfChunkUnits; - uint8_t ucStripeSize; - uint8_t ucParams; - uint8_t ucReserved; - uint32_t ulLogDrvSize; - IPS_CHUNK chunk[IPS_MAX_CHUNKS]; -} IPS_LD, *PIPS_LD; - -typedef struct { - uint8_t board_disc[8]; - uint8_t processor[8]; - uint8_t ucNoChanType; - uint8_t ucNoHostIntType; - uint8_t ucCompression; - uint8_t ucNvramType; - uint32_t ulNvramSize; -} IPS_HARDWARE, *PIPS_HARDWARE; - -typedef struct { - uint8_t ucLogDriveCount; - uint8_t ucDateD; - uint8_t ucDateM; - uint8_t ucDateY; - uint8_t init_id[4]; - uint8_t host_id[12]; - uint8_t time_sign[8]; - uint32_t UserOpt; - uint16_t user_field; - uint8_t ucRebuildRate; - uint8_t ucReserve; - IPS_HARDWARE hardware_disc; - IPS_LD logical_drive[IPS_MAX_LD]; - IPS_DEVSTATE dev[IPS_MAX_CHANNELS][IPS_MAX_TARGETS+1]; - uint8_t reserved[512]; -} IPS_CONF, *PIPS_CONF; - -typedef struct { - uint32_t signature; - uint8_t reserved1; - uint8_t adapter_slot; - uint16_t adapter_type; - uint8_t ctrl_bios[8]; - uint8_t versioning; /* 1 = Versioning Supported, else 0 */ - uint8_t version_mismatch; /* 1 = Versioning MisMatch, else 0 */ - uint8_t reserved2; - uint8_t operating_system; - uint8_t driver_high[4]; - uint8_t driver_low[4]; - uint8_t BiosCompatibilityID[8]; - uint8_t ReservedForOS2[8]; - uint8_t bios_high[4]; /* Adapter's Flashed BIOS Version */ - uint8_t bios_low[4]; - uint8_t adapter_order[16]; /* BIOS Telling us the Sort Order */ - uint8_t Filler[60]; -} IPS_NVRAM_P5, *PIPS_NVRAM_P5; - -/*--------------------------------------------------------------------------*/ -/* Data returned from a GetVersion Command */ -/*--------------------------------------------------------------------------*/ - - /* SubSystem Parameter[4] */ -#define IPS_GET_VERSION_SUPPORT 0x00018000 /* Mask for Versioning Support */ - -typedef struct -{ - uint32_t revision; - uint8_t bootBlkVersion[32]; - uint8_t bootBlkAttributes[4]; - uint8_t codeBlkVersion[32]; - uint8_t biosVersion[32]; - uint8_t biosAttributes[4]; - uint8_t compatibilityId[32]; - uint8_t reserved[4]; -} IPS_VERSION_DATA; - - -typedef struct _IPS_SUBSYS { - uint32_t param[128]; -} IPS_SUBSYS, *PIPS_SUBSYS; - -/** - ** SCSI Structures - **/ - -/* - * Inquiry Data Format - */ -typedef struct { - uint8_t DeviceType; - uint8_t DeviceTypeQualifier; - uint8_t Version; - uint8_t ResponseDataFormat; - uint8_t AdditionalLength; - uint8_t Reserved; - uint8_t Flags[2]; - uint8_t VendorId[8]; - uint8_t ProductId[16]; - uint8_t ProductRevisionLevel[4]; - uint8_t Reserved2; /* Provides NULL terminator to name */ -} IPS_SCSI_INQ_DATA, *PIPS_SCSI_INQ_DATA; - -/* - * Read Capacity Data Format - */ -typedef struct { - uint32_t lba; - uint32_t len; -} IPS_SCSI_CAPACITY; - -/* - * Request Sense Data Format - */ -typedef struct { - uint8_t ResponseCode; - uint8_t SegmentNumber; - uint8_t Flags; - uint8_t Information[4]; - uint8_t AdditionalLength; - uint8_t CommandSpecific[4]; - uint8_t AdditionalSenseCode; - uint8_t AdditionalSenseCodeQual; - uint8_t FRUCode; - uint8_t SenseKeySpecific[3]; -} IPS_SCSI_REQSEN; - -/* - * Sense Data Format - Page 3 - */ -typedef struct { - uint8_t PageCode; - uint8_t PageLength; - uint16_t TracksPerZone; - uint16_t AltSectorsPerZone; - uint16_t AltTracksPerZone; - uint16_t AltTracksPerVolume; - uint16_t SectorsPerTrack; - uint16_t BytesPerSector; - uint16_t Interleave; - uint16_t TrackSkew; - uint16_t CylinderSkew; - uint8_t flags; - uint8_t reserved[3]; -} IPS_SCSI_MODE_PAGE3; - -/* - * Sense Data Format - Page 4 - */ -typedef struct { - uint8_t PageCode; - uint8_t PageLength; - uint16_t CylindersHigh; - uint8_t CylindersLow; - uint8_t Heads; - uint16_t WritePrecompHigh; - uint8_t WritePrecompLow; - uint16_t ReducedWriteCurrentHigh; - uint8_t ReducedWriteCurrentLow; - uint16_t StepRate; - uint16_t LandingZoneHigh; - uint8_t LandingZoneLow; - uint8_t flags; - uint8_t RotationalOffset; - uint8_t Reserved; - uint16_t MediumRotationRate; - uint8_t Reserved2[2]; -} IPS_SCSI_MODE_PAGE4; - -/* - * Sense Data Format - Page 8 - */ -typedef struct { - uint8_t PageCode; - uint8_t PageLength; - uint8_t flags; - uint8_t RetentPrio; - uint16_t DisPrefetchLen; - uint16_t MinPrefetchLen; - uint16_t MaxPrefetchLen; - uint16_t MaxPrefetchCeiling; -} IPS_SCSI_MODE_PAGE8; - -/* - * Sense Data Format - Block Descriptor (DASD) - */ -typedef struct { - uint32_t NumberOfBlocks; - uint8_t DensityCode; - uint16_t BlockLengthHigh; - uint8_t BlockLengthLow; -} IPS_SCSI_MODE_PAGE_BLKDESC; - -/* - * Sense Data Format - Mode Page Header - */ -typedef struct { - uint8_t DataLength; - uint8_t MediumType; - uint8_t Reserved; - uint8_t BlockDescLength; -} IPS_SCSI_MODE_PAGE_HEADER; - -typedef struct { - IPS_SCSI_MODE_PAGE_HEADER hdr; - IPS_SCSI_MODE_PAGE_BLKDESC blkdesc; - - union { - IPS_SCSI_MODE_PAGE3 pg3; - IPS_SCSI_MODE_PAGE4 pg4; - IPS_SCSI_MODE_PAGE8 pg8; - } pdata; -} IPS_SCSI_MODE_PAGE_DATA; - -/* - * Scatter Gather list format - */ -typedef struct ips_sglist { - uint32_t address; - uint32_t length; -} IPS_STD_SG_LIST; - -typedef struct ips_enh_sglist { - uint32_t address_lo; - uint32_t address_hi; - uint32_t length; - uint32_t reserved; -} IPS_ENH_SG_LIST; - -typedef union { - void *list; - IPS_STD_SG_LIST *std_list; - IPS_ENH_SG_LIST *enh_list; -} IPS_SG_LIST; - -typedef struct _IPS_INFOSTR { - char *buffer; - int length; - int offset; - int pos; - int localpos; -} IPS_INFOSTR; - -typedef struct { - char *option_name; - int *option_flag; - int option_value; -} IPS_OPTION; - -/* - * Status Info - */ -typedef struct ips_stat { - uint32_t residue_len; - void *scb_addr; - uint8_t padding[12 - sizeof(void *)]; -} ips_stat_t; - -/* - * SCB Queue Format - */ -typedef struct ips_scb_queue { - struct ips_scb *head; - struct ips_scb *tail; - int count; -} ips_scb_queue_t; - -/* - * Wait queue_format - */ -typedef struct ips_wait_queue { - struct scsi_cmnd *head; - struct scsi_cmnd *tail; - int count; -} ips_wait_queue_t; - -typedef struct ips_copp_wait_item { - struct scsi_cmnd *scsi_cmd; - struct ips_copp_wait_item *next; -} ips_copp_wait_item_t; - -typedef struct ips_copp_queue { - struct ips_copp_wait_item *head; - struct ips_copp_wait_item *tail; - int count; -} ips_copp_queue_t; - -/* forward decl for host structure */ -struct ips_ha; - -typedef struct { - int (*reset)(struct ips_ha *); - int (*issue)(struct ips_ha *, struct ips_scb *); - int (*isinit)(struct ips_ha *); - int (*isintr)(struct ips_ha *); - int (*init)(struct ips_ha *); - int (*erasebios)(struct ips_ha *); - int (*programbios)(struct ips_ha *, char *, uint32_t, uint32_t); - int (*verifybios)(struct ips_ha *, char *, uint32_t, uint32_t); - void (*statinit)(struct ips_ha *); - int (*intr)(struct ips_ha *); - void (*enableint)(struct ips_ha *); - uint32_t (*statupd)(struct ips_ha *); -} ips_hw_func_t; - -typedef struct ips_ha { - uint8_t ha_id[IPS_MAX_CHANNELS+1]; - uint32_t dcdb_active[IPS_MAX_CHANNELS]; - uint32_t io_addr; /* Base I/O address */ - uint8_t ntargets; /* Number of targets */ - uint8_t nbus; /* Number of buses */ - uint8_t nlun; /* Number of Luns */ - uint16_t ad_type; /* Adapter type */ - uint16_t host_num; /* Adapter number */ - uint32_t max_xfer; /* Maximum Xfer size */ - uint32_t max_cmds; /* Max concurrent commands */ - uint32_t num_ioctl; /* Number of Ioctls */ - ips_stat_t sp; /* Status packer pointer */ - struct ips_scb *scbs; /* Array of all CCBS */ - struct ips_scb *scb_freelist; /* SCB free list */ - ips_wait_queue_t scb_waitlist; /* Pending SCB list */ - ips_copp_queue_t copp_waitlist; /* Pending PT list */ - ips_scb_queue_t scb_activelist; /* Active SCB list */ - IPS_IO_CMD *dummy; /* dummy command */ - IPS_ADAPTER *adapt; /* Adapter status area */ - IPS_LD_INFO *logical_drive_info; /* Adapter Logical Drive Info */ - dma_addr_t logical_drive_info_dma_addr; /* Logical Drive Info DMA Address */ - IPS_ENQ *enq; /* Adapter Enquiry data */ - IPS_CONF *conf; /* Adapter config data */ - IPS_NVRAM_P5 *nvram; /* NVRAM page 5 data */ - IPS_SUBSYS *subsys; /* Subsystem parameters */ - char *ioctl_data; /* IOCTL data area */ - uint32_t ioctl_datasize; /* IOCTL data size */ - uint32_t cmd_in_progress; /* Current command in progress*/ - int flags; /* */ - uint8_t waitflag; /* are we waiting for cmd */ - uint8_t active; - int ioctl_reset; /* IOCTL Requested Reset Flag */ - uint16_t reset_count; /* number of resets */ - time_t last_ffdc; /* last time we sent ffdc info*/ - uint8_t slot_num; /* PCI Slot Number */ - int ioctl_len; /* size of ioctl buffer */ - dma_addr_t ioctl_busaddr; /* dma address of ioctl buffer*/ - uint8_t bios_version[8]; /* BIOS Revision */ - uint32_t mem_addr; /* Memory mapped address */ - uint32_t io_len; /* Size of IO Address */ - uint32_t mem_len; /* Size of memory address */ - char __iomem *mem_ptr; /* Memory mapped Ptr */ - char __iomem *ioremap_ptr;/* ioremapped memory pointer */ - ips_hw_func_t func; /* hw function pointers */ - struct pci_dev *pcidev; /* PCI device handle */ - char *flash_data; /* Save Area for flash data */ - int flash_len; /* length of flash buffer */ - u32 flash_datasize; /* Save Area for flash data size */ - dma_addr_t flash_busaddr; /* dma address of flash buffer*/ - dma_addr_t enq_busaddr; /* dma address of enq struct */ - uint8_t requires_esl; /* Requires an EraseStripeLock */ -} ips_ha_t; - -typedef void (*ips_scb_callback) (ips_ha_t *, struct ips_scb *); - -/* - * SCB Format - */ -typedef struct ips_scb { - IPS_HOST_COMMAND cmd; - IPS_DCDB_TABLE dcdb; - uint8_t target_id; - uint8_t bus; - uint8_t lun; - uint8_t cdb[12]; - uint32_t scb_busaddr; - uint32_t old_data_busaddr; // Obsolete, but kept for old utility compatibility - uint32_t timeout; - uint8_t basic_status; - uint8_t extended_status; - uint8_t breakup; - uint8_t sg_break; - uint32_t data_len; - uint32_t sg_len; - uint32_t flags; - uint32_t op_code; - IPS_SG_LIST sg_list; - struct scsi_cmnd *scsi_cmd; - struct ips_scb *q_next; - ips_scb_callback callback; - uint32_t sg_busaddr; - int sg_count; - dma_addr_t data_busaddr; -} ips_scb_t; - -typedef struct ips_scb_pt { - IPS_HOST_COMMAND cmd; - IPS_DCDB_TABLE dcdb; - uint8_t target_id; - uint8_t bus; - uint8_t lun; - uint8_t cdb[12]; - uint32_t scb_busaddr; - uint32_t data_busaddr; - uint32_t timeout; - uint8_t basic_status; - uint8_t extended_status; - uint16_t breakup; - uint32_t data_len; - uint32_t sg_len; - uint32_t flags; - uint32_t op_code; - IPS_SG_LIST *sg_list; - struct scsi_cmnd *scsi_cmd; - struct ips_scb *q_next; - ips_scb_callback callback; -} ips_scb_pt_t; - -/* - * Passthru Command Format - */ -typedef struct { - uint8_t CoppID[4]; - uint32_t CoppCmd; - uint32_t PtBuffer; - uint8_t *CmdBuffer; - uint32_t CmdBSize; - ips_scb_pt_t CoppCP; - uint32_t TimeOut; - uint8_t BasicStatus; - uint8_t ExtendedStatus; - uint8_t AdapterType; - uint8_t reserved; -} ips_passthru_t; - -#endif - -/* The Version Information below gets created by SED during the build process. */ -/* Do not modify the next line; it's what SED is looking for to do the insert. */ -/* Version Info */ -/************************************************************************* -* -* VERSION.H -- version numbers and copyright notices in various formats -* -*************************************************************************/ - -#define IPS_VER_MAJOR 7 -#define IPS_VER_MAJOR_STRING __stringify(IPS_VER_MAJOR) -#define IPS_VER_MINOR 12 -#define IPS_VER_MINOR_STRING __stringify(IPS_VER_MINOR) -#define IPS_VER_BUILD 05 -#define IPS_VER_BUILD_STRING __stringify(IPS_VER_BUILD) -#define IPS_VER_STRING IPS_VER_MAJOR_STRING "." \ - IPS_VER_MINOR_STRING "." IPS_VER_BUILD_STRING -#define IPS_RELEASE_ID 0x00020000 -#define IPS_BUILD_IDENT 761 -#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved." -#define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to 2004. All Rights Reserved." -#define IPS_DELLCOPYRIGHT_STRING "(c) Copyright Dell 2004. All Rights Reserved." -#define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002." - -/* Version numbers for various adapters */ -#define IPS_VER_SERVERAID1 "2.25.01" -#define IPS_VER_SERVERAID2 "2.88.13" -#define IPS_VER_NAVAJO "2.88.13" -#define IPS_VER_SERVERAID3 "6.10.24" -#define IPS_VER_SERVERAID4H "7.12.02" -#define IPS_VER_SERVERAID4MLx "7.12.02" -#define IPS_VER_SARASOTA "7.12.02" -#define IPS_VER_MARCO "7.12.02" -#define IPS_VER_SEBRING "7.12.02" -#define IPS_VER_KEYWEST "7.12.02" - -/* Compatibility IDs for various adapters */ -#define IPS_COMPAT_UNKNOWN "" -#define IPS_COMPAT_CURRENT "KW710" -#define IPS_COMPAT_SERVERAID1 "2.25.01" -#define IPS_COMPAT_SERVERAID2 "2.88.13" -#define IPS_COMPAT_NAVAJO "2.88.13" -#define IPS_COMPAT_KIOWA "2.88.13" -#define IPS_COMPAT_SERVERAID3H "SB610" -#define IPS_COMPAT_SERVERAID3L "SB610" -#define IPS_COMPAT_SERVERAID4H "KW710" -#define IPS_COMPAT_SERVERAID4M "KW710" -#define IPS_COMPAT_SERVERAID4L "KW710" -#define IPS_COMPAT_SERVERAID4Mx "KW710" -#define IPS_COMPAT_SERVERAID4Lx "KW710" -#define IPS_COMPAT_SARASOTA "KW710" -#define IPS_COMPAT_MARCO "KW710" -#define IPS_COMPAT_SEBRING "KW710" -#define IPS_COMPAT_TAMPA "KW710" -#define IPS_COMPAT_KEYWEST "KW710" -#define IPS_COMPAT_BIOS "KW710" - -#define IPS_COMPAT_MAX_ADAPTER_TYPE 18 -#define IPS_COMPAT_ID_LENGTH 8 - -#define IPS_DEFINE_COMPAT_TABLE(tablename) \ - char tablename[IPS_COMPAT_MAX_ADAPTER_TYPE] [IPS_COMPAT_ID_LENGTH] = { \ - IPS_COMPAT_UNKNOWN, \ - IPS_COMPAT_SERVERAID1, \ - IPS_COMPAT_SERVERAID2, \ - IPS_COMPAT_NAVAJO, \ - IPS_COMPAT_KIOWA, \ - IPS_COMPAT_SERVERAID3H, \ - IPS_COMPAT_SERVERAID3L, \ - IPS_COMPAT_SERVERAID4H, \ - IPS_COMPAT_SERVERAID4M, \ - IPS_COMPAT_SERVERAID4L, \ - IPS_COMPAT_SERVERAID4Mx, \ - IPS_COMPAT_SERVERAID4Lx, \ - IPS_COMPAT_SARASOTA, /* one-channel variety of SARASOTA */ \ - IPS_COMPAT_SARASOTA, /* two-channel variety of SARASOTA */ \ - IPS_COMPAT_MARCO, \ - IPS_COMPAT_SEBRING, \ - IPS_COMPAT_TAMPA, \ - IPS_COMPAT_KEYWEST \ - } - - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 2 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -2 - * c-argdecl-indent: 2 - * c-label-offset: -2 - * c-continued-statement-offset: 2 - * c-continued-brace-offset: 0 - * indent-tabs-mode: nil - * tab-width: 8 - * End: - */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/Makefile b/ANDROID_3.4.5/drivers/scsi/isci/Makefile deleted file mode 100644 index 3359e10e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -obj-$(CONFIG_SCSI_ISCI) += isci.o -isci-objs := init.o phy.o request.o \ - remote_device.o port.o \ - host.o task.o probe_roms.o \ - remote_node_context.o \ - remote_node_table.o \ - unsolicited_frame_control.o \ - port_config.o \ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/host.c b/ANDROID_3.4.5/drivers/scsi/isci/host.c deleted file mode 100644 index d4bf9c12..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/host.c +++ /dev/null @@ -1,3034 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include "host.h" -#include "isci.h" -#include "port.h" -#include "probe_roms.h" -#include "remote_device.h" -#include "request.h" -#include "scu_completion_codes.h" -#include "scu_event_codes.h" -#include "registers.h" -#include "scu_remote_node_context.h" -#include "scu_task_context.h" - -#define SCU_CONTEXT_RAM_INIT_STALL_TIME 200 - -#define smu_max_ports(dcc_value) \ - (\ - (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK) \ - >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT) + 1 \ - ) - -#define smu_max_task_contexts(dcc_value) \ - (\ - (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK) \ - >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT) + 1 \ - ) - -#define smu_max_rncs(dcc_value) \ - (\ - (((dcc_value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) \ - >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT) + 1 \ - ) - -#define SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT 100 - -/** - * - * - * The number of milliseconds to wait while a given phy is consuming power - * before allowing another set of phys to consume power. Ultimately, this will - * be specified by OEM parameter. - */ -#define SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL 500 - -/** - * NORMALIZE_PUT_POINTER() - - * - * This macro will normalize the completion queue put pointer so its value can - * be used as an array inde - */ -#define NORMALIZE_PUT_POINTER(x) \ - ((x) & SMU_COMPLETION_QUEUE_PUT_POINTER_MASK) - - -/** - * NORMALIZE_EVENT_POINTER() - - * - * This macro will normalize the completion queue event entry so its value can - * be used as an index. - */ -#define NORMALIZE_EVENT_POINTER(x) \ - (\ - ((x) & SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK) \ - >> SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT \ - ) - -/** - * NORMALIZE_GET_POINTER() - - * - * This macro will normalize the completion queue get pointer so its value can - * be used as an index into an array - */ -#define NORMALIZE_GET_POINTER(x) \ - ((x) & SMU_COMPLETION_QUEUE_GET_POINTER_MASK) - -/** - * NORMALIZE_GET_POINTER_CYCLE_BIT() - - * - * This macro will normalize the completion queue cycle pointer so it matches - * the completion queue cycle bit - */ -#define NORMALIZE_GET_POINTER_CYCLE_BIT(x) \ - ((SMU_CQGR_CYCLE_BIT & (x)) << (31 - SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT)) - -/** - * COMPLETION_QUEUE_CYCLE_BIT() - - * - * This macro will return the cycle bit of the completion queue entry - */ -#define COMPLETION_QUEUE_CYCLE_BIT(x) ((x) & 0x80000000) - -/* Init the state machine and call the state entry function (if any) */ -void sci_init_sm(struct sci_base_state_machine *sm, - const struct sci_base_state *state_table, u32 initial_state) -{ - sci_state_transition_t handler; - - sm->initial_state_id = initial_state; - sm->previous_state_id = initial_state; - sm->current_state_id = initial_state; - sm->state_table = state_table; - - handler = sm->state_table[initial_state].enter_state; - if (handler) - handler(sm); -} - -/* Call the state exit fn, update the current state, call the state entry fn */ -void sci_change_state(struct sci_base_state_machine *sm, u32 next_state) -{ - sci_state_transition_t handler; - - handler = sm->state_table[sm->current_state_id].exit_state; - if (handler) - handler(sm); - - sm->previous_state_id = sm->current_state_id; - sm->current_state_id = next_state; - - handler = sm->state_table[sm->current_state_id].enter_state; - if (handler) - handler(sm); -} - -static bool sci_controller_completion_queue_has_entries(struct isci_host *ihost) -{ - u32 get_value = ihost->completion_queue_get; - u32 get_index = get_value & SMU_COMPLETION_QUEUE_GET_POINTER_MASK; - - if (NORMALIZE_GET_POINTER_CYCLE_BIT(get_value) == - COMPLETION_QUEUE_CYCLE_BIT(ihost->completion_queue[get_index])) - return true; - - return false; -} - -static bool sci_controller_isr(struct isci_host *ihost) -{ - if (sci_controller_completion_queue_has_entries(ihost)) { - return true; - } else { - /* - * we have a spurious interrupt it could be that we have already - * emptied the completion queue from a previous interrupt */ - writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status); - - /* - * There is a race in the hardware that could cause us not to be notified - * of an interrupt completion if we do not take this step. We will mask - * then unmask the interrupts so if there is another interrupt pending - * the clearing of the interrupt source we get the next interrupt message. */ - writel(0xFF000000, &ihost->smu_registers->interrupt_mask); - writel(0, &ihost->smu_registers->interrupt_mask); - } - - return false; -} - -irqreturn_t isci_msix_isr(int vec, void *data) -{ - struct isci_host *ihost = data; - - if (sci_controller_isr(ihost)) - tasklet_schedule(&ihost->completion_tasklet); - - return IRQ_HANDLED; -} - -static bool sci_controller_error_isr(struct isci_host *ihost) -{ - u32 interrupt_status; - - interrupt_status = - readl(&ihost->smu_registers->interrupt_status); - interrupt_status &= (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND); - - if (interrupt_status != 0) { - /* - * There is an error interrupt pending so let it through and handle - * in the callback */ - return true; - } - - /* - * There is a race in the hardware that could cause us not to be notified - * of an interrupt completion if we do not take this step. We will mask - * then unmask the error interrupts so if there was another interrupt - * pending we will be notified. - * Could we write the value of (SMU_ISR_QUEUE_ERROR | SMU_ISR_QUEUE_SUSPEND)? */ - writel(0xff, &ihost->smu_registers->interrupt_mask); - writel(0, &ihost->smu_registers->interrupt_mask); - - return false; -} - -static void sci_controller_task_completion(struct isci_host *ihost, u32 ent) -{ - u32 index = SCU_GET_COMPLETION_INDEX(ent); - struct isci_request *ireq = ihost->reqs[index]; - - /* Make sure that we really want to process this IO request */ - if (test_bit(IREQ_ACTIVE, &ireq->flags) && - ireq->io_tag != SCI_CONTROLLER_INVALID_IO_TAG && - ISCI_TAG_SEQ(ireq->io_tag) == ihost->io_request_sequence[index]) - /* Yep this is a valid io request pass it along to the - * io request handler - */ - sci_io_request_tc_completion(ireq, ent); -} - -static void sci_controller_sdma_completion(struct isci_host *ihost, u32 ent) -{ - u32 index; - struct isci_request *ireq; - struct isci_remote_device *idev; - - index = SCU_GET_COMPLETION_INDEX(ent); - - switch (scu_get_command_request_type(ent)) { - case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC: - case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC: - ireq = ihost->reqs[index]; - dev_warn(&ihost->pdev->dev, "%s: %x for io request %p\n", - __func__, ent, ireq); - /* @todo For a post TC operation we need to fail the IO - * request - */ - break; - case SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC: - case SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC: - case SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC: - idev = ihost->device_table[index]; - dev_warn(&ihost->pdev->dev, "%s: %x for device %p\n", - __func__, ent, idev); - /* @todo For a port RNC operation we need to fail the - * device - */ - break; - default: - dev_warn(&ihost->pdev->dev, "%s: unknown completion type %x\n", - __func__, ent); - break; - } -} - -static void sci_controller_unsolicited_frame(struct isci_host *ihost, u32 ent) -{ - u32 index; - u32 frame_index; - - struct scu_unsolicited_frame_header *frame_header; - struct isci_phy *iphy; - struct isci_remote_device *idev; - - enum sci_status result = SCI_FAILURE; - - frame_index = SCU_GET_FRAME_INDEX(ent); - - frame_header = ihost->uf_control.buffers.array[frame_index].header; - ihost->uf_control.buffers.array[frame_index].state = UNSOLICITED_FRAME_IN_USE; - - if (SCU_GET_FRAME_ERROR(ent)) { - /* - * / @todo If the IAF frame or SIGNATURE FIS frame has an error will - * / this cause a problem? We expect the phy initialization will - * / fail if there is an error in the frame. */ - sci_controller_release_frame(ihost, frame_index); - return; - } - - if (frame_header->is_address_frame) { - index = SCU_GET_PROTOCOL_ENGINE_INDEX(ent); - iphy = &ihost->phys[index]; - result = sci_phy_frame_handler(iphy, frame_index); - } else { - - index = SCU_GET_COMPLETION_INDEX(ent); - - if (index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) { - /* - * This is a signature fis or a frame from a direct attached SATA - * device that has not yet been created. In either case forwared - * the frame to the PE and let it take care of the frame data. */ - index = SCU_GET_PROTOCOL_ENGINE_INDEX(ent); - iphy = &ihost->phys[index]; - result = sci_phy_frame_handler(iphy, frame_index); - } else { - if (index < ihost->remote_node_entries) - idev = ihost->device_table[index]; - else - idev = NULL; - - if (idev != NULL) - result = sci_remote_device_frame_handler(idev, frame_index); - else - sci_controller_release_frame(ihost, frame_index); - } - } - - if (result != SCI_SUCCESS) { - /* - * / @todo Is there any reason to report some additional error message - * / when we get this failure notifiction? */ - } -} - -static void sci_controller_event_completion(struct isci_host *ihost, u32 ent) -{ - struct isci_remote_device *idev; - struct isci_request *ireq; - struct isci_phy *iphy; - u32 index; - - index = SCU_GET_COMPLETION_INDEX(ent); - - switch (scu_get_event_type(ent)) { - case SCU_EVENT_TYPE_SMU_COMMAND_ERROR: - /* / @todo The driver did something wrong and we need to fix the condtion. */ - dev_err(&ihost->pdev->dev, - "%s: SCIC Controller 0x%p received SMU command error " - "0x%x\n", - __func__, - ihost, - ent); - break; - - case SCU_EVENT_TYPE_SMU_PCQ_ERROR: - case SCU_EVENT_TYPE_SMU_ERROR: - case SCU_EVENT_TYPE_FATAL_MEMORY_ERROR: - /* - * / @todo This is a hardware failure and its likely that we want to - * / reset the controller. */ - dev_err(&ihost->pdev->dev, - "%s: SCIC Controller 0x%p received fatal controller " - "event 0x%x\n", - __func__, - ihost, - ent); - break; - - case SCU_EVENT_TYPE_TRANSPORT_ERROR: - ireq = ihost->reqs[index]; - sci_io_request_event_handler(ireq, ent); - break; - - case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT: - switch (scu_get_event_specifier(ent)) { - case SCU_EVENT_SPECIFIC_SMP_RESPONSE_NO_PE: - case SCU_EVENT_SPECIFIC_TASK_TIMEOUT: - ireq = ihost->reqs[index]; - if (ireq != NULL) - sci_io_request_event_handler(ireq, ent); - else - dev_warn(&ihost->pdev->dev, - "%s: SCIC Controller 0x%p received " - "event 0x%x for io request object " - "that doesnt exist.\n", - __func__, - ihost, - ent); - - break; - - case SCU_EVENT_SPECIFIC_IT_NEXUS_TIMEOUT: - idev = ihost->device_table[index]; - if (idev != NULL) - sci_remote_device_event_handler(idev, ent); - else - dev_warn(&ihost->pdev->dev, - "%s: SCIC Controller 0x%p received " - "event 0x%x for remote device object " - "that doesnt exist.\n", - __func__, - ihost, - ent); - - break; - } - break; - - case SCU_EVENT_TYPE_BROADCAST_CHANGE: - /* - * direct the broadcast change event to the phy first and then let - * the phy redirect the broadcast change to the port object */ - case SCU_EVENT_TYPE_ERR_CNT_EVENT: - /* - * direct error counter event to the phy object since that is where - * we get the event notification. This is a type 4 event. */ - case SCU_EVENT_TYPE_OSSP_EVENT: - index = SCU_GET_PROTOCOL_ENGINE_INDEX(ent); - iphy = &ihost->phys[index]; - sci_phy_event_handler(iphy, ent); - break; - - case SCU_EVENT_TYPE_RNC_SUSPEND_TX: - case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: - case SCU_EVENT_TYPE_RNC_OPS_MISC: - if (index < ihost->remote_node_entries) { - idev = ihost->device_table[index]; - - if (idev != NULL) - sci_remote_device_event_handler(idev, ent); - } else - dev_err(&ihost->pdev->dev, - "%s: SCIC Controller 0x%p received event 0x%x " - "for remote device object 0x%0x that doesnt " - "exist.\n", - __func__, - ihost, - ent, - index); - - break; - - default: - dev_warn(&ihost->pdev->dev, - "%s: SCIC Controller received unknown event code %x\n", - __func__, - ent); - break; - } -} - -static void sci_controller_process_completions(struct isci_host *ihost) -{ - u32 completion_count = 0; - u32 ent; - u32 get_index; - u32 get_cycle; - u32 event_get; - u32 event_cycle; - - dev_dbg(&ihost->pdev->dev, - "%s: completion queue begining get:0x%08x\n", - __func__, - ihost->completion_queue_get); - - /* Get the component parts of the completion queue */ - get_index = NORMALIZE_GET_POINTER(ihost->completion_queue_get); - get_cycle = SMU_CQGR_CYCLE_BIT & ihost->completion_queue_get; - - event_get = NORMALIZE_EVENT_POINTER(ihost->completion_queue_get); - event_cycle = SMU_CQGR_EVENT_CYCLE_BIT & ihost->completion_queue_get; - - while ( - NORMALIZE_GET_POINTER_CYCLE_BIT(get_cycle) - == COMPLETION_QUEUE_CYCLE_BIT(ihost->completion_queue[get_index]) - ) { - completion_count++; - - ent = ihost->completion_queue[get_index]; - - /* increment the get pointer and check for rollover to toggle the cycle bit */ - get_cycle ^= ((get_index+1) & SCU_MAX_COMPLETION_QUEUE_ENTRIES) << - (SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT - SCU_MAX_COMPLETION_QUEUE_SHIFT); - get_index = (get_index+1) & (SCU_MAX_COMPLETION_QUEUE_ENTRIES-1); - - dev_dbg(&ihost->pdev->dev, - "%s: completion queue entry:0x%08x\n", - __func__, - ent); - - switch (SCU_GET_COMPLETION_TYPE(ent)) { - case SCU_COMPLETION_TYPE_TASK: - sci_controller_task_completion(ihost, ent); - break; - - case SCU_COMPLETION_TYPE_SDMA: - sci_controller_sdma_completion(ihost, ent); - break; - - case SCU_COMPLETION_TYPE_UFI: - sci_controller_unsolicited_frame(ihost, ent); - break; - - case SCU_COMPLETION_TYPE_EVENT: - sci_controller_event_completion(ihost, ent); - break; - - case SCU_COMPLETION_TYPE_NOTIFY: { - event_cycle ^= ((event_get+1) & SCU_MAX_EVENTS) << - (SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_SHIFT - SCU_MAX_EVENTS_SHIFT); - event_get = (event_get+1) & (SCU_MAX_EVENTS-1); - - sci_controller_event_completion(ihost, ent); - break; - } - default: - dev_warn(&ihost->pdev->dev, - "%s: SCIC Controller received unknown " - "completion type %x\n", - __func__, - ent); - break; - } - } - - /* Update the get register if we completed one or more entries */ - if (completion_count > 0) { - ihost->completion_queue_get = - SMU_CQGR_GEN_BIT(ENABLE) | - SMU_CQGR_GEN_BIT(EVENT_ENABLE) | - event_cycle | - SMU_CQGR_GEN_VAL(EVENT_POINTER, event_get) | - get_cycle | - SMU_CQGR_GEN_VAL(POINTER, get_index); - - writel(ihost->completion_queue_get, - &ihost->smu_registers->completion_queue_get); - - } - - dev_dbg(&ihost->pdev->dev, - "%s: completion queue ending get:0x%08x\n", - __func__, - ihost->completion_queue_get); - -} - -static void sci_controller_error_handler(struct isci_host *ihost) -{ - u32 interrupt_status; - - interrupt_status = - readl(&ihost->smu_registers->interrupt_status); - - if ((interrupt_status & SMU_ISR_QUEUE_SUSPEND) && - sci_controller_completion_queue_has_entries(ihost)) { - - sci_controller_process_completions(ihost); - writel(SMU_ISR_QUEUE_SUSPEND, &ihost->smu_registers->interrupt_status); - } else { - dev_err(&ihost->pdev->dev, "%s: status: %#x\n", __func__, - interrupt_status); - - sci_change_state(&ihost->sm, SCIC_FAILED); - - return; - } - - /* If we dont process any completions I am not sure that we want to do this. - * We are in the middle of a hardware fault and should probably be reset. - */ - writel(0, &ihost->smu_registers->interrupt_mask); -} - -irqreturn_t isci_intx_isr(int vec, void *data) -{ - irqreturn_t ret = IRQ_NONE; - struct isci_host *ihost = data; - - if (sci_controller_isr(ihost)) { - writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status); - tasklet_schedule(&ihost->completion_tasklet); - ret = IRQ_HANDLED; - } else if (sci_controller_error_isr(ihost)) { - spin_lock(&ihost->scic_lock); - sci_controller_error_handler(ihost); - spin_unlock(&ihost->scic_lock); - ret = IRQ_HANDLED; - } - - return ret; -} - -irqreturn_t isci_error_isr(int vec, void *data) -{ - struct isci_host *ihost = data; - - if (sci_controller_error_isr(ihost)) - sci_controller_error_handler(ihost); - - return IRQ_HANDLED; -} - -/** - * isci_host_start_complete() - This function is called by the core library, - * through the ISCI Module, to indicate controller start status. - * @isci_host: This parameter specifies the ISCI host object - * @completion_status: This parameter specifies the completion status from the - * core library. - * - */ -static void isci_host_start_complete(struct isci_host *ihost, enum sci_status completion_status) -{ - if (completion_status != SCI_SUCCESS) - dev_info(&ihost->pdev->dev, - "controller start timed out, continuing...\n"); - isci_host_change_state(ihost, isci_ready); - clear_bit(IHOST_START_PENDING, &ihost->flags); - wake_up(&ihost->eventq); -} - -int isci_host_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - struct isci_host *ihost = ha->lldd_ha; - - if (test_bit(IHOST_START_PENDING, &ihost->flags)) - return 0; - - sas_drain_work(ha); - - dev_dbg(&ihost->pdev->dev, - "%s: ihost->status = %d, time = %ld\n", - __func__, isci_host_get_state(ihost), time); - - return 1; - -} - -/** - * sci_controller_get_suggested_start_timeout() - This method returns the - * suggested sci_controller_start() timeout amount. The user is free to - * use any timeout value, but this method provides the suggested minimum - * start timeout value. The returned value is based upon empirical - * information determined as a result of interoperability testing. - * @controller: the handle to the controller object for which to return the - * suggested start timeout. - * - * This method returns the number of milliseconds for the suggested start - * operation timeout. - */ -static u32 sci_controller_get_suggested_start_timeout(struct isci_host *ihost) -{ - /* Validate the user supplied parameters. */ - if (!ihost) - return 0; - - /* - * The suggested minimum timeout value for a controller start operation: - * - * Signature FIS Timeout - * + Phy Start Timeout - * + Number of Phy Spin Up Intervals - * --------------------------------- - * Number of milliseconds for the controller start operation. - * - * NOTE: The number of phy spin up intervals will be equivalent - * to the number of phys divided by the number phys allowed - * per interval - 1 (once OEM parameters are supported). - * Currently we assume only 1 phy per interval. */ - - return SCIC_SDS_SIGNATURE_FIS_TIMEOUT - + SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT - + ((SCI_MAX_PHYS - 1) * SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL); -} - -static void sci_controller_enable_interrupts(struct isci_host *ihost) -{ - BUG_ON(ihost->smu_registers == NULL); - writel(0, &ihost->smu_registers->interrupt_mask); -} - -void sci_controller_disable_interrupts(struct isci_host *ihost) -{ - BUG_ON(ihost->smu_registers == NULL); - writel(0xffffffff, &ihost->smu_registers->interrupt_mask); -} - -static void sci_controller_enable_port_task_scheduler(struct isci_host *ihost) -{ - u32 port_task_scheduler_value; - - port_task_scheduler_value = - readl(&ihost->scu_registers->peg0.ptsg.control); - port_task_scheduler_value |= - (SCU_PTSGCR_GEN_BIT(ETM_ENABLE) | - SCU_PTSGCR_GEN_BIT(PTSG_ENABLE)); - writel(port_task_scheduler_value, - &ihost->scu_registers->peg0.ptsg.control); -} - -static void sci_controller_assign_task_entries(struct isci_host *ihost) -{ - u32 task_assignment; - - /* - * Assign all the TCs to function 0 - * TODO: Do we actually need to read this register to write it back? - */ - - task_assignment = - readl(&ihost->smu_registers->task_context_assignment[0]); - - task_assignment |= (SMU_TCA_GEN_VAL(STARTING, 0)) | - (SMU_TCA_GEN_VAL(ENDING, ihost->task_context_entries - 1)) | - (SMU_TCA_GEN_BIT(RANGE_CHECK_ENABLE)); - - writel(task_assignment, - &ihost->smu_registers->task_context_assignment[0]); - -} - -static void sci_controller_initialize_completion_queue(struct isci_host *ihost) -{ - u32 index; - u32 completion_queue_control_value; - u32 completion_queue_get_value; - u32 completion_queue_put_value; - - ihost->completion_queue_get = 0; - - completion_queue_control_value = - (SMU_CQC_QUEUE_LIMIT_SET(SCU_MAX_COMPLETION_QUEUE_ENTRIES - 1) | - SMU_CQC_EVENT_LIMIT_SET(SCU_MAX_EVENTS - 1)); - - writel(completion_queue_control_value, - &ihost->smu_registers->completion_queue_control); - - - /* Set the completion queue get pointer and enable the queue */ - completion_queue_get_value = ( - (SMU_CQGR_GEN_VAL(POINTER, 0)) - | (SMU_CQGR_GEN_VAL(EVENT_POINTER, 0)) - | (SMU_CQGR_GEN_BIT(ENABLE)) - | (SMU_CQGR_GEN_BIT(EVENT_ENABLE)) - ); - - writel(completion_queue_get_value, - &ihost->smu_registers->completion_queue_get); - - /* Set the completion queue put pointer */ - completion_queue_put_value = ( - (SMU_CQPR_GEN_VAL(POINTER, 0)) - | (SMU_CQPR_GEN_VAL(EVENT_POINTER, 0)) - ); - - writel(completion_queue_put_value, - &ihost->smu_registers->completion_queue_put); - - /* Initialize the cycle bit of the completion queue entries */ - for (index = 0; index < SCU_MAX_COMPLETION_QUEUE_ENTRIES; index++) { - /* - * If get.cycle_bit != completion_queue.cycle_bit - * its not a valid completion queue entry - * so at system start all entries are invalid */ - ihost->completion_queue[index] = 0x80000000; - } -} - -static void sci_controller_initialize_unsolicited_frame_queue(struct isci_host *ihost) -{ - u32 frame_queue_control_value; - u32 frame_queue_get_value; - u32 frame_queue_put_value; - - /* Write the queue size */ - frame_queue_control_value = - SCU_UFQC_GEN_VAL(QUEUE_SIZE, SCU_MAX_UNSOLICITED_FRAMES); - - writel(frame_queue_control_value, - &ihost->scu_registers->sdma.unsolicited_frame_queue_control); - - /* Setup the get pointer for the unsolicited frame queue */ - frame_queue_get_value = ( - SCU_UFQGP_GEN_VAL(POINTER, 0) - | SCU_UFQGP_GEN_BIT(ENABLE_BIT) - ); - - writel(frame_queue_get_value, - &ihost->scu_registers->sdma.unsolicited_frame_get_pointer); - /* Setup the put pointer for the unsolicited frame queue */ - frame_queue_put_value = SCU_UFQPP_GEN_VAL(POINTER, 0); - writel(frame_queue_put_value, - &ihost->scu_registers->sdma.unsolicited_frame_put_pointer); -} - -static void sci_controller_transition_to_ready(struct isci_host *ihost, enum sci_status status) -{ - if (ihost->sm.current_state_id == SCIC_STARTING) { - /* - * We move into the ready state, because some of the phys/ports - * may be up and operational. - */ - sci_change_state(&ihost->sm, SCIC_READY); - - isci_host_start_complete(ihost, status); - } -} - -static bool is_phy_starting(struct isci_phy *iphy) -{ - enum sci_phy_states state; - - state = iphy->sm.current_state_id; - switch (state) { - case SCI_PHY_STARTING: - case SCI_PHY_SUB_INITIAL: - case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: - case SCI_PHY_SUB_AWAIT_IAF_UF: - case SCI_PHY_SUB_AWAIT_SAS_POWER: - case SCI_PHY_SUB_AWAIT_SATA_POWER: - case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: - case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: - case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: - case SCI_PHY_SUB_FINAL: - return true; - default: - return false; - } -} - -/** - * sci_controller_start_next_phy - start phy - * @scic: controller - * - * If all the phys have been started, then attempt to transition the - * controller to the READY state and inform the user - * (sci_cb_controller_start_complete()). - */ -static enum sci_status sci_controller_start_next_phy(struct isci_host *ihost) -{ - struct sci_oem_params *oem = &ihost->oem_parameters; - struct isci_phy *iphy; - enum sci_status status; - - status = SCI_SUCCESS; - - if (ihost->phy_startup_timer_pending) - return status; - - if (ihost->next_phy_to_start >= SCI_MAX_PHYS) { - bool is_controller_start_complete = true; - u32 state; - u8 index; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - iphy = &ihost->phys[index]; - state = iphy->sm.current_state_id; - - if (!phy_get_non_dummy_port(iphy)) - continue; - - /* The controller start operation is complete iff: - * - all links have been given an opportunity to start - * - have no indication of a connected device - * - have an indication of a connected device and it has - * finished the link training process. - */ - if ((iphy->is_in_link_training == false && state == SCI_PHY_INITIAL) || - (iphy->is_in_link_training == false && state == SCI_PHY_STOPPED) || - (iphy->is_in_link_training == true && is_phy_starting(iphy)) || - (ihost->port_agent.phy_ready_mask != ihost->port_agent.phy_configured_mask)) { - is_controller_start_complete = false; - break; - } - } - - /* - * The controller has successfully finished the start process. - * Inform the SCI Core user and transition to the READY state. */ - if (is_controller_start_complete == true) { - sci_controller_transition_to_ready(ihost, SCI_SUCCESS); - sci_del_timer(&ihost->phy_timer); - ihost->phy_startup_timer_pending = false; - } - } else { - iphy = &ihost->phys[ihost->next_phy_to_start]; - - if (oem->controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE) { - if (phy_get_non_dummy_port(iphy) == NULL) { - ihost->next_phy_to_start++; - - /* Caution recursion ahead be forwarned - * - * The PHY was never added to a PORT in MPC mode - * so start the next phy in sequence This phy - * will never go link up and will not draw power - * the OEM parameters either configured the phy - * incorrectly for the PORT or it was never - * assigned to a PORT - */ - return sci_controller_start_next_phy(ihost); - } - } - - status = sci_phy_start(iphy); - - if (status == SCI_SUCCESS) { - sci_mod_timer(&ihost->phy_timer, - SCIC_SDS_CONTROLLER_PHY_START_TIMEOUT); - ihost->phy_startup_timer_pending = true; - } else { - dev_warn(&ihost->pdev->dev, - "%s: Controller stop operation failed " - "to stop phy %d because of status " - "%d.\n", - __func__, - ihost->phys[ihost->next_phy_to_start].phy_index, - status); - } - - ihost->next_phy_to_start++; - } - - return status; -} - -static void phy_startup_timeout(unsigned long data) -{ - struct sci_timer *tmr = (struct sci_timer *)data; - struct isci_host *ihost = container_of(tmr, typeof(*ihost), phy_timer); - unsigned long flags; - enum sci_status status; - - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmr->cancel) - goto done; - - ihost->phy_startup_timer_pending = false; - - do { - status = sci_controller_start_next_phy(ihost); - } while (status != SCI_SUCCESS); - -done: - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - -static u16 isci_tci_active(struct isci_host *ihost) -{ - return CIRC_CNT(ihost->tci_head, ihost->tci_tail, SCI_MAX_IO_REQUESTS); -} - -static enum sci_status sci_controller_start(struct isci_host *ihost, - u32 timeout) -{ - enum sci_status result; - u16 index; - - if (ihost->sm.current_state_id != SCIC_INITIALIZED) { - dev_warn(&ihost->pdev->dev, - "SCIC Controller start operation requested in " - "invalid state\n"); - return SCI_FAILURE_INVALID_STATE; - } - - /* Build the TCi free pool */ - BUILD_BUG_ON(SCI_MAX_IO_REQUESTS > 1 << sizeof(ihost->tci_pool[0]) * 8); - ihost->tci_head = 0; - ihost->tci_tail = 0; - for (index = 0; index < ihost->task_context_entries; index++) - isci_tci_free(ihost, index); - - /* Build the RNi free pool */ - sci_remote_node_table_initialize(&ihost->available_remote_nodes, - ihost->remote_node_entries); - - /* - * Before anything else lets make sure we will not be - * interrupted by the hardware. - */ - sci_controller_disable_interrupts(ihost); - - /* Enable the port task scheduler */ - sci_controller_enable_port_task_scheduler(ihost); - - /* Assign all the task entries to ihost physical function */ - sci_controller_assign_task_entries(ihost); - - /* Now initialize the completion queue */ - sci_controller_initialize_completion_queue(ihost); - - /* Initialize the unsolicited frame queue for use */ - sci_controller_initialize_unsolicited_frame_queue(ihost); - - /* Start all of the ports on this controller */ - for (index = 0; index < ihost->logical_port_entries; index++) { - struct isci_port *iport = &ihost->ports[index]; - - result = sci_port_start(iport); - if (result) - return result; - } - - sci_controller_start_next_phy(ihost); - - sci_mod_timer(&ihost->timer, timeout); - - sci_change_state(&ihost->sm, SCIC_STARTING); - - return SCI_SUCCESS; -} - -void isci_host_scan_start(struct Scsi_Host *shost) -{ - struct isci_host *ihost = SHOST_TO_SAS_HA(shost)->lldd_ha; - unsigned long tmo = sci_controller_get_suggested_start_timeout(ihost); - - set_bit(IHOST_START_PENDING, &ihost->flags); - - spin_lock_irq(&ihost->scic_lock); - sci_controller_start(ihost, tmo); - sci_controller_enable_interrupts(ihost); - spin_unlock_irq(&ihost->scic_lock); -} - -static void isci_host_stop_complete(struct isci_host *ihost, enum sci_status completion_status) -{ - isci_host_change_state(ihost, isci_stopped); - sci_controller_disable_interrupts(ihost); - clear_bit(IHOST_STOP_PENDING, &ihost->flags); - wake_up(&ihost->eventq); -} - -static void sci_controller_completion_handler(struct isci_host *ihost) -{ - /* Empty out the completion queue */ - if (sci_controller_completion_queue_has_entries(ihost)) - sci_controller_process_completions(ihost); - - /* Clear the interrupt and enable all interrupts again */ - writel(SMU_ISR_COMPLETION, &ihost->smu_registers->interrupt_status); - /* Could we write the value of SMU_ISR_COMPLETION? */ - writel(0xFF000000, &ihost->smu_registers->interrupt_mask); - writel(0, &ihost->smu_registers->interrupt_mask); -} - -/** - * isci_host_completion_routine() - This function is the delayed service - * routine that calls the sci core library's completion handler. It's - * scheduled as a tasklet from the interrupt service routine when interrupts - * in use, or set as the timeout function in polled mode. - * @data: This parameter specifies the ISCI host object - * - */ -static void isci_host_completion_routine(unsigned long data) -{ - struct isci_host *ihost = (struct isci_host *)data; - struct list_head completed_request_list; - struct list_head errored_request_list; - struct list_head *current_position; - struct list_head *next_position; - struct isci_request *request; - struct isci_request *next_request; - struct sas_task *task; - u16 active; - - INIT_LIST_HEAD(&completed_request_list); - INIT_LIST_HEAD(&errored_request_list); - - spin_lock_irq(&ihost->scic_lock); - - sci_controller_completion_handler(ihost); - - /* Take the lists of completed I/Os from the host. */ - - list_splice_init(&ihost->requests_to_complete, - &completed_request_list); - - /* Take the list of errored I/Os from the host. */ - list_splice_init(&ihost->requests_to_errorback, - &errored_request_list); - - spin_unlock_irq(&ihost->scic_lock); - - /* Process any completions in the lists. */ - list_for_each_safe(current_position, next_position, - &completed_request_list) { - - request = list_entry(current_position, struct isci_request, - completed_node); - task = isci_request_access_task(request); - - /* Normal notification (task_done) */ - dev_dbg(&ihost->pdev->dev, - "%s: Normal - request/task = %p/%p\n", - __func__, - request, - task); - - /* Return the task to libsas */ - if (task != NULL) { - - task->lldd_task = NULL; - if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - - /* If the task is already in the abort path, - * the task_done callback cannot be called. - */ - task->task_done(task); - } - } - - spin_lock_irq(&ihost->scic_lock); - isci_free_tag(ihost, request->io_tag); - spin_unlock_irq(&ihost->scic_lock); - } - list_for_each_entry_safe(request, next_request, &errored_request_list, - completed_node) { - - task = isci_request_access_task(request); - - /* Use sas_task_abort */ - dev_warn(&ihost->pdev->dev, - "%s: Error - request/task = %p/%p\n", - __func__, - request, - task); - - if (task != NULL) { - - /* Put the task into the abort path if it's not there - * already. - */ - if (!(task->task_state_flags & SAS_TASK_STATE_ABORTED)) - sas_task_abort(task); - - } else { - /* This is a case where the request has completed with a - * status such that it needed further target servicing, - * but the sas_task reference has already been removed - * from the request. Since it was errored, it was not - * being aborted, so there is nothing to do except free - * it. - */ - - spin_lock_irq(&ihost->scic_lock); - /* Remove the request from the remote device's list - * of pending requests. - */ - list_del_init(&request->dev_node); - isci_free_tag(ihost, request->io_tag); - spin_unlock_irq(&ihost->scic_lock); - } - } - - /* the coalesence timeout doubles at each encoding step, so - * update it based on the ilog2 value of the outstanding requests - */ - active = isci_tci_active(ihost); - writel(SMU_ICC_GEN_VAL(NUMBER, active) | - SMU_ICC_GEN_VAL(TIMER, ISCI_COALESCE_BASE + ilog2(active)), - &ihost->smu_registers->interrupt_coalesce_control); -} - -/** - * sci_controller_stop() - This method will stop an individual controller - * object.This method will invoke the associated user callback upon - * completion. The completion callback is called when the following - * conditions are met: -# the method return status is SCI_SUCCESS. -# the - * controller has been quiesced. This method will ensure that all IO - * requests are quiesced, phys are stopped, and all additional operation by - * the hardware is halted. - * @controller: the handle to the controller object to stop. - * @timeout: This parameter specifies the number of milliseconds in which the - * stop operation should complete. - * - * The controller must be in the STARTED or STOPPED state. Indicate if the - * controller stop method succeeded or failed in some way. SCI_SUCCESS if the - * stop operation successfully began. SCI_WARNING_ALREADY_IN_STATE if the - * controller is already in the STOPPED state. SCI_FAILURE_INVALID_STATE if the - * controller is not either in the STARTED or STOPPED states. - */ -static enum sci_status sci_controller_stop(struct isci_host *ihost, u32 timeout) -{ - if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, - "SCIC Controller stop operation requested in " - "invalid state\n"); - return SCI_FAILURE_INVALID_STATE; - } - - sci_mod_timer(&ihost->timer, timeout); - sci_change_state(&ihost->sm, SCIC_STOPPING); - return SCI_SUCCESS; -} - -/** - * sci_controller_reset() - This method will reset the supplied core - * controller regardless of the state of said controller. This operation is - * considered destructive. In other words, all current operations are wiped - * out. No IO completions for outstanding devices occur. Outstanding IO - * requests are not aborted or completed at the actual remote device. - * @controller: the handle to the controller object to reset. - * - * Indicate if the controller reset method succeeded or failed in some way. - * SCI_SUCCESS if the reset operation successfully started. SCI_FATAL_ERROR if - * the controller reset operation is unable to complete. - */ -static enum sci_status sci_controller_reset(struct isci_host *ihost) -{ - switch (ihost->sm.current_state_id) { - case SCIC_RESET: - case SCIC_READY: - case SCIC_STOPPED: - case SCIC_FAILED: - /* - * The reset operation is not a graceful cleanup, just - * perform the state transition. - */ - sci_change_state(&ihost->sm, SCIC_RESETTING); - return SCI_SUCCESS; - default: - dev_warn(&ihost->pdev->dev, - "SCIC Controller reset operation requested in " - "invalid state\n"); - return SCI_FAILURE_INVALID_STATE; - } -} - -void isci_host_deinit(struct isci_host *ihost) -{ - int i; - - /* disable output data selects */ - for (i = 0; i < isci_gpio_count(ihost); i++) - writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]); - - isci_host_change_state(ihost, isci_stopping); - for (i = 0; i < SCI_MAX_PORTS; i++) { - struct isci_port *iport = &ihost->ports[i]; - struct isci_remote_device *idev, *d; - - list_for_each_entry_safe(idev, d, &iport->remote_dev_list, node) { - if (test_bit(IDEV_ALLOCATED, &idev->flags)) - isci_remote_device_stop(ihost, idev); - } - } - - set_bit(IHOST_STOP_PENDING, &ihost->flags); - - spin_lock_irq(&ihost->scic_lock); - sci_controller_stop(ihost, SCIC_CONTROLLER_STOP_TIMEOUT); - spin_unlock_irq(&ihost->scic_lock); - - wait_for_stop(ihost); - - /* disable sgpio: where the above wait should give time for the - * enclosure to sample the gpios going inactive - */ - writel(0, &ihost->scu_registers->peg0.sgpio.interface_control); - - sci_controller_reset(ihost); - - /* Cancel any/all outstanding port timers */ - for (i = 0; i < ihost->logical_port_entries; i++) { - struct isci_port *iport = &ihost->ports[i]; - del_timer_sync(&iport->timer.timer); - } - - /* Cancel any/all outstanding phy timers */ - for (i = 0; i < SCI_MAX_PHYS; i++) { - struct isci_phy *iphy = &ihost->phys[i]; - del_timer_sync(&iphy->sata_timer.timer); - } - - del_timer_sync(&ihost->port_agent.timer.timer); - - del_timer_sync(&ihost->power_control.timer.timer); - - del_timer_sync(&ihost->timer.timer); - - del_timer_sync(&ihost->phy_timer.timer); -} - -static void __iomem *scu_base(struct isci_host *isci_host) -{ - struct pci_dev *pdev = isci_host->pdev; - int id = isci_host->id; - - return pcim_iomap_table(pdev)[SCI_SCU_BAR * 2] + SCI_SCU_BAR_SIZE * id; -} - -static void __iomem *smu_base(struct isci_host *isci_host) -{ - struct pci_dev *pdev = isci_host->pdev; - int id = isci_host->id; - - return pcim_iomap_table(pdev)[SCI_SMU_BAR * 2] + SCI_SMU_BAR_SIZE * id; -} - -static void isci_user_parameters_get(struct sci_user_parameters *u) -{ - int i; - - for (i = 0; i < SCI_MAX_PHYS; i++) { - struct sci_phy_user_params *u_phy = &u->phys[i]; - - u_phy->max_speed_generation = phy_gen; - - /* we are not exporting these for now */ - u_phy->align_insertion_frequency = 0x7f; - u_phy->in_connection_align_insertion_frequency = 0xff; - u_phy->notify_enable_spin_up_insertion_frequency = 0x33; - } - - u->stp_inactivity_timeout = stp_inactive_to; - u->ssp_inactivity_timeout = ssp_inactive_to; - u->stp_max_occupancy_timeout = stp_max_occ_to; - u->ssp_max_occupancy_timeout = ssp_max_occ_to; - u->no_outbound_task_timeout = no_outbound_task_to; - u->max_concurr_spinup = max_concurr_spinup; -} - -static void sci_controller_initial_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - - sci_change_state(&ihost->sm, SCIC_RESET); -} - -static inline void sci_controller_starting_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - - sci_del_timer(&ihost->timer); -} - -#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS 853 -#define INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS 1280 -#define INTERRUPT_COALESCE_TIMEOUT_MAX_US 2700000 -#define INTERRUPT_COALESCE_NUMBER_MAX 256 -#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN 7 -#define INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX 28 - -/** - * sci_controller_set_interrupt_coalescence() - This method allows the user to - * configure the interrupt coalescence. - * @controller: This parameter represents the handle to the controller object - * for which its interrupt coalesce register is overridden. - * @coalesce_number: Used to control the number of entries in the Completion - * Queue before an interrupt is generated. If the number of entries exceed - * this number, an interrupt will be generated. The valid range of the input - * is [0, 256]. A setting of 0 results in coalescing being disabled. - * @coalesce_timeout: Timeout value in microseconds. The valid range of the - * input is [0, 2700000] . A setting of 0 is allowed and results in no - * interrupt coalescing timeout. - * - * Indicate if the user successfully set the interrupt coalesce parameters. - * SCI_SUCCESS The user successfully updated the interrutp coalescence. - * SCI_FAILURE_INVALID_PARAMETER_VALUE The user input value is out of range. - */ -static enum sci_status -sci_controller_set_interrupt_coalescence(struct isci_host *ihost, - u32 coalesce_number, - u32 coalesce_timeout) -{ - u8 timeout_encode = 0; - u32 min = 0; - u32 max = 0; - - /* Check if the input parameters fall in the range. */ - if (coalesce_number > INTERRUPT_COALESCE_NUMBER_MAX) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - /* - * Defined encoding for interrupt coalescing timeout: - * Value Min Max Units - * ----- --- --- ----- - * 0 - - Disabled - * 1 13.3 20.0 ns - * 2 26.7 40.0 - * 3 53.3 80.0 - * 4 106.7 160.0 - * 5 213.3 320.0 - * 6 426.7 640.0 - * 7 853.3 1280.0 - * 8 1.7 2.6 us - * 9 3.4 5.1 - * 10 6.8 10.2 - * 11 13.7 20.5 - * 12 27.3 41.0 - * 13 54.6 81.9 - * 14 109.2 163.8 - * 15 218.5 327.7 - * 16 436.9 655.4 - * 17 873.8 1310.7 - * 18 1.7 2.6 ms - * 19 3.5 5.2 - * 20 7.0 10.5 - * 21 14.0 21.0 - * 22 28.0 41.9 - * 23 55.9 83.9 - * 24 111.8 167.8 - * 25 223.7 335.5 - * 26 447.4 671.1 - * 27 894.8 1342.2 - * 28 1.8 2.7 s - * Others Undefined */ - - /* - * Use the table above to decide the encode of interrupt coalescing timeout - * value for register writing. */ - if (coalesce_timeout == 0) - timeout_encode = 0; - else{ - /* make the timeout value in unit of (10 ns). */ - coalesce_timeout = coalesce_timeout * 100; - min = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_LOWER_BOUND_NS / 10; - max = INTERRUPT_COALESCE_TIMEOUT_BASE_RANGE_UPPER_BOUND_NS / 10; - - /* get the encode of timeout for register writing. */ - for (timeout_encode = INTERRUPT_COALESCE_TIMEOUT_ENCODE_MIN; - timeout_encode <= INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX; - timeout_encode++) { - if (min <= coalesce_timeout && max > coalesce_timeout) - break; - else if (coalesce_timeout >= max && coalesce_timeout < min * 2 - && coalesce_timeout <= INTERRUPT_COALESCE_TIMEOUT_MAX_US * 100) { - if ((coalesce_timeout - max) < (2 * min - coalesce_timeout)) - break; - else{ - timeout_encode++; - break; - } - } else { - max = max * 2; - min = min * 2; - } - } - - if (timeout_encode == INTERRUPT_COALESCE_TIMEOUT_ENCODE_MAX + 1) - /* the value is out of range. */ - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - } - - writel(SMU_ICC_GEN_VAL(NUMBER, coalesce_number) | - SMU_ICC_GEN_VAL(TIMER, timeout_encode), - &ihost->smu_registers->interrupt_coalesce_control); - - - ihost->interrupt_coalesce_number = (u16)coalesce_number; - ihost->interrupt_coalesce_timeout = coalesce_timeout / 100; - - return SCI_SUCCESS; -} - - -static void sci_controller_ready_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - u32 val; - - /* enable clock gating for power control of the scu unit */ - val = readl(&ihost->smu_registers->clock_gating_control); - val &= ~(SMU_CGUCR_GEN_BIT(REGCLK_ENABLE) | - SMU_CGUCR_GEN_BIT(TXCLK_ENABLE) | - SMU_CGUCR_GEN_BIT(XCLK_ENABLE)); - val |= SMU_CGUCR_GEN_BIT(IDLE_ENABLE); - writel(val, &ihost->smu_registers->clock_gating_control); - - /* set the default interrupt coalescence number and timeout value. */ - sci_controller_set_interrupt_coalescence(ihost, 0, 0); -} - -static void sci_controller_ready_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - - /* disable interrupt coalescence. */ - sci_controller_set_interrupt_coalescence(ihost, 0, 0); -} - -static enum sci_status sci_controller_stop_phys(struct isci_host *ihost) -{ - u32 index; - enum sci_status status; - enum sci_status phy_status; - - status = SCI_SUCCESS; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - phy_status = sci_phy_stop(&ihost->phys[index]); - - if (phy_status != SCI_SUCCESS && - phy_status != SCI_FAILURE_INVALID_STATE) { - status = SCI_FAILURE; - - dev_warn(&ihost->pdev->dev, - "%s: Controller stop operation failed to stop " - "phy %d because of status %d.\n", - __func__, - ihost->phys[index].phy_index, phy_status); - } - } - - return status; -} - -static enum sci_status sci_controller_stop_ports(struct isci_host *ihost) -{ - u32 index; - enum sci_status port_status; - enum sci_status status = SCI_SUCCESS; - - for (index = 0; index < ihost->logical_port_entries; index++) { - struct isci_port *iport = &ihost->ports[index]; - - port_status = sci_port_stop(iport); - - if ((port_status != SCI_SUCCESS) && - (port_status != SCI_FAILURE_INVALID_STATE)) { - status = SCI_FAILURE; - - dev_warn(&ihost->pdev->dev, - "%s: Controller stop operation failed to " - "stop port %d because of status %d.\n", - __func__, - iport->logical_port_index, - port_status); - } - } - - return status; -} - -static enum sci_status sci_controller_stop_devices(struct isci_host *ihost) -{ - u32 index; - enum sci_status status; - enum sci_status device_status; - - status = SCI_SUCCESS; - - for (index = 0; index < ihost->remote_node_entries; index++) { - if (ihost->device_table[index] != NULL) { - /* / @todo What timeout value do we want to provide to this request? */ - device_status = sci_remote_device_stop(ihost->device_table[index], 0); - - if ((device_status != SCI_SUCCESS) && - (device_status != SCI_FAILURE_INVALID_STATE)) { - dev_warn(&ihost->pdev->dev, - "%s: Controller stop operation failed " - "to stop device 0x%p because of " - "status %d.\n", - __func__, - ihost->device_table[index], device_status); - } - } - } - - return status; -} - -static void sci_controller_stopping_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - - /* Stop all of the components for this controller */ - sci_controller_stop_phys(ihost); - sci_controller_stop_ports(ihost); - sci_controller_stop_devices(ihost); -} - -static void sci_controller_stopping_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - - sci_del_timer(&ihost->timer); -} - -static void sci_controller_reset_hardware(struct isci_host *ihost) -{ - /* Disable interrupts so we dont take any spurious interrupts */ - sci_controller_disable_interrupts(ihost); - - /* Reset the SCU */ - writel(0xFFFFFFFF, &ihost->smu_registers->soft_reset_control); - - /* Delay for 1ms to before clearing the CQP and UFQPR. */ - udelay(1000); - - /* The write to the CQGR clears the CQP */ - writel(0x00000000, &ihost->smu_registers->completion_queue_get); - - /* The write to the UFQGP clears the UFQPR */ - writel(0, &ihost->scu_registers->sdma.unsolicited_frame_get_pointer); -} - -static void sci_controller_resetting_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_host *ihost = container_of(sm, typeof(*ihost), sm); - - sci_controller_reset_hardware(ihost); - sci_change_state(&ihost->sm, SCIC_RESET); -} - -static const struct sci_base_state sci_controller_state_table[] = { - [SCIC_INITIAL] = { - .enter_state = sci_controller_initial_state_enter, - }, - [SCIC_RESET] = {}, - [SCIC_INITIALIZING] = {}, - [SCIC_INITIALIZED] = {}, - [SCIC_STARTING] = { - .exit_state = sci_controller_starting_state_exit, - }, - [SCIC_READY] = { - .enter_state = sci_controller_ready_state_enter, - .exit_state = sci_controller_ready_state_exit, - }, - [SCIC_RESETTING] = { - .enter_state = sci_controller_resetting_state_enter, - }, - [SCIC_STOPPING] = { - .enter_state = sci_controller_stopping_state_enter, - .exit_state = sci_controller_stopping_state_exit, - }, - [SCIC_STOPPED] = {}, - [SCIC_FAILED] = {} -}; - -static void sci_controller_set_default_config_parameters(struct isci_host *ihost) -{ - /* these defaults are overridden by the platform / firmware */ - u16 index; - - /* Default to APC mode. */ - ihost->oem_parameters.controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; - - /* Default to APC mode. */ - ihost->oem_parameters.controller.max_concurr_spin_up = 1; - - /* Default to no SSC operation. */ - ihost->oem_parameters.controller.do_enable_ssc = false; - - /* Default to short cables on all phys. */ - ihost->oem_parameters.controller.cable_selection_mask = 0; - - /* Initialize all of the port parameter information to narrow ports. */ - for (index = 0; index < SCI_MAX_PORTS; index++) { - ihost->oem_parameters.ports[index].phy_mask = 0; - } - - /* Initialize all of the phy parameter information. */ - for (index = 0; index < SCI_MAX_PHYS; index++) { - /* Default to 3G (i.e. Gen 2). */ - ihost->user_parameters.phys[index].max_speed_generation = - SCIC_SDS_PARM_GEN2_SPEED; - - /* the frequencies cannot be 0 */ - ihost->user_parameters.phys[index].align_insertion_frequency = 0x7f; - ihost->user_parameters.phys[index].in_connection_align_insertion_frequency = 0xff; - ihost->user_parameters.phys[index].notify_enable_spin_up_insertion_frequency = 0x33; - - /* - * Previous Vitesse based expanders had a arbitration issue that - * is worked around by having the upper 32-bits of SAS address - * with a value greater then the Vitesse company identifier. - * Hence, usage of 0x5FCFFFFF. */ - ihost->oem_parameters.phys[index].sas_address.low = 0x1 + ihost->id; - ihost->oem_parameters.phys[index].sas_address.high = 0x5FCFFFFF; - } - - ihost->user_parameters.stp_inactivity_timeout = 5; - ihost->user_parameters.ssp_inactivity_timeout = 5; - ihost->user_parameters.stp_max_occupancy_timeout = 5; - ihost->user_parameters.ssp_max_occupancy_timeout = 20; - ihost->user_parameters.no_outbound_task_timeout = 2; -} - -static void controller_timeout(unsigned long data) -{ - struct sci_timer *tmr = (struct sci_timer *)data; - struct isci_host *ihost = container_of(tmr, typeof(*ihost), timer); - struct sci_base_state_machine *sm = &ihost->sm; - unsigned long flags; - - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmr->cancel) - goto done; - - if (sm->current_state_id == SCIC_STARTING) - sci_controller_transition_to_ready(ihost, SCI_FAILURE_TIMEOUT); - else if (sm->current_state_id == SCIC_STOPPING) { - sci_change_state(sm, SCIC_FAILED); - isci_host_stop_complete(ihost, SCI_FAILURE_TIMEOUT); - } else /* / @todo Now what do we want to do in this case? */ - dev_err(&ihost->pdev->dev, - "%s: Controller timer fired when controller was not " - "in a state being timed.\n", - __func__); - -done: - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - -static enum sci_status sci_controller_construct(struct isci_host *ihost, - void __iomem *scu_base, - void __iomem *smu_base) -{ - u8 i; - - sci_init_sm(&ihost->sm, sci_controller_state_table, SCIC_INITIAL); - - ihost->scu_registers = scu_base; - ihost->smu_registers = smu_base; - - sci_port_configuration_agent_construct(&ihost->port_agent); - - /* Construct the ports for this controller */ - for (i = 0; i < SCI_MAX_PORTS; i++) - sci_port_construct(&ihost->ports[i], i, ihost); - sci_port_construct(&ihost->ports[i], SCIC_SDS_DUMMY_PORT, ihost); - - /* Construct the phys for this controller */ - for (i = 0; i < SCI_MAX_PHYS; i++) { - /* Add all the PHYs to the dummy port */ - sci_phy_construct(&ihost->phys[i], - &ihost->ports[SCI_MAX_PORTS], i); - } - - ihost->invalid_phy_mask = 0; - - sci_init_timer(&ihost->timer, controller_timeout); - - /* Initialize the User and OEM parameters to default values. */ - sci_controller_set_default_config_parameters(ihost); - - return sci_controller_reset(ihost); -} - -int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version) -{ - int i; - - for (i = 0; i < SCI_MAX_PORTS; i++) - if (oem->ports[i].phy_mask > SCIC_SDS_PARM_PHY_MASK_MAX) - return -EINVAL; - - for (i = 0; i < SCI_MAX_PHYS; i++) - if (oem->phys[i].sas_address.high == 0 && - oem->phys[i].sas_address.low == 0) - return -EINVAL; - - if (oem->controller.mode_type == SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) { - for (i = 0; i < SCI_MAX_PHYS; i++) - if (oem->ports[i].phy_mask != 0) - return -EINVAL; - } else if (oem->controller.mode_type == SCIC_PORT_MANUAL_CONFIGURATION_MODE) { - u8 phy_mask = 0; - - for (i = 0; i < SCI_MAX_PHYS; i++) - phy_mask |= oem->ports[i].phy_mask; - - if (phy_mask == 0) - return -EINVAL; - } else - return -EINVAL; - - if (oem->controller.max_concurr_spin_up > MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT || - oem->controller.max_concurr_spin_up < 1) - return -EINVAL; - - if (oem->controller.do_enable_ssc) { - if (version < ISCI_ROM_VER_1_1 && oem->controller.do_enable_ssc != 1) - return -EINVAL; - - if (version >= ISCI_ROM_VER_1_1) { - u8 test = oem->controller.ssc_sata_tx_spread_level; - - switch (test) { - case 0: - case 2: - case 3: - case 6: - case 7: - break; - default: - return -EINVAL; - } - - test = oem->controller.ssc_sas_tx_spread_level; - if (oem->controller.ssc_sas_tx_type == 0) { - switch (test) { - case 0: - case 2: - case 3: - break; - default: - return -EINVAL; - } - } else if (oem->controller.ssc_sas_tx_type == 1) { - switch (test) { - case 0: - case 3: - case 6: - break; - default: - return -EINVAL; - } - } - } - } - - return 0; -} - -static enum sci_status sci_oem_parameters_set(struct isci_host *ihost) -{ - u32 state = ihost->sm.current_state_id; - struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); - - if (state == SCIC_RESET || - state == SCIC_INITIALIZING || - state == SCIC_INITIALIZED) { - u8 oem_version = pci_info->orom ? pci_info->orom->hdr.version : - ISCI_ROM_VER_1_0; - - if (sci_oem_parameters_validate(&ihost->oem_parameters, - oem_version)) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - return SCI_SUCCESS; - } - - return SCI_FAILURE_INVALID_STATE; -} - -static u8 max_spin_up(struct isci_host *ihost) -{ - if (ihost->user_parameters.max_concurr_spinup) - return min_t(u8, ihost->user_parameters.max_concurr_spinup, - MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT); - else - return min_t(u8, ihost->oem_parameters.controller.max_concurr_spin_up, - MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT); -} - -static void power_control_timeout(unsigned long data) -{ - struct sci_timer *tmr = (struct sci_timer *)data; - struct isci_host *ihost = container_of(tmr, typeof(*ihost), power_control.timer); - struct isci_phy *iphy; - unsigned long flags; - u8 i; - - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmr->cancel) - goto done; - - ihost->power_control.phys_granted_power = 0; - - if (ihost->power_control.phys_waiting == 0) { - ihost->power_control.timer_started = false; - goto done; - } - - for (i = 0; i < SCI_MAX_PHYS; i++) { - - if (ihost->power_control.phys_waiting == 0) - break; - - iphy = ihost->power_control.requesters[i]; - if (iphy == NULL) - continue; - - if (ihost->power_control.phys_granted_power >= max_spin_up(ihost)) - break; - - ihost->power_control.requesters[i] = NULL; - ihost->power_control.phys_waiting--; - ihost->power_control.phys_granted_power++; - sci_phy_consume_power_handler(iphy); - - if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { - u8 j; - - for (j = 0; j < SCI_MAX_PHYS; j++) { - struct isci_phy *requester = ihost->power_control.requesters[j]; - - /* - * Search the power_control queue to see if there are other phys - * attached to the same remote device. If found, take all of - * them out of await_sas_power state. - */ - if (requester != NULL && requester != iphy) { - u8 other = memcmp(requester->frame_rcvd.iaf.sas_addr, - iphy->frame_rcvd.iaf.sas_addr, - sizeof(requester->frame_rcvd.iaf.sas_addr)); - - if (other == 0) { - ihost->power_control.requesters[j] = NULL; - ihost->power_control.phys_waiting--; - sci_phy_consume_power_handler(requester); - } - } - } - } - } - - /* - * It doesn't matter if the power list is empty, we need to start the - * timer in case another phy becomes ready. - */ - sci_mod_timer(tmr, SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL); - ihost->power_control.timer_started = true; - -done: - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - -void sci_controller_power_control_queue_insert(struct isci_host *ihost, - struct isci_phy *iphy) -{ - BUG_ON(iphy == NULL); - - if (ihost->power_control.phys_granted_power < max_spin_up(ihost)) { - ihost->power_control.phys_granted_power++; - sci_phy_consume_power_handler(iphy); - - /* - * stop and start the power_control timer. When the timer fires, the - * no_of_phys_granted_power will be set to 0 - */ - if (ihost->power_control.timer_started) - sci_del_timer(&ihost->power_control.timer); - - sci_mod_timer(&ihost->power_control.timer, - SCIC_SDS_CONTROLLER_POWER_CONTROL_INTERVAL); - ihost->power_control.timer_started = true; - - } else { - /* - * There are phys, attached to the same sas address as this phy, are - * already in READY state, this phy don't need wait. - */ - u8 i; - struct isci_phy *current_phy; - - for (i = 0; i < SCI_MAX_PHYS; i++) { - u8 other; - current_phy = &ihost->phys[i]; - - other = memcmp(current_phy->frame_rcvd.iaf.sas_addr, - iphy->frame_rcvd.iaf.sas_addr, - sizeof(current_phy->frame_rcvd.iaf.sas_addr)); - - if (current_phy->sm.current_state_id == SCI_PHY_READY && - current_phy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS && - other == 0) { - sci_phy_consume_power_handler(iphy); - break; - } - } - - if (i == SCI_MAX_PHYS) { - /* Add the phy in the waiting list */ - ihost->power_control.requesters[iphy->phy_index] = iphy; - ihost->power_control.phys_waiting++; - } - } -} - -void sci_controller_power_control_queue_remove(struct isci_host *ihost, - struct isci_phy *iphy) -{ - BUG_ON(iphy == NULL); - - if (ihost->power_control.requesters[iphy->phy_index]) - ihost->power_control.phys_waiting--; - - ihost->power_control.requesters[iphy->phy_index] = NULL; -} - -static int is_long_cable(int phy, unsigned char selection_byte) -{ - return !!(selection_byte & (1 << phy)); -} - -static int is_medium_cable(int phy, unsigned char selection_byte) -{ - return !!(selection_byte & (1 << (phy + 4))); -} - -static enum cable_selections decode_selection_byte( - int phy, - unsigned char selection_byte) -{ - return ((selection_byte & (1 << phy)) ? 1 : 0) - + (selection_byte & (1 << (phy + 4)) ? 2 : 0); -} - -static unsigned char *to_cable_select(struct isci_host *ihost) -{ - if (is_cable_select_overridden()) - return ((unsigned char *)&cable_selection_override) - + ihost->id; - else - return &ihost->oem_parameters.controller.cable_selection_mask; -} - -enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy) -{ - return decode_selection_byte(phy, *to_cable_select(ihost)); -} - -char *lookup_cable_names(enum cable_selections selection) -{ - static char *cable_names[] = { - [short_cable] = "short", - [long_cable] = "long", - [medium_cable] = "medium", - [undefined_cable] = "" /* bit 0==1 */ - }; - return (selection <= undefined_cable) ? cable_names[selection] - : cable_names[undefined_cable]; -} - -#define AFE_REGISTER_WRITE_DELAY 10 - -static void sci_controller_afe_initialization(struct isci_host *ihost) -{ - struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; - const struct sci_oem_params *oem = &ihost->oem_parameters; - struct pci_dev *pdev = ihost->pdev; - u32 afe_status; - u32 phy_id; - unsigned char cable_selection_mask = *to_cable_select(ihost); - - /* Clear DFX Status registers */ - writel(0x0081000f, &afe->afe_dfx_master_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - - if (is_b0(pdev) || is_c0(pdev) || is_c1(pdev)) { - /* PM Rx Equalization Save, PM SPhy Rx Acknowledgement - * Timer, PM Stagger Timer - */ - writel(0x0007FFFF, &afe->afe_pmsn_master_control2); - udelay(AFE_REGISTER_WRITE_DELAY); - } - - /* Configure bias currents to normal */ - if (is_a2(pdev)) - writel(0x00005A00, &afe->afe_bias_control); - else if (is_b0(pdev) || is_c0(pdev)) - writel(0x00005F00, &afe->afe_bias_control); - else if (is_c1(pdev)) - writel(0x00005500, &afe->afe_bias_control); - - udelay(AFE_REGISTER_WRITE_DELAY); - - /* Enable PLL */ - if (is_a2(pdev)) - writel(0x80040908, &afe->afe_pll_control0); - else if (is_b0(pdev) || is_c0(pdev)) - writel(0x80040A08, &afe->afe_pll_control0); - else if (is_c1(pdev)) { - writel(0x80000B08, &afe->afe_pll_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - writel(0x00000B08, &afe->afe_pll_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - writel(0x80000B08, &afe->afe_pll_control0); - } - - udelay(AFE_REGISTER_WRITE_DELAY); - - /* Wait for the PLL to lock */ - do { - afe_status = readl(&afe->afe_common_block_status); - udelay(AFE_REGISTER_WRITE_DELAY); - } while ((afe_status & 0x00001000) == 0); - - if (is_a2(pdev)) { - /* Shorten SAS SNW lock time (RxLock timer value from 76 - * us to 50 us) - */ - writel(0x7bcc96ad, &afe->afe_pmsn_master_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - } - - for (phy_id = 0; phy_id < SCI_MAX_PHYS; phy_id++) { - struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_id]; - const struct sci_phy_oem_params *oem_phy = &oem->phys[phy_id]; - int cable_length_long = - is_long_cable(phy_id, cable_selection_mask); - int cable_length_medium = - is_medium_cable(phy_id, cable_selection_mask); - - if (is_a2(pdev)) { - /* All defaults, except the Receive Word - * Alignament/Comma Detect Enable....(0xe800) - */ - writel(0x00004512, &xcvr->afe_xcvr_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(0x0050100F, &xcvr->afe_xcvr_control1); - udelay(AFE_REGISTER_WRITE_DELAY); - } else if (is_b0(pdev)) { - /* Configure transmitter SSC parameters */ - writel(0x00030000, &xcvr->afe_tx_ssc_control); - udelay(AFE_REGISTER_WRITE_DELAY); - } else if (is_c0(pdev)) { - /* Configure transmitter SSC parameters */ - writel(0x00010202, &xcvr->afe_tx_ssc_control); - udelay(AFE_REGISTER_WRITE_DELAY); - - /* All defaults, except the Receive Word - * Alignament/Comma Detect Enable....(0xe800) - */ - writel(0x00014500, &xcvr->afe_xcvr_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - } else if (is_c1(pdev)) { - /* Configure transmitter SSC parameters */ - writel(0x00010202, &xcvr->afe_tx_ssc_control); - udelay(AFE_REGISTER_WRITE_DELAY); - - /* All defaults, except the Receive Word - * Alignament/Comma Detect Enable....(0xe800) - */ - writel(0x0001C500, &xcvr->afe_xcvr_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - } - - /* Power up TX and RX out from power down (PWRDNTX and - * PWRDNRX) & increase TX int & ext bias 20%....(0xe85c) - */ - if (is_a2(pdev)) - writel(0x000003F0, &xcvr->afe_channel_control); - else if (is_b0(pdev)) { - writel(0x000003D7, &xcvr->afe_channel_control); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(0x000003D4, &xcvr->afe_channel_control); - } else if (is_c0(pdev)) { - writel(0x000001E7, &xcvr->afe_channel_control); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(0x000001E4, &xcvr->afe_channel_control); - } else if (is_c1(pdev)) { - writel(cable_length_long ? 0x000002F7 : 0x000001F7, - &xcvr->afe_channel_control); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(cable_length_long ? 0x000002F4 : 0x000001F4, - &xcvr->afe_channel_control); - } - udelay(AFE_REGISTER_WRITE_DELAY); - - if (is_a2(pdev)) { - /* Enable TX equalization (0xe824) */ - writel(0x00040000, &xcvr->afe_tx_control); - udelay(AFE_REGISTER_WRITE_DELAY); - } - - if (is_a2(pdev) || is_b0(pdev)) - /* RDPI=0x0(RX Power On), RXOOBDETPDNC=0x0, - * TPD=0x0(TX Power On), RDD=0x0(RX Detect - * Enabled) ....(0xe800) - */ - writel(0x00004100, &xcvr->afe_xcvr_control0); - else if (is_c0(pdev)) - writel(0x00014100, &xcvr->afe_xcvr_control0); - else if (is_c1(pdev)) - writel(0x0001C100, &xcvr->afe_xcvr_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - - /* Leave DFE/FFE on */ - if (is_a2(pdev)) - writel(0x3F11103F, &xcvr->afe_rx_ssc_control0); - else if (is_b0(pdev)) { - writel(0x3F11103F, &xcvr->afe_rx_ssc_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - /* Enable TX equalization (0xe824) */ - writel(0x00040000, &xcvr->afe_tx_control); - } else if (is_c0(pdev)) { - writel(0x01400C0F, &xcvr->afe_rx_ssc_control1); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(0x3F6F103F, &xcvr->afe_rx_ssc_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - - /* Enable TX equalization (0xe824) */ - writel(0x00040000, &xcvr->afe_tx_control); - } else if (is_c1(pdev)) { - writel(cable_length_long ? 0x01500C0C : - cable_length_medium ? 0x01400C0D : 0x02400C0D, - &xcvr->afe_xcvr_control1); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(0x000003E0, &xcvr->afe_dfx_rx_control1); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(cable_length_long ? 0x33091C1F : - cable_length_medium ? 0x3315181F : 0x2B17161F, - &xcvr->afe_rx_ssc_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - - /* Enable TX equalization (0xe824) */ - writel(0x00040000, &xcvr->afe_tx_control); - } - - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(oem_phy->afe_tx_amp_control0, &xcvr->afe_tx_amp_control0); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(oem_phy->afe_tx_amp_control1, &xcvr->afe_tx_amp_control1); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(oem_phy->afe_tx_amp_control2, &xcvr->afe_tx_amp_control2); - udelay(AFE_REGISTER_WRITE_DELAY); - - writel(oem_phy->afe_tx_amp_control3, &xcvr->afe_tx_amp_control3); - udelay(AFE_REGISTER_WRITE_DELAY); - } - - /* Transfer control to the PEs */ - writel(0x00010f00, &afe->afe_dfx_master_control0); - udelay(AFE_REGISTER_WRITE_DELAY); -} - -static void sci_controller_initialize_power_control(struct isci_host *ihost) -{ - sci_init_timer(&ihost->power_control.timer, power_control_timeout); - - memset(ihost->power_control.requesters, 0, - sizeof(ihost->power_control.requesters)); - - ihost->power_control.phys_waiting = 0; - ihost->power_control.phys_granted_power = 0; -} - -static enum sci_status sci_controller_initialize(struct isci_host *ihost) -{ - struct sci_base_state_machine *sm = &ihost->sm; - enum sci_status result = SCI_FAILURE; - unsigned long i, state, val; - - if (ihost->sm.current_state_id != SCIC_RESET) { - dev_warn(&ihost->pdev->dev, - "SCIC Controller initialize operation requested " - "in invalid state\n"); - return SCI_FAILURE_INVALID_STATE; - } - - sci_change_state(sm, SCIC_INITIALIZING); - - sci_init_timer(&ihost->phy_timer, phy_startup_timeout); - - ihost->next_phy_to_start = 0; - ihost->phy_startup_timer_pending = false; - - sci_controller_initialize_power_control(ihost); - - /* - * There is nothing to do here for B0 since we do not have to - * program the AFE registers. - * / @todo The AFE settings are supposed to be correct for the B0 but - * / presently they seem to be wrong. */ - sci_controller_afe_initialization(ihost); - - - /* Take the hardware out of reset */ - writel(0, &ihost->smu_registers->soft_reset_control); - - /* - * / @todo Provide meaningfull error code for hardware failure - * result = SCI_FAILURE_CONTROLLER_HARDWARE; */ - for (i = 100; i >= 1; i--) { - u32 status; - - /* Loop until the hardware reports success */ - udelay(SCU_CONTEXT_RAM_INIT_STALL_TIME); - status = readl(&ihost->smu_registers->control_status); - - if ((status & SCU_RAM_INIT_COMPLETED) == SCU_RAM_INIT_COMPLETED) - break; - } - if (i == 0) - goto out; - - /* - * Determine what are the actaul device capacities that the - * hardware will support */ - val = readl(&ihost->smu_registers->device_context_capacity); - - /* Record the smaller of the two capacity values */ - ihost->logical_port_entries = min(smu_max_ports(val), SCI_MAX_PORTS); - ihost->task_context_entries = min(smu_max_task_contexts(val), SCI_MAX_IO_REQUESTS); - ihost->remote_node_entries = min(smu_max_rncs(val), SCI_MAX_REMOTE_DEVICES); - - /* - * Make all PEs that are unassigned match up with the - * logical ports - */ - for (i = 0; i < ihost->logical_port_entries; i++) { - struct scu_port_task_scheduler_group_registers __iomem - *ptsg = &ihost->scu_registers->peg0.ptsg; - - writel(i, &ptsg->protocol_engine[i]); - } - - /* Initialize hardware PCI Relaxed ordering in DMA engines */ - val = readl(&ihost->scu_registers->sdma.pdma_configuration); - val |= SCU_PDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE); - writel(val, &ihost->scu_registers->sdma.pdma_configuration); - - val = readl(&ihost->scu_registers->sdma.cdma_configuration); - val |= SCU_CDMACR_GEN_BIT(PCI_RELAXED_ORDERING_ENABLE); - writel(val, &ihost->scu_registers->sdma.cdma_configuration); - - /* - * Initialize the PHYs before the PORTs because the PHY registers - * are accessed during the port initialization. - */ - for (i = 0; i < SCI_MAX_PHYS; i++) { - result = sci_phy_initialize(&ihost->phys[i], - &ihost->scu_registers->peg0.pe[i].tl, - &ihost->scu_registers->peg0.pe[i].ll); - if (result != SCI_SUCCESS) - goto out; - } - - for (i = 0; i < ihost->logical_port_entries; i++) { - struct isci_port *iport = &ihost->ports[i]; - - iport->port_task_scheduler_registers = &ihost->scu_registers->peg0.ptsg.port[i]; - iport->port_pe_configuration_register = &ihost->scu_registers->peg0.ptsg.protocol_engine[0]; - iport->viit_registers = &ihost->scu_registers->peg0.viit[i]; - } - - result = sci_port_configuration_agent_initialize(ihost, &ihost->port_agent); - - out: - /* Advance the controller state machine */ - if (result == SCI_SUCCESS) - state = SCIC_INITIALIZED; - else - state = SCIC_FAILED; - sci_change_state(sm, state); - - return result; -} - -static enum sci_status sci_user_parameters_set(struct isci_host *ihost, - struct sci_user_parameters *sci_parms) -{ - u32 state = ihost->sm.current_state_id; - - if (state == SCIC_RESET || - state == SCIC_INITIALIZING || - state == SCIC_INITIALIZED) { - u16 index; - - /* - * Validate the user parameters. If they are not legal, then - * return a failure. - */ - for (index = 0; index < SCI_MAX_PHYS; index++) { - struct sci_phy_user_params *user_phy; - - user_phy = &sci_parms->phys[index]; - - if (!((user_phy->max_speed_generation <= - SCIC_SDS_PARM_MAX_SPEED) && - (user_phy->max_speed_generation > - SCIC_SDS_PARM_NO_SPEED))) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - if (user_phy->in_connection_align_insertion_frequency < - 3) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - if ((user_phy->in_connection_align_insertion_frequency < - 3) || - (user_phy->align_insertion_frequency == 0) || - (user_phy-> - notify_enable_spin_up_insertion_frequency == - 0)) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - } - - if ((sci_parms->stp_inactivity_timeout == 0) || - (sci_parms->ssp_inactivity_timeout == 0) || - (sci_parms->stp_max_occupancy_timeout == 0) || - (sci_parms->ssp_max_occupancy_timeout == 0) || - (sci_parms->no_outbound_task_timeout == 0)) - return SCI_FAILURE_INVALID_PARAMETER_VALUE; - - memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms)); - - return SCI_SUCCESS; - } - - return SCI_FAILURE_INVALID_STATE; -} - -static int sci_controller_mem_init(struct isci_host *ihost) -{ - struct device *dev = &ihost->pdev->dev; - dma_addr_t dma; - size_t size; - int err; - - size = SCU_MAX_COMPLETION_QUEUE_ENTRIES * sizeof(u32); - ihost->completion_queue = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL); - if (!ihost->completion_queue) - return -ENOMEM; - - writel(lower_32_bits(dma), &ihost->smu_registers->completion_queue_lower); - writel(upper_32_bits(dma), &ihost->smu_registers->completion_queue_upper); - - size = ihost->remote_node_entries * sizeof(union scu_remote_node_context); - ihost->remote_node_context_table = dmam_alloc_coherent(dev, size, &dma, - GFP_KERNEL); - if (!ihost->remote_node_context_table) - return -ENOMEM; - - writel(lower_32_bits(dma), &ihost->smu_registers->remote_node_context_lower); - writel(upper_32_bits(dma), &ihost->smu_registers->remote_node_context_upper); - - size = ihost->task_context_entries * sizeof(struct scu_task_context), - ihost->task_context_table = dmam_alloc_coherent(dev, size, &dma, GFP_KERNEL); - if (!ihost->task_context_table) - return -ENOMEM; - - ihost->task_context_dma = dma; - writel(lower_32_bits(dma), &ihost->smu_registers->host_task_table_lower); - writel(upper_32_bits(dma), &ihost->smu_registers->host_task_table_upper); - - err = sci_unsolicited_frame_control_construct(ihost); - if (err) - return err; - - /* - * Inform the silicon as to the location of the UF headers and - * address table. - */ - writel(lower_32_bits(ihost->uf_control.headers.physical_address), - &ihost->scu_registers->sdma.uf_header_base_address_lower); - writel(upper_32_bits(ihost->uf_control.headers.physical_address), - &ihost->scu_registers->sdma.uf_header_base_address_upper); - - writel(lower_32_bits(ihost->uf_control.address_table.physical_address), - &ihost->scu_registers->sdma.uf_address_table_lower); - writel(upper_32_bits(ihost->uf_control.address_table.physical_address), - &ihost->scu_registers->sdma.uf_address_table_upper); - - return 0; -} - -int isci_host_init(struct isci_host *ihost) -{ - int err = 0, i; - enum sci_status status; - struct sci_user_parameters sci_user_params; - struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); - - spin_lock_init(&ihost->state_lock); - spin_lock_init(&ihost->scic_lock); - init_waitqueue_head(&ihost->eventq); - - isci_host_change_state(ihost, isci_starting); - - status = sci_controller_construct(ihost, scu_base(ihost), - smu_base(ihost)); - - if (status != SCI_SUCCESS) { - dev_err(&ihost->pdev->dev, - "%s: sci_controller_construct failed - status = %x\n", - __func__, - status); - return -ENODEV; - } - - ihost->sas_ha.dev = &ihost->pdev->dev; - ihost->sas_ha.lldd_ha = ihost; - - /* - * grab initial values stored in the controller object for OEM and USER - * parameters - */ - isci_user_parameters_get(&sci_user_params); - status = sci_user_parameters_set(ihost, &sci_user_params); - if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, - "%s: sci_user_parameters_set failed\n", - __func__); - return -ENODEV; - } - - /* grab any OEM parameters specified in orom */ - if (pci_info->orom) { - status = isci_parse_oem_parameters(&ihost->oem_parameters, - pci_info->orom, - ihost->id); - if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, - "parsing firmware oem parameters failed\n"); - return -EINVAL; - } - } - - status = sci_oem_parameters_set(ihost); - if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, - "%s: sci_oem_parameters_set failed\n", - __func__); - return -ENODEV; - } - - tasklet_init(&ihost->completion_tasklet, - isci_host_completion_routine, (unsigned long)ihost); - - INIT_LIST_HEAD(&ihost->requests_to_complete); - INIT_LIST_HEAD(&ihost->requests_to_errorback); - - spin_lock_irq(&ihost->scic_lock); - status = sci_controller_initialize(ihost); - spin_unlock_irq(&ihost->scic_lock); - if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, - "%s: sci_controller_initialize failed -" - " status = 0x%x\n", - __func__, status); - return -ENODEV; - } - - err = sci_controller_mem_init(ihost); - if (err) - return err; - - for (i = 0; i < SCI_MAX_PORTS; i++) - isci_port_init(&ihost->ports[i], ihost, i); - - for (i = 0; i < SCI_MAX_PHYS; i++) - isci_phy_init(&ihost->phys[i], ihost, i); - - /* enable sgpio */ - writel(1, &ihost->scu_registers->peg0.sgpio.interface_control); - for (i = 0; i < isci_gpio_count(ihost); i++) - writel(SGPIO_HW_CONTROL, &ihost->scu_registers->peg0.sgpio.output_data_select[i]); - writel(0, &ihost->scu_registers->peg0.sgpio.vendor_specific_code); - - for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { - struct isci_remote_device *idev = &ihost->devices[i]; - - INIT_LIST_HEAD(&idev->reqs_in_process); - INIT_LIST_HEAD(&idev->node); - } - - for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) { - struct isci_request *ireq; - dma_addr_t dma; - - ireq = dmam_alloc_coherent(&ihost->pdev->dev, - sizeof(struct isci_request), &dma, - GFP_KERNEL); - if (!ireq) - return -ENOMEM; - - ireq->tc = &ihost->task_context_table[i]; - ireq->owning_controller = ihost; - spin_lock_init(&ireq->state_lock); - ireq->request_daddr = dma; - ireq->isci_host = ihost; - ihost->reqs[i] = ireq; - } - - return 0; -} - -void sci_controller_link_up(struct isci_host *ihost, struct isci_port *iport, - struct isci_phy *iphy) -{ - switch (ihost->sm.current_state_id) { - case SCIC_STARTING: - sci_del_timer(&ihost->phy_timer); - ihost->phy_startup_timer_pending = false; - ihost->port_agent.link_up_handler(ihost, &ihost->port_agent, - iport, iphy); - sci_controller_start_next_phy(ihost); - break; - case SCIC_READY: - ihost->port_agent.link_up_handler(ihost, &ihost->port_agent, - iport, iphy); - break; - default: - dev_dbg(&ihost->pdev->dev, - "%s: SCIC Controller linkup event from phy %d in " - "unexpected state %d\n", __func__, iphy->phy_index, - ihost->sm.current_state_id); - } -} - -void sci_controller_link_down(struct isci_host *ihost, struct isci_port *iport, - struct isci_phy *iphy) -{ - switch (ihost->sm.current_state_id) { - case SCIC_STARTING: - case SCIC_READY: - ihost->port_agent.link_down_handler(ihost, &ihost->port_agent, - iport, iphy); - break; - default: - dev_dbg(&ihost->pdev->dev, - "%s: SCIC Controller linkdown event from phy %d in " - "unexpected state %d\n", - __func__, - iphy->phy_index, - ihost->sm.current_state_id); - } -} - -static bool sci_controller_has_remote_devices_stopping(struct isci_host *ihost) -{ - u32 index; - - for (index = 0; index < ihost->remote_node_entries; index++) { - if ((ihost->device_table[index] != NULL) && - (ihost->device_table[index]->sm.current_state_id == SCI_DEV_STOPPING)) - return true; - } - - return false; -} - -void sci_controller_remote_device_stopped(struct isci_host *ihost, - struct isci_remote_device *idev) -{ - if (ihost->sm.current_state_id != SCIC_STOPPING) { - dev_dbg(&ihost->pdev->dev, - "SCIC Controller 0x%p remote device stopped event " - "from device 0x%p in unexpected state %d\n", - ihost, idev, - ihost->sm.current_state_id); - return; - } - - if (!sci_controller_has_remote_devices_stopping(ihost)) - sci_change_state(&ihost->sm, SCIC_STOPPED); -} - -void sci_controller_post_request(struct isci_host *ihost, u32 request) -{ - dev_dbg(&ihost->pdev->dev, "%s[%d]: %#x\n", - __func__, ihost->id, request); - - writel(request, &ihost->smu_registers->post_context_port); -} - -struct isci_request *sci_request_by_tag(struct isci_host *ihost, u16 io_tag) -{ - u16 task_index; - u16 task_sequence; - - task_index = ISCI_TAG_TCI(io_tag); - - if (task_index < ihost->task_context_entries) { - struct isci_request *ireq = ihost->reqs[task_index]; - - if (test_bit(IREQ_ACTIVE, &ireq->flags)) { - task_sequence = ISCI_TAG_SEQ(io_tag); - - if (task_sequence == ihost->io_request_sequence[task_index]) - return ireq; - } - } - - return NULL; -} - -/** - * This method allocates remote node index and the reserves the remote node - * context space for use. This method can fail if there are no more remote - * node index available. - * @scic: This is the controller object which contains the set of - * free remote node ids - * @sci_dev: This is the device object which is requesting the a remote node - * id - * @node_id: This is the remote node id that is assinged to the device if one - * is available - * - * enum sci_status SCI_FAILURE_OUT_OF_RESOURCES if there are no available remote - * node index available. - */ -enum sci_status sci_controller_allocate_remote_node_context(struct isci_host *ihost, - struct isci_remote_device *idev, - u16 *node_id) -{ - u16 node_index; - u32 remote_node_count = sci_remote_device_node_count(idev); - - node_index = sci_remote_node_table_allocate_remote_node( - &ihost->available_remote_nodes, remote_node_count - ); - - if (node_index != SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) { - ihost->device_table[node_index] = idev; - - *node_id = node_index; - - return SCI_SUCCESS; - } - - return SCI_FAILURE_INSUFFICIENT_RESOURCES; -} - -void sci_controller_free_remote_node_context(struct isci_host *ihost, - struct isci_remote_device *idev, - u16 node_id) -{ - u32 remote_node_count = sci_remote_device_node_count(idev); - - if (ihost->device_table[node_id] == idev) { - ihost->device_table[node_id] = NULL; - - sci_remote_node_table_release_remote_node_index( - &ihost->available_remote_nodes, remote_node_count, node_id - ); - } -} - -void sci_controller_copy_sata_response(void *response_buffer, - void *frame_header, - void *frame_buffer) -{ - /* XXX type safety? */ - memcpy(response_buffer, frame_header, sizeof(u32)); - - memcpy(response_buffer + sizeof(u32), - frame_buffer, - sizeof(struct dev_to_host_fis) - sizeof(u32)); -} - -void sci_controller_release_frame(struct isci_host *ihost, u32 frame_index) -{ - if (sci_unsolicited_frame_control_release_frame(&ihost->uf_control, frame_index)) - writel(ihost->uf_control.get, - &ihost->scu_registers->sdma.unsolicited_frame_get_pointer); -} - -void isci_tci_free(struct isci_host *ihost, u16 tci) -{ - u16 tail = ihost->tci_tail & (SCI_MAX_IO_REQUESTS-1); - - ihost->tci_pool[tail] = tci; - ihost->tci_tail = tail + 1; -} - -static u16 isci_tci_alloc(struct isci_host *ihost) -{ - u16 head = ihost->tci_head & (SCI_MAX_IO_REQUESTS-1); - u16 tci = ihost->tci_pool[head]; - - ihost->tci_head = head + 1; - return tci; -} - -static u16 isci_tci_space(struct isci_host *ihost) -{ - return CIRC_SPACE(ihost->tci_head, ihost->tci_tail, SCI_MAX_IO_REQUESTS); -} - -u16 isci_alloc_tag(struct isci_host *ihost) -{ - if (isci_tci_space(ihost)) { - u16 tci = isci_tci_alloc(ihost); - u8 seq = ihost->io_request_sequence[tci]; - - return ISCI_TAG(seq, tci); - } - - return SCI_CONTROLLER_INVALID_IO_TAG; -} - -enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag) -{ - u16 tci = ISCI_TAG_TCI(io_tag); - u16 seq = ISCI_TAG_SEQ(io_tag); - - /* prevent tail from passing head */ - if (isci_tci_active(ihost) == 0) - return SCI_FAILURE_INVALID_IO_TAG; - - if (seq == ihost->io_request_sequence[tci]) { - ihost->io_request_sequence[tci] = (seq+1) & (SCI_MAX_SEQ-1); - - isci_tci_free(ihost, tci); - - return SCI_SUCCESS; - } - return SCI_FAILURE_INVALID_IO_TAG; -} - -enum sci_status sci_controller_start_io(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - enum sci_status status; - - if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, "invalid state to start I/O"); - return SCI_FAILURE_INVALID_STATE; - } - - status = sci_remote_device_start_io(ihost, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - set_bit(IREQ_ACTIVE, &ireq->flags); - sci_controller_post_request(ihost, ireq->post_context); - return SCI_SUCCESS; -} - -enum sci_status sci_controller_terminate_request(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - /* terminate an ongoing (i.e. started) core IO request. This does not - * abort the IO request at the target, but rather removes the IO - * request from the host controller. - */ - enum sci_status status; - - if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, - "invalid state to terminate request\n"); - return SCI_FAILURE_INVALID_STATE; - } - - status = sci_io_request_terminate(ireq); - if (status != SCI_SUCCESS) - return status; - - /* - * Utilize the original post context command and or in the POST_TC_ABORT - * request sub-type. - */ - sci_controller_post_request(ihost, - ireq->post_context | SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT); - return SCI_SUCCESS; -} - -/** - * sci_controller_complete_io() - This method will perform core specific - * completion operations for an IO request. After this method is invoked, - * the user should consider the IO request as invalid until it is properly - * reused (i.e. re-constructed). - * @ihost: The handle to the controller object for which to complete the - * IO request. - * @idev: The handle to the remote device object for which to complete - * the IO request. - * @ireq: the handle to the io request object to complete. - */ -enum sci_status sci_controller_complete_io(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - enum sci_status status; - u16 index; - - switch (ihost->sm.current_state_id) { - case SCIC_STOPPING: - /* XXX: Implement this function */ - return SCI_FAILURE; - case SCIC_READY: - status = sci_remote_device_complete_io(ihost, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - index = ISCI_TAG_TCI(ireq->io_tag); - clear_bit(IREQ_ACTIVE, &ireq->flags); - return SCI_SUCCESS; - default: - dev_warn(&ihost->pdev->dev, "invalid state to complete I/O"); - return SCI_FAILURE_INVALID_STATE; - } - -} - -enum sci_status sci_controller_continue_io(struct isci_request *ireq) -{ - struct isci_host *ihost = ireq->owning_controller; - - if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, "invalid state to continue I/O"); - return SCI_FAILURE_INVALID_STATE; - } - - set_bit(IREQ_ACTIVE, &ireq->flags); - sci_controller_post_request(ihost, ireq->post_context); - return SCI_SUCCESS; -} - -/** - * sci_controller_start_task() - This method is called by the SCIC user to - * send/start a framework task management request. - * @controller: the handle to the controller object for which to start the task - * management request. - * @remote_device: the handle to the remote device object for which to start - * the task management request. - * @task_request: the handle to the task request object to start. - */ -enum sci_task_status sci_controller_start_task(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - enum sci_status status; - - if (ihost->sm.current_state_id != SCIC_READY) { - dev_warn(&ihost->pdev->dev, - "%s: SCIC Controller starting task from invalid " - "state\n", - __func__); - return SCI_TASK_FAILURE_INVALID_STATE; - } - - status = sci_remote_device_start_task(ihost, idev, ireq); - switch (status) { - case SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS: - set_bit(IREQ_ACTIVE, &ireq->flags); - - /* - * We will let framework know this task request started successfully, - * although core is still woring on starting the request (to post tc when - * RNC is resumed.) - */ - return SCI_SUCCESS; - case SCI_SUCCESS: - set_bit(IREQ_ACTIVE, &ireq->flags); - sci_controller_post_request(ihost, ireq->post_context); - break; - default: - break; - } - - return status; -} - -static int sci_write_gpio_tx_gp(struct isci_host *ihost, u8 reg_index, u8 reg_count, u8 *write_data) -{ - int d; - - /* no support for TX_GP_CFG */ - if (reg_index == 0) - return -EINVAL; - - for (d = 0; d < isci_gpio_count(ihost); d++) { - u32 val = 0x444; /* all ODx.n clear */ - int i; - - for (i = 0; i < 3; i++) { - int bit = (i << 2) + 2; - - bit = try_test_sas_gpio_gp_bit(to_sas_gpio_od(d, i), - write_data, reg_index, - reg_count); - if (bit < 0) - break; - - /* if od is set, clear the 'invert' bit */ - val &= ~(bit << ((i << 2) + 2)); - } - - if (i < 3) - break; - writel(val, &ihost->scu_registers->peg0.sgpio.output_data_select[d]); - } - - /* unless reg_index is > 1, we should always be able to write at - * least one register - */ - return d > 0; -} - -int isci_gpio_write(struct sas_ha_struct *sas_ha, u8 reg_type, u8 reg_index, - u8 reg_count, u8 *write_data) -{ - struct isci_host *ihost = sas_ha->lldd_ha; - int written; - - switch (reg_type) { - case SAS_GPIO_REG_TX_GP: - written = sci_write_gpio_tx_gp(ihost, reg_index, reg_count, write_data); - break; - default: - written = -EINVAL; - } - - return written; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/host.h b/ANDROID_3.4.5/drivers/scsi/isci/host.h deleted file mode 100644 index adbad69d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/host.h +++ /dev/null @@ -1,568 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _SCI_HOST_H_ -#define _SCI_HOST_H_ - -#include "remote_device.h" -#include "phy.h" -#include "isci.h" -#include "remote_node_table.h" -#include "registers.h" -#include "unsolicited_frame_control.h" -#include "probe_roms.h" - -struct isci_request; -struct scu_task_context; - - -/** - * struct sci_power_control - - * - * This structure defines the fields for managing power control for direct - * attached disk devices. - */ -struct sci_power_control { - /** - * This field is set when the power control timer is running and cleared when - * it is not. - */ - bool timer_started; - - /** - * Timer to control when the directed attached disks can consume power. - */ - struct sci_timer timer; - - /** - * This field is used to keep track of how many phys are put into the - * requesters field. - */ - u8 phys_waiting; - - /** - * This field is used to keep track of how many phys have been granted to consume power - */ - u8 phys_granted_power; - - /** - * This field is an array of phys that we are waiting on. The phys are direct - * mapped into requesters via struct sci_phy.phy_index - */ - struct isci_phy *requesters[SCI_MAX_PHYS]; - -}; - -struct sci_port_configuration_agent; -typedef void (*port_config_fn)(struct isci_host *, - struct sci_port_configuration_agent *, - struct isci_port *, struct isci_phy *); - -struct sci_port_configuration_agent { - u16 phy_configured_mask; - u16 phy_ready_mask; - struct { - u8 min_index; - u8 max_index; - } phy_valid_port_range[SCI_MAX_PHYS]; - bool timer_pending; - port_config_fn link_up_handler; - port_config_fn link_down_handler; - struct sci_timer timer; -}; - -/** - * isci_host - primary host/controller object - * @timer: timeout start/stop operations - * @device_table: rni (hw remote node index) to remote device lookup table - * @available_remote_nodes: rni allocator - * @power_control: manage device spin up - * @io_request_sequence: generation number for tci's (task contexts) - * @task_context_table: hw task context table - * @remote_node_context_table: hw remote node context table - * @completion_queue: hw-producer driver-consumer communication ring - * @completion_queue_get: tracks the driver 'head' of the ring to notify hw - * @logical_port_entries: min({driver|silicon}-supported-port-count) - * @remote_node_entries: min({driver|silicon}-supported-node-count) - * @task_context_entries: min({driver|silicon}-supported-task-count) - * @phy_timer: phy startup timer - * @invalid_phy_mask: if an invalid_link_up notification is reported a bit for - * the phy index is set so further notifications are not - * made. Once the phy reports link up and is made part of a - * port then this bit is cleared. - - */ -struct isci_host { - struct sci_base_state_machine sm; - /* XXX can we time this externally */ - struct sci_timer timer; - /* XXX drop reference module params directly */ - struct sci_user_parameters user_parameters; - /* XXX no need to be a union */ - struct sci_oem_params oem_parameters; - struct sci_port_configuration_agent port_agent; - struct isci_remote_device *device_table[SCI_MAX_REMOTE_DEVICES]; - struct sci_remote_node_table available_remote_nodes; - struct sci_power_control power_control; - u8 io_request_sequence[SCI_MAX_IO_REQUESTS]; - struct scu_task_context *task_context_table; - dma_addr_t task_context_dma; - union scu_remote_node_context *remote_node_context_table; - u32 *completion_queue; - u32 completion_queue_get; - u32 logical_port_entries; - u32 remote_node_entries; - u32 task_context_entries; - struct sci_unsolicited_frame_control uf_control; - - /* phy startup */ - struct sci_timer phy_timer; - /* XXX kill */ - bool phy_startup_timer_pending; - u32 next_phy_to_start; - /* XXX convert to unsigned long and use bitops */ - u8 invalid_phy_mask; - - /* TODO attempt dynamic interrupt coalescing scheme */ - u16 interrupt_coalesce_number; - u32 interrupt_coalesce_timeout; - struct smu_registers __iomem *smu_registers; - struct scu_registers __iomem *scu_registers; - - u16 tci_head; - u16 tci_tail; - u16 tci_pool[SCI_MAX_IO_REQUESTS]; - - int id; /* unique within a given pci device */ - struct isci_phy phys[SCI_MAX_PHYS]; - struct isci_port ports[SCI_MAX_PORTS + 1]; /* includes dummy port */ - struct asd_sas_port sas_ports[SCI_MAX_PORTS]; - struct sas_ha_struct sas_ha; - - spinlock_t state_lock; - struct pci_dev *pdev; - enum isci_status status; - #define IHOST_START_PENDING 0 - #define IHOST_STOP_PENDING 1 - unsigned long flags; - wait_queue_head_t eventq; - struct Scsi_Host *shost; - struct tasklet_struct completion_tasklet; - struct list_head requests_to_complete; - struct list_head requests_to_errorback; - spinlock_t scic_lock; - struct isci_request *reqs[SCI_MAX_IO_REQUESTS]; - struct isci_remote_device devices[SCI_MAX_REMOTE_DEVICES]; -}; - -/** - * enum sci_controller_states - This enumeration depicts all the states - * for the common controller state machine. - */ -enum sci_controller_states { - /** - * Simply the initial state for the base controller state machine. - */ - SCIC_INITIAL = 0, - - /** - * This state indicates that the controller is reset. The memory for - * the controller is in it's initial state, but the controller requires - * initialization. - * This state is entered from the INITIAL state. - * This state is entered from the RESETTING state. - */ - SCIC_RESET, - - /** - * This state is typically an action state that indicates the controller - * is in the process of initialization. In this state no new IO operations - * are permitted. - * This state is entered from the RESET state. - */ - SCIC_INITIALIZING, - - /** - * This state indicates that the controller has been successfully - * initialized. In this state no new IO operations are permitted. - * This state is entered from the INITIALIZING state. - */ - SCIC_INITIALIZED, - - /** - * This state indicates the the controller is in the process of becoming - * ready (i.e. starting). In this state no new IO operations are permitted. - * This state is entered from the INITIALIZED state. - */ - SCIC_STARTING, - - /** - * This state indicates the controller is now ready. Thus, the user - * is able to perform IO operations on the controller. - * This state is entered from the STARTING state. - */ - SCIC_READY, - - /** - * This state is typically an action state that indicates the controller - * is in the process of resetting. Thus, the user is unable to perform - * IO operations on the controller. A reset is considered destructive in - * most cases. - * This state is entered from the READY state. - * This state is entered from the FAILED state. - * This state is entered from the STOPPED state. - */ - SCIC_RESETTING, - - /** - * This state indicates that the controller is in the process of stopping. - * In this state no new IO operations are permitted, but existing IO - * operations are allowed to complete. - * This state is entered from the READY state. - */ - SCIC_STOPPING, - - /** - * This state indicates that the controller has successfully been stopped. - * In this state no new IO operations are permitted. - * This state is entered from the STOPPING state. - */ - SCIC_STOPPED, - - /** - * This state indicates that the controller could not successfully be - * initialized. In this state no new IO operations are permitted. - * This state is entered from the INITIALIZING state. - * This state is entered from the STARTING state. - * This state is entered from the STOPPING state. - * This state is entered from the RESETTING state. - */ - SCIC_FAILED, -}; - -/** - * struct isci_pci_info - This class represents the pci function containing the - * controllers. Depending on PCI SKU, there could be up to 2 controllers in - * the PCI function. - */ -#define SCI_MAX_MSIX_INT (SCI_NUM_MSI_X_INT*SCI_MAX_CONTROLLERS) - -struct isci_pci_info { - struct msix_entry msix_entries[SCI_MAX_MSIX_INT]; - struct isci_host *hosts[SCI_MAX_CONTROLLERS]; - struct isci_orom *orom; -}; - -static inline struct isci_pci_info *to_pci_info(struct pci_dev *pdev) -{ - return pci_get_drvdata(pdev); -} - -#define for_each_isci_host(id, ihost, pdev) \ - for (id = 0, ihost = to_pci_info(pdev)->hosts[id]; \ - id < ARRAY_SIZE(to_pci_info(pdev)->hosts) && ihost; \ - ihost = to_pci_info(pdev)->hosts[++id]) - -static inline enum isci_status isci_host_get_state(struct isci_host *isci_host) -{ - return isci_host->status; -} - -static inline void isci_host_change_state(struct isci_host *isci_host, - enum isci_status status) -{ - unsigned long flags; - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_host = %p, state = 0x%x", - __func__, - isci_host, - status); - spin_lock_irqsave(&isci_host->state_lock, flags); - isci_host->status = status; - spin_unlock_irqrestore(&isci_host->state_lock, flags); - -} - -static inline void wait_for_start(struct isci_host *ihost) -{ - wait_event(ihost->eventq, !test_bit(IHOST_START_PENDING, &ihost->flags)); -} - -static inline void wait_for_stop(struct isci_host *ihost) -{ - wait_event(ihost->eventq, !test_bit(IHOST_STOP_PENDING, &ihost->flags)); -} - -static inline void wait_for_device_start(struct isci_host *ihost, struct isci_remote_device *idev) -{ - wait_event(ihost->eventq, !test_bit(IDEV_START_PENDING, &idev->flags)); -} - -static inline void wait_for_device_stop(struct isci_host *ihost, struct isci_remote_device *idev) -{ - wait_event(ihost->eventq, !test_bit(IDEV_STOP_PENDING, &idev->flags)); -} - -static inline struct isci_host *dev_to_ihost(struct domain_device *dev) -{ - return dev->port->ha->lldd_ha; -} - -/* we always use protocol engine group zero */ -#define ISCI_PEG 0 - -/* see sci_controller_io_tag_allocate|free for how seq and tci are built */ -#define ISCI_TAG(seq, tci) (((u16) (seq)) << 12 | tci) - -/* these are returned by the hardware, so sanitize them */ -#define ISCI_TAG_SEQ(tag) (((tag) >> 12) & (SCI_MAX_SEQ-1)) -#define ISCI_TAG_TCI(tag) ((tag) & (SCI_MAX_IO_REQUESTS-1)) - -/* interrupt coalescing baseline: 9 == 3 to 5us interrupt delay per command */ -#define ISCI_COALESCE_BASE 9 - -/* expander attached sata devices require 3 rnc slots */ -static inline int sci_remote_device_node_count(struct isci_remote_device *idev) -{ - struct domain_device *dev = idev->domain_dev; - - if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) && - !idev->is_direct_attached) - return SCU_STP_REMOTE_NODE_COUNT; - return SCU_SSP_REMOTE_NODE_COUNT; -} - -/** - * sci_controller_clear_invalid_phy() - - * - * This macro will clear the bit in the invalid phy mask for this controller - * object. This is used to control messages reported for invalid link up - * notifications. - */ -#define sci_controller_clear_invalid_phy(controller, phy) \ - ((controller)->invalid_phy_mask &= ~(1 << (phy)->phy_index)) - -static inline struct device *scirdev_to_dev(struct isci_remote_device *idev) -{ - if (!idev || !idev->isci_port || !idev->isci_port->isci_host) - return NULL; - - return &idev->isci_port->isci_host->pdev->dev; -} - -static inline bool is_a2(struct pci_dev *pdev) -{ - if (pdev->revision < 4) - return true; - return false; -} - -static inline bool is_b0(struct pci_dev *pdev) -{ - if (pdev->revision == 4) - return true; - return false; -} - -static inline bool is_c0(struct pci_dev *pdev) -{ - if (pdev->revision == 5) - return true; - return false; -} - -static inline bool is_c1(struct pci_dev *pdev) -{ - if (pdev->revision >= 6) - return true; - return false; -} - -enum cable_selections { - short_cable = 0, - long_cable = 1, - medium_cable = 2, - undefined_cable = 3 -}; - -#define CABLE_OVERRIDE_DISABLED (0x10000) - -static inline int is_cable_select_overridden(void) -{ - return cable_selection_override < CABLE_OVERRIDE_DISABLED; -} - -enum cable_selections decode_cable_selection(struct isci_host *ihost, int phy); -void validate_cable_selections(struct isci_host *ihost); -char *lookup_cable_names(enum cable_selections); - -/* set hw control for 'activity', even though active enclosures seem to drive - * the activity led on their own. Skip setting FSENG control on 'status' due - * to unexpected operation and 'error' due to not being a supported automatic - * FSENG output - */ -#define SGPIO_HW_CONTROL 0x00000443 - -static inline int isci_gpio_count(struct isci_host *ihost) -{ - return ARRAY_SIZE(ihost->scu_registers->peg0.sgpio.output_data_select); -} - -void sci_controller_post_request(struct isci_host *ihost, - u32 request); -void sci_controller_release_frame(struct isci_host *ihost, - u32 frame_index); -void sci_controller_copy_sata_response(void *response_buffer, - void *frame_header, - void *frame_buffer); -enum sci_status sci_controller_allocate_remote_node_context(struct isci_host *ihost, - struct isci_remote_device *idev, - u16 *node_id); -void sci_controller_free_remote_node_context( - struct isci_host *ihost, - struct isci_remote_device *idev, - u16 node_id); - -struct isci_request *sci_request_by_tag(struct isci_host *ihost, - u16 io_tag); - -void sci_controller_power_control_queue_insert( - struct isci_host *ihost, - struct isci_phy *iphy); - -void sci_controller_power_control_queue_remove( - struct isci_host *ihost, - struct isci_phy *iphy); - -void sci_controller_link_up( - struct isci_host *ihost, - struct isci_port *iport, - struct isci_phy *iphy); - -void sci_controller_link_down( - struct isci_host *ihost, - struct isci_port *iport, - struct isci_phy *iphy); - -void sci_controller_remote_device_stopped( - struct isci_host *ihost, - struct isci_remote_device *idev); - -void sci_controller_copy_task_context( - struct isci_host *ihost, - struct isci_request *ireq); - -void sci_controller_register_setup(struct isci_host *ihost); - -enum sci_status sci_controller_continue_io(struct isci_request *ireq); -int isci_host_scan_finished(struct Scsi_Host *, unsigned long); -void isci_host_scan_start(struct Scsi_Host *); -u16 isci_alloc_tag(struct isci_host *ihost); -enum sci_status isci_free_tag(struct isci_host *ihost, u16 io_tag); -void isci_tci_free(struct isci_host *ihost, u16 tci); - -int isci_host_init(struct isci_host *); - -void isci_host_init_controller_names( - struct isci_host *isci_host, - unsigned int controller_idx); - -void isci_host_deinit( - struct isci_host *); - -void isci_host_port_link_up( - struct isci_host *, - struct isci_port *, - struct isci_phy *); -int isci_host_dev_found(struct domain_device *); - -void isci_host_remote_device_start_complete( - struct isci_host *, - struct isci_remote_device *, - enum sci_status); - -void sci_controller_disable_interrupts( - struct isci_host *ihost); - -enum sci_status sci_controller_start_io( - struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq); - -enum sci_task_status sci_controller_start_task( - struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq); - -enum sci_status sci_controller_terminate_request( - struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq); - -enum sci_status sci_controller_complete_io( - struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq); - -void sci_port_configuration_agent_construct( - struct sci_port_configuration_agent *port_agent); - -enum sci_status sci_port_configuration_agent_initialize( - struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent); - -int isci_gpio_write(struct sas_ha_struct *, u8 reg_type, u8 reg_index, - u8 reg_count, u8 *write_data); -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/isci/init.c b/ANDROID_3.4.5/drivers/scsi/isci/init.c deleted file mode 100644 index bc6cf888..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/init.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "host.h" -#include "isci.h" -#include "task.h" -#include "probe_roms.h" - -#define MAJ 1 -#define MIN 1 -#define BUILD 0 -#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ - __stringify(BUILD) - -MODULE_VERSION(DRV_VERSION); - -static struct scsi_transport_template *isci_transport_template; - -static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = { - { PCI_VDEVICE(INTEL, 0x1D61),}, - { PCI_VDEVICE(INTEL, 0x1D63),}, - { PCI_VDEVICE(INTEL, 0x1D65),}, - { PCI_VDEVICE(INTEL, 0x1D67),}, - { PCI_VDEVICE(INTEL, 0x1D69),}, - { PCI_VDEVICE(INTEL, 0x1D6B),}, - { PCI_VDEVICE(INTEL, 0x1D60),}, - { PCI_VDEVICE(INTEL, 0x1D62),}, - { PCI_VDEVICE(INTEL, 0x1D64),}, - { PCI_VDEVICE(INTEL, 0x1D66),}, - { PCI_VDEVICE(INTEL, 0x1D68),}, - { PCI_VDEVICE(INTEL, 0x1D6A),}, - {} -}; - -MODULE_DEVICE_TABLE(pci, isci_id_table); - -/* linux isci specific settings */ - -unsigned char no_outbound_task_to = 2; -module_param(no_outbound_task_to, byte, 0); -MODULE_PARM_DESC(no_outbound_task_to, "No Outbound Task Timeout (1us incr)"); - -u16 ssp_max_occ_to = 20; -module_param(ssp_max_occ_to, ushort, 0); -MODULE_PARM_DESC(ssp_max_occ_to, "SSP Max occupancy timeout (100us incr)"); - -u16 stp_max_occ_to = 5; -module_param(stp_max_occ_to, ushort, 0); -MODULE_PARM_DESC(stp_max_occ_to, "STP Max occupancy timeout (100us incr)"); - -u16 ssp_inactive_to = 5; -module_param(ssp_inactive_to, ushort, 0); -MODULE_PARM_DESC(ssp_inactive_to, "SSP inactivity timeout (100us incr)"); - -u16 stp_inactive_to = 5; -module_param(stp_inactive_to, ushort, 0); -MODULE_PARM_DESC(stp_inactive_to, "STP inactivity timeout (100us incr)"); - -unsigned char phy_gen = SCIC_SDS_PARM_GEN2_SPEED; -module_param(phy_gen, byte, 0); -MODULE_PARM_DESC(phy_gen, "PHY generation (1: 1.5Gbps 2: 3.0Gbps 3: 6.0Gbps)"); - -unsigned char max_concurr_spinup; -module_param(max_concurr_spinup, byte, 0); -MODULE_PARM_DESC(max_concurr_spinup, "Max concurrent device spinup"); - -uint cable_selection_override = CABLE_OVERRIDE_DISABLED; -module_param(cable_selection_override, uint, 0); - -MODULE_PARM_DESC(cable_selection_override, - "This field indicates length of the SAS/SATA cable between " - "host and device. If any bits > 15 are set (default) " - "indicates \"use platform defaults\""); - -static ssize_t isci_show_id(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = container_of(dev, typeof(*shost), shost_dev); - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - struct isci_host *ihost = container_of(sas_ha, typeof(*ihost), sas_ha); - - return snprintf(buf, PAGE_SIZE, "%d\n", ihost->id); -} - -static DEVICE_ATTR(isci_id, S_IRUGO, isci_show_id, NULL); - -struct device_attribute *isci_host_attrs[] = { - &dev_attr_isci_id, - NULL -}; - -static struct scsi_host_template isci_sht = { - - .module = THIS_MODULE, - .name = DRV_NAME, - .proc_name = DRV_NAME, - .queuecommand = sas_queuecommand, - .target_alloc = sas_target_alloc, - .slave_configure = sas_slave_configure, - .scan_finished = isci_host_scan_finished, - .scan_start = isci_host_scan_start, - .change_queue_depth = sas_change_queue_depth, - .change_queue_type = sas_change_queue_type, - .bios_param = sas_bios_param, - .can_queue = ISCI_CAN_QUEUE_VAL, - .cmd_per_lun = 1, - .this_id = -1, - .sg_tablesize = SG_ALL, - .max_sectors = SCSI_DEFAULT_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .target_destroy = sas_target_destroy, - .ioctl = sas_ioctl, - .shost_attrs = isci_host_attrs, -}; - -static struct sas_domain_function_template isci_transport_ops = { - - /* The class calls these to notify the LLDD of an event. */ - .lldd_port_formed = isci_port_formed, - .lldd_port_deformed = isci_port_deformed, - - /* The class calls these when a device is found or gone. */ - .lldd_dev_found = isci_remote_device_found, - .lldd_dev_gone = isci_remote_device_gone, - - .lldd_execute_task = isci_task_execute_task, - /* Task Management Functions. Must be called from process context. */ - .lldd_abort_task = isci_task_abort_task, - .lldd_abort_task_set = isci_task_abort_task_set, - .lldd_clear_aca = isci_task_clear_aca, - .lldd_clear_task_set = isci_task_clear_task_set, - .lldd_I_T_nexus_reset = isci_task_I_T_nexus_reset, - .lldd_lu_reset = isci_task_lu_reset, - .lldd_query_task = isci_task_query_task, - - /* ata recovery called from ata-eh */ - .lldd_ata_check_ready = isci_ata_check_ready, - - /* Port and Adapter management */ - .lldd_clear_nexus_port = isci_task_clear_nexus_port, - .lldd_clear_nexus_ha = isci_task_clear_nexus_ha, - - /* Phy management */ - .lldd_control_phy = isci_phy_control, - - /* GPIO support */ - .lldd_write_gpio = isci_gpio_write, -}; - - -/****************************************************************************** -* P R O T E C T E D M E T H O D S -******************************************************************************/ - - - -/** - * isci_register_sas_ha() - This method initializes various lldd - * specific members of the sas_ha struct and calls the libsas - * sas_register_ha() function. - * @isci_host: This parameter specifies the lldd specific wrapper for the - * libsas sas_ha struct. - * - * This method returns an error code indicating sucess or failure. The user - * should check for possible memory allocation error return otherwise, a zero - * indicates success. - */ -static int isci_register_sas_ha(struct isci_host *isci_host) -{ - int i; - struct sas_ha_struct *sas_ha = &(isci_host->sas_ha); - struct asd_sas_phy **sas_phys; - struct asd_sas_port **sas_ports; - - sas_phys = devm_kzalloc(&isci_host->pdev->dev, - SCI_MAX_PHYS * sizeof(void *), - GFP_KERNEL); - if (!sas_phys) - return -ENOMEM; - - sas_ports = devm_kzalloc(&isci_host->pdev->dev, - SCI_MAX_PORTS * sizeof(void *), - GFP_KERNEL); - if (!sas_ports) - return -ENOMEM; - - sas_ha->sas_ha_name = DRV_NAME; - sas_ha->lldd_module = THIS_MODULE; - sas_ha->sas_addr = &isci_host->phys[0].sas_addr[0]; - - for (i = 0; i < SCI_MAX_PHYS; i++) { - sas_phys[i] = &isci_host->phys[i].sas_phy; - sas_ports[i] = &isci_host->sas_ports[i]; - } - - sas_ha->sas_phy = sas_phys; - sas_ha->sas_port = sas_ports; - sas_ha->num_phys = SCI_MAX_PHYS; - - sas_ha->lldd_queue_size = ISCI_CAN_QUEUE_VAL; - sas_ha->lldd_max_execute_num = 1; - sas_ha->strict_wide_ports = 1; - - sas_register_ha(sas_ha); - - return 0; -} - -static void isci_unregister(struct isci_host *isci_host) -{ - struct Scsi_Host *shost; - - if (!isci_host) - return; - - shost = isci_host->shost; - - sas_unregister_ha(&isci_host->sas_ha); - - sas_remove_host(isci_host->shost); - scsi_remove_host(isci_host->shost); - scsi_host_put(isci_host->shost); -} - -static int __devinit isci_pci_init(struct pci_dev *pdev) -{ - int err, bar_num, bar_mask = 0; - void __iomem * const *iomap; - - err = pcim_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, - "failed enable PCI device %s!\n", - pci_name(pdev)); - return err; - } - - for (bar_num = 0; bar_num < SCI_PCI_BAR_COUNT; bar_num++) - bar_mask |= 1 << (bar_num * 2); - - err = pcim_iomap_regions(pdev, bar_mask, DRV_NAME); - if (err) - return err; - - iomap = pcim_iomap_table(pdev); - if (!iomap) - return -ENOMEM; - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) - return err; - } - - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (err) { - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (err) - return err; - } - - return 0; -} - -static int num_controllers(struct pci_dev *pdev) -{ - /* bar size alone can tell us if we are running with a dual controller - * part, no need to trust revision ids that might be under broken firmware - * control - */ - resource_size_t scu_bar_size = pci_resource_len(pdev, SCI_SCU_BAR*2); - resource_size_t smu_bar_size = pci_resource_len(pdev, SCI_SMU_BAR*2); - - if (scu_bar_size >= SCI_SCU_BAR_SIZE*SCI_MAX_CONTROLLERS && - smu_bar_size >= SCI_SMU_BAR_SIZE*SCI_MAX_CONTROLLERS) - return SCI_MAX_CONTROLLERS; - else - return 1; -} - -static int isci_setup_interrupts(struct pci_dev *pdev) -{ - int err, i, num_msix; - struct isci_host *ihost; - struct isci_pci_info *pci_info = to_pci_info(pdev); - - /* - * Determine the number of vectors associated with this - * PCI function. - */ - num_msix = num_controllers(pdev) * SCI_NUM_MSI_X_INT; - - for (i = 0; i < num_msix; i++) - pci_info->msix_entries[i].entry = i; - - err = pci_enable_msix(pdev, pci_info->msix_entries, num_msix); - if (err) - goto intx; - - for (i = 0; i < num_msix; i++) { - int id = i / SCI_NUM_MSI_X_INT; - struct msix_entry *msix = &pci_info->msix_entries[i]; - irq_handler_t isr; - - ihost = pci_info->hosts[id]; - /* odd numbered vectors are error interrupts */ - if (i & 1) - isr = isci_error_isr; - else - isr = isci_msix_isr; - - err = devm_request_irq(&pdev->dev, msix->vector, isr, 0, - DRV_NAME"-msix", ihost); - if (!err) - continue; - - dev_info(&pdev->dev, "msix setup failed falling back to intx\n"); - while (i--) { - id = i / SCI_NUM_MSI_X_INT; - ihost = pci_info->hosts[id]; - msix = &pci_info->msix_entries[i]; - devm_free_irq(&pdev->dev, msix->vector, ihost); - } - pci_disable_msix(pdev); - goto intx; - } - return 0; - - intx: - for_each_isci_host(i, ihost, pdev) { - err = devm_request_irq(&pdev->dev, pdev->irq, isci_intx_isr, - IRQF_SHARED, DRV_NAME"-intx", ihost); - if (err) - break; - } - return err; -} - -static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) -{ - struct isci_host *isci_host; - struct Scsi_Host *shost; - int err; - - isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL); - if (!isci_host) - return NULL; - - isci_host->pdev = pdev; - isci_host->id = id; - - shost = scsi_host_alloc(&isci_sht, sizeof(void *)); - if (!shost) - return NULL; - isci_host->shost = shost; - - dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: " - "{%s, %s, %s, %s}\n", - (is_cable_select_overridden() ? "* " : ""), isci_host->id, - lookup_cable_names(decode_cable_selection(isci_host, 3)), - lookup_cable_names(decode_cable_selection(isci_host, 2)), - lookup_cable_names(decode_cable_selection(isci_host, 1)), - lookup_cable_names(decode_cable_selection(isci_host, 0))); - - err = isci_host_init(isci_host); - if (err) - goto err_shost; - - SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha; - isci_host->sas_ha.core.shost = shost; - shost->transportt = isci_transport_template; - - shost->max_id = ~0; - shost->max_lun = ~0; - shost->max_cmd_len = MAX_COMMAND_SIZE; - - err = scsi_add_host(shost, &pdev->dev); - if (err) - goto err_shost; - - err = isci_register_sas_ha(isci_host); - if (err) - goto err_shost_remove; - - return isci_host; - - err_shost_remove: - scsi_remove_host(shost); - err_shost: - scsi_host_put(shost); - - return NULL; -} - -static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct isci_pci_info *pci_info; - int err, i; - struct isci_host *isci_host; - const struct firmware *fw = NULL; - struct isci_orom *orom = NULL; - char *source = "(platform)"; - - dev_info(&pdev->dev, "driver configured for rev: %d silicon\n", - pdev->revision); - - pci_info = devm_kzalloc(&pdev->dev, sizeof(*pci_info), GFP_KERNEL); - if (!pci_info) - return -ENOMEM; - pci_set_drvdata(pdev, pci_info); - - if (efi_enabled) - orom = isci_get_efi_var(pdev); - - if (!orom) - orom = isci_request_oprom(pdev); - - for (i = 0; orom && i < num_controllers(pdev); i++) { - if (sci_oem_parameters_validate(&orom->ctrl[i], - orom->hdr.version)) { - dev_warn(&pdev->dev, - "[%d]: invalid oem parameters detected, falling back to firmware\n", i); - devm_kfree(&pdev->dev, orom); - orom = NULL; - break; - } - } - - if (!orom) { - source = "(firmware)"; - orom = isci_request_firmware(pdev, fw); - if (!orom) { - /* TODO convert this to WARN_TAINT_ONCE once the - * orom/efi parameter support is widely available - */ - dev_warn(&pdev->dev, - "Loading user firmware failed, using default " - "values\n"); - dev_warn(&pdev->dev, - "Default OEM configuration being used: 4 " - "narrow ports, and default SAS Addresses\n"); - } - } - - if (orom) - dev_info(&pdev->dev, - "OEM SAS parameters (version: %u.%u) loaded %s\n", - (orom->hdr.version & 0xf0) >> 4, - (orom->hdr.version & 0xf), source); - - pci_info->orom = orom; - - err = isci_pci_init(pdev); - if (err) - return err; - - for (i = 0; i < num_controllers(pdev); i++) { - struct isci_host *h = isci_host_alloc(pdev, i); - - if (!h) { - err = -ENOMEM; - goto err_host_alloc; - } - pci_info->hosts[i] = h; - - /* turn on DIF support */ - scsi_host_set_prot(h->shost, - SHOST_DIF_TYPE1_PROTECTION | - SHOST_DIF_TYPE2_PROTECTION | - SHOST_DIF_TYPE3_PROTECTION); - scsi_host_set_guard(h->shost, SHOST_DIX_GUARD_CRC); - } - - err = isci_setup_interrupts(pdev); - if (err) - goto err_host_alloc; - - for_each_isci_host(i, isci_host, pdev) - scsi_scan_host(isci_host->shost); - - return 0; - - err_host_alloc: - for_each_isci_host(i, isci_host, pdev) - isci_unregister(isci_host); - return err; -} - -static void __devexit isci_pci_remove(struct pci_dev *pdev) -{ - struct isci_host *ihost; - int i; - - for_each_isci_host(i, ihost, pdev) { - wait_for_start(ihost); - isci_unregister(ihost); - isci_host_deinit(ihost); - } -} - -static struct pci_driver isci_pci_driver = { - .name = DRV_NAME, - .id_table = isci_id_table, - .probe = isci_pci_probe, - .remove = __devexit_p(isci_pci_remove), -}; - -static __init int isci_init(void) -{ - int err; - - pr_info("%s: Intel(R) C600 SAS Controller Driver - version %s\n", - DRV_NAME, DRV_VERSION); - - isci_transport_template = sas_domain_attach_transport(&isci_transport_ops); - if (!isci_transport_template) - return -ENOMEM; - - err = pci_register_driver(&isci_pci_driver); - if (err) - sas_release_transport(isci_transport_template); - - return err; -} - -static __exit void isci_exit(void) -{ - pci_unregister_driver(&isci_pci_driver); - sas_release_transport(isci_transport_template); -} - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_FIRMWARE(ISCI_FW_NAME); -module_init(isci_init); -module_exit(isci_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/isci/isci.h b/ANDROID_3.4.5/drivers/scsi/isci/isci.h deleted file mode 100644 index 234ab46f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/isci.h +++ /dev/null @@ -1,539 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __ISCI_H__ -#define __ISCI_H__ - -#include -#include - -#define DRV_NAME "isci" -#define SCI_PCI_BAR_COUNT 2 -#define SCI_NUM_MSI_X_INT 2 -#define SCI_SMU_BAR 0 -#define SCI_SMU_BAR_SIZE (16*1024) -#define SCI_SCU_BAR 1 -#define SCI_SCU_BAR_SIZE (4*1024*1024) -#define SCI_IO_SPACE_BAR0 2 -#define SCI_IO_SPACE_BAR1 3 -#define ISCI_CAN_QUEUE_VAL 250 /* < SCI_MAX_IO_REQUESTS ? */ -#define SCIC_CONTROLLER_STOP_TIMEOUT 5000 - -#define SCI_CONTROLLER_INVALID_IO_TAG 0xFFFF - -#define SCI_MAX_PHYS (4UL) -#define SCI_MAX_PORTS SCI_MAX_PHYS -#define SCI_MAX_SMP_PHYS (384) /* not silicon constrained */ -#define SCI_MAX_REMOTE_DEVICES (256UL) -#define SCI_MAX_IO_REQUESTS (256UL) -#define SCI_MAX_SEQ (16) -#define SCI_MAX_MSIX_MESSAGES (2) -#define SCI_MAX_SCATTER_GATHER_ELEMENTS 130 /* not silicon constrained */ -#define SCI_MAX_CONTROLLERS 2 -#define SCI_MAX_DOMAINS SCI_MAX_PORTS - -#define SCU_MAX_CRITICAL_NOTIFICATIONS (384) -#define SCU_MAX_EVENTS_SHIFT (7) -#define SCU_MAX_EVENTS (1 << SCU_MAX_EVENTS_SHIFT) -#define SCU_MAX_UNSOLICITED_FRAMES (128) -#define SCU_MAX_COMPLETION_QUEUE_SCRATCH (128) -#define SCU_MAX_COMPLETION_QUEUE_ENTRIES (SCU_MAX_CRITICAL_NOTIFICATIONS \ - + SCU_MAX_EVENTS \ - + SCU_MAX_UNSOLICITED_FRAMES \ - + SCI_MAX_IO_REQUESTS \ - + SCU_MAX_COMPLETION_QUEUE_SCRATCH) -#define SCU_MAX_COMPLETION_QUEUE_SHIFT (ilog2(SCU_MAX_COMPLETION_QUEUE_ENTRIES)) - -#define SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES (4096) -#define SCU_UNSOLICITED_FRAME_BUFFER_SIZE (1024U) -#define SCU_INVALID_FRAME_INDEX (0xFFFF) - -#define SCU_IO_REQUEST_MAX_SGE_SIZE (0x00FFFFFF) -#define SCU_IO_REQUEST_MAX_TRANSFER_LENGTH (0x00FFFFFF) - -static inline void check_sizes(void) -{ - BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_EVENTS); - BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES <= 8); - BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_UNSOLICITED_FRAMES); - BUILD_BUG_ON_NOT_POWER_OF_2(SCU_MAX_COMPLETION_QUEUE_ENTRIES); - BUILD_BUG_ON(SCU_MAX_UNSOLICITED_FRAMES > SCU_ABSOLUTE_MAX_UNSOLICITED_FRAMES); - BUILD_BUG_ON_NOT_POWER_OF_2(SCI_MAX_IO_REQUESTS); - BUILD_BUG_ON_NOT_POWER_OF_2(SCI_MAX_SEQ); -} - -/** - * enum sci_status - This is the general return status enumeration for non-IO, - * non-task management related SCI interface methods. - * - * - */ -enum sci_status { - /** - * This member indicates successful completion. - */ - SCI_SUCCESS = 0, - - /** - * This value indicates that the calling method completed successfully, - * but that the IO may have completed before having it's start method - * invoked. This occurs during SAT translation for requests that do - * not require an IO to the target or for any other requests that may - * be completed without having to submit IO. - */ - SCI_SUCCESS_IO_COMPLETE_BEFORE_START, - - /** - * This Value indicates that the SCU hardware returned an early response - * because the io request specified more data than is returned by the - * target device (mode pages, inquiry data, etc.). The completion routine - * will handle this case to get the actual number of bytes transferred. - */ - SCI_SUCCESS_IO_DONE_EARLY, - - /** - * This member indicates that the object for which a state change is - * being requested is already in said state. - */ - SCI_WARNING_ALREADY_IN_STATE, - - /** - * This member indicates interrupt coalescence timer may cause SAS - * specification compliance issues (i.e. SMP target mode response - * frames must be returned within 1.9 milliseconds). - */ - SCI_WARNING_TIMER_CONFLICT, - - /** - * This field indicates a sequence of action is not completed yet. Mostly, - * this status is used when multiple ATA commands are needed in a SATI translation. - */ - SCI_WARNING_SEQUENCE_INCOMPLETE, - - /** - * This member indicates that there was a general failure. - */ - SCI_FAILURE, - - /** - * This member indicates that the SCI implementation is unable to complete - * an operation due to a critical flaw the prevents any further operation - * (i.e. an invalid pointer). - */ - SCI_FATAL_ERROR, - - /** - * This member indicates the calling function failed, because the state - * of the controller is in a state that prevents successful completion. - */ - SCI_FAILURE_INVALID_STATE, - - /** - * This member indicates the calling function failed, because there is - * insufficient resources/memory to complete the request. - */ - SCI_FAILURE_INSUFFICIENT_RESOURCES, - - /** - * This member indicates the calling function failed, because the - * controller object required for the operation can't be located. - */ - SCI_FAILURE_CONTROLLER_NOT_FOUND, - - /** - * This member indicates the calling function failed, because the - * discovered controller type is not supported by the library. - */ - SCI_FAILURE_UNSUPPORTED_CONTROLLER_TYPE, - - /** - * This member indicates the calling function failed, because the - * requested initialization data version isn't supported. - */ - SCI_FAILURE_UNSUPPORTED_INIT_DATA_VERSION, - - /** - * This member indicates the calling function failed, because the - * requested configuration of SAS Phys into SAS Ports is not supported. - */ - SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION, - - /** - * This member indicates the calling function failed, because the - * requested protocol is not supported by the remote device, port, - * or controller. - */ - SCI_FAILURE_UNSUPPORTED_PROTOCOL, - - /** - * This member indicates the calling function failed, because the - * requested information type is not supported by the SCI implementation. - */ - SCI_FAILURE_UNSUPPORTED_INFORMATION_TYPE, - - /** - * This member indicates the calling function failed, because the - * device already exists. - */ - SCI_FAILURE_DEVICE_EXISTS, - - /** - * This member indicates the calling function failed, because adding - * a phy to the object is not possible. - */ - SCI_FAILURE_ADDING_PHY_UNSUPPORTED, - - /** - * This member indicates the calling function failed, because the - * requested information type is not supported by the SCI implementation. - */ - SCI_FAILURE_UNSUPPORTED_INFORMATION_FIELD, - - /** - * This member indicates the calling function failed, because the SCI - * implementation does not support the supplied time limit. - */ - SCI_FAILURE_UNSUPPORTED_TIME_LIMIT, - - /** - * This member indicates the calling method failed, because the SCI - * implementation does not contain the specified Phy. - */ - SCI_FAILURE_INVALID_PHY, - - /** - * This member indicates the calling method failed, because the SCI - * implementation does not contain the specified Port. - */ - SCI_FAILURE_INVALID_PORT, - - /** - * This member indicates the calling method was partly successful - * The port was reset but not all phys in port are operational - */ - SCI_FAILURE_RESET_PORT_PARTIAL_SUCCESS, - - /** - * This member indicates that calling method failed - * The port reset did not complete because none of the phys are operational - */ - SCI_FAILURE_RESET_PORT_FAILURE, - - /** - * This member indicates the calling method failed, because the SCI - * implementation does not contain the specified remote device. - */ - SCI_FAILURE_INVALID_REMOTE_DEVICE, - - /** - * This member indicates the calling method failed, because the remote - * device is in a bad state and requires a reset. - */ - SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED, - - /** - * This member indicates the calling method failed, because the SCI - * implementation does not contain or support the specified IO tag. - */ - SCI_FAILURE_INVALID_IO_TAG, - - /** - * This member indicates that the operation failed and the user should - * check the response data associated with the IO. - */ - SCI_FAILURE_IO_RESPONSE_VALID, - - /** - * This member indicates that the operation failed, the failure is - * controller implementation specific, and the response data associated - * with the request is not valid. You can query for the controller - * specific error information via sci_controller_get_request_status() - */ - SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR, - - /** - * This member indicated that the operation failed because the - * user requested this IO to be terminated. - */ - SCI_FAILURE_IO_TERMINATED, - - /** - * This member indicates that the operation failed and the associated - * request requires a SCSI abort task to be sent to the target. - */ - SCI_FAILURE_IO_REQUIRES_SCSI_ABORT, - - /** - * This member indicates that the operation failed because the supplied - * device could not be located. - */ - SCI_FAILURE_DEVICE_NOT_FOUND, - - /** - * This member indicates that the operation failed because the - * objects association is required and is not correctly set. - */ - SCI_FAILURE_INVALID_ASSOCIATION, - - /** - * This member indicates that the operation failed, because a timeout - * occurred. - */ - SCI_FAILURE_TIMEOUT, - - /** - * This member indicates that the operation failed, because the user - * specified a value that is either invalid or not supported. - */ - SCI_FAILURE_INVALID_PARAMETER_VALUE, - - /** - * This value indicates that the operation failed, because the number - * of messages (MSI-X) is not supported. - */ - SCI_FAILURE_UNSUPPORTED_MESSAGE_COUNT, - - /** - * This value indicates that the method failed due to a lack of - * available NCQ tags. - */ - SCI_FAILURE_NO_NCQ_TAG_AVAILABLE, - - /** - * This value indicates that a protocol violation has occurred on the - * link. - */ - SCI_FAILURE_PROTOCOL_VIOLATION, - - /** - * This value indicates a failure condition that retry may help to clear. - */ - SCI_FAILURE_RETRY_REQUIRED, - - /** - * This field indicates the retry limit was reached when a retry is attempted - */ - SCI_FAILURE_RETRY_LIMIT_REACHED, - - /** - * This member indicates the calling method was partly successful. - * Mostly, this status is used when a LUN_RESET issued to an expander attached - * STP device in READY NCQ substate needs to have RNC suspended/resumed - * before posting TC. - */ - SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS, - - /** - * This field indicates an illegal phy connection based on the routing attribute - * of both expander phy attached to each other. - */ - SCI_FAILURE_ILLEGAL_ROUTING_ATTRIBUTE_CONFIGURATION, - - /** - * This field indicates a CONFIG ROUTE INFO command has a response with function result - * INDEX DOES NOT EXIST, usually means exceeding max route index. - */ - SCI_FAILURE_EXCEED_MAX_ROUTE_INDEX, - - /** - * This value indicates that an unsupported PCI device ID has been - * specified. This indicates that attempts to invoke - * sci_library_allocate_controller() will fail. - */ - SCI_FAILURE_UNSUPPORTED_PCI_DEVICE_ID - -}; - -/** - * enum sci_io_status - This enumeration depicts all of the possible IO - * completion status values. Each value in this enumeration maps directly - * to a value in the enum sci_status enumeration. Please refer to that - * enumeration for detailed comments concerning what the status represents. - * - * Add the API to retrieve the SCU status from the core. Check to see that the - * following status are properly handled: - SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL - * - SCI_IO_FAILURE_INVALID_IO_TAG - */ -enum sci_io_status { - SCI_IO_SUCCESS = SCI_SUCCESS, - SCI_IO_FAILURE = SCI_FAILURE, - SCI_IO_SUCCESS_COMPLETE_BEFORE_START = SCI_SUCCESS_IO_COMPLETE_BEFORE_START, - SCI_IO_SUCCESS_IO_DONE_EARLY = SCI_SUCCESS_IO_DONE_EARLY, - SCI_IO_FAILURE_INVALID_STATE = SCI_FAILURE_INVALID_STATE, - SCI_IO_FAILURE_INSUFFICIENT_RESOURCES = SCI_FAILURE_INSUFFICIENT_RESOURCES, - SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL = SCI_FAILURE_UNSUPPORTED_PROTOCOL, - SCI_IO_FAILURE_RESPONSE_VALID = SCI_FAILURE_IO_RESPONSE_VALID, - SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR, - SCI_IO_FAILURE_TERMINATED = SCI_FAILURE_IO_TERMINATED, - SCI_IO_FAILURE_REQUIRES_SCSI_ABORT = SCI_FAILURE_IO_REQUIRES_SCSI_ABORT, - SCI_IO_FAILURE_INVALID_PARAMETER_VALUE = SCI_FAILURE_INVALID_PARAMETER_VALUE, - SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE = SCI_FAILURE_NO_NCQ_TAG_AVAILABLE, - SCI_IO_FAILURE_PROTOCOL_VIOLATION = SCI_FAILURE_PROTOCOL_VIOLATION, - - SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED, - - SCI_IO_FAILURE_RETRY_REQUIRED = SCI_FAILURE_RETRY_REQUIRED, - SCI_IO_FAILURE_RETRY_LIMIT_REACHED = SCI_FAILURE_RETRY_LIMIT_REACHED, - SCI_IO_FAILURE_INVALID_REMOTE_DEVICE = SCI_FAILURE_INVALID_REMOTE_DEVICE -}; - -/** - * enum sci_task_status - This enumeration depicts all of the possible task - * completion status values. Each value in this enumeration maps directly - * to a value in the enum sci_status enumeration. Please refer to that - * enumeration for detailed comments concerning what the status represents. - * - * Check to see that the following status are properly handled: - */ -enum sci_task_status { - SCI_TASK_SUCCESS = SCI_SUCCESS, - SCI_TASK_FAILURE = SCI_FAILURE, - SCI_TASK_FAILURE_INVALID_STATE = SCI_FAILURE_INVALID_STATE, - SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES = SCI_FAILURE_INSUFFICIENT_RESOURCES, - SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL = SCI_FAILURE_UNSUPPORTED_PROTOCOL, - SCI_TASK_FAILURE_INVALID_TAG = SCI_FAILURE_INVALID_IO_TAG, - SCI_TASK_FAILURE_RESPONSE_VALID = SCI_FAILURE_IO_RESPONSE_VALID, - SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR, - SCI_TASK_FAILURE_TERMINATED = SCI_FAILURE_IO_TERMINATED, - SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE = SCI_FAILURE_INVALID_PARAMETER_VALUE, - - SCI_TASK_FAILURE_REMOTE_DEVICE_RESET_REQUIRED = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED, - SCI_TASK_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS = SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS - -}; - -/** - * sci_swab32_cpy - convert between scsi and scu-hardware byte format - * @dest: receive the 4-byte endian swapped version of src - * @src: word aligned source buffer - * - * scu hardware handles SSP/SMP control, response, and unidentified - * frames in "big endian dword" order. Regardless of host endian this - * is always a swab32()-per-dword conversion of the standard definition, - * i.e. single byte fields swapped and multi-byte fields in little- - * endian - */ -static inline void sci_swab32_cpy(void *_dest, void *_src, ssize_t word_cnt) -{ - u32 *dest = _dest, *src = _src; - - while (--word_cnt >= 0) - dest[word_cnt] = swab32(src[word_cnt]); -} - -extern unsigned char no_outbound_task_to; -extern u16 ssp_max_occ_to; -extern u16 stp_max_occ_to; -extern u16 ssp_inactive_to; -extern u16 stp_inactive_to; -extern unsigned char phy_gen; -extern unsigned char max_concurr_spinup; -extern uint cable_selection_override; - -irqreturn_t isci_msix_isr(int vec, void *data); -irqreturn_t isci_intx_isr(int vec, void *data); -irqreturn_t isci_error_isr(int vec, void *data); - -/* - * Each timer is associated with a cancellation flag that is set when - * del_timer() is called and checked in the timer callback function. This - * is needed since del_timer_sync() cannot be called with sci_lock held. - * For deinit however, del_timer_sync() is used without holding the lock. - */ -struct sci_timer { - struct timer_list timer; - bool cancel; -}; - -static inline -void sci_init_timer(struct sci_timer *tmr, void (*fn)(unsigned long)) -{ - tmr->timer.function = fn; - tmr->timer.data = (unsigned long) tmr; - tmr->cancel = 0; - init_timer(&tmr->timer); -} - -static inline void sci_mod_timer(struct sci_timer *tmr, unsigned long msec) -{ - tmr->cancel = 0; - mod_timer(&tmr->timer, jiffies + msecs_to_jiffies(msec)); -} - -static inline void sci_del_timer(struct sci_timer *tmr) -{ - tmr->cancel = 1; - del_timer(&tmr->timer); -} - -struct sci_base_state_machine { - const struct sci_base_state *state_table; - u32 initial_state_id; - u32 current_state_id; - u32 previous_state_id; -}; - -typedef void (*sci_state_transition_t)(struct sci_base_state_machine *sm); - -struct sci_base_state { - sci_state_transition_t enter_state; /* Called on state entry */ - sci_state_transition_t exit_state; /* Called on state exit */ -}; - -extern void sci_init_sm(struct sci_base_state_machine *sm, - const struct sci_base_state *state_table, - u32 initial_state); -extern void sci_change_state(struct sci_base_state_machine *sm, u32 next_state); -#endif /* __ISCI_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/phy.c b/ANDROID_3.4.5/drivers/scsi/isci/phy.c deleted file mode 100644 index fab35868..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/phy.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "isci.h" -#include "host.h" -#include "phy.h" -#include "scu_event_codes.h" -#include "probe_roms.h" - -#undef C -#define C(a) (#a) -static const char *phy_state_name(enum sci_phy_states state) -{ - static const char * const strings[] = PHY_STATES; - - return strings[state]; -} -#undef C - -/* Maximum arbitration wait time in micro-seconds */ -#define SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME (700) - -enum sas_linkrate sci_phy_linkrate(struct isci_phy *iphy) -{ - return iphy->max_negotiated_speed; -} - -static struct isci_host *phy_to_host(struct isci_phy *iphy) -{ - struct isci_phy *table = iphy - iphy->phy_index; - struct isci_host *ihost = container_of(table, typeof(*ihost), phys[0]); - - return ihost; -} - -static struct device *sciphy_to_dev(struct isci_phy *iphy) -{ - return &phy_to_host(iphy)->pdev->dev; -} - -static enum sci_status -sci_phy_transport_layer_initialization(struct isci_phy *iphy, - struct scu_transport_layer_registers __iomem *reg) -{ - u32 tl_control; - - iphy->transport_layer_registers = reg; - - writel(SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX, - &iphy->transport_layer_registers->stp_rni); - - /* - * Hardware team recommends that we enable the STP prefetch for all - * transports - */ - tl_control = readl(&iphy->transport_layer_registers->control); - tl_control |= SCU_TLCR_GEN_BIT(STP_WRITE_DATA_PREFETCH); - writel(tl_control, &iphy->transport_layer_registers->control); - - return SCI_SUCCESS; -} - -static enum sci_status -sci_phy_link_layer_initialization(struct isci_phy *iphy, - struct scu_link_layer_registers __iomem *llr) -{ - struct isci_host *ihost = iphy->owning_port->owning_controller; - struct sci_phy_user_params *phy_user; - struct sci_phy_oem_params *phy_oem; - int phy_idx = iphy->phy_index; - struct sci_phy_cap phy_cap; - u32 phy_configuration; - u32 parity_check = 0; - u32 parity_count = 0; - u32 llctl, link_rate; - u32 clksm_value = 0; - u32 sp_timeouts = 0; - - phy_user = &ihost->user_parameters.phys[phy_idx]; - phy_oem = &ihost->oem_parameters.phys[phy_idx]; - iphy->link_layer_registers = llr; - - /* Set our IDENTIFY frame data */ - #define SCI_END_DEVICE 0x01 - - writel(SCU_SAS_TIID_GEN_BIT(SMP_INITIATOR) | - SCU_SAS_TIID_GEN_BIT(SSP_INITIATOR) | - SCU_SAS_TIID_GEN_BIT(STP_INITIATOR) | - SCU_SAS_TIID_GEN_BIT(DA_SATA_HOST) | - SCU_SAS_TIID_GEN_VAL(DEVICE_TYPE, SCI_END_DEVICE), - &llr->transmit_identification); - - /* Write the device SAS Address */ - writel(0xFEDCBA98, &llr->sas_device_name_high); - writel(phy_idx, &llr->sas_device_name_low); - - /* Write the source SAS Address */ - writel(phy_oem->sas_address.high, &llr->source_sas_address_high); - writel(phy_oem->sas_address.low, &llr->source_sas_address_low); - - /* Clear and Set the PHY Identifier */ - writel(0, &llr->identify_frame_phy_id); - writel(SCU_SAS_TIPID_GEN_VALUE(ID, phy_idx), &llr->identify_frame_phy_id); - - /* Change the initial state of the phy configuration register */ - phy_configuration = readl(&llr->phy_configuration); - - /* Hold OOB state machine in reset */ - phy_configuration |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET); - writel(phy_configuration, &llr->phy_configuration); - - /* Configure the SNW capabilities */ - phy_cap.all = 0; - phy_cap.start = 1; - phy_cap.gen3_no_ssc = 1; - phy_cap.gen2_no_ssc = 1; - phy_cap.gen1_no_ssc = 1; - if (ihost->oem_parameters.controller.do_enable_ssc) { - struct scu_afe_registers __iomem *afe = &ihost->scu_registers->afe; - struct scu_afe_transceiver *xcvr = &afe->scu_afe_xcvr[phy_idx]; - struct isci_pci_info *pci_info = to_pci_info(ihost->pdev); - bool en_sas = false; - bool en_sata = false; - u32 sas_type = 0; - u32 sata_spread = 0x2; - u32 sas_spread = 0x2; - - phy_cap.gen3_ssc = 1; - phy_cap.gen2_ssc = 1; - phy_cap.gen1_ssc = 1; - - if (pci_info->orom->hdr.version < ISCI_ROM_VER_1_1) - en_sas = en_sata = true; - else { - sata_spread = ihost->oem_parameters.controller.ssc_sata_tx_spread_level; - sas_spread = ihost->oem_parameters.controller.ssc_sas_tx_spread_level; - - if (sata_spread) - en_sata = true; - - if (sas_spread) { - en_sas = true; - sas_type = ihost->oem_parameters.controller.ssc_sas_tx_type; - } - - } - - if (en_sas) { - u32 reg; - - reg = readl(&xcvr->afe_xcvr_control0); - reg |= (0x00100000 | (sas_type << 19)); - writel(reg, &xcvr->afe_xcvr_control0); - - reg = readl(&xcvr->afe_tx_ssc_control); - reg |= sas_spread << 8; - writel(reg, &xcvr->afe_tx_ssc_control); - } - - if (en_sata) { - u32 reg; - - reg = readl(&xcvr->afe_tx_ssc_control); - reg |= sata_spread; - writel(reg, &xcvr->afe_tx_ssc_control); - - reg = readl(&llr->stp_control); - reg |= 1 << 12; - writel(reg, &llr->stp_control); - } - } - - /* The SAS specification indicates that the phy_capabilities that - * are transmitted shall have an even parity. Calculate the parity. - */ - parity_check = phy_cap.all; - while (parity_check != 0) { - if (parity_check & 0x1) - parity_count++; - parity_check >>= 1; - } - - /* If parity indicates there are an odd number of bits set, then - * set the parity bit to 1 in the phy capabilities. - */ - if ((parity_count % 2) != 0) - phy_cap.parity = 1; - - writel(phy_cap.all, &llr->phy_capabilities); - - /* Set the enable spinup period but disable the ability to send - * notify enable spinup - */ - writel(SCU_ENSPINUP_GEN_VAL(COUNT, - phy_user->notify_enable_spin_up_insertion_frequency), - &llr->notify_enable_spinup_control); - - /* Write the ALIGN Insertion Ferequency for connected phy and - * inpendent of connected state - */ - clksm_value = SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(CONNECTED, - phy_user->in_connection_align_insertion_frequency); - - clksm_value |= SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(GENERAL, - phy_user->align_insertion_frequency); - - writel(clksm_value, &llr->clock_skew_management); - - if (is_c0(ihost->pdev) || is_c1(ihost->pdev)) { - writel(0x04210400, &llr->afe_lookup_table_control); - writel(0x020A7C05, &llr->sas_primitive_timeout); - } else - writel(0x02108421, &llr->afe_lookup_table_control); - - llctl = SCU_SAS_LLCTL_GEN_VAL(NO_OUTBOUND_TASK_TIMEOUT, - (u8)ihost->user_parameters.no_outbound_task_timeout); - - switch (phy_user->max_speed_generation) { - case SCIC_SDS_PARM_GEN3_SPEED: - link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3; - break; - case SCIC_SDS_PARM_GEN2_SPEED: - link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2; - break; - default: - link_rate = SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1; - break; - } - llctl |= SCU_SAS_LLCTL_GEN_VAL(MAX_LINK_RATE, link_rate); - writel(llctl, &llr->link_layer_control); - - sp_timeouts = readl(&llr->sas_phy_timeouts); - - /* Clear the default 0x36 (54us) RATE_CHANGE timeout value. */ - sp_timeouts &= ~SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0xFF); - - /* Set RATE_CHANGE timeout value to 0x3B (59us). This ensures SCU can - * lock with 3Gb drive when SCU max rate is set to 1.5Gb. - */ - sp_timeouts |= SCU_SAS_PHYTOV_GEN_VAL(RATE_CHANGE, 0x3B); - - writel(sp_timeouts, &llr->sas_phy_timeouts); - - if (is_a2(ihost->pdev)) { - /* Program the max ARB time for the PHY to 700us so we - * inter-operate with the PMC expander which shuts down - * PHYs if the expander PHY generates too many breaks. - * This time value will guarantee that the initiator PHY - * will generate the break. - */ - writel(SCIC_SDS_PHY_MAX_ARBITRATION_WAIT_TIME, - &llr->maximum_arbitration_wait_timer_timeout); - } - - /* Disable link layer hang detection, rely on the OS timeout for - * I/O timeouts. - */ - writel(0, &llr->link_layer_hang_detection_timeout); - - /* We can exit the initial state to the stopped state */ - sci_change_state(&iphy->sm, SCI_PHY_STOPPED); - - return SCI_SUCCESS; -} - -static void phy_sata_timeout(unsigned long data) -{ - struct sci_timer *tmr = (struct sci_timer *)data; - struct isci_phy *iphy = container_of(tmr, typeof(*iphy), sata_timer); - struct isci_host *ihost = iphy->owning_port->owning_controller; - unsigned long flags; - - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmr->cancel) - goto done; - - dev_dbg(sciphy_to_dev(iphy), - "%s: SCIC SDS Phy 0x%p did not receive signature fis before " - "timeout.\n", - __func__, - iphy); - - sci_change_state(&iphy->sm, SCI_PHY_STARTING); -done: - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - -/** - * This method returns the port currently containing this phy. If the phy is - * currently contained by the dummy port, then the phy is considered to not - * be part of a port. - * @sci_phy: This parameter specifies the phy for which to retrieve the - * containing port. - * - * This method returns a handle to a port that contains the supplied phy. - * NULL This value is returned if the phy is not part of a real - * port (i.e. it's contained in the dummy port). !NULL All other - * values indicate a handle/pointer to the port containing the phy. - */ -struct isci_port *phy_get_non_dummy_port(struct isci_phy *iphy) -{ - struct isci_port *iport = iphy->owning_port; - - if (iport->physical_port_index == SCIC_SDS_DUMMY_PORT) - return NULL; - - return iphy->owning_port; -} - -/** - * This method will assign a port to the phy object. - * @out]: iphy This parameter specifies the phy for which to assign a port - * object. - * - * - */ -void sci_phy_set_port( - struct isci_phy *iphy, - struct isci_port *iport) -{ - iphy->owning_port = iport; - - if (iphy->bcn_received_while_port_unassigned) { - iphy->bcn_received_while_port_unassigned = false; - sci_port_broadcast_change_received(iphy->owning_port, iphy); - } -} - -enum sci_status sci_phy_initialize(struct isci_phy *iphy, - struct scu_transport_layer_registers __iomem *tl, - struct scu_link_layer_registers __iomem *ll) -{ - /* Perfrom the initialization of the TL hardware */ - sci_phy_transport_layer_initialization(iphy, tl); - - /* Perofrm the initialization of the PE hardware */ - sci_phy_link_layer_initialization(iphy, ll); - - /* There is nothing that needs to be done in this state just - * transition to the stopped state - */ - sci_change_state(&iphy->sm, SCI_PHY_STOPPED); - - return SCI_SUCCESS; -} - -/** - * This method assigns the direct attached device ID for this phy. - * - * @iphy The phy for which the direct attached device id is to - * be assigned. - * @device_id The direct attached device ID to assign to the phy. - * This will either be the RNi for the device or an invalid RNi if there - * is no current device assigned to the phy. - */ -void sci_phy_setup_transport(struct isci_phy *iphy, u32 device_id) -{ - u32 tl_control; - - writel(device_id, &iphy->transport_layer_registers->stp_rni); - - /* - * The read should guarantee that the first write gets posted - * before the next write - */ - tl_control = readl(&iphy->transport_layer_registers->control); - tl_control |= SCU_TLCR_GEN_BIT(CLEAR_TCI_NCQ_MAPPING_TABLE); - writel(tl_control, &iphy->transport_layer_registers->control); -} - -static void sci_phy_suspend(struct isci_phy *iphy) -{ - u32 scu_sas_pcfg_value; - - scu_sas_pcfg_value = - readl(&iphy->link_layer_registers->phy_configuration); - scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE); - writel(scu_sas_pcfg_value, - &iphy->link_layer_registers->phy_configuration); - - sci_phy_setup_transport(iphy, SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX); -} - -void sci_phy_resume(struct isci_phy *iphy) -{ - u32 scu_sas_pcfg_value; - - scu_sas_pcfg_value = - readl(&iphy->link_layer_registers->phy_configuration); - scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE); - writel(scu_sas_pcfg_value, - &iphy->link_layer_registers->phy_configuration); -} - -void sci_phy_get_sas_address(struct isci_phy *iphy, struct sci_sas_address *sas) -{ - sas->high = readl(&iphy->link_layer_registers->source_sas_address_high); - sas->low = readl(&iphy->link_layer_registers->source_sas_address_low); -} - -void sci_phy_get_attached_sas_address(struct isci_phy *iphy, struct sci_sas_address *sas) -{ - struct sas_identify_frame *iaf; - - iaf = &iphy->frame_rcvd.iaf; - memcpy(sas, iaf->sas_addr, SAS_ADDR_SIZE); -} - -void sci_phy_get_protocols(struct isci_phy *iphy, struct sci_phy_proto *proto) -{ - proto->all = readl(&iphy->link_layer_registers->transmit_identification); -} - -enum sci_status sci_phy_start(struct isci_phy *iphy) -{ - enum sci_phy_states state = iphy->sm.current_state_id; - - if (state != SCI_PHY_STOPPED) { - dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", - __func__, phy_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - return SCI_SUCCESS; -} - -enum sci_status sci_phy_stop(struct isci_phy *iphy) -{ - enum sci_phy_states state = iphy->sm.current_state_id; - - switch (state) { - case SCI_PHY_SUB_INITIAL: - case SCI_PHY_SUB_AWAIT_OSSP_EN: - case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: - case SCI_PHY_SUB_AWAIT_SAS_POWER: - case SCI_PHY_SUB_AWAIT_SATA_POWER: - case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: - case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: - case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: - case SCI_PHY_SUB_FINAL: - case SCI_PHY_READY: - break; - default: - dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", - __func__, phy_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - sci_change_state(&iphy->sm, SCI_PHY_STOPPED); - return SCI_SUCCESS; -} - -enum sci_status sci_phy_reset(struct isci_phy *iphy) -{ - enum sci_phy_states state = iphy->sm.current_state_id; - - if (state != SCI_PHY_READY) { - dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", - __func__, phy_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - sci_change_state(&iphy->sm, SCI_PHY_RESETTING); - return SCI_SUCCESS; -} - -enum sci_status sci_phy_consume_power_handler(struct isci_phy *iphy) -{ - enum sci_phy_states state = iphy->sm.current_state_id; - - switch (state) { - case SCI_PHY_SUB_AWAIT_SAS_POWER: { - u32 enable_spinup; - - enable_spinup = readl(&iphy->link_layer_registers->notify_enable_spinup_control); - enable_spinup |= SCU_ENSPINUP_GEN_BIT(ENABLE); - writel(enable_spinup, &iphy->link_layer_registers->notify_enable_spinup_control); - - /* Change state to the final state this substate machine has run to completion */ - sci_change_state(&iphy->sm, SCI_PHY_SUB_FINAL); - - return SCI_SUCCESS; - } - case SCI_PHY_SUB_AWAIT_SATA_POWER: { - u32 scu_sas_pcfg_value; - - /* Release the spinup hold state and reset the OOB state machine */ - scu_sas_pcfg_value = - readl(&iphy->link_layer_registers->phy_configuration); - scu_sas_pcfg_value &= - ~(SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD) | SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE)); - scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_RESET); - writel(scu_sas_pcfg_value, - &iphy->link_layer_registers->phy_configuration); - - /* Now restart the OOB operation */ - scu_sas_pcfg_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET); - scu_sas_pcfg_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); - writel(scu_sas_pcfg_value, - &iphy->link_layer_registers->phy_configuration); - - /* Change state to the final state this substate machine has run to completion */ - sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_PHY_EN); - - return SCI_SUCCESS; - } - default: - dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", - __func__, phy_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -static void sci_phy_start_sas_link_training(struct isci_phy *iphy) -{ - /* continue the link training for the phy as if it were a SAS PHY - * instead of a SATA PHY. This is done because the completion queue had a SAS - * PHY DETECTED event when the state machine was expecting a SATA PHY event. - */ - u32 phy_control; - - phy_control = readl(&iphy->link_layer_registers->phy_configuration); - phy_control |= SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD); - writel(phy_control, - &iphy->link_layer_registers->phy_configuration); - - sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SAS_SPEED_EN); - - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SAS; -} - -static void sci_phy_start_sata_link_training(struct isci_phy *iphy) -{ - /* This method continues the link training for the phy as if it were a SATA PHY - * instead of a SAS PHY. This is done because the completion queue had a SATA - * SPINUP HOLD event when the state machine was expecting a SAS PHY event. none - */ - sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_POWER); - - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA; -} - -/** - * sci_phy_complete_link_training - perform processing common to - * all protocols upon completion of link training. - * @sci_phy: This parameter specifies the phy object for which link training - * has completed. - * @max_link_rate: This parameter specifies the maximum link rate to be - * associated with this phy. - * @next_state: This parameter specifies the next state for the phy's starting - * sub-state machine. - * - */ -static void sci_phy_complete_link_training(struct isci_phy *iphy, - enum sas_linkrate max_link_rate, - u32 next_state) -{ - iphy->max_negotiated_speed = max_link_rate; - - sci_change_state(&iphy->sm, next_state); -} - -static const char *phy_event_name(u32 event_code) -{ - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_PORT_SELECTOR_DETECTED: - return "port selector"; - case SCU_EVENT_SENT_PORT_SELECTION: - return "port selection"; - case SCU_EVENT_HARD_RESET_TRANSMITTED: - return "tx hard reset"; - case SCU_EVENT_HARD_RESET_RECEIVED: - return "rx hard reset"; - case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: - return "identify timeout"; - case SCU_EVENT_LINK_FAILURE: - return "link fail"; - case SCU_EVENT_SATA_SPINUP_HOLD: - return "sata spinup hold"; - case SCU_EVENT_SAS_15_SSC: - case SCU_EVENT_SAS_15: - return "sas 1.5"; - case SCU_EVENT_SAS_30_SSC: - case SCU_EVENT_SAS_30: - return "sas 3.0"; - case SCU_EVENT_SAS_60_SSC: - case SCU_EVENT_SAS_60: - return "sas 6.0"; - case SCU_EVENT_SATA_15_SSC: - case SCU_EVENT_SATA_15: - return "sata 1.5"; - case SCU_EVENT_SATA_30_SSC: - case SCU_EVENT_SATA_30: - return "sata 3.0"; - case SCU_EVENT_SATA_60_SSC: - case SCU_EVENT_SATA_60: - return "sata 6.0"; - case SCU_EVENT_SAS_PHY_DETECTED: - return "sas detect"; - case SCU_EVENT_SATA_PHY_DETECTED: - return "sata detect"; - default: - return "unknown"; - } -} - -#define phy_event_dbg(iphy, state, code) \ - dev_dbg(sciphy_to_dev(iphy), "phy-%d:%d: %s event: %s (%x)\n", \ - phy_to_host(iphy)->id, iphy->phy_index, \ - phy_state_name(state), phy_event_name(code), code) - -#define phy_event_warn(iphy, state, code) \ - dev_warn(sciphy_to_dev(iphy), "phy-%d:%d: %s event: %s (%x)\n", \ - phy_to_host(iphy)->id, iphy->phy_index, \ - phy_state_name(state), phy_event_name(code), code) - -enum sci_status sci_phy_event_handler(struct isci_phy *iphy, u32 event_code) -{ - enum sci_phy_states state = iphy->sm.current_state_id; - - switch (state) { - case SCI_PHY_SUB_AWAIT_OSSP_EN: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SAS_PHY_DETECTED: - sci_phy_start_sas_link_training(iphy); - iphy->is_in_link_training = true; - break; - case SCU_EVENT_SATA_SPINUP_HOLD: - sci_phy_start_sata_link_training(iphy); - iphy->is_in_link_training = true; - break; - default: - phy_event_dbg(iphy, state, event_code); - return SCI_FAILURE; - } - return SCI_SUCCESS; - case SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SAS_PHY_DETECTED: - /* - * Why is this being reported again by the controller? - * We would re-enter this state so just stay here */ - break; - case SCU_EVENT_SAS_15: - case SCU_EVENT_SAS_15_SSC: - sci_phy_complete_link_training(iphy, SAS_LINK_RATE_1_5_GBPS, - SCI_PHY_SUB_AWAIT_IAF_UF); - break; - case SCU_EVENT_SAS_30: - case SCU_EVENT_SAS_30_SSC: - sci_phy_complete_link_training(iphy, SAS_LINK_RATE_3_0_GBPS, - SCI_PHY_SUB_AWAIT_IAF_UF); - break; - case SCU_EVENT_SAS_60: - case SCU_EVENT_SAS_60_SSC: - sci_phy_complete_link_training(iphy, SAS_LINK_RATE_6_0_GBPS, - SCI_PHY_SUB_AWAIT_IAF_UF); - break; - case SCU_EVENT_SATA_SPINUP_HOLD: - /* - * We were doing SAS PHY link training and received a SATA PHY event - * continue OOB/SN as if this were a SATA PHY */ - sci_phy_start_sata_link_training(iphy); - break; - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE; - break; - } - return SCI_SUCCESS; - case SCI_PHY_SUB_AWAIT_IAF_UF: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SAS_PHY_DETECTED: - /* Backup the state machine */ - sci_phy_start_sas_link_training(iphy); - break; - case SCU_EVENT_SATA_SPINUP_HOLD: - /* We were doing SAS PHY link training and received a - * SATA PHY event continue OOB/SN as if this were a - * SATA PHY - */ - sci_phy_start_sata_link_training(iphy); - break; - case SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT: - case SCU_EVENT_LINK_FAILURE: - case SCU_EVENT_HARD_RESET_RECEIVED: - /* Start the oob/sn state machine over again */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE; - } - return SCI_SUCCESS; - case SCI_PHY_SUB_AWAIT_SAS_POWER: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE; - } - return SCI_SUCCESS; - case SCI_PHY_SUB_AWAIT_SATA_POWER: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - case SCU_EVENT_SATA_SPINUP_HOLD: - /* These events are received every 10ms and are - * expected while in this state - */ - break; - - case SCU_EVENT_SAS_PHY_DETECTED: - /* There has been a change in the phy type before OOB/SN for the - * SATA finished start down the SAS link traning path. - */ - sci_phy_start_sas_link_training(iphy); - break; - - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE; - } - return SCI_SUCCESS; - case SCI_PHY_SUB_AWAIT_SATA_PHY_EN: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - case SCU_EVENT_SATA_SPINUP_HOLD: - /* These events might be received since we dont know how many may be in - * the completion queue while waiting for power - */ - break; - case SCU_EVENT_SATA_PHY_DETECTED: - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_SATA; - - /* We have received the SATA PHY notification change state */ - sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN); - break; - case SCU_EVENT_SAS_PHY_DETECTED: - /* There has been a change in the phy type before OOB/SN for the - * SATA finished start down the SAS link traning path. - */ - sci_phy_start_sas_link_training(iphy); - break; - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE; - } - return SCI_SUCCESS; - case SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SATA_PHY_DETECTED: - /* - * The hardware reports multiple SATA PHY detected events - * ignore the extras */ - break; - case SCU_EVENT_SATA_15: - case SCU_EVENT_SATA_15_SSC: - sci_phy_complete_link_training(iphy, SAS_LINK_RATE_1_5_GBPS, - SCI_PHY_SUB_AWAIT_SIG_FIS_UF); - break; - case SCU_EVENT_SATA_30: - case SCU_EVENT_SATA_30_SSC: - sci_phy_complete_link_training(iphy, SAS_LINK_RATE_3_0_GBPS, - SCI_PHY_SUB_AWAIT_SIG_FIS_UF); - break; - case SCU_EVENT_SATA_60: - case SCU_EVENT_SATA_60_SSC: - sci_phy_complete_link_training(iphy, SAS_LINK_RATE_6_0_GBPS, - SCI_PHY_SUB_AWAIT_SIG_FIS_UF); - break; - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - case SCU_EVENT_SAS_PHY_DETECTED: - /* - * There has been a change in the phy type before OOB/SN for the - * SATA finished start down the SAS link traning path. */ - sci_phy_start_sas_link_training(iphy); - break; - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE; - } - - return SCI_SUCCESS; - case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_SATA_PHY_DETECTED: - /* Backup the state machine */ - sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_SATA_SPEED_EN); - break; - - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE; - } - return SCI_SUCCESS; - case SCI_PHY_READY: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_LINK_FAILURE: - /* Link failure change state back to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - case SCU_EVENT_BROADCAST_CHANGE: - /* Broadcast change received. Notify the port. */ - if (phy_get_non_dummy_port(iphy) != NULL) - sci_port_broadcast_change_received(iphy->owning_port, iphy); - else - iphy->bcn_received_while_port_unassigned = true; - break; - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE_INVALID_STATE; - } - return SCI_SUCCESS; - case SCI_PHY_RESETTING: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_HARD_RESET_TRANSMITTED: - /* Link failure change state back to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - break; - default: - phy_event_warn(iphy, state, event_code); - return SCI_FAILURE_INVALID_STATE; - break; - } - return SCI_SUCCESS; - default: - dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", - __func__, phy_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -enum sci_status sci_phy_frame_handler(struct isci_phy *iphy, u32 frame_index) -{ - enum sci_phy_states state = iphy->sm.current_state_id; - struct isci_host *ihost = iphy->owning_port->owning_controller; - enum sci_status result; - unsigned long flags; - - switch (state) { - case SCI_PHY_SUB_AWAIT_IAF_UF: { - u32 *frame_words; - struct sas_identify_frame iaf; - - result = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - (void **)&frame_words); - - if (result != SCI_SUCCESS) - return result; - - sci_swab32_cpy(&iaf, frame_words, sizeof(iaf) / sizeof(u32)); - if (iaf.frame_type == 0) { - u32 state; - - spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags); - memcpy(&iphy->frame_rcvd.iaf, &iaf, sizeof(iaf)); - spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags); - if (iaf.smp_tport) { - /* We got the IAF for an expander PHY go to the final - * state since there are no power requirements for - * expander phys. - */ - state = SCI_PHY_SUB_FINAL; - } else { - /* We got the IAF we can now go to the await spinup - * semaphore state - */ - state = SCI_PHY_SUB_AWAIT_SAS_POWER; - } - sci_change_state(&iphy->sm, state); - result = SCI_SUCCESS; - } else - dev_warn(sciphy_to_dev(iphy), - "%s: PHY starting substate machine received " - "unexpected frame id %x\n", - __func__, frame_index); - - sci_controller_release_frame(ihost, frame_index); - return result; - } - case SCI_PHY_SUB_AWAIT_SIG_FIS_UF: { - struct dev_to_host_fis *frame_header; - u32 *fis_frame_data; - - result = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - (void **)&frame_header); - - if (result != SCI_SUCCESS) - return result; - - if ((frame_header->fis_type == FIS_REGD2H) && - !(frame_header->status & ATA_BUSY)) { - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - (void **)&fis_frame_data); - - spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags); - sci_controller_copy_sata_response(&iphy->frame_rcvd.fis, - frame_header, - fis_frame_data); - spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags); - - /* got IAF we can now go to the await spinup semaphore state */ - sci_change_state(&iphy->sm, SCI_PHY_SUB_FINAL); - - result = SCI_SUCCESS; - } else - dev_warn(sciphy_to_dev(iphy), - "%s: PHY starting substate machine received " - "unexpected frame id %x\n", - __func__, frame_index); - - /* Regardless of the result we are done with this frame with it */ - sci_controller_release_frame(ihost, frame_index); - - return result; - } - default: - dev_dbg(sciphy_to_dev(iphy), "%s: in wrong state: %s\n", - __func__, phy_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - -} - -static void sci_phy_starting_initial_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - /* This is just an temporary state go off to the starting state */ - sci_change_state(&iphy->sm, SCI_PHY_SUB_AWAIT_OSSP_EN); -} - -static void sci_phy_starting_await_sas_power_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - struct isci_host *ihost = iphy->owning_port->owning_controller; - - sci_controller_power_control_queue_insert(ihost, iphy); -} - -static void sci_phy_starting_await_sas_power_substate_exit(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - struct isci_host *ihost = iphy->owning_port->owning_controller; - - sci_controller_power_control_queue_remove(ihost, iphy); -} - -static void sci_phy_starting_await_sata_power_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - struct isci_host *ihost = iphy->owning_port->owning_controller; - - sci_controller_power_control_queue_insert(ihost, iphy); -} - -static void sci_phy_starting_await_sata_power_substate_exit(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - struct isci_host *ihost = iphy->owning_port->owning_controller; - - sci_controller_power_control_queue_remove(ihost, iphy); -} - -static void sci_phy_starting_await_sata_phy_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - sci_mod_timer(&iphy->sata_timer, SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT); -} - -static void sci_phy_starting_await_sata_phy_substate_exit(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - sci_del_timer(&iphy->sata_timer); -} - -static void sci_phy_starting_await_sata_speed_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - sci_mod_timer(&iphy->sata_timer, SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT); -} - -static void sci_phy_starting_await_sata_speed_substate_exit(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - sci_del_timer(&iphy->sata_timer); -} - -static void sci_phy_starting_await_sig_fis_uf_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - if (sci_port_link_detected(iphy->owning_port, iphy)) { - - /* - * Clear the PE suspend condition so we can actually - * receive SIG FIS - * The hardware will not respond to the XRDY until the PE - * suspend condition is cleared. - */ - sci_phy_resume(iphy); - - sci_mod_timer(&iphy->sata_timer, - SCIC_SDS_SIGNATURE_FIS_TIMEOUT); - } else - iphy->is_in_link_training = false; -} - -static void sci_phy_starting_await_sig_fis_uf_substate_exit(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - sci_del_timer(&iphy->sata_timer); -} - -static void sci_phy_starting_final_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - /* State machine has run to completion so exit out and change - * the base state machine to the ready state - */ - sci_change_state(&iphy->sm, SCI_PHY_READY); -} - -/** - * - * @sci_phy: This is the struct isci_phy object to stop. - * - * This method will stop the struct isci_phy object. This does not reset the - * protocol engine it just suspends it and places it in a state where it will - * not cause the end device to power up. none - */ -static void scu_link_layer_stop_protocol_engine( - struct isci_phy *iphy) -{ - u32 scu_sas_pcfg_value; - u32 enable_spinup_value; - - /* Suspend the protocol engine and place it in a sata spinup hold state */ - scu_sas_pcfg_value = - readl(&iphy->link_layer_registers->phy_configuration); - scu_sas_pcfg_value |= - (SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | - SCU_SAS_PCFG_GEN_BIT(SUSPEND_PROTOCOL_ENGINE) | - SCU_SAS_PCFG_GEN_BIT(SATA_SPINUP_HOLD)); - writel(scu_sas_pcfg_value, - &iphy->link_layer_registers->phy_configuration); - - /* Disable the notify enable spinup primitives */ - enable_spinup_value = readl(&iphy->link_layer_registers->notify_enable_spinup_control); - enable_spinup_value &= ~SCU_ENSPINUP_GEN_BIT(ENABLE); - writel(enable_spinup_value, &iphy->link_layer_registers->notify_enable_spinup_control); -} - -static void scu_link_layer_start_oob(struct isci_phy *iphy) -{ - struct scu_link_layer_registers __iomem *ll = iphy->link_layer_registers; - u32 val; - - /** Reset OOB sequence - start */ - val = readl(&ll->phy_configuration); - val &= ~(SCU_SAS_PCFG_GEN_BIT(OOB_RESET) | - SCU_SAS_PCFG_GEN_BIT(HARD_RESET)); - writel(val, &ll->phy_configuration); - readl(&ll->phy_configuration); /* flush */ - /** Reset OOB sequence - end */ - - /** Start OOB sequence - start */ - val = readl(&ll->phy_configuration); - val |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); - writel(val, &ll->phy_configuration); - readl(&ll->phy_configuration); /* flush */ - /** Start OOB sequence - end */ -} - -/** - * - * - * This method will transmit a hard reset request on the specified phy. The SCU - * hardware requires that we reset the OOB state machine and set the hard reset - * bit in the phy configuration register. We then must start OOB over with the - * hard reset bit set. - */ -static void scu_link_layer_tx_hard_reset( - struct isci_phy *iphy) -{ - u32 phy_configuration_value; - - /* - * SAS Phys must wait for the HARD_RESET_TX event notification to transition - * to the starting state. */ - phy_configuration_value = - readl(&iphy->link_layer_registers->phy_configuration); - phy_configuration_value |= - (SCU_SAS_PCFG_GEN_BIT(HARD_RESET) | - SCU_SAS_PCFG_GEN_BIT(OOB_RESET)); - writel(phy_configuration_value, - &iphy->link_layer_registers->phy_configuration); - - /* Now take the OOB state machine out of reset */ - phy_configuration_value |= SCU_SAS_PCFG_GEN_BIT(OOB_ENABLE); - phy_configuration_value &= ~SCU_SAS_PCFG_GEN_BIT(OOB_RESET); - writel(phy_configuration_value, - &iphy->link_layer_registers->phy_configuration); -} - -static void sci_phy_stopped_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - struct isci_port *iport = iphy->owning_port; - struct isci_host *ihost = iport->owning_controller; - - /* - * @todo We need to get to the controller to place this PE in a - * reset state - */ - sci_del_timer(&iphy->sata_timer); - - scu_link_layer_stop_protocol_engine(iphy); - - if (iphy->sm.previous_state_id != SCI_PHY_INITIAL) - sci_controller_link_down(ihost, phy_get_non_dummy_port(iphy), iphy); -} - -static void sci_phy_starting_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - struct isci_port *iport = iphy->owning_port; - struct isci_host *ihost = iport->owning_controller; - - scu_link_layer_stop_protocol_engine(iphy); - scu_link_layer_start_oob(iphy); - - /* We don't know what kind of phy we are going to be just yet */ - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN; - iphy->bcn_received_while_port_unassigned = false; - - if (iphy->sm.previous_state_id == SCI_PHY_READY) - sci_controller_link_down(ihost, phy_get_non_dummy_port(iphy), iphy); - - sci_change_state(&iphy->sm, SCI_PHY_SUB_INITIAL); -} - -static void sci_phy_ready_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - struct isci_port *iport = iphy->owning_port; - struct isci_host *ihost = iport->owning_controller; - - sci_controller_link_up(ihost, phy_get_non_dummy_port(iphy), iphy); -} - -static void sci_phy_ready_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - sci_phy_suspend(iphy); -} - -static void sci_phy_resetting_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_phy *iphy = container_of(sm, typeof(*iphy), sm); - - /* The phy is being reset, therefore deactivate it from the port. In - * the resetting state we don't notify the user regarding link up and - * link down notifications - */ - sci_port_deactivate_phy(iphy->owning_port, iphy, false); - - if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { - scu_link_layer_tx_hard_reset(iphy); - } else { - /* The SCU does not need to have a discrete reset state so - * just go back to the starting state. - */ - sci_change_state(&iphy->sm, SCI_PHY_STARTING); - } -} - -static const struct sci_base_state sci_phy_state_table[] = { - [SCI_PHY_INITIAL] = { }, - [SCI_PHY_STOPPED] = { - .enter_state = sci_phy_stopped_state_enter, - }, - [SCI_PHY_STARTING] = { - .enter_state = sci_phy_starting_state_enter, - }, - [SCI_PHY_SUB_INITIAL] = { - .enter_state = sci_phy_starting_initial_substate_enter, - }, - [SCI_PHY_SUB_AWAIT_OSSP_EN] = { }, - [SCI_PHY_SUB_AWAIT_SAS_SPEED_EN] = { }, - [SCI_PHY_SUB_AWAIT_IAF_UF] = { }, - [SCI_PHY_SUB_AWAIT_SAS_POWER] = { - .enter_state = sci_phy_starting_await_sas_power_substate_enter, - .exit_state = sci_phy_starting_await_sas_power_substate_exit, - }, - [SCI_PHY_SUB_AWAIT_SATA_POWER] = { - .enter_state = sci_phy_starting_await_sata_power_substate_enter, - .exit_state = sci_phy_starting_await_sata_power_substate_exit - }, - [SCI_PHY_SUB_AWAIT_SATA_PHY_EN] = { - .enter_state = sci_phy_starting_await_sata_phy_substate_enter, - .exit_state = sci_phy_starting_await_sata_phy_substate_exit - }, - [SCI_PHY_SUB_AWAIT_SATA_SPEED_EN] = { - .enter_state = sci_phy_starting_await_sata_speed_substate_enter, - .exit_state = sci_phy_starting_await_sata_speed_substate_exit - }, - [SCI_PHY_SUB_AWAIT_SIG_FIS_UF] = { - .enter_state = sci_phy_starting_await_sig_fis_uf_substate_enter, - .exit_state = sci_phy_starting_await_sig_fis_uf_substate_exit - }, - [SCI_PHY_SUB_FINAL] = { - .enter_state = sci_phy_starting_final_substate_enter, - }, - [SCI_PHY_READY] = { - .enter_state = sci_phy_ready_state_enter, - .exit_state = sci_phy_ready_state_exit, - }, - [SCI_PHY_RESETTING] = { - .enter_state = sci_phy_resetting_state_enter, - }, - [SCI_PHY_FINAL] = { }, -}; - -void sci_phy_construct(struct isci_phy *iphy, - struct isci_port *iport, u8 phy_index) -{ - sci_init_sm(&iphy->sm, sci_phy_state_table, SCI_PHY_INITIAL); - - /* Copy the rest of the input data to our locals */ - iphy->owning_port = iport; - iphy->phy_index = phy_index; - iphy->bcn_received_while_port_unassigned = false; - iphy->protocol = SCIC_SDS_PHY_PROTOCOL_UNKNOWN; - iphy->link_layer_registers = NULL; - iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; - - /* Create the SIGNATURE FIS Timeout timer for this phy */ - sci_init_timer(&iphy->sata_timer, phy_sata_timeout); -} - -void isci_phy_init(struct isci_phy *iphy, struct isci_host *ihost, int index) -{ - struct sci_oem_params *oem = &ihost->oem_parameters; - u64 sci_sas_addr; - __be64 sas_addr; - - sci_sas_addr = oem->phys[index].sas_address.high; - sci_sas_addr <<= 32; - sci_sas_addr |= oem->phys[index].sas_address.low; - sas_addr = cpu_to_be64(sci_sas_addr); - memcpy(iphy->sas_addr, &sas_addr, sizeof(sas_addr)); - - iphy->sas_phy.enabled = 0; - iphy->sas_phy.id = index; - iphy->sas_phy.sas_addr = &iphy->sas_addr[0]; - iphy->sas_phy.frame_rcvd = (u8 *)&iphy->frame_rcvd; - iphy->sas_phy.ha = &ihost->sas_ha; - iphy->sas_phy.lldd_phy = iphy; - iphy->sas_phy.enabled = 1; - iphy->sas_phy.class = SAS; - iphy->sas_phy.iproto = SAS_PROTOCOL_ALL; - iphy->sas_phy.tproto = 0; - iphy->sas_phy.type = PHY_TYPE_PHYSICAL; - iphy->sas_phy.role = PHY_ROLE_INITIATOR; - iphy->sas_phy.oob_mode = OOB_NOT_CONNECTED; - iphy->sas_phy.linkrate = SAS_LINK_RATE_UNKNOWN; - memset(&iphy->frame_rcvd, 0, sizeof(iphy->frame_rcvd)); -} - - -/** - * isci_phy_control() - This function is one of the SAS Domain Template - * functions. This is a phy management function. - * @phy: This parameter specifies the sphy being controlled. - * @func: This parameter specifies the phy control function being invoked. - * @buf: This parameter is specific to the phy function being invoked. - * - * status, zero indicates success. - */ -int isci_phy_control(struct asd_sas_phy *sas_phy, - enum phy_func func, - void *buf) -{ - int ret = 0; - struct isci_phy *iphy = sas_phy->lldd_phy; - struct asd_sas_port *port = sas_phy->port; - struct isci_host *ihost = sas_phy->ha->lldd_ha; - unsigned long flags; - - dev_dbg(&ihost->pdev->dev, - "%s: phy %p; func %d; buf %p; isci phy %p, port %p\n", - __func__, sas_phy, func, buf, iphy, port); - - switch (func) { - case PHY_FUNC_DISABLE: - spin_lock_irqsave(&ihost->scic_lock, flags); - sci_phy_stop(iphy); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - break; - - case PHY_FUNC_LINK_RESET: - spin_lock_irqsave(&ihost->scic_lock, flags); - sci_phy_stop(iphy); - sci_phy_start(iphy); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - break; - - case PHY_FUNC_HARD_RESET: - if (!port) - return -ENODEV; - - ret = isci_port_perform_hard_reset(ihost, port->lldd_port, iphy); - - break; - case PHY_FUNC_GET_EVENTS: { - struct scu_link_layer_registers __iomem *r; - struct sas_phy *phy = sas_phy->phy; - - r = iphy->link_layer_registers; - phy->running_disparity_error_count = readl(&r->running_disparity_error_count); - phy->loss_of_dword_sync_count = readl(&r->loss_of_sync_error_count); - phy->phy_reset_problem_count = readl(&r->phy_reset_problem_count); - phy->invalid_dword_count = readl(&r->invalid_dword_counter); - break; - } - - default: - dev_dbg(&ihost->pdev->dev, - "%s: phy %p; func %d NOT IMPLEMENTED!\n", - __func__, sas_phy, func); - ret = -ENOSYS; - break; - } - return ret; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/phy.h b/ANDROID_3.4.5/drivers/scsi/isci/phy.h deleted file mode 100644 index 0e45833b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/phy.h +++ /dev/null @@ -1,467 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _ISCI_PHY_H_ -#define _ISCI_PHY_H_ - -#include -#include -#include "isci.h" -#include "sas.h" - -/* This is the timeout value for the SATA phy to wait for a SIGNATURE FIS - * before restarting the starting state machine. Technically, the old parallel - * ATA specification required up to 30 seconds for a device to issue its - * signature FIS as a result of a soft reset. Now we see that devices respond - * generally within 15 seconds, but we'll use 25 for now. - */ -#define SCIC_SDS_SIGNATURE_FIS_TIMEOUT 25000 - -/* This is the timeout for the SATA OOB/SN because the hardware does not - * recognize a hot plug after OOB signal but before the SN signals. We need to - * make sure after a hotplug timeout if we have not received the speed event - * notification from the hardware that we restart the hardware OOB state - * machine. - */ -#define SCIC_SDS_SATA_LINK_TRAINING_TIMEOUT 250 - -enum sci_phy_protocol { - SCIC_SDS_PHY_PROTOCOL_UNKNOWN, - SCIC_SDS_PHY_PROTOCOL_SAS, - SCIC_SDS_PHY_PROTOCOL_SATA, - SCIC_SDS_MAX_PHY_PROTOCOLS -}; - -/** - * isci_phy - hba local phy infrastructure - * @sm: - * @protocol: attached device protocol - * @phy_index: physical index relative to the controller (0-3) - * @bcn_received_while_port_unassigned: bcn to report after port association - * @sata_timer: timeout SATA signature FIS arrival - */ -struct isci_phy { - struct sci_base_state_machine sm; - struct isci_port *owning_port; - enum sas_linkrate max_negotiated_speed; - enum sci_phy_protocol protocol; - u8 phy_index; - bool bcn_received_while_port_unassigned; - bool is_in_link_training; - struct sci_timer sata_timer; - struct scu_transport_layer_registers __iomem *transport_layer_registers; - struct scu_link_layer_registers __iomem *link_layer_registers; - struct asd_sas_phy sas_phy; - u8 sas_addr[SAS_ADDR_SIZE]; - union { - struct sas_identify_frame iaf; - struct dev_to_host_fis fis; - } frame_rcvd; -}; - -static inline struct isci_phy *to_iphy(struct asd_sas_phy *sas_phy) -{ - struct isci_phy *iphy = container_of(sas_phy, typeof(*iphy), sas_phy); - - return iphy; -} - -struct sci_phy_cap { - union { - struct { - /* - * The SAS specification indicates the start bit shall - * always be set to - * 1. This implementation will have the start bit set - * to 0 if the PHY CAPABILITIES were either not - * received or speed negotiation failed. - */ - u8 start:1; - u8 tx_ssc_type:1; - u8 res1:2; - u8 req_logical_linkrate:4; - - u32 gen1_no_ssc:1; - u32 gen1_ssc:1; - u32 gen2_no_ssc:1; - u32 gen2_ssc:1; - u32 gen3_no_ssc:1; - u32 gen3_ssc:1; - u32 res2:17; - u32 parity:1; - }; - u32 all; - }; -} __packed; - -/* this data structure reflects the link layer transmit identification reg */ -struct sci_phy_proto { - union { - struct { - u16 _r_a:1; - u16 smp_iport:1; - u16 stp_iport:1; - u16 ssp_iport:1; - u16 _r_b:4; - u16 _r_c:1; - u16 smp_tport:1; - u16 stp_tport:1; - u16 ssp_tport:1; - u16 _r_d:4; - }; - u16 all; - }; -} __packed; - - -/** - * struct sci_phy_properties - This structure defines the properties common to - * all phys that can be retrieved. - * - * - */ -struct sci_phy_properties { - /** - * This field specifies the port that currently contains the - * supplied phy. This field may be set to NULL - * if the phy is not currently contained in a port. - */ - struct isci_port *iport; - - /** - * This field specifies the link rate at which the phy is - * currently operating. - */ - enum sas_linkrate negotiated_link_rate; - - /** - * This field specifies the index of the phy in relation to other - * phys within the controller. This index is zero relative. - */ - u8 index; -}; - -/** - * struct sci_sas_phy_properties - This structure defines the properties, - * specific to a SAS phy, that can be retrieved. - * - * - */ -struct sci_sas_phy_properties { - /** - * This field delineates the Identify Address Frame received - * from the remote end point. - */ - struct sas_identify_frame rcvd_iaf; - - /** - * This field delineates the Phy capabilities structure received - * from the remote end point. - */ - struct sci_phy_cap rcvd_cap; - -}; - -/** - * struct sci_sata_phy_properties - This structure defines the properties, - * specific to a SATA phy, that can be retrieved. - * - * - */ -struct sci_sata_phy_properties { - /** - * This field delineates the signature FIS received from the - * attached target. - */ - struct dev_to_host_fis signature_fis; - - /** - * This field specifies to the user if a port selector is connected - * on the specified phy. - */ - bool is_port_selector_present; - -}; - -/** - * enum sci_phy_counter_id - This enumeration depicts the various pieces of - * optional information that can be retrieved for a specific phy. - * - * - */ -enum sci_phy_counter_id { - /** - * This PHY information field tracks the number of frames received. - */ - SCIC_PHY_COUNTER_RECEIVED_FRAME, - - /** - * This PHY information field tracks the number of frames transmitted. - */ - SCIC_PHY_COUNTER_TRANSMITTED_FRAME, - - /** - * This PHY information field tracks the number of DWORDs received. - */ - SCIC_PHY_COUNTER_RECEIVED_FRAME_WORD, - - /** - * This PHY information field tracks the number of DWORDs transmitted. - */ - SCIC_PHY_COUNTER_TRANSMITTED_FRAME_DWORD, - - /** - * This PHY information field tracks the number of times DWORD - * synchronization was lost. - */ - SCIC_PHY_COUNTER_LOSS_OF_SYNC_ERROR, - - /** - * This PHY information field tracks the number of received DWORDs with - * running disparity errors. - */ - SCIC_PHY_COUNTER_RECEIVED_DISPARITY_ERROR, - - /** - * This PHY information field tracks the number of received frames with a - * CRC error (not including short or truncated frames). - */ - SCIC_PHY_COUNTER_RECEIVED_FRAME_CRC_ERROR, - - /** - * This PHY information field tracks the number of DONE (ACK/NAK TIMEOUT) - * primitives received. - */ - SCIC_PHY_COUNTER_RECEIVED_DONE_ACK_NAK_TIMEOUT, - - /** - * This PHY information field tracks the number of DONE (ACK/NAK TIMEOUT) - * primitives transmitted. - */ - SCIC_PHY_COUNTER_TRANSMITTED_DONE_ACK_NAK_TIMEOUT, - - /** - * This PHY information field tracks the number of times the inactivity - * timer for connections on the phy has been utilized. - */ - SCIC_PHY_COUNTER_INACTIVITY_TIMER_EXPIRED, - - /** - * This PHY information field tracks the number of DONE (CREDIT TIMEOUT) - * primitives received. - */ - SCIC_PHY_COUNTER_RECEIVED_DONE_CREDIT_TIMEOUT, - - /** - * This PHY information field tracks the number of DONE (CREDIT TIMEOUT) - * primitives transmitted. - */ - SCIC_PHY_COUNTER_TRANSMITTED_DONE_CREDIT_TIMEOUT, - - /** - * This PHY information field tracks the number of CREDIT BLOCKED - * primitives received. - * @note Depending on remote device implementation, credit blocks - * may occur regularly. - */ - SCIC_PHY_COUNTER_RECEIVED_CREDIT_BLOCKED, - - /** - * This PHY information field contains the number of short frames - * received. A short frame is simply a frame smaller then what is - * allowed by either the SAS or SATA specification. - */ - SCIC_PHY_COUNTER_RECEIVED_SHORT_FRAME, - - /** - * This PHY information field contains the number of frames received after - * credit has been exhausted. - */ - SCIC_PHY_COUNTER_RECEIVED_FRAME_WITHOUT_CREDIT, - - /** - * This PHY information field contains the number of frames received after - * a DONE has been received. - */ - SCIC_PHY_COUNTER_RECEIVED_FRAME_AFTER_DONE, - - /** - * This PHY information field contains the number of times the phy - * failed to achieve DWORD synchronization during speed negotiation. - */ - SCIC_PHY_COUNTER_SN_DWORD_SYNC_ERROR -}; - -/** - * enum sci_phy_states - phy state machine states - * @SCI_PHY_INITIAL: Simply the initial state for the base domain state - * machine. - * @SCI_PHY_STOPPED: phy has successfully been stopped. In this state - * no new IO operations are permitted on this phy. - * @SCI_PHY_STARTING: the phy is in the process of becomming ready. In - * this state no new IO operations are permitted on - * this phy. - * @SCI_PHY_SUB_INITIAL: Initial state - * @SCI_PHY_SUB_AWAIT_OSSP_EN: Wait state for the hardware OSSP event - * type notification - * @SCI_PHY_SUB_AWAIT_SAS_SPEED_EN: Wait state for the PHY speed - * notification - * @SCI_PHY_SUB_AWAIT_IAF_UF: Wait state for the IAF Unsolicited frame - * notification - * @SCI_PHY_SUB_AWAIT_SAS_POWER: Wait state for the request to consume - * power - * @SCI_PHY_SUB_AWAIT_SATA_POWER: Wait state for request to consume - * power - * @SCI_PHY_SUB_AWAIT_SATA_PHY_EN: Wait state for the SATA PHY - * notification - * @SCI_PHY_SUB_AWAIT_SATA_SPEED_EN: Wait for the SATA PHY speed - * notification - * @SCI_PHY_SUB_AWAIT_SIG_FIS_UF: Wait state for the SIGNATURE FIS - * unsolicited frame notification - * @SCI_PHY_SUB_FINAL: Exit state for this state machine - * @SCI_PHY_READY: phy is now ready. Thus, the user is able to perform - * IO operations utilizing this phy as long as it is - * currently part of a valid port. This state is - * entered from the STARTING state. - * @SCI_PHY_RESETTING: phy is in the process of being reset. In this - * state no new IO operations are permitted on this - * phy. This state is entered from the READY state. - * @SCI_PHY_FINAL: Simply the final state for the base phy state - * machine. - */ -#define PHY_STATES {\ - C(PHY_INITIAL),\ - C(PHY_STOPPED),\ - C(PHY_STARTING),\ - C(PHY_SUB_INITIAL),\ - C(PHY_SUB_AWAIT_OSSP_EN),\ - C(PHY_SUB_AWAIT_SAS_SPEED_EN),\ - C(PHY_SUB_AWAIT_IAF_UF),\ - C(PHY_SUB_AWAIT_SAS_POWER),\ - C(PHY_SUB_AWAIT_SATA_POWER),\ - C(PHY_SUB_AWAIT_SATA_PHY_EN),\ - C(PHY_SUB_AWAIT_SATA_SPEED_EN),\ - C(PHY_SUB_AWAIT_SIG_FIS_UF),\ - C(PHY_SUB_FINAL),\ - C(PHY_READY),\ - C(PHY_RESETTING),\ - C(PHY_FINAL),\ - } -#undef C -#define C(a) SCI_##a -enum sci_phy_states PHY_STATES; -#undef C - -void sci_phy_construct( - struct isci_phy *iphy, - struct isci_port *iport, - u8 phy_index); - -struct isci_port *phy_get_non_dummy_port(struct isci_phy *iphy); - -void sci_phy_set_port( - struct isci_phy *iphy, - struct isci_port *iport); - -enum sci_status sci_phy_initialize( - struct isci_phy *iphy, - struct scu_transport_layer_registers __iomem *transport_layer_registers, - struct scu_link_layer_registers __iomem *link_layer_registers); - -enum sci_status sci_phy_start( - struct isci_phy *iphy); - -enum sci_status sci_phy_stop( - struct isci_phy *iphy); - -enum sci_status sci_phy_reset( - struct isci_phy *iphy); - -void sci_phy_resume( - struct isci_phy *iphy); - -void sci_phy_setup_transport( - struct isci_phy *iphy, - u32 device_id); - -enum sci_status sci_phy_event_handler( - struct isci_phy *iphy, - u32 event_code); - -enum sci_status sci_phy_frame_handler( - struct isci_phy *iphy, - u32 frame_index); - -enum sci_status sci_phy_consume_power_handler( - struct isci_phy *iphy); - -void sci_phy_get_sas_address( - struct isci_phy *iphy, - struct sci_sas_address *sas_address); - -void sci_phy_get_attached_sas_address( - struct isci_phy *iphy, - struct sci_sas_address *sas_address); - -struct sci_phy_proto; -void sci_phy_get_protocols( - struct isci_phy *iphy, - struct sci_phy_proto *protocols); -enum sas_linkrate sci_phy_linkrate(struct isci_phy *iphy); - -struct isci_host; -void isci_phy_init(struct isci_phy *iphy, struct isci_host *ihost, int index); -int isci_phy_control(struct asd_sas_phy *phy, enum phy_func func, void *buf); - -#endif /* !defined(_ISCI_PHY_H_) */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/port.c b/ANDROID_3.4.5/drivers/scsi/isci/port.c deleted file mode 100644 index 5fada73b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/port.c +++ /dev/null @@ -1,1764 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "isci.h" -#include "port.h" -#include "request.h" - -#define SCIC_SDS_PORT_HARD_RESET_TIMEOUT (1000) -#define SCU_DUMMY_INDEX (0xFFFF) - -#undef C -#define C(a) (#a) -const char *port_state_name(enum sci_port_states state) -{ - static const char * const strings[] = PORT_STATES; - - return strings[state]; -} -#undef C - -static struct device *sciport_to_dev(struct isci_port *iport) -{ - int i = iport->physical_port_index; - struct isci_port *table; - struct isci_host *ihost; - - if (i == SCIC_SDS_DUMMY_PORT) - i = SCI_MAX_PORTS+1; - - table = iport - i; - ihost = container_of(table, typeof(*ihost), ports[0]); - - return &ihost->pdev->dev; -} - -static void sci_port_get_protocols(struct isci_port *iport, struct sci_phy_proto *proto) -{ - u8 index; - - proto->all = 0; - for (index = 0; index < SCI_MAX_PHYS; index++) { - struct isci_phy *iphy = iport->phy_table[index]; - - if (!iphy) - continue; - sci_phy_get_protocols(iphy, proto); - } -} - -static u32 sci_port_get_phys(struct isci_port *iport) -{ - u32 index; - u32 mask; - - mask = 0; - for (index = 0; index < SCI_MAX_PHYS; index++) - if (iport->phy_table[index]) - mask |= (1 << index); - - return mask; -} - -/** - * sci_port_get_properties() - This method simply returns the properties - * regarding the port, such as: physical index, protocols, sas address, etc. - * @port: this parameter specifies the port for which to retrieve the physical - * index. - * @properties: This parameter specifies the properties structure into which to - * copy the requested information. - * - * Indicate if the user specified a valid port. SCI_SUCCESS This value is - * returned if the specified port was valid. SCI_FAILURE_INVALID_PORT This - * value is returned if the specified port is not valid. When this value is - * returned, no data is copied to the properties output parameter. - */ -enum sci_status sci_port_get_properties(struct isci_port *iport, - struct sci_port_properties *prop) -{ - if (!iport || iport->logical_port_index == SCIC_SDS_DUMMY_PORT) - return SCI_FAILURE_INVALID_PORT; - - prop->index = iport->logical_port_index; - prop->phy_mask = sci_port_get_phys(iport); - sci_port_get_sas_address(iport, &prop->local.sas_address); - sci_port_get_protocols(iport, &prop->local.protocols); - sci_port_get_attached_sas_address(iport, &prop->remote.sas_address); - - return SCI_SUCCESS; -} - -static void sci_port_bcn_enable(struct isci_port *iport) -{ - struct isci_phy *iphy; - u32 val; - int i; - - for (i = 0; i < ARRAY_SIZE(iport->phy_table); i++) { - iphy = iport->phy_table[i]; - if (!iphy) - continue; - val = readl(&iphy->link_layer_registers->link_layer_control); - /* clear the bit by writing 1. */ - writel(val, &iphy->link_layer_registers->link_layer_control); - } -} - -static void isci_port_bc_change_received(struct isci_host *ihost, - struct isci_port *iport, - struct isci_phy *iphy) -{ - dev_dbg(&ihost->pdev->dev, - "%s: isci_phy = %p, sas_phy = %p\n", - __func__, iphy, &iphy->sas_phy); - - ihost->sas_ha.notify_port_event(&iphy->sas_phy, PORTE_BROADCAST_RCVD); - sci_port_bcn_enable(iport); -} - -static void isci_port_link_up(struct isci_host *isci_host, - struct isci_port *iport, - struct isci_phy *iphy) -{ - unsigned long flags; - struct sci_port_properties properties; - unsigned long success = true; - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_port = %p\n", - __func__, iport); - - spin_lock_irqsave(&iphy->sas_phy.frame_rcvd_lock, flags); - - sci_port_get_properties(iport, &properties); - - if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA) { - u64 attached_sas_address; - - iphy->sas_phy.oob_mode = SATA_OOB_MODE; - iphy->sas_phy.frame_rcvd_size = sizeof(struct dev_to_host_fis); - - /* - * For direct-attached SATA devices, the SCI core will - * automagically assign a SAS address to the end device - * for the purpose of creating a port. This SAS address - * will not be the same as assigned to the PHY and needs - * to be obtained from struct sci_port_properties properties. - */ - attached_sas_address = properties.remote.sas_address.high; - attached_sas_address <<= 32; - attached_sas_address |= properties.remote.sas_address.low; - swab64s(&attached_sas_address); - - memcpy(&iphy->sas_phy.attached_sas_addr, - &attached_sas_address, sizeof(attached_sas_address)); - } else if (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SAS) { - iphy->sas_phy.oob_mode = SAS_OOB_MODE; - iphy->sas_phy.frame_rcvd_size = sizeof(struct sas_identify_frame); - - /* Copy the attached SAS address from the IAF */ - memcpy(iphy->sas_phy.attached_sas_addr, - iphy->frame_rcvd.iaf.sas_addr, SAS_ADDR_SIZE); - } else { - dev_err(&isci_host->pdev->dev, "%s: unkown target\n", __func__); - success = false; - } - - iphy->sas_phy.phy->negotiated_linkrate = sci_phy_linkrate(iphy); - - spin_unlock_irqrestore(&iphy->sas_phy.frame_rcvd_lock, flags); - - /* Notify libsas that we have an address frame, if indeed - * we've found an SSP, SMP, or STP target */ - if (success) - isci_host->sas_ha.notify_port_event(&iphy->sas_phy, - PORTE_BYTES_DMAED); -} - - -/** - * isci_port_link_down() - This function is called by the sci core when a link - * becomes inactive. - * @isci_host: This parameter specifies the isci host object. - * @phy: This parameter specifies the isci phy with the active link. - * @port: This parameter specifies the isci port with the active link. - * - */ -static void isci_port_link_down(struct isci_host *isci_host, - struct isci_phy *isci_phy, - struct isci_port *isci_port) -{ - struct isci_remote_device *isci_device; - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_port = %p\n", __func__, isci_port); - - if (isci_port) { - - /* check to see if this is the last phy on this port. */ - if (isci_phy->sas_phy.port && - isci_phy->sas_phy.port->num_phys == 1) { - /* change the state for all devices on this port. The - * next task sent to this device will be returned as - * SAS_TASK_UNDELIVERED, and the scsi mid layer will - * remove the target - */ - list_for_each_entry(isci_device, - &isci_port->remote_dev_list, - node) { - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device = %p\n", - __func__, isci_device); - set_bit(IDEV_GONE, &isci_device->flags); - } - } - } - - /* Notify libsas of the borken link, this will trigger calls to our - * isci_port_deformed and isci_dev_gone functions. - */ - sas_phy_disconnected(&isci_phy->sas_phy); - isci_host->sas_ha.notify_phy_event(&isci_phy->sas_phy, - PHYE_LOSS_OF_SIGNAL); - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_port = %p - Done\n", __func__, isci_port); -} - -static bool is_port_ready_state(enum sci_port_states state) -{ - switch (state) { - case SCI_PORT_READY: - case SCI_PORT_SUB_WAITING: - case SCI_PORT_SUB_OPERATIONAL: - case SCI_PORT_SUB_CONFIGURING: - return true; - default: - return false; - } -} - -/* flag dummy rnc hanling when exiting a ready state */ -static void port_state_machine_change(struct isci_port *iport, - enum sci_port_states state) -{ - struct sci_base_state_machine *sm = &iport->sm; - enum sci_port_states old_state = sm->current_state_id; - - if (is_port_ready_state(old_state) && !is_port_ready_state(state)) - iport->ready_exit = true; - - sci_change_state(sm, state); - iport->ready_exit = false; -} - -/** - * isci_port_hard_reset_complete() - This function is called by the sci core - * when the hard reset complete notification has been received. - * @port: This parameter specifies the sci port with the active link. - * @completion_status: This parameter specifies the core status for the reset - * process. - * - */ -static void isci_port_hard_reset_complete(struct isci_port *isci_port, - enum sci_status completion_status) -{ - struct isci_host *ihost = isci_port->owning_controller; - - dev_dbg(&ihost->pdev->dev, - "%s: isci_port = %p, completion_status=%x\n", - __func__, isci_port, completion_status); - - /* Save the status of the hard reset from the port. */ - isci_port->hard_reset_status = completion_status; - - if (completion_status != SCI_SUCCESS) { - - /* The reset failed. The port state is now SCI_PORT_FAILED. */ - if (isci_port->active_phy_mask == 0) { - int phy_idx = isci_port->last_active_phy; - struct isci_phy *iphy = &ihost->phys[phy_idx]; - - /* Generate the link down now to the host, since it - * was intercepted by the hard reset state machine when - * it really happened. - */ - isci_port_link_down(ihost, iphy, isci_port); - } - /* Advance the port state so that link state changes will be - * noticed. - */ - port_state_machine_change(isci_port, SCI_PORT_SUB_WAITING); - - } - clear_bit(IPORT_RESET_PENDING, &isci_port->state); - wake_up(&ihost->eventq); - -} - -/* This method will return a true value if the specified phy can be assigned to - * this port The following is a list of phys for each port that are allowed: - - * Port 0 - 3 2 1 0 - Port 1 - 1 - Port 2 - 3 2 - Port 3 - 3 This method - * doesn't preclude all configurations. It merely ensures that a phy is part - * of the allowable set of phy identifiers for that port. For example, one - * could assign phy 3 to port 0 and no other phys. Please refer to - * sci_port_is_phy_mask_valid() for information regarding whether the - * phy_mask for a port can be supported. bool true if this is a valid phy - * assignment for the port false if this is not a valid phy assignment for the - * port - */ -bool sci_port_is_valid_phy_assignment(struct isci_port *iport, u32 phy_index) -{ - struct isci_host *ihost = iport->owning_controller; - struct sci_user_parameters *user = &ihost->user_parameters; - - /* Initialize to invalid value. */ - u32 existing_phy_index = SCI_MAX_PHYS; - u32 index; - - if ((iport->physical_port_index == 1) && (phy_index != 1)) - return false; - - if (iport->physical_port_index == 3 && phy_index != 3) - return false; - - if (iport->physical_port_index == 2 && - (phy_index == 0 || phy_index == 1)) - return false; - - for (index = 0; index < SCI_MAX_PHYS; index++) - if (iport->phy_table[index] && index != phy_index) - existing_phy_index = index; - - /* Ensure that all of the phys in the port are capable of - * operating at the same maximum link rate. - */ - if (existing_phy_index < SCI_MAX_PHYS && - user->phys[phy_index].max_speed_generation != - user->phys[existing_phy_index].max_speed_generation) - return false; - - return true; -} - -/** - * - * @sci_port: This is the port object for which to determine if the phy mask - * can be supported. - * - * This method will return a true value if the port's phy mask can be supported - * by the SCU. The following is a list of valid PHY mask configurations for - * each port: - Port 0 - [[3 2] 1] 0 - Port 1 - [1] - Port 2 - [[3] 2] - * - Port 3 - [3] This method returns a boolean indication specifying if the - * phy mask can be supported. true if this is a valid phy assignment for the - * port false if this is not a valid phy assignment for the port - */ -static bool sci_port_is_phy_mask_valid( - struct isci_port *iport, - u32 phy_mask) -{ - if (iport->physical_port_index == 0) { - if (((phy_mask & 0x0F) == 0x0F) - || ((phy_mask & 0x03) == 0x03) - || ((phy_mask & 0x01) == 0x01) - || (phy_mask == 0)) - return true; - } else if (iport->physical_port_index == 1) { - if (((phy_mask & 0x02) == 0x02) - || (phy_mask == 0)) - return true; - } else if (iport->physical_port_index == 2) { - if (((phy_mask & 0x0C) == 0x0C) - || ((phy_mask & 0x04) == 0x04) - || (phy_mask == 0)) - return true; - } else if (iport->physical_port_index == 3) { - if (((phy_mask & 0x08) == 0x08) - || (phy_mask == 0)) - return true; - } - - return false; -} - -/* - * This method retrieves a currently active (i.e. connected) phy contained in - * the port. Currently, the lowest order phy that is connected is returned. - * This method returns a pointer to a SCIS_SDS_PHY object. NULL This value is - * returned if there are no currently active (i.e. connected to a remote end - * point) phys contained in the port. All other values specify a struct sci_phy - * object that is active in the port. - */ -static struct isci_phy *sci_port_get_a_connected_phy(struct isci_port *iport) -{ - u32 index; - struct isci_phy *iphy; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - /* Ensure that the phy is both part of the port and currently - * connected to the remote end-point. - */ - iphy = iport->phy_table[index]; - if (iphy && sci_port_active_phy(iport, iphy)) - return iphy; - } - - return NULL; -} - -static enum sci_status sci_port_set_phy(struct isci_port *iport, struct isci_phy *iphy) -{ - /* Check to see if we can add this phy to a port - * that means that the phy is not part of a port and that the port does - * not already have a phy assinged to the phy index. - */ - if (!iport->phy_table[iphy->phy_index] && - !phy_get_non_dummy_port(iphy) && - sci_port_is_valid_phy_assignment(iport, iphy->phy_index)) { - /* Phy is being added in the stopped state so we are in MPC mode - * make logical port index = physical port index - */ - iport->logical_port_index = iport->physical_port_index; - iport->phy_table[iphy->phy_index] = iphy; - sci_phy_set_port(iphy, iport); - - return SCI_SUCCESS; - } - - return SCI_FAILURE; -} - -static enum sci_status sci_port_clear_phy(struct isci_port *iport, struct isci_phy *iphy) -{ - /* Make sure that this phy is part of this port */ - if (iport->phy_table[iphy->phy_index] == iphy && - phy_get_non_dummy_port(iphy) == iport) { - struct isci_host *ihost = iport->owning_controller; - - /* Yep it is assigned to this port so remove it */ - sci_phy_set_port(iphy, &ihost->ports[SCI_MAX_PORTS]); - iport->phy_table[iphy->phy_index] = NULL; - return SCI_SUCCESS; - } - - return SCI_FAILURE; -} - -void sci_port_get_sas_address(struct isci_port *iport, struct sci_sas_address *sas) -{ - u32 index; - - sas->high = 0; - sas->low = 0; - for (index = 0; index < SCI_MAX_PHYS; index++) - if (iport->phy_table[index]) - sci_phy_get_sas_address(iport->phy_table[index], sas); -} - -void sci_port_get_attached_sas_address(struct isci_port *iport, struct sci_sas_address *sas) -{ - struct isci_phy *iphy; - - /* - * Ensure that the phy is both part of the port and currently - * connected to the remote end-point. - */ - iphy = sci_port_get_a_connected_phy(iport); - if (iphy) { - if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA) { - sci_phy_get_attached_sas_address(iphy, sas); - } else { - sci_phy_get_sas_address(iphy, sas); - sas->low += iphy->phy_index; - } - } else { - sas->high = 0; - sas->low = 0; - } -} - -/** - * sci_port_construct_dummy_rnc() - create dummy rnc for si workaround - * - * @sci_port: logical port on which we need to create the remote node context - * @rni: remote node index for this remote node context. - * - * This routine will construct a dummy remote node context data structure - * This structure will be posted to the hardware to work around a scheduler - * error in the hardware. - */ -static void sci_port_construct_dummy_rnc(struct isci_port *iport, u16 rni) -{ - union scu_remote_node_context *rnc; - - rnc = &iport->owning_controller->remote_node_context_table[rni]; - - memset(rnc, 0, sizeof(union scu_remote_node_context)); - - rnc->ssp.remote_sas_address_hi = 0; - rnc->ssp.remote_sas_address_lo = 0; - - rnc->ssp.remote_node_index = rni; - rnc->ssp.remote_node_port_width = 1; - rnc->ssp.logical_port_index = iport->physical_port_index; - - rnc->ssp.nexus_loss_timer_enable = false; - rnc->ssp.check_bit = false; - rnc->ssp.is_valid = true; - rnc->ssp.is_remote_node_context = true; - rnc->ssp.function_number = 0; - rnc->ssp.arbitration_wait_time = 0; -} - -/* - * construct a dummy task context data structure. This - * structure will be posted to the hardwre to work around a scheduler error - * in the hardware. - */ -static void sci_port_construct_dummy_task(struct isci_port *iport, u16 tag) -{ - struct isci_host *ihost = iport->owning_controller; - struct scu_task_context *task_context; - - task_context = &ihost->task_context_table[ISCI_TAG_TCI(tag)]; - memset(task_context, 0, sizeof(struct scu_task_context)); - - task_context->initiator_request = 1; - task_context->connection_rate = 1; - task_context->logical_port_index = iport->physical_port_index; - task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; - task_context->task_index = ISCI_TAG_TCI(tag); - task_context->valid = SCU_TASK_CONTEXT_VALID; - task_context->context_type = SCU_TASK_CONTEXT_TYPE; - task_context->remote_node_index = iport->reserved_rni; - task_context->do_not_dma_ssp_good_response = 1; - task_context->task_phase = 0x01; -} - -static void sci_port_destroy_dummy_resources(struct isci_port *iport) -{ - struct isci_host *ihost = iport->owning_controller; - - if (iport->reserved_tag != SCI_CONTROLLER_INVALID_IO_TAG) - isci_free_tag(ihost, iport->reserved_tag); - - if (iport->reserved_rni != SCU_DUMMY_INDEX) - sci_remote_node_table_release_remote_node_index(&ihost->available_remote_nodes, - 1, iport->reserved_rni); - - iport->reserved_rni = SCU_DUMMY_INDEX; - iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG; -} - -void sci_port_setup_transports(struct isci_port *iport, u32 device_id) -{ - u8 index; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - if (iport->active_phy_mask & (1 << index)) - sci_phy_setup_transport(iport->phy_table[index], device_id); - } -} - -static void sci_port_resume_phy(struct isci_port *iport, struct isci_phy *iphy) -{ - sci_phy_resume(iphy); - iport->enabled_phy_mask |= 1 << iphy->phy_index; -} - -static void sci_port_activate_phy(struct isci_port *iport, - struct isci_phy *iphy, - u8 flags) -{ - struct isci_host *ihost = iport->owning_controller; - - if (iphy->protocol != SCIC_SDS_PHY_PROTOCOL_SATA && (flags & PF_RESUME)) - sci_phy_resume(iphy); - - iport->active_phy_mask |= 1 << iphy->phy_index; - - sci_controller_clear_invalid_phy(ihost, iphy); - - if (flags & PF_NOTIFY) - isci_port_link_up(ihost, iport, iphy); -} - -void sci_port_deactivate_phy(struct isci_port *iport, struct isci_phy *iphy, - bool do_notify_user) -{ - struct isci_host *ihost = iport->owning_controller; - - iport->active_phy_mask &= ~(1 << iphy->phy_index); - iport->enabled_phy_mask &= ~(1 << iphy->phy_index); - if (!iport->active_phy_mask) - iport->last_active_phy = iphy->phy_index; - - iphy->max_negotiated_speed = SAS_LINK_RATE_UNKNOWN; - - /* Re-assign the phy back to the LP as if it were a narrow port for APC - * mode. For MPC mode, the phy will remain in the port. - */ - if (iport->owning_controller->oem_parameters.controller.mode_type == - SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE) - writel(iphy->phy_index, - &iport->port_pe_configuration_register[iphy->phy_index]); - - if (do_notify_user == true) - isci_port_link_down(ihost, iphy, iport); -} - -static void sci_port_invalid_link_up(struct isci_port *iport, struct isci_phy *iphy) -{ - struct isci_host *ihost = iport->owning_controller; - - /* - * Check to see if we have alreay reported this link as bad and if - * not go ahead and tell the SCI_USER that we have discovered an - * invalid link. - */ - if ((ihost->invalid_phy_mask & (1 << iphy->phy_index)) == 0) { - ihost->invalid_phy_mask |= 1 << iphy->phy_index; - dev_warn(&ihost->pdev->dev, "Invalid link up!\n"); - } -} - -/** - * sci_port_general_link_up_handler - phy can be assigned to port? - * @sci_port: sci_port object for which has a phy that has gone link up. - * @sci_phy: This is the struct isci_phy object that has gone link up. - * @flags: PF_RESUME, PF_NOTIFY to sci_port_activate_phy - * - * Determine if this phy can be assigned to this port . If the phy is - * not a valid PHY for this port then the function will notify the user. - * A PHY can only be part of a port if it's attached SAS ADDRESS is the - * same as all other PHYs in the same port. - */ -static void sci_port_general_link_up_handler(struct isci_port *iport, - struct isci_phy *iphy, - u8 flags) -{ - struct sci_sas_address port_sas_address; - struct sci_sas_address phy_sas_address; - - sci_port_get_attached_sas_address(iport, &port_sas_address); - sci_phy_get_attached_sas_address(iphy, &phy_sas_address); - - /* If the SAS address of the new phy matches the SAS address of - * other phys in the port OR this is the first phy in the port, - * then activate the phy and allow it to be used for operations - * in this port. - */ - if ((phy_sas_address.high == port_sas_address.high && - phy_sas_address.low == port_sas_address.low) || - iport->active_phy_mask == 0) { - struct sci_base_state_machine *sm = &iport->sm; - - sci_port_activate_phy(iport, iphy, flags); - if (sm->current_state_id == SCI_PORT_RESETTING) - port_state_machine_change(iport, SCI_PORT_READY); - } else - sci_port_invalid_link_up(iport, iphy); -} - - - -/** - * This method returns false if the port only has a single phy object assigned. - * If there are no phys or more than one phy then the method will return - * true. - * @sci_port: The port for which the wide port condition is to be checked. - * - * bool true Is returned if this is a wide ported port. false Is returned if - * this is a narrow port. - */ -static bool sci_port_is_wide(struct isci_port *iport) -{ - u32 index; - u32 phy_count = 0; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - if (iport->phy_table[index] != NULL) { - phy_count++; - } - } - - return phy_count != 1; -} - -/** - * This method is called by the PHY object when the link is detected. if the - * port wants the PHY to continue on to the link up state then the port - * layer must return true. If the port object returns false the phy object - * must halt its attempt to go link up. - * @sci_port: The port associated with the phy object. - * @sci_phy: The phy object that is trying to go link up. - * - * true if the phy object can continue to the link up condition. true Is - * returned if this phy can continue to the ready state. false Is returned if - * can not continue on to the ready state. This notification is in place for - * wide ports and direct attached phys. Since there are no wide ported SATA - * devices this could become an invalid port configuration. - */ -bool sci_port_link_detected( - struct isci_port *iport, - struct isci_phy *iphy) -{ - if ((iport->logical_port_index != SCIC_SDS_DUMMY_PORT) && - (iphy->protocol == SCIC_SDS_PHY_PROTOCOL_SATA)) { - if (sci_port_is_wide(iport)) { - sci_port_invalid_link_up(iport, iphy); - return false; - } else { - struct isci_host *ihost = iport->owning_controller; - struct isci_port *dst_port = &(ihost->ports[iphy->phy_index]); - writel(iphy->phy_index, - &dst_port->port_pe_configuration_register[iphy->phy_index]); - } - } - - return true; -} - -static void port_timeout(unsigned long data) -{ - struct sci_timer *tmr = (struct sci_timer *)data; - struct isci_port *iport = container_of(tmr, typeof(*iport), timer); - struct isci_host *ihost = iport->owning_controller; - unsigned long flags; - u32 current_state; - - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmr->cancel) - goto done; - - current_state = iport->sm.current_state_id; - - if (current_state == SCI_PORT_RESETTING) { - /* if the port is still in the resetting state then the timeout - * fired before the reset completed. - */ - port_state_machine_change(iport, SCI_PORT_FAILED); - } else if (current_state == SCI_PORT_STOPPED) { - /* if the port is stopped then the start request failed In this - * case stay in the stopped state. - */ - dev_err(sciport_to_dev(iport), - "%s: SCIC Port 0x%p failed to stop before tiemout.\n", - __func__, - iport); - } else if (current_state == SCI_PORT_STOPPING) { - dev_dbg(sciport_to_dev(iport), - "%s: port%d: stop complete timeout\n", - __func__, iport->physical_port_index); - } else { - /* The port is in the ready state and we have a timer - * reporting a timeout this should not happen. - */ - dev_err(sciport_to_dev(iport), - "%s: SCIC Port 0x%p is processing a timeout operation " - "in state %d.\n", __func__, iport, current_state); - } - -done: - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - -/* --------------------------------------------------------------------------- */ - -/** - * This function updates the hardwares VIIT entry for this port. - * - * - */ -static void sci_port_update_viit_entry(struct isci_port *iport) -{ - struct sci_sas_address sas_address; - - sci_port_get_sas_address(iport, &sas_address); - - writel(sas_address.high, - &iport->viit_registers->initiator_sas_address_hi); - writel(sas_address.low, - &iport->viit_registers->initiator_sas_address_lo); - - /* This value get cleared just in case its not already cleared */ - writel(0, &iport->viit_registers->reserved); - - /* We are required to update the status register last */ - writel(SCU_VIIT_ENTRY_ID_VIIT | - SCU_VIIT_IPPT_INITIATOR | - ((1 << iport->physical_port_index) << SCU_VIIT_ENTRY_LPVIE_SHIFT) | - SCU_VIIT_STATUS_ALL_VALID, - &iport->viit_registers->status); -} - -enum sas_linkrate sci_port_get_max_allowed_speed(struct isci_port *iport) -{ - u16 index; - struct isci_phy *iphy; - enum sas_linkrate max_allowed_speed = SAS_LINK_RATE_6_0_GBPS; - - /* - * Loop through all of the phys in this port and find the phy with the - * lowest maximum link rate. */ - for (index = 0; index < SCI_MAX_PHYS; index++) { - iphy = iport->phy_table[index]; - if (iphy && sci_port_active_phy(iport, iphy) && - iphy->max_negotiated_speed < max_allowed_speed) - max_allowed_speed = iphy->max_negotiated_speed; - } - - return max_allowed_speed; -} - -static void sci_port_suspend_port_task_scheduler(struct isci_port *iport) -{ - u32 pts_control_value; - - pts_control_value = readl(&iport->port_task_scheduler_registers->control); - pts_control_value |= SCU_PTSxCR_GEN_BIT(SUSPEND); - writel(pts_control_value, &iport->port_task_scheduler_registers->control); -} - -/** - * sci_port_post_dummy_request() - post dummy/workaround request - * @sci_port: port to post task - * - * Prevent the hardware scheduler from posting new requests to the front - * of the scheduler queue causing a starvation problem for currently - * ongoing requests. - * - */ -static void sci_port_post_dummy_request(struct isci_port *iport) -{ - struct isci_host *ihost = iport->owning_controller; - u16 tag = iport->reserved_tag; - struct scu_task_context *tc; - u32 command; - - tc = &ihost->task_context_table[ISCI_TAG_TCI(tag)]; - tc->abort = 0; - - command = SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - iport->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | - ISCI_TAG_TCI(tag); - - sci_controller_post_request(ihost, command); -} - -/** - * This routine will abort the dummy request. This will alow the hardware to - * power down parts of the silicon to save power. - * - * @sci_port: The port on which the task must be aborted. - * - */ -static void sci_port_abort_dummy_request(struct isci_port *iport) -{ - struct isci_host *ihost = iport->owning_controller; - u16 tag = iport->reserved_tag; - struct scu_task_context *tc; - u32 command; - - tc = &ihost->task_context_table[ISCI_TAG_TCI(tag)]; - tc->abort = 1; - - command = SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT | - iport->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | - ISCI_TAG_TCI(tag); - - sci_controller_post_request(ihost, command); -} - -/** - * - * @sci_port: This is the struct isci_port object to resume. - * - * This method will resume the port task scheduler for this port object. none - */ -static void -sci_port_resume_port_task_scheduler(struct isci_port *iport) -{ - u32 pts_control_value; - - pts_control_value = readl(&iport->port_task_scheduler_registers->control); - pts_control_value &= ~SCU_PTSxCR_GEN_BIT(SUSPEND); - writel(pts_control_value, &iport->port_task_scheduler_registers->control); -} - -static void sci_port_ready_substate_waiting_enter(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - - sci_port_suspend_port_task_scheduler(iport); - - iport->not_ready_reason = SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS; - - if (iport->active_phy_mask != 0) { - /* At least one of the phys on the port is ready */ - port_state_machine_change(iport, - SCI_PORT_SUB_OPERATIONAL); - } -} - -static void scic_sds_port_ready_substate_waiting_exit( - struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - sci_port_resume_port_task_scheduler(iport); -} - -static void sci_port_ready_substate_operational_enter(struct sci_base_state_machine *sm) -{ - u32 index; - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - struct isci_host *ihost = iport->owning_controller; - - dev_dbg(&ihost->pdev->dev, "%s: port%d ready\n", - __func__, iport->physical_port_index); - - for (index = 0; index < SCI_MAX_PHYS; index++) { - if (iport->phy_table[index]) { - writel(iport->physical_port_index, - &iport->port_pe_configuration_register[ - iport->phy_table[index]->phy_index]); - if (((iport->active_phy_mask^iport->enabled_phy_mask) & (1 << index)) != 0) - sci_port_resume_phy(iport, iport->phy_table[index]); - } - } - - sci_port_update_viit_entry(iport); - - /* - * Post the dummy task for the port so the hardware can schedule - * io correctly - */ - sci_port_post_dummy_request(iport); -} - -static void sci_port_invalidate_dummy_remote_node(struct isci_port *iport) -{ - struct isci_host *ihost = iport->owning_controller; - u8 phys_index = iport->physical_port_index; - union scu_remote_node_context *rnc; - u16 rni = iport->reserved_rni; - u32 command; - - rnc = &ihost->remote_node_context_table[rni]; - - rnc->ssp.is_valid = false; - - /* ensure the preceding tc abort request has reached the - * controller and give it ample time to act before posting the rnc - * invalidate - */ - readl(&ihost->smu_registers->interrupt_status); /* flush */ - udelay(10); - - command = SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE | - phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; - - sci_controller_post_request(ihost, command); -} - -/** - * - * @object: This is the object which is cast to a struct isci_port object. - * - * This method will perform the actions required by the struct isci_port on - * exiting the SCI_PORT_SUB_OPERATIONAL. This function reports - * the port not ready and suspends the port task scheduler. none - */ -static void sci_port_ready_substate_operational_exit(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - struct isci_host *ihost = iport->owning_controller; - - /* - * Kill the dummy task for this port if it has not yet posted - * the hardware will treat this as a NOP and just return abort - * complete. - */ - sci_port_abort_dummy_request(iport); - - dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n", - __func__, iport->physical_port_index); - - if (iport->ready_exit) - sci_port_invalidate_dummy_remote_node(iport); -} - -static void sci_port_ready_substate_configuring_enter(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - struct isci_host *ihost = iport->owning_controller; - - if (iport->active_phy_mask == 0) { - dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n", - __func__, iport->physical_port_index); - - port_state_machine_change(iport, SCI_PORT_SUB_WAITING); - } else - port_state_machine_change(iport, SCI_PORT_SUB_OPERATIONAL); -} - -enum sci_status sci_port_start(struct isci_port *iport) -{ - struct isci_host *ihost = iport->owning_controller; - enum sci_status status = SCI_SUCCESS; - enum sci_port_states state; - u32 phy_mask; - - state = iport->sm.current_state_id; - if (state != SCI_PORT_STOPPED) { - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - if (iport->assigned_device_count > 0) { - /* TODO This is a start failure operation because - * there are still devices assigned to this port. - * There must be no devices assigned to a port on a - * start operation. - */ - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - - if (iport->reserved_rni == SCU_DUMMY_INDEX) { - u16 rni = sci_remote_node_table_allocate_remote_node( - &ihost->available_remote_nodes, 1); - - if (rni != SCU_DUMMY_INDEX) - sci_port_construct_dummy_rnc(iport, rni); - else - status = SCI_FAILURE_INSUFFICIENT_RESOURCES; - iport->reserved_rni = rni; - } - - if (iport->reserved_tag == SCI_CONTROLLER_INVALID_IO_TAG) { - u16 tag; - - tag = isci_alloc_tag(ihost); - if (tag == SCI_CONTROLLER_INVALID_IO_TAG) - status = SCI_FAILURE_INSUFFICIENT_RESOURCES; - else - sci_port_construct_dummy_task(iport, tag); - iport->reserved_tag = tag; - } - - if (status == SCI_SUCCESS) { - phy_mask = sci_port_get_phys(iport); - - /* - * There are one or more phys assigned to this port. Make sure - * the port's phy mask is in fact legal and supported by the - * silicon. - */ - if (sci_port_is_phy_mask_valid(iport, phy_mask) == true) { - port_state_machine_change(iport, - SCI_PORT_READY); - - return SCI_SUCCESS; - } - status = SCI_FAILURE; - } - - if (status != SCI_SUCCESS) - sci_port_destroy_dummy_resources(iport); - - return status; -} - -enum sci_status sci_port_stop(struct isci_port *iport) -{ - enum sci_port_states state; - - state = iport->sm.current_state_id; - switch (state) { - case SCI_PORT_STOPPED: - return SCI_SUCCESS; - case SCI_PORT_SUB_WAITING: - case SCI_PORT_SUB_OPERATIONAL: - case SCI_PORT_SUB_CONFIGURING: - case SCI_PORT_RESETTING: - port_state_machine_change(iport, - SCI_PORT_STOPPING); - return SCI_SUCCESS; - default: - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -static enum sci_status sci_port_hard_reset(struct isci_port *iport, u32 timeout) -{ - enum sci_status status = SCI_FAILURE_INVALID_PHY; - struct isci_phy *iphy = NULL; - enum sci_port_states state; - u32 phy_index; - - state = iport->sm.current_state_id; - if (state != SCI_PORT_SUB_OPERATIONAL) { - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - /* Select a phy on which we can send the hard reset request. */ - for (phy_index = 0; phy_index < SCI_MAX_PHYS && !iphy; phy_index++) { - iphy = iport->phy_table[phy_index]; - if (iphy && !sci_port_active_phy(iport, iphy)) { - /* - * We found a phy but it is not ready select - * different phy - */ - iphy = NULL; - } - } - - /* If we have a phy then go ahead and start the reset procedure */ - if (!iphy) - return status; - status = sci_phy_reset(iphy); - - if (status != SCI_SUCCESS) - return status; - - sci_mod_timer(&iport->timer, timeout); - iport->not_ready_reason = SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED; - - port_state_machine_change(iport, SCI_PORT_RESETTING); - return SCI_SUCCESS; -} - -/** - * sci_port_add_phy() - - * @sci_port: This parameter specifies the port in which the phy will be added. - * @sci_phy: This parameter is the phy which is to be added to the port. - * - * This method will add a PHY to the selected port. This method returns an - * enum sci_status. SCI_SUCCESS the phy has been added to the port. Any other - * status is a failure to add the phy to the port. - */ -enum sci_status sci_port_add_phy(struct isci_port *iport, - struct isci_phy *iphy) -{ - enum sci_status status; - enum sci_port_states state; - - state = iport->sm.current_state_id; - switch (state) { - case SCI_PORT_STOPPED: { - struct sci_sas_address port_sas_address; - - /* Read the port assigned SAS Address if there is one */ - sci_port_get_sas_address(iport, &port_sas_address); - - if (port_sas_address.high != 0 && port_sas_address.low != 0) { - struct sci_sas_address phy_sas_address; - - /* Make sure that the PHY SAS Address matches the SAS Address - * for this port - */ - sci_phy_get_sas_address(iphy, &phy_sas_address); - - if (port_sas_address.high != phy_sas_address.high || - port_sas_address.low != phy_sas_address.low) - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - return sci_port_set_phy(iport, iphy); - } - case SCI_PORT_SUB_WAITING: - case SCI_PORT_SUB_OPERATIONAL: - status = sci_port_set_phy(iport, iphy); - - if (status != SCI_SUCCESS) - return status; - - sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME); - iport->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; - port_state_machine_change(iport, SCI_PORT_SUB_CONFIGURING); - - return status; - case SCI_PORT_SUB_CONFIGURING: - status = sci_port_set_phy(iport, iphy); - - if (status != SCI_SUCCESS) - return status; - sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY); - - /* Re-enter the configuring state since this may be the last phy in - * the port. - */ - port_state_machine_change(iport, - SCI_PORT_SUB_CONFIGURING); - return SCI_SUCCESS; - default: - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -/** - * sci_port_remove_phy() - - * @sci_port: This parameter specifies the port in which the phy will be added. - * @sci_phy: This parameter is the phy which is to be added to the port. - * - * This method will remove the PHY from the selected PORT. This method returns - * an enum sci_status. SCI_SUCCESS the phy has been removed from the port. Any - * other status is a failure to add the phy to the port. - */ -enum sci_status sci_port_remove_phy(struct isci_port *iport, - struct isci_phy *iphy) -{ - enum sci_status status; - enum sci_port_states state; - - state = iport->sm.current_state_id; - - switch (state) { - case SCI_PORT_STOPPED: - return sci_port_clear_phy(iport, iphy); - case SCI_PORT_SUB_OPERATIONAL: - status = sci_port_clear_phy(iport, iphy); - if (status != SCI_SUCCESS) - return status; - - sci_port_deactivate_phy(iport, iphy, true); - iport->not_ready_reason = SCIC_PORT_NOT_READY_RECONFIGURING; - port_state_machine_change(iport, - SCI_PORT_SUB_CONFIGURING); - return SCI_SUCCESS; - case SCI_PORT_SUB_CONFIGURING: - status = sci_port_clear_phy(iport, iphy); - - if (status != SCI_SUCCESS) - return status; - sci_port_deactivate_phy(iport, iphy, true); - - /* Re-enter the configuring state since this may be the last phy in - * the port - */ - port_state_machine_change(iport, - SCI_PORT_SUB_CONFIGURING); - return SCI_SUCCESS; - default: - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -enum sci_status sci_port_link_up(struct isci_port *iport, - struct isci_phy *iphy) -{ - enum sci_port_states state; - - state = iport->sm.current_state_id; - switch (state) { - case SCI_PORT_SUB_WAITING: - /* Since this is the first phy going link up for the port we - * can just enable it and continue - */ - sci_port_activate_phy(iport, iphy, PF_NOTIFY|PF_RESUME); - - port_state_machine_change(iport, - SCI_PORT_SUB_OPERATIONAL); - return SCI_SUCCESS; - case SCI_PORT_SUB_OPERATIONAL: - sci_port_general_link_up_handler(iport, iphy, PF_NOTIFY|PF_RESUME); - return SCI_SUCCESS; - case SCI_PORT_RESETTING: - /* TODO We should make sure that the phy that has gone - * link up is the same one on which we sent the reset. It is - * possible that the phy on which we sent the reset is not the - * one that has gone link up and we want to make sure that - * phy being reset comes back. Consider the case where a - * reset is sent but before the hardware processes the reset it - * get a link up on the port because of a hot plug event. - * because of the reset request this phy will go link down - * almost immediately. - */ - - /* In the resetting state we don't notify the user regarding - * link up and link down notifications. - */ - sci_port_general_link_up_handler(iport, iphy, PF_RESUME); - return SCI_SUCCESS; - default: - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -enum sci_status sci_port_link_down(struct isci_port *iport, - struct isci_phy *iphy) -{ - enum sci_port_states state; - - state = iport->sm.current_state_id; - switch (state) { - case SCI_PORT_SUB_OPERATIONAL: - sci_port_deactivate_phy(iport, iphy, true); - - /* If there are no active phys left in the port, then - * transition the port to the WAITING state until such time - * as a phy goes link up - */ - if (iport->active_phy_mask == 0) - port_state_machine_change(iport, - SCI_PORT_SUB_WAITING); - return SCI_SUCCESS; - case SCI_PORT_RESETTING: - /* In the resetting state we don't notify the user regarding - * link up and link down notifications. */ - sci_port_deactivate_phy(iport, iphy, false); - return SCI_SUCCESS; - default: - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -enum sci_status sci_port_start_io(struct isci_port *iport, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - enum sci_port_states state; - - state = iport->sm.current_state_id; - switch (state) { - case SCI_PORT_SUB_WAITING: - return SCI_FAILURE_INVALID_STATE; - case SCI_PORT_SUB_OPERATIONAL: - iport->started_request_count++; - return SCI_SUCCESS; - default: - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -enum sci_status sci_port_complete_io(struct isci_port *iport, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - enum sci_port_states state; - - state = iport->sm.current_state_id; - switch (state) { - case SCI_PORT_STOPPED: - dev_warn(sciport_to_dev(iport), "%s: in wrong state: %s\n", - __func__, port_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - case SCI_PORT_STOPPING: - sci_port_decrement_request_count(iport); - - if (iport->started_request_count == 0) - port_state_machine_change(iport, - SCI_PORT_STOPPED); - break; - case SCI_PORT_READY: - case SCI_PORT_RESETTING: - case SCI_PORT_FAILED: - case SCI_PORT_SUB_WAITING: - case SCI_PORT_SUB_OPERATIONAL: - sci_port_decrement_request_count(iport); - break; - case SCI_PORT_SUB_CONFIGURING: - sci_port_decrement_request_count(iport); - if (iport->started_request_count == 0) { - port_state_machine_change(iport, - SCI_PORT_SUB_OPERATIONAL); - } - break; - } - return SCI_SUCCESS; -} - -static void sci_port_enable_port_task_scheduler(struct isci_port *iport) -{ - u32 pts_control_value; - - /* enable the port task scheduler in a suspended state */ - pts_control_value = readl(&iport->port_task_scheduler_registers->control); - pts_control_value |= SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND); - writel(pts_control_value, &iport->port_task_scheduler_registers->control); -} - -static void sci_port_disable_port_task_scheduler(struct isci_port *iport) -{ - u32 pts_control_value; - - pts_control_value = readl(&iport->port_task_scheduler_registers->control); - pts_control_value &= - ~(SCU_PTSxCR_GEN_BIT(ENABLE) | SCU_PTSxCR_GEN_BIT(SUSPEND)); - writel(pts_control_value, &iport->port_task_scheduler_registers->control); -} - -static void sci_port_post_dummy_remote_node(struct isci_port *iport) -{ - struct isci_host *ihost = iport->owning_controller; - u8 phys_index = iport->physical_port_index; - union scu_remote_node_context *rnc; - u16 rni = iport->reserved_rni; - u32 command; - - rnc = &ihost->remote_node_context_table[rni]; - rnc->ssp.is_valid = true; - - command = SCU_CONTEXT_COMMAND_POST_RNC_32 | - phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; - - sci_controller_post_request(ihost, command); - - /* ensure hardware has seen the post rnc command and give it - * ample time to act before sending the suspend - */ - readl(&ihost->smu_registers->interrupt_status); /* flush */ - udelay(10); - - command = SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX | - phys_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT | rni; - - sci_controller_post_request(ihost, command); -} - -static void sci_port_stopped_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - - if (iport->sm.previous_state_id == SCI_PORT_STOPPING) { - /* - * If we enter this state becasuse of a request to stop - * the port then we want to disable the hardwares port - * task scheduler. */ - sci_port_disable_port_task_scheduler(iport); - } -} - -static void sci_port_stopped_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - - /* Enable and suspend the port task scheduler */ - sci_port_enable_port_task_scheduler(iport); -} - -static void sci_port_ready_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - struct isci_host *ihost = iport->owning_controller; - u32 prev_state; - - prev_state = iport->sm.previous_state_id; - if (prev_state == SCI_PORT_RESETTING) - isci_port_hard_reset_complete(iport, SCI_SUCCESS); - else - dev_dbg(&ihost->pdev->dev, "%s: port%d !ready\n", - __func__, iport->physical_port_index); - - /* Post and suspend the dummy remote node context for this port. */ - sci_port_post_dummy_remote_node(iport); - - /* Start the ready substate machine */ - port_state_machine_change(iport, - SCI_PORT_SUB_WAITING); -} - -static void sci_port_resetting_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - - sci_del_timer(&iport->timer); -} - -static void sci_port_stopping_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - - sci_del_timer(&iport->timer); - - sci_port_destroy_dummy_resources(iport); -} - -static void sci_port_failed_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_port *iport = container_of(sm, typeof(*iport), sm); - - isci_port_hard_reset_complete(iport, SCI_FAILURE_TIMEOUT); -} - -/* --------------------------------------------------------------------------- */ - -static const struct sci_base_state sci_port_state_table[] = { - [SCI_PORT_STOPPED] = { - .enter_state = sci_port_stopped_state_enter, - .exit_state = sci_port_stopped_state_exit - }, - [SCI_PORT_STOPPING] = { - .exit_state = sci_port_stopping_state_exit - }, - [SCI_PORT_READY] = { - .enter_state = sci_port_ready_state_enter, - }, - [SCI_PORT_SUB_WAITING] = { - .enter_state = sci_port_ready_substate_waiting_enter, - .exit_state = scic_sds_port_ready_substate_waiting_exit, - }, - [SCI_PORT_SUB_OPERATIONAL] = { - .enter_state = sci_port_ready_substate_operational_enter, - .exit_state = sci_port_ready_substate_operational_exit - }, - [SCI_PORT_SUB_CONFIGURING] = { - .enter_state = sci_port_ready_substate_configuring_enter - }, - [SCI_PORT_RESETTING] = { - .exit_state = sci_port_resetting_state_exit - }, - [SCI_PORT_FAILED] = { - .enter_state = sci_port_failed_state_enter, - } -}; - -void sci_port_construct(struct isci_port *iport, u8 index, - struct isci_host *ihost) -{ - sci_init_sm(&iport->sm, sci_port_state_table, SCI_PORT_STOPPED); - - iport->logical_port_index = SCIC_SDS_DUMMY_PORT; - iport->physical_port_index = index; - iport->active_phy_mask = 0; - iport->enabled_phy_mask = 0; - iport->last_active_phy = 0; - iport->ready_exit = false; - - iport->owning_controller = ihost; - - iport->started_request_count = 0; - iport->assigned_device_count = 0; - - iport->reserved_rni = SCU_DUMMY_INDEX; - iport->reserved_tag = SCI_CONTROLLER_INVALID_IO_TAG; - - sci_init_timer(&iport->timer, port_timeout); - - iport->port_task_scheduler_registers = NULL; - - for (index = 0; index < SCI_MAX_PHYS; index++) - iport->phy_table[index] = NULL; -} - -void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index) -{ - INIT_LIST_HEAD(&iport->remote_dev_list); - INIT_LIST_HEAD(&iport->domain_dev_list); - iport->isci_host = ihost; -} - -void sci_port_broadcast_change_received(struct isci_port *iport, struct isci_phy *iphy) -{ - struct isci_host *ihost = iport->owning_controller; - - /* notify the user. */ - isci_port_bc_change_received(ihost, iport, iphy); -} - -static void wait_port_reset(struct isci_host *ihost, struct isci_port *iport) -{ - wait_event(ihost->eventq, !test_bit(IPORT_RESET_PENDING, &iport->state)); -} - -int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, - struct isci_phy *iphy) -{ - unsigned long flags; - enum sci_status status; - int ret = TMF_RESP_FUNC_COMPLETE; - - dev_dbg(&ihost->pdev->dev, "%s: iport = %p\n", - __func__, iport); - - spin_lock_irqsave(&ihost->scic_lock, flags); - set_bit(IPORT_RESET_PENDING, &iport->state); - - #define ISCI_PORT_RESET_TIMEOUT SCIC_SDS_SIGNATURE_FIS_TIMEOUT - status = sci_port_hard_reset(iport, ISCI_PORT_RESET_TIMEOUT); - - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (status == SCI_SUCCESS) { - wait_port_reset(ihost, iport); - - dev_dbg(&ihost->pdev->dev, - "%s: iport = %p; hard reset completion\n", - __func__, iport); - - if (iport->hard_reset_status != SCI_SUCCESS) { - ret = TMF_RESP_FUNC_FAILED; - - dev_err(&ihost->pdev->dev, - "%s: iport = %p; hard reset failed (0x%x)\n", - __func__, iport, iport->hard_reset_status); - } - } else { - clear_bit(IPORT_RESET_PENDING, &iport->state); - wake_up(&ihost->eventq); - ret = TMF_RESP_FUNC_FAILED; - - dev_err(&ihost->pdev->dev, - "%s: iport = %p; sci_port_hard_reset call" - " failed 0x%x\n", - __func__, iport, status); - - } - - /* If the hard reset for the port has failed, consider this - * the same as link failures on all phys in the port. - */ - if (ret != TMF_RESP_FUNC_COMPLETE) { - - dev_err(&ihost->pdev->dev, - "%s: iport = %p; hard reset failed " - "(0x%x) - driving explicit link fail for all phys\n", - __func__, iport, iport->hard_reset_status); - } - return ret; -} - -int isci_ata_check_ready(struct domain_device *dev) -{ - struct isci_port *iport = dev->port->lldd_port; - struct isci_host *ihost = dev_to_ihost(dev); - struct isci_remote_device *idev; - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&ihost->scic_lock, flags); - idev = isci_lookup_device(dev); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (!idev) - goto out; - - if (test_bit(IPORT_RESET_PENDING, &iport->state)) - goto out; - - rc = !!iport->active_phy_mask; - out: - isci_put_device(idev); - - return rc; -} - -void isci_port_deformed(struct asd_sas_phy *phy) -{ - struct isci_host *ihost = phy->ha->lldd_ha; - struct isci_port *iport = phy->port->lldd_port; - unsigned long flags; - int i; - - /* we got a port notification on a port that was subsequently - * torn down and libsas is just now catching up - */ - if (!iport) - return; - - spin_lock_irqsave(&ihost->scic_lock, flags); - for (i = 0; i < SCI_MAX_PHYS; i++) { - if (iport->active_phy_mask & 1 << i) - break; - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (i >= SCI_MAX_PHYS) - dev_dbg(&ihost->pdev->dev, "%s: port: %ld\n", - __func__, (long) (iport - &ihost->ports[0])); -} - -void isci_port_formed(struct asd_sas_phy *phy) -{ - struct isci_host *ihost = phy->ha->lldd_ha; - struct isci_phy *iphy = to_iphy(phy); - struct asd_sas_port *port = phy->port; - struct isci_port *iport; - unsigned long flags; - int i; - - /* initial ports are formed as the driver is still initializing, - * wait for that process to complete - */ - wait_for_start(ihost); - - spin_lock_irqsave(&ihost->scic_lock, flags); - for (i = 0; i < SCI_MAX_PORTS; i++) { - iport = &ihost->ports[i]; - if (iport->active_phy_mask & 1 << iphy->phy_index) - break; - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (i >= SCI_MAX_PORTS) - iport = NULL; - - port->lldd_port = iport; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/port.h b/ANDROID_3.4.5/drivers/scsi/isci/port.h deleted file mode 100644 index 6b56240c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/port.h +++ /dev/null @@ -1,284 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _ISCI_PORT_H_ -#define _ISCI_PORT_H_ - -#include -#include "isci.h" -#include "sas.h" -#include "phy.h" - -#define SCIC_SDS_DUMMY_PORT 0xFF - -#define PF_NOTIFY (1 << 0) -#define PF_RESUME (1 << 1) - -struct isci_phy; -struct isci_host; - -enum isci_status { - isci_freed = 0x00, - isci_starting = 0x01, - isci_ready = 0x02, - isci_ready_for_io = 0x03, - isci_stopping = 0x04, - isci_stopped = 0x05, -}; - -/** - * struct isci_port - isci direct attached sas port object - * @ready_exit: several states constitute 'ready'. When exiting ready we - * need to take extra port-teardown actions that are - * skipped when exiting to another 'ready' state. - * @logical_port_index: software port index - * @physical_port_index: hardware port index - * @active_phy_mask: identifies phy members - * @enabled_phy_mask: phy mask for the port - * that are already part of the port - * @reserved_tag: - * @reserved_rni: reserver for port task scheduler workaround - * @started_request_count: reference count for outstanding commands - * @not_ready_reason: set during state transitions and notified - * @timer: timeout start/stop operations - */ -struct isci_port { - struct isci_host *isci_host; - struct list_head remote_dev_list; - struct list_head domain_dev_list; - #define IPORT_RESET_PENDING 0 - unsigned long state; - enum sci_status hard_reset_status; - struct sci_base_state_machine sm; - bool ready_exit; - u8 logical_port_index; - u8 physical_port_index; - u8 active_phy_mask; - u8 enabled_phy_mask; - u8 last_active_phy; - u16 reserved_rni; - u16 reserved_tag; - u32 started_request_count; - u32 assigned_device_count; - u32 not_ready_reason; - struct isci_phy *phy_table[SCI_MAX_PHYS]; - struct isci_host *owning_controller; - struct sci_timer timer; - struct scu_port_task_scheduler_registers __iomem *port_task_scheduler_registers; - /* XXX rework: only one register, no need to replicate per-port */ - u32 __iomem *port_pe_configuration_register; - struct scu_viit_entry __iomem *viit_registers; -}; - -enum sci_port_not_ready_reason_code { - SCIC_PORT_NOT_READY_NO_ACTIVE_PHYS, - SCIC_PORT_NOT_READY_HARD_RESET_REQUESTED, - SCIC_PORT_NOT_READY_INVALID_PORT_CONFIGURATION, - SCIC_PORT_NOT_READY_RECONFIGURING, - - SCIC_PORT_NOT_READY_REASON_CODE_MAX -}; - -struct sci_port_end_point_properties { - struct sci_sas_address sas_address; - struct sci_phy_proto protocols; -}; - -struct sci_port_properties { - u32 index; - struct sci_port_end_point_properties local; - struct sci_port_end_point_properties remote; - u32 phy_mask; -}; - -/** - * enum sci_port_states - port state machine states - * @SCI_PORT_STOPPED: port has successfully been stopped. In this state - * no new IO operations are permitted. This state is - * entered from the STOPPING state. - * @SCI_PORT_STOPPING: port is in the process of stopping. In this - * state no new IO operations are permitted, but - * existing IO operations are allowed to complete. - * This state is entered from the READY state. - * @SCI_PORT_READY: port is now ready. Thus, the user is able to - * perform IO operations on this port. This state is - * entered from the STARTING state. - * @SCI_PORT_SUB_WAITING: port is started and ready but has no active - * phys. - * @SCI_PORT_SUB_OPERATIONAL: port is started and ready and there is at - * least one phy operational. - * @SCI_PORT_SUB_CONFIGURING: port is started and there was an - * add/remove phy event. This state is only - * used in Automatic Port Configuration Mode - * (APC) - * @SCI_PORT_RESETTING: port is in the process of performing a hard - * reset. Thus, the user is unable to perform IO - * operations on this port. This state is entered - * from the READY state. - * @SCI_PORT_FAILED: port has failed a reset request. This state is - * entered when a port reset request times out. This - * state is entered from the RESETTING state. - */ -#define PORT_STATES {\ - C(PORT_STOPPED),\ - C(PORT_STOPPING),\ - C(PORT_READY),\ - C(PORT_SUB_WAITING),\ - C(PORT_SUB_OPERATIONAL),\ - C(PORT_SUB_CONFIGURING),\ - C(PORT_RESETTING),\ - C(PORT_FAILED),\ - } -#undef C -#define C(a) SCI_##a -enum sci_port_states PORT_STATES; -#undef C - -static inline void sci_port_decrement_request_count(struct isci_port *iport) -{ - if (WARN_ONCE(iport->started_request_count == 0, - "%s: tried to decrement started_request_count past 0!?", - __func__)) - /* pass */; - else - iport->started_request_count--; -} - -#define sci_port_active_phy(port, phy) \ - (((port)->active_phy_mask & (1 << (phy)->phy_index)) != 0) - -void sci_port_construct( - struct isci_port *iport, - u8 port_index, - struct isci_host *ihost); - -enum sci_status sci_port_start(struct isci_port *iport); -enum sci_status sci_port_stop(struct isci_port *iport); - -enum sci_status sci_port_add_phy( - struct isci_port *iport, - struct isci_phy *iphy); - -enum sci_status sci_port_remove_phy( - struct isci_port *iport, - struct isci_phy *iphy); - -void sci_port_setup_transports( - struct isci_port *iport, - u32 device_id); - -void isci_port_bcn_enable(struct isci_host *, struct isci_port *); - -void sci_port_deactivate_phy( - struct isci_port *iport, - struct isci_phy *iphy, - bool do_notify_user); - -bool sci_port_link_detected( - struct isci_port *iport, - struct isci_phy *iphy); - -enum sci_status sci_port_get_properties( - struct isci_port *iport, - struct sci_port_properties *prop); - -enum sci_status sci_port_link_up(struct isci_port *iport, - struct isci_phy *iphy); -enum sci_status sci_port_link_down(struct isci_port *iport, - struct isci_phy *iphy); - -struct isci_request; -struct isci_remote_device; -enum sci_status sci_port_start_io( - struct isci_port *iport, - struct isci_remote_device *idev, - struct isci_request *ireq); - -enum sci_status sci_port_complete_io( - struct isci_port *iport, - struct isci_remote_device *idev, - struct isci_request *ireq); - -enum sas_linkrate sci_port_get_max_allowed_speed( - struct isci_port *iport); - -void sci_port_broadcast_change_received( - struct isci_port *iport, - struct isci_phy *iphy); - -bool sci_port_is_valid_phy_assignment( - struct isci_port *iport, - u32 phy_index); - -void sci_port_get_sas_address( - struct isci_port *iport, - struct sci_sas_address *sas_address); - -void sci_port_get_attached_sas_address( - struct isci_port *iport, - struct sci_sas_address *sas_address); - -void isci_port_formed(struct asd_sas_phy *); -void isci_port_deformed(struct asd_sas_phy *); - -void isci_port_init( - struct isci_port *port, - struct isci_host *host, - int index); - -int isci_port_perform_hard_reset(struct isci_host *ihost, struct isci_port *iport, - struct isci_phy *iphy); -int isci_ata_check_ready(struct domain_device *dev); -#endif /* !defined(_ISCI_PORT_H_) */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/port_config.c b/ANDROID_3.4.5/drivers/scsi/isci/port_config.c deleted file mode 100644 index 6d1e9544..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/port_config.c +++ /dev/null @@ -1,763 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "host.h" - -#define SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT (10) -#define SCIC_SDS_APC_RECONFIGURATION_TIMEOUT (10) -#define SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION (250) - -enum SCIC_SDS_APC_ACTIVITY { - SCIC_SDS_APC_SKIP_PHY, - SCIC_SDS_APC_ADD_PHY, - SCIC_SDS_APC_START_TIMER, - - SCIC_SDS_APC_ACTIVITY_MAX -}; - -/* - * ****************************************************************************** - * General port configuration agent routines - * ****************************************************************************** */ - -/** - * - * @address_one: A SAS Address to be compared. - * @address_two: A SAS Address to be compared. - * - * Compare the two SAS Address and if SAS Address One is greater than SAS - * Address Two then return > 0 else if SAS Address One is less than SAS Address - * Two return < 0 Otherwise they are the same return 0 A signed value of x > 0 - * > y where x is returned for Address One > Address Two y is returned for - * Address One < Address Two 0 is returned ofr Address One = Address Two - */ -static s32 sci_sas_address_compare( - struct sci_sas_address address_one, - struct sci_sas_address address_two) -{ - if (address_one.high > address_two.high) { - return 1; - } else if (address_one.high < address_two.high) { - return -1; - } else if (address_one.low > address_two.low) { - return 1; - } else if (address_one.low < address_two.low) { - return -1; - } - - /* The two SAS Address must be identical */ - return 0; -} - -/** - * - * @controller: The controller object used for the port search. - * @phy: The phy object to match. - * - * This routine will find a matching port for the phy. This means that the - * port and phy both have the same broadcast sas address and same received sas - * address. The port address or the NULL if there is no matching - * port. port address if the port can be found to match the phy. - * NULL if there is no matching port for the phy. - */ -static struct isci_port *sci_port_configuration_agent_find_port( - struct isci_host *ihost, - struct isci_phy *iphy) -{ - u8 i; - struct sci_sas_address port_sas_address; - struct sci_sas_address port_attached_device_address; - struct sci_sas_address phy_sas_address; - struct sci_sas_address phy_attached_device_address; - - /* - * Since this phy can be a member of a wide port check to see if one or - * more phys match the sent and received SAS address as this phy in which - * case it should participate in the same port. - */ - sci_phy_get_sas_address(iphy, &phy_sas_address); - sci_phy_get_attached_sas_address(iphy, &phy_attached_device_address); - - for (i = 0; i < ihost->logical_port_entries; i++) { - struct isci_port *iport = &ihost->ports[i]; - - sci_port_get_sas_address(iport, &port_sas_address); - sci_port_get_attached_sas_address(iport, &port_attached_device_address); - - if (sci_sas_address_compare(port_sas_address, phy_sas_address) == 0 && - sci_sas_address_compare(port_attached_device_address, phy_attached_device_address) == 0) - return iport; - } - - return NULL; -} - -/** - * - * @controller: This is the controller object that contains the port agent - * @port_agent: This is the port configruation agent for the controller. - * - * This routine will validate the port configuration is correct for the SCU - * hardware. The SCU hardware allows for port configurations as follows. LP0 - * -> (PE0), (PE0, PE1), (PE0, PE1, PE2, PE3) LP1 -> (PE1) LP2 -> (PE2), (PE2, - * PE3) LP3 -> (PE3) enum sci_status SCI_SUCCESS the port configuration is valid for - * this port configuration agent. SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION - * the port configuration is not valid for this port configuration agent. - */ -static enum sci_status sci_port_configuration_agent_validate_ports( - struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent) -{ - struct sci_sas_address first_address; - struct sci_sas_address second_address; - - /* - * Sanity check the max ranges for all the phys the max index - * is always equal to the port range index */ - if (port_agent->phy_valid_port_range[0].max_index != 0 || - port_agent->phy_valid_port_range[1].max_index != 1 || - port_agent->phy_valid_port_range[2].max_index != 2 || - port_agent->phy_valid_port_range[3].max_index != 3) - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - - /* - * This is a request to configure a single x4 port or at least attempt - * to make all the phys into a single port */ - if (port_agent->phy_valid_port_range[0].min_index == 0 && - port_agent->phy_valid_port_range[1].min_index == 0 && - port_agent->phy_valid_port_range[2].min_index == 0 && - port_agent->phy_valid_port_range[3].min_index == 0) - return SCI_SUCCESS; - - /* - * This is a degenerate case where phy 1 and phy 2 are assigned - * to the same port this is explicitly disallowed by the hardware - * unless they are part of the same x4 port and this condition was - * already checked above. */ - if (port_agent->phy_valid_port_range[2].min_index == 1) { - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - - /* - * PE0 and PE3 can never have the same SAS Address unless they - * are part of the same x4 wide port and we have already checked - * for this condition. */ - sci_phy_get_sas_address(&ihost->phys[0], &first_address); - sci_phy_get_sas_address(&ihost->phys[3], &second_address); - - if (sci_sas_address_compare(first_address, second_address) == 0) { - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - - /* - * PE0 and PE1 are configured into a 2x1 ports make sure that the - * SAS Address for PE0 and PE2 are different since they can not be - * part of the same port. */ - if (port_agent->phy_valid_port_range[0].min_index == 0 && - port_agent->phy_valid_port_range[1].min_index == 1) { - sci_phy_get_sas_address(&ihost->phys[0], &first_address); - sci_phy_get_sas_address(&ihost->phys[2], &second_address); - - if (sci_sas_address_compare(first_address, second_address) == 0) { - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - } - - /* - * PE2 and PE3 are configured into a 2x1 ports make sure that the - * SAS Address for PE1 and PE3 are different since they can not be - * part of the same port. */ - if (port_agent->phy_valid_port_range[2].min_index == 2 && - port_agent->phy_valid_port_range[3].min_index == 3) { - sci_phy_get_sas_address(&ihost->phys[1], &first_address); - sci_phy_get_sas_address(&ihost->phys[3], &second_address); - - if (sci_sas_address_compare(first_address, second_address) == 0) { - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - } - - return SCI_SUCCESS; -} - -/* - * ****************************************************************************** - * Manual port configuration agent routines - * ****************************************************************************** */ - -/* verify all of the phys in the same port are using the same SAS address */ -static enum sci_status -sci_mpc_agent_validate_phy_configuration(struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent) -{ - u32 phy_mask; - u32 assigned_phy_mask; - struct sci_sas_address sas_address; - struct sci_sas_address phy_assigned_address; - u8 port_index; - u8 phy_index; - - assigned_phy_mask = 0; - sas_address.high = 0; - sas_address.low = 0; - - for (port_index = 0; port_index < SCI_MAX_PORTS; port_index++) { - phy_mask = ihost->oem_parameters.ports[port_index].phy_mask; - - if (!phy_mask) - continue; - /* - * Make sure that one or more of the phys were not already assinged to - * a different port. */ - if ((phy_mask & ~assigned_phy_mask) == 0) { - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - - /* Find the starting phy index for this round through the loop */ - for (phy_index = 0; phy_index < SCI_MAX_PHYS; phy_index++) { - if ((phy_mask & (1 << phy_index)) == 0) - continue; - sci_phy_get_sas_address(&ihost->phys[phy_index], - &sas_address); - - /* - * The phy_index can be used as the starting point for the - * port range since the hardware starts all logical ports - * the same as the PE index. */ - port_agent->phy_valid_port_range[phy_index].min_index = port_index; - port_agent->phy_valid_port_range[phy_index].max_index = phy_index; - - if (phy_index != port_index) { - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - - break; - } - - /* - * See how many additional phys are being added to this logical port. - * Note: We have not moved the current phy_index so we will actually - * compare the startting phy with itself. - * This is expected and required to add the phy to the port. */ - while (phy_index < SCI_MAX_PHYS) { - if ((phy_mask & (1 << phy_index)) == 0) - continue; - sci_phy_get_sas_address(&ihost->phys[phy_index], - &phy_assigned_address); - - if (sci_sas_address_compare(sas_address, phy_assigned_address) != 0) { - /* - * The phy mask specified that this phy is part of the same port - * as the starting phy and it is not so fail this configuration */ - return SCI_FAILURE_UNSUPPORTED_PORT_CONFIGURATION; - } - - port_agent->phy_valid_port_range[phy_index].min_index = port_index; - port_agent->phy_valid_port_range[phy_index].max_index = phy_index; - - sci_port_add_phy(&ihost->ports[port_index], - &ihost->phys[phy_index]); - - assigned_phy_mask |= (1 << phy_index); - } - - phy_index++; - } - - return sci_port_configuration_agent_validate_ports(ihost, port_agent); -} - -static void mpc_agent_timeout(unsigned long data) -{ - u8 index; - struct sci_timer *tmr = (struct sci_timer *)data; - struct sci_port_configuration_agent *port_agent; - struct isci_host *ihost; - unsigned long flags; - u16 configure_phy_mask; - - port_agent = container_of(tmr, typeof(*port_agent), timer); - ihost = container_of(port_agent, typeof(*ihost), port_agent); - - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmr->cancel) - goto done; - - port_agent->timer_pending = false; - - /* Find the mask of phys that are reported read but as yet unconfigured into a port */ - configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - struct isci_phy *iphy = &ihost->phys[index]; - - if (configure_phy_mask & (1 << index)) { - port_agent->link_up_handler(ihost, port_agent, - phy_get_non_dummy_port(iphy), - iphy); - } - } - -done: - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - -static void sci_mpc_agent_link_up(struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent, - struct isci_port *iport, - struct isci_phy *iphy) -{ - /* If the port is NULL then the phy was not assigned to a port. - * This is because the phy was not given the same SAS Address as - * the other PHYs in the port. - */ - if (!iport) - return; - - port_agent->phy_ready_mask |= (1 << iphy->phy_index); - sci_port_link_up(iport, iphy); - if ((iport->active_phy_mask & (1 << iphy->phy_index))) - port_agent->phy_configured_mask |= (1 << iphy->phy_index); -} - -/** - * - * @controller: This is the controller object that receives the link down - * notification. - * @port: This is the port object associated with the phy. If the is no - * associated port this is an NULL. The port is an invalid - * handle only if the phy was never port of this port. This happens when - * the phy is not broadcasting the same SAS address as the other phys in the - * assigned port. - * @phy: This is the phy object which has gone link down. - * - * This function handles the manual port configuration link down notifications. - * Since all ports and phys are associated at initialization time we just turn - * around and notifiy the port object of the link down event. If this PHY is - * not associated with a port there is no action taken. Is it possible to get a - * link down notification from a phy that has no assocoated port? - */ -static void sci_mpc_agent_link_down( - struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent, - struct isci_port *iport, - struct isci_phy *iphy) -{ - if (iport != NULL) { - /* - * If we can form a new port from the remainder of the phys - * then we want to start the timer to allow the SCI User to - * cleanup old devices and rediscover the port before - * rebuilding the port with the phys that remain in the ready - * state. - */ - port_agent->phy_ready_mask &= ~(1 << iphy->phy_index); - port_agent->phy_configured_mask &= ~(1 << iphy->phy_index); - - /* - * Check to see if there are more phys waiting to be - * configured into a port. If there are allow the SCI User - * to tear down this port, if necessary, and then reconstruct - * the port after the timeout. - */ - if ((port_agent->phy_configured_mask == 0x0000) && - (port_agent->phy_ready_mask != 0x0000) && - !port_agent->timer_pending) { - port_agent->timer_pending = true; - - sci_mod_timer(&port_agent->timer, - SCIC_SDS_MPC_RECONFIGURATION_TIMEOUT); - } - - sci_port_link_down(iport, iphy); - } -} - -/* verify phys are assigned a valid SAS address for automatic port - * configuration mode. - */ -static enum sci_status -sci_apc_agent_validate_phy_configuration(struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent) -{ - u8 phy_index; - u8 port_index; - struct sci_sas_address sas_address; - struct sci_sas_address phy_assigned_address; - - phy_index = 0; - - while (phy_index < SCI_MAX_PHYS) { - port_index = phy_index; - - /* Get the assigned SAS Address for the first PHY on the controller. */ - sci_phy_get_sas_address(&ihost->phys[phy_index], - &sas_address); - - while (++phy_index < SCI_MAX_PHYS) { - sci_phy_get_sas_address(&ihost->phys[phy_index], - &phy_assigned_address); - - /* Verify each of the SAS address are all the same for every PHY */ - if (sci_sas_address_compare(sas_address, phy_assigned_address) == 0) { - port_agent->phy_valid_port_range[phy_index].min_index = port_index; - port_agent->phy_valid_port_range[phy_index].max_index = phy_index; - } else { - port_agent->phy_valid_port_range[phy_index].min_index = phy_index; - port_agent->phy_valid_port_range[phy_index].max_index = phy_index; - break; - } - } - } - - return sci_port_configuration_agent_validate_ports(ihost, port_agent); -} - -/* - * This routine will restart the automatic port configuration timeout - * timer for the next time period. This could be caused by either a link - * down event or a link up event where we can not yet tell to which a phy - * belongs. - */ -static void sci_apc_agent_start_timer( - struct sci_port_configuration_agent *port_agent, - u32 timeout) -{ - if (port_agent->timer_pending) - sci_del_timer(&port_agent->timer); - - port_agent->timer_pending = true; - sci_mod_timer(&port_agent->timer, timeout); -} - -static void sci_apc_agent_configure_ports(struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent, - struct isci_phy *iphy, - bool start_timer) -{ - u8 port_index; - enum sci_status status; - struct isci_port *iport; - enum SCIC_SDS_APC_ACTIVITY apc_activity = SCIC_SDS_APC_SKIP_PHY; - - iport = sci_port_configuration_agent_find_port(ihost, iphy); - - if (iport) { - if (sci_port_is_valid_phy_assignment(iport, iphy->phy_index)) - apc_activity = SCIC_SDS_APC_ADD_PHY; - else - apc_activity = SCIC_SDS_APC_SKIP_PHY; - } else { - /* - * There is no matching Port for this PHY so lets search through the - * Ports and see if we can add the PHY to its own port or maybe start - * the timer and wait to see if a wider port can be made. - * - * Note the break when we reach the condition of the port id == phy id */ - for (port_index = port_agent->phy_valid_port_range[iphy->phy_index].min_index; - port_index <= port_agent->phy_valid_port_range[iphy->phy_index].max_index; - port_index++) { - - iport = &ihost->ports[port_index]; - - /* First we must make sure that this PHY can be added to this Port. */ - if (sci_port_is_valid_phy_assignment(iport, iphy->phy_index)) { - /* - * Port contains a PHY with a greater PHY ID than the current - * PHY that has gone link up. This phy can not be part of any - * port so skip it and move on. */ - if (iport->active_phy_mask > (1 << iphy->phy_index)) { - apc_activity = SCIC_SDS_APC_SKIP_PHY; - break; - } - - /* - * We have reached the end of our Port list and have not found - * any reason why we should not either add the PHY to the port - * or wait for more phys to become active. */ - if (iport->physical_port_index == iphy->phy_index) { - /* - * The Port either has no active PHYs. - * Consider that if the port had any active PHYs we would have - * or active PHYs with - * a lower PHY Id than this PHY. */ - if (apc_activity != SCIC_SDS_APC_START_TIMER) { - apc_activity = SCIC_SDS_APC_ADD_PHY; - } - - break; - } - - /* - * The current Port has no active PHYs and this PHY could be part - * of this Port. Since we dont know as yet setup to start the - * timer and see if there is a better configuration. */ - if (iport->active_phy_mask == 0) { - apc_activity = SCIC_SDS_APC_START_TIMER; - } - } else if (iport->active_phy_mask != 0) { - /* - * The Port has an active phy and the current Phy can not - * participate in this port so skip the PHY and see if - * there is a better configuration. */ - apc_activity = SCIC_SDS_APC_SKIP_PHY; - } - } - } - - /* - * Check to see if the start timer operations should instead map to an - * add phy operation. This is caused because we have been waiting to - * add a phy to a port but could not becuase the automatic port - * configuration engine had a choice of possible ports for the phy. - * Since we have gone through a timeout we are going to restrict the - * choice to the smallest possible port. */ - if ( - (start_timer == false) - && (apc_activity == SCIC_SDS_APC_START_TIMER) - ) { - apc_activity = SCIC_SDS_APC_ADD_PHY; - } - - switch (apc_activity) { - case SCIC_SDS_APC_ADD_PHY: - status = sci_port_add_phy(iport, iphy); - - if (status == SCI_SUCCESS) { - port_agent->phy_configured_mask |= (1 << iphy->phy_index); - } - break; - - case SCIC_SDS_APC_START_TIMER: - sci_apc_agent_start_timer(port_agent, - SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); - break; - - case SCIC_SDS_APC_SKIP_PHY: - default: - /* do nothing the PHY can not be made part of a port at this time. */ - break; - } -} - -/** - * sci_apc_agent_link_up - handle apc link up events - * @scic: This is the controller object that receives the link up - * notification. - * @sci_port: This is the port object associated with the phy. If the is no - * associated port this is an NULL. - * @sci_phy: This is the phy object which has gone link up. - * - * This method handles the automatic port configuration for link up - * notifications. Is it possible to get a link down notification from a phy - * that has no assocoated port? - */ -static void sci_apc_agent_link_up(struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent, - struct isci_port *iport, - struct isci_phy *iphy) -{ - u8 phy_index = iphy->phy_index; - - if (!iport) { - /* the phy is not the part of this port */ - port_agent->phy_ready_mask |= 1 << phy_index; - sci_apc_agent_start_timer(port_agent, - SCIC_SDS_APC_WAIT_LINK_UP_NOTIFICATION); - } else { - /* the phy is already the part of the port */ - u32 port_state = iport->sm.current_state_id; - - /* if the PORT'S state is resetting then the link up is from - * port hard reset in this case, we need to tell the port - * that link up is recieved - */ - BUG_ON(port_state != SCI_PORT_RESETTING); - port_agent->phy_ready_mask |= 1 << phy_index; - sci_port_link_up(iport, iphy); - } -} - -/** - * - * @controller: This is the controller object that receives the link down - * notification. - * @iport: This is the port object associated with the phy. If the is no - * associated port this is an NULL. - * @iphy: This is the phy object which has gone link down. - * - * This method handles the automatic port configuration link down - * notifications. not associated with a port there is no action taken. Is it - * possible to get a link down notification from a phy that has no assocoated - * port? - */ -static void sci_apc_agent_link_down( - struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent, - struct isci_port *iport, - struct isci_phy *iphy) -{ - port_agent->phy_ready_mask &= ~(1 << iphy->phy_index); - - if (!iport) - return; - if (port_agent->phy_configured_mask & (1 << iphy->phy_index)) { - enum sci_status status; - - status = sci_port_remove_phy(iport, iphy); - - if (status == SCI_SUCCESS) - port_agent->phy_configured_mask &= ~(1 << iphy->phy_index); - } -} - -/* configure the phys into ports when the timer fires */ -static void apc_agent_timeout(unsigned long data) -{ - u32 index; - struct sci_timer *tmr = (struct sci_timer *)data; - struct sci_port_configuration_agent *port_agent; - struct isci_host *ihost; - unsigned long flags; - u16 configure_phy_mask; - - port_agent = container_of(tmr, typeof(*port_agent), timer); - ihost = container_of(port_agent, typeof(*ihost), port_agent); - - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmr->cancel) - goto done; - - port_agent->timer_pending = false; - - configure_phy_mask = ~port_agent->phy_configured_mask & port_agent->phy_ready_mask; - - if (!configure_phy_mask) - goto done; - - for (index = 0; index < SCI_MAX_PHYS; index++) { - if ((configure_phy_mask & (1 << index)) == 0) - continue; - - sci_apc_agent_configure_ports(ihost, port_agent, - &ihost->phys[index], false); - } - -done: - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - -/* - * ****************************************************************************** - * Public port configuration agent routines - * ****************************************************************************** */ - -/** - * - * - * This method will construct the port configuration agent for operation. This - * call is universal for both manual port configuration and automatic port - * configuration modes. - */ -void sci_port_configuration_agent_construct( - struct sci_port_configuration_agent *port_agent) -{ - u32 index; - - port_agent->phy_configured_mask = 0x00; - port_agent->phy_ready_mask = 0x00; - - port_agent->link_up_handler = NULL; - port_agent->link_down_handler = NULL; - - port_agent->timer_pending = false; - - for (index = 0; index < SCI_MAX_PORTS; index++) { - port_agent->phy_valid_port_range[index].min_index = 0; - port_agent->phy_valid_port_range[index].max_index = 0; - } -} - -enum sci_status sci_port_configuration_agent_initialize( - struct isci_host *ihost, - struct sci_port_configuration_agent *port_agent) -{ - enum sci_status status; - enum sci_port_configuration_mode mode; - - mode = ihost->oem_parameters.controller.mode_type; - - if (mode == SCIC_PORT_MANUAL_CONFIGURATION_MODE) { - status = sci_mpc_agent_validate_phy_configuration( - ihost, port_agent); - - port_agent->link_up_handler = sci_mpc_agent_link_up; - port_agent->link_down_handler = sci_mpc_agent_link_down; - - sci_init_timer(&port_agent->timer, mpc_agent_timeout); - } else { - status = sci_apc_agent_validate_phy_configuration( - ihost, port_agent); - - port_agent->link_up_handler = sci_apc_agent_link_up; - port_agent->link_down_handler = sci_apc_agent_link_down; - - sci_init_timer(&port_agent->timer, apc_agent_timeout); - } - - return status; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/probe_roms.c b/ANDROID_3.4.5/drivers/scsi/isci/probe_roms.c deleted file mode 100644 index 9b8117b9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/probe_roms.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - */ - -/* probe_roms - scan for oem parameters */ - -#include -#include -#include -#include -#include - -#include "isci.h" -#include "task.h" -#include "probe_roms.h" - -static efi_char16_t isci_efivar_name[] = { - 'R', 's', 't', 'S', 'c', 'u', 'O' -}; - -struct isci_orom *isci_request_oprom(struct pci_dev *pdev) -{ - void __iomem *oprom = pci_map_biosrom(pdev); - struct isci_orom *rom = NULL; - size_t len, i; - int j; - char oem_sig[4]; - struct isci_oem_hdr oem_hdr; - u8 *tmp, sum; - - if (!oprom) - return NULL; - - len = pci_biosrom_size(pdev); - rom = devm_kzalloc(&pdev->dev, sizeof(*rom), GFP_KERNEL); - if (!rom) { - dev_warn(&pdev->dev, - "Unable to allocate memory for orom\n"); - return NULL; - } - - for (i = 0; i < len && rom; i += ISCI_OEM_SIG_SIZE) { - memcpy_fromio(oem_sig, oprom + i, ISCI_OEM_SIG_SIZE); - - /* we think we found the OEM table */ - if (memcmp(oem_sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) == 0) { - size_t copy_len; - - memcpy_fromio(&oem_hdr, oprom + i, sizeof(oem_hdr)); - - copy_len = min(oem_hdr.len - sizeof(oem_hdr), - sizeof(*rom)); - - memcpy_fromio(rom, - oprom + i + sizeof(oem_hdr), - copy_len); - - /* calculate checksum */ - tmp = (u8 *)&oem_hdr; - for (j = 0, sum = 0; j < sizeof(oem_hdr); j++, tmp++) - sum += *tmp; - - tmp = (u8 *)rom; - for (j = 0; j < sizeof(*rom); j++, tmp++) - sum += *tmp; - - if (sum != 0) { - dev_warn(&pdev->dev, - "OEM table checksum failed\n"); - continue; - } - - /* keep going if that's not the oem param table */ - if (memcmp(rom->hdr.signature, - ISCI_ROM_SIG, - ISCI_ROM_SIG_SIZE) != 0) - continue; - - dev_info(&pdev->dev, - "OEM parameter table found in OROM\n"); - break; - } - } - - if (i >= len) { - dev_err(&pdev->dev, "oprom parse error\n"); - devm_kfree(&pdev->dev, rom); - rom = NULL; - } - pci_unmap_biosrom(oprom); - - return rom; -} - -enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem, - struct isci_orom *orom, int scu_index) -{ - /* check for valid inputs */ - if (scu_index < 0 || scu_index >= SCI_MAX_CONTROLLERS || - scu_index > orom->hdr.num_elements || !oem) - return -EINVAL; - - *oem = orom->ctrl[scu_index]; - return 0; -} - -struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw) -{ - struct isci_orom *orom = NULL, *data; - int i, j; - - if (request_firmware(&fw, ISCI_FW_NAME, &pdev->dev) != 0) - return NULL; - - if (fw->size < sizeof(*orom)) - goto out; - - data = (struct isci_orom *)fw->data; - - if (strncmp(ISCI_ROM_SIG, data->hdr.signature, - strlen(ISCI_ROM_SIG)) != 0) - goto out; - - orom = devm_kzalloc(&pdev->dev, fw->size, GFP_KERNEL); - if (!orom) - goto out; - - memcpy(orom, fw->data, fw->size); - - if (is_c0(pdev) || is_c1(pdev)) - goto out; - - /* - * deprecated: override default amp_control for pre-preproduction - * silicon revisions - */ - for (i = 0; i < ARRAY_SIZE(orom->ctrl); i++) - for (j = 0; j < ARRAY_SIZE(orom->ctrl[i].phys); j++) { - orom->ctrl[i].phys[j].afe_tx_amp_control0 = 0xe7c03; - orom->ctrl[i].phys[j].afe_tx_amp_control1 = 0xe7c03; - orom->ctrl[i].phys[j].afe_tx_amp_control2 = 0xe7c03; - orom->ctrl[i].phys[j].afe_tx_amp_control3 = 0xe7c03; - } - out: - release_firmware(fw); - - return orom; -} - -static struct efi *get_efi(void) -{ -#ifdef CONFIG_EFI - return &efi; -#else - return NULL; -#endif -} - -struct isci_orom *isci_get_efi_var(struct pci_dev *pdev) -{ - efi_status_t status; - struct isci_orom *rom; - struct isci_oem_hdr *oem_hdr; - u8 *tmp, sum; - int j; - unsigned long data_len; - u8 *efi_data; - u32 efi_attrib = 0; - - data_len = 1024; - efi_data = devm_kzalloc(&pdev->dev, data_len, GFP_KERNEL); - if (!efi_data) { - dev_warn(&pdev->dev, - "Unable to allocate memory for EFI data\n"); - return NULL; - } - - rom = (struct isci_orom *)(efi_data + sizeof(struct isci_oem_hdr)); - - if (get_efi()) - status = get_efi()->get_variable(isci_efivar_name, - &ISCI_EFI_VENDOR_GUID, - &efi_attrib, - &data_len, - efi_data); - else - status = EFI_NOT_FOUND; - - if (status != EFI_SUCCESS) { - dev_warn(&pdev->dev, - "Unable to obtain EFI var data for OEM parms\n"); - return NULL; - } - - oem_hdr = (struct isci_oem_hdr *)efi_data; - - if (memcmp(oem_hdr->sig, ISCI_OEM_SIG, ISCI_OEM_SIG_SIZE) != 0) { - dev_warn(&pdev->dev, - "Invalid OEM header signature\n"); - return NULL; - } - - /* calculate checksum */ - tmp = (u8 *)efi_data; - for (j = 0, sum = 0; j < (sizeof(*oem_hdr) + sizeof(*rom)); j++, tmp++) - sum += *tmp; - - if (sum != 0) { - dev_warn(&pdev->dev, - "OEM table checksum failed\n"); - return NULL; - } - - if (memcmp(rom->hdr.signature, - ISCI_ROM_SIG, - ISCI_ROM_SIG_SIZE) != 0) { - dev_warn(&pdev->dev, - "Invalid OEM table signature\n"); - return NULL; - } - - return rom; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/probe_roms.h b/ANDROID_3.4.5/drivers/scsi/isci/probe_roms.h deleted file mode 100644 index bb0e9d4d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/probe_roms.h +++ /dev/null @@ -1,332 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _ISCI_PROBE_ROMS_H_ -#define _ISCI_PROBE_ROMS_H_ - -#ifdef __KERNEL__ -#include -#include -#include -#include "isci.h" - -#define SCIC_SDS_PARM_NO_SPEED 0 - -/* generation 1 (i.e. 1.5 Gb/s) */ -#define SCIC_SDS_PARM_GEN1_SPEED 1 - -/* generation 2 (i.e. 3.0 Gb/s) */ -#define SCIC_SDS_PARM_GEN2_SPEED 2 - -/* generation 3 (i.e. 6.0 Gb/s) */ -#define SCIC_SDS_PARM_GEN3_SPEED 3 -#define SCIC_SDS_PARM_MAX_SPEED SCIC_SDS_PARM_GEN3_SPEED - -/* parameters that can be set by module parameters */ -struct sci_user_parameters { - struct sci_phy_user_params { - /** - * This field specifies the NOTIFY (ENABLE SPIN UP) primitive - * insertion frequency for this phy index. - */ - u32 notify_enable_spin_up_insertion_frequency; - - /** - * This method specifies the number of transmitted DWORDs within which - * to transmit a single ALIGN primitive. This value applies regardless - * of what type of device is attached or connection state. A value of - * 0 indicates that no ALIGN primitives will be inserted. - */ - u16 align_insertion_frequency; - - /** - * This method specifies the number of transmitted DWORDs within which - * to transmit 2 ALIGN primitives. This applies for SAS connections - * only. A minimum value of 3 is required for this field. - */ - u16 in_connection_align_insertion_frequency; - - /** - * This field indicates the maximum speed generation to be utilized - * by phys in the supplied port. - * - A value of 1 indicates generation 1 (i.e. 1.5 Gb/s). - * - A value of 2 indicates generation 2 (i.e. 3.0 Gb/s). - * - A value of 3 indicates generation 3 (i.e. 6.0 Gb/s). - */ - u8 max_speed_generation; - - } phys[SCI_MAX_PHYS]; - - /** - * This field specifies the maximum number of direct attached devices - * that can have power supplied to them simultaneously. - */ - u8 max_concurr_spinup; - - /** - * This field specifies the number of seconds to allow a phy to consume - * power before yielding to another phy. - * - */ - u8 phy_spin_up_delay_interval; - - /** - * These timer values specifies how long a link will remain open with no - * activity in increments of a microsecond, it can be in increments of - * 100 microseconds if the upper most bit is set. - * - */ - u16 stp_inactivity_timeout; - u16 ssp_inactivity_timeout; - - /** - * These timer values specifies how long a link will remain open in increments - * of 100 microseconds. - * - */ - u16 stp_max_occupancy_timeout; - u16 ssp_max_occupancy_timeout; - - /** - * This timer value specifies how long a link will remain open with no - * outbound traffic in increments of a microsecond. - * - */ - u8 no_outbound_task_timeout; - -}; - -#define SCIC_SDS_PARM_PHY_MASK_MIN 0x0 -#define SCIC_SDS_PARM_PHY_MASK_MAX 0xF -#define MAX_CONCURRENT_DEVICE_SPIN_UP_COUNT 4 - -struct sci_oem_params; -int sci_oem_parameters_validate(struct sci_oem_params *oem, u8 version); - -struct isci_orom; -struct isci_orom *isci_request_oprom(struct pci_dev *pdev); -enum sci_status isci_parse_oem_parameters(struct sci_oem_params *oem, - struct isci_orom *orom, int scu_index); -struct isci_orom *isci_request_firmware(struct pci_dev *pdev, const struct firmware *fw); -struct isci_orom *isci_get_efi_var(struct pci_dev *pdev); - -struct isci_oem_hdr { - u8 sig[4]; - u8 rev_major; - u8 rev_minor; - u16 len; - u8 checksum; - u8 reserved1; - u16 reserved2; -} __attribute__ ((packed)); - -#else -#define SCI_MAX_PORTS 4 -#define SCI_MAX_PHYS 4 -#define SCI_MAX_CONTROLLERS 2 -#endif - -#define ISCI_FW_NAME "isci/isci_firmware.bin" - -#define ROMSIGNATURE 0xaa55 - -#define ISCI_OEM_SIG "$OEM" -#define ISCI_OEM_SIG_SIZE 4 -#define ISCI_ROM_SIG "ISCUOEMB" -#define ISCI_ROM_SIG_SIZE 8 - -#define ISCI_EFI_VENDOR_GUID \ - EFI_GUID(0x193dfefa, 0xa445, 0x4302, 0x99, 0xd8, 0xef, 0x3a, 0xad, \ - 0x1a, 0x04, 0xc6) -#define ISCI_EFI_VAR_NAME "RstScuO" - -#define ISCI_ROM_VER_1_0 0x10 -#define ISCI_ROM_VER_1_1 0x11 -#define ISCI_ROM_VER_1_3 0x13 -#define ISCI_ROM_VER_LATEST ISCI_ROM_VER_1_3 - -/* Allowed PORT configuration modes APC Automatic PORT configuration mode is - * defined by the OEM configuration parameters providing no PHY_MASK parameters - * for any PORT. i.e. There are no phys assigned to any of the ports at start. - * MPC Manual PORT configuration mode is defined by the OEM configuration - * parameters providing a PHY_MASK value for any PORT. It is assumed that any - * PORT with no PHY_MASK is an invalid port and not all PHYs must be assigned. - * A PORT_PHY mask that assigns just a single PHY to a port and no other PHYs - * being assigned is sufficient to declare manual PORT configuration. - */ -enum sci_port_configuration_mode { - SCIC_PORT_MANUAL_CONFIGURATION_MODE = 0, - SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE = 1 -}; - -struct sci_bios_oem_param_block_hdr { - uint8_t signature[ISCI_ROM_SIG_SIZE]; - uint16_t total_block_length; - uint8_t hdr_length; - uint8_t version; - uint8_t preboot_source; - uint8_t num_elements; - uint16_t element_length; - uint8_t reserved[8]; -} __attribute__ ((packed)); - -struct sci_oem_params { - struct { - uint8_t mode_type; - uint8_t max_concurr_spin_up; - /* - * This bitfield indicates the OEM's desired default Tx - * Spread Spectrum Clocking (SSC) settings for SATA and SAS. - * NOTE: Default SSC Modulation Frequency is 31.5KHz. - */ - union { - struct { - /* - * NOTE: Max spread for SATA is +0 / -5000 PPM. - * Down-spreading SSC (only method allowed for SATA): - * SATA SSC Tx Disabled = 0x0 - * SATA SSC Tx at +0 / -1419 PPM Spread = 0x2 - * SATA SSC Tx at +0 / -2129 PPM Spread = 0x3 - * SATA SSC Tx at +0 / -4257 PPM Spread = 0x6 - * SATA SSC Tx at +0 / -4967 PPM Spread = 0x7 - */ - uint8_t ssc_sata_tx_spread_level:4; - /* - * SAS SSC Tx Disabled = 0x0 - * - * NOTE: Max spread for SAS down-spreading +0 / - * -2300 PPM - * Down-spreading SSC: - * SAS SSC Tx at +0 / -1419 PPM Spread = 0x2 - * SAS SSC Tx at +0 / -2129 PPM Spread = 0x3 - * - * NOTE: Max spread for SAS center-spreading +2300 / - * -2300 PPM - * Center-spreading SSC: - * SAS SSC Tx at +1064 / -1064 PPM Spread = 0x3 - * SAS SSC Tx at +2129 / -2129 PPM Spread = 0x6 - */ - uint8_t ssc_sas_tx_spread_level:3; - /* - * NOTE: Refer to the SSC section of the SAS 2.x - * Specification for proper setting of this field. - * For standard SAS Initiator SAS PHY operation it - * should be 0 for Down-spreading. - * SAS SSC Tx spread type: - * Down-spreading SSC = 0 - * Center-spreading SSC = 1 - */ - uint8_t ssc_sas_tx_type:1; - }; - uint8_t do_enable_ssc; - }; - /* - * This field indicates length of the SAS/SATA cable between - * host and device. - * This field is used make relationship between analog - * parameters of the phy in the silicon and length of the cable. - * Supported cable attenuation levels: - * "short"- up to 3m, "medium"-3m to 6m, and "long"- more than - * 6m. - * - * This is bit mask field: - * - * BIT: (MSB) 7 6 5 4 - * ASSIGNMENT: - Medium cable - * length assignment - * BIT: 3 2 1 0 (LSB) - * ASSIGNMENT: - Long cable length - * assignment - * - * BITS 7-4 are set when the cable length is assigned to medium - * BITS 3-0 are set when the cable length is assigned to long - * - * The BIT positions are clear when the cable length is - * assigned to short. - * - * Setting the bits for both long and medium cable length is - * undefined. - * - * A value of 0x84 would assign - * phy3 - medium - * phy2 - long - * phy1 - short - * phy0 - short - */ - uint8_t cable_selection_mask; - } controller; - - struct { - uint8_t phy_mask; - } ports[SCI_MAX_PORTS]; - - struct sci_phy_oem_params { - struct { - uint32_t high; - uint32_t low; - } sas_address; - - uint32_t afe_tx_amp_control0; - uint32_t afe_tx_amp_control1; - uint32_t afe_tx_amp_control2; - uint32_t afe_tx_amp_control3; - } phys[SCI_MAX_PHYS]; -} __attribute__ ((packed)); - -struct isci_orom { - struct sci_bios_oem_param_block_hdr hdr; - struct sci_oem_params ctrl[SCI_MAX_CONTROLLERS]; -} __attribute__ ((packed)); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/isci/registers.h b/ANDROID_3.4.5/drivers/scsi/isci/registers.h deleted file mode 100644 index 7eb0ccd4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/registers.h +++ /dev/null @@ -1,1855 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCU_REGISTERS_H_ -#define _SCU_REGISTERS_H_ - -/** - * This file contains the constants and structures for the SCU memory mapped - * registers. - * - * - */ - -#define SCU_VIIT_ENTRY_ID_MASK (0xC0000000) -#define SCU_VIIT_ENTRY_ID_SHIFT (30) - -#define SCU_VIIT_ENTRY_FUNCTION_MASK (0x0FF00000) -#define SCU_VIIT_ENTRY_FUNCTION_SHIFT (20) - -#define SCU_VIIT_ENTRY_IPPTMODE_MASK (0x0001F800) -#define SCU_VIIT_ENTRY_IPPTMODE_SHIFT (12) - -#define SCU_VIIT_ENTRY_LPVIE_MASK (0x00000F00) -#define SCU_VIIT_ENTRY_LPVIE_SHIFT (8) - -#define SCU_VIIT_ENTRY_STATUS_MASK (0x000000FF) -#define SCU_VIIT_ENTRY_STATUS_SHIFT (0) - -#define SCU_VIIT_ENTRY_ID_INVALID (0 << SCU_VIIT_ENTRY_ID_SHIFT) -#define SCU_VIIT_ENTRY_ID_VIIT (1 << SCU_VIIT_ENTRY_ID_SHIFT) -#define SCU_VIIT_ENTRY_ID_IIT (2 << SCU_VIIT_ENTRY_ID_SHIFT) -#define SCU_VIIT_ENTRY_ID_VIRT_EXP (3 << SCU_VIIT_ENTRY_ID_SHIFT) - -#define SCU_VIIT_IPPT_SSP_INITIATOR (0x01 << SCU_VIIT_ENTRY_IPPTMODE_SHIFT) -#define SCU_VIIT_IPPT_SMP_INITIATOR (0x02 << SCU_VIIT_ENTRY_IPPTMODE_SHIFT) -#define SCU_VIIT_IPPT_STP_INITIATOR (0x04 << SCU_VIIT_ENTRY_IPPTMODE_SHIFT) -#define SCU_VIIT_IPPT_INITIATOR \ - (\ - SCU_VIIT_IPPT_SSP_INITIATOR \ - | SCU_VIIT_IPPT_SMP_INITIATOR \ - | SCU_VIIT_IPPT_STP_INITIATOR \ - ) - -#define SCU_VIIT_STATUS_RNC_VALID (0x01 << SCU_VIIT_ENTRY_STATUS_SHIFT) -#define SCU_VIIT_STATUS_ADDRESS_VALID (0x02 << SCU_VIIT_ENTRY_STATUS_SHIFT) -#define SCU_VIIT_STATUS_RNI_VALID (0x04 << SCU_VIIT_ENTRY_STATUS_SHIFT) -#define SCU_VIIT_STATUS_ALL_VALID \ - (\ - SCU_VIIT_STATUS_RNC_VALID \ - | SCU_VIIT_STATUS_ADDRESS_VALID \ - | SCU_VIIT_STATUS_RNI_VALID \ - ) - -#define SCU_VIIT_IPPT_SMP_TARGET (0x10 << SCU_VIIT_ENTRY_IPPTMODE_SHIFT) - -/** - * struct scu_viit_entry - This is the SCU Virtual Initiator Table Entry - * - * - */ -struct scu_viit_entry { - /** - * This must be encoded as to the type of initiator that is being constructed - * for this port. - */ - u32 status; - - /** - * Virtual initiator high SAS Address - */ - u32 initiator_sas_address_hi; - - /** - * Virtual initiator low SAS Address - */ - u32 initiator_sas_address_lo; - - /** - * This must be 0 - */ - u32 reserved; - -}; - - -/* IIT Status Defines */ -#define SCU_IIT_ENTRY_ID_MASK (0xC0000000) -#define SCU_IIT_ENTRY_ID_SHIFT (30) - -#define SCU_IIT_ENTRY_STATUS_UPDATE_MASK (0x20000000) -#define SCU_IIT_ENTRY_STATUS_UPDATE_SHIFT (29) - -#define SCU_IIT_ENTRY_LPI_MASK (0x00000F00) -#define SCU_IIT_ENTRY_LPI_SHIFT (8) - -#define SCU_IIT_ENTRY_STATUS_MASK (0x000000FF) -#define SCU_IIT_ENTRY_STATUS_SHIFT (0) - -/* IIT Remote Initiator Defines */ -#define SCU_IIT_ENTRY_REMOTE_TAG_MASK (0x0000FFFF) -#define SCU_IIT_ENTRY_REMOTE_TAG_SHIFT (0) - -#define SCU_IIT_ENTRY_REMOTE_RNC_MASK (0x0FFF0000) -#define SCU_IIT_ENTRY_REMOTE_RNC_SHIFT (16) - -#define SCU_IIT_ENTRY_ID_INVALID (0 << SCU_IIT_ENTRY_ID_SHIFT) -#define SCU_IIT_ENTRY_ID_VIIT (1 << SCU_IIT_ENTRY_ID_SHIFT) -#define SCU_IIT_ENTRY_ID_IIT (2 << SCU_IIT_ENTRY_ID_SHIFT) -#define SCU_IIT_ENTRY_ID_VIRT_EXP (3 << SCU_IIT_ENTRY_ID_SHIFT) - -/** - * struct scu_iit_entry - This will be implemented later when we support - * virtual functions - * - * - */ -struct scu_iit_entry { - u32 status; - u32 remote_initiator_sas_address_hi; - u32 remote_initiator_sas_address_lo; - u32 remote_initiator; - -}; - -/* Generate a value for an SCU register */ -#define SCU_GEN_VALUE(name, value) \ - (((value) << name ## _SHIFT) & (name ## _MASK)) - -/* - * Generate a bit value for an SCU register - * Make sure that the register MASK is just a single bit */ -#define SCU_GEN_BIT(name) \ - SCU_GEN_VALUE(name, ((u32)1)) - -#define SCU_SET_BIT(name, reg_value) \ - ((reg_value) | SCU_GEN_BIT(name)) - -#define SCU_CLEAR_BIT(name, reg_value) \ - ((reg_value)$ ~(SCU_GEN_BIT(name))) - -/* - * ***************************************************************************** - * Unions for bitfield definitions of SCU Registers - * SMU Post Context Port - * ***************************************************************************** */ -#define SMU_POST_CONTEXT_PORT_CONTEXT_INDEX_SHIFT (0) -#define SMU_POST_CONTEXT_PORT_CONTEXT_INDEX_MASK (0x00000FFF) -#define SMU_POST_CONTEXT_PORT_LOGICAL_PORT_INDEX_SHIFT (12) -#define SMU_POST_CONTEXT_PORT_LOGICAL_PORT_INDEX_MASK (0x0000F000) -#define SMU_POST_CONTEXT_PORT_PROTOCOL_ENGINE_SHIFT (16) -#define SMU_POST_CONTEXT_PORT_PROTOCOL_ENGINE_MASK (0x00030000) -#define SMU_POST_CONTEXT_PORT_COMMAND_CONTEXT_SHIFT (18) -#define SMU_POST_CONTEXT_PORT_COMMAND_CONTEXT_MASK (0x00FC0000) -#define SMU_POST_CONTEXT_PORT_RESERVED_MASK (0xFF000000) - -#define SMU_PCP_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_POST_CONTEXT_PORT_ ## name, value) - -/* ***************************************************************************** */ -#define SMU_INTERRUPT_STATUS_COMPLETION_SHIFT (31) -#define SMU_INTERRUPT_STATUS_COMPLETION_MASK (0x80000000) -#define SMU_INTERRUPT_STATUS_QUEUE_SUSPEND_SHIFT (1) -#define SMU_INTERRUPT_STATUS_QUEUE_SUSPEND_MASK (0x00000002) -#define SMU_INTERRUPT_STATUS_QUEUE_ERROR_SHIFT (0) -#define SMU_INTERRUPT_STATUS_QUEUE_ERROR_MASK (0x00000001) -#define SMU_INTERRUPT_STATUS_RESERVED_MASK (0x7FFFFFFC) - -#define SMU_ISR_GEN_BIT(name) \ - SCU_GEN_BIT(SMU_INTERRUPT_STATUS_ ## name) - -#define SMU_ISR_QUEUE_ERROR SMU_ISR_GEN_BIT(QUEUE_ERROR) -#define SMU_ISR_QUEUE_SUSPEND SMU_ISR_GEN_BIT(QUEUE_SUSPEND) -#define SMU_ISR_COMPLETION SMU_ISR_GEN_BIT(COMPLETION) - -/* ***************************************************************************** */ -#define SMU_INTERRUPT_MASK_COMPLETION_SHIFT (31) -#define SMU_INTERRUPT_MASK_COMPLETION_MASK (0x80000000) -#define SMU_INTERRUPT_MASK_QUEUE_SUSPEND_SHIFT (1) -#define SMU_INTERRUPT_MASK_QUEUE_SUSPEND_MASK (0x00000002) -#define SMU_INTERRUPT_MASK_QUEUE_ERROR_SHIFT (0) -#define SMU_INTERRUPT_MASK_QUEUE_ERROR_MASK (0x00000001) -#define SMU_INTERRUPT_MASK_RESERVED_MASK (0x7FFFFFFC) - -#define SMU_IMR_GEN_BIT(name) \ - SCU_GEN_BIT(SMU_INTERRUPT_MASK_ ## name) - -#define SMU_IMR_QUEUE_ERROR SMU_IMR_GEN_BIT(QUEUE_ERROR) -#define SMU_IMR_QUEUE_SUSPEND SMU_IMR_GEN_BIT(QUEUE_SUSPEND) -#define SMU_IMR_COMPLETION SMU_IMR_GEN_BIT(COMPLETION) - -/* ***************************************************************************** */ -#define SMU_INTERRUPT_COALESCING_CONTROL_TIMER_SHIFT (0) -#define SMU_INTERRUPT_COALESCING_CONTROL_TIMER_MASK (0x0000001F) -#define SMU_INTERRUPT_COALESCING_CONTROL_NUMBER_SHIFT (8) -#define SMU_INTERRUPT_COALESCING_CONTROL_NUMBER_MASK (0x0000FF00) -#define SMU_INTERRUPT_COALESCING_CONTROL_RESERVED_MASK (0xFFFF00E0) - -#define SMU_ICC_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_INTERRUPT_COALESCING_CONTROL_ ## name, value) - -/* ***************************************************************************** */ -#define SMU_TASK_CONTEXT_RANGE_START_SHIFT (0) -#define SMU_TASK_CONTEXT_RANGE_START_MASK (0x00000FFF) -#define SMU_TASK_CONTEXT_RANGE_ENDING_SHIFT (16) -#define SMU_TASK_CONTEXT_RANGE_ENDING_MASK (0x0FFF0000) -#define SMU_TASK_CONTEXT_RANGE_ENABLE_SHIFT (31) -#define SMU_TASK_CONTEXT_RANGE_ENABLE_MASK (0x80000000) -#define SMU_TASK_CONTEXT_RANGE_RESERVED_MASK (0x7000F000) - -#define SMU_TCR_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_TASK_CONTEXT_RANGE_ ## name, value) - -#define SMU_TCR_GEN_BIT(name, value) \ - SCU_GEN_BIT(SMU_TASK_CONTEXT_RANGE_ ## name) - -/* ***************************************************************************** */ - -#define SMU_COMPLETION_QUEUE_PUT_POINTER_SHIFT (0) -#define SMU_COMPLETION_QUEUE_PUT_POINTER_MASK (0x00003FFF) -#define SMU_COMPLETION_QUEUE_PUT_CYCLE_BIT_SHIFT (15) -#define SMU_COMPLETION_QUEUE_PUT_CYCLE_BIT_MASK (0x00008000) -#define SMU_COMPLETION_QUEUE_PUT_EVENT_POINTER_SHIFT (16) -#define SMU_COMPLETION_QUEUE_PUT_EVENT_POINTER_MASK (0x03FF0000) -#define SMU_COMPLETION_QUEUE_PUT_EVENT_CYCLE_BIT_SHIFT (26) -#define SMU_COMPLETION_QUEUE_PUT_EVENT_CYCLE_BIT_MASK (0x04000000) -#define SMU_COMPLETION_QUEUE_PUT_RESERVED_MASK (0xF8004000) - -#define SMU_CQPR_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_COMPLETION_QUEUE_PUT_ ## name, value) - -#define SMU_CQPR_GEN_BIT(name) \ - SCU_GEN_BIT(SMU_COMPLETION_QUEUE_PUT_ ## name) - -/* ***************************************************************************** */ - -#define SMU_COMPLETION_QUEUE_GET_POINTER_SHIFT (0) -#define SMU_COMPLETION_QUEUE_GET_POINTER_MASK (0x00003FFF) -#define SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_SHIFT (15) -#define SMU_COMPLETION_QUEUE_GET_CYCLE_BIT_MASK (0x00008000) -#define SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_SHIFT (16) -#define SMU_COMPLETION_QUEUE_GET_EVENT_POINTER_MASK (0x03FF0000) -#define SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_SHIFT (26) -#define SMU_COMPLETION_QUEUE_GET_EVENT_CYCLE_BIT_MASK (0x04000000) -#define SMU_COMPLETION_QUEUE_GET_ENABLE_SHIFT (30) -#define SMU_COMPLETION_QUEUE_GET_ENABLE_MASK (0x40000000) -#define SMU_COMPLETION_QUEUE_GET_EVENT_ENABLE_SHIFT (31) -#define SMU_COMPLETION_QUEUE_GET_EVENT_ENABLE_MASK (0x80000000) -#define SMU_COMPLETION_QUEUE_GET_RESERVED_MASK (0x38004000) - -#define SMU_CQGR_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_COMPLETION_QUEUE_GET_ ## name, value) - -#define SMU_CQGR_GEN_BIT(name) \ - SCU_GEN_BIT(SMU_COMPLETION_QUEUE_GET_ ## name) - -#define SMU_CQGR_CYCLE_BIT \ - SMU_CQGR_GEN_BIT(CYCLE_BIT) - -#define SMU_CQGR_EVENT_CYCLE_BIT \ - SMU_CQGR_GEN_BIT(EVENT_CYCLE_BIT) - -#define SMU_CQGR_GET_POINTER_SET(value) \ - SMU_CQGR_GEN_VAL(POINTER, value) - - -/* ***************************************************************************** */ -#define SMU_COMPLETION_QUEUE_CONTROL_QUEUE_LIMIT_SHIFT (0) -#define SMU_COMPLETION_QUEUE_CONTROL_QUEUE_LIMIT_MASK (0x00003FFF) -#define SMU_COMPLETION_QUEUE_CONTROL_EVENT_LIMIT_SHIFT (16) -#define SMU_COMPLETION_QUEUE_CONTROL_EVENT_LIMIT_MASK (0x03FF0000) -#define SMU_COMPLETION_QUEUE_CONTROL_RESERVED_MASK (0xFC00C000) - -#define SMU_CQC_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_COMPLETION_QUEUE_CONTROL_ ## name, value) - -#define SMU_CQC_QUEUE_LIMIT_SET(value) \ - SMU_CQC_GEN_VAL(QUEUE_LIMIT, value) - -#define SMU_CQC_EVENT_LIMIT_SET(value) \ - SMU_CQC_GEN_VAL(EVENT_LIMIT, value) - - -/* ***************************************************************************** */ -#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT (0) -#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK (0x00000FFF) -#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT (12) -#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK (0x00007000) -#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT (15) -#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK (0x07FF8000) -#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_SHIFT (27) -#define SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_MASK (0x08000000) -#define SMU_DEVICE_CONTEXT_CAPACITY_RESERVED_MASK (0xF0000000) - -#define SMU_DCC_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_DEVICE_CONTEXT_CAPACITY_ ## name, value) - -#define SMU_DCC_GET_MAX_PEG(value) \ - (\ - ((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_PEG_MASK) \ - >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT \ - ) - -#define SMU_DCC_GET_MAX_LP(value) \ - (\ - ((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_MASK) \ - >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_LP_SHIFT \ - ) - -#define SMU_DCC_GET_MAX_TC(value) \ - (\ - ((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_MASK) \ - >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_TC_SHIFT \ - ) - -#define SMU_DCC_GET_MAX_RNC(value) \ - (\ - ((value) & SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_MASK) \ - >> SMU_DEVICE_CONTEXT_CAPACITY_MAX_RNC_SHIFT \ - ) - -/* ***************************************************************************** */ -#define SMU_CLOCK_GATING_CONTROL_IDLE_ENABLE_SHIFT (0) -#define SMU_CLOCK_GATING_CONTROL_IDLE_ENABLE_MASK (0x00000001) -#define SMU_CLOCK_GATING_CONTROL_XCLK_ENABLE_SHIFT (1) -#define SMU_CLOCK_GATING_CONTROL_XCLK_ENABLE_MASK (0x00000002) -#define SMU_CLOCK_GATING_CONTROL_TXCLK_ENABLE_SHIFT (2) -#define SMU_CLOCK_GATING_CONTROL_TXCLK_ENABLE_MASK (0x00000004) -#define SMU_CLOCK_GATING_CONTROL_REGCLK_ENABLE_SHIFT (3) -#define SMU_CLOCK_GATING_CONTROL_REGCLK_ENABLE_MASK (0x00000008) -#define SMU_CLOCK_GATING_CONTROL_IDLE_TIMEOUT_SHIFT (16) -#define SMU_CLOCK_GATING_CONTROL_IDLE_TIMEOUT_MASK (0x000F0000) -#define SMU_CLOCK_GATING_CONTROL_FORCE_IDLE_SHIFT (31) -#define SMU_CLOCK_GATING_CONTROL_FORCE_IDLE_MASK (0x80000000) -#define SMU_CLOCK_GATING_CONTROL_RESERVED_MASK (0x7FF0FFF0) - -#define SMU_CGUCR_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_CLOCK_GATING_CONTROL_##name, value) - -#define SMU_CGUCR_GEN_BIT(name) \ - SCU_GEN_BIT(SMU_CLOCK_GATING_CONTROL_##name) - -/* -------------------------------------------------------------------------- */ - -#define SMU_CONTROL_STATUS_TASK_CONTEXT_RANGE_ENABLE_SHIFT (0) -#define SMU_CONTROL_STATUS_TASK_CONTEXT_RANGE_ENABLE_MASK (0x00000001) -#define SMU_CONTROL_STATUS_COMPLETION_BYTE_SWAP_ENABLE_SHIFT (1) -#define SMU_CONTROL_STATUS_COMPLETION_BYTE_SWAP_ENABLE_MASK (0x00000002) -#define SMU_CONTROL_STATUS_CONTEXT_RAM_INIT_COMPLETED_SHIFT (16) -#define SMU_CONTROL_STATUS_CONTEXT_RAM_INIT_COMPLETED_MASK (0x00010000) -#define SMU_CONTROL_STATUS_SCHEDULER_RAM_INIT_COMPLETED_SHIFT (17) -#define SMU_CONTROL_STATUS_SCHEDULER_RAM_INIT_COMPLETED_MASK (0x00020000) -#define SMU_CONTROL_STATUS_RESERVED_MASK (0xFFFCFFFC) - -#define SMU_SMUCSR_GEN_BIT(name) \ - SCU_GEN_BIT(SMU_CONTROL_STATUS_ ## name) - -#define SMU_SMUCSR_SCHEDULER_RAM_INIT_COMPLETED \ - (SMU_SMUCSR_GEN_BIT(SCHEDULER_RAM_INIT_COMPLETED)) - -#define SMU_SMUCSR_CONTEXT_RAM_INIT_COMPLETED \ - (SMU_SMUCSR_GEN_BIT(CONTEXT_RAM_INIT_COMPLETED)) - -#define SCU_RAM_INIT_COMPLETED \ - (\ - SMU_SMUCSR_CONTEXT_RAM_INIT_COMPLETED \ - | SMU_SMUCSR_SCHEDULER_RAM_INIT_COMPLETED \ - ) - -/* -------------------------------------------------------------------------- */ - -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE0_SHIFT (0) -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE0_MASK (0x00000001) -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE1_SHIFT (1) -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE1_MASK (0x00000002) -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE2_SHIFT (2) -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE2_MASK (0x00000004) -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE3_SHIFT (3) -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_PE3_MASK (0x00000008) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE0_SHIFT (8) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE0_MASK (0x00000100) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE1_SHIFT (9) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE1_MASK (0x00000200) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE2_SHIFT (10) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE2_MASK (0x00000400) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE3_SHIFT (11) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_PE3_MASK (0x00000800) - -#define SMU_RESET_PROTOCOL_ENGINE(peg, pe) \ - ((1 << (pe)) << ((peg) * 8)) - -#define SMU_RESET_PEG_PROTOCOL_ENGINES(peg) \ - (\ - SMU_RESET_PROTOCOL_ENGINE(peg, 0) \ - | SMU_RESET_PROTOCOL_ENGINE(peg, 1) \ - | SMU_RESET_PROTOCOL_ENGINE(peg, 2) \ - | SMU_RESET_PROTOCOL_ENGINE(peg, 3) \ - ) - -#define SMU_RESET_ALL_PROTOCOL_ENGINES() \ - (\ - SMU_RESET_PEG_PROTOCOL_ENGINES(0) \ - | SMU_RESET_PEG_PROTOCOL_ENGINES(1) \ - ) - -#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP0_SHIFT (16) -#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP0_MASK (0x00010000) -#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP2_SHIFT (17) -#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG0_LP2_MASK (0x00020000) -#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP0_SHIFT (18) -#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP0_MASK (0x00040000) -#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP2_SHIFT (19) -#define SMU_SOFTRESET_CONTROL_RESET_WIDE_PORT_PEG1_LP2_MASK (0x00080000) - -#define SMU_RESET_WIDE_PORT_QUEUE(peg, wide_port) \ - ((1 << ((wide_port) / 2)) << ((peg) * 2) << 16) - -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_SHIFT (20) -#define SMU_SOFTRESET_CONTROL_RESET_PEG0_MASK (0x00100000) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_SHIFT (21) -#define SMU_SOFTRESET_CONTROL_RESET_PEG1_MASK (0x00200000) -#define SMU_SOFTRESET_CONTROL_RESET_SCU_SHIFT (22) -#define SMU_SOFTRESET_CONTROL_RESET_SCU_MASK (0x00400000) - -/* - * It seems to make sense that if you are going to reset the protocol - * engine group that you would also reset all of the protocol engines */ -#define SMU_RESET_PROTOCOL_ENGINE_GROUP(peg) \ - (\ - (1 << ((peg) + 20)) \ - | SMU_RESET_WIDE_PORT_QUEUE(peg, 0) \ - | SMU_RESET_WIDE_PORT_QUEUE(peg, 1) \ - | SMU_RESET_PEG_PROTOCOL_ENGINES(peg) \ - ) - -#define SMU_RESET_ALL_PROTOCOL_ENGINE_GROUPS() \ - (\ - SMU_RESET_PROTOCOL_ENGINE_GROUP(0) \ - | SMU_RESET_PROTOCOL_ENGINE_GROUP(1) \ - ) - -#define SMU_RESET_SCU() (0xFFFFFFFF) - - - -/* ***************************************************************************** */ -#define SMU_TASK_CONTEXT_ASSIGNMENT_STARTING_SHIFT (0) -#define SMU_TASK_CONTEXT_ASSIGNMENT_STARTING_MASK (0x00000FFF) -#define SMU_TASK_CONTEXT_ASSIGNMENT_ENDING_SHIFT (16) -#define SMU_TASK_CONTEXT_ASSIGNMENT_ENDING_MASK (0x0FFF0000) -#define SMU_TASK_CONTEXT_ASSIGNMENT_RANGE_CHECK_ENABLE_SHIFT (31) -#define SMU_TASK_CONTEXT_ASSIGNMENT_RANGE_CHECK_ENABLE_MASK (0x80000000) -#define SMU_TASK_CONTEXT_ASSIGNMENT_RESERVED_MASK (0x7000F000) - -#define SMU_TCA_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SMU_TASK_CONTEXT_ASSIGNMENT_ ## name, value) - -#define SMU_TCA_GEN_BIT(name) \ - SCU_GEN_BIT(SMU_TASK_CONTEXT_ASSIGNMENT_ ## name) - -/* ***************************************************************************** */ -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_QUEUE_SIZE_SHIFT (0) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_QUEUE_SIZE_MASK (0x00000FFF) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_RESERVED_MASK (0xFFFFF000) - -#define SCU_UFQC_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_CONTROL_ ## name, value) - -#define SCU_UFQC_QUEUE_SIZE_SET(value) \ - SCU_UFQC_GEN_VAL(QUEUE_SIZE, value) - -/* ***************************************************************************** */ -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_POINTER_SHIFT (0) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_POINTER_MASK (0x00000FFF) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_CYCLE_BIT_SHIFT (12) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_CYCLE_BIT_MASK (0x00001000) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_RESERVED_MASK (0xFFFFE000) - -#define SCU_UFQPP_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_ ## name, value) - -#define SCU_UFQPP_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_PUT_ ## name) - -/* - * ***************************************************************************** - * * SDMA Registers - * ***************************************************************************** */ -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_POINTER_SHIFT (0) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_POINTER_MASK (0x00000FFF) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_CYCLE_BIT_SHIFT (12) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_CYCLE_BIT_MASK (12) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ENABLE_BIT_SHIFT (31) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ENABLE_BIT_MASK (0x80000000) -#define SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_RESERVED_MASK (0x7FFFE000) - -#define SCU_UFQGP_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ ## name, value) - -#define SCU_UFQGP_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_SDMA_UNSOLICITED_FRAME_QUEUE_GET_ ## name) - -#define SCU_UFQGP_CYCLE_BIT(value) \ - SCU_UFQGP_GEN_BIT(CYCLE_BIT, value) - -#define SCU_UFQGP_GET_POINTER(value) \ - SCU_UFQGP_GEN_VALUE(POINTER, value) - -#define SCU_UFQGP_ENABLE(value) \ - (SCU_UFQGP_GEN_BIT(ENABLE) | value) - -#define SCU_UFQGP_DISABLE(value) \ - (~SCU_UFQGP_GEN_BIT(ENABLE) & value) - -#define SCU_UFQGP_VALUE(bit, value) \ - (SCU_UFQGP_CYCLE_BIT(bit) | SCU_UFQGP_GET_POINTER(value)) - -/* ***************************************************************************** */ -#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_SHIFT (0) -#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_MASK (0x0000FFFF) -#define SCU_PDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_SHIFT (16) -#define SCU_PDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_MASK (0x00010000) -#define SCU_PDMA_CONFIGURATION_PCI_NO_SNOOP_ENABLE_SHIFT (17) -#define SCU_PDMA_CONFIGURATION_PCI_NO_SNOOP_ENABLE_MASK (0x00020000) -#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_BYTE_SWAP_SHIFT (18) -#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_BYTE_SWAP_MASK (0x00040000) -#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_SGL_FETCH_SHIFT (19) -#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_SGL_FETCH_MASK (0x00080000) -#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_RX_HEADER_RAM_WRITE_SHIFT (20) -#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_RX_HEADER_RAM_WRITE_MASK (0x00100000) -#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_UF_ADDRESS_FETCH_SHIFT (21) -#define SCU_PDMA_CONFIGURATION_BIG_ENDIAN_CONTROL_XPI_UF_ADDRESS_FETCH_MASK (0x00200000) -#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_SELECT_SHIFT (22) -#define SCU_PDMA_CONFIGURATION_ADDRESS_MODIFIER_SELECT_MASK (0x00400000) -#define SCU_PDMA_CONFIGURATION_RESERVED_MASK (0xFF800000) - -#define SCU_PDMACR_GEN_VALUE(name, value) \ - SCU_GEN_VALUE(SCU_PDMA_CONFIGURATION_ ## name, value) - -#define SCU_PDMACR_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_PDMA_CONFIGURATION_ ## name) - -#define SCU_PDMACR_BE_GEN_BIT(name) \ - SCU_PCMACR_GEN_BIT(BIG_ENDIAN_CONTROL_ ## name) - -/* ***************************************************************************** */ -#define SCU_CDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_SHIFT (8) -#define SCU_CDMA_CONFIGURATION_PCI_RELAXED_ORDERING_ENABLE_MASK (0x00000100) - -#define SCU_CDMACR_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_CDMA_CONFIGURATION_ ## name) - -/* - * ***************************************************************************** - * * SCU Link Layer Registers - * ***************************************************************************** */ -#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_TIMEOUT_SHIFT (0) -#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_TIMEOUT_MASK (0x000000FF) -#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_LOCK_TIME_SHIFT (8) -#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_LOCK_TIME_MASK (0x0000FF00) -#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_RATE_CHANGE_DELAY_SHIFT (16) -#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_RATE_CHANGE_DELAY_MASK (0x00FF0000) -#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_DWORD_SYNC_TIMEOUT_SHIFT (24) -#define SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_DWORD_SYNC_TIMEOUT_MASK (0xFF000000) -#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_REQUIRED_MASK (0x00000000) -#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_DEFAULT_MASK (0x7D00676F) -#define SCU_LINK_LAYER_SPEED_NECGOIATION_TIMER_VALUES_RESERVED_MASK (0x00FF0000) - -#define SCU_SAS_SPDTOV_GEN_VALUE(name, value) \ - SCU_GEN_VALUE(SCU_LINK_LAYER_SPEED_NEGOTIATION_TIMER_VALUES_ ## name, value) - - -#define SCU_LINK_STATUS_DWORD_SYNC_AQUIRED_SHIFT (2) -#define SCU_LINK_STATUS_DWORD_SYNC_AQUIRED_MASK (0x00000004) -#define SCU_LINK_STATUS_TRANSMIT_PORT_SELECTION_DONE_SHIFT (4) -#define SCU_LINK_STATUS_TRANSMIT_PORT_SELECTION_DONE_MASK (0x00000010) -#define SCU_LINK_STATUS_RECEIVER_CREDIT_EXHAUSTED_SHIFT (5) -#define SCU_LINK_STATUS_RECEIVER_CREDIT_EXHAUSTED_MASK (0x00000020) -#define SCU_LINK_STATUS_RESERVED_MASK (0xFFFFFFCD) - -#define SCU_SAS_LLSTA_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_LINK_STATUS_ ## name) - - -/* TODO: Where is the SATA_PSELTOV register? */ - -/* - * ***************************************************************************** - * * SCU SAS Maximum Arbitration Wait Time Timeout Register - * ***************************************************************************** */ -#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_VALUE_SHIFT (0) -#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_VALUE_MASK (0x00007FFF) -#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_SCALE_SHIFT (15) -#define SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_SCALE_MASK (0x00008000) - -#define SCU_SAS_MAWTTOV_GEN_VALUE(name, value) \ - SCU_GEN_VALUE(SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_ ## name, value) - -#define SCU_SAS_MAWTTOV_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_SAS_MAX_ARBITRATION_WAIT_TIME_TIMEOUT_ ## name) - - -/* - * TODO: Where is the SAS_LNKTOV regsiter? - * TODO: Where is the SAS_PHYTOV register? */ - -#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_TARGET_SHIFT (1) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_TARGET_MASK (0x00000002) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_TARGET_SHIFT (2) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_TARGET_MASK (0x00000004) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_TARGET_SHIFT (3) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_TARGET_MASK (0x00000008) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_DA_SATA_HOST_SHIFT (8) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_DA_SATA_HOST_MASK (0x00000100) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_INITIATOR_SHIFT (9) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_SMP_INITIATOR_MASK (0x00000200) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_INITIATOR_SHIFT (10) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_STP_INITIATOR_MASK (0x00000400) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_INITIATOR_SHIFT (11) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_SSP_INITIATOR_MASK (0x00000800) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_REASON_CODE_SHIFT (16) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_REASON_CODE_MASK (0x000F0000) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_ADDRESS_FRAME_TYPE_SHIFT (24) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_ADDRESS_FRAME_TYPE_MASK (0x0F000000) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_DEVICE_TYPE_SHIFT (28) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_DEVICE_TYPE_MASK (0x70000000) -#define SCU_SAS_TRANSMIT_IDENTIFICATION_RESERVED_MASK (0x80F0F1F1) - -#define SCU_SAS_TIID_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_SAS_TRANSMIT_IDENTIFICATION_ ## name, value) - -#define SCU_SAS_TIID_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_SAS_TRANSMIT_IDENTIFICATION_ ## name) - -/* SAS Identify Frame PHY Identifier Register */ -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_BREAK_REPLY_CAPABLE_SHIFT (16) -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_BREAK_REPLY_CAPABLE_MASK (0x00010000) -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_REQUESTED_INSIDE_ZPSDS_SHIFT (17) -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_REQUESTED_INSIDE_ZPSDS_MASK (0x00020000) -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_INSIDE_ZPSDS_PERSISTENT_SHIFT (18) -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_INSIDE_ZPSDS_PERSISTENT_MASK (0x00040000) -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ID_SHIFT (24) -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ID_MASK (0xFF000000) -#define SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_RESERVED_MASK (0x00F800FF) - -#define SCU_SAS_TIPID_GEN_VALUE(name, value) \ - SCU_GEN_VALUE(SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ ## name, value) - -#define SCU_SAS_TIPID_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_LINK_LAYER_IDENTIFY_FRAME_PHY_IDENTIFIER_ ## name) - - -#define SCU_SAS_PHY_CONFIGURATION_TX_PARITY_CHECK_SHIFT (4) -#define SCU_SAS_PHY_CONFIGURATION_TX_PARITY_CHECK_MASK (0x00000010) -#define SCU_SAS_PHY_CONFIGURATION_TX_BAD_CRC_SHIFT (6) -#define SCU_SAS_PHY_CONFIGURATION_TX_BAD_CRC_MASK (0x00000040) -#define SCU_SAS_PHY_CONFIGURATION_DISABLE_SCRAMBLER_SHIFT (7) -#define SCU_SAS_PHY_CONFIGURATION_DISABLE_SCRAMBLER_MASK (0x00000080) -#define SCU_SAS_PHY_CONFIGURATION_DISABLE_DESCRAMBLER_SHIFT (8) -#define SCU_SAS_PHY_CONFIGURATION_DISABLE_DESCRAMBLER_MASK (0x00000100) -#define SCU_SAS_PHY_CONFIGURATION_DISABLE_CREDIT_INSERTION_SHIFT (9) -#define SCU_SAS_PHY_CONFIGURATION_DISABLE_CREDIT_INSERTION_MASK (0x00000200) -#define SCU_SAS_PHY_CONFIGURATION_SUSPEND_PROTOCOL_ENGINE_SHIFT (11) -#define SCU_SAS_PHY_CONFIGURATION_SUSPEND_PROTOCOL_ENGINE_MASK (0x00000800) -#define SCU_SAS_PHY_CONFIGURATION_SATA_SPINUP_HOLD_SHIFT (12) -#define SCU_SAS_PHY_CONFIGURATION_SATA_SPINUP_HOLD_MASK (0x00001000) -#define SCU_SAS_PHY_CONFIGURATION_TRANSMIT_PORT_SELECTION_SIGNAL_SHIFT (13) -#define SCU_SAS_PHY_CONFIGURATION_TRANSMIT_PORT_SELECTION_SIGNAL_MASK (0x00002000) -#define SCU_SAS_PHY_CONFIGURATION_HARD_RESET_SHIFT (14) -#define SCU_SAS_PHY_CONFIGURATION_HARD_RESET_MASK (0x00004000) -#define SCU_SAS_PHY_CONFIGURATION_OOB_ENABLE_SHIFT (15) -#define SCU_SAS_PHY_CONFIGURATION_OOB_ENABLE_MASK (0x00008000) -#define SCU_SAS_PHY_CONFIGURATION_ENABLE_FRAME_TX_INSERT_ALIGN_SHIFT (23) -#define SCU_SAS_PHY_CONFIGURATION_ENABLE_FRAME_TX_INSERT_ALIGN_MASK (0x00800000) -#define SCU_SAS_PHY_CONFIGURATION_FORWARD_IDENTIFY_FRAME_SHIFT (27) -#define SCU_SAS_PHY_CONFIGURATION_FORWARD_IDENTIFY_FRAME_MASK (0x08000000) -#define SCU_SAS_PHY_CONFIGURATION_DISABLE_BYTE_TRANSPOSE_STP_FRAME_SHIFT (28) -#define SCU_SAS_PHY_CONFIGURATION_DISABLE_BYTE_TRANSPOSE_STP_FRAME_MASK (0x10000000) -#define SCU_SAS_PHY_CONFIGURATION_OOB_RESET_SHIFT (29) -#define SCU_SAS_PHY_CONFIGURATION_OOB_RESET_MASK (0x20000000) -#define SCU_SAS_PHY_CONFIGURATION_THREE_IAF_ENABLE_SHIFT (30) -#define SCU_SAS_PHY_CONFIGURATION_THREE_IAF_ENABLE_MASK (0x40000000) -#define SCU_SAS_PHY_CONFIGURATION_OOB_ALIGN0_ENABLE_SHIFT (31) -#define SCU_SAS_PHY_CONFIGURATION_OOB_ALIGN0_ENABLE_MASK (0x80000000) -#define SCU_SAS_PHY_CONFIGURATION_REQUIRED_MASK (0x0100000F) -#define SCU_SAS_PHY_CONFIGURATION_DEFAULT_MASK (0x4180100F) -#define SCU_SAS_PHY_CONFIGURATION_RESERVED_MASK (0x00000000) - -#define SCU_SAS_PCFG_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_SAS_PHY_CONFIGURATION_ ## name) - -#define SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_GENERAL_SHIFT (0) -#define SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_GENERAL_MASK (0x000007FF) -#define SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_CONNECTED_SHIFT (16) -#define SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_CONNECTED_MASK (0x00ff0000) - -#define SCU_ALIGN_INSERTION_FREQUENCY_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_LINK_LAYER_ALIGN_INSERTION_FREQUENCY_##name, value) - -#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_COUNT_SHIFT (0) -#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_COUNT_MASK (0x0003FFFF) -#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ENABLE_SHIFT (31) -#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ENABLE_MASK (0x80000000) -#define SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_RESERVED_MASK (0x7FFC0000) - -#define SCU_ENSPINUP_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ ## name, value) - -#define SCU_ENSPINUP_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_LINK_LAYER_ENABLE_SPINUP_CONTROL_ ## name) - - -#define SCU_LINK_LAYER_PHY_CAPABILITIES_TXSSCTYPE_SHIFT (1) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_TXSSCTYPE_MASK (0x00000002) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_RLLRATE_SHIFT (4) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_RLLRATE_MASK (0x000000F0) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO15GBPS_SHIFT (8) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO15GBPS_MASK (0x00000100) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW15GBPS_SHIFT (9) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW15GBPS_MASK (0x00000201) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO30GBPS_SHIFT (10) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO30GBPS_MASK (0x00000401) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW30GBPS_SHIFT (11) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW30GBPS_MASK (0x00000801) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO60GBPS_SHIFT (12) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SWO60GBPS_MASK (0x00001001) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW60GBPS_SHIFT (13) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_SW60GBPS_MASK (0x00002001) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_EVEN_PARITY_SHIFT (31) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_EVEN_PARITY_MASK (0x80000000) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_DEFAULT_MASK (0x00003F01) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_REQUIRED_MASK (0x00000001) -#define SCU_LINK_LAYER_PHY_CAPABILITIES_RESERVED_MASK (0x7FFFC00D) - -#define SCU_SAS_PHYCAP_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_LINK_LAYER_PHY_CAPABILITIES_ ## name, value) - -#define SCU_SAS_PHYCAP_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_LINK_LAYER_PHY_CAPABILITIES_ ## name) - - -#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_VIRTUAL_EXPANDER_PHY_ZONE_GROUP_SHIFT (0) -#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_VIRTUAL_EXPANDER_PHY_ZONE_GROUP_MASK (0x000000FF) -#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_INSIDE_SOURCE_ZONE_GROUP_SHIFT (31) -#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_INSIDE_SOURCE_ZONE_GROUP_MASK (0x80000000) -#define SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_RESERVED_MASK (0x7FFFFF00) - -#define SCU_PSZGCR_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_ ## name, value) - -#define SCU_PSZGCR_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_LINK_LAYER_PHY_SOURCE_ZONE_GROUP_CONTROL_ ## name) - -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_LOCKED_SHIFT (1) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_LOCKED_MASK (0x00000002) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_UPDATING_SHIFT (2) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE0_UPDATING_MASK (0x00000004) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_LOCKED_SHIFT (4) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_LOCKED_MASK (0x00000010) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_UPDATING_SHIFT (5) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZONE1_UPDATING_MASK (0x00000020) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE0_SHIFT (16) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE0_MASK (0x00030000) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE0_SHIFT (19) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE0_MASK (0x00080000) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE1_SHIFT (20) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE1_MASK (0x00300000) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE1_SHIFT (23) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE1_MASK (0x00800000) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE2_SHIFT (24) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE2_MASK (0x03000000) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE2_SHIFT (27) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE2_MASK (0x08000000) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE3_SHIFT (28) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ZPT_ASSOCIATION_PE3_MASK (0x30000000) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE3_SHIFT (31) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_AIP_ENABLE_PE3_MASK (0x80000000) -#define SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_RESERVED_MASK (0x4444FFC9) - -#define SCU_PEG_SCUVZECR_GEN_VAL(name, val) \ - SCU_GEN_VALUE(SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ ## name, val) - -#define SCU_PEG_SCUVZECR_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_PROTOCOL_ENGINE_GROUP_VIRTUAL_ZONING_EXPANDER_CONTROL_ ## name) - - -/* - * ***************************************************************************** - * * Port Task Scheduler registers shift and mask values - * ***************************************************************************** */ -#define SCU_PTSG_CONTROL_IT_NEXUS_TIMEOUT_SHIFT (0) -#define SCU_PTSG_CONTROL_IT_NEXUS_TIMEOUT_MASK (0x0000FFFF) -#define SCU_PTSG_CONTROL_TASK_TIMEOUT_SHIFT (16) -#define SCU_PTSG_CONTROL_TASK_TIMEOUT_MASK (0x00FF0000) -#define SCU_PTSG_CONTROL_PTSG_ENABLE_SHIFT (24) -#define SCU_PTSG_CONTROL_PTSG_ENABLE_MASK (0x01000000) -#define SCU_PTSG_CONTROL_ETM_ENABLE_SHIFT (25) -#define SCU_PTSG_CONTROL_ETM_ENABLE_MASK (0x02000000) -#define SCU_PTSG_CONTROL_DEFAULT_MASK (0x00020002) -#define SCU_PTSG_CONTROL_REQUIRED_MASK (0x00000000) -#define SCU_PTSG_CONTROL_RESERVED_MASK (0xFC000000) - -#define SCU_PTSGCR_GEN_VAL(name, val) \ - SCU_GEN_VALUE(SCU_PTSG_CONTROL_ ## name, val) - -#define SCU_PTSGCR_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_PTSG_CONTROL_ ## name) - - -/* ***************************************************************************** */ -#define SCU_PTSG_REAL_TIME_CLOCK_SHIFT (0) -#define SCU_PTSG_REAL_TIME_CLOCK_MASK (0x0000FFFF) -#define SCU_PTSG_REAL_TIME_CLOCK_RESERVED_MASK (0xFFFF0000) - -#define SCU_RTCR_GEN_VAL(name, val) \ - SCU_GEN_VALUE(SCU_PTSG_ ## name, val) - - -#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_PRESCALER_VALUE_SHIFT (0) -#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_PRESCALER_VALUE_MASK (0x00FFFFFF) -#define SCU_PTSG_REAL_TIME_CLOCK_CONTROL_RESERVED_MASK (0xFF000000) - -#define SCU_RTCCR_GEN_VAL(name, val) \ - SCU_GEN_VALUE(SCU_PTSG_REAL_TIME_CLOCK_CONTROL_ ## name, val) - - -#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_SUSPEND_SHIFT (0) -#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_SUSPEND_MASK (0x00000001) -#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_ENABLE_SHIFT (1) -#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_ENABLE_MASK (0x00000002) -#define SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_RESERVED_MASK (0xFFFFFFFC) - -#define SCU_PTSxCR_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_PTSG_PORT_TASK_SCHEDULER_CONTROL_ ## name) - - -#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_NEXT_RN_VALID_SHIFT (0) -#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_NEXT_RN_VALID_MASK (0x00000001) -#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_ACTIVE_RNSC_LIST_VALID_SHIFT (1) -#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_ACTIVE_RNSC_LIST_VALID_MASK (0x00000002) -#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_PTS_SUSPENDED_SHIFT (2) -#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_PTS_SUSPENDED_MASK (0x00000004) -#define SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_RESERVED_MASK (0xFFFFFFF8) - -#define SCU_PTSxSR_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_PTSG_PORT_TASK_SCHEDULER_STATUS_ ## name) - -/* - * ***************************************************************************** - * * SMU Registers - * ***************************************************************************** */ - -/* - * ---------------------------------------------------------------------------- - * SMU Registers - * These registers are based off of BAR0 - * - * To calculate the offset for other functions use - * BAR0 + FN# * SystemPageSize * 2 - * - * The TCA is only accessable from FN#0 (Physical Function) and each - * is programmed by (BAR0 + SCU_SMU_TCA_OFFSET + (FN# * 0x04)) or - * TCA0 for FN#0 is at BAR0 + 0x0400 - * TCA1 for FN#1 is at BAR0 + 0x0404 - * etc. - * ---------------------------------------------------------------------------- - * Accessable to all FN#s */ -#define SCU_SMU_PCP_OFFSET 0x0000 -#define SCU_SMU_AMR_OFFSET 0x0004 -#define SCU_SMU_ISR_OFFSET 0x0010 -#define SCU_SMU_IMR_OFFSET 0x0014 -#define SCU_SMU_ICC_OFFSET 0x0018 -#define SCU_SMU_HTTLBAR_OFFSET 0x0020 -#define SCU_SMU_HTTUBAR_OFFSET 0x0024 -#define SCU_SMU_TCR_OFFSET 0x0028 -#define SCU_SMU_CQLBAR_OFFSET 0x0030 -#define SCU_SMU_CQUBAR_OFFSET 0x0034 -#define SCU_SMU_CQPR_OFFSET 0x0040 -#define SCU_SMU_CQGR_OFFSET 0x0044 -#define SCU_SMU_CQC_OFFSET 0x0048 -/* Accessable to FN#0 only */ -#define SCU_SMU_RNCLBAR_OFFSET 0x0080 -#define SCU_SMU_RNCUBAR_OFFSET 0x0084 -#define SCU_SMU_DCC_OFFSET 0x0090 -#define SCU_SMU_DFC_OFFSET 0x0094 -#define SCU_SMU_SMUCSR_OFFSET 0x0098 -#define SCU_SMU_SCUSRCR_OFFSET 0x009C -#define SCU_SMU_SMAW_OFFSET 0x00A0 -#define SCU_SMU_SMDW_OFFSET 0x00A4 -/* Accessable to FN#0 only */ -#define SCU_SMU_TCA_OFFSET 0x0400 -/* Accessable to all FN#s */ -#define SCU_SMU_MT_MLAR0_OFFSET 0x2000 -#define SCU_SMU_MT_MUAR0_OFFSET 0x2004 -#define SCU_SMU_MT_MDR0_OFFSET 0x2008 -#define SCU_SMU_MT_VCR0_OFFSET 0x200C -#define SCU_SMU_MT_MLAR1_OFFSET 0x2010 -#define SCU_SMU_MT_MUAR1_OFFSET 0x2014 -#define SCU_SMU_MT_MDR1_OFFSET 0x2018 -#define SCU_SMU_MT_VCR1_OFFSET 0x201C -#define SCU_SMU_MPBA_OFFSET 0x3000 - -/** - * struct smu_registers - These are the SMU registers - * - * - */ -struct smu_registers { -/* 0x0000 PCP */ - u32 post_context_port; -/* 0x0004 AMR */ - u32 address_modifier; - u32 reserved_08; - u32 reserved_0C; -/* 0x0010 ISR */ - u32 interrupt_status; -/* 0x0014 IMR */ - u32 interrupt_mask; -/* 0x0018 ICC */ - u32 interrupt_coalesce_control; - u32 reserved_1C; -/* 0x0020 HTTLBAR */ - u32 host_task_table_lower; -/* 0x0024 HTTUBAR */ - u32 host_task_table_upper; -/* 0x0028 TCR */ - u32 task_context_range; - u32 reserved_2C; -/* 0x0030 CQLBAR */ - u32 completion_queue_lower; -/* 0x0034 CQUBAR */ - u32 completion_queue_upper; - u32 reserved_38; - u32 reserved_3C; -/* 0x0040 CQPR */ - u32 completion_queue_put; -/* 0x0044 CQGR */ - u32 completion_queue_get; -/* 0x0048 CQC */ - u32 completion_queue_control; - u32 reserved_4C; - u32 reserved_5x[4]; - u32 reserved_6x[4]; - u32 reserved_7x[4]; -/* - * Accessable to FN#0 only - * 0x0080 RNCLBAR */ - u32 remote_node_context_lower; -/* 0x0084 RNCUBAR */ - u32 remote_node_context_upper; - u32 reserved_88; - u32 reserved_8C; -/* 0x0090 DCC */ - u32 device_context_capacity; -/* 0x0094 DFC */ - u32 device_function_capacity; -/* 0x0098 SMUCSR */ - u32 control_status; -/* 0x009C SCUSRCR */ - u32 soft_reset_control; -/* 0x00A0 SMAW */ - u32 mmr_address_window; -/* 0x00A4 SMDW */ - u32 mmr_data_window; -/* 0x00A8 CGUCR */ - u32 clock_gating_control; -/* 0x00AC CGUPC */ - u32 clock_gating_performance; -/* A whole bunch of reserved space */ - u32 reserved_Bx[4]; - u32 reserved_Cx[4]; - u32 reserved_Dx[4]; - u32 reserved_Ex[4]; - u32 reserved_Fx[4]; - u32 reserved_1xx[64]; - u32 reserved_2xx[64]; - u32 reserved_3xx[64]; -/* - * Accessable to FN#0 only - * 0x0400 TCA */ - u32 task_context_assignment[256]; -/* MSI-X registers not included */ -}; - -/* - * ***************************************************************************** - * SDMA Registers - * ***************************************************************************** */ -#define SCU_SDMA_BASE 0x6000 -#define SCU_SDMA_PUFATLHAR_OFFSET 0x0000 -#define SCU_SDMA_PUFATUHAR_OFFSET 0x0004 -#define SCU_SDMA_UFLHBAR_OFFSET 0x0008 -#define SCU_SDMA_UFUHBAR_OFFSET 0x000C -#define SCU_SDMA_UFQC_OFFSET 0x0010 -#define SCU_SDMA_UFQPP_OFFSET 0x0014 -#define SCU_SDMA_UFQGP_OFFSET 0x0018 -#define SCU_SDMA_PDMACR_OFFSET 0x001C -#define SCU_SDMA_CDMACR_OFFSET 0x0080 - -/** - * struct scu_sdma_registers - These are the SCU SDMA Registers - * - * - */ -struct scu_sdma_registers { -/* 0x0000 PUFATLHAR */ - u32 uf_address_table_lower; -/* 0x0004 PUFATUHAR */ - u32 uf_address_table_upper; -/* 0x0008 UFLHBAR */ - u32 uf_header_base_address_lower; -/* 0x000C UFUHBAR */ - u32 uf_header_base_address_upper; -/* 0x0010 UFQC */ - u32 unsolicited_frame_queue_control; -/* 0x0014 UFQPP */ - u32 unsolicited_frame_put_pointer; -/* 0x0018 UFQGP */ - u32 unsolicited_frame_get_pointer; -/* 0x001C PDMACR */ - u32 pdma_configuration; -/* Reserved until offset 0x80 */ - u32 reserved_0020_007C[0x18]; -/* 0x0080 CDMACR */ - u32 cdma_configuration; -/* Remainder SDMA register space */ - u32 reserved_0084_0400[0xDF]; - -}; - -/* - * ***************************************************************************** - * * SCU Link Registers - * ***************************************************************************** */ -#define SCU_PEG0_OFFSET 0x0000 -#define SCU_PEG1_OFFSET 0x8000 - -#define SCU_TL0_OFFSET 0x0000 -#define SCU_TL1_OFFSET 0x0400 -#define SCU_TL2_OFFSET 0x0800 -#define SCU_TL3_OFFSET 0x0C00 - -#define SCU_LL_OFFSET 0x0080 -#define SCU_LL0_OFFSET (SCU_TL0_OFFSET + SCU_LL_OFFSET) -#define SCU_LL1_OFFSET (SCU_TL1_OFFSET + SCU_LL_OFFSET) -#define SCU_LL2_OFFSET (SCU_TL2_OFFSET + SCU_LL_OFFSET) -#define SCU_LL3_OFFSET (SCU_TL3_OFFSET + SCU_LL_OFFSET) - -/* Transport Layer Offsets (PEG + TL) */ -#define SCU_TLCR_OFFSET 0x0000 -#define SCU_TLADTR_OFFSET 0x0004 -#define SCU_TLTTMR_OFFSET 0x0008 -#define SCU_TLEECR0_OFFSET 0x000C -#define SCU_STPTLDARNI_OFFSET 0x0010 - - -#define SCU_TLCR_HASH_SAS_CHECKING_ENABLE_SHIFT (0) -#define SCU_TLCR_HASH_SAS_CHECKING_ENABLE_MASK (0x00000001) -#define SCU_TLCR_CLEAR_TCI_NCQ_MAPPING_TABLE_SHIFT (1) -#define SCU_TLCR_CLEAR_TCI_NCQ_MAPPING_TABLE_MASK (0x00000002) -#define SCU_TLCR_STP_WRITE_DATA_PREFETCH_SHIFT (3) -#define SCU_TLCR_STP_WRITE_DATA_PREFETCH_MASK (0x00000008) -#define SCU_TLCR_CMD_NAK_STATUS_CODE_SHIFT (4) -#define SCU_TLCR_CMD_NAK_STATUS_CODE_MASK (0x00000010) -#define SCU_TLCR_RESERVED_MASK (0xFFFFFFEB) - -#define SCU_TLCR_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_TLCR_ ## name) - -/** - * struct scu_transport_layer_registers - These are the SCU Transport Layer - * registers - * - * - */ -struct scu_transport_layer_registers { - /* 0x0000 TLCR */ - u32 control; - /* 0x0004 TLADTR */ - u32 arbitration_delay_timer; - /* 0x0008 TLTTMR */ - u32 timer_test_mode; - /* 0x000C reserved */ - u32 reserved_0C; - /* 0x0010 STPTLDARNI */ - u32 stp_rni; - /* 0x0014 TLFEWPORCTRL */ - u32 tlfe_wpo_read_control; - /* 0x0018 TLFEWPORDATA */ - u32 tlfe_wpo_read_data; - /* 0x001C RXTLSSCSR1 */ - u32 rxtl_single_step_control_status_1; - /* 0x0020 RXTLSSCSR2 */ - u32 rxtl_single_step_control_status_2; - /* 0x0024 AWTRDDCR */ - u32 tlfe_awt_retry_delay_debug_control; - /* Remainder of TL memory space */ - u32 reserved_0028_007F[0x16]; - -}; - -/* Protocol Engine Group Registers */ -#define SCU_SCUVZECRx_OFFSET 0x1080 - -/* Link Layer Offsets (PEG + TL + LL) */ -#define SCU_SAS_SPDTOV_OFFSET 0x0000 -#define SCU_SAS_LLSTA_OFFSET 0x0004 -#define SCU_SATA_PSELTOV_OFFSET 0x0008 -#define SCU_SAS_TIMETOV_OFFSET 0x0010 -#define SCU_SAS_LOSTOT_OFFSET 0x0014 -#define SCU_SAS_LNKTOV_OFFSET 0x0018 -#define SCU_SAS_PHYTOV_OFFSET 0x001C -#define SCU_SAS_AFERCNT_OFFSET 0x0020 -#define SCU_SAS_WERCNT_OFFSET 0x0024 -#define SCU_SAS_TIID_OFFSET 0x0028 -#define SCU_SAS_TIDNH_OFFSET 0x002C -#define SCU_SAS_TIDNL_OFFSET 0x0030 -#define SCU_SAS_TISSAH_OFFSET 0x0034 -#define SCU_SAS_TISSAL_OFFSET 0x0038 -#define SCU_SAS_TIPID_OFFSET 0x003C -#define SCU_SAS_TIRES2_OFFSET 0x0040 -#define SCU_SAS_ADRSTA_OFFSET 0x0044 -#define SCU_SAS_MAWTTOV_OFFSET 0x0048 -#define SCU_SAS_FRPLDFIL_OFFSET 0x0054 -#define SCU_SAS_RFCNT_OFFSET 0x0060 -#define SCU_SAS_TFCNT_OFFSET 0x0064 -#define SCU_SAS_RFDCNT_OFFSET 0x0068 -#define SCU_SAS_TFDCNT_OFFSET 0x006C -#define SCU_SAS_LERCNT_OFFSET 0x0070 -#define SCU_SAS_RDISERRCNT_OFFSET 0x0074 -#define SCU_SAS_CRERCNT_OFFSET 0x0078 -#define SCU_STPCTL_OFFSET 0x007C -#define SCU_SAS_PCFG_OFFSET 0x0080 -#define SCU_SAS_CLKSM_OFFSET 0x0084 -#define SCU_SAS_TXCOMWAKE_OFFSET 0x0088 -#define SCU_SAS_TXCOMINIT_OFFSET 0x008C -#define SCU_SAS_TXCOMSAS_OFFSET 0x0090 -#define SCU_SAS_COMINIT_OFFSET 0x0094 -#define SCU_SAS_COMWAKE_OFFSET 0x0098 -#define SCU_SAS_COMSAS_OFFSET 0x009C -#define SCU_SAS_SFERCNT_OFFSET 0x00A0 -#define SCU_SAS_CDFERCNT_OFFSET 0x00A4 -#define SCU_SAS_DNFERCNT_OFFSET 0x00A8 -#define SCU_SAS_PRSTERCNT_OFFSET 0x00AC -#define SCU_SAS_CNTCTL_OFFSET 0x00B0 -#define SCU_SAS_SSPTOV_OFFSET 0x00B4 -#define SCU_FTCTL_OFFSET 0x00B8 -#define SCU_FRCTL_OFFSET 0x00BC -#define SCU_FTWMRK_OFFSET 0x00C0 -#define SCU_ENSPINUP_OFFSET 0x00C4 -#define SCU_SAS_TRNTOV_OFFSET 0x00C8 -#define SCU_SAS_PHYCAP_OFFSET 0x00CC -#define SCU_SAS_PHYCTL_OFFSET 0x00D0 -#define SCU_SAS_LLCTL_OFFSET 0x00D8 -#define SCU_AFE_XCVRCR_OFFSET 0x00DC -#define SCU_AFE_LUTCR_OFFSET 0x00E0 - -#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_SHIFT (0UL) -#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_ALIGN_DETECTION_MASK (0x000000FFUL) -#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_SHIFT (8UL) -#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_HOT_PLUG_MASK (0x0000FF00UL) -#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_SHIFT (16UL) -#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_COMSAS_DETECTION_MASK (0x00FF0000UL) -#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_SHIFT (24UL) -#define SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_RATE_CHANGE_MASK (0xFF000000UL) - -#define SCU_SAS_PHYTOV_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_SAS_PHY_TIMER_TIMEOUT_VALUES_##name, value) - -#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_SHIFT (0) -#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_MASK (0x00000003) -#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN1 (0) -#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN2 (1) -#define SCU_SAS_LINK_LAYER_CONTROL_MAX_LINK_RATE_GEN3 (2) -#define SCU_SAS_LINK_LAYER_CONTROL_BROADCAST_PRIMITIVE_SHIFT (2) -#define SCU_SAS_LINK_LAYER_CONTROL_BROADCAST_PRIMITIVE_MASK (0x000003FC) -#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_ACTIVE_TASK_DISABLE_SHIFT (16) -#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_ACTIVE_TASK_DISABLE_MASK (0x00010000) -#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_OUTBOUND_TASK_DISABLE_SHIFT (17) -#define SCU_SAS_LINK_LAYER_CONTROL_CLOSE_NO_OUTBOUND_TASK_DISABLE_MASK (0x00020000) -#define SCU_SAS_LINK_LAYER_CONTROL_NO_OUTBOUND_TASK_TIMEOUT_SHIFT (24) -#define SCU_SAS_LINK_LAYER_CONTROL_NO_OUTBOUND_TASK_TIMEOUT_MASK (0xFF000000) -#define SCU_SAS_LINK_LAYER_CONTROL_RESERVED (0x00FCFC00) - -#define SCU_SAS_LLCTL_GEN_VAL(name, value) \ - SCU_GEN_VALUE(SCU_SAS_LINK_LAYER_CONTROL_ ## name, value) - -#define SCU_SAS_LLCTL_GEN_BIT(name) \ - SCU_GEN_BIT(SCU_SAS_LINK_LAYER_CONTROL_ ## name) - - -/* #define SCU_FRXHECR_DCNT_OFFSET 0x00B0 */ -#define SCU_PSZGCR_OFFSET 0x00E4 -#define SCU_SAS_RECPHYCAP_OFFSET 0x00E8 -/* #define SCU_TX_LUTSEL_OFFSET 0x00B8 */ - -#define SCU_SAS_PTxC_OFFSET 0x00D4 /* Same offset as SAS_TCTSTM */ - -/** - * struct scu_link_layer_registers - SCU Link Layer Registers - * - * - */ -struct scu_link_layer_registers { -/* 0x0000 SAS_SPDTOV */ - u32 speed_negotiation_timers; -/* 0x0004 SAS_LLSTA */ - u32 link_layer_status; -/* 0x0008 SATA_PSELTOV */ - u32 port_selector_timeout; - u32 reserved0C; -/* 0x0010 SAS_TIMETOV */ - u32 timeout_unit_value; -/* 0x0014 SAS_RCDTOV */ - u32 rcd_timeout; -/* 0x0018 SAS_LNKTOV */ - u32 link_timer_timeouts; -/* 0x001C SAS_PHYTOV */ - u32 sas_phy_timeouts; -/* 0x0020 SAS_AFERCNT */ - u32 received_address_frame_error_counter; -/* 0x0024 SAS_WERCNT */ - u32 invalid_dword_counter; -/* 0x0028 SAS_TIID */ - u32 transmit_identification; -/* 0x002C SAS_TIDNH */ - u32 sas_device_name_high; -/* 0x0030 SAS_TIDNL */ - u32 sas_device_name_low; -/* 0x0034 SAS_TISSAH */ - u32 source_sas_address_high; -/* 0x0038 SAS_TISSAL */ - u32 source_sas_address_low; -/* 0x003C SAS_TIPID */ - u32 identify_frame_phy_id; -/* 0x0040 SAS_TIRES2 */ - u32 identify_frame_reserved; -/* 0x0044 SAS_ADRSTA */ - u32 received_address_frame; -/* 0x0048 SAS_MAWTTOV */ - u32 maximum_arbitration_wait_timer_timeout; -/* 0x004C SAS_PTxC */ - u32 transmit_primitive; -/* 0x0050 SAS_RORES */ - u32 error_counter_event_notification_control; -/* 0x0054 SAS_FRPLDFIL */ - u32 frxq_payload_fill_threshold; -/* 0x0058 SAS_LLHANG_TOT */ - u32 link_layer_hang_detection_timeout; - u32 reserved_5C; -/* 0x0060 SAS_RFCNT */ - u32 received_frame_count; -/* 0x0064 SAS_TFCNT */ - u32 transmit_frame_count; -/* 0x0068 SAS_RFDCNT */ - u32 received_dword_count; -/* 0x006C SAS_TFDCNT */ - u32 transmit_dword_count; -/* 0x0070 SAS_LERCNT */ - u32 loss_of_sync_error_count; -/* 0x0074 SAS_RDISERRCNT */ - u32 running_disparity_error_count; -/* 0x0078 SAS_CRERCNT */ - u32 received_frame_crc_error_count; -/* 0x007C STPCTL */ - u32 stp_control; -/* 0x0080 SAS_PCFG */ - u32 phy_configuration; -/* 0x0084 SAS_CLKSM */ - u32 clock_skew_management; -/* 0x0088 SAS_TXCOMWAKE */ - u32 transmit_comwake_signal; -/* 0x008C SAS_TXCOMINIT */ - u32 transmit_cominit_signal; -/* 0x0090 SAS_TXCOMSAS */ - u32 transmit_comsas_signal; -/* 0x0094 SAS_COMINIT */ - u32 cominit_control; -/* 0x0098 SAS_COMWAKE */ - u32 comwake_control; -/* 0x009C SAS_COMSAS */ - u32 comsas_control; -/* 0x00A0 SAS_SFERCNT */ - u32 received_short_frame_count; -/* 0x00A4 SAS_CDFERCNT */ - u32 received_frame_without_credit_count; -/* 0x00A8 SAS_DNFERCNT */ - u32 received_frame_after_done_count; -/* 0x00AC SAS_PRSTERCNT */ - u32 phy_reset_problem_count; -/* 0x00B0 SAS_CNTCTL */ - u32 counter_control; -/* 0x00B4 SAS_SSPTOV */ - u32 ssp_timer_timeout_values; -/* 0x00B8 FTCTL */ - u32 ftx_control; -/* 0x00BC FRCTL */ - u32 frx_control; -/* 0x00C0 FTWMRK */ - u32 ftx_watermark; -/* 0x00C4 ENSPINUP */ - u32 notify_enable_spinup_control; -/* 0x00C8 SAS_TRNTOV */ - u32 sas_training_sequence_timer_values; -/* 0x00CC SAS_PHYCAP */ - u32 phy_capabilities; -/* 0x00D0 SAS_PHYCTL */ - u32 phy_control; - u32 reserved_d4; -/* 0x00D8 LLCTL */ - u32 link_layer_control; -/* 0x00DC AFE_XCVRCR */ - u32 afe_xcvr_control; -/* 0x00E0 AFE_LUTCR */ - u32 afe_lookup_table_control; -/* 0x00E4 PSZGCR */ - u32 phy_source_zone_group_control; -/* 0x00E8 SAS_RECPHYCAP */ - u32 receive_phycap; - u32 reserved_ec; -/* 0x00F0 SNAFERXRSTCTL */ - u32 speed_negotiation_afe_rx_reset_control; -/* 0x00F4 SAS_SSIPMCTL */ - u32 power_management_control; -/* 0x00F8 SAS_PSPREQ_PRIM */ - u32 sas_pm_partial_request_primitive; -/* 0x00FC SAS_PSSREQ_PRIM */ - u32 sas_pm_slumber_request_primitive; -/* 0x0100 SAS_PPSACK_PRIM */ - u32 sas_pm_ack_primitive_register; -/* 0x0104 SAS_PSNAK_PRIM */ - u32 sas_pm_nak_primitive_register; -/* 0x0108 SAS_SSIPMTOV */ - u32 sas_primitive_timeout; - u32 reserved_10c; -/* 0x0110 - 0x011C PLAPRDCTRLxREG */ - u32 pla_product_control[4]; -/* 0x0120 PLAPRDSUMREG */ - u32 pla_product_sum; -/* 0x0124 PLACONTROLREG */ - u32 pla_control; -/* Remainder of memory space 896 bytes */ - u32 reserved_0128_037f[0x96]; - -}; - -/* - * 0x00D4 // Same offset as SAS_TCTSTM SAS_PTxC - * u32 primitive_transmit_control; */ - -/* - * ---------------------------------------------------------------------------- - * SGPIO - * ---------------------------------------------------------------------------- */ -#define SCU_SGPIO_OFFSET 0x1400 - -/* #define SCU_SGPIO_OFFSET 0x6000 // later moves to 0x1400 see HSD 652625 */ -#define SCU_SGPIO_SGICR_OFFSET 0x0000 -#define SCU_SGPIO_SGPBR_OFFSET 0x0004 -#define SCU_SGPIO_SGSDLR_OFFSET 0x0008 -#define SCU_SGPIO_SGSDUR_OFFSET 0x000C -#define SCU_SGPIO_SGSIDLR_OFFSET 0x0010 -#define SCU_SGPIO_SGSIDUR_OFFSET 0x0014 -#define SCU_SGPIO_SGVSCR_OFFSET 0x0018 -/* Address from 0x0820 to 0x083C */ -#define SCU_SGPIO_SGODSR_OFFSET 0x0020 - -/** - * struct scu_sgpio_registers - SCU SGPIO Registers - * - * - */ -struct scu_sgpio_registers { -/* 0x0000 SGPIO_SGICR */ - u32 interface_control; -/* 0x0004 SGPIO_SGPBR */ - u32 blink_rate; -/* 0x0008 SGPIO_SGSDLR */ - u32 start_drive_lower; -/* 0x000C SGPIO_SGSDUR */ - u32 start_drive_upper; -/* 0x0010 SGPIO_SGSIDLR */ - u32 serial_input_lower; -/* 0x0014 SGPIO_SGSIDUR */ - u32 serial_input_upper; -/* 0x0018 SGPIO_SGVSCR */ - u32 vendor_specific_code; -/* 0x001C Reserved */ - u32 reserved_001c; -/* 0x0020 SGPIO_SGODSR */ - u32 output_data_select[8]; -/* Remainder of memory space 256 bytes */ - u32 reserved_1444_14ff[0x30]; - -}; - -/* - * ***************************************************************************** - * * Defines for VIIT entry offsets - * * Access additional entries by SCU_VIIT_BASE + index * 0x10 - * ***************************************************************************** */ -#define SCU_VIIT_BASE 0x1c00 - -struct scu_viit_registers { - u32 registers[256]; -}; - -/* - * ***************************************************************************** - * * SCU PORT TASK SCHEDULER REGISTERS - * ***************************************************************************** */ - -#define SCU_PTSG_BASE 0x1000 - -#define SCU_PTSG_PTSGCR_OFFSET 0x0000 -#define SCU_PTSG_RTCR_OFFSET 0x0004 -#define SCU_PTSG_RTCCR_OFFSET 0x0008 -#define SCU_PTSG_PTS0CR_OFFSET 0x0010 -#define SCU_PTSG_PTS0SR_OFFSET 0x0014 -#define SCU_PTSG_PTS1CR_OFFSET 0x0018 -#define SCU_PTSG_PTS1SR_OFFSET 0x001C -#define SCU_PTSG_PTS2CR_OFFSET 0x0020 -#define SCU_PTSG_PTS2SR_OFFSET 0x0024 -#define SCU_PTSG_PTS3CR_OFFSET 0x0028 -#define SCU_PTSG_PTS3SR_OFFSET 0x002C -#define SCU_PTSG_PCSPE0CR_OFFSET 0x0030 -#define SCU_PTSG_PCSPE1CR_OFFSET 0x0034 -#define SCU_PTSG_PCSPE2CR_OFFSET 0x0038 -#define SCU_PTSG_PCSPE3CR_OFFSET 0x003C -#define SCU_PTSG_ETMTSCCR_OFFSET 0x0040 -#define SCU_PTSG_ETMRNSCCR_OFFSET 0x0044 - -/** - * struct scu_port_task_scheduler_registers - These are the control/stats pairs - * for each Port Task Scheduler. - * - * - */ -struct scu_port_task_scheduler_registers { - u32 control; - u32 status; -}; - -/** - * struct scu_port_task_scheduler_group_registers - These are the PORT Task - * Scheduler registers - * - * - */ -struct scu_port_task_scheduler_group_registers { -/* 0x0000 PTSGCR */ - u32 control; -/* 0x0004 RTCR */ - u32 real_time_clock; -/* 0x0008 RTCCR */ - u32 real_time_clock_control; -/* 0x000C */ - u32 reserved_0C; -/* - * 0x0010 PTS0CR - * 0x0014 PTS0SR - * 0x0018 PTS1CR - * 0x001C PTS1SR - * 0x0020 PTS2CR - * 0x0024 PTS2SR - * 0x0028 PTS3CR - * 0x002C PTS3SR */ - struct scu_port_task_scheduler_registers port[4]; -/* - * 0x0030 PCSPE0CR - * 0x0034 PCSPE1CR - * 0x0038 PCSPE2CR - * 0x003C PCSPE3CR */ - u32 protocol_engine[4]; -/* 0x0040 ETMTSCCR */ - u32 tc_scanning_interval_control; -/* 0x0044 ETMRNSCCR */ - u32 rnc_scanning_interval_control; -/* Remainder of memory space 128 bytes */ - u32 reserved_1048_107f[0x0E]; - -}; - -#define SCU_PTSG_SCUVZECR_OFFSET 0x003C - -/* - * ***************************************************************************** - * * AFE REGISTERS - * ***************************************************************************** */ -#define SCU_AFE_MMR_BASE 0xE000 - -/* - * AFE 0 is at offset 0x0800 - * AFE 1 is at offset 0x0900 - * AFE 2 is at offset 0x0a00 - * AFE 3 is at offset 0x0b00 */ -struct scu_afe_transceiver { - /* 0x0000 AFE_XCVR_CTRL0 */ - u32 afe_xcvr_control0; - /* 0x0004 AFE_XCVR_CTRL1 */ - u32 afe_xcvr_control1; - /* 0x0008 */ - u32 reserved_0008; - /* 0x000c afe_dfx_rx_control0 */ - u32 afe_dfx_rx_control0; - /* 0x0010 AFE_DFX_RX_CTRL1 */ - u32 afe_dfx_rx_control1; - /* 0x0014 */ - u32 reserved_0014; - /* 0x0018 AFE_DFX_RX_STS0 */ - u32 afe_dfx_rx_status0; - /* 0x001c AFE_DFX_RX_STS1 */ - u32 afe_dfx_rx_status1; - /* 0x0020 */ - u32 reserved_0020; - /* 0x0024 AFE_TX_CTRL */ - u32 afe_tx_control; - /* 0x0028 AFE_TX_AMP_CTRL0 */ - u32 afe_tx_amp_control0; - /* 0x002c AFE_TX_AMP_CTRL1 */ - u32 afe_tx_amp_control1; - /* 0x0030 AFE_TX_AMP_CTRL2 */ - u32 afe_tx_amp_control2; - /* 0x0034 AFE_TX_AMP_CTRL3 */ - u32 afe_tx_amp_control3; - /* 0x0038 afe_tx_ssc_control */ - u32 afe_tx_ssc_control; - /* 0x003c */ - u32 reserved_003c; - /* 0x0040 AFE_RX_SSC_CTRL0 */ - u32 afe_rx_ssc_control0; - /* 0x0044 AFE_RX_SSC_CTRL1 */ - u32 afe_rx_ssc_control1; - /* 0x0048 AFE_RX_SSC_CTRL2 */ - u32 afe_rx_ssc_control2; - /* 0x004c AFE_RX_EQ_STS0 */ - u32 afe_rx_eq_status0; - /* 0x0050 AFE_RX_EQ_STS1 */ - u32 afe_rx_eq_status1; - /* 0x0054 AFE_RX_CDR_STS */ - u32 afe_rx_cdr_status; - /* 0x0058 */ - u32 reserved_0058; - /* 0x005c AFE_CHAN_CTRL */ - u32 afe_channel_control; - /* 0x0060-0x006c */ - u32 reserved_0060_006c[0x04]; - /* 0x0070 AFE_XCVR_EC_STS0 */ - u32 afe_xcvr_error_capture_status0; - /* 0x0074 AFE_XCVR_EC_STS1 */ - u32 afe_xcvr_error_capture_status1; - /* 0x0078 AFE_XCVR_EC_STS2 */ - u32 afe_xcvr_error_capture_status2; - /* 0x007c afe_xcvr_ec_status3 */ - u32 afe_xcvr_error_capture_status3; - /* 0x0080 AFE_XCVR_EC_STS4 */ - u32 afe_xcvr_error_capture_status4; - /* 0x0084 AFE_XCVR_EC_STS5 */ - u32 afe_xcvr_error_capture_status5; - /* 0x0088-0x00fc */ - u32 reserved_008c_00fc[0x1e]; -}; - -/** - * struct scu_afe_registers - AFE Regsiters - * - * - */ -/* Uaoa AFE registers */ -struct scu_afe_registers { - /* 0Xe000 AFE_BIAS_CTRL */ - u32 afe_bias_control; - u32 reserved_0004; - /* 0x0008 AFE_PLL_CTRL0 */ - u32 afe_pll_control0; - /* 0x000c AFE_PLL_CTRL1 */ - u32 afe_pll_control1; - /* 0x0010 AFE_PLL_CTRL2 */ - u32 afe_pll_control2; - /* 0x0014 AFE_CB_STS */ - u32 afe_common_block_status; - /* 0x0018-0x007c */ - u32 reserved_18_7c[0x1a]; - /* 0x0080 AFE_PMSN_MCTRL0 */ - u32 afe_pmsn_master_control0; - /* 0x0084 AFE_PMSN_MCTRL1 */ - u32 afe_pmsn_master_control1; - /* 0x0088 AFE_PMSN_MCTRL2 */ - u32 afe_pmsn_master_control2; - /* 0x008C-0x00fc */ - u32 reserved_008c_00fc[0x1D]; - /* 0x0100 AFE_DFX_MST_CTRL0 */ - u32 afe_dfx_master_control0; - /* 0x0104 AFE_DFX_MST_CTRL1 */ - u32 afe_dfx_master_control1; - /* 0x0108 AFE_DFX_DCL_CTRL */ - u32 afe_dfx_dcl_control; - /* 0x010c AFE_DFX_DMON_CTRL */ - u32 afe_dfx_digital_monitor_control; - /* 0x0110 AFE_DFX_AMONP_CTRL */ - u32 afe_dfx_analog_p_monitor_control; - /* 0x0114 AFE_DFX_AMONN_CTRL */ - u32 afe_dfx_analog_n_monitor_control; - /* 0x0118 AFE_DFX_NTL_STS */ - u32 afe_dfx_ntl_status; - /* 0x011c AFE_DFX_FIFO_STS0 */ - u32 afe_dfx_fifo_status0; - /* 0x0120 AFE_DFX_FIFO_STS1 */ - u32 afe_dfx_fifo_status1; - /* 0x0124 AFE_DFX_MPAT_CTRL */ - u32 afe_dfx_master_pattern_control; - /* 0x0128 AFE_DFX_P0_CTRL */ - u32 afe_dfx_p0_control; - /* 0x012c-0x01a8 AFE_DFX_P0_DRx */ - u32 afe_dfx_p0_data[32]; - /* 0x01ac */ - u32 reserved_01ac; - /* 0x01b0-0x020c AFE_DFX_P0_IRx */ - u32 afe_dfx_p0_instruction[24]; - /* 0x0210 */ - u32 reserved_0210; - /* 0x0214 AFE_DFX_P1_CTRL */ - u32 afe_dfx_p1_control; - /* 0x0218-0x245 AFE_DFX_P1_DRx */ - u32 afe_dfx_p1_data[16]; - /* 0x0258-0x029c */ - u32 reserved_0258_029c[0x12]; - /* 0x02a0-0x02bc AFE_DFX_P1_IRx */ - u32 afe_dfx_p1_instruction[8]; - /* 0x02c0-0x2fc */ - u32 reserved_02c0_02fc[0x10]; - /* 0x0300 AFE_DFX_TX_PMSN_CTRL */ - u32 afe_dfx_tx_pmsn_control; - /* 0x0304 AFE_DFX_RX_PMSN_CTRL */ - u32 afe_dfx_rx_pmsn_control; - u32 reserved_0308; - /* 0x030c AFE_DFX_NOA_CTRL0 */ - u32 afe_dfx_noa_control0; - /* 0x0310 AFE_DFX_NOA_CTRL1 */ - u32 afe_dfx_noa_control1; - /* 0x0314 AFE_DFX_NOA_CTRL2 */ - u32 afe_dfx_noa_control2; - /* 0x0318 AFE_DFX_NOA_CTRL3 */ - u32 afe_dfx_noa_control3; - /* 0x031c AFE_DFX_NOA_CTRL4 */ - u32 afe_dfx_noa_control4; - /* 0x0320 AFE_DFX_NOA_CTRL5 */ - u32 afe_dfx_noa_control5; - /* 0x0324 AFE_DFX_NOA_CTRL6 */ - u32 afe_dfx_noa_control6; - /* 0x0328 AFE_DFX_NOA_CTRL7 */ - u32 afe_dfx_noa_control7; - /* 0x032c-0x07fc */ - u32 reserved_032c_07fc[0x135]; - - /* 0x0800-0x0bfc */ - struct scu_afe_transceiver scu_afe_xcvr[4]; - - /* 0x0c00-0x0ffc */ - u32 reserved_0c00_0ffc[0x0100]; -}; - -struct scu_protocol_engine_group_registers { - u32 table[0xE0]; -}; - - -struct scu_viit_iit { - u32 table[256]; -}; - -/** - * Placeholder for the ZONE Partition Table information ZONING will not be - * included in the 1.1 release. - * - * - */ -struct scu_zone_partition_table { - u32 table[2048]; -}; - -/** - * Placeholder for the CRAM register since I am not sure if we need to - * read/write to these registers as yet. - * - * - */ -struct scu_completion_ram { - u32 ram[128]; -}; - -/** - * Placeholder for the FBRAM registers since I am not sure if we need to - * read/write to these registers as yet. - * - * - */ -struct scu_frame_buffer_ram { - u32 ram[128]; -}; - -#define scu_scratch_ram_SIZE_IN_DWORDS 256 - -/** - * Placeholder for the scratch RAM registers. - * - * - */ -struct scu_scratch_ram { - u32 ram[scu_scratch_ram_SIZE_IN_DWORDS]; -}; - -/** - * Placeholder since I am not yet sure what these registers are here for. - * - * - */ -struct noa_protocol_engine_partition { - u32 reserved[64]; -}; - -/** - * Placeholder since I am not yet sure what these registers are here for. - * - * - */ -struct noa_hub_partition { - u32 reserved[64]; -}; - -/** - * Placeholder since I am not yet sure what these registers are here for. - * - * - */ -struct noa_host_interface_partition { - u32 reserved[64]; -}; - -/** - * struct transport_link_layer_pair - The SCU Hardware pairs up the TL - * registers with the LL registers so we must place them adjcent to make the - * array of registers in the PEG. - * - * - */ -struct transport_link_layer_pair { - struct scu_transport_layer_registers tl; - struct scu_link_layer_registers ll; -}; - -/** - * struct scu_peg_registers - SCU Protocol Engine Memory mapped register space. - * These registers are unique to each protocol engine group. There can be - * at most two PEG for a single SCU part. - * - * - */ -struct scu_peg_registers { - struct transport_link_layer_pair pe[4]; - struct scu_port_task_scheduler_group_registers ptsg; - struct scu_protocol_engine_group_registers peg; - struct scu_sgpio_registers sgpio; - u32 reserved_01500_1BFF[0x1C0]; - struct scu_viit_entry viit[64]; - struct scu_zone_partition_table zpt0; - struct scu_zone_partition_table zpt1; -}; - -/** - * struct scu_registers - SCU regsiters including both PEG registers if we turn - * on that compile option. All of these registers are in the memory mapped - * space returned from BAR1. - * - * - */ -struct scu_registers { - /* 0x0000 - PEG 0 */ - struct scu_peg_registers peg0; - - /* 0x6000 - SDMA and Miscellaneous */ - struct scu_sdma_registers sdma; - struct scu_completion_ram cram; - struct scu_frame_buffer_ram fbram; - u32 reserved_6800_69FF[0x80]; - struct noa_protocol_engine_partition noa_pe; - struct noa_hub_partition noa_hub; - struct noa_host_interface_partition noa_if; - u32 reserved_6d00_7fff[0x4c0]; - - /* 0x8000 - PEG 1 */ - struct scu_peg_registers peg1; - - /* 0xE000 - AFE Registers */ - struct scu_afe_registers afe; - - /* 0xF000 - reserved */ - u32 reserved_f000_211fff[0x80c00]; - - /* 0x212000 - scratch RAM */ - struct scu_scratch_ram scratch_ram; -}; - -#endif /* _SCU_REGISTERS_HEADER_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/remote_device.c b/ANDROID_3.4.5/drivers/scsi/isci/remote_device.c deleted file mode 100644 index 8f501b0a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/remote_device.c +++ /dev/null @@ -1,1436 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include "isci.h" -#include "port.h" -#include "remote_device.h" -#include "request.h" -#include "remote_node_context.h" -#include "scu_event_codes.h" -#include "task.h" - -#undef C -#define C(a) (#a) -const char *dev_state_name(enum sci_remote_device_states state) -{ - static const char * const strings[] = REMOTE_DEV_STATES; - - return strings[state]; -} -#undef C - -/** - * isci_remote_device_not_ready() - This function is called by the ihost when - * the remote device is not ready. We mark the isci device as ready (not - * "ready_for_io") and signal the waiting proccess. - * @isci_host: This parameter specifies the isci host object. - * @isci_device: This parameter specifies the remote device - * - * sci_lock is held on entrance to this function. - */ -static void isci_remote_device_not_ready(struct isci_host *ihost, - struct isci_remote_device *idev, u32 reason) -{ - struct isci_request *ireq; - - dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p\n", __func__, idev); - - switch (reason) { - case SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED: - set_bit(IDEV_GONE, &idev->flags); - break; - case SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED: - set_bit(IDEV_IO_NCQERROR, &idev->flags); - - /* Kill all outstanding requests for the device. */ - list_for_each_entry(ireq, &idev->reqs_in_process, dev_node) { - - dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p request = %p\n", - __func__, idev, ireq); - - sci_controller_terminate_request(ihost, - idev, - ireq); - } - /* Fall through into the default case... */ - default: - clear_bit(IDEV_IO_READY, &idev->flags); - break; - } -} - -/** - * isci_remote_device_ready() - This function is called by the ihost when the - * remote device is ready. We mark the isci device as ready and signal the - * waiting proccess. - * @ihost: our valid isci_host - * @idev: remote device - * - */ -static void isci_remote_device_ready(struct isci_host *ihost, struct isci_remote_device *idev) -{ - dev_dbg(&ihost->pdev->dev, - "%s: idev = %p\n", __func__, idev); - - clear_bit(IDEV_IO_NCQERROR, &idev->flags); - set_bit(IDEV_IO_READY, &idev->flags); - if (test_and_clear_bit(IDEV_START_PENDING, &idev->flags)) - wake_up(&ihost->eventq); -} - -/* called once the remote node context is ready to be freed. - * The remote device can now report that its stop operation is complete. none - */ -static void rnc_destruct_done(void *_dev) -{ - struct isci_remote_device *idev = _dev; - - BUG_ON(idev->started_request_count != 0); - sci_change_state(&idev->sm, SCI_DEV_STOPPED); -} - -static enum sci_status sci_remote_device_terminate_requests(struct isci_remote_device *idev) -{ - struct isci_host *ihost = idev->owning_port->owning_controller; - enum sci_status status = SCI_SUCCESS; - u32 i; - - for (i = 0; i < SCI_MAX_IO_REQUESTS; i++) { - struct isci_request *ireq = ihost->reqs[i]; - enum sci_status s; - - if (!test_bit(IREQ_ACTIVE, &ireq->flags) || - ireq->target_device != idev) - continue; - - s = sci_controller_terminate_request(ihost, idev, ireq); - if (s != SCI_SUCCESS) - status = s; - } - - return status; -} - -enum sci_status sci_remote_device_stop(struct isci_remote_device *idev, - u32 timeout) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - - switch (state) { - case SCI_DEV_INITIAL: - case SCI_DEV_FAILED: - case SCI_DEV_FINAL: - default: - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - case SCI_DEV_STOPPED: - return SCI_SUCCESS; - case SCI_DEV_STARTING: - /* device not started so there had better be no requests */ - BUG_ON(idev->started_request_count != 0); - sci_remote_node_context_destruct(&idev->rnc, - rnc_destruct_done, idev); - /* Transition to the stopping state and wait for the - * remote node to complete being posted and invalidated. - */ - sci_change_state(sm, SCI_DEV_STOPPING); - return SCI_SUCCESS; - case SCI_DEV_READY: - case SCI_STP_DEV_IDLE: - case SCI_STP_DEV_CMD: - case SCI_STP_DEV_NCQ: - case SCI_STP_DEV_NCQ_ERROR: - case SCI_STP_DEV_AWAIT_RESET: - case SCI_SMP_DEV_IDLE: - case SCI_SMP_DEV_CMD: - sci_change_state(sm, SCI_DEV_STOPPING); - if (idev->started_request_count == 0) { - sci_remote_node_context_destruct(&idev->rnc, - rnc_destruct_done, idev); - return SCI_SUCCESS; - } else - return sci_remote_device_terminate_requests(idev); - break; - case SCI_DEV_STOPPING: - /* All requests should have been terminated, but if there is an - * attempt to stop a device already in the stopping state, then - * try again to terminate. - */ - return sci_remote_device_terminate_requests(idev); - case SCI_DEV_RESETTING: - sci_change_state(sm, SCI_DEV_STOPPING); - return SCI_SUCCESS; - } -} - -enum sci_status sci_remote_device_reset(struct isci_remote_device *idev) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - - switch (state) { - case SCI_DEV_INITIAL: - case SCI_DEV_STOPPED: - case SCI_DEV_STARTING: - case SCI_SMP_DEV_IDLE: - case SCI_SMP_DEV_CMD: - case SCI_DEV_STOPPING: - case SCI_DEV_FAILED: - case SCI_DEV_RESETTING: - case SCI_DEV_FINAL: - default: - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - case SCI_DEV_READY: - case SCI_STP_DEV_IDLE: - case SCI_STP_DEV_CMD: - case SCI_STP_DEV_NCQ: - case SCI_STP_DEV_NCQ_ERROR: - case SCI_STP_DEV_AWAIT_RESET: - sci_change_state(sm, SCI_DEV_RESETTING); - return SCI_SUCCESS; - } -} - -enum sci_status sci_remote_device_reset_complete(struct isci_remote_device *idev) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - - if (state != SCI_DEV_RESETTING) { - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - sci_change_state(sm, SCI_DEV_READY); - return SCI_SUCCESS; -} - -enum sci_status sci_remote_device_suspend(struct isci_remote_device *idev, - u32 suspend_type) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - - if (state != SCI_STP_DEV_CMD) { - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - return sci_remote_node_context_suspend(&idev->rnc, - suspend_type, NULL, NULL); -} - -enum sci_status sci_remote_device_frame_handler(struct isci_remote_device *idev, - u32 frame_index) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - struct isci_host *ihost = idev->owning_port->owning_controller; - enum sci_status status; - - switch (state) { - case SCI_DEV_INITIAL: - case SCI_DEV_STOPPED: - case SCI_DEV_STARTING: - case SCI_STP_DEV_IDLE: - case SCI_SMP_DEV_IDLE: - case SCI_DEV_FINAL: - default: - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - /* Return the frame back to the controller */ - sci_controller_release_frame(ihost, frame_index); - return SCI_FAILURE_INVALID_STATE; - case SCI_DEV_READY: - case SCI_STP_DEV_NCQ_ERROR: - case SCI_STP_DEV_AWAIT_RESET: - case SCI_DEV_STOPPING: - case SCI_DEV_FAILED: - case SCI_DEV_RESETTING: { - struct isci_request *ireq; - struct ssp_frame_hdr hdr; - void *frame_header; - ssize_t word_cnt; - - status = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - &frame_header); - if (status != SCI_SUCCESS) - return status; - - word_cnt = sizeof(hdr) / sizeof(u32); - sci_swab32_cpy(&hdr, frame_header, word_cnt); - - ireq = sci_request_by_tag(ihost, be16_to_cpu(hdr.tag)); - if (ireq && ireq->target_device == idev) { - /* The IO request is now in charge of releasing the frame */ - status = sci_io_request_frame_handler(ireq, frame_index); - } else { - /* We could not map this tag to a valid IO - * request Just toss the frame and continue - */ - sci_controller_release_frame(ihost, frame_index); - } - break; - } - case SCI_STP_DEV_NCQ: { - struct dev_to_host_fis *hdr; - - status = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - (void **)&hdr); - if (status != SCI_SUCCESS) - return status; - - if (hdr->fis_type == FIS_SETDEVBITS && - (hdr->status & ATA_ERR)) { - idev->not_ready_reason = SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED; - - /* TODO Check sactive and complete associated IO if any. */ - sci_change_state(sm, SCI_STP_DEV_NCQ_ERROR); - } else if (hdr->fis_type == FIS_REGD2H && - (hdr->status & ATA_ERR)) { - /* - * Some devices return D2H FIS when an NCQ error is detected. - * Treat this like an SDB error FIS ready reason. - */ - idev->not_ready_reason = SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED; - sci_change_state(&idev->sm, SCI_STP_DEV_NCQ_ERROR); - } else - status = SCI_FAILURE; - - sci_controller_release_frame(ihost, frame_index); - break; - } - case SCI_STP_DEV_CMD: - case SCI_SMP_DEV_CMD: - /* The device does not process any UF received from the hardware while - * in this state. All unsolicited frames are forwarded to the io request - * object. - */ - status = sci_io_request_frame_handler(idev->working_request, frame_index); - break; - } - - return status; -} - -static bool is_remote_device_ready(struct isci_remote_device *idev) -{ - - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - - switch (state) { - case SCI_DEV_READY: - case SCI_STP_DEV_IDLE: - case SCI_STP_DEV_CMD: - case SCI_STP_DEV_NCQ: - case SCI_STP_DEV_NCQ_ERROR: - case SCI_STP_DEV_AWAIT_RESET: - case SCI_SMP_DEV_IDLE: - case SCI_SMP_DEV_CMD: - return true; - default: - return false; - } -} - -/* - * called once the remote node context has transisitioned to a ready - * state (after suspending RX and/or TX due to early D2H fis) - */ -static void atapi_remote_device_resume_done(void *_dev) -{ - struct isci_remote_device *idev = _dev; - struct isci_request *ireq = idev->working_request; - - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); -} - -enum sci_status sci_remote_device_event_handler(struct isci_remote_device *idev, - u32 event_code) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - enum sci_status status; - - switch (scu_get_event_type(event_code)) { - case SCU_EVENT_TYPE_RNC_OPS_MISC: - case SCU_EVENT_TYPE_RNC_SUSPEND_TX: - case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: - status = sci_remote_node_context_event_handler(&idev->rnc, event_code); - break; - case SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT: - if (scu_get_event_code(event_code) == SCU_EVENT_IT_NEXUS_TIMEOUT) { - status = SCI_SUCCESS; - - /* Suspend the associated RNC */ - sci_remote_node_context_suspend(&idev->rnc, - SCI_SOFTWARE_SUSPENSION, - NULL, NULL); - - dev_dbg(scirdev_to_dev(idev), - "%s: device: %p event code: %x: %s\n", - __func__, idev, event_code, - is_remote_device_ready(idev) - ? "I_T_Nexus_Timeout event" - : "I_T_Nexus_Timeout event in wrong state"); - - break; - } - /* Else, fall through and treat as unhandled... */ - default: - dev_dbg(scirdev_to_dev(idev), - "%s: device: %p event code: %x: %s\n", - __func__, idev, event_code, - is_remote_device_ready(idev) - ? "unexpected event" - : "unexpected event in wrong state"); - status = SCI_FAILURE_INVALID_STATE; - break; - } - - if (status != SCI_SUCCESS) - return status; - - if (state == SCI_STP_DEV_ATAPI_ERROR) { - /* For ATAPI error state resume the RNC right away. */ - if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX || - scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) { - return sci_remote_node_context_resume(&idev->rnc, - atapi_remote_device_resume_done, - idev); - } - } - - if (state == SCI_STP_DEV_IDLE) { - - /* We pick up suspension events to handle specifically to this - * state. We resume the RNC right away. - */ - if (scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX || - scu_get_event_type(event_code) == SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX) - status = sci_remote_node_context_resume(&idev->rnc, NULL, NULL); - } - - return status; -} - -static void sci_remote_device_start_request(struct isci_remote_device *idev, - struct isci_request *ireq, - enum sci_status status) -{ - struct isci_port *iport = idev->owning_port; - - /* cleanup requests that failed after starting on the port */ - if (status != SCI_SUCCESS) - sci_port_complete_io(iport, idev, ireq); - else { - kref_get(&idev->kref); - idev->started_request_count++; - } -} - -enum sci_status sci_remote_device_start_io(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - struct isci_port *iport = idev->owning_port; - enum sci_status status; - - switch (state) { - case SCI_DEV_INITIAL: - case SCI_DEV_STOPPED: - case SCI_DEV_STARTING: - case SCI_STP_DEV_NCQ_ERROR: - case SCI_DEV_STOPPING: - case SCI_DEV_FAILED: - case SCI_DEV_RESETTING: - case SCI_DEV_FINAL: - default: - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - case SCI_DEV_READY: - /* attempt to start an io request for this device object. The remote - * device object will issue the start request for the io and if - * successful it will start the request for the port object then - * increment its own request count. - */ - status = sci_port_start_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - status = sci_remote_node_context_start_io(&idev->rnc, ireq); - if (status != SCI_SUCCESS) - break; - - status = sci_request_start(ireq); - break; - case SCI_STP_DEV_IDLE: { - /* handle the start io operation for a sata device that is in - * the command idle state. - Evalute the type of IO request to - * be started - If its an NCQ request change to NCQ substate - - * If its any other command change to the CMD substate - * - * If this is a softreset we may want to have a different - * substate. - */ - enum sci_remote_device_states new_state; - struct sas_task *task = isci_request_access_task(ireq); - - status = sci_port_start_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - status = sci_remote_node_context_start_io(&idev->rnc, ireq); - if (status != SCI_SUCCESS) - break; - - status = sci_request_start(ireq); - if (status != SCI_SUCCESS) - break; - - if (task->ata_task.use_ncq) - new_state = SCI_STP_DEV_NCQ; - else { - idev->working_request = ireq; - new_state = SCI_STP_DEV_CMD; - } - sci_change_state(sm, new_state); - break; - } - case SCI_STP_DEV_NCQ: { - struct sas_task *task = isci_request_access_task(ireq); - - if (task->ata_task.use_ncq) { - status = sci_port_start_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - status = sci_remote_node_context_start_io(&idev->rnc, ireq); - if (status != SCI_SUCCESS) - break; - - status = sci_request_start(ireq); - } else - return SCI_FAILURE_INVALID_STATE; - break; - } - case SCI_STP_DEV_AWAIT_RESET: - return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; - case SCI_SMP_DEV_IDLE: - status = sci_port_start_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - status = sci_remote_node_context_start_io(&idev->rnc, ireq); - if (status != SCI_SUCCESS) - break; - - status = sci_request_start(ireq); - if (status != SCI_SUCCESS) - break; - - idev->working_request = ireq; - sci_change_state(&idev->sm, SCI_SMP_DEV_CMD); - break; - case SCI_STP_DEV_CMD: - case SCI_SMP_DEV_CMD: - /* device is already handling a command it can not accept new commands - * until this one is complete. - */ - return SCI_FAILURE_INVALID_STATE; - } - - sci_remote_device_start_request(idev, ireq, status); - return status; -} - -static enum sci_status common_complete_io(struct isci_port *iport, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - enum sci_status status; - - status = sci_request_complete(ireq); - if (status != SCI_SUCCESS) - return status; - - status = sci_port_complete_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - sci_remote_device_decrement_request_count(idev); - return status; -} - -enum sci_status sci_remote_device_complete_io(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - struct isci_port *iport = idev->owning_port; - enum sci_status status; - - switch (state) { - case SCI_DEV_INITIAL: - case SCI_DEV_STOPPED: - case SCI_DEV_STARTING: - case SCI_STP_DEV_IDLE: - case SCI_SMP_DEV_IDLE: - case SCI_DEV_FAILED: - case SCI_DEV_FINAL: - default: - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - case SCI_DEV_READY: - case SCI_STP_DEV_AWAIT_RESET: - case SCI_DEV_RESETTING: - status = common_complete_io(iport, idev, ireq); - break; - case SCI_STP_DEV_CMD: - case SCI_STP_DEV_NCQ: - case SCI_STP_DEV_NCQ_ERROR: - case SCI_STP_DEV_ATAPI_ERROR: - status = common_complete_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - break; - - if (ireq->sci_status == SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { - /* This request causes hardware error, device needs to be Lun Reset. - * So here we force the state machine to IDLE state so the rest IOs - * can reach RNC state handler, these IOs will be completed by RNC with - * status of "DEVICE_RESET_REQUIRED", instead of "INVALID STATE". - */ - sci_change_state(sm, SCI_STP_DEV_AWAIT_RESET); - } else if (idev->started_request_count == 0) - sci_change_state(sm, SCI_STP_DEV_IDLE); - break; - case SCI_SMP_DEV_CMD: - status = common_complete_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - break; - sci_change_state(sm, SCI_SMP_DEV_IDLE); - break; - case SCI_DEV_STOPPING: - status = common_complete_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - break; - - if (idev->started_request_count == 0) - sci_remote_node_context_destruct(&idev->rnc, - rnc_destruct_done, - idev); - break; - } - - if (status != SCI_SUCCESS) - dev_err(scirdev_to_dev(idev), - "%s: Port:0x%p Device:0x%p Request:0x%p Status:0x%x " - "could not complete\n", __func__, iport, - idev, ireq, status); - else - isci_put_device(idev); - - return status; -} - -static void sci_remote_device_continue_request(void *dev) -{ - struct isci_remote_device *idev = dev; - - /* we need to check if this request is still valid to continue. */ - if (idev->working_request) - sci_controller_continue_io(idev->working_request); -} - -enum sci_status sci_remote_device_start_task(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - struct isci_port *iport = idev->owning_port; - enum sci_status status; - - switch (state) { - case SCI_DEV_INITIAL: - case SCI_DEV_STOPPED: - case SCI_DEV_STARTING: - case SCI_SMP_DEV_IDLE: - case SCI_SMP_DEV_CMD: - case SCI_DEV_STOPPING: - case SCI_DEV_FAILED: - case SCI_DEV_RESETTING: - case SCI_DEV_FINAL: - default: - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - case SCI_STP_DEV_IDLE: - case SCI_STP_DEV_CMD: - case SCI_STP_DEV_NCQ: - case SCI_STP_DEV_NCQ_ERROR: - case SCI_STP_DEV_AWAIT_RESET: - status = sci_port_start_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - status = sci_remote_node_context_start_task(&idev->rnc, ireq); - if (status != SCI_SUCCESS) - goto out; - - status = sci_request_start(ireq); - if (status != SCI_SUCCESS) - goto out; - - /* Note: If the remote device state is not IDLE this will - * replace the request that probably resulted in the task - * management request. - */ - idev->working_request = ireq; - sci_change_state(sm, SCI_STP_DEV_CMD); - - /* The remote node context must cleanup the TCi to NCQ mapping - * table. The only way to do this correctly is to either write - * to the TLCR register or to invalidate and repost the RNC. In - * either case the remote node context state machine will take - * the correct action when the remote node context is suspended - * and later resumed. - */ - sci_remote_node_context_suspend(&idev->rnc, - SCI_SOFTWARE_SUSPENSION, NULL, NULL); - sci_remote_node_context_resume(&idev->rnc, - sci_remote_device_continue_request, - idev); - - out: - sci_remote_device_start_request(idev, ireq, status); - /* We need to let the controller start request handler know that - * it can't post TC yet. We will provide a callback function to - * post TC when RNC gets resumed. - */ - return SCI_FAILURE_RESET_DEVICE_PARTIAL_SUCCESS; - case SCI_DEV_READY: - status = sci_port_start_io(iport, idev, ireq); - if (status != SCI_SUCCESS) - return status; - - status = sci_remote_node_context_start_task(&idev->rnc, ireq); - if (status != SCI_SUCCESS) - break; - - status = sci_request_start(ireq); - break; - } - sci_remote_device_start_request(idev, ireq, status); - - return status; -} - -void sci_remote_device_post_request(struct isci_remote_device *idev, u32 request) -{ - struct isci_port *iport = idev->owning_port; - u32 context; - - context = request | - (ISCI_PEG << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (iport->physical_port_index << SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | - idev->rnc.remote_node_index; - - sci_controller_post_request(iport->owning_controller, context); -} - -/* called once the remote node context has transisitioned to a - * ready state. This is the indication that the remote device object can also - * transition to ready. - */ -static void remote_device_resume_done(void *_dev) -{ - struct isci_remote_device *idev = _dev; - - if (is_remote_device_ready(idev)) - return; - - /* go 'ready' if we are not already in a ready state */ - sci_change_state(&idev->sm, SCI_DEV_READY); -} - -static void sci_stp_remote_device_ready_idle_substate_resume_complete_handler(void *_dev) -{ - struct isci_remote_device *idev = _dev; - struct isci_host *ihost = idev->owning_port->owning_controller; - - /* For NCQ operation we do not issue a isci_remote_device_not_ready(). - * As a result, avoid sending the ready notification. - */ - if (idev->sm.previous_state_id != SCI_STP_DEV_NCQ) - isci_remote_device_ready(ihost, idev); -} - -static void sci_remote_device_initial_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - - /* Initial state is a transitional state to the stopped state */ - sci_change_state(&idev->sm, SCI_DEV_STOPPED); -} - -/** - * sci_remote_device_destruct() - free remote node context and destruct - * @remote_device: This parameter specifies the remote device to be destructed. - * - * Remote device objects are a limited resource. As such, they must be - * protected. Thus calls to construct and destruct are mutually exclusive and - * non-reentrant. The return value shall indicate if the device was - * successfully destructed or if some failure occurred. enum sci_status This value - * is returned if the device is successfully destructed. - * SCI_FAILURE_INVALID_REMOTE_DEVICE This value is returned if the supplied - * device isn't valid (e.g. it's already been destoryed, the handle isn't - * valid, etc.). - */ -static enum sci_status sci_remote_device_destruct(struct isci_remote_device *idev) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - struct isci_host *ihost; - - if (state != SCI_DEV_STOPPED) { - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - ihost = idev->owning_port->owning_controller; - sci_controller_free_remote_node_context(ihost, idev, - idev->rnc.remote_node_index); - idev->rnc.remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX; - sci_change_state(sm, SCI_DEV_FINAL); - - return SCI_SUCCESS; -} - -/** - * isci_remote_device_deconstruct() - This function frees an isci_remote_device. - * @ihost: This parameter specifies the isci host object. - * @idev: This parameter specifies the remote device to be freed. - * - */ -static void isci_remote_device_deconstruct(struct isci_host *ihost, struct isci_remote_device *idev) -{ - dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p\n", __func__, idev); - - /* There should not be any outstanding io's. All paths to - * here should go through isci_remote_device_nuke_requests. - * If we hit this condition, we will need a way to complete - * io requests in process */ - BUG_ON(!list_empty(&idev->reqs_in_process)); - - sci_remote_device_destruct(idev); - list_del_init(&idev->node); - isci_put_device(idev); -} - -static void sci_remote_device_stopped_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - struct isci_host *ihost = idev->owning_port->owning_controller; - u32 prev_state; - - /* If we are entering from the stopping state let the SCI User know that - * the stop operation has completed. - */ - prev_state = idev->sm.previous_state_id; - if (prev_state == SCI_DEV_STOPPING) - isci_remote_device_deconstruct(ihost, idev); - - sci_controller_remote_device_stopped(ihost, idev); -} - -static void sci_remote_device_starting_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - struct isci_host *ihost = idev->owning_port->owning_controller; - - isci_remote_device_not_ready(ihost, idev, - SCIC_REMOTE_DEVICE_NOT_READY_START_REQUESTED); -} - -static void sci_remote_device_ready_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - struct isci_host *ihost = idev->owning_port->owning_controller; - struct domain_device *dev = idev->domain_dev; - - if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_SATA)) { - sci_change_state(&idev->sm, SCI_STP_DEV_IDLE); - } else if (dev_is_expander(dev)) { - sci_change_state(&idev->sm, SCI_SMP_DEV_IDLE); - } else - isci_remote_device_ready(ihost, idev); -} - -static void sci_remote_device_ready_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - struct domain_device *dev = idev->domain_dev; - - if (dev->dev_type == SAS_END_DEV) { - struct isci_host *ihost = idev->owning_port->owning_controller; - - isci_remote_device_not_ready(ihost, idev, - SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED); - } -} - -static void sci_remote_device_resetting_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - - sci_remote_node_context_suspend( - &idev->rnc, SCI_SOFTWARE_SUSPENSION, NULL, NULL); -} - -static void sci_remote_device_resetting_state_exit(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - - sci_remote_node_context_resume(&idev->rnc, NULL, NULL); -} - -static void sci_stp_remote_device_ready_idle_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - - idev->working_request = NULL; - if (sci_remote_node_context_is_ready(&idev->rnc)) { - /* - * Since the RNC is ready, it's alright to finish completion - * processing (e.g. signal the remote device is ready). */ - sci_stp_remote_device_ready_idle_substate_resume_complete_handler(idev); - } else { - sci_remote_node_context_resume(&idev->rnc, - sci_stp_remote_device_ready_idle_substate_resume_complete_handler, - idev); - } -} - -static void sci_stp_remote_device_ready_cmd_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - struct isci_host *ihost = idev->owning_port->owning_controller; - - BUG_ON(idev->working_request == NULL); - - isci_remote_device_not_ready(ihost, idev, - SCIC_REMOTE_DEVICE_NOT_READY_SATA_REQUEST_STARTED); -} - -static void sci_stp_remote_device_ready_ncq_error_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - struct isci_host *ihost = idev->owning_port->owning_controller; - - if (idev->not_ready_reason == SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED) - isci_remote_device_not_ready(ihost, idev, - idev->not_ready_reason); -} - -static void sci_smp_remote_device_ready_idle_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - struct isci_host *ihost = idev->owning_port->owning_controller; - - isci_remote_device_ready(ihost, idev); -} - -static void sci_smp_remote_device_ready_cmd_substate_enter(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - struct isci_host *ihost = idev->owning_port->owning_controller; - - BUG_ON(idev->working_request == NULL); - - isci_remote_device_not_ready(ihost, idev, - SCIC_REMOTE_DEVICE_NOT_READY_SMP_REQUEST_STARTED); -} - -static void sci_smp_remote_device_ready_cmd_substate_exit(struct sci_base_state_machine *sm) -{ - struct isci_remote_device *idev = container_of(sm, typeof(*idev), sm); - - idev->working_request = NULL; -} - -static const struct sci_base_state sci_remote_device_state_table[] = { - [SCI_DEV_INITIAL] = { - .enter_state = sci_remote_device_initial_state_enter, - }, - [SCI_DEV_STOPPED] = { - .enter_state = sci_remote_device_stopped_state_enter, - }, - [SCI_DEV_STARTING] = { - .enter_state = sci_remote_device_starting_state_enter, - }, - [SCI_DEV_READY] = { - .enter_state = sci_remote_device_ready_state_enter, - .exit_state = sci_remote_device_ready_state_exit - }, - [SCI_STP_DEV_IDLE] = { - .enter_state = sci_stp_remote_device_ready_idle_substate_enter, - }, - [SCI_STP_DEV_CMD] = { - .enter_state = sci_stp_remote_device_ready_cmd_substate_enter, - }, - [SCI_STP_DEV_NCQ] = { }, - [SCI_STP_DEV_NCQ_ERROR] = { - .enter_state = sci_stp_remote_device_ready_ncq_error_substate_enter, - }, - [SCI_STP_DEV_ATAPI_ERROR] = { }, - [SCI_STP_DEV_AWAIT_RESET] = { }, - [SCI_SMP_DEV_IDLE] = { - .enter_state = sci_smp_remote_device_ready_idle_substate_enter, - }, - [SCI_SMP_DEV_CMD] = { - .enter_state = sci_smp_remote_device_ready_cmd_substate_enter, - .exit_state = sci_smp_remote_device_ready_cmd_substate_exit, - }, - [SCI_DEV_STOPPING] = { }, - [SCI_DEV_FAILED] = { }, - [SCI_DEV_RESETTING] = { - .enter_state = sci_remote_device_resetting_state_enter, - .exit_state = sci_remote_device_resetting_state_exit - }, - [SCI_DEV_FINAL] = { }, -}; - -/** - * sci_remote_device_construct() - common construction - * @sci_port: SAS/SATA port through which this device is accessed. - * @sci_dev: remote device to construct - * - * This routine just performs benign initialization and does not - * allocate the remote_node_context which is left to - * sci_remote_device_[de]a_construct(). sci_remote_device_destruct() - * frees the remote_node_context(s) for the device. - */ -static void sci_remote_device_construct(struct isci_port *iport, - struct isci_remote_device *idev) -{ - idev->owning_port = iport; - idev->started_request_count = 0; - - sci_init_sm(&idev->sm, sci_remote_device_state_table, SCI_DEV_INITIAL); - - sci_remote_node_context_construct(&idev->rnc, - SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX); -} - -/** - * sci_remote_device_da_construct() - construct direct attached device. - * - * The information (e.g. IAF, Signature FIS, etc.) necessary to build - * the device is known to the SCI Core since it is contained in the - * sci_phy object. Remote node context(s) is/are a global resource - * allocated by this routine, freed by sci_remote_device_destruct(). - * - * Returns: - * SCI_FAILURE_DEVICE_EXISTS - device has already been constructed. - * SCI_FAILURE_UNSUPPORTED_PROTOCOL - e.g. sas device attached to - * sata-only controller instance. - * SCI_FAILURE_INSUFFICIENT_RESOURCES - remote node contexts exhausted. - */ -static enum sci_status sci_remote_device_da_construct(struct isci_port *iport, - struct isci_remote_device *idev) -{ - enum sci_status status; - struct sci_port_properties properties; - struct domain_device *dev = idev->domain_dev; - - sci_remote_device_construct(iport, idev); - - /* - * This information is request to determine how many remote node context - * entries will be needed to store the remote node. - */ - idev->is_direct_attached = true; - - sci_port_get_properties(iport, &properties); - /* Get accurate port width from port's phy mask for a DA device. */ - idev->device_port_width = hweight32(properties.phy_mask); - - status = sci_controller_allocate_remote_node_context(iport->owning_controller, - idev, - &idev->rnc.remote_node_index); - - if (status != SCI_SUCCESS) - return status; - - if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || - (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) - /* pass */; - else - return SCI_FAILURE_UNSUPPORTED_PROTOCOL; - - idev->connection_rate = sci_port_get_max_allowed_speed(iport); - - return SCI_SUCCESS; -} - -/** - * sci_remote_device_ea_construct() - construct expander attached device - * - * Remote node context(s) is/are a global resource allocated by this - * routine, freed by sci_remote_device_destruct(). - * - * Returns: - * SCI_FAILURE_DEVICE_EXISTS - device has already been constructed. - * SCI_FAILURE_UNSUPPORTED_PROTOCOL - e.g. sas device attached to - * sata-only controller instance. - * SCI_FAILURE_INSUFFICIENT_RESOURCES - remote node contexts exhausted. - */ -static enum sci_status sci_remote_device_ea_construct(struct isci_port *iport, - struct isci_remote_device *idev) -{ - struct domain_device *dev = idev->domain_dev; - enum sci_status status; - - sci_remote_device_construct(iport, idev); - - status = sci_controller_allocate_remote_node_context(iport->owning_controller, - idev, - &idev->rnc.remote_node_index); - if (status != SCI_SUCCESS) - return status; - - if (dev->dev_type == SAS_END_DEV || dev->dev_type == SATA_DEV || - (dev->tproto & SAS_PROTOCOL_STP) || dev_is_expander(dev)) - /* pass */; - else - return SCI_FAILURE_UNSUPPORTED_PROTOCOL; - - /* - * For SAS-2 the physical link rate is actually a logical link - * rate that incorporates multiplexing. The SCU doesn't - * incorporate multiplexing and for the purposes of the - * connection the logical link rate is that same as the - * physical. Furthermore, the SAS-2 and SAS-1.1 fields overlay - * one another, so this code works for both situations. */ - idev->connection_rate = min_t(u16, sci_port_get_max_allowed_speed(iport), - dev->linkrate); - - /* / @todo Should I assign the port width by reading all of the phys on the port? */ - idev->device_port_width = 1; - - return SCI_SUCCESS; -} - -/** - * sci_remote_device_start() - This method will start the supplied remote - * device. This method enables normal IO requests to flow through to the - * remote device. - * @remote_device: This parameter specifies the device to be started. - * @timeout: This parameter specifies the number of milliseconds in which the - * start operation should complete. - * - * An indication of whether the device was successfully started. SCI_SUCCESS - * This value is returned if the device was successfully started. - * SCI_FAILURE_INVALID_PHY This value is returned if the user attempts to start - * the device when there have been no phys added to it. - */ -static enum sci_status sci_remote_device_start(struct isci_remote_device *idev, - u32 timeout) -{ - struct sci_base_state_machine *sm = &idev->sm; - enum sci_remote_device_states state = sm->current_state_id; - enum sci_status status; - - if (state != SCI_DEV_STOPPED) { - dev_warn(scirdev_to_dev(idev), "%s: in wrong state: %s\n", - __func__, dev_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } - - status = sci_remote_node_context_resume(&idev->rnc, - remote_device_resume_done, - idev); - if (status != SCI_SUCCESS) - return status; - - sci_change_state(sm, SCI_DEV_STARTING); - - return SCI_SUCCESS; -} - -static enum sci_status isci_remote_device_construct(struct isci_port *iport, - struct isci_remote_device *idev) -{ - struct isci_host *ihost = iport->isci_host; - struct domain_device *dev = idev->domain_dev; - enum sci_status status; - - if (dev->parent && dev_is_expander(dev->parent)) - status = sci_remote_device_ea_construct(iport, idev); - else - status = sci_remote_device_da_construct(iport, idev); - - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, "%s: construct failed: %d\n", - __func__, status); - - return status; - } - - /* start the device. */ - status = sci_remote_device_start(idev, ISCI_REMOTE_DEVICE_START_TIMEOUT); - - if (status != SCI_SUCCESS) - dev_warn(&ihost->pdev->dev, "remote device start failed: %d\n", - status); - - return status; -} - -void isci_remote_device_nuke_requests(struct isci_host *ihost, struct isci_remote_device *idev) -{ - DECLARE_COMPLETION_ONSTACK(aborted_task_completion); - - dev_dbg(&ihost->pdev->dev, - "%s: idev = %p\n", __func__, idev); - - /* Cleanup all requests pending for this device. */ - isci_terminate_pending_requests(ihost, idev); - - dev_dbg(&ihost->pdev->dev, - "%s: idev = %p, done\n", __func__, idev); -} - -/** - * This function builds the isci_remote_device when a libsas dev_found message - * is received. - * @isci_host: This parameter specifies the isci host object. - * @port: This parameter specifies the isci_port conected to this device. - * - * pointer to new isci_remote_device. - */ -static struct isci_remote_device * -isci_remote_device_alloc(struct isci_host *ihost, struct isci_port *iport) -{ - struct isci_remote_device *idev; - int i; - - for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { - idev = &ihost->devices[i]; - if (!test_and_set_bit(IDEV_ALLOCATED, &idev->flags)) - break; - } - - if (i >= SCI_MAX_REMOTE_DEVICES) { - dev_warn(&ihost->pdev->dev, "%s: failed\n", __func__); - return NULL; - } - - if (WARN_ONCE(!list_empty(&idev->reqs_in_process), "found requests in process\n")) - return NULL; - - if (WARN_ONCE(!list_empty(&idev->node), "found non-idle remote device\n")) - return NULL; - - return idev; -} - -void isci_remote_device_release(struct kref *kref) -{ - struct isci_remote_device *idev = container_of(kref, typeof(*idev), kref); - struct isci_host *ihost = idev->isci_port->isci_host; - - idev->domain_dev = NULL; - idev->isci_port = NULL; - clear_bit(IDEV_START_PENDING, &idev->flags); - clear_bit(IDEV_STOP_PENDING, &idev->flags); - clear_bit(IDEV_IO_READY, &idev->flags); - clear_bit(IDEV_GONE, &idev->flags); - smp_mb__before_clear_bit(); - clear_bit(IDEV_ALLOCATED, &idev->flags); - wake_up(&ihost->eventq); -} - -/** - * isci_remote_device_stop() - This function is called internally to stop the - * remote device. - * @isci_host: This parameter specifies the isci host object. - * @isci_device: This parameter specifies the remote device. - * - * The status of the ihost request to stop. - */ -enum sci_status isci_remote_device_stop(struct isci_host *ihost, struct isci_remote_device *idev) -{ - enum sci_status status; - unsigned long flags; - - dev_dbg(&ihost->pdev->dev, - "%s: isci_device = %p\n", __func__, idev); - - spin_lock_irqsave(&ihost->scic_lock, flags); - idev->domain_dev->lldd_dev = NULL; /* disable new lookups */ - set_bit(IDEV_GONE, &idev->flags); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - /* Kill all outstanding requests. */ - isci_remote_device_nuke_requests(ihost, idev); - - set_bit(IDEV_STOP_PENDING, &idev->flags); - - spin_lock_irqsave(&ihost->scic_lock, flags); - status = sci_remote_device_stop(idev, 50); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - /* Wait for the stop complete callback. */ - if (WARN_ONCE(status != SCI_SUCCESS, "failed to stop device\n")) - /* nothing to wait for */; - else - wait_for_device_stop(ihost, idev); - - return status; -} - -/** - * isci_remote_device_gone() - This function is called by libsas when a domain - * device is removed. - * @domain_device: This parameter specifies the libsas domain device. - * - */ -void isci_remote_device_gone(struct domain_device *dev) -{ - struct isci_host *ihost = dev_to_ihost(dev); - struct isci_remote_device *idev = dev->lldd_dev; - - dev_dbg(&ihost->pdev->dev, - "%s: domain_device = %p, isci_device = %p, isci_port = %p\n", - __func__, dev, idev, idev->isci_port); - - isci_remote_device_stop(ihost, idev); -} - - -/** - * isci_remote_device_found() - This function is called by libsas when a remote - * device is discovered. A remote device object is created and started. the - * function then sleeps until the sci core device started message is - * received. - * @domain_device: This parameter specifies the libsas domain device. - * - * status, zero indicates success. - */ -int isci_remote_device_found(struct domain_device *dev) -{ - struct isci_host *isci_host = dev_to_ihost(dev); - struct isci_port *isci_port = dev->port->lldd_port; - struct isci_remote_device *isci_device; - enum sci_status status; - - dev_dbg(&isci_host->pdev->dev, - "%s: domain_device = %p\n", __func__, dev); - - if (!isci_port) - return -ENODEV; - - isci_device = isci_remote_device_alloc(isci_host, isci_port); - if (!isci_device) - return -ENODEV; - - kref_init(&isci_device->kref); - INIT_LIST_HEAD(&isci_device->node); - - spin_lock_irq(&isci_host->scic_lock); - isci_device->domain_dev = dev; - isci_device->isci_port = isci_port; - list_add_tail(&isci_device->node, &isci_port->remote_dev_list); - - set_bit(IDEV_START_PENDING, &isci_device->flags); - status = isci_remote_device_construct(isci_port, isci_device); - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_device = %p\n", - __func__, isci_device); - - if (status == SCI_SUCCESS) { - /* device came up, advertise it to the world */ - dev->lldd_dev = isci_device; - } else - isci_put_device(isci_device); - spin_unlock_irq(&isci_host->scic_lock); - - /* wait for the device ready callback. */ - wait_for_device_start(isci_host, isci_device); - - return status == SCI_SUCCESS ? 0 : -ENODEV; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/remote_device.h b/ANDROID_3.4.5/drivers/scsi/isci/remote_device.h deleted file mode 100644 index 58637ee0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/remote_device.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _ISCI_REMOTE_DEVICE_H_ -#define _ISCI_REMOTE_DEVICE_H_ -#include -#include -#include "scu_remote_node_context.h" -#include "remote_node_context.h" -#include "port.h" - -enum sci_remote_device_not_ready_reason_code { - SCIC_REMOTE_DEVICE_NOT_READY_START_REQUESTED, - SCIC_REMOTE_DEVICE_NOT_READY_STOP_REQUESTED, - SCIC_REMOTE_DEVICE_NOT_READY_SATA_REQUEST_STARTED, - SCIC_REMOTE_DEVICE_NOT_READY_SATA_SDB_ERROR_FIS_RECEIVED, - SCIC_REMOTE_DEVICE_NOT_READY_SMP_REQUEST_STARTED, - SCIC_REMOTE_DEVICE_NOT_READY_REASON_CODE_MAX -}; - -/** - * isci_remote_device - isci representation of a sas expander / end point - * @device_port_width: hw setting for number of simultaneous connections - * @connection_rate: per-taskcontext connection rate for this device - * @working_request: SATA requests have no tag we for unaccelerated - * protocols we need a method to associate unsolicited - * frames with a pending request - */ -struct isci_remote_device { - #define IDEV_START_PENDING 0 - #define IDEV_STOP_PENDING 1 - #define IDEV_ALLOCATED 2 - #define IDEV_GONE 3 - #define IDEV_IO_READY 4 - #define IDEV_IO_NCQERROR 5 - unsigned long flags; - struct kref kref; - struct isci_port *isci_port; - struct domain_device *domain_dev; - struct list_head node; - struct list_head reqs_in_process; - struct sci_base_state_machine sm; - u32 device_port_width; - enum sas_linkrate connection_rate; - bool is_direct_attached; - struct isci_port *owning_port; - struct sci_remote_node_context rnc; - /* XXX unify with device reference counting and delete */ - u32 started_request_count; - struct isci_request *working_request; - u32 not_ready_reason; -}; - -#define ISCI_REMOTE_DEVICE_START_TIMEOUT 5000 - -/* device reference routines must be called under sci_lock */ -static inline struct isci_remote_device *isci_lookup_device(struct domain_device *dev) -{ - struct isci_remote_device *idev = dev->lldd_dev; - - if (idev && !test_bit(IDEV_GONE, &idev->flags)) { - kref_get(&idev->kref); - return idev; - } - - return NULL; -} - -void isci_remote_device_release(struct kref *kref); -static inline void isci_put_device(struct isci_remote_device *idev) -{ - if (idev) - kref_put(&idev->kref, isci_remote_device_release); -} - -enum sci_status isci_remote_device_stop(struct isci_host *ihost, - struct isci_remote_device *idev); -void isci_remote_device_nuke_requests(struct isci_host *ihost, - struct isci_remote_device *idev); -void isci_remote_device_gone(struct domain_device *domain_dev); -int isci_remote_device_found(struct domain_device *domain_dev); - -/** - * sci_remote_device_stop() - This method will stop both transmission and - * reception of link activity for the supplied remote device. This method - * disables normal IO requests from flowing through to the remote device. - * @remote_device: This parameter specifies the device to be stopped. - * @timeout: This parameter specifies the number of milliseconds in which the - * stop operation should complete. - * - * An indication of whether the device was successfully stopped. SCI_SUCCESS - * This value is returned if the transmission and reception for the device was - * successfully stopped. - */ -enum sci_status sci_remote_device_stop( - struct isci_remote_device *idev, - u32 timeout); - -/** - * sci_remote_device_reset() - This method will reset the device making it - * ready for operation. This method must be called anytime the device is - * reset either through a SMP phy control or a port hard reset request. - * @remote_device: This parameter specifies the device to be reset. - * - * This method does not actually cause the device hardware to be reset. This - * method resets the software object so that it will be operational after a - * device hardware reset completes. An indication of whether the device reset - * was accepted. SCI_SUCCESS This value is returned if the device reset is - * started. - */ -enum sci_status sci_remote_device_reset( - struct isci_remote_device *idev); - -/** - * sci_remote_device_reset_complete() - This method informs the device object - * that the reset operation is complete and the device can resume operation - * again. - * @remote_device: This parameter specifies the device which is to be informed - * of the reset complete operation. - * - * An indication that the device is resuming operation. SCI_SUCCESS the device - * is resuming operation. - */ -enum sci_status sci_remote_device_reset_complete( - struct isci_remote_device *idev); - -/** - * enum sci_remote_device_states - This enumeration depicts all the states - * for the common remote device state machine. - * @SCI_DEV_INITIAL: Simply the initial state for the base remote device - * state machine. - * - * @SCI_DEV_STOPPED: This state indicates that the remote device has - * successfully been stopped. In this state no new IO operations are - * permitted. This state is entered from the INITIAL state. This state - * is entered from the STOPPING state. - * - * @SCI_DEV_STARTING: This state indicates the the remote device is in - * the process of becoming ready (i.e. starting). In this state no new - * IO operations are permitted. This state is entered from the STOPPED - * state. - * - * @SCI_DEV_READY: This state indicates the remote device is now ready. - * Thus, the user is able to perform IO operations on the remote device. - * This state is entered from the STARTING state. - * - * @SCI_STP_DEV_IDLE: This is the idle substate for the stp remote - * device. When there are no active IO for the device it is is in this - * state. - * - * @SCI_STP_DEV_CMD: This is the command state for for the STP remote - * device. This state is entered when the device is processing a - * non-NCQ command. The device object will fail any new start IO - * requests until this command is complete. - * - * @SCI_STP_DEV_NCQ: This is the NCQ state for the STP remote device. - * This state is entered when the device is processing an NCQ reuqest. - * It will remain in this state so long as there is one or more NCQ - * requests being processed. - * - * @SCI_STP_DEV_NCQ_ERROR: This is the NCQ error state for the STP - * remote device. This state is entered when an SDB error FIS is - * received by the device object while in the NCQ state. The device - * object will only accept a READ LOG command while in this state. - * - * @SCI_STP_DEV_ATAPI_ERROR: This is the ATAPI error state for the STP - * ATAPI remote device. This state is entered when ATAPI device sends - * error status FIS without data while the device object is in CMD - * state. A suspension event is expected in this state. The device - * object will resume right away. - * - * @SCI_STP_DEV_AWAIT_RESET: This is the READY substate indicates the - * device is waiting for the RESET task coming to be recovered from - * certain hardware specific error. - * - * @SCI_SMP_DEV_IDLE: This is the ready operational substate for the - * remote device. This is the normal operational state for a remote - * device. - * - * @SCI_SMP_DEV_CMD: This is the suspended state for the remote device. - * This is the state that the device is placed in when a RNC suspend is - * received by the SCU hardware. - * - * @SCI_DEV_STOPPING: This state indicates that the remote device is in - * the process of stopping. In this state no new IO operations are - * permitted, but existing IO operations are allowed to complete. This - * state is entered from the READY state. This state is entered from - * the FAILED state. - * - * @SCI_DEV_FAILED: This state indicates that the remote device has - * failed. In this state no new IO operations are permitted. This - * state is entered from the INITIALIZING state. This state is entered - * from the READY state. - * - * @SCI_DEV_RESETTING: This state indicates the device is being reset. - * In this state no new IO operations are permitted. This state is - * entered from the READY state. - * - * @SCI_DEV_FINAL: Simply the final state for the base remote device - * state machine. - */ -#define REMOTE_DEV_STATES {\ - C(DEV_INITIAL),\ - C(DEV_STOPPED),\ - C(DEV_STARTING),\ - C(DEV_READY),\ - C(STP_DEV_IDLE),\ - C(STP_DEV_CMD),\ - C(STP_DEV_NCQ),\ - C(STP_DEV_NCQ_ERROR),\ - C(STP_DEV_ATAPI_ERROR),\ - C(STP_DEV_AWAIT_RESET),\ - C(SMP_DEV_IDLE),\ - C(SMP_DEV_CMD),\ - C(DEV_STOPPING),\ - C(DEV_FAILED),\ - C(DEV_RESETTING),\ - C(DEV_FINAL),\ - } -#undef C -#define C(a) SCI_##a -enum sci_remote_device_states REMOTE_DEV_STATES; -#undef C -const char *dev_state_name(enum sci_remote_device_states state); - -static inline struct isci_remote_device *rnc_to_dev(struct sci_remote_node_context *rnc) -{ - struct isci_remote_device *idev; - - idev = container_of(rnc, typeof(*idev), rnc); - - return idev; -} - -static inline bool dev_is_expander(struct domain_device *dev) -{ - return dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV; -} - -static inline void sci_remote_device_decrement_request_count(struct isci_remote_device *idev) -{ - /* XXX delete this voodoo when converting to the top-level device - * reference count - */ - if (WARN_ONCE(idev->started_request_count == 0, - "%s: tried to decrement started_request_count past 0!?", - __func__)) - /* pass */; - else - idev->started_request_count--; -} - -enum sci_status sci_remote_device_frame_handler( - struct isci_remote_device *idev, - u32 frame_index); - -enum sci_status sci_remote_device_event_handler( - struct isci_remote_device *idev, - u32 event_code); - -enum sci_status sci_remote_device_start_io( - struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq); - -enum sci_status sci_remote_device_start_task( - struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq); - -enum sci_status sci_remote_device_complete_io( - struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq); - -enum sci_status sci_remote_device_suspend( - struct isci_remote_device *idev, - u32 suspend_type); - -void sci_remote_device_post_request( - struct isci_remote_device *idev, - u32 request); - -#endif /* !defined(_ISCI_REMOTE_DEVICE_H_) */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/remote_node_context.c b/ANDROID_3.4.5/drivers/scsi/isci/remote_node_context.c deleted file mode 100644 index 3a946348..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/remote_node_context.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "host.h" -#include "isci.h" -#include "remote_device.h" -#include "remote_node_context.h" -#include "scu_event_codes.h" -#include "scu_task_context.h" - -#undef C -#define C(a) (#a) -const char *rnc_state_name(enum scis_sds_remote_node_context_states state) -{ - static const char * const strings[] = RNC_STATES; - - return strings[state]; -} -#undef C - -/** - * - * @sci_rnc: The state of the remote node context object to check. - * - * This method will return true if the remote node context is in a READY state - * otherwise it will return false bool true if the remote node context is in - * the ready state. false if the remote node context is not in the ready state. - */ -bool sci_remote_node_context_is_ready( - struct sci_remote_node_context *sci_rnc) -{ - u32 current_state = sci_rnc->sm.current_state_id; - - if (current_state == SCI_RNC_READY) { - return true; - } - - return false; -} - -static union scu_remote_node_context *sci_rnc_by_id(struct isci_host *ihost, u16 id) -{ - if (id < ihost->remote_node_entries && - ihost->device_table[id]) - return &ihost->remote_node_context_table[id]; - - return NULL; -} - -static void sci_remote_node_context_construct_buffer(struct sci_remote_node_context *sci_rnc) -{ - struct isci_remote_device *idev = rnc_to_dev(sci_rnc); - struct domain_device *dev = idev->domain_dev; - int rni = sci_rnc->remote_node_index; - union scu_remote_node_context *rnc; - struct isci_host *ihost; - __le64 sas_addr; - - ihost = idev->owning_port->owning_controller; - rnc = sci_rnc_by_id(ihost, rni); - - memset(rnc, 0, sizeof(union scu_remote_node_context) - * sci_remote_device_node_count(idev)); - - rnc->ssp.remote_node_index = rni; - rnc->ssp.remote_node_port_width = idev->device_port_width; - rnc->ssp.logical_port_index = idev->owning_port->physical_port_index; - - /* sas address is __be64, context ram format is __le64 */ - sas_addr = cpu_to_le64(SAS_ADDR(dev->sas_addr)); - rnc->ssp.remote_sas_address_hi = upper_32_bits(sas_addr); - rnc->ssp.remote_sas_address_lo = lower_32_bits(sas_addr); - - rnc->ssp.nexus_loss_timer_enable = true; - rnc->ssp.check_bit = false; - rnc->ssp.is_valid = false; - rnc->ssp.is_remote_node_context = true; - rnc->ssp.function_number = 0; - - rnc->ssp.arbitration_wait_time = 0; - - if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { - rnc->ssp.connection_occupancy_timeout = - ihost->user_parameters.stp_max_occupancy_timeout; - rnc->ssp.connection_inactivity_timeout = - ihost->user_parameters.stp_inactivity_timeout; - } else { - rnc->ssp.connection_occupancy_timeout = - ihost->user_parameters.ssp_max_occupancy_timeout; - rnc->ssp.connection_inactivity_timeout = - ihost->user_parameters.ssp_inactivity_timeout; - } - - rnc->ssp.initial_arbitration_wait_time = 0; - - /* Open Address Frame Parameters */ - rnc->ssp.oaf_connection_rate = idev->connection_rate; - rnc->ssp.oaf_features = 0; - rnc->ssp.oaf_source_zone_group = 0; - rnc->ssp.oaf_more_compatibility_features = 0; -} - -/** - * - * @sci_rnc: - * @callback: - * @callback_parameter: - * - * This method will setup the remote node context object so it will transition - * to its ready state. If the remote node context is already setup to - * transition to its final state then this function does nothing. none - */ -static void sci_remote_node_context_setup_to_resume( - struct sci_remote_node_context *sci_rnc, - scics_sds_remote_node_context_callback callback, - void *callback_parameter) -{ - if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) { - sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY; - sci_rnc->user_callback = callback; - sci_rnc->user_cookie = callback_parameter; - } -} - -static void sci_remote_node_context_setup_to_destory( - struct sci_remote_node_context *sci_rnc, - scics_sds_remote_node_context_callback callback, - void *callback_parameter) -{ - sci_rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL; - sci_rnc->user_callback = callback; - sci_rnc->user_cookie = callback_parameter; -} - -/** - * - * - * This method just calls the user callback function and then resets the - * callback. - */ -static void sci_remote_node_context_notify_user( - struct sci_remote_node_context *rnc) -{ - if (rnc->user_callback != NULL) { - (*rnc->user_callback)(rnc->user_cookie); - - rnc->user_callback = NULL; - rnc->user_cookie = NULL; - } -} - -static void sci_remote_node_context_continue_state_transitions(struct sci_remote_node_context *rnc) -{ - if (rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) - sci_remote_node_context_resume(rnc, rnc->user_callback, - rnc->user_cookie); -} - -static void sci_remote_node_context_validate_context_buffer(struct sci_remote_node_context *sci_rnc) -{ - union scu_remote_node_context *rnc_buffer; - struct isci_remote_device *idev = rnc_to_dev(sci_rnc); - struct domain_device *dev = idev->domain_dev; - struct isci_host *ihost = idev->owning_port->owning_controller; - - rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index); - - rnc_buffer->ssp.is_valid = true; - - if (!idev->is_direct_attached && - (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP))) { - sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_96); - } else { - sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_32); - - if (idev->is_direct_attached) - sci_port_setup_transports(idev->owning_port, - sci_rnc->remote_node_index); - } -} - -static void sci_remote_node_context_invalidate_context_buffer(struct sci_remote_node_context *sci_rnc) -{ - union scu_remote_node_context *rnc_buffer; - struct isci_remote_device *idev = rnc_to_dev(sci_rnc); - struct isci_host *ihost = idev->owning_port->owning_controller; - - rnc_buffer = sci_rnc_by_id(ihost, sci_rnc->remote_node_index); - - rnc_buffer->ssp.is_valid = false; - - sci_remote_device_post_request(rnc_to_dev(sci_rnc), - SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE); -} - -static void sci_remote_node_context_initial_state_enter(struct sci_base_state_machine *sm) -{ - struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); - - /* Check to see if we have gotten back to the initial state because - * someone requested to destroy the remote node context object. - */ - if (sm->previous_state_id == SCI_RNC_INVALIDATING) { - rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; - sci_remote_node_context_notify_user(rnc); - } -} - -static void sci_remote_node_context_posting_state_enter(struct sci_base_state_machine *sm) -{ - struct sci_remote_node_context *sci_rnc = container_of(sm, typeof(*sci_rnc), sm); - - sci_remote_node_context_validate_context_buffer(sci_rnc); -} - -static void sci_remote_node_context_invalidating_state_enter(struct sci_base_state_machine *sm) -{ - struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); - - sci_remote_node_context_invalidate_context_buffer(rnc); -} - -static void sci_remote_node_context_resuming_state_enter(struct sci_base_state_machine *sm) -{ - struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); - struct isci_remote_device *idev; - struct domain_device *dev; - - idev = rnc_to_dev(rnc); - dev = idev->domain_dev; - - /* - * For direct attached SATA devices we need to clear the TLCR - * NCQ to TCi tag mapping on the phy and in cases where we - * resume because of a target reset we also need to update - * the STPTLDARNI register with the RNi of the device - */ - if ((dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) && - idev->is_direct_attached) - sci_port_setup_transports(idev->owning_port, - rnc->remote_node_index); - - sci_remote_device_post_request(idev, SCU_CONTEXT_COMMAND_POST_RNC_RESUME); -} - -static void sci_remote_node_context_ready_state_enter(struct sci_base_state_machine *sm) -{ - struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); - - rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; - - if (rnc->user_callback) - sci_remote_node_context_notify_user(rnc); -} - -static void sci_remote_node_context_tx_suspended_state_enter(struct sci_base_state_machine *sm) -{ - struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); - - sci_remote_node_context_continue_state_transitions(rnc); -} - -static void sci_remote_node_context_tx_rx_suspended_state_enter(struct sci_base_state_machine *sm) -{ - struct sci_remote_node_context *rnc = container_of(sm, typeof(*rnc), sm); - - sci_remote_node_context_continue_state_transitions(rnc); -} - -static const struct sci_base_state sci_remote_node_context_state_table[] = { - [SCI_RNC_INITIAL] = { - .enter_state = sci_remote_node_context_initial_state_enter, - }, - [SCI_RNC_POSTING] = { - .enter_state = sci_remote_node_context_posting_state_enter, - }, - [SCI_RNC_INVALIDATING] = { - .enter_state = sci_remote_node_context_invalidating_state_enter, - }, - [SCI_RNC_RESUMING] = { - .enter_state = sci_remote_node_context_resuming_state_enter, - }, - [SCI_RNC_READY] = { - .enter_state = sci_remote_node_context_ready_state_enter, - }, - [SCI_RNC_TX_SUSPENDED] = { - .enter_state = sci_remote_node_context_tx_suspended_state_enter, - }, - [SCI_RNC_TX_RX_SUSPENDED] = { - .enter_state = sci_remote_node_context_tx_rx_suspended_state_enter, - }, - [SCI_RNC_AWAIT_SUSPENSION] = { }, -}; - -void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, - u16 remote_node_index) -{ - memset(rnc, 0, sizeof(struct sci_remote_node_context)); - - rnc->remote_node_index = remote_node_index; - rnc->destination_state = SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED; - - sci_init_sm(&rnc->sm, sci_remote_node_context_state_table, SCI_RNC_INITIAL); -} - -enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_context *sci_rnc, - u32 event_code) -{ - enum scis_sds_remote_node_context_states state; - - state = sci_rnc->sm.current_state_id; - switch (state) { - case SCI_RNC_POSTING: - switch (scu_get_event_code(event_code)) { - case SCU_EVENT_POST_RNC_COMPLETE: - sci_change_state(&sci_rnc->sm, SCI_RNC_READY); - break; - default: - goto out; - } - break; - case SCI_RNC_INVALIDATING: - if (scu_get_event_code(event_code) == SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE) { - if (sci_rnc->destination_state == SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL) - state = SCI_RNC_INITIAL; - else - state = SCI_RNC_POSTING; - sci_change_state(&sci_rnc->sm, state); - } else { - switch (scu_get_event_type(event_code)) { - case SCU_EVENT_TYPE_RNC_SUSPEND_TX: - case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: - /* We really dont care if the hardware is going to suspend - * the device since it's being invalidated anyway */ - dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: SCIC Remote Node Context 0x%p was " - "suspeneded by hardware while being " - "invalidated.\n", __func__, sci_rnc); - break; - default: - goto out; - } - } - break; - case SCI_RNC_RESUMING: - if (scu_get_event_code(event_code) == SCU_EVENT_POST_RCN_RELEASE) { - sci_change_state(&sci_rnc->sm, SCI_RNC_READY); - } else { - switch (scu_get_event_type(event_code)) { - case SCU_EVENT_TYPE_RNC_SUSPEND_TX: - case SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX: - /* We really dont care if the hardware is going to suspend - * the device since it's being resumed anyway */ - dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: SCIC Remote Node Context 0x%p was " - "suspeneded by hardware while being resumed.\n", - __func__, sci_rnc); - break; - default: - goto out; - } - } - break; - case SCI_RNC_READY: - switch (scu_get_event_type(event_code)) { - case SCU_EVENT_TL_RNC_SUSPEND_TX: - sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED); - sci_rnc->suspension_code = scu_get_event_specifier(event_code); - break; - case SCU_EVENT_TL_RNC_SUSPEND_TX_RX: - sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED); - sci_rnc->suspension_code = scu_get_event_specifier(event_code); - break; - default: - goto out; - } - break; - case SCI_RNC_AWAIT_SUSPENSION: - switch (scu_get_event_type(event_code)) { - case SCU_EVENT_TL_RNC_SUSPEND_TX: - sci_change_state(&sci_rnc->sm, SCI_RNC_TX_SUSPENDED); - sci_rnc->suspension_code = scu_get_event_specifier(event_code); - break; - case SCU_EVENT_TL_RNC_SUSPEND_TX_RX: - sci_change_state(&sci_rnc->sm, SCI_RNC_TX_RX_SUSPENDED); - sci_rnc->suspension_code = scu_get_event_specifier(event_code); - break; - default: - goto out; - } - break; - default: - dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); - return SCI_FAILURE_INVALID_STATE; - } - return SCI_SUCCESS; - - out: - dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: code: %#x state: %d\n", __func__, event_code, state); - return SCI_FAILURE; - -} - -enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context *sci_rnc, - scics_sds_remote_node_context_callback cb_fn, - void *cb_p) -{ - enum scis_sds_remote_node_context_states state; - - state = sci_rnc->sm.current_state_id; - switch (state) { - case SCI_RNC_INVALIDATING: - sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p); - return SCI_SUCCESS; - case SCI_RNC_POSTING: - case SCI_RNC_RESUMING: - case SCI_RNC_READY: - case SCI_RNC_TX_SUSPENDED: - case SCI_RNC_TX_RX_SUSPENDED: - case SCI_RNC_AWAIT_SUSPENSION: - sci_remote_node_context_setup_to_destory(sci_rnc, cb_fn, cb_p); - sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); - return SCI_SUCCESS; - case SCI_RNC_INITIAL: - dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); - /* We have decided that the destruct request on the remote node context - * can not fail since it is either in the initial/destroyed state or is - * can be destroyed. - */ - return SCI_SUCCESS; - default: - dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); - return SCI_FAILURE_INVALID_STATE; - } -} - -enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc, - u32 suspend_type, - scics_sds_remote_node_context_callback cb_fn, - void *cb_p) -{ - enum scis_sds_remote_node_context_states state; - - state = sci_rnc->sm.current_state_id; - if (state != SCI_RNC_READY) { - dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); - return SCI_FAILURE_INVALID_STATE; - } - - sci_rnc->user_callback = cb_fn; - sci_rnc->user_cookie = cb_p; - sci_rnc->suspension_code = suspend_type; - - if (suspend_type == SCI_SOFTWARE_SUSPENSION) { - sci_remote_device_post_request(rnc_to_dev(sci_rnc), - SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX); - } - - sci_change_state(&sci_rnc->sm, SCI_RNC_AWAIT_SUSPENSION); - return SCI_SUCCESS; -} - -enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc, - scics_sds_remote_node_context_callback cb_fn, - void *cb_p) -{ - enum scis_sds_remote_node_context_states state; - - state = sci_rnc->sm.current_state_id; - switch (state) { - case SCI_RNC_INITIAL: - if (sci_rnc->remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) - return SCI_FAILURE_INVALID_STATE; - - sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); - sci_remote_node_context_construct_buffer(sci_rnc); - sci_change_state(&sci_rnc->sm, SCI_RNC_POSTING); - return SCI_SUCCESS; - case SCI_RNC_POSTING: - case SCI_RNC_INVALIDATING: - case SCI_RNC_RESUMING: - if (sci_rnc->destination_state != SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY) - return SCI_FAILURE_INVALID_STATE; - - sci_rnc->user_callback = cb_fn; - sci_rnc->user_cookie = cb_p; - return SCI_SUCCESS; - case SCI_RNC_TX_SUSPENDED: { - struct isci_remote_device *idev = rnc_to_dev(sci_rnc); - struct domain_device *dev = idev->domain_dev; - - sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); - - /* TODO: consider adding a resume action of NONE, INVALIDATE, WRITE_TLCR */ - if (dev->dev_type == SAS_END_DEV || dev_is_expander(dev)) - sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); - else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { - if (idev->is_direct_attached) { - /* @todo Fix this since I am being silly in writing to the STPTLDARNI register. */ - sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); - } else { - sci_change_state(&sci_rnc->sm, SCI_RNC_INVALIDATING); - } - } else - return SCI_FAILURE; - return SCI_SUCCESS; - } - case SCI_RNC_TX_RX_SUSPENDED: - sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); - sci_change_state(&sci_rnc->sm, SCI_RNC_RESUMING); - return SCI_FAILURE_INVALID_STATE; - case SCI_RNC_AWAIT_SUSPENSION: - sci_remote_node_context_setup_to_resume(sci_rnc, cb_fn, cb_p); - return SCI_SUCCESS; - default: - dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); - return SCI_FAILURE_INVALID_STATE; - } -} - -enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc, - struct isci_request *ireq) -{ - enum scis_sds_remote_node_context_states state; - - state = sci_rnc->sm.current_state_id; - - switch (state) { - case SCI_RNC_READY: - return SCI_SUCCESS; - case SCI_RNC_TX_SUSPENDED: - case SCI_RNC_TX_RX_SUSPENDED: - case SCI_RNC_AWAIT_SUSPENSION: - dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); - return SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; - default: - break; - } - dev_dbg(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: requested to start IO while still resuming, %d\n", - __func__, state); - return SCI_FAILURE_INVALID_STATE; -} - -enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc, - struct isci_request *ireq) -{ - enum scis_sds_remote_node_context_states state; - - state = sci_rnc->sm.current_state_id; - switch (state) { - case SCI_RNC_RESUMING: - case SCI_RNC_READY: - case SCI_RNC_AWAIT_SUSPENSION: - return SCI_SUCCESS; - case SCI_RNC_TX_SUSPENDED: - case SCI_RNC_TX_RX_SUSPENDED: - sci_remote_node_context_resume(sci_rnc, NULL, NULL); - return SCI_SUCCESS; - default: - dev_warn(scirdev_to_dev(rnc_to_dev(sci_rnc)), - "%s: invalid state %d\n", __func__, state); - return SCI_FAILURE_INVALID_STATE; - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/remote_node_context.h b/ANDROID_3.4.5/drivers/scsi/isci/remote_node_context.h deleted file mode 100644 index a241e0f4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/remote_node_context.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ -#define _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ - -/** - * This file contains the structures, constants, and prototypes associated with - * the remote node context in the silicon. It exists to model and manage - * the remote node context in the silicon. - * - * - */ - -#include "isci.h" - -/** - * - * - * This constant represents an invalid remote device id, it is used to program - * the STPDARNI register so the driver knows when it has received a SIGNATURE - * FIS from the SCU. - */ -#define SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX 0x0FFF - -#define SCU_HARDWARE_SUSPENSION (0) -#define SCI_SOFTWARE_SUSPENSION (1) - -struct isci_request; -struct isci_remote_device; -struct sci_remote_node_context; - -typedef void (*scics_sds_remote_node_context_callback)(void *); - -/** - * enum sci_remote_node_context_states - * @SCI_RNC_INITIAL initial state for a remote node context. On a resume - * request the remote node context will transition to the posting state. - * - * @SCI_RNC_POSTING: transition state that posts the RNi to the hardware. Once - * the RNC is posted the remote node context will be made ready. - * - * @SCI_RNC_INVALIDATING: transition state that will post an RNC invalidate to - * the hardware. Once the invalidate is complete the remote node context will - * transition to the posting state. - * - * @SCI_RNC_RESUMING: transition state that will post an RNC resume to the - * hardare. Once the event notification of resume complete is received the - * remote node context will transition to the ready state. - * - * @SCI_RNC_READY: state that the remote node context must be in to accept io - * request operations. - * - * @SCI_RNC_TX_SUSPENDED: state that the remote node context transitions to when - * it gets a TX suspend notification from the hardware. - * - * @SCI_RNC_TX_RX_SUSPENDED: state that the remote node context transitions to - * when it gets a TX RX suspend notification from the hardware. - * - * @SCI_RNC_AWAIT_SUSPENSION: wait state for the remote node context that waits - * for a suspend notification from the hardware. This state is entered when - * either there is a request to supend the remote node context or when there is - * a TC completion where the remote node will be suspended by the hardware. - */ -#define RNC_STATES {\ - C(RNC_INITIAL),\ - C(RNC_POSTING),\ - C(RNC_INVALIDATING),\ - C(RNC_RESUMING),\ - C(RNC_READY),\ - C(RNC_TX_SUSPENDED),\ - C(RNC_TX_RX_SUSPENDED),\ - C(RNC_AWAIT_SUSPENSION),\ - } -#undef C -#define C(a) SCI_##a -enum scis_sds_remote_node_context_states RNC_STATES; -#undef C -const char *rnc_state_name(enum scis_sds_remote_node_context_states state); - -/** - * - * - * This enumeration is used to define the end destination state for the remote - * node context. - */ -enum sci_remote_node_context_destination_state { - SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_UNSPECIFIED, - SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_READY, - SCIC_SDS_REMOTE_NODE_DESTINATION_STATE_FINAL -}; - -/** - * struct sci_remote_node_context - This structure contains the data - * associated with the remote node context object. The remote node context - * (RNC) object models the the remote device information necessary to manage - * the silicon RNC. - */ -struct sci_remote_node_context { - /** - * This field indicates the remote node index (RNI) associated with - * this RNC. - */ - u16 remote_node_index; - - /** - * This field is the recored suspension code or the reason for the remote node - * context suspension. - */ - u32 suspension_code; - - /** - * This field is true if the remote node context is resuming from its current - * state. This can cause an automatic resume on receiving a suspension - * notification. - */ - enum sci_remote_node_context_destination_state destination_state; - - /** - * This field contains the callback function that the user requested to be - * called when the requested state transition is complete. - */ - scics_sds_remote_node_context_callback user_callback; - - /** - * This field contains the parameter that is called when the user requested - * state transition is completed. - */ - void *user_cookie; - - /** - * This field contains the data for the object's state machine. - */ - struct sci_base_state_machine sm; -}; - -void sci_remote_node_context_construct(struct sci_remote_node_context *rnc, - u16 remote_node_index); - - -bool sci_remote_node_context_is_ready( - struct sci_remote_node_context *sci_rnc); - -enum sci_status sci_remote_node_context_event_handler(struct sci_remote_node_context *sci_rnc, - u32 event_code); -enum sci_status sci_remote_node_context_destruct(struct sci_remote_node_context *sci_rnc, - scics_sds_remote_node_context_callback callback, - void *callback_parameter); -enum sci_status sci_remote_node_context_suspend(struct sci_remote_node_context *sci_rnc, - u32 suspend_type, - scics_sds_remote_node_context_callback cb_fn, - void *cb_p); -enum sci_status sci_remote_node_context_resume(struct sci_remote_node_context *sci_rnc, - scics_sds_remote_node_context_callback cb_fn, - void *cb_p); -enum sci_status sci_remote_node_context_start_task(struct sci_remote_node_context *sci_rnc, - struct isci_request *ireq); -enum sci_status sci_remote_node_context_start_io(struct sci_remote_node_context *sci_rnc, - struct isci_request *ireq); - -#endif /* _SCIC_SDS_REMOTE_NODE_CONTEXT_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/remote_node_table.c b/ANDROID_3.4.5/drivers/scsi/isci/remote_node_table.c deleted file mode 100644 index 301b3141..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/remote_node_table.c +++ /dev/null @@ -1,598 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * This file contains the implementation of the SCIC_SDS_REMOTE_NODE_TABLE - * public, protected, and private methods. - * - * - */ -#include "remote_node_table.h" -#include "remote_node_context.h" - -/** - * - * @remote_node_table: This is the remote node index table from which the - * selection will be made. - * @group_table_index: This is the index to the group table from which to - * search for an available selection. - * - * This routine will find the bit position in absolute bit terms of the next 32 - * + bit position. If there are available bits in the first u32 then it is - * just bit position. u32 This is the absolute bit position for an available - * group. - */ -static u32 sci_remote_node_table_get_group_index( - struct sci_remote_node_table *remote_node_table, - u32 group_table_index) -{ - u32 dword_index; - u32 *group_table; - u32 bit_index; - - group_table = remote_node_table->remote_node_groups[group_table_index]; - - for (dword_index = 0; dword_index < remote_node_table->group_array_size; dword_index++) { - if (group_table[dword_index] != 0) { - for (bit_index = 0; bit_index < 32; bit_index++) { - if ((group_table[dword_index] & (1 << bit_index)) != 0) { - return (dword_index * 32) + bit_index; - } - } - } - } - - return SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX; -} - -/** - * - * @out]: remote_node_table This the remote node table in which to clear the - * selector. - * @set_index: This is the remote node selector in which the change will be - * made. - * @group_index: This is the bit index in the table to be modified. - * - * This method will clear the group index entry in the specified group index - * table. none - */ -static void sci_remote_node_table_clear_group_index( - struct sci_remote_node_table *remote_node_table, - u32 group_table_index, - u32 group_index) -{ - u32 dword_index; - u32 bit_index; - u32 *group_table; - - BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT); - BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32)); - - dword_index = group_index / 32; - bit_index = group_index % 32; - group_table = remote_node_table->remote_node_groups[group_table_index]; - - group_table[dword_index] = group_table[dword_index] & ~(1 << bit_index); -} - -/** - * - * @out]: remote_node_table This the remote node table in which to set the - * selector. - * @group_table_index: This is the remote node selector in which the change - * will be made. - * @group_index: This is the bit position in the table to be modified. - * - * This method will set the group index bit entry in the specified gropu index - * table. none - */ -static void sci_remote_node_table_set_group_index( - struct sci_remote_node_table *remote_node_table, - u32 group_table_index, - u32 group_index) -{ - u32 dword_index; - u32 bit_index; - u32 *group_table; - - BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT); - BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32)); - - dword_index = group_index / 32; - bit_index = group_index % 32; - group_table = remote_node_table->remote_node_groups[group_table_index]; - - group_table[dword_index] = group_table[dword_index] | (1 << bit_index); -} - -/** - * - * @out]: remote_node_table This is the remote node table in which to modify - * the remote node availability. - * @remote_node_index: This is the remote node index that is being returned to - * the table. - * - * This method will set the remote to available in the remote node allocation - * table. none - */ -static void sci_remote_node_table_set_node_index( - struct sci_remote_node_table *remote_node_table, - u32 remote_node_index) -{ - u32 dword_location; - u32 dword_remainder; - u32 slot_normalized; - u32 slot_position; - - BUG_ON( - (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD) - <= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT) - ); - - dword_location = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD; - dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD; - slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32); - slot_position = remote_node_index % SCU_STP_REMOTE_NODE_COUNT; - - remote_node_table->available_remote_nodes[dword_location] |= - 1 << (slot_normalized + slot_position); -} - -/** - * - * @out]: remote_node_table This is the remote node table from which to clear - * the available remote node bit. - * @remote_node_index: This is the remote node index which is to be cleared - * from the table. - * - * This method clears the remote node index from the table of available remote - * nodes. none - */ -static void sci_remote_node_table_clear_node_index( - struct sci_remote_node_table *remote_node_table, - u32 remote_node_index) -{ - u32 dword_location; - u32 dword_remainder; - u32 slot_position; - u32 slot_normalized; - - BUG_ON( - (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD) - <= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT) - ); - - dword_location = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD; - dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD; - slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32); - slot_position = remote_node_index % SCU_STP_REMOTE_NODE_COUNT; - - remote_node_table->available_remote_nodes[dword_location] &= - ~(1 << (slot_normalized + slot_position)); -} - -/** - * - * @out]: remote_node_table The remote node table from which the slot will be - * cleared. - * @group_index: The index for the slot that is to be cleared. - * - * This method clears the entire table slot at the specified slot index. none - */ -static void sci_remote_node_table_clear_group( - struct sci_remote_node_table *remote_node_table, - u32 group_index) -{ - u32 dword_location; - u32 dword_remainder; - u32 dword_value; - - BUG_ON( - (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD) - <= (group_index / SCU_STP_REMOTE_NODE_COUNT) - ); - - dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; - dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; - - dword_value = remote_node_table->available_remote_nodes[dword_location]; - dword_value &= ~(SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4)); - remote_node_table->available_remote_nodes[dword_location] = dword_value; -} - -/** - * - * @remote_node_table: - * - * THis method sets an entire remote node group in the remote node table. - */ -static void sci_remote_node_table_set_group( - struct sci_remote_node_table *remote_node_table, - u32 group_index) -{ - u32 dword_location; - u32 dword_remainder; - u32 dword_value; - - BUG_ON( - (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD) - <= (group_index / SCU_STP_REMOTE_NODE_COUNT) - ); - - dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; - dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; - - dword_value = remote_node_table->available_remote_nodes[dword_location]; - dword_value |= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4)); - remote_node_table->available_remote_nodes[dword_location] = dword_value; -} - -/** - * - * @remote_node_table: This is the remote node table that for which the group - * value is to be returned. - * @group_index: This is the group index to use to find the group value. - * - * This method will return the group value for the specified group index. The - * bit values at the specified remote node group index. - */ -static u8 sci_remote_node_table_get_group_value( - struct sci_remote_node_table *remote_node_table, - u32 group_index) -{ - u32 dword_location; - u32 dword_remainder; - u32 dword_value; - - dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; - dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; - - dword_value = remote_node_table->available_remote_nodes[dword_location]; - dword_value &= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4)); - dword_value = dword_value >> (dword_remainder * 4); - - return (u8)dword_value; -} - -/** - * - * @out]: remote_node_table The remote that which is to be initialized. - * @remote_node_entries: The number of entries to put in the table. - * - * This method will initialize the remote node table for use. none - */ -void sci_remote_node_table_initialize( - struct sci_remote_node_table *remote_node_table, - u32 remote_node_entries) -{ - u32 index; - - /* - * Initialize the raw data we could improve the speed by only initializing - * those entries that we are actually going to be used */ - memset( - remote_node_table->available_remote_nodes, - 0x00, - sizeof(remote_node_table->available_remote_nodes) - ); - - memset( - remote_node_table->remote_node_groups, - 0x00, - sizeof(remote_node_table->remote_node_groups) - ); - - /* Initialize the available remote node sets */ - remote_node_table->available_nodes_array_size = (u16) - (remote_node_entries / SCIC_SDS_REMOTE_NODES_PER_DWORD) - + ((remote_node_entries % SCIC_SDS_REMOTE_NODES_PER_DWORD) != 0); - - - /* Initialize each full DWORD to a FULL SET of remote nodes */ - for (index = 0; index < remote_node_entries; index++) { - sci_remote_node_table_set_node_index(remote_node_table, index); - } - - remote_node_table->group_array_size = (u16) - (remote_node_entries / (SCU_STP_REMOTE_NODE_COUNT * 32)) - + ((remote_node_entries % (SCU_STP_REMOTE_NODE_COUNT * 32)) != 0); - - for (index = 0; index < (remote_node_entries / SCU_STP_REMOTE_NODE_COUNT); index++) { - /* - * These are all guaranteed to be full slot values so fill them in the - * available sets of 3 remote nodes */ - sci_remote_node_table_set_group_index(remote_node_table, 2, index); - } - - /* Now fill in any remainders that we may find */ - if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 2) { - sci_remote_node_table_set_group_index(remote_node_table, 1, index); - } else if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 1) { - sci_remote_node_table_set_group_index(remote_node_table, 0, index); - } -} - -/** - * - * @out]: remote_node_table The remote node table from which to allocate a - * remote node. - * @table_index: The group index that is to be used for the search. - * - * This method will allocate a single RNi from the remote node table. The - * table index will determine from which remote node group table to search. - * This search may fail and another group node table can be specified. The - * function is designed to allow a serach of the available single remote node - * group up to the triple remote node group. If an entry is found in the - * specified table the remote node is removed and the remote node groups are - * updated. The RNi value or an invalid remote node context if an RNi can not - * be found. - */ -static u16 sci_remote_node_table_allocate_single_remote_node( - struct sci_remote_node_table *remote_node_table, - u32 group_table_index) -{ - u8 index; - u8 group_value; - u32 group_index; - u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX; - - group_index = sci_remote_node_table_get_group_index( - remote_node_table, group_table_index); - - /* We could not find an available slot in the table selector 0 */ - if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) { - group_value = sci_remote_node_table_get_group_value( - remote_node_table, group_index); - - for (index = 0; index < SCU_STP_REMOTE_NODE_COUNT; index++) { - if (((1 << index) & group_value) != 0) { - /* We have selected a bit now clear it */ - remote_node_index = (u16)(group_index * SCU_STP_REMOTE_NODE_COUNT - + index); - - sci_remote_node_table_clear_group_index( - remote_node_table, group_table_index, group_index - ); - - sci_remote_node_table_clear_node_index( - remote_node_table, remote_node_index - ); - - if (group_table_index > 0) { - sci_remote_node_table_set_group_index( - remote_node_table, group_table_index - 1, group_index - ); - } - - break; - } - } - } - - return remote_node_index; -} - -/** - * - * @remote_node_table: This is the remote node table from which to allocate the - * remote node entries. - * @group_table_index: THis is the group table index which must equal two (2) - * for this operation. - * - * This method will allocate three consecutive remote node context entries. If - * there are no remaining triple entries the function will return a failure. - * The remote node index that represents three consecutive remote node entries - * or an invalid remote node context if none can be found. - */ -static u16 sci_remote_node_table_allocate_triple_remote_node( - struct sci_remote_node_table *remote_node_table, - u32 group_table_index) -{ - u32 group_index; - u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX; - - group_index = sci_remote_node_table_get_group_index( - remote_node_table, group_table_index); - - if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) { - remote_node_index = (u16)group_index * SCU_STP_REMOTE_NODE_COUNT; - - sci_remote_node_table_clear_group_index( - remote_node_table, group_table_index, group_index - ); - - sci_remote_node_table_clear_group( - remote_node_table, group_index - ); - } - - return remote_node_index; -} - -/** - * - * @remote_node_table: This is the remote node table from which the remote node - * allocation is to take place. - * @remote_node_count: This is ther remote node count which is one of - * SCU_SSP_REMOTE_NODE_COUNT(1) or SCU_STP_REMOTE_NODE_COUNT(3). - * - * This method will allocate a remote node that mataches the remote node count - * specified by the caller. Valid values for remote node count is - * SCU_SSP_REMOTE_NODE_COUNT(1) or SCU_STP_REMOTE_NODE_COUNT(3). u16 This is - * the remote node index that is returned or an invalid remote node context. - */ -u16 sci_remote_node_table_allocate_remote_node( - struct sci_remote_node_table *remote_node_table, - u32 remote_node_count) -{ - u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX; - - if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) { - remote_node_index = - sci_remote_node_table_allocate_single_remote_node( - remote_node_table, 0); - - if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) { - remote_node_index = - sci_remote_node_table_allocate_single_remote_node( - remote_node_table, 1); - } - - if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) { - remote_node_index = - sci_remote_node_table_allocate_single_remote_node( - remote_node_table, 2); - } - } else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) { - remote_node_index = - sci_remote_node_table_allocate_triple_remote_node( - remote_node_table, 2); - } - - return remote_node_index; -} - -/** - * - * @remote_node_table: - * - * This method will free a single remote node index back to the remote node - * table. This routine will update the remote node groups - */ -static void sci_remote_node_table_release_single_remote_node( - struct sci_remote_node_table *remote_node_table, - u16 remote_node_index) -{ - u32 group_index; - u8 group_value; - - group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT; - - group_value = sci_remote_node_table_get_group_value(remote_node_table, group_index); - - /* - * Assert that we are not trying to add an entry to a slot that is already - * full. */ - BUG_ON(group_value == SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE); - - if (group_value == 0x00) { - /* - * There are no entries in this slot so it must be added to the single - * slot table. */ - sci_remote_node_table_set_group_index(remote_node_table, 0, group_index); - } else if ((group_value & (group_value - 1)) == 0) { - /* - * There is only one entry in this slot so it must be moved from the - * single slot table to the dual slot table */ - sci_remote_node_table_clear_group_index(remote_node_table, 0, group_index); - sci_remote_node_table_set_group_index(remote_node_table, 1, group_index); - } else { - /* - * There are two entries in the slot so it must be moved from the dual - * slot table to the tripple slot table. */ - sci_remote_node_table_clear_group_index(remote_node_table, 1, group_index); - sci_remote_node_table_set_group_index(remote_node_table, 2, group_index); - } - - sci_remote_node_table_set_node_index(remote_node_table, remote_node_index); -} - -/** - * - * @remote_node_table: This is the remote node table to which the remote node - * index is to be freed. - * - * This method will release a group of three consecutive remote nodes back to - * the free remote nodes. - */ -static void sci_remote_node_table_release_triple_remote_node( - struct sci_remote_node_table *remote_node_table, - u16 remote_node_index) -{ - u32 group_index; - - group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT; - - sci_remote_node_table_set_group_index( - remote_node_table, 2, group_index - ); - - sci_remote_node_table_set_group(remote_node_table, group_index); -} - -/** - * - * @remote_node_table: The remote node table to which the remote node index is - * to be freed. - * @remote_node_count: This is the count of consecutive remote nodes that are - * to be freed. - * - * This method will release the remote node index back into the remote node - * table free pool. - */ -void sci_remote_node_table_release_remote_node_index( - struct sci_remote_node_table *remote_node_table, - u32 remote_node_count, - u16 remote_node_index) -{ - if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) { - sci_remote_node_table_release_single_remote_node( - remote_node_table, remote_node_index); - } else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) { - sci_remote_node_table_release_triple_remote_node( - remote_node_table, remote_node_index); - } -} - diff --git a/ANDROID_3.4.5/drivers/scsi/isci/remote_node_table.h b/ANDROID_3.4.5/drivers/scsi/isci/remote_node_table.h deleted file mode 100644 index 721ab982..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/remote_node_table.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCIC_SDS_REMOTE_NODE_TABLE_H_ -#define _SCIC_SDS_REMOTE_NODE_TABLE_H_ - -#include "isci.h" - -/** - * - * - * Remote node sets are sets of remote node index in the remtoe node table The - * SCU hardware requires that STP remote node entries take three consecutive - * remote node index so the table is arranged in sets of three. The bits are - * used as 0111 0111 to make a byte and the bits define the set of three remote - * nodes to use as a sequence. - */ -#define SCIC_SDS_REMOTE_NODE_SETS_PER_BYTE 2 - -/** - * - * - * Since the remote node table is organized as DWORDS take the remote node sets - * in bytes and represent them in DWORDs. The lowest ordered bits are the ones - * used in case full DWORD is not being used. i.e. 0000 0000 0000 0000 0111 - * 0111 0111 0111 // if only a single WORD is in use in the DWORD. - */ -#define SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD \ - (sizeof(u32) * SCIC_SDS_REMOTE_NODE_SETS_PER_BYTE) -/** - * - * - * This is a count of the numeber of remote nodes that can be represented in a - * byte - */ -#define SCIC_SDS_REMOTE_NODES_PER_BYTE \ - (SCU_STP_REMOTE_NODE_COUNT * SCIC_SDS_REMOTE_NODE_SETS_PER_BYTE) - -/** - * - * - * This is a count of the number of remote nodes that can be represented in a - * DWROD - */ -#define SCIC_SDS_REMOTE_NODES_PER_DWORD \ - (sizeof(u32) * SCIC_SDS_REMOTE_NODES_PER_BYTE) - -/** - * - * - * This is the number of bits in a remote node group - */ -#define SCIC_SDS_REMOTE_NODES_BITS_PER_GROUP 4 - -#define SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX (0xFFFFFFFF) -#define SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE (0x07) -#define SCIC_SDS_REMOTE_NODE_TABLE_EMPTY_SLOT_VALUE (0x00) - -/** - * - * - * Expander attached sata remote node count - */ -#define SCU_STP_REMOTE_NODE_COUNT 3 - -/** - * - * - * Expander or direct attached ssp remote node count - */ -#define SCU_SSP_REMOTE_NODE_COUNT 1 - -/** - * - * - * Direct attached STP remote node count - */ -#define SCU_SATA_REMOTE_NODE_COUNT 1 - -/** - * struct sci_remote_node_table - - * - * - */ -struct sci_remote_node_table { - /** - * This field contains the array size in dwords - */ - u16 available_nodes_array_size; - - /** - * This field contains the array size of the - */ - u16 group_array_size; - - /** - * This field is the array of available remote node entries in bits. - * Because of the way STP remote node data is allocated on the SCU hardware - * the remote nodes must occupy three consecutive remote node context - * entries. For ease of allocation and de-allocation we have broken the - * sets of three into a single nibble. When the STP RNi is allocated all - * of the bits in the nibble are cleared. This math results in a table size - * of MAX_REMOTE_NODES / CONSECUTIVE RNi ENTRIES for STP / 2 entries per byte. - */ - u32 available_remote_nodes[ - (SCI_MAX_REMOTE_DEVICES / SCIC_SDS_REMOTE_NODES_PER_DWORD) - + ((SCI_MAX_REMOTE_DEVICES % SCIC_SDS_REMOTE_NODES_PER_DWORD) != 0)]; - - /** - * This field is the nibble selector for the above table. There are three - * possible selectors each for fast lookup when trying to find one, two or - * three remote node entries. - */ - u32 remote_node_groups[ - SCU_STP_REMOTE_NODE_COUNT][ - (SCI_MAX_REMOTE_DEVICES / (32 * SCU_STP_REMOTE_NODE_COUNT)) - + ((SCI_MAX_REMOTE_DEVICES % (32 * SCU_STP_REMOTE_NODE_COUNT)) != 0)]; - -}; - -/* --------------------------------------------------------------------------- */ - -void sci_remote_node_table_initialize( - struct sci_remote_node_table *remote_node_table, - u32 remote_node_entries); - -u16 sci_remote_node_table_allocate_remote_node( - struct sci_remote_node_table *remote_node_table, - u32 remote_node_count); - -void sci_remote_node_table_release_remote_node_index( - struct sci_remote_node_table *remote_node_table, - u32 remote_node_count, - u16 remote_node_index); - -#endif /* _SCIC_SDS_REMOTE_NODE_TABLE_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/request.c b/ANDROID_3.4.5/drivers/scsi/isci/request.c deleted file mode 100644 index 2def1e39..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/request.c +++ /dev/null @@ -1,3631 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "isci.h" -#include "task.h" -#include "request.h" -#include "scu_completion_codes.h" -#include "scu_event_codes.h" -#include "sas.h" - -#undef C -#define C(a) (#a) -const char *req_state_name(enum sci_base_request_states state) -{ - static const char * const strings[] = REQUEST_STATES; - - return strings[state]; -} -#undef C - -static struct scu_sgl_element_pair *to_sgl_element_pair(struct isci_request *ireq, - int idx) -{ - if (idx == 0) - return &ireq->tc->sgl_pair_ab; - else if (idx == 1) - return &ireq->tc->sgl_pair_cd; - else if (idx < 0) - return NULL; - else - return &ireq->sg_table[idx - 2]; -} - -static dma_addr_t to_sgl_element_pair_dma(struct isci_host *ihost, - struct isci_request *ireq, u32 idx) -{ - u32 offset; - - if (idx == 0) { - offset = (void *) &ireq->tc->sgl_pair_ab - - (void *) &ihost->task_context_table[0]; - return ihost->task_context_dma + offset; - } else if (idx == 1) { - offset = (void *) &ireq->tc->sgl_pair_cd - - (void *) &ihost->task_context_table[0]; - return ihost->task_context_dma + offset; - } - - return sci_io_request_get_dma_addr(ireq, &ireq->sg_table[idx - 2]); -} - -static void init_sgl_element(struct scu_sgl_element *e, struct scatterlist *sg) -{ - e->length = sg_dma_len(sg); - e->address_upper = upper_32_bits(sg_dma_address(sg)); - e->address_lower = lower_32_bits(sg_dma_address(sg)); - e->address_modifier = 0; -} - -static void sci_request_build_sgl(struct isci_request *ireq) -{ - struct isci_host *ihost = ireq->isci_host; - struct sas_task *task = isci_request_access_task(ireq); - struct scatterlist *sg = NULL; - dma_addr_t dma_addr; - u32 sg_idx = 0; - struct scu_sgl_element_pair *scu_sg = NULL; - struct scu_sgl_element_pair *prev_sg = NULL; - - if (task->num_scatter > 0) { - sg = task->scatter; - - while (sg) { - scu_sg = to_sgl_element_pair(ireq, sg_idx); - init_sgl_element(&scu_sg->A, sg); - sg = sg_next(sg); - if (sg) { - init_sgl_element(&scu_sg->B, sg); - sg = sg_next(sg); - } else - memset(&scu_sg->B, 0, sizeof(scu_sg->B)); - - if (prev_sg) { - dma_addr = to_sgl_element_pair_dma(ihost, - ireq, - sg_idx); - - prev_sg->next_pair_upper = - upper_32_bits(dma_addr); - prev_sg->next_pair_lower = - lower_32_bits(dma_addr); - } - - prev_sg = scu_sg; - sg_idx++; - } - } else { /* handle when no sg */ - scu_sg = to_sgl_element_pair(ireq, sg_idx); - - dma_addr = dma_map_single(&ihost->pdev->dev, - task->scatter, - task->total_xfer_len, - task->data_dir); - - ireq->zero_scatter_daddr = dma_addr; - - scu_sg->A.length = task->total_xfer_len; - scu_sg->A.address_upper = upper_32_bits(dma_addr); - scu_sg->A.address_lower = lower_32_bits(dma_addr); - } - - if (scu_sg) { - scu_sg->next_pair_upper = 0; - scu_sg->next_pair_lower = 0; - } -} - -static void sci_io_request_build_ssp_command_iu(struct isci_request *ireq) -{ - struct ssp_cmd_iu *cmd_iu; - struct sas_task *task = isci_request_access_task(ireq); - - cmd_iu = &ireq->ssp.cmd; - - memcpy(cmd_iu->LUN, task->ssp_task.LUN, 8); - cmd_iu->add_cdb_len = 0; - cmd_iu->_r_a = 0; - cmd_iu->_r_b = 0; - cmd_iu->en_fburst = 0; /* unsupported */ - cmd_iu->task_prio = task->ssp_task.task_prio; - cmd_iu->task_attr = task->ssp_task.task_attr; - cmd_iu->_r_c = 0; - - sci_swab32_cpy(&cmd_iu->cdb, task->ssp_task.cdb, - sizeof(task->ssp_task.cdb) / sizeof(u32)); -} - -static void sci_task_request_build_ssp_task_iu(struct isci_request *ireq) -{ - struct ssp_task_iu *task_iu; - struct sas_task *task = isci_request_access_task(ireq); - struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq); - - task_iu = &ireq->ssp.tmf; - - memset(task_iu, 0, sizeof(struct ssp_task_iu)); - - memcpy(task_iu->LUN, task->ssp_task.LUN, 8); - - task_iu->task_func = isci_tmf->tmf_code; - task_iu->task_tag = - (test_bit(IREQ_TMF, &ireq->flags)) ? - isci_tmf->io_tag : - SCI_CONTROLLER_INVALID_IO_TAG; -} - -/** - * This method is will fill in the SCU Task Context for any type of SSP request. - * @sci_req: - * @task_context: - * - */ -static void scu_ssp_reqeust_construct_task_context( - struct isci_request *ireq, - struct scu_task_context *task_context) -{ - dma_addr_t dma_addr; - struct isci_remote_device *idev; - struct isci_port *iport; - - idev = ireq->target_device; - iport = idev->owning_port; - - /* Fill in the TC with the its required data */ - task_context->abort = 0; - task_context->priority = 0; - task_context->initiator_request = 1; - task_context->connection_rate = idev->connection_rate; - task_context->protocol_engine_index = ISCI_PEG; - task_context->logical_port_index = iport->physical_port_index; - task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SSP; - task_context->valid = SCU_TASK_CONTEXT_VALID; - task_context->context_type = SCU_TASK_CONTEXT_TYPE; - - task_context->remote_node_index = idev->rnc.remote_node_index; - task_context->command_code = 0; - - task_context->link_layer_control = 0; - task_context->do_not_dma_ssp_good_response = 1; - task_context->strict_ordering = 0; - task_context->control_frame = 0; - task_context->timeout_enable = 0; - task_context->block_guard_enable = 0; - - task_context->address_modifier = 0; - - /* task_context->type.ssp.tag = ireq->io_tag; */ - task_context->task_phase = 0x01; - - ireq->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (ISCI_PEG << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (iport->physical_port_index << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | - ISCI_TAG_TCI(ireq->io_tag)); - - /* - * Copy the physical address for the command buffer to the - * SCU Task Context - */ - dma_addr = sci_io_request_get_dma_addr(ireq, &ireq->ssp.cmd); - - task_context->command_iu_upper = upper_32_bits(dma_addr); - task_context->command_iu_lower = lower_32_bits(dma_addr); - - /* - * Copy the physical address for the response buffer to the - * SCU Task Context - */ - dma_addr = sci_io_request_get_dma_addr(ireq, &ireq->ssp.rsp); - - task_context->response_iu_upper = upper_32_bits(dma_addr); - task_context->response_iu_lower = lower_32_bits(dma_addr); -} - -static u8 scu_bg_blk_size(struct scsi_device *sdp) -{ - switch (sdp->sector_size) { - case 512: - return 0; - case 1024: - return 1; - case 4096: - return 3; - default: - return 0xff; - } -} - -static u32 scu_dif_bytes(u32 len, u32 sector_size) -{ - return (len >> ilog2(sector_size)) * 8; -} - -static void scu_ssp_ireq_dif_insert(struct isci_request *ireq, u8 type, u8 op) -{ - struct scu_task_context *tc = ireq->tc; - struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task; - u8 blk_sz = scu_bg_blk_size(scmd->device); - - tc->block_guard_enable = 1; - tc->blk_prot_en = 1; - tc->blk_sz = blk_sz; - /* DIF write insert */ - tc->blk_prot_func = 0x2; - - tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes, - scmd->device->sector_size); - - /* always init to 0, used by hw */ - tc->interm_crc_val = 0; - - tc->init_crc_seed = 0; - tc->app_tag_verify = 0; - tc->app_tag_gen = 0; - tc->ref_tag_seed_verify = 0; - - /* always init to same as bg_blk_sz */ - tc->UD_bytes_immed_val = scmd->device->sector_size; - - tc->reserved_DC_0 = 0; - - /* always init to 8 */ - tc->DIF_bytes_immed_val = 8; - - tc->reserved_DC_1 = 0; - tc->bgc_blk_sz = scmd->device->sector_size; - tc->reserved_E0_0 = 0; - tc->app_tag_gen_mask = 0; - - /** setup block guard control **/ - tc->bgctl = 0; - - /* DIF write insert */ - tc->bgctl_f.op = 0x2; - - tc->app_tag_verify_mask = 0; - - /* must init to 0 for hw */ - tc->blk_guard_err = 0; - - tc->reserved_E8_0 = 0; - - if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) - tc->ref_tag_seed_gen = scsi_get_lba(scmd) & 0xffffffff; - else if (type & SCSI_PROT_DIF_TYPE3) - tc->ref_tag_seed_gen = 0; -} - -static void scu_ssp_ireq_dif_strip(struct isci_request *ireq, u8 type, u8 op) -{ - struct scu_task_context *tc = ireq->tc; - struct scsi_cmnd *scmd = ireq->ttype_ptr.io_task_ptr->uldd_task; - u8 blk_sz = scu_bg_blk_size(scmd->device); - - tc->block_guard_enable = 1; - tc->blk_prot_en = 1; - tc->blk_sz = blk_sz; - /* DIF read strip */ - tc->blk_prot_func = 0x1; - - tc->transfer_length_bytes += scu_dif_bytes(tc->transfer_length_bytes, - scmd->device->sector_size); - - /* always init to 0, used by hw */ - tc->interm_crc_val = 0; - - tc->init_crc_seed = 0; - tc->app_tag_verify = 0; - tc->app_tag_gen = 0; - - if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) - tc->ref_tag_seed_verify = scsi_get_lba(scmd) & 0xffffffff; - else if (type & SCSI_PROT_DIF_TYPE3) - tc->ref_tag_seed_verify = 0; - - /* always init to same as bg_blk_sz */ - tc->UD_bytes_immed_val = scmd->device->sector_size; - - tc->reserved_DC_0 = 0; - - /* always init to 8 */ - tc->DIF_bytes_immed_val = 8; - - tc->reserved_DC_1 = 0; - tc->bgc_blk_sz = scmd->device->sector_size; - tc->reserved_E0_0 = 0; - tc->app_tag_gen_mask = 0; - - /** setup block guard control **/ - tc->bgctl = 0; - - /* DIF read strip */ - tc->bgctl_f.crc_verify = 1; - tc->bgctl_f.op = 0x1; - if ((type & SCSI_PROT_DIF_TYPE1) || (type & SCSI_PROT_DIF_TYPE2)) { - tc->bgctl_f.ref_tag_chk = 1; - tc->bgctl_f.app_f_detect = 1; - } else if (type & SCSI_PROT_DIF_TYPE3) - tc->bgctl_f.app_ref_f_detect = 1; - - tc->app_tag_verify_mask = 0; - - /* must init to 0 for hw */ - tc->blk_guard_err = 0; - - tc->reserved_E8_0 = 0; - tc->ref_tag_seed_gen = 0; -} - -/** - * This method is will fill in the SCU Task Context for a SSP IO request. - * @sci_req: - * - */ -static void scu_ssp_io_request_construct_task_context(struct isci_request *ireq, - enum dma_data_direction dir, - u32 len) -{ - struct scu_task_context *task_context = ireq->tc; - struct sas_task *sas_task = ireq->ttype_ptr.io_task_ptr; - struct scsi_cmnd *scmd = sas_task->uldd_task; - u8 prot_type = scsi_get_prot_type(scmd); - u8 prot_op = scsi_get_prot_op(scmd); - - scu_ssp_reqeust_construct_task_context(ireq, task_context); - - task_context->ssp_command_iu_length = - sizeof(struct ssp_cmd_iu) / sizeof(u32); - task_context->type.ssp.frame_type = SSP_COMMAND; - - switch (dir) { - case DMA_FROM_DEVICE: - case DMA_NONE: - default: - task_context->task_type = SCU_TASK_TYPE_IOREAD; - break; - case DMA_TO_DEVICE: - task_context->task_type = SCU_TASK_TYPE_IOWRITE; - break; - } - - task_context->transfer_length_bytes = len; - - if (task_context->transfer_length_bytes > 0) - sci_request_build_sgl(ireq); - - if (prot_type != SCSI_PROT_DIF_TYPE0) { - if (prot_op == SCSI_PROT_READ_STRIP) - scu_ssp_ireq_dif_strip(ireq, prot_type, prot_op); - else if (prot_op == SCSI_PROT_WRITE_INSERT) - scu_ssp_ireq_dif_insert(ireq, prot_type, prot_op); - } -} - -/** - * This method will fill in the SCU Task Context for a SSP Task request. The - * following important settings are utilized: -# priority == - * SCU_TASK_PRIORITY_HIGH. This ensures that the task request is issued - * ahead of other task destined for the same Remote Node. -# task_type == - * SCU_TASK_TYPE_IOREAD. This simply indicates that a normal request type - * (i.e. non-raw frame) is being utilized to perform task management. -# - * control_frame == 1. This ensures that the proper endianess is set so - * that the bytes are transmitted in the right order for a task frame. - * @sci_req: This parameter specifies the task request object being - * constructed. - * - */ -static void scu_ssp_task_request_construct_task_context(struct isci_request *ireq) -{ - struct scu_task_context *task_context = ireq->tc; - - scu_ssp_reqeust_construct_task_context(ireq, task_context); - - task_context->control_frame = 1; - task_context->priority = SCU_TASK_PRIORITY_HIGH; - task_context->task_type = SCU_TASK_TYPE_RAW_FRAME; - task_context->transfer_length_bytes = 0; - task_context->type.ssp.frame_type = SSP_TASK; - task_context->ssp_command_iu_length = - sizeof(struct ssp_task_iu) / sizeof(u32); -} - -/** - * This method is will fill in the SCU Task Context for any type of SATA - * request. This is called from the various SATA constructors. - * @sci_req: The general IO request object which is to be used in - * constructing the SCU task context. - * @task_context: The buffer pointer for the SCU task context which is being - * constructed. - * - * The general io request construction is complete. The buffer assignment for - * the command buffer is complete. none Revisit task context construction to - * determine what is common for SSP/SMP/STP task context structures. - */ -static void scu_sata_reqeust_construct_task_context( - struct isci_request *ireq, - struct scu_task_context *task_context) -{ - dma_addr_t dma_addr; - struct isci_remote_device *idev; - struct isci_port *iport; - - idev = ireq->target_device; - iport = idev->owning_port; - - /* Fill in the TC with the its required data */ - task_context->abort = 0; - task_context->priority = SCU_TASK_PRIORITY_NORMAL; - task_context->initiator_request = 1; - task_context->connection_rate = idev->connection_rate; - task_context->protocol_engine_index = ISCI_PEG; - task_context->logical_port_index = iport->physical_port_index; - task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_STP; - task_context->valid = SCU_TASK_CONTEXT_VALID; - task_context->context_type = SCU_TASK_CONTEXT_TYPE; - - task_context->remote_node_index = idev->rnc.remote_node_index; - task_context->command_code = 0; - - task_context->link_layer_control = 0; - task_context->do_not_dma_ssp_good_response = 1; - task_context->strict_ordering = 0; - task_context->control_frame = 0; - task_context->timeout_enable = 0; - task_context->block_guard_enable = 0; - - task_context->address_modifier = 0; - task_context->task_phase = 0x01; - - task_context->ssp_command_iu_length = - (sizeof(struct host_to_dev_fis) - sizeof(u32)) / sizeof(u32); - - /* Set the first word of the H2D REG FIS */ - task_context->type.words[0] = *(u32 *)&ireq->stp.cmd; - - ireq->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (ISCI_PEG << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (iport->physical_port_index << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | - ISCI_TAG_TCI(ireq->io_tag)); - /* - * Copy the physical address for the command buffer to the SCU Task - * Context. We must offset the command buffer by 4 bytes because the - * first 4 bytes are transfered in the body of the TC. - */ - dma_addr = sci_io_request_get_dma_addr(ireq, - ((char *) &ireq->stp.cmd) + - sizeof(u32)); - - task_context->command_iu_upper = upper_32_bits(dma_addr); - task_context->command_iu_lower = lower_32_bits(dma_addr); - - /* SATA Requests do not have a response buffer */ - task_context->response_iu_upper = 0; - task_context->response_iu_lower = 0; -} - -static void scu_stp_raw_request_construct_task_context(struct isci_request *ireq) -{ - struct scu_task_context *task_context = ireq->tc; - - scu_sata_reqeust_construct_task_context(ireq, task_context); - - task_context->control_frame = 0; - task_context->priority = SCU_TASK_PRIORITY_NORMAL; - task_context->task_type = SCU_TASK_TYPE_SATA_RAW_FRAME; - task_context->type.stp.fis_type = FIS_REGH2D; - task_context->transfer_length_bytes = sizeof(struct host_to_dev_fis) - sizeof(u32); -} - -static enum sci_status sci_stp_pio_request_construct(struct isci_request *ireq, - bool copy_rx_frame) -{ - struct isci_stp_request *stp_req = &ireq->stp.req; - - scu_stp_raw_request_construct_task_context(ireq); - - stp_req->status = 0; - stp_req->sgl.offset = 0; - stp_req->sgl.set = SCU_SGL_ELEMENT_PAIR_A; - - if (copy_rx_frame) { - sci_request_build_sgl(ireq); - stp_req->sgl.index = 0; - } else { - /* The user does not want the data copied to the SGL buffer location */ - stp_req->sgl.index = -1; - } - - return SCI_SUCCESS; -} - -/** - * - * @sci_req: This parameter specifies the request to be constructed as an - * optimized request. - * @optimized_task_type: This parameter specifies whether the request is to be - * an UDMA request or a NCQ request. - A value of 0 indicates UDMA. - A - * value of 1 indicates NCQ. - * - * This method will perform request construction common to all types of STP - * requests that are optimized by the silicon (i.e. UDMA, NCQ). This method - * returns an indication as to whether the construction was successful. - */ -static void sci_stp_optimized_request_construct(struct isci_request *ireq, - u8 optimized_task_type, - u32 len, - enum dma_data_direction dir) -{ - struct scu_task_context *task_context = ireq->tc; - - /* Build the STP task context structure */ - scu_sata_reqeust_construct_task_context(ireq, task_context); - - /* Copy over the SGL elements */ - sci_request_build_sgl(ireq); - - /* Copy over the number of bytes to be transfered */ - task_context->transfer_length_bytes = len; - - if (dir == DMA_TO_DEVICE) { - /* - * The difference between the DMA IN and DMA OUT request task type - * values are consistent with the difference between FPDMA READ - * and FPDMA WRITE values. Add the supplied task type parameter - * to this difference to set the task type properly for this - * DATA OUT (WRITE) case. */ - task_context->task_type = optimized_task_type + (SCU_TASK_TYPE_DMA_OUT - - SCU_TASK_TYPE_DMA_IN); - } else { - /* - * For the DATA IN (READ) case, simply save the supplied - * optimized task type. */ - task_context->task_type = optimized_task_type; - } -} - -static void sci_atapi_construct(struct isci_request *ireq) -{ - struct host_to_dev_fis *h2d_fis = &ireq->stp.cmd; - struct sas_task *task; - - /* To simplify the implementation we take advantage of the - * silicon's partial acceleration of atapi protocol (dma data - * transfers), so we promote all commands to dma protocol. This - * breaks compatibility with ATA_HORKAGE_ATAPI_MOD16_DMA drives. - */ - h2d_fis->features |= ATAPI_PKT_DMA; - - scu_stp_raw_request_construct_task_context(ireq); - - task = isci_request_access_task(ireq); - if (task->data_dir == DMA_NONE) - task->total_xfer_len = 0; - - /* clear the response so we can detect arrivial of an - * unsolicited h2d fis - */ - ireq->stp.rsp.fis_type = 0; -} - -static enum sci_status -sci_io_request_construct_sata(struct isci_request *ireq, - u32 len, - enum dma_data_direction dir, - bool copy) -{ - enum sci_status status = SCI_SUCCESS; - struct sas_task *task = isci_request_access_task(ireq); - struct domain_device *dev = ireq->target_device->domain_dev; - - /* check for management protocols */ - if (test_bit(IREQ_TMF, &ireq->flags)) { - struct isci_tmf *tmf = isci_request_access_tmf(ireq); - - dev_err(&ireq->owning_controller->pdev->dev, - "%s: Request 0x%p received un-handled SAT " - "management protocol 0x%x.\n", - __func__, ireq, tmf->tmf_code); - - return SCI_FAILURE; - } - - if (!sas_protocol_ata(task->task_proto)) { - dev_err(&ireq->owning_controller->pdev->dev, - "%s: Non-ATA protocol in SATA path: 0x%x\n", - __func__, - task->task_proto); - return SCI_FAILURE; - - } - - /* ATAPI */ - if (dev->sata_dev.command_set == ATAPI_COMMAND_SET && - task->ata_task.fis.command == ATA_CMD_PACKET) { - sci_atapi_construct(ireq); - return SCI_SUCCESS; - } - - /* non data */ - if (task->data_dir == DMA_NONE) { - scu_stp_raw_request_construct_task_context(ireq); - return SCI_SUCCESS; - } - - /* NCQ */ - if (task->ata_task.use_ncq) { - sci_stp_optimized_request_construct(ireq, - SCU_TASK_TYPE_FPDMAQ_READ, - len, dir); - return SCI_SUCCESS; - } - - /* DMA */ - if (task->ata_task.dma_xfer) { - sci_stp_optimized_request_construct(ireq, - SCU_TASK_TYPE_DMA_IN, - len, dir); - return SCI_SUCCESS; - } else /* PIO */ - return sci_stp_pio_request_construct(ireq, copy); - - return status; -} - -static enum sci_status sci_io_request_construct_basic_ssp(struct isci_request *ireq) -{ - struct sas_task *task = isci_request_access_task(ireq); - - ireq->protocol = SCIC_SSP_PROTOCOL; - - scu_ssp_io_request_construct_task_context(ireq, - task->data_dir, - task->total_xfer_len); - - sci_io_request_build_ssp_command_iu(ireq); - - sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED); - - return SCI_SUCCESS; -} - -enum sci_status sci_task_request_construct_ssp( - struct isci_request *ireq) -{ - /* Construct the SSP Task SCU Task Context */ - scu_ssp_task_request_construct_task_context(ireq); - - /* Fill in the SSP Task IU */ - sci_task_request_build_ssp_task_iu(ireq); - - sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED); - - return SCI_SUCCESS; -} - -static enum sci_status sci_io_request_construct_basic_sata(struct isci_request *ireq) -{ - enum sci_status status; - bool copy = false; - struct sas_task *task = isci_request_access_task(ireq); - - ireq->protocol = SCIC_STP_PROTOCOL; - - copy = (task->data_dir == DMA_NONE) ? false : true; - - status = sci_io_request_construct_sata(ireq, - task->total_xfer_len, - task->data_dir, - copy); - - if (status == SCI_SUCCESS) - sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED); - - return status; -} - -/** - * sci_req_tx_bytes - bytes transferred when reply underruns request - * @ireq: request that was terminated early - */ -#define SCU_TASK_CONTEXT_SRAM 0x200000 -static u32 sci_req_tx_bytes(struct isci_request *ireq) -{ - struct isci_host *ihost = ireq->owning_controller; - u32 ret_val = 0; - - if (readl(&ihost->smu_registers->address_modifier) == 0) { - void __iomem *scu_reg_base = ihost->scu_registers; - - /* get the bytes of data from the Address == BAR1 + 20002Ch + (256*TCi) where - * BAR1 is the scu_registers - * 0x20002C = 0x200000 + 0x2c - * = start of task context SRAM + offset of (type.ssp.data_offset) - * TCi is the io_tag of struct sci_request - */ - ret_val = readl(scu_reg_base + - (SCU_TASK_CONTEXT_SRAM + offsetof(struct scu_task_context, type.ssp.data_offset)) + - ((sizeof(struct scu_task_context)) * ISCI_TAG_TCI(ireq->io_tag))); - } - - return ret_val; -} - -enum sci_status sci_request_start(struct isci_request *ireq) -{ - enum sci_base_request_states state; - struct scu_task_context *tc = ireq->tc; - struct isci_host *ihost = ireq->owning_controller; - - state = ireq->sm.current_state_id; - if (state != SCI_REQ_CONSTRUCTED) { - dev_warn(&ihost->pdev->dev, - "%s: SCIC IO Request requested to start while in wrong " - "state %d\n", __func__, state); - return SCI_FAILURE_INVALID_STATE; - } - - tc->task_index = ISCI_TAG_TCI(ireq->io_tag); - - switch (tc->protocol_type) { - case SCU_TASK_CONTEXT_PROTOCOL_SMP: - case SCU_TASK_CONTEXT_PROTOCOL_SSP: - /* SSP/SMP Frame */ - tc->type.ssp.tag = ireq->io_tag; - tc->type.ssp.target_port_transfer_tag = 0xFFFF; - break; - - case SCU_TASK_CONTEXT_PROTOCOL_STP: - /* STP/SATA Frame - * tc->type.stp.ncq_tag = ireq->ncq_tag; - */ - break; - - case SCU_TASK_CONTEXT_PROTOCOL_NONE: - /* / @todo When do we set no protocol type? */ - break; - - default: - /* This should never happen since we build the IO - * requests */ - break; - } - - /* Add to the post_context the io tag value */ - ireq->post_context |= ISCI_TAG_TCI(ireq->io_tag); - - /* Everything is good go ahead and change state */ - sci_change_state(&ireq->sm, SCI_REQ_STARTED); - - return SCI_SUCCESS; -} - -enum sci_status -sci_io_request_terminate(struct isci_request *ireq) -{ - enum sci_base_request_states state; - - state = ireq->sm.current_state_id; - - switch (state) { - case SCI_REQ_CONSTRUCTED: - ireq->scu_status = SCU_TASK_DONE_TASK_ABORT; - ireq->sci_status = SCI_FAILURE_IO_TERMINATED; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - return SCI_SUCCESS; - case SCI_REQ_STARTED: - case SCI_REQ_TASK_WAIT_TC_COMP: - case SCI_REQ_SMP_WAIT_RESP: - case SCI_REQ_SMP_WAIT_TC_COMP: - case SCI_REQ_STP_UDMA_WAIT_TC_COMP: - case SCI_REQ_STP_UDMA_WAIT_D2H: - case SCI_REQ_STP_NON_DATA_WAIT_H2D: - case SCI_REQ_STP_NON_DATA_WAIT_D2H: - case SCI_REQ_STP_PIO_WAIT_H2D: - case SCI_REQ_STP_PIO_WAIT_FRAME: - case SCI_REQ_STP_PIO_DATA_IN: - case SCI_REQ_STP_PIO_DATA_OUT: - case SCI_REQ_ATAPI_WAIT_H2D: - case SCI_REQ_ATAPI_WAIT_PIO_SETUP: - case SCI_REQ_ATAPI_WAIT_D2H: - case SCI_REQ_ATAPI_WAIT_TC_COMP: - sci_change_state(&ireq->sm, SCI_REQ_ABORTING); - return SCI_SUCCESS; - case SCI_REQ_TASK_WAIT_TC_RESP: - /* The task frame was already confirmed to have been - * sent by the SCU HW. Since the state machine is - * now only waiting for the task response itself, - * abort the request and complete it immediately - * and don't wait for the task response. - */ - sci_change_state(&ireq->sm, SCI_REQ_ABORTING); - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - return SCI_SUCCESS; - case SCI_REQ_ABORTING: - /* If a request has a termination requested twice, return - * a failure indication, since HW confirmation of the first - * abort is still outstanding. - */ - case SCI_REQ_COMPLETED: - default: - dev_warn(&ireq->owning_controller->pdev->dev, - "%s: SCIC IO Request requested to abort while in wrong " - "state %d\n", - __func__, - ireq->sm.current_state_id); - break; - } - - return SCI_FAILURE_INVALID_STATE; -} - -enum sci_status sci_request_complete(struct isci_request *ireq) -{ - enum sci_base_request_states state; - struct isci_host *ihost = ireq->owning_controller; - - state = ireq->sm.current_state_id; - if (WARN_ONCE(state != SCI_REQ_COMPLETED, - "isci: request completion from wrong state (%s)\n", - req_state_name(state))) - return SCI_FAILURE_INVALID_STATE; - - if (ireq->saved_rx_frame_index != SCU_INVALID_FRAME_INDEX) - sci_controller_release_frame(ihost, - ireq->saved_rx_frame_index); - - /* XXX can we just stop the machine and remove the 'final' state? */ - sci_change_state(&ireq->sm, SCI_REQ_FINAL); - return SCI_SUCCESS; -} - -enum sci_status sci_io_request_event_handler(struct isci_request *ireq, - u32 event_code) -{ - enum sci_base_request_states state; - struct isci_host *ihost = ireq->owning_controller; - - state = ireq->sm.current_state_id; - - if (state != SCI_REQ_STP_PIO_DATA_IN) { - dev_warn(&ihost->pdev->dev, "%s: (%x) in wrong state %s\n", - __func__, event_code, req_state_name(state)); - - return SCI_FAILURE_INVALID_STATE; - } - - switch (scu_get_event_specifier(event_code)) { - case SCU_TASK_DONE_CRC_ERR << SCU_EVENT_SPECIFIC_CODE_SHIFT: - /* We are waiting for data and the SCU has R_ERR the data frame. - * Go back to waiting for the D2H Register FIS - */ - sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME); - return SCI_SUCCESS; - default: - dev_err(&ihost->pdev->dev, - "%s: pio request unexpected event %#x\n", - __func__, event_code); - - /* TODO Should we fail the PIO request when we get an - * unexpected event? - */ - return SCI_FAILURE; - } -} - -/* - * This function copies response data for requests returning response data - * instead of sense data. - * @sci_req: This parameter specifies the request object for which to copy - * the response data. - */ -static void sci_io_request_copy_response(struct isci_request *ireq) -{ - void *resp_buf; - u32 len; - struct ssp_response_iu *ssp_response; - struct isci_tmf *isci_tmf = isci_request_access_tmf(ireq); - - ssp_response = &ireq->ssp.rsp; - - resp_buf = &isci_tmf->resp.resp_iu; - - len = min_t(u32, - SSP_RESP_IU_MAX_SIZE, - be32_to_cpu(ssp_response->response_data_len)); - - memcpy(resp_buf, ssp_response->resp_data, len); -} - -static enum sci_status -request_started_state_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - struct ssp_response_iu *resp_iu; - u8 datapres; - - /* TODO: Any SDMA return code of other than 0 is bad decode 0x003C0000 - * to determine SDMA status - */ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - break; - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EARLY_RESP): { - /* There are times when the SCU hardware will return an early - * response because the io request specified more data than is - * returned by the target device (mode pages, inquiry data, - * etc.). We must check the response stats to see if this is - * truly a failed request or a good request that just got - * completed early. - */ - struct ssp_response_iu *resp = &ireq->ssp.rsp; - ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); - - sci_swab32_cpy(&ireq->ssp.rsp, - &ireq->ssp.rsp, - word_cnt); - - if (resp->status == 0) { - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS_IO_DONE_EARLY; - } else { - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - } - break; - } - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CHECK_RESPONSE): { - ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); - - sci_swab32_cpy(&ireq->ssp.rsp, - &ireq->ssp.rsp, - word_cnt); - - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - break; - } - - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RESP_LEN_ERR): - /* TODO With TASK_DONE_RESP_LEN_ERR is the response frame - * guaranteed to be received before this completion status is - * posted? - */ - resp_iu = &ireq->ssp.rsp; - datapres = resp_iu->datapres; - - if (datapres == 1 || datapres == 2) { - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - } else { - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - } - break; - /* only stp device gets suspended. */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_PERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_DATA_LEN_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_ABORT_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_WD_LEN): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_RESP): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_SDBFIS): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDB_ERR): - if (ireq->protocol == SCIC_STP_PROTOCOL) { - ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >> - SCU_COMPLETION_TL_STATUS_SHIFT; - ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; - } else { - ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >> - SCU_COMPLETION_TL_STATUS_SHIFT; - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - } - break; - - /* both stp/ssp device gets suspended */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LF_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_WRONG_DESTINATION): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_BAD_DESTINATION): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_ZONE_VIOLATION): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED): - ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >> - SCU_COMPLETION_TL_STATUS_SHIFT; - ireq->sci_status = SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED; - break; - - /* neither ssp nor stp gets suspended. */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_NAK_CMD_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_XR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_XR_IU_LEN_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SDMA_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OFFSET_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_EXCESS_DATA): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_DATA): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_OPEN_FAIL): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_VIIT_ENTRY_NV): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_IIT_ENTRY_NV): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_RNCNV_OUTBOUND): - default: - ireq->scu_status = SCU_GET_COMPLETION_TL_STATUS(completion_code) >> - SCU_COMPLETION_TL_STATUS_SHIFT; - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - break; - } - - /* - * TODO: This is probably wrong for ACK/NAK timeout conditions - */ - - /* In all cases we will treat this as the completion of the IO req. */ - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - return SCI_SUCCESS; -} - -static enum sci_status -request_aborting_state_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT): - case (SCU_TASK_DONE_TASK_ABORT << SCU_COMPLETION_TL_STATUS_SHIFT): - ireq->scu_status = SCU_TASK_DONE_TASK_ABORT; - ireq->sci_status = SCI_FAILURE_IO_TERMINATED; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - - default: - /* Unless we get some strange error wait for the task abort to complete - * TODO: Should there be a state change for this completion? - */ - break; - } - - return SCI_SUCCESS; -} - -static enum sci_status ssp_task_request_await_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, SCI_REQ_TASK_WAIT_TC_RESP); - break; - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_ACK_NAK_TO): - /* Currently, the decision is to simply allow the task request - * to timeout if the task IU wasn't received successfully. - * There is a potential for receiving multiple task responses if - * we decide to send the task IU again. - */ - dev_warn(&ireq->owning_controller->pdev->dev, - "%s: TaskRequest:0x%p CompletionCode:%x - " - "ACK/NAK timeout\n", __func__, ireq, - completion_code); - - sci_change_state(&ireq->sm, SCI_REQ_TASK_WAIT_TC_RESP); - break; - default: - /* - * All other completion status cause the IO to be complete. - * If a NAK was received, then it is up to the user to retry - * the request. - */ - ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - -static enum sci_status -smp_request_await_response_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - /* In the AWAIT RESPONSE state, any TC completion is - * unexpected. but if the TC has success status, we - * complete the IO anyway. - */ - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_RESP_TO_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_UFI_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_FRM_TYPE_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_SMP_LL_RX_ERR): - /* These status has been seen in a specific LSI - * expander, which sometimes is not able to send smp - * response within 2 ms. This causes our hardware break - * the connection and set TC completion with one of - * these SMP_XXX_XX_ERR status. For these type of error, - * we ask ihost user to retry the request. - */ - ireq->scu_status = SCU_TASK_DONE_SMP_RESP_TO_ERR; - ireq->sci_status = SCI_FAILURE_RETRY_REQUIRED; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - default: - /* All other completion status cause the IO to be complete. If a NAK - * was received, then it is up to the user to retry the request - */ - ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - -static enum sci_status -smp_request_await_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - default: - /* All other completion status cause the IO to be - * complete. If a NAK was received, then it is up to - * the user to retry the request. - */ - ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - -static struct scu_sgl_element *pio_sgl_next(struct isci_stp_request *stp_req) -{ - struct scu_sgl_element *sgl; - struct scu_sgl_element_pair *sgl_pair; - struct isci_request *ireq = to_ireq(stp_req); - struct isci_stp_pio_sgl *pio_sgl = &stp_req->sgl; - - sgl_pair = to_sgl_element_pair(ireq, pio_sgl->index); - if (!sgl_pair) - sgl = NULL; - else if (pio_sgl->set == SCU_SGL_ELEMENT_PAIR_A) { - if (sgl_pair->B.address_lower == 0 && - sgl_pair->B.address_upper == 0) { - sgl = NULL; - } else { - pio_sgl->set = SCU_SGL_ELEMENT_PAIR_B; - sgl = &sgl_pair->B; - } - } else { - if (sgl_pair->next_pair_lower == 0 && - sgl_pair->next_pair_upper == 0) { - sgl = NULL; - } else { - pio_sgl->index++; - pio_sgl->set = SCU_SGL_ELEMENT_PAIR_A; - sgl_pair = to_sgl_element_pair(ireq, pio_sgl->index); - sgl = &sgl_pair->A; - } - } - - return sgl; -} - -static enum sci_status -stp_request_non_data_await_h2d_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, SCI_REQ_STP_NON_DATA_WAIT_D2H); - break; - - default: - /* All other completion status cause the IO to be - * complete. If a NAK was received, then it is up to - * the user to retry the request. - */ - ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - } - - return SCI_SUCCESS; -} - -#define SCU_MAX_FRAME_BUFFER_SIZE 0x400 /* 1K is the maximum SCU frame data payload */ - -/* transmit DATA_FIS from (current sgl + offset) for input - * parameter length. current sgl and offset is alreay stored in the IO request - */ -static enum sci_status sci_stp_request_pio_data_out_trasmit_data_frame( - struct isci_request *ireq, - u32 length) -{ - struct isci_stp_request *stp_req = &ireq->stp.req; - struct scu_task_context *task_context = ireq->tc; - struct scu_sgl_element_pair *sgl_pair; - struct scu_sgl_element *current_sgl; - - /* Recycle the TC and reconstruct it for sending out DATA FIS containing - * for the data from current_sgl+offset for the input length - */ - sgl_pair = to_sgl_element_pair(ireq, stp_req->sgl.index); - if (stp_req->sgl.set == SCU_SGL_ELEMENT_PAIR_A) - current_sgl = &sgl_pair->A; - else - current_sgl = &sgl_pair->B; - - /* update the TC */ - task_context->command_iu_upper = current_sgl->address_upper; - task_context->command_iu_lower = current_sgl->address_lower; - task_context->transfer_length_bytes = length; - task_context->type.stp.fis_type = FIS_DATA; - - /* send the new TC out. */ - return sci_controller_continue_io(ireq); -} - -static enum sci_status sci_stp_request_pio_data_out_transmit_data(struct isci_request *ireq) -{ - struct isci_stp_request *stp_req = &ireq->stp.req; - struct scu_sgl_element_pair *sgl_pair; - enum sci_status status = SCI_SUCCESS; - struct scu_sgl_element *sgl; - u32 offset; - u32 len = 0; - - offset = stp_req->sgl.offset; - sgl_pair = to_sgl_element_pair(ireq, stp_req->sgl.index); - if (WARN_ONCE(!sgl_pair, "%s: null sgl element", __func__)) - return SCI_FAILURE; - - if (stp_req->sgl.set == SCU_SGL_ELEMENT_PAIR_A) { - sgl = &sgl_pair->A; - len = sgl_pair->A.length - offset; - } else { - sgl = &sgl_pair->B; - len = sgl_pair->B.length - offset; - } - - if (stp_req->pio_len == 0) - return SCI_SUCCESS; - - if (stp_req->pio_len >= len) { - status = sci_stp_request_pio_data_out_trasmit_data_frame(ireq, len); - if (status != SCI_SUCCESS) - return status; - stp_req->pio_len -= len; - - /* update the current sgl, offset and save for future */ - sgl = pio_sgl_next(stp_req); - offset = 0; - } else if (stp_req->pio_len < len) { - sci_stp_request_pio_data_out_trasmit_data_frame(ireq, stp_req->pio_len); - - /* Sgl offset will be adjusted and saved for future */ - offset += stp_req->pio_len; - sgl->address_lower += stp_req->pio_len; - stp_req->pio_len = 0; - } - - stp_req->sgl.offset = offset; - - return status; -} - -/** - * - * @stp_request: The request that is used for the SGL processing. - * @data_buffer: The buffer of data to be copied. - * @length: The length of the data transfer. - * - * Copy the data from the buffer for the length specified to the IO reqeust SGL - * specified data region. enum sci_status - */ -static enum sci_status -sci_stp_request_pio_data_in_copy_data_buffer(struct isci_stp_request *stp_req, - u8 *data_buf, u32 len) -{ - struct isci_request *ireq; - u8 *src_addr; - int copy_len; - struct sas_task *task; - struct scatterlist *sg; - void *kaddr; - int total_len = len; - - ireq = to_ireq(stp_req); - task = isci_request_access_task(ireq); - src_addr = data_buf; - - if (task->num_scatter > 0) { - sg = task->scatter; - - while (total_len > 0) { - struct page *page = sg_page(sg); - - copy_len = min_t(int, total_len, sg_dma_len(sg)); - kaddr = kmap_atomic(page); - memcpy(kaddr + sg->offset, src_addr, copy_len); - kunmap_atomic(kaddr); - total_len -= copy_len; - src_addr += copy_len; - sg = sg_next(sg); - } - } else { - BUG_ON(task->total_xfer_len < total_len); - memcpy(task->scatter, src_addr, total_len); - } - - return SCI_SUCCESS; -} - -/** - * - * @sci_req: The PIO DATA IN request that is to receive the data. - * @data_buffer: The buffer to copy from. - * - * Copy the data buffer to the io request data region. enum sci_status - */ -static enum sci_status sci_stp_request_pio_data_in_copy_data( - struct isci_stp_request *stp_req, - u8 *data_buffer) -{ - enum sci_status status; - - /* - * If there is less than 1K remaining in the transfer request - * copy just the data for the transfer */ - if (stp_req->pio_len < SCU_MAX_FRAME_BUFFER_SIZE) { - status = sci_stp_request_pio_data_in_copy_data_buffer( - stp_req, data_buffer, stp_req->pio_len); - - if (status == SCI_SUCCESS) - stp_req->pio_len = 0; - } else { - /* We are transfering the whole frame so copy */ - status = sci_stp_request_pio_data_in_copy_data_buffer( - stp_req, data_buffer, SCU_MAX_FRAME_BUFFER_SIZE); - - if (status == SCI_SUCCESS) - stp_req->pio_len -= SCU_MAX_FRAME_BUFFER_SIZE; - } - - return status; -} - -static enum sci_status -stp_request_pio_await_h2d_completion_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - enum sci_status status = SCI_SUCCESS; - - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME); - break; - - default: - /* All other completion status cause the IO to be - * complete. If a NAK was received, then it is up to - * the user to retry the request. - */ - ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - } - - return status; -} - -static enum sci_status -pio_data_out_tx_done_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - enum sci_status status = SCI_SUCCESS; - bool all_frames_transferred = false; - struct isci_stp_request *stp_req = &ireq->stp.req; - - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - /* Transmit data */ - if (stp_req->pio_len != 0) { - status = sci_stp_request_pio_data_out_transmit_data(ireq); - if (status == SCI_SUCCESS) { - if (stp_req->pio_len == 0) - all_frames_transferred = true; - } - } else if (stp_req->pio_len == 0) { - /* - * this will happen if the all data is written at the - * first time after the pio setup fis is received - */ - all_frames_transferred = true; - } - - /* all data transferred. */ - if (all_frames_transferred) { - /* - * Change the state to SCI_REQ_STP_PIO_DATA_IN - * and wait for PIO_SETUP fis / or D2H REg fis. */ - sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME); - } - break; - - default: - /* - * All other completion status cause the IO to be complete. - * If a NAK was received, then it is up to the user to retry - * the request. - */ - ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - } - - return status; -} - -static enum sci_status sci_stp_request_udma_general_frame_handler(struct isci_request *ireq, - u32 frame_index) -{ - struct isci_host *ihost = ireq->owning_controller; - struct dev_to_host_fis *frame_header; - enum sci_status status; - u32 *frame_buffer; - - status = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - (void **)&frame_header); - - if ((status == SCI_SUCCESS) && - (frame_header->fis_type == FIS_REGD2H)) { - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - (void **)&frame_buffer); - - sci_controller_copy_sata_response(&ireq->stp.rsp, - frame_header, - frame_buffer); - } - - sci_controller_release_frame(ihost, frame_index); - - return status; -} - -static enum sci_status process_unsolicited_fis(struct isci_request *ireq, - u32 frame_index) -{ - struct isci_host *ihost = ireq->owning_controller; - enum sci_status status; - struct dev_to_host_fis *frame_header; - u32 *frame_buffer; - - status = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - (void **)&frame_header); - - if (status != SCI_SUCCESS) - return status; - - if (frame_header->fis_type != FIS_REGD2H) { - dev_err(&ireq->isci_host->pdev->dev, - "%s ERROR: invalid fis type 0x%X\n", - __func__, frame_header->fis_type); - return SCI_FAILURE; - } - - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - (void **)&frame_buffer); - - sci_controller_copy_sata_response(&ireq->stp.rsp, - (u32 *)frame_header, - frame_buffer); - - /* Frame has been decoded return it to the controller */ - sci_controller_release_frame(ihost, frame_index); - - return status; -} - -static enum sci_status atapi_d2h_reg_frame_handler(struct isci_request *ireq, - u32 frame_index) -{ - struct sas_task *task = isci_request_access_task(ireq); - enum sci_status status; - - status = process_unsolicited_fis(ireq, frame_index); - - if (status == SCI_SUCCESS) { - if (ireq->stp.rsp.status & ATA_ERR) - status = SCI_IO_FAILURE_RESPONSE_VALID; - } else { - status = SCI_IO_FAILURE_RESPONSE_VALID; - } - - if (status != SCI_SUCCESS) { - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = status; - } else { - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - } - - /* the d2h ufi is the end of non-data commands */ - if (task->data_dir == DMA_NONE) - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - - return status; -} - -static void scu_atapi_reconstruct_raw_frame_task_context(struct isci_request *ireq) -{ - struct ata_device *dev = sas_to_ata_dev(ireq->target_device->domain_dev); - void *atapi_cdb = ireq->ttype_ptr.io_task_ptr->ata_task.atapi_packet; - struct scu_task_context *task_context = ireq->tc; - - /* fill in the SCU Task Context for a DATA fis containing CDB in Raw Frame - * type. The TC for previous Packet fis was already there, we only need to - * change the H2D fis content. - */ - memset(&ireq->stp.cmd, 0, sizeof(struct host_to_dev_fis)); - memcpy(((u8 *)&ireq->stp.cmd + sizeof(u32)), atapi_cdb, ATAPI_CDB_LEN); - memset(&(task_context->type.stp), 0, sizeof(struct stp_task_context)); - task_context->type.stp.fis_type = FIS_DATA; - task_context->transfer_length_bytes = dev->cdb_len; -} - -static void scu_atapi_construct_task_context(struct isci_request *ireq) -{ - struct ata_device *dev = sas_to_ata_dev(ireq->target_device->domain_dev); - struct sas_task *task = isci_request_access_task(ireq); - struct scu_task_context *task_context = ireq->tc; - int cdb_len = dev->cdb_len; - - /* reference: SSTL 1.13.4.2 - * task_type, sata_direction - */ - if (task->data_dir == DMA_TO_DEVICE) { - task_context->task_type = SCU_TASK_TYPE_PACKET_DMA_OUT; - task_context->sata_direction = 0; - } else { - /* todo: for NO_DATA command, we need to send out raw frame. */ - task_context->task_type = SCU_TASK_TYPE_PACKET_DMA_IN; - task_context->sata_direction = 1; - } - - memset(&task_context->type.stp, 0, sizeof(task_context->type.stp)); - task_context->type.stp.fis_type = FIS_DATA; - - memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd)); - memcpy(&ireq->stp.cmd.lbal, task->ata_task.atapi_packet, cdb_len); - task_context->ssp_command_iu_length = cdb_len / sizeof(u32); - - /* task phase is set to TX_CMD */ - task_context->task_phase = 0x1; - - /* retry counter */ - task_context->stp_retry_count = 0; - - /* data transfer size. */ - task_context->transfer_length_bytes = task->total_xfer_len; - - /* setup sgl */ - sci_request_build_sgl(ireq); -} - -enum sci_status -sci_io_request_frame_handler(struct isci_request *ireq, - u32 frame_index) -{ - struct isci_host *ihost = ireq->owning_controller; - struct isci_stp_request *stp_req = &ireq->stp.req; - enum sci_base_request_states state; - enum sci_status status; - ssize_t word_cnt; - - state = ireq->sm.current_state_id; - switch (state) { - case SCI_REQ_STARTED: { - struct ssp_frame_hdr ssp_hdr; - void *frame_header; - - sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - &frame_header); - - word_cnt = sizeof(struct ssp_frame_hdr) / sizeof(u32); - sci_swab32_cpy(&ssp_hdr, frame_header, word_cnt); - - if (ssp_hdr.frame_type == SSP_RESPONSE) { - struct ssp_response_iu *resp_iu; - ssize_t word_cnt = SSP_RESP_IU_MAX_SIZE / sizeof(u32); - - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - (void **)&resp_iu); - - sci_swab32_cpy(&ireq->ssp.rsp, resp_iu, word_cnt); - - resp_iu = &ireq->ssp.rsp; - - if (resp_iu->datapres == 0x01 || - resp_iu->datapres == 0x02) { - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - } else { - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - } - } else { - /* not a response frame, why did it get forwarded? */ - dev_err(&ihost->pdev->dev, - "%s: SCIC IO Request 0x%p received unexpected " - "frame %d type 0x%02x\n", __func__, ireq, - frame_index, ssp_hdr.frame_type); - } - - /* - * In any case we are done with this frame buffer return it to - * the controller - */ - sci_controller_release_frame(ihost, frame_index); - - return SCI_SUCCESS; - } - - case SCI_REQ_TASK_WAIT_TC_RESP: - sci_io_request_copy_response(ireq); - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - sci_controller_release_frame(ihost, frame_index); - return SCI_SUCCESS; - - case SCI_REQ_SMP_WAIT_RESP: { - struct sas_task *task = isci_request_access_task(ireq); - struct scatterlist *sg = &task->smp_task.smp_resp; - void *frame_header, *kaddr; - u8 *rsp; - - sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - &frame_header); - kaddr = kmap_atomic(sg_page(sg)); - rsp = kaddr + sg->offset; - sci_swab32_cpy(rsp, frame_header, 1); - - if (rsp[0] == SMP_RESPONSE) { - void *smp_resp; - - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - &smp_resp); - - word_cnt = (sg->length/4)-1; - if (word_cnt > 0) - word_cnt = min_t(unsigned int, word_cnt, - SCU_UNSOLICITED_FRAME_BUFFER_SIZE/4); - sci_swab32_cpy(rsp + 4, smp_resp, word_cnt); - - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, SCI_REQ_SMP_WAIT_TC_COMP); - } else { - /* - * This was not a response frame why did it get - * forwarded? - */ - dev_err(&ihost->pdev->dev, - "%s: SCIC SMP Request 0x%p received unexpected " - "frame %d type 0x%02x\n", - __func__, - ireq, - frame_index, - rsp[0]); - - ireq->scu_status = SCU_TASK_DONE_SMP_FRM_TYPE_ERR; - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - } - kunmap_atomic(kaddr); - - sci_controller_release_frame(ihost, frame_index); - - return SCI_SUCCESS; - } - - case SCI_REQ_STP_UDMA_WAIT_TC_COMP: - return sci_stp_request_udma_general_frame_handler(ireq, - frame_index); - - case SCI_REQ_STP_UDMA_WAIT_D2H: - /* Use the general frame handler to copy the resposne data */ - status = sci_stp_request_udma_general_frame_handler(ireq, frame_index); - - if (status != SCI_SUCCESS) - return status; - - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - return SCI_SUCCESS; - - case SCI_REQ_STP_NON_DATA_WAIT_D2H: { - struct dev_to_host_fis *frame_header; - u32 *frame_buffer; - - status = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - (void **)&frame_header); - - if (status != SCI_SUCCESS) { - dev_err(&ihost->pdev->dev, - "%s: SCIC IO Request 0x%p could not get frame " - "header for frame index %d, status %x\n", - __func__, - stp_req, - frame_index, - status); - - return status; - } - - switch (frame_header->fis_type) { - case FIS_REGD2H: - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - (void **)&frame_buffer); - - sci_controller_copy_sata_response(&ireq->stp.rsp, - frame_header, - frame_buffer); - - /* The command has completed with error */ - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - break; - - default: - dev_warn(&ihost->pdev->dev, - "%s: IO Request:0x%p Frame Id:%d protocol " - "violation occurred\n", __func__, stp_req, - frame_index); - - ireq->scu_status = SCU_TASK_DONE_UNEXP_FIS; - ireq->sci_status = SCI_FAILURE_PROTOCOL_VIOLATION; - break; - } - - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - - /* Frame has been decoded return it to the controller */ - sci_controller_release_frame(ihost, frame_index); - - return status; - } - - case SCI_REQ_STP_PIO_WAIT_FRAME: { - struct sas_task *task = isci_request_access_task(ireq); - struct dev_to_host_fis *frame_header; - u32 *frame_buffer; - - status = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - (void **)&frame_header); - - if (status != SCI_SUCCESS) { - dev_err(&ihost->pdev->dev, - "%s: SCIC IO Request 0x%p could not get frame " - "header for frame index %d, status %x\n", - __func__, stp_req, frame_index, status); - return status; - } - - switch (frame_header->fis_type) { - case FIS_PIO_SETUP: - /* Get from the frame buffer the PIO Setup Data */ - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - (void **)&frame_buffer); - - /* Get the data from the PIO Setup The SCU Hardware - * returns first word in the frame_header and the rest - * of the data is in the frame buffer so we need to - * back up one dword - */ - - /* transfer_count: first 16bits in the 4th dword */ - stp_req->pio_len = frame_buffer[3] & 0xffff; - - /* status: 4th byte in the 3rd dword */ - stp_req->status = (frame_buffer[2] >> 24) & 0xff; - - sci_controller_copy_sata_response(&ireq->stp.rsp, - frame_header, - frame_buffer); - - ireq->stp.rsp.status = stp_req->status; - - /* The next state is dependent on whether the - * request was PIO Data-in or Data out - */ - if (task->data_dir == DMA_FROM_DEVICE) { - sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_DATA_IN); - } else if (task->data_dir == DMA_TO_DEVICE) { - /* Transmit data */ - status = sci_stp_request_pio_data_out_transmit_data(ireq); - if (status != SCI_SUCCESS) - break; - sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_DATA_OUT); - } - break; - - case FIS_SETDEVBITS: - sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME); - break; - - case FIS_REGD2H: - if (frame_header->status & ATA_BUSY) { - /* - * Now why is the drive sending a D2H Register - * FIS when it is still busy? Do nothing since - * we are still in the right state. - */ - dev_dbg(&ihost->pdev->dev, - "%s: SCIC PIO Request 0x%p received " - "D2H Register FIS with BSY status " - "0x%x\n", - __func__, - stp_req, - frame_header->status); - break; - } - - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - (void **)&frame_buffer); - - sci_controller_copy_sata_response(&ireq->stp.req, - frame_header, - frame_buffer); - - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - - default: - /* FIXME: what do we do here? */ - break; - } - - /* Frame is decoded return it to the controller */ - sci_controller_release_frame(ihost, frame_index); - - return status; - } - - case SCI_REQ_STP_PIO_DATA_IN: { - struct dev_to_host_fis *frame_header; - struct sata_fis_data *frame_buffer; - - status = sci_unsolicited_frame_control_get_header(&ihost->uf_control, - frame_index, - (void **)&frame_header); - - if (status != SCI_SUCCESS) { - dev_err(&ihost->pdev->dev, - "%s: SCIC IO Request 0x%p could not get frame " - "header for frame index %d, status %x\n", - __func__, - stp_req, - frame_index, - status); - return status; - } - - if (frame_header->fis_type != FIS_DATA) { - dev_err(&ihost->pdev->dev, - "%s: SCIC PIO Request 0x%p received frame %d " - "with fis type 0x%02x when expecting a data " - "fis.\n", - __func__, - stp_req, - frame_index, - frame_header->fis_type); - - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_FAILURE_IO_REQUIRES_SCSI_ABORT; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - - /* Frame is decoded return it to the controller */ - sci_controller_release_frame(ihost, frame_index); - return status; - } - - if (stp_req->sgl.index < 0) { - ireq->saved_rx_frame_index = frame_index; - stp_req->pio_len = 0; - } else { - sci_unsolicited_frame_control_get_buffer(&ihost->uf_control, - frame_index, - (void **)&frame_buffer); - - status = sci_stp_request_pio_data_in_copy_data(stp_req, - (u8 *)frame_buffer); - - /* Frame is decoded return it to the controller */ - sci_controller_release_frame(ihost, frame_index); - } - - /* Check for the end of the transfer, are there more - * bytes remaining for this data transfer - */ - if (status != SCI_SUCCESS || stp_req->pio_len != 0) - return status; - - if ((stp_req->status & ATA_BUSY) == 0) { - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - } else { - sci_change_state(&ireq->sm, SCI_REQ_STP_PIO_WAIT_FRAME); - } - return status; - } - - case SCI_REQ_ATAPI_WAIT_PIO_SETUP: { - struct sas_task *task = isci_request_access_task(ireq); - - sci_controller_release_frame(ihost, frame_index); - ireq->target_device->working_request = ireq; - if (task->data_dir == DMA_NONE) { - sci_change_state(&ireq->sm, SCI_REQ_ATAPI_WAIT_TC_COMP); - scu_atapi_reconstruct_raw_frame_task_context(ireq); - } else { - sci_change_state(&ireq->sm, SCI_REQ_ATAPI_WAIT_D2H); - scu_atapi_construct_task_context(ireq); - } - - sci_controller_continue_io(ireq); - return SCI_SUCCESS; - } - case SCI_REQ_ATAPI_WAIT_D2H: - return atapi_d2h_reg_frame_handler(ireq, frame_index); - case SCI_REQ_ABORTING: - /* - * TODO: Is it even possible to get an unsolicited frame in the - * aborting state? - */ - sci_controller_release_frame(ihost, frame_index); - return SCI_SUCCESS; - - default: - dev_warn(&ihost->pdev->dev, - "%s: SCIC IO Request given unexpected frame %x while " - "in state %d\n", - __func__, - frame_index, - state); - - sci_controller_release_frame(ihost, frame_index); - return SCI_FAILURE_INVALID_STATE; - } -} - -static enum sci_status stp_request_udma_await_tc_event(struct isci_request *ireq, - u32 completion_code) -{ - enum sci_status status = SCI_SUCCESS; - - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_UNEXP_FIS): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_REG_ERR): - /* We must check ther response buffer to see if the D2H - * Register FIS was received before we got the TC - * completion. - */ - if (ireq->stp.rsp.fis_type == FIS_REGD2H) { - sci_remote_device_suspend(ireq->target_device, - SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))); - - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - } else { - /* If we have an error completion status for the - * TC then we can expect a D2H register FIS from - * the device so we must change state to wait - * for it - */ - sci_change_state(&ireq->sm, SCI_REQ_STP_UDMA_WAIT_D2H); - } - break; - - /* TODO Check to see if any of these completion status need to - * wait for the device to host register fis. - */ - /* TODO We can retry the command for SCU_TASK_DONE_CMD_LL_R_ERR - * - this comes only for B0 - */ - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_INV_FIS_LEN): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_MAX_PLD_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_LL_R_ERR): - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_CMD_LL_R_ERR): - sci_remote_device_suspend(ireq->target_device, - SCU_EVENT_SPECIFIC(SCU_NORMALIZE_COMPLETION_STATUS(completion_code))); - /* Fall through to the default case */ - default: - /* All other completion status cause the IO to be complete. */ - ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - } - - return status; -} - -static enum sci_status atapi_raw_completion(struct isci_request *ireq, u32 completion_code, - enum sci_base_request_states next) -{ - enum sci_status status = SCI_SUCCESS; - - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case SCU_MAKE_COMPLETION_STATUS(SCU_TASK_DONE_GOOD): - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, next); - break; - default: - /* All other completion status cause the IO to be complete. - * If a NAK was received, then it is up to the user to retry - * the request. - */ - ireq->scu_status = SCU_NORMALIZE_COMPLETION_STATUS(completion_code); - ireq->sci_status = SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR; - - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - } - - return status; -} - -static enum sci_status atapi_data_tc_completion_handler(struct isci_request *ireq, - u32 completion_code) -{ - struct isci_remote_device *idev = ireq->target_device; - struct dev_to_host_fis *d2h = &ireq->stp.rsp; - enum sci_status status = SCI_SUCCESS; - - switch (SCU_GET_COMPLETION_TL_STATUS(completion_code)) { - case (SCU_TASK_DONE_GOOD << SCU_COMPLETION_TL_STATUS_SHIFT): - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - - case (SCU_TASK_DONE_UNEXP_FIS << SCU_COMPLETION_TL_STATUS_SHIFT): { - u16 len = sci_req_tx_bytes(ireq); - - /* likely non-error data underrrun, workaround missing - * d2h frame from the controller - */ - if (d2h->fis_type != FIS_REGD2H) { - d2h->fis_type = FIS_REGD2H; - d2h->flags = (1 << 6); - d2h->status = 0x50; - d2h->error = 0; - d2h->lbal = 0; - d2h->byte_count_low = len & 0xff; - d2h->byte_count_high = len >> 8; - d2h->device = 0xa0; - d2h->lbal_exp = 0; - d2h->lbam_exp = 0; - d2h->lbah_exp = 0; - d2h->_r_a = 0; - d2h->sector_count = 0x3; - d2h->sector_count_exp = 0; - d2h->_r_b = 0; - d2h->_r_c = 0; - d2h->_r_d = 0; - } - - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS_IO_DONE_EARLY; - status = ireq->sci_status; - - /* the hw will have suspended the rnc, so complete the - * request upon pending resume - */ - sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR); - break; - } - case (SCU_TASK_DONE_EXCESS_DATA << SCU_COMPLETION_TL_STATUS_SHIFT): - /* In this case, there is no UF coming after. - * compelte the IO now. - */ - ireq->scu_status = SCU_TASK_DONE_GOOD; - ireq->sci_status = SCI_SUCCESS; - sci_change_state(&ireq->sm, SCI_REQ_COMPLETED); - break; - - default: - if (d2h->fis_type == FIS_REGD2H) { - /* UF received change the device state to ATAPI_ERROR */ - status = ireq->sci_status; - sci_change_state(&idev->sm, SCI_STP_DEV_ATAPI_ERROR); - } else { - /* If receiving any non-sucess TC status, no UF - * received yet, then an UF for the status fis - * is coming after (XXX: suspect this is - * actually a protocol error or a bug like the - * DONE_UNEXP_FIS case) - */ - ireq->scu_status = SCU_TASK_DONE_CHECK_RESPONSE; - ireq->sci_status = SCI_FAILURE_IO_RESPONSE_VALID; - - sci_change_state(&ireq->sm, SCI_REQ_ATAPI_WAIT_D2H); - } - break; - } - - return status; -} - -enum sci_status -sci_io_request_tc_completion(struct isci_request *ireq, - u32 completion_code) -{ - enum sci_base_request_states state; - struct isci_host *ihost = ireq->owning_controller; - - state = ireq->sm.current_state_id; - - switch (state) { - case SCI_REQ_STARTED: - return request_started_state_tc_event(ireq, completion_code); - - case SCI_REQ_TASK_WAIT_TC_COMP: - return ssp_task_request_await_tc_event(ireq, - completion_code); - - case SCI_REQ_SMP_WAIT_RESP: - return smp_request_await_response_tc_event(ireq, - completion_code); - - case SCI_REQ_SMP_WAIT_TC_COMP: - return smp_request_await_tc_event(ireq, completion_code); - - case SCI_REQ_STP_UDMA_WAIT_TC_COMP: - return stp_request_udma_await_tc_event(ireq, - completion_code); - - case SCI_REQ_STP_NON_DATA_WAIT_H2D: - return stp_request_non_data_await_h2d_tc_event(ireq, - completion_code); - - case SCI_REQ_STP_PIO_WAIT_H2D: - return stp_request_pio_await_h2d_completion_tc_event(ireq, - completion_code); - - case SCI_REQ_STP_PIO_DATA_OUT: - return pio_data_out_tx_done_tc_event(ireq, completion_code); - - case SCI_REQ_ABORTING: - return request_aborting_state_tc_event(ireq, - completion_code); - - case SCI_REQ_ATAPI_WAIT_H2D: - return atapi_raw_completion(ireq, completion_code, - SCI_REQ_ATAPI_WAIT_PIO_SETUP); - - case SCI_REQ_ATAPI_WAIT_TC_COMP: - return atapi_raw_completion(ireq, completion_code, - SCI_REQ_ATAPI_WAIT_D2H); - - case SCI_REQ_ATAPI_WAIT_D2H: - return atapi_data_tc_completion_handler(ireq, completion_code); - - default: - dev_warn(&ihost->pdev->dev, "%s: %x in wrong state %s\n", - __func__, completion_code, req_state_name(state)); - return SCI_FAILURE_INVALID_STATE; - } -} - -/** - * isci_request_process_response_iu() - This function sets the status and - * response iu, in the task struct, from the request object for the upper - * layer driver. - * @sas_task: This parameter is the task struct from the upper layer driver. - * @resp_iu: This parameter points to the response iu of the completed request. - * @dev: This parameter specifies the linux device struct. - * - * none. - */ -static void isci_request_process_response_iu( - struct sas_task *task, - struct ssp_response_iu *resp_iu, - struct device *dev) -{ - dev_dbg(dev, - "%s: resp_iu = %p " - "resp_iu->status = 0x%x,\nresp_iu->datapres = %d " - "resp_iu->response_data_len = %x, " - "resp_iu->sense_data_len = %x\nrepsonse data: ", - __func__, - resp_iu, - resp_iu->status, - resp_iu->datapres, - resp_iu->response_data_len, - resp_iu->sense_data_len); - - task->task_status.stat = resp_iu->status; - - /* libsas updates the task status fields based on the response iu. */ - sas_ssp_task_response(dev, task, resp_iu); -} - -/** - * isci_request_set_open_reject_status() - This function prepares the I/O - * completion for OPEN_REJECT conditions. - * @request: This parameter is the completed isci_request object. - * @response_ptr: This parameter specifies the service response for the I/O. - * @status_ptr: This parameter specifies the exec status for the I/O. - * @complete_to_host_ptr: This parameter specifies the action to be taken by - * the LLDD with respect to completing this request or forcing an abort - * condition on the I/O. - * @open_rej_reason: This parameter specifies the encoded reason for the - * abandon-class reject. - * - * none. - */ -static void isci_request_set_open_reject_status( - struct isci_request *request, - struct sas_task *task, - enum service_response *response_ptr, - enum exec_status *status_ptr, - enum isci_completion_selection *complete_to_host_ptr, - enum sas_open_rej_reason open_rej_reason) -{ - /* Task in the target is done. */ - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - *response_ptr = SAS_TASK_UNDELIVERED; - *status_ptr = SAS_OPEN_REJECT; - *complete_to_host_ptr = isci_perform_normal_io_completion; - task->task_status.open_rej_reason = open_rej_reason; -} - -/** - * isci_request_handle_controller_specific_errors() - This function decodes - * controller-specific I/O completion error conditions. - * @request: This parameter is the completed isci_request object. - * @response_ptr: This parameter specifies the service response for the I/O. - * @status_ptr: This parameter specifies the exec status for the I/O. - * @complete_to_host_ptr: This parameter specifies the action to be taken by - * the LLDD with respect to completing this request or forcing an abort - * condition on the I/O. - * - * none. - */ -static void isci_request_handle_controller_specific_errors( - struct isci_remote_device *idev, - struct isci_request *request, - struct sas_task *task, - enum service_response *response_ptr, - enum exec_status *status_ptr, - enum isci_completion_selection *complete_to_host_ptr) -{ - unsigned int cstatus; - - cstatus = request->scu_status; - - dev_dbg(&request->isci_host->pdev->dev, - "%s: %p SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR " - "- controller status = 0x%x\n", - __func__, request, cstatus); - - /* Decode the controller-specific errors; most - * important is to recognize those conditions in which - * the target may still have a task outstanding that - * must be aborted. - * - * Note that there are SCU completion codes being - * named in the decode below for which SCIC has already - * done work to handle them in a way other than as - * a controller-specific completion code; these are left - * in the decode below for completeness sake. - */ - switch (cstatus) { - case SCU_TASK_DONE_DMASETUP_DIRERR: - /* Also SCU_TASK_DONE_SMP_FRM_TYPE_ERR: */ - case SCU_TASK_DONE_XFERCNT_ERR: - /* Also SCU_TASK_DONE_SMP_UFI_ERR: */ - if (task->task_proto == SAS_PROTOCOL_SMP) { - /* SCU_TASK_DONE_SMP_UFI_ERR == Task Done. */ - *response_ptr = SAS_TASK_COMPLETE; - - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - *status_ptr = SAS_DEVICE_UNKNOWN; - else - *status_ptr = SAS_ABORTED_TASK; - - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = - isci_perform_normal_io_completion; - } else { - /* Task in the target is not done. */ - *response_ptr = SAS_TASK_UNDELIVERED; - - if (!idev) - *status_ptr = SAS_DEVICE_UNKNOWN; - else - *status_ptr = SAM_STAT_TASK_ABORTED; - - clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = - isci_perform_error_io_completion; - } - - break; - - case SCU_TASK_DONE_CRC_ERR: - case SCU_TASK_DONE_NAK_CMD_ERR: - case SCU_TASK_DONE_EXCESS_DATA: - case SCU_TASK_DONE_UNEXP_FIS: - /* Also SCU_TASK_DONE_UNEXP_RESP: */ - case SCU_TASK_DONE_VIIT_ENTRY_NV: /* TODO - conditions? */ - case SCU_TASK_DONE_IIT_ENTRY_NV: /* TODO - conditions? */ - case SCU_TASK_DONE_RNCNV_OUTBOUND: /* TODO - conditions? */ - /* These are conditions in which the target - * has completed the task, so that no cleanup - * is necessary. - */ - *response_ptr = SAS_TASK_COMPLETE; - - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - *status_ptr = SAS_DEVICE_UNKNOWN; - else - *status_ptr = SAS_ABORTED_TASK; - - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = isci_perform_normal_io_completion; - break; - - - /* Note that the only open reject completion codes seen here will be - * abandon-class codes; all others are automatically retried in the SCU. - */ - case SCU_TASK_OPEN_REJECT_WRONG_DESTINATION: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_WRONG_DEST); - break; - - case SCU_TASK_OPEN_REJECT_ZONE_VIOLATION: - - /* Note - the return of AB0 will change when - * libsas implements detection of zone violations. - */ - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB0); - break; - - case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB1); - break; - - case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB2); - break; - - case SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_RESV_AB3); - break; - - case SCU_TASK_OPEN_REJECT_BAD_DESTINATION: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_BAD_DEST); - break; - - case SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_STP_NORES); - break; - - case SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_EPROTO); - break; - - case SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED: - - isci_request_set_open_reject_status( - request, task, response_ptr, status_ptr, - complete_to_host_ptr, SAS_OREJ_CONN_RATE); - break; - - case SCU_TASK_DONE_LL_R_ERR: - /* Also SCU_TASK_DONE_ACK_NAK_TO: */ - case SCU_TASK_DONE_LL_PERR: - case SCU_TASK_DONE_LL_SY_TERM: - /* Also SCU_TASK_DONE_NAK_ERR:*/ - case SCU_TASK_DONE_LL_LF_TERM: - /* Also SCU_TASK_DONE_DATA_LEN_ERR: */ - case SCU_TASK_DONE_LL_ABORT_ERR: - case SCU_TASK_DONE_SEQ_INV_TYPE: - /* Also SCU_TASK_DONE_UNEXP_XR: */ - case SCU_TASK_DONE_XR_IU_LEN_ERR: - case SCU_TASK_DONE_INV_FIS_LEN: - /* Also SCU_TASK_DONE_XR_WD_LEN: */ - case SCU_TASK_DONE_SDMA_ERR: - case SCU_TASK_DONE_OFFSET_ERR: - case SCU_TASK_DONE_MAX_PLD_ERR: - case SCU_TASK_DONE_LF_ERR: - case SCU_TASK_DONE_SMP_RESP_TO_ERR: /* Escalate to dev reset? */ - case SCU_TASK_DONE_SMP_LL_RX_ERR: - case SCU_TASK_DONE_UNEXP_DATA: - case SCU_TASK_DONE_UNEXP_SDBFIS: - case SCU_TASK_DONE_REG_ERR: - case SCU_TASK_DONE_SDB_ERR: - case SCU_TASK_DONE_TASK_ABORT: - default: - /* Task in the target is not done. */ - *response_ptr = SAS_TASK_UNDELIVERED; - *status_ptr = SAM_STAT_TASK_ABORTED; - - if (task->task_proto == SAS_PROTOCOL_SMP) { - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = isci_perform_normal_io_completion; - } else { - clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - *complete_to_host_ptr = isci_perform_error_io_completion; - } - break; - } -} - -/** - * isci_task_save_for_upper_layer_completion() - This function saves the - * request for later completion to the upper layer driver. - * @host: This parameter is a pointer to the host on which the the request - * should be queued (either as an error or success). - * @request: This parameter is the completed request. - * @response: This parameter is the response code for the completed task. - * @status: This parameter is the status code for the completed task. - * - * none. - */ -static void isci_task_save_for_upper_layer_completion( - struct isci_host *host, - struct isci_request *request, - enum service_response response, - enum exec_status status, - enum isci_completion_selection task_notification_selection) -{ - struct sas_task *task = isci_request_access_task(request); - - task_notification_selection - = isci_task_set_completion_status(task, response, status, - task_notification_selection); - - /* Tasks aborted specifically by a call to the lldd_abort_task - * function should not be completed to the host in the regular path. - */ - switch (task_notification_selection) { - - case isci_perform_normal_io_completion: - /* Normal notification (task_done) */ - - /* Add to the completed list. */ - list_add(&request->completed_node, - &host->requests_to_complete); - - /* Take the request off the device's pending request list. */ - list_del_init(&request->dev_node); - break; - - case isci_perform_aborted_io_completion: - /* No notification to libsas because this request is - * already in the abort path. - */ - /* Wake up whatever process was waiting for this - * request to complete. - */ - WARN_ON(request->io_request_completion == NULL); - - if (request->io_request_completion != NULL) { - - /* Signal whoever is waiting that this - * request is complete. - */ - complete(request->io_request_completion); - } - break; - - case isci_perform_error_io_completion: - /* Use sas_task_abort */ - /* Add to the aborted list. */ - list_add(&request->completed_node, - &host->requests_to_errorback); - break; - - default: - /* Add to the error to libsas list. */ - list_add(&request->completed_node, - &host->requests_to_errorback); - break; - } - dev_dbg(&host->pdev->dev, - "%s: %d - task = %p, response=%d (%d), status=%d (%d)\n", - __func__, task_notification_selection, task, - (task) ? task->task_status.resp : 0, response, - (task) ? task->task_status.stat : 0, status); -} - -static void isci_process_stp_response(struct sas_task *task, struct dev_to_host_fis *fis) -{ - struct task_status_struct *ts = &task->task_status; - struct ata_task_resp *resp = (void *)&ts->buf[0]; - - resp->frame_len = sizeof(*fis); - memcpy(resp->ending_fis, fis, sizeof(*fis)); - ts->buf_valid_size = sizeof(*resp); - - /* If the device fault bit is set in the status register, then - * set the sense data and return. - */ - if (fis->status & ATA_DF) - ts->stat = SAS_PROTO_RESPONSE; - else if (fis->status & ATA_ERR) - ts->stat = SAM_STAT_CHECK_CONDITION; - else - ts->stat = SAM_STAT_GOOD; - - ts->resp = SAS_TASK_COMPLETE; -} - -static void isci_request_io_request_complete(struct isci_host *ihost, - struct isci_request *request, - enum sci_io_status completion_status) -{ - struct sas_task *task = isci_request_access_task(request); - struct ssp_response_iu *resp_iu; - unsigned long task_flags; - struct isci_remote_device *idev = request->target_device; - enum service_response response = SAS_TASK_UNDELIVERED; - enum exec_status status = SAS_ABORTED_TASK; - enum isci_request_status request_status; - enum isci_completion_selection complete_to_host - = isci_perform_normal_io_completion; - - dev_dbg(&ihost->pdev->dev, - "%s: request = %p, task = %p,\n" - "task->data_dir = %d completion_status = 0x%x\n", - __func__, - request, - task, - task->data_dir, - completion_status); - - spin_lock(&request->state_lock); - request_status = request->status; - - /* Decode the request status. Note that if the request has been - * aborted by a task management function, we don't care - * what the status is. - */ - switch (request_status) { - - case aborted: - /* "aborted" indicates that the request was aborted by a task - * management function, since once a task management request is - * perfomed by the device, the request only completes because - * of the subsequent driver terminate. - * - * Aborted also means an external thread is explicitly managing - * this request, so that we do not complete it up the stack. - * - * The target is still there (since the TMF was successful). - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = SAS_TASK_COMPLETE; - - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; - - complete_to_host = isci_perform_aborted_io_completion; - /* This was an aborted request. */ - - spin_unlock(&request->state_lock); - break; - - case aborting: - /* aborting means that the task management function tried and - * failed to abort the request. We need to note the request - * as SAS_TASK_UNDELIVERED, so that the scsi mid layer marks the - * target as down. - * - * Aborting also means an external thread is explicitly managing - * this request, so that we do not complete it up the stack. - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = SAS_TASK_UNDELIVERED; - - if (!idev) - /* The device has been /is being stopped. Note that - * we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_PHY_DOWN; - - complete_to_host = isci_perform_aborted_io_completion; - - /* This was an aborted request. */ - - spin_unlock(&request->state_lock); - break; - - case terminating: - - /* This was an terminated request. This happens when - * the I/O is being terminated because of an action on - * the device (reset, tear down, etc.), and the I/O needs - * to be completed up the stack. - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = SAS_TASK_UNDELIVERED; - - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; - - complete_to_host = isci_perform_aborted_io_completion; - - /* This was a terminated request. */ - - spin_unlock(&request->state_lock); - break; - - case dead: - /* This was a terminated request that timed-out during the - * termination process. There is no task to complete to - * libsas. - */ - complete_to_host = isci_perform_normal_io_completion; - spin_unlock(&request->state_lock); - break; - - default: - - /* The request is done from an SCU HW perspective. */ - request->status = completed; - - spin_unlock(&request->state_lock); - - /* This is an active request being completed from the core. */ - switch (completion_status) { - - case SCI_IO_FAILURE_RESPONSE_VALID: - dev_dbg(&ihost->pdev->dev, - "%s: SCI_IO_FAILURE_RESPONSE_VALID (%p/%p)\n", - __func__, - request, - task); - - if (sas_protocol_ata(task->task_proto)) { - isci_process_stp_response(task, &request->stp.rsp); - } else if (SAS_PROTOCOL_SSP == task->task_proto) { - - /* crack the iu response buffer. */ - resp_iu = &request->ssp.rsp; - isci_request_process_response_iu(task, resp_iu, - &ihost->pdev->dev); - - } else if (SAS_PROTOCOL_SMP == task->task_proto) { - - dev_err(&ihost->pdev->dev, - "%s: SCI_IO_FAILURE_RESPONSE_VALID: " - "SAS_PROTOCOL_SMP protocol\n", - __func__); - - } else - dev_err(&ihost->pdev->dev, - "%s: unknown protocol\n", __func__); - - /* use the task status set in the task struct by the - * isci_request_process_response_iu call. - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = task->task_status.resp; - status = task->task_status.stat; - break; - - case SCI_IO_SUCCESS: - case SCI_IO_SUCCESS_IO_DONE_EARLY: - - response = SAS_TASK_COMPLETE; - status = SAM_STAT_GOOD; - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - - if (completion_status == SCI_IO_SUCCESS_IO_DONE_EARLY) { - - /* This was an SSP / STP / SATA transfer. - * There is a possibility that less data than - * the maximum was transferred. - */ - u32 transferred_length = sci_req_tx_bytes(request); - - task->task_status.residual - = task->total_xfer_len - transferred_length; - - /* If there were residual bytes, call this an - * underrun. - */ - if (task->task_status.residual != 0) - status = SAS_DATA_UNDERRUN; - - dev_dbg(&ihost->pdev->dev, - "%s: SCI_IO_SUCCESS_IO_DONE_EARLY %d\n", - __func__, - status); - - } else - dev_dbg(&ihost->pdev->dev, - "%s: SCI_IO_SUCCESS\n", - __func__); - - break; - - case SCI_IO_FAILURE_TERMINATED: - dev_dbg(&ihost->pdev->dev, - "%s: SCI_IO_FAILURE_TERMINATED (%p/%p)\n", - __func__, - request, - task); - - /* The request was terminated explicitly. No handling - * is needed in the SCSI error handler path. - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - response = SAS_TASK_UNDELIVERED; - - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; - - complete_to_host = isci_perform_normal_io_completion; - break; - - case SCI_FAILURE_CONTROLLER_SPECIFIC_IO_ERR: - - isci_request_handle_controller_specific_errors( - idev, request, task, &response, &status, - &complete_to_host); - - break; - - case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: - /* This is a special case, in that the I/O completion - * is telling us that the device needs a reset. - * In order for the device reset condition to be - * noticed, the I/O has to be handled in the error - * handler. Set the reset flag and cause the - * SCSI error thread to be scheduled. - */ - spin_lock_irqsave(&task->task_state_lock, task_flags); - task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; - spin_unlock_irqrestore(&task->task_state_lock, task_flags); - - /* Fail the I/O. */ - response = SAS_TASK_UNDELIVERED; - status = SAM_STAT_TASK_ABORTED; - - complete_to_host = isci_perform_error_io_completion; - clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - break; - - case SCI_FAILURE_RETRY_REQUIRED: - - /* Fail the I/O so it can be retried. */ - response = SAS_TASK_UNDELIVERED; - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; - - complete_to_host = isci_perform_normal_io_completion; - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - break; - - - default: - /* Catch any otherwise unhandled error codes here. */ - dev_dbg(&ihost->pdev->dev, - "%s: invalid completion code: 0x%x - " - "isci_request = %p\n", - __func__, completion_status, request); - - response = SAS_TASK_UNDELIVERED; - - /* See if the device has been/is being stopped. Note - * that we ignore the quiesce state, since we are - * concerned about the actual device state. - */ - if (!idev) - status = SAS_DEVICE_UNKNOWN; - else - status = SAS_ABORTED_TASK; - - if (SAS_PROTOCOL_SMP == task->task_proto) { - set_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - complete_to_host = isci_perform_normal_io_completion; - } else { - clear_bit(IREQ_COMPLETE_IN_TARGET, &request->flags); - complete_to_host = isci_perform_error_io_completion; - } - break; - } - break; - } - - switch (task->task_proto) { - case SAS_PROTOCOL_SSP: - if (task->data_dir == DMA_NONE) - break; - if (task->num_scatter == 0) - /* 0 indicates a single dma address */ - dma_unmap_single(&ihost->pdev->dev, - request->zero_scatter_daddr, - task->total_xfer_len, task->data_dir); - else /* unmap the sgl dma addresses */ - dma_unmap_sg(&ihost->pdev->dev, task->scatter, - request->num_sg_entries, task->data_dir); - break; - case SAS_PROTOCOL_SMP: { - struct scatterlist *sg = &task->smp_task.smp_req; - struct smp_req *smp_req; - void *kaddr; - - dma_unmap_sg(&ihost->pdev->dev, sg, 1, DMA_TO_DEVICE); - - /* need to swab it back in case the command buffer is re-used */ - kaddr = kmap_atomic(sg_page(sg)); - smp_req = kaddr + sg->offset; - sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32)); - kunmap_atomic(kaddr); - break; - } - default: - break; - } - - /* Put the completed request on the correct list */ - isci_task_save_for_upper_layer_completion(ihost, request, response, - status, complete_to_host - ); - - /* complete the io request to the core. */ - sci_controller_complete_io(ihost, request->target_device, request); - - /* set terminated handle so it cannot be completed or - * terminated again, and to cause any calls into abort - * task to recognize the already completed case. - */ - set_bit(IREQ_TERMINATED, &request->flags); -} - -static void sci_request_started_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_request *ireq = container_of(sm, typeof(*ireq), sm); - struct domain_device *dev = ireq->target_device->domain_dev; - enum sci_base_request_states state; - struct sas_task *task; - - /* XXX as hch said always creating an internal sas_task for tmf - * requests would simplify the driver - */ - task = (test_bit(IREQ_TMF, &ireq->flags)) ? NULL : isci_request_access_task(ireq); - - /* all unaccelerated request types (non ssp or ncq) handled with - * substates - */ - if (!task && dev->dev_type == SAS_END_DEV) { - state = SCI_REQ_TASK_WAIT_TC_COMP; - } else if (task && task->task_proto == SAS_PROTOCOL_SMP) { - state = SCI_REQ_SMP_WAIT_RESP; - } else if (task && sas_protocol_ata(task->task_proto) && - !task->ata_task.use_ncq) { - if (dev->sata_dev.command_set == ATAPI_COMMAND_SET && - task->ata_task.fis.command == ATA_CMD_PACKET) { - state = SCI_REQ_ATAPI_WAIT_H2D; - } else if (task->data_dir == DMA_NONE) { - state = SCI_REQ_STP_NON_DATA_WAIT_H2D; - } else if (task->ata_task.dma_xfer) { - state = SCI_REQ_STP_UDMA_WAIT_TC_COMP; - } else /* PIO */ { - state = SCI_REQ_STP_PIO_WAIT_H2D; - } - } else { - /* SSP or NCQ are fully accelerated, no substates */ - return; - } - sci_change_state(sm, state); -} - -static void sci_request_completed_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_request *ireq = container_of(sm, typeof(*ireq), sm); - struct isci_host *ihost = ireq->owning_controller; - - /* Tell the SCI_USER that the IO request is complete */ - if (!test_bit(IREQ_TMF, &ireq->flags)) - isci_request_io_request_complete(ihost, ireq, - ireq->sci_status); - else - isci_task_request_complete(ihost, ireq, ireq->sci_status); -} - -static void sci_request_aborting_state_enter(struct sci_base_state_machine *sm) -{ - struct isci_request *ireq = container_of(sm, typeof(*ireq), sm); - - /* Setting the abort bit in the Task Context is required by the silicon. */ - ireq->tc->abort = 1; -} - -static void sci_stp_request_started_non_data_await_h2d_completion_enter(struct sci_base_state_machine *sm) -{ - struct isci_request *ireq = container_of(sm, typeof(*ireq), sm); - - ireq->target_device->working_request = ireq; -} - -static void sci_stp_request_started_pio_await_h2d_completion_enter(struct sci_base_state_machine *sm) -{ - struct isci_request *ireq = container_of(sm, typeof(*ireq), sm); - - ireq->target_device->working_request = ireq; -} - -static const struct sci_base_state sci_request_state_table[] = { - [SCI_REQ_INIT] = { }, - [SCI_REQ_CONSTRUCTED] = { }, - [SCI_REQ_STARTED] = { - .enter_state = sci_request_started_state_enter, - }, - [SCI_REQ_STP_NON_DATA_WAIT_H2D] = { - .enter_state = sci_stp_request_started_non_data_await_h2d_completion_enter, - }, - [SCI_REQ_STP_NON_DATA_WAIT_D2H] = { }, - [SCI_REQ_STP_PIO_WAIT_H2D] = { - .enter_state = sci_stp_request_started_pio_await_h2d_completion_enter, - }, - [SCI_REQ_STP_PIO_WAIT_FRAME] = { }, - [SCI_REQ_STP_PIO_DATA_IN] = { }, - [SCI_REQ_STP_PIO_DATA_OUT] = { }, - [SCI_REQ_STP_UDMA_WAIT_TC_COMP] = { }, - [SCI_REQ_STP_UDMA_WAIT_D2H] = { }, - [SCI_REQ_TASK_WAIT_TC_COMP] = { }, - [SCI_REQ_TASK_WAIT_TC_RESP] = { }, - [SCI_REQ_SMP_WAIT_RESP] = { }, - [SCI_REQ_SMP_WAIT_TC_COMP] = { }, - [SCI_REQ_ATAPI_WAIT_H2D] = { }, - [SCI_REQ_ATAPI_WAIT_PIO_SETUP] = { }, - [SCI_REQ_ATAPI_WAIT_D2H] = { }, - [SCI_REQ_ATAPI_WAIT_TC_COMP] = { }, - [SCI_REQ_COMPLETED] = { - .enter_state = sci_request_completed_state_enter, - }, - [SCI_REQ_ABORTING] = { - .enter_state = sci_request_aborting_state_enter, - }, - [SCI_REQ_FINAL] = { }, -}; - -static void -sci_general_request_construct(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - sci_init_sm(&ireq->sm, sci_request_state_table, SCI_REQ_INIT); - - ireq->target_device = idev; - ireq->protocol = SCIC_NO_PROTOCOL; - ireq->saved_rx_frame_index = SCU_INVALID_FRAME_INDEX; - - ireq->sci_status = SCI_SUCCESS; - ireq->scu_status = 0; - ireq->post_context = 0xFFFFFFFF; -} - -static enum sci_status -sci_io_request_construct(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *ireq) -{ - struct domain_device *dev = idev->domain_dev; - enum sci_status status = SCI_SUCCESS; - - /* Build the common part of the request */ - sci_general_request_construct(ihost, idev, ireq); - - if (idev->rnc.remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) - return SCI_FAILURE_INVALID_REMOTE_DEVICE; - - if (dev->dev_type == SAS_END_DEV) - /* pass */; - else if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) - memset(&ireq->stp.cmd, 0, sizeof(ireq->stp.cmd)); - else if (dev_is_expander(dev)) - /* pass */; - else - return SCI_FAILURE_UNSUPPORTED_PROTOCOL; - - memset(ireq->tc, 0, offsetof(struct scu_task_context, sgl_pair_ab)); - - return status; -} - -enum sci_status sci_task_request_construct(struct isci_host *ihost, - struct isci_remote_device *idev, - u16 io_tag, struct isci_request *ireq) -{ - struct domain_device *dev = idev->domain_dev; - enum sci_status status = SCI_SUCCESS; - - /* Build the common part of the request */ - sci_general_request_construct(ihost, idev, ireq); - - if (dev->dev_type == SAS_END_DEV || - dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTOCOL_STP)) { - set_bit(IREQ_TMF, &ireq->flags); - memset(ireq->tc, 0, sizeof(struct scu_task_context)); - } else - status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; - - return status; -} - -static enum sci_status isci_request_ssp_request_construct( - struct isci_request *request) -{ - enum sci_status status; - - dev_dbg(&request->isci_host->pdev->dev, - "%s: request = %p\n", - __func__, - request); - status = sci_io_request_construct_basic_ssp(request); - return status; -} - -static enum sci_status isci_request_stp_request_construct(struct isci_request *ireq) -{ - struct sas_task *task = isci_request_access_task(ireq); - struct host_to_dev_fis *fis = &ireq->stp.cmd; - struct ata_queued_cmd *qc = task->uldd_task; - enum sci_status status; - - dev_dbg(&ireq->isci_host->pdev->dev, - "%s: ireq = %p\n", - __func__, - ireq); - - memcpy(fis, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); - if (!task->ata_task.device_control_reg_update) - fis->flags |= 0x80; - fis->flags &= 0xF0; - - status = sci_io_request_construct_basic_sata(ireq); - - if (qc && (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ)) { - fis->sector_count = qc->tag << 3; - ireq->tc->type.stp.ncq_tag = qc->tag; - } - - return status; -} - -static enum sci_status -sci_io_request_construct_smp(struct device *dev, - struct isci_request *ireq, - struct sas_task *task) -{ - struct scatterlist *sg = &task->smp_task.smp_req; - struct isci_remote_device *idev; - struct scu_task_context *task_context; - struct isci_port *iport; - struct smp_req *smp_req; - void *kaddr; - u8 req_len; - u32 cmd; - - kaddr = kmap_atomic(sg_page(sg)); - smp_req = kaddr + sg->offset; - /* - * Look at the SMP requests' header fields; for certain SAS 1.x SMP - * functions under SAS 2.0, a zero request length really indicates - * a non-zero default length. - */ - if (smp_req->req_len == 0) { - switch (smp_req->func) { - case SMP_DISCOVER: - case SMP_REPORT_PHY_ERR_LOG: - case SMP_REPORT_PHY_SATA: - case SMP_REPORT_ROUTE_INFO: - smp_req->req_len = 2; - break; - case SMP_CONF_ROUTE_INFO: - case SMP_PHY_CONTROL: - case SMP_PHY_TEST_FUNCTION: - smp_req->req_len = 9; - break; - /* Default - zero is a valid default for 2.0. */ - } - } - req_len = smp_req->req_len; - sci_swab32_cpy(smp_req, smp_req, sg->length / sizeof(u32)); - cmd = *(u32 *) smp_req; - kunmap_atomic(kaddr); - - if (!dma_map_sg(dev, sg, 1, DMA_TO_DEVICE)) - return SCI_FAILURE; - - ireq->protocol = SCIC_SMP_PROTOCOL; - - /* byte swap the smp request. */ - - task_context = ireq->tc; - - idev = ireq->target_device; - iport = idev->owning_port; - - /* - * Fill in the TC with the its required data - * 00h - */ - task_context->priority = 0; - task_context->initiator_request = 1; - task_context->connection_rate = idev->connection_rate; - task_context->protocol_engine_index = ISCI_PEG; - task_context->logical_port_index = iport->physical_port_index; - task_context->protocol_type = SCU_TASK_CONTEXT_PROTOCOL_SMP; - task_context->abort = 0; - task_context->valid = SCU_TASK_CONTEXT_VALID; - task_context->context_type = SCU_TASK_CONTEXT_TYPE; - - /* 04h */ - task_context->remote_node_index = idev->rnc.remote_node_index; - task_context->command_code = 0; - task_context->task_type = SCU_TASK_TYPE_SMP_REQUEST; - - /* 08h */ - task_context->link_layer_control = 0; - task_context->do_not_dma_ssp_good_response = 1; - task_context->strict_ordering = 0; - task_context->control_frame = 1; - task_context->timeout_enable = 0; - task_context->block_guard_enable = 0; - - /* 0ch */ - task_context->address_modifier = 0; - - /* 10h */ - task_context->ssp_command_iu_length = req_len; - - /* 14h */ - task_context->transfer_length_bytes = 0; - - /* - * 18h ~ 30h, protocol specific - * since commandIU has been build by framework at this point, we just - * copy the frist DWord from command IU to this location. */ - memcpy(&task_context->type.smp, &cmd, sizeof(u32)); - - /* - * 40h - * "For SMP you could program it to zero. We would prefer that way - * so that done code will be consistent." - Venki - */ - task_context->task_phase = 0; - - ireq->post_context = (SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC | - (ISCI_PEG << SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT) | - (iport->physical_port_index << - SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT) | - ISCI_TAG_TCI(ireq->io_tag)); - /* - * Copy the physical address for the command buffer to the SCU Task - * Context command buffer should not contain command header. - */ - task_context->command_iu_upper = upper_32_bits(sg_dma_address(sg)); - task_context->command_iu_lower = lower_32_bits(sg_dma_address(sg) + sizeof(u32)); - - /* SMP response comes as UF, so no need to set response IU address. */ - task_context->response_iu_upper = 0; - task_context->response_iu_lower = 0; - - sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED); - - return SCI_SUCCESS; -} - -/* - * isci_smp_request_build() - This function builds the smp request. - * @ireq: This parameter points to the isci_request allocated in the - * request construct function. - * - * SCI_SUCCESS on successfull completion, or specific failure code. - */ -static enum sci_status isci_smp_request_build(struct isci_request *ireq) -{ - struct sas_task *task = isci_request_access_task(ireq); - struct device *dev = &ireq->isci_host->pdev->dev; - enum sci_status status = SCI_FAILURE; - - status = sci_io_request_construct_smp(dev, ireq, task); - if (status != SCI_SUCCESS) - dev_dbg(&ireq->isci_host->pdev->dev, - "%s: failed with status = %d\n", - __func__, - status); - - return status; -} - -/** - * isci_io_request_build() - This function builds the io request object. - * @ihost: This parameter specifies the ISCI host object - * @request: This parameter points to the isci_request object allocated in the - * request construct function. - * @sci_device: This parameter is the handle for the sci core's remote device - * object that is the destination for this request. - * - * SCI_SUCCESS on successfull completion, or specific failure code. - */ -static enum sci_status isci_io_request_build(struct isci_host *ihost, - struct isci_request *request, - struct isci_remote_device *idev) -{ - enum sci_status status = SCI_SUCCESS; - struct sas_task *task = isci_request_access_task(request); - - dev_dbg(&ihost->pdev->dev, - "%s: idev = 0x%p; request = %p, " - "num_scatter = %d\n", - __func__, - idev, - request, - task->num_scatter); - - /* map the sgl addresses, if present. - * libata does the mapping for sata devices - * before we get the request. - */ - if (task->num_scatter && - !sas_protocol_ata(task->task_proto) && - !(SAS_PROTOCOL_SMP & task->task_proto)) { - - request->num_sg_entries = dma_map_sg( - &ihost->pdev->dev, - task->scatter, - task->num_scatter, - task->data_dir - ); - - if (request->num_sg_entries == 0) - return SCI_FAILURE_INSUFFICIENT_RESOURCES; - } - - status = sci_io_request_construct(ihost, idev, request); - - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: failed request construct\n", - __func__); - return SCI_FAILURE; - } - - switch (task->task_proto) { - case SAS_PROTOCOL_SMP: - status = isci_smp_request_build(request); - break; - case SAS_PROTOCOL_SSP: - status = isci_request_ssp_request_construct(request); - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - status = isci_request_stp_request_construct(request); - break; - default: - dev_dbg(&ihost->pdev->dev, - "%s: unknown protocol\n", __func__); - return SCI_FAILURE; - } - - return SCI_SUCCESS; -} - -static struct isci_request *isci_request_from_tag(struct isci_host *ihost, u16 tag) -{ - struct isci_request *ireq; - - ireq = ihost->reqs[ISCI_TAG_TCI(tag)]; - ireq->io_tag = tag; - ireq->io_request_completion = NULL; - ireq->flags = 0; - ireq->num_sg_entries = 0; - INIT_LIST_HEAD(&ireq->completed_node); - INIT_LIST_HEAD(&ireq->dev_node); - isci_request_change_state(ireq, allocated); - - return ireq; -} - -static struct isci_request *isci_io_request_from_tag(struct isci_host *ihost, - struct sas_task *task, - u16 tag) -{ - struct isci_request *ireq; - - ireq = isci_request_from_tag(ihost, tag); - ireq->ttype_ptr.io_task_ptr = task; - clear_bit(IREQ_TMF, &ireq->flags); - task->lldd_task = ireq; - - return ireq; -} - -struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost, - struct isci_tmf *isci_tmf, - u16 tag) -{ - struct isci_request *ireq; - - ireq = isci_request_from_tag(ihost, tag); - ireq->ttype_ptr.tmf_task_ptr = isci_tmf; - set_bit(IREQ_TMF, &ireq->flags); - - return ireq; -} - -int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev, - struct sas_task *task, u16 tag) -{ - enum sci_status status = SCI_FAILURE_UNSUPPORTED_PROTOCOL; - struct isci_request *ireq; - unsigned long flags; - int ret = 0; - - /* do common allocation and init of request object. */ - ireq = isci_io_request_from_tag(ihost, task, tag); - - status = isci_io_request_build(ihost, ireq, idev); - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: request_construct failed - status = 0x%x\n", - __func__, - status); - return status; - } - - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (test_bit(IDEV_IO_NCQERROR, &idev->flags)) { - - if (isci_task_is_ncq_recovery(task)) { - - /* The device is in an NCQ recovery state. Issue the - * request on the task side. Note that it will - * complete on the I/O request side because the - * request was built that way (ie. - * ireq->is_task_management_request is false). - */ - status = sci_controller_start_task(ihost, - idev, - ireq); - } else { - status = SCI_FAILURE; - } - } else { - /* send the request, let the core assign the IO TAG. */ - status = sci_controller_start_io(ihost, idev, - ireq); - } - - if (status != SCI_SUCCESS && - status != SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { - dev_dbg(&ihost->pdev->dev, - "%s: failed request start (0x%x)\n", - __func__, status); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - return status; - } - - /* Either I/O started OK, or the core has signaled that - * the device needs a target reset. - * - * In either case, hold onto the I/O for later. - * - * Update it's status and add it to the list in the - * remote device object. - */ - list_add(&ireq->dev_node, &idev->reqs_in_process); - - if (status == SCI_SUCCESS) { - isci_request_change_state(ireq, started); - } else { - /* The request did not really start in the - * hardware, so clear the request handle - * here so no terminations will be done. - */ - set_bit(IREQ_TERMINATED, &ireq->flags); - isci_request_change_state(ireq, completed); - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (status == - SCI_FAILURE_REMOTE_DEVICE_RESET_REQUIRED) { - /* Signal libsas that we need the SCSI error - * handler thread to work on this I/O and that - * we want a device reset. - */ - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags |= SAS_TASK_NEED_DEV_RESET; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - /* Cause this task to be scheduled in the SCSI error - * handler thread. - */ - sas_task_abort(task); - - /* Change the status, since we are holding - * the I/O until it is managed by the SCSI - * error handler. - */ - status = SCI_SUCCESS; - } - - return ret; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/request.h b/ANDROID_3.4.5/drivers/scsi/isci/request.h deleted file mode 100644 index 057f2378..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/request.h +++ /dev/null @@ -1,425 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _ISCI_REQUEST_H_ -#define _ISCI_REQUEST_H_ - -#include "isci.h" -#include "host.h" -#include "scu_task_context.h" - -/** - * struct isci_request_status - This enum defines the possible states of an I/O - * request. - * - * - */ -enum isci_request_status { - unallocated = 0x00, - allocated = 0x01, - started = 0x02, - completed = 0x03, - aborting = 0x04, - aborted = 0x05, - terminating = 0x06, - dead = 0x07 -}; - -enum sci_request_protocol { - SCIC_NO_PROTOCOL, - SCIC_SMP_PROTOCOL, - SCIC_SSP_PROTOCOL, - SCIC_STP_PROTOCOL -}; /* XXX remove me, use sas_task.{dev|task_proto} instead */; - -/** - * isci_stp_request - extra request infrastructure to handle pio/atapi protocol - * @pio_len - number of bytes requested at PIO setup - * @status - pio setup ending status value to tell us if we need - * to wait for another fis or if the transfer is complete. Upon - * receipt of a d2h fis this will be the status field of that fis. - * @sgl - track pio transfer progress as we iterate through the sgl - */ -struct isci_stp_request { - u32 pio_len; - u8 status; - - struct isci_stp_pio_sgl { - int index; - u8 set; - u32 offset; - } sgl; -}; - -struct isci_request { - enum isci_request_status status; - #define IREQ_COMPLETE_IN_TARGET 0 - #define IREQ_TERMINATED 1 - #define IREQ_TMF 2 - #define IREQ_ACTIVE 3 - unsigned long flags; - /* XXX kill ttype and ttype_ptr, allocate full sas_task */ - union ttype_ptr_union { - struct sas_task *io_task_ptr; /* When ttype==io_task */ - struct isci_tmf *tmf_task_ptr; /* When ttype==tmf_task */ - } ttype_ptr; - struct isci_host *isci_host; - /* For use in the requests_to_{complete|abort} lists: */ - struct list_head completed_node; - /* For use in the reqs_in_process list: */ - struct list_head dev_node; - spinlock_t state_lock; - dma_addr_t request_daddr; - dma_addr_t zero_scatter_daddr; - unsigned int num_sg_entries; - /* Note: "io_request_completion" is completed in two different ways - * depending on whether this is a TMF or regular request. - * - TMF requests are completed in the thread that started them; - * - regular requests are completed in the request completion callback - * function. - * This difference in operation allows the aborter of a TMF request - * to be sure that once the TMF request completes, the I/O that the - * TMF was aborting is guaranteed to have completed. - * - * XXX kill io_request_completion - */ - struct completion *io_request_completion; - struct sci_base_state_machine sm; - struct isci_host *owning_controller; - struct isci_remote_device *target_device; - u16 io_tag; - enum sci_request_protocol protocol; - u32 scu_status; /* hardware result */ - u32 sci_status; /* upper layer disposition */ - u32 post_context; - struct scu_task_context *tc; - /* could be larger with sg chaining */ - #define SCU_SGL_SIZE ((SCI_MAX_SCATTER_GATHER_ELEMENTS + 1) / 2) - struct scu_sgl_element_pair sg_table[SCU_SGL_SIZE] __attribute__ ((aligned(32))); - /* This field is a pointer to the stored rx frame data. It is used in - * STP internal requests and SMP response frames. If this field is - * non-NULL the saved frame must be released on IO request completion. - */ - u32 saved_rx_frame_index; - - union { - struct { - union { - struct ssp_cmd_iu cmd; - struct ssp_task_iu tmf; - }; - union { - struct ssp_response_iu rsp; - u8 rsp_buf[SSP_RESP_IU_MAX_SIZE]; - }; - } ssp; - struct { - struct isci_stp_request req; - struct host_to_dev_fis cmd; - struct dev_to_host_fis rsp; - } stp; - }; -}; - -static inline struct isci_request *to_ireq(struct isci_stp_request *stp_req) -{ - struct isci_request *ireq; - - ireq = container_of(stp_req, typeof(*ireq), stp.req); - return ireq; -} - -/** - * enum sci_base_request_states - request state machine states - * - * @SCI_REQ_INIT: Simply the initial state for the base request state machine. - * - * @SCI_REQ_CONSTRUCTED: This state indicates that the request has been - * constructed. This state is entered from the INITIAL state. - * - * @SCI_REQ_STARTED: This state indicates that the request has been started. - * This state is entered from the CONSTRUCTED state. - * - * @SCI_REQ_STP_UDMA_WAIT_TC_COMP: - * @SCI_REQ_STP_UDMA_WAIT_D2H: - * @SCI_REQ_STP_NON_DATA_WAIT_H2D: - * @SCI_REQ_STP_NON_DATA_WAIT_D2H: - * - * @SCI_REQ_STP_PIO_WAIT_H2D: While in this state the IO request object is - * waiting for the TC completion notification for the H2D Register FIS - * - * @SCI_REQ_STP_PIO_WAIT_FRAME: While in this state the IO request object is - * waiting for either a PIO Setup FIS or a D2H register FIS. The type of frame - * received is based on the result of the prior frame and line conditions. - * - * @SCI_REQ_STP_PIO_DATA_IN: While in this state the IO request object is - * waiting for a DATA frame from the device. - * - * @SCI_REQ_STP_PIO_DATA_OUT: While in this state the IO request object is - * waiting to transmit the next data frame to the device. - * - * @SCI_REQ_ATAPI_WAIT_H2D: While in this state the IO request object is - * waiting for the TC completion notification for the H2D Register FIS - * - * @SCI_REQ_ATAPI_WAIT_PIO_SETUP: While in this state the IO request object is - * waiting for either a PIO Setup. - * - * @SCI_REQ_ATAPI_WAIT_D2H: The non-data IO transit to this state in this state - * after receiving TC completion. While in this state IO request object is - * waiting for D2H status frame as UF. - * - * @SCI_REQ_ATAPI_WAIT_TC_COMP: When transmitting raw frames hardware reports - * task context completion after every frame submission, so in the - * non-accelerated case we need to expect the completion for the "cdb" frame. - * - * @SCI_REQ_TASK_WAIT_TC_COMP: The AWAIT_TC_COMPLETION sub-state indicates that - * the started raw task management request is waiting for the transmission of - * the initial frame (i.e. command, task, etc.). - * - * @SCI_REQ_TASK_WAIT_TC_RESP: This sub-state indicates that the started task - * management request is waiting for the reception of an unsolicited frame - * (i.e. response IU). - * - * @SCI_REQ_SMP_WAIT_RESP: This sub-state indicates that the started task - * management request is waiting for the reception of an unsolicited frame - * (i.e. response IU). - * - * @SCI_REQ_SMP_WAIT_TC_COMP: The AWAIT_TC_COMPLETION sub-state indicates that - * the started SMP request is waiting for the transmission of the initial frame - * (i.e. command, task, etc.). - * - * @SCI_REQ_COMPLETED: This state indicates that the request has completed. - * This state is entered from the STARTED state. This state is entered from the - * ABORTING state. - * - * @SCI_REQ_ABORTING: This state indicates that the request is in the process - * of being terminated/aborted. This state is entered from the CONSTRUCTED - * state. This state is entered from the STARTED state. - * - * @SCI_REQ_FINAL: Simply the final state for the base request state machine. - */ -#define REQUEST_STATES {\ - C(REQ_INIT),\ - C(REQ_CONSTRUCTED),\ - C(REQ_STARTED),\ - C(REQ_STP_UDMA_WAIT_TC_COMP),\ - C(REQ_STP_UDMA_WAIT_D2H),\ - C(REQ_STP_NON_DATA_WAIT_H2D),\ - C(REQ_STP_NON_DATA_WAIT_D2H),\ - C(REQ_STP_PIO_WAIT_H2D),\ - C(REQ_STP_PIO_WAIT_FRAME),\ - C(REQ_STP_PIO_DATA_IN),\ - C(REQ_STP_PIO_DATA_OUT),\ - C(REQ_ATAPI_WAIT_H2D),\ - C(REQ_ATAPI_WAIT_PIO_SETUP),\ - C(REQ_ATAPI_WAIT_D2H),\ - C(REQ_ATAPI_WAIT_TC_COMP),\ - C(REQ_TASK_WAIT_TC_COMP),\ - C(REQ_TASK_WAIT_TC_RESP),\ - C(REQ_SMP_WAIT_RESP),\ - C(REQ_SMP_WAIT_TC_COMP),\ - C(REQ_COMPLETED),\ - C(REQ_ABORTING),\ - C(REQ_FINAL),\ - } -#undef C -#define C(a) SCI_##a -enum sci_base_request_states REQUEST_STATES; -#undef C -const char *req_state_name(enum sci_base_request_states state); - -enum sci_status sci_request_start(struct isci_request *ireq); -enum sci_status sci_io_request_terminate(struct isci_request *ireq); -enum sci_status -sci_io_request_event_handler(struct isci_request *ireq, - u32 event_code); -enum sci_status -sci_io_request_frame_handler(struct isci_request *ireq, - u32 frame_index); -enum sci_status -sci_task_request_terminate(struct isci_request *ireq); -extern enum sci_status -sci_request_complete(struct isci_request *ireq); -extern enum sci_status -sci_io_request_tc_completion(struct isci_request *ireq, u32 code); - -/* XXX open code in caller */ -static inline dma_addr_t -sci_io_request_get_dma_addr(struct isci_request *ireq, void *virt_addr) -{ - - char *requested_addr = (char *)virt_addr; - char *base_addr = (char *)ireq; - - BUG_ON(requested_addr < base_addr); - BUG_ON((requested_addr - base_addr) >= sizeof(*ireq)); - - return ireq->request_daddr + (requested_addr - base_addr); -} - -/** - * isci_request_change_state() - This function sets the status of the request - * object. - * @request: This parameter points to the isci_request object - * @status: This Parameter is the new status of the object - * - */ -static inline enum isci_request_status -isci_request_change_state(struct isci_request *isci_request, - enum isci_request_status status) -{ - enum isci_request_status old_state; - unsigned long flags; - - dev_dbg(&isci_request->isci_host->pdev->dev, - "%s: isci_request = %p, state = 0x%x\n", - __func__, - isci_request, - status); - - BUG_ON(isci_request == NULL); - - spin_lock_irqsave(&isci_request->state_lock, flags); - old_state = isci_request->status; - isci_request->status = status; - spin_unlock_irqrestore(&isci_request->state_lock, flags); - - return old_state; -} - -/** - * isci_request_change_started_to_newstate() - This function sets the status of - * the request object. - * @request: This parameter points to the isci_request object - * @status: This Parameter is the new status of the object - * - * state previous to any change. - */ -static inline enum isci_request_status -isci_request_change_started_to_newstate(struct isci_request *isci_request, - struct completion *completion_ptr, - enum isci_request_status newstate) -{ - enum isci_request_status old_state; - unsigned long flags; - - spin_lock_irqsave(&isci_request->state_lock, flags); - - old_state = isci_request->status; - - if (old_state == started || old_state == aborting) { - BUG_ON(isci_request->io_request_completion != NULL); - - isci_request->io_request_completion = completion_ptr; - isci_request->status = newstate; - } - - spin_unlock_irqrestore(&isci_request->state_lock, flags); - - dev_dbg(&isci_request->isci_host->pdev->dev, - "%s: isci_request = %p, old_state = 0x%x\n", - __func__, - isci_request, - old_state); - - return old_state; -} - -/** - * isci_request_change_started_to_aborted() - This function sets the status of - * the request object. - * @request: This parameter points to the isci_request object - * @completion_ptr: This parameter is saved as the kernel completion structure - * signalled when the old request completes. - * - * state previous to any change. - */ -static inline enum isci_request_status -isci_request_change_started_to_aborted(struct isci_request *isci_request, - struct completion *completion_ptr) -{ - return isci_request_change_started_to_newstate(isci_request, - completion_ptr, - aborted); -} - -#define isci_request_access_task(req) ((req)->ttype_ptr.io_task_ptr) - -#define isci_request_access_tmf(req) ((req)->ttype_ptr.tmf_task_ptr) - -struct isci_request *isci_tmf_request_from_tag(struct isci_host *ihost, - struct isci_tmf *isci_tmf, - u16 tag); -int isci_request_execute(struct isci_host *ihost, struct isci_remote_device *idev, - struct sas_task *task, u16 tag); -void isci_terminate_pending_requests(struct isci_host *ihost, - struct isci_remote_device *idev); -enum sci_status -sci_task_request_construct(struct isci_host *ihost, - struct isci_remote_device *idev, - u16 io_tag, - struct isci_request *ireq); -enum sci_status sci_task_request_construct_ssp(struct isci_request *ireq); -void sci_smp_request_copy_response(struct isci_request *ireq); - -static inline int isci_task_is_ncq_recovery(struct sas_task *task) -{ - return (sas_protocol_ata(task->task_proto) && - task->ata_task.fis.command == ATA_CMD_READ_LOG_EXT && - task->ata_task.fis.lbal == ATA_LOG_SATA_NCQ); - -} - -#endif /* !defined(_ISCI_REQUEST_H_) */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/sas.h b/ANDROID_3.4.5/drivers/scsi/isci/sas.h deleted file mode 100644 index dc26b4ae..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/sas.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCI_SAS_H_ -#define _SCI_SAS_H_ - -#include - -/* - * SATA FIS Types These constants depict the various SATA FIS types devined in - * the serial ATA specification. - * XXX: This needs to go into - */ -#define FIS_REGH2D 0x27 -#define FIS_REGD2H 0x34 -#define FIS_SETDEVBITS 0xA1 -#define FIS_DMA_ACTIVATE 0x39 -#define FIS_DMA_SETUP 0x41 -#define FIS_BIST_ACTIVATE 0x58 -#define FIS_PIO_SETUP 0x5F -#define FIS_DATA 0x46 - -/**************************************************************************/ -#define SSP_RESP_IU_MAX_SIZE 280 - -/* - * contents of the SSP COMMAND INFORMATION UNIT. - * For specific information on each of these individual fields please - * reference the SAS specification SSP transport layer section. - * XXX: This needs to go into - */ -struct ssp_cmd_iu { - u8 LUN[8]; - u8 add_cdb_len:6; - u8 _r_a:2; - u8 _r_b; - u8 en_fburst:1; - u8 task_prio:4; - u8 task_attr:3; - u8 _r_c; - - u8 cdb[16]; -} __packed; - -/* - * contents of the SSP TASK INFORMATION UNIT. - * For specific information on each of these individual fields please - * reference the SAS specification SSP transport layer section. - * XXX: This needs to go into - */ -struct ssp_task_iu { - u8 LUN[8]; - u8 _r_a; - u8 task_func; - u8 _r_b[4]; - u16 task_tag; - u8 _r_c[12]; -} __packed; - - -/* - * struct smp_req_phy_id - This structure defines the contents of - * an SMP Request that is comprised of the struct smp_request_header and a - * phy identifier. - * Examples: SMP_REQUEST_DISCOVER, SMP_REQUEST_REPORT_PHY_SATA. - * - * For specific information on each of these individual fields please reference - * the SAS specification. - */ -struct smp_req_phy_id { - u8 _r_a[4]; /* bytes 4-7 */ - - u8 ign_zone_grp:1; /* byte 8 */ - u8 _r_b:7; - - u8 phy_id; /* byte 9 */ - u8 _r_c; /* byte 10 */ - u8 _r_d; /* byte 11 */ -} __packed; - -/* - * struct smp_req_config_route_info - This structure defines the - * contents of an SMP Configure Route Information request. - * - * For specific information on each of these individual fields please reference - * the SAS specification. - */ -struct smp_req_conf_rtinfo { - u16 exp_change_cnt; /* bytes 4-5 */ - u8 exp_rt_idx_hi; /* byte 6 */ - u8 exp_rt_idx; /* byte 7 */ - - u8 _r_a; /* byte 8 */ - u8 phy_id; /* byte 9 */ - u16 _r_b; /* bytes 10-11 */ - - u8 _r_c:7; /* byte 12 */ - u8 dis_rt_entry:1; - u8 _r_d[3]; /* bytes 13-15 */ - - u8 rt_sas_addr[8]; /* bytes 16-23 */ - u8 _r_e[16]; /* bytes 24-39 */ -} __packed; - -/* - * struct smp_req_phycntl - This structure defines the contents of an - * SMP Phy Controller request. - * - * For specific information on each of these individual fields please reference - * the SAS specification. - */ -struct smp_req_phycntl { - u16 exp_change_cnt; /* byte 4-5 */ - - u8 _r_a[3]; /* bytes 6-8 */ - - u8 phy_id; /* byte 9 */ - u8 phy_op; /* byte 10 */ - - u8 upd_pathway:1; /* byte 11 */ - u8 _r_b:7; - - u8 _r_c[12]; /* byte 12-23 */ - - u8 att_dev_name[8]; /* byte 24-31 */ - - u8 _r_d:4; /* byte 32 */ - u8 min_linkrate:4; - - u8 _r_e:4; /* byte 33 */ - u8 max_linkrate:4; - - u8 _r_f[2]; /* byte 34-35 */ - - u8 pathway:4; /* byte 36 */ - u8 _r_g:4; - - u8 _r_h[3]; /* bytes 37-39 */ -} __packed; - -/* - * struct smp_req - This structure simply unionizes the existing request - * structures into a common request type. - * - * XXX: This data structure may need to go to scsi/sas.h - */ -struct smp_req { - u8 type; /* byte 0 */ - u8 func; /* byte 1 */ - u8 alloc_resp_len; /* byte 2 */ - u8 req_len; /* byte 3 */ - u8 req_data[0]; -} __packed; - -/* - * struct sci_sas_address - This structure depicts how a SAS address is - * represented by SCI. - * XXX convert this to u8 [SAS_ADDR_SIZE] like the rest of libsas - * - */ -struct sci_sas_address { - u32 high; - u32 low; -}; -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/isci/scu_completion_codes.h b/ANDROID_3.4.5/drivers/scsi/isci/scu_completion_codes.h deleted file mode 100644 index c8b329c6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/scu_completion_codes.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCU_COMPLETION_CODES_HEADER_ -#define _SCU_COMPLETION_CODES_HEADER_ - -/** - * This file contains the constants and macros for the SCU hardware completion - * codes. - * - * - */ - -#define SCU_COMPLETION_TYPE_SHIFT 28 -#define SCU_COMPLETION_TYPE_MASK 0x70000000 - -/** - * SCU_COMPLETION_TYPE() - - * - * This macro constructs an SCU completion type - */ -#define SCU_COMPLETION_TYPE(type) \ - ((u32)(type) << SCU_COMPLETION_TYPE_SHIFT) - -/** - * SCU_COMPLETION_TYPE() - - * - * These macros contain the SCU completion types SCU_COMPLETION_TYPE - */ -#define SCU_COMPLETION_TYPE_TASK SCU_COMPLETION_TYPE(0) -#define SCU_COMPLETION_TYPE_SDMA SCU_COMPLETION_TYPE(1) -#define SCU_COMPLETION_TYPE_UFI SCU_COMPLETION_TYPE(2) -#define SCU_COMPLETION_TYPE_EVENT SCU_COMPLETION_TYPE(3) -#define SCU_COMPLETION_TYPE_NOTIFY SCU_COMPLETION_TYPE(4) - -/** - * - * - * These constants provide the shift and mask values for the various parts of - * an SCU completion code. - */ -#define SCU_COMPLETION_STATUS_MASK 0x0FFC0000 -#define SCU_COMPLETION_TL_STATUS_MASK 0x0FC00000 -#define SCU_COMPLETION_TL_STATUS_SHIFT 22 -#define SCU_COMPLETION_SDMA_STATUS_MASK 0x003C0000 -#define SCU_COMPLETION_PEG_MASK 0x00010000 -#define SCU_COMPLETION_PORT_MASK 0x00007000 -#define SCU_COMPLETION_PE_MASK SCU_COMPLETION_PORT_MASK -#define SCU_COMPLETION_PE_SHIFT 12 -#define SCU_COMPLETION_INDEX_MASK 0x00000FFF - -/** - * SCU_GET_COMPLETION_TYPE() - - * - * This macro returns the SCU completion type. - */ -#define SCU_GET_COMPLETION_TYPE(completion_code) \ - ((completion_code) & SCU_COMPLETION_TYPE_MASK) - -/** - * SCU_GET_COMPLETION_STATUS() - - * - * This macro returns the SCU completion status. - */ -#define SCU_GET_COMPLETION_STATUS(completion_code) \ - ((completion_code) & SCU_COMPLETION_STATUS_MASK) - -/** - * SCU_GET_COMPLETION_TL_STATUS() - - * - * This macro returns the transport layer completion status. - */ -#define SCU_GET_COMPLETION_TL_STATUS(completion_code) \ - ((completion_code) & SCU_COMPLETION_TL_STATUS_MASK) - -/** - * SCU_MAKE_COMPLETION_STATUS() - - * - * This macro takes a completion code and performs the shift and mask - * operations to turn it into a completion code that can be compared to a - * SCU_GET_COMPLETION_TL_STATUS. - */ -#define SCU_MAKE_COMPLETION_STATUS(completion_code) \ - ((u32)(completion_code) << SCU_COMPLETION_TL_STATUS_SHIFT) - -/** - * SCU_NORMALIZE_COMPLETION_STATUS() - - * - * This macro takes a SCU_GET_COMPLETION_TL_STATUS and normalizes it for a - * return code. - */ -#define SCU_NORMALIZE_COMPLETION_STATUS(completion_code) \ - (\ - ((completion_code) & SCU_COMPLETION_TL_STATUS_MASK) \ - >> SCU_COMPLETION_TL_STATUS_SHIFT \ - ) - -/** - * SCU_GET_COMPLETION_SDMA_STATUS() - - * - * This macro returns the SDMA completion status. - */ -#define SCU_GET_COMPLETION_SDMA_STATUS(completion_code) \ - ((completion_code) & SCU_COMPLETION_SDMA_STATUS_MASK) - -/** - * SCU_GET_COMPLETION_PEG() - - * - * This macro returns the Protocol Engine Group from the completion code. - */ -#define SCU_GET_COMPLETION_PEG(completion_code) \ - ((completion_code) & SCU_COMPLETION_PEG_MASK) - -/** - * SCU_GET_COMPLETION_PORT() - - * - * This macro reuturns the logical port index from the completion code. - */ -#define SCU_GET_COMPLETION_PORT(completion_code) \ - ((completion_code) & SCU_COMPLETION_PORT_MASK) - -/** - * SCU_GET_PROTOCOL_ENGINE_INDEX() - - * - * This macro returns the PE index from the completion code. - */ -#define SCU_GET_PROTOCOL_ENGINE_INDEX(completion_code) \ - (((completion_code) & SCU_COMPLETION_PE_MASK) >> SCU_COMPLETION_PE_SHIFT) - -/** - * SCU_GET_COMPLETION_INDEX() - - * - * This macro returns the index of the completion which is either a TCi or an - * RNi depending on the completion type. - */ -#define SCU_GET_COMPLETION_INDEX(completion_code) \ - ((completion_code) & SCU_COMPLETION_INDEX_MASK) - -#define SCU_UNSOLICITED_FRAME_MASK 0x0FFF0000 -#define SCU_UNSOLICITED_FRAME_SHIFT 16 - -/** - * SCU_GET_FRAME_INDEX() - - * - * This macro returns a normalized frame index from an unsolicited frame - * completion. - */ -#define SCU_GET_FRAME_INDEX(completion_code) \ - (\ - ((completion_code) & SCU_UNSOLICITED_FRAME_MASK) \ - >> SCU_UNSOLICITED_FRAME_SHIFT \ - ) - -#define SCU_UNSOLICITED_FRAME_ERROR_MASK 0x00008000 - -/** - * SCU_GET_FRAME_ERROR() - - * - * This macro returns a zero (0) value if there is no frame error otherwise it - * returns non-zero (!0). - */ -#define SCU_GET_FRAME_ERROR(completion_code) \ - ((completion_code) & SCU_UNSOLICITED_FRAME_ERROR_MASK) - -/** - * - * - * These constants represent normalized completion codes which must be shifted - * 18 bits to match it with the hardware completion code. In a 16-bit compiler, - * immediate constants are 16-bit values (the size of an int). If we shift - * those by 18 bits, we completely lose the value. To ensure the value is a - * 32-bit value like we want, each immediate value must be cast to a u32. - */ -#define SCU_TASK_DONE_GOOD ((u32)0x00) -#define SCU_TASK_DONE_CRC_ERR ((u32)0x14) -#define SCU_TASK_DONE_CHECK_RESPONSE ((u32)0x14) -#define SCU_TASK_DONE_GEN_RESPONSE ((u32)0x15) -#define SCU_TASK_DONE_NAK_CMD_ERR ((u32)0x16) -#define SCU_TASK_DONE_CMD_LL_R_ERR ((u32)0x16) -#define SCU_TASK_DONE_LL_R_ERR ((u32)0x17) -#define SCU_TASK_DONE_ACK_NAK_TO ((u32)0x17) -#define SCU_TASK_DONE_LL_PERR ((u32)0x18) -#define SCU_TASK_DONE_LL_SY_TERM ((u32)0x19) -#define SCU_TASK_DONE_NAK_ERR ((u32)0x19) -#define SCU_TASK_DONE_LL_LF_TERM ((u32)0x1A) -#define SCU_TASK_DONE_DATA_LEN_ERR ((u32)0x1A) -#define SCU_TASK_DONE_LL_CL_TERM ((u32)0x1B) -#define SCU_TASK_DONE_LL_ABORT_ERR ((u32)0x1B) -#define SCU_TASK_DONE_SEQ_INV_TYPE ((u32)0x1C) -#define SCU_TASK_DONE_UNEXP_XR ((u32)0x1C) -#define SCU_TASK_DONE_INV_FIS_TYPE ((u32)0x1D) -#define SCU_TASK_DONE_XR_IU_LEN_ERR ((u32)0x1D) -#define SCU_TASK_DONE_INV_FIS_LEN ((u32)0x1E) -#define SCU_TASK_DONE_XR_WD_LEN ((u32)0x1E) -#define SCU_TASK_DONE_SDMA_ERR ((u32)0x1F) -#define SCU_TASK_DONE_OFFSET_ERR ((u32)0x20) -#define SCU_TASK_DONE_MAX_PLD_ERR ((u32)0x21) -#define SCU_TASK_DONE_EXCESS_DATA ((u32)0x22) -#define SCU_TASK_DONE_LF_ERR ((u32)0x23) -#define SCU_TASK_DONE_UNEXP_FIS ((u32)0x24) -#define SCU_TASK_DONE_UNEXP_RESP ((u32)0x24) -#define SCU_TASK_DONE_EARLY_RESP ((u32)0x25) -#define SCU_TASK_DONE_SMP_RESP_TO_ERR ((u32)0x26) -#define SCU_TASK_DONE_DMASETUP_DIRERR ((u32)0x27) -#define SCU_TASK_DONE_SMP_UFI_ERR ((u32)0x27) -#define SCU_TASK_DONE_XFERCNT_ERR ((u32)0x28) -#define SCU_TASK_DONE_SMP_FRM_TYPE_ERR ((u32)0x28) -#define SCU_TASK_DONE_SMP_LL_RX_ERR ((u32)0x29) -#define SCU_TASK_DONE_RESP_LEN_ERR ((u32)0x2A) -#define SCU_TASK_DONE_UNEXP_DATA ((u32)0x2B) -#define SCU_TASK_DONE_OPEN_FAIL ((u32)0x2C) -#define SCU_TASK_DONE_UNEXP_SDBFIS ((u32)0x2D) -#define SCU_TASK_DONE_REG_ERR ((u32)0x2E) -#define SCU_TASK_DONE_SDB_ERR ((u32)0x2F) -#define SCU_TASK_DONE_TASK_ABORT ((u32)0x30) -#define SCU_TASK_DONE_CMD_SDMA_ERR ((U32)0x32) -#define SCU_TASK_DONE_CMD_LL_ABORT_ERR ((U32)0x33) -#define SCU_TASK_OPEN_REJECT_WRONG_DESTINATION ((u32)0x34) -#define SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_1 ((u32)0x35) -#define SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_2 ((u32)0x36) -#define SCU_TASK_OPEN_REJECT_RESERVED_ABANDON_3 ((u32)0x37) -#define SCU_TASK_OPEN_REJECT_BAD_DESTINATION ((u32)0x38) -#define SCU_TASK_OPEN_REJECT_ZONE_VIOLATION ((u32)0x39) -#define SCU_TASK_DONE_VIIT_ENTRY_NV ((u32)0x3A) -#define SCU_TASK_DONE_IIT_ENTRY_NV ((u32)0x3B) -#define SCU_TASK_DONE_RNCNV_OUTBOUND ((u32)0x3C) -#define SCU_TASK_OPEN_REJECT_STP_RESOURCES_BUSY ((u32)0x3D) -#define SCU_TASK_OPEN_REJECT_PROTOCOL_NOT_SUPPORTED ((u32)0x3E) -#define SCU_TASK_OPEN_REJECT_CONNECTION_RATE_NOT_SUPPORTED ((u32)0x3F) - -#endif /* _SCU_COMPLETION_CODES_HEADER_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/scu_event_codes.h b/ANDROID_3.4.5/drivers/scsi/isci/scu_event_codes.h deleted file mode 100644 index 36a945ad..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/scu_event_codes.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SCU_EVENT_CODES_HEADER__ -#define __SCU_EVENT_CODES_HEADER__ - -/** - * This file contains the constants and macros for the SCU event codes. - * - * - */ - -#define SCU_EVENT_TYPE_CODE_SHIFT 24 -#define SCU_EVENT_TYPE_CODE_MASK 0x0F000000 - -#define SCU_EVENT_SPECIFIC_CODE_SHIFT 18 -#define SCU_EVENT_SPECIFIC_CODE_MASK 0x00FC0000 - -#define SCU_EVENT_CODE_MASK \ - (SCU_EVENT_TYPE_CODE_MASK | SCU_EVENT_SPECIFIC_CODE_MASK) - -/** - * SCU_EVENT_TYPE() - - * - * This macro constructs an SCU event type from the type value. - */ -#define SCU_EVENT_TYPE(type) \ - ((u32)(type) << SCU_EVENT_TYPE_CODE_SHIFT) - -/** - * SCU_EVENT_SPECIFIC() - - * - * This macro constructs an SCU event specifier from the code value. - */ -#define SCU_EVENT_SPECIFIC(code) \ - ((u32)(code) << SCU_EVENT_SPECIFIC_CODE_SHIFT) - -/** - * SCU_EVENT_MESSAGE() - - * - * This macro constructs a combines an SCU event type and SCU event specifier - * from the type and code values. - */ -#define SCU_EVENT_MESSAGE(type, code) \ - ((type) | SCU_EVENT_SPECIFIC(code)) - -/** - * SCU_EVENT_TYPE() - - * - * SCU_EVENT_TYPES - */ -#define SCU_EVENT_TYPE_SMU_COMMAND_ERROR SCU_EVENT_TYPE(0x08) -#define SCU_EVENT_TYPE_SMU_PCQ_ERROR SCU_EVENT_TYPE(0x09) -#define SCU_EVENT_TYPE_SMU_ERROR SCU_EVENT_TYPE(0x00) -#define SCU_EVENT_TYPE_TRANSPORT_ERROR SCU_EVENT_TYPE(0x01) -#define SCU_EVENT_TYPE_BROADCAST_CHANGE SCU_EVENT_TYPE(0x02) -#define SCU_EVENT_TYPE_OSSP_EVENT SCU_EVENT_TYPE(0x03) -#define SCU_EVENT_TYPE_FATAL_MEMORY_ERROR SCU_EVENT_TYPE(0x0F) -#define SCU_EVENT_TYPE_RNC_SUSPEND_TX SCU_EVENT_TYPE(0x04) -#define SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX SCU_EVENT_TYPE(0x05) -#define SCU_EVENT_TYPE_RNC_OPS_MISC SCU_EVENT_TYPE(0x06) -#define SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT SCU_EVENT_TYPE(0x07) -#define SCU_EVENT_TYPE_ERR_CNT_EVENT SCU_EVENT_TYPE(0x0A) - -/** - * - * - * SCU_EVENT_SPECIFIERS - */ -#define SCU_EVENT_SPECIFIER_DRIVER_SUSPEND 0x20 -#define SCU_EVENT_SPECIFIER_RNC_RELEASE 0x00 - -/** - * - * - * SMU_COMMAND_EVENTS - */ -#define SCU_EVENT_INVALID_CONTEXT_COMMAND \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_COMMAND_ERROR, 0x00) - -/** - * - * - * SMU_PCQ_EVENTS - */ -#define SCU_EVENT_UNCORRECTABLE_PCQ_ERROR \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_PCQ_ERROR, 0x00) - -/** - * - * - * SMU_EVENTS - */ -#define SCU_EVENT_UNCORRECTABLE_REGISTER_WRITE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_ERROR, 0x02) -#define SCU_EVENT_UNCORRECTABLE_REGISTER_READ \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_ERROR, 0x03) -#define SCU_EVENT_PCIE_INTERFACE_ERROR \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_ERROR, 0x04) -#define SCU_EVENT_FUNCTION_LEVEL_RESET \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_SMU_ERROR, 0x05) - -/** - * - * - * TRANSPORT_LEVEL_ERRORS - */ -#define SCU_EVENT_ACK_NAK_TIMEOUT_ERROR \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_TRANSPORT_ERROR, 0x00) - -/** - * - * - * BROADCAST_CHANGE_EVENTS - */ -#define SCU_EVENT_BROADCAST_CHANGE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x01) -#define SCU_EVENT_BROADCAST_RESERVED0 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x02) -#define SCU_EVENT_BROADCAST_RESERVED1 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x03) -#define SCU_EVENT_BROADCAST_SES \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x04) -#define SCU_EVENT_BROADCAST_EXPANDER \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x05) -#define SCU_EVENT_BROADCAST_AEN \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x06) -#define SCU_EVENT_BROADCAST_RESERVED3 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x07) -#define SCU_EVENT_BROADCAST_RESERVED4 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x08) -#define SCU_EVENT_PE_SUSPENDED \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_BROADCAST_CHANGE, 0x09) - -/** - * - * - * OSSP_EVENTS - */ -#define SCU_EVENT_PORT_SELECTOR_DETECTED \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x10) -#define SCU_EVENT_SENT_PORT_SELECTION \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x11) -#define SCU_EVENT_HARD_RESET_TRANSMITTED \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x12) -#define SCU_EVENT_HARD_RESET_RECEIVED \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x13) -#define SCU_EVENT_RECEIVED_IDENTIFY_TIMEOUT \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x15) -#define SCU_EVENT_LINK_FAILURE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x16) -#define SCU_EVENT_SATA_SPINUP_HOLD \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x17) -#define SCU_EVENT_SAS_15_SSC \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x18) -#define SCU_EVENT_SAS_15 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x19) -#define SCU_EVENT_SAS_30_SSC \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1A) -#define SCU_EVENT_SAS_30 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1B) -#define SCU_EVENT_SAS_60_SSC \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1C) -#define SCU_EVENT_SAS_60 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1D) -#define SCU_EVENT_SATA_15_SSC \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1E) -#define SCU_EVENT_SATA_15 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x1F) -#define SCU_EVENT_SATA_30_SSC \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x20) -#define SCU_EVENT_SATA_30 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x21) -#define SCU_EVENT_SATA_60_SSC \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x22) -#define SCU_EVENT_SATA_60 \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x23) -#define SCU_EVENT_SAS_PHY_DETECTED \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x24) -#define SCU_EVENT_SATA_PHY_DETECTED \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_OSSP_EVENT, 0x25) - -/** - * - * - * FATAL_INTERNAL_MEMORY_ERROR_EVENTS - */ -#define SCU_EVENT_TSC_RNSC_UNCORRECTABLE_ERROR \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_FATAL_MEMORY_ERROR, 0x00) -#define SCU_EVENT_TC_RNC_UNCORRECTABLE_ERROR \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_FATAL_MEMORY_ERROR, 0x01) -#define SCU_EVENT_ZPT_UNCORRECTABLE_ERROR \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_FATAL_MEMORY_ERROR, 0x02) - -/** - * - * - * REMOTE_NODE_SUSPEND_EVENTS - */ -#define SCU_EVENT_TL_RNC_SUSPEND_TX \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX, 0x00) -#define SCU_EVENT_TL_RNC_SUSPEND_TX_RX \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX, 0x00) -#define SCU_EVENT_DRIVER_POST_RNC_SUSPEND_TX \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX, 0x20) -#define SCU_EVENT_DRIVER_POST_RNC_SUSPEND_TX_RX \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_SUSPEND_TX_RX, 0x20) - -/** - * - * - * REMOTE_NODE_MISC_EVENTS - */ -#define SCU_EVENT_POST_RCN_RELEASE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, SCU_EVENT_SPECIFIER_RNC_RELEASE) -#define SCU_EVENT_POST_IT_NEXUS_LOSS_TIMER_ENABLE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, 0x01) -#define SCU_EVENT_POST_IT_NEXUS_LOSS_TIMER_DISABLE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, 0x02) -#define SCU_EVENT_POST_RNC_COMPLETE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, 0x03) -#define SCU_EVENT_POST_RNC_INVALIDATE_COMPLETE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_RNC_OPS_MISC, 0x04) - -/** - * - * - * ERROR_COUNT_EVENT - */ -#define SCU_EVENT_RX_CREDIT_BLOCKED_RECEIVED \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_ERR_CNT_EVENT, 0x00) -#define SCU_EVENT_TX_DONE_CREDIT_TIMEOUT \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_ERR_CNT_EVENT, 0x01) -#define SCU_EVENT_RX_DONE_CREDIT_TIMEOUT \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_ERR_CNT_EVENT, 0x02) - -/** - * scu_get_event_type() - - * - * This macro returns the SCU event type from the event code. - */ -#define scu_get_event_type(event_code) \ - ((event_code) & SCU_EVENT_TYPE_CODE_MASK) - -/** - * scu_get_event_specifier() - - * - * This macro returns the SCU event specifier from the event code. - */ -#define scu_get_event_specifier(event_code) \ - ((event_code) & SCU_EVENT_SPECIFIC_CODE_MASK) - -/** - * scu_get_event_code() - - * - * This macro returns the combined SCU event type and SCU event specifier from - * the event code. - */ -#define scu_get_event_code(event_code) \ - ((event_code) & SCU_EVENT_CODE_MASK) - - -/** - * - * - * PTS_SCHEDULE_EVENT - */ -#define SCU_EVENT_SMP_RESPONSE_NO_PE \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT, 0x00) -#define SCU_EVENT_SPECIFIC_SMP_RESPONSE_NO_PE \ - scu_get_event_specifier(SCU_EVENT_SMP_RESPONSE_NO_PE) - -#define SCU_EVENT_TASK_TIMEOUT \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT, 0x01) -#define SCU_EVENT_SPECIFIC_TASK_TIMEOUT \ - scu_get_event_specifier(SCU_EVENT_TASK_TIMEOUT) - -#define SCU_EVENT_IT_NEXUS_TIMEOUT \ - SCU_EVENT_MESSAGE(SCU_EVENT_TYPE_PTX_SCHEDULE_EVENT, 0x02) -#define SCU_EVENT_SPECIFIC_IT_NEXUS_TIMEOUT \ - scu_get_event_specifier(SCU_EVENT_IT_NEXUS_TIMEOUT) - - -#endif /* __SCU_EVENT_CODES_HEADER__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/scu_remote_node_context.h b/ANDROID_3.4.5/drivers/scsi/isci/scu_remote_node_context.h deleted file mode 100644 index 33745adc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/scu_remote_node_context.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef __SCU_REMOTE_NODE_CONTEXT_HEADER__ -#define __SCU_REMOTE_NODE_CONTEXT_HEADER__ - -/** - * This file contains the structures and constatns used by the SCU hardware to - * describe a remote node context. - * - * - */ - -/** - * struct ssp_remote_node_context - This structure contains the SCU hardware - * definition for an SSP remote node. - * - * - */ -struct ssp_remote_node_context { - /* WORD 0 */ - - /** - * This field is the remote node index assigned for this remote node. All - * remote nodes must have a unique remote node index. The value of the remote - * node index can not exceed the maximum number of remote nodes reported in - * the SCU device context capacity register. - */ - u32 remote_node_index:12; - u32 reserved0_1:4; - - /** - * This field tells the SCU hardware how many simultaneous connections that - * this remote node will support. - */ - u32 remote_node_port_width:4; - - /** - * This field tells the SCU hardware which logical port to associate with this - * remote node. - */ - u32 logical_port_index:3; - u32 reserved0_2:5; - - /** - * This field will enable the I_T nexus loss timer for this remote node. - */ - u32 nexus_loss_timer_enable:1; - - /** - * This field is the for driver debug only and is not used. - */ - u32 check_bit:1; - - /** - * This field must be set to true when the hardware DMAs the remote node - * context to the hardware SRAM. When the remote node is being invalidated - * this field must be set to false. - */ - u32 is_valid:1; - - /** - * This field must be set to true. - */ - u32 is_remote_node_context:1; - - /* WORD 1 - 2 */ - - /** - * This is the low word of the remote device SAS Address - */ - u32 remote_sas_address_lo; - - /** - * This field is the high word of the remote device SAS Address - */ - u32 remote_sas_address_hi; - - /* WORD 3 */ - /** - * This field reprensets the function number assigned to this remote device. - * This value must match the virtual function number that is being used to - * communicate to the device. - */ - u32 function_number:8; - u32 reserved3_1:8; - - /** - * This field provides the driver a way to cheat on the arbitration wait time - * for this remote node. - */ - u32 arbitration_wait_time:16; - - /* WORD 4 */ - /** - * This field tells the SCU hardware how long this device may occupy the - * connection before it must be closed. - */ - u32 connection_occupancy_timeout:16; - - /** - * This field tells the SCU hardware how long to maintain a connection when - * there are no frames being transmitted on the link. - */ - u32 connection_inactivity_timeout:16; - - /* WORD 5 */ - /** - * This field allows the driver to cheat on the arbitration wait time for this - * remote node. - */ - u32 initial_arbitration_wait_time:16; - - /** - * This field is tells the hardware what to program for the connection rate in - * the open address frame. See the SAS spec for valid values. - */ - u32 oaf_connection_rate:4; - - /** - * This field tells the SCU hardware what to program for the features in the - * open address frame. See the SAS spec for valid values. - */ - u32 oaf_features:4; - - /** - * This field tells the SCU hardware what to use for the source zone group in - * the open address frame. See the SAS spec for more details on zoning. - */ - u32 oaf_source_zone_group:8; - - /* WORD 6 */ - /** - * This field tells the SCU hardware what to use as the more capibilities in - * the open address frame. See the SAS Spec for details. - */ - u32 oaf_more_compatibility_features; - - /* WORD 7 */ - u32 reserved7; - -}; - -/** - * struct stp_remote_node_context - This structure contains the SCU hardware - * definition for a STP remote node. - * - * STP Targets are not yet supported so this definition is a placeholder until - * we do support them. - */ -struct stp_remote_node_context { - /** - * Placeholder data for the STP remote node. - */ - u32 data[8]; - -}; - -/** - * This union combines the SAS and SATA remote node definitions. - * - * union scu_remote_node_context - */ -union scu_remote_node_context { - /** - * SSP Remote Node - */ - struct ssp_remote_node_context ssp; - - /** - * STP Remote Node - */ - struct stp_remote_node_context stp; - -}; - -#endif /* __SCU_REMOTE_NODE_CONTEXT_HEADER__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/scu_task_context.h b/ANDROID_3.4.5/drivers/scsi/isci/scu_task_context.h deleted file mode 100644 index 869a979e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/scu_task_context.h +++ /dev/null @@ -1,965 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCU_TASK_CONTEXT_H_ -#define _SCU_TASK_CONTEXT_H_ - -/** - * This file contains the structures and constants for the SCU hardware task - * context. - * - * - */ - - -/** - * enum scu_ssp_task_type - This enumberation defines the various SSP task - * types the SCU hardware will accept. The definition for the various task - * types the SCU hardware will accept can be found in the DS specification. - * - * - */ -typedef enum { - SCU_TASK_TYPE_IOREAD, /* /< IO READ direction or no direction */ - SCU_TASK_TYPE_IOWRITE, /* /< IO Write direction */ - SCU_TASK_TYPE_SMP_REQUEST, /* /< SMP Request type */ - SCU_TASK_TYPE_RESPONSE, /* /< Driver generated response frame (targt mode) */ - SCU_TASK_TYPE_RAW_FRAME, /* /< Raw frame request type */ - SCU_TASK_TYPE_PRIMITIVE /* /< Request for a primitive to be transmitted */ -} scu_ssp_task_type; - -/** - * enum scu_sata_task_type - This enumeration defines the various SATA task - * types the SCU hardware will accept. The definition for the various task - * types the SCU hardware will accept can be found in the DS specification. - * - * - */ -typedef enum { - SCU_TASK_TYPE_DMA_IN, /* /< Read request */ - SCU_TASK_TYPE_FPDMAQ_READ, /* /< NCQ read request */ - SCU_TASK_TYPE_PACKET_DMA_IN, /* /< Packet read request */ - SCU_TASK_TYPE_SATA_RAW_FRAME, /* /< Raw frame request */ - RESERVED_4, - RESERVED_5, - RESERVED_6, - RESERVED_7, - SCU_TASK_TYPE_DMA_OUT, /* /< Write request */ - SCU_TASK_TYPE_FPDMAQ_WRITE, /* /< NCQ write Request */ - SCU_TASK_TYPE_PACKET_DMA_OUT /* /< Packet write request */ -} scu_sata_task_type; - - -/** - * - * - * SCU_CONTEXT_TYPE - */ -#define SCU_TASK_CONTEXT_TYPE 0 -#define SCU_RNC_CONTEXT_TYPE 1 - -/** - * - * - * SCU_TASK_CONTEXT_VALIDITY - */ -#define SCU_TASK_CONTEXT_INVALID 0 -#define SCU_TASK_CONTEXT_VALID 1 - -/** - * - * - * SCU_COMMAND_CODE - */ -#define SCU_COMMAND_CODE_INITIATOR_NEW_TASK 0 -#define SCU_COMMAND_CODE_ACTIVE_TASK 1 -#define SCU_COMMAND_CODE_PRIMITIVE_SEQ_TASK 2 -#define SCU_COMMAND_CODE_TARGET_RAW_FRAMES 3 - -/** - * - * - * SCU_TASK_PRIORITY - */ -/** - * - * - * This priority is used when there is no priority request for this request. - */ -#define SCU_TASK_PRIORITY_NORMAL 0 - -/** - * - * - * This priority indicates that the task should be scheduled to the head of the - * queue. The task will NOT be executed if the TX is suspended for the remote - * node. - */ -#define SCU_TASK_PRIORITY_HEAD_OF_Q 1 - -/** - * - * - * This priority indicates that the task will be executed before all - * SCU_TASK_PRIORITY_NORMAL and SCU_TASK_PRIORITY_HEAD_OF_Q tasks. The task - * WILL be executed if the TX is suspended for the remote node. - */ -#define SCU_TASK_PRIORITY_HIGH 2 - -/** - * - * - * This task priority is reserved and should not be used. - */ -#define SCU_TASK_PRIORITY_RESERVED 3 - -#define SCU_TASK_INITIATOR_MODE 1 -#define SCU_TASK_TARGET_MODE 0 - -#define SCU_TASK_REGULAR 0 -#define SCU_TASK_ABORTED 1 - -/* direction bit defintion */ -/** - * - * - * SATA_DIRECTION - */ -#define SCU_SATA_WRITE_DATA_DIRECTION 0 -#define SCU_SATA_READ_DATA_DIRECTION 1 - -/** - * - * - * SCU_COMMAND_CONTEXT_MACROS These macros provide the mask and shift - * operations to construct the various SCU commands - */ -#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_SHIFT 21 -#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK 0x00E00000 -#define scu_get_command_request_type(x) \ - ((x) & SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK) - -#define SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_SHIFT 18 -#define SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK 0x001C0000 -#define scu_get_command_request_subtype(x) \ - ((x) & SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK) - -#define SCU_CONTEXT_COMMAND_REQUEST_FULLTYPE_MASK \ - (\ - SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK \ - | SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK \ - ) -#define scu_get_command_request_full_type(x) \ - ((x) & SCU_CONTEXT_COMMAND_REQUEST_FULLTYPE_MASK) - -#define SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT 16 -#define SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_MASK 0x00010000 -#define scu_get_command_protocl_engine_group(x) \ - ((x) & SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_MASK) - -#define SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT 12 -#define SCU_CONTEXT_COMMAND_LOGICAL_PORT_MASK 0x00007000 -#define scu_get_command_reqeust_logical_port(x) \ - ((x) & SCU_CONTEXT_COMMAND_LOGICAL_PORT_MASK) - - -#define MAKE_SCU_CONTEXT_COMMAND_TYPE(type) \ - ((u32)(type) << SCU_CONTEXT_COMMAND_REQUEST_TYPE_SHIFT) - -/** - * MAKE_SCU_CONTEXT_COMMAND_TYPE() - - * - * SCU_COMMAND_TYPES These constants provide the grouping of the different SCU - * command types. - */ -#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC MAKE_SCU_CONTEXT_COMMAND_TYPE(0) -#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC MAKE_SCU_CONTEXT_COMMAND_TYPE(1) -#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(2) -#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(3) -#define SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC MAKE_SCU_CONTEXT_COMMAND_TYPE(6) - -#define MAKE_SCU_CONTEXT_COMMAND_REQUEST(type, command) \ - ((type) | ((command) << SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_SHIFT)) - -/** - * - * - * SCU_REQUEST_TYPES These constants are the various request types that can be - * posted to the SCU hardware. - */ -#define SCU_CONTEXT_COMMAND_REQUST_POST_TC \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC, 0)) - -#define SCU_CONTEXT_COMMAND_REQUEST_POST_TC_ABORT \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_TC, 1)) - -#define SCU_CONTEXT_COMMAND_REQUST_DUMP_TC \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_TC, 0)) - -#define SCU_CONTEXT_COMMAND_POST_RNC_32 \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC, 0)) - -#define SCU_CONTEXT_COMMAND_POST_RNC_96 \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC, 1)) - -#define SCU_CONTEXT_COMMAND_POST_RNC_INVALIDATE \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_POST_RNC, 2)) - -#define SCU_CONTEXT_COMMAND_DUMP_RNC_32 \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC, 0)) - -#define SCU_CONTEXT_COMMAND_DUMP_RNC_96 \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_DUMP_RNC, 1)) - -#define SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 0)) - -#define SCU_CONTEXT_COMMAND_POST_RNC_SUSPEND_TX_RX \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 1)) - -#define SCU_CONTEXT_COMMAND_POST_RNC_RESUME \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 2)) - -#define SCU_CONTEXT_IT_NEXUS_LOSS_TIMER_ENABLE \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 3)) - -#define SCU_CONTEXT_IT_NEXUS_LOSS_TIMER_DISABLE \ - (MAKE_SCU_CONTEXT_COMMAND_REQUEST(SCU_CONTEXT_COMMAND_REQUEST_TYPE_OTHER_RNC, 4)) - -/** - * - * - * SCU_TASK_CONTEXT_PROTOCOL SCU Task context protocol types this is uesd to - * program the SCU Task context protocol field in word 0x00. - */ -#define SCU_TASK_CONTEXT_PROTOCOL_SMP 0x00 -#define SCU_TASK_CONTEXT_PROTOCOL_SSP 0x01 -#define SCU_TASK_CONTEXT_PROTOCOL_STP 0x02 -#define SCU_TASK_CONTEXT_PROTOCOL_NONE 0x07 - -/** - * struct ssp_task_context - This is the SCU hardware definition for an SSP - * request. - * - * - */ -struct ssp_task_context { - /* OFFSET 0x18 */ - u32 reserved00:24; - u32 frame_type:8; - - /* OFFSET 0x1C */ - u32 reserved01; - - /* OFFSET 0x20 */ - u32 fill_bytes:2; - u32 reserved02:6; - u32 changing_data_pointer:1; - u32 retransmit:1; - u32 retry_data_frame:1; - u32 tlr_control:2; - u32 reserved03:19; - - /* OFFSET 0x24 */ - u32 uiRsvd4; - - /* OFFSET 0x28 */ - u32 target_port_transfer_tag:16; - u32 tag:16; - - /* OFFSET 0x2C */ - u32 data_offset; -}; - -/** - * struct stp_task_context - This is the SCU hardware definition for an STP - * request. - * - * - */ -struct stp_task_context { - /* OFFSET 0x18 */ - u32 fis_type:8; - u32 pm_port:4; - u32 reserved0:3; - u32 control:1; - u32 command:8; - u32 features:8; - - /* OFFSET 0x1C */ - u32 reserved1; - - /* OFFSET 0x20 */ - u32 reserved2; - - /* OFFSET 0x24 */ - u32 reserved3; - - /* OFFSET 0x28 */ - u32 ncq_tag:5; - u32 reserved4:27; - - /* OFFSET 0x2C */ - u32 data_offset; /* TODO: What is this used for? */ -}; - -/** - * struct smp_task_context - This is the SCU hardware definition for an SMP - * request. - * - * - */ -struct smp_task_context { - /* OFFSET 0x18 */ - u32 response_length:8; - u32 function_result:8; - u32 function:8; - u32 frame_type:8; - - /* OFFSET 0x1C */ - u32 smp_response_ufi:12; - u32 reserved1:20; - - /* OFFSET 0x20 */ - u32 reserved2; - - /* OFFSET 0x24 */ - u32 reserved3; - - /* OFFSET 0x28 */ - u32 reserved4; - - /* OFFSET 0x2C */ - u32 reserved5; -}; - -/** - * struct primitive_task_context - This is the SCU hardware definition used - * when the driver wants to send a primitive on the link. - * - * - */ -struct primitive_task_context { - /* OFFSET 0x18 */ - /** - * This field is the control word and it must be 0. - */ - u32 control; /* /< must be set to 0 */ - - /* OFFSET 0x1C */ - /** - * This field specifies the primitive that is to be transmitted. - */ - u32 sequence; - - /* OFFSET 0x20 */ - u32 reserved0; - - /* OFFSET 0x24 */ - u32 reserved1; - - /* OFFSET 0x28 */ - u32 reserved2; - - /* OFFSET 0x2C */ - u32 reserved3; -}; - -/** - * The union of the protocols that can be selected in the SCU task context - * field. - * - * protocol_context - */ -union protocol_context { - struct ssp_task_context ssp; - struct stp_task_context stp; - struct smp_task_context smp; - struct primitive_task_context primitive; - u32 words[6]; -}; - -/** - * struct scu_sgl_element - This structure represents a single SCU defined SGL - * element. SCU SGLs contain a 64 bit address with the maximum data transfer - * being 24 bits in size. The SGL can not cross a 4GB boundary. - * - * struct scu_sgl_element - */ -struct scu_sgl_element { - /** - * This field is the upper 32 bits of the 64 bit physical address. - */ - u32 address_upper; - - /** - * This field is the lower 32 bits of the 64 bit physical address. - */ - u32 address_lower; - - /** - * This field is the number of bytes to transfer. - */ - u32 length:24; - - /** - * This field is the address modifier to be used when a virtual function is - * requesting a data transfer. - */ - u32 address_modifier:8; - -}; - -#define SCU_SGL_ELEMENT_PAIR_A 0 -#define SCU_SGL_ELEMENT_PAIR_B 1 - -/** - * struct scu_sgl_element_pair - This structure is the SCU hardware definition - * of a pair of SGL elements. The SCU hardware always works on SGL pairs. - * They are refered to in the DS specification as SGL A and SGL B. Each SGL - * pair is followed by the address of the next pair. - * - * - */ -struct scu_sgl_element_pair { - /* OFFSET 0x60-0x68 */ - /** - * This field is the SGL element A of the SGL pair. - */ - struct scu_sgl_element A; - - /* OFFSET 0x6C-0x74 */ - /** - * This field is the SGL element B of the SGL pair. - */ - struct scu_sgl_element B; - - /* OFFSET 0x78-0x7C */ - /** - * This field is the upper 32 bits of the 64 bit address to the next SGL - * element pair. - */ - u32 next_pair_upper; - - /** - * This field is the lower 32 bits of the 64 bit address to the next SGL - * element pair. - */ - u32 next_pair_lower; - -}; - -/** - * struct transport_snapshot - This structure is the SCU hardware scratch area - * for the task context. This is set to 0 by the driver but can be read by - * issuing a dump TC request to the SCU. - * - * - */ -struct transport_snapshot { - /* OFFSET 0x48 */ - u32 xfer_rdy_write_data_length; - - /* OFFSET 0x4C */ - u32 data_offset; - - /* OFFSET 0x50 */ - u32 data_transfer_size:24; - u32 reserved_50_0:8; - - /* OFFSET 0x54 */ - u32 next_initiator_write_data_offset; - - /* OFFSET 0x58 */ - u32 next_initiator_write_data_xfer_size:24; - u32 reserved_58_0:8; -}; - -/** - * struct scu_task_context - This structure defines the contents of the SCU - * silicon task context. It lays out all of the fields according to the - * expected order and location for the Storage Controller unit. - * - * - */ -struct scu_task_context { - /* OFFSET 0x00 ------ */ - /** - * This field must be encoded to one of the valid SCU task priority values - * - SCU_TASK_PRIORITY_NORMAL - * - SCU_TASK_PRIORITY_HEAD_OF_Q - * - SCU_TASK_PRIORITY_HIGH - */ - u32 priority:2; - - /** - * This field must be set to true if this is an initiator generated request. - * Until target mode is supported all task requests are initiator requests. - */ - u32 initiator_request:1; - - /** - * This field must be set to one of the valid connection rates valid values - * are 0x8, 0x9, and 0xA. - */ - u32 connection_rate:4; - - /** - * This field muse be programed when generating an SMP response since the SMP - * connection remains open until the SMP response is generated. - */ - u32 protocol_engine_index:3; - - /** - * This field must contain the logical port for the task request. - */ - u32 logical_port_index:3; - - /** - * This field must be set to one of the SCU_TASK_CONTEXT_PROTOCOL values - * - SCU_TASK_CONTEXT_PROTOCOL_SMP - * - SCU_TASK_CONTEXT_PROTOCOL_SSP - * - SCU_TASK_CONTEXT_PROTOCOL_STP - * - SCU_TASK_CONTEXT_PROTOCOL_NONE - */ - u32 protocol_type:3; - - /** - * This filed must be set to the TCi allocated for this task - */ - u32 task_index:12; - - /** - * This field is reserved and must be set to 0x00 - */ - u32 reserved_00_0:1; - - /** - * For a normal task request this must be set to 0. If this is an abort of - * this task request it must be set to 1. - */ - u32 abort:1; - - /** - * This field must be set to true for the SCU hardware to process the task. - */ - u32 valid:1; - - /** - * This field must be set to SCU_TASK_CONTEXT_TYPE - */ - u32 context_type:1; - - /* OFFSET 0x04 */ - /** - * This field contains the RNi that is the target of this request. - */ - u32 remote_node_index:12; - - /** - * This field is programmed if this is a mirrored request, which we are not - * using, in which case it is the RNi for the mirrored target. - */ - u32 mirrored_node_index:12; - - /** - * This field is programmed with the direction of the SATA reqeust - * - SCU_SATA_WRITE_DATA_DIRECTION - * - SCU_SATA_READ_DATA_DIRECTION - */ - u32 sata_direction:1; - - /** - * This field is programmsed with one of the following SCU_COMMAND_CODE - * - SCU_COMMAND_CODE_INITIATOR_NEW_TASK - * - SCU_COMMAND_CODE_ACTIVE_TASK - * - SCU_COMMAND_CODE_PRIMITIVE_SEQ_TASK - * - SCU_COMMAND_CODE_TARGET_RAW_FRAMES - */ - u32 command_code:2; - - /** - * This field is set to true if the remote node should be suspended. - * This bit is only valid for SSP & SMP target devices. - */ - u32 suspend_node:1; - - /** - * This field is programmed with one of the following command type codes - * - * For SAS requests use the scu_ssp_task_type - * - SCU_TASK_TYPE_IOREAD - * - SCU_TASK_TYPE_IOWRITE - * - SCU_TASK_TYPE_SMP_REQUEST - * - SCU_TASK_TYPE_RESPONSE - * - SCU_TASK_TYPE_RAW_FRAME - * - SCU_TASK_TYPE_PRIMITIVE - * - * For SATA requests use the scu_sata_task_type - * - SCU_TASK_TYPE_DMA_IN - * - SCU_TASK_TYPE_FPDMAQ_READ - * - SCU_TASK_TYPE_PACKET_DMA_IN - * - SCU_TASK_TYPE_SATA_RAW_FRAME - * - SCU_TASK_TYPE_DMA_OUT - * - SCU_TASK_TYPE_FPDMAQ_WRITE - * - SCU_TASK_TYPE_PACKET_DMA_OUT - */ - u32 task_type:4; - - /* OFFSET 0x08 */ - /** - * This field is reserved and the must be set to 0x00 - */ - u32 link_layer_control:8; /* presently all reserved */ - - /** - * This field is set to true when TLR is to be enabled - */ - u32 ssp_tlr_enable:1; - - /** - * This is field specifies if the SCU DMAs a response frame to host - * memory for good response frames when operating in target mode. - */ - u32 dma_ssp_target_good_response:1; - - /** - * This field indicates if the SCU should DMA the response frame to - * host memory. - */ - u32 do_not_dma_ssp_good_response:1; - - /** - * This field is set to true when strict ordering is to be enabled - */ - u32 strict_ordering:1; - - /** - * This field indicates the type of endianess to be utilized for the - * frame. command, task, and response frames utilized control_frame - * set to 1. - */ - u32 control_frame:1; - - /** - * This field is reserved and the driver should set to 0x00 - */ - u32 tl_control_reserved:3; - - /** - * This field is set to true when the SCU hardware task timeout control is to - * be enabled - */ - u32 timeout_enable:1; - - /** - * This field is reserved and the driver should set it to 0x00 - */ - u32 pts_control_reserved:7; - - /** - * This field should be set to true when block guard is to be enabled - */ - u32 block_guard_enable:1; - - /** - * This field is reserved and the driver should set to 0x00 - */ - u32 sdma_control_reserved:7; - - /* OFFSET 0x0C */ - /** - * This field is the address modifier for this io request it should be - * programmed with the virtual function that is making the request. - */ - u32 address_modifier:16; - - /** - * @todo What we support mirrored SMP response frame? - */ - u32 mirrored_protocol_engine:3; /* mirrored protocol Engine Index */ - - /** - * If this is a mirrored request the logical port index for the mirrored RNi - * must be programmed. - */ - u32 mirrored_logical_port:4; /* mirrored local port index */ - - /** - * This field is reserved and the driver must set it to 0x00 - */ - u32 reserved_0C_0:8; - - /** - * This field must be set to true if the mirrored request processing is to be - * enabled. - */ - u32 mirror_request_enable:1; /* Mirrored request Enable */ - - /* OFFSET 0x10 */ - /** - * This field is the command iu length in dwords - */ - u32 ssp_command_iu_length:8; - - /** - * This is the target TLR enable bit it must be set to 0 when creatning the - * task context. - */ - u32 xfer_ready_tlr_enable:1; - - /** - * This field is reserved and the driver must set it to 0x00 - */ - u32 reserved_10_0:7; - - /** - * This is the maximum burst size that the SCU hardware will send in one - * connection its value is (N x 512) and N must be a multiple of 2. If the - * value is 0x00 then maximum burst size is disabled. - */ - u32 ssp_max_burst_size:16; - - /* OFFSET 0x14 */ - /** - * This filed is set to the number of bytes to be transfered in the request. - */ - u32 transfer_length_bytes:24; /* In terms of bytes */ - - /** - * This field is reserved and the driver should set it to 0x00 - */ - u32 reserved_14_0:8; - - /* OFFSET 0x18-0x2C */ - /** - * This union provides for the protocol specif part of the SCU Task Context. - */ - union protocol_context type; - - /* OFFSET 0x30-0x34 */ - /** - * This field is the upper 32 bits of the 64 bit physical address of the - * command iu buffer - */ - u32 command_iu_upper; - - /** - * This field is the lower 32 bits of the 64 bit physical address of the - * command iu buffer - */ - u32 command_iu_lower; - - /* OFFSET 0x38-0x3C */ - /** - * This field is the upper 32 bits of the 64 bit physical address of the - * response iu buffer - */ - u32 response_iu_upper; - - /** - * This field is the lower 32 bits of the 64 bit physical address of the - * response iu buffer - */ - u32 response_iu_lower; - - /* OFFSET 0x40 */ - /** - * This field is set to the task phase of the SCU hardware. The driver must - * set this to 0x01 - */ - u32 task_phase:8; - - /** - * This field is set to the transport layer task status. The driver must set - * this to 0x00 - */ - u32 task_status:8; - - /** - * This field is used during initiator write TLR - */ - u32 previous_extended_tag:4; - - /** - * This field is set the maximum number of retries for a STP non-data FIS - */ - u32 stp_retry_count:2; - - /** - * This field is reserved and the driver must set it to 0x00 - */ - u32 reserved_40_1:2; - - /** - * This field is used by the SCU TL to determine when to take a snapshot when - * tranmitting read data frames. - * - 0x00 The entire IO - * - 0x01 32k - * - 0x02 64k - * - 0x04 128k - * - 0x08 256k - */ - u32 ssp_tlr_threshold:4; - - /** - * This field is reserved and the driver must set it to 0x00 - */ - u32 reserved_40_2:4; - - /* OFFSET 0x44 */ - u32 write_data_length; /* read only set to 0 */ - - /* OFFSET 0x48-0x58 */ - struct transport_snapshot snapshot; /* read only set to 0 */ - - /* OFFSET 0x5C */ - u32 blk_prot_en:1; - u32 blk_sz:2; - u32 blk_prot_func:2; - u32 reserved_5C_0:9; - u32 active_sgl_element:2; /* read only set to 0 */ - u32 sgl_exhausted:1; /* read only set to 0 */ - u32 payload_data_transfer_error:4; /* read only set to 0 */ - u32 frame_buffer_offset:11; /* read only set to 0 */ - - /* OFFSET 0x60-0x7C */ - /** - * This field is the first SGL element pair found in the TC data structure. - */ - struct scu_sgl_element_pair sgl_pair_ab; - /* OFFSET 0x80-0x9C */ - /** - * This field is the second SGL element pair found in the TC data structure. - */ - struct scu_sgl_element_pair sgl_pair_cd; - - /* OFFSET 0xA0-BC */ - struct scu_sgl_element_pair sgl_snapshot_ac; - - /* OFFSET 0xC0 */ - u32 active_sgl_element_pair; /* read only set to 0 */ - - /* OFFSET 0xC4-0xCC */ - u32 reserved_C4_CC[3]; - - /* OFFSET 0xD0 */ - u32 interm_crc_val:16; - u32 init_crc_seed:16; - - /* OFFSET 0xD4 */ - u32 app_tag_verify:16; - u32 app_tag_gen:16; - - /* OFFSET 0xD8 */ - u32 ref_tag_seed_verify; - - /* OFFSET 0xDC */ - u32 UD_bytes_immed_val:13; - u32 reserved_DC_0:3; - u32 DIF_bytes_immed_val:4; - u32 reserved_DC_1:12; - - /* OFFSET 0xE0 */ - u32 bgc_blk_sz:13; - u32 reserved_E0_0:3; - u32 app_tag_gen_mask:16; - - /* OFFSET 0xE4 */ - union { - u16 bgctl; - struct { - u16 crc_verify:1; - u16 app_tag_chk:1; - u16 ref_tag_chk:1; - u16 op:2; - u16 legacy:1; - u16 invert_crc_seed:1; - u16 ref_tag_gen:1; - u16 fixed_ref_tag:1; - u16 invert_crc:1; - u16 app_ref_f_detect:1; - u16 uninit_dif_check_err:1; - u16 uninit_dif_bypass:1; - u16 app_f_detect:1; - u16 reserved_0:2; - } bgctl_f; - }; - - u16 app_tag_verify_mask; - - /* OFFSET 0xE8 */ - u32 blk_guard_err:8; - u32 reserved_E8_0:24; - - /* OFFSET 0xEC */ - u32 ref_tag_seed_gen; - - /* OFFSET 0xF0 */ - u32 intermediate_crc_valid_snapshot:16; - u32 reserved_F0_0:16; - - /* OFFSET 0xF4 */ - u32 reference_tag_seed_for_verify_function_snapshot; - - /* OFFSET 0xF8 */ - u32 snapshot_of_reserved_dword_DC_of_tc; - - /* OFFSET 0xFC */ - u32 reference_tag_seed_for_generate_function_snapshot; - -} __packed; - -#endif /* _SCU_TASK_CONTEXT_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/task.c b/ANDROID_3.4.5/drivers/scsi/isci/task.c deleted file mode 100644 index 374254ed..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/task.c +++ /dev/null @@ -1,1323 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include "sas.h" -#include -#include "remote_device.h" -#include "remote_node_context.h" -#include "isci.h" -#include "request.h" -#include "task.h" -#include "host.h" - -/** -* isci_task_refuse() - complete the request to the upper layer driver in -* the case where an I/O needs to be completed back in the submit path. -* @ihost: host on which the the request was queued -* @task: request to complete -* @response: response code for the completed task. -* @status: status code for the completed task. -* -*/ -static void isci_task_refuse(struct isci_host *ihost, struct sas_task *task, - enum service_response response, - enum exec_status status) - -{ - enum isci_completion_selection disposition; - - disposition = isci_perform_normal_io_completion; - disposition = isci_task_set_completion_status(task, response, status, - disposition); - - /* Tasks aborted specifically by a call to the lldd_abort_task - * function should not be completed to the host in the regular path. - */ - switch (disposition) { - case isci_perform_normal_io_completion: - /* Normal notification (task_done) */ - dev_dbg(&ihost->pdev->dev, - "%s: Normal - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); - - task->lldd_task = NULL; - task->task_done(task); - break; - - case isci_perform_aborted_io_completion: - /* - * No notification because this request is already in the - * abort path. - */ - dev_dbg(&ihost->pdev->dev, - "%s: Aborted - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); - break; - - case isci_perform_error_io_completion: - /* Use sas_task_abort */ - dev_dbg(&ihost->pdev->dev, - "%s: Error - task = %p, response=%d, " - "status=%d\n", - __func__, task, response, status); - sas_task_abort(task); - break; - - default: - dev_dbg(&ihost->pdev->dev, - "%s: isci task notification default case!", - __func__); - sas_task_abort(task); - break; - } -} - -#define for_each_sas_task(num, task) \ - for (; num > 0; num--,\ - task = list_entry(task->list.next, struct sas_task, list)) - - -static inline int isci_device_io_ready(struct isci_remote_device *idev, - struct sas_task *task) -{ - return idev ? test_bit(IDEV_IO_READY, &idev->flags) || - (test_bit(IDEV_IO_NCQERROR, &idev->flags) && - isci_task_is_ncq_recovery(task)) - : 0; -} -/** - * isci_task_execute_task() - This function is one of the SAS Domain Template - * functions. This function is called by libsas to send a task down to - * hardware. - * @task: This parameter specifies the SAS task to send. - * @num: This parameter specifies the number of tasks to queue. - * @gfp_flags: This parameter specifies the context of this call. - * - * status, zero indicates success. - */ -int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags) -{ - struct isci_host *ihost = dev_to_ihost(task->dev); - struct isci_remote_device *idev; - unsigned long flags; - bool io_ready; - u16 tag; - - dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num); - - for_each_sas_task(num, task) { - enum sci_status status = SCI_FAILURE; - - spin_lock_irqsave(&ihost->scic_lock, flags); - idev = isci_lookup_device(task->dev); - io_ready = isci_device_io_ready(idev, task); - tag = isci_alloc_tag(ihost); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - dev_dbg(&ihost->pdev->dev, - "task: %p, num: %d dev: %p idev: %p:%#lx cmd = %p\n", - task, num, task->dev, idev, idev ? idev->flags : 0, - task->uldd_task); - - if (!idev) { - isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED, - SAS_DEVICE_UNKNOWN); - } else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) { - /* Indicate QUEUE_FULL so that the scsi midlayer - * retries. - */ - isci_task_refuse(ihost, task, SAS_TASK_COMPLETE, - SAS_QUEUE_FULL); - } else { - /* There is a device and it's ready for I/O. */ - spin_lock_irqsave(&task->task_state_lock, flags); - - if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { - /* The I/O was aborted. */ - spin_unlock_irqrestore(&task->task_state_lock, - flags); - - isci_task_refuse(ihost, task, - SAS_TASK_UNDELIVERED, - SAM_STAT_TASK_ABORTED); - } else { - task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - /* build and send the request. */ - status = isci_request_execute(ihost, idev, task, tag); - - if (status != SCI_SUCCESS) { - - spin_lock_irqsave(&task->task_state_lock, flags); - /* Did not really start this command. */ - task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - if (test_bit(IDEV_GONE, &idev->flags)) { - - /* Indicate that the device - * is gone. - */ - isci_task_refuse(ihost, task, - SAS_TASK_UNDELIVERED, - SAS_DEVICE_UNKNOWN); - } else { - /* Indicate QUEUE_FULL so that - * the scsi midlayer retries. - * If the request failed for - * remote device reasons, it - * gets returned as - * SAS_TASK_UNDELIVERED next - * time through. - */ - isci_task_refuse(ihost, task, - SAS_TASK_COMPLETE, - SAS_QUEUE_FULL); - } - } - } - } - if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) { - spin_lock_irqsave(&ihost->scic_lock, flags); - /* command never hit the device, so just free - * the tci and skip the sequence increment - */ - isci_tci_free(ihost, ISCI_TAG_TCI(tag)); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - } - isci_put_device(idev); - } - return 0; -} - -static struct isci_request *isci_task_request_build(struct isci_host *ihost, - struct isci_remote_device *idev, - u16 tag, struct isci_tmf *isci_tmf) -{ - enum sci_status status = SCI_FAILURE; - struct isci_request *ireq = NULL; - struct domain_device *dev; - - dev_dbg(&ihost->pdev->dev, - "%s: isci_tmf = %p\n", __func__, isci_tmf); - - dev = idev->domain_dev; - - /* do common allocation and init of request object. */ - ireq = isci_tmf_request_from_tag(ihost, isci_tmf, tag); - if (!ireq) - return NULL; - - /* let the core do it's construct. */ - status = sci_task_request_construct(ihost, idev, tag, - ireq); - - if (status != SCI_SUCCESS) { - dev_warn(&ihost->pdev->dev, - "%s: sci_task_request_construct failed - " - "status = 0x%x\n", - __func__, - status); - return NULL; - } - - /* XXX convert to get this from task->tproto like other drivers */ - if (dev->dev_type == SAS_END_DEV) { - isci_tmf->proto = SAS_PROTOCOL_SSP; - status = sci_task_request_construct_ssp(ireq); - if (status != SCI_SUCCESS) - return NULL; - } - - return ireq; -} - -/** -* isci_request_mark_zombie() - This function must be called with scic_lock held. -*/ -static void isci_request_mark_zombie(struct isci_host *ihost, struct isci_request *ireq) -{ - struct completion *tmf_completion = NULL; - struct completion *req_completion; - - /* Set the request state to "dead". */ - ireq->status = dead; - - req_completion = ireq->io_request_completion; - ireq->io_request_completion = NULL; - - if (test_bit(IREQ_TMF, &ireq->flags)) { - /* Break links with the TMF request. */ - struct isci_tmf *tmf = isci_request_access_tmf(ireq); - - /* In the case where a task request is dying, - * the thread waiting on the complete will sit and - * timeout unless we wake it now. Since the TMF - * has a default error status, complete it here - * to wake the waiting thread. - */ - if (tmf) { - tmf_completion = tmf->complete; - tmf->complete = NULL; - } - ireq->ttype_ptr.tmf_task_ptr = NULL; - dev_dbg(&ihost->pdev->dev, "%s: tmf_code %d, managed tag %#x\n", - __func__, tmf->tmf_code, tmf->io_tag); - } else { - /* Break links with the sas_task - the callback is done - * elsewhere. - */ - struct sas_task *task = isci_request_access_task(ireq); - - if (task) - task->lldd_task = NULL; - - ireq->ttype_ptr.io_task_ptr = NULL; - } - - dev_warn(&ihost->pdev->dev, "task context unrecoverable (tag: %#x)\n", - ireq->io_tag); - - /* Don't force waiting threads to timeout. */ - if (req_completion) - complete(req_completion); - - if (tmf_completion != NULL) - complete(tmf_completion); -} - -static int isci_task_execute_tmf(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_tmf *tmf, unsigned long timeout_ms) -{ - DECLARE_COMPLETION_ONSTACK(completion); - enum sci_task_status status = SCI_TASK_FAILURE; - struct isci_request *ireq; - int ret = TMF_RESP_FUNC_FAILED; - unsigned long flags; - unsigned long timeleft; - u16 tag; - - spin_lock_irqsave(&ihost->scic_lock, flags); - tag = isci_alloc_tag(ihost); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (tag == SCI_CONTROLLER_INVALID_IO_TAG) - return ret; - - /* sanity check, return TMF_RESP_FUNC_FAILED - * if the device is not there and ready. - */ - if (!idev || - (!test_bit(IDEV_IO_READY, &idev->flags) && - !test_bit(IDEV_IO_NCQERROR, &idev->flags))) { - dev_dbg(&ihost->pdev->dev, - "%s: idev = %p not ready (%#lx)\n", - __func__, - idev, idev ? idev->flags : 0); - goto err_tci; - } else - dev_dbg(&ihost->pdev->dev, - "%s: idev = %p\n", - __func__, idev); - - /* Assign the pointer to the TMF's completion kernel wait structure. */ - tmf->complete = &completion; - tmf->status = SCI_FAILURE_TIMEOUT; - - ireq = isci_task_request_build(ihost, idev, tag, tmf); - if (!ireq) - goto err_tci; - - spin_lock_irqsave(&ihost->scic_lock, flags); - - /* start the TMF io. */ - status = sci_controller_start_task(ihost, idev, ireq); - - if (status != SCI_TASK_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: start_io failed - status = 0x%x, request = %p\n", - __func__, - status, - ireq); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - goto err_tci; - } - - if (tmf->cb_state_func != NULL) - tmf->cb_state_func(isci_tmf_started, tmf, tmf->cb_data); - - isci_request_change_state(ireq, started); - - /* add the request to the remote device request list. */ - list_add(&ireq->dev_node, &idev->reqs_in_process); - - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - /* Wait for the TMF to complete, or a timeout. */ - timeleft = wait_for_completion_timeout(&completion, - msecs_to_jiffies(timeout_ms)); - - if (timeleft == 0) { - /* The TMF did not complete - this could be because - * of an unplug. Terminate the TMF request now. - */ - spin_lock_irqsave(&ihost->scic_lock, flags); - - if (tmf->cb_state_func != NULL) - tmf->cb_state_func(isci_tmf_timed_out, tmf, - tmf->cb_data); - - sci_controller_terminate_request(ihost, idev, ireq); - - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - timeleft = wait_for_completion_timeout( - &completion, - msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC)); - - if (!timeleft) { - /* Strange condition - the termination of the TMF - * request timed-out. - */ - spin_lock_irqsave(&ihost->scic_lock, flags); - - /* If the TMF status has not changed, kill it. */ - if (tmf->status == SCI_FAILURE_TIMEOUT) - isci_request_mark_zombie(ihost, ireq); - - spin_unlock_irqrestore(&ihost->scic_lock, flags); - } - } - - isci_print_tmf(ihost, tmf); - - if (tmf->status == SCI_SUCCESS) - ret = TMF_RESP_FUNC_COMPLETE; - else if (tmf->status == SCI_FAILURE_IO_RESPONSE_VALID) { - dev_dbg(&ihost->pdev->dev, - "%s: tmf.status == " - "SCI_FAILURE_IO_RESPONSE_VALID\n", - __func__); - ret = TMF_RESP_FUNC_COMPLETE; - } - /* Else - leave the default "failed" status alone. */ - - dev_dbg(&ihost->pdev->dev, - "%s: completed request = %p\n", - __func__, - ireq); - - return ret; - - err_tci: - spin_lock_irqsave(&ihost->scic_lock, flags); - isci_tci_free(ihost, ISCI_TAG_TCI(tag)); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - return ret; -} - -static void isci_task_build_tmf(struct isci_tmf *tmf, - enum isci_tmf_function_codes code, - void (*tmf_sent_cb)(enum isci_tmf_cb_state, - struct isci_tmf *, - void *), - void *cb_data) -{ - memset(tmf, 0, sizeof(*tmf)); - - tmf->tmf_code = code; - tmf->cb_state_func = tmf_sent_cb; - tmf->cb_data = cb_data; -} - -static void isci_task_build_abort_task_tmf(struct isci_tmf *tmf, - enum isci_tmf_function_codes code, - void (*tmf_sent_cb)(enum isci_tmf_cb_state, - struct isci_tmf *, - void *), - struct isci_request *old_request) -{ - isci_task_build_tmf(tmf, code, tmf_sent_cb, old_request); - tmf->io_tag = old_request->io_tag; -} - -/** - * isci_task_validate_request_to_abort() - This function checks the given I/O - * against the "started" state. If the request is still "started", it's - * state is changed to aborted. NOTE: isci_host->scic_lock MUST BE HELD - * BEFORE CALLING THIS FUNCTION. - * @isci_request: This parameter specifies the request object to control. - * @isci_host: This parameter specifies the ISCI host object - * @isci_device: This is the device to which the request is pending. - * @aborted_io_completion: This is a completion structure that will be added to - * the request in case it is changed to aborting; this completion is - * triggered when the request is fully completed. - * - * Either "started" on successful change of the task status to "aborted", or - * "unallocated" if the task cannot be controlled. - */ -static enum isci_request_status isci_task_validate_request_to_abort( - struct isci_request *isci_request, - struct isci_host *isci_host, - struct isci_remote_device *isci_device, - struct completion *aborted_io_completion) -{ - enum isci_request_status old_state = unallocated; - - /* Only abort the task if it's in the - * device's request_in_process list - */ - if (isci_request && !list_empty(&isci_request->dev_node)) { - old_state = isci_request_change_started_to_aborted( - isci_request, aborted_io_completion); - - } - - return old_state; -} - -static int isci_request_is_dealloc_managed(enum isci_request_status stat) -{ - switch (stat) { - case aborted: - case aborting: - case terminating: - case completed: - case dead: - return true; - default: - return false; - } -} - -/** - * isci_terminate_request_core() - This function will terminate the given - * request, and wait for it to complete. This function must only be called - * from a thread that can wait. Note that the request is terminated and - * completed (back to the host, if started there). - * @ihost: This SCU. - * @idev: The target. - * @isci_request: The I/O request to be terminated. - * - */ -static void isci_terminate_request_core(struct isci_host *ihost, - struct isci_remote_device *idev, - struct isci_request *isci_request) -{ - enum sci_status status = SCI_SUCCESS; - bool was_terminated = false; - bool needs_cleanup_handling = false; - unsigned long flags; - unsigned long termination_completed = 1; - struct completion *io_request_completion; - - dev_dbg(&ihost->pdev->dev, - "%s: device = %p; request = %p\n", - __func__, idev, isci_request); - - spin_lock_irqsave(&ihost->scic_lock, flags); - - io_request_completion = isci_request->io_request_completion; - - /* Note that we are not going to control - * the target to abort the request. - */ - set_bit(IREQ_COMPLETE_IN_TARGET, &isci_request->flags); - - /* Make sure the request wasn't just sitting around signalling - * device condition (if the request handle is NULL, then the - * request completed but needed additional handling here). - */ - if (!test_bit(IREQ_TERMINATED, &isci_request->flags)) { - was_terminated = true; - needs_cleanup_handling = true; - status = sci_controller_terminate_request(ihost, - idev, - isci_request); - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - /* - * The only time the request to terminate will - * fail is when the io request is completed and - * being aborted. - */ - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: sci_controller_terminate_request" - " returned = 0x%x\n", - __func__, status); - - isci_request->io_request_completion = NULL; - - } else { - if (was_terminated) { - dev_dbg(&ihost->pdev->dev, - "%s: before completion wait (%p/%p)\n", - __func__, isci_request, io_request_completion); - - /* Wait here for the request to complete. */ - termination_completed - = wait_for_completion_timeout( - io_request_completion, - msecs_to_jiffies(ISCI_TERMINATION_TIMEOUT_MSEC)); - - if (!termination_completed) { - - /* The request to terminate has timed out. */ - spin_lock_irqsave(&ihost->scic_lock, flags); - - /* Check for state changes. */ - if (!test_bit(IREQ_TERMINATED, - &isci_request->flags)) { - - /* The best we can do is to have the - * request die a silent death if it - * ever really completes. - */ - isci_request_mark_zombie(ihost, - isci_request); - needs_cleanup_handling = true; - } else - termination_completed = 1; - - spin_unlock_irqrestore(&ihost->scic_lock, - flags); - - if (!termination_completed) { - - dev_dbg(&ihost->pdev->dev, - "%s: *** Timeout waiting for " - "termination(%p/%p)\n", - __func__, io_request_completion, - isci_request); - - /* The request can no longer be referenced - * safely since it may go away if the - * termination every really does complete. - */ - isci_request = NULL; - } - } - if (termination_completed) - dev_dbg(&ihost->pdev->dev, - "%s: after completion wait (%p/%p)\n", - __func__, isci_request, io_request_completion); - } - - if (termination_completed) { - - isci_request->io_request_completion = NULL; - - /* Peek at the status of the request. This will tell - * us if there was special handling on the request such that it - * needs to be detached and freed here. - */ - spin_lock_irqsave(&isci_request->state_lock, flags); - - needs_cleanup_handling - = isci_request_is_dealloc_managed( - isci_request->status); - - spin_unlock_irqrestore(&isci_request->state_lock, flags); - - } - if (needs_cleanup_handling) { - - dev_dbg(&ihost->pdev->dev, - "%s: cleanup isci_device=%p, request=%p\n", - __func__, idev, isci_request); - - if (isci_request != NULL) { - spin_lock_irqsave(&ihost->scic_lock, flags); - isci_free_tag(ihost, isci_request->io_tag); - isci_request_change_state(isci_request, unallocated); - list_del_init(&isci_request->dev_node); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - } - } - } -} - -/** - * isci_terminate_pending_requests() - This function will change the all of the - * requests on the given device's state to "aborting", will terminate the - * requests, and wait for them to complete. This function must only be - * called from a thread that can wait. Note that the requests are all - * terminated and completed (back to the host, if started there). - * @isci_host: This parameter specifies SCU. - * @idev: This parameter specifies the target. - * - */ -void isci_terminate_pending_requests(struct isci_host *ihost, - struct isci_remote_device *idev) -{ - struct completion request_completion; - enum isci_request_status old_state; - unsigned long flags; - LIST_HEAD(list); - - spin_lock_irqsave(&ihost->scic_lock, flags); - list_splice_init(&idev->reqs_in_process, &list); - - /* assumes that isci_terminate_request_core deletes from the list */ - while (!list_empty(&list)) { - struct isci_request *ireq = list_entry(list.next, typeof(*ireq), dev_node); - - /* Change state to "terminating" if it is currently - * "started". - */ - old_state = isci_request_change_started_to_newstate(ireq, - &request_completion, - terminating); - switch (old_state) { - case started: - case completed: - case aborting: - break; - default: - /* termination in progress, or otherwise dispositioned. - * We know the request was on 'list' so should be safe - * to move it back to reqs_in_process - */ - list_move(&ireq->dev_node, &idev->reqs_in_process); - ireq = NULL; - break; - } - - if (!ireq) - continue; - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - init_completion(&request_completion); - - dev_dbg(&ihost->pdev->dev, - "%s: idev=%p request=%p; task=%p old_state=%d\n", - __func__, idev, ireq, - (!test_bit(IREQ_TMF, &ireq->flags) - ? isci_request_access_task(ireq) - : NULL), - old_state); - - /* If the old_state is started: - * This request was not already being aborted. If it had been, - * then the aborting I/O (ie. the TMF request) would not be in - * the aborting state, and thus would be terminated here. Note - * that since the TMF completion's call to the kernel function - * "complete()" does not happen until the pending I/O request - * terminate fully completes, we do not have to implement a - * special wait here for already aborting requests - the - * termination of the TMF request will force the request - * to finish it's already started terminate. - * - * If old_state == completed: - * This request completed from the SCU hardware perspective - * and now just needs cleaning up in terms of freeing the - * request and potentially calling up to libsas. - * - * If old_state == aborting: - * This request has already gone through a TMF timeout, but may - * not have been terminated; needs cleaning up at least. - */ - isci_terminate_request_core(ihost, idev, ireq); - spin_lock_irqsave(&ihost->scic_lock, flags); - } - spin_unlock_irqrestore(&ihost->scic_lock, flags); -} - -/** - * isci_task_send_lu_reset_sas() - This function is called by of the SAS Domain - * Template functions. - * @lun: This parameter specifies the lun to be reset. - * - * status, zero indicates success. - */ -static int isci_task_send_lu_reset_sas( - struct isci_host *isci_host, - struct isci_remote_device *isci_device, - u8 *lun) -{ - struct isci_tmf tmf; - int ret = TMF_RESP_FUNC_FAILED; - - dev_dbg(&isci_host->pdev->dev, - "%s: isci_host = %p, isci_device = %p\n", - __func__, isci_host, isci_device); - /* Send the LUN reset to the target. By the time the call returns, - * the TMF has fully exected in the target (in which case the return - * value is "TMF_RESP_FUNC_COMPLETE", or the request timed-out (or - * was otherwise unable to be executed ("TMF_RESP_FUNC_FAILED"). - */ - isci_task_build_tmf(&tmf, isci_tmf_ssp_lun_reset, NULL, NULL); - - #define ISCI_LU_RESET_TIMEOUT_MS 2000 /* 2 second timeout. */ - ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, ISCI_LU_RESET_TIMEOUT_MS); - - if (ret == TMF_RESP_FUNC_COMPLETE) - dev_dbg(&isci_host->pdev->dev, - "%s: %p: TMF_LU_RESET passed\n", - __func__, isci_device); - else - dev_dbg(&isci_host->pdev->dev, - "%s: %p: TMF_LU_RESET failed (%x)\n", - __func__, isci_device, ret); - - return ret; -} - -int isci_task_lu_reset(struct domain_device *dev, u8 *lun) -{ - struct isci_host *isci_host = dev_to_ihost(dev); - struct isci_remote_device *isci_device; - unsigned long flags; - int ret; - - spin_lock_irqsave(&isci_host->scic_lock, flags); - isci_device = isci_lookup_device(dev); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - - dev_dbg(&isci_host->pdev->dev, - "%s: domain_device=%p, isci_host=%p; isci_device=%p\n", - __func__, dev, isci_host, isci_device); - - if (!isci_device) { - /* If the device is gone, stop the escalations. */ - dev_dbg(&isci_host->pdev->dev, "%s: No dev\n", __func__); - - ret = TMF_RESP_FUNC_COMPLETE; - goto out; - } - - /* Send the task management part of the reset. */ - if (dev_is_sata(dev)) { - sas_ata_schedule_reset(dev); - ret = TMF_RESP_FUNC_COMPLETE; - } else - ret = isci_task_send_lu_reset_sas(isci_host, isci_device, lun); - - /* If the LUN reset worked, all the I/O can now be terminated. */ - if (ret == TMF_RESP_FUNC_COMPLETE) - /* Terminate all I/O now. */ - isci_terminate_pending_requests(isci_host, - isci_device); - - out: - isci_put_device(isci_device); - return ret; -} - - -/* int (*lldd_clear_nexus_port)(struct asd_sas_port *); */ -int isci_task_clear_nexus_port(struct asd_sas_port *port) -{ - return TMF_RESP_FUNC_FAILED; -} - - - -int isci_task_clear_nexus_ha(struct sas_ha_struct *ha) -{ - return TMF_RESP_FUNC_FAILED; -} - -/* Task Management Functions. Must be called from process context. */ - -/** - * isci_abort_task_process_cb() - This is a helper function for the abort task - * TMF command. It manages the request state with respect to the successful - * transmission / completion of the abort task request. - * @cb_state: This parameter specifies when this function was called - after - * the TMF request has been started and after it has timed-out. - * @tmf: This parameter specifies the TMF in progress. - * - * - */ -static void isci_abort_task_process_cb( - enum isci_tmf_cb_state cb_state, - struct isci_tmf *tmf, - void *cb_data) -{ - struct isci_request *old_request; - - old_request = (struct isci_request *)cb_data; - - dev_dbg(&old_request->isci_host->pdev->dev, - "%s: tmf=%p, old_request=%p\n", - __func__, tmf, old_request); - - switch (cb_state) { - - case isci_tmf_started: - /* The TMF has been started. Nothing to do here, since the - * request state was already set to "aborted" by the abort - * task function. - */ - if ((old_request->status != aborted) - && (old_request->status != completed)) - dev_dbg(&old_request->isci_host->pdev->dev, - "%s: Bad request status (%d): tmf=%p, old_request=%p\n", - __func__, old_request->status, tmf, old_request); - break; - - case isci_tmf_timed_out: - - /* Set the task's state to "aborting", since the abort task - * function thread set it to "aborted" (above) in anticipation - * of the task management request working correctly. Since the - * timeout has now fired, the TMF request failed. We set the - * state such that the request completion will indicate the - * device is no longer present. - */ - isci_request_change_state(old_request, aborting); - break; - - default: - dev_dbg(&old_request->isci_host->pdev->dev, - "%s: Bad cb_state (%d): tmf=%p, old_request=%p\n", - __func__, cb_state, tmf, old_request); - break; - } -} - -/** - * isci_task_abort_task() - This function is one of the SAS Domain Template - * functions. This function is called by libsas to abort a specified task. - * @task: This parameter specifies the SAS task to abort. - * - * status, zero indicates success. - */ -int isci_task_abort_task(struct sas_task *task) -{ - struct isci_host *isci_host = dev_to_ihost(task->dev); - DECLARE_COMPLETION_ONSTACK(aborted_io_completion); - struct isci_request *old_request = NULL; - enum isci_request_status old_state; - struct isci_remote_device *isci_device = NULL; - struct isci_tmf tmf; - int ret = TMF_RESP_FUNC_FAILED; - unsigned long flags; - int perform_termination = 0; - - /* Get the isci_request reference from the task. Note that - * this check does not depend on the pending request list - * in the device, because tasks driving resets may land here - * after completion in the core. - */ - spin_lock_irqsave(&isci_host->scic_lock, flags); - spin_lock(&task->task_state_lock); - - old_request = task->lldd_task; - - /* If task is already done, the request isn't valid */ - if (!(task->task_state_flags & SAS_TASK_STATE_DONE) && - (task->task_state_flags & SAS_TASK_AT_INITIATOR) && - old_request) - isci_device = isci_lookup_device(task->dev); - - spin_unlock(&task->task_state_lock); - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - - dev_dbg(&isci_host->pdev->dev, - "%s: dev = %p, task = %p, old_request == %p\n", - __func__, isci_device, task, old_request); - - /* Device reset conditions signalled in task_state_flags are the - * responsbility of libsas to observe at the start of the error - * handler thread. - */ - if (!isci_device || !old_request) { - /* The request has already completed and there - * is nothing to do here other than to set the task - * done bit, and indicate that the task abort function - * was sucessful. - */ - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags |= SAS_TASK_STATE_DONE; - task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | - SAS_TASK_STATE_PENDING); - spin_unlock_irqrestore(&task->task_state_lock, flags); - - ret = TMF_RESP_FUNC_COMPLETE; - - dev_dbg(&isci_host->pdev->dev, - "%s: abort task not needed for %p\n", - __func__, task); - goto out; - } - - spin_lock_irqsave(&isci_host->scic_lock, flags); - - /* Check the request status and change to "aborted" if currently - * "starting"; if true then set the I/O kernel completion - * struct that will be triggered when the request completes. - */ - old_state = isci_task_validate_request_to_abort( - old_request, isci_host, isci_device, - &aborted_io_completion); - if ((old_state != started) && - (old_state != completed) && - (old_state != aborting)) { - - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - - /* The request was already being handled by someone else (because - * they got to set the state away from started). - */ - dev_dbg(&isci_host->pdev->dev, - "%s: device = %p; old_request %p already being aborted\n", - __func__, - isci_device, old_request); - ret = TMF_RESP_FUNC_COMPLETE; - goto out; - } - if (task->task_proto == SAS_PROTOCOL_SMP || - sas_protocol_ata(task->task_proto) || - test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { - - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - - dev_dbg(&isci_host->pdev->dev, - "%s: %s request" - " or complete_in_target (%d), thus no TMF\n", - __func__, - ((task->task_proto == SAS_PROTOCOL_SMP) - ? "SMP" - : (sas_protocol_ata(task->task_proto) - ? "SATA/STP" - : "") - ), - test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)); - - if (test_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags)) { - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags |= SAS_TASK_STATE_DONE; - task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | - SAS_TASK_STATE_PENDING); - spin_unlock_irqrestore(&task->task_state_lock, flags); - ret = TMF_RESP_FUNC_COMPLETE; - } else { - spin_lock_irqsave(&task->task_state_lock, flags); - task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | - SAS_TASK_STATE_PENDING); - spin_unlock_irqrestore(&task->task_state_lock, flags); - } - - /* STP and SMP devices are not sent a TMF, but the - * outstanding I/O request is terminated below. This is - * because SATA/STP and SMP discovery path timeouts directly - * call the abort task interface for cleanup. - */ - perform_termination = 1; - - } else { - /* Fill in the tmf stucture */ - isci_task_build_abort_task_tmf(&tmf, isci_tmf_ssp_task_abort, - isci_abort_task_process_cb, - old_request); - - spin_unlock_irqrestore(&isci_host->scic_lock, flags); - - #define ISCI_ABORT_TASK_TIMEOUT_MS 500 /* 1/2 second timeout */ - ret = isci_task_execute_tmf(isci_host, isci_device, &tmf, - ISCI_ABORT_TASK_TIMEOUT_MS); - - if (ret == TMF_RESP_FUNC_COMPLETE) - perform_termination = 1; - else - dev_dbg(&isci_host->pdev->dev, - "%s: isci_task_send_tmf failed\n", __func__); - } - if (perform_termination) { - set_bit(IREQ_COMPLETE_IN_TARGET, &old_request->flags); - - /* Clean up the request on our side, and wait for the aborted - * I/O to complete. - */ - isci_terminate_request_core(isci_host, isci_device, - old_request); - } - - /* Make sure we do not leave a reference to aborted_io_completion */ - old_request->io_request_completion = NULL; - out: - isci_put_device(isci_device); - return ret; -} - -/** - * isci_task_abort_task_set() - This function is one of the SAS Domain Template - * functions. This is one of the Task Management functoins called by libsas, - * to abort all task for the given lun. - * @d_device: This parameter specifies the domain device associated with this - * request. - * @lun: This parameter specifies the lun associated with this request. - * - * status, zero indicates success. - */ -int isci_task_abort_task_set( - struct domain_device *d_device, - u8 *lun) -{ - return TMF_RESP_FUNC_FAILED; -} - - -/** - * isci_task_clear_aca() - This function is one of the SAS Domain Template - * functions. This is one of the Task Management functoins called by libsas. - * @d_device: This parameter specifies the domain device associated with this - * request. - * @lun: This parameter specifies the lun associated with this request. - * - * status, zero indicates success. - */ -int isci_task_clear_aca( - struct domain_device *d_device, - u8 *lun) -{ - return TMF_RESP_FUNC_FAILED; -} - - - -/** - * isci_task_clear_task_set() - This function is one of the SAS Domain Template - * functions. This is one of the Task Management functoins called by libsas. - * @d_device: This parameter specifies the domain device associated with this - * request. - * @lun: This parameter specifies the lun associated with this request. - * - * status, zero indicates success. - */ -int isci_task_clear_task_set( - struct domain_device *d_device, - u8 *lun) -{ - return TMF_RESP_FUNC_FAILED; -} - - -/** - * isci_task_query_task() - This function is implemented to cause libsas to - * correctly escalate the failed abort to a LUN or target reset (this is - * because sas_scsi_find_task libsas function does not correctly interpret - * all return codes from the abort task call). When TMF_RESP_FUNC_SUCC is - * returned, libsas turns this into a LUN reset; when FUNC_FAILED is - * returned, libsas will turn this into a target reset - * @task: This parameter specifies the sas task being queried. - * @lun: This parameter specifies the lun associated with this request. - * - * status, zero indicates success. - */ -int isci_task_query_task( - struct sas_task *task) -{ - /* See if there is a pending device reset for this device. */ - if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) - return TMF_RESP_FUNC_FAILED; - else - return TMF_RESP_FUNC_SUCC; -} - -/* - * isci_task_request_complete() - This function is called by the sci core when - * an task request completes. - * @ihost: This parameter specifies the ISCI host object - * @ireq: This parameter is the completed isci_request object. - * @completion_status: This parameter specifies the completion status from the - * sci core. - * - * none. - */ -void -isci_task_request_complete(struct isci_host *ihost, - struct isci_request *ireq, - enum sci_task_status completion_status) -{ - struct isci_tmf *tmf = isci_request_access_tmf(ireq); - struct completion *tmf_complete = NULL; - struct completion *request_complete = ireq->io_request_completion; - - dev_dbg(&ihost->pdev->dev, - "%s: request = %p, status=%d\n", - __func__, ireq, completion_status); - - isci_request_change_state(ireq, completed); - - set_bit(IREQ_COMPLETE_IN_TARGET, &ireq->flags); - - if (tmf) { - tmf->status = completion_status; - - if (tmf->proto == SAS_PROTOCOL_SSP) { - memcpy(&tmf->resp.resp_iu, - &ireq->ssp.rsp, - SSP_RESP_IU_MAX_SIZE); - } else if (tmf->proto == SAS_PROTOCOL_SATA) { - memcpy(&tmf->resp.d2h_fis, - &ireq->stp.rsp, - sizeof(struct dev_to_host_fis)); - } - /* PRINT_TMF( ((struct isci_tmf *)request->task)); */ - tmf_complete = tmf->complete; - } - sci_controller_complete_io(ihost, ireq->target_device, ireq); - /* set the 'terminated' flag handle to make sure it cannot be terminated - * or completed again. - */ - set_bit(IREQ_TERMINATED, &ireq->flags); - - /* As soon as something is in the terminate path, deallocation is - * managed there. Note that the final non-managed state of a task - * request is "completed". - */ - if ((ireq->status == completed) || - !isci_request_is_dealloc_managed(ireq->status)) { - isci_request_change_state(ireq, unallocated); - isci_free_tag(ihost, ireq->io_tag); - list_del_init(&ireq->dev_node); - } - - /* "request_complete" is set if the task was being terminated. */ - if (request_complete) - complete(request_complete); - - /* The task management part completes last. */ - if (tmf_complete) - complete(tmf_complete); -} - -static int isci_reset_device(struct isci_host *ihost, - struct domain_device *dev, - struct isci_remote_device *idev) -{ - int rc; - unsigned long flags; - enum sci_status status; - struct sas_phy *phy = sas_get_local_phy(dev); - struct isci_port *iport = dev->port->lldd_port; - - dev_dbg(&ihost->pdev->dev, "%s: idev %p\n", __func__, idev); - - spin_lock_irqsave(&ihost->scic_lock, flags); - status = sci_remote_device_reset(idev); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: sci_remote_device_reset(%p) returned %d!\n", - __func__, idev, status); - rc = TMF_RESP_FUNC_FAILED; - goto out; - } - - if (scsi_is_sas_phy_local(phy)) { - struct isci_phy *iphy = &ihost->phys[phy->number]; - - rc = isci_port_perform_hard_reset(ihost, iport, iphy); - } else - rc = sas_phy_reset(phy, !dev_is_sata(dev)); - - /* Terminate in-progress I/O now. */ - isci_remote_device_nuke_requests(ihost, idev); - - /* Since all pending TCs have been cleaned, resume the RNC. */ - spin_lock_irqsave(&ihost->scic_lock, flags); - status = sci_remote_device_reset_complete(idev); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (status != SCI_SUCCESS) { - dev_dbg(&ihost->pdev->dev, - "%s: sci_remote_device_reset_complete(%p) " - "returned %d!\n", __func__, idev, status); - } - - dev_dbg(&ihost->pdev->dev, "%s: idev %p complete.\n", __func__, idev); - out: - sas_put_local_phy(phy); - return rc; -} - -int isci_task_I_T_nexus_reset(struct domain_device *dev) -{ - struct isci_host *ihost = dev_to_ihost(dev); - struct isci_remote_device *idev; - unsigned long flags; - int ret; - - spin_lock_irqsave(&ihost->scic_lock, flags); - idev = isci_lookup_device(dev); - spin_unlock_irqrestore(&ihost->scic_lock, flags); - - if (!idev) { - /* XXX: need to cleanup any ireqs targeting this - * domain_device - */ - ret = TMF_RESP_FUNC_COMPLETE; - goto out; - } - - ret = isci_reset_device(ihost, dev, idev); - out: - isci_put_device(idev); - return ret; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/task.h b/ANDROID_3.4.5/drivers/scsi/isci/task.h deleted file mode 100644 index 7b6d0e32..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/task.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef _ISCI_TASK_H_ -#define _ISCI_TASK_H_ - -#include -#include "host.h" - -#define ISCI_TERMINATION_TIMEOUT_MSEC 500 - -struct isci_request; - -/** - * enum isci_tmf_cb_state - This enum defines the possible states in which the - * TMF callback function is invoked during the TMF execution process. - * - * - */ -enum isci_tmf_cb_state { - - isci_tmf_init_state = 0, - isci_tmf_started, - isci_tmf_timed_out -}; - -/** - * enum isci_tmf_function_codes - This enum defines the possible preparations - * of task management requests. - * - * - */ -enum isci_tmf_function_codes { - - isci_tmf_func_none = 0, - isci_tmf_ssp_task_abort = TMF_ABORT_TASK, - isci_tmf_ssp_lun_reset = TMF_LU_RESET, -}; -/** - * struct isci_tmf - This class represents the task management object which - * acts as an interface to libsas for processing task management requests - * - * - */ -struct isci_tmf { - - struct completion *complete; - enum sas_protocol proto; - union { - struct ssp_response_iu resp_iu; - struct dev_to_host_fis d2h_fis; - u8 rsp_buf[SSP_RESP_IU_MAX_SIZE]; - } resp; - unsigned char lun[8]; - u16 io_tag; - enum isci_tmf_function_codes tmf_code; - int status; - - /* The optional callback function allows the user process to - * track the TMF transmit / timeout conditions. - */ - void (*cb_state_func)( - enum isci_tmf_cb_state, - struct isci_tmf *, void *); - void *cb_data; - -}; - -static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf) -{ - if (SAS_PROTOCOL_SATA == tmf->proto) - dev_dbg(&ihost->pdev->dev, - "%s: status = %x\n" - "tmf->resp.d2h_fis.status = %x\n" - "tmf->resp.d2h_fis.error = %x\n", - __func__, - tmf->status, - tmf->resp.d2h_fis.status, - tmf->resp.d2h_fis.error); - else - dev_dbg(&ihost->pdev->dev, - "%s: status = %x\n" - "tmf->resp.resp_iu.data_present = %x\n" - "tmf->resp.resp_iu.status = %x\n" - "tmf->resp.resp_iu.data_length = %x\n" - "tmf->resp.resp_iu.data[0] = %x\n" - "tmf->resp.resp_iu.data[1] = %x\n" - "tmf->resp.resp_iu.data[2] = %x\n" - "tmf->resp.resp_iu.data[3] = %x\n", - __func__, - tmf->status, - tmf->resp.resp_iu.datapres, - tmf->resp.resp_iu.status, - be32_to_cpu(tmf->resp.resp_iu.response_data_len), - tmf->resp.resp_iu.resp_data[0], - tmf->resp.resp_iu.resp_data[1], - tmf->resp.resp_iu.resp_data[2], - tmf->resp.resp_iu.resp_data[3]); -} - - -int isci_task_execute_task( - struct sas_task *task, - int num, - gfp_t gfp_flags); - -int isci_task_abort_task( - struct sas_task *task); - -int isci_task_abort_task_set( - struct domain_device *d_device, - u8 *lun); - -int isci_task_clear_aca( - struct domain_device *d_device, - u8 *lun); - -int isci_task_clear_task_set( - struct domain_device *d_device, - u8 *lun); - -int isci_task_query_task( - struct sas_task *task); - -int isci_task_lu_reset( - struct domain_device *d_device, - u8 *lun); - -int isci_task_clear_nexus_port( - struct asd_sas_port *port); - -int isci_task_clear_nexus_ha( - struct sas_ha_struct *ha); - -int isci_task_I_T_nexus_reset( - struct domain_device *d_device); - -void isci_task_request_complete( - struct isci_host *isci_host, - struct isci_request *request, - enum sci_task_status completion_status); - -u16 isci_task_ssp_request_get_io_tag_to_manage( - struct isci_request *request); - -u8 isci_task_ssp_request_get_function( - struct isci_request *request); - - -void *isci_task_ssp_request_get_response_data_address( - struct isci_request *request); - -u32 isci_task_ssp_request_get_response_data_length( - struct isci_request *request); - -int isci_queuecommand( - struct scsi_cmnd *scsi_cmd, - void (*donefunc)(struct scsi_cmnd *)); - -/** - * enum isci_completion_selection - This enum defines the possible actions to - * take with respect to a given request's notification back to libsas. - * - * - */ -enum isci_completion_selection { - - isci_perform_normal_io_completion, /* Normal notify (task_done) */ - isci_perform_aborted_io_completion, /* No notification. */ - isci_perform_error_io_completion /* Use sas_task_abort */ -}; - -/** - * isci_task_set_completion_status() - This function sets the completion status - * for the request. - * @task: This parameter is the completed request. - * @response: This parameter is the response code for the completed task. - * @status: This parameter is the status code for the completed task. - * -* @return The new notification mode for the request. -*/ -static inline enum isci_completion_selection -isci_task_set_completion_status( - struct sas_task *task, - enum service_response response, - enum exec_status status, - enum isci_completion_selection task_notification_selection) -{ - unsigned long flags; - - spin_lock_irqsave(&task->task_state_lock, flags); - - /* If a device reset is being indicated, make sure the I/O - * is in the error path. - */ - if (task->task_state_flags & SAS_TASK_NEED_DEV_RESET) { - /* Fail the I/O to make sure it goes into the error path. */ - response = SAS_TASK_UNDELIVERED; - status = SAM_STAT_TASK_ABORTED; - - task_notification_selection = isci_perform_error_io_completion; - } - task->task_status.resp = response; - task->task_status.stat = status; - - switch (task->task_proto) { - - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - - if (task_notification_selection - == isci_perform_error_io_completion) { - /* SATA/STP I/O has it's own means of scheduling device - * error handling on the normal path. - */ - task_notification_selection - = isci_perform_normal_io_completion; - } - break; - default: - break; - } - - switch (task_notification_selection) { - - case isci_perform_error_io_completion: - - if (task->task_proto == SAS_PROTOCOL_SMP) { - /* There is no error escalation in the SMP case. - * Convert to a normal completion to avoid the - * timeout in the discovery path and to let the - * next action take place quickly. - */ - task_notification_selection - = isci_perform_normal_io_completion; - - /* Fall through to the normal case... */ - } else { - /* Use sas_task_abort */ - /* Leave SAS_TASK_STATE_DONE clear - * Leave SAS_TASK_AT_INITIATOR set. - */ - break; - } - - case isci_perform_aborted_io_completion: - /* This path can occur with task-managed requests as well as - * requests terminated because of LUN or device resets. - */ - /* Fall through to the normal case... */ - case isci_perform_normal_io_completion: - /* Normal notification (task_done) */ - task->task_state_flags |= SAS_TASK_STATE_DONE; - task->task_state_flags &= ~(SAS_TASK_AT_INITIATOR | - SAS_TASK_STATE_PENDING); - break; - default: - WARN_ONCE(1, "unknown task_notification_selection: %d\n", - task_notification_selection); - break; - } - - spin_unlock_irqrestore(&task->task_state_lock, flags); - - return task_notification_selection; - -} -#endif /* !defined(_SCI_TASK_H_) */ diff --git a/ANDROID_3.4.5/drivers/scsi/isci/unsolicited_frame_control.c b/ANDROID_3.4.5/drivers/scsi/isci/unsolicited_frame_control.c deleted file mode 100644 index 16f88ab9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/unsolicited_frame_control.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "host.h" -#include "unsolicited_frame_control.h" -#include "registers.h" - -int sci_unsolicited_frame_control_construct(struct isci_host *ihost) -{ - struct sci_unsolicited_frame_control *uf_control = &ihost->uf_control; - struct sci_unsolicited_frame *uf; - u32 buf_len, header_len, i; - dma_addr_t dma; - size_t size; - void *virt; - - /* - * Prepare all of the memory sizes for the UF headers, UF address - * table, and UF buffers themselves. - */ - buf_len = SCU_MAX_UNSOLICITED_FRAMES * SCU_UNSOLICITED_FRAME_BUFFER_SIZE; - header_len = SCU_MAX_UNSOLICITED_FRAMES * sizeof(struct scu_unsolicited_frame_header); - size = buf_len + header_len + SCU_MAX_UNSOLICITED_FRAMES * sizeof(uf_control->address_table.array[0]); - - /* - * The Unsolicited Frame buffers are set at the start of the UF - * memory descriptor entry. The headers and address table will be - * placed after the buffers. - */ - virt = dmam_alloc_coherent(&ihost->pdev->dev, size, &dma, GFP_KERNEL); - if (!virt) - return -ENOMEM; - - /* - * Program the location of the UF header table into the SCU. - * Notes: - * - The address must align on a 64-byte boundary. Guaranteed to be - * on 64-byte boundary already 1KB boundary for unsolicited frames. - * - Program unused header entries to overlap with the last - * unsolicited frame. The silicon will never DMA to these unused - * headers, since we program the UF address table pointers to - * NULL. - */ - uf_control->headers.physical_address = dma + buf_len; - uf_control->headers.array = virt + buf_len; - - /* - * Program the location of the UF address table into the SCU. - * Notes: - * - The address must align on a 64-bit boundary. Guaranteed to be on 64 - * byte boundary already due to above programming headers being on a - * 64-bit boundary and headers are on a 64-bytes in size. - */ - uf_control->address_table.physical_address = dma + buf_len + header_len; - uf_control->address_table.array = virt + buf_len + header_len; - uf_control->get = 0; - - /* - * UF buffer requirements are: - * - The last entry in the UF queue is not NULL. - * - There is a power of 2 number of entries (NULL or not-NULL) - * programmed into the queue. - * - Aligned on a 1KB boundary. */ - - /* - * Program the actual used UF buffers into the UF address table and - * the controller's array of UFs. - */ - for (i = 0; i < SCU_MAX_UNSOLICITED_FRAMES; i++) { - uf = &uf_control->buffers.array[i]; - - uf_control->address_table.array[i] = dma; - - uf->buffer = virt; - uf->header = &uf_control->headers.array[i]; - uf->state = UNSOLICITED_FRAME_EMPTY; - - /* - * Increment the address of the physical and virtual memory - * pointers. Everything is aligned on 1k boundary with an - * increment of 1k. - */ - virt += SCU_UNSOLICITED_FRAME_BUFFER_SIZE; - dma += SCU_UNSOLICITED_FRAME_BUFFER_SIZE; - } - - return 0; -} - -enum sci_status sci_unsolicited_frame_control_get_header(struct sci_unsolicited_frame_control *uf_control, - u32 frame_index, - void **frame_header) -{ - if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) { - /* Skip the first word in the frame since this is a controll word used - * by the hardware. - */ - *frame_header = &uf_control->buffers.array[frame_index].header->data; - - return SCI_SUCCESS; - } - - return SCI_FAILURE_INVALID_PARAMETER_VALUE; -} - -enum sci_status sci_unsolicited_frame_control_get_buffer(struct sci_unsolicited_frame_control *uf_control, - u32 frame_index, - void **frame_buffer) -{ - if (frame_index < SCU_MAX_UNSOLICITED_FRAMES) { - *frame_buffer = uf_control->buffers.array[frame_index].buffer; - - return SCI_SUCCESS; - } - - return SCI_FAILURE_INVALID_PARAMETER_VALUE; -} - -bool sci_unsolicited_frame_control_release_frame(struct sci_unsolicited_frame_control *uf_control, - u32 frame_index) -{ - u32 frame_get; - u32 frame_cycle; - - frame_get = uf_control->get & (SCU_MAX_UNSOLICITED_FRAMES - 1); - frame_cycle = uf_control->get & SCU_MAX_UNSOLICITED_FRAMES; - - /* - * In the event there are NULL entries in the UF table, we need to - * advance the get pointer in order to find out if this frame should - * be released (i.e. update the get pointer) - */ - while (lower_32_bits(uf_control->address_table.array[frame_get]) == 0 && - upper_32_bits(uf_control->address_table.array[frame_get]) == 0 && - frame_get < SCU_MAX_UNSOLICITED_FRAMES) - frame_get++; - - /* - * The table has a NULL entry as it's last element. This is - * illegal. - */ - BUG_ON(frame_get >= SCU_MAX_UNSOLICITED_FRAMES); - if (frame_index >= SCU_MAX_UNSOLICITED_FRAMES) - return false; - - uf_control->buffers.array[frame_index].state = UNSOLICITED_FRAME_RELEASED; - - if (frame_get != frame_index) { - /* - * Frames remain in use until we advance the get pointer - * so there is nothing we can do here - */ - return false; - } - - /* - * The frame index is equal to the current get pointer so we - * can now free up all of the frame entries that - */ - while (uf_control->buffers.array[frame_get].state == UNSOLICITED_FRAME_RELEASED) { - uf_control->buffers.array[frame_get].state = UNSOLICITED_FRAME_EMPTY; - - if (frame_get+1 == SCU_MAX_UNSOLICITED_FRAMES-1) { - frame_cycle ^= SCU_MAX_UNSOLICITED_FRAMES; - frame_get = 0; - } else - frame_get++; - } - - uf_control->get = SCU_UFQGP_GEN_BIT(ENABLE_BIT) | frame_cycle | frame_get; - - return true; -} diff --git a/ANDROID_3.4.5/drivers/scsi/isci/unsolicited_frame_control.h b/ANDROID_3.4.5/drivers/scsi/isci/unsolicited_frame_control.h deleted file mode 100644 index 75d89668..00000000 --- a/ANDROID_3.4.5/drivers/scsi/isci/unsolicited_frame_control.h +++ /dev/null @@ -1,278 +0,0 @@ -/* - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _SCIC_SDS_UNSOLICITED_FRAME_CONTROL_H_ -#define _SCIC_SDS_UNSOLICITED_FRAME_CONTROL_H_ - -#include "isci.h" - -#define SCU_UNSOLICITED_FRAME_HEADER_DATA_DWORDS 15 - -/** - * struct scu_unsolicited_frame_header - - * - * This structure delineates the format of an unsolicited frame header. The - * first DWORD are UF attributes defined by the silicon architecture. The data - * depicts actual header information received on the link. - */ -struct scu_unsolicited_frame_header { - /** - * This field indicates if there is an Initiator Index Table entry with - * which this header is associated. - */ - u32 iit_exists:1; - - /** - * This field simply indicates the protocol type (i.e. SSP, STP, SMP). - */ - u32 protocol_type:3; - - /** - * This field indicates if the frame is an address frame (IAF or OAF) - * or if it is a information unit frame. - */ - u32 is_address_frame:1; - - /** - * This field simply indicates the connection rate at which the frame - * was received. - */ - u32 connection_rate:4; - - u32 reserved:23; - - /** - * This field represents the actual header data received on the link. - */ - u32 data[SCU_UNSOLICITED_FRAME_HEADER_DATA_DWORDS]; - -}; - - - -/** - * enum unsolicited_frame_state - - * - * This enumeration represents the current unsolicited frame state. The - * controller object can not updtate the hardware unsolicited frame put pointer - * unless it has already processed the priror unsolicited frames. - */ -enum unsolicited_frame_state { - /** - * This state is when the frame is empty and not in use. It is - * different from the released state in that the hardware could DMA - * data to this frame buffer. - */ - UNSOLICITED_FRAME_EMPTY, - - /** - * This state is set when the frame buffer is in use by by some - * object in the system. - */ - UNSOLICITED_FRAME_IN_USE, - - /** - * This state is set when the frame is returned to the free pool - * but one or more frames prior to this one are still in use. - * Once all of the frame before this one are freed it will go to - * the empty state. - */ - UNSOLICITED_FRAME_RELEASED, - - UNSOLICITED_FRAME_MAX_STATES -}; - -/** - * struct sci_unsolicited_frame - - * - * This is the unsolicited frame data structure it acts as the container for - * the current frame state, frame header and frame buffer. - */ -struct sci_unsolicited_frame { - /** - * This field contains the current frame state - */ - enum unsolicited_frame_state state; - - /** - * This field points to the frame header data. - */ - struct scu_unsolicited_frame_header *header; - - /** - * This field points to the frame buffer data. - */ - void *buffer; - -}; - -/** - * struct sci_uf_header_array - - * - * This structure contains all of the unsolicited frame header information. - */ -struct sci_uf_header_array { - /** - * This field is represents a virtual pointer to the start - * address of the UF address table. The table contains - * 64-bit pointers as required by the hardware. - */ - struct scu_unsolicited_frame_header *array; - - /** - * This field specifies the physical address location for the UF - * buffer array. - */ - dma_addr_t physical_address; - -}; - -/** - * struct sci_uf_buffer_array - - * - * This structure contains all of the unsolicited frame buffer (actual payload) - * information. - */ -struct sci_uf_buffer_array { - /** - * This field is the unsolicited frame data its used to manage - * the data for the unsolicited frame requests. It also represents - * the virtual address location that corresponds to the - * physical_address field. - */ - struct sci_unsolicited_frame array[SCU_MAX_UNSOLICITED_FRAMES]; - - /** - * This field specifies the physical address location for the UF - * buffer array. - */ - dma_addr_t physical_address; -}; - -/** - * struct sci_uf_address_table_array - - * - * This object maintains all of the unsolicited frame address table specific - * data. The address table is a collection of 64-bit pointers that point to - * 1KB buffers into which the silicon will DMA unsolicited frames. - */ -struct sci_uf_address_table_array { - /** - * This field represents a virtual pointer that refers to the - * starting address of the UF address table. - * 64-bit pointers are required by the hardware. - */ - u64 *array; - - /** - * This field specifies the physical address location for the UF - * address table. - */ - dma_addr_t physical_address; - -}; - -/** - * struct sci_unsolicited_frame_control - - * - * This object contains all of the data necessary to handle unsolicited frames. - */ -struct sci_unsolicited_frame_control { - /** - * This field is the software copy of the unsolicited frame queue - * get pointer. The controller object writes this value to the - * hardware to let the hardware put more unsolicited frame entries. - */ - u32 get; - - /** - * This field contains all of the unsolicited frame header - * specific fields. - */ - struct sci_uf_header_array headers; - - /** - * This field contains all of the unsolicited frame buffer - * specific fields. - */ - struct sci_uf_buffer_array buffers; - - /** - * This field contains all of the unsolicited frame address table - * specific fields. - */ - struct sci_uf_address_table_array address_table; - -}; - -struct isci_host; - -int sci_unsolicited_frame_control_construct(struct isci_host *ihost); - -enum sci_status sci_unsolicited_frame_control_get_header( - struct sci_unsolicited_frame_control *uf_control, - u32 frame_index, - void **frame_header); - -enum sci_status sci_unsolicited_frame_control_get_buffer( - struct sci_unsolicited_frame_control *uf_control, - u32 frame_index, - void **frame_buffer); - -bool sci_unsolicited_frame_control_release_frame( - struct sci_unsolicited_frame_control *uf_control, - u32 frame_index); - -#endif /* _SCIC_SDS_UNSOLICITED_FRAME_CONTROL_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/iscsi_boot_sysfs.c b/ANDROID_3.4.5/drivers/scsi/iscsi_boot_sysfs.c deleted file mode 100644 index 14c1c8f6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/iscsi_boot_sysfs.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Export the iSCSI boot info to userland via sysfs. - * - * Copyright (C) 2010 Red Hat, Inc. All rights reserved. - * Copyright (C) 2010 Mike Christie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License v2.0 as published by - * the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include - - -MODULE_AUTHOR("Mike Christie "); -MODULE_DESCRIPTION("sysfs interface and helpers to export iSCSI boot information"); -MODULE_LICENSE("GPL"); -/* - * The kobject and attribute structures. - */ -struct iscsi_boot_attr { - struct attribute attr; - int type; - ssize_t (*show) (void *data, int type, char *buf); -}; - -/* - * The routine called for all sysfs attributes. - */ -static ssize_t iscsi_boot_show_attribute(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct iscsi_boot_kobj *boot_kobj = - container_of(kobj, struct iscsi_boot_kobj, kobj); - struct iscsi_boot_attr *boot_attr = - container_of(attr, struct iscsi_boot_attr, attr); - ssize_t ret = -EIO; - char *str = buf; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (boot_kobj->show) - ret = boot_kobj->show(boot_kobj->data, boot_attr->type, str); - return ret; -} - -static const struct sysfs_ops iscsi_boot_attr_ops = { - .show = iscsi_boot_show_attribute, -}; - -static void iscsi_boot_kobj_release(struct kobject *kobj) -{ - struct iscsi_boot_kobj *boot_kobj = - container_of(kobj, struct iscsi_boot_kobj, kobj); - - if (boot_kobj->release) - boot_kobj->release(boot_kobj->data); - kfree(boot_kobj); -} - -static struct kobj_type iscsi_boot_ktype = { - .release = iscsi_boot_kobj_release, - .sysfs_ops = &iscsi_boot_attr_ops, -}; - -#define iscsi_boot_rd_attr(fnname, sysfs_name, attr_type) \ -static struct iscsi_boot_attr iscsi_boot_attr_##fnname = { \ - .attr = { .name = __stringify(sysfs_name), .mode = 0444 }, \ - .type = attr_type, \ -} - -/* Target attrs */ -iscsi_boot_rd_attr(tgt_index, index, ISCSI_BOOT_TGT_INDEX); -iscsi_boot_rd_attr(tgt_flags, flags, ISCSI_BOOT_TGT_FLAGS); -iscsi_boot_rd_attr(tgt_ip, ip-addr, ISCSI_BOOT_TGT_IP_ADDR); -iscsi_boot_rd_attr(tgt_port, port, ISCSI_BOOT_TGT_PORT); -iscsi_boot_rd_attr(tgt_lun, lun, ISCSI_BOOT_TGT_LUN); -iscsi_boot_rd_attr(tgt_chap, chap-type, ISCSI_BOOT_TGT_CHAP_TYPE); -iscsi_boot_rd_attr(tgt_nic, nic-assoc, ISCSI_BOOT_TGT_NIC_ASSOC); -iscsi_boot_rd_attr(tgt_name, target-name, ISCSI_BOOT_TGT_NAME); -iscsi_boot_rd_attr(tgt_chap_name, chap-name, ISCSI_BOOT_TGT_CHAP_NAME); -iscsi_boot_rd_attr(tgt_chap_secret, chap-secret, ISCSI_BOOT_TGT_CHAP_SECRET); -iscsi_boot_rd_attr(tgt_chap_rev_name, rev-chap-name, - ISCSI_BOOT_TGT_REV_CHAP_NAME); -iscsi_boot_rd_attr(tgt_chap_rev_secret, rev-chap-name-secret, - ISCSI_BOOT_TGT_REV_CHAP_SECRET); - -static struct attribute *target_attrs[] = { - &iscsi_boot_attr_tgt_index.attr, - &iscsi_boot_attr_tgt_flags.attr, - &iscsi_boot_attr_tgt_ip.attr, - &iscsi_boot_attr_tgt_port.attr, - &iscsi_boot_attr_tgt_lun.attr, - &iscsi_boot_attr_tgt_chap.attr, - &iscsi_boot_attr_tgt_nic.attr, - &iscsi_boot_attr_tgt_name.attr, - &iscsi_boot_attr_tgt_chap_name.attr, - &iscsi_boot_attr_tgt_chap_secret.attr, - &iscsi_boot_attr_tgt_chap_rev_name.attr, - &iscsi_boot_attr_tgt_chap_rev_secret.attr, - NULL -}; - -static umode_t iscsi_boot_tgt_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) -{ - struct iscsi_boot_kobj *boot_kobj = - container_of(kobj, struct iscsi_boot_kobj, kobj); - - if (attr == &iscsi_boot_attr_tgt_index.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_INDEX); - else if (attr == &iscsi_boot_attr_tgt_flags.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_FLAGS); - else if (attr == &iscsi_boot_attr_tgt_ip.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_IP_ADDR); - else if (attr == &iscsi_boot_attr_tgt_port.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_PORT); - else if (attr == &iscsi_boot_attr_tgt_lun.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_LUN); - else if (attr == &iscsi_boot_attr_tgt_chap.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_CHAP_TYPE); - else if (attr == &iscsi_boot_attr_tgt_nic.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_NIC_ASSOC); - else if (attr == &iscsi_boot_attr_tgt_name.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_NAME); - else if (attr == &iscsi_boot_attr_tgt_chap_name.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_CHAP_NAME); - else if (attr == &iscsi_boot_attr_tgt_chap_secret.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_CHAP_SECRET); - else if (attr == &iscsi_boot_attr_tgt_chap_rev_name.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_REV_CHAP_NAME); - else if (attr == &iscsi_boot_attr_tgt_chap_rev_secret.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_TGT_REV_CHAP_SECRET); - return 0; -} - -static struct attribute_group iscsi_boot_target_attr_group = { - .attrs = target_attrs, - .is_visible = iscsi_boot_tgt_attr_is_visible, -}; - -/* Ethernet attrs */ -iscsi_boot_rd_attr(eth_index, index, ISCSI_BOOT_ETH_INDEX); -iscsi_boot_rd_attr(eth_flags, flags, ISCSI_BOOT_ETH_FLAGS); -iscsi_boot_rd_attr(eth_ip, ip-addr, ISCSI_BOOT_ETH_IP_ADDR); -iscsi_boot_rd_attr(eth_subnet, subnet-mask, ISCSI_BOOT_ETH_SUBNET_MASK); -iscsi_boot_rd_attr(eth_origin, origin, ISCSI_BOOT_ETH_ORIGIN); -iscsi_boot_rd_attr(eth_gateway, gateway, ISCSI_BOOT_ETH_GATEWAY); -iscsi_boot_rd_attr(eth_primary_dns, primary-dns, ISCSI_BOOT_ETH_PRIMARY_DNS); -iscsi_boot_rd_attr(eth_secondary_dns, secondary-dns, - ISCSI_BOOT_ETH_SECONDARY_DNS); -iscsi_boot_rd_attr(eth_dhcp, dhcp, ISCSI_BOOT_ETH_DHCP); -iscsi_boot_rd_attr(eth_vlan, vlan, ISCSI_BOOT_ETH_VLAN); -iscsi_boot_rd_attr(eth_mac, mac, ISCSI_BOOT_ETH_MAC); -iscsi_boot_rd_attr(eth_hostname, hostname, ISCSI_BOOT_ETH_HOSTNAME); - -static struct attribute *ethernet_attrs[] = { - &iscsi_boot_attr_eth_index.attr, - &iscsi_boot_attr_eth_flags.attr, - &iscsi_boot_attr_eth_ip.attr, - &iscsi_boot_attr_eth_subnet.attr, - &iscsi_boot_attr_eth_origin.attr, - &iscsi_boot_attr_eth_gateway.attr, - &iscsi_boot_attr_eth_primary_dns.attr, - &iscsi_boot_attr_eth_secondary_dns.attr, - &iscsi_boot_attr_eth_dhcp.attr, - &iscsi_boot_attr_eth_vlan.attr, - &iscsi_boot_attr_eth_mac.attr, - &iscsi_boot_attr_eth_hostname.attr, - NULL -}; - -static umode_t iscsi_boot_eth_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) -{ - struct iscsi_boot_kobj *boot_kobj = - container_of(kobj, struct iscsi_boot_kobj, kobj); - - if (attr == &iscsi_boot_attr_eth_index.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_INDEX); - else if (attr == &iscsi_boot_attr_eth_flags.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_FLAGS); - else if (attr == &iscsi_boot_attr_eth_ip.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_IP_ADDR); - else if (attr == &iscsi_boot_attr_eth_subnet.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_SUBNET_MASK); - else if (attr == &iscsi_boot_attr_eth_origin.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_ORIGIN); - else if (attr == &iscsi_boot_attr_eth_gateway.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_GATEWAY); - else if (attr == &iscsi_boot_attr_eth_primary_dns.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_PRIMARY_DNS); - else if (attr == &iscsi_boot_attr_eth_secondary_dns.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_SECONDARY_DNS); - else if (attr == &iscsi_boot_attr_eth_dhcp.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_DHCP); - else if (attr == &iscsi_boot_attr_eth_vlan.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_VLAN); - else if (attr == &iscsi_boot_attr_eth_mac.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_MAC); - else if (attr == &iscsi_boot_attr_eth_hostname.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_ETH_HOSTNAME); - return 0; -} - -static struct attribute_group iscsi_boot_ethernet_attr_group = { - .attrs = ethernet_attrs, - .is_visible = iscsi_boot_eth_attr_is_visible, -}; - -/* Initiator attrs */ -iscsi_boot_rd_attr(ini_index, index, ISCSI_BOOT_INI_INDEX); -iscsi_boot_rd_attr(ini_flags, flags, ISCSI_BOOT_INI_FLAGS); -iscsi_boot_rd_attr(ini_isns, isns-server, ISCSI_BOOT_INI_ISNS_SERVER); -iscsi_boot_rd_attr(ini_slp, slp-server, ISCSI_BOOT_INI_SLP_SERVER); -iscsi_boot_rd_attr(ini_primary_radius, pri-radius-server, - ISCSI_BOOT_INI_PRI_RADIUS_SERVER); -iscsi_boot_rd_attr(ini_secondary_radius, sec-radius-server, - ISCSI_BOOT_INI_SEC_RADIUS_SERVER); -iscsi_boot_rd_attr(ini_name, initiator-name, ISCSI_BOOT_INI_INITIATOR_NAME); - -static struct attribute *initiator_attrs[] = { - &iscsi_boot_attr_ini_index.attr, - &iscsi_boot_attr_ini_flags.attr, - &iscsi_boot_attr_ini_isns.attr, - &iscsi_boot_attr_ini_slp.attr, - &iscsi_boot_attr_ini_primary_radius.attr, - &iscsi_boot_attr_ini_secondary_radius.attr, - &iscsi_boot_attr_ini_name.attr, - NULL -}; - -static umode_t iscsi_boot_ini_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) -{ - struct iscsi_boot_kobj *boot_kobj = - container_of(kobj, struct iscsi_boot_kobj, kobj); - - if (attr == &iscsi_boot_attr_ini_index.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_INI_INDEX); - if (attr == &iscsi_boot_attr_ini_flags.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_INI_FLAGS); - if (attr == &iscsi_boot_attr_ini_isns.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_INI_ISNS_SERVER); - if (attr == &iscsi_boot_attr_ini_slp.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_INI_SLP_SERVER); - if (attr == &iscsi_boot_attr_ini_primary_radius.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_INI_PRI_RADIUS_SERVER); - if (attr == &iscsi_boot_attr_ini_secondary_radius.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_INI_SEC_RADIUS_SERVER); - if (attr == &iscsi_boot_attr_ini_name.attr) - return boot_kobj->is_visible(boot_kobj->data, - ISCSI_BOOT_INI_INITIATOR_NAME); - - return 0; -} - -static struct attribute_group iscsi_boot_initiator_attr_group = { - .attrs = initiator_attrs, - .is_visible = iscsi_boot_ini_attr_is_visible, -}; - -static struct iscsi_boot_kobj * -iscsi_boot_create_kobj(struct iscsi_boot_kset *boot_kset, - struct attribute_group *attr_group, - const char *name, int index, void *data, - ssize_t (*show) (void *data, int type, char *buf), - umode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) -{ - struct iscsi_boot_kobj *boot_kobj; - - boot_kobj = kzalloc(sizeof(*boot_kobj), GFP_KERNEL); - if (!boot_kobj) - return NULL; - INIT_LIST_HEAD(&boot_kobj->list); - - boot_kobj->kobj.kset = boot_kset->kset; - if (kobject_init_and_add(&boot_kobj->kobj, &iscsi_boot_ktype, - NULL, name, index)) { - kfree(boot_kobj); - return NULL; - } - boot_kobj->data = data; - boot_kobj->show = show; - boot_kobj->is_visible = is_visible; - boot_kobj->release = release; - - if (sysfs_create_group(&boot_kobj->kobj, attr_group)) { - /* - * We do not want to free this because the caller - * will assume that since the creation call failed - * the boot kobj was not setup and the normal release - * path is not being run. - */ - boot_kobj->release = NULL; - kobject_put(&boot_kobj->kobj); - return NULL; - } - boot_kobj->attr_group = attr_group; - - kobject_uevent(&boot_kobj->kobj, KOBJ_ADD); - /* Nothing broke so lets add it to the list. */ - list_add_tail(&boot_kobj->list, &boot_kset->kobj_list); - return boot_kobj; -} - -static void iscsi_boot_remove_kobj(struct iscsi_boot_kobj *boot_kobj) -{ - list_del(&boot_kobj->list); - sysfs_remove_group(&boot_kobj->kobj, boot_kobj->attr_group); - kobject_put(&boot_kobj->kobj); -} - -/** - * iscsi_boot_create_target() - create boot target sysfs dir - * @boot_kset: boot kset - * @index: the target id - * @data: driver specific data for target - * @show: attr show function - * @is_visible: attr visibility function - * @release: release function - * - * Note: The boot sysfs lib will free the data passed in for the caller - * when all refs to the target kobject have been released. - */ -struct iscsi_boot_kobj * -iscsi_boot_create_target(struct iscsi_boot_kset *boot_kset, int index, - void *data, - ssize_t (*show) (void *data, int type, char *buf), - umode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) -{ - return iscsi_boot_create_kobj(boot_kset, &iscsi_boot_target_attr_group, - "target%d", index, data, show, is_visible, - release); -} -EXPORT_SYMBOL_GPL(iscsi_boot_create_target); - -/** - * iscsi_boot_create_initiator() - create boot initiator sysfs dir - * @boot_kset: boot kset - * @index: the initiator id - * @data: driver specific data - * @show: attr show function - * @is_visible: attr visibility function - * @release: release function - * - * Note: The boot sysfs lib will free the data passed in for the caller - * when all refs to the initiator kobject have been released. - */ -struct iscsi_boot_kobj * -iscsi_boot_create_initiator(struct iscsi_boot_kset *boot_kset, int index, - void *data, - ssize_t (*show) (void *data, int type, char *buf), - umode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) -{ - return iscsi_boot_create_kobj(boot_kset, - &iscsi_boot_initiator_attr_group, - "initiator", index, data, show, - is_visible, release); -} -EXPORT_SYMBOL_GPL(iscsi_boot_create_initiator); - -/** - * iscsi_boot_create_ethernet() - create boot ethernet sysfs dir - * @boot_kset: boot kset - * @index: the ethernet device id - * @data: driver specific data - * @show: attr show function - * @is_visible: attr visibility function - * @release: release function - * - * Note: The boot sysfs lib will free the data passed in for the caller - * when all refs to the ethernet kobject have been released. - */ -struct iscsi_boot_kobj * -iscsi_boot_create_ethernet(struct iscsi_boot_kset *boot_kset, int index, - void *data, - ssize_t (*show) (void *data, int type, char *buf), - umode_t (*is_visible) (void *data, int type), - void (*release) (void *data)) -{ - return iscsi_boot_create_kobj(boot_kset, - &iscsi_boot_ethernet_attr_group, - "ethernet%d", index, data, show, - is_visible, release); -} -EXPORT_SYMBOL_GPL(iscsi_boot_create_ethernet); - -/** - * iscsi_boot_create_kset() - creates root sysfs tree - * @set_name: name of root dir - */ -struct iscsi_boot_kset *iscsi_boot_create_kset(const char *set_name) -{ - struct iscsi_boot_kset *boot_kset; - - boot_kset = kzalloc(sizeof(*boot_kset), GFP_KERNEL); - if (!boot_kset) - return NULL; - - boot_kset->kset = kset_create_and_add(set_name, NULL, firmware_kobj); - if (!boot_kset->kset) { - kfree(boot_kset); - return NULL; - } - - INIT_LIST_HEAD(&boot_kset->kobj_list); - return boot_kset; -} -EXPORT_SYMBOL_GPL(iscsi_boot_create_kset); - -/** - * iscsi_boot_create_host_kset() - creates root sysfs tree for a scsi host - * @hostno: host number of scsi host - */ -struct iscsi_boot_kset *iscsi_boot_create_host_kset(unsigned int hostno) -{ - struct iscsi_boot_kset *boot_kset; - char *set_name; - - set_name = kasprintf(GFP_KERNEL, "iscsi_boot%u", hostno); - if (!set_name) - return NULL; - - boot_kset = iscsi_boot_create_kset(set_name); - kfree(set_name); - return boot_kset; -} -EXPORT_SYMBOL_GPL(iscsi_boot_create_host_kset); - -/** - * iscsi_boot_destroy_kset() - destroy kset and kobjects under it - * @boot_kset: boot kset - * - * This will remove the kset and kobjects and attrs under it. - */ -void iscsi_boot_destroy_kset(struct iscsi_boot_kset *boot_kset) -{ - struct iscsi_boot_kobj *boot_kobj, *tmp_kobj; - - if (!boot_kset) - return; - - list_for_each_entry_safe(boot_kobj, tmp_kobj, - &boot_kset->kobj_list, list) - iscsi_boot_remove_kobj(boot_kobj); - - kset_unregister(boot_kset->kset); -} -EXPORT_SYMBOL_GPL(iscsi_boot_destroy_kset); diff --git a/ANDROID_3.4.5/drivers/scsi/iscsi_tcp.c b/ANDROID_3.4.5/drivers/scsi/iscsi_tcp.c deleted file mode 100644 index 453a740f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/iscsi_tcp.c +++ /dev/null @@ -1,1011 +0,0 @@ -/* - * iSCSI Initiator over TCP/IP Data-Path - * - * Copyright (C) 2004 Dmitry Yusupov - * Copyright (C) 2004 Alex Aizman - * Copyright (C) 2005 - 2006 Mike Christie - * Copyright (C) 2006 Red Hat, Inc. All rights reserved. - * maintained by open-iscsi@googlegroups.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * See the file COPYING included with this distribution for more details. - * - * Credits: - * Christoph Hellwig - * FUJITA Tomonori - * Arne Redlich - * Zhenyu Wang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iscsi_tcp.h" - -MODULE_AUTHOR("Mike Christie , " - "Dmitry Yusupov , " - "Alex Aizman "); -MODULE_DESCRIPTION("iSCSI/TCP data-path"); -MODULE_LICENSE("GPL"); - -static struct scsi_transport_template *iscsi_sw_tcp_scsi_transport; -static struct scsi_host_template iscsi_sw_tcp_sht; -static struct iscsi_transport iscsi_sw_tcp_transport; - -static unsigned int iscsi_max_lun = 512; -module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); - -static int iscsi_sw_tcp_dbg; -module_param_named(debug_iscsi_tcp, iscsi_sw_tcp_dbg, int, - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_iscsi_tcp, "Turn on debugging for iscsi_tcp module " - "Set to 1 to turn on, and zero to turn off. Default is off."); - -#define ISCSI_SW_TCP_DBG(_conn, dbg_fmt, arg...) \ - do { \ - if (iscsi_sw_tcp_dbg) \ - iscsi_conn_printk(KERN_INFO, _conn, \ - "%s " dbg_fmt, \ - __func__, ##arg); \ - } while (0); - - -/** - * iscsi_sw_tcp_recv - TCP receive in sendfile fashion - * @rd_desc: read descriptor - * @skb: socket buffer - * @offset: offset in skb - * @len: skb->len - offset - */ -static int iscsi_sw_tcp_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, - unsigned int offset, size_t len) -{ - struct iscsi_conn *conn = rd_desc->arg.data; - unsigned int consumed, total_consumed = 0; - int status; - - ISCSI_SW_TCP_DBG(conn, "in %d bytes\n", skb->len - offset); - - do { - status = 0; - consumed = iscsi_tcp_recv_skb(conn, skb, offset, 0, &status); - offset += consumed; - total_consumed += consumed; - } while (consumed != 0 && status != ISCSI_TCP_SKB_DONE); - - ISCSI_SW_TCP_DBG(conn, "read %d bytes status %d\n", - skb->len - offset, status); - return total_consumed; -} - -/** - * iscsi_sw_sk_state_check - check socket state - * @sk: socket - * - * If the socket is in CLOSE or CLOSE_WAIT we should - * not close the connection if there is still some - * data pending. - * - * Must be called with sk_callback_lock. - */ -static inline int iscsi_sw_sk_state_check(struct sock *sk) -{ - struct iscsi_conn *conn = sk->sk_user_data; - - if ((sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) && - !atomic_read(&sk->sk_rmem_alloc)) { - ISCSI_SW_TCP_DBG(conn, "TCP_CLOSE|TCP_CLOSE_WAIT\n"); - iscsi_conn_failure(conn, ISCSI_ERR_TCP_CONN_CLOSE); - return -ECONNRESET; - } - return 0; -} - -static void iscsi_sw_tcp_data_ready(struct sock *sk, int flag) -{ - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; - read_descriptor_t rd_desc; - - read_lock(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock(&sk->sk_callback_lock); - return; - } - tcp_conn = conn->dd_data; - - /* - * Use rd_desc to pass 'conn' to iscsi_tcp_recv. - * We set count to 1 because we want the network layer to - * hand us all the skbs that are available. iscsi_tcp_recv - * handled pdus that cross buffers or pdus that still need data. - */ - rd_desc.arg.data = conn; - rd_desc.count = 1; - tcp_read_sock(sk, &rd_desc, iscsi_sw_tcp_recv); - - iscsi_sw_sk_state_check(sk); - - /* If we had to (atomically) map a highmem page, - * unmap it now. */ - iscsi_tcp_segment_unmap(&tcp_conn->in.segment); - read_unlock(&sk->sk_callback_lock); -} - -static void iscsi_sw_tcp_state_change(struct sock *sk) -{ - struct iscsi_tcp_conn *tcp_conn; - struct iscsi_sw_tcp_conn *tcp_sw_conn; - struct iscsi_conn *conn; - struct iscsi_session *session; - void (*old_state_change)(struct sock *); - - read_lock(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock(&sk->sk_callback_lock); - return; - } - session = conn->session; - - iscsi_sw_sk_state_check(sk); - - tcp_conn = conn->dd_data; - tcp_sw_conn = tcp_conn->dd_data; - old_state_change = tcp_sw_conn->old_state_change; - - read_unlock(&sk->sk_callback_lock); - - old_state_change(sk); -} - -/** - * iscsi_write_space - Called when more output buffer space is available - * @sk: socket space is available for - **/ -static void iscsi_sw_tcp_write_space(struct sock *sk) -{ - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; - struct iscsi_sw_tcp_conn *tcp_sw_conn; - void (*old_write_space)(struct sock *); - - read_lock_bh(&sk->sk_callback_lock); - conn = sk->sk_user_data; - if (!conn) { - read_unlock_bh(&sk->sk_callback_lock); - return; - } - - tcp_conn = conn->dd_data; - tcp_sw_conn = tcp_conn->dd_data; - old_write_space = tcp_sw_conn->old_write_space; - read_unlock_bh(&sk->sk_callback_lock); - - old_write_space(sk); - - ISCSI_SW_TCP_DBG(conn, "iscsi_write_space\n"); - iscsi_conn_queue_work(conn); -} - -static void iscsi_sw_tcp_conn_set_callbacks(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct sock *sk = tcp_sw_conn->sock->sk; - - /* assign new callbacks */ - write_lock_bh(&sk->sk_callback_lock); - sk->sk_user_data = conn; - tcp_sw_conn->old_data_ready = sk->sk_data_ready; - tcp_sw_conn->old_state_change = sk->sk_state_change; - tcp_sw_conn->old_write_space = sk->sk_write_space; - sk->sk_data_ready = iscsi_sw_tcp_data_ready; - sk->sk_state_change = iscsi_sw_tcp_state_change; - sk->sk_write_space = iscsi_sw_tcp_write_space; - write_unlock_bh(&sk->sk_callback_lock); -} - -static void -iscsi_sw_tcp_conn_restore_callbacks(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct sock *sk = tcp_sw_conn->sock->sk; - - /* restore socket callbacks, see also: iscsi_conn_set_callbacks() */ - write_lock_bh(&sk->sk_callback_lock); - sk->sk_user_data = NULL; - sk->sk_data_ready = tcp_sw_conn->old_data_ready; - sk->sk_state_change = tcp_sw_conn->old_state_change; - sk->sk_write_space = tcp_sw_conn->old_write_space; - sk->sk_no_check = 0; - write_unlock_bh(&sk->sk_callback_lock); -} - -/** - * iscsi_sw_tcp_xmit_segment - transmit segment - * @tcp_conn: the iSCSI TCP connection - * @segment: the buffer to transmnit - * - * This function transmits as much of the buffer as - * the network layer will accept, and returns the number of - * bytes transmitted. - * - * If CRC hashing is enabled, the function will compute the - * hash as it goes. When the entire segment has been transmitted, - * it will retrieve the hash value and send it as well. - */ -static int iscsi_sw_tcp_xmit_segment(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment) -{ - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct socket *sk = tcp_sw_conn->sock; - unsigned int copied = 0; - int r = 0; - - while (!iscsi_tcp_segment_done(tcp_conn, segment, 0, r)) { - struct scatterlist *sg; - unsigned int offset, copy; - int flags = 0; - - r = 0; - offset = segment->copied; - copy = segment->size - offset; - - if (segment->total_copied + segment->size < segment->total_size) - flags |= MSG_MORE; - - /* Use sendpage if we can; else fall back to sendmsg */ - if (!segment->data) { - sg = segment->sg; - offset += segment->sg_offset + sg->offset; - r = tcp_sw_conn->sendpage(sk, sg_page(sg), offset, - copy, flags); - } else { - struct msghdr msg = { .msg_flags = flags }; - struct kvec iov = { - .iov_base = segment->data + offset, - .iov_len = copy - }; - - r = kernel_sendmsg(sk, &msg, &iov, 1, copy); - } - - if (r < 0) { - iscsi_tcp_segment_unmap(segment); - return r; - } - copied += r; - } - return copied; -} - -/** - * iscsi_sw_tcp_xmit - TCP transmit - **/ -static int iscsi_sw_tcp_xmit(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct iscsi_segment *segment = &tcp_sw_conn->out.segment; - unsigned int consumed = 0; - int rc = 0; - - while (1) { - rc = iscsi_sw_tcp_xmit_segment(tcp_conn, segment); - /* - * We may not have been able to send data because the conn - * is getting stopped. libiscsi will know so propagate err - * for it to do the right thing. - */ - if (rc == -EAGAIN) - return rc; - else if (rc < 0) { - rc = ISCSI_ERR_XMIT_FAILED; - goto error; - } else if (rc == 0) - break; - - consumed += rc; - - if (segment->total_copied >= segment->total_size) { - if (segment->done != NULL) { - rc = segment->done(tcp_conn, segment); - if (rc != 0) - goto error; - } - } - } - - ISCSI_SW_TCP_DBG(conn, "xmit %d bytes\n", consumed); - - conn->txdata_octets += consumed; - return consumed; - -error: - /* Transmit error. We could initiate error recovery - * here. */ - ISCSI_SW_TCP_DBG(conn, "Error sending PDU, errno=%d\n", rc); - iscsi_conn_failure(conn, rc); - return -EIO; -} - -/** - * iscsi_tcp_xmit_qlen - return the number of bytes queued for xmit - */ -static inline int iscsi_sw_tcp_xmit_qlen(struct iscsi_conn *conn) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct iscsi_segment *segment = &tcp_sw_conn->out.segment; - - return segment->total_copied - segment->total_size; -} - -static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task) -{ - struct iscsi_conn *conn = task->conn; - int rc; - - while (iscsi_sw_tcp_xmit_qlen(conn)) { - rc = iscsi_sw_tcp_xmit(conn); - if (rc == 0) - return -EAGAIN; - if (rc < 0) - return rc; - } - - return 0; -} - -/* - * This is called when we're done sending the header. - * Simply copy the data_segment to the send segment, and return. - */ -static int iscsi_sw_tcp_send_hdr_done(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment) -{ - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - - tcp_sw_conn->out.segment = tcp_sw_conn->out.data_segment; - ISCSI_SW_TCP_DBG(tcp_conn->iscsi_conn, - "Header done. Next segment size %u total_size %u\n", - tcp_sw_conn->out.segment.size, - tcp_sw_conn->out.segment.total_size); - return 0; -} - -static void iscsi_sw_tcp_send_hdr_prep(struct iscsi_conn *conn, void *hdr, - size_t hdrlen) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - - ISCSI_SW_TCP_DBG(conn, "%s\n", conn->hdrdgst_en ? - "digest enabled" : "digest disabled"); - - /* Clear the data segment - needs to be filled in by the - * caller using iscsi_tcp_send_data_prep() */ - memset(&tcp_sw_conn->out.data_segment, 0, - sizeof(struct iscsi_segment)); - - /* If header digest is enabled, compute the CRC and - * place the digest into the same buffer. We make - * sure that both iscsi_tcp_task and mtask have - * sufficient room. - */ - if (conn->hdrdgst_en) { - iscsi_tcp_dgst_header(&tcp_sw_conn->tx_hash, hdr, hdrlen, - hdr + hdrlen); - hdrlen += ISCSI_DIGEST_SIZE; - } - - /* Remember header pointer for later, when we need - * to decide whether there's a payload to go along - * with the header. */ - tcp_sw_conn->out.hdr = hdr; - - iscsi_segment_init_linear(&tcp_sw_conn->out.segment, hdr, hdrlen, - iscsi_sw_tcp_send_hdr_done, NULL); -} - -/* - * Prepare the send buffer for the payload data. - * Padding and checksumming will all be taken care - * of by the iscsi_segment routines. - */ -static int -iscsi_sw_tcp_send_data_prep(struct iscsi_conn *conn, struct scatterlist *sg, - unsigned int count, unsigned int offset, - unsigned int len) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct hash_desc *tx_hash = NULL; - unsigned int hdr_spec_len; - - ISCSI_SW_TCP_DBG(conn, "offset=%d, datalen=%d %s\n", offset, len, - conn->datadgst_en ? - "digest enabled" : "digest disabled"); - - /* Make sure the datalen matches what the caller - said he would send. */ - hdr_spec_len = ntoh24(tcp_sw_conn->out.hdr->dlength); - WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); - - if (conn->datadgst_en) - tx_hash = &tcp_sw_conn->tx_hash; - - return iscsi_segment_seek_sg(&tcp_sw_conn->out.data_segment, - sg, count, offset, len, - NULL, tx_hash); -} - -static void -iscsi_sw_tcp_send_linear_data_prep(struct iscsi_conn *conn, void *data, - size_t len) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct hash_desc *tx_hash = NULL; - unsigned int hdr_spec_len; - - ISCSI_SW_TCP_DBG(conn, "datalen=%zd %s\n", len, conn->datadgst_en ? - "digest enabled" : "digest disabled"); - - /* Make sure the datalen matches what the caller - said he would send. */ - hdr_spec_len = ntoh24(tcp_sw_conn->out.hdr->dlength); - WARN_ON(iscsi_padded(len) != iscsi_padded(hdr_spec_len)); - - if (conn->datadgst_en) - tx_hash = &tcp_sw_conn->tx_hash; - - iscsi_segment_init_linear(&tcp_sw_conn->out.data_segment, - data, len, NULL, tx_hash); -} - -static int iscsi_sw_tcp_pdu_init(struct iscsi_task *task, - unsigned int offset, unsigned int count) -{ - struct iscsi_conn *conn = task->conn; - int err = 0; - - iscsi_sw_tcp_send_hdr_prep(conn, task->hdr, task->hdr_len); - - if (!count) - return 0; - - if (!task->sc) - iscsi_sw_tcp_send_linear_data_prep(conn, task->data, count); - else { - struct scsi_data_buffer *sdb = scsi_out(task->sc); - - err = iscsi_sw_tcp_send_data_prep(conn, sdb->table.sgl, - sdb->table.nents, offset, - count); - } - - if (err) { - /* got invalid offset/len */ - return -EIO; - } - return 0; -} - -static int iscsi_sw_tcp_pdu_alloc(struct iscsi_task *task, uint8_t opcode) -{ - struct iscsi_tcp_task *tcp_task = task->dd_data; - - task->hdr = task->dd_data + sizeof(*tcp_task); - task->hdr_max = sizeof(struct iscsi_sw_tcp_hdrbuf) - ISCSI_DIGEST_SIZE; - return 0; -} - -static struct iscsi_cls_conn * -iscsi_sw_tcp_conn_create(struct iscsi_cls_session *cls_session, - uint32_t conn_idx) -{ - struct iscsi_conn *conn; - struct iscsi_cls_conn *cls_conn; - struct iscsi_tcp_conn *tcp_conn; - struct iscsi_sw_tcp_conn *tcp_sw_conn; - - cls_conn = iscsi_tcp_conn_setup(cls_session, sizeof(*tcp_sw_conn), - conn_idx); - if (!cls_conn) - return NULL; - conn = cls_conn->dd_data; - tcp_conn = conn->dd_data; - tcp_sw_conn = tcp_conn->dd_data; - - tcp_sw_conn->tx_hash.tfm = crypto_alloc_hash("crc32c", 0, - CRYPTO_ALG_ASYNC); - tcp_sw_conn->tx_hash.flags = 0; - if (IS_ERR(tcp_sw_conn->tx_hash.tfm)) - goto free_conn; - - tcp_sw_conn->rx_hash.tfm = crypto_alloc_hash("crc32c", 0, - CRYPTO_ALG_ASYNC); - tcp_sw_conn->rx_hash.flags = 0; - if (IS_ERR(tcp_sw_conn->rx_hash.tfm)) - goto free_tx_tfm; - tcp_conn->rx_hash = &tcp_sw_conn->rx_hash; - - return cls_conn; - -free_tx_tfm: - crypto_free_hash(tcp_sw_conn->tx_hash.tfm); -free_conn: - iscsi_conn_printk(KERN_ERR, conn, - "Could not create connection due to crc32c " - "loading error. Make sure the crc32c " - "module is built as a module or into the " - "kernel\n"); - iscsi_tcp_conn_teardown(cls_conn); - return NULL; -} - -static void iscsi_sw_tcp_release_conn(struct iscsi_conn *conn) -{ - struct iscsi_session *session = conn->session; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct socket *sock = tcp_sw_conn->sock; - - if (!sock) - return; - - sock_hold(sock->sk); - iscsi_sw_tcp_conn_restore_callbacks(conn); - sock_put(sock->sk); - - spin_lock_bh(&session->lock); - tcp_sw_conn->sock = NULL; - spin_unlock_bh(&session->lock); - sockfd_put(sock); -} - -static void iscsi_sw_tcp_conn_destroy(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - - iscsi_sw_tcp_release_conn(conn); - - if (tcp_sw_conn->tx_hash.tfm) - crypto_free_hash(tcp_sw_conn->tx_hash.tfm); - if (tcp_sw_conn->rx_hash.tfm) - crypto_free_hash(tcp_sw_conn->rx_hash.tfm); - - iscsi_tcp_conn_teardown(cls_conn); -} - -static void iscsi_sw_tcp_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct socket *sock = tcp_sw_conn->sock; - - /* userspace may have goofed up and not bound us */ - if (!sock) - return; - - sock->sk->sk_err = EIO; - wake_up_interruptible(sk_sleep(sock->sk)); - - /* stop xmit side */ - iscsi_suspend_tx(conn); - - /* stop recv side and release socket */ - iscsi_sw_tcp_release_conn(conn); - - iscsi_conn_stop(cls_conn, flag); -} - -static int -iscsi_sw_tcp_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, uint64_t transport_eph, - int is_leading) -{ - struct iscsi_session *session = cls_session->dd_data; - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct sock *sk; - struct socket *sock; - int err; - - /* lookup for existing socket */ - sock = sockfd_lookup((int)transport_eph, &err); - if (!sock) { - iscsi_conn_printk(KERN_ERR, conn, - "sockfd_lookup failed %d\n", err); - return -EEXIST; - } - - err = iscsi_conn_bind(cls_session, cls_conn, is_leading); - if (err) - goto free_socket; - - spin_lock_bh(&session->lock); - /* bind iSCSI connection and socket */ - tcp_sw_conn->sock = sock; - spin_unlock_bh(&session->lock); - - /* setup Socket parameters */ - sk = sock->sk; - sk->sk_reuse = 1; - sk->sk_sndtimeo = 15 * HZ; /* FIXME: make it configurable */ - sk->sk_allocation = GFP_ATOMIC; - - iscsi_sw_tcp_conn_set_callbacks(conn); - tcp_sw_conn->sendpage = tcp_sw_conn->sock->ops->sendpage; - /* - * set receive state machine into initial state - */ - iscsi_tcp_hdr_recv_prep(tcp_conn); - return 0; - -free_socket: - sockfd_put(sock); - return err; -} - -static int iscsi_sw_tcp_conn_set_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf, - int buflen) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - - switch(param) { - case ISCSI_PARAM_HDRDGST_EN: - iscsi_set_param(cls_conn, param, buf, buflen); - break; - case ISCSI_PARAM_DATADGST_EN: - iscsi_set_param(cls_conn, param, buf, buflen); - tcp_sw_conn->sendpage = conn->datadgst_en ? - sock_no_sendpage : tcp_sw_conn->sock->ops->sendpage; - break; - case ISCSI_PARAM_MAX_R2T: - return iscsi_tcp_set_max_r2t(conn, buf); - default: - return iscsi_set_param(cls_conn, param, buf, buflen); - } - - return 0; -} - -static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - struct sockaddr_in6 addr; - int rc, len; - - switch(param) { - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_CONN_ADDRESS: - spin_lock_bh(&conn->session->lock); - if (!tcp_sw_conn || !tcp_sw_conn->sock) { - spin_unlock_bh(&conn->session->lock); - return -ENOTCONN; - } - rc = kernel_getpeername(tcp_sw_conn->sock, - (struct sockaddr *)&addr, &len); - spin_unlock_bh(&conn->session->lock); - if (rc) - return rc; - - return iscsi_conn_get_addr_param((struct sockaddr_storage *) - &addr, param, buf); - default: - return iscsi_conn_get_param(cls_conn, param, buf); - } - - return 0; -} - -static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost, - enum iscsi_host_param param, char *buf) -{ - struct iscsi_sw_tcp_host *tcp_sw_host = iscsi_host_priv(shost); - struct iscsi_session *session = tcp_sw_host->session; - struct iscsi_conn *conn; - struct iscsi_tcp_conn *tcp_conn; - struct iscsi_sw_tcp_conn *tcp_sw_conn; - struct sockaddr_in6 addr; - int rc, len; - - switch (param) { - case ISCSI_HOST_PARAM_IPADDRESS: - spin_lock_bh(&session->lock); - conn = session->leadconn; - if (!conn) { - spin_unlock_bh(&session->lock); - return -ENOTCONN; - } - tcp_conn = conn->dd_data; - - tcp_sw_conn = tcp_conn->dd_data; - if (!tcp_sw_conn->sock) { - spin_unlock_bh(&session->lock); - return -ENOTCONN; - } - - rc = kernel_getsockname(tcp_sw_conn->sock, - (struct sockaddr *)&addr, &len); - spin_unlock_bh(&session->lock); - if (rc) - return rc; - - return iscsi_conn_get_addr_param((struct sockaddr_storage *) - &addr, param, buf); - default: - return iscsi_host_get_param(shost, param, buf); - } - - return 0; -} - -static void -iscsi_sw_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; - - stats->custom_length = 3; - strcpy(stats->custom[0].desc, "tx_sendpage_failures"); - stats->custom[0].value = tcp_sw_conn->sendpage_failures_cnt; - strcpy(stats->custom[1].desc, "rx_discontiguous_hdr"); - stats->custom[1].value = tcp_sw_conn->discontiguous_hdr_cnt; - strcpy(stats->custom[2].desc, "eh_abort_cnt"); - stats->custom[2].value = conn->eh_abort_cnt; - - iscsi_tcp_conn_get_stats(cls_conn, stats); -} - -static struct iscsi_cls_session * -iscsi_sw_tcp_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, - uint16_t qdepth, uint32_t initial_cmdsn) -{ - struct iscsi_cls_session *cls_session; - struct iscsi_session *session; - struct iscsi_sw_tcp_host *tcp_sw_host; - struct Scsi_Host *shost; - - if (ep) { - printk(KERN_ERR "iscsi_tcp: invalid ep %p.\n", ep); - return NULL; - } - - shost = iscsi_host_alloc(&iscsi_sw_tcp_sht, - sizeof(struct iscsi_sw_tcp_host), 1); - if (!shost) - return NULL; - shost->transportt = iscsi_sw_tcp_scsi_transport; - shost->cmd_per_lun = qdepth; - shost->max_lun = iscsi_max_lun; - shost->max_id = 0; - shost->max_channel = 0; - shost->max_cmd_len = SCSI_MAX_VARLEN_CDB_SIZE; - - if (iscsi_host_add(shost, NULL)) - goto free_host; - - cls_session = iscsi_session_setup(&iscsi_sw_tcp_transport, shost, - cmds_max, 0, - sizeof(struct iscsi_tcp_task) + - sizeof(struct iscsi_sw_tcp_hdrbuf), - initial_cmdsn, 0); - if (!cls_session) - goto remove_host; - session = cls_session->dd_data; - tcp_sw_host = iscsi_host_priv(shost); - tcp_sw_host->session = session; - - shost->can_queue = session->scsi_cmds_max; - if (iscsi_tcp_r2tpool_alloc(session)) - goto remove_session; - return cls_session; - -remove_session: - iscsi_session_teardown(cls_session); -remove_host: - iscsi_host_remove(shost); -free_host: - iscsi_host_free(shost); - return NULL; -} - -static void iscsi_sw_tcp_session_destroy(struct iscsi_cls_session *cls_session) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); - - iscsi_tcp_r2tpool_free(cls_session->dd_data); - iscsi_session_teardown(cls_session); - - iscsi_host_remove(shost); - iscsi_host_free(shost); -} - -static umode_t iscsi_sw_tcp_attr_is_visible(int param_type, int param) -{ - switch (param_type) { - case ISCSI_HOST_PARAM: - switch (param) { - case ISCSI_HOST_PARAM_NETDEV_NAME: - case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_IPADDRESS: - case ISCSI_HOST_PARAM_INITIATOR_NAME: - return S_IRUGO; - default: - return 0; - } - case ISCSI_PARAM: - switch (param) { - case ISCSI_PARAM_MAX_RECV_DLENGTH: - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - case ISCSI_PARAM_HDRDGST_EN: - case ISCSI_PARAM_DATADGST_EN: - case ISCSI_PARAM_CONN_ADDRESS: - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_EXP_STATSN: - case ISCSI_PARAM_PERSISTENT_ADDRESS: - case ISCSI_PARAM_PERSISTENT_PORT: - case ISCSI_PARAM_PING_TMO: - case ISCSI_PARAM_RECV_TMO: - case ISCSI_PARAM_INITIAL_R2T_EN: - case ISCSI_PARAM_MAX_R2T: - case ISCSI_PARAM_IMM_DATA_EN: - case ISCSI_PARAM_FIRST_BURST: - case ISCSI_PARAM_MAX_BURST: - case ISCSI_PARAM_PDU_INORDER_EN: - case ISCSI_PARAM_DATASEQ_INORDER_EN: - case ISCSI_PARAM_ERL: - case ISCSI_PARAM_TARGET_NAME: - case ISCSI_PARAM_TPGT: - case ISCSI_PARAM_USERNAME: - case ISCSI_PARAM_PASSWORD: - case ISCSI_PARAM_USERNAME_IN: - case ISCSI_PARAM_PASSWORD_IN: - case ISCSI_PARAM_FAST_ABORT: - case ISCSI_PARAM_ABORT_TMO: - case ISCSI_PARAM_LU_RESET_TMO: - case ISCSI_PARAM_TGT_RESET_TMO: - case ISCSI_PARAM_IFACE_NAME: - case ISCSI_PARAM_INITIATOR_NAME: - return S_IRUGO; - default: - return 0; - } - } - - return 0; -} - -static int iscsi_sw_tcp_slave_alloc(struct scsi_device *sdev) -{ - set_bit(QUEUE_FLAG_BIDI, &sdev->request_queue->queue_flags); - return 0; -} - -static int iscsi_sw_tcp_slave_configure(struct scsi_device *sdev) -{ - blk_queue_bounce_limit(sdev->request_queue, BLK_BOUNCE_ANY); - blk_queue_dma_alignment(sdev->request_queue, 0); - return 0; -} - -static struct scsi_host_template iscsi_sw_tcp_sht = { - .module = THIS_MODULE, - .name = "iSCSI Initiator over TCP/IP", - .queuecommand = iscsi_queuecommand, - .change_queue_depth = iscsi_change_queue_depth, - .can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1, - .sg_tablesize = 4096, - .max_sectors = 0xFFFF, - .cmd_per_lun = ISCSI_DEF_CMD_PER_LUN, - .eh_abort_handler = iscsi_eh_abort, - .eh_device_reset_handler= iscsi_eh_device_reset, - .eh_target_reset_handler = iscsi_eh_recover_target, - .use_clustering = DISABLE_CLUSTERING, - .slave_alloc = iscsi_sw_tcp_slave_alloc, - .slave_configure = iscsi_sw_tcp_slave_configure, - .target_alloc = iscsi_target_alloc, - .proc_name = "iscsi_tcp", - .this_id = -1, -}; - -static struct iscsi_transport iscsi_sw_tcp_transport = { - .owner = THIS_MODULE, - .name = "tcp", - .caps = CAP_RECOVERY_L0 | CAP_MULTI_R2T | CAP_HDRDGST - | CAP_DATADGST, - /* session management */ - .create_session = iscsi_sw_tcp_session_create, - .destroy_session = iscsi_sw_tcp_session_destroy, - /* connection management */ - .create_conn = iscsi_sw_tcp_conn_create, - .bind_conn = iscsi_sw_tcp_conn_bind, - .destroy_conn = iscsi_sw_tcp_conn_destroy, - .attr_is_visible = iscsi_sw_tcp_attr_is_visible, - .set_param = iscsi_sw_tcp_conn_set_param, - .get_conn_param = iscsi_sw_tcp_conn_get_param, - .get_session_param = iscsi_session_get_param, - .start_conn = iscsi_conn_start, - .stop_conn = iscsi_sw_tcp_conn_stop, - /* iscsi host params */ - .get_host_param = iscsi_sw_tcp_host_get_param, - .set_host_param = iscsi_host_set_param, - /* IO */ - .send_pdu = iscsi_conn_send_pdu, - .get_stats = iscsi_sw_tcp_conn_get_stats, - /* iscsi task/cmd helpers */ - .init_task = iscsi_tcp_task_init, - .xmit_task = iscsi_tcp_task_xmit, - .cleanup_task = iscsi_tcp_cleanup_task, - /* low level pdu helpers */ - .xmit_pdu = iscsi_sw_tcp_pdu_xmit, - .init_pdu = iscsi_sw_tcp_pdu_init, - .alloc_pdu = iscsi_sw_tcp_pdu_alloc, - /* recovery */ - .session_recovery_timedout = iscsi_session_recovery_timedout, -}; - -static int __init iscsi_sw_tcp_init(void) -{ - if (iscsi_max_lun < 1) { - printk(KERN_ERR "iscsi_tcp: Invalid max_lun value of %u\n", - iscsi_max_lun); - return -EINVAL; - } - - iscsi_sw_tcp_scsi_transport = iscsi_register_transport( - &iscsi_sw_tcp_transport); - if (!iscsi_sw_tcp_scsi_transport) - return -ENODEV; - - return 0; -} - -static void __exit iscsi_sw_tcp_exit(void) -{ - iscsi_unregister_transport(&iscsi_sw_tcp_transport); -} - -module_init(iscsi_sw_tcp_init); -module_exit(iscsi_sw_tcp_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/iscsi_tcp.h b/ANDROID_3.4.5/drivers/scsi/iscsi_tcp.h deleted file mode 100644 index 666fe093..00000000 --- a/ANDROID_3.4.5/drivers/scsi/iscsi_tcp.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * iSCSI Initiator TCP Transport - * Copyright (C) 2004 Dmitry Yusupov - * Copyright (C) 2004 Alex Aizman - * Copyright (C) 2005 - 2006 Mike Christie - * Copyright (C) 2006 Red Hat, Inc. All rights reserved. - * maintained by open-iscsi@googlegroups.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * See the file COPYING included with this distribution for more details. - */ - -#ifndef ISCSI_SW_TCP_H -#define ISCSI_SW_TCP_H - -#include -#include - -struct socket; -struct iscsi_tcp_conn; - -/* Socket connection send helper */ -struct iscsi_sw_tcp_send { - struct iscsi_hdr *hdr; - struct iscsi_segment segment; - struct iscsi_segment data_segment; -}; - -struct iscsi_sw_tcp_conn { - struct socket *sock; - - struct iscsi_sw_tcp_send out; - /* old values for socket callbacks */ - void (*old_data_ready)(struct sock *, int); - void (*old_state_change)(struct sock *); - void (*old_write_space)(struct sock *); - - /* data and header digests */ - struct hash_desc tx_hash; /* CRC32C (Tx) */ - struct hash_desc rx_hash; /* CRC32C (Rx) */ - - /* MIB custom statistics */ - uint32_t sendpage_failures_cnt; - uint32_t discontiguous_hdr_cnt; - - ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int); -}; - -struct iscsi_sw_tcp_host { - struct iscsi_session *session; -}; - -struct iscsi_sw_tcp_hdrbuf { - struct iscsi_hdr hdrbuf; - char hdrextbuf[ISCSI_MAX_AHS_SIZE + - ISCSI_DIGEST_SIZE]; -}; - -#endif /* ISCSI_SW_TCP_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/jazz_esp.c b/ANDROID_3.4.5/drivers/scsi/jazz_esp.c deleted file mode 100644 index 27cfb0cb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/jazz_esp.c +++ /dev/null @@ -1,249 +0,0 @@ -/* jazz_esp.c: ESP front-end for MIPS JAZZ systems. - * - * Copyright (C) 2007 Thomas Bogendörfer (tsbogend@alpha.frankende) - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include "esp_scsi.h" - -#define DRV_MODULE_NAME "jazz_esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.000" -#define DRV_MODULE_RELDATE "May 19, 2007" - -static void jazz_esp_write8(struct esp *esp, u8 val, unsigned long reg) -{ - *(volatile u8 *)(esp->regs + reg) = val; -} - -static u8 jazz_esp_read8(struct esp *esp, unsigned long reg) -{ - return *(volatile u8 *)(esp->regs + reg); -} - -static dma_addr_t jazz_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return dma_map_single(esp->dev, buf, sz, dir); -} - -static int jazz_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - return dma_map_sg(esp->dev, sg, num_sg, dir); -} - -static void jazz_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - dma_unmap_single(esp->dev, addr, sz, dir); -} - -static void jazz_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); -} - -static int jazz_esp_irq_pending(struct esp *esp) -{ - if (jazz_esp_read8(esp, ESP_STATUS) & ESP_STAT_INTR) - return 1; - return 0; -} - -static void jazz_esp_reset_dma(struct esp *esp) -{ - vdma_disable ((int)esp->dma_regs); -} - -static void jazz_esp_dma_drain(struct esp *esp) -{ - /* nothing to do */ -} - -static void jazz_esp_dma_invalidate(struct esp *esp) -{ - vdma_disable ((int)esp->dma_regs); -} - -static void jazz_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) -{ - BUG_ON(!(cmd & ESP_CMD_DMA)); - - jazz_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); - jazz_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - vdma_disable ((int)esp->dma_regs); - if (write) - vdma_set_mode ((int)esp->dma_regs, DMA_MODE_READ); - else - vdma_set_mode ((int)esp->dma_regs, DMA_MODE_WRITE); - - vdma_set_addr ((int)esp->dma_regs, addr); - vdma_set_count ((int)esp->dma_regs, dma_count); - vdma_enable ((int)esp->dma_regs); - - scsi_esp_cmd(esp, cmd); -} - -static int jazz_esp_dma_error(struct esp *esp) -{ - u32 enable = vdma_get_enable((int)esp->dma_regs); - - if (enable & (R4030_MEM_INTR|R4030_ADDR_INTR)) - return 1; - - return 0; -} - -static const struct esp_driver_ops jazz_esp_ops = { - .esp_write8 = jazz_esp_write8, - .esp_read8 = jazz_esp_read8, - .map_single = jazz_esp_map_single, - .map_sg = jazz_esp_map_sg, - .unmap_single = jazz_esp_unmap_single, - .unmap_sg = jazz_esp_unmap_sg, - .irq_pending = jazz_esp_irq_pending, - .reset_dma = jazz_esp_reset_dma, - .dma_drain = jazz_esp_dma_drain, - .dma_invalidate = jazz_esp_dma_invalidate, - .send_dma_cmd = jazz_esp_send_dma_cmd, - .dma_error = jazz_esp_dma_error, -}; - -static int __devinit esp_jazz_probe(struct platform_device *dev) -{ - struct scsi_host_template *tpnt = &scsi_esp_template; - struct Scsi_Host *host; - struct esp *esp; - struct resource *res; - int err; - - host = scsi_host_alloc(tpnt, sizeof(struct esp)); - - err = -ENOMEM; - if (!host) - goto fail; - - host->max_id = 8; - esp = shost_priv(host); - - esp->host = host; - esp->dev = dev; - esp->ops = &jazz_esp_ops; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) - goto fail_unlink; - - esp->regs = (void __iomem *)res->start; - if (!esp->regs) - goto fail_unlink; - - res = platform_get_resource(dev, IORESOURCE_MEM, 1); - if (!res) - goto fail_unlink; - - esp->dma_regs = (void __iomem *)res->start; - - esp->command_block = dma_alloc_coherent(esp->dev, 16, - &esp->command_block_dma, - GFP_KERNEL); - if (!esp->command_block) - goto fail_unmap_regs; - - host->irq = platform_get_irq(dev, 0); - err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); - if (err < 0) - goto fail_unmap_command_block; - - esp->scsi_id = 7; - esp->host->this_id = esp->scsi_id; - esp->scsi_id_mask = (1 << esp->scsi_id); - esp->cfreq = 40000000; - - dev_set_drvdata(&dev->dev, esp); - - err = scsi_esp_register(esp, &dev->dev); - if (err) - goto fail_free_irq; - - return 0; - -fail_free_irq: - free_irq(host->irq, esp); -fail_unmap_command_block: - dma_free_coherent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); -fail_unmap_regs: -fail_unlink: - scsi_host_put(host); -fail: - return err; -} - -static int __devexit esp_jazz_remove(struct platform_device *dev) -{ - struct esp *esp = dev_get_drvdata(&dev->dev); - unsigned int irq = esp->host->irq; - - scsi_esp_unregister(esp); - - free_irq(irq, esp); - dma_free_coherent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); - - scsi_host_put(esp->host); - - return 0; -} - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:jazz_esp"); - -static struct platform_driver esp_jazz_driver = { - .probe = esp_jazz_probe, - .remove = __devexit_p(esp_jazz_remove), - .driver = { - .name = "jazz_esp", - .owner = THIS_MODULE, - }, -}; - -static int __init jazz_esp_init(void) -{ - return platform_driver_register(&esp_jazz_driver); -} - -static void __exit jazz_esp_exit(void) -{ - platform_driver_unregister(&esp_jazz_driver); -} - -MODULE_DESCRIPTION("JAZZ ESP SCSI driver"); -MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -module_init(jazz_esp_init); -module_exit(jazz_esp_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/lasi700.c b/ANDROID_3.4.5/drivers/scsi/lasi700.c deleted file mode 100644 index 23880f8f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lasi700.c +++ /dev/null @@ -1,187 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ - -/* PARISC LASI driver for the 53c700 chip - * - * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- - */ - -/* - * Many thanks to Richard Hirst for patiently - * debugging this driver on the parisc architecture and suggesting - * many improvements and bug fixes. - * - * Thanks also go to Linuxcare Inc. for providing several PARISC - * machines for me to debug the driver on. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "53c700.h" - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("lasi700 SCSI Driver"); -MODULE_LICENSE("GPL"); - -#define LASI_700_SVERSION 0x00071 -#define LASI_710_SVERSION 0x00082 - -#define LASI700_ID_TABLE { \ - .hw_type = HPHW_FIO, \ - .sversion = LASI_700_SVERSION, \ - .hversion = HVERSION_ANY_ID, \ - .hversion_rev = HVERSION_REV_ANY_ID, \ -} - -#define LASI710_ID_TABLE { \ - .hw_type = HPHW_FIO, \ - .sversion = LASI_710_SVERSION, \ - .hversion = HVERSION_ANY_ID, \ - .hversion_rev = HVERSION_REV_ANY_ID, \ -} - -#define LASI700_CLOCK 25 -#define LASI710_CLOCK 40 -#define LASI_SCSI_CORE_OFFSET 0x100 - -static struct parisc_device_id lasi700_ids[] = { - LASI700_ID_TABLE, - LASI710_ID_TABLE, - { 0 } -}; - -static struct scsi_host_template lasi700_template = { - .name = "LASI SCSI 53c700", - .proc_name = "lasi700", - .this_id = 7, - .module = THIS_MODULE, -}; -MODULE_DEVICE_TABLE(parisc, lasi700_ids); - -static int __init -lasi700_probe(struct parisc_device *dev) -{ - unsigned long base = dev->hpa.start + LASI_SCSI_CORE_OFFSET; - struct NCR_700_Host_Parameters *hostdata; - struct Scsi_Host *host; - - hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); - if (!hostdata) { - dev_printk(KERN_ERR, &dev->dev, "Failed to allocate host data\n"); - return -ENOMEM; - } - - hostdata->dev = &dev->dev; - dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); - hostdata->base = ioremap_nocache(base, 0x100); - hostdata->differential = 0; - - if (dev->id.sversion == LASI_700_SVERSION) { - hostdata->clock = LASI700_CLOCK; - hostdata->force_le_on_be = 1; - } else { - hostdata->clock = LASI710_CLOCK; - hostdata->force_le_on_be = 0; - hostdata->chip710 = 1; - hostdata->dmode_extra = DMODE_FC2; - hostdata->burst_length = 8; - } - - host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev); - if (!host) - goto out_kfree; - host->this_id = 7; - host->base = base; - host->irq = dev->irq; - if(request_irq(dev->irq, NCR_700_intr, IRQF_SHARED, "lasi700", host)) { - printk(KERN_ERR "lasi700: request_irq failed!\n"); - goto out_put_host; - } - - dev_set_drvdata(&dev->dev, host); - scsi_scan_host(host); - - return 0; - - out_put_host: - scsi_host_put(host); - out_kfree: - iounmap(hostdata->base); - kfree(hostdata); - return -ENODEV; -} - -static int __exit -lasi700_driver_remove(struct parisc_device *dev) -{ - struct Scsi_Host *host = dev_get_drvdata(&dev->dev); - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - - scsi_remove_host(host); - NCR_700_release(host); - free_irq(host->irq, host); - iounmap(hostdata->base); - kfree(hostdata); - - return 0; -} - -static struct parisc_driver lasi700_driver = { - .name = "lasi_scsi", - .id_table = lasi700_ids, - .probe = lasi700_probe, - .remove = __devexit_p(lasi700_driver_remove), -}; - -static int __init -lasi700_init(void) -{ - return register_parisc_driver(&lasi700_driver); -} - -static void __exit -lasi700_exit(void) -{ - unregister_parisc_driver(&lasi700_driver); -} - -module_init(lasi700_init); -module_exit(lasi700_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/Makefile b/ANDROID_3.4.5/drivers/scsi/libfc/Makefile deleted file mode 100644 index 4bb23ac8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# $Id: Makefile - -obj-$(CONFIG_LIBFC) += libfc.o - -libfc-objs := \ - fc_libfc.o \ - fc_disc.o \ - fc_exch.o \ - fc_elsct.o \ - fc_frame.o \ - fc_lport.o \ - fc_rport.o \ - fc_fcp.o \ - fc_npiv.o diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_disc.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_disc.c deleted file mode 100644 index 8e561e6a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_disc.c +++ /dev/null @@ -1,743 +0,0 @@ -/* - * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -/* - * Target Discovery - * - * This block discovers all FC-4 remote ports, including FCP initiators. It - * also handles RSCN events and re-discovery if necessary. - */ - -/* - * DISC LOCKING - * - * The disc mutex is can be locked when acquiring rport locks, but may not - * be held when acquiring the lport lock. Refer to fc_lport.c for more - * details. - */ - -#include -#include -#include -#include -#include - -#include - -#include - -#include "fc_libfc.h" - -#define FC_DISC_RETRY_LIMIT 3 /* max retries */ -#define FC_DISC_RETRY_DELAY 500UL /* (msecs) delay */ - -static void fc_disc_gpn_ft_req(struct fc_disc *); -static void fc_disc_gpn_ft_resp(struct fc_seq *, struct fc_frame *, void *); -static void fc_disc_done(struct fc_disc *, enum fc_disc_event); -static void fc_disc_timeout(struct work_struct *); -static int fc_disc_single(struct fc_lport *, struct fc_disc_port *); -static void fc_disc_restart(struct fc_disc *); - -/** - * fc_disc_stop_rports() - Delete all the remote ports associated with the lport - * @disc: The discovery job to stop remote ports on - * - * Locking Note: This function expects that the lport mutex is locked before - * calling it. - */ -static void fc_disc_stop_rports(struct fc_disc *disc) -{ - struct fc_lport *lport; - struct fc_rport_priv *rdata; - - lport = fc_disc_lport(disc); - - mutex_lock(&disc->disc_mutex); - list_for_each_entry_rcu(rdata, &disc->rports, peers) - lport->tt.rport_logoff(rdata); - mutex_unlock(&disc->disc_mutex); -} - -/** - * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN) - * @disc: The discovery object to which the RSCN applies - * @fp: The RSCN frame - * - * Locking Note: This function expects that the disc_mutex is locked - * before it is called. - */ -static void fc_disc_recv_rscn_req(struct fc_disc *disc, struct fc_frame *fp) -{ - struct fc_lport *lport; - struct fc_els_rscn *rp; - struct fc_els_rscn_page *pp; - struct fc_seq_els_data rjt_data; - unsigned int len; - int redisc = 0; - enum fc_els_rscn_ev_qual ev_qual; - enum fc_els_rscn_addr_fmt fmt; - LIST_HEAD(disc_ports); - struct fc_disc_port *dp, *next; - - lport = fc_disc_lport(disc); - - FC_DISC_DBG(disc, "Received an RSCN event\n"); - - /* make sure the frame contains an RSCN message */ - rp = fc_frame_payload_get(fp, sizeof(*rp)); - if (!rp) - goto reject; - /* make sure the page length is as expected (4 bytes) */ - if (rp->rscn_page_len != sizeof(*pp)) - goto reject; - /* get the RSCN payload length */ - len = ntohs(rp->rscn_plen); - if (len < sizeof(*rp)) - goto reject; - /* make sure the frame contains the expected payload */ - rp = fc_frame_payload_get(fp, len); - if (!rp) - goto reject; - /* payload must be a multiple of the RSCN page size */ - len -= sizeof(*rp); - if (len % sizeof(*pp)) - goto reject; - - for (pp = (void *)(rp + 1); len > 0; len -= sizeof(*pp), pp++) { - ev_qual = pp->rscn_page_flags >> ELS_RSCN_EV_QUAL_BIT; - ev_qual &= ELS_RSCN_EV_QUAL_MASK; - fmt = pp->rscn_page_flags >> ELS_RSCN_ADDR_FMT_BIT; - fmt &= ELS_RSCN_ADDR_FMT_MASK; - /* - * if we get an address format other than port - * (area, domain, fabric), then do a full discovery - */ - switch (fmt) { - case ELS_ADDR_FMT_PORT: - FC_DISC_DBG(disc, "Port address format for port " - "(%6.6x)\n", ntoh24(pp->rscn_fid)); - dp = kzalloc(sizeof(*dp), GFP_KERNEL); - if (!dp) { - redisc = 1; - break; - } - dp->lp = lport; - dp->port_id = ntoh24(pp->rscn_fid); - list_add_tail(&dp->peers, &disc_ports); - break; - case ELS_ADDR_FMT_AREA: - case ELS_ADDR_FMT_DOM: - case ELS_ADDR_FMT_FAB: - default: - FC_DISC_DBG(disc, "Address format is (%d)\n", fmt); - redisc = 1; - break; - } - } - lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); - - /* - * If not doing a complete rediscovery, do GPN_ID on - * the individual ports mentioned in the list. - * If any of these get an error, do a full rediscovery. - * In any case, go through the list and free the entries. - */ - list_for_each_entry_safe(dp, next, &disc_ports, peers) { - list_del(&dp->peers); - if (!redisc) - redisc = fc_disc_single(lport, dp); - kfree(dp); - } - if (redisc) { - FC_DISC_DBG(disc, "RSCN received: rediscovering\n"); - fc_disc_restart(disc); - } else { - FC_DISC_DBG(disc, "RSCN received: not rediscovering. " - "redisc %d state %d in_prog %d\n", - redisc, lport->state, disc->pending); - } - fc_frame_free(fp); - return; -reject: - FC_DISC_DBG(disc, "Received a bad RSCN frame\n"); - rjt_data.reason = ELS_RJT_LOGIC; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); -} - -/** - * fc_disc_recv_req() - Handle incoming requests - * @lport: The local port receiving the request - * @fp: The request frame - * - * Locking Note: This function is called from the EM and will lock - * the disc_mutex before calling the handler for the - * request. - */ -static void fc_disc_recv_req(struct fc_lport *lport, struct fc_frame *fp) -{ - u8 op; - struct fc_disc *disc = &lport->disc; - - op = fc_frame_payload_op(fp); - switch (op) { - case ELS_RSCN: - mutex_lock(&disc->disc_mutex); - fc_disc_recv_rscn_req(disc, fp); - mutex_unlock(&disc->disc_mutex); - break; - default: - FC_DISC_DBG(disc, "Received an unsupported request, " - "the opcode is (%x)\n", op); - fc_frame_free(fp); - break; - } -} - -/** - * fc_disc_restart() - Restart discovery - * @disc: The discovery object to be restarted - * - * Locking Note: This function expects that the disc mutex - * is already locked. - */ -static void fc_disc_restart(struct fc_disc *disc) -{ - if (!disc->disc_callback) - return; - - FC_DISC_DBG(disc, "Restarting discovery\n"); - - disc->requested = 1; - if (disc->pending) - return; - - /* - * Advance disc_id. This is an arbitrary non-zero number that will - * match the value in the fc_rport_priv after discovery for all - * freshly-discovered remote ports. Avoid wrapping to zero. - */ - disc->disc_id = (disc->disc_id + 2) | 1; - disc->retry_count = 0; - fc_disc_gpn_ft_req(disc); -} - -/** - * fc_disc_start() - Start discovery on a local port - * @lport: The local port to have discovery started on - * @disc_callback: Callback function to be called when discovery is complete - */ -static void fc_disc_start(void (*disc_callback)(struct fc_lport *, - enum fc_disc_event), - struct fc_lport *lport) -{ - struct fc_disc *disc = &lport->disc; - - /* - * At this point we may have a new disc job or an existing - * one. Either way, let's lock when we make changes to it - * and send the GPN_FT request. - */ - mutex_lock(&disc->disc_mutex); - disc->disc_callback = disc_callback; - fc_disc_restart(disc); - mutex_unlock(&disc->disc_mutex); -} - -/** - * fc_disc_done() - Discovery has been completed - * @disc: The discovery context - * @event: The discovery completion status - * - * Locking Note: This function expects that the disc mutex is locked before - * it is called. The discovery callback is then made with the lock released, - * and the lock is re-taken before returning from this function - */ -static void fc_disc_done(struct fc_disc *disc, enum fc_disc_event event) -{ - struct fc_lport *lport = fc_disc_lport(disc); - struct fc_rport_priv *rdata; - - FC_DISC_DBG(disc, "Discovery complete\n"); - - disc->pending = 0; - if (disc->requested) { - fc_disc_restart(disc); - return; - } - - /* - * Go through all remote ports. If they were found in the latest - * discovery, reverify or log them in. Otherwise, log them out. - * Skip ports which were never discovered. These are the dNS port - * and ports which were created by PLOGI. - */ - list_for_each_entry_rcu(rdata, &disc->rports, peers) { - if (!rdata->disc_id) - continue; - if (rdata->disc_id == disc->disc_id) - lport->tt.rport_login(rdata); - else - lport->tt.rport_logoff(rdata); - } - - mutex_unlock(&disc->disc_mutex); - disc->disc_callback(lport, event); - mutex_lock(&disc->disc_mutex); -} - -/** - * fc_disc_error() - Handle error on dNS request - * @disc: The discovery context - * @fp: The error code encoded as a frame pointer - */ -static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) -{ - struct fc_lport *lport = fc_disc_lport(disc); - unsigned long delay = 0; - - FC_DISC_DBG(disc, "Error %ld, retries %d/%d\n", - PTR_ERR(fp), disc->retry_count, - FC_DISC_RETRY_LIMIT); - - if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) { - /* - * Memory allocation failure, or the exchange timed out, - * retry after delay. - */ - if (disc->retry_count < FC_DISC_RETRY_LIMIT) { - /* go ahead and retry */ - if (!fp) - delay = msecs_to_jiffies(FC_DISC_RETRY_DELAY); - else { - delay = msecs_to_jiffies(lport->e_d_tov); - - /* timeout faster first time */ - if (!disc->retry_count) - delay /= 4; - } - disc->retry_count++; - schedule_delayed_work(&disc->disc_work, delay); - } else - fc_disc_done(disc, DISC_EV_FAILED); - } else if (PTR_ERR(fp) == -FC_EX_CLOSED) { - /* - * if discovery fails due to lport reset, clear - * pending flag so that subsequent discovery can - * continue - */ - disc->pending = 0; - } -} - -/** - * fc_disc_gpn_ft_req() - Send Get Port Names by FC-4 type (GPN_FT) request - * @lport: The discovery context - * - * Locking Note: This function expects that the disc_mutex is locked - * before it is called. - */ -static void fc_disc_gpn_ft_req(struct fc_disc *disc) -{ - struct fc_frame *fp; - struct fc_lport *lport = fc_disc_lport(disc); - - WARN_ON(!fc_lport_test_ready(lport)); - - disc->pending = 1; - disc->requested = 0; - - disc->buf_len = 0; - disc->seq_count = 0; - fp = fc_frame_alloc(lport, - sizeof(struct fc_ct_hdr) + - sizeof(struct fc_ns_gid_ft)); - if (!fp) - goto err; - - if (lport->tt.elsct_send(lport, 0, fp, - FC_NS_GPN_FT, - fc_disc_gpn_ft_resp, - disc, 3 * lport->r_a_tov)) - return; -err: - fc_disc_error(disc, NULL); -} - -/** - * fc_disc_gpn_ft_parse() - Parse the body of the dNS GPN_FT response. - * @lport: The local port the GPN_FT was received on - * @buf: The GPN_FT response buffer - * @len: The size of response buffer - * - * Goes through the list of IDs and names resulting from a request. - */ -static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) -{ - struct fc_lport *lport; - struct fc_gpn_ft_resp *np; - char *bp; - size_t plen; - size_t tlen; - int error = 0; - struct fc_rport_identifiers ids; - struct fc_rport_priv *rdata; - - lport = fc_disc_lport(disc); - disc->seq_count++; - - /* - * Handle partial name record left over from previous call. - */ - bp = buf; - plen = len; - np = (struct fc_gpn_ft_resp *)bp; - tlen = disc->buf_len; - disc->buf_len = 0; - if (tlen) { - WARN_ON(tlen >= sizeof(*np)); - plen = sizeof(*np) - tlen; - WARN_ON(plen <= 0); - WARN_ON(plen >= sizeof(*np)); - if (plen > len) - plen = len; - np = &disc->partial_buf; - memcpy((char *)np + tlen, bp, plen); - - /* - * Set bp so that the loop below will advance it to the - * first valid full name element. - */ - bp -= tlen; - len += tlen; - plen += tlen; - disc->buf_len = (unsigned char) plen; - if (plen == sizeof(*np)) - disc->buf_len = 0; - } - - /* - * Handle full name records, including the one filled from above. - * Normally, np == bp and plen == len, but from the partial case above, - * bp, len describe the overall buffer, and np, plen describe the - * partial buffer, which if would usually be full now. - * After the first time through the loop, things return to "normal". - */ - while (plen >= sizeof(*np)) { - ids.port_id = ntoh24(np->fp_fid); - ids.port_name = ntohll(np->fp_wwpn); - - if (ids.port_id != lport->port_id && - ids.port_name != lport->wwpn) { - rdata = lport->tt.rport_create(lport, ids.port_id); - if (rdata) { - rdata->ids.port_name = ids.port_name; - rdata->disc_id = disc->disc_id; - } else { - printk(KERN_WARNING "libfc: Failed to allocate " - "memory for the newly discovered port " - "(%6.6x)\n", ids.port_id); - error = -ENOMEM; - } - } - - if (np->fp_flags & FC_NS_FID_LAST) { - fc_disc_done(disc, DISC_EV_SUCCESS); - len = 0; - break; - } - len -= sizeof(*np); - bp += sizeof(*np); - np = (struct fc_gpn_ft_resp *)bp; - plen = len; - } - - /* - * Save any partial record at the end of the buffer for next time. - */ - if (error == 0 && len > 0 && len < sizeof(*np)) { - if (np != &disc->partial_buf) { - FC_DISC_DBG(disc, "Partial buffer remains " - "for discovery\n"); - memcpy(&disc->partial_buf, np, len); - } - disc->buf_len = (unsigned char) len; - } - return error; -} - -/** - * fc_disc_timeout() - Handler for discovery timeouts - * @work: Structure holding discovery context that needs to retry discovery - */ -static void fc_disc_timeout(struct work_struct *work) -{ - struct fc_disc *disc = container_of(work, - struct fc_disc, - disc_work.work); - mutex_lock(&disc->disc_mutex); - fc_disc_gpn_ft_req(disc); - mutex_unlock(&disc->disc_mutex); -} - -/** - * fc_disc_gpn_ft_resp() - Handle a response frame from Get Port Names (GPN_FT) - * @sp: The sequence that the GPN_FT response was received on - * @fp: The GPN_FT response frame - * @lp_arg: The discovery context - * - * Locking Note: This function is called without disc mutex held, and - * should do all its processing with the mutex held - */ -static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, - void *disc_arg) -{ - struct fc_disc *disc = disc_arg; - struct fc_ct_hdr *cp; - struct fc_frame_header *fh; - enum fc_disc_event event = DISC_EV_NONE; - unsigned int seq_cnt; - unsigned int len; - int error = 0; - - mutex_lock(&disc->disc_mutex); - FC_DISC_DBG(disc, "Received a GPN_FT response\n"); - - if (IS_ERR(fp)) { - fc_disc_error(disc, fp); - mutex_unlock(&disc->disc_mutex); - return; - } - - WARN_ON(!fc_frame_is_linear(fp)); /* buffer must be contiguous */ - fh = fc_frame_header_get(fp); - len = fr_len(fp) - sizeof(*fh); - seq_cnt = ntohs(fh->fh_seq_cnt); - if (fr_sof(fp) == FC_SOF_I3 && seq_cnt == 0 && disc->seq_count == 0) { - cp = fc_frame_payload_get(fp, sizeof(*cp)); - if (!cp) { - FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n", - fr_len(fp)); - event = DISC_EV_FAILED; - } else if (ntohs(cp->ct_cmd) == FC_FS_ACC) { - - /* Accepted, parse the response. */ - len -= sizeof(*cp); - error = fc_disc_gpn_ft_parse(disc, cp + 1, len); - } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { - FC_DISC_DBG(disc, "GPN_FT rejected reason %x exp %x " - "(check zoning)\n", cp->ct_reason, - cp->ct_explan); - event = DISC_EV_FAILED; - if (cp->ct_reason == FC_FS_RJT_UNABL && - cp->ct_explan == FC_FS_EXP_FTNR) - event = DISC_EV_SUCCESS; - } else { - FC_DISC_DBG(disc, "GPN_FT unexpected response code " - "%x\n", ntohs(cp->ct_cmd)); - event = DISC_EV_FAILED; - } - } else if (fr_sof(fp) == FC_SOF_N3 && seq_cnt == disc->seq_count) { - error = fc_disc_gpn_ft_parse(disc, fh + 1, len); - } else { - FC_DISC_DBG(disc, "GPN_FT unexpected frame - out of sequence? " - "seq_cnt %x expected %x sof %x eof %x\n", - seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); - event = DISC_EV_FAILED; - } - if (error) - fc_disc_error(disc, fp); - else if (event != DISC_EV_NONE) - fc_disc_done(disc, event); - fc_frame_free(fp); - mutex_unlock(&disc->disc_mutex); -} - -/** - * fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID) - * @sp: The sequence the GPN_ID is on - * @fp: The response frame - * @rdata_arg: The remote port that sent the GPN_ID response - * - * Locking Note: This function is called without disc mutex held. - */ -static void fc_disc_gpn_id_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rdata_arg) -{ - struct fc_rport_priv *rdata = rdata_arg; - struct fc_rport_priv *new_rdata; - struct fc_lport *lport; - struct fc_disc *disc; - struct fc_ct_hdr *cp; - struct fc_ns_gid_pn *pn; - u64 port_name; - - lport = rdata->local_port; - disc = &lport->disc; - - mutex_lock(&disc->disc_mutex); - if (PTR_ERR(fp) == -FC_EX_CLOSED) - goto out; - if (IS_ERR(fp)) - goto redisc; - - cp = fc_frame_payload_get(fp, sizeof(*cp)); - if (!cp) - goto redisc; - if (ntohs(cp->ct_cmd) == FC_FS_ACC) { - if (fr_len(fp) < sizeof(struct fc_frame_header) + - sizeof(*cp) + sizeof(*pn)) - goto redisc; - pn = (struct fc_ns_gid_pn *)(cp + 1); - port_name = get_unaligned_be64(&pn->fn_wwpn); - if (rdata->ids.port_name == -1) - rdata->ids.port_name = port_name; - else if (rdata->ids.port_name != port_name) { - FC_DISC_DBG(disc, "GPN_ID accepted. WWPN changed. " - "Port-id %6.6x wwpn %16.16llx\n", - rdata->ids.port_id, port_name); - lport->tt.rport_logoff(rdata); - - new_rdata = lport->tt.rport_create(lport, - rdata->ids.port_id); - if (new_rdata) { - new_rdata->disc_id = disc->disc_id; - lport->tt.rport_login(new_rdata); - } - goto out; - } - rdata->disc_id = disc->disc_id; - lport->tt.rport_login(rdata); - } else if (ntohs(cp->ct_cmd) == FC_FS_RJT) { - FC_DISC_DBG(disc, "GPN_ID rejected reason %x exp %x\n", - cp->ct_reason, cp->ct_explan); - lport->tt.rport_logoff(rdata); - } else { - FC_DISC_DBG(disc, "GPN_ID unexpected response code %x\n", - ntohs(cp->ct_cmd)); -redisc: - fc_disc_restart(disc); - } -out: - mutex_unlock(&disc->disc_mutex); - kref_put(&rdata->kref, lport->tt.rport_destroy); -} - -/** - * fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request - * @lport: The local port to initiate discovery on - * @rdata: remote port private data - * - * Locking Note: This function expects that the disc_mutex is locked - * before it is called. - * On failure, an error code is returned. - */ -static int fc_disc_gpn_id_req(struct fc_lport *lport, - struct fc_rport_priv *rdata) -{ - struct fc_frame *fp; - - fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + - sizeof(struct fc_ns_fid)); - if (!fp) - return -ENOMEM; - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, FC_NS_GPN_ID, - fc_disc_gpn_id_resp, rdata, - 3 * lport->r_a_tov)) - return -ENOMEM; - kref_get(&rdata->kref); - return 0; -} - -/** - * fc_disc_single() - Discover the directory information for a single target - * @lport: The local port the remote port is associated with - * @dp: The port to rediscover - * - * Locking Note: This function expects that the disc_mutex is locked - * before it is called. - */ -static int fc_disc_single(struct fc_lport *lport, struct fc_disc_port *dp) -{ - struct fc_rport_priv *rdata; - - rdata = lport->tt.rport_create(lport, dp->port_id); - if (!rdata) - return -ENOMEM; - rdata->disc_id = 0; - return fc_disc_gpn_id_req(lport, rdata); -} - -/** - * fc_disc_stop() - Stop discovery for a given lport - * @lport: The local port that discovery should stop on - */ -static void fc_disc_stop(struct fc_lport *lport) -{ - struct fc_disc *disc = &lport->disc; - - if (disc->pending) - cancel_delayed_work_sync(&disc->disc_work); - fc_disc_stop_rports(disc); -} - -/** - * fc_disc_stop_final() - Stop discovery for a given lport - * @lport: The lport that discovery should stop on - * - * This function will block until discovery has been - * completely stopped and all rports have been deleted. - */ -static void fc_disc_stop_final(struct fc_lport *lport) -{ - fc_disc_stop(lport); - lport->tt.rport_flush_queue(); -} - -/** - * fc_disc_init() - Initialize the discovery layer for a local port - * @lport: The local port that needs the discovery layer to be initialized - */ -int fc_disc_init(struct fc_lport *lport) -{ - struct fc_disc *disc; - - if (!lport->tt.disc_start) - lport->tt.disc_start = fc_disc_start; - - if (!lport->tt.disc_stop) - lport->tt.disc_stop = fc_disc_stop; - - if (!lport->tt.disc_stop_final) - lport->tt.disc_stop_final = fc_disc_stop_final; - - if (!lport->tt.disc_recv_req) - lport->tt.disc_recv_req = fc_disc_recv_req; - - disc = &lport->disc; - INIT_DELAYED_WORK(&disc->disc_work, fc_disc_timeout); - mutex_init(&disc->disc_mutex); - INIT_LIST_HEAD(&disc->rports); - - disc->priv = lport; - - return 0; -} -EXPORT_SYMBOL(fc_disc_init); diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_elsct.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_elsct.c deleted file mode 100644 index c2384d50..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_elsct.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright(c) 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -/* - * Provide interface to send ELS/CT FC frames - */ - -#include -#include -#include -#include -#include -#include -#include -#include "fc_libfc.h" - -/** - * fc_elsct_send() - Send an ELS or CT frame - * @lport: The local port to send the frame on - * @did: The destination ID for the frame - * @fp: The frame to be sent - * @op: The operational code - * @resp: The callback routine when the response is received - * @arg: The argument to pass to the response callback routine - * @timer_msec: The timeout period for the frame (in msecs) - */ -struct fc_seq *fc_elsct_send(struct fc_lport *lport, u32 did, - struct fc_frame *fp, unsigned int op, - void (*resp)(struct fc_seq *, - struct fc_frame *, - void *), - void *arg, u32 timer_msec) -{ - enum fc_rctl r_ctl; - enum fc_fh_type fh_type; - int rc; - - /* ELS requests */ - if ((op >= ELS_LS_RJT) && (op <= ELS_AUTH_ELS)) - rc = fc_els_fill(lport, did, fp, op, &r_ctl, &fh_type); - else { - /* CT requests */ - rc = fc_ct_fill(lport, did, fp, op, &r_ctl, &fh_type, &did); - } - - if (rc) { - fc_frame_free(fp); - return NULL; - } - - fc_fill_fc_hdr(fp, r_ctl, did, lport->port_id, fh_type, - FC_FCTL_REQ, 0); - - return lport->tt.exch_seq_send(lport, fp, resp, NULL, arg, timer_msec); -} -EXPORT_SYMBOL(fc_elsct_send); - -/** - * fc_elsct_init() - Initialize the ELS/CT layer - * @lport: The local port to initialize the ELS/CT layer for - */ -int fc_elsct_init(struct fc_lport *lport) -{ - if (!lport->tt.elsct_send) - lport->tt.elsct_send = fc_elsct_send; - - return 0; -} -EXPORT_SYMBOL(fc_elsct_init); - -/** - * fc_els_resp_type() - Return a string describing the ELS response - * @fp: The frame pointer or possible error code - */ -const char *fc_els_resp_type(struct fc_frame *fp) -{ - const char *msg; - struct fc_frame_header *fh; - struct fc_ct_hdr *ct; - - if (IS_ERR(fp)) { - switch (-PTR_ERR(fp)) { - case FC_NO_ERR: - msg = "response no error"; - break; - case FC_EX_TIMEOUT: - msg = "response timeout"; - break; - case FC_EX_CLOSED: - msg = "response closed"; - break; - default: - msg = "response unknown error"; - break; - } - } else { - fh = fc_frame_header_get(fp); - switch (fh->fh_type) { - case FC_TYPE_ELS: - switch (fc_frame_payload_op(fp)) { - case ELS_LS_ACC: - msg = "accept"; - break; - case ELS_LS_RJT: - msg = "reject"; - break; - default: - msg = "response unknown ELS"; - break; - } - break; - case FC_TYPE_CT: - ct = fc_frame_payload_get(fp, sizeof(*ct)); - if (ct) { - switch (ntohs(ct->ct_cmd)) { - case FC_FS_ACC: - msg = "CT accept"; - break; - case FC_FS_RJT: - msg = "CT reject"; - break; - default: - msg = "response unknown CT"; - break; - } - } else { - msg = "short CT response"; - } - break; - default: - msg = "response not ELS or CT"; - break; - } - } - return msg; -} diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_exch.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_exch.c deleted file mode 100644 index aceffadb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_exch.c +++ /dev/null @@ -1,2519 +0,0 @@ -/* - * Copyright(c) 2007 Intel Corporation. All rights reserved. - * Copyright(c) 2008 Red Hat, Inc. All rights reserved. - * Copyright(c) 2008 Mike Christie - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -/* - * Fibre Channel exchange and sequence handling. - */ - -#include -#include -#include -#include - -#include - -#include -#include - -#include "fc_libfc.h" - -u16 fc_cpu_mask; /* cpu mask for possible cpus */ -EXPORT_SYMBOL(fc_cpu_mask); -static u16 fc_cpu_order; /* 2's power to represent total possible cpus */ -static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ -static struct workqueue_struct *fc_exch_workqueue; - -/* - * Structure and function definitions for managing Fibre Channel Exchanges - * and Sequences. - * - * The three primary structures used here are fc_exch_mgr, fc_exch, and fc_seq. - * - * fc_exch_mgr holds the exchange state for an N port - * - * fc_exch holds state for one exchange and links to its active sequence. - * - * fc_seq holds the state for an individual sequence. - */ - -/** - * struct fc_exch_pool - Per cpu exchange pool - * @next_index: Next possible free exchange index - * @total_exches: Total allocated exchanges - * @lock: Exch pool lock - * @ex_list: List of exchanges - * - * This structure manages per cpu exchanges in array of exchange pointers. - * This array is allocated followed by struct fc_exch_pool memory for - * assigned range of exchanges to per cpu pool. - */ -struct fc_exch_pool { - spinlock_t lock; - struct list_head ex_list; - u16 next_index; - u16 total_exches; - - /* two cache of free slot in exch array */ - u16 left; - u16 right; -} ____cacheline_aligned_in_smp; - -/** - * struct fc_exch_mgr - The Exchange Manager (EM). - * @class: Default class for new sequences - * @kref: Reference counter - * @min_xid: Minimum exchange ID - * @max_xid: Maximum exchange ID - * @ep_pool: Reserved exchange pointers - * @pool_max_index: Max exch array index in exch pool - * @pool: Per cpu exch pool - * @stats: Statistics structure - * - * This structure is the center for creating exchanges and sequences. - * It manages the allocation of exchange IDs. - */ -struct fc_exch_mgr { - struct fc_exch_pool __percpu *pool; - mempool_t *ep_pool; - enum fc_class class; - struct kref kref; - u16 min_xid; - u16 max_xid; - u16 pool_max_index; - - /* - * currently exchange mgr stats are updated but not used. - * either stats can be expose via sysfs or remove them - * all together if not used XXX - */ - struct { - atomic_t no_free_exch; - atomic_t no_free_exch_xid; - atomic_t xid_not_found; - atomic_t xid_busy; - atomic_t seq_not_found; - atomic_t non_bls_resp; - } stats; -}; - -/** - * struct fc_exch_mgr_anchor - primary structure for list of EMs - * @ema_list: Exchange Manager Anchor list - * @mp: Exchange Manager associated with this anchor - * @match: Routine to determine if this anchor's EM should be used - * - * When walking the list of anchors the match routine will be called - * for each anchor to determine if that EM should be used. The last - * anchor in the list will always match to handle any exchanges not - * handled by other EMs. The non-default EMs would be added to the - * anchor list by HW that provides FCoE offloads. - */ -struct fc_exch_mgr_anchor { - struct list_head ema_list; - struct fc_exch_mgr *mp; - bool (*match)(struct fc_frame *); -}; - -static void fc_exch_rrq(struct fc_exch *); -static void fc_seq_ls_acc(struct fc_frame *); -static void fc_seq_ls_rjt(struct fc_frame *, enum fc_els_rjt_reason, - enum fc_els_rjt_explan); -static void fc_exch_els_rec(struct fc_frame *); -static void fc_exch_els_rrq(struct fc_frame *); - -/* - * Internal implementation notes. - * - * The exchange manager is one by default in libfc but LLD may choose - * to have one per CPU. The sequence manager is one per exchange manager - * and currently never separated. - * - * Section 9.8 in FC-FS-2 specifies: "The SEQ_ID is a one-byte field - * assigned by the Sequence Initiator that shall be unique for a specific - * D_ID and S_ID pair while the Sequence is open." Note that it isn't - * qualified by exchange ID, which one might think it would be. - * In practice this limits the number of open sequences and exchanges to 256 - * per session. For most targets we could treat this limit as per exchange. - * - * The exchange and its sequence are freed when the last sequence is received. - * It's possible for the remote port to leave an exchange open without - * sending any sequences. - * - * Notes on reference counts: - * - * Exchanges are reference counted and exchange gets freed when the reference - * count becomes zero. - * - * Timeouts: - * Sequences are timed out for E_D_TOV and R_A_TOV. - * - * Sequence event handling: - * - * The following events may occur on initiator sequences: - * - * Send. - * For now, the whole thing is sent. - * Receive ACK - * This applies only to class F. - * The sequence is marked complete. - * ULP completion. - * The upper layer calls fc_exch_done() when done - * with exchange and sequence tuple. - * RX-inferred completion. - * When we receive the next sequence on the same exchange, we can - * retire the previous sequence ID. (XXX not implemented). - * Timeout. - * R_A_TOV frees the sequence ID. If we're waiting for ACK, - * E_D_TOV causes abort and calls upper layer response handler - * with FC_EX_TIMEOUT error. - * Receive RJT - * XXX defer. - * Send ABTS - * On timeout. - * - * The following events may occur on recipient sequences: - * - * Receive - * Allocate sequence for first frame received. - * Hold during receive handler. - * Release when final frame received. - * Keep status of last N of these for the ELS RES command. XXX TBD. - * Receive ABTS - * Deallocate sequence - * Send RJT - * Deallocate - * - * For now, we neglect conditions where only part of a sequence was - * received or transmitted, or where out-of-order receipt is detected. - */ - -/* - * Locking notes: - * - * The EM code run in a per-CPU worker thread. - * - * To protect against concurrency between a worker thread code and timers, - * sequence allocation and deallocation must be locked. - * - exchange refcnt can be done atomicly without locks. - * - sequence allocation must be locked by exch lock. - * - If the EM pool lock and ex_lock must be taken at the same time, then the - * EM pool lock must be taken before the ex_lock. - */ - -/* - * opcode names for debugging. - */ -static char *fc_exch_rctl_names[] = FC_RCTL_NAMES_INIT; - -/** - * fc_exch_name_lookup() - Lookup name by opcode - * @op: Opcode to be looked up - * @table: Opcode/name table - * @max_index: Index not to be exceeded - * - * This routine is used to determine a human-readable string identifying - * a R_CTL opcode. - */ -static inline const char *fc_exch_name_lookup(unsigned int op, char **table, - unsigned int max_index) -{ - const char *name = NULL; - - if (op < max_index) - name = table[op]; - if (!name) - name = "unknown"; - return name; -} - -/** - * fc_exch_rctl_name() - Wrapper routine for fc_exch_name_lookup() - * @op: The opcode to be looked up - */ -static const char *fc_exch_rctl_name(unsigned int op) -{ - return fc_exch_name_lookup(op, fc_exch_rctl_names, - ARRAY_SIZE(fc_exch_rctl_names)); -} - -/** - * fc_exch_hold() - Increment an exchange's reference count - * @ep: Echange to be held - */ -static inline void fc_exch_hold(struct fc_exch *ep) -{ - atomic_inc(&ep->ex_refcnt); -} - -/** - * fc_exch_setup_hdr() - Initialize a FC header by initializing some fields - * and determine SOF and EOF. - * @ep: The exchange to that will use the header - * @fp: The frame whose header is to be modified - * @f_ctl: F_CTL bits that will be used for the frame header - * - * The fields initialized by this routine are: fh_ox_id, fh_rx_id, - * fh_seq_id, fh_seq_cnt and the SOF and EOF. - */ -static void fc_exch_setup_hdr(struct fc_exch *ep, struct fc_frame *fp, - u32 f_ctl) -{ - struct fc_frame_header *fh = fc_frame_header_get(fp); - u16 fill; - - fr_sof(fp) = ep->class; - if (ep->seq.cnt) - fr_sof(fp) = fc_sof_normal(ep->class); - - if (f_ctl & FC_FC_END_SEQ) { - fr_eof(fp) = FC_EOF_T; - if (fc_sof_needs_ack(ep->class)) - fr_eof(fp) = FC_EOF_N; - /* - * From F_CTL. - * The number of fill bytes to make the length a 4-byte - * multiple is the low order 2-bits of the f_ctl. - * The fill itself will have been cleared by the frame - * allocation. - * After this, the length will be even, as expected by - * the transport. - */ - fill = fr_len(fp) & 3; - if (fill) { - fill = 4 - fill; - /* TODO, this may be a problem with fragmented skb */ - skb_put(fp_skb(fp), fill); - hton24(fh->fh_f_ctl, f_ctl | fill); - } - } else { - WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */ - fr_eof(fp) = FC_EOF_N; - } - - /* - * Initialize remainig fh fields - * from fc_fill_fc_hdr - */ - fh->fh_ox_id = htons(ep->oxid); - fh->fh_rx_id = htons(ep->rxid); - fh->fh_seq_id = ep->seq.id; - fh->fh_seq_cnt = htons(ep->seq.cnt); -} - -/** - * fc_exch_release() - Decrement an exchange's reference count - * @ep: Exchange to be released - * - * If the reference count reaches zero and the exchange is complete, - * it is freed. - */ -static void fc_exch_release(struct fc_exch *ep) -{ - struct fc_exch_mgr *mp; - - if (atomic_dec_and_test(&ep->ex_refcnt)) { - mp = ep->em; - if (ep->destructor) - ep->destructor(&ep->seq, ep->arg); - WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE)); - mempool_free(ep, mp->ep_pool); - } -} - -/** - * fc_exch_done_locked() - Complete an exchange with the exchange lock held - * @ep: The exchange that is complete - */ -static int fc_exch_done_locked(struct fc_exch *ep) -{ - int rc = 1; - - /* - * We must check for completion in case there are two threads - * tyring to complete this. But the rrq code will reuse the - * ep, and in that case we only clear the resp and set it as - * complete, so it can be reused by the timer to send the rrq. - */ - ep->resp = NULL; - if (ep->state & FC_EX_DONE) - return rc; - ep->esb_stat |= ESB_ST_COMPLETE; - - if (!(ep->esb_stat & ESB_ST_REC_QUAL)) { - ep->state |= FC_EX_DONE; - if (cancel_delayed_work(&ep->timeout_work)) - atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ - rc = 0; - } - return rc; -} - -/** - * fc_exch_ptr_get() - Return an exchange from an exchange pool - * @pool: Exchange Pool to get an exchange from - * @index: Index of the exchange within the pool - * - * Use the index to get an exchange from within an exchange pool. exches - * will point to an array of exchange pointers. The index will select - * the exchange within the array. - */ -static inline struct fc_exch *fc_exch_ptr_get(struct fc_exch_pool *pool, - u16 index) -{ - struct fc_exch **exches = (struct fc_exch **)(pool + 1); - return exches[index]; -} - -/** - * fc_exch_ptr_set() - Assign an exchange to a slot in an exchange pool - * @pool: The pool to assign the exchange to - * @index: The index in the pool where the exchange will be assigned - * @ep: The exchange to assign to the pool - */ -static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index, - struct fc_exch *ep) -{ - ((struct fc_exch **)(pool + 1))[index] = ep; -} - -/** - * fc_exch_delete() - Delete an exchange - * @ep: The exchange to be deleted - */ -static void fc_exch_delete(struct fc_exch *ep) -{ - struct fc_exch_pool *pool; - u16 index; - - pool = ep->pool; - spin_lock_bh(&pool->lock); - WARN_ON(pool->total_exches <= 0); - pool->total_exches--; - - /* update cache of free slot */ - index = (ep->xid - ep->em->min_xid) >> fc_cpu_order; - if (pool->left == FC_XID_UNKNOWN) - pool->left = index; - else if (pool->right == FC_XID_UNKNOWN) - pool->right = index; - else - pool->next_index = index; - - fc_exch_ptr_set(pool, index, NULL); - list_del(&ep->ex_list); - spin_unlock_bh(&pool->lock); - fc_exch_release(ep); /* drop hold for exch in mp */ -} - -/** - * fc_exch_timer_set_locked() - Start a timer for an exchange w/ the - * the exchange lock held - * @ep: The exchange whose timer will start - * @timer_msec: The timeout period - * - * Used for upper level protocols to time out the exchange. - * The timer is cancelled when it fires or when the exchange completes. - */ -static inline void fc_exch_timer_set_locked(struct fc_exch *ep, - unsigned int timer_msec) -{ - if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) - return; - - FC_EXCH_DBG(ep, "Exchange timer armed\n"); - - if (queue_delayed_work(fc_exch_workqueue, &ep->timeout_work, - msecs_to_jiffies(timer_msec))) - fc_exch_hold(ep); /* hold for timer */ -} - -/** - * fc_exch_timer_set() - Lock the exchange and set the timer - * @ep: The exchange whose timer will start - * @timer_msec: The timeout period - */ -static void fc_exch_timer_set(struct fc_exch *ep, unsigned int timer_msec) -{ - spin_lock_bh(&ep->ex_lock); - fc_exch_timer_set_locked(ep, timer_msec); - spin_unlock_bh(&ep->ex_lock); -} - -/** - * fc_seq_send() - Send a frame using existing sequence/exchange pair - * @lport: The local port that the exchange will be sent on - * @sp: The sequence to be sent - * @fp: The frame to be sent on the exchange - */ -static int fc_seq_send(struct fc_lport *lport, struct fc_seq *sp, - struct fc_frame *fp) -{ - struct fc_exch *ep; - struct fc_frame_header *fh = fc_frame_header_get(fp); - int error; - u32 f_ctl; - u8 fh_type = fh->fh_type; - - ep = fc_seq_exch(sp); - WARN_ON((ep->esb_stat & ESB_ST_SEQ_INIT) != ESB_ST_SEQ_INIT); - - f_ctl = ntoh24(fh->fh_f_ctl); - fc_exch_setup_hdr(ep, fp, f_ctl); - fr_encaps(fp) = ep->encaps; - - /* - * update sequence count if this frame is carrying - * multiple FC frames when sequence offload is enabled - * by LLD. - */ - if (fr_max_payload(fp)) - sp->cnt += DIV_ROUND_UP((fr_len(fp) - sizeof(*fh)), - fr_max_payload(fp)); - else - sp->cnt++; - - /* - * Send the frame. - */ - error = lport->tt.frame_send(lport, fp); - - if (fh_type == FC_TYPE_BLS) - return error; - - /* - * Update the exchange and sequence flags, - * assuming all frames for the sequence have been sent. - * We can only be called to send once for each sequence. - */ - spin_lock_bh(&ep->ex_lock); - ep->f_ctl = f_ctl & ~FC_FC_FIRST_SEQ; /* not first seq */ - if (f_ctl & FC_FC_SEQ_INIT) - ep->esb_stat &= ~ESB_ST_SEQ_INIT; - spin_unlock_bh(&ep->ex_lock); - return error; -} - -/** - * fc_seq_alloc() - Allocate a sequence for a given exchange - * @ep: The exchange to allocate a new sequence for - * @seq_id: The sequence ID to be used - * - * We don't support multiple originated sequences on the same exchange. - * By implication, any previously originated sequence on this exchange - * is complete, and we reallocate the same sequence. - */ -static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) -{ - struct fc_seq *sp; - - sp = &ep->seq; - sp->ssb_stat = 0; - sp->cnt = 0; - sp->id = seq_id; - return sp; -} - -/** - * fc_seq_start_next_locked() - Allocate a new sequence on the same - * exchange as the supplied sequence - * @sp: The sequence/exchange to get a new sequence for - */ -static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp) -{ - struct fc_exch *ep = fc_seq_exch(sp); - - sp = fc_seq_alloc(ep, ep->seq_id++); - FC_EXCH_DBG(ep, "f_ctl %6x seq %2x\n", - ep->f_ctl, sp->id); - return sp; -} - -/** - * fc_seq_start_next() - Lock the exchange and get a new sequence - * for a given sequence/exchange pair - * @sp: The sequence/exchange to get a new exchange for - */ -static struct fc_seq *fc_seq_start_next(struct fc_seq *sp) -{ - struct fc_exch *ep = fc_seq_exch(sp); - - spin_lock_bh(&ep->ex_lock); - sp = fc_seq_start_next_locked(sp); - spin_unlock_bh(&ep->ex_lock); - - return sp; -} - -/* - * Set the response handler for the exchange associated with a sequence. - */ -static void fc_seq_set_resp(struct fc_seq *sp, - void (*resp)(struct fc_seq *, struct fc_frame *, - void *), - void *arg) -{ - struct fc_exch *ep = fc_seq_exch(sp); - - spin_lock_bh(&ep->ex_lock); - ep->resp = resp; - ep->arg = arg; - spin_unlock_bh(&ep->ex_lock); -} - -/** - * fc_exch_abort_locked() - Abort an exchange - * @ep: The exchange to be aborted - * @timer_msec: The period of time to wait before aborting - * - * Locking notes: Called with exch lock held - * - * Return value: 0 on success else error code - */ -static int fc_exch_abort_locked(struct fc_exch *ep, - unsigned int timer_msec) -{ - struct fc_seq *sp; - struct fc_frame *fp; - int error; - - if (ep->esb_stat & (ESB_ST_COMPLETE | ESB_ST_ABNORMAL) || - ep->state & (FC_EX_DONE | FC_EX_RST_CLEANUP)) - return -ENXIO; - - /* - * Send the abort on a new sequence if possible. - */ - sp = fc_seq_start_next_locked(&ep->seq); - if (!sp) - return -ENOMEM; - - ep->esb_stat |= ESB_ST_SEQ_INIT | ESB_ST_ABNORMAL; - if (timer_msec) - fc_exch_timer_set_locked(ep, timer_msec); - - /* - * If not logged into the fabric, don't send ABTS but leave - * sequence active until next timeout. - */ - if (!ep->sid) - return 0; - - /* - * Send an abort for the sequence that timed out. - */ - fp = fc_frame_alloc(ep->lp, 0); - if (fp) { - fc_fill_fc_hdr(fp, FC_RCTL_BA_ABTS, ep->did, ep->sid, - FC_TYPE_BLS, FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - error = fc_seq_send(ep->lp, sp, fp); - } else - error = -ENOBUFS; - return error; -} - -/** - * fc_seq_exch_abort() - Abort an exchange and sequence - * @req_sp: The sequence to be aborted - * @timer_msec: The period of time to wait before aborting - * - * Generally called because of a timeout or an abort from the upper layer. - * - * Return value: 0 on success else error code - */ -static int fc_seq_exch_abort(const struct fc_seq *req_sp, - unsigned int timer_msec) -{ - struct fc_exch *ep; - int error; - - ep = fc_seq_exch(req_sp); - spin_lock_bh(&ep->ex_lock); - error = fc_exch_abort_locked(ep, timer_msec); - spin_unlock_bh(&ep->ex_lock); - return error; -} - -/** - * fc_exch_timeout() - Handle exchange timer expiration - * @work: The work_struct identifying the exchange that timed out - */ -static void fc_exch_timeout(struct work_struct *work) -{ - struct fc_exch *ep = container_of(work, struct fc_exch, - timeout_work.work); - struct fc_seq *sp = &ep->seq; - void (*resp)(struct fc_seq *, struct fc_frame *fp, void *arg); - void *arg; - u32 e_stat; - int rc = 1; - - FC_EXCH_DBG(ep, "Exchange timed out\n"); - - spin_lock_bh(&ep->ex_lock); - if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) - goto unlock; - - e_stat = ep->esb_stat; - if (e_stat & ESB_ST_COMPLETE) { - ep->esb_stat = e_stat & ~ESB_ST_REC_QUAL; - spin_unlock_bh(&ep->ex_lock); - if (e_stat & ESB_ST_REC_QUAL) - fc_exch_rrq(ep); - goto done; - } else { - resp = ep->resp; - arg = ep->arg; - ep->resp = NULL; - if (e_stat & ESB_ST_ABNORMAL) - rc = fc_exch_done_locked(ep); - spin_unlock_bh(&ep->ex_lock); - if (!rc) - fc_exch_delete(ep); - if (resp) - resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); - fc_seq_exch_abort(sp, 2 * ep->r_a_tov); - goto done; - } -unlock: - spin_unlock_bh(&ep->ex_lock); -done: - /* - * This release matches the hold taken when the timer was set. - */ - fc_exch_release(ep); -} - -/** - * fc_exch_em_alloc() - Allocate an exchange from a specified EM. - * @lport: The local port that the exchange is for - * @mp: The exchange manager that will allocate the exchange - * - * Returns pointer to allocated fc_exch with exch lock held. - */ -static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, - struct fc_exch_mgr *mp) -{ - struct fc_exch *ep; - unsigned int cpu; - u16 index; - struct fc_exch_pool *pool; - - /* allocate memory for exchange */ - ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); - if (!ep) { - atomic_inc(&mp->stats.no_free_exch); - goto out; - } - memset(ep, 0, sizeof(*ep)); - - cpu = get_cpu(); - pool = per_cpu_ptr(mp->pool, cpu); - spin_lock_bh(&pool->lock); - put_cpu(); - - /* peek cache of free slot */ - if (pool->left != FC_XID_UNKNOWN) { - index = pool->left; - pool->left = FC_XID_UNKNOWN; - goto hit; - } - if (pool->right != FC_XID_UNKNOWN) { - index = pool->right; - pool->right = FC_XID_UNKNOWN; - goto hit; - } - - index = pool->next_index; - /* allocate new exch from pool */ - while (fc_exch_ptr_get(pool, index)) { - index = index == mp->pool_max_index ? 0 : index + 1; - if (index == pool->next_index) - goto err; - } - pool->next_index = index == mp->pool_max_index ? 0 : index + 1; -hit: - fc_exch_hold(ep); /* hold for exch in mp */ - spin_lock_init(&ep->ex_lock); - /* - * Hold exch lock for caller to prevent fc_exch_reset() - * from releasing exch while fc_exch_alloc() caller is - * still working on exch. - */ - spin_lock_bh(&ep->ex_lock); - - fc_exch_ptr_set(pool, index, ep); - list_add_tail(&ep->ex_list, &pool->ex_list); - fc_seq_alloc(ep, ep->seq_id++); - pool->total_exches++; - spin_unlock_bh(&pool->lock); - - /* - * update exchange - */ - ep->oxid = ep->xid = (index << fc_cpu_order | cpu) + mp->min_xid; - ep->em = mp; - ep->pool = pool; - ep->lp = lport; - ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ - ep->rxid = FC_XID_UNKNOWN; - ep->class = mp->class; - INIT_DELAYED_WORK(&ep->timeout_work, fc_exch_timeout); -out: - return ep; -err: - spin_unlock_bh(&pool->lock); - atomic_inc(&mp->stats.no_free_exch_xid); - mempool_free(ep, mp->ep_pool); - return NULL; -} - -/** - * fc_exch_alloc() - Allocate an exchange from an EM on a - * local port's list of EMs. - * @lport: The local port that will own the exchange - * @fp: The FC frame that the exchange will be for - * - * This function walks the list of exchange manager(EM) - * anchors to select an EM for a new exchange allocation. The - * EM is selected when a NULL match function pointer is encountered - * or when a call to a match function returns true. - */ -static inline struct fc_exch *fc_exch_alloc(struct fc_lport *lport, - struct fc_frame *fp) -{ - struct fc_exch_mgr_anchor *ema; - - list_for_each_entry(ema, &lport->ema_list, ema_list) - if (!ema->match || ema->match(fp)) - return fc_exch_em_alloc(lport, ema->mp); - return NULL; -} - -/** - * fc_exch_find() - Lookup and hold an exchange - * @mp: The exchange manager to lookup the exchange from - * @xid: The XID of the exchange to look up - */ -static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid) -{ - struct fc_exch_pool *pool; - struct fc_exch *ep = NULL; - - if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) { - pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask); - spin_lock_bh(&pool->lock); - ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order); - if (ep && ep->xid == xid) - fc_exch_hold(ep); - spin_unlock_bh(&pool->lock); - } - return ep; -} - - -/** - * fc_exch_done() - Indicate that an exchange/sequence tuple is complete and - * the memory allocated for the related objects may be freed. - * @sp: The sequence that has completed - */ -static void fc_exch_done(struct fc_seq *sp) -{ - struct fc_exch *ep = fc_seq_exch(sp); - int rc; - - spin_lock_bh(&ep->ex_lock); - rc = fc_exch_done_locked(ep); - spin_unlock_bh(&ep->ex_lock); - if (!rc) - fc_exch_delete(ep); -} - -/** - * fc_exch_resp() - Allocate a new exchange for a response frame - * @lport: The local port that the exchange was for - * @mp: The exchange manager to allocate the exchange from - * @fp: The response frame - * - * Sets the responder ID in the frame header. - */ -static struct fc_exch *fc_exch_resp(struct fc_lport *lport, - struct fc_exch_mgr *mp, - struct fc_frame *fp) -{ - struct fc_exch *ep; - struct fc_frame_header *fh; - - ep = fc_exch_alloc(lport, fp); - if (ep) { - ep->class = fc_frame_class(fp); - - /* - * Set EX_CTX indicating we're responding on this exchange. - */ - ep->f_ctl |= FC_FC_EX_CTX; /* we're responding */ - ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not new */ - fh = fc_frame_header_get(fp); - ep->sid = ntoh24(fh->fh_d_id); - ep->did = ntoh24(fh->fh_s_id); - ep->oid = ep->did; - - /* - * Allocated exchange has placed the XID in the - * originator field. Move it to the responder field, - * and set the originator XID from the frame. - */ - ep->rxid = ep->xid; - ep->oxid = ntohs(fh->fh_ox_id); - ep->esb_stat |= ESB_ST_RESP | ESB_ST_SEQ_INIT; - if ((ntoh24(fh->fh_f_ctl) & FC_FC_SEQ_INIT) == 0) - ep->esb_stat &= ~ESB_ST_SEQ_INIT; - - fc_exch_hold(ep); /* hold for caller */ - spin_unlock_bh(&ep->ex_lock); /* lock from fc_exch_alloc */ - } - return ep; -} - -/** - * fc_seq_lookup_recip() - Find a sequence where the other end - * originated the sequence - * @lport: The local port that the frame was sent to - * @mp: The Exchange Manager to lookup the exchange from - * @fp: The frame associated with the sequence we're looking for - * - * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold - * on the ep that should be released by the caller. - */ -static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, - struct fc_exch_mgr *mp, - struct fc_frame *fp) -{ - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fc_exch *ep = NULL; - struct fc_seq *sp = NULL; - enum fc_pf_rjt_reason reject = FC_RJT_NONE; - u32 f_ctl; - u16 xid; - - f_ctl = ntoh24(fh->fh_f_ctl); - WARN_ON((f_ctl & FC_FC_SEQ_CTX) != 0); - - /* - * Lookup or create the exchange if we will be creating the sequence. - */ - if (f_ctl & FC_FC_EX_CTX) { - xid = ntohs(fh->fh_ox_id); /* we originated exch */ - ep = fc_exch_find(mp, xid); - if (!ep) { - atomic_inc(&mp->stats.xid_not_found); - reject = FC_RJT_OX_ID; - goto out; - } - if (ep->rxid == FC_XID_UNKNOWN) - ep->rxid = ntohs(fh->fh_rx_id); - else if (ep->rxid != ntohs(fh->fh_rx_id)) { - reject = FC_RJT_OX_ID; - goto rel; - } - } else { - xid = ntohs(fh->fh_rx_id); /* we are the responder */ - - /* - * Special case for MDS issuing an ELS TEST with a - * bad rxid of 0. - * XXX take this out once we do the proper reject. - */ - if (xid == 0 && fh->fh_r_ctl == FC_RCTL_ELS_REQ && - fc_frame_payload_op(fp) == ELS_TEST) { - fh->fh_rx_id = htons(FC_XID_UNKNOWN); - xid = FC_XID_UNKNOWN; - } - - /* - * new sequence - find the exchange - */ - ep = fc_exch_find(mp, xid); - if ((f_ctl & FC_FC_FIRST_SEQ) && fc_sof_is_init(fr_sof(fp))) { - if (ep) { - atomic_inc(&mp->stats.xid_busy); - reject = FC_RJT_RX_ID; - goto rel; - } - ep = fc_exch_resp(lport, mp, fp); - if (!ep) { - reject = FC_RJT_EXCH_EST; /* XXX */ - goto out; - } - xid = ep->xid; /* get our XID */ - } else if (!ep) { - atomic_inc(&mp->stats.xid_not_found); - reject = FC_RJT_RX_ID; /* XID not found */ - goto out; - } - } - - /* - * At this point, we have the exchange held. - * Find or create the sequence. - */ - if (fc_sof_is_init(fr_sof(fp))) { - sp = &ep->seq; - sp->ssb_stat |= SSB_ST_RESP; - sp->id = fh->fh_seq_id; - } else { - sp = &ep->seq; - if (sp->id != fh->fh_seq_id) { - atomic_inc(&mp->stats.seq_not_found); - if (f_ctl & FC_FC_END_SEQ) { - /* - * Update sequence_id based on incoming last - * frame of sequence exchange. This is needed - * for FCoE target where DDP has been used - * on target where, stack is indicated only - * about last frame's (payload _header) header. - * Whereas "seq_id" which is part of - * frame_header is allocated by initiator - * which is totally different from "seq_id" - * allocated when XFER_RDY was sent by target. - * To avoid false -ve which results into not - * sending RSP, hence write request on other - * end never finishes. - */ - spin_lock_bh(&ep->ex_lock); - sp->ssb_stat |= SSB_ST_RESP; - sp->id = fh->fh_seq_id; - spin_unlock_bh(&ep->ex_lock); - } else { - /* sequence/exch should exist */ - reject = FC_RJT_SEQ_ID; - goto rel; - } - } - } - WARN_ON(ep != fc_seq_exch(sp)); - - if (f_ctl & FC_FC_SEQ_INIT) - ep->esb_stat |= ESB_ST_SEQ_INIT; - - fr_seq(fp) = sp; -out: - return reject; -rel: - fc_exch_done(&ep->seq); - fc_exch_release(ep); /* hold from fc_exch_find/fc_exch_resp */ - return reject; -} - -/** - * fc_seq_lookup_orig() - Find a sequence where this end - * originated the sequence - * @mp: The Exchange Manager to lookup the exchange from - * @fp: The frame associated with the sequence we're looking for - * - * Does not hold the sequence for the caller. - */ -static struct fc_seq *fc_seq_lookup_orig(struct fc_exch_mgr *mp, - struct fc_frame *fp) -{ - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fc_exch *ep; - struct fc_seq *sp = NULL; - u32 f_ctl; - u16 xid; - - f_ctl = ntoh24(fh->fh_f_ctl); - WARN_ON((f_ctl & FC_FC_SEQ_CTX) != FC_FC_SEQ_CTX); - xid = ntohs((f_ctl & FC_FC_EX_CTX) ? fh->fh_ox_id : fh->fh_rx_id); - ep = fc_exch_find(mp, xid); - if (!ep) - return NULL; - if (ep->seq.id == fh->fh_seq_id) { - /* - * Save the RX_ID if we didn't previously know it. - */ - sp = &ep->seq; - if ((f_ctl & FC_FC_EX_CTX) != 0 && - ep->rxid == FC_XID_UNKNOWN) { - ep->rxid = ntohs(fh->fh_rx_id); - } - } - fc_exch_release(ep); - return sp; -} - -/** - * fc_exch_set_addr() - Set the source and destination IDs for an exchange - * @ep: The exchange to set the addresses for - * @orig_id: The originator's ID - * @resp_id: The responder's ID - * - * Note this must be done before the first sequence of the exchange is sent. - */ -static void fc_exch_set_addr(struct fc_exch *ep, - u32 orig_id, u32 resp_id) -{ - ep->oid = orig_id; - if (ep->esb_stat & ESB_ST_RESP) { - ep->sid = resp_id; - ep->did = orig_id; - } else { - ep->sid = orig_id; - ep->did = resp_id; - } -} - -/** - * fc_seq_els_rsp_send() - Send an ELS response using information from - * the existing sequence/exchange. - * @fp: The received frame - * @els_cmd: The ELS command to be sent - * @els_data: The ELS data to be sent - * - * The received frame is not freed. - */ -static void fc_seq_els_rsp_send(struct fc_frame *fp, enum fc_els_cmd els_cmd, - struct fc_seq_els_data *els_data) -{ - switch (els_cmd) { - case ELS_LS_RJT: - fc_seq_ls_rjt(fp, els_data->reason, els_data->explan); - break; - case ELS_LS_ACC: - fc_seq_ls_acc(fp); - break; - case ELS_RRQ: - fc_exch_els_rrq(fp); - break; - case ELS_REC: - fc_exch_els_rec(fp); - break; - default: - FC_LPORT_DBG(fr_dev(fp), "Invalid ELS CMD:%x\n", els_cmd); - } -} - -/** - * fc_seq_send_last() - Send a sequence that is the last in the exchange - * @sp: The sequence that is to be sent - * @fp: The frame that will be sent on the sequence - * @rctl: The R_CTL information to be sent - * @fh_type: The frame header type - */ -static void fc_seq_send_last(struct fc_seq *sp, struct fc_frame *fp, - enum fc_rctl rctl, enum fc_fh_type fh_type) -{ - u32 f_ctl; - struct fc_exch *ep = fc_seq_exch(sp); - - f_ctl = FC_FC_LAST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT; - f_ctl |= ep->f_ctl; - fc_fill_fc_hdr(fp, rctl, ep->did, ep->sid, fh_type, f_ctl, 0); - fc_seq_send(ep->lp, sp, fp); -} - -/** - * fc_seq_send_ack() - Send an acknowledgement that we've received a frame - * @sp: The sequence to send the ACK on - * @rx_fp: The received frame that is being acknoledged - * - * Send ACK_1 (or equiv.) indicating we received something. - */ -static void fc_seq_send_ack(struct fc_seq *sp, const struct fc_frame *rx_fp) -{ - struct fc_frame *fp; - struct fc_frame_header *rx_fh; - struct fc_frame_header *fh; - struct fc_exch *ep = fc_seq_exch(sp); - struct fc_lport *lport = ep->lp; - unsigned int f_ctl; - - /* - * Don't send ACKs for class 3. - */ - if (fc_sof_needs_ack(fr_sof(rx_fp))) { - fp = fc_frame_alloc(lport, 0); - if (!fp) - return; - - fh = fc_frame_header_get(fp); - fh->fh_r_ctl = FC_RCTL_ACK_1; - fh->fh_type = FC_TYPE_BLS; - - /* - * Form f_ctl by inverting EX_CTX and SEQ_CTX (bits 23, 22). - * Echo FIRST_SEQ, LAST_SEQ, END_SEQ, END_CONN, SEQ_INIT. - * Bits 9-8 are meaningful (retransmitted or unidirectional). - * Last ACK uses bits 7-6 (continue sequence), - * bits 5-4 are meaningful (what kind of ACK to use). - */ - rx_fh = fc_frame_header_get(rx_fp); - f_ctl = ntoh24(rx_fh->fh_f_ctl); - f_ctl &= FC_FC_EX_CTX | FC_FC_SEQ_CTX | - FC_FC_FIRST_SEQ | FC_FC_LAST_SEQ | - FC_FC_END_SEQ | FC_FC_END_CONN | FC_FC_SEQ_INIT | - FC_FC_RETX_SEQ | FC_FC_UNI_TX; - f_ctl ^= FC_FC_EX_CTX | FC_FC_SEQ_CTX; - hton24(fh->fh_f_ctl, f_ctl); - - fc_exch_setup_hdr(ep, fp, f_ctl); - fh->fh_seq_id = rx_fh->fh_seq_id; - fh->fh_seq_cnt = rx_fh->fh_seq_cnt; - fh->fh_parm_offset = htonl(1); /* ack single frame */ - - fr_sof(fp) = fr_sof(rx_fp); - if (f_ctl & FC_FC_END_SEQ) - fr_eof(fp) = FC_EOF_T; - else - fr_eof(fp) = FC_EOF_N; - - lport->tt.frame_send(lport, fp); - } -} - -/** - * fc_exch_send_ba_rjt() - Send BLS Reject - * @rx_fp: The frame being rejected - * @reason: The reason the frame is being rejected - * @explan: The explanation for the rejection - * - * This is for rejecting BA_ABTS only. - */ -static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp, - enum fc_ba_rjt_reason reason, - enum fc_ba_rjt_explan explan) -{ - struct fc_frame *fp; - struct fc_frame_header *rx_fh; - struct fc_frame_header *fh; - struct fc_ba_rjt *rp; - struct fc_lport *lport; - unsigned int f_ctl; - - lport = fr_dev(rx_fp); - fp = fc_frame_alloc(lport, sizeof(*rp)); - if (!fp) - return; - fh = fc_frame_header_get(fp); - rx_fh = fc_frame_header_get(rx_fp); - - memset(fh, 0, sizeof(*fh) + sizeof(*rp)); - - rp = fc_frame_payload_get(fp, sizeof(*rp)); - rp->br_reason = reason; - rp->br_explan = explan; - - /* - * seq_id, cs_ctl, df_ctl and param/offset are zero. - */ - memcpy(fh->fh_s_id, rx_fh->fh_d_id, 3); - memcpy(fh->fh_d_id, rx_fh->fh_s_id, 3); - fh->fh_ox_id = rx_fh->fh_ox_id; - fh->fh_rx_id = rx_fh->fh_rx_id; - fh->fh_seq_cnt = rx_fh->fh_seq_cnt; - fh->fh_r_ctl = FC_RCTL_BA_RJT; - fh->fh_type = FC_TYPE_BLS; - - /* - * Form f_ctl by inverting EX_CTX and SEQ_CTX (bits 23, 22). - * Echo FIRST_SEQ, LAST_SEQ, END_SEQ, END_CONN, SEQ_INIT. - * Bits 9-8 are meaningful (retransmitted or unidirectional). - * Last ACK uses bits 7-6 (continue sequence), - * bits 5-4 are meaningful (what kind of ACK to use). - * Always set LAST_SEQ, END_SEQ. - */ - f_ctl = ntoh24(rx_fh->fh_f_ctl); - f_ctl &= FC_FC_EX_CTX | FC_FC_SEQ_CTX | - FC_FC_END_CONN | FC_FC_SEQ_INIT | - FC_FC_RETX_SEQ | FC_FC_UNI_TX; - f_ctl ^= FC_FC_EX_CTX | FC_FC_SEQ_CTX; - f_ctl |= FC_FC_LAST_SEQ | FC_FC_END_SEQ; - f_ctl &= ~FC_FC_FIRST_SEQ; - hton24(fh->fh_f_ctl, f_ctl); - - fr_sof(fp) = fc_sof_class(fr_sof(rx_fp)); - fr_eof(fp) = FC_EOF_T; - if (fc_sof_needs_ack(fr_sof(fp))) - fr_eof(fp) = FC_EOF_N; - - lport->tt.frame_send(lport, fp); -} - -/** - * fc_exch_recv_abts() - Handle an incoming ABTS - * @ep: The exchange the abort was on - * @rx_fp: The ABTS frame - * - * This would be for target mode usually, but could be due to lost - * FCP transfer ready, confirm or RRQ. We always handle this as an - * exchange abort, ignoring the parameter. - */ -static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp) -{ - struct fc_frame *fp; - struct fc_ba_acc *ap; - struct fc_frame_header *fh; - struct fc_seq *sp; - - if (!ep) - goto reject; - spin_lock_bh(&ep->ex_lock); - if (ep->esb_stat & ESB_ST_COMPLETE) { - spin_unlock_bh(&ep->ex_lock); - goto reject; - } - if (!(ep->esb_stat & ESB_ST_REC_QUAL)) - fc_exch_hold(ep); /* hold for REC_QUAL */ - ep->esb_stat |= ESB_ST_ABNORMAL | ESB_ST_REC_QUAL; - fc_exch_timer_set_locked(ep, ep->r_a_tov); - - fp = fc_frame_alloc(ep->lp, sizeof(*ap)); - if (!fp) { - spin_unlock_bh(&ep->ex_lock); - goto free; - } - fh = fc_frame_header_get(fp); - ap = fc_frame_payload_get(fp, sizeof(*ap)); - memset(ap, 0, sizeof(*ap)); - sp = &ep->seq; - ap->ba_high_seq_cnt = htons(0xffff); - if (sp->ssb_stat & SSB_ST_RESP) { - ap->ba_seq_id = sp->id; - ap->ba_seq_id_val = FC_BA_SEQ_ID_VAL; - ap->ba_high_seq_cnt = fh->fh_seq_cnt; - ap->ba_low_seq_cnt = htons(sp->cnt); - } - sp = fc_seq_start_next_locked(sp); - spin_unlock_bh(&ep->ex_lock); - fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS); - fc_frame_free(rx_fp); - return; - -reject: - fc_exch_send_ba_rjt(rx_fp, FC_BA_RJT_UNABLE, FC_BA_RJT_INV_XID); -free: - fc_frame_free(rx_fp); -} - -/** - * fc_seq_assign() - Assign exchange and sequence for incoming request - * @lport: The local port that received the request - * @fp: The request frame - * - * On success, the sequence pointer will be returned and also in fr_seq(@fp). - * A reference will be held on the exchange/sequence for the caller, which - * must call fc_seq_release(). - */ -static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp) -{ - struct fc_exch_mgr_anchor *ema; - - WARN_ON(lport != fr_dev(fp)); - WARN_ON(fr_seq(fp)); - fr_seq(fp) = NULL; - - list_for_each_entry(ema, &lport->ema_list, ema_list) - if ((!ema->match || ema->match(fp)) && - fc_seq_lookup_recip(lport, ema->mp, fp) == FC_RJT_NONE) - break; - return fr_seq(fp); -} - -/** - * fc_seq_release() - Release the hold - * @sp: The sequence. - */ -static void fc_seq_release(struct fc_seq *sp) -{ - fc_exch_release(fc_seq_exch(sp)); -} - -/** - * fc_exch_recv_req() - Handler for an incoming request - * @lport: The local port that received the request - * @mp: The EM that the exchange is on - * @fp: The request frame - * - * This is used when the other end is originating the exchange - * and the sequence. - */ -static void fc_exch_recv_req(struct fc_lport *lport, struct fc_exch_mgr *mp, - struct fc_frame *fp) -{ - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fc_seq *sp = NULL; - struct fc_exch *ep = NULL; - enum fc_pf_rjt_reason reject; - - /* We can have the wrong fc_lport at this point with NPIV, which is a - * problem now that we know a new exchange needs to be allocated - */ - lport = fc_vport_id_lookup(lport, ntoh24(fh->fh_d_id)); - if (!lport) { - fc_frame_free(fp); - return; - } - fr_dev(fp) = lport; - - BUG_ON(fr_seq(fp)); /* XXX remove later */ - - /* - * If the RX_ID is 0xffff, don't allocate an exchange. - * The upper-level protocol may request one later, if needed. - */ - if (fh->fh_rx_id == htons(FC_XID_UNKNOWN)) - return lport->tt.lport_recv(lport, fp); - - reject = fc_seq_lookup_recip(lport, mp, fp); - if (reject == FC_RJT_NONE) { - sp = fr_seq(fp); /* sequence will be held */ - ep = fc_seq_exch(sp); - fc_seq_send_ack(sp, fp); - ep->encaps = fr_encaps(fp); - - /* - * Call the receive function. - * - * The receive function may allocate a new sequence - * over the old one, so we shouldn't change the - * sequence after this. - * - * The frame will be freed by the receive function. - * If new exch resp handler is valid then call that - * first. - */ - if (ep->resp) - ep->resp(sp, fp, ep->arg); - else - lport->tt.lport_recv(lport, fp); - fc_exch_release(ep); /* release from lookup */ - } else { - FC_LPORT_DBG(lport, "exch/seq lookup failed: reject %x\n", - reject); - fc_frame_free(fp); - } -} - -/** - * fc_exch_recv_seq_resp() - Handler for an incoming response where the other - * end is the originator of the sequence that is a - * response to our initial exchange - * @mp: The EM that the exchange is on - * @fp: The response frame - */ -static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) -{ - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fc_seq *sp; - struct fc_exch *ep; - enum fc_sof sof; - u32 f_ctl; - void (*resp)(struct fc_seq *, struct fc_frame *fp, void *arg); - void *ex_resp_arg; - int rc; - - ep = fc_exch_find(mp, ntohs(fh->fh_ox_id)); - if (!ep) { - atomic_inc(&mp->stats.xid_not_found); - goto out; - } - if (ep->esb_stat & ESB_ST_COMPLETE) { - atomic_inc(&mp->stats.xid_not_found); - goto rel; - } - if (ep->rxid == FC_XID_UNKNOWN) - ep->rxid = ntohs(fh->fh_rx_id); - if (ep->sid != 0 && ep->sid != ntoh24(fh->fh_d_id)) { - atomic_inc(&mp->stats.xid_not_found); - goto rel; - } - if (ep->did != ntoh24(fh->fh_s_id) && - ep->did != FC_FID_FLOGI) { - atomic_inc(&mp->stats.xid_not_found); - goto rel; - } - sof = fr_sof(fp); - sp = &ep->seq; - if (fc_sof_is_init(sof)) { - sp->ssb_stat |= SSB_ST_RESP; - sp->id = fh->fh_seq_id; - } else if (sp->id != fh->fh_seq_id) { - atomic_inc(&mp->stats.seq_not_found); - goto rel; - } - - f_ctl = ntoh24(fh->fh_f_ctl); - fr_seq(fp) = sp; - if (f_ctl & FC_FC_SEQ_INIT) - ep->esb_stat |= ESB_ST_SEQ_INIT; - - if (fc_sof_needs_ack(sof)) - fc_seq_send_ack(sp, fp); - resp = ep->resp; - ex_resp_arg = ep->arg; - - if (fh->fh_type != FC_TYPE_FCP && fr_eof(fp) == FC_EOF_T && - (f_ctl & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) == - (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) { - spin_lock_bh(&ep->ex_lock); - resp = ep->resp; - rc = fc_exch_done_locked(ep); - WARN_ON(fc_seq_exch(sp) != ep); - spin_unlock_bh(&ep->ex_lock); - if (!rc) - fc_exch_delete(ep); - } - - /* - * Call the receive function. - * The sequence is held (has a refcnt) for us, - * but not for the receive function. - * - * The receive function may allocate a new sequence - * over the old one, so we shouldn't change the - * sequence after this. - * - * The frame will be freed by the receive function. - * If new exch resp handler is valid then call that - * first. - */ - if (resp) - resp(sp, fp, ex_resp_arg); - else - fc_frame_free(fp); - fc_exch_release(ep); - return; -rel: - fc_exch_release(ep); -out: - fc_frame_free(fp); -} - -/** - * fc_exch_recv_resp() - Handler for a sequence where other end is - * responding to our sequence - * @mp: The EM that the exchange is on - * @fp: The response frame - */ -static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) -{ - struct fc_seq *sp; - - sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ - - if (!sp) - atomic_inc(&mp->stats.xid_not_found); - else - atomic_inc(&mp->stats.non_bls_resp); - - fc_frame_free(fp); -} - -/** - * fc_exch_abts_resp() - Handler for a response to an ABT - * @ep: The exchange that the frame is on - * @fp: The response frame - * - * This response would be to an ABTS cancelling an exchange or sequence. - * The response can be either BA_ACC or BA_RJT - */ -static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) -{ - void (*resp)(struct fc_seq *, struct fc_frame *fp, void *arg); - void *ex_resp_arg; - struct fc_frame_header *fh; - struct fc_ba_acc *ap; - struct fc_seq *sp; - u16 low; - u16 high; - int rc = 1, has_rec = 0; - - fh = fc_frame_header_get(fp); - FC_EXCH_DBG(ep, "exch: BLS rctl %x - %s\n", fh->fh_r_ctl, - fc_exch_rctl_name(fh->fh_r_ctl)); - - if (cancel_delayed_work_sync(&ep->timeout_work)) - fc_exch_release(ep); /* release from pending timer hold */ - - spin_lock_bh(&ep->ex_lock); - switch (fh->fh_r_ctl) { - case FC_RCTL_BA_ACC: - ap = fc_frame_payload_get(fp, sizeof(*ap)); - if (!ap) - break; - - /* - * Decide whether to establish a Recovery Qualifier. - * We do this if there is a non-empty SEQ_CNT range and - * SEQ_ID is the same as the one we aborted. - */ - low = ntohs(ap->ba_low_seq_cnt); - high = ntohs(ap->ba_high_seq_cnt); - if ((ep->esb_stat & ESB_ST_REC_QUAL) == 0 && - (ap->ba_seq_id_val != FC_BA_SEQ_ID_VAL || - ap->ba_seq_id == ep->seq_id) && low != high) { - ep->esb_stat |= ESB_ST_REC_QUAL; - fc_exch_hold(ep); /* hold for recovery qualifier */ - has_rec = 1; - } - break; - case FC_RCTL_BA_RJT: - break; - default: - break; - } - - resp = ep->resp; - ex_resp_arg = ep->arg; - - /* do we need to do some other checks here. Can we reuse more of - * fc_exch_recv_seq_resp - */ - sp = &ep->seq; - /* - * do we want to check END_SEQ as well as LAST_SEQ here? - */ - if (ep->fh_type != FC_TYPE_FCP && - ntoh24(fh->fh_f_ctl) & FC_FC_LAST_SEQ) - rc = fc_exch_done_locked(ep); - spin_unlock_bh(&ep->ex_lock); - if (!rc) - fc_exch_delete(ep); - - if (resp) - resp(sp, fp, ex_resp_arg); - else - fc_frame_free(fp); - - if (has_rec) - fc_exch_timer_set(ep, ep->r_a_tov); - -} - -/** - * fc_exch_recv_bls() - Handler for a BLS sequence - * @mp: The EM that the exchange is on - * @fp: The request frame - * - * The BLS frame is always a sequence initiated by the remote side. - * We may be either the originator or recipient of the exchange. - */ -static void fc_exch_recv_bls(struct fc_exch_mgr *mp, struct fc_frame *fp) -{ - struct fc_frame_header *fh; - struct fc_exch *ep; - u32 f_ctl; - - fh = fc_frame_header_get(fp); - f_ctl = ntoh24(fh->fh_f_ctl); - fr_seq(fp) = NULL; - - ep = fc_exch_find(mp, (f_ctl & FC_FC_EX_CTX) ? - ntohs(fh->fh_ox_id) : ntohs(fh->fh_rx_id)); - if (ep && (f_ctl & FC_FC_SEQ_INIT)) { - spin_lock_bh(&ep->ex_lock); - ep->esb_stat |= ESB_ST_SEQ_INIT; - spin_unlock_bh(&ep->ex_lock); - } - if (f_ctl & FC_FC_SEQ_CTX) { - /* - * A response to a sequence we initiated. - * This should only be ACKs for class 2 or F. - */ - switch (fh->fh_r_ctl) { - case FC_RCTL_ACK_1: - case FC_RCTL_ACK_0: - break; - default: - if (ep) - FC_EXCH_DBG(ep, "BLS rctl %x - %s received", - fh->fh_r_ctl, - fc_exch_rctl_name(fh->fh_r_ctl)); - break; - } - fc_frame_free(fp); - } else { - switch (fh->fh_r_ctl) { - case FC_RCTL_BA_RJT: - case FC_RCTL_BA_ACC: - if (ep) - fc_exch_abts_resp(ep, fp); - else - fc_frame_free(fp); - break; - case FC_RCTL_BA_ABTS: - fc_exch_recv_abts(ep, fp); - break; - default: /* ignore junk */ - fc_frame_free(fp); - break; - } - } - if (ep) - fc_exch_release(ep); /* release hold taken by fc_exch_find */ -} - -/** - * fc_seq_ls_acc() - Accept sequence with LS_ACC - * @rx_fp: The received frame, not freed here. - * - * If this fails due to allocation or transmit congestion, assume the - * originator will repeat the sequence. - */ -static void fc_seq_ls_acc(struct fc_frame *rx_fp) -{ - struct fc_lport *lport; - struct fc_els_ls_acc *acc; - struct fc_frame *fp; - - lport = fr_dev(rx_fp); - fp = fc_frame_alloc(lport, sizeof(*acc)); - if (!fp) - return; - acc = fc_frame_payload_get(fp, sizeof(*acc)); - memset(acc, 0, sizeof(*acc)); - acc->la_cmd = ELS_LS_ACC; - fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); -} - -/** - * fc_seq_ls_rjt() - Reject a sequence with ELS LS_RJT - * @rx_fp: The received frame, not freed here. - * @reason: The reason the sequence is being rejected - * @explan: The explanation for the rejection - * - * If this fails due to allocation or transmit congestion, assume the - * originator will repeat the sequence. - */ -static void fc_seq_ls_rjt(struct fc_frame *rx_fp, enum fc_els_rjt_reason reason, - enum fc_els_rjt_explan explan) -{ - struct fc_lport *lport; - struct fc_els_ls_rjt *rjt; - struct fc_frame *fp; - - lport = fr_dev(rx_fp); - fp = fc_frame_alloc(lport, sizeof(*rjt)); - if (!fp) - return; - rjt = fc_frame_payload_get(fp, sizeof(*rjt)); - memset(rjt, 0, sizeof(*rjt)); - rjt->er_cmd = ELS_LS_RJT; - rjt->er_reason = reason; - rjt->er_explan = explan; - fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); -} - -/** - * fc_exch_reset() - Reset an exchange - * @ep: The exchange to be reset - */ -static void fc_exch_reset(struct fc_exch *ep) -{ - struct fc_seq *sp; - void (*resp)(struct fc_seq *, struct fc_frame *, void *); - void *arg; - int rc = 1; - - spin_lock_bh(&ep->ex_lock); - fc_exch_abort_locked(ep, 0); - ep->state |= FC_EX_RST_CLEANUP; - if (cancel_delayed_work(&ep->timeout_work)) - atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ - resp = ep->resp; - ep->resp = NULL; - if (ep->esb_stat & ESB_ST_REC_QUAL) - atomic_dec(&ep->ex_refcnt); /* drop hold for rec_qual */ - ep->esb_stat &= ~ESB_ST_REC_QUAL; - arg = ep->arg; - sp = &ep->seq; - rc = fc_exch_done_locked(ep); - spin_unlock_bh(&ep->ex_lock); - if (!rc) - fc_exch_delete(ep); - - if (resp) - resp(sp, ERR_PTR(-FC_EX_CLOSED), arg); -} - -/** - * fc_exch_pool_reset() - Reset a per cpu exchange pool - * @lport: The local port that the exchange pool is on - * @pool: The exchange pool to be reset - * @sid: The source ID - * @did: The destination ID - * - * Resets a per cpu exches pool, releasing all of its sequences - * and exchanges. If sid is non-zero then reset only exchanges - * we sourced from the local port's FID. If did is non-zero then - * only reset exchanges destined for the local port's FID. - */ -static void fc_exch_pool_reset(struct fc_lport *lport, - struct fc_exch_pool *pool, - u32 sid, u32 did) -{ - struct fc_exch *ep; - struct fc_exch *next; - - spin_lock_bh(&pool->lock); -restart: - list_for_each_entry_safe(ep, next, &pool->ex_list, ex_list) { - if ((lport == ep->lp) && - (sid == 0 || sid == ep->sid) && - (did == 0 || did == ep->did)) { - fc_exch_hold(ep); - spin_unlock_bh(&pool->lock); - - fc_exch_reset(ep); - - fc_exch_release(ep); - spin_lock_bh(&pool->lock); - - /* - * must restart loop incase while lock - * was down multiple eps were released. - */ - goto restart; - } - } - pool->next_index = 0; - pool->left = FC_XID_UNKNOWN; - pool->right = FC_XID_UNKNOWN; - spin_unlock_bh(&pool->lock); -} - -/** - * fc_exch_mgr_reset() - Reset all EMs of a local port - * @lport: The local port whose EMs are to be reset - * @sid: The source ID - * @did: The destination ID - * - * Reset all EMs associated with a given local port. Release all - * sequences and exchanges. If sid is non-zero then reset only the - * exchanges sent from the local port's FID. If did is non-zero then - * reset only exchanges destined for the local port's FID. - */ -void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did) -{ - struct fc_exch_mgr_anchor *ema; - unsigned int cpu; - - list_for_each_entry(ema, &lport->ema_list, ema_list) { - for_each_possible_cpu(cpu) - fc_exch_pool_reset(lport, - per_cpu_ptr(ema->mp->pool, cpu), - sid, did); - } -} -EXPORT_SYMBOL(fc_exch_mgr_reset); - -/** - * fc_exch_lookup() - find an exchange - * @lport: The local port - * @xid: The exchange ID - * - * Returns exchange pointer with hold for caller, or NULL if not found. - */ -static struct fc_exch *fc_exch_lookup(struct fc_lport *lport, u32 xid) -{ - struct fc_exch_mgr_anchor *ema; - - list_for_each_entry(ema, &lport->ema_list, ema_list) - if (ema->mp->min_xid <= xid && xid <= ema->mp->max_xid) - return fc_exch_find(ema->mp, xid); - return NULL; -} - -/** - * fc_exch_els_rec() - Handler for ELS REC (Read Exchange Concise) requests - * @rfp: The REC frame, not freed here. - * - * Note that the requesting port may be different than the S_ID in the request. - */ -static void fc_exch_els_rec(struct fc_frame *rfp) -{ - struct fc_lport *lport; - struct fc_frame *fp; - struct fc_exch *ep; - struct fc_els_rec *rp; - struct fc_els_rec_acc *acc; - enum fc_els_rjt_reason reason = ELS_RJT_LOGIC; - enum fc_els_rjt_explan explan; - u32 sid; - u16 rxid; - u16 oxid; - - lport = fr_dev(rfp); - rp = fc_frame_payload_get(rfp, sizeof(*rp)); - explan = ELS_EXPL_INV_LEN; - if (!rp) - goto reject; - sid = ntoh24(rp->rec_s_id); - rxid = ntohs(rp->rec_rx_id); - oxid = ntohs(rp->rec_ox_id); - - ep = fc_exch_lookup(lport, - sid == fc_host_port_id(lport->host) ? oxid : rxid); - explan = ELS_EXPL_OXID_RXID; - if (!ep) - goto reject; - if (ep->oid != sid || oxid != ep->oxid) - goto rel; - if (rxid != FC_XID_UNKNOWN && rxid != ep->rxid) - goto rel; - fp = fc_frame_alloc(lport, sizeof(*acc)); - if (!fp) - goto out; - - acc = fc_frame_payload_get(fp, sizeof(*acc)); - memset(acc, 0, sizeof(*acc)); - acc->reca_cmd = ELS_LS_ACC; - acc->reca_ox_id = rp->rec_ox_id; - memcpy(acc->reca_ofid, rp->rec_s_id, 3); - acc->reca_rx_id = htons(ep->rxid); - if (ep->sid == ep->oid) - hton24(acc->reca_rfid, ep->did); - else - hton24(acc->reca_rfid, ep->sid); - acc->reca_fc4value = htonl(ep->seq.rec_data); - acc->reca_e_stat = htonl(ep->esb_stat & (ESB_ST_RESP | - ESB_ST_SEQ_INIT | - ESB_ST_COMPLETE)); - fc_fill_reply_hdr(fp, rfp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); -out: - fc_exch_release(ep); - return; - -rel: - fc_exch_release(ep); -reject: - fc_seq_ls_rjt(rfp, reason, explan); -} - -/** - * fc_exch_rrq_resp() - Handler for RRQ responses - * @sp: The sequence that the RRQ is on - * @fp: The RRQ frame - * @arg: The exchange that the RRQ is on - * - * TODO: fix error handler. - */ -static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg) -{ - struct fc_exch *aborted_ep = arg; - unsigned int op; - - if (IS_ERR(fp)) { - int err = PTR_ERR(fp); - - if (err == -FC_EX_CLOSED || err == -FC_EX_TIMEOUT) - goto cleanup; - FC_EXCH_DBG(aborted_ep, "Cannot process RRQ, " - "frame error %d\n", err); - return; - } - - op = fc_frame_payload_op(fp); - fc_frame_free(fp); - - switch (op) { - case ELS_LS_RJT: - FC_EXCH_DBG(aborted_ep, "LS_RJT for RRQ"); - /* fall through */ - case ELS_LS_ACC: - goto cleanup; - default: - FC_EXCH_DBG(aborted_ep, "unexpected response op %x " - "for RRQ", op); - return; - } - -cleanup: - fc_exch_done(&aborted_ep->seq); - /* drop hold for rec qual */ - fc_exch_release(aborted_ep); -} - - -/** - * fc_exch_seq_send() - Send a frame using a new exchange and sequence - * @lport: The local port to send the frame on - * @fp: The frame to be sent - * @resp: The response handler for this request - * @destructor: The destructor for the exchange - * @arg: The argument to be passed to the response handler - * @timer_msec: The timeout period for the exchange - * - * The frame pointer with some of the header's fields must be - * filled before calling this routine, those fields are: - * - * - routing control - * - FC port did - * - FC port sid - * - FC header type - * - frame control - * - parameter or relative offset - */ -static struct fc_seq *fc_exch_seq_send(struct fc_lport *lport, - struct fc_frame *fp, - void (*resp)(struct fc_seq *, - struct fc_frame *fp, - void *arg), - void (*destructor)(struct fc_seq *, - void *), - void *arg, u32 timer_msec) -{ - struct fc_exch *ep; - struct fc_seq *sp = NULL; - struct fc_frame_header *fh; - struct fc_fcp_pkt *fsp = NULL; - int rc = 1; - - ep = fc_exch_alloc(lport, fp); - if (!ep) { - fc_frame_free(fp); - return NULL; - } - ep->esb_stat |= ESB_ST_SEQ_INIT; - fh = fc_frame_header_get(fp); - fc_exch_set_addr(ep, ntoh24(fh->fh_s_id), ntoh24(fh->fh_d_id)); - ep->resp = resp; - ep->destructor = destructor; - ep->arg = arg; - ep->r_a_tov = FC_DEF_R_A_TOV; - ep->lp = lport; - sp = &ep->seq; - - ep->fh_type = fh->fh_type; /* save for possbile timeout handling */ - ep->f_ctl = ntoh24(fh->fh_f_ctl); - fc_exch_setup_hdr(ep, fp, ep->f_ctl); - sp->cnt++; - - if (ep->xid <= lport->lro_xid && fh->fh_r_ctl == FC_RCTL_DD_UNSOL_CMD) { - fsp = fr_fsp(fp); - fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); - } - - if (unlikely(lport->tt.frame_send(lport, fp))) - goto err; - - if (timer_msec) - fc_exch_timer_set_locked(ep, timer_msec); - ep->f_ctl &= ~FC_FC_FIRST_SEQ; /* not first seq */ - - if (ep->f_ctl & FC_FC_SEQ_INIT) - ep->esb_stat &= ~ESB_ST_SEQ_INIT; - spin_unlock_bh(&ep->ex_lock); - return sp; -err: - if (fsp) - fc_fcp_ddp_done(fsp); - rc = fc_exch_done_locked(ep); - spin_unlock_bh(&ep->ex_lock); - if (!rc) - fc_exch_delete(ep); - return NULL; -} - -/** - * fc_exch_rrq() - Send an ELS RRQ (Reinstate Recovery Qualifier) command - * @ep: The exchange to send the RRQ on - * - * This tells the remote port to stop blocking the use of - * the exchange and the seq_cnt range. - */ -static void fc_exch_rrq(struct fc_exch *ep) -{ - struct fc_lport *lport; - struct fc_els_rrq *rrq; - struct fc_frame *fp; - u32 did; - - lport = ep->lp; - - fp = fc_frame_alloc(lport, sizeof(*rrq)); - if (!fp) - goto retry; - - rrq = fc_frame_payload_get(fp, sizeof(*rrq)); - memset(rrq, 0, sizeof(*rrq)); - rrq->rrq_cmd = ELS_RRQ; - hton24(rrq->rrq_s_id, ep->sid); - rrq->rrq_ox_id = htons(ep->oxid); - rrq->rrq_rx_id = htons(ep->rxid); - - did = ep->did; - if (ep->esb_stat & ESB_ST_RESP) - did = ep->sid; - - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, did, - lport->port_id, FC_TYPE_ELS, - FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - - if (fc_exch_seq_send(lport, fp, fc_exch_rrq_resp, NULL, ep, - lport->e_d_tov)) - return; - -retry: - spin_lock_bh(&ep->ex_lock); - if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) { - spin_unlock_bh(&ep->ex_lock); - /* drop hold for rec qual */ - fc_exch_release(ep); - return; - } - ep->esb_stat |= ESB_ST_REC_QUAL; - fc_exch_timer_set_locked(ep, ep->r_a_tov); - spin_unlock_bh(&ep->ex_lock); -} - -/** - * fc_exch_els_rrq() - Handler for ELS RRQ (Reset Recovery Qualifier) requests - * @fp: The RRQ frame, not freed here. - */ -static void fc_exch_els_rrq(struct fc_frame *fp) -{ - struct fc_lport *lport; - struct fc_exch *ep = NULL; /* request or subject exchange */ - struct fc_els_rrq *rp; - u32 sid; - u16 xid; - enum fc_els_rjt_explan explan; - - lport = fr_dev(fp); - rp = fc_frame_payload_get(fp, sizeof(*rp)); - explan = ELS_EXPL_INV_LEN; - if (!rp) - goto reject; - - /* - * lookup subject exchange. - */ - sid = ntoh24(rp->rrq_s_id); /* subject source */ - xid = fc_host_port_id(lport->host) == sid ? - ntohs(rp->rrq_ox_id) : ntohs(rp->rrq_rx_id); - ep = fc_exch_lookup(lport, xid); - explan = ELS_EXPL_OXID_RXID; - if (!ep) - goto reject; - spin_lock_bh(&ep->ex_lock); - if (ep->oxid != ntohs(rp->rrq_ox_id)) - goto unlock_reject; - if (ep->rxid != ntohs(rp->rrq_rx_id) && - ep->rxid != FC_XID_UNKNOWN) - goto unlock_reject; - explan = ELS_EXPL_SID; - if (ep->sid != sid) - goto unlock_reject; - - /* - * Clear Recovery Qualifier state, and cancel timer if complete. - */ - if (ep->esb_stat & ESB_ST_REC_QUAL) { - ep->esb_stat &= ~ESB_ST_REC_QUAL; - atomic_dec(&ep->ex_refcnt); /* drop hold for rec qual */ - } - if (ep->esb_stat & ESB_ST_COMPLETE) { - if (cancel_delayed_work(&ep->timeout_work)) - atomic_dec(&ep->ex_refcnt); /* drop timer hold */ - } - - spin_unlock_bh(&ep->ex_lock); - - /* - * Send LS_ACC. - */ - fc_seq_ls_acc(fp); - goto out; - -unlock_reject: - spin_unlock_bh(&ep->ex_lock); -reject: - fc_seq_ls_rjt(fp, ELS_RJT_LOGIC, explan); -out: - if (ep) - fc_exch_release(ep); /* drop hold from fc_exch_find */ -} - -/** - * fc_exch_mgr_add() - Add an exchange manager to a local port's list of EMs - * @lport: The local port to add the exchange manager to - * @mp: The exchange manager to be added to the local port - * @match: The match routine that indicates when this EM should be used - */ -struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport, - struct fc_exch_mgr *mp, - bool (*match)(struct fc_frame *)) -{ - struct fc_exch_mgr_anchor *ema; - - ema = kmalloc(sizeof(*ema), GFP_ATOMIC); - if (!ema) - return ema; - - ema->mp = mp; - ema->match = match; - /* add EM anchor to EM anchors list */ - list_add_tail(&ema->ema_list, &lport->ema_list); - kref_get(&mp->kref); - return ema; -} -EXPORT_SYMBOL(fc_exch_mgr_add); - -/** - * fc_exch_mgr_destroy() - Destroy an exchange manager - * @kref: The reference to the EM to be destroyed - */ -static void fc_exch_mgr_destroy(struct kref *kref) -{ - struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref); - - mempool_destroy(mp->ep_pool); - free_percpu(mp->pool); - kfree(mp); -} - -/** - * fc_exch_mgr_del() - Delete an EM from a local port's list - * @ema: The exchange manager anchor identifying the EM to be deleted - */ -void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema) -{ - /* remove EM anchor from EM anchors list */ - list_del(&ema->ema_list); - kref_put(&ema->mp->kref, fc_exch_mgr_destroy); - kfree(ema); -} -EXPORT_SYMBOL(fc_exch_mgr_del); - -/** - * fc_exch_mgr_list_clone() - Share all exchange manager objects - * @src: Source lport to clone exchange managers from - * @dst: New lport that takes references to all the exchange managers - */ -int fc_exch_mgr_list_clone(struct fc_lport *src, struct fc_lport *dst) -{ - struct fc_exch_mgr_anchor *ema, *tmp; - - list_for_each_entry(ema, &src->ema_list, ema_list) { - if (!fc_exch_mgr_add(dst, ema->mp, ema->match)) - goto err; - } - return 0; -err: - list_for_each_entry_safe(ema, tmp, &dst->ema_list, ema_list) - fc_exch_mgr_del(ema); - return -ENOMEM; -} -EXPORT_SYMBOL(fc_exch_mgr_list_clone); - -/** - * fc_exch_mgr_alloc() - Allocate an exchange manager - * @lport: The local port that the new EM will be associated with - * @class: The default FC class for new exchanges - * @min_xid: The minimum XID for exchanges from the new EM - * @max_xid: The maximum XID for exchanges from the new EM - * @match: The match routine for the new EM - */ -struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lport, - enum fc_class class, - u16 min_xid, u16 max_xid, - bool (*match)(struct fc_frame *)) -{ - struct fc_exch_mgr *mp; - u16 pool_exch_range; - size_t pool_size; - unsigned int cpu; - struct fc_exch_pool *pool; - - if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN || - (min_xid & fc_cpu_mask) != 0) { - FC_LPORT_DBG(lport, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", - min_xid, max_xid); - return NULL; - } - - /* - * allocate memory for EM - */ - mp = kzalloc(sizeof(struct fc_exch_mgr), GFP_ATOMIC); - if (!mp) - return NULL; - - mp->class = class; - /* adjust em exch xid range for offload */ - mp->min_xid = min_xid; - - /* reduce range so per cpu pool fits into PCPU_MIN_UNIT_SIZE pool */ - pool_exch_range = (PCPU_MIN_UNIT_SIZE - sizeof(*pool)) / - sizeof(struct fc_exch *); - if ((max_xid - min_xid + 1) / (fc_cpu_mask + 1) > pool_exch_range) { - mp->max_xid = pool_exch_range * (fc_cpu_mask + 1) + - min_xid - 1; - } else { - mp->max_xid = max_xid; - pool_exch_range = (mp->max_xid - mp->min_xid + 1) / - (fc_cpu_mask + 1); - } - - mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep); - if (!mp->ep_pool) - goto free_mp; - - /* - * Setup per cpu exch pool with entire exchange id range equally - * divided across all cpus. The exch pointers array memory is - * allocated for exch range per pool. - */ - mp->pool_max_index = pool_exch_range - 1; - - /* - * Allocate and initialize per cpu exch pool - */ - pool_size = sizeof(*pool) + pool_exch_range * sizeof(struct fc_exch *); - mp->pool = __alloc_percpu(pool_size, __alignof__(struct fc_exch_pool)); - if (!mp->pool) - goto free_mempool; - for_each_possible_cpu(cpu) { - pool = per_cpu_ptr(mp->pool, cpu); - pool->next_index = 0; - pool->left = FC_XID_UNKNOWN; - pool->right = FC_XID_UNKNOWN; - spin_lock_init(&pool->lock); - INIT_LIST_HEAD(&pool->ex_list); - } - - kref_init(&mp->kref); - if (!fc_exch_mgr_add(lport, mp, match)) { - free_percpu(mp->pool); - goto free_mempool; - } - - /* - * Above kref_init() sets mp->kref to 1 and then - * call to fc_exch_mgr_add incremented mp->kref again, - * so adjust that extra increment. - */ - kref_put(&mp->kref, fc_exch_mgr_destroy); - return mp; - -free_mempool: - mempool_destroy(mp->ep_pool); -free_mp: - kfree(mp); - return NULL; -} -EXPORT_SYMBOL(fc_exch_mgr_alloc); - -/** - * fc_exch_mgr_free() - Free all exchange managers on a local port - * @lport: The local port whose EMs are to be freed - */ -void fc_exch_mgr_free(struct fc_lport *lport) -{ - struct fc_exch_mgr_anchor *ema, *next; - - flush_workqueue(fc_exch_workqueue); - list_for_each_entry_safe(ema, next, &lport->ema_list, ema_list) - fc_exch_mgr_del(ema); -} -EXPORT_SYMBOL(fc_exch_mgr_free); - -/** - * fc_find_ema() - Lookup and return appropriate Exchange Manager Anchor depending - * upon 'xid'. - * @f_ctl: f_ctl - * @lport: The local port the frame was received on - * @fh: The received frame header - */ -static struct fc_exch_mgr_anchor *fc_find_ema(u32 f_ctl, - struct fc_lport *lport, - struct fc_frame_header *fh) -{ - struct fc_exch_mgr_anchor *ema; - u16 xid; - - if (f_ctl & FC_FC_EX_CTX) - xid = ntohs(fh->fh_ox_id); - else { - xid = ntohs(fh->fh_rx_id); - if (xid == FC_XID_UNKNOWN) - return list_entry(lport->ema_list.prev, - typeof(*ema), ema_list); - } - - list_for_each_entry(ema, &lport->ema_list, ema_list) { - if ((xid >= ema->mp->min_xid) && - (xid <= ema->mp->max_xid)) - return ema; - } - return NULL; -} -/** - * fc_exch_recv() - Handler for received frames - * @lport: The local port the frame was received on - * @fp: The received frame - */ -void fc_exch_recv(struct fc_lport *lport, struct fc_frame *fp) -{ - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fc_exch_mgr_anchor *ema; - u32 f_ctl; - - /* lport lock ? */ - if (!lport || lport->state == LPORT_ST_DISABLED) { - FC_LPORT_DBG(lport, "Receiving frames for an lport that " - "has not been initialized correctly\n"); - fc_frame_free(fp); - return; - } - - f_ctl = ntoh24(fh->fh_f_ctl); - ema = fc_find_ema(f_ctl, lport, fh); - if (!ema) { - FC_LPORT_DBG(lport, "Unable to find Exchange Manager Anchor," - "fc_ctl <0x%x>, xid <0x%x>\n", - f_ctl, - (f_ctl & FC_FC_EX_CTX) ? - ntohs(fh->fh_ox_id) : - ntohs(fh->fh_rx_id)); - fc_frame_free(fp); - return; - } - - /* - * If frame is marked invalid, just drop it. - */ - switch (fr_eof(fp)) { - case FC_EOF_T: - if (f_ctl & FC_FC_END_SEQ) - skb_trim(fp_skb(fp), fr_len(fp) - FC_FC_FILL(f_ctl)); - /* fall through */ - case FC_EOF_N: - if (fh->fh_type == FC_TYPE_BLS) - fc_exch_recv_bls(ema->mp, fp); - else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == - FC_FC_EX_CTX) - fc_exch_recv_seq_resp(ema->mp, fp); - else if (f_ctl & FC_FC_SEQ_CTX) - fc_exch_recv_resp(ema->mp, fp); - else /* no EX_CTX and no SEQ_CTX */ - fc_exch_recv_req(lport, ema->mp, fp); - break; - default: - FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)", - fr_eof(fp)); - fc_frame_free(fp); - } -} -EXPORT_SYMBOL(fc_exch_recv); - -/** - * fc_exch_init() - Initialize the exchange layer for a local port - * @lport: The local port to initialize the exchange layer for - */ -int fc_exch_init(struct fc_lport *lport) -{ - if (!lport->tt.seq_start_next) - lport->tt.seq_start_next = fc_seq_start_next; - - if (!lport->tt.seq_set_resp) - lport->tt.seq_set_resp = fc_seq_set_resp; - - if (!lport->tt.exch_seq_send) - lport->tt.exch_seq_send = fc_exch_seq_send; - - if (!lport->tt.seq_send) - lport->tt.seq_send = fc_seq_send; - - if (!lport->tt.seq_els_rsp_send) - lport->tt.seq_els_rsp_send = fc_seq_els_rsp_send; - - if (!lport->tt.exch_done) - lport->tt.exch_done = fc_exch_done; - - if (!lport->tt.exch_mgr_reset) - lport->tt.exch_mgr_reset = fc_exch_mgr_reset; - - if (!lport->tt.seq_exch_abort) - lport->tt.seq_exch_abort = fc_seq_exch_abort; - - if (!lport->tt.seq_assign) - lport->tt.seq_assign = fc_seq_assign; - - if (!lport->tt.seq_release) - lport->tt.seq_release = fc_seq_release; - - return 0; -} -EXPORT_SYMBOL(fc_exch_init); - -/** - * fc_setup_exch_mgr() - Setup an exchange manager - */ -int fc_setup_exch_mgr(void) -{ - fc_em_cachep = kmem_cache_create("libfc_em", sizeof(struct fc_exch), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!fc_em_cachep) - return -ENOMEM; - - /* - * Initialize fc_cpu_mask and fc_cpu_order. The - * fc_cpu_mask is set for nr_cpu_ids rounded up - * to order of 2's * power and order is stored - * in fc_cpu_order as this is later required in - * mapping between an exch id and exch array index - * in per cpu exch pool. - * - * This round up is required to align fc_cpu_mask - * to exchange id's lower bits such that all incoming - * frames of an exchange gets delivered to the same - * cpu on which exchange originated by simple bitwise - * AND operation between fc_cpu_mask and exchange id. - */ - fc_cpu_mask = 1; - fc_cpu_order = 0; - while (fc_cpu_mask < nr_cpu_ids) { - fc_cpu_mask <<= 1; - fc_cpu_order++; - } - fc_cpu_mask--; - - fc_exch_workqueue = create_singlethread_workqueue("fc_exch_workqueue"); - if (!fc_exch_workqueue) - goto err; - return 0; -err: - kmem_cache_destroy(fc_em_cachep); - return -ENOMEM; -} - -/** - * fc_destroy_exch_mgr() - Destroy an exchange manager - */ -void fc_destroy_exch_mgr(void) -{ - destroy_workqueue(fc_exch_workqueue); - kmem_cache_destroy(fc_em_cachep); -} diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_fcp.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_fcp.c deleted file mode 100644 index f7357308..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_fcp.c +++ /dev/null @@ -1,2286 +0,0 @@ -/* - * Copyright(c) 2007 Intel Corporation. All rights reserved. - * Copyright(c) 2008 Red Hat, Inc. All rights reserved. - * Copyright(c) 2008 Mike Christie - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include "fc_libfc.h" - -static struct kmem_cache *scsi_pkt_cachep; - -/* SRB state definitions */ -#define FC_SRB_FREE 0 /* cmd is free */ -#define FC_SRB_CMD_SENT (1 << 0) /* cmd has been sent */ -#define FC_SRB_RCV_STATUS (1 << 1) /* response has arrived */ -#define FC_SRB_ABORT_PENDING (1 << 2) /* cmd abort sent to device */ -#define FC_SRB_ABORTED (1 << 3) /* abort acknowledged */ -#define FC_SRB_DISCONTIG (1 << 4) /* non-sequential data recvd */ -#define FC_SRB_COMPL (1 << 5) /* fc_io_compl has been run */ -#define FC_SRB_FCP_PROCESSING_TMO (1 << 6) /* timer function processing */ - -#define FC_SRB_READ (1 << 1) -#define FC_SRB_WRITE (1 << 0) - -/* - * The SCp.ptr should be tested and set under the scsi_pkt_queue lock - */ -#define CMD_SP(Cmnd) ((struct fc_fcp_pkt *)(Cmnd)->SCp.ptr) -#define CMD_ENTRY_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in) -#define CMD_COMPL_STATUS(Cmnd) ((Cmnd)->SCp.this_residual) -#define CMD_SCSI_STATUS(Cmnd) ((Cmnd)->SCp.Status) -#define CMD_RESID_LEN(Cmnd) ((Cmnd)->SCp.buffers_residual) - -/** - * struct fc_fcp_internal - FCP layer internal data - * @scsi_pkt_pool: Memory pool to draw FCP packets from - * @scsi_queue_lock: Protects the scsi_pkt_queue - * @scsi_pkt_queue: Current FCP packets - * @last_can_queue_ramp_down_time: ramp down time - * @last_can_queue_ramp_up_time: ramp up time - * @max_can_queue: max can_queue size - */ -struct fc_fcp_internal { - mempool_t *scsi_pkt_pool; - spinlock_t scsi_queue_lock; - struct list_head scsi_pkt_queue; - unsigned long last_can_queue_ramp_down_time; - unsigned long last_can_queue_ramp_up_time; - int max_can_queue; -}; - -#define fc_get_scsi_internal(x) ((struct fc_fcp_internal *)(x)->scsi_priv) - -/* - * function prototypes - * FC scsi I/O related functions - */ -static void fc_fcp_recv_data(struct fc_fcp_pkt *, struct fc_frame *); -static void fc_fcp_recv(struct fc_seq *, struct fc_frame *, void *); -static void fc_fcp_resp(struct fc_fcp_pkt *, struct fc_frame *); -static void fc_fcp_complete_locked(struct fc_fcp_pkt *); -static void fc_tm_done(struct fc_seq *, struct fc_frame *, void *); -static void fc_fcp_error(struct fc_fcp_pkt *, struct fc_frame *); -static void fc_fcp_recovery(struct fc_fcp_pkt *, u8 code); -static void fc_fcp_timeout(unsigned long); -static void fc_fcp_rec(struct fc_fcp_pkt *); -static void fc_fcp_rec_error(struct fc_fcp_pkt *, struct fc_frame *); -static void fc_fcp_rec_resp(struct fc_seq *, struct fc_frame *, void *); -static void fc_io_compl(struct fc_fcp_pkt *); - -static void fc_fcp_srr(struct fc_fcp_pkt *, enum fc_rctl, u32); -static void fc_fcp_srr_resp(struct fc_seq *, struct fc_frame *, void *); -static void fc_fcp_srr_error(struct fc_fcp_pkt *, struct fc_frame *); - -/* - * command status codes - */ -#define FC_COMPLETE 0 -#define FC_CMD_ABORTED 1 -#define FC_CMD_RESET 2 -#define FC_CMD_PLOGO 3 -#define FC_SNS_RCV 4 -#define FC_TRANS_ERR 5 -#define FC_DATA_OVRRUN 6 -#define FC_DATA_UNDRUN 7 -#define FC_ERROR 8 -#define FC_HRD_ERROR 9 -#define FC_CRC_ERROR 10 -#define FC_TIMED_OUT 11 - -/* - * Error recovery timeout values. - */ -#define FC_SCSI_TM_TOV (10 * HZ) -#define FC_HOST_RESET_TIMEOUT (30 * HZ) -#define FC_CAN_QUEUE_PERIOD (60 * HZ) - -#define FC_MAX_ERROR_CNT 5 -#define FC_MAX_RECOV_RETRY 3 - -#define FC_FCP_DFLT_QUEUE_DEPTH 32 - -/** - * fc_fcp_pkt_alloc() - Allocate a fcp_pkt - * @lport: The local port that the FCP packet is for - * @gfp: GFP flags for allocation - * - * Return value: fcp_pkt structure or null on allocation failure. - * Context: Can be called from process context, no lock is required. - */ -static struct fc_fcp_pkt *fc_fcp_pkt_alloc(struct fc_lport *lport, gfp_t gfp) -{ - struct fc_fcp_internal *si = fc_get_scsi_internal(lport); - struct fc_fcp_pkt *fsp; - - fsp = mempool_alloc(si->scsi_pkt_pool, gfp); - if (fsp) { - memset(fsp, 0, sizeof(*fsp)); - fsp->lp = lport; - fsp->xfer_ddp = FC_XID_UNKNOWN; - atomic_set(&fsp->ref_cnt, 1); - init_timer(&fsp->timer); - fsp->timer.data = (unsigned long)fsp; - INIT_LIST_HEAD(&fsp->list); - spin_lock_init(&fsp->scsi_pkt_lock); - } - return fsp; -} - -/** - * fc_fcp_pkt_release() - Release hold on a fcp_pkt - * @fsp: The FCP packet to be released - * - * Context: Can be called from process or interrupt context, - * no lock is required. - */ -static void fc_fcp_pkt_release(struct fc_fcp_pkt *fsp) -{ - if (atomic_dec_and_test(&fsp->ref_cnt)) { - struct fc_fcp_internal *si = fc_get_scsi_internal(fsp->lp); - - mempool_free(fsp, si->scsi_pkt_pool); - } -} - -/** - * fc_fcp_pkt_hold() - Hold a fcp_pkt - * @fsp: The FCP packet to be held - */ -static void fc_fcp_pkt_hold(struct fc_fcp_pkt *fsp) -{ - atomic_inc(&fsp->ref_cnt); -} - -/** - * fc_fcp_pkt_destory() - Release hold on a fcp_pkt - * @seq: The sequence that the FCP packet is on (required by destructor API) - * @fsp: The FCP packet to be released - * - * This routine is called by a destructor callback in the exch_seq_send() - * routine of the libfc Transport Template. The 'struct fc_seq' is a required - * argument even though it is not used by this routine. - * - * Context: No locking required. - */ -static void fc_fcp_pkt_destroy(struct fc_seq *seq, void *fsp) -{ - fc_fcp_pkt_release(fsp); -} - -/** - * fc_fcp_lock_pkt() - Lock a fcp_pkt and increase its reference count - * @fsp: The FCP packet to be locked and incremented - * - * We should only return error if we return a command to SCSI-ml before - * getting a response. This can happen in cases where we send a abort, but - * do not wait for the response and the abort and command can be passing - * each other on the wire/network-layer. - * - * Note: this function locks the packet and gets a reference to allow - * callers to call the completion function while the lock is held and - * not have to worry about the packets refcount. - * - * TODO: Maybe we should just have callers grab/release the lock and - * have a function that they call to verify the fsp and grab a ref if - * needed. - */ -static inline int fc_fcp_lock_pkt(struct fc_fcp_pkt *fsp) -{ - spin_lock_bh(&fsp->scsi_pkt_lock); - if (fsp->state & FC_SRB_COMPL) { - spin_unlock_bh(&fsp->scsi_pkt_lock); - return -EPERM; - } - - fc_fcp_pkt_hold(fsp); - return 0; -} - -/** - * fc_fcp_unlock_pkt() - Release a fcp_pkt's lock and decrement its - * reference count - * @fsp: The FCP packet to be unlocked and decremented - */ -static inline void fc_fcp_unlock_pkt(struct fc_fcp_pkt *fsp) -{ - spin_unlock_bh(&fsp->scsi_pkt_lock); - fc_fcp_pkt_release(fsp); -} - -/** - * fc_fcp_timer_set() - Start a timer for a fcp_pkt - * @fsp: The FCP packet to start a timer for - * @delay: The timeout period in jiffies - */ -static void fc_fcp_timer_set(struct fc_fcp_pkt *fsp, unsigned long delay) -{ - if (!(fsp->state & FC_SRB_COMPL)) - mod_timer(&fsp->timer, jiffies + delay); -} - -/** - * fc_fcp_send_abort() - Send an abort for exchanges associated with a - * fcp_pkt - * @fsp: The FCP packet to abort exchanges on - */ -static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp) -{ - if (!fsp->seq_ptr) - return -EINVAL; - - fsp->state |= FC_SRB_ABORT_PENDING; - return fsp->lp->tt.seq_exch_abort(fsp->seq_ptr, 0); -} - -/** - * fc_fcp_retry_cmd() - Retry a fcp_pkt - * @fsp: The FCP packet to be retried - * - * Sets the status code to be FC_ERROR and then calls - * fc_fcp_complete_locked() which in turn calls fc_io_compl(). - * fc_io_compl() will notify the SCSI-ml that the I/O is done. - * The SCSI-ml will retry the command. - */ -static void fc_fcp_retry_cmd(struct fc_fcp_pkt *fsp) -{ - if (fsp->seq_ptr) { - fsp->lp->tt.exch_done(fsp->seq_ptr); - fsp->seq_ptr = NULL; - } - - fsp->state &= ~FC_SRB_ABORT_PENDING; - fsp->io_status = 0; - fsp->status_code = FC_ERROR; - fc_fcp_complete_locked(fsp); -} - -/** - * fc_fcp_ddp_setup() - Calls a LLD's ddp_setup routine to set up DDP context - * @fsp: The FCP packet that will manage the DDP frames - * @xid: The XID that will be used for the DDP exchange - */ -void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid) -{ - struct fc_lport *lport; - - lport = fsp->lp; - if ((fsp->req_flags & FC_SRB_READ) && - (lport->lro_enabled) && (lport->tt.ddp_setup)) { - if (lport->tt.ddp_setup(lport, xid, scsi_sglist(fsp->cmd), - scsi_sg_count(fsp->cmd))) - fsp->xfer_ddp = xid; - } -} - -/** - * fc_fcp_ddp_done() - Calls a LLD's ddp_done routine to release any - * DDP related resources for a fcp_pkt - * @fsp: The FCP packet that DDP had been used on - */ -void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp) -{ - struct fc_lport *lport; - - if (!fsp) - return; - - if (fsp->xfer_ddp == FC_XID_UNKNOWN) - return; - - lport = fsp->lp; - if (lport->tt.ddp_done) { - fsp->xfer_len = lport->tt.ddp_done(lport, fsp->xfer_ddp); - fsp->xfer_ddp = FC_XID_UNKNOWN; - } -} - -/** - * fc_fcp_can_queue_ramp_up() - increases can_queue - * @lport: lport to ramp up can_queue - */ -static void fc_fcp_can_queue_ramp_up(struct fc_lport *lport) -{ - struct fc_fcp_internal *si = fc_get_scsi_internal(lport); - unsigned long flags; - int can_queue; - - spin_lock_irqsave(lport->host->host_lock, flags); - - if (si->last_can_queue_ramp_up_time && - (time_before(jiffies, si->last_can_queue_ramp_up_time + - FC_CAN_QUEUE_PERIOD))) - goto unlock; - - if (time_before(jiffies, si->last_can_queue_ramp_down_time + - FC_CAN_QUEUE_PERIOD)) - goto unlock; - - si->last_can_queue_ramp_up_time = jiffies; - - can_queue = lport->host->can_queue << 1; - if (can_queue >= si->max_can_queue) { - can_queue = si->max_can_queue; - si->last_can_queue_ramp_down_time = 0; - } - lport->host->can_queue = can_queue; - shost_printk(KERN_ERR, lport->host, "libfc: increased " - "can_queue to %d.\n", can_queue); - -unlock: - spin_unlock_irqrestore(lport->host->host_lock, flags); -} - -/** - * fc_fcp_can_queue_ramp_down() - reduces can_queue - * @lport: lport to reduce can_queue - * - * If we are getting memory allocation failures, then we may - * be trying to execute too many commands. We let the running - * commands complete or timeout, then try again with a reduced - * can_queue. Eventually we will hit the point where we run - * on all reserved structs. - */ -static void fc_fcp_can_queue_ramp_down(struct fc_lport *lport) -{ - struct fc_fcp_internal *si = fc_get_scsi_internal(lport); - unsigned long flags; - int can_queue; - - spin_lock_irqsave(lport->host->host_lock, flags); - - if (si->last_can_queue_ramp_down_time && - (time_before(jiffies, si->last_can_queue_ramp_down_time + - FC_CAN_QUEUE_PERIOD))) - goto unlock; - - si->last_can_queue_ramp_down_time = jiffies; - - can_queue = lport->host->can_queue; - can_queue >>= 1; - if (!can_queue) - can_queue = 1; - lport->host->can_queue = can_queue; - shost_printk(KERN_ERR, lport->host, "libfc: Could not allocate frame.\n" - "Reducing can_queue to %d.\n", can_queue); - -unlock: - spin_unlock_irqrestore(lport->host->host_lock, flags); -} - -/* - * fc_fcp_frame_alloc() - Allocates fc_frame structure and buffer. - * @lport: fc lport struct - * @len: payload length - * - * Allocates fc_frame structure and buffer but if fails to allocate - * then reduce can_queue. - */ -static inline struct fc_frame *fc_fcp_frame_alloc(struct fc_lport *lport, - size_t len) -{ - struct fc_frame *fp; - - fp = fc_frame_alloc(lport, len); - if (likely(fp)) - return fp; - - /* error case */ - fc_fcp_can_queue_ramp_down(lport); - return NULL; -} - -/** - * fc_fcp_recv_data() - Handler for receiving SCSI-FCP data from a target - * @fsp: The FCP packet the data is on - * @fp: The data frame - */ -static void fc_fcp_recv_data(struct fc_fcp_pkt *fsp, struct fc_frame *fp) -{ - struct scsi_cmnd *sc = fsp->cmd; - struct fc_lport *lport = fsp->lp; - struct fcoe_dev_stats *stats; - struct fc_frame_header *fh; - size_t start_offset; - size_t offset; - u32 crc; - u32 copy_len = 0; - size_t len; - void *buf; - struct scatterlist *sg; - u32 nents; - u8 host_bcode = FC_COMPLETE; - - fh = fc_frame_header_get(fp); - offset = ntohl(fh->fh_parm_offset); - start_offset = offset; - len = fr_len(fp) - sizeof(*fh); - buf = fc_frame_payload_get(fp, 0); - - /* - * if this I/O is ddped then clear it and initiate recovery since data - * frames are expected to be placed directly in that case. - * - * Indicate error to scsi-ml because something went wrong with the - * ddp handling to get us here. - */ - if (fsp->xfer_ddp != FC_XID_UNKNOWN) { - fc_fcp_ddp_done(fsp); - FC_FCP_DBG(fsp, "DDP I/O in fc_fcp_recv_data set ERROR\n"); - host_bcode = FC_ERROR; - goto err; - } - if (offset + len > fsp->data_len) { - /* this should never happen */ - if ((fr_flags(fp) & FCPHF_CRC_UNCHECKED) && - fc_frame_crc_check(fp)) - goto crc_err; - FC_FCP_DBG(fsp, "data received past end. len %zx offset %zx " - "data_len %x\n", len, offset, fsp->data_len); - - /* Data is corrupted indicate scsi-ml should retry */ - host_bcode = FC_DATA_OVRRUN; - goto err; - } - if (offset != fsp->xfer_len) - fsp->state |= FC_SRB_DISCONTIG; - - sg = scsi_sglist(sc); - nents = scsi_sg_count(sc); - - if (!(fr_flags(fp) & FCPHF_CRC_UNCHECKED)) { - copy_len = fc_copy_buffer_to_sglist(buf, len, sg, &nents, - &offset, NULL); - } else { - crc = crc32(~0, (u8 *) fh, sizeof(*fh)); - copy_len = fc_copy_buffer_to_sglist(buf, len, sg, &nents, - &offset, &crc); - buf = fc_frame_payload_get(fp, 0); - if (len % 4) - crc = crc32(crc, buf + len, 4 - (len % 4)); - - if (~crc != le32_to_cpu(fr_crc(fp))) { -crc_err: - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - stats->ErrorFrames++; - /* per cpu count, not total count, but OK for limit */ - if (stats->InvalidCRCCount++ < FC_MAX_ERROR_CNT) - printk(KERN_WARNING "libfc: CRC error on data " - "frame for port (%6.6x)\n", - lport->port_id); - put_cpu(); - /* - * Assume the frame is total garbage. - * We may have copied it over the good part - * of the buffer. - * If so, we need to retry the entire operation. - * Otherwise, ignore it. - */ - if (fsp->state & FC_SRB_DISCONTIG) { - host_bcode = FC_CRC_ERROR; - goto err; - } - return; - } - } - - if (fsp->xfer_contig_end == start_offset) - fsp->xfer_contig_end += copy_len; - fsp->xfer_len += copy_len; - - /* - * In the very rare event that this data arrived after the response - * and completes the transfer, call the completion handler. - */ - if (unlikely(fsp->state & FC_SRB_RCV_STATUS) && - fsp->xfer_len == fsp->data_len - fsp->scsi_resid) - fc_fcp_complete_locked(fsp); - return; -err: - fc_fcp_recovery(fsp, host_bcode); -} - -/** - * fc_fcp_send_data() - Send SCSI data to a target - * @fsp: The FCP packet the data is on - * @sp: The sequence the data is to be sent on - * @offset: The starting offset for this data request - * @seq_blen: The burst length for this data request - * - * Called after receiving a Transfer Ready data descriptor. - * If the LLD is capable of sequence offload then send down the - * seq_blen amount of data in single frame, otherwise send - * multiple frames of the maximum frame payload supported by - * the target port. - */ -static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, - size_t offset, size_t seq_blen) -{ - struct fc_exch *ep; - struct scsi_cmnd *sc; - struct scatterlist *sg; - struct fc_frame *fp = NULL; - struct fc_lport *lport = fsp->lp; - struct page *page; - size_t remaining; - size_t t_blen; - size_t tlen; - size_t sg_bytes; - size_t frame_offset, fh_parm_offset; - size_t off; - int error; - void *data = NULL; - void *page_addr; - int using_sg = lport->sg_supp; - u32 f_ctl; - - WARN_ON(seq_blen <= 0); - if (unlikely(offset + seq_blen > fsp->data_len)) { - /* this should never happen */ - FC_FCP_DBG(fsp, "xfer-ready past end. seq_blen %zx " - "offset %zx\n", seq_blen, offset); - fc_fcp_send_abort(fsp); - return 0; - } else if (offset != fsp->xfer_len) { - /* Out of Order Data Request - no problem, but unexpected. */ - FC_FCP_DBG(fsp, "xfer-ready non-contiguous. " - "seq_blen %zx offset %zx\n", seq_blen, offset); - } - - /* - * if LLD is capable of seq_offload then set transport - * burst length (t_blen) to seq_blen, otherwise set t_blen - * to max FC frame payload previously set in fsp->max_payload. - */ - t_blen = fsp->max_payload; - if (lport->seq_offload) { - t_blen = min(seq_blen, (size_t)lport->lso_max); - FC_FCP_DBG(fsp, "fsp=%p:lso:blen=%zx lso_max=0x%x t_blen=%zx\n", - fsp, seq_blen, lport->lso_max, t_blen); - } - - if (t_blen > 512) - t_blen &= ~(512 - 1); /* round down to block size */ - sc = fsp->cmd; - - remaining = seq_blen; - fh_parm_offset = frame_offset = offset; - tlen = 0; - seq = lport->tt.seq_start_next(seq); - f_ctl = FC_FC_REL_OFF; - WARN_ON(!seq); - - sg = scsi_sglist(sc); - - while (remaining > 0 && sg) { - if (offset >= sg->length) { - offset -= sg->length; - sg = sg_next(sg); - continue; - } - if (!fp) { - tlen = min(t_blen, remaining); - - /* - * TODO. Temporary workaround. fc_seq_send() can't - * handle odd lengths in non-linear skbs. - * This will be the final fragment only. - */ - if (tlen % 4) - using_sg = 0; - fp = fc_frame_alloc(lport, using_sg ? 0 : tlen); - if (!fp) - return -ENOMEM; - - data = fc_frame_header_get(fp) + 1; - fh_parm_offset = frame_offset; - fr_max_payload(fp) = fsp->max_payload; - } - - off = offset + sg->offset; - sg_bytes = min(tlen, sg->length - offset); - sg_bytes = min(sg_bytes, - (size_t) (PAGE_SIZE - (off & ~PAGE_MASK))); - page = sg_page(sg) + (off >> PAGE_SHIFT); - if (using_sg) { - get_page(page); - skb_fill_page_desc(fp_skb(fp), - skb_shinfo(fp_skb(fp))->nr_frags, - page, off & ~PAGE_MASK, sg_bytes); - fp_skb(fp)->data_len += sg_bytes; - fr_len(fp) += sg_bytes; - fp_skb(fp)->truesize += PAGE_SIZE; - } else { - /* - * The scatterlist item may be bigger than PAGE_SIZE, - * but we must not cross pages inside the kmap. - */ - page_addr = kmap_atomic(page); - memcpy(data, (char *)page_addr + (off & ~PAGE_MASK), - sg_bytes); - kunmap_atomic(page_addr); - data += sg_bytes; - } - offset += sg_bytes; - frame_offset += sg_bytes; - tlen -= sg_bytes; - remaining -= sg_bytes; - - if ((skb_shinfo(fp_skb(fp))->nr_frags < FC_FRAME_SG_LEN) && - (tlen)) - continue; - - /* - * Send sequence with transfer sequence initiative in case - * this is last FCP frame of the sequence. - */ - if (remaining == 0) - f_ctl |= FC_FC_SEQ_INIT | FC_FC_END_SEQ; - - ep = fc_seq_exch(seq); - fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid, - FC_TYPE_FCP, f_ctl, fh_parm_offset); - - /* - * send fragment using for a sequence. - */ - error = lport->tt.seq_send(lport, seq, fp); - if (error) { - WARN_ON(1); /* send error should be rare */ - return error; - } - fp = NULL; - } - fsp->xfer_len += seq_blen; /* premature count? */ - return 0; -} - -/** - * fc_fcp_abts_resp() - Receive an ABTS response - * @fsp: The FCP packet that is being aborted - * @fp: The response frame - */ -static void fc_fcp_abts_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) -{ - int ba_done = 1; - struct fc_ba_rjt *brp; - struct fc_frame_header *fh; - - fh = fc_frame_header_get(fp); - switch (fh->fh_r_ctl) { - case FC_RCTL_BA_ACC: - break; - case FC_RCTL_BA_RJT: - brp = fc_frame_payload_get(fp, sizeof(*brp)); - if (brp && brp->br_reason == FC_BA_RJT_LOG_ERR) - break; - /* fall thru */ - default: - /* - * we will let the command timeout - * and scsi-ml recover in this case, - * therefore cleared the ba_done flag. - */ - ba_done = 0; - } - - if (ba_done) { - fsp->state |= FC_SRB_ABORTED; - fsp->state &= ~FC_SRB_ABORT_PENDING; - - if (fsp->wait_for_comp) - complete(&fsp->tm_done); - else - fc_fcp_complete_locked(fsp); - } -} - -/** - * fc_fcp_recv() - Receive an FCP frame - * @seq: The sequence the frame is on - * @fp: The received frame - * @arg: The related FCP packet - * - * Context: Called from Soft IRQ context. Can not be called - * holding the FCP packet list lock. - */ -static void fc_fcp_recv(struct fc_seq *seq, struct fc_frame *fp, void *arg) -{ - struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)arg; - struct fc_lport *lport = fsp->lp; - struct fc_frame_header *fh; - struct fcp_txrdy *dd; - u8 r_ctl; - int rc = 0; - - if (IS_ERR(fp)) { - fc_fcp_error(fsp, fp); - return; - } - - fh = fc_frame_header_get(fp); - r_ctl = fh->fh_r_ctl; - - if (lport->state != LPORT_ST_READY) - goto out; - if (fc_fcp_lock_pkt(fsp)) - goto out; - - if (fh->fh_type == FC_TYPE_BLS) { - fc_fcp_abts_resp(fsp, fp); - goto unlock; - } - - if (fsp->state & (FC_SRB_ABORTED | FC_SRB_ABORT_PENDING)) - goto unlock; - - if (r_ctl == FC_RCTL_DD_DATA_DESC) { - /* - * received XFER RDY from the target - * need to send data to the target - */ - WARN_ON(fr_flags(fp) & FCPHF_CRC_UNCHECKED); - dd = fc_frame_payload_get(fp, sizeof(*dd)); - WARN_ON(!dd); - - rc = fc_fcp_send_data(fsp, seq, - (size_t) ntohl(dd->ft_data_ro), - (size_t) ntohl(dd->ft_burst_len)); - if (!rc) - seq->rec_data = fsp->xfer_len; - } else if (r_ctl == FC_RCTL_DD_SOL_DATA) { - /* - * received a DATA frame - * next we will copy the data to the system buffer - */ - WARN_ON(fr_len(fp) < sizeof(*fh)); /* len may be 0 */ - fc_fcp_recv_data(fsp, fp); - seq->rec_data = fsp->xfer_contig_end; - } else if (r_ctl == FC_RCTL_DD_CMD_STATUS) { - WARN_ON(fr_flags(fp) & FCPHF_CRC_UNCHECKED); - - fc_fcp_resp(fsp, fp); - } else { - FC_FCP_DBG(fsp, "unexpected frame. r_ctl %x\n", r_ctl); - } -unlock: - fc_fcp_unlock_pkt(fsp); -out: - fc_frame_free(fp); -} - -/** - * fc_fcp_resp() - Handler for FCP responses - * @fsp: The FCP packet the response is for - * @fp: The response frame - */ -static void fc_fcp_resp(struct fc_fcp_pkt *fsp, struct fc_frame *fp) -{ - struct fc_frame_header *fh; - struct fcp_resp *fc_rp; - struct fcp_resp_ext *rp_ex; - struct fcp_resp_rsp_info *fc_rp_info; - u32 plen; - u32 expected_len; - u32 respl = 0; - u32 snsl = 0; - u8 flags = 0; - - plen = fr_len(fp); - fh = (struct fc_frame_header *)fr_hdr(fp); - if (unlikely(plen < sizeof(*fh) + sizeof(*fc_rp))) - goto len_err; - plen -= sizeof(*fh); - fc_rp = (struct fcp_resp *)(fh + 1); - fsp->cdb_status = fc_rp->fr_status; - flags = fc_rp->fr_flags; - fsp->scsi_comp_flags = flags; - expected_len = fsp->data_len; - - /* if ddp, update xfer len */ - fc_fcp_ddp_done(fsp); - - if (unlikely((flags & ~FCP_CONF_REQ) || fc_rp->fr_status)) { - rp_ex = (void *)(fc_rp + 1); - if (flags & (FCP_RSP_LEN_VAL | FCP_SNS_LEN_VAL)) { - if (plen < sizeof(*fc_rp) + sizeof(*rp_ex)) - goto len_err; - fc_rp_info = (struct fcp_resp_rsp_info *)(rp_ex + 1); - if (flags & FCP_RSP_LEN_VAL) { - respl = ntohl(rp_ex->fr_rsp_len); - if (respl != sizeof(*fc_rp_info)) - goto len_err; - if (fsp->wait_for_comp) { - /* Abuse cdb_status for rsp code */ - fsp->cdb_status = fc_rp_info->rsp_code; - complete(&fsp->tm_done); - /* - * tmfs will not have any scsi cmd so - * exit here - */ - return; - } - } - if (flags & FCP_SNS_LEN_VAL) { - snsl = ntohl(rp_ex->fr_sns_len); - if (snsl > SCSI_SENSE_BUFFERSIZE) - snsl = SCSI_SENSE_BUFFERSIZE; - memcpy(fsp->cmd->sense_buffer, - (char *)fc_rp_info + respl, snsl); - } - } - if (flags & (FCP_RESID_UNDER | FCP_RESID_OVER)) { - if (plen < sizeof(*fc_rp) + sizeof(rp_ex->fr_resid)) - goto len_err; - if (flags & FCP_RESID_UNDER) { - fsp->scsi_resid = ntohl(rp_ex->fr_resid); - /* - * The cmnd->underflow is the minimum number of - * bytes that must be transferred for this - * command. Provided a sense condition is not - * present, make sure the actual amount - * transferred is at least the underflow value - * or fail. - */ - if (!(flags & FCP_SNS_LEN_VAL) && - (fc_rp->fr_status == 0) && - (scsi_bufflen(fsp->cmd) - - fsp->scsi_resid) < fsp->cmd->underflow) - goto err; - expected_len -= fsp->scsi_resid; - } else { - fsp->status_code = FC_ERROR; - } - } - } - fsp->state |= FC_SRB_RCV_STATUS; - - /* - * Check for missing or extra data frames. - */ - if (unlikely(fsp->xfer_len != expected_len)) { - if (fsp->xfer_len < expected_len) { - /* - * Some data may be queued locally, - * Wait a at least one jiffy to see if it is delivered. - * If this expires without data, we may do SRR. - */ - fc_fcp_timer_set(fsp, 2); - return; - } - fsp->status_code = FC_DATA_OVRRUN; - FC_FCP_DBG(fsp, "tgt %6.6x xfer len %zx greater than expected, " - "len %x, data len %x\n", - fsp->rport->port_id, - fsp->xfer_len, expected_len, fsp->data_len); - } - fc_fcp_complete_locked(fsp); - return; - -len_err: - FC_FCP_DBG(fsp, "short FCP response. flags 0x%x len %u respl %u " - "snsl %u\n", flags, fr_len(fp), respl, snsl); -err: - fsp->status_code = FC_ERROR; - fc_fcp_complete_locked(fsp); -} - -/** - * fc_fcp_complete_locked() - Complete processing of a fcp_pkt with the - * fcp_pkt lock held - * @fsp: The FCP packet to be completed - * - * This function may sleep if a timer is pending. The packet lock must be - * held, and the host lock must not be held. - */ -static void fc_fcp_complete_locked(struct fc_fcp_pkt *fsp) -{ - struct fc_lport *lport = fsp->lp; - struct fc_seq *seq; - struct fc_exch *ep; - u32 f_ctl; - - if (fsp->state & FC_SRB_ABORT_PENDING) - return; - - if (fsp->state & FC_SRB_ABORTED) { - if (!fsp->status_code) - fsp->status_code = FC_CMD_ABORTED; - } else { - /* - * Test for transport underrun, independent of response - * underrun status. - */ - if (fsp->xfer_len < fsp->data_len && !fsp->io_status && - (!(fsp->scsi_comp_flags & FCP_RESID_UNDER) || - fsp->xfer_len < fsp->data_len - fsp->scsi_resid)) { - fsp->status_code = FC_DATA_UNDRUN; - fsp->io_status = 0; - } - } - - seq = fsp->seq_ptr; - if (seq) { - fsp->seq_ptr = NULL; - if (unlikely(fsp->scsi_comp_flags & FCP_CONF_REQ)) { - struct fc_frame *conf_frame; - struct fc_seq *csp; - - csp = lport->tt.seq_start_next(seq); - conf_frame = fc_fcp_frame_alloc(fsp->lp, 0); - if (conf_frame) { - f_ctl = FC_FC_SEQ_INIT; - f_ctl |= FC_FC_LAST_SEQ | FC_FC_END_SEQ; - ep = fc_seq_exch(seq); - fc_fill_fc_hdr(conf_frame, FC_RCTL_DD_SOL_CTL, - ep->did, ep->sid, - FC_TYPE_FCP, f_ctl, 0); - lport->tt.seq_send(lport, csp, conf_frame); - } - } - lport->tt.exch_done(seq); - } - /* - * Some resets driven by SCSI are not I/Os and do not have - * SCSI commands associated with the requests. We should not - * call I/O completion if we do not have a SCSI command. - */ - if (fsp->cmd) - fc_io_compl(fsp); -} - -/** - * fc_fcp_cleanup_cmd() - Cancel the active exchange on a fcp_pkt - * @fsp: The FCP packet whose exchanges should be canceled - * @error: The reason for the cancellation - */ -static void fc_fcp_cleanup_cmd(struct fc_fcp_pkt *fsp, int error) -{ - struct fc_lport *lport = fsp->lp; - - if (fsp->seq_ptr) { - lport->tt.exch_done(fsp->seq_ptr); - fsp->seq_ptr = NULL; - } - fsp->status_code = error; -} - -/** - * fc_fcp_cleanup_each_cmd() - Cancel all exchanges on a local port - * @lport: The local port whose exchanges should be canceled - * @id: The target's ID - * @lun: The LUN - * @error: The reason for cancellation - * - * If lun or id is -1, they are ignored. - */ -static void fc_fcp_cleanup_each_cmd(struct fc_lport *lport, unsigned int id, - unsigned int lun, int error) -{ - struct fc_fcp_internal *si = fc_get_scsi_internal(lport); - struct fc_fcp_pkt *fsp; - struct scsi_cmnd *sc_cmd; - unsigned long flags; - - spin_lock_irqsave(&si->scsi_queue_lock, flags); -restart: - list_for_each_entry(fsp, &si->scsi_pkt_queue, list) { - sc_cmd = fsp->cmd; - if (id != -1 && scmd_id(sc_cmd) != id) - continue; - - if (lun != -1 && sc_cmd->device->lun != lun) - continue; - - fc_fcp_pkt_hold(fsp); - spin_unlock_irqrestore(&si->scsi_queue_lock, flags); - - if (!fc_fcp_lock_pkt(fsp)) { - fc_fcp_cleanup_cmd(fsp, error); - fc_io_compl(fsp); - fc_fcp_unlock_pkt(fsp); - } - - fc_fcp_pkt_release(fsp); - spin_lock_irqsave(&si->scsi_queue_lock, flags); - /* - * while we dropped the lock multiple pkts could - * have been released, so we have to start over. - */ - goto restart; - } - spin_unlock_irqrestore(&si->scsi_queue_lock, flags); -} - -/** - * fc_fcp_abort_io() - Abort all FCP-SCSI exchanges on a local port - * @lport: The local port whose exchanges are to be aborted - */ -static void fc_fcp_abort_io(struct fc_lport *lport) -{ - fc_fcp_cleanup_each_cmd(lport, -1, -1, FC_HRD_ERROR); -} - -/** - * fc_fcp_pkt_send() - Send a fcp_pkt - * @lport: The local port to send the FCP packet on - * @fsp: The FCP packet to send - * - * Return: Zero for success and -1 for failure - * Locks: Called without locks held - */ -static int fc_fcp_pkt_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp) -{ - struct fc_fcp_internal *si = fc_get_scsi_internal(lport); - unsigned long flags; - int rc; - - fsp->cmd->SCp.ptr = (char *)fsp; - fsp->cdb_cmd.fc_dl = htonl(fsp->data_len); - fsp->cdb_cmd.fc_flags = fsp->req_flags & ~FCP_CFL_LEN_MASK; - - int_to_scsilun(fsp->cmd->device->lun, &fsp->cdb_cmd.fc_lun); - memcpy(fsp->cdb_cmd.fc_cdb, fsp->cmd->cmnd, fsp->cmd->cmd_len); - - spin_lock_irqsave(&si->scsi_queue_lock, flags); - list_add_tail(&fsp->list, &si->scsi_pkt_queue); - spin_unlock_irqrestore(&si->scsi_queue_lock, flags); - rc = lport->tt.fcp_cmd_send(lport, fsp, fc_fcp_recv); - if (unlikely(rc)) { - spin_lock_irqsave(&si->scsi_queue_lock, flags); - fsp->cmd->SCp.ptr = NULL; - list_del(&fsp->list); - spin_unlock_irqrestore(&si->scsi_queue_lock, flags); - } - - return rc; -} - -/** - * get_fsp_rec_tov() - Helper function to get REC_TOV - * @fsp: the FCP packet - * - * Returns rec tov in jiffies as rpriv->e_d_tov + 1 second - */ -static inline unsigned int get_fsp_rec_tov(struct fc_fcp_pkt *fsp) -{ - struct fc_rport_libfc_priv *rpriv = fsp->rport->dd_data; - - return msecs_to_jiffies(rpriv->e_d_tov) + HZ; -} - -/** - * fc_fcp_cmd_send() - Send a FCP command - * @lport: The local port to send the command on - * @fsp: The FCP packet the command is on - * @resp: The handler for the response - */ -static int fc_fcp_cmd_send(struct fc_lport *lport, struct fc_fcp_pkt *fsp, - void (*resp)(struct fc_seq *, - struct fc_frame *fp, - void *arg)) -{ - struct fc_frame *fp; - struct fc_seq *seq; - struct fc_rport *rport; - struct fc_rport_libfc_priv *rpriv; - const size_t len = sizeof(fsp->cdb_cmd); - int rc = 0; - - if (fc_fcp_lock_pkt(fsp)) - return 0; - - fp = fc_fcp_frame_alloc(lport, sizeof(fsp->cdb_cmd)); - if (!fp) { - rc = -1; - goto unlock; - } - - memcpy(fc_frame_payload_get(fp, len), &fsp->cdb_cmd, len); - fr_fsp(fp) = fsp; - rport = fsp->rport; - fsp->max_payload = rport->maxframe_size; - rpriv = rport->dd_data; - - fc_fill_fc_hdr(fp, FC_RCTL_DD_UNSOL_CMD, rport->port_id, - rpriv->local_port->port_id, FC_TYPE_FCP, - FC_FCTL_REQ, 0); - - seq = lport->tt.exch_seq_send(lport, fp, resp, fc_fcp_pkt_destroy, - fsp, 0); - if (!seq) { - rc = -1; - goto unlock; - } - fsp->seq_ptr = seq; - fc_fcp_pkt_hold(fsp); /* hold for fc_fcp_pkt_destroy */ - - setup_timer(&fsp->timer, fc_fcp_timeout, (unsigned long)fsp); - if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED) - fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); - -unlock: - fc_fcp_unlock_pkt(fsp); - return rc; -} - -/** - * fc_fcp_error() - Handler for FCP layer errors - * @fsp: The FCP packet the error is on - * @fp: The frame that has errored - */ -static void fc_fcp_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) -{ - int error = PTR_ERR(fp); - - if (fc_fcp_lock_pkt(fsp)) - return; - - if (error == -FC_EX_CLOSED) { - fc_fcp_retry_cmd(fsp); - goto unlock; - } - - /* - * clear abort pending, because the lower layer - * decided to force completion. - */ - fsp->state &= ~FC_SRB_ABORT_PENDING; - fsp->status_code = FC_CMD_PLOGO; - fc_fcp_complete_locked(fsp); -unlock: - fc_fcp_unlock_pkt(fsp); -} - -/** - * fc_fcp_pkt_abort() - Abort a fcp_pkt - * @fsp: The FCP packet to abort on - * - * Called to send an abort and then wait for abort completion - */ -static int fc_fcp_pkt_abort(struct fc_fcp_pkt *fsp) -{ - int rc = FAILED; - unsigned long ticks_left; - - if (fc_fcp_send_abort(fsp)) - return FAILED; - - init_completion(&fsp->tm_done); - fsp->wait_for_comp = 1; - - spin_unlock_bh(&fsp->scsi_pkt_lock); - ticks_left = wait_for_completion_timeout(&fsp->tm_done, - FC_SCSI_TM_TOV); - spin_lock_bh(&fsp->scsi_pkt_lock); - fsp->wait_for_comp = 0; - - if (!ticks_left) { - FC_FCP_DBG(fsp, "target abort cmd failed\n"); - } else if (fsp->state & FC_SRB_ABORTED) { - FC_FCP_DBG(fsp, "target abort cmd passed\n"); - rc = SUCCESS; - fc_fcp_complete_locked(fsp); - } - - return rc; -} - -/** - * fc_lun_reset_send() - Send LUN reset command - * @data: The FCP packet that identifies the LUN to be reset - */ -static void fc_lun_reset_send(unsigned long data) -{ - struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data; - struct fc_lport *lport = fsp->lp; - - if (lport->tt.fcp_cmd_send(lport, fsp, fc_tm_done)) { - if (fsp->recov_retry++ >= FC_MAX_RECOV_RETRY) - return; - if (fc_fcp_lock_pkt(fsp)) - return; - setup_timer(&fsp->timer, fc_lun_reset_send, (unsigned long)fsp); - fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); - fc_fcp_unlock_pkt(fsp); - } -} - -/** - * fc_lun_reset() - Send a LUN RESET command to a device - * and wait for the reply - * @lport: The local port to sent the command on - * @fsp: The FCP packet that identifies the LUN to be reset - * @id: The SCSI command ID - * @lun: The LUN ID to be reset - */ -static int fc_lun_reset(struct fc_lport *lport, struct fc_fcp_pkt *fsp, - unsigned int id, unsigned int lun) -{ - int rc; - - fsp->cdb_cmd.fc_dl = htonl(fsp->data_len); - fsp->cdb_cmd.fc_tm_flags = FCP_TMF_LUN_RESET; - int_to_scsilun(lun, &fsp->cdb_cmd.fc_lun); - - fsp->wait_for_comp = 1; - init_completion(&fsp->tm_done); - - fc_lun_reset_send((unsigned long)fsp); - - /* - * wait for completion of reset - * after that make sure all commands are terminated - */ - rc = wait_for_completion_timeout(&fsp->tm_done, FC_SCSI_TM_TOV); - - spin_lock_bh(&fsp->scsi_pkt_lock); - fsp->state |= FC_SRB_COMPL; - spin_unlock_bh(&fsp->scsi_pkt_lock); - - del_timer_sync(&fsp->timer); - - spin_lock_bh(&fsp->scsi_pkt_lock); - if (fsp->seq_ptr) { - lport->tt.exch_done(fsp->seq_ptr); - fsp->seq_ptr = NULL; - } - fsp->wait_for_comp = 0; - spin_unlock_bh(&fsp->scsi_pkt_lock); - - if (!rc) { - FC_SCSI_DBG(lport, "lun reset failed\n"); - return FAILED; - } - - /* cdb_status holds the tmf's rsp code */ - if (fsp->cdb_status != FCP_TMF_CMPL) - return FAILED; - - FC_SCSI_DBG(lport, "lun reset to lun %u completed\n", lun); - fc_fcp_cleanup_each_cmd(lport, id, lun, FC_CMD_ABORTED); - return SUCCESS; -} - -/** - * fc_tm_done() - Task Management response handler - * @seq: The sequence that the response is on - * @fp: The response frame - * @arg: The FCP packet the response is for - */ -static void fc_tm_done(struct fc_seq *seq, struct fc_frame *fp, void *arg) -{ - struct fc_fcp_pkt *fsp = arg; - struct fc_frame_header *fh; - - if (IS_ERR(fp)) { - /* - * If there is an error just let it timeout or wait - * for TMF to be aborted if it timedout. - * - * scsi-eh will escalate for when either happens. - */ - return; - } - - if (fc_fcp_lock_pkt(fsp)) - goto out; - - /* - * raced with eh timeout handler. - */ - if (!fsp->seq_ptr || !fsp->wait_for_comp) - goto out_unlock; - - fh = fc_frame_header_get(fp); - if (fh->fh_type != FC_TYPE_BLS) - fc_fcp_resp(fsp, fp); - fsp->seq_ptr = NULL; - fsp->lp->tt.exch_done(seq); -out_unlock: - fc_fcp_unlock_pkt(fsp); -out: - fc_frame_free(fp); -} - -/** - * fc_fcp_cleanup() - Cleanup all FCP exchanges on a local port - * @lport: The local port to be cleaned up - */ -static void fc_fcp_cleanup(struct fc_lport *lport) -{ - fc_fcp_cleanup_each_cmd(lport, -1, -1, FC_ERROR); -} - -/** - * fc_fcp_timeout() - Handler for fcp_pkt timeouts - * @data: The FCP packet that has timed out - * - * If REC is supported then just issue it and return. The REC exchange will - * complete or time out and recovery can continue at that point. Otherwise, - * if the response has been received without all the data it has been - * ER_TIMEOUT since the response was received. If the response has not been - * received we see if data was received recently. If it has been then we - * continue waiting, otherwise, we abort the command. - */ -static void fc_fcp_timeout(unsigned long data) -{ - struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)data; - struct fc_rport *rport = fsp->rport; - struct fc_rport_libfc_priv *rpriv = rport->dd_data; - - if (fc_fcp_lock_pkt(fsp)) - return; - - if (fsp->cdb_cmd.fc_tm_flags) - goto unlock; - - fsp->state |= FC_SRB_FCP_PROCESSING_TMO; - - if (rpriv->flags & FC_RP_FLAGS_REC_SUPPORTED) - fc_fcp_rec(fsp); - else if (fsp->state & FC_SRB_RCV_STATUS) - fc_fcp_complete_locked(fsp); - else - fc_fcp_recovery(fsp, FC_TIMED_OUT); - fsp->state &= ~FC_SRB_FCP_PROCESSING_TMO; -unlock: - fc_fcp_unlock_pkt(fsp); -} - -/** - * fc_fcp_rec() - Send a REC ELS request - * @fsp: The FCP packet to send the REC request on - */ -static void fc_fcp_rec(struct fc_fcp_pkt *fsp) -{ - struct fc_lport *lport; - struct fc_frame *fp; - struct fc_rport *rport; - struct fc_rport_libfc_priv *rpriv; - - lport = fsp->lp; - rport = fsp->rport; - rpriv = rport->dd_data; - if (!fsp->seq_ptr || rpriv->rp_state != RPORT_ST_READY) { - fsp->status_code = FC_HRD_ERROR; - fsp->io_status = 0; - fc_fcp_complete_locked(fsp); - return; - } - - fp = fc_fcp_frame_alloc(lport, sizeof(struct fc_els_rec)); - if (!fp) - goto retry; - - fr_seq(fp) = fsp->seq_ptr; - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rport->port_id, - rpriv->local_port->port_id, FC_TYPE_ELS, - FC_FCTL_REQ, 0); - if (lport->tt.elsct_send(lport, rport->port_id, fp, ELS_REC, - fc_fcp_rec_resp, fsp, - 2 * lport->r_a_tov)) { - fc_fcp_pkt_hold(fsp); /* hold while REC outstanding */ - return; - } -retry: - if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) - fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); - else - fc_fcp_recovery(fsp, FC_TIMED_OUT); -} - -/** - * fc_fcp_rec_resp() - Handler for REC ELS responses - * @seq: The sequence the response is on - * @fp: The response frame - * @arg: The FCP packet the response is on - * - * If the response is a reject then the scsi layer will handle - * the timeout. If the response is a LS_ACC then if the I/O was not completed - * set the timeout and return. If the I/O was completed then complete the - * exchange and tell the SCSI layer. - */ -static void fc_fcp_rec_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) -{ - struct fc_fcp_pkt *fsp = (struct fc_fcp_pkt *)arg; - struct fc_els_rec_acc *recp; - struct fc_els_ls_rjt *rjt; - u32 e_stat; - u8 opcode; - u32 offset; - enum dma_data_direction data_dir; - enum fc_rctl r_ctl; - struct fc_rport_libfc_priv *rpriv; - - if (IS_ERR(fp)) { - fc_fcp_rec_error(fsp, fp); - return; - } - - if (fc_fcp_lock_pkt(fsp)) - goto out; - - fsp->recov_retry = 0; - opcode = fc_frame_payload_op(fp); - if (opcode == ELS_LS_RJT) { - rjt = fc_frame_payload_get(fp, sizeof(*rjt)); - switch (rjt->er_reason) { - default: - FC_FCP_DBG(fsp, "device %x unexpected REC reject " - "reason %d expl %d\n", - fsp->rport->port_id, rjt->er_reason, - rjt->er_explan); - /* fall through */ - case ELS_RJT_UNSUP: - FC_FCP_DBG(fsp, "device does not support REC\n"); - rpriv = fsp->rport->dd_data; - /* - * if we do not spport RECs or got some bogus - * reason then resetup timer so we check for - * making progress. - */ - rpriv->flags &= ~FC_RP_FLAGS_REC_SUPPORTED; - break; - case ELS_RJT_LOGIC: - case ELS_RJT_UNAB: - /* - * If no data transfer, the command frame got dropped - * so we just retry. If data was transferred, we - * lost the response but the target has no record, - * so we abort and retry. - */ - if (rjt->er_explan == ELS_EXPL_OXID_RXID && - fsp->xfer_len == 0) { - fc_fcp_retry_cmd(fsp); - break; - } - fc_fcp_recovery(fsp, FC_ERROR); - break; - } - } else if (opcode == ELS_LS_ACC) { - if (fsp->state & FC_SRB_ABORTED) - goto unlock_out; - - data_dir = fsp->cmd->sc_data_direction; - recp = fc_frame_payload_get(fp, sizeof(*recp)); - offset = ntohl(recp->reca_fc4value); - e_stat = ntohl(recp->reca_e_stat); - - if (e_stat & ESB_ST_COMPLETE) { - - /* - * The exchange is complete. - * - * For output, we must've lost the response. - * For input, all data must've been sent. - * We lost may have lost the response - * (and a confirmation was requested) and maybe - * some data. - * - * If all data received, send SRR - * asking for response. If partial data received, - * or gaps, SRR requests data at start of gap. - * Recovery via SRR relies on in-order-delivery. - */ - if (data_dir == DMA_TO_DEVICE) { - r_ctl = FC_RCTL_DD_CMD_STATUS; - } else if (fsp->xfer_contig_end == offset) { - r_ctl = FC_RCTL_DD_CMD_STATUS; - } else { - offset = fsp->xfer_contig_end; - r_ctl = FC_RCTL_DD_SOL_DATA; - } - fc_fcp_srr(fsp, r_ctl, offset); - } else if (e_stat & ESB_ST_SEQ_INIT) { - /* - * The remote port has the initiative, so just - * keep waiting for it to complete. - */ - fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); - } else { - - /* - * The exchange is incomplete, we have seq. initiative. - * Lost response with requested confirmation, - * lost confirmation, lost transfer ready or - * lost write data. - * - * For output, if not all data was received, ask - * for transfer ready to be repeated. - * - * If we received or sent all the data, send SRR to - * request response. - * - * If we lost a response, we may have lost some read - * data as well. - */ - r_ctl = FC_RCTL_DD_SOL_DATA; - if (data_dir == DMA_TO_DEVICE) { - r_ctl = FC_RCTL_DD_CMD_STATUS; - if (offset < fsp->data_len) - r_ctl = FC_RCTL_DD_DATA_DESC; - } else if (offset == fsp->xfer_contig_end) { - r_ctl = FC_RCTL_DD_CMD_STATUS; - } else if (fsp->xfer_contig_end < offset) { - offset = fsp->xfer_contig_end; - } - fc_fcp_srr(fsp, r_ctl, offset); - } - } -unlock_out: - fc_fcp_unlock_pkt(fsp); -out: - fc_fcp_pkt_release(fsp); /* drop hold for outstanding REC */ - fc_frame_free(fp); -} - -/** - * fc_fcp_rec_error() - Handler for REC errors - * @fsp: The FCP packet the error is on - * @fp: The REC frame - */ -static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) -{ - int error = PTR_ERR(fp); - - if (fc_fcp_lock_pkt(fsp)) - goto out; - - switch (error) { - case -FC_EX_CLOSED: - fc_fcp_retry_cmd(fsp); - break; - - default: - FC_FCP_DBG(fsp, "REC %p fid %6.6x error unexpected error %d\n", - fsp, fsp->rport->port_id, error); - fsp->status_code = FC_CMD_PLOGO; - /* fall through */ - - case -FC_EX_TIMEOUT: - /* - * Assume REC or LS_ACC was lost. - * The exchange manager will have aborted REC, so retry. - */ - FC_FCP_DBG(fsp, "REC fid %6.6x error error %d retry %d/%d\n", - fsp->rport->port_id, error, fsp->recov_retry, - FC_MAX_RECOV_RETRY); - if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) - fc_fcp_rec(fsp); - else - fc_fcp_recovery(fsp, FC_ERROR); - break; - } - fc_fcp_unlock_pkt(fsp); -out: - fc_fcp_pkt_release(fsp); /* drop hold for outstanding REC */ -} - -/** - * fc_fcp_recovery() - Handler for fcp_pkt recovery - * @fsp: The FCP pkt that needs to be aborted - */ -static void fc_fcp_recovery(struct fc_fcp_pkt *fsp, u8 code) -{ - fsp->status_code = code; - fsp->cdb_status = 0; - fsp->io_status = 0; - /* - * if this fails then we let the scsi command timer fire and - * scsi-ml escalate. - */ - fc_fcp_send_abort(fsp); -} - -/** - * fc_fcp_srr() - Send a SRR request (Sequence Retransmission Request) - * @fsp: The FCP packet the SRR is to be sent on - * @r_ctl: The R_CTL field for the SRR request - * This is called after receiving status but insufficient data, or - * when expecting status but the request has timed out. - */ -static void fc_fcp_srr(struct fc_fcp_pkt *fsp, enum fc_rctl r_ctl, u32 offset) -{ - struct fc_lport *lport = fsp->lp; - struct fc_rport *rport; - struct fc_rport_libfc_priv *rpriv; - struct fc_exch *ep = fc_seq_exch(fsp->seq_ptr); - struct fc_seq *seq; - struct fcp_srr *srr; - struct fc_frame *fp; - unsigned int rec_tov; - - rport = fsp->rport; - rpriv = rport->dd_data; - - if (!(rpriv->flags & FC_RP_FLAGS_RETRY) || - rpriv->rp_state != RPORT_ST_READY) - goto retry; /* shouldn't happen */ - fp = fc_fcp_frame_alloc(lport, sizeof(*srr)); - if (!fp) - goto retry; - - srr = fc_frame_payload_get(fp, sizeof(*srr)); - memset(srr, 0, sizeof(*srr)); - srr->srr_op = ELS_SRR; - srr->srr_ox_id = htons(ep->oxid); - srr->srr_rx_id = htons(ep->rxid); - srr->srr_r_ctl = r_ctl; - srr->srr_rel_off = htonl(offset); - - fc_fill_fc_hdr(fp, FC_RCTL_ELS4_REQ, rport->port_id, - rpriv->local_port->port_id, FC_TYPE_FCP, - FC_FCTL_REQ, 0); - - rec_tov = get_fsp_rec_tov(fsp); - seq = lport->tt.exch_seq_send(lport, fp, fc_fcp_srr_resp, - fc_fcp_pkt_destroy, - fsp, jiffies_to_msecs(rec_tov)); - if (!seq) - goto retry; - - fsp->recov_seq = seq; - fsp->xfer_len = offset; - fsp->xfer_contig_end = offset; - fsp->state &= ~FC_SRB_RCV_STATUS; - fc_fcp_pkt_hold(fsp); /* hold for outstanding SRR */ - return; -retry: - fc_fcp_retry_cmd(fsp); -} - -/** - * fc_fcp_srr_resp() - Handler for SRR response - * @seq: The sequence the SRR is on - * @fp: The SRR frame - * @arg: The FCP packet the SRR is on - */ -static void fc_fcp_srr_resp(struct fc_seq *seq, struct fc_frame *fp, void *arg) -{ - struct fc_fcp_pkt *fsp = arg; - struct fc_frame_header *fh; - - if (IS_ERR(fp)) { - fc_fcp_srr_error(fsp, fp); - return; - } - - if (fc_fcp_lock_pkt(fsp)) - goto out; - - fh = fc_frame_header_get(fp); - /* - * BUG? fc_fcp_srr_error calls exch_done which would release - * the ep. But if fc_fcp_srr_error had got -FC_EX_TIMEOUT, - * then fc_exch_timeout would be sending an abort. The exch_done - * call by fc_fcp_srr_error would prevent fc_exch.c from seeing - * an abort response though. - */ - if (fh->fh_type == FC_TYPE_BLS) { - fc_fcp_unlock_pkt(fsp); - return; - } - - switch (fc_frame_payload_op(fp)) { - case ELS_LS_ACC: - fsp->recov_retry = 0; - fc_fcp_timer_set(fsp, get_fsp_rec_tov(fsp)); - break; - case ELS_LS_RJT: - default: - fc_fcp_recovery(fsp, FC_ERROR); - break; - } - fc_fcp_unlock_pkt(fsp); -out: - fsp->lp->tt.exch_done(seq); - fc_frame_free(fp); -} - -/** - * fc_fcp_srr_error() - Handler for SRR errors - * @fsp: The FCP packet that the SRR error is on - * @fp: The SRR frame - */ -static void fc_fcp_srr_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) -{ - if (fc_fcp_lock_pkt(fsp)) - goto out; - switch (PTR_ERR(fp)) { - case -FC_EX_TIMEOUT: - if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) - fc_fcp_rec(fsp); - else - fc_fcp_recovery(fsp, FC_TIMED_OUT); - break; - case -FC_EX_CLOSED: /* e.g., link failure */ - /* fall through */ - default: - fc_fcp_retry_cmd(fsp); - break; - } - fc_fcp_unlock_pkt(fsp); -out: - fsp->lp->tt.exch_done(fsp->recov_seq); -} - -/** - * fc_fcp_lport_queue_ready() - Determine if the lport and it's queue is ready - * @lport: The local port to be checked - */ -static inline int fc_fcp_lport_queue_ready(struct fc_lport *lport) -{ - /* lock ? */ - return (lport->state == LPORT_ST_READY) && - lport->link_up && !lport->qfull; -} - -/** - * fc_queuecommand() - The queuecommand function of the SCSI template - * @shost: The Scsi_Host that the command was issued to - * @cmd: The scsi_cmnd to be executed - * - * This is the i/o strategy routine, called by the SCSI layer. - */ -int fc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc_cmd) -{ - struct fc_lport *lport = shost_priv(shost); - struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); - struct fc_fcp_pkt *fsp; - struct fc_rport_libfc_priv *rpriv; - int rval; - int rc = 0; - struct fcoe_dev_stats *stats; - - rval = fc_remote_port_chkready(rport); - if (rval) { - sc_cmd->result = rval; - sc_cmd->scsi_done(sc_cmd); - return 0; - } - - if (!*(struct fc_remote_port **)rport->dd_data) { - /* - * rport is transitioning from blocked/deleted to - * online - */ - sc_cmd->result = DID_IMM_RETRY << 16; - sc_cmd->scsi_done(sc_cmd); - goto out; - } - - rpriv = rport->dd_data; - - if (!fc_fcp_lport_queue_ready(lport)) { - if (lport->qfull) - fc_fcp_can_queue_ramp_down(lport); - rc = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - - fsp = fc_fcp_pkt_alloc(lport, GFP_ATOMIC); - if (fsp == NULL) { - rc = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - - /* - * build the libfc request pkt - */ - fsp->cmd = sc_cmd; /* save the cmd */ - fsp->rport = rport; /* set the remote port ptr */ - - /* - * set up the transfer length - */ - fsp->data_len = scsi_bufflen(sc_cmd); - fsp->xfer_len = 0; - - /* - * setup the data direction - */ - stats = per_cpu_ptr(lport->dev_stats, get_cpu()); - if (sc_cmd->sc_data_direction == DMA_FROM_DEVICE) { - fsp->req_flags = FC_SRB_READ; - stats->InputRequests++; - stats->InputBytes += fsp->data_len; - } else if (sc_cmd->sc_data_direction == DMA_TO_DEVICE) { - fsp->req_flags = FC_SRB_WRITE; - stats->OutputRequests++; - stats->OutputBytes += fsp->data_len; - } else { - fsp->req_flags = 0; - stats->ControlRequests++; - } - put_cpu(); - - /* - * send it to the lower layer - * if we get -1 return then put the request in the pending - * queue. - */ - rval = fc_fcp_pkt_send(lport, fsp); - if (rval != 0) { - fsp->state = FC_SRB_FREE; - fc_fcp_pkt_release(fsp); - rc = SCSI_MLQUEUE_HOST_BUSY; - } -out: - return rc; -} -EXPORT_SYMBOL(fc_queuecommand); - -/** - * fc_io_compl() - Handle responses for completed commands - * @fsp: The FCP packet that is complete - * - * Translates fcp_pkt errors to a Linux SCSI errors. - * The fcp packet lock must be held when calling. - */ -static void fc_io_compl(struct fc_fcp_pkt *fsp) -{ - struct fc_fcp_internal *si; - struct scsi_cmnd *sc_cmd; - struct fc_lport *lport; - unsigned long flags; - - /* release outstanding ddp context */ - fc_fcp_ddp_done(fsp); - - fsp->state |= FC_SRB_COMPL; - if (!(fsp->state & FC_SRB_FCP_PROCESSING_TMO)) { - spin_unlock_bh(&fsp->scsi_pkt_lock); - del_timer_sync(&fsp->timer); - spin_lock_bh(&fsp->scsi_pkt_lock); - } - - lport = fsp->lp; - si = fc_get_scsi_internal(lport); - - /* - * if can_queue ramp down is done then try can_queue ramp up - * since commands are completing now. - */ - if (si->last_can_queue_ramp_down_time) - fc_fcp_can_queue_ramp_up(lport); - - sc_cmd = fsp->cmd; - CMD_SCSI_STATUS(sc_cmd) = fsp->cdb_status; - switch (fsp->status_code) { - case FC_COMPLETE: - if (fsp->cdb_status == 0) { - /* - * good I/O status - */ - sc_cmd->result = DID_OK << 16; - if (fsp->scsi_resid) - CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid; - } else { - /* - * transport level I/O was ok but scsi - * has non zero status - */ - sc_cmd->result = (DID_OK << 16) | fsp->cdb_status; - } - break; - case FC_ERROR: - FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " - "due to FC_ERROR\n"); - sc_cmd->result = DID_ERROR << 16; - break; - case FC_DATA_UNDRUN: - if ((fsp->cdb_status == 0) && !(fsp->req_flags & FC_SRB_READ)) { - /* - * scsi status is good but transport level - * underrun. - */ - if (fsp->state & FC_SRB_RCV_STATUS) { - sc_cmd->result = DID_OK << 16; - } else { - FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml" - " due to FC_DATA_UNDRUN (trans)\n"); - sc_cmd->result = DID_ERROR << 16; - } - } else { - /* - * scsi got underrun, this is an error - */ - FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " - "due to FC_DATA_UNDRUN (scsi)\n"); - CMD_RESID_LEN(sc_cmd) = fsp->scsi_resid; - sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status; - } - break; - case FC_DATA_OVRRUN: - /* - * overrun is an error - */ - FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " - "due to FC_DATA_OVRRUN\n"); - sc_cmd->result = (DID_ERROR << 16) | fsp->cdb_status; - break; - case FC_CMD_ABORTED: - FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " - "due to FC_CMD_ABORTED\n"); - sc_cmd->result = (DID_ERROR << 16) | fsp->io_status; - break; - case FC_CMD_RESET: - FC_FCP_DBG(fsp, "Returning DID_RESET to scsi-ml " - "due to FC_CMD_RESET\n"); - sc_cmd->result = (DID_RESET << 16); - break; - case FC_HRD_ERROR: - FC_FCP_DBG(fsp, "Returning DID_NO_CONNECT to scsi-ml " - "due to FC_HRD_ERROR\n"); - sc_cmd->result = (DID_NO_CONNECT << 16); - break; - case FC_CRC_ERROR: - FC_FCP_DBG(fsp, "Returning DID_PARITY to scsi-ml " - "due to FC_CRC_ERROR\n"); - sc_cmd->result = (DID_PARITY << 16); - break; - case FC_TIMED_OUT: - FC_FCP_DBG(fsp, "Returning DID_BUS_BUSY to scsi-ml " - "due to FC_TIMED_OUT\n"); - sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status; - break; - default: - FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " - "due to unknown error\n"); - sc_cmd->result = (DID_ERROR << 16); - break; - } - - if (lport->state != LPORT_ST_READY && fsp->status_code != FC_COMPLETE) - sc_cmd->result = (DID_TRANSPORT_DISRUPTED << 16); - - spin_lock_irqsave(&si->scsi_queue_lock, flags); - list_del(&fsp->list); - sc_cmd->SCp.ptr = NULL; - spin_unlock_irqrestore(&si->scsi_queue_lock, flags); - sc_cmd->scsi_done(sc_cmd); - - /* release ref from initial allocation in queue command */ - fc_fcp_pkt_release(fsp); -} - -/** - * fc_eh_abort() - Abort a command - * @sc_cmd: The SCSI command to abort - * - * From SCSI host template. - * Send an ABTS to the target device and wait for the response. - */ -int fc_eh_abort(struct scsi_cmnd *sc_cmd) -{ - struct fc_fcp_pkt *fsp; - struct fc_lport *lport; - struct fc_fcp_internal *si; - int rc = FAILED; - unsigned long flags; - int rval; - - rval = fc_block_scsi_eh(sc_cmd); - if (rval) - return rval; - - lport = shost_priv(sc_cmd->device->host); - if (lport->state != LPORT_ST_READY) - return rc; - else if (!lport->link_up) - return rc; - - si = fc_get_scsi_internal(lport); - spin_lock_irqsave(&si->scsi_queue_lock, flags); - fsp = CMD_SP(sc_cmd); - if (!fsp) { - /* command completed while scsi eh was setting up */ - spin_unlock_irqrestore(&si->scsi_queue_lock, flags); - return SUCCESS; - } - /* grab a ref so the fsp and sc_cmd cannot be relased from under us */ - fc_fcp_pkt_hold(fsp); - spin_unlock_irqrestore(&si->scsi_queue_lock, flags); - - if (fc_fcp_lock_pkt(fsp)) { - /* completed while we were waiting for timer to be deleted */ - rc = SUCCESS; - goto release_pkt; - } - - rc = fc_fcp_pkt_abort(fsp); - fc_fcp_unlock_pkt(fsp); - -release_pkt: - fc_fcp_pkt_release(fsp); - return rc; -} -EXPORT_SYMBOL(fc_eh_abort); - -/** - * fc_eh_device_reset() - Reset a single LUN - * @sc_cmd: The SCSI command which identifies the device whose - * LUN is to be reset - * - * Set from SCSI host template. - */ -int fc_eh_device_reset(struct scsi_cmnd *sc_cmd) -{ - struct fc_lport *lport; - struct fc_fcp_pkt *fsp; - struct fc_rport *rport = starget_to_rport(scsi_target(sc_cmd->device)); - int rc = FAILED; - int rval; - - rval = fc_block_scsi_eh(sc_cmd); - if (rval) - return rval; - - lport = shost_priv(sc_cmd->device->host); - - if (lport->state != LPORT_ST_READY) - return rc; - - FC_SCSI_DBG(lport, "Resetting rport (%6.6x)\n", rport->port_id); - - fsp = fc_fcp_pkt_alloc(lport, GFP_NOIO); - if (fsp == NULL) { - printk(KERN_WARNING "libfc: could not allocate scsi_pkt\n"); - goto out; - } - - /* - * Build the libfc request pkt. Do not set the scsi cmnd, because - * the sc passed in is not setup for execution like when sent - * through the queuecommand callout. - */ - fsp->rport = rport; /* set the remote port ptr */ - - /* - * flush outstanding commands - */ - rc = fc_lun_reset(lport, fsp, scmd_id(sc_cmd), sc_cmd->device->lun); - fsp->state = FC_SRB_FREE; - fc_fcp_pkt_release(fsp); - -out: - return rc; -} -EXPORT_SYMBOL(fc_eh_device_reset); - -/** - * fc_eh_host_reset() - Reset a Scsi_Host. - * @sc_cmd: The SCSI command that identifies the SCSI host to be reset - */ -int fc_eh_host_reset(struct scsi_cmnd *sc_cmd) -{ - struct Scsi_Host *shost = sc_cmd->device->host; - struct fc_lport *lport = shost_priv(shost); - unsigned long wait_tmo; - - FC_SCSI_DBG(lport, "Resetting host\n"); - - fc_block_scsi_eh(sc_cmd); - - lport->tt.lport_reset(lport); - wait_tmo = jiffies + FC_HOST_RESET_TIMEOUT; - while (!fc_fcp_lport_queue_ready(lport) && time_before(jiffies, - wait_tmo)) - msleep(1000); - - if (fc_fcp_lport_queue_ready(lport)) { - shost_printk(KERN_INFO, shost, "libfc: Host reset succeeded " - "on port (%6.6x)\n", lport->port_id); - return SUCCESS; - } else { - shost_printk(KERN_INFO, shost, "libfc: Host reset failed, " - "port (%6.6x) is not ready.\n", - lport->port_id); - return FAILED; - } -} -EXPORT_SYMBOL(fc_eh_host_reset); - -/** - * fc_slave_alloc() - Configure the queue depth of a Scsi_Host - * @sdev: The SCSI device that identifies the SCSI host - * - * Configures queue depth based on host's cmd_per_len. If not set - * then we use the libfc default. - */ -int fc_slave_alloc(struct scsi_device *sdev) -{ - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - - if (!rport || fc_remote_port_chkready(rport)) - return -ENXIO; - - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, FC_FCP_DFLT_QUEUE_DEPTH); - else - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), - FC_FCP_DFLT_QUEUE_DEPTH); - - return 0; -} -EXPORT_SYMBOL(fc_slave_alloc); - -/** - * fc_change_queue_depth() - Change a device's queue depth - * @sdev: The SCSI device whose queue depth is to change - * @qdepth: The new queue depth - * @reason: The resason for the change - */ -int fc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) -{ - switch (reason) { - case SCSI_QDEPTH_DEFAULT: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); - break; - case SCSI_QDEPTH_QFULL: - scsi_track_queue_full(sdev, qdepth); - break; - case SCSI_QDEPTH_RAMP_UP: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); - break; - default: - return -EOPNOTSUPP; - } - return sdev->queue_depth; -} -EXPORT_SYMBOL(fc_change_queue_depth); - -/** - * fc_change_queue_type() - Change a device's queue type - * @sdev: The SCSI device whose queue depth is to change - * @tag_type: Identifier for queue type - */ -int fc_change_queue_type(struct scsi_device *sdev, int tag_type) -{ - if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, tag_type); - if (tag_type) - scsi_activate_tcq(sdev, sdev->queue_depth); - else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - } else - tag_type = 0; - - return tag_type; -} -EXPORT_SYMBOL(fc_change_queue_type); - -/** - * fc_fcp_destory() - Tear down the FCP layer for a given local port - * @lport: The local port that no longer needs the FCP layer - */ -void fc_fcp_destroy(struct fc_lport *lport) -{ - struct fc_fcp_internal *si = fc_get_scsi_internal(lport); - - if (!list_empty(&si->scsi_pkt_queue)) - printk(KERN_ERR "libfc: Leaked SCSI packets when destroying " - "port (%6.6x)\n", lport->port_id); - - mempool_destroy(si->scsi_pkt_pool); - kfree(si); - lport->scsi_priv = NULL; -} -EXPORT_SYMBOL(fc_fcp_destroy); - -int fc_setup_fcp(void) -{ - int rc = 0; - - scsi_pkt_cachep = kmem_cache_create("libfc_fcp_pkt", - sizeof(struct fc_fcp_pkt), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!scsi_pkt_cachep) { - printk(KERN_ERR "libfc: Unable to allocate SRB cache, " - "module load failed!"); - rc = -ENOMEM; - } - - return rc; -} - -void fc_destroy_fcp(void) -{ - if (scsi_pkt_cachep) - kmem_cache_destroy(scsi_pkt_cachep); -} - -/** - * fc_fcp_init() - Initialize the FCP layer for a local port - * @lport: The local port to initialize the exchange layer for - */ -int fc_fcp_init(struct fc_lport *lport) -{ - int rc; - struct fc_fcp_internal *si; - - if (!lport->tt.fcp_cmd_send) - lport->tt.fcp_cmd_send = fc_fcp_cmd_send; - - if (!lport->tt.fcp_cleanup) - lport->tt.fcp_cleanup = fc_fcp_cleanup; - - if (!lport->tt.fcp_abort_io) - lport->tt.fcp_abort_io = fc_fcp_abort_io; - - si = kzalloc(sizeof(struct fc_fcp_internal), GFP_KERNEL); - if (!si) - return -ENOMEM; - lport->scsi_priv = si; - si->max_can_queue = lport->host->can_queue; - INIT_LIST_HEAD(&si->scsi_pkt_queue); - spin_lock_init(&si->scsi_queue_lock); - - si->scsi_pkt_pool = mempool_create_slab_pool(2, scsi_pkt_cachep); - if (!si->scsi_pkt_pool) { - rc = -ENOMEM; - goto free_internal; - } - return 0; - -free_internal: - kfree(si); - return rc; -} -EXPORT_SYMBOL(fc_fcp_init); diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_frame.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_frame.c deleted file mode 100644 index 981329a1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_frame.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright(c) 2007 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -/* - * Frame allocation. - */ -#include -#include -#include -#include -#include - -#include - -/* - * Check the CRC in a frame. - */ -u32 fc_frame_crc_check(struct fc_frame *fp) -{ - u32 crc; - u32 error; - const u8 *bp; - unsigned int len; - - WARN_ON(!fc_frame_is_linear(fp)); - fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; - len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */ - bp = (const u8 *) fr_hdr(fp); - crc = ~crc32(~0, bp, len); - error = crc ^ fr_crc(fp); - return error; -} -EXPORT_SYMBOL(fc_frame_crc_check); - -/* - * Allocate a frame intended to be sent via fcoe_xmit. - * Get an sk_buff for the frame and set the length. - */ -struct fc_frame *_fc_frame_alloc(size_t len) -{ - struct fc_frame *fp; - struct sk_buff *skb; - - WARN_ON((len % sizeof(u32)) != 0); - len += sizeof(struct fc_frame_header); - skb = alloc_skb_fclone(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM + - NET_SKB_PAD, GFP_ATOMIC); - if (!skb) - return NULL; - skb_reserve(skb, NET_SKB_PAD + FC_FRAME_HEADROOM); - fp = (struct fc_frame *) skb; - fc_frame_init(fp); - skb_put(skb, len); - return fp; -} -EXPORT_SYMBOL(_fc_frame_alloc); - -struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len) -{ - struct fc_frame *fp; - size_t fill; - - fill = payload_len % 4; - if (fill != 0) - fill = 4 - fill; - fp = _fc_frame_alloc(payload_len + fill); - if (fp) { - memset((char *) fr_hdr(fp) + payload_len, 0, fill); - /* trim is OK, we just allocated it so there are no fragments */ - skb_trim(fp_skb(fp), - payload_len + sizeof(struct fc_frame_header)); - } - return fp; -} -EXPORT_SYMBOL(fc_frame_alloc_fill); diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.c deleted file mode 100644 index 8d65a51a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.c +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include "fc_libfc.h" - -MODULE_AUTHOR("Open-FCoE.org"); -MODULE_DESCRIPTION("libfc"); -MODULE_LICENSE("GPL v2"); - -unsigned int fc_debug_logging; -module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); - -DEFINE_MUTEX(fc_prov_mutex); -static LIST_HEAD(fc_local_ports); -struct blocking_notifier_head fc_lport_notifier_head = - BLOCKING_NOTIFIER_INIT(fc_lport_notifier_head); -EXPORT_SYMBOL(fc_lport_notifier_head); - -/* - * Providers which primarily send requests and PRLIs. - */ -struct fc4_prov *fc_active_prov[FC_FC4_PROV_SIZE] = { - [0] = &fc_rport_t0_prov, - [FC_TYPE_FCP] = &fc_rport_fcp_init, -}; - -/* - * Providers which receive requests. - */ -struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = { - [FC_TYPE_ELS] = &fc_lport_els_prov, -}; - -/** - * libfc_init() - Initialize libfc.ko - */ -static int __init libfc_init(void) -{ - int rc = 0; - - rc = fc_setup_fcp(); - if (rc) - return rc; - - rc = fc_setup_exch_mgr(); - if (rc) - goto destroy_pkt_cache; - - rc = fc_setup_rport(); - if (rc) - goto destroy_em; - - return rc; -destroy_em: - fc_destroy_exch_mgr(); -destroy_pkt_cache: - fc_destroy_fcp(); - return rc; -} -module_init(libfc_init); - -/** - * libfc_exit() - Tear down libfc.ko - */ -static void __exit libfc_exit(void) -{ - fc_destroy_fcp(); - fc_destroy_exch_mgr(); - fc_destroy_rport(); -} -module_exit(libfc_exit); - -/** - * fc_copy_buffer_to_sglist() - This routine copies the data of a buffer - * into a scatter-gather list (SG list). - * - * @buf: pointer to the data buffer. - * @len: the byte-length of the data buffer. - * @sg: pointer to the pointer of the SG list. - * @nents: pointer to the remaining number of entries in the SG list. - * @offset: pointer to the current offset in the SG list. - * @crc: pointer to the 32-bit crc value. - * If crc is NULL, CRC is not calculated. - */ -u32 fc_copy_buffer_to_sglist(void *buf, size_t len, - struct scatterlist *sg, - u32 *nents, size_t *offset, - u32 *crc) -{ - size_t remaining = len; - u32 copy_len = 0; - - while (remaining > 0 && sg) { - size_t off, sg_bytes; - void *page_addr; - - if (*offset >= sg->length) { - /* - * Check for end and drop resources - * from the last iteration. - */ - if (!(*nents)) - break; - --(*nents); - *offset -= sg->length; - sg = sg_next(sg); - continue; - } - sg_bytes = min(remaining, sg->length - *offset); - - /* - * The scatterlist item may be bigger than PAGE_SIZE, - * but we are limited to mapping PAGE_SIZE at a time. - */ - off = *offset + sg->offset; - sg_bytes = min(sg_bytes, - (size_t)(PAGE_SIZE - (off & ~PAGE_MASK))); - page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT)); - if (crc) - *crc = crc32(*crc, buf, sg_bytes); - memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes); - kunmap_atomic(page_addr); - buf += sg_bytes; - *offset += sg_bytes; - remaining -= sg_bytes; - copy_len += sg_bytes; - } - return copy_len; -} - -/** - * fc_fill_hdr() - fill FC header fields based on request - * @fp: reply frame containing header to be filled in - * @in_fp: request frame containing header to use in filling in reply - * @r_ctl: R_CTL value for header - * @f_ctl: F_CTL value for header, with 0 pad - * @seq_cnt: sequence count for the header, ignored if frame has a sequence - * @parm_offset: parameter / offset value - */ -void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, - enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset) -{ - struct fc_frame_header *fh; - struct fc_frame_header *in_fh; - struct fc_seq *sp; - u32 fill; - - fh = __fc_frame_header_get(fp); - in_fh = __fc_frame_header_get(in_fp); - - if (f_ctl & FC_FC_END_SEQ) { - fill = -fr_len(fp) & 3; - if (fill) { - /* TODO, this may be a problem with fragmented skb */ - memset(skb_put(fp_skb(fp), fill), 0, fill); - f_ctl |= fill; - } - fr_eof(fp) = FC_EOF_T; - } else { - WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */ - fr_eof(fp) = FC_EOF_N; - } - - fh->fh_r_ctl = r_ctl; - memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id)); - memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id)); - fh->fh_type = in_fh->fh_type; - hton24(fh->fh_f_ctl, f_ctl); - fh->fh_ox_id = in_fh->fh_ox_id; - fh->fh_rx_id = in_fh->fh_rx_id; - fh->fh_cs_ctl = 0; - fh->fh_df_ctl = 0; - fh->fh_parm_offset = htonl(parm_offset); - - sp = fr_seq(in_fp); - if (sp) { - fr_seq(fp) = sp; - fh->fh_seq_id = sp->id; - seq_cnt = sp->cnt; - } else { - fh->fh_seq_id = 0; - } - fh->fh_seq_cnt = ntohs(seq_cnt); - fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3; - fr_encaps(fp) = fr_encaps(in_fp); -} -EXPORT_SYMBOL(fc_fill_hdr); - -/** - * fc_fill_reply_hdr() - fill FC reply header fields based on request - * @fp: reply frame containing header to be filled in - * @in_fp: request frame containing header to use in filling in reply - * @r_ctl: R_CTL value for reply - * @parm_offset: parameter / offset value - */ -void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, - enum fc_rctl r_ctl, u32 parm_offset) -{ - struct fc_seq *sp; - - sp = fr_seq(in_fp); - if (sp) - fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp); - fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset); -} -EXPORT_SYMBOL(fc_fill_reply_hdr); - -/** - * fc_fc4_conf_lport_params() - Modify "service_params" of specified lport - * if there is service provider (target provider) registered with libfc - * for specified "fc_ft_type" - * @lport: Local port which service_params needs to be modified - * @type: FC-4 type, such as FC_TYPE_FCP - */ -void fc_fc4_conf_lport_params(struct fc_lport *lport, enum fc_fh_type type) -{ - struct fc4_prov *prov_entry; - BUG_ON(type >= FC_FC4_PROV_SIZE); - BUG_ON(!lport); - prov_entry = fc_passive_prov[type]; - if (type == FC_TYPE_FCP) { - if (prov_entry && prov_entry->recv) - lport->service_params |= FCP_SPPF_TARG_FCN; - } -} - -void fc_lport_iterate(void (*notify)(struct fc_lport *, void *), void *arg) -{ - struct fc_lport *lport; - - mutex_lock(&fc_prov_mutex); - list_for_each_entry(lport, &fc_local_ports, lport_list) - notify(lport, arg); - mutex_unlock(&fc_prov_mutex); -} -EXPORT_SYMBOL(fc_lport_iterate); - -/** - * fc_fc4_register_provider() - register FC-4 upper-level provider. - * @type: FC-4 type, such as FC_TYPE_FCP - * @prov: structure describing provider including ops vector. - * - * Returns 0 on success, negative error otherwise. - */ -int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *prov) -{ - struct fc4_prov **prov_entry; - int ret = 0; - - if (type >= FC_FC4_PROV_SIZE) - return -EINVAL; - mutex_lock(&fc_prov_mutex); - prov_entry = (prov->recv ? fc_passive_prov : fc_active_prov) + type; - if (*prov_entry) - ret = -EBUSY; - else - *prov_entry = prov; - mutex_unlock(&fc_prov_mutex); - return ret; -} -EXPORT_SYMBOL(fc_fc4_register_provider); - -/** - * fc_fc4_deregister_provider() - deregister FC-4 upper-level provider. - * @type: FC-4 type, such as FC_TYPE_FCP - * @prov: structure describing provider including ops vector. - */ -void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov) -{ - BUG_ON(type >= FC_FC4_PROV_SIZE); - mutex_lock(&fc_prov_mutex); - if (prov->recv) - rcu_assign_pointer(fc_passive_prov[type], NULL); - else - rcu_assign_pointer(fc_active_prov[type], NULL); - mutex_unlock(&fc_prov_mutex); - synchronize_rcu(); -} -EXPORT_SYMBOL(fc_fc4_deregister_provider); - -/** - * fc_fc4_add_lport() - add new local port to list and run notifiers. - * @lport: The new local port. - */ -void fc_fc4_add_lport(struct fc_lport *lport) -{ - mutex_lock(&fc_prov_mutex); - list_add_tail(&lport->lport_list, &fc_local_ports); - blocking_notifier_call_chain(&fc_lport_notifier_head, - FC_LPORT_EV_ADD, lport); - mutex_unlock(&fc_prov_mutex); -} - -/** - * fc_fc4_del_lport() - remove local port from list and run notifiers. - * @lport: The new local port. - */ -void fc_fc4_del_lport(struct fc_lport *lport) -{ - mutex_lock(&fc_prov_mutex); - list_del(&lport->lport_list); - blocking_notifier_call_chain(&fc_lport_notifier_head, - FC_LPORT_EV_DEL, lport); - mutex_unlock(&fc_prov_mutex); -} diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.h b/ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.h deleted file mode 100644 index c2830cc6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_libfc.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#ifndef _FC_LIBFC_H_ -#define _FC_LIBFC_H_ - -#define FC_LIBFC_LOGGING 0x01 /* General logging, not categorized */ -#define FC_LPORT_LOGGING 0x02 /* lport layer logging */ -#define FC_DISC_LOGGING 0x04 /* discovery layer logging */ -#define FC_RPORT_LOGGING 0x08 /* rport layer logging */ -#define FC_FCP_LOGGING 0x10 /* I/O path logging */ -#define FC_EM_LOGGING 0x20 /* Exchange Manager logging */ -#define FC_EXCH_LOGGING 0x40 /* Exchange/Sequence logging */ -#define FC_SCSI_LOGGING 0x80 /* SCSI logging (mostly error handling) */ - -extern unsigned int fc_debug_logging; - -#define FC_CHECK_LOGGING(LEVEL, CMD) \ - do { \ - if (unlikely(fc_debug_logging & LEVEL)) \ - do { \ - CMD; \ - } while (0); \ - } while (0) - -#define FC_LIBFC_DBG(fmt, args...) \ - FC_CHECK_LOGGING(FC_LIBFC_LOGGING, \ - printk(KERN_INFO "libfc: " fmt, ##args)) - -#define FC_LPORT_DBG(lport, fmt, args...) \ - FC_CHECK_LOGGING(FC_LPORT_LOGGING, \ - printk(KERN_INFO "host%u: lport %6.6x: " fmt, \ - (lport)->host->host_no, \ - (lport)->port_id, ##args)) - -#define FC_DISC_DBG(disc, fmt, args...) \ - FC_CHECK_LOGGING(FC_DISC_LOGGING, \ - printk(KERN_INFO "host%u: disc: " fmt, \ - fc_disc_lport(disc)->host->host_no, \ - ##args)) - -#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \ - FC_CHECK_LOGGING(FC_RPORT_LOGGING, \ - printk(KERN_INFO "host%u: rport %6.6x: " fmt, \ - (lport)->host->host_no, \ - (port_id), ##args)) - -#define FC_RPORT_DBG(rdata, fmt, args...) \ - FC_RPORT_ID_DBG((rdata)->local_port, (rdata)->ids.port_id, fmt, ##args) - -#define FC_FCP_DBG(pkt, fmt, args...) \ - FC_CHECK_LOGGING(FC_FCP_LOGGING, \ - { \ - if ((pkt)->seq_ptr) { \ - struct fc_exch *_ep = NULL; \ - _ep = fc_seq_exch((pkt)->seq_ptr); \ - printk(KERN_INFO "host%u: fcp: %6.6x: " \ - "xid %04x-%04x: " fmt, \ - (pkt)->lp->host->host_no, \ - (pkt)->rport->port_id, \ - (_ep)->oxid, (_ep)->rxid, ##args); \ - } else { \ - printk(KERN_INFO "host%u: fcp: %6.6x: " fmt, \ - (pkt)->lp->host->host_no, \ - (pkt)->rport->port_id, ##args); \ - } \ - }) - -#define FC_EXCH_DBG(exch, fmt, args...) \ - FC_CHECK_LOGGING(FC_EXCH_LOGGING, \ - printk(KERN_INFO "host%u: xid %4x: " fmt, \ - (exch)->lp->host->host_no, \ - exch->xid, ##args)) - -#define FC_SCSI_DBG(lport, fmt, args...) \ - FC_CHECK_LOGGING(FC_SCSI_LOGGING, \ - printk(KERN_INFO "host%u: scsi: " fmt, \ - (lport)->host->host_no, ##args)) - -/* - * FC-4 Providers. - */ -extern struct fc4_prov *fc_active_prov[]; /* providers without recv */ -extern struct fc4_prov *fc_passive_prov[]; /* providers with recv */ -extern struct mutex fc_prov_mutex; /* lock over table changes */ - -extern struct fc4_prov fc_rport_t0_prov; /* type 0 provider */ -extern struct fc4_prov fc_lport_els_prov; /* ELS provider */ -extern struct fc4_prov fc_rport_fcp_init; /* FCP initiator provider */ - -/* - * Set up direct-data placement for this I/O request - */ -void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid); -void fc_fcp_ddp_done(struct fc_fcp_pkt *fsp); - -/* - * Module setup functions - */ -int fc_setup_exch_mgr(void); -void fc_destroy_exch_mgr(void); -int fc_setup_rport(void); -void fc_destroy_rport(void); -int fc_setup_fcp(void); -void fc_destroy_fcp(void); - -/* - * Internal libfc functions - */ -const char *fc_els_resp_type(struct fc_frame *); -extern void fc_fc4_add_lport(struct fc_lport *); -extern void fc_fc4_del_lport(struct fc_lport *); -extern void fc_fc4_conf_lport_params(struct fc_lport *, enum fc_fh_type); - -/* - * Copies a buffer into an sg list - */ -u32 fc_copy_buffer_to_sglist(void *buf, size_t len, - struct scatterlist *sg, - u32 *nents, size_t *offset, - u32 *crc); - -#endif /* _FC_LIBFC_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_lport.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_lport.c deleted file mode 100644 index cc83b66d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_lport.c +++ /dev/null @@ -1,2135 +0,0 @@ -/* - * Copyright(c) 2007 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -/* - * PORT LOCKING NOTES - * - * These comments only apply to the 'port code' which consists of the lport, - * disc and rport blocks. - * - * MOTIVATION - * - * The lport, disc and rport blocks all have mutexes that are used to protect - * those objects. The main motivation for these locks is to prevent from - * having an lport reset just before we send a frame. In that scenario the - * lport's FID would get set to zero and then we'd send a frame with an - * invalid SID. We also need to ensure that states don't change unexpectedly - * while processing another state. - * - * HIERARCHY - * - * The following hierarchy defines the locking rules. A greater lock - * may be held before acquiring a lesser lock, but a lesser lock should never - * be held while attempting to acquire a greater lock. Here is the hierarchy- - * - * lport > disc, lport > rport, disc > rport - * - * CALLBACKS - * - * The callbacks cause complications with this scheme. There is a callback - * from the rport (to either lport or disc) and a callback from disc - * (to the lport). - * - * As rports exit the rport state machine a callback is made to the owner of - * the rport to notify success or failure. Since the callback is likely to - * cause the lport or disc to grab its lock we cannot hold the rport lock - * while making the callback. To ensure that the rport is not free'd while - * processing the callback the rport callbacks are serialized through a - * single-threaded workqueue. An rport would never be free'd while in a - * callback handler because no other rport work in this queue can be executed - * at the same time. - * - * When discovery succeeds or fails a callback is made to the lport as - * notification. Currently, successful discovery causes the lport to take no - * action. A failure will cause the lport to reset. There is likely a circular - * locking problem with this implementation. - */ - -/* - * LPORT LOCKING - * - * The critical sections protected by the lport's mutex are quite broad and - * may be improved upon in the future. The lport code and its locking doesn't - * influence the I/O path, so excessive locking doesn't penalize I/O - * performance. - * - * The strategy is to lock whenever processing a request or response. Note - * that every _enter_* function corresponds to a state change. They generally - * change the lports state and then send a request out on the wire. We lock - * before calling any of these functions to protect that state change. This - * means that the entry points into the lport block manage the locks while - * the state machine can transition between states (i.e. _enter_* functions) - * while always staying protected. - * - * When handling responses we also hold the lport mutex broadly. When the - * lport receives the response frame it locks the mutex and then calls the - * appropriate handler for the particuar response. Generally a response will - * trigger a state change and so the lock must already be held. - * - * Retries also have to consider the locking. The retries occur from a work - * context and the work function will lock the lport and then retry the state - * (i.e. _enter_* function). - */ - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include "fc_libfc.h" - -/* Fabric IDs to use for point-to-point mode, chosen on whims. */ -#define FC_LOCAL_PTP_FID_LO 0x010101 -#define FC_LOCAL_PTP_FID_HI 0x010102 - -#define DNS_DELAY 3 /* Discovery delay after RSCN (in seconds)*/ - -static void fc_lport_error(struct fc_lport *, struct fc_frame *); - -static void fc_lport_enter_reset(struct fc_lport *); -static void fc_lport_enter_flogi(struct fc_lport *); -static void fc_lport_enter_dns(struct fc_lport *); -static void fc_lport_enter_ns(struct fc_lport *, enum fc_lport_state); -static void fc_lport_enter_scr(struct fc_lport *); -static void fc_lport_enter_ready(struct fc_lport *); -static void fc_lport_enter_logo(struct fc_lport *); -static void fc_lport_enter_fdmi(struct fc_lport *lport); -static void fc_lport_enter_ms(struct fc_lport *, enum fc_lport_state); - -static const char *fc_lport_state_names[] = { - [LPORT_ST_DISABLED] = "disabled", - [LPORT_ST_FLOGI] = "FLOGI", - [LPORT_ST_DNS] = "dNS", - [LPORT_ST_RNN_ID] = "RNN_ID", - [LPORT_ST_RSNN_NN] = "RSNN_NN", - [LPORT_ST_RSPN_ID] = "RSPN_ID", - [LPORT_ST_RFT_ID] = "RFT_ID", - [LPORT_ST_RFF_ID] = "RFF_ID", - [LPORT_ST_FDMI] = "FDMI", - [LPORT_ST_RHBA] = "RHBA", - [LPORT_ST_RPA] = "RPA", - [LPORT_ST_DHBA] = "DHBA", - [LPORT_ST_DPRT] = "DPRT", - [LPORT_ST_SCR] = "SCR", - [LPORT_ST_READY] = "Ready", - [LPORT_ST_LOGO] = "LOGO", - [LPORT_ST_RESET] = "reset", -}; - -/** - * struct fc_bsg_info - FC Passthrough managemet structure - * @job: The passthrough job - * @lport: The local port to pass through a command - * @rsp_code: The expected response code - * @sg: job->reply_payload.sg_list - * @nents: job->reply_payload.sg_cnt - * @offset: The offset into the response data - */ -struct fc_bsg_info { - struct fc_bsg_job *job; - struct fc_lport *lport; - u16 rsp_code; - struct scatterlist *sg; - u32 nents; - size_t offset; -}; - -/** - * fc_frame_drop() - Dummy frame handler - * @lport: The local port the frame was received on - * @fp: The received frame - */ -static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp) -{ - fc_frame_free(fp); - return 0; -} - -/** - * fc_lport_rport_callback() - Event handler for rport events - * @lport: The lport which is receiving the event - * @rdata: private remote port data - * @event: The event that occurred - * - * Locking Note: The rport lock should not be held when calling - * this function. - */ -static void fc_lport_rport_callback(struct fc_lport *lport, - struct fc_rport_priv *rdata, - enum fc_rport_event event) -{ - FC_LPORT_DBG(lport, "Received a %d event for port (%6.6x)\n", event, - rdata->ids.port_id); - - mutex_lock(&lport->lp_mutex); - switch (event) { - case RPORT_EV_READY: - if (lport->state == LPORT_ST_DNS) { - lport->dns_rdata = rdata; - fc_lport_enter_ns(lport, LPORT_ST_RNN_ID); - } else if (lport->state == LPORT_ST_FDMI) { - lport->ms_rdata = rdata; - fc_lport_enter_ms(lport, LPORT_ST_DHBA); - } else { - FC_LPORT_DBG(lport, "Received an READY event " - "on port (%6.6x) for the directory " - "server, but the lport is not " - "in the DNS or FDMI state, it's in the " - "%d state", rdata->ids.port_id, - lport->state); - lport->tt.rport_logoff(rdata); - } - break; - case RPORT_EV_LOGO: - case RPORT_EV_FAILED: - case RPORT_EV_STOP: - if (rdata->ids.port_id == FC_FID_DIR_SERV) - lport->dns_rdata = NULL; - else if (rdata->ids.port_id == FC_FID_MGMT_SERV) - lport->ms_rdata = NULL; - break; - case RPORT_EV_NONE: - break; - } - mutex_unlock(&lport->lp_mutex); -} - -/** - * fc_lport_state() - Return a string which represents the lport's state - * @lport: The lport whose state is to converted to a string - */ -static const char *fc_lport_state(struct fc_lport *lport) -{ - const char *cp; - - cp = fc_lport_state_names[lport->state]; - if (!cp) - cp = "unknown"; - return cp; -} - -/** - * fc_lport_ptp_setup() - Create an rport for point-to-point mode - * @lport: The lport to attach the ptp rport to - * @remote_fid: The FID of the ptp rport - * @remote_wwpn: The WWPN of the ptp rport - * @remote_wwnn: The WWNN of the ptp rport - */ -static void fc_lport_ptp_setup(struct fc_lport *lport, - u32 remote_fid, u64 remote_wwpn, - u64 remote_wwnn) -{ - mutex_lock(&lport->disc.disc_mutex); - if (lport->ptp_rdata) { - lport->tt.rport_logoff(lport->ptp_rdata); - kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy); - } - lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid); - kref_get(&lport->ptp_rdata->kref); - lport->ptp_rdata->ids.port_name = remote_wwpn; - lport->ptp_rdata->ids.node_name = remote_wwnn; - mutex_unlock(&lport->disc.disc_mutex); - - lport->tt.rport_login(lport->ptp_rdata); - - fc_lport_enter_ready(lport); -} - -/** - * fc_get_host_port_state() - Return the port state of the given Scsi_Host - * @shost: The SCSI host whose port state is to be determined - */ -void fc_get_host_port_state(struct Scsi_Host *shost) -{ - struct fc_lport *lport = shost_priv(shost); - - mutex_lock(&lport->lp_mutex); - if (!lport->link_up) - fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; - else - switch (lport->state) { - case LPORT_ST_READY: - fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; - break; - default: - fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; - } - mutex_unlock(&lport->lp_mutex); -} -EXPORT_SYMBOL(fc_get_host_port_state); - -/** - * fc_get_host_speed() - Return the speed of the given Scsi_Host - * @shost: The SCSI host whose port speed is to be determined - */ -void fc_get_host_speed(struct Scsi_Host *shost) -{ - struct fc_lport *lport = shost_priv(shost); - - fc_host_speed(shost) = lport->link_speed; -} -EXPORT_SYMBOL(fc_get_host_speed); - -/** - * fc_get_host_stats() - Return the Scsi_Host's statistics - * @shost: The SCSI host whose statistics are to be returned - */ -struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) -{ - struct fc_host_statistics *fcoe_stats; - struct fc_lport *lport = shost_priv(shost); - struct timespec v0, v1; - unsigned int cpu; - u64 fcp_in_bytes = 0; - u64 fcp_out_bytes = 0; - - fcoe_stats = &lport->host_stats; - memset(fcoe_stats, 0, sizeof(struct fc_host_statistics)); - - jiffies_to_timespec(jiffies, &v0); - jiffies_to_timespec(lport->boot_time, &v1); - fcoe_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); - - for_each_possible_cpu(cpu) { - struct fcoe_dev_stats *stats; - - stats = per_cpu_ptr(lport->dev_stats, cpu); - - fcoe_stats->tx_frames += stats->TxFrames; - fcoe_stats->tx_words += stats->TxWords; - fcoe_stats->rx_frames += stats->RxFrames; - fcoe_stats->rx_words += stats->RxWords; - fcoe_stats->error_frames += stats->ErrorFrames; - fcoe_stats->invalid_crc_count += stats->InvalidCRCCount; - fcoe_stats->fcp_input_requests += stats->InputRequests; - fcoe_stats->fcp_output_requests += stats->OutputRequests; - fcoe_stats->fcp_control_requests += stats->ControlRequests; - fcp_in_bytes += stats->InputBytes; - fcp_out_bytes += stats->OutputBytes; - fcoe_stats->link_failure_count += stats->LinkFailureCount; - } - fcoe_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000); - fcoe_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000); - fcoe_stats->lip_count = -1; - fcoe_stats->nos_count = -1; - fcoe_stats->loss_of_sync_count = -1; - fcoe_stats->loss_of_signal_count = -1; - fcoe_stats->prim_seq_protocol_err_count = -1; - fcoe_stats->dumped_frames = -1; - return fcoe_stats; -} -EXPORT_SYMBOL(fc_get_host_stats); - -/** - * fc_lport_flogi_fill() - Fill in FLOGI command for request - * @lport: The local port the FLOGI is for - * @flogi: The FLOGI command - * @op: The opcode - */ -static void fc_lport_flogi_fill(struct fc_lport *lport, - struct fc_els_flogi *flogi, - unsigned int op) -{ - struct fc_els_csp *sp; - struct fc_els_cssp *cp; - - memset(flogi, 0, sizeof(*flogi)); - flogi->fl_cmd = (u8) op; - put_unaligned_be64(lport->wwpn, &flogi->fl_wwpn); - put_unaligned_be64(lport->wwnn, &flogi->fl_wwnn); - sp = &flogi->fl_csp; - sp->sp_hi_ver = 0x20; - sp->sp_lo_ver = 0x20; - sp->sp_bb_cred = htons(10); /* this gets set by gateway */ - sp->sp_bb_data = htons((u16) lport->mfs); - cp = &flogi->fl_cssp[3 - 1]; /* class 3 parameters */ - cp->cp_class = htons(FC_CPC_VALID | FC_CPC_SEQ); - if (op != ELS_FLOGI) { - sp->sp_features = htons(FC_SP_FT_CIRO); - sp->sp_tot_seq = htons(255); /* seq. we accept */ - sp->sp_rel_off = htons(0x1f); - sp->sp_e_d_tov = htonl(lport->e_d_tov); - - cp->cp_rdfs = htons((u16) lport->mfs); - cp->cp_con_seq = htons(255); - cp->cp_open_seq = 1; - } -} - -/** - * fc_lport_add_fc4_type() - Add a supported FC-4 type to a local port - * @lport: The local port to add a new FC-4 type to - * @type: The new FC-4 type - */ -static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) -{ - __be32 *mp; - - mp = &lport->fcts.ff_type_map[type / FC_NS_BPW]; - *mp = htonl(ntohl(*mp) | 1UL << (type % FC_NS_BPW)); -} - -/** - * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. - * @lport: Fibre Channel local port receiving the RLIR - * @fp: The RLIR request frame - * - * Locking Note: The lport lock is expected to be held before calling - * this function. - */ -static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp) -{ - FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", - fc_lport_state(lport)); - - lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); - fc_frame_free(fp); -} - -/** - * fc_lport_recv_echo_req() - Handle received ECHO request - * @lport: The local port receiving the ECHO - * @fp: ECHO request frame - * - * Locking Note: The lport lock is expected to be held before calling - * this function. - */ -static void fc_lport_recv_echo_req(struct fc_lport *lport, - struct fc_frame *in_fp) -{ - struct fc_frame *fp; - unsigned int len; - void *pp; - void *dp; - - FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n", - fc_lport_state(lport)); - - len = fr_len(in_fp) - sizeof(struct fc_frame_header); - pp = fc_frame_payload_get(in_fp, len); - - if (len < sizeof(__be32)) - len = sizeof(__be32); - - fp = fc_frame_alloc(lport, len); - if (fp) { - dp = fc_frame_payload_get(fp, len); - memcpy(dp, pp, len); - *((__be32 *)dp) = htonl(ELS_LS_ACC << 24); - fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); - } - fc_frame_free(in_fp); -} - -/** - * fc_lport_recv_rnid_req() - Handle received Request Node ID data request - * @lport: The local port receiving the RNID - * @fp: The RNID request frame - * - * Locking Note: The lport lock is expected to be held before calling - * this function. - */ -static void fc_lport_recv_rnid_req(struct fc_lport *lport, - struct fc_frame *in_fp) -{ - struct fc_frame *fp; - struct fc_els_rnid *req; - struct { - struct fc_els_rnid_resp rnid; - struct fc_els_rnid_cid cid; - struct fc_els_rnid_gen gen; - } *rp; - struct fc_seq_els_data rjt_data; - u8 fmt; - size_t len; - - FC_LPORT_DBG(lport, "Received RNID request while in state %s\n", - fc_lport_state(lport)); - - req = fc_frame_payload_get(in_fp, sizeof(*req)); - if (!req) { - rjt_data.reason = ELS_RJT_LOGIC; - rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); - } else { - fmt = req->rnid_fmt; - len = sizeof(*rp); - if (fmt != ELS_RNIDF_GEN || - ntohl(lport->rnid_gen.rnid_atype) == 0) { - fmt = ELS_RNIDF_NONE; /* nothing to provide */ - len -= sizeof(rp->gen); - } - fp = fc_frame_alloc(lport, len); - if (fp) { - rp = fc_frame_payload_get(fp, len); - memset(rp, 0, len); - rp->rnid.rnid_cmd = ELS_LS_ACC; - rp->rnid.rnid_fmt = fmt; - rp->rnid.rnid_cid_len = sizeof(rp->cid); - rp->cid.rnid_wwpn = htonll(lport->wwpn); - rp->cid.rnid_wwnn = htonll(lport->wwnn); - if (fmt == ELS_RNIDF_GEN) { - rp->rnid.rnid_sid_len = sizeof(rp->gen); - memcpy(&rp->gen, &lport->rnid_gen, - sizeof(rp->gen)); - } - fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); - } - } - fc_frame_free(in_fp); -} - -/** - * fc_lport_recv_logo_req() - Handle received fabric LOGO request - * @lport: The local port receiving the LOGO - * @fp: The LOGO request frame - * - * Locking Note: The lport lock is exected to be held before calling - * this function. - */ -static void fc_lport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) -{ - lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); - fc_lport_enter_reset(lport); - fc_frame_free(fp); -} - -/** - * fc_fabric_login() - Start the lport state machine - * @lport: The local port that should log into the fabric - * - * Locking Note: This function should not be called - * with the lport lock held. - */ -int fc_fabric_login(struct fc_lport *lport) -{ - int rc = -1; - - mutex_lock(&lport->lp_mutex); - if (lport->state == LPORT_ST_DISABLED || - lport->state == LPORT_ST_LOGO) { - fc_lport_state_enter(lport, LPORT_ST_RESET); - fc_lport_enter_reset(lport); - rc = 0; - } - mutex_unlock(&lport->lp_mutex); - - return rc; -} -EXPORT_SYMBOL(fc_fabric_login); - -/** - * __fc_linkup() - Handler for transport linkup events - * @lport: The lport whose link is up - * - * Locking: must be called with the lp_mutex held - */ -void __fc_linkup(struct fc_lport *lport) -{ - if (!lport->link_up) { - lport->link_up = 1; - - if (lport->state == LPORT_ST_RESET) - fc_lport_enter_flogi(lport); - } -} - -/** - * fc_linkup() - Handler for transport linkup events - * @lport: The local port whose link is up - */ -void fc_linkup(struct fc_lport *lport) -{ - printk(KERN_INFO "host%d: libfc: Link up on port (%6.6x)\n", - lport->host->host_no, lport->port_id); - - mutex_lock(&lport->lp_mutex); - __fc_linkup(lport); - mutex_unlock(&lport->lp_mutex); -} -EXPORT_SYMBOL(fc_linkup); - -/** - * __fc_linkdown() - Handler for transport linkdown events - * @lport: The lport whose link is down - * - * Locking: must be called with the lp_mutex held - */ -void __fc_linkdown(struct fc_lport *lport) -{ - if (lport->link_up) { - lport->link_up = 0; - fc_lport_enter_reset(lport); - lport->tt.fcp_cleanup(lport); - } -} - -/** - * fc_linkdown() - Handler for transport linkdown events - * @lport: The local port whose link is down - */ -void fc_linkdown(struct fc_lport *lport) -{ - printk(KERN_INFO "host%d: libfc: Link down on port (%6.6x)\n", - lport->host->host_no, lport->port_id); - - mutex_lock(&lport->lp_mutex); - __fc_linkdown(lport); - mutex_unlock(&lport->lp_mutex); -} -EXPORT_SYMBOL(fc_linkdown); - -/** - * fc_fabric_logoff() - Logout of the fabric - * @lport: The local port to logoff the fabric - * - * Return value: - * 0 for success, -1 for failure - */ -int fc_fabric_logoff(struct fc_lport *lport) -{ - lport->tt.disc_stop_final(lport); - mutex_lock(&lport->lp_mutex); - if (lport->dns_rdata) - lport->tt.rport_logoff(lport->dns_rdata); - mutex_unlock(&lport->lp_mutex); - lport->tt.rport_flush_queue(); - mutex_lock(&lport->lp_mutex); - fc_lport_enter_logo(lport); - mutex_unlock(&lport->lp_mutex); - cancel_delayed_work_sync(&lport->retry_work); - return 0; -} -EXPORT_SYMBOL(fc_fabric_logoff); - -/** - * fc_lport_destroy() - Unregister a fc_lport - * @lport: The local port to unregister - * - * Note: - * exit routine for fc_lport instance - * clean-up all the allocated memory - * and free up other system resources. - * - */ -int fc_lport_destroy(struct fc_lport *lport) -{ - mutex_lock(&lport->lp_mutex); - lport->state = LPORT_ST_DISABLED; - lport->link_up = 0; - lport->tt.frame_send = fc_frame_drop; - mutex_unlock(&lport->lp_mutex); - - lport->tt.fcp_abort_io(lport); - lport->tt.disc_stop_final(lport); - lport->tt.exch_mgr_reset(lport, 0, 0); - fc_fc4_del_lport(lport); - return 0; -} -EXPORT_SYMBOL(fc_lport_destroy); - -/** - * fc_set_mfs() - Set the maximum frame size for a local port - * @lport: The local port to set the MFS for - * @mfs: The new MFS - */ -int fc_set_mfs(struct fc_lport *lport, u32 mfs) -{ - unsigned int old_mfs; - int rc = -EINVAL; - - mutex_lock(&lport->lp_mutex); - - old_mfs = lport->mfs; - - if (mfs >= FC_MIN_MAX_FRAME) { - mfs &= ~3; - if (mfs > FC_MAX_FRAME) - mfs = FC_MAX_FRAME; - mfs -= sizeof(struct fc_frame_header); - lport->mfs = mfs; - rc = 0; - } - - if (!rc && mfs < old_mfs) - fc_lport_enter_reset(lport); - - mutex_unlock(&lport->lp_mutex); - - return rc; -} -EXPORT_SYMBOL(fc_set_mfs); - -/** - * fc_lport_disc_callback() - Callback for discovery events - * @lport: The local port receiving the event - * @event: The discovery event - */ -static void fc_lport_disc_callback(struct fc_lport *lport, - enum fc_disc_event event) -{ - switch (event) { - case DISC_EV_SUCCESS: - FC_LPORT_DBG(lport, "Discovery succeeded\n"); - break; - case DISC_EV_FAILED: - printk(KERN_ERR "host%d: libfc: " - "Discovery failed for port (%6.6x)\n", - lport->host->host_no, lport->port_id); - mutex_lock(&lport->lp_mutex); - fc_lport_enter_reset(lport); - mutex_unlock(&lport->lp_mutex); - break; - case DISC_EV_NONE: - WARN_ON(1); - break; - } -} - -/** - * fc_rport_enter_ready() - Enter the ready state and start discovery - * @lport: The local port that is ready - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_ready(struct fc_lport *lport) -{ - FC_LPORT_DBG(lport, "Entered READY from state %s\n", - fc_lport_state(lport)); - - fc_lport_state_enter(lport, LPORT_ST_READY); - if (lport->vport) - fc_vport_set_state(lport->vport, FC_VPORT_ACTIVE); - fc_vports_linkchange(lport); - - if (!lport->ptp_rdata) - lport->tt.disc_start(fc_lport_disc_callback, lport); -} - -/** - * fc_lport_set_port_id() - set the local port Port ID - * @lport: The local port which will have its Port ID set. - * @port_id: The new port ID. - * @fp: The frame containing the incoming request, or NULL. - * - * Locking Note: The lport lock is expected to be held before calling - * this function. - */ -static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id, - struct fc_frame *fp) -{ - if (port_id) - printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n", - lport->host->host_no, port_id); - - lport->port_id = port_id; - - /* Update the fc_host */ - fc_host_port_id(lport->host) = port_id; - - if (lport->tt.lport_set_port_id) - lport->tt.lport_set_port_id(lport, port_id, fp); -} - -/** - * fc_lport_set_port_id() - set the local port Port ID for point-to-multipoint - * @lport: The local port which will have its Port ID set. - * @port_id: The new port ID. - * - * Called by the lower-level driver when transport sets the local port_id. - * This is used in VN_port to VN_port mode for FCoE, and causes FLOGI and - * discovery to be skipped. - */ -void fc_lport_set_local_id(struct fc_lport *lport, u32 port_id) -{ - mutex_lock(&lport->lp_mutex); - - fc_lport_set_port_id(lport, port_id, NULL); - - switch (lport->state) { - case LPORT_ST_RESET: - case LPORT_ST_FLOGI: - if (port_id) - fc_lport_enter_ready(lport); - break; - default: - break; - } - mutex_unlock(&lport->lp_mutex); -} -EXPORT_SYMBOL(fc_lport_set_local_id); - -/** - * fc_lport_recv_flogi_req() - Receive a FLOGI request - * @lport: The local port that received the request - * @rx_fp: The FLOGI frame - * - * A received FLOGI request indicates a point-to-point connection. - * Accept it with the common service parameters indicating our N port. - * Set up to do a PLOGI if we have the higher-number WWPN. - * - * Locking Note: The lport lock is expected to be held before calling - * this function. - */ -static void fc_lport_recv_flogi_req(struct fc_lport *lport, - struct fc_frame *rx_fp) -{ - struct fc_frame *fp; - struct fc_frame_header *fh; - struct fc_els_flogi *flp; - struct fc_els_flogi *new_flp; - u64 remote_wwpn; - u32 remote_fid; - u32 local_fid; - - FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", - fc_lport_state(lport)); - - remote_fid = fc_frame_sid(rx_fp); - flp = fc_frame_payload_get(rx_fp, sizeof(*flp)); - if (!flp) - goto out; - remote_wwpn = get_unaligned_be64(&flp->fl_wwpn); - if (remote_wwpn == lport->wwpn) { - printk(KERN_WARNING "host%d: libfc: Received FLOGI from port " - "with same WWPN %16.16llx\n", - lport->host->host_no, remote_wwpn); - goto out; - } - FC_LPORT_DBG(lport, "FLOGI from port WWPN %16.16llx\n", remote_wwpn); - - /* - * XXX what is the right thing to do for FIDs? - * The originator might expect our S_ID to be 0xfffffe. - * But if so, both of us could end up with the same FID. - */ - local_fid = FC_LOCAL_PTP_FID_LO; - if (remote_wwpn < lport->wwpn) { - local_fid = FC_LOCAL_PTP_FID_HI; - if (!remote_fid || remote_fid == local_fid) - remote_fid = FC_LOCAL_PTP_FID_LO; - } else if (!remote_fid) { - remote_fid = FC_LOCAL_PTP_FID_HI; - } - - fc_lport_set_port_id(lport, local_fid, rx_fp); - - fp = fc_frame_alloc(lport, sizeof(*flp)); - if (fp) { - new_flp = fc_frame_payload_get(fp, sizeof(*flp)); - fc_lport_flogi_fill(lport, new_flp, ELS_FLOGI); - new_flp->fl_cmd = (u8) ELS_LS_ACC; - - /* - * Send the response. If this fails, the originator should - * repeat the sequence. - */ - fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); - fh = fc_frame_header_get(fp); - hton24(fh->fh_s_id, local_fid); - hton24(fh->fh_d_id, remote_fid); - lport->tt.frame_send(lport, fp); - - } else { - fc_lport_error(lport, fp); - } - fc_lport_ptp_setup(lport, remote_fid, remote_wwpn, - get_unaligned_be64(&flp->fl_wwnn)); -out: - fc_frame_free(rx_fp); -} - -/** - * fc_lport_recv_els_req() - The generic lport ELS request handler - * @lport: The local port that received the request - * @fp: The request frame - * - * This function will see if the lport handles the request or - * if an rport should handle the request. - * - * Locking Note: This function should not be called with the lport - * lock held because it will grab the lock. - */ -static void fc_lport_recv_els_req(struct fc_lport *lport, - struct fc_frame *fp) -{ - void (*recv)(struct fc_lport *, struct fc_frame *); - - mutex_lock(&lport->lp_mutex); - - /* - * Handle special ELS cases like FLOGI, LOGO, and - * RSCN here. These don't require a session. - * Even if we had a session, it might not be ready. - */ - if (!lport->link_up) - fc_frame_free(fp); - else { - /* - * Check opcode. - */ - recv = lport->tt.rport_recv_req; - switch (fc_frame_payload_op(fp)) { - case ELS_FLOGI: - if (!lport->point_to_multipoint) - recv = fc_lport_recv_flogi_req; - break; - case ELS_LOGO: - if (fc_frame_sid(fp) == FC_FID_FLOGI) - recv = fc_lport_recv_logo_req; - break; - case ELS_RSCN: - recv = lport->tt.disc_recv_req; - break; - case ELS_ECHO: - recv = fc_lport_recv_echo_req; - break; - case ELS_RLIR: - recv = fc_lport_recv_rlir_req; - break; - case ELS_RNID: - recv = fc_lport_recv_rnid_req; - break; - } - - recv(lport, fp); - } - mutex_unlock(&lport->lp_mutex); -} - -static int fc_lport_els_prli(struct fc_rport_priv *rdata, u32 spp_len, - const struct fc_els_spp *spp_in, - struct fc_els_spp *spp_out) -{ - return FC_SPP_RESP_INVL; -} - -struct fc4_prov fc_lport_els_prov = { - .prli = fc_lport_els_prli, - .recv = fc_lport_recv_els_req, -}; - -/** - * fc_lport_recv_req() - The generic lport request handler - * @lport: The lport that received the request - * @fp: The frame the request is in - * - * Locking Note: This function should not be called with the lport - * lock held because it may grab the lock. - */ -static void fc_lport_recv_req(struct fc_lport *lport, - struct fc_frame *fp) -{ - struct fc_frame_header *fh = fc_frame_header_get(fp); - struct fc_seq *sp = fr_seq(fp); - struct fc4_prov *prov; - - /* - * Use RCU read lock and module_lock to be sure module doesn't - * deregister and get unloaded while we're calling it. - * try_module_get() is inlined and accepts a NULL parameter. - * Only ELSes and FCP target ops should come through here. - * The locking is unfortunate, and a better scheme is being sought. - */ - - rcu_read_lock(); - if (fh->fh_type >= FC_FC4_PROV_SIZE) - goto drop; - prov = rcu_dereference(fc_passive_prov[fh->fh_type]); - if (!prov || !try_module_get(prov->module)) - goto drop; - rcu_read_unlock(); - prov->recv(lport, fp); - module_put(prov->module); - return; -drop: - rcu_read_unlock(); - FC_LPORT_DBG(lport, "dropping unexpected frame type %x\n", fh->fh_type); - fc_frame_free(fp); - lport->tt.exch_done(sp); -} - -/** - * fc_lport_reset() - Reset a local port - * @lport: The local port which should be reset - * - * Locking Note: This functions should not be called with the - * lport lock held. - */ -int fc_lport_reset(struct fc_lport *lport) -{ - cancel_delayed_work_sync(&lport->retry_work); - mutex_lock(&lport->lp_mutex); - fc_lport_enter_reset(lport); - mutex_unlock(&lport->lp_mutex); - return 0; -} -EXPORT_SYMBOL(fc_lport_reset); - -/** - * fc_lport_reset_locked() - Reset the local port w/ the lport lock held - * @lport: The local port to be reset - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_reset_locked(struct fc_lport *lport) -{ - if (lport->dns_rdata) - lport->tt.rport_logoff(lport->dns_rdata); - - if (lport->ptp_rdata) { - lport->tt.rport_logoff(lport->ptp_rdata); - kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy); - lport->ptp_rdata = NULL; - } - - lport->tt.disc_stop(lport); - - lport->tt.exch_mgr_reset(lport, 0, 0); - fc_host_fabric_name(lport->host) = 0; - - if (lport->port_id && (!lport->point_to_multipoint || !lport->link_up)) - fc_lport_set_port_id(lport, 0, NULL); -} - -/** - * fc_lport_enter_reset() - Reset the local port - * @lport: The local port to be reset - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_reset(struct fc_lport *lport) -{ - FC_LPORT_DBG(lport, "Entered RESET state from %s state\n", - fc_lport_state(lport)); - - if (lport->state == LPORT_ST_DISABLED || lport->state == LPORT_ST_LOGO) - return; - - if (lport->vport) { - if (lport->link_up) - fc_vport_set_state(lport->vport, FC_VPORT_INITIALIZING); - else - fc_vport_set_state(lport->vport, FC_VPORT_LINKDOWN); - } - fc_lport_state_enter(lport, LPORT_ST_RESET); - fc_host_post_event(lport->host, fc_get_event_number(), - FCH_EVT_LIPRESET, 0); - fc_vports_linkchange(lport); - fc_lport_reset_locked(lport); - if (lport->link_up) - fc_lport_enter_flogi(lport); -} - -/** - * fc_lport_enter_disabled() - Disable the local port - * @lport: The local port to be reset - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_disabled(struct fc_lport *lport) -{ - FC_LPORT_DBG(lport, "Entered disabled state from %s state\n", - fc_lport_state(lport)); - - fc_lport_state_enter(lport, LPORT_ST_DISABLED); - fc_vports_linkchange(lport); - fc_lport_reset_locked(lport); -} - -/** - * fc_lport_error() - Handler for any errors - * @lport: The local port that the error was on - * @fp: The error code encoded in a frame pointer - * - * If the error was caused by a resource allocation failure - * then wait for half a second and retry, otherwise retry - * after the e_d_tov time. - */ -static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) -{ - unsigned long delay = 0; - FC_LPORT_DBG(lport, "Error %ld in state %s, retries %d\n", - PTR_ERR(fp), fc_lport_state(lport), - lport->retry_count); - - if (PTR_ERR(fp) == -FC_EX_CLOSED) - return; - - /* - * Memory allocation failure, or the exchange timed out - * or we received LS_RJT. - * Retry after delay - */ - if (lport->retry_count < lport->max_retry_count) { - lport->retry_count++; - if (!fp) - delay = msecs_to_jiffies(500); - else - delay = msecs_to_jiffies(lport->e_d_tov); - - schedule_delayed_work(&lport->retry_work, delay); - } else - fc_lport_enter_reset(lport); -} - -/** - * fc_lport_ns_resp() - Handle response to a name server - * registration exchange - * @sp: current sequence in exchange - * @fp: response frame - * @lp_arg: Fibre Channel host port instance - * - * Locking Note: This function will be called without the lport lock - * held, but it will lock, call an _enter_* function or fc_lport_error() - * and then unlock the lport. - */ -static void fc_lport_ns_resp(struct fc_seq *sp, struct fc_frame *fp, - void *lp_arg) -{ - struct fc_lport *lport = lp_arg; - struct fc_frame_header *fh; - struct fc_ct_hdr *ct; - - FC_LPORT_DBG(lport, "Received a ns %s\n", fc_els_resp_type(fp)); - - if (fp == ERR_PTR(-FC_EX_CLOSED)) - return; - - mutex_lock(&lport->lp_mutex); - - if (lport->state < LPORT_ST_RNN_ID || lport->state > LPORT_ST_RFF_ID) { - FC_LPORT_DBG(lport, "Received a name server response, " - "but in state %s\n", fc_lport_state(lport)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - - fh = fc_frame_header_get(fp); - ct = fc_frame_payload_get(fp, sizeof(*ct)); - - if (fh && ct && fh->fh_type == FC_TYPE_CT && - ct->ct_fs_type == FC_FST_DIR && - ct->ct_fs_subtype == FC_NS_SUBTYPE && - ntohs(ct->ct_cmd) == FC_FS_ACC) - switch (lport->state) { - case LPORT_ST_RNN_ID: - fc_lport_enter_ns(lport, LPORT_ST_RSNN_NN); - break; - case LPORT_ST_RSNN_NN: - fc_lport_enter_ns(lport, LPORT_ST_RSPN_ID); - break; - case LPORT_ST_RSPN_ID: - fc_lport_enter_ns(lport, LPORT_ST_RFT_ID); - break; - case LPORT_ST_RFT_ID: - fc_lport_enter_ns(lport, LPORT_ST_RFF_ID); - break; - case LPORT_ST_RFF_ID: - if (lport->fdmi_enabled) - fc_lport_enter_fdmi(lport); - else - fc_lport_enter_scr(lport); - break; - default: - /* should have already been caught by state checks */ - break; - } - else - fc_lport_error(lport, fp); -out: - fc_frame_free(fp); -err: - mutex_unlock(&lport->lp_mutex); -} - -/** - * fc_lport_ms_resp() - Handle response to a management server - * exchange - * @sp: current sequence in exchange - * @fp: response frame - * @lp_arg: Fibre Channel host port instance - * - * Locking Note: This function will be called without the lport lock - * held, but it will lock, call an _enter_* function or fc_lport_error() - * and then unlock the lport. - */ -static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp, - void *lp_arg) -{ - struct fc_lport *lport = lp_arg; - struct fc_frame_header *fh; - struct fc_ct_hdr *ct; - - FC_LPORT_DBG(lport, "Received a ms %s\n", fc_els_resp_type(fp)); - - if (fp == ERR_PTR(-FC_EX_CLOSED)) - return; - - mutex_lock(&lport->lp_mutex); - - if (lport->state < LPORT_ST_RHBA || lport->state > LPORT_ST_DPRT) { - FC_LPORT_DBG(lport, "Received a management server response, " - "but in state %s\n", fc_lport_state(lport)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - - fh = fc_frame_header_get(fp); - ct = fc_frame_payload_get(fp, sizeof(*ct)); - - if (fh && ct && fh->fh_type == FC_TYPE_CT && - ct->ct_fs_type == FC_FST_MGMT && - ct->ct_fs_subtype == FC_FDMI_SUBTYPE) { - FC_LPORT_DBG(lport, "Received a management server response, " - "reason=%d explain=%d\n", - ct->ct_reason, - ct->ct_explan); - - switch (lport->state) { - case LPORT_ST_RHBA: - if (ntohs(ct->ct_cmd) == FC_FS_ACC) - fc_lport_enter_ms(lport, LPORT_ST_RPA); - else /* Error Skip RPA */ - fc_lport_enter_scr(lport); - break; - case LPORT_ST_RPA: - fc_lport_enter_scr(lport); - break; - case LPORT_ST_DPRT: - fc_lport_enter_ms(lport, LPORT_ST_RHBA); - break; - case LPORT_ST_DHBA: - fc_lport_enter_ms(lport, LPORT_ST_DPRT); - break; - default: - /* should have already been caught by state checks */ - break; - } - } else { - /* Invalid Frame? */ - fc_lport_error(lport, fp); - } -out: - fc_frame_free(fp); -err: - mutex_unlock(&lport->lp_mutex); -} - -/** - * fc_lport_scr_resp() - Handle response to State Change Register (SCR) request - * @sp: current sequence in SCR exchange - * @fp: response frame - * @lp_arg: Fibre Channel lport port instance that sent the registration request - * - * Locking Note: This function will be called without the lport lock - * held, but it will lock, call an _enter_* function or fc_lport_error - * and then unlock the lport. - */ -static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp, - void *lp_arg) -{ - struct fc_lport *lport = lp_arg; - u8 op; - - FC_LPORT_DBG(lport, "Received a SCR %s\n", fc_els_resp_type(fp)); - - if (fp == ERR_PTR(-FC_EX_CLOSED)) - return; - - mutex_lock(&lport->lp_mutex); - - if (lport->state != LPORT_ST_SCR) { - FC_LPORT_DBG(lport, "Received a SCR response, but in state " - "%s\n", fc_lport_state(lport)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - - op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC) - fc_lport_enter_ready(lport); - else - fc_lport_error(lport, fp); - -out: - fc_frame_free(fp); -err: - mutex_unlock(&lport->lp_mutex); -} - -/** - * fc_lport_enter_scr() - Send a SCR (State Change Register) request - * @lport: The local port to register for state changes - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_scr(struct fc_lport *lport) -{ - struct fc_frame *fp; - - FC_LPORT_DBG(lport, "Entered SCR state from %s state\n", - fc_lport_state(lport)); - - fc_lport_state_enter(lport, LPORT_ST_SCR); - - fp = fc_frame_alloc(lport, sizeof(struct fc_els_scr)); - if (!fp) { - fc_lport_error(lport, fp); - return; - } - - if (!lport->tt.elsct_send(lport, FC_FID_FCTRL, fp, ELS_SCR, - fc_lport_scr_resp, lport, - 2 * lport->r_a_tov)) - fc_lport_error(lport, NULL); -} - -/** - * fc_lport_enter_ns() - register some object with the name server - * @lport: Fibre Channel local port to register - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state) -{ - struct fc_frame *fp; - enum fc_ns_req cmd; - int size = sizeof(struct fc_ct_hdr); - size_t len; - - FC_LPORT_DBG(lport, "Entered %s state from %s state\n", - fc_lport_state_names[state], - fc_lport_state(lport)); - - fc_lport_state_enter(lport, state); - - switch (state) { - case LPORT_ST_RNN_ID: - cmd = FC_NS_RNN_ID; - size += sizeof(struct fc_ns_rn_id); - break; - case LPORT_ST_RSNN_NN: - len = strnlen(fc_host_symbolic_name(lport->host), 255); - /* if there is no symbolic name, skip to RFT_ID */ - if (!len) - return fc_lport_enter_ns(lport, LPORT_ST_RFT_ID); - cmd = FC_NS_RSNN_NN; - size += sizeof(struct fc_ns_rsnn) + len; - break; - case LPORT_ST_RSPN_ID: - len = strnlen(fc_host_symbolic_name(lport->host), 255); - /* if there is no symbolic name, skip to RFT_ID */ - if (!len) - return fc_lport_enter_ns(lport, LPORT_ST_RFT_ID); - cmd = FC_NS_RSPN_ID; - size += sizeof(struct fc_ns_rspn) + len; - break; - case LPORT_ST_RFT_ID: - cmd = FC_NS_RFT_ID; - size += sizeof(struct fc_ns_rft); - break; - case LPORT_ST_RFF_ID: - cmd = FC_NS_RFF_ID; - size += sizeof(struct fc_ns_rff_id); - break; - default: - fc_lport_error(lport, NULL); - return; - } - - fp = fc_frame_alloc(lport, size); - if (!fp) { - fc_lport_error(lport, fp); - return; - } - - if (!lport->tt.elsct_send(lport, FC_FID_DIR_SERV, fp, cmd, - fc_lport_ns_resp, - lport, 3 * lport->r_a_tov)) - fc_lport_error(lport, fp); -} - -static struct fc_rport_operations fc_lport_rport_ops = { - .event_callback = fc_lport_rport_callback, -}; - -/** - * fc_rport_enter_dns() - Create a fc_rport for the name server - * @lport: The local port requesting a remote port for the name server - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_dns(struct fc_lport *lport) -{ - struct fc_rport_priv *rdata; - - FC_LPORT_DBG(lport, "Entered DNS state from %s state\n", - fc_lport_state(lport)); - - fc_lport_state_enter(lport, LPORT_ST_DNS); - - mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_create(lport, FC_FID_DIR_SERV); - mutex_unlock(&lport->disc.disc_mutex); - if (!rdata) - goto err; - - rdata->ops = &fc_lport_rport_ops; - lport->tt.rport_login(rdata); - return; - -err: - fc_lport_error(lport, NULL); -} - -/** - * fc_lport_enter_ms() - management server commands - * @lport: Fibre Channel local port to register - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) -{ - struct fc_frame *fp; - enum fc_fdmi_req cmd; - int size = sizeof(struct fc_ct_hdr); - size_t len; - int numattrs; - - FC_LPORT_DBG(lport, "Entered %s state from %s state\n", - fc_lport_state_names[state], - fc_lport_state(lport)); - - fc_lport_state_enter(lport, state); - - switch (state) { - case LPORT_ST_RHBA: - cmd = FC_FDMI_RHBA; - /* Number of HBA Attributes */ - numattrs = 10; - len = sizeof(struct fc_fdmi_rhba); - len -= sizeof(struct fc_fdmi_attr_entry); - len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); - len += FC_FDMI_HBA_ATTR_NODENAME_LEN; - len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN; - len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN; - len += FC_FDMI_HBA_ATTR_MODEL_LEN; - len += FC_FDMI_HBA_ATTR_MODELDESCR_LEN; - len += FC_FDMI_HBA_ATTR_HARDWAREVERSION_LEN; - len += FC_FDMI_HBA_ATTR_DRIVERVERSION_LEN; - len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN; - len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN; - len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN; - - size += len; - break; - case LPORT_ST_RPA: - cmd = FC_FDMI_RPA; - /* Number of Port Attributes */ - numattrs = 6; - len = sizeof(struct fc_fdmi_rpa); - len -= sizeof(struct fc_fdmi_attr_entry); - len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); - len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN; - len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN; - len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN; - len += FC_FDMI_PORT_ATTR_MAXFRAMESIZE_LEN; - len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN; - len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN; - - size += len; - break; - case LPORT_ST_DPRT: - cmd = FC_FDMI_DPRT; - len = sizeof(struct fc_fdmi_dprt); - size += len; - break; - case LPORT_ST_DHBA: - cmd = FC_FDMI_DHBA; - len = sizeof(struct fc_fdmi_dhba); - size += len; - break; - default: - fc_lport_error(lport, NULL); - return; - } - - FC_LPORT_DBG(lport, "Cmd=0x%x Len %d size %d\n", - cmd, (int)len, size); - fp = fc_frame_alloc(lport, size); - if (!fp) { - fc_lport_error(lport, fp); - return; - } - - if (!lport->tt.elsct_send(lport, FC_FID_MGMT_SERV, fp, cmd, - fc_lport_ms_resp, - lport, 3 * lport->r_a_tov)) - fc_lport_error(lport, fp); -} - -/** - * fc_rport_enter_fdmi() - Create a fc_rport for the management server - * @lport: The local port requesting a remote port for the management server - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_fdmi(struct fc_lport *lport) -{ - struct fc_rport_priv *rdata; - - FC_LPORT_DBG(lport, "Entered FDMI state from %s state\n", - fc_lport_state(lport)); - - fc_lport_state_enter(lport, LPORT_ST_FDMI); - - mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_create(lport, FC_FID_MGMT_SERV); - mutex_unlock(&lport->disc.disc_mutex); - if (!rdata) - goto err; - - rdata->ops = &fc_lport_rport_ops; - lport->tt.rport_login(rdata); - return; - -err: - fc_lport_error(lport, NULL); -} - -/** - * fc_lport_timeout() - Handler for the retry_work timer - * @work: The work struct of the local port - */ -static void fc_lport_timeout(struct work_struct *work) -{ - struct fc_lport *lport = - container_of(work, struct fc_lport, - retry_work.work); - - mutex_lock(&lport->lp_mutex); - - switch (lport->state) { - case LPORT_ST_DISABLED: - WARN_ON(1); - break; - case LPORT_ST_READY: - break; - case LPORT_ST_RESET: - break; - case LPORT_ST_FLOGI: - fc_lport_enter_flogi(lport); - break; - case LPORT_ST_DNS: - fc_lport_enter_dns(lport); - break; - case LPORT_ST_RNN_ID: - case LPORT_ST_RSNN_NN: - case LPORT_ST_RSPN_ID: - case LPORT_ST_RFT_ID: - case LPORT_ST_RFF_ID: - fc_lport_enter_ns(lport, lport->state); - break; - case LPORT_ST_FDMI: - fc_lport_enter_fdmi(lport); - break; - case LPORT_ST_RHBA: - case LPORT_ST_RPA: - case LPORT_ST_DHBA: - case LPORT_ST_DPRT: - fc_lport_enter_ms(lport, lport->state); - break; - case LPORT_ST_SCR: - fc_lport_enter_scr(lport); - break; - case LPORT_ST_LOGO: - fc_lport_enter_logo(lport); - break; - } - - mutex_unlock(&lport->lp_mutex); -} - -/** - * fc_lport_logo_resp() - Handle response to LOGO request - * @sp: The sequence that the LOGO was on - * @fp: The LOGO frame - * @lp_arg: The lport port that received the LOGO request - * - * Locking Note: This function will be called without the lport lock - * held, but it will lock, call an _enter_* function or fc_lport_error() - * and then unlock the lport. - */ -void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, - void *lp_arg) -{ - struct fc_lport *lport = lp_arg; - u8 op; - - FC_LPORT_DBG(lport, "Received a LOGO %s\n", fc_els_resp_type(fp)); - - if (fp == ERR_PTR(-FC_EX_CLOSED)) - return; - - mutex_lock(&lport->lp_mutex); - - if (lport->state != LPORT_ST_LOGO) { - FC_LPORT_DBG(lport, "Received a LOGO response, but in state " - "%s\n", fc_lport_state(lport)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - - op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC) - fc_lport_enter_disabled(lport); - else - fc_lport_error(lport, fp); - -out: - fc_frame_free(fp); -err: - mutex_unlock(&lport->lp_mutex); -} -EXPORT_SYMBOL(fc_lport_logo_resp); - -/** - * fc_rport_enter_logo() - Logout of the fabric - * @lport: The local port to be logged out - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_logo(struct fc_lport *lport) -{ - struct fc_frame *fp; - struct fc_els_logo *logo; - - FC_LPORT_DBG(lport, "Entered LOGO state from %s state\n", - fc_lport_state(lport)); - - fc_lport_state_enter(lport, LPORT_ST_LOGO); - fc_vports_linkchange(lport); - - fp = fc_frame_alloc(lport, sizeof(*logo)); - if (!fp) { - fc_lport_error(lport, fp); - return; - } - - if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, ELS_LOGO, - fc_lport_logo_resp, lport, - 2 * lport->r_a_tov)) - fc_lport_error(lport, NULL); -} - -/** - * fc_lport_flogi_resp() - Handle response to FLOGI request - * @sp: The sequence that the FLOGI was on - * @fp: The FLOGI response frame - * @lp_arg: The lport port that received the FLOGI response - * - * Locking Note: This function will be called without the lport lock - * held, but it will lock, call an _enter_* function or fc_lport_error() - * and then unlock the lport. - */ -void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, - void *lp_arg) -{ - struct fc_lport *lport = lp_arg; - struct fc_frame_header *fh; - struct fc_els_flogi *flp; - u32 did; - u16 csp_flags; - unsigned int r_a_tov; - unsigned int e_d_tov; - u16 mfs; - - FC_LPORT_DBG(lport, "Received a FLOGI %s\n", fc_els_resp_type(fp)); - - if (fp == ERR_PTR(-FC_EX_CLOSED)) - return; - - mutex_lock(&lport->lp_mutex); - - if (lport->state != LPORT_ST_FLOGI) { - FC_LPORT_DBG(lport, "Received a FLOGI response, but in state " - "%s\n", fc_lport_state(lport)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_lport_error(lport, fp); - goto err; - } - - fh = fc_frame_header_get(fp); - did = fc_frame_did(fp); - if (fh->fh_r_ctl != FC_RCTL_ELS_REP || did == 0 || - fc_frame_payload_op(fp) != ELS_LS_ACC) { - FC_LPORT_DBG(lport, "FLOGI not accepted or bad response\n"); - fc_lport_error(lport, fp); - goto err; - } - - flp = fc_frame_payload_get(fp, sizeof(*flp)); - if (!flp) { - FC_LPORT_DBG(lport, "FLOGI bad response\n"); - fc_lport_error(lport, fp); - goto err; - } - - mfs = ntohs(flp->fl_csp.sp_bb_data) & - FC_SP_BB_DATA_MASK; - - if (mfs < FC_SP_MIN_MAX_PAYLOAD || mfs > FC_SP_MAX_MAX_PAYLOAD) { - FC_LPORT_DBG(lport, "FLOGI bad mfs:%hu response, " - "lport->mfs:%hu\n", mfs, lport->mfs); - fc_lport_error(lport, fp); - goto err; - } - - if (mfs <= lport->mfs) { - lport->mfs = mfs; - fc_host_maxframe_size(lport->host) = mfs; - } - - csp_flags = ntohs(flp->fl_csp.sp_features); - r_a_tov = ntohl(flp->fl_csp.sp_r_a_tov); - e_d_tov = ntohl(flp->fl_csp.sp_e_d_tov); - if (csp_flags & FC_SP_FT_EDTR) - e_d_tov /= 1000000; - - lport->npiv_enabled = !!(csp_flags & FC_SP_FT_NPIV_ACC); - - if ((csp_flags & FC_SP_FT_FPORT) == 0) { - if (e_d_tov > lport->e_d_tov) - lport->e_d_tov = e_d_tov; - lport->r_a_tov = 2 * e_d_tov; - fc_lport_set_port_id(lport, did, fp); - printk(KERN_INFO "host%d: libfc: " - "Port (%6.6x) entered " - "point-to-point mode\n", - lport->host->host_no, did); - fc_lport_ptp_setup(lport, fc_frame_sid(fp), - get_unaligned_be64( - &flp->fl_wwpn), - get_unaligned_be64( - &flp->fl_wwnn)); - } else { - lport->e_d_tov = e_d_tov; - lport->r_a_tov = r_a_tov; - fc_host_fabric_name(lport->host) = - get_unaligned_be64(&flp->fl_wwnn); - fc_lport_set_port_id(lport, did, fp); - fc_lport_enter_dns(lport); - } - -out: - fc_frame_free(fp); -err: - mutex_unlock(&lport->lp_mutex); -} -EXPORT_SYMBOL(fc_lport_flogi_resp); - -/** - * fc_rport_enter_flogi() - Send a FLOGI request to the fabric manager - * @lport: Fibre Channel local port to be logged in to the fabric - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static void fc_lport_enter_flogi(struct fc_lport *lport) -{ - struct fc_frame *fp; - - FC_LPORT_DBG(lport, "Entered FLOGI state from %s state\n", - fc_lport_state(lport)); - - fc_lport_state_enter(lport, LPORT_ST_FLOGI); - - if (lport->point_to_multipoint) { - if (lport->port_id) - fc_lport_enter_ready(lport); - return; - } - - fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); - if (!fp) - return fc_lport_error(lport, fp); - - if (!lport->tt.elsct_send(lport, FC_FID_FLOGI, fp, - lport->vport ? ELS_FDISC : ELS_FLOGI, - fc_lport_flogi_resp, lport, - lport->vport ? 2 * lport->r_a_tov : - lport->e_d_tov)) - fc_lport_error(lport, NULL); -} - -/** - * fc_lport_config() - Configure a fc_lport - * @lport: The local port to be configured - */ -int fc_lport_config(struct fc_lport *lport) -{ - INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); - mutex_init(&lport->lp_mutex); - - fc_lport_state_enter(lport, LPORT_ST_DISABLED); - - fc_lport_add_fc4_type(lport, FC_TYPE_FCP); - fc_lport_add_fc4_type(lport, FC_TYPE_CT); - fc_fc4_conf_lport_params(lport, FC_TYPE_FCP); - - return 0; -} -EXPORT_SYMBOL(fc_lport_config); - -/** - * fc_lport_init() - Initialize the lport layer for a local port - * @lport: The local port to initialize the exchange layer for - */ -int fc_lport_init(struct fc_lport *lport) -{ - if (!lport->tt.lport_recv) - lport->tt.lport_recv = fc_lport_recv_req; - - if (!lport->tt.lport_reset) - lport->tt.lport_reset = fc_lport_reset; - - fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; - fc_host_node_name(lport->host) = lport->wwnn; - fc_host_port_name(lport->host) = lport->wwpn; - fc_host_supported_classes(lport->host) = FC_COS_CLASS3; - memset(fc_host_supported_fc4s(lport->host), 0, - sizeof(fc_host_supported_fc4s(lport->host))); - fc_host_supported_fc4s(lport->host)[2] = 1; - fc_host_supported_fc4s(lport->host)[7] = 1; - - /* This value is also unchanging */ - memset(fc_host_active_fc4s(lport->host), 0, - sizeof(fc_host_active_fc4s(lport->host))); - fc_host_active_fc4s(lport->host)[2] = 1; - fc_host_active_fc4s(lport->host)[7] = 1; - fc_host_maxframe_size(lport->host) = lport->mfs; - fc_host_supported_speeds(lport->host) = 0; - if (lport->link_supported_speeds & FC_PORTSPEED_1GBIT) - fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_1GBIT; - if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT) - fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT; - fc_fc4_add_lport(lport); - - return 0; -} -EXPORT_SYMBOL(fc_lport_init); - -/** - * fc_lport_bsg_resp() - The common response handler for FC Passthrough requests - * @sp: The sequence for the FC Passthrough response - * @fp: The response frame - * @info_arg: The BSG info that the response is for - */ -static void fc_lport_bsg_resp(struct fc_seq *sp, struct fc_frame *fp, - void *info_arg) -{ - struct fc_bsg_info *info = info_arg; - struct fc_bsg_job *job = info->job; - struct fc_lport *lport = info->lport; - struct fc_frame_header *fh; - size_t len; - void *buf; - - if (IS_ERR(fp)) { - job->reply->result = (PTR_ERR(fp) == -FC_EX_CLOSED) ? - -ECONNABORTED : -ETIMEDOUT; - job->reply_len = sizeof(uint32_t); - job->state_flags |= FC_RQST_STATE_DONE; - job->job_done(job); - kfree(info); - return; - } - - mutex_lock(&lport->lp_mutex); - fh = fc_frame_header_get(fp); - len = fr_len(fp) - sizeof(*fh); - buf = fc_frame_payload_get(fp, 0); - - if (fr_sof(fp) == FC_SOF_I3 && !ntohs(fh->fh_seq_cnt)) { - /* Get the response code from the first frame payload */ - unsigned short cmd = (info->rsp_code == FC_FS_ACC) ? - ntohs(((struct fc_ct_hdr *)buf)->ct_cmd) : - (unsigned short)fc_frame_payload_op(fp); - - /* Save the reply status of the job */ - job->reply->reply_data.ctels_reply.status = - (cmd == info->rsp_code) ? - FC_CTELS_STATUS_OK : FC_CTELS_STATUS_REJECT; - } - - job->reply->reply_payload_rcv_len += - fc_copy_buffer_to_sglist(buf, len, info->sg, &info->nents, - &info->offset, NULL); - - if (fr_eof(fp) == FC_EOF_T && - (ntoh24(fh->fh_f_ctl) & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) == - (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) { - if (job->reply->reply_payload_rcv_len > - job->reply_payload.payload_len) - job->reply->reply_payload_rcv_len = - job->reply_payload.payload_len; - job->reply->result = 0; - job->state_flags |= FC_RQST_STATE_DONE; - job->job_done(job); - kfree(info); - } - fc_frame_free(fp); - mutex_unlock(&lport->lp_mutex); -} - -/** - * fc_lport_els_request() - Send ELS passthrough request - * @job: The BSG Passthrough job - * @lport: The local port sending the request - * @did: The destination port id - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static int fc_lport_els_request(struct fc_bsg_job *job, - struct fc_lport *lport, - u32 did, u32 tov) -{ - struct fc_bsg_info *info; - struct fc_frame *fp; - struct fc_frame_header *fh; - char *pp; - int len; - - fp = fc_frame_alloc(lport, job->request_payload.payload_len); - if (!fp) - return -ENOMEM; - - len = job->request_payload.payload_len; - pp = fc_frame_payload_get(fp, len); - - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, - pp, len); - - fh = fc_frame_header_get(fp); - fh->fh_r_ctl = FC_RCTL_ELS_REQ; - hton24(fh->fh_d_id, did); - hton24(fh->fh_s_id, lport->port_id); - fh->fh_type = FC_TYPE_ELS; - hton24(fh->fh_f_ctl, FC_FCTL_REQ); - fh->fh_cs_ctl = 0; - fh->fh_df_ctl = 0; - fh->fh_parm_offset = 0; - - info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL); - if (!info) { - fc_frame_free(fp); - return -ENOMEM; - } - - info->job = job; - info->lport = lport; - info->rsp_code = ELS_LS_ACC; - info->nents = job->reply_payload.sg_cnt; - info->sg = job->reply_payload.sg_list; - - if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp, - NULL, info, tov)) { - kfree(info); - return -ECOMM; - } - return 0; -} - -/** - * fc_lport_ct_request() - Send CT Passthrough request - * @job: The BSG Passthrough job - * @lport: The local port sending the request - * @did: The destination FC-ID - * @tov: The timeout period to wait for the response - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. - */ -static int fc_lport_ct_request(struct fc_bsg_job *job, - struct fc_lport *lport, u32 did, u32 tov) -{ - struct fc_bsg_info *info; - struct fc_frame *fp; - struct fc_frame_header *fh; - struct fc_ct_req *ct; - size_t len; - - fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + - job->request_payload.payload_len); - if (!fp) - return -ENOMEM; - - len = job->request_payload.payload_len; - ct = fc_frame_payload_get(fp, len); - - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, - ct, len); - - fh = fc_frame_header_get(fp); - fh->fh_r_ctl = FC_RCTL_DD_UNSOL_CTL; - hton24(fh->fh_d_id, did); - hton24(fh->fh_s_id, lport->port_id); - fh->fh_type = FC_TYPE_CT; - hton24(fh->fh_f_ctl, FC_FCTL_REQ); - fh->fh_cs_ctl = 0; - fh->fh_df_ctl = 0; - fh->fh_parm_offset = 0; - - info = kzalloc(sizeof(struct fc_bsg_info), GFP_KERNEL); - if (!info) { - fc_frame_free(fp); - return -ENOMEM; - } - - info->job = job; - info->lport = lport; - info->rsp_code = FC_FS_ACC; - info->nents = job->reply_payload.sg_cnt; - info->sg = job->reply_payload.sg_list; - - if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp, - NULL, info, tov)) { - kfree(info); - return -ECOMM; - } - return 0; -} - -/** - * fc_lport_bsg_request() - The common entry point for sending - * FC Passthrough requests - * @job: The BSG passthrough job - */ -int fc_lport_bsg_request(struct fc_bsg_job *job) -{ - struct request *rsp = job->req->next_rq; - struct Scsi_Host *shost = job->shost; - struct fc_lport *lport = shost_priv(shost); - struct fc_rport *rport; - struct fc_rport_priv *rdata; - int rc = -EINVAL; - u32 did; - - job->reply->reply_payload_rcv_len = 0; - if (rsp) - rsp->resid_len = job->reply_payload.payload_len; - - mutex_lock(&lport->lp_mutex); - - switch (job->request->msgcode) { - case FC_BSG_RPT_ELS: - rport = job->rport; - if (!rport) - break; - - rdata = rport->dd_data; - rc = fc_lport_els_request(job, lport, rport->port_id, - rdata->e_d_tov); - break; - - case FC_BSG_RPT_CT: - rport = job->rport; - if (!rport) - break; - - rdata = rport->dd_data; - rc = fc_lport_ct_request(job, lport, rport->port_id, - rdata->e_d_tov); - break; - - case FC_BSG_HST_CT: - did = ntoh24(job->request->rqst_data.h_ct.port_id); - if (did == FC_FID_DIR_SERV) - rdata = lport->dns_rdata; - else - rdata = lport->tt.rport_lookup(lport, did); - - if (!rdata) - break; - - rc = fc_lport_ct_request(job, lport, did, rdata->e_d_tov); - break; - - case FC_BSG_HST_ELS_NOLOGIN: - did = ntoh24(job->request->rqst_data.h_els.port_id); - rc = fc_lport_els_request(job, lport, did, lport->e_d_tov); - break; - } - - mutex_unlock(&lport->lp_mutex); - return rc; -} -EXPORT_SYMBOL(fc_lport_bsg_request); diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_npiv.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_npiv.c deleted file mode 100644 index 9fbf78ed..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_npiv.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright(c) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -/* - * NPIV VN_Port helper functions for libfc - */ - -#include -#include - -/** - * fc_vport_create() - Create a new NPIV vport instance - * @vport: fc_vport structure from scsi_transport_fc - * @privsize: driver private data size to allocate along with the Scsi_Host - */ - -struct fc_lport *libfc_vport_create(struct fc_vport *vport, int privsize) -{ - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_lport *n_port = shost_priv(shost); - struct fc_lport *vn_port; - - vn_port = libfc_host_alloc(shost->hostt, privsize); - if (!vn_port) - return vn_port; - - vn_port->vport = vport; - vport->dd_data = vn_port; - - mutex_lock(&n_port->lp_mutex); - list_add_tail(&vn_port->list, &n_port->vports); - mutex_unlock(&n_port->lp_mutex); - - return vn_port; -} -EXPORT_SYMBOL(libfc_vport_create); - -/** - * fc_vport_id_lookup() - find NPIV lport that matches a given fabric ID - * @n_port: Top level N_Port which may have multiple NPIV VN_Ports - * @port_id: Fabric ID to find a match for - * - * Returns: matching lport pointer or NULL if there is no match - */ -struct fc_lport *fc_vport_id_lookup(struct fc_lport *n_port, u32 port_id) -{ - struct fc_lport *lport = NULL; - struct fc_lport *vn_port; - - if (n_port->port_id == port_id) - return n_port; - - if (port_id == FC_FID_FLOGI) - return n_port; /* for point-to-point */ - - mutex_lock(&n_port->lp_mutex); - list_for_each_entry(vn_port, &n_port->vports, list) { - if (vn_port->port_id == port_id) { - lport = vn_port; - break; - } - } - mutex_unlock(&n_port->lp_mutex); - - return lport; -} -EXPORT_SYMBOL(fc_vport_id_lookup); - -/* - * When setting the link state of vports during an lport state change, it's - * necessary to hold the lp_mutex of both the N_Port and the VN_Port. - * This tells the lockdep engine to treat the nested locking of the VN_Port - * as a different lock class. - */ -enum libfc_lport_mutex_class { - LPORT_MUTEX_NORMAL = 0, - LPORT_MUTEX_VN_PORT = 1, -}; - -/** - * __fc_vport_setlink() - update link and status on a VN_Port - * @n_port: parent N_Port - * @vn_port: VN_Port to update - * - * Locking: must be called with both the N_Port and VN_Port lp_mutex held - */ -static void __fc_vport_setlink(struct fc_lport *n_port, - struct fc_lport *vn_port) -{ - struct fc_vport *vport = vn_port->vport; - - if (vn_port->state == LPORT_ST_DISABLED) - return; - - if (n_port->state == LPORT_ST_READY) { - if (n_port->npiv_enabled) { - fc_vport_set_state(vport, FC_VPORT_INITIALIZING); - __fc_linkup(vn_port); - } else { - fc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - __fc_linkdown(vn_port); - } - } else { - fc_vport_set_state(vport, FC_VPORT_LINKDOWN); - __fc_linkdown(vn_port); - } -} - -/** - * fc_vport_setlink() - update link and status on a VN_Port - * @vn_port: virtual port to update - */ -void fc_vport_setlink(struct fc_lport *vn_port) -{ - struct fc_vport *vport = vn_port->vport; - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_lport *n_port = shost_priv(shost); - - mutex_lock(&n_port->lp_mutex); - mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT); - __fc_vport_setlink(n_port, vn_port); - mutex_unlock(&vn_port->lp_mutex); - mutex_unlock(&n_port->lp_mutex); -} -EXPORT_SYMBOL(fc_vport_setlink); - -/** - * fc_vports_linkchange() - change the link state of all vports - * @n_port: Parent N_Port that has changed state - * - * Locking: called with the n_port lp_mutex held - */ -void fc_vports_linkchange(struct fc_lport *n_port) -{ - struct fc_lport *vn_port; - - list_for_each_entry(vn_port, &n_port->vports, list) { - mutex_lock_nested(&vn_port->lp_mutex, LPORT_MUTEX_VN_PORT); - __fc_vport_setlink(n_port, vn_port); - mutex_unlock(&vn_port->lp_mutex); - } -} - diff --git a/ANDROID_3.4.5/drivers/scsi/libfc/fc_rport.c b/ANDROID_3.4.5/drivers/scsi/libfc/fc_rport.c deleted file mode 100644 index 83aa1efe..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libfc/fc_rport.c +++ /dev/null @@ -1,2042 +0,0 @@ -/* - * Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -/* - * RPORT GENERAL INFO - * - * This file contains all processing regarding fc_rports. It contains the - * rport state machine and does all rport interaction with the transport class. - * There should be no other places in libfc that interact directly with the - * transport class in regards to adding and deleting rports. - * - * fc_rport's represent N_Port's within the fabric. - */ - -/* - * RPORT LOCKING - * - * The rport should never hold the rport mutex and then attempt to acquire - * either the lport or disc mutexes. The rport's mutex is considered lesser - * than both the lport's mutex and the disc mutex. Refer to fc_lport.c for - * more comments on the hierarchy. - * - * The locking strategy is similar to the lport's strategy. The lock protects - * the rport's states and is held and released by the entry points to the rport - * block. All _enter_* functions correspond to rport states and expect the rport - * mutex to be locked before calling them. This means that rports only handle - * one request or response at a time, since they're not critical for the I/O - * path this potential over-use of the mutex is acceptable. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "fc_libfc.h" - -static struct workqueue_struct *rport_event_queue; - -static void fc_rport_enter_flogi(struct fc_rport_priv *); -static void fc_rport_enter_plogi(struct fc_rport_priv *); -static void fc_rport_enter_prli(struct fc_rport_priv *); -static void fc_rport_enter_rtv(struct fc_rport_priv *); -static void fc_rport_enter_ready(struct fc_rport_priv *); -static void fc_rport_enter_logo(struct fc_rport_priv *); -static void fc_rport_enter_adisc(struct fc_rport_priv *); - -static void fc_rport_recv_plogi_req(struct fc_lport *, struct fc_frame *); -static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_frame *); -static void fc_rport_recv_prlo_req(struct fc_rport_priv *, struct fc_frame *); -static void fc_rport_recv_logo_req(struct fc_lport *, struct fc_frame *); -static void fc_rport_timeout(struct work_struct *); -static void fc_rport_error(struct fc_rport_priv *, struct fc_frame *); -static void fc_rport_error_retry(struct fc_rport_priv *, struct fc_frame *); -static void fc_rport_work(struct work_struct *); - -static const char *fc_rport_state_names[] = { - [RPORT_ST_INIT] = "Init", - [RPORT_ST_FLOGI] = "FLOGI", - [RPORT_ST_PLOGI_WAIT] = "PLOGI_WAIT", - [RPORT_ST_PLOGI] = "PLOGI", - [RPORT_ST_PRLI] = "PRLI", - [RPORT_ST_RTV] = "RTV", - [RPORT_ST_READY] = "Ready", - [RPORT_ST_ADISC] = "ADISC", - [RPORT_ST_DELETE] = "Delete", -}; - -/** - * fc_rport_lookup() - Lookup a remote port by port_id - * @lport: The local port to lookup the remote port on - * @port_id: The remote port ID to look up - * - * The caller must hold either disc_mutex or rcu_read_lock(). - */ -static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, - u32 port_id) -{ - struct fc_rport_priv *rdata; - - list_for_each_entry_rcu(rdata, &lport->disc.rports, peers) - if (rdata->ids.port_id == port_id) - return rdata; - return NULL; -} - -/** - * fc_rport_create() - Create a new remote port - * @lport: The local port this remote port will be associated with - * @ids: The identifiers for the new remote port - * - * The remote port will start in the INIT state. - * - * Locking note: must be called with the disc_mutex held. - */ -static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, - u32 port_id) -{ - struct fc_rport_priv *rdata; - - rdata = lport->tt.rport_lookup(lport, port_id); - if (rdata) - return rdata; - - rdata = kzalloc(sizeof(*rdata) + lport->rport_priv_size, GFP_KERNEL); - if (!rdata) - return NULL; - - rdata->ids.node_name = -1; - rdata->ids.port_name = -1; - rdata->ids.port_id = port_id; - rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; - - kref_init(&rdata->kref); - mutex_init(&rdata->rp_mutex); - rdata->local_port = lport; - rdata->rp_state = RPORT_ST_INIT; - rdata->event = RPORT_EV_NONE; - rdata->flags = FC_RP_FLAGS_REC_SUPPORTED; - rdata->e_d_tov = lport->e_d_tov; - rdata->r_a_tov = lport->r_a_tov; - rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; - INIT_DELAYED_WORK(&rdata->retry_work, fc_rport_timeout); - INIT_WORK(&rdata->event_work, fc_rport_work); - if (port_id != FC_FID_DIR_SERV) { - rdata->lld_event_callback = lport->tt.rport_event_callback; - list_add_rcu(&rdata->peers, &lport->disc.rports); - } - return rdata; -} - -/** - * fc_rport_destroy() - Free a remote port after last reference is released - * @kref: The remote port's kref - */ -static void fc_rport_destroy(struct kref *kref) -{ - struct fc_rport_priv *rdata; - - rdata = container_of(kref, struct fc_rport_priv, kref); - kfree_rcu(rdata, rcu); -} - -/** - * fc_rport_state() - Return a string identifying the remote port's state - * @rdata: The remote port - */ -static const char *fc_rport_state(struct fc_rport_priv *rdata) -{ - const char *cp; - - cp = fc_rport_state_names[rdata->rp_state]; - if (!cp) - cp = "Unknown"; - return cp; -} - -/** - * fc_set_rport_loss_tmo() - Set the remote port loss timeout - * @rport: The remote port that gets a new timeout value - * @timeout: The new timeout value (in seconds) - */ -void fc_set_rport_loss_tmo(struct fc_rport *rport, u32 timeout) -{ - if (timeout) - rport->dev_loss_tmo = timeout; - else - rport->dev_loss_tmo = 1; -} -EXPORT_SYMBOL(fc_set_rport_loss_tmo); - -/** - * fc_plogi_get_maxframe() - Get the maximum payload from the common service - * parameters in a FLOGI frame - * @flp: The FLOGI or PLOGI payload - * @maxval: The maximum frame size upper limit; this may be less than what - * is in the service parameters - */ -static unsigned int fc_plogi_get_maxframe(struct fc_els_flogi *flp, - unsigned int maxval) -{ - unsigned int mfs; - - /* - * Get max payload from the common service parameters and the - * class 3 receive data field size. - */ - mfs = ntohs(flp->fl_csp.sp_bb_data) & FC_SP_BB_DATA_MASK; - if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval) - maxval = mfs; - mfs = ntohs(flp->fl_cssp[3 - 1].cp_rdfs); - if (mfs >= FC_SP_MIN_MAX_PAYLOAD && mfs < maxval) - maxval = mfs; - return maxval; -} - -/** - * fc_rport_state_enter() - Change the state of a remote port - * @rdata: The remote port whose state should change - * @new: The new state - * - * Locking Note: Called with the rport lock held - */ -static void fc_rport_state_enter(struct fc_rport_priv *rdata, - enum fc_rport_state new) -{ - if (rdata->rp_state != new) - rdata->retries = 0; - rdata->rp_state = new; -} - -/** - * fc_rport_work() - Handler for remote port events in the rport_event_queue - * @work: Handle to the remote port being dequeued - */ -static void fc_rport_work(struct work_struct *work) -{ - u32 port_id; - struct fc_rport_priv *rdata = - container_of(work, struct fc_rport_priv, event_work); - struct fc_rport_libfc_priv *rpriv; - enum fc_rport_event event; - struct fc_lport *lport = rdata->local_port; - struct fc_rport_operations *rport_ops; - struct fc_rport_identifiers ids; - struct fc_rport *rport; - struct fc4_prov *prov; - u8 type; - - mutex_lock(&rdata->rp_mutex); - event = rdata->event; - rport_ops = rdata->ops; - rport = rdata->rport; - - FC_RPORT_DBG(rdata, "work event %u\n", event); - - switch (event) { - case RPORT_EV_READY: - ids = rdata->ids; - rdata->event = RPORT_EV_NONE; - rdata->major_retries = 0; - kref_get(&rdata->kref); - mutex_unlock(&rdata->rp_mutex); - - if (!rport) - rport = fc_remote_port_add(lport->host, 0, &ids); - if (!rport) { - FC_RPORT_DBG(rdata, "Failed to add the rport\n"); - lport->tt.rport_logoff(rdata); - kref_put(&rdata->kref, lport->tt.rport_destroy); - return; - } - mutex_lock(&rdata->rp_mutex); - if (rdata->rport) - FC_RPORT_DBG(rdata, "rport already allocated\n"); - rdata->rport = rport; - rport->maxframe_size = rdata->maxframe_size; - rport->supported_classes = rdata->supported_classes; - - rpriv = rport->dd_data; - rpriv->local_port = lport; - rpriv->rp_state = rdata->rp_state; - rpriv->flags = rdata->flags; - rpriv->e_d_tov = rdata->e_d_tov; - rpriv->r_a_tov = rdata->r_a_tov; - mutex_unlock(&rdata->rp_mutex); - - if (rport_ops && rport_ops->event_callback) { - FC_RPORT_DBG(rdata, "callback ev %d\n", event); - rport_ops->event_callback(lport, rdata, event); - } - if (rdata->lld_event_callback) { - FC_RPORT_DBG(rdata, "lld callback ev %d\n", event); - rdata->lld_event_callback(lport, rdata, event); - } - kref_put(&rdata->kref, lport->tt.rport_destroy); - break; - - case RPORT_EV_FAILED: - case RPORT_EV_LOGO: - case RPORT_EV_STOP: - if (rdata->prli_count) { - mutex_lock(&fc_prov_mutex); - for (type = 1; type < FC_FC4_PROV_SIZE; type++) { - prov = fc_passive_prov[type]; - if (prov && prov->prlo) - prov->prlo(rdata); - } - mutex_unlock(&fc_prov_mutex); - } - port_id = rdata->ids.port_id; - mutex_unlock(&rdata->rp_mutex); - - if (rport_ops && rport_ops->event_callback) { - FC_RPORT_DBG(rdata, "callback ev %d\n", event); - rport_ops->event_callback(lport, rdata, event); - } - if (rdata->lld_event_callback) { - FC_RPORT_DBG(rdata, "lld callback ev %d\n", event); - rdata->lld_event_callback(lport, rdata, event); - } - cancel_delayed_work_sync(&rdata->retry_work); - - /* - * Reset any outstanding exchanges before freeing rport. - */ - lport->tt.exch_mgr_reset(lport, 0, port_id); - lport->tt.exch_mgr_reset(lport, port_id, 0); - - if (rport) { - rpriv = rport->dd_data; - rpriv->rp_state = RPORT_ST_DELETE; - mutex_lock(&rdata->rp_mutex); - rdata->rport = NULL; - mutex_unlock(&rdata->rp_mutex); - fc_remote_port_delete(rport); - } - - mutex_lock(&lport->disc.disc_mutex); - mutex_lock(&rdata->rp_mutex); - if (rdata->rp_state == RPORT_ST_DELETE) { - if (port_id == FC_FID_DIR_SERV) { - rdata->event = RPORT_EV_NONE; - mutex_unlock(&rdata->rp_mutex); - kref_put(&rdata->kref, lport->tt.rport_destroy); - } else if ((rdata->flags & FC_RP_STARTED) && - rdata->major_retries < - lport->max_rport_retry_count) { - rdata->major_retries++; - rdata->event = RPORT_EV_NONE; - FC_RPORT_DBG(rdata, "work restart\n"); - fc_rport_enter_flogi(rdata); - mutex_unlock(&rdata->rp_mutex); - } else { - FC_RPORT_DBG(rdata, "work delete\n"); - list_del_rcu(&rdata->peers); - mutex_unlock(&rdata->rp_mutex); - kref_put(&rdata->kref, lport->tt.rport_destroy); - } - } else { - /* - * Re-open for events. Reissue READY event if ready. - */ - rdata->event = RPORT_EV_NONE; - if (rdata->rp_state == RPORT_ST_READY) - fc_rport_enter_ready(rdata); - mutex_unlock(&rdata->rp_mutex); - } - mutex_unlock(&lport->disc.disc_mutex); - break; - - default: - mutex_unlock(&rdata->rp_mutex); - break; - } -} - -/** - * fc_rport_login() - Start the remote port login state machine - * @rdata: The remote port to be logged in to - * - * Locking Note: Called without the rport lock held. This - * function will hold the rport lock, call an _enter_* - * function and then unlock the rport. - * - * This indicates the intent to be logged into the remote port. - * If it appears we are already logged in, ADISC is used to verify - * the setup. - */ -static int fc_rport_login(struct fc_rport_priv *rdata) -{ - mutex_lock(&rdata->rp_mutex); - - rdata->flags |= FC_RP_STARTED; - switch (rdata->rp_state) { - case RPORT_ST_READY: - FC_RPORT_DBG(rdata, "ADISC port\n"); - fc_rport_enter_adisc(rdata); - break; - case RPORT_ST_DELETE: - FC_RPORT_DBG(rdata, "Restart deleted port\n"); - break; - default: - FC_RPORT_DBG(rdata, "Login to port\n"); - fc_rport_enter_flogi(rdata); - break; - } - mutex_unlock(&rdata->rp_mutex); - - return 0; -} - -/** - * fc_rport_enter_delete() - Schedule a remote port to be deleted - * @rdata: The remote port to be deleted - * @event: The event to report as the reason for deletion - * - * Locking Note: Called with the rport lock held. - * - * Allow state change into DELETE only once. - * - * Call queue_work only if there's no event already pending. - * Set the new event so that the old pending event will not occur. - * Since we have the mutex, even if fc_rport_work() is already started, - * it'll see the new event. - */ -static void fc_rport_enter_delete(struct fc_rport_priv *rdata, - enum fc_rport_event event) -{ - if (rdata->rp_state == RPORT_ST_DELETE) - return; - - FC_RPORT_DBG(rdata, "Delete port\n"); - - fc_rport_state_enter(rdata, RPORT_ST_DELETE); - - if (rdata->event == RPORT_EV_NONE) - queue_work(rport_event_queue, &rdata->event_work); - rdata->event = event; -} - -/** - * fc_rport_logoff() - Logoff and remove a remote port - * @rdata: The remote port to be logged off of - * - * Locking Note: Called without the rport lock held. This - * function will hold the rport lock, call an _enter_* - * function and then unlock the rport. - */ -static int fc_rport_logoff(struct fc_rport_priv *rdata) -{ - mutex_lock(&rdata->rp_mutex); - - FC_RPORT_DBG(rdata, "Remove port\n"); - - rdata->flags &= ~FC_RP_STARTED; - if (rdata->rp_state == RPORT_ST_DELETE) { - FC_RPORT_DBG(rdata, "Port in Delete state, not removing\n"); - goto out; - } - fc_rport_enter_logo(rdata); - - /* - * Change the state to Delete so that we discard - * the response. - */ - fc_rport_enter_delete(rdata, RPORT_EV_STOP); -out: - mutex_unlock(&rdata->rp_mutex); - return 0; -} - -/** - * fc_rport_enter_ready() - Transition to the RPORT_ST_READY state - * @rdata: The remote port that is ready - * - * Locking Note: The rport lock is expected to be held before calling - * this routine. - */ -static void fc_rport_enter_ready(struct fc_rport_priv *rdata) -{ - fc_rport_state_enter(rdata, RPORT_ST_READY); - - FC_RPORT_DBG(rdata, "Port is Ready\n"); - - if (rdata->event == RPORT_EV_NONE) - queue_work(rport_event_queue, &rdata->event_work); - rdata->event = RPORT_EV_READY; -} - -/** - * fc_rport_timeout() - Handler for the retry_work timer - * @work: Handle to the remote port that has timed out - * - * Locking Note: Called without the rport lock held. This - * function will hold the rport lock, call an _enter_* - * function and then unlock the rport. - */ -static void fc_rport_timeout(struct work_struct *work) -{ - struct fc_rport_priv *rdata = - container_of(work, struct fc_rport_priv, retry_work.work); - - mutex_lock(&rdata->rp_mutex); - - switch (rdata->rp_state) { - case RPORT_ST_FLOGI: - fc_rport_enter_flogi(rdata); - break; - case RPORT_ST_PLOGI: - fc_rport_enter_plogi(rdata); - break; - case RPORT_ST_PRLI: - fc_rport_enter_prli(rdata); - break; - case RPORT_ST_RTV: - fc_rport_enter_rtv(rdata); - break; - case RPORT_ST_ADISC: - fc_rport_enter_adisc(rdata); - break; - case RPORT_ST_PLOGI_WAIT: - case RPORT_ST_READY: - case RPORT_ST_INIT: - case RPORT_ST_DELETE: - break; - } - - mutex_unlock(&rdata->rp_mutex); -} - -/** - * fc_rport_error() - Error handler, called once retries have been exhausted - * @rdata: The remote port the error is happened on - * @fp: The error code encapsulated in a frame pointer - * - * Locking Note: The rport lock is expected to be held before - * calling this routine - */ -static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp) -{ - FC_RPORT_DBG(rdata, "Error %ld in state %s, retries %d\n", - IS_ERR(fp) ? -PTR_ERR(fp) : 0, - fc_rport_state(rdata), rdata->retries); - - switch (rdata->rp_state) { - case RPORT_ST_FLOGI: - case RPORT_ST_PLOGI: - rdata->flags &= ~FC_RP_STARTED; - fc_rport_enter_delete(rdata, RPORT_EV_FAILED); - break; - case RPORT_ST_RTV: - fc_rport_enter_ready(rdata); - break; - case RPORT_ST_PRLI: - case RPORT_ST_ADISC: - fc_rport_enter_logo(rdata); - break; - case RPORT_ST_PLOGI_WAIT: - case RPORT_ST_DELETE: - case RPORT_ST_READY: - case RPORT_ST_INIT: - break; - } -} - -/** - * fc_rport_error_retry() - Handler for remote port state retries - * @rdata: The remote port whose state is to be retried - * @fp: The error code encapsulated in a frame pointer - * - * If the error was an exchange timeout retry immediately, - * otherwise wait for E_D_TOV. - * - * Locking Note: The rport lock is expected to be held before - * calling this routine - */ -static void fc_rport_error_retry(struct fc_rport_priv *rdata, - struct fc_frame *fp) -{ - unsigned long delay = FC_DEF_E_D_TOV; - - /* make sure this isn't an FC_EX_CLOSED error, never retry those */ - if (PTR_ERR(fp) == -FC_EX_CLOSED) - goto out; - - if (rdata->retries < rdata->local_port->max_rport_retry_count) { - FC_RPORT_DBG(rdata, "Error %ld in state %s, retrying\n", - PTR_ERR(fp), fc_rport_state(rdata)); - rdata->retries++; - /* no additional delay on exchange timeouts */ - if (PTR_ERR(fp) == -FC_EX_TIMEOUT) - delay = 0; - schedule_delayed_work(&rdata->retry_work, delay); - return; - } - -out: - fc_rport_error(rdata, fp); -} - -/** - * fc_rport_login_complete() - Handle parameters and completion of p-mp login. - * @rdata: The remote port which we logged into or which logged into us. - * @fp: The FLOGI or PLOGI request or response frame - * - * Returns non-zero error if a problem is detected with the frame. - * Does not free the frame. - * - * This is only used in point-to-multipoint mode for FIP currently. - */ -static int fc_rport_login_complete(struct fc_rport_priv *rdata, - struct fc_frame *fp) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_els_flogi *flogi; - unsigned int e_d_tov; - u16 csp_flags; - - flogi = fc_frame_payload_get(fp, sizeof(*flogi)); - if (!flogi) - return -EINVAL; - - csp_flags = ntohs(flogi->fl_csp.sp_features); - - if (fc_frame_payload_op(fp) == ELS_FLOGI) { - if (csp_flags & FC_SP_FT_FPORT) { - FC_RPORT_DBG(rdata, "Fabric bit set in FLOGI\n"); - return -EINVAL; - } - } else { - - /* - * E_D_TOV is not valid on an incoming FLOGI request. - */ - e_d_tov = ntohl(flogi->fl_csp.sp_e_d_tov); - if (csp_flags & FC_SP_FT_EDTR) - e_d_tov /= 1000000; - if (e_d_tov > rdata->e_d_tov) - rdata->e_d_tov = e_d_tov; - } - rdata->maxframe_size = fc_plogi_get_maxframe(flogi, lport->mfs); - return 0; -} - -/** - * fc_rport_flogi_resp() - Handle response to FLOGI request for p-mp mode - * @sp: The sequence that the FLOGI was on - * @fp: The FLOGI response frame - * @rp_arg: The remote port that received the FLOGI response - */ -static void fc_rport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rp_arg) -{ - struct fc_rport_priv *rdata = rp_arg; - struct fc_lport *lport = rdata->local_port; - struct fc_els_flogi *flogi; - unsigned int r_a_tov; - - FC_RPORT_DBG(rdata, "Received a FLOGI %s\n", fc_els_resp_type(fp)); - - if (fp == ERR_PTR(-FC_EX_CLOSED)) - goto put; - - mutex_lock(&rdata->rp_mutex); - - if (rdata->rp_state != RPORT_ST_FLOGI) { - FC_RPORT_DBG(rdata, "Received a FLOGI response, but in state " - "%s\n", fc_rport_state(rdata)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_rport_error(rdata, fp); - goto err; - } - - if (fc_frame_payload_op(fp) != ELS_LS_ACC) - goto bad; - if (fc_rport_login_complete(rdata, fp)) - goto bad; - - flogi = fc_frame_payload_get(fp, sizeof(*flogi)); - if (!flogi) - goto bad; - r_a_tov = ntohl(flogi->fl_csp.sp_r_a_tov); - if (r_a_tov > rdata->r_a_tov) - rdata->r_a_tov = r_a_tov; - - if (rdata->ids.port_name < lport->wwpn) - fc_rport_enter_plogi(rdata); - else - fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); -out: - fc_frame_free(fp); -err: - mutex_unlock(&rdata->rp_mutex); -put: - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); - return; -bad: - FC_RPORT_DBG(rdata, "Bad FLOGI response\n"); - fc_rport_error_retry(rdata, fp); - goto out; -} - -/** - * fc_rport_enter_flogi() - Send a FLOGI request to the remote port for p-mp - * @rdata: The remote port to send a FLOGI to - * - * Locking Note: The rport lock is expected to be held before calling - * this routine. - */ -static void fc_rport_enter_flogi(struct fc_rport_priv *rdata) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_frame *fp; - - if (!lport->point_to_multipoint) - return fc_rport_enter_plogi(rdata); - - FC_RPORT_DBG(rdata, "Entered FLOGI state from %s state\n", - fc_rport_state(rdata)); - - fc_rport_state_enter(rdata, RPORT_ST_FLOGI); - - fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); - if (!fp) - return fc_rport_error_retry(rdata, fp); - - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_FLOGI, - fc_rport_flogi_resp, rdata, - 2 * lport->r_a_tov)) - fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); -} - -/** - * fc_rport_recv_flogi_req() - Handle Fabric Login (FLOGI) request in p-mp mode - * @lport: The local port that received the PLOGI request - * @rx_fp: The PLOGI request frame - */ -static void fc_rport_recv_flogi_req(struct fc_lport *lport, - struct fc_frame *rx_fp) -{ - struct fc_disc *disc; - struct fc_els_flogi *flp; - struct fc_rport_priv *rdata; - struct fc_frame *fp = rx_fp; - struct fc_seq_els_data rjt_data; - u32 sid; - - sid = fc_frame_sid(fp); - - FC_RPORT_ID_DBG(lport, sid, "Received FLOGI request\n"); - - disc = &lport->disc; - mutex_lock(&disc->disc_mutex); - - if (!lport->point_to_multipoint) { - rjt_data.reason = ELS_RJT_UNSUP; - rjt_data.explan = ELS_EXPL_NONE; - goto reject; - } - - flp = fc_frame_payload_get(fp, sizeof(*flp)); - if (!flp) { - rjt_data.reason = ELS_RJT_LOGIC; - rjt_data.explan = ELS_EXPL_INV_LEN; - goto reject; - } - - rdata = lport->tt.rport_lookup(lport, sid); - if (!rdata) { - rjt_data.reason = ELS_RJT_FIP; - rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; - goto reject; - } - mutex_lock(&rdata->rp_mutex); - - FC_RPORT_DBG(rdata, "Received FLOGI in %s state\n", - fc_rport_state(rdata)); - - switch (rdata->rp_state) { - case RPORT_ST_INIT: - /* - * If received the FLOGI request on RPORT which is INIT state - * (means not transition to FLOGI either fc_rport timeout - * function didn;t trigger or this end hasn;t received - * beacon yet from other end. In that case only, allow RPORT - * state machine to continue, otherwise fall through which - * causes the code to send reject response. - * NOTE; Not checking for FIP->state such as VNMP_UP or - * VNMP_CLAIM because if FIP state is not one of those, - * RPORT wouldn;t have created and 'rport_lookup' would have - * failed anyway in that case. - */ - if (lport->point_to_multipoint) - break; - case RPORT_ST_DELETE: - mutex_unlock(&rdata->rp_mutex); - rjt_data.reason = ELS_RJT_FIP; - rjt_data.explan = ELS_EXPL_NOT_NEIGHBOR; - goto reject; - case RPORT_ST_FLOGI: - case RPORT_ST_PLOGI_WAIT: - case RPORT_ST_PLOGI: - break; - case RPORT_ST_PRLI: - case RPORT_ST_RTV: - case RPORT_ST_READY: - case RPORT_ST_ADISC: - /* - * Set the remote port to be deleted and to then restart. - * This queues work to be sure exchanges are reset. - */ - fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - mutex_unlock(&rdata->rp_mutex); - rjt_data.reason = ELS_RJT_BUSY; - rjt_data.explan = ELS_EXPL_NONE; - goto reject; - } - if (fc_rport_login_complete(rdata, fp)) { - mutex_unlock(&rdata->rp_mutex); - rjt_data.reason = ELS_RJT_LOGIC; - rjt_data.explan = ELS_EXPL_NONE; - goto reject; - } - - fp = fc_frame_alloc(lport, sizeof(*flp)); - if (!fp) - goto out; - - fc_flogi_fill(lport, fp); - flp = fc_frame_payload_get(fp, sizeof(*flp)); - flp->fl_cmd = ELS_LS_ACC; - - fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); - - if (rdata->ids.port_name < lport->wwpn) - fc_rport_enter_plogi(rdata); - else - fc_rport_state_enter(rdata, RPORT_ST_PLOGI_WAIT); -out: - mutex_unlock(&rdata->rp_mutex); - mutex_unlock(&disc->disc_mutex); - fc_frame_free(rx_fp); - return; - -reject: - mutex_unlock(&disc->disc_mutex); - lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); - fc_frame_free(rx_fp); -} - -/** - * fc_rport_plogi_resp() - Handler for ELS PLOGI responses - * @sp: The sequence the PLOGI is on - * @fp: The PLOGI response frame - * @rdata_arg: The remote port that sent the PLOGI response - * - * Locking Note: This function will be called without the rport lock - * held, but it will lock, call an _enter_* function or fc_rport_error - * and then unlock the rport. - */ -static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rdata_arg) -{ - struct fc_rport_priv *rdata = rdata_arg; - struct fc_lport *lport = rdata->local_port; - struct fc_els_flogi *plp = NULL; - u16 csp_seq; - u16 cssp_seq; - u8 op; - - mutex_lock(&rdata->rp_mutex); - - FC_RPORT_DBG(rdata, "Received a PLOGI %s\n", fc_els_resp_type(fp)); - - if (rdata->rp_state != RPORT_ST_PLOGI) { - FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state " - "%s\n", fc_rport_state(rdata)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_rport_error_retry(rdata, fp); - goto err; - } - - op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC && - (plp = fc_frame_payload_get(fp, sizeof(*plp))) != NULL) { - rdata->ids.port_name = get_unaligned_be64(&plp->fl_wwpn); - rdata->ids.node_name = get_unaligned_be64(&plp->fl_wwnn); - - /* save plogi response sp_features for further reference */ - rdata->sp_features = ntohs(plp->fl_csp.sp_features); - - if (lport->point_to_multipoint) - fc_rport_login_complete(rdata, fp); - csp_seq = ntohs(plp->fl_csp.sp_tot_seq); - cssp_seq = ntohs(plp->fl_cssp[3 - 1].cp_con_seq); - if (cssp_seq < csp_seq) - csp_seq = cssp_seq; - rdata->max_seq = csp_seq; - rdata->maxframe_size = fc_plogi_get_maxframe(plp, lport->mfs); - fc_rport_enter_prli(rdata); - } else - fc_rport_error_retry(rdata, fp); - -out: - fc_frame_free(fp); -err: - mutex_unlock(&rdata->rp_mutex); - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); -} - -/** - * fc_rport_enter_plogi() - Send Port Login (PLOGI) request - * @rdata: The remote port to send a PLOGI to - * - * Locking Note: The rport lock is expected to be held before calling - * this routine. - */ -static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_frame *fp; - - FC_RPORT_DBG(rdata, "Port entered PLOGI state from %s state\n", - fc_rport_state(rdata)); - - fc_rport_state_enter(rdata, RPORT_ST_PLOGI); - - rdata->maxframe_size = FC_MIN_MAX_PAYLOAD; - fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi)); - if (!fp) { - FC_RPORT_DBG(rdata, "%s frame alloc failed\n", __func__); - fc_rport_error_retry(rdata, fp); - return; - } - rdata->e_d_tov = lport->e_d_tov; - - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_PLOGI, - fc_rport_plogi_resp, rdata, - 2 * lport->r_a_tov)) - fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); -} - -/** - * fc_rport_prli_resp() - Process Login (PRLI) response handler - * @sp: The sequence the PRLI response was on - * @fp: The PRLI response frame - * @rdata_arg: The remote port that sent the PRLI response - * - * Locking Note: This function will be called without the rport lock - * held, but it will lock, call an _enter_* function or fc_rport_error - * and then unlock the rport. - */ -static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rdata_arg) -{ - struct fc_rport_priv *rdata = rdata_arg; - struct { - struct fc_els_prli prli; - struct fc_els_spp spp; - } *pp; - struct fc_els_spp temp_spp; - struct fc4_prov *prov; - u32 roles = FC_RPORT_ROLE_UNKNOWN; - u32 fcp_parm = 0; - u8 op; - u8 resp_code = 0; - - mutex_lock(&rdata->rp_mutex); - - FC_RPORT_DBG(rdata, "Received a PRLI %s\n", fc_els_resp_type(fp)); - - if (rdata->rp_state != RPORT_ST_PRLI) { - FC_RPORT_DBG(rdata, "Received a PRLI response, but in state " - "%s\n", fc_rport_state(rdata)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_rport_error_retry(rdata, fp); - goto err; - } - - /* reinitialize remote port roles */ - rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; - - op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC) { - pp = fc_frame_payload_get(fp, sizeof(*pp)); - if (!pp) - goto out; - - resp_code = (pp->spp.spp_flags & FC_SPP_RESP_MASK); - FC_RPORT_DBG(rdata, "PRLI spp_flags = 0x%x\n", - pp->spp.spp_flags); - rdata->spp_type = pp->spp.spp_type; - if (resp_code != FC_SPP_RESP_ACK) { - if (resp_code == FC_SPP_RESP_CONF) - fc_rport_error(rdata, fp); - else - fc_rport_error_retry(rdata, fp); - goto out; - } - if (pp->prli.prli_spp_len < sizeof(pp->spp)) - goto out; - - fcp_parm = ntohl(pp->spp.spp_params); - if (fcp_parm & FCP_SPPF_RETRY) - rdata->flags |= FC_RP_FLAGS_RETRY; - if (fcp_parm & FCP_SPPF_CONF_COMPL) - rdata->flags |= FC_RP_FLAGS_CONF_REQ; - - prov = fc_passive_prov[FC_TYPE_FCP]; - if (prov) { - memset(&temp_spp, 0, sizeof(temp_spp)); - prov->prli(rdata, pp->prli.prli_spp_len, - &pp->spp, &temp_spp); - } - - rdata->supported_classes = FC_COS_CLASS3; - if (fcp_parm & FCP_SPPF_INIT_FCN) - roles |= FC_RPORT_ROLE_FCP_INITIATOR; - if (fcp_parm & FCP_SPPF_TARG_FCN) - roles |= FC_RPORT_ROLE_FCP_TARGET; - - rdata->ids.roles = roles; - fc_rport_enter_rtv(rdata); - - } else { - FC_RPORT_DBG(rdata, "Bad ELS response for PRLI command\n"); - fc_rport_error_retry(rdata, fp); - } - -out: - fc_frame_free(fp); -err: - mutex_unlock(&rdata->rp_mutex); - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); -} - -/** - * fc_rport_enter_prli() - Send Process Login (PRLI) request - * @rdata: The remote port to send the PRLI request to - * - * Locking Note: The rport lock is expected to be held before calling - * this routine. - */ -static void fc_rport_enter_prli(struct fc_rport_priv *rdata) -{ - struct fc_lport *lport = rdata->local_port; - struct { - struct fc_els_prli prli; - struct fc_els_spp spp; - } *pp; - struct fc_frame *fp; - struct fc4_prov *prov; - - /* - * If the rport is one of the well known addresses - * we skip PRLI and RTV and go straight to READY. - */ - if (rdata->ids.port_id >= FC_FID_DOM_MGR) { - fc_rport_enter_ready(rdata); - return; - } - - FC_RPORT_DBG(rdata, "Port entered PRLI state from %s state\n", - fc_rport_state(rdata)); - - fc_rport_state_enter(rdata, RPORT_ST_PRLI); - - fp = fc_frame_alloc(lport, sizeof(*pp)); - if (!fp) { - fc_rport_error_retry(rdata, fp); - return; - } - - fc_prli_fill(lport, fp); - - prov = fc_passive_prov[FC_TYPE_FCP]; - if (prov) { - pp = fc_frame_payload_get(fp, sizeof(*pp)); - prov->prli(rdata, sizeof(pp->spp), NULL, &pp->spp); - } - - fc_fill_fc_hdr(fp, FC_RCTL_ELS_REQ, rdata->ids.port_id, - fc_host_port_id(lport->host), FC_TYPE_ELS, - FC_FC_FIRST_SEQ | FC_FC_END_SEQ | FC_FC_SEQ_INIT, 0); - - if (!lport->tt.exch_seq_send(lport, fp, fc_rport_prli_resp, - NULL, rdata, 2 * lport->r_a_tov)) - fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); -} - -/** - * fc_rport_els_rtv_resp() - Handler for Request Timeout Value (RTV) responses - * @sp: The sequence the RTV was on - * @fp: The RTV response frame - * @rdata_arg: The remote port that sent the RTV response - * - * Many targets don't seem to support this. - * - * Locking Note: This function will be called without the rport lock - * held, but it will lock, call an _enter_* function or fc_rport_error - * and then unlock the rport. - */ -static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rdata_arg) -{ - struct fc_rport_priv *rdata = rdata_arg; - u8 op; - - mutex_lock(&rdata->rp_mutex); - - FC_RPORT_DBG(rdata, "Received a RTV %s\n", fc_els_resp_type(fp)); - - if (rdata->rp_state != RPORT_ST_RTV) { - FC_RPORT_DBG(rdata, "Received a RTV response, but in state " - "%s\n", fc_rport_state(rdata)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_rport_error(rdata, fp); - goto err; - } - - op = fc_frame_payload_op(fp); - if (op == ELS_LS_ACC) { - struct fc_els_rtv_acc *rtv; - u32 toq; - u32 tov; - - rtv = fc_frame_payload_get(fp, sizeof(*rtv)); - if (rtv) { - toq = ntohl(rtv->rtv_toq); - tov = ntohl(rtv->rtv_r_a_tov); - if (tov == 0) - tov = 1; - rdata->r_a_tov = tov; - tov = ntohl(rtv->rtv_e_d_tov); - if (toq & FC_ELS_RTV_EDRES) - tov /= 1000000; - if (tov == 0) - tov = 1; - rdata->e_d_tov = tov; - } - } - - fc_rport_enter_ready(rdata); - -out: - fc_frame_free(fp); -err: - mutex_unlock(&rdata->rp_mutex); - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); -} - -/** - * fc_rport_enter_rtv() - Send Request Timeout Value (RTV) request - * @rdata: The remote port to send the RTV request to - * - * Locking Note: The rport lock is expected to be held before calling - * this routine. - */ -static void fc_rport_enter_rtv(struct fc_rport_priv *rdata) -{ - struct fc_frame *fp; - struct fc_lport *lport = rdata->local_port; - - FC_RPORT_DBG(rdata, "Port entered RTV state from %s state\n", - fc_rport_state(rdata)); - - fc_rport_state_enter(rdata, RPORT_ST_RTV); - - fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv)); - if (!fp) { - fc_rport_error_retry(rdata, fp); - return; - } - - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_RTV, - fc_rport_rtv_resp, rdata, - 2 * lport->r_a_tov)) - fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); -} - -/** - * fc_rport_logo_resp() - Handler for logout (LOGO) responses - * @sp: The sequence the LOGO was on - * @fp: The LOGO response frame - * @lport_arg: The local port - */ -static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, - void *lport_arg) -{ - struct fc_lport *lport = lport_arg; - - FC_RPORT_ID_DBG(lport, fc_seq_exch(sp)->did, - "Received a LOGO %s\n", fc_els_resp_type(fp)); - if (IS_ERR(fp)) - return; - fc_frame_free(fp); -} - -/** - * fc_rport_enter_logo() - Send a logout (LOGO) request - * @rdata: The remote port to send the LOGO request to - * - * Locking Note: The rport lock is expected to be held before calling - * this routine. - */ -static void fc_rport_enter_logo(struct fc_rport_priv *rdata) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_frame *fp; - - FC_RPORT_DBG(rdata, "Port sending LOGO from %s state\n", - fc_rport_state(rdata)); - - fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo)); - if (!fp) - return; - (void)lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_LOGO, - fc_rport_logo_resp, lport, 0); -} - -/** - * fc_rport_els_adisc_resp() - Handler for Address Discovery (ADISC) responses - * @sp: The sequence the ADISC response was on - * @fp: The ADISC response frame - * @rdata_arg: The remote port that sent the ADISC response - * - * Locking Note: This function will be called without the rport lock - * held, but it will lock, call an _enter_* function or fc_rport_error - * and then unlock the rport. - */ -static void fc_rport_adisc_resp(struct fc_seq *sp, struct fc_frame *fp, - void *rdata_arg) -{ - struct fc_rport_priv *rdata = rdata_arg; - struct fc_els_adisc *adisc; - u8 op; - - mutex_lock(&rdata->rp_mutex); - - FC_RPORT_DBG(rdata, "Received a ADISC response\n"); - - if (rdata->rp_state != RPORT_ST_ADISC) { - FC_RPORT_DBG(rdata, "Received a ADISC resp but in state %s\n", - fc_rport_state(rdata)); - if (IS_ERR(fp)) - goto err; - goto out; - } - - if (IS_ERR(fp)) { - fc_rport_error(rdata, fp); - goto err; - } - - /* - * If address verification failed. Consider us logged out of the rport. - * Since the rport is still in discovery, we want to be - * logged in, so go to PLOGI state. Otherwise, go back to READY. - */ - op = fc_frame_payload_op(fp); - adisc = fc_frame_payload_get(fp, sizeof(*adisc)); - if (op != ELS_LS_ACC || !adisc || - ntoh24(adisc->adisc_port_id) != rdata->ids.port_id || - get_unaligned_be64(&adisc->adisc_wwpn) != rdata->ids.port_name || - get_unaligned_be64(&adisc->adisc_wwnn) != rdata->ids.node_name) { - FC_RPORT_DBG(rdata, "ADISC error or mismatch\n"); - fc_rport_enter_flogi(rdata); - } else { - FC_RPORT_DBG(rdata, "ADISC OK\n"); - fc_rport_enter_ready(rdata); - } -out: - fc_frame_free(fp); -err: - mutex_unlock(&rdata->rp_mutex); - kref_put(&rdata->kref, rdata->local_port->tt.rport_destroy); -} - -/** - * fc_rport_enter_adisc() - Send Address Discover (ADISC) request - * @rdata: The remote port to send the ADISC request to - * - * Locking Note: The rport lock is expected to be held before calling - * this routine. - */ -static void fc_rport_enter_adisc(struct fc_rport_priv *rdata) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_frame *fp; - - FC_RPORT_DBG(rdata, "sending ADISC from %s state\n", - fc_rport_state(rdata)); - - fc_rport_state_enter(rdata, RPORT_ST_ADISC); - - fp = fc_frame_alloc(lport, sizeof(struct fc_els_adisc)); - if (!fp) { - fc_rport_error_retry(rdata, fp); - return; - } - if (!lport->tt.elsct_send(lport, rdata->ids.port_id, fp, ELS_ADISC, - fc_rport_adisc_resp, rdata, - 2 * lport->r_a_tov)) - fc_rport_error_retry(rdata, NULL); - else - kref_get(&rdata->kref); -} - -/** - * fc_rport_recv_adisc_req() - Handler for Address Discovery (ADISC) requests - * @rdata: The remote port that sent the ADISC request - * @in_fp: The ADISC request frame - * - * Locking Note: Called with the lport and rport locks held. - */ -static void fc_rport_recv_adisc_req(struct fc_rport_priv *rdata, - struct fc_frame *in_fp) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_frame *fp; - struct fc_els_adisc *adisc; - struct fc_seq_els_data rjt_data; - - FC_RPORT_DBG(rdata, "Received ADISC request\n"); - - adisc = fc_frame_payload_get(in_fp, sizeof(*adisc)); - if (!adisc) { - rjt_data.reason = ELS_RJT_PROT; - rjt_data.explan = ELS_EXPL_INV_LEN; - lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); - goto drop; - } - - fp = fc_frame_alloc(lport, sizeof(*adisc)); - if (!fp) - goto drop; - fc_adisc_fill(lport, fp); - adisc = fc_frame_payload_get(fp, sizeof(*adisc)); - adisc->adisc_cmd = ELS_LS_ACC; - fc_fill_reply_hdr(fp, in_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); -drop: - fc_frame_free(in_fp); -} - -/** - * fc_rport_recv_rls_req() - Handle received Read Link Status request - * @rdata: The remote port that sent the RLS request - * @rx_fp: The PRLI request frame - * - * Locking Note: The rport lock is expected to be held before calling - * this function. - */ -static void fc_rport_recv_rls_req(struct fc_rport_priv *rdata, - struct fc_frame *rx_fp) - -{ - struct fc_lport *lport = rdata->local_port; - struct fc_frame *fp; - struct fc_els_rls *rls; - struct fc_els_rls_resp *rsp; - struct fc_els_lesb *lesb; - struct fc_seq_els_data rjt_data; - struct fc_host_statistics *hst; - - FC_RPORT_DBG(rdata, "Received RLS request while in state %s\n", - fc_rport_state(rdata)); - - rls = fc_frame_payload_get(rx_fp, sizeof(*rls)); - if (!rls) { - rjt_data.reason = ELS_RJT_PROT; - rjt_data.explan = ELS_EXPL_INV_LEN; - goto out_rjt; - } - - fp = fc_frame_alloc(lport, sizeof(*rsp)); - if (!fp) { - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_INSUF_RES; - goto out_rjt; - } - - rsp = fc_frame_payload_get(fp, sizeof(*rsp)); - memset(rsp, 0, sizeof(*rsp)); - rsp->rls_cmd = ELS_LS_ACC; - lesb = &rsp->rls_lesb; - if (lport->tt.get_lesb) { - /* get LESB from LLD if it supports it */ - lport->tt.get_lesb(lport, lesb); - } else { - fc_get_host_stats(lport->host); - hst = &lport->host_stats; - lesb->lesb_link_fail = htonl(hst->link_failure_count); - lesb->lesb_sync_loss = htonl(hst->loss_of_sync_count); - lesb->lesb_sig_loss = htonl(hst->loss_of_signal_count); - lesb->lesb_prim_err = htonl(hst->prim_seq_protocol_err_count); - lesb->lesb_inv_word = htonl(hst->invalid_tx_word_count); - lesb->lesb_inv_crc = htonl(hst->invalid_crc_count); - } - - fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); - goto out; - -out_rjt: - lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); -out: - fc_frame_free(rx_fp); -} - -/** - * fc_rport_recv_els_req() - Handler for validated ELS requests - * @lport: The local port that received the ELS request - * @fp: The ELS request frame - * - * Handle incoming ELS requests that require port login. - * The ELS opcode has already been validated by the caller. - * - * Locking Note: Called with the lport lock held. - */ -static void fc_rport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) -{ - struct fc_rport_priv *rdata; - struct fc_seq_els_data els_data; - - mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_lookup(lport, fc_frame_sid(fp)); - if (!rdata) { - mutex_unlock(&lport->disc.disc_mutex); - goto reject; - } - mutex_lock(&rdata->rp_mutex); - mutex_unlock(&lport->disc.disc_mutex); - - switch (rdata->rp_state) { - case RPORT_ST_PRLI: - case RPORT_ST_RTV: - case RPORT_ST_READY: - case RPORT_ST_ADISC: - break; - default: - mutex_unlock(&rdata->rp_mutex); - goto reject; - } - - switch (fc_frame_payload_op(fp)) { - case ELS_PRLI: - fc_rport_recv_prli_req(rdata, fp); - break; - case ELS_PRLO: - fc_rport_recv_prlo_req(rdata, fp); - break; - case ELS_ADISC: - fc_rport_recv_adisc_req(rdata, fp); - break; - case ELS_RRQ: - lport->tt.seq_els_rsp_send(fp, ELS_RRQ, NULL); - fc_frame_free(fp); - break; - case ELS_REC: - lport->tt.seq_els_rsp_send(fp, ELS_REC, NULL); - fc_frame_free(fp); - break; - case ELS_RLS: - fc_rport_recv_rls_req(rdata, fp); - break; - default: - fc_frame_free(fp); /* can't happen */ - break; - } - - mutex_unlock(&rdata->rp_mutex); - return; - -reject: - els_data.reason = ELS_RJT_UNAB; - els_data.explan = ELS_EXPL_PLOGI_REQD; - lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data); - fc_frame_free(fp); -} - -/** - * fc_rport_recv_req() - Handler for requests - * @lport: The local port that received the request - * @fp: The request frame - * - * Locking Note: Called with the lport lock held. - */ -static void fc_rport_recv_req(struct fc_lport *lport, struct fc_frame *fp) -{ - struct fc_seq_els_data els_data; - - /* - * Handle FLOGI, PLOGI and LOGO requests separately, since they - * don't require prior login. - * Check for unsupported opcodes first and reject them. - * For some ops, it would be incorrect to reject with "PLOGI required". - */ - switch (fc_frame_payload_op(fp)) { - case ELS_FLOGI: - fc_rport_recv_flogi_req(lport, fp); - break; - case ELS_PLOGI: - fc_rport_recv_plogi_req(lport, fp); - break; - case ELS_LOGO: - fc_rport_recv_logo_req(lport, fp); - break; - case ELS_PRLI: - case ELS_PRLO: - case ELS_ADISC: - case ELS_RRQ: - case ELS_REC: - case ELS_RLS: - fc_rport_recv_els_req(lport, fp); - break; - default: - els_data.reason = ELS_RJT_UNSUP; - els_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &els_data); - fc_frame_free(fp); - break; - } -} - -/** - * fc_rport_recv_plogi_req() - Handler for Port Login (PLOGI) requests - * @lport: The local port that received the PLOGI request - * @rx_fp: The PLOGI request frame - * - * Locking Note: The rport lock is held before calling this function. - */ -static void fc_rport_recv_plogi_req(struct fc_lport *lport, - struct fc_frame *rx_fp) -{ - struct fc_disc *disc; - struct fc_rport_priv *rdata; - struct fc_frame *fp = rx_fp; - struct fc_els_flogi *pl; - struct fc_seq_els_data rjt_data; - u32 sid; - - sid = fc_frame_sid(fp); - - FC_RPORT_ID_DBG(lport, sid, "Received PLOGI request\n"); - - pl = fc_frame_payload_get(fp, sizeof(*pl)); - if (!pl) { - FC_RPORT_ID_DBG(lport, sid, "Received PLOGI too short\n"); - rjt_data.reason = ELS_RJT_PROT; - rjt_data.explan = ELS_EXPL_INV_LEN; - goto reject; - } - - disc = &lport->disc; - mutex_lock(&disc->disc_mutex); - rdata = lport->tt.rport_create(lport, sid); - if (!rdata) { - mutex_unlock(&disc->disc_mutex); - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_INSUF_RES; - goto reject; - } - - mutex_lock(&rdata->rp_mutex); - mutex_unlock(&disc->disc_mutex); - - rdata->ids.port_name = get_unaligned_be64(&pl->fl_wwpn); - rdata->ids.node_name = get_unaligned_be64(&pl->fl_wwnn); - - /* - * If the rport was just created, possibly due to the incoming PLOGI, - * set the state appropriately and accept the PLOGI. - * - * If we had also sent a PLOGI, and if the received PLOGI is from a - * higher WWPN, we accept it, otherwise an LS_RJT is sent with reason - * "command already in progress". - * - * XXX TBD: If the session was ready before, the PLOGI should result in - * all outstanding exchanges being reset. - */ - switch (rdata->rp_state) { - case RPORT_ST_INIT: - FC_RPORT_DBG(rdata, "Received PLOGI in INIT state\n"); - break; - case RPORT_ST_PLOGI_WAIT: - FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI_WAIT state\n"); - break; - case RPORT_ST_PLOGI: - FC_RPORT_DBG(rdata, "Received PLOGI in PLOGI state\n"); - if (rdata->ids.port_name < lport->wwpn) { - mutex_unlock(&rdata->rp_mutex); - rjt_data.reason = ELS_RJT_INPROG; - rjt_data.explan = ELS_EXPL_NONE; - goto reject; - } - break; - case RPORT_ST_PRLI: - case RPORT_ST_RTV: - case RPORT_ST_READY: - case RPORT_ST_ADISC: - FC_RPORT_DBG(rdata, "Received PLOGI in logged-in state %d " - "- ignored for now\n", rdata->rp_state); - /* XXX TBD - should reset */ - break; - case RPORT_ST_FLOGI: - case RPORT_ST_DELETE: - FC_RPORT_DBG(rdata, "Received PLOGI in state %s - send busy\n", - fc_rport_state(rdata)); - mutex_unlock(&rdata->rp_mutex); - rjt_data.reason = ELS_RJT_BUSY; - rjt_data.explan = ELS_EXPL_NONE; - goto reject; - } - - /* - * Get session payload size from incoming PLOGI. - */ - rdata->maxframe_size = fc_plogi_get_maxframe(pl, lport->mfs); - - /* - * Send LS_ACC. If this fails, the originator should retry. - */ - fp = fc_frame_alloc(lport, sizeof(*pl)); - if (!fp) - goto out; - - fc_plogi_fill(lport, fp, ELS_LS_ACC); - fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); - fc_rport_enter_prli(rdata); -out: - mutex_unlock(&rdata->rp_mutex); - fc_frame_free(rx_fp); - return; - -reject: - lport->tt.seq_els_rsp_send(fp, ELS_LS_RJT, &rjt_data); - fc_frame_free(fp); -} - -/** - * fc_rport_recv_prli_req() - Handler for process login (PRLI) requests - * @rdata: The remote port that sent the PRLI request - * @rx_fp: The PRLI request frame - * - * Locking Note: The rport lock is exected to be held before calling - * this function. - */ -static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, - struct fc_frame *rx_fp) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_frame *fp; - struct { - struct fc_els_prli prli; - struct fc_els_spp spp; - } *pp; - struct fc_els_spp *rspp; /* request service param page */ - struct fc_els_spp *spp; /* response spp */ - unsigned int len; - unsigned int plen; - enum fc_els_spp_resp resp; - enum fc_els_spp_resp passive; - struct fc_seq_els_data rjt_data; - struct fc4_prov *prov; - - FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", - fc_rport_state(rdata)); - - len = fr_len(rx_fp) - sizeof(struct fc_frame_header); - pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); - if (!pp) - goto reject_len; - plen = ntohs(pp->prli.prli_len); - if ((plen % 4) != 0 || plen > len || plen < 16) - goto reject_len; - if (plen < len) - len = plen; - plen = pp->prli.prli_spp_len; - if ((plen % 4) != 0 || plen < sizeof(*spp) || - plen > len || len < sizeof(*pp) || plen < 12) - goto reject_len; - rspp = &pp->spp; - - fp = fc_frame_alloc(lport, len); - if (!fp) { - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_INSUF_RES; - goto reject; - } - pp = fc_frame_payload_get(fp, len); - WARN_ON(!pp); - memset(pp, 0, len); - pp->prli.prli_cmd = ELS_LS_ACC; - pp->prli.prli_spp_len = plen; - pp->prli.prli_len = htons(len); - len -= sizeof(struct fc_els_prli); - - /* - * Go through all the service parameter pages and build - * response. If plen indicates longer SPP than standard, - * use that. The entire response has been pre-cleared above. - */ - spp = &pp->spp; - mutex_lock(&fc_prov_mutex); - while (len >= plen) { - rdata->spp_type = rspp->spp_type; - spp->spp_type = rspp->spp_type; - spp->spp_type_ext = rspp->spp_type_ext; - resp = 0; - - if (rspp->spp_type < FC_FC4_PROV_SIZE) { - prov = fc_active_prov[rspp->spp_type]; - if (prov) - resp = prov->prli(rdata, plen, rspp, spp); - prov = fc_passive_prov[rspp->spp_type]; - if (prov) { - passive = prov->prli(rdata, plen, rspp, spp); - if (!resp || passive == FC_SPP_RESP_ACK) - resp = passive; - } - } - if (!resp) { - if (spp->spp_flags & FC_SPP_EST_IMG_PAIR) - resp |= FC_SPP_RESP_CONF; - else - resp |= FC_SPP_RESP_INVL; - } - spp->spp_flags |= resp; - len -= plen; - rspp = (struct fc_els_spp *)((char *)rspp + plen); - spp = (struct fc_els_spp *)((char *)spp + plen); - } - mutex_unlock(&fc_prov_mutex); - - /* - * Send LS_ACC. If this fails, the originator should retry. - */ - fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); - - switch (rdata->rp_state) { - case RPORT_ST_PRLI: - fc_rport_enter_ready(rdata); - break; - default: - break; - } - goto drop; - -reject_len: - rjt_data.reason = ELS_RJT_PROT; - rjt_data.explan = ELS_EXPL_INV_LEN; -reject: - lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); -drop: - fc_frame_free(rx_fp); -} - -/** - * fc_rport_recv_prlo_req() - Handler for process logout (PRLO) requests - * @rdata: The remote port that sent the PRLO request - * @rx_fp: The PRLO request frame - * - * Locking Note: The rport lock is exected to be held before calling - * this function. - */ -static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata, - struct fc_frame *rx_fp) -{ - struct fc_lport *lport = rdata->local_port; - struct fc_frame *fp; - struct { - struct fc_els_prlo prlo; - struct fc_els_spp spp; - } *pp; - struct fc_els_spp *rspp; /* request service param page */ - struct fc_els_spp *spp; /* response spp */ - unsigned int len; - unsigned int plen; - struct fc_seq_els_data rjt_data; - - FC_RPORT_DBG(rdata, "Received PRLO request while in state %s\n", - fc_rport_state(rdata)); - - len = fr_len(rx_fp) - sizeof(struct fc_frame_header); - pp = fc_frame_payload_get(rx_fp, sizeof(*pp)); - if (!pp) - goto reject_len; - plen = ntohs(pp->prlo.prlo_len); - if (plen != 20) - goto reject_len; - if (plen < len) - len = plen; - - rspp = &pp->spp; - - fp = fc_frame_alloc(lport, len); - if (!fp) { - rjt_data.reason = ELS_RJT_UNAB; - rjt_data.explan = ELS_EXPL_INSUF_RES; - goto reject; - } - - pp = fc_frame_payload_get(fp, len); - WARN_ON(!pp); - memset(pp, 0, len); - pp->prlo.prlo_cmd = ELS_LS_ACC; - pp->prlo.prlo_obs = 0x10; - pp->prlo.prlo_len = htons(len); - spp = &pp->spp; - spp->spp_type = rspp->spp_type; - spp->spp_type_ext = rspp->spp_type_ext; - spp->spp_flags = FC_SPP_RESP_ACK; - - fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - - fc_fill_reply_hdr(fp, rx_fp, FC_RCTL_ELS_REP, 0); - lport->tt.frame_send(lport, fp); - goto drop; - -reject_len: - rjt_data.reason = ELS_RJT_PROT; - rjt_data.explan = ELS_EXPL_INV_LEN; -reject: - lport->tt.seq_els_rsp_send(rx_fp, ELS_LS_RJT, &rjt_data); -drop: - fc_frame_free(rx_fp); -} - -/** - * fc_rport_recv_logo_req() - Handler for logout (LOGO) requests - * @lport: The local port that received the LOGO request - * @fp: The LOGO request frame - * - * Locking Note: The rport lock is exected to be held before calling - * this function. - */ -static void fc_rport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) -{ - struct fc_rport_priv *rdata; - u32 sid; - - lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); - - sid = fc_frame_sid(fp); - - mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_lookup(lport, sid); - if (rdata) { - mutex_lock(&rdata->rp_mutex); - FC_RPORT_DBG(rdata, "Received LOGO request while in state %s\n", - fc_rport_state(rdata)); - - fc_rport_enter_delete(rdata, RPORT_EV_LOGO); - mutex_unlock(&rdata->rp_mutex); - } else - FC_RPORT_ID_DBG(lport, sid, - "Received LOGO from non-logged-in port\n"); - mutex_unlock(&lport->disc.disc_mutex); - fc_frame_free(fp); -} - -/** - * fc_rport_flush_queue() - Flush the rport_event_queue - */ -static void fc_rport_flush_queue(void) -{ - flush_workqueue(rport_event_queue); -} - -/** - * fc_rport_init() - Initialize the remote port layer for a local port - * @lport: The local port to initialize the remote port layer for - */ -int fc_rport_init(struct fc_lport *lport) -{ - if (!lport->tt.rport_lookup) - lport->tt.rport_lookup = fc_rport_lookup; - - if (!lport->tt.rport_create) - lport->tt.rport_create = fc_rport_create; - - if (!lport->tt.rport_login) - lport->tt.rport_login = fc_rport_login; - - if (!lport->tt.rport_logoff) - lport->tt.rport_logoff = fc_rport_logoff; - - if (!lport->tt.rport_recv_req) - lport->tt.rport_recv_req = fc_rport_recv_req; - - if (!lport->tt.rport_flush_queue) - lport->tt.rport_flush_queue = fc_rport_flush_queue; - - if (!lport->tt.rport_destroy) - lport->tt.rport_destroy = fc_rport_destroy; - - return 0; -} -EXPORT_SYMBOL(fc_rport_init); - -/** - * fc_rport_fcp_prli() - Handle incoming PRLI for the FCP initiator. - * @rdata: remote port private - * @spp_len: service parameter page length - * @rspp: received service parameter page - * @spp: response service parameter page - * - * Returns the value for the response code to be placed in spp_flags; - * Returns 0 if not an initiator. - */ -static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len, - const struct fc_els_spp *rspp, - struct fc_els_spp *spp) -{ - struct fc_lport *lport = rdata->local_port; - u32 fcp_parm; - - fcp_parm = ntohl(rspp->spp_params); - rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN; - if (fcp_parm & FCP_SPPF_INIT_FCN) - rdata->ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; - if (fcp_parm & FCP_SPPF_TARG_FCN) - rdata->ids.roles |= FC_RPORT_ROLE_FCP_TARGET; - if (fcp_parm & FCP_SPPF_RETRY) - rdata->flags |= FC_RP_FLAGS_RETRY; - rdata->supported_classes = FC_COS_CLASS3; - - if (!(lport->service_params & FC_RPORT_ROLE_FCP_INITIATOR)) - return 0; - - spp->spp_flags |= rspp->spp_flags & FC_SPP_EST_IMG_PAIR; - - /* - * OR in our service parameters with other providers (target), if any. - */ - fcp_parm = ntohl(spp->spp_params); - spp->spp_params = htonl(fcp_parm | lport->service_params); - return FC_SPP_RESP_ACK; -} - -/* - * FC-4 provider ops for FCP initiator. - */ -struct fc4_prov fc_rport_fcp_init = { - .prli = fc_rport_fcp_prli, -}; - -/** - * fc_rport_t0_prli() - Handle incoming PRLI parameters for type 0 - * @rdata: remote port private - * @spp_len: service parameter page length - * @rspp: received service parameter page - * @spp: response service parameter page - */ -static int fc_rport_t0_prli(struct fc_rport_priv *rdata, u32 spp_len, - const struct fc_els_spp *rspp, - struct fc_els_spp *spp) -{ - if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR) - return FC_SPP_RESP_INVL; - return FC_SPP_RESP_ACK; -} - -/* - * FC-4 provider ops for type 0 service parameters. - * - * This handles the special case of type 0 which is always successful - * but doesn't do anything otherwise. - */ -struct fc4_prov fc_rport_t0_prov = { - .prli = fc_rport_t0_prli, -}; - -/** - * fc_setup_rport() - Initialize the rport_event_queue - */ -int fc_setup_rport(void) -{ - rport_event_queue = create_singlethread_workqueue("fc_rport_eq"); - if (!rport_event_queue) - return -ENOMEM; - return 0; -} - -/** - * fc_destroy_rport() - Destroy the rport_event_queue - */ -void fc_destroy_rport(void) -{ - destroy_workqueue(rport_event_queue); -} - -/** - * fc_rport_terminate_io() - Stop all outstanding I/O on a remote port - * @rport: The remote port whose I/O should be terminated - */ -void fc_rport_terminate_io(struct fc_rport *rport) -{ - struct fc_rport_libfc_priv *rpriv = rport->dd_data; - struct fc_lport *lport = rpriv->local_port; - - lport->tt.exch_mgr_reset(lport, 0, rport->port_id); - lport->tt.exch_mgr_reset(lport, rport->port_id, 0); -} -EXPORT_SYMBOL(fc_rport_terminate_io); diff --git a/ANDROID_3.4.5/drivers/scsi/libiscsi.c b/ANDROID_3.4.5/drivers/scsi/libiscsi.c deleted file mode 100644 index 82c3fd4b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libiscsi.c +++ /dev/null @@ -1,3472 +0,0 @@ -/* - * iSCSI lib functions - * - * Copyright (C) 2006 Red Hat, Inc. All rights reserved. - * Copyright (C) 2004 - 2006 Mike Christie - * Copyright (C) 2004 - 2005 Dmitry Yusupov - * Copyright (C) 2004 - 2005 Alex Aizman - * maintained by open-iscsi@googlegroups.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int iscsi_dbg_lib_conn; -module_param_named(debug_libiscsi_conn, iscsi_dbg_lib_conn, int, - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_libiscsi_conn, - "Turn on debugging for connections in libiscsi module. " - "Set to 1 to turn on, and zero to turn off. Default is off."); - -static int iscsi_dbg_lib_session; -module_param_named(debug_libiscsi_session, iscsi_dbg_lib_session, int, - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_libiscsi_session, - "Turn on debugging for sessions in libiscsi module. " - "Set to 1 to turn on, and zero to turn off. Default is off."); - -static int iscsi_dbg_lib_eh; -module_param_named(debug_libiscsi_eh, iscsi_dbg_lib_eh, int, - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_libiscsi_eh, - "Turn on debugging for error handling in libiscsi module. " - "Set to 1 to turn on, and zero to turn off. Default is off."); - -#define ISCSI_DBG_CONN(_conn, dbg_fmt, arg...) \ - do { \ - if (iscsi_dbg_lib_conn) \ - iscsi_conn_printk(KERN_INFO, _conn, \ - "%s " dbg_fmt, \ - __func__, ##arg); \ - } while (0); - -#define ISCSI_DBG_SESSION(_session, dbg_fmt, arg...) \ - do { \ - if (iscsi_dbg_lib_session) \ - iscsi_session_printk(KERN_INFO, _session, \ - "%s " dbg_fmt, \ - __func__, ##arg); \ - } while (0); - -#define ISCSI_DBG_EH(_session, dbg_fmt, arg...) \ - do { \ - if (iscsi_dbg_lib_eh) \ - iscsi_session_printk(KERN_INFO, _session, \ - "%s " dbg_fmt, \ - __func__, ##arg); \ - } while (0); - -inline void iscsi_conn_queue_work(struct iscsi_conn *conn) -{ - struct Scsi_Host *shost = conn->session->host; - struct iscsi_host *ihost = shost_priv(shost); - - if (ihost->workq) - queue_work(ihost->workq, &conn->xmitwork); -} -EXPORT_SYMBOL_GPL(iscsi_conn_queue_work); - -static void __iscsi_update_cmdsn(struct iscsi_session *session, - uint32_t exp_cmdsn, uint32_t max_cmdsn) -{ - /* - * standard specifies this check for when to update expected and - * max sequence numbers - */ - if (iscsi_sna_lt(max_cmdsn, exp_cmdsn - 1)) - return; - - if (exp_cmdsn != session->exp_cmdsn && - !iscsi_sna_lt(exp_cmdsn, session->exp_cmdsn)) - session->exp_cmdsn = exp_cmdsn; - - if (max_cmdsn != session->max_cmdsn && - !iscsi_sna_lt(max_cmdsn, session->max_cmdsn)) { - session->max_cmdsn = max_cmdsn; - /* - * if the window closed with IO queued, then kick the - * xmit thread - */ - if (!list_empty(&session->leadconn->cmdqueue) || - !list_empty(&session->leadconn->mgmtqueue)) - iscsi_conn_queue_work(session->leadconn); - } -} - -void iscsi_update_cmdsn(struct iscsi_session *session, struct iscsi_nopin *hdr) -{ - __iscsi_update_cmdsn(session, be32_to_cpu(hdr->exp_cmdsn), - be32_to_cpu(hdr->max_cmdsn)); -} -EXPORT_SYMBOL_GPL(iscsi_update_cmdsn); - -/** - * iscsi_prep_data_out_pdu - initialize Data-Out - * @task: scsi command task - * @r2t: R2T info - * @hdr: iscsi data in pdu - * - * Notes: - * Initialize Data-Out within this R2T sequence and finds - * proper data_offset within this SCSI command. - * - * This function is called with connection lock taken. - **/ -void iscsi_prep_data_out_pdu(struct iscsi_task *task, struct iscsi_r2t_info *r2t, - struct iscsi_data *hdr) -{ - struct iscsi_conn *conn = task->conn; - unsigned int left = r2t->data_length - r2t->sent; - - task->hdr_len = sizeof(struct iscsi_data); - - memset(hdr, 0, sizeof(struct iscsi_data)); - hdr->ttt = r2t->ttt; - hdr->datasn = cpu_to_be32(r2t->datasn); - r2t->datasn++; - hdr->opcode = ISCSI_OP_SCSI_DATA_OUT; - hdr->lun = task->lun; - hdr->itt = task->hdr_itt; - hdr->exp_statsn = r2t->exp_statsn; - hdr->offset = cpu_to_be32(r2t->data_offset + r2t->sent); - if (left > conn->max_xmit_dlength) { - hton24(hdr->dlength, conn->max_xmit_dlength); - r2t->data_count = conn->max_xmit_dlength; - hdr->flags = 0; - } else { - hton24(hdr->dlength, left); - r2t->data_count = left; - hdr->flags = ISCSI_FLAG_CMD_FINAL; - } - conn->dataout_pdus_cnt++; -} -EXPORT_SYMBOL_GPL(iscsi_prep_data_out_pdu); - -static int iscsi_add_hdr(struct iscsi_task *task, unsigned len) -{ - unsigned exp_len = task->hdr_len + len; - - if (exp_len > task->hdr_max) { - WARN_ON(1); - return -EINVAL; - } - - WARN_ON(len & (ISCSI_PAD_LEN - 1)); /* caller must pad the AHS */ - task->hdr_len = exp_len; - return 0; -} - -/* - * make an extended cdb AHS - */ -static int iscsi_prep_ecdb_ahs(struct iscsi_task *task) -{ - struct scsi_cmnd *cmd = task->sc; - unsigned rlen, pad_len; - unsigned short ahslength; - struct iscsi_ecdb_ahdr *ecdb_ahdr; - int rc; - - ecdb_ahdr = iscsi_next_hdr(task); - rlen = cmd->cmd_len - ISCSI_CDB_SIZE; - - BUG_ON(rlen > sizeof(ecdb_ahdr->ecdb)); - ahslength = rlen + sizeof(ecdb_ahdr->reserved); - - pad_len = iscsi_padding(rlen); - - rc = iscsi_add_hdr(task, sizeof(ecdb_ahdr->ahslength) + - sizeof(ecdb_ahdr->ahstype) + ahslength + pad_len); - if (rc) - return rc; - - if (pad_len) - memset(&ecdb_ahdr->ecdb[rlen], 0, pad_len); - - ecdb_ahdr->ahslength = cpu_to_be16(ahslength); - ecdb_ahdr->ahstype = ISCSI_AHSTYPE_CDB; - ecdb_ahdr->reserved = 0; - memcpy(ecdb_ahdr->ecdb, cmd->cmnd + ISCSI_CDB_SIZE, rlen); - - ISCSI_DBG_SESSION(task->conn->session, - "iscsi_prep_ecdb_ahs: varlen_cdb_len %d " - "rlen %d pad_len %d ahs_length %d iscsi_headers_size " - "%u\n", cmd->cmd_len, rlen, pad_len, ahslength, - task->hdr_len); - return 0; -} - -static int iscsi_prep_bidi_ahs(struct iscsi_task *task) -{ - struct scsi_cmnd *sc = task->sc; - struct iscsi_rlength_ahdr *rlen_ahdr; - int rc; - - rlen_ahdr = iscsi_next_hdr(task); - rc = iscsi_add_hdr(task, sizeof(*rlen_ahdr)); - if (rc) - return rc; - - rlen_ahdr->ahslength = - cpu_to_be16(sizeof(rlen_ahdr->read_length) + - sizeof(rlen_ahdr->reserved)); - rlen_ahdr->ahstype = ISCSI_AHSTYPE_RLENGTH; - rlen_ahdr->reserved = 0; - rlen_ahdr->read_length = cpu_to_be32(scsi_in(sc)->length); - - ISCSI_DBG_SESSION(task->conn->session, - "bidi-in rlen_ahdr->read_length(%d) " - "rlen_ahdr->ahslength(%d)\n", - be32_to_cpu(rlen_ahdr->read_length), - be16_to_cpu(rlen_ahdr->ahslength)); - return 0; -} - -/** - * iscsi_check_tmf_restrictions - check if a task is affected by TMF - * @task: iscsi task - * @opcode: opcode to check for - * - * During TMF a task has to be checked if it's affected. - * All unrelated I/O can be passed through, but I/O to the - * affected LUN should be restricted. - * If 'fast_abort' is set we won't be sending any I/O to the - * affected LUN. - * Otherwise the target is waiting for all TTTs to be completed, - * so we have to send all outstanding Data-Out PDUs to the target. - */ -static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode) -{ - struct iscsi_conn *conn = task->conn; - struct iscsi_tm *tmf = &conn->tmhdr; - unsigned int hdr_lun; - - if (conn->tmf_state == TMF_INITIAL) - return 0; - - if ((tmf->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_TMFUNC) - return 0; - - switch (ISCSI_TM_FUNC_VALUE(tmf)) { - case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: - /* - * Allow PDUs for unrelated LUNs - */ - hdr_lun = scsilun_to_int(&tmf->lun); - if (hdr_lun != task->sc->device->lun) - return 0; - /* fall through */ - case ISCSI_TM_FUNC_TARGET_WARM_RESET: - /* - * Fail all SCSI cmd PDUs - */ - if (opcode != ISCSI_OP_SCSI_DATA_OUT) { - iscsi_conn_printk(KERN_INFO, conn, - "task [op %x/%x itt " - "0x%x/0x%x] " - "rejected.\n", - task->hdr->opcode, opcode, - task->itt, task->hdr_itt); - return -EACCES; - } - /* - * And also all data-out PDUs in response to R2T - * if fast_abort is set. - */ - if (conn->session->fast_abort) { - iscsi_conn_printk(KERN_INFO, conn, - "task [op %x/%x itt " - "0x%x/0x%x] fast abort.\n", - task->hdr->opcode, opcode, - task->itt, task->hdr_itt); - return -EACCES; - } - break; - case ISCSI_TM_FUNC_ABORT_TASK: - /* - * the caller has already checked if the task - * they want to abort was in the pending queue so if - * we are here the cmd pdu has gone out already, and - * we will only hit this for data-outs - */ - if (opcode == ISCSI_OP_SCSI_DATA_OUT && - task->hdr_itt == tmf->rtt) { - ISCSI_DBG_SESSION(conn->session, - "Preventing task %x/%x from sending " - "data-out due to abort task in " - "progress\n", task->itt, - task->hdr_itt); - return -EACCES; - } - break; - } - - return 0; -} - -/** - * iscsi_prep_scsi_cmd_pdu - prep iscsi scsi cmd pdu - * @task: iscsi task - * - * Prep basic iSCSI PDU fields for a scsi cmd pdu. The LLD should set - * fields like dlength or final based on how much data it sends - */ -static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) -{ - struct iscsi_conn *conn = task->conn; - struct iscsi_session *session = conn->session; - struct scsi_cmnd *sc = task->sc; - struct iscsi_scsi_req *hdr; - unsigned hdrlength, cmd_len; - itt_t itt; - int rc; - - rc = iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_CMD); - if (rc) - return rc; - - if (conn->session->tt->alloc_pdu) { - rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_CMD); - if (rc) - return rc; - } - hdr = (struct iscsi_scsi_req *)task->hdr; - itt = hdr->itt; - memset(hdr, 0, sizeof(*hdr)); - - if (session->tt->parse_pdu_itt) - hdr->itt = task->hdr_itt = itt; - else - hdr->itt = task->hdr_itt = build_itt(task->itt, - task->conn->session->age); - task->hdr_len = 0; - rc = iscsi_add_hdr(task, sizeof(*hdr)); - if (rc) - return rc; - hdr->opcode = ISCSI_OP_SCSI_CMD; - hdr->flags = ISCSI_ATTR_SIMPLE; - int_to_scsilun(sc->device->lun, &hdr->lun); - task->lun = hdr->lun; - hdr->exp_statsn = cpu_to_be32(conn->exp_statsn); - cmd_len = sc->cmd_len; - if (cmd_len < ISCSI_CDB_SIZE) - memset(&hdr->cdb[cmd_len], 0, ISCSI_CDB_SIZE - cmd_len); - else if (cmd_len > ISCSI_CDB_SIZE) { - rc = iscsi_prep_ecdb_ahs(task); - if (rc) - return rc; - cmd_len = ISCSI_CDB_SIZE; - } - memcpy(hdr->cdb, sc->cmnd, cmd_len); - - task->imm_count = 0; - if (scsi_bidi_cmnd(sc)) { - hdr->flags |= ISCSI_FLAG_CMD_READ; - rc = iscsi_prep_bidi_ahs(task); - if (rc) - return rc; - } - if (sc->sc_data_direction == DMA_TO_DEVICE) { - unsigned out_len = scsi_out(sc)->length; - struct iscsi_r2t_info *r2t = &task->unsol_r2t; - - hdr->data_length = cpu_to_be32(out_len); - hdr->flags |= ISCSI_FLAG_CMD_WRITE; - /* - * Write counters: - * - * imm_count bytes to be sent right after - * SCSI PDU Header - * - * unsol_count bytes(as Data-Out) to be sent - * without R2T ack right after - * immediate data - * - * r2t data_length bytes to be sent via R2T ack's - * - * pad_count bytes to be sent as zero-padding - */ - memset(r2t, 0, sizeof(*r2t)); - - if (session->imm_data_en) { - if (out_len >= session->first_burst) - task->imm_count = min(session->first_burst, - conn->max_xmit_dlength); - else - task->imm_count = min(out_len, - conn->max_xmit_dlength); - hton24(hdr->dlength, task->imm_count); - } else - zero_data(hdr->dlength); - - if (!session->initial_r2t_en) { - r2t->data_length = min(session->first_burst, out_len) - - task->imm_count; - r2t->data_offset = task->imm_count; - r2t->ttt = cpu_to_be32(ISCSI_RESERVED_TAG); - r2t->exp_statsn = cpu_to_be32(conn->exp_statsn); - } - - if (!task->unsol_r2t.data_length) - /* No unsolicit Data-Out's */ - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - } else { - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - zero_data(hdr->dlength); - hdr->data_length = cpu_to_be32(scsi_in(sc)->length); - - if (sc->sc_data_direction == DMA_FROM_DEVICE) - hdr->flags |= ISCSI_FLAG_CMD_READ; - } - - /* calculate size of additional header segments (AHSs) */ - hdrlength = task->hdr_len - sizeof(*hdr); - - WARN_ON(hdrlength & (ISCSI_PAD_LEN-1)); - hdrlength /= ISCSI_PAD_LEN; - - WARN_ON(hdrlength >= 256); - hdr->hlength = hdrlength & 0xFF; - hdr->cmdsn = task->cmdsn = cpu_to_be32(session->cmdsn); - - if (session->tt->init_task && session->tt->init_task(task)) - return -EIO; - - task->state = ISCSI_TASK_RUNNING; - session->cmdsn++; - - conn->scsicmd_pdus_cnt++; - ISCSI_DBG_SESSION(session, "iscsi prep [%s cid %d sc %p cdb 0x%x " - "itt 0x%x len %d bidi_len %d cmdsn %d win %d]\n", - scsi_bidi_cmnd(sc) ? "bidirectional" : - sc->sc_data_direction == DMA_TO_DEVICE ? - "write" : "read", conn->id, sc, sc->cmnd[0], - task->itt, scsi_bufflen(sc), - scsi_bidi_cmnd(sc) ? scsi_in(sc)->length : 0, - session->cmdsn, - session->max_cmdsn - session->exp_cmdsn + 1); - return 0; -} - -/** - * iscsi_free_task - free a task - * @task: iscsi cmd task - * - * Must be called with session lock. - * This function returns the scsi command to scsi-ml or cleans - * up mgmt tasks then returns the task to the pool. - */ -static void iscsi_free_task(struct iscsi_task *task) -{ - struct iscsi_conn *conn = task->conn; - struct iscsi_session *session = conn->session; - struct scsi_cmnd *sc = task->sc; - int oldstate = task->state; - - ISCSI_DBG_SESSION(session, "freeing task itt 0x%x state %d sc %p\n", - task->itt, task->state, task->sc); - - session->tt->cleanup_task(task); - task->state = ISCSI_TASK_FREE; - task->sc = NULL; - /* - * login task is preallocated so do not free - */ - if (conn->login_task == task) - return; - - kfifo_in(&session->cmdpool.queue, (void*)&task, sizeof(void*)); - - if (sc) { - task->sc = NULL; - /* SCSI eh reuses commands to verify us */ - sc->SCp.ptr = NULL; - /* - * queue command may call this to free the task, so - * it will decide how to return sc to scsi-ml. - */ - if (oldstate != ISCSI_TASK_REQUEUE_SCSIQ) - sc->scsi_done(sc); - } -} - -void __iscsi_get_task(struct iscsi_task *task) -{ - atomic_inc(&task->refcount); -} -EXPORT_SYMBOL_GPL(__iscsi_get_task); - -void __iscsi_put_task(struct iscsi_task *task) -{ - if (atomic_dec_and_test(&task->refcount)) - iscsi_free_task(task); -} -EXPORT_SYMBOL_GPL(__iscsi_put_task); - -void iscsi_put_task(struct iscsi_task *task) -{ - struct iscsi_session *session = task->conn->session; - - spin_lock_bh(&session->lock); - __iscsi_put_task(task); - spin_unlock_bh(&session->lock); -} -EXPORT_SYMBOL_GPL(iscsi_put_task); - -/** - * iscsi_complete_task - finish a task - * @task: iscsi cmd task - * @state: state to complete task with - * - * Must be called with session lock. - */ -static void iscsi_complete_task(struct iscsi_task *task, int state) -{ - struct iscsi_conn *conn = task->conn; - - ISCSI_DBG_SESSION(conn->session, - "complete task itt 0x%x state %d sc %p\n", - task->itt, task->state, task->sc); - if (task->state == ISCSI_TASK_COMPLETED || - task->state == ISCSI_TASK_ABRT_TMF || - task->state == ISCSI_TASK_ABRT_SESS_RECOV || - task->state == ISCSI_TASK_REQUEUE_SCSIQ) - return; - WARN_ON_ONCE(task->state == ISCSI_TASK_FREE); - task->state = state; - - if (!list_empty(&task->running)) - list_del_init(&task->running); - - if (conn->task == task) - conn->task = NULL; - - if (conn->ping_task == task) - conn->ping_task = NULL; - - /* release get from queueing */ - __iscsi_put_task(task); -} - -/** - * iscsi_complete_scsi_task - finish scsi task normally - * @task: iscsi task for scsi cmd - * @exp_cmdsn: expected cmd sn in cpu format - * @max_cmdsn: max cmd sn in cpu format - * - * This is used when drivers do not need or cannot perform - * lower level pdu processing. - * - * Called with session lock - */ -void iscsi_complete_scsi_task(struct iscsi_task *task, - uint32_t exp_cmdsn, uint32_t max_cmdsn) -{ - struct iscsi_conn *conn = task->conn; - - ISCSI_DBG_SESSION(conn->session, "[itt 0x%x]\n", task->itt); - - conn->last_recv = jiffies; - __iscsi_update_cmdsn(conn->session, exp_cmdsn, max_cmdsn); - iscsi_complete_task(task, ISCSI_TASK_COMPLETED); -} -EXPORT_SYMBOL_GPL(iscsi_complete_scsi_task); - - -/* - * session lock must be held and if not called for a task that is - * still pending or from the xmit thread, then xmit thread must - * be suspended. - */ -static void fail_scsi_task(struct iscsi_task *task, int err) -{ - struct iscsi_conn *conn = task->conn; - struct scsi_cmnd *sc; - int state; - - /* - * if a command completes and we get a successful tmf response - * we will hit this because the scsi eh abort code does not take - * a ref to the task. - */ - sc = task->sc; - if (!sc) - return; - - if (task->state == ISCSI_TASK_PENDING) { - /* - * cmd never made it to the xmit thread, so we should not count - * the cmd in the sequencing - */ - conn->session->queued_cmdsn--; - /* it was never sent so just complete like normal */ - state = ISCSI_TASK_COMPLETED; - } else if (err == DID_TRANSPORT_DISRUPTED) - state = ISCSI_TASK_ABRT_SESS_RECOV; - else - state = ISCSI_TASK_ABRT_TMF; - - sc->result = err << 16; - if (!scsi_bidi_cmnd(sc)) - scsi_set_resid(sc, scsi_bufflen(sc)); - else { - scsi_out(sc)->resid = scsi_out(sc)->length; - scsi_in(sc)->resid = scsi_in(sc)->length; - } - - iscsi_complete_task(task, state); -} - -static int iscsi_prep_mgmt_task(struct iscsi_conn *conn, - struct iscsi_task *task) -{ - struct iscsi_session *session = conn->session; - struct iscsi_hdr *hdr = task->hdr; - struct iscsi_nopout *nop = (struct iscsi_nopout *)hdr; - uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK; - - if (conn->session->state == ISCSI_STATE_LOGGING_OUT) - return -ENOTCONN; - - if (opcode != ISCSI_OP_LOGIN && opcode != ISCSI_OP_TEXT) - nop->exp_statsn = cpu_to_be32(conn->exp_statsn); - /* - * pre-format CmdSN for outgoing PDU. - */ - nop->cmdsn = cpu_to_be32(session->cmdsn); - if (hdr->itt != RESERVED_ITT) { - /* - * TODO: We always use immediate for normal session pdus. - * If we start to send tmfs or nops as non-immediate then - * we should start checking the cmdsn numbers for mgmt tasks. - * - * During discovery sessions iscsid sends TEXT as non immediate, - * but we always only send one PDU at a time. - */ - if (conn->c_stage == ISCSI_CONN_STARTED && - !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { - session->queued_cmdsn++; - session->cmdsn++; - } - } - - if (session->tt->init_task && session->tt->init_task(task)) - return -EIO; - - if ((hdr->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_LOGOUT) - session->state = ISCSI_STATE_LOGGING_OUT; - - task->state = ISCSI_TASK_RUNNING; - ISCSI_DBG_SESSION(session, "mgmtpdu [op 0x%x hdr->itt 0x%x " - "datalen %d]\n", hdr->opcode & ISCSI_OPCODE_MASK, - hdr->itt, task->data_count); - return 0; -} - -static struct iscsi_task * -__iscsi_conn_send_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - char *data, uint32_t data_size) -{ - struct iscsi_session *session = conn->session; - struct iscsi_host *ihost = shost_priv(session->host); - uint8_t opcode = hdr->opcode & ISCSI_OPCODE_MASK; - struct iscsi_task *task; - itt_t itt; - - if (session->state == ISCSI_STATE_TERMINATE) - return NULL; - - if (opcode == ISCSI_OP_LOGIN || opcode == ISCSI_OP_TEXT) { - /* - * Login and Text are sent serially, in - * request-followed-by-response sequence. - * Same task can be used. Same ITT must be used. - * Note that login_task is preallocated at conn_create(). - */ - if (conn->login_task->state != ISCSI_TASK_FREE) { - iscsi_conn_printk(KERN_ERR, conn, "Login/Text in " - "progress. Cannot start new task.\n"); - return NULL; - } - - task = conn->login_task; - } else { - if (session->state != ISCSI_STATE_LOGGED_IN) - return NULL; - - BUG_ON(conn->c_stage == ISCSI_CONN_INITIAL_STAGE); - BUG_ON(conn->c_stage == ISCSI_CONN_STOPPED); - - if (!kfifo_out(&session->cmdpool.queue, - (void*)&task, sizeof(void*))) - return NULL; - } - /* - * released in complete pdu for task we expect a response for, and - * released by the lld when it has transmitted the task for - * pdus we do not expect a response for. - */ - atomic_set(&task->refcount, 1); - task->conn = conn; - task->sc = NULL; - INIT_LIST_HEAD(&task->running); - task->state = ISCSI_TASK_PENDING; - - if (data_size) { - memcpy(task->data, data, data_size); - task->data_count = data_size; - } else - task->data_count = 0; - - if (conn->session->tt->alloc_pdu) { - if (conn->session->tt->alloc_pdu(task, hdr->opcode)) { - iscsi_conn_printk(KERN_ERR, conn, "Could not allocate " - "pdu for mgmt task.\n"); - goto free_task; - } - } - - itt = task->hdr->itt; - task->hdr_len = sizeof(struct iscsi_hdr); - memcpy(task->hdr, hdr, sizeof(struct iscsi_hdr)); - - if (hdr->itt != RESERVED_ITT) { - if (session->tt->parse_pdu_itt) - task->hdr->itt = itt; - else - task->hdr->itt = build_itt(task->itt, - task->conn->session->age); - } - - if (!ihost->workq) { - if (iscsi_prep_mgmt_task(conn, task)) - goto free_task; - - if (session->tt->xmit_task(task)) - goto free_task; - } else { - list_add_tail(&task->running, &conn->mgmtqueue); - iscsi_conn_queue_work(conn); - } - - return task; - -free_task: - __iscsi_put_task(task); - return NULL; -} - -int iscsi_conn_send_pdu(struct iscsi_cls_conn *cls_conn, struct iscsi_hdr *hdr, - char *data, uint32_t data_size) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - int err = 0; - - spin_lock_bh(&session->lock); - if (!__iscsi_conn_send_pdu(conn, hdr, data, data_size)) - err = -EPERM; - spin_unlock_bh(&session->lock); - return err; -} -EXPORT_SYMBOL_GPL(iscsi_conn_send_pdu); - -/** - * iscsi_cmd_rsp - SCSI Command Response processing - * @conn: iscsi connection - * @hdr: iscsi header - * @task: scsi command task - * @data: cmd data buffer - * @datalen: len of buffer - * - * iscsi_cmd_rsp sets up the scsi_cmnd fields based on the PDU and - * then completes the command and task. - **/ -static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - struct iscsi_task *task, char *data, - int datalen) -{ - struct iscsi_scsi_rsp *rhdr = (struct iscsi_scsi_rsp *)hdr; - struct iscsi_session *session = conn->session; - struct scsi_cmnd *sc = task->sc; - - iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); - conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; - - sc->result = (DID_OK << 16) | rhdr->cmd_status; - - if (rhdr->response != ISCSI_STATUS_CMD_COMPLETED) { - sc->result = DID_ERROR << 16; - goto out; - } - - if (rhdr->cmd_status == SAM_STAT_CHECK_CONDITION) { - uint16_t senselen; - - if (datalen < 2) { -invalid_datalen: - iscsi_conn_printk(KERN_ERR, conn, - "Got CHECK_CONDITION but invalid data " - "buffer size of %d\n", datalen); - sc->result = DID_BAD_TARGET << 16; - goto out; - } - - senselen = get_unaligned_be16(data); - if (datalen < senselen) - goto invalid_datalen; - - memcpy(sc->sense_buffer, data + 2, - min_t(uint16_t, senselen, SCSI_SENSE_BUFFERSIZE)); - ISCSI_DBG_SESSION(session, "copied %d bytes of sense\n", - min_t(uint16_t, senselen, - SCSI_SENSE_BUFFERSIZE)); - } - - if (rhdr->flags & (ISCSI_FLAG_CMD_BIDI_UNDERFLOW | - ISCSI_FLAG_CMD_BIDI_OVERFLOW)) { - int res_count = be32_to_cpu(rhdr->bi_residual_count); - - if (scsi_bidi_cmnd(sc) && res_count > 0 && - (rhdr->flags & ISCSI_FLAG_CMD_BIDI_OVERFLOW || - res_count <= scsi_in(sc)->length)) - scsi_in(sc)->resid = res_count; - else - sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } - - if (rhdr->flags & (ISCSI_FLAG_CMD_UNDERFLOW | - ISCSI_FLAG_CMD_OVERFLOW)) { - int res_count = be32_to_cpu(rhdr->residual_count); - - if (res_count > 0 && - (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || - res_count <= scsi_bufflen(sc))) - /* write side for bidi or uni-io set_resid */ - scsi_set_resid(sc, res_count); - else - sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } -out: - ISCSI_DBG_SESSION(session, "cmd rsp done [sc %p res %d itt 0x%x]\n", - sc, sc->result, task->itt); - conn->scsirsp_pdus_cnt++; - iscsi_complete_task(task, ISCSI_TASK_COMPLETED); -} - -/** - * iscsi_data_in_rsp - SCSI Data-In Response processing - * @conn: iscsi connection - * @hdr: iscsi pdu - * @task: scsi command task - **/ -static void -iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - struct iscsi_task *task) -{ - struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)hdr; - struct scsi_cmnd *sc = task->sc; - - if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS)) - return; - - iscsi_update_cmdsn(conn->session, (struct iscsi_nopin *)hdr); - sc->result = (DID_OK << 16) | rhdr->cmd_status; - conn->exp_statsn = be32_to_cpu(rhdr->statsn) + 1; - if (rhdr->flags & (ISCSI_FLAG_DATA_UNDERFLOW | - ISCSI_FLAG_DATA_OVERFLOW)) { - int res_count = be32_to_cpu(rhdr->residual_count); - - if (res_count > 0 && - (rhdr->flags & ISCSI_FLAG_CMD_OVERFLOW || - res_count <= scsi_in(sc)->length)) - scsi_in(sc)->resid = res_count; - else - sc->result = (DID_BAD_TARGET << 16) | rhdr->cmd_status; - } - - ISCSI_DBG_SESSION(conn->session, "data in with status done " - "[sc %p res %d itt 0x%x]\n", - sc, sc->result, task->itt); - conn->scsirsp_pdus_cnt++; - iscsi_complete_task(task, ISCSI_TASK_COMPLETED); -} - -static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr) -{ - struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr; - - conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - conn->tmfrsp_pdus_cnt++; - - if (conn->tmf_state != TMF_QUEUED) - return; - - if (tmf->response == ISCSI_TMF_RSP_COMPLETE) - conn->tmf_state = TMF_SUCCESS; - else if (tmf->response == ISCSI_TMF_RSP_NO_TASK) - conn->tmf_state = TMF_NOT_FOUND; - else - conn->tmf_state = TMF_FAILED; - wake_up(&conn->ehwait); -} - -static void iscsi_send_nopout(struct iscsi_conn *conn, struct iscsi_nopin *rhdr) -{ - struct iscsi_nopout hdr; - struct iscsi_task *task; - - if (!rhdr && conn->ping_task) - return; - - memset(&hdr, 0, sizeof(struct iscsi_nopout)); - hdr.opcode = ISCSI_OP_NOOP_OUT | ISCSI_OP_IMMEDIATE; - hdr.flags = ISCSI_FLAG_CMD_FINAL; - - if (rhdr) { - hdr.lun = rhdr->lun; - hdr.ttt = rhdr->ttt; - hdr.itt = RESERVED_ITT; - } else - hdr.ttt = RESERVED_ITT; - - task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)&hdr, NULL, 0); - if (!task) - iscsi_conn_printk(KERN_ERR, conn, "Could not send nopout\n"); - else if (!rhdr) { - /* only track our nops */ - conn->ping_task = task; - conn->last_ping = jiffies; - } -} - -static int iscsi_nop_out_rsp(struct iscsi_task *task, - struct iscsi_nopin *nop, char *data, int datalen) -{ - struct iscsi_conn *conn = task->conn; - int rc = 0; - - if (conn->ping_task != task) { - /* - * If this is not in response to one of our - * nops then it must be from userspace. - */ - if (iscsi_recv_pdu(conn->cls_conn, (struct iscsi_hdr *)nop, - data, datalen)) - rc = ISCSI_ERR_CONN_FAILED; - } else - mod_timer(&conn->transport_timer, jiffies + conn->recv_timeout); - iscsi_complete_task(task, ISCSI_TASK_COMPLETED); - return rc; -} - -static int iscsi_handle_reject(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - char *data, int datalen) -{ - struct iscsi_reject *reject = (struct iscsi_reject *)hdr; - struct iscsi_hdr rejected_pdu; - int opcode, rc = 0; - - conn->exp_statsn = be32_to_cpu(reject->statsn) + 1; - - if (ntoh24(reject->dlength) > datalen || - ntoh24(reject->dlength) < sizeof(struct iscsi_hdr)) { - iscsi_conn_printk(KERN_ERR, conn, "Cannot handle rejected " - "pdu. Invalid data length (pdu dlength " - "%u, datalen %d\n", ntoh24(reject->dlength), - datalen); - return ISCSI_ERR_PROTO; - } - memcpy(&rejected_pdu, data, sizeof(struct iscsi_hdr)); - opcode = rejected_pdu.opcode & ISCSI_OPCODE_MASK; - - switch (reject->reason) { - case ISCSI_REASON_DATA_DIGEST_ERROR: - iscsi_conn_printk(KERN_ERR, conn, - "pdu (op 0x%x itt 0x%x) rejected " - "due to DataDigest error.\n", - rejected_pdu.itt, opcode); - break; - case ISCSI_REASON_IMM_CMD_REJECT: - iscsi_conn_printk(KERN_ERR, conn, - "pdu (op 0x%x itt 0x%x) rejected. Too many " - "immediate commands.\n", - rejected_pdu.itt, opcode); - /* - * We only send one TMF at a time so if the target could not - * handle it, then it should get fixed (RFC mandates that - * a target can handle one immediate TMF per conn). - * - * For nops-outs, we could have sent more than one if - * the target is sending us lots of nop-ins - */ - if (opcode != ISCSI_OP_NOOP_OUT) - return 0; - - if (rejected_pdu.itt == cpu_to_be32(ISCSI_RESERVED_TAG)) - /* - * nop-out in response to target's nop-out rejected. - * Just resend. - */ - iscsi_send_nopout(conn, - (struct iscsi_nopin*)&rejected_pdu); - else { - struct iscsi_task *task; - /* - * Our nop as ping got dropped. We know the target - * and transport are ok so just clean up - */ - task = iscsi_itt_to_task(conn, rejected_pdu.itt); - if (!task) { - iscsi_conn_printk(KERN_ERR, conn, - "Invalid pdu reject. Could " - "not lookup rejected task.\n"); - rc = ISCSI_ERR_BAD_ITT; - } else - rc = iscsi_nop_out_rsp(task, - (struct iscsi_nopin*)&rejected_pdu, - NULL, 0); - } - break; - default: - iscsi_conn_printk(KERN_ERR, conn, - "pdu (op 0x%x itt 0x%x) rejected. Reason " - "code 0x%x\n", rejected_pdu.itt, - rejected_pdu.opcode, reject->reason); - break; - } - return rc; -} - -/** - * iscsi_itt_to_task - look up task by itt - * @conn: iscsi connection - * @itt: itt - * - * This should be used for mgmt tasks like login and nops, or if - * the LDD's itt space does not include the session age. - * - * The session lock must be held. - */ -struct iscsi_task *iscsi_itt_to_task(struct iscsi_conn *conn, itt_t itt) -{ - struct iscsi_session *session = conn->session; - int i; - - if (itt == RESERVED_ITT) - return NULL; - - if (session->tt->parse_pdu_itt) - session->tt->parse_pdu_itt(conn, itt, &i, NULL); - else - i = get_itt(itt); - if (i >= session->cmds_max) - return NULL; - - return session->cmds[i]; -} -EXPORT_SYMBOL_GPL(iscsi_itt_to_task); - -/** - * __iscsi_complete_pdu - complete pdu - * @conn: iscsi conn - * @hdr: iscsi header - * @data: data buffer - * @datalen: len of data buffer - * - * Completes pdu processing by freeing any resources allocated at - * queuecommand or send generic. session lock must be held and verify - * itt must have been called. - */ -int __iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - char *data, int datalen) -{ - struct iscsi_session *session = conn->session; - int opcode = hdr->opcode & ISCSI_OPCODE_MASK, rc = 0; - struct iscsi_task *task; - uint32_t itt; - - conn->last_recv = jiffies; - rc = iscsi_verify_itt(conn, hdr->itt); - if (rc) - return rc; - - if (hdr->itt != RESERVED_ITT) - itt = get_itt(hdr->itt); - else - itt = ~0U; - - ISCSI_DBG_SESSION(session, "[op 0x%x cid %d itt 0x%x len %d]\n", - opcode, conn->id, itt, datalen); - - if (itt == ~0U) { - iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); - - switch(opcode) { - case ISCSI_OP_NOOP_IN: - if (datalen) { - rc = ISCSI_ERR_PROTO; - break; - } - - if (hdr->ttt == cpu_to_be32(ISCSI_RESERVED_TAG)) - break; - - iscsi_send_nopout(conn, (struct iscsi_nopin*)hdr); - break; - case ISCSI_OP_REJECT: - rc = iscsi_handle_reject(conn, hdr, data, datalen); - break; - case ISCSI_OP_ASYNC_EVENT: - conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) - rc = ISCSI_ERR_CONN_FAILED; - break; - default: - rc = ISCSI_ERR_BAD_OPCODE; - break; - } - goto out; - } - - switch(opcode) { - case ISCSI_OP_SCSI_CMD_RSP: - case ISCSI_OP_SCSI_DATA_IN: - task = iscsi_itt_to_ctask(conn, hdr->itt); - if (!task) - return ISCSI_ERR_BAD_ITT; - task->last_xfer = jiffies; - break; - case ISCSI_OP_R2T: - /* - * LLD handles R2Ts if they need to. - */ - return 0; - case ISCSI_OP_LOGOUT_RSP: - case ISCSI_OP_LOGIN_RSP: - case ISCSI_OP_TEXT_RSP: - case ISCSI_OP_SCSI_TMFUNC_RSP: - case ISCSI_OP_NOOP_IN: - task = iscsi_itt_to_task(conn, hdr->itt); - if (!task) - return ISCSI_ERR_BAD_ITT; - break; - default: - return ISCSI_ERR_BAD_OPCODE; - } - - switch(opcode) { - case ISCSI_OP_SCSI_CMD_RSP: - iscsi_scsi_cmd_rsp(conn, hdr, task, data, datalen); - break; - case ISCSI_OP_SCSI_DATA_IN: - iscsi_data_in_rsp(conn, hdr, task); - break; - case ISCSI_OP_LOGOUT_RSP: - iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); - if (datalen) { - rc = ISCSI_ERR_PROTO; - break; - } - conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - goto recv_pdu; - case ISCSI_OP_LOGIN_RSP: - case ISCSI_OP_TEXT_RSP: - iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); - /* - * login related PDU's exp_statsn is handled in - * userspace - */ - goto recv_pdu; - case ISCSI_OP_SCSI_TMFUNC_RSP: - iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); - if (datalen) { - rc = ISCSI_ERR_PROTO; - break; - } - - iscsi_tmf_rsp(conn, hdr); - iscsi_complete_task(task, ISCSI_TASK_COMPLETED); - break; - case ISCSI_OP_NOOP_IN: - iscsi_update_cmdsn(session, (struct iscsi_nopin*)hdr); - if (hdr->ttt != cpu_to_be32(ISCSI_RESERVED_TAG) || datalen) { - rc = ISCSI_ERR_PROTO; - break; - } - conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1; - - rc = iscsi_nop_out_rsp(task, (struct iscsi_nopin*)hdr, - data, datalen); - break; - default: - rc = ISCSI_ERR_BAD_OPCODE; - break; - } - -out: - return rc; -recv_pdu: - if (iscsi_recv_pdu(conn->cls_conn, hdr, data, datalen)) - rc = ISCSI_ERR_CONN_FAILED; - iscsi_complete_task(task, ISCSI_TASK_COMPLETED); - return rc; -} -EXPORT_SYMBOL_GPL(__iscsi_complete_pdu); - -int iscsi_complete_pdu(struct iscsi_conn *conn, struct iscsi_hdr *hdr, - char *data, int datalen) -{ - int rc; - - spin_lock(&conn->session->lock); - rc = __iscsi_complete_pdu(conn, hdr, data, datalen); - spin_unlock(&conn->session->lock); - return rc; -} -EXPORT_SYMBOL_GPL(iscsi_complete_pdu); - -int iscsi_verify_itt(struct iscsi_conn *conn, itt_t itt) -{ - struct iscsi_session *session = conn->session; - int age = 0, i = 0; - - if (itt == RESERVED_ITT) - return 0; - - if (session->tt->parse_pdu_itt) - session->tt->parse_pdu_itt(conn, itt, &i, &age); - else { - i = get_itt(itt); - age = ((__force u32)itt >> ISCSI_AGE_SHIFT) & ISCSI_AGE_MASK; - } - - if (age != session->age) { - iscsi_conn_printk(KERN_ERR, conn, - "received itt %x expected session age (%x)\n", - (__force u32)itt, session->age); - return ISCSI_ERR_BAD_ITT; - } - - if (i >= session->cmds_max) { - iscsi_conn_printk(KERN_ERR, conn, - "received invalid itt index %u (max cmds " - "%u.\n", i, session->cmds_max); - return ISCSI_ERR_BAD_ITT; - } - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_verify_itt); - -/** - * iscsi_itt_to_ctask - look up ctask by itt - * @conn: iscsi connection - * @itt: itt - * - * This should be used for cmd tasks. - * - * The session lock must be held. - */ -struct iscsi_task *iscsi_itt_to_ctask(struct iscsi_conn *conn, itt_t itt) -{ - struct iscsi_task *task; - - if (iscsi_verify_itt(conn, itt)) - return NULL; - - task = iscsi_itt_to_task(conn, itt); - if (!task || !task->sc) - return NULL; - - if (task->sc->SCp.phase != conn->session->age) { - iscsi_session_printk(KERN_ERR, conn->session, - "task's session age %d, expected %d\n", - task->sc->SCp.phase, conn->session->age); - return NULL; - } - - return task; -} -EXPORT_SYMBOL_GPL(iscsi_itt_to_ctask); - -void iscsi_session_failure(struct iscsi_session *session, - enum iscsi_err err) -{ - struct iscsi_conn *conn; - struct device *dev; - - spin_lock_bh(&session->lock); - conn = session->leadconn; - if (session->state == ISCSI_STATE_TERMINATE || !conn) { - spin_unlock_bh(&session->lock); - return; - } - - dev = get_device(&conn->cls_conn->dev); - spin_unlock_bh(&session->lock); - if (!dev) - return; - /* - * if the host is being removed bypass the connection - * recovery initialization because we are going to kill - * the session. - */ - if (err == ISCSI_ERR_INVALID_HOST) - iscsi_conn_error_event(conn->cls_conn, err); - else - iscsi_conn_failure(conn, err); - put_device(dev); -} -EXPORT_SYMBOL_GPL(iscsi_session_failure); - -void iscsi_conn_failure(struct iscsi_conn *conn, enum iscsi_err err) -{ - struct iscsi_session *session = conn->session; - - spin_lock_bh(&session->lock); - if (session->state == ISCSI_STATE_FAILED) { - spin_unlock_bh(&session->lock); - return; - } - - if (conn->stop_stage == 0) - session->state = ISCSI_STATE_FAILED; - spin_unlock_bh(&session->lock); - - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); - iscsi_conn_error_event(conn->cls_conn, err); -} -EXPORT_SYMBOL_GPL(iscsi_conn_failure); - -static int iscsi_check_cmdsn_window_closed(struct iscsi_conn *conn) -{ - struct iscsi_session *session = conn->session; - - /* - * Check for iSCSI window and take care of CmdSN wrap-around - */ - if (!iscsi_sna_lte(session->queued_cmdsn, session->max_cmdsn)) { - ISCSI_DBG_SESSION(session, "iSCSI CmdSN closed. ExpCmdSn " - "%u MaxCmdSN %u CmdSN %u/%u\n", - session->exp_cmdsn, session->max_cmdsn, - session->cmdsn, session->queued_cmdsn); - return -ENOSPC; - } - return 0; -} - -static int iscsi_xmit_task(struct iscsi_conn *conn) -{ - struct iscsi_task *task = conn->task; - int rc; - - if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) - return -ENODATA; - - __iscsi_get_task(task); - spin_unlock_bh(&conn->session->lock); - rc = conn->session->tt->xmit_task(task); - spin_lock_bh(&conn->session->lock); - if (!rc) { - /* done with this task */ - task->last_xfer = jiffies; - conn->task = NULL; - } - __iscsi_put_task(task); - return rc; -} - -/** - * iscsi_requeue_task - requeue task to run from session workqueue - * @task: task to requeue - * - * LLDs that need to run a task from the session workqueue should call - * this. The session lock must be held. This should only be called - * by software drivers. - */ -void iscsi_requeue_task(struct iscsi_task *task) -{ - struct iscsi_conn *conn = task->conn; - - /* - * this may be on the requeue list already if the xmit_task callout - * is handling the r2ts while we are adding new ones - */ - if (list_empty(&task->running)) - list_add_tail(&task->running, &conn->requeue); - iscsi_conn_queue_work(conn); -} -EXPORT_SYMBOL_GPL(iscsi_requeue_task); - -/** - * iscsi_data_xmit - xmit any command into the scheduled connection - * @conn: iscsi connection - * - * Notes: - * The function can return -EAGAIN in which case the caller must - * re-schedule it again later or recover. '0' return code means - * successful xmit. - **/ -static int iscsi_data_xmit(struct iscsi_conn *conn) -{ - struct iscsi_task *task; - int rc = 0; - - spin_lock_bh(&conn->session->lock); - if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) { - ISCSI_DBG_SESSION(conn->session, "Tx suspended!\n"); - spin_unlock_bh(&conn->session->lock); - return -ENODATA; - } - - if (conn->task) { - rc = iscsi_xmit_task(conn); - if (rc) - goto done; - } - - /* - * process mgmt pdus like nops before commands since we should - * only have one nop-out as a ping from us and targets should not - * overflow us with nop-ins - */ -check_mgmt: - while (!list_empty(&conn->mgmtqueue)) { - conn->task = list_entry(conn->mgmtqueue.next, - struct iscsi_task, running); - list_del_init(&conn->task->running); - if (iscsi_prep_mgmt_task(conn, conn->task)) { - __iscsi_put_task(conn->task); - conn->task = NULL; - continue; - } - rc = iscsi_xmit_task(conn); - if (rc) - goto done; - } - - /* process pending command queue */ - while (!list_empty(&conn->cmdqueue)) { - conn->task = list_entry(conn->cmdqueue.next, struct iscsi_task, - running); - list_del_init(&conn->task->running); - if (conn->session->state == ISCSI_STATE_LOGGING_OUT) { - fail_scsi_task(conn->task, DID_IMM_RETRY); - continue; - } - rc = iscsi_prep_scsi_cmd_pdu(conn->task); - if (rc) { - if (rc == -ENOMEM || rc == -EACCES) { - list_add_tail(&conn->task->running, - &conn->cmdqueue); - conn->task = NULL; - goto done; - } else - fail_scsi_task(conn->task, DID_ABORT); - continue; - } - rc = iscsi_xmit_task(conn); - if (rc) - goto done; - /* - * we could continuously get new task requests so - * we need to check the mgmt queue for nops that need to - * be sent to aviod starvation - */ - if (!list_empty(&conn->mgmtqueue)) - goto check_mgmt; - } - - while (!list_empty(&conn->requeue)) { - /* - * we always do fastlogout - conn stop code will clean up. - */ - if (conn->session->state == ISCSI_STATE_LOGGING_OUT) - break; - - task = list_entry(conn->requeue.next, struct iscsi_task, - running); - if (iscsi_check_tmf_restrictions(task, ISCSI_OP_SCSI_DATA_OUT)) - break; - - conn->task = task; - list_del_init(&conn->task->running); - conn->task->state = ISCSI_TASK_RUNNING; - rc = iscsi_xmit_task(conn); - if (rc) - goto done; - if (!list_empty(&conn->mgmtqueue)) - goto check_mgmt; - } - spin_unlock_bh(&conn->session->lock); - return -ENODATA; - -done: - spin_unlock_bh(&conn->session->lock); - return rc; -} - -static void iscsi_xmitworker(struct work_struct *work) -{ - struct iscsi_conn *conn = - container_of(work, struct iscsi_conn, xmitwork); - int rc; - /* - * serialize Xmit worker on a per-connection basis. - */ - do { - rc = iscsi_data_xmit(conn); - } while (rc >= 0 || rc == -EAGAIN); -} - -static inline struct iscsi_task *iscsi_alloc_task(struct iscsi_conn *conn, - struct scsi_cmnd *sc) -{ - struct iscsi_task *task; - - if (!kfifo_out(&conn->session->cmdpool.queue, - (void *) &task, sizeof(void *))) - return NULL; - - sc->SCp.phase = conn->session->age; - sc->SCp.ptr = (char *) task; - - atomic_set(&task->refcount, 1); - task->state = ISCSI_TASK_PENDING; - task->conn = conn; - task->sc = sc; - task->have_checked_conn = false; - task->last_timeout = jiffies; - task->last_xfer = jiffies; - INIT_LIST_HEAD(&task->running); - return task; -} - -enum { - FAILURE_BAD_HOST = 1, - FAILURE_SESSION_FAILED, - FAILURE_SESSION_FREED, - FAILURE_WINDOW_CLOSED, - FAILURE_OOM, - FAILURE_SESSION_TERMINATE, - FAILURE_SESSION_IN_RECOVERY, - FAILURE_SESSION_RECOVERY_TIMEOUT, - FAILURE_SESSION_LOGGING_OUT, - FAILURE_SESSION_NOT_READY, -}; - -int iscsi_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *sc) -{ - struct iscsi_cls_session *cls_session; - struct iscsi_host *ihost; - int reason = 0; - struct iscsi_session *session; - struct iscsi_conn *conn; - struct iscsi_task *task = NULL; - - sc->result = 0; - sc->SCp.ptr = NULL; - - ihost = shost_priv(host); - - cls_session = starget_to_session(scsi_target(sc->device)); - session = cls_session->dd_data; - spin_lock_bh(&session->lock); - - reason = iscsi_session_chkready(cls_session); - if (reason) { - sc->result = reason; - goto fault; - } - - if (session->state != ISCSI_STATE_LOGGED_IN) { - /* - * to handle the race between when we set the recovery state - * and block the session we requeue here (commands could - * be entering our queuecommand while a block is starting - * up because the block code is not locked) - */ - switch (session->state) { - case ISCSI_STATE_FAILED: - case ISCSI_STATE_IN_RECOVERY: - reason = FAILURE_SESSION_IN_RECOVERY; - sc->result = DID_IMM_RETRY << 16; - break; - case ISCSI_STATE_LOGGING_OUT: - reason = FAILURE_SESSION_LOGGING_OUT; - sc->result = DID_IMM_RETRY << 16; - break; - case ISCSI_STATE_RECOVERY_FAILED: - reason = FAILURE_SESSION_RECOVERY_TIMEOUT; - sc->result = DID_TRANSPORT_FAILFAST << 16; - break; - case ISCSI_STATE_TERMINATE: - reason = FAILURE_SESSION_TERMINATE; - sc->result = DID_NO_CONNECT << 16; - break; - default: - reason = FAILURE_SESSION_FREED; - sc->result = DID_NO_CONNECT << 16; - } - goto fault; - } - - conn = session->leadconn; - if (!conn) { - reason = FAILURE_SESSION_FREED; - sc->result = DID_NO_CONNECT << 16; - goto fault; - } - - if (test_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx)) { - reason = FAILURE_SESSION_IN_RECOVERY; - sc->result = DID_REQUEUE; - goto fault; - } - - if (iscsi_check_cmdsn_window_closed(conn)) { - reason = FAILURE_WINDOW_CLOSED; - goto reject; - } - - task = iscsi_alloc_task(conn, sc); - if (!task) { - reason = FAILURE_OOM; - goto reject; - } - - if (!ihost->workq) { - reason = iscsi_prep_scsi_cmd_pdu(task); - if (reason) { - if (reason == -ENOMEM || reason == -EACCES) { - reason = FAILURE_OOM; - goto prepd_reject; - } else { - sc->result = DID_ABORT << 16; - goto prepd_fault; - } - } - if (session->tt->xmit_task(task)) { - session->cmdsn--; - reason = FAILURE_SESSION_NOT_READY; - goto prepd_reject; - } - } else { - list_add_tail(&task->running, &conn->cmdqueue); - iscsi_conn_queue_work(conn); - } - - session->queued_cmdsn++; - spin_unlock_bh(&session->lock); - return 0; - -prepd_reject: - iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ); -reject: - spin_unlock_bh(&session->lock); - ISCSI_DBG_SESSION(session, "cmd 0x%x rejected (%d)\n", - sc->cmnd[0], reason); - return SCSI_MLQUEUE_TARGET_BUSY; - -prepd_fault: - iscsi_complete_task(task, ISCSI_TASK_REQUEUE_SCSIQ); -fault: - spin_unlock_bh(&session->lock); - ISCSI_DBG_SESSION(session, "iscsi: cmd 0x%x is not queued (%d)\n", - sc->cmnd[0], reason); - if (!scsi_bidi_cmnd(sc)) - scsi_set_resid(sc, scsi_bufflen(sc)); - else { - scsi_out(sc)->resid = scsi_out(sc)->length; - scsi_in(sc)->resid = scsi_in(sc)->length; - } - sc->scsi_done(sc); - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_queuecommand); - -int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason) -{ - switch (reason) { - case SCSI_QDEPTH_DEFAULT: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); - break; - case SCSI_QDEPTH_QFULL: - scsi_track_queue_full(sdev, depth); - break; - case SCSI_QDEPTH_RAMP_UP: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); - break; - default: - return -EOPNOTSUPP; - } - return sdev->queue_depth; -} -EXPORT_SYMBOL_GPL(iscsi_change_queue_depth); - -int iscsi_target_alloc(struct scsi_target *starget) -{ - struct iscsi_cls_session *cls_session = starget_to_session(starget); - struct iscsi_session *session = cls_session->dd_data; - - starget->can_queue = session->scsi_cmds_max; - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_target_alloc); - -static void iscsi_tmf_timedout(unsigned long data) -{ - struct iscsi_conn *conn = (struct iscsi_conn *)data; - struct iscsi_session *session = conn->session; - - spin_lock(&session->lock); - if (conn->tmf_state == TMF_QUEUED) { - conn->tmf_state = TMF_TIMEDOUT; - ISCSI_DBG_EH(session, "tmf timedout\n"); - /* unblock eh_abort() */ - wake_up(&conn->ehwait); - } - spin_unlock(&session->lock); -} - -static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn, - struct iscsi_tm *hdr, int age, - int timeout) -{ - struct iscsi_session *session = conn->session; - struct iscsi_task *task; - - task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr, - NULL, 0); - if (!task) { - spin_unlock_bh(&session->lock); - iscsi_conn_printk(KERN_ERR, conn, "Could not send TMF.\n"); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - spin_lock_bh(&session->lock); - return -EPERM; - } - conn->tmfcmd_pdus_cnt++; - conn->tmf_timer.expires = timeout * HZ + jiffies; - conn->tmf_timer.function = iscsi_tmf_timedout; - conn->tmf_timer.data = (unsigned long)conn; - add_timer(&conn->tmf_timer); - ISCSI_DBG_EH(session, "tmf set timeout\n"); - - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); - - /* - * block eh thread until: - * - * 1) tmf response - * 2) tmf timeout - * 3) session is terminated or restarted or userspace has - * given up on recovery - */ - wait_event_interruptible(conn->ehwait, age != session->age || - session->state != ISCSI_STATE_LOGGED_IN || - conn->tmf_state != TMF_QUEUED); - if (signal_pending(current)) - flush_signals(current); - del_timer_sync(&conn->tmf_timer); - - mutex_lock(&session->eh_mutex); - spin_lock_bh(&session->lock); - /* if the session drops it will clean up the task */ - if (age != session->age || - session->state != ISCSI_STATE_LOGGED_IN) - return -ENOTCONN; - return 0; -} - -/* - * Fail commands. session lock held and recv side suspended and xmit - * thread flushed - */ -static void fail_scsi_tasks(struct iscsi_conn *conn, unsigned lun, - int error) -{ - struct iscsi_task *task; - int i; - - for (i = 0; i < conn->session->cmds_max; i++) { - task = conn->session->cmds[i]; - if (!task->sc || task->state == ISCSI_TASK_FREE) - continue; - - if (lun != -1 && lun != task->sc->device->lun) - continue; - - ISCSI_DBG_SESSION(conn->session, - "failing sc %p itt 0x%x state %d\n", - task->sc, task->itt, task->state); - fail_scsi_task(task, error); - } -} - -/** - * iscsi_suspend_queue - suspend iscsi_queuecommand - * @conn: iscsi conn to stop queueing IO on - * - * This grabs the session lock to make sure no one is in - * xmit_task/queuecommand, and then sets suspend to prevent - * new commands from being queued. This only needs to be called - * by offload drivers that need to sync a path like ep disconnect - * with the iscsi_queuecommand/xmit_task. To start IO again libiscsi - * will call iscsi_start_tx and iscsi_unblock_session when in FFP. - */ -void iscsi_suspend_queue(struct iscsi_conn *conn) -{ - spin_lock_bh(&conn->session->lock); - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - spin_unlock_bh(&conn->session->lock); -} -EXPORT_SYMBOL_GPL(iscsi_suspend_queue); - -/** - * iscsi_suspend_tx - suspend iscsi_data_xmit - * @conn: iscsi conn tp stop processing IO on. - * - * This function sets the suspend bit to prevent iscsi_data_xmit - * from sending new IO, and if work is queued on the xmit thread - * it will wait for it to be completed. - */ -void iscsi_suspend_tx(struct iscsi_conn *conn) -{ - struct Scsi_Host *shost = conn->session->host; - struct iscsi_host *ihost = shost_priv(shost); - - set_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - if (ihost->workq) - flush_workqueue(ihost->workq); -} -EXPORT_SYMBOL_GPL(iscsi_suspend_tx); - -static void iscsi_start_tx(struct iscsi_conn *conn) -{ - clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - iscsi_conn_queue_work(conn); -} - -/* - * We want to make sure a ping is in flight. It has timed out. - * And we are not busy processing a pdu that is making - * progress but got started before the ping and is taking a while - * to complete so the ping is just stuck behind it in a queue. - */ -static int iscsi_has_ping_timed_out(struct iscsi_conn *conn) -{ - if (conn->ping_task && - time_before_eq(conn->last_recv + (conn->recv_timeout * HZ) + - (conn->ping_timeout * HZ), jiffies)) - return 1; - else - return 0; -} - -static enum blk_eh_timer_return iscsi_eh_cmd_timed_out(struct scsi_cmnd *sc) -{ - enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED; - struct iscsi_task *task = NULL, *running_task; - struct iscsi_cls_session *cls_session; - struct iscsi_session *session; - struct iscsi_conn *conn; - int i; - - cls_session = starget_to_session(scsi_target(sc->device)); - session = cls_session->dd_data; - - ISCSI_DBG_EH(session, "scsi cmd %p timedout\n", sc); - - spin_lock(&session->lock); - task = (struct iscsi_task *)sc->SCp.ptr; - if (!task) { - /* - * Raced with completion. Blk layer has taken ownership - * so let timeout code complete it now. - */ - rc = BLK_EH_HANDLED; - goto done; - } - - if (session->state != ISCSI_STATE_LOGGED_IN) { - /* - * We are probably in the middle of iscsi recovery so let - * that complete and handle the error. - */ - rc = BLK_EH_RESET_TIMER; - goto done; - } - - conn = session->leadconn; - if (!conn) { - /* In the middle of shuting down */ - rc = BLK_EH_RESET_TIMER; - goto done; - } - - /* - * If we have sent (at least queued to the network layer) a pdu or - * recvd one for the task since the last timeout ask for - * more time. If on the next timeout we have not made progress - * we can check if it is the task or connection when we send the - * nop as a ping. - */ - if (time_after(task->last_xfer, task->last_timeout)) { - ISCSI_DBG_EH(session, "Command making progress. Asking " - "scsi-ml for more time to complete. " - "Last data xfer at %lu. Last timeout was at " - "%lu\n.", task->last_xfer, task->last_timeout); - task->have_checked_conn = false; - rc = BLK_EH_RESET_TIMER; - goto done; - } - - if (!conn->recv_timeout && !conn->ping_timeout) - goto done; - /* - * if the ping timedout then we are in the middle of cleaning up - * and can let the iscsi eh handle it - */ - if (iscsi_has_ping_timed_out(conn)) { - rc = BLK_EH_RESET_TIMER; - goto done; - } - - for (i = 0; i < conn->session->cmds_max; i++) { - running_task = conn->session->cmds[i]; - if (!running_task->sc || running_task == task || - running_task->state != ISCSI_TASK_RUNNING) - continue; - - /* - * Only check if cmds started before this one have made - * progress, or this could never fail - */ - if (time_after(running_task->sc->jiffies_at_alloc, - task->sc->jiffies_at_alloc)) - continue; - - if (time_after(running_task->last_xfer, task->last_timeout)) { - /* - * This task has not made progress, but a task - * started before us has transferred data since - * we started/last-checked. We could be queueing - * too many tasks or the LU is bad. - * - * If the device is bad the cmds ahead of us on - * other devs will complete, and this loop will - * eventually fail starting the scsi eh. - */ - ISCSI_DBG_EH(session, "Command has not made progress " - "but commands ahead of it have. " - "Asking scsi-ml for more time to " - "complete. Our last xfer vs running task " - "last xfer %lu/%lu. Last check %lu.\n", - task->last_xfer, running_task->last_xfer, - task->last_timeout); - rc = BLK_EH_RESET_TIMER; - goto done; - } - } - - /* Assumes nop timeout is shorter than scsi cmd timeout */ - if (task->have_checked_conn) - goto done; - - /* - * Checking the transport already or nop from a cmd timeout still - * running - */ - if (conn->ping_task) { - task->have_checked_conn = true; - rc = BLK_EH_RESET_TIMER; - goto done; - } - - /* Make sure there is a transport check done */ - iscsi_send_nopout(conn, NULL); - task->have_checked_conn = true; - rc = BLK_EH_RESET_TIMER; - -done: - if (task) - task->last_timeout = jiffies; - spin_unlock(&session->lock); - ISCSI_DBG_EH(session, "return %s\n", rc == BLK_EH_RESET_TIMER ? - "timer reset" : "nh"); - return rc; -} - -static void iscsi_check_transport_timeouts(unsigned long data) -{ - struct iscsi_conn *conn = (struct iscsi_conn *)data; - struct iscsi_session *session = conn->session; - unsigned long recv_timeout, next_timeout = 0, last_recv; - - spin_lock(&session->lock); - if (session->state != ISCSI_STATE_LOGGED_IN) - goto done; - - recv_timeout = conn->recv_timeout; - if (!recv_timeout) - goto done; - - recv_timeout *= HZ; - last_recv = conn->last_recv; - - if (iscsi_has_ping_timed_out(conn)) { - iscsi_conn_printk(KERN_ERR, conn, "ping timeout of %d secs " - "expired, recv timeout %d, last rx %lu, " - "last ping %lu, now %lu\n", - conn->ping_timeout, conn->recv_timeout, - last_recv, conn->last_ping, jiffies); - spin_unlock(&session->lock); - iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED); - return; - } - - if (time_before_eq(last_recv + recv_timeout, jiffies)) { - /* send a ping to try to provoke some traffic */ - ISCSI_DBG_CONN(conn, "Sending nopout as ping\n"); - iscsi_send_nopout(conn, NULL); - next_timeout = conn->last_ping + (conn->ping_timeout * HZ); - } else - next_timeout = last_recv + recv_timeout; - - ISCSI_DBG_CONN(conn, "Setting next tmo %lu\n", next_timeout); - mod_timer(&conn->transport_timer, next_timeout); -done: - spin_unlock(&session->lock); -} - -static void iscsi_prep_abort_task_pdu(struct iscsi_task *task, - struct iscsi_tm *hdr) -{ - memset(hdr, 0, sizeof(*hdr)); - hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; - hdr->flags = ISCSI_TM_FUNC_ABORT_TASK & ISCSI_FLAG_TM_FUNC_MASK; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hdr->lun = task->lun; - hdr->rtt = task->hdr_itt; - hdr->refcmdsn = task->cmdsn; -} - -int iscsi_eh_abort(struct scsi_cmnd *sc) -{ - struct iscsi_cls_session *cls_session; - struct iscsi_session *session; - struct iscsi_conn *conn; - struct iscsi_task *task; - struct iscsi_tm *hdr; - int rc, age; - - cls_session = starget_to_session(scsi_target(sc->device)); - session = cls_session->dd_data; - - ISCSI_DBG_EH(session, "aborting sc %p\n", sc); - - mutex_lock(&session->eh_mutex); - spin_lock_bh(&session->lock); - /* - * if session was ISCSI_STATE_IN_RECOVERY then we may not have - * got the command. - */ - if (!sc->SCp.ptr) { - ISCSI_DBG_EH(session, "sc never reached iscsi layer or " - "it completed.\n"); - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); - return SUCCESS; - } - - /* - * If we are not logged in or we have started a new session - * then let the host reset code handle this - */ - if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN || - sc->SCp.phase != session->age) { - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); - ISCSI_DBG_EH(session, "failing abort due to dropped " - "session.\n"); - return FAILED; - } - - conn = session->leadconn; - conn->eh_abort_cnt++; - age = session->age; - - task = (struct iscsi_task *)sc->SCp.ptr; - ISCSI_DBG_EH(session, "aborting [sc %p itt 0x%x]\n", - sc, task->itt); - - /* task completed before time out */ - if (!task->sc) { - ISCSI_DBG_EH(session, "sc completed while abort in progress\n"); - goto success; - } - - if (task->state == ISCSI_TASK_PENDING) { - fail_scsi_task(task, DID_ABORT); - goto success; - } - - /* only have one tmf outstanding at a time */ - if (conn->tmf_state != TMF_INITIAL) - goto failed; - conn->tmf_state = TMF_QUEUED; - - hdr = &conn->tmhdr; - iscsi_prep_abort_task_pdu(task, hdr); - - if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout)) { - rc = FAILED; - goto failed; - } - - switch (conn->tmf_state) { - case TMF_SUCCESS: - spin_unlock_bh(&session->lock); - /* - * stop tx side incase the target had sent a abort rsp but - * the initiator was still writing out data. - */ - iscsi_suspend_tx(conn); - /* - * we do not stop the recv side because targets have been - * good and have never sent us a successful tmf response - * then sent more data for the cmd. - */ - spin_lock_bh(&session->lock); - fail_scsi_task(task, DID_ABORT); - conn->tmf_state = TMF_INITIAL; - memset(hdr, 0, sizeof(*hdr)); - spin_unlock_bh(&session->lock); - iscsi_start_tx(conn); - goto success_unlocked; - case TMF_TIMEDOUT: - spin_unlock_bh(&session->lock); - iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST); - goto failed_unlocked; - case TMF_NOT_FOUND: - if (!sc->SCp.ptr) { - conn->tmf_state = TMF_INITIAL; - memset(hdr, 0, sizeof(*hdr)); - /* task completed before tmf abort response */ - ISCSI_DBG_EH(session, "sc completed while abort in " - "progress\n"); - goto success; - } - /* fall through */ - default: - conn->tmf_state = TMF_INITIAL; - goto failed; - } - -success: - spin_unlock_bh(&session->lock); -success_unlocked: - ISCSI_DBG_EH(session, "abort success [sc %p itt 0x%x]\n", - sc, task->itt); - mutex_unlock(&session->eh_mutex); - return SUCCESS; - -failed: - spin_unlock_bh(&session->lock); -failed_unlocked: - ISCSI_DBG_EH(session, "abort failed [sc %p itt 0x%x]\n", sc, - task ? task->itt : 0); - mutex_unlock(&session->eh_mutex); - return FAILED; -} -EXPORT_SYMBOL_GPL(iscsi_eh_abort); - -static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) -{ - memset(hdr, 0, sizeof(*hdr)); - hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; - hdr->flags = ISCSI_TM_FUNC_LOGICAL_UNIT_RESET & ISCSI_FLAG_TM_FUNC_MASK; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - int_to_scsilun(sc->device->lun, &hdr->lun); - hdr->rtt = RESERVED_ITT; -} - -int iscsi_eh_device_reset(struct scsi_cmnd *sc) -{ - struct iscsi_cls_session *cls_session; - struct iscsi_session *session; - struct iscsi_conn *conn; - struct iscsi_tm *hdr; - int rc = FAILED; - - cls_session = starget_to_session(scsi_target(sc->device)); - session = cls_session->dd_data; - - ISCSI_DBG_EH(session, "LU Reset [sc %p lun %u]\n", sc, sc->device->lun); - - mutex_lock(&session->eh_mutex); - spin_lock_bh(&session->lock); - /* - * Just check if we are not logged in. We cannot check for - * the phase because the reset could come from a ioctl. - */ - if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) - goto unlock; - conn = session->leadconn; - - /* only have one tmf outstanding at a time */ - if (conn->tmf_state != TMF_INITIAL) - goto unlock; - conn->tmf_state = TMF_QUEUED; - - hdr = &conn->tmhdr; - iscsi_prep_lun_reset_pdu(sc, hdr); - - if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age, - session->lu_reset_timeout)) { - rc = FAILED; - goto unlock; - } - - switch (conn->tmf_state) { - case TMF_SUCCESS: - break; - case TMF_TIMEDOUT: - spin_unlock_bh(&session->lock); - iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST); - goto done; - default: - conn->tmf_state = TMF_INITIAL; - goto unlock; - } - - rc = SUCCESS; - spin_unlock_bh(&session->lock); - - iscsi_suspend_tx(conn); - - spin_lock_bh(&session->lock); - memset(hdr, 0, sizeof(*hdr)); - fail_scsi_tasks(conn, sc->device->lun, DID_ERROR); - conn->tmf_state = TMF_INITIAL; - spin_unlock_bh(&session->lock); - - iscsi_start_tx(conn); - goto done; - -unlock: - spin_unlock_bh(&session->lock); -done: - ISCSI_DBG_EH(session, "dev reset result = %s\n", - rc == SUCCESS ? "SUCCESS" : "FAILED"); - mutex_unlock(&session->eh_mutex); - return rc; -} -EXPORT_SYMBOL_GPL(iscsi_eh_device_reset); - -void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *session = cls_session->dd_data; - - spin_lock_bh(&session->lock); - if (session->state != ISCSI_STATE_LOGGED_IN) { - session->state = ISCSI_STATE_RECOVERY_FAILED; - if (session->leadconn) - wake_up(&session->leadconn->ehwait); - } - spin_unlock_bh(&session->lock); -} -EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout); - -/** - * iscsi_eh_session_reset - drop session and attempt relogin - * @sc: scsi command - * - * This function will wait for a relogin, session termination from - * userspace, or a recovery/replacement timeout. - */ -int iscsi_eh_session_reset(struct scsi_cmnd *sc) -{ - struct iscsi_cls_session *cls_session; - struct iscsi_session *session; - struct iscsi_conn *conn; - - cls_session = starget_to_session(scsi_target(sc->device)); - session = cls_session->dd_data; - conn = session->leadconn; - - mutex_lock(&session->eh_mutex); - spin_lock_bh(&session->lock); - if (session->state == ISCSI_STATE_TERMINATE) { -failed: - ISCSI_DBG_EH(session, - "failing session reset: Could not log back into " - "%s, %s [age %d]\n", session->targetname, - conn->persistent_address, session->age); - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); - return FAILED; - } - - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); - /* - * we drop the lock here but the leadconn cannot be destoyed while - * we are in the scsi eh - */ - iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST); - - ISCSI_DBG_EH(session, "wait for relogin\n"); - wait_event_interruptible(conn->ehwait, - session->state == ISCSI_STATE_TERMINATE || - session->state == ISCSI_STATE_LOGGED_IN || - session->state == ISCSI_STATE_RECOVERY_FAILED); - if (signal_pending(current)) - flush_signals(current); - - mutex_lock(&session->eh_mutex); - spin_lock_bh(&session->lock); - if (session->state == ISCSI_STATE_LOGGED_IN) { - ISCSI_DBG_EH(session, - "session reset succeeded for %s,%s\n", - session->targetname, conn->persistent_address); - } else - goto failed; - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); - return SUCCESS; -} -EXPORT_SYMBOL_GPL(iscsi_eh_session_reset); - -static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr) -{ - memset(hdr, 0, sizeof(*hdr)); - hdr->opcode = ISCSI_OP_SCSI_TMFUNC | ISCSI_OP_IMMEDIATE; - hdr->flags = ISCSI_TM_FUNC_TARGET_WARM_RESET & ISCSI_FLAG_TM_FUNC_MASK; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hdr->rtt = RESERVED_ITT; -} - -/** - * iscsi_eh_target_reset - reset target - * @sc: scsi command - * - * This will attempt to send a warm target reset. - */ -int iscsi_eh_target_reset(struct scsi_cmnd *sc) -{ - struct iscsi_cls_session *cls_session; - struct iscsi_session *session; - struct iscsi_conn *conn; - struct iscsi_tm *hdr; - int rc = FAILED; - - cls_session = starget_to_session(scsi_target(sc->device)); - session = cls_session->dd_data; - - ISCSI_DBG_EH(session, "tgt Reset [sc %p tgt %s]\n", sc, - session->targetname); - - mutex_lock(&session->eh_mutex); - spin_lock_bh(&session->lock); - /* - * Just check if we are not logged in. We cannot check for - * the phase because the reset could come from a ioctl. - */ - if (!session->leadconn || session->state != ISCSI_STATE_LOGGED_IN) - goto unlock; - conn = session->leadconn; - - /* only have one tmf outstanding at a time */ - if (conn->tmf_state != TMF_INITIAL) - goto unlock; - conn->tmf_state = TMF_QUEUED; - - hdr = &conn->tmhdr; - iscsi_prep_tgt_reset_pdu(sc, hdr); - - if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age, - session->tgt_reset_timeout)) { - rc = FAILED; - goto unlock; - } - - switch (conn->tmf_state) { - case TMF_SUCCESS: - break; - case TMF_TIMEDOUT: - spin_unlock_bh(&session->lock); - iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST); - goto done; - default: - conn->tmf_state = TMF_INITIAL; - goto unlock; - } - - rc = SUCCESS; - spin_unlock_bh(&session->lock); - - iscsi_suspend_tx(conn); - - spin_lock_bh(&session->lock); - memset(hdr, 0, sizeof(*hdr)); - fail_scsi_tasks(conn, -1, DID_ERROR); - conn->tmf_state = TMF_INITIAL; - spin_unlock_bh(&session->lock); - - iscsi_start_tx(conn); - goto done; - -unlock: - spin_unlock_bh(&session->lock); -done: - ISCSI_DBG_EH(session, "tgt %s reset result = %s\n", session->targetname, - rc == SUCCESS ? "SUCCESS" : "FAILED"); - mutex_unlock(&session->eh_mutex); - return rc; -} -EXPORT_SYMBOL_GPL(iscsi_eh_target_reset); - -/** - * iscsi_eh_recover_target - reset target and possibly the session - * @sc: scsi command - * - * This will attempt to send a warm target reset. If that fails, - * we will escalate to ERL0 session recovery. - */ -int iscsi_eh_recover_target(struct scsi_cmnd *sc) -{ - int rc; - - rc = iscsi_eh_target_reset(sc); - if (rc == FAILED) - rc = iscsi_eh_session_reset(sc); - return rc; -} -EXPORT_SYMBOL_GPL(iscsi_eh_recover_target); - -/* - * Pre-allocate a pool of @max items of @item_size. By default, the pool - * should be accessed via kfifo_{get,put} on q->queue. - * Optionally, the caller can obtain the array of object pointers - * by passing in a non-NULL @items pointer - */ -int -iscsi_pool_init(struct iscsi_pool *q, int max, void ***items, int item_size) -{ - int i, num_arrays = 1; - - memset(q, 0, sizeof(*q)); - - q->max = max; - - /* If the user passed an items pointer, he wants a copy of - * the array. */ - if (items) - num_arrays++; - q->pool = kzalloc(num_arrays * max * sizeof(void*), GFP_KERNEL); - if (q->pool == NULL) - return -ENOMEM; - - kfifo_init(&q->queue, (void*)q->pool, max * sizeof(void*)); - - for (i = 0; i < max; i++) { - q->pool[i] = kzalloc(item_size, GFP_KERNEL); - if (q->pool[i] == NULL) { - q->max = i; - goto enomem; - } - kfifo_in(&q->queue, (void*)&q->pool[i], sizeof(void*)); - } - - if (items) { - *items = q->pool + max; - memcpy(*items, q->pool, max * sizeof(void *)); - } - - return 0; - -enomem: - iscsi_pool_free(q); - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(iscsi_pool_init); - -void iscsi_pool_free(struct iscsi_pool *q) -{ - int i; - - for (i = 0; i < q->max; i++) - kfree(q->pool[i]); - kfree(q->pool); -} -EXPORT_SYMBOL_GPL(iscsi_pool_free); - -/** - * iscsi_host_add - add host to system - * @shost: scsi host - * @pdev: parent device - * - * This should be called by partial offload and software iscsi drivers - * to add a host to the system. - */ -int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev) -{ - if (!shost->can_queue) - shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX; - - if (!shost->cmd_per_lun) - shost->cmd_per_lun = ISCSI_DEF_CMD_PER_LUN; - - if (!shost->transportt->eh_timed_out) - shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out; - return scsi_add_host(shost, pdev); -} -EXPORT_SYMBOL_GPL(iscsi_host_add); - -/** - * iscsi_host_alloc - allocate a host and driver data - * @sht: scsi host template - * @dd_data_size: driver host data size - * @xmit_can_sleep: bool indicating if LLD will queue IO from a work queue - * - * This should be called by partial offload and software iscsi drivers. - * To access the driver specific memory use the iscsi_host_priv() macro. - */ -struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht, - int dd_data_size, bool xmit_can_sleep) -{ - struct Scsi_Host *shost; - struct iscsi_host *ihost; - - shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size); - if (!shost) - return NULL; - ihost = shost_priv(shost); - - if (xmit_can_sleep) { - snprintf(ihost->workq_name, sizeof(ihost->workq_name), - "iscsi_q_%d", shost->host_no); - ihost->workq = create_singlethread_workqueue(ihost->workq_name); - if (!ihost->workq) - goto free_host; - } - - spin_lock_init(&ihost->lock); - ihost->state = ISCSI_HOST_SETUP; - ihost->num_sessions = 0; - init_waitqueue_head(&ihost->session_removal_wq); - return shost; - -free_host: - scsi_host_put(shost); - return NULL; -} -EXPORT_SYMBOL_GPL(iscsi_host_alloc); - -static void iscsi_notify_host_removed(struct iscsi_cls_session *cls_session) -{ - iscsi_session_failure(cls_session->dd_data, ISCSI_ERR_INVALID_HOST); -} - -/** - * iscsi_host_remove - remove host and sessions - * @shost: scsi host - * - * If there are any sessions left, this will initiate the removal and wait - * for the completion. - */ -void iscsi_host_remove(struct Scsi_Host *shost) -{ - struct iscsi_host *ihost = shost_priv(shost); - unsigned long flags; - - spin_lock_irqsave(&ihost->lock, flags); - ihost->state = ISCSI_HOST_REMOVED; - spin_unlock_irqrestore(&ihost->lock, flags); - - iscsi_host_for_each_session(shost, iscsi_notify_host_removed); - wait_event_interruptible(ihost->session_removal_wq, - ihost->num_sessions == 0); - if (signal_pending(current)) - flush_signals(current); - - scsi_remove_host(shost); - if (ihost->workq) - destroy_workqueue(ihost->workq); -} -EXPORT_SYMBOL_GPL(iscsi_host_remove); - -void iscsi_host_free(struct Scsi_Host *shost) -{ - struct iscsi_host *ihost = shost_priv(shost); - - kfree(ihost->netdev); - kfree(ihost->hwaddress); - kfree(ihost->initiatorname); - scsi_host_put(shost); -} -EXPORT_SYMBOL_GPL(iscsi_host_free); - -static void iscsi_host_dec_session_cnt(struct Scsi_Host *shost) -{ - struct iscsi_host *ihost = shost_priv(shost); - unsigned long flags; - - shost = scsi_host_get(shost); - if (!shost) { - printk(KERN_ERR "Invalid state. Cannot notify host removal " - "of session teardown event because host already " - "removed.\n"); - return; - } - - spin_lock_irqsave(&ihost->lock, flags); - ihost->num_sessions--; - if (ihost->num_sessions == 0) - wake_up(&ihost->session_removal_wq); - spin_unlock_irqrestore(&ihost->lock, flags); - scsi_host_put(shost); -} - -/** - * iscsi_session_setup - create iscsi cls session and host and session - * @iscsit: iscsi transport template - * @shost: scsi host - * @cmds_max: session can queue - * @cmd_task_size: LLD task private data size - * @initial_cmdsn: initial CmdSN - * - * This can be used by software iscsi_transports that allocate - * a session per scsi host. - * - * Callers should set cmds_max to the largest total numer (mgmt + scsi) of - * tasks they support. The iscsi layer reserves ISCSI_MGMT_CMDS_MAX tasks - * for nop handling and login/logout requests. - */ -struct iscsi_cls_session * -iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost, - uint16_t cmds_max, int dd_size, int cmd_task_size, - uint32_t initial_cmdsn, unsigned int id) -{ - struct iscsi_host *ihost = shost_priv(shost); - struct iscsi_session *session; - struct iscsi_cls_session *cls_session; - int cmd_i, scsi_cmds, total_cmds = cmds_max; - unsigned long flags; - - spin_lock_irqsave(&ihost->lock, flags); - if (ihost->state == ISCSI_HOST_REMOVED) { - spin_unlock_irqrestore(&ihost->lock, flags); - return NULL; - } - ihost->num_sessions++; - spin_unlock_irqrestore(&ihost->lock, flags); - - if (!total_cmds) - total_cmds = ISCSI_DEF_XMIT_CMDS_MAX; - /* - * The iscsi layer needs some tasks for nop handling and tmfs, - * so the cmds_max must at least be greater than ISCSI_MGMT_CMDS_MAX - * + 1 command for scsi IO. - */ - if (total_cmds < ISCSI_TOTAL_CMDS_MIN) { - printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " - "must be a power of two that is at least %d.\n", - total_cmds, ISCSI_TOTAL_CMDS_MIN); - goto dec_session_count; - } - - if (total_cmds > ISCSI_TOTAL_CMDS_MAX) { - printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " - "must be a power of 2 less than or equal to %d.\n", - cmds_max, ISCSI_TOTAL_CMDS_MAX); - total_cmds = ISCSI_TOTAL_CMDS_MAX; - } - - if (!is_power_of_2(total_cmds)) { - printk(KERN_ERR "iscsi: invalid can_queue of %d. can_queue " - "must be a power of 2.\n", total_cmds); - total_cmds = rounddown_pow_of_two(total_cmds); - if (total_cmds < ISCSI_TOTAL_CMDS_MIN) - return NULL; - printk(KERN_INFO "iscsi: Rounding can_queue to %d.\n", - total_cmds); - } - scsi_cmds = total_cmds - ISCSI_MGMT_CMDS_MAX; - - cls_session = iscsi_alloc_session(shost, iscsit, - sizeof(struct iscsi_session) + - dd_size); - if (!cls_session) - goto dec_session_count; - session = cls_session->dd_data; - session->cls_session = cls_session; - session->host = shost; - session->state = ISCSI_STATE_FREE; - session->fast_abort = 1; - session->tgt_reset_timeout = 30; - session->lu_reset_timeout = 15; - session->abort_timeout = 10; - session->scsi_cmds_max = scsi_cmds; - session->cmds_max = total_cmds; - session->queued_cmdsn = session->cmdsn = initial_cmdsn; - session->exp_cmdsn = initial_cmdsn + 1; - session->max_cmdsn = initial_cmdsn + 1; - session->max_r2t = 1; - session->tt = iscsit; - session->dd_data = cls_session->dd_data + sizeof(*session); - mutex_init(&session->eh_mutex); - spin_lock_init(&session->lock); - - /* initialize SCSI PDU commands pool */ - if (iscsi_pool_init(&session->cmdpool, session->cmds_max, - (void***)&session->cmds, - cmd_task_size + sizeof(struct iscsi_task))) - goto cmdpool_alloc_fail; - - /* pre-format cmds pool with ITT */ - for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { - struct iscsi_task *task = session->cmds[cmd_i]; - - if (cmd_task_size) - task->dd_data = &task[1]; - task->itt = cmd_i; - task->state = ISCSI_TASK_FREE; - INIT_LIST_HEAD(&task->running); - } - - if (!try_module_get(iscsit->owner)) - goto module_get_fail; - - if (iscsi_add_session(cls_session, id)) - goto cls_session_fail; - - return cls_session; - -cls_session_fail: - module_put(iscsit->owner); -module_get_fail: - iscsi_pool_free(&session->cmdpool); -cmdpool_alloc_fail: - iscsi_free_session(cls_session); -dec_session_count: - iscsi_host_dec_session_cnt(shost); - return NULL; -} -EXPORT_SYMBOL_GPL(iscsi_session_setup); - -/** - * iscsi_session_teardown - destroy session, host, and cls_session - * @cls_session: iscsi session - * - * The driver must have called iscsi_remove_session before - * calling this. - */ -void iscsi_session_teardown(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *session = cls_session->dd_data; - struct module *owner = cls_session->transport->owner; - struct Scsi_Host *shost = session->host; - - iscsi_pool_free(&session->cmdpool); - - kfree(session->password); - kfree(session->password_in); - kfree(session->username); - kfree(session->username_in); - kfree(session->targetname); - kfree(session->targetalias); - kfree(session->initiatorname); - kfree(session->ifacename); - - iscsi_destroy_session(cls_session); - iscsi_host_dec_session_cnt(shost); - module_put(owner); -} -EXPORT_SYMBOL_GPL(iscsi_session_teardown); - -/** - * iscsi_conn_setup - create iscsi_cls_conn and iscsi_conn - * @cls_session: iscsi_cls_session - * @dd_size: private driver data size - * @conn_idx: cid - */ -struct iscsi_cls_conn * -iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size, - uint32_t conn_idx) -{ - struct iscsi_session *session = cls_session->dd_data; - struct iscsi_conn *conn; - struct iscsi_cls_conn *cls_conn; - char *data; - - cls_conn = iscsi_create_conn(cls_session, sizeof(*conn) + dd_size, - conn_idx); - if (!cls_conn) - return NULL; - conn = cls_conn->dd_data; - memset(conn, 0, sizeof(*conn) + dd_size); - - conn->dd_data = cls_conn->dd_data + sizeof(*conn); - conn->session = session; - conn->cls_conn = cls_conn; - conn->c_stage = ISCSI_CONN_INITIAL_STAGE; - conn->id = conn_idx; - conn->exp_statsn = 0; - conn->tmf_state = TMF_INITIAL; - - init_timer(&conn->transport_timer); - conn->transport_timer.data = (unsigned long)conn; - conn->transport_timer.function = iscsi_check_transport_timeouts; - - INIT_LIST_HEAD(&conn->mgmtqueue); - INIT_LIST_HEAD(&conn->cmdqueue); - INIT_LIST_HEAD(&conn->requeue); - INIT_WORK(&conn->xmitwork, iscsi_xmitworker); - - /* allocate login_task used for the login/text sequences */ - spin_lock_bh(&session->lock); - if (!kfifo_out(&session->cmdpool.queue, - (void*)&conn->login_task, - sizeof(void*))) { - spin_unlock_bh(&session->lock); - goto login_task_alloc_fail; - } - spin_unlock_bh(&session->lock); - - data = (char *) __get_free_pages(GFP_KERNEL, - get_order(ISCSI_DEF_MAX_RECV_SEG_LEN)); - if (!data) - goto login_task_data_alloc_fail; - conn->login_task->data = conn->data = data; - - init_timer(&conn->tmf_timer); - init_waitqueue_head(&conn->ehwait); - - return cls_conn; - -login_task_data_alloc_fail: - kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task, - sizeof(void*)); -login_task_alloc_fail: - iscsi_destroy_conn(cls_conn); - return NULL; -} -EXPORT_SYMBOL_GPL(iscsi_conn_setup); - -/** - * iscsi_conn_teardown - teardown iscsi connection - * cls_conn: iscsi class connection - * - * TODO: we may need to make this into a two step process - * like scsi-mls remove + put host - */ -void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - unsigned long flags; - - del_timer_sync(&conn->transport_timer); - - spin_lock_bh(&session->lock); - conn->c_stage = ISCSI_CONN_CLEANUP_WAIT; - if (session->leadconn == conn) { - /* - * leading connection? then give up on recovery. - */ - session->state = ISCSI_STATE_TERMINATE; - wake_up(&conn->ehwait); - } - spin_unlock_bh(&session->lock); - - /* - * Block until all in-progress commands for this connection - * time out or fail. - */ - for (;;) { - spin_lock_irqsave(session->host->host_lock, flags); - if (!session->host->host_busy) { /* OK for ERL == 0 */ - spin_unlock_irqrestore(session->host->host_lock, flags); - break; - } - spin_unlock_irqrestore(session->host->host_lock, flags); - msleep_interruptible(500); - iscsi_conn_printk(KERN_INFO, conn, "iscsi conn_destroy(): " - "host_busy %d host_failed %d\n", - session->host->host_busy, - session->host->host_failed); - /* - * force eh_abort() to unblock - */ - wake_up(&conn->ehwait); - } - - /* flush queued up work because we free the connection below */ - iscsi_suspend_tx(conn); - - spin_lock_bh(&session->lock); - free_pages((unsigned long) conn->data, - get_order(ISCSI_DEF_MAX_RECV_SEG_LEN)); - kfree(conn->persistent_address); - kfifo_in(&session->cmdpool.queue, (void*)&conn->login_task, - sizeof(void*)); - if (session->leadconn == conn) - session->leadconn = NULL; - spin_unlock_bh(&session->lock); - - iscsi_destroy_conn(cls_conn); -} -EXPORT_SYMBOL_GPL(iscsi_conn_teardown); - -int iscsi_conn_start(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - - if (!session) { - iscsi_conn_printk(KERN_ERR, conn, - "can't start unbound connection\n"); - return -EPERM; - } - - if ((session->imm_data_en || !session->initial_r2t_en) && - session->first_burst > session->max_burst) { - iscsi_conn_printk(KERN_INFO, conn, "invalid burst lengths: " - "first_burst %d max_burst %d\n", - session->first_burst, session->max_burst); - return -EINVAL; - } - - if (conn->ping_timeout && !conn->recv_timeout) { - iscsi_conn_printk(KERN_ERR, conn, "invalid recv timeout of " - "zero. Using 5 seconds\n."); - conn->recv_timeout = 5; - } - - if (conn->recv_timeout && !conn->ping_timeout) { - iscsi_conn_printk(KERN_ERR, conn, "invalid ping timeout of " - "zero. Using 5 seconds.\n"); - conn->ping_timeout = 5; - } - - spin_lock_bh(&session->lock); - conn->c_stage = ISCSI_CONN_STARTED; - session->state = ISCSI_STATE_LOGGED_IN; - session->queued_cmdsn = session->cmdsn; - - conn->last_recv = jiffies; - conn->last_ping = jiffies; - if (conn->recv_timeout && conn->ping_timeout) - mod_timer(&conn->transport_timer, - jiffies + (conn->recv_timeout * HZ)); - - switch(conn->stop_stage) { - case STOP_CONN_RECOVER: - /* - * unblock eh_abort() if it is blocked. re-try all - * commands after successful recovery - */ - conn->stop_stage = 0; - conn->tmf_state = TMF_INITIAL; - session->age++; - if (session->age == 16) - session->age = 0; - break; - case STOP_CONN_TERM: - conn->stop_stage = 0; - break; - default: - break; - } - spin_unlock_bh(&session->lock); - - iscsi_unblock_session(session->cls_session); - wake_up(&conn->ehwait); - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_conn_start); - -static void -fail_mgmt_tasks(struct iscsi_session *session, struct iscsi_conn *conn) -{ - struct iscsi_task *task; - int i, state; - - for (i = 0; i < conn->session->cmds_max; i++) { - task = conn->session->cmds[i]; - if (task->sc) - continue; - - if (task->state == ISCSI_TASK_FREE) - continue; - - ISCSI_DBG_SESSION(conn->session, - "failing mgmt itt 0x%x state %d\n", - task->itt, task->state); - state = ISCSI_TASK_ABRT_SESS_RECOV; - if (task->state == ISCSI_TASK_PENDING) - state = ISCSI_TASK_COMPLETED; - iscsi_complete_task(task, state); - - } -} - -static void iscsi_start_session_recovery(struct iscsi_session *session, - struct iscsi_conn *conn, int flag) -{ - int old_stop_stage; - - mutex_lock(&session->eh_mutex); - spin_lock_bh(&session->lock); - if (conn->stop_stage == STOP_CONN_TERM) { - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); - return; - } - - /* - * When this is called for the in_login state, we only want to clean - * up the login task and connection. We do not need to block and set - * the recovery state again - */ - if (flag == STOP_CONN_TERM) - session->state = ISCSI_STATE_TERMINATE; - else if (conn->stop_stage != STOP_CONN_RECOVER) - session->state = ISCSI_STATE_IN_RECOVERY; - - old_stop_stage = conn->stop_stage; - conn->stop_stage = flag; - spin_unlock_bh(&session->lock); - - del_timer_sync(&conn->transport_timer); - iscsi_suspend_tx(conn); - - spin_lock_bh(&session->lock); - conn->c_stage = ISCSI_CONN_STOPPED; - spin_unlock_bh(&session->lock); - - /* - * for connection level recovery we should not calculate - * header digest. conn->hdr_size used for optimization - * in hdr_extract() and will be re-negotiated at - * set_param() time. - */ - if (flag == STOP_CONN_RECOVER) { - conn->hdrdgst_en = 0; - conn->datadgst_en = 0; - if (session->state == ISCSI_STATE_IN_RECOVERY && - old_stop_stage != STOP_CONN_RECOVER) { - ISCSI_DBG_SESSION(session, "blocking session\n"); - iscsi_block_session(session->cls_session); - } - } - - /* - * flush queues. - */ - spin_lock_bh(&session->lock); - fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED); - fail_mgmt_tasks(session, conn); - memset(&conn->tmhdr, 0, sizeof(conn->tmhdr)); - spin_unlock_bh(&session->lock); - mutex_unlock(&session->eh_mutex); -} - -void iscsi_conn_stop(struct iscsi_cls_conn *cls_conn, int flag) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - - switch (flag) { - case STOP_CONN_RECOVER: - case STOP_CONN_TERM: - iscsi_start_session_recovery(session, conn, flag); - break; - default: - iscsi_conn_printk(KERN_ERR, conn, - "invalid stop flag %d\n", flag); - } -} -EXPORT_SYMBOL_GPL(iscsi_conn_stop); - -int iscsi_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, int is_leading) -{ - struct iscsi_session *session = cls_session->dd_data; - struct iscsi_conn *conn = cls_conn->dd_data; - - spin_lock_bh(&session->lock); - if (is_leading) - session->leadconn = conn; - spin_unlock_bh(&session->lock); - - /* - * Unblock xmitworker(), Login Phase will pass through. - */ - clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_rx); - clear_bit(ISCSI_SUSPEND_BIT, &conn->suspend_tx); - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_conn_bind); - -static int iscsi_switch_str_param(char **param, char *new_val_buf) -{ - char *new_val; - - if (*param) { - if (!strcmp(*param, new_val_buf)) - return 0; - } - - new_val = kstrdup(new_val_buf, GFP_NOIO); - if (!new_val) - return -ENOMEM; - - kfree(*param); - *param = new_val; - return 0; -} - -int iscsi_set_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf, int buflen) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - struct iscsi_session *session = conn->session; - - switch(param) { - case ISCSI_PARAM_FAST_ABORT: - sscanf(buf, "%d", &session->fast_abort); - break; - case ISCSI_PARAM_ABORT_TMO: - sscanf(buf, "%d", &session->abort_timeout); - break; - case ISCSI_PARAM_LU_RESET_TMO: - sscanf(buf, "%d", &session->lu_reset_timeout); - break; - case ISCSI_PARAM_TGT_RESET_TMO: - sscanf(buf, "%d", &session->tgt_reset_timeout); - break; - case ISCSI_PARAM_PING_TMO: - sscanf(buf, "%d", &conn->ping_timeout); - break; - case ISCSI_PARAM_RECV_TMO: - sscanf(buf, "%d", &conn->recv_timeout); - break; - case ISCSI_PARAM_MAX_RECV_DLENGTH: - sscanf(buf, "%d", &conn->max_recv_dlength); - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - sscanf(buf, "%d", &conn->max_xmit_dlength); - break; - case ISCSI_PARAM_HDRDGST_EN: - sscanf(buf, "%d", &conn->hdrdgst_en); - break; - case ISCSI_PARAM_DATADGST_EN: - sscanf(buf, "%d", &conn->datadgst_en); - break; - case ISCSI_PARAM_INITIAL_R2T_EN: - sscanf(buf, "%d", &session->initial_r2t_en); - break; - case ISCSI_PARAM_MAX_R2T: - sscanf(buf, "%hu", &session->max_r2t); - break; - case ISCSI_PARAM_IMM_DATA_EN: - sscanf(buf, "%d", &session->imm_data_en); - break; - case ISCSI_PARAM_FIRST_BURST: - sscanf(buf, "%d", &session->first_burst); - break; - case ISCSI_PARAM_MAX_BURST: - sscanf(buf, "%d", &session->max_burst); - break; - case ISCSI_PARAM_PDU_INORDER_EN: - sscanf(buf, "%d", &session->pdu_inorder_en); - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - sscanf(buf, "%d", &session->dataseq_inorder_en); - break; - case ISCSI_PARAM_ERL: - sscanf(buf, "%d", &session->erl); - break; - case ISCSI_PARAM_EXP_STATSN: - sscanf(buf, "%u", &conn->exp_statsn); - break; - case ISCSI_PARAM_USERNAME: - return iscsi_switch_str_param(&session->username, buf); - case ISCSI_PARAM_USERNAME_IN: - return iscsi_switch_str_param(&session->username_in, buf); - case ISCSI_PARAM_PASSWORD: - return iscsi_switch_str_param(&session->password, buf); - case ISCSI_PARAM_PASSWORD_IN: - return iscsi_switch_str_param(&session->password_in, buf); - case ISCSI_PARAM_TARGET_NAME: - return iscsi_switch_str_param(&session->targetname, buf); - case ISCSI_PARAM_TARGET_ALIAS: - return iscsi_switch_str_param(&session->targetalias, buf); - case ISCSI_PARAM_TPGT: - sscanf(buf, "%d", &session->tpgt); - break; - case ISCSI_PARAM_PERSISTENT_PORT: - sscanf(buf, "%d", &conn->persistent_port); - break; - case ISCSI_PARAM_PERSISTENT_ADDRESS: - return iscsi_switch_str_param(&conn->persistent_address, buf); - case ISCSI_PARAM_IFACE_NAME: - return iscsi_switch_str_param(&session->ifacename, buf); - case ISCSI_PARAM_INITIATOR_NAME: - return iscsi_switch_str_param(&session->initiatorname, buf); - default: - return -ENOSYS; - } - - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_set_param); - -int iscsi_session_get_param(struct iscsi_cls_session *cls_session, - enum iscsi_param param, char *buf) -{ - struct iscsi_session *session = cls_session->dd_data; - int len; - - switch(param) { - case ISCSI_PARAM_FAST_ABORT: - len = sprintf(buf, "%d\n", session->fast_abort); - break; - case ISCSI_PARAM_ABORT_TMO: - len = sprintf(buf, "%d\n", session->abort_timeout); - break; - case ISCSI_PARAM_LU_RESET_TMO: - len = sprintf(buf, "%d\n", session->lu_reset_timeout); - break; - case ISCSI_PARAM_TGT_RESET_TMO: - len = sprintf(buf, "%d\n", session->tgt_reset_timeout); - break; - case ISCSI_PARAM_INITIAL_R2T_EN: - len = sprintf(buf, "%d\n", session->initial_r2t_en); - break; - case ISCSI_PARAM_MAX_R2T: - len = sprintf(buf, "%hu\n", session->max_r2t); - break; - case ISCSI_PARAM_IMM_DATA_EN: - len = sprintf(buf, "%d\n", session->imm_data_en); - break; - case ISCSI_PARAM_FIRST_BURST: - len = sprintf(buf, "%u\n", session->first_burst); - break; - case ISCSI_PARAM_MAX_BURST: - len = sprintf(buf, "%u\n", session->max_burst); - break; - case ISCSI_PARAM_PDU_INORDER_EN: - len = sprintf(buf, "%d\n", session->pdu_inorder_en); - break; - case ISCSI_PARAM_DATASEQ_INORDER_EN: - len = sprintf(buf, "%d\n", session->dataseq_inorder_en); - break; - case ISCSI_PARAM_ERL: - len = sprintf(buf, "%d\n", session->erl); - break; - case ISCSI_PARAM_TARGET_NAME: - len = sprintf(buf, "%s\n", session->targetname); - break; - case ISCSI_PARAM_TARGET_ALIAS: - len = sprintf(buf, "%s\n", session->targetalias); - break; - case ISCSI_PARAM_TPGT: - len = sprintf(buf, "%d\n", session->tpgt); - break; - case ISCSI_PARAM_USERNAME: - len = sprintf(buf, "%s\n", session->username); - break; - case ISCSI_PARAM_USERNAME_IN: - len = sprintf(buf, "%s\n", session->username_in); - break; - case ISCSI_PARAM_PASSWORD: - len = sprintf(buf, "%s\n", session->password); - break; - case ISCSI_PARAM_PASSWORD_IN: - len = sprintf(buf, "%s\n", session->password_in); - break; - case ISCSI_PARAM_IFACE_NAME: - len = sprintf(buf, "%s\n", session->ifacename); - break; - case ISCSI_PARAM_INITIATOR_NAME: - len = sprintf(buf, "%s\n", session->initiatorname); - break; - default: - return -ENOSYS; - } - - return len; -} -EXPORT_SYMBOL_GPL(iscsi_session_get_param); - -int iscsi_conn_get_addr_param(struct sockaddr_storage *addr, - enum iscsi_param param, char *buf) -{ - struct sockaddr_in6 *sin6 = NULL; - struct sockaddr_in *sin = NULL; - int len; - - switch (addr->ss_family) { - case AF_INET: - sin = (struct sockaddr_in *)addr; - break; - case AF_INET6: - sin6 = (struct sockaddr_in6 *)addr; - break; - default: - return -EINVAL; - } - - switch (param) { - case ISCSI_PARAM_CONN_ADDRESS: - case ISCSI_HOST_PARAM_IPADDRESS: - if (sin) - len = sprintf(buf, "%pI4\n", &sin->sin_addr.s_addr); - else - len = sprintf(buf, "%pI6\n", &sin6->sin6_addr); - break; - case ISCSI_PARAM_CONN_PORT: - if (sin) - len = sprintf(buf, "%hu\n", be16_to_cpu(sin->sin_port)); - else - len = sprintf(buf, "%hu\n", - be16_to_cpu(sin6->sin6_port)); - break; - default: - return -EINVAL; - } - - return len; -} -EXPORT_SYMBOL_GPL(iscsi_conn_get_addr_param); - -int iscsi_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - int len; - - switch(param) { - case ISCSI_PARAM_PING_TMO: - len = sprintf(buf, "%u\n", conn->ping_timeout); - break; - case ISCSI_PARAM_RECV_TMO: - len = sprintf(buf, "%u\n", conn->recv_timeout); - break; - case ISCSI_PARAM_MAX_RECV_DLENGTH: - len = sprintf(buf, "%u\n", conn->max_recv_dlength); - break; - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - len = sprintf(buf, "%u\n", conn->max_xmit_dlength); - break; - case ISCSI_PARAM_HDRDGST_EN: - len = sprintf(buf, "%d\n", conn->hdrdgst_en); - break; - case ISCSI_PARAM_DATADGST_EN: - len = sprintf(buf, "%d\n", conn->datadgst_en); - break; - case ISCSI_PARAM_IFMARKER_EN: - len = sprintf(buf, "%d\n", conn->ifmarker_en); - break; - case ISCSI_PARAM_OFMARKER_EN: - len = sprintf(buf, "%d\n", conn->ofmarker_en); - break; - case ISCSI_PARAM_EXP_STATSN: - len = sprintf(buf, "%u\n", conn->exp_statsn); - break; - case ISCSI_PARAM_PERSISTENT_PORT: - len = sprintf(buf, "%d\n", conn->persistent_port); - break; - case ISCSI_PARAM_PERSISTENT_ADDRESS: - len = sprintf(buf, "%s\n", conn->persistent_address); - break; - default: - return -ENOSYS; - } - - return len; -} -EXPORT_SYMBOL_GPL(iscsi_conn_get_param); - -int iscsi_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, - char *buf) -{ - struct iscsi_host *ihost = shost_priv(shost); - int len; - - switch (param) { - case ISCSI_HOST_PARAM_NETDEV_NAME: - len = sprintf(buf, "%s\n", ihost->netdev); - break; - case ISCSI_HOST_PARAM_HWADDRESS: - len = sprintf(buf, "%s\n", ihost->hwaddress); - break; - case ISCSI_HOST_PARAM_INITIATOR_NAME: - len = sprintf(buf, "%s\n", ihost->initiatorname); - break; - default: - return -ENOSYS; - } - - return len; -} -EXPORT_SYMBOL_GPL(iscsi_host_get_param); - -int iscsi_host_set_param(struct Scsi_Host *shost, enum iscsi_host_param param, - char *buf, int buflen) -{ - struct iscsi_host *ihost = shost_priv(shost); - - switch (param) { - case ISCSI_HOST_PARAM_NETDEV_NAME: - return iscsi_switch_str_param(&ihost->netdev, buf); - case ISCSI_HOST_PARAM_HWADDRESS: - return iscsi_switch_str_param(&ihost->hwaddress, buf); - case ISCSI_HOST_PARAM_INITIATOR_NAME: - return iscsi_switch_str_param(&ihost->initiatorname, buf); - default: - return -ENOSYS; - } - - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_host_set_param); - -MODULE_AUTHOR("Mike Christie"); -MODULE_DESCRIPTION("iSCSI library functions"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/libiscsi_tcp.c b/ANDROID_3.4.5/drivers/scsi/libiscsi_tcp.c deleted file mode 100644 index 552e8a2b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libiscsi_tcp.c +++ /dev/null @@ -1,1206 +0,0 @@ -/* - * iSCSI over TCP/IP Data-Path lib - * - * Copyright (C) 2004 Dmitry Yusupov - * Copyright (C) 2004 Alex Aizman - * Copyright (C) 2005 - 2006 Mike Christie - * Copyright (C) 2006 Red Hat, Inc. All rights reserved. - * maintained by open-iscsi@googlegroups.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * See the file COPYING included with this distribution for more details. - * - * Credits: - * Christoph Hellwig - * FUJITA Tomonori - * Arne Redlich - * Zhenyu Wang - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iscsi_tcp.h" - -MODULE_AUTHOR("Mike Christie , " - "Dmitry Yusupov , " - "Alex Aizman "); -MODULE_DESCRIPTION("iSCSI/TCP data-path"); -MODULE_LICENSE("GPL"); - -static int iscsi_dbg_libtcp; -module_param_named(debug_libiscsi_tcp, iscsi_dbg_libtcp, int, - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_libiscsi_tcp, "Turn on debugging for libiscsi_tcp " - "module. Set to 1 to turn on, and zero to turn off. Default " - "is off."); - -#define ISCSI_DBG_TCP(_conn, dbg_fmt, arg...) \ - do { \ - if (iscsi_dbg_libtcp) \ - iscsi_conn_printk(KERN_INFO, _conn, \ - "%s " dbg_fmt, \ - __func__, ##arg); \ - } while (0); - -static int iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment); - -/* - * Scatterlist handling: inside the iscsi_segment, we - * remember an index into the scatterlist, and set data/size - * to the current scatterlist entry. For highmem pages, we - * kmap as needed. - * - * Note that the page is unmapped when we return from - * TCP's data_ready handler, so we may end up mapping and - * unmapping the same page repeatedly. The whole reason - * for this is that we shouldn't keep the page mapped - * outside the softirq. - */ - -/** - * iscsi_tcp_segment_init_sg - init indicated scatterlist entry - * @segment: the buffer object - * @sg: scatterlist - * @offset: byte offset into that sg entry - * - * This function sets up the segment so that subsequent - * data is copied to the indicated sg entry, at the given - * offset. - */ -static inline void -iscsi_tcp_segment_init_sg(struct iscsi_segment *segment, - struct scatterlist *sg, unsigned int offset) -{ - segment->sg = sg; - segment->sg_offset = offset; - segment->size = min(sg->length - offset, - segment->total_size - segment->total_copied); - segment->data = NULL; -} - -/** - * iscsi_tcp_segment_map - map the current S/G page - * @segment: iscsi_segment - * @recv: 1 if called from recv path - * - * We only need to possibly kmap data if scatter lists are being used, - * because the iscsi passthrough and internal IO paths will never use high - * mem pages. - */ -static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) -{ - struct scatterlist *sg; - - if (segment->data != NULL || !segment->sg) - return; - - sg = segment->sg; - BUG_ON(segment->sg_mapped); - BUG_ON(sg->length == 0); - - /* - * If the page count is greater than one it is ok to send - * to the network layer's zero copy send path. If not we - * have to go the slow sendmsg path. We always map for the - * recv path. - */ - if (page_count(sg_page(sg)) >= 1 && !recv) - return; - - if (recv) { - segment->atomic_mapped = true; - segment->sg_mapped = kmap_atomic(sg_page(sg)); - } else { - segment->atomic_mapped = false; - /* the xmit path can sleep with the page mapped so use kmap */ - segment->sg_mapped = kmap(sg_page(sg)); - } - - segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; -} - -void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) -{ - if (segment->sg_mapped) { - if (segment->atomic_mapped) - kunmap_atomic(segment->sg_mapped); - else - kunmap(sg_page(segment->sg)); - segment->sg_mapped = NULL; - segment->data = NULL; - } -} -EXPORT_SYMBOL_GPL(iscsi_tcp_segment_unmap); - -/* - * Splice the digest buffer into the buffer - */ -static inline void -iscsi_tcp_segment_splice_digest(struct iscsi_segment *segment, void *digest) -{ - segment->data = digest; - segment->digest_len = ISCSI_DIGEST_SIZE; - segment->total_size += ISCSI_DIGEST_SIZE; - segment->size = ISCSI_DIGEST_SIZE; - segment->copied = 0; - segment->sg = NULL; - segment->hash = NULL; -} - -/** - * iscsi_tcp_segment_done - check whether the segment is complete - * @tcp_conn: iscsi tcp connection - * @segment: iscsi segment to check - * @recv: set to one of this is called from the recv path - * @copied: number of bytes copied - * - * Check if we're done receiving this segment. If the receive - * buffer is full but we expect more data, move on to the - * next entry in the scatterlist. - * - * If the amount of data we received isn't a multiple of 4, - * we will transparently receive the pad bytes, too. - * - * This function must be re-entrant. - */ -int iscsi_tcp_segment_done(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment, int recv, - unsigned copied) -{ - struct scatterlist sg; - unsigned int pad; - - ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copied %u %u size %u %s\n", - segment->copied, copied, segment->size, - recv ? "recv" : "xmit"); - if (segment->hash && copied) { - /* - * If a segment is kmapd we must unmap it before sending - * to the crypto layer since that will try to kmap it again. - */ - iscsi_tcp_segment_unmap(segment); - - if (!segment->data) { - sg_init_table(&sg, 1); - sg_set_page(&sg, sg_page(segment->sg), copied, - segment->copied + segment->sg_offset + - segment->sg->offset); - } else - sg_init_one(&sg, segment->data + segment->copied, - copied); - crypto_hash_update(segment->hash, &sg, copied); - } - - segment->copied += copied; - if (segment->copied < segment->size) { - iscsi_tcp_segment_map(segment, recv); - return 0; - } - - segment->total_copied += segment->copied; - segment->copied = 0; - segment->size = 0; - - /* Unmap the current scatterlist page, if there is one. */ - iscsi_tcp_segment_unmap(segment); - - /* Do we have more scatterlist entries? */ - ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "total copied %u total size %u\n", - segment->total_copied, segment->total_size); - if (segment->total_copied < segment->total_size) { - /* Proceed to the next entry in the scatterlist. */ - iscsi_tcp_segment_init_sg(segment, sg_next(segment->sg), - 0); - iscsi_tcp_segment_map(segment, recv); - BUG_ON(segment->size == 0); - return 0; - } - - /* Do we need to handle padding? */ - if (!(tcp_conn->iscsi_conn->session->tt->caps & CAP_PADDING_OFFLOAD)) { - pad = iscsi_padding(segment->total_copied); - if (pad != 0) { - ISCSI_DBG_TCP(tcp_conn->iscsi_conn, - "consume %d pad bytes\n", pad); - segment->total_size += pad; - segment->size = pad; - segment->data = segment->padbuf; - return 0; - } - } - - /* - * Set us up for transferring the data digest. hdr digest - * is completely handled in hdr done function. - */ - if (segment->hash) { - crypto_hash_final(segment->hash, segment->digest); - iscsi_tcp_segment_splice_digest(segment, - recv ? segment->recv_digest : segment->digest); - return 0; - } - - return 1; -} -EXPORT_SYMBOL_GPL(iscsi_tcp_segment_done); - -/** - * iscsi_tcp_segment_recv - copy data to segment - * @tcp_conn: the iSCSI TCP connection - * @segment: the buffer to copy to - * @ptr: data pointer - * @len: amount of data available - * - * This function copies up to @len bytes to the - * given buffer, and returns the number of bytes - * consumed, which can actually be less than @len. - * - * If hash digest is enabled, the function will update the - * hash while copying. - * Combining these two operations doesn't buy us a lot (yet), - * but in the future we could implement combined copy+crc, - * just way we do for network layer checksums. - */ -static int -iscsi_tcp_segment_recv(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment, const void *ptr, - unsigned int len) -{ - unsigned int copy = 0, copied = 0; - - while (!iscsi_tcp_segment_done(tcp_conn, segment, 1, copy)) { - if (copied == len) { - ISCSI_DBG_TCP(tcp_conn->iscsi_conn, - "copied %d bytes\n", len); - break; - } - - copy = min(len - copied, segment->size - segment->copied); - ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "copying %d\n", copy); - memcpy(segment->data + segment->copied, ptr + copied, copy); - copied += copy; - } - return copied; -} - -inline void -iscsi_tcp_dgst_header(struct hash_desc *hash, const void *hdr, size_t hdrlen, - unsigned char digest[ISCSI_DIGEST_SIZE]) -{ - struct scatterlist sg; - - sg_init_one(&sg, hdr, hdrlen); - crypto_hash_digest(hash, &sg, hdrlen, digest); -} -EXPORT_SYMBOL_GPL(iscsi_tcp_dgst_header); - -static inline int -iscsi_tcp_dgst_verify(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment) -{ - if (!segment->digest_len) - return 1; - - if (memcmp(segment->recv_digest, segment->digest, - segment->digest_len)) { - ISCSI_DBG_TCP(tcp_conn->iscsi_conn, "digest mismatch\n"); - return 0; - } - - return 1; -} - -/* - * Helper function to set up segment buffer - */ -static inline void -__iscsi_segment_init(struct iscsi_segment *segment, size_t size, - iscsi_segment_done_fn_t *done, struct hash_desc *hash) -{ - memset(segment, 0, sizeof(*segment)); - segment->total_size = size; - segment->done = done; - - if (hash) { - segment->hash = hash; - crypto_hash_init(hash); - } -} - -inline void -iscsi_segment_init_linear(struct iscsi_segment *segment, void *data, - size_t size, iscsi_segment_done_fn_t *done, - struct hash_desc *hash) -{ - __iscsi_segment_init(segment, size, done, hash); - segment->data = data; - segment->size = size; -} -EXPORT_SYMBOL_GPL(iscsi_segment_init_linear); - -inline int -iscsi_segment_seek_sg(struct iscsi_segment *segment, - struct scatterlist *sg_list, unsigned int sg_count, - unsigned int offset, size_t size, - iscsi_segment_done_fn_t *done, struct hash_desc *hash) -{ - struct scatterlist *sg; - unsigned int i; - - __iscsi_segment_init(segment, size, done, hash); - for_each_sg(sg_list, sg, sg_count, i) { - if (offset < sg->length) { - iscsi_tcp_segment_init_sg(segment, sg, offset); - return 0; - } - offset -= sg->length; - } - - return ISCSI_ERR_DATA_OFFSET; -} -EXPORT_SYMBOL_GPL(iscsi_segment_seek_sg); - -/** - * iscsi_tcp_hdr_recv_prep - prep segment for hdr reception - * @tcp_conn: iscsi connection to prep for - * - * This function always passes NULL for the hash argument, because when this - * function is called we do not yet know the final size of the header and want - * to delay the digest processing until we know that. - */ -void iscsi_tcp_hdr_recv_prep(struct iscsi_tcp_conn *tcp_conn) -{ - ISCSI_DBG_TCP(tcp_conn->iscsi_conn, - "(%s)\n", tcp_conn->iscsi_conn->hdrdgst_en ? - "digest enabled" : "digest disabled"); - iscsi_segment_init_linear(&tcp_conn->in.segment, - tcp_conn->in.hdr_buf, sizeof(struct iscsi_hdr), - iscsi_tcp_hdr_recv_done, NULL); -} -EXPORT_SYMBOL_GPL(iscsi_tcp_hdr_recv_prep); - -/* - * Handle incoming reply to any other type of command - */ -static int -iscsi_tcp_data_recv_done(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment) -{ - struct iscsi_conn *conn = tcp_conn->iscsi_conn; - int rc = 0; - - if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) - return ISCSI_ERR_DATA_DGST; - - rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, - conn->data, tcp_conn->in.datalen); - if (rc) - return rc; - - iscsi_tcp_hdr_recv_prep(tcp_conn); - return 0; -} - -static void -iscsi_tcp_data_recv_prep(struct iscsi_tcp_conn *tcp_conn) -{ - struct iscsi_conn *conn = tcp_conn->iscsi_conn; - struct hash_desc *rx_hash = NULL; - - if (conn->datadgst_en && - !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) - rx_hash = tcp_conn->rx_hash; - - iscsi_segment_init_linear(&tcp_conn->in.segment, - conn->data, tcp_conn->in.datalen, - iscsi_tcp_data_recv_done, rx_hash); -} - -/** - * iscsi_tcp_cleanup_task - free tcp_task resources - * @task: iscsi task - * - * must be called with session lock - */ -void iscsi_tcp_cleanup_task(struct iscsi_task *task) -{ - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct iscsi_r2t_info *r2t; - - /* nothing to do for mgmt */ - if (!task->sc) - return; - - /* flush task's r2t queues */ - while (kfifo_out(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*))) { - kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t, - sizeof(void*)); - ISCSI_DBG_TCP(task->conn, "pending r2t dropped\n"); - } - - r2t = tcp_task->r2t; - if (r2t != NULL) { - kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t, - sizeof(void*)); - tcp_task->r2t = NULL; - } -} -EXPORT_SYMBOL_GPL(iscsi_tcp_cleanup_task); - -/** - * iscsi_tcp_data_in - SCSI Data-In Response processing - * @conn: iscsi connection - * @task: scsi command task - */ -static int iscsi_tcp_data_in(struct iscsi_conn *conn, struct iscsi_task *task) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct iscsi_data_rsp *rhdr = (struct iscsi_data_rsp *)tcp_conn->in.hdr; - int datasn = be32_to_cpu(rhdr->datasn); - unsigned total_in_length = scsi_in(task->sc)->length; - - /* - * lib iscsi will update this in the completion handling if there - * is status. - */ - if (!(rhdr->flags & ISCSI_FLAG_DATA_STATUS)) - iscsi_update_cmdsn(conn->session, (struct iscsi_nopin*)rhdr); - - if (tcp_conn->in.datalen == 0) - return 0; - - if (tcp_task->exp_datasn != datasn) { - ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->datasn(%d)" - "\n", tcp_task->exp_datasn, datasn); - return ISCSI_ERR_DATASN; - } - - tcp_task->exp_datasn++; - - tcp_task->data_offset = be32_to_cpu(rhdr->offset); - if (tcp_task->data_offset + tcp_conn->in.datalen > total_in_length) { - ISCSI_DBG_TCP(conn, "data_offset(%d) + data_len(%d) > " - "total_length_in(%d)\n", tcp_task->data_offset, - tcp_conn->in.datalen, total_in_length); - return ISCSI_ERR_DATA_OFFSET; - } - - conn->datain_pdus_cnt++; - return 0; -} - -/** - * iscsi_tcp_r2t_rsp - iSCSI R2T Response processing - * @conn: iscsi connection - * @task: scsi command task - */ -static int iscsi_tcp_r2t_rsp(struct iscsi_conn *conn, struct iscsi_task *task) -{ - struct iscsi_session *session = conn->session; - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_r2t_rsp *rhdr = (struct iscsi_r2t_rsp *)tcp_conn->in.hdr; - struct iscsi_r2t_info *r2t; - int r2tsn = be32_to_cpu(rhdr->r2tsn); - int rc; - - if (tcp_conn->in.datalen) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2t with datalen %d\n", - tcp_conn->in.datalen); - return ISCSI_ERR_DATALEN; - } - - if (tcp_task->exp_datasn != r2tsn){ - ISCSI_DBG_TCP(conn, "task->exp_datasn(%d) != rhdr->r2tsn(%d)\n", - tcp_task->exp_datasn, r2tsn); - return ISCSI_ERR_R2TSN; - } - - /* fill-in new R2T associated with the task */ - iscsi_update_cmdsn(session, (struct iscsi_nopin*)rhdr); - - if (!task->sc || session->state != ISCSI_STATE_LOGGED_IN) { - iscsi_conn_printk(KERN_INFO, conn, - "dropping R2T itt %d in recovery.\n", - task->itt); - return 0; - } - - rc = kfifo_out(&tcp_task->r2tpool.queue, (void*)&r2t, sizeof(void*)); - if (!rc) { - iscsi_conn_printk(KERN_ERR, conn, "Could not allocate R2T. " - "Target has sent more R2Ts than it " - "negotiated for or driver has has leaked.\n"); - return ISCSI_ERR_PROTO; - } - - r2t->exp_statsn = rhdr->statsn; - r2t->data_length = be32_to_cpu(rhdr->data_length); - if (r2t->data_length == 0) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2T with zero data len\n"); - kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t, - sizeof(void*)); - return ISCSI_ERR_DATALEN; - } - - if (r2t->data_length > session->max_burst) - ISCSI_DBG_TCP(conn, "invalid R2T with data len %u and max " - "burst %u. Attempting to execute request.\n", - r2t->data_length, session->max_burst); - - r2t->data_offset = be32_to_cpu(rhdr->data_offset); - if (r2t->data_offset + r2t->data_length > scsi_out(task->sc)->length) { - iscsi_conn_printk(KERN_ERR, conn, - "invalid R2T with data len %u at offset %u " - "and total length %d\n", r2t->data_length, - r2t->data_offset, scsi_out(task->sc)->length); - kfifo_in(&tcp_task->r2tpool.queue, (void*)&r2t, - sizeof(void*)); - return ISCSI_ERR_DATALEN; - } - - r2t->ttt = rhdr->ttt; /* no flip */ - r2t->datasn = 0; - r2t->sent = 0; - - tcp_task->exp_datasn = r2tsn + 1; - kfifo_in(&tcp_task->r2tqueue, (void*)&r2t, sizeof(void*)); - conn->r2t_pdus_cnt++; - - iscsi_requeue_task(task); - return 0; -} - -/* - * Handle incoming reply to DataIn command - */ -static int -iscsi_tcp_process_data_in(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment) -{ - struct iscsi_conn *conn = tcp_conn->iscsi_conn; - struct iscsi_hdr *hdr = tcp_conn->in.hdr; - int rc; - - if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) - return ISCSI_ERR_DATA_DGST; - - /* check for non-exceptional status */ - if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { - rc = iscsi_complete_pdu(conn, tcp_conn->in.hdr, NULL, 0); - if (rc) - return rc; - } - - iscsi_tcp_hdr_recv_prep(tcp_conn); - return 0; -} - -/** - * iscsi_tcp_hdr_dissect - process PDU header - * @conn: iSCSI connection - * @hdr: PDU header - * - * This function analyzes the header of the PDU received, - * and performs several sanity checks. If the PDU is accompanied - * by data, the receive buffer is set up to copy the incoming data - * to the correct location. - */ -static int -iscsi_tcp_hdr_dissect(struct iscsi_conn *conn, struct iscsi_hdr *hdr) -{ - int rc = 0, opcode, ahslen; - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_task *task; - - /* verify PDU length */ - tcp_conn->in.datalen = ntoh24(hdr->dlength); - if (tcp_conn->in.datalen > conn->max_recv_dlength) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi_tcp: datalen %d > %d\n", - tcp_conn->in.datalen, conn->max_recv_dlength); - return ISCSI_ERR_DATALEN; - } - - /* Additional header segments. So far, we don't - * process additional headers. - */ - ahslen = hdr->hlength << 2; - - opcode = hdr->opcode & ISCSI_OPCODE_MASK; - /* verify itt (itt encoding: age+cid+itt) */ - rc = iscsi_verify_itt(conn, hdr->itt); - if (rc) - return rc; - - ISCSI_DBG_TCP(conn, "opcode 0x%x ahslen %d datalen %d\n", - opcode, ahslen, tcp_conn->in.datalen); - - switch(opcode) { - case ISCSI_OP_SCSI_DATA_IN: - spin_lock(&conn->session->lock); - task = iscsi_itt_to_ctask(conn, hdr->itt); - if (!task) - rc = ISCSI_ERR_BAD_ITT; - else - rc = iscsi_tcp_data_in(conn, task); - if (rc) { - spin_unlock(&conn->session->lock); - break; - } - - if (tcp_conn->in.datalen) { - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct hash_desc *rx_hash = NULL; - struct scsi_data_buffer *sdb = scsi_in(task->sc); - - /* - * Setup copy of Data-In into the Scsi_Cmnd - * Scatterlist case: - * We set up the iscsi_segment to point to the next - * scatterlist entry to copy to. As we go along, - * we move on to the next scatterlist entry and - * update the digest per-entry. - */ - if (conn->datadgst_en && - !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) - rx_hash = tcp_conn->rx_hash; - - ISCSI_DBG_TCP(conn, "iscsi_tcp_begin_data_in( " - "offset=%d, datalen=%d)\n", - tcp_task->data_offset, - tcp_conn->in.datalen); - task->last_xfer = jiffies; - rc = iscsi_segment_seek_sg(&tcp_conn->in.segment, - sdb->table.sgl, - sdb->table.nents, - tcp_task->data_offset, - tcp_conn->in.datalen, - iscsi_tcp_process_data_in, - rx_hash); - spin_unlock(&conn->session->lock); - return rc; - } - rc = __iscsi_complete_pdu(conn, hdr, NULL, 0); - spin_unlock(&conn->session->lock); - break; - case ISCSI_OP_SCSI_CMD_RSP: - if (tcp_conn->in.datalen) { - iscsi_tcp_data_recv_prep(tcp_conn); - return 0; - } - rc = iscsi_complete_pdu(conn, hdr, NULL, 0); - break; - case ISCSI_OP_R2T: - spin_lock(&conn->session->lock); - task = iscsi_itt_to_ctask(conn, hdr->itt); - if (!task) - rc = ISCSI_ERR_BAD_ITT; - else if (ahslen) - rc = ISCSI_ERR_AHSLEN; - else if (task->sc->sc_data_direction == DMA_TO_DEVICE) { - task->last_xfer = jiffies; - rc = iscsi_tcp_r2t_rsp(conn, task); - } else - rc = ISCSI_ERR_PROTO; - spin_unlock(&conn->session->lock); - break; - case ISCSI_OP_LOGIN_RSP: - case ISCSI_OP_TEXT_RSP: - case ISCSI_OP_REJECT: - case ISCSI_OP_ASYNC_EVENT: - /* - * It is possible that we could get a PDU with a buffer larger - * than 8K, but there are no targets that currently do this. - * For now we fail until we find a vendor that needs it - */ - if (ISCSI_DEF_MAX_RECV_SEG_LEN < tcp_conn->in.datalen) { - iscsi_conn_printk(KERN_ERR, conn, - "iscsi_tcp: received buffer of " - "len %u but conn buffer is only %u " - "(opcode %0x)\n", - tcp_conn->in.datalen, - ISCSI_DEF_MAX_RECV_SEG_LEN, opcode); - rc = ISCSI_ERR_PROTO; - break; - } - - /* If there's data coming in with the response, - * receive it to the connection's buffer. - */ - if (tcp_conn->in.datalen) { - iscsi_tcp_data_recv_prep(tcp_conn); - return 0; - } - /* fall through */ - case ISCSI_OP_LOGOUT_RSP: - case ISCSI_OP_NOOP_IN: - case ISCSI_OP_SCSI_TMFUNC_RSP: - rc = iscsi_complete_pdu(conn, hdr, NULL, 0); - break; - default: - rc = ISCSI_ERR_BAD_OPCODE; - break; - } - - if (rc == 0) { - /* Anything that comes with data should have - * been handled above. */ - if (tcp_conn->in.datalen) - return ISCSI_ERR_PROTO; - iscsi_tcp_hdr_recv_prep(tcp_conn); - } - - return rc; -} - -/** - * iscsi_tcp_hdr_recv_done - process PDU header - * - * This is the callback invoked when the PDU header has - * been received. If the header is followed by additional - * header segments, we go back for more data. - */ -static int -iscsi_tcp_hdr_recv_done(struct iscsi_tcp_conn *tcp_conn, - struct iscsi_segment *segment) -{ - struct iscsi_conn *conn = tcp_conn->iscsi_conn; - struct iscsi_hdr *hdr; - - /* Check if there are additional header segments - * *prior* to computing the digest, because we - * may need to go back to the caller for more. - */ - hdr = (struct iscsi_hdr *) tcp_conn->in.hdr_buf; - if (segment->copied == sizeof(struct iscsi_hdr) && hdr->hlength) { - /* Bump the header length - the caller will - * just loop around and get the AHS for us, and - * call again. */ - unsigned int ahslen = hdr->hlength << 2; - - /* Make sure we don't overflow */ - if (sizeof(*hdr) + ahslen > sizeof(tcp_conn->in.hdr_buf)) - return ISCSI_ERR_AHSLEN; - - segment->total_size += ahslen; - segment->size += ahslen; - return 0; - } - - /* We're done processing the header. See if we're doing - * header digests; if so, set up the recv_digest buffer - * and go back for more. */ - if (conn->hdrdgst_en && - !(conn->session->tt->caps & CAP_DIGEST_OFFLOAD)) { - if (segment->digest_len == 0) { - /* - * Even if we offload the digest processing we - * splice it in so we can increment the skb/segment - * counters in preparation for the data segment. - */ - iscsi_tcp_segment_splice_digest(segment, - segment->recv_digest); - return 0; - } - - iscsi_tcp_dgst_header(tcp_conn->rx_hash, hdr, - segment->total_copied - ISCSI_DIGEST_SIZE, - segment->digest); - - if (!iscsi_tcp_dgst_verify(tcp_conn, segment)) - return ISCSI_ERR_HDR_DGST; - } - - tcp_conn->in.hdr = hdr; - return iscsi_tcp_hdr_dissect(conn, hdr); -} - -/** - * iscsi_tcp_recv_segment_is_hdr - tests if we are reading in a header - * @tcp_conn: iscsi tcp conn - * - * returns non zero if we are currently processing or setup to process - * a header. - */ -inline int iscsi_tcp_recv_segment_is_hdr(struct iscsi_tcp_conn *tcp_conn) -{ - return tcp_conn->in.segment.done == iscsi_tcp_hdr_recv_done; -} -EXPORT_SYMBOL_GPL(iscsi_tcp_recv_segment_is_hdr); - -/** - * iscsi_tcp_recv_skb - Process skb - * @conn: iscsi connection - * @skb: network buffer with header and/or data segment - * @offset: offset in skb - * @offload: bool indicating if transfer was offloaded - * - * Will return status of transfer in status. And will return - * number of bytes copied. - */ -int iscsi_tcp_recv_skb(struct iscsi_conn *conn, struct sk_buff *skb, - unsigned int offset, bool offloaded, int *status) -{ - struct iscsi_tcp_conn *tcp_conn = conn->dd_data; - struct iscsi_segment *segment = &tcp_conn->in.segment; - struct skb_seq_state seq; - unsigned int consumed = 0; - int rc = 0; - - ISCSI_DBG_TCP(conn, "in %d bytes\n", skb->len - offset); - /* - * Update for each skb instead of pdu, because over slow networks a - * data_in's data could take a while to read in. We also want to - * account for r2ts. - */ - conn->last_recv = jiffies; - - if (unlikely(conn->suspend_rx)) { - ISCSI_DBG_TCP(conn, "Rx suspended!\n"); - *status = ISCSI_TCP_SUSPENDED; - return 0; - } - - if (offloaded) { - segment->total_copied = segment->total_size; - goto segment_done; - } - - skb_prepare_seq_read(skb, offset, skb->len, &seq); - while (1) { - unsigned int avail; - const u8 *ptr; - - avail = skb_seq_read(consumed, &ptr, &seq); - if (avail == 0) { - ISCSI_DBG_TCP(conn, "no more data avail. Consumed %d\n", - consumed); - *status = ISCSI_TCP_SKB_DONE; - skb_abort_seq_read(&seq); - goto skb_done; - } - BUG_ON(segment->copied >= segment->size); - - ISCSI_DBG_TCP(conn, "skb %p ptr=%p avail=%u\n", skb, ptr, - avail); - rc = iscsi_tcp_segment_recv(tcp_conn, segment, ptr, avail); - BUG_ON(rc == 0); - consumed += rc; - - if (segment->total_copied >= segment->total_size) { - skb_abort_seq_read(&seq); - goto segment_done; - } - } - -segment_done: - *status = ISCSI_TCP_SEGMENT_DONE; - ISCSI_DBG_TCP(conn, "segment done\n"); - rc = segment->done(tcp_conn, segment); - if (rc != 0) { - *status = ISCSI_TCP_CONN_ERR; - ISCSI_DBG_TCP(conn, "Error receiving PDU, errno=%d\n", rc); - iscsi_conn_failure(conn, rc); - return 0; - } - /* The done() functions sets up the next segment. */ - -skb_done: - conn->rxdata_octets += consumed; - return consumed; -} -EXPORT_SYMBOL_GPL(iscsi_tcp_recv_skb); - -/** - * iscsi_tcp_task_init - Initialize iSCSI SCSI_READ or SCSI_WRITE commands - * @conn: iscsi connection - * @task: scsi command task - * @sc: scsi command - */ -int iscsi_tcp_task_init(struct iscsi_task *task) -{ - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct iscsi_conn *conn = task->conn; - struct scsi_cmnd *sc = task->sc; - int err; - - if (!sc) { - /* - * mgmt tasks do not have a scatterlist since they come - * in from the iscsi interface. - */ - ISCSI_DBG_TCP(conn, "mtask deq [itt 0x%x]\n", task->itt); - - return conn->session->tt->init_pdu(task, 0, task->data_count); - } - - BUG_ON(kfifo_len(&tcp_task->r2tqueue)); - tcp_task->exp_datasn = 0; - - /* Prepare PDU, optionally w/ immediate data */ - ISCSI_DBG_TCP(conn, "task deq [itt 0x%x imm %d unsol %d]\n", - task->itt, task->imm_count, task->unsol_r2t.data_length); - - err = conn->session->tt->init_pdu(task, 0, task->imm_count); - if (err) - return err; - task->imm_count = 0; - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_tcp_task_init); - -static struct iscsi_r2t_info *iscsi_tcp_get_curr_r2t(struct iscsi_task *task) -{ - struct iscsi_session *session = task->conn->session; - struct iscsi_tcp_task *tcp_task = task->dd_data; - struct iscsi_r2t_info *r2t = NULL; - - if (iscsi_task_has_unsol_data(task)) - r2t = &task->unsol_r2t; - else { - spin_lock_bh(&session->lock); - if (tcp_task->r2t) { - r2t = tcp_task->r2t; - /* Continue with this R2T? */ - if (r2t->data_length <= r2t->sent) { - ISCSI_DBG_TCP(task->conn, - " done with r2t %p\n", r2t); - kfifo_in(&tcp_task->r2tpool.queue, - (void *)&tcp_task->r2t, - sizeof(void *)); - tcp_task->r2t = r2t = NULL; - } - } - - if (r2t == NULL) { - if (kfifo_out(&tcp_task->r2tqueue, - (void *)&tcp_task->r2t, sizeof(void *)) != - sizeof(void *)) - r2t = NULL; - else - r2t = tcp_task->r2t; - } - spin_unlock_bh(&session->lock); - } - - return r2t; -} - -/** - * iscsi_tcp_task_xmit - xmit normal PDU task - * @task: iscsi command task - * - * We're expected to return 0 when everything was transmitted successfully, - * -EAGAIN if there's still data in the queue, or != 0 for any other kind - * of error. - */ -int iscsi_tcp_task_xmit(struct iscsi_task *task) -{ - struct iscsi_conn *conn = task->conn; - struct iscsi_session *session = conn->session; - struct iscsi_r2t_info *r2t; - int rc = 0; - -flush: - /* Flush any pending data first. */ - rc = session->tt->xmit_pdu(task); - if (rc < 0) - return rc; - - /* mgmt command */ - if (!task->sc) { - if (task->hdr->itt == RESERVED_ITT) - iscsi_put_task(task); - return 0; - } - - /* Are we done already? */ - if (task->sc->sc_data_direction != DMA_TO_DEVICE) - return 0; - - r2t = iscsi_tcp_get_curr_r2t(task); - if (r2t == NULL) { - /* Waiting for more R2Ts to arrive. */ - ISCSI_DBG_TCP(conn, "no R2Ts yet\n"); - return 0; - } - - rc = conn->session->tt->alloc_pdu(task, ISCSI_OP_SCSI_DATA_OUT); - if (rc) - return rc; - iscsi_prep_data_out_pdu(task, r2t, (struct iscsi_data *) task->hdr); - - ISCSI_DBG_TCP(conn, "sol dout %p [dsn %d itt 0x%x doff %d dlen %d]\n", - r2t, r2t->datasn - 1, task->hdr->itt, - r2t->data_offset + r2t->sent, r2t->data_count); - - rc = conn->session->tt->init_pdu(task, r2t->data_offset + r2t->sent, - r2t->data_count); - if (rc) { - iscsi_conn_failure(conn, ISCSI_ERR_XMIT_FAILED); - return rc; - } - - r2t->sent += r2t->data_count; - goto flush; -} -EXPORT_SYMBOL_GPL(iscsi_tcp_task_xmit); - -struct iscsi_cls_conn * -iscsi_tcp_conn_setup(struct iscsi_cls_session *cls_session, int dd_data_size, - uint32_t conn_idx) - -{ - struct iscsi_conn *conn; - struct iscsi_cls_conn *cls_conn; - struct iscsi_tcp_conn *tcp_conn; - - cls_conn = iscsi_conn_setup(cls_session, - sizeof(*tcp_conn) + dd_data_size, conn_idx); - if (!cls_conn) - return NULL; - conn = cls_conn->dd_data; - /* - * due to strange issues with iser these are not set - * in iscsi_conn_setup - */ - conn->max_recv_dlength = ISCSI_DEF_MAX_RECV_SEG_LEN; - - tcp_conn = conn->dd_data; - tcp_conn->iscsi_conn = conn; - tcp_conn->dd_data = conn->dd_data + sizeof(*tcp_conn); - return cls_conn; -} -EXPORT_SYMBOL_GPL(iscsi_tcp_conn_setup); - -void iscsi_tcp_conn_teardown(struct iscsi_cls_conn *cls_conn) -{ - iscsi_conn_teardown(cls_conn); -} -EXPORT_SYMBOL_GPL(iscsi_tcp_conn_teardown); - -int iscsi_tcp_r2tpool_alloc(struct iscsi_session *session) -{ - int i; - int cmd_i; - - /* - * initialize per-task: R2T pool and xmit queue - */ - for (cmd_i = 0; cmd_i < session->cmds_max; cmd_i++) { - struct iscsi_task *task = session->cmds[cmd_i]; - struct iscsi_tcp_task *tcp_task = task->dd_data; - - /* - * pre-allocated x2 as much r2ts to handle race when - * target acks DataOut faster than we data_xmit() queues - * could replenish r2tqueue. - */ - - /* R2T pool */ - if (iscsi_pool_init(&tcp_task->r2tpool, - session->max_r2t * 2, NULL, - sizeof(struct iscsi_r2t_info))) { - goto r2t_alloc_fail; - } - - /* R2T xmit queue */ - if (kfifo_alloc(&tcp_task->r2tqueue, - session->max_r2t * 4 * sizeof(void*), GFP_KERNEL)) { - iscsi_pool_free(&tcp_task->r2tpool); - goto r2t_alloc_fail; - } - } - - return 0; - -r2t_alloc_fail: - for (i = 0; i < cmd_i; i++) { - struct iscsi_task *task = session->cmds[i]; - struct iscsi_tcp_task *tcp_task = task->dd_data; - - kfifo_free(&tcp_task->r2tqueue); - iscsi_pool_free(&tcp_task->r2tpool); - } - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_alloc); - -void iscsi_tcp_r2tpool_free(struct iscsi_session *session) -{ - int i; - - for (i = 0; i < session->cmds_max; i++) { - struct iscsi_task *task = session->cmds[i]; - struct iscsi_tcp_task *tcp_task = task->dd_data; - - kfifo_free(&tcp_task->r2tqueue); - iscsi_pool_free(&tcp_task->r2tpool); - } -} -EXPORT_SYMBOL_GPL(iscsi_tcp_r2tpool_free); - -int iscsi_tcp_set_max_r2t(struct iscsi_conn *conn, char *buf) -{ - struct iscsi_session *session = conn->session; - unsigned short r2ts = 0; - - sscanf(buf, "%hu", &r2ts); - if (session->max_r2t == r2ts) - return 0; - - if (!r2ts || !is_power_of_2(r2ts)) - return -EINVAL; - - session->max_r2t = r2ts; - iscsi_tcp_r2tpool_free(session); - return iscsi_tcp_r2tpool_alloc(session); -} -EXPORT_SYMBOL_GPL(iscsi_tcp_set_max_r2t); - -void iscsi_tcp_conn_get_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats) -{ - struct iscsi_conn *conn = cls_conn->dd_data; - - stats->txdata_octets = conn->txdata_octets; - stats->rxdata_octets = conn->rxdata_octets; - stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; - stats->dataout_pdus = conn->dataout_pdus_cnt; - stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; - stats->datain_pdus = conn->datain_pdus_cnt; - stats->r2t_pdus = conn->r2t_pdus_cnt; - stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; - stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; -} -EXPORT_SYMBOL_GPL(iscsi_tcp_conn_get_stats); diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/Kconfig b/ANDROID_3.4.5/drivers/scsi/libsas/Kconfig deleted file mode 100644 index 9dafe64e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -# -# Kernel configuration file for the SAS Class -# -# Copyright (C) 2005 Adaptec, Inc. All rights reserved. -# Copyright (C) 2005 Luben Tuikov -# -# This file is licensed under GPLv2. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 of the -# License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -config SCSI_SAS_LIBSAS - tristate "SAS Domain Transport Attributes" - depends on SCSI - select SCSI_SAS_ATTRS - help - This provides transport specific helpers for SAS drivers which - use the domain device construct (like the aic94xxx). - -config SCSI_SAS_ATA - bool "ATA support for libsas (requires libata)" - depends on SCSI_SAS_LIBSAS - depends on ATA = y || ATA = SCSI_SAS_LIBSAS - help - Builds in ATA support into libsas. Will necessitate - the loading of libata along with libsas. - -config SCSI_SAS_HOST_SMP - bool "Support for SMP interpretation for SAS hosts" - default y - depends on SCSI_SAS_LIBSAS - help - Allows sas hosts to receive SMP frames. Selecting this - option builds an SMP interpreter into libsas. Say - N here if you want to save the few kb this consumes. diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/Makefile b/ANDROID_3.4.5/drivers/scsi/libsas/Makefile deleted file mode 100644 index 2e70140f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/Makefile +++ /dev/null @@ -1,35 +0,0 @@ -# -# Kernel Makefile for the libsas helpers -# -# Copyright (C) 2005 Adaptec, Inc. All rights reserved. -# Copyright (C) 2005 Luben Tuikov -# -# This file is licensed under GPLv2. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 of the -# License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA - -obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas.o -libsas-y += sas_init.o \ - sas_phy.o \ - sas_port.o \ - sas_event.o \ - sas_dump.o \ - sas_discover.o \ - sas_expander.o \ - sas_scsi_host.o \ - sas_task.o -libsas-$(CONFIG_SCSI_SAS_ATA) += sas_ata.o -libsas-$(CONFIG_SCSI_SAS_HOST_SMP) += sas_host_smp.o diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_ata.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_ata.c deleted file mode 100644 index d109cc3a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_ata.c +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Support for SATA devices on Serial Attached SCSI (SAS) controllers - * - * Copyright (C) 2006 IBM Corporation - * - * Written by: Darrick J. Wong , IBM Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#include -#include -#include -#include - -#include -#include "sas_internal.h" -#include -#include -#include -#include -#include -#include -#include "../scsi_sas_internal.h" -#include "../scsi_transport_api.h" -#include - -static enum ata_completion_errors sas_to_ata_err(struct task_status_struct *ts) -{ - /* Cheesy attempt to translate SAS errors into ATA. Hah! */ - - /* transport error */ - if (ts->resp == SAS_TASK_UNDELIVERED) - return AC_ERR_ATA_BUS; - - /* ts->resp == SAS_TASK_COMPLETE */ - /* task delivered, what happened afterwards? */ - switch (ts->stat) { - case SAS_DEV_NO_RESPONSE: - return AC_ERR_TIMEOUT; - - case SAS_INTERRUPTED: - case SAS_PHY_DOWN: - case SAS_NAK_R_ERR: - return AC_ERR_ATA_BUS; - - - case SAS_DATA_UNDERRUN: - /* - * Some programs that use the taskfile interface - * (smartctl in particular) can cause underrun - * problems. Ignore these errors, perhaps at our - * peril. - */ - return 0; - - case SAS_DATA_OVERRUN: - case SAS_QUEUE_FULL: - case SAS_DEVICE_UNKNOWN: - case SAS_SG_ERR: - return AC_ERR_INVALID; - - case SAS_OPEN_TO: - case SAS_OPEN_REJECT: - SAS_DPRINTK("%s: Saw error %d. What to do?\n", - __func__, ts->stat); - return AC_ERR_OTHER; - - case SAM_STAT_CHECK_CONDITION: - case SAS_ABORTED_TASK: - return AC_ERR_DEV; - - case SAS_PROTO_RESPONSE: - /* This means the ending_fis has the error - * value; return 0 here to collect it */ - return 0; - default: - return 0; - } -} - -static void sas_ata_task_done(struct sas_task *task) -{ - struct ata_queued_cmd *qc = task->uldd_task; - struct domain_device *dev = task->dev; - struct task_status_struct *stat = &task->task_status; - struct ata_task_resp *resp = (struct ata_task_resp *)stat->buf; - struct sas_ha_struct *sas_ha = dev->port->ha; - enum ata_completion_errors ac; - unsigned long flags; - struct ata_link *link; - struct ata_port *ap; - - spin_lock_irqsave(&dev->done_lock, flags); - if (test_bit(SAS_HA_FROZEN, &sas_ha->state)) - task = NULL; - else if (qc && qc->scsicmd) - ASSIGN_SAS_TASK(qc->scsicmd, NULL); - spin_unlock_irqrestore(&dev->done_lock, flags); - - /* check if libsas-eh got to the task before us */ - if (unlikely(!task)) - return; - - if (!qc) - goto qc_already_gone; - - ap = qc->ap; - link = &ap->link; - - spin_lock_irqsave(ap->lock, flags); - /* check if we lost the race with libata/sas_ata_post_internal() */ - if (unlikely(ap->pflags & ATA_PFLAG_FROZEN)) { - spin_unlock_irqrestore(ap->lock, flags); - if (qc->scsicmd) - goto qc_already_gone; - else { - /* if eh is not involved and the port is frozen then the - * ata internal abort process has taken responsibility - * for this sas_task - */ - return; - } - } - - if (stat->stat == SAS_PROTO_RESPONSE || stat->stat == SAM_STAT_GOOD || - ((stat->stat == SAM_STAT_CHECK_CONDITION && - dev->sata_dev.command_set == ATAPI_COMMAND_SET))) { - memcpy(dev->sata_dev.fis, resp->ending_fis, ATA_RESP_FIS_SIZE); - - if (!link->sactive) { - qc->err_mask |= ac_err_mask(dev->sata_dev.fis[2]); - } else { - link->eh_info.err_mask |= ac_err_mask(dev->sata_dev.fis[2]); - if (unlikely(link->eh_info.err_mask)) - qc->flags |= ATA_QCFLAG_FAILED; - } - } else { - ac = sas_to_ata_err(stat); - if (ac) { - SAS_DPRINTK("%s: SAS error %x\n", __func__, - stat->stat); - /* We saw a SAS error. Send a vague error. */ - if (!link->sactive) { - qc->err_mask = ac; - } else { - link->eh_info.err_mask |= AC_ERR_DEV; - qc->flags |= ATA_QCFLAG_FAILED; - } - - dev->sata_dev.fis[3] = 0x04; /* status err */ - dev->sata_dev.fis[2] = ATA_ERR; - } - } - - qc->lldd_task = NULL; - ata_qc_complete(qc); - spin_unlock_irqrestore(ap->lock, flags); - -qc_already_gone: - list_del_init(&task->list); - sas_free_task(task); -} - -static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc) -{ - unsigned long flags; - struct sas_task *task; - struct scatterlist *sg; - int ret = AC_ERR_SYSTEM; - unsigned int si, xfer = 0; - struct ata_port *ap = qc->ap; - struct domain_device *dev = ap->private_data; - struct sas_ha_struct *sas_ha = dev->port->ha; - struct Scsi_Host *host = sas_ha->core.shost; - struct sas_internal *i = to_sas_internal(host->transportt); - - /* TODO: audit callers to ensure they are ready for qc_issue to - * unconditionally re-enable interrupts - */ - local_irq_save(flags); - spin_unlock(ap->lock); - - /* If the device fell off, no sense in issuing commands */ - if (test_bit(SAS_DEV_GONE, &dev->state)) - goto out; - - task = sas_alloc_task(GFP_ATOMIC); - if (!task) - goto out; - task->dev = dev; - task->task_proto = SAS_PROTOCOL_STP; - task->task_done = sas_ata_task_done; - - if (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ) { - /* Need to zero out the tag libata assigned us */ - qc->tf.nsect = 0; - } - - ata_tf_to_fis(&qc->tf, 1, 0, (u8*)&task->ata_task.fis); - task->uldd_task = qc; - if (ata_is_atapi(qc->tf.protocol)) { - memcpy(task->ata_task.atapi_packet, qc->cdb, qc->dev->cdb_len); - task->total_xfer_len = qc->nbytes; - task->num_scatter = qc->n_elem; - } else { - for_each_sg(qc->sg, sg, qc->n_elem, si) - xfer += sg->length; - - task->total_xfer_len = xfer; - task->num_scatter = si; - } - - task->data_dir = qc->dma_dir; - task->scatter = qc->sg; - task->ata_task.retry_count = 1; - task->task_state_flags = SAS_TASK_STATE_PENDING; - qc->lldd_task = task; - - switch (qc->tf.protocol) { - case ATA_PROT_NCQ: - task->ata_task.use_ncq = 1; - /* fall through */ - case ATAPI_PROT_DMA: - case ATA_PROT_DMA: - task->ata_task.dma_xfer = 1; - break; - } - - if (qc->scsicmd) - ASSIGN_SAS_TASK(qc->scsicmd, task); - - if (sas_ha->lldd_max_execute_num < 2) - ret = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); - else - ret = sas_queue_up(task); - - /* Examine */ - if (ret) { - SAS_DPRINTK("lldd_execute_task returned: %d\n", ret); - - if (qc->scsicmd) - ASSIGN_SAS_TASK(qc->scsicmd, NULL); - sas_free_task(task); - ret = AC_ERR_SYSTEM; - } - - out: - spin_lock(ap->lock); - local_irq_restore(flags); - return ret; -} - -static bool sas_ata_qc_fill_rtf(struct ata_queued_cmd *qc) -{ - struct domain_device *dev = qc->ap->private_data; - - ata_tf_from_fis(dev->sata_dev.fis, &qc->result_tf); - return true; -} - -static struct sas_internal *dev_to_sas_internal(struct domain_device *dev) -{ - return to_sas_internal(dev->port->ha->core.shost->transportt); -} - -static void sas_get_ata_command_set(struct domain_device *dev); - -int sas_get_ata_info(struct domain_device *dev, struct ex_phy *phy) -{ - if (phy->attached_tproto & SAS_PROTOCOL_STP) - dev->tproto = phy->attached_tproto; - if (phy->attached_sata_dev) - dev->tproto |= SATA_DEV; - - if (phy->attached_dev_type == SATA_PENDING) - dev->dev_type = SATA_PENDING; - else { - int res; - - dev->dev_type = SATA_DEV; - res = sas_get_report_phy_sata(dev->parent, phy->phy_id, - &dev->sata_dev.rps_resp); - if (res) { - SAS_DPRINTK("report phy sata to %016llx:0x%x returned " - "0x%x\n", SAS_ADDR(dev->parent->sas_addr), - phy->phy_id, res); - return res; - } - memcpy(dev->frame_rcvd, &dev->sata_dev.rps_resp.rps.fis, - sizeof(struct dev_to_host_fis)); - /* TODO switch to ata_dev_classify() */ - sas_get_ata_command_set(dev); - } - return 0; -} - -static int sas_ata_clear_pending(struct domain_device *dev, struct ex_phy *phy) -{ - int res; - - /* we weren't pending, so successfully end the reset sequence now */ - if (dev->dev_type != SATA_PENDING) - return 1; - - /* hmmm, if this succeeds do we need to repost the domain_device to the - * lldd so it can pick up new parameters? - */ - res = sas_get_ata_info(dev, phy); - if (res) - return 0; /* retry */ - else - return 1; -} - -static int smp_ata_check_ready(struct ata_link *link) -{ - int res; - struct ata_port *ap = link->ap; - struct domain_device *dev = ap->private_data; - struct domain_device *ex_dev = dev->parent; - struct sas_phy *phy = sas_get_local_phy(dev); - struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy->number]; - - res = sas_ex_phy_discover(ex_dev, phy->number); - sas_put_local_phy(phy); - - /* break the wait early if the expander is unreachable, - * otherwise keep polling - */ - if (res == -ECOMM) - return res; - if (res != SMP_RESP_FUNC_ACC) - return 0; - - switch (ex_phy->attached_dev_type) { - case SATA_PENDING: - return 0; - case SAS_END_DEV: - if (ex_phy->attached_sata_dev) - return sas_ata_clear_pending(dev, ex_phy); - default: - return -ENODEV; - } -} - -static int local_ata_check_ready(struct ata_link *link) -{ - struct ata_port *ap = link->ap; - struct domain_device *dev = ap->private_data; - struct sas_internal *i = dev_to_sas_internal(dev); - - if (i->dft->lldd_ata_check_ready) - return i->dft->lldd_ata_check_ready(dev); - else { - /* lldd's that don't implement 'ready' checking get the - * old default behavior of not coordinating reset - * recovery with libata - */ - return 1; - } -} - -static int sas_ata_printk(const char *level, const struct domain_device *ddev, - const char *fmt, ...) -{ - struct ata_port *ap = ddev->sata_dev.ap; - struct device *dev = &ddev->rphy->dev; - struct va_format vaf; - va_list args; - int r; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - r = printk("%ssas: ata%u: %s: %pV", - level, ap->print_id, dev_name(dev), &vaf); - - va_end(args); - - return r; -} - -static int sas_ata_hard_reset(struct ata_link *link, unsigned int *class, - unsigned long deadline) -{ - int ret = 0, res; - struct sas_phy *phy; - struct ata_port *ap = link->ap; - int (*check_ready)(struct ata_link *link); - struct domain_device *dev = ap->private_data; - struct sas_internal *i = dev_to_sas_internal(dev); - - res = i->dft->lldd_I_T_nexus_reset(dev); - if (res == -ENODEV) - return res; - - if (res != TMF_RESP_FUNC_COMPLETE) - sas_ata_printk(KERN_DEBUG, dev, "Unable to reset ata device?\n"); - - phy = sas_get_local_phy(dev); - if (scsi_is_sas_phy_local(phy)) - check_ready = local_ata_check_ready; - else - check_ready = smp_ata_check_ready; - sas_put_local_phy(phy); - - ret = ata_wait_after_reset(link, deadline, check_ready); - if (ret && ret != -EAGAIN) - sas_ata_printk(KERN_ERR, dev, "reset failed (errno=%d)\n", ret); - - /* XXX: if the class changes during the reset the upper layer - * should be informed, if the device has gone away we assume - * libsas will eventually delete it - */ - switch (dev->sata_dev.command_set) { - case ATA_COMMAND_SET: - *class = ATA_DEV_ATA; - break; - case ATAPI_COMMAND_SET: - *class = ATA_DEV_ATAPI; - break; - } - - ap->cbl = ATA_CBL_SATA; - return ret; -} - -/* - * notify the lldd to forget the sas_task for this internal ata command - * that bypasses scsi-eh - */ -static void sas_ata_internal_abort(struct sas_task *task) -{ - struct sas_internal *si = dev_to_sas_internal(task->dev); - unsigned long flags; - int res; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_ABORTED || - task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("%s: Task %p already finished.\n", __func__, - task); - goto out; - } - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - res = si->dft->lldd_abort_task(task); - - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_DONE || - res == TMF_RESP_FUNC_COMPLETE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - goto out; - } - - /* XXX we are not prepared to deal with ->lldd_abort_task() - * failures. TODO: lldds need to unconditionally forget about - * aborted ata tasks, otherwise we (likely) leak the sas task - * here - */ - SAS_DPRINTK("%s: Task %p leaked.\n", __func__, task); - - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) - task->task_state_flags &= ~SAS_TASK_STATE_ABORTED; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - return; - out: - list_del_init(&task->list); - sas_free_task(task); -} - -static void sas_ata_post_internal(struct ata_queued_cmd *qc) -{ - if (qc->flags & ATA_QCFLAG_FAILED) - qc->err_mask |= AC_ERR_OTHER; - - if (qc->err_mask) { - /* - * Find the sas_task and kill it. By this point, libata - * has decided to kill the qc and has frozen the port. - * In this state sas_ata_task_done() will no longer free - * the sas_task, so we need to notify the lldd (via - * ->lldd_abort_task) that the task is dead and free it - * ourselves. - */ - struct sas_task *task = qc->lldd_task; - - qc->lldd_task = NULL; - if (!task) - return; - task->uldd_task = NULL; - sas_ata_internal_abort(task); - } -} - - -static void sas_ata_set_dmamode(struct ata_port *ap, struct ata_device *ata_dev) -{ - struct domain_device *dev = ap->private_data; - struct sas_internal *i = dev_to_sas_internal(dev); - - if (i->dft->lldd_ata_set_dmamode) - i->dft->lldd_ata_set_dmamode(dev); -} - -static struct ata_port_operations sas_sata_ops = { - .prereset = ata_std_prereset, - .hardreset = sas_ata_hard_reset, - .postreset = ata_std_postreset, - .error_handler = ata_std_error_handler, - .post_internal_cmd = sas_ata_post_internal, - .qc_defer = ata_std_qc_defer, - .qc_prep = ata_noop_qc_prep, - .qc_issue = sas_ata_qc_issue, - .qc_fill_rtf = sas_ata_qc_fill_rtf, - .port_start = ata_sas_port_start, - .port_stop = ata_sas_port_stop, - .set_dmamode = sas_ata_set_dmamode, -}; - -static struct ata_port_info sata_port_info = { - .flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA | ATA_FLAG_NCQ, - .pio_mask = ATA_PIO4, - .mwdma_mask = ATA_MWDMA2, - .udma_mask = ATA_UDMA6, - .port_ops = &sas_sata_ops -}; - -int sas_ata_init(struct domain_device *found_dev) -{ - struct sas_ha_struct *ha = found_dev->port->ha; - struct Scsi_Host *shost = ha->core.shost; - struct ata_port *ap; - int rc; - - ata_host_init(&found_dev->sata_dev.ata_host, - ha->dev, - sata_port_info.flags, - &sas_sata_ops); - ap = ata_sas_port_alloc(&found_dev->sata_dev.ata_host, - &sata_port_info, - shost); - if (!ap) { - SAS_DPRINTK("ata_sas_port_alloc failed.\n"); - return -ENODEV; - } - - ap->private_data = found_dev; - ap->cbl = ATA_CBL_SATA; - ap->scsi_host = shost; - rc = ata_sas_port_init(ap); - if (rc) { - ata_sas_port_destroy(ap); - return rc; - } - found_dev->sata_dev.ap = ap; - - return 0; -} - -void sas_ata_task_abort(struct sas_task *task) -{ - struct ata_queued_cmd *qc = task->uldd_task; - struct completion *waiting; - - /* Bounce SCSI-initiated commands to the SCSI EH */ - if (qc->scsicmd) { - struct request_queue *q = qc->scsicmd->device->request_queue; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - blk_abort_request(qc->scsicmd->request); - spin_unlock_irqrestore(q->queue_lock, flags); - scsi_schedule_eh(qc->scsicmd->device->host); - return; - } - - /* Internal command, fake a timeout and complete. */ - qc->flags &= ~ATA_QCFLAG_ACTIVE; - qc->flags |= ATA_QCFLAG_FAILED; - qc->err_mask |= AC_ERR_TIMEOUT; - waiting = qc->private_data; - complete(waiting); -} - -static void sas_get_ata_command_set(struct domain_device *dev) -{ - struct dev_to_host_fis *fis = - (struct dev_to_host_fis *) dev->frame_rcvd; - - if (dev->dev_type == SATA_PENDING) - return; - - if ((fis->sector_count == 1 && /* ATA */ - fis->lbal == 1 && - fis->lbam == 0 && - fis->lbah == 0 && - fis->device == 0) - || - (fis->sector_count == 0 && /* CE-ATA (mATA) */ - fis->lbal == 0 && - fis->lbam == 0xCE && - fis->lbah == 0xAA && - (fis->device & ~0x10) == 0)) - - dev->sata_dev.command_set = ATA_COMMAND_SET; - - else if ((fis->interrupt_reason == 1 && /* ATAPI */ - fis->lbal == 1 && - fis->byte_count_low == 0x14 && - fis->byte_count_high == 0xEB && - (fis->device & ~0x10) == 0)) - - dev->sata_dev.command_set = ATAPI_COMMAND_SET; - - else if ((fis->sector_count == 1 && /* SEMB */ - fis->lbal == 1 && - fis->lbam == 0x3C && - fis->lbah == 0xC3 && - fis->device == 0) - || - (fis->interrupt_reason == 1 && /* SATA PM */ - fis->lbal == 1 && - fis->byte_count_low == 0x69 && - fis->byte_count_high == 0x96 && - (fis->device & ~0x10) == 0)) - - /* Treat it as a superset? */ - dev->sata_dev.command_set = ATAPI_COMMAND_SET; -} - -void sas_probe_sata(struct asd_sas_port *port) -{ - struct domain_device *dev, *n; - - mutex_lock(&port->ha->disco_mutex); - list_for_each_entry(dev, &port->disco_list, disco_list_node) { - if (!dev_is_sata(dev)) - continue; - - ata_sas_async_probe(dev->sata_dev.ap); - } - mutex_unlock(&port->ha->disco_mutex); - - list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { - if (!dev_is_sata(dev)) - continue; - - sas_ata_wait_eh(dev); - - /* if libata could not bring the link up, don't surface - * the device - */ - if (ata_dev_disabled(sas_to_ata_dev(dev))) - sas_fail_probe(dev, __func__, -ENODEV); - } -} - -/** - * sas_discover_sata -- discover an STP/SATA domain device - * @dev: pointer to struct domain_device of interest - * - * Devices directly attached to a HA port, have no parents. All other - * devices do, and should have their "parent" pointer set appropriately - * before calling this function. - */ -int sas_discover_sata(struct domain_device *dev) -{ - int res; - - if (dev->dev_type == SATA_PM) - return -ENODEV; - - sas_get_ata_command_set(dev); - sas_fill_in_rphy(dev, dev->rphy); - - res = sas_notify_lldd_dev_found(dev); - if (res) - return res; - - sas_discover_event(dev->port, DISCE_PROBE); - return 0; -} - -static void async_sas_ata_eh(void *data, async_cookie_t cookie) -{ - struct domain_device *dev = data; - struct ata_port *ap = dev->sata_dev.ap; - struct sas_ha_struct *ha = dev->port->ha; - - /* hold a reference over eh since we may be racing with final - * remove once all commands are completed - */ - kref_get(&dev->kref); - sas_ata_printk(KERN_DEBUG, dev, "dev error handler\n"); - ata_scsi_port_error_handler(ha->core.shost, ap); - sas_put_device(dev); -} - -void sas_ata_strategy_handler(struct Scsi_Host *shost) -{ - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - LIST_HEAD(async); - int i; - - /* it's ok to defer revalidation events during ata eh, these - * disks are in one of three states: - * 1/ present for initial domain discovery, and these - * resets will cause bcn flutters - * 2/ hot removed, we'll discover that after eh fails - * 3/ hot added after initial discovery, lost the race, and need - * to catch the next train. - */ - sas_disable_revalidation(sas_ha); - - spin_lock_irq(&sas_ha->phy_port_lock); - for (i = 0; i < sas_ha->num_phys; i++) { - struct asd_sas_port *port = sas_ha->sas_port[i]; - struct domain_device *dev; - - spin_lock(&port->dev_list_lock); - list_for_each_entry(dev, &port->dev_list, dev_list_node) { - if (!dev_is_sata(dev)) - continue; - async_schedule_domain(async_sas_ata_eh, dev, &async); - } - spin_unlock(&port->dev_list_lock); - } - spin_unlock_irq(&sas_ha->phy_port_lock); - - async_synchronize_full_domain(&async); - - sas_enable_revalidation(sas_ha); -} - -void sas_ata_eh(struct Scsi_Host *shost, struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *cmd, *n; - struct domain_device *eh_dev; - - do { - LIST_HEAD(sata_q); - eh_dev = NULL; - - list_for_each_entry_safe(cmd, n, work_q, eh_entry) { - struct domain_device *ddev = cmd_to_domain_dev(cmd); - - if (!dev_is_sata(ddev) || TO_SAS_TASK(cmd)) - continue; - if (eh_dev && eh_dev != ddev) - continue; - eh_dev = ddev; - list_move(&cmd->eh_entry, &sata_q); - } - - if (!list_empty(&sata_q)) { - struct ata_port *ap = eh_dev->sata_dev.ap; - - sas_ata_printk(KERN_DEBUG, eh_dev, "cmd error handler\n"); - ata_scsi_cmd_error_handler(shost, ap, &sata_q); - /* - * ata's error handler may leave the cmd on the list - * so make sure they don't remain on a stack list - * about to go out of scope. - * - * This looks strange, since the commands are - * now part of no list, but the next error - * action will be ata_port_error_handler() - * which takes no list and sweeps them up - * anyway from the ata tag array. - */ - while (!list_empty(&sata_q)) - list_del_init(sata_q.next); - } - } while (eh_dev); -} - -void sas_ata_schedule_reset(struct domain_device *dev) -{ - struct ata_eh_info *ehi; - struct ata_port *ap; - unsigned long flags; - - if (!dev_is_sata(dev)) - return; - - ap = dev->sata_dev.ap; - ehi = &ap->link.eh_info; - - spin_lock_irqsave(ap->lock, flags); - ehi->err_mask |= AC_ERR_TIMEOUT; - ehi->action |= ATA_EH_RESET; - ata_port_schedule_eh(ap); - spin_unlock_irqrestore(ap->lock, flags); -} -EXPORT_SYMBOL_GPL(sas_ata_schedule_reset); - -void sas_ata_wait_eh(struct domain_device *dev) -{ - struct ata_port *ap; - - if (!dev_is_sata(dev)) - return; - - ap = dev->sata_dev.ap; - ata_port_wait_eh(ap); -} diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_discover.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_discover.c deleted file mode 100644 index 629a0865..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_discover.c +++ /dev/null @@ -1,534 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Discover process - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include -#include -#include "sas_internal.h" - -#include -#include -#include -#include "../scsi_sas_internal.h" - -/* ---------- Basic task processing for discovery purposes ---------- */ - -void sas_init_dev(struct domain_device *dev) -{ - switch (dev->dev_type) { - case SAS_END_DEV: - break; - case EDGE_DEV: - case FANOUT_DEV: - INIT_LIST_HEAD(&dev->ex_dev.children); - mutex_init(&dev->ex_dev.cmd_mutex); - break; - case SATA_DEV: - case SATA_PM: - case SATA_PM_PORT: - case SATA_PENDING: - INIT_LIST_HEAD(&dev->sata_dev.children); - break; - default: - break; - } -} - -/* ---------- Domain device discovery ---------- */ - -/** - * sas_get_port_device -- Discover devices which caused port creation - * @port: pointer to struct sas_port of interest - * - * Devices directly attached to a HA port, have no parent. This is - * how we know they are (domain) "root" devices. All other devices - * do, and should have their "parent" pointer set appropriately as - * soon as a child device is discovered. - */ -static int sas_get_port_device(struct asd_sas_port *port) -{ - struct asd_sas_phy *phy; - struct sas_rphy *rphy; - struct domain_device *dev; - int rc = -ENODEV; - - dev = sas_alloc_device(); - if (!dev) - return -ENOMEM; - - spin_lock_irq(&port->phy_list_lock); - if (list_empty(&port->phy_list)) { - spin_unlock_irq(&port->phy_list_lock); - sas_put_device(dev); - return -ENODEV; - } - phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el); - spin_lock(&phy->frame_rcvd_lock); - memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd), - (size_t)phy->frame_rcvd_size)); - spin_unlock(&phy->frame_rcvd_lock); - spin_unlock_irq(&port->phy_list_lock); - - if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) { - struct dev_to_host_fis *fis = - (struct dev_to_host_fis *) dev->frame_rcvd; - if (fis->interrupt_reason == 1 && fis->lbal == 1 && - fis->byte_count_low==0x69 && fis->byte_count_high == 0x96 - && (fis->device & ~0x10) == 0) - dev->dev_type = SATA_PM; - else - dev->dev_type = SATA_DEV; - dev->tproto = SAS_PROTOCOL_SATA; - } else { - struct sas_identify_frame *id = - (struct sas_identify_frame *) dev->frame_rcvd; - dev->dev_type = id->dev_type; - dev->iproto = id->initiator_bits; - dev->tproto = id->target_bits; - } - - sas_init_dev(dev); - - dev->port = port; - switch (dev->dev_type) { - case SATA_DEV: - rc = sas_ata_init(dev); - if (rc) { - rphy = NULL; - break; - } - /* fall through */ - case SAS_END_DEV: - rphy = sas_end_device_alloc(port->port); - break; - case EDGE_DEV: - rphy = sas_expander_alloc(port->port, - SAS_EDGE_EXPANDER_DEVICE); - break; - case FANOUT_DEV: - rphy = sas_expander_alloc(port->port, - SAS_FANOUT_EXPANDER_DEVICE); - break; - default: - printk("ERROR: Unidentified device type %d\n", dev->dev_type); - rphy = NULL; - break; - } - - if (!rphy) { - sas_put_device(dev); - return rc; - } - - rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; - memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE); - sas_fill_in_rphy(dev, rphy); - sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); - port->port_dev = dev; - dev->linkrate = port->linkrate; - dev->min_linkrate = port->linkrate; - dev->max_linkrate = port->linkrate; - dev->pathways = port->num_phys; - memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE); - memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE); - memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE); - port->disc.max_level = 0; - sas_device_set_phy(dev, port->port); - - dev->rphy = rphy; - get_device(&dev->rphy->dev); - - if (dev_is_sata(dev) || dev->dev_type == SAS_END_DEV) - list_add_tail(&dev->disco_list_node, &port->disco_list); - else { - spin_lock_irq(&port->dev_list_lock); - list_add_tail(&dev->dev_list_node, &port->dev_list); - spin_unlock_irq(&port->dev_list_lock); - } - - spin_lock_irq(&port->phy_list_lock); - list_for_each_entry(phy, &port->phy_list, port_phy_el) - sas_phy_set_target(phy, dev); - spin_unlock_irq(&port->phy_list_lock); - - return 0; -} - -/* ---------- Discover and Revalidate ---------- */ - -int sas_notify_lldd_dev_found(struct domain_device *dev) -{ - int res = 0; - struct sas_ha_struct *sas_ha = dev->port->ha; - struct Scsi_Host *shost = sas_ha->core.shost; - struct sas_internal *i = to_sas_internal(shost->transportt); - - if (i->dft->lldd_dev_found) { - res = i->dft->lldd_dev_found(dev); - if (res) { - printk("sas: driver on pcidev %s cannot handle " - "device %llx, error:%d\n", - dev_name(sas_ha->dev), - SAS_ADDR(dev->sas_addr), res); - } - kref_get(&dev->kref); - } - return res; -} - - -void sas_notify_lldd_dev_gone(struct domain_device *dev) -{ - struct sas_ha_struct *sas_ha = dev->port->ha; - struct Scsi_Host *shost = sas_ha->core.shost; - struct sas_internal *i = to_sas_internal(shost->transportt); - - if (i->dft->lldd_dev_gone) { - i->dft->lldd_dev_gone(dev); - sas_put_device(dev); - } -} - -static void sas_probe_devices(struct work_struct *work) -{ - struct domain_device *dev, *n; - struct sas_discovery_event *ev = to_sas_discovery_event(work); - struct asd_sas_port *port = ev->port; - - clear_bit(DISCE_PROBE, &port->disc.pending); - - /* devices must be domain members before link recovery and probe */ - list_for_each_entry(dev, &port->disco_list, disco_list_node) { - spin_lock_irq(&port->dev_list_lock); - list_add_tail(&dev->dev_list_node, &port->dev_list); - spin_unlock_irq(&port->dev_list_lock); - } - - sas_probe_sata(port); - - list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) { - int err; - - err = sas_rphy_add(dev->rphy); - if (err) - sas_fail_probe(dev, __func__, err); - else - list_del_init(&dev->disco_list_node); - } -} - -/** - * sas_discover_end_dev -- discover an end device (SSP, etc) - * @end: pointer to domain device of interest - * - * See comment in sas_discover_sata(). - */ -int sas_discover_end_dev(struct domain_device *dev) -{ - int res; - - res = sas_notify_lldd_dev_found(dev); - if (res) - return res; - sas_discover_event(dev->port, DISCE_PROBE); - - return 0; -} - -/* ---------- Device registration and unregistration ---------- */ - -void sas_free_device(struct kref *kref) -{ - struct domain_device *dev = container_of(kref, typeof(*dev), kref); - - put_device(&dev->rphy->dev); - dev->rphy = NULL; - - if (dev->parent) - sas_put_device(dev->parent); - - sas_port_put_phy(dev->phy); - dev->phy = NULL; - - /* remove the phys and ports, everything else should be gone */ - if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) - kfree(dev->ex_dev.ex_phy); - - if (dev_is_sata(dev) && dev->sata_dev.ap) { - ata_sas_port_destroy(dev->sata_dev.ap); - dev->sata_dev.ap = NULL; - } - - kfree(dev); -} - -static void sas_unregister_common_dev(struct asd_sas_port *port, struct domain_device *dev) -{ - sas_notify_lldd_dev_gone(dev); - if (!dev->parent) - dev->port->port_dev = NULL; - else - list_del_init(&dev->siblings); - - spin_lock_irq(&port->dev_list_lock); - list_del_init(&dev->dev_list_node); - spin_unlock_irq(&port->dev_list_lock); - - sas_put_device(dev); -} - -static void sas_destruct_devices(struct work_struct *work) -{ - struct domain_device *dev, *n; - struct sas_discovery_event *ev = to_sas_discovery_event(work); - struct asd_sas_port *port = ev->port; - - clear_bit(DISCE_DESTRUCT, &port->disc.pending); - - list_for_each_entry_safe(dev, n, &port->destroy_list, disco_list_node) { - list_del_init(&dev->disco_list_node); - - sas_remove_children(&dev->rphy->dev); - sas_rphy_delete(dev->rphy); - sas_unregister_common_dev(port, dev); - } -} - -void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev) -{ - if (!test_bit(SAS_DEV_DESTROY, &dev->state) && - !list_empty(&dev->disco_list_node)) { - /* this rphy never saw sas_rphy_add */ - list_del_init(&dev->disco_list_node); - sas_rphy_free(dev->rphy); - sas_unregister_common_dev(port, dev); - return; - } - - if (!test_and_set_bit(SAS_DEV_DESTROY, &dev->state)) { - sas_rphy_unlink(dev->rphy); - list_move_tail(&dev->disco_list_node, &port->destroy_list); - sas_discover_event(dev->port, DISCE_DESTRUCT); - } -} - -void sas_unregister_domain_devices(struct asd_sas_port *port, int gone) -{ - struct domain_device *dev, *n; - - list_for_each_entry_safe_reverse(dev, n, &port->dev_list, dev_list_node) { - if (gone) - set_bit(SAS_DEV_GONE, &dev->state); - sas_unregister_dev(port, dev); - } - - list_for_each_entry_safe(dev, n, &port->disco_list, disco_list_node) - sas_unregister_dev(port, dev); - - port->port->rphy = NULL; - -} - -void sas_device_set_phy(struct domain_device *dev, struct sas_port *port) -{ - struct sas_ha_struct *ha; - struct sas_phy *new_phy; - - if (!dev) - return; - - ha = dev->port->ha; - new_phy = sas_port_get_phy(port); - - /* pin and record last seen phy */ - spin_lock_irq(&ha->phy_port_lock); - if (new_phy) { - sas_port_put_phy(dev->phy); - dev->phy = new_phy; - } - spin_unlock_irq(&ha->phy_port_lock); -} - -/* ---------- Discovery and Revalidation ---------- */ - -/** - * sas_discover_domain -- discover the domain - * @port: port to the domain of interest - * - * NOTE: this process _must_ quit (return) as soon as any connection - * errors are encountered. Connection recovery is done elsewhere. - * Discover process only interrogates devices in order to discover the - * domain. - */ -static void sas_discover_domain(struct work_struct *work) -{ - struct domain_device *dev; - int error = 0; - struct sas_discovery_event *ev = to_sas_discovery_event(work); - struct asd_sas_port *port = ev->port; - - clear_bit(DISCE_DISCOVER_DOMAIN, &port->disc.pending); - - if (port->port_dev) - return; - - error = sas_get_port_device(port); - if (error) - return; - dev = port->port_dev; - - SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, - task_pid_nr(current)); - - switch (dev->dev_type) { - case SAS_END_DEV: - error = sas_discover_end_dev(dev); - break; - case EDGE_DEV: - case FANOUT_DEV: - error = sas_discover_root_expander(dev); - break; - case SATA_DEV: - case SATA_PM: -#ifdef CONFIG_SCSI_SAS_ATA - error = sas_discover_sata(dev); - break; -#else - SAS_DPRINTK("ATA device seen but CONFIG_SCSI_SAS_ATA=N so cannot attach\n"); - /* Fall through */ -#endif - default: - error = -ENXIO; - SAS_DPRINTK("unhandled device %d\n", dev->dev_type); - break; - } - - if (error) { - sas_rphy_free(dev->rphy); - list_del_init(&dev->disco_list_node); - spin_lock_irq(&port->dev_list_lock); - list_del_init(&dev->dev_list_node); - spin_unlock_irq(&port->dev_list_lock); - - sas_put_device(dev); - port->port_dev = NULL; - } - - SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id, - task_pid_nr(current), error); -} - -static void sas_revalidate_domain(struct work_struct *work) -{ - int res = 0; - struct sas_discovery_event *ev = to_sas_discovery_event(work); - struct asd_sas_port *port = ev->port; - struct sas_ha_struct *ha = port->ha; - - /* prevent revalidation from finding sata links in recovery */ - mutex_lock(&ha->disco_mutex); - if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) { - SAS_DPRINTK("REVALIDATION DEFERRED on port %d, pid:%d\n", - port->id, task_pid_nr(current)); - goto out; - } - - clear_bit(DISCE_REVALIDATE_DOMAIN, &port->disc.pending); - - SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, - task_pid_nr(current)); - - if (port->port_dev) - res = sas_ex_revalidate_domain(port->port_dev); - - SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", - port->id, task_pid_nr(current), res); - out: - mutex_unlock(&ha->disco_mutex); -} - -/* ---------- Events ---------- */ - -static void sas_chain_work(struct sas_ha_struct *ha, struct sas_work *sw) -{ - /* chained work is not subject to SA_HA_DRAINING or - * SAS_HA_REGISTERED, because it is either submitted in the - * workqueue, or known to be submitted from a context that is - * not racing against draining - */ - scsi_queue_work(ha->core.shost, &sw->work); -} - -static void sas_chain_event(int event, unsigned long *pending, - struct sas_work *sw, - struct sas_ha_struct *ha) -{ - if (!test_and_set_bit(event, pending)) { - unsigned long flags; - - spin_lock_irqsave(&ha->state_lock, flags); - sas_chain_work(ha, sw); - spin_unlock_irqrestore(&ha->state_lock, flags); - } -} - -int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) -{ - struct sas_discovery *disc; - - if (!port) - return 0; - disc = &port->disc; - - BUG_ON(ev >= DISC_NUM_EVENTS); - - sas_chain_event(ev, &disc->pending, &disc->disc_work[ev].work, port->ha); - - return 0; -} - -/** - * sas_init_disc -- initialize the discovery struct in the port - * @port: pointer to struct port - * - * Called when the ports are being initialized. - */ -void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) -{ - int i; - - static const work_func_t sas_event_fns[DISC_NUM_EVENTS] = { - [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, - [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, - [DISCE_PROBE] = sas_probe_devices, - [DISCE_DESTRUCT] = sas_destruct_devices, - }; - - disc->pending = 0; - for (i = 0; i < DISC_NUM_EVENTS; i++) { - INIT_SAS_WORK(&disc->disc_work[i].work, sas_event_fns[i]); - disc->disc_work[i].port = port; - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.c deleted file mode 100644 index fc460933..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Dump/Debugging routines - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "sas_dump.h" - -static const char *sas_hae_str[] = { - [0] = "HAE_RESET", -}; - -static const char *sas_porte_str[] = { - [0] = "PORTE_BYTES_DMAED", - [1] = "PORTE_BROADCAST_RCVD", - [2] = "PORTE_LINK_RESET_ERR", - [3] = "PORTE_TIMER_EVENT", - [4] = "PORTE_HARD_RESET", -}; - -static const char *sas_phye_str[] = { - [0] = "PHYE_LOSS_OF_SIGNAL", - [1] = "PHYE_OOB_DONE", - [2] = "PHYE_OOB_ERROR", - [3] = "PHYE_SPINUP_HOLD", -}; - -void sas_dprint_porte(int phyid, enum port_event pe) -{ - SAS_DPRINTK("phy%d: port event: %s\n", phyid, sas_porte_str[pe]); -} -void sas_dprint_phye(int phyid, enum phy_event pe) -{ - SAS_DPRINTK("phy%d: phy event: %s\n", phyid, sas_phye_str[pe]); -} - -void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he) -{ - SAS_DPRINTK("ha %s: %s event\n", dev_name(sas_ha->dev), - sas_hae_str[he]); -} - -void sas_dump_port(struct asd_sas_port *port) -{ - SAS_DPRINTK("port%d: class:0x%x\n", port->id, port->class); - SAS_DPRINTK("port%d: sas_addr:%llx\n", port->id, - SAS_ADDR(port->sas_addr)); - SAS_DPRINTK("port%d: attached_sas_addr:%llx\n", port->id, - SAS_ADDR(port->attached_sas_addr)); - SAS_DPRINTK("port%d: iproto:0x%x\n", port->id, port->iproto); - SAS_DPRINTK("port%d: tproto:0x%x\n", port->id, port->tproto); - SAS_DPRINTK("port%d: oob_mode:0x%x\n", port->id, port->oob_mode); - SAS_DPRINTK("port%d: num_phys:%d\n", port->id, port->num_phys); -} diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.h b/ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.h deleted file mode 100644 index 800e4c69..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_dump.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Dump/Debugging routines header file - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "sas_internal.h" - -void sas_dprint_porte(int phyid, enum port_event pe); -void sas_dprint_phye(int phyid, enum phy_event pe); -void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he); -void sas_dump_port(struct asd_sas_port *port); diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_event.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_event.c deleted file mode 100644 index 4e4292d2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_event.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Event processing - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include "sas_internal.h" -#include "sas_dump.h" - -void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw) -{ - if (!test_bit(SAS_HA_REGISTERED, &ha->state)) - return; - - if (test_bit(SAS_HA_DRAINING, &ha->state)) { - /* add it to the defer list, if not already pending */ - if (list_empty(&sw->drain_node)) - list_add(&sw->drain_node, &ha->defer_q); - } else - scsi_queue_work(ha->core.shost, &sw->work); -} - -static void sas_queue_event(int event, unsigned long *pending, - struct sas_work *work, - struct sas_ha_struct *ha) -{ - if (!test_and_set_bit(event, pending)) { - unsigned long flags; - - spin_lock_irqsave(&ha->state_lock, flags); - sas_queue_work(ha, work); - spin_unlock_irqrestore(&ha->state_lock, flags); - } -} - - -void __sas_drain_work(struct sas_ha_struct *ha) -{ - struct workqueue_struct *wq = ha->core.shost->work_q; - struct sas_work *sw, *_sw; - - set_bit(SAS_HA_DRAINING, &ha->state); - /* flush submitters */ - spin_lock_irq(&ha->state_lock); - spin_unlock_irq(&ha->state_lock); - - drain_workqueue(wq); - - spin_lock_irq(&ha->state_lock); - clear_bit(SAS_HA_DRAINING, &ha->state); - list_for_each_entry_safe(sw, _sw, &ha->defer_q, drain_node) { - list_del_init(&sw->drain_node); - sas_queue_work(ha, sw); - } - spin_unlock_irq(&ha->state_lock); -} - -int sas_drain_work(struct sas_ha_struct *ha) -{ - int err; - - err = mutex_lock_interruptible(&ha->drain_mutex); - if (err) - return err; - if (test_bit(SAS_HA_REGISTERED, &ha->state)) - __sas_drain_work(ha); - mutex_unlock(&ha->drain_mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(sas_drain_work); - -void sas_disable_revalidation(struct sas_ha_struct *ha) -{ - mutex_lock(&ha->disco_mutex); - set_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state); - mutex_unlock(&ha->disco_mutex); -} - -void sas_enable_revalidation(struct sas_ha_struct *ha) -{ - int i; - - mutex_lock(&ha->disco_mutex); - clear_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state); - for (i = 0; i < ha->num_phys; i++) { - struct asd_sas_port *port = ha->sas_port[i]; - const int ev = DISCE_REVALIDATE_DOMAIN; - struct sas_discovery *d = &port->disc; - - if (!test_and_clear_bit(ev, &d->pending)) - continue; - - sas_queue_event(ev, &d->pending, &d->disc_work[ev].work, ha); - } - mutex_unlock(&ha->disco_mutex); -} - -static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) -{ - BUG_ON(event >= HA_NUM_EVENTS); - - sas_queue_event(event, &sas_ha->pending, - &sas_ha->ha_events[event].work, sas_ha); -} - -static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) -{ - struct sas_ha_struct *ha = phy->ha; - - BUG_ON(event >= PORT_NUM_EVENTS); - - sas_queue_event(event, &phy->port_events_pending, - &phy->port_events[event].work, ha); -} - -static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) -{ - struct sas_ha_struct *ha = phy->ha; - - BUG_ON(event >= PHY_NUM_EVENTS); - - sas_queue_event(event, &phy->phy_events_pending, - &phy->phy_events[event].work, ha); -} - -int sas_init_events(struct sas_ha_struct *sas_ha) -{ - static const work_func_t sas_ha_event_fns[HA_NUM_EVENTS] = { - [HAE_RESET] = sas_hae_reset, - }; - - int i; - - for (i = 0; i < HA_NUM_EVENTS; i++) { - INIT_SAS_WORK(&sas_ha->ha_events[i].work, sas_ha_event_fns[i]); - sas_ha->ha_events[i].ha = sas_ha; - } - - sas_ha->notify_ha_event = notify_ha_event; - sas_ha->notify_port_event = notify_port_event; - sas_ha->notify_phy_event = notify_phy_event; - - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_expander.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_expander.c deleted file mode 100644 index caa0525d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_expander.c +++ /dev/null @@ -1,2184 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Expander discovery and configuration - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include -#include -#include - -#include "sas_internal.h" - -#include -#include -#include -#include "../scsi_sas_internal.h" - -static int sas_discover_expander(struct domain_device *dev); -static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr); -static int sas_configure_phy(struct domain_device *dev, int phy_id, - u8 *sas_addr, int include); -static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr); - -/* ---------- SMP task management ---------- */ - -static void smp_task_timedout(unsigned long _task) -{ - struct sas_task *task = (void *) _task; - unsigned long flags; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - complete(&task->completion); -} - -static void smp_task_done(struct sas_task *task) -{ - if (!del_timer(&task->timer)) - return; - complete(&task->completion); -} - -/* Give it some long enough timeout. In seconds. */ -#define SMP_TIMEOUT 10 - -static int smp_execute_task(struct domain_device *dev, void *req, int req_size, - void *resp, int resp_size) -{ - int res, retry; - struct sas_task *task = NULL; - struct sas_internal *i = - to_sas_internal(dev->port->ha->core.shost->transportt); - - mutex_lock(&dev->ex_dev.cmd_mutex); - for (retry = 0; retry < 3; retry++) { - if (test_bit(SAS_DEV_GONE, &dev->state)) { - res = -ECOMM; - break; - } - - task = sas_alloc_task(GFP_KERNEL); - if (!task) { - res = -ENOMEM; - break; - } - task->dev = dev; - task->task_proto = dev->tproto; - sg_init_one(&task->smp_task.smp_req, req, req_size); - sg_init_one(&task->smp_task.smp_resp, resp, resp_size); - - task->task_done = smp_task_done; - - task->timer.data = (unsigned long) task; - task->timer.function = smp_task_timedout; - task->timer.expires = jiffies + SMP_TIMEOUT*HZ; - add_timer(&task->timer); - - res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL); - - if (res) { - del_timer(&task->timer); - SAS_DPRINTK("executing SMP task failed:%d\n", res); - break; - } - - wait_for_completion(&task->completion); - res = -ECOMM; - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - SAS_DPRINTK("smp task timed out or aborted\n"); - i->dft->lldd_abort_task(task); - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - SAS_DPRINTK("SMP task aborted and not done\n"); - break; - } - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_STAT_GOOD) { - res = 0; - break; - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_UNDERRUN) { - /* no error, but return the number of bytes of - * underrun */ - res = task->task_status.residual; - break; - } - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_OVERRUN) { - res = -EMSGSIZE; - break; - } - if (task->task_status.resp == SAS_TASK_UNDELIVERED && - task->task_status.stat == SAS_DEVICE_UNKNOWN) - break; - else { - SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " - "status 0x%x\n", __func__, - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat); - sas_free_task(task); - task = NULL; - } - } - mutex_unlock(&dev->ex_dev.cmd_mutex); - - BUG_ON(retry == 3 && task != NULL); - sas_free_task(task); - return res; -} - -/* ---------- Allocations ---------- */ - -static inline void *alloc_smp_req(int size) -{ - u8 *p = kzalloc(size, GFP_KERNEL); - if (p) - p[0] = SMP_REQUEST; - return p; -} - -static inline void *alloc_smp_resp(int size) -{ - return kzalloc(size, GFP_KERNEL); -} - -static char sas_route_char(struct domain_device *dev, struct ex_phy *phy) -{ - switch (phy->routing_attr) { - case TABLE_ROUTING: - if (dev->ex_dev.t2t_supp) - return 'U'; - else - return 'T'; - case DIRECT_ROUTING: - return 'D'; - case SUBTRACTIVE_ROUTING: - return 'S'; - default: - return '?'; - } -} - -static enum sas_dev_type to_dev_type(struct discover_resp *dr) -{ - /* This is detecting a failure to transmit initial dev to host - * FIS as described in section J.5 of sas-2 r16 - */ - if (dr->attached_dev_type == NO_DEVICE && dr->attached_sata_dev && - dr->linkrate >= SAS_LINK_RATE_1_5_GBPS) - return SATA_PENDING; - else - return dr->attached_dev_type; -} - -static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp) -{ - enum sas_dev_type dev_type; - enum sas_linkrate linkrate; - u8 sas_addr[SAS_ADDR_SIZE]; - struct smp_resp *resp = rsp; - struct discover_resp *dr = &resp->disc; - struct sas_ha_struct *ha = dev->port->ha; - struct expander_device *ex = &dev->ex_dev; - struct ex_phy *phy = &ex->ex_phy[phy_id]; - struct sas_rphy *rphy = dev->rphy; - bool new_phy = !phy->phy; - char *type; - - if (new_phy) { - if (WARN_ON_ONCE(test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state))) - return; - phy->phy = sas_phy_alloc(&rphy->dev, phy_id); - - /* FIXME: error_handling */ - BUG_ON(!phy->phy); - } - - switch (resp->result) { - case SMP_RESP_PHY_VACANT: - phy->phy_state = PHY_VACANT; - break; - default: - phy->phy_state = PHY_NOT_PRESENT; - break; - case SMP_RESP_FUNC_ACC: - phy->phy_state = PHY_EMPTY; /* do not know yet */ - break; - } - - /* check if anything important changed to squelch debug */ - dev_type = phy->attached_dev_type; - linkrate = phy->linkrate; - memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); - - phy->attached_dev_type = to_dev_type(dr); - if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) - goto out; - phy->phy_id = phy_id; - phy->linkrate = dr->linkrate; - phy->attached_sata_host = dr->attached_sata_host; - phy->attached_sata_dev = dr->attached_sata_dev; - phy->attached_sata_ps = dr->attached_sata_ps; - phy->attached_iproto = dr->iproto << 1; - phy->attached_tproto = dr->tproto << 1; - /* help some expanders that fail to zero sas_address in the 'no - * device' case - */ - if (phy->attached_dev_type == NO_DEVICE || - phy->linkrate < SAS_LINK_RATE_1_5_GBPS) - memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); - else - memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE); - phy->attached_phy_id = dr->attached_phy_id; - phy->phy_change_count = dr->change_count; - phy->routing_attr = dr->routing_attr; - phy->virtual = dr->virtual; - phy->last_da_index = -1; - - phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr); - phy->phy->identify.device_type = dr->attached_dev_type; - phy->phy->identify.initiator_port_protocols = phy->attached_iproto; - phy->phy->identify.target_port_protocols = phy->attached_tproto; - if (!phy->attached_tproto && dr->attached_sata_dev) - phy->phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; - phy->phy->identify.phy_identifier = phy_id; - phy->phy->minimum_linkrate_hw = dr->hmin_linkrate; - phy->phy->maximum_linkrate_hw = dr->hmax_linkrate; - phy->phy->minimum_linkrate = dr->pmin_linkrate; - phy->phy->maximum_linkrate = dr->pmax_linkrate; - phy->phy->negotiated_linkrate = phy->linkrate; - - if (new_phy) - if (sas_phy_add(phy->phy)) { - sas_phy_free(phy->phy); - return; - } - - out: - switch (phy->attached_dev_type) { - case SATA_PENDING: - type = "stp pending"; - break; - case NO_DEVICE: - type = "no device"; - break; - case SAS_END_DEV: - if (phy->attached_iproto) { - if (phy->attached_tproto) - type = "host+target"; - else - type = "host"; - } else { - if (dr->attached_sata_dev) - type = "stp"; - else - type = "ssp"; - } - break; - case EDGE_DEV: - case FANOUT_DEV: - type = "smp"; - break; - default: - type = "unknown"; - } - - /* this routine is polled by libata error recovery so filter - * unimportant messages - */ - if (new_phy || phy->attached_dev_type != dev_type || - phy->linkrate != linkrate || - SAS_ADDR(phy->attached_sas_addr) != SAS_ADDR(sas_addr)) - /* pass */; - else - return; - - /* if the attached device type changed and ata_eh is active, - * make sure we run revalidation when eh completes (see: - * sas_enable_revalidation) - */ - if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) - set_bit(DISCE_REVALIDATE_DOMAIN, &dev->port->disc.pending); - - SAS_DPRINTK("%sex %016llx phy%02d:%c:%X attached: %016llx (%s)\n", - test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state) ? "ata: " : "", - SAS_ADDR(dev->sas_addr), phy->phy_id, - sas_route_char(dev, phy), phy->linkrate, - SAS_ADDR(phy->attached_sas_addr), type); -} - -/* check if we have an existing attached ata device on this expander phy */ -struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id) -{ - struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id]; - struct domain_device *dev; - struct sas_rphy *rphy; - - if (!ex_phy->port) - return NULL; - - rphy = ex_phy->port->rphy; - if (!rphy) - return NULL; - - dev = sas_find_dev_by_rphy(rphy); - - if (dev && dev_is_sata(dev)) - return dev; - - return NULL; -} - -#define DISCOVER_REQ_SIZE 16 -#define DISCOVER_RESP_SIZE 56 - -static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req, - u8 *disc_resp, int single) -{ - struct discover_resp *dr; - int res; - - disc_req[9] = single; - - res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE, - disc_resp, DISCOVER_RESP_SIZE); - if (res) - return res; - dr = &((struct smp_resp *)disc_resp)->disc; - if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) { - sas_printk("Found loopback topology, just ignore it!\n"); - return 0; - } - sas_set_ex_phy(dev, single, disc_resp); - return 0; -} - -int sas_ex_phy_discover(struct domain_device *dev, int single) -{ - struct expander_device *ex = &dev->ex_dev; - int res = 0; - u8 *disc_req; - u8 *disc_resp; - - disc_req = alloc_smp_req(DISCOVER_REQ_SIZE); - if (!disc_req) - return -ENOMEM; - - disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE); - if (!disc_resp) { - kfree(disc_req); - return -ENOMEM; - } - - disc_req[1] = SMP_DISCOVER; - - if (0 <= single && single < ex->num_phys) { - res = sas_ex_phy_discover_helper(dev, disc_req, disc_resp, single); - } else { - int i; - - for (i = 0; i < ex->num_phys; i++) { - res = sas_ex_phy_discover_helper(dev, disc_req, - disc_resp, i); - if (res) - goto out_err; - } - } -out_err: - kfree(disc_resp); - kfree(disc_req); - return res; -} - -static int sas_expander_discover(struct domain_device *dev) -{ - struct expander_device *ex = &dev->ex_dev; - int res = -ENOMEM; - - ex->ex_phy = kzalloc(sizeof(*ex->ex_phy)*ex->num_phys, GFP_KERNEL); - if (!ex->ex_phy) - return -ENOMEM; - - res = sas_ex_phy_discover(dev, -1); - if (res) - goto out_err; - - return 0; - out_err: - kfree(ex->ex_phy); - ex->ex_phy = NULL; - return res; -} - -#define MAX_EXPANDER_PHYS 128 - -static void ex_assign_report_general(struct domain_device *dev, - struct smp_resp *resp) -{ - struct report_general_resp *rg = &resp->rg; - - dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count); - dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes); - dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS); - dev->ex_dev.t2t_supp = rg->t2t_supp; - dev->ex_dev.conf_route_table = rg->conf_route_table; - dev->ex_dev.configuring = rg->configuring; - memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8); -} - -#define RG_REQ_SIZE 8 -#define RG_RESP_SIZE 32 - -static int sas_ex_general(struct domain_device *dev) -{ - u8 *rg_req; - struct smp_resp *rg_resp; - int res; - int i; - - rg_req = alloc_smp_req(RG_REQ_SIZE); - if (!rg_req) - return -ENOMEM; - - rg_resp = alloc_smp_resp(RG_RESP_SIZE); - if (!rg_resp) { - kfree(rg_req); - return -ENOMEM; - } - - rg_req[1] = SMP_REPORT_GENERAL; - - for (i = 0; i < 5; i++) { - res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp, - RG_RESP_SIZE); - - if (res) { - SAS_DPRINTK("RG to ex %016llx failed:0x%x\n", - SAS_ADDR(dev->sas_addr), res); - goto out; - } else if (rg_resp->result != SMP_RESP_FUNC_ACC) { - SAS_DPRINTK("RG:ex %016llx returned SMP result:0x%x\n", - SAS_ADDR(dev->sas_addr), rg_resp->result); - res = rg_resp->result; - goto out; - } - - ex_assign_report_general(dev, rg_resp); - - if (dev->ex_dev.configuring) { - SAS_DPRINTK("RG: ex %llx self-configuring...\n", - SAS_ADDR(dev->sas_addr)); - schedule_timeout_interruptible(5*HZ); - } else - break; - } -out: - kfree(rg_req); - kfree(rg_resp); - return res; -} - -static void ex_assign_manuf_info(struct domain_device *dev, void - *_mi_resp) -{ - u8 *mi_resp = _mi_resp; - struct sas_rphy *rphy = dev->rphy; - struct sas_expander_device *edev = rphy_to_expander_device(rphy); - - memcpy(edev->vendor_id, mi_resp + 12, SAS_EXPANDER_VENDOR_ID_LEN); - memcpy(edev->product_id, mi_resp + 20, SAS_EXPANDER_PRODUCT_ID_LEN); - memcpy(edev->product_rev, mi_resp + 36, - SAS_EXPANDER_PRODUCT_REV_LEN); - - if (mi_resp[8] & 1) { - memcpy(edev->component_vendor_id, mi_resp + 40, - SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); - edev->component_id = mi_resp[48] << 8 | mi_resp[49]; - edev->component_revision_id = mi_resp[50]; - } -} - -#define MI_REQ_SIZE 8 -#define MI_RESP_SIZE 64 - -static int sas_ex_manuf_info(struct domain_device *dev) -{ - u8 *mi_req; - u8 *mi_resp; - int res; - - mi_req = alloc_smp_req(MI_REQ_SIZE); - if (!mi_req) - return -ENOMEM; - - mi_resp = alloc_smp_resp(MI_RESP_SIZE); - if (!mi_resp) { - kfree(mi_req); - return -ENOMEM; - } - - mi_req[1] = SMP_REPORT_MANUF_INFO; - - res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE); - if (res) { - SAS_DPRINTK("MI: ex %016llx failed:0x%x\n", - SAS_ADDR(dev->sas_addr), res); - goto out; - } else if (mi_resp[2] != SMP_RESP_FUNC_ACC) { - SAS_DPRINTK("MI ex %016llx returned SMP result:0x%x\n", - SAS_ADDR(dev->sas_addr), mi_resp[2]); - goto out; - } - - ex_assign_manuf_info(dev, mi_resp); -out: - kfree(mi_req); - kfree(mi_resp); - return res; -} - -#define PC_REQ_SIZE 44 -#define PC_RESP_SIZE 8 - -int sas_smp_phy_control(struct domain_device *dev, int phy_id, - enum phy_func phy_func, - struct sas_phy_linkrates *rates) -{ - u8 *pc_req; - u8 *pc_resp; - int res; - - pc_req = alloc_smp_req(PC_REQ_SIZE); - if (!pc_req) - return -ENOMEM; - - pc_resp = alloc_smp_resp(PC_RESP_SIZE); - if (!pc_resp) { - kfree(pc_req); - return -ENOMEM; - } - - pc_req[1] = SMP_PHY_CONTROL; - pc_req[9] = phy_id; - pc_req[10]= phy_func; - if (rates) { - pc_req[32] = rates->minimum_linkrate << 4; - pc_req[33] = rates->maximum_linkrate << 4; - } - - res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE); - - kfree(pc_resp); - kfree(pc_req); - return res; -} - -static void sas_ex_disable_phy(struct domain_device *dev, int phy_id) -{ - struct expander_device *ex = &dev->ex_dev; - struct ex_phy *phy = &ex->ex_phy[phy_id]; - - sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE, NULL); - phy->linkrate = SAS_PHY_DISABLED; -} - -static void sas_ex_disable_port(struct domain_device *dev, u8 *sas_addr) -{ - struct expander_device *ex = &dev->ex_dev; - int i; - - for (i = 0; i < ex->num_phys; i++) { - struct ex_phy *phy = &ex->ex_phy[i]; - - if (phy->phy_state == PHY_VACANT || - phy->phy_state == PHY_NOT_PRESENT) - continue; - - if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(sas_addr)) - sas_ex_disable_phy(dev, i); - } -} - -static int sas_dev_present_in_domain(struct asd_sas_port *port, - u8 *sas_addr) -{ - struct domain_device *dev; - - if (SAS_ADDR(port->sas_addr) == SAS_ADDR(sas_addr)) - return 1; - list_for_each_entry(dev, &port->dev_list, dev_list_node) { - if (SAS_ADDR(dev->sas_addr) == SAS_ADDR(sas_addr)) - return 1; - } - return 0; -} - -#define RPEL_REQ_SIZE 16 -#define RPEL_RESP_SIZE 32 -int sas_smp_get_phy_events(struct sas_phy *phy) -{ - int res; - u8 *req; - u8 *resp; - struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); - struct domain_device *dev = sas_find_dev_by_rphy(rphy); - - req = alloc_smp_req(RPEL_REQ_SIZE); - if (!req) - return -ENOMEM; - - resp = alloc_smp_resp(RPEL_RESP_SIZE); - if (!resp) { - kfree(req); - return -ENOMEM; - } - - req[1] = SMP_REPORT_PHY_ERR_LOG; - req[9] = phy->number; - - res = smp_execute_task(dev, req, RPEL_REQ_SIZE, - resp, RPEL_RESP_SIZE); - - if (!res) - goto out; - - phy->invalid_dword_count = scsi_to_u32(&resp[12]); - phy->running_disparity_error_count = scsi_to_u32(&resp[16]); - phy->loss_of_dword_sync_count = scsi_to_u32(&resp[20]); - phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); - - out: - kfree(resp); - return res; - -} - -#ifdef CONFIG_SCSI_SAS_ATA - -#define RPS_REQ_SIZE 16 -#define RPS_RESP_SIZE 60 - -int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, - struct smp_resp *rps_resp) -{ - int res; - u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE); - u8 *resp = (u8 *)rps_resp; - - if (!rps_req) - return -ENOMEM; - - rps_req[1] = SMP_REPORT_PHY_SATA; - rps_req[9] = phy_id; - - res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE, - rps_resp, RPS_RESP_SIZE); - - /* 0x34 is the FIS type for the D2H fis. There's a potential - * standards cockup here. sas-2 explicitly specifies the FIS - * should be encoded so that FIS type is in resp[24]. - * However, some expanders endian reverse this. Undo the - * reversal here */ - if (!res && resp[27] == 0x34 && resp[24] != 0x34) { - int i; - - for (i = 0; i < 5; i++) { - int j = 24 + (i*4); - u8 a, b; - a = resp[j + 0]; - b = resp[j + 1]; - resp[j + 0] = resp[j + 3]; - resp[j + 1] = resp[j + 2]; - resp[j + 2] = b; - resp[j + 3] = a; - } - } - - kfree(rps_req); - return res; -} -#endif - -static void sas_ex_get_linkrate(struct domain_device *parent, - struct domain_device *child, - struct ex_phy *parent_phy) -{ - struct expander_device *parent_ex = &parent->ex_dev; - struct sas_port *port; - int i; - - child->pathways = 0; - - port = parent_phy->port; - - for (i = 0; i < parent_ex->num_phys; i++) { - struct ex_phy *phy = &parent_ex->ex_phy[i]; - - if (phy->phy_state == PHY_VACANT || - phy->phy_state == PHY_NOT_PRESENT) - continue; - - if (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(child->sas_addr)) { - - child->min_linkrate = min(parent->min_linkrate, - phy->linkrate); - child->max_linkrate = max(parent->max_linkrate, - phy->linkrate); - child->pathways++; - sas_port_add_phy(port, phy->phy); - } - } - child->linkrate = min(parent_phy->linkrate, child->max_linkrate); - child->pathways = min(child->pathways, parent->pathways); -} - -static struct domain_device *sas_ex_discover_end_dev( - struct domain_device *parent, int phy_id) -{ - struct expander_device *parent_ex = &parent->ex_dev; - struct ex_phy *phy = &parent_ex->ex_phy[phy_id]; - struct domain_device *child = NULL; - struct sas_rphy *rphy; - int res; - - if (phy->attached_sata_host || phy->attached_sata_ps) - return NULL; - - child = sas_alloc_device(); - if (!child) - return NULL; - - kref_get(&parent->kref); - child->parent = parent; - child->port = parent->port; - child->iproto = phy->attached_iproto; - memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); - sas_hash_addr(child->hashed_sas_addr, child->sas_addr); - if (!phy->port) { - phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); - if (unlikely(!phy->port)) - goto out_err; - if (unlikely(sas_port_add(phy->port) != 0)) { - sas_port_free(phy->port); - goto out_err; - } - } - sas_ex_get_linkrate(parent, child, phy); - sas_device_set_phy(child, phy->port); - -#ifdef CONFIG_SCSI_SAS_ATA - if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) { - res = sas_get_ata_info(child, phy); - if (res) - goto out_free; - - sas_init_dev(child); - res = sas_ata_init(child); - if (res) - goto out_free; - rphy = sas_end_device_alloc(phy->port); - if (!rphy) - goto out_free; - - child->rphy = rphy; - get_device(&rphy->dev); - - list_add_tail(&child->disco_list_node, &parent->port->disco_list); - - res = sas_discover_sata(child); - if (res) { - SAS_DPRINTK("sas_discover_sata() for device %16llx at " - "%016llx:0x%x returned 0x%x\n", - SAS_ADDR(child->sas_addr), - SAS_ADDR(parent->sas_addr), phy_id, res); - goto out_list_del; - } - } else -#endif - if (phy->attached_tproto & SAS_PROTOCOL_SSP) { - child->dev_type = SAS_END_DEV; - rphy = sas_end_device_alloc(phy->port); - /* FIXME: error handling */ - if (unlikely(!rphy)) - goto out_free; - child->tproto = phy->attached_tproto; - sas_init_dev(child); - - child->rphy = rphy; - get_device(&rphy->dev); - sas_fill_in_rphy(child, rphy); - - list_add_tail(&child->disco_list_node, &parent->port->disco_list); - - res = sas_discover_end_dev(child); - if (res) { - SAS_DPRINTK("sas_discover_end_dev() for device %16llx " - "at %016llx:0x%x returned 0x%x\n", - SAS_ADDR(child->sas_addr), - SAS_ADDR(parent->sas_addr), phy_id, res); - goto out_list_del; - } - } else { - SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n", - phy->attached_tproto, SAS_ADDR(parent->sas_addr), - phy_id); - goto out_free; - } - - list_add_tail(&child->siblings, &parent_ex->children); - return child; - - out_list_del: - sas_rphy_free(child->rphy); - list_del(&child->disco_list_node); - spin_lock_irq(&parent->port->dev_list_lock); - list_del(&child->dev_list_node); - spin_unlock_irq(&parent->port->dev_list_lock); - out_free: - sas_port_delete(phy->port); - out_err: - phy->port = NULL; - sas_put_device(child); - return NULL; -} - -/* See if this phy is part of a wide port */ -static int sas_ex_join_wide_port(struct domain_device *parent, int phy_id) -{ - struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id]; - int i; - - for (i = 0; i < parent->ex_dev.num_phys; i++) { - struct ex_phy *ephy = &parent->ex_dev.ex_phy[i]; - - if (ephy == phy) - continue; - - if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr, - SAS_ADDR_SIZE) && ephy->port) { - sas_port_add_phy(ephy->port, phy->phy); - phy->port = ephy->port; - phy->phy_state = PHY_DEVICE_DISCOVERED; - return 0; - } - } - - return -ENODEV; -} - -static struct domain_device *sas_ex_discover_expander( - struct domain_device *parent, int phy_id) -{ - struct sas_expander_device *parent_ex = rphy_to_expander_device(parent->rphy); - struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id]; - struct domain_device *child = NULL; - struct sas_rphy *rphy; - struct sas_expander_device *edev; - struct asd_sas_port *port; - int res; - - if (phy->routing_attr == DIRECT_ROUTING) { - SAS_DPRINTK("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not " - "allowed\n", - SAS_ADDR(parent->sas_addr), phy_id, - SAS_ADDR(phy->attached_sas_addr), - phy->attached_phy_id); - return NULL; - } - child = sas_alloc_device(); - if (!child) - return NULL; - - phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); - /* FIXME: better error handling */ - BUG_ON(sas_port_add(phy->port) != 0); - - - switch (phy->attached_dev_type) { - case EDGE_DEV: - rphy = sas_expander_alloc(phy->port, - SAS_EDGE_EXPANDER_DEVICE); - break; - case FANOUT_DEV: - rphy = sas_expander_alloc(phy->port, - SAS_FANOUT_EXPANDER_DEVICE); - break; - default: - rphy = NULL; /* shut gcc up */ - BUG(); - } - port = parent->port; - child->rphy = rphy; - get_device(&rphy->dev); - edev = rphy_to_expander_device(rphy); - child->dev_type = phy->attached_dev_type; - kref_get(&parent->kref); - child->parent = parent; - child->port = port; - child->iproto = phy->attached_iproto; - child->tproto = phy->attached_tproto; - memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); - sas_hash_addr(child->hashed_sas_addr, child->sas_addr); - sas_ex_get_linkrate(parent, child, phy); - edev->level = parent_ex->level + 1; - parent->port->disc.max_level = max(parent->port->disc.max_level, - edev->level); - sas_init_dev(child); - sas_fill_in_rphy(child, rphy); - sas_rphy_add(rphy); - - spin_lock_irq(&parent->port->dev_list_lock); - list_add_tail(&child->dev_list_node, &parent->port->dev_list); - spin_unlock_irq(&parent->port->dev_list_lock); - - res = sas_discover_expander(child); - if (res) { - sas_rphy_delete(rphy); - spin_lock_irq(&parent->port->dev_list_lock); - list_del(&child->dev_list_node); - spin_unlock_irq(&parent->port->dev_list_lock); - sas_put_device(child); - return NULL; - } - list_add_tail(&child->siblings, &parent->ex_dev.children); - return child; -} - -static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) -{ - struct expander_device *ex = &dev->ex_dev; - struct ex_phy *ex_phy = &ex->ex_phy[phy_id]; - struct domain_device *child = NULL; - int res = 0; - - /* Phy state */ - if (ex_phy->linkrate == SAS_SATA_SPINUP_HOLD) { - if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET, NULL)) - res = sas_ex_phy_discover(dev, phy_id); - if (res) - return res; - } - - /* Parent and domain coherency */ - if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) == - SAS_ADDR(dev->port->sas_addr))) { - sas_add_parent_port(dev, phy_id); - return 0; - } - if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) == - SAS_ADDR(dev->parent->sas_addr))) { - sas_add_parent_port(dev, phy_id); - if (ex_phy->routing_attr == TABLE_ROUTING) - sas_configure_phy(dev, phy_id, dev->port->sas_addr, 1); - return 0; - } - - if (sas_dev_present_in_domain(dev->port, ex_phy->attached_sas_addr)) - sas_ex_disable_port(dev, ex_phy->attached_sas_addr); - - if (ex_phy->attached_dev_type == NO_DEVICE) { - if (ex_phy->routing_attr == DIRECT_ROUTING) { - memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE); - sas_configure_routing(dev, ex_phy->attached_sas_addr); - } - return 0; - } else if (ex_phy->linkrate == SAS_LINK_RATE_UNKNOWN) - return 0; - - if (ex_phy->attached_dev_type != SAS_END_DEV && - ex_phy->attached_dev_type != FANOUT_DEV && - ex_phy->attached_dev_type != EDGE_DEV && - ex_phy->attached_dev_type != SATA_PENDING) { - SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx " - "phy 0x%x\n", ex_phy->attached_dev_type, - SAS_ADDR(dev->sas_addr), - phy_id); - return 0; - } - - res = sas_configure_routing(dev, ex_phy->attached_sas_addr); - if (res) { - SAS_DPRINTK("configure routing for dev %016llx " - "reported 0x%x. Forgotten\n", - SAS_ADDR(ex_phy->attached_sas_addr), res); - sas_disable_routing(dev, ex_phy->attached_sas_addr); - return res; - } - - res = sas_ex_join_wide_port(dev, phy_id); - if (!res) { - SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", - phy_id, SAS_ADDR(ex_phy->attached_sas_addr)); - return res; - } - - switch (ex_phy->attached_dev_type) { - case SAS_END_DEV: - case SATA_PENDING: - child = sas_ex_discover_end_dev(dev, phy_id); - break; - case FANOUT_DEV: - if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) { - SAS_DPRINTK("second fanout expander %016llx phy 0x%x " - "attached to ex %016llx phy 0x%x\n", - SAS_ADDR(ex_phy->attached_sas_addr), - ex_phy->attached_phy_id, - SAS_ADDR(dev->sas_addr), - phy_id); - sas_ex_disable_phy(dev, phy_id); - break; - } else - memcpy(dev->port->disc.fanout_sas_addr, - ex_phy->attached_sas_addr, SAS_ADDR_SIZE); - /* fallthrough */ - case EDGE_DEV: - child = sas_ex_discover_expander(dev, phy_id); - break; - default: - break; - } - - if (child) { - int i; - - for (i = 0; i < ex->num_phys; i++) { - if (ex->ex_phy[i].phy_state == PHY_VACANT || - ex->ex_phy[i].phy_state == PHY_NOT_PRESENT) - continue; - /* - * Due to races, the phy might not get added to the - * wide port, so we add the phy to the wide port here. - */ - if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) == - SAS_ADDR(child->sas_addr)) { - ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED; - res = sas_ex_join_wide_port(dev, i); - if (!res) - SAS_DPRINTK("Attaching ex phy%d to wide port %016llx\n", - i, SAS_ADDR(ex->ex_phy[i].attached_sas_addr)); - - } - } - } - - return res; -} - -static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr) -{ - struct expander_device *ex = &dev->ex_dev; - int i; - - for (i = 0; i < ex->num_phys; i++) { - struct ex_phy *phy = &ex->ex_phy[i]; - - if (phy->phy_state == PHY_VACANT || - phy->phy_state == PHY_NOT_PRESENT) - continue; - - if ((phy->attached_dev_type == EDGE_DEV || - phy->attached_dev_type == FANOUT_DEV) && - phy->routing_attr == SUBTRACTIVE_ROUTING) { - - memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE); - - return 1; - } - } - return 0; -} - -static int sas_check_level_subtractive_boundary(struct domain_device *dev) -{ - struct expander_device *ex = &dev->ex_dev; - struct domain_device *child; - u8 sub_addr[8] = {0, }; - - list_for_each_entry(child, &ex->children, siblings) { - if (child->dev_type != EDGE_DEV && - child->dev_type != FANOUT_DEV) - continue; - if (sub_addr[0] == 0) { - sas_find_sub_addr(child, sub_addr); - continue; - } else { - u8 s2[8]; - - if (sas_find_sub_addr(child, s2) && - (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) { - - SAS_DPRINTK("ex %016llx->%016llx-?->%016llx " - "diverges from subtractive " - "boundary %016llx\n", - SAS_ADDR(dev->sas_addr), - SAS_ADDR(child->sas_addr), - SAS_ADDR(s2), - SAS_ADDR(sub_addr)); - - sas_ex_disable_port(child, s2); - } - } - } - return 0; -} -/** - * sas_ex_discover_devices -- discover devices attached to this expander - * dev: pointer to the expander domain device - * single: if you want to do a single phy, else set to -1; - * - * Configure this expander for use with its devices and register the - * devices of this expander. - */ -static int sas_ex_discover_devices(struct domain_device *dev, int single) -{ - struct expander_device *ex = &dev->ex_dev; - int i = 0, end = ex->num_phys; - int res = 0; - - if (0 <= single && single < end) { - i = single; - end = i+1; - } - - for ( ; i < end; i++) { - struct ex_phy *ex_phy = &ex->ex_phy[i]; - - if (ex_phy->phy_state == PHY_VACANT || - ex_phy->phy_state == PHY_NOT_PRESENT || - ex_phy->phy_state == PHY_DEVICE_DISCOVERED) - continue; - - switch (ex_phy->linkrate) { - case SAS_PHY_DISABLED: - case SAS_PHY_RESET_PROBLEM: - case SAS_SATA_PORT_SELECTOR: - continue; - default: - res = sas_ex_discover_dev(dev, i); - if (res) - break; - continue; - } - } - - if (!res) - sas_check_level_subtractive_boundary(dev); - - return res; -} - -static int sas_check_ex_subtractive_boundary(struct domain_device *dev) -{ - struct expander_device *ex = &dev->ex_dev; - int i; - u8 *sub_sas_addr = NULL; - - if (dev->dev_type != EDGE_DEV) - return 0; - - for (i = 0; i < ex->num_phys; i++) { - struct ex_phy *phy = &ex->ex_phy[i]; - - if (phy->phy_state == PHY_VACANT || - phy->phy_state == PHY_NOT_PRESENT) - continue; - - if ((phy->attached_dev_type == FANOUT_DEV || - phy->attached_dev_type == EDGE_DEV) && - phy->routing_attr == SUBTRACTIVE_ROUTING) { - - if (!sub_sas_addr) - sub_sas_addr = &phy->attached_sas_addr[0]; - else if (SAS_ADDR(sub_sas_addr) != - SAS_ADDR(phy->attached_sas_addr)) { - - SAS_DPRINTK("ex %016llx phy 0x%x " - "diverges(%016llx) on subtractive " - "boundary(%016llx). Disabled\n", - SAS_ADDR(dev->sas_addr), i, - SAS_ADDR(phy->attached_sas_addr), - SAS_ADDR(sub_sas_addr)); - sas_ex_disable_phy(dev, i); - } - } - } - return 0; -} - -static void sas_print_parent_topology_bug(struct domain_device *child, - struct ex_phy *parent_phy, - struct ex_phy *child_phy) -{ - static const char *ex_type[] = { - [EDGE_DEV] = "edge", - [FANOUT_DEV] = "fanout", - }; - struct domain_device *parent = child->parent; - - sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx " - "phy 0x%x has %c:%c routing link!\n", - - ex_type[parent->dev_type], - SAS_ADDR(parent->sas_addr), - parent_phy->phy_id, - - ex_type[child->dev_type], - SAS_ADDR(child->sas_addr), - child_phy->phy_id, - - sas_route_char(parent, parent_phy), - sas_route_char(child, child_phy)); -} - -static int sas_check_eeds(struct domain_device *child, - struct ex_phy *parent_phy, - struct ex_phy *child_phy) -{ - int res = 0; - struct domain_device *parent = child->parent; - - if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) { - res = -ENODEV; - SAS_DPRINTK("edge ex %016llx phy S:0x%x <--> edge ex %016llx " - "phy S:0x%x, while there is a fanout ex %016llx\n", - SAS_ADDR(parent->sas_addr), - parent_phy->phy_id, - SAS_ADDR(child->sas_addr), - child_phy->phy_id, - SAS_ADDR(parent->port->disc.fanout_sas_addr)); - } else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) { - memcpy(parent->port->disc.eeds_a, parent->sas_addr, - SAS_ADDR_SIZE); - memcpy(parent->port->disc.eeds_b, child->sas_addr, - SAS_ADDR_SIZE); - } else if (((SAS_ADDR(parent->port->disc.eeds_a) == - SAS_ADDR(parent->sas_addr)) || - (SAS_ADDR(parent->port->disc.eeds_a) == - SAS_ADDR(child->sas_addr))) - && - ((SAS_ADDR(parent->port->disc.eeds_b) == - SAS_ADDR(parent->sas_addr)) || - (SAS_ADDR(parent->port->disc.eeds_b) == - SAS_ADDR(child->sas_addr)))) - ; - else { - res = -ENODEV; - SAS_DPRINTK("edge ex %016llx phy 0x%x <--> edge ex %016llx " - "phy 0x%x link forms a third EEDS!\n", - SAS_ADDR(parent->sas_addr), - parent_phy->phy_id, - SAS_ADDR(child->sas_addr), - child_phy->phy_id); - } - - return res; -} - -/* Here we spill over 80 columns. It is intentional. - */ -static int sas_check_parent_topology(struct domain_device *child) -{ - struct expander_device *child_ex = &child->ex_dev; - struct expander_device *parent_ex; - int i; - int res = 0; - - if (!child->parent) - return 0; - - if (child->parent->dev_type != EDGE_DEV && - child->parent->dev_type != FANOUT_DEV) - return 0; - - parent_ex = &child->parent->ex_dev; - - for (i = 0; i < parent_ex->num_phys; i++) { - struct ex_phy *parent_phy = &parent_ex->ex_phy[i]; - struct ex_phy *child_phy; - - if (parent_phy->phy_state == PHY_VACANT || - parent_phy->phy_state == PHY_NOT_PRESENT) - continue; - - if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr)) - continue; - - child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id]; - - switch (child->parent->dev_type) { - case EDGE_DEV: - if (child->dev_type == FANOUT_DEV) { - if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING || - child_phy->routing_attr != TABLE_ROUTING) { - sas_print_parent_topology_bug(child, parent_phy, child_phy); - res = -ENODEV; - } - } else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) { - if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) { - res = sas_check_eeds(child, parent_phy, child_phy); - } else if (child_phy->routing_attr != TABLE_ROUTING) { - sas_print_parent_topology_bug(child, parent_phy, child_phy); - res = -ENODEV; - } - } else if (parent_phy->routing_attr == TABLE_ROUTING) { - if (child_phy->routing_attr == SUBTRACTIVE_ROUTING || - (child_phy->routing_attr == TABLE_ROUTING && - child_ex->t2t_supp && parent_ex->t2t_supp)) { - /* All good */; - } else { - sas_print_parent_topology_bug(child, parent_phy, child_phy); - res = -ENODEV; - } - } - break; - case FANOUT_DEV: - if (parent_phy->routing_attr != TABLE_ROUTING || - child_phy->routing_attr != SUBTRACTIVE_ROUTING) { - sas_print_parent_topology_bug(child, parent_phy, child_phy); - res = -ENODEV; - } - break; - default: - break; - } - } - - return res; -} - -#define RRI_REQ_SIZE 16 -#define RRI_RESP_SIZE 44 - -static int sas_configure_present(struct domain_device *dev, int phy_id, - u8 *sas_addr, int *index, int *present) -{ - int i, res = 0; - struct expander_device *ex = &dev->ex_dev; - struct ex_phy *phy = &ex->ex_phy[phy_id]; - u8 *rri_req; - u8 *rri_resp; - - *present = 0; - *index = 0; - - rri_req = alloc_smp_req(RRI_REQ_SIZE); - if (!rri_req) - return -ENOMEM; - - rri_resp = alloc_smp_resp(RRI_RESP_SIZE); - if (!rri_resp) { - kfree(rri_req); - return -ENOMEM; - } - - rri_req[1] = SMP_REPORT_ROUTE_INFO; - rri_req[9] = phy_id; - - for (i = 0; i < ex->max_route_indexes ; i++) { - *(__be16 *)(rri_req+6) = cpu_to_be16(i); - res = smp_execute_task(dev, rri_req, RRI_REQ_SIZE, rri_resp, - RRI_RESP_SIZE); - if (res) - goto out; - res = rri_resp[2]; - if (res == SMP_RESP_NO_INDEX) { - SAS_DPRINTK("overflow of indexes: dev %016llx " - "phy 0x%x index 0x%x\n", - SAS_ADDR(dev->sas_addr), phy_id, i); - goto out; - } else if (res != SMP_RESP_FUNC_ACC) { - SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x " - "result 0x%x\n", __func__, - SAS_ADDR(dev->sas_addr), phy_id, i, res); - goto out; - } - if (SAS_ADDR(sas_addr) != 0) { - if (SAS_ADDR(rri_resp+16) == SAS_ADDR(sas_addr)) { - *index = i; - if ((rri_resp[12] & 0x80) == 0x80) - *present = 0; - else - *present = 1; - goto out; - } else if (SAS_ADDR(rri_resp+16) == 0) { - *index = i; - *present = 0; - goto out; - } - } else if (SAS_ADDR(rri_resp+16) == 0 && - phy->last_da_index < i) { - phy->last_da_index = i; - *index = i; - *present = 0; - goto out; - } - } - res = -1; -out: - kfree(rri_req); - kfree(rri_resp); - return res; -} - -#define CRI_REQ_SIZE 44 -#define CRI_RESP_SIZE 8 - -static int sas_configure_set(struct domain_device *dev, int phy_id, - u8 *sas_addr, int index, int include) -{ - int res; - u8 *cri_req; - u8 *cri_resp; - - cri_req = alloc_smp_req(CRI_REQ_SIZE); - if (!cri_req) - return -ENOMEM; - - cri_resp = alloc_smp_resp(CRI_RESP_SIZE); - if (!cri_resp) { - kfree(cri_req); - return -ENOMEM; - } - - cri_req[1] = SMP_CONF_ROUTE_INFO; - *(__be16 *)(cri_req+6) = cpu_to_be16(index); - cri_req[9] = phy_id; - if (SAS_ADDR(sas_addr) == 0 || !include) - cri_req[12] |= 0x80; - memcpy(cri_req+16, sas_addr, SAS_ADDR_SIZE); - - res = smp_execute_task(dev, cri_req, CRI_REQ_SIZE, cri_resp, - CRI_RESP_SIZE); - if (res) - goto out; - res = cri_resp[2]; - if (res == SMP_RESP_NO_INDEX) { - SAS_DPRINTK("overflow of indexes: dev %016llx phy 0x%x " - "index 0x%x\n", - SAS_ADDR(dev->sas_addr), phy_id, index); - } -out: - kfree(cri_req); - kfree(cri_resp); - return res; -} - -static int sas_configure_phy(struct domain_device *dev, int phy_id, - u8 *sas_addr, int include) -{ - int index; - int present; - int res; - - res = sas_configure_present(dev, phy_id, sas_addr, &index, &present); - if (res) - return res; - if (include ^ present) - return sas_configure_set(dev, phy_id, sas_addr, index,include); - - return res; -} - -/** - * sas_configure_parent -- configure routing table of parent - * parent: parent expander - * child: child expander - * sas_addr: SAS port identifier of device directly attached to child - */ -static int sas_configure_parent(struct domain_device *parent, - struct domain_device *child, - u8 *sas_addr, int include) -{ - struct expander_device *ex_parent = &parent->ex_dev; - int res = 0; - int i; - - if (parent->parent) { - res = sas_configure_parent(parent->parent, parent, sas_addr, - include); - if (res) - return res; - } - - if (ex_parent->conf_route_table == 0) { - SAS_DPRINTK("ex %016llx has self-configuring routing table\n", - SAS_ADDR(parent->sas_addr)); - return 0; - } - - for (i = 0; i < ex_parent->num_phys; i++) { - struct ex_phy *phy = &ex_parent->ex_phy[i]; - - if ((phy->routing_attr == TABLE_ROUTING) && - (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(child->sas_addr))) { - res = sas_configure_phy(parent, i, sas_addr, include); - if (res) - return res; - } - } - - return res; -} - -/** - * sas_configure_routing -- configure routing - * dev: expander device - * sas_addr: port identifier of device directly attached to the expander device - */ -static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr) -{ - if (dev->parent) - return sas_configure_parent(dev->parent, dev, sas_addr, 1); - return 0; -} - -static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr) -{ - if (dev->parent) - return sas_configure_parent(dev->parent, dev, sas_addr, 0); - return 0; -} - -/** - * sas_discover_expander -- expander discovery - * @ex: pointer to expander domain device - * - * See comment in sas_discover_sata(). - */ -static int sas_discover_expander(struct domain_device *dev) -{ - int res; - - res = sas_notify_lldd_dev_found(dev); - if (res) - return res; - - res = sas_ex_general(dev); - if (res) - goto out_err; - res = sas_ex_manuf_info(dev); - if (res) - goto out_err; - - res = sas_expander_discover(dev); - if (res) { - SAS_DPRINTK("expander %016llx discovery failed(0x%x)\n", - SAS_ADDR(dev->sas_addr), res); - goto out_err; - } - - sas_check_ex_subtractive_boundary(dev); - res = sas_check_parent_topology(dev); - if (res) - goto out_err; - return 0; -out_err: - sas_notify_lldd_dev_gone(dev); - return res; -} - -static int sas_ex_level_discovery(struct asd_sas_port *port, const int level) -{ - int res = 0; - struct domain_device *dev; - - list_for_each_entry(dev, &port->dev_list, dev_list_node) { - if (dev->dev_type == EDGE_DEV || - dev->dev_type == FANOUT_DEV) { - struct sas_expander_device *ex = - rphy_to_expander_device(dev->rphy); - - if (level == ex->level) - res = sas_ex_discover_devices(dev, -1); - else if (level > 0) - res = sas_ex_discover_devices(port->port_dev, -1); - - } - } - - return res; -} - -static int sas_ex_bfs_disc(struct asd_sas_port *port) -{ - int res; - int level; - - do { - level = port->disc.max_level; - res = sas_ex_level_discovery(port, level); - mb(); - } while (level < port->disc.max_level); - - return res; -} - -int sas_discover_root_expander(struct domain_device *dev) -{ - int res; - struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); - - res = sas_rphy_add(dev->rphy); - if (res) - goto out_err; - - ex->level = dev->port->disc.max_level; /* 0 */ - res = sas_discover_expander(dev); - if (res) - goto out_err2; - - sas_ex_bfs_disc(dev->port); - - return res; - -out_err2: - sas_rphy_remove(dev->rphy); -out_err: - return res; -} - -/* ---------- Domain revalidation ---------- */ - -static int sas_get_phy_discover(struct domain_device *dev, - int phy_id, struct smp_resp *disc_resp) -{ - int res; - u8 *disc_req; - - disc_req = alloc_smp_req(DISCOVER_REQ_SIZE); - if (!disc_req) - return -ENOMEM; - - disc_req[1] = SMP_DISCOVER; - disc_req[9] = phy_id; - - res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE, - disc_resp, DISCOVER_RESP_SIZE); - if (res) - goto out; - else if (disc_resp->result != SMP_RESP_FUNC_ACC) { - res = disc_resp->result; - goto out; - } -out: - kfree(disc_req); - return res; -} - -static int sas_get_phy_change_count(struct domain_device *dev, - int phy_id, int *pcc) -{ - int res; - struct smp_resp *disc_resp; - - disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); - if (!disc_resp) - return -ENOMEM; - - res = sas_get_phy_discover(dev, phy_id, disc_resp); - if (!res) - *pcc = disc_resp->disc.change_count; - - kfree(disc_resp); - return res; -} - -static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, - u8 *sas_addr, enum sas_dev_type *type) -{ - int res; - struct smp_resp *disc_resp; - struct discover_resp *dr; - - disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); - if (!disc_resp) - return -ENOMEM; - dr = &disc_resp->disc; - - res = sas_get_phy_discover(dev, phy_id, disc_resp); - if (res == 0) { - memcpy(sas_addr, disc_resp->disc.attached_sas_addr, 8); - *type = to_dev_type(dr); - if (*type == 0) - memset(sas_addr, 0, 8); - } - kfree(disc_resp); - return res; -} - -static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id, - int from_phy, bool update) -{ - struct expander_device *ex = &dev->ex_dev; - int res = 0; - int i; - - for (i = from_phy; i < ex->num_phys; i++) { - int phy_change_count = 0; - - res = sas_get_phy_change_count(dev, i, &phy_change_count); - switch (res) { - case SMP_RESP_PHY_VACANT: - case SMP_RESP_NO_PHY: - continue; - case SMP_RESP_FUNC_ACC: - break; - default: - return res; - } - - if (phy_change_count != ex->ex_phy[i].phy_change_count) { - if (update) - ex->ex_phy[i].phy_change_count = - phy_change_count; - *phy_id = i; - return 0; - } - } - return 0; -} - -static int sas_get_ex_change_count(struct domain_device *dev, int *ecc) -{ - int res; - u8 *rg_req; - struct smp_resp *rg_resp; - - rg_req = alloc_smp_req(RG_REQ_SIZE); - if (!rg_req) - return -ENOMEM; - - rg_resp = alloc_smp_resp(RG_RESP_SIZE); - if (!rg_resp) { - kfree(rg_req); - return -ENOMEM; - } - - rg_req[1] = SMP_REPORT_GENERAL; - - res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp, - RG_RESP_SIZE); - if (res) - goto out; - if (rg_resp->result != SMP_RESP_FUNC_ACC) { - res = rg_resp->result; - goto out; - } - - *ecc = be16_to_cpu(rg_resp->rg.change_count); -out: - kfree(rg_resp); - kfree(rg_req); - return res; -} -/** - * sas_find_bcast_dev - find the device issue BROADCAST(CHANGE). - * @dev:domain device to be detect. - * @src_dev: the device which originated BROADCAST(CHANGE). - * - * Add self-configuration expander suport. Suppose two expander cascading, - * when the first level expander is self-configuring, hotplug the disks in - * second level expander, BROADCAST(CHANGE) will not only be originated - * in the second level expander, but also be originated in the first level - * expander (see SAS protocol SAS 2r-14, 7.11 for detail), it is to say, - * expander changed count in two level expanders will all increment at least - * once, but the phy which chang count has changed is the source device which - * we concerned. - */ - -static int sas_find_bcast_dev(struct domain_device *dev, - struct domain_device **src_dev) -{ - struct expander_device *ex = &dev->ex_dev; - int ex_change_count = -1; - int phy_id = -1; - int res; - struct domain_device *ch; - - res = sas_get_ex_change_count(dev, &ex_change_count); - if (res) - goto out; - if (ex_change_count != -1 && ex_change_count != ex->ex_change_count) { - /* Just detect if this expander phys phy change count changed, - * in order to determine if this expander originate BROADCAST, - * and do not update phy change count field in our structure. - */ - res = sas_find_bcast_phy(dev, &phy_id, 0, false); - if (phy_id != -1) { - *src_dev = dev; - ex->ex_change_count = ex_change_count; - SAS_DPRINTK("Expander phy change count has changed\n"); - return res; - } else - SAS_DPRINTK("Expander phys DID NOT change\n"); - } - list_for_each_entry(ch, &ex->children, siblings) { - if (ch->dev_type == EDGE_DEV || ch->dev_type == FANOUT_DEV) { - res = sas_find_bcast_dev(ch, src_dev); - if (*src_dev) - return res; - } - } -out: - return res; -} - -static void sas_unregister_ex_tree(struct asd_sas_port *port, struct domain_device *dev) -{ - struct expander_device *ex = &dev->ex_dev; - struct domain_device *child, *n; - - list_for_each_entry_safe(child, n, &ex->children, siblings) { - set_bit(SAS_DEV_GONE, &child->state); - if (child->dev_type == EDGE_DEV || - child->dev_type == FANOUT_DEV) - sas_unregister_ex_tree(port, child); - else - sas_unregister_dev(port, child); - } - sas_unregister_dev(port, dev); -} - -static void sas_unregister_devs_sas_addr(struct domain_device *parent, - int phy_id, bool last) -{ - struct expander_device *ex_dev = &parent->ex_dev; - struct ex_phy *phy = &ex_dev->ex_phy[phy_id]; - struct domain_device *child, *n, *found = NULL; - if (last) { - list_for_each_entry_safe(child, n, - &ex_dev->children, siblings) { - if (SAS_ADDR(child->sas_addr) == - SAS_ADDR(phy->attached_sas_addr)) { - set_bit(SAS_DEV_GONE, &child->state); - if (child->dev_type == EDGE_DEV || - child->dev_type == FANOUT_DEV) - sas_unregister_ex_tree(parent->port, child); - else - sas_unregister_dev(parent->port, child); - found = child; - break; - } - } - sas_disable_routing(parent, phy->attached_sas_addr); - } - memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); - if (phy->port) { - sas_port_delete_phy(phy->port, phy->phy); - sas_device_set_phy(found, phy->port); - if (phy->port->num_phys == 0) - sas_port_delete(phy->port); - phy->port = NULL; - } -} - -static int sas_discover_bfs_by_root_level(struct domain_device *root, - const int level) -{ - struct expander_device *ex_root = &root->ex_dev; - struct domain_device *child; - int res = 0; - - list_for_each_entry(child, &ex_root->children, siblings) { - if (child->dev_type == EDGE_DEV || - child->dev_type == FANOUT_DEV) { - struct sas_expander_device *ex = - rphy_to_expander_device(child->rphy); - - if (level > ex->level) - res = sas_discover_bfs_by_root_level(child, - level); - else if (level == ex->level) - res = sas_ex_discover_devices(child, -1); - } - } - return res; -} - -static int sas_discover_bfs_by_root(struct domain_device *dev) -{ - int res; - struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); - int level = ex->level+1; - - res = sas_ex_discover_devices(dev, -1); - if (res) - goto out; - do { - res = sas_discover_bfs_by_root_level(dev, level); - mb(); - level += 1; - } while (level <= dev->port->disc.max_level); -out: - return res; -} - -static int sas_discover_new(struct domain_device *dev, int phy_id) -{ - struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id]; - struct domain_device *child; - bool found = false; - int res, i; - - SAS_DPRINTK("ex %016llx phy%d new device attached\n", - SAS_ADDR(dev->sas_addr), phy_id); - res = sas_ex_phy_discover(dev, phy_id); - if (res) - goto out; - /* to support the wide port inserted */ - for (i = 0; i < dev->ex_dev.num_phys; i++) { - struct ex_phy *ex_phy_temp = &dev->ex_dev.ex_phy[i]; - if (i == phy_id) - continue; - if (SAS_ADDR(ex_phy_temp->attached_sas_addr) == - SAS_ADDR(ex_phy->attached_sas_addr)) { - found = true; - break; - } - } - if (found) { - sas_ex_join_wide_port(dev, phy_id); - return 0; - } - res = sas_ex_discover_devices(dev, phy_id); - if (!res) - goto out; - list_for_each_entry(child, &dev->ex_dev.children, siblings) { - if (SAS_ADDR(child->sas_addr) == - SAS_ADDR(ex_phy->attached_sas_addr)) { - if (child->dev_type == EDGE_DEV || - child->dev_type == FANOUT_DEV) - res = sas_discover_bfs_by_root(child); - break; - } - } -out: - return res; -} - -static bool dev_type_flutter(enum sas_dev_type new, enum sas_dev_type old) -{ - if (old == new) - return true; - - /* treat device directed resets as flutter, if we went - * SAS_END_DEV to SATA_PENDING the link needs recovery - */ - if ((old == SATA_PENDING && new == SAS_END_DEV) || - (old == SAS_END_DEV && new == SATA_PENDING)) - return true; - - return false; -} - -static int sas_rediscover_dev(struct domain_device *dev, int phy_id, bool last) -{ - struct expander_device *ex = &dev->ex_dev; - struct ex_phy *phy = &ex->ex_phy[phy_id]; - enum sas_dev_type type = NO_DEVICE; - u8 sas_addr[8]; - int res; - - res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type); - switch (res) { - case SMP_RESP_NO_PHY: - phy->phy_state = PHY_NOT_PRESENT; - sas_unregister_devs_sas_addr(dev, phy_id, last); - return res; - case SMP_RESP_PHY_VACANT: - phy->phy_state = PHY_VACANT; - sas_unregister_devs_sas_addr(dev, phy_id, last); - return res; - case SMP_RESP_FUNC_ACC: - break; - } - - if (SAS_ADDR(sas_addr) == 0) { - phy->phy_state = PHY_EMPTY; - sas_unregister_devs_sas_addr(dev, phy_id, last); - return res; - } else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) && - dev_type_flutter(type, phy->attached_dev_type)) { - struct domain_device *ata_dev = sas_ex_to_ata(dev, phy_id); - char *action = ""; - - sas_ex_phy_discover(dev, phy_id); - - if (ata_dev && phy->attached_dev_type == SATA_PENDING) - action = ", needs recovery"; - SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter%s\n", - SAS_ADDR(dev->sas_addr), phy_id, action); - return res; - } - - /* delete the old link */ - if (SAS_ADDR(phy->attached_sas_addr) && - SAS_ADDR(sas_addr) != SAS_ADDR(phy->attached_sas_addr)) { - SAS_DPRINTK("ex %016llx phy 0x%x replace %016llx\n", - SAS_ADDR(dev->sas_addr), phy_id, - SAS_ADDR(phy->attached_sas_addr)); - sas_unregister_devs_sas_addr(dev, phy_id, last); - } - - return sas_discover_new(dev, phy_id); -} - -/** - * sas_rediscover - revalidate the domain. - * @dev:domain device to be detect. - * @phy_id: the phy id will be detected. - * - * NOTE: this process _must_ quit (return) as soon as any connection - * errors are encountered. Connection recovery is done elsewhere. - * Discover process only interrogates devices in order to discover the - * domain.For plugging out, we un-register the device only when it is - * the last phy in the port, for other phys in this port, we just delete it - * from the port.For inserting, we do discovery when it is the - * first phy,for other phys in this port, we add it to the port to - * forming the wide-port. - */ -static int sas_rediscover(struct domain_device *dev, const int phy_id) -{ - struct expander_device *ex = &dev->ex_dev; - struct ex_phy *changed_phy = &ex->ex_phy[phy_id]; - int res = 0; - int i; - bool last = true; /* is this the last phy of the port */ - - SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n", - SAS_ADDR(dev->sas_addr), phy_id); - - if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) { - for (i = 0; i < ex->num_phys; i++) { - struct ex_phy *phy = &ex->ex_phy[i]; - - if (i == phy_id) - continue; - if (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(changed_phy->attached_sas_addr)) { - SAS_DPRINTK("phy%d part of wide port with " - "phy%d\n", phy_id, i); - last = false; - break; - } - } - res = sas_rediscover_dev(dev, phy_id, last); - } else - res = sas_discover_new(dev, phy_id); - return res; -} - -/** - * sas_revalidate_domain -- revalidate the domain - * @port: port to the domain of interest - * - * NOTE: this process _must_ quit (return) as soon as any connection - * errors are encountered. Connection recovery is done elsewhere. - * Discover process only interrogates devices in order to discover the - * domain. - */ -int sas_ex_revalidate_domain(struct domain_device *port_dev) -{ - int res; - struct domain_device *dev = NULL; - - res = sas_find_bcast_dev(port_dev, &dev); - if (res) - goto out; - if (dev) { - struct expander_device *ex = &dev->ex_dev; - int i = 0, phy_id; - - do { - phy_id = -1; - res = sas_find_bcast_phy(dev, &phy_id, i, true); - if (phy_id == -1) - break; - res = sas_rediscover(dev, phy_id); - i = phy_id + 1; - } while (i < ex->num_phys); - } -out: - return res; -} - -int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, - struct request *req) -{ - struct domain_device *dev; - int ret, type; - struct request *rsp = req->next_rq; - - if (!rsp) { - printk("%s: space for a smp response is missing\n", - __func__); - return -EINVAL; - } - - /* no rphy means no smp target support (ie aic94xx host) */ - if (!rphy) - return sas_smp_host_handler(shost, req, rsp); - - type = rphy->identify.device_type; - - if (type != SAS_EDGE_EXPANDER_DEVICE && - type != SAS_FANOUT_EXPANDER_DEVICE) { - printk("%s: can we send a smp request to a device?\n", - __func__); - return -EINVAL; - } - - dev = sas_find_dev_by_rphy(rphy); - if (!dev) { - printk("%s: fail to find a domain_device?\n", __func__); - return -EINVAL; - } - - /* do we need to support multiple segments? */ - if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { - printk("%s: multiple segments req %u %u, rsp %u %u\n", - __func__, req->bio->bi_vcnt, blk_rq_bytes(req), - rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); - return -EINVAL; - } - - ret = smp_execute_task(dev, bio_data(req->bio), blk_rq_bytes(req), - bio_data(rsp->bio), blk_rq_bytes(rsp)); - if (ret > 0) { - /* positive number is the untransferred residual */ - rsp->resid_len = ret; - req->resid_len = 0; - ret = 0; - } else if (ret == 0) { - rsp->resid_len = 0; - req->resid_len = 0; - } - - return ret; -} diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_host_smp.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_host_smp.c deleted file mode 100644 index d2479257..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_host_smp.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Expander discovery and configuration - * - * Copyright (C) 2007 James E.J. Bottomley - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 only. - */ -#include -#include -#include -#include - -#include "sas_internal.h" - -#include -#include -#include "../scsi_sas_internal.h" - -static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data, - u8 phy_id) -{ - struct sas_phy *phy; - struct sas_rphy *rphy; - - if (phy_id >= sas_ha->num_phys) { - resp_data[2] = SMP_RESP_NO_PHY; - return; - } - resp_data[2] = SMP_RESP_FUNC_ACC; - - phy = sas_ha->sas_phy[phy_id]->phy; - resp_data[9] = phy_id; - resp_data[13] = phy->negotiated_linkrate; - memcpy(resp_data + 16, sas_ha->sas_addr, SAS_ADDR_SIZE); - memcpy(resp_data + 24, sas_ha->sas_phy[phy_id]->attached_sas_addr, - SAS_ADDR_SIZE); - resp_data[40] = (phy->minimum_linkrate << 4) | - phy->minimum_linkrate_hw; - resp_data[41] = (phy->maximum_linkrate << 4) | - phy->maximum_linkrate_hw; - - if (!sas_ha->sas_phy[phy_id]->port || - !sas_ha->sas_phy[phy_id]->port->port_dev) - return; - - rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy; - resp_data[12] = rphy->identify.device_type << 4; - resp_data[14] = rphy->identify.initiator_port_protocols; - resp_data[15] = rphy->identify.target_port_protocols; -} - -/** - * to_sas_gpio_gp_bit - given the gpio frame data find the byte/bit position of 'od' - * @od: od bit to find - * @data: incoming bitstream (from frame) - * @index: requested data register index (from frame) - * @count: total number of registers in the bitstream (from frame) - * @bit: bit position of 'od' in the returned byte - * - * returns NULL if 'od' is not in 'data' - * - * From SFF-8485 v0.7: - * "In GPIO_TX[1], bit 0 of byte 3 contains the first bit (i.e., OD0.0) - * and bit 7 of byte 0 contains the 32nd bit (i.e., OD10.1). - * - * In GPIO_TX[2], bit 0 of byte 3 contains the 33rd bit (i.e., OD10.2) - * and bit 7 of byte 0 contains the 64th bit (i.e., OD21.0)." - * - * The general-purpose (raw-bitstream) RX registers have the same layout - * although 'od' is renamed 'id' for 'input data'. - * - * SFF-8489 defines the behavior of the LEDs in response to the 'od' values. - */ -static u8 *to_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count, u8 *bit) -{ - unsigned int reg; - u8 byte; - - /* gp registers start at index 1 */ - if (index == 0) - return NULL; - - index--; /* make index 0-based */ - if (od < index * 32) - return NULL; - - od -= index * 32; - reg = od >> 5; - - if (reg >= count) - return NULL; - - od &= (1 << 5) - 1; - byte = 3 - (od >> 3); - *bit = od & ((1 << 3) - 1); - - return &data[reg * 4 + byte]; -} - -int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count) -{ - u8 *byte; - u8 bit; - - byte = to_sas_gpio_gp_bit(od, data, index, count, &bit); - if (!byte) - return -1; - - return (*byte >> bit) & 1; -} -EXPORT_SYMBOL(try_test_sas_gpio_gp_bit); - -static int sas_host_smp_write_gpio(struct sas_ha_struct *sas_ha, u8 *resp_data, - u8 reg_type, u8 reg_index, u8 reg_count, - u8 *req_data) -{ - struct sas_internal *i = to_sas_internal(sas_ha->core.shost->transportt); - int written; - - if (i->dft->lldd_write_gpio == NULL) { - resp_data[2] = SMP_RESP_FUNC_UNK; - return 0; - } - - written = i->dft->lldd_write_gpio(sas_ha, reg_type, reg_index, - reg_count, req_data); - - if (written < 0) { - resp_data[2] = SMP_RESP_FUNC_FAILED; - written = 0; - } else - resp_data[2] = SMP_RESP_FUNC_ACC; - - return written; -} - -static void sas_report_phy_sata(struct sas_ha_struct *sas_ha, u8 *resp_data, - u8 phy_id) -{ - struct sas_rphy *rphy; - struct dev_to_host_fis *fis; - int i; - - if (phy_id >= sas_ha->num_phys) { - resp_data[2] = SMP_RESP_NO_PHY; - return; - } - - resp_data[2] = SMP_RESP_PHY_NO_SATA; - - if (!sas_ha->sas_phy[phy_id]->port) - return; - - rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy; - fis = (struct dev_to_host_fis *) - sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd; - if (rphy->identify.target_port_protocols != SAS_PROTOCOL_SATA) - return; - - resp_data[2] = SMP_RESP_FUNC_ACC; - resp_data[9] = phy_id; - memcpy(resp_data + 16, sas_ha->sas_phy[phy_id]->attached_sas_addr, - SAS_ADDR_SIZE); - - /* check to see if we have a valid d2h fis */ - if (fis->fis_type != 0x34) - return; - - /* the d2h fis is required by the standard to be in LE format */ - for (i = 0; i < 20; i += 4) { - u8 *dst = resp_data + 24 + i, *src = - &sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd[i]; - dst[0] = src[3]; - dst[1] = src[2]; - dst[2] = src[1]; - dst[3] = src[0]; - } -} - -static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id, - u8 phy_op, enum sas_linkrate min, - enum sas_linkrate max, u8 *resp_data) -{ - struct sas_internal *i = - to_sas_internal(sas_ha->core.shost->transportt); - struct sas_phy_linkrates rates; - struct asd_sas_phy *asd_phy; - - if (phy_id >= sas_ha->num_phys) { - resp_data[2] = SMP_RESP_NO_PHY; - return; - } - - asd_phy = sas_ha->sas_phy[phy_id]; - switch (phy_op) { - case PHY_FUNC_NOP: - case PHY_FUNC_LINK_RESET: - case PHY_FUNC_HARD_RESET: - case PHY_FUNC_DISABLE: - case PHY_FUNC_CLEAR_ERROR_LOG: - case PHY_FUNC_CLEAR_AFFIL: - case PHY_FUNC_TX_SATA_PS_SIGNAL: - break; - - default: - resp_data[2] = SMP_RESP_PHY_UNK_OP; - return; - } - - rates.minimum_linkrate = min; - rates.maximum_linkrate = max; - - /* filter reset requests through libata eh */ - if (phy_op == PHY_FUNC_LINK_RESET && sas_try_ata_reset(asd_phy) == 0) { - resp_data[2] = SMP_RESP_FUNC_ACC; - return; - } - - if (i->dft->lldd_control_phy(asd_phy, phy_op, &rates)) - resp_data[2] = SMP_RESP_FUNC_FAILED; - else - resp_data[2] = SMP_RESP_FUNC_ACC; -} - -int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, - struct request *rsp) -{ - u8 *req_data = NULL, *resp_data = NULL, *buf; - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - int error = -EINVAL; - - /* eight is the minimum size for request and response frames */ - if (blk_rq_bytes(req) < 8 || blk_rq_bytes(rsp) < 8) - goto out; - - if (bio_offset(req->bio) + blk_rq_bytes(req) > PAGE_SIZE || - bio_offset(rsp->bio) + blk_rq_bytes(rsp) > PAGE_SIZE) { - shost_printk(KERN_ERR, shost, - "SMP request/response frame crosses page boundary"); - goto out; - } - - req_data = kzalloc(blk_rq_bytes(req), GFP_KERNEL); - - /* make sure frame can always be built ... we copy - * back only the requested length */ - resp_data = kzalloc(max(blk_rq_bytes(rsp), 128U), GFP_KERNEL); - - if (!req_data || !resp_data) { - error = -ENOMEM; - goto out; - } - - local_irq_disable(); - buf = kmap_atomic(bio_page(req->bio)); - memcpy(req_data, buf, blk_rq_bytes(req)); - kunmap_atomic(buf - bio_offset(req->bio)); - local_irq_enable(); - - if (req_data[0] != SMP_REQUEST) - goto out; - - /* always succeeds ... even if we can't process the request - * the result is in the response frame */ - error = 0; - - /* set up default don't know response */ - resp_data[0] = SMP_RESPONSE; - resp_data[1] = req_data[1]; - resp_data[2] = SMP_RESP_FUNC_UNK; - - switch (req_data[1]) { - case SMP_REPORT_GENERAL: - req->resid_len -= 8; - rsp->resid_len -= 32; - resp_data[2] = SMP_RESP_FUNC_ACC; - resp_data[9] = sas_ha->num_phys; - break; - - case SMP_REPORT_MANUF_INFO: - req->resid_len -= 8; - rsp->resid_len -= 64; - resp_data[2] = SMP_RESP_FUNC_ACC; - memcpy(resp_data + 12, shost->hostt->name, - SAS_EXPANDER_VENDOR_ID_LEN); - memcpy(resp_data + 20, "libsas virt phy", - SAS_EXPANDER_PRODUCT_ID_LEN); - break; - - case SMP_READ_GPIO_REG: - /* FIXME: need GPIO support in the transport class */ - break; - - case SMP_DISCOVER: - req->resid_len -= 16; - if ((int)req->resid_len < 0) { - req->resid_len = 0; - error = -EINVAL; - goto out; - } - rsp->resid_len -= 56; - sas_host_smp_discover(sas_ha, resp_data, req_data[9]); - break; - - case SMP_REPORT_PHY_ERR_LOG: - /* FIXME: could implement this with additional - * libsas callbacks providing the HW supports it */ - break; - - case SMP_REPORT_PHY_SATA: - req->resid_len -= 16; - if ((int)req->resid_len < 0) { - req->resid_len = 0; - error = -EINVAL; - goto out; - } - rsp->resid_len -= 60; - sas_report_phy_sata(sas_ha, resp_data, req_data[9]); - break; - - case SMP_REPORT_ROUTE_INFO: - /* Can't implement; hosts have no routes */ - break; - - case SMP_WRITE_GPIO_REG: { - /* SFF-8485 v0.7 */ - const int base_frame_size = 11; - int to_write = req_data[4]; - - if (blk_rq_bytes(req) < base_frame_size + to_write * 4 || - req->resid_len < base_frame_size + to_write * 4) { - resp_data[2] = SMP_RESP_INV_FRM_LEN; - break; - } - - to_write = sas_host_smp_write_gpio(sas_ha, resp_data, req_data[2], - req_data[3], to_write, &req_data[8]); - req->resid_len -= base_frame_size + to_write * 4; - rsp->resid_len -= 8; - break; - } - - case SMP_CONF_ROUTE_INFO: - /* Can't implement; hosts have no routes */ - break; - - case SMP_PHY_CONTROL: - req->resid_len -= 44; - if ((int)req->resid_len < 0) { - req->resid_len = 0; - error = -EINVAL; - goto out; - } - rsp->resid_len -= 8; - sas_phy_control(sas_ha, req_data[9], req_data[10], - req_data[32] >> 4, req_data[33] >> 4, - resp_data); - break; - - case SMP_PHY_TEST_FUNCTION: - /* FIXME: should this be implemented? */ - break; - - default: - /* probably a 2.0 function */ - break; - } - - local_irq_disable(); - buf = kmap_atomic(bio_page(rsp->bio)); - memcpy(buf, resp_data, blk_rq_bytes(rsp)); - flush_kernel_dcache_page(bio_page(rsp->bio)); - kunmap_atomic(buf - bio_offset(rsp->bio)); - local_irq_enable(); - - out: - kfree(req_data); - kfree(resp_data); - return error; -} diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_init.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_init.c deleted file mode 100644 index 10cb5ae3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_init.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Transport Layer initialization - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sas_internal.h" - -#include "../scsi_sas_internal.h" - -static struct kmem_cache *sas_task_cache; - -struct sas_task *sas_alloc_task(gfp_t flags) -{ - struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags); - - if (task) { - INIT_LIST_HEAD(&task->list); - spin_lock_init(&task->task_state_lock); - task->task_state_flags = SAS_TASK_STATE_PENDING; - init_timer(&task->timer); - init_completion(&task->completion); - } - - return task; -} -EXPORT_SYMBOL_GPL(sas_alloc_task); - -void sas_free_task(struct sas_task *task) -{ - if (task) { - BUG_ON(!list_empty(&task->list)); - kmem_cache_free(sas_task_cache, task); - } -} -EXPORT_SYMBOL_GPL(sas_free_task); - -/*------------ SAS addr hash -----------*/ -void sas_hash_addr(u8 *hashed, const u8 *sas_addr) -{ - const u32 poly = 0x00DB2777; - u32 r = 0; - int i; - - for (i = 0; i < 8; i++) { - int b; - for (b = 7; b >= 0; b--) { - r <<= 1; - if ((1 << b) & sas_addr[i]) { - if (!(r & 0x01000000)) - r ^= poly; - } else if (r & 0x01000000) - r ^= poly; - } - } - - hashed[0] = (r >> 16) & 0xFF; - hashed[1] = (r >> 8) & 0xFF ; - hashed[2] = r & 0xFF; -} - - -/* ---------- HA events ---------- */ - -void sas_hae_reset(struct work_struct *work) -{ - struct sas_ha_event *ev = to_sas_ha_event(work); - struct sas_ha_struct *ha = ev->ha; - - clear_bit(HAE_RESET, &ha->pending); -} - -int sas_register_ha(struct sas_ha_struct *sas_ha) -{ - int error = 0; - - mutex_init(&sas_ha->disco_mutex); - spin_lock_init(&sas_ha->phy_port_lock); - sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr); - - if (sas_ha->lldd_queue_size == 0) - sas_ha->lldd_queue_size = 1; - else if (sas_ha->lldd_queue_size == -1) - sas_ha->lldd_queue_size = 128; /* Sanity */ - - set_bit(SAS_HA_REGISTERED, &sas_ha->state); - spin_lock_init(&sas_ha->state_lock); - mutex_init(&sas_ha->drain_mutex); - INIT_LIST_HEAD(&sas_ha->defer_q); - - error = sas_register_phys(sas_ha); - if (error) { - printk(KERN_NOTICE "couldn't register sas phys:%d\n", error); - return error; - } - - error = sas_register_ports(sas_ha); - if (error) { - printk(KERN_NOTICE "couldn't register sas ports:%d\n", error); - goto Undo_phys; - } - - error = sas_init_events(sas_ha); - if (error) { - printk(KERN_NOTICE "couldn't start event thread:%d\n", error); - goto Undo_ports; - } - - if (sas_ha->lldd_max_execute_num > 1) { - error = sas_init_queue(sas_ha); - if (error) { - printk(KERN_NOTICE "couldn't start queue thread:%d, " - "running in direct mode\n", error); - sas_ha->lldd_max_execute_num = 1; - } - } - - INIT_LIST_HEAD(&sas_ha->eh_done_q); - INIT_LIST_HEAD(&sas_ha->eh_ata_q); - - return 0; - -Undo_ports: - sas_unregister_ports(sas_ha); -Undo_phys: - - return error; -} - -int sas_unregister_ha(struct sas_ha_struct *sas_ha) -{ - /* Set the state to unregistered to avoid further unchained - * events to be queued, and flush any in-progress drainers - */ - mutex_lock(&sas_ha->drain_mutex); - spin_lock_irq(&sas_ha->state_lock); - clear_bit(SAS_HA_REGISTERED, &sas_ha->state); - spin_unlock_irq(&sas_ha->state_lock); - __sas_drain_work(sas_ha); - mutex_unlock(&sas_ha->drain_mutex); - - sas_unregister_ports(sas_ha); - - /* flush unregistration work */ - mutex_lock(&sas_ha->drain_mutex); - __sas_drain_work(sas_ha); - mutex_unlock(&sas_ha->drain_mutex); - - if (sas_ha->lldd_max_execute_num > 1) { - sas_shutdown_queue(sas_ha); - sas_ha->lldd_max_execute_num = 1; - } - - return 0; -} - -static int sas_get_linkerrors(struct sas_phy *phy) -{ - if (scsi_is_sas_phy_local(phy)) { - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; - struct sas_internal *i = - to_sas_internal(sas_ha->core.shost->transportt); - - return i->dft->lldd_control_phy(asd_phy, PHY_FUNC_GET_EVENTS, NULL); - } - - return sas_smp_get_phy_events(phy); -} - -int sas_try_ata_reset(struct asd_sas_phy *asd_phy) -{ - struct domain_device *dev = NULL; - - /* try to route user requested link resets through libata */ - if (asd_phy->port) - dev = asd_phy->port->port_dev; - - /* validate that dev has been probed */ - if (dev) - dev = sas_find_dev_by_rphy(dev->rphy); - - if (dev && dev_is_sata(dev)) { - sas_ata_schedule_reset(dev); - sas_ata_wait_eh(dev); - return 0; - } - - return -ENODEV; -} - -/** - * transport_sas_phy_reset - reset a phy and permit libata to manage the link - * - * phy reset request via sysfs in host workqueue context so we know we - * can block on eh and safely traverse the domain_device topology - */ -static int transport_sas_phy_reset(struct sas_phy *phy, int hard_reset) -{ - enum phy_func reset_type; - - if (hard_reset) - reset_type = PHY_FUNC_HARD_RESET; - else - reset_type = PHY_FUNC_LINK_RESET; - - if (scsi_is_sas_phy_local(phy)) { - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; - struct sas_internal *i = - to_sas_internal(sas_ha->core.shost->transportt); - - if (!hard_reset && sas_try_ata_reset(asd_phy) == 0) - return 0; - return i->dft->lldd_control_phy(asd_phy, reset_type, NULL); - } else { - struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); - struct domain_device *ddev = sas_find_dev_by_rphy(rphy); - struct domain_device *ata_dev = sas_ex_to_ata(ddev, phy->number); - - if (ata_dev && !hard_reset) { - sas_ata_schedule_reset(ata_dev); - sas_ata_wait_eh(ata_dev); - return 0; - } else - return sas_smp_phy_control(ddev, phy->number, reset_type, NULL); - } -} - -static int sas_phy_enable(struct sas_phy *phy, int enable) -{ - int ret; - enum phy_func cmd; - - if (enable) - cmd = PHY_FUNC_LINK_RESET; - else - cmd = PHY_FUNC_DISABLE; - - if (scsi_is_sas_phy_local(phy)) { - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; - struct sas_internal *i = - to_sas_internal(sas_ha->core.shost->transportt); - - if (enable) - ret = transport_sas_phy_reset(phy, 0); - else - ret = i->dft->lldd_control_phy(asd_phy, cmd, NULL); - } else { - struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); - struct domain_device *ddev = sas_find_dev_by_rphy(rphy); - - if (enable) - ret = transport_sas_phy_reset(phy, 0); - else - ret = sas_smp_phy_control(ddev, phy->number, cmd, NULL); - } - return ret; -} - -int sas_phy_reset(struct sas_phy *phy, int hard_reset) -{ - int ret; - enum phy_func reset_type; - - if (!phy->enabled) - return -ENODEV; - - if (hard_reset) - reset_type = PHY_FUNC_HARD_RESET; - else - reset_type = PHY_FUNC_LINK_RESET; - - if (scsi_is_sas_phy_local(phy)) { - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; - struct sas_internal *i = - to_sas_internal(sas_ha->core.shost->transportt); - - ret = i->dft->lldd_control_phy(asd_phy, reset_type, NULL); - } else { - struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); - struct domain_device *ddev = sas_find_dev_by_rphy(rphy); - ret = sas_smp_phy_control(ddev, phy->number, reset_type, NULL); - } - return ret; -} - -int sas_set_phy_speed(struct sas_phy *phy, - struct sas_phy_linkrates *rates) -{ - int ret; - - if ((rates->minimum_linkrate && - rates->minimum_linkrate > phy->maximum_linkrate) || - (rates->maximum_linkrate && - rates->maximum_linkrate < phy->minimum_linkrate)) - return -EINVAL; - - if (rates->minimum_linkrate && - rates->minimum_linkrate < phy->minimum_linkrate_hw) - rates->minimum_linkrate = phy->minimum_linkrate_hw; - - if (rates->maximum_linkrate && - rates->maximum_linkrate > phy->maximum_linkrate_hw) - rates->maximum_linkrate = phy->maximum_linkrate_hw; - - if (scsi_is_sas_phy_local(phy)) { - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); - struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; - struct sas_internal *i = - to_sas_internal(sas_ha->core.shost->transportt); - - ret = i->dft->lldd_control_phy(asd_phy, PHY_FUNC_SET_LINK_RATE, - rates); - } else { - struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); - struct domain_device *ddev = sas_find_dev_by_rphy(rphy); - ret = sas_smp_phy_control(ddev, phy->number, - PHY_FUNC_LINK_RESET, rates); - - } - - return ret; -} - -static void sas_phy_release(struct sas_phy *phy) -{ - kfree(phy->hostdata); - phy->hostdata = NULL; -} - -static void phy_reset_work(struct work_struct *work) -{ - struct sas_phy_data *d = container_of(work, typeof(*d), reset_work.work); - - d->reset_result = transport_sas_phy_reset(d->phy, d->hard_reset); -} - -static void phy_enable_work(struct work_struct *work) -{ - struct sas_phy_data *d = container_of(work, typeof(*d), enable_work.work); - - d->enable_result = sas_phy_enable(d->phy, d->enable); -} - -static int sas_phy_setup(struct sas_phy *phy) -{ - struct sas_phy_data *d = kzalloc(sizeof(*d), GFP_KERNEL); - - if (!d) - return -ENOMEM; - - mutex_init(&d->event_lock); - INIT_SAS_WORK(&d->reset_work, phy_reset_work); - INIT_SAS_WORK(&d->enable_work, phy_enable_work); - d->phy = phy; - phy->hostdata = d; - - return 0; -} - -static int queue_phy_reset(struct sas_phy *phy, int hard_reset) -{ - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - struct sas_phy_data *d = phy->hostdata; - int rc; - - if (!d) - return -ENOMEM; - - /* libsas workqueue coordinates ata-eh reset with discovery */ - mutex_lock(&d->event_lock); - d->reset_result = 0; - d->hard_reset = hard_reset; - - spin_lock_irq(&ha->state_lock); - sas_queue_work(ha, &d->reset_work); - spin_unlock_irq(&ha->state_lock); - - rc = sas_drain_work(ha); - if (rc == 0) - rc = d->reset_result; - mutex_unlock(&d->event_lock); - - return rc; -} - -static int queue_phy_enable(struct sas_phy *phy, int enable) -{ - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - struct sas_phy_data *d = phy->hostdata; - int rc; - - if (!d) - return -ENOMEM; - - /* libsas workqueue coordinates ata-eh reset with discovery */ - mutex_lock(&d->event_lock); - d->enable_result = 0; - d->enable = enable; - - spin_lock_irq(&ha->state_lock); - sas_queue_work(ha, &d->enable_work); - spin_unlock_irq(&ha->state_lock); - - rc = sas_drain_work(ha); - if (rc == 0) - rc = d->enable_result; - mutex_unlock(&d->event_lock); - - return rc; -} - -static struct sas_function_template sft = { - .phy_enable = queue_phy_enable, - .phy_reset = queue_phy_reset, - .phy_setup = sas_phy_setup, - .phy_release = sas_phy_release, - .set_phy_speed = sas_set_phy_speed, - .get_linkerrors = sas_get_linkerrors, - .smp_handler = sas_smp_handler, -}; - -struct scsi_transport_template * -sas_domain_attach_transport(struct sas_domain_function_template *dft) -{ - struct scsi_transport_template *stt = sas_attach_transport(&sft); - struct sas_internal *i; - - if (!stt) - return stt; - - i = to_sas_internal(stt); - i->dft = dft; - stt->create_work_queue = 1; - stt->eh_timed_out = sas_scsi_timed_out; - stt->eh_strategy_handler = sas_scsi_recover_host; - - return stt; -} -EXPORT_SYMBOL_GPL(sas_domain_attach_transport); - - -void sas_domain_release_transport(struct scsi_transport_template *stt) -{ - sas_release_transport(stt); -} -EXPORT_SYMBOL_GPL(sas_domain_release_transport); - -/* ---------- SAS Class register/unregister ---------- */ - -static int __init sas_class_init(void) -{ - sas_task_cache = KMEM_CACHE(sas_task, SLAB_HWCACHE_ALIGN); - if (!sas_task_cache) - return -ENOMEM; - - return 0; -} - -static void __exit sas_class_exit(void) -{ - kmem_cache_destroy(sas_task_cache); -} - -MODULE_AUTHOR("Luben Tuikov "); -MODULE_DESCRIPTION("SAS Transport Layer"); -MODULE_LICENSE("GPL v2"); - -module_init(sas_class_init); -module_exit(sas_class_exit); - -EXPORT_SYMBOL_GPL(sas_register_ha); -EXPORT_SYMBOL_GPL(sas_unregister_ha); diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_internal.h b/ANDROID_3.4.5/drivers/scsi/libsas/sas_internal.h deleted file mode 100644 index 507e4cf1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_internal.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Serial Attached SCSI (SAS) class internal header file - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - */ - -#ifndef _SAS_INTERNAL_H_ -#define _SAS_INTERNAL_H_ - -#include -#include -#include -#include -#include - -#define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__) - -#define SAS_DPRINTK(fmt, ...) printk(KERN_DEBUG "sas: " fmt, ## __VA_ARGS__) - -#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble) -#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0) - -struct sas_phy_data { - /* let reset be performed in sas_queue_work() context */ - struct sas_phy *phy; - struct mutex event_lock; - int hard_reset; - int reset_result; - struct sas_work reset_work; - int enable; - int enable_result; - struct sas_work enable_work; -}; - -void sas_scsi_recover_host(struct Scsi_Host *shost); - -int sas_show_class(enum sas_class class, char *buf); -int sas_show_proto(enum sas_protocol proto, char *buf); -int sas_show_linkrate(enum sas_linkrate linkrate, char *buf); -int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf); - -int sas_register_phys(struct sas_ha_struct *sas_ha); -void sas_unregister_phys(struct sas_ha_struct *sas_ha); - -int sas_register_ports(struct sas_ha_struct *sas_ha); -void sas_unregister_ports(struct sas_ha_struct *sas_ha); - -enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *); - -int sas_init_queue(struct sas_ha_struct *sas_ha); -int sas_init_events(struct sas_ha_struct *sas_ha); -void sas_shutdown_queue(struct sas_ha_struct *sas_ha); -void sas_disable_revalidation(struct sas_ha_struct *ha); -void sas_enable_revalidation(struct sas_ha_struct *ha); -void __sas_drain_work(struct sas_ha_struct *ha); - -void sas_deform_port(struct asd_sas_phy *phy, int gone); - -void sas_porte_bytes_dmaed(struct work_struct *work); -void sas_porte_broadcast_rcvd(struct work_struct *work); -void sas_porte_link_reset_err(struct work_struct *work); -void sas_porte_timer_event(struct work_struct *work); -void sas_porte_hard_reset(struct work_struct *work); -void sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw); - -int sas_notify_lldd_dev_found(struct domain_device *); -void sas_notify_lldd_dev_gone(struct domain_device *); - -int sas_smp_phy_control(struct domain_device *dev, int phy_id, - enum phy_func phy_func, struct sas_phy_linkrates *); -int sas_smp_get_phy_events(struct sas_phy *phy); - -void sas_device_set_phy(struct domain_device *dev, struct sas_port *port); -struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); -struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); -int sas_ex_phy_discover(struct domain_device *dev, int single); -int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, - struct smp_resp *rps_resp); -int sas_try_ata_reset(struct asd_sas_phy *phy); -void sas_hae_reset(struct work_struct *work); - -void sas_free_device(struct kref *kref); - -#ifdef CONFIG_SCSI_SAS_HOST_SMP -extern int sas_smp_host_handler(struct Scsi_Host *shost, struct request *req, - struct request *rsp); -#else -static inline int sas_smp_host_handler(struct Scsi_Host *shost, - struct request *req, - struct request *rsp) -{ - shost_printk(KERN_ERR, shost, - "Cannot send SMP to a sas host (not enabled in CONFIG)\n"); - return -EINVAL; -} -#endif - -static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err) -{ - SAS_DPRINTK("%s: for %s device %16llx returned %d\n", - func, dev->parent ? "exp-attached" : - "direct-attached", - SAS_ADDR(dev->sas_addr), err); - sas_unregister_dev(dev->port, dev); -} - -static inline void sas_fill_in_rphy(struct domain_device *dev, - struct sas_rphy *rphy) -{ - rphy->identify.sas_address = SAS_ADDR(dev->sas_addr); - rphy->identify.initiator_port_protocols = dev->iproto; - rphy->identify.target_port_protocols = dev->tproto; - switch (dev->dev_type) { - case SATA_DEV: - /* FIXME: need sata device type */ - case SAS_END_DEV: - case SATA_PENDING: - rphy->identify.device_type = SAS_END_DEVICE; - break; - case EDGE_DEV: - rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE; - break; - case FANOUT_DEV: - rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE; - break; - default: - rphy->identify.device_type = SAS_PHY_UNUSED; - break; - } -} - -static inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_device *dev) -{ - struct sas_phy *phy = p->phy; - - if (dev) { - if (dev_is_sata(dev)) - phy->identify.device_type = SAS_END_DEVICE; - else - phy->identify.device_type = dev->dev_type; - phy->identify.target_port_protocols = dev->tproto; - } else { - phy->identify.device_type = SAS_PHY_UNUSED; - phy->identify.target_port_protocols = 0; - } -} - -static inline void sas_add_parent_port(struct domain_device *dev, int phy_id) -{ - struct expander_device *ex = &dev->ex_dev; - struct ex_phy *ex_phy = &ex->ex_phy[phy_id]; - - if (!ex->parent_port) { - ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id); - /* FIXME: error handling */ - BUG_ON(!ex->parent_port); - BUG_ON(sas_port_add(ex->parent_port)); - sas_port_mark_backlink(ex->parent_port); - } - sas_port_add_phy(ex->parent_port, ex_phy->phy); -} - -static inline struct domain_device *sas_alloc_device(void) -{ - struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL); - - if (dev) { - INIT_LIST_HEAD(&dev->siblings); - INIT_LIST_HEAD(&dev->dev_list_node); - INIT_LIST_HEAD(&dev->disco_list_node); - kref_init(&dev->kref); - spin_lock_init(&dev->done_lock); - } - return dev; -} - -static inline void sas_put_device(struct domain_device *dev) -{ - kref_put(&dev->kref, sas_free_device); -} - -#endif /* _SAS_INTERNAL_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_phy.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_phy.c deleted file mode 100644 index 521422e8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_phy.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Phy class - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "sas_internal.h" -#include -#include -#include -#include "../scsi_sas_internal.h" - -/* ---------- Phy events ---------- */ - -static void sas_phye_loss_of_signal(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - - clear_bit(PHYE_LOSS_OF_SIGNAL, &phy->phy_events_pending); - phy->error = 0; - sas_deform_port(phy, 1); -} - -static void sas_phye_oob_done(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - - clear_bit(PHYE_OOB_DONE, &phy->phy_events_pending); - phy->error = 0; -} - -static void sas_phye_oob_error(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - struct sas_ha_struct *sas_ha = phy->ha; - struct asd_sas_port *port = phy->port; - struct sas_internal *i = - to_sas_internal(sas_ha->core.shost->transportt); - - clear_bit(PHYE_OOB_ERROR, &phy->phy_events_pending); - - sas_deform_port(phy, 1); - - if (!port && phy->enabled && i->dft->lldd_control_phy) { - phy->error++; - switch (phy->error) { - case 1: - case 2: - i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET, - NULL); - break; - case 3: - default: - phy->error = 0; - phy->enabled = 0; - i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL); - break; - } - } -} - -static void sas_phye_spinup_hold(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - struct sas_ha_struct *sas_ha = phy->ha; - struct sas_internal *i = - to_sas_internal(sas_ha->core.shost->transportt); - - clear_bit(PHYE_SPINUP_HOLD, &phy->phy_events_pending); - - phy->error = 0; - i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL); -} - -/* ---------- Phy class registration ---------- */ - -int sas_register_phys(struct sas_ha_struct *sas_ha) -{ - int i; - - static const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = { - [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal, - [PHYE_OOB_DONE] = sas_phye_oob_done, - [PHYE_OOB_ERROR] = sas_phye_oob_error, - [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, - }; - - static const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = { - [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed, - [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd, - [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err, - [PORTE_TIMER_EVENT] = sas_porte_timer_event, - [PORTE_HARD_RESET] = sas_porte_hard_reset, - }; - - /* Now register the phys. */ - for (i = 0; i < sas_ha->num_phys; i++) { - int k; - struct asd_sas_phy *phy = sas_ha->sas_phy[i]; - - phy->error = 0; - INIT_LIST_HEAD(&phy->port_phy_el); - for (k = 0; k < PORT_NUM_EVENTS; k++) { - INIT_SAS_WORK(&phy->port_events[k].work, sas_port_event_fns[k]); - phy->port_events[k].phy = phy; - } - - for (k = 0; k < PHY_NUM_EVENTS; k++) { - INIT_SAS_WORK(&phy->phy_events[k].work, sas_phy_event_fns[k]); - phy->phy_events[k].phy = phy; - } - - phy->port = NULL; - phy->ha = sas_ha; - spin_lock_init(&phy->frame_rcvd_lock); - spin_lock_init(&phy->sas_prim_lock); - phy->frame_rcvd_size = 0; - - phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, i); - if (!phy->phy) - return -ENOMEM; - - phy->phy->identify.initiator_port_protocols = - phy->iproto; - phy->phy->identify.target_port_protocols = phy->tproto; - phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr); - phy->phy->identify.phy_identifier = i; - phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; - phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; - phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; - phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; - phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; - - sas_phy_add(phy->phy); - } - - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_port.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_port.c deleted file mode 100644 index e884a8c5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_port.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Serial Attached SCSI (SAS) Port class - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "sas_internal.h" - -#include -#include -#include "../scsi_sas_internal.h" - -static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy *phy) -{ - struct sas_ha_struct *sas_ha = phy->ha; - - if (memcmp(port->attached_sas_addr, phy->attached_sas_addr, - SAS_ADDR_SIZE) != 0 || (sas_ha->strict_wide_ports && - memcmp(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE) != 0)) - return false; - return true; -} - -/** - * sas_form_port -- add this phy to a port - * @phy: the phy of interest - * - * This function adds this phy to an existing port, thus creating a wide - * port, or it creates a port and adds the phy to the port. - */ -static void sas_form_port(struct asd_sas_phy *phy) -{ - int i; - struct sas_ha_struct *sas_ha = phy->ha; - struct asd_sas_port *port = phy->port; - struct sas_internal *si = - to_sas_internal(sas_ha->core.shost->transportt); - unsigned long flags; - - if (port) { - if (!phy_is_wideport_member(port, phy)) - sas_deform_port(phy, 0); - else { - SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", - __func__, phy->id, phy->port->id, - phy->port->num_phys); - return; - } - } - - /* see if the phy should be part of a wide port */ - spin_lock_irqsave(&sas_ha->phy_port_lock, flags); - for (i = 0; i < sas_ha->num_phys; i++) { - port = sas_ha->sas_port[i]; - spin_lock(&port->phy_list_lock); - if (*(u64 *) port->sas_addr && - phy_is_wideport_member(port, phy) && port->num_phys > 0) { - /* wide port */ - SAS_DPRINTK("phy%d matched wide port%d\n", phy->id, - port->id); - break; - } - spin_unlock(&port->phy_list_lock); - } - /* The phy does not match any existing port, create a new one */ - if (i == sas_ha->num_phys) { - for (i = 0; i < sas_ha->num_phys; i++) { - port = sas_ha->sas_port[i]; - spin_lock(&port->phy_list_lock); - if (*(u64 *)port->sas_addr == 0 - && port->num_phys == 0) { - memcpy(port->sas_addr, phy->sas_addr, - SAS_ADDR_SIZE); - break; - } - spin_unlock(&port->phy_list_lock); - } - } - - if (i >= sas_ha->num_phys) { - printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", - __func__); - spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); - return; - } - - /* add the phy to the port */ - list_add_tail(&phy->port_phy_el, &port->phy_list); - sas_phy_set_target(phy, port->port_dev); - phy->port = port; - port->num_phys++; - port->phy_mask |= (1U << phy->id); - - if (*(u64 *)port->attached_sas_addr == 0) { - port->class = phy->class; - memcpy(port->attached_sas_addr, phy->attached_sas_addr, - SAS_ADDR_SIZE); - port->iproto = phy->iproto; - port->tproto = phy->tproto; - port->oob_mode = phy->oob_mode; - port->linkrate = phy->linkrate; - } else - port->linkrate = max(port->linkrate, phy->linkrate); - spin_unlock(&port->phy_list_lock); - spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); - - if (!port->port) { - port->port = sas_port_alloc(phy->phy->dev.parent, port->id); - BUG_ON(!port->port); - sas_port_add(port->port); - } - sas_port_add_phy(port->port, phy->phy); - - SAS_DPRINTK("%s added to %s, phy_mask:0x%x (%16llx)\n", - dev_name(&phy->phy->dev), dev_name(&port->port->dev), - port->phy_mask, - SAS_ADDR(port->attached_sas_addr)); - - if (port->port_dev) - port->port_dev->pathways = port->num_phys; - - /* Tell the LLDD about this port formation. */ - if (si->dft->lldd_port_formed) - si->dft->lldd_port_formed(phy); - - sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); -} - -/** - * sas_deform_port -- remove this phy from the port it belongs to - * @phy: the phy of interest - * - * This is called when the physical link to the other phy has been - * lost (on this phy), in Event thread context. We cannot delay here. - */ -void sas_deform_port(struct asd_sas_phy *phy, int gone) -{ - struct sas_ha_struct *sas_ha = phy->ha; - struct asd_sas_port *port = phy->port; - struct sas_internal *si = - to_sas_internal(sas_ha->core.shost->transportt); - struct domain_device *dev; - unsigned long flags; - - if (!port) - return; /* done by a phy event */ - - dev = port->port_dev; - if (dev) - dev->pathways--; - - if (port->num_phys == 1) { - sas_unregister_domain_devices(port, gone); - sas_port_delete(port->port); - port->port = NULL; - } else { - sas_port_delete_phy(port->port, phy->phy); - sas_device_set_phy(dev, port->port); - } - - if (si->dft->lldd_port_deformed) - si->dft->lldd_port_deformed(phy); - - spin_lock_irqsave(&sas_ha->phy_port_lock, flags); - spin_lock(&port->phy_list_lock); - - list_del_init(&phy->port_phy_el); - sas_phy_set_target(phy, NULL); - phy->port = NULL; - port->num_phys--; - port->phy_mask &= ~(1U << phy->id); - - if (port->num_phys == 0) { - INIT_LIST_HEAD(&port->phy_list); - memset(port->sas_addr, 0, SAS_ADDR_SIZE); - memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE); - port->class = 0; - port->iproto = 0; - port->tproto = 0; - port->oob_mode = 0; - port->phy_mask = 0; - } - spin_unlock(&port->phy_list_lock); - spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags); - - return; -} - -/* ---------- SAS port events ---------- */ - -void sas_porte_bytes_dmaed(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - - clear_bit(PORTE_BYTES_DMAED, &phy->port_events_pending); - - sas_form_port(phy); -} - -void sas_porte_broadcast_rcvd(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - unsigned long flags; - u32 prim; - - clear_bit(PORTE_BROADCAST_RCVD, &phy->port_events_pending); - - spin_lock_irqsave(&phy->sas_prim_lock, flags); - prim = phy->sas_prim; - spin_unlock_irqrestore(&phy->sas_prim_lock, flags); - - SAS_DPRINTK("broadcast received: %d\n", prim); - sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN); -} - -void sas_porte_link_reset_err(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - - clear_bit(PORTE_LINK_RESET_ERR, &phy->port_events_pending); - - sas_deform_port(phy, 1); -} - -void sas_porte_timer_event(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - - clear_bit(PORTE_TIMER_EVENT, &phy->port_events_pending); - - sas_deform_port(phy, 1); -} - -void sas_porte_hard_reset(struct work_struct *work) -{ - struct asd_sas_event *ev = to_asd_sas_event(work); - struct asd_sas_phy *phy = ev->phy; - - clear_bit(PORTE_HARD_RESET, &phy->port_events_pending); - - sas_deform_port(phy, 1); -} - -/* ---------- SAS port registration ---------- */ - -static void sas_init_port(struct asd_sas_port *port, - struct sas_ha_struct *sas_ha, int i) -{ - memset(port, 0, sizeof(*port)); - port->id = i; - INIT_LIST_HEAD(&port->dev_list); - INIT_LIST_HEAD(&port->disco_list); - INIT_LIST_HEAD(&port->destroy_list); - spin_lock_init(&port->phy_list_lock); - INIT_LIST_HEAD(&port->phy_list); - port->ha = sas_ha; - - spin_lock_init(&port->dev_list_lock); -} - -int sas_register_ports(struct sas_ha_struct *sas_ha) -{ - int i; - - /* initialize the ports and discovery */ - for (i = 0; i < sas_ha->num_phys; i++) { - struct asd_sas_port *port = sas_ha->sas_port[i]; - - sas_init_port(port, sas_ha, i); - sas_init_disc(&port->disc, port); - } - return 0; -} - -void sas_unregister_ports(struct sas_ha_struct *sas_ha) -{ - int i; - - for (i = 0; i < sas_ha->num_phys; i++) - if (sas_ha->sas_phy[i]->port) - sas_deform_port(sas_ha->sas_phy[i], 0); - -} diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_scsi_host.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_scsi_host.c deleted file mode 100644 index f0b9b7bf..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_scsi_host.c +++ /dev/null @@ -1,1071 +0,0 @@ -/* - * Serial Attached SCSI (SAS) class SCSI Host glue. - * - * Copyright (C) 2005 Adaptec, Inc. All rights reserved. - * Copyright (C) 2005 Luben Tuikov - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - * - */ - -#include -#include -#include -#include - -#include "sas_internal.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include "../scsi_sas_internal.h" -#include "../scsi_transport_api.h" -#include "../scsi_priv.h" - -#include -#include -#include -#include -#include -#include - -/* record final status and free the task */ -static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task) -{ - struct task_status_struct *ts = &task->task_status; - int hs = 0, stat = 0; - - if (ts->resp == SAS_TASK_UNDELIVERED) { - /* transport error */ - hs = DID_NO_CONNECT; - } else { /* ts->resp == SAS_TASK_COMPLETE */ - /* task delivered, what happened afterwards? */ - switch (ts->stat) { - case SAS_DEV_NO_RESPONSE: - case SAS_INTERRUPTED: - case SAS_PHY_DOWN: - case SAS_NAK_R_ERR: - case SAS_OPEN_TO: - hs = DID_NO_CONNECT; - break; - case SAS_DATA_UNDERRUN: - scsi_set_resid(sc, ts->residual); - if (scsi_bufflen(sc) - scsi_get_resid(sc) < sc->underflow) - hs = DID_ERROR; - break; - case SAS_DATA_OVERRUN: - hs = DID_ERROR; - break; - case SAS_QUEUE_FULL: - hs = DID_SOFT_ERROR; /* retry */ - break; - case SAS_DEVICE_UNKNOWN: - hs = DID_BAD_TARGET; - break; - case SAS_SG_ERR: - hs = DID_PARITY; - break; - case SAS_OPEN_REJECT: - if (ts->open_rej_reason == SAS_OREJ_RSVD_RETRY) - hs = DID_SOFT_ERROR; /* retry */ - else - hs = DID_ERROR; - break; - case SAS_PROTO_RESPONSE: - SAS_DPRINTK("LLDD:%s sent SAS_PROTO_RESP for an SSP " - "task; please report this\n", - task->dev->port->ha->sas_ha_name); - break; - case SAS_ABORTED_TASK: - hs = DID_ABORT; - break; - case SAM_STAT_CHECK_CONDITION: - memcpy(sc->sense_buffer, ts->buf, - min(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); - stat = SAM_STAT_CHECK_CONDITION; - break; - default: - stat = ts->stat; - break; - } - } - - sc->result = (hs << 16) | stat; - ASSIGN_SAS_TASK(sc, NULL); - list_del_init(&task->list); - sas_free_task(task); -} - -static void sas_scsi_task_done(struct sas_task *task) -{ - struct scsi_cmnd *sc = task->uldd_task; - struct domain_device *dev = task->dev; - struct sas_ha_struct *ha = dev->port->ha; - unsigned long flags; - - spin_lock_irqsave(&dev->done_lock, flags); - if (test_bit(SAS_HA_FROZEN, &ha->state)) - task = NULL; - else - ASSIGN_SAS_TASK(sc, NULL); - spin_unlock_irqrestore(&dev->done_lock, flags); - - if (unlikely(!task)) { - /* task will be completed by the error handler */ - SAS_DPRINTK("task done but aborted\n"); - return; - } - - if (unlikely(!sc)) { - SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n"); - list_del_init(&task->list); - sas_free_task(task); - return; - } - - sas_end_task(sc, task); - sc->scsi_done(sc); -} - -static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, - struct domain_device *dev, - gfp_t gfp_flags) -{ - struct sas_task *task = sas_alloc_task(gfp_flags); - struct scsi_lun lun; - - if (!task) - return NULL; - - task->uldd_task = cmd; - ASSIGN_SAS_TASK(cmd, task); - - task->dev = dev; - task->task_proto = task->dev->tproto; /* BUG_ON(!SSP) */ - - task->ssp_task.retry_count = 1; - int_to_scsilun(cmd->device->lun, &lun); - memcpy(task->ssp_task.LUN, &lun.scsi_lun, 8); - task->ssp_task.task_attr = TASK_ATTR_SIMPLE; - memcpy(task->ssp_task.cdb, cmd->cmnd, 16); - - task->scatter = scsi_sglist(cmd); - task->num_scatter = scsi_sg_count(cmd); - task->total_xfer_len = scsi_bufflen(cmd); - task->data_dir = cmd->sc_data_direction; - - task->task_done = sas_scsi_task_done; - - return task; -} - -int sas_queue_up(struct sas_task *task) -{ - struct sas_ha_struct *sas_ha = task->dev->port->ha; - struct scsi_core *core = &sas_ha->core; - unsigned long flags; - LIST_HEAD(list); - - spin_lock_irqsave(&core->task_queue_lock, flags); - if (sas_ha->lldd_queue_size < core->task_queue_size + 1) { - spin_unlock_irqrestore(&core->task_queue_lock, flags); - return -SAS_QUEUE_FULL; - } - list_add_tail(&task->list, &core->task_queue); - core->task_queue_size += 1; - spin_unlock_irqrestore(&core->task_queue_lock, flags); - wake_up_process(core->queue_thread); - - return 0; -} - -int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) -{ - struct sas_internal *i = to_sas_internal(host->transportt); - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_ha_struct *sas_ha = dev->port->ha; - struct sas_task *task; - int res = 0; - - /* If the device fell off, no sense in issuing commands */ - if (test_bit(SAS_DEV_GONE, &dev->state)) { - cmd->result = DID_BAD_TARGET << 16; - goto out_done; - } - - if (dev_is_sata(dev)) { - spin_lock_irq(dev->sata_dev.ap->lock); - res = ata_sas_queuecmd(cmd, dev->sata_dev.ap); - spin_unlock_irq(dev->sata_dev.ap->lock); - return res; - } - - task = sas_create_task(cmd, dev, GFP_ATOMIC); - if (!task) - return SCSI_MLQUEUE_HOST_BUSY; - - /* Queue up, Direct Mode or Task Collector Mode. */ - if (sas_ha->lldd_max_execute_num < 2) - res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); - else - res = sas_queue_up(task); - - if (res) - goto out_free_task; - return 0; - -out_free_task: - SAS_DPRINTK("lldd_execute_task returned: %d\n", res); - ASSIGN_SAS_TASK(cmd, NULL); - sas_free_task(task); - if (res == -SAS_QUEUE_FULL) - cmd->result = DID_SOFT_ERROR << 16; /* retry */ - else - cmd->result = DID_ERROR << 16; -out_done: - cmd->scsi_done(cmd); - return 0; -} - -static void sas_eh_finish_cmd(struct scsi_cmnd *cmd) -{ - struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(cmd->device->host); - struct sas_task *task = TO_SAS_TASK(cmd); - - /* At this point, we only get called following an actual abort - * of the task, so we should be guaranteed not to be racing with - * any completions from the LLD. Task is freed after this. - */ - sas_end_task(cmd, task); - - /* now finish the command and move it on to the error - * handler done list, this also takes it off the - * error handler pending list. - */ - scsi_eh_finish_cmd(cmd, &sas_ha->eh_done_q); -} - -static void sas_eh_defer_cmd(struct scsi_cmnd *cmd) -{ - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_ha_struct *ha = dev->port->ha; - struct sas_task *task = TO_SAS_TASK(cmd); - - if (!dev_is_sata(dev)) { - sas_eh_finish_cmd(cmd); - return; - } - - /* report the timeout to libata */ - sas_end_task(cmd, task); - list_move_tail(&cmd->eh_entry, &ha->eh_ata_q); -} - -static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) -{ - struct scsi_cmnd *cmd, *n; - - list_for_each_entry_safe(cmd, n, error_q, eh_entry) { - if (cmd->device->sdev_target == my_cmd->device->sdev_target && - cmd->device->lun == my_cmd->device->lun) - sas_eh_defer_cmd(cmd); - } -} - -static void sas_scsi_clear_queue_I_T(struct list_head *error_q, - struct domain_device *dev) -{ - struct scsi_cmnd *cmd, *n; - - list_for_each_entry_safe(cmd, n, error_q, eh_entry) { - struct domain_device *x = cmd_to_domain_dev(cmd); - - if (x == dev) - sas_eh_finish_cmd(cmd); - } -} - -static void sas_scsi_clear_queue_port(struct list_head *error_q, - struct asd_sas_port *port) -{ - struct scsi_cmnd *cmd, *n; - - list_for_each_entry_safe(cmd, n, error_q, eh_entry) { - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct asd_sas_port *x = dev->port; - - if (x == port) - sas_eh_finish_cmd(cmd); - } -} - -enum task_disposition { - TASK_IS_DONE, - TASK_IS_ABORTED, - TASK_IS_AT_LU, - TASK_IS_NOT_AT_HA, - TASK_IS_NOT_AT_LU, - TASK_ABORT_FAILED, -}; - -static enum task_disposition sas_scsi_find_task(struct sas_task *task) -{ - struct sas_ha_struct *ha = task->dev->port->ha; - unsigned long flags; - int i, res; - struct sas_internal *si = - to_sas_internal(task->dev->port->ha->core.shost->transportt); - - if (ha->lldd_max_execute_num > 1) { - struct scsi_core *core = &ha->core; - struct sas_task *t, *n; - - mutex_lock(&core->task_queue_flush); - spin_lock_irqsave(&core->task_queue_lock, flags); - list_for_each_entry_safe(t, n, &core->task_queue, list) - if (task == t) { - list_del_init(&t->list); - break; - } - spin_unlock_irqrestore(&core->task_queue_lock, flags); - mutex_unlock(&core->task_queue_flush); - - if (task == t) - return TASK_IS_NOT_AT_HA; - } - - for (i = 0; i < 5; i++) { - SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task); - res = si->dft->lldd_abort_task(task); - - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - SAS_DPRINTK("%s: task 0x%p is done\n", __func__, - task); - return TASK_IS_DONE; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - - if (res == TMF_RESP_FUNC_COMPLETE) { - SAS_DPRINTK("%s: task 0x%p is aborted\n", - __func__, task); - return TASK_IS_ABORTED; - } else if (si->dft->lldd_query_task) { - SAS_DPRINTK("%s: querying task 0x%p\n", - __func__, task); - res = si->dft->lldd_query_task(task); - switch (res) { - case TMF_RESP_FUNC_SUCC: - SAS_DPRINTK("%s: task 0x%p at LU\n", - __func__, task); - return TASK_IS_AT_LU; - case TMF_RESP_FUNC_COMPLETE: - SAS_DPRINTK("%s: task 0x%p not at LU\n", - __func__, task); - return TASK_IS_NOT_AT_LU; - case TMF_RESP_FUNC_FAILED: - SAS_DPRINTK("%s: task 0x%p failed to abort\n", - __func__, task); - return TASK_ABORT_FAILED; - } - - } - } - return res; -} - -static int sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd) -{ - int res = TMF_RESP_FUNC_FAILED; - struct scsi_lun lun; - struct sas_internal *i = - to_sas_internal(dev->port->ha->core.shost->transportt); - - int_to_scsilun(cmd->device->lun, &lun); - - SAS_DPRINTK("eh: device %llx LUN %x has the task\n", - SAS_ADDR(dev->sas_addr), - cmd->device->lun); - - if (i->dft->lldd_abort_task_set) - res = i->dft->lldd_abort_task_set(dev, lun.scsi_lun); - - if (res == TMF_RESP_FUNC_FAILED) { - if (i->dft->lldd_clear_task_set) - res = i->dft->lldd_clear_task_set(dev, lun.scsi_lun); - } - - if (res == TMF_RESP_FUNC_FAILED) { - if (i->dft->lldd_lu_reset) - res = i->dft->lldd_lu_reset(dev, lun.scsi_lun); - } - - return res; -} - -static int sas_recover_I_T(struct domain_device *dev) -{ - int res = TMF_RESP_FUNC_FAILED; - struct sas_internal *i = - to_sas_internal(dev->port->ha->core.shost->transportt); - - SAS_DPRINTK("I_T nexus reset for dev %016llx\n", - SAS_ADDR(dev->sas_addr)); - - if (i->dft->lldd_I_T_nexus_reset) - res = i->dft->lldd_I_T_nexus_reset(dev); - - return res; -} - -/* take a reference on the last known good phy for this device */ -struct sas_phy *sas_get_local_phy(struct domain_device *dev) -{ - struct sas_ha_struct *ha = dev->port->ha; - struct sas_phy *phy; - unsigned long flags; - - /* a published domain device always has a valid phy, it may be - * stale, but it is never NULL - */ - BUG_ON(!dev->phy); - - spin_lock_irqsave(&ha->phy_port_lock, flags); - phy = dev->phy; - get_device(&phy->dev); - spin_unlock_irqrestore(&ha->phy_port_lock, flags); - - return phy; -} -EXPORT_SYMBOL_GPL(sas_get_local_phy); - -/* Attempt to send a LUN reset message to a device */ -int sas_eh_device_reset_handler(struct scsi_cmnd *cmd) -{ - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_internal *i = - to_sas_internal(dev->port->ha->core.shost->transportt); - struct scsi_lun lun; - int res; - - int_to_scsilun(cmd->device->lun, &lun); - - if (!i->dft->lldd_lu_reset) - return FAILED; - - res = i->dft->lldd_lu_reset(dev, lun.scsi_lun); - if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) - return SUCCESS; - - return FAILED; -} - -/* Attempt to send a phy (bus) reset */ -int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd) -{ - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_phy *phy = sas_get_local_phy(dev); - int res; - - res = sas_phy_reset(phy, 1); - if (res) - SAS_DPRINTK("Bus reset of %s failed 0x%x\n", - kobject_name(&phy->dev.kobj), - res); - sas_put_local_phy(phy); - - if (res == TMF_RESP_FUNC_SUCC || res == TMF_RESP_FUNC_COMPLETE) - return SUCCESS; - - return FAILED; -} - -/* Try to reset a device */ -static int try_to_reset_cmd_device(struct scsi_cmnd *cmd) -{ - int res; - struct Scsi_Host *shost = cmd->device->host; - - if (!shost->hostt->eh_device_reset_handler) - goto try_bus_reset; - - res = shost->hostt->eh_device_reset_handler(cmd); - if (res == SUCCESS) - return res; - -try_bus_reset: - if (shost->hostt->eh_bus_reset_handler) - return shost->hostt->eh_bus_reset_handler(cmd); - - return FAILED; -} - -static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *work_q) -{ - struct scsi_cmnd *cmd, *n; - enum task_disposition res = TASK_IS_DONE; - int tmf_resp, need_reset; - struct sas_internal *i = to_sas_internal(shost->transportt); - unsigned long flags; - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - LIST_HEAD(done); - - /* clean out any commands that won the completion vs eh race */ - list_for_each_entry_safe(cmd, n, work_q, eh_entry) { - struct domain_device *dev = cmd_to_domain_dev(cmd); - struct sas_task *task; - - spin_lock_irqsave(&dev->done_lock, flags); - /* by this point the lldd has either observed - * SAS_HA_FROZEN and is leaving the task alone, or has - * won the race with eh and decided to complete it - */ - task = TO_SAS_TASK(cmd); - spin_unlock_irqrestore(&dev->done_lock, flags); - - if (!task) - list_move_tail(&cmd->eh_entry, &done); - } - - Again: - list_for_each_entry_safe(cmd, n, work_q, eh_entry) { - struct sas_task *task = TO_SAS_TASK(cmd); - - list_del_init(&cmd->eh_entry); - - spin_lock_irqsave(&task->task_state_lock, flags); - need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET; - spin_unlock_irqrestore(&task->task_state_lock, flags); - - if (need_reset) { - SAS_DPRINTK("%s: task 0x%p requests reset\n", - __func__, task); - goto reset; - } - - SAS_DPRINTK("trying to find task 0x%p\n", task); - res = sas_scsi_find_task(task); - - cmd->eh_eflags = 0; - - switch (res) { - case TASK_IS_NOT_AT_HA: - SAS_DPRINTK("%s: task 0x%p is not at ha: %s\n", - __func__, task, - cmd->retries ? "retry" : "aborted"); - if (cmd->retries) - cmd->retries--; - sas_eh_finish_cmd(cmd); - continue; - case TASK_IS_DONE: - SAS_DPRINTK("%s: task 0x%p is done\n", __func__, - task); - sas_eh_defer_cmd(cmd); - continue; - case TASK_IS_ABORTED: - SAS_DPRINTK("%s: task 0x%p is aborted\n", - __func__, task); - sas_eh_defer_cmd(cmd); - continue; - case TASK_IS_AT_LU: - SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); - reset: - tmf_resp = sas_recover_lu(task->dev, cmd); - if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { - SAS_DPRINTK("dev %016llx LU %x is " - "recovered\n", - SAS_ADDR(task->dev), - cmd->device->lun); - sas_eh_defer_cmd(cmd); - sas_scsi_clear_queue_lu(work_q, cmd); - goto Again; - } - /* fallthrough */ - case TASK_IS_NOT_AT_LU: - case TASK_ABORT_FAILED: - SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", - task); - tmf_resp = sas_recover_I_T(task->dev); - if (tmf_resp == TMF_RESP_FUNC_COMPLETE || - tmf_resp == -ENODEV) { - struct domain_device *dev = task->dev; - SAS_DPRINTK("I_T %016llx recovered\n", - SAS_ADDR(task->dev->sas_addr)); - sas_eh_finish_cmd(cmd); - sas_scsi_clear_queue_I_T(work_q, dev); - goto Again; - } - /* Hammer time :-) */ - try_to_reset_cmd_device(cmd); - if (i->dft->lldd_clear_nexus_port) { - struct asd_sas_port *port = task->dev->port; - SAS_DPRINTK("clearing nexus for port:%d\n", - port->id); - res = i->dft->lldd_clear_nexus_port(port); - if (res == TMF_RESP_FUNC_COMPLETE) { - SAS_DPRINTK("clear nexus port:%d " - "succeeded\n", port->id); - sas_eh_finish_cmd(cmd); - sas_scsi_clear_queue_port(work_q, - port); - goto Again; - } - } - if (i->dft->lldd_clear_nexus_ha) { - SAS_DPRINTK("clear nexus ha\n"); - res = i->dft->lldd_clear_nexus_ha(ha); - if (res == TMF_RESP_FUNC_COMPLETE) { - SAS_DPRINTK("clear nexus ha " - "succeeded\n"); - sas_eh_finish_cmd(cmd); - goto clear_q; - } - } - /* If we are here -- this means that no amount - * of effort could recover from errors. Quite - * possibly the HA just disappeared. - */ - SAS_DPRINTK("error from device %llx, LUN %x " - "couldn't be recovered in any way\n", - SAS_ADDR(task->dev->sas_addr), - cmd->device->lun); - - sas_eh_finish_cmd(cmd); - goto clear_q; - } - } - out: - list_splice_tail(&done, work_q); - list_splice_tail_init(&ha->eh_ata_q, work_q); - return; - - clear_q: - SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__); - list_for_each_entry_safe(cmd, n, work_q, eh_entry) - sas_eh_finish_cmd(cmd); - goto out; -} - -void sas_scsi_recover_host(struct Scsi_Host *shost) -{ - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - unsigned long flags; - LIST_HEAD(eh_work_q); - - spin_lock_irqsave(shost->host_lock, flags); - list_splice_init(&shost->eh_cmd_q, &eh_work_q); - shost->host_eh_scheduled = 0; - spin_unlock_irqrestore(shost->host_lock, flags); - - SAS_DPRINTK("Enter %s busy: %d failed: %d\n", - __func__, shost->host_busy, shost->host_failed); - /* - * Deal with commands that still have SAS tasks (i.e. they didn't - * complete via the normal sas_task completion mechanism), - * SAS_HA_FROZEN gives eh dominion over all sas_task completion. - */ - set_bit(SAS_HA_FROZEN, &ha->state); - sas_eh_handle_sas_errors(shost, &eh_work_q); - clear_bit(SAS_HA_FROZEN, &ha->state); - if (list_empty(&eh_work_q)) - goto out; - - /* - * Now deal with SCSI commands that completed ok but have a an error - * code (and hopefully sense data) attached. This is roughly what - * scsi_unjam_host does, but we skip scsi_eh_abort_cmds because any - * command we see here has no sas_task and is thus unknown to the HA. - */ - sas_ata_eh(shost, &eh_work_q, &ha->eh_done_q); - if (!scsi_eh_get_sense(&eh_work_q, &ha->eh_done_q)) - scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q); - -out: - if (ha->lldd_max_execute_num > 1) - wake_up_process(ha->core.queue_thread); - - /* now link into libata eh --- if we have any ata devices */ - sas_ata_strategy_handler(shost); - - scsi_eh_flush_done_q(&ha->eh_done_q); - - SAS_DPRINTK("--- Exit %s: busy: %d failed: %d\n", - __func__, shost->host_busy, shost->host_failed); -} - -enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) -{ - scmd_printk(KERN_DEBUG, cmd, "command %p timed out\n", cmd); - - return BLK_EH_NOT_HANDLED; -} - -int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) -{ - struct domain_device *dev = sdev_to_domain_dev(sdev); - - if (dev_is_sata(dev)) - return ata_sas_scsi_ioctl(dev->sata_dev.ap, sdev, cmd, arg); - - return -EINVAL; -} - -struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) -{ - struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent); - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - struct domain_device *found_dev = NULL; - int i; - unsigned long flags; - - spin_lock_irqsave(&ha->phy_port_lock, flags); - for (i = 0; i < ha->num_phys; i++) { - struct asd_sas_port *port = ha->sas_port[i]; - struct domain_device *dev; - - spin_lock(&port->dev_list_lock); - list_for_each_entry(dev, &port->dev_list, dev_list_node) { - if (rphy == dev->rphy) { - found_dev = dev; - spin_unlock(&port->dev_list_lock); - goto found; - } - } - spin_unlock(&port->dev_list_lock); - } - found: - spin_unlock_irqrestore(&ha->phy_port_lock, flags); - - return found_dev; -} - -int sas_target_alloc(struct scsi_target *starget) -{ - struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent); - struct domain_device *found_dev = sas_find_dev_by_rphy(rphy); - - if (!found_dev) - return -ENODEV; - - kref_get(&found_dev->kref); - starget->hostdata = found_dev; - return 0; -} - -#define SAS_DEF_QD 256 - -int sas_slave_configure(struct scsi_device *scsi_dev) -{ - struct domain_device *dev = sdev_to_domain_dev(scsi_dev); - struct sas_ha_struct *sas_ha; - - BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE); - - if (dev_is_sata(dev)) { - ata_sas_slave_configure(scsi_dev, dev->sata_dev.ap); - return 0; - } - - sas_ha = dev->port->ha; - - sas_read_port_mode_page(scsi_dev); - - if (scsi_dev->tagged_supported) { - scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG); - scsi_activate_tcq(scsi_dev, SAS_DEF_QD); - } else { - SAS_DPRINTK("device %llx, LUN %x doesn't support " - "TCQ\n", SAS_ADDR(dev->sas_addr), - scsi_dev->lun); - scsi_dev->tagged_supported = 0; - scsi_set_tag_type(scsi_dev, 0); - scsi_deactivate_tcq(scsi_dev, 1); - } - - scsi_dev->allow_restart = 1; - - return 0; -} - -int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason) -{ - struct domain_device *dev = sdev_to_domain_dev(sdev); - - if (dev_is_sata(dev)) - return __ata_change_queue_depth(dev->sata_dev.ap, sdev, depth, - reason); - - switch (reason) { - case SCSI_QDEPTH_DEFAULT: - case SCSI_QDEPTH_RAMP_UP: - if (!sdev->tagged_supported) - depth = 1; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth); - break; - case SCSI_QDEPTH_QFULL: - scsi_track_queue_full(sdev, depth); - break; - default: - return -EOPNOTSUPP; - } - - return depth; -} - -int sas_change_queue_type(struct scsi_device *scsi_dev, int qt) -{ - struct domain_device *dev = sdev_to_domain_dev(scsi_dev); - - if (dev_is_sata(dev)) - return -EINVAL; - - if (!scsi_dev->tagged_supported) - return 0; - - scsi_deactivate_tcq(scsi_dev, 1); - - scsi_set_tag_type(scsi_dev, qt); - scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); - - return qt; -} - -int sas_bios_param(struct scsi_device *scsi_dev, - struct block_device *bdev, - sector_t capacity, int *hsc) -{ - hsc[0] = 255; - hsc[1] = 63; - sector_div(capacity, 255*63); - hsc[2] = capacity; - - return 0; -} - -/* ---------- Task Collector Thread implementation ---------- */ - -static void sas_queue(struct sas_ha_struct *sas_ha) -{ - struct scsi_core *core = &sas_ha->core; - unsigned long flags; - LIST_HEAD(q); - int can_queue; - int res; - struct sas_internal *i = to_sas_internal(core->shost->transportt); - - mutex_lock(&core->task_queue_flush); - spin_lock_irqsave(&core->task_queue_lock, flags); - while (!kthread_should_stop() && - !list_empty(&core->task_queue) && - !test_bit(SAS_HA_FROZEN, &sas_ha->state)) { - - can_queue = sas_ha->lldd_queue_size - core->task_queue_size; - if (can_queue >= 0) { - can_queue = core->task_queue_size; - list_splice_init(&core->task_queue, &q); - } else { - struct list_head *a, *n; - - can_queue = sas_ha->lldd_queue_size; - list_for_each_safe(a, n, &core->task_queue) { - list_move_tail(a, &q); - if (--can_queue == 0) - break; - } - can_queue = sas_ha->lldd_queue_size; - } - core->task_queue_size -= can_queue; - spin_unlock_irqrestore(&core->task_queue_lock, flags); - { - struct sas_task *task = list_entry(q.next, - struct sas_task, - list); - list_del_init(&q); - res = i->dft->lldd_execute_task(task, can_queue, - GFP_KERNEL); - if (unlikely(res)) - __list_add(&q, task->list.prev, &task->list); - } - spin_lock_irqsave(&core->task_queue_lock, flags); - if (res) { - list_splice_init(&q, &core->task_queue); /*at head*/ - core->task_queue_size += can_queue; - } - } - spin_unlock_irqrestore(&core->task_queue_lock, flags); - mutex_unlock(&core->task_queue_flush); -} - -/** - * sas_queue_thread -- The Task Collector thread - * @_sas_ha: pointer to struct sas_ha - */ -static int sas_queue_thread(void *_sas_ha) -{ - struct sas_ha_struct *sas_ha = _sas_ha; - - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - schedule(); - sas_queue(sas_ha); - if (kthread_should_stop()) - break; - } - - return 0; -} - -int sas_init_queue(struct sas_ha_struct *sas_ha) -{ - struct scsi_core *core = &sas_ha->core; - - spin_lock_init(&core->task_queue_lock); - mutex_init(&core->task_queue_flush); - core->task_queue_size = 0; - INIT_LIST_HEAD(&core->task_queue); - - core->queue_thread = kthread_run(sas_queue_thread, sas_ha, - "sas_queue_%d", core->shost->host_no); - if (IS_ERR(core->queue_thread)) - return PTR_ERR(core->queue_thread); - return 0; -} - -void sas_shutdown_queue(struct sas_ha_struct *sas_ha) -{ - unsigned long flags; - struct scsi_core *core = &sas_ha->core; - struct sas_task *task, *n; - - kthread_stop(core->queue_thread); - - if (!list_empty(&core->task_queue)) - SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n", - SAS_ADDR(sas_ha->sas_addr)); - - spin_lock_irqsave(&core->task_queue_lock, flags); - list_for_each_entry_safe(task, n, &core->task_queue, list) { - struct scsi_cmnd *cmd = task->uldd_task; - - list_del_init(&task->list); - - ASSIGN_SAS_TASK(cmd, NULL); - sas_free_task(task); - cmd->result = DID_ABORT << 16; - cmd->scsi_done(cmd); - } - spin_unlock_irqrestore(&core->task_queue_lock, flags); -} - -/* - * Tell an upper layer that it needs to initiate an abort for a given task. - * This should only ever be called by an LLDD. - */ -void sas_task_abort(struct sas_task *task) -{ - struct scsi_cmnd *sc = task->uldd_task; - - /* Escape for libsas internal commands */ - if (!sc) { - if (!del_timer(&task->timer)) - return; - task->timer.function(task->timer.data); - return; - } - - if (dev_is_sata(task->dev)) { - sas_ata_task_abort(task); - } else { - struct request_queue *q = sc->device->request_queue; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - blk_abort_request(sc->request); - spin_unlock_irqrestore(q->queue_lock, flags); - scsi_schedule_eh(sc->device->host); - } -} - -void sas_target_destroy(struct scsi_target *starget) -{ - struct domain_device *found_dev = starget->hostdata; - - if (!found_dev) - return; - - starget->hostdata = NULL; - sas_put_device(found_dev); -} - -static void sas_parse_addr(u8 *sas_addr, const char *p) -{ - int i; - for (i = 0; i < SAS_ADDR_SIZE; i++) { - u8 h, l; - if (!*p) - break; - h = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10; - p++; - l = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10; - p++; - sas_addr[i] = (h<<4) | l; - } -} - -#define SAS_STRING_ADDR_SIZE 16 - -int sas_request_addr(struct Scsi_Host *shost, u8 *addr) -{ - int res; - const struct firmware *fw; - - res = request_firmware(&fw, "sas_addr", &shost->shost_gendev); - if (res) - return res; - - if (fw->size < SAS_STRING_ADDR_SIZE) { - res = -ENODEV; - goto out; - } - - sas_parse_addr(addr, fw->data); - -out: - release_firmware(fw); - return res; -} -EXPORT_SYMBOL_GPL(sas_request_addr); - -EXPORT_SYMBOL_GPL(sas_queuecommand); -EXPORT_SYMBOL_GPL(sas_target_alloc); -EXPORT_SYMBOL_GPL(sas_slave_configure); -EXPORT_SYMBOL_GPL(sas_change_queue_depth); -EXPORT_SYMBOL_GPL(sas_change_queue_type); -EXPORT_SYMBOL_GPL(sas_bios_param); -EXPORT_SYMBOL_GPL(sas_task_abort); -EXPORT_SYMBOL_GPL(sas_phy_reset); -EXPORT_SYMBOL_GPL(sas_eh_device_reset_handler); -EXPORT_SYMBOL_GPL(sas_eh_bus_reset_handler); -EXPORT_SYMBOL_GPL(sas_target_destroy); -EXPORT_SYMBOL_GPL(sas_ioctl); diff --git a/ANDROID_3.4.5/drivers/scsi/libsas/sas_task.c b/ANDROID_3.4.5/drivers/scsi/libsas/sas_task.c deleted file mode 100644 index a78e5bd3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsas/sas_task.c +++ /dev/null @@ -1,37 +0,0 @@ -#include -#include -#include -#include - -/* fill task_status_struct based on SSP response frame */ -void sas_ssp_task_response(struct device *dev, struct sas_task *task, - struct ssp_response_iu *iu) -{ - struct task_status_struct *tstat = &task->task_status; - - tstat->resp = SAS_TASK_COMPLETE; - - if (iu->datapres == 0) - tstat->stat = iu->status; - else if (iu->datapres == 1) - tstat->stat = iu->resp_data[3]; - else if (iu->datapres == 2) { - tstat->stat = SAM_STAT_CHECK_CONDITION; - tstat->buf_valid_size = - min_t(int, SAS_STATUS_BUF_SIZE, - be32_to_cpu(iu->sense_data_len)); - memcpy(tstat->buf, iu->sense_data, tstat->buf_valid_size); - - if (iu->status != SAM_STAT_CHECK_CONDITION) - dev_printk(KERN_WARNING, dev, - "dev %llx sent sense data, but " - "stat(%x) is not CHECK CONDITION\n", - SAS_ADDR(task->dev->sas_addr), - iu->status); - } - else - /* when datapres contains corrupt/unknown value... */ - tstat->stat = SAM_STAT_CHECK_CONDITION; -} -EXPORT_SYMBOL_GPL(sas_ssp_task_response); - diff --git a/ANDROID_3.4.5/drivers/scsi/libsrp.c b/ANDROID_3.4.5/drivers/scsi/libsrp.c deleted file mode 100644 index 0707ecdb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/libsrp.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * SCSI RDMA Protocol lib functions - * - * Copyright (C) 2006 FUJITA Tomonori - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -enum srp_task_attributes { - SRP_SIMPLE_TASK = 0, - SRP_HEAD_TASK = 1, - SRP_ORDERED_TASK = 2, - SRP_ACA_TASK = 4 -}; - -/* tmp - will replace with SCSI logging stuff */ -#define eprintk(fmt, args...) \ -do { \ - printk("%s(%d) " fmt, __func__, __LINE__, ##args); \ -} while (0) -/* #define dprintk eprintk */ -#define dprintk(fmt, args...) - -static int srp_iu_pool_alloc(struct srp_queue *q, size_t max, - struct srp_buf **ring) -{ - int i; - struct iu_entry *iue; - - q->pool = kcalloc(max, sizeof(struct iu_entry *), GFP_KERNEL); - if (!q->pool) - return -ENOMEM; - q->items = kcalloc(max, sizeof(struct iu_entry), GFP_KERNEL); - if (!q->items) - goto free_pool; - - spin_lock_init(&q->lock); - kfifo_init(&q->queue, (void *) q->pool, max * sizeof(void *)); - - for (i = 0, iue = q->items; i < max; i++) { - kfifo_in(&q->queue, (void *) &iue, sizeof(void *)); - iue->sbuf = ring[i]; - iue++; - } - return 0; - - kfree(q->items); -free_pool: - kfree(q->pool); - return -ENOMEM; -} - -static void srp_iu_pool_free(struct srp_queue *q) -{ - kfree(q->items); - kfree(q->pool); -} - -static struct srp_buf **srp_ring_alloc(struct device *dev, - size_t max, size_t size) -{ - int i; - struct srp_buf **ring; - - ring = kcalloc(max, sizeof(struct srp_buf *), GFP_KERNEL); - if (!ring) - return NULL; - - for (i = 0; i < max; i++) { - ring[i] = kzalloc(sizeof(struct srp_buf), GFP_KERNEL); - if (!ring[i]) - goto out; - ring[i]->buf = dma_alloc_coherent(dev, size, &ring[i]->dma, - GFP_KERNEL); - if (!ring[i]->buf) - goto out; - } - return ring; - -out: - for (i = 0; i < max && ring[i]; i++) { - if (ring[i]->buf) - dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma); - kfree(ring[i]); - } - kfree(ring); - - return NULL; -} - -static void srp_ring_free(struct device *dev, struct srp_buf **ring, size_t max, - size_t size) -{ - int i; - - for (i = 0; i < max; i++) { - dma_free_coherent(dev, size, ring[i]->buf, ring[i]->dma); - kfree(ring[i]); - } - kfree(ring); -} - -int srp_target_alloc(struct srp_target *target, struct device *dev, - size_t nr, size_t iu_size) -{ - int err; - - spin_lock_init(&target->lock); - INIT_LIST_HEAD(&target->cmd_queue); - - target->dev = dev; - dev_set_drvdata(target->dev, target); - - target->srp_iu_size = iu_size; - target->rx_ring_size = nr; - target->rx_ring = srp_ring_alloc(target->dev, nr, iu_size); - if (!target->rx_ring) - return -ENOMEM; - err = srp_iu_pool_alloc(&target->iu_queue, nr, target->rx_ring); - if (err) - goto free_ring; - - return 0; - -free_ring: - srp_ring_free(target->dev, target->rx_ring, nr, iu_size); - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(srp_target_alloc); - -void srp_target_free(struct srp_target *target) -{ - srp_ring_free(target->dev, target->rx_ring, target->rx_ring_size, - target->srp_iu_size); - srp_iu_pool_free(&target->iu_queue); -} -EXPORT_SYMBOL_GPL(srp_target_free); - -struct iu_entry *srp_iu_get(struct srp_target *target) -{ - struct iu_entry *iue = NULL; - - if (kfifo_out_locked(&target->iu_queue.queue, (void *) &iue, - sizeof(void *), &target->iu_queue.lock) != sizeof(void *)) { - WARN_ONCE(1, "unexpected fifo state"); - return NULL; - } - if (!iue) - return iue; - iue->target = target; - INIT_LIST_HEAD(&iue->ilist); - iue->flags = 0; - return iue; -} -EXPORT_SYMBOL_GPL(srp_iu_get); - -void srp_iu_put(struct iu_entry *iue) -{ - kfifo_in_locked(&iue->target->iu_queue.queue, (void *) &iue, - sizeof(void *), &iue->target->iu_queue.lock); -} -EXPORT_SYMBOL_GPL(srp_iu_put); - -static int srp_direct_data(struct scsi_cmnd *sc, struct srp_direct_buf *md, - enum dma_data_direction dir, srp_rdma_t rdma_io, - int dma_map, int ext_desc) -{ - struct iu_entry *iue = NULL; - struct scatterlist *sg = NULL; - int err, nsg = 0, len; - - if (dma_map) { - iue = (struct iu_entry *) sc->SCp.ptr; - sg = scsi_sglist(sc); - - dprintk("%p %u %u %d\n", iue, scsi_bufflen(sc), - md->len, scsi_sg_count(sc)); - - nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc), - DMA_BIDIRECTIONAL); - if (!nsg) { - printk("fail to map %p %d\n", iue, scsi_sg_count(sc)); - return 0; - } - len = min(scsi_bufflen(sc), md->len); - } else - len = md->len; - - err = rdma_io(sc, sg, nsg, md, 1, dir, len); - - if (dma_map) - dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); - - return err; -} - -static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, - struct srp_indirect_buf *id, - enum dma_data_direction dir, srp_rdma_t rdma_io, - int dma_map, int ext_desc) -{ - struct iu_entry *iue = NULL; - struct srp_direct_buf *md = NULL; - struct scatterlist dummy, *sg = NULL; - dma_addr_t token = 0; - int err = 0; - int nmd, nsg = 0, len; - - if (dma_map || ext_desc) { - iue = (struct iu_entry *) sc->SCp.ptr; - sg = scsi_sglist(sc); - - dprintk("%p %u %u %d %d\n", - iue, scsi_bufflen(sc), id->len, - cmd->data_in_desc_cnt, cmd->data_out_desc_cnt); - } - - nmd = id->table_desc.len / sizeof(struct srp_direct_buf); - - if ((dir == DMA_FROM_DEVICE && nmd == cmd->data_in_desc_cnt) || - (dir == DMA_TO_DEVICE && nmd == cmd->data_out_desc_cnt)) { - md = &id->desc_list[0]; - goto rdma; - } - - if (ext_desc && dma_map) { - md = dma_alloc_coherent(iue->target->dev, id->table_desc.len, - &token, GFP_KERNEL); - if (!md) { - eprintk("Can't get dma memory %u\n", id->table_desc.len); - return -ENOMEM; - } - - sg_init_one(&dummy, md, id->table_desc.len); - sg_dma_address(&dummy) = token; - sg_dma_len(&dummy) = id->table_desc.len; - err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE, - id->table_desc.len); - if (err) { - eprintk("Error copying indirect table %d\n", err); - goto free_mem; - } - } else { - eprintk("This command uses external indirect buffer\n"); - return -EINVAL; - } - -rdma: - if (dma_map) { - nsg = dma_map_sg(iue->target->dev, sg, scsi_sg_count(sc), - DMA_BIDIRECTIONAL); - if (!nsg) { - eprintk("fail to map %p %d\n", iue, scsi_sg_count(sc)); - err = -EIO; - goto free_mem; - } - len = min(scsi_bufflen(sc), id->len); - } else - len = id->len; - - err = rdma_io(sc, sg, nsg, md, nmd, dir, len); - - if (dma_map) - dma_unmap_sg(iue->target->dev, sg, nsg, DMA_BIDIRECTIONAL); - -free_mem: - if (token && dma_map) - dma_free_coherent(iue->target->dev, id->table_desc.len, md, token); - - return err; -} - -static int data_out_desc_size(struct srp_cmd *cmd) -{ - int size = 0; - u8 fmt = cmd->buf_fmt >> 4; - - switch (fmt) { - case SRP_NO_DATA_DESC: - break; - case SRP_DATA_DESC_DIRECT: - size = sizeof(struct srp_direct_buf); - break; - case SRP_DATA_DESC_INDIRECT: - size = sizeof(struct srp_indirect_buf) + - sizeof(struct srp_direct_buf) * cmd->data_out_desc_cnt; - break; - default: - eprintk("client error. Invalid data_out_format %x\n", fmt); - break; - } - return size; -} - -/* - * TODO: this can be called multiple times for a single command if it - * has very long data. - */ -int srp_transfer_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, - srp_rdma_t rdma_io, int dma_map, int ext_desc) -{ - struct srp_direct_buf *md; - struct srp_indirect_buf *id; - enum dma_data_direction dir; - int offset, err = 0; - u8 format; - - offset = cmd->add_cdb_len & ~3; - - dir = srp_cmd_direction(cmd); - if (dir == DMA_FROM_DEVICE) - offset += data_out_desc_size(cmd); - - if (dir == DMA_TO_DEVICE) - format = cmd->buf_fmt >> 4; - else - format = cmd->buf_fmt & ((1U << 4) - 1); - - switch (format) { - case SRP_NO_DATA_DESC: - break; - case SRP_DATA_DESC_DIRECT: - md = (struct srp_direct_buf *) - (cmd->add_data + offset); - err = srp_direct_data(sc, md, dir, rdma_io, dma_map, ext_desc); - break; - case SRP_DATA_DESC_INDIRECT: - id = (struct srp_indirect_buf *) - (cmd->add_data + offset); - err = srp_indirect_data(sc, cmd, id, dir, rdma_io, dma_map, - ext_desc); - break; - default: - eprintk("Unknown format %d %x\n", dir, format); - err = -EINVAL; - } - - return err; -} -EXPORT_SYMBOL_GPL(srp_transfer_data); - -static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir) -{ - struct srp_direct_buf *md; - struct srp_indirect_buf *id; - int len = 0, offset = cmd->add_cdb_len & ~3; - u8 fmt; - - if (dir == DMA_TO_DEVICE) - fmt = cmd->buf_fmt >> 4; - else { - fmt = cmd->buf_fmt & ((1U << 4) - 1); - offset += data_out_desc_size(cmd); - } - - switch (fmt) { - case SRP_NO_DATA_DESC: - break; - case SRP_DATA_DESC_DIRECT: - md = (struct srp_direct_buf *) (cmd->add_data + offset); - len = md->len; - break; - case SRP_DATA_DESC_INDIRECT: - id = (struct srp_indirect_buf *) (cmd->add_data + offset); - len = id->len; - break; - default: - eprintk("invalid data format %x\n", fmt); - break; - } - return len; -} - -int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, - u64 itn_id, u64 addr) -{ - enum dma_data_direction dir; - struct scsi_cmnd *sc; - int tag, len, err; - - switch (cmd->task_attr) { - case SRP_SIMPLE_TASK: - tag = MSG_SIMPLE_TAG; - break; - case SRP_ORDERED_TASK: - tag = MSG_ORDERED_TAG; - break; - case SRP_HEAD_TASK: - tag = MSG_HEAD_TAG; - break; - default: - eprintk("Task attribute %d not supported\n", cmd->task_attr); - tag = MSG_ORDERED_TAG; - } - - dir = srp_cmd_direction(cmd); - len = vscsis_data_length(cmd, dir); - - dprintk("%p %x %lx %d %d %d %llx\n", info, cmd->cdb[0], - cmd->lun, dir, len, tag, (unsigned long long) cmd->tag); - - sc = scsi_host_get_command(shost, dir, GFP_KERNEL); - if (!sc) - return -ENOMEM; - - sc->SCp.ptr = info; - memcpy(sc->cmnd, cmd->cdb, MAX_COMMAND_SIZE); - sc->sdb.length = len; - sc->sdb.table.sgl = (void *) (unsigned long) addr; - sc->tag = tag; - err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun, - cmd->tag); - if (err) - scsi_host_put_command(shost, sc); - - return err; -} -EXPORT_SYMBOL_GPL(srp_cmd_queue); - -MODULE_DESCRIPTION("SCSI RDMA Protocol lib functions"); -MODULE_AUTHOR("FUJITA Tomonori"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/Makefile b/ANDROID_3.4.5/drivers/scsi/lpfc/Makefile deleted file mode 100644 index fe5d396a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -#/******************************************************************* -# * This file is part of the Emulex Linux Device Driver for * -# * Fibre Channel Host Bus Adapters. * -# * Copyright (C) 2004-2012 Emulex. All rights reserved. * -# * EMULEX and SLI are trademarks of Emulex. * -# * www.emulex.com * -# * * -# * This program is free software; you can redistribute it and/or * -# * modify it under the terms of version 2 of the GNU General * -# * Public License as published by the Free Software Foundation. * -# * This program is distributed in the hope that it will be useful. * -# * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * -# * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * -# * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * -# * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * -# * TO BE LEGALLY INVALID. See the GNU General Public License for * -# * more details, a copy of which can be found in the file COPYING * -# * included with this package. * -# *******************************************************************/ -###################################################################### - -ccflags-$(GCOV) := -fprofile-arcs -ftest-coverage -ccflags-$(GCOV) += -O0 - -ccflags-y += -Werror - -obj-$(CONFIG_SCSI_LPFC) := lpfc.o - -lpfc-objs := lpfc_mem.o lpfc_sli.o lpfc_ct.o lpfc_els.o lpfc_hbadisc.o \ - lpfc_init.o lpfc_mbox.o lpfc_nportdisc.o lpfc_scsi.o lpfc_attr.o \ - lpfc_vport.o lpfc_debugfs.o lpfc_bsg.o diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc.h deleted file mode 100644 index 3a1ffdd6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc.h +++ /dev/null @@ -1,1004 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include - -#if defined(CONFIG_DEBUG_FS) && !defined(CONFIG_SCSI_LPFC_DEBUG_FS) -#define CONFIG_SCSI_LPFC_DEBUG_FS -#endif - -struct lpfc_sli2_slim; - -#define LPFC_PCI_DEV_LP 0x1 -#define LPFC_PCI_DEV_OC 0x2 - -#define LPFC_SLI_REV2 2 -#define LPFC_SLI_REV3 3 -#define LPFC_SLI_REV4 4 - -#define LPFC_MAX_TARGET 4096 /* max number of targets supported */ -#define LPFC_MAX_DISC_THREADS 64 /* max outstanding discovery els - requests */ -#define LPFC_MAX_NS_RETRY 3 /* Number of retry attempts to contact - the NameServer before giving up. */ -#define LPFC_CMD_PER_LUN 3 /* max outstanding cmds per lun */ -#define LPFC_DEFAULT_SG_SEG_CNT 64 /* sg element count per scsi cmnd */ -#define LPFC_DEFAULT_MENLO_SG_SEG_CNT 128 /* sg element count per scsi - cmnd for menlo needs nearly twice as for firmware - downloads using bsg */ -#define LPFC_DEFAULT_PROT_SG_SEG_CNT 4096 /* sg protection elements count */ -#define LPFC_MAX_SG_SEG_CNT 4096 /* sg element count per scsi cmnd */ -#define LPFC_MAX_SGE_SIZE 0x80000000 /* Maximum data allowed in a SGE */ -#define LPFC_MAX_PROT_SG_SEG_CNT 4096 /* prot sg element count per scsi cmd*/ -#define LPFC_IOCB_LIST_CNT 2250 /* list of IOCBs for fast-path usage. */ -#define LPFC_Q_RAMP_UP_INTERVAL 120 /* lun q_depth ramp up interval */ -#define LPFC_VNAME_LEN 100 /* vport symbolic name length */ -#define LPFC_TGTQ_INTERVAL 40000 /* Min amount of time between tgt - queue depth change in millisecs */ -#define LPFC_TGTQ_RAMPUP_PCENT 5 /* Target queue rampup in percentage */ -#define LPFC_MIN_TGT_QDEPTH 10 -#define LPFC_MAX_TGT_QDEPTH 0xFFFF - -#define LPFC_MAX_BUCKET_COUNT 20 /* Maximum no. of buckets for stat data - collection. */ -/* - * Following time intervals are used of adjusting SCSI device - * queue depths when there are driver resource error or Firmware - * resource error. - */ -#define QUEUE_RAMP_DOWN_INTERVAL (1 * HZ) /* 1 Second */ -#define QUEUE_RAMP_UP_INTERVAL (300 * HZ) /* 5 minutes */ - -/* Number of exchanges reserved for discovery to complete */ -#define LPFC_DISC_IOCB_BUFF_COUNT 20 - -#define LPFC_HB_MBOX_INTERVAL 5 /* Heart beat interval in seconds. */ -#define LPFC_HB_MBOX_TIMEOUT 30 /* Heart beat timeout in seconds. */ - -/* Error Attention event polling interval */ -#define LPFC_ERATT_POLL_INTERVAL 5 /* EATT poll interval in seconds */ - -/* Define macros for 64 bit support */ -#define putPaddrLow(addr) ((uint32_t) (0xffffffff & (u64)(addr))) -#define putPaddrHigh(addr) ((uint32_t) (0xffffffff & (((u64)(addr))>>32))) -#define getPaddr(high, low) ((dma_addr_t)( \ - (( (u64)(high)<<16 ) << 16)|( (u64)(low)))) -/* Provide maximum configuration definitions. */ -#define LPFC_DRVR_TIMEOUT 16 /* driver iocb timeout value in sec */ -#define FC_MAX_ADPTMSG 64 - -#define MAX_HBAEVT 32 - -/* Number of MSI-X vectors the driver uses */ -#define LPFC_MSIX_VECTORS 2 - -/* lpfc wait event data ready flag */ -#define LPFC_DATA_READY (1<<0) - -enum lpfc_polling_flags { - ENABLE_FCP_RING_POLLING = 0x1, - DISABLE_FCP_RING_INT = 0x2 -}; - -/* Provide DMA memory definitions the driver uses per port instance. */ -struct lpfc_dmabuf { - struct list_head list; - void *virt; /* virtual address ptr */ - dma_addr_t phys; /* mapped address */ - uint32_t buffer_tag; /* used for tagged queue ring */ -}; - -struct lpfc_dma_pool { - struct lpfc_dmabuf *elements; - uint32_t max_count; - uint32_t current_count; -}; - -struct hbq_dmabuf { - struct lpfc_dmabuf hbuf; - struct lpfc_dmabuf dbuf; - uint32_t size; - uint32_t tag; - struct lpfc_cq_event cq_event; - unsigned long time_stamp; -}; - -/* Priority bit. Set value to exceed low water mark in lpfc_mem. */ -#define MEM_PRI 0x100 - - -/****************************************************************************/ -/* Device VPD save area */ -/****************************************************************************/ -typedef struct lpfc_vpd { - uint32_t status; /* vpd status value */ - uint32_t length; /* number of bytes actually returned */ - struct { - uint32_t rsvd1; /* Revision numbers */ - uint32_t biuRev; - uint32_t smRev; - uint32_t smFwRev; - uint32_t endecRev; - uint16_t rBit; - uint8_t fcphHigh; - uint8_t fcphLow; - uint8_t feaLevelHigh; - uint8_t feaLevelLow; - uint32_t postKernRev; - uint32_t opFwRev; - uint8_t opFwName[16]; - uint32_t sli1FwRev; - uint8_t sli1FwName[16]; - uint32_t sli2FwRev; - uint8_t sli2FwName[16]; - } rev; - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd3 :19; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd2 : 3; /* Reserved */ - uint32_t cbg : 1; /* Configure BlockGuard */ - uint32_t cmv : 1; /* Configure Max VPIs */ - uint32_t ccrp : 1; /* Config Command Ring Polling */ - uint32_t csah : 1; /* Configure Synchronous Abort Handling */ - uint32_t chbs : 1; /* Cofigure Host Backing store */ - uint32_t cinb : 1; /* Enable Interrupt Notification Block */ - uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */ - uint32_t cmx : 1; /* Configure Max XRIs */ - uint32_t cmr : 1; /* Configure Max RPIs */ -#else /* __LITTLE_ENDIAN */ - uint32_t cmr : 1; /* Configure Max RPIs */ - uint32_t cmx : 1; /* Configure Max XRIs */ - uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */ - uint32_t cinb : 1; /* Enable Interrupt Notification Block */ - uint32_t chbs : 1; /* Cofigure Host Backing store */ - uint32_t csah : 1; /* Configure Synchronous Abort Handling */ - uint32_t ccrp : 1; /* Config Command Ring Polling */ - uint32_t cmv : 1; /* Configure Max VPIs */ - uint32_t cbg : 1; /* Configure BlockGuard */ - uint32_t rsvd2 : 3; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd3 :19; /* Reserved */ -#endif - } sli3Feat; -} lpfc_vpd_t; - -struct lpfc_scsi_buf; - - -/* - * lpfc stat counters - */ -struct lpfc_stats { - /* Statistics for ELS commands */ - uint32_t elsLogiCol; - uint32_t elsRetryExceeded; - uint32_t elsXmitRetry; - uint32_t elsDelayRetry; - uint32_t elsRcvDrop; - uint32_t elsRcvFrame; - uint32_t elsRcvRSCN; - uint32_t elsRcvRNID; - uint32_t elsRcvFARP; - uint32_t elsRcvFARPR; - uint32_t elsRcvFLOGI; - uint32_t elsRcvPLOGI; - uint32_t elsRcvADISC; - uint32_t elsRcvPDISC; - uint32_t elsRcvFAN; - uint32_t elsRcvLOGO; - uint32_t elsRcvPRLO; - uint32_t elsRcvPRLI; - uint32_t elsRcvLIRR; - uint32_t elsRcvRLS; - uint32_t elsRcvRPS; - uint32_t elsRcvRPL; - uint32_t elsRcvRRQ; - uint32_t elsRcvRTV; - uint32_t elsRcvECHO; - uint32_t elsXmitFLOGI; - uint32_t elsXmitFDISC; - uint32_t elsXmitPLOGI; - uint32_t elsXmitPRLI; - uint32_t elsXmitADISC; - uint32_t elsXmitLOGO; - uint32_t elsXmitSCR; - uint32_t elsXmitRNID; - uint32_t elsXmitFARP; - uint32_t elsXmitFARPR; - uint32_t elsXmitACC; - uint32_t elsXmitLSRJT; - - uint32_t frameRcvBcast; - uint32_t frameRcvMulti; - uint32_t strayXmitCmpl; - uint32_t frameXmitDelay; - uint32_t xriCmdCmpl; - uint32_t xriStatErr; - uint32_t LinkUp; - uint32_t LinkDown; - uint32_t LinkMultiEvent; - uint32_t NoRcvBuf; - uint32_t fcpCmd; - uint32_t fcpCmpl; - uint32_t fcpRspErr; - uint32_t fcpRemoteStop; - uint32_t fcpPortRjt; - uint32_t fcpPortBusy; - uint32_t fcpError; - uint32_t fcpLocalErr; -}; - -struct lpfc_hba; - - -enum discovery_state { - LPFC_VPORT_UNKNOWN = 0, /* vport state is unknown */ - LPFC_VPORT_FAILED = 1, /* vport has failed */ - LPFC_LOCAL_CFG_LINK = 6, /* local NPORT Id configured */ - LPFC_FLOGI = 7, /* FLOGI sent to Fabric */ - LPFC_FDISC = 8, /* FDISC sent for vport */ - LPFC_FABRIC_CFG_LINK = 9, /* Fabric assigned NPORT Id - * configured */ - LPFC_NS_REG = 10, /* Register with NameServer */ - LPFC_NS_QRY = 11, /* Query NameServer for NPort ID list */ - LPFC_BUILD_DISC_LIST = 12, /* Build ADISC and PLOGI lists for - * device authentication / discovery */ - LPFC_DISC_AUTH = 13, /* Processing ADISC list */ - LPFC_VPORT_READY = 32, -}; - -enum hba_state { - LPFC_LINK_UNKNOWN = 0, /* HBA state is unknown */ - LPFC_WARM_START = 1, /* HBA state after selective reset */ - LPFC_INIT_START = 2, /* Initial state after board reset */ - LPFC_INIT_MBX_CMDS = 3, /* Initialize HBA with mbox commands */ - LPFC_LINK_DOWN = 4, /* HBA initialized, link is down */ - LPFC_LINK_UP = 5, /* Link is up - issue READ_LA */ - LPFC_CLEAR_LA = 6, /* authentication cmplt - issue - * CLEAR_LA */ - LPFC_HBA_READY = 32, - LPFC_HBA_ERROR = -1 -}; - -struct lpfc_vport { - struct lpfc_hba *phba; - struct list_head listentry; - uint8_t port_type; -#define LPFC_PHYSICAL_PORT 1 -#define LPFC_NPIV_PORT 2 -#define LPFC_FABRIC_PORT 3 - enum discovery_state port_state; - - uint16_t vpi; - uint16_t vfi; - uint8_t vpi_state; -#define LPFC_VPI_REGISTERED 0x1 - - uint32_t fc_flag; /* FC flags */ -/* Several of these flags are HBA centric and should be moved to - * phba->link_flag (e.g. FC_PTP, FC_PUBLIC_LOOP) - */ -#define FC_PT2PT 0x1 /* pt2pt with no fabric */ -#define FC_PT2PT_PLOGI 0x2 /* pt2pt initiate PLOGI */ -#define FC_DISC_TMO 0x4 /* Discovery timer running */ -#define FC_PUBLIC_LOOP 0x8 /* Public loop */ -#define FC_LBIT 0x10 /* LOGIN bit in loopinit set */ -#define FC_RSCN_MODE 0x20 /* RSCN cmd rcv'ed */ -#define FC_NLP_MORE 0x40 /* More node to process in node tbl */ -#define FC_OFFLINE_MODE 0x80 /* Interface is offline for diag */ -#define FC_FABRIC 0x100 /* We are fabric attached */ -#define FC_VPORT_LOGO_RCVD 0x200 /* LOGO received on vport */ -#define FC_RSCN_DISCOVERY 0x400 /* Auth all devices after RSCN */ -#define FC_LOGO_RCVD_DID_CHNG 0x800 /* FDISC on phys port detect DID chng*/ -#define FC_SCSI_SCAN_TMO 0x4000 /* scsi scan timer running */ -#define FC_ABORT_DISCOVERY 0x8000 /* we want to abort discovery */ -#define FC_NDISC_ACTIVE 0x10000 /* NPort discovery active */ -#define FC_BYPASSED_MODE 0x20000 /* NPort is in bypassed mode */ -#define FC_VPORT_NEEDS_REG_VPI 0x80000 /* Needs to have its vpi registered */ -#define FC_RSCN_DEFERRED 0x100000 /* A deferred RSCN being processed */ -#define FC_VPORT_NEEDS_INIT_VPI 0x200000 /* Need to INIT_VPI before FDISC */ -#define FC_VPORT_CVL_RCVD 0x400000 /* VLink failed due to CVL */ -#define FC_VFI_REGISTERED 0x800000 /* VFI is registered */ -#define FC_FDISC_COMPLETED 0x1000000/* FDISC completed */ -#define FC_DISC_DELAYED 0x2000000/* Delay NPort discovery */ - - uint32_t ct_flags; -#define FC_CT_RFF_ID 0x1 /* RFF_ID accepted by switch */ -#define FC_CT_RNN_ID 0x2 /* RNN_ID accepted by switch */ -#define FC_CT_RSNN_NN 0x4 /* RSNN_NN accepted by switch */ -#define FC_CT_RSPN_ID 0x8 /* RSPN_ID accepted by switch */ -#define FC_CT_RFT_ID 0x10 /* RFT_ID accepted by switch */ - - struct list_head fc_nodes; - - /* Keep counters for the number of entries in each list. */ - uint16_t fc_plogi_cnt; - uint16_t fc_adisc_cnt; - uint16_t fc_reglogin_cnt; - uint16_t fc_prli_cnt; - uint16_t fc_unmap_cnt; - uint16_t fc_map_cnt; - uint16_t fc_npr_cnt; - uint16_t fc_unused_cnt; - struct serv_parm fc_sparam; /* buffer for our service parameters */ - - uint32_t fc_myDID; /* fibre channel S_ID */ - uint32_t fc_prevDID; /* previous fibre channel S_ID */ - struct lpfc_name fabric_portname; - struct lpfc_name fabric_nodename; - - int32_t stopped; /* HBA has not been restarted since last ERATT */ - uint8_t fc_linkspeed; /* Link speed after last READ_LA */ - - uint32_t num_disc_nodes; /*in addition to hba_state */ - - uint32_t fc_nlp_cnt; /* outstanding NODELIST requests */ - uint32_t fc_rscn_id_cnt; /* count of RSCNs payloads in list */ - uint32_t fc_rscn_flush; /* flag use of fc_rscn_id_list */ - struct lpfc_dmabuf *fc_rscn_id_list[FC_MAX_HOLD_RSCN]; - struct lpfc_name fc_nodename; /* fc nodename */ - struct lpfc_name fc_portname; /* fc portname */ - - struct lpfc_work_evt disc_timeout_evt; - - struct timer_list fc_disctmo; /* Discovery rescue timer */ - uint8_t fc_ns_retry; /* retries for fabric nameserver */ - uint32_t fc_prli_sent; /* cntr for outstanding PRLIs */ - - spinlock_t work_port_lock; - uint32_t work_port_events; /* Timeout to be handled */ -#define WORKER_DISC_TMO 0x1 /* vport: Discovery timeout */ -#define WORKER_ELS_TMO 0x2 /* vport: ELS timeout */ -#define WORKER_FDMI_TMO 0x4 /* vport: FDMI timeout */ -#define WORKER_DELAYED_DISC_TMO 0x8 /* vport: delayed discovery */ - -#define WORKER_MBOX_TMO 0x100 /* hba: MBOX timeout */ -#define WORKER_HB_TMO 0x200 /* hba: Heart beat timeout */ -#define WORKER_FABRIC_BLOCK_TMO 0x400 /* hba: fabric block timeout */ -#define WORKER_RAMP_DOWN_QUEUE 0x800 /* hba: Decrease Q depth */ -#define WORKER_RAMP_UP_QUEUE 0x1000 /* hba: Increase Q depth */ -#define WORKER_SERVICE_TXQ 0x2000 /* hba: IOCBs on the txq */ - - struct timer_list fc_fdmitmo; - struct timer_list els_tmofunc; - struct timer_list delayed_disc_tmo; - - int unreg_vpi_cmpl; - - uint8_t load_flag; -#define FC_LOADING 0x1 /* HBA in process of loading drvr */ -#define FC_UNLOADING 0x2 /* HBA in process of unloading drvr */ - /* Vport Config Parameters */ - uint32_t cfg_scan_down; - uint32_t cfg_lun_queue_depth; - uint32_t cfg_nodev_tmo; - uint32_t cfg_devloss_tmo; - uint32_t cfg_restrict_login; - uint32_t cfg_peer_port_login; - uint32_t cfg_fcp_class; - uint32_t cfg_use_adisc; - uint32_t cfg_fdmi_on; - uint32_t cfg_discovery_threads; - uint32_t cfg_log_verbose; - uint32_t cfg_max_luns; - uint32_t cfg_enable_da_id; - uint32_t cfg_max_scsicmpl_time; - uint32_t cfg_tgt_queue_depth; - - uint32_t dev_loss_tmo_changed; - - struct fc_vport *fc_vport; - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - struct dentry *debug_disc_trc; - struct dentry *debug_nodelist; - struct dentry *vport_debugfs_root; - struct lpfc_debugfs_trc *disc_trc; - atomic_t disc_trc_cnt; -#endif - uint8_t stat_data_enabled; - uint8_t stat_data_blocked; - struct list_head rcv_buffer_list; - unsigned long rcv_buffer_time_stamp; - uint32_t vport_flag; -#define STATIC_VPORT 1 -}; - -struct hbq_s { - uint16_t entry_count; /* Current number of HBQ slots */ - uint16_t buffer_count; /* Current number of buffers posted */ - uint32_t next_hbqPutIdx; /* Index to next HBQ slot to use */ - uint32_t hbqPutIdx; /* HBQ slot to use */ - uint32_t local_hbqGetIdx; /* Local copy of Get index from Port */ - void *hbq_virt; /* Virtual ptr to this hbq */ - struct list_head hbq_buffer_list; /* buffers assigned to this HBQ */ - /* Callback for HBQ buffer allocation */ - struct hbq_dmabuf *(*hbq_alloc_buffer) (struct lpfc_hba *); - /* Callback for HBQ buffer free */ - void (*hbq_free_buffer) (struct lpfc_hba *, - struct hbq_dmabuf *); -}; - -#define LPFC_MAX_HBQS 4 -/* this matches the position in the lpfc_hbq_defs array */ -#define LPFC_ELS_HBQ 0 -#define LPFC_EXTRA_HBQ 1 - -enum hba_temp_state { - HBA_NORMAL_TEMP, - HBA_OVER_TEMP -}; - -enum intr_type_t { - NONE = 0, - INTx, - MSI, - MSIX, -}; - -struct unsol_rcv_ct_ctx { - uint32_t ctxt_id; - uint32_t SID; - uint32_t flags; -#define UNSOL_VALID 0x00000001 - uint16_t oxid; - uint16_t rxid; -}; - -#define LPFC_USER_LINK_SPEED_AUTO 0 /* auto select (default)*/ -#define LPFC_USER_LINK_SPEED_1G 1 /* 1 Gigabaud */ -#define LPFC_USER_LINK_SPEED_2G 2 /* 2 Gigabaud */ -#define LPFC_USER_LINK_SPEED_4G 4 /* 4 Gigabaud */ -#define LPFC_USER_LINK_SPEED_8G 8 /* 8 Gigabaud */ -#define LPFC_USER_LINK_SPEED_10G 10 /* 10 Gigabaud */ -#define LPFC_USER_LINK_SPEED_16G 16 /* 16 Gigabaud */ -#define LPFC_USER_LINK_SPEED_MAX LPFC_USER_LINK_SPEED_16G -#define LPFC_USER_LINK_SPEED_BITMAP ((1 << LPFC_USER_LINK_SPEED_16G) | \ - (1 << LPFC_USER_LINK_SPEED_10G) | \ - (1 << LPFC_USER_LINK_SPEED_8G) | \ - (1 << LPFC_USER_LINK_SPEED_4G) | \ - (1 << LPFC_USER_LINK_SPEED_2G) | \ - (1 << LPFC_USER_LINK_SPEED_1G) | \ - (1 << LPFC_USER_LINK_SPEED_AUTO)) -#define LPFC_LINK_SPEED_STRING "0, 1, 2, 4, 8, 10, 16" - -enum nemb_type { - nemb_mse = 1, - nemb_hbd -}; - -enum mbox_type { - mbox_rd = 1, - mbox_wr -}; - -enum dma_type { - dma_mbox = 1, - dma_ebuf -}; - -enum sta_type { - sta_pre_addr = 1, - sta_pos_addr -}; - -struct lpfc_mbox_ext_buf_ctx { - uint32_t state; -#define LPFC_BSG_MBOX_IDLE 0 -#define LPFC_BSG_MBOX_HOST 1 -#define LPFC_BSG_MBOX_PORT 2 -#define LPFC_BSG_MBOX_DONE 3 -#define LPFC_BSG_MBOX_ABTS 4 - enum nemb_type nembType; - enum mbox_type mboxType; - uint32_t numBuf; - uint32_t mbxTag; - uint32_t seqNum; - struct lpfc_dmabuf *mbx_dmabuf; - struct list_head ext_dmabuf_list; -}; - -struct lpfc_hba { - /* SCSI interface function jump table entries */ - int (*lpfc_new_scsi_buf) - (struct lpfc_vport *, int); - struct lpfc_scsi_buf * (*lpfc_get_scsi_buf) - (struct lpfc_hba *, struct lpfc_nodelist *); - int (*lpfc_scsi_prep_dma_buf) - (struct lpfc_hba *, struct lpfc_scsi_buf *); - void (*lpfc_scsi_unprep_dma_buf) - (struct lpfc_hba *, struct lpfc_scsi_buf *); - void (*lpfc_release_scsi_buf) - (struct lpfc_hba *, struct lpfc_scsi_buf *); - void (*lpfc_rampdown_queue_depth) - (struct lpfc_hba *); - void (*lpfc_scsi_prep_cmnd) - (struct lpfc_vport *, struct lpfc_scsi_buf *, - struct lpfc_nodelist *); - - /* IOCB interface function jump table entries */ - int (*__lpfc_sli_issue_iocb) - (struct lpfc_hba *, uint32_t, - struct lpfc_iocbq *, uint32_t); - void (*__lpfc_sli_release_iocbq)(struct lpfc_hba *, - struct lpfc_iocbq *); - int (*lpfc_hba_down_post)(struct lpfc_hba *phba); - IOCB_t * (*lpfc_get_iocb_from_iocbq) - (struct lpfc_iocbq *); - void (*lpfc_scsi_cmd_iocb_cmpl) - (struct lpfc_hba *, struct lpfc_iocbq *, struct lpfc_iocbq *); - - /* MBOX interface function jump table entries */ - int (*lpfc_sli_issue_mbox) - (struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); - - /* Slow-path IOCB process function jump table entries */ - void (*lpfc_sli_handle_slow_ring_event) - (struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - uint32_t mask); - - /* INIT device interface function jump table entries */ - int (*lpfc_sli_hbq_to_firmware) - (struct lpfc_hba *, uint32_t, struct hbq_dmabuf *); - int (*lpfc_sli_brdrestart) - (struct lpfc_hba *); - int (*lpfc_sli_brdready) - (struct lpfc_hba *, uint32_t); - void (*lpfc_handle_eratt) - (struct lpfc_hba *); - void (*lpfc_stop_port) - (struct lpfc_hba *); - int (*lpfc_hba_init_link) - (struct lpfc_hba *, uint32_t); - int (*lpfc_hba_down_link) - (struct lpfc_hba *, uint32_t); - int (*lpfc_selective_reset) - (struct lpfc_hba *); - - int (*lpfc_bg_scsi_prep_dma_buf) - (struct lpfc_hba *, struct lpfc_scsi_buf *); - /* Add new entries here */ - - /* SLI4 specific HBA data structure */ - struct lpfc_sli4_hba sli4_hba; - - struct lpfc_sli sli; - uint8_t pci_dev_grp; /* lpfc PCI dev group: 0x0, 0x1, 0x2,... */ - uint32_t sli_rev; /* SLI2, SLI3, or SLI4 */ - uint32_t sli3_options; /* Mask of enabled SLI3 options */ -#define LPFC_SLI3_HBQ_ENABLED 0x01 -#define LPFC_SLI3_NPIV_ENABLED 0x02 -#define LPFC_SLI3_VPORT_TEARDOWN 0x04 -#define LPFC_SLI3_CRP_ENABLED 0x08 -#define LPFC_SLI3_BG_ENABLED 0x20 -#define LPFC_SLI3_DSS_ENABLED 0x40 -#define LPFC_SLI4_PERFH_ENABLED 0x80 -#define LPFC_SLI4_PHWQ_ENABLED 0x100 - uint32_t iocb_cmd_size; - uint32_t iocb_rsp_size; - - enum hba_state link_state; - uint32_t link_flag; /* link state flags */ -#define LS_LOOPBACK_MODE 0x1 /* NPort is in Loopback mode */ - /* This flag is set while issuing */ - /* INIT_LINK mailbox command */ -#define LS_NPIV_FAB_SUPPORTED 0x2 /* Fabric supports NPIV */ -#define LS_IGNORE_ERATT 0x4 /* intr handler should ignore ERATT */ - - uint32_t hba_flag; /* hba generic flags */ -#define HBA_ERATT_HANDLED 0x1 /* This flag is set when eratt handled */ -#define DEFER_ERATT 0x2 /* Deferred error attention in progress */ -#define HBA_FCOE_MODE 0x4 /* HBA function in FCoE Mode */ -#define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/ -#define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */ -#define FCP_XRI_ABORT_EVENT 0x20 -#define ELS_XRI_ABORT_EVENT 0x40 -#define ASYNC_EVENT 0x80 -#define LINK_DISABLED 0x100 /* Link disabled by user */ -#define FCF_TS_INPROG 0x200 /* FCF table scan in progress */ -#define FCF_RR_INPROG 0x400 /* FCF roundrobin flogi in progress */ -#define HBA_FIP_SUPPORT 0x800 /* FIP support in HBA */ -#define HBA_AER_ENABLED 0x1000 /* AER enabled with HBA */ -#define HBA_DEVLOSS_TMO 0x2000 /* HBA in devloss timeout */ -#define HBA_RRQ_ACTIVE 0x4000 /* process the rrq active list */ - uint32_t fcp_ring_in_use; /* When polling test if intr-hndlr active*/ - struct lpfc_dmabuf slim2p; - - MAILBOX_t *mbox; - uint32_t *mbox_ext; - struct lpfc_mbox_ext_buf_ctx mbox_ext_buf_ctx; - uint32_t ha_copy; - struct _PCB *pcb; - struct _IOCB *IOCBs; - - struct lpfc_dmabuf hbqslimp; - - uint16_t pci_cfg_value; - - uint8_t fc_linkspeed; /* Link speed after last READ_LA */ - - uint32_t fc_eventTag; /* event tag for link attention */ - uint32_t link_events; - - /* These fields used to be binfo */ - uint32_t fc_pref_DID; /* preferred D_ID */ - uint8_t fc_pref_ALPA; /* preferred AL_PA */ - uint32_t fc_edtovResol; /* E_D_TOV timer resolution */ - uint32_t fc_edtov; /* E_D_TOV timer value */ - uint32_t fc_arbtov; /* ARB_TOV timer value */ - uint32_t fc_ratov; /* R_A_TOV timer value */ - uint32_t fc_rttov; /* R_T_TOV timer value */ - uint32_t fc_altov; /* AL_TOV timer value */ - uint32_t fc_crtov; /* C_R_TOV timer value */ - uint32_t fc_citov; /* C_I_TOV timer value */ - - struct serv_parm fc_fabparam; /* fabric service parameters buffer */ - uint8_t alpa_map[128]; /* AL_PA map from READ_LA */ - - uint32_t lmt; - - uint32_t fc_topology; /* link topology, from LINK INIT */ - - struct lpfc_stats fc_stat; - - struct lpfc_nodelist fc_fcpnodev; /* nodelist entry for no device */ - uint32_t nport_event_cnt; /* timestamp for nlplist entry */ - - uint8_t wwnn[8]; - uint8_t wwpn[8]; - uint32_t RandomData[7]; - - /* HBA Config Parameters */ - uint32_t cfg_ack0; - uint32_t cfg_enable_npiv; - uint32_t cfg_enable_rrq; - uint32_t cfg_topology; - uint32_t cfg_link_speed; -#define LPFC_FCF_FOV 1 /* Fast fcf failover */ -#define LPFC_FCF_PRIORITY 2 /* Priority fcf failover */ - uint32_t cfg_fcf_failover_policy; - uint32_t cfg_cr_delay; - uint32_t cfg_cr_count; - uint32_t cfg_multi_ring_support; - uint32_t cfg_multi_ring_rctl; - uint32_t cfg_multi_ring_type; - uint32_t cfg_poll; - uint32_t cfg_poll_tmo; - uint32_t cfg_use_msi; - uint32_t cfg_fcp_imax; - uint32_t cfg_fcp_wq_count; - uint32_t cfg_fcp_eq_count; - uint32_t cfg_sg_seg_cnt; - uint32_t cfg_prot_sg_seg_cnt; - uint32_t cfg_sg_dma_buf_size; - uint64_t cfg_soft_wwnn; - uint64_t cfg_soft_wwpn; - uint32_t cfg_hba_queue_depth; - uint32_t cfg_enable_hba_reset; - uint32_t cfg_enable_hba_heartbeat; - uint32_t cfg_enable_bg; - uint32_t cfg_hostmem_hgp; - uint32_t cfg_log_verbose; - uint32_t cfg_aer_support; - uint32_t cfg_sriov_nr_virtfn; - uint32_t cfg_iocb_cnt; - uint32_t cfg_suppress_link_up; -#define LPFC_INITIALIZE_LINK 0 /* do normal init_link mbox */ -#define LPFC_DELAY_INIT_LINK 1 /* layered driver hold off */ -#define LPFC_DELAY_INIT_LINK_INDEFINITELY 2 /* wait, manual intervention */ - uint32_t cfg_enable_dss; - lpfc_vpd_t vpd; /* vital product data */ - - struct pci_dev *pcidev; - struct list_head work_list; - uint32_t work_ha; /* Host Attention Bits for WT */ - uint32_t work_ha_mask; /* HA Bits owned by WT */ - uint32_t work_hs; /* HS stored in case of ERRAT */ - uint32_t work_status[2]; /* Extra status from SLIM */ - - wait_queue_head_t work_waitq; - struct task_struct *worker_thread; - unsigned long data_flags; - - uint32_t hbq_in_use; /* HBQs in use flag */ - struct list_head rb_pend_list; /* Received buffers to be processed */ - uint32_t hbq_count; /* Count of configured HBQs */ - struct hbq_s hbqs[LPFC_MAX_HBQS]; /* local copy of hbq indicies */ - - uint32_t fcp_qidx; /* next work queue to post work to */ - - unsigned long pci_bar0_map; /* Physical address for PCI BAR0 */ - unsigned long pci_bar1_map; /* Physical address for PCI BAR1 */ - unsigned long pci_bar2_map; /* Physical address for PCI BAR2 */ - void __iomem *slim_memmap_p; /* Kernel memory mapped address for - PCI BAR0 */ - void __iomem *ctrl_regs_memmap_p;/* Kernel memory mapped address for - PCI BAR2 */ - - void __iomem *MBslimaddr; /* virtual address for mbox cmds */ - void __iomem *HAregaddr; /* virtual address for host attn reg */ - void __iomem *CAregaddr; /* virtual address for chip attn reg */ - void __iomem *HSregaddr; /* virtual address for host status - reg */ - void __iomem *HCregaddr; /* virtual address for host ctl reg */ - - struct lpfc_hgp __iomem *host_gp; /* Host side get/put pointers */ - struct lpfc_pgp *port_gp; - uint32_t __iomem *hbq_put; /* Address in SLIM to HBQ put ptrs */ - uint32_t *hbq_get; /* Host mem address of HBQ get ptrs */ - - int brd_no; /* FC board number */ - char SerialNumber[32]; /* adapter Serial Number */ - char OptionROMVersion[32]; /* adapter BIOS / Fcode version */ - char ModelDesc[256]; /* Model Description */ - char ModelName[80]; /* Model Name */ - char ProgramType[256]; /* Program Type */ - char Port[20]; /* Port No */ - uint8_t vpd_flag; /* VPD data flag */ - -#define VPD_MODEL_DESC 0x1 /* valid vpd model description */ -#define VPD_MODEL_NAME 0x2 /* valid vpd model name */ -#define VPD_PROGRAM_TYPE 0x4 /* valid vpd program type */ -#define VPD_PORT 0x8 /* valid vpd port data */ -#define VPD_MASK 0xf /* mask for any vpd data */ - - uint8_t soft_wwn_enable; - - struct timer_list fcp_poll_timer; - struct timer_list eratt_poll; - - /* - * stat counters - */ - uint64_t fc4InputRequests; - uint64_t fc4OutputRequests; - uint64_t fc4ControlRequests; - uint64_t bg_guard_err_cnt; - uint64_t bg_apptag_err_cnt; - uint64_t bg_reftag_err_cnt; - - /* fastpath list. */ - spinlock_t scsi_buf_list_lock; - struct list_head lpfc_scsi_buf_list; - uint32_t total_scsi_bufs; - struct list_head lpfc_iocb_list; - uint32_t total_iocbq_bufs; - struct list_head active_rrq_list; - spinlock_t hbalock; - - /* pci_mem_pools */ - struct pci_pool *lpfc_scsi_dma_buf_pool; - struct pci_pool *lpfc_mbuf_pool; - struct pci_pool *lpfc_hrb_pool; /* header receive buffer pool */ - struct pci_pool *lpfc_drb_pool; /* data receive buffer pool */ - struct pci_pool *lpfc_hbq_pool; /* SLI3 hbq buffer pool */ - struct lpfc_dma_pool lpfc_mbuf_safety_pool; - - mempool_t *mbox_mem_pool; - mempool_t *nlp_mem_pool; - mempool_t *rrq_pool; - - struct fc_host_statistics link_stats; - enum intr_type_t intr_type; - uint32_t intr_mode; -#define LPFC_INTR_ERROR 0xFFFFFFFF - struct msix_entry msix_entries[LPFC_MSIX_VECTORS]; - - struct list_head port_list; - struct lpfc_vport *pport; /* physical lpfc_vport pointer */ - uint16_t max_vpi; /* Maximum virtual nports */ -#define LPFC_MAX_VPI 0xFFFF /* Max number of VPI supported */ - uint16_t max_vports; /* - * For IOV HBAs max_vpi can change - * after a reset. max_vports is max - * number of vports present. This can - * be greater than max_vpi. - */ - uint16_t vpi_base; - uint16_t vfi_base; - unsigned long *vpi_bmask; /* vpi allocation table */ - uint16_t *vpi_ids; - uint16_t vpi_count; - struct list_head lpfc_vpi_blk_list; - - /* Data structure used by fabric iocb scheduler */ - struct list_head fabric_iocb_list; - atomic_t fabric_iocb_count; - struct timer_list fabric_block_timer; - unsigned long bit_flags; -#define FABRIC_COMANDS_BLOCKED 0 - atomic_t num_rsrc_err; - atomic_t num_cmd_success; - unsigned long last_rsrc_error_time; - unsigned long last_ramp_down_time; - unsigned long last_ramp_up_time; -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - struct dentry *hba_debugfs_root; - atomic_t debugfs_vport_count; - struct dentry *debug_hbqinfo; - struct dentry *debug_dumpHostSlim; - struct dentry *debug_dumpHBASlim; - struct dentry *debug_dumpData; /* BlockGuard BPL */ - struct dentry *debug_dumpDif; /* BlockGuard BPL */ - struct dentry *debug_InjErrLBA; /* LBA to inject errors at */ - struct dentry *debug_InjErrNPortID; /* NPortID to inject errors at */ - struct dentry *debug_InjErrWWPN; /* WWPN to inject errors at */ - struct dentry *debug_writeGuard; /* inject write guard_tag errors */ - struct dentry *debug_writeApp; /* inject write app_tag errors */ - struct dentry *debug_writeRef; /* inject write ref_tag errors */ - struct dentry *debug_readGuard; /* inject read guard_tag errors */ - struct dentry *debug_readApp; /* inject read app_tag errors */ - struct dentry *debug_readRef; /* inject read ref_tag errors */ - - /* T10 DIF error injection */ - uint32_t lpfc_injerr_wgrd_cnt; - uint32_t lpfc_injerr_wapp_cnt; - uint32_t lpfc_injerr_wref_cnt; - uint32_t lpfc_injerr_rgrd_cnt; - uint32_t lpfc_injerr_rapp_cnt; - uint32_t lpfc_injerr_rref_cnt; - uint32_t lpfc_injerr_nportid; - struct lpfc_name lpfc_injerr_wwpn; - sector_t lpfc_injerr_lba; -#define LPFC_INJERR_LBA_OFF (sector_t)(-1) - - struct dentry *debug_slow_ring_trc; - struct lpfc_debugfs_trc *slow_ring_trc; - atomic_t slow_ring_trc_cnt; - /* iDiag debugfs sub-directory */ - struct dentry *idiag_root; - struct dentry *idiag_pci_cfg; - struct dentry *idiag_bar_acc; - struct dentry *idiag_que_info; - struct dentry *idiag_que_acc; - struct dentry *idiag_drb_acc; - struct dentry *idiag_ctl_acc; - struct dentry *idiag_mbx_acc; - struct dentry *idiag_ext_acc; -#endif - - /* Used for deferred freeing of ELS data buffers */ - struct list_head elsbuf; - int elsbuf_cnt; - int elsbuf_prev_cnt; - - uint8_t temp_sensor_support; - /* Fields used for heart beat. */ - unsigned long last_completion_time; - unsigned long skipped_hb; - struct timer_list hb_tmofunc; - uint8_t hb_outstanding; - struct timer_list rrq_tmr; - enum hba_temp_state over_temp_state; - /* ndlp reference management */ - spinlock_t ndlp_lock; - /* - * Following bit will be set for all buffer tags which are not - * associated with any HBQ. - */ -#define QUE_BUFTAG_BIT (1<<31) - uint32_t buffer_tag_count; - int wait_4_mlo_maint_flg; - wait_queue_head_t wait_4_mlo_m_q; - /* data structure used for latency data collection */ -#define LPFC_NO_BUCKET 0 -#define LPFC_LINEAR_BUCKET 1 -#define LPFC_POWER2_BUCKET 2 - uint8_t bucket_type; - uint32_t bucket_base; - uint32_t bucket_step; - -/* Maximum number of events that can be outstanding at any time*/ -#define LPFC_MAX_EVT_COUNT 512 - atomic_t fast_event_count; - uint32_t fcoe_eventtag; - uint32_t fcoe_eventtag_at_fcf_scan; - uint32_t fcoe_cvl_eventtag; - uint32_t fcoe_cvl_eventtag_attn; - struct lpfc_fcf fcf; - uint8_t fc_map[3]; - uint8_t valid_vlan; - uint16_t vlan_id; - struct list_head fcf_conn_rec_list; - - spinlock_t ct_ev_lock; /* synchronize access to ct_ev_waiters */ - struct list_head ct_ev_waiters; - struct unsol_rcv_ct_ctx ct_ctx[64]; - uint32_t ctx_idx; - - uint8_t menlo_flag; /* menlo generic flags */ -#define HBA_MENLO_SUPPORT 0x1 /* HBA supports menlo commands */ - uint32_t iocb_cnt; - uint32_t iocb_max; - atomic_t sdev_cnt; - uint8_t fips_spec_rev; - uint8_t fips_level; -}; - -static inline struct Scsi_Host * -lpfc_shost_from_vport(struct lpfc_vport *vport) -{ - return container_of((void *) vport, struct Scsi_Host, hostdata[0]); -} - -static inline void -lpfc_set_loopback_flag(struct lpfc_hba *phba) -{ - if (phba->cfg_topology == FLAGS_LOCAL_LB) - phba->link_flag |= LS_LOOPBACK_MODE; - else - phba->link_flag &= ~LS_LOOPBACK_MODE; -} - -static inline int -lpfc_is_link_up(struct lpfc_hba *phba) -{ - return phba->link_state == LPFC_LINK_UP || - phba->link_state == LPFC_CLEAR_LA || - phba->link_state == LPFC_HBA_READY; -} - -static inline void -lpfc_worker_wake_up(struct lpfc_hba *phba) -{ - /* Set the lpfc data pending flag */ - set_bit(LPFC_DATA_READY, &phba->data_flags); - - /* Wake up worker thread */ - wake_up(&phba->work_waitq); - return; -} - -static inline int -lpfc_readl(void __iomem *addr, uint32_t *data) -{ - uint32_t temp; - temp = readl(addr); - if (temp == 0xffffffff) - return -EIO; - *data = temp; - return 0; -} - -static inline int -lpfc_sli_read_hs(struct lpfc_hba *phba) -{ - /* - * There was a link/board error. Read the status register to retrieve - * the error event and process it. - */ - phba->sli.slistat.err_attn_event++; - - /* Save status info and check for unplug error */ - if (lpfc_readl(phba->HSregaddr, &phba->work_hs) || - lpfc_readl(phba->MBslimaddr + 0xa8, &phba->work_status[0]) || - lpfc_readl(phba->MBslimaddr + 0xac, &phba->work_status[1])) { - return -EIO; - } - - /* Clear chip Host Attention error bit */ - writel(HA_ERATT, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - phba->pport->stopped = 1; - - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_attr.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_attr.c deleted file mode 100644 index 5eb2bc11..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_attr.c +++ /dev/null @@ -1,4950 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_version.h" -#include "lpfc_compat.h" -#include "lpfc_crtn.h" -#include "lpfc_vport.h" - -#define LPFC_DEF_DEVLOSS_TMO 30 -#define LPFC_MIN_DEVLOSS_TMO 1 -#define LPFC_MAX_DEVLOSS_TMO 255 - -/* - * Write key size should be multiple of 4. If write key is changed - * make sure that library write key is also changed. - */ -#define LPFC_REG_WRITE_KEY_SIZE 4 -#define LPFC_REG_WRITE_KEY "EMLX" - -/** - * lpfc_jedec_to_ascii - Hex to ascii convertor according to JEDEC rules - * @incr: integer to convert. - * @hdw: ascii string holding converted integer plus a string terminator. - * - * Description: - * JEDEC Joint Electron Device Engineering Council. - * Convert a 32 bit integer composed of 8 nibbles into an 8 byte ascii - * character string. The string is then terminated with a NULL in byte 9. - * Hex 0-9 becomes ascii '0' to '9'. - * Hex a-f becomes ascii '=' to 'B' capital B. - * - * Notes: - * Coded for 32 bit integers only. - **/ -static void -lpfc_jedec_to_ascii(int incr, char hdw[]) -{ - int i, j; - for (i = 0; i < 8; i++) { - j = (incr & 0xf); - if (j <= 9) - hdw[7 - i] = 0x30 + j; - else - hdw[7 - i] = 0x61 + j - 10; - incr = (incr >> 4); - } - hdw[8] = 0; - return; -} - -/** - * lpfc_drvr_version_show - Return the Emulex driver string with version number - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_drvr_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, LPFC_MODULE_DESC "\n"); -} - -/** - * lpfc_enable_fip_show - Return the fip mode of the HBA - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_enable_fip_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - if (phba->hba_flag & HBA_FIP_SUPPORT) - return snprintf(buf, PAGE_SIZE, "1\n"); - else - return snprintf(buf, PAGE_SIZE, "0\n"); -} - -static ssize_t -lpfc_bg_info_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - if (phba->cfg_enable_bg) - if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) - return snprintf(buf, PAGE_SIZE, "BlockGuard Enabled\n"); - else - return snprintf(buf, PAGE_SIZE, - "BlockGuard Not Supported\n"); - else - return snprintf(buf, PAGE_SIZE, - "BlockGuard Disabled\n"); -} - -static ssize_t -lpfc_bg_guard_err_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long)phba->bg_guard_err_cnt); -} - -static ssize_t -lpfc_bg_apptag_err_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long)phba->bg_apptag_err_cnt); -} - -static ssize_t -lpfc_bg_reftag_err_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long)phba->bg_reftag_err_cnt); -} - -/** - * lpfc_info_show - Return some pci info about the host in ascii - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the formatted text from lpfc_info(). - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_info_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - - return snprintf(buf, PAGE_SIZE, "%s\n",lpfc_info(host)); -} - -/** - * lpfc_serialnum_show - Return the hba serial number in ascii - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the formatted text serial number. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_serialnum_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%s\n",phba->SerialNumber); -} - -/** - * lpfc_temp_sensor_show - Return the temperature sensor level - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the formatted support level. - * - * Description: - * Returns a number indicating the temperature sensor level currently - * supported, zero or one in ascii. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_temp_sensor_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - return snprintf(buf, PAGE_SIZE, "%d\n",phba->temp_sensor_support); -} - -/** - * lpfc_modeldesc_show - Return the model description of the hba - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the scsi vpd model description. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_modeldesc_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelDesc); -} - -/** - * lpfc_modelname_show - Return the model name of the hba - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the scsi vpd model name. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_modelname_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%s\n",phba->ModelName); -} - -/** - * lpfc_programtype_show - Return the program type of the hba - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the scsi vpd program type. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_programtype_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%s\n",phba->ProgramType); -} - -/** - * lpfc_mlomgmt_show - Return the Menlo Maintenance sli flag - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the Menlo Maintenance sli flag. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_mlomgmt_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%d\n", - (phba->sli.sli_flag & LPFC_MENLO_MAINT)); -} - -/** - * lpfc_vportnum_show - Return the port number in ascii of the hba - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains scsi vpd program type. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_vportnum_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%s\n",phba->Port); -} - -/** - * lpfc_fwrev_show - Return the firmware rev running in the hba - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the scsi vpd program type. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_fwrev_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint32_t if_type; - uint8_t sli_family; - char fwrev[FW_REV_STR_SIZE]; - int len; - - lpfc_decode_firmware_rev(phba, fwrev, 1); - if_type = phba->sli4_hba.pc_sli4_params.if_type; - sli_family = phba->sli4_hba.pc_sli4_params.sli_family; - - if (phba->sli_rev < LPFC_SLI_REV4) - len = snprintf(buf, PAGE_SIZE, "%s, sli-%d\n", - fwrev, phba->sli_rev); - else - len = snprintf(buf, PAGE_SIZE, "%s, sli-%d:%d:%x\n", - fwrev, phba->sli_rev, if_type, sli_family); - - return len; -} - -/** - * lpfc_hdw_show - Return the jedec information about the hba - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the scsi vpd program type. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_hdw_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - char hdw[9]; - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - lpfc_vpd_t *vp = &phba->vpd; - - lpfc_jedec_to_ascii(vp->rev.biuRev, hdw); - return snprintf(buf, PAGE_SIZE, "%s\n", hdw); -} - -/** - * lpfc_option_rom_version_show - Return the adapter ROM FCode version - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the ROM and FCode ascii strings. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_option_rom_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%s\n", phba->OptionROMVersion); -} - -/** - * lpfc_state_show - Return the link state of the port - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains text describing the state of the link. - * - * Notes: - * The switch statement has no default so zero will be returned. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_link_state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int len = 0; - - switch (phba->link_state) { - case LPFC_LINK_UNKNOWN: - case LPFC_WARM_START: - case LPFC_INIT_START: - case LPFC_INIT_MBX_CMDS: - case LPFC_LINK_DOWN: - case LPFC_HBA_ERROR: - if (phba->hba_flag & LINK_DISABLED) - len += snprintf(buf + len, PAGE_SIZE-len, - "Link Down - User disabled\n"); - else - len += snprintf(buf + len, PAGE_SIZE-len, - "Link Down\n"); - break; - case LPFC_LINK_UP: - case LPFC_CLEAR_LA: - case LPFC_HBA_READY: - len += snprintf(buf + len, PAGE_SIZE-len, "Link Up - "); - - switch (vport->port_state) { - case LPFC_LOCAL_CFG_LINK: - len += snprintf(buf + len, PAGE_SIZE-len, - "Configuring Link\n"); - break; - case LPFC_FDISC: - case LPFC_FLOGI: - case LPFC_FABRIC_CFG_LINK: - case LPFC_NS_REG: - case LPFC_NS_QRY: - case LPFC_BUILD_DISC_LIST: - case LPFC_DISC_AUTH: - len += snprintf(buf + len, PAGE_SIZE - len, - "Discovery\n"); - break; - case LPFC_VPORT_READY: - len += snprintf(buf + len, PAGE_SIZE - len, "Ready\n"); - break; - - case LPFC_VPORT_FAILED: - len += snprintf(buf + len, PAGE_SIZE - len, "Failed\n"); - break; - - case LPFC_VPORT_UNKNOWN: - len += snprintf(buf + len, PAGE_SIZE - len, - "Unknown\n"); - break; - } - if (phba->sli.sli_flag & LPFC_MENLO_MAINT) - len += snprintf(buf + len, PAGE_SIZE-len, - " Menlo Maint Mode\n"); - else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - if (vport->fc_flag & FC_PUBLIC_LOOP) - len += snprintf(buf + len, PAGE_SIZE-len, - " Public Loop\n"); - else - len += snprintf(buf + len, PAGE_SIZE-len, - " Private Loop\n"); - } else { - if (vport->fc_flag & FC_FABRIC) - len += snprintf(buf + len, PAGE_SIZE-len, - " Fabric\n"); - else - len += snprintf(buf + len, PAGE_SIZE-len, - " Point-2-Point\n"); - } - } - - return len; -} - -/** - * lpfc_sli4_protocol_show - Return the fip mode of the HBA - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_sli4_protocol_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - if (phba->sli_rev < LPFC_SLI_REV4) - return snprintf(buf, PAGE_SIZE, "fc\n"); - - if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) { - if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_GE) - return snprintf(buf, PAGE_SIZE, "fcoe\n"); - if (phba->sli4_hba.lnk_info.lnk_tp == LPFC_LNK_TYPE_FC) - return snprintf(buf, PAGE_SIZE, "fc\n"); - } - return snprintf(buf, PAGE_SIZE, "unknown\n"); -} - -/** - * lpfc_link_state_store - Transition the link_state on an HBA port - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: one or more lpfc_polling_flags values. - * @count: not used. - * - * Returns: - * -EINVAL if the buffer is not "up" or "down" - * return from link state change function if non-zero - * length of the buf on success - **/ -static ssize_t -lpfc_link_state_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - int status = -EINVAL; - - if ((strncmp(buf, "up", sizeof("up") - 1) == 0) && - (phba->link_state == LPFC_LINK_DOWN)) - status = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); - else if ((strncmp(buf, "down", sizeof("down") - 1) == 0) && - (phba->link_state >= LPFC_LINK_UP)) - status = phba->lpfc_hba_down_link(phba, MBX_NOWAIT); - - if (status == 0) - return strlen(buf); - else - return status; -} - -/** - * lpfc_num_discovered_ports_show - Return sum of mapped and unmapped vports - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the sum of fc mapped and unmapped. - * - * Description: - * Returns the ascii text number of the sum of the fc mapped and unmapped - * vport counts. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_num_discovered_ports_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - - return snprintf(buf, PAGE_SIZE, "%d\n", - vport->fc_map_cnt + vport->fc_unmap_cnt); -} - -/** - * lpfc_issue_lip - Misnomer, name carried over from long ago - * @shost: Scsi_Host pointer. - * - * Description: - * Bring the link down gracefully then re-init the link. The firmware will - * re-init the fiber channel interface as required. Does not issue a LIP. - * - * Returns: - * -EPERM port offline or management commands are being blocked - * -ENOMEM cannot allocate memory for the mailbox command - * -EIO error sending the mailbox command - * zero for success - **/ -static int -lpfc_issue_lip(struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *pmboxq; - int mbxstatus = MBXERR_ERROR; - - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO)) - return -EPERM; - - pmboxq = mempool_alloc(phba->mbox_mem_pool,GFP_KERNEL); - - if (!pmboxq) - return -ENOMEM; - - memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; - pmboxq->u.mb.mbxOwner = OWN_HOST; - - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO * 2); - - if ((mbxstatus == MBX_SUCCESS) && - (pmboxq->u.mb.mbxStatus == 0 || - pmboxq->u.mb.mbxStatus == MBXERR_LINK_DOWN)) { - memset((void *)pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - lpfc_init_link(phba, pmboxq, phba->cfg_topology, - phba->cfg_link_speed); - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, - phba->fc_ratov * 2); - if ((mbxstatus == MBX_SUCCESS) && - (pmboxq->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION)) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2859 SLI authentication is required " - "for INIT_LINK but has not done yet\n"); - } - - lpfc_set_loopback_flag(phba); - if (mbxstatus != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - - if (mbxstatus == MBXERR_ERROR) - return -EIO; - - return 0; -} - -/** - * lpfc_do_offline - Issues a mailbox command to bring the link down - * @phba: lpfc_hba pointer. - * @type: LPFC_EVT_OFFLINE, LPFC_EVT_WARM_START, LPFC_EVT_KILL. - * - * Notes: - * Assumes any error from lpfc_do_offline() will be negative. - * Can wait up to 5 seconds for the port ring buffers count - * to reach zero, prints a warning if it is not zero and continues. - * lpfc_workq_post_event() returns a non-zero return code if call fails. - * - * Returns: - * -EIO error posting the event - * zero for success - **/ -static int -lpfc_do_offline(struct lpfc_hba *phba, uint32_t type) -{ - struct completion online_compl; - struct lpfc_sli_ring *pring; - struct lpfc_sli *psli; - int status = 0; - int cnt = 0; - int i; - int rc; - - init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_OFFLINE_PREP); - if (rc == 0) - return -ENOMEM; - - wait_for_completion(&online_compl); - - if (status != 0) - return -EIO; - - psli = &phba->sli; - - /* Wait a little for things to settle down, but not - * long enough for dev loss timeout to expire. - */ - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - while (pring->txcmplq_cnt) { - msleep(10); - if (cnt++ > 500) { /* 5 secs */ - lpfc_printf_log(phba, - KERN_WARNING, LOG_INIT, - "0466 Outstanding IO when " - "bringing Adapter offline\n"); - break; - } - } - } - - init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &status, &online_compl, type); - if (rc == 0) - return -ENOMEM; - - wait_for_completion(&online_compl); - - if (status != 0) - return -EIO; - - return 0; -} - -/** - * lpfc_selective_reset - Offline then onlines the port - * @phba: lpfc_hba pointer. - * - * Description: - * If the port is configured to allow a reset then the hba is brought - * offline then online. - * - * Notes: - * Assumes any error from lpfc_do_offline() will be negative. - * Do not make this function static. - * - * Returns: - * lpfc_do_offline() return code if not zero - * -EIO reset not configured or error posting the event - * zero for success - **/ -int -lpfc_selective_reset(struct lpfc_hba *phba) -{ - struct completion online_compl; - int status = 0; - int rc; - - if (!phba->cfg_enable_hba_reset) - return -EACCES; - - status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - - if (status != 0) - return status; - - init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; - - wait_for_completion(&online_compl); - - if (status != 0) - return -EIO; - - return 0; -} - -/** - * lpfc_issue_reset - Selectively resets an adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing the string "selective". - * @count: unused variable. - * - * Description: - * If the buf contains the string "selective" then lpfc_selective_reset() - * is called to perform the reset. - * - * Notes: - * Assumes any error from lpfc_selective_reset() will be negative. - * If lpfc_selective_reset() returns zero then the length of the buffer - * is returned which indicates success - * - * Returns: - * -EINVAL if the buffer does not contain the string "selective" - * length of buf if lpfc-selective_reset() if the call succeeds - * return value of lpfc_selective_reset() if the call fails -**/ -static ssize_t -lpfc_issue_reset(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int status = -EINVAL; - - if (!phba->cfg_enable_hba_reset) - return -EACCES; - - if (strncmp(buf, "selective", sizeof("selective") - 1) == 0) - status = phba->lpfc_selective_reset(phba); - - if (status == 0) - return strlen(buf); - else - return status; -} - -/** - * lpfc_sli4_pdev_status_reg_wait - Wait for pdev status register for readyness - * @phba: lpfc_hba pointer. - * - * Description: - * SLI4 interface type-2 device to wait on the sliport status register for - * the readyness after performing a firmware reset. - * - * Returns: - * zero for success, -EPERM when port does not have privilage to perform the - * reset, -EIO when port timeout from recovering from the reset. - * - * Note: - * As the caller will interpret the return code by value, be careful in making - * change or addition to return codes. - **/ -int -lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) -{ - struct lpfc_register portstat_reg = {0}; - int i; - - msleep(100); - lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, - &portstat_reg.word0); - - /* verify if privilaged for the request operation */ - if (!bf_get(lpfc_sliport_status_rn, &portstat_reg) && - !bf_get(lpfc_sliport_status_err, &portstat_reg)) - return -EPERM; - - /* wait for the SLI port firmware ready after firmware reset */ - for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) { - msleep(10); - lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, - &portstat_reg.word0); - if (!bf_get(lpfc_sliport_status_err, &portstat_reg)) - continue; - if (!bf_get(lpfc_sliport_status_rn, &portstat_reg)) - continue; - if (!bf_get(lpfc_sliport_status_rdy, &portstat_reg)) - continue; - break; - } - - if (i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT) - return 0; - else - return -EIO; -} - -/** - * lpfc_sli4_pdev_reg_request - Request physical dev to perform a register acc - * @phba: lpfc_hba pointer. - * - * Description: - * Request SLI4 interface type-2 device to perform a physical register set - * access. - * - * Returns: - * zero for success - **/ -static ssize_t -lpfc_sli4_pdev_reg_request(struct lpfc_hba *phba, uint32_t opcode) -{ - struct completion online_compl; - struct pci_dev *pdev = phba->pcidev; - uint32_t before_fc_flag; - uint32_t sriov_nr_virtfn; - uint32_t reg_val; - int status = 0, rc = 0; - int job_posted = 1, sriov_err; - - if (!phba->cfg_enable_hba_reset) - return -EACCES; - - if ((phba->sli_rev < LPFC_SLI_REV4) || - (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_2)) - return -EPERM; - - /* Keep state if we need to restore back */ - before_fc_flag = phba->pport->fc_flag; - sriov_nr_virtfn = phba->cfg_sriov_nr_virtfn; - - /* Disable SR-IOV virtual functions if enabled */ - if (phba->cfg_sriov_nr_virtfn) { - pci_disable_sriov(pdev); - phba->cfg_sriov_nr_virtfn = 0; - } - status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - - if (status != 0) - return status; - - /* wait for the device to be quiesced before firmware reset */ - msleep(100); - - reg_val = readl(phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PDEV_CTL_OFFSET); - - if (opcode == LPFC_FW_DUMP) - reg_val |= LPFC_FW_DUMP_REQUEST; - else if (opcode == LPFC_FW_RESET) - reg_val |= LPFC_CTL_PDEV_CTL_FRST; - else if (opcode == LPFC_DV_RESET) - reg_val |= LPFC_CTL_PDEV_CTL_DRST; - - writel(reg_val, phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PDEV_CTL_OFFSET); - /* flush */ - readl(phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET); - - /* delay driver action following IF_TYPE_2 reset */ - rc = lpfc_sli4_pdev_status_reg_wait(phba); - - if (rc == -EPERM) { - /* no privilage for reset */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3150 No privilage to perform the requested " - "access: x%x\n", reg_val); - } else if (rc == -EIO) { - /* reset failed, there is nothing more we can do */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3153 Fail to perform the requested " - "access: x%x\n", reg_val); - return rc; - } - - /* keep the original port state */ - if (before_fc_flag & FC_OFFLINE_MODE) - goto out; - - init_completion(&online_compl); - job_posted = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - if (!job_posted) - goto out; - - wait_for_completion(&online_compl); - -out: - /* in any case, restore the virtual functions enabled as before */ - if (sriov_nr_virtfn) { - sriov_err = - lpfc_sli_probe_sriov_nr_virtfn(phba, sriov_nr_virtfn); - if (!sriov_err) - phba->cfg_sriov_nr_virtfn = sriov_nr_virtfn; - } - - /* return proper error code */ - if (!rc) { - if (!job_posted) - rc = -ENOMEM; - else if (status) - rc = -EIO; - } - return rc; -} - -/** - * lpfc_nport_evt_cnt_show - Return the number of nport events - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the ascii number of nport events. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_nport_evt_cnt_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%d\n", phba->nport_event_cnt); -} - -/** - * lpfc_board_mode_show - Return the state of the board - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the state of the adapter. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_board_mode_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - char * state; - - if (phba->link_state == LPFC_HBA_ERROR) - state = "error"; - else if (phba->link_state == LPFC_WARM_START) - state = "warm start"; - else if (phba->link_state == LPFC_INIT_START) - state = "offline"; - else - state = "online"; - - return snprintf(buf, PAGE_SIZE, "%s\n", state); -} - -/** - * lpfc_board_mode_store - Puts the hba in online, offline, warm or error state - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing one of the strings "online", "offline", "warm" or "error". - * @count: unused variable. - * - * Returns: - * -EACCES if enable hba reset not enabled - * -EINVAL if the buffer does not contain a valid string (see above) - * -EIO if lpfc_workq_post_event() or lpfc_do_offline() fails - * buf length greater than zero indicates success - **/ -static ssize_t -lpfc_board_mode_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct completion online_compl; - char *board_mode_str = NULL; - int status = 0; - int rc; - - if (!phba->cfg_enable_hba_reset) { - status = -EACCES; - goto board_mode_out; - } - - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3050 lpfc_board_mode set to %s\n", buf); - - init_completion(&online_compl); - - if(strncmp(buf, "online", sizeof("online") - 1) == 0) { - rc = lpfc_workq_post_event(phba, &status, &online_compl, - LPFC_EVT_ONLINE); - if (rc == 0) { - status = -ENOMEM; - goto board_mode_out; - } - wait_for_completion(&online_compl); - } else if (strncmp(buf, "offline", sizeof("offline") - 1) == 0) - status = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - else if (strncmp(buf, "warm", sizeof("warm") - 1) == 0) - if (phba->sli_rev == LPFC_SLI_REV4) - status = -EINVAL; - else - status = lpfc_do_offline(phba, LPFC_EVT_WARM_START); - else if (strncmp(buf, "error", sizeof("error") - 1) == 0) - if (phba->sli_rev == LPFC_SLI_REV4) - status = -EINVAL; - else - status = lpfc_do_offline(phba, LPFC_EVT_KILL); - else if (strncmp(buf, "dump", sizeof("dump") - 1) == 0) - status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_DUMP); - else if (strncmp(buf, "fw_reset", sizeof("fw_reset") - 1) == 0) - status = lpfc_sli4_pdev_reg_request(phba, LPFC_FW_RESET); - else if (strncmp(buf, "dv_reset", sizeof("dv_reset") - 1) == 0) - status = lpfc_sli4_pdev_reg_request(phba, LPFC_DV_RESET); - else - status = -EINVAL; - -board_mode_out: - if (!status) - return strlen(buf); - else { - board_mode_str = strchr(buf, '\n'); - if (board_mode_str) - *board_mode_str = '\0'; - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3097 Failed \"%s\", status(%d), " - "fc_flag(x%x)\n", - buf, status, phba->pport->fc_flag); - return status; - } -} - -/** - * lpfc_get_hba_info - Return various bits of informaton about the adapter - * @phba: pointer to the adapter structure. - * @mxri: max xri count. - * @axri: available xri count. - * @mrpi: max rpi count. - * @arpi: available rpi count. - * @mvpi: max vpi count. - * @avpi: available vpi count. - * - * Description: - * If an integer pointer for an count is not null then the value for the - * count is returned. - * - * Returns: - * zero on error - * one for success - **/ -static int -lpfc_get_hba_info(struct lpfc_hba *phba, - uint32_t *mxri, uint32_t *axri, - uint32_t *mrpi, uint32_t *arpi, - uint32_t *mvpi, uint32_t *avpi) -{ - struct lpfc_mbx_read_config *rd_config; - LPFC_MBOXQ_t *pmboxq; - MAILBOX_t *pmb; - int rc = 0; - uint32_t max_vpi; - - /* - * prevent udev from issuing mailbox commands until the port is - * configured. - */ - if (phba->link_state < LPFC_LINK_DOWN || - !phba->mbox_mem_pool || - (phba->sli.sli_flag & LPFC_SLI_ACTIVE) == 0) - return 0; - - if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) - return 0; - - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) - return 0; - memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - - pmb = &pmboxq->u.mb; - pmb->mbxCommand = MBX_READ_CONFIG; - pmb->mbxOwner = OWN_HOST; - pmboxq->context1 = NULL; - - if (phba->pport->fc_flag & FC_OFFLINE_MODE) - rc = MBX_NOT_FINISHED; - else - rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - return 0; - } - - if (phba->sli_rev == LPFC_SLI_REV4) { - rd_config = &pmboxq->u.mqe.un.rd_config; - if (mrpi) - *mrpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config); - if (arpi) - *arpi = bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config) - - phba->sli4_hba.max_cfg_param.rpi_used; - if (mxri) - *mxri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config); - if (axri) - *axri = bf_get(lpfc_mbx_rd_conf_xri_count, rd_config) - - phba->sli4_hba.max_cfg_param.xri_used; - - /* Account for differences with SLI-3. Get vpi count from - * mailbox data and subtract one for max vpi value. - */ - max_vpi = (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) > 0) ? - (bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config) - 1) : 0; - - if (mvpi) - *mvpi = max_vpi; - if (avpi) - *avpi = max_vpi - phba->sli4_hba.max_cfg_param.vpi_used; - } else { - if (mrpi) - *mrpi = pmb->un.varRdConfig.max_rpi; - if (arpi) - *arpi = pmb->un.varRdConfig.avail_rpi; - if (mxri) - *mxri = pmb->un.varRdConfig.max_xri; - if (axri) - *axri = pmb->un.varRdConfig.avail_xri; - if (mvpi) - *mvpi = pmb->un.varRdConfig.max_vpi; - if (avpi) - *avpi = pmb->un.varRdConfig.avail_vpi; - } - - mempool_free(pmboxq, phba->mbox_mem_pool); - return 1; -} - -/** - * lpfc_max_rpi_show - Return maximum rpi - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the maximum rpi count in decimal or "Unknown". - * - * Description: - * Calls lpfc_get_hba_info() asking for just the mrpi count. - * If lpfc_get_hba_info() returns zero (failure) the buffer text is set - * to "Unknown" and the buffer length is returned, therefore the caller - * must check for "Unknown" in the buffer to detect a failure. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_max_rpi_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint32_t cnt; - - if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, NULL, NULL, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", cnt); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); -} - -/** - * lpfc_used_rpi_show - Return maximum rpi minus available rpi - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing the used rpi count in decimal or "Unknown". - * - * Description: - * Calls lpfc_get_hba_info() asking for just the mrpi and arpi counts. - * If lpfc_get_hba_info() returns zero (failure) the buffer text is set - * to "Unknown" and the buffer length is returned, therefore the caller - * must check for "Unknown" in the buffer to detect a failure. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_used_rpi_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint32_t cnt, acnt; - - if (lpfc_get_hba_info(phba, NULL, NULL, &cnt, &acnt, NULL, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); -} - -/** - * lpfc_max_xri_show - Return maximum xri - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the maximum xri count in decimal or "Unknown". - * - * Description: - * Calls lpfc_get_hba_info() asking for just the mrpi count. - * If lpfc_get_hba_info() returns zero (failure) the buffer text is set - * to "Unknown" and the buffer length is returned, therefore the caller - * must check for "Unknown" in the buffer to detect a failure. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_max_xri_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint32_t cnt; - - if (lpfc_get_hba_info(phba, &cnt, NULL, NULL, NULL, NULL, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", cnt); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); -} - -/** - * lpfc_used_xri_show - Return maximum xpi minus the available xpi - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the used xri count in decimal or "Unknown". - * - * Description: - * Calls lpfc_get_hba_info() asking for just the mxri and axri counts. - * If lpfc_get_hba_info() returns zero (failure) the buffer text is set - * to "Unknown" and the buffer length is returned, therefore the caller - * must check for "Unknown" in the buffer to detect a failure. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_used_xri_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint32_t cnt, acnt; - - if (lpfc_get_hba_info(phba, &cnt, &acnt, NULL, NULL, NULL, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); -} - -/** - * lpfc_max_vpi_show - Return maximum vpi - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the maximum vpi count in decimal or "Unknown". - * - * Description: - * Calls lpfc_get_hba_info() asking for just the mvpi count. - * If lpfc_get_hba_info() returns zero (failure) the buffer text is set - * to "Unknown" and the buffer length is returned, therefore the caller - * must check for "Unknown" in the buffer to detect a failure. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_max_vpi_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint32_t cnt; - - if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, NULL)) - return snprintf(buf, PAGE_SIZE, "%d\n", cnt); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); -} - -/** - * lpfc_used_vpi_show - Return maximum vpi minus the available vpi - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the used vpi count in decimal or "Unknown". - * - * Description: - * Calls lpfc_get_hba_info() asking for just the mvpi and avpi counts. - * If lpfc_get_hba_info() returns zero (failure) the buffer text is set - * to "Unknown" and the buffer length is returned, therefore the caller - * must check for "Unknown" in the buffer to detect a failure. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_used_vpi_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint32_t cnt, acnt; - - if (lpfc_get_hba_info(phba, NULL, NULL, NULL, NULL, &cnt, &acnt)) - return snprintf(buf, PAGE_SIZE, "%d\n", (cnt - acnt)); - return snprintf(buf, PAGE_SIZE, "Unknown\n"); -} - -/** - * lpfc_npiv_info_show - Return text about NPIV support for the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: text that must be interpreted to determine if npiv is supported. - * - * Description: - * Buffer will contain text indicating npiv is not suppoerted on the port, - * the port is an NPIV physical port, or it is an npiv virtual port with - * the id of the vport. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_npiv_info_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - if (!(phba->max_vpi)) - return snprintf(buf, PAGE_SIZE, "NPIV Not Supported\n"); - if (vport->port_type == LPFC_PHYSICAL_PORT) - return snprintf(buf, PAGE_SIZE, "NPIV Physical\n"); - return snprintf(buf, PAGE_SIZE, "NPIV Virtual (VPI %d)\n", vport->vpi); -} - -/** - * lpfc_poll_show - Return text about poll support for the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the cfg_poll in hex. - * - * Notes: - * cfg_poll should be a lpfc_polling_flags type. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_poll_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%#x\n", phba->cfg_poll); -} - -/** - * lpfc_poll_store - Set the value of cfg_poll for the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: one or more lpfc_polling_flags values. - * @count: not used. - * - * Notes: - * buf contents converted to integer and checked for a valid value. - * - * Returns: - * -EINVAL if the buffer connot be converted or is out of range - * length of the buf on success - **/ -static ssize_t -lpfc_poll_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint32_t creg_val; - uint32_t old_val; - int val=0; - - if (!isdigit(buf[0])) - return -EINVAL; - - if (sscanf(buf, "%i", &val) != 1) - return -EINVAL; - - if ((val & 0x3) != val) - return -EINVAL; - - if (phba->sli_rev == LPFC_SLI_REV4) - val = 0; - - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3051 lpfc_poll changed from %d to %d\n", - phba->cfg_poll, val); - - spin_lock_irq(&phba->hbalock); - - old_val = phba->cfg_poll; - - if (val & ENABLE_FCP_RING_POLLING) { - if ((val & DISABLE_FCP_RING_INT) && - !(old_val & DISABLE_FCP_RING_INT)) { - if (lpfc_readl(phba->HCregaddr, &creg_val)) { - spin_unlock_irq(&phba->hbalock); - return -EINVAL; - } - creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING); - writel(creg_val, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - - lpfc_poll_start_timer(phba); - } - } else if (val != 0x0) { - spin_unlock_irq(&phba->hbalock); - return -EINVAL; - } - - if (!(val & DISABLE_FCP_RING_INT) && - (old_val & DISABLE_FCP_RING_INT)) - { - spin_unlock_irq(&phba->hbalock); - del_timer(&phba->fcp_poll_timer); - spin_lock_irq(&phba->hbalock); - if (lpfc_readl(phba->HCregaddr, &creg_val)) { - spin_unlock_irq(&phba->hbalock); - return -EINVAL; - } - creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); - writel(creg_val, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - - phba->cfg_poll = val; - - spin_unlock_irq(&phba->hbalock); - - return strlen(buf); -} - -/** - * lpfc_fips_level_show - Return the current FIPS level for the HBA - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_fips_level_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%d\n", phba->fips_level); -} - -/** - * lpfc_fips_rev_show - Return the FIPS Spec revision for the HBA - * @dev: class unused variable. - * @attr: device attribute, not used. - * @buf: on return contains the module description text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_fips_rev_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%d\n", phba->fips_spec_rev); -} - -/** - * lpfc_dss_show - Return the current state of dss and the configured state - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the formatted text. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_dss_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "%s - %sOperational\n", - (phba->cfg_enable_dss) ? "Enabled" : "Disabled", - (phba->sli3_options & LPFC_SLI3_DSS_ENABLED) ? - "" : "Not "); -} - -/** - * lpfc_sriov_hw_max_virtfn_show - Return maximum number of virtual functions - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the formatted support level. - * - * Description: - * Returns the maximum number of virtual functions a physical function can - * support, 0 will be returned if called on virtual function. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_sriov_hw_max_virtfn_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - uint16_t max_nr_virtfn; - - max_nr_virtfn = lpfc_sli_sriov_nr_virtfn_get(phba); - return snprintf(buf, PAGE_SIZE, "%d\n", max_nr_virtfn); -} - -/** - * lpfc_param_show - Return a cfg attribute value in decimal - * - * Description: - * Macro that given an attr e.g. hba_queue_depth expands - * into a function with the name lpfc_hba_queue_depth_show. - * - * lpfc_##attr##_show: Return the decimal value of an adapters cfg_xxx field. - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the attribute value in decimal. - * - * Returns: size of formatted string. - **/ -#define lpfc_param_show(attr) \ -static ssize_t \ -lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct Scsi_Host *shost = class_to_shost(dev);\ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - struct lpfc_hba *phba = vport->phba;\ - uint val = 0;\ - val = phba->cfg_##attr;\ - return snprintf(buf, PAGE_SIZE, "%d\n",\ - phba->cfg_##attr);\ -} - -/** - * lpfc_param_hex_show - Return a cfg attribute value in hex - * - * Description: - * Macro that given an attr e.g. hba_queue_depth expands - * into a function with the name lpfc_hba_queue_depth_show - * - * lpfc_##attr##_show: Return the hex value of an adapters cfg_xxx field. - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the attribute value in hexadecimal. - * - * Returns: size of formatted string. - **/ -#define lpfc_param_hex_show(attr) \ -static ssize_t \ -lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct Scsi_Host *shost = class_to_shost(dev);\ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - struct lpfc_hba *phba = vport->phba;\ - uint val = 0;\ - val = phba->cfg_##attr;\ - return snprintf(buf, PAGE_SIZE, "%#x\n",\ - phba->cfg_##attr);\ -} - -/** - * lpfc_param_init - Initializes a cfg attribute - * - * Description: - * Macro that given an attr e.g. hba_queue_depth expands - * into a function with the name lpfc_hba_queue_depth_init. The macro also - * takes a default argument, a minimum and maximum argument. - * - * lpfc_##attr##_init: Initializes an attribute. - * @phba: pointer the the adapter structure. - * @val: integer attribute value. - * - * Validates the min and max values then sets the adapter config field - * accordingly, or uses the default if out of range and prints an error message. - * - * Returns: - * zero on success - * -EINVAL if default used - **/ -#define lpfc_param_init(attr, default, minval, maxval) \ -static int \ -lpfc_##attr##_init(struct lpfc_hba *phba, uint val) \ -{ \ - if (val >= minval && val <= maxval) {\ - phba->cfg_##attr = val;\ - return 0;\ - }\ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ - "0449 lpfc_"#attr" attribute cannot be set to %d, "\ - "allowed range is ["#minval", "#maxval"]\n", val); \ - phba->cfg_##attr = default;\ - return -EINVAL;\ -} - -/** - * lpfc_param_set - Set a cfg attribute value - * - * Description: - * Macro that given an attr e.g. hba_queue_depth expands - * into a function with the name lpfc_hba_queue_depth_set - * - * lpfc_##attr##_set: Sets an attribute value. - * @phba: pointer the the adapter structure. - * @val: integer attribute value. - * - * Description: - * Validates the min and max values then sets the - * adapter config field if in the valid range. prints error message - * and does not set the parameter if invalid. - * - * Returns: - * zero on success - * -EINVAL if val is invalid - **/ -#define lpfc_param_set(attr, default, minval, maxval) \ -static int \ -lpfc_##attr##_set(struct lpfc_hba *phba, uint val) \ -{ \ - if (val >= minval && val <= maxval) {\ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ - "3052 lpfc_" #attr " changed from %d to %d\n", \ - phba->cfg_##attr, val); \ - phba->cfg_##attr = val;\ - return 0;\ - }\ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, \ - "0450 lpfc_"#attr" attribute cannot be set to %d, "\ - "allowed range is ["#minval", "#maxval"]\n", val); \ - return -EINVAL;\ -} - -/** - * lpfc_param_store - Set a vport attribute value - * - * Description: - * Macro that given an attr e.g. hba_queue_depth expands - * into a function with the name lpfc_hba_queue_depth_store. - * - * lpfc_##attr##_store: Set an sttribute value. - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: contains the attribute value in ascii. - * @count: not used. - * - * Description: - * Convert the ascii text number to an integer, then - * use the lpfc_##attr##_set function to set the value. - * - * Returns: - * -EINVAL if val is invalid or lpfc_##attr##_set() fails - * length of buffer upon success. - **/ -#define lpfc_param_store(attr) \ -static ssize_t \ -lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct Scsi_Host *shost = class_to_shost(dev);\ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - struct lpfc_hba *phba = vport->phba;\ - uint val = 0;\ - if (!isdigit(buf[0]))\ - return -EINVAL;\ - if (sscanf(buf, "%i", &val) != 1)\ - return -EINVAL;\ - if (lpfc_##attr##_set(phba, val) == 0) \ - return strlen(buf);\ - else \ - return -EINVAL;\ -} - -/** - * lpfc_vport_param_show - Return decimal formatted cfg attribute value - * - * Description: - * Macro that given an attr e.g. hba_queue_depth expands - * into a function with the name lpfc_hba_queue_depth_show - * - * lpfc_##attr##_show: prints the attribute value in decimal. - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the attribute value in decimal. - * - * Returns: length of formatted string. - **/ -#define lpfc_vport_param_show(attr) \ -static ssize_t \ -lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct Scsi_Host *shost = class_to_shost(dev);\ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - uint val = 0;\ - val = vport->cfg_##attr;\ - return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_##attr);\ -} - -/** - * lpfc_vport_param_hex_show - Return hex formatted attribute value - * - * Description: - * Macro that given an attr e.g. - * hba_queue_depth expands into a function with the name - * lpfc_hba_queue_depth_show - * - * lpfc_##attr##_show: prints the attribute value in hexadecimal. - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the attribute value in hexadecimal. - * - * Returns: length of formatted string. - **/ -#define lpfc_vport_param_hex_show(attr) \ -static ssize_t \ -lpfc_##attr##_show(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct Scsi_Host *shost = class_to_shost(dev);\ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - uint val = 0;\ - val = vport->cfg_##attr;\ - return snprintf(buf, PAGE_SIZE, "%#x\n", vport->cfg_##attr);\ -} - -/** - * lpfc_vport_param_init - Initialize a vport cfg attribute - * - * Description: - * Macro that given an attr e.g. hba_queue_depth expands - * into a function with the name lpfc_hba_queue_depth_init. The macro also - * takes a default argument, a minimum and maximum argument. - * - * lpfc_##attr##_init: validates the min and max values then sets the - * adapter config field accordingly, or uses the default if out of range - * and prints an error message. - * @phba: pointer the the adapter structure. - * @val: integer attribute value. - * - * Returns: - * zero on success - * -EINVAL if default used - **/ -#define lpfc_vport_param_init(attr, default, minval, maxval) \ -static int \ -lpfc_##attr##_init(struct lpfc_vport *vport, uint val) \ -{ \ - if (val >= minval && val <= maxval) {\ - vport->cfg_##attr = val;\ - return 0;\ - }\ - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ - "0423 lpfc_"#attr" attribute cannot be set to %d, "\ - "allowed range is ["#minval", "#maxval"]\n", val); \ - vport->cfg_##attr = default;\ - return -EINVAL;\ -} - -/** - * lpfc_vport_param_set - Set a vport cfg attribute - * - * Description: - * Macro that given an attr e.g. hba_queue_depth expands - * into a function with the name lpfc_hba_queue_depth_set - * - * lpfc_##attr##_set: validates the min and max values then sets the - * adapter config field if in the valid range. prints error message - * and does not set the parameter if invalid. - * @phba: pointer the the adapter structure. - * @val: integer attribute value. - * - * Returns: - * zero on success - * -EINVAL if val is invalid - **/ -#define lpfc_vport_param_set(attr, default, minval, maxval) \ -static int \ -lpfc_##attr##_set(struct lpfc_vport *vport, uint val) \ -{ \ - if (val >= minval && val <= maxval) {\ - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ - "3053 lpfc_" #attr " changed from %d to %d\n", \ - vport->cfg_##attr, val); \ - vport->cfg_##attr = val;\ - return 0;\ - }\ - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, \ - "0424 lpfc_"#attr" attribute cannot be set to %d, "\ - "allowed range is ["#minval", "#maxval"]\n", val); \ - return -EINVAL;\ -} - -/** - * lpfc_vport_param_store - Set a vport attribute - * - * Description: - * Macro that given an attr e.g. hba_queue_depth - * expands into a function with the name lpfc_hba_queue_depth_store - * - * lpfc_##attr##_store: convert the ascii text number to an integer, then - * use the lpfc_##attr##_set function to set the value. - * @cdev: class device that is converted into a Scsi_host. - * @buf: contains the attribute value in decimal. - * @count: not used. - * - * Returns: - * -EINVAL if val is invalid or lpfc_##attr##_set() fails - * length of buffer upon success. - **/ -#define lpfc_vport_param_store(attr) \ -static ssize_t \ -lpfc_##attr##_store(struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct Scsi_Host *shost = class_to_shost(dev);\ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata;\ - uint val = 0;\ - if (!isdigit(buf[0]))\ - return -EINVAL;\ - if (sscanf(buf, "%i", &val) != 1)\ - return -EINVAL;\ - if (lpfc_##attr##_set(vport, val) == 0) \ - return strlen(buf);\ - else \ - return -EINVAL;\ -} - - -#define LPFC_ATTR(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_init(name, defval, minval, maxval) - -#define LPFC_ATTR_R(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_show(name)\ -lpfc_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_ATTR_RW(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_show(name)\ -lpfc_param_init(name, defval, minval, maxval)\ -lpfc_param_set(name, defval, minval, maxval)\ -lpfc_param_store(name)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ - lpfc_##name##_show, lpfc_##name##_store) - -#define LPFC_ATTR_HEX_R(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_hex_show(name)\ -lpfc_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_param_hex_show(name)\ -lpfc_param_init(name, defval, minval, maxval)\ -lpfc_param_set(name, defval, minval, maxval)\ -lpfc_param_store(name)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ - lpfc_##name##_show, lpfc_##name##_store) - -#define LPFC_VPORT_ATTR(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_init(name, defval, minval, maxval) - -#define LPFC_VPORT_ATTR_R(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_VPORT_ATTR_RW(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -lpfc_vport_param_set(name, defval, minval, maxval)\ -lpfc_vport_param_store(name)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ - lpfc_##name##_show, lpfc_##name##_store) - -#define LPFC_VPORT_ATTR_HEX_R(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_hex_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO , lpfc_##name##_show, NULL) - -#define LPFC_VPORT_ATTR_HEX_RW(name, defval, minval, maxval, desc) \ -static uint lpfc_##name = defval;\ -module_param(lpfc_##name, uint, S_IRUGO);\ -MODULE_PARM_DESC(lpfc_##name, desc);\ -lpfc_vport_param_hex_show(name)\ -lpfc_vport_param_init(name, defval, minval, maxval)\ -lpfc_vport_param_set(name, defval, minval, maxval)\ -lpfc_vport_param_store(name)\ -static DEVICE_ATTR(lpfc_##name, S_IRUGO | S_IWUSR,\ - lpfc_##name##_show, lpfc_##name##_store) - -static DEVICE_ATTR(bg_info, S_IRUGO, lpfc_bg_info_show, NULL); -static DEVICE_ATTR(bg_guard_err, S_IRUGO, lpfc_bg_guard_err_show, NULL); -static DEVICE_ATTR(bg_apptag_err, S_IRUGO, lpfc_bg_apptag_err_show, NULL); -static DEVICE_ATTR(bg_reftag_err, S_IRUGO, lpfc_bg_reftag_err_show, NULL); -static DEVICE_ATTR(info, S_IRUGO, lpfc_info_show, NULL); -static DEVICE_ATTR(serialnum, S_IRUGO, lpfc_serialnum_show, NULL); -static DEVICE_ATTR(modeldesc, S_IRUGO, lpfc_modeldesc_show, NULL); -static DEVICE_ATTR(modelname, S_IRUGO, lpfc_modelname_show, NULL); -static DEVICE_ATTR(programtype, S_IRUGO, lpfc_programtype_show, NULL); -static DEVICE_ATTR(portnum, S_IRUGO, lpfc_vportnum_show, NULL); -static DEVICE_ATTR(fwrev, S_IRUGO, lpfc_fwrev_show, NULL); -static DEVICE_ATTR(hdw, S_IRUGO, lpfc_hdw_show, NULL); -static DEVICE_ATTR(link_state, S_IRUGO | S_IWUSR, lpfc_link_state_show, - lpfc_link_state_store); -static DEVICE_ATTR(option_rom_version, S_IRUGO, - lpfc_option_rom_version_show, NULL); -static DEVICE_ATTR(num_discovered_ports, S_IRUGO, - lpfc_num_discovered_ports_show, NULL); -static DEVICE_ATTR(menlo_mgmt_mode, S_IRUGO, lpfc_mlomgmt_show, NULL); -static DEVICE_ATTR(nport_evt_cnt, S_IRUGO, lpfc_nport_evt_cnt_show, NULL); -static DEVICE_ATTR(lpfc_drvr_version, S_IRUGO, lpfc_drvr_version_show, NULL); -static DEVICE_ATTR(lpfc_enable_fip, S_IRUGO, lpfc_enable_fip_show, NULL); -static DEVICE_ATTR(board_mode, S_IRUGO | S_IWUSR, - lpfc_board_mode_show, lpfc_board_mode_store); -static DEVICE_ATTR(issue_reset, S_IWUSR, NULL, lpfc_issue_reset); -static DEVICE_ATTR(max_vpi, S_IRUGO, lpfc_max_vpi_show, NULL); -static DEVICE_ATTR(used_vpi, S_IRUGO, lpfc_used_vpi_show, NULL); -static DEVICE_ATTR(max_rpi, S_IRUGO, lpfc_max_rpi_show, NULL); -static DEVICE_ATTR(used_rpi, S_IRUGO, lpfc_used_rpi_show, NULL); -static DEVICE_ATTR(max_xri, S_IRUGO, lpfc_max_xri_show, NULL); -static DEVICE_ATTR(used_xri, S_IRUGO, lpfc_used_xri_show, NULL); -static DEVICE_ATTR(npiv_info, S_IRUGO, lpfc_npiv_info_show, NULL); -static DEVICE_ATTR(lpfc_temp_sensor, S_IRUGO, lpfc_temp_sensor_show, NULL); -static DEVICE_ATTR(lpfc_fips_level, S_IRUGO, lpfc_fips_level_show, NULL); -static DEVICE_ATTR(lpfc_fips_rev, S_IRUGO, lpfc_fips_rev_show, NULL); -static DEVICE_ATTR(lpfc_dss, S_IRUGO, lpfc_dss_show, NULL); -static DEVICE_ATTR(lpfc_sriov_hw_max_virtfn, S_IRUGO, - lpfc_sriov_hw_max_virtfn_show, NULL); -static DEVICE_ATTR(protocol, S_IRUGO, lpfc_sli4_protocol_show, NULL); - -static char *lpfc_soft_wwn_key = "C99G71SL8032A"; - -/** - * lpfc_soft_wwn_enable_store - Allows setting of the wwn if the key is valid - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing the string lpfc_soft_wwn_key. - * @count: must be size of lpfc_soft_wwn_key. - * - * Returns: - * -EINVAL if the buffer does not contain lpfc_soft_wwn_key - * length of buf indicates success - **/ -static ssize_t -lpfc_soft_wwn_enable_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - unsigned int cnt = count; - - /* - * We're doing a simple sanity check for soft_wwpn setting. - * We require that the user write a specific key to enable - * the soft_wwpn attribute to be settable. Once the attribute - * is written, the enable key resets. If further updates are - * desired, the key must be written again to re-enable the - * attribute. - * - * The "key" is not secret - it is a hardcoded string shown - * here. The intent is to protect against the random user or - * application that is just writing attributes. - */ - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if ((cnt != strlen(lpfc_soft_wwn_key)) || - (strncmp(buf, lpfc_soft_wwn_key, strlen(lpfc_soft_wwn_key)) != 0)) - return -EINVAL; - - phba->soft_wwn_enable = 1; - return count; -} -static DEVICE_ATTR(lpfc_soft_wwn_enable, S_IWUSR, NULL, - lpfc_soft_wwn_enable_store); - -/** - * lpfc_soft_wwpn_show - Return the cfg soft ww port name of the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the wwpn in hexadecimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_soft_wwpn_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - return snprintf(buf, PAGE_SIZE, "0x%llx\n", - (unsigned long long)phba->cfg_soft_wwpn); -} - -/** - * lpfc_soft_wwpn_store - Set the ww port name of the adapter - * @dev class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: contains the wwpn in hexadecimal. - * @count: number of wwpn bytes in buf - * - * Returns: - * -EACCES hba reset not enabled, adapter over temp - * -EINVAL soft wwn not enabled, count is invalid, invalid wwpn byte invalid - * -EIO error taking adapter offline or online - * value of count on success - **/ -static ssize_t -lpfc_soft_wwpn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct completion online_compl; - int stat1=0, stat2=0; - unsigned int i, j, cnt=count; - u8 wwpn[8]; - int rc; - - if (!phba->cfg_enable_hba_reset) - return -EACCES; - spin_lock_irq(&phba->hbalock); - if (phba->over_temp_state == HBA_OVER_TEMP) { - spin_unlock_irq(&phba->hbalock); - return -EACCES; - } - spin_unlock_irq(&phba->hbalock); - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) || - ((cnt == 17) && (*buf++ != 'x')) || - ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) - return -EINVAL; - - phba->soft_wwn_enable = 0; - - memset(wwpn, 0, sizeof(wwpn)); - - /* Validate and store the new name */ - for (i=0, j=0; i < 16; i++) { - int value; - - value = hex_to_bin(*buf++); - if (value >= 0) - j = (j << 4) | value; - else - return -EINVAL; - if (i % 2) { - wwpn[i/2] = j & 0xff; - j = 0; - } - } - phba->cfg_soft_wwpn = wwn_to_u64(wwpn); - fc_host_port_name(shost) = phba->cfg_soft_wwpn; - if (phba->cfg_soft_wwnn) - fc_host_node_name(shost) = phba->cfg_soft_wwnn; - - dev_printk(KERN_NOTICE, &phba->pcidev->dev, - "lpfc%d: Reinitializing to use soft_wwpn\n", phba->brd_no); - - stat1 = lpfc_do_offline(phba, LPFC_EVT_OFFLINE); - if (stat1) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0463 lpfc_soft_wwpn attribute set failed to " - "reinit adapter - %d\n", stat1); - init_completion(&online_compl); - rc = lpfc_workq_post_event(phba, &stat2, &online_compl, - LPFC_EVT_ONLINE); - if (rc == 0) - return -ENOMEM; - - wait_for_completion(&online_compl); - if (stat2) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0464 lpfc_soft_wwpn attribute set failed to " - "reinit adapter - %d\n", stat2); - return (stat1 || stat2) ? -EIO : count; -} -static DEVICE_ATTR(lpfc_soft_wwpn, S_IRUGO | S_IWUSR,\ - lpfc_soft_wwpn_show, lpfc_soft_wwpn_store); - -/** - * lpfc_soft_wwnn_show - Return the cfg soft ww node name for the adapter - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: on return contains the wwnn in hexadecimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_soft_wwnn_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - return snprintf(buf, PAGE_SIZE, "0x%llx\n", - (unsigned long long)phba->cfg_soft_wwnn); -} - -/** - * lpfc_soft_wwnn_store - sets the ww node name of the adapter - * @cdev: class device that is converted into a Scsi_host. - * @buf: contains the ww node name in hexadecimal. - * @count: number of wwnn bytes in buf. - * - * Returns: - * -EINVAL soft wwn not enabled, count is invalid, invalid wwnn byte invalid - * value of count on success - **/ -static ssize_t -lpfc_soft_wwnn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - unsigned int i, j, cnt=count; - u8 wwnn[8]; - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - if (!phba->soft_wwn_enable || (cnt < 16) || (cnt > 18) || - ((cnt == 17) && (*buf++ != 'x')) || - ((cnt == 18) && ((*buf++ != '0') || (*buf++ != 'x')))) - return -EINVAL; - - /* - * Allow wwnn to be set many times, as long as the enable is set. - * However, once the wwpn is set, everything locks. - */ - - memset(wwnn, 0, sizeof(wwnn)); - - /* Validate and store the new name */ - for (i=0, j=0; i < 16; i++) { - int value; - - value = hex_to_bin(*buf++); - if (value >= 0) - j = (j << 4) | value; - else - return -EINVAL; - if (i % 2) { - wwnn[i/2] = j & 0xff; - j = 0; - } - } - phba->cfg_soft_wwnn = wwn_to_u64(wwnn); - - dev_printk(KERN_NOTICE, &phba->pcidev->dev, - "lpfc%d: soft_wwnn set. Value will take effect upon " - "setting of the soft_wwpn\n", phba->brd_no); - - return count; -} -static DEVICE_ATTR(lpfc_soft_wwnn, S_IRUGO | S_IWUSR,\ - lpfc_soft_wwnn_show, lpfc_soft_wwnn_store); - - -static int lpfc_poll = 0; -module_param(lpfc_poll, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_poll, "FCP ring polling mode control:" - " 0 - none," - " 1 - poll with interrupts enabled" - " 3 - poll and disable FCP ring interrupts"); - -static DEVICE_ATTR(lpfc_poll, S_IRUGO | S_IWUSR, - lpfc_poll_show, lpfc_poll_store); - -int lpfc_sli_mode = 0; -module_param(lpfc_sli_mode, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_sli_mode, "SLI mode selector:" - " 0 - auto (SLI-3 if supported)," - " 2 - select SLI-2 even on SLI-3 capable HBAs," - " 3 - select SLI-3"); - -int lpfc_enable_npiv = 1; -module_param(lpfc_enable_npiv, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_enable_npiv, "Enable NPIV functionality"); -lpfc_param_show(enable_npiv); -lpfc_param_init(enable_npiv, 1, 0, 1); -static DEVICE_ATTR(lpfc_enable_npiv, S_IRUGO, lpfc_enable_npiv_show, NULL); - -LPFC_ATTR_R(fcf_failover_policy, 1, 1, 2, - "FCF Fast failover=1 Priority failover=2"); - -int lpfc_enable_rrq; -module_param(lpfc_enable_rrq, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_enable_rrq, "Enable RRQ functionality"); -lpfc_param_show(enable_rrq); -lpfc_param_init(enable_rrq, 0, 0, 1); -static DEVICE_ATTR(lpfc_enable_rrq, S_IRUGO, lpfc_enable_rrq_show, NULL); - -/* -# lpfc_suppress_link_up: Bring link up at initialization -# 0x0 = bring link up (issue MBX_INIT_LINK) -# 0x1 = do NOT bring link up at initialization(MBX_INIT_LINK) -# 0x2 = never bring up link -# Default value is 0. -*/ -LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK, - LPFC_DELAY_INIT_LINK_INDEFINITELY, - "Suppress Link Up at initialization"); -/* -# lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS -# 1 - (1024) -# 2 - (2048) -# 3 - (3072) -# 4 - (4096) -# 5 - (5120) -*/ -static ssize_t -lpfc_iocb_hw_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; - - return snprintf(buf, PAGE_SIZE, "%d\n", phba->iocb_max); -} - -static DEVICE_ATTR(iocb_hw, S_IRUGO, - lpfc_iocb_hw_show, NULL); -static ssize_t -lpfc_txq_hw_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; - - return snprintf(buf, PAGE_SIZE, "%d\n", - phba->sli.ring[LPFC_ELS_RING].txq_max); -} - -static DEVICE_ATTR(txq_hw, S_IRUGO, - lpfc_txq_hw_show, NULL); -static ssize_t -lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_hba *phba = ((struct lpfc_vport *) shost->hostdata)->phba; - - return snprintf(buf, PAGE_SIZE, "%d\n", - phba->sli.ring[LPFC_ELS_RING].txcmplq_max); -} - -static DEVICE_ATTR(txcmplq_hw, S_IRUGO, - lpfc_txcmplq_hw_show, NULL); - -int lpfc_iocb_cnt = 2; -module_param(lpfc_iocb_cnt, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_iocb_cnt, - "Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs"); -lpfc_param_show(iocb_cnt); -lpfc_param_init(iocb_cnt, 2, 1, 5); -static DEVICE_ATTR(lpfc_iocb_cnt, S_IRUGO, - lpfc_iocb_cnt_show, NULL); - -/* -# lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear -# until the timer expires. Value range is [0,255]. Default value is 30. -*/ -static int lpfc_nodev_tmo = LPFC_DEF_DEVLOSS_TMO; -static int lpfc_devloss_tmo = LPFC_DEF_DEVLOSS_TMO; -module_param(lpfc_nodev_tmo, int, 0); -MODULE_PARM_DESC(lpfc_nodev_tmo, - "Seconds driver will hold I/O waiting " - "for a device to come back"); - -/** - * lpfc_nodev_tmo_show - Return the hba dev loss timeout value - * @dev: class converted to a Scsi_host structure. - * @attr: device attribute, not used. - * @buf: on return contains the dev loss timeout in decimal. - * - * Returns: size of formatted string. - **/ -static ssize_t -lpfc_nodev_tmo_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - - return snprintf(buf, PAGE_SIZE, "%d\n", vport->cfg_devloss_tmo); -} - -/** - * lpfc_nodev_tmo_init - Set the hba nodev timeout value - * @vport: lpfc vport structure pointer. - * @val: contains the nodev timeout value. - * - * Description: - * If the devloss tmo is already set then nodev tmo is set to devloss tmo, - * a kernel error message is printed and zero is returned. - * Else if val is in range then nodev tmo and devloss tmo are set to val. - * Otherwise nodev tmo is set to the default value. - * - * Returns: - * zero if already set or if val is in range - * -EINVAL val out of range - **/ -static int -lpfc_nodev_tmo_init(struct lpfc_vport *vport, int val) -{ - if (vport->cfg_devloss_tmo != LPFC_DEF_DEVLOSS_TMO) { - vport->cfg_nodev_tmo = vport->cfg_devloss_tmo; - if (val != LPFC_DEF_DEVLOSS_TMO) - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0407 Ignoring nodev_tmo module " - "parameter because devloss_tmo is " - "set.\n"); - return 0; - } - - if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) { - vport->cfg_nodev_tmo = val; - vport->cfg_devloss_tmo = val; - return 0; - } - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0400 lpfc_nodev_tmo attribute cannot be set to" - " %d, allowed range is [%d, %d]\n", - val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO); - vport->cfg_nodev_tmo = LPFC_DEF_DEVLOSS_TMO; - return -EINVAL; -} - -/** - * lpfc_update_rport_devloss_tmo - Update dev loss tmo value - * @vport: lpfc vport structure pointer. - * - * Description: - * Update all the ndlp's dev loss tmo with the vport devloss tmo value. - **/ -static void -lpfc_update_rport_devloss_tmo(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost; - struct lpfc_nodelist *ndlp; - - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) - if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport) - ndlp->rport->dev_loss_tmo = vport->cfg_devloss_tmo; - spin_unlock_irq(shost->host_lock); -} - -/** - * lpfc_nodev_tmo_set - Set the vport nodev tmo and devloss tmo values - * @vport: lpfc vport structure pointer. - * @val: contains the tmo value. - * - * Description: - * If the devloss tmo is already set or the vport dev loss tmo has changed - * then a kernel error message is printed and zero is returned. - * Else if val is in range then nodev tmo and devloss tmo are set to val. - * Otherwise nodev tmo is set to the default value. - * - * Returns: - * zero if already set or if val is in range - * -EINVAL val out of range - **/ -static int -lpfc_nodev_tmo_set(struct lpfc_vport *vport, int val) -{ - if (vport->dev_loss_tmo_changed || - (lpfc_devloss_tmo != LPFC_DEF_DEVLOSS_TMO)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0401 Ignoring change to nodev_tmo " - "because devloss_tmo is set.\n"); - return 0; - } - if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) { - vport->cfg_nodev_tmo = val; - vport->cfg_devloss_tmo = val; - /* - * For compat: set the fc_host dev loss so new rports - * will get the value. - */ - fc_host_dev_loss_tmo(lpfc_shost_from_vport(vport)) = val; - lpfc_update_rport_devloss_tmo(vport); - return 0; - } - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0403 lpfc_nodev_tmo attribute cannot be set to" - "%d, allowed range is [%d, %d]\n", - val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO); - return -EINVAL; -} - -lpfc_vport_param_store(nodev_tmo) - -static DEVICE_ATTR(lpfc_nodev_tmo, S_IRUGO | S_IWUSR, - lpfc_nodev_tmo_show, lpfc_nodev_tmo_store); - -/* -# lpfc_devloss_tmo: If set, it will hold all I/O errors on devices that -# disappear until the timer expires. Value range is [0,255]. Default -# value is 30. -*/ -module_param(lpfc_devloss_tmo, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_devloss_tmo, - "Seconds driver will hold I/O waiting " - "for a device to come back"); -lpfc_vport_param_init(devloss_tmo, LPFC_DEF_DEVLOSS_TMO, - LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO) -lpfc_vport_param_show(devloss_tmo) - -/** - * lpfc_devloss_tmo_set - Sets vport nodev tmo, devloss tmo values, changed bit - * @vport: lpfc vport structure pointer. - * @val: contains the tmo value. - * - * Description: - * If val is in a valid range then set the vport nodev tmo, - * devloss tmo, also set the vport dev loss tmo changed flag. - * Else a kernel error message is printed. - * - * Returns: - * zero if val is in range - * -EINVAL val out of range - **/ -static int -lpfc_devloss_tmo_set(struct lpfc_vport *vport, int val) -{ - if (val >= LPFC_MIN_DEVLOSS_TMO && val <= LPFC_MAX_DEVLOSS_TMO) { - vport->cfg_nodev_tmo = val; - vport->cfg_devloss_tmo = val; - vport->dev_loss_tmo_changed = 1; - fc_host_dev_loss_tmo(lpfc_shost_from_vport(vport)) = val; - lpfc_update_rport_devloss_tmo(vport); - return 0; - } - - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0404 lpfc_devloss_tmo attribute cannot be set to" - " %d, allowed range is [%d, %d]\n", - val, LPFC_MIN_DEVLOSS_TMO, LPFC_MAX_DEVLOSS_TMO); - return -EINVAL; -} - -lpfc_vport_param_store(devloss_tmo) -static DEVICE_ATTR(lpfc_devloss_tmo, S_IRUGO | S_IWUSR, - lpfc_devloss_tmo_show, lpfc_devloss_tmo_store); - -/* -# lpfc_log_verbose: Only turn this flag on if you are willing to risk being -# deluged with LOTS of information. -# You can set a bit mask to record specific types of verbose messages: -# See lpfc_logmsh.h for definitions. -*/ -LPFC_VPORT_ATTR_HEX_RW(log_verbose, 0x0, 0x0, 0xffffffff, - "Verbose logging bit-mask"); - -/* -# lpfc_enable_da_id: This turns on the DA_ID CT command that deregisters -# objects that have been registered with the nameserver after login. -*/ -LPFC_VPORT_ATTR_R(enable_da_id, 1, 0, 1, - "Deregister nameserver objects before LOGO"); - -/* -# lun_queue_depth: This parameter is used to limit the number of outstanding -# commands per FCP LUN. Value range is [1,128]. Default value is 30. -*/ -LPFC_VPORT_ATTR_R(lun_queue_depth, 30, 1, 128, - "Max number of FCP commands we can queue to a specific LUN"); - -/* -# tgt_queue_depth: This parameter is used to limit the number of outstanding -# commands per target port. Value range is [10,65535]. Default value is 65535. -*/ -LPFC_VPORT_ATTR_R(tgt_queue_depth, 65535, 10, 65535, - "Max number of FCP commands we can queue to a specific target port"); - -/* -# hba_queue_depth: This parameter is used to limit the number of outstanding -# commands per lpfc HBA. Value range is [32,8192]. If this parameter -# value is greater than the maximum number of exchanges supported by the HBA, -# then maximum number of exchanges supported by the HBA is used to determine -# the hba_queue_depth. -*/ -LPFC_ATTR_R(hba_queue_depth, 8192, 32, 8192, - "Max number of FCP commands we can queue to a lpfc HBA"); - -/* -# peer_port_login: This parameter allows/prevents logins -# between peer ports hosted on the same physical port. -# When this parameter is set 0 peer ports of same physical port -# are not allowed to login to each other. -# When this parameter is set 1 peer ports of same physical port -# are allowed to login to each other. -# Default value of this parameter is 0. -*/ -LPFC_VPORT_ATTR_R(peer_port_login, 0, 0, 1, - "Allow peer ports on the same physical port to login to each " - "other."); - -/* -# restrict_login: This parameter allows/prevents logins -# between Virtual Ports and remote initiators. -# When this parameter is not set (0) Virtual Ports will accept PLOGIs from -# other initiators and will attempt to PLOGI all remote ports. -# When this parameter is set (1) Virtual Ports will reject PLOGIs from -# remote ports and will not attempt to PLOGI to other initiators. -# This parameter does not restrict to the physical port. -# This parameter does not restrict logins to Fabric resident remote ports. -# Default value of this parameter is 1. -*/ -static int lpfc_restrict_login = 1; -module_param(lpfc_restrict_login, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_restrict_login, - "Restrict virtual ports login to remote initiators."); -lpfc_vport_param_show(restrict_login); - -/** - * lpfc_restrict_login_init - Set the vport restrict login flag - * @vport: lpfc vport structure pointer. - * @val: contains the restrict login value. - * - * Description: - * If val is not in a valid range then log a kernel error message and set - * the vport restrict login to one. - * If the port type is physical clear the restrict login flag and return. - * Else set the restrict login flag to val. - * - * Returns: - * zero if val is in range - * -EINVAL val out of range - **/ -static int -lpfc_restrict_login_init(struct lpfc_vport *vport, int val) -{ - if (val < 0 || val > 1) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0422 lpfc_restrict_login attribute cannot " - "be set to %d, allowed range is [0, 1]\n", - val); - vport->cfg_restrict_login = 1; - return -EINVAL; - } - if (vport->port_type == LPFC_PHYSICAL_PORT) { - vport->cfg_restrict_login = 0; - return 0; - } - vport->cfg_restrict_login = val; - return 0; -} - -/** - * lpfc_restrict_login_set - Set the vport restrict login flag - * @vport: lpfc vport structure pointer. - * @val: contains the restrict login value. - * - * Description: - * If val is not in a valid range then log a kernel error message and set - * the vport restrict login to one. - * If the port type is physical and the val is not zero log a kernel - * error message, clear the restrict login flag and return zero. - * Else set the restrict login flag to val. - * - * Returns: - * zero if val is in range - * -EINVAL val out of range - **/ -static int -lpfc_restrict_login_set(struct lpfc_vport *vport, int val) -{ - if (val < 0 || val > 1) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0425 lpfc_restrict_login attribute cannot " - "be set to %d, allowed range is [0, 1]\n", - val); - vport->cfg_restrict_login = 1; - return -EINVAL; - } - if (vport->port_type == LPFC_PHYSICAL_PORT && val != 0) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0468 lpfc_restrict_login must be 0 for " - "Physical ports.\n"); - vport->cfg_restrict_login = 0; - return 0; - } - vport->cfg_restrict_login = val; - return 0; -} -lpfc_vport_param_store(restrict_login); -static DEVICE_ATTR(lpfc_restrict_login, S_IRUGO | S_IWUSR, - lpfc_restrict_login_show, lpfc_restrict_login_store); - -/* -# Some disk devices have a "select ID" or "select Target" capability. -# From a protocol standpoint "select ID" usually means select the -# Fibre channel "ALPA". In the FC-AL Profile there is an "informative -# annex" which contains a table that maps a "select ID" (a number -# between 0 and 7F) to an ALPA. By default, for compatibility with -# older drivers, the lpfc driver scans this table from low ALPA to high -# ALPA. -# -# Turning on the scan-down variable (on = 1, off = 0) will -# cause the lpfc driver to use an inverted table, effectively -# scanning ALPAs from high to low. Value range is [0,1]. Default value is 1. -# -# (Note: This "select ID" functionality is a LOOP ONLY characteristic -# and will not work across a fabric. Also this parameter will take -# effect only in the case when ALPA map is not available.) -*/ -LPFC_VPORT_ATTR_R(scan_down, 1, 0, 1, - "Start scanning for devices from highest ALPA to lowest"); - -/* -# lpfc_topology: link topology for init link -# 0x0 = attempt loop mode then point-to-point -# 0x01 = internal loopback mode -# 0x02 = attempt point-to-point mode only -# 0x04 = attempt loop mode only -# 0x06 = attempt point-to-point mode then loop -# Set point-to-point mode if you want to run as an N_Port. -# Set loop mode if you want to run as an NL_Port. Value range is [0,0x6]. -# Default value is 0. -*/ - -/** - * lpfc_topology_set - Set the adapters topology field - * @phba: lpfc_hba pointer. - * @val: topology value. - * - * Description: - * If val is in a valid range then set the adapter's topology field and - * issue a lip; if the lip fails reset the topology to the old value. - * - * If the value is not in range log a kernel error message and return an error. - * - * Returns: - * zero if val is in range and lip okay - * non-zero return value from lpfc_issue_lip() - * -EINVAL val out of range - **/ -static ssize_t -lpfc_topology_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int val = 0; - int nolip = 0; - const char *val_buf = buf; - int err; - uint32_t prev_val; - - if (!strncmp(buf, "nolip ", strlen("nolip "))) { - nolip = 1; - val_buf = &buf[strlen("nolip ")]; - } - - if (!isdigit(val_buf[0])) - return -EINVAL; - if (sscanf(val_buf, "%i", &val) != 1) - return -EINVAL; - - if (val >= 0 && val <= 6) { - prev_val = phba->cfg_topology; - phba->cfg_topology = val; - if (phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G && - val == 4) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3113 Loop mode not supported at speed %d\n", - phba->cfg_link_speed); - phba->cfg_topology = prev_val; - return -EINVAL; - } - if (nolip) - return strlen(buf); - - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3054 lpfc_topology changed from %d to %d\n", - prev_val, val); - err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); - if (err) { - phba->cfg_topology = prev_val; - return -EINVAL; - } else - return strlen(buf); - } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "%d:0467 lpfc_topology attribute cannot be set to %d, " - "allowed range is [0, 6]\n", - phba->brd_no, val); - return -EINVAL; -} -static int lpfc_topology = 0; -module_param(lpfc_topology, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_topology, "Select Fibre Channel topology"); -lpfc_param_show(topology) -lpfc_param_init(topology, 0, 0, 6) -static DEVICE_ATTR(lpfc_topology, S_IRUGO | S_IWUSR, - lpfc_topology_show, lpfc_topology_store); - -/** - * lpfc_static_vport_show: Read callback function for - * lpfc_static_vport sysfs file. - * @dev: Pointer to class device object. - * @attr: device attribute structure. - * @buf: Data buffer. - * - * This function is the read call back function for - * lpfc_static_vport sysfs file. The lpfc_static_vport - * sysfs file report the mageability of the vport. - **/ -static ssize_t -lpfc_static_vport_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - if (vport->vport_flag & STATIC_VPORT) - sprintf(buf, "1\n"); - else - sprintf(buf, "0\n"); - - return strlen(buf); -} - -/* - * Sysfs attribute to control the statistical data collection. - */ -static DEVICE_ATTR(lpfc_static_vport, S_IRUGO, - lpfc_static_vport_show, NULL); - -/** - * lpfc_stat_data_ctrl_store - write call back for lpfc_stat_data_ctrl sysfs file - * @dev: Pointer to class device. - * @buf: Data buffer. - * @count: Size of the data buffer. - * - * This function get called when an user write to the lpfc_stat_data_ctrl - * sysfs file. This function parse the command written to the sysfs file - * and take appropriate action. These commands are used for controlling - * driver statistical data collection. - * Following are the command this function handles. - * - * setbucket - * = Set the latency buckets. - * destroybucket = destroy all the buckets. - * start = start data collection - * stop = stop data collection - * reset = reset the collected data - **/ -static ssize_t -lpfc_stat_data_ctrl_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; -#define LPFC_MAX_DATA_CTRL_LEN 1024 - static char bucket_data[LPFC_MAX_DATA_CTRL_LEN]; - unsigned long i; - char *str_ptr, *token; - struct lpfc_vport **vports; - struct Scsi_Host *v_shost; - char *bucket_type_str, *base_str, *step_str; - unsigned long base, step, bucket_type; - - if (!strncmp(buf, "setbucket", strlen("setbucket"))) { - if (strlen(buf) > (LPFC_MAX_DATA_CTRL_LEN - 1)) - return -EINVAL; - - strcpy(bucket_data, buf); - str_ptr = &bucket_data[0]; - /* Ignore this token - this is command token */ - token = strsep(&str_ptr, "\t "); - if (!token) - return -EINVAL; - - bucket_type_str = strsep(&str_ptr, "\t "); - if (!bucket_type_str) - return -EINVAL; - - if (!strncmp(bucket_type_str, "linear", strlen("linear"))) - bucket_type = LPFC_LINEAR_BUCKET; - else if (!strncmp(bucket_type_str, "power2", strlen("power2"))) - bucket_type = LPFC_POWER2_BUCKET; - else - return -EINVAL; - - base_str = strsep(&str_ptr, "\t "); - if (!base_str) - return -EINVAL; - base = simple_strtoul(base_str, NULL, 0); - - step_str = strsep(&str_ptr, "\t "); - if (!step_str) - return -EINVAL; - step = simple_strtoul(step_str, NULL, 0); - if (!step) - return -EINVAL; - - /* Block the data collection for every vport */ - vports = lpfc_create_vport_work_array(phba); - if (vports == NULL) - return -ENOMEM; - - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - v_shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(v_shost->host_lock); - /* Block and reset data collection */ - vports[i]->stat_data_blocked = 1; - if (vports[i]->stat_data_enabled) - lpfc_vport_reset_stat_data(vports[i]); - spin_unlock_irq(v_shost->host_lock); - } - - /* Set the bucket attributes */ - phba->bucket_type = bucket_type; - phba->bucket_base = base; - phba->bucket_step = step; - - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - v_shost = lpfc_shost_from_vport(vports[i]); - - /* Unblock data collection */ - spin_lock_irq(v_shost->host_lock); - vports[i]->stat_data_blocked = 0; - spin_unlock_irq(v_shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); - return strlen(buf); - } - - if (!strncmp(buf, "destroybucket", strlen("destroybucket"))) { - vports = lpfc_create_vport_work_array(phba); - if (vports == NULL) - return -ENOMEM; - - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - v_shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - vports[i]->stat_data_blocked = 1; - lpfc_free_bucket(vport); - vport->stat_data_enabled = 0; - vports[i]->stat_data_blocked = 0; - spin_unlock_irq(shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); - phba->bucket_type = LPFC_NO_BUCKET; - phba->bucket_base = 0; - phba->bucket_step = 0; - return strlen(buf); - } - - if (!strncmp(buf, "start", strlen("start"))) { - /* If no buckets configured return error */ - if (phba->bucket_type == LPFC_NO_BUCKET) - return -EINVAL; - spin_lock_irq(shost->host_lock); - if (vport->stat_data_enabled) { - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - lpfc_alloc_bucket(vport); - vport->stat_data_enabled = 1; - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - - if (!strncmp(buf, "stop", strlen("stop"))) { - spin_lock_irq(shost->host_lock); - if (vport->stat_data_enabled == 0) { - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - lpfc_free_bucket(vport); - vport->stat_data_enabled = 0; - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - - if (!strncmp(buf, "reset", strlen("reset"))) { - if ((phba->bucket_type == LPFC_NO_BUCKET) - || !vport->stat_data_enabled) - return strlen(buf); - spin_lock_irq(shost->host_lock); - vport->stat_data_blocked = 1; - lpfc_vport_reset_stat_data(vport); - vport->stat_data_blocked = 0; - spin_unlock_irq(shost->host_lock); - return strlen(buf); - } - return -EINVAL; -} - - -/** - * lpfc_stat_data_ctrl_show - Read function for lpfc_stat_data_ctrl sysfs file - * @dev: Pointer to class device object. - * @buf: Data buffer. - * - * This function is the read call back function for - * lpfc_stat_data_ctrl sysfs file. This function report the - * current statistical data collection state. - **/ -static ssize_t -lpfc_stat_data_ctrl_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int index = 0; - int i; - char *bucket_type; - unsigned long bucket_value; - - switch (phba->bucket_type) { - case LPFC_LINEAR_BUCKET: - bucket_type = "linear"; - break; - case LPFC_POWER2_BUCKET: - bucket_type = "power2"; - break; - default: - bucket_type = "No Bucket"; - break; - } - - sprintf(&buf[index], "Statistical Data enabled :%d, " - "blocked :%d, Bucket type :%s, Bucket base :%d," - " Bucket step :%d\nLatency Ranges :", - vport->stat_data_enabled, vport->stat_data_blocked, - bucket_type, phba->bucket_base, phba->bucket_step); - index = strlen(buf); - if (phba->bucket_type != LPFC_NO_BUCKET) { - for (i = 0; i < LPFC_MAX_BUCKET_COUNT; i++) { - if (phba->bucket_type == LPFC_LINEAR_BUCKET) - bucket_value = phba->bucket_base + - phba->bucket_step * i; - else - bucket_value = phba->bucket_base + - (1 << i) * phba->bucket_step; - - if (index + 10 > PAGE_SIZE) - break; - sprintf(&buf[index], "%08ld ", bucket_value); - index = strlen(buf); - } - } - sprintf(&buf[index], "\n"); - return strlen(buf); -} - -/* - * Sysfs attribute to control the statistical data collection. - */ -static DEVICE_ATTR(lpfc_stat_data_ctrl, S_IRUGO | S_IWUSR, - lpfc_stat_data_ctrl_show, lpfc_stat_data_ctrl_store); - -/* - * lpfc_drvr_stat_data: sysfs attr to get driver statistical data. - */ - -/* - * Each Bucket takes 11 characters and 1 new line + 17 bytes WWN - * for each target. - */ -#define STAT_DATA_SIZE_PER_TARGET(NUM_BUCKETS) ((NUM_BUCKETS) * 11 + 18) -#define MAX_STAT_DATA_SIZE_PER_TARGET \ - STAT_DATA_SIZE_PER_TARGET(LPFC_MAX_BUCKET_COUNT) - - -/** - * sysfs_drvr_stat_data_read - Read function for lpfc_drvr_stat_data attribute - * @filp: sysfs file - * @kobj: Pointer to the kernel object - * @bin_attr: Attribute object - * @buff: Buffer pointer - * @off: File offset - * @count: Buffer size - * - * This function is the read call back function for lpfc_drvr_stat_data - * sysfs file. This function export the statistical data to user - * applications. - **/ -static ssize_t -sysfs_drvr_stat_data_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev = container_of(kobj, struct device, - kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int i = 0, index = 0; - unsigned long nport_index; - struct lpfc_nodelist *ndlp = NULL; - nport_index = (unsigned long)off / - MAX_STAT_DATA_SIZE_PER_TARGET; - - if (!vport->stat_data_enabled || vport->stat_data_blocked - || (phba->bucket_type == LPFC_NO_BUCKET)) - return 0; - - spin_lock_irq(shost->host_lock); - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || !ndlp->lat_data) - continue; - - if (nport_index > 0) { - nport_index--; - continue; - } - - if ((index + MAX_STAT_DATA_SIZE_PER_TARGET) - > count) - break; - - if (!ndlp->lat_data) - continue; - - /* Print the WWN */ - sprintf(&buf[index], "%02x%02x%02x%02x%02x%02x%02x%02x:", - ndlp->nlp_portname.u.wwn[0], - ndlp->nlp_portname.u.wwn[1], - ndlp->nlp_portname.u.wwn[2], - ndlp->nlp_portname.u.wwn[3], - ndlp->nlp_portname.u.wwn[4], - ndlp->nlp_portname.u.wwn[5], - ndlp->nlp_portname.u.wwn[6], - ndlp->nlp_portname.u.wwn[7]); - - index = strlen(buf); - - for (i = 0; i < LPFC_MAX_BUCKET_COUNT; i++) { - sprintf(&buf[index], "%010u,", - ndlp->lat_data[i].cmd_count); - index = strlen(buf); - } - sprintf(&buf[index], "\n"); - index = strlen(buf); - } - spin_unlock_irq(shost->host_lock); - return index; -} - -static struct bin_attribute sysfs_drvr_stat_data_attr = { - .attr = { - .name = "lpfc_drvr_stat_data", - .mode = S_IRUSR, - }, - .size = LPFC_MAX_TARGET * MAX_STAT_DATA_SIZE_PER_TARGET, - .read = sysfs_drvr_stat_data_read, - .write = NULL, -}; - -/* -# lpfc_link_speed: Link speed selection for initializing the Fibre Channel -# connection. -# Value range is [0,16]. Default value is 0. -*/ -/** - * lpfc_link_speed_set - Set the adapters link speed - * @phba: lpfc_hba pointer. - * @val: link speed value. - * - * Description: - * If val is in a valid range then set the adapter's link speed field and - * issue a lip; if the lip fails reset the link speed to the old value. - * - * Notes: - * If the value is not in range log a kernel error message and return an error. - * - * Returns: - * zero if val is in range and lip okay. - * non-zero return value from lpfc_issue_lip() - * -EINVAL val out of range - **/ -static ssize_t -lpfc_link_speed_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int val = LPFC_USER_LINK_SPEED_AUTO; - int nolip = 0; - const char *val_buf = buf; - int err; - uint32_t prev_val; - - if (!strncmp(buf, "nolip ", strlen("nolip "))) { - nolip = 1; - val_buf = &buf[strlen("nolip ")]; - } - - if (!isdigit(val_buf[0])) - return -EINVAL; - if (sscanf(val_buf, "%i", &val) != 1) - return -EINVAL; - - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3055 lpfc_link_speed changed from %d to %d %s\n", - phba->cfg_link_speed, val, nolip ? "(nolip)" : "(lip)"); - - if (((val == LPFC_USER_LINK_SPEED_1G) && !(phba->lmt & LMT_1Gb)) || - ((val == LPFC_USER_LINK_SPEED_2G) && !(phba->lmt & LMT_2Gb)) || - ((val == LPFC_USER_LINK_SPEED_4G) && !(phba->lmt & LMT_4Gb)) || - ((val == LPFC_USER_LINK_SPEED_8G) && !(phba->lmt & LMT_8Gb)) || - ((val == LPFC_USER_LINK_SPEED_10G) && !(phba->lmt & LMT_10Gb)) || - ((val == LPFC_USER_LINK_SPEED_16G) && !(phba->lmt & LMT_16Gb))) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2879 lpfc_link_speed attribute cannot be set " - "to %d. Speed is not supported by this port.\n", - val); - return -EINVAL; - } - if (val == LPFC_USER_LINK_SPEED_16G && - phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3112 lpfc_link_speed attribute cannot be set " - "to %d. Speed is not supported in loop mode.\n", - val); - return -EINVAL; - } - if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) && - (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) { - prev_val = phba->cfg_link_speed; - phba->cfg_link_speed = val; - if (nolip) - return strlen(buf); - - err = lpfc_issue_lip(lpfc_shost_from_vport(phba->pport)); - if (err) { - phba->cfg_link_speed = prev_val; - return -EINVAL; - } else - return strlen(buf); - } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0469 lpfc_link_speed attribute cannot be set to %d, " - "allowed values are ["LPFC_LINK_SPEED_STRING"]\n", val); - return -EINVAL; -} - -static int lpfc_link_speed = 0; -module_param(lpfc_link_speed, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_link_speed, "Select link speed"); -lpfc_param_show(link_speed) - -/** - * lpfc_link_speed_init - Set the adapters link speed - * @phba: lpfc_hba pointer. - * @val: link speed value. - * - * Description: - * If val is in a valid range then set the adapter's link speed field. - * - * Notes: - * If the value is not in range log a kernel error message, clear the link - * speed and return an error. - * - * Returns: - * zero if val saved. - * -EINVAL val out of range - **/ -static int -lpfc_link_speed_init(struct lpfc_hba *phba, int val) -{ - if (val == LPFC_USER_LINK_SPEED_16G && phba->cfg_topology == 4) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3111 lpfc_link_speed of %d cannot " - "support loop mode, setting topology to default.\n", - val); - phba->cfg_topology = 0; - } - if ((val >= 0) && (val <= LPFC_USER_LINK_SPEED_MAX) && - (LPFC_USER_LINK_SPEED_BITMAP & (1 << val))) { - phba->cfg_link_speed = val; - return 0; - } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0405 lpfc_link_speed attribute cannot " - "be set to %d, allowed values are " - "["LPFC_LINK_SPEED_STRING"]\n", val); - phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; - return -EINVAL; -} - -static DEVICE_ATTR(lpfc_link_speed, S_IRUGO | S_IWUSR, - lpfc_link_speed_show, lpfc_link_speed_store); - -/* -# lpfc_aer_support: Support PCIe device Advanced Error Reporting (AER) -# 0 = aer disabled or not supported -# 1 = aer supported and enabled (default) -# Value range is [0,1]. Default value is 1. -*/ - -/** - * lpfc_aer_support_store - Set the adapter for aer support - * - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing enable or disable aer flag. - * @count: unused variable. - * - * Description: - * If the val is 1 and currently the device's AER capability was not - * enabled, invoke the kernel's enable AER helper routine, trying to - * enable the device's AER capability. If the helper routine enabling - * AER returns success, update the device's cfg_aer_support flag to - * indicate AER is supported by the device; otherwise, if the device - * AER capability is already enabled to support AER, then do nothing. - * - * If the val is 0 and currently the device's AER support was enabled, - * invoke the kernel's disable AER helper routine. After that, update - * the device's cfg_aer_support flag to indicate AER is not supported - * by the device; otherwise, if the device AER capability is already - * disabled from supporting AER, then do nothing. - * - * Returns: - * length of the buf on success if val is in range the intended mode - * is supported. - * -EINVAL if val out of range or intended mode is not supported. - **/ -static ssize_t -lpfc_aer_support_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int val = 0, rc = -EINVAL; - - if (!isdigit(buf[0])) - return -EINVAL; - if (sscanf(buf, "%i", &val) != 1) - return -EINVAL; - - switch (val) { - case 0: - if (phba->hba_flag & HBA_AER_ENABLED) { - rc = pci_disable_pcie_error_reporting(phba->pcidev); - if (!rc) { - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~HBA_AER_ENABLED; - spin_unlock_irq(&phba->hbalock); - phba->cfg_aer_support = 0; - rc = strlen(buf); - } else - rc = -EPERM; - } else { - phba->cfg_aer_support = 0; - rc = strlen(buf); - } - break; - case 1: - if (!(phba->hba_flag & HBA_AER_ENABLED)) { - rc = pci_enable_pcie_error_reporting(phba->pcidev); - if (!rc) { - spin_lock_irq(&phba->hbalock); - phba->hba_flag |= HBA_AER_ENABLED; - spin_unlock_irq(&phba->hbalock); - phba->cfg_aer_support = 1; - rc = strlen(buf); - } else - rc = -EPERM; - } else { - phba->cfg_aer_support = 1; - rc = strlen(buf); - } - break; - default: - rc = -EINVAL; - break; - } - return rc; -} - -static int lpfc_aer_support = 1; -module_param(lpfc_aer_support, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_aer_support, "Enable PCIe device AER support"); -lpfc_param_show(aer_support) - -/** - * lpfc_aer_support_init - Set the initial adapters aer support flag - * @phba: lpfc_hba pointer. - * @val: enable aer or disable aer flag. - * - * Description: - * If val is in a valid range [0,1], then set the adapter's initial - * cfg_aer_support field. It will be up to the driver's probe_one - * routine to determine whether the device's AER support can be set - * or not. - * - * Notes: - * If the value is not in range log a kernel error message, and - * choose the default value of setting AER support and return. - * - * Returns: - * zero if val saved. - * -EINVAL val out of range - **/ -static int -lpfc_aer_support_init(struct lpfc_hba *phba, int val) -{ - if (val == 0 || val == 1) { - phba->cfg_aer_support = val; - return 0; - } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2712 lpfc_aer_support attribute value %d out " - "of range, allowed values are 0|1, setting it " - "to default value of 1\n", val); - /* By default, try to enable AER on a device */ - phba->cfg_aer_support = 1; - return -EINVAL; -} - -static DEVICE_ATTR(lpfc_aer_support, S_IRUGO | S_IWUSR, - lpfc_aer_support_show, lpfc_aer_support_store); - -/** - * lpfc_aer_cleanup_state - Clean up aer state to the aer enabled device - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing flag 1 for aer cleanup state. - * @count: unused variable. - * - * Description: - * If the @buf contains 1 and the device currently has the AER support - * enabled, then invokes the kernel AER helper routine - * pci_cleanup_aer_uncorrect_error_status to clean up the uncorrectable - * error status register. - * - * Notes: - * - * Returns: - * -EINVAL if the buf does not contain the 1 or the device is not currently - * enabled with the AER support. - **/ -static ssize_t -lpfc_aer_cleanup_state(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int val, rc = -1; - - if (!isdigit(buf[0])) - return -EINVAL; - if (sscanf(buf, "%i", &val) != 1) - return -EINVAL; - if (val != 1) - return -EINVAL; - - if (phba->hba_flag & HBA_AER_ENABLED) - rc = pci_cleanup_aer_uncorrect_error_status(phba->pcidev); - - if (rc == 0) - return strlen(buf); - else - return -EPERM; -} - -static DEVICE_ATTR(lpfc_aer_state_cleanup, S_IWUSR, NULL, - lpfc_aer_cleanup_state); - -/** - * lpfc_sriov_nr_virtfn_store - Enable the adapter for sr-iov virtual functions - * - * @dev: class device that is converted into a Scsi_host. - * @attr: device attribute, not used. - * @buf: containing the string the number of vfs to be enabled. - * @count: unused variable. - * - * Description: - * When this api is called either through user sysfs, the driver shall - * try to enable or disable SR-IOV virtual functions according to the - * following: - * - * If zero virtual function has been enabled to the physical function, - * the driver shall invoke the pci enable virtual function api trying - * to enable the virtual functions. If the nr_vfn provided is greater - * than the maximum supported, the maximum virtual function number will - * be used for invoking the api; otherwise, the nr_vfn provided shall - * be used for invoking the api. If the api call returned success, the - * actual number of virtual functions enabled will be set to the driver - * cfg_sriov_nr_virtfn; otherwise, -EINVAL shall be returned and driver - * cfg_sriov_nr_virtfn remains zero. - * - * If none-zero virtual functions have already been enabled to the - * physical function, as reflected by the driver's cfg_sriov_nr_virtfn, - * -EINVAL will be returned and the driver does nothing; - * - * If the nr_vfn provided is zero and none-zero virtual functions have - * been enabled, as indicated by the driver's cfg_sriov_nr_virtfn, the - * disabling virtual function api shall be invoded to disable all the - * virtual functions and driver's cfg_sriov_nr_virtfn shall be set to - * zero. Otherwise, if zero virtual function has been enabled, do - * nothing. - * - * Returns: - * length of the buf on success if val is in range the intended mode - * is supported. - * -EINVAL if val out of range or intended mode is not supported. - **/ -static ssize_t -lpfc_sriov_nr_virtfn_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct pci_dev *pdev = phba->pcidev; - int val = 0, rc = -EINVAL; - - /* Sanity check on user data */ - if (!isdigit(buf[0])) - return -EINVAL; - if (sscanf(buf, "%i", &val) != 1) - return -EINVAL; - if (val < 0) - return -EINVAL; - - /* Request disabling virtual functions */ - if (val == 0) { - if (phba->cfg_sriov_nr_virtfn > 0) { - pci_disable_sriov(pdev); - phba->cfg_sriov_nr_virtfn = 0; - } - return strlen(buf); - } - - /* Request enabling virtual functions */ - if (phba->cfg_sriov_nr_virtfn > 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3018 There are %d virtual functions " - "enabled on physical function.\n", - phba->cfg_sriov_nr_virtfn); - return -EEXIST; - } - - if (val <= LPFC_MAX_VFN_PER_PFN) - phba->cfg_sriov_nr_virtfn = val; - else { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3019 Enabling %d virtual functions is not " - "allowed.\n", val); - return -EINVAL; - } - - rc = lpfc_sli_probe_sriov_nr_virtfn(phba, phba->cfg_sriov_nr_virtfn); - if (rc) { - phba->cfg_sriov_nr_virtfn = 0; - rc = -EPERM; - } else - rc = strlen(buf); - - return rc; -} - -static int lpfc_sriov_nr_virtfn = LPFC_DEF_VFN_PER_PFN; -module_param(lpfc_sriov_nr_virtfn, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(lpfc_sriov_nr_virtfn, "Enable PCIe device SR-IOV virtual fn"); -lpfc_param_show(sriov_nr_virtfn) - -/** - * lpfc_sriov_nr_virtfn_init - Set the initial sr-iov virtual function enable - * @phba: lpfc_hba pointer. - * @val: link speed value. - * - * Description: - * If val is in a valid range [0,255], then set the adapter's initial - * cfg_sriov_nr_virtfn field. If it's greater than the maximum, the maximum - * number shall be used instead. It will be up to the driver's probe_one - * routine to determine whether the device's SR-IOV is supported or not. - * - * Returns: - * zero if val saved. - * -EINVAL val out of range - **/ -static int -lpfc_sriov_nr_virtfn_init(struct lpfc_hba *phba, int val) -{ - if (val >= 0 && val <= LPFC_MAX_VFN_PER_PFN) { - phba->cfg_sriov_nr_virtfn = val; - return 0; - } - - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3017 Enabling %d virtual functions is not " - "allowed.\n", val); - return -EINVAL; -} -static DEVICE_ATTR(lpfc_sriov_nr_virtfn, S_IRUGO | S_IWUSR, - lpfc_sriov_nr_virtfn_show, lpfc_sriov_nr_virtfn_store); - -/* -# lpfc_fcp_class: Determines FC class to use for the FCP protocol. -# Value range is [2,3]. Default value is 3. -*/ -LPFC_VPORT_ATTR_R(fcp_class, 3, 2, 3, - "Select Fibre Channel class of service for FCP sequences"); - -/* -# lpfc_use_adisc: Use ADISC for FCP rediscovery instead of PLOGI. Value range -# is [0,1]. Default value is 0. -*/ -LPFC_VPORT_ATTR_RW(use_adisc, 0, 0, 1, - "Use ADISC on rediscovery to authenticate FCP devices"); - -/* -# lpfc_max_scsicmpl_time: Use scsi command completion time to control I/O queue -# depth. Default value is 0. When the value of this parameter is zero the -# SCSI command completion time is not used for controlling I/O queue depth. When -# the parameter is set to a non-zero value, the I/O queue depth is controlled -# to limit the I/O completion time to the parameter value. -# The value is set in milliseconds. -*/ -static int lpfc_max_scsicmpl_time; -module_param(lpfc_max_scsicmpl_time, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_max_scsicmpl_time, - "Use command completion time to control queue depth"); -lpfc_vport_param_show(max_scsicmpl_time); -lpfc_vport_param_init(max_scsicmpl_time, 0, 0, 60000); -static int -lpfc_max_scsicmpl_time_set(struct lpfc_vport *vport, int val) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp, *next_ndlp; - - if (val == vport->cfg_max_scsicmpl_time) - return 0; - if ((val < 0) || (val > 60000)) - return -EINVAL; - vport->cfg_max_scsicmpl_time = val; - - spin_lock_irq(shost->host_lock); - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - continue; - ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; - } - spin_unlock_irq(shost->host_lock); - return 0; -} -lpfc_vport_param_store(max_scsicmpl_time); -static DEVICE_ATTR(lpfc_max_scsicmpl_time, S_IRUGO | S_IWUSR, - lpfc_max_scsicmpl_time_show, - lpfc_max_scsicmpl_time_store); - -/* -# lpfc_ack0: Use ACK0, instead of ACK1 for class 2 acknowledgement. Value -# range is [0,1]. Default value is 0. -*/ -LPFC_ATTR_R(ack0, 0, 0, 1, "Enable ACK0 support"); - -/* -# lpfc_cr_delay & lpfc_cr_count: Default values for I/O colaesing -# cr_delay (msec) or cr_count outstanding commands. cr_delay can take -# value [0,63]. cr_count can take value [1,255]. Default value of cr_delay -# is 0. Default value of cr_count is 1. The cr_count feature is disabled if -# cr_delay is set to 0. -*/ -LPFC_ATTR_RW(cr_delay, 0, 0, 63, "A count of milliseconds after which an " - "interrupt response is generated"); - -LPFC_ATTR_RW(cr_count, 1, 1, 255, "A count of I/O completions after which an " - "interrupt response is generated"); - -/* -# lpfc_multi_ring_support: Determines how many rings to spread available -# cmd/rsp IOCB entries across. -# Value range is [1,2]. Default value is 1. -*/ -LPFC_ATTR_R(multi_ring_support, 1, 1, 2, "Determines number of primary " - "SLI rings to spread IOCB entries across"); - -/* -# lpfc_multi_ring_rctl: If lpfc_multi_ring_support is enabled, this -# identifies what rctl value to configure the additional ring for. -# Value range is [1,0xff]. Default value is 4 (Unsolicated Data). -*/ -LPFC_ATTR_R(multi_ring_rctl, FC_RCTL_DD_UNSOL_DATA, 1, - 255, "Identifies RCTL for additional ring configuration"); - -/* -# lpfc_multi_ring_type: If lpfc_multi_ring_support is enabled, this -# identifies what type value to configure the additional ring for. -# Value range is [1,0xff]. Default value is 5 (LLC/SNAP). -*/ -LPFC_ATTR_R(multi_ring_type, FC_TYPE_IP, 1, - 255, "Identifies TYPE for additional ring configuration"); - -/* -# lpfc_fdmi_on: controls FDMI support. -# 0 = no FDMI support -# 1 = support FDMI without attribute of hostname -# 2 = support FDMI with attribute of hostname -# Value range [0,2]. Default value is 0. -*/ -LPFC_VPORT_ATTR_RW(fdmi_on, 0, 0, 2, "Enable FDMI support"); - -/* -# Specifies the maximum number of ELS cmds we can have outstanding (for -# discovery). Value range is [1,64]. Default value = 32. -*/ -LPFC_VPORT_ATTR(discovery_threads, 32, 1, 64, "Maximum number of ELS commands " - "during discovery"); - -/* -# lpfc_max_luns: maximum allowed LUN. -# Value range is [0,65535]. Default value is 255. -# NOTE: The SCSI layer might probe all allowed LUN on some old targets. -*/ -LPFC_VPORT_ATTR_R(max_luns, 255, 0, 65535, "Maximum allowed LUN"); - -/* -# lpfc_poll_tmo: .Milliseconds driver will wait between polling FCP ring. -# Value range is [1,255], default value is 10. -*/ -LPFC_ATTR_RW(poll_tmo, 10, 1, 255, - "Milliseconds driver will wait between polling FCP ring"); - -/* -# lpfc_use_msi: Use MSI (Message Signaled Interrupts) in systems that -# support this feature -# 0 = MSI disabled -# 1 = MSI enabled -# 2 = MSI-X enabled (default) -# Value range is [0,2]. Default value is 2. -*/ -LPFC_ATTR_R(use_msi, 2, 0, 2, "Use Message Signaled Interrupts (1) or " - "MSI-X (2), if possible"); - -/* -# lpfc_fcp_imax: Set the maximum number of fast-path FCP interrupts per second -# -# Value range is [636,651042]. Default value is 10000. -*/ -LPFC_ATTR_R(fcp_imax, LPFC_FP_DEF_IMAX, LPFC_MIM_IMAX, LPFC_DMULT_CONST, - "Set the maximum number of fast-path FCP interrupts per second"); - -/* -# lpfc_fcp_wq_count: Set the number of fast-path FCP work queues -# -# Value range is [1,31]. Default value is 4. -*/ -LPFC_ATTR_R(fcp_wq_count, LPFC_FP_WQN_DEF, LPFC_FP_WQN_MIN, LPFC_FP_WQN_MAX, - "Set the number of fast-path FCP work queues, if possible"); - -/* -# lpfc_fcp_eq_count: Set the number of fast-path FCP event queues -# -# Value range is [1,7]. Default value is 1. -*/ -LPFC_ATTR_R(fcp_eq_count, LPFC_FP_EQN_DEF, LPFC_FP_EQN_MIN, LPFC_FP_EQN_MAX, - "Set the number of fast-path FCP event queues, if possible"); - -/* -# lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. -# 0 = HBA resets disabled -# 1 = HBA resets enabled (default) -# Value range is [0,1]. Default value is 1. -*/ -LPFC_ATTR_R(enable_hba_reset, 1, 0, 1, "Enable HBA resets from the driver."); - -/* -# lpfc_enable_hba_heartbeat: Disable HBA heartbeat timer.. -# 0 = HBA Heartbeat disabled -# 1 = HBA Heartbeat enabled (default) -# Value range is [0,1]. Default value is 1. -*/ -LPFC_ATTR_R(enable_hba_heartbeat, 0, 0, 1, "Enable HBA Heartbeat."); - -/* -# lpfc_enable_bg: Enable BlockGuard (Emulex's Implementation of T10-DIF) -# 0 = BlockGuard disabled (default) -# 1 = BlockGuard enabled -# Value range is [0,1]. Default value is 0. -*/ -LPFC_ATTR_R(enable_bg, 0, 0, 1, "Enable BlockGuard Support"); - -/* -# lpfc_prot_mask: i -# - Bit mask of host protection capabilities used to register with the -# SCSI mid-layer -# - Only meaningful if BG is turned on (lpfc_enable_bg=1). -# - Allows you to ultimately specify which profiles to use -# - Default will result in registering capabilities for all profiles. -# -*/ -unsigned int lpfc_prot_mask = SHOST_DIF_TYPE1_PROTECTION | - SHOST_DIX_TYPE0_PROTECTION | - SHOST_DIX_TYPE1_PROTECTION; - -module_param(lpfc_prot_mask, uint, S_IRUGO); -MODULE_PARM_DESC(lpfc_prot_mask, "host protection mask"); - -/* -# lpfc_prot_guard: i -# - Bit mask of protection guard types to register with the SCSI mid-layer -# - Guard types are currently either 1) IP checksum 2) T10-DIF CRC -# - Allows you to ultimately specify which profiles to use -# - Default will result in registering capabilities for all guard types -# -*/ -unsigned char lpfc_prot_guard = SHOST_DIX_GUARD_IP; -module_param(lpfc_prot_guard, byte, S_IRUGO); -MODULE_PARM_DESC(lpfc_prot_guard, "host protection guard type"); - -/* - * Delay initial NPort discovery when Clean Address bit is cleared in - * FLOGI/FDISC accept and FCID/Fabric name/Fabric portname is changed. - * This parameter can have value 0 or 1. - * When this parameter is set to 0, no delay is added to the initial - * discovery. - * When this parameter is set to non-zero value, initial Nport discovery is - * delayed by ra_tov seconds when Clean Address bit is cleared in FLOGI/FDISC - * accept and FCID/Fabric name/Fabric portname is changed. - * Driver always delay Nport discovery for subsequent FLOGI/FDISC completion - * when Clean Address bit is cleared in FLOGI/FDISC - * accept and FCID/Fabric name/Fabric portname is changed. - * Default value is 0. - */ -int lpfc_delay_discovery; -module_param(lpfc_delay_discovery, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_delay_discovery, - "Delay NPort discovery when Clean Address bit is cleared. " - "Allowed values: 0,1."); - -/* - * lpfc_sg_seg_cnt - Initial Maximum DMA Segment Count - * This value can be set to values between 64 and 256. The default value is - * 64, but may be increased to allow for larger Max I/O sizes. The scsi layer - * will be allowed to request I/Os of sizes up to (MAX_SEG_COUNT * SEG_SIZE). - */ -LPFC_ATTR_R(sg_seg_cnt, LPFC_DEFAULT_SG_SEG_CNT, LPFC_DEFAULT_SG_SEG_CNT, - LPFC_MAX_SG_SEG_CNT, "Max Scatter Gather Segment Count"); - -LPFC_ATTR_R(prot_sg_seg_cnt, LPFC_DEFAULT_PROT_SG_SEG_CNT, - LPFC_DEFAULT_PROT_SG_SEG_CNT, LPFC_MAX_PROT_SG_SEG_CNT, - "Max Protection Scatter Gather Segment Count"); - -struct device_attribute *lpfc_hba_attrs[] = { - &dev_attr_bg_info, - &dev_attr_bg_guard_err, - &dev_attr_bg_apptag_err, - &dev_attr_bg_reftag_err, - &dev_attr_info, - &dev_attr_serialnum, - &dev_attr_modeldesc, - &dev_attr_modelname, - &dev_attr_programtype, - &dev_attr_portnum, - &dev_attr_fwrev, - &dev_attr_hdw, - &dev_attr_option_rom_version, - &dev_attr_link_state, - &dev_attr_num_discovered_ports, - &dev_attr_menlo_mgmt_mode, - &dev_attr_lpfc_drvr_version, - &dev_attr_lpfc_enable_fip, - &dev_attr_lpfc_temp_sensor, - &dev_attr_lpfc_log_verbose, - &dev_attr_lpfc_lun_queue_depth, - &dev_attr_lpfc_tgt_queue_depth, - &dev_attr_lpfc_hba_queue_depth, - &dev_attr_lpfc_peer_port_login, - &dev_attr_lpfc_nodev_tmo, - &dev_attr_lpfc_devloss_tmo, - &dev_attr_lpfc_fcp_class, - &dev_attr_lpfc_use_adisc, - &dev_attr_lpfc_ack0, - &dev_attr_lpfc_topology, - &dev_attr_lpfc_scan_down, - &dev_attr_lpfc_link_speed, - &dev_attr_lpfc_cr_delay, - &dev_attr_lpfc_cr_count, - &dev_attr_lpfc_multi_ring_support, - &dev_attr_lpfc_multi_ring_rctl, - &dev_attr_lpfc_multi_ring_type, - &dev_attr_lpfc_fdmi_on, - &dev_attr_lpfc_max_luns, - &dev_attr_lpfc_enable_npiv, - &dev_attr_lpfc_fcf_failover_policy, - &dev_attr_lpfc_enable_rrq, - &dev_attr_nport_evt_cnt, - &dev_attr_board_mode, - &dev_attr_max_vpi, - &dev_attr_used_vpi, - &dev_attr_max_rpi, - &dev_attr_used_rpi, - &dev_attr_max_xri, - &dev_attr_used_xri, - &dev_attr_npiv_info, - &dev_attr_issue_reset, - &dev_attr_lpfc_poll, - &dev_attr_lpfc_poll_tmo, - &dev_attr_lpfc_use_msi, - &dev_attr_lpfc_fcp_imax, - &dev_attr_lpfc_fcp_wq_count, - &dev_attr_lpfc_fcp_eq_count, - &dev_attr_lpfc_enable_bg, - &dev_attr_lpfc_soft_wwnn, - &dev_attr_lpfc_soft_wwpn, - &dev_attr_lpfc_soft_wwn_enable, - &dev_attr_lpfc_enable_hba_reset, - &dev_attr_lpfc_enable_hba_heartbeat, - &dev_attr_lpfc_sg_seg_cnt, - &dev_attr_lpfc_max_scsicmpl_time, - &dev_attr_lpfc_stat_data_ctrl, - &dev_attr_lpfc_prot_sg_seg_cnt, - &dev_attr_lpfc_aer_support, - &dev_attr_lpfc_aer_state_cleanup, - &dev_attr_lpfc_sriov_nr_virtfn, - &dev_attr_lpfc_suppress_link_up, - &dev_attr_lpfc_iocb_cnt, - &dev_attr_iocb_hw, - &dev_attr_txq_hw, - &dev_attr_txcmplq_hw, - &dev_attr_lpfc_fips_level, - &dev_attr_lpfc_fips_rev, - &dev_attr_lpfc_dss, - &dev_attr_lpfc_sriov_hw_max_virtfn, - &dev_attr_protocol, - NULL, -}; - -struct device_attribute *lpfc_vport_attrs[] = { - &dev_attr_info, - &dev_attr_link_state, - &dev_attr_num_discovered_ports, - &dev_attr_lpfc_drvr_version, - &dev_attr_lpfc_log_verbose, - &dev_attr_lpfc_lun_queue_depth, - &dev_attr_lpfc_tgt_queue_depth, - &dev_attr_lpfc_nodev_tmo, - &dev_attr_lpfc_devloss_tmo, - &dev_attr_lpfc_hba_queue_depth, - &dev_attr_lpfc_peer_port_login, - &dev_attr_lpfc_restrict_login, - &dev_attr_lpfc_fcp_class, - &dev_attr_lpfc_use_adisc, - &dev_attr_lpfc_fdmi_on, - &dev_attr_lpfc_max_luns, - &dev_attr_nport_evt_cnt, - &dev_attr_npiv_info, - &dev_attr_lpfc_enable_da_id, - &dev_attr_lpfc_max_scsicmpl_time, - &dev_attr_lpfc_stat_data_ctrl, - &dev_attr_lpfc_static_vport, - &dev_attr_lpfc_fips_level, - &dev_attr_lpfc_fips_rev, - NULL, -}; - -/** - * sysfs_ctlreg_write - Write method for writing to ctlreg - * @filp: open sysfs file - * @kobj: kernel kobject that contains the kernel class device. - * @bin_attr: kernel attributes passed to us. - * @buf: contains the data to be written to the adapter IOREG space. - * @off: offset into buffer to beginning of data. - * @count: bytes to transfer. - * - * Description: - * Accessed via /sys/class/scsi_host/hostxxx/ctlreg. - * Uses the adapter io control registers to send buf contents to the adapter. - * - * Returns: - * -ERANGE off and count combo out of range - * -EINVAL off, count or buff address invalid - * -EPERM adapter is offline - * value of count, buf contents written - **/ -static ssize_t -sysfs_ctlreg_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - size_t buf_off; - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - if (phba->sli_rev >= LPFC_SLI_REV4) - return -EPERM; - - if ((off + count) > FF_REG_AREA_SIZE) - return -ERANGE; - - if (count <= LPFC_REG_WRITE_KEY_SIZE) - return 0; - - if (off % 4 || count % 4 || (unsigned long)buf % 4) - return -EINVAL; - - /* This is to protect HBA registers from accidental writes. */ - if (memcmp(buf, LPFC_REG_WRITE_KEY, LPFC_REG_WRITE_KEY_SIZE)) - return -EINVAL; - - if (!(vport->fc_flag & FC_OFFLINE_MODE)) - return -EPERM; - - spin_lock_irq(&phba->hbalock); - for (buf_off = 0; buf_off < count - LPFC_REG_WRITE_KEY_SIZE; - buf_off += sizeof(uint32_t)) - writel(*((uint32_t *)(buf + buf_off + LPFC_REG_WRITE_KEY_SIZE)), - phba->ctrl_regs_memmap_p + off + buf_off); - - spin_unlock_irq(&phba->hbalock); - - return count; -} - -/** - * sysfs_ctlreg_read - Read method for reading from ctlreg - * @filp: open sysfs file - * @kobj: kernel kobject that contains the kernel class device. - * @bin_attr: kernel attributes passed to us. - * @buf: if successful contains the data from the adapter IOREG space. - * @off: offset into buffer to beginning of data. - * @count: bytes to transfer. - * - * Description: - * Accessed via /sys/class/scsi_host/hostxxx/ctlreg. - * Uses the adapter io control registers to read data into buf. - * - * Returns: - * -ERANGE off and count combo out of range - * -EINVAL off, count or buff address invalid - * value of count, buf contents read - **/ -static ssize_t -sysfs_ctlreg_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - size_t buf_off; - uint32_t * tmp_ptr; - struct device *dev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = class_to_shost(dev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - if (phba->sli_rev >= LPFC_SLI_REV4) - return -EPERM; - - if (off > FF_REG_AREA_SIZE) - return -ERANGE; - - if ((off + count) > FF_REG_AREA_SIZE) - count = FF_REG_AREA_SIZE - off; - - if (count == 0) return 0; - - if (off % 4 || count % 4 || (unsigned long)buf % 4) - return -EINVAL; - - spin_lock_irq(&phba->hbalock); - - for (buf_off = 0; buf_off < count; buf_off += sizeof(uint32_t)) { - tmp_ptr = (uint32_t *)(buf + buf_off); - *tmp_ptr = readl(phba->ctrl_regs_memmap_p + off + buf_off); - } - - spin_unlock_irq(&phba->hbalock); - - return count; -} - -static struct bin_attribute sysfs_ctlreg_attr = { - .attr = { - .name = "ctlreg", - .mode = S_IRUSR | S_IWUSR, - }, - .size = 256, - .read = sysfs_ctlreg_read, - .write = sysfs_ctlreg_write, -}; - -/** - * sysfs_mbox_write - Write method for writing information via mbox - * @filp: open sysfs file - * @kobj: kernel kobject that contains the kernel class device. - * @bin_attr: kernel attributes passed to us. - * @buf: contains the data to be written to sysfs mbox. - * @off: offset into buffer to beginning of data. - * @count: bytes to transfer. - * - * Description: - * Deprecated function. All mailbox access from user space is performed via the - * bsg interface. - * - * Returns: - * -EPERM operation not permitted - **/ -static ssize_t -sysfs_mbox_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - return -EPERM; -} - -/** - * sysfs_mbox_read - Read method for reading information via mbox - * @filp: open sysfs file - * @kobj: kernel kobject that contains the kernel class device. - * @bin_attr: kernel attributes passed to us. - * @buf: contains the data to be read from sysfs mbox. - * @off: offset into buffer to beginning of data. - * @count: bytes to transfer. - * - * Description: - * Deprecated function. All mailbox access from user space is performed via the - * bsg interface. - * - * Returns: - * -EPERM operation not permitted - **/ -static ssize_t -sysfs_mbox_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - return -EPERM; -} - -static struct bin_attribute sysfs_mbox_attr = { - .attr = { - .name = "mbox", - .mode = S_IRUSR | S_IWUSR, - }, - .size = MAILBOX_SYSFS_MAX, - .read = sysfs_mbox_read, - .write = sysfs_mbox_write, -}; - -/** - * lpfc_alloc_sysfs_attr - Creates the ctlreg and mbox entries - * @vport: address of lpfc vport structure. - * - * Return codes: - * zero on success - * error return code from sysfs_create_bin_file() - **/ -int -lpfc_alloc_sysfs_attr(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - int error; - - error = sysfs_create_bin_file(&shost->shost_dev.kobj, - &sysfs_drvr_stat_data_attr); - - /* Virtual ports do not need ctrl_reg and mbox */ - if (error || vport->port_type == LPFC_NPIV_PORT) - goto out; - - error = sysfs_create_bin_file(&shost->shost_dev.kobj, - &sysfs_ctlreg_attr); - if (error) - goto out_remove_stat_attr; - - error = sysfs_create_bin_file(&shost->shost_dev.kobj, - &sysfs_mbox_attr); - if (error) - goto out_remove_ctlreg_attr; - - return 0; -out_remove_ctlreg_attr: - sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); -out_remove_stat_attr: - sysfs_remove_bin_file(&shost->shost_dev.kobj, - &sysfs_drvr_stat_data_attr); -out: - return error; -} - -/** - * lpfc_free_sysfs_attr - Removes the ctlreg and mbox entries - * @vport: address of lpfc vport structure. - **/ -void -lpfc_free_sysfs_attr(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - sysfs_remove_bin_file(&shost->shost_dev.kobj, - &sysfs_drvr_stat_data_attr); - /* Virtual ports do not need ctrl_reg and mbox */ - if (vport->port_type == LPFC_NPIV_PORT) - return; - sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_mbox_attr); - sysfs_remove_bin_file(&shost->shost_dev.kobj, &sysfs_ctlreg_attr); -} - - -/* - * Dynamic FC Host Attributes Support - */ - -/** - * lpfc_get_host_port_id - Copy the vport DID into the scsi host port id - * @shost: kernel scsi host pointer. - **/ -static void -lpfc_get_host_port_id(struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - - /* note: fc_myDID already in cpu endianness */ - fc_host_port_id(shost) = vport->fc_myDID; -} - -/** - * lpfc_get_host_port_type - Set the value of the scsi host port type - * @shost: kernel scsi host pointer. - **/ -static void -lpfc_get_host_port_type(struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - spin_lock_irq(shost->host_lock); - - if (vport->port_type == LPFC_NPIV_PORT) { - fc_host_port_type(shost) = FC_PORTTYPE_NPIV; - } else if (lpfc_is_link_up(phba)) { - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - if (vport->fc_flag & FC_PUBLIC_LOOP) - fc_host_port_type(shost) = FC_PORTTYPE_NLPORT; - else - fc_host_port_type(shost) = FC_PORTTYPE_LPORT; - } else { - if (vport->fc_flag & FC_FABRIC) - fc_host_port_type(shost) = FC_PORTTYPE_NPORT; - else - fc_host_port_type(shost) = FC_PORTTYPE_PTP; - } - } else - fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN; - - spin_unlock_irq(shost->host_lock); -} - -/** - * lpfc_get_host_port_state - Set the value of the scsi host port state - * @shost: kernel scsi host pointer. - **/ -static void -lpfc_get_host_port_state(struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - spin_lock_irq(shost->host_lock); - - if (vport->fc_flag & FC_OFFLINE_MODE) - fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; - else { - switch (phba->link_state) { - case LPFC_LINK_UNKNOWN: - case LPFC_LINK_DOWN: - fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; - break; - case LPFC_LINK_UP: - case LPFC_CLEAR_LA: - case LPFC_HBA_READY: - /* Links up, reports port state accordingly */ - if (vport->port_state < LPFC_VPORT_READY) - fc_host_port_state(shost) = - FC_PORTSTATE_BYPASSED; - else - fc_host_port_state(shost) = - FC_PORTSTATE_ONLINE; - break; - case LPFC_HBA_ERROR: - fc_host_port_state(shost) = FC_PORTSTATE_ERROR; - break; - default: - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - break; - } - } - - spin_unlock_irq(shost->host_lock); -} - -/** - * lpfc_get_host_speed - Set the value of the scsi host speed - * @shost: kernel scsi host pointer. - **/ -static void -lpfc_get_host_speed(struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - - spin_lock_irq(shost->host_lock); - - if (lpfc_is_link_up(phba)) { - switch(phba->fc_linkspeed) { - case LPFC_LINK_SPEED_1GHZ: - fc_host_speed(shost) = FC_PORTSPEED_1GBIT; - break; - case LPFC_LINK_SPEED_2GHZ: - fc_host_speed(shost) = FC_PORTSPEED_2GBIT; - break; - case LPFC_LINK_SPEED_4GHZ: - fc_host_speed(shost) = FC_PORTSPEED_4GBIT; - break; - case LPFC_LINK_SPEED_8GHZ: - fc_host_speed(shost) = FC_PORTSPEED_8GBIT; - break; - case LPFC_LINK_SPEED_10GHZ: - fc_host_speed(shost) = FC_PORTSPEED_10GBIT; - break; - case LPFC_LINK_SPEED_16GHZ: - fc_host_speed(shost) = FC_PORTSPEED_16GBIT; - break; - default: - fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - break; - } - } else - fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN; - - spin_unlock_irq(shost->host_lock); -} - -/** - * lpfc_get_host_fabric_name - Set the value of the scsi host fabric name - * @shost: kernel scsi host pointer. - **/ -static void -lpfc_get_host_fabric_name (struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - u64 node_name; - - spin_lock_irq(shost->host_lock); - - if ((vport->port_state > LPFC_FLOGI) && - ((vport->fc_flag & FC_FABRIC) || - ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && - (vport->fc_flag & FC_PUBLIC_LOOP)))) - node_name = wwn_to_u64(phba->fc_fabparam.nodeName.u.wwn); - else - /* fabric is local port if there is no F/FL_Port */ - node_name = 0; - - spin_unlock_irq(shost->host_lock); - - fc_host_fabric_name(shost) = node_name; -} - -/** - * lpfc_get_stats - Return statistical information about the adapter - * @shost: kernel scsi host pointer. - * - * Notes: - * NULL on error for link down, no mbox pool, sli2 active, - * management not allowed, memory allocation error, or mbox error. - * - * Returns: - * NULL for error - * address of the adapter host statistics - **/ -static struct fc_host_statistics * -lpfc_get_stats(struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_sli *psli = &phba->sli; - struct fc_host_statistics *hs = &phba->link_stats; - struct lpfc_lnk_stat * lso = &psli->lnk_stat_offsets; - LPFC_MBOXQ_t *pmboxq; - MAILBOX_t *pmb; - unsigned long seconds; - int rc = 0; - - /* - * prevent udev from issuing mailbox commands until the port is - * configured. - */ - if (phba->link_state < LPFC_LINK_DOWN || - !phba->mbox_mem_pool || - (phba->sli.sli_flag & LPFC_SLI_ACTIVE) == 0) - return NULL; - - if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) - return NULL; - - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) - return NULL; - memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - - pmb = &pmboxq->u.mb; - pmb->mbxCommand = MBX_READ_STATUS; - pmb->mbxOwner = OWN_HOST; - pmboxq->context1 = NULL; - pmboxq->vport = vport; - - if (vport->fc_flag & FC_OFFLINE_MODE) - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - return NULL; - } - - memset(hs, 0, sizeof (struct fc_host_statistics)); - - hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt; - /* - * The MBX_READ_STATUS returns tx_k_bytes which has to - * converted to words - */ - hs->tx_words = (uint64_t) - ((uint64_t)pmb->un.varRdStatus.xmitByteCnt - * (uint64_t)256); - hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt; - hs->rx_words = (uint64_t) - ((uint64_t)pmb->un.varRdStatus.rcvByteCnt - * (uint64_t)256); - - memset(pmboxq, 0, sizeof (LPFC_MBOXQ_t)); - pmb->mbxCommand = MBX_READ_LNK_STAT; - pmb->mbxOwner = OWN_HOST; - pmboxq->context1 = NULL; - pmboxq->vport = vport; - - if (vport->fc_flag & FC_OFFLINE_MODE) - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - return NULL; - } - - hs->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; - hs->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt; - hs->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt; - hs->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt; - hs->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord; - hs->invalid_crc_count = pmb->un.varRdLnk.crcCnt; - hs->error_frames = pmb->un.varRdLnk.crcCnt; - - hs->link_failure_count -= lso->link_failure_count; - hs->loss_of_sync_count -= lso->loss_of_sync_count; - hs->loss_of_signal_count -= lso->loss_of_signal_count; - hs->prim_seq_protocol_err_count -= lso->prim_seq_protocol_err_count; - hs->invalid_tx_word_count -= lso->invalid_tx_word_count; - hs->invalid_crc_count -= lso->invalid_crc_count; - hs->error_frames -= lso->error_frames; - - if (phba->hba_flag & HBA_FCOE_MODE) { - hs->lip_count = -1; - hs->nos_count = (phba->link_events >> 1); - hs->nos_count -= lso->link_events; - } else if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - hs->lip_count = (phba->fc_eventTag >> 1); - hs->lip_count -= lso->link_events; - hs->nos_count = -1; - } else { - hs->lip_count = -1; - hs->nos_count = (phba->fc_eventTag >> 1); - hs->nos_count -= lso->link_events; - } - - hs->dumped_frames = -1; - - seconds = get_seconds(); - if (seconds < psli->stats_start) - hs->seconds_since_last_reset = seconds + - ((unsigned long)-1 - psli->stats_start); - else - hs->seconds_since_last_reset = seconds - psli->stats_start; - - mempool_free(pmboxq, phba->mbox_mem_pool); - - return hs; -} - -/** - * lpfc_reset_stats - Copy the adapter link stats information - * @shost: kernel scsi host pointer. - **/ -static void -lpfc_reset_stats(struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_lnk_stat *lso = &psli->lnk_stat_offsets; - LPFC_MBOXQ_t *pmboxq; - MAILBOX_t *pmb; - int rc = 0; - - if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) - return; - - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) - return; - memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - - pmb = &pmboxq->u.mb; - pmb->mbxCommand = MBX_READ_STATUS; - pmb->mbxOwner = OWN_HOST; - pmb->un.varWords[0] = 0x1; /* reset request */ - pmboxq->context1 = NULL; - pmboxq->vport = vport; - - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - return; - } - - memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - pmb->mbxCommand = MBX_READ_LNK_STAT; - pmb->mbxOwner = OWN_HOST; - pmboxq->context1 = NULL; - pmboxq->vport = vport; - - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - else - rc = lpfc_sli_issue_mbox_wait(phba, pmboxq, phba->fc_ratov * 2); - - if (rc != MBX_SUCCESS) { - if (rc != MBX_TIMEOUT) - mempool_free( pmboxq, phba->mbox_mem_pool); - return; - } - - lso->link_failure_count = pmb->un.varRdLnk.linkFailureCnt; - lso->loss_of_sync_count = pmb->un.varRdLnk.lossSyncCnt; - lso->loss_of_signal_count = pmb->un.varRdLnk.lossSignalCnt; - lso->prim_seq_protocol_err_count = pmb->un.varRdLnk.primSeqErrCnt; - lso->invalid_tx_word_count = pmb->un.varRdLnk.invalidXmitWord; - lso->invalid_crc_count = pmb->un.varRdLnk.crcCnt; - lso->error_frames = pmb->un.varRdLnk.crcCnt; - if (phba->hba_flag & HBA_FCOE_MODE) - lso->link_events = (phba->link_events >> 1); - else - lso->link_events = (phba->fc_eventTag >> 1); - - psli->stats_start = get_seconds(); - - mempool_free(pmboxq, phba->mbox_mem_pool); - - return; -} - -/* - * The LPFC driver treats linkdown handling as target loss events so there - * are no sysfs handlers for link_down_tmo. - */ - -/** - * lpfc_get_node_by_target - Return the nodelist for a target - * @starget: kernel scsi target pointer. - * - * Returns: - * address of the node list if found - * NULL target not found - **/ -static struct lpfc_nodelist * -lpfc_get_node_by_target(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_nodelist *ndlp; - - spin_lock_irq(shost->host_lock); - /* Search for this, mapped, target ID */ - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_MAPPED_NODE && - starget->id == ndlp->nlp_sid) { - spin_unlock_irq(shost->host_lock); - return ndlp; - } - } - spin_unlock_irq(shost->host_lock); - return NULL; -} - -/** - * lpfc_get_starget_port_id - Set the target port id to the ndlp DID or -1 - * @starget: kernel scsi target pointer. - **/ -static void -lpfc_get_starget_port_id(struct scsi_target *starget) -{ - struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget); - - fc_starget_port_id(starget) = ndlp ? ndlp->nlp_DID : -1; -} - -/** - * lpfc_get_starget_node_name - Set the target node name - * @starget: kernel scsi target pointer. - * - * Description: Set the target node name to the ndlp node name wwn or zero. - **/ -static void -lpfc_get_starget_node_name(struct scsi_target *starget) -{ - struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget); - - fc_starget_node_name(starget) = - ndlp ? wwn_to_u64(ndlp->nlp_nodename.u.wwn) : 0; -} - -/** - * lpfc_get_starget_port_name - Set the target port name - * @starget: kernel scsi target pointer. - * - * Description: set the target port name to the ndlp port name wwn or zero. - **/ -static void -lpfc_get_starget_port_name(struct scsi_target *starget) -{ - struct lpfc_nodelist *ndlp = lpfc_get_node_by_target(starget); - - fc_starget_port_name(starget) = - ndlp ? wwn_to_u64(ndlp->nlp_portname.u.wwn) : 0; -} - -/** - * lpfc_set_rport_loss_tmo - Set the rport dev loss tmo - * @rport: fc rport address. - * @timeout: new value for dev loss tmo. - * - * Description: - * If timeout is non zero set the dev_loss_tmo to timeout, else set - * dev_loss_tmo to one. - **/ -static void -lpfc_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) -{ - if (timeout) - rport->dev_loss_tmo = timeout; - else - rport->dev_loss_tmo = 1; -} - -/** - * lpfc_rport_show_function - Return rport target information - * - * Description: - * Macro that uses field to generate a function with the name lpfc_show_rport_ - * - * lpfc_show_rport_##field: returns the bytes formatted in buf - * @cdev: class converted to an fc_rport. - * @buf: on return contains the target_field or zero. - * - * Returns: size of formatted string. - **/ -#define lpfc_rport_show_function(field, format_string, sz, cast) \ -static ssize_t \ -lpfc_show_rport_##field (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct fc_rport *rport = transport_class_to_rport(dev); \ - struct lpfc_rport_data *rdata = rport->hostdata; \ - return snprintf(buf, sz, format_string, \ - (rdata->target) ? cast rdata->target->field : 0); \ -} - -#define lpfc_rport_rd_attr(field, format_string, sz) \ - lpfc_rport_show_function(field, format_string, sz, ) \ -static FC_RPORT_ATTR(field, S_IRUGO, lpfc_show_rport_##field, NULL) - -/** - * lpfc_set_vport_symbolic_name - Set the vport's symbolic name - * @fc_vport: The fc_vport who's symbolic name has been changed. - * - * Description: - * This function is called by the transport after the @fc_vport's symbolic name - * has been changed. This function re-registers the symbolic name with the - * switch to propagate the change into the fabric if the vport is active. - **/ -static void -lpfc_set_vport_symbolic_name(struct fc_vport *fc_vport) -{ - struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; - - if (vport->port_state == LPFC_VPORT_READY) - lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); -} - -/** - * lpfc_hba_log_verbose_init - Set hba's log verbose level - * @phba: Pointer to lpfc_hba struct. - * - * This function is called by the lpfc_get_cfgparam() routine to set the - * module lpfc_log_verbose into the @phba cfg_log_verbose for use with - * log message according to the module's lpfc_log_verbose parameter setting - * before hba port or vport created. - **/ -static void -lpfc_hba_log_verbose_init(struct lpfc_hba *phba, uint32_t verbose) -{ - phba->cfg_log_verbose = verbose; -} - -struct fc_function_template lpfc_transport_functions = { - /* fixed attributes the driver supports */ - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_supported_speeds = 1, - .show_host_maxframe_size = 1, - .show_host_symbolic_name = 1, - - /* dynamic attributes the driver supports */ - .get_host_port_id = lpfc_get_host_port_id, - .show_host_port_id = 1, - - .get_host_port_type = lpfc_get_host_port_type, - .show_host_port_type = 1, - - .get_host_port_state = lpfc_get_host_port_state, - .show_host_port_state = 1, - - /* active_fc4s is shown but doesn't change (thus no get function) */ - .show_host_active_fc4s = 1, - - .get_host_speed = lpfc_get_host_speed, - .show_host_speed = 1, - - .get_host_fabric_name = lpfc_get_host_fabric_name, - .show_host_fabric_name = 1, - - /* - * The LPFC driver treats linkdown handling as target loss events - * so there are no sysfs handlers for link_down_tmo. - */ - - .get_fc_host_stats = lpfc_get_stats, - .reset_fc_host_stats = lpfc_reset_stats, - - .dd_fcrport_size = sizeof(struct lpfc_rport_data), - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - - .set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - - .get_starget_port_id = lpfc_get_starget_port_id, - .show_starget_port_id = 1, - - .get_starget_node_name = lpfc_get_starget_node_name, - .show_starget_node_name = 1, - - .get_starget_port_name = lpfc_get_starget_port_name, - .show_starget_port_name = 1, - - .issue_fc_host_lip = lpfc_issue_lip, - .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk, - .terminate_rport_io = lpfc_terminate_rport_io, - - .dd_fcvport_size = sizeof(struct lpfc_vport *), - - .vport_disable = lpfc_vport_disable, - - .set_vport_symbolic_name = lpfc_set_vport_symbolic_name, - - .bsg_request = lpfc_bsg_request, - .bsg_timeout = lpfc_bsg_timeout, -}; - -struct fc_function_template lpfc_vport_transport_functions = { - /* fixed attributes the driver supports */ - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_fc4s = 1, - .show_host_supported_speeds = 1, - .show_host_maxframe_size = 1, - .show_host_symbolic_name = 1, - - /* dynamic attributes the driver supports */ - .get_host_port_id = lpfc_get_host_port_id, - .show_host_port_id = 1, - - .get_host_port_type = lpfc_get_host_port_type, - .show_host_port_type = 1, - - .get_host_port_state = lpfc_get_host_port_state, - .show_host_port_state = 1, - - /* active_fc4s is shown but doesn't change (thus no get function) */ - .show_host_active_fc4s = 1, - - .get_host_speed = lpfc_get_host_speed, - .show_host_speed = 1, - - .get_host_fabric_name = lpfc_get_host_fabric_name, - .show_host_fabric_name = 1, - - /* - * The LPFC driver treats linkdown handling as target loss events - * so there are no sysfs handlers for link_down_tmo. - */ - - .get_fc_host_stats = lpfc_get_stats, - .reset_fc_host_stats = lpfc_reset_stats, - - .dd_fcrport_size = sizeof(struct lpfc_rport_data), - .show_rport_maxframe_size = 1, - .show_rport_supported_classes = 1, - - .set_rport_dev_loss_tmo = lpfc_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - - .get_starget_port_id = lpfc_get_starget_port_id, - .show_starget_port_id = 1, - - .get_starget_node_name = lpfc_get_starget_node_name, - .show_starget_node_name = 1, - - .get_starget_port_name = lpfc_get_starget_port_name, - .show_starget_port_name = 1, - - .dev_loss_tmo_callbk = lpfc_dev_loss_tmo_callbk, - .terminate_rport_io = lpfc_terminate_rport_io, - - .vport_disable = lpfc_vport_disable, - - .set_vport_symbolic_name = lpfc_set_vport_symbolic_name, -}; - -/** - * lpfc_get_cfgparam - Used during probe_one to init the adapter structure - * @phba: lpfc_hba pointer. - **/ -void -lpfc_get_cfgparam(struct lpfc_hba *phba) -{ - lpfc_cr_delay_init(phba, lpfc_cr_delay); - lpfc_cr_count_init(phba, lpfc_cr_count); - lpfc_multi_ring_support_init(phba, lpfc_multi_ring_support); - lpfc_multi_ring_rctl_init(phba, lpfc_multi_ring_rctl); - lpfc_multi_ring_type_init(phba, lpfc_multi_ring_type); - lpfc_ack0_init(phba, lpfc_ack0); - lpfc_topology_init(phba, lpfc_topology); - lpfc_link_speed_init(phba, lpfc_link_speed); - lpfc_poll_tmo_init(phba, lpfc_poll_tmo); - lpfc_enable_npiv_init(phba, lpfc_enable_npiv); - lpfc_fcf_failover_policy_init(phba, lpfc_fcf_failover_policy); - lpfc_enable_rrq_init(phba, lpfc_enable_rrq); - lpfc_use_msi_init(phba, lpfc_use_msi); - lpfc_fcp_imax_init(phba, lpfc_fcp_imax); - lpfc_fcp_wq_count_init(phba, lpfc_fcp_wq_count); - lpfc_fcp_eq_count_init(phba, lpfc_fcp_eq_count); - lpfc_enable_hba_reset_init(phba, lpfc_enable_hba_reset); - lpfc_enable_hba_heartbeat_init(phba, lpfc_enable_hba_heartbeat); - lpfc_enable_bg_init(phba, lpfc_enable_bg); - if (phba->sli_rev == LPFC_SLI_REV4) - phba->cfg_poll = 0; - else - phba->cfg_poll = lpfc_poll; - phba->cfg_soft_wwnn = 0L; - phba->cfg_soft_wwpn = 0L; - lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); - lpfc_prot_sg_seg_cnt_init(phba, lpfc_prot_sg_seg_cnt); - lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); - lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); - lpfc_aer_support_init(phba, lpfc_aer_support); - lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn); - lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); - lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); - phba->cfg_enable_dss = 1; - return; -} - -/** - * lpfc_get_vport_cfgparam - Used during port create, init the vport structure - * @vport: lpfc_vport pointer. - **/ -void -lpfc_get_vport_cfgparam(struct lpfc_vport *vport) -{ - lpfc_log_verbose_init(vport, lpfc_log_verbose); - lpfc_lun_queue_depth_init(vport, lpfc_lun_queue_depth); - lpfc_tgt_queue_depth_init(vport, lpfc_tgt_queue_depth); - lpfc_devloss_tmo_init(vport, lpfc_devloss_tmo); - lpfc_nodev_tmo_init(vport, lpfc_nodev_tmo); - lpfc_peer_port_login_init(vport, lpfc_peer_port_login); - lpfc_restrict_login_init(vport, lpfc_restrict_login); - lpfc_fcp_class_init(vport, lpfc_fcp_class); - lpfc_use_adisc_init(vport, lpfc_use_adisc); - lpfc_max_scsicmpl_time_init(vport, lpfc_max_scsicmpl_time); - lpfc_fdmi_on_init(vport, lpfc_fdmi_on); - lpfc_discovery_threads_init(vport, lpfc_discovery_threads); - lpfc_max_luns_init(vport, lpfc_max_luns); - lpfc_scan_down_init(vport, lpfc_scan_down); - lpfc_enable_da_id_init(vport, lpfc_enable_da_id); - return; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.c deleted file mode 100644 index 141e4b40..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.c +++ /dev/null @@ -1,5195 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2011 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_bsg.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_debugfs.h" -#include "lpfc_vport.h" -#include "lpfc_version.h" - -struct lpfc_bsg_event { - struct list_head node; - struct kref kref; - wait_queue_head_t wq; - - /* Event type and waiter identifiers */ - uint32_t type_mask; - uint32_t req_id; - uint32_t reg_id; - - /* next two flags are here for the auto-delete logic */ - unsigned long wait_time_stamp; - int waiting; - - /* seen and not seen events */ - struct list_head events_to_get; - struct list_head events_to_see; - - /* job waiting for this event to finish */ - struct fc_bsg_job *set_job; -}; - -struct lpfc_bsg_iocb { - struct lpfc_iocbq *cmdiocbq; - struct lpfc_iocbq *rspiocbq; - struct lpfc_dmabuf *bmp; - struct lpfc_nodelist *ndlp; - - /* job waiting for this iocb to finish */ - struct fc_bsg_job *set_job; -}; - -struct lpfc_bsg_mbox { - LPFC_MBOXQ_t *pmboxq; - MAILBOX_t *mb; - struct lpfc_dmabuf *dmabuffers; /* for BIU diags */ - uint8_t *ext; /* extended mailbox data */ - uint32_t mbOffset; /* from app */ - uint32_t inExtWLen; /* from app */ - uint32_t outExtWLen; /* from app */ - - /* job waiting for this mbox command to finish */ - struct fc_bsg_job *set_job; -}; - -#define MENLO_DID 0x0000FC0E - -struct lpfc_bsg_menlo { - struct lpfc_iocbq *cmdiocbq; - struct lpfc_iocbq *rspiocbq; - struct lpfc_dmabuf *bmp; - - /* job waiting for this iocb to finish */ - struct fc_bsg_job *set_job; -}; - -#define TYPE_EVT 1 -#define TYPE_IOCB 2 -#define TYPE_MBOX 3 -#define TYPE_MENLO 4 -struct bsg_job_data { - uint32_t type; - union { - struct lpfc_bsg_event *evt; - struct lpfc_bsg_iocb iocb; - struct lpfc_bsg_mbox mbox; - struct lpfc_bsg_menlo menlo; - } context_un; -}; - -struct event_data { - struct list_head node; - uint32_t type; - uint32_t immed_dat; - void *data; - uint32_t len; -}; - -#define BUF_SZ_4K 4096 -#define SLI_CT_ELX_LOOPBACK 0x10 - -enum ELX_LOOPBACK_CMD { - ELX_LOOPBACK_XRI_SETUP, - ELX_LOOPBACK_DATA, -}; - -#define ELX_LOOPBACK_HEADER_SZ \ - (size_t)(&((struct lpfc_sli_ct_request *)NULL)->un) - -struct lpfc_dmabufext { - struct lpfc_dmabuf dma; - uint32_t size; - uint32_t flag; -}; - -/** - * lpfc_bsg_send_mgmt_cmd_cmp - lpfc_bsg_send_mgmt_cmd's completion handler - * @phba: Pointer to HBA context object. - * @cmdiocbq: Pointer to command iocb. - * @rspiocbq: Pointer to response iocb. - * - * This function is the completion handler for iocbs issued using - * lpfc_bsg_send_mgmt_cmd function. This function is called by the - * ring event handler function without any lock held. This function - * can be called from both worker thread context and interrupt - * context. This function also can be called from another thread which - * cleans up the SLI layer objects. - * This function copies the contents of the response iocb to the - * response iocb memory object provided by the caller of - * lpfc_sli_issue_iocb_wait and then wakes up the thread which - * sleeps for the iocb completion. - **/ -static void -lpfc_bsg_send_mgmt_cmd_cmp(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocbq, - struct lpfc_iocbq *rspiocbq) -{ - struct bsg_job_data *dd_data; - struct fc_bsg_job *job; - IOCB_t *rsp; - struct lpfc_dmabuf *bmp; - struct lpfc_nodelist *ndlp; - struct lpfc_bsg_iocb *iocb; - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = cmdiocbq->context2; - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - lpfc_sli_release_iocbq(phba, cmdiocbq); - return; - } - - iocb = &dd_data->context_un.iocb; - job = iocb->set_job; - job->dd_data = NULL; /* so timeout handler does not reply */ - - bmp = iocb->bmp; - rsp = &rspiocbq->iocb; - ndlp = cmdiocbq->context1; - - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - - if (rsp->ulpStatus) { - if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & 0xff) { - case IOERR_SEQUENCE_TIMEOUT: - rc = -ETIMEDOUT; - break; - case IOERR_INVALID_RPI: - rc = -EFAULT; - break; - default: - rc = -EACCES; - break; - } - } else - rc = -EACCES; - } else - job->reply->reply_payload_rcv_len = - rsp->un.genreq64.bdl.bdeSize; - - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); - lpfc_sli_release_iocbq(phba, cmdiocbq); - lpfc_nlp_put(ndlp); - kfree(bmp); - kfree(dd_data); - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace */ - job->job_done(job); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return; -} - -/** - * lpfc_bsg_send_mgmt_cmd - send a CT command from a bsg request - * @job: fc_bsg_job to handle - **/ -static int -lpfc_bsg_send_mgmt_cmd(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_rport_data *rdata = job->rport->dd_data; - struct lpfc_nodelist *ndlp = rdata->pnode; - struct ulp_bde64 *bpl = NULL; - uint32_t timeout; - struct lpfc_iocbq *cmdiocbq = NULL; - IOCB_t *cmd; - struct lpfc_dmabuf *bmp = NULL; - int request_nseg; - int reply_nseg; - struct scatterlist *sgel = NULL; - int numbde; - dma_addr_t busaddr; - struct bsg_job_data *dd_data; - uint32_t creg_val; - int rc = 0; - int iocb_stat; - - /* in case no data is transferred */ - job->reply->reply_payload_rcv_len = 0; - - /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2733 Failed allocation of dd_data\n"); - rc = -ENOMEM; - goto no_dd_data; - } - - if (!lpfc_nlp_get(ndlp)) { - rc = -ENODEV; - goto no_ndlp; - } - - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) { - rc = -ENOMEM; - goto free_ndlp; - } - - if (ndlp->nlp_flag & NLP_ELS_SND_MASK) { - rc = -ENODEV; - goto free_bmp; - } - - cmdiocbq = lpfc_sli_get_iocbq(phba); - if (!cmdiocbq) { - rc = -ENOMEM; - goto free_bmp; - } - - cmd = &cmdiocbq->iocb; - bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); - if (!bmp->virt) { - rc = -ENOMEM; - goto free_cmdiocbq; - } - - INIT_LIST_HEAD(&bmp->list); - bpl = (struct ulp_bde64 *) bmp->virt; - request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { - busaddr = sg_dma_address(sgel); - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl->tus.f.bdeSize = sg_dma_len(sgel); - bpl->tus.w = cpu_to_le32(bpl->tus.w); - bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); - bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); - bpl++; - } - - reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { - busaddr = sg_dma_address(sgel); - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; - bpl->tus.f.bdeSize = sg_dma_len(sgel); - bpl->tus.w = cpu_to_le32(bpl->tus.w); - bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); - bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); - bpl++; - } - - cmd->un.genreq64.bdl.ulpIoTag32 = 0; - cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); - cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); - cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - cmd->un.genreq64.bdl.bdeSize = - (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); - cmd->ulpCommand = CMD_GEN_REQUEST64_CR; - cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); - cmd->un.genreq64.w5.hcsw.Dfctl = 0; - cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; - cmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; - cmd->ulpBdeCount = 1; - cmd->ulpLe = 1; - cmd->ulpClass = CLASS3; - cmd->ulpContext = ndlp->nlp_rpi; - if (phba->sli_rev == LPFC_SLI_REV4) - cmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - cmd->ulpOwner = OWN_CHIP; - cmdiocbq->vport = phba->pport; - cmdiocbq->context3 = bmp; - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - timeout = phba->fc_ratov * 2; - cmd->ulpTimeout = timeout; - - cmdiocbq->iocb_cmpl = lpfc_bsg_send_mgmt_cmd_cmp; - cmdiocbq->context1 = ndlp; - cmdiocbq->context2 = dd_data; - dd_data->type = TYPE_IOCB; - dd_data->context_un.iocb.cmdiocbq = cmdiocbq; - dd_data->context_un.iocb.set_job = job; - dd_data->context_un.iocb.bmp = bmp; - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - if (lpfc_readl(phba->HCregaddr, &creg_val)) { - rc = -EIO ; - goto free_cmdiocbq; - } - creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); - writel(creg_val, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - - iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); - if (iocb_stat == IOCB_SUCCESS) - return 0; /* done for now */ - else if (iocb_stat == IOCB_BUSY) - rc = -EAGAIN; - else - rc = -EIO; - - - /* iocb failed so cleanup */ - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); - -free_cmdiocbq: - lpfc_sli_release_iocbq(phba, cmdiocbq); -free_bmp: - kfree(bmp); -free_ndlp: - lpfc_nlp_put(ndlp); -no_ndlp: - kfree(dd_data); -no_dd_data: - /* make error code available to userspace */ - job->reply->result = rc; - job->dd_data = NULL; - return rc; -} - -/** - * lpfc_bsg_rport_els_cmp - lpfc_bsg_rport_els's completion handler - * @phba: Pointer to HBA context object. - * @cmdiocbq: Pointer to command iocb. - * @rspiocbq: Pointer to response iocb. - * - * This function is the completion handler for iocbs issued using - * lpfc_bsg_rport_els_cmp function. This function is called by the - * ring event handler function without any lock held. This function - * can be called from both worker thread context and interrupt - * context. This function also can be called from other thread which - * cleans up the SLI layer objects. - * This function copies the contents of the response iocb to the - * response iocb memory object provided by the caller of - * lpfc_sli_issue_iocb_wait and then wakes up the thread which - * sleeps for the iocb completion. - **/ -static void -lpfc_bsg_rport_els_cmp(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocbq, - struct lpfc_iocbq *rspiocbq) -{ - struct bsg_job_data *dd_data; - struct fc_bsg_job *job; - IOCB_t *rsp; - struct lpfc_nodelist *ndlp; - struct lpfc_dmabuf *pbuflist = NULL; - struct fc_bsg_ctels_reply *els_reply; - uint8_t *rjt_data; - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = cmdiocbq->context1; - /* normal completion and timeout crossed paths, already done */ - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return; - } - - cmdiocbq->iocb_flag |= LPFC_IO_WAKE; - if (cmdiocbq->context2 && rspiocbq) - memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, - &rspiocbq->iocb, sizeof(IOCB_t)); - - job = dd_data->context_un.iocb.set_job; - cmdiocbq = dd_data->context_un.iocb.cmdiocbq; - rspiocbq = dd_data->context_un.iocb.rspiocbq; - rsp = &rspiocbq->iocb; - ndlp = dd_data->context_un.iocb.ndlp; - - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - - if (job->reply->result == -EAGAIN) - rc = -EAGAIN; - else if (rsp->ulpStatus == IOSTAT_SUCCESS) - job->reply->reply_payload_rcv_len = - rsp->un.elsreq64.bdl.bdeSize; - else if (rsp->ulpStatus == IOSTAT_LS_RJT) { - job->reply->reply_payload_rcv_len = - sizeof(struct fc_bsg_ctels_reply); - /* LS_RJT data returned in word 4 */ - rjt_data = (uint8_t *)&rsp->un.ulpWord[4]; - els_reply = &job->reply->reply_data.ctels_reply; - els_reply->status = FC_CTELS_STATUS_REJECT; - els_reply->rjt_data.action = rjt_data[3]; - els_reply->rjt_data.reason_code = rjt_data[2]; - els_reply->rjt_data.reason_explanation = rjt_data[1]; - els_reply->rjt_data.vendor_unique = rjt_data[0]; - } else - rc = -EIO; - - pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; - lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); - lpfc_sli_release_iocbq(phba, rspiocbq); - lpfc_sli_release_iocbq(phba, cmdiocbq); - lpfc_nlp_put(ndlp); - kfree(dd_data); - /* make error code available to userspace */ - job->reply->result = rc; - job->dd_data = NULL; - /* complete the job back to userspace */ - job->job_done(job); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return; -} - -/** - * lpfc_bsg_rport_els - send an ELS command from a bsg request - * @job: fc_bsg_job to handle - **/ -static int -lpfc_bsg_rport_els(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_rport_data *rdata = job->rport->dd_data; - struct lpfc_nodelist *ndlp = rdata->pnode; - uint32_t elscmd; - uint32_t cmdsize; - uint32_t rspsize; - struct lpfc_iocbq *rspiocbq; - struct lpfc_iocbq *cmdiocbq; - IOCB_t *rsp; - uint16_t rpi = 0; - struct lpfc_dmabuf *pcmd; - struct lpfc_dmabuf *prsp; - struct lpfc_dmabuf *pbuflist = NULL; - struct ulp_bde64 *bpl; - int request_nseg; - int reply_nseg; - struct scatterlist *sgel = NULL; - int numbde; - dma_addr_t busaddr; - struct bsg_job_data *dd_data; - uint32_t creg_val; - int rc = 0; - - /* in case no data is transferred */ - job->reply->reply_payload_rcv_len = 0; - - /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2735 Failed allocation of dd_data\n"); - rc = -ENOMEM; - goto no_dd_data; - } - - if (!lpfc_nlp_get(ndlp)) { - rc = -ENODEV; - goto free_dd_data; - } - - elscmd = job->request->rqst_data.r_els.els_code; - cmdsize = job->request_payload.payload_len; - rspsize = job->reply_payload.payload_len; - rspiocbq = lpfc_sli_get_iocbq(phba); - if (!rspiocbq) { - lpfc_nlp_put(ndlp); - rc = -ENOMEM; - goto free_dd_data; - } - - rsp = &rspiocbq->iocb; - rpi = ndlp->nlp_rpi; - - cmdiocbq = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, - ndlp->nlp_DID, elscmd); - if (!cmdiocbq) { - rc = -EIO; - goto free_rspiocbq; - } - - /* prep els iocb set context1 to the ndlp, context2 to the command - * dmabuf, context3 holds the data dmabuf - */ - pcmd = (struct lpfc_dmabuf *) cmdiocbq->context2; - prsp = (struct lpfc_dmabuf *) pcmd->list.next; - lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); - kfree(pcmd); - lpfc_mbuf_free(phba, prsp->virt, prsp->phys); - kfree(prsp); - cmdiocbq->context2 = NULL; - - pbuflist = (struct lpfc_dmabuf *) cmdiocbq->context3; - bpl = (struct ulp_bde64 *) pbuflist->virt; - - request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { - busaddr = sg_dma_address(sgel); - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl->tus.f.bdeSize = sg_dma_len(sgel); - bpl->tus.w = cpu_to_le32(bpl->tus.w); - bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); - bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); - bpl++; - } - - reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { - busaddr = sg_dma_address(sgel); - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; - bpl->tus.f.bdeSize = sg_dma_len(sgel); - bpl->tus.w = cpu_to_le32(bpl->tus.w); - bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); - bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); - bpl++; - } - cmdiocbq->iocb.un.elsreq64.bdl.bdeSize = - (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); - if (phba->sli_rev == LPFC_SLI_REV4) - cmdiocbq->iocb.ulpContext = phba->sli4_hba.rpi_ids[rpi]; - else - cmdiocbq->iocb.ulpContext = rpi; - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - cmdiocbq->context1 = NULL; - cmdiocbq->context2 = NULL; - - cmdiocbq->iocb_cmpl = lpfc_bsg_rport_els_cmp; - cmdiocbq->context1 = dd_data; - cmdiocbq->context2 = rspiocbq; - dd_data->type = TYPE_IOCB; - dd_data->context_un.iocb.cmdiocbq = cmdiocbq; - dd_data->context_un.iocb.rspiocbq = rspiocbq; - dd_data->context_un.iocb.set_job = job; - dd_data->context_un.iocb.bmp = NULL; - dd_data->context_un.iocb.ndlp = ndlp; - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - if (lpfc_readl(phba->HCregaddr, &creg_val)) { - rc = -EIO; - goto linkdown_err; - } - creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); - writel(creg_val, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, 0); - lpfc_nlp_put(ndlp); - if (rc == IOCB_SUCCESS) - return 0; /* done for now */ - else if (rc == IOCB_BUSY) - rc = -EAGAIN; - else - rc = -EIO; - -linkdown_err: - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - - lpfc_mbuf_free(phba, pbuflist->virt, pbuflist->phys); - - lpfc_sli_release_iocbq(phba, cmdiocbq); - -free_rspiocbq: - lpfc_sli_release_iocbq(phba, rspiocbq); - -free_dd_data: - kfree(dd_data); - -no_dd_data: - /* make error code available to userspace */ - job->reply->result = rc; - job->dd_data = NULL; - return rc; -} - -/** - * lpfc_bsg_event_free - frees an allocated event structure - * @kref: Pointer to a kref. - * - * Called from kref_put. Back cast the kref into an event structure address. - * Free any events to get, delete associated nodes, free any events to see, - * free any data then free the event itself. - **/ -static void -lpfc_bsg_event_free(struct kref *kref) -{ - struct lpfc_bsg_event *evt = container_of(kref, struct lpfc_bsg_event, - kref); - struct event_data *ed; - - list_del(&evt->node); - - while (!list_empty(&evt->events_to_get)) { - ed = list_entry(evt->events_to_get.next, typeof(*ed), node); - list_del(&ed->node); - kfree(ed->data); - kfree(ed); - } - - while (!list_empty(&evt->events_to_see)) { - ed = list_entry(evt->events_to_see.next, typeof(*ed), node); - list_del(&ed->node); - kfree(ed->data); - kfree(ed); - } - - kfree(evt); -} - -/** - * lpfc_bsg_event_ref - increments the kref for an event - * @evt: Pointer to an event structure. - **/ -static inline void -lpfc_bsg_event_ref(struct lpfc_bsg_event *evt) -{ - kref_get(&evt->kref); -} - -/** - * lpfc_bsg_event_unref - Uses kref_put to free an event structure - * @evt: Pointer to an event structure. - **/ -static inline void -lpfc_bsg_event_unref(struct lpfc_bsg_event *evt) -{ - kref_put(&evt->kref, lpfc_bsg_event_free); -} - -/** - * lpfc_bsg_event_new - allocate and initialize a event structure - * @ev_mask: Mask of events. - * @ev_reg_id: Event reg id. - * @ev_req_id: Event request id. - **/ -static struct lpfc_bsg_event * -lpfc_bsg_event_new(uint32_t ev_mask, int ev_reg_id, uint32_t ev_req_id) -{ - struct lpfc_bsg_event *evt = kzalloc(sizeof(*evt), GFP_KERNEL); - - if (!evt) - return NULL; - - INIT_LIST_HEAD(&evt->events_to_get); - INIT_LIST_HEAD(&evt->events_to_see); - evt->type_mask = ev_mask; - evt->req_id = ev_req_id; - evt->reg_id = ev_reg_id; - evt->wait_time_stamp = jiffies; - init_waitqueue_head(&evt->wq); - kref_init(&evt->kref); - return evt; -} - -/** - * diag_cmd_data_free - Frees an lpfc dma buffer extension - * @phba: Pointer to HBA context object. - * @mlist: Pointer to an lpfc dma buffer extension. - **/ -static int -diag_cmd_data_free(struct lpfc_hba *phba, struct lpfc_dmabufext *mlist) -{ - struct lpfc_dmabufext *mlast; - struct pci_dev *pcidev; - struct list_head head, *curr, *next; - - if ((!mlist) || (!lpfc_is_link_up(phba) && - (phba->link_flag & LS_LOOPBACK_MODE))) { - return 0; - } - - pcidev = phba->pcidev; - list_add_tail(&head, &mlist->dma.list); - - list_for_each_safe(curr, next, &head) { - mlast = list_entry(curr, struct lpfc_dmabufext , dma.list); - if (mlast->dma.virt) - dma_free_coherent(&pcidev->dev, - mlast->size, - mlast->dma.virt, - mlast->dma.phys); - kfree(mlast); - } - return 0; -} - -/** - * lpfc_bsg_ct_unsol_event - process an unsolicited CT command - * @phba: - * @pring: - * @piocbq: - * - * This function is called when an unsolicited CT command is received. It - * forwards the event to any processes registered to receive CT events. - **/ -int -lpfc_bsg_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocbq) -{ - uint32_t evt_req_id = 0; - uint32_t cmd; - uint32_t len; - struct lpfc_dmabuf *dmabuf = NULL; - struct lpfc_bsg_event *evt; - struct event_data *evt_dat = NULL; - struct lpfc_iocbq *iocbq; - size_t offset = 0; - struct list_head head; - struct ulp_bde64 *bde; - dma_addr_t dma_addr; - int i; - struct lpfc_dmabuf *bdeBuf1 = piocbq->context2; - struct lpfc_dmabuf *bdeBuf2 = piocbq->context3; - struct lpfc_hbq_entry *hbqe; - struct lpfc_sli_ct_request *ct_req; - struct fc_bsg_job *job = NULL; - unsigned long flags; - int size = 0; - - INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); - - if (piocbq->iocb.ulpBdeCount == 0 || - piocbq->iocb.un.cont64[0].tus.f.bdeSize == 0) - goto error_ct_unsol_exit; - - if (phba->link_state == LPFC_HBA_ERROR || - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) - goto error_ct_unsol_exit; - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) - dmabuf = bdeBuf1; - else { - dma_addr = getPaddr(piocbq->iocb.un.cont64[0].addrHigh, - piocbq->iocb.un.cont64[0].addrLow); - dmabuf = lpfc_sli_ringpostbuf_get(phba, pring, dma_addr); - } - if (dmabuf == NULL) - goto error_ct_unsol_exit; - ct_req = (struct lpfc_sli_ct_request *)dmabuf->virt; - evt_req_id = ct_req->FsType; - cmd = ct_req->CommandResponse.bits.CmdRsp; - len = ct_req->CommandResponse.bits.Size; - if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_sli_ringpostbuf_put(phba, pring, dmabuf); - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_for_each_entry(evt, &phba->ct_ev_waiters, node) { - if (!(evt->type_mask & FC_REG_CT_EVENT) || - evt->req_id != evt_req_id) - continue; - - lpfc_bsg_event_ref(evt); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - evt_dat = kzalloc(sizeof(*evt_dat), GFP_KERNEL); - if (evt_dat == NULL) { - spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_bsg_event_unref(evt); - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2614 Memory allocation failed for " - "CT event\n"); - break; - } - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - /* take accumulated byte count from the last iocbq */ - iocbq = list_entry(head.prev, typeof(*iocbq), list); - evt_dat->len = iocbq->iocb.unsli3.rcvsli3.acc_len; - } else { - list_for_each_entry(iocbq, &head, list) { - for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) - evt_dat->len += - iocbq->iocb.un.cont64[i].tus.f.bdeSize; - } - } - - evt_dat->data = kzalloc(evt_dat->len, GFP_KERNEL); - if (evt_dat->data == NULL) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2615 Memory allocation failed for " - "CT event data, size %d\n", - evt_dat->len); - kfree(evt_dat); - spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_bsg_event_unref(evt); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - goto error_ct_unsol_exit; - } - - list_for_each_entry(iocbq, &head, list) { - size = 0; - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - bdeBuf1 = iocbq->context2; - bdeBuf2 = iocbq->context3; - } - for (i = 0; i < iocbq->iocb.ulpBdeCount; i++) { - if (phba->sli3_options & - LPFC_SLI3_HBQ_ENABLED) { - if (i == 0) { - hbqe = (struct lpfc_hbq_entry *) - &iocbq->iocb.un.ulpWord[0]; - size = hbqe->bde.tus.f.bdeSize; - dmabuf = bdeBuf1; - } else if (i == 1) { - hbqe = (struct lpfc_hbq_entry *) - &iocbq->iocb.unsli3. - sli3Words[4]; - size = hbqe->bde.tus.f.bdeSize; - dmabuf = bdeBuf2; - } - if ((offset + size) > evt_dat->len) - size = evt_dat->len - offset; - } else { - size = iocbq->iocb.un.cont64[i]. - tus.f.bdeSize; - bde = &iocbq->iocb.un.cont64[i]; - dma_addr = getPaddr(bde->addrHigh, - bde->addrLow); - dmabuf = lpfc_sli_ringpostbuf_get(phba, - pring, dma_addr); - } - if (!dmabuf) { - lpfc_printf_log(phba, KERN_ERR, - LOG_LIBDFC, "2616 No dmabuf " - "found for iocbq 0x%p\n", - iocbq); - kfree(evt_dat->data); - kfree(evt_dat); - spin_lock_irqsave(&phba->ct_ev_lock, - flags); - lpfc_bsg_event_unref(evt); - spin_unlock_irqrestore( - &phba->ct_ev_lock, flags); - goto error_ct_unsol_exit; - } - memcpy((char *)(evt_dat->data) + offset, - dmabuf->virt, size); - offset += size; - if (evt_req_id != SLI_CT_ELX_LOOPBACK && - !(phba->sli3_options & - LPFC_SLI3_HBQ_ENABLED)) { - lpfc_sli_ringpostbuf_put(phba, pring, - dmabuf); - } else { - switch (cmd) { - case ELX_LOOPBACK_DATA: - if (phba->sli_rev < - LPFC_SLI_REV4) - diag_cmd_data_free(phba, - (struct lpfc_dmabufext - *)dmabuf); - break; - case ELX_LOOPBACK_XRI_SETUP: - if ((phba->sli_rev == - LPFC_SLI_REV2) || - (phba->sli3_options & - LPFC_SLI3_HBQ_ENABLED - )) { - lpfc_in_buf_free(phba, - dmabuf); - } else { - lpfc_post_buffer(phba, - pring, - 1); - } - break; - default: - if (!(phba->sli3_options & - LPFC_SLI3_HBQ_ENABLED)) - lpfc_post_buffer(phba, - pring, - 1); - break; - } - } - } - } - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - if (phba->sli_rev == LPFC_SLI_REV4) { - evt_dat->immed_dat = phba->ctx_idx; - phba->ctx_idx = (phba->ctx_idx + 1) % 64; - /* Provide warning for over-run of the ct_ctx array */ - if (phba->ct_ctx[evt_dat->immed_dat].flags & - UNSOL_VALID) - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, - "2717 CT context array entry " - "[%d] over-run: oxid:x%x, " - "sid:x%x\n", phba->ctx_idx, - phba->ct_ctx[ - evt_dat->immed_dat].oxid, - phba->ct_ctx[ - evt_dat->immed_dat].SID); - phba->ct_ctx[evt_dat->immed_dat].rxid = - piocbq->iocb.ulpContext; - phba->ct_ctx[evt_dat->immed_dat].oxid = - piocbq->iocb.unsli3.rcvsli3.ox_id; - phba->ct_ctx[evt_dat->immed_dat].SID = - piocbq->iocb.un.rcvels.remoteID; - phba->ct_ctx[evt_dat->immed_dat].flags = UNSOL_VALID; - } else - evt_dat->immed_dat = piocbq->iocb.ulpContext; - - evt_dat->type = FC_REG_CT_EVENT; - list_add(&evt_dat->node, &evt->events_to_see); - if (evt_req_id == SLI_CT_ELX_LOOPBACK) { - wake_up_interruptible(&evt->wq); - lpfc_bsg_event_unref(evt); - break; - } - - list_move(evt->events_to_see.prev, &evt->events_to_get); - lpfc_bsg_event_unref(evt); - - job = evt->set_job; - evt->set_job = NULL; - if (job) { - job->reply->reply_payload_rcv_len = size; - /* make error code available to userspace */ - job->reply->result = 0; - job->dd_data = NULL; - /* complete the job back to userspace */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - job->job_done(job); - spin_lock_irqsave(&phba->ct_ev_lock, flags); - } - } - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - -error_ct_unsol_exit: - if (!list_empty(&head)) - list_del(&head); - if ((phba->sli_rev < LPFC_SLI_REV4) && - (evt_req_id == SLI_CT_ELX_LOOPBACK)) - return 0; - return 1; -} - -/** - * lpfc_bsg_hba_set_event - process a SET_EVENT bsg vendor command - * @job: SET_EVENT fc_bsg_job - **/ -static int -lpfc_bsg_hba_set_event(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct set_ct_event *event_req; - struct lpfc_bsg_event *evt; - int rc = 0; - struct bsg_job_data *dd_data = NULL; - uint32_t ev_mask; - unsigned long flags; - - if (job->request_len < - sizeof(struct fc_bsg_request) + sizeof(struct set_ct_event)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2612 Received SET_CT_EVENT below minimum " - "size\n"); - rc = -EINVAL; - goto job_error; - } - - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (dd_data == NULL) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2734 Failed allocation of dd_data\n"); - rc = -ENOMEM; - goto job_error; - } - - event_req = (struct set_ct_event *) - job->request->rqst_data.h_vendor.vendor_cmd; - ev_mask = ((uint32_t)(unsigned long)event_req->type_mask & - FC_REG_EVENT_MASK); - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_for_each_entry(evt, &phba->ct_ev_waiters, node) { - if (evt->reg_id == event_req->ev_reg_id) { - lpfc_bsg_event_ref(evt); - evt->wait_time_stamp = jiffies; - break; - } - } - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - - if (&evt->node == &phba->ct_ev_waiters) { - /* no event waiting struct yet - first call */ - evt = lpfc_bsg_event_new(ev_mask, event_req->ev_reg_id, - event_req->ev_req_id); - if (!evt) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2617 Failed allocation of event " - "waiter\n"); - rc = -ENOMEM; - goto job_error; - } - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_add(&evt->node, &phba->ct_ev_waiters); - lpfc_bsg_event_ref(evt); - evt->wait_time_stamp = jiffies; - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - } - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - evt->waiting = 1; - dd_data->type = TYPE_EVT; - dd_data->context_un.evt = evt; - evt->set_job = job; /* for unsolicited command */ - job->dd_data = dd_data; /* for fc transport timeout callback*/ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return 0; /* call job done later */ - -job_error: - if (dd_data != NULL) - kfree(dd_data); - - job->dd_data = NULL; - return rc; -} - -/** - * lpfc_bsg_hba_get_event - process a GET_EVENT bsg vendor command - * @job: GET_EVENT fc_bsg_job - **/ -static int -lpfc_bsg_hba_get_event(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct get_ct_event *event_req; - struct get_ct_event_reply *event_reply; - struct lpfc_bsg_event *evt; - struct event_data *evt_dat = NULL; - unsigned long flags; - uint32_t rc = 0; - - if (job->request_len < - sizeof(struct fc_bsg_request) + sizeof(struct get_ct_event)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2613 Received GET_CT_EVENT request below " - "minimum size\n"); - rc = -EINVAL; - goto job_error; - } - - event_req = (struct get_ct_event *) - job->request->rqst_data.h_vendor.vendor_cmd; - - event_reply = (struct get_ct_event_reply *) - job->reply->reply_data.vendor_reply.vendor_rsp; - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_for_each_entry(evt, &phba->ct_ev_waiters, node) { - if (evt->reg_id == event_req->ev_reg_id) { - if (list_empty(&evt->events_to_get)) - break; - lpfc_bsg_event_ref(evt); - evt->wait_time_stamp = jiffies; - evt_dat = list_entry(evt->events_to_get.prev, - struct event_data, node); - list_del(&evt_dat->node); - break; - } - } - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - - /* The app may continue to ask for event data until it gets - * an error indicating that there isn't anymore - */ - if (evt_dat == NULL) { - job->reply->reply_payload_rcv_len = 0; - rc = -ENOENT; - goto job_error; - } - - if (evt_dat->len > job->request_payload.payload_len) { - evt_dat->len = job->request_payload.payload_len; - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2618 Truncated event data at %d " - "bytes\n", - job->request_payload.payload_len); - } - - event_reply->type = evt_dat->type; - event_reply->immed_data = evt_dat->immed_dat; - if (evt_dat->len > 0) - job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, - evt_dat->data, evt_dat->len); - else - job->reply->reply_payload_rcv_len = 0; - - if (evt_dat) { - kfree(evt_dat->data); - kfree(evt_dat); - } - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_bsg_event_unref(evt); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - job->dd_data = NULL; - job->reply->result = 0; - job->job_done(job); - return 0; - -job_error: - job->dd_data = NULL; - job->reply->result = rc; - return rc; -} - -/** - * lpfc_issue_ct_rsp_cmp - lpfc_issue_ct_rsp's completion handler - * @phba: Pointer to HBA context object. - * @cmdiocbq: Pointer to command iocb. - * @rspiocbq: Pointer to response iocb. - * - * This function is the completion handler for iocbs issued using - * lpfc_issue_ct_rsp_cmp function. This function is called by the - * ring event handler function without any lock held. This function - * can be called from both worker thread context and interrupt - * context. This function also can be called from other thread which - * cleans up the SLI layer objects. - * This function copy the contents of the response iocb to the - * response iocb memory object provided by the caller of - * lpfc_sli_issue_iocb_wait and then wakes up the thread which - * sleeps for the iocb completion. - **/ -static void -lpfc_issue_ct_rsp_cmp(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocbq, - struct lpfc_iocbq *rspiocbq) -{ - struct bsg_job_data *dd_data; - struct fc_bsg_job *job; - IOCB_t *rsp; - struct lpfc_dmabuf *bmp; - struct lpfc_nodelist *ndlp; - unsigned long flags; - int rc = 0; - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = cmdiocbq->context2; - /* normal completion and timeout crossed paths, already done */ - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return; - } - - job = dd_data->context_un.iocb.set_job; - bmp = dd_data->context_un.iocb.bmp; - rsp = &rspiocbq->iocb; - ndlp = dd_data->context_un.iocb.ndlp; - - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - - if (rsp->ulpStatus) { - if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & 0xff) { - case IOERR_SEQUENCE_TIMEOUT: - rc = -ETIMEDOUT; - break; - case IOERR_INVALID_RPI: - rc = -EFAULT; - break; - default: - rc = -EACCES; - break; - } - } else - rc = -EACCES; - } else - job->reply->reply_payload_rcv_len = - rsp->un.genreq64.bdl.bdeSize; - - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); - lpfc_sli_release_iocbq(phba, cmdiocbq); - lpfc_nlp_put(ndlp); - kfree(bmp); - kfree(dd_data); - /* make error code available to userspace */ - job->reply->result = rc; - job->dd_data = NULL; - /* complete the job back to userspace */ - job->job_done(job); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return; -} - -/** - * lpfc_issue_ct_rsp - issue a ct response - * @phba: Pointer to HBA context object. - * @job: Pointer to the job object. - * @tag: tag index value into the ports context exchange array. - * @bmp: Pointer to a dma buffer descriptor. - * @num_entry: Number of enties in the bde. - **/ -static int -lpfc_issue_ct_rsp(struct lpfc_hba *phba, struct fc_bsg_job *job, uint32_t tag, - struct lpfc_dmabuf *bmp, int num_entry) -{ - IOCB_t *icmd; - struct lpfc_iocbq *ctiocb = NULL; - int rc = 0; - struct lpfc_nodelist *ndlp = NULL; - struct bsg_job_data *dd_data; - uint32_t creg_val; - - /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2736 Failed allocation of dd_data\n"); - rc = -ENOMEM; - goto no_dd_data; - } - - /* Allocate buffer for command iocb */ - ctiocb = lpfc_sli_get_iocbq(phba); - if (!ctiocb) { - rc = -ENOMEM; - goto no_ctiocb; - } - - icmd = &ctiocb->iocb; - icmd->un.xseq64.bdl.ulpIoTag32 = 0; - icmd->un.xseq64.bdl.addrHigh = putPaddrHigh(bmp->phys); - icmd->un.xseq64.bdl.addrLow = putPaddrLow(bmp->phys); - icmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.xseq64.bdl.bdeSize = (num_entry * sizeof(struct ulp_bde64)); - icmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); - icmd->un.xseq64.w5.hcsw.Dfctl = 0; - icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_SOL_CTL; - icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; - - /* Fill in rest of iocb */ - icmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; - icmd->ulpBdeCount = 1; - icmd->ulpLe = 1; - icmd->ulpClass = CLASS3; - if (phba->sli_rev == LPFC_SLI_REV4) { - /* Do not issue unsol response if oxid not marked as valid */ - if (!(phba->ct_ctx[tag].flags & UNSOL_VALID)) { - rc = IOCB_ERROR; - goto issue_ct_rsp_exit; - } - icmd->ulpContext = phba->ct_ctx[tag].rxid; - icmd->unsli3.rcvsli3.ox_id = phba->ct_ctx[tag].oxid; - ndlp = lpfc_findnode_did(phba->pport, phba->ct_ctx[tag].SID); - if (!ndlp) { - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, - "2721 ndlp null for oxid %x SID %x\n", - icmd->ulpContext, - phba->ct_ctx[tag].SID); - rc = IOCB_ERROR; - goto issue_ct_rsp_exit; - } - - /* Check if the ndlp is active */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - rc = -IOCB_ERROR; - goto issue_ct_rsp_exit; - } - - /* get a refernece count so the ndlp doesn't go away while - * we respond - */ - if (!lpfc_nlp_get(ndlp)) { - rc = -IOCB_ERROR; - goto issue_ct_rsp_exit; - } - - icmd->un.ulpWord[3] = - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - - /* The exchange is done, mark the entry as invalid */ - phba->ct_ctx[tag].flags &= ~UNSOL_VALID; - } else - icmd->ulpContext = (ushort) tag; - - icmd->ulpTimeout = phba->fc_ratov * 2; - - /* Xmit CT response on exchange */ - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "2722 Xmit CT response on exchange x%x Data: x%x x%x x%x\n", - icmd->ulpContext, icmd->ulpIoTag, tag, phba->link_state); - - ctiocb->iocb_cmpl = NULL; - ctiocb->iocb_flag |= LPFC_IO_LIBDFC; - ctiocb->vport = phba->pport; - ctiocb->context3 = bmp; - - ctiocb->iocb_cmpl = lpfc_issue_ct_rsp_cmp; - ctiocb->context2 = dd_data; - ctiocb->context1 = ndlp; - dd_data->type = TYPE_IOCB; - dd_data->context_un.iocb.cmdiocbq = ctiocb; - dd_data->context_un.iocb.rspiocbq = NULL; - dd_data->context_un.iocb.set_job = job; - dd_data->context_un.iocb.bmp = bmp; - dd_data->context_un.iocb.ndlp = ndlp; - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - if (lpfc_readl(phba->HCregaddr, &creg_val)) { - rc = -IOCB_ERROR; - goto issue_ct_rsp_exit; - } - creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); - writel(creg_val, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); - - if (rc == IOCB_SUCCESS) - return 0; /* done for now */ - -issue_ct_rsp_exit: - lpfc_sli_release_iocbq(phba, ctiocb); -no_ctiocb: - kfree(dd_data); -no_dd_data: - return rc; -} - -/** - * lpfc_bsg_send_mgmt_rsp - process a SEND_MGMT_RESP bsg vendor command - * @job: SEND_MGMT_RESP fc_bsg_job - **/ -static int -lpfc_bsg_send_mgmt_rsp(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct send_mgmt_resp *mgmt_resp = (struct send_mgmt_resp *) - job->request->rqst_data.h_vendor.vendor_cmd; - struct ulp_bde64 *bpl; - struct lpfc_dmabuf *bmp = NULL; - struct scatterlist *sgel = NULL; - int request_nseg; - int numbde; - dma_addr_t busaddr; - uint32_t tag = mgmt_resp->tag; - unsigned long reqbfrcnt = - (unsigned long)job->request_payload.payload_len; - int rc = 0; - - /* in case no data is transferred */ - job->reply->reply_payload_rcv_len = 0; - - if (!reqbfrcnt || (reqbfrcnt > (80 * BUF_SZ_4K))) { - rc = -ERANGE; - goto send_mgmt_rsp_exit; - } - - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) { - rc = -ENOMEM; - goto send_mgmt_rsp_exit; - } - - bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); - if (!bmp->virt) { - rc = -ENOMEM; - goto send_mgmt_rsp_free_bmp; - } - - INIT_LIST_HEAD(&bmp->list); - bpl = (struct ulp_bde64 *) bmp->virt; - request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { - busaddr = sg_dma_address(sgel); - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl->tus.f.bdeSize = sg_dma_len(sgel); - bpl->tus.w = cpu_to_le32(bpl->tus.w); - bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); - bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); - bpl++; - } - - rc = lpfc_issue_ct_rsp(phba, job, tag, bmp, request_nseg); - - if (rc == IOCB_SUCCESS) - return 0; /* done for now */ - - /* TBD need to handle a timeout */ - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - rc = -EACCES; - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); - -send_mgmt_rsp_free_bmp: - kfree(bmp); -send_mgmt_rsp_exit: - /* make error code available to userspace */ - job->reply->result = rc; - job->dd_data = NULL; - return rc; -} - -/** - * lpfc_bsg_diag_mode_enter - process preparing into device diag loopback mode - * @phba: Pointer to HBA context object. - * - * This function is responsible for preparing driver for diag loopback - * on device. - */ -static int -lpfc_bsg_diag_mode_enter(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - struct Scsi_Host *shost; - struct lpfc_sli *psli; - struct lpfc_sli_ring *pring; - int i = 0; - - psli = &phba->sli; - if (!psli) - return -ENODEV; - - pring = &psli->ring[LPFC_FCP_RING]; - if (!pring) - return -ENODEV; - - if ((phba->link_state == LPFC_HBA_ERROR) || - (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) - return -EACCES; - - vports = lpfc_create_vport_work_array(phba); - if (vports) { - for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - scsi_block_requests(shost); - } - lpfc_destroy_vport_work_array(phba, vports); - } else { - shost = lpfc_shost_from_vport(phba->pport); - scsi_block_requests(shost); - } - - while (pring->txcmplq_cnt) { - if (i++ > 500) /* wait up to 5 seconds */ - break; - msleep(10); - } - return 0; -} - -/** - * lpfc_bsg_diag_mode_exit - exit process from device diag loopback mode - * @phba: Pointer to HBA context object. - * - * This function is responsible for driver exit processing of setting up - * diag loopback mode on device. - */ -static void -lpfc_bsg_diag_mode_exit(struct lpfc_hba *phba) -{ - struct Scsi_Host *shost; - struct lpfc_vport **vports; - int i; - - vports = lpfc_create_vport_work_array(phba); - if (vports) { - for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - scsi_unblock_requests(shost); - } - lpfc_destroy_vport_work_array(phba, vports); - } else { - shost = lpfc_shost_from_vport(phba->pport); - scsi_unblock_requests(shost); - } - return; -} - -/** - * lpfc_sli3_bsg_diag_loopback_mode - process an sli3 bsg vendor command - * @phba: Pointer to HBA context object. - * @job: LPFC_BSG_VENDOR_DIAG_MODE - * - * This function is responsible for placing an sli3 port into diagnostic - * loopback mode in order to perform a diagnostic loopback test. - * All new scsi requests are blocked, a small delay is used to allow the - * scsi requests to complete then the link is brought down. If the link is - * is placed in loopback mode then scsi requests are again allowed - * so the scsi mid-layer doesn't give up on the port. - * All of this is done in-line. - */ -static int -lpfc_sli3_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) -{ - struct diag_mode_set *loopback_mode; - uint32_t link_flags; - uint32_t timeout; - LPFC_MBOXQ_t *pmboxq = NULL; - int mbxstatus = MBX_SUCCESS; - int i = 0; - int rc = 0; - - /* no data to return just the return code */ - job->reply->reply_payload_rcv_len = 0; - - if (job->request_len < sizeof(struct fc_bsg_request) + - sizeof(struct diag_mode_set)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2738 Received DIAG MODE request size:%d " - "below the minimum size:%d\n", - job->request_len, - (int)(sizeof(struct fc_bsg_request) + - sizeof(struct diag_mode_set))); - rc = -EINVAL; - goto job_error; - } - - rc = lpfc_bsg_diag_mode_enter(phba); - if (rc) - goto job_error; - - /* bring the link to diagnostic mode */ - loopback_mode = (struct diag_mode_set *) - job->request->rqst_data.h_vendor.vendor_cmd; - link_flags = loopback_mode->type; - timeout = loopback_mode->timeout * 100; - - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) { - rc = -ENOMEM; - goto loopback_mode_exit; - } - memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - pmboxq->u.mb.mbxCommand = MBX_DOWN_LINK; - pmboxq->u.mb.mbxOwner = OWN_HOST; - - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); - - if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) { - /* wait for link down before proceeding */ - i = 0; - while (phba->link_state != LPFC_LINK_DOWN) { - if (i++ > timeout) { - rc = -ETIMEDOUT; - goto loopback_mode_exit; - } - msleep(10); - } - - memset((void *)pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - if (link_flags == INTERNAL_LOOP_BACK) - pmboxq->u.mb.un.varInitLnk.link_flags = FLAGS_LOCAL_LB; - else - pmboxq->u.mb.un.varInitLnk.link_flags = - FLAGS_TOPOLOGY_MODE_LOOP; - - pmboxq->u.mb.mbxCommand = MBX_INIT_LINK; - pmboxq->u.mb.mbxOwner = OWN_HOST; - - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, - LPFC_MBOX_TMO); - - if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) - rc = -ENODEV; - else { - spin_lock_irq(&phba->hbalock); - phba->link_flag |= LS_LOOPBACK_MODE; - spin_unlock_irq(&phba->hbalock); - /* wait for the link attention interrupt */ - msleep(100); - - i = 0; - while (phba->link_state != LPFC_HBA_READY) { - if (i++ > timeout) { - rc = -ETIMEDOUT; - break; - } - - msleep(10); - } - } - - } else - rc = -ENODEV; - -loopback_mode_exit: - lpfc_bsg_diag_mode_exit(phba); - - /* - * Let SLI layer release mboxq if mbox command completed after timeout. - */ - if (pmboxq && mbxstatus != MBX_TIMEOUT) - mempool_free(pmboxq, phba->mbox_mem_pool); - -job_error: - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace if no error */ - if (rc == 0) - job->job_done(job); - return rc; -} - -/** - * lpfc_sli4_bsg_set_link_diag_state - set sli4 link diag state - * @phba: Pointer to HBA context object. - * @diag: Flag for set link to diag or nomral operation state. - * - * This function is responsible for issuing a sli4 mailbox command for setting - * link to either diag state or normal operation state. - */ -static int -lpfc_sli4_bsg_set_link_diag_state(struct lpfc_hba *phba, uint32_t diag) -{ - LPFC_MBOXQ_t *pmboxq; - struct lpfc_mbx_set_link_diag_state *link_diag_state; - uint32_t req_len, alloc_len; - int mbxstatus = MBX_SUCCESS, rc; - - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) - return -ENOMEM; - - req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, - req_len, LPFC_SLI4_MBX_EMBED); - if (alloc_len != req_len) { - rc = -ENOMEM; - goto link_diag_state_set_out; - } - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3128 Set link to diagnostic state:x%x (x%x/x%x)\n", - diag, phba->sli4_hba.lnk_info.lnk_tp, - phba->sli4_hba.lnk_info.lnk_no); - - link_diag_state = &pmboxq->u.mqe.un.link_diag_state; - bf_set(lpfc_mbx_set_diag_state_link_num, &link_diag_state->u.req, - phba->sli4_hba.lnk_info.lnk_no); - bf_set(lpfc_mbx_set_diag_state_link_type, &link_diag_state->u.req, - phba->sli4_hba.lnk_info.lnk_tp); - if (diag) - bf_set(lpfc_mbx_set_diag_state_diag, - &link_diag_state->u.req, 1); - else - bf_set(lpfc_mbx_set_diag_state_diag, - &link_diag_state->u.req, 0); - - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); - - if ((mbxstatus == MBX_SUCCESS) && (pmboxq->u.mb.mbxStatus == 0)) - rc = 0; - else - rc = -ENODEV; - -link_diag_state_set_out: - if (pmboxq && (mbxstatus != MBX_TIMEOUT)) - mempool_free(pmboxq, phba->mbox_mem_pool); - - return rc; -} - -/** - * lpfc_sli4_bsg_set_internal_loopback - set sli4 internal loopback diagnostic - * @phba: Pointer to HBA context object. - * - * This function is responsible for issuing a sli4 mailbox command for setting - * up internal loopback diagnostic. - */ -static int -lpfc_sli4_bsg_set_internal_loopback(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *pmboxq; - uint32_t req_len, alloc_len; - struct lpfc_mbx_set_link_diag_loopback *link_diag_loopback; - int mbxstatus = MBX_SUCCESS, rc = 0; - - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) - return -ENOMEM; - req_len = (sizeof(struct lpfc_mbx_set_link_diag_loopback) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK, - req_len, LPFC_SLI4_MBX_EMBED); - if (alloc_len != req_len) { - mempool_free(pmboxq, phba->mbox_mem_pool); - return -ENOMEM; - } - link_diag_loopback = &pmboxq->u.mqe.un.link_diag_loopback; - bf_set(lpfc_mbx_set_diag_state_link_num, - &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_no); - bf_set(lpfc_mbx_set_diag_state_link_type, - &link_diag_loopback->u.req, phba->sli4_hba.lnk_info.lnk_tp); - bf_set(lpfc_mbx_set_diag_lpbk_type, &link_diag_loopback->u.req, - LPFC_DIAG_LOOPBACK_TYPE_INTERNAL); - - mbxstatus = lpfc_sli_issue_mbox_wait(phba, pmboxq, LPFC_MBOX_TMO); - if ((mbxstatus != MBX_SUCCESS) || (pmboxq->u.mb.mbxStatus)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "3127 Failed setup loopback mode mailbox " - "command, rc:x%x, status:x%x\n", mbxstatus, - pmboxq->u.mb.mbxStatus); - rc = -ENODEV; - } - if (pmboxq && (mbxstatus != MBX_TIMEOUT)) - mempool_free(pmboxq, phba->mbox_mem_pool); - return rc; -} - -/** - * lpfc_sli4_diag_fcport_reg_setup - setup port registrations for diagnostic - * @phba: Pointer to HBA context object. - * - * This function set up SLI4 FC port registrations for diagnostic run, which - * includes all the rpis, vfi, and also vpi. - */ -static int -lpfc_sli4_diag_fcport_reg_setup(struct lpfc_hba *phba) -{ - int rc; - - if (phba->pport->fc_flag & FC_VFI_REGISTERED) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "3136 Port still had vfi registered: " - "mydid:x%x, fcfi:%d, vfi:%d, vpi:%d\n", - phba->pport->fc_myDID, phba->fcf.fcfi, - phba->sli4_hba.vfi_ids[phba->pport->vfi], - phba->vpi_ids[phba->pport->vpi]); - return -EINVAL; - } - rc = lpfc_issue_reg_vfi(phba->pport); - return rc; -} - -/** - * lpfc_sli4_bsg_diag_loopback_mode - process an sli4 bsg vendor command - * @phba: Pointer to HBA context object. - * @job: LPFC_BSG_VENDOR_DIAG_MODE - * - * This function is responsible for placing an sli4 port into diagnostic - * loopback mode in order to perform a diagnostic loopback test. - */ -static int -lpfc_sli4_bsg_diag_loopback_mode(struct lpfc_hba *phba, struct fc_bsg_job *job) -{ - struct diag_mode_set *loopback_mode; - uint32_t link_flags, timeout; - int i, rc = 0; - - /* no data to return just the return code */ - job->reply->reply_payload_rcv_len = 0; - - if (job->request_len < sizeof(struct fc_bsg_request) + - sizeof(struct diag_mode_set)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "3011 Received DIAG MODE request size:%d " - "below the minimum size:%d\n", - job->request_len, - (int)(sizeof(struct fc_bsg_request) + - sizeof(struct diag_mode_set))); - rc = -EINVAL; - goto job_error; - } - - rc = lpfc_bsg_diag_mode_enter(phba); - if (rc) - goto job_error; - - /* indicate we are in loobpack diagnostic mode */ - spin_lock_irq(&phba->hbalock); - phba->link_flag |= LS_LOOPBACK_MODE; - spin_unlock_irq(&phba->hbalock); - - /* reset port to start frome scratch */ - rc = lpfc_selective_reset(phba); - if (rc) - goto job_error; - - /* bring the link to diagnostic mode */ - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3129 Bring link to diagnostic state.\n"); - loopback_mode = (struct diag_mode_set *) - job->request->rqst_data.h_vendor.vendor_cmd; - link_flags = loopback_mode->type; - timeout = loopback_mode->timeout * 100; - - rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "3130 Failed to bring link to diagnostic " - "state, rc:x%x\n", rc); - goto loopback_mode_exit; - } - - /* wait for link down before proceeding */ - i = 0; - while (phba->link_state != LPFC_LINK_DOWN) { - if (i++ > timeout) { - rc = -ETIMEDOUT; - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3131 Timeout waiting for link to " - "diagnostic mode, timeout:%d ms\n", - timeout * 10); - goto loopback_mode_exit; - } - msleep(10); - } - - /* set up loopback mode */ - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3132 Set up loopback mode:x%x\n", link_flags); - - if (link_flags == INTERNAL_LOOP_BACK) - rc = lpfc_sli4_bsg_set_internal_loopback(phba); - else if (link_flags == EXTERNAL_LOOP_BACK) - rc = lpfc_hba_init_link_fc_topology(phba, - FLAGS_TOPOLOGY_MODE_PT_PT, - MBX_NOWAIT); - else { - rc = -EINVAL; - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "3141 Loopback mode:x%x not supported\n", - link_flags); - goto loopback_mode_exit; - } - - if (!rc) { - /* wait for the link attention interrupt */ - msleep(100); - i = 0; - while (phba->link_state < LPFC_LINK_UP) { - if (i++ > timeout) { - rc = -ETIMEDOUT; - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3137 Timeout waiting for link up " - "in loopback mode, timeout:%d ms\n", - timeout * 10); - break; - } - msleep(10); - } - } - - /* port resource registration setup for loopback diagnostic */ - if (!rc) { - /* set up a none zero myDID for loopback test */ - phba->pport->fc_myDID = 1; - rc = lpfc_sli4_diag_fcport_reg_setup(phba); - } else - goto loopback_mode_exit; - - if (!rc) { - /* wait for the port ready */ - msleep(100); - i = 0; - while (phba->link_state != LPFC_HBA_READY) { - if (i++ > timeout) { - rc = -ETIMEDOUT; - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3133 Timeout waiting for port " - "loopback mode ready, timeout:%d ms\n", - timeout * 10); - break; - } - msleep(10); - } - } - -loopback_mode_exit: - /* clear loopback diagnostic mode */ - if (rc) { - spin_lock_irq(&phba->hbalock); - phba->link_flag &= ~LS_LOOPBACK_MODE; - spin_unlock_irq(&phba->hbalock); - } - lpfc_bsg_diag_mode_exit(phba); - -job_error: - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace if no error */ - if (rc == 0) - job->job_done(job); - return rc; -} - -/** - * lpfc_bsg_diag_loopback_mode - bsg vendor command for diag loopback mode - * @job: LPFC_BSG_VENDOR_DIAG_MODE - * - * This function is responsible for responding to check and dispatch bsg diag - * command from the user to proper driver action routines. - */ -static int -lpfc_bsg_diag_loopback_mode(struct fc_bsg_job *job) -{ - struct Scsi_Host *shost; - struct lpfc_vport *vport; - struct lpfc_hba *phba; - int rc; - - shost = job->shost; - if (!shost) - return -ENODEV; - vport = (struct lpfc_vport *)job->shost->hostdata; - if (!vport) - return -ENODEV; - phba = vport->phba; - if (!phba) - return -ENODEV; - - if (phba->sli_rev < LPFC_SLI_REV4) - rc = lpfc_sli3_bsg_diag_loopback_mode(phba, job); - else if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_IF_TYPE_2) - rc = lpfc_sli4_bsg_diag_loopback_mode(phba, job); - else - rc = -ENODEV; - - return rc; -} - -/** - * lpfc_sli4_bsg_diag_mode_end - sli4 bsg vendor command for ending diag mode - * @job: LPFC_BSG_VENDOR_DIAG_MODE_END - * - * This function is responsible for responding to check and dispatch bsg diag - * command from the user to proper driver action routines. - */ -static int -lpfc_sli4_bsg_diag_mode_end(struct fc_bsg_job *job) -{ - struct Scsi_Host *shost; - struct lpfc_vport *vport; - struct lpfc_hba *phba; - struct diag_mode_set *loopback_mode_end_cmd; - uint32_t timeout; - int rc, i; - - shost = job->shost; - if (!shost) - return -ENODEV; - vport = (struct lpfc_vport *)job->shost->hostdata; - if (!vport) - return -ENODEV; - phba = vport->phba; - if (!phba) - return -ENODEV; - - if (phba->sli_rev < LPFC_SLI_REV4) - return -ENODEV; - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_2) - return -ENODEV; - - /* clear loopback diagnostic mode */ - spin_lock_irq(&phba->hbalock); - phba->link_flag &= ~LS_LOOPBACK_MODE; - spin_unlock_irq(&phba->hbalock); - loopback_mode_end_cmd = (struct diag_mode_set *) - job->request->rqst_data.h_vendor.vendor_cmd; - timeout = loopback_mode_end_cmd->timeout * 100; - - rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "3139 Failed to bring link to diagnostic " - "state, rc:x%x\n", rc); - goto loopback_mode_end_exit; - } - - /* wait for link down before proceeding */ - i = 0; - while (phba->link_state != LPFC_LINK_DOWN) { - if (i++ > timeout) { - rc = -ETIMEDOUT; - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3140 Timeout waiting for link to " - "diagnostic mode_end, timeout:%d ms\n", - timeout * 10); - /* there is nothing much we can do here */ - break; - } - msleep(10); - } - - /* reset port resource registrations */ - rc = lpfc_selective_reset(phba); - phba->pport->fc_myDID = 0; - -loopback_mode_end_exit: - /* make return code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace if no error */ - if (rc == 0) - job->job_done(job); - return rc; -} - -/** - * lpfc_sli4_bsg_link_diag_test - sli4 bsg vendor command for diag link test - * @job: LPFC_BSG_VENDOR_DIAG_LINK_TEST - * - * This function is to perform SLI4 diag link test request from the user - * applicaiton. - */ -static int -lpfc_sli4_bsg_link_diag_test(struct fc_bsg_job *job) -{ - struct Scsi_Host *shost; - struct lpfc_vport *vport; - struct lpfc_hba *phba; - LPFC_MBOXQ_t *pmboxq; - struct sli4_link_diag *link_diag_test_cmd; - uint32_t req_len, alloc_len; - uint32_t timeout; - struct lpfc_mbx_run_link_diag_test *run_link_diag_test; - union lpfc_sli4_cfg_shdr *shdr; - uint32_t shdr_status, shdr_add_status; - struct diag_status *diag_status_reply; - int mbxstatus, rc = 0; - - shost = job->shost; - if (!shost) { - rc = -ENODEV; - goto job_error; - } - vport = (struct lpfc_vport *)job->shost->hostdata; - if (!vport) { - rc = -ENODEV; - goto job_error; - } - phba = vport->phba; - if (!phba) { - rc = -ENODEV; - goto job_error; - } - - if (phba->sli_rev < LPFC_SLI_REV4) { - rc = -ENODEV; - goto job_error; - } - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_2) { - rc = -ENODEV; - goto job_error; - } - - if (job->request_len < sizeof(struct fc_bsg_request) + - sizeof(struct sli4_link_diag)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "3013 Received LINK DIAG TEST request " - " size:%d below the minimum size:%d\n", - job->request_len, - (int)(sizeof(struct fc_bsg_request) + - sizeof(struct sli4_link_diag))); - rc = -EINVAL; - goto job_error; - } - - rc = lpfc_bsg_diag_mode_enter(phba); - if (rc) - goto job_error; - - link_diag_test_cmd = (struct sli4_link_diag *) - job->request->rqst_data.h_vendor.vendor_cmd; - timeout = link_diag_test_cmd->timeout * 100; - - rc = lpfc_sli4_bsg_set_link_diag_state(phba, 1); - - if (rc) - goto job_error; - - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) { - rc = -ENOMEM; - goto link_diag_test_exit; - } - - req_len = (sizeof(struct lpfc_mbx_set_link_diag_state) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - alloc_len = lpfc_sli4_config(phba, pmboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE, - req_len, LPFC_SLI4_MBX_EMBED); - if (alloc_len != req_len) { - rc = -ENOMEM; - goto link_diag_test_exit; - } - run_link_diag_test = &pmboxq->u.mqe.un.link_diag_test; - bf_set(lpfc_mbx_run_diag_test_link_num, &run_link_diag_test->u.req, - phba->sli4_hba.lnk_info.lnk_no); - bf_set(lpfc_mbx_run_diag_test_link_type, &run_link_diag_test->u.req, - phba->sli4_hba.lnk_info.lnk_tp); - bf_set(lpfc_mbx_run_diag_test_test_id, &run_link_diag_test->u.req, - link_diag_test_cmd->test_id); - bf_set(lpfc_mbx_run_diag_test_loops, &run_link_diag_test->u.req, - link_diag_test_cmd->loops); - bf_set(lpfc_mbx_run_diag_test_test_ver, &run_link_diag_test->u.req, - link_diag_test_cmd->test_version); - bf_set(lpfc_mbx_run_diag_test_err_act, &run_link_diag_test->u.req, - link_diag_test_cmd->error_action); - - mbxstatus = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - - shdr = (union lpfc_sli4_cfg_shdr *) - &pmboxq->u.mqe.un.sli4_config.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || mbxstatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "3010 Run link diag test mailbox failed with " - "mbx_status x%x status x%x, add_status x%x\n", - mbxstatus, shdr_status, shdr_add_status); - } - - diag_status_reply = (struct diag_status *) - job->reply->reply_data.vendor_reply.vendor_rsp; - - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct diag_status)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "3012 Received Run link diag test reply " - "below minimum size (%d): reply_len:%d\n", - (int)(sizeof(struct fc_bsg_request) + - sizeof(struct diag_status)), - job->reply_len); - rc = -EINVAL; - goto job_error; - } - - diag_status_reply->mbox_status = mbxstatus; - diag_status_reply->shdr_status = shdr_status; - diag_status_reply->shdr_add_status = shdr_add_status; - -link_diag_test_exit: - rc = lpfc_sli4_bsg_set_link_diag_state(phba, 0); - - if (pmboxq) - mempool_free(pmboxq, phba->mbox_mem_pool); - - lpfc_bsg_diag_mode_exit(phba); - -job_error: - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace if no error */ - if (rc == 0) - job->job_done(job); - return rc; -} - -/** - * lpfcdiag_loop_self_reg - obtains a remote port login id - * @phba: Pointer to HBA context object - * @rpi: Pointer to a remote port login id - * - * This function obtains a remote port login id so the diag loopback test - * can send and receive its own unsolicited CT command. - **/ -static int lpfcdiag_loop_self_reg(struct lpfc_hba *phba, uint16_t *rpi) -{ - LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *dmabuff; - int status; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - - if (phba->sli_rev < LPFC_SLI_REV4) - status = lpfc_reg_rpi(phba, 0, phba->pport->fc_myDID, - (uint8_t *)&phba->pport->fc_sparam, - mbox, *rpi); - else { - *rpi = lpfc_sli4_alloc_rpi(phba); - status = lpfc_reg_rpi(phba, phba->pport->vpi, - phba->pport->fc_myDID, - (uint8_t *)&phba->pport->fc_sparam, - mbox, *rpi); - } - - if (status) { - mempool_free(mbox, phba->mbox_mem_pool); - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_free_rpi(phba, *rpi); - return -ENOMEM; - } - - dmabuff = (struct lpfc_dmabuf *) mbox->context1; - mbox->context1 = NULL; - mbox->context2 = NULL; - status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); - - if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { - lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); - kfree(dmabuff); - if (status != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_free_rpi(phba, *rpi); - return -ENODEV; - } - - if (phba->sli_rev < LPFC_SLI_REV4) - *rpi = mbox->u.mb.un.varWords[0]; - - lpfc_mbuf_free(phba, dmabuff->virt, dmabuff->phys); - kfree(dmabuff); - mempool_free(mbox, phba->mbox_mem_pool); - return 0; -} - -/** - * lpfcdiag_loop_self_unreg - unregs from the rpi - * @phba: Pointer to HBA context object - * @rpi: Remote port login id - * - * This function unregisters the rpi obtained in lpfcdiag_loop_self_reg - **/ -static int lpfcdiag_loop_self_unreg(struct lpfc_hba *phba, uint16_t rpi) -{ - LPFC_MBOXQ_t *mbox; - int status; - - /* Allocate mboxq structure */ - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox == NULL) - return -ENOMEM; - - if (phba->sli_rev < LPFC_SLI_REV4) - lpfc_unreg_login(phba, 0, rpi, mbox); - else - lpfc_unreg_login(phba, phba->pport->vpi, - phba->sli4_hba.rpi_ids[rpi], mbox); - - status = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); - - if ((status != MBX_SUCCESS) || (mbox->u.mb.mbxStatus)) { - if (status != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - return -EIO; - } - mempool_free(mbox, phba->mbox_mem_pool); - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_free_rpi(phba, rpi); - return 0; -} - -/** - * lpfcdiag_loop_get_xri - obtains the transmit and receive ids - * @phba: Pointer to HBA context object - * @rpi: Remote port login id - * @txxri: Pointer to transmit exchange id - * @rxxri: Pointer to response exchabge id - * - * This function obtains the transmit and receive ids required to send - * an unsolicited ct command with a payload. A special lpfc FsType and CmdRsp - * flags are used to the unsolicted response handler is able to process - * the ct command sent on the same port. - **/ -static int lpfcdiag_loop_get_xri(struct lpfc_hba *phba, uint16_t rpi, - uint16_t *txxri, uint16_t * rxxri) -{ - struct lpfc_bsg_event *evt; - struct lpfc_iocbq *cmdiocbq, *rspiocbq; - IOCB_t *cmd, *rsp; - struct lpfc_dmabuf *dmabuf; - struct ulp_bde64 *bpl = NULL; - struct lpfc_sli_ct_request *ctreq = NULL; - int ret_val = 0; - int time_left; - int iocb_stat = 0; - unsigned long flags; - - *txxri = 0; - *rxxri = 0; - evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, - SLI_CT_ELX_LOOPBACK); - if (!evt) - return -ENOMEM; - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_add(&evt->node, &phba->ct_ev_waiters); - lpfc_bsg_event_ref(evt); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - - cmdiocbq = lpfc_sli_get_iocbq(phba); - rspiocbq = lpfc_sli_get_iocbq(phba); - - dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (dmabuf) { - dmabuf->virt = lpfc_mbuf_alloc(phba, 0, &dmabuf->phys); - if (dmabuf->virt) { - INIT_LIST_HEAD(&dmabuf->list); - bpl = (struct ulp_bde64 *) dmabuf->virt; - memset(bpl, 0, sizeof(*bpl)); - ctreq = (struct lpfc_sli_ct_request *)(bpl + 1); - bpl->addrHigh = - le32_to_cpu(putPaddrHigh(dmabuf->phys + - sizeof(*bpl))); - bpl->addrLow = - le32_to_cpu(putPaddrLow(dmabuf->phys + - sizeof(*bpl))); - bpl->tus.f.bdeFlags = 0; - bpl->tus.f.bdeSize = ELX_LOOPBACK_HEADER_SZ; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - } - } - - if (cmdiocbq == NULL || rspiocbq == NULL || - dmabuf == NULL || bpl == NULL || ctreq == NULL || - dmabuf->virt == NULL) { - ret_val = -ENOMEM; - goto err_get_xri_exit; - } - - cmd = &cmdiocbq->iocb; - rsp = &rspiocbq->iocb; - - memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); - - ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; - ctreq->RevisionId.bits.InId = 0; - ctreq->FsType = SLI_CT_ELX_LOOPBACK; - ctreq->FsSubType = 0; - ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_XRI_SETUP; - ctreq->CommandResponse.bits.Size = 0; - - - cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(dmabuf->phys); - cmd->un.xseq64.bdl.addrLow = putPaddrLow(dmabuf->phys); - cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - cmd->un.xseq64.bdl.bdeSize = sizeof(*bpl); - - cmd->un.xseq64.w5.hcsw.Fctl = LA; - cmd->un.xseq64.w5.hcsw.Dfctl = 0; - cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; - cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; - - cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CR; - cmd->ulpBdeCount = 1; - cmd->ulpLe = 1; - cmd->ulpClass = CLASS3; - cmd->ulpContext = rpi; - - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - cmdiocbq->vport = phba->pport; - - iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, - rspiocbq, - (phba->fc_ratov * 2) - + LPFC_DRVR_TIMEOUT); - if (iocb_stat) { - ret_val = -EIO; - goto err_get_xri_exit; - } - *txxri = rsp->ulpContext; - - evt->waiting = 1; - evt->wait_time_stamp = jiffies; - time_left = wait_event_interruptible_timeout( - evt->wq, !list_empty(&evt->events_to_see), - ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); - if (list_empty(&evt->events_to_see)) - ret_val = (time_left) ? -EINTR : -ETIMEDOUT; - else { - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_move(evt->events_to_see.prev, &evt->events_to_get); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - *rxxri = (list_entry(evt->events_to_get.prev, - typeof(struct event_data), - node))->immed_dat; - } - evt->waiting = 0; - -err_get_xri_exit: - spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_bsg_event_unref(evt); /* release ref */ - lpfc_bsg_event_unref(evt); /* delete */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - - if (dmabuf) { - if (dmabuf->virt) - lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - } - - if (cmdiocbq && (iocb_stat != IOCB_TIMEDOUT)) - lpfc_sli_release_iocbq(phba, cmdiocbq); - if (rspiocbq) - lpfc_sli_release_iocbq(phba, rspiocbq); - return ret_val; -} - -/** - * lpfc_bsg_dma_page_alloc - allocate a bsg mbox page sized dma buffers - * @phba: Pointer to HBA context object - * - * This function allocates BSG_MBOX_SIZE (4KB) page size dma buffer and. - * retruns the pointer to the buffer. - **/ -static struct lpfc_dmabuf * -lpfc_bsg_dma_page_alloc(struct lpfc_hba *phba) -{ - struct lpfc_dmabuf *dmabuf; - struct pci_dev *pcidev = phba->pcidev; - - /* allocate dma buffer struct */ - dmabuf = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!dmabuf) - return NULL; - - INIT_LIST_HEAD(&dmabuf->list); - - /* now, allocate dma buffer */ - dmabuf->virt = dma_alloc_coherent(&pcidev->dev, BSG_MBOX_SIZE, - &(dmabuf->phys), GFP_KERNEL); - - if (!dmabuf->virt) { - kfree(dmabuf); - return NULL; - } - memset((uint8_t *)dmabuf->virt, 0, BSG_MBOX_SIZE); - - return dmabuf; -} - -/** - * lpfc_bsg_dma_page_free - free a bsg mbox page sized dma buffer - * @phba: Pointer to HBA context object. - * @dmabuf: Pointer to the bsg mbox page sized dma buffer descriptor. - * - * This routine just simply frees a dma buffer and its associated buffer - * descriptor referred by @dmabuf. - **/ -static void -lpfc_bsg_dma_page_free(struct lpfc_hba *phba, struct lpfc_dmabuf *dmabuf) -{ - struct pci_dev *pcidev = phba->pcidev; - - if (!dmabuf) - return; - - if (dmabuf->virt) - dma_free_coherent(&pcidev->dev, BSG_MBOX_SIZE, - dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - return; -} - -/** - * lpfc_bsg_dma_page_list_free - free a list of bsg mbox page sized dma buffers - * @phba: Pointer to HBA context object. - * @dmabuf_list: Pointer to a list of bsg mbox page sized dma buffer descs. - * - * This routine just simply frees all dma buffers and their associated buffer - * descriptors referred by @dmabuf_list. - **/ -static void -lpfc_bsg_dma_page_list_free(struct lpfc_hba *phba, - struct list_head *dmabuf_list) -{ - struct lpfc_dmabuf *dmabuf, *next_dmabuf; - - if (list_empty(dmabuf_list)) - return; - - list_for_each_entry_safe(dmabuf, next_dmabuf, dmabuf_list, list) { - list_del_init(&dmabuf->list); - lpfc_bsg_dma_page_free(phba, dmabuf); - } - return; -} - -/** - * diag_cmd_data_alloc - fills in a bde struct with dma buffers - * @phba: Pointer to HBA context object - * @bpl: Pointer to 64 bit bde structure - * @size: Number of bytes to process - * @nocopydata: Flag to copy user data into the allocated buffer - * - * This function allocates page size buffers and populates an lpfc_dmabufext. - * If allowed the user data pointed to with indataptr is copied into the kernel - * memory. The chained list of page size buffers is returned. - **/ -static struct lpfc_dmabufext * -diag_cmd_data_alloc(struct lpfc_hba *phba, - struct ulp_bde64 *bpl, uint32_t size, - int nocopydata) -{ - struct lpfc_dmabufext *mlist = NULL; - struct lpfc_dmabufext *dmp; - int cnt, offset = 0, i = 0; - struct pci_dev *pcidev; - - pcidev = phba->pcidev; - - while (size) { - /* We get chunks of 4K */ - if (size > BUF_SZ_4K) - cnt = BUF_SZ_4K; - else - cnt = size; - - /* allocate struct lpfc_dmabufext buffer header */ - dmp = kmalloc(sizeof(struct lpfc_dmabufext), GFP_KERNEL); - if (!dmp) - goto out; - - INIT_LIST_HEAD(&dmp->dma.list); - - /* Queue it to a linked list */ - if (mlist) - list_add_tail(&dmp->dma.list, &mlist->dma.list); - else - mlist = dmp; - - /* allocate buffer */ - dmp->dma.virt = dma_alloc_coherent(&pcidev->dev, - cnt, - &(dmp->dma.phys), - GFP_KERNEL); - - if (!dmp->dma.virt) - goto out; - - dmp->size = cnt; - - if (nocopydata) { - bpl->tus.f.bdeFlags = 0; - pci_dma_sync_single_for_device(phba->pcidev, - dmp->dma.phys, LPFC_BPL_SIZE, PCI_DMA_TODEVICE); - - } else { - memset((uint8_t *)dmp->dma.virt, 0, cnt); - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; - } - - /* build buffer ptr list for IOCB */ - bpl->addrLow = le32_to_cpu(putPaddrLow(dmp->dma.phys)); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(dmp->dma.phys)); - bpl->tus.f.bdeSize = (ushort) cnt; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - bpl++; - - i++; - offset += cnt; - size -= cnt; - } - - mlist->flag = i; - return mlist; -out: - diag_cmd_data_free(phba, mlist); - return NULL; -} - -/** - * lpfcdiag_loop_post_rxbufs - post the receive buffers for an unsol CT cmd - * @phba: Pointer to HBA context object - * @rxxri: Receive exchange id - * @len: Number of data bytes - * - * This function allocates and posts a data buffer of sufficient size to receive - * an unsolicted CT command. - **/ -static int lpfcdiag_loop_post_rxbufs(struct lpfc_hba *phba, uint16_t rxxri, - size_t len) -{ - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; - struct lpfc_iocbq *cmdiocbq; - IOCB_t *cmd = NULL; - struct list_head head, *curr, *next; - struct lpfc_dmabuf *rxbmp; - struct lpfc_dmabuf *dmp; - struct lpfc_dmabuf *mp[2] = {NULL, NULL}; - struct ulp_bde64 *rxbpl = NULL; - uint32_t num_bde; - struct lpfc_dmabufext *rxbuffer = NULL; - int ret_val = 0; - int iocb_stat; - int i = 0; - - cmdiocbq = lpfc_sli_get_iocbq(phba); - rxbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (rxbmp != NULL) { - rxbmp->virt = lpfc_mbuf_alloc(phba, 0, &rxbmp->phys); - if (rxbmp->virt) { - INIT_LIST_HEAD(&rxbmp->list); - rxbpl = (struct ulp_bde64 *) rxbmp->virt; - rxbuffer = diag_cmd_data_alloc(phba, rxbpl, len, 0); - } - } - - if (!cmdiocbq || !rxbmp || !rxbpl || !rxbuffer) { - ret_val = -ENOMEM; - goto err_post_rxbufs_exit; - } - - /* Queue buffers for the receive exchange */ - num_bde = (uint32_t)rxbuffer->flag; - dmp = &rxbuffer->dma; - - cmd = &cmdiocbq->iocb; - i = 0; - - INIT_LIST_HEAD(&head); - list_add_tail(&head, &dmp->list); - list_for_each_safe(curr, next, &head) { - mp[i] = list_entry(curr, struct lpfc_dmabuf, list); - list_del(curr); - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - mp[i]->buffer_tag = lpfc_sli_get_buffer_tag(phba); - cmd->un.quexri64cx.buff.bde.addrHigh = - putPaddrHigh(mp[i]->phys); - cmd->un.quexri64cx.buff.bde.addrLow = - putPaddrLow(mp[i]->phys); - cmd->un.quexri64cx.buff.bde.tus.f.bdeSize = - ((struct lpfc_dmabufext *)mp[i])->size; - cmd->un.quexri64cx.buff.buffer_tag = mp[i]->buffer_tag; - cmd->ulpCommand = CMD_QUE_XRI64_CX; - cmd->ulpPU = 0; - cmd->ulpLe = 1; - cmd->ulpBdeCount = 1; - cmd->unsli3.que_xri64cx_ext_words.ebde_count = 0; - - } else { - cmd->un.cont64[i].addrHigh = putPaddrHigh(mp[i]->phys); - cmd->un.cont64[i].addrLow = putPaddrLow(mp[i]->phys); - cmd->un.cont64[i].tus.f.bdeSize = - ((struct lpfc_dmabufext *)mp[i])->size; - cmd->ulpBdeCount = ++i; - - if ((--num_bde > 0) && (i < 2)) - continue; - - cmd->ulpCommand = CMD_QUE_XRI_BUF64_CX; - cmd->ulpLe = 1; - } - - cmd->ulpClass = CLASS3; - cmd->ulpContext = rxxri; - - iocb_stat = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, - 0); - if (iocb_stat == IOCB_ERROR) { - diag_cmd_data_free(phba, - (struct lpfc_dmabufext *)mp[0]); - if (mp[1]) - diag_cmd_data_free(phba, - (struct lpfc_dmabufext *)mp[1]); - dmp = list_entry(next, struct lpfc_dmabuf, list); - ret_val = -EIO; - goto err_post_rxbufs_exit; - } - - lpfc_sli_ringpostbuf_put(phba, pring, mp[0]); - if (mp[1]) { - lpfc_sli_ringpostbuf_put(phba, pring, mp[1]); - mp[1] = NULL; - } - - /* The iocb was freed by lpfc_sli_issue_iocb */ - cmdiocbq = lpfc_sli_get_iocbq(phba); - if (!cmdiocbq) { - dmp = list_entry(next, struct lpfc_dmabuf, list); - ret_val = -EIO; - goto err_post_rxbufs_exit; - } - - cmd = &cmdiocbq->iocb; - i = 0; - } - list_del(&head); - -err_post_rxbufs_exit: - - if (rxbmp) { - if (rxbmp->virt) - lpfc_mbuf_free(phba, rxbmp->virt, rxbmp->phys); - kfree(rxbmp); - } - - if (cmdiocbq) - lpfc_sli_release_iocbq(phba, cmdiocbq); - return ret_val; -} - -/** - * lpfc_bsg_diag_loopback_run - run loopback on a port by issue ct cmd to itself - * @job: LPFC_BSG_VENDOR_DIAG_TEST fc_bsg_job - * - * This function receives a user data buffer to be transmitted and received on - * the same port, the link must be up and in loopback mode prior - * to being called. - * 1. A kernel buffer is allocated to copy the user data into. - * 2. The port registers with "itself". - * 3. The transmit and receive exchange ids are obtained. - * 4. The receive exchange id is posted. - * 5. A new els loopback event is created. - * 6. The command and response iocbs are allocated. - * 7. The cmd iocb FsType is set to elx loopback and the CmdRsp to looppback. - * - * This function is meant to be called n times while the port is in loopback - * so it is the apps responsibility to issue a reset to take the port out - * of loopback mode. - **/ -static int -lpfc_bsg_diag_loopback_run(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct diag_mode_test *diag_mode; - struct lpfc_bsg_event *evt; - struct event_data *evdat; - struct lpfc_sli *psli = &phba->sli; - uint32_t size; - uint32_t full_size; - size_t segment_len = 0, segment_offset = 0, current_offset = 0; - uint16_t rpi = 0; - struct lpfc_iocbq *cmdiocbq, *rspiocbq = NULL; - IOCB_t *cmd, *rsp = NULL; - struct lpfc_sli_ct_request *ctreq; - struct lpfc_dmabuf *txbmp; - struct ulp_bde64 *txbpl = NULL; - struct lpfc_dmabufext *txbuffer = NULL; - struct list_head head; - struct lpfc_dmabuf *curr; - uint16_t txxri = 0, rxxri; - uint32_t num_bde; - uint8_t *ptr = NULL, *rx_databuf = NULL; - int rc = 0; - int time_left; - int iocb_stat; - unsigned long flags; - void *dataout = NULL; - uint32_t total_mem; - - /* in case no data is returned return just the return code */ - job->reply->reply_payload_rcv_len = 0; - - if (job->request_len < - sizeof(struct fc_bsg_request) + sizeof(struct diag_mode_test)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2739 Received DIAG TEST request below minimum " - "size\n"); - rc = -EINVAL; - goto loopback_test_exit; - } - - if (job->request_payload.payload_len != - job->reply_payload.payload_len) { - rc = -EINVAL; - goto loopback_test_exit; - } - diag_mode = (struct diag_mode_test *) - job->request->rqst_data.h_vendor.vendor_cmd; - - if ((phba->link_state == LPFC_HBA_ERROR) || - (psli->sli_flag & LPFC_BLOCK_MGMT_IO) || - (!(psli->sli_flag & LPFC_SLI_ACTIVE))) { - rc = -EACCES; - goto loopback_test_exit; - } - - if (!lpfc_is_link_up(phba) || !(phba->link_flag & LS_LOOPBACK_MODE)) { - rc = -EACCES; - goto loopback_test_exit; - } - - size = job->request_payload.payload_len; - full_size = size + ELX_LOOPBACK_HEADER_SZ; /* plus the header */ - - if ((size == 0) || (size > 80 * BUF_SZ_4K)) { - rc = -ERANGE; - goto loopback_test_exit; - } - - if (full_size >= BUF_SZ_4K) { - /* - * Allocate memory for ioctl data. If buffer is bigger than 64k, - * then we allocate 64k and re-use that buffer over and over to - * xfer the whole block. This is because Linux kernel has a - * problem allocating more than 120k of kernel space memory. Saw - * problem with GET_FCPTARGETMAPPING... - */ - if (size <= (64 * 1024)) - total_mem = full_size; - else - total_mem = 64 * 1024; - } else - /* Allocate memory for ioctl data */ - total_mem = BUF_SZ_4K; - - dataout = kmalloc(total_mem, GFP_KERNEL); - if (dataout == NULL) { - rc = -ENOMEM; - goto loopback_test_exit; - } - - ptr = dataout; - ptr += ELX_LOOPBACK_HEADER_SZ; - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, - ptr, size); - rc = lpfcdiag_loop_self_reg(phba, &rpi); - if (rc) - goto loopback_test_exit; - - if (phba->sli_rev < LPFC_SLI_REV4) { - rc = lpfcdiag_loop_get_xri(phba, rpi, &txxri, &rxxri); - if (rc) { - lpfcdiag_loop_self_unreg(phba, rpi); - goto loopback_test_exit; - } - - rc = lpfcdiag_loop_post_rxbufs(phba, rxxri, full_size); - if (rc) { - lpfcdiag_loop_self_unreg(phba, rpi); - goto loopback_test_exit; - } - } - evt = lpfc_bsg_event_new(FC_REG_CT_EVENT, current->pid, - SLI_CT_ELX_LOOPBACK); - if (!evt) { - lpfcdiag_loop_self_unreg(phba, rpi); - rc = -ENOMEM; - goto loopback_test_exit; - } - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_add(&evt->node, &phba->ct_ev_waiters); - lpfc_bsg_event_ref(evt); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - - cmdiocbq = lpfc_sli_get_iocbq(phba); - if (phba->sli_rev < LPFC_SLI_REV4) - rspiocbq = lpfc_sli_get_iocbq(phba); - txbmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - - if (txbmp) { - txbmp->virt = lpfc_mbuf_alloc(phba, 0, &txbmp->phys); - if (txbmp->virt) { - INIT_LIST_HEAD(&txbmp->list); - txbpl = (struct ulp_bde64 *) txbmp->virt; - txbuffer = diag_cmd_data_alloc(phba, - txbpl, full_size, 0); - } - } - - if (!cmdiocbq || !txbmp || !txbpl || !txbuffer || !txbmp->virt) { - rc = -ENOMEM; - goto err_loopback_test_exit; - } - if ((phba->sli_rev < LPFC_SLI_REV4) && !rspiocbq) { - rc = -ENOMEM; - goto err_loopback_test_exit; - } - - cmd = &cmdiocbq->iocb; - if (phba->sli_rev < LPFC_SLI_REV4) - rsp = &rspiocbq->iocb; - - INIT_LIST_HEAD(&head); - list_add_tail(&head, &txbuffer->dma.list); - list_for_each_entry(curr, &head, list) { - segment_len = ((struct lpfc_dmabufext *)curr)->size; - if (current_offset == 0) { - ctreq = curr->virt; - memset(ctreq, 0, ELX_LOOPBACK_HEADER_SZ); - ctreq->RevisionId.bits.Revision = SLI_CT_REVISION; - ctreq->RevisionId.bits.InId = 0; - ctreq->FsType = SLI_CT_ELX_LOOPBACK; - ctreq->FsSubType = 0; - ctreq->CommandResponse.bits.CmdRsp = ELX_LOOPBACK_DATA; - ctreq->CommandResponse.bits.Size = size; - segment_offset = ELX_LOOPBACK_HEADER_SZ; - } else - segment_offset = 0; - - BUG_ON(segment_offset >= segment_len); - memcpy(curr->virt + segment_offset, - ptr + current_offset, - segment_len - segment_offset); - - current_offset += segment_len - segment_offset; - BUG_ON(current_offset > size); - } - list_del(&head); - - /* Build the XMIT_SEQUENCE iocb */ - num_bde = (uint32_t)txbuffer->flag; - - cmd->un.xseq64.bdl.addrHigh = putPaddrHigh(txbmp->phys); - cmd->un.xseq64.bdl.addrLow = putPaddrLow(txbmp->phys); - cmd->un.xseq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - cmd->un.xseq64.bdl.bdeSize = (num_bde * sizeof(struct ulp_bde64)); - - cmd->un.xseq64.w5.hcsw.Fctl = (LS | LA); - cmd->un.xseq64.w5.hcsw.Dfctl = 0; - cmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; - cmd->un.xseq64.w5.hcsw.Type = FC_TYPE_CT; - - cmd->ulpCommand = CMD_XMIT_SEQUENCE64_CX; - cmd->ulpBdeCount = 1; - cmd->ulpLe = 1; - cmd->ulpClass = CLASS3; - - if (phba->sli_rev < LPFC_SLI_REV4) { - cmd->ulpContext = txxri; - } else { - cmd->un.xseq64.bdl.ulpIoTag32 = 0; - cmd->un.ulpWord[3] = phba->sli4_hba.rpi_ids[rpi]; - cmdiocbq->context3 = txbmp; - cmdiocbq->sli4_xritag = NO_XRI; - cmd->unsli3.rcvsli3.ox_id = 0xffff; - } - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - cmdiocbq->vport = phba->pport; - iocb_stat = lpfc_sli_issue_iocb_wait(phba, LPFC_ELS_RING, cmdiocbq, - rspiocbq, (phba->fc_ratov * 2) + - LPFC_DRVR_TIMEOUT); - - if ((iocb_stat != IOCB_SUCCESS) || ((phba->sli_rev < LPFC_SLI_REV4) && - (rsp->ulpStatus != IOCB_SUCCESS))) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "3126 Failed loopback test issue iocb: " - "iocb_stat:x%x\n", iocb_stat); - rc = -EIO; - goto err_loopback_test_exit; - } - - evt->waiting = 1; - time_left = wait_event_interruptible_timeout( - evt->wq, !list_empty(&evt->events_to_see), - ((phba->fc_ratov * 2) + LPFC_DRVR_TIMEOUT) * HZ); - evt->waiting = 0; - if (list_empty(&evt->events_to_see)) { - rc = (time_left) ? -EINTR : -ETIMEDOUT; - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "3125 Not receiving unsolicited event, " - "rc:x%x\n", rc); - } else { - spin_lock_irqsave(&phba->ct_ev_lock, flags); - list_move(evt->events_to_see.prev, &evt->events_to_get); - evdat = list_entry(evt->events_to_get.prev, - typeof(*evdat), node); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - rx_databuf = evdat->data; - if (evdat->len != full_size) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "1603 Loopback test did not receive expected " - "data length. actual length 0x%x expected " - "length 0x%x\n", - evdat->len, full_size); - rc = -EIO; - } else if (rx_databuf == NULL) - rc = -EIO; - else { - rc = IOCB_SUCCESS; - /* skip over elx loopback header */ - rx_databuf += ELX_LOOPBACK_HEADER_SZ; - job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - rx_databuf, size); - job->reply->reply_payload_rcv_len = size; - } - } - -err_loopback_test_exit: - lpfcdiag_loop_self_unreg(phba, rpi); - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - lpfc_bsg_event_unref(evt); /* release ref */ - lpfc_bsg_event_unref(evt); /* delete */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - - if (cmdiocbq != NULL) - lpfc_sli_release_iocbq(phba, cmdiocbq); - - if (rspiocbq != NULL) - lpfc_sli_release_iocbq(phba, rspiocbq); - - if (txbmp != NULL) { - if (txbpl != NULL) { - if (txbuffer != NULL) - diag_cmd_data_free(phba, txbuffer); - lpfc_mbuf_free(phba, txbmp->virt, txbmp->phys); - } - kfree(txbmp); - } - -loopback_test_exit: - kfree(dataout); - /* make error code available to userspace */ - job->reply->result = rc; - job->dd_data = NULL; - /* complete the job back to userspace if no error */ - if (rc == IOCB_SUCCESS) - job->job_done(job); - return rc; -} - -/** - * lpfc_bsg_get_dfc_rev - process a GET_DFC_REV bsg vendor command - * @job: GET_DFC_REV fc_bsg_job - **/ -static int -lpfc_bsg_get_dfc_rev(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct get_mgmt_rev *event_req; - struct get_mgmt_rev_reply *event_reply; - int rc = 0; - - if (job->request_len < - sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2740 Received GET_DFC_REV request below " - "minimum size\n"); - rc = -EINVAL; - goto job_error; - } - - event_req = (struct get_mgmt_rev *) - job->request->rqst_data.h_vendor.vendor_cmd; - - event_reply = (struct get_mgmt_rev_reply *) - job->reply->reply_data.vendor_reply.vendor_rsp; - - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct get_mgmt_rev_reply)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2741 Received GET_DFC_REV reply below " - "minimum size\n"); - rc = -EINVAL; - goto job_error; - } - - event_reply->info.a_Major = MANAGEMENT_MAJOR_REV; - event_reply->info.a_Minor = MANAGEMENT_MINOR_REV; -job_error: - job->reply->result = rc; - if (rc == 0) - job->job_done(job); - return rc; -} - -/** - * lpfc_bsg_issue_mbox_cmpl - lpfc_bsg_issue_mbox mbox completion handler - * @phba: Pointer to HBA context object. - * @pmboxq: Pointer to mailbox command. - * - * This is completion handler function for mailbox commands issued from - * lpfc_bsg_issue_mbox function. This function is called by the - * mailbox event handler function with no lock held. This function - * will wake up thread waiting on the wait queue pointed by context1 - * of the mailbox. - **/ -void -lpfc_bsg_issue_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) -{ - struct bsg_job_data *dd_data; - struct fc_bsg_job *job; - uint32_t size; - unsigned long flags; - uint8_t *pmb, *pmb_buf; - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = pmboxq->context1; - /* job already timed out? */ - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return; - } - - /* - * The outgoing buffer is readily referred from the dma buffer, - * just need to get header part from mailboxq structure. - */ - pmb = (uint8_t *)&pmboxq->u.mb; - pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; - memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); - - job = dd_data->context_un.mbox.set_job; - if (job) { - size = job->reply_payload.payload_len; - job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - pmb_buf, size); - /* need to hold the lock until we set job->dd_data to NULL - * to hold off the timeout handler returning to the mid-layer - * while we are still processing the job. - */ - job->dd_data = NULL; - dd_data->context_un.mbox.set_job = NULL; - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - } else { - dd_data->context_un.mbox.set_job = NULL; - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - } - - mempool_free(dd_data->context_un.mbox.pmboxq, phba->mbox_mem_pool); - lpfc_bsg_dma_page_free(phba, dd_data->context_un.mbox.dmabuffers); - kfree(dd_data); - - if (job) { - job->reply->result = 0; - job->job_done(job); - } - return; -} - -/** - * lpfc_bsg_check_cmd_access - test for a supported mailbox command - * @phba: Pointer to HBA context object. - * @mb: Pointer to a mailbox object. - * @vport: Pointer to a vport object. - * - * Some commands require the port to be offline, some may not be called from - * the application. - **/ -static int lpfc_bsg_check_cmd_access(struct lpfc_hba *phba, - MAILBOX_t *mb, struct lpfc_vport *vport) -{ - /* return negative error values for bsg job */ - switch (mb->mbxCommand) { - /* Offline only */ - case MBX_INIT_LINK: - case MBX_DOWN_LINK: - case MBX_CONFIG_LINK: - case MBX_CONFIG_RING: - case MBX_RESET_RING: - case MBX_UNREG_LOGIN: - case MBX_CLEAR_LA: - case MBX_DUMP_CONTEXT: - case MBX_RUN_DIAGS: - case MBX_RESTART: - case MBX_SET_MASK: - if (!(vport->fc_flag & FC_OFFLINE_MODE)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2743 Command 0x%x is illegal in on-line " - "state\n", - mb->mbxCommand); - return -EPERM; - } - case MBX_WRITE_NV: - case MBX_WRITE_VPARMS: - case MBX_LOAD_SM: - case MBX_READ_NV: - case MBX_READ_CONFIG: - case MBX_READ_RCONFIG: - case MBX_READ_STATUS: - case MBX_READ_XRI: - case MBX_READ_REV: - case MBX_READ_LNK_STAT: - case MBX_DUMP_MEMORY: - case MBX_DOWN_LOAD: - case MBX_UPDATE_CFG: - case MBX_KILL_BOARD: - case MBX_LOAD_AREA: - case MBX_LOAD_EXP_ROM: - case MBX_BEACON: - case MBX_DEL_LD_ENTRY: - case MBX_SET_DEBUG: - case MBX_WRITE_WWN: - case MBX_SLI4_CONFIG: - case MBX_READ_EVENT_LOG: - case MBX_READ_EVENT_LOG_STATUS: - case MBX_WRITE_EVENT_LOG: - case MBX_PORT_CAPABILITIES: - case MBX_PORT_IOV_CONTROL: - case MBX_RUN_BIU_DIAG64: - break; - case MBX_SET_VARIABLE: - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "1226 mbox: set_variable 0x%x, 0x%x\n", - mb->un.varWords[0], - mb->un.varWords[1]); - if ((mb->un.varWords[0] == SETVAR_MLOMNT) - && (mb->un.varWords[1] == 1)) { - phba->wait_4_mlo_maint_flg = 1; - } else if (mb->un.varWords[0] == SETVAR_MLORST) { - spin_lock_irq(&phba->hbalock); - phba->link_flag &= ~LS_LOOPBACK_MODE; - spin_unlock_irq(&phba->hbalock); - phba->fc_topology = LPFC_TOPOLOGY_PT_PT; - } - break; - case MBX_READ_SPARM64: - case MBX_READ_TOPOLOGY: - case MBX_REG_LOGIN: - case MBX_REG_LOGIN64: - case MBX_CONFIG_PORT: - case MBX_RUN_BIU_DIAG: - default: - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2742 Unknown Command 0x%x\n", - mb->mbxCommand); - return -EPERM; - } - - return 0; /* ok */ -} - -/** - * lpfc_bsg_mbox_ext_cleanup - clean up context of multi-buffer mbox session - * @phba: Pointer to HBA context object. - * - * This is routine clean up and reset BSG handling of multi-buffer mbox - * command session. - **/ -static void -lpfc_bsg_mbox_ext_session_reset(struct lpfc_hba *phba) -{ - if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) - return; - - /* free all memory, including dma buffers */ - lpfc_bsg_dma_page_list_free(phba, - &phba->mbox_ext_buf_ctx.ext_dmabuf_list); - lpfc_bsg_dma_page_free(phba, phba->mbox_ext_buf_ctx.mbx_dmabuf); - /* multi-buffer write mailbox command pass-through complete */ - memset((char *)&phba->mbox_ext_buf_ctx, 0, - sizeof(struct lpfc_mbox_ext_buf_ctx)); - INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list); - - return; -} - -/** - * lpfc_bsg_issue_mbox_ext_handle_job - job handler for multi-buffer mbox cmpl - * @phba: Pointer to HBA context object. - * @pmboxq: Pointer to mailbox command. - * - * This is routine handles BSG job for mailbox commands completions with - * multiple external buffers. - **/ -static struct fc_bsg_job * -lpfc_bsg_issue_mbox_ext_handle_job(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) -{ - struct bsg_job_data *dd_data; - struct fc_bsg_job *job; - uint8_t *pmb, *pmb_buf; - unsigned long flags; - uint32_t size; - int rc = 0; - struct lpfc_dmabuf *dmabuf; - struct lpfc_sli_config_mbox *sli_cfg_mbx; - uint8_t *pmbx; - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = pmboxq->context1; - /* has the job already timed out? */ - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - job = NULL; - goto job_done_out; - } - - /* - * The outgoing buffer is readily referred from the dma buffer, - * just need to get header part from mailboxq structure. - */ - pmb = (uint8_t *)&pmboxq->u.mb; - pmb_buf = (uint8_t *)dd_data->context_un.mbox.mb; - /* Copy the byte swapped response mailbox back to the user */ - memcpy(pmb_buf, pmb, sizeof(MAILBOX_t)); - /* if there is any non-embedded extended data copy that too */ - dmabuf = phba->mbox_ext_buf_ctx.mbx_dmabuf; - sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; - if (!bsg_bf_get(lpfc_mbox_hdr_emb, - &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { - pmbx = (uint8_t *)dmabuf->virt; - /* byte swap the extended data following the mailbox command */ - lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], - &pmbx[sizeof(MAILBOX_t)], - sli_cfg_mbx->un.sli_config_emb0_subsys.mse[0].buf_len); - } - - job = dd_data->context_un.mbox.set_job; - if (job) { - size = job->reply_payload.payload_len; - job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - pmb_buf, size); - /* result for successful */ - job->reply->result = 0; - job->dd_data = NULL; - /* need to hold the lock util we set job->dd_data to NULL - * to hold off the timeout handler from midlayer to take - * any action. - */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2937 SLI_CONFIG ext-buffer maibox command " - "(x%x/x%x) complete bsg job done, bsize:%d\n", - phba->mbox_ext_buf_ctx.nembType, - phba->mbox_ext_buf_ctx.mboxType, size); - lpfc_idiag_mbxacc_dump_bsg_mbox(phba, - phba->mbox_ext_buf_ctx.nembType, - phba->mbox_ext_buf_ctx.mboxType, - dma_ebuf, sta_pos_addr, - phba->mbox_ext_buf_ctx.mbx_dmabuf, 0); - } else - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - -job_done_out: - if (!job) - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2938 SLI_CONFIG ext-buffer maibox " - "command (x%x/x%x) failure, rc:x%x\n", - phba->mbox_ext_buf_ctx.nembType, - phba->mbox_ext_buf_ctx.mboxType, rc); - /* state change */ - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_DONE; - kfree(dd_data); - - return job; -} - -/** - * lpfc_bsg_issue_read_mbox_ext_cmpl - compl handler for multi-buffer read mbox - * @phba: Pointer to HBA context object. - * @pmboxq: Pointer to mailbox command. - * - * This is completion handler function for mailbox read commands with multiple - * external buffers. - **/ -static void -lpfc_bsg_issue_read_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) -{ - struct fc_bsg_job *job; - - /* handle the BSG job with mailbox command */ - if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_ABTS) - pmboxq->u.mb.mbxStatus = MBXERR_ERROR; - - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2939 SLI_CONFIG ext-buffer rd maibox command " - "complete, ctxState:x%x, mbxStatus:x%x\n", - phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); - - job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); - - if (pmboxq->u.mb.mbxStatus || phba->mbox_ext_buf_ctx.numBuf == 1) - lpfc_bsg_mbox_ext_session_reset(phba); - - /* free base driver mailbox structure memory */ - mempool_free(pmboxq, phba->mbox_mem_pool); - - /* complete the bsg job if we have it */ - if (job) - job->job_done(job); - - return; -} - -/** - * lpfc_bsg_issue_write_mbox_ext_cmpl - cmpl handler for multi-buffer write mbox - * @phba: Pointer to HBA context object. - * @pmboxq: Pointer to mailbox command. - * - * This is completion handler function for mailbox write commands with multiple - * external buffers. - **/ -static void -lpfc_bsg_issue_write_mbox_ext_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) -{ - struct fc_bsg_job *job; - - /* handle the BSG job with the mailbox command */ - if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_ABTS) - pmboxq->u.mb.mbxStatus = MBXERR_ERROR; - - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2940 SLI_CONFIG ext-buffer wr maibox command " - "complete, ctxState:x%x, mbxStatus:x%x\n", - phba->mbox_ext_buf_ctx.state, pmboxq->u.mb.mbxStatus); - - job = lpfc_bsg_issue_mbox_ext_handle_job(phba, pmboxq); - - /* free all memory, including dma buffers */ - mempool_free(pmboxq, phba->mbox_mem_pool); - lpfc_bsg_mbox_ext_session_reset(phba); - - /* complete the bsg job if we have it */ - if (job) - job->job_done(job); - - return; -} - -static void -lpfc_bsg_sli_cfg_dma_desc_setup(struct lpfc_hba *phba, enum nemb_type nemb_tp, - uint32_t index, struct lpfc_dmabuf *mbx_dmabuf, - struct lpfc_dmabuf *ext_dmabuf) -{ - struct lpfc_sli_config_mbox *sli_cfg_mbx; - - /* pointer to the start of mailbox command */ - sli_cfg_mbx = (struct lpfc_sli_config_mbox *)mbx_dmabuf->virt; - - if (nemb_tp == nemb_mse) { - if (index == 0) { - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].pa_hi = - putPaddrHigh(mbx_dmabuf->phys + - sizeof(MAILBOX_t)); - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].pa_lo = - putPaddrLow(mbx_dmabuf->phys + - sizeof(MAILBOX_t)); - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2943 SLI_CONFIG(mse)[%d], " - "bufLen:%d, addrHi:x%x, addrLo:x%x\n", - index, - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].buf_len, - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].pa_hi, - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].pa_lo); - } else { - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].pa_hi = - putPaddrHigh(ext_dmabuf->phys); - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].pa_lo = - putPaddrLow(ext_dmabuf->phys); - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2944 SLI_CONFIG(mse)[%d], " - "bufLen:%d, addrHi:x%x, addrLo:x%x\n", - index, - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].buf_len, - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].pa_hi, - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[index].pa_lo); - } - } else { - if (index == 0) { - sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[index].pa_hi = - putPaddrHigh(mbx_dmabuf->phys + - sizeof(MAILBOX_t)); - sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[index].pa_lo = - putPaddrLow(mbx_dmabuf->phys + - sizeof(MAILBOX_t)); - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3007 SLI_CONFIG(hbd)[%d], " - "bufLen:%d, addrHi:x%x, addrLo:x%x\n", - index, - bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, - &sli_cfg_mbx->un. - sli_config_emb1_subsys.hbd[index]), - sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[index].pa_hi, - sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[index].pa_lo); - - } else { - sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[index].pa_hi = - putPaddrHigh(ext_dmabuf->phys); - sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[index].pa_lo = - putPaddrLow(ext_dmabuf->phys); - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3008 SLI_CONFIG(hbd)[%d], " - "bufLen:%d, addrHi:x%x, addrLo:x%x\n", - index, - bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, - &sli_cfg_mbx->un. - sli_config_emb1_subsys.hbd[index]), - sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[index].pa_hi, - sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[index].pa_lo); - } - } - return; -} - -/** - * lpfc_bsg_sli_cfg_mse_read_cmd_ext - sli_config non-embedded mailbox cmd read - * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @nemb_tp: Enumerate of non-embedded mailbox command type. - * @dmabuff: Pointer to a DMA buffer descriptor. - * - * This routine performs SLI_CONFIG (0x9B) read mailbox command operation with - * non-embedded external bufffers. - **/ -static int -lpfc_bsg_sli_cfg_read_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, - enum nemb_type nemb_tp, - struct lpfc_dmabuf *dmabuf) -{ - struct lpfc_sli_config_mbox *sli_cfg_mbx; - struct dfc_mbox_req *mbox_req; - struct lpfc_dmabuf *curr_dmabuf, *next_dmabuf; - uint32_t ext_buf_cnt, ext_buf_index; - struct lpfc_dmabuf *ext_dmabuf = NULL; - struct bsg_job_data *dd_data = NULL; - LPFC_MBOXQ_t *pmboxq = NULL; - MAILBOX_t *pmb; - uint8_t *pmbx; - int rc, i; - - mbox_req = - (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; - - /* pointer to the start of mailbox command */ - sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; - - if (nemb_tp == nemb_mse) { - ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, - &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); - if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2945 Handled SLI_CONFIG(mse) rd, " - "ext_buf_cnt(%d) out of range(%d)\n", - ext_buf_cnt, - LPFC_MBX_SLI_CONFIG_MAX_MSE); - rc = -ERANGE; - goto job_error; - } - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2941 Handled SLI_CONFIG(mse) rd, " - "ext_buf_cnt:%d\n", ext_buf_cnt); - } else { - /* sanity check on interface type for support */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_2) { - rc = -ENODEV; - goto job_error; - } - /* nemb_tp == nemb_hbd */ - ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; - if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2946 Handled SLI_CONFIG(hbd) rd, " - "ext_buf_cnt(%d) out of range(%d)\n", - ext_buf_cnt, - LPFC_MBX_SLI_CONFIG_MAX_HBD); - rc = -ERANGE; - goto job_error; - } - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2942 Handled SLI_CONFIG(hbd) rd, " - "ext_buf_cnt:%d\n", ext_buf_cnt); - } - - /* before dma descriptor setup */ - lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, - sta_pre_addr, dmabuf, ext_buf_cnt); - - /* reject non-embedded mailbox command with none external buffer */ - if (ext_buf_cnt == 0) { - rc = -EPERM; - goto job_error; - } else if (ext_buf_cnt > 1) { - /* additional external read buffers */ - for (i = 1; i < ext_buf_cnt; i++) { - ext_dmabuf = lpfc_bsg_dma_page_alloc(phba); - if (!ext_dmabuf) { - rc = -ENOMEM; - goto job_error; - } - list_add_tail(&ext_dmabuf->list, - &phba->mbox_ext_buf_ctx.ext_dmabuf_list); - } - } - - /* bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - rc = -ENOMEM; - goto job_error; - } - - /* mailbox command structure for base driver */ - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) { - rc = -ENOMEM; - goto job_error; - } - memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - - /* for the first external buffer */ - lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); - - /* for the rest of external buffer descriptors if any */ - if (ext_buf_cnt > 1) { - ext_buf_index = 1; - list_for_each_entry_safe(curr_dmabuf, next_dmabuf, - &phba->mbox_ext_buf_ctx.ext_dmabuf_list, list) { - lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, - ext_buf_index, dmabuf, - curr_dmabuf); - ext_buf_index++; - } - } - - /* after dma descriptor setup */ - lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_rd, dma_mbox, - sta_pos_addr, dmabuf, ext_buf_cnt); - - /* construct base driver mbox command */ - pmb = &pmboxq->u.mb; - pmbx = (uint8_t *)dmabuf->virt; - memcpy(pmb, pmbx, sizeof(*pmb)); - pmb->mbxOwner = OWN_HOST; - pmboxq->vport = phba->pport; - - /* multi-buffer handling context */ - phba->mbox_ext_buf_ctx.nembType = nemb_tp; - phba->mbox_ext_buf_ctx.mboxType = mbox_rd; - phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; - phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; - phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; - phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; - - /* callback for multi-buffer read mailbox command */ - pmboxq->mbox_cmpl = lpfc_bsg_issue_read_mbox_ext_cmpl; - - /* context fields to callback function */ - pmboxq->context1 = dd_data; - dd_data->type = TYPE_MBOX; - dd_data->context_un.mbox.pmboxq = pmboxq; - dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; - dd_data->context_un.mbox.set_job = job; - job->dd_data = dd_data; - - /* state change */ - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; - - /* - * Non-embedded mailbox subcommand data gets byte swapped here because - * the lower level driver code only does the first 64 mailbox words. - */ - if ((!bsg_bf_get(lpfc_mbox_hdr_emb, - &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) && - (nemb_tp == nemb_mse)) - lpfc_sli_pcimem_bcopy(&pmbx[sizeof(MAILBOX_t)], - &pmbx[sizeof(MAILBOX_t)], - sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[0].buf_len); - - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); - if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2947 Issued SLI_CONFIG ext-buffer " - "maibox command, rc:x%x\n", rc); - return SLI_CONFIG_HANDLED; - } - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2948 Failed to issue SLI_CONFIG ext-buffer " - "maibox command, rc:x%x\n", rc); - rc = -EPIPE; - -job_error: - if (pmboxq) - mempool_free(pmboxq, phba->mbox_mem_pool); - lpfc_bsg_dma_page_list_free(phba, - &phba->mbox_ext_buf_ctx.ext_dmabuf_list); - kfree(dd_data); - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; - return rc; -} - -/** - * lpfc_bsg_sli_cfg_write_cmd_ext - sli_config non-embedded mailbox cmd write - * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. - * - * This routine performs SLI_CONFIG (0x9B) write mailbox command operation with - * non-embedded external bufffers. - **/ -static int -lpfc_bsg_sli_cfg_write_cmd_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, - enum nemb_type nemb_tp, - struct lpfc_dmabuf *dmabuf) -{ - struct dfc_mbox_req *mbox_req; - struct lpfc_sli_config_mbox *sli_cfg_mbx; - uint32_t ext_buf_cnt; - struct bsg_job_data *dd_data = NULL; - LPFC_MBOXQ_t *pmboxq = NULL; - MAILBOX_t *pmb; - uint8_t *mbx; - int rc = SLI_CONFIG_NOT_HANDLED, i; - - mbox_req = - (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; - - /* pointer to the start of mailbox command */ - sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; - - if (nemb_tp == nemb_mse) { - ext_buf_cnt = bsg_bf_get(lpfc_mbox_hdr_mse_cnt, - &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr); - if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_MSE) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2953 Failed SLI_CONFIG(mse) wr, " - "ext_buf_cnt(%d) out of range(%d)\n", - ext_buf_cnt, - LPFC_MBX_SLI_CONFIG_MAX_MSE); - return -ERANGE; - } - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2949 Handled SLI_CONFIG(mse) wr, " - "ext_buf_cnt:%d\n", ext_buf_cnt); - } else { - /* sanity check on interface type for support */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_2) - return -ENODEV; - /* nemb_tp == nemb_hbd */ - ext_buf_cnt = sli_cfg_mbx->un.sli_config_emb1_subsys.hbd_count; - if (ext_buf_cnt > LPFC_MBX_SLI_CONFIG_MAX_HBD) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2954 Failed SLI_CONFIG(hbd) wr, " - "ext_buf_cnt(%d) out of range(%d)\n", - ext_buf_cnt, - LPFC_MBX_SLI_CONFIG_MAX_HBD); - return -ERANGE; - } - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2950 Handled SLI_CONFIG(hbd) wr, " - "ext_buf_cnt:%d\n", ext_buf_cnt); - } - - /* before dma buffer descriptor setup */ - lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, - sta_pre_addr, dmabuf, ext_buf_cnt); - - if (ext_buf_cnt == 0) - return -EPERM; - - /* for the first external buffer */ - lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, 0, dmabuf, dmabuf); - - /* after dma descriptor setup */ - lpfc_idiag_mbxacc_dump_bsg_mbox(phba, nemb_tp, mbox_wr, dma_mbox, - sta_pos_addr, dmabuf, ext_buf_cnt); - - /* log for looking forward */ - for (i = 1; i < ext_buf_cnt; i++) { - if (nemb_tp == nemb_mse) - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2951 SLI_CONFIG(mse), buf[%d]-length:%d\n", - i, sli_cfg_mbx->un.sli_config_emb0_subsys. - mse[i].buf_len); - else - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2952 SLI_CONFIG(hbd), buf[%d]-length:%d\n", - i, bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, - &sli_cfg_mbx->un.sli_config_emb1_subsys. - hbd[i])); - } - - /* multi-buffer handling context */ - phba->mbox_ext_buf_ctx.nembType = nemb_tp; - phba->mbox_ext_buf_ctx.mboxType = mbox_wr; - phba->mbox_ext_buf_ctx.numBuf = ext_buf_cnt; - phba->mbox_ext_buf_ctx.mbxTag = mbox_req->extMboxTag; - phba->mbox_ext_buf_ctx.seqNum = mbox_req->extSeqNum; - phba->mbox_ext_buf_ctx.mbx_dmabuf = dmabuf; - - if (ext_buf_cnt == 1) { - /* bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - rc = -ENOMEM; - goto job_error; - } - - /* mailbox command structure for base driver */ - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) { - rc = -ENOMEM; - goto job_error; - } - memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - pmb = &pmboxq->u.mb; - mbx = (uint8_t *)dmabuf->virt; - memcpy(pmb, mbx, sizeof(*pmb)); - pmb->mbxOwner = OWN_HOST; - pmboxq->vport = phba->pport; - - /* callback for multi-buffer read mailbox command */ - pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; - - /* context fields to callback function */ - pmboxq->context1 = dd_data; - dd_data->type = TYPE_MBOX; - dd_data->context_un.mbox.pmboxq = pmboxq; - dd_data->context_un.mbox.mb = (MAILBOX_t *)mbx; - dd_data->context_un.mbox.set_job = job; - job->dd_data = dd_data; - - /* state change */ - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; - - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); - if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2955 Issued SLI_CONFIG ext-buffer " - "maibox command, rc:x%x\n", rc); - return SLI_CONFIG_HANDLED; - } - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2956 Failed to issue SLI_CONFIG ext-buffer " - "maibox command, rc:x%x\n", rc); - rc = -EPIPE; - goto job_error; - } - - /* wait for additoinal external buffers */ - job->reply->result = 0; - job->job_done(job); - return SLI_CONFIG_HANDLED; - -job_error: - if (pmboxq) - mempool_free(pmboxq, phba->mbox_mem_pool); - kfree(dd_data); - - return rc; -} - -/** - * lpfc_bsg_handle_sli_cfg_mbox - handle sli-cfg mailbox cmd with ext buffer - * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. - * - * This routine handles SLI_CONFIG (0x9B) mailbox command with non-embedded - * external bufffers, including both 0x9B with non-embedded MSEs and 0x9B - * with embedded sussystem 0x1 and opcodes with external HBDs. - **/ -static int -lpfc_bsg_handle_sli_cfg_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, - struct lpfc_dmabuf *dmabuf) -{ - struct lpfc_sli_config_mbox *sli_cfg_mbx; - uint32_t subsys; - uint32_t opcode; - int rc = SLI_CONFIG_NOT_HANDLED; - - /* state change on new multi-buffer pass-through mailbox command */ - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_HOST; - - sli_cfg_mbx = (struct lpfc_sli_config_mbox *)dmabuf->virt; - - if (!bsg_bf_get(lpfc_mbox_hdr_emb, - &sli_cfg_mbx->un.sli_config_emb0_subsys.sli_config_hdr)) { - subsys = bsg_bf_get(lpfc_emb0_subcmnd_subsys, - &sli_cfg_mbx->un.sli_config_emb0_subsys); - opcode = bsg_bf_get(lpfc_emb0_subcmnd_opcode, - &sli_cfg_mbx->un.sli_config_emb0_subsys); - if (subsys == SLI_CONFIG_SUBSYS_FCOE) { - switch (opcode) { - case FCOE_OPCODE_READ_FCF: - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2957 Handled SLI_CONFIG " - "subsys_fcoe, opcode:x%x\n", - opcode); - rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, - nemb_mse, dmabuf); - break; - case FCOE_OPCODE_ADD_FCF: - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2958 Handled SLI_CONFIG " - "subsys_fcoe, opcode:x%x\n", - opcode); - rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, - nemb_mse, dmabuf); - break; - default: - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2959 Reject SLI_CONFIG " - "subsys_fcoe, opcode:x%x\n", - opcode); - rc = -EPERM; - break; - } - } else if (subsys == SLI_CONFIG_SUBSYS_COMN) { - switch (opcode) { - case COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES: - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3106 Handled SLI_CONFIG " - "subsys_comn, opcode:x%x\n", - opcode); - rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, - nemb_mse, dmabuf); - break; - default: - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "3107 Reject SLI_CONFIG " - "subsys_comn, opcode:x%x\n", - opcode); - rc = -EPERM; - break; - } - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2977 Reject SLI_CONFIG " - "subsys:x%d, opcode:x%x\n", - subsys, opcode); - rc = -EPERM; - } - } else { - subsys = bsg_bf_get(lpfc_emb1_subcmnd_subsys, - &sli_cfg_mbx->un.sli_config_emb1_subsys); - opcode = bsg_bf_get(lpfc_emb1_subcmnd_opcode, - &sli_cfg_mbx->un.sli_config_emb1_subsys); - if (subsys == SLI_CONFIG_SUBSYS_COMN) { - switch (opcode) { - case COMN_OPCODE_READ_OBJECT: - case COMN_OPCODE_READ_OBJECT_LIST: - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2960 Handled SLI_CONFIG " - "subsys_comn, opcode:x%x\n", - opcode); - rc = lpfc_bsg_sli_cfg_read_cmd_ext(phba, job, - nemb_hbd, dmabuf); - break; - case COMN_OPCODE_WRITE_OBJECT: - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2961 Handled SLI_CONFIG " - "subsys_comn, opcode:x%x\n", - opcode); - rc = lpfc_bsg_sli_cfg_write_cmd_ext(phba, job, - nemb_hbd, dmabuf); - break; - default: - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2962 Not handled SLI_CONFIG " - "subsys_comn, opcode:x%x\n", - opcode); - rc = SLI_CONFIG_NOT_HANDLED; - break; - } - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2978 Not handled SLI_CONFIG " - "subsys:x%d, opcode:x%x\n", - subsys, opcode); - rc = SLI_CONFIG_NOT_HANDLED; - } - } - - /* state reset on not handled new multi-buffer mailbox command */ - if (rc != SLI_CONFIG_HANDLED) - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_IDLE; - - return rc; -} - -/** - * lpfc_bsg_mbox_ext_abort_req - request to abort mbox command with ext buffers - * @phba: Pointer to HBA context object. - * - * This routine is for requesting to abort a pass-through mailbox command with - * multiple external buffers due to error condition. - **/ -static void -lpfc_bsg_mbox_ext_abort(struct lpfc_hba *phba) -{ - if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; - else - lpfc_bsg_mbox_ext_session_reset(phba); - return; -} - -/** - * lpfc_bsg_read_ebuf_get - get the next mailbox read external buffer - * @phba: Pointer to HBA context object. - * @dmabuf: Pointer to a DMA buffer descriptor. - * - * This routine extracts the next mailbox read external buffer back to - * user space through BSG. - **/ -static int -lpfc_bsg_read_ebuf_get(struct lpfc_hba *phba, struct fc_bsg_job *job) -{ - struct lpfc_sli_config_mbox *sli_cfg_mbx; - struct lpfc_dmabuf *dmabuf; - uint8_t *pbuf; - uint32_t size; - uint32_t index; - - index = phba->mbox_ext_buf_ctx.seqNum; - phba->mbox_ext_buf_ctx.seqNum++; - - sli_cfg_mbx = (struct lpfc_sli_config_mbox *) - phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; - - if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { - size = bsg_bf_get(lpfc_mbox_sli_config_mse_len, - &sli_cfg_mbx->un.sli_config_emb0_subsys.mse[index]); - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2963 SLI_CONFIG (mse) ext-buffer rd get " - "buffer[%d], size:%d\n", index, size); - } else { - size = bsg_bf_get(lpfc_mbox_sli_config_ecmn_hbd_len, - &sli_cfg_mbx->un.sli_config_emb1_subsys.hbd[index]); - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2964 SLI_CONFIG (hbd) ext-buffer rd get " - "buffer[%d], size:%d\n", index, size); - } - if (list_empty(&phba->mbox_ext_buf_ctx.ext_dmabuf_list)) - return -EPIPE; - dmabuf = list_first_entry(&phba->mbox_ext_buf_ctx.ext_dmabuf_list, - struct lpfc_dmabuf, list); - list_del_init(&dmabuf->list); - - /* after dma buffer descriptor setup */ - lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, - mbox_rd, dma_ebuf, sta_pos_addr, - dmabuf, index); - - pbuf = (uint8_t *)dmabuf->virt; - job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - pbuf, size); - - lpfc_bsg_dma_page_free(phba, dmabuf); - - if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2965 SLI_CONFIG (hbd) ext-buffer rd mbox " - "command session done\n"); - lpfc_bsg_mbox_ext_session_reset(phba); - } - - job->reply->result = 0; - job->job_done(job); - - return SLI_CONFIG_HANDLED; -} - -/** - * lpfc_bsg_write_ebuf_set - set the next mailbox write external buffer - * @phba: Pointer to HBA context object. - * @dmabuf: Pointer to a DMA buffer descriptor. - * - * This routine sets up the next mailbox read external buffer obtained - * from user space through BSG. - **/ -static int -lpfc_bsg_write_ebuf_set(struct lpfc_hba *phba, struct fc_bsg_job *job, - struct lpfc_dmabuf *dmabuf) -{ - struct lpfc_sli_config_mbox *sli_cfg_mbx; - struct bsg_job_data *dd_data = NULL; - LPFC_MBOXQ_t *pmboxq = NULL; - MAILBOX_t *pmb; - enum nemb_type nemb_tp; - uint8_t *pbuf; - uint32_t size; - uint32_t index; - int rc; - - index = phba->mbox_ext_buf_ctx.seqNum; - phba->mbox_ext_buf_ctx.seqNum++; - nemb_tp = phba->mbox_ext_buf_ctx.nembType; - - sli_cfg_mbx = (struct lpfc_sli_config_mbox *) - phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; - - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - rc = -ENOMEM; - goto job_error; - } - - pbuf = (uint8_t *)dmabuf->virt; - size = job->request_payload.payload_len; - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, - pbuf, size); - - if (phba->mbox_ext_buf_ctx.nembType == nemb_mse) { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2966 SLI_CONFIG (mse) ext-buffer wr set " - "buffer[%d], size:%d\n", - phba->mbox_ext_buf_ctx.seqNum, size); - - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2967 SLI_CONFIG (hbd) ext-buffer wr set " - "buffer[%d], size:%d\n", - phba->mbox_ext_buf_ctx.seqNum, size); - - } - - /* set up external buffer descriptor and add to external buffer list */ - lpfc_bsg_sli_cfg_dma_desc_setup(phba, nemb_tp, index, - phba->mbox_ext_buf_ctx.mbx_dmabuf, - dmabuf); - list_add_tail(&dmabuf->list, &phba->mbox_ext_buf_ctx.ext_dmabuf_list); - - /* after write dma buffer */ - lpfc_idiag_mbxacc_dump_bsg_mbox(phba, phba->mbox_ext_buf_ctx.nembType, - mbox_wr, dma_ebuf, sta_pos_addr, - dmabuf, index); - - if (phba->mbox_ext_buf_ctx.seqNum == phba->mbox_ext_buf_ctx.numBuf) { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2968 SLI_CONFIG ext-buffer wr all %d " - "ebuffers received\n", - phba->mbox_ext_buf_ctx.numBuf); - /* mailbox command structure for base driver */ - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) { - rc = -ENOMEM; - goto job_error; - } - memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - pbuf = (uint8_t *)phba->mbox_ext_buf_ctx.mbx_dmabuf->virt; - pmb = &pmboxq->u.mb; - memcpy(pmb, pbuf, sizeof(*pmb)); - pmb->mbxOwner = OWN_HOST; - pmboxq->vport = phba->pport; - - /* callback for multi-buffer write mailbox command */ - pmboxq->mbox_cmpl = lpfc_bsg_issue_write_mbox_ext_cmpl; - - /* context fields to callback function */ - pmboxq->context1 = dd_data; - dd_data->type = TYPE_MBOX; - dd_data->context_un.mbox.pmboxq = pmboxq; - dd_data->context_un.mbox.mb = (MAILBOX_t *)pbuf; - dd_data->context_un.mbox.set_job = job; - job->dd_data = dd_data; - - /* state change */ - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_PORT; - - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); - if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2969 Issued SLI_CONFIG ext-buffer " - "maibox command, rc:x%x\n", rc); - return SLI_CONFIG_HANDLED; - } - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2970 Failed to issue SLI_CONFIG ext-buffer " - "maibox command, rc:x%x\n", rc); - rc = -EPIPE; - goto job_error; - } - - /* wait for additoinal external buffers */ - job->reply->result = 0; - job->job_done(job); - return SLI_CONFIG_HANDLED; - -job_error: - lpfc_bsg_dma_page_free(phba, dmabuf); - kfree(dd_data); - - return rc; -} - -/** - * lpfc_bsg_handle_sli_cfg_ebuf - handle ext buffer with sli-cfg mailbox cmd - * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. - * - * This routine handles the external buffer with SLI_CONFIG (0x9B) mailbox - * command with multiple non-embedded external buffers. - **/ -static int -lpfc_bsg_handle_sli_cfg_ebuf(struct lpfc_hba *phba, struct fc_bsg_job *job, - struct lpfc_dmabuf *dmabuf) -{ - int rc; - - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2971 SLI_CONFIG buffer (type:x%x)\n", - phba->mbox_ext_buf_ctx.mboxType); - - if (phba->mbox_ext_buf_ctx.mboxType == mbox_rd) { - if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_DONE) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2972 SLI_CONFIG rd buffer state " - "mismatch:x%x\n", - phba->mbox_ext_buf_ctx.state); - lpfc_bsg_mbox_ext_abort(phba); - return -EPIPE; - } - rc = lpfc_bsg_read_ebuf_get(phba, job); - if (rc == SLI_CONFIG_HANDLED) - lpfc_bsg_dma_page_free(phba, dmabuf); - } else { /* phba->mbox_ext_buf_ctx.mboxType == mbox_wr */ - if (phba->mbox_ext_buf_ctx.state != LPFC_BSG_MBOX_HOST) { - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2973 SLI_CONFIG wr buffer state " - "mismatch:x%x\n", - phba->mbox_ext_buf_ctx.state); - lpfc_bsg_mbox_ext_abort(phba); - return -EPIPE; - } - rc = lpfc_bsg_write_ebuf_set(phba, job, dmabuf); - } - return rc; -} - -/** - * lpfc_bsg_handle_sli_cfg_ext - handle sli-cfg mailbox with external buffer - * @phba: Pointer to HBA context object. - * @mb: Pointer to a BSG mailbox object. - * @dmabuff: Pointer to a DMA buffer descriptor. - * - * This routine checkes and handles non-embedded multi-buffer SLI_CONFIG - * (0x9B) mailbox commands and external buffers. - **/ -static int -lpfc_bsg_handle_sli_cfg_ext(struct lpfc_hba *phba, struct fc_bsg_job *job, - struct lpfc_dmabuf *dmabuf) -{ - struct dfc_mbox_req *mbox_req; - int rc = SLI_CONFIG_NOT_HANDLED; - - mbox_req = - (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; - - /* mbox command with/without single external buffer */ - if (mbox_req->extMboxTag == 0 && mbox_req->extSeqNum == 0) - return rc; - - /* mbox command and first external buffer */ - if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_IDLE) { - if (mbox_req->extSeqNum == 1) { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2974 SLI_CONFIG mailbox: tag:%d, " - "seq:%d\n", mbox_req->extMboxTag, - mbox_req->extSeqNum); - rc = lpfc_bsg_handle_sli_cfg_mbox(phba, job, dmabuf); - return rc; - } else - goto sli_cfg_ext_error; - } - - /* - * handle additional external buffers - */ - - /* check broken pipe conditions */ - if (mbox_req->extMboxTag != phba->mbox_ext_buf_ctx.mbxTag) - goto sli_cfg_ext_error; - if (mbox_req->extSeqNum > phba->mbox_ext_buf_ctx.numBuf) - goto sli_cfg_ext_error; - if (mbox_req->extSeqNum != phba->mbox_ext_buf_ctx.seqNum + 1) - goto sli_cfg_ext_error; - - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2975 SLI_CONFIG mailbox external buffer: " - "extSta:x%x, tag:%d, seq:%d\n", - phba->mbox_ext_buf_ctx.state, mbox_req->extMboxTag, - mbox_req->extSeqNum); - rc = lpfc_bsg_handle_sli_cfg_ebuf(phba, job, dmabuf); - return rc; - -sli_cfg_ext_error: - /* all other cases, broken pipe */ - lpfc_printf_log(phba, KERN_ERR, LOG_LIBDFC, - "2976 SLI_CONFIG mailbox broken pipe: " - "ctxSta:x%x, ctxNumBuf:%d " - "ctxTag:%d, ctxSeq:%d, tag:%d, seq:%d\n", - phba->mbox_ext_buf_ctx.state, - phba->mbox_ext_buf_ctx.numBuf, - phba->mbox_ext_buf_ctx.mbxTag, - phba->mbox_ext_buf_ctx.seqNum, - mbox_req->extMboxTag, mbox_req->extSeqNum); - - lpfc_bsg_mbox_ext_session_reset(phba); - - return -EPIPE; -} - -/** - * lpfc_bsg_issue_mbox - issues a mailbox command on behalf of an app - * @phba: Pointer to HBA context object. - * @mb: Pointer to a mailbox object. - * @vport: Pointer to a vport object. - * - * Allocate a tracking object, mailbox command memory, get a mailbox - * from the mailbox pool, copy the caller mailbox command. - * - * If offline and the sli is active we need to poll for the command (port is - * being reset) and com-plete the job, otherwise issue the mailbox command and - * let our completion handler finish the command. - **/ -static uint32_t -lpfc_bsg_issue_mbox(struct lpfc_hba *phba, struct fc_bsg_job *job, - struct lpfc_vport *vport) -{ - LPFC_MBOXQ_t *pmboxq = NULL; /* internal mailbox queue */ - MAILBOX_t *pmb; /* shortcut to the pmboxq mailbox */ - /* a 4k buffer to hold the mb and extended data from/to the bsg */ - uint8_t *pmbx = NULL; - struct bsg_job_data *dd_data = NULL; /* bsg data tracking structure */ - struct lpfc_dmabuf *dmabuf = NULL; - struct dfc_mbox_req *mbox_req; - struct READ_EVENT_LOG_VAR *rdEventLog; - uint32_t transmit_length, receive_length, mode; - struct lpfc_mbx_sli4_config *sli4_config; - struct lpfc_mbx_nembed_cmd *nembed_sge; - struct mbox_header *header; - struct ulp_bde64 *bde; - uint8_t *ext = NULL; - int rc = 0; - uint8_t *from; - uint32_t size; - - - /* in case no data is transferred */ - job->reply->reply_payload_rcv_len = 0; - - /* sanity check to protect driver */ - if (job->reply_payload.payload_len > BSG_MBOX_SIZE || - job->request_payload.payload_len > BSG_MBOX_SIZE) { - rc = -ERANGE; - goto job_done; - } - - /* - * Don't allow mailbox commands to be sent when blocked or when in - * the middle of discovery - */ - if (phba->sli.sli_flag & LPFC_BLOCK_MGMT_IO) { - rc = -EAGAIN; - goto job_done; - } - - mbox_req = - (struct dfc_mbox_req *)job->request->rqst_data.h_vendor.vendor_cmd; - - /* check if requested extended data lengths are valid */ - if ((mbox_req->inExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t)) || - (mbox_req->outExtWLen > BSG_MBOX_SIZE/sizeof(uint32_t))) { - rc = -ERANGE; - goto job_done; - } - - dmabuf = lpfc_bsg_dma_page_alloc(phba); - if (!dmabuf || !dmabuf->virt) { - rc = -ENOMEM; - goto job_done; - } - - /* Get the mailbox command or external buffer from BSG */ - pmbx = (uint8_t *)dmabuf->virt; - size = job->request_payload.payload_len; - sg_copy_to_buffer(job->request_payload.sg_list, - job->request_payload.sg_cnt, pmbx, size); - - /* Handle possible SLI_CONFIG with non-embedded payloads */ - if (phba->sli_rev == LPFC_SLI_REV4) { - rc = lpfc_bsg_handle_sli_cfg_ext(phba, job, dmabuf); - if (rc == SLI_CONFIG_HANDLED) - goto job_cont; - if (rc) - goto job_done; - /* SLI_CONFIG_NOT_HANDLED for other mailbox commands */ - } - - rc = lpfc_bsg_check_cmd_access(phba, (MAILBOX_t *)pmbx, vport); - if (rc != 0) - goto job_done; /* must be negative */ - - /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2727 Failed allocation of dd_data\n"); - rc = -ENOMEM; - goto job_done; - } - - pmboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmboxq) { - rc = -ENOMEM; - goto job_done; - } - memset(pmboxq, 0, sizeof(LPFC_MBOXQ_t)); - - pmb = &pmboxq->u.mb; - memcpy(pmb, pmbx, sizeof(*pmb)); - pmb->mbxOwner = OWN_HOST; - pmboxq->vport = vport; - - /* If HBA encountered an error attention, allow only DUMP - * or RESTART mailbox commands until the HBA is restarted. - */ - if (phba->pport->stopped && - pmb->mbxCommand != MBX_DUMP_MEMORY && - pmb->mbxCommand != MBX_RESTART && - pmb->mbxCommand != MBX_WRITE_VPARMS && - pmb->mbxCommand != MBX_WRITE_WWN) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "2797 mbox: Issued mailbox cmd " - "0x%x while in stopped state.\n", - pmb->mbxCommand); - - /* extended mailbox commands will need an extended buffer */ - if (mbox_req->inExtWLen || mbox_req->outExtWLen) { - from = pmbx; - ext = from + sizeof(MAILBOX_t); - pmboxq->context2 = ext; - pmboxq->in_ext_byte_len = - mbox_req->inExtWLen * sizeof(uint32_t); - pmboxq->out_ext_byte_len = - mbox_req->outExtWLen * sizeof(uint32_t); - pmboxq->mbox_offset_word = mbox_req->mbOffset; - } - - /* biu diag will need a kernel buffer to transfer the data - * allocate our own buffer and setup the mailbox command to - * use ours - */ - if (pmb->mbxCommand == MBX_RUN_BIU_DIAG64) { - transmit_length = pmb->un.varWords[1]; - receive_length = pmb->un.varWords[4]; - /* transmit length cannot be greater than receive length or - * mailbox extension size - */ - if ((transmit_length > receive_length) || - (transmit_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { - rc = -ERANGE; - goto job_done; - } - pmb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh = - putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t)); - pmb->un.varBIUdiag.un.s2.xmit_bde64.addrLow = - putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t)); - - pmb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh = - putPaddrHigh(dmabuf->phys + sizeof(MAILBOX_t) - + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); - pmb->un.varBIUdiag.un.s2.rcv_bde64.addrLow = - putPaddrLow(dmabuf->phys + sizeof(MAILBOX_t) - + pmb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize); - } else if (pmb->mbxCommand == MBX_READ_EVENT_LOG) { - rdEventLog = &pmb->un.varRdEventLog; - receive_length = rdEventLog->rcv_bde64.tus.f.bdeSize; - mode = bf_get(lpfc_event_log, rdEventLog); - - /* receive length cannot be greater than mailbox - * extension size - */ - if (receive_length > BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { - rc = -ERANGE; - goto job_done; - } - - /* mode zero uses a bde like biu diags command */ - if (mode == 0) { - pmb->un.varWords[3] = putPaddrLow(dmabuf->phys - + sizeof(MAILBOX_t)); - pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys - + sizeof(MAILBOX_t)); - } - } else if (phba->sli_rev == LPFC_SLI_REV4) { - /* Let type 4 (well known data) through because the data is - * returned in varwords[4-8] - * otherwise check the recieve length and fetch the buffer addr - */ - if ((pmb->mbxCommand == MBX_DUMP_MEMORY) && - (pmb->un.varDmp.type != DMP_WELL_KNOWN)) { - /* rebuild the command for sli4 using our own buffers - * like we do for biu diags - */ - receive_length = pmb->un.varWords[2]; - /* receive length cannot be greater than mailbox - * extension size - */ - if (receive_length == 0) { - rc = -ERANGE; - goto job_done; - } - pmb->un.varWords[3] = putPaddrLow(dmabuf->phys - + sizeof(MAILBOX_t)); - pmb->un.varWords[4] = putPaddrHigh(dmabuf->phys - + sizeof(MAILBOX_t)); - } else if ((pmb->mbxCommand == MBX_UPDATE_CFG) && - pmb->un.varUpdateCfg.co) { - bde = (struct ulp_bde64 *)&pmb->un.varWords[4]; - - /* bde size cannot be greater than mailbox ext size */ - if (bde->tus.f.bdeSize > - BSG_MBOX_SIZE - sizeof(MAILBOX_t)) { - rc = -ERANGE; - goto job_done; - } - bde->addrHigh = putPaddrHigh(dmabuf->phys - + sizeof(MAILBOX_t)); - bde->addrLow = putPaddrLow(dmabuf->phys - + sizeof(MAILBOX_t)); - } else if (pmb->mbxCommand == MBX_SLI4_CONFIG) { - /* Handling non-embedded SLI_CONFIG mailbox command */ - sli4_config = &pmboxq->u.mqe.un.sli4_config; - if (!bf_get(lpfc_mbox_hdr_emb, - &sli4_config->header.cfg_mhdr)) { - /* rebuild the command for sli4 using our - * own buffers like we do for biu diags - */ - header = (struct mbox_header *) - &pmb->un.varWords[0]; - nembed_sge = (struct lpfc_mbx_nembed_cmd *) - &pmb->un.varWords[0]; - receive_length = nembed_sge->sge[0].length; - - /* receive length cannot be greater than - * mailbox extension size - */ - if ((receive_length == 0) || - (receive_length > - BSG_MBOX_SIZE - sizeof(MAILBOX_t))) { - rc = -ERANGE; - goto job_done; - } - - nembed_sge->sge[0].pa_hi = - putPaddrHigh(dmabuf->phys - + sizeof(MAILBOX_t)); - nembed_sge->sge[0].pa_lo = - putPaddrLow(dmabuf->phys - + sizeof(MAILBOX_t)); - } - } - } - - dd_data->context_un.mbox.dmabuffers = dmabuf; - - /* setup wake call as IOCB callback */ - pmboxq->mbox_cmpl = lpfc_bsg_issue_mbox_cmpl; - - /* setup context field to pass wait_queue pointer to wake function */ - pmboxq->context1 = dd_data; - dd_data->type = TYPE_MBOX; - dd_data->context_un.mbox.pmboxq = pmboxq; - dd_data->context_un.mbox.mb = (MAILBOX_t *)pmbx; - dd_data->context_un.mbox.set_job = job; - dd_data->context_un.mbox.ext = ext; - dd_data->context_un.mbox.mbOffset = mbox_req->mbOffset; - dd_data->context_un.mbox.inExtWLen = mbox_req->inExtWLen; - dd_data->context_un.mbox.outExtWLen = mbox_req->outExtWLen; - job->dd_data = dd_data; - - if ((vport->fc_flag & FC_OFFLINE_MODE) || - (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE))) { - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - rc = (rc == MBX_TIMEOUT) ? -ETIME : -ENODEV; - goto job_done; - } - - /* job finished, copy the data */ - memcpy(pmbx, pmb, sizeof(*pmb)); - job->reply->reply_payload_rcv_len = - sg_copy_from_buffer(job->reply_payload.sg_list, - job->reply_payload.sg_cnt, - pmbx, size); - /* not waiting mbox already done */ - rc = 0; - goto job_done; - } - - rc = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); - if ((rc == MBX_SUCCESS) || (rc == MBX_BUSY)) - return 1; /* job started */ - -job_done: - /* common exit for error or job completed inline */ - if (pmboxq) - mempool_free(pmboxq, phba->mbox_mem_pool); - lpfc_bsg_dma_page_free(phba, dmabuf); - kfree(dd_data); - -job_cont: - return rc; -} - -/** - * lpfc_bsg_mbox_cmd - process an fc bsg LPFC_BSG_VENDOR_MBOX command - * @job: MBOX fc_bsg_job for LPFC_BSG_VENDOR_MBOX. - **/ -static int -lpfc_bsg_mbox_cmd(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct dfc_mbox_req *mbox_req; - int rc = 0; - - /* mix-and-match backward compatibility */ - job->reply->reply_payload_rcv_len = 0; - if (job->request_len < - sizeof(struct fc_bsg_request) + sizeof(struct dfc_mbox_req)) { - lpfc_printf_log(phba, KERN_INFO, LOG_LIBDFC, - "2737 Mix-and-match backward compability " - "between MBOX_REQ old size:%d and " - "new request size:%d\n", - (int)(job->request_len - - sizeof(struct fc_bsg_request)), - (int)sizeof(struct dfc_mbox_req)); - mbox_req = (struct dfc_mbox_req *) - job->request->rqst_data.h_vendor.vendor_cmd; - mbox_req->extMboxTag = 0; - mbox_req->extSeqNum = 0; - } - - rc = lpfc_bsg_issue_mbox(phba, job, vport); - - if (rc == 0) { - /* job done */ - job->reply->result = 0; - job->dd_data = NULL; - job->job_done(job); - } else if (rc == 1) - /* job submitted, will complete later*/ - rc = 0; /* return zero, no error */ - else { - /* some error occurred */ - job->reply->result = rc; - job->dd_data = NULL; - } - - return rc; -} - -/** - * lpfc_bsg_menlo_cmd_cmp - lpfc_menlo_cmd completion handler - * @phba: Pointer to HBA context object. - * @cmdiocbq: Pointer to command iocb. - * @rspiocbq: Pointer to response iocb. - * - * This function is the completion handler for iocbs issued using - * lpfc_menlo_cmd function. This function is called by the - * ring event handler function without any lock held. This function - * can be called from both worker thread context and interrupt - * context. This function also can be called from another thread which - * cleans up the SLI layer objects. - * This function copies the contents of the response iocb to the - * response iocb memory object provided by the caller of - * lpfc_sli_issue_iocb_wait and then wakes up the thread which - * sleeps for the iocb completion. - **/ -static void -lpfc_bsg_menlo_cmd_cmp(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocbq, - struct lpfc_iocbq *rspiocbq) -{ - struct bsg_job_data *dd_data; - struct fc_bsg_job *job; - IOCB_t *rsp; - struct lpfc_dmabuf *bmp; - struct lpfc_bsg_menlo *menlo; - unsigned long flags; - struct menlo_response *menlo_resp; - int rc = 0; - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = cmdiocbq->context1; - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return; - } - - menlo = &dd_data->context_un.menlo; - job = menlo->set_job; - job->dd_data = NULL; /* so timeout handler does not reply */ - - spin_lock(&phba->hbalock); - cmdiocbq->iocb_flag |= LPFC_IO_WAKE; - if (cmdiocbq->context2 && rspiocbq) - memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, - &rspiocbq->iocb, sizeof(IOCB_t)); - spin_unlock(&phba->hbalock); - - bmp = menlo->bmp; - rspiocbq = menlo->rspiocbq; - rsp = &rspiocbq->iocb; - - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - - /* always return the xri, this would be used in the case - * of a menlo download to allow the data to be sent as a continuation - * of the exchange. - */ - menlo_resp = (struct menlo_response *) - job->reply->reply_data.vendor_reply.vendor_rsp; - menlo_resp->xri = rsp->ulpContext; - if (rsp->ulpStatus) { - if (rsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (rsp->un.ulpWord[4] & 0xff) { - case IOERR_SEQUENCE_TIMEOUT: - rc = -ETIMEDOUT; - break; - case IOERR_INVALID_RPI: - rc = -EFAULT; - break; - default: - rc = -EACCES; - break; - } - } else - rc = -EACCES; - } else - job->reply->reply_payload_rcv_len = - rsp->un.genreq64.bdl.bdeSize; - - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); - lpfc_sli_release_iocbq(phba, rspiocbq); - lpfc_sli_release_iocbq(phba, cmdiocbq); - kfree(bmp); - kfree(dd_data); - /* make error code available to userspace */ - job->reply->result = rc; - /* complete the job back to userspace */ - job->job_done(job); - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return; -} - -/** - * lpfc_menlo_cmd - send an ioctl for menlo hardware - * @job: fc_bsg_job to handle - * - * This function issues a gen request 64 CR ioctl for all menlo cmd requests, - * all the command completions will return the xri for the command. - * For menlo data requests a gen request 64 CX is used to continue the exchange - * supplied in the menlo request header xri field. - **/ -static int -lpfc_menlo_cmd(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocbq, *rspiocbq; - IOCB_t *cmd, *rsp; - int rc = 0; - struct menlo_command *menlo_cmd; - struct menlo_response *menlo_resp; - struct lpfc_dmabuf *bmp = NULL; - int request_nseg; - int reply_nseg; - struct scatterlist *sgel = NULL; - int numbde; - dma_addr_t busaddr; - struct bsg_job_data *dd_data; - struct ulp_bde64 *bpl = NULL; - - /* in case no data is returned return just the return code */ - job->reply->reply_payload_rcv_len = 0; - - if (job->request_len < - sizeof(struct fc_bsg_request) + - sizeof(struct menlo_command)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2784 Received MENLO_CMD request below " - "minimum size\n"); - rc = -ERANGE; - goto no_dd_data; - } - - if (job->reply_len < - sizeof(struct fc_bsg_request) + sizeof(struct menlo_response)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2785 Received MENLO_CMD reply below " - "minimum size\n"); - rc = -ERANGE; - goto no_dd_data; - } - - if (!(phba->menlo_flag & HBA_MENLO_SUPPORT)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2786 Adapter does not support menlo " - "commands\n"); - rc = -EPERM; - goto no_dd_data; - } - - menlo_cmd = (struct menlo_command *) - job->request->rqst_data.h_vendor.vendor_cmd; - - menlo_resp = (struct menlo_response *) - job->reply->reply_data.vendor_reply.vendor_rsp; - - /* allocate our bsg tracking structure */ - dd_data = kmalloc(sizeof(struct bsg_job_data), GFP_KERNEL); - if (!dd_data) { - lpfc_printf_log(phba, KERN_WARNING, LOG_LIBDFC, - "2787 Failed allocation of dd_data\n"); - rc = -ENOMEM; - goto no_dd_data; - } - - bmp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) { - rc = -ENOMEM; - goto free_dd; - } - - cmdiocbq = lpfc_sli_get_iocbq(phba); - if (!cmdiocbq) { - rc = -ENOMEM; - goto free_bmp; - } - - rspiocbq = lpfc_sli_get_iocbq(phba); - if (!rspiocbq) { - rc = -ENOMEM; - goto free_cmdiocbq; - } - - rsp = &rspiocbq->iocb; - - bmp->virt = lpfc_mbuf_alloc(phba, 0, &bmp->phys); - if (!bmp->virt) { - rc = -ENOMEM; - goto free_rspiocbq; - } - - INIT_LIST_HEAD(&bmp->list); - bpl = (struct ulp_bde64 *) bmp->virt; - request_nseg = pci_map_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - for_each_sg(job->request_payload.sg_list, sgel, request_nseg, numbde) { - busaddr = sg_dma_address(sgel); - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl->tus.f.bdeSize = sg_dma_len(sgel); - bpl->tus.w = cpu_to_le32(bpl->tus.w); - bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); - bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); - bpl++; - } - - reply_nseg = pci_map_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - for_each_sg(job->reply_payload.sg_list, sgel, reply_nseg, numbde) { - busaddr = sg_dma_address(sgel); - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; - bpl->tus.f.bdeSize = sg_dma_len(sgel); - bpl->tus.w = cpu_to_le32(bpl->tus.w); - bpl->addrLow = cpu_to_le32(putPaddrLow(busaddr)); - bpl->addrHigh = cpu_to_le32(putPaddrHigh(busaddr)); - bpl++; - } - - cmd = &cmdiocbq->iocb; - cmd->un.genreq64.bdl.ulpIoTag32 = 0; - cmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); - cmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); - cmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - cmd->un.genreq64.bdl.bdeSize = - (request_nseg + reply_nseg) * sizeof(struct ulp_bde64); - cmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); - cmd->un.genreq64.w5.hcsw.Dfctl = 0; - cmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CMD; - cmd->un.genreq64.w5.hcsw.Type = MENLO_TRANSPORT_TYPE; /* 0xfe */ - cmd->ulpBdeCount = 1; - cmd->ulpClass = CLASS3; - cmd->ulpOwner = OWN_CHIP; - cmd->ulpLe = 1; /* Limited Edition */ - cmdiocbq->iocb_flag |= LPFC_IO_LIBDFC; - cmdiocbq->vport = phba->pport; - /* We want the firmware to timeout before we do */ - cmd->ulpTimeout = MENLO_TIMEOUT - 5; - cmdiocbq->context3 = bmp; - cmdiocbq->context2 = rspiocbq; - cmdiocbq->iocb_cmpl = lpfc_bsg_menlo_cmd_cmp; - cmdiocbq->context1 = dd_data; - cmdiocbq->context2 = rspiocbq; - if (menlo_cmd->cmd == LPFC_BSG_VENDOR_MENLO_CMD) { - cmd->ulpCommand = CMD_GEN_REQUEST64_CR; - cmd->ulpPU = MENLO_PU; /* 3 */ - cmd->un.ulpWord[4] = MENLO_DID; /* 0x0000FC0E */ - cmd->ulpContext = MENLO_CONTEXT; /* 0 */ - } else { - cmd->ulpCommand = CMD_GEN_REQUEST64_CX; - cmd->ulpPU = 1; - cmd->un.ulpWord[4] = 0; - cmd->ulpContext = menlo_cmd->xri; - } - - dd_data->type = TYPE_MENLO; - dd_data->context_un.menlo.cmdiocbq = cmdiocbq; - dd_data->context_un.menlo.rspiocbq = rspiocbq; - dd_data->context_un.menlo.set_job = job; - dd_data->context_un.menlo.bmp = bmp; - - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, cmdiocbq, - MENLO_TIMEOUT - 5); - if (rc == IOCB_SUCCESS) - return 0; /* done for now */ - - /* iocb failed so cleanup */ - pci_unmap_sg(phba->pcidev, job->request_payload.sg_list, - job->request_payload.sg_cnt, DMA_TO_DEVICE); - pci_unmap_sg(phba->pcidev, job->reply_payload.sg_list, - job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); - -free_rspiocbq: - lpfc_sli_release_iocbq(phba, rspiocbq); -free_cmdiocbq: - lpfc_sli_release_iocbq(phba, cmdiocbq); -free_bmp: - kfree(bmp); -free_dd: - kfree(dd_data); -no_dd_data: - /* make error code available to userspace */ - job->reply->result = rc; - job->dd_data = NULL; - return rc; -} - -/** - * lpfc_bsg_hst_vendor - process a vendor-specific fc_bsg_job - * @job: fc_bsg_job to handle - **/ -static int -lpfc_bsg_hst_vendor(struct fc_bsg_job *job) -{ - int command = job->request->rqst_data.h_vendor.vendor_cmd[0]; - int rc; - - switch (command) { - case LPFC_BSG_VENDOR_SET_CT_EVENT: - rc = lpfc_bsg_hba_set_event(job); - break; - case LPFC_BSG_VENDOR_GET_CT_EVENT: - rc = lpfc_bsg_hba_get_event(job); - break; - case LPFC_BSG_VENDOR_SEND_MGMT_RESP: - rc = lpfc_bsg_send_mgmt_rsp(job); - break; - case LPFC_BSG_VENDOR_DIAG_MODE: - rc = lpfc_bsg_diag_loopback_mode(job); - break; - case LPFC_BSG_VENDOR_DIAG_MODE_END: - rc = lpfc_sli4_bsg_diag_mode_end(job); - break; - case LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK: - rc = lpfc_bsg_diag_loopback_run(job); - break; - case LPFC_BSG_VENDOR_LINK_DIAG_TEST: - rc = lpfc_sli4_bsg_link_diag_test(job); - break; - case LPFC_BSG_VENDOR_GET_MGMT_REV: - rc = lpfc_bsg_get_dfc_rev(job); - break; - case LPFC_BSG_VENDOR_MBOX: - rc = lpfc_bsg_mbox_cmd(job); - break; - case LPFC_BSG_VENDOR_MENLO_CMD: - case LPFC_BSG_VENDOR_MENLO_DATA: - rc = lpfc_menlo_cmd(job); - break; - default: - rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - /* make error code available to userspace */ - job->reply->result = rc; - break; - } - - return rc; -} - -/** - * lpfc_bsg_request - handle a bsg request from the FC transport - * @job: fc_bsg_job to handle - **/ -int -lpfc_bsg_request(struct fc_bsg_job *job) -{ - uint32_t msgcode; - int rc; - - msgcode = job->request->msgcode; - switch (msgcode) { - case FC_BSG_HST_VENDOR: - rc = lpfc_bsg_hst_vendor(job); - break; - case FC_BSG_RPT_ELS: - rc = lpfc_bsg_rport_els(job); - break; - case FC_BSG_RPT_CT: - rc = lpfc_bsg_send_mgmt_cmd(job); - break; - default: - rc = -EINVAL; - job->reply->reply_payload_rcv_len = 0; - /* make error code available to userspace */ - job->reply->result = rc; - break; - } - - return rc; -} - -/** - * lpfc_bsg_timeout - handle timeout of a bsg request from the FC transport - * @job: fc_bsg_job that has timed out - * - * This function just aborts the job's IOCB. The aborted IOCB will return to - * the waiting function which will handle passing the error back to userspace - **/ -int -lpfc_bsg_timeout(struct fc_bsg_job *job) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)job->shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb; - struct lpfc_bsg_event *evt; - struct lpfc_bsg_iocb *iocb; - struct lpfc_bsg_mbox *mbox; - struct lpfc_bsg_menlo *menlo; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct bsg_job_data *dd_data; - unsigned long flags; - - spin_lock_irqsave(&phba->ct_ev_lock, flags); - dd_data = (struct bsg_job_data *)job->dd_data; - /* timeout and completion crossed paths if no dd_data */ - if (!dd_data) { - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - return 0; - } - - switch (dd_data->type) { - case TYPE_IOCB: - iocb = &dd_data->context_un.iocb; - cmdiocb = iocb->cmdiocbq; - /* hint to completion handler that the job timed out */ - job->reply->result = -EAGAIN; - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - /* this will call our completion handler */ - spin_lock_irq(&phba->hbalock); - lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); - spin_unlock_irq(&phba->hbalock); - break; - case TYPE_EVT: - evt = dd_data->context_un.evt; - /* this event has no job anymore */ - evt->set_job = NULL; - job->dd_data = NULL; - job->reply->reply_payload_rcv_len = 0; - /* Return -EAGAIN which is our way of signallying the - * app to retry. - */ - job->reply->result = -EAGAIN; - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - job->job_done(job); - break; - case TYPE_MBOX: - mbox = &dd_data->context_un.mbox; - /* this mbox has no job anymore */ - mbox->set_job = NULL; - job->dd_data = NULL; - job->reply->reply_payload_rcv_len = 0; - job->reply->result = -EAGAIN; - /* the mbox completion handler can now be run */ - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - job->job_done(job); - if (phba->mbox_ext_buf_ctx.state == LPFC_BSG_MBOX_PORT) - phba->mbox_ext_buf_ctx.state = LPFC_BSG_MBOX_ABTS; - break; - case TYPE_MENLO: - menlo = &dd_data->context_un.menlo; - cmdiocb = menlo->cmdiocbq; - /* hint to completion handler that the job timed out */ - job->reply->result = -EAGAIN; - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - /* this will call our completion handler */ - spin_lock_irq(&phba->hbalock); - lpfc_sli_issue_abort_iotag(phba, pring, cmdiocb); - spin_unlock_irq(&phba->hbalock); - break; - default: - spin_unlock_irqrestore(&phba->ct_ev_lock, flags); - break; - } - - /* scsi transport fc fc_bsg_job_timeout expects a zero return code, - * otherwise an error message will be displayed on the console - * so always return success (zero) - */ - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.h deleted file mode 100644 index edfe61fc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_bsg.h +++ /dev/null @@ -1,285 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2010 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ -/* bsg definitions - * No pointers to user data are allowed, all application buffers and sizes will - * derived through the bsg interface. - * - * These are the vendor unique structures passed in using the bsg - * FC_BSG_HST_VENDOR message code type. - */ -#define LPFC_BSG_VENDOR_SET_CT_EVENT 1 -#define LPFC_BSG_VENDOR_GET_CT_EVENT 2 -#define LPFC_BSG_VENDOR_SEND_MGMT_RESP 3 -#define LPFC_BSG_VENDOR_DIAG_MODE 4 -#define LPFC_BSG_VENDOR_DIAG_RUN_LOOPBACK 5 -#define LPFC_BSG_VENDOR_GET_MGMT_REV 6 -#define LPFC_BSG_VENDOR_MBOX 7 -#define LPFC_BSG_VENDOR_MENLO_CMD 8 -#define LPFC_BSG_VENDOR_MENLO_DATA 9 -#define LPFC_BSG_VENDOR_DIAG_MODE_END 10 -#define LPFC_BSG_VENDOR_LINK_DIAG_TEST 11 - -struct set_ct_event { - uint32_t command; - uint32_t type_mask; - uint32_t ev_req_id; - uint32_t ev_reg_id; -}; - -struct get_ct_event { - uint32_t command; - uint32_t ev_reg_id; - uint32_t ev_req_id; -}; - -struct get_ct_event_reply { - uint32_t immed_data; - uint32_t type; -}; - -struct send_mgmt_resp { - uint32_t command; - uint32_t tag; -}; - - -#define INTERNAL_LOOP_BACK 0x1 /* adapter short cuts the loop internally */ -#define EXTERNAL_LOOP_BACK 0x2 /* requires an external loopback plug */ - -struct diag_mode_set { - uint32_t command; - uint32_t type; - uint32_t timeout; -}; - -struct sli4_link_diag { - uint32_t command; - uint32_t timeout; - uint32_t test_id; - uint32_t loops; - uint32_t test_version; - uint32_t error_action; -}; - -struct diag_mode_test { - uint32_t command; -}; - -struct diag_status { - uint32_t mbox_status; - uint32_t shdr_status; - uint32_t shdr_add_status; -}; - -#define LPFC_WWNN_TYPE 0 -#define LPFC_WWPN_TYPE 1 - -struct get_mgmt_rev { - uint32_t command; -}; - -#define MANAGEMENT_MAJOR_REV 1 -#define MANAGEMENT_MINOR_REV 1 - -/* the MgmtRevInfo structure */ -struct MgmtRevInfo { - uint32_t a_Major; - uint32_t a_Minor; -}; - -struct get_mgmt_rev_reply { - struct MgmtRevInfo info; -}; - -#define BSG_MBOX_SIZE 4096 /* mailbox command plus extended data */ - -/* BSG mailbox request header */ -struct dfc_mbox_req { - uint32_t command; - uint32_t mbOffset; - uint32_t inExtWLen; - uint32_t outExtWLen; - uint32_t extMboxTag; - uint32_t extSeqNum; -}; - -/* Used for menlo command or menlo data. The xri is only used for menlo data */ -struct menlo_command { - uint32_t cmd; - uint32_t xri; -}; - -struct menlo_response { - uint32_t xri; /* return the xri of the iocb exchange */ -}; - -/* - * macros and data structures for handling sli-config mailbox command - * pass-through support, this header file is shared between user and - * kernel spaces, note the set of macros are duplicates from lpfc_hw4.h, - * with macro names prefixed with bsg_, as the macros defined in - * lpfc_hw4.h are not accessible from user space. - */ - -/* Macros to deal with bit fields. Each bit field must have 3 #defines - * associated with it (_SHIFT, _MASK, and _WORD). - * EG. For a bit field that is in the 7th bit of the "field4" field of a - * structure and is 2 bits in size the following #defines must exist: - * struct temp { - * uint32_t field1; - * uint32_t field2; - * uint32_t field3; - * uint32_t field4; - * #define example_bit_field_SHIFT 7 - * #define example_bit_field_MASK 0x03 - * #define example_bit_field_WORD field4 - * uint32_t field5; - * }; - * Then the macros below may be used to get or set the value of that field. - * EG. To get the value of the bit field from the above example: - * struct temp t1; - * value = bsg_bf_get(example_bit_field, &t1); - * And then to set that bit field: - * bsg_bf_set(example_bit_field, &t1, 2); - * Or clear that bit field: - * bsg_bf_set(example_bit_field, &t1, 0); - */ -#define bsg_bf_get_le32(name, ptr) \ - ((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK) -#define bsg_bf_get(name, ptr) \ - (((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK) -#define bsg_bf_set_le32(name, ptr, value) \ - ((ptr)->name##_WORD = cpu_to_le32(((((value) & \ - name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \ - ~(name##_MASK << name##_SHIFT))))) -#define bsg_bf_set(name, ptr, value) \ - ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \ - ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT)))) - -/* - * The sli_config structure specified here is based on the following - * restriction: - * - * -- SLI_CONFIG EMB=0, carrying MSEs, will carry subcommands without - * carrying HBD. - * -- SLI_CONFIG EMB=1, not carrying MSE, will carry subcommands with or - * without carrying HBDs. - */ - -struct lpfc_sli_config_mse { - uint32_t pa_lo; - uint32_t pa_hi; - uint32_t buf_len; -#define lpfc_mbox_sli_config_mse_len_SHIFT 0 -#define lpfc_mbox_sli_config_mse_len_MASK 0xffffff -#define lpfc_mbox_sli_config_mse_len_WORD buf_len -}; - -struct lpfc_sli_config_hbd { - uint32_t buf_len; -#define lpfc_mbox_sli_config_ecmn_hbd_len_SHIFT 0 -#define lpfc_mbox_sli_config_ecmn_hbd_len_MASK 0xffffff -#define lpfc_mbox_sli_config_ecmn_hbd_len_WORD buf_len - uint32_t pa_lo; - uint32_t pa_hi; -}; - -struct lpfc_sli_config_hdr { - uint32_t word1; -#define lpfc_mbox_hdr_emb_SHIFT 0 -#define lpfc_mbox_hdr_emb_MASK 0x00000001 -#define lpfc_mbox_hdr_emb_WORD word1 -#define lpfc_mbox_hdr_mse_cnt_SHIFT 3 -#define lpfc_mbox_hdr_mse_cnt_MASK 0x0000001f -#define lpfc_mbox_hdr_mse_cnt_WORD word1 - uint32_t payload_length; - uint32_t tag_lo; - uint32_t tag_hi; - uint32_t reserved5; -}; - -struct lpfc_sli_config_emb0_subsys { - struct lpfc_sli_config_hdr sli_config_hdr; -#define LPFC_MBX_SLI_CONFIG_MAX_MSE 19 - struct lpfc_sli_config_mse mse[LPFC_MBX_SLI_CONFIG_MAX_MSE]; - uint32_t padding; - uint32_t word64; -#define lpfc_emb0_subcmnd_opcode_SHIFT 0 -#define lpfc_emb0_subcmnd_opcode_MASK 0xff -#define lpfc_emb0_subcmnd_opcode_WORD word64 -#define lpfc_emb0_subcmnd_subsys_SHIFT 8 -#define lpfc_emb0_subcmnd_subsys_MASK 0xff -#define lpfc_emb0_subcmnd_subsys_WORD word64 -/* Subsystem FCOE (0x0C) OpCodes */ -#define SLI_CONFIG_SUBSYS_FCOE 0x0C -#define FCOE_OPCODE_READ_FCF 0x08 -#define FCOE_OPCODE_ADD_FCF 0x09 -}; - -struct lpfc_sli_config_emb1_subsys { - struct lpfc_sli_config_hdr sli_config_hdr; - uint32_t word6; -#define lpfc_emb1_subcmnd_opcode_SHIFT 0 -#define lpfc_emb1_subcmnd_opcode_MASK 0xff -#define lpfc_emb1_subcmnd_opcode_WORD word6 -#define lpfc_emb1_subcmnd_subsys_SHIFT 8 -#define lpfc_emb1_subcmnd_subsys_MASK 0xff -#define lpfc_emb1_subcmnd_subsys_WORD word6 -/* Subsystem COMN (0x01) OpCodes */ -#define SLI_CONFIG_SUBSYS_COMN 0x01 -#define COMN_OPCODE_READ_OBJECT 0xAB -#define COMN_OPCODE_WRITE_OBJECT 0xAC -#define COMN_OPCODE_READ_OBJECT_LIST 0xAD -#define COMN_OPCODE_DELETE_OBJECT 0xAE -#define COMN_OPCODE_GET_CNTL_ADDL_ATTRIBUTES 0x79 - uint32_t timeout; - uint32_t request_length; - uint32_t word9; -#define lpfc_subcmnd_version_SHIFT 0 -#define lpfc_subcmnd_version_MASK 0xff -#define lpfc_subcmnd_version_WORD word9 - uint32_t word10; -#define lpfc_subcmnd_ask_rd_len_SHIFT 0 -#define lpfc_subcmnd_ask_rd_len_MASK 0xffffff -#define lpfc_subcmnd_ask_rd_len_WORD word10 - uint32_t rd_offset; - uint32_t obj_name[26]; - uint32_t hbd_count; -#define LPFC_MBX_SLI_CONFIG_MAX_HBD 8 - struct lpfc_sli_config_hbd hbd[LPFC_MBX_SLI_CONFIG_MAX_HBD]; -}; - -struct lpfc_sli_config_mbox { - uint32_t word0; -#define lpfc_mqe_status_SHIFT 16 -#define lpfc_mqe_status_MASK 0x0000FFFF -#define lpfc_mqe_status_WORD word0 -#define lpfc_mqe_command_SHIFT 8 -#define lpfc_mqe_command_MASK 0x000000FF -#define lpfc_mqe_command_WORD word0 - union { - struct lpfc_sli_config_emb0_subsys sli_config_emb0_subsys; - struct lpfc_sli_config_emb1_subsys sli_config_emb1_subsys; - } un; -}; - -/* driver only */ -#define SLI_CONFIG_NOT_HANDLED 0 -#define SLI_CONFIG_HANDLED 1 diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_compat.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_compat.h deleted file mode 100644 index c88e556e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_compat.h +++ /dev/null @@ -1,96 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2011 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -/* - * This file provides macros to aid compilation in the Linux 2.4 kernel - * over various platform architectures. - */ - -/******************************************************************* -Note: HBA's SLI memory contains little-endian LW. -Thus to access it from a little-endian host, -memcpy_toio() and memcpy_fromio() can be used. -However on a big-endian host, copy 4 bytes at a time, -using writel() and readl(). - *******************************************************************/ -#include - -#ifdef __BIG_ENDIAN - -static inline void -lpfc_memcpy_to_slim(void __iomem *dest, void *src, unsigned int bytes) -{ - uint32_t __iomem *dest32; - uint32_t *src32; - unsigned int four_bytes; - - - dest32 = (uint32_t __iomem *) dest; - src32 = (uint32_t *) src; - - /* write input bytes, 4 bytes at a time */ - for (four_bytes = bytes /4; four_bytes > 0; four_bytes--) { - writel( *src32, dest32); - readl(dest32); /* flush */ - dest32++; - src32++; - } - - return; -} - -static inline void -lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes) -{ - uint32_t *dest32; - uint32_t __iomem *src32; - unsigned int four_bytes; - - - dest32 = (uint32_t *) dest; - src32 = (uint32_t __iomem *) src; - - /* read input bytes, 4 bytes at a time */ - for (four_bytes = bytes /4; four_bytes > 0; four_bytes--) { - *dest32 = readl( src32); - dest32++; - src32++; - } - - return; -} - -#else - -static inline void -lpfc_memcpy_to_slim( void __iomem *dest, void *src, unsigned int bytes) -{ - /* convert bytes in argument list to word count for copy function */ - __iowrite32_copy(dest, src, bytes / sizeof(uint32_t)); -} - -static inline void -lpfc_memcpy_from_slim( void *dest, void __iomem *src, unsigned int bytes) -{ - /* actually returns 1 byte past dest */ - memcpy_fromio( dest, src, bytes); -} - -#endif /* __BIG_ENDIAN */ diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_crtn.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_crtn.h deleted file mode 100644 index 330dd719..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_crtn.h +++ /dev/null @@ -1,465 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2011 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -typedef int (*node_filter)(struct lpfc_nodelist *, void *); - -struct fc_rport; -void lpfc_down_link(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_sli_read_link_ste(struct lpfc_hba *); -void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t, uint16_t); -void lpfc_dump_wakeup_param(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_dump_static_vport(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t); -int lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *, struct lpfcMboxq *); -void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_config_async(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); - -void lpfc_heart_beat(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_read_topology(struct lpfc_hba *, LPFC_MBOXQ_t *, struct lpfc_dmabuf *); -void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_issue_clear_la(struct lpfc_hba *, struct lpfc_vport *); -void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_config_msi(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *, int); -void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_reg_rpi(struct lpfc_hba *, uint16_t, uint32_t, uint8_t *, - LPFC_MBOXQ_t *, uint16_t); -void lpfc_set_var(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); -void lpfc_unreg_login(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); -void lpfc_unreg_did(struct lpfc_hba *, uint16_t, uint32_t, LPFC_MBOXQ_t *); -void lpfc_sli4_unreg_all_rpis(struct lpfc_vport *); - -void lpfc_reg_vpi(struct lpfc_vport *, LPFC_MBOXQ_t *); -void lpfc_register_new_vport(struct lpfc_hba *, struct lpfc_vport *, - struct lpfc_nodelist *); -void lpfc_unreg_vpi(struct lpfc_hba *, uint16_t, LPFC_MBOXQ_t *); -void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t); -void lpfc_request_features(struct lpfc_hba *, struct lpfcMboxq *); -void lpfc_supported_pages(struct lpfcMboxq *); -void lpfc_pc_sli4_params(struct lpfcMboxq *); -int lpfc_pc_sli4_params_get(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_sli4_mbox_rsrc_extent(struct lpfc_hba *, struct lpfcMboxq *, - uint16_t, uint16_t, bool); -int lpfc_get_sli4_parameters(struct lpfc_hba *, LPFC_MBOXQ_t *); -struct lpfc_vport *lpfc_find_vport_by_did(struct lpfc_hba *, uint32_t); -void lpfc_cleanup_rcv_buffers(struct lpfc_vport *); -void lpfc_rcv_seq_check_edtov(struct lpfc_vport *); -void lpfc_cleanup_rpis(struct lpfc_vport *, int); -void lpfc_cleanup_pending_mbox(struct lpfc_vport *); -int lpfc_linkdown(struct lpfc_hba *); -void lpfc_linkdown_port(struct lpfc_vport *); -void lpfc_port_link_failure(struct lpfc_vport *); -void lpfc_mbx_cmpl_read_topology(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_init_vpi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *); -void lpfc_retry_pport_discovery(struct lpfc_hba *); -void lpfc_release_rpi(struct lpfc_hba *, struct lpfc_vport *, uint16_t); - -void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_unregister_vfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_enqueue_node(struct lpfc_vport *, struct lpfc_nodelist *); -void lpfc_dequeue_node(struct lpfc_vport *, struct lpfc_nodelist *); -struct lpfc_nodelist *lpfc_enable_node(struct lpfc_vport *, - struct lpfc_nodelist *, int); -void lpfc_nlp_set_state(struct lpfc_vport *, struct lpfc_nodelist *, int); -void lpfc_drop_node(struct lpfc_vport *, struct lpfc_nodelist *); -void lpfc_set_disctmo(struct lpfc_vport *); -int lpfc_can_disctmo(struct lpfc_vport *); -int lpfc_unreg_rpi(struct lpfc_vport *, struct lpfc_nodelist *); -void lpfc_unreg_all_rpis(struct lpfc_vport *); -void lpfc_unreg_hba_rpis(struct lpfc_hba *); -void lpfc_unreg_default_rpis(struct lpfc_vport *); -void lpfc_issue_reg_vpi(struct lpfc_hba *, struct lpfc_vport *); - -int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *, struct lpfc_nodelist *); -void lpfc_nlp_init(struct lpfc_vport *, struct lpfc_nodelist *, uint32_t); -struct lpfc_nodelist *lpfc_nlp_get(struct lpfc_nodelist *); -int lpfc_nlp_put(struct lpfc_nodelist *); -int lpfc_nlp_not_used(struct lpfc_nodelist *ndlp); -struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_vport *, uint32_t); -void lpfc_disc_list_loopmap(struct lpfc_vport *); -void lpfc_disc_start(struct lpfc_vport *); -void lpfc_cleanup_discovery_resources(struct lpfc_vport *); -void lpfc_cleanup(struct lpfc_vport *); -void lpfc_disc_timeout(unsigned long); - -struct lpfc_nodelist *__lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); -struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_vport *, uint16_t); -void lpfc_worker_wake_up(struct lpfc_hba *); -int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t); -int lpfc_do_work(void *); -int lpfc_disc_state_machine(struct lpfc_vport *, struct lpfc_nodelist *, void *, - uint32_t); - -void lpfc_do_scr_ns_plogi(struct lpfc_hba *, struct lpfc_vport *); -int lpfc_check_sparm(struct lpfc_vport *, struct lpfc_nodelist *, - struct serv_parm *, uint32_t, int); -int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist *); -void lpfc_more_plogi(struct lpfc_vport *); -void lpfc_more_adisc(struct lpfc_vport *); -void lpfc_end_rscn(struct lpfc_vport *); -int lpfc_els_chk_latt(struct lpfc_vport *); -int lpfc_els_abort_flogi(struct lpfc_hba *); -int lpfc_initial_flogi(struct lpfc_vport *); -void lpfc_issue_init_vfi(struct lpfc_vport *); -int lpfc_initial_fdisc(struct lpfc_vport *); -int lpfc_issue_els_plogi(struct lpfc_vport *, uint32_t, uint8_t); -int lpfc_issue_els_prli(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); -int lpfc_issue_els_adisc(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); -int lpfc_issue_els_logo(struct lpfc_vport *, struct lpfc_nodelist *, uint8_t); -int lpfc_issue_els_npiv_logo(struct lpfc_vport *, struct lpfc_nodelist *); -int lpfc_issue_els_scr(struct lpfc_vport *, uint32_t, uint8_t); -int lpfc_issue_fabric_reglogin(struct lpfc_vport *); -int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); -int lpfc_ct_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *); -int lpfc_els_rsp_acc(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, - struct lpfc_nodelist *, LPFC_MBOXQ_t *); -int lpfc_els_rsp_reject(struct lpfc_vport *, uint32_t, struct lpfc_iocbq *, - struct lpfc_nodelist *, LPFC_MBOXQ_t *); -int lpfc_els_rsp_adisc_acc(struct lpfc_vport *, struct lpfc_iocbq *, - struct lpfc_nodelist *); -int lpfc_els_rsp_prli_acc(struct lpfc_vport *, struct lpfc_iocbq *, - struct lpfc_nodelist *); -void lpfc_cancel_retry_delay_tmo(struct lpfc_vport *, struct lpfc_nodelist *); -void lpfc_els_retry_delay(unsigned long); -void lpfc_els_retry_delay_handler(struct lpfc_nodelist *); -void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); -int lpfc_els_handle_rscn(struct lpfc_vport *); -void lpfc_els_flush_rscn(struct lpfc_vport *); -int lpfc_rscn_payload_check(struct lpfc_vport *, uint32_t); -void lpfc_els_flush_all_cmd(struct lpfc_hba *); -void lpfc_els_flush_cmd(struct lpfc_vport *); -int lpfc_els_disc_adisc(struct lpfc_vport *); -int lpfc_els_disc_plogi(struct lpfc_vport *); -void lpfc_els_timeout(unsigned long); -void lpfc_els_timeout_handler(struct lpfc_vport *); -struct lpfc_iocbq *lpfc_prep_els_iocb(struct lpfc_vport *, uint8_t, uint16_t, - uint8_t, struct lpfc_nodelist *, - uint32_t, uint32_t); -void lpfc_hb_timeout_handler(struct lpfc_hba *); - -void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); -void lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); -int lpfc_ns_cmd(struct lpfc_vport *, int, uint8_t, uint32_t); -int lpfc_fdmi_cmd(struct lpfc_vport *, struct lpfc_nodelist *, int); -void lpfc_fdmi_tmo(unsigned long); -void lpfc_fdmi_timeout_handler(struct lpfc_vport *); -void lpfc_delayed_disc_tmo(unsigned long); -void lpfc_delayed_disc_timeout_handler(struct lpfc_vport *); - -int lpfc_config_port_prep(struct lpfc_hba *); -void lpfc_update_vport_wwn(struct lpfc_vport *vport); -int lpfc_config_port_post(struct lpfc_hba *); -int lpfc_hba_down_prep(struct lpfc_hba *); -int lpfc_hba_down_post(struct lpfc_hba *); -void lpfc_hba_init(struct lpfc_hba *, uint32_t *); -int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int); -void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int); -int lpfc_online(struct lpfc_hba *); -void lpfc_unblock_mgmt_io(struct lpfc_hba *); -void lpfc_offline_prep(struct lpfc_hba *); -void lpfc_offline(struct lpfc_hba *); -void lpfc_reset_hba(struct lpfc_hba *); - -int lpfc_sli_setup(struct lpfc_hba *); -int lpfc_sli_queue_setup(struct lpfc_hba *); - -void lpfc_handle_eratt(struct lpfc_hba *); -void lpfc_handle_latt(struct lpfc_hba *); -irqreturn_t lpfc_sli_intr_handler(int, void *); -irqreturn_t lpfc_sli_sp_intr_handler(int, void *); -irqreturn_t lpfc_sli_fp_intr_handler(int, void *); -irqreturn_t lpfc_sli4_intr_handler(int, void *); -irqreturn_t lpfc_sli4_sp_intr_handler(int, void *); -irqreturn_t lpfc_sli4_fp_intr_handler(int, void *); - -void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_sli4_swap_str(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); -void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *); -LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *); -void __lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbox_cmpl_put(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_mbox_cmd_check(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_mbox_dev_check(struct lpfc_hba *); -int lpfc_mbox_tmo_val(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_init_vfi(struct lpfcMboxq *, struct lpfc_vport *); -void lpfc_reg_vfi(struct lpfcMboxq *, struct lpfc_vport *, dma_addr_t); -void lpfc_init_vpi(struct lpfc_hba *, struct lpfcMboxq *, uint16_t); -void lpfc_unreg_vfi(struct lpfcMboxq *, struct lpfc_vport *); -void lpfc_reg_fcfi(struct lpfc_hba *, struct lpfcMboxq *); -void lpfc_unreg_fcfi(struct lpfcMboxq *, uint16_t); -void lpfc_resume_rpi(struct lpfcMboxq *, struct lpfc_nodelist *); -int lpfc_check_pending_fcoe_event(struct lpfc_hba *, uint8_t); -void lpfc_issue_init_vpi(struct lpfc_vport *); - -void lpfc_config_hbq(struct lpfc_hba *, uint32_t, struct lpfc_hbq_init *, - uint32_t , LPFC_MBOXQ_t *); -struct hbq_dmabuf *lpfc_els_hbq_alloc(struct lpfc_hba *); -void lpfc_els_hbq_free(struct lpfc_hba *, struct hbq_dmabuf *); -struct hbq_dmabuf *lpfc_sli4_rb_alloc(struct lpfc_hba *); -void lpfc_sli4_rb_free(struct lpfc_hba *, struct hbq_dmabuf *); -void lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *, struct fcf_record *, - uint16_t); -void lpfc_unregister_fcf(struct lpfc_hba *); -void lpfc_unregister_fcf_rescan(struct lpfc_hba *); -void lpfc_unregister_unused_fcf(struct lpfc_hba *); -int lpfc_sli4_redisc_fcf_table(struct lpfc_hba *); -void lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *); -void lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *); -uint16_t lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *); -void lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *, uint16_t); -int lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *, uint16_t); -void lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *, uint16_t); -int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *, uint16_t); -void lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *); - -int lpfc_mem_alloc(struct lpfc_hba *, int align); -void lpfc_mem_free(struct lpfc_hba *); -void lpfc_mem_free_all(struct lpfc_hba *); -void lpfc_stop_vport_timers(struct lpfc_vport *); - -void lpfc_poll_timeout(unsigned long ptr); -void lpfc_poll_start_timer(struct lpfc_hba *); -void lpfc_poll_eratt(unsigned long); -int -lpfc_sli_handle_fast_ring_event(struct lpfc_hba *, - struct lpfc_sli_ring *, uint32_t); - -struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *); -void lpfc_sli_release_iocbq(struct lpfc_hba *, struct lpfc_iocbq *); -uint16_t lpfc_sli_next_iotag(struct lpfc_hba *, struct lpfc_iocbq *); -void lpfc_sli_cancel_iocbs(struct lpfc_hba *, struct list_head *, uint32_t, - uint32_t); -void lpfc_sli_wake_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_selective_reset(struct lpfc_hba *); -void lpfc_reset_barrier(struct lpfc_hba *); -int lpfc_sli_brdready(struct lpfc_hba *, uint32_t); -int lpfc_sli_brdkill(struct lpfc_hba *); -int lpfc_sli_brdreset(struct lpfc_hba *); -int lpfc_sli_brdrestart(struct lpfc_hba *); -int lpfc_sli_hba_setup(struct lpfc_hba *); -int lpfc_sli_config_port(struct lpfc_hba *, int); -int lpfc_sli_host_down(struct lpfc_vport *); -int lpfc_sli_hba_down(struct lpfc_hba *); -int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); -int lpfc_sli_handle_mb_event(struct lpfc_hba *); -void lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *); -int lpfc_sli_check_eratt(struct lpfc_hba *); -void lpfc_sli_handle_slow_ring_event(struct lpfc_hba *, - struct lpfc_sli_ring *, uint32_t); -void lpfc_sli4_handle_received_buffer(struct lpfc_hba *, struct hbq_dmabuf *); -void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, - struct lpfc_iocbq *, uint32_t); -void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t); -void lpfc_sli_bemem_bcopy(void *, void *, uint32_t); -void lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *); -void lpfc_sli_hba_iocb_abort(struct lpfc_hba *); -void lpfc_sli_flush_fcp_rings(struct lpfc_hba *); -int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_dmabuf *); -struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *, - struct lpfc_sli_ring *, - dma_addr_t); - -uint32_t lpfc_sli_get_buffer_tag(struct lpfc_hba *); -struct lpfc_dmabuf * lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *, - struct lpfc_sli_ring *, uint32_t ); - -int lpfc_sli_hbq_count(void); -int lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *, uint32_t); -void lpfc_sli_hbqbuf_free_all(struct lpfc_hba *); -int lpfc_sli_hbq_size(void); -int lpfc_sli_issue_abort_iotag(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); -int lpfc_sli_sum_iocb(struct lpfc_vport *, uint16_t, uint64_t, lpfc_ctx_cmd); -int lpfc_sli_abort_iocb(struct lpfc_vport *, struct lpfc_sli_ring *, uint16_t, - uint64_t, lpfc_ctx_cmd); - -void lpfc_mbox_timeout(unsigned long); -void lpfc_mbox_timeout_handler(struct lpfc_hba *); - -struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_vport *, uint32_t); -struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_vport *, - struct lpfc_name *); - -int lpfc_sli_issue_mbox_wait(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t); - -int lpfc_sli_issue_iocb_wait(struct lpfc_hba *, uint32_t, - struct lpfc_iocbq *, struct lpfc_iocbq *, - uint32_t); -void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); - -void lpfc_sli_free_hbq(struct lpfc_hba *, struct hbq_dmabuf *); - -void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *); -void __lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); -void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t); - -void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *); -/* Function prototypes. */ -const char* lpfc_info(struct Scsi_Host *); -int lpfc_scan_finished(struct Scsi_Host *, unsigned long); - -int lpfc_init_api_table_setup(struct lpfc_hba *, uint8_t); -int lpfc_sli_api_table_setup(struct lpfc_hba *, uint8_t); -int lpfc_scsi_api_table_setup(struct lpfc_hba *, uint8_t); -int lpfc_mbox_api_table_setup(struct lpfc_hba *, uint8_t); -int lpfc_api_table_setup(struct lpfc_hba *, uint8_t); - -void lpfc_get_cfgparam(struct lpfc_hba *); -void lpfc_get_vport_cfgparam(struct lpfc_vport *); -int lpfc_alloc_sysfs_attr(struct lpfc_vport *); -void lpfc_free_sysfs_attr(struct lpfc_vport *); -extern struct device_attribute *lpfc_hba_attrs[]; -extern struct device_attribute *lpfc_vport_attrs[]; -extern struct scsi_host_template lpfc_template; -extern struct scsi_host_template lpfc_vport_template; -extern struct fc_function_template lpfc_transport_functions; -extern struct fc_function_template lpfc_vport_transport_functions; -extern int lpfc_sli_mode; -extern int lpfc_enable_npiv; -extern int lpfc_delay_discovery; - -int lpfc_vport_symbolic_node_name(struct lpfc_vport *, char *, size_t); -int lpfc_vport_symbolic_port_name(struct lpfc_vport *, char *, size_t); -void lpfc_terminate_rport_io(struct fc_rport *); -void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport); - -struct lpfc_vport *lpfc_create_port(struct lpfc_hba *, int, struct device *); -int lpfc_vport_disable(struct fc_vport *fc_vport, bool disable); -int lpfc_mbx_unreg_vpi(struct lpfc_vport *); -void destroy_port(struct lpfc_vport *); -int lpfc_get_instance(void); -void lpfc_host_attrib_init(struct Scsi_Host *); - -extern void lpfc_debugfs_initialize(struct lpfc_vport *); -extern void lpfc_debugfs_terminate(struct lpfc_vport *); -extern void lpfc_debugfs_disc_trc(struct lpfc_vport *, int, char *, uint32_t, - uint32_t, uint32_t); -extern void lpfc_debugfs_slow_ring_trc(struct lpfc_hba *, char *, uint32_t, - uint32_t, uint32_t); -extern struct lpfc_hbq_init *lpfc_hbq_defs[]; - -/* SLI4 if_type 2 externs. */ -int lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *); -int lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *); -int lpfc_sli4_get_allocated_extnts(struct lpfc_hba *, uint16_t, - uint16_t *, uint16_t *); -int lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *, uint16_t, - uint16_t *, uint16_t *); - -/* externs BlockGuard */ -extern char *_dump_buf_data; -extern unsigned long _dump_buf_data_order; -extern char *_dump_buf_dif; -extern unsigned long _dump_buf_dif_order; -extern spinlock_t _dump_buf_lock; -extern int _dump_buf_done; -extern spinlock_t pgcnt_lock; -extern unsigned int pgcnt; -extern unsigned int lpfc_prot_mask; -extern unsigned char lpfc_prot_guard; - -/* Interface exported by fabric iocb scheduler */ -void lpfc_fabric_abort_nport(struct lpfc_nodelist *); -void lpfc_fabric_abort_hba(struct lpfc_hba *); -void lpfc_fabric_block_timeout(unsigned long); -void lpfc_unblock_fabric_iocbs(struct lpfc_hba *); -void lpfc_rampdown_queue_depth(struct lpfc_hba *); -void lpfc_ramp_down_queue_handler(struct lpfc_hba *); -void lpfc_ramp_up_queue_handler(struct lpfc_hba *); -void lpfc_scsi_dev_block(struct lpfc_hba *); - -void -lpfc_send_els_failure_event(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); -struct lpfc_fast_path_event *lpfc_alloc_fast_evt(struct lpfc_hba *); -void lpfc_free_fast_evt(struct lpfc_hba *, struct lpfc_fast_path_event *); -void lpfc_create_static_vport(struct lpfc_hba *); -void lpfc_stop_hba_timers(struct lpfc_hba *); -void lpfc_stop_port(struct lpfc_hba *); -void __lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *); -void lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *); -void lpfc_parse_fcoe_conf(struct lpfc_hba *, uint8_t *, uint32_t); -int lpfc_parse_vpd(struct lpfc_hba *, uint8_t *, int); -void lpfc_start_fdiscs(struct lpfc_hba *phba); -struct lpfc_vport *lpfc_find_vport_by_vpid(struct lpfc_hba *, uint16_t); -struct lpfc_sglq *__lpfc_get_active_sglq(struct lpfc_hba *, uint16_t); -#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code) -#define HBA_EVENT_RSCN 5 -#define HBA_EVENT_LINK_UP 2 -#define HBA_EVENT_LINK_DOWN 3 - -/* functions to support SGIOv4/bsg interface */ -int lpfc_bsg_request(struct fc_bsg_job *); -int lpfc_bsg_timeout(struct fc_bsg_job *); -int lpfc_bsg_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); -void __lpfc_sli_ringtx_put(struct lpfc_hba *, struct lpfc_sli_ring *, - struct lpfc_iocbq *); -struct lpfc_iocbq *lpfc_sli_ringtx_get(struct lpfc_hba *, - struct lpfc_sli_ring *); -int __lpfc_sli_issue_iocb(struct lpfc_hba *, uint32_t, - struct lpfc_iocbq *, uint32_t); -uint32_t lpfc_drain_txq(struct lpfc_hba *); -void lpfc_clr_rrq_active(struct lpfc_hba *, uint16_t, struct lpfc_node_rrq *); -int lpfc_test_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *, uint16_t); -void lpfc_handle_rrq_active(struct lpfc_hba *); -int lpfc_send_rrq(struct lpfc_hba *, struct lpfc_node_rrq *); -int lpfc_set_rrq_active(struct lpfc_hba *, struct lpfc_nodelist *, - uint16_t, uint16_t, uint16_t); -uint16_t lpfc_sli4_xri_inrange(struct lpfc_hba *, uint16_t); -void lpfc_cleanup_wt_rrqs(struct lpfc_hba *); -void lpfc_cleanup_vports_rrqs(struct lpfc_vport *, struct lpfc_nodelist *); -struct lpfc_node_rrq *lpfc_get_active_rrq(struct lpfc_vport *, uint16_t, - uint32_t); -void lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *, enum nemb_type, - enum mbox_type, enum dma_type, enum sta_type, - struct lpfc_dmabuf *, uint32_t); -void lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *, MAILBOX_t *); -int lpfc_wr_object(struct lpfc_hba *, struct list_head *, uint32_t, uint32_t *); -/* functions to support SR-IOV */ -int lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *, int); -uint16_t lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *); -int lpfc_sli4_queue_create(struct lpfc_hba *); -void lpfc_sli4_queue_destroy(struct lpfc_hba *); -void lpfc_sli4_abts_err_handler(struct lpfc_hba *, struct lpfc_nodelist *, - struct sli4_wcqe_xri_aborted *); -int lpfc_hba_init_link_fc_topology(struct lpfc_hba *, uint32_t, uint32_t); -int lpfc_issue_reg_vfi(struct lpfc_vport *); -int lpfc_issue_unreg_vfi(struct lpfc_vport *); -int lpfc_selective_reset(struct lpfc_hba *); -int lpfc_sli4_read_config(struct lpfc_hba *phba); -int lpfc_scsi_buf_update(struct lpfc_hba *phba); -void lpfc_sli4_node_prep(struct lpfc_hba *phba); diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_ct.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_ct.c deleted file mode 100644 index 93e96b3c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_ct.c +++ /dev/null @@ -1,1910 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2010 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -/* - * Fibre Channel SCSI LAN Device Driver CT support: FC Generic Services FC-GS - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_version.h" -#include "lpfc_vport.h" -#include "lpfc_debugfs.h" - -/* FDMI Port Speed definitions */ -#define HBA_PORTSPEED_1GBIT 0x0001 /* 1 GBit/sec */ -#define HBA_PORTSPEED_2GBIT 0x0002 /* 2 GBit/sec */ -#define HBA_PORTSPEED_4GBIT 0x0008 /* 4 GBit/sec */ -#define HBA_PORTSPEED_10GBIT 0x0004 /* 10 GBit/sec */ -#define HBA_PORTSPEED_8GBIT 0x0010 /* 8 GBit/sec */ -#define HBA_PORTSPEED_16GBIT 0x0020 /* 16 GBit/sec */ -#define HBA_PORTSPEED_UNKNOWN 0x0800 /* Unknown */ - -#define FOURBYTES 4 - - -static char *lpfc_release_version = LPFC_DRIVER_VERSION; - -static void -lpfc_ct_ignore_hbq_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct lpfc_dmabuf *mp, uint32_t size) -{ - if (!mp) { - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "0146 Ignoring unsolicited CT No HBQ " - "status = x%x\n", - piocbq->iocb.ulpStatus); - } - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "0145 Ignoring unsolicted CT HBQ Size:%d " - "status = x%x\n", - size, piocbq->iocb.ulpStatus); -} - -static void -lpfc_ct_unsol_buffer(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct lpfc_dmabuf *mp, uint32_t size) -{ - lpfc_ct_ignore_hbq_buffer(phba, piocbq, mp, size); -} - -void -lpfc_ct_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocbq) -{ - struct lpfc_dmabuf *mp = NULL; - IOCB_t *icmd = &piocbq->iocb; - int i; - struct lpfc_iocbq *iocbq; - dma_addr_t paddr; - uint32_t size; - struct list_head head; - struct lpfc_dmabuf *bdeBuf; - - if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) - return; - - if (unlikely(icmd->ulpStatus == IOSTAT_NEED_BUFFER)) { - lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); - } else if ((icmd->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING)) { - /* Not enough posted buffers; Try posting more buffers */ - phba->fc_stat.NoRcvBuf++; - if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_post_buffer(phba, pring, 2); - return; - } - - /* If there are no BDEs associated with this IOCB, - * there is nothing to do. - */ - if (icmd->ulpBdeCount == 0) - return; - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); - list_for_each_entry(iocbq, &head, list) { - icmd = &iocbq->iocb; - if (icmd->ulpBdeCount == 0) - continue; - bdeBuf = iocbq->context2; - iocbq->context2 = NULL; - size = icmd->un.cont64[0].tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); - lpfc_in_buf_free(phba, bdeBuf); - if (icmd->ulpBdeCount == 2) { - bdeBuf = iocbq->context3; - iocbq->context3 = NULL; - size = icmd->unsli3.rcvsli3.bde2.tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, - size); - lpfc_in_buf_free(phba, bdeBuf); - } - } - list_del(&head); - } else { - INIT_LIST_HEAD(&head); - list_add_tail(&head, &piocbq->list); - list_for_each_entry(iocbq, &head, list) { - icmd = &iocbq->iocb; - if (icmd->ulpBdeCount == 0) - lpfc_ct_unsol_buffer(phba, iocbq, NULL, 0); - for (i = 0; i < icmd->ulpBdeCount; i++) { - paddr = getPaddr(icmd->un.cont64[i].addrHigh, - icmd->un.cont64[i].addrLow); - mp = lpfc_sli_ringpostbuf_get(phba, pring, - paddr); - size = icmd->un.cont64[i].tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, iocbq, mp, size); - lpfc_in_buf_free(phba, mp); - } - lpfc_post_buffer(phba, pring, i); - } - list_del(&head); - } -} - -/** - * lpfc_sli4_ct_abort_unsol_event - Default handle for sli4 unsol abort - * @phba: Pointer to HBA context object. - * @pring: Pointer to the driver internal I/O ring. - * @piocbq: Pointer to the IOCBQ. - * - * This function serves as the default handler for the sli4 unsolicited - * abort event. It shall be invoked when there is no application interface - * registered unsolicited abort handler. This handler does nothing but - * just simply releases the dma buffer used by the unsol abort event. - **/ -void -lpfc_sli4_ct_abort_unsol_event(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocbq) -{ - IOCB_t *icmd = &piocbq->iocb; - struct lpfc_dmabuf *bdeBuf; - uint32_t size; - - /* Forward abort event to any process registered to receive ct event */ - if (lpfc_bsg_ct_unsol_event(phba, pring, piocbq) == 0) - return; - - /* If there is no BDE associated with IOCB, there is nothing to do */ - if (icmd->ulpBdeCount == 0) - return; - bdeBuf = piocbq->context2; - piocbq->context2 = NULL; - size = icmd->un.cont64[0].tus.f.bdeSize; - lpfc_ct_unsol_buffer(phba, piocbq, bdeBuf, size); - lpfc_in_buf_free(phba, bdeBuf); -} - -static void -lpfc_free_ct_rsp(struct lpfc_hba *phba, struct lpfc_dmabuf *mlist) -{ - struct lpfc_dmabuf *mlast, *next_mlast; - - list_for_each_entry_safe(mlast, next_mlast, &mlist->list, list) { - lpfc_mbuf_free(phba, mlast->virt, mlast->phys); - list_del(&mlast->list); - kfree(mlast); - } - lpfc_mbuf_free(phba, mlist->virt, mlist->phys); - kfree(mlist); - return; -} - -static struct lpfc_dmabuf * -lpfc_alloc_ct_rsp(struct lpfc_hba *phba, int cmdcode, struct ulp_bde64 *bpl, - uint32_t size, int *entries) -{ - struct lpfc_dmabuf *mlist = NULL; - struct lpfc_dmabuf *mp; - int cnt, i = 0; - - /* We get chunks of FCELSSIZE */ - cnt = size > FCELSSIZE ? FCELSSIZE: size; - - while (size) { - /* Allocate buffer for rsp payload */ - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) { - if (mlist) - lpfc_free_ct_rsp(phba, mlist); - return NULL; - } - - INIT_LIST_HEAD(&mp->list); - - if (cmdcode == be16_to_cpu(SLI_CTNS_GID_FT) || - cmdcode == be16_to_cpu(SLI_CTNS_GFF_ID)) - mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); - else - mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys)); - - if (!mp->virt) { - kfree(mp); - if (mlist) - lpfc_free_ct_rsp(phba, mlist); - return NULL; - } - - /* Queue it to a linked list */ - if (!mlist) - mlist = mp; - else - list_add_tail(&mp->list, &mlist->list); - - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; - /* build buffer ptr list for IOCB */ - bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); - bpl->tus.f.bdeSize = (uint16_t) cnt; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - bpl++; - - i++; - size -= cnt; - } - - *entries = i; - return mlist; -} - -int -lpfc_ct_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *ctiocb) -{ - struct lpfc_dmabuf *buf_ptr; - - if (ctiocb->context_un.ndlp) { - lpfc_nlp_put(ctiocb->context_un.ndlp); - ctiocb->context_un.ndlp = NULL; - } - if (ctiocb->context1) { - buf_ptr = (struct lpfc_dmabuf *) ctiocb->context1; - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - ctiocb->context1 = NULL; - } - if (ctiocb->context2) { - lpfc_free_ct_rsp(phba, (struct lpfc_dmabuf *) ctiocb->context2); - ctiocb->context2 = NULL; - } - - if (ctiocb->context3) { - buf_ptr = (struct lpfc_dmabuf *) ctiocb->context3; - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - ctiocb->context1 = NULL; - } - lpfc_sli_release_iocbq(phba, ctiocb); - return 0; -} - -static int -lpfc_gen_req(struct lpfc_vport *vport, struct lpfc_dmabuf *bmp, - struct lpfc_dmabuf *inp, struct lpfc_dmabuf *outp, - void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *), - struct lpfc_nodelist *ndlp, uint32_t usr_flg, uint32_t num_entry, - uint32_t tmo, uint8_t retry) -{ - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; - struct lpfc_iocbq *geniocb; - int rc; - - /* Allocate buffer for command iocb */ - geniocb = lpfc_sli_get_iocbq(phba); - - if (geniocb == NULL) - return 1; - - icmd = &geniocb->iocb; - icmd->un.genreq64.bdl.ulpIoTag32 = 0; - icmd->un.genreq64.bdl.addrHigh = putPaddrHigh(bmp->phys); - icmd->un.genreq64.bdl.addrLow = putPaddrLow(bmp->phys); - icmd->un.genreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.genreq64.bdl.bdeSize = (num_entry * sizeof (struct ulp_bde64)); - - if (usr_flg) - geniocb->context3 = NULL; - else - geniocb->context3 = (uint8_t *) bmp; - - /* Save for completion so we can release these resources */ - geniocb->context1 = (uint8_t *) inp; - geniocb->context2 = (uint8_t *) outp; - geniocb->context_un.ndlp = lpfc_nlp_get(ndlp); - - /* Fill in payload, bp points to frame payload */ - icmd->ulpCommand = CMD_GEN_REQUEST64_CR; - - /* Fill in rest of iocb */ - icmd->un.genreq64.w5.hcsw.Fctl = (SI | LA); - icmd->un.genreq64.w5.hcsw.Dfctl = 0; - icmd->un.genreq64.w5.hcsw.Rctl = FC_RCTL_DD_UNSOL_CTL; - icmd->un.genreq64.w5.hcsw.Type = FC_TYPE_CT; - - if (!tmo) { - /* FC spec states we need 3 * ratov for CT requests */ - tmo = (3 * phba->fc_ratov); - } - icmd->ulpTimeout = tmo; - icmd->ulpBdeCount = 1; - icmd->ulpLe = 1; - icmd->ulpClass = CLASS3; - icmd->ulpContext = ndlp->nlp_rpi; - if (phba->sli_rev == LPFC_SLI_REV4) - icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { - /* For GEN_REQUEST64_CR, use the RPI */ - icmd->ulpCt_h = 0; - icmd->ulpCt_l = 0; - } - - /* Issue GEN REQ IOCB for NPORT */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0119 Issue GEN REQ IOCB to NPORT x%x " - "Data: x%x x%x\n", - ndlp->nlp_DID, icmd->ulpIoTag, - vport->port_state); - geniocb->iocb_cmpl = cmpl; - geniocb->drvrTimeout = icmd->ulpTimeout + LPFC_DRVR_TIMEOUT; - geniocb->vport = vport; - geniocb->retry = retry; - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, geniocb, 0); - - if (rc == IOCB_ERROR) { - lpfc_sli_release_iocbq(phba, geniocb); - return 1; - } - - return 0; -} - -static int -lpfc_ct_cmd(struct lpfc_vport *vport, struct lpfc_dmabuf *inmp, - struct lpfc_dmabuf *bmp, struct lpfc_nodelist *ndlp, - void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *), - uint32_t rsp_size, uint8_t retry) -{ - struct lpfc_hba *phba = vport->phba; - struct ulp_bde64 *bpl = (struct ulp_bde64 *) bmp->virt; - struct lpfc_dmabuf *outmp; - int cnt = 0, status; - int cmdcode = ((struct lpfc_sli_ct_request *) inmp->virt)-> - CommandResponse.bits.CmdRsp; - - bpl++; /* Skip past ct request */ - - /* Put buffer(s) for ct rsp in bpl */ - outmp = lpfc_alloc_ct_rsp(phba, cmdcode, bpl, rsp_size, &cnt); - if (!outmp) - return -ENOMEM; - /* - * Form the CT IOCB. The total number of BDEs in this IOCB - * is the single command plus response count from - * lpfc_alloc_ct_rsp. - */ - cnt += 1; - status = lpfc_gen_req(vport, bmp, inmp, outmp, cmpl, ndlp, 0, - cnt, 0, retry); - if (status) { - lpfc_free_ct_rsp(phba, outmp); - return -ENOMEM; - } - return 0; -} - -struct lpfc_vport * -lpfc_find_vport_by_did(struct lpfc_hba *phba, uint32_t did) { - struct lpfc_vport *vport_curr; - unsigned long flags; - - spin_lock_irqsave(&phba->hbalock, flags); - list_for_each_entry(vport_curr, &phba->port_list, listentry) { - if ((vport_curr->fc_myDID) && (vport_curr->fc_myDID == did)) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return vport_curr; - } - } - spin_unlock_irqrestore(&phba->hbalock, flags); - return NULL; -} - -static int -lpfc_ns_rsp(struct lpfc_vport *vport, struct lpfc_dmabuf *mp, uint32_t Size) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_sli_ct_request *Response = - (struct lpfc_sli_ct_request *) mp->virt; - struct lpfc_nodelist *ndlp = NULL; - struct lpfc_dmabuf *mlast, *next_mp; - uint32_t *ctptr = (uint32_t *) & Response->un.gid.PortType; - uint32_t Did, CTentry; - int Cnt; - struct list_head head; - - lpfc_set_disctmo(vport); - vport->num_disc_nodes = 0; - vport->fc_ns_retry = 0; - - - list_add_tail(&head, &mp->list); - list_for_each_entry_safe(mp, next_mp, &head, list) { - mlast = mp; - - Cnt = Size > FCELSSIZE ? FCELSSIZE : Size; - - Size -= Cnt; - - if (!ctptr) { - ctptr = (uint32_t *) mlast->virt; - } else - Cnt -= 16; /* subtract length of CT header */ - - /* Loop through entire NameServer list of DIDs */ - while (Cnt >= sizeof (uint32_t)) { - /* Get next DID from NameServer List */ - CTentry = *ctptr++; - Did = ((be32_to_cpu(CTentry)) & Mask_DID); - - ndlp = NULL; - - /* - * Check for rscn processing or not - * To conserve rpi's, filter out addresses for other - * vports on the same physical HBAs. - */ - if ((Did != vport->fc_myDID) && - ((lpfc_find_vport_by_did(phba, Did) == NULL) || - vport->cfg_peer_port_login)) { - if ((vport->port_type != LPFC_NPIV_PORT) || - (!(vport->ct_flags & FC_CT_RFF_ID)) || - (!vport->cfg_restrict_login)) { - ndlp = lpfc_setup_disc_node(vport, Did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - lpfc_debugfs_disc_trc(vport, - LPFC_DISC_TRC_CT, - "Parse GID_FTrsp: " - "did:x%x flg:x%x x%x", - Did, ndlp->nlp_flag, - vport->fc_flag); - - lpfc_printf_vlog(vport, - KERN_INFO, - LOG_DISCOVERY, - "0238 Process " - "x%x NameServer Rsp" - "Data: x%x x%x x%x\n", - Did, ndlp->nlp_flag, - vport->fc_flag, - vport->fc_rscn_id_cnt); - } else { - lpfc_debugfs_disc_trc(vport, - LPFC_DISC_TRC_CT, - "Skip1 GID_FTrsp: " - "did:x%x flg:x%x cnt:%d", - Did, vport->fc_flag, - vport->fc_rscn_id_cnt); - - lpfc_printf_vlog(vport, - KERN_INFO, - LOG_DISCOVERY, - "0239 Skip x%x " - "NameServer Rsp Data: " - "x%x x%x\n", - Did, vport->fc_flag, - vport->fc_rscn_id_cnt); - } - - } else { - if (!(vport->fc_flag & FC_RSCN_MODE) || - (lpfc_rscn_payload_check(vport, Did))) { - lpfc_debugfs_disc_trc(vport, - LPFC_DISC_TRC_CT, - "Query GID_FTrsp: " - "did:x%x flg:x%x cnt:%d", - Did, vport->fc_flag, - vport->fc_rscn_id_cnt); - - /* This NPortID was previously - * a FCP target, * Don't even - * bother to send GFF_ID. - */ - ndlp = lpfc_findnode_did(vport, - Did); - if (ndlp && - NLP_CHK_NODE_ACT(ndlp) - && (ndlp->nlp_type & - NLP_FCP_TARGET)) - lpfc_setup_disc_node - (vport, Did); - else if (lpfc_ns_cmd(vport, - SLI_CTNS_GFF_ID, - 0, Did) == 0) - vport->num_disc_nodes++; - else - lpfc_setup_disc_node - (vport, Did); - } - else { - lpfc_debugfs_disc_trc(vport, - LPFC_DISC_TRC_CT, - "Skip2 GID_FTrsp: " - "did:x%x flg:x%x cnt:%d", - Did, vport->fc_flag, - vport->fc_rscn_id_cnt); - - lpfc_printf_vlog(vport, - KERN_INFO, - LOG_DISCOVERY, - "0245 Skip x%x " - "NameServer Rsp Data: " - "x%x x%x\n", - Did, vport->fc_flag, - vport->fc_rscn_id_cnt); - } - } - } - if (CTentry & (be32_to_cpu(SLI_CT_LAST_ENTRY))) - goto nsout1; - Cnt -= sizeof (uint32_t); - } - ctptr = NULL; - - } - -nsout1: - list_del(&head); - return 0; -} - -static void -lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp; - struct lpfc_dmabuf *bmp; - struct lpfc_dmabuf *outp; - struct lpfc_sli_ct_request *CTrsp; - struct lpfc_nodelist *ndlp; - int rc; - - /* First save ndlp, before we overwrite it */ - ndlp = cmdiocb->context_un.ndlp; - - /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; - - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - bmp = (struct lpfc_dmabuf *) cmdiocb->context3; - irsp = &rspiocb->iocb; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "GID_FT cmpl: status:x%x/x%x rtry:%d", - irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_ns_retry); - - /* Don't bother processing response if vport is being torn down. */ - if (vport->load_flag & FC_UNLOADING) { - if (vport->fc_flag & FC_RSCN_MODE) - lpfc_els_flush_rscn(vport); - goto out; - } - - if (lpfc_els_chk_latt(vport)) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0216 Link event during NS query\n"); - if (vport->fc_flag & FC_RSCN_MODE) - lpfc_els_flush_rscn(vport); - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - goto out; - } - if (lpfc_error_lost_link(irsp)) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0226 NS query failed due to link event\n"); - if (vport->fc_flag & FC_RSCN_MODE) - lpfc_els_flush_rscn(vport); - goto out; - } - if (irsp->ulpStatus) { - /* Check for retry */ - if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { - if (irsp->ulpStatus != IOSTAT_LOCAL_REJECT || - irsp->un.ulpWord[4] != IOERR_NO_RESOURCES) - vport->fc_ns_retry++; - - /* CT command is being retried */ - rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, - vport->fc_ns_retry, 0); - if (rc == 0) - goto out; - } - if (vport->fc_flag & FC_RSCN_MODE) - lpfc_els_flush_rscn(vport); - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0257 GID_FT Query error: 0x%x 0x%x\n", - irsp->ulpStatus, vport->fc_ns_retry); - } else { - /* Good status, continue checking */ - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0208 NameServer Rsp Data: x%x\n", - vport->fc_flag); - lpfc_ns_rsp(vport, outp, - (uint32_t) (irsp->un.genreq64.bdl.bdeSize)); - } else if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { - /* NameServer Rsp Error */ - if ((CTrsp->ReasonCode == SLI_CT_UNABLE_TO_PERFORM_REQ) - && (CTrsp->Explanation == SLI_CT_NO_FC4_TYPES)) { - lpfc_printf_vlog(vport, KERN_INFO, - LOG_DISCOVERY, - "0269 No NameServer Entries " - "Data: x%x x%x x%x x%x\n", - CTrsp->CommandResponse.bits.CmdRsp, - (uint32_t) CTrsp->ReasonCode, - (uint32_t) CTrsp->Explanation, - vport->fc_flag); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "GID_FT no entry cmd:x%x rsn:x%x exp:x%x", - (uint32_t)CTrsp->CommandResponse.bits.CmdRsp, - (uint32_t) CTrsp->ReasonCode, - (uint32_t) CTrsp->Explanation); - } else { - lpfc_printf_vlog(vport, KERN_INFO, - LOG_DISCOVERY, - "0240 NameServer Rsp Error " - "Data: x%x x%x x%x x%x\n", - CTrsp->CommandResponse.bits.CmdRsp, - (uint32_t) CTrsp->ReasonCode, - (uint32_t) CTrsp->Explanation, - vport->fc_flag); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "GID_FT rsp err1 cmd:x%x rsn:x%x exp:x%x", - (uint32_t)CTrsp->CommandResponse.bits.CmdRsp, - (uint32_t) CTrsp->ReasonCode, - (uint32_t) CTrsp->Explanation); - } - - - } else { - /* NameServer Rsp Error */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0241 NameServer Rsp Error " - "Data: x%x x%x x%x x%x\n", - CTrsp->CommandResponse.bits.CmdRsp, - (uint32_t) CTrsp->ReasonCode, - (uint32_t) CTrsp->Explanation, - vport->fc_flag); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "GID_FT rsp err2 cmd:x%x rsn:x%x exp:x%x", - (uint32_t)CTrsp->CommandResponse.bits.CmdRsp, - (uint32_t) CTrsp->ReasonCode, - (uint32_t) CTrsp->Explanation); - } - } - /* Link up / RSCN discovery */ - if (vport->num_disc_nodes == 0) { - /* - * The driver has cycled through all Nports in the RSCN payload. - * Complete the handling by cleaning up and marking the - * current driver state. - */ - if (vport->port_state >= LPFC_DISC_AUTH) { - if (vport->fc_flag & FC_RSCN_MODE) { - lpfc_els_flush_rscn(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ - spin_unlock_irq(shost->host_lock); - } - else - lpfc_els_flush_rscn(vport); - } - - lpfc_disc_start(vport); - } -out: - cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */ - lpfc_ct_free_iocb(phba, cmdiocb); - return; -} - -static void -lpfc_cmpl_ct_cmd_gff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_dmabuf *inp = (struct lpfc_dmabuf *) cmdiocb->context1; - struct lpfc_dmabuf *outp = (struct lpfc_dmabuf *) cmdiocb->context2; - struct lpfc_sli_ct_request *CTrsp; - int did, rc, retry; - uint8_t fbits; - struct lpfc_nodelist *ndlp; - - did = ((struct lpfc_sli_ct_request *) inp->virt)->un.gff.PortId; - did = be32_to_cpu(did); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "GFF_ID cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], did); - - if (irsp->ulpStatus == IOSTAT_SUCCESS) { - /* Good status, continue checking */ - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - fbits = CTrsp->un.gff_acc.fbits[FCP_TYPE_FEATURE_OFFSET]; - - if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) { - if ((fbits & FC4_FEATURE_INIT) && - !(fbits & FC4_FEATURE_TARGET)) { - lpfc_printf_vlog(vport, KERN_INFO, - LOG_DISCOVERY, - "0270 Skip x%x GFF " - "NameServer Rsp Data: (init) " - "x%x x%x\n", did, fbits, - vport->fc_rscn_id_cnt); - goto out; - } - } - } - else { - /* Check for retry */ - if (cmdiocb->retry < LPFC_MAX_NS_RETRY) { - retry = 1; - if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { - switch (irsp->un.ulpWord[4]) { - case IOERR_NO_RESOURCES: - /* We don't increment the retry - * count for this case. - */ - break; - case IOERR_LINK_DOWN: - case IOERR_SLI_ABORTED: - case IOERR_SLI_DOWN: - retry = 0; - break; - default: - cmdiocb->retry++; - } - } - else - cmdiocb->retry++; - - if (retry) { - /* CT command is being retried */ - rc = lpfc_ns_cmd(vport, SLI_CTNS_GFF_ID, - cmdiocb->retry, did); - if (rc == 0) { - /* success */ - lpfc_ct_free_iocb(phba, cmdiocb); - return; - } - } - } - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0267 NameServer GFF Rsp " - "x%x Error (%d %d) Data: x%x x%x\n", - did, irsp->ulpStatus, irsp->un.ulpWord[4], - vport->fc_flag, vport->fc_rscn_id_cnt); - } - - /* This is a target port, unregistered port, or the GFF_ID failed */ - ndlp = lpfc_setup_disc_node(vport, did); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0242 Process x%x GFF " - "NameServer Rsp Data: x%x x%x x%x\n", - did, ndlp->nlp_flag, vport->fc_flag, - vport->fc_rscn_id_cnt); - } else { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0243 Skip x%x GFF " - "NameServer Rsp Data: x%x x%x\n", did, - vport->fc_flag, vport->fc_rscn_id_cnt); - } -out: - /* Link up / RSCN discovery */ - if (vport->num_disc_nodes) - vport->num_disc_nodes--; - if (vport->num_disc_nodes == 0) { - /* - * The driver has cycled through all Nports in the RSCN payload. - * Complete the handling by cleaning up and marking the - * current driver state. - */ - if (vport->port_state >= LPFC_DISC_AUTH) { - if (vport->fc_flag & FC_RSCN_MODE) { - lpfc_els_flush_rscn(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_MODE; /* RSCN still */ - spin_unlock_irq(shost->host_lock); - } - else - lpfc_els_flush_rscn(vport); - } - lpfc_disc_start(vport); - } - lpfc_ct_free_iocb(phba, cmdiocb); - return; -} - - -static void -lpfc_cmpl_ct(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct lpfc_dmabuf *inp; - struct lpfc_dmabuf *outp; - IOCB_t *irsp; - struct lpfc_sli_ct_request *CTrsp; - struct lpfc_nodelist *ndlp; - int cmdcode, rc; - uint8_t retry; - uint32_t latt; - - /* First save ndlp, before we overwrite it */ - ndlp = cmdiocb->context_un.ndlp; - - /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; - - inp = (struct lpfc_dmabuf *) cmdiocb->context1; - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - irsp = &rspiocb->iocb; - - cmdcode = be16_to_cpu(((struct lpfc_sli_ct_request *) inp->virt)-> - CommandResponse.bits.CmdRsp); - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - - latt = lpfc_els_chk_latt(vport); - - /* RFT request completes status CmdRsp */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0209 CT Request completes, latt %d, " - "ulpStatus x%x CmdRsp x%x, Context x%x, Tag x%x\n", - latt, irsp->ulpStatus, - CTrsp->CommandResponse.bits.CmdRsp, - cmdiocb->iocb.ulpContext, cmdiocb->iocb.ulpIoTag); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "CT cmd cmpl: status:x%x/x%x cmd:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], cmdcode); - - if (irsp->ulpStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0268 NS cmd %x Error (%d %d)\n", - cmdcode, irsp->ulpStatus, irsp->un.ulpWord[4]); - - if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - ((irsp->un.ulpWord[4] == IOERR_SLI_DOWN) || - (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED))) - goto out; - - retry = cmdiocb->retry; - if (retry >= LPFC_MAX_NS_RETRY) - goto out; - - retry++; - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0250 Retrying NS cmd %x\n", cmdcode); - rc = lpfc_ns_cmd(vport, cmdcode, retry, 0); - if (rc == 0) - goto out; - } - -out: - cmdiocb->context_un.ndlp = ndlp; /* Now restore ndlp for free */ - lpfc_ct_free_iocb(phba, cmdiocb); - return; -} - -static void -lpfc_cmpl_ct_cmd_rft_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_vport *vport = cmdiocb->vport; - - if (irsp->ulpStatus == IOSTAT_SUCCESS) { - struct lpfc_dmabuf *outp; - struct lpfc_sli_ct_request *CTrsp; - - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) - vport->ct_flags |= FC_CT_RFT_ID; - } - lpfc_cmpl_ct(phba, cmdiocb, rspiocb); - return; -} - -static void -lpfc_cmpl_ct_cmd_rnn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_vport *vport = cmdiocb->vport; - - if (irsp->ulpStatus == IOSTAT_SUCCESS) { - struct lpfc_dmabuf *outp; - struct lpfc_sli_ct_request *CTrsp; - - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) - vport->ct_flags |= FC_CT_RNN_ID; - } - lpfc_cmpl_ct(phba, cmdiocb, rspiocb); - return; -} - -static void -lpfc_cmpl_ct_cmd_rspn_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_vport *vport = cmdiocb->vport; - - if (irsp->ulpStatus == IOSTAT_SUCCESS) { - struct lpfc_dmabuf *outp; - struct lpfc_sli_ct_request *CTrsp; - - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) - vport->ct_flags |= FC_CT_RSPN_ID; - } - lpfc_cmpl_ct(phba, cmdiocb, rspiocb); - return; -} - -static void -lpfc_cmpl_ct_cmd_rsnn_nn(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_vport *vport = cmdiocb->vport; - - if (irsp->ulpStatus == IOSTAT_SUCCESS) { - struct lpfc_dmabuf *outp; - struct lpfc_sli_ct_request *CTrsp; - - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) - vport->ct_flags |= FC_CT_RSNN_NN; - } - lpfc_cmpl_ct(phba, cmdiocb, rspiocb); - return; -} - -static void -lpfc_cmpl_ct_cmd_da_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - - /* even if it fails we will act as though it succeeded. */ - vport->ct_flags = 0; - lpfc_cmpl_ct(phba, cmdiocb, rspiocb); - return; -} - -static void -lpfc_cmpl_ct_cmd_rff_id(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_vport *vport = cmdiocb->vport; - - if (irsp->ulpStatus == IOSTAT_SUCCESS) { - struct lpfc_dmabuf *outp; - struct lpfc_sli_ct_request *CTrsp; - - outp = (struct lpfc_dmabuf *) cmdiocb->context2; - CTrsp = (struct lpfc_sli_ct_request *) outp->virt; - if (CTrsp->CommandResponse.bits.CmdRsp == - be16_to_cpu(SLI_CT_RESPONSE_FS_ACC)) - vport->ct_flags |= FC_CT_RFF_ID; - } - lpfc_cmpl_ct(phba, cmdiocb, rspiocb); - return; -} - -int -lpfc_vport_symbolic_port_name(struct lpfc_vport *vport, char *symbol, - size_t size) -{ - int n; - uint8_t *wwn = vport->phba->wwpn; - - n = snprintf(symbol, size, - "Emulex PPN-%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", - wwn[0], wwn[1], wwn[2], wwn[3], - wwn[4], wwn[5], wwn[6], wwn[7]); - - if (vport->port_type == LPFC_PHYSICAL_PORT) - return n; - - if (n < size) - n += snprintf(symbol + n, size - n, " VPort-%d", vport->vpi); - - if (n < size && - strlen(vport->fc_vport->symbolic_name)) - n += snprintf(symbol + n, size - n, " VName-%s", - vport->fc_vport->symbolic_name); - return n; -} - -int -lpfc_vport_symbolic_node_name(struct lpfc_vport *vport, char *symbol, - size_t size) -{ - char fwrev[FW_REV_STR_SIZE]; - int n; - - lpfc_decode_firmware_rev(vport->phba, fwrev, 0); - - n = snprintf(symbol, size, "Emulex %s FV%s DV%s", - vport->phba->ModelName, fwrev, lpfc_release_version); - return n; -} - -/* - * lpfc_ns_cmd - * Description: - * Issue Cmd to NameServer - * SLI_CTNS_GID_FT - * LI_CTNS_RFT_ID - */ -int -lpfc_ns_cmd(struct lpfc_vport *vport, int cmdcode, - uint8_t retry, uint32_t context) -{ - struct lpfc_nodelist * ndlp; - struct lpfc_hba *phba = vport->phba; - struct lpfc_dmabuf *mp, *bmp; - struct lpfc_sli_ct_request *CtReq; - struct ulp_bde64 *bpl; - void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *) = NULL; - uint32_t rsp_size = 1024; - size_t size; - int rc = 0; - - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) - || ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) { - rc=1; - goto ns_cmd_exit; - } - - /* fill in BDEs for command */ - /* Allocate buffer for command payload */ - mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) { - rc=2; - goto ns_cmd_exit; - } - - INIT_LIST_HEAD(&mp->list); - mp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(mp->phys)); - if (!mp->virt) { - rc=3; - goto ns_cmd_free_mp; - } - - /* Allocate buffer for Buffer ptr list */ - bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) { - rc=4; - goto ns_cmd_free_mpvirt; - } - - INIT_LIST_HEAD(&bmp->list); - bmp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &(bmp->phys)); - if (!bmp->virt) { - rc=5; - goto ns_cmd_free_bmp; - } - - /* NameServer Req */ - lpfc_printf_vlog(vport, KERN_INFO ,LOG_DISCOVERY, - "0236 NameServer Req Data: x%x x%x x%x\n", - cmdcode, vport->fc_flag, vport->fc_rscn_id_cnt); - - bpl = (struct ulp_bde64 *) bmp->virt; - memset(bpl, 0, sizeof(struct ulp_bde64)); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); - bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); - bpl->tus.f.bdeFlags = 0; - if (cmdcode == SLI_CTNS_GID_FT) - bpl->tus.f.bdeSize = GID_REQUEST_SZ; - else if (cmdcode == SLI_CTNS_GFF_ID) - bpl->tus.f.bdeSize = GFF_REQUEST_SZ; - else if (cmdcode == SLI_CTNS_RFT_ID) - bpl->tus.f.bdeSize = RFT_REQUEST_SZ; - else if (cmdcode == SLI_CTNS_RNN_ID) - bpl->tus.f.bdeSize = RNN_REQUEST_SZ; - else if (cmdcode == SLI_CTNS_RSPN_ID) - bpl->tus.f.bdeSize = RSPN_REQUEST_SZ; - else if (cmdcode == SLI_CTNS_RSNN_NN) - bpl->tus.f.bdeSize = RSNN_REQUEST_SZ; - else if (cmdcode == SLI_CTNS_DA_ID) - bpl->tus.f.bdeSize = DA_ID_REQUEST_SZ; - else if (cmdcode == SLI_CTNS_RFF_ID) - bpl->tus.f.bdeSize = RFF_REQUEST_SZ; - else - bpl->tus.f.bdeSize = 0; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - - CtReq = (struct lpfc_sli_ct_request *) mp->virt; - memset(CtReq, 0, sizeof (struct lpfc_sli_ct_request)); - CtReq->RevisionId.bits.Revision = SLI_CT_REVISION; - CtReq->RevisionId.bits.InId = 0; - CtReq->FsType = SLI_CT_DIRECTORY_SERVICE; - CtReq->FsSubType = SLI_CT_DIRECTORY_NAME_SERVER; - CtReq->CommandResponse.bits.Size = 0; - switch (cmdcode) { - case SLI_CTNS_GID_FT: - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_GID_FT); - CtReq->un.gid.Fc4Type = SLI_CTPT_FCP; - if (vport->port_state < LPFC_NS_QRY) - vport->port_state = LPFC_NS_QRY; - lpfc_set_disctmo(vport); - cmpl = lpfc_cmpl_ct_cmd_gid_ft; - rsp_size = FC_MAX_NS_RSP; - break; - - case SLI_CTNS_GFF_ID: - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_GFF_ID); - CtReq->un.gff.PortId = cpu_to_be32(context); - cmpl = lpfc_cmpl_ct_cmd_gff_id; - break; - - case SLI_CTNS_RFT_ID: - vport->ct_flags &= ~FC_CT_RFT_ID; - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RFT_ID); - CtReq->un.rft.PortId = cpu_to_be32(vport->fc_myDID); - CtReq->un.rft.fcpReg = 1; - cmpl = lpfc_cmpl_ct_cmd_rft_id; - break; - - case SLI_CTNS_RNN_ID: - vport->ct_flags &= ~FC_CT_RNN_ID; - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RNN_ID); - CtReq->un.rnn.PortId = cpu_to_be32(vport->fc_myDID); - memcpy(CtReq->un.rnn.wwnn, &vport->fc_nodename, - sizeof (struct lpfc_name)); - cmpl = lpfc_cmpl_ct_cmd_rnn_id; - break; - - case SLI_CTNS_RSPN_ID: - vport->ct_flags &= ~FC_CT_RSPN_ID; - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RSPN_ID); - CtReq->un.rspn.PortId = cpu_to_be32(vport->fc_myDID); - size = sizeof(CtReq->un.rspn.symbname); - CtReq->un.rspn.len = - lpfc_vport_symbolic_port_name(vport, - CtReq->un.rspn.symbname, size); - cmpl = lpfc_cmpl_ct_cmd_rspn_id; - break; - case SLI_CTNS_RSNN_NN: - vport->ct_flags &= ~FC_CT_RSNN_NN; - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RSNN_NN); - memcpy(CtReq->un.rsnn.wwnn, &vport->fc_nodename, - sizeof (struct lpfc_name)); - size = sizeof(CtReq->un.rsnn.symbname); - CtReq->un.rsnn.len = - lpfc_vport_symbolic_node_name(vport, - CtReq->un.rsnn.symbname, size); - cmpl = lpfc_cmpl_ct_cmd_rsnn_nn; - break; - case SLI_CTNS_DA_ID: - /* Implement DA_ID Nameserver request */ - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_DA_ID); - CtReq->un.da_id.port_id = cpu_to_be32(vport->fc_myDID); - cmpl = lpfc_cmpl_ct_cmd_da_id; - break; - case SLI_CTNS_RFF_ID: - vport->ct_flags &= ~FC_CT_RFF_ID; - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_CTNS_RFF_ID); - CtReq->un.rff.PortId = cpu_to_be32(vport->fc_myDID); - CtReq->un.rff.fbits = FC4_FEATURE_INIT; - CtReq->un.rff.type_code = FC_TYPE_FCP; - cmpl = lpfc_cmpl_ct_cmd_rff_id; - break; - } - /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count - * to hold ndlp reference for the corresponding callback function. - */ - if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, rsp_size, retry)) { - /* On success, The cmpl function will free the buffers */ - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "Issue CT cmd: cmd:x%x did:x%x", - cmdcode, ndlp->nlp_DID, 0); - return 0; - } - rc=6; - - /* Decrement ndlp reference count to release ndlp reference held - * for the failed command's callback function. - */ - lpfc_nlp_put(ndlp); - - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); -ns_cmd_free_bmp: - kfree(bmp); -ns_cmd_free_mpvirt: - lpfc_mbuf_free(phba, mp->virt, mp->phys); -ns_cmd_free_mp: - kfree(mp); -ns_cmd_exit: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0266 Issue NameServer Req x%x err %d Data: x%x x%x\n", - cmdcode, rc, vport->fc_flag, vport->fc_rscn_id_cnt); - return 1; -} - -static void -lpfc_cmpl_ct_cmd_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq * rspiocb) -{ - struct lpfc_dmabuf *inp = cmdiocb->context1; - struct lpfc_dmabuf *outp = cmdiocb->context2; - struct lpfc_sli_ct_request *CTrsp = outp->virt; - struct lpfc_sli_ct_request *CTcmd = inp->virt; - struct lpfc_nodelist *ndlp; - uint16_t fdmi_cmd = CTcmd->CommandResponse.bits.CmdRsp; - uint16_t fdmi_rsp = CTrsp->CommandResponse.bits.CmdRsp; - struct lpfc_vport *vport = cmdiocb->vport; - IOCB_t *irsp = &rspiocb->iocb; - uint32_t latt; - - latt = lpfc_els_chk_latt(vport); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_CT, - "FDMI cmpl: status:x%x/x%x latt:%d", - irsp->ulpStatus, irsp->un.ulpWord[4], latt); - - if (latt || irsp->ulpStatus) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0229 FDMI cmd %04x failed, latt = %d " - "ulpStatus: x%x, rid x%x\n", - be16_to_cpu(fdmi_cmd), latt, irsp->ulpStatus, - irsp->un.ulpWord[4]); - lpfc_ct_free_iocb(phba, cmdiocb); - return; - } - - ndlp = lpfc_findnode_did(vport, FDMI_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - goto fail_out; - - if (fdmi_rsp == be16_to_cpu(SLI_CT_RESPONSE_FS_RJT)) { - /* FDMI rsp failed */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0220 FDMI rsp failed Data: x%x\n", - be16_to_cpu(fdmi_cmd)); - } - - switch (be16_to_cpu(fdmi_cmd)) { - case SLI_MGMT_RHBA: - lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RPA); - break; - - case SLI_MGMT_RPA: - break; - - case SLI_MGMT_DHBA: - lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DPRT); - break; - - case SLI_MGMT_DPRT: - lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_RHBA); - break; - } - -fail_out: - lpfc_ct_free_iocb(phba, cmdiocb); - return; -} - -int -lpfc_fdmi_cmd(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int cmdcode) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_dmabuf *mp, *bmp; - struct lpfc_sli_ct_request *CtReq; - struct ulp_bde64 *bpl; - uint32_t size; - REG_HBA *rh; - PORT_ENTRY *pe; - REG_PORT_ATTRIBUTE *pab; - ATTRIBUTE_BLOCK *ab; - ATTRIBUTE_ENTRY *ae; - void (*cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); - - - /* fill in BDEs for command */ - /* Allocate buffer for command payload */ - mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) - goto fdmi_cmd_exit; - - mp->virt = lpfc_mbuf_alloc(phba, 0, &(mp->phys)); - if (!mp->virt) - goto fdmi_cmd_free_mp; - - /* Allocate buffer for Buffer ptr list */ - bmp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (!bmp) - goto fdmi_cmd_free_mpvirt; - - bmp->virt = lpfc_mbuf_alloc(phba, 0, &(bmp->phys)); - if (!bmp->virt) - goto fdmi_cmd_free_bmp; - - INIT_LIST_HEAD(&mp->list); - INIT_LIST_HEAD(&bmp->list); - - /* FDMI request */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0218 FDMI Request Data: x%x x%x x%x\n", - vport->fc_flag, vport->port_state, cmdcode); - CtReq = (struct lpfc_sli_ct_request *) mp->virt; - - memset(CtReq, 0, sizeof(struct lpfc_sli_ct_request)); - CtReq->RevisionId.bits.Revision = SLI_CT_REVISION; - CtReq->RevisionId.bits.InId = 0; - - CtReq->FsType = SLI_CT_MANAGEMENT_SERVICE; - CtReq->FsSubType = SLI_CT_FDMI_Subtypes; - size = 0; - - switch (cmdcode) { - case SLI_MGMT_RHBA: - { - lpfc_vpd_t *vp = &phba->vpd; - uint32_t i, j, incr; - int len; - - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_MGMT_RHBA); - CtReq->CommandResponse.bits.Size = 0; - rh = (REG_HBA *) & CtReq->un.PortID; - memcpy(&rh->hi.PortName, &vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - /* One entry (port) per adapter */ - rh->rpl.EntryCnt = be32_to_cpu(1); - memcpy(&rh->rpl.pe, &vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - - /* point to the HBA attribute block */ - size = 2 * sizeof (struct lpfc_name) + FOURBYTES; - ab = (ATTRIBUTE_BLOCK *) ((uint8_t *) rh + size); - ab->EntryCnt = 0; - - /* Point to the beginning of the first HBA attribute - entry */ - /* #1 HBA attribute entry */ - size += FOURBYTES; - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(NODE_NAME); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES - + sizeof (struct lpfc_name)); - memcpy(&ae->un.NodeName, &vport->fc_sparam.nodeName, - sizeof (struct lpfc_name)); - ab->EntryCnt++; - size += FOURBYTES + sizeof (struct lpfc_name); - - /* #2 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(MANUFACTURER); - strcpy(ae->un.Manufacturer, "Emulex Corporation"); - len = strlen(ae->un.Manufacturer); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - ab->EntryCnt++; - size += FOURBYTES + len; - - /* #3 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(SERIAL_NUMBER); - strcpy(ae->un.SerialNumber, phba->SerialNumber); - len = strlen(ae->un.SerialNumber); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - ab->EntryCnt++; - size += FOURBYTES + len; - - /* #4 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(MODEL); - strcpy(ae->un.Model, phba->ModelName); - len = strlen(ae->un.Model); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - ab->EntryCnt++; - size += FOURBYTES + len; - - /* #5 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(MODEL_DESCRIPTION); - strcpy(ae->un.ModelDescription, phba->ModelDesc); - len = strlen(ae->un.ModelDescription); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - ab->EntryCnt++; - size += FOURBYTES + len; - - /* #6 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(HARDWARE_VERSION); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 8); - /* Convert JEDEC ID to ascii for hardware version */ - incr = vp->rev.biuRev; - for (i = 0; i < 8; i++) { - j = (incr & 0xf); - if (j <= 9) - ae->un.HardwareVersion[7 - i] = - (char)((uint8_t) 0x30 + - (uint8_t) j); - else - ae->un.HardwareVersion[7 - i] = - (char)((uint8_t) 0x61 + - (uint8_t) (j - 10)); - incr = (incr >> 4); - } - ab->EntryCnt++; - size += FOURBYTES + 8; - - /* #7 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(DRIVER_VERSION); - strcpy(ae->un.DriverVersion, lpfc_release_version); - len = strlen(ae->un.DriverVersion); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - ab->EntryCnt++; - size += FOURBYTES + len; - - /* #8 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(OPTION_ROM_VERSION); - strcpy(ae->un.OptionROMVersion, phba->OptionROMVersion); - len = strlen(ae->un.OptionROMVersion); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - ab->EntryCnt++; - size += FOURBYTES + len; - - /* #9 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(FIRMWARE_VERSION); - lpfc_decode_firmware_rev(phba, ae->un.FirmwareVersion, - 1); - len = strlen(ae->un.FirmwareVersion); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - ab->EntryCnt++; - size += FOURBYTES + len; - - /* #10 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION); - sprintf(ae->un.OsNameVersion, "%s %s %s", - init_utsname()->sysname, - init_utsname()->release, - init_utsname()->version); - len = strlen(ae->un.OsNameVersion); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - ab->EntryCnt++; - size += FOURBYTES + len; - - /* #11 HBA attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size); - ae->ad.bits.AttrType = be16_to_cpu(MAX_CT_PAYLOAD_LEN); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - ae->un.MaxCTPayloadLen = (65 * 4096); - ab->EntryCnt++; - size += FOURBYTES + 4; - - ab->EntryCnt = be32_to_cpu(ab->EntryCnt); - /* Total size */ - size = GID_REQUEST_SZ - 4 + size; - } - break; - - case SLI_MGMT_RPA: - { - lpfc_vpd_t *vp; - struct serv_parm *hsp; - int len; - - vp = &phba->vpd; - - CtReq->CommandResponse.bits.CmdRsp = - be16_to_cpu(SLI_MGMT_RPA); - CtReq->CommandResponse.bits.Size = 0; - pab = (REG_PORT_ATTRIBUTE *) & CtReq->un.PortID; - size = sizeof (struct lpfc_name) + FOURBYTES; - memcpy((uint8_t *) & pab->PortName, - (uint8_t *) & vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - pab->ab.EntryCnt = 0; - - /* #1 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_FC4_TYPES); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 32); - ae->un.SupportFC4Types[2] = 1; - ae->un.SupportFC4Types[7] = 1; - pab->ab.EntryCnt++; - size += FOURBYTES + 32; - - /* #2 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(SUPPORTED_SPEED); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - - ae->un.SupportSpeed = 0; - if (phba->lmt & LMT_16Gb) - ae->un.SupportSpeed |= HBA_PORTSPEED_16GBIT; - if (phba->lmt & LMT_10Gb) - ae->un.SupportSpeed |= HBA_PORTSPEED_10GBIT; - if (phba->lmt & LMT_8Gb) - ae->un.SupportSpeed |= HBA_PORTSPEED_8GBIT; - if (phba->lmt & LMT_4Gb) - ae->un.SupportSpeed |= HBA_PORTSPEED_4GBIT; - if (phba->lmt & LMT_2Gb) - ae->un.SupportSpeed |= HBA_PORTSPEED_2GBIT; - if (phba->lmt & LMT_1Gb) - ae->un.SupportSpeed |= HBA_PORTSPEED_1GBIT; - - pab->ab.EntryCnt++; - size += FOURBYTES + 4; - - /* #3 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(PORT_SPEED); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - switch(phba->fc_linkspeed) { - case LPFC_LINK_SPEED_1GHZ: - ae->un.PortSpeed = HBA_PORTSPEED_1GBIT; - break; - case LPFC_LINK_SPEED_2GHZ: - ae->un.PortSpeed = HBA_PORTSPEED_2GBIT; - break; - case LPFC_LINK_SPEED_4GHZ: - ae->un.PortSpeed = HBA_PORTSPEED_4GBIT; - break; - case LPFC_LINK_SPEED_8GHZ: - ae->un.PortSpeed = HBA_PORTSPEED_8GBIT; - break; - case LPFC_LINK_SPEED_10GHZ: - ae->un.PortSpeed = HBA_PORTSPEED_10GBIT; - break; - case LPFC_LINK_SPEED_16GHZ: - ae->un.PortSpeed = HBA_PORTSPEED_16GBIT; - break; - default: - ae->un.PortSpeed = HBA_PORTSPEED_UNKNOWN; - break; - } - pab->ab.EntryCnt++; - size += FOURBYTES + 4; - - /* #4 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(MAX_FRAME_SIZE); - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + 4); - hsp = (struct serv_parm *) & vport->fc_sparam; - ae->un.MaxFrameSize = - (((uint32_t) hsp->cmn. - bbRcvSizeMsb) << 8) | (uint32_t) hsp->cmn. - bbRcvSizeLsb; - pab->ab.EntryCnt++; - size += FOURBYTES + 4; - - /* #5 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + size); - ae->ad.bits.AttrType = be16_to_cpu(OS_DEVICE_NAME); - strcpy((char *)ae->un.OsDeviceName, LPFC_DRIVER_NAME); - len = strlen((char *)ae->un.OsDeviceName); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len); - pab->ab.EntryCnt++; - size += FOURBYTES + len; - - if (vport->cfg_fdmi_on == 2) { - /* #6 Port attribute entry */ - ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) pab + - size); - ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME); - sprintf(ae->un.HostName, "%s", - init_utsname()->nodename); - len = strlen(ae->un.HostName); - len += (len & 3) ? (4 - (len & 3)) : 4; - ae->ad.bits.AttrLen = - be16_to_cpu(FOURBYTES + len); - pab->ab.EntryCnt++; - size += FOURBYTES + len; - } - - pab->ab.EntryCnt = be32_to_cpu(pab->ab.EntryCnt); - /* Total size */ - size = GID_REQUEST_SZ - 4 + size; - } - break; - - case SLI_MGMT_DHBA: - CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DHBA); - CtReq->CommandResponse.bits.Size = 0; - pe = (PORT_ENTRY *) & CtReq->un.PortID; - memcpy((uint8_t *) & pe->PortName, - (uint8_t *) & vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name); - break; - - case SLI_MGMT_DPRT: - CtReq->CommandResponse.bits.CmdRsp = be16_to_cpu(SLI_MGMT_DPRT); - CtReq->CommandResponse.bits.Size = 0; - pe = (PORT_ENTRY *) & CtReq->un.PortID; - memcpy((uint8_t *) & pe->PortName, - (uint8_t *) & vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - size = GID_REQUEST_SZ - 4 + sizeof (struct lpfc_name); - break; - } - - bpl = (struct ulp_bde64 *) bmp->virt; - bpl->addrHigh = le32_to_cpu(putPaddrHigh(mp->phys) ); - bpl->addrLow = le32_to_cpu(putPaddrLow(mp->phys) ); - bpl->tus.f.bdeFlags = 0; - bpl->tus.f.bdeSize = size; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - - cmpl = lpfc_cmpl_ct_cmd_fdmi; - - /* The lpfc_ct_cmd/lpfc_get_req shall increment ndlp reference count - * to hold ndlp reference for the corresponding callback function. - */ - if (!lpfc_ct_cmd(vport, mp, bmp, ndlp, cmpl, FC_MAX_NS_RSP, 0)) - return 0; - - /* Decrement ndlp reference count to release ndlp reference held - * for the failed command's callback function. - */ - lpfc_nlp_put(ndlp); - - lpfc_mbuf_free(phba, bmp->virt, bmp->phys); -fdmi_cmd_free_bmp: - kfree(bmp); -fdmi_cmd_free_mpvirt: - lpfc_mbuf_free(phba, mp->virt, mp->phys); -fdmi_cmd_free_mp: - kfree(mp); -fdmi_cmd_exit: - /* Issue FDMI request failed */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0244 Issue FDMI request failed Data: x%x\n", - cmdcode); - return 1; -} - -/** - * lpfc_delayed_disc_tmo - Timeout handler for delayed discovery timer. - * @ptr - Context object of the timer. - * - * This function set the WORKER_DELAYED_DISC_TMO flag and wake up - * the worker thread. - **/ -void -lpfc_delayed_disc_tmo(unsigned long ptr) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)ptr; - struct lpfc_hba *phba = vport->phba; - uint32_t tmo_posted; - unsigned long iflag; - - spin_lock_irqsave(&vport->work_port_lock, iflag); - tmo_posted = vport->work_port_events & WORKER_DELAYED_DISC_TMO; - if (!tmo_posted) - vport->work_port_events |= WORKER_DELAYED_DISC_TMO; - spin_unlock_irqrestore(&vport->work_port_lock, iflag); - - if (!tmo_posted) - lpfc_worker_wake_up(phba); - return; -} - -/** - * lpfc_delayed_disc_timeout_handler - Function called by worker thread to - * handle delayed discovery. - * @vport: pointer to a host virtual N_Port data structure. - * - * This function start nport discovery of the vport. - **/ -void -lpfc_delayed_disc_timeout_handler(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - spin_lock_irq(shost->host_lock); - if (!(vport->fc_flag & FC_DISC_DELAYED)) { - spin_unlock_irq(shost->host_lock); - return; - } - vport->fc_flag &= ~FC_DISC_DELAYED; - spin_unlock_irq(shost->host_lock); - - lpfc_do_scr_ns_plogi(vport->phba, vport); -} - -void -lpfc_fdmi_tmo(unsigned long ptr) -{ - struct lpfc_vport *vport = (struct lpfc_vport *)ptr; - struct lpfc_hba *phba = vport->phba; - uint32_t tmo_posted; - unsigned long iflag; - - spin_lock_irqsave(&vport->work_port_lock, iflag); - tmo_posted = vport->work_port_events & WORKER_FDMI_TMO; - if (!tmo_posted) - vport->work_port_events |= WORKER_FDMI_TMO; - spin_unlock_irqrestore(&vport->work_port_lock, iflag); - - if (!tmo_posted) - lpfc_worker_wake_up(phba); - return; -} - -void -lpfc_fdmi_timeout_handler(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp; - - ndlp = lpfc_findnode_did(vport, FDMI_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - if (init_utsname()->nodename[0] != '\0') - lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); - else - mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60); - } - return; -} - -void -lpfc_decode_firmware_rev(struct lpfc_hba *phba, char *fwrevision, int flag) -{ - struct lpfc_sli *psli = &phba->sli; - lpfc_vpd_t *vp = &phba->vpd; - uint32_t b1, b2, b3, b4, i, rev; - char c; - uint32_t *ptr, str[4]; - uint8_t *fwname; - - if (phba->sli_rev == LPFC_SLI_REV4) - snprintf(fwrevision, FW_REV_STR_SIZE, "%s", vp->rev.opFwName); - else if (vp->rev.rBit) { - if (psli->sli_flag & LPFC_SLI_ACTIVE) - rev = vp->rev.sli2FwRev; - else - rev = vp->rev.sli1FwRev; - - b1 = (rev & 0x0000f000) >> 12; - b2 = (rev & 0x00000f00) >> 8; - b3 = (rev & 0x000000c0) >> 6; - b4 = (rev & 0x00000030) >> 4; - - switch (b4) { - case 0: - c = 'N'; - break; - case 1: - c = 'A'; - break; - case 2: - c = 'B'; - break; - case 3: - c = 'X'; - break; - default: - c = 0; - break; - } - b4 = (rev & 0x0000000f); - - if (psli->sli_flag & LPFC_SLI_ACTIVE) - fwname = vp->rev.sli2FwName; - else - fwname = vp->rev.sli1FwName; - - for (i = 0; i < 16; i++) - if (fwname[i] == 0x20) - fwname[i] = 0; - - ptr = (uint32_t*)fwname; - - for (i = 0; i < 3; i++) - str[i] = be32_to_cpu(*ptr++); - - if (c == 0) { - if (flag) - sprintf(fwrevision, "%d.%d%d (%s)", - b1, b2, b3, (char *)str); - else - sprintf(fwrevision, "%d.%d%d", b1, - b2, b3); - } else { - if (flag) - sprintf(fwrevision, "%d.%d%d%c%d (%s)", - b1, b2, b3, c, - b4, (char *)str); - else - sprintf(fwrevision, "%d.%d%d%c%d", - b1, b2, b3, c, b4); - } - } else { - rev = vp->rev.smFwRev; - - b1 = (rev & 0xff000000) >> 24; - b2 = (rev & 0x00f00000) >> 20; - b3 = (rev & 0x000f0000) >> 16; - c = (rev & 0x0000ff00) >> 8; - b4 = (rev & 0x000000ff); - - sprintf(fwrevision, "%d.%d%d%c%d", b1, b2, b3, c, b4); - } - return; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.c deleted file mode 100644 index af04b0d6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.c +++ /dev/null @@ -1,4468 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2007-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_vport.h" -#include "lpfc_version.h" -#include "lpfc_compat.h" -#include "lpfc_debugfs.h" -#include "lpfc_bsg.h" - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS -/* - * debugfs interface - * - * To access this interface the user should: - * # mount -t debugfs none /sys/kernel/debug - * - * The lpfc debugfs directory hierarchy is: - * /sys/kernel/debug/lpfc/fnX/vportY - * where X is the lpfc hba function unique_id - * where Y is the vport VPI on that hba - * - * Debugging services available per vport: - * discovery_trace - * This is an ACSII readable file that contains a trace of the last - * lpfc_debugfs_max_disc_trc events that happened on a specific vport. - * See lpfc_debugfs.h for different categories of discovery events. - * To enable the discovery trace, the following module parameters must be set: - * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support - * lpfc_debugfs_max_disc_trc=X Where X is the event trace depth for - * EACH vport. X MUST also be a power of 2. - * lpfc_debugfs_mask_disc_trc=Y Where Y is an event mask as defined in - * lpfc_debugfs.h . - * - * slow_ring_trace - * This is an ACSII readable file that contains a trace of the last - * lpfc_debugfs_max_slow_ring_trc events that happened on a specific HBA. - * To enable the slow ring trace, the following module parameters must be set: - * lpfc_debugfs_enable=1 Turns on lpfc debugfs filesystem support - * lpfc_debugfs_max_slow_ring_trc=X Where X is the event trace depth for - * the HBA. X MUST also be a power of 2. - */ -static int lpfc_debugfs_enable = 1; -module_param(lpfc_debugfs_enable, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_debugfs_enable, "Enable debugfs services"); - -/* This MUST be a power of 2 */ -static int lpfc_debugfs_max_disc_trc; -module_param(lpfc_debugfs_max_disc_trc, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_debugfs_max_disc_trc, - "Set debugfs discovery trace depth"); - -/* This MUST be a power of 2 */ -static int lpfc_debugfs_max_slow_ring_trc; -module_param(lpfc_debugfs_max_slow_ring_trc, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_debugfs_max_slow_ring_trc, - "Set debugfs slow ring trace depth"); - -static int lpfc_debugfs_mask_disc_trc; -module_param(lpfc_debugfs_mask_disc_trc, int, S_IRUGO); -MODULE_PARM_DESC(lpfc_debugfs_mask_disc_trc, - "Set debugfs discovery trace mask"); - -#include - -static atomic_t lpfc_debugfs_seq_trc_cnt = ATOMIC_INIT(0); -static unsigned long lpfc_debugfs_start_time = 0L; - -/* iDiag */ -static struct lpfc_idiag idiag; - -/** - * lpfc_debugfs_disc_trc_data - Dump discovery logging to a buffer - * @vport: The vport to gather the log info from. - * @buf: The buffer to dump log into. - * @size: The maximum amount of data to process. - * - * Description: - * This routine gathers the lpfc discovery debugfs data from the @vport and - * dumps it to @buf up to @size number of bytes. It will start at the next entry - * in the log and process the log until the end of the buffer. Then it will - * gather from the beginning of the log and process until the current entry. - * - * Notes: - * Discovery logging will be disabled while while this routine dumps the log. - * - * Return Value: - * This routine returns the amount of bytes that were dumped into @buf and will - * not exceed @size. - **/ -static int -lpfc_debugfs_disc_trc_data(struct lpfc_vport *vport, char *buf, int size) -{ - int i, index, len, enable; - uint32_t ms; - struct lpfc_debugfs_trc *dtp; - char *buffer; - - buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL); - if (!buffer) - return 0; - - enable = lpfc_debugfs_enable; - lpfc_debugfs_enable = 0; - - len = 0; - index = (atomic_read(&vport->disc_trc_cnt) + 1) & - (lpfc_debugfs_max_disc_trc - 1); - for (i = index; i < lpfc_debugfs_max_disc_trc; i++) { - dtp = vport->disc_trc + i; - if (!dtp->fmt) - continue; - ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); - snprintf(buffer, - LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", - dtp->seq_cnt, ms, dtp->fmt); - len += snprintf(buf+len, size-len, buffer, - dtp->data1, dtp->data2, dtp->data3); - } - for (i = 0; i < index; i++) { - dtp = vport->disc_trc + i; - if (!dtp->fmt) - continue; - ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); - snprintf(buffer, - LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", - dtp->seq_cnt, ms, dtp->fmt); - len += snprintf(buf+len, size-len, buffer, - dtp->data1, dtp->data2, dtp->data3); - } - - lpfc_debugfs_enable = enable; - kfree(buffer); - - return len; -} - -/** - * lpfc_debugfs_slow_ring_trc_data - Dump slow ring logging to a buffer - * @phba: The HBA to gather the log info from. - * @buf: The buffer to dump log into. - * @size: The maximum amount of data to process. - * - * Description: - * This routine gathers the lpfc slow ring debugfs data from the @phba and - * dumps it to @buf up to @size number of bytes. It will start at the next entry - * in the log and process the log until the end of the buffer. Then it will - * gather from the beginning of the log and process until the current entry. - * - * Notes: - * Slow ring logging will be disabled while while this routine dumps the log. - * - * Return Value: - * This routine returns the amount of bytes that were dumped into @buf and will - * not exceed @size. - **/ -static int -lpfc_debugfs_slow_ring_trc_data(struct lpfc_hba *phba, char *buf, int size) -{ - int i, index, len, enable; - uint32_t ms; - struct lpfc_debugfs_trc *dtp; - char *buffer; - - buffer = kmalloc(LPFC_DEBUG_TRC_ENTRY_SIZE, GFP_KERNEL); - if (!buffer) - return 0; - - enable = lpfc_debugfs_enable; - lpfc_debugfs_enable = 0; - - len = 0; - index = (atomic_read(&phba->slow_ring_trc_cnt) + 1) & - (lpfc_debugfs_max_slow_ring_trc - 1); - for (i = index; i < lpfc_debugfs_max_slow_ring_trc; i++) { - dtp = phba->slow_ring_trc + i; - if (!dtp->fmt) - continue; - ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); - snprintf(buffer, - LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", - dtp->seq_cnt, ms, dtp->fmt); - len += snprintf(buf+len, size-len, buffer, - dtp->data1, dtp->data2, dtp->data3); - } - for (i = 0; i < index; i++) { - dtp = phba->slow_ring_trc + i; - if (!dtp->fmt) - continue; - ms = jiffies_to_msecs(dtp->jif - lpfc_debugfs_start_time); - snprintf(buffer, - LPFC_DEBUG_TRC_ENTRY_SIZE, "%010d:%010d ms:%s\n", - dtp->seq_cnt, ms, dtp->fmt); - len += snprintf(buf+len, size-len, buffer, - dtp->data1, dtp->data2, dtp->data3); - } - - lpfc_debugfs_enable = enable; - kfree(buffer); - - return len; -} - -static int lpfc_debugfs_last_hbq = -1; - -/** - * lpfc_debugfs_hbqinfo_data - Dump host buffer queue info to a buffer - * @phba: The HBA to gather host buffer info from. - * @buf: The buffer to dump log into. - * @size: The maximum amount of data to process. - * - * Description: - * This routine dumps the host buffer queue info from the @phba to @buf up to - * @size number of bytes. A header that describes the current hbq state will be - * dumped to @buf first and then info on each hbq entry will be dumped to @buf - * until @size bytes have been dumped or all the hbq info has been dumped. - * - * Notes: - * This routine will rotate through each configured HBQ each time called. - * - * Return Value: - * This routine returns the amount of bytes that were dumped into @buf and will - * not exceed @size. - **/ -static int -lpfc_debugfs_hbqinfo_data(struct lpfc_hba *phba, char *buf, int size) -{ - int len = 0; - int cnt, i, j, found, posted, low; - uint32_t phys, raw_index, getidx; - struct lpfc_hbq_init *hip; - struct hbq_s *hbqs; - struct lpfc_hbq_entry *hbqe; - struct lpfc_dmabuf *d_buf; - struct hbq_dmabuf *hbq_buf; - - if (phba->sli_rev != 3) - return 0; - cnt = LPFC_HBQINFO_SIZE; - spin_lock_irq(&phba->hbalock); - - /* toggle between multiple hbqs, if any */ - i = lpfc_sli_hbq_count(); - if (i > 1) { - lpfc_debugfs_last_hbq++; - if (lpfc_debugfs_last_hbq >= i) - lpfc_debugfs_last_hbq = 0; - } - else - lpfc_debugfs_last_hbq = 0; - - i = lpfc_debugfs_last_hbq; - - len += snprintf(buf+len, size-len, "HBQ %d Info\n", i); - - hbqs = &phba->hbqs[i]; - posted = 0; - list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) - posted++; - - hip = lpfc_hbq_defs[i]; - len += snprintf(buf+len, size-len, - "idx:%d prof:%d rn:%d bufcnt:%d icnt:%d acnt:%d posted %d\n", - hip->hbq_index, hip->profile, hip->rn, - hip->buffer_count, hip->init_count, hip->add_count, posted); - - raw_index = phba->hbq_get[i]; - getidx = le32_to_cpu(raw_index); - len += snprintf(buf+len, size-len, - "entrys:%d bufcnt:%d Put:%d nPut:%d localGet:%d hbaGet:%d\n", - hbqs->entry_count, hbqs->buffer_count, hbqs->hbqPutIdx, - hbqs->next_hbqPutIdx, hbqs->local_hbqGetIdx, getidx); - - hbqe = (struct lpfc_hbq_entry *) phba->hbqs[i].hbq_virt; - for (j=0; jentry_count; j++) { - len += snprintf(buf+len, size-len, - "%03d: %08x %04x %05x ", j, - le32_to_cpu(hbqe->bde.addrLow), - le32_to_cpu(hbqe->bde.tus.w), - le32_to_cpu(hbqe->buffer_tag)); - i = 0; - found = 0; - - /* First calculate if slot has an associated posted buffer */ - low = hbqs->hbqPutIdx - posted; - if (low >= 0) { - if ((j >= hbqs->hbqPutIdx) || (j < low)) { - len += snprintf(buf+len, size-len, "Unused\n"); - goto skipit; - } - } - else { - if ((j >= hbqs->hbqPutIdx) && - (j < (hbqs->entry_count+low))) { - len += snprintf(buf+len, size-len, "Unused\n"); - goto skipit; - } - } - - /* Get the Buffer info for the posted buffer */ - list_for_each_entry(d_buf, &hbqs->hbq_buffer_list, list) { - hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); - phys = ((uint64_t)hbq_buf->dbuf.phys & 0xffffffff); - if (phys == le32_to_cpu(hbqe->bde.addrLow)) { - len += snprintf(buf+len, size-len, - "Buf%d: %p %06x\n", i, - hbq_buf->dbuf.virt, hbq_buf->tag); - found = 1; - break; - } - i++; - } - if (!found) { - len += snprintf(buf+len, size-len, "No DMAinfo?\n"); - } -skipit: - hbqe++; - if (len > LPFC_HBQINFO_SIZE - 54) - break; - } - spin_unlock_irq(&phba->hbalock); - return len; -} - -static int lpfc_debugfs_last_hba_slim_off; - -/** - * lpfc_debugfs_dumpHBASlim_data - Dump HBA SLIM info to a buffer - * @phba: The HBA to gather SLIM info from. - * @buf: The buffer to dump log into. - * @size: The maximum amount of data to process. - * - * Description: - * This routine dumps the current contents of HBA SLIM for the HBA associated - * with @phba to @buf up to @size bytes of data. This is the raw HBA SLIM data. - * - * Notes: - * This routine will only dump up to 1024 bytes of data each time called and - * should be called multiple times to dump the entire HBA SLIM. - * - * Return Value: - * This routine returns the amount of bytes that were dumped into @buf and will - * not exceed @size. - **/ -static int -lpfc_debugfs_dumpHBASlim_data(struct lpfc_hba *phba, char *buf, int size) -{ - int len = 0; - int i, off; - uint32_t *ptr; - char *buffer; - - buffer = kmalloc(1024, GFP_KERNEL); - if (!buffer) - return 0; - - off = 0; - spin_lock_irq(&phba->hbalock); - - len += snprintf(buf+len, size-len, "HBA SLIM\n"); - lpfc_memcpy_from_slim(buffer, - phba->MBslimaddr + lpfc_debugfs_last_hba_slim_off, 1024); - - ptr = (uint32_t *)&buffer[0]; - off = lpfc_debugfs_last_hba_slim_off; - - /* Set it up for the next time */ - lpfc_debugfs_last_hba_slim_off += 1024; - if (lpfc_debugfs_last_hba_slim_off >= 4096) - lpfc_debugfs_last_hba_slim_off = 0; - - i = 1024; - while (i > 0) { - len += snprintf(buf+len, size-len, - "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", - off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), - *(ptr+5), *(ptr+6), *(ptr+7)); - ptr += 8; - i -= (8 * sizeof(uint32_t)); - off += (8 * sizeof(uint32_t)); - } - - spin_unlock_irq(&phba->hbalock); - kfree(buffer); - - return len; -} - -/** - * lpfc_debugfs_dumpHostSlim_data - Dump host SLIM info to a buffer - * @phba: The HBA to gather Host SLIM info from. - * @buf: The buffer to dump log into. - * @size: The maximum amount of data to process. - * - * Description: - * This routine dumps the current contents of host SLIM for the host associated - * with @phba to @buf up to @size bytes of data. The dump will contain the - * Mailbox, PCB, Rings, and Registers that are located in host memory. - * - * Return Value: - * This routine returns the amount of bytes that were dumped into @buf and will - * not exceed @size. - **/ -static int -lpfc_debugfs_dumpHostSlim_data(struct lpfc_hba *phba, char *buf, int size) -{ - int len = 0; - int i, off; - uint32_t word0, word1, word2, word3; - uint32_t *ptr; - struct lpfc_pgp *pgpp; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - - off = 0; - spin_lock_irq(&phba->hbalock); - - len += snprintf(buf+len, size-len, "SLIM Mailbox\n"); - ptr = (uint32_t *)phba->slim2p.virt; - i = sizeof(MAILBOX_t); - while (i > 0) { - len += snprintf(buf+len, size-len, - "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", - off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), - *(ptr+5), *(ptr+6), *(ptr+7)); - ptr += 8; - i -= (8 * sizeof(uint32_t)); - off += (8 * sizeof(uint32_t)); - } - - len += snprintf(buf+len, size-len, "SLIM PCB\n"); - ptr = (uint32_t *)phba->pcb; - i = sizeof(PCB_t); - while (i > 0) { - len += snprintf(buf+len, size-len, - "%08x: %08x %08x %08x %08x %08x %08x %08x %08x\n", - off, *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), - *(ptr+5), *(ptr+6), *(ptr+7)); - ptr += 8; - i -= (8 * sizeof(uint32_t)); - off += (8 * sizeof(uint32_t)); - } - - for (i = 0; i < 4; i++) { - pgpp = &phba->port_gp[i]; - pring = &psli->ring[i]; - len += snprintf(buf+len, size-len, - "Ring %d: CMD GetInx:%d (Max:%d Next:%d " - "Local:%d flg:x%x) RSP PutInx:%d Max:%d\n", - i, pgpp->cmdGetInx, pring->numCiocb, - pring->next_cmdidx, pring->local_getidx, - pring->flag, pgpp->rspPutInx, pring->numRiocb); - } - - if (phba->sli_rev <= LPFC_SLI_REV3) { - word0 = readl(phba->HAregaddr); - word1 = readl(phba->CAregaddr); - word2 = readl(phba->HSregaddr); - word3 = readl(phba->HCregaddr); - len += snprintf(buf+len, size-len, "HA:%08x CA:%08x HS:%08x " - "HC:%08x\n", word0, word1, word2, word3); - } - spin_unlock_irq(&phba->hbalock); - return len; -} - -/** - * lpfc_debugfs_nodelist_data - Dump target node list to a buffer - * @vport: The vport to gather target node info from. - * @buf: The buffer to dump log into. - * @size: The maximum amount of data to process. - * - * Description: - * This routine dumps the current target node list associated with @vport to - * @buf up to @size bytes of data. Each node entry in the dump will contain a - * node state, DID, WWPN, WWNN, RPI, flags, type, and other useful fields. - * - * Return Value: - * This routine returns the amount of bytes that were dumped into @buf and will - * not exceed @size. - **/ -static int -lpfc_debugfs_nodelist_data(struct lpfc_vport *vport, char *buf, int size) -{ - int len = 0; - int cnt; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp; - unsigned char *statep, *name; - - cnt = (LPFC_NODELIST_SIZE / LPFC_NODELIST_ENTRY_SIZE); - - spin_lock_irq(shost->host_lock); - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!cnt) { - len += snprintf(buf+len, size-len, - "Missing Nodelist Entries\n"); - break; - } - cnt--; - switch (ndlp->nlp_state) { - case NLP_STE_UNUSED_NODE: - statep = "UNUSED"; - break; - case NLP_STE_PLOGI_ISSUE: - statep = "PLOGI "; - break; - case NLP_STE_ADISC_ISSUE: - statep = "ADISC "; - break; - case NLP_STE_REG_LOGIN_ISSUE: - statep = "REGLOG"; - break; - case NLP_STE_PRLI_ISSUE: - statep = "PRLI "; - break; - case NLP_STE_UNMAPPED_NODE: - statep = "UNMAP "; - break; - case NLP_STE_MAPPED_NODE: - statep = "MAPPED"; - break; - case NLP_STE_NPR_NODE: - statep = "NPR "; - break; - default: - statep = "UNKNOWN"; - } - len += snprintf(buf+len, size-len, "%s DID:x%06x ", - statep, ndlp->nlp_DID); - name = (unsigned char *)&ndlp->nlp_portname; - len += snprintf(buf+len, size-len, - "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ", - *name, *(name+1), *(name+2), *(name+3), - *(name+4), *(name+5), *(name+6), *(name+7)); - name = (unsigned char *)&ndlp->nlp_nodename; - len += snprintf(buf+len, size-len, - "WWNN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x ", - *name, *(name+1), *(name+2), *(name+3), - *(name+4), *(name+5), *(name+6), *(name+7)); - len += snprintf(buf+len, size-len, "RPI:%03d flag:x%08x ", - ndlp->nlp_rpi, ndlp->nlp_flag); - if (!ndlp->nlp_type) - len += snprintf(buf+len, size-len, "UNKNOWN_TYPE "); - if (ndlp->nlp_type & NLP_FC_NODE) - len += snprintf(buf+len, size-len, "FC_NODE "); - if (ndlp->nlp_type & NLP_FABRIC) - len += snprintf(buf+len, size-len, "FABRIC "); - if (ndlp->nlp_type & NLP_FCP_TARGET) - len += snprintf(buf+len, size-len, "FCP_TGT sid:%d ", - ndlp->nlp_sid); - if (ndlp->nlp_type & NLP_FCP_INITIATOR) - len += snprintf(buf+len, size-len, "FCP_INITIATOR "); - len += snprintf(buf+len, size-len, "usgmap:%x ", - ndlp->nlp_usg_map); - len += snprintf(buf+len, size-len, "refcnt:%x", - atomic_read(&ndlp->kref.refcount)); - len += snprintf(buf+len, size-len, "\n"); - } - spin_unlock_irq(shost->host_lock); - return len; -} -#endif - -/** - * lpfc_debugfs_disc_trc - Store discovery trace log - * @vport: The vport to associate this trace string with for retrieval. - * @mask: Log entry classification. - * @fmt: Format string to be displayed when dumping the log. - * @data1: 1st data parameter to be applied to @fmt. - * @data2: 2nd data parameter to be applied to @fmt. - * @data3: 3rd data parameter to be applied to @fmt. - * - * Description: - * This routine is used by the driver code to add a debugfs log entry to the - * discovery trace buffer associated with @vport. Only entries with a @mask that - * match the current debugfs discovery mask will be saved. Entries that do not - * match will be thrown away. @fmt, @data1, @data2, and @data3 are used like - * printf when displaying the log. - **/ -inline void -lpfc_debugfs_disc_trc(struct lpfc_vport *vport, int mask, char *fmt, - uint32_t data1, uint32_t data2, uint32_t data3) -{ -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - struct lpfc_debugfs_trc *dtp; - int index; - - if (!(lpfc_debugfs_mask_disc_trc & mask)) - return; - - if (!lpfc_debugfs_enable || !lpfc_debugfs_max_disc_trc || - !vport || !vport->disc_trc) - return; - - index = atomic_inc_return(&vport->disc_trc_cnt) & - (lpfc_debugfs_max_disc_trc - 1); - dtp = vport->disc_trc + index; - dtp->fmt = fmt; - dtp->data1 = data1; - dtp->data2 = data2; - dtp->data3 = data3; - dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt); - dtp->jif = jiffies; -#endif - return; -} - -/** - * lpfc_debugfs_slow_ring_trc - Store slow ring trace log - * @phba: The phba to associate this trace string with for retrieval. - * @fmt: Format string to be displayed when dumping the log. - * @data1: 1st data parameter to be applied to @fmt. - * @data2: 2nd data parameter to be applied to @fmt. - * @data3: 3rd data parameter to be applied to @fmt. - * - * Description: - * This routine is used by the driver code to add a debugfs log entry to the - * discovery trace buffer associated with @vport. @fmt, @data1, @data2, and - * @data3 are used like printf when displaying the log. - **/ -inline void -lpfc_debugfs_slow_ring_trc(struct lpfc_hba *phba, char *fmt, - uint32_t data1, uint32_t data2, uint32_t data3) -{ -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - struct lpfc_debugfs_trc *dtp; - int index; - - if (!lpfc_debugfs_enable || !lpfc_debugfs_max_slow_ring_trc || - !phba || !phba->slow_ring_trc) - return; - - index = atomic_inc_return(&phba->slow_ring_trc_cnt) & - (lpfc_debugfs_max_slow_ring_trc - 1); - dtp = phba->slow_ring_trc + index; - dtp->fmt = fmt; - dtp->data1 = data1; - dtp->data2 = data2; - dtp->data3 = data3; - dtp->seq_cnt = atomic_inc_return(&lpfc_debugfs_seq_trc_cnt); - dtp->jif = jiffies; -#endif - return; -} - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS -/** - * lpfc_debugfs_disc_trc_open - Open the discovery trace log - * @inode: The inode pointer that contains a vport pointer. - * @file: The file pointer to attach the log output. - * - * Description: - * This routine is the entry point for the debugfs open file operation. It gets - * the vport from the i_private field in @inode, allocates the necessary buffer - * for the log, fills the buffer from the in-memory log for this vport, and then - * returns a pointer to that log in the private_data field in @file. - * - * Returns: - * This function returns zero if successful. On error it will return an negative - * error value. - **/ -static int -lpfc_debugfs_disc_trc_open(struct inode *inode, struct file *file) -{ - struct lpfc_vport *vport = inode->i_private; - struct lpfc_debug *debug; - int size; - int rc = -ENOMEM; - - if (!lpfc_debugfs_max_disc_trc) { - rc = -ENOSPC; - goto out; - } - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - size = (lpfc_debugfs_max_disc_trc * LPFC_DEBUG_TRC_ENTRY_SIZE); - size = PAGE_ALIGN(size); - - debug->buffer = kmalloc(size, GFP_KERNEL); - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = lpfc_debugfs_disc_trc_data(vport, debug->buffer, size); - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -/** - * lpfc_debugfs_slow_ring_trc_open - Open the Slow Ring trace log - * @inode: The inode pointer that contains a vport pointer. - * @file: The file pointer to attach the log output. - * - * Description: - * This routine is the entry point for the debugfs open file operation. It gets - * the vport from the i_private field in @inode, allocates the necessary buffer - * for the log, fills the buffer from the in-memory log for this vport, and then - * returns a pointer to that log in the private_data field in @file. - * - * Returns: - * This function returns zero if successful. On error it will return an negative - * error value. - **/ -static int -lpfc_debugfs_slow_ring_trc_open(struct inode *inode, struct file *file) -{ - struct lpfc_hba *phba = inode->i_private; - struct lpfc_debug *debug; - int size; - int rc = -ENOMEM; - - if (!lpfc_debugfs_max_slow_ring_trc) { - rc = -ENOSPC; - goto out; - } - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - size = (lpfc_debugfs_max_slow_ring_trc * LPFC_DEBUG_TRC_ENTRY_SIZE); - size = PAGE_ALIGN(size); - - debug->buffer = kmalloc(size, GFP_KERNEL); - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = lpfc_debugfs_slow_ring_trc_data(phba, debug->buffer, size); - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -/** - * lpfc_debugfs_hbqinfo_open - Open the hbqinfo debugfs buffer - * @inode: The inode pointer that contains a vport pointer. - * @file: The file pointer to attach the log output. - * - * Description: - * This routine is the entry point for the debugfs open file operation. It gets - * the vport from the i_private field in @inode, allocates the necessary buffer - * for the log, fills the buffer from the in-memory log for this vport, and then - * returns a pointer to that log in the private_data field in @file. - * - * Returns: - * This function returns zero if successful. On error it will return an negative - * error value. - **/ -static int -lpfc_debugfs_hbqinfo_open(struct inode *inode, struct file *file) -{ - struct lpfc_hba *phba = inode->i_private; - struct lpfc_debug *debug; - int rc = -ENOMEM; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - debug->buffer = kmalloc(LPFC_HBQINFO_SIZE, GFP_KERNEL); - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = lpfc_debugfs_hbqinfo_data(phba, debug->buffer, - LPFC_HBQINFO_SIZE); - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -/** - * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer - * @inode: The inode pointer that contains a vport pointer. - * @file: The file pointer to attach the log output. - * - * Description: - * This routine is the entry point for the debugfs open file operation. It gets - * the vport from the i_private field in @inode, allocates the necessary buffer - * for the log, fills the buffer from the in-memory log for this vport, and then - * returns a pointer to that log in the private_data field in @file. - * - * Returns: - * This function returns zero if successful. On error it will return an negative - * error value. - **/ -static int -lpfc_debugfs_dumpHBASlim_open(struct inode *inode, struct file *file) -{ - struct lpfc_hba *phba = inode->i_private; - struct lpfc_debug *debug; - int rc = -ENOMEM; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - debug->buffer = kmalloc(LPFC_DUMPHBASLIM_SIZE, GFP_KERNEL); - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = lpfc_debugfs_dumpHBASlim_data(phba, debug->buffer, - LPFC_DUMPHBASLIM_SIZE); - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -/** - * lpfc_debugfs_dumpHostSlim_open - Open the Dump Host SLIM debugfs buffer - * @inode: The inode pointer that contains a vport pointer. - * @file: The file pointer to attach the log output. - * - * Description: - * This routine is the entry point for the debugfs open file operation. It gets - * the vport from the i_private field in @inode, allocates the necessary buffer - * for the log, fills the buffer from the in-memory log for this vport, and then - * returns a pointer to that log in the private_data field in @file. - * - * Returns: - * This function returns zero if successful. On error it will return an negative - * error value. - **/ -static int -lpfc_debugfs_dumpHostSlim_open(struct inode *inode, struct file *file) -{ - struct lpfc_hba *phba = inode->i_private; - struct lpfc_debug *debug; - int rc = -ENOMEM; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - debug->buffer = kmalloc(LPFC_DUMPHOSTSLIM_SIZE, GFP_KERNEL); - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = lpfc_debugfs_dumpHostSlim_data(phba, debug->buffer, - LPFC_DUMPHOSTSLIM_SIZE); - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -static int -lpfc_debugfs_dumpData_open(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug; - int rc = -ENOMEM; - - if (!_dump_buf_data) - return -EBUSY; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - printk(KERN_ERR "9059 BLKGRD: %s: _dump_buf_data=0x%p\n", - __func__, _dump_buf_data); - debug->buffer = _dump_buf_data; - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = (1 << _dump_buf_data_order) << PAGE_SHIFT; - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -static int -lpfc_debugfs_dumpDif_open(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug; - int rc = -ENOMEM; - - if (!_dump_buf_dif) - return -EBUSY; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - printk(KERN_ERR "9060 BLKGRD: %s: _dump_buf_dif=0x%p file=%s\n", - __func__, _dump_buf_dif, file->f_dentry->d_name.name); - debug->buffer = _dump_buf_dif; - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = (1 << _dump_buf_dif_order) << PAGE_SHIFT; - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -static ssize_t -lpfc_debugfs_dumpDataDif_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - /* - * The Data/DIF buffers only save one failing IO - * The write op is used as a reset mechanism after an IO has - * already been saved to the next one can be saved - */ - spin_lock(&_dump_buf_lock); - - memset((void *)_dump_buf_data, 0, - ((1 << PAGE_SHIFT) << _dump_buf_data_order)); - memset((void *)_dump_buf_dif, 0, - ((1 << PAGE_SHIFT) << _dump_buf_dif_order)); - - _dump_buf_done = 0; - - spin_unlock(&_dump_buf_lock); - - return nbytes; -} - -static ssize_t -lpfc_debugfs_dif_err_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct dentry *dent = file->f_dentry; - struct lpfc_hba *phba = file->private_data; - char cbuf[32]; - uint64_t tmp = 0; - int cnt = 0; - - if (dent == phba->debug_writeGuard) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wgrd_cnt); - else if (dent == phba->debug_writeApp) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wapp_cnt); - else if (dent == phba->debug_writeRef) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_wref_cnt); - else if (dent == phba->debug_readGuard) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rgrd_cnt); - else if (dent == phba->debug_readApp) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rapp_cnt); - else if (dent == phba->debug_readRef) - cnt = snprintf(cbuf, 32, "%u\n", phba->lpfc_injerr_rref_cnt); - else if (dent == phba->debug_InjErrNPortID) - cnt = snprintf(cbuf, 32, "0x%06x\n", phba->lpfc_injerr_nportid); - else if (dent == phba->debug_InjErrWWPN) { - memcpy(&tmp, &phba->lpfc_injerr_wwpn, sizeof(struct lpfc_name)); - tmp = cpu_to_be64(tmp); - cnt = snprintf(cbuf, 32, "0x%016llx\n", tmp); - } else if (dent == phba->debug_InjErrLBA) { - if (phba->lpfc_injerr_lba == (sector_t)(-1)) - cnt = snprintf(cbuf, 32, "off\n"); - else - cnt = snprintf(cbuf, 32, "0x%llx\n", - (uint64_t) phba->lpfc_injerr_lba); - } else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0547 Unknown debugfs error injection entry\n"); - - return simple_read_from_buffer(buf, nbytes, ppos, &cbuf, cnt); -} - -static ssize_t -lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct dentry *dent = file->f_dentry; - struct lpfc_hba *phba = file->private_data; - char dstbuf[32]; - uint64_t tmp = 0; - int size; - - memset(dstbuf, 0, 32); - size = (nbytes < 32) ? nbytes : 32; - if (copy_from_user(dstbuf, buf, size)) - return 0; - - if (dent == phba->debug_InjErrLBA) { - if ((buf[0] == 'o') && (buf[1] == 'f') && (buf[2] == 'f')) - tmp = (uint64_t)(-1); - } - - if ((tmp == 0) && (kstrtoull(dstbuf, 0, &tmp))) - return 0; - - if (dent == phba->debug_writeGuard) - phba->lpfc_injerr_wgrd_cnt = (uint32_t)tmp; - else if (dent == phba->debug_writeApp) - phba->lpfc_injerr_wapp_cnt = (uint32_t)tmp; - else if (dent == phba->debug_writeRef) - phba->lpfc_injerr_wref_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readGuard) - phba->lpfc_injerr_rgrd_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readApp) - phba->lpfc_injerr_rapp_cnt = (uint32_t)tmp; - else if (dent == phba->debug_readRef) - phba->lpfc_injerr_rref_cnt = (uint32_t)tmp; - else if (dent == phba->debug_InjErrLBA) - phba->lpfc_injerr_lba = (sector_t)tmp; - else if (dent == phba->debug_InjErrNPortID) - phba->lpfc_injerr_nportid = (uint32_t)(tmp & Mask_DID); - else if (dent == phba->debug_InjErrWWPN) { - tmp = cpu_to_be64(tmp); - memcpy(&phba->lpfc_injerr_wwpn, &tmp, sizeof(struct lpfc_name)); - } else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0548 Unknown debugfs error injection entry\n"); - - return nbytes; -} - -static int -lpfc_debugfs_dif_err_release(struct inode *inode, struct file *file) -{ - return 0; -} - -/** - * lpfc_debugfs_nodelist_open - Open the nodelist debugfs file - * @inode: The inode pointer that contains a vport pointer. - * @file: The file pointer to attach the log output. - * - * Description: - * This routine is the entry point for the debugfs open file operation. It gets - * the vport from the i_private field in @inode, allocates the necessary buffer - * for the log, fills the buffer from the in-memory log for this vport, and then - * returns a pointer to that log in the private_data field in @file. - * - * Returns: - * This function returns zero if successful. On error it will return an negative - * error value. - **/ -static int -lpfc_debugfs_nodelist_open(struct inode *inode, struct file *file) -{ - struct lpfc_vport *vport = inode->i_private; - struct lpfc_debug *debug; - int rc = -ENOMEM; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - goto out; - - /* Round to page boundary */ - debug->buffer = kmalloc(LPFC_NODELIST_SIZE, GFP_KERNEL); - if (!debug->buffer) { - kfree(debug); - goto out; - } - - debug->len = lpfc_debugfs_nodelist_data(vport, debug->buffer, - LPFC_NODELIST_SIZE); - file->private_data = debug; - - rc = 0; -out: - return rc; -} - -/** - * lpfc_debugfs_lseek - Seek through a debugfs file - * @file: The file pointer to seek through. - * @off: The offset to seek to or the amount to seek by. - * @whence: Indicates how to seek. - * - * Description: - * This routine is the entry point for the debugfs lseek file operation. The - * @whence parameter indicates whether @off is the offset to directly seek to, - * or if it is a value to seek forward or reverse by. This function figures out - * what the new offset of the debugfs file will be and assigns that value to the - * f_pos field of @file. - * - * Returns: - * This function returns the new offset if successful and returns a negative - * error if unable to process the seek. - **/ -static loff_t -lpfc_debugfs_lseek(struct file *file, loff_t off, int whence) -{ - struct lpfc_debug *debug; - loff_t pos = -1; - - debug = file->private_data; - - switch (whence) { - case 0: - pos = off; - break; - case 1: - pos = file->f_pos + off; - break; - case 2: - pos = debug->len - off; - } - return (pos < 0 || pos > debug->len) ? -EINVAL : (file->f_pos = pos); -} - -/** - * lpfc_debugfs_read - Read a debugfs file - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from from the buffer indicated in the private_data - * field of @file. It will start reading at @ppos and copy up to @nbytes of - * data to @buf. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_debugfs_read(struct file *file, char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - - return simple_read_from_buffer(buf, nbytes, ppos, debug->buffer, - debug->len); -} - -/** - * lpfc_debugfs_release - Release the buffer used to store debugfs file data - * @inode: The inode pointer that contains a vport pointer. (unused) - * @file: The file pointer that contains the buffer to release. - * - * Description: - * This routine frees the buffer that was allocated when the debugfs file was - * opened. - * - * Returns: - * This function returns zero. - **/ -static int -lpfc_debugfs_release(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug = file->private_data; - - kfree(debug->buffer); - kfree(debug); - - return 0; -} - -static int -lpfc_debugfs_dumpDataDif_release(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug = file->private_data; - - debug->buffer = NULL; - kfree(debug); - - return 0; -} - -/* - * --------------------------------- - * iDiag debugfs file access methods - * --------------------------------- - * - * All access methods are through the proper SLI4 PCI function's debugfs - * iDiag directory: - * - * /sys/kernel/debug/lpfc/fn<#>/iDiag - */ - -/** - * lpfc_idiag_cmd_get - Get and parse idiag debugfs comands from user space - * @buf: The pointer to the user space buffer. - * @nbytes: The number of bytes in the user space buffer. - * @idiag_cmd: pointer to the idiag command struct. - * - * This routine reads data from debugfs user space buffer and parses the - * buffer for getting the idiag command and arguments. The while space in - * between the set of data is used as the parsing separator. - * - * This routine returns 0 when successful, it returns proper error code - * back to the user space in error conditions. - */ -static int lpfc_idiag_cmd_get(const char __user *buf, size_t nbytes, - struct lpfc_idiag_cmd *idiag_cmd) -{ - char mybuf[64]; - char *pbuf, *step_str; - int i; - size_t bsize; - - /* Protect copy from user */ - if (!access_ok(VERIFY_READ, buf, nbytes)) - return -EFAULT; - - memset(mybuf, 0, sizeof(mybuf)); - memset(idiag_cmd, 0, sizeof(*idiag_cmd)); - bsize = min(nbytes, (sizeof(mybuf)-1)); - - if (copy_from_user(mybuf, buf, bsize)) - return -EFAULT; - pbuf = &mybuf[0]; - step_str = strsep(&pbuf, "\t "); - - /* The opcode must present */ - if (!step_str) - return -EINVAL; - - idiag_cmd->opcode = simple_strtol(step_str, NULL, 0); - if (idiag_cmd->opcode == 0) - return -EINVAL; - - for (i = 0; i < LPFC_IDIAG_CMD_DATA_SIZE; i++) { - step_str = strsep(&pbuf, "\t "); - if (!step_str) - return i; - idiag_cmd->data[i] = simple_strtol(step_str, NULL, 0); - } - return i; -} - -/** - * lpfc_idiag_open - idiag open debugfs - * @inode: The inode pointer that contains a pointer to phba. - * @file: The file pointer to attach the file operation. - * - * Description: - * This routine is the entry point for the debugfs open file operation. It - * gets the reference to phba from the i_private field in @inode, it then - * allocates buffer for the file operation, performs the necessary PCI config - * space read into the allocated buffer according to the idiag user command - * setup, and then returns a pointer to buffer in the private_data field in - * @file. - * - * Returns: - * This function returns zero if successful. On error it will return an - * negative error value. - **/ -static int -lpfc_idiag_open(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug; - - debug = kmalloc(sizeof(*debug), GFP_KERNEL); - if (!debug) - return -ENOMEM; - - debug->i_private = inode->i_private; - debug->buffer = NULL; - file->private_data = debug; - - return 0; -} - -/** - * lpfc_idiag_release - Release idiag access file operation - * @inode: The inode pointer that contains a vport pointer. (unused) - * @file: The file pointer that contains the buffer to release. - * - * Description: - * This routine is the generic release routine for the idiag access file - * operation, it frees the buffer that was allocated when the debugfs file - * was opened. - * - * Returns: - * This function returns zero. - **/ -static int -lpfc_idiag_release(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug = file->private_data; - - /* Free the buffers to the file operation */ - kfree(debug->buffer); - kfree(debug); - - return 0; -} - -/** - * lpfc_idiag_cmd_release - Release idiag cmd access file operation - * @inode: The inode pointer that contains a vport pointer. (unused) - * @file: The file pointer that contains the buffer to release. - * - * Description: - * This routine frees the buffer that was allocated when the debugfs file - * was opened. It also reset the fields in the idiag command struct in the - * case of command for write operation. - * - * Returns: - * This function returns zero. - **/ -static int -lpfc_idiag_cmd_release(struct inode *inode, struct file *file) -{ - struct lpfc_debug *debug = file->private_data; - - if (debug->op == LPFC_IDIAG_OP_WR) { - switch (idiag.cmd.opcode) { - case LPFC_IDIAG_CMD_PCICFG_WR: - case LPFC_IDIAG_CMD_PCICFG_ST: - case LPFC_IDIAG_CMD_PCICFG_CL: - case LPFC_IDIAG_CMD_QUEACC_WR: - case LPFC_IDIAG_CMD_QUEACC_ST: - case LPFC_IDIAG_CMD_QUEACC_CL: - memset(&idiag, 0, sizeof(idiag)); - break; - default: - break; - } - } - - /* Free the buffers to the file operation */ - kfree(debug->buffer); - kfree(debug); - - return 0; -} - -/** - * lpfc_idiag_pcicfg_read - idiag debugfs read pcicfg - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from the @phba pci config space according to the - * idiag command, and copies to user @buf. Depending on the PCI config space - * read command setup, it does either a single register read of a byte - * (8 bits), a word (16 bits), or a dword (32 bits) or browsing through all - * registers from the 4K extended PCI config space. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_idiag_pcicfg_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - int offset_label, offset, len = 0, index = LPFC_PCI_CFG_RD_SIZE; - int where, count; - char *pbuffer; - struct pci_dev *pdev; - uint32_t u32val; - uint16_t u16val; - uint8_t u8val; - - pdev = phba->pcidev; - if (!pdev) - return 0; - - /* This is a user read operation */ - debug->op = LPFC_IDIAG_OP_RD; - - if (!debug->buffer) - debug->buffer = kmalloc(LPFC_PCI_CFG_SIZE, GFP_KERNEL); - if (!debug->buffer) - return 0; - pbuffer = debug->buffer; - - if (*ppos) - return 0; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { - where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; - count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; - } else - return 0; - - /* Read single PCI config space register */ - switch (count) { - case SIZE_U8: /* byte (8 bits) */ - pci_read_config_byte(pdev, where, &u8val); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, - "%03x: %02x\n", where, u8val); - break; - case SIZE_U16: /* word (16 bits) */ - pci_read_config_word(pdev, where, &u16val); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, - "%03x: %04x\n", where, u16val); - break; - case SIZE_U32: /* double word (32 bits) */ - pci_read_config_dword(pdev, where, &u32val); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, - "%03x: %08x\n", where, u32val); - break; - case LPFC_PCI_CFG_BROWSE: /* browse all */ - goto pcicfg_browse; - break; - default: - /* illegal count */ - len = 0; - break; - } - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); - -pcicfg_browse: - - /* Browse all PCI config space registers */ - offset_label = idiag.offset.last_rd; - offset = offset_label; - - /* Read PCI config space */ - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, - "%03x: ", offset_label); - while (index > 0) { - pci_read_config_dword(pdev, offset, &u32val); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, - "%08x ", u32val); - offset += sizeof(uint32_t); - if (offset >= LPFC_PCI_CFG_SIZE) { - len += snprintf(pbuffer+len, - LPFC_PCI_CFG_SIZE-len, "\n"); - break; - } - index -= sizeof(uint32_t); - if (!index) - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, - "\n"); - else if (!(index % (8 * sizeof(uint32_t)))) { - offset_label += (8 * sizeof(uint32_t)); - len += snprintf(pbuffer+len, LPFC_PCI_CFG_SIZE-len, - "\n%03x: ", offset_label); - } - } - - /* Set up the offset for next portion of pci cfg read */ - if (index == 0) { - idiag.offset.last_rd += LPFC_PCI_CFG_RD_SIZE; - if (idiag.offset.last_rd >= LPFC_PCI_CFG_SIZE) - idiag.offset.last_rd = 0; - } else - idiag.offset.last_rd = 0; - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); -} - -/** - * lpfc_idiag_pcicfg_write - Syntax check and set up idiag pcicfg commands - * @file: The file pointer to read from. - * @buf: The buffer to copy the user data from. - * @nbytes: The number of bytes to get. - * @ppos: The position in the file to start reading from. - * - * This routine get the debugfs idiag command struct from user space and - * then perform the syntax check for PCI config space read or write command - * accordingly. In the case of PCI config space read command, it sets up - * the command in the idiag command struct for the debugfs read operation. - * In the case of PCI config space write operation, it executes the write - * operation into the PCI config space accordingly. - * - * It returns the @nbytges passing in from debugfs user space when successful. - * In case of error conditions, it returns proper error code back to the user - * space. - */ -static ssize_t -lpfc_idiag_pcicfg_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - uint32_t where, value, count; - uint32_t u32val; - uint16_t u16val; - uint8_t u8val; - struct pci_dev *pdev; - int rc; - - pdev = phba->pcidev; - if (!pdev) - return -EFAULT; - - /* This is a user write operation */ - debug->op = LPFC_IDIAG_OP_WR; - - rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc < 0) - return rc; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_RD) { - /* Sanity check on PCI config read command line arguments */ - if (rc != LPFC_PCI_CFG_RD_CMD_ARG) - goto error_out; - /* Read command from PCI config space, set up command fields */ - where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; - count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; - if (count == LPFC_PCI_CFG_BROWSE) { - if (where % sizeof(uint32_t)) - goto error_out; - /* Starting offset to browse */ - idiag.offset.last_rd = where; - } else if ((count != sizeof(uint8_t)) && - (count != sizeof(uint16_t)) && - (count != sizeof(uint32_t))) - goto error_out; - if (count == sizeof(uint8_t)) { - if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t)) - goto error_out; - if (where % sizeof(uint8_t)) - goto error_out; - } - if (count == sizeof(uint16_t)) { - if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t)) - goto error_out; - if (where % sizeof(uint16_t)) - goto error_out; - } - if (count == sizeof(uint32_t)) { - if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t)) - goto error_out; - if (where % sizeof(uint32_t)) - goto error_out; - } - } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR || - idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST || - idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { - /* Sanity check on PCI config write command line arguments */ - if (rc != LPFC_PCI_CFG_WR_CMD_ARG) - goto error_out; - /* Write command to PCI config space, read-modify-write */ - where = idiag.cmd.data[IDIAG_PCICFG_WHERE_INDX]; - count = idiag.cmd.data[IDIAG_PCICFG_COUNT_INDX]; - value = idiag.cmd.data[IDIAG_PCICFG_VALUE_INDX]; - /* Sanity checks */ - if ((count != sizeof(uint8_t)) && - (count != sizeof(uint16_t)) && - (count != sizeof(uint32_t))) - goto error_out; - if (count == sizeof(uint8_t)) { - if (where > LPFC_PCI_CFG_SIZE - sizeof(uint8_t)) - goto error_out; - if (where % sizeof(uint8_t)) - goto error_out; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR) - pci_write_config_byte(pdev, where, - (uint8_t)value); - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) { - rc = pci_read_config_byte(pdev, where, &u8val); - if (!rc) { - u8val |= (uint8_t)value; - pci_write_config_byte(pdev, where, - u8val); - } - } - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { - rc = pci_read_config_byte(pdev, where, &u8val); - if (!rc) { - u8val &= (uint8_t)(~value); - pci_write_config_byte(pdev, where, - u8val); - } - } - } - if (count == sizeof(uint16_t)) { - if (where > LPFC_PCI_CFG_SIZE - sizeof(uint16_t)) - goto error_out; - if (where % sizeof(uint16_t)) - goto error_out; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR) - pci_write_config_word(pdev, where, - (uint16_t)value); - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) { - rc = pci_read_config_word(pdev, where, &u16val); - if (!rc) { - u16val |= (uint16_t)value; - pci_write_config_word(pdev, where, - u16val); - } - } - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { - rc = pci_read_config_word(pdev, where, &u16val); - if (!rc) { - u16val &= (uint16_t)(~value); - pci_write_config_word(pdev, where, - u16val); - } - } - } - if (count == sizeof(uint32_t)) { - if (where > LPFC_PCI_CFG_SIZE - sizeof(uint32_t)) - goto error_out; - if (where % sizeof(uint32_t)) - goto error_out; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_WR) - pci_write_config_dword(pdev, where, value); - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_ST) { - rc = pci_read_config_dword(pdev, where, - &u32val); - if (!rc) { - u32val |= value; - pci_write_config_dword(pdev, where, - u32val); - } - } - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_PCICFG_CL) { - rc = pci_read_config_dword(pdev, where, - &u32val); - if (!rc) { - u32val &= ~value; - pci_write_config_dword(pdev, where, - u32val); - } - } - } - } else - /* All other opecodes are illegal for now */ - goto error_out; - - return nbytes; -error_out: - memset(&idiag, 0, sizeof(idiag)); - return -EINVAL; -} - -/** - * lpfc_idiag_baracc_read - idiag debugfs pci bar access read - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from the @phba pci bar memory mapped space - * according to the idiag command, and copies to user @buf. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_idiag_baracc_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - int offset_label, offset, offset_run, len = 0, index; - int bar_num, acc_range, bar_size; - char *pbuffer; - void __iomem *mem_mapped_bar; - uint32_t if_type; - struct pci_dev *pdev; - uint32_t u32val; - - pdev = phba->pcidev; - if (!pdev) - return 0; - - /* This is a user read operation */ - debug->op = LPFC_IDIAG_OP_RD; - - if (!debug->buffer) - debug->buffer = kmalloc(LPFC_PCI_BAR_RD_BUF_SIZE, GFP_KERNEL); - if (!debug->buffer) - return 0; - pbuffer = debug->buffer; - - if (*ppos) - return 0; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) { - bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX]; - offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX]; - acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX]; - bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX]; - } else - return 0; - - if (acc_range == 0) - return 0; - - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { - if (bar_num == IDIAG_BARACC_BAR_0) - mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; - else if (bar_num == IDIAG_BARACC_BAR_1) - mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p; - else if (bar_num == IDIAG_BARACC_BAR_2) - mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p; - else - return 0; - } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { - if (bar_num == IDIAG_BARACC_BAR_0) - mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; - else - return 0; - } else - return 0; - - /* Read single PCI bar space register */ - if (acc_range == SINGLE_WORD) { - offset_run = offset; - u32val = readl(mem_mapped_bar + offset_run); - len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, - "%05x: %08x\n", offset_run, u32val); - } else - goto baracc_browse; - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); - -baracc_browse: - - /* Browse all PCI bar space registers */ - offset_label = idiag.offset.last_rd; - offset_run = offset_label; - - /* Read PCI bar memory mapped space */ - len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, - "%05x: ", offset_label); - index = LPFC_PCI_BAR_RD_SIZE; - while (index > 0) { - u32val = readl(mem_mapped_bar + offset_run); - len += snprintf(pbuffer+len, LPFC_PCI_BAR_RD_BUF_SIZE-len, - "%08x ", u32val); - offset_run += sizeof(uint32_t); - if (acc_range == LPFC_PCI_BAR_BROWSE) { - if (offset_run >= bar_size) { - len += snprintf(pbuffer+len, - LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); - break; - } - } else { - if (offset_run >= offset + - (acc_range * sizeof(uint32_t))) { - len += snprintf(pbuffer+len, - LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); - break; - } - } - index -= sizeof(uint32_t); - if (!index) - len += snprintf(pbuffer+len, - LPFC_PCI_BAR_RD_BUF_SIZE-len, "\n"); - else if (!(index % (8 * sizeof(uint32_t)))) { - offset_label += (8 * sizeof(uint32_t)); - len += snprintf(pbuffer+len, - LPFC_PCI_BAR_RD_BUF_SIZE-len, - "\n%05x: ", offset_label); - } - } - - /* Set up the offset for next portion of pci bar read */ - if (index == 0) { - idiag.offset.last_rd += LPFC_PCI_BAR_RD_SIZE; - if (acc_range == LPFC_PCI_BAR_BROWSE) { - if (idiag.offset.last_rd >= bar_size) - idiag.offset.last_rd = 0; - } else { - if (offset_run >= offset + - (acc_range * sizeof(uint32_t))) - idiag.offset.last_rd = offset; - } - } else { - if (acc_range == LPFC_PCI_BAR_BROWSE) - idiag.offset.last_rd = 0; - else - idiag.offset.last_rd = offset; - } - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); -} - -/** - * lpfc_idiag_baracc_write - Syntax check and set up idiag bar access commands - * @file: The file pointer to read from. - * @buf: The buffer to copy the user data from. - * @nbytes: The number of bytes to get. - * @ppos: The position in the file to start reading from. - * - * This routine get the debugfs idiag command struct from user space and - * then perform the syntax check for PCI bar memory mapped space read or - * write command accordingly. In the case of PCI bar memory mapped space - * read command, it sets up the command in the idiag command struct for - * the debugfs read operation. In the case of PCI bar memorpy mapped space - * write operation, it executes the write operation into the PCI bar memory - * mapped space accordingly. - * - * It returns the @nbytges passing in from debugfs user space when successful. - * In case of error conditions, it returns proper error code back to the user - * space. - */ -static ssize_t -lpfc_idiag_baracc_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - uint32_t bar_num, bar_size, offset, value, acc_range; - struct pci_dev *pdev; - void __iomem *mem_mapped_bar; - uint32_t if_type; - uint32_t u32val; - int rc; - - pdev = phba->pcidev; - if (!pdev) - return -EFAULT; - - /* This is a user write operation */ - debug->op = LPFC_IDIAG_OP_WR; - - rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc < 0) - return rc; - - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - bar_num = idiag.cmd.data[IDIAG_BARACC_BAR_NUM_INDX]; - - if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { - if ((bar_num != IDIAG_BARACC_BAR_0) && - (bar_num != IDIAG_BARACC_BAR_1) && - (bar_num != IDIAG_BARACC_BAR_2)) - goto error_out; - } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { - if (bar_num != IDIAG_BARACC_BAR_0) - goto error_out; - } else - goto error_out; - - if (if_type == LPFC_SLI_INTF_IF_TYPE_0) { - if (bar_num == IDIAG_BARACC_BAR_0) { - idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = - LPFC_PCI_IF0_BAR0_SIZE; - mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; - } else if (bar_num == IDIAG_BARACC_BAR_1) { - idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = - LPFC_PCI_IF0_BAR1_SIZE; - mem_mapped_bar = phba->sli4_hba.ctrl_regs_memmap_p; - } else if (bar_num == IDIAG_BARACC_BAR_2) { - idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = - LPFC_PCI_IF0_BAR2_SIZE; - mem_mapped_bar = phba->sli4_hba.drbl_regs_memmap_p; - } else - goto error_out; - } else if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { - if (bar_num == IDIAG_BARACC_BAR_0) { - idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX] = - LPFC_PCI_IF2_BAR0_SIZE; - mem_mapped_bar = phba->sli4_hba.conf_regs_memmap_p; - } else - goto error_out; - } else - goto error_out; - - offset = idiag.cmd.data[IDIAG_BARACC_OFF_SET_INDX]; - if (offset % sizeof(uint32_t)) - goto error_out; - - bar_size = idiag.cmd.data[IDIAG_BARACC_BAR_SZE_INDX]; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_RD) { - /* Sanity check on PCI config read command line arguments */ - if (rc != LPFC_PCI_BAR_RD_CMD_ARG) - goto error_out; - acc_range = idiag.cmd.data[IDIAG_BARACC_ACC_MOD_INDX]; - if (acc_range == LPFC_PCI_BAR_BROWSE) { - if (offset > bar_size - sizeof(uint32_t)) - goto error_out; - /* Starting offset to browse */ - idiag.offset.last_rd = offset; - } else if (acc_range > SINGLE_WORD) { - if (offset + acc_range * sizeof(uint32_t) > bar_size) - goto error_out; - /* Starting offset to browse */ - idiag.offset.last_rd = offset; - } else if (acc_range != SINGLE_WORD) - goto error_out; - } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR || - idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST || - idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) { - /* Sanity check on PCI bar write command line arguments */ - if (rc != LPFC_PCI_BAR_WR_CMD_ARG) - goto error_out; - /* Write command to PCI bar space, read-modify-write */ - acc_range = SINGLE_WORD; - value = idiag.cmd.data[IDIAG_BARACC_REG_VAL_INDX]; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_WR) { - writel(value, mem_mapped_bar + offset); - readl(mem_mapped_bar + offset); - } - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_ST) { - u32val = readl(mem_mapped_bar + offset); - u32val |= value; - writel(u32val, mem_mapped_bar + offset); - readl(mem_mapped_bar + offset); - } - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_BARACC_CL) { - u32val = readl(mem_mapped_bar + offset); - u32val &= ~value; - writel(u32val, mem_mapped_bar + offset); - readl(mem_mapped_bar + offset); - } - } else - /* All other opecodes are illegal for now */ - goto error_out; - - return nbytes; -error_out: - memset(&idiag, 0, sizeof(idiag)); - return -EINVAL; -} - -/** - * lpfc_idiag_queinfo_read - idiag debugfs read queue information - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from the @phba SLI4 PCI function queue information, - * and copies to user @buf. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_idiag_queinfo_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - int len = 0, fcp_qidx; - char *pbuffer; - - if (!debug->buffer) - debug->buffer = kmalloc(LPFC_QUE_INFO_GET_BUF_SIZE, GFP_KERNEL); - if (!debug->buffer) - return 0; - pbuffer = debug->buffer; - - if (*ppos) - return 0; - - /* Get slow-path event queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path EQ information:\n"); - if (phba->sli4_hba.sp_eq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tEQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.sp_eq->queue_id, - phba->sli4_hba.sp_eq->entry_count, - phba->sli4_hba.sp_eq->entry_size, - phba->sli4_hba.sp_eq->host_index, - phba->sli4_hba.sp_eq->hba_index); - } - - /* Get fast-path event queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path EQ information:\n"); - if (phba->sli4_hba.fp_eq) { - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; - fcp_qidx++) { - if (phba->sli4_hba.fp_eq[fcp_qidx]) { - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tEQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.fp_eq[fcp_qidx]->queue_id, - phba->sli4_hba.fp_eq[fcp_qidx]->entry_count, - phba->sli4_hba.fp_eq[fcp_qidx]->entry_size, - phba->sli4_hba.fp_eq[fcp_qidx]->host_index, - phba->sli4_hba.fp_eq[fcp_qidx]->hba_index); - } - } - } - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); - - /* Get mailbox complete queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path MBX CQ information:\n"); - if (phba->sli4_hba.mbx_cq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated EQID[%02d]:\n", - phba->sli4_hba.mbx_cq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tCQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.mbx_cq->queue_id, - phba->sli4_hba.mbx_cq->entry_count, - phba->sli4_hba.mbx_cq->entry_size, - phba->sli4_hba.mbx_cq->host_index, - phba->sli4_hba.mbx_cq->hba_index); - } - - /* Get slow-path complete queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path ELS CQ information:\n"); - if (phba->sli4_hba.els_cq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated EQID[%02d]:\n", - phba->sli4_hba.els_cq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tCQID [%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.els_cq->queue_id, - phba->sli4_hba.els_cq->entry_count, - phba->sli4_hba.els_cq->entry_size, - phba->sli4_hba.els_cq->host_index, - phba->sli4_hba.els_cq->hba_index); - } - - /* Get fast-path complete queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path FCP CQ information:\n"); - fcp_qidx = 0; - if (phba->sli4_hba.fcp_cq) { - do { - if (phba->sli4_hba.fcp_cq[fcp_qidx]) { - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated EQID[%02d]:\n", - phba->sli4_hba.fcp_cq[fcp_qidx]->assoc_qid); - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tCQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.fcp_cq[fcp_qidx]->queue_id, - phba->sli4_hba.fcp_cq[fcp_qidx]->entry_count, - phba->sli4_hba.fcp_cq[fcp_qidx]->entry_size, - phba->sli4_hba.fcp_cq[fcp_qidx]->host_index, - phba->sli4_hba.fcp_cq[fcp_qidx]->hba_index); - } - } while (++fcp_qidx < phba->cfg_fcp_eq_count); - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); - } - - /* Get mailbox queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path MBX MQ information:\n"); - if (phba->sli4_hba.mbx_wq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated CQID[%02d]:\n", - phba->sli4_hba.mbx_wq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tWQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.mbx_wq->queue_id, - phba->sli4_hba.mbx_wq->entry_count, - phba->sli4_hba.mbx_wq->entry_size, - phba->sli4_hba.mbx_wq->host_index, - phba->sli4_hba.mbx_wq->hba_index); - } - - /* Get slow-path work queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path ELS WQ information:\n"); - if (phba->sli4_hba.els_wq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated CQID[%02d]:\n", - phba->sli4_hba.els_wq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tWQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n\n", - phba->sli4_hba.els_wq->queue_id, - phba->sli4_hba.els_wq->entry_count, - phba->sli4_hba.els_wq->entry_size, - phba->sli4_hba.els_wq->host_index, - phba->sli4_hba.els_wq->hba_index); - } - - /* Get fast-path work queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Fast-path FCP WQ information:\n"); - if (phba->sli4_hba.fcp_wq) { - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; - fcp_qidx++) { - if (!phba->sli4_hba.fcp_wq[fcp_qidx]) - continue; - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated CQID[%02d]:\n", - phba->sli4_hba.fcp_wq[fcp_qidx]->assoc_qid); - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tWQID[%02d], " - "QE-COUNT[%04d], WQE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.fcp_wq[fcp_qidx]->queue_id, - phba->sli4_hba.fcp_wq[fcp_qidx]->entry_count, - phba->sli4_hba.fcp_wq[fcp_qidx]->entry_size, - phba->sli4_hba.fcp_wq[fcp_qidx]->host_index, - phba->sli4_hba.fcp_wq[fcp_qidx]->hba_index); - } - len += snprintf(pbuffer+len, - LPFC_QUE_INFO_GET_BUF_SIZE-len, "\n"); - } - - /* Get receive queue information */ - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Slow-path RQ information:\n"); - if (phba->sli4_hba.hdr_rq && phba->sli4_hba.dat_rq) { - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "Associated CQID[%02d]:\n", - phba->sli4_hba.hdr_rq->assoc_qid); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tHQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.hdr_rq->queue_id, - phba->sli4_hba.hdr_rq->entry_count, - phba->sli4_hba.hdr_rq->entry_size, - phba->sli4_hba.hdr_rq->host_index, - phba->sli4_hba.hdr_rq->hba_index); - len += snprintf(pbuffer+len, LPFC_QUE_INFO_GET_BUF_SIZE-len, - "\tDQID[%02d], " - "QE-COUNT[%04d], QE-SIZE[%04d], " - "HOST-INDEX[%04d], PORT-INDEX[%04d]\n", - phba->sli4_hba.dat_rq->queue_id, - phba->sli4_hba.dat_rq->entry_count, - phba->sli4_hba.dat_rq->entry_size, - phba->sli4_hba.dat_rq->host_index, - phba->sli4_hba.dat_rq->hba_index); - } - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); -} - -/** - * lpfc_idiag_que_param_check - queue access command parameter sanity check - * @q: The pointer to queue structure. - * @index: The index into a queue entry. - * @count: The number of queue entries to access. - * - * Description: - * The routine performs sanity check on device queue access method commands. - * - * Returns: - * This function returns -EINVAL when fails the sanity check, otherwise, it - * returns 0. - **/ -static int -lpfc_idiag_que_param_check(struct lpfc_queue *q, int index, int count) -{ - /* Only support single entry read or browsing */ - if ((count != 1) && (count != LPFC_QUE_ACC_BROWSE)) - return -EINVAL; - if (index > q->entry_count - 1) - return -EINVAL; - return 0; -} - -/** - * lpfc_idiag_queacc_read_qe - read a single entry from the given queue index - * @pbuffer: The pointer to buffer to copy the read data into. - * @pque: The pointer to the queue to be read. - * @index: The index into the queue entry. - * - * Description: - * This routine reads out a single entry from the given queue's index location - * and copies it into the buffer provided. - * - * Returns: - * This function returns 0 when it fails, otherwise, it returns the length of - * the data read into the buffer provided. - **/ -static int -lpfc_idiag_queacc_read_qe(char *pbuffer, int len, struct lpfc_queue *pque, - uint32_t index) -{ - int offset, esize; - uint32_t *pentry; - - if (!pbuffer || !pque) - return 0; - - esize = pque->entry_size; - len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, - "QE-INDEX[%04d]:\n", index); - - offset = 0; - pentry = pque->qe[index].address; - while (esize > 0) { - len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, - "%08x ", *pentry); - pentry++; - offset += sizeof(uint32_t); - esize -= sizeof(uint32_t); - if (esize > 0 && !(offset % (4 * sizeof(uint32_t)))) - len += snprintf(pbuffer+len, - LPFC_QUE_ACC_BUF_SIZE-len, "\n"); - } - len += snprintf(pbuffer+len, LPFC_QUE_ACC_BUF_SIZE-len, "\n"); - - return len; -} - -/** - * lpfc_idiag_queacc_read - idiag debugfs read port queue - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from the @phba device queue memory according to the - * idiag command, and copies to user @buf. Depending on the queue dump read - * command setup, it does either a single queue entry read or browing through - * all entries of the queue. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_idiag_queacc_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - uint32_t last_index, index, count; - struct lpfc_queue *pque = NULL; - char *pbuffer; - int len = 0; - - /* This is a user read operation */ - debug->op = LPFC_IDIAG_OP_RD; - - if (!debug->buffer) - debug->buffer = kmalloc(LPFC_QUE_ACC_BUF_SIZE, GFP_KERNEL); - if (!debug->buffer) - return 0; - pbuffer = debug->buffer; - - if (*ppos) - return 0; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { - index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX]; - count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX]; - pque = (struct lpfc_queue *)idiag.ptr_private; - } else - return 0; - - /* Browse the queue starting from index */ - if (count == LPFC_QUE_ACC_BROWSE) - goto que_browse; - - /* Read a single entry from the queue */ - len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); - -que_browse: - - /* Browse all entries from the queue */ - last_index = idiag.offset.last_rd; - index = last_index; - - while (len < LPFC_QUE_ACC_SIZE - pque->entry_size) { - len = lpfc_idiag_queacc_read_qe(pbuffer, len, pque, index); - index++; - if (index > pque->entry_count - 1) - break; - } - - /* Set up the offset for next portion of pci cfg read */ - if (index > pque->entry_count - 1) - index = 0; - idiag.offset.last_rd = index; - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); -} - -/** - * lpfc_idiag_queacc_write - Syntax check and set up idiag queacc commands - * @file: The file pointer to read from. - * @buf: The buffer to copy the user data from. - * @nbytes: The number of bytes to get. - * @ppos: The position in the file to start reading from. - * - * This routine get the debugfs idiag command struct from user space and then - * perform the syntax check for port queue read (dump) or write (set) command - * accordingly. In the case of port queue read command, it sets up the command - * in the idiag command struct for the following debugfs read operation. In - * the case of port queue write operation, it executes the write operation - * into the port queue entry accordingly. - * - * It returns the @nbytges passing in from debugfs user space when successful. - * In case of error conditions, it returns proper error code back to the user - * space. - **/ -static ssize_t -lpfc_idiag_queacc_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - uint32_t qidx, quetp, queid, index, count, offset, value; - uint32_t *pentry; - struct lpfc_queue *pque; - int rc; - - /* This is a user write operation */ - debug->op = LPFC_IDIAG_OP_WR; - - rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc < 0) - return rc; - - /* Get and sanity check on command feilds */ - quetp = idiag.cmd.data[IDIAG_QUEACC_QUETP_INDX]; - queid = idiag.cmd.data[IDIAG_QUEACC_QUEID_INDX]; - index = idiag.cmd.data[IDIAG_QUEACC_INDEX_INDX]; - count = idiag.cmd.data[IDIAG_QUEACC_COUNT_INDX]; - offset = idiag.cmd.data[IDIAG_QUEACC_OFFST_INDX]; - value = idiag.cmd.data[IDIAG_QUEACC_VALUE_INDX]; - - /* Sanity check on command line arguments */ - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || - idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || - idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { - if (rc != LPFC_QUE_ACC_WR_CMD_ARG) - goto error_out; - if (count != 1) - goto error_out; - } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { - if (rc != LPFC_QUE_ACC_RD_CMD_ARG) - goto error_out; - } else - goto error_out; - - switch (quetp) { - case LPFC_IDIAG_EQ: - /* Slow-path event queue */ - if (phba->sli4_hba.sp_eq && - phba->sli4_hba.sp_eq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.sp_eq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.sp_eq; - goto pass_check; - } - /* Fast-path event queue */ - if (phba->sli4_hba.fp_eq) { - for (qidx = 0; qidx < phba->cfg_fcp_eq_count; qidx++) { - if (phba->sli4_hba.fp_eq[qidx] && - phba->sli4_hba.fp_eq[qidx]->queue_id == - queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.fp_eq[qidx], - index, count); - if (rc) - goto error_out; - idiag.ptr_private = - phba->sli4_hba.fp_eq[qidx]; - goto pass_check; - } - } - } - goto error_out; - break; - case LPFC_IDIAG_CQ: - /* MBX complete queue */ - if (phba->sli4_hba.mbx_cq && - phba->sli4_hba.mbx_cq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.mbx_cq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.mbx_cq; - goto pass_check; - } - /* ELS complete queue */ - if (phba->sli4_hba.els_cq && - phba->sli4_hba.els_cq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.els_cq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.els_cq; - goto pass_check; - } - /* FCP complete queue */ - if (phba->sli4_hba.fcp_cq) { - qidx = 0; - do { - if (phba->sli4_hba.fcp_cq[qidx] && - phba->sli4_hba.fcp_cq[qidx]->queue_id == - queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.fcp_cq[qidx], - index, count); - if (rc) - goto error_out; - idiag.ptr_private = - phba->sli4_hba.fcp_cq[qidx]; - goto pass_check; - } - } while (++qidx < phba->cfg_fcp_eq_count); - } - goto error_out; - break; - case LPFC_IDIAG_MQ: - /* MBX work queue */ - if (phba->sli4_hba.mbx_wq && - phba->sli4_hba.mbx_wq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.mbx_wq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.mbx_wq; - goto pass_check; - } - goto error_out; - break; - case LPFC_IDIAG_WQ: - /* ELS work queue */ - if (phba->sli4_hba.els_wq && - phba->sli4_hba.els_wq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.els_wq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.els_wq; - goto pass_check; - } - /* FCP work queue */ - if (phba->sli4_hba.fcp_wq) { - for (qidx = 0; qidx < phba->cfg_fcp_wq_count; qidx++) { - if (!phba->sli4_hba.fcp_wq[qidx]) - continue; - if (phba->sli4_hba.fcp_wq[qidx]->queue_id == - queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.fcp_wq[qidx], - index, count); - if (rc) - goto error_out; - idiag.ptr_private = - phba->sli4_hba.fcp_wq[qidx]; - goto pass_check; - } - } - } - goto error_out; - break; - case LPFC_IDIAG_RQ: - /* HDR queue */ - if (phba->sli4_hba.hdr_rq && - phba->sli4_hba.hdr_rq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.hdr_rq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.hdr_rq; - goto pass_check; - } - /* DAT queue */ - if (phba->sli4_hba.dat_rq && - phba->sli4_hba.dat_rq->queue_id == queid) { - /* Sanity check */ - rc = lpfc_idiag_que_param_check( - phba->sli4_hba.dat_rq, index, count); - if (rc) - goto error_out; - idiag.ptr_private = phba->sli4_hba.dat_rq; - goto pass_check; - } - goto error_out; - break; - default: - goto error_out; - break; - } - -pass_check: - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_RD) { - if (count == LPFC_QUE_ACC_BROWSE) - idiag.offset.last_rd = index; - } - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR || - idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST || - idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) { - /* Additional sanity checks on write operation */ - pque = (struct lpfc_queue *)idiag.ptr_private; - if (offset > pque->entry_size/sizeof(uint32_t) - 1) - goto error_out; - pentry = pque->qe[index].address; - pentry += offset; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_WR) - *pentry = value; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_ST) - *pentry |= value; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_QUEACC_CL) - *pentry &= ~value; - } - return nbytes; - -error_out: - /* Clean out command structure on command error out */ - memset(&idiag, 0, sizeof(idiag)); - return -EINVAL; -} - -/** - * lpfc_idiag_drbacc_read_reg - idiag debugfs read a doorbell register - * @phba: The pointer to hba structure. - * @pbuffer: The pointer to the buffer to copy the data to. - * @len: The lenght of bytes to copied. - * @drbregid: The id to doorbell registers. - * - * Description: - * This routine reads a doorbell register and copies its content to the - * user buffer pointed to by @pbuffer. - * - * Returns: - * This function returns the amount of data that was copied into @pbuffer. - **/ -static int -lpfc_idiag_drbacc_read_reg(struct lpfc_hba *phba, char *pbuffer, - int len, uint32_t drbregid) -{ - - if (!pbuffer) - return 0; - - switch (drbregid) { - case LPFC_DRB_EQCQ: - len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, - "EQCQ-DRB-REG: 0x%08x\n", - readl(phba->sli4_hba.EQCQDBregaddr)); - break; - case LPFC_DRB_MQ: - len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, - "MQ-DRB-REG: 0x%08x\n", - readl(phba->sli4_hba.MQDBregaddr)); - break; - case LPFC_DRB_WQ: - len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, - "WQ-DRB-REG: 0x%08x\n", - readl(phba->sli4_hba.WQDBregaddr)); - break; - case LPFC_DRB_RQ: - len += snprintf(pbuffer+len, LPFC_DRB_ACC_BUF_SIZE-len, - "RQ-DRB-REG: 0x%08x\n", - readl(phba->sli4_hba.RQDBregaddr)); - break; - default: - break; - } - - return len; -} - -/** - * lpfc_idiag_drbacc_read - idiag debugfs read port doorbell - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from the @phba device doorbell register according - * to the idiag command, and copies to user @buf. Depending on the doorbell - * register read command setup, it does either a single doorbell register - * read or dump all doorbell registers. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_idiag_drbacc_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - uint32_t drb_reg_id, i; - char *pbuffer; - int len = 0; - - /* This is a user read operation */ - debug->op = LPFC_IDIAG_OP_RD; - - if (!debug->buffer) - debug->buffer = kmalloc(LPFC_DRB_ACC_BUF_SIZE, GFP_KERNEL); - if (!debug->buffer) - return 0; - pbuffer = debug->buffer; - - if (*ppos) - return 0; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) - drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX]; - else - return 0; - - if (drb_reg_id == LPFC_DRB_ACC_ALL) - for (i = 1; i <= LPFC_DRB_MAX; i++) - len = lpfc_idiag_drbacc_read_reg(phba, - pbuffer, len, i); - else - len = lpfc_idiag_drbacc_read_reg(phba, - pbuffer, len, drb_reg_id); - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); -} - -/** - * lpfc_idiag_drbacc_write - Syntax check and set up idiag drbacc commands - * @file: The file pointer to read from. - * @buf: The buffer to copy the user data from. - * @nbytes: The number of bytes to get. - * @ppos: The position in the file to start reading from. - * - * This routine get the debugfs idiag command struct from user space and then - * perform the syntax check for port doorbell register read (dump) or write - * (set) command accordingly. In the case of port queue read command, it sets - * up the command in the idiag command struct for the following debugfs read - * operation. In the case of port doorbell register write operation, it - * executes the write operation into the port doorbell register accordingly. - * - * It returns the @nbytges passing in from debugfs user space when successful. - * In case of error conditions, it returns proper error code back to the user - * space. - **/ -static ssize_t -lpfc_idiag_drbacc_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - uint32_t drb_reg_id, value, reg_val = 0; - void __iomem *drb_reg; - int rc; - - /* This is a user write operation */ - debug->op = LPFC_IDIAG_OP_WR; - - rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc < 0) - return rc; - - /* Sanity check on command line arguments */ - drb_reg_id = idiag.cmd.data[IDIAG_DRBACC_REGID_INDX]; - value = idiag.cmd.data[IDIAG_DRBACC_VALUE_INDX]; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || - idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || - idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { - if (rc != LPFC_DRB_ACC_WR_CMD_ARG) - goto error_out; - if (drb_reg_id > LPFC_DRB_MAX) - goto error_out; - } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_RD) { - if (rc != LPFC_DRB_ACC_RD_CMD_ARG) - goto error_out; - if ((drb_reg_id > LPFC_DRB_MAX) && - (drb_reg_id != LPFC_DRB_ACC_ALL)) - goto error_out; - } else - goto error_out; - - /* Perform the write access operation */ - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR || - idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST || - idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { - switch (drb_reg_id) { - case LPFC_DRB_EQCQ: - drb_reg = phba->sli4_hba.EQCQDBregaddr; - break; - case LPFC_DRB_MQ: - drb_reg = phba->sli4_hba.MQDBregaddr; - break; - case LPFC_DRB_WQ: - drb_reg = phba->sli4_hba.WQDBregaddr; - break; - case LPFC_DRB_RQ: - drb_reg = phba->sli4_hba.RQDBregaddr; - break; - default: - goto error_out; - } - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_WR) - reg_val = value; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_ST) { - reg_val = readl(drb_reg); - reg_val |= value; - } - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_DRBACC_CL) { - reg_val = readl(drb_reg); - reg_val &= ~value; - } - writel(reg_val, drb_reg); - readl(drb_reg); /* flush */ - } - return nbytes; - -error_out: - /* Clean out command structure on command error out */ - memset(&idiag, 0, sizeof(idiag)); - return -EINVAL; -} - -/** - * lpfc_idiag_ctlacc_read_reg - idiag debugfs read a control registers - * @phba: The pointer to hba structure. - * @pbuffer: The pointer to the buffer to copy the data to. - * @len: The lenght of bytes to copied. - * @drbregid: The id to doorbell registers. - * - * Description: - * This routine reads a control register and copies its content to the - * user buffer pointed to by @pbuffer. - * - * Returns: - * This function returns the amount of data that was copied into @pbuffer. - **/ -static int -lpfc_idiag_ctlacc_read_reg(struct lpfc_hba *phba, char *pbuffer, - int len, uint32_t ctlregid) -{ - - if (!pbuffer) - return 0; - - switch (ctlregid) { - case LPFC_CTL_PORT_SEM: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, - "Port SemReg: 0x%08x\n", - readl(phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_SEM_OFFSET)); - break; - case LPFC_CTL_PORT_STA: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, - "Port StaReg: 0x%08x\n", - readl(phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_STA_OFFSET)); - break; - case LPFC_CTL_PORT_CTL: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, - "Port CtlReg: 0x%08x\n", - readl(phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_CTL_OFFSET)); - break; - case LPFC_CTL_PORT_ER1: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, - "Port Er1Reg: 0x%08x\n", - readl(phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_ER1_OFFSET)); - break; - case LPFC_CTL_PORT_ER2: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, - "Port Er2Reg: 0x%08x\n", - readl(phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_ER2_OFFSET)); - break; - case LPFC_CTL_PDEV_CTL: - len += snprintf(pbuffer+len, LPFC_CTL_ACC_BUF_SIZE-len, - "PDev CtlReg: 0x%08x\n", - readl(phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PDEV_CTL_OFFSET)); - break; - default: - break; - } - return len; -} - -/** - * lpfc_idiag_ctlacc_read - idiag debugfs read port and device control register - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from the @phba port and device registers according - * to the idiag command, and copies to user @buf. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_idiag_ctlacc_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - uint32_t ctl_reg_id, i; - char *pbuffer; - int len = 0; - - /* This is a user read operation */ - debug->op = LPFC_IDIAG_OP_RD; - - if (!debug->buffer) - debug->buffer = kmalloc(LPFC_CTL_ACC_BUF_SIZE, GFP_KERNEL); - if (!debug->buffer) - return 0; - pbuffer = debug->buffer; - - if (*ppos) - return 0; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) - ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX]; - else - return 0; - - if (ctl_reg_id == LPFC_CTL_ACC_ALL) - for (i = 1; i <= LPFC_CTL_MAX; i++) - len = lpfc_idiag_ctlacc_read_reg(phba, - pbuffer, len, i); - else - len = lpfc_idiag_ctlacc_read_reg(phba, - pbuffer, len, ctl_reg_id); - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); -} - -/** - * lpfc_idiag_ctlacc_write - Syntax check and set up idiag ctlacc commands - * @file: The file pointer to read from. - * @buf: The buffer to copy the user data from. - * @nbytes: The number of bytes to get. - * @ppos: The position in the file to start reading from. - * - * This routine get the debugfs idiag command struct from user space and then - * perform the syntax check for port and device control register read (dump) - * or write (set) command accordingly. - * - * It returns the @nbytges passing in from debugfs user space when successful. - * In case of error conditions, it returns proper error code back to the user - * space. - **/ -static ssize_t -lpfc_idiag_ctlacc_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - uint32_t ctl_reg_id, value, reg_val = 0; - void __iomem *ctl_reg; - int rc; - - /* This is a user write operation */ - debug->op = LPFC_IDIAG_OP_WR; - - rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc < 0) - return rc; - - /* Sanity check on command line arguments */ - ctl_reg_id = idiag.cmd.data[IDIAG_CTLACC_REGID_INDX]; - value = idiag.cmd.data[IDIAG_CTLACC_VALUE_INDX]; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR || - idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST || - idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { - if (rc != LPFC_CTL_ACC_WR_CMD_ARG) - goto error_out; - if (ctl_reg_id > LPFC_CTL_MAX) - goto error_out; - } else if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_RD) { - if (rc != LPFC_CTL_ACC_RD_CMD_ARG) - goto error_out; - if ((ctl_reg_id > LPFC_CTL_MAX) && - (ctl_reg_id != LPFC_CTL_ACC_ALL)) - goto error_out; - } else - goto error_out; - - /* Perform the write access operation */ - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR || - idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST || - idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { - switch (ctl_reg_id) { - case LPFC_CTL_PORT_SEM: - ctl_reg = phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_SEM_OFFSET; - break; - case LPFC_CTL_PORT_STA: - ctl_reg = phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_STA_OFFSET; - break; - case LPFC_CTL_PORT_CTL: - ctl_reg = phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_CTL_OFFSET; - break; - case LPFC_CTL_PORT_ER1: - ctl_reg = phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_ER1_OFFSET; - break; - case LPFC_CTL_PORT_ER2: - ctl_reg = phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_ER2_OFFSET; - break; - case LPFC_CTL_PDEV_CTL: - ctl_reg = phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PDEV_CTL_OFFSET; - break; - default: - goto error_out; - } - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_WR) - reg_val = value; - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_ST) { - reg_val = readl(ctl_reg); - reg_val |= value; - } - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_CTLACC_CL) { - reg_val = readl(ctl_reg); - reg_val &= ~value; - } - writel(reg_val, ctl_reg); - readl(ctl_reg); /* flush */ - } - return nbytes; - -error_out: - /* Clean out command structure on command error out */ - memset(&idiag, 0, sizeof(idiag)); - return -EINVAL; -} - -/** - * lpfc_idiag_mbxacc_get_setup - idiag debugfs get mailbox access setup - * @phba: Pointer to HBA context object. - * @pbuffer: Pointer to data buffer. - * - * Description: - * This routine gets the driver mailbox access debugfs setup information. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static int -lpfc_idiag_mbxacc_get_setup(struct lpfc_hba *phba, char *pbuffer) -{ - uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd; - int len = 0; - - mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; - mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; - mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; - mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; - - len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, - "mbx_dump_map: 0x%08x\n", mbx_dump_map); - len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, - "mbx_dump_cnt: %04d\n", mbx_dump_cnt); - len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, - "mbx_word_cnt: %04d\n", mbx_word_cnt); - len += snprintf(pbuffer+len, LPFC_MBX_ACC_BUF_SIZE-len, - "mbx_mbox_cmd: 0x%02x\n", mbx_mbox_cmd); - - return len; -} - -/** - * lpfc_idiag_mbxacc_read - idiag debugfs read on mailbox access - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from the @phba driver mailbox access debugfs setup - * information. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_idiag_mbxacc_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - char *pbuffer; - int len = 0; - - /* This is a user read operation */ - debug->op = LPFC_IDIAG_OP_RD; - - if (!debug->buffer) - debug->buffer = kmalloc(LPFC_MBX_ACC_BUF_SIZE, GFP_KERNEL); - if (!debug->buffer) - return 0; - pbuffer = debug->buffer; - - if (*ppos) - return 0; - - if ((idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) && - (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP)) - return 0; - - len = lpfc_idiag_mbxacc_get_setup(phba, pbuffer); - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); -} - -/** - * lpfc_idiag_mbxacc_write - Syntax check and set up idiag mbxacc commands - * @file: The file pointer to read from. - * @buf: The buffer to copy the user data from. - * @nbytes: The number of bytes to get. - * @ppos: The position in the file to start reading from. - * - * This routine get the debugfs idiag command struct from user space and then - * perform the syntax check for driver mailbox command (dump) and sets up the - * necessary states in the idiag command struct accordingly. - * - * It returns the @nbytges passing in from debugfs user space when successful. - * In case of error conditions, it returns proper error code back to the user - * space. - **/ -static ssize_t -lpfc_idiag_mbxacc_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - uint32_t mbx_dump_map, mbx_dump_cnt, mbx_word_cnt, mbx_mbox_cmd; - int rc; - - /* This is a user write operation */ - debug->op = LPFC_IDIAG_OP_WR; - - rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc < 0) - return rc; - - /* Sanity check on command line arguments */ - mbx_mbox_cmd = idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; - mbx_dump_map = idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; - mbx_dump_cnt = idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; - mbx_word_cnt = idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; - - if (idiag.cmd.opcode == LPFC_IDIAG_CMD_MBXACC_DP) { - if (!(mbx_dump_map & LPFC_MBX_DMP_MBX_ALL)) - goto error_out; - if ((mbx_dump_map & ~LPFC_MBX_DMP_MBX_ALL) && - (mbx_dump_map != LPFC_MBX_DMP_ALL)) - goto error_out; - if (mbx_word_cnt > sizeof(MAILBOX_t)) - goto error_out; - } else if (idiag.cmd.opcode == LPFC_IDIAG_BSG_MBXACC_DP) { - if (!(mbx_dump_map & LPFC_BSG_DMP_MBX_ALL)) - goto error_out; - if ((mbx_dump_map & ~LPFC_BSG_DMP_MBX_ALL) && - (mbx_dump_map != LPFC_MBX_DMP_ALL)) - goto error_out; - if (mbx_word_cnt > (BSG_MBOX_SIZE)/4) - goto error_out; - if (mbx_mbox_cmd != 0x9b) - goto error_out; - } else - goto error_out; - - if (mbx_word_cnt == 0) - goto error_out; - if (rc != LPFC_MBX_DMP_ARG) - goto error_out; - if (mbx_mbox_cmd & ~0xff) - goto error_out; - - /* condition for stop mailbox dump */ - if (mbx_dump_cnt == 0) - goto reset_out; - - return nbytes; - -reset_out: - /* Clean out command structure on command error out */ - memset(&idiag, 0, sizeof(idiag)); - return nbytes; - -error_out: - /* Clean out command structure on command error out */ - memset(&idiag, 0, sizeof(idiag)); - return -EINVAL; -} - -/** - * lpfc_idiag_extacc_avail_get - get the available extents information - * @phba: pointer to lpfc hba data structure. - * @pbuffer: pointer to internal buffer. - * @len: length into the internal buffer data has been copied. - * - * Description: - * This routine is to get the available extent information. - * - * Returns: - * overall lenth of the data read into the internal buffer. - **/ -static int -lpfc_idiag_extacc_avail_get(struct lpfc_hba *phba, char *pbuffer, int len) -{ - uint16_t ext_cnt, ext_size; - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\nAvailable Extents Information:\n"); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tPort Available VPI extents: "); - lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VPI, - &ext_cnt, &ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "Count %3d, Size %3d\n", ext_cnt, ext_size); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tPort Available VFI extents: "); - lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_VFI, - &ext_cnt, &ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "Count %3d, Size %3d\n", ext_cnt, ext_size); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tPort Available RPI extents: "); - lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_RPI, - &ext_cnt, &ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "Count %3d, Size %3d\n", ext_cnt, ext_size); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tPort Available XRI extents: "); - lpfc_sli4_get_avail_extnt_rsrc(phba, LPFC_RSC_TYPE_FCOE_XRI, - &ext_cnt, &ext_size); - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "Count %3d, Size %3d\n", ext_cnt, ext_size); - - return len; -} - -/** - * lpfc_idiag_extacc_alloc_get - get the allocated extents information - * @phba: pointer to lpfc hba data structure. - * @pbuffer: pointer to internal buffer. - * @len: length into the internal buffer data has been copied. - * - * Description: - * This routine is to get the allocated extent information. - * - * Returns: - * overall lenth of the data read into the internal buffer. - **/ -static int -lpfc_idiag_extacc_alloc_get(struct lpfc_hba *phba, char *pbuffer, int len) -{ - uint16_t ext_cnt, ext_size; - int rc; - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\nAllocated Extents Information:\n"); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tHost Allocated VPI extents: "); - rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VPI, - &ext_cnt, &ext_size); - if (!rc) - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "Port %d Extent %3d, Size %3d\n", - phba->brd_no, ext_cnt, ext_size); - else - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "N/A\n"); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tHost Allocated VFI extents: "); - rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_VFI, - &ext_cnt, &ext_size); - if (!rc) - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "Port %d Extent %3d, Size %3d\n", - phba->brd_no, ext_cnt, ext_size); - else - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "N/A\n"); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tHost Allocated RPI extents: "); - rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_RPI, - &ext_cnt, &ext_size); - if (!rc) - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "Port %d Extent %3d, Size %3d\n", - phba->brd_no, ext_cnt, ext_size); - else - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "N/A\n"); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tHost Allocated XRI extents: "); - rc = lpfc_sli4_get_allocated_extnts(phba, LPFC_RSC_TYPE_FCOE_XRI, - &ext_cnt, &ext_size); - if (!rc) - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "Port %d Extent %3d, Size %3d\n", - phba->brd_no, ext_cnt, ext_size); - else - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "N/A\n"); - - return len; -} - -/** - * lpfc_idiag_extacc_drivr_get - get driver extent information - * @phba: pointer to lpfc hba data structure. - * @pbuffer: pointer to internal buffer. - * @len: length into the internal buffer data has been copied. - * - * Description: - * This routine is to get the driver extent information. - * - * Returns: - * overall lenth of the data read into the internal buffer. - **/ -static int -lpfc_idiag_extacc_drivr_get(struct lpfc_hba *phba, char *pbuffer, int len) -{ - struct lpfc_rsrc_blks *rsrc_blks; - int index; - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\nDriver Extents Information:\n"); - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tVPI extents:\n"); - index = 0; - list_for_each_entry(rsrc_blks, &phba->lpfc_vpi_blk_list, list) { - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\t\tBlock %3d: Start %4d, Count %4d\n", - index, rsrc_blks->rsrc_start, - rsrc_blks->rsrc_size); - index++; - } - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tVFI extents:\n"); - index = 0; - list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_vfi_blk_list, - list) { - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\t\tBlock %3d: Start %4d, Count %4d\n", - index, rsrc_blks->rsrc_start, - rsrc_blks->rsrc_size); - index++; - } - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tRPI extents:\n"); - index = 0; - list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_rpi_blk_list, - list) { - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\t\tBlock %3d: Start %4d, Count %4d\n", - index, rsrc_blks->rsrc_start, - rsrc_blks->rsrc_size); - index++; - } - - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\tXRI extents:\n"); - index = 0; - list_for_each_entry(rsrc_blks, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - len += snprintf(pbuffer+len, LPFC_EXT_ACC_BUF_SIZE-len, - "\t\tBlock %3d: Start %4d, Count %4d\n", - index, rsrc_blks->rsrc_start, - rsrc_blks->rsrc_size); - index++; - } - - return len; -} - -/** - * lpfc_idiag_extacc_write - Syntax check and set up idiag extacc commands - * @file: The file pointer to read from. - * @buf: The buffer to copy the user data from. - * @nbytes: The number of bytes to get. - * @ppos: The position in the file to start reading from. - * - * This routine get the debugfs idiag command struct from user space and then - * perform the syntax check for extent information access commands and sets - * up the necessary states in the idiag command struct accordingly. - * - * It returns the @nbytges passing in from debugfs user space when successful. - * In case of error conditions, it returns proper error code back to the user - * space. - **/ -static ssize_t -lpfc_idiag_extacc_write(struct file *file, const char __user *buf, - size_t nbytes, loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - uint32_t ext_map; - int rc; - - /* This is a user write operation */ - debug->op = LPFC_IDIAG_OP_WR; - - rc = lpfc_idiag_cmd_get(buf, nbytes, &idiag.cmd); - if (rc < 0) - return rc; - - ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX]; - - if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD) - goto error_out; - if (rc != LPFC_EXT_ACC_CMD_ARG) - goto error_out; - if (!(ext_map & LPFC_EXT_ACC_ALL)) - goto error_out; - - return nbytes; -error_out: - /* Clean out command structure on command error out */ - memset(&idiag, 0, sizeof(idiag)); - return -EINVAL; -} - -/** - * lpfc_idiag_extacc_read - idiag debugfs read access to extent information - * @file: The file pointer to read from. - * @buf: The buffer to copy the data to. - * @nbytes: The number of bytes to read. - * @ppos: The position in the file to start reading from. - * - * Description: - * This routine reads data from the proper extent information according to - * the idiag command, and copies to user @buf. - * - * Returns: - * This function returns the amount of data that was read (this could be less - * than @nbytes if the end of the file was reached) or a negative error value. - **/ -static ssize_t -lpfc_idiag_extacc_read(struct file *file, char __user *buf, size_t nbytes, - loff_t *ppos) -{ - struct lpfc_debug *debug = file->private_data; - struct lpfc_hba *phba = (struct lpfc_hba *)debug->i_private; - char *pbuffer; - uint32_t ext_map; - int len = 0; - - /* This is a user read operation */ - debug->op = LPFC_IDIAG_OP_RD; - - if (!debug->buffer) - debug->buffer = kmalloc(LPFC_EXT_ACC_BUF_SIZE, GFP_KERNEL); - if (!debug->buffer) - return 0; - pbuffer = debug->buffer; - if (*ppos) - return 0; - if (idiag.cmd.opcode != LPFC_IDIAG_CMD_EXTACC_RD) - return 0; - - ext_map = idiag.cmd.data[IDIAG_EXTACC_EXMAP_INDX]; - if (ext_map & LPFC_EXT_ACC_AVAIL) - len = lpfc_idiag_extacc_avail_get(phba, pbuffer, len); - if (ext_map & LPFC_EXT_ACC_ALLOC) - len = lpfc_idiag_extacc_alloc_get(phba, pbuffer, len); - if (ext_map & LPFC_EXT_ACC_DRIVR) - len = lpfc_idiag_extacc_drivr_get(phba, pbuffer, len); - - return simple_read_from_buffer(buf, nbytes, ppos, pbuffer, len); -} - -#undef lpfc_debugfs_op_disc_trc -static const struct file_operations lpfc_debugfs_op_disc_trc = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_disc_trc_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .release = lpfc_debugfs_release, -}; - -#undef lpfc_debugfs_op_nodelist -static const struct file_operations lpfc_debugfs_op_nodelist = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_nodelist_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .release = lpfc_debugfs_release, -}; - -#undef lpfc_debugfs_op_hbqinfo -static const struct file_operations lpfc_debugfs_op_hbqinfo = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_hbqinfo_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .release = lpfc_debugfs_release, -}; - -#undef lpfc_debugfs_op_dumpHBASlim -static const struct file_operations lpfc_debugfs_op_dumpHBASlim = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_dumpHBASlim_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .release = lpfc_debugfs_release, -}; - -#undef lpfc_debugfs_op_dumpHostSlim -static const struct file_operations lpfc_debugfs_op_dumpHostSlim = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_dumpHostSlim_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .release = lpfc_debugfs_release, -}; - -#undef lpfc_debugfs_op_dumpData -static const struct file_operations lpfc_debugfs_op_dumpData = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_dumpData_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .write = lpfc_debugfs_dumpDataDif_write, - .release = lpfc_debugfs_dumpDataDif_release, -}; - -#undef lpfc_debugfs_op_dumpDif -static const struct file_operations lpfc_debugfs_op_dumpDif = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_dumpDif_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .write = lpfc_debugfs_dumpDataDif_write, - .release = lpfc_debugfs_dumpDataDif_release, -}; - -#undef lpfc_debugfs_op_dif_err -static const struct file_operations lpfc_debugfs_op_dif_err = { - .owner = THIS_MODULE, - .open = simple_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_dif_err_read, - .write = lpfc_debugfs_dif_err_write, - .release = lpfc_debugfs_dif_err_release, -}; - -#undef lpfc_debugfs_op_slow_ring_trc -static const struct file_operations lpfc_debugfs_op_slow_ring_trc = { - .owner = THIS_MODULE, - .open = lpfc_debugfs_slow_ring_trc_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_debugfs_read, - .release = lpfc_debugfs_release, -}; - -static struct dentry *lpfc_debugfs_root = NULL; -static atomic_t lpfc_debugfs_hba_count; - -/* - * File operations for the iDiag debugfs - */ -#undef lpfc_idiag_op_pciCfg -static const struct file_operations lpfc_idiag_op_pciCfg = { - .owner = THIS_MODULE, - .open = lpfc_idiag_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_idiag_pcicfg_read, - .write = lpfc_idiag_pcicfg_write, - .release = lpfc_idiag_cmd_release, -}; - -#undef lpfc_idiag_op_barAcc -static const struct file_operations lpfc_idiag_op_barAcc = { - .owner = THIS_MODULE, - .open = lpfc_idiag_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_idiag_baracc_read, - .write = lpfc_idiag_baracc_write, - .release = lpfc_idiag_cmd_release, -}; - -#undef lpfc_idiag_op_queInfo -static const struct file_operations lpfc_idiag_op_queInfo = { - .owner = THIS_MODULE, - .open = lpfc_idiag_open, - .read = lpfc_idiag_queinfo_read, - .release = lpfc_idiag_release, -}; - -#undef lpfc_idiag_op_queAcc -static const struct file_operations lpfc_idiag_op_queAcc = { - .owner = THIS_MODULE, - .open = lpfc_idiag_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_idiag_queacc_read, - .write = lpfc_idiag_queacc_write, - .release = lpfc_idiag_cmd_release, -}; - -#undef lpfc_idiag_op_drbAcc -static const struct file_operations lpfc_idiag_op_drbAcc = { - .owner = THIS_MODULE, - .open = lpfc_idiag_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_idiag_drbacc_read, - .write = lpfc_idiag_drbacc_write, - .release = lpfc_idiag_cmd_release, -}; - -#undef lpfc_idiag_op_ctlAcc -static const struct file_operations lpfc_idiag_op_ctlAcc = { - .owner = THIS_MODULE, - .open = lpfc_idiag_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_idiag_ctlacc_read, - .write = lpfc_idiag_ctlacc_write, - .release = lpfc_idiag_cmd_release, -}; - -#undef lpfc_idiag_op_mbxAcc -static const struct file_operations lpfc_idiag_op_mbxAcc = { - .owner = THIS_MODULE, - .open = lpfc_idiag_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_idiag_mbxacc_read, - .write = lpfc_idiag_mbxacc_write, - .release = lpfc_idiag_cmd_release, -}; - -#undef lpfc_idiag_op_extAcc -static const struct file_operations lpfc_idiag_op_extAcc = { - .owner = THIS_MODULE, - .open = lpfc_idiag_open, - .llseek = lpfc_debugfs_lseek, - .read = lpfc_idiag_extacc_read, - .write = lpfc_idiag_extacc_write, - .release = lpfc_idiag_cmd_release, -}; - -#endif - -/* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command - * @phba: Pointer to HBA context object. - * @dmabuf: Pointer to a DMA buffer descriptor. - * - * Description: - * This routine dump a bsg pass-through non-embedded mailbox command with - * external buffer. - **/ -void -lpfc_idiag_mbxacc_dump_bsg_mbox(struct lpfc_hba *phba, enum nemb_type nemb_tp, - enum mbox_type mbox_tp, enum dma_type dma_tp, - enum sta_type sta_tp, - struct lpfc_dmabuf *dmabuf, uint32_t ext_buf) -{ -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - uint32_t *mbx_mbox_cmd, *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt; - char line_buf[LPFC_MBX_ACC_LBUF_SZ]; - int len = 0; - uint32_t do_dump = 0; - uint32_t *pword; - uint32_t i; - - if (idiag.cmd.opcode != LPFC_IDIAG_BSG_MBXACC_DP) - return; - - mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; - mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; - mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; - mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; - - if (!(*mbx_dump_map & LPFC_MBX_DMP_ALL) || - (*mbx_dump_cnt == 0) || - (*mbx_word_cnt == 0)) - return; - - if (*mbx_mbox_cmd != 0x9B) - return; - - if ((mbox_tp == mbox_rd) && (dma_tp == dma_mbox)) { - if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_MBX) { - do_dump |= LPFC_BSG_DMP_MBX_RD_MBX; - printk(KERN_ERR "\nRead mbox command (x%x), " - "nemb:0x%x, extbuf_cnt:%d:\n", - sta_tp, nemb_tp, ext_buf); - } - } - if ((mbox_tp == mbox_rd) && (dma_tp == dma_ebuf)) { - if (*mbx_dump_map & LPFC_BSG_DMP_MBX_RD_BUF) { - do_dump |= LPFC_BSG_DMP_MBX_RD_BUF; - printk(KERN_ERR "\nRead mbox buffer (x%x), " - "nemb:0x%x, extbuf_seq:%d:\n", - sta_tp, nemb_tp, ext_buf); - } - } - if ((mbox_tp == mbox_wr) && (dma_tp == dma_mbox)) { - if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_MBX) { - do_dump |= LPFC_BSG_DMP_MBX_WR_MBX; - printk(KERN_ERR "\nWrite mbox command (x%x), " - "nemb:0x%x, extbuf_cnt:%d:\n", - sta_tp, nemb_tp, ext_buf); - } - } - if ((mbox_tp == mbox_wr) && (dma_tp == dma_ebuf)) { - if (*mbx_dump_map & LPFC_BSG_DMP_MBX_WR_BUF) { - do_dump |= LPFC_BSG_DMP_MBX_WR_BUF; - printk(KERN_ERR "\nWrite mbox buffer (x%x), " - "nemb:0x%x, extbuf_seq:%d:\n", - sta_tp, nemb_tp, ext_buf); - } - } - - /* dump buffer content */ - if (do_dump) { - pword = (uint32_t *)dmabuf->virt; - for (i = 0; i < *mbx_word_cnt; i++) { - if (!(i % 8)) { - if (i != 0) - printk(KERN_ERR "%s\n", line_buf); - len = 0; - len += snprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, - "%03d: ", i); - } - len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, - "%08x ", (uint32_t)*pword); - pword++; - } - if ((i - 1) % 8) - printk(KERN_ERR "%s\n", line_buf); - (*mbx_dump_cnt)--; - } - - /* Clean out command structure on reaching dump count */ - if (*mbx_dump_cnt == 0) - memset(&idiag, 0, sizeof(idiag)); - return; -#endif -} - -/* lpfc_idiag_mbxacc_dump_issue_mbox - idiag debugfs dump issue mailbox command - * @phba: Pointer to HBA context object. - * @dmabuf: Pointer to a DMA buffer descriptor. - * - * Description: - * This routine dump a pass-through non-embedded mailbox command from issue - * mailbox command. - **/ -void -lpfc_idiag_mbxacc_dump_issue_mbox(struct lpfc_hba *phba, MAILBOX_t *pmbox) -{ -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - uint32_t *mbx_dump_map, *mbx_dump_cnt, *mbx_word_cnt, *mbx_mbox_cmd; - char line_buf[LPFC_MBX_ACC_LBUF_SZ]; - int len = 0; - uint32_t *pword; - uint8_t *pbyte; - uint32_t i, j; - - if (idiag.cmd.opcode != LPFC_IDIAG_CMD_MBXACC_DP) - return; - - mbx_mbox_cmd = &idiag.cmd.data[IDIAG_MBXACC_MBCMD_INDX]; - mbx_dump_map = &idiag.cmd.data[IDIAG_MBXACC_DPMAP_INDX]; - mbx_dump_cnt = &idiag.cmd.data[IDIAG_MBXACC_DPCNT_INDX]; - mbx_word_cnt = &idiag.cmd.data[IDIAG_MBXACC_WDCNT_INDX]; - - if (!(*mbx_dump_map & LPFC_MBX_DMP_MBX_ALL) || - (*mbx_dump_cnt == 0) || - (*mbx_word_cnt == 0)) - return; - - if ((*mbx_mbox_cmd != LPFC_MBX_ALL_CMD) && - (*mbx_mbox_cmd != pmbox->mbxCommand)) - return; - - /* dump buffer content */ - if (*mbx_dump_map & LPFC_MBX_DMP_MBX_WORD) { - printk(KERN_ERR "Mailbox command:0x%x dump by word:\n", - pmbox->mbxCommand); - pword = (uint32_t *)pmbox; - for (i = 0; i < *mbx_word_cnt; i++) { - if (!(i % 8)) { - if (i != 0) - printk(KERN_ERR "%s\n", line_buf); - len = 0; - memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); - len += snprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, - "%03d: ", i); - } - len += snprintf(line_buf+len, LPFC_MBX_ACC_LBUF_SZ-len, - "%08x ", - ((uint32_t)*pword) & 0xffffffff); - pword++; - } - if ((i - 1) % 8) - printk(KERN_ERR "%s\n", line_buf); - printk(KERN_ERR "\n"); - } - if (*mbx_dump_map & LPFC_MBX_DMP_MBX_BYTE) { - printk(KERN_ERR "Mailbox command:0x%x dump by byte:\n", - pmbox->mbxCommand); - pbyte = (uint8_t *)pmbox; - for (i = 0; i < *mbx_word_cnt; i++) { - if (!(i % 8)) { - if (i != 0) - printk(KERN_ERR "%s\n", line_buf); - len = 0; - memset(line_buf, 0, LPFC_MBX_ACC_LBUF_SZ); - len += snprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, - "%03d: ", i); - } - for (j = 0; j < 4; j++) { - len += snprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, - "%02x", - ((uint8_t)*pbyte) & 0xff); - pbyte++; - } - len += snprintf(line_buf+len, - LPFC_MBX_ACC_LBUF_SZ-len, " "); - } - if ((i - 1) % 8) - printk(KERN_ERR "%s\n", line_buf); - printk(KERN_ERR "\n"); - } - (*mbx_dump_cnt)--; - - /* Clean out command structure on reaching dump count */ - if (*mbx_dump_cnt == 0) - memset(&idiag, 0, sizeof(idiag)); - return; -#endif -} - -/** - * lpfc_debugfs_initialize - Initialize debugfs for a vport - * @vport: The vport pointer to initialize. - * - * Description: - * When Debugfs is configured this routine sets up the lpfc debugfs file system. - * If not already created, this routine will create the lpfc directory, and - * lpfcX directory (for this HBA), and vportX directory for this vport. It will - * also create each file used to access lpfc specific debugfs information. - **/ -inline void -lpfc_debugfs_initialize(struct lpfc_vport *vport) -{ -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - struct lpfc_hba *phba = vport->phba; - char name[64]; - uint32_t num, i; - - if (!lpfc_debugfs_enable) - return; - - /* Setup lpfc root directory */ - if (!lpfc_debugfs_root) { - lpfc_debugfs_root = debugfs_create_dir("lpfc", NULL); - atomic_set(&lpfc_debugfs_hba_count, 0); - if (!lpfc_debugfs_root) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0408 Cannot create debugfs root\n"); - goto debug_failed; - } - } - if (!lpfc_debugfs_start_time) - lpfc_debugfs_start_time = jiffies; - - /* Setup funcX directory for specific HBA PCI function */ - snprintf(name, sizeof(name), "fn%d", phba->brd_no); - if (!phba->hba_debugfs_root) { - phba->hba_debugfs_root = - debugfs_create_dir(name, lpfc_debugfs_root); - if (!phba->hba_debugfs_root) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0412 Cannot create debugfs hba\n"); - goto debug_failed; - } - atomic_inc(&lpfc_debugfs_hba_count); - atomic_set(&phba->debugfs_vport_count, 0); - - /* Setup hbqinfo */ - snprintf(name, sizeof(name), "hbqinfo"); - phba->debug_hbqinfo = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_hbqinfo); - if (!phba->debug_hbqinfo) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0411 Cannot create debugfs hbqinfo\n"); - goto debug_failed; - } - - /* Setup dumpHBASlim */ - if (phba->sli_rev < LPFC_SLI_REV4) { - snprintf(name, sizeof(name), "dumpHBASlim"); - phba->debug_dumpHBASlim = - debugfs_create_file(name, - S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpHBASlim); - if (!phba->debug_dumpHBASlim) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0413 Cannot create debugfs " - "dumpHBASlim\n"); - goto debug_failed; - } - } else - phba->debug_dumpHBASlim = NULL; - - /* Setup dumpHostSlim */ - if (phba->sli_rev < LPFC_SLI_REV4) { - snprintf(name, sizeof(name), "dumpHostSlim"); - phba->debug_dumpHostSlim = - debugfs_create_file(name, - S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpHostSlim); - if (!phba->debug_dumpHostSlim) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0414 Cannot create debugfs " - "dumpHostSlim\n"); - goto debug_failed; - } - } else - phba->debug_dumpHBASlim = NULL; - - /* Setup dumpData */ - snprintf(name, sizeof(name), "dumpData"); - phba->debug_dumpData = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpData); - if (!phba->debug_dumpData) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0800 Cannot create debugfs dumpData\n"); - goto debug_failed; - } - - /* Setup dumpDif */ - snprintf(name, sizeof(name), "dumpDif"); - phba->debug_dumpDif = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dumpDif); - if (!phba->debug_dumpDif) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0801 Cannot create debugfs dumpDif\n"); - goto debug_failed; - } - - /* Setup DIF Error Injections */ - snprintf(name, sizeof(name), "InjErrLBA"); - phba->debug_InjErrLBA = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_InjErrLBA) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0807 Cannot create debugfs InjErrLBA\n"); - goto debug_failed; - } - phba->lpfc_injerr_lba = LPFC_INJERR_LBA_OFF; - - snprintf(name, sizeof(name), "InjErrNPortID"); - phba->debug_InjErrNPortID = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_InjErrNPortID) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0809 Cannot create debugfs InjErrNPortID\n"); - goto debug_failed; - } - - snprintf(name, sizeof(name), "InjErrWWPN"); - phba->debug_InjErrWWPN = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_InjErrWWPN) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0810 Cannot create debugfs InjErrWWPN\n"); - goto debug_failed; - } - - snprintf(name, sizeof(name), "writeGuardInjErr"); - phba->debug_writeGuard = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_writeGuard) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0802 Cannot create debugfs writeGuard\n"); - goto debug_failed; - } - - snprintf(name, sizeof(name), "writeAppInjErr"); - phba->debug_writeApp = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_writeApp) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0803 Cannot create debugfs writeApp\n"); - goto debug_failed; - } - - snprintf(name, sizeof(name), "writeRefInjErr"); - phba->debug_writeRef = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_writeRef) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0804 Cannot create debugfs writeRef\n"); - goto debug_failed; - } - - snprintf(name, sizeof(name), "readGuardInjErr"); - phba->debug_readGuard = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_readGuard) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0808 Cannot create debugfs readGuard\n"); - goto debug_failed; - } - - snprintf(name, sizeof(name), "readAppInjErr"); - phba->debug_readApp = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_readApp) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0805 Cannot create debugfs readApp\n"); - goto debug_failed; - } - - snprintf(name, sizeof(name), "readRefInjErr"); - phba->debug_readRef = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_dif_err); - if (!phba->debug_readRef) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0806 Cannot create debugfs readApp\n"); - goto debug_failed; - } - - /* Setup slow ring trace */ - if (lpfc_debugfs_max_slow_ring_trc) { - num = lpfc_debugfs_max_slow_ring_trc - 1; - if (num & lpfc_debugfs_max_slow_ring_trc) { - /* Change to be a power of 2 */ - num = lpfc_debugfs_max_slow_ring_trc; - i = 0; - while (num > 1) { - num = num >> 1; - i++; - } - lpfc_debugfs_max_slow_ring_trc = (1 << i); - printk(KERN_ERR - "lpfc_debugfs_max_disc_trc changed to " - "%d\n", lpfc_debugfs_max_disc_trc); - } - } - - snprintf(name, sizeof(name), "slow_ring_trace"); - phba->debug_slow_ring_trc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->hba_debugfs_root, - phba, &lpfc_debugfs_op_slow_ring_trc); - if (!phba->debug_slow_ring_trc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0415 Cannot create debugfs " - "slow_ring_trace\n"); - goto debug_failed; - } - if (!phba->slow_ring_trc) { - phba->slow_ring_trc = kmalloc( - (sizeof(struct lpfc_debugfs_trc) * - lpfc_debugfs_max_slow_ring_trc), - GFP_KERNEL); - if (!phba->slow_ring_trc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0416 Cannot create debugfs " - "slow_ring buffer\n"); - goto debug_failed; - } - atomic_set(&phba->slow_ring_trc_cnt, 0); - memset(phba->slow_ring_trc, 0, - (sizeof(struct lpfc_debugfs_trc) * - lpfc_debugfs_max_slow_ring_trc)); - } - } - - snprintf(name, sizeof(name), "vport%d", vport->vpi); - if (!vport->vport_debugfs_root) { - vport->vport_debugfs_root = - debugfs_create_dir(name, phba->hba_debugfs_root); - if (!vport->vport_debugfs_root) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0417 Can't create debugfs\n"); - goto debug_failed; - } - atomic_inc(&phba->debugfs_vport_count); - } - - if (lpfc_debugfs_max_disc_trc) { - num = lpfc_debugfs_max_disc_trc - 1; - if (num & lpfc_debugfs_max_disc_trc) { - /* Change to be a power of 2 */ - num = lpfc_debugfs_max_disc_trc; - i = 0; - while (num > 1) { - num = num >> 1; - i++; - } - lpfc_debugfs_max_disc_trc = (1 << i); - printk(KERN_ERR - "lpfc_debugfs_max_disc_trc changed to %d\n", - lpfc_debugfs_max_disc_trc); - } - } - - vport->disc_trc = kzalloc( - (sizeof(struct lpfc_debugfs_trc) * lpfc_debugfs_max_disc_trc), - GFP_KERNEL); - - if (!vport->disc_trc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0418 Cannot create debugfs disc trace " - "buffer\n"); - goto debug_failed; - } - atomic_set(&vport->disc_trc_cnt, 0); - - snprintf(name, sizeof(name), "discovery_trace"); - vport->debug_disc_trc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_disc_trc); - if (!vport->debug_disc_trc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "0419 Cannot create debugfs " - "discovery_trace\n"); - goto debug_failed; - } - snprintf(name, sizeof(name), "nodelist"); - vport->debug_nodelist = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - vport->vport_debugfs_root, - vport, &lpfc_debugfs_op_nodelist); - if (!vport->debug_nodelist) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2985 Can't create debugfs nodelist\n"); - goto debug_failed; - } - - /* - * iDiag debugfs root entry points for SLI4 device only - */ - if (phba->sli_rev < LPFC_SLI_REV4) - goto debug_failed; - - snprintf(name, sizeof(name), "iDiag"); - if (!phba->idiag_root) { - phba->idiag_root = - debugfs_create_dir(name, phba->hba_debugfs_root); - if (!phba->idiag_root) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2922 Can't create idiag debugfs\n"); - goto debug_failed; - } - /* Initialize iDiag data structure */ - memset(&idiag, 0, sizeof(idiag)); - } - - /* iDiag read PCI config space */ - snprintf(name, sizeof(name), "pciCfg"); - if (!phba->idiag_pci_cfg) { - phba->idiag_pci_cfg = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_pciCfg); - if (!phba->idiag_pci_cfg) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2923 Can't create idiag debugfs\n"); - goto debug_failed; - } - idiag.offset.last_rd = 0; - } - - /* iDiag PCI BAR access */ - snprintf(name, sizeof(name), "barAcc"); - if (!phba->idiag_bar_acc) { - phba->idiag_bar_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_barAcc); - if (!phba->idiag_bar_acc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "3056 Can't create idiag debugfs\n"); - goto debug_failed; - } - idiag.offset.last_rd = 0; - } - - /* iDiag get PCI function queue information */ - snprintf(name, sizeof(name), "queInfo"); - if (!phba->idiag_que_info) { - phba->idiag_que_info = - debugfs_create_file(name, S_IFREG|S_IRUGO, - phba->idiag_root, phba, &lpfc_idiag_op_queInfo); - if (!phba->idiag_que_info) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2924 Can't create idiag debugfs\n"); - goto debug_failed; - } - } - - /* iDiag access PCI function queue */ - snprintf(name, sizeof(name), "queAcc"); - if (!phba->idiag_que_acc) { - phba->idiag_que_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_queAcc); - if (!phba->idiag_que_acc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2926 Can't create idiag debugfs\n"); - goto debug_failed; - } - } - - /* iDiag access PCI function doorbell registers */ - snprintf(name, sizeof(name), "drbAcc"); - if (!phba->idiag_drb_acc) { - phba->idiag_drb_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_drbAcc); - if (!phba->idiag_drb_acc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2927 Can't create idiag debugfs\n"); - goto debug_failed; - } - } - - /* iDiag access PCI function control registers */ - snprintf(name, sizeof(name), "ctlAcc"); - if (!phba->idiag_ctl_acc) { - phba->idiag_ctl_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_ctlAcc); - if (!phba->idiag_ctl_acc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2981 Can't create idiag debugfs\n"); - goto debug_failed; - } - } - - /* iDiag access mbox commands */ - snprintf(name, sizeof(name), "mbxAcc"); - if (!phba->idiag_mbx_acc) { - phba->idiag_mbx_acc = - debugfs_create_file(name, S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, &lpfc_idiag_op_mbxAcc); - if (!phba->idiag_mbx_acc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2980 Can't create idiag debugfs\n"); - goto debug_failed; - } - } - - /* iDiag extents access commands */ - if (phba->sli4_hba.extents_in_use) { - snprintf(name, sizeof(name), "extAcc"); - if (!phba->idiag_ext_acc) { - phba->idiag_ext_acc = - debugfs_create_file(name, - S_IFREG|S_IRUGO|S_IWUSR, - phba->idiag_root, phba, - &lpfc_idiag_op_extAcc); - if (!phba->idiag_ext_acc) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, - "2986 Cant create " - "idiag debugfs\n"); - goto debug_failed; - } - } - } - -debug_failed: - return; -#endif -} - -/** - * lpfc_debugfs_terminate - Tear down debugfs infrastructure for this vport - * @vport: The vport pointer to remove from debugfs. - * - * Description: - * When Debugfs is configured this routine removes debugfs file system elements - * that are specific to this vport. It also checks to see if there are any - * users left for the debugfs directories associated with the HBA and driver. If - * this is the last user of the HBA directory or driver directory then it will - * remove those from the debugfs infrastructure as well. - **/ -inline void -lpfc_debugfs_terminate(struct lpfc_vport *vport) -{ -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - struct lpfc_hba *phba = vport->phba; - - if (vport->disc_trc) { - kfree(vport->disc_trc); - vport->disc_trc = NULL; - } - if (vport->debug_disc_trc) { - debugfs_remove(vport->debug_disc_trc); /* discovery_trace */ - vport->debug_disc_trc = NULL; - } - if (vport->debug_nodelist) { - debugfs_remove(vport->debug_nodelist); /* nodelist */ - vport->debug_nodelist = NULL; - } - if (vport->vport_debugfs_root) { - debugfs_remove(vport->vport_debugfs_root); /* vportX */ - vport->vport_debugfs_root = NULL; - atomic_dec(&phba->debugfs_vport_count); - } - if (atomic_read(&phba->debugfs_vport_count) == 0) { - - if (phba->debug_hbqinfo) { - debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ - phba->debug_hbqinfo = NULL; - } - if (phba->debug_dumpHBASlim) { - debugfs_remove(phba->debug_dumpHBASlim); /* HBASlim */ - phba->debug_dumpHBASlim = NULL; - } - if (phba->debug_dumpHostSlim) { - debugfs_remove(phba->debug_dumpHostSlim); /* HostSlim */ - phba->debug_dumpHostSlim = NULL; - } - if (phba->debug_dumpData) { - debugfs_remove(phba->debug_dumpData); /* dumpData */ - phba->debug_dumpData = NULL; - } - - if (phba->debug_dumpDif) { - debugfs_remove(phba->debug_dumpDif); /* dumpDif */ - phba->debug_dumpDif = NULL; - } - if (phba->debug_InjErrLBA) { - debugfs_remove(phba->debug_InjErrLBA); /* InjErrLBA */ - phba->debug_InjErrLBA = NULL; - } - if (phba->debug_InjErrNPortID) { /* InjErrNPortID */ - debugfs_remove(phba->debug_InjErrNPortID); - phba->debug_InjErrNPortID = NULL; - } - if (phba->debug_InjErrWWPN) { - debugfs_remove(phba->debug_InjErrWWPN); /* InjErrWWPN */ - phba->debug_InjErrWWPN = NULL; - } - if (phba->debug_writeGuard) { - debugfs_remove(phba->debug_writeGuard); /* writeGuard */ - phba->debug_writeGuard = NULL; - } - if (phba->debug_writeApp) { - debugfs_remove(phba->debug_writeApp); /* writeApp */ - phba->debug_writeApp = NULL; - } - if (phba->debug_writeRef) { - debugfs_remove(phba->debug_writeRef); /* writeRef */ - phba->debug_writeRef = NULL; - } - if (phba->debug_readGuard) { - debugfs_remove(phba->debug_readGuard); /* readGuard */ - phba->debug_readGuard = NULL; - } - if (phba->debug_readApp) { - debugfs_remove(phba->debug_readApp); /* readApp */ - phba->debug_readApp = NULL; - } - if (phba->debug_readRef) { - debugfs_remove(phba->debug_readRef); /* readRef */ - phba->debug_readRef = NULL; - } - - if (phba->slow_ring_trc) { - kfree(phba->slow_ring_trc); - phba->slow_ring_trc = NULL; - } - if (phba->debug_slow_ring_trc) { - /* slow_ring_trace */ - debugfs_remove(phba->debug_slow_ring_trc); - phba->debug_slow_ring_trc = NULL; - } - - /* - * iDiag release - */ - if (phba->sli_rev == LPFC_SLI_REV4) { - if (phba->idiag_ext_acc) { - /* iDiag extAcc */ - debugfs_remove(phba->idiag_ext_acc); - phba->idiag_ext_acc = NULL; - } - if (phba->idiag_mbx_acc) { - /* iDiag mbxAcc */ - debugfs_remove(phba->idiag_mbx_acc); - phba->idiag_mbx_acc = NULL; - } - if (phba->idiag_ctl_acc) { - /* iDiag ctlAcc */ - debugfs_remove(phba->idiag_ctl_acc); - phba->idiag_ctl_acc = NULL; - } - if (phba->idiag_drb_acc) { - /* iDiag drbAcc */ - debugfs_remove(phba->idiag_drb_acc); - phba->idiag_drb_acc = NULL; - } - if (phba->idiag_que_acc) { - /* iDiag queAcc */ - debugfs_remove(phba->idiag_que_acc); - phba->idiag_que_acc = NULL; - } - if (phba->idiag_que_info) { - /* iDiag queInfo */ - debugfs_remove(phba->idiag_que_info); - phba->idiag_que_info = NULL; - } - if (phba->idiag_bar_acc) { - /* iDiag barAcc */ - debugfs_remove(phba->idiag_bar_acc); - phba->idiag_bar_acc = NULL; - } - if (phba->idiag_pci_cfg) { - /* iDiag pciCfg */ - debugfs_remove(phba->idiag_pci_cfg); - phba->idiag_pci_cfg = NULL; - } - - /* Finally remove the iDiag debugfs root */ - if (phba->idiag_root) { - /* iDiag root */ - debugfs_remove(phba->idiag_root); - phba->idiag_root = NULL; - } - } - - if (phba->hba_debugfs_root) { - debugfs_remove(phba->hba_debugfs_root); /* fnX */ - phba->hba_debugfs_root = NULL; - atomic_dec(&lpfc_debugfs_hba_count); - } - - if (atomic_read(&lpfc_debugfs_hba_count) == 0) { - debugfs_remove(lpfc_debugfs_root); /* lpfc */ - lpfc_debugfs_root = NULL; - } - } -#endif - return; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.h deleted file mode 100644 index f83bd944..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_debugfs.h +++ /dev/null @@ -1,269 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2007-2011 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#ifndef _H_LPFC_DEBUG_FS -#define _H_LPFC_DEBUG_FS - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - -/* size of output line, for discovery_trace and slow_ring_trace */ -#define LPFC_DEBUG_TRC_ENTRY_SIZE 100 - -/* nodelist output buffer size */ -#define LPFC_NODELIST_SIZE 8192 -#define LPFC_NODELIST_ENTRY_SIZE 120 - -/* dumpHBASlim output buffer size */ -#define LPFC_DUMPHBASLIM_SIZE 4096 - -/* dumpHostSlim output buffer size */ -#define LPFC_DUMPHOSTSLIM_SIZE 4096 - -/* hbqinfo output buffer size */ -#define LPFC_HBQINFO_SIZE 8192 - -/* - * For SLI4 iDiag debugfs diagnostics tool - */ - -/* pciConf */ -#define LPFC_PCI_CFG_BROWSE 0xffff -#define LPFC_PCI_CFG_RD_CMD_ARG 2 -#define LPFC_PCI_CFG_WR_CMD_ARG 3 -#define LPFC_PCI_CFG_SIZE 4096 -#define LPFC_PCI_CFG_RD_SIZE (LPFC_PCI_CFG_SIZE/4) - -#define IDIAG_PCICFG_WHERE_INDX 0 -#define IDIAG_PCICFG_COUNT_INDX 1 -#define IDIAG_PCICFG_VALUE_INDX 2 - -/* barAcc */ -#define LPFC_PCI_BAR_BROWSE 0xffff -#define LPFC_PCI_BAR_RD_CMD_ARG 3 -#define LPFC_PCI_BAR_WR_CMD_ARG 3 - -#define LPFC_PCI_IF0_BAR0_SIZE (1024 * 16) -#define LPFC_PCI_IF0_BAR1_SIZE (1024 * 128) -#define LPFC_PCI_IF0_BAR2_SIZE (1024 * 128) -#define LPFC_PCI_IF2_BAR0_SIZE (1024 * 32) - -#define LPFC_PCI_BAR_RD_BUF_SIZE 4096 -#define LPFC_PCI_BAR_RD_SIZE (LPFC_PCI_BAR_RD_BUF_SIZE/4) - -#define LPFC_PCI_IF0_BAR0_RD_SIZE (LPFC_PCI_IF0_BAR0_SIZE/4) -#define LPFC_PCI_IF0_BAR1_RD_SIZE (LPFC_PCI_IF0_BAR1_SIZE/4) -#define LPFC_PCI_IF0_BAR2_RD_SIZE (LPFC_PCI_IF0_BAR2_SIZE/4) -#define LPFC_PCI_IF2_BAR0_RD_SIZE (LPFC_PCI_IF2_BAR0_SIZE/4) - -#define IDIAG_BARACC_BAR_NUM_INDX 0 -#define IDIAG_BARACC_OFF_SET_INDX 1 -#define IDIAG_BARACC_ACC_MOD_INDX 2 -#define IDIAG_BARACC_REG_VAL_INDX 2 -#define IDIAG_BARACC_BAR_SZE_INDX 3 - -#define IDIAG_BARACC_BAR_0 0 -#define IDIAG_BARACC_BAR_1 1 -#define IDIAG_BARACC_BAR_2 2 - -#define SINGLE_WORD 1 - -/* queue info */ -#define LPFC_QUE_INFO_GET_BUF_SIZE 4096 - -/* queue acc */ -#define LPFC_QUE_ACC_BROWSE 0xffff -#define LPFC_QUE_ACC_RD_CMD_ARG 4 -#define LPFC_QUE_ACC_WR_CMD_ARG 6 -#define LPFC_QUE_ACC_BUF_SIZE 4096 -#define LPFC_QUE_ACC_SIZE (LPFC_QUE_ACC_BUF_SIZE/2) - -#define LPFC_IDIAG_EQ 1 -#define LPFC_IDIAG_CQ 2 -#define LPFC_IDIAG_MQ 3 -#define LPFC_IDIAG_WQ 4 -#define LPFC_IDIAG_RQ 5 - -#define IDIAG_QUEACC_QUETP_INDX 0 -#define IDIAG_QUEACC_QUEID_INDX 1 -#define IDIAG_QUEACC_INDEX_INDX 2 -#define IDIAG_QUEACC_COUNT_INDX 3 -#define IDIAG_QUEACC_OFFST_INDX 4 -#define IDIAG_QUEACC_VALUE_INDX 5 - -/* doorbell register acc */ -#define LPFC_DRB_ACC_ALL 0xffff -#define LPFC_DRB_ACC_RD_CMD_ARG 1 -#define LPFC_DRB_ACC_WR_CMD_ARG 2 -#define LPFC_DRB_ACC_BUF_SIZE 256 - -#define LPFC_DRB_EQCQ 1 -#define LPFC_DRB_MQ 2 -#define LPFC_DRB_WQ 3 -#define LPFC_DRB_RQ 4 - -#define LPFC_DRB_MAX 4 - -#define IDIAG_DRBACC_REGID_INDX 0 -#define IDIAG_DRBACC_VALUE_INDX 1 - -/* control register acc */ -#define LPFC_CTL_ACC_ALL 0xffff -#define LPFC_CTL_ACC_RD_CMD_ARG 1 -#define LPFC_CTL_ACC_WR_CMD_ARG 2 -#define LPFC_CTL_ACC_BUF_SIZE 256 - -#define LPFC_CTL_PORT_SEM 1 -#define LPFC_CTL_PORT_STA 2 -#define LPFC_CTL_PORT_CTL 3 -#define LPFC_CTL_PORT_ER1 4 -#define LPFC_CTL_PORT_ER2 5 -#define LPFC_CTL_PDEV_CTL 6 - -#define LPFC_CTL_MAX 6 - -#define IDIAG_CTLACC_REGID_INDX 0 -#define IDIAG_CTLACC_VALUE_INDX 1 - -/* mailbox access */ -#define LPFC_MBX_DMP_ARG 4 - -#define LPFC_MBX_ACC_BUF_SIZE 512 -#define LPFC_MBX_ACC_LBUF_SZ 128 - -#define LPFC_MBX_DMP_MBX_WORD 0x00000001 -#define LPFC_MBX_DMP_MBX_BYTE 0x00000002 -#define LPFC_MBX_DMP_MBX_ALL (LPFC_MBX_DMP_MBX_WORD | LPFC_MBX_DMP_MBX_BYTE) - -#define LPFC_BSG_DMP_MBX_RD_MBX 0x00000001 -#define LPFC_BSG_DMP_MBX_RD_BUF 0x00000002 -#define LPFC_BSG_DMP_MBX_WR_MBX 0x00000004 -#define LPFC_BSG_DMP_MBX_WR_BUF 0x00000008 -#define LPFC_BSG_DMP_MBX_ALL (LPFC_BSG_DMP_MBX_RD_MBX | \ - LPFC_BSG_DMP_MBX_RD_BUF | \ - LPFC_BSG_DMP_MBX_WR_MBX | \ - LPFC_BSG_DMP_MBX_WR_BUF) - -#define LPFC_MBX_DMP_ALL 0xffff -#define LPFC_MBX_ALL_CMD 0xff - -#define IDIAG_MBXACC_MBCMD_INDX 0 -#define IDIAG_MBXACC_DPMAP_INDX 1 -#define IDIAG_MBXACC_DPCNT_INDX 2 -#define IDIAG_MBXACC_WDCNT_INDX 3 - -/* extents access */ -#define LPFC_EXT_ACC_CMD_ARG 1 -#define LPFC_EXT_ACC_BUF_SIZE 4096 - -#define LPFC_EXT_ACC_AVAIL 0x1 -#define LPFC_EXT_ACC_ALLOC 0x2 -#define LPFC_EXT_ACC_DRIVR 0x4 -#define LPFC_EXT_ACC_ALL (LPFC_EXT_ACC_DRIVR | \ - LPFC_EXT_ACC_AVAIL | \ - LPFC_EXT_ACC_ALLOC) - -#define IDIAG_EXTACC_EXMAP_INDX 0 - -#define SIZE_U8 sizeof(uint8_t) -#define SIZE_U16 sizeof(uint16_t) -#define SIZE_U32 sizeof(uint32_t) - -struct lpfc_debug { - char *i_private; - char op; -#define LPFC_IDIAG_OP_RD 1 -#define LPFC_IDIAG_OP_WR 2 - char *buffer; - int len; -}; - -struct lpfc_debugfs_trc { - char *fmt; - uint32_t data1; - uint32_t data2; - uint32_t data3; - uint32_t seq_cnt; - unsigned long jif; -}; - -struct lpfc_idiag_offset { - uint32_t last_rd; -}; - -#define LPFC_IDIAG_CMD_DATA_SIZE 8 -struct lpfc_idiag_cmd { - uint32_t opcode; -#define LPFC_IDIAG_CMD_PCICFG_RD 0x00000001 -#define LPFC_IDIAG_CMD_PCICFG_WR 0x00000002 -#define LPFC_IDIAG_CMD_PCICFG_ST 0x00000003 -#define LPFC_IDIAG_CMD_PCICFG_CL 0x00000004 - -#define LPFC_IDIAG_CMD_BARACC_RD 0x00000008 -#define LPFC_IDIAG_CMD_BARACC_WR 0x00000009 -#define LPFC_IDIAG_CMD_BARACC_ST 0x0000000a -#define LPFC_IDIAG_CMD_BARACC_CL 0x0000000b - -#define LPFC_IDIAG_CMD_QUEACC_RD 0x00000011 -#define LPFC_IDIAG_CMD_QUEACC_WR 0x00000012 -#define LPFC_IDIAG_CMD_QUEACC_ST 0x00000013 -#define LPFC_IDIAG_CMD_QUEACC_CL 0x00000014 - -#define LPFC_IDIAG_CMD_DRBACC_RD 0x00000021 -#define LPFC_IDIAG_CMD_DRBACC_WR 0x00000022 -#define LPFC_IDIAG_CMD_DRBACC_ST 0x00000023 -#define LPFC_IDIAG_CMD_DRBACC_CL 0x00000024 - -#define LPFC_IDIAG_CMD_CTLACC_RD 0x00000031 -#define LPFC_IDIAG_CMD_CTLACC_WR 0x00000032 -#define LPFC_IDIAG_CMD_CTLACC_ST 0x00000033 -#define LPFC_IDIAG_CMD_CTLACC_CL 0x00000034 - -#define LPFC_IDIAG_CMD_MBXACC_DP 0x00000041 -#define LPFC_IDIAG_BSG_MBXACC_DP 0x00000042 - -#define LPFC_IDIAG_CMD_EXTACC_RD 0x00000051 - - uint32_t data[LPFC_IDIAG_CMD_DATA_SIZE]; -}; - -struct lpfc_idiag { - uint32_t active; - struct lpfc_idiag_cmd cmd; - struct lpfc_idiag_offset offset; - void *ptr_private; -}; -#endif - -/* Mask for discovery_trace */ -#define LPFC_DISC_TRC_ELS_CMD 0x1 /* Trace ELS commands */ -#define LPFC_DISC_TRC_ELS_RSP 0x2 /* Trace ELS response */ -#define LPFC_DISC_TRC_ELS_UNSOL 0x4 /* Trace ELS rcv'ed */ -#define LPFC_DISC_TRC_ELS_ALL 0x7 /* Trace ELS */ -#define LPFC_DISC_TRC_MBOX_VPORT 0x8 /* Trace vport MBOXs */ -#define LPFC_DISC_TRC_MBOX 0x10 /* Trace other MBOXs */ -#define LPFC_DISC_TRC_MBOX_ALL 0x18 /* Trace all MBOXs */ -#define LPFC_DISC_TRC_CT 0x20 /* Trace disc CT requests */ -#define LPFC_DISC_TRC_DSM 0x40 /* Trace DSM events */ -#define LPFC_DISC_TRC_RPORT 0x80 /* Trace rport events */ -#define LPFC_DISC_TRC_NODE 0x100 /* Trace ndlp state changes */ - -#define LPFC_DISC_TRC_DISCOVERY 0xef /* common mask for general - * discovery */ -#endif /* H_LPFC_DEBUG_FS */ diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_disc.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_disc.h deleted file mode 100644 index 1d84b63f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_disc.h +++ /dev/null @@ -1,265 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#define FC_MAX_HOLD_RSCN 32 /* max number of deferred RSCNs */ -#define FC_MAX_NS_RSP 64512 /* max size NameServer rsp */ -#define FC_MAXLOOP 126 /* max devices supported on a fc loop */ -#define LPFC_DISC_FLOGI_TMO 10 /* Discovery FLOGI ratov */ - - -/* This is the protocol dependent definition for a Node List Entry. - * This is used by Fibre Channel protocol to support FCP. - */ - -/* worker thread events */ -enum lpfc_work_type { - LPFC_EVT_ONLINE, - LPFC_EVT_OFFLINE_PREP, - LPFC_EVT_OFFLINE, - LPFC_EVT_WARM_START, - LPFC_EVT_KILL, - LPFC_EVT_ELS_RETRY, - LPFC_EVT_DEV_LOSS, - LPFC_EVT_FASTPATH_MGMT_EVT, - LPFC_EVT_RESET_HBA, -}; - -/* structure used to queue event to the discovery tasklet */ -struct lpfc_work_evt { - struct list_head evt_listp; - void *evt_arg1; - void *evt_arg2; - enum lpfc_work_type evt; -}; - -struct lpfc_scsi_check_condition_event; -struct lpfc_scsi_varqueuedepth_event; -struct lpfc_scsi_event_header; -struct lpfc_fabric_event_header; -struct lpfc_fcprdchkerr_event; - -/* structure used for sending events from fast path */ -struct lpfc_fast_path_event { - struct lpfc_work_evt work_evt; - struct lpfc_vport *vport; - union { - struct lpfc_scsi_check_condition_event check_cond_evt; - struct lpfc_scsi_varqueuedepth_event queue_depth_evt; - struct lpfc_scsi_event_header scsi_evt; - struct lpfc_fabric_event_header fabric_evt; - struct lpfc_fcprdchkerr_event read_check_error; - } un; -}; - -#define LPFC_SLI4_MAX_XRI 1024 /* Used to make the ndlp's xri_bitmap */ -#define XRI_BITMAP_ULONGS (LPFC_SLI4_MAX_XRI / BITS_PER_LONG) -struct lpfc_node_rrqs { - unsigned long xri_bitmap[XRI_BITMAP_ULONGS]; -}; - -struct lpfc_nodelist { - struct list_head nlp_listp; - struct lpfc_name nlp_portname; - struct lpfc_name nlp_nodename; - uint32_t nlp_flag; /* entry flags */ - uint32_t nlp_DID; /* FC D_ID of entry */ - uint32_t nlp_last_elscmd; /* Last ELS cmd sent */ - uint16_t nlp_type; -#define NLP_FC_NODE 0x1 /* entry is an FC node */ -#define NLP_FABRIC 0x4 /* entry rep a Fabric entity */ -#define NLP_FCP_TARGET 0x8 /* entry is an FCP target */ -#define NLP_FCP_INITIATOR 0x10 /* entry is an FCP Initiator */ - - uint16_t nlp_rpi; - uint16_t nlp_state; /* state transition indicator */ - uint16_t nlp_prev_state; /* state transition indicator */ - uint16_t nlp_xri; /* output exchange id for RPI */ - uint16_t nlp_sid; /* scsi id */ -#define NLP_NO_SID 0xffff - uint16_t nlp_maxframe; /* Max RCV frame size */ - uint8_t nlp_class_sup; /* Supported Classes */ - uint8_t nlp_retry; /* used for ELS retries */ - uint8_t nlp_fcp_info; /* class info, bits 0-3 */ -#define NLP_FCP_2_DEVICE 0x10 /* FCP-2 device */ - - uint16_t nlp_usg_map; /* ndlp management usage bitmap */ -#define NLP_USG_NODE_ACT_BIT 0x1 /* Indicate ndlp is actively used */ -#define NLP_USG_IACT_REQ_BIT 0x2 /* Request to inactivate ndlp */ -#define NLP_USG_FREE_REQ_BIT 0x4 /* Request to invoke ndlp memory free */ -#define NLP_USG_FREE_ACK_BIT 0x8 /* Indicate ndlp memory free invoked */ - - struct timer_list nlp_delayfunc; /* Used for delayed ELS cmds */ - struct lpfc_hba *phba; - struct fc_rport *rport; /* Corresponding FC transport - port structure */ - struct lpfc_vport *vport; - struct lpfc_work_evt els_retry_evt; - struct lpfc_work_evt dev_loss_evt; - struct kref kref; - atomic_t cmd_pending; - uint32_t cmd_qdepth; - unsigned long last_change_time; - struct lpfc_node_rrqs active_rrqs; - struct lpfc_scsicmd_bkt *lat_data; /* Latency data */ -}; -struct lpfc_node_rrq { - struct list_head list; - uint16_t xritag; - uint16_t send_rrq; - uint16_t rxid; - uint32_t nlp_DID; /* FC D_ID of entry */ - struct lpfc_vport *vport; - struct lpfc_nodelist *ndlp; - unsigned long rrq_stop_time; -}; - -/* Defines for nlp_flag (uint32) */ -#define NLP_IGNR_REG_CMPL 0x00000001 /* Rcvd rscn before we cmpl reg login */ -#define NLP_REG_LOGIN_SEND 0x00000002 /* sent reglogin to adapter */ -#define NLP_PLOGI_SND 0x00000020 /* sent PLOGI request for this entry */ -#define NLP_PRLI_SND 0x00000040 /* sent PRLI request for this entry */ -#define NLP_ADISC_SND 0x00000080 /* sent ADISC request for this entry */ -#define NLP_LOGO_SND 0x00000100 /* sent LOGO request for this entry */ -#define NLP_RNID_SND 0x00000400 /* sent RNID request for this entry */ -#define NLP_ELS_SND_MASK 0x000007e0 /* sent ELS request for this entry */ -#define NLP_DEFER_RM 0x00010000 /* Remove this ndlp if no longer used */ -#define NLP_DELAY_TMO 0x00020000 /* delay timeout is running for node */ -#define NLP_NPR_2B_DISC 0x00040000 /* node is included in num_disc_nodes */ -#define NLP_RCV_PLOGI 0x00080000 /* Rcv'ed PLOGI from remote system */ -#define NLP_LOGO_ACC 0x00100000 /* Process LOGO after ACC completes */ -#define NLP_TGT_NO_SCSIID 0x00200000 /* good PRLI but no binding for scsid */ -#define NLP_ACC_REGLOGIN 0x01000000 /* Issue Reg Login after successful - ACC */ -#define NLP_NPR_ADISC 0x02000000 /* Issue ADISC when dq'ed from - NPR list */ -#define NLP_RM_DFLT_RPI 0x04000000 /* need to remove leftover dflt RPI */ -#define NLP_NODEV_REMOVE 0x08000000 /* Defer removal till discovery ends */ -#define NLP_TARGET_REMOVE 0x10000000 /* Target remove in process */ -#define NLP_SC_REQ 0x20000000 /* Target requires authentication */ -#define NLP_RPI_REGISTERED 0x80000000 /* nlp_rpi is valid */ - -/* ndlp usage management macros */ -#define NLP_CHK_NODE_ACT(ndlp) (((ndlp)->nlp_usg_map \ - & NLP_USG_NODE_ACT_BIT) \ - && \ - !((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_ACK_BIT)) -#define NLP_SET_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_NODE_ACT_BIT) -#define NLP_INT_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - = NLP_USG_NODE_ACT_BIT) -#define NLP_CLR_NODE_ACT(ndlp) ((ndlp)->nlp_usg_map \ - &= ~NLP_USG_NODE_ACT_BIT) -#define NLP_CHK_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_IACT_REQ_BIT) -#define NLP_SET_IACT_REQ(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_IACT_REQ_BIT) -#define NLP_CHK_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_REQ_BIT) -#define NLP_SET_FREE_REQ(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_FREE_REQ_BIT) -#define NLP_CHK_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ - & NLP_USG_FREE_ACK_BIT) -#define NLP_SET_FREE_ACK(ndlp) ((ndlp)->nlp_usg_map \ - |= NLP_USG_FREE_ACK_BIT) - -/* There are 4 different double linked lists nodelist entries can reside on. - * The Port Login (PLOGI) list and Address Discovery (ADISC) list are used - * when Link Up discovery or Registered State Change Notification (RSCN) - * processing is needed. Each list holds the nodes that require a PLOGI or - * ADISC Extended Link Service (ELS) request. These lists keep track of the - * nodes affected by an RSCN, or a Link Up (Typically, all nodes are effected - * by Link Up) event. The unmapped_list contains all nodes that have - * successfully logged into at the Fibre Channel level. The - * mapped_list will contain all nodes that are mapped FCP targets. - * - * The bind list is a list of undiscovered (potentially non-existent) nodes - * that we have saved binding information on. This information is used when - * nodes transition from the unmapped to the mapped list. - */ - -/* Defines for nlp_state */ -#define NLP_STE_UNUSED_NODE 0x0 /* node is just allocated */ -#define NLP_STE_PLOGI_ISSUE 0x1 /* PLOGI was sent to NL_PORT */ -#define NLP_STE_ADISC_ISSUE 0x2 /* ADISC was sent to NL_PORT */ -#define NLP_STE_REG_LOGIN_ISSUE 0x3 /* REG_LOGIN was issued for NL_PORT */ -#define NLP_STE_PRLI_ISSUE 0x4 /* PRLI was sent to NL_PORT */ -#define NLP_STE_UNMAPPED_NODE 0x5 /* PRLI completed from NL_PORT */ -#define NLP_STE_MAPPED_NODE 0x6 /* Identified as a FCP Target */ -#define NLP_STE_NPR_NODE 0x7 /* NPort disappeared */ -#define NLP_STE_MAX_STATE 0x8 -#define NLP_STE_FREED_NODE 0xff /* node entry was freed to MEM_NLP */ - -/* For UNUSED_NODE state, the node has just been allocated. - * For PLOGI_ISSUE and REG_LOGIN_ISSUE, the node is on - * the PLOGI list. For REG_LOGIN_COMPL, the node is taken off the PLOGI list - * and put on the unmapped list. For ADISC processing, the node is taken off - * the ADISC list and placed on either the mapped or unmapped list (depending - * on its previous state). Once on the unmapped list, a PRLI is issued and the - * state changed to PRLI_ISSUE. When the PRLI completion occurs, the state is - * changed to PRLI_COMPL. If the completion indicates a mapped - * node, the node is taken off the unmapped list. The binding list is checked - * for a valid binding, or a binding is automatically assigned. If binding - * assignment is unsuccessful, the node is left on the unmapped list. If - * binding assignment is successful, the associated binding list entry (if - * any) is removed, and the node is placed on the mapped list. - */ -/* - * For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped - * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers - * expire, all effected nodes will receive a DEVICE_RM event. - */ -/* - * For a Link Up or RSCN, all nodes will move from the mapped / unmapped lists - * to either the ADISC or PLOGI list. After a Nameserver query or ALPA loopmap - * check, additional nodes may be added (DEVICE_ADD) or removed (DEVICE_RM) to / - * from the PLOGI or ADISC lists. Once the PLOGI and ADISC lists are populated, - * we will first process the ADISC list. 32 entries are processed initially and - * ADISC is initited for each one. Completions / Events for each node are - * funnelled thru the state machine. As each node finishes ADISC processing, it - * starts ADISC for any nodes waiting for ADISC processing. If no nodes are - * waiting, and the ADISC list count is identically 0, then we are done. For - * Link Up discovery, since all nodes on the PLOGI list are UNREG_LOGIN'ed, we - * can issue a CLEAR_LA and reenable Link Events. Next we will process the PLOGI - * list. 32 entries are processed initially and PLOGI is initited for each one. - * Completions / Events for each node are funnelled thru the state machine. As - * each node finishes PLOGI processing, it starts PLOGI for any nodes waiting - * for PLOGI processing. If no nodes are waiting, and the PLOGI list count is - * identically 0, then we are done. We have now completed discovery / RSCN - * handling. Upon completion, ALL nodes should be on either the mapped or - * unmapped lists. - */ - -/* Defines for Node List Entry Events that could happen */ -#define NLP_EVT_RCV_PLOGI 0x0 /* Rcv'd an ELS PLOGI command */ -#define NLP_EVT_RCV_PRLI 0x1 /* Rcv'd an ELS PRLI command */ -#define NLP_EVT_RCV_LOGO 0x2 /* Rcv'd an ELS LOGO command */ -#define NLP_EVT_RCV_ADISC 0x3 /* Rcv'd an ELS ADISC command */ -#define NLP_EVT_RCV_PDISC 0x4 /* Rcv'd an ELS PDISC command */ -#define NLP_EVT_RCV_PRLO 0x5 /* Rcv'd an ELS PRLO command */ -#define NLP_EVT_CMPL_PLOGI 0x6 /* Sent an ELS PLOGI command */ -#define NLP_EVT_CMPL_PRLI 0x7 /* Sent an ELS PRLI command */ -#define NLP_EVT_CMPL_LOGO 0x8 /* Sent an ELS LOGO command */ -#define NLP_EVT_CMPL_ADISC 0x9 /* Sent an ELS ADISC command */ -#define NLP_EVT_CMPL_REG_LOGIN 0xa /* REG_LOGIN mbox cmd completed */ -#define NLP_EVT_DEVICE_RM 0xb /* Device not found in NS / ALPAmap */ -#define NLP_EVT_DEVICE_RECOVERY 0xc /* Device existence unknown */ -#define NLP_EVT_MAX_EVENT 0xd - diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_els.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_els.c deleted file mode 100644 index 3407b39e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_els.c +++ /dev/null @@ -1,7898 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ -/* See Fibre Channel protocol T11 FC-LS for details */ -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_vport.h" -#include "lpfc_debugfs.h" - -static int lpfc_els_retry(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); -static void lpfc_cmpl_fabric_iocb(struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); -static void lpfc_fabric_abort_vport(struct lpfc_vport *vport); -static int lpfc_issue_els_fdisc(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, uint8_t retry); -static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, - struct lpfc_iocbq *iocb); - -static int lpfc_max_els_tries = 3; - -/** - * lpfc_els_chk_latt - Check host link attention event for a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine checks whether there is an outstanding host link - * attention event during the discovery process with the @vport. It is done - * by reading the HBA's Host Attention (HA) register. If there is any host - * link attention events during this @vport's discovery process, the @vport - * shall be marked as FC_ABORT_DISCOVERY, a host link attention clear shall - * be issued if the link state is not already in host link cleared state, - * and a return code shall indicate whether the host link attention event - * had happened. - * - * Note that, if either the host link is in state LPFC_LINK_DOWN or @vport - * state in LPFC_VPORT_READY, the request for checking host link attention - * event will be ignored and a return code shall indicate no host link - * attention event had happened. - * - * Return codes - * 0 - no host link attention event happened - * 1 - host link attention event happened - **/ -int -lpfc_els_chk_latt(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - uint32_t ha_copy; - - if (vport->port_state >= LPFC_VPORT_READY || - phba->link_state == LPFC_LINK_DOWN || - phba->sli_rev > LPFC_SLI_REV3) - return 0; - - /* Read the HBA Host Attention Register */ - if (lpfc_readl(phba->HAregaddr, &ha_copy)) - return 1; - - if (!(ha_copy & HA_LATT)) - return 0; - - /* Pending Link Event during Discovery */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0237 Pending Link Event during " - "Discovery: State x%x\n", - phba->pport->port_state); - - /* CLEAR_LA should re-enable link attention events and - * we should then immediately take a LATT event. The - * LATT processing should call lpfc_linkdown() which - * will cleanup any left over in-progress discovery - * events. - */ - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_ABORT_DISCOVERY; - spin_unlock_irq(shost->host_lock); - - if (phba->link_state != LPFC_CLEAR_LA) - lpfc_issue_clear_la(phba, vport); - - return 1; -} - -/** - * lpfc_prep_els_iocb - Allocate and prepare a lpfc iocb data structure - * @vport: pointer to a host virtual N_Port data structure. - * @expectRsp: flag indicating whether response is expected. - * @cmdSize: size of the ELS command. - * @retry: number of retries to the command IOCB when it fails. - * @ndlp: pointer to a node-list data structure. - * @did: destination identifier. - * @elscmd: the ELS command code. - * - * This routine is used for allocating a lpfc-IOCB data structure from - * the driver lpfc-IOCB free-list and prepare the IOCB with the parameters - * passed into the routine for discovery state machine to issue an Extended - * Link Service (ELS) commands. It is a generic lpfc-IOCB allocation - * and preparation routine that is used by all the discovery state machine - * routines and the ELS command-specific fields will be later set up by - * the individual discovery machine routines after calling this routine - * allocating and preparing a generic IOCB data structure. It fills in the - * Buffer Descriptor Entries (BDEs), allocates buffers for both command - * payload and response payload (if expected). The reference count on the - * ndlp is incremented by 1 and the reference to the ndlp is put into - * context1 of the IOCB data structure for this IOCB to hold the ndlp - * reference for the command's callback function to access later. - * - * Return code - * Pointer to the newly allocated/prepared els iocb data structure - * NULL - when els iocb data structure allocation/preparation failed - **/ -struct lpfc_iocbq * -lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, - uint16_t cmdSize, uint8_t retry, - struct lpfc_nodelist *ndlp, uint32_t did, - uint32_t elscmd) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *elsiocb; - struct lpfc_dmabuf *pcmd, *prsp, *pbuflist; - struct ulp_bde64 *bpl; - IOCB_t *icmd; - - - if (!lpfc_is_link_up(phba)) - return NULL; - - /* Allocate buffer for command iocb */ - elsiocb = lpfc_sli_get_iocbq(phba); - - if (elsiocb == NULL) - return NULL; - - /* - * If this command is for fabric controller and HBA running - * in FIP mode send FLOGI, FDISC and LOGO as FIP frames. - */ - if ((did == Fabric_DID) && - (phba->hba_flag & HBA_FIP_SUPPORT) && - ((elscmd == ELS_CMD_FLOGI) || - (elscmd == ELS_CMD_FDISC) || - (elscmd == ELS_CMD_LOGO))) - switch (elscmd) { - case ELS_CMD_FLOGI: - elsiocb->iocb_flag |= - ((LPFC_ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT) - & LPFC_FIP_ELS_ID_MASK); - break; - case ELS_CMD_FDISC: - elsiocb->iocb_flag |= - ((LPFC_ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT) - & LPFC_FIP_ELS_ID_MASK); - break; - case ELS_CMD_LOGO: - elsiocb->iocb_flag |= - ((LPFC_ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT) - & LPFC_FIP_ELS_ID_MASK); - break; - } - else - elsiocb->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK; - - icmd = &elsiocb->iocb; - - /* fill in BDEs for command */ - /* Allocate buffer for command payload */ - pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (pcmd) - pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); - if (!pcmd || !pcmd->virt) - goto els_iocb_free_pcmb_exit; - - INIT_LIST_HEAD(&pcmd->list); - - /* Allocate buffer for response payload */ - if (expectRsp) { - prsp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (prsp) - prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, - &prsp->phys); - if (!prsp || !prsp->virt) - goto els_iocb_free_prsp_exit; - INIT_LIST_HEAD(&prsp->list); - } else - prsp = NULL; - - /* Allocate buffer for Buffer ptr list */ - pbuflist = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (pbuflist) - pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, - &pbuflist->phys); - if (!pbuflist || !pbuflist->virt) - goto els_iocb_free_pbuf_exit; - - INIT_LIST_HEAD(&pbuflist->list); - - icmd->un.elsreq64.bdl.addrHigh = putPaddrHigh(pbuflist->phys); - icmd->un.elsreq64.bdl.addrLow = putPaddrLow(pbuflist->phys); - icmd->un.elsreq64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - icmd->un.elsreq64.remoteID = did; /* DID */ - if (expectRsp) { - icmd->un.elsreq64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); - icmd->ulpCommand = CMD_ELS_REQUEST64_CR; - icmd->ulpTimeout = phba->fc_ratov * 2; - } else { - icmd->un.elsreq64.bdl.bdeSize = sizeof(struct ulp_bde64); - icmd->ulpCommand = CMD_XMIT_ELS_RSP64_CX; - } - icmd->ulpBdeCount = 1; - icmd->ulpLe = 1; - icmd->ulpClass = CLASS3; - - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { - icmd->un.elsreq64.myID = vport->fc_myDID; - - /* For ELS_REQUEST64_CR, use the VPI by default */ - icmd->ulpContext = phba->vpi_ids[vport->vpi]; - icmd->ulpCt_h = 0; - /* The CT field must be 0=INVALID_RPI for the ECHO cmd */ - if (elscmd == ELS_CMD_ECHO) - icmd->ulpCt_l = 0; /* context = invalid RPI */ - else - icmd->ulpCt_l = 1; /* context = VPI */ - } - - bpl = (struct ulp_bde64 *) pbuflist->virt; - bpl->addrLow = le32_to_cpu(putPaddrLow(pcmd->phys)); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(pcmd->phys)); - bpl->tus.f.bdeSize = cmdSize; - bpl->tus.f.bdeFlags = 0; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - - if (expectRsp) { - bpl++; - bpl->addrLow = le32_to_cpu(putPaddrLow(prsp->phys)); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(prsp->phys)); - bpl->tus.f.bdeSize = FCELSSIZE; - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - } - - /* prevent preparing iocb with NULL ndlp reference */ - elsiocb->context1 = lpfc_nlp_get(ndlp); - if (!elsiocb->context1) - goto els_iocb_free_pbuf_exit; - elsiocb->context2 = pcmd; - elsiocb->context3 = pbuflist; - elsiocb->retry = retry; - elsiocb->vport = vport; - elsiocb->drvrTimeout = (phba->fc_ratov << 1) + LPFC_DRVR_TIMEOUT; - - if (prsp) { - list_add(&prsp->list, &pcmd->list); - } - if (expectRsp) { - /* Xmit ELS command to remote NPORT */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0116 Xmit ELS command x%x to remote " - "NPORT x%x I/O tag: x%x, port state: x%x\n", - elscmd, did, elsiocb->iotag, - vport->port_state); - } else { - /* Xmit ELS response to remote NPORT */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0117 Xmit ELS response x%x to remote " - "NPORT x%x I/O tag: x%x, size: x%x\n", - elscmd, ndlp->nlp_DID, elsiocb->iotag, - cmdSize); - } - return elsiocb; - -els_iocb_free_pbuf_exit: - if (expectRsp) - lpfc_mbuf_free(phba, prsp->virt, prsp->phys); - kfree(pbuflist); - -els_iocb_free_prsp_exit: - lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); - kfree(prsp); - -els_iocb_free_pcmb_exit: - kfree(pcmd); - lpfc_sli_release_iocbq(phba, elsiocb); - return NULL; -} - -/** - * lpfc_issue_fabric_reglogin - Issue fabric registration login for a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine issues a fabric registration login for a @vport. An - * active ndlp node with Fabric_DID must already exist for this @vport. - * The routine invokes two mailbox commands to carry out fabric registration - * login through the HBA firmware: the first mailbox command requests the - * HBA to perform link configuration for the @vport; and the second mailbox - * command requests the HBA to perform the actual fabric registration login - * with the @vport. - * - * Return code - * 0 - successfully issued fabric registration login for @vport - * -ENXIO -- failed to issue fabric registration login for @vport - **/ -int -lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *mp; - struct lpfc_nodelist *ndlp; - struct serv_parm *sp; - int rc; - int err = 0; - - sp = &phba->fc_fabparam; - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - err = 1; - goto fail; - } - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - err = 2; - goto fail; - } - - vport->port_state = LPFC_FABRIC_CFG_LINK; - lpfc_config_link(phba, mbox); - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - err = 3; - goto fail_free_mbox; - } - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - err = 4; - goto fail; - } - rc = lpfc_reg_rpi(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, - ndlp->nlp_rpi); - if (rc) { - err = 5; - goto fail_free_mbox; - } - - mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; - mbox->vport = vport; - /* increment the reference count on ndlp to hold reference - * for the callback routine. - */ - mbox->context2 = lpfc_nlp_get(ndlp); - - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - err = 6; - goto fail_issue_reg_login; - } - - return 0; - -fail_issue_reg_login: - /* decrement the reference count on ndlp just incremented - * for the failed mbox command. - */ - lpfc_nlp_put(ndlp); - mp = (struct lpfc_dmabuf *) mbox->context1; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); -fail_free_mbox: - mempool_free(mbox, phba->mbox_mem_pool); - -fail: - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0249 Cannot issue Register Fabric login: Err %d\n", err); - return -ENXIO; -} - -/** - * lpfc_issue_reg_vfi - Register VFI for this vport's fabric login - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for - * the @vport. This mailbox command is necessary for SLI4 port only. - * - * Return code - * 0 - successfully issued REG_VFI for @vport - * A failure code otherwise. - **/ -int -lpfc_issue_reg_vfi(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mboxq; - struct lpfc_nodelist *ndlp; - struct serv_parm *sp; - struct lpfc_dmabuf *dmabuf; - int rc = 0; - - sp = &phba->fc_fabparam; - /* move forward in case of SLI4 FC port loopback test */ - if ((phba->sli_rev == LPFC_SLI_REV4) && - !(phba->link_flag & LS_LOOPBACK_MODE)) { - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - rc = -ENODEV; - goto fail; - } - } - - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!dmabuf) { - rc = -ENOMEM; - goto fail; - } - dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys); - if (!dmabuf->virt) { - rc = -ENOMEM; - goto fail_free_dmabuf; - } - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - rc = -ENOMEM; - goto fail_free_coherent; - } - vport->port_state = LPFC_FABRIC_CFG_LINK; - memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam)); - lpfc_reg_vfi(mboxq, vport, dmabuf->phys); - mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi; - mboxq->vport = vport; - mboxq->context1 = dmabuf; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - rc = -ENXIO; - goto fail_free_mbox; - } - return 0; - -fail_free_mbox: - mempool_free(mboxq, phba->mbox_mem_pool); -fail_free_coherent: - lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); -fail_free_dmabuf: - kfree(dmabuf); -fail: - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0289 Issue Register VFI failed: Err %d\n", rc); - return rc; -} - -/** - * lpfc_issue_unreg_vfi - Unregister VFI for this vport's fabric login - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine issues a UNREG_VFI mailbox with the vfi, vpi, fcfi triplet for - * the @vport. This mailbox command is necessary for SLI4 port only. - * - * Return code - * 0 - successfully issued REG_VFI for @vport - * A failure code otherwise. - **/ -int -lpfc_issue_unreg_vfi(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - struct Scsi_Host *shost; - LPFC_MBOXQ_t *mboxq; - int rc; - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2556 UNREG_VFI mbox allocation failed" - "HBA state x%x\n", phba->pport->port_state); - return -ENOMEM; - } - - lpfc_unreg_vfi(mboxq, vport); - mboxq->vport = vport; - mboxq->mbox_cmpl = lpfc_unregister_vfi_cmpl; - - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2557 UNREG_VFI issue mbox failed rc x%x " - "HBA state x%x\n", - rc, phba->pport->port_state); - mempool_free(mboxq, phba->mbox_mem_pool); - return -EIO; - } - - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); - return 0; -} - -/** - * lpfc_check_clean_addr_bit - Check whether assigned FCID is clean. - * @vport: pointer to a host virtual N_Port data structure. - * @sp: pointer to service parameter data structure. - * - * This routine is called from FLOGI/FDISC completion handler functions. - * lpfc_check_clean_addr_bit return 1 when FCID/Fabric portname/ Fabric - * node nodename is changed in the completion service parameter else return - * 0. This function also set flag in the vport data structure to delay - * NP_Port discovery after the FLOGI/FDISC completion if Clean address bit - * in FLOGI/FDISC response is cleared and FCID/Fabric portname/ Fabric - * node nodename is changed in the completion service parameter. - * - * Return code - * 0 - FCID and Fabric Nodename and Fabric portname is not changed. - * 1 - FCID or Fabric Nodename or Fabric portname is changed. - * - **/ -static uint8_t -lpfc_check_clean_addr_bit(struct lpfc_vport *vport, - struct serv_parm *sp) -{ - uint8_t fabric_param_changed = 0; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if ((vport->fc_prevDID != vport->fc_myDID) || - memcmp(&vport->fabric_portname, &sp->portName, - sizeof(struct lpfc_name)) || - memcmp(&vport->fabric_nodename, &sp->nodeName, - sizeof(struct lpfc_name))) - fabric_param_changed = 1; - - /* - * Word 1 Bit 31 in common service parameter is overloaded. - * Word 1 Bit 31 in FLOGI request is multiple NPort request - * Word 1 Bit 31 in FLOGI response is clean address bit - * - * If fabric parameter is changed and clean address bit is - * cleared delay nport discovery if - * - vport->fc_prevDID != 0 (not initial discovery) OR - * - lpfc_delay_discovery module parameter is set. - */ - if (fabric_param_changed && !sp->cmn.clean_address_bit && - (vport->fc_prevDID || lpfc_delay_discovery)) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_DISC_DELAYED; - spin_unlock_irq(shost->host_lock); - } - - return fabric_param_changed; -} - - -/** - * lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port - * @vport: pointer to a host virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * @sp: pointer to service parameter data structure. - * @irsp: pointer to the IOCB within the lpfc response IOCB. - * - * This routine is invoked by the lpfc_cmpl_els_flogi() completion callback - * function to handle the completion of a Fabric Login (FLOGI) into a fabric - * port in a fabric topology. It properly sets up the parameters to the @ndlp - * from the IOCB response. It also check the newly assigned N_Port ID to the - * @vport against the previously assigned N_Port ID. If it is different from - * the previously assigned Destination ID (DID), the lpfc_unreg_rpi() routine - * is invoked on all the remaining nodes with the @vport to unregister the - * Remote Port Indicators (RPIs). Finally, the lpfc_issue_fabric_reglogin() - * is invoked to register login to the fabric. - * - * Return code - * 0 - Success (currently, always return 0) - **/ -static int -lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct serv_parm *sp, IOCB_t *irsp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_nodelist *np; - struct lpfc_nodelist *next_np; - uint8_t fabric_param_changed; - - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_FABRIC; - spin_unlock_irq(shost->host_lock); - - phba->fc_edtov = be32_to_cpu(sp->cmn.e_d_tov); - if (sp->cmn.edtovResolution) /* E_D_TOV ticks are in nanoseconds */ - phba->fc_edtov = (phba->fc_edtov + 999999) / 1000000; - - phba->fc_edtovResol = sp->cmn.edtovResolution; - phba->fc_ratov = (be32_to_cpu(sp->cmn.w2.r_a_tov) + 999) / 1000; - - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PUBLIC_LOOP; - spin_unlock_irq(shost->host_lock); - } - - vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; - memcpy(&ndlp->nlp_portname, &sp->portName, sizeof(struct lpfc_name)); - memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof(struct lpfc_name)); - ndlp->nlp_class_sup = 0; - if (sp->cls1.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS1; - if (sp->cls2.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS2; - if (sp->cls3.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; - ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | - sp->cmn.bbRcvSizeLsb; - - fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp); - memcpy(&vport->fabric_portname, &sp->portName, - sizeof(struct lpfc_name)); - memcpy(&vport->fabric_nodename, &sp->nodeName, - sizeof(struct lpfc_name)); - memcpy(&phba->fc_fabparam, sp, sizeof(struct serv_parm)); - - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { - if (sp->cmn.response_multiple_NPort) { - lpfc_printf_vlog(vport, KERN_WARNING, - LOG_ELS | LOG_VPORT, - "1816 FLOGI NPIV supported, " - "response data 0x%x\n", - sp->cmn.response_multiple_NPort); - spin_lock_irq(&phba->hbalock); - phba->link_flag |= LS_NPIV_FAB_SUPPORTED; - spin_unlock_irq(&phba->hbalock); - } else { - /* Because we asked f/w for NPIV it still expects us - to call reg_vnpid atleast for the physcial host */ - lpfc_printf_vlog(vport, KERN_WARNING, - LOG_ELS | LOG_VPORT, - "1817 Fabric does not support NPIV " - "- configuring single port mode.\n"); - spin_lock_irq(&phba->hbalock); - phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; - spin_unlock_irq(&phba->hbalock); - } - } - - if (fabric_param_changed && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { - - /* If our NportID changed, we need to ensure all - * remaining NPORTs get unreg_login'ed. - */ - list_for_each_entry_safe(np, next_np, - &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(np)) - continue; - if ((np->nlp_state != NLP_STE_NPR_NODE) || - !(np->nlp_flag & NLP_NPR_ADISC)) - continue; - spin_lock_irq(shost->host_lock); - np->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - lpfc_unreg_rpi(vport, np); - } - lpfc_cleanup_pending_mbox(vport); - - if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_sli4_unreg_all_rpis(vport); - lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - /* - * If VPI is unreged, driver need to do INIT_VPI - * before re-registering - */ - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); - } - } else if ((phba->sli_rev == LPFC_SLI_REV4) && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { - /* - * Driver needs to re-reg VPI in order for f/w - * to update the MAC address. - */ - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - lpfc_register_new_vport(phba, vport, ndlp); - return 0; - } - - if (phba->sli_rev < LPFC_SLI_REV4) { - lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED && - vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) - lpfc_register_new_vport(phba, vport, ndlp); - else - lpfc_issue_fabric_reglogin(vport); - } else { - ndlp->nlp_type |= NLP_FABRIC; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - if ((!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) && - (vport->vpi_state & LPFC_VPI_REGISTERED)) { - lpfc_start_fdiscs(phba); - lpfc_do_scr_ns_plogi(phba, vport); - } else if (vport->fc_flag & FC_VFI_REGISTERED) - lpfc_issue_init_vpi(vport); - else { - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3135 Need register VFI: (x%x/%x)\n", - vport->fc_prevDID, vport->fc_myDID); - lpfc_issue_reg_vfi(vport); - } - } - return 0; -} - -/** - * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port - * @vport: pointer to a host virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * @sp: pointer to service parameter data structure. - * - * This routine is invoked by the lpfc_cmpl_els_flogi() completion callback - * function to handle the completion of a Fabric Login (FLOGI) into an N_Port - * in a point-to-point topology. First, the @vport's N_Port Name is compared - * with the received N_Port Name: if the @vport's N_Port Name is greater than - * the received N_Port Name lexicographically, this node shall assign local - * N_Port ID (PT2PT_LocalID: 1) and remote N_Port ID (PT2PT_RemoteID: 2) and - * will send out Port Login (PLOGI) with the N_Port IDs assigned. Otherwise, - * this node shall just wait for the remote node to issue PLOGI and assign - * N_Port IDs. - * - * Return code - * 0 - Success - * -ENXIO - Fail - **/ -static int -lpfc_cmpl_els_flogi_nport(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct serv_parm *sp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; - int rc; - - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); - - phba->fc_edtov = FF_DEF_EDTOV; - phba->fc_ratov = FF_DEF_RATOV; - rc = memcmp(&vport->fc_portname, &sp->portName, - sizeof(vport->fc_portname)); - if (rc >= 0) { - /* This side will initiate the PLOGI */ - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PT2PT_PLOGI; - spin_unlock_irq(shost->host_lock); - - /* - * N_Port ID cannot be 0, set our to LocalID the other - * side will be RemoteID. - */ - - /* not equal */ - if (rc) - vport->fc_myDID = PT2PT_LocalID; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - goto fail; - - lpfc_config_link(phba, mbox); - - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - goto fail; - } - /* Decrement ndlp reference count indicating that ndlp can be - * safely released when other references to it are done. - */ - lpfc_nlp_put(ndlp); - - ndlp = lpfc_findnode_did(vport, PT2PT_RemoteID); - if (!ndlp) { - /* - * Cannot find existing Fabric ndlp, so allocate a - * new one - */ - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - goto fail; - lpfc_nlp_init(vport, ndlp, PT2PT_RemoteID); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if(!ndlp) - goto fail; - } - - memcpy(&ndlp->nlp_portname, &sp->portName, - sizeof(struct lpfc_name)); - memcpy(&ndlp->nlp_nodename, &sp->nodeName, - sizeof(struct lpfc_name)); - /* Set state will put ndlp onto node list if not already done */ - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - } else - /* This side will wait for the PLOGI, decrement ndlp reference - * count indicating that ndlp can be released when other - * references to it are done. - */ - lpfc_nlp_put(ndlp); - - /* If we are pt2pt with another NPort, force NPIV off! */ - phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; - - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PT2PT; - spin_unlock_irq(shost->host_lock); - - /* Start discovery - this should just do CLEAR_LA */ - lpfc_disc_start(vport); - return 0; -fail: - return -ENXIO; -} - -/** - * lpfc_cmpl_els_flogi - Completion callback function for flogi - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the top-level completion callback function for issuing - * a Fabric Login (FLOGI) command. If the response IOCB reported error, - * the lpfc_els_retry() routine shall be invoked to retry the FLOGI. If - * retry has been made (either immediately or delayed with lpfc_els_retry() - * returning 1), the command IOCB will be released and function returned. - * If the retry attempt has been given up (possibly reach the maximum - * number of retries), one additional decrement of ndlp reference shall be - * invoked before going out after releasing the command IOCB. This will - * actually release the remote node (Note, lpfc_els_free_iocb() will also - * invoke one decrement of ndlp reference count). If no error reported in - * the IOCB status, the command Port ID field is used to determine whether - * this is a point-to-point topology or a fabric topology: if the Port ID - * field is assigned, it is a fabric topology; otherwise, it is a - * point-to-point topology. The routine lpfc_cmpl_els_flogi_fabric() or - * lpfc_cmpl_els_flogi_nport() shall be invoked accordingly to handle the - * specific topology completion conditions. - **/ -static void -lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_nodelist *ndlp = cmdiocb->context1; - struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp; - struct serv_parm *sp; - uint16_t fcf_index; - int rc; - - /* Check to see if link went down during discovery */ - if (lpfc_els_chk_latt(vport)) { - /* One additional decrement on node reference count to - * trigger the release of the node - */ - lpfc_nlp_put(ndlp); - goto out; - } - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "FLOGI cmpl: status:x%x/x%x state:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - vport->port_state); - - if (irsp->ulpStatus) { - /* - * In case of FIP mode, perform roundrobin FCF failover - * due to new FCF discovery - */ - if ((phba->hba_flag & HBA_FIP_SUPPORT) && - (phba->fcf.fcf_flag & FCF_DISCOVERY)) { - if (phba->link_state < LPFC_LINK_UP) - goto stop_rr_fcf_flogi; - if ((phba->fcoe_cvl_eventtag_attn == - phba->fcoe_cvl_eventtag) && - (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_SLI_ABORTED)) - goto stop_rr_fcf_flogi; - else - phba->fcoe_cvl_eventtag_attn = - phba->fcoe_cvl_eventtag; - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, - "2611 FLOGI failed on FCF (x%x), " - "status:x%x/x%x, tmo:x%x, perform " - "roundrobin FCF failover\n", - phba->fcf.current_rec.fcf_indx, - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout); - lpfc_sli4_set_fcf_flogi_fail(phba, - phba->fcf.current_rec.fcf_indx); - fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba); - rc = lpfc_sli4_fcf_rr_next_proc(vport, fcf_index); - if (rc) - goto out; - } - -stop_rr_fcf_flogi: - /* FLOGI failure */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2858 FLOGI failure Status:x%x/x%x TMO:x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout); - - /* Check for retry */ - if (lpfc_els_retry(phba, cmdiocb, rspiocb)) - goto out; - - /* FLOGI failure */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0100 FLOGI failure Status:x%x/x%x TMO:x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout); - - /* FLOGI failed, so there is no fabric */ - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); - - /* If private loop, then allow max outstanding els to be - * LPFC_MAX_DISC_THREADS (32). Scanning in the case of no - * alpa map would take too long otherwise. - */ - if (phba->alpa_map[0] == 0) - vport->cfg_discovery_threads = LPFC_MAX_DISC_THREADS; - if ((phba->sli_rev == LPFC_SLI_REV4) && - (!(vport->fc_flag & FC_VFI_REGISTERED) || - (vport->fc_prevDID != vport->fc_myDID))) { - if (vport->fc_flag & FC_VFI_REGISTERED) - lpfc_sli4_unreg_all_rpis(vport); - lpfc_issue_reg_vfi(vport); - lpfc_nlp_put(ndlp); - goto out; - } - goto flogifail; - } - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_CVL_RCVD; - vport->fc_flag &= ~FC_VPORT_LOGO_RCVD; - spin_unlock_irq(shost->host_lock); - - /* - * The FLogI succeeded. Sync the data for the CPU before - * accessing it. - */ - prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); - - sp = prsp->virt + sizeof(uint32_t); - - /* FLOGI completes successfully */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0101 FLOGI completes successfully " - "Data: x%x x%x x%x x%x\n", - irsp->un.ulpWord[4], sp->cmn.e_d_tov, - sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution); - - if (vport->port_state == LPFC_FLOGI) { - /* - * If Common Service Parameters indicate Nport - * we are point to point, if Fport we are Fabric. - */ - if (sp->cmn.fPort) - rc = lpfc_cmpl_els_flogi_fabric(vport, ndlp, sp, irsp); - else if (!(phba->hba_flag & HBA_FCOE_MODE)) - rc = lpfc_cmpl_els_flogi_nport(vport, ndlp, sp); - else { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_FIP | LOG_ELS, - "2831 FLOGI response with cleared Fabric " - "bit fcf_index 0x%x " - "Switch Name %02x%02x%02x%02x%02x%02x%02x%02x " - "Fabric Name " - "%02x%02x%02x%02x%02x%02x%02x%02x\n", - phba->fcf.current_rec.fcf_indx, - phba->fcf.current_rec.switch_name[0], - phba->fcf.current_rec.switch_name[1], - phba->fcf.current_rec.switch_name[2], - phba->fcf.current_rec.switch_name[3], - phba->fcf.current_rec.switch_name[4], - phba->fcf.current_rec.switch_name[5], - phba->fcf.current_rec.switch_name[6], - phba->fcf.current_rec.switch_name[7], - phba->fcf.current_rec.fabric_name[0], - phba->fcf.current_rec.fabric_name[1], - phba->fcf.current_rec.fabric_name[2], - phba->fcf.current_rec.fabric_name[3], - phba->fcf.current_rec.fabric_name[4], - phba->fcf.current_rec.fabric_name[5], - phba->fcf.current_rec.fabric_name[6], - phba->fcf.current_rec.fabric_name[7]); - lpfc_nlp_put(ndlp); - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_DISCOVERY; - phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO); - spin_unlock_irq(&phba->hbalock); - goto out; - } - if (!rc) { - /* Mark the FCF discovery process done */ - if (phba->hba_flag & HBA_FIP_SUPPORT) - lpfc_printf_vlog(vport, KERN_INFO, LOG_FIP | - LOG_ELS, - "2769 FLOGI to FCF (x%x) " - "completed successfully\n", - phba->fcf.current_rec.fcf_indx); - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_DISCOVERY; - phba->hba_flag &= ~(FCF_RR_INPROG | HBA_DEVLOSS_TMO); - spin_unlock_irq(&phba->hbalock); - goto out; - } - } - -flogifail: - lpfc_nlp_put(ndlp); - - if (!lpfc_error_lost_link(irsp)) { - /* FLOGI failed, so just use loop map to make discovery list */ - lpfc_disc_list_loopmap(vport); - - /* Start discovery */ - lpfc_disc_start(vport); - } else if (((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || - ((irsp->un.ulpWord[4] != IOERR_SLI_ABORTED) && - (irsp->un.ulpWord[4] != IOERR_SLI_DOWN))) && - (phba->link_state != LPFC_CLEAR_LA)) { - /* If FLOGI failed enable link interrupt. */ - lpfc_issue_clear_la(phba, vport); - } -out: - lpfc_els_free_iocb(phba, cmdiocb); -} - -/** - * lpfc_issue_els_flogi - Issue an flogi iocb command for a vport - * @vport: pointer to a host virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * @retry: number of retries to the command IOCB. - * - * This routine issues a Fabric Login (FLOGI) Request ELS command - * for a @vport. The initiator service parameters are put into the payload - * of the FLOGI Request IOCB and the top-level callback function pointer - * to lpfc_cmpl_els_flogi() routine is put to the IOCB completion callback - * function field. The lpfc_issue_fabric_iocb routine is invoked to send - * out FLOGI ELS command with one outstanding fabric IOCB at a time. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the FLOGI ELS command. - * - * Return code - * 0 - successfully issued flogi iocb for @vport - * 1 - failed to issue flogi iocb for @vport - **/ -static int -lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint8_t retry) -{ - struct lpfc_hba *phba = vport->phba; - struct serv_parm *sp; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli_ring *pring; - uint8_t *pcmd; - uint16_t cmdsize; - uint32_t tmo; - int rc; - - pring = &phba->sli.ring[LPFC_ELS_RING]; - - cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, - ndlp->nlp_DID, ELS_CMD_FLOGI); - - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - /* For FLOGI request, remainder of payload is service parameters */ - *((uint32_t *) (pcmd)) = ELS_CMD_FLOGI; - pcmd += sizeof(uint32_t); - memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); - sp = (struct serv_parm *) pcmd; - - /* Setup CSPs accordingly for Fabric */ - sp->cmn.e_d_tov = 0; - sp->cmn.w2.r_a_tov = 0; - sp->cmn.virtual_fabric_support = 0; - sp->cls1.classValid = 0; - sp->cls2.seqDelivery = 1; - sp->cls3.seqDelivery = 1; - if (sp->cmn.fcphLow < FC_PH3) - sp->cmn.fcphLow = FC_PH3; - if (sp->cmn.fcphHigh < FC_PH3) - sp->cmn.fcphHigh = FC_PH3; - - if (phba->sli_rev == LPFC_SLI_REV4) { - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_IF_TYPE_0) { - elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1); - elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1); - /* FLOGI needs to be 3 for WQE FCFI */ - /* Set the fcfi to the fcfi we registered with */ - elsiocb->iocb.ulpContext = phba->fcf.fcfi; - } - } else { - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { - sp->cmn.request_multiple_Nport = 1; - /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */ - icmd->ulpCt_h = 1; - icmd->ulpCt_l = 0; - } else - sp->cmn.request_multiple_Nport = 0; - } - - if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) { - icmd->un.elsreq64.myID = 0; - icmd->un.elsreq64.fl = 1; - } - - tmo = phba->fc_ratov; - phba->fc_ratov = LPFC_DISC_FLOGI_TMO; - lpfc_set_disctmo(vport); - phba->fc_ratov = tmo; - - phba->fc_stat.elsXmitFLOGI++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_flogi; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue FLOGI: opt:x%x", - phba->sli3_options, 0, 0); - - rc = lpfc_issue_fabric_iocb(phba, elsiocb); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_els_abort_flogi - Abort all outstanding flogi iocbs - * @phba: pointer to lpfc hba data structure. - * - * This routine aborts all the outstanding Fabric Login (FLOGI) IOCBs - * with a @phba. This routine walks all the outstanding IOCBs on the txcmplq - * list and issues an abort IOCB commond on each outstanding IOCB that - * contains a active Fabric_DID ndlp. Note that this function is to issue - * the abort IOCB command on all the outstanding IOCBs, thus when this - * function returns, it does not guarantee all the IOCBs are actually aborted. - * - * Return code - * 0 - Successfully issued abort iocb on all outstanding flogis (Always 0) - **/ -int -lpfc_els_abort_flogi(struct lpfc_hba *phba) -{ - struct lpfc_sli_ring *pring; - struct lpfc_iocbq *iocb, *next_iocb; - struct lpfc_nodelist *ndlp; - IOCB_t *icmd; - - /* Abort outstanding I/O on NPort */ - lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "0201 Abort outstanding I/O on NPort x%x\n", - Fabric_DID); - - pring = &phba->sli.ring[LPFC_ELS_RING]; - - /* - * Check the txcmplq for an iocb that matches the nport the driver is - * searching for. - */ - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { - icmd = &iocb->iocb; - if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR) { - ndlp = (struct lpfc_nodelist *)(iocb->context1); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (ndlp->nlp_DID == Fabric_DID)) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); - } - } - spin_unlock_irq(&phba->hbalock); - - return 0; -} - -/** - * lpfc_initial_flogi - Issue an initial fabric login for a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine issues an initial Fabric Login (FLOGI) for the @vport - * specified. It first searches the ndlp with the Fabric_DID (0xfffffe) from - * the @vport's ndlp list. If no such ndlp found, it will create an ndlp and - * put it into the @vport's ndlp list. If an inactive ndlp found on the list, - * it will just be enabled and made active. The lpfc_issue_els_flogi() routine - * is then invoked with the @vport and the ndlp to perform the FLOGI for the - * @vport. - * - * Return code - * 0 - failed to issue initial flogi for @vport - * 1 - successfully issued initial flogi for @vport - **/ -int -lpfc_initial_flogi(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_nodelist *ndlp; - - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); - - /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) { - /* Cannot find existing Fabric ndlp, so allocate a new one */ - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - return 0; - lpfc_nlp_init(vport, ndlp, Fabric_DID); - /* Set the node type */ - ndlp->nlp_type |= NLP_FABRIC; - /* Put ndlp onto node list */ - lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; - } - - if (lpfc_issue_els_flogi(vport, ndlp, 0)) { - /* This decrement of reference count to node shall kick off - * the release of the node. - */ - lpfc_nlp_put(ndlp); - return 0; - } - return 1; -} - -/** - * lpfc_initial_fdisc - Issue an initial fabric discovery for a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine issues an initial Fabric Discover (FDISC) for the @vport - * specified. It first searches the ndlp with the Fabric_DID (0xfffffe) from - * the @vport's ndlp list. If no such ndlp found, it will create an ndlp and - * put it into the @vport's ndlp list. If an inactive ndlp found on the list, - * it will just be enabled and made active. The lpfc_issue_els_fdisc() routine - * is then invoked with the @vport and the ndlp to perform the FDISC for the - * @vport. - * - * Return code - * 0 - failed to issue initial fdisc for @vport - * 1 - successfully issued initial fdisc for @vport - **/ -int -lpfc_initial_fdisc(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_nodelist *ndlp; - - /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) { - /* Cannot find existing Fabric ndlp, so allocate a new one */ - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - return 0; - lpfc_nlp_init(vport, ndlp, Fabric_DID); - /* Put ndlp onto node list */ - lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; - } - - if (lpfc_issue_els_fdisc(vport, ndlp, 0)) { - /* decrement node reference count to trigger the release of - * the node. - */ - lpfc_nlp_put(ndlp); - return 0; - } - return 1; -} - -/** - * lpfc_more_plogi - Check and issue remaining plogis for a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine checks whether there are more remaining Port Logins - * (PLOGI) to be issued for the @vport. If so, it will invoke the routine - * lpfc_els_disc_plogi() to go through the Node Port Recovery (NPR) nodes - * to issue ELS PLOGIs up to the configured discover threads with the - * @vport (@vport->cfg_discovery_threads). The function also decrement - * the @vport's num_disc_node by 1 if it is not already 0. - **/ -void -lpfc_more_plogi(struct lpfc_vport *vport) -{ - int sentplogi; - - if (vport->num_disc_nodes) - vport->num_disc_nodes--; - - /* Continue discovery with PLOGIs to go */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0232 Continue discovery with %d PLOGIs to go " - "Data: x%x x%x x%x\n", - vport->num_disc_nodes, vport->fc_plogi_cnt, - vport->fc_flag, vport->port_state); - /* Check to see if there are more PLOGIs to be sent */ - if (vport->fc_flag & FC_NLP_MORE) - /* go thru NPR nodes and issue any remaining ELS PLOGIs */ - sentplogi = lpfc_els_disc_plogi(vport); - - return; -} - -/** - * lpfc_plogi_confirm_nport - Confirm pologi wwpn matches stored ndlp - * @phba: pointer to lpfc hba data structure. - * @prsp: pointer to response IOCB payload. - * @ndlp: pointer to a node-list data structure. - * - * This routine checks and indicates whether the WWPN of an N_Port, retrieved - * from a PLOGI, matches the WWPN that is stored in the @ndlp for that N_POrt. - * The following cases are considered N_Port confirmed: - * 1) The N_Port is a Fabric ndlp; 2) The @ndlp is on vport list and matches - * the WWPN of the N_Port logged into; 3) The @ndlp is not on vport list but - * it does not have WWPN assigned either. If the WWPN is confirmed, the - * pointer to the @ndlp will be returned. If the WWPN is not confirmed: - * 1) if there is a node on vport list other than the @ndlp with the same - * WWPN of the N_Port PLOGI logged into, the lpfc_unreg_rpi() will be invoked - * on that node to release the RPI associated with the node; 2) if there is - * no node found on vport list with the same WWPN of the N_Port PLOGI logged - * into, a new node shall be allocated (or activated). In either case, the - * parameters of the @ndlp shall be copied to the new_ndlp, the @ndlp shall - * be released and the new_ndlp shall be put on to the vport node list and - * its pointer returned as the confirmed node. - * - * Note that before the @ndlp got "released", the keepDID from not-matching - * or inactive "new_ndlp" on the vport node list is assigned to the nlp_DID - * of the @ndlp. This is because the release of @ndlp is actually to put it - * into an inactive state on the vport node list and the vport node list - * management algorithm does not allow two node with a same DID. - * - * Return code - * pointer to the PLOGI N_Port @ndlp - **/ -static struct lpfc_nodelist * -lpfc_plogi_confirm_nport(struct lpfc_hba *phba, uint32_t *prsp, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_vport *vport = ndlp->vport; - struct lpfc_nodelist *new_ndlp; - struct lpfc_rport_data *rdata; - struct fc_rport *rport; - struct serv_parm *sp; - uint8_t name[sizeof(struct lpfc_name)]; - uint32_t rc, keepDID = 0; - int put_node; - int put_rport; - struct lpfc_node_rrqs rrq; - - /* Fabric nodes can have the same WWPN so we don't bother searching - * by WWPN. Just return the ndlp that was given to us. - */ - if (ndlp->nlp_type & NLP_FABRIC) - return ndlp; - - sp = (struct serv_parm *) ((uint8_t *) prsp + sizeof(uint32_t)); - memset(name, 0, sizeof(struct lpfc_name)); - - /* Now we find out if the NPort we are logging into, matches the WWPN - * we have for that ndlp. If not, we have some work to do. - */ - new_ndlp = lpfc_findnode_wwpn(vport, &sp->portName); - - if (new_ndlp == ndlp && NLP_CHK_NODE_ACT(new_ndlp)) - return ndlp; - memset(&rrq.xri_bitmap, 0, sizeof(new_ndlp->active_rrqs.xri_bitmap)); - - if (!new_ndlp) { - rc = memcmp(&ndlp->nlp_portname, name, - sizeof(struct lpfc_name)); - if (!rc) - return ndlp; - new_ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC); - if (!new_ndlp) - return ndlp; - lpfc_nlp_init(vport, new_ndlp, ndlp->nlp_DID); - } else if (!NLP_CHK_NODE_ACT(new_ndlp)) { - rc = memcmp(&ndlp->nlp_portname, name, - sizeof(struct lpfc_name)); - if (!rc) - return ndlp; - new_ndlp = lpfc_enable_node(vport, new_ndlp, - NLP_STE_UNUSED_NODE); - if (!new_ndlp) - return ndlp; - keepDID = new_ndlp->nlp_DID; - if (phba->sli_rev == LPFC_SLI_REV4) - memcpy(&rrq.xri_bitmap, - &new_ndlp->active_rrqs.xri_bitmap, - sizeof(new_ndlp->active_rrqs.xri_bitmap)); - } else { - keepDID = new_ndlp->nlp_DID; - if (phba->sli_rev == LPFC_SLI_REV4) - memcpy(&rrq.xri_bitmap, - &new_ndlp->active_rrqs.xri_bitmap, - sizeof(new_ndlp->active_rrqs.xri_bitmap)); - } - - lpfc_unreg_rpi(vport, new_ndlp); - new_ndlp->nlp_DID = ndlp->nlp_DID; - new_ndlp->nlp_prev_state = ndlp->nlp_prev_state; - if (phba->sli_rev == LPFC_SLI_REV4) - memcpy(new_ndlp->active_rrqs.xri_bitmap, - &ndlp->active_rrqs.xri_bitmap, - sizeof(ndlp->active_rrqs.xri_bitmap)); - - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) - new_ndlp->nlp_flag |= NLP_NPR_2B_DISC; - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - - /* Set state will put new_ndlp on to node list if not already done */ - lpfc_nlp_set_state(vport, new_ndlp, ndlp->nlp_state); - - /* Move this back to NPR state */ - if (memcmp(&ndlp->nlp_portname, name, sizeof(struct lpfc_name)) == 0) { - /* The new_ndlp is replacing ndlp totally, so we need - * to put ndlp on UNUSED list and try to free it. - */ - - /* Fix up the rport accordingly */ - rport = ndlp->rport; - if (rport) { - rdata = rport->dd_data; - if (rdata->pnode == ndlp) { - lpfc_nlp_put(ndlp); - ndlp->rport = NULL; - rdata->pnode = lpfc_nlp_get(new_ndlp); - new_ndlp->rport = rport; - } - new_ndlp->nlp_type = ndlp->nlp_type; - } - /* We shall actually free the ndlp with both nlp_DID and - * nlp_portname fields equals 0 to avoid any ndlp on the - * nodelist never to be used. - */ - if (ndlp->nlp_DID == 0) { - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - } - - /* Two ndlps cannot have the same did on the nodelist */ - ndlp->nlp_DID = keepDID; - if (phba->sli_rev == LPFC_SLI_REV4) - memcpy(&ndlp->active_rrqs.xri_bitmap, - &rrq.xri_bitmap, - sizeof(ndlp->active_rrqs.xri_bitmap)); - lpfc_drop_node(vport, ndlp); - } - else { - lpfc_unreg_rpi(vport, ndlp); - /* Two ndlps cannot have the same did */ - ndlp->nlp_DID = keepDID; - if (phba->sli_rev == LPFC_SLI_REV4) - memcpy(&ndlp->active_rrqs.xri_bitmap, - &rrq.xri_bitmap, - sizeof(ndlp->active_rrqs.xri_bitmap)); - /* Since we are swapping the ndlp passed in with the new one - * and the did has already been swapped, copy over the - * state and names. - */ - memcpy(&new_ndlp->nlp_portname, &ndlp->nlp_portname, - sizeof(struct lpfc_name)); - memcpy(&new_ndlp->nlp_nodename, &ndlp->nlp_nodename, - sizeof(struct lpfc_name)); - new_ndlp->nlp_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - /* Fix up the rport accordingly */ - rport = ndlp->rport; - if (rport) { - rdata = rport->dd_data; - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); - } - } - return new_ndlp; -} - -/** - * lpfc_end_rscn - Check and handle more rscn for a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine checks whether more Registration State Change - * Notifications (RSCNs) came in while the discovery state machine was in - * the FC_RSCN_MODE. If so, the lpfc_els_handle_rscn() routine will be - * invoked to handle the additional RSCNs for the @vport. Otherwise, the - * FC_RSCN_MODE bit will be cleared with the @vport to mark as the end of - * handling the RSCNs. - **/ -void -lpfc_end_rscn(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (vport->fc_flag & FC_RSCN_MODE) { - /* - * Check to see if more RSCNs came in while we were - * processing this one. - */ - if (vport->fc_rscn_id_cnt || - (vport->fc_flag & FC_RSCN_DISCOVERY) != 0) - lpfc_els_handle_rscn(vport); - else { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - } - } -} - -/** - * lpfc_cmpl_els_rrq - Completion handled for els RRQs. - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine will call the clear rrq function to free the rrq and - * clear the xri's bit in the ndlp's xri_bitmap. If the ndlp does not - * exist then the clear_rrq is still called because the rrq needs to - * be freed. - **/ - -static void -lpfc_cmpl_els_rrq(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - IOCB_t *irsp; - struct lpfc_nodelist *ndlp; - struct lpfc_node_rrq *rrq; - - /* we pass cmdiocb to state machine which needs rspiocb as well */ - rrq = cmdiocb->context_un.rrq; - cmdiocb->context_un.rsp_iocb = rspiocb; - - irsp = &rspiocb->iocb; - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "RRQ cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->un.elsreq64.remoteID); - - ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || ndlp != rrq->ndlp) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2882 RRQ completes to NPort x%x " - "with no ndlp. Data: x%x x%x x%x\n", - irsp->un.elsreq64.remoteID, - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpIoTag); - goto out; - } - - /* rrq completes to NPort */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "2880 RRQ completes to NPort x%x " - "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, rrq->xritag, rrq->rxid); - - if (irsp->ulpStatus) { - /* Check for retry */ - /* RRQ failed Don't print the vport to vport rjts */ - if (irsp->ulpStatus != IOSTAT_LS_RJT || - (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) && - ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) || - (phba)->pport->cfg_log_verbose & LOG_ELS) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2881 RRQ failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); - } -out: - if (rrq) - lpfc_clr_rrq_active(phba, rrq->xritag, rrq); - lpfc_els_free_iocb(phba, cmdiocb); - return; -} -/** - * lpfc_cmpl_els_plogi - Completion callback function for plogi - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the completion callback function for issuing the Port - * Login (PLOGI) command. For PLOGI completion, there must be an active - * ndlp on the vport node list that matches the remote node ID from the - * PLOGI response IOCB. If such ndlp does not exist, the PLOGI is simply - * ignored and command IOCB released. The PLOGI response IOCB status is - * checked for error conditons. If there is error status reported, PLOGI - * retry shall be attempted by invoking the lpfc_els_retry() routine. - * Otherwise, the lpfc_plogi_confirm_nport() routine shall be invoked on - * the ndlp and the NLP_EVT_CMPL_PLOGI state to the Discover State Machine - * (DSM) is set for this PLOGI completion. Finally, it checks whether - * there are additional N_Port nodes with the vport that need to perform - * PLOGI. If so, the lpfc_more_plogi() routine is invoked to issue addition - * PLOGIs. - **/ -static void -lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp; - struct lpfc_nodelist *ndlp; - struct lpfc_dmabuf *prsp; - int disc, rc, did, type; - - /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; - - irsp = &rspiocb->iocb; - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "PLOGI cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->un.elsreq64.remoteID); - - ndlp = lpfc_findnode_did(vport, irsp->un.elsreq64.remoteID); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0136 PLOGI completes to NPort x%x " - "with no ndlp. Data: x%x x%x x%x\n", - irsp->un.elsreq64.remoteID, - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpIoTag); - goto out; - } - - /* Since ndlp can be freed in the disc state machine, note if this node - * is being used during discovery. - */ - spin_lock_irq(shost->host_lock); - disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - rc = 0; - - /* PLOGI completes to NPort */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0102 PLOGI completes to NPort x%x " - "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, disc, vport->num_disc_nodes); - /* Check to see if link went down during discovery */ - if (lpfc_els_chk_latt(vport)) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - goto out; - } - - /* ndlp could be freed in DSM, save these values now */ - type = ndlp->nlp_type; - did = ndlp->nlp_DID; - - if (irsp->ulpStatus) { - /* Check for retry */ - if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { - /* ELS command is being retried */ - if (disc) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - } - goto out; - } - /* PLOGI failed Don't print the vport to vport rjts */ - if (irsp->ulpStatus != IOSTAT_LS_RJT || - (((irsp->un.ulpWord[4]) >> 16 != LSRJT_INVALID_CMD) && - ((irsp->un.ulpWord[4]) >> 16 != LSRJT_UNABLE_TPC)) || - (phba)->pport->cfg_log_verbose & LOG_ELS) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2753 PLOGI failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); - /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) - rc = NLP_STE_FREED_NODE; - else - rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_PLOGI); - } else { - /* Good status, call state machine */ - prsp = list_entry(((struct lpfc_dmabuf *) - cmdiocb->context2)->list.next, - struct lpfc_dmabuf, list); - ndlp = lpfc_plogi_confirm_nport(phba, prsp->virt, ndlp); - rc = lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_PLOGI); - } - - if (disc && vport->num_disc_nodes) { - /* Check to see if there are more PLOGIs to be sent */ - lpfc_more_plogi(vport); - - if (vport->num_disc_nodes == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); - - lpfc_can_disctmo(vport); - lpfc_end_rscn(vport); - } - } - -out: - lpfc_els_free_iocb(phba, cmdiocb); - return; -} - -/** - * lpfc_issue_els_plogi - Issue an plogi iocb command for a vport - * @vport: pointer to a host virtual N_Port data structure. - * @did: destination port identifier. - * @retry: number of retries to the command IOCB. - * - * This routine issues a Port Login (PLOGI) command to a remote N_Port - * (with the @did) for a @vport. Before issuing a PLOGI to a remote N_Port, - * the ndlp with the remote N_Port DID must exist on the @vport's ndlp list. - * This routine constructs the proper feilds of the PLOGI IOCB and invokes - * the lpfc_sli_issue_iocb() routine to send out PLOGI ELS command. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the PLOGI ELS command. - * - * Return code - * 0 - Successfully issued a plogi for @vport - * 1 - failed to issue a plogi for @vport - **/ -int -lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) -{ - struct lpfc_hba *phba = vport->phba; - struct serv_parm *sp; - IOCB_t *icmd; - struct lpfc_nodelist *ndlp; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; - uint8_t *pcmd; - uint16_t cmdsize; - int ret; - - psli = &phba->sli; - - ndlp = lpfc_findnode_did(vport, did); - if (ndlp && !NLP_CHK_NODE_ACT(ndlp)) - ndlp = NULL; - - /* If ndlp is not NULL, we will bump the reference count on it */ - cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, - ELS_CMD_PLOGI); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - /* For PLOGI request, remainder of payload is service parameters */ - *((uint32_t *) (pcmd)) = ELS_CMD_PLOGI; - pcmd += sizeof(uint32_t); - memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); - sp = (struct serv_parm *) pcmd; - - /* - * If we are a N-port connected to a Fabric, fix-up paramm's so logins - * to device on remote loops work. - */ - if ((vport->fc_flag & FC_FABRIC) && !(vport->fc_flag & FC_PUBLIC_LOOP)) - sp->cmn.altBbCredit = 1; - - if (sp->cmn.fcphLow < FC_PH_4_3) - sp->cmn.fcphLow = FC_PH_4_3; - - if (sp->cmn.fcphHigh < FC_PH3) - sp->cmn.fcphHigh = FC_PH3; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue PLOGI: did:x%x", - did, 0, 0); - - phba->fc_stat.elsXmitPLOGI++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_plogi; - ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - - if (ret == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_cmpl_els_prli - Completion callback function for prli - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the completion callback function for a Process Login - * (PRLI) ELS command. The PRLI response IOCB status is checked for error - * status. If there is error status reported, PRLI retry shall be attempted - * by invoking the lpfc_els_retry() routine. Otherwise, the state - * NLP_EVT_CMPL_PRLI is sent to the Discover State Machine (DSM) for this - * ndlp to mark the PRLI completion. - **/ -static void -lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp; - struct lpfc_sli *psli; - struct lpfc_nodelist *ndlp; - - psli = &phba->sli; - /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; - - irsp = &(rspiocb->iocb); - ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_PRLI_SND; - spin_unlock_irq(shost->host_lock); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "PRLI cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - ndlp->nlp_DID); - /* PRLI completes to NPort */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0103 PRLI completes to NPort x%x " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, vport->num_disc_nodes); - - vport->fc_prli_sent--; - /* Check to see if link went down during discovery */ - if (lpfc_els_chk_latt(vport)) - goto out; - - if (irsp->ulpStatus) { - /* Check for retry */ - if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { - /* ELS command is being retried */ - goto out; - } - /* PRLI failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2754 PRLI failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); - /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) - goto out; - else - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_PRLI); - } else - /* Good status, call state machine */ - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_PRLI); -out: - lpfc_els_free_iocb(phba, cmdiocb); - return; -} - -/** - * lpfc_issue_els_prli - Issue a prli iocb command for a vport - * @vport: pointer to a host virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * @retry: number of retries to the command IOCB. - * - * This routine issues a Process Login (PRLI) ELS command for the - * @vport. The PRLI service parameters are set up in the payload of the - * PRLI Request command and the pointer to lpfc_cmpl_els_prli() routine - * is put to the IOCB completion callback func field before invoking the - * routine lpfc_sli_issue_iocb() to send out PRLI command. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the PRLI ELS command. - * - * Return code - * 0 - successfully issued prli iocb command for @vport - * 1 - failed to issue prli iocb command for @vport - **/ -int -lpfc_issue_els_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint8_t retry) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - PRLI *npr; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - uint8_t *pcmd; - uint16_t cmdsize; - - cmdsize = (sizeof(uint32_t) + sizeof(PRLI)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, - ndlp->nlp_DID, ELS_CMD_PRLI); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - /* For PRLI request, remainder of payload is service parameters */ - memset(pcmd, 0, (sizeof(PRLI) + sizeof(uint32_t))); - *((uint32_t *) (pcmd)) = ELS_CMD_PRLI; - pcmd += sizeof(uint32_t); - - /* For PRLI, remainder of payload is PRLI parameter page */ - npr = (PRLI *) pcmd; - /* - * If our firmware version is 3.20 or later, - * set the following bits for FC-TAPE support. - */ - if (phba->vpd.rev.feaLevelHigh >= 0x02) { - npr->ConfmComplAllowed = 1; - npr->Retry = 1; - npr->TaskRetryIdReq = 1; - } - npr->estabImagePair = 1; - npr->readXferRdyDis = 1; - - /* For FCP support */ - npr->prliType = PRLI_FCP_TYPE; - npr->initiatorFunc = 1; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue PRLI: did:x%x", - ndlp->nlp_DID, 0, 0); - - phba->fc_stat.elsXmitPRLI++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_prli; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_PRLI_SND; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_PRLI_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - vport->fc_prli_sent++; - return 0; -} - -/** - * lpfc_rscn_disc - Perform rscn discovery for a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine performs Registration State Change Notification (RSCN) - * discovery for a @vport. If the @vport's node port recovery count is not - * zero, it will invoke the lpfc_els_disc_plogi() to perform PLOGI for all - * the nodes that need recovery. If none of the PLOGI were needed through - * the lpfc_els_disc_plogi() routine, the lpfc_end_rscn() routine shall be - * invoked to check and handle possible more RSCN came in during the period - * of processing the current ones. - **/ -static void -lpfc_rscn_disc(struct lpfc_vport *vport) -{ - lpfc_can_disctmo(vport); - - /* RSCN discovery */ - /* go thru NPR nodes and issue ELS PLOGIs */ - if (vport->fc_npr_cnt) - if (lpfc_els_disc_plogi(vport)) - return; - - lpfc_end_rscn(vport); -} - -/** - * lpfc_adisc_done - Complete the adisc phase of discovery - * @vport: pointer to lpfc_vport hba data structure that finished all ADISCs. - * - * This function is called when the final ADISC is completed during discovery. - * This function handles clearing link attention or issuing reg_vpi depending - * on whether npiv is enabled. This function also kicks off the PLOGI phase of - * discovery. - * This function is called with no locks held. - **/ -static void -lpfc_adisc_done(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - - /* - * For NPIV, cmpl_reg_vpi will set port_state to READY, - * and continue discovery. - */ - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - !(vport->fc_flag & FC_RSCN_MODE) && - (phba->sli_rev < LPFC_SLI_REV4)) { - lpfc_issue_reg_vpi(phba, vport); - return; - } - /* - * For SLI2, we need to set port_state to READY - * and continue discovery. - */ - if (vport->port_state < LPFC_VPORT_READY) { - /* If we get here, there is nothing to ADISC */ - if (vport->port_type == LPFC_PHYSICAL_PORT) - lpfc_issue_clear_la(phba, vport); - if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { - vport->num_disc_nodes = 0; - /* go thru NPR list, issue ELS PLOGIs */ - if (vport->fc_npr_cnt) - lpfc_els_disc_plogi(vport); - if (!vport->num_disc_nodes) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - lpfc_end_rscn(vport); - } - } - vport->port_state = LPFC_VPORT_READY; - } else - lpfc_rscn_disc(vport); -} - -/** - * lpfc_more_adisc - Issue more adisc as needed - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine determines whether there are more ndlps on a @vport - * node list need to have Address Discover (ADISC) issued. If so, it will - * invoke the lpfc_els_disc_adisc() routine to issue ADISC on the @vport's - * remaining nodes which need to have ADISC sent. - **/ -void -lpfc_more_adisc(struct lpfc_vport *vport) -{ - int sentadisc; - - if (vport->num_disc_nodes) - vport->num_disc_nodes--; - /* Continue discovery with ADISCs to go */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0210 Continue discovery with %d ADISCs to go " - "Data: x%x x%x x%x\n", - vport->num_disc_nodes, vport->fc_adisc_cnt, - vport->fc_flag, vport->port_state); - /* Check to see if there are more ADISCs to be sent */ - if (vport->fc_flag & FC_NLP_MORE) { - lpfc_set_disctmo(vport); - /* go thru NPR nodes and issue any remaining ELS ADISCs */ - sentadisc = lpfc_els_disc_adisc(vport); - } - if (!vport->num_disc_nodes) - lpfc_adisc_done(vport); - return; -} - -/** - * lpfc_cmpl_els_adisc - Completion callback function for adisc - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the completion function for issuing the Address Discover - * (ADISC) command. It first checks to see whether link went down during - * the discovery process. If so, the node will be marked as node port - * recovery for issuing discover IOCB by the link attention handler and - * exit. Otherwise, the response status is checked. If error was reported - * in the response status, the ADISC command shall be retried by invoking - * the lpfc_els_retry() routine. Otherwise, if no error was reported in - * the response status, the state machine is invoked to set transition - * with respect to NLP_EVT_CMPL_ADISC event. - **/ -static void -lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp; - struct lpfc_nodelist *ndlp; - int disc; - - /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; - - irsp = &(rspiocb->iocb); - ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "ADISC cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - ndlp->nlp_DID); - - /* Since ndlp can be freed in the disc state machine, note if this node - * is being used during discovery. - */ - spin_lock_irq(shost->host_lock); - disc = (ndlp->nlp_flag & NLP_NPR_2B_DISC); - ndlp->nlp_flag &= ~(NLP_ADISC_SND | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - /* ADISC completes to NPort */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0104 ADISC completes to NPort x%x " - "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, disc, vport->num_disc_nodes); - /* Check to see if link went down during discovery */ - if (lpfc_els_chk_latt(vport)) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - goto out; - } - - if (irsp->ulpStatus) { - /* Check for retry */ - if (lpfc_els_retry(phba, cmdiocb, rspiocb)) { - /* ELS command is being retried */ - if (disc) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - lpfc_set_disctmo(vport); - } - goto out; - } - /* ADISC failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2755 ADISC failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); - /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (!lpfc_error_lost_link(irsp)) - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_ADISC); - } else - /* Good status, call state machine */ - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_ADISC); - - /* Check to see if there are more ADISCs to be sent */ - if (disc && vport->num_disc_nodes) - lpfc_more_adisc(vport); -out: - lpfc_els_free_iocb(phba, cmdiocb); - return; -} - -/** - * lpfc_issue_els_adisc - Issue an address discover iocb to an node on a vport - * @vport: pointer to a virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * @retry: number of retries to the command IOCB. - * - * This routine issues an Address Discover (ADISC) for an @ndlp on a - * @vport. It prepares the payload of the ADISC ELS command, updates the - * and states of the ndlp, and invokes the lpfc_sli_issue_iocb() routine - * to issue the ADISC ELS command. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the ADISC ELS command. - * - * Return code - * 0 - successfully issued adisc - * 1 - failed to issue adisc - **/ -int -lpfc_issue_els_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint8_t retry) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - ADISC *ap; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - uint8_t *pcmd; - uint16_t cmdsize; - - cmdsize = (sizeof(uint32_t) + sizeof(ADISC)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, - ndlp->nlp_DID, ELS_CMD_ADISC); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - /* For ADISC request, remainder of payload is service parameters */ - *((uint32_t *) (pcmd)) = ELS_CMD_ADISC; - pcmd += sizeof(uint32_t); - - /* Fill in ADISC payload */ - ap = (ADISC *) pcmd; - ap->hardAL_PA = phba->fc_pref_ALPA; - memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name)); - memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); - ap->DID = be32_to_cpu(vport->fc_myDID); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue ADISC: did:x%x", - ndlp->nlp_DID, 0, 0); - - phba->fc_stat.elsXmitADISC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_adisc; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_ADISC_SND; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_ADISC_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_cmpl_els_logo - Completion callback function for logo - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the completion function for issuing the ELS Logout (LOGO) - * command. If no error status was reported from the LOGO response, the - * state machine of the associated ndlp shall be invoked for transition with - * respect to NLP_EVT_CMPL_LOGO event. Otherwise, if error status was reported, - * the lpfc_els_retry() routine will be invoked to retry the LOGO command. - **/ -static void -lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - struct lpfc_vport *vport = ndlp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp; - struct lpfc_sli *psli; - struct lpfcMboxq *mbox; - - psli = &phba->sli; - /* we pass cmdiocb to state machine which needs rspiocb as well */ - cmdiocb->context_un.rsp_iocb = rspiocb; - - irsp = &(rspiocb->iocb); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "LOGO cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - ndlp->nlp_DID); - /* LOGO completes to NPort */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0105 LOGO completes to NPort x%x " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, vport->num_disc_nodes); - /* Check to see if link went down during discovery */ - if (lpfc_els_chk_latt(vport)) - goto out; - - if (ndlp->nlp_flag & NLP_TARGET_REMOVE) { - /* NLP_EVT_DEVICE_RM should unregister the RPI - * which should abort all outstanding IOs. - */ - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_DEVICE_RM); - goto out; - } - - if (irsp->ulpStatus) { - /* Check for retry */ - if (lpfc_els_retry(phba, cmdiocb, rspiocb)) - /* ELS command is being retried */ - goto out; - /* LOGO failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2756 LOGO failure DID:%06X Status:x%x/x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, - irsp->un.ulpWord[4]); - /* Do not call DSM for lpfc_els_abort'ed ELS cmds */ - if (lpfc_error_lost_link(irsp)) - goto out; - else - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_LOGO); - } else - /* Good status, call state machine. - * This will unregister the rpi if needed. - */ - lpfc_disc_state_machine(vport, ndlp, cmdiocb, - NLP_EVT_CMPL_LOGO); -out: - lpfc_els_free_iocb(phba, cmdiocb); - /* If we are in pt2pt mode, we could rcv new S_ID on PLOGI */ - if ((vport->fc_flag & FC_PT2PT) && - !(vport->fc_flag & FC_PT2PT_PLOGI)) { - phba->pport->fc_myDID = 0; - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox) { - lpfc_config_link(phba, mbox); - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == - MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - } - } - } - return; -} - -/** - * lpfc_issue_els_logo - Issue a logo to an node on a vport - * @vport: pointer to a virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * @retry: number of retries to the command IOCB. - * - * This routine constructs and issues an ELS Logout (LOGO) iocb command - * to a remote node, referred by an @ndlp on a @vport. It constructs the - * payload of the IOCB, properly sets up the @ndlp state, and invokes the - * lpfc_sli_issue_iocb() routine to send out the LOGO ELS command. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the LOGO ELS command. - * - * Return code - * 0 - successfully issued logo - * 1 - failed to issue logo - **/ -int -lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint8_t retry) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - uint8_t *pcmd; - uint16_t cmdsize; - int rc; - - spin_lock_irq(shost->host_lock); - if (ndlp->nlp_flag & NLP_LOGO_SND) { - spin_unlock_irq(shost->host_lock); - return 0; - } - spin_unlock_irq(shost->host_lock); - - cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, - ndlp->nlp_DID, ELS_CMD_LOGO); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; - pcmd += sizeof(uint32_t); - - /* Fill in LOGO payload */ - *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID); - pcmd += sizeof(uint32_t); - memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name)); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue LOGO: did:x%x", - ndlp->nlp_DID, 0, 0); - - phba->fc_stat.elsXmitLOGO++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_logo; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - - if (rc == IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_cmpl_els_cmd - Completion callback function for generic els command - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is a generic completion callback function for ELS commands. - * Specifically, it is the callback function which does not need to perform - * any command specific operations. It is currently used by the ELS command - * issuing routines for the ELS State Change Request (SCR), - * lpfc_issue_els_scr(), and the ELS Fibre Channel Address Resolution - * Protocol Response (FARPR) routine, lpfc_issue_els_farpr(). Other than - * certain debug loggings, this callback function simply invokes the - * lpfc_els_chk_latt() routine to check whether link went down during the - * discovery process. - **/ -static void -lpfc_cmpl_els_cmd(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - IOCB_t *irsp; - - irsp = &rspiocb->iocb; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "ELS cmd cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->un.elsreq64.remoteID); - /* ELS cmd tag completes */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0106 ELS cmd tag x%x completes Data: x%x x%x x%x\n", - irsp->ulpIoTag, irsp->ulpStatus, - irsp->un.ulpWord[4], irsp->ulpTimeout); - /* Check to see if link went down during discovery */ - lpfc_els_chk_latt(vport); - lpfc_els_free_iocb(phba, cmdiocb); - return; -} - -/** - * lpfc_issue_els_scr - Issue a scr to an node on a vport - * @vport: pointer to a host virtual N_Port data structure. - * @nportid: N_Port identifier to the remote node. - * @retry: number of retries to the command IOCB. - * - * This routine issues a State Change Request (SCR) to a fabric node - * on a @vport. The remote node @nportid is passed into the function. It - * first search the @vport node list to find the matching ndlp. If no such - * ndlp is found, a new ndlp shall be created for this (SCR) purpose. An - * IOCB is allocated, payload prepared, and the lpfc_sli_issue_iocb() - * routine is invoked to send the SCR IOCB. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the SCR ELS command. - * - * Return code - * 0 - Successfully issued scr command - * 1 - Failed to issue scr command - **/ -int -lpfc_issue_els_scr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) -{ - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; - uint8_t *pcmd; - uint16_t cmdsize; - struct lpfc_nodelist *ndlp; - - psli = &phba->sli; - cmdsize = (sizeof(uint32_t) + sizeof(SCR)); - - ndlp = lpfc_findnode_did(vport, nportid); - if (!ndlp) { - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - return 1; - lpfc_nlp_init(vport, ndlp, nportid); - lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; - } - - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, - ndlp->nlp_DID, ELS_CMD_SCR); - - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); - return 1; - } - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - *((uint32_t *) (pcmd)) = ELS_CMD_SCR; - pcmd += sizeof(uint32_t); - - /* For SCR, remainder of payload is SCR parameter page */ - memset(pcmd, 0, sizeof(SCR)); - ((SCR *) pcmd)->Function = SCR_FUNC_FULL; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue SCR: did:x%x", - ndlp->nlp_DID, 0, 0); - - phba->fc_stat.elsXmitSCR++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the rlease of - * the node. - */ - lpfc_nlp_put(ndlp); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - /* This will cause the callback-function lpfc_cmpl_els_cmd to - * trigger the release of node. - */ - lpfc_nlp_put(ndlp); - return 0; -} - -/** - * lpfc_issue_els_farpr - Issue a farp to an node on a vport - * @vport: pointer to a host virtual N_Port data structure. - * @nportid: N_Port identifier to the remote node. - * @retry: number of retries to the command IOCB. - * - * This routine issues a Fibre Channel Address Resolution Response - * (FARPR) to a node on a vport. The remote node N_Port identifier (@nportid) - * is passed into the function. It first search the @vport node list to find - * the matching ndlp. If no such ndlp is found, a new ndlp shall be created - * for this (FARPR) purpose. An IOCB is allocated, payload prepared, and the - * lpfc_sli_issue_iocb() routine is invoked to send the FARPR ELS command. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the PARPR ELS command. - * - * Return code - * 0 - Successfully issued farpr command - * 1 - Failed to issue farpr command - **/ -static int -lpfc_issue_els_farpr(struct lpfc_vport *vport, uint32_t nportid, uint8_t retry) -{ - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; - FARP *fp; - uint8_t *pcmd; - uint32_t *lp; - uint16_t cmdsize; - struct lpfc_nodelist *ondlp; - struct lpfc_nodelist *ndlp; - - psli = &phba->sli; - cmdsize = (sizeof(uint32_t) + sizeof(FARP)); - - ndlp = lpfc_findnode_did(vport, nportid); - if (!ndlp) { - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - return 1; - lpfc_nlp_init(vport, ndlp, nportid); - lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 1; - } - - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, - ndlp->nlp_DID, ELS_CMD_RNID); - if (!elsiocb) { - /* This will trigger the release of the node just - * allocated - */ - lpfc_nlp_put(ndlp); - return 1; - } - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - *((uint32_t *) (pcmd)) = ELS_CMD_FARPR; - pcmd += sizeof(uint32_t); - - /* Fill in FARPR payload */ - fp = (FARP *) (pcmd); - memset(fp, 0, sizeof(FARP)); - lp = (uint32_t *) pcmd; - *lp++ = be32_to_cpu(nportid); - *lp++ = be32_to_cpu(vport->fc_myDID); - fp->Rflags = 0; - fp->Mflags = (FARP_MATCH_PORT | FARP_MATCH_NODE); - - memcpy(&fp->RportName, &vport->fc_portname, sizeof(struct lpfc_name)); - memcpy(&fp->RnodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); - ondlp = lpfc_findnode_did(vport, nportid); - if (ondlp && NLP_CHK_NODE_ACT(ondlp)) { - memcpy(&fp->OportName, &ondlp->nlp_portname, - sizeof(struct lpfc_name)); - memcpy(&fp->OnodeName, &ondlp->nlp_nodename, - sizeof(struct lpfc_name)); - } - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue FARPR: did:x%x", - ndlp->nlp_DID, 0, 0); - - phba->fc_stat.elsXmitFARPR++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_cmd; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - /* The additional lpfc_nlp_put will cause the following - * lpfc_els_free_iocb routine to trigger the release of - * the node. - */ - lpfc_nlp_put(ndlp); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - /* This will cause the callback-function lpfc_cmpl_els_cmd to - * trigger the release of the node. - */ - lpfc_nlp_put(ndlp); - return 0; -} - -/** - * lpfc_cancel_retry_delay_tmo - Cancel the timer with delayed iocb-cmd retry - * @vport: pointer to a host virtual N_Port data structure. - * @nlp: pointer to a node-list data structure. - * - * This routine cancels the timer with a delayed IOCB-command retry for - * a @vport's @ndlp. It stops the timer for the delayed function retrial and - * removes the ELS retry event if it presents. In addition, if the - * NLP_NPR_2B_DISC bit is set in the @nlp's nlp_flag bitmap, ADISC IOCB - * commands are sent for the @vport's nodes that require issuing discovery - * ADISC. - **/ -void -lpfc_cancel_retry_delay_tmo(struct lpfc_vport *vport, struct lpfc_nodelist *nlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_work_evt *evtp; - - if (!(nlp->nlp_flag & NLP_DELAY_TMO)) - return; - spin_lock_irq(shost->host_lock); - nlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - del_timer_sync(&nlp->nlp_delayfunc); - nlp->nlp_last_elscmd = 0; - if (!list_empty(&nlp->els_retry_evt.evt_listp)) { - list_del_init(&nlp->els_retry_evt.evt_listp); - /* Decrement nlp reference count held for the delayed retry */ - evtp = &nlp->els_retry_evt; - lpfc_nlp_put((struct lpfc_nodelist *)evtp->evt_arg1); - } - if (nlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); - nlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - if (vport->num_disc_nodes) { - if (vport->port_state < LPFC_VPORT_READY) { - /* Check if there are more ADISCs to be sent */ - lpfc_more_adisc(vport); - } else { - /* Check if there are more PLOGIs to be sent */ - lpfc_more_plogi(vport); - if (vport->num_disc_nodes == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - lpfc_end_rscn(vport); - } - } - } - } - return; -} - -/** - * lpfc_els_retry_delay - Timer function with a ndlp delayed function timer - * @ptr: holder for the pointer to the timer function associated data (ndlp). - * - * This routine is invoked by the ndlp delayed-function timer to check - * whether there is any pending ELS retry event(s) with the node. If not, it - * simply returns. Otherwise, if there is at least one ELS delayed event, it - * adds the delayed events to the HBA work list and invokes the - * lpfc_worker_wake_up() routine to wake up worker thread to process the - * event. Note that lpfc_nlp_get() is called before posting the event to - * the work list to hold reference count of ndlp so that it guarantees the - * reference to ndlp will still be available when the worker thread gets - * to the event associated with the ndlp. - **/ -void -lpfc_els_retry_delay(unsigned long ptr) -{ - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr; - struct lpfc_vport *vport = ndlp->vport; - struct lpfc_hba *phba = vport->phba; - unsigned long flags; - struct lpfc_work_evt *evtp = &ndlp->els_retry_evt; - - spin_lock_irqsave(&phba->hbalock, flags); - if (!list_empty(&evtp->evt_listp)) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return; - } - - /* We need to hold the node by incrementing the reference - * count until the queued work is done - */ - evtp->evt_arg1 = lpfc_nlp_get(ndlp); - if (evtp->evt_arg1) { - evtp->evt = LPFC_EVT_ELS_RETRY; - list_add_tail(&evtp->evt_listp, &phba->work_list); - lpfc_worker_wake_up(phba); - } - spin_unlock_irqrestore(&phba->hbalock, flags); - return; -} - -/** - * lpfc_els_retry_delay_handler - Work thread handler for ndlp delayed function - * @ndlp: pointer to a node-list data structure. - * - * This routine is the worker-thread handler for processing the @ndlp delayed - * event(s), posted by the lpfc_els_retry_delay() routine. It simply retrieves - * the last ELS command from the associated ndlp and invokes the proper ELS - * function according to the delayed ELS command to retry the command. - **/ -void -lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) -{ - struct lpfc_vport *vport = ndlp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - uint32_t cmd, did, retry; - - spin_lock_irq(shost->host_lock); - did = ndlp->nlp_DID; - cmd = ndlp->nlp_last_elscmd; - ndlp->nlp_last_elscmd = 0; - - if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { - spin_unlock_irq(shost->host_lock); - return; - } - - ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - /* - * If a discovery event readded nlp_delayfunc after timer - * firing and before processing the timer, cancel the - * nlp_delayfunc. - */ - del_timer_sync(&ndlp->nlp_delayfunc); - retry = ndlp->nlp_retry; - ndlp->nlp_retry = 0; - - switch (cmd) { - case ELS_CMD_FLOGI: - lpfc_issue_els_flogi(vport, ndlp, retry); - break; - case ELS_CMD_PLOGI: - if (!lpfc_issue_els_plogi(vport, ndlp->nlp_DID, retry)) { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - } - break; - case ELS_CMD_ADISC: - if (!lpfc_issue_els_adisc(vport, ndlp, retry)) { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); - } - break; - case ELS_CMD_PRLI: - if (!lpfc_issue_els_prli(vport, ndlp, retry)) { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); - } - break; - case ELS_CMD_LOGO: - if (!lpfc_issue_els_logo(vport, ndlp, retry)) { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - } - break; - case ELS_CMD_FDISC: - if (!(vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI)) - lpfc_issue_els_fdisc(vport, ndlp, retry); - break; - } - return; -} - -/** - * lpfc_els_retry - Make retry decision on an els command iocb - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine makes a retry decision on an ELS command IOCB, which has - * failed. The following ELS IOCBs use this function for retrying the command - * when previously issued command responsed with error status: FLOGI, PLOGI, - * PRLI, ADISC, LOGO, and FDISC. Based on the ELS command type and the - * returned error status, it makes the decision whether a retry shall be - * issued for the command, and whether a retry shall be made immediately or - * delayed. In the former case, the corresponding ELS command issuing-function - * is called to retry the command. In the later case, the ELS command shall - * be posted to the ndlp delayed event and delayed function timer set to the - * ndlp for the delayed command issusing. - * - * Return code - * 0 - No retry of els command is made - * 1 - Immediate or delayed retry of els command is made - **/ -static int -lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - uint32_t *elscmd; - struct ls_rjt stat; - int retry = 0, maxretry = lpfc_max_els_tries, delay = 0; - int logerr = 0; - uint32_t cmd = 0; - uint32_t did; - - - /* Note: context2 may be 0 for internal driver abort - * of delays ELS command. - */ - - if (pcmd && pcmd->virt) { - elscmd = (uint32_t *) (pcmd->virt); - cmd = *elscmd++; - } - - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) - did = ndlp->nlp_DID; - else { - /* We should only hit this case for retrying PLOGI */ - did = irsp->un.elsreq64.remoteID; - ndlp = lpfc_findnode_did(vport, did); - if ((!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - && (cmd != ELS_CMD_PLOGI)) - return 1; - } - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Retry ELS: wd7:x%x wd4:x%x did:x%x", - *(((uint32_t *) irsp) + 7), irsp->un.ulpWord[4], ndlp->nlp_DID); - - switch (irsp->ulpStatus) { - case IOSTAT_FCP_RSP_ERROR: - break; - case IOSTAT_REMOTE_STOP: - if (phba->sli_rev == LPFC_SLI_REV4) { - /* This IO was aborted by the target, we don't - * know the rxid and because we did not send the - * ABTS we cannot generate and RRQ. - */ - lpfc_set_rrq_active(phba, ndlp, - cmdiocb->sli4_xritag, 0, 0); - } - break; - case IOSTAT_LOCAL_REJECT: - switch ((irsp->un.ulpWord[4] & 0xff)) { - case IOERR_LOOP_OPEN_FAILURE: - if (cmd == ELS_CMD_FLOGI) { - if (PCI_DEVICE_ID_HORNET == - phba->pcidev->device) { - phba->fc_topology = LPFC_TOPOLOGY_LOOP; - phba->pport->fc_myDID = 0; - phba->alpa_map[0] = 0; - phba->alpa_map[1] = 0; - } - } - if (cmd == ELS_CMD_PLOGI && cmdiocb->retry == 0) - delay = 1000; - retry = 1; - break; - - case IOERR_ILLEGAL_COMMAND: - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0124 Retry illegal cmd x%x " - "retry:x%x delay:x%x\n", - cmd, cmdiocb->retry, delay); - retry = 1; - /* All command's retry policy */ - maxretry = 8; - if (cmdiocb->retry > 2) - delay = 1000; - break; - - case IOERR_NO_RESOURCES: - logerr = 1; /* HBA out of resources */ - retry = 1; - if (cmdiocb->retry > 100) - delay = 100; - maxretry = 250; - break; - - case IOERR_ILLEGAL_FRAME: - delay = 100; - retry = 1; - break; - - case IOERR_SEQUENCE_TIMEOUT: - case IOERR_INVALID_RPI: - retry = 1; - break; - } - break; - - case IOSTAT_NPORT_RJT: - case IOSTAT_FABRIC_RJT: - if (irsp->un.ulpWord[4] & RJT_UNAVAIL_TEMP) { - retry = 1; - break; - } - break; - - case IOSTAT_NPORT_BSY: - case IOSTAT_FABRIC_BSY: - logerr = 1; /* Fabric / Remote NPort out of resources */ - retry = 1; - break; - - case IOSTAT_LS_RJT: - stat.un.lsRjtError = be32_to_cpu(irsp->un.ulpWord[4]); - /* Added for Vendor specifc support - * Just keep retrying for these Rsn / Exp codes - */ - switch (stat.un.b.lsRjtRsnCode) { - case LSRJT_UNABLE_TPC: - if (stat.un.b.lsRjtRsnCodeExp == - LSEXP_CMD_IN_PROGRESS) { - if (cmd == ELS_CMD_PLOGI) { - delay = 1000; - maxretry = 48; - } - retry = 1; - break; - } - if (stat.un.b.lsRjtRsnCodeExp == - LSEXP_CANT_GIVE_DATA) { - if (cmd == ELS_CMD_PLOGI) { - delay = 1000; - maxretry = 48; - } - retry = 1; - break; - } - if (cmd == ELS_CMD_PLOGI) { - delay = 1000; - maxretry = lpfc_max_els_tries + 1; - retry = 1; - break; - } - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - (cmd == ELS_CMD_FDISC) && - (stat.un.b.lsRjtRsnCodeExp == LSEXP_OUT_OF_RESOURCE)){ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0125 FDISC Failed (x%x). " - "Fabric out of resources\n", - stat.un.lsRjtError); - lpfc_vport_set_state(vport, - FC_VPORT_NO_FABRIC_RSCS); - } - break; - - case LSRJT_LOGICAL_BSY: - if ((cmd == ELS_CMD_PLOGI) || - (cmd == ELS_CMD_PRLI)) { - delay = 1000; - maxretry = 48; - } else if (cmd == ELS_CMD_FDISC) { - /* FDISC retry policy */ - maxretry = 48; - if (cmdiocb->retry >= 32) - delay = 1000; - } - retry = 1; - break; - - case LSRJT_LOGICAL_ERR: - /* There are some cases where switches return this - * error when they are not ready and should be returning - * Logical Busy. We should delay every time. - */ - if (cmd == ELS_CMD_FDISC && - stat.un.b.lsRjtRsnCodeExp == LSEXP_PORT_LOGIN_REQ) { - maxretry = 3; - delay = 1000; - retry = 1; - break; - } - case LSRJT_PROTOCOL_ERR: - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - (cmd == ELS_CMD_FDISC) && - ((stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_PNAME) || - (stat.un.b.lsRjtRsnCodeExp == LSEXP_INVALID_NPORT_ID)) - ) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0122 FDISC Failed (x%x). " - "Fabric Detected Bad WWN\n", - stat.un.lsRjtError); - lpfc_vport_set_state(vport, - FC_VPORT_FABRIC_REJ_WWN); - } - break; - } - break; - - case IOSTAT_INTERMED_RSP: - case IOSTAT_BA_RJT: - break; - - default: - break; - } - - if (did == FDMI_DID) - retry = 1; - - if ((cmd == ELS_CMD_FLOGI) && - (phba->fc_topology != LPFC_TOPOLOGY_LOOP) && - !lpfc_error_lost_link(irsp)) { - /* FLOGI retry policy */ - retry = 1; - /* retry FLOGI forever */ - maxretry = 0; - if (cmdiocb->retry >= 100) - delay = 5000; - else if (cmdiocb->retry >= 32) - delay = 1000; - } else if ((cmd == ELS_CMD_FDISC) && !lpfc_error_lost_link(irsp)) { - /* retry FDISCs every second up to devloss */ - retry = 1; - maxretry = vport->cfg_devloss_tmo; - delay = 1000; - } - - cmdiocb->retry++; - if (maxretry && (cmdiocb->retry >= maxretry)) { - phba->fc_stat.elsRetryExceeded++; - retry = 0; - } - - if ((vport->load_flag & FC_UNLOADING) != 0) - retry = 0; - - if (retry) { - if ((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_FDISC)) { - /* Stop retrying PLOGI and FDISC if in FCF discovery */ - if (phba->fcf.fcf_flag & FCF_DISCOVERY) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "2849 Stop retry ELS command " - "x%x to remote NPORT x%x, " - "Data: x%x x%x\n", cmd, did, - cmdiocb->retry, delay); - return 0; - } - } - - /* Retry ELS command to remote NPORT */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0107 Retry ELS command x%x to remote " - "NPORT x%x Data: x%x x%x\n", - cmd, did, cmdiocb->retry, delay); - - if (((cmd == ELS_CMD_PLOGI) || (cmd == ELS_CMD_ADISC)) && - ((irsp->ulpStatus != IOSTAT_LOCAL_REJECT) || - ((irsp->un.ulpWord[4] & 0xff) != IOERR_NO_RESOURCES))) { - /* Don't reset timer for no resources */ - - /* If discovery / RSCN timer is running, reset it */ - if (timer_pending(&vport->fc_disctmo) || - (vport->fc_flag & FC_RSCN_MODE)) - lpfc_set_disctmo(vport); - } - - phba->fc_stat.elsXmitRetry++; - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && delay) { - phba->fc_stat.elsDelayRetry++; - ndlp->nlp_retry = cmdiocb->retry; - - /* delay is specified in milliseconds */ - mod_timer(&ndlp->nlp_delayfunc, - jiffies + msecs_to_jiffies(delay)); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - - ndlp->nlp_prev_state = ndlp->nlp_state; - if (cmd == ELS_CMD_PRLI) - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_REG_LOGIN_ISSUE); - else - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_NPR_NODE); - ndlp->nlp_last_elscmd = cmd; - - return 1; - } - switch (cmd) { - case ELS_CMD_FLOGI: - lpfc_issue_els_flogi(vport, ndlp, cmdiocb->retry); - return 1; - case ELS_CMD_FDISC: - lpfc_issue_els_fdisc(vport, ndlp, cmdiocb->retry); - return 1; - case ELS_CMD_PLOGI: - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_PLOGI_ISSUE); - } - lpfc_issue_els_plogi(vport, did, cmdiocb->retry); - return 1; - case ELS_CMD_ADISC: - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); - lpfc_issue_els_adisc(vport, ndlp, cmdiocb->retry); - return 1; - case ELS_CMD_PRLI: - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); - lpfc_issue_els_prli(vport, ndlp, cmdiocb->retry); - return 1; - case ELS_CMD_LOGO: - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - lpfc_issue_els_logo(vport, ndlp, cmdiocb->retry); - return 1; - } - } - /* No retry ELS command to remote NPORT */ - if (logerr) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0137 No retry ELS command x%x to remote " - "NPORT x%x: Out of Resources: Error:x%x/%x\n", - cmd, did, irsp->ulpStatus, - irsp->un.ulpWord[4]); - } - else { - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0108 No retry ELS command x%x to remote " - "NPORT x%x Retried:%d Error:x%x/%x\n", - cmd, did, cmdiocb->retry, irsp->ulpStatus, - irsp->un.ulpWord[4]); - } - return 0; -} - -/** - * lpfc_els_free_data - Free lpfc dma buffer and data structure with an iocb - * @phba: pointer to lpfc hba data structure. - * @buf_ptr1: pointer to the lpfc DMA buffer data structure. - * - * This routine releases the lpfc DMA (Direct Memory Access) buffer(s) - * associated with a command IOCB back to the lpfc DMA buffer pool. It first - * checks to see whether there is a lpfc DMA buffer associated with the - * response of the command IOCB. If so, it will be released before releasing - * the lpfc DMA buffer associated with the IOCB itself. - * - * Return code - * 0 - Successfully released lpfc DMA buffer (currently, always return 0) - **/ -static int -lpfc_els_free_data(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr1) -{ - struct lpfc_dmabuf *buf_ptr; - - /* Free the response before processing the command. */ - if (!list_empty(&buf_ptr1->list)) { - list_remove_head(&buf_ptr1->list, buf_ptr, - struct lpfc_dmabuf, - list); - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - } - lpfc_mbuf_free(phba, buf_ptr1->virt, buf_ptr1->phys); - kfree(buf_ptr1); - return 0; -} - -/** - * lpfc_els_free_bpl - Free lpfc dma buffer and data structure with bpl - * @phba: pointer to lpfc hba data structure. - * @buf_ptr: pointer to the lpfc dma buffer data structure. - * - * This routine releases the lpfc Direct Memory Access (DMA) buffer - * associated with a Buffer Pointer List (BPL) back to the lpfc DMA buffer - * pool. - * - * Return code - * 0 - Successfully released lpfc DMA buffer (currently, always return 0) - **/ -static int -lpfc_els_free_bpl(struct lpfc_hba *phba, struct lpfc_dmabuf *buf_ptr) -{ - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - return 0; -} - -/** - * lpfc_els_free_iocb - Free a command iocb and its associated resources - * @phba: pointer to lpfc hba data structure. - * @elsiocb: pointer to lpfc els command iocb data structure. - * - * This routine frees a command IOCB and its associated resources. The - * command IOCB data structure contains the reference to various associated - * resources, these fields must be set to NULL if the associated reference - * not present: - * context1 - reference to ndlp - * context2 - reference to cmd - * context2->next - reference to rsp - * context3 - reference to bpl - * - * It first properly decrements the reference count held on ndlp for the - * IOCB completion callback function. If LPFC_DELAY_MEM_FREE flag is not - * set, it invokes the lpfc_els_free_data() routine to release the Direct - * Memory Access (DMA) buffers associated with the IOCB. Otherwise, it - * adds the DMA buffer the @phba data structure for the delayed release. - * If reference to the Buffer Pointer List (BPL) is present, the - * lpfc_els_free_bpl() routine is invoked to release the DMA memory - * associated with BPL. Finally, the lpfc_sli_release_iocbq() routine is - * invoked to release the IOCB data structure back to @phba IOCBQ list. - * - * Return code - * 0 - Success (currently, always return 0) - **/ -int -lpfc_els_free_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *elsiocb) -{ - struct lpfc_dmabuf *buf_ptr, *buf_ptr1; - struct lpfc_nodelist *ndlp; - - ndlp = (struct lpfc_nodelist *)elsiocb->context1; - if (ndlp) { - if (ndlp->nlp_flag & NLP_DEFER_RM) { - lpfc_nlp_put(ndlp); - - /* If the ndlp is not being used by another discovery - * thread, free it. - */ - if (!lpfc_nlp_not_used(ndlp)) { - /* If ndlp is being used by another discovery - * thread, just clear NLP_DEFER_RM - */ - ndlp->nlp_flag &= ~NLP_DEFER_RM; - } - } - else - lpfc_nlp_put(ndlp); - elsiocb->context1 = NULL; - } - /* context2 = cmd, context2->next = rsp, context3 = bpl */ - if (elsiocb->context2) { - if (elsiocb->iocb_flag & LPFC_DELAY_MEM_FREE) { - /* Firmware could still be in progress of DMAing - * payload, so don't free data buffer till after - * a hbeat. - */ - elsiocb->iocb_flag &= ~LPFC_DELAY_MEM_FREE; - buf_ptr = elsiocb->context2; - elsiocb->context2 = NULL; - if (buf_ptr) { - buf_ptr1 = NULL; - spin_lock_irq(&phba->hbalock); - if (!list_empty(&buf_ptr->list)) { - list_remove_head(&buf_ptr->list, - buf_ptr1, struct lpfc_dmabuf, - list); - INIT_LIST_HEAD(&buf_ptr1->list); - list_add_tail(&buf_ptr1->list, - &phba->elsbuf); - phba->elsbuf_cnt++; - } - INIT_LIST_HEAD(&buf_ptr->list); - list_add_tail(&buf_ptr->list, &phba->elsbuf); - phba->elsbuf_cnt++; - spin_unlock_irq(&phba->hbalock); - } - } else { - buf_ptr1 = (struct lpfc_dmabuf *) elsiocb->context2; - lpfc_els_free_data(phba, buf_ptr1); - } - } - - if (elsiocb->context3) { - buf_ptr = (struct lpfc_dmabuf *) elsiocb->context3; - lpfc_els_free_bpl(phba, buf_ptr); - } - lpfc_sli_release_iocbq(phba, elsiocb); - return 0; -} - -/** - * lpfc_cmpl_els_logo_acc - Completion callback function to logo acc response - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the completion callback function to the Logout (LOGO) - * Accept (ACC) Response ELS command. This routine is invoked to indicate - * the completion of the LOGO process. It invokes the lpfc_nlp_not_used() to - * release the ndlp if it has the last reference remaining (reference count - * is 1). If succeeded (meaning ndlp released), it sets the IOCB context1 - * field to NULL to inform the following lpfc_els_free_iocb() routine no - * ndlp reference count needs to be decremented. Otherwise, the ndlp - * reference use-count shall be decremented by the lpfc_els_free_iocb() - * routine. Finally, the lpfc_els_free_iocb() is invoked to release the - * IOCB data structure. - **/ -static void -lpfc_cmpl_els_logo_acc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - struct lpfc_vport *vport = cmdiocb->vport; - IOCB_t *irsp; - - irsp = &rspiocb->iocb; - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "ACC LOGO cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], ndlp->nlp_DID); - /* ACC to LOGO completes to NPort */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0109 ACC to LOGO completes to NPort x%x " - "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - - if (ndlp->nlp_state == NLP_STE_NPR_NODE) { - /* NPort Recovery mode or node is just allocated */ - if (!lpfc_nlp_not_used(ndlp)) { - /* If the ndlp is being used by another discovery - * thread, just unregister the RPI. - */ - lpfc_unreg_rpi(vport, ndlp); - } else { - /* Indicate the node has already released, should - * not reference to it from within lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; - } - } - - /* - * The driver received a LOGO from the rport and has ACK'd it. - * At this point, the driver is done so release the IOCB - */ - lpfc_els_free_iocb(phba, cmdiocb); - - /* - * Remove the ndlp reference if it's a fabric node that has - * sent us an unsolicted LOGO. - */ - if (ndlp->nlp_type & NLP_FABRIC) - lpfc_nlp_put(ndlp); - - return; -} - -/** - * lpfc_mbx_cmpl_dflt_rpi - Completion callbk func for unreg dflt rpi mbox cmd - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This routine is the completion callback function for unregister default - * RPI (Remote Port Index) mailbox command to the @phba. It simply releases - * the associated lpfc Direct Memory Access (DMA) buffer back to the pool and - * decrements the ndlp reference count held for this completion callback - * function. After that, it invokes the lpfc_nlp_not_used() to check - * whether there is only one reference left on the ndlp. If so, it will - * perform one more decrement and trigger the release of the ndlp. - **/ -void -lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; - - pmb->context1 = NULL; - pmb->context2 = NULL; - - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - lpfc_nlp_put(ndlp); - /* This is the end of the default RPI cleanup logic for this - * ndlp. If no other discovery threads are using this ndlp. - * we should free all resources associated with it. - */ - lpfc_nlp_not_used(ndlp); - } - - return; -} - -/** - * lpfc_cmpl_els_rsp - Completion callback function for els response iocb cmd - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the completion callback function for ELS Response IOCB - * command. In normal case, this callback function just properly sets the - * nlp_flag bitmap in the ndlp data structure, if the mbox command reference - * field in the command IOCB is not NULL, the referred mailbox command will - * be send out, and then invokes the lpfc_els_free_iocb() routine to release - * the IOCB. Under error conditions, such as when a LS_RJT is returned or a - * link down event occurred during the discovery, the lpfc_nlp_not_used() - * routine shall be invoked trying to release the ndlp if no other threads - * are currently referring it. - **/ -static void -lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - struct lpfc_vport *vport = ndlp ? ndlp->vport : NULL; - struct Scsi_Host *shost = vport ? lpfc_shost_from_vport(vport) : NULL; - IOCB_t *irsp; - uint8_t *pcmd; - LPFC_MBOXQ_t *mbox = NULL; - struct lpfc_dmabuf *mp = NULL; - uint32_t ls_rjt = 0; - - irsp = &rspiocb->iocb; - - if (cmdiocb->context_un.mbox) - mbox = cmdiocb->context_un.mbox; - - /* First determine if this is a LS_RJT cmpl. Note, this callback - * function can have cmdiocb->contest1 (ndlp) field set to NULL. - */ - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) { - /* A LS_RJT associated with Default RPI cleanup has its own - * separate code path. - */ - if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI)) - ls_rjt = 1; - } - - /* Check to see if link went down during discovery */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || lpfc_els_chk_latt(vport)) { - if (mbox) { - mp = (struct lpfc_dmabuf *) mbox->context1; - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mempool_free(mbox, phba->mbox_mem_pool); - } - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) - if (lpfc_nlp_not_used(ndlp)) { - ndlp = NULL; - /* Indicate the node has already released, - * should not reference to it from within - * the routine lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; - } - goto out; - } - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "ELS rsp cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], - cmdiocb->iocb.un.elsreq64.remoteID); - /* ELS response tag completes */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0110 ELS response tag x%x completes " - "Data: x%x x%x x%x x%x x%x x%x x%x\n", - cmdiocb->iocb.ulpIoTag, rspiocb->iocb.ulpStatus, - rspiocb->iocb.un.ulpWord[4], rspiocb->iocb.ulpTimeout, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - if (mbox) { - if ((rspiocb->iocb.ulpStatus == 0) - && (ndlp->nlp_flag & NLP_ACC_REGLOGIN)) { - lpfc_unreg_rpi(vport, ndlp); - /* Increment reference count to ndlp to hold the - * reference to ndlp for the callback function. - */ - mbox->context2 = lpfc_nlp_get(ndlp); - mbox->vport = vport; - if (ndlp->nlp_flag & NLP_RM_DFLT_RPI) { - mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; - mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; - } - else { - mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_REG_LOGIN_ISSUE); - } - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - != MBX_NOT_FINISHED) - goto out; - else - /* Decrement the ndlp reference count we - * set for this failed mailbox command. - */ - lpfc_nlp_put(ndlp); - - /* ELS rsp: Cannot issue reg_login for */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0138 ELS rsp: Cannot issue reg_login for x%x " - "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - - if (lpfc_nlp_not_used(ndlp)) { - ndlp = NULL; - /* Indicate node has already been released, - * should not reference to it from within - * the routine lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; - } - } else { - /* Do not drop node for lpfc_els_abort'ed ELS cmds */ - if (!lpfc_error_lost_link(irsp) && - ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - if (lpfc_nlp_not_used(ndlp)) { - ndlp = NULL; - /* Indicate node has already been - * released, should not reference - * to it from within the routine - * lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; - } - } - } - mp = (struct lpfc_dmabuf *) mbox->context1; - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mempool_free(mbox, phba->mbox_mem_pool); - } -out: - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); - spin_unlock_irq(shost->host_lock); - - /* If the node is not being used by another discovery thread, - * and we are sending a reject, we are done with it. - * Release driver reference count here and free associated - * resources. - */ - if (ls_rjt) - if (lpfc_nlp_not_used(ndlp)) - /* Indicate node has already been released, - * should not reference to it from within - * the routine lpfc_els_free_iocb. - */ - cmdiocb->context1 = NULL; - } - - lpfc_els_free_iocb(phba, cmdiocb); - return; -} - -/** - * lpfc_els_rsp_acc - Prepare and issue an acc response iocb command - * @vport: pointer to a host virtual N_Port data structure. - * @flag: the els command code to be accepted. - * @oldiocb: pointer to the original lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * @mbox: pointer to the driver internal queue element for mailbox command. - * - * This routine prepares and issues an Accept (ACC) response IOCB - * command. It uses the @flag to properly set up the IOCB field for the - * specific ACC response command to be issued and invokes the - * lpfc_sli_issue_iocb() routine to send out ACC response IOCB. If a - * @mbox pointer is passed in, it will be put into the context_un.mbox - * field of the IOCB for the completion callback function to issue the - * mailbox command to the HBA later when callback is invoked. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the corresponding response ELS IOCB command. - * - * Return code - * 0 - Successfully issued acc response - * 1 - Failed to issue acc response - **/ -int -lpfc_els_rsp_acc(struct lpfc_vport *vport, uint32_t flag, - struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp, - LPFC_MBOXQ_t *mbox) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; - IOCB_t *oldcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; - uint8_t *pcmd; - uint16_t cmdsize; - int rc; - ELS_PKT *els_pkt_ptr; - - psli = &phba->sli; - oldcmd = &oldiocb->iocb; - - switch (flag) { - case ELS_CMD_ACC: - cmdsize = sizeof(uint32_t); - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, - ndlp, ndlp->nlp_DID, ELS_CMD_ACC); - if (!elsiocb) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); - return 1; - } - - icmd = &elsiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - break; - case ELS_CMD_PLOGI: - cmdsize = (sizeof(struct serv_parm) + sizeof(uint32_t)); - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, - ndlp, ndlp->nlp_DID, ELS_CMD_ACC); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - if (mbox) - elsiocb->context_un.mbox = mbox; - - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); - memcpy(pcmd, &vport->fc_sparam, sizeof(struct serv_parm)); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC PLOGI: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - break; - case ELS_CMD_PRLO: - cmdsize = sizeof(uint32_t) + sizeof(PRLO); - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, - ndlp, ndlp->nlp_DID, ELS_CMD_PRLO); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - memcpy(pcmd, ((struct lpfc_dmabuf *) oldiocb->context2)->virt, - sizeof(uint32_t) + sizeof(PRLO)); - *((uint32_t *) (pcmd)) = ELS_CMD_PRLO_ACC; - els_pkt_ptr = (ELS_PKT *) pcmd; - els_pkt_ptr->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC PRLO: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - break; - default: - return 1; - } - /* Xmit ELS ACC response tag */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0128 Xmit ELS ACC response tag x%x, XRI: x%x, " - "DID: x%x, nlp_flag: x%x nlp_state: x%x RPI: x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - if (ndlp->nlp_flag & NLP_LOGO_ACC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); - elsiocb->iocb_cmpl = lpfc_cmpl_els_logo_acc; - } else { - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - } - - phba->fc_stat.elsXmitACC++; - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_els_rsp_reject - Propare and issue a rjt response iocb command - * @vport: pointer to a virtual N_Port data structure. - * @rejectError: - * @oldiocb: pointer to the original lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * @mbox: pointer to the driver internal queue element for mailbox command. - * - * This routine prepares and issue an Reject (RJT) response IOCB - * command. If a @mbox pointer is passed in, it will be put into the - * context_un.mbox field of the IOCB for the completion callback function - * to issue to the HBA later. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the reject response ELS IOCB command. - * - * Return code - * 0 - Successfully issued reject response - * 1 - Failed to issue reject response - **/ -int -lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, - struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp, - LPFC_MBOXQ_t *mbox) -{ - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; - IOCB_t *oldcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; - uint8_t *pcmd; - uint16_t cmdsize; - int rc; - - psli = &phba->sli; - cmdsize = 2 * sizeof(uint32_t); - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, - ndlp->nlp_DID, ELS_CMD_LS_RJT); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - *((uint32_t *) (pcmd)) = ELS_CMD_LS_RJT; - pcmd += sizeof(uint32_t); - *((uint32_t *) (pcmd)) = rejectError; - - if (mbox) - elsiocb->context_un.mbox = mbox; - - /* Xmit ELS RJT response tag */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0129 Xmit ELS RJT x%x response tag x%x " - "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, " - "rpi x%x\n", - rejectError, elsiocb->iotag, - elsiocb->iocb.ulpContext, ndlp->nlp_DID, - ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue LS_RJT: did:x%x flg:x%x err:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, rejectError); - - phba->fc_stat.elsXmitLSRJT++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_els_rsp_adisc_acc - Prepare and issue acc response to adisc iocb cmd - * @vport: pointer to a virtual N_Port data structure. - * @oldiocb: pointer to the original lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine prepares and issues an Accept (ACC) response to Address - * Discover (ADISC) ELS command. It simply prepares the payload of the IOCB - * and invokes the lpfc_sli_issue_iocb() routine to send out the command. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the ADISC Accept response ELS IOCB command. - * - * Return code - * 0 - Successfully issued acc adisc response - * 1 - Failed to issue adisc acc response - **/ -int -lpfc_els_rsp_adisc_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - ADISC *ap; - IOCB_t *icmd, *oldcmd; - struct lpfc_iocbq *elsiocb; - uint8_t *pcmd; - uint16_t cmdsize; - int rc; - - cmdsize = sizeof(uint32_t) + sizeof(ADISC); - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - - /* Xmit ADISC ACC response tag */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0130 Xmit ADISC ACC response iotag x%x xri: " - "x%x, did x%x, nlp_flag x%x, nlp_state x%x rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); - - ap = (ADISC *) (pcmd); - ap->hardAL_PA = phba->fc_pref_ALPA; - memcpy(&ap->portName, &vport->fc_portname, sizeof(struct lpfc_name)); - memcpy(&ap->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); - ap->DID = be32_to_cpu(vport->fc_myDID); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC ADISC: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - - phba->fc_stat.elsXmitACC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_els_rsp_prli_acc - Prepare and issue acc response to prli iocb cmd - * @vport: pointer to a virtual N_Port data structure. - * @oldiocb: pointer to the original lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine prepares and issues an Accept (ACC) response to Process - * Login (PRLI) ELS command. It simply prepares the payload of the IOCB - * and invokes the lpfc_sli_issue_iocb() routine to send out the command. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the PRLI Accept response ELS IOCB command. - * - * Return code - * 0 - Successfully issued acc prli response - * 1 - Failed to issue acc prli response - **/ -int -lpfc_els_rsp_prli_acc(struct lpfc_vport *vport, struct lpfc_iocbq *oldiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - PRLI *npr; - lpfc_vpd_t *vpd; - IOCB_t *icmd; - IOCB_t *oldcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; - uint8_t *pcmd; - uint16_t cmdsize; - int rc; - - psli = &phba->sli; - - cmdsize = sizeof(uint32_t) + sizeof(PRLI); - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, - ndlp->nlp_DID, (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK))); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - - /* Xmit PRLI ACC response tag */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0131 Xmit PRLI ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - *((uint32_t *) (pcmd)) = (ELS_CMD_ACC | (ELS_CMD_PRLI & ~ELS_RSP_MASK)); - pcmd += sizeof(uint32_t); - - /* For PRLI, remainder of payload is PRLI parameter page */ - memset(pcmd, 0, sizeof(PRLI)); - - npr = (PRLI *) pcmd; - vpd = &phba->vpd; - /* - * If the remote port is a target and our firmware version is 3.20 or - * later, set the following bits for FC-TAPE support. - */ - if ((ndlp->nlp_type & NLP_FCP_TARGET) && - (vpd->rev.feaLevelHigh >= 0x02)) { - npr->ConfmComplAllowed = 1; - npr->Retry = 1; - npr->TaskRetryIdReq = 1; - } - - npr->acceptRspCode = PRLI_REQ_EXECUTED; - npr->estabImagePair = 1; - npr->readXferRdyDis = 1; - npr->ConfmComplAllowed = 1; - - npr->prliType = PRLI_FCP_TYPE; - npr->initiatorFunc = 1; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC PRLI: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - - phba->fc_stat.elsXmitACC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_els_rsp_rnid_acc - Issue rnid acc response iocb command - * @vport: pointer to a virtual N_Port data structure. - * @format: rnid command format. - * @oldiocb: pointer to the original lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine issues a Request Node Identification Data (RNID) Accept - * (ACC) response. It constructs the RNID ACC response command according to - * the proper @format and then calls the lpfc_sli_issue_iocb() routine to - * issue the response. Note that this command does not need to hold the ndlp - * reference count for the callback. So, the ndlp reference count taken by - * the lpfc_prep_els_iocb() routine is put back and the context1 field of - * IOCB is set to NULL to indicate to the lpfc_els_free_iocb() routine that - * there is no ndlp reference available. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function. However, for the RNID Accept Response ELS command, - * this is undone later by this routine after the IOCB is allocated. - * - * Return code - * 0 - Successfully issued acc rnid response - * 1 - Failed to issue acc rnid response - **/ -static int -lpfc_els_rsp_rnid_acc(struct lpfc_vport *vport, uint8_t format, - struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - RNID *rn; - IOCB_t *icmd, *oldcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; - uint8_t *pcmd; - uint16_t cmdsize; - int rc; - - psli = &phba->sli; - cmdsize = sizeof(uint32_t) + sizeof(uint32_t) - + (2 * sizeof(struct lpfc_name)); - if (format) - cmdsize += sizeof(RNID_TOP_DISC); - - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - - /* Xmit RNID ACC response tag */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0132 Xmit RNID ACC response tag x%x xri x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); - - memset(pcmd, 0, sizeof(RNID)); - rn = (RNID *) (pcmd); - rn->Format = format; - rn->CommonLen = (2 * sizeof(struct lpfc_name)); - memcpy(&rn->portName, &vport->fc_portname, sizeof(struct lpfc_name)); - memcpy(&rn->nodeName, &vport->fc_nodename, sizeof(struct lpfc_name)); - switch (format) { - case 0: - rn->SpecificLen = 0; - break; - case RNID_TOPOLOGY_DISC: - rn->SpecificLen = sizeof(RNID_TOP_DISC); - memcpy(&rn->un.topologyDisc.portName, - &vport->fc_portname, sizeof(struct lpfc_name)); - rn->un.topologyDisc.unitType = RNID_HBA; - rn->un.topologyDisc.physPort = 0; - rn->un.topologyDisc.attachedNodes = 0; - break; - default: - rn->CommonLen = 0; - rn->SpecificLen = 0; - break; - } - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC RNID: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - - phba->fc_stat.elsXmitACC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_els_clear_rrq - Clear the rq that this rrq describes. - * @vport: pointer to a virtual N_Port data structure. - * @iocb: pointer to the lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * Return - **/ -static void -lpfc_els_clear_rrq(struct lpfc_vport *vport, - struct lpfc_iocbq *iocb, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - uint8_t *pcmd; - struct RRQ *rrq; - uint16_t rxid; - uint16_t xri; - struct lpfc_node_rrq *prrq; - - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) iocb->context2)->virt); - pcmd += sizeof(uint32_t); - rrq = (struct RRQ *)pcmd; - rrq->rrq_exchg = be32_to_cpu(rrq->rrq_exchg); - rxid = bf_get(rrq_rxid, rrq); - - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "2883 Clear RRQ for SID:x%x OXID:x%x RXID:x%x" - " x%x x%x\n", - be32_to_cpu(bf_get(rrq_did, rrq)), - bf_get(rrq_oxid, rrq), - rxid, - iocb->iotag, iocb->iocb.ulpContext); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Clear RRQ: did:x%x flg:x%x exchg:x%.08x", - ndlp->nlp_DID, ndlp->nlp_flag, rrq->rrq_exchg); - if (vport->fc_myDID == be32_to_cpu(bf_get(rrq_did, rrq))) - xri = bf_get(rrq_oxid, rrq); - else - xri = rxid; - prrq = lpfc_get_active_rrq(vport, xri, ndlp->nlp_DID); - if (prrq) - lpfc_clr_rrq_active(phba, xri, prrq); - return; -} - -/** - * lpfc_els_rsp_echo_acc - Issue echo acc response - * @vport: pointer to a virtual N_Port data structure. - * @data: pointer to echo data to return in the accept. - * @oldiocb: pointer to the original lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * Return code - * 0 - Successfully issued acc echo response - * 1 - Failed to issue acc echo response - **/ -static int -lpfc_els_rsp_echo_acc(struct lpfc_vport *vport, uint8_t *data, - struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *elsiocb; - struct lpfc_sli *psli; - uint8_t *pcmd; - uint16_t cmdsize; - int rc; - - psli = &phba->sli; - cmdsize = oldiocb->iocb.unsli3.rcvsli3.acc_len; - - /* The accumulated length can exceed the BPL_SIZE. For - * now, use this as the limit - */ - if (cmdsize > LPFC_BPL_SIZE) - cmdsize = LPFC_BPL_SIZE; - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - if (!elsiocb) - return 1; - - elsiocb->iocb.ulpContext = oldiocb->iocb.ulpContext; /* Xri / rx_id */ - elsiocb->iocb.unsli3.rcvsli3.ox_id = oldiocb->iocb.unsli3.rcvsli3.ox_id; - - /* Xmit ECHO ACC response tag */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "2876 Xmit ECHO ACC response tag x%x xri x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext); - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); - memcpy(pcmd, data, cmdsize - sizeof(uint32_t)); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_RSP, - "Issue ACC ECHO: did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - - phba->fc_stat.elsXmitACC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_els_disc_adisc - Issue remaining adisc iocbs to npr nodes of a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine issues Address Discover (ADISC) ELS commands to those - * N_Ports which are in node port recovery state and ADISC has not been issued - * for the @vport. Each time an ELS ADISC IOCB is issued by invoking the - * lpfc_issue_els_adisc() routine, the per @vport number of discover count - * (num_disc_nodes) shall be incremented. If the num_disc_nodes reaches a - * pre-configured threshold (cfg_discovery_threads), the @vport fc_flag will - * be marked with FC_NLP_MORE bit and the process of issuing remaining ADISC - * IOCBs quit for later pick up. On the other hand, after walking through - * all the ndlps with the @vport and there is none ADISC IOCB issued, the - * @vport fc_flag shall be cleared with FC_NLP_MORE bit indicating there is - * no more ADISC need to be sent. - * - * Return code - * The number of N_Ports with adisc issued. - **/ -int -lpfc_els_disc_adisc(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp, *next_ndlp; - int sentadisc = 0; - - /* go thru NPR nodes and issue any remaining ELS ADISCs */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_NPR_NODE && - (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && - (ndlp->nlp_flag & NLP_NPR_ADISC) != 0) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); - lpfc_issue_els_adisc(vport, ndlp, 0); - sentadisc++; - vport->num_disc_nodes++; - if (vport->num_disc_nodes >= - vport->cfg_discovery_threads) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); - break; - } - } - } - if (sentadisc == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); - } - return sentadisc; -} - -/** - * lpfc_els_disc_plogi - Issue plogi for all npr nodes of a vport before adisc - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine issues Port Login (PLOGI) ELS commands to all the N_Ports - * which are in node port recovery state, with a @vport. Each time an ELS - * ADISC PLOGI IOCB is issued by invoking the lpfc_issue_els_plogi() routine, - * the per @vport number of discover count (num_disc_nodes) shall be - * incremented. If the num_disc_nodes reaches a pre-configured threshold - * (cfg_discovery_threads), the @vport fc_flag will be marked with FC_NLP_MORE - * bit set and quit the process of issuing remaining ADISC PLOGIN IOCBs for - * later pick up. On the other hand, after walking through all the ndlps with - * the @vport and there is none ADISC PLOGI IOCB issued, the @vport fc_flag - * shall be cleared with the FC_NLP_MORE bit indicating there is no more ADISC - * PLOGI need to be sent. - * - * Return code - * The number of N_Ports with plogi issued. - **/ -int -lpfc_els_disc_plogi(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp, *next_ndlp; - int sentplogi = 0; - - /* go thru NPR nodes and issue any remaining ELS PLOGIs */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_NPR_NODE && - (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && - (ndlp->nlp_flag & NLP_DELAY_TMO) == 0 && - (ndlp->nlp_flag & NLP_NPR_ADISC) == 0) { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - sentplogi++; - vport->num_disc_nodes++; - if (vport->num_disc_nodes >= - vport->cfg_discovery_threads) { - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); - break; - } - } - } - if (sentplogi) { - lpfc_set_disctmo(vport); - } - else { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NLP_MORE; - spin_unlock_irq(shost->host_lock); - } - return sentplogi; -} - -/** - * lpfc_els_flush_rscn - Clean up any rscn activities with a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine cleans up any Registration State Change Notification - * (RSCN) activity with a @vport. Note that the fc_rscn_flush flag of the - * @vport together with the host_lock is used to prevent multiple thread - * trying to access the RSCN array on a same @vport at the same time. - **/ -void -lpfc_els_flush_rscn(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - int i; - - spin_lock_irq(shost->host_lock); - if (vport->fc_rscn_flush) { - /* Another thread is walking fc_rscn_id_list on this vport */ - spin_unlock_irq(shost->host_lock); - return; - } - /* Indicate we are walking lpfc_els_flush_rscn on this vport */ - vport->fc_rscn_flush = 1; - spin_unlock_irq(shost->host_lock); - - for (i = 0; i < vport->fc_rscn_id_cnt; i++) { - lpfc_in_buf_free(phba, vport->fc_rscn_id_list[i]); - vport->fc_rscn_id_list[i] = NULL; - } - spin_lock_irq(shost->host_lock); - vport->fc_rscn_id_cnt = 0; - vport->fc_flag &= ~(FC_RSCN_MODE | FC_RSCN_DISCOVERY); - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - /* Indicate we are done walking this fc_rscn_id_list */ - vport->fc_rscn_flush = 0; -} - -/** - * lpfc_rscn_payload_check - Check whether there is a pending rscn to a did - * @vport: pointer to a host virtual N_Port data structure. - * @did: remote destination port identifier. - * - * This routine checks whether there is any pending Registration State - * Configuration Notification (RSCN) to a @did on @vport. - * - * Return code - * None zero - The @did matched with a pending rscn - * 0 - not able to match @did with a pending rscn - **/ -int -lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) -{ - D_ID ns_did; - D_ID rscn_did; - uint32_t *lp; - uint32_t payload_len, i; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - ns_did.un.word = did; - - /* Never match fabric nodes for RSCNs */ - if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) - return 0; - - /* If we are doing a FULL RSCN rediscovery, match everything */ - if (vport->fc_flag & FC_RSCN_DISCOVERY) - return did; - - spin_lock_irq(shost->host_lock); - if (vport->fc_rscn_flush) { - /* Another thread is walking fc_rscn_id_list on this vport */ - spin_unlock_irq(shost->host_lock); - return 0; - } - /* Indicate we are walking fc_rscn_id_list on this vport */ - vport->fc_rscn_flush = 1; - spin_unlock_irq(shost->host_lock); - for (i = 0; i < vport->fc_rscn_id_cnt; i++) { - lp = vport->fc_rscn_id_list[i]->virt; - payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK); - payload_len -= sizeof(uint32_t); /* take off word 0 */ - while (payload_len) { - rscn_did.un.word = be32_to_cpu(*lp++); - payload_len -= sizeof(uint32_t); - switch (rscn_did.un.b.resv & RSCN_ADDRESS_FORMAT_MASK) { - case RSCN_ADDRESS_FORMAT_PORT: - if ((ns_did.un.b.domain == rscn_did.un.b.domain) - && (ns_did.un.b.area == rscn_did.un.b.area) - && (ns_did.un.b.id == rscn_did.un.b.id)) - goto return_did_out; - break; - case RSCN_ADDRESS_FORMAT_AREA: - if ((ns_did.un.b.domain == rscn_did.un.b.domain) - && (ns_did.un.b.area == rscn_did.un.b.area)) - goto return_did_out; - break; - case RSCN_ADDRESS_FORMAT_DOMAIN: - if (ns_did.un.b.domain == rscn_did.un.b.domain) - goto return_did_out; - break; - case RSCN_ADDRESS_FORMAT_FABRIC: - goto return_did_out; - } - } - } - /* Indicate we are done with walking fc_rscn_id_list on this vport */ - vport->fc_rscn_flush = 0; - return 0; -return_did_out: - /* Indicate we are done with walking fc_rscn_id_list on this vport */ - vport->fc_rscn_flush = 0; - return did; -} - -/** - * lpfc_rscn_recovery_check - Send recovery event to vport nodes matching rscn - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine sends recovery (NLP_EVT_DEVICE_RECOVERY) event to the - * state machine for a @vport's nodes that are with pending RSCN (Registration - * State Change Notification). - * - * Return code - * 0 - Successful (currently alway return 0) - **/ -static int -lpfc_rscn_recovery_check(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp = NULL; - - /* Move all affected nodes by pending RSCNs to NPR state. */ - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || - (ndlp->nlp_state == NLP_STE_UNUSED_NODE) || - !lpfc_rscn_payload_check(vport, ndlp->nlp_DID)) - continue; - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - lpfc_cancel_retry_delay_tmo(vport, ndlp); - } - return 0; -} - -/** - * lpfc_send_rscn_event - Send an RSCN event to management application - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * - * lpfc_send_rscn_event sends an RSCN netlink event to management - * applications. - */ -static void -lpfc_send_rscn_event(struct lpfc_vport *vport, - struct lpfc_iocbq *cmdiocb) -{ - struct lpfc_dmabuf *pcmd; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - uint32_t *payload_ptr; - uint32_t payload_len; - struct lpfc_rscn_event_header *rscn_event_data; - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - payload_ptr = (uint32_t *) pcmd->virt; - payload_len = be32_to_cpu(*payload_ptr & ~ELS_CMD_MASK); - - rscn_event_data = kmalloc(sizeof(struct lpfc_rscn_event_header) + - payload_len, GFP_KERNEL); - if (!rscn_event_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0147 Failed to allocate memory for RSCN event\n"); - return; - } - rscn_event_data->event_type = FC_REG_RSCN_EVENT; - rscn_event_data->payload_length = payload_len; - memcpy(rscn_event_data->rscn_payload, payload_ptr, - payload_len); - - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(struct lpfc_els_event_header) + payload_len, - (char *)rscn_event_data, - LPFC_NL_VENDOR_ID); - - kfree(rscn_event_data); -} - -/** - * lpfc_els_rcv_rscn - Process an unsolicited rscn iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes an unsolicited RSCN (Registration State Change - * Notification) IOCB. First, the payload of the unsolicited RSCN is walked - * to invoke fc_host_post_event() routine to the FC transport layer. If the - * discover state machine is about to begin discovery, it just accepts the - * RSCN and the discovery process will satisfy the RSCN. If this RSCN only - * contains N_Port IDs for other vports on this HBA, it just accepts the - * RSCN and ignore processing it. If the state machine is in the recovery - * state, the fc_rscn_id_list of this @vport is walked and the - * lpfc_rscn_recovery_check() routine is invoked to send recovery event for - * all nodes that match RSCN payload. Otherwise, the lpfc_els_handle_rscn() - * routine is invoked to handle the RSCN event. - * - * Return code - * 0 - Just sent the acc response - * 1 - Sent the acc response and waited for name server completion - **/ -static int -lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_dmabuf *pcmd; - uint32_t *lp, *datap; - IOCB_t *icmd; - uint32_t payload_len, length, nportid, *cmd; - int rscn_cnt; - int rscn_id = 0, hba_id = 0; - int i; - - icmd = &cmdiocb->iocb; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - - payload_len = be32_to_cpu(*lp++ & ~ELS_CMD_MASK); - payload_len -= sizeof(uint32_t); /* take off word 0 */ - /* RSCN received */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0214 RSCN received Data: x%x x%x x%x x%x\n", - vport->fc_flag, payload_len, *lp, - vport->fc_rscn_id_cnt); - - /* Send an RSCN event to the management application */ - lpfc_send_rscn_event(vport, cmdiocb); - - for (i = 0; i < payload_len/sizeof(uint32_t); i++) - fc_host_post_event(shost, fc_get_event_number(), - FCH_EVT_RSCN, lp[i]); - - /* If we are about to begin discovery, just ACC the RSCN. - * Discovery processing will satisfy it. - */ - if (vport->port_state <= LPFC_NS_QRY) { - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RSCN ignore: did:x%x/ste:x%x flg:x%x", - ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); - - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - return 0; - } - - /* If this RSCN just contains NPortIDs for other vports on this HBA, - * just ACC and ignore it. - */ - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - !(vport->cfg_peer_port_login)) { - i = payload_len; - datap = lp; - while (i > 0) { - nportid = *datap++; - nportid = ((be32_to_cpu(nportid)) & Mask_DID); - i -= sizeof(uint32_t); - rscn_id++; - if (lpfc_find_vport_by_did(phba, nportid)) - hba_id++; - } - if (rscn_id == hba_id) { - /* ALL NPortIDs in RSCN are on HBA */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0219 Ignore RSCN " - "Data: x%x x%x x%x x%x\n", - vport->fc_flag, payload_len, - *lp, vport->fc_rscn_id_cnt); - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RSCN vport: did:x%x/ste:x%x flg:x%x", - ndlp->nlp_DID, vport->port_state, - ndlp->nlp_flag); - - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, - ndlp, NULL); - return 0; - } - } - - spin_lock_irq(shost->host_lock); - if (vport->fc_rscn_flush) { - /* Another thread is walking fc_rscn_id_list on this vport */ - vport->fc_flag |= FC_RSCN_DISCOVERY; - spin_unlock_irq(shost->host_lock); - /* Send back ACC */ - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - return 0; - } - /* Indicate we are walking fc_rscn_id_list on this vport */ - vport->fc_rscn_flush = 1; - spin_unlock_irq(shost->host_lock); - /* Get the array count after successfully have the token */ - rscn_cnt = vport->fc_rscn_id_cnt; - /* If we are already processing an RSCN, save the received - * RSCN payload buffer, cmdiocb->context2 to process later. - */ - if (vport->fc_flag & (FC_RSCN_MODE | FC_NDISC_ACTIVE)) { - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RSCN defer: did:x%x/ste:x%x flg:x%x", - ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); - - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_DEFERRED; - if ((rscn_cnt < FC_MAX_HOLD_RSCN) && - !(vport->fc_flag & FC_RSCN_DISCOVERY)) { - vport->fc_flag |= FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - if (rscn_cnt) { - cmd = vport->fc_rscn_id_list[rscn_cnt-1]->virt; - length = be32_to_cpu(*cmd & ~ELS_CMD_MASK); - } - if ((rscn_cnt) && - (payload_len + length <= LPFC_BPL_SIZE)) { - *cmd &= ELS_CMD_MASK; - *cmd |= cpu_to_be32(payload_len + length); - memcpy(((uint8_t *)cmd) + length, lp, - payload_len); - } else { - vport->fc_rscn_id_list[rscn_cnt] = pcmd; - vport->fc_rscn_id_cnt++; - /* If we zero, cmdiocb->context2, the calling - * routine will not try to free it. - */ - cmdiocb->context2 = NULL; - } - /* Deferred RSCN */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0235 Deferred RSCN " - "Data: x%x x%x x%x\n", - vport->fc_rscn_id_cnt, vport->fc_flag, - vport->port_state); - } else { - vport->fc_flag |= FC_RSCN_DISCOVERY; - spin_unlock_irq(shost->host_lock); - /* ReDiscovery RSCN */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0234 ReDiscovery RSCN " - "Data: x%x x%x x%x\n", - vport->fc_rscn_id_cnt, vport->fc_flag, - vport->port_state); - } - /* Indicate we are done walking fc_rscn_id_list on this vport */ - vport->fc_rscn_flush = 0; - /* Send back ACC */ - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - /* send RECOVERY event for ALL nodes that match RSCN payload */ - lpfc_rscn_recovery_check(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_DEFERRED; - spin_unlock_irq(shost->host_lock); - return 0; - } - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RSCN: did:x%x/ste:x%x flg:x%x", - ndlp->nlp_DID, vport->port_state, ndlp->nlp_flag); - - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - vport->fc_rscn_id_list[vport->fc_rscn_id_cnt++] = pcmd; - /* Indicate we are done walking fc_rscn_id_list on this vport */ - vport->fc_rscn_flush = 0; - /* - * If we zero, cmdiocb->context2, the calling routine will - * not try to free it. - */ - cmdiocb->context2 = NULL; - lpfc_set_disctmo(vport); - /* Send back ACC */ - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - /* send RECOVERY event for ALL nodes that match RSCN payload */ - lpfc_rscn_recovery_check(vport); - return lpfc_els_handle_rscn(vport); -} - -/** - * lpfc_els_handle_rscn - Handle rscn for a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine handles the Registration State Configuration Notification - * (RSCN) for a @vport. If login to NameServer does not exist, a new ndlp shall - * be created and a Port Login (PLOGI) to the NameServer is issued. Otherwise, - * if the ndlp to NameServer exists, a Common Transport (CT) command to the - * NameServer shall be issued. If CT command to the NameServer fails to be - * issued, the lpfc_els_flush_rscn() routine shall be invoked to clean up any - * RSCN activities with the @vport. - * - * Return code - * 0 - Cleaned up rscn on the @vport - * 1 - Wait for plogi to name server before proceed - **/ -int -lpfc_els_handle_rscn(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp; - struct lpfc_hba *phba = vport->phba; - - /* Ignore RSCN if the port is being torn down. */ - if (vport->load_flag & FC_UNLOADING) { - lpfc_els_flush_rscn(vport); - return 0; - } - - /* Start timer for RSCN processing */ - lpfc_set_disctmo(vport); - - /* RSCN processed */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0215 RSCN processed Data: x%x x%x x%x x%x\n", - vport->fc_flag, 0, vport->fc_rscn_id_cnt, - vport->port_state); - - /* To process RSCN, first compare RSCN data with NameServer */ - vport->fc_ns_retry = 0; - vport->num_disc_nodes = 0; - - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { - /* Good ndlp, issue CT Request to NameServer */ - if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0) == 0) - /* Wait for NameServer query cmpl before we can - continue */ - return 1; - } else { - /* If login to NameServer does not exist, issue one */ - /* Good status, issue PLOGI to NameServer */ - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) - /* Wait for NameServer login cmpl before we can - continue */ - return 1; - - if (ndlp) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_PLOGI_ISSUE); - if (!ndlp) { - lpfc_els_flush_rscn(vport); - return 0; - } - ndlp->nlp_prev_state = NLP_STE_UNUSED_NODE; - } else { - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) { - lpfc_els_flush_rscn(vport); - return 0; - } - lpfc_nlp_init(vport, ndlp, NameServer_DID); - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - } - ndlp->nlp_type |= NLP_FABRIC; - lpfc_issue_els_plogi(vport, NameServer_DID, 0); - /* Wait for NameServer login cmpl before we can - * continue - */ - return 1; - } - - lpfc_els_flush_rscn(vport); - return 0; -} - -/** - * lpfc_els_rcv_flogi - Process an unsolicited flogi iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Fabric Login (FLOGI) IOCB received as an ELS - * unsolicited event. An unsolicited FLOGI can be received in a point-to- - * point topology. As an unsolicited FLOGI should not be received in a loop - * mode, any unsolicited FLOGI received in loop mode shall be ignored. The - * lpfc_check_sparm() routine is invoked to check the parameters in the - * unsolicited FLOGI. If parameters validation failed, the routine - * lpfc_els_rsp_reject() shall be called with reject reason code set to - * LSEXP_SPARM_OPTIONS to reject the FLOGI. Otherwise, the Port WWN in the - * FLOGI shall be compared with the Port WWN of the @vport to determine who - * will initiate PLOGI. The higher lexicographical value party shall has - * higher priority (as the winning port) and will initiate PLOGI and - * communicate Port_IDs (Addresses) for both nodes in PLOGI. The result - * of this will be marked in the @vport fc_flag field with FC_PT2PT_PLOGI - * and then the lpfc_els_rsp_acc() routine is invoked to accept the FLOGI. - * - * Return code - * 0 - Successfully processed the unsolicited flogi - * 1 - Failed to process the unsolicited flogi - **/ -static int -lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - uint32_t *lp = (uint32_t *) pcmd->virt; - IOCB_t *icmd = &cmdiocb->iocb; - struct serv_parm *sp; - LPFC_MBOXQ_t *mbox; - struct ls_rjt stat; - uint32_t cmd, did; - int rc; - - cmd = *lp++; - sp = (struct serv_parm *) lp; - - /* FLOGI received */ - - lpfc_set_disctmo(vport); - - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - /* We should never receive a FLOGI in loop mode, ignore it */ - did = icmd->un.elsreq64.remoteID; - - /* An FLOGI ELS command was received from DID in - Loop Mode */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0113 An FLOGI ELS command x%x was " - "received from DID x%x in Loop Mode\n", - cmd, did); - return 1; - } - - did = Fabric_DID; - - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { - /* For a FLOGI we accept, then if our portname is greater - * then the remote portname we initiate Nport login. - */ - - rc = memcmp(&vport->fc_portname, &sp->portName, - sizeof(struct lpfc_name)); - - if (!rc) { - if (phba->sli_rev < LPFC_SLI_REV4) { - mbox = mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!mbox) - return 1; - lpfc_linkdown(phba); - lpfc_init_link(phba, mbox, - phba->cfg_topology, - phba->cfg_link_speed); - mbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, - MBX_NOWAIT); - lpfc_set_loopback_flag(phba); - if (rc == MBX_NOT_FINISHED) - mempool_free(mbox, phba->mbox_mem_pool); - return 1; - } else { - /* abort the flogi coming back to ourselves - * due to external loopback on the port. - */ - lpfc_els_abort_flogi(phba); - return 0; - } - } else if (rc > 0) { /* greater than */ - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PT2PT_PLOGI; - spin_unlock_irq(shost->host_lock); - } - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_PT2PT; - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); - } else { - /* Reject this request because invalid parameters */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, - NULL); - return 1; - } - - /* Send back ACC */ - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); - - return 0; -} - -/** - * lpfc_els_rcv_rnid - Process an unsolicited rnid iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Request Node Identification Data (RNID) IOCB - * received as an ELS unsolicited event. Only when the RNID specified format - * 0x0 or 0xDF (Topology Discovery Specific Node Identification Data) - * present, this routine will invoke the lpfc_els_rsp_rnid_acc() routine to - * Accept (ACC) the RNID ELS command. All the other RNID formats are - * rejected by invoking the lpfc_els_rsp_reject() routine. - * - * Return code - * 0 - Successfully processed rnid iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_rnid(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_dmabuf *pcmd; - uint32_t *lp; - IOCB_t *icmd; - RNID *rn; - struct ls_rjt stat; - uint32_t cmd, did; - - icmd = &cmdiocb->iocb; - did = icmd->un.elsreq64.remoteID; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - - cmd = *lp++; - rn = (RNID *) lp; - - /* RNID received */ - - switch (rn->Format) { - case 0: - case RNID_TOPOLOGY_DISC: - /* Send back ACC */ - lpfc_els_rsp_rnid_acc(vport, rn->Format, cmdiocb, ndlp); - break; - default: - /* Reject this request because format not supported */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, - NULL); - } - return 0; -} - -/** - * lpfc_els_rcv_echo - Process an unsolicited echo iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * Return code - * 0 - Successfully processed echo iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_echo(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - uint8_t *pcmd; - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) cmdiocb->context2)->virt); - - /* skip over first word of echo command to find echo data */ - pcmd += sizeof(uint32_t); - - lpfc_els_rsp_echo_acc(vport, pcmd, cmdiocb, ndlp); - return 0; -} - -/** - * lpfc_els_rcv_lirr - Process an unsolicited lirr iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes a Link Incident Report Registration(LIRR) IOCB - * received as an ELS unsolicited event. Currently, this function just invokes - * the lpfc_els_rsp_reject() routine to reject the LIRR IOCB unconditionally. - * - * Return code - * 0 - Successfully processed lirr iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct ls_rjt stat; - - /* For now, unconditionally reject this command */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return 0; -} - -/** - * lpfc_els_rcv_rrq - Process an unsolicited rrq iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes a Reinstate Recovery Qualifier (RRQ) IOCB - * received as an ELS unsolicited event. A request to RRQ shall only - * be accepted if the Originator Nx_Port N_Port_ID or the Responder - * Nx_Port N_Port_ID of the target Exchange is the same as the - * N_Port_ID of the Nx_Port that makes the request. If the RRQ is - * not accepted, an LS_RJT with reason code "Unable to perform - * command request" and reason code explanation "Invalid Originator - * S_ID" shall be returned. For now, we just unconditionally accept - * RRQ from the target. - **/ -static void -lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - if (vport->phba->sli_rev == LPFC_SLI_REV4) - lpfc_els_clear_rrq(vport, cmdiocb, ndlp); -} - -/** - * lpfc_els_rsp_rls_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This routine is the completion callback function for the MBX_READ_LNK_STAT - * mailbox command. This callback function is to actually send the Accept - * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It - * collects the link statistics from the completion of the MBX_READ_LNK_STAT - * mailbox command, constructs the RPS response with the link statistics - * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC - * response to the RPS. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. - * - **/ -static void -lpfc_els_rsp_rls_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb; - IOCB_t *icmd; - struct RLS_RSP *rls_rsp; - uint8_t *pcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_nodelist *ndlp; - uint16_t oxid; - uint16_t rxid; - uint32_t cmdsize; - - mb = &pmb->u.mb; - - ndlp = (struct lpfc_nodelist *) pmb->context2; - rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff); - oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff); - pmb->context1 = NULL; - pmb->context2 = NULL; - - if (mb->mbxStatus) { - mempool_free(pmb, phba->mbox_mem_pool); - return; - } - - cmdsize = sizeof(struct RLS_RSP) + sizeof(uint32_t); - mempool_free(pmb, phba->mbox_mem_pool); - elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, - lpfc_max_els_tries, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - - /* Decrement the ndlp reference count from previous mbox command */ - lpfc_nlp_put(ndlp); - - if (!elsiocb) - return; - - icmd = &elsiocb->iocb; - icmd->ulpContext = rxid; - icmd->unsli3.rcvsli3.ox_id = oxid; - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); /* Skip past command */ - rls_rsp = (struct RLS_RSP *)pcmd; - - rls_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); - rls_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); - rls_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); - rls_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); - rls_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); - rls_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); - - /* Xmit ELS RLS ACC response tag */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, - "2874 Xmit ELS RLS ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) - lpfc_els_free_iocb(phba, elsiocb); -} - -/** - * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This routine is the completion callback function for the MBX_READ_LNK_STAT - * mailbox command. This callback function is to actually send the Accept - * (ACC) response to a Read Port Status (RPS) unsolicited IOCB event. It - * collects the link statistics from the completion of the MBX_READ_LNK_STAT - * mailbox command, constructs the RPS response with the link statistics - * collected, and then invokes the lpfc_sli_issue_iocb() routine to send ACC - * response to the RPS. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. - * - **/ -static void -lpfc_els_rsp_rps_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb; - IOCB_t *icmd; - RPS_RSP *rps_rsp; - uint8_t *pcmd; - struct lpfc_iocbq *elsiocb; - struct lpfc_nodelist *ndlp; - uint16_t status; - uint16_t oxid; - uint16_t rxid; - uint32_t cmdsize; - - mb = &pmb->u.mb; - - ndlp = (struct lpfc_nodelist *) pmb->context2; - rxid = (uint16_t) ((unsigned long)(pmb->context1) & 0xffff); - oxid = (uint16_t) (((unsigned long)(pmb->context1) >> 16) & 0xffff); - pmb->context1 = NULL; - pmb->context2 = NULL; - - if (mb->mbxStatus) { - mempool_free(pmb, phba->mbox_mem_pool); - return; - } - - cmdsize = sizeof(RPS_RSP) + sizeof(uint32_t); - mempool_free(pmb, phba->mbox_mem_pool); - elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, - lpfc_max_els_tries, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - - /* Decrement the ndlp reference count from previous mbox command */ - lpfc_nlp_put(ndlp); - - if (!elsiocb) - return; - - icmd = &elsiocb->iocb; - icmd->ulpContext = rxid; - icmd->unsli3.rcvsli3.ox_id = oxid; - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); /* Skip past command */ - rps_rsp = (RPS_RSP *)pcmd; - - if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) - status = 0x10; - else - status = 0x8; - if (phba->pport->fc_flag & FC_FABRIC) - status |= 0x4; - - rps_rsp->rsvd1 = 0; - rps_rsp->portStatus = cpu_to_be16(status); - rps_rsp->linkFailureCnt = cpu_to_be32(mb->un.varRdLnk.linkFailureCnt); - rps_rsp->lossSyncCnt = cpu_to_be32(mb->un.varRdLnk.lossSyncCnt); - rps_rsp->lossSignalCnt = cpu_to_be32(mb->un.varRdLnk.lossSignalCnt); - rps_rsp->primSeqErrCnt = cpu_to_be32(mb->un.varRdLnk.primSeqErrCnt); - rps_rsp->invalidXmitWord = cpu_to_be32(mb->un.varRdLnk.invalidXmitWord); - rps_rsp->crcCnt = cpu_to_be32(mb->un.varRdLnk.crcCnt); - /* Xmit ELS RPS ACC response tag */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, - "0118 Xmit ELS RPS ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) - lpfc_els_free_iocb(phba, elsiocb); - return; -} - -/** - * lpfc_els_rcv_rls - Process an unsolicited rls iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Read Port Status (RPL) IOCB received as an - * ELS unsolicited event. It first checks the remote port state. If the - * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE - * state, it invokes the lpfc_els_rsl_reject() routine to send the reject - * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command - * for reading the HBA link statistics. It is for the callback function, - * lpfc_els_rsp_rls_acc(), set to the MBX_READ_LNK_STAT mailbox command - * to actually sending out RPL Accept (ACC) response. - * - * Return codes - * 0 - Successfully processed rls iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_rls(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *pcmd; - struct ls_rjt stat; - - if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ - goto reject_out; - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); - if (mbox) { - lpfc_read_lnk_stat(phba, mbox); - mbox->context1 = (void *)((unsigned long) - ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | - cmdiocb->iocb.ulpContext)); /* rx_id */ - mbox->context2 = lpfc_nlp_get(ndlp); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_els_rsp_rls_acc; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - != MBX_NOT_FINISHED) - /* Mbox completion will send ELS Response */ - return 0; - /* Decrement reference count used for the failed mbox - * command. - */ - lpfc_nlp_put(ndlp); - mempool_free(mbox, phba->mbox_mem_pool); - } -reject_out: - /* issue rejection response */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return 0; -} - -/** - * lpfc_els_rcv_rtv - Process an unsolicited rtv iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Read Timout Value (RTV) IOCB received as an - * ELS unsolicited event. It first checks the remote port state. If the - * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE - * state, it invokes the lpfc_els_rsl_reject() routine to send the reject - * response. Otherwise, it sends the Accept(ACC) response to a Read Timeout - * Value (RTV) unsolicited IOCB event. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPS Accept Response ELS IOCB command. - * - * Return codes - * 0 - Successfully processed rtv iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_rtv(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - struct ls_rjt stat; - struct RTV_RSP *rtv_rsp; - uint8_t *pcmd; - struct lpfc_iocbq *elsiocb; - uint32_t cmdsize; - - - if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ - goto reject_out; - - cmdsize = sizeof(struct RTV_RSP) + sizeof(uint32_t); - elsiocb = lpfc_prep_els_iocb(phba->pport, 0, cmdsize, - lpfc_max_els_tries, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - - if (!elsiocb) - return 1; - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint32_t); /* Skip past command */ - - /* use the command's xri in the response */ - elsiocb->iocb.ulpContext = cmdiocb->iocb.ulpContext; /* Xri / rx_id */ - elsiocb->iocb.unsli3.rcvsli3.ox_id = cmdiocb->iocb.unsli3.rcvsli3.ox_id; - - rtv_rsp = (struct RTV_RSP *)pcmd; - - /* populate RTV payload */ - rtv_rsp->ratov = cpu_to_be32(phba->fc_ratov * 1000); /* report msecs */ - rtv_rsp->edtov = cpu_to_be32(phba->fc_edtov); - bf_set(qtov_edtovres, rtv_rsp, phba->fc_edtovResol ? 1 : 0); - bf_set(qtov_rttov, rtv_rsp, 0); /* Field is for FC ONLY */ - rtv_rsp->qtov = cpu_to_be32(rtv_rsp->qtov); - - /* Xmit ELS RLS ACC response tag */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_ELS, - "2875 Xmit ELS RTV ACC response tag x%x xri x%x, " - "did x%x, nlp_flag x%x, nlp_state x%x, rpi x%x, " - "Data: x%x x%x x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi, - rtv_rsp->ratov, rtv_rsp->edtov, rtv_rsp->qtov); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == IOCB_ERROR) - lpfc_els_free_iocb(phba, elsiocb); - return 0; - -reject_out: - /* issue rejection response */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return 0; -} - -/* lpfc_els_rcv_rps - Process an unsolicited rps iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Read Port Status (RPS) IOCB received as an - * ELS unsolicited event. It first checks the remote port state. If the - * remote port is not in NLP_STE_UNMAPPED_NODE state or NLP_STE_MAPPED_NODE - * state, it invokes the lpfc_els_rsp_reject() routine to send the reject - * response. Otherwise, it issue the MBX_READ_LNK_STAT mailbox command - * for reading the HBA link statistics. It is for the callback function, - * lpfc_els_rsp_rps_acc(), set to the MBX_READ_LNK_STAT mailbox command - * to actually sending out RPS Accept (ACC) response. - * - * Return codes - * 0 - Successfully processed rps iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_rps(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t *lp; - uint8_t flag; - LPFC_MBOXQ_t *mbox; - struct lpfc_dmabuf *pcmd; - RPS *rps; - struct ls_rjt stat; - - if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) - /* reject the unsolicited RPS request and done with it */ - goto reject_out; - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - flag = (be32_to_cpu(*lp++) & 0xf); - rps = (RPS *) lp; - - if ((flag == 0) || - ((flag == 1) && (be32_to_cpu(rps->un.portNum) == 0)) || - ((flag == 2) && (memcmp(&rps->un.portName, &vport->fc_portname, - sizeof(struct lpfc_name)) == 0))) { - - printk("Fix me....\n"); - dump_stack(); - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_ATOMIC); - if (mbox) { - lpfc_read_lnk_stat(phba, mbox); - mbox->context1 = (void *)((unsigned long) - ((cmdiocb->iocb.unsli3.rcvsli3.ox_id << 16) | - cmdiocb->iocb.ulpContext)); /* rx_id */ - mbox->context2 = lpfc_nlp_get(ndlp); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_els_rsp_rps_acc; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - != MBX_NOT_FINISHED) - /* Mbox completion will send ELS Response */ - return 0; - /* Decrement reference count used for the failed mbox - * command. - */ - lpfc_nlp_put(ndlp); - mempool_free(mbox, phba->mbox_mem_pool); - } - } - -reject_out: - /* issue rejection response */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return 0; -} - -/* lpfc_issue_els_rrq - Process an unsolicited rps iocb - * @vport: pointer to a host virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * @did: DID of the target. - * @rrq: Pointer to the rrq struct. - * - * Build a ELS RRQ command and send it to the target. If the issue_iocb is - * Successful the the completion handler will clear the RRQ. - * - * Return codes - * 0 - Successfully sent rrq els iocb. - * 1 - Failed to send rrq els iocb. - **/ -static int -lpfc_issue_els_rrq(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint32_t did, struct lpfc_node_rrq *rrq) -{ - struct lpfc_hba *phba = vport->phba; - struct RRQ *els_rrq; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - uint8_t *pcmd; - uint16_t cmdsize; - int ret; - - - if (ndlp != rrq->ndlp) - ndlp = rrq->ndlp; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - return 1; - - /* If ndlp is not NULL, we will bump the reference count on it */ - cmdsize = (sizeof(uint32_t) + sizeof(struct RRQ)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, did, - ELS_CMD_RRQ); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - - /* For RRQ request, remainder of payload is Exchange IDs */ - *((uint32_t *) (pcmd)) = ELS_CMD_RRQ; - pcmd += sizeof(uint32_t); - els_rrq = (struct RRQ *) pcmd; - - bf_set(rrq_oxid, els_rrq, rrq->xritag); - bf_set(rrq_rxid, els_rrq, rrq->rxid); - bf_set(rrq_did, els_rrq, vport->fc_myDID); - els_rrq->rrq = cpu_to_be32(els_rrq->rrq); - els_rrq->rrq_exchg = cpu_to_be32(els_rrq->rrq_exchg); - - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue RRQ: did:x%x", - did, rrq->xritag, rrq->rxid); - elsiocb->context_un.rrq = rrq; - elsiocb->iocb_cmpl = lpfc_cmpl_els_rrq; - ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0); - - if (ret == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_send_rrq - Sends ELS RRQ if needed. - * @phba: pointer to lpfc hba data structure. - * @rrq: pointer to the active rrq. - * - * This routine will call the lpfc_issue_els_rrq if the rrq is - * still active for the xri. If this function returns a failure then - * the caller needs to clean up the RRQ by calling lpfc_clr_active_rrq. - * - * Returns 0 Success. - * 1 Failure. - **/ -int -lpfc_send_rrq(struct lpfc_hba *phba, struct lpfc_node_rrq *rrq) -{ - struct lpfc_nodelist *ndlp = lpfc_findnode_did(rrq->vport, - rrq->nlp_DID); - if (lpfc_test_rrq_active(phba, ndlp, rrq->xritag)) - return lpfc_issue_els_rrq(rrq->vport, ndlp, - rrq->nlp_DID, rrq); - else - return 1; -} - -/** - * lpfc_els_rsp_rpl_acc - Issue an accept rpl els command - * @vport: pointer to a host virtual N_Port data structure. - * @cmdsize: size of the ELS command. - * @oldiocb: pointer to the original lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine issuees an Accept (ACC) Read Port List (RPL) ELS command. - * It is to be called by the lpfc_els_rcv_rpl() routine to accept the RPL. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the RPL Accept Response ELS command. - * - * Return code - * 0 - Successfully issued ACC RPL ELS command - * 1 - Failed to issue ACC RPL ELS command - **/ -static int -lpfc_els_rsp_rpl_acc(struct lpfc_vport *vport, uint16_t cmdsize, - struct lpfc_iocbq *oldiocb, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd, *oldcmd; - RPL_RSP rpl_rsp; - struct lpfc_iocbq *elsiocb; - uint8_t *pcmd; - - elsiocb = lpfc_prep_els_iocb(vport, 0, cmdsize, oldiocb->retry, ndlp, - ndlp->nlp_DID, ELS_CMD_ACC); - - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - oldcmd = &oldiocb->iocb; - icmd->ulpContext = oldcmd->ulpContext; /* Xri / rx_id */ - icmd->unsli3.rcvsli3.ox_id = oldcmd->unsli3.rcvsli3.ox_id; - - pcmd = (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_ACC; - pcmd += sizeof(uint16_t); - *((uint16_t *)(pcmd)) = be16_to_cpu(cmdsize); - pcmd += sizeof(uint16_t); - - /* Setup the RPL ACC payload */ - rpl_rsp.listLen = be32_to_cpu(1); - rpl_rsp.index = 0; - rpl_rsp.port_num_blk.portNum = 0; - rpl_rsp.port_num_blk.portID = be32_to_cpu(vport->fc_myDID); - memcpy(&rpl_rsp.port_num_blk.portName, &vport->fc_portname, - sizeof(struct lpfc_name)); - memcpy(pcmd, &rpl_rsp, cmdsize - sizeof(uint32_t)); - /* Xmit ELS RPL ACC response tag */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0120 Xmit ELS RPL ACC response tag x%x " - "xri x%x, did x%x, nlp_flag x%x, nlp_state x%x, " - "rpi x%x\n", - elsiocb->iotag, elsiocb->iocb.ulpContext, - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - elsiocb->iocb_cmpl = lpfc_cmpl_els_rsp; - phba->fc_stat.elsXmitACC++; - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_els_rcv_rpl - Process an unsolicited rpl iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Read Port List (RPL) IOCB received as an ELS - * unsolicited event. It first checks the remote port state. If the remote - * port is not in NLP_STE_UNMAPPED_NODE and NLP_STE_MAPPED_NODE states, it - * invokes the lpfc_els_rsp_reject() routine to send reject response. - * Otherwise, this routine then invokes the lpfc_els_rsp_rpl_acc() routine - * to accept the RPL. - * - * Return code - * 0 - Successfully processed rpl iocb (currently always return 0) - **/ -static int -lpfc_els_rcv_rpl(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_dmabuf *pcmd; - uint32_t *lp; - uint32_t maxsize; - uint16_t cmdsize; - RPL *rpl; - struct ls_rjt stat; - - if ((ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_MAPPED_NODE)) { - /* issue rejection response */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CANT_GIVE_DATA; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, - NULL); - /* rejected the unsolicited RPL request and done with it */ - return 0; - } - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - rpl = (RPL *) (lp + 1); - maxsize = be32_to_cpu(rpl->maxsize); - - /* We support only one port */ - if ((rpl->index == 0) && - ((maxsize == 0) || - ((maxsize * sizeof(uint32_t)) >= sizeof(RPL_RSP)))) { - cmdsize = sizeof(uint32_t) + sizeof(RPL_RSP); - } else { - cmdsize = sizeof(uint32_t) + maxsize * sizeof(uint32_t); - } - lpfc_els_rsp_rpl_acc(vport, cmdsize, cmdiocb, ndlp); - - return 0; -} - -/** - * lpfc_els_rcv_farp - Process an unsolicited farp request els command - * @vport: pointer to a virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Fibre Channel Address Resolution Protocol - * (FARP) Request IOCB received as an ELS unsolicited event. Currently, - * the lpfc driver only supports matching on WWPN or WWNN for FARP. As such, - * FARP_MATCH_PORT flag and FARP_MATCH_NODE flag are checked against the - * Match Flag in the FARP request IOCB: if FARP_MATCH_PORT flag is set, the - * remote PortName is compared against the FC PortName stored in the @vport - * data structure; if FARP_MATCH_NODE flag is set, the remote NodeName is - * compared against the FC NodeName stored in the @vport data structure. - * If any of these matches and the FARP_REQUEST_FARPR flag is set in the - * FARP request IOCB Response Flag, the lpfc_issue_els_farpr() routine is - * invoked to send out FARP Response to the remote node. Before sending the - * FARP Response, however, the FARP_REQUEST_PLOGI flag is check in the FARP - * request IOCB Response Flag and, if it is set, the lpfc_issue_els_plogi() - * routine is invoked to log into the remote port first. - * - * Return code - * 0 - Either the FARP Match Mode not supported or successfully processed - **/ -static int -lpfc_els_rcv_farp(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_dmabuf *pcmd; - uint32_t *lp; - IOCB_t *icmd; - FARP *fp; - uint32_t cmd, cnt, did; - - icmd = &cmdiocb->iocb; - did = icmd->un.elsreq64.remoteID; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - - cmd = *lp++; - fp = (FARP *) lp; - /* FARP-REQ received from DID */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0601 FARP-REQ received from DID x%x\n", did); - /* We will only support match on WWPN or WWNN */ - if (fp->Mflags & ~(FARP_MATCH_NODE | FARP_MATCH_PORT)) { - return 0; - } - - cnt = 0; - /* If this FARP command is searching for my portname */ - if (fp->Mflags & FARP_MATCH_PORT) { - if (memcmp(&fp->RportName, &vport->fc_portname, - sizeof(struct lpfc_name)) == 0) - cnt = 1; - } - - /* If this FARP command is searching for my nodename */ - if (fp->Mflags & FARP_MATCH_NODE) { - if (memcmp(&fp->RnodeName, &vport->fc_nodename, - sizeof(struct lpfc_name)) == 0) - cnt = 1; - } - - if (cnt) { - if ((ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) || - (ndlp->nlp_state == NLP_STE_MAPPED_NODE)) { - /* Log back into the node before sending the FARP. */ - if (fp->Rflags & FARP_REQUEST_PLOGI) { - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - } - - /* Send a FARP response to that node */ - if (fp->Rflags & FARP_REQUEST_FARPR) - lpfc_issue_els_farpr(vport, did, 0); - } - } - return 0; -} - -/** - * lpfc_els_rcv_farpr - Process an unsolicited farp response iocb - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine processes Fibre Channel Address Resolution Protocol - * Response (FARPR) IOCB received as an ELS unsolicited event. It simply - * invokes the lpfc_els_rsp_acc() routine to the remote node to accept - * the FARP response request. - * - * Return code - * 0 - Successfully processed FARPR IOCB (currently always return 0) - **/ -static int -lpfc_els_rcv_farpr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_dmabuf *pcmd; - uint32_t *lp; - IOCB_t *icmd; - uint32_t cmd, did; - - icmd = &cmdiocb->iocb; - did = icmd->un.elsreq64.remoteID; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - - cmd = *lp++; - /* FARP-RSP received from DID */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0600 FARP-RSP received from DID x%x\n", did); - /* ACCEPT the Farp resp request */ - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - - return 0; -} - -/** - * lpfc_els_rcv_fan - Process an unsolicited fan iocb command - * @vport: pointer to a host virtual N_Port data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @fan_ndlp: pointer to a node-list data structure. - * - * This routine processes a Fabric Address Notification (FAN) IOCB - * command received as an ELS unsolicited event. The FAN ELS command will - * only be processed on a physical port (i.e., the @vport represents the - * physical port). The fabric NodeName and PortName from the FAN IOCB are - * compared against those in the phba data structure. If any of those is - * different, the lpfc_initial_flogi() routine is invoked to initialize - * Fabric Login (FLOGI) to the fabric to start the discover over. Otherwise, - * if both of those are identical, the lpfc_issue_fabric_reglogin() routine - * is invoked to register login to the fabric. - * - * Return code - * 0 - Successfully processed fan iocb (currently always return 0). - **/ -static int -lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, - struct lpfc_nodelist *fan_ndlp) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t *lp; - FAN *fp; - - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0265 FAN received\n"); - lp = (uint32_t *)((struct lpfc_dmabuf *)cmdiocb->context2)->virt; - fp = (FAN *) ++lp; - /* FAN received; Fan does not have a reply sequence */ - if ((vport == phba->pport) && - (vport->port_state == LPFC_LOCAL_CFG_LINK)) { - if ((memcmp(&phba->fc_fabparam.nodeName, &fp->FnodeName, - sizeof(struct lpfc_name))) || - (memcmp(&phba->fc_fabparam.portName, &fp->FportName, - sizeof(struct lpfc_name)))) { - /* This port has switched fabrics. FLOGI is required */ - lpfc_issue_init_vfi(vport); - } else { - /* FAN verified - skip FLOGI */ - vport->fc_myDID = vport->fc_prevDID; - if (phba->sli_rev < LPFC_SLI_REV4) - lpfc_issue_fabric_reglogin(vport); - else { - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "3138 Need register VFI: (x%x/%x)\n", - vport->fc_prevDID, vport->fc_myDID); - lpfc_issue_reg_vfi(vport); - } - } - } - return 0; -} - -/** - * lpfc_els_timeout - Handler funciton to the els timer - * @ptr: holder for the timer function associated data. - * - * This routine is invoked by the ELS timer after timeout. It posts the ELS - * timer timeout event by setting the WORKER_ELS_TMO bit to the work port - * event bitmap and then invokes the lpfc_worker_wake_up() routine to wake - * up the worker thread. It is for the worker thread to invoke the routine - * lpfc_els_timeout_handler() to work on the posted event WORKER_ELS_TMO. - **/ -void -lpfc_els_timeout(unsigned long ptr) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) ptr; - struct lpfc_hba *phba = vport->phba; - uint32_t tmo_posted; - unsigned long iflag; - - spin_lock_irqsave(&vport->work_port_lock, iflag); - tmo_posted = vport->work_port_events & WORKER_ELS_TMO; - if (!tmo_posted) - vport->work_port_events |= WORKER_ELS_TMO; - spin_unlock_irqrestore(&vport->work_port_lock, iflag); - - if (!tmo_posted) - lpfc_worker_wake_up(phba); - return; -} - - -/** - * lpfc_els_timeout_handler - Process an els timeout event - * @vport: pointer to a virtual N_Port data structure. - * - * This routine is the actual handler function that processes an ELS timeout - * event. It walks the ELS ring to get and abort all the IOCBs (except the - * ABORT/CLOSE/FARP/FARPR/FDISC), which are associated with the @vport by - * invoking the lpfc_sli_issue_abort_iotag() routine. - **/ -void -lpfc_els_timeout_handler(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_sli_ring *pring; - struct lpfc_iocbq *tmp_iocb, *piocb; - IOCB_t *cmd = NULL; - struct lpfc_dmabuf *pcmd; - uint32_t els_command = 0; - uint32_t timeout; - uint32_t remote_ID = 0xffffffff; - LIST_HEAD(txcmplq_completions); - LIST_HEAD(abort_list); - - - timeout = (uint32_t)(phba->fc_ratov << 1); - - pring = &phba->sli.ring[LPFC_ELS_RING]; - - spin_lock_irq(&phba->hbalock); - list_splice_init(&pring->txcmplq, &txcmplq_completions); - spin_unlock_irq(&phba->hbalock); - - list_for_each_entry_safe(piocb, tmp_iocb, &txcmplq_completions, list) { - cmd = &piocb->iocb; - - if ((piocb->iocb_flag & LPFC_IO_LIBDFC) != 0 || - piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || - piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) - continue; - - if (piocb->vport != vport) - continue; - - pcmd = (struct lpfc_dmabuf *) piocb->context2; - if (pcmd) - els_command = *(uint32_t *) (pcmd->virt); - - if (els_command == ELS_CMD_FARP || - els_command == ELS_CMD_FARPR || - els_command == ELS_CMD_FDISC) - continue; - - if (piocb->drvrTimeout > 0) { - if (piocb->drvrTimeout >= timeout) - piocb->drvrTimeout -= timeout; - else - piocb->drvrTimeout = 0; - continue; - } - - remote_ID = 0xffffffff; - if (cmd->ulpCommand != CMD_GEN_REQUEST64_CR) - remote_ID = cmd->un.elsreq64.remoteID; - else { - struct lpfc_nodelist *ndlp; - ndlp = __lpfc_findnode_rpi(vport, cmd->ulpContext); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) - remote_ID = ndlp->nlp_DID; - } - list_add_tail(&piocb->dlist, &abort_list); - } - spin_lock_irq(&phba->hbalock); - list_splice(&txcmplq_completions, &pring->txcmplq); - spin_unlock_irq(&phba->hbalock); - - list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0127 ELS timeout Data: x%x x%x x%x " - "x%x\n", els_command, - remote_ID, cmd->ulpCommand, cmd->ulpIoTag); - spin_lock_irq(&phba->hbalock); - list_del_init(&piocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, piocb); - spin_unlock_irq(&phba->hbalock); - } - - if (phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt) - mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout); -} - -/** - * lpfc_els_flush_cmd - Clean up the outstanding els commands to a vport - * @vport: pointer to a host virtual N_Port data structure. - * - * This routine is used to clean up all the outstanding ELS commands on a - * @vport. It first aborts the @vport by invoking lpfc_fabric_abort_vport() - * routine. After that, it walks the ELS transmit queue to remove all the - * IOCBs with the @vport other than the QUE_RING and ABORT/CLOSE IOCBs. For - * the IOCBs with a non-NULL completion callback function, the callback - * function will be invoked with the status set to IOSTAT_LOCAL_REJECT and - * un.ulpWord[4] set to IOERR_SLI_ABORTED. For IOCBs with a NULL completion - * callback function, the IOCB will simply be released. Finally, it walks - * the ELS transmit completion queue to issue an abort IOCB to any transmit - * completion queue IOCB that is associated with the @vport and is not - * an IOCB from libdfc (i.e., the management plane IOCBs that are not - * part of the discovery state machine) out to HBA by invoking the - * lpfc_sli_issue_abort_iotag() routine. Note that this function issues the - * abort IOCB to any transmit completion queueed IOCB, it does not guarantee - * the IOCBs are aborted when this function returns. - **/ -void -lpfc_els_flush_cmd(struct lpfc_vport *vport) -{ - LIST_HEAD(completions); - struct lpfc_hba *phba = vport->phba; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct lpfc_iocbq *tmp_iocb, *piocb; - IOCB_t *cmd = NULL; - - lpfc_fabric_abort_vport(vport); - - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { - cmd = &piocb->iocb; - - if (piocb->iocb_flag & LPFC_IO_LIBDFC) { - continue; - } - - /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */ - if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN || - cmd->ulpCommand == CMD_QUE_RING_BUF64_CN || - cmd->ulpCommand == CMD_CLOSE_XRI_CN || - cmd->ulpCommand == CMD_ABORT_XRI_CN) - continue; - - if (piocb->vport != vport) - continue; - - list_move_tail(&piocb->list, &completions); - pring->txq_cnt--; - } - - list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { - if (piocb->iocb_flag & LPFC_IO_LIBDFC) { - continue; - } - - if (piocb->vport != vport) - continue; - - lpfc_sli_issue_abort_iotag(phba, pring, piocb); - } - spin_unlock_irq(&phba->hbalock); - - /* Cancell all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); - - return; -} - -/** - * lpfc_els_flush_all_cmd - Clean up all the outstanding els commands to a HBA - * @phba: pointer to lpfc hba data structure. - * - * This routine is used to clean up all the outstanding ELS commands on a - * @phba. It first aborts the @phba by invoking the lpfc_fabric_abort_hba() - * routine. After that, it walks the ELS transmit queue to remove all the - * IOCBs to the @phba other than the QUE_RING and ABORT/CLOSE IOCBs. For - * the IOCBs with the completion callback function associated, the callback - * function will be invoked with the status set to IOSTAT_LOCAL_REJECT and - * un.ulpWord[4] set to IOERR_SLI_ABORTED. For IOCBs without the completion - * callback function associated, the IOCB will simply be released. Finally, - * it walks the ELS transmit completion queue to issue an abort IOCB to any - * transmit completion queue IOCB that is not an IOCB from libdfc (i.e., the - * management plane IOCBs that are not part of the discovery state machine) - * out to HBA by invoking the lpfc_sli_issue_abort_iotag() routine. - **/ -void -lpfc_els_flush_all_cmd(struct lpfc_hba *phba) -{ - LIST_HEAD(completions); - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct lpfc_iocbq *tmp_iocb, *piocb; - IOCB_t *cmd = NULL; - - lpfc_fabric_abort_hba(phba); - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(piocb, tmp_iocb, &pring->txq, list) { - cmd = &piocb->iocb; - if (piocb->iocb_flag & LPFC_IO_LIBDFC) - continue; - /* Do not flush out the QUE_RING and ABORT/CLOSE iocbs */ - if (cmd->ulpCommand == CMD_QUE_RING_BUF_CN || - cmd->ulpCommand == CMD_QUE_RING_BUF64_CN || - cmd->ulpCommand == CMD_CLOSE_XRI_CN || - cmd->ulpCommand == CMD_ABORT_XRI_CN) - continue; - list_move_tail(&piocb->list, &completions); - pring->txq_cnt--; - } - list_for_each_entry_safe(piocb, tmp_iocb, &pring->txcmplq, list) { - if (piocb->iocb_flag & LPFC_IO_LIBDFC) - continue; - lpfc_sli_issue_abort_iotag(phba, pring, piocb); - } - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); - - return; -} - -/** - * lpfc_send_els_failure_event - Posts an ELS command failure event - * @phba: Pointer to hba context object. - * @cmdiocbp: Pointer to command iocb which reported error. - * @rspiocbp: Pointer to response iocb which reported error. - * - * This function sends an event when there is an ELS command - * failure. - **/ -void -lpfc_send_els_failure_event(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocbp, - struct lpfc_iocbq *rspiocbp) -{ - struct lpfc_vport *vport = cmdiocbp->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_lsrjt_event lsrjt_event; - struct lpfc_fabric_event_header fabric_event; - struct ls_rjt stat; - struct lpfc_nodelist *ndlp; - uint32_t *pcmd; - - ndlp = cmdiocbp->context1; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - return; - - if (rspiocbp->iocb.ulpStatus == IOSTAT_LS_RJT) { - lsrjt_event.header.event_type = FC_REG_ELS_EVENT; - lsrjt_event.header.subcategory = LPFC_EVENT_LSRJT_RCV; - memcpy(lsrjt_event.header.wwpn, &ndlp->nlp_portname, - sizeof(struct lpfc_name)); - memcpy(lsrjt_event.header.wwnn, &ndlp->nlp_nodename, - sizeof(struct lpfc_name)); - pcmd = (uint32_t *) (((struct lpfc_dmabuf *) - cmdiocbp->context2)->virt); - lsrjt_event.command = (pcmd != NULL) ? *pcmd : 0; - stat.un.lsRjtError = be32_to_cpu(rspiocbp->iocb.un.ulpWord[4]); - lsrjt_event.reason_code = stat.un.b.lsRjtRsnCode; - lsrjt_event.explanation = stat.un.b.lsRjtRsnCodeExp; - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(lsrjt_event), - (char *)&lsrjt_event, - LPFC_NL_VENDOR_ID); - return; - } - if ((rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) || - (rspiocbp->iocb.ulpStatus == IOSTAT_FABRIC_BSY)) { - fabric_event.event_type = FC_REG_FABRIC_EVENT; - if (rspiocbp->iocb.ulpStatus == IOSTAT_NPORT_BSY) - fabric_event.subcategory = LPFC_EVENT_PORT_BUSY; - else - fabric_event.subcategory = LPFC_EVENT_FABRIC_BUSY; - memcpy(fabric_event.wwpn, &ndlp->nlp_portname, - sizeof(struct lpfc_name)); - memcpy(fabric_event.wwnn, &ndlp->nlp_nodename, - sizeof(struct lpfc_name)); - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(fabric_event), - (char *)&fabric_event, - LPFC_NL_VENDOR_ID); - return; - } - -} - -/** - * lpfc_send_els_event - Posts unsolicited els event - * @vport: Pointer to vport object. - * @ndlp: Pointer FC node object. - * @cmd: ELS command code. - * - * This function posts an event when there is an incoming - * unsolicited ELS command. - **/ -static void -lpfc_send_els_event(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - uint32_t *payload) -{ - struct lpfc_els_event_header *els_data = NULL; - struct lpfc_logo_event *logo_data = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (*payload == ELS_CMD_LOGO) { - logo_data = kmalloc(sizeof(struct lpfc_logo_event), GFP_KERNEL); - if (!logo_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0148 Failed to allocate memory " - "for LOGO event\n"); - return; - } - els_data = &logo_data->header; - } else { - els_data = kmalloc(sizeof(struct lpfc_els_event_header), - GFP_KERNEL); - if (!els_data) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0149 Failed to allocate memory " - "for ELS event\n"); - return; - } - } - els_data->event_type = FC_REG_ELS_EVENT; - switch (*payload) { - case ELS_CMD_PLOGI: - els_data->subcategory = LPFC_EVENT_PLOGI_RCV; - break; - case ELS_CMD_PRLO: - els_data->subcategory = LPFC_EVENT_PRLO_RCV; - break; - case ELS_CMD_ADISC: - els_data->subcategory = LPFC_EVENT_ADISC_RCV; - break; - case ELS_CMD_LOGO: - els_data->subcategory = LPFC_EVENT_LOGO_RCV; - /* Copy the WWPN in the LOGO payload */ - memcpy(logo_data->logo_wwpn, &payload[2], - sizeof(struct lpfc_name)); - break; - default: - kfree(els_data); - return; - } - memcpy(els_data->wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name)); - memcpy(els_data->wwnn, &ndlp->nlp_nodename, sizeof(struct lpfc_name)); - if (*payload == ELS_CMD_LOGO) { - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(struct lpfc_logo_event), - (char *)logo_data, - LPFC_NL_VENDOR_ID); - kfree(logo_data); - } else { - fc_host_post_vendor_event(shost, - fc_get_event_number(), - sizeof(struct lpfc_els_event_header), - (char *)els_data, - LPFC_NL_VENDOR_ID); - kfree(els_data); - } - - return; -} - - -/** - * lpfc_els_unsol_buffer - Process an unsolicited event data buffer - * @phba: pointer to lpfc hba data structure. - * @pring: pointer to a SLI ring. - * @vport: pointer to a host virtual N_Port data structure. - * @elsiocb: pointer to lpfc els command iocb data structure. - * - * This routine is used for processing the IOCB associated with a unsolicited - * event. It first determines whether there is an existing ndlp that matches - * the DID from the unsolicited IOCB. If not, it will create a new one with - * the DID from the unsolicited IOCB. The ELS command from the unsolicited - * IOCB is then used to invoke the proper routine and to set up proper state - * of the discovery state machine. - **/ -static void -lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_vport *vport, struct lpfc_iocbq *elsiocb) -{ - struct Scsi_Host *shost; - struct lpfc_nodelist *ndlp; - struct ls_rjt stat; - uint32_t *payload; - uint32_t cmd, did, newnode, rjt_err = 0; - IOCB_t *icmd = &elsiocb->iocb; - - if (!vport || !(elsiocb->context2)) - goto dropit; - - newnode = 0; - payload = ((struct lpfc_dmabuf *)elsiocb->context2)->virt; - cmd = *payload; - if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) == 0) - lpfc_post_buffer(phba, pring, 1); - - did = icmd->un.rcvels.remoteID; - if (icmd->ulpStatus) { - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV Unsol ELS: status:x%x/x%x did:x%x", - icmd->ulpStatus, icmd->un.ulpWord[4], did); - goto dropit; - } - - /* Check to see if link went down during discovery */ - if (lpfc_els_chk_latt(vport)) - goto dropit; - - /* Ignore traffic received during vport shutdown. */ - if (vport->load_flag & FC_UNLOADING) - goto dropit; - - /* If NPort discovery is delayed drop incoming ELS */ - if ((vport->fc_flag & FC_DISC_DELAYED) && - (cmd != ELS_CMD_PLOGI)) - goto dropit; - - ndlp = lpfc_findnode_did(vport, did); - if (!ndlp) { - /* Cannot find existing Fabric ndlp, so allocate a new one */ - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - goto dropit; - - lpfc_nlp_init(vport, ndlp, did); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - newnode = 1; - if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) - ndlp->nlp_type |= NLP_FABRIC; - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto dropit; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - newnode = 1; - if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) - ndlp->nlp_type |= NLP_FABRIC; - } else if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { - /* This is similar to the new node path */ - ndlp = lpfc_nlp_get(ndlp); - if (!ndlp) - goto dropit; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - newnode = 1; - } - - phba->fc_stat.elsRcvFrame++; - - elsiocb->context1 = lpfc_nlp_get(ndlp); - elsiocb->vport = vport; - - if ((cmd & ELS_CMD_MASK) == ELS_CMD_RSCN) { - cmd &= ELS_CMD_MASK; - } - /* ELS command received from NPORT */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0112 ELS command x%x received from NPORT x%x " - "Data: x%x\n", cmd, did, vport->port_state); - switch (cmd) { - case ELS_CMD_PLOGI: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV PLOGI: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvPLOGI++; - ndlp = lpfc_plogi_confirm_nport(phba, payload, ndlp); - - lpfc_send_els_event(vport, ndlp, payload); - - /* If Nport discovery is delayed, reject PLOGIs */ - if (vport->fc_flag & FC_DISC_DELAYED) { - rjt_err = LSRJT_UNABLE_TPC; - break; - } - if (vport->port_state < LPFC_DISC_AUTH) { - if (!(phba->pport->fc_flag & FC_PT2PT) || - (phba->pport->fc_flag & FC_PT2PT_PLOGI)) { - rjt_err = LSRJT_UNABLE_TPC; - break; - } - /* We get here, and drop thru, if we are PT2PT with - * another NPort and the other side has initiated - * the PLOGI before responding to our FLOGI. - */ - } - - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_TARGET_REMOVE; - spin_unlock_irq(shost->host_lock); - - lpfc_disc_state_machine(vport, ndlp, elsiocb, - NLP_EVT_RCV_PLOGI); - - break; - case ELS_CMD_FLOGI: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FLOGI: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvFLOGI++; - lpfc_els_rcv_flogi(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_LOGO: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV LOGO: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvLOGO++; - lpfc_send_els_event(vport, ndlp, payload); - if (vport->port_state < LPFC_DISC_AUTH) { - rjt_err = LSRJT_UNABLE_TPC; - break; - } - lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_LOGO); - break; - case ELS_CMD_PRLO: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV PRLO: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvPRLO++; - lpfc_send_els_event(vport, ndlp, payload); - if (vport->port_state < LPFC_DISC_AUTH) { - rjt_err = LSRJT_UNABLE_TPC; - break; - } - lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLO); - break; - case ELS_CMD_RSCN: - phba->fc_stat.elsRcvRSCN++; - lpfc_els_rcv_rscn(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_ADISC: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV ADISC: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - lpfc_send_els_event(vport, ndlp, payload); - phba->fc_stat.elsRcvADISC++; - if (vport->port_state < LPFC_DISC_AUTH) { - rjt_err = LSRJT_UNABLE_TPC; - break; - } - lpfc_disc_state_machine(vport, ndlp, elsiocb, - NLP_EVT_RCV_ADISC); - break; - case ELS_CMD_PDISC: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV PDISC: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvPDISC++; - if (vport->port_state < LPFC_DISC_AUTH) { - rjt_err = LSRJT_UNABLE_TPC; - break; - } - lpfc_disc_state_machine(vport, ndlp, elsiocb, - NLP_EVT_RCV_PDISC); - break; - case ELS_CMD_FARPR: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FARPR: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvFARPR++; - lpfc_els_rcv_farpr(vport, elsiocb, ndlp); - break; - case ELS_CMD_FARP: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FARP: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvFARP++; - lpfc_els_rcv_farp(vport, elsiocb, ndlp); - break; - case ELS_CMD_FAN: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV FAN: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvFAN++; - lpfc_els_rcv_fan(vport, elsiocb, ndlp); - break; - case ELS_CMD_PRLI: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV PRLI: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvPRLI++; - if (vport->port_state < LPFC_DISC_AUTH) { - rjt_err = LSRJT_UNABLE_TPC; - break; - } - lpfc_disc_state_machine(vport, ndlp, elsiocb, NLP_EVT_RCV_PRLI); - break; - case ELS_CMD_LIRR: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV LIRR: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvLIRR++; - lpfc_els_rcv_lirr(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_RLS: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RLS: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvRLS++; - lpfc_els_rcv_rls(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_RPS: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RPS: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvRPS++; - lpfc_els_rcv_rps(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_RPL: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RPL: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvRPL++; - lpfc_els_rcv_rpl(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_RNID: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RNID: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvRNID++; - lpfc_els_rcv_rnid(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_RTV: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RTV: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - phba->fc_stat.elsRcvRTV++; - lpfc_els_rcv_rtv(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_RRQ: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV RRQ: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvRRQ++; - lpfc_els_rcv_rrq(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - case ELS_CMD_ECHO: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV ECHO: did:x%x/ste:x%x flg:x%x", - did, vport->port_state, ndlp->nlp_flag); - - phba->fc_stat.elsRcvECHO++; - lpfc_els_rcv_echo(vport, elsiocb, ndlp); - if (newnode) - lpfc_nlp_put(ndlp); - break; - default: - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, - "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", - cmd, did, vport->port_state); - - /* Unsupported ELS command, reject */ - rjt_err = LSRJT_CMD_UNSUPPORTED; - - /* Unknown ELS command received from NPORT */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0115 Unknown ELS command x%x " - "received from NPORT x%x\n", cmd, did); - if (newnode) - lpfc_nlp_put(ndlp); - break; - } - - /* check if need to LS_RJT received ELS cmd */ - if (rjt_err) { - memset(&stat, 0, sizeof(stat)); - stat.un.b.lsRjtRsnCode = rjt_err; - stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, elsiocb, ndlp, - NULL); - } - - lpfc_nlp_put(elsiocb->context1); - elsiocb->context1 = NULL; - return; - -dropit: - if (vport && !(vport->load_flag & FC_UNLOADING)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0111 Dropping received ELS cmd " - "Data: x%x x%x x%x\n", - icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout); - phba->fc_stat.elsRcvDrop++; -} - -/** - * lpfc_els_unsol_event - Process an unsolicited event from an els sli ring - * @phba: pointer to lpfc hba data structure. - * @pring: pointer to a SLI ring. - * @elsiocb: pointer to lpfc els iocb data structure. - * - * This routine is used to process an unsolicited event received from a SLI - * (Service Level Interface) ring. The actual processing of the data buffer - * associated with the unsolicited event is done by invoking the routine - * lpfc_els_unsol_buffer() after properly set up the iocb buffer from the - * SLI ring on which the unsolicited event was received. - **/ -void -lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *elsiocb) -{ - struct lpfc_vport *vport = phba->pport; - IOCB_t *icmd = &elsiocb->iocb; - dma_addr_t paddr; - struct lpfc_dmabuf *bdeBuf1 = elsiocb->context2; - struct lpfc_dmabuf *bdeBuf2 = elsiocb->context3; - - elsiocb->context1 = NULL; - elsiocb->context2 = NULL; - elsiocb->context3 = NULL; - - if (icmd->ulpStatus == IOSTAT_NEED_BUFFER) { - lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); - } else if (icmd->ulpStatus == IOSTAT_LOCAL_REJECT && - (icmd->un.ulpWord[4] & 0xff) == IOERR_RCV_BUFFER_WAITING) { - phba->fc_stat.NoRcvBuf++; - /* Not enough posted buffers; Try posting more buffers */ - if (!(phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) - lpfc_post_buffer(phba, pring, 0); - return; - } - - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - (icmd->ulpCommand == CMD_IOCB_RCV_ELS64_CX || - icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) { - if (icmd->unsli3.rcvsli3.vpi == 0xffff) - vport = phba->pport; - else - vport = lpfc_find_vport_by_vpid(phba, - icmd->unsli3.rcvsli3.vpi); - } - - /* If there are no BDEs associated - * with this IOCB, there is nothing to do. - */ - if (icmd->ulpBdeCount == 0) - return; - - /* type of ELS cmd is first 32bit word - * in packet - */ - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - elsiocb->context2 = bdeBuf1; - } else { - paddr = getPaddr(icmd->un.cont64[0].addrHigh, - icmd->un.cont64[0].addrLow); - elsiocb->context2 = lpfc_sli_ringpostbuf_get(phba, pring, - paddr); - } - - lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); - /* - * The different unsolicited event handlers would tell us - * if they are done with "mp" by setting context2 to NULL. - */ - if (elsiocb->context2) { - lpfc_in_buf_free(phba, (struct lpfc_dmabuf *)elsiocb->context2); - elsiocb->context2 = NULL; - } - - /* RCV_ELS64_CX provide for 2 BDEs - process 2nd if included */ - if ((phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) && - icmd->ulpBdeCount == 2) { - elsiocb->context2 = bdeBuf2; - lpfc_els_unsol_buffer(phba, pring, vport, elsiocb); - /* free mp if we are done with it */ - if (elsiocb->context2) { - lpfc_in_buf_free(phba, elsiocb->context2); - elsiocb->context2 = NULL; - } - } -} - -/** - * lpfc_do_scr_ns_plogi - Issue a plogi to the name server for scr - * @phba: pointer to lpfc hba data structure. - * @vport: pointer to a virtual N_Port data structure. - * - * This routine issues a Port Login (PLOGI) to the Name Server with - * State Change Request (SCR) for a @vport. This routine will create an - * ndlp for the Name Server associated to the @vport if such node does - * not already exist. The PLOGI to Name Server is issued by invoking the - * lpfc_issue_els_plogi() routine. If Fabric-Device Management Interface - * (FDMI) is configured to the @vport, a FDMI node will be created and - * the PLOGI to FDMI is issued by invoking lpfc_issue_els_plogi() routine. - **/ -void -lpfc_do_scr_ns_plogi(struct lpfc_hba *phba, struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp, *ndlp_fdmi; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - /* - * If lpfc_delay_discovery parameter is set and the clean address - * bit is cleared and fc fabric parameters chenged, delay FC NPort - * discovery. - */ - spin_lock_irq(shost->host_lock); - if (vport->fc_flag & FC_DISC_DELAYED) { - spin_unlock_irq(shost->host_lock); - mod_timer(&vport->delayed_disc_tmo, - jiffies + HZ * phba->fc_ratov); - return; - } - spin_unlock_irq(shost->host_lock); - - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (!ndlp) { - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) { - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - lpfc_disc_start(vport); - return; - } - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0251 NameServer login: no memory\n"); - return; - } - lpfc_nlp_init(vport, ndlp, NameServer_DID); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) { - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - lpfc_disc_start(vport); - return; - } - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0348 NameServer login: node freed\n"); - return; - } - } - ndlp->nlp_type |= NLP_FABRIC; - - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - - if (lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0)) { - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0252 Cannot issue NameServer login\n"); - return; - } - - if (vport->cfg_fdmi_on) { - /* If this is the first time, allocate an ndlp and initialize - * it. Otherwise, make sure the node is enabled and then do the - * login. - */ - ndlp_fdmi = lpfc_findnode_did(vport, FDMI_DID); - if (!ndlp_fdmi) { - ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool, - GFP_KERNEL); - if (ndlp_fdmi) { - lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID); - ndlp_fdmi->nlp_type |= NLP_FABRIC; - } else - return; - } - if (!NLP_CHK_NODE_ACT(ndlp_fdmi)) - ndlp_fdmi = lpfc_enable_node(vport, - ndlp_fdmi, - NLP_STE_NPR_NODE); - - if (ndlp_fdmi) { - lpfc_nlp_set_state(vport, ndlp_fdmi, - NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, ndlp_fdmi->nlp_DID, 0); - } - } -} - -/** - * lpfc_cmpl_reg_new_vport - Completion callback function to register new vport - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This routine is the completion callback function to register new vport - * mailbox command. If the new vport mailbox command completes successfully, - * the fabric registration login shall be performed on physical port (the - * new vport created is actually a physical port, with VPI 0) or the port - * login to Name Server for State Change Request (SCR) will be performed - * on virtual port (real virtual port, with VPI greater than 0). - **/ -static void -lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; - MAILBOX_t *mb = &pmb->u.mb; - int rc; - - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - - if (mb->mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0915 Register VPI failed : Status: x%x" - " upd bit: x%x \n", mb->mbxStatus, - mb->un.varRegVpi.upd); - if (phba->sli_rev == LPFC_SLI_REV4 && - mb->un.varRegVpi.upd) - goto mbox_err_exit ; - - switch (mb->mbxStatus) { - case 0x11: /* unsupported feature */ - case 0x9603: /* max_vpi exceeded */ - case 0x9602: /* Link event since CLEAR_LA */ - /* giving up on vport registration */ - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - break; - /* If reg_vpi fail with invalid VPI status, re-init VPI */ - case 0x20: - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - lpfc_init_vpi(phba, pmb, vport->vpi); - pmb->vport = vport; - pmb->mbox_cmpl = lpfc_init_vpi_cmpl; - rc = lpfc_sli_issue_mbox(phba, pmb, - MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, - KERN_ERR, LOG_MBOX, - "2732 Failed to issue INIT_VPI" - " mailbox command\n"); - } else { - lpfc_nlp_put(ndlp); - return; - } - - default: - /* Try to recover from this error */ - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_unreg_all_rpis(vport); - lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - if (vport->port_type == LPFC_PHYSICAL_PORT - && !(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) - lpfc_issue_init_vfi(vport); - else - lpfc_initial_fdisc(vport); - break; - } - } else { - spin_lock_irq(shost->host_lock); - vport->vpi_state |= LPFC_VPI_REGISTERED; - spin_unlock_irq(shost->host_lock); - if (vport == phba->pport) { - if (phba->sli_rev < LPFC_SLI_REV4) - lpfc_issue_fabric_reglogin(vport); - else { - /* - * If the physical port is instantiated using - * FDISC, do not start vport discovery. - */ - if (vport->port_state != LPFC_FDISC) - lpfc_start_fdiscs(phba); - lpfc_do_scr_ns_plogi(phba, vport); - } - } else - lpfc_do_scr_ns_plogi(phba, vport); - } -mbox_err_exit: - /* Now, we decrement the ndlp reference count held for this - * callback function - */ - lpfc_nlp_put(ndlp); - - mempool_free(pmb, phba->mbox_mem_pool); - return; -} - -/** - * lpfc_register_new_vport - Register a new vport with a HBA - * @phba: pointer to lpfc hba data structure. - * @vport: pointer to a host virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine registers the @vport as a new virtual port with a HBA. - * It is done through a registering vpi mailbox command. - **/ -void -lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - LPFC_MBOXQ_t *mbox; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox) { - lpfc_reg_vpi(vport, mbox); - mbox->vport = vport; - mbox->context2 = lpfc_nlp_get(ndlp); - mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - == MBX_NOT_FINISHED) { - /* mailbox command not success, decrement ndlp - * reference count for this command - */ - lpfc_nlp_put(ndlp); - mempool_free(mbox, phba->mbox_mem_pool); - - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0253 Register VPI: Can't send mbox\n"); - goto mbox_err_exit; - } - } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0254 Register VPI: no memory\n"); - goto mbox_err_exit; - } - return; - -mbox_err_exit: - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - return; -} - -/** - * lpfc_cancel_all_vport_retry_delay_timer - Cancel all vport retry delay timer - * @phba: pointer to lpfc hba data structure. - * - * This routine cancels the retry delay timers to all the vports. - **/ -void -lpfc_cancel_all_vport_retry_delay_timer(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - struct lpfc_nodelist *ndlp; - uint32_t link_state; - int i; - - /* Treat this failure as linkdown for all vports */ - link_state = phba->link_state; - lpfc_linkdown(phba); - phba->link_state = link_state; - - vports = lpfc_create_vport_work_array(phba); - - if (vports) { - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - ndlp = lpfc_findnode_did(vports[i], Fabric_DID); - if (ndlp) - lpfc_cancel_retry_delay_tmo(vports[i], ndlp); - lpfc_els_flush_cmd(vports[i]); - } - lpfc_destroy_vport_work_array(phba, vports); - } -} - -/** - * lpfc_retry_pport_discovery - Start timer to retry FLOGI. - * @phba: pointer to lpfc hba data structure. - * - * This routine abort all pending discovery commands and - * start a timer to retry FLOGI for the physical port - * discovery. - **/ -void -lpfc_retry_pport_discovery(struct lpfc_hba *phba) -{ - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; - - /* Cancel the all vports retry delay retry timers */ - lpfc_cancel_all_vport_retry_delay_timer(phba); - - /* If fabric require FLOGI, then re-instantiate physical login */ - ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (!ndlp) - return; - - shost = lpfc_shost_from_vport(phba->pport); - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; - phba->pport->port_state = LPFC_FLOGI; - return; -} - -/** - * lpfc_fabric_login_reqd - Check if FLOGI required. - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to FDISC command iocb. - * @rspiocb: pointer to FDISC response iocb. - * - * This routine checks if a FLOGI is reguired for FDISC - * to succeed. - **/ -static int -lpfc_fabric_login_reqd(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - - if ((rspiocb->iocb.ulpStatus != IOSTAT_FABRIC_RJT) || - (rspiocb->iocb.un.ulpWord[4] != RJT_LOGIN_REQUIRED)) - return 0; - else - return 1; -} - -/** - * lpfc_cmpl_els_fdisc - Completion function for fdisc iocb command - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the completion callback function to a Fabric Discover - * (FDISC) ELS command. Since all the FDISC ELS commands are issued - * single threaded, each FDISC completion callback function will reset - * the discovery timer for all vports such that the timers will not get - * unnecessary timeout. The function checks the FDISC IOCB status. If error - * detected, the vport will be set to FC_VPORT_FAILED state. Otherwise,the - * vport will set to FC_VPORT_ACTIVE state. It then checks whether the DID - * assigned to the vport has been changed with the completion of the FDISC - * command. If so, both RPI (Remote Port Index) and VPI (Virtual Port Index) - * are unregistered from the HBA, and then the lpfc_register_new_vport() - * routine is invoked to register new vport with the HBA. Otherwise, the - * lpfc_do_scr_ns_plogi() routine is invoked to issue a PLOGI to the Name - * Server for State Change Request (SCR). - **/ -static void -lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) cmdiocb->context1; - struct lpfc_nodelist *np; - struct lpfc_nodelist *next_np; - IOCB_t *irsp = &rspiocb->iocb; - struct lpfc_iocbq *piocb; - struct lpfc_dmabuf *pcmd = cmdiocb->context2, *prsp; - struct serv_parm *sp; - uint8_t fabric_param_changed; - - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0123 FDISC completes. x%x/x%x prevDID: x%x\n", - irsp->ulpStatus, irsp->un.ulpWord[4], - vport->fc_prevDID); - /* Since all FDISCs are being single threaded, we - * must reset the discovery timer for ALL vports - * waiting to send FDISC when one completes. - */ - list_for_each_entry(piocb, &phba->fabric_iocb_list, list) { - lpfc_set_disctmo(piocb->vport); - } - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "FDISC cmpl: status:x%x/x%x prevdid:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID); - - if (irsp->ulpStatus) { - - if (lpfc_fabric_login_reqd(phba, cmdiocb, rspiocb)) { - lpfc_retry_pport_discovery(phba); - goto out; - } - - /* Check for retry */ - if (lpfc_els_retry(phba, cmdiocb, rspiocb)) - goto out; - /* FDISC failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0126 FDISC failed. (x%x/x%x)\n", - irsp->ulpStatus, irsp->un.ulpWord[4]); - goto fdisc_failed; - } - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_CVL_RCVD; - vport->fc_flag &= ~FC_VPORT_LOGO_RCVD; - vport->fc_flag |= FC_FABRIC; - if (vport->phba->fc_topology == LPFC_TOPOLOGY_LOOP) - vport->fc_flag |= FC_PUBLIC_LOOP; - spin_unlock_irq(shost->host_lock); - - vport->fc_myDID = irsp->un.ulpWord[4] & Mask_DID; - lpfc_vport_set_state(vport, FC_VPORT_ACTIVE); - prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); - sp = prsp->virt + sizeof(uint32_t); - fabric_param_changed = lpfc_check_clean_addr_bit(vport, sp); - memcpy(&vport->fabric_portname, &sp->portName, - sizeof(struct lpfc_name)); - memcpy(&vport->fabric_nodename, &sp->nodeName, - sizeof(struct lpfc_name)); - if (fabric_param_changed && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { - /* If our NportID changed, we need to ensure all - * remaining NPORTs get unreg_login'ed so we can - * issue unreg_vpi. - */ - list_for_each_entry_safe(np, next_np, - &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp) || - (np->nlp_state != NLP_STE_NPR_NODE) || - !(np->nlp_flag & NLP_NPR_ADISC)) - continue; - spin_lock_irq(shost->host_lock); - np->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - lpfc_unreg_rpi(vport, np); - } - lpfc_cleanup_pending_mbox(vport); - - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_unreg_all_rpis(vport); - - lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - if (phba->sli_rev == LPFC_SLI_REV4) - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - else - vport->fc_flag |= FC_LOGO_RCVD_DID_CHNG; - spin_unlock_irq(shost->host_lock); - } else if ((phba->sli_rev == LPFC_SLI_REV4) && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) { - /* - * Driver needs to re-reg VPI in order for f/w - * to update the MAC address. - */ - lpfc_register_new_vport(phba, vport, ndlp); - goto out; - } - - if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) - lpfc_issue_init_vpi(vport); - else if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) - lpfc_register_new_vport(phba, vport, ndlp); - else - lpfc_do_scr_ns_plogi(phba, vport); - goto out; -fdisc_failed: - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - /* Cancel discovery timer */ - lpfc_can_disctmo(vport); - lpfc_nlp_put(ndlp); -out: - lpfc_els_free_iocb(phba, cmdiocb); -} - -/** - * lpfc_issue_els_fdisc - Issue a fdisc iocb command - * @vport: pointer to a virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * @retry: number of retries to the command IOCB. - * - * This routine prepares and issues a Fabric Discover (FDISC) IOCB to - * a remote node (@ndlp) off a @vport. It uses the lpfc_issue_fabric_iocb() - * routine to issue the IOCB, which makes sure only one outstanding fabric - * IOCB will be sent off HBA at any given time. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the FDISC ELS command. - * - * Return code - * 0 - Successfully issued fdisc iocb command - * 1 - Failed to issue fdisc iocb command - **/ -static int -lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint8_t retry) -{ - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - struct serv_parm *sp; - uint8_t *pcmd; - uint16_t cmdsize; - int did = ndlp->nlp_DID; - int rc; - - vport->port_state = LPFC_FDISC; - vport->fc_myDID = 0; - cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, - ELS_CMD_FDISC); - if (!elsiocb) { - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0255 Issue FDISC: no IOCB\n"); - return 1; - } - - icmd = &elsiocb->iocb; - icmd->un.elsreq64.myID = 0; - icmd->un.elsreq64.fl = 1; - - /* - * SLI3 ports require a different context type value than SLI4. - * Catch SLI3 ports here and override the prep. - */ - if (phba->sli_rev == LPFC_SLI_REV3) { - icmd->ulpCt_h = 1; - icmd->ulpCt_l = 0; - } - - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_FDISC; - pcmd += sizeof(uint32_t); /* CSP Word 1 */ - memcpy(pcmd, &vport->phba->pport->fc_sparam, sizeof(struct serv_parm)); - sp = (struct serv_parm *) pcmd; - /* Setup CSPs accordingly for Fabric */ - sp->cmn.e_d_tov = 0; - sp->cmn.w2.r_a_tov = 0; - sp->cmn.virtual_fabric_support = 0; - sp->cls1.classValid = 0; - sp->cls2.seqDelivery = 1; - sp->cls3.seqDelivery = 1; - - pcmd += sizeof(uint32_t); /* CSP Word 2 */ - pcmd += sizeof(uint32_t); /* CSP Word 3 */ - pcmd += sizeof(uint32_t); /* CSP Word 4 */ - pcmd += sizeof(uint32_t); /* Port Name */ - memcpy(pcmd, &vport->fc_portname, 8); - pcmd += sizeof(uint32_t); /* Node Name */ - pcmd += sizeof(uint32_t); /* Node Name */ - memcpy(pcmd, &vport->fc_nodename, 8); - - lpfc_set_disctmo(vport); - - phba->fc_stat.elsXmitFDISC++; - elsiocb->iocb_cmpl = lpfc_cmpl_els_fdisc; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue FDISC: did:x%x", - did, 0, 0); - - rc = lpfc_issue_fabric_iocb(phba, elsiocb); - if (rc == IOCB_ERROR) { - lpfc_els_free_iocb(phba, elsiocb); - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0256 Issue FDISC: Cannot send IOCB\n"); - return 1; - } - lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING); - return 0; -} - -/** - * lpfc_cmpl_els_npiv_logo - Completion function with vport logo - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the completion callback function to the issuing of a LOGO - * ELS command off a vport. It frees the command IOCB and then decrement the - * reference count held on ndlp for this completion function, indicating that - * the reference to the ndlp is no long needed. Note that the - * lpfc_els_free_iocb() routine decrements the ndlp reference held for this - * callback function and an additional explicit ndlp reference decrementation - * will trigger the actual release of the ndlp. - **/ -static void -lpfc_cmpl_els_npiv_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - IOCB_t *irsp; - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - ndlp = (struct lpfc_nodelist *)cmdiocb->context1; - irsp = &rspiocb->iocb; - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "LOGO npiv cmpl: status:x%x/x%x did:x%x", - irsp->ulpStatus, irsp->un.ulpWord[4], irsp->un.rcvels.remoteID); - - lpfc_els_free_iocb(phba, cmdiocb); - vport->unreg_vpi_cmpl = VPORT_ERROR; - - /* Trigger the release of the ndlp after logo */ - lpfc_nlp_put(ndlp); - - /* NPIV LOGO completes to NPort */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "2928 NPIV LOGO completes to NPort x%x " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, irsp->ulpStatus, irsp->un.ulpWord[4], - irsp->ulpTimeout, vport->num_disc_nodes); - - if (irsp->ulpStatus == IOSTAT_SUCCESS) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_FABRIC; - spin_unlock_irq(shost->host_lock); - } -} - -/** - * lpfc_issue_els_npiv_logo - Issue a logo off a vport - * @vport: pointer to a virtual N_Port data structure. - * @ndlp: pointer to a node-list data structure. - * - * This routine issues a LOGO ELS command to an @ndlp off a @vport. - * - * Note that, in lpfc_prep_els_iocb() routine, the reference count of ndlp - * will be incremented by 1 for holding the ndlp and the reference to ndlp - * will be stored into the context1 field of the IOCB for the completion - * callback function to the LOGO ELS command. - * - * Return codes - * 0 - Successfully issued logo off the @vport - * 1 - Failed to issue logo off the @vport - **/ -int -lpfc_issue_els_npiv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - IOCB_t *icmd; - struct lpfc_iocbq *elsiocb; - uint8_t *pcmd; - uint16_t cmdsize; - - cmdsize = 2 * sizeof(uint32_t) + sizeof(struct lpfc_name); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, 0, ndlp, ndlp->nlp_DID, - ELS_CMD_LOGO); - if (!elsiocb) - return 1; - - icmd = &elsiocb->iocb; - pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); - *((uint32_t *) (pcmd)) = ELS_CMD_LOGO; - pcmd += sizeof(uint32_t); - - /* Fill in LOGO payload */ - *((uint32_t *) (pcmd)) = be32_to_cpu(vport->fc_myDID); - pcmd += sizeof(uint32_t); - memcpy(pcmd, &vport->fc_portname, sizeof(struct lpfc_name)); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Issue LOGO npiv did:x%x flg:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, 0); - - elsiocb->iocb_cmpl = lpfc_cmpl_els_npiv_logo; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - if (lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, elsiocb, 0) == - IOCB_ERROR) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_LOGO_SND; - spin_unlock_irq(shost->host_lock); - lpfc_els_free_iocb(phba, elsiocb); - return 1; - } - return 0; -} - -/** - * lpfc_fabric_block_timeout - Handler function to the fabric block timer - * @ptr: holder for the timer function associated data. - * - * This routine is invoked by the fabric iocb block timer after - * timeout. It posts the fabric iocb block timeout event by setting the - * WORKER_FABRIC_BLOCK_TMO bit to work port event bitmap and then invokes - * lpfc_worker_wake_up() routine to wake up the worker thread. It is for - * the worker thread to invoke the lpfc_unblock_fabric_iocbs() on the - * posted event WORKER_FABRIC_BLOCK_TMO. - **/ -void -lpfc_fabric_block_timeout(unsigned long ptr) -{ - struct lpfc_hba *phba = (struct lpfc_hba *) ptr; - unsigned long iflags; - uint32_t tmo_posted; - - spin_lock_irqsave(&phba->pport->work_port_lock, iflags); - tmo_posted = phba->pport->work_port_events & WORKER_FABRIC_BLOCK_TMO; - if (!tmo_posted) - phba->pport->work_port_events |= WORKER_FABRIC_BLOCK_TMO; - spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); - - if (!tmo_posted) - lpfc_worker_wake_up(phba); - return; -} - -/** - * lpfc_resume_fabric_iocbs - Issue a fabric iocb from driver internal list - * @phba: pointer to lpfc hba data structure. - * - * This routine issues one fabric iocb from the driver internal list to - * the HBA. It first checks whether it's ready to issue one fabric iocb to - * the HBA (whether there is no outstanding fabric iocb). If so, it shall - * remove one pending fabric iocb from the driver internal list and invokes - * lpfc_sli_issue_iocb() routine to send the fabric iocb to the HBA. - **/ -static void -lpfc_resume_fabric_iocbs(struct lpfc_hba *phba) -{ - struct lpfc_iocbq *iocb; - unsigned long iflags; - int ret; - IOCB_t *cmd; - -repeat: - iocb = NULL; - spin_lock_irqsave(&phba->hbalock, iflags); - /* Post any pending iocb to the SLI layer */ - if (atomic_read(&phba->fabric_iocb_count) == 0) { - list_remove_head(&phba->fabric_iocb_list, iocb, typeof(*iocb), - list); - if (iocb) - /* Increment fabric iocb count to hold the position */ - atomic_inc(&phba->fabric_iocb_count); - } - spin_unlock_irqrestore(&phba->hbalock, iflags); - if (iocb) { - iocb->fabric_iocb_cmpl = iocb->iocb_cmpl; - iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb; - iocb->iocb_flag |= LPFC_IO_FABRIC; - - lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD, - "Fabric sched1: ste:x%x", - iocb->vport->port_state, 0, 0); - - ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0); - - if (ret == IOCB_ERROR) { - iocb->iocb_cmpl = iocb->fabric_iocb_cmpl; - iocb->fabric_iocb_cmpl = NULL; - iocb->iocb_flag &= ~LPFC_IO_FABRIC; - cmd = &iocb->iocb; - cmd->ulpStatus = IOSTAT_LOCAL_REJECT; - cmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - iocb->iocb_cmpl(phba, iocb, iocb); - - atomic_dec(&phba->fabric_iocb_count); - goto repeat; - } - } - - return; -} - -/** - * lpfc_unblock_fabric_iocbs - Unblock issuing fabric iocb command - * @phba: pointer to lpfc hba data structure. - * - * This routine unblocks the issuing fabric iocb command. The function - * will clear the fabric iocb block bit and then invoke the routine - * lpfc_resume_fabric_iocbs() to issue one of the pending fabric iocb - * from the driver internal fabric iocb list. - **/ -void -lpfc_unblock_fabric_iocbs(struct lpfc_hba *phba) -{ - clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); - - lpfc_resume_fabric_iocbs(phba); - return; -} - -/** - * lpfc_block_fabric_iocbs - Block issuing fabric iocb command - * @phba: pointer to lpfc hba data structure. - * - * This routine blocks the issuing fabric iocb for a specified amount of - * time (currently 100 ms). This is done by set the fabric iocb block bit - * and set up a timeout timer for 100ms. When the block bit is set, no more - * fabric iocb will be issued out of the HBA. - **/ -static void -lpfc_block_fabric_iocbs(struct lpfc_hba *phba) -{ - int blocked; - - blocked = test_and_set_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); - /* Start a timer to unblock fabric iocbs after 100ms */ - if (!blocked) - mod_timer(&phba->fabric_block_timer, jiffies + HZ/10 ); - - return; -} - -/** - * lpfc_cmpl_fabric_iocb - Completion callback function for fabric iocb - * @phba: pointer to lpfc hba data structure. - * @cmdiocb: pointer to lpfc command iocb data structure. - * @rspiocb: pointer to lpfc response iocb data structure. - * - * This routine is the callback function that is put to the fabric iocb's - * callback function pointer (iocb->iocb_cmpl). The original iocb's callback - * function pointer has been stored in iocb->fabric_iocb_cmpl. This callback - * function first restores and invokes the original iocb's callback function - * and then invokes the lpfc_resume_fabric_iocbs() routine to issue the next - * fabric bound iocb from the driver internal fabric iocb list onto the wire. - **/ -static void -lpfc_cmpl_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct ls_rjt stat; - - if ((cmdiocb->iocb_flag & LPFC_IO_FABRIC) != LPFC_IO_FABRIC) - BUG(); - - switch (rspiocb->iocb.ulpStatus) { - case IOSTAT_NPORT_RJT: - case IOSTAT_FABRIC_RJT: - if (rspiocb->iocb.un.ulpWord[4] & RJT_UNAVAIL_TEMP) { - lpfc_block_fabric_iocbs(phba); - } - break; - - case IOSTAT_NPORT_BSY: - case IOSTAT_FABRIC_BSY: - lpfc_block_fabric_iocbs(phba); - break; - - case IOSTAT_LS_RJT: - stat.un.lsRjtError = - be32_to_cpu(rspiocb->iocb.un.ulpWord[4]); - if ((stat.un.b.lsRjtRsnCode == LSRJT_UNABLE_TPC) || - (stat.un.b.lsRjtRsnCode == LSRJT_LOGICAL_BSY)) - lpfc_block_fabric_iocbs(phba); - break; - } - - if (atomic_read(&phba->fabric_iocb_count) == 0) - BUG(); - - cmdiocb->iocb_cmpl = cmdiocb->fabric_iocb_cmpl; - cmdiocb->fabric_iocb_cmpl = NULL; - cmdiocb->iocb_flag &= ~LPFC_IO_FABRIC; - cmdiocb->iocb_cmpl(phba, cmdiocb, rspiocb); - - atomic_dec(&phba->fabric_iocb_count); - if (!test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags)) { - /* Post any pending iocbs to HBA */ - lpfc_resume_fabric_iocbs(phba); - } -} - -/** - * lpfc_issue_fabric_iocb - Issue a fabric iocb command - * @phba: pointer to lpfc hba data structure. - * @iocb: pointer to lpfc command iocb data structure. - * - * This routine is used as the top-level API for issuing a fabric iocb command - * such as FLOGI and FDISC. To accommodate certain switch fabric, this driver - * function makes sure that only one fabric bound iocb will be outstanding at - * any given time. As such, this function will first check to see whether there - * is already an outstanding fabric iocb on the wire. If so, it will put the - * newly issued iocb onto the driver internal fabric iocb list, waiting to be - * issued later. Otherwise, it will issue the iocb on the wire and update the - * fabric iocb count it indicate that there is one fabric iocb on the wire. - * - * Note, this implementation has a potential sending out fabric IOCBs out of - * order. The problem is caused by the construction of the "ready" boolen does - * not include the condition that the internal fabric IOCB list is empty. As - * such, it is possible a fabric IOCB issued by this routine might be "jump" - * ahead of the fabric IOCBs in the internal list. - * - * Return code - * IOCB_SUCCESS - either fabric iocb put on the list or issued successfully - * IOCB_ERROR - failed to issue fabric iocb - **/ -static int -lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb) -{ - unsigned long iflags; - int ready; - int ret; - - if (atomic_read(&phba->fabric_iocb_count) > 1) - BUG(); - - spin_lock_irqsave(&phba->hbalock, iflags); - ready = atomic_read(&phba->fabric_iocb_count) == 0 && - !test_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); - - if (ready) - /* Increment fabric iocb count to hold the position */ - atomic_inc(&phba->fabric_iocb_count); - spin_unlock_irqrestore(&phba->hbalock, iflags); - if (ready) { - iocb->fabric_iocb_cmpl = iocb->iocb_cmpl; - iocb->iocb_cmpl = lpfc_cmpl_fabric_iocb; - iocb->iocb_flag |= LPFC_IO_FABRIC; - - lpfc_debugfs_disc_trc(iocb->vport, LPFC_DISC_TRC_ELS_CMD, - "Fabric sched2: ste:x%x", - iocb->vport->port_state, 0, 0); - - ret = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, iocb, 0); - - if (ret == IOCB_ERROR) { - iocb->iocb_cmpl = iocb->fabric_iocb_cmpl; - iocb->fabric_iocb_cmpl = NULL; - iocb->iocb_flag &= ~LPFC_IO_FABRIC; - atomic_dec(&phba->fabric_iocb_count); - } - } else { - spin_lock_irqsave(&phba->hbalock, iflags); - list_add_tail(&iocb->list, &phba->fabric_iocb_list); - spin_unlock_irqrestore(&phba->hbalock, iflags); - ret = IOCB_SUCCESS; - } - return ret; -} - -/** - * lpfc_fabric_abort_vport - Abort a vport's iocbs from driver fabric iocb list - * @vport: pointer to a virtual N_Port data structure. - * - * This routine aborts all the IOCBs associated with a @vport from the - * driver internal fabric IOCB list. The list contains fabric IOCBs to be - * issued to the ELS IOCB ring. This abort function walks the fabric IOCB - * list, removes each IOCB associated with the @vport off the list, set the - * status feild to IOSTAT_LOCAL_REJECT, and invokes the callback function - * associated with the IOCB. - **/ -static void lpfc_fabric_abort_vport(struct lpfc_vport *vport) -{ - LIST_HEAD(completions); - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *tmp_iocb, *piocb; - - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list, - list) { - - if (piocb->vport != vport) - continue; - - list_move_tail(&piocb->list, &completions); - } - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); -} - -/** - * lpfc_fabric_abort_nport - Abort a ndlp's iocbs from driver fabric iocb list - * @ndlp: pointer to a node-list data structure. - * - * This routine aborts all the IOCBs associated with an @ndlp from the - * driver internal fabric IOCB list. The list contains fabric IOCBs to be - * issued to the ELS IOCB ring. This abort function walks the fabric IOCB - * list, removes each IOCB associated with the @ndlp off the list, set the - * status feild to IOSTAT_LOCAL_REJECT, and invokes the callback function - * associated with the IOCB. - **/ -void lpfc_fabric_abort_nport(struct lpfc_nodelist *ndlp) -{ - LIST_HEAD(completions); - struct lpfc_hba *phba = ndlp->phba; - struct lpfc_iocbq *tmp_iocb, *piocb; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(piocb, tmp_iocb, &phba->fabric_iocb_list, - list) { - if ((lpfc_check_sli_ndlp(phba, pring, piocb, ndlp))) { - - list_move_tail(&piocb->list, &completions); - } - } - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); -} - -/** - * lpfc_fabric_abort_hba - Abort all iocbs on driver fabric iocb list - * @phba: pointer to lpfc hba data structure. - * - * This routine aborts all the IOCBs currently on the driver internal - * fabric IOCB list. The list contains fabric IOCBs to be issued to the ELS - * IOCB ring. This function takes the entire IOCB list off the fabric IOCB - * list, removes IOCBs off the list, set the status feild to - * IOSTAT_LOCAL_REJECT, and invokes the callback function associated with - * the IOCB. - **/ -void lpfc_fabric_abort_hba(struct lpfc_hba *phba) -{ - LIST_HEAD(completions); - - spin_lock_irq(&phba->hbalock); - list_splice_init(&phba->fabric_iocb_list, &completions); - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); -} - -/** - * lpfc_sli4_vport_delete_els_xri_aborted -Remove all ndlp references for vport - * @vport: pointer to lpfc vport data structure. - * - * This routine is invoked by the vport cleanup for deletions and the cleanup - * for an ndlp on removal. - **/ -void -lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; - unsigned long iflag = 0; - - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.abts_sgl_list_lock); - list_for_each_entry_safe(sglq_entry, sglq_next, - &phba->sli4_hba.lpfc_abts_els_sgl_list, list) { - if (sglq_entry->ndlp && sglq_entry->ndlp->vport == vport) - sglq_entry->ndlp = NULL; - } - spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - return; -} - -/** - * lpfc_sli4_els_xri_aborted - Slow-path process of els xri abort - * @phba: pointer to lpfc hba data structure. - * @axri: pointer to the els xri abort wcqe structure. - * - * This routine is invoked by the worker thread to process a SLI4 slow-path - * ELS aborted xri. - **/ -void -lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, - struct sli4_wcqe_xri_aborted *axri) -{ - uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); - uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); - uint16_t lxri = 0; - - struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; - unsigned long iflag = 0; - struct lpfc_nodelist *ndlp; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.abts_sgl_list_lock); - list_for_each_entry_safe(sglq_entry, sglq_next, - &phba->sli4_hba.lpfc_abts_els_sgl_list, list) { - if (sglq_entry->sli4_xritag == xri) { - list_del(&sglq_entry->list); - ndlp = sglq_entry->ndlp; - sglq_entry->ndlp = NULL; - list_add_tail(&sglq_entry->list, - &phba->sli4_hba.lpfc_sgl_list); - sglq_entry->state = SGL_FREED; - spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); - - /* Check if TXQ queue needs to be serviced */ - if (pring->txq_cnt) - lpfc_worker_wake_up(phba); - return; - } - } - spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); - lxri = lpfc_sli4_xri_inrange(phba, xri); - if (lxri == NO_XRI) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - return; - } - sglq_entry = __lpfc_get_active_sglq(phba, lxri); - if (!sglq_entry || (sglq_entry->sli4_xritag != xri)) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - return; - } - sglq_entry->state = SGL_XRI_ABORTED; - spin_unlock_irqrestore(&phba->hbalock, iflag); - return; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hbadisc.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hbadisc.c deleted file mode 100644 index b507536d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hbadisc.c +++ /dev/null @@ -1,6143 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_vport.h" -#include "lpfc_debugfs.h" - -/* AlpaArray for assignment of scsid for scan-down and bind_method */ -static uint8_t lpfcAlpaArray[] = { - 0xEF, 0xE8, 0xE4, 0xE2, 0xE1, 0xE0, 0xDC, 0xDA, 0xD9, 0xD6, - 0xD5, 0xD4, 0xD3, 0xD2, 0xD1, 0xCE, 0xCD, 0xCC, 0xCB, 0xCA, - 0xC9, 0xC7, 0xC6, 0xC5, 0xC3, 0xBC, 0xBA, 0xB9, 0xB6, 0xB5, - 0xB4, 0xB3, 0xB2, 0xB1, 0xAE, 0xAD, 0xAC, 0xAB, 0xAA, 0xA9, - 0xA7, 0xA6, 0xA5, 0xA3, 0x9F, 0x9E, 0x9D, 0x9B, 0x98, 0x97, - 0x90, 0x8F, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7C, 0x7A, 0x79, - 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x6E, 0x6D, 0x6C, 0x6B, - 0x6A, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5C, 0x5A, 0x59, 0x56, - 0x55, 0x54, 0x53, 0x52, 0x51, 0x4E, 0x4D, 0x4C, 0x4B, 0x4A, - 0x49, 0x47, 0x46, 0x45, 0x43, 0x3C, 0x3A, 0x39, 0x36, 0x35, - 0x34, 0x33, 0x32, 0x31, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A, 0x29, - 0x27, 0x26, 0x25, 0x23, 0x1F, 0x1E, 0x1D, 0x1B, 0x18, 0x17, - 0x10, 0x0F, 0x08, 0x04, 0x02, 0x01 -}; - -static void lpfc_disc_timeout_handler(struct lpfc_vport *); -static void lpfc_disc_flush_list(struct lpfc_vport *vport); -static void lpfc_unregister_fcfi_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *); -static int lpfc_fcf_inuse(struct lpfc_hba *); - -void -lpfc_terminate_rport_io(struct fc_rport *rport) -{ - struct lpfc_rport_data *rdata; - struct lpfc_nodelist * ndlp; - struct lpfc_hba *phba; - - rdata = rport->dd_data; - ndlp = rdata->pnode; - - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) - printk(KERN_ERR "Cannot find remote node" - " to terminate I/O Data x%x\n", - rport->port_id); - return; - } - - phba = ndlp->phba; - - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT, - "rport terminate: sid:x%x did:x%x flg:x%x", - ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); - - if (ndlp->nlp_sid != NLP_NO_SID) { - lpfc_sli_abort_iocb(ndlp->vport, - &phba->sli.ring[phba->sli.fcp_ring], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); - } -} - -/* - * This function will be called when dev_loss_tmo fire. - */ -void -lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) -{ - struct lpfc_rport_data *rdata; - struct lpfc_nodelist * ndlp; - struct lpfc_vport *vport; - struct lpfc_hba *phba; - struct lpfc_work_evt *evtp; - int put_node; - int put_rport; - - rdata = rport->dd_data; - ndlp = rdata->pnode; - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - return; - - vport = ndlp->vport; - phba = vport->phba; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport devlosscb: sid:x%x did:x%x flg:x%x", - ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); - - /* Don't defer this if we are in the process of deleting the vport - * or unloading the driver. The unload will cleanup the node - * appropriately we just need to cleanup the ndlp rport info here. - */ - if (vport->load_flag & FC_UNLOADING) { - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); - return; - } - - if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) - return; - - evtp = &ndlp->dev_loss_evt; - - if (!list_empty(&evtp->evt_listp)) - return; - - spin_lock_irq(&phba->hbalock); - /* We need to hold the node by incrementing the reference - * count until this queued work is done - */ - evtp->evt_arg1 = lpfc_nlp_get(ndlp); - if (evtp->evt_arg1) { - evtp->evt = LPFC_EVT_DEV_LOSS; - list_add_tail(&evtp->evt_listp, &phba->work_list); - lpfc_worker_wake_up(phba); - } - spin_unlock_irq(&phba->hbalock); - - return; -} - -/** - * lpfc_dev_loss_tmo_handler - Remote node devloss timeout handler - * @ndlp: Pointer to remote node object. - * - * This function is called from the worker thread when devloss timeout timer - * expires. For SLI4 host, this routine shall return 1 when at lease one - * remote node, including this @ndlp, is still in use of FCF; otherwise, this - * routine shall return 0 when there is no remote node is still in use of FCF - * when devloss timeout happened to this @ndlp. - **/ -static int -lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) -{ - struct lpfc_rport_data *rdata; - struct fc_rport *rport; - struct lpfc_vport *vport; - struct lpfc_hba *phba; - uint8_t *name; - int put_node; - int put_rport; - int warn_on = 0; - int fcf_inuse = 0; - - rport = ndlp->rport; - - if (!rport) - return fcf_inuse; - - rdata = rport->dd_data; - name = (uint8_t *) &ndlp->nlp_portname; - vport = ndlp->vport; - phba = vport->phba; - - if (phba->sli_rev == LPFC_SLI_REV4) - fcf_inuse = lpfc_fcf_inuse(phba); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport devlosstmo:did:x%x type:x%x id:x%x", - ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); - - /* Don't defer this if we are in the process of deleting the vport - * or unloading the driver. The unload will cleanup the node - * appropriately we just need to cleanup the ndlp rport info here. - */ - if (vport->load_flag & FC_UNLOADING) { - if (ndlp->nlp_sid != NLP_NO_SID) { - /* flush the target */ - lpfc_sli_abort_iocb(vport, - &phba->sli.ring[phba->sli.fcp_ring], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); - } - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); - return fcf_inuse; - } - - if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0284 Devloss timeout Ignored on " - "WWPN %x:%x:%x:%x:%x:%x:%x:%x " - "NPort x%x\n", - *name, *(name+1), *(name+2), *(name+3), - *(name+4), *(name+5), *(name+6), *(name+7), - ndlp->nlp_DID); - return fcf_inuse; - } - - if (ndlp->nlp_type & NLP_FABRIC) { - /* We will clean up these Nodes in linkup */ - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); - return fcf_inuse; - } - - if (ndlp->nlp_sid != NLP_NO_SID) { - warn_on = 1; - /* flush the target */ - lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); - } - - if (warn_on) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0203 Devloss timeout on " - "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " - "NPort x%06x Data: x%x x%x x%x\n", - *name, *(name+1), *(name+2), *(name+3), - *(name+4), *(name+5), *(name+6), *(name+7), - ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_state, ndlp->nlp_rpi); - } else { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0204 Devloss timeout on " - "WWPN %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x " - "NPort x%06x Data: x%x x%x x%x\n", - *name, *(name+1), *(name+2), *(name+3), - *(name+4), *(name+5), *(name+6), *(name+7), - ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_state, ndlp->nlp_rpi); - } - - put_node = rdata->pnode != NULL; - put_rport = ndlp->rport != NULL; - rdata->pnode = NULL; - ndlp->rport = NULL; - if (put_node) - lpfc_nlp_put(ndlp); - if (put_rport) - put_device(&rport->dev); - - if (!(vport->load_flag & FC_UNLOADING) && - !(ndlp->nlp_flag & NLP_DELAY_TMO) && - !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE) && - (ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) && - (ndlp->nlp_state != NLP_STE_PRLI_ISSUE)) - lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); - - return fcf_inuse; -} - -/** - * lpfc_sli4_post_dev_loss_tmo_handler - SLI4 post devloss timeout handler - * @phba: Pointer to hba context object. - * @fcf_inuse: SLI4 FCF in-use state reported from devloss timeout handler. - * @nlp_did: remote node identifer with devloss timeout. - * - * This function is called from the worker thread after invoking devloss - * timeout handler and releasing the reference count for the ndlp with - * which the devloss timeout was handled for SLI4 host. For the devloss - * timeout of the last remote node which had been in use of FCF, when this - * routine is invoked, it shall be guaranteed that none of the remote are - * in-use of FCF. When devloss timeout to the last remote using the FCF, - * if the FIP engine is neither in FCF table scan process nor roundrobin - * failover process, the in-use FCF shall be unregistered. If the FIP - * engine is in FCF discovery process, the devloss timeout state shall - * be set for either the FCF table scan process or roundrobin failover - * process to unregister the in-use FCF. - **/ -static void -lpfc_sli4_post_dev_loss_tmo_handler(struct lpfc_hba *phba, int fcf_inuse, - uint32_t nlp_did) -{ - /* If devloss timeout happened to a remote node when FCF had no - * longer been in-use, do nothing. - */ - if (!fcf_inuse) - return; - - if ((phba->hba_flag & HBA_FIP_SUPPORT) && !lpfc_fcf_inuse(phba)) { - spin_lock_irq(&phba->hbalock); - if (phba->fcf.fcf_flag & FCF_DISCOVERY) { - if (phba->hba_flag & HBA_DEVLOSS_TMO) { - spin_unlock_irq(&phba->hbalock); - return; - } - phba->hba_flag |= HBA_DEVLOSS_TMO; - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2847 Last remote node (x%x) using " - "FCF devloss tmo\n", nlp_did); - } - if (phba->fcf.fcf_flag & FCF_REDISC_PROG) { - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2868 Devloss tmo to FCF rediscovery " - "in progress\n"); - return; - } - if (!(phba->hba_flag & (FCF_TS_INPROG | FCF_RR_INPROG))) { - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2869 Devloss tmo to idle FIP engine, " - "unreg in-use FCF and rescan.\n"); - /* Unregister in-use FCF and rescan */ - lpfc_unregister_fcf_rescan(phba); - return; - } - spin_unlock_irq(&phba->hbalock); - if (phba->hba_flag & FCF_TS_INPROG) - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2870 FCF table scan in progress\n"); - if (phba->hba_flag & FCF_RR_INPROG) - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2871 FLOGI roundrobin FCF failover " - "in progress\n"); - } - lpfc_unregister_unused_fcf(phba); -} - -/** - * lpfc_alloc_fast_evt - Allocates data structure for posting event - * @phba: Pointer to hba context object. - * - * This function is called from the functions which need to post - * events from interrupt context. This function allocates data - * structure required for posting event. It also keeps track of - * number of events pending and prevent event storm when there are - * too many events. - **/ -struct lpfc_fast_path_event * -lpfc_alloc_fast_evt(struct lpfc_hba *phba) { - struct lpfc_fast_path_event *ret; - - /* If there are lot of fast event do not exhaust memory due to this */ - if (atomic_read(&phba->fast_event_count) > LPFC_MAX_EVT_COUNT) - return NULL; - - ret = kzalloc(sizeof(struct lpfc_fast_path_event), - GFP_ATOMIC); - if (ret) { - atomic_inc(&phba->fast_event_count); - INIT_LIST_HEAD(&ret->work_evt.evt_listp); - ret->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT; - } - return ret; -} - -/** - * lpfc_free_fast_evt - Frees event data structure - * @phba: Pointer to hba context object. - * @evt: Event object which need to be freed. - * - * This function frees the data structure required for posting - * events. - **/ -void -lpfc_free_fast_evt(struct lpfc_hba *phba, - struct lpfc_fast_path_event *evt) { - - atomic_dec(&phba->fast_event_count); - kfree(evt); -} - -/** - * lpfc_send_fastpath_evt - Posts events generated from fast path - * @phba: Pointer to hba context object. - * @evtp: Event data structure. - * - * This function is called from worker thread, when the interrupt - * context need to post an event. This function posts the event - * to fc transport netlink interface. - **/ -static void -lpfc_send_fastpath_evt(struct lpfc_hba *phba, - struct lpfc_work_evt *evtp) -{ - unsigned long evt_category, evt_sub_category; - struct lpfc_fast_path_event *fast_evt_data; - char *evt_data; - uint32_t evt_data_size; - struct Scsi_Host *shost; - - fast_evt_data = container_of(evtp, struct lpfc_fast_path_event, - work_evt); - - evt_category = (unsigned long) fast_evt_data->un.fabric_evt.event_type; - evt_sub_category = (unsigned long) fast_evt_data->un. - fabric_evt.subcategory; - shost = lpfc_shost_from_vport(fast_evt_data->vport); - if (evt_category == FC_REG_FABRIC_EVENT) { - if (evt_sub_category == LPFC_EVENT_FCPRDCHKERR) { - evt_data = (char *) &fast_evt_data->un.read_check_error; - evt_data_size = sizeof(fast_evt_data->un. - read_check_error); - } else if ((evt_sub_category == LPFC_EVENT_FABRIC_BUSY) || - (evt_sub_category == LPFC_EVENT_PORT_BUSY)) { - evt_data = (char *) &fast_evt_data->un.fabric_evt; - evt_data_size = sizeof(fast_evt_data->un.fabric_evt); - } else { - lpfc_free_fast_evt(phba, fast_evt_data); - return; - } - } else if (evt_category == FC_REG_SCSI_EVENT) { - switch (evt_sub_category) { - case LPFC_EVENT_QFULL: - case LPFC_EVENT_DEVBSY: - evt_data = (char *) &fast_evt_data->un.scsi_evt; - evt_data_size = sizeof(fast_evt_data->un.scsi_evt); - break; - case LPFC_EVENT_CHECK_COND: - evt_data = (char *) &fast_evt_data->un.check_cond_evt; - evt_data_size = sizeof(fast_evt_data->un. - check_cond_evt); - break; - case LPFC_EVENT_VARQUEDEPTH: - evt_data = (char *) &fast_evt_data->un.queue_depth_evt; - evt_data_size = sizeof(fast_evt_data->un. - queue_depth_evt); - break; - default: - lpfc_free_fast_evt(phba, fast_evt_data); - return; - } - } else { - lpfc_free_fast_evt(phba, fast_evt_data); - return; - } - - fc_host_post_vendor_event(shost, - fc_get_event_number(), - evt_data_size, - evt_data, - LPFC_NL_VENDOR_ID); - - lpfc_free_fast_evt(phba, fast_evt_data); - return; -} - -static void -lpfc_work_list_done(struct lpfc_hba *phba) -{ - struct lpfc_work_evt *evtp = NULL; - struct lpfc_nodelist *ndlp; - int free_evt; - int fcf_inuse; - uint32_t nlp_did; - - spin_lock_irq(&phba->hbalock); - while (!list_empty(&phba->work_list)) { - list_remove_head((&phba->work_list), evtp, typeof(*evtp), - evt_listp); - spin_unlock_irq(&phba->hbalock); - free_evt = 1; - switch (evtp->evt) { - case LPFC_EVT_ELS_RETRY: - ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); - lpfc_els_retry_delay_handler(ndlp); - free_evt = 0; /* evt is part of ndlp */ - /* decrement the node reference count held - * for this queued work - */ - lpfc_nlp_put(ndlp); - break; - case LPFC_EVT_DEV_LOSS: - ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); - fcf_inuse = lpfc_dev_loss_tmo_handler(ndlp); - free_evt = 0; - /* decrement the node reference count held for - * this queued work - */ - nlp_did = ndlp->nlp_DID; - lpfc_nlp_put(ndlp); - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_post_dev_loss_tmo_handler(phba, - fcf_inuse, - nlp_did); - break; - case LPFC_EVT_ONLINE: - if (phba->link_state < LPFC_LINK_DOWN) - *(int *) (evtp->evt_arg1) = lpfc_online(phba); - else - *(int *) (evtp->evt_arg1) = 0; - complete((struct completion *)(evtp->evt_arg2)); - break; - case LPFC_EVT_OFFLINE_PREP: - if (phba->link_state >= LPFC_LINK_DOWN) - lpfc_offline_prep(phba); - *(int *)(evtp->evt_arg1) = 0; - complete((struct completion *)(evtp->evt_arg2)); - break; - case LPFC_EVT_OFFLINE: - lpfc_offline(phba); - lpfc_sli_brdrestart(phba); - *(int *)(evtp->evt_arg1) = - lpfc_sli_brdready(phba, HS_FFRDY | HS_MBRDY); - lpfc_unblock_mgmt_io(phba); - complete((struct completion *)(evtp->evt_arg2)); - break; - case LPFC_EVT_WARM_START: - lpfc_offline(phba); - lpfc_reset_barrier(phba); - lpfc_sli_brdreset(phba); - lpfc_hba_down_post(phba); - *(int *)(evtp->evt_arg1) = - lpfc_sli_brdready(phba, HS_MBRDY); - lpfc_unblock_mgmt_io(phba); - complete((struct completion *)(evtp->evt_arg2)); - break; - case LPFC_EVT_KILL: - lpfc_offline(phba); - *(int *)(evtp->evt_arg1) - = (phba->pport->stopped) - ? 0 : lpfc_sli_brdkill(phba); - lpfc_unblock_mgmt_io(phba); - complete((struct completion *)(evtp->evt_arg2)); - break; - case LPFC_EVT_FASTPATH_MGMT_EVT: - lpfc_send_fastpath_evt(phba, evtp); - free_evt = 0; - break; - case LPFC_EVT_RESET_HBA: - if (!(phba->pport->load_flag & FC_UNLOADING)) - lpfc_reset_hba(phba); - break; - } - if (free_evt) - kfree(evtp); - spin_lock_irq(&phba->hbalock); - } - spin_unlock_irq(&phba->hbalock); - -} - -static void -lpfc_work_done(struct lpfc_hba *phba) -{ - struct lpfc_sli_ring *pring; - uint32_t ha_copy, status, control, work_port_events; - struct lpfc_vport **vports; - struct lpfc_vport *vport; - int i; - - spin_lock_irq(&phba->hbalock); - ha_copy = phba->work_ha; - phba->work_ha = 0; - spin_unlock_irq(&phba->hbalock); - - /* First, try to post the next mailbox command to SLI4 device */ - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) - lpfc_sli4_post_async_mbox(phba); - - if (ha_copy & HA_ERATT) - /* Handle the error attention event */ - lpfc_handle_eratt(phba); - - if (ha_copy & HA_MBATT) - lpfc_sli_handle_mb_event(phba); - - if (ha_copy & HA_LATT) - lpfc_handle_latt(phba); - - /* Process SLI4 events */ - if (phba->pci_dev_grp == LPFC_PCI_DEV_OC) { - if (phba->hba_flag & HBA_RRQ_ACTIVE) - lpfc_handle_rrq_active(phba); - if (phba->hba_flag & FCP_XRI_ABORT_EVENT) - lpfc_sli4_fcp_xri_abort_event_proc(phba); - if (phba->hba_flag & ELS_XRI_ABORT_EVENT) - lpfc_sli4_els_xri_abort_event_proc(phba); - if (phba->hba_flag & ASYNC_EVENT) - lpfc_sli4_async_event_proc(phba); - if (phba->hba_flag & HBA_POST_RECEIVE_BUFFER) { - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~HBA_POST_RECEIVE_BUFFER; - spin_unlock_irq(&phba->hbalock); - lpfc_sli_hbqbuf_add_hbqs(phba, LPFC_ELS_HBQ); - } - if (phba->fcf.fcf_flag & FCF_REDISC_EVT) - lpfc_sli4_fcf_redisc_event_proc(phba); - } - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports; i++) { - /* - * We could have no vports in array if unloading, so if - * this happens then just use the pport - */ - if (vports[i] == NULL && i == 0) - vport = phba->pport; - else - vport = vports[i]; - if (vport == NULL) - break; - spin_lock_irq(&vport->work_port_lock); - work_port_events = vport->work_port_events; - vport->work_port_events &= ~work_port_events; - spin_unlock_irq(&vport->work_port_lock); - if (work_port_events & WORKER_DISC_TMO) - lpfc_disc_timeout_handler(vport); - if (work_port_events & WORKER_ELS_TMO) - lpfc_els_timeout_handler(vport); - if (work_port_events & WORKER_HB_TMO) - lpfc_hb_timeout_handler(phba); - if (work_port_events & WORKER_MBOX_TMO) - lpfc_mbox_timeout_handler(phba); - if (work_port_events & WORKER_FABRIC_BLOCK_TMO) - lpfc_unblock_fabric_iocbs(phba); - if (work_port_events & WORKER_FDMI_TMO) - lpfc_fdmi_timeout_handler(vport); - if (work_port_events & WORKER_RAMP_DOWN_QUEUE) - lpfc_ramp_down_queue_handler(phba); - if (work_port_events & WORKER_RAMP_UP_QUEUE) - lpfc_ramp_up_queue_handler(phba); - if (work_port_events & WORKER_DELAYED_DISC_TMO) - lpfc_delayed_disc_timeout_handler(vport); - } - lpfc_destroy_vport_work_array(phba, vports); - - pring = &phba->sli.ring[LPFC_ELS_RING]; - status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); - status >>= (4*LPFC_ELS_RING); - if ((status & HA_RXMASK) || - (pring->flag & LPFC_DEFERRED_RING_EVENT) || - (phba->hba_flag & HBA_SP_QUEUE_EVT)) { - if (pring->flag & LPFC_STOP_IOCB_EVENT) { - pring->flag |= LPFC_DEFERRED_RING_EVENT; - /* Set the lpfc data pending flag */ - set_bit(LPFC_DATA_READY, &phba->data_flags); - } else { - pring->flag &= ~LPFC_DEFERRED_RING_EVENT; - lpfc_sli_handle_slow_ring_event(phba, pring, - (status & - HA_RXMASK)); - } - if ((phba->sli_rev == LPFC_SLI_REV4) && pring->txq_cnt) - lpfc_drain_txq(phba); - /* - * Turn on Ring interrupts - */ - if (phba->sli_rev <= LPFC_SLI_REV3) { - spin_lock_irq(&phba->hbalock); - control = readl(phba->HCregaddr); - if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) { - lpfc_debugfs_slow_ring_trc(phba, - "WRK Enable ring: cntl:x%x hacopy:x%x", - control, ha_copy, 0); - - control |= (HC_R0INT_ENA << LPFC_ELS_RING); - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } else { - lpfc_debugfs_slow_ring_trc(phba, - "WRK Ring ok: cntl:x%x hacopy:x%x", - control, ha_copy, 0); - } - spin_unlock_irq(&phba->hbalock); - } - } - lpfc_work_list_done(phba); -} - -int -lpfc_do_work(void *p) -{ - struct lpfc_hba *phba = p; - int rc; - - set_user_nice(current, -20); - phba->data_flags = 0; - - while (!kthread_should_stop()) { - /* wait and check worker queue activities */ - rc = wait_event_interruptible(phba->work_waitq, - (test_and_clear_bit(LPFC_DATA_READY, - &phba->data_flags) - || kthread_should_stop())); - /* Signal wakeup shall terminate the worker thread */ - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "0433 Wakeup on signal: rc=x%x\n", rc); - break; - } - - /* Attend pending lpfc data processing */ - lpfc_work_done(phba); - } - phba->worker_thread = NULL; - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "0432 Worker thread stopped.\n"); - return 0; -} - -/* - * This is only called to handle FC worker events. Since this a rare - * occurrence, we allocate a struct lpfc_work_evt structure here instead of - * embedding it in the IOCB. - */ -int -lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, - uint32_t evt) -{ - struct lpfc_work_evt *evtp; - unsigned long flags; - - /* - * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will - * be queued to worker thread for processing - */ - evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_ATOMIC); - if (!evtp) - return 0; - - evtp->evt_arg1 = arg1; - evtp->evt_arg2 = arg2; - evtp->evt = evt; - - spin_lock_irqsave(&phba->hbalock, flags); - list_add_tail(&evtp->evt_listp, &phba->work_list); - spin_unlock_irqrestore(&phba->hbalock, flags); - - lpfc_worker_wake_up(phba); - - return 1; -} - -void -lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_nodelist *ndlp, *next_ndlp; - int rc; - - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - continue; - if ((phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) || - ((vport->port_type == LPFC_NPIV_PORT) && - (ndlp->nlp_DID == NameServer_DID))) - lpfc_unreg_rpi(vport, ndlp); - - /* Leave Fabric nodes alone on link down */ - if ((phba->sli_rev < LPFC_SLI_REV4) && - (!remove && ndlp->nlp_type & NLP_FABRIC)) - continue; - rc = lpfc_disc_state_machine(vport, ndlp, NULL, - remove - ? NLP_EVT_DEVICE_RM - : NLP_EVT_DEVICE_RECOVERY); - } - if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) { - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_unreg_all_rpis(vport); - lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - } -} - -void -lpfc_port_link_failure(struct lpfc_vport *vport) -{ - lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); - - /* Cleanup any outstanding received buffers */ - lpfc_cleanup_rcv_buffers(vport); - - /* Cleanup any outstanding RSCN activity */ - lpfc_els_flush_rscn(vport); - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_cmd(vport); - - lpfc_cleanup_rpis(vport, 0); - - /* Turn off discovery timer if its running */ - lpfc_can_disctmo(vport); -} - -void -lpfc_linkdown_port(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Link Down: state:x%x rtry:x%x flg:x%x", - vport->port_state, vport->fc_ns_retry, vport->fc_flag); - - lpfc_port_link_failure(vport); - - /* Stop delayed Nport discovery */ - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_DISC_DELAYED; - spin_unlock_irq(shost->host_lock); - del_timer_sync(&vport->delayed_disc_tmo); -} - -int -lpfc_linkdown(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport = phba->pport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_vport **vports; - LPFC_MBOXQ_t *mb; - int i; - - if (phba->link_state == LPFC_LINK_DOWN) - return 0; - - /* Block all SCSI stack I/Os */ - lpfc_scsi_dev_block(phba); - - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE); - spin_unlock_irq(&phba->hbalock); - if (phba->link_state > LPFC_LINK_DOWN) { - phba->link_state = LPFC_LINK_DOWN; - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~FC_LBIT; - spin_unlock_irq(shost->host_lock); - } - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - /* Issue a LINK DOWN event to all nodes */ - lpfc_linkdown_port(vports[i]); - } - lpfc_destroy_vport_work_array(phba, vports); - /* Clean up any firmware default rpi's */ - mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mb) { - lpfc_unreg_did(phba, 0xffff, LPFC_UNREG_ALL_DFLT_RPIS, mb); - mb->vport = vport; - mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT) - == MBX_NOT_FINISHED) { - mempool_free(mb, phba->mbox_mem_pool); - } - } - - /* Setup myDID for link up if we are in pt2pt mode */ - if (phba->pport->fc_flag & FC_PT2PT) { - phba->pport->fc_myDID = 0; - mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mb) { - lpfc_config_link(phba, mb); - mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mb->vport = vport; - if (lpfc_sli_issue_mbox(phba, mb, MBX_NOWAIT) - == MBX_NOT_FINISHED) { - mempool_free(mb, phba->mbox_mem_pool); - } - } - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); - spin_unlock_irq(shost->host_lock); - } - - return 0; -} - -static void -lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp; - - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - continue; - if (ndlp->nlp_type & NLP_FABRIC) { - /* On Linkup its safe to clean up the ndlp - * from Fabric connections. - */ - if (ndlp->nlp_DID != Fabric_DID) - lpfc_unreg_rpi(vport, ndlp); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { - /* Fail outstanding IO now since device is - * marked for PLOGI. - */ - lpfc_unreg_rpi(vport, ndlp); - } - } -} - -static void -lpfc_linkup_port(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - - if ((vport->load_flag & FC_UNLOADING) != 0) - return; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "Link Up: top:x%x speed:x%x flg:x%x", - phba->fc_topology, phba->fc_linkspeed, phba->link_flag); - - /* If NPIV is not enabled, only bring the physical port up */ - if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - (vport != phba->pport)) - return; - - fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKUP, 0); - - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY | - FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY); - vport->fc_flag |= FC_NDISC_ACTIVE; - vport->fc_ns_retry = 0; - spin_unlock_irq(shost->host_lock); - - if (vport->fc_flag & FC_LBIT) - lpfc_linkup_cleanup_nodes(vport); - -} - -static int -lpfc_linkup(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - int i; - - lpfc_cleanup_wt_rrqs(phba); - phba->link_state = LPFC_LINK_UP; - - /* Unblock fabric iocbs if they are blocked */ - clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); - del_timer_sync(&phba->fabric_block_timer); - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) - lpfc_linkup_port(vports[i]); - lpfc_destroy_vport_work_array(phba, vports); - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - (phba->sli_rev < LPFC_SLI_REV4)) - lpfc_issue_clear_la(phba, phba->pport); - - return 0; -} - -/* - * This routine handles processing a CLEAR_LA mailbox - * command upon completion. It is setup in the LPFC_MBOXQ - * as the completion routine when the command is - * handed off to the SLI layer. - */ -static void -lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_sli *psli = &phba->sli; - MAILBOX_t *mb = &pmb->u.mb; - uint32_t control; - - /* Since we don't do discovery right now, turn these off here */ - psli->ring[psli->extra_ring].flag &= ~LPFC_STOP_IOCB_EVENT; - psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT; - psli->ring[psli->next_ring].flag &= ~LPFC_STOP_IOCB_EVENT; - - /* Check for error */ - if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) { - /* CLEAR_LA mbox error state */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0320 CLEAR_LA mbxStatus error x%x hba " - "state x%x\n", - mb->mbxStatus, vport->port_state); - phba->link_state = LPFC_HBA_ERROR; - goto out; - } - - if (vport->port_type == LPFC_PHYSICAL_PORT) - phba->link_state = LPFC_HBA_READY; - - spin_lock_irq(&phba->hbalock); - psli->sli_flag |= LPFC_PROCESS_LA; - control = readl(phba->HCregaddr); - control |= HC_LAINT_ENA; - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - spin_unlock_irq(&phba->hbalock); - mempool_free(pmb, phba->mbox_mem_pool); - return; - -out: - /* Device Discovery completes */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0225 Device Discovery completes\n"); - mempool_free(pmb, phba->mbox_mem_pool); - - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_ABORT_DISCOVERY; - spin_unlock_irq(shost->host_lock); - - lpfc_can_disctmo(vport); - - /* turn on Link Attention interrupts */ - - spin_lock_irq(&phba->hbalock); - psli->sli_flag |= LPFC_PROCESS_LA; - control = readl(phba->HCregaddr); - control |= HC_LAINT_ENA; - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - spin_unlock_irq(&phba->hbalock); - - return; -} - - -static void -lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - - if (pmb->u.mb.mbxStatus) - goto out; - - mempool_free(pmb, phba->mbox_mem_pool); - - /* don't perform discovery for SLI4 loopback diagnostic test */ - if ((phba->sli_rev == LPFC_SLI_REV4) && - !(phba->hba_flag & HBA_FCOE_MODE) && - (phba->link_flag & LS_LOOPBACK_MODE)) - return; - - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP && - vport->fc_flag & FC_PUBLIC_LOOP && - !(vport->fc_flag & FC_LBIT)) { - /* Need to wait for FAN - use discovery timer - * for timeout. port_state is identically - * LPFC_LOCAL_CFG_LINK while waiting for FAN - */ - lpfc_set_disctmo(vport); - return; - } - - /* Start discovery by sending a FLOGI. port_state is identically - * LPFC_FLOGI while waiting for FLOGI cmpl - */ - if (vport->port_state != LPFC_FLOGI) - lpfc_initial_flogi(vport); - return; - -out: - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0306 CONFIG_LINK mbxStatus error x%x " - "HBA state x%x\n", - pmb->u.mb.mbxStatus, vport->port_state); - mempool_free(pmb, phba->mbox_mem_pool); - - lpfc_linkdown(phba); - - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0200 CONFIG_LINK bad hba state x%x\n", - vport->port_state); - - lpfc_issue_clear_la(phba, vport); - return; -} - -/** - * lpfc_sli4_clear_fcf_rr_bmask - * @phba pointer to the struct lpfc_hba for this port. - * This fucnction resets the round robin bit mask and clears the - * fcf priority list. The list deletions are done while holding the - * hbalock. The ON_LIST flag and the FLOGI_FAILED flags are cleared - * from the lpfc_fcf_pri record. - **/ -void -lpfc_sli4_clear_fcf_rr_bmask(struct lpfc_hba *phba) -{ - struct lpfc_fcf_pri *fcf_pri; - struct lpfc_fcf_pri *next_fcf_pri; - memset(phba->fcf.fcf_rr_bmask, 0, sizeof(*phba->fcf.fcf_rr_bmask)); - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(fcf_pri, next_fcf_pri, - &phba->fcf.fcf_pri_list, list) { - list_del_init(&fcf_pri->list); - fcf_pri->fcf_rec.flag = 0; - } - spin_unlock_irq(&phba->hbalock); -} -static void -lpfc_mbx_cmpl_reg_fcfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct lpfc_vport *vport = mboxq->vport; - - if (mboxq->u.mb.mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2017 REG_FCFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); - goto fail_out; - } - - /* Start FCoE discovery by sending a FLOGI. */ - phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, &mboxq->u.mqe.un.reg_fcfi); - /* Set the FCFI registered flag */ - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag |= FCF_REGISTERED; - spin_unlock_irq(&phba->hbalock); - - /* If there is a pending FCoE event, restart FCF table scan. */ - if ((!(phba->hba_flag & FCF_RR_INPROG)) && - lpfc_check_pending_fcoe_event(phba, LPFC_UNREG_FCF)) - goto fail_out; - - /* Mark successful completion of FCF table scan */ - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE); - phba->hba_flag &= ~FCF_TS_INPROG; - if (vport->port_state != LPFC_FLOGI) { - phba->hba_flag |= FCF_RR_INPROG; - spin_unlock_irq(&phba->hbalock); - lpfc_issue_init_vfi(vport); - goto out; - } - spin_unlock_irq(&phba->hbalock); - goto out; - -fail_out: - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~FCF_RR_INPROG; - spin_unlock_irq(&phba->hbalock); -out: - mempool_free(mboxq, phba->mbox_mem_pool); -} - -/** - * lpfc_fab_name_match - Check if the fcf fabric name match. - * @fab_name: pointer to fabric name. - * @new_fcf_record: pointer to fcf record. - * - * This routine compare the fcf record's fabric name with provided - * fabric name. If the fabric name are identical this function - * returns 1 else return 0. - **/ -static uint32_t -lpfc_fab_name_match(uint8_t *fab_name, struct fcf_record *new_fcf_record) -{ - if (fab_name[0] != bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record)) - return 0; - if (fab_name[1] != bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record)) - return 0; - if (fab_name[2] != bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record)) - return 0; - if (fab_name[3] != bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record)) - return 0; - if (fab_name[4] != bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record)) - return 0; - if (fab_name[5] != bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record)) - return 0; - if (fab_name[6] != bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record)) - return 0; - if (fab_name[7] != bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record)) - return 0; - return 1; -} - -/** - * lpfc_sw_name_match - Check if the fcf switch name match. - * @fab_name: pointer to fabric name. - * @new_fcf_record: pointer to fcf record. - * - * This routine compare the fcf record's switch name with provided - * switch name. If the switch name are identical this function - * returns 1 else return 0. - **/ -static uint32_t -lpfc_sw_name_match(uint8_t *sw_name, struct fcf_record *new_fcf_record) -{ - if (sw_name[0] != bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record)) - return 0; - if (sw_name[1] != bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record)) - return 0; - if (sw_name[2] != bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record)) - return 0; - if (sw_name[3] != bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record)) - return 0; - if (sw_name[4] != bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record)) - return 0; - if (sw_name[5] != bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record)) - return 0; - if (sw_name[6] != bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record)) - return 0; - if (sw_name[7] != bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record)) - return 0; - return 1; -} - -/** - * lpfc_mac_addr_match - Check if the fcf mac address match. - * @mac_addr: pointer to mac address. - * @new_fcf_record: pointer to fcf record. - * - * This routine compare the fcf record's mac address with HBA's - * FCF mac address. If the mac addresses are identical this function - * returns 1 else return 0. - **/ -static uint32_t -lpfc_mac_addr_match(uint8_t *mac_addr, struct fcf_record *new_fcf_record) -{ - if (mac_addr[0] != bf_get(lpfc_fcf_record_mac_0, new_fcf_record)) - return 0; - if (mac_addr[1] != bf_get(lpfc_fcf_record_mac_1, new_fcf_record)) - return 0; - if (mac_addr[2] != bf_get(lpfc_fcf_record_mac_2, new_fcf_record)) - return 0; - if (mac_addr[3] != bf_get(lpfc_fcf_record_mac_3, new_fcf_record)) - return 0; - if (mac_addr[4] != bf_get(lpfc_fcf_record_mac_4, new_fcf_record)) - return 0; - if (mac_addr[5] != bf_get(lpfc_fcf_record_mac_5, new_fcf_record)) - return 0; - return 1; -} - -static bool -lpfc_vlan_id_match(uint16_t curr_vlan_id, uint16_t new_vlan_id) -{ - return (curr_vlan_id == new_vlan_id); -} - -/** - * lpfc_update_fcf_record - Update driver fcf record - * __lpfc_update_fcf_record_pri - update the lpfc_fcf_pri record. - * @phba: pointer to lpfc hba data structure. - * @fcf_index: Index for the lpfc_fcf_record. - * @new_fcf_record: pointer to hba fcf record. - * - * This routine updates the driver FCF priority record from the new HBA FCF - * record. This routine is called with the host lock held. - **/ -static void -__lpfc_update_fcf_record_pri(struct lpfc_hba *phba, uint16_t fcf_index, - struct fcf_record *new_fcf_record - ) -{ - struct lpfc_fcf_pri *fcf_pri; - - fcf_pri = &phba->fcf.fcf_pri[fcf_index]; - fcf_pri->fcf_rec.fcf_index = fcf_index; - /* FCF record priority */ - fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority; - -} - -/** - * lpfc_copy_fcf_record - Copy fcf information to lpfc_hba. - * @fcf: pointer to driver fcf record. - * @new_fcf_record: pointer to fcf record. - * - * This routine copies the FCF information from the FCF - * record to lpfc_hba data structure. - **/ -static void -lpfc_copy_fcf_record(struct lpfc_fcf_rec *fcf_rec, - struct fcf_record *new_fcf_record) -{ - /* Fabric name */ - fcf_rec->fabric_name[0] = - bf_get(lpfc_fcf_record_fab_name_0, new_fcf_record); - fcf_rec->fabric_name[1] = - bf_get(lpfc_fcf_record_fab_name_1, new_fcf_record); - fcf_rec->fabric_name[2] = - bf_get(lpfc_fcf_record_fab_name_2, new_fcf_record); - fcf_rec->fabric_name[3] = - bf_get(lpfc_fcf_record_fab_name_3, new_fcf_record); - fcf_rec->fabric_name[4] = - bf_get(lpfc_fcf_record_fab_name_4, new_fcf_record); - fcf_rec->fabric_name[5] = - bf_get(lpfc_fcf_record_fab_name_5, new_fcf_record); - fcf_rec->fabric_name[6] = - bf_get(lpfc_fcf_record_fab_name_6, new_fcf_record); - fcf_rec->fabric_name[7] = - bf_get(lpfc_fcf_record_fab_name_7, new_fcf_record); - /* Mac address */ - fcf_rec->mac_addr[0] = bf_get(lpfc_fcf_record_mac_0, new_fcf_record); - fcf_rec->mac_addr[1] = bf_get(lpfc_fcf_record_mac_1, new_fcf_record); - fcf_rec->mac_addr[2] = bf_get(lpfc_fcf_record_mac_2, new_fcf_record); - fcf_rec->mac_addr[3] = bf_get(lpfc_fcf_record_mac_3, new_fcf_record); - fcf_rec->mac_addr[4] = bf_get(lpfc_fcf_record_mac_4, new_fcf_record); - fcf_rec->mac_addr[5] = bf_get(lpfc_fcf_record_mac_5, new_fcf_record); - /* FCF record index */ - fcf_rec->fcf_indx = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); - /* FCF record priority */ - fcf_rec->priority = new_fcf_record->fip_priority; - /* Switch name */ - fcf_rec->switch_name[0] = - bf_get(lpfc_fcf_record_switch_name_0, new_fcf_record); - fcf_rec->switch_name[1] = - bf_get(lpfc_fcf_record_switch_name_1, new_fcf_record); - fcf_rec->switch_name[2] = - bf_get(lpfc_fcf_record_switch_name_2, new_fcf_record); - fcf_rec->switch_name[3] = - bf_get(lpfc_fcf_record_switch_name_3, new_fcf_record); - fcf_rec->switch_name[4] = - bf_get(lpfc_fcf_record_switch_name_4, new_fcf_record); - fcf_rec->switch_name[5] = - bf_get(lpfc_fcf_record_switch_name_5, new_fcf_record); - fcf_rec->switch_name[6] = - bf_get(lpfc_fcf_record_switch_name_6, new_fcf_record); - fcf_rec->switch_name[7] = - bf_get(lpfc_fcf_record_switch_name_7, new_fcf_record); -} - -/** - * lpfc_update_fcf_record - Update driver fcf record - * @phba: pointer to lpfc hba data structure. - * @fcf_rec: pointer to driver fcf record. - * @new_fcf_record: pointer to hba fcf record. - * @addr_mode: address mode to be set to the driver fcf record. - * @vlan_id: vlan tag to be set to the driver fcf record. - * @flag: flag bits to be set to the driver fcf record. - * - * This routine updates the driver FCF record from the new HBA FCF record - * together with the address mode, vlan_id, and other informations. This - * routine is called with the host lock held. - **/ -static void -__lpfc_update_fcf_record(struct lpfc_hba *phba, struct lpfc_fcf_rec *fcf_rec, - struct fcf_record *new_fcf_record, uint32_t addr_mode, - uint16_t vlan_id, uint32_t flag) -{ - /* Copy the fields from the HBA's FCF record */ - lpfc_copy_fcf_record(fcf_rec, new_fcf_record); - /* Update other fields of driver FCF record */ - fcf_rec->addr_mode = addr_mode; - fcf_rec->vlan_id = vlan_id; - fcf_rec->flag |= (flag | RECORD_VALID); - __lpfc_update_fcf_record_pri(phba, - bf_get(lpfc_fcf_record_fcf_index, new_fcf_record), - new_fcf_record); -} - -/** - * lpfc_register_fcf - Register the FCF with hba. - * @phba: pointer to lpfc hba data structure. - * - * This routine issues a register fcfi mailbox command to register - * the fcf with HBA. - **/ -static void -lpfc_register_fcf(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *fcf_mbxq; - int rc; - - spin_lock_irq(&phba->hbalock); - /* If the FCF is not available do nothing. */ - if (!(phba->fcf.fcf_flag & FCF_AVAILABLE)) { - phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); - spin_unlock_irq(&phba->hbalock); - return; - } - - /* The FCF is already registered, start discovery */ - if (phba->fcf.fcf_flag & FCF_REGISTERED) { - phba->fcf.fcf_flag |= (FCF_SCAN_DONE | FCF_IN_USE); - phba->hba_flag &= ~FCF_TS_INPROG; - if (phba->pport->port_state != LPFC_FLOGI) { - phba->hba_flag |= FCF_RR_INPROG; - spin_unlock_irq(&phba->hbalock); - lpfc_initial_flogi(phba->pport); - return; - } - spin_unlock_irq(&phba->hbalock); - return; - } - spin_unlock_irq(&phba->hbalock); - - fcf_mbxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!fcf_mbxq) { - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); - spin_unlock_irq(&phba->hbalock); - return; - } - - lpfc_reg_fcfi(phba, fcf_mbxq); - fcf_mbxq->vport = phba->pport; - fcf_mbxq->mbox_cmpl = lpfc_mbx_cmpl_reg_fcfi; - rc = lpfc_sli_issue_mbox(phba, fcf_mbxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); - spin_unlock_irq(&phba->hbalock); - mempool_free(fcf_mbxq, phba->mbox_mem_pool); - } - - return; -} - -/** - * lpfc_match_fcf_conn_list - Check if the FCF record can be used for discovery. - * @phba: pointer to lpfc hba data structure. - * @new_fcf_record: pointer to fcf record. - * @boot_flag: Indicates if this record used by boot bios. - * @addr_mode: The address mode to be used by this FCF - * @vlan_id: The vlan id to be used as vlan tagging by this FCF. - * - * This routine compare the fcf record with connect list obtained from the - * config region to decide if this FCF can be used for SAN discovery. It returns - * 1 if this record can be used for SAN discovery else return zero. If this FCF - * record can be used for SAN discovery, the boot_flag will indicate if this FCF - * is used by boot bios and addr_mode will indicate the addressing mode to be - * used for this FCF when the function returns. - * If the FCF record need to be used with a particular vlan id, the vlan is - * set in the vlan_id on return of the function. If not VLAN tagging need to - * be used with the FCF vlan_id will be set to LPFC_FCOE_NULL_VID; - **/ -static int -lpfc_match_fcf_conn_list(struct lpfc_hba *phba, - struct fcf_record *new_fcf_record, - uint32_t *boot_flag, uint32_t *addr_mode, - uint16_t *vlan_id) -{ - struct lpfc_fcf_conn_entry *conn_entry; - int i, j, fcf_vlan_id = 0; - - /* Find the lowest VLAN id in the FCF record */ - for (i = 0; i < 512; i++) { - if (new_fcf_record->vlan_bitmap[i]) { - fcf_vlan_id = i * 8; - j = 0; - while (!((new_fcf_record->vlan_bitmap[i] >> j) & 1)) { - j++; - fcf_vlan_id++; - } - break; - } - } - - /* If FCF not available return 0 */ - if (!bf_get(lpfc_fcf_record_fcf_avail, new_fcf_record) || - !bf_get(lpfc_fcf_record_fcf_valid, new_fcf_record)) - return 0; - - if (!(phba->hba_flag & HBA_FIP_SUPPORT)) { - *boot_flag = 0; - *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, - new_fcf_record); - if (phba->valid_vlan) - *vlan_id = phba->vlan_id; - else - *vlan_id = LPFC_FCOE_NULL_VID; - return 1; - } - - /* - * If there are no FCF connection table entry, driver connect to all - * FCFs. - */ - if (list_empty(&phba->fcf_conn_rec_list)) { - *boot_flag = 0; - *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, - new_fcf_record); - - /* - * When there are no FCF connect entries, use driver's default - * addressing mode - FPMA. - */ - if (*addr_mode & LPFC_FCF_FPMA) - *addr_mode = LPFC_FCF_FPMA; - - /* If FCF record report a vlan id use that vlan id */ - if (fcf_vlan_id) - *vlan_id = fcf_vlan_id; - else - *vlan_id = LPFC_FCOE_NULL_VID; - return 1; - } - - list_for_each_entry(conn_entry, - &phba->fcf_conn_rec_list, list) { - if (!(conn_entry->conn_rec.flags & FCFCNCT_VALID)) - continue; - - if ((conn_entry->conn_rec.flags & FCFCNCT_FBNM_VALID) && - !lpfc_fab_name_match(conn_entry->conn_rec.fabric_name, - new_fcf_record)) - continue; - if ((conn_entry->conn_rec.flags & FCFCNCT_SWNM_VALID) && - !lpfc_sw_name_match(conn_entry->conn_rec.switch_name, - new_fcf_record)) - continue; - if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) { - /* - * If the vlan bit map does not have the bit set for the - * vlan id to be used, then it is not a match. - */ - if (!(new_fcf_record->vlan_bitmap - [conn_entry->conn_rec.vlan_tag / 8] & - (1 << (conn_entry->conn_rec.vlan_tag % 8)))) - continue; - } - - /* - * If connection record does not support any addressing mode, - * skip the FCF record. - */ - if (!(bf_get(lpfc_fcf_record_mac_addr_prov, new_fcf_record) - & (LPFC_FCF_FPMA | LPFC_FCF_SPMA))) - continue; - - /* - * Check if the connection record specifies a required - * addressing mode. - */ - if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && - !(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED)) { - - /* - * If SPMA required but FCF not support this continue. - */ - if ((conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && - !(bf_get(lpfc_fcf_record_mac_addr_prov, - new_fcf_record) & LPFC_FCF_SPMA)) - continue; - - /* - * If FPMA required but FCF not support this continue. - */ - if (!(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && - !(bf_get(lpfc_fcf_record_mac_addr_prov, - new_fcf_record) & LPFC_FCF_FPMA)) - continue; - } - - /* - * This fcf record matches filtering criteria. - */ - if (conn_entry->conn_rec.flags & FCFCNCT_BOOT) - *boot_flag = 1; - else - *boot_flag = 0; - - /* - * If user did not specify any addressing mode, or if the - * preferred addressing mode specified by user is not supported - * by FCF, allow fabric to pick the addressing mode. - */ - *addr_mode = bf_get(lpfc_fcf_record_mac_addr_prov, - new_fcf_record); - /* - * If the user specified a required address mode, assign that - * address mode - */ - if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && - (!(conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED))) - *addr_mode = (conn_entry->conn_rec.flags & - FCFCNCT_AM_SPMA) ? - LPFC_FCF_SPMA : LPFC_FCF_FPMA; - /* - * If the user specified a preferred address mode, use the - * addr mode only if FCF support the addr_mode. - */ - else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && - (conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) && - (conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && - (*addr_mode & LPFC_FCF_SPMA)) - *addr_mode = LPFC_FCF_SPMA; - else if ((conn_entry->conn_rec.flags & FCFCNCT_AM_VALID) && - (conn_entry->conn_rec.flags & FCFCNCT_AM_PREFERRED) && - !(conn_entry->conn_rec.flags & FCFCNCT_AM_SPMA) && - (*addr_mode & LPFC_FCF_FPMA)) - *addr_mode = LPFC_FCF_FPMA; - - /* If matching connect list has a vlan id, use it */ - if (conn_entry->conn_rec.flags & FCFCNCT_VLAN_VALID) - *vlan_id = conn_entry->conn_rec.vlan_tag; - /* - * If no vlan id is specified in connect list, use the vlan id - * in the FCF record - */ - else if (fcf_vlan_id) - *vlan_id = fcf_vlan_id; - else - *vlan_id = LPFC_FCOE_NULL_VID; - - return 1; - } - - return 0; -} - -/** - * lpfc_check_pending_fcoe_event - Check if there is pending fcoe event. - * @phba: pointer to lpfc hba data structure. - * @unreg_fcf: Unregister FCF if FCF table need to be re-scaned. - * - * This function check if there is any fcoe event pending while driver - * scan FCF entries. If there is any pending event, it will restart the - * FCF saning and return 1 else return 0. - */ -int -lpfc_check_pending_fcoe_event(struct lpfc_hba *phba, uint8_t unreg_fcf) -{ - /* - * If the Link is up and no FCoE events while in the - * FCF discovery, no need to restart FCF discovery. - */ - if ((phba->link_state >= LPFC_LINK_UP) && - (phba->fcoe_eventtag == phba->fcoe_eventtag_at_fcf_scan)) - return 0; - - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2768 Pending link or FCF event during current " - "handling of the previous event: link_state:x%x, " - "evt_tag_at_scan:x%x, evt_tag_current:x%x\n", - phba->link_state, phba->fcoe_eventtag_at_fcf_scan, - phba->fcoe_eventtag); - - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_AVAILABLE; - spin_unlock_irq(&phba->hbalock); - - if (phba->link_state >= LPFC_LINK_UP) { - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, - "2780 Restart FCF table scan due to " - "pending FCF event:evt_tag_at_scan:x%x, " - "evt_tag_current:x%x\n", - phba->fcoe_eventtag_at_fcf_scan, - phba->fcoe_eventtag); - lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); - } else { - /* - * Do not continue FCF discovery and clear FCF_TS_INPROG - * flag - */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, - "2833 Stop FCF discovery process due to link " - "state change (x%x)\n", phba->link_state); - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~(FCF_TS_INPROG | FCF_RR_INPROG); - phba->fcf.fcf_flag &= ~(FCF_REDISC_FOV | FCF_DISCOVERY); - spin_unlock_irq(&phba->hbalock); - } - - /* Unregister the currently registered FCF if required */ - if (unreg_fcf) { - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_REGISTERED; - spin_unlock_irq(&phba->hbalock); - lpfc_sli4_unregister_fcf(phba); - } - return 1; -} - -/** - * lpfc_sli4_new_fcf_random_select - Randomly select an eligible new fcf record - * @phba: pointer to lpfc hba data structure. - * @fcf_cnt: number of eligible fcf record seen so far. - * - * This function makes an running random selection decision on FCF record to - * use through a sequence of @fcf_cnt eligible FCF records with equal - * probability. To perform integer manunipulation of random numbers with - * size unit32_t, the lower 16 bits of the 32-bit random number returned - * from random32() are taken as the random random number generated. - * - * Returns true when outcome is for the newly read FCF record should be - * chosen; otherwise, return false when outcome is for keeping the previously - * chosen FCF record. - **/ -static bool -lpfc_sli4_new_fcf_random_select(struct lpfc_hba *phba, uint32_t fcf_cnt) -{ - uint32_t rand_num; - - /* Get 16-bit uniform random number */ - rand_num = (0xFFFF & random32()); - - /* Decision with probability 1/fcf_cnt */ - if ((fcf_cnt * rand_num) < 0xFFFF) - return true; - else - return false; -} - -/** - * lpfc_sli4_fcf_rec_mbox_parse - Parse read_fcf mbox command. - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to mailbox object. - * @next_fcf_index: pointer to holder of next fcf index. - * - * This routine parses the non-embedded fcf mailbox command by performing the - * necessarily error checking, non-embedded read FCF record mailbox command - * SGE parsing, and endianness swapping. - * - * Returns the pointer to the new FCF record in the non-embedded mailbox - * command DMA memory if successfully, other NULL. - */ -static struct fcf_record * -lpfc_sli4_fcf_rec_mbox_parse(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, - uint16_t *next_fcf_index) -{ - void *virt_addr; - dma_addr_t phys_addr; - struct lpfc_mbx_sge sge; - struct lpfc_mbx_read_fcf_tbl *read_fcf; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - struct fcf_record *new_fcf_record; - - /* Get the first SGE entry from the non-embedded DMA memory. This - * routine only uses a single SGE. - */ - lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); - if (unlikely(!mboxq->sge_array)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2524 Failed to get the non-embedded SGE " - "virtual address\n"); - return NULL; - } - virt_addr = mboxq->sge_array->addr[0]; - - shdr = (union lpfc_sli4_cfg_shdr *)virt_addr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status) { - if (shdr_status == STATUS_FCF_TABLE_EMPTY) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "2726 READ_FCF_RECORD Indicates empty " - "FCF table.\n"); - else - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "2521 READ_FCF_RECORD mailbox failed " - "with status x%x add_status x%x, " - "mbx\n", shdr_status, shdr_add_status); - return NULL; - } - - /* Interpreting the returned information of the FCF record */ - read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr; - lpfc_sli_pcimem_bcopy(read_fcf, read_fcf, - sizeof(struct lpfc_mbx_read_fcf_tbl)); - *next_fcf_index = bf_get(lpfc_mbx_read_fcf_tbl_nxt_vindx, read_fcf); - new_fcf_record = (struct fcf_record *)(virt_addr + - sizeof(struct lpfc_mbx_read_fcf_tbl)); - lpfc_sli_pcimem_bcopy(new_fcf_record, new_fcf_record, - offsetof(struct fcf_record, vlan_bitmap)); - new_fcf_record->word137 = le32_to_cpu(new_fcf_record->word137); - new_fcf_record->word138 = le32_to_cpu(new_fcf_record->word138); - - return new_fcf_record; -} - -/** - * lpfc_sli4_log_fcf_record_info - Log the information of a fcf record - * @phba: pointer to lpfc hba data structure. - * @fcf_record: pointer to the fcf record. - * @vlan_id: the lowest vlan identifier associated to this fcf record. - * @next_fcf_index: the index to the next fcf record in hba's fcf table. - * - * This routine logs the detailed FCF record if the LOG_FIP loggin is - * enabled. - **/ -static void -lpfc_sli4_log_fcf_record_info(struct lpfc_hba *phba, - struct fcf_record *fcf_record, - uint16_t vlan_id, - uint16_t next_fcf_index) -{ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2764 READ_FCF_RECORD:\n" - "\tFCF_Index : x%x\n" - "\tFCF_Avail : x%x\n" - "\tFCF_Valid : x%x\n" - "\tFIP_Priority : x%x\n" - "\tMAC_Provider : x%x\n" - "\tLowest VLANID : x%x\n" - "\tFCF_MAC Addr : x%x:%x:%x:%x:%x:%x\n" - "\tFabric_Name : x%x:%x:%x:%x:%x:%x:%x:%x\n" - "\tSwitch_Name : x%x:%x:%x:%x:%x:%x:%x:%x\n" - "\tNext_FCF_Index: x%x\n", - bf_get(lpfc_fcf_record_fcf_index, fcf_record), - bf_get(lpfc_fcf_record_fcf_avail, fcf_record), - bf_get(lpfc_fcf_record_fcf_valid, fcf_record), - fcf_record->fip_priority, - bf_get(lpfc_fcf_record_mac_addr_prov, fcf_record), - vlan_id, - bf_get(lpfc_fcf_record_mac_0, fcf_record), - bf_get(lpfc_fcf_record_mac_1, fcf_record), - bf_get(lpfc_fcf_record_mac_2, fcf_record), - bf_get(lpfc_fcf_record_mac_3, fcf_record), - bf_get(lpfc_fcf_record_mac_4, fcf_record), - bf_get(lpfc_fcf_record_mac_5, fcf_record), - bf_get(lpfc_fcf_record_fab_name_0, fcf_record), - bf_get(lpfc_fcf_record_fab_name_1, fcf_record), - bf_get(lpfc_fcf_record_fab_name_2, fcf_record), - bf_get(lpfc_fcf_record_fab_name_3, fcf_record), - bf_get(lpfc_fcf_record_fab_name_4, fcf_record), - bf_get(lpfc_fcf_record_fab_name_5, fcf_record), - bf_get(lpfc_fcf_record_fab_name_6, fcf_record), - bf_get(lpfc_fcf_record_fab_name_7, fcf_record), - bf_get(lpfc_fcf_record_switch_name_0, fcf_record), - bf_get(lpfc_fcf_record_switch_name_1, fcf_record), - bf_get(lpfc_fcf_record_switch_name_2, fcf_record), - bf_get(lpfc_fcf_record_switch_name_3, fcf_record), - bf_get(lpfc_fcf_record_switch_name_4, fcf_record), - bf_get(lpfc_fcf_record_switch_name_5, fcf_record), - bf_get(lpfc_fcf_record_switch_name_6, fcf_record), - bf_get(lpfc_fcf_record_switch_name_7, fcf_record), - next_fcf_index); -} - -/** - lpfc_sli4_fcf_record_match - testing new FCF record for matching existing FCF - * @phba: pointer to lpfc hba data structure. - * @fcf_rec: pointer to an existing FCF record. - * @new_fcf_record: pointer to a new FCF record. - * @new_vlan_id: vlan id from the new FCF record. - * - * This function performs matching test of a new FCF record against an existing - * FCF record. If the new_vlan_id passed in is LPFC_FCOE_IGNORE_VID, vlan id - * will not be used as part of the FCF record matching criteria. - * - * Returns true if all the fields matching, otherwise returns false. - */ -static bool -lpfc_sli4_fcf_record_match(struct lpfc_hba *phba, - struct lpfc_fcf_rec *fcf_rec, - struct fcf_record *new_fcf_record, - uint16_t new_vlan_id) -{ - if (new_vlan_id != LPFC_FCOE_IGNORE_VID) - if (!lpfc_vlan_id_match(fcf_rec->vlan_id, new_vlan_id)) - return false; - if (!lpfc_mac_addr_match(fcf_rec->mac_addr, new_fcf_record)) - return false; - if (!lpfc_sw_name_match(fcf_rec->switch_name, new_fcf_record)) - return false; - if (!lpfc_fab_name_match(fcf_rec->fabric_name, new_fcf_record)) - return false; - if (fcf_rec->priority != new_fcf_record->fip_priority) - return false; - return true; -} - -/** - * lpfc_sli4_fcf_rr_next_proc - processing next roundrobin fcf - * @vport: Pointer to vport object. - * @fcf_index: index to next fcf. - * - * This function processing the roundrobin fcf failover to next fcf index. - * When this function is invoked, there will be a current fcf registered - * for flogi. - * Return: 0 for continue retrying flogi on currently registered fcf; - * 1 for stop flogi on currently registered fcf; - */ -int lpfc_sli4_fcf_rr_next_proc(struct lpfc_vport *vport, uint16_t fcf_index) -{ - struct lpfc_hba *phba = vport->phba; - int rc; - - if (fcf_index == LPFC_FCOE_FCF_NEXT_NONE) { - spin_lock_irq(&phba->hbalock); - if (phba->hba_flag & HBA_DEVLOSS_TMO) { - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2872 Devloss tmo with no eligible " - "FCF, unregister in-use FCF (x%x) " - "and rescan FCF table\n", - phba->fcf.current_rec.fcf_indx); - lpfc_unregister_fcf_rescan(phba); - goto stop_flogi_current_fcf; - } - /* Mark the end to FLOGI roundrobin failover */ - phba->hba_flag &= ~FCF_RR_INPROG; - /* Allow action to new fcf asynchronous event */ - phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE); - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2865 No FCF available, stop roundrobin FCF " - "failover and change port state:x%x/x%x\n", - phba->pport->port_state, LPFC_VPORT_UNKNOWN); - phba->pport->port_state = LPFC_VPORT_UNKNOWN; - goto stop_flogi_current_fcf; - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_ELS, - "2794 Try FLOGI roundrobin FCF failover to " - "(x%x)\n", fcf_index); - rc = lpfc_sli4_fcf_rr_read_fcf_rec(phba, fcf_index); - if (rc) - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | LOG_ELS, - "2761 FLOGI roundrobin FCF failover " - "failed (rc:x%x) to read FCF (x%x)\n", - rc, phba->fcf.current_rec.fcf_indx); - else - goto stop_flogi_current_fcf; - } - return 0; - -stop_flogi_current_fcf: - lpfc_can_disctmo(vport); - return 1; -} - -/** - * lpfc_sli4_fcf_pri_list_del - * @phba: pointer to lpfc hba data structure. - * @fcf_index the index of the fcf record to delete - * This routine checks the on list flag of the fcf_index to be deleted. - * If it is one the list then it is removed from the list, and the flag - * is cleared. This routine grab the hbalock before removing the fcf - * record from the list. - **/ -static void lpfc_sli4_fcf_pri_list_del(struct lpfc_hba *phba, - uint16_t fcf_index) -{ - struct lpfc_fcf_pri *new_fcf_pri; - - new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "3058 deleting idx x%x pri x%x flg x%x\n", - fcf_index, new_fcf_pri->fcf_rec.priority, - new_fcf_pri->fcf_rec.flag); - spin_lock_irq(&phba->hbalock); - if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) { - if (phba->fcf.current_rec.priority == - new_fcf_pri->fcf_rec.priority) - phba->fcf.eligible_fcf_cnt--; - list_del_init(&new_fcf_pri->list); - new_fcf_pri->fcf_rec.flag &= ~LPFC_FCF_ON_PRI_LIST; - } - spin_unlock_irq(&phba->hbalock); -} - -/** - * lpfc_sli4_set_fcf_flogi_fail - * @phba: pointer to lpfc hba data structure. - * @fcf_index the index of the fcf record to update - * This routine acquires the hbalock and then set the LPFC_FCF_FLOGI_FAILED - * flag so the the round robin slection for the particular priority level - * will try a different fcf record that does not have this bit set. - * If the fcf record is re-read for any reason this flag is cleared brfore - * adding it to the priority list. - **/ -void -lpfc_sli4_set_fcf_flogi_fail(struct lpfc_hba *phba, uint16_t fcf_index) -{ - struct lpfc_fcf_pri *new_fcf_pri; - new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; - spin_lock_irq(&phba->hbalock); - new_fcf_pri->fcf_rec.flag |= LPFC_FCF_FLOGI_FAILED; - spin_unlock_irq(&phba->hbalock); -} - -/** - * lpfc_sli4_fcf_pri_list_add - * @phba: pointer to lpfc hba data structure. - * @fcf_index the index of the fcf record to add - * This routine checks the priority of the fcf_index to be added. - * If it is a lower priority than the current head of the fcf_pri list - * then it is added to the list in the right order. - * If it is the same priority as the current head of the list then it - * is added to the head of the list and its bit in the rr_bmask is set. - * If the fcf_index to be added is of a higher priority than the current - * head of the list then the rr_bmask is cleared, its bit is set in the - * rr_bmask and it is added to the head of the list. - * returns: - * 0=success 1=failure - **/ -int lpfc_sli4_fcf_pri_list_add(struct lpfc_hba *phba, uint16_t fcf_index, - struct fcf_record *new_fcf_record) -{ - uint16_t current_fcf_pri; - uint16_t last_index; - struct lpfc_fcf_pri *fcf_pri; - struct lpfc_fcf_pri *next_fcf_pri; - struct lpfc_fcf_pri *new_fcf_pri; - int ret; - - new_fcf_pri = &phba->fcf.fcf_pri[fcf_index]; - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "3059 adding idx x%x pri x%x flg x%x\n", - fcf_index, new_fcf_record->fip_priority, - new_fcf_pri->fcf_rec.flag); - spin_lock_irq(&phba->hbalock); - if (new_fcf_pri->fcf_rec.flag & LPFC_FCF_ON_PRI_LIST) - list_del_init(&new_fcf_pri->list); - new_fcf_pri->fcf_rec.fcf_index = fcf_index; - new_fcf_pri->fcf_rec.priority = new_fcf_record->fip_priority; - if (list_empty(&phba->fcf.fcf_pri_list)) { - list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list); - ret = lpfc_sli4_fcf_rr_index_set(phba, - new_fcf_pri->fcf_rec.fcf_index); - goto out; - } - - last_index = find_first_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX); - if (last_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { - ret = 0; /* Empty rr list */ - goto out; - } - current_fcf_pri = phba->fcf.fcf_pri[last_index].fcf_rec.priority; - if (new_fcf_pri->fcf_rec.priority <= current_fcf_pri) { - list_add(&new_fcf_pri->list, &phba->fcf.fcf_pri_list); - if (new_fcf_pri->fcf_rec.priority < current_fcf_pri) { - memset(phba->fcf.fcf_rr_bmask, 0, - sizeof(*phba->fcf.fcf_rr_bmask)); - /* fcfs_at_this_priority_level = 1; */ - phba->fcf.eligible_fcf_cnt = 1; - } else - /* fcfs_at_this_priority_level++; */ - phba->fcf.eligible_fcf_cnt++; - ret = lpfc_sli4_fcf_rr_index_set(phba, - new_fcf_pri->fcf_rec.fcf_index); - goto out; - } - - list_for_each_entry_safe(fcf_pri, next_fcf_pri, - &phba->fcf.fcf_pri_list, list) { - if (new_fcf_pri->fcf_rec.priority <= - fcf_pri->fcf_rec.priority) { - if (fcf_pri->list.prev == &phba->fcf.fcf_pri_list) - list_add(&new_fcf_pri->list, - &phba->fcf.fcf_pri_list); - else - list_add(&new_fcf_pri->list, - &((struct lpfc_fcf_pri *) - fcf_pri->list.prev)->list); - ret = 0; - goto out; - } else if (fcf_pri->list.next == &phba->fcf.fcf_pri_list - || new_fcf_pri->fcf_rec.priority < - next_fcf_pri->fcf_rec.priority) { - list_add(&new_fcf_pri->list, &fcf_pri->list); - ret = 0; - goto out; - } - if (new_fcf_pri->fcf_rec.priority > fcf_pri->fcf_rec.priority) - continue; - - } - ret = 1; -out: - /* we use = instead of |= to clear the FLOGI_FAILED flag. */ - new_fcf_pri->fcf_rec.flag = LPFC_FCF_ON_PRI_LIST; - spin_unlock_irq(&phba->hbalock); - return ret; -} - -/** - * lpfc_mbx_cmpl_fcf_scan_read_fcf_rec - fcf scan read_fcf mbox cmpl handler. - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to mailbox object. - * - * This function iterates through all the fcf records available in - * HBA and chooses the optimal FCF record for discovery. After finding - * the FCF for discovery it registers the FCF record and kicks start - * discovery. - * If FCF_IN_USE flag is set in currently used FCF, the routine tries to - * use an FCF record which matches fabric name and mac address of the - * currently used FCF record. - * If the driver supports only one FCF, it will try to use the FCF record - * used by BOOT_BIOS. - */ -void -lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct fcf_record *new_fcf_record; - uint32_t boot_flag, addr_mode; - uint16_t fcf_index, next_fcf_index; - struct lpfc_fcf_rec *fcf_rec = NULL; - uint16_t vlan_id; - uint32_t seed; - bool select_new_fcf; - int rc; - - /* If there is pending FCoE event restart FCF table scan */ - if (lpfc_check_pending_fcoe_event(phba, LPFC_SKIP_UNREG_FCF)) { - lpfc_sli4_mbox_cmd_free(phba, mboxq); - return; - } - - /* Parse the FCF record from the non-embedded mailbox command */ - new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq, - &next_fcf_index); - if (!new_fcf_record) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "2765 Mailbox command READ_FCF_RECORD " - "failed to retrieve a FCF record.\n"); - /* Let next new FCF event trigger fast failover */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~FCF_TS_INPROG; - spin_unlock_irq(&phba->hbalock); - lpfc_sli4_mbox_cmd_free(phba, mboxq); - return; - } - - /* Check the FCF record against the connection list */ - rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag, - &addr_mode, &vlan_id); - - /* Log the FCF record information if turned on */ - lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id, - next_fcf_index); - - /* - * If the fcf record does not match with connect list entries - * read the next entry; otherwise, this is an eligible FCF - * record for roundrobin FCF failover. - */ - if (!rc) { - lpfc_sli4_fcf_pri_list_del(phba, - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record)); - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2781 FCF (x%x) failed connection " - "list check: (x%x/x%x)\n", - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record), - bf_get(lpfc_fcf_record_fcf_avail, - new_fcf_record), - bf_get(lpfc_fcf_record_fcf_valid, - new_fcf_record)); - if ((phba->fcf.fcf_flag & FCF_IN_USE) && - lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec, - new_fcf_record, LPFC_FCOE_IGNORE_VID)) { - if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) != - phba->fcf.current_rec.fcf_indx) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "2862 FCF (x%x) matches property " - "of in-use FCF (x%x)\n", - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record), - phba->fcf.current_rec.fcf_indx); - goto read_next_fcf; - } - /* - * In case the current in-use FCF record becomes - * invalid/unavailable during FCF discovery that - * was not triggered by fast FCF failover process, - * treat it as fast FCF failover. - */ - if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND) && - !(phba->fcf.fcf_flag & FCF_REDISC_FOV)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2835 Invalid in-use FCF " - "(x%x), enter FCF failover " - "table scan.\n", - phba->fcf.current_rec.fcf_indx); - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag |= FCF_REDISC_FOV; - spin_unlock_irq(&phba->hbalock); - lpfc_sli4_mbox_cmd_free(phba, mboxq); - lpfc_sli4_fcf_scan_read_fcf_rec(phba, - LPFC_FCOE_FCF_GET_FIRST); - return; - } - } - goto read_next_fcf; - } else { - fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); - rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, - new_fcf_record); - if (rc) - goto read_next_fcf; - } - - /* - * If this is not the first FCF discovery of the HBA, use last - * FCF record for the discovery. The condition that a rescan - * matches the in-use FCF record: fabric name, switch name, mac - * address, and vlan_id. - */ - spin_lock_irq(&phba->hbalock); - if (phba->fcf.fcf_flag & FCF_IN_USE) { - if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV && - lpfc_sli4_fcf_record_match(phba, &phba->fcf.current_rec, - new_fcf_record, vlan_id)) { - if (bf_get(lpfc_fcf_record_fcf_index, new_fcf_record) == - phba->fcf.current_rec.fcf_indx) { - phba->fcf.fcf_flag |= FCF_AVAILABLE; - if (phba->fcf.fcf_flag & FCF_REDISC_PEND) - /* Stop FCF redisc wait timer */ - __lpfc_sli4_stop_fcf_redisc_wait_timer( - phba); - else if (phba->fcf.fcf_flag & FCF_REDISC_FOV) - /* Fast failover, mark completed */ - phba->fcf.fcf_flag &= ~FCF_REDISC_FOV; - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2836 New FCF matches in-use " - "FCF (x%x)\n", - phba->fcf.current_rec.fcf_indx); - goto out; - } else - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "2863 New FCF (x%x) matches " - "property of in-use FCF (x%x)\n", - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record), - phba->fcf.current_rec.fcf_indx); - } - /* - * Read next FCF record from HBA searching for the matching - * with in-use record only if not during the fast failover - * period. In case of fast failover period, it shall try to - * determine whether the FCF record just read should be the - * next candidate. - */ - if (!(phba->fcf.fcf_flag & FCF_REDISC_FOV)) { - spin_unlock_irq(&phba->hbalock); - goto read_next_fcf; - } - } - /* - * Update on failover FCF record only if it's in FCF fast-failover - * period; otherwise, update on current FCF record. - */ - if (phba->fcf.fcf_flag & FCF_REDISC_FOV) - fcf_rec = &phba->fcf.failover_rec; - else - fcf_rec = &phba->fcf.current_rec; - - if (phba->fcf.fcf_flag & FCF_AVAILABLE) { - /* - * If the driver FCF record does not have boot flag - * set and new hba fcf record has boot flag set, use - * the new hba fcf record. - */ - if (boot_flag && !(fcf_rec->flag & BOOT_ENABLE)) { - /* Choose this FCF record */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2837 Update current FCF record " - "(x%x) with new FCF record (x%x)\n", - fcf_rec->fcf_indx, - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record)); - __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, - addr_mode, vlan_id, BOOT_ENABLE); - spin_unlock_irq(&phba->hbalock); - goto read_next_fcf; - } - /* - * If the driver FCF record has boot flag set and the - * new hba FCF record does not have boot flag, read - * the next FCF record. - */ - if (!boot_flag && (fcf_rec->flag & BOOT_ENABLE)) { - spin_unlock_irq(&phba->hbalock); - goto read_next_fcf; - } - /* - * If the new hba FCF record has lower priority value - * than the driver FCF record, use the new record. - */ - if (new_fcf_record->fip_priority < fcf_rec->priority) { - /* Choose the new FCF record with lower priority */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2838 Update current FCF record " - "(x%x) with new FCF record (x%x)\n", - fcf_rec->fcf_indx, - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record)); - __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, - addr_mode, vlan_id, 0); - /* Reset running random FCF selection count */ - phba->fcf.eligible_fcf_cnt = 1; - } else if (new_fcf_record->fip_priority == fcf_rec->priority) { - /* Update running random FCF selection count */ - phba->fcf.eligible_fcf_cnt++; - select_new_fcf = lpfc_sli4_new_fcf_random_select(phba, - phba->fcf.eligible_fcf_cnt); - if (select_new_fcf) { - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2839 Update current FCF record " - "(x%x) with new FCF record (x%x)\n", - fcf_rec->fcf_indx, - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record)); - /* Choose the new FCF by random selection */ - __lpfc_update_fcf_record(phba, fcf_rec, - new_fcf_record, - addr_mode, vlan_id, 0); - } - } - spin_unlock_irq(&phba->hbalock); - goto read_next_fcf; - } - /* - * This is the first suitable FCF record, choose this record for - * initial best-fit FCF. - */ - if (fcf_rec) { - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2840 Update initial FCF candidate " - "with FCF (x%x)\n", - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record)); - __lpfc_update_fcf_record(phba, fcf_rec, new_fcf_record, - addr_mode, vlan_id, (boot_flag ? - BOOT_ENABLE : 0)); - phba->fcf.fcf_flag |= FCF_AVAILABLE; - /* Setup initial running random FCF selection count */ - phba->fcf.eligible_fcf_cnt = 1; - /* Seeding the random number generator for random selection */ - seed = (uint32_t)(0xFFFFFFFF & jiffies); - srandom32(seed); - } - spin_unlock_irq(&phba->hbalock); - goto read_next_fcf; - -read_next_fcf: - lpfc_sli4_mbox_cmd_free(phba, mboxq); - if (next_fcf_index == LPFC_FCOE_FCF_NEXT_NONE || next_fcf_index == 0) { - if (phba->fcf.fcf_flag & FCF_REDISC_FOV) { - /* - * Case of FCF fast failover scan - */ - - /* - * It has not found any suitable FCF record, cancel - * FCF scan inprogress, and do nothing - */ - if (!(phba->fcf.failover_rec.flag & RECORD_VALID)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2782 No suitable FCF found: " - "(x%x/x%x)\n", - phba->fcoe_eventtag_at_fcf_scan, - bf_get(lpfc_fcf_record_fcf_index, - new_fcf_record)); - spin_lock_irq(&phba->hbalock); - if (phba->hba_flag & HBA_DEVLOSS_TMO) { - phba->hba_flag &= ~FCF_TS_INPROG; - spin_unlock_irq(&phba->hbalock); - /* Unregister in-use FCF and rescan */ - lpfc_printf_log(phba, KERN_INFO, - LOG_FIP, - "2864 On devloss tmo " - "unreg in-use FCF and " - "rescan FCF table\n"); - lpfc_unregister_fcf_rescan(phba); - return; - } - /* - * Let next new FCF event trigger fast failover - */ - phba->hba_flag &= ~FCF_TS_INPROG; - spin_unlock_irq(&phba->hbalock); - return; - } - /* - * It has found a suitable FCF record that is not - * the same as in-use FCF record, unregister the - * in-use FCF record, replace the in-use FCF record - * with the new FCF record, mark FCF fast failover - * completed, and then start register the new FCF - * record. - */ - - /* Unregister the current in-use FCF record */ - lpfc_unregister_fcf(phba); - - /* Replace in-use record with the new record */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2842 Replace in-use FCF (x%x) " - "with failover FCF (x%x)\n", - phba->fcf.current_rec.fcf_indx, - phba->fcf.failover_rec.fcf_indx); - memcpy(&phba->fcf.current_rec, - &phba->fcf.failover_rec, - sizeof(struct lpfc_fcf_rec)); - /* - * Mark the fast FCF failover rediscovery completed - * and the start of the first round of the roundrobin - * FCF failover. - */ - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_REDISC_FOV; - spin_unlock_irq(&phba->hbalock); - /* Register to the new FCF record */ - lpfc_register_fcf(phba); - } else { - /* - * In case of transaction period to fast FCF failover, - * do nothing when search to the end of the FCF table. - */ - if ((phba->fcf.fcf_flag & FCF_REDISC_EVT) || - (phba->fcf.fcf_flag & FCF_REDISC_PEND)) - return; - - if (phba->cfg_fcf_failover_policy == LPFC_FCF_FOV && - phba->fcf.fcf_flag & FCF_IN_USE) { - /* - * In case the current in-use FCF record no - * longer existed during FCF discovery that - * was not triggered by fast FCF failover - * process, treat it as fast FCF failover. - */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2841 In-use FCF record (x%x) " - "not reported, entering fast " - "FCF failover mode scanning.\n", - phba->fcf.current_rec.fcf_indx); - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag |= FCF_REDISC_FOV; - spin_unlock_irq(&phba->hbalock); - lpfc_sli4_fcf_scan_read_fcf_rec(phba, - LPFC_FCOE_FCF_GET_FIRST); - return; - } - /* Register to the new FCF record */ - lpfc_register_fcf(phba); - } - } else - lpfc_sli4_fcf_scan_read_fcf_rec(phba, next_fcf_index); - return; - -out: - lpfc_sli4_mbox_cmd_free(phba, mboxq); - lpfc_register_fcf(phba); - - return; -} - -/** - * lpfc_mbx_cmpl_fcf_rr_read_fcf_rec - fcf roundrobin read_fcf mbox cmpl hdler - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to mailbox object. - * - * This is the callback function for FLOGI failure roundrobin FCF failover - * read FCF record mailbox command from the eligible FCF record bmask for - * performing the failover. If the FCF read back is not valid/available, it - * fails through to retrying FLOGI to the currently registered FCF again. - * Otherwise, if the FCF read back is valid and available, it will set the - * newly read FCF record to the failover FCF record, unregister currently - * registered FCF record, copy the failover FCF record to the current - * FCF record, and then register the current FCF record before proceeding - * to trying FLOGI on the new failover FCF. - */ -void -lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct fcf_record *new_fcf_record; - uint32_t boot_flag, addr_mode; - uint16_t next_fcf_index, fcf_index; - uint16_t current_fcf_index; - uint16_t vlan_id; - int rc; - - /* If link state is not up, stop the roundrobin failover process */ - if (phba->link_state < LPFC_LINK_UP) { - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_DISCOVERY; - phba->hba_flag &= ~FCF_RR_INPROG; - spin_unlock_irq(&phba->hbalock); - goto out; - } - - /* Parse the FCF record from the non-embedded mailbox command */ - new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq, - &next_fcf_index); - if (!new_fcf_record) { - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2766 Mailbox command READ_FCF_RECORD " - "failed to retrieve a FCF record.\n"); - goto error_out; - } - - /* Get the needed parameters from FCF record */ - rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag, - &addr_mode, &vlan_id); - - /* Log the FCF record information if turned on */ - lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id, - next_fcf_index); - - fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); - if (!rc) { - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2848 Remove ineligible FCF (x%x) from " - "from roundrobin bmask\n", fcf_index); - /* Clear roundrobin bmask bit for ineligible FCF */ - lpfc_sli4_fcf_rr_index_clear(phba, fcf_index); - /* Perform next round of roundrobin FCF failover */ - fcf_index = lpfc_sli4_fcf_rr_next_index_get(phba); - rc = lpfc_sli4_fcf_rr_next_proc(phba->pport, fcf_index); - if (rc) - goto out; - goto error_out; - } - - if (fcf_index == phba->fcf.current_rec.fcf_indx) { - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2760 Perform FLOGI roundrobin FCF failover: " - "FCF (x%x) back to FCF (x%x)\n", - phba->fcf.current_rec.fcf_indx, fcf_index); - /* Wait 500 ms before retrying FLOGI to current FCF */ - msleep(500); - lpfc_issue_init_vfi(phba->pport); - goto out; - } - - /* Upload new FCF record to the failover FCF record */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2834 Update current FCF (x%x) with new FCF (x%x)\n", - phba->fcf.failover_rec.fcf_indx, fcf_index); - spin_lock_irq(&phba->hbalock); - __lpfc_update_fcf_record(phba, &phba->fcf.failover_rec, - new_fcf_record, addr_mode, vlan_id, - (boot_flag ? BOOT_ENABLE : 0)); - spin_unlock_irq(&phba->hbalock); - - current_fcf_index = phba->fcf.current_rec.fcf_indx; - - /* Unregister the current in-use FCF record */ - lpfc_unregister_fcf(phba); - - /* Replace in-use record with the new record */ - memcpy(&phba->fcf.current_rec, &phba->fcf.failover_rec, - sizeof(struct lpfc_fcf_rec)); - - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2783 Perform FLOGI roundrobin FCF failover: FCF " - "(x%x) to FCF (x%x)\n", current_fcf_index, fcf_index); - -error_out: - lpfc_register_fcf(phba); -out: - lpfc_sli4_mbox_cmd_free(phba, mboxq); -} - -/** - * lpfc_mbx_cmpl_read_fcf_rec - read fcf completion handler. - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to mailbox object. - * - * This is the callback function of read FCF record mailbox command for - * updating the eligible FCF bmask for FLOGI failure roundrobin FCF - * failover when a new FCF event happened. If the FCF read back is - * valid/available and it passes the connection list check, it updates - * the bmask for the eligible FCF record for roundrobin failover. - */ -void -lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct fcf_record *new_fcf_record; - uint32_t boot_flag, addr_mode; - uint16_t fcf_index, next_fcf_index; - uint16_t vlan_id; - int rc; - - /* If link state is not up, no need to proceed */ - if (phba->link_state < LPFC_LINK_UP) - goto out; - - /* If FCF discovery period is over, no need to proceed */ - if (!(phba->fcf.fcf_flag & FCF_DISCOVERY)) - goto out; - - /* Parse the FCF record from the non-embedded mailbox command */ - new_fcf_record = lpfc_sli4_fcf_rec_mbox_parse(phba, mboxq, - &next_fcf_index); - if (!new_fcf_record) { - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2767 Mailbox command READ_FCF_RECORD " - "failed to retrieve a FCF record.\n"); - goto out; - } - - /* Check the connection list for eligibility */ - rc = lpfc_match_fcf_conn_list(phba, new_fcf_record, &boot_flag, - &addr_mode, &vlan_id); - - /* Log the FCF record information if turned on */ - lpfc_sli4_log_fcf_record_info(phba, new_fcf_record, vlan_id, - next_fcf_index); - - if (!rc) - goto out; - - /* Update the eligible FCF record index bmask */ - fcf_index = bf_get(lpfc_fcf_record_fcf_index, new_fcf_record); - - rc = lpfc_sli4_fcf_pri_list_add(phba, fcf_index, new_fcf_record); - -out: - lpfc_sli4_mbox_cmd_free(phba, mboxq); -} - -/** - * lpfc_init_vfi_cmpl - Completion handler for init_vfi mbox command. - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to mailbox data structure. - * - * This function handles completion of init vfi mailbox command. - */ -void -lpfc_init_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct lpfc_vport *vport = mboxq->vport; - - /* - * VFI not supported on interface type 0, just do the flogi - * Also continue if the VFI is in use - just use the same one. - */ - if (mboxq->u.mb.mbxStatus && - (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_0) && - mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, - "2891 Init VFI mailbox failed 0x%x\n", - mboxq->u.mb.mbxStatus); - mempool_free(mboxq, phba->mbox_mem_pool); - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - return; - } - - lpfc_initial_flogi(vport); - mempool_free(mboxq, phba->mbox_mem_pool); - return; -} - -/** - * lpfc_issue_init_vfi - Issue init_vfi mailbox command. - * @vport: pointer to lpfc_vport data structure. - * - * This function issue a init_vfi mailbox command to initialize the VFI and - * VPI for the physical port. - */ -void -lpfc_issue_init_vfi(struct lpfc_vport *vport) -{ - LPFC_MBOXQ_t *mboxq; - int rc; - struct lpfc_hba *phba = vport->phba; - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2892 Failed to allocate " - "init_vfi mailbox\n"); - return; - } - lpfc_init_vfi(mboxq, vport); - mboxq->mbox_cmpl = lpfc_init_vfi_cmpl; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2893 Failed to issue init_vfi mailbox\n"); - mempool_free(mboxq, vport->phba->mbox_mem_pool); - } -} - -/** - * lpfc_init_vpi_cmpl - Completion handler for init_vpi mbox command. - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to mailbox data structure. - * - * This function handles completion of init vpi mailbox command. - */ -void -lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct lpfc_vport *vport = mboxq->vport; - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (mboxq->u.mb.mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, - "2609 Init VPI mailbox failed 0x%x\n", - mboxq->u.mb.mbxStatus); - mempool_free(mboxq, phba->mbox_mem_pool); - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - return; - } - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); - - /* If this port is physical port or FDISC is done, do reg_vpi */ - if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) { - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) - lpfc_printf_vlog(vport, KERN_ERR, - LOG_DISCOVERY, - "2731 Cannot find fabric " - "controller node\n"); - else - lpfc_register_new_vport(phba, vport, ndlp); - mempool_free(mboxq, phba->mbox_mem_pool); - return; - } - - if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) - lpfc_initial_fdisc(vport); - else { - lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "2606 No NPIV Fabric support\n"); - } - mempool_free(mboxq, phba->mbox_mem_pool); - return; -} - -/** - * lpfc_issue_init_vpi - Issue init_vpi mailbox command. - * @vport: pointer to lpfc_vport data structure. - * - * This function issue a init_vpi mailbox command to initialize - * VPI for the vport. - */ -void -lpfc_issue_init_vpi(struct lpfc_vport *vport) -{ - LPFC_MBOXQ_t *mboxq; - int rc; - - mboxq = mempool_alloc(vport->phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2607 Failed to allocate " - "init_vpi mailbox\n"); - return; - } - lpfc_init_vpi(vport->phba, mboxq, vport->vpi); - mboxq->vport = vport; - mboxq->mbox_cmpl = lpfc_init_vpi_cmpl; - rc = lpfc_sli_issue_mbox(vport->phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, - LOG_MBOX, "2608 Failed to issue init_vpi mailbox\n"); - mempool_free(mboxq, vport->phba->mbox_mem_pool); - } -} - -/** - * lpfc_start_fdiscs - send fdiscs for each vports on this port. - * @phba: pointer to lpfc hba data structure. - * - * This function loops through the list of vports on the @phba and issues an - * FDISC if possible. - */ -void -lpfc_start_fdiscs(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - int i; - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) { - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - if (vports[i]->port_type == LPFC_PHYSICAL_PORT) - continue; - /* There are no vpi for this vport */ - if (vports[i]->vpi > phba->max_vpi) { - lpfc_vport_set_state(vports[i], - FC_VPORT_FAILED); - continue; - } - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - lpfc_vport_set_state(vports[i], - FC_VPORT_LINKDOWN); - continue; - } - if (vports[i]->fc_flag & FC_VPORT_NEEDS_INIT_VPI) { - lpfc_issue_init_vpi(vports[i]); - continue; - } - if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) - lpfc_initial_fdisc(vports[i]); - else { - lpfc_vport_set_state(vports[i], - FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vports[i], KERN_ERR, - LOG_ELS, - "0259 No NPIV " - "Fabric support\n"); - } - } - } - lpfc_destroy_vport_work_array(phba, vports); -} - -void -lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct lpfc_dmabuf *dmabuf = mboxq->context1; - struct lpfc_vport *vport = mboxq->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - /* - * VFI not supported for interface type 0, so ignore any mailbox - * error (except VFI in use) and continue with the discovery. - */ - if (mboxq->u.mb.mbxStatus && - (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_0) && - mboxq->u.mb.mbxStatus != MBX_VFI_IN_USE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2018 REG_VFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - /* FLOGI failed, use loop map to make discovery list */ - lpfc_disc_list_loopmap(vport); - /* Start discovery */ - lpfc_disc_start(vport); - goto out_free_mem; - } - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - goto out_free_mem; - } - /* The VPI is implicitly registered when the VFI is registered */ - spin_lock_irq(shost->host_lock); - vport->vpi_state |= LPFC_VPI_REGISTERED; - vport->fc_flag |= FC_VFI_REGISTERED; - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); - - /* In case SLI4 FC loopback test, we are ready */ - if ((phba->sli_rev == LPFC_SLI_REV4) && - (phba->link_flag & LS_LOOPBACK_MODE)) { - phba->link_state = LPFC_HBA_READY; - goto out_free_mem; - } - - if (vport->port_state == LPFC_FABRIC_CFG_LINK) { - /* For private loop just start discovery and we are done. */ - if ((phba->fc_topology == LPFC_TOPOLOGY_LOOP) && - !(vport->fc_flag & FC_PUBLIC_LOOP)) { - /* Use loop map to make discovery list */ - lpfc_disc_list_loopmap(vport); - /* Start discovery */ - lpfc_disc_start(vport); - } else { - lpfc_start_fdiscs(phba); - lpfc_do_scr_ns_plogi(phba, vport); - } - } - -out_free_mem: - mempool_free(mboxq, phba->mbox_mem_pool); - lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - return; -} - -static void -lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; - struct lpfc_vport *vport = pmb->vport; - - - /* Check for error */ - if (mb->mbxStatus) { - /* READ_SPARAM mbox error state */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0319 READ_SPARAM mbxStatus error x%x " - "hba state x%x>\n", - mb->mbxStatus, vport->port_state); - lpfc_linkdown(phba); - goto out; - } - - memcpy((uint8_t *) &vport->fc_sparam, (uint8_t *) mp->virt, - sizeof (struct serv_parm)); - lpfc_update_vport_wwn(vport); - if (vport->port_type == LPFC_PHYSICAL_PORT) { - memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn)); - memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn)); - } - - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - return; - -out: - pmb->context1 = NULL; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - lpfc_issue_clear_la(phba, vport); - mempool_free(pmb, phba->mbox_mem_pool); - return; -} - -static void -lpfc_mbx_process_link_up(struct lpfc_hba *phba, struct lpfc_mbx_read_top *la) -{ - struct lpfc_vport *vport = phba->pport; - LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox = NULL; - struct Scsi_Host *shost; - int i; - struct lpfc_dmabuf *mp; - int rc; - struct fcf_record *fcf_record; - - spin_lock_irq(&phba->hbalock); - switch (bf_get(lpfc_mbx_read_top_link_spd, la)) { - case LPFC_LINK_SPEED_1GHZ: - case LPFC_LINK_SPEED_2GHZ: - case LPFC_LINK_SPEED_4GHZ: - case LPFC_LINK_SPEED_8GHZ: - case LPFC_LINK_SPEED_10GHZ: - case LPFC_LINK_SPEED_16GHZ: - phba->fc_linkspeed = bf_get(lpfc_mbx_read_top_link_spd, la); - break; - default: - phba->fc_linkspeed = LPFC_LINK_SPEED_UNKNOWN; - break; - } - - phba->fc_topology = bf_get(lpfc_mbx_read_top_topology, la); - phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; - - shost = lpfc_shost_from_vport(vport); - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; - - /* if npiv is enabled and this adapter supports npiv log - * a message that npiv is not supported in this topology - */ - if (phba->cfg_enable_npiv && phba->max_vpi) - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1309 Link Up Event npiv not supported in loop " - "topology\n"); - /* Get Loop Map information */ - if (bf_get(lpfc_mbx_read_top_il, la)) { - spin_lock(shost->host_lock); - vport->fc_flag |= FC_LBIT; - spin_unlock(shost->host_lock); - } - - vport->fc_myDID = bf_get(lpfc_mbx_read_top_alpa_granted, la); - i = la->lilpBde64.tus.f.bdeSize; - - if (i == 0) { - phba->alpa_map[0] = 0; - } else { - if (vport->cfg_log_verbose & LOG_LINK_EVENT) { - int numalpa, j, k; - union { - uint8_t pamap[16]; - struct { - uint32_t wd1; - uint32_t wd2; - uint32_t wd3; - uint32_t wd4; - } pa; - } un; - numalpa = phba->alpa_map[0]; - j = 0; - while (j < numalpa) { - memset(un.pamap, 0, 16); - for (k = 1; j < numalpa; k++) { - un.pamap[k - 1] = - phba->alpa_map[j + 1]; - j++; - if (k == 16) - break; - } - /* Link Up Event ALPA map */ - lpfc_printf_log(phba, - KERN_WARNING, - LOG_LINK_EVENT, - "1304 Link Up Event " - "ALPA map Data: x%x " - "x%x x%x x%x\n", - un.pa.wd1, un.pa.wd2, - un.pa.wd3, un.pa.wd4); - } - } - } - } else { - if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { - if (phba->max_vpi && phba->cfg_enable_npiv && - (phba->sli_rev >= LPFC_SLI_REV3)) - phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; - } - vport->fc_myDID = phba->fc_pref_DID; - spin_lock(shost->host_lock); - vport->fc_flag |= FC_LBIT; - spin_unlock(shost->host_lock); - } - spin_unlock_irq(&phba->hbalock); - - lpfc_linkup(phba); - sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!sparam_mbox) - goto out; - - rc = lpfc_read_sparam(phba, sparam_mbox, 0); - if (rc) { - mempool_free(sparam_mbox, phba->mbox_mem_pool); - goto out; - } - sparam_mbox->vport = vport; - sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; - rc = lpfc_sli_issue_mbox(phba, sparam_mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mp = (struct lpfc_dmabuf *) sparam_mbox->context1; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(sparam_mbox, phba->mbox_mem_pool); - goto out; - } - - if (!(phba->hba_flag & HBA_FCOE_MODE)) { - cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!cfglink_mbox) - goto out; - vport->port_state = LPFC_LOCAL_CFG_LINK; - lpfc_config_link(phba, cfglink_mbox); - cfglink_mbox->vport = vport; - cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; - rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(cfglink_mbox, phba->mbox_mem_pool); - goto out; - } - } else { - vport->port_state = LPFC_VPORT_UNKNOWN; - /* - * Add the driver's default FCF record at FCF index 0 now. This - * is phase 1 implementation that support FCF index 0 and driver - * defaults. - */ - if (!(phba->hba_flag & HBA_FIP_SUPPORT)) { - fcf_record = kzalloc(sizeof(struct fcf_record), - GFP_KERNEL); - if (unlikely(!fcf_record)) { - lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, - "2554 Could not allocate memory for " - "fcf record\n"); - rc = -ENODEV; - goto out; - } - - lpfc_sli4_build_dflt_fcf_record(phba, fcf_record, - LPFC_FCOE_FCF_DEF_INDEX); - rc = lpfc_sli4_add_fcf_record(phba, fcf_record); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, - "2013 Could not manually add FCF " - "record 0, status %d\n", rc); - rc = -ENODEV; - kfree(fcf_record); - goto out; - } - kfree(fcf_record); - } - /* - * The driver is expected to do FIP/FCF. Call the port - * and get the FCF Table. - */ - spin_lock_irq(&phba->hbalock); - if (phba->hba_flag & FCF_TS_INPROG) { - spin_unlock_irq(&phba->hbalock); - return; - } - /* This is the initial FCF discovery scan */ - phba->fcf.fcf_flag |= FCF_INIT_DISC; - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, - "2778 Start FCF table scan at linkup\n"); - rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, - LPFC_FCOE_FCF_GET_FIRST); - if (rc) { - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_INIT_DISC; - spin_unlock_irq(&phba->hbalock); - goto out; - } - /* Reset FCF roundrobin bmask for new discovery */ - lpfc_sli4_clear_fcf_rr_bmask(phba); - } - - return; -out: - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0263 Discovery Mailbox error: state: 0x%x : %p %p\n", - vport->port_state, sparam_mbox, cfglink_mbox); - lpfc_issue_clear_la(phba, vport); - return; -} - -static void -lpfc_enable_la(struct lpfc_hba *phba) -{ - uint32_t control; - struct lpfc_sli *psli = &phba->sli; - spin_lock_irq(&phba->hbalock); - psli->sli_flag |= LPFC_PROCESS_LA; - if (phba->sli_rev <= LPFC_SLI_REV3) { - control = readl(phba->HCregaddr); - control |= HC_LAINT_ENA; - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - spin_unlock_irq(&phba->hbalock); -} - -static void -lpfc_mbx_issue_link_down(struct lpfc_hba *phba) -{ - lpfc_linkdown(phba); - lpfc_enable_la(phba); - lpfc_unregister_unused_fcf(phba); - /* turn on Link Attention interrupts - no CLEAR_LA needed */ -} - - -/* - * This routine handles processing a READ_TOPOLOGY mailbox - * command upon completion. It is setup in the LPFC_MBOXQ - * as the completion routine when the command is - * handed off to the SLI layer. - */ -void -lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_mbx_read_top *la; - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); - - /* Unblock ELS traffic */ - phba->sli.ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT; - /* Check for error */ - if (mb->mbxStatus) { - lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, - "1307 READ_LA mbox error x%x state x%x\n", - mb->mbxStatus, vport->port_state); - lpfc_mbx_issue_link_down(phba); - phba->link_state = LPFC_HBA_ERROR; - goto lpfc_mbx_cmpl_read_topology_free_mbuf; - } - - la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop; - - memcpy(&phba->alpa_map[0], mp->virt, 128); - - spin_lock_irq(shost->host_lock); - if (bf_get(lpfc_mbx_read_top_pb, la)) - vport->fc_flag |= FC_BYPASSED_MODE; - else - vport->fc_flag &= ~FC_BYPASSED_MODE; - spin_unlock_irq(shost->host_lock); - - if ((phba->fc_eventTag < la->eventTag) || - (phba->fc_eventTag == la->eventTag)) { - phba->fc_stat.LinkMultiEvent++; - if (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP) - if (phba->fc_eventTag != 0) - lpfc_linkdown(phba); - } - - phba->fc_eventTag = la->eventTag; - spin_lock_irq(&phba->hbalock); - if (bf_get(lpfc_mbx_read_top_mm, la)) - phba->sli.sli_flag |= LPFC_MENLO_MAINT; - else - phba->sli.sli_flag &= ~LPFC_MENLO_MAINT; - spin_unlock_irq(&phba->hbalock); - - phba->link_events++; - if ((bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP) && - (!bf_get(lpfc_mbx_read_top_mm, la))) { - phba->fc_stat.LinkUp++; - if (phba->link_flag & LS_LOOPBACK_MODE) { - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1306 Link Up Event in loop back mode " - "x%x received Data: x%x x%x x%x x%x\n", - la->eventTag, phba->fc_eventTag, - bf_get(lpfc_mbx_read_top_alpa_granted, - la), - bf_get(lpfc_mbx_read_top_link_spd, la), - phba->alpa_map[0]); - } else { - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1303 Link Up Event x%x received " - "Data: x%x x%x x%x x%x x%x x%x %d\n", - la->eventTag, phba->fc_eventTag, - bf_get(lpfc_mbx_read_top_alpa_granted, - la), - bf_get(lpfc_mbx_read_top_link_spd, la), - phba->alpa_map[0], - bf_get(lpfc_mbx_read_top_mm, la), - bf_get(lpfc_mbx_read_top_fa, la), - phba->wait_4_mlo_maint_flg); - } - lpfc_mbx_process_link_up(phba, la); - } else if (bf_get(lpfc_mbx_read_top_att_type, la) == - LPFC_ATT_LINK_DOWN) { - phba->fc_stat.LinkDown++; - if (phba->link_flag & LS_LOOPBACK_MODE) - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1308 Link Down Event in loop back mode " - "x%x received " - "Data: x%x x%x x%x\n", - la->eventTag, phba->fc_eventTag, - phba->pport->port_state, vport->fc_flag); - else - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1305 Link Down Event x%x received " - "Data: x%x x%x x%x x%x x%x\n", - la->eventTag, phba->fc_eventTag, - phba->pport->port_state, vport->fc_flag, - bf_get(lpfc_mbx_read_top_mm, la), - bf_get(lpfc_mbx_read_top_fa, la)); - lpfc_mbx_issue_link_down(phba); - } - if ((bf_get(lpfc_mbx_read_top_mm, la)) && - (bf_get(lpfc_mbx_read_top_att_type, la) == LPFC_ATT_LINK_UP)) { - if (phba->link_state != LPFC_LINK_DOWN) { - phba->fc_stat.LinkDown++; - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1312 Link Down Event x%x received " - "Data: x%x x%x x%x\n", - la->eventTag, phba->fc_eventTag, - phba->pport->port_state, vport->fc_flag); - lpfc_mbx_issue_link_down(phba); - } else - lpfc_enable_la(phba); - - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1310 Menlo Maint Mode Link up Event x%x rcvd " - "Data: x%x x%x x%x\n", - la->eventTag, phba->fc_eventTag, - phba->pport->port_state, vport->fc_flag); - /* - * The cmnd that triggered this will be waiting for this - * signal. - */ - /* WAKEUP for MENLO_SET_MODE or MENLO_RESET command. */ - if (phba->wait_4_mlo_maint_flg) { - phba->wait_4_mlo_maint_flg = 0; - wake_up_interruptible(&phba->wait_4_mlo_m_q); - } - } - - if (bf_get(lpfc_mbx_read_top_fa, la)) { - if (bf_get(lpfc_mbx_read_top_mm, la)) - lpfc_issue_clear_la(phba, vport); - lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, - "1311 fa %d\n", - bf_get(lpfc_mbx_read_top_fa, la)); - } - -lpfc_mbx_cmpl_read_topology_free_mbuf: - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - return; -} - -/* - * This routine handles processing a REG_LOGIN mailbox - * command upon completion. It is setup in the LPFC_MBOXQ - * as the completion routine when the command is - * handed off to the SLI layer. - */ -void -lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - pmb->context1 = NULL; - pmb->context2 = NULL; - - if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; - - if (ndlp->nlp_flag & NLP_IGNR_REG_CMPL || - ndlp->nlp_state != NLP_STE_REG_LOGIN_ISSUE) { - /* We rcvd a rscn after issuing this - * mbox reg login, we may have cycled - * back through the state and be - * back at reg login state so this - * mbox needs to be ignored becase - * there is another reg login in - * process. - */ - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock_irq(shost->host_lock); - } else - /* Good status, call state machine */ - lpfc_disc_state_machine(vport, ndlp, pmb, - NLP_EVT_CMPL_REG_LOGIN); - - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - /* decrement the node reference count held for this callback - * function. - */ - lpfc_nlp_put(ndlp); - - return; -} - -static void -lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_vport *vport = pmb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - switch (mb->mbxStatus) { - case 0x0011: - case 0x0020: - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0911 cmpl_unreg_vpi, mb status = 0x%x\n", - mb->mbxStatus); - break; - /* If VPI is busy, reset the HBA */ - case 0x9700: - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "2798 Unreg_vpi failed vpi 0x%x, mb status = 0x%x\n", - vport->vpi, mb->mbxStatus); - if (!(phba->pport->load_flag & FC_UNLOADING)) - lpfc_workq_post_event(phba, NULL, NULL, - LPFC_EVT_RESET_HBA); - } - spin_lock_irq(shost->host_lock); - vport->vpi_state &= ~LPFC_VPI_REGISTERED; - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - vport->unreg_vpi_cmpl = VPORT_OK; - mempool_free(pmb, phba->mbox_mem_pool); - lpfc_cleanup_vports_rrqs(vport, NULL); - /* - * This shost reference might have been taken at the beginning of - * lpfc_vport_delete() - */ - if ((vport->load_flag & FC_UNLOADING) && (vport != phba->pport)) - scsi_host_put(shost); -} - -int -lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; - int rc; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return 1; - - lpfc_unreg_vpi(phba, vport->vpi, mbox); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, - "1800 Could not issue unreg_vpi\n"); - mempool_free(mbox, phba->mbox_mem_pool); - vport->unreg_vpi_cmpl = VPORT_ERROR; - return rc; - } - return 0; -} - -static void -lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - MAILBOX_t *mb = &pmb->u.mb; - - switch (mb->mbxStatus) { - case 0x0011: - case 0x9601: - case 0x9602: - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0912 cmpl_reg_vpi, mb status = 0x%x\n", - mb->mbxStatus); - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); - vport->fc_myDID = 0; - goto out; - } - - spin_lock_irq(shost->host_lock); - vport->vpi_state |= LPFC_VPI_REGISTERED; - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - vport->num_disc_nodes = 0; - /* go thru NPR list and issue ELS PLOGIs */ - if (vport->fc_npr_cnt) - lpfc_els_disc_plogi(vport); - - if (!vport->num_disc_nodes) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - } - vport->port_state = LPFC_VPORT_READY; - -out: - mempool_free(pmb, phba->mbox_mem_pool); - return; -} - -/** - * lpfc_create_static_vport - Read HBA config region to create static vports. - * @phba: pointer to lpfc hba data structure. - * - * This routine issue a DUMP mailbox command for config region 22 to get - * the list of static vports to be created. The function create vports - * based on the information returned from the HBA. - **/ -void -lpfc_create_static_vport(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *pmb = NULL; - MAILBOX_t *mb; - struct static_vport_info *vport_info; - int rc = 0, i; - struct fc_vport_identifiers vport_id; - struct fc_vport *new_fc_vport; - struct Scsi_Host *shost; - struct lpfc_vport *vport; - uint16_t offset = 0; - uint8_t *vport_buff; - struct lpfc_dmabuf *mp; - uint32_t byte_count = 0; - - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0542 lpfc_create_static_vport failed to" - " allocate mailbox memory\n"); - return; - } - - mb = &pmb->u.mb; - - vport_info = kzalloc(sizeof(struct static_vport_info), GFP_KERNEL); - if (!vport_info) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0543 lpfc_create_static_vport failed to" - " allocate vport_info\n"); - mempool_free(pmb, phba->mbox_mem_pool); - return; - } - - vport_buff = (uint8_t *) vport_info; - do { - if (lpfc_dump_static_vport(phba, pmb, offset)) - goto out; - - pmb->vport = phba->pport; - rc = lpfc_sli_issue_mbox_wait(phba, pmb, LPFC_MBOX_TMO); - - if ((rc != MBX_SUCCESS) || mb->mbxStatus) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0544 lpfc_create_static_vport failed to" - " issue dump mailbox command ret 0x%x " - "status 0x%x\n", - rc, mb->mbxStatus); - goto out; - } - - if (phba->sli_rev == LPFC_SLI_REV4) { - byte_count = pmb->u.mqe.un.mb_words[5]; - mp = (struct lpfc_dmabuf *) pmb->context2; - if (byte_count > sizeof(struct static_vport_info) - - offset) - byte_count = sizeof(struct static_vport_info) - - offset; - memcpy(vport_buff + offset, mp->virt, byte_count); - offset += byte_count; - } else { - if (mb->un.varDmp.word_cnt > - sizeof(struct static_vport_info) - offset) - mb->un.varDmp.word_cnt = - sizeof(struct static_vport_info) - - offset; - byte_count = mb->un.varDmp.word_cnt; - lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - vport_buff + offset, - byte_count); - - offset += byte_count; - } - - } while (byte_count && - offset < sizeof(struct static_vport_info)); - - - if ((le32_to_cpu(vport_info->signature) != VPORT_INFO_SIG) || - ((le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK) - != VPORT_INFO_REV)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0545 lpfc_create_static_vport bad" - " information header 0x%x 0x%x\n", - le32_to_cpu(vport_info->signature), - le32_to_cpu(vport_info->rev) & VPORT_INFO_REV_MASK); - - goto out; - } - - shost = lpfc_shost_from_vport(phba->pport); - - for (i = 0; i < MAX_STATIC_VPORT_COUNT; i++) { - memset(&vport_id, 0, sizeof(vport_id)); - vport_id.port_name = wwn_to_u64(vport_info->vport_list[i].wwpn); - vport_id.node_name = wwn_to_u64(vport_info->vport_list[i].wwnn); - if (!vport_id.port_name || !vport_id.node_name) - continue; - - vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR; - vport_id.vport_type = FC_PORTTYPE_NPIV; - vport_id.disable = false; - new_fc_vport = fc_vport_create(shost, 0, &vport_id); - - if (!new_fc_vport) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0546 lpfc_create_static_vport failed to" - " create vport\n"); - continue; - } - - vport = *(struct lpfc_vport **)new_fc_vport->dd_data; - vport->vport_flag |= STATIC_VPORT; - } - -out: - kfree(vport_info); - if (rc != MBX_TIMEOUT) { - if (pmb->context2) { - mp = (struct lpfc_dmabuf *) pmb->context2; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mempool_free(pmb, phba->mbox_mem_pool); - } - - return; -} - -/* - * This routine handles processing a Fabric REG_LOGIN mailbox - * command upon completion. It is setup in the LPFC_MBOXQ - * as the completion routine when the command is - * handed off to the SLI layer. - */ -void -lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; - - ndlp = (struct lpfc_nodelist *) pmb->context2; - pmb->context1 = NULL; - pmb->context2 = NULL; - - if (mb->mbxStatus) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "0258 Register Fabric login error: 0x%x\n", - mb->mbxStatus); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - /* FLOGI failed, use loop map to make discovery list */ - lpfc_disc_list_loopmap(vport); - - /* Start discovery */ - lpfc_disc_start(vport); - /* Decrement the reference count to ndlp after the - * reference to the ndlp are done. - */ - lpfc_nlp_put(ndlp); - return; - } - - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - /* Decrement the reference count to ndlp after the reference - * to the ndlp are done. - */ - lpfc_nlp_put(ndlp); - return; - } - - if (phba->sli_rev < LPFC_SLI_REV4) - ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; - ndlp->nlp_type |= NLP_FABRIC; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - - if (vport->port_state == LPFC_FABRIC_CFG_LINK) { - /* when physical port receive logo donot start - * vport discovery */ - if (!(vport->fc_flag & FC_LOGO_RCVD_DID_CHNG)) - lpfc_start_fdiscs(phba); - else { - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG ; - spin_unlock_irq(shost->host_lock); - } - lpfc_do_scr_ns_plogi(phba, vport); - } - - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - - /* Drop the reference count from the mbox at the end after - * all the current reference to the ndlp have been done. - */ - lpfc_nlp_put(ndlp); - return; -} - -/* - * This routine handles processing a NameServer REG_LOGIN mailbox - * command upon completion. It is setup in the LPFC_MBOXQ - * as the completion routine when the command is - * handed off to the SLI layer. - */ -void -lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; - struct lpfc_vport *vport = pmb->vport; - - pmb->context1 = NULL; - pmb->context2 = NULL; - - if (mb->mbxStatus) { -out: - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0260 Register NameServer error: 0x%x\n", - mb->mbxStatus); - /* decrement the node reference count held for this - * callback function. - */ - lpfc_nlp_put(ndlp); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - - /* If no other thread is using the ndlp, free it */ - lpfc_nlp_not_used(ndlp); - - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - /* - * RegLogin failed, use loop map to make discovery - * list - */ - lpfc_disc_list_loopmap(vport); - - /* Start discovery */ - lpfc_disc_start(vport); - return; - } - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - return; - } - - if (phba->sli_rev < LPFC_SLI_REV4) - ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; - ndlp->nlp_type |= NLP_FABRIC; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - - if (vport->port_state < LPFC_VPORT_READY) { - /* Link up discovery requires Fabric registration. */ - lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, 0); /* Do this first! */ - lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0); - lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0); - lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); - lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0); - - /* Issue SCR just before NameServer GID_FT Query */ - lpfc_issue_els_scr(vport, SCR_DID, 0); - } - - vport->fc_ns_retry = 0; - /* Good status, issue CT Request to NameServer */ - if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0)) { - /* Cannot issue NameServer Query, so finish up discovery */ - goto out; - } - - /* decrement the node reference count held for this - * callback function. - */ - lpfc_nlp_put(ndlp); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - - return; -} - -static void -lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct fc_rport *rport; - struct lpfc_rport_data *rdata; - struct fc_rport_identifiers rport_ids; - struct lpfc_hba *phba = vport->phba; - - /* Remote port has reappeared. Re-register w/ FC transport */ - rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn); - rport_ids.port_name = wwn_to_u64(ndlp->nlp_portname.u.wwn); - rport_ids.port_id = ndlp->nlp_DID; - rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; - - /* - * We leave our node pointer in rport->dd_data when we unregister a - * FCP target port. But fc_remote_port_add zeros the space to which - * rport->dd_data points. So, if we're reusing a previously - * registered port, drop the reference that we took the last time we - * registered the port. - */ - if (ndlp->rport && ndlp->rport->dd_data && - ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) - lpfc_nlp_put(ndlp); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport add: did:x%x flg:x%x type x%x", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); - - /* Don't add the remote port if unloading. */ - if (vport->load_flag & FC_UNLOADING) - return; - - ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); - if (!rport || !get_device(&rport->dev)) { - dev_printk(KERN_WARNING, &phba->pcidev->dev, - "Warning: fc_remote_port_add failed\n"); - return; - } - - /* initialize static port data */ - rport->maxframe_size = ndlp->nlp_maxframe; - rport->supported_classes = ndlp->nlp_class_sup; - rdata = rport->dd_data; - rdata->pnode = lpfc_nlp_get(ndlp); - - if (ndlp->nlp_type & NLP_FCP_TARGET) - rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; - if (ndlp->nlp_type & NLP_FCP_INITIATOR) - rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; - - if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) - fc_remote_port_rolechg(rport, rport_ids.roles); - - if ((rport->scsi_target_id != -1) && - (rport->scsi_target_id < LPFC_MAX_TARGET)) { - ndlp->nlp_sid = rport->scsi_target_id; - } - return; -} - -static void -lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) -{ - struct fc_rport *rport = ndlp->rport; - - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT, - "rport delete: did:x%x flg:x%x type x%x", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); - - fc_remote_port_delete(rport); - - return; -} - -static void -lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - spin_lock_irq(shost->host_lock); - switch (state) { - case NLP_STE_UNUSED_NODE: - vport->fc_unused_cnt += count; - break; - case NLP_STE_PLOGI_ISSUE: - vport->fc_plogi_cnt += count; - break; - case NLP_STE_ADISC_ISSUE: - vport->fc_adisc_cnt += count; - break; - case NLP_STE_REG_LOGIN_ISSUE: - vport->fc_reglogin_cnt += count; - break; - case NLP_STE_PRLI_ISSUE: - vport->fc_prli_cnt += count; - break; - case NLP_STE_UNMAPPED_NODE: - vport->fc_unmap_cnt += count; - break; - case NLP_STE_MAPPED_NODE: - vport->fc_map_cnt += count; - break; - case NLP_STE_NPR_NODE: - vport->fc_npr_cnt += count; - break; - } - spin_unlock_irq(shost->host_lock); -} - -static void -lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - int old_state, int new_state) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (new_state == NLP_STE_UNMAPPED_NODE) { - ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; - ndlp->nlp_type |= NLP_FC_NODE; - } - if (new_state == NLP_STE_MAPPED_NODE) - ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; - if (new_state == NLP_STE_NPR_NODE) - ndlp->nlp_flag &= ~NLP_RCV_PLOGI; - - /* Transport interface */ - if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE || - old_state == NLP_STE_UNMAPPED_NODE)) { - vport->phba->nport_event_cnt++; - lpfc_unregister_remote_port(ndlp); - } - - if (new_state == NLP_STE_MAPPED_NODE || - new_state == NLP_STE_UNMAPPED_NODE) { - vport->phba->nport_event_cnt++; - /* - * Tell the fc transport about the port, if we haven't - * already. If we have, and it's a scsi entity, be - * sure to unblock any attached scsi devices - */ - lpfc_register_remote_port(vport, ndlp); - } - if ((new_state == NLP_STE_MAPPED_NODE) && - (vport->stat_data_enabled)) { - /* - * A new target is discovered, if there is no buffer for - * statistical data collection allocate buffer. - */ - ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT, - sizeof(struct lpfc_scsicmd_bkt), - GFP_KERNEL); - - if (!ndlp->lat_data) - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "0286 lpfc_nlp_state_cleanup failed to " - "allocate statistical data buffer DID " - "0x%x\n", ndlp->nlp_DID); - } - /* - * if we added to Mapped list, but the remote port - * registration failed or assigned a target id outside - * our presentable range - move the node to the - * Unmapped List - */ - if (new_state == NLP_STE_MAPPED_NODE && - (!ndlp->rport || - ndlp->rport->scsi_target_id == -1 || - ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_TGT_NO_SCSIID; - spin_unlock_irq(shost->host_lock); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - } -} - -static char * -lpfc_nlp_state_name(char *buffer, size_t size, int state) -{ - static char *states[] = { - [NLP_STE_UNUSED_NODE] = "UNUSED", - [NLP_STE_PLOGI_ISSUE] = "PLOGI", - [NLP_STE_ADISC_ISSUE] = "ADISC", - [NLP_STE_REG_LOGIN_ISSUE] = "REGLOGIN", - [NLP_STE_PRLI_ISSUE] = "PRLI", - [NLP_STE_UNMAPPED_NODE] = "UNMAPPED", - [NLP_STE_MAPPED_NODE] = "MAPPED", - [NLP_STE_NPR_NODE] = "NPR", - }; - - if (state < NLP_STE_MAX_STATE && states[state]) - strlcpy(buffer, states[state], size); - else - snprintf(buffer, size, "unknown (%d)", state); - return buffer; -} - -void -lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - int state) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - int old_state = ndlp->nlp_state; - char name1[16], name2[16]; - - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0904 NPort state transition x%06x, %s -> %s\n", - ndlp->nlp_DID, - lpfc_nlp_state_name(name1, sizeof(name1), old_state), - lpfc_nlp_state_name(name2, sizeof(name2), state)); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, - "node statechg did:x%x old:%d ste:%d", - ndlp->nlp_DID, old_state, state); - - if (old_state == NLP_STE_NPR_NODE && - state != NLP_STE_NPR_NODE) - lpfc_cancel_retry_delay_tmo(vport, ndlp); - if (old_state == NLP_STE_UNMAPPED_NODE) { - ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID; - ndlp->nlp_type &= ~NLP_FC_NODE; - } - - if (list_empty(&ndlp->nlp_listp)) { - spin_lock_irq(shost->host_lock); - list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); - spin_unlock_irq(shost->host_lock); - } else if (old_state) - lpfc_nlp_counters(vport, old_state, -1); - - ndlp->nlp_state = state; - lpfc_nlp_counters(vport, state, 1); - lpfc_nlp_state_cleanup(vport, ndlp, old_state, state); -} - -void -lpfc_enqueue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (list_empty(&ndlp->nlp_listp)) { - spin_lock_irq(shost->host_lock); - list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); - spin_unlock_irq(shost->host_lock); - } -} - -void -lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - lpfc_cancel_retry_delay_tmo(vport, ndlp); - if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) - lpfc_nlp_counters(vport, ndlp->nlp_state, -1); - spin_lock_irq(shost->host_lock); - list_del_init(&ndlp->nlp_listp); - spin_unlock_irq(shost->host_lock); - lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, - NLP_STE_UNUSED_NODE); -} - -static void -lpfc_disable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - lpfc_cancel_retry_delay_tmo(vport, ndlp); - if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) - lpfc_nlp_counters(vport, ndlp->nlp_state, -1); - lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, - NLP_STE_UNUSED_NODE); -} -/** - * lpfc_initialize_node - Initialize all fields of node object - * @vport: Pointer to Virtual Port object. - * @ndlp: Pointer to FC node object. - * @did: FC_ID of the node. - * - * This function is always called when node object need to be initialized. - * It initializes all the fields of the node object. Although the reference - * to phba from @ndlp can be obtained indirectly through it's reference to - * @vport, a direct reference to phba is taken here by @ndlp. This is due - * to the life-span of the @ndlp might go beyond the existence of @vport as - * the final release of ndlp is determined by its reference count. And, the - * operation on @ndlp needs the reference to phba. - **/ -static inline void -lpfc_initialize_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint32_t did) -{ - INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); - INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); - init_timer(&ndlp->nlp_delayfunc); - ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; - ndlp->nlp_delayfunc.data = (unsigned long)ndlp; - ndlp->nlp_DID = did; - ndlp->vport = vport; - ndlp->phba = vport->phba; - ndlp->nlp_sid = NLP_NO_SID; - kref_init(&ndlp->kref); - NLP_INT_NODE_ACT(ndlp); - atomic_set(&ndlp->cmd_pending, 0); - ndlp->cmd_qdepth = vport->cfg_tgt_queue_depth; - if (vport->phba->sli_rev == LPFC_SLI_REV4) - ndlp->nlp_rpi = lpfc_sli4_alloc_rpi(vport->phba); -} - -struct lpfc_nodelist * -lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - int state) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t did; - unsigned long flags; - - if (!ndlp) - return NULL; - - spin_lock_irqsave(&phba->ndlp_lock, flags); - /* The ndlp should not be in memory free mode */ - if (NLP_CHK_FREE_REQ(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0277 lpfc_enable_node: ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); - return NULL; - } - /* The ndlp should not already be in active mode */ - if (NLP_CHK_NODE_ACT(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0278 lpfc_enable_node: ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); - return NULL; - } - - /* Keep the original DID */ - did = ndlp->nlp_DID; - - /* re-initialize ndlp except of ndlp linked list pointer */ - memset((((char *)ndlp) + sizeof (struct list_head)), 0, - sizeof (struct lpfc_nodelist) - sizeof (struct list_head)); - lpfc_initialize_node(vport, ndlp, did); - - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - - if (state != NLP_STE_UNUSED_NODE) - lpfc_nlp_set_state(vport, ndlp, state); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, - "node enable: did:x%x", - ndlp->nlp_DID, 0, 0); - return ndlp; -} - -void -lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - /* - * Use of lpfc_drop_node and UNUSED list: lpfc_drop_node should - * be used if we wish to issue the "last" lpfc_nlp_put() to remove - * the ndlp from the vport. The ndlp marked as UNUSED on the list - * until ALL other outstanding threads have completed. We check - * that the ndlp not already in the UNUSED state before we proceed. - */ - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - return; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); - if (vport->phba->sli_rev == LPFC_SLI_REV4) - lpfc_cleanup_vports_rrqs(vport, ndlp); - lpfc_nlp_put(ndlp); - return; -} - -/* - * Start / ReStart rescue timer for Discovery / RSCN handling - */ -void -lpfc_set_disctmo(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - uint32_t tmo; - - if (vport->port_state == LPFC_LOCAL_CFG_LINK) { - /* For FAN, timeout should be greater than edtov */ - tmo = (((phba->fc_edtov + 999) / 1000) + 1); - } else { - /* Normal discovery timeout should be > than ELS/CT timeout - * FC spec states we need 3 * ratov for CT requests - */ - tmo = ((phba->fc_ratov * 3) + 3); - } - - - if (!timer_pending(&vport->fc_disctmo)) { - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "set disc timer: tmo:x%x state:x%x flg:x%x", - tmo, vport->port_state, vport->fc_flag); - } - - mod_timer(&vport->fc_disctmo, jiffies + HZ * tmo); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_DISC_TMO; - spin_unlock_irq(shost->host_lock); - - /* Start Discovery Timer state */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0247 Start Discovery Timer state x%x " - "Data: x%x x%lx x%x x%x\n", - vport->port_state, tmo, - (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt, - vport->fc_adisc_cnt); - - return; -} - -/* - * Cancel rescue timer for Discovery / RSCN handling - */ -int -lpfc_can_disctmo(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - unsigned long iflags; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "can disc timer: state:x%x rtry:x%x flg:x%x", - vport->port_state, vport->fc_ns_retry, vport->fc_flag); - - /* Turn off discovery timer if its running */ - if (vport->fc_flag & FC_DISC_TMO) { - spin_lock_irqsave(shost->host_lock, iflags); - vport->fc_flag &= ~FC_DISC_TMO; - spin_unlock_irqrestore(shost->host_lock, iflags); - del_timer_sync(&vport->fc_disctmo); - spin_lock_irqsave(&vport->work_port_lock, iflags); - vport->work_port_events &= ~WORKER_DISC_TMO; - spin_unlock_irqrestore(&vport->work_port_lock, iflags); - } - - /* Cancel Discovery Timer state */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0248 Cancel Discovery Timer state x%x " - "Data: x%x x%x x%x\n", - vport->port_state, vport->fc_flag, - vport->fc_plogi_cnt, vport->fc_adisc_cnt); - return 0; -} - -/* - * Check specified ring for outstanding IOCB on the SLI queue - * Return true if iocb matches the specified nport - */ -int -lpfc_check_sli_ndlp(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, - struct lpfc_iocbq *iocb, - struct lpfc_nodelist *ndlp) -{ - struct lpfc_sli *psli = &phba->sli; - IOCB_t *icmd = &iocb->iocb; - struct lpfc_vport *vport = ndlp->vport; - - if (iocb->vport != vport) - return 0; - - if (pring->ringno == LPFC_ELS_RING) { - switch (icmd->ulpCommand) { - case CMD_GEN_REQUEST64_CR: - if (iocb->context_un.ndlp == ndlp) - return 1; - case CMD_ELS_REQUEST64_CR: - if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID) - return 1; - case CMD_XMIT_ELS_RSP64_CX: - if (iocb->context1 == (uint8_t *) ndlp) - return 1; - } - } else if (pring->ringno == psli->extra_ring) { - - } else if (pring->ringno == psli->fcp_ring) { - /* Skip match check if waiting to relogin to FCP target */ - if ((ndlp->nlp_type & NLP_FCP_TARGET) && - (ndlp->nlp_flag & NLP_DELAY_TMO)) { - return 0; - } - if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) { - return 1; - } - } else if (pring->ringno == psli->next_ring) { - - } - return 0; -} - -/* - * Free resources / clean up outstanding I/Os - * associated with nlp_rpi in the LPFC_NODELIST entry. - */ -static int -lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) -{ - LIST_HEAD(completions); - struct lpfc_sli *psli; - struct lpfc_sli_ring *pring; - struct lpfc_iocbq *iocb, *next_iocb; - uint32_t i; - - lpfc_fabric_abort_nport(ndlp); - - /* - * Everything that matches on txcmplq will be returned - * by firmware with a no rpi error. - */ - psli = &phba->sli; - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { - /* Now process each ring */ - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(iocb, next_iocb, &pring->txq, - list) { - /* - * Check to see if iocb matches the nport we are - * looking for - */ - if ((lpfc_check_sli_ndlp(phba, pring, iocb, - ndlp))) { - /* It matches, so deque and call compl - with an error */ - list_move_tail(&iocb->list, - &completions); - pring->txq_cnt--; - } - } - spin_unlock_irq(&phba->hbalock); - } - } - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); - - return 0; -} - -/* - * Free rpi associated with LPFC_NODELIST entry. - * This routine is called from lpfc_freenode(), when we are removing - * a LPFC_NODELIST entry. It is also called if the driver initiates a - * LOGO that completes successfully, and we are waiting to PLOGI back - * to the remote NPort. In addition, it is called after we receive - * and unsolicated ELS cmd, send back a rsp, the rsp completes and - * we are waiting to PLOGI back to the remote NPort. - */ -int -lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; - int rc; - uint16_t rpi; - - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox) { - /* SLI4 ports require the physical rpi value. */ - rpi = ndlp->nlp_rpi; - if (phba->sli_rev == LPFC_SLI_REV4) - rpi = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - lpfc_unreg_login(phba, vport->vpi, rpi, mbox); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - mempool_free(mbox, phba->mbox_mem_pool); - } - lpfc_no_rpi(phba, ndlp); - - if (phba->sli_rev != LPFC_SLI_REV4) - ndlp->nlp_rpi = 0; - ndlp->nlp_flag &= ~NLP_RPI_REGISTERED; - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - return 1; - } - return 0; -} - -/** - * lpfc_unreg_hba_rpis - Unregister rpis registered to the hba. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unregister all the currently registered RPIs - * to the HBA. - **/ -void -lpfc_unreg_hba_rpis(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; - int i; - - vports = lpfc_create_vport_work_array(phba); - if (!vports) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "2884 Vport array allocation failed \n"); - return; - } - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { - /* The mempool_alloc might sleep */ - spin_unlock_irq(shost->host_lock); - lpfc_unreg_rpi(vports[i], ndlp); - spin_lock_irq(shost->host_lock); - } - } - spin_unlock_irq(shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); -} - -void -lpfc_unreg_all_rpis(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; - int rc; - - if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_sli4_unreg_all_rpis(vport); - return; - } - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox) { - lpfc_unreg_login(phba, vport->vpi, LPFC_UNREG_ALL_RPIS_VPORT, - mbox); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->context1 = NULL; - rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - - if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, - "1836 Could not issue " - "unreg_login(all_rpis) status %d\n", rc); - } -} - -void -lpfc_unreg_default_rpis(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; - int rc; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox) { - lpfc_unreg_did(phba, vport->vpi, LPFC_UNREG_ALL_DFLT_RPIS, - mbox); - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->context1 = NULL; - rc = lpfc_sli_issue_mbox_wait(phba, mbox, LPFC_MBOX_TMO); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - - if ((rc == MBX_TIMEOUT) || (rc == MBX_NOT_FINISHED)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX | LOG_VPORT, - "1815 Could not issue " - "unreg_did (default rpis) status %d\n", - rc); - } -} - -/* - * Free resources associated with LPFC_NODELIST entry - * so it can be freed. - */ -static int -lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mb, *nextmb; - struct lpfc_dmabuf *mp; - - /* Cleanup node for NPort */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0900 Cleanup node for NPort x%x " - "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_state, ndlp->nlp_rpi); - if (NLP_CHK_FREE_REQ(ndlp)) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0280 lpfc_cleanup_node: ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); - lpfc_dequeue_node(vport, ndlp); - } else { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, - "0281 lpfc_cleanup_node: ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); - lpfc_disable_node(vport, ndlp); - } - - /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ - if ((mb = phba->sli.mbox_active)) { - if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && - (ndlp == (struct lpfc_nodelist *) mb->context2)) { - mb->context2 = NULL; - mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - } - } - - spin_lock_irq(&phba->hbalock); - /* Cleanup REG_LOGIN completions which are not yet processed */ - list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) { - if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) || - (ndlp != (struct lpfc_nodelist *) mb->context2)) - continue; - - mb->context2 = NULL; - mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - } - - list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { - if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && - (ndlp == (struct lpfc_nodelist *) mb->context2)) { - mp = (struct lpfc_dmabuf *) (mb->context1); - if (mp) { - __lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - list_del(&mb->list); - mempool_free(mb, phba->mbox_mem_pool); - /* We shall not invoke the lpfc_nlp_put to decrement - * the ndlp reference count as we are in the process - * of lpfc_nlp_release. - */ - } - } - spin_unlock_irq(&phba->hbalock); - - lpfc_els_abort(phba, ndlp); - - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - - ndlp->nlp_last_elscmd = 0; - del_timer_sync(&ndlp->nlp_delayfunc); - - list_del_init(&ndlp->els_retry_evt.evt_listp); - list_del_init(&ndlp->dev_loss_evt.evt_listp); - lpfc_cleanup_vports_rrqs(vport, ndlp); - lpfc_unreg_rpi(vport, ndlp); - - return 0; -} - -/* - * Check to see if we can free the nlp back to the freelist. - * If we are in the middle of using the nlp in the discovery state - * machine, defer the free till we reach the end of the state machine. - */ -static void -lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_rport_data *rdata; - LPFC_MBOXQ_t *mbox; - int rc; - - lpfc_cancel_retry_delay_tmo(vport, ndlp); - if ((ndlp->nlp_flag & NLP_DEFER_RM) && - !(ndlp->nlp_flag & NLP_REG_LOGIN_SEND) && - !(ndlp->nlp_flag & NLP_RPI_REGISTERED)) { - /* For this case we need to cleanup the default rpi - * allocated by the firmware. - */ - if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) - != NULL) { - rc = lpfc_reg_rpi(phba, vport->vpi, ndlp->nlp_DID, - (uint8_t *) &vport->fc_sparam, mbox, ndlp->nlp_rpi); - if (rc) { - mempool_free(mbox, phba->mbox_mem_pool); - } - else { - mbox->mbox_flag |= LPFC_MBX_IMED_UNREG; - mbox->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; - mbox->vport = vport; - mbox->context2 = NULL; - rc =lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - } - } - } - } - lpfc_cleanup_node(vport, ndlp); - - /* - * We can get here with a non-NULL ndlp->rport because when we - * unregister a rport we don't break the rport/node linkage. So if we - * do, make sure we don't leaving any dangling pointers behind. - */ - if (ndlp->rport) { - rdata = ndlp->rport->dd_data; - rdata->pnode = NULL; - ndlp->rport = NULL; - } -} - -static int -lpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint32_t did) -{ - D_ID mydid, ndlpdid, matchdid; - - if (did == Bcast_DID) - return 0; - - /* First check for Direct match */ - if (ndlp->nlp_DID == did) - return 1; - - /* Next check for area/domain identically equals 0 match */ - mydid.un.word = vport->fc_myDID; - if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) { - return 0; - } - - matchdid.un.word = did; - ndlpdid.un.word = ndlp->nlp_DID; - if (matchdid.un.b.id == ndlpdid.un.b.id) { - if ((mydid.un.b.domain == matchdid.un.b.domain) && - (mydid.un.b.area == matchdid.un.b.area)) { - if ((ndlpdid.un.b.domain == 0) && - (ndlpdid.un.b.area == 0)) { - if (ndlpdid.un.b.id) - return 1; - } - return 0; - } - - matchdid.un.word = ndlp->nlp_DID; - if ((mydid.un.b.domain == ndlpdid.un.b.domain) && - (mydid.un.b.area == ndlpdid.un.b.area)) { - if ((matchdid.un.b.domain == 0) && - (matchdid.un.b.area == 0)) { - if (matchdid.un.b.id) - return 1; - } - } - } - return 0; -} - -/* Search for a nodelist entry */ -static struct lpfc_nodelist * -__lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) -{ - struct lpfc_nodelist *ndlp; - uint32_t data1; - - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (lpfc_matchdid(vport, ndlp, did)) { - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0929 FIND node DID " - "Data: x%p x%x x%x x%x\n", - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - return ndlp; - } - } - - /* FIND node did NOT FOUND */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0932 FIND node did x%x NOT FOUND.\n", did); - return NULL; -} - -struct lpfc_nodelist * -lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp; - unsigned long iflags; - - spin_lock_irqsave(shost->host_lock, iflags); - ndlp = __lpfc_findnode_did(vport, did); - spin_unlock_irqrestore(shost->host_lock, iflags); - return ndlp; -} - -struct lpfc_nodelist * -lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp; - - ndlp = lpfc_findnode_did(vport, did); - if (!ndlp) { - if ((vport->fc_flag & FC_RSCN_MODE) != 0 && - lpfc_rscn_payload_check(vport, did) == 0) - return NULL; - ndlp = (struct lpfc_nodelist *) - mempool_alloc(vport->phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - return NULL; - lpfc_nlp_init(vport, ndlp, did); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - return ndlp; - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_NPR_NODE); - if (!ndlp) - return NULL; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - return ndlp; - } - - if ((vport->fc_flag & FC_RSCN_MODE) && - !(vport->fc_flag & FC_NDISC_ACTIVE)) { - if (lpfc_rscn_payload_check(vport, did)) { - /* If we've already received a PLOGI from this NPort - * we don't need to try to discover it again. - */ - if (ndlp->nlp_flag & NLP_RCV_PLOGI) - return NULL; - - /* Since this node is marked for discovery, - * delay timeout is not needed. - */ - lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - } else - ndlp = NULL; - } else { - /* If we've already received a PLOGI from this NPort, - * or we are already in the process of discovery on it, - * we don't need to try to discover it again. - */ - if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || - ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || - ndlp->nlp_flag & NLP_RCV_PLOGI) - return NULL; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - } - return ndlp; -} - -/* Build a list of nodes to discover based on the loopmap */ -void -lpfc_disc_list_loopmap(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - int j; - uint32_t alpa, index; - - if (!lpfc_is_link_up(phba)) - return; - - if (phba->fc_topology != LPFC_TOPOLOGY_LOOP) - return; - - /* Check for loop map present or not */ - if (phba->alpa_map[0]) { - for (j = 1; j <= phba->alpa_map[0]; j++) { - alpa = phba->alpa_map[j]; - if (((vport->fc_myDID & 0xff) == alpa) || (alpa == 0)) - continue; - lpfc_setup_disc_node(vport, alpa); - } - } else { - /* No alpamap, so try all alpa's */ - for (j = 0; j < FC_MAXLOOP; j++) { - /* If cfg_scan_down is set, start from highest - * ALPA (0xef) to lowest (0x1). - */ - if (vport->cfg_scan_down) - index = j; - else - index = FC_MAXLOOP - j - 1; - alpa = lpfcAlpaArray[index]; - if ((vport->fc_myDID & 0xff) == alpa) - continue; - lpfc_setup_disc_node(vport, alpa); - } - } - return; -} - -void -lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport) -{ - LPFC_MBOXQ_t *mbox; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *extra_ring = &psli->ring[psli->extra_ring]; - struct lpfc_sli_ring *fcp_ring = &psli->ring[psli->fcp_ring]; - struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring]; - int rc; - - /* - * if it's not a physical port or if we already send - * clear_la then don't send it. - */ - if ((phba->link_state >= LPFC_CLEAR_LA) || - (vport->port_type != LPFC_PHYSICAL_PORT) || - (phba->sli_rev == LPFC_SLI_REV4)) - return; - - /* Link up discovery */ - if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) { - phba->link_state = LPFC_CLEAR_LA; - lpfc_clear_la(phba, mbox); - mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - lpfc_disc_flush_list(vport); - extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - next_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - phba->link_state = LPFC_HBA_ERROR; - } - } -} - -/* Reg_vpi to tell firmware to resume normal operations */ -void -lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport) -{ - LPFC_MBOXQ_t *regvpimbox; - - regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (regvpimbox) { - lpfc_reg_vpi(vport, regvpimbox); - regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi; - regvpimbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, regvpimbox, MBX_NOWAIT) - == MBX_NOT_FINISHED) { - mempool_free(regvpimbox, phba->mbox_mem_pool); - } - } -} - -/* Start Link up / RSCN discovery on NPR nodes */ -void -lpfc_disc_start(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - uint32_t num_sent; - uint32_t clear_la_pending; - int did_changed; - - if (!lpfc_is_link_up(phba)) - return; - - if (phba->link_state == LPFC_CLEAR_LA) - clear_la_pending = 1; - else - clear_la_pending = 0; - - if (vport->port_state < LPFC_VPORT_READY) - vport->port_state = LPFC_DISC_AUTH; - - lpfc_set_disctmo(vport); - - if (vport->fc_prevDID == vport->fc_myDID) - did_changed = 0; - else - did_changed = 1; - - vport->fc_prevDID = vport->fc_myDID; - vport->num_disc_nodes = 0; - - /* Start Discovery state */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0202 Start Discovery hba state x%x " - "Data: x%x x%x x%x\n", - vport->port_state, vport->fc_flag, vport->fc_plogi_cnt, - vport->fc_adisc_cnt); - - /* First do ADISCs - if any */ - num_sent = lpfc_els_disc_adisc(vport); - - if (num_sent) - return; - - /* Register the VPI for SLI3, NON-NPIV only. */ - if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - !(vport->fc_flag & FC_PT2PT) && - !(vport->fc_flag & FC_RSCN_MODE) && - (phba->sli_rev < LPFC_SLI_REV4)) { - lpfc_issue_reg_vpi(phba, vport); - return; - } - - /* - * For SLI2, we need to set port_state to READY and continue - * discovery. - */ - if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) { - /* If we get here, there is nothing to ADISC */ - if (vport->port_type == LPFC_PHYSICAL_PORT) - lpfc_issue_clear_la(phba, vport); - - if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { - vport->num_disc_nodes = 0; - /* go thru NPR nodes and issue ELS PLOGIs */ - if (vport->fc_npr_cnt) - lpfc_els_disc_plogi(vport); - - if (!vport->num_disc_nodes) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - } - } - vport->port_state = LPFC_VPORT_READY; - } else { - /* Next do PLOGIs - if any */ - num_sent = lpfc_els_disc_plogi(vport); - - if (num_sent) - return; - - if (vport->fc_flag & FC_RSCN_MODE) { - /* Check to see if more RSCNs came in while we - * were processing this one. - */ - if ((vport->fc_rscn_id_cnt == 0) && - (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - } else - lpfc_els_handle_rscn(vport); - } - } - return; -} - -/* - * Ignore completion for all IOCBs on tx and txcmpl queue for ELS - * ring the match the sppecified nodelist. - */ -static void -lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) -{ - LIST_HEAD(completions); - struct lpfc_sli *psli; - IOCB_t *icmd; - struct lpfc_iocbq *iocb, *next_iocb; - struct lpfc_sli_ring *pring; - - psli = &phba->sli; - pring = &psli->ring[LPFC_ELS_RING]; - - /* Error matching iocb on txq or txcmplq - * First check the txq. - */ - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { - if (iocb->context1 != ndlp) { - continue; - } - icmd = &iocb->iocb; - if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) || - (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) { - - list_move_tail(&iocb->list, &completions); - pring->txq_cnt--; - } - } - - /* Next check the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { - if (iocb->context1 != ndlp) { - continue; - } - icmd = &iocb->iocb; - if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR || - icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX) { - lpfc_sli_issue_abort_iotag(phba, pring, iocb); - } - } - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); -} - -static void -lpfc_disc_flush_list(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp, *next_ndlp; - struct lpfc_hba *phba = vport->phba; - - if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, - nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || - ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { - lpfc_free_tx(phba, ndlp); - } - } - } -} - -void -lpfc_cleanup_discovery_resources(struct lpfc_vport *vport) -{ - lpfc_els_flush_rscn(vport); - lpfc_els_flush_cmd(vport); - lpfc_disc_flush_list(vport); -} - -/*****************************************************************************/ -/* - * NAME: lpfc_disc_timeout - * - * FUNCTION: Fibre Channel driver discovery timeout routine. - * - * EXECUTION ENVIRONMENT: interrupt only - * - * CALLED FROM: - * Timer function - * - * RETURNS: - * none - */ -/*****************************************************************************/ -void -lpfc_disc_timeout(unsigned long ptr) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) ptr; - struct lpfc_hba *phba = vport->phba; - uint32_t tmo_posted; - unsigned long flags = 0; - - if (unlikely(!phba)) - return; - - spin_lock_irqsave(&vport->work_port_lock, flags); - tmo_posted = vport->work_port_events & WORKER_DISC_TMO; - if (!tmo_posted) - vport->work_port_events |= WORKER_DISC_TMO; - spin_unlock_irqrestore(&vport->work_port_lock, flags); - - if (!tmo_posted) - lpfc_worker_wake_up(phba); - return; -} - -static void -lpfc_disc_timeout_handler(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_nodelist *ndlp, *next_ndlp; - LPFC_MBOXQ_t *initlinkmbox; - int rc, clrlaerr = 0; - - if (!(vport->fc_flag & FC_DISC_TMO)) - return; - - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_DISC_TMO; - spin_unlock_irq(shost->host_lock); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, - "disc timeout: state:x%x rtry:x%x flg:x%x", - vport->port_state, vport->fc_ns_retry, vport->fc_flag); - - switch (vport->port_state) { - - case LPFC_LOCAL_CFG_LINK: - /* port_state is identically LPFC_LOCAL_CFG_LINK while waiting for - * FAN - */ - /* FAN timeout */ - lpfc_printf_vlog(vport, KERN_WARNING, LOG_DISCOVERY, - "0221 FAN timeout\n"); - /* Start discovery by sending FLOGI, clean up old rpis */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, - nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state != NLP_STE_NPR_NODE) - continue; - if (ndlp->nlp_type & NLP_FABRIC) { - /* Clean up the ndlp on Fabric connections */ - lpfc_drop_node(vport, ndlp); - - } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { - /* Fail outstanding IO now since device - * is marked for PLOGI. - */ - lpfc_unreg_rpi(vport, ndlp); - } - } - if (vport->port_state != LPFC_FLOGI) { - if (phba->sli_rev <= LPFC_SLI_REV3) - lpfc_initial_flogi(vport); - else - lpfc_issue_init_vfi(vport); - return; - } - break; - - case LPFC_FDISC: - case LPFC_FLOGI: - /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ - /* Initial FLOGI timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0222 Initial %s timeout\n", - vport->vpi ? "FDISC" : "FLOGI"); - - /* Assume no Fabric and go on with discovery. - * Check for outstanding ELS FLOGI to abort. - */ - - /* FLOGI failed, so just use loop map to make discovery list */ - lpfc_disc_list_loopmap(vport); - - /* Start discovery */ - lpfc_disc_start(vport); - break; - - case LPFC_FABRIC_CFG_LINK: - /* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for - NameServer login */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0223 Timeout while waiting for " - "NameServer login\n"); - /* Next look for NameServer ndlp */ - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) - lpfc_els_abort(phba, ndlp); - - /* ReStart discovery */ - goto restart_disc; - - case LPFC_NS_QRY: - /* Check for wait for NameServer Rsp timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0224 NameServer Query timeout " - "Data: x%x x%x\n", - vport->fc_ns_retry, LPFC_MAX_NS_RETRY); - - if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { - /* Try it one more time */ - vport->fc_ns_retry++; - rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, - vport->fc_ns_retry, 0); - if (rc == 0) - break; - } - vport->fc_ns_retry = 0; - -restart_disc: - /* - * Discovery is over. - * set port_state to PORT_READY if SLI2. - * cmpl_reg_vpi will set port_state to READY for SLI3. - */ - if (phba->sli_rev < LPFC_SLI_REV4) { - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) - lpfc_issue_reg_vpi(phba, vport); - else { - lpfc_issue_clear_la(phba, vport); - vport->port_state = LPFC_VPORT_READY; - } - } - - /* Setup and issue mailbox INITIALIZE LINK command */ - initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!initlinkmbox) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0206 Device Discovery " - "completion error\n"); - phba->link_state = LPFC_HBA_ERROR; - break; - } - - lpfc_linkdown(phba); - lpfc_init_link(phba, initlinkmbox, phba->cfg_topology, - phba->cfg_link_speed); - initlinkmbox->u.mb.un.varInitLnk.lipsr_AL_PA = 0; - initlinkmbox->vport = vport; - initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, initlinkmbox, MBX_NOWAIT); - lpfc_set_loopback_flag(phba); - if (rc == MBX_NOT_FINISHED) - mempool_free(initlinkmbox, phba->mbox_mem_pool); - - break; - - case LPFC_DISC_AUTH: - /* Node Authentication timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0227 Node Authentication timeout\n"); - lpfc_disc_flush_list(vport); - - /* - * set port_state to PORT_READY if SLI2. - * cmpl_reg_vpi will set port_state to READY for SLI3. - */ - if (phba->sli_rev < LPFC_SLI_REV4) { - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) - lpfc_issue_reg_vpi(phba, vport); - else { /* NPIV Not enabled */ - lpfc_issue_clear_la(phba, vport); - vport->port_state = LPFC_VPORT_READY; - } - } - break; - - case LPFC_VPORT_READY: - if (vport->fc_flag & FC_RSCN_MODE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0231 RSCN timeout Data: x%x " - "x%x\n", - vport->fc_ns_retry, LPFC_MAX_NS_RETRY); - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_cmd(vport); - - lpfc_els_flush_rscn(vport); - lpfc_disc_flush_list(vport); - } - break; - - default: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0273 Unexpected discovery timeout, " - "vport State x%x\n", vport->port_state); - break; - } - - switch (phba->link_state) { - case LPFC_CLEAR_LA: - /* CLEAR LA timeout */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0228 CLEAR LA timeout\n"); - clrlaerr = 1; - break; - - case LPFC_LINK_UP: - lpfc_issue_clear_la(phba, vport); - /* Drop thru */ - case LPFC_LINK_UNKNOWN: - case LPFC_WARM_START: - case LPFC_INIT_START: - case LPFC_INIT_MBX_CMDS: - case LPFC_LINK_DOWN: - case LPFC_HBA_ERROR: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0230 Unexpected timeout, hba link " - "state x%x\n", phba->link_state); - clrlaerr = 1; - break; - - case LPFC_HBA_READY: - break; - } - - if (clrlaerr) { - lpfc_disc_flush_list(vport); - psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; - psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; - psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; - vport->port_state = LPFC_VPORT_READY; - } - - return; -} - -/* - * This routine handles processing a NameServer REG_LOGIN mailbox - * command upon completion. It is setup in the LPFC_MBOXQ - * as the completion routine when the command is - * handed off to the SLI layer. - */ -void -lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); - struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; - struct lpfc_vport *vport = pmb->vport; - - pmb->context1 = NULL; - pmb->context2 = NULL; - - if (phba->sli_rev < LPFC_SLI_REV4) - ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; - ndlp->nlp_type |= NLP_FABRIC; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - - /* - * Start issuing Fabric-Device Management Interface (FDMI) command to - * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if - * fdmi-on=2 (supporting RPA/hostnmae) - */ - - if (vport->cfg_fdmi_on == 1) - lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); - else - mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60); - - /* decrement the node reference count held for this callback - * function. - */ - lpfc_nlp_put(ndlp); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - - return; -} - -static int -lpfc_filter_by_rpi(struct lpfc_nodelist *ndlp, void *param) -{ - uint16_t *rpi = param; - - /* check for active node */ - if (!NLP_CHK_NODE_ACT(ndlp)) - return 0; - - return ndlp->nlp_rpi == *rpi; -} - -static int -lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param) -{ - return memcmp(&ndlp->nlp_portname, param, - sizeof(ndlp->nlp_portname)) == 0; -} - -static struct lpfc_nodelist * -__lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) -{ - struct lpfc_nodelist *ndlp; - - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (filter(ndlp, param)) - return ndlp; - } - return NULL; -} - -/* - * This routine looks up the ndlp lists for the given RPI. If rpi found it - * returns the node list element pointer else return NULL. - */ -struct lpfc_nodelist * -__lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) -{ - return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi); -} - -/* - * This routine looks up the ndlp lists for the given WWPN. If WWPN found it - * returns the node element list pointer else return NULL. - */ -struct lpfc_nodelist * -lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp; - - spin_lock_irq(shost->host_lock); - ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwpn, wwpn); - spin_unlock_irq(shost->host_lock); - return ndlp; -} - -/* - * This routine looks up the ndlp lists for the given RPI. If the rpi - * is found, the routine returns the node element list pointer else - * return NULL. - */ -struct lpfc_nodelist * -lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_nodelist *ndlp; - - spin_lock_irq(shost->host_lock); - ndlp = __lpfc_findnode_rpi(vport, rpi); - spin_unlock_irq(shost->host_lock); - return ndlp; -} - -/** - * lpfc_find_vport_by_vpid - Find a vport on a HBA through vport identifier - * @phba: pointer to lpfc hba data structure. - * @vpi: the physical host virtual N_Port identifier. - * - * This routine finds a vport on a HBA (referred by @phba) through a - * @vpi. The function walks the HBA's vport list and returns the address - * of the vport with the matching @vpi. - * - * Return code - * NULL - No vport with the matching @vpi found - * Otherwise - Address to the vport with the matching @vpi. - **/ -struct lpfc_vport * -lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) -{ - struct lpfc_vport *vport; - unsigned long flags; - int i = 0; - - /* The physical ports are always vpi 0 - translate is unnecessary. */ - if (vpi > 0) { - /* - * Translate the physical vpi to the logical vpi. The - * vport stores the logical vpi. - */ - for (i = 0; i < phba->max_vpi; i++) { - if (vpi == phba->vpi_ids[i]) - break; - } - - if (i >= phba->max_vpi) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "2936 Could not find Vport mapped " - "to vpi %d\n", vpi); - return NULL; - } - } - - spin_lock_irqsave(&phba->hbalock, flags); - list_for_each_entry(vport, &phba->port_list, listentry) { - if (vport->vpi == i) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return vport; - } - } - spin_unlock_irqrestore(&phba->hbalock, flags); - return NULL; -} - -void -lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - uint32_t did) -{ - memset(ndlp, 0, sizeof (struct lpfc_nodelist)); - - lpfc_initialize_node(vport, ndlp, did); - INIT_LIST_HEAD(&ndlp->nlp_listp); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, - "node init: did:x%x", - ndlp->nlp_DID, 0, 0); - - return; -} - -/* This routine releases all resources associated with a specifc NPort's ndlp - * and mempool_free's the nodelist. - */ -static void -lpfc_nlp_release(struct kref *kref) -{ - struct lpfc_hba *phba; - unsigned long flags; - struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, - kref); - - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node release: did:x%x flg:x%x type:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); - - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0279 lpfc_nlp_release: ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); - - /* remove ndlp from action. */ - lpfc_nlp_remove(ndlp->vport, ndlp); - - /* clear the ndlp active flag for all release cases */ - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - NLP_CLR_NODE_ACT(ndlp); - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); - - /* free ndlp memory for final ndlp release */ - if (NLP_CHK_FREE_REQ(ndlp)) { - kfree(ndlp->lat_data); - mempool_free(ndlp, ndlp->phba->nlp_mem_pool); - } -} - -/* This routine bumps the reference count for a ndlp structure to ensure - * that one discovery thread won't free a ndlp while another discovery thread - * is using it. - */ -struct lpfc_nodelist * -lpfc_nlp_get(struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba; - unsigned long flags; - - if (ndlp) { - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node get: did:x%x flg:x%x refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount)); - /* The check of ndlp usage to prevent incrementing the - * ndlp reference count that is in the process of being - * released. - */ - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - if (!NLP_CHK_NODE_ACT(ndlp) || NLP_CHK_FREE_ACK(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0276 lpfc_nlp_get: ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); - return NULL; - } else - kref_get(&ndlp->kref); - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - } - return ndlp; -} - -/* This routine decrements the reference count for a ndlp structure. If the - * count goes to 0, this indicates the the associated nodelist should be - * freed. Returning 1 indicates the ndlp resource has been released; on the - * other hand, returning 0 indicates the ndlp resource has not been released - * yet. - */ -int -lpfc_nlp_put(struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba; - unsigned long flags; - - if (!ndlp) - return 1; - - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node put: did:x%x flg:x%x refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount)); - phba = ndlp->phba; - spin_lock_irqsave(&phba->ndlp_lock, flags); - /* Check the ndlp memory free acknowledge flag to avoid the - * possible race condition that kref_put got invoked again - * after previous one has done ndlp memory free. - */ - if (NLP_CHK_FREE_ACK(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0274 lpfc_nlp_put: ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); - return 1; - } - /* Check the ndlp inactivate log flag to avoid the possible - * race condition that kref_put got invoked again after ndlp - * is already in inactivating state. - */ - if (NLP_CHK_IACT_REQ(ndlp)) { - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - lpfc_printf_vlog(ndlp->vport, KERN_WARNING, LOG_NODE, - "0275 lpfc_nlp_put: ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - (void *)ndlp, ndlp->nlp_usg_map, - atomic_read(&ndlp->kref.refcount)); - return 1; - } - /* For last put, mark the ndlp usage flags to make sure no - * other kref_get and kref_put on the same ndlp shall get - * in between the process when the final kref_put has been - * invoked on this ndlp. - */ - if (atomic_read(&ndlp->kref.refcount) == 1) { - /* Indicate ndlp is put to inactive state. */ - NLP_SET_IACT_REQ(ndlp); - /* Acknowledge ndlp memory free has been seen. */ - if (NLP_CHK_FREE_REQ(ndlp)) - NLP_SET_FREE_ACK(ndlp); - } - spin_unlock_irqrestore(&phba->ndlp_lock, flags); - /* Note, the kref_put returns 1 when decrementing a reference - * count that was 1, it invokes the release callback function, - * but it still left the reference count as 1 (not actually - * performs the last decrementation). Otherwise, it actually - * decrements the reference count and returns 0. - */ - return kref_put(&ndlp->kref, lpfc_nlp_release); -} - -/* This routine free's the specified nodelist if it is not in use - * by any other discovery thread. This routine returns 1 if the - * ndlp has been freed. A return value of 0 indicates the ndlp is - * not yet been released. - */ -int -lpfc_nlp_not_used(struct lpfc_nodelist *ndlp) -{ - lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, - "node not used: did:x%x flg:x%x refcnt:x%x", - ndlp->nlp_DID, ndlp->nlp_flag, - atomic_read(&ndlp->kref.refcount)); - if (atomic_read(&ndlp->kref.refcount) == 1) - if (lpfc_nlp_put(ndlp)) - return 1; - return 0; -} - -/** - * lpfc_fcf_inuse - Check if FCF can be unregistered. - * @phba: Pointer to hba context object. - * - * This function iterate through all FC nodes associated - * will all vports to check if there is any node with - * fc_rports associated with it. If there is an fc_rport - * associated with the node, then the node is either in - * discovered state or its devloss_timer is pending. - */ -static int -lpfc_fcf_inuse(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - int i, ret = 0; - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; - - vports = lpfc_create_vport_work_array(phba); - - /* If driver cannot allocate memory, indicate fcf is in use */ - if (!vports) - return 1; - - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - /* - * IF the CVL_RCVD bit is not set then we have sent the - * flogi. - * If dev_loss fires while we are waiting we do not want to - * unreg the fcf. - */ - if (!(vports[i]->fc_flag & FC_VPORT_CVL_RCVD)) { - spin_unlock_irq(shost->host_lock); - ret = 1; - goto out; - } - list_for_each_entry(ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (NLP_CHK_NODE_ACT(ndlp) && ndlp->rport && - (ndlp->rport->roles & FC_RPORT_ROLE_FCP_TARGET)) { - ret = 1; - spin_unlock_irq(shost->host_lock); - goto out; - } else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { - ret = 1; - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "2624 RPI %x DID %x flag %x " - "still logged in\n", - ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag); - } - } - spin_unlock_irq(shost->host_lock); - } -out: - lpfc_destroy_vport_work_array(phba, vports); - return ret; -} - -/** - * lpfc_unregister_vfi_cmpl - Completion handler for unreg vfi. - * @phba: Pointer to hba context object. - * @mboxq: Pointer to mailbox object. - * - * This function frees memory associated with the mailbox command. - */ -void -lpfc_unregister_vfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct lpfc_vport *vport = mboxq->vport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (mboxq->u.mb.mbxStatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2555 UNREG_VFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); - } - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); - mempool_free(mboxq, phba->mbox_mem_pool); - return; -} - -/** - * lpfc_unregister_fcfi_cmpl - Completion handler for unreg fcfi. - * @phba: Pointer to hba context object. - * @mboxq: Pointer to mailbox object. - * - * This function frees memory associated with the mailbox command. - */ -static void -lpfc_unregister_fcfi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct lpfc_vport *vport = mboxq->vport; - - if (mboxq->u.mb.mbxStatus) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2550 UNREG_FCFI mbxStatus error x%x " - "HBA state x%x\n", - mboxq->u.mb.mbxStatus, vport->port_state); - } - mempool_free(mboxq, phba->mbox_mem_pool); - return; -} - -/** - * lpfc_unregister_fcf_prep - Unregister fcf record preparation - * @phba: Pointer to hba context object. - * - * This function prepare the HBA for unregistering the currently registered - * FCF from the HBA. It performs unregistering, in order, RPIs, VPIs, and - * VFIs. - */ -int -lpfc_unregister_fcf_prep(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; - int i, rc; - - /* Unregister RPIs */ - if (lpfc_fcf_inuse(phba)) - lpfc_unreg_hba_rpis(phba); - - /* At this point, all discovery is aborted */ - phba->pport->port_state = LPFC_VPORT_UNKNOWN; - - /* Unregister VPIs */ - vports = lpfc_create_vport_work_array(phba); - if (vports && (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - /* Stop FLOGI/FDISC retries */ - ndlp = lpfc_findnode_did(vports[i], Fabric_DID); - if (ndlp) - lpfc_cancel_retry_delay_tmo(vports[i], ndlp); - lpfc_cleanup_pending_mbox(vports[i]); - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_unreg_all_rpis(vports[i]); - lpfc_mbx_unreg_vpi(vports[i]); - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; - spin_unlock_irq(shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_all_cmd(phba); - - /* Unregister the physical port VFI */ - rc = lpfc_issue_unreg_vfi(phba->pport); - return rc; -} - -/** - * lpfc_sli4_unregister_fcf - Unregister currently registered FCF record - * @phba: Pointer to hba context object. - * - * This function issues synchronous unregister FCF mailbox command to HBA to - * unregister the currently registered FCF record. The driver does not reset - * the driver FCF usage state flags. - * - * Return 0 if successfully issued, none-zero otherwise. - */ -int -lpfc_sli4_unregister_fcf(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *mbox; - int rc; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2551 UNREG_FCFI mbox allocation failed" - "HBA state x%x\n", phba->pport->port_state); - return -ENOMEM; - } - lpfc_unreg_fcfi(mbox, phba->fcf.fcfi); - mbox->vport = phba->pport; - mbox->mbox_cmpl = lpfc_unregister_fcfi_cmpl; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2552 Unregister FCFI command failed rc x%x " - "HBA state x%x\n", - rc, phba->pport->port_state); - return -EINVAL; - } - return 0; -} - -/** - * lpfc_unregister_fcf_rescan - Unregister currently registered fcf and rescan - * @phba: Pointer to hba context object. - * - * This function unregisters the currently reigstered FCF. This function - * also tries to find another FCF for discovery by rescan the HBA FCF table. - */ -void -lpfc_unregister_fcf_rescan(struct lpfc_hba *phba) -{ - int rc; - - /* Preparation for unregistering fcf */ - rc = lpfc_unregister_fcf_prep(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "2748 Failed to prepare for unregistering " - "HBA's FCF record: rc=%d\n", rc); - return; - } - - /* Now, unregister FCF record and reset HBA FCF state */ - rc = lpfc_sli4_unregister_fcf(phba); - if (rc) - return; - /* Reset HBA FCF states after successful unregister FCF */ - phba->fcf.fcf_flag = 0; - phba->fcf.current_rec.flag = 0; - - /* - * If driver is not unloading, check if there is any other - * FCF record that can be used for discovery. - */ - if ((phba->pport->load_flag & FC_UNLOADING) || - (phba->link_state < LPFC_LINK_UP)) - return; - - /* This is considered as the initial FCF discovery scan */ - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag |= FCF_INIT_DISC; - spin_unlock_irq(&phba->hbalock); - - /* Reset FCF roundrobin bmask for new discovery */ - lpfc_sli4_clear_fcf_rr_bmask(phba); - - rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); - - if (rc) { - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_INIT_DISC; - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY|LOG_MBOX, - "2553 lpfc_unregister_unused_fcf failed " - "to read FCF record HBA state x%x\n", - phba->pport->port_state); - } -} - -/** - * lpfc_unregister_fcf - Unregister the currently registered fcf record - * @phba: Pointer to hba context object. - * - * This function just unregisters the currently reigstered FCF. It does not - * try to find another FCF for discovery. - */ -void -lpfc_unregister_fcf(struct lpfc_hba *phba) -{ - int rc; - - /* Preparation for unregistering fcf */ - rc = lpfc_unregister_fcf_prep(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "2749 Failed to prepare for unregistering " - "HBA's FCF record: rc=%d\n", rc); - return; - } - - /* Now, unregister FCF record and reset HBA FCF state */ - rc = lpfc_sli4_unregister_fcf(phba); - if (rc) - return; - /* Set proper HBA FCF states after successful unregister FCF */ - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_REGISTERED; - spin_unlock_irq(&phba->hbalock); -} - -/** - * lpfc_unregister_unused_fcf - Unregister FCF if all devices are disconnected. - * @phba: Pointer to hba context object. - * - * This function check if there are any connected remote port for the FCF and - * if all the devices are disconnected, this function unregister FCFI. - * This function also tries to use another FCF for discovery. - */ -void -lpfc_unregister_unused_fcf(struct lpfc_hba *phba) -{ - /* - * If HBA is not running in FIP mode, if HBA does not support - * FCoE, if FCF discovery is ongoing, or if FCF has not been - * registered, do nothing. - */ - spin_lock_irq(&phba->hbalock); - if (!(phba->hba_flag & HBA_FCOE_MODE) || - !(phba->fcf.fcf_flag & FCF_REGISTERED) || - !(phba->hba_flag & HBA_FIP_SUPPORT) || - (phba->fcf.fcf_flag & FCF_DISCOVERY) || - (phba->pport->port_state == LPFC_FLOGI)) { - spin_unlock_irq(&phba->hbalock); - return; - } - spin_unlock_irq(&phba->hbalock); - - if (lpfc_fcf_inuse(phba)) - return; - - lpfc_unregister_fcf_rescan(phba); -} - -/** - * lpfc_read_fcf_conn_tbl - Create driver FCF connection table. - * @phba: Pointer to hba context object. - * @buff: Buffer containing the FCF connection table as in the config - * region. - * This function create driver data structure for the FCF connection - * record table read from config region 23. - */ -static void -lpfc_read_fcf_conn_tbl(struct lpfc_hba *phba, - uint8_t *buff) -{ - struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; - struct lpfc_fcf_conn_hdr *conn_hdr; - struct lpfc_fcf_conn_rec *conn_rec; - uint32_t record_count; - int i; - - /* Free the current connect table */ - list_for_each_entry_safe(conn_entry, next_conn_entry, - &phba->fcf_conn_rec_list, list) { - list_del_init(&conn_entry->list); - kfree(conn_entry); - } - - conn_hdr = (struct lpfc_fcf_conn_hdr *) buff; - record_count = conn_hdr->length * sizeof(uint32_t)/ - sizeof(struct lpfc_fcf_conn_rec); - - conn_rec = (struct lpfc_fcf_conn_rec *) - (buff + sizeof(struct lpfc_fcf_conn_hdr)); - - for (i = 0; i < record_count; i++) { - if (!(conn_rec[i].flags & FCFCNCT_VALID)) - continue; - conn_entry = kzalloc(sizeof(struct lpfc_fcf_conn_entry), - GFP_KERNEL); - if (!conn_entry) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2566 Failed to allocate connection" - " table entry\n"); - return; - } - - memcpy(&conn_entry->conn_rec, &conn_rec[i], - sizeof(struct lpfc_fcf_conn_rec)); - conn_entry->conn_rec.vlan_tag = - le16_to_cpu(conn_entry->conn_rec.vlan_tag) & 0xFFF; - conn_entry->conn_rec.flags = - le16_to_cpu(conn_entry->conn_rec.flags); - list_add_tail(&conn_entry->list, - &phba->fcf_conn_rec_list); - } -} - -/** - * lpfc_read_fcoe_param - Read FCoe parameters from conf region.. - * @phba: Pointer to hba context object. - * @buff: Buffer containing the FCoE parameter data structure. - * - * This function update driver data structure with config - * parameters read from config region 23. - */ -static void -lpfc_read_fcoe_param(struct lpfc_hba *phba, - uint8_t *buff) -{ - struct lpfc_fip_param_hdr *fcoe_param_hdr; - struct lpfc_fcoe_params *fcoe_param; - - fcoe_param_hdr = (struct lpfc_fip_param_hdr *) - buff; - fcoe_param = (struct lpfc_fcoe_params *) - (buff + sizeof(struct lpfc_fip_param_hdr)); - - if ((fcoe_param_hdr->parm_version != FIPP_VERSION) || - (fcoe_param_hdr->length != FCOE_PARAM_LENGTH)) - return; - - if (fcoe_param_hdr->parm_flags & FIPP_VLAN_VALID) { - phba->valid_vlan = 1; - phba->vlan_id = le16_to_cpu(fcoe_param->vlan_tag) & - 0xFFF; - } - - phba->fc_map[0] = fcoe_param->fc_map[0]; - phba->fc_map[1] = fcoe_param->fc_map[1]; - phba->fc_map[2] = fcoe_param->fc_map[2]; - return; -} - -/** - * lpfc_get_rec_conf23 - Get a record type in config region data. - * @buff: Buffer containing config region 23 data. - * @size: Size of the data buffer. - * @rec_type: Record type to be searched. - * - * This function searches config region data to find the beginning - * of the record specified by record_type. If record found, this - * function return pointer to the record else return NULL. - */ -static uint8_t * -lpfc_get_rec_conf23(uint8_t *buff, uint32_t size, uint8_t rec_type) -{ - uint32_t offset = 0, rec_length; - - if ((buff[0] == LPFC_REGION23_LAST_REC) || - (size < sizeof(uint32_t))) - return NULL; - - rec_length = buff[offset + 1]; - - /* - * One TLV record has one word header and number of data words - * specified in the rec_length field of the record header. - */ - while ((offset + rec_length * sizeof(uint32_t) + sizeof(uint32_t)) - <= size) { - if (buff[offset] == rec_type) - return &buff[offset]; - - if (buff[offset] == LPFC_REGION23_LAST_REC) - return NULL; - - offset += rec_length * sizeof(uint32_t) + sizeof(uint32_t); - rec_length = buff[offset + 1]; - } - return NULL; -} - -/** - * lpfc_parse_fcoe_conf - Parse FCoE config data read from config region 23. - * @phba: Pointer to lpfc_hba data structure. - * @buff: Buffer containing config region 23 data. - * @size: Size of the data buffer. - * - * This function parses the FCoE config parameters in config region 23 and - * populate driver data structure with the parameters. - */ -void -lpfc_parse_fcoe_conf(struct lpfc_hba *phba, - uint8_t *buff, - uint32_t size) -{ - uint32_t offset = 0, rec_length; - uint8_t *rec_ptr; - - /* - * If data size is less than 2 words signature and version cannot be - * verified. - */ - if (size < 2*sizeof(uint32_t)) - return; - - /* Check the region signature first */ - if (memcmp(buff, LPFC_REGION23_SIGNATURE, 4)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2567 Config region 23 has bad signature\n"); - return; - } - - offset += 4; - - /* Check the data structure version */ - if (buff[offset] != LPFC_REGION23_VERSION) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2568 Config region 23 has bad version\n"); - return; - } - offset += 4; - - rec_length = buff[offset + 1]; - - /* Read FCoE param record */ - rec_ptr = lpfc_get_rec_conf23(&buff[offset], - size - offset, FCOE_PARAM_TYPE); - if (rec_ptr) - lpfc_read_fcoe_param(phba, rec_ptr); - - /* Read FCF connection table */ - rec_ptr = lpfc_get_rec_conf23(&buff[offset], - size - offset, FCOE_CONN_TBL_TYPE); - if (rec_ptr) - lpfc_read_fcf_conn_tbl(phba, rec_ptr); - -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw.h deleted file mode 100644 index 5f280b5a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw.h +++ /dev/null @@ -1,3835 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2011 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#define FDMI_DID 0xfffffaU -#define NameServer_DID 0xfffffcU -#define SCR_DID 0xfffffdU -#define Fabric_DID 0xfffffeU -#define Bcast_DID 0xffffffU -#define Mask_DID 0xffffffU -#define CT_DID_MASK 0xffff00U -#define Fabric_DID_MASK 0xfff000U -#define WELL_KNOWN_DID_MASK 0xfffff0U - -#define PT2PT_LocalID 1 -#define PT2PT_RemoteID 2 - -#define FF_DEF_EDTOV 2000 /* Default E_D_TOV (2000ms) */ -#define FF_DEF_ALTOV 15 /* Default AL_TIME (15ms) */ -#define FF_DEF_RATOV 2 /* Default RA_TOV (2s) */ -#define FF_DEF_ARBTOV 1900 /* Default ARB_TOV (1900ms) */ - -#define LPFC_BUF_RING0 64 /* Number of buffers to post to RING - 0 */ - -#define FCELSSIZE 1024 /* maximum ELS transfer size */ - -#define LPFC_FCP_RING 0 /* ring 0 for FCP initiator commands */ -#define LPFC_EXTRA_RING 1 /* ring 1 for other protocols */ -#define LPFC_ELS_RING 2 /* ring 2 for ELS commands */ -#define LPFC_FCP_NEXT_RING 3 - -#define SLI2_IOCB_CMD_R0_ENTRIES 172 /* SLI-2 FCP command ring entries */ -#define SLI2_IOCB_RSP_R0_ENTRIES 134 /* SLI-2 FCP response ring entries */ -#define SLI2_IOCB_CMD_R1_ENTRIES 4 /* SLI-2 extra command ring entries */ -#define SLI2_IOCB_RSP_R1_ENTRIES 4 /* SLI-2 extra response ring entries */ -#define SLI2_IOCB_CMD_R1XTRA_ENTRIES 36 /* SLI-2 extra FCP cmd ring entries */ -#define SLI2_IOCB_RSP_R1XTRA_ENTRIES 52 /* SLI-2 extra FCP rsp ring entries */ -#define SLI2_IOCB_CMD_R2_ENTRIES 20 /* SLI-2 ELS command ring entries */ -#define SLI2_IOCB_RSP_R2_ENTRIES 20 /* SLI-2 ELS response ring entries */ -#define SLI2_IOCB_CMD_R3_ENTRIES 0 -#define SLI2_IOCB_RSP_R3_ENTRIES 0 -#define SLI2_IOCB_CMD_R3XTRA_ENTRIES 24 -#define SLI2_IOCB_RSP_R3XTRA_ENTRIES 32 - -#define SLI2_IOCB_CMD_SIZE 32 -#define SLI2_IOCB_RSP_SIZE 32 -#define SLI3_IOCB_CMD_SIZE 128 -#define SLI3_IOCB_RSP_SIZE 64 - -#define LPFC_UNREG_ALL_RPIS_VPORT 0xffff -#define LPFC_UNREG_ALL_DFLT_RPIS 0xffffffff - -/* vendor ID used in SCSI netlink calls */ -#define LPFC_NL_VENDOR_ID (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX) - -#define FW_REV_STR_SIZE 32 -/* Common Transport structures and definitions */ - -union CtRevisionId { - /* Structure is in Big Endian format */ - struct { - uint32_t Revision:8; - uint32_t InId:24; - } bits; - uint32_t word; -}; - -union CtCommandResponse { - /* Structure is in Big Endian format */ - struct { - uint32_t CmdRsp:16; - uint32_t Size:16; - } bits; - uint32_t word; -}; - -#define FC4_FEATURE_INIT 0x2 -#define FC4_FEATURE_TARGET 0x1 - -struct lpfc_sli_ct_request { - /* Structure is in Big Endian format */ - union CtRevisionId RevisionId; - uint8_t FsType; - uint8_t FsSubType; - uint8_t Options; - uint8_t Rsrvd1; - union CtCommandResponse CommandResponse; - uint8_t Rsrvd2; - uint8_t ReasonCode; - uint8_t Explanation; - uint8_t VendorUnique; - - union { - uint32_t PortID; - struct gid { - uint8_t PortType; /* for GID_PT requests */ - uint8_t DomainScope; - uint8_t AreaScope; - uint8_t Fc4Type; /* for GID_FT requests */ - } gid; - struct rft { - uint32_t PortId; /* For RFT_ID requests */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd0:16; - uint32_t rsvd1:7; - uint32_t fcpReg:1; /* Type 8 */ - uint32_t rsvd2:2; - uint32_t ipReg:1; /* Type 5 */ - uint32_t rsvd3:5; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t rsvd0:16; - uint32_t fcpReg:1; /* Type 8 */ - uint32_t rsvd1:7; - uint32_t rsvd3:5; - uint32_t ipReg:1; /* Type 5 */ - uint32_t rsvd2:2; -#endif - - uint32_t rsvd[7]; - } rft; - struct rnn { - uint32_t PortId; /* For RNN_ID requests */ - uint8_t wwnn[8]; - } rnn; - struct rsnn { /* For RSNN_ID requests */ - uint8_t wwnn[8]; - uint8_t len; - uint8_t symbname[255]; - } rsnn; - struct da_id { /* For DA_ID requests */ - uint32_t port_id; - } da_id; - struct rspn { /* For RSPN_ID requests */ - uint32_t PortId; - uint8_t len; - uint8_t symbname[255]; - } rspn; - struct gff { - uint32_t PortId; - } gff; - struct gff_acc { - uint8_t fbits[128]; - } gff_acc; -#define FCP_TYPE_FEATURE_OFFSET 7 - struct rff { - uint32_t PortId; - uint8_t reserved[2]; - uint8_t fbits; - uint8_t type_code; /* type=8 for FCP */ - } rff; - } un; -}; - -#define SLI_CT_REVISION 1 -#define GID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct gid)) -#define GFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct gff)) -#define RFT_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct rft)) -#define RFF_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct rff)) -#define RNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct rnn)) -#define RSNN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct rsnn)) -#define DA_ID_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct da_id)) -#define RSPN_REQUEST_SZ (offsetof(struct lpfc_sli_ct_request, un) + \ - sizeof(struct rspn)) - -/* - * FsType Definitions - */ - -#define SLI_CT_MANAGEMENT_SERVICE 0xFA -#define SLI_CT_TIME_SERVICE 0xFB -#define SLI_CT_DIRECTORY_SERVICE 0xFC -#define SLI_CT_FABRIC_CONTROLLER_SERVICE 0xFD - -/* - * Directory Service Subtypes - */ - -#define SLI_CT_DIRECTORY_NAME_SERVER 0x02 - -/* - * Response Codes - */ - -#define SLI_CT_RESPONSE_FS_RJT 0x8001 -#define SLI_CT_RESPONSE_FS_ACC 0x8002 - -/* - * Reason Codes - */ - -#define SLI_CT_NO_ADDITIONAL_EXPL 0x0 -#define SLI_CT_INVALID_COMMAND 0x01 -#define SLI_CT_INVALID_VERSION 0x02 -#define SLI_CT_LOGICAL_ERROR 0x03 -#define SLI_CT_INVALID_IU_SIZE 0x04 -#define SLI_CT_LOGICAL_BUSY 0x05 -#define SLI_CT_PROTOCOL_ERROR 0x07 -#define SLI_CT_UNABLE_TO_PERFORM_REQ 0x09 -#define SLI_CT_REQ_NOT_SUPPORTED 0x0b -#define SLI_CT_HBA_INFO_NOT_REGISTERED 0x10 -#define SLI_CT_MULTIPLE_HBA_ATTR_OF_SAME_TYPE 0x11 -#define SLI_CT_INVALID_HBA_ATTR_BLOCK_LEN 0x12 -#define SLI_CT_HBA_ATTR_NOT_PRESENT 0x13 -#define SLI_CT_PORT_INFO_NOT_REGISTERED 0x20 -#define SLI_CT_MULTIPLE_PORT_ATTR_OF_SAME_TYPE 0x21 -#define SLI_CT_INVALID_PORT_ATTR_BLOCK_LEN 0x22 -#define SLI_CT_VENDOR_UNIQUE 0xff - -/* - * Name Server SLI_CT_UNABLE_TO_PERFORM_REQ Explanations - */ - -#define SLI_CT_NO_PORT_ID 0x01 -#define SLI_CT_NO_PORT_NAME 0x02 -#define SLI_CT_NO_NODE_NAME 0x03 -#define SLI_CT_NO_CLASS_OF_SERVICE 0x04 -#define SLI_CT_NO_IP_ADDRESS 0x05 -#define SLI_CT_NO_IPA 0x06 -#define SLI_CT_NO_FC4_TYPES 0x07 -#define SLI_CT_NO_SYMBOLIC_PORT_NAME 0x08 -#define SLI_CT_NO_SYMBOLIC_NODE_NAME 0x09 -#define SLI_CT_NO_PORT_TYPE 0x0A -#define SLI_CT_ACCESS_DENIED 0x10 -#define SLI_CT_INVALID_PORT_ID 0x11 -#define SLI_CT_DATABASE_EMPTY 0x12 - -/* - * Name Server Command Codes - */ - -#define SLI_CTNS_GA_NXT 0x0100 -#define SLI_CTNS_GPN_ID 0x0112 -#define SLI_CTNS_GNN_ID 0x0113 -#define SLI_CTNS_GCS_ID 0x0114 -#define SLI_CTNS_GFT_ID 0x0117 -#define SLI_CTNS_GSPN_ID 0x0118 -#define SLI_CTNS_GPT_ID 0x011A -#define SLI_CTNS_GFF_ID 0x011F -#define SLI_CTNS_GID_PN 0x0121 -#define SLI_CTNS_GID_NN 0x0131 -#define SLI_CTNS_GIP_NN 0x0135 -#define SLI_CTNS_GIPA_NN 0x0136 -#define SLI_CTNS_GSNN_NN 0x0139 -#define SLI_CTNS_GNN_IP 0x0153 -#define SLI_CTNS_GIPA_IP 0x0156 -#define SLI_CTNS_GID_FT 0x0171 -#define SLI_CTNS_GID_PT 0x01A1 -#define SLI_CTNS_RPN_ID 0x0212 -#define SLI_CTNS_RNN_ID 0x0213 -#define SLI_CTNS_RCS_ID 0x0214 -#define SLI_CTNS_RFT_ID 0x0217 -#define SLI_CTNS_RSPN_ID 0x0218 -#define SLI_CTNS_RPT_ID 0x021A -#define SLI_CTNS_RFF_ID 0x021F -#define SLI_CTNS_RIP_NN 0x0235 -#define SLI_CTNS_RIPA_NN 0x0236 -#define SLI_CTNS_RSNN_NN 0x0239 -#define SLI_CTNS_DA_ID 0x0300 - -/* - * Port Types - */ - -#define SLI_CTPT_N_PORT 0x01 -#define SLI_CTPT_NL_PORT 0x02 -#define SLI_CTPT_FNL_PORT 0x03 -#define SLI_CTPT_IP 0x04 -#define SLI_CTPT_FCP 0x08 -#define SLI_CTPT_NX_PORT 0x7F -#define SLI_CTPT_F_PORT 0x81 -#define SLI_CTPT_FL_PORT 0x82 -#define SLI_CTPT_E_PORT 0x84 - -#define SLI_CT_LAST_ENTRY 0x80000000 - -/* Fibre Channel Service Parameter definitions */ - -#define FC_PH_4_0 6 /* FC-PH version 4.0 */ -#define FC_PH_4_1 7 /* FC-PH version 4.1 */ -#define FC_PH_4_2 8 /* FC-PH version 4.2 */ -#define FC_PH_4_3 9 /* FC-PH version 4.3 */ - -#define FC_PH_LOW 8 /* Lowest supported FC-PH version */ -#define FC_PH_HIGH 9 /* Highest supported FC-PH version */ -#define FC_PH3 0x20 /* FC-PH-3 version */ - -#define FF_FRAME_SIZE 2048 - -struct lpfc_name { - union { - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t nameType:4; /* FC Word 0, bit 28:31 */ - uint8_t IEEEextMsn:4; /* FC Word 0, bit 24:27, bit - 8:11 of IEEE ext */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t IEEEextMsn:4; /* FC Word 0, bit 24:27, bit - 8:11 of IEEE ext */ - uint8_t nameType:4; /* FC Word 0, bit 28:31 */ -#endif - -#define NAME_IEEE 0x1 /* IEEE name - nameType */ -#define NAME_IEEE_EXT 0x2 /* IEEE extended name */ -#define NAME_FC_TYPE 0x3 /* FC native name type */ -#define NAME_IP_TYPE 0x4 /* IP address */ -#define NAME_CCITT_TYPE 0xC -#define NAME_CCITT_GR_TYPE 0xE - uint8_t IEEEextLsb; /* FC Word 0, bit 16:23, IEEE - extended Lsb */ - uint8_t IEEE[6]; /* FC IEEE address */ - } s; - uint8_t wwn[8]; - } u; -}; - -struct csp { - uint8_t fcphHigh; /* FC Word 0, byte 0 */ - uint8_t fcphLow; - uint8_t bbCreditMsb; - uint8_t bbCreditlsb; /* FC Word 0, byte 3 */ - -/* - * Word 1 Bit 31 in common service parameter is overloaded. - * Word 1 Bit 31 in FLOGI request is multiple NPort request - * Word 1 Bit 31 in FLOGI response is clean address bit - */ -#define clean_address_bit request_multiple_Nport /* Word 1, bit 31 */ -/* - * Word 1 Bit 30 in common service parameter is overloaded. - * Word 1 Bit 30 in FLOGI request is Virtual Fabrics - * Word 1 Bit 30 in PLOGI request is random offset - */ -#define virtual_fabric_support randomOffset /* Word 1, bit 30 */ -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */ - uint16_t randomOffset:1; /* FC Word 1, bit 30 */ - uint16_t response_multiple_NPort:1; /* FC Word 1, bit 29 */ - uint16_t fPort:1; /* FC Word 1, bit 28 */ - uint16_t altBbCredit:1; /* FC Word 1, bit 27 */ - uint16_t edtovResolution:1; /* FC Word 1, bit 26 */ - uint16_t multicast:1; /* FC Word 1, bit 25 */ - uint16_t broadcast:1; /* FC Word 1, bit 24 */ - - uint16_t huntgroup:1; /* FC Word 1, bit 23 */ - uint16_t simplex:1; /* FC Word 1, bit 22 */ - uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */ - uint16_t dhd:1; /* FC Word 1, bit 18 */ - uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */ - uint16_t payloadlength:1; /* FC Word 1, bit 16 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t broadcast:1; /* FC Word 1, bit 24 */ - uint16_t multicast:1; /* FC Word 1, bit 25 */ - uint16_t edtovResolution:1; /* FC Word 1, bit 26 */ - uint16_t altBbCredit:1; /* FC Word 1, bit 27 */ - uint16_t fPort:1; /* FC Word 1, bit 28 */ - uint16_t response_multiple_NPort:1; /* FC Word 1, bit 29 */ - uint16_t randomOffset:1; /* FC Word 1, bit 30 */ - uint16_t request_multiple_Nport:1; /* FC Word 1, bit 31 */ - - uint16_t payloadlength:1; /* FC Word 1, bit 16 */ - uint16_t contIncSeqCnt:1; /* FC Word 1, bit 17 */ - uint16_t dhd:1; /* FC Word 1, bit 18 */ - uint16_t word1Reserved1:3; /* FC Word 1, bit 21:19 */ - uint16_t simplex:1; /* FC Word 1, bit 22 */ - uint16_t huntgroup:1; /* FC Word 1, bit 23 */ -#endif - - uint8_t bbRcvSizeMsb; /* Upper nibble is reserved */ - uint8_t bbRcvSizeLsb; /* FC Word 1, byte 3 */ - union { - struct { - uint8_t word2Reserved1; /* FC Word 2 byte 0 */ - - uint8_t totalConcurrSeq; /* FC Word 2 byte 1 */ - uint8_t roByCategoryMsb; /* FC Word 2 byte 2 */ - - uint8_t roByCategoryLsb; /* FC Word 2 byte 3 */ - } nPort; - uint32_t r_a_tov; /* R_A_TOV must be in B.E. format */ - } w2; - - uint32_t e_d_tov; /* E_D_TOV must be in B.E. format */ -}; - -struct class_parms { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t classValid:1; /* FC Word 0, bit 31 */ - uint8_t intermix:1; /* FC Word 0, bit 30 */ - uint8_t stackedXparent:1; /* FC Word 0, bit 29 */ - uint8_t stackedLockDown:1; /* FC Word 0, bit 28 */ - uint8_t seqDelivery:1; /* FC Word 0, bit 27 */ - uint8_t word0Reserved1:3; /* FC Word 0, bit 24:26 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t word0Reserved1:3; /* FC Word 0, bit 24:26 */ - uint8_t seqDelivery:1; /* FC Word 0, bit 27 */ - uint8_t stackedLockDown:1; /* FC Word 0, bit 28 */ - uint8_t stackedXparent:1; /* FC Word 0, bit 29 */ - uint8_t intermix:1; /* FC Word 0, bit 30 */ - uint8_t classValid:1; /* FC Word 0, bit 31 */ - -#endif - - uint8_t word0Reserved2; /* FC Word 0, bit 16:23 */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t iCtlXidReAssgn:2; /* FC Word 0, Bit 14:15 */ - uint8_t iCtlInitialPa:2; /* FC Word 0, bit 12:13 */ - uint8_t iCtlAck0capable:1; /* FC Word 0, bit 11 */ - uint8_t iCtlAckNcapable:1; /* FC Word 0, bit 10 */ - uint8_t word0Reserved3:2; /* FC Word 0, bit 8: 9 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t word0Reserved3:2; /* FC Word 0, bit 8: 9 */ - uint8_t iCtlAckNcapable:1; /* FC Word 0, bit 10 */ - uint8_t iCtlAck0capable:1; /* FC Word 0, bit 11 */ - uint8_t iCtlInitialPa:2; /* FC Word 0, bit 12:13 */ - uint8_t iCtlXidReAssgn:2; /* FC Word 0, Bit 14:15 */ -#endif - - uint8_t word0Reserved4; /* FC Word 0, bit 0: 7 */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t rCtlAck0capable:1; /* FC Word 1, bit 31 */ - uint8_t rCtlAckNcapable:1; /* FC Word 1, bit 30 */ - uint8_t rCtlXidInterlck:1; /* FC Word 1, bit 29 */ - uint8_t rCtlErrorPolicy:2; /* FC Word 1, bit 27:28 */ - uint8_t word1Reserved1:1; /* FC Word 1, bit 26 */ - uint8_t rCtlCatPerSeq:2; /* FC Word 1, bit 24:25 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t rCtlCatPerSeq:2; /* FC Word 1, bit 24:25 */ - uint8_t word1Reserved1:1; /* FC Word 1, bit 26 */ - uint8_t rCtlErrorPolicy:2; /* FC Word 1, bit 27:28 */ - uint8_t rCtlXidInterlck:1; /* FC Word 1, bit 29 */ - uint8_t rCtlAckNcapable:1; /* FC Word 1, bit 30 */ - uint8_t rCtlAck0capable:1; /* FC Word 1, bit 31 */ -#endif - - uint8_t word1Reserved2; /* FC Word 1, bit 16:23 */ - uint8_t rcvDataSizeMsb; /* FC Word 1, bit 8:15 */ - uint8_t rcvDataSizeLsb; /* FC Word 1, bit 0: 7 */ - - uint8_t concurrentSeqMsb; /* FC Word 2, bit 24:31 */ - uint8_t concurrentSeqLsb; /* FC Word 2, bit 16:23 */ - uint8_t EeCreditSeqMsb; /* FC Word 2, bit 8:15 */ - uint8_t EeCreditSeqLsb; /* FC Word 2, bit 0: 7 */ - - uint8_t openSeqPerXchgMsb; /* FC Word 3, bit 24:31 */ - uint8_t openSeqPerXchgLsb; /* FC Word 3, bit 16:23 */ - uint8_t word3Reserved1; /* Fc Word 3, bit 8:15 */ - uint8_t word3Reserved2; /* Fc Word 3, bit 0: 7 */ -}; - -struct serv_parm { /* Structure is in Big Endian format */ - struct csp cmn; - struct lpfc_name portName; - struct lpfc_name nodeName; - struct class_parms cls1; - struct class_parms cls2; - struct class_parms cls3; - struct class_parms cls4; - uint8_t vendorVersion[16]; -}; - -/* - * Virtual Fabric Tagging Header - */ -struct fc_vft_header { - uint32_t word0; -#define fc_vft_hdr_r_ctl_SHIFT 24 -#define fc_vft_hdr_r_ctl_MASK 0xFF -#define fc_vft_hdr_r_ctl_WORD word0 -#define fc_vft_hdr_ver_SHIFT 22 -#define fc_vft_hdr_ver_MASK 0x3 -#define fc_vft_hdr_ver_WORD word0 -#define fc_vft_hdr_type_SHIFT 18 -#define fc_vft_hdr_type_MASK 0xF -#define fc_vft_hdr_type_WORD word0 -#define fc_vft_hdr_e_SHIFT 16 -#define fc_vft_hdr_e_MASK 0x1 -#define fc_vft_hdr_e_WORD word0 -#define fc_vft_hdr_priority_SHIFT 13 -#define fc_vft_hdr_priority_MASK 0x7 -#define fc_vft_hdr_priority_WORD word0 -#define fc_vft_hdr_vf_id_SHIFT 1 -#define fc_vft_hdr_vf_id_MASK 0xFFF -#define fc_vft_hdr_vf_id_WORD word0 - uint32_t word1; -#define fc_vft_hdr_hopct_SHIFT 24 -#define fc_vft_hdr_hopct_MASK 0xFF -#define fc_vft_hdr_hopct_WORD word1 -}; - -/* - * Extended Link Service LS_COMMAND codes (Payload Word 0) - */ -#ifdef __BIG_ENDIAN_BITFIELD -#define ELS_CMD_MASK 0xffff0000 -#define ELS_RSP_MASK 0xff000000 -#define ELS_CMD_LS_RJT 0x01000000 -#define ELS_CMD_ACC 0x02000000 -#define ELS_CMD_PLOGI 0x03000000 -#define ELS_CMD_FLOGI 0x04000000 -#define ELS_CMD_LOGO 0x05000000 -#define ELS_CMD_ABTX 0x06000000 -#define ELS_CMD_RCS 0x07000000 -#define ELS_CMD_RES 0x08000000 -#define ELS_CMD_RSS 0x09000000 -#define ELS_CMD_RSI 0x0A000000 -#define ELS_CMD_ESTS 0x0B000000 -#define ELS_CMD_ESTC 0x0C000000 -#define ELS_CMD_ADVC 0x0D000000 -#define ELS_CMD_RTV 0x0E000000 -#define ELS_CMD_RLS 0x0F000000 -#define ELS_CMD_ECHO 0x10000000 -#define ELS_CMD_TEST 0x11000000 -#define ELS_CMD_RRQ 0x12000000 -#define ELS_CMD_PRLI 0x20100014 -#define ELS_CMD_PRLO 0x21100014 -#define ELS_CMD_PRLO_ACC 0x02100014 -#define ELS_CMD_PDISC 0x50000000 -#define ELS_CMD_FDISC 0x51000000 -#define ELS_CMD_ADISC 0x52000000 -#define ELS_CMD_FARP 0x54000000 -#define ELS_CMD_FARPR 0x55000000 -#define ELS_CMD_RPS 0x56000000 -#define ELS_CMD_RPL 0x57000000 -#define ELS_CMD_FAN 0x60000000 -#define ELS_CMD_RSCN 0x61040000 -#define ELS_CMD_SCR 0x62000000 -#define ELS_CMD_RNID 0x78000000 -#define ELS_CMD_LIRR 0x7A000000 -#else /* __LITTLE_ENDIAN_BITFIELD */ -#define ELS_CMD_MASK 0xffff -#define ELS_RSP_MASK 0xff -#define ELS_CMD_LS_RJT 0x01 -#define ELS_CMD_ACC 0x02 -#define ELS_CMD_PLOGI 0x03 -#define ELS_CMD_FLOGI 0x04 -#define ELS_CMD_LOGO 0x05 -#define ELS_CMD_ABTX 0x06 -#define ELS_CMD_RCS 0x07 -#define ELS_CMD_RES 0x08 -#define ELS_CMD_RSS 0x09 -#define ELS_CMD_RSI 0x0A -#define ELS_CMD_ESTS 0x0B -#define ELS_CMD_ESTC 0x0C -#define ELS_CMD_ADVC 0x0D -#define ELS_CMD_RTV 0x0E -#define ELS_CMD_RLS 0x0F -#define ELS_CMD_ECHO 0x10 -#define ELS_CMD_TEST 0x11 -#define ELS_CMD_RRQ 0x12 -#define ELS_CMD_PRLI 0x14001020 -#define ELS_CMD_PRLO 0x14001021 -#define ELS_CMD_PRLO_ACC 0x14001002 -#define ELS_CMD_PDISC 0x50 -#define ELS_CMD_FDISC 0x51 -#define ELS_CMD_ADISC 0x52 -#define ELS_CMD_FARP 0x54 -#define ELS_CMD_FARPR 0x55 -#define ELS_CMD_RPS 0x56 -#define ELS_CMD_RPL 0x57 -#define ELS_CMD_FAN 0x60 -#define ELS_CMD_RSCN 0x0461 -#define ELS_CMD_SCR 0x62 -#define ELS_CMD_RNID 0x78 -#define ELS_CMD_LIRR 0x7A -#endif - -/* - * LS_RJT Payload Definition - */ - -struct ls_rjt { /* Structure is in Big Endian format */ - union { - uint32_t lsRjtError; - struct { - uint8_t lsRjtRsvd0; /* FC Word 0, bit 24:31 */ - - uint8_t lsRjtRsnCode; /* FC Word 0, bit 16:23 */ - /* LS_RJT reason codes */ -#define LSRJT_INVALID_CMD 0x01 -#define LSRJT_LOGICAL_ERR 0x03 -#define LSRJT_LOGICAL_BSY 0x05 -#define LSRJT_PROTOCOL_ERR 0x07 -#define LSRJT_UNABLE_TPC 0x09 /* Unable to perform command */ -#define LSRJT_CMD_UNSUPPORTED 0x0B -#define LSRJT_VENDOR_UNIQUE 0xFF /* See Byte 3 */ - - uint8_t lsRjtRsnCodeExp; /* FC Word 0, bit 8:15 */ - /* LS_RJT reason explanation */ -#define LSEXP_NOTHING_MORE 0x00 -#define LSEXP_SPARM_OPTIONS 0x01 -#define LSEXP_SPARM_ICTL 0x03 -#define LSEXP_SPARM_RCTL 0x05 -#define LSEXP_SPARM_RCV_SIZE 0x07 -#define LSEXP_SPARM_CONCUR_SEQ 0x09 -#define LSEXP_SPARM_CREDIT 0x0B -#define LSEXP_INVALID_PNAME 0x0D -#define LSEXP_INVALID_NNAME 0x0E -#define LSEXP_INVALID_CSP 0x0F -#define LSEXP_INVALID_ASSOC_HDR 0x11 -#define LSEXP_ASSOC_HDR_REQ 0x13 -#define LSEXP_INVALID_O_SID 0x15 -#define LSEXP_INVALID_OX_RX 0x17 -#define LSEXP_CMD_IN_PROGRESS 0x19 -#define LSEXP_PORT_LOGIN_REQ 0x1E -#define LSEXP_INVALID_NPORT_ID 0x1F -#define LSEXP_INVALID_SEQ_ID 0x21 -#define LSEXP_INVALID_XCHG 0x23 -#define LSEXP_INACTIVE_XCHG 0x25 -#define LSEXP_RQ_REQUIRED 0x27 -#define LSEXP_OUT_OF_RESOURCE 0x29 -#define LSEXP_CANT_GIVE_DATA 0x2A -#define LSEXP_REQ_UNSUPPORTED 0x2C - uint8_t vendorUnique; /* FC Word 0, bit 0: 7 */ - } b; - } un; -}; - -/* - * N_Port Login (FLOGO/PLOGO Request) Payload Definition - */ - -typedef struct _LOGO { /* Structure is in Big Endian format */ - union { - uint32_t nPortId32; /* Access nPortId as a word */ - struct { - uint8_t word1Reserved1; /* FC Word 1, bit 31:24 */ - uint8_t nPortIdByte0; /* N_port ID bit 16:23 */ - uint8_t nPortIdByte1; /* N_port ID bit 8:15 */ - uint8_t nPortIdByte2; /* N_port ID bit 0: 7 */ - } b; - } un; - struct lpfc_name portName; /* N_port name field */ -} LOGO; - -/* - * FCP Login (PRLI Request / ACC) Payload Definition - */ - -#define PRLX_PAGE_LEN 0x10 -#define TPRLO_PAGE_LEN 0x14 - -typedef struct _PRLI { /* Structure is in Big Endian format */ - uint8_t prliType; /* FC Parm Word 0, bit 24:31 */ - -#define PRLI_FCP_TYPE 0x08 - uint8_t word0Reserved1; /* FC Parm Word 0, bit 16:23 */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t origProcAssocV:1; /* FC Parm Word 0, bit 15 */ - uint8_t respProcAssocV:1; /* FC Parm Word 0, bit 14 */ - uint8_t estabImagePair:1; /* FC Parm Word 0, bit 13 */ - - /* ACC = imagePairEstablished */ - uint8_t word0Reserved2:1; /* FC Parm Word 0, bit 12 */ - uint8_t acceptRspCode:4; /* FC Parm Word 0, bit 8:11, ACC ONLY */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t acceptRspCode:4; /* FC Parm Word 0, bit 8:11, ACC ONLY */ - uint8_t word0Reserved2:1; /* FC Parm Word 0, bit 12 */ - uint8_t estabImagePair:1; /* FC Parm Word 0, bit 13 */ - uint8_t respProcAssocV:1; /* FC Parm Word 0, bit 14 */ - uint8_t origProcAssocV:1; /* FC Parm Word 0, bit 15 */ - /* ACC = imagePairEstablished */ -#endif - -#define PRLI_REQ_EXECUTED 0x1 /* acceptRspCode */ -#define PRLI_NO_RESOURCES 0x2 -#define PRLI_INIT_INCOMPLETE 0x3 -#define PRLI_NO_SUCH_PA 0x4 -#define PRLI_PREDEF_CONFIG 0x5 -#define PRLI_PARTIAL_SUCCESS 0x6 -#define PRLI_INVALID_PAGE_CNT 0x7 - uint8_t word0Reserved3; /* FC Parm Word 0, bit 0:7 */ - - uint32_t origProcAssoc; /* FC Parm Word 1, bit 0:31 */ - - uint32_t respProcAssoc; /* FC Parm Word 2, bit 0:31 */ - - uint8_t word3Reserved1; /* FC Parm Word 3, bit 24:31 */ - uint8_t word3Reserved2; /* FC Parm Word 3, bit 16:23 */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t Word3bit15Resved:1; /* FC Parm Word 3, bit 15 */ - uint16_t Word3bit14Resved:1; /* FC Parm Word 3, bit 14 */ - uint16_t Word3bit13Resved:1; /* FC Parm Word 3, bit 13 */ - uint16_t Word3bit12Resved:1; /* FC Parm Word 3, bit 12 */ - uint16_t Word3bit11Resved:1; /* FC Parm Word 3, bit 11 */ - uint16_t Word3bit10Resved:1; /* FC Parm Word 3, bit 10 */ - uint16_t TaskRetryIdReq:1; /* FC Parm Word 3, bit 9 */ - uint16_t Retry:1; /* FC Parm Word 3, bit 8 */ - uint16_t ConfmComplAllowed:1; /* FC Parm Word 3, bit 7 */ - uint16_t dataOverLay:1; /* FC Parm Word 3, bit 6 */ - uint16_t initiatorFunc:1; /* FC Parm Word 3, bit 5 */ - uint16_t targetFunc:1; /* FC Parm Word 3, bit 4 */ - uint16_t cmdDataMixEna:1; /* FC Parm Word 3, bit 3 */ - uint16_t dataRspMixEna:1; /* FC Parm Word 3, bit 2 */ - uint16_t readXferRdyDis:1; /* FC Parm Word 3, bit 1 */ - uint16_t writeXferRdyDis:1; /* FC Parm Word 3, bit 0 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t Retry:1; /* FC Parm Word 3, bit 8 */ - uint16_t TaskRetryIdReq:1; /* FC Parm Word 3, bit 9 */ - uint16_t Word3bit10Resved:1; /* FC Parm Word 3, bit 10 */ - uint16_t Word3bit11Resved:1; /* FC Parm Word 3, bit 11 */ - uint16_t Word3bit12Resved:1; /* FC Parm Word 3, bit 12 */ - uint16_t Word3bit13Resved:1; /* FC Parm Word 3, bit 13 */ - uint16_t Word3bit14Resved:1; /* FC Parm Word 3, bit 14 */ - uint16_t Word3bit15Resved:1; /* FC Parm Word 3, bit 15 */ - uint16_t writeXferRdyDis:1; /* FC Parm Word 3, bit 0 */ - uint16_t readXferRdyDis:1; /* FC Parm Word 3, bit 1 */ - uint16_t dataRspMixEna:1; /* FC Parm Word 3, bit 2 */ - uint16_t cmdDataMixEna:1; /* FC Parm Word 3, bit 3 */ - uint16_t targetFunc:1; /* FC Parm Word 3, bit 4 */ - uint16_t initiatorFunc:1; /* FC Parm Word 3, bit 5 */ - uint16_t dataOverLay:1; /* FC Parm Word 3, bit 6 */ - uint16_t ConfmComplAllowed:1; /* FC Parm Word 3, bit 7 */ -#endif -} PRLI; - -/* - * FCP Logout (PRLO Request / ACC) Payload Definition - */ - -typedef struct _PRLO { /* Structure is in Big Endian format */ - uint8_t prloType; /* FC Parm Word 0, bit 24:31 */ - -#define PRLO_FCP_TYPE 0x08 - uint8_t word0Reserved1; /* FC Parm Word 0, bit 16:23 */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t origProcAssocV:1; /* FC Parm Word 0, bit 15 */ - uint8_t respProcAssocV:1; /* FC Parm Word 0, bit 14 */ - uint8_t word0Reserved2:2; /* FC Parm Word 0, bit 12:13 */ - uint8_t acceptRspCode:4; /* FC Parm Word 0, bit 8:11, ACC ONLY */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t acceptRspCode:4; /* FC Parm Word 0, bit 8:11, ACC ONLY */ - uint8_t word0Reserved2:2; /* FC Parm Word 0, bit 12:13 */ - uint8_t respProcAssocV:1; /* FC Parm Word 0, bit 14 */ - uint8_t origProcAssocV:1; /* FC Parm Word 0, bit 15 */ -#endif - -#define PRLO_REQ_EXECUTED 0x1 /* acceptRspCode */ -#define PRLO_NO_SUCH_IMAGE 0x4 -#define PRLO_INVALID_PAGE_CNT 0x7 - - uint8_t word0Reserved3; /* FC Parm Word 0, bit 0:7 */ - - uint32_t origProcAssoc; /* FC Parm Word 1, bit 0:31 */ - - uint32_t respProcAssoc; /* FC Parm Word 2, bit 0:31 */ - - uint32_t word3Reserved1; /* FC Parm Word 3, bit 0:31 */ -} PRLO; - -typedef struct _ADISC { /* Structure is in Big Endian format */ - uint32_t hardAL_PA; - struct lpfc_name portName; - struct lpfc_name nodeName; - uint32_t DID; -} ADISC; - -typedef struct _FARP { /* Structure is in Big Endian format */ - uint32_t Mflags:8; - uint32_t Odid:24; -#define FARP_NO_ACTION 0 /* FARP information enclosed, no - action */ -#define FARP_MATCH_PORT 0x1 /* Match on Responder Port Name */ -#define FARP_MATCH_NODE 0x2 /* Match on Responder Node Name */ -#define FARP_MATCH_IP 0x4 /* Match on IP address, not supported */ -#define FARP_MATCH_IPV4 0x5 /* Match on IPV4 address, not - supported */ -#define FARP_MATCH_IPV6 0x6 /* Match on IPV6 address, not - supported */ - uint32_t Rflags:8; - uint32_t Rdid:24; -#define FARP_REQUEST_PLOGI 0x1 /* Request for PLOGI */ -#define FARP_REQUEST_FARPR 0x2 /* Request for FARP Response */ - struct lpfc_name OportName; - struct lpfc_name OnodeName; - struct lpfc_name RportName; - struct lpfc_name RnodeName; - uint8_t Oipaddr[16]; - uint8_t Ripaddr[16]; -} FARP; - -typedef struct _FAN { /* Structure is in Big Endian format */ - uint32_t Fdid; - struct lpfc_name FportName; - struct lpfc_name FnodeName; -} FAN; - -typedef struct _SCR { /* Structure is in Big Endian format */ - uint8_t resvd1; - uint8_t resvd2; - uint8_t resvd3; - uint8_t Function; -#define SCR_FUNC_FABRIC 0x01 -#define SCR_FUNC_NPORT 0x02 -#define SCR_FUNC_FULL 0x03 -#define SCR_CLEAR 0xff -} SCR; - -typedef struct _RNID_TOP_DISC { - struct lpfc_name portName; - uint8_t resvd[8]; - uint32_t unitType; -#define RNID_HBA 0x7 -#define RNID_HOST 0xa -#define RNID_DRIVER 0xd - uint32_t physPort; - uint32_t attachedNodes; - uint16_t ipVersion; -#define RNID_IPV4 0x1 -#define RNID_IPV6 0x2 - uint16_t UDPport; - uint8_t ipAddr[16]; - uint16_t resvd1; - uint16_t flags; -#define RNID_TD_SUPPORT 0x1 -#define RNID_LP_VALID 0x2 -} RNID_TOP_DISC; - -typedef struct _RNID { /* Structure is in Big Endian format */ - uint8_t Format; -#define RNID_TOPOLOGY_DISC 0xdf - uint8_t CommonLen; - uint8_t resvd1; - uint8_t SpecificLen; - struct lpfc_name portName; - struct lpfc_name nodeName; - union { - RNID_TOP_DISC topologyDisc; /* topology disc (0xdf) */ - } un; -} RNID; - -typedef struct _RPS { /* Structure is in Big Endian format */ - union { - uint32_t portNum; - struct lpfc_name portName; - } un; -} RPS; - -typedef struct _RPS_RSP { /* Structure is in Big Endian format */ - uint16_t rsvd1; - uint16_t portStatus; - uint32_t linkFailureCnt; - uint32_t lossSyncCnt; - uint32_t lossSignalCnt; - uint32_t primSeqErrCnt; - uint32_t invalidXmitWord; - uint32_t crcCnt; -} RPS_RSP; - -struct RLS { /* Structure is in Big Endian format */ - uint32_t rls; -#define rls_rsvd_SHIFT 24 -#define rls_rsvd_MASK 0x000000ff -#define rls_rsvd_WORD rls -#define rls_did_SHIFT 0 -#define rls_did_MASK 0x00ffffff -#define rls_did_WORD rls -}; - -struct RLS_RSP { /* Structure is in Big Endian format */ - uint32_t linkFailureCnt; - uint32_t lossSyncCnt; - uint32_t lossSignalCnt; - uint32_t primSeqErrCnt; - uint32_t invalidXmitWord; - uint32_t crcCnt; -}; - -struct RRQ { /* Structure is in Big Endian format */ - uint32_t rrq; -#define rrq_rsvd_SHIFT 24 -#define rrq_rsvd_MASK 0x000000ff -#define rrq_rsvd_WORD rrq -#define rrq_did_SHIFT 0 -#define rrq_did_MASK 0x00ffffff -#define rrq_did_WORD rrq - uint32_t rrq_exchg; -#define rrq_oxid_SHIFT 16 -#define rrq_oxid_MASK 0xffff -#define rrq_oxid_WORD rrq_exchg -#define rrq_rxid_SHIFT 0 -#define rrq_rxid_MASK 0xffff -#define rrq_rxid_WORD rrq_exchg -}; - -#define LPFC_MAX_VFN_PER_PFN 255 /* Maximum VFs allowed per ARI */ -#define LPFC_DEF_VFN_PER_PFN 0 /* Default VFs due to platform limitation*/ - -struct RTV_RSP { /* Structure is in Big Endian format */ - uint32_t ratov; - uint32_t edtov; - uint32_t qtov; -#define qtov_rsvd0_SHIFT 28 -#define qtov_rsvd0_MASK 0x0000000f -#define qtov_rsvd0_WORD qtov /* reserved */ -#define qtov_edtovres_SHIFT 27 -#define qtov_edtovres_MASK 0x00000001 -#define qtov_edtovres_WORD qtov /* E_D_TOV Resolution */ -#define qtov__rsvd1_SHIFT 19 -#define qtov_rsvd1_MASK 0x0000003f -#define qtov_rsvd1_WORD qtov /* reserved */ -#define qtov_rttov_SHIFT 18 -#define qtov_rttov_MASK 0x00000001 -#define qtov_rttov_WORD qtov /* R_T_TOV value */ -#define qtov_rsvd2_SHIFT 0 -#define qtov_rsvd2_MASK 0x0003ffff -#define qtov_rsvd2_WORD qtov /* reserved */ -}; - - -typedef struct _RPL { /* Structure is in Big Endian format */ - uint32_t maxsize; - uint32_t index; -} RPL; - -typedef struct _PORT_NUM_BLK { - uint32_t portNum; - uint32_t portID; - struct lpfc_name portName; -} PORT_NUM_BLK; - -typedef struct _RPL_RSP { /* Structure is in Big Endian format */ - uint32_t listLen; - uint32_t index; - PORT_NUM_BLK port_num_blk; -} RPL_RSP; - -/* This is used for RSCN command */ -typedef struct _D_ID { /* Structure is in Big Endian format */ - union { - uint32_t word; - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t resv; - uint8_t domain; - uint8_t area; - uint8_t id; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t id; - uint8_t area; - uint8_t domain; - uint8_t resv; -#endif - } b; - } un; -} D_ID; - -#define RSCN_ADDRESS_FORMAT_PORT 0x0 -#define RSCN_ADDRESS_FORMAT_AREA 0x1 -#define RSCN_ADDRESS_FORMAT_DOMAIN 0x2 -#define RSCN_ADDRESS_FORMAT_FABRIC 0x3 -#define RSCN_ADDRESS_FORMAT_MASK 0x3 - -/* - * Structure to define all ELS Payload types - */ - -typedef struct _ELS_PKT { /* Structure is in Big Endian format */ - uint8_t elsCode; /* FC Word 0, bit 24:31 */ - uint8_t elsByte1; - uint8_t elsByte2; - uint8_t elsByte3; - union { - struct ls_rjt lsRjt; /* Payload for LS_RJT ELS response */ - struct serv_parm logi; /* Payload for PLOGI/FLOGI/PDISC/ACC */ - LOGO logo; /* Payload for PLOGO/FLOGO/ACC */ - PRLI prli; /* Payload for PRLI/ACC */ - PRLO prlo; /* Payload for PRLO/ACC */ - ADISC adisc; /* Payload for ADISC/ACC */ - FARP farp; /* Payload for FARP/ACC */ - FAN fan; /* Payload for FAN */ - SCR scr; /* Payload for SCR/ACC */ - RNID rnid; /* Payload for RNID */ - uint8_t pad[128 - 4]; /* Pad out to payload of 128 bytes */ - } un; -} ELS_PKT; - -/* - * FDMI - * HBA MAnagement Operations Command Codes - */ -#define SLI_MGMT_GRHL 0x100 /* Get registered HBA list */ -#define SLI_MGMT_GHAT 0x101 /* Get HBA attributes */ -#define SLI_MGMT_GRPL 0x102 /* Get registered Port list */ -#define SLI_MGMT_GPAT 0x110 /* Get Port attributes */ -#define SLI_MGMT_RHBA 0x200 /* Register HBA */ -#define SLI_MGMT_RHAT 0x201 /* Register HBA attributes */ -#define SLI_MGMT_RPRT 0x210 /* Register Port */ -#define SLI_MGMT_RPA 0x211 /* Register Port attributes */ -#define SLI_MGMT_DHBA 0x300 /* De-register HBA */ -#define SLI_MGMT_DPRT 0x310 /* De-register Port */ - -/* - * Management Service Subtypes - */ -#define SLI_CT_FDMI_Subtypes 0x10 - -/* - * HBA Management Service Reject Code - */ -#define REJECT_CODE 0x9 /* Unable to perform command request */ - -/* - * HBA Management Service Reject Reason Code - * Please refer to the Reason Codes above - */ - -/* - * HBA Attribute Types - */ -#define NODE_NAME 0x1 -#define MANUFACTURER 0x2 -#define SERIAL_NUMBER 0x3 -#define MODEL 0x4 -#define MODEL_DESCRIPTION 0x5 -#define HARDWARE_VERSION 0x6 -#define DRIVER_VERSION 0x7 -#define OPTION_ROM_VERSION 0x8 -#define FIRMWARE_VERSION 0x9 -#define OS_NAME_VERSION 0xa -#define MAX_CT_PAYLOAD_LEN 0xb - -/* - * Port Attrubute Types - */ -#define SUPPORTED_FC4_TYPES 0x1 -#define SUPPORTED_SPEED 0x2 -#define PORT_SPEED 0x3 -#define MAX_FRAME_SIZE 0x4 -#define OS_DEVICE_NAME 0x5 -#define HOST_NAME 0x6 - -union AttributesDef { - /* Structure is in Big Endian format */ - struct { - uint32_t AttrType:16; - uint32_t AttrLen:16; - } bits; - uint32_t word; -}; - - -/* - * HBA Attribute Entry (8 - 260 bytes) - */ -typedef struct { - union AttributesDef ad; - union { - uint32_t VendorSpecific; - uint8_t Manufacturer[64]; - uint8_t SerialNumber[64]; - uint8_t Model[256]; - uint8_t ModelDescription[256]; - uint8_t HardwareVersion[256]; - uint8_t DriverVersion[256]; - uint8_t OptionROMVersion[256]; - uint8_t FirmwareVersion[256]; - struct lpfc_name NodeName; - uint8_t SupportFC4Types[32]; - uint32_t SupportSpeed; - uint32_t PortSpeed; - uint32_t MaxFrameSize; - uint8_t OsDeviceName[256]; - uint8_t OsNameVersion[256]; - uint32_t MaxCTPayloadLen; - uint8_t HostName[256]; - } un; -} ATTRIBUTE_ENTRY; - -/* - * HBA Attribute Block - */ -typedef struct { - uint32_t EntryCnt; /* Number of HBA attribute entries */ - ATTRIBUTE_ENTRY Entry; /* Variable-length array */ -} ATTRIBUTE_BLOCK; - -/* - * Port Entry - */ -typedef struct { - struct lpfc_name PortName; -} PORT_ENTRY; - -/* - * HBA Identifier - */ -typedef struct { - struct lpfc_name PortName; -} HBA_IDENTIFIER; - -/* - * Registered Port List Format - */ -typedef struct { - uint32_t EntryCnt; - PORT_ENTRY pe; /* Variable-length array */ -} REG_PORT_LIST; - -/* - * Register HBA(RHBA) - */ -typedef struct { - HBA_IDENTIFIER hi; - REG_PORT_LIST rpl; /* variable-length array */ -/* ATTRIBUTE_BLOCK ab; */ -} REG_HBA; - -/* - * Register HBA Attributes (RHAT) - */ -typedef struct { - struct lpfc_name HBA_PortName; - ATTRIBUTE_BLOCK ab; -} REG_HBA_ATTRIBUTE; - -/* - * Register Port Attributes (RPA) - */ -typedef struct { - struct lpfc_name PortName; - ATTRIBUTE_BLOCK ab; -} REG_PORT_ATTRIBUTE; - -/* - * Get Registered HBA List (GRHL) Accept Payload Format - */ -typedef struct { - uint32_t HBA__Entry_Cnt; /* Number of Registered HBA Identifiers */ - struct lpfc_name HBA_PortName; /* Variable-length array */ -} GRHL_ACC_PAYLOAD; - -/* - * Get Registered Port List (GRPL) Accept Payload Format - */ -typedef struct { - uint32_t RPL_Entry_Cnt; /* Number of Registered Port Entries */ - PORT_ENTRY Reg_Port_Entry[1]; /* Variable-length array */ -} GRPL_ACC_PAYLOAD; - -/* - * Get Port Attributes (GPAT) Accept Payload Format - */ - -typedef struct { - ATTRIBUTE_BLOCK pab; -} GPAT_ACC_PAYLOAD; - - -/* - * Begin HBA configuration parameters. - * The PCI configuration register BAR assignments are: - * BAR0, offset 0x10 - SLIM base memory address - * BAR1, offset 0x14 - SLIM base memory high address - * BAR2, offset 0x18 - REGISTER base memory address - * BAR3, offset 0x1c - REGISTER base memory high address - * BAR4, offset 0x20 - BIU I/O registers - * BAR5, offset 0x24 - REGISTER base io high address - */ - -/* Number of rings currently used and available. */ -#define MAX_CONFIGURED_RINGS 3 -#define MAX_RINGS 4 - -/* IOCB / Mailbox is owned by FireFly */ -#define OWN_CHIP 1 - -/* IOCB / Mailbox is owned by Host */ -#define OWN_HOST 0 - -/* Number of 4-byte words in an IOCB. */ -#define IOCB_WORD_SZ 8 - -/* network headers for Dfctl field */ -#define FC_NET_HDR 0x20 - -/* Start FireFly Register definitions */ -#define PCI_VENDOR_ID_EMULEX 0x10df -#define PCI_DEVICE_ID_FIREFLY 0x1ae5 -#define PCI_DEVICE_ID_PROTEUS_VF 0xe100 -#define PCI_DEVICE_ID_BALIUS 0xe131 -#define PCI_DEVICE_ID_PROTEUS_PF 0xe180 -#define PCI_DEVICE_ID_LANCER_FC 0xe200 -#define PCI_DEVICE_ID_LANCER_FC_VF 0xe208 -#define PCI_DEVICE_ID_LANCER_FCOE 0xe260 -#define PCI_DEVICE_ID_LANCER_FCOE_VF 0xe268 -#define PCI_DEVICE_ID_SAT_SMB 0xf011 -#define PCI_DEVICE_ID_SAT_MID 0xf015 -#define PCI_DEVICE_ID_RFLY 0xf095 -#define PCI_DEVICE_ID_PFLY 0xf098 -#define PCI_DEVICE_ID_LP101 0xf0a1 -#define PCI_DEVICE_ID_TFLY 0xf0a5 -#define PCI_DEVICE_ID_BSMB 0xf0d1 -#define PCI_DEVICE_ID_BMID 0xf0d5 -#define PCI_DEVICE_ID_ZSMB 0xf0e1 -#define PCI_DEVICE_ID_ZMID 0xf0e5 -#define PCI_DEVICE_ID_NEPTUNE 0xf0f5 -#define PCI_DEVICE_ID_NEPTUNE_SCSP 0xf0f6 -#define PCI_DEVICE_ID_NEPTUNE_DCSP 0xf0f7 -#define PCI_DEVICE_ID_SAT 0xf100 -#define PCI_DEVICE_ID_SAT_SCSP 0xf111 -#define PCI_DEVICE_ID_SAT_DCSP 0xf112 -#define PCI_DEVICE_ID_FALCON 0xf180 -#define PCI_DEVICE_ID_SUPERFLY 0xf700 -#define PCI_DEVICE_ID_DRAGONFLY 0xf800 -#define PCI_DEVICE_ID_CENTAUR 0xf900 -#define PCI_DEVICE_ID_PEGASUS 0xf980 -#define PCI_DEVICE_ID_THOR 0xfa00 -#define PCI_DEVICE_ID_VIPER 0xfb00 -#define PCI_DEVICE_ID_LP10000S 0xfc00 -#define PCI_DEVICE_ID_LP11000S 0xfc10 -#define PCI_DEVICE_ID_LPE11000S 0xfc20 -#define PCI_DEVICE_ID_SAT_S 0xfc40 -#define PCI_DEVICE_ID_PROTEUS_S 0xfc50 -#define PCI_DEVICE_ID_HELIOS 0xfd00 -#define PCI_DEVICE_ID_HELIOS_SCSP 0xfd11 -#define PCI_DEVICE_ID_HELIOS_DCSP 0xfd12 -#define PCI_DEVICE_ID_ZEPHYR 0xfe00 -#define PCI_DEVICE_ID_HORNET 0xfe05 -#define PCI_DEVICE_ID_ZEPHYR_SCSP 0xfe11 -#define PCI_DEVICE_ID_ZEPHYR_DCSP 0xfe12 -#define PCI_VENDOR_ID_SERVERENGINE 0x19a2 -#define PCI_DEVICE_ID_TIGERSHARK 0x0704 -#define PCI_DEVICE_ID_TOMCAT 0x0714 - -#define JEDEC_ID_ADDRESS 0x0080001c -#define FIREFLY_JEDEC_ID 0x1ACC -#define SUPERFLY_JEDEC_ID 0x0020 -#define DRAGONFLY_JEDEC_ID 0x0021 -#define DRAGONFLY_V2_JEDEC_ID 0x0025 -#define CENTAUR_2G_JEDEC_ID 0x0026 -#define CENTAUR_1G_JEDEC_ID 0x0028 -#define PEGASUS_ORION_JEDEC_ID 0x0036 -#define PEGASUS_JEDEC_ID 0x0038 -#define THOR_JEDEC_ID 0x0012 -#define HELIOS_JEDEC_ID 0x0364 -#define ZEPHYR_JEDEC_ID 0x0577 -#define VIPER_JEDEC_ID 0x4838 -#define SATURN_JEDEC_ID 0x1004 -#define HORNET_JDEC_ID 0x2057706D - -#define JEDEC_ID_MASK 0x0FFFF000 -#define JEDEC_ID_SHIFT 12 -#define FC_JEDEC_ID(id) ((id & JEDEC_ID_MASK) >> JEDEC_ID_SHIFT) - -typedef struct { /* FireFly BIU registers */ - uint32_t hostAtt; /* See definitions for Host Attention - register */ - uint32_t chipAtt; /* See definitions for Chip Attention - register */ - uint32_t hostStatus; /* See definitions for Host Status register */ - uint32_t hostControl; /* See definitions for Host Control register */ - uint32_t buiConfig; /* See definitions for BIU configuration - register */ -} FF_REGS; - -/* IO Register size in bytes */ -#define FF_REG_AREA_SIZE 256 - -/* Host Attention Register */ - -#define HA_REG_OFFSET 0 /* Byte offset from register base address */ - -#define HA_R0RE_REQ 0x00000001 /* Bit 0 */ -#define HA_R0CE_RSP 0x00000002 /* Bit 1 */ -#define HA_R0ATT 0x00000008 /* Bit 3 */ -#define HA_R1RE_REQ 0x00000010 /* Bit 4 */ -#define HA_R1CE_RSP 0x00000020 /* Bit 5 */ -#define HA_R1ATT 0x00000080 /* Bit 7 */ -#define HA_R2RE_REQ 0x00000100 /* Bit 8 */ -#define HA_R2CE_RSP 0x00000200 /* Bit 9 */ -#define HA_R2ATT 0x00000800 /* Bit 11 */ -#define HA_R3RE_REQ 0x00001000 /* Bit 12 */ -#define HA_R3CE_RSP 0x00002000 /* Bit 13 */ -#define HA_R3ATT 0x00008000 /* Bit 15 */ -#define HA_LATT 0x20000000 /* Bit 29 */ -#define HA_MBATT 0x40000000 /* Bit 30 */ -#define HA_ERATT 0x80000000 /* Bit 31 */ - -#define HA_RXRE_REQ 0x00000001 /* Bit 0 */ -#define HA_RXCE_RSP 0x00000002 /* Bit 1 */ -#define HA_RXATT 0x00000008 /* Bit 3 */ -#define HA_RXMASK 0x0000000f - -#define HA_R0_CLR_MSK (HA_R0RE_REQ | HA_R0CE_RSP | HA_R0ATT) -#define HA_R1_CLR_MSK (HA_R1RE_REQ | HA_R1CE_RSP | HA_R1ATT) -#define HA_R2_CLR_MSK (HA_R2RE_REQ | HA_R2CE_RSP | HA_R2ATT) -#define HA_R3_CLR_MSK (HA_R3RE_REQ | HA_R3CE_RSP | HA_R3ATT) - -#define HA_R0_POS 3 -#define HA_R1_POS 7 -#define HA_R2_POS 11 -#define HA_R3_POS 15 -#define HA_LE_POS 29 -#define HA_MB_POS 30 -#define HA_ER_POS 31 -/* Chip Attention Register */ - -#define CA_REG_OFFSET 4 /* Byte offset from register base address */ - -#define CA_R0CE_REQ 0x00000001 /* Bit 0 */ -#define CA_R0RE_RSP 0x00000002 /* Bit 1 */ -#define CA_R0ATT 0x00000008 /* Bit 3 */ -#define CA_R1CE_REQ 0x00000010 /* Bit 4 */ -#define CA_R1RE_RSP 0x00000020 /* Bit 5 */ -#define CA_R1ATT 0x00000080 /* Bit 7 */ -#define CA_R2CE_REQ 0x00000100 /* Bit 8 */ -#define CA_R2RE_RSP 0x00000200 /* Bit 9 */ -#define CA_R2ATT 0x00000800 /* Bit 11 */ -#define CA_R3CE_REQ 0x00001000 /* Bit 12 */ -#define CA_R3RE_RSP 0x00002000 /* Bit 13 */ -#define CA_R3ATT 0x00008000 /* Bit 15 */ -#define CA_MBATT 0x40000000 /* Bit 30 */ - -/* Host Status Register */ - -#define HS_REG_OFFSET 8 /* Byte offset from register base address */ - -#define HS_MBRDY 0x00400000 /* Bit 22 */ -#define HS_FFRDY 0x00800000 /* Bit 23 */ -#define HS_FFER8 0x01000000 /* Bit 24 */ -#define HS_FFER7 0x02000000 /* Bit 25 */ -#define HS_FFER6 0x04000000 /* Bit 26 */ -#define HS_FFER5 0x08000000 /* Bit 27 */ -#define HS_FFER4 0x10000000 /* Bit 28 */ -#define HS_FFER3 0x20000000 /* Bit 29 */ -#define HS_FFER2 0x40000000 /* Bit 30 */ -#define HS_FFER1 0x80000000 /* Bit 31 */ -#define HS_CRIT_TEMP 0x00000100 /* Bit 8 */ -#define HS_FFERM 0xFF000100 /* Mask for error bits 31:24 and 8 */ -#define UNPLUG_ERR 0x00000001 /* Indicate pci hot unplug */ -/* Host Control Register */ - -#define HC_REG_OFFSET 12 /* Byte offset from register base address */ - -#define HC_MBINT_ENA 0x00000001 /* Bit 0 */ -#define HC_R0INT_ENA 0x00000002 /* Bit 1 */ -#define HC_R1INT_ENA 0x00000004 /* Bit 2 */ -#define HC_R2INT_ENA 0x00000008 /* Bit 3 */ -#define HC_R3INT_ENA 0x00000010 /* Bit 4 */ -#define HC_INITHBI 0x02000000 /* Bit 25 */ -#define HC_INITMB 0x04000000 /* Bit 26 */ -#define HC_INITFF 0x08000000 /* Bit 27 */ -#define HC_LAINT_ENA 0x20000000 /* Bit 29 */ -#define HC_ERINT_ENA 0x80000000 /* Bit 31 */ - -/* Message Signaled Interrupt eXtension (MSI-X) message identifiers */ -#define MSIX_DFLT_ID 0 -#define MSIX_RNG0_ID 0 -#define MSIX_RNG1_ID 1 -#define MSIX_RNG2_ID 2 -#define MSIX_RNG3_ID 3 - -#define MSIX_LINK_ID 4 -#define MSIX_MBOX_ID 5 - -#define MSIX_SPARE0_ID 6 -#define MSIX_SPARE1_ID 7 - -/* Mailbox Commands */ -#define MBX_SHUTDOWN 0x00 /* terminate testing */ -#define MBX_LOAD_SM 0x01 -#define MBX_READ_NV 0x02 -#define MBX_WRITE_NV 0x03 -#define MBX_RUN_BIU_DIAG 0x04 -#define MBX_INIT_LINK 0x05 -#define MBX_DOWN_LINK 0x06 -#define MBX_CONFIG_LINK 0x07 -#define MBX_CONFIG_RING 0x09 -#define MBX_RESET_RING 0x0A -#define MBX_READ_CONFIG 0x0B -#define MBX_READ_RCONFIG 0x0C -#define MBX_READ_SPARM 0x0D -#define MBX_READ_STATUS 0x0E -#define MBX_READ_RPI 0x0F -#define MBX_READ_XRI 0x10 -#define MBX_READ_REV 0x11 -#define MBX_READ_LNK_STAT 0x12 -#define MBX_REG_LOGIN 0x13 -#define MBX_UNREG_LOGIN 0x14 -#define MBX_CLEAR_LA 0x16 -#define MBX_DUMP_MEMORY 0x17 -#define MBX_DUMP_CONTEXT 0x18 -#define MBX_RUN_DIAGS 0x19 -#define MBX_RESTART 0x1A -#define MBX_UPDATE_CFG 0x1B -#define MBX_DOWN_LOAD 0x1C -#define MBX_DEL_LD_ENTRY 0x1D -#define MBX_RUN_PROGRAM 0x1E -#define MBX_SET_MASK 0x20 -#define MBX_SET_VARIABLE 0x21 -#define MBX_UNREG_D_ID 0x23 -#define MBX_KILL_BOARD 0x24 -#define MBX_CONFIG_FARP 0x25 -#define MBX_BEACON 0x2A -#define MBX_CONFIG_MSI 0x30 -#define MBX_HEARTBEAT 0x31 -#define MBX_WRITE_VPARMS 0x32 -#define MBX_ASYNCEVT_ENABLE 0x33 -#define MBX_READ_EVENT_LOG_STATUS 0x37 -#define MBX_READ_EVENT_LOG 0x38 -#define MBX_WRITE_EVENT_LOG 0x39 - -#define MBX_PORT_CAPABILITIES 0x3B -#define MBX_PORT_IOV_CONTROL 0x3C - -#define MBX_CONFIG_HBQ 0x7C -#define MBX_LOAD_AREA 0x81 -#define MBX_RUN_BIU_DIAG64 0x84 -#define MBX_CONFIG_PORT 0x88 -#define MBX_READ_SPARM64 0x8D -#define MBX_READ_RPI64 0x8F -#define MBX_REG_LOGIN64 0x93 -#define MBX_READ_TOPOLOGY 0x95 -#define MBX_REG_VPI 0x96 -#define MBX_UNREG_VPI 0x97 - -#define MBX_WRITE_WWN 0x98 -#define MBX_SET_DEBUG 0x99 -#define MBX_LOAD_EXP_ROM 0x9C -#define MBX_SLI4_CONFIG 0x9B -#define MBX_SLI4_REQ_FTRS 0x9D -#define MBX_MAX_CMDS 0x9E -#define MBX_RESUME_RPI 0x9E -#define MBX_SLI2_CMD_MASK 0x80 -#define MBX_REG_VFI 0x9F -#define MBX_REG_FCFI 0xA0 -#define MBX_UNREG_VFI 0xA1 -#define MBX_UNREG_FCFI 0xA2 -#define MBX_INIT_VFI 0xA3 -#define MBX_INIT_VPI 0xA4 - -#define MBX_AUTH_PORT 0xF8 -#define MBX_SECURITY_MGMT 0xF9 - -/* IOCB Commands */ - -#define CMD_RCV_SEQUENCE_CX 0x01 -#define CMD_XMIT_SEQUENCE_CR 0x02 -#define CMD_XMIT_SEQUENCE_CX 0x03 -#define CMD_XMIT_BCAST_CN 0x04 -#define CMD_XMIT_BCAST_CX 0x05 -#define CMD_QUE_RING_BUF_CN 0x06 -#define CMD_QUE_XRI_BUF_CX 0x07 -#define CMD_IOCB_CONTINUE_CN 0x08 -#define CMD_RET_XRI_BUF_CX 0x09 -#define CMD_ELS_REQUEST_CR 0x0A -#define CMD_ELS_REQUEST_CX 0x0B -#define CMD_RCV_ELS_REQ_CX 0x0D -#define CMD_ABORT_XRI_CN 0x0E -#define CMD_ABORT_XRI_CX 0x0F -#define CMD_CLOSE_XRI_CN 0x10 -#define CMD_CLOSE_XRI_CX 0x11 -#define CMD_CREATE_XRI_CR 0x12 -#define CMD_CREATE_XRI_CX 0x13 -#define CMD_GET_RPI_CN 0x14 -#define CMD_XMIT_ELS_RSP_CX 0x15 -#define CMD_GET_RPI_CR 0x16 -#define CMD_XRI_ABORTED_CX 0x17 -#define CMD_FCP_IWRITE_CR 0x18 -#define CMD_FCP_IWRITE_CX 0x19 -#define CMD_FCP_IREAD_CR 0x1A -#define CMD_FCP_IREAD_CX 0x1B -#define CMD_FCP_ICMND_CR 0x1C -#define CMD_FCP_ICMND_CX 0x1D -#define CMD_FCP_TSEND_CX 0x1F -#define CMD_FCP_TRECEIVE_CX 0x21 -#define CMD_FCP_TRSP_CX 0x23 -#define CMD_FCP_AUTO_TRSP_CX 0x29 - -#define CMD_ADAPTER_MSG 0x20 -#define CMD_ADAPTER_DUMP 0x22 - -/* SLI_2 IOCB Command Set */ - -#define CMD_ASYNC_STATUS 0x7C -#define CMD_RCV_SEQUENCE64_CX 0x81 -#define CMD_XMIT_SEQUENCE64_CR 0x82 -#define CMD_XMIT_SEQUENCE64_CX 0x83 -#define CMD_XMIT_BCAST64_CN 0x84 -#define CMD_XMIT_BCAST64_CX 0x85 -#define CMD_QUE_RING_BUF64_CN 0x86 -#define CMD_QUE_XRI_BUF64_CX 0x87 -#define CMD_IOCB_CONTINUE64_CN 0x88 -#define CMD_RET_XRI_BUF64_CX 0x89 -#define CMD_ELS_REQUEST64_CR 0x8A -#define CMD_ELS_REQUEST64_CX 0x8B -#define CMD_ABORT_MXRI64_CN 0x8C -#define CMD_RCV_ELS_REQ64_CX 0x8D -#define CMD_XMIT_ELS_RSP64_CX 0x95 -#define CMD_XMIT_BLS_RSP64_CX 0x97 -#define CMD_FCP_IWRITE64_CR 0x98 -#define CMD_FCP_IWRITE64_CX 0x99 -#define CMD_FCP_IREAD64_CR 0x9A -#define CMD_FCP_IREAD64_CX 0x9B -#define CMD_FCP_ICMND64_CR 0x9C -#define CMD_FCP_ICMND64_CX 0x9D -#define CMD_FCP_TSEND64_CX 0x9F -#define CMD_FCP_TRECEIVE64_CX 0xA1 -#define CMD_FCP_TRSP64_CX 0xA3 - -#define CMD_QUE_XRI64_CX 0xB3 -#define CMD_IOCB_RCV_SEQ64_CX 0xB5 -#define CMD_IOCB_RCV_ELS64_CX 0xB7 -#define CMD_IOCB_RET_XRI64_CX 0xB9 -#define CMD_IOCB_RCV_CONT64_CX 0xBB - -#define CMD_GEN_REQUEST64_CR 0xC2 -#define CMD_GEN_REQUEST64_CX 0xC3 - -/* Unhandled SLI-3 Commands */ -#define CMD_IOCB_XMIT_MSEQ64_CR 0xB0 -#define CMD_IOCB_XMIT_MSEQ64_CX 0xB1 -#define CMD_IOCB_RCV_SEQ_LIST64_CX 0xC1 -#define CMD_IOCB_RCV_ELS_LIST64_CX 0xCD -#define CMD_IOCB_CLOSE_EXTENDED_CN 0xB6 -#define CMD_IOCB_ABORT_EXTENDED_CN 0xBA -#define CMD_IOCB_RET_HBQE64_CN 0xCA -#define CMD_IOCB_FCP_IBIDIR64_CR 0xAC -#define CMD_IOCB_FCP_IBIDIR64_CX 0xAD -#define CMD_IOCB_FCP_ITASKMGT64_CX 0xAF -#define CMD_IOCB_LOGENTRY_CN 0x94 -#define CMD_IOCB_LOGENTRY_ASYNC_CN 0x96 - -/* Data Security SLI Commands */ -#define DSSCMD_IWRITE64_CR 0xF8 -#define DSSCMD_IWRITE64_CX 0xF9 -#define DSSCMD_IREAD64_CR 0xFA -#define DSSCMD_IREAD64_CX 0xFB - -#define CMD_MAX_IOCB_CMD 0xFB -#define CMD_IOCB_MASK 0xff - -#define MAX_MSG_DATA 28 /* max msg data in CMD_ADAPTER_MSG - iocb */ -#define LPFC_MAX_ADPTMSG 32 /* max msg data */ -/* - * Define Status - */ -#define MBX_SUCCESS 0 -#define MBXERR_NUM_RINGS 1 -#define MBXERR_NUM_IOCBS 2 -#define MBXERR_IOCBS_EXCEEDED 3 -#define MBXERR_BAD_RING_NUMBER 4 -#define MBXERR_MASK_ENTRIES_RANGE 5 -#define MBXERR_MASKS_EXCEEDED 6 -#define MBXERR_BAD_PROFILE 7 -#define MBXERR_BAD_DEF_CLASS 8 -#define MBXERR_BAD_MAX_RESPONDER 9 -#define MBXERR_BAD_MAX_ORIGINATOR 10 -#define MBXERR_RPI_REGISTERED 11 -#define MBXERR_RPI_FULL 12 -#define MBXERR_NO_RESOURCES 13 -#define MBXERR_BAD_RCV_LENGTH 14 -#define MBXERR_DMA_ERROR 15 -#define MBXERR_ERROR 16 -#define MBXERR_LINK_DOWN 0x33 -#define MBXERR_SEC_NO_PERMISSION 0xF02 -#define MBX_NOT_FINISHED 255 - -#define MBX_BUSY 0xffffff /* Attempted cmd to busy Mailbox */ -#define MBX_TIMEOUT 0xfffffe /* time-out expired waiting for */ - -#define TEMPERATURE_OFFSET 0xB0 /* Slim offset for critical temperature event */ - -/* - * Begin Structure Definitions for Mailbox Commands - */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t tval; - uint8_t tmask; - uint8_t rval; - uint8_t rmask; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t rmask; - uint8_t rval; - uint8_t tmask; - uint8_t tval; -#endif -} RR_REG; - -struct ulp_bde { - uint32_t bdeAddress; -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t bdeReserved:4; - uint32_t bdeAddrHigh:4; - uint32_t bdeSize:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t bdeSize:24; - uint32_t bdeAddrHigh:4; - uint32_t bdeReserved:4; -#endif -}; - -typedef struct ULP_BDL { /* SLI-2 */ -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t bdeFlags:8; /* BDL Flags */ - uint32_t bdeSize:24; /* Size of BDL array in host memory (bytes) */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t bdeSize:24; /* Size of BDL array in host memory (bytes) */ - uint32_t bdeFlags:8; /* BDL Flags */ -#endif - - uint32_t addrLow; /* Address 0:31 */ - uint32_t addrHigh; /* Address 32:63 */ - uint32_t ulpIoTag32; /* Can be used for 32 bit I/O Tag */ -} ULP_BDL; - -/* - * BlockGuard Definitions - */ - -enum lpfc_protgrp_type { - LPFC_PG_TYPE_INVALID = 0, /* used to indicate errors */ - LPFC_PG_TYPE_NO_DIF, /* no DIF data pointed to by prot grp */ - LPFC_PG_TYPE_EMBD_DIF, /* DIF is embedded (inline) with data */ - LPFC_PG_TYPE_DIF_BUF /* DIF has its own scatter/gather list */ -}; - -/* PDE Descriptors */ -#define LPFC_PDE5_DESCRIPTOR 0x85 -#define LPFC_PDE6_DESCRIPTOR 0x86 -#define LPFC_PDE7_DESCRIPTOR 0x87 - -/* BlockGuard Opcodes */ -#define BG_OP_IN_NODIF_OUT_CRC 0x0 -#define BG_OP_IN_CRC_OUT_NODIF 0x1 -#define BG_OP_IN_NODIF_OUT_CSUM 0x2 -#define BG_OP_IN_CSUM_OUT_NODIF 0x3 -#define BG_OP_IN_CRC_OUT_CRC 0x4 -#define BG_OP_IN_CSUM_OUT_CSUM 0x5 -#define BG_OP_IN_CRC_OUT_CSUM 0x6 -#define BG_OP_IN_CSUM_OUT_CRC 0x7 - -struct lpfc_pde5 { - uint32_t word0; -#define pde5_type_SHIFT 24 -#define pde5_type_MASK 0x000000ff -#define pde5_type_WORD word0 -#define pde5_rsvd0_SHIFT 0 -#define pde5_rsvd0_MASK 0x00ffffff -#define pde5_rsvd0_WORD word0 - uint32_t reftag; /* Reference Tag Value */ - uint32_t reftagtr; /* Reference Tag Translation Value */ -}; - -struct lpfc_pde6 { - uint32_t word0; -#define pde6_type_SHIFT 24 -#define pde6_type_MASK 0x000000ff -#define pde6_type_WORD word0 -#define pde6_rsvd0_SHIFT 0 -#define pde6_rsvd0_MASK 0x00ffffff -#define pde6_rsvd0_WORD word0 - uint32_t word1; -#define pde6_rsvd1_SHIFT 26 -#define pde6_rsvd1_MASK 0x0000003f -#define pde6_rsvd1_WORD word1 -#define pde6_na_SHIFT 25 -#define pde6_na_MASK 0x00000001 -#define pde6_na_WORD word1 -#define pde6_rsvd2_SHIFT 16 -#define pde6_rsvd2_MASK 0x000001FF -#define pde6_rsvd2_WORD word1 -#define pde6_apptagtr_SHIFT 0 -#define pde6_apptagtr_MASK 0x0000ffff -#define pde6_apptagtr_WORD word1 - uint32_t word2; -#define pde6_optx_SHIFT 28 -#define pde6_optx_MASK 0x0000000f -#define pde6_optx_WORD word2 -#define pde6_oprx_SHIFT 24 -#define pde6_oprx_MASK 0x0000000f -#define pde6_oprx_WORD word2 -#define pde6_nr_SHIFT 23 -#define pde6_nr_MASK 0x00000001 -#define pde6_nr_WORD word2 -#define pde6_ce_SHIFT 22 -#define pde6_ce_MASK 0x00000001 -#define pde6_ce_WORD word2 -#define pde6_re_SHIFT 21 -#define pde6_re_MASK 0x00000001 -#define pde6_re_WORD word2 -#define pde6_ae_SHIFT 20 -#define pde6_ae_MASK 0x00000001 -#define pde6_ae_WORD word2 -#define pde6_ai_SHIFT 19 -#define pde6_ai_MASK 0x00000001 -#define pde6_ai_WORD word2 -#define pde6_bs_SHIFT 16 -#define pde6_bs_MASK 0x00000007 -#define pde6_bs_WORD word2 -#define pde6_apptagval_SHIFT 0 -#define pde6_apptagval_MASK 0x0000ffff -#define pde6_apptagval_WORD word2 -}; - -struct lpfc_pde7 { - uint32_t word0; -#define pde7_type_SHIFT 24 -#define pde7_type_MASK 0x000000ff -#define pde7_type_WORD word0 -#define pde7_rsvd0_SHIFT 0 -#define pde7_rsvd0_MASK 0x00ffffff -#define pde7_rsvd0_WORD word0 - uint32_t addrHigh; - uint32_t addrLow; -}; - -/* Structure for MB Command LOAD_SM and DOWN_LOAD */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd2:25; - uint32_t acknowledgment:1; - uint32_t version:1; - uint32_t erase_or_prog:1; - uint32_t update_flash:1; - uint32_t update_ram:1; - uint32_t method:1; - uint32_t load_cmplt:1; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t load_cmplt:1; - uint32_t method:1; - uint32_t update_ram:1; - uint32_t update_flash:1; - uint32_t erase_or_prog:1; - uint32_t version:1; - uint32_t acknowledgment:1; - uint32_t rsvd2:25; -#endif - - uint32_t dl_to_adr_low; - uint32_t dl_to_adr_high; - uint32_t dl_len; - union { - uint32_t dl_from_mbx_offset; - struct ulp_bde dl_from_bde; - struct ulp_bde64 dl_from_bde64; - } un; - -} LOAD_SM_VAR; - -/* Structure for MB Command READ_NVPARM (02) */ - -typedef struct { - uint32_t rsvd1[3]; /* Read as all one's */ - uint32_t rsvd2; /* Read as all zero's */ - uint32_t portname[2]; /* N_PORT name */ - uint32_t nodename[2]; /* NODE name */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t pref_DID:24; - uint32_t hardAL_PA:8; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t hardAL_PA:8; - uint32_t pref_DID:24; -#endif - - uint32_t rsvd3[21]; /* Read as all one's */ -} READ_NV_VAR; - -/* Structure for MB Command WRITE_NVPARMS (03) */ - -typedef struct { - uint32_t rsvd1[3]; /* Must be all one's */ - uint32_t rsvd2; /* Must be all zero's */ - uint32_t portname[2]; /* N_PORT name */ - uint32_t nodename[2]; /* NODE name */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t pref_DID:24; - uint32_t hardAL_PA:8; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t hardAL_PA:8; - uint32_t pref_DID:24; -#endif - - uint32_t rsvd3[21]; /* Must be all one's */ -} WRITE_NV_VAR; - -/* Structure for MB Command RUN_BIU_DIAG (04) */ -/* Structure for MB Command RUN_BIU_DIAG64 (0x84) */ - -typedef struct { - uint32_t rsvd1; - union { - struct { - struct ulp_bde xmit_bde; - struct ulp_bde rcv_bde; - } s1; - struct { - struct ulp_bde64 xmit_bde64; - struct ulp_bde64 rcv_bde64; - } s2; - } un; -} BIU_DIAG_VAR; - -/* Structure for MB command READ_EVENT_LOG (0x38) */ -struct READ_EVENT_LOG_VAR { - uint32_t word1; -#define lpfc_event_log_SHIFT 29 -#define lpfc_event_log_MASK 0x00000001 -#define lpfc_event_log_WORD word1 -#define USE_MAILBOX_RESPONSE 1 - uint32_t offset; - struct ulp_bde64 rcv_bde64; -}; - -/* Structure for MB Command INIT_LINK (05) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1:24; - uint32_t lipsr_AL_PA:8; /* AL_PA to issue Lip Selective Reset to */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t lipsr_AL_PA:8; /* AL_PA to issue Lip Selective Reset to */ - uint32_t rsvd1:24; -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t fabric_AL_PA; /* If using a Fabric Assigned AL_PA */ - uint8_t rsvd2; - uint16_t link_flags; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t link_flags; - uint8_t rsvd2; - uint8_t fabric_AL_PA; /* If using a Fabric Assigned AL_PA */ -#endif - -#define FLAGS_TOPOLOGY_MODE_LOOP_PT 0x00 /* Attempt loop then pt-pt */ -#define FLAGS_LOCAL_LB 0x01 /* link_flags (=1) ENDEC loopback */ -#define FLAGS_TOPOLOGY_MODE_PT_PT 0x02 /* Attempt pt-pt only */ -#define FLAGS_TOPOLOGY_MODE_LOOP 0x04 /* Attempt loop only */ -#define FLAGS_TOPOLOGY_MODE_PT_LOOP 0x06 /* Attempt pt-pt then loop */ -#define FLAGS_UNREG_LOGIN_ALL 0x08 /* UNREG_LOGIN all on link down */ -#define FLAGS_LIRP_LILP 0x80 /* LIRP / LILP is disabled */ - -#define FLAGS_TOPOLOGY_FAILOVER 0x0400 /* Bit 10 */ -#define FLAGS_LINK_SPEED 0x0800 /* Bit 11 */ -#define FLAGS_IMED_ABORT 0x04000 /* Bit 14 */ - - uint32_t link_speed; -#define LINK_SPEED_AUTO 0x0 /* Auto selection */ -#define LINK_SPEED_1G 0x1 /* 1 Gigabaud */ -#define LINK_SPEED_2G 0x2 /* 2 Gigabaud */ -#define LINK_SPEED_4G 0x4 /* 4 Gigabaud */ -#define LINK_SPEED_8G 0x8 /* 8 Gigabaud */ -#define LINK_SPEED_10G 0x10 /* 10 Gigabaud */ -#define LINK_SPEED_16G 0x11 /* 16 Gigabaud */ - -} INIT_LINK_VAR; - -/* Structure for MB Command DOWN_LINK (06) */ - -typedef struct { - uint32_t rsvd1; -} DOWN_LINK_VAR; - -/* Structure for MB Command CONFIG_LINK (07) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t cr:1; - uint32_t ci:1; - uint32_t cr_delay:6; - uint32_t cr_count:8; - uint32_t rsvd1:8; - uint32_t MaxBBC:8; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t MaxBBC:8; - uint32_t rsvd1:8; - uint32_t cr_count:8; - uint32_t cr_delay:6; - uint32_t ci:1; - uint32_t cr:1; -#endif - - uint32_t myId; - uint32_t rsvd2; - uint32_t edtov; - uint32_t arbtov; - uint32_t ratov; - uint32_t rttov; - uint32_t altov; - uint32_t crtov; - uint32_t citov; -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rrq_enable:1; - uint32_t rrq_immed:1; - uint32_t rsvd4:29; - uint32_t ack0_enable:1; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t ack0_enable:1; - uint32_t rsvd4:29; - uint32_t rrq_immed:1; - uint32_t rrq_enable:1; -#endif -} CONFIG_LINK; - -/* Structure for MB Command PART_SLIM (08) - * will be removed since SLI1 is no longer supported! - */ -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t offCiocb; - uint16_t numCiocb; - uint16_t offRiocb; - uint16_t numRiocb; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t numCiocb; - uint16_t offCiocb; - uint16_t numRiocb; - uint16_t offRiocb; -#endif -} RING_DEF; - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t unused1:24; - uint32_t numRing:8; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t numRing:8; - uint32_t unused1:24; -#endif - - RING_DEF ringdef[4]; - uint32_t hbainit; -} PART_SLIM_VAR; - -/* Structure for MB Command CONFIG_RING (09) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t unused2:6; - uint32_t recvSeq:1; - uint32_t recvNotify:1; - uint32_t numMask:8; - uint32_t profile:8; - uint32_t unused1:4; - uint32_t ring:4; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t ring:4; - uint32_t unused1:4; - uint32_t profile:8; - uint32_t numMask:8; - uint32_t recvNotify:1; - uint32_t recvSeq:1; - uint32_t unused2:6; -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t maxRespXchg; - uint16_t maxOrigXchg; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t maxOrigXchg; - uint16_t maxRespXchg; -#endif - - RR_REG rrRegs[6]; -} CONFIG_RING_VAR; - -/* Structure for MB Command RESET_RING (10) */ - -typedef struct { - uint32_t ring_no; -} RESET_RING_VAR; - -/* Structure for MB Command READ_CONFIG (11) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t cr:1; - uint32_t ci:1; - uint32_t cr_delay:6; - uint32_t cr_count:8; - uint32_t InitBBC:8; - uint32_t MaxBBC:8; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t MaxBBC:8; - uint32_t InitBBC:8; - uint32_t cr_count:8; - uint32_t cr_delay:6; - uint32_t ci:1; - uint32_t cr:1; -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t topology:8; - uint32_t myDid:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t myDid:24; - uint32_t topology:8; -#endif - - /* Defines for topology (defined previously) */ -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t AR:1; - uint32_t IR:1; - uint32_t rsvd1:29; - uint32_t ack0:1; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t ack0:1; - uint32_t rsvd1:29; - uint32_t IR:1; - uint32_t AR:1; -#endif - - uint32_t edtov; - uint32_t arbtov; - uint32_t ratov; - uint32_t rttov; - uint32_t altov; - uint32_t lmt; -#define LMT_RESERVED 0x000 /* Not used */ -#define LMT_1Gb 0x004 -#define LMT_2Gb 0x008 -#define LMT_4Gb 0x040 -#define LMT_8Gb 0x080 -#define LMT_10Gb 0x100 -#define LMT_16Gb 0x200 - uint32_t rsvd2; - uint32_t rsvd3; - uint32_t max_xri; - uint32_t max_iocb; - uint32_t max_rpi; - uint32_t avail_xri; - uint32_t avail_iocb; - uint32_t avail_rpi; - uint32_t max_vpi; - uint32_t rsvd4; - uint32_t rsvd5; - uint32_t avail_vpi; -} READ_CONFIG_VAR; - -/* Structure for MB Command READ_RCONFIG (12) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd2:7; - uint32_t recvNotify:1; - uint32_t numMask:8; - uint32_t profile:8; - uint32_t rsvd1:4; - uint32_t ring:4; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t ring:4; - uint32_t rsvd1:4; - uint32_t profile:8; - uint32_t numMask:8; - uint32_t recvNotify:1; - uint32_t rsvd2:7; -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t maxResp; - uint16_t maxOrig; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t maxOrig; - uint16_t maxResp; -#endif - - RR_REG rrRegs[6]; - -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t cmdRingOffset; - uint16_t cmdEntryCnt; - uint16_t rspRingOffset; - uint16_t rspEntryCnt; - uint16_t nextCmdOffset; - uint16_t rsvd3; - uint16_t nextRspOffset; - uint16_t rsvd4; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t cmdEntryCnt; - uint16_t cmdRingOffset; - uint16_t rspEntryCnt; - uint16_t rspRingOffset; - uint16_t rsvd3; - uint16_t nextCmdOffset; - uint16_t rsvd4; - uint16_t nextRspOffset; -#endif -} READ_RCONF_VAR; - -/* Structure for MB Command READ_SPARM (13) */ -/* Structure for MB Command READ_SPARM64 (0x8D) */ - -typedef struct { - uint32_t rsvd1; - uint32_t rsvd2; - union { - struct ulp_bde sp; /* This BDE points to struct serv_parm - structure */ - struct ulp_bde64 sp64; - } un; -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t rsvd3; - uint16_t vpi; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t vpi; - uint16_t rsvd3; -#endif -} READ_SPARM_VAR; - -/* Structure for MB Command READ_STATUS (14) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1:31; - uint32_t clrCounters:1; - uint16_t activeXriCnt; - uint16_t activeRpiCnt; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t clrCounters:1; - uint32_t rsvd1:31; - uint16_t activeRpiCnt; - uint16_t activeXriCnt; -#endif - - uint32_t xmitByteCnt; - uint32_t rcvByteCnt; - uint32_t xmitFrameCnt; - uint32_t rcvFrameCnt; - uint32_t xmitSeqCnt; - uint32_t rcvSeqCnt; - uint32_t totalOrigExchanges; - uint32_t totalRespExchanges; - uint32_t rcvPbsyCnt; - uint32_t rcvFbsyCnt; -} READ_STATUS_VAR; - -/* Structure for MB Command READ_RPI (15) */ -/* Structure for MB Command READ_RPI64 (0x8F) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t nextRpi; - uint16_t reqRpi; - uint32_t rsvd2:8; - uint32_t DID:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t reqRpi; - uint16_t nextRpi; - uint32_t DID:24; - uint32_t rsvd2:8; -#endif - - union { - struct ulp_bde sp; - struct ulp_bde64 sp64; - } un; - -} READ_RPI_VAR; - -/* Structure for MB Command READ_XRI (16) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t nextXri; - uint16_t reqXri; - uint16_t rsvd1; - uint16_t rpi; - uint32_t rsvd2:8; - uint32_t DID:24; - uint32_t rsvd3:8; - uint32_t SID:24; - uint32_t rsvd4; - uint8_t seqId; - uint8_t rsvd5; - uint16_t seqCount; - uint16_t oxId; - uint16_t rxId; - uint32_t rsvd6:30; - uint32_t si:1; - uint32_t exchOrig:1; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t reqXri; - uint16_t nextXri; - uint16_t rpi; - uint16_t rsvd1; - uint32_t DID:24; - uint32_t rsvd2:8; - uint32_t SID:24; - uint32_t rsvd3:8; - uint32_t rsvd4; - uint16_t seqCount; - uint8_t rsvd5; - uint8_t seqId; - uint16_t rxId; - uint16_t oxId; - uint32_t exchOrig:1; - uint32_t si:1; - uint32_t rsvd6:30; -#endif -} READ_XRI_VAR; - -/* Structure for MB Command READ_REV (17) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t cv:1; - uint32_t rr:1; - uint32_t rsvd2:2; - uint32_t v3req:1; - uint32_t v3rsp:1; - uint32_t rsvd1:25; - uint32_t rv:1; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t rv:1; - uint32_t rsvd1:25; - uint32_t v3rsp:1; - uint32_t v3req:1; - uint32_t rsvd2:2; - uint32_t rr:1; - uint32_t cv:1; -#endif - - uint32_t biuRev; - uint32_t smRev; - union { - uint32_t smFwRev; - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t ProgType; - uint8_t ProgId; - uint16_t ProgVer:4; - uint16_t ProgRev:4; - uint16_t ProgFixLvl:2; - uint16_t ProgDistType:2; - uint16_t DistCnt:4; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t DistCnt:4; - uint16_t ProgDistType:2; - uint16_t ProgFixLvl:2; - uint16_t ProgRev:4; - uint16_t ProgVer:4; - uint8_t ProgId; - uint8_t ProgType; -#endif - - } b; - } un; - uint32_t endecRev; -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t feaLevelHigh; - uint8_t feaLevelLow; - uint8_t fcphHigh; - uint8_t fcphLow; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t fcphLow; - uint8_t fcphHigh; - uint8_t feaLevelLow; - uint8_t feaLevelHigh; -#endif - - uint32_t postKernRev; - uint32_t opFwRev; - uint8_t opFwName[16]; - uint32_t sli1FwRev; - uint8_t sli1FwName[16]; - uint32_t sli2FwRev; - uint8_t sli2FwName[16]; - uint32_t sli3Feat; - uint32_t RandomData[6]; -} READ_REV_VAR; - -/* Structure for MB Command READ_LINK_STAT (18) */ - -typedef struct { - uint32_t rsvd1; - uint32_t linkFailureCnt; - uint32_t lossSyncCnt; - - uint32_t lossSignalCnt; - uint32_t primSeqErrCnt; - uint32_t invalidXmitWord; - uint32_t crcCnt; - uint32_t primSeqTimeout; - uint32_t elasticOverrun; - uint32_t arbTimeout; -} READ_LNK_VAR; - -/* Structure for MB Command REG_LOGIN (19) */ -/* Structure for MB Command REG_LOGIN64 (0x93) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t rsvd1; - uint16_t rpi; - uint32_t rsvd2:8; - uint32_t did:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t rpi; - uint16_t rsvd1; - uint32_t did:24; - uint32_t rsvd2:8; -#endif - - union { - struct ulp_bde sp; - struct ulp_bde64 sp64; - } un; - -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t rsvd6; - uint16_t vpi; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t vpi; - uint16_t rsvd6; -#endif - -} REG_LOGIN_VAR; - -/* Word 30 contents for REG_LOGIN */ -typedef union { - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t rsvd1:12; - uint16_t wd30_class:4; - uint16_t xri; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t xri; - uint16_t wd30_class:4; - uint16_t rsvd1:12; -#endif - } f; - uint32_t word; -} REG_WD30; - -/* Structure for MB Command UNREG_LOGIN (20) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t rsvd1; - uint16_t rpi; - uint32_t rsvd2; - uint32_t rsvd3; - uint32_t rsvd4; - uint32_t rsvd5; - uint16_t rsvd6; - uint16_t vpi; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t rpi; - uint16_t rsvd1; - uint32_t rsvd2; - uint32_t rsvd3; - uint32_t rsvd4; - uint32_t rsvd5; - uint16_t vpi; - uint16_t rsvd6; -#endif -} UNREG_LOGIN_VAR; - -/* Structure for MB Command REG_VPI (0x96) */ -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1; - uint32_t rsvd2:7; - uint32_t upd:1; - uint32_t sid:24; - uint32_t wwn[2]; - uint32_t rsvd5; - uint16_t vfi; - uint16_t vpi; -#else /* __LITTLE_ENDIAN */ - uint32_t rsvd1; - uint32_t sid:24; - uint32_t upd:1; - uint32_t rsvd2:7; - uint32_t wwn[2]; - uint32_t rsvd5; - uint16_t vpi; - uint16_t vfi; -#endif -} REG_VPI_VAR; - -/* Structure for MB Command UNREG_VPI (0x97) */ -typedef struct { - uint32_t rsvd1; -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t rsvd2; - uint16_t sli4_vpi; -#else /* __LITTLE_ENDIAN */ - uint16_t sli4_vpi; - uint16_t rsvd2; -#endif - uint32_t rsvd3; - uint32_t rsvd4; - uint32_t rsvd5; -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t rsvd6; - uint16_t vpi; -#else /* __LITTLE_ENDIAN */ - uint16_t vpi; - uint16_t rsvd6; -#endif -} UNREG_VPI_VAR; - -/* Structure for MB Command UNREG_D_ID (0x23) */ - -typedef struct { - uint32_t did; - uint32_t rsvd2; - uint32_t rsvd3; - uint32_t rsvd4; - uint32_t rsvd5; -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t rsvd6; - uint16_t vpi; -#else - uint16_t vpi; - uint16_t rsvd6; -#endif -} UNREG_D_ID_VAR; - -/* Structure for MB Command READ_TOPOLOGY (0x95) */ -struct lpfc_mbx_read_top { - uint32_t eventTag; /* Event tag */ - uint32_t word2; -#define lpfc_mbx_read_top_fa_SHIFT 12 -#define lpfc_mbx_read_top_fa_MASK 0x00000001 -#define lpfc_mbx_read_top_fa_WORD word2 -#define lpfc_mbx_read_top_mm_SHIFT 11 -#define lpfc_mbx_read_top_mm_MASK 0x00000001 -#define lpfc_mbx_read_top_mm_WORD word2 -#define lpfc_mbx_read_top_pb_SHIFT 9 -#define lpfc_mbx_read_top_pb_MASK 0X00000001 -#define lpfc_mbx_read_top_pb_WORD word2 -#define lpfc_mbx_read_top_il_SHIFT 8 -#define lpfc_mbx_read_top_il_MASK 0x00000001 -#define lpfc_mbx_read_top_il_WORD word2 -#define lpfc_mbx_read_top_att_type_SHIFT 0 -#define lpfc_mbx_read_top_att_type_MASK 0x000000FF -#define lpfc_mbx_read_top_att_type_WORD word2 -#define LPFC_ATT_RESERVED 0x00 /* Reserved - attType */ -#define LPFC_ATT_LINK_UP 0x01 /* Link is up */ -#define LPFC_ATT_LINK_DOWN 0x02 /* Link is down */ - uint32_t word3; -#define lpfc_mbx_read_top_alpa_granted_SHIFT 24 -#define lpfc_mbx_read_top_alpa_granted_MASK 0x000000FF -#define lpfc_mbx_read_top_alpa_granted_WORD word3 -#define lpfc_mbx_read_top_lip_alps_SHIFT 16 -#define lpfc_mbx_read_top_lip_alps_MASK 0x000000FF -#define lpfc_mbx_read_top_lip_alps_WORD word3 -#define lpfc_mbx_read_top_lip_type_SHIFT 8 -#define lpfc_mbx_read_top_lip_type_MASK 0x000000FF -#define lpfc_mbx_read_top_lip_type_WORD word3 -#define lpfc_mbx_read_top_topology_SHIFT 0 -#define lpfc_mbx_read_top_topology_MASK 0x000000FF -#define lpfc_mbx_read_top_topology_WORD word3 -#define LPFC_TOPOLOGY_PT_PT 0x01 /* Topology is pt-pt / pt-fabric */ -#define LPFC_TOPOLOGY_LOOP 0x02 /* Topology is FC-AL */ -#define LPFC_TOPOLOGY_MM 0x05 /* maint mode zephtr to menlo */ - /* store the LILP AL_PA position map into */ - struct ulp_bde64 lilpBde64; -#define LPFC_ALPA_MAP_SIZE 128 - uint32_t word7; -#define lpfc_mbx_read_top_ld_lu_SHIFT 31 -#define lpfc_mbx_read_top_ld_lu_MASK 0x00000001 -#define lpfc_mbx_read_top_ld_lu_WORD word7 -#define lpfc_mbx_read_top_ld_tf_SHIFT 30 -#define lpfc_mbx_read_top_ld_tf_MASK 0x00000001 -#define lpfc_mbx_read_top_ld_tf_WORD word7 -#define lpfc_mbx_read_top_ld_link_spd_SHIFT 8 -#define lpfc_mbx_read_top_ld_link_spd_MASK 0x000000FF -#define lpfc_mbx_read_top_ld_link_spd_WORD word7 -#define lpfc_mbx_read_top_ld_nl_port_SHIFT 4 -#define lpfc_mbx_read_top_ld_nl_port_MASK 0x0000000F -#define lpfc_mbx_read_top_ld_nl_port_WORD word7 -#define lpfc_mbx_read_top_ld_tx_SHIFT 2 -#define lpfc_mbx_read_top_ld_tx_MASK 0x00000003 -#define lpfc_mbx_read_top_ld_tx_WORD word7 -#define lpfc_mbx_read_top_ld_rx_SHIFT 0 -#define lpfc_mbx_read_top_ld_rx_MASK 0x00000003 -#define lpfc_mbx_read_top_ld_rx_WORD word7 - uint32_t word8; -#define lpfc_mbx_read_top_lu_SHIFT 31 -#define lpfc_mbx_read_top_lu_MASK 0x00000001 -#define lpfc_mbx_read_top_lu_WORD word8 -#define lpfc_mbx_read_top_tf_SHIFT 30 -#define lpfc_mbx_read_top_tf_MASK 0x00000001 -#define lpfc_mbx_read_top_tf_WORD word8 -#define lpfc_mbx_read_top_link_spd_SHIFT 8 -#define lpfc_mbx_read_top_link_spd_MASK 0x000000FF -#define lpfc_mbx_read_top_link_spd_WORD word8 -#define lpfc_mbx_read_top_nl_port_SHIFT 4 -#define lpfc_mbx_read_top_nl_port_MASK 0x0000000F -#define lpfc_mbx_read_top_nl_port_WORD word8 -#define lpfc_mbx_read_top_tx_SHIFT 2 -#define lpfc_mbx_read_top_tx_MASK 0x00000003 -#define lpfc_mbx_read_top_tx_WORD word8 -#define lpfc_mbx_read_top_rx_SHIFT 0 -#define lpfc_mbx_read_top_rx_MASK 0x00000003 -#define lpfc_mbx_read_top_rx_WORD word8 -#define LPFC_LINK_SPEED_UNKNOWN 0x0 -#define LPFC_LINK_SPEED_1GHZ 0x04 -#define LPFC_LINK_SPEED_2GHZ 0x08 -#define LPFC_LINK_SPEED_4GHZ 0x10 -#define LPFC_LINK_SPEED_8GHZ 0x20 -#define LPFC_LINK_SPEED_10GHZ 0x40 -#define LPFC_LINK_SPEED_16GHZ 0x80 -}; - -/* Structure for MB Command CLEAR_LA (22) */ - -typedef struct { - uint32_t eventTag; /* Event tag */ - uint32_t rsvd1; -} CLEAR_LA_VAR; - -/* Structure for MB Command DUMP */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd:25; - uint32_t ra:1; - uint32_t co:1; - uint32_t cv:1; - uint32_t type:4; - uint32_t entry_index:16; - uint32_t region_id:16; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t type:4; - uint32_t cv:1; - uint32_t co:1; - uint32_t ra:1; - uint32_t rsvd:25; - uint32_t region_id:16; - uint32_t entry_index:16; -#endif - - uint32_t sli4_length; - uint32_t word_cnt; - uint32_t resp_offset; -} DUMP_VAR; - -#define DMP_MEM_REG 0x1 -#define DMP_NV_PARAMS 0x2 -#define DMP_LMSD 0x3 /* Link Module Serial Data */ -#define DMP_WELL_KNOWN 0x4 - -#define DMP_REGION_VPD 0xe -#define DMP_VPD_SIZE 0x400 /* maximum amount of VPD */ -#define DMP_RSP_OFFSET 0x14 /* word 5 contains first word of rsp */ -#define DMP_RSP_SIZE 0x6C /* maximum of 27 words of rsp data */ - -#define DMP_REGION_VPORT 0x16 /* VPort info region */ -#define DMP_VPORT_REGION_SIZE 0x200 -#define DMP_MBOX_OFFSET_WORD 0x5 - -#define DMP_REGION_23 0x17 /* fcoe param and port state region */ -#define DMP_RGN23_SIZE 0x400 - -#define WAKE_UP_PARMS_REGION_ID 4 -#define WAKE_UP_PARMS_WORD_SIZE 15 - -struct vport_rec { - uint8_t wwpn[8]; - uint8_t wwnn[8]; -}; - -#define VPORT_INFO_SIG 0x32324752 -#define VPORT_INFO_REV_MASK 0xff -#define VPORT_INFO_REV 0x1 -#define MAX_STATIC_VPORT_COUNT 16 -struct static_vport_info { - uint32_t signature; - uint32_t rev; - struct vport_rec vport_list[MAX_STATIC_VPORT_COUNT]; - uint32_t resvd[66]; -}; - -/* Option rom version structure */ -struct prog_id { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t type; - uint8_t id; - uint32_t ver:4; /* Major Version */ - uint32_t rev:4; /* Revision */ - uint32_t lev:2; /* Level */ - uint32_t dist:2; /* Dist Type */ - uint32_t num:4; /* number after dist type */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t num:4; /* number after dist type */ - uint32_t dist:2; /* Dist Type */ - uint32_t lev:2; /* Level */ - uint32_t rev:4; /* Revision */ - uint32_t ver:4; /* Major Version */ - uint8_t id; - uint8_t type; -#endif -}; - -/* Structure for MB Command UPDATE_CFG (0x1B) */ - -struct update_cfg_var { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd2:16; - uint32_t type:8; - uint32_t rsvd:1; - uint32_t ra:1; - uint32_t co:1; - uint32_t cv:1; - uint32_t req:4; - uint32_t entry_length:16; - uint32_t region_id:16; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t req:4; - uint32_t cv:1; - uint32_t co:1; - uint32_t ra:1; - uint32_t rsvd:1; - uint32_t type:8; - uint32_t rsvd2:16; - uint32_t region_id:16; - uint32_t entry_length:16; -#endif - - uint32_t resp_info; - uint32_t byte_cnt; - uint32_t data_offset; -}; - -struct hbq_mask { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t tmatch; - uint8_t tmask; - uint8_t rctlmatch; - uint8_t rctlmask; -#else /* __LITTLE_ENDIAN */ - uint8_t rctlmask; - uint8_t rctlmatch; - uint8_t tmask; - uint8_t tmatch; -#endif -}; - - -/* Structure for MB Command CONFIG_HBQ (7c) */ - -struct config_hbq_var { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1 :7; - uint32_t recvNotify :1; /* Receive Notification */ - uint32_t numMask :8; /* # Mask Entries */ - uint32_t profile :8; /* Selection Profile */ - uint32_t rsvd2 :8; -#else /* __LITTLE_ENDIAN */ - uint32_t rsvd2 :8; - uint32_t profile :8; /* Selection Profile */ - uint32_t numMask :8; /* # Mask Entries */ - uint32_t recvNotify :1; /* Receive Notification */ - uint32_t rsvd1 :7; -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t hbqId :16; - uint32_t rsvd3 :12; - uint32_t ringMask :4; -#else /* __LITTLE_ENDIAN */ - uint32_t ringMask :4; - uint32_t rsvd3 :12; - uint32_t hbqId :16; -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t entry_count :16; - uint32_t rsvd4 :8; - uint32_t headerLen :8; -#else /* __LITTLE_ENDIAN */ - uint32_t headerLen :8; - uint32_t rsvd4 :8; - uint32_t entry_count :16; -#endif - - uint32_t hbqaddrLow; - uint32_t hbqaddrHigh; - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd5 :31; - uint32_t logEntry :1; -#else /* __LITTLE_ENDIAN */ - uint32_t logEntry :1; - uint32_t rsvd5 :31; -#endif - - uint32_t rsvd6; /* w7 */ - uint32_t rsvd7; /* w8 */ - uint32_t rsvd8; /* w9 */ - - struct hbq_mask hbqMasks[6]; - - - union { - uint32_t allprofiles[12]; - - struct { - #ifdef __BIG_ENDIAN_BITFIELD - uint32_t seqlenoff :16; - uint32_t maxlen :16; - #else /* __LITTLE_ENDIAN */ - uint32_t maxlen :16; - uint32_t seqlenoff :16; - #endif - #ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1 :28; - uint32_t seqlenbcnt :4; - #else /* __LITTLE_ENDIAN */ - uint32_t seqlenbcnt :4; - uint32_t rsvd1 :28; - #endif - uint32_t rsvd[10]; - } profile2; - - struct { - #ifdef __BIG_ENDIAN_BITFIELD - uint32_t seqlenoff :16; - uint32_t maxlen :16; - #else /* __LITTLE_ENDIAN */ - uint32_t maxlen :16; - uint32_t seqlenoff :16; - #endif - #ifdef __BIG_ENDIAN_BITFIELD - uint32_t cmdcodeoff :28; - uint32_t rsvd1 :12; - uint32_t seqlenbcnt :4; - #else /* __LITTLE_ENDIAN */ - uint32_t seqlenbcnt :4; - uint32_t rsvd1 :12; - uint32_t cmdcodeoff :28; - #endif - uint32_t cmdmatch[8]; - - uint32_t rsvd[2]; - } profile3; - - struct { - #ifdef __BIG_ENDIAN_BITFIELD - uint32_t seqlenoff :16; - uint32_t maxlen :16; - #else /* __LITTLE_ENDIAN */ - uint32_t maxlen :16; - uint32_t seqlenoff :16; - #endif - #ifdef __BIG_ENDIAN_BITFIELD - uint32_t cmdcodeoff :28; - uint32_t rsvd1 :12; - uint32_t seqlenbcnt :4; - #else /* __LITTLE_ENDIAN */ - uint32_t seqlenbcnt :4; - uint32_t rsvd1 :12; - uint32_t cmdcodeoff :28; - #endif - uint32_t cmdmatch[8]; - - uint32_t rsvd[2]; - } profile5; - - } profiles; - -}; - - - -/* Structure for MB Command CONFIG_PORT (0x88) */ -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t cBE : 1; - uint32_t cET : 1; - uint32_t cHpcb : 1; - uint32_t cMA : 1; - uint32_t sli_mode : 4; - uint32_t pcbLen : 24; /* bit 23:0 of memory based port - * config block */ -#else /* __LITTLE_ENDIAN */ - uint32_t pcbLen : 24; /* bit 23:0 of memory based port - * config block */ - uint32_t sli_mode : 4; - uint32_t cMA : 1; - uint32_t cHpcb : 1; - uint32_t cET : 1; - uint32_t cBE : 1; -#endif - - uint32_t pcbLow; /* bit 31:0 of memory based port config block */ - uint32_t pcbHigh; /* bit 63:32 of memory based port config block */ - uint32_t hbainit[5]; -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t hps : 1; /* bit 31 word9 Host Pointer in slim */ - uint32_t rsvd : 31; /* least significant 31 bits of word 9 */ -#else /* __LITTLE_ENDIAN */ - uint32_t rsvd : 31; /* least significant 31 bits of word 9 */ - uint32_t hps : 1; /* bit 31 word9 Host Pointer in slim */ -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd1 : 19; /* Reserved */ - uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t casabt : 1; /* Configure async abts status notice */ - uint32_t rsvd2 : 2; /* Reserved */ - uint32_t cbg : 1; /* Configure BlockGuard */ - uint32_t cmv : 1; /* Configure Max VPIs */ - uint32_t ccrp : 1; /* Config Command Ring Polling */ - uint32_t csah : 1; /* Configure Synchronous Abort Handling */ - uint32_t chbs : 1; /* Cofigure Host Backing store */ - uint32_t cinb : 1; /* Enable Interrupt Notification Block */ - uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */ - uint32_t cmx : 1; /* Configure Max XRIs */ - uint32_t cmr : 1; /* Configure Max RPIs */ -#else /* __LITTLE_ENDIAN */ - uint32_t cmr : 1; /* Configure Max RPIs */ - uint32_t cmx : 1; /* Configure Max XRIs */ - uint32_t cerbm : 1; /* Configure Enhanced Receive Buf Mgmt */ - uint32_t cinb : 1; /* Enable Interrupt Notification Block */ - uint32_t chbs : 1; /* Cofigure Host Backing store */ - uint32_t csah : 1; /* Configure Synchronous Abort Handling */ - uint32_t ccrp : 1; /* Config Command Ring Polling */ - uint32_t cmv : 1; /* Configure Max VPIs */ - uint32_t cbg : 1; /* Configure BlockGuard */ - uint32_t rsvd2 : 2; /* Reserved */ - uint32_t casabt : 1; /* Configure async abts status notice */ - uint32_t cdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd1 : 19; /* Reserved */ -#endif -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd3 : 19; /* Reserved */ - uint32_t gdss : 1; /* Configure Data Security SLI */ - uint32_t gasabt : 1; /* Grant async abts status notice */ - uint32_t rsvd4 : 2; /* Reserved */ - uint32_t gbg : 1; /* Grant BlockGuard */ - uint32_t gmv : 1; /* Grant Max VPIs */ - uint32_t gcrp : 1; /* Grant Command Ring Polling */ - uint32_t gsah : 1; /* Grant Synchronous Abort Handling */ - uint32_t ghbs : 1; /* Grant Host Backing Store */ - uint32_t ginb : 1; /* Grant Interrupt Notification Block */ - uint32_t gerbm : 1; /* Grant ERBM Request */ - uint32_t gmx : 1; /* Grant Max XRIs */ - uint32_t gmr : 1; /* Grant Max RPIs */ -#else /* __LITTLE_ENDIAN */ - uint32_t gmr : 1; /* Grant Max RPIs */ - uint32_t gmx : 1; /* Grant Max XRIs */ - uint32_t gerbm : 1; /* Grant ERBM Request */ - uint32_t ginb : 1; /* Grant Interrupt Notification Block */ - uint32_t ghbs : 1; /* Grant Host Backing Store */ - uint32_t gsah : 1; /* Grant Synchronous Abort Handling */ - uint32_t gcrp : 1; /* Grant Command Ring Polling */ - uint32_t gmv : 1; /* Grant Max VPIs */ - uint32_t gbg : 1; /* Grant BlockGuard */ - uint32_t rsvd4 : 2; /* Reserved */ - uint32_t gasabt : 1; /* Grant async abts status notice */ - uint32_t gdss : 1; /* Configure Data Security SLI */ - uint32_t rsvd3 : 19; /* Reserved */ -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t max_rpi : 16; /* Max RPIs Port should configure */ - uint32_t max_xri : 16; /* Max XRIs Port should configure */ -#else /* __LITTLE_ENDIAN */ - uint32_t max_xri : 16; /* Max XRIs Port should configure */ - uint32_t max_rpi : 16; /* Max RPIs Port should configure */ -#endif - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */ - uint32_t rsvd5 : 16; /* Max HBQs Host expect to configure */ -#else /* __LITTLE_ENDIAN */ - uint32_t rsvd5 : 16; /* Max HBQs Host expect to configure */ - uint32_t max_hbq : 16; /* Max HBQs Host expect to configure */ -#endif - - uint32_t rsvd6; /* Reserved */ - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t fips_rev : 3; /* FIPS Spec Revision */ - uint32_t fips_level : 4; /* FIPS Level */ - uint32_t sec_err : 9; /* security crypto error */ - uint32_t max_vpi : 16; /* Max number of virt N-Ports */ -#else /* __LITTLE_ENDIAN */ - uint32_t max_vpi : 16; /* Max number of virt N-Ports */ - uint32_t sec_err : 9; /* security crypto error */ - uint32_t fips_level : 4; /* FIPS Level */ - uint32_t fips_rev : 3; /* FIPS Spec Revision */ -#endif - -} CONFIG_PORT_VAR; - -/* Structure for MB Command CONFIG_MSI (0x30) */ -struct config_msi_var { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t dfltMsgNum:8; /* Default message number */ - uint32_t rsvd1:11; /* Reserved */ - uint32_t NID:5; /* Number of secondary attention IDs */ - uint32_t rsvd2:5; /* Reserved */ - uint32_t dfltPresent:1; /* Default message number present */ - uint32_t addFlag:1; /* Add association flag */ - uint32_t reportFlag:1; /* Report association flag */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t reportFlag:1; /* Report association flag */ - uint32_t addFlag:1; /* Add association flag */ - uint32_t dfltPresent:1; /* Default message number present */ - uint32_t rsvd2:5; /* Reserved */ - uint32_t NID:5; /* Number of secondary attention IDs */ - uint32_t rsvd1:11; /* Reserved */ - uint32_t dfltMsgNum:8; /* Default message number */ -#endif - uint32_t attentionConditions[2]; - uint8_t attentionId[16]; - uint8_t messageNumberByHA[64]; - uint8_t messageNumberByID[16]; - uint32_t autoClearHA[2]; -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd3:16; - uint32_t autoClearID:16; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t autoClearID:16; - uint32_t rsvd3:16; -#endif - uint32_t rsvd4; -}; - -/* SLI-2 Port Control Block */ - -/* SLIM POINTER */ -#define SLIMOFF 0x30 /* WORD */ - -typedef struct _SLI2_RDSC { - uint32_t cmdEntries; - uint32_t cmdAddrLow; - uint32_t cmdAddrHigh; - - uint32_t rspEntries; - uint32_t rspAddrLow; - uint32_t rspAddrHigh; -} SLI2_RDSC; - -typedef struct _PCB { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t type:8; -#define TYPE_NATIVE_SLI2 0x01 - uint32_t feature:8; -#define FEATURE_INITIAL_SLI2 0x01 - uint32_t rsvd:12; - uint32_t maxRing:4; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t maxRing:4; - uint32_t rsvd:12; - uint32_t feature:8; -#define FEATURE_INITIAL_SLI2 0x01 - uint32_t type:8; -#define TYPE_NATIVE_SLI2 0x01 -#endif - - uint32_t mailBoxSize; - uint32_t mbAddrLow; - uint32_t mbAddrHigh; - - uint32_t hgpAddrLow; - uint32_t hgpAddrHigh; - - uint32_t pgpAddrLow; - uint32_t pgpAddrHigh; - SLI2_RDSC rdsc[MAX_RINGS]; -} PCB_t; - -/* NEW_FEATURE */ -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd0:27; - uint32_t discardFarp:1; - uint32_t IPEnable:1; - uint32_t nodeName:1; - uint32_t portName:1; - uint32_t filterEnable:1; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t filterEnable:1; - uint32_t portName:1; - uint32_t nodeName:1; - uint32_t IPEnable:1; - uint32_t discardFarp:1; - uint32_t rsvd:27; -#endif - - uint8_t portname[8]; /* Used to be struct lpfc_name */ - uint8_t nodename[8]; - uint32_t rsvd1; - uint32_t rsvd2; - uint32_t rsvd3; - uint32_t IPAddress; -} CONFIG_FARP_VAR; - -/* Structure for MB Command MBX_ASYNCEVT_ENABLE (0x33) */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rsvd:30; - uint32_t ring:2; /* Ring for ASYNC_EVENT iocb Bits 0-1*/ -#else /* __LITTLE_ENDIAN */ - uint32_t ring:2; /* Ring for ASYNC_EVENT iocb Bits 0-1*/ - uint32_t rsvd:30; -#endif -} ASYNCEVT_ENABLE_VAR; - -/* Union of all Mailbox Command types */ -#define MAILBOX_CMD_WSIZE 32 -#define MAILBOX_CMD_SIZE (MAILBOX_CMD_WSIZE * sizeof(uint32_t)) -/* ext_wsize times 4 bytes should not be greater than max xmit size */ -#define MAILBOX_EXT_WSIZE 512 -#define MAILBOX_EXT_SIZE (MAILBOX_EXT_WSIZE * sizeof(uint32_t)) -#define MAILBOX_HBA_EXT_OFFSET 0x100 -/* max mbox xmit size is a page size for sysfs IO operations */ -#define MAILBOX_SYSFS_MAX 4096 - -typedef union { - uint32_t varWords[MAILBOX_CMD_WSIZE - 1]; /* first word is type/ - * feature/max ring number - */ - LOAD_SM_VAR varLdSM; /* cmd = 1 (LOAD_SM) */ - READ_NV_VAR varRDnvp; /* cmd = 2 (READ_NVPARMS) */ - WRITE_NV_VAR varWTnvp; /* cmd = 3 (WRITE_NVPARMS) */ - BIU_DIAG_VAR varBIUdiag; /* cmd = 4 (RUN_BIU_DIAG) */ - INIT_LINK_VAR varInitLnk; /* cmd = 5 (INIT_LINK) */ - DOWN_LINK_VAR varDwnLnk; /* cmd = 6 (DOWN_LINK) */ - CONFIG_LINK varCfgLnk; /* cmd = 7 (CONFIG_LINK) */ - PART_SLIM_VAR varSlim; /* cmd = 8 (PART_SLIM) */ - CONFIG_RING_VAR varCfgRing; /* cmd = 9 (CONFIG_RING) */ - RESET_RING_VAR varRstRing; /* cmd = 10 (RESET_RING) */ - READ_CONFIG_VAR varRdConfig; /* cmd = 11 (READ_CONFIG) */ - READ_RCONF_VAR varRdRConfig; /* cmd = 12 (READ_RCONFIG) */ - READ_SPARM_VAR varRdSparm; /* cmd = 13 (READ_SPARM(64)) */ - READ_STATUS_VAR varRdStatus; /* cmd = 14 (READ_STATUS) */ - READ_RPI_VAR varRdRPI; /* cmd = 15 (READ_RPI(64)) */ - READ_XRI_VAR varRdXRI; /* cmd = 16 (READ_XRI) */ - READ_REV_VAR varRdRev; /* cmd = 17 (READ_REV) */ - READ_LNK_VAR varRdLnk; /* cmd = 18 (READ_LNK_STAT) */ - REG_LOGIN_VAR varRegLogin; /* cmd = 19 (REG_LOGIN(64)) */ - UNREG_LOGIN_VAR varUnregLogin; /* cmd = 20 (UNREG_LOGIN) */ - CLEAR_LA_VAR varClearLA; /* cmd = 22 (CLEAR_LA) */ - DUMP_VAR varDmp; /* Warm Start DUMP mbx cmd */ - UNREG_D_ID_VAR varUnregDID; /* cmd = 0x23 (UNREG_D_ID) */ - CONFIG_FARP_VAR varCfgFarp; /* cmd = 0x25 (CONFIG_FARP) - * NEW_FEATURE - */ - struct config_hbq_var varCfgHbq;/* cmd = 0x7c (CONFIG_HBQ) */ - struct update_cfg_var varUpdateCfg; /* cmd = 0x1B (UPDATE_CFG)*/ - CONFIG_PORT_VAR varCfgPort; /* cmd = 0x88 (CONFIG_PORT) */ - struct lpfc_mbx_read_top varReadTop; /* cmd = 0x95 (READ_TOPOLOGY) */ - REG_VPI_VAR varRegVpi; /* cmd = 0x96 (REG_VPI) */ - UNREG_VPI_VAR varUnregVpi; /* cmd = 0x97 (UNREG_VPI) */ - ASYNCEVT_ENABLE_VAR varCfgAsyncEvent; /*cmd = x33 (CONFIG_ASYNC) */ - struct READ_EVENT_LOG_VAR varRdEventLog; /* cmd = 0x38 - * (READ_EVENT_LOG) - */ - struct config_msi_var varCfgMSI;/* cmd = x30 (CONFIG_MSI) */ -} MAILVARIANTS; - -/* - * SLI-2 specific structures - */ - -struct lpfc_hgp { - __le32 cmdPutInx; - __le32 rspGetInx; -}; - -struct lpfc_pgp { - __le32 cmdGetInx; - __le32 rspPutInx; -}; - -struct sli2_desc { - uint32_t unused1[16]; - struct lpfc_hgp host[MAX_RINGS]; - struct lpfc_pgp port[MAX_RINGS]; -}; - -struct sli3_desc { - struct lpfc_hgp host[MAX_RINGS]; - uint32_t reserved[8]; - uint32_t hbq_put[16]; -}; - -struct sli3_pgp { - struct lpfc_pgp port[MAX_RINGS]; - uint32_t hbq_get[16]; -}; - -union sli_var { - struct sli2_desc s2; - struct sli3_desc s3; - struct sli3_pgp s3_pgp; -}; - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t mbxStatus; - uint8_t mbxCommand; - uint8_t mbxReserved:6; - uint8_t mbxHc:1; - uint8_t mbxOwner:1; /* Low order bit first word */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t mbxOwner:1; /* Low order bit first word */ - uint8_t mbxHc:1; - uint8_t mbxReserved:6; - uint8_t mbxCommand; - uint16_t mbxStatus; -#endif - - MAILVARIANTS un; - union sli_var us; -} MAILBOX_t; - -/* - * Begin Structure Definitions for IOCB Commands - */ - -typedef struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t statAction; - uint8_t statRsn; - uint8_t statBaExp; - uint8_t statLocalError; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t statLocalError; - uint8_t statBaExp; - uint8_t statRsn; - uint8_t statAction; -#endif - /* statRsn P/F_RJT reason codes */ -#define RJT_BAD_D_ID 0x01 /* Invalid D_ID field */ -#define RJT_BAD_S_ID 0x02 /* Invalid S_ID field */ -#define RJT_UNAVAIL_TEMP 0x03 /* N_Port unavailable temp. */ -#define RJT_UNAVAIL_PERM 0x04 /* N_Port unavailable perm. */ -#define RJT_UNSUP_CLASS 0x05 /* Class not supported */ -#define RJT_DELIM_ERR 0x06 /* Delimiter usage error */ -#define RJT_UNSUP_TYPE 0x07 /* Type not supported */ -#define RJT_BAD_CONTROL 0x08 /* Invalid link conrtol */ -#define RJT_BAD_RCTL 0x09 /* R_CTL invalid */ -#define RJT_BAD_FCTL 0x0A /* F_CTL invalid */ -#define RJT_BAD_OXID 0x0B /* OX_ID invalid */ -#define RJT_BAD_RXID 0x0C /* RX_ID invalid */ -#define RJT_BAD_SEQID 0x0D /* SEQ_ID invalid */ -#define RJT_BAD_DFCTL 0x0E /* DF_CTL invalid */ -#define RJT_BAD_SEQCNT 0x0F /* SEQ_CNT invalid */ -#define RJT_BAD_PARM 0x10 /* Param. field invalid */ -#define RJT_XCHG_ERR 0x11 /* Exchange error */ -#define RJT_PROT_ERR 0x12 /* Protocol error */ -#define RJT_BAD_LENGTH 0x13 /* Invalid Length */ -#define RJT_UNEXPECTED_ACK 0x14 /* Unexpected ACK */ -#define RJT_LOGIN_REQUIRED 0x16 /* Login required */ -#define RJT_TOO_MANY_SEQ 0x17 /* Excessive sequences */ -#define RJT_XCHG_NOT_STRT 0x18 /* Exchange not started */ -#define RJT_UNSUP_SEC_HDR 0x19 /* Security hdr not supported */ -#define RJT_UNAVAIL_PATH 0x1A /* Fabric Path not available */ -#define RJT_VENDOR_UNIQUE 0xFF /* Vendor unique error */ - -#define IOERR_SUCCESS 0x00 /* statLocalError */ -#define IOERR_MISSING_CONTINUE 0x01 -#define IOERR_SEQUENCE_TIMEOUT 0x02 -#define IOERR_INTERNAL_ERROR 0x03 -#define IOERR_INVALID_RPI 0x04 -#define IOERR_NO_XRI 0x05 -#define IOERR_ILLEGAL_COMMAND 0x06 -#define IOERR_XCHG_DROPPED 0x07 -#define IOERR_ILLEGAL_FIELD 0x08 -#define IOERR_BAD_CONTINUE 0x09 -#define IOERR_TOO_MANY_BUFFERS 0x0A -#define IOERR_RCV_BUFFER_WAITING 0x0B -#define IOERR_NO_CONNECTION 0x0C -#define IOERR_TX_DMA_FAILED 0x0D -#define IOERR_RX_DMA_FAILED 0x0E -#define IOERR_ILLEGAL_FRAME 0x0F -#define IOERR_EXTRA_DATA 0x10 -#define IOERR_NO_RESOURCES 0x11 -#define IOERR_RESERVED 0x12 -#define IOERR_ILLEGAL_LENGTH 0x13 -#define IOERR_UNSUPPORTED_FEATURE 0x14 -#define IOERR_ABORT_IN_PROGRESS 0x15 -#define IOERR_ABORT_REQUESTED 0x16 -#define IOERR_RECEIVE_BUFFER_TIMEOUT 0x17 -#define IOERR_LOOP_OPEN_FAILURE 0x18 -#define IOERR_RING_RESET 0x19 -#define IOERR_LINK_DOWN 0x1A -#define IOERR_CORRUPTED_DATA 0x1B -#define IOERR_CORRUPTED_RPI 0x1C -#define IOERR_OUT_OF_ORDER_DATA 0x1D -#define IOERR_OUT_OF_ORDER_ACK 0x1E -#define IOERR_DUP_FRAME 0x1F -#define IOERR_LINK_CONTROL_FRAME 0x20 /* ACK_N received */ -#define IOERR_BAD_HOST_ADDRESS 0x21 -#define IOERR_RCV_HDRBUF_WAITING 0x22 -#define IOERR_MISSING_HDR_BUFFER 0x23 -#define IOERR_MSEQ_CHAIN_CORRUPTED 0x24 -#define IOERR_ABORTMULT_REQUESTED 0x25 -#define IOERR_BUFFER_SHORTAGE 0x28 -#define IOERR_DEFAULT 0x29 -#define IOERR_CNT 0x2A -#define IOERR_SLER_FAILURE 0x46 -#define IOERR_SLER_CMD_RCV_FAILURE 0x47 -#define IOERR_SLER_REC_RJT_ERR 0x48 -#define IOERR_SLER_REC_SRR_RETRY_ERR 0x49 -#define IOERR_SLER_SRR_RJT_ERR 0x4A -#define IOERR_SLER_RRQ_RJT_ERR 0x4C -#define IOERR_SLER_RRQ_RETRY_ERR 0x4D -#define IOERR_SLER_ABTS_ERR 0x4E -#define IOERR_ELXSEC_KEY_UNWRAP_ERROR 0xF0 -#define IOERR_ELXSEC_KEY_UNWRAP_COMPARE_ERROR 0xF1 -#define IOERR_ELXSEC_CRYPTO_ERROR 0xF2 -#define IOERR_ELXSEC_CRYPTO_COMPARE_ERROR 0xF3 -#define IOERR_DRVR_MASK 0x100 -#define IOERR_SLI_DOWN 0x101 /* ulpStatus - Driver defined */ -#define IOERR_SLI_BRESET 0x102 -#define IOERR_SLI_ABORTED 0x103 -} PARM_ERR; - -typedef union { - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t Rctl; /* R_CTL field */ - uint8_t Type; /* TYPE field */ - uint8_t Dfctl; /* DF_CTL field */ - uint8_t Fctl; /* Bits 0-7 of IOCB word 5 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint8_t Fctl; /* Bits 0-7 of IOCB word 5 */ - uint8_t Dfctl; /* DF_CTL field */ - uint8_t Type; /* TYPE field */ - uint8_t Rctl; /* R_CTL field */ -#endif - -#define BC 0x02 /* Broadcast Received - Fctl */ -#define SI 0x04 /* Sequence Initiative */ -#define LA 0x08 /* Ignore Link Attention state */ -#define LS 0x80 /* Last Sequence */ - } hcsw; - uint32_t reserved; -} WORD5; - -/* IOCB Command template for a generic response */ -typedef struct { - uint32_t reserved[4]; - PARM_ERR perr; -} GENERIC_RSP; - -/* IOCB Command template for XMIT / XMIT_BCAST / RCV_SEQUENCE / XMIT_ELS */ -typedef struct { - struct ulp_bde xrsqbde[2]; - uint32_t xrsqRo; /* Starting Relative Offset */ - WORD5 w5; /* Header control/status word */ -} XR_SEQ_FIELDS; - -/* IOCB Command template for ELS_REQUEST */ -typedef struct { - struct ulp_bde elsReq; - struct ulp_bde elsRsp; - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t word4Rsvd:7; - uint32_t fl:1; - uint32_t myID:24; - uint32_t word5Rsvd:8; - uint32_t remoteID:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t myID:24; - uint32_t fl:1; - uint32_t word4Rsvd:7; - uint32_t remoteID:24; - uint32_t word5Rsvd:8; -#endif -} ELS_REQUEST; - -/* IOCB Command template for RCV_ELS_REQ */ -typedef struct { - struct ulp_bde elsReq[2]; - uint32_t parmRo; - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t word5Rsvd:8; - uint32_t remoteID:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t remoteID:24; - uint32_t word5Rsvd:8; -#endif -} RCV_ELS_REQ; - -/* IOCB Command template for ABORT / CLOSE_XRI */ -typedef struct { - uint32_t rsvd[3]; - uint32_t abortType; -#define ABORT_TYPE_ABTX 0x00000000 -#define ABORT_TYPE_ABTS 0x00000001 - uint32_t parm; -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t abortContextTag; /* ulpContext from command to abort/close */ - uint16_t abortIoTag; /* ulpIoTag from command to abort/close */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t abortIoTag; /* ulpIoTag from command to abort/close */ - uint16_t abortContextTag; /* ulpContext from command to abort/close */ -#endif -} AC_XRI; - -/* IOCB Command template for ABORT_MXRI64 */ -typedef struct { - uint32_t rsvd[3]; - uint32_t abortType; - uint32_t parm; - uint32_t iotag32; -} A_MXRI64; - -/* IOCB Command template for GET_RPI */ -typedef struct { - uint32_t rsvd[4]; - uint32_t parmRo; -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t word5Rsvd:8; - uint32_t remoteID:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t remoteID:24; - uint32_t word5Rsvd:8; -#endif -} GET_RPI; - -/* IOCB Command template for all FCP Initiator commands */ -typedef struct { - struct ulp_bde fcpi_cmnd; /* FCP_CMND payload descriptor */ - struct ulp_bde fcpi_rsp; /* Rcv buffer */ - uint32_t fcpi_parm; - uint32_t fcpi_XRdy; /* transfer ready for IWRITE */ -} FCPI_FIELDS; - -/* IOCB Command template for all FCP Target commands */ -typedef struct { - struct ulp_bde fcpt_Buffer[2]; /* FCP_CMND payload descriptor */ - uint32_t fcpt_Offset; - uint32_t fcpt_Length; /* transfer ready for IWRITE */ -} FCPT_FIELDS; - -/* SLI-2 IOCB structure definitions */ - -/* IOCB Command template for 64 bit XMIT / XMIT_BCAST / XMIT_ELS */ -typedef struct { - ULP_BDL bdl; - uint32_t xrsqRo; /* Starting Relative Offset */ - WORD5 w5; /* Header control/status word */ -} XMT_SEQ_FIELDS64; - -/* IOCB Command template for 64 bit RCV_SEQUENCE64 */ -typedef struct { - struct ulp_bde64 rcvBde; - uint32_t rsvd1; - uint32_t xrsqRo; /* Starting Relative Offset */ - WORD5 w5; /* Header control/status word */ -} RCV_SEQ_FIELDS64; - -/* IOCB Command template for ELS_REQUEST64 */ -typedef struct { - ULP_BDL bdl; -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t word4Rsvd:7; - uint32_t fl:1; - uint32_t myID:24; - uint32_t word5Rsvd:8; - uint32_t remoteID:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t myID:24; - uint32_t fl:1; - uint32_t word4Rsvd:7; - uint32_t remoteID:24; - uint32_t word5Rsvd:8; -#endif -} ELS_REQUEST64; - -/* IOCB Command template for GEN_REQUEST64 */ -typedef struct { - ULP_BDL bdl; - uint32_t xrsqRo; /* Starting Relative Offset */ - WORD5 w5; /* Header control/status word */ -} GEN_REQUEST64; - -/* IOCB Command template for RCV_ELS_REQ64 */ -typedef struct { - struct ulp_bde64 elsReq; - uint32_t rcvd1; - uint32_t parmRo; - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t word5Rsvd:8; - uint32_t remoteID:24; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t remoteID:24; - uint32_t word5Rsvd:8; -#endif -} RCV_ELS_REQ64; - -/* IOCB Command template for RCV_SEQ64 */ -struct rcv_seq64 { - struct ulp_bde64 elsReq; - uint32_t hbq_1; - uint32_t parmRo; -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t rctl:8; - uint32_t type:8; - uint32_t dfctl:8; - uint32_t ls:1; - uint32_t fs:1; - uint32_t rsvd2:3; - uint32_t si:1; - uint32_t bc:1; - uint32_t rsvd3:1; -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t rsvd3:1; - uint32_t bc:1; - uint32_t si:1; - uint32_t rsvd2:3; - uint32_t fs:1; - uint32_t ls:1; - uint32_t dfctl:8; - uint32_t type:8; - uint32_t rctl:8; -#endif -}; - -/* IOCB Command template for all 64 bit FCP Initiator commands */ -typedef struct { - ULP_BDL bdl; - uint32_t fcpi_parm; - uint32_t fcpi_XRdy; /* transfer ready for IWRITE */ -} FCPI_FIELDS64; - -/* IOCB Command template for all 64 bit FCP Target commands */ -typedef struct { - ULP_BDL bdl; - uint32_t fcpt_Offset; - uint32_t fcpt_Length; /* transfer ready for IWRITE */ -} FCPT_FIELDS64; - -/* IOCB Command template for Async Status iocb commands */ -typedef struct { - uint32_t rsvd[4]; - uint32_t param; -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t evt_code; /* High order bits word 5 */ - uint16_t sub_ctxt_tag; /* Low order bits word 5 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t sub_ctxt_tag; /* High order bits word 5 */ - uint16_t evt_code; /* Low order bits word 5 */ -#endif -} ASYNCSTAT_FIELDS; -#define ASYNC_TEMP_WARN 0x100 -#define ASYNC_TEMP_SAFE 0x101 -#define ASYNC_STATUS_CN 0x102 - -/* IOCB Command template for CMD_IOCB_RCV_ELS64_CX (0xB7) - or CMD_IOCB_RCV_SEQ64_CX (0xB5) */ - -struct rcv_sli3 { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t ox_id; - uint16_t seq_cnt; - - uint16_t vpi; - uint16_t word9Rsvd; -#else /* __LITTLE_ENDIAN */ - uint16_t seq_cnt; - uint16_t ox_id; - - uint16_t word9Rsvd; - uint16_t vpi; -#endif - uint32_t word10Rsvd; - uint32_t acc_len; /* accumulated length */ - struct ulp_bde64 bde2; -}; - -/* Structure used for a single HBQ entry */ -struct lpfc_hbq_entry { - struct ulp_bde64 bde; - uint32_t buffer_tag; -}; - -/* IOCB Command template for QUE_XRI64_CX (0xB3) command */ -typedef struct { - struct lpfc_hbq_entry buff; - uint32_t rsvd; - uint32_t rsvd1; -} QUE_XRI64_CX_FIELDS; - -struct que_xri64cx_ext_fields { - uint32_t iotag64_low; - uint32_t iotag64_high; - uint32_t ebde_count; - uint32_t rsvd; - struct lpfc_hbq_entry buff[5]; -}; - -struct sli3_bg_fields { - uint32_t filler[6]; /* word 8-13 in IOCB */ - uint32_t bghm; /* word 14 - BlockGuard High Water Mark */ -/* Bitfields for bgstat (BlockGuard Status - word 15 of IOCB) */ -#define BGS_BIDIR_BG_PROF_MASK 0xff000000 -#define BGS_BIDIR_BG_PROF_SHIFT 24 -#define BGS_BIDIR_ERR_COND_FLAGS_MASK 0x003f0000 -#define BGS_BIDIR_ERR_COND_SHIFT 16 -#define BGS_BG_PROFILE_MASK 0x0000ff00 -#define BGS_BG_PROFILE_SHIFT 8 -#define BGS_INVALID_PROF_MASK 0x00000020 -#define BGS_INVALID_PROF_SHIFT 5 -#define BGS_UNINIT_DIF_BLOCK_MASK 0x00000010 -#define BGS_UNINIT_DIF_BLOCK_SHIFT 4 -#define BGS_HI_WATER_MARK_PRESENT_MASK 0x00000008 -#define BGS_HI_WATER_MARK_PRESENT_SHIFT 3 -#define BGS_REFTAG_ERR_MASK 0x00000004 -#define BGS_REFTAG_ERR_SHIFT 2 -#define BGS_APPTAG_ERR_MASK 0x00000002 -#define BGS_APPTAG_ERR_SHIFT 1 -#define BGS_GUARD_ERR_MASK 0x00000001 -#define BGS_GUARD_ERR_SHIFT 0 - uint32_t bgstat; /* word 15 - BlockGuard Status */ -}; - -static inline uint32_t -lpfc_bgs_get_bidir_bg_prof(uint32_t bgstat) -{ - return (bgstat & BGS_BIDIR_BG_PROF_MASK) >> - BGS_BIDIR_BG_PROF_SHIFT; -} - -static inline uint32_t -lpfc_bgs_get_bidir_err_cond(uint32_t bgstat) -{ - return (bgstat & BGS_BIDIR_ERR_COND_FLAGS_MASK) >> - BGS_BIDIR_ERR_COND_SHIFT; -} - -static inline uint32_t -lpfc_bgs_get_bg_prof(uint32_t bgstat) -{ - return (bgstat & BGS_BG_PROFILE_MASK) >> - BGS_BG_PROFILE_SHIFT; -} - -static inline uint32_t -lpfc_bgs_get_invalid_prof(uint32_t bgstat) -{ - return (bgstat & BGS_INVALID_PROF_MASK) >> - BGS_INVALID_PROF_SHIFT; -} - -static inline uint32_t -lpfc_bgs_get_uninit_dif_block(uint32_t bgstat) -{ - return (bgstat & BGS_UNINIT_DIF_BLOCK_MASK) >> - BGS_UNINIT_DIF_BLOCK_SHIFT; -} - -static inline uint32_t -lpfc_bgs_get_hi_water_mark_present(uint32_t bgstat) -{ - return (bgstat & BGS_HI_WATER_MARK_PRESENT_MASK) >> - BGS_HI_WATER_MARK_PRESENT_SHIFT; -} - -static inline uint32_t -lpfc_bgs_get_reftag_err(uint32_t bgstat) -{ - return (bgstat & BGS_REFTAG_ERR_MASK) >> - BGS_REFTAG_ERR_SHIFT; -} - -static inline uint32_t -lpfc_bgs_get_apptag_err(uint32_t bgstat) -{ - return (bgstat & BGS_APPTAG_ERR_MASK) >> - BGS_APPTAG_ERR_SHIFT; -} - -static inline uint32_t -lpfc_bgs_get_guard_err(uint32_t bgstat) -{ - return (bgstat & BGS_GUARD_ERR_MASK) >> - BGS_GUARD_ERR_SHIFT; -} - -#define LPFC_EXT_DATA_BDE_COUNT 3 -struct fcp_irw_ext { - uint32_t io_tag64_low; - uint32_t io_tag64_high; -#ifdef __BIG_ENDIAN_BITFIELD - uint8_t reserved1; - uint8_t reserved2; - uint8_t reserved3; - uint8_t ebde_count; -#else /* __LITTLE_ENDIAN */ - uint8_t ebde_count; - uint8_t reserved3; - uint8_t reserved2; - uint8_t reserved1; -#endif - uint32_t reserved4; - struct ulp_bde64 rbde; /* response bde */ - struct ulp_bde64 dbde[LPFC_EXT_DATA_BDE_COUNT]; /* data BDE or BPL */ - uint8_t icd[32]; /* immediate command data (32 bytes) */ -}; - -typedef struct _IOCB { /* IOCB structure */ - union { - GENERIC_RSP grsp; /* Generic response */ - XR_SEQ_FIELDS xrseq; /* XMIT / BCAST / RCV_SEQUENCE cmd */ - struct ulp_bde cont[3]; /* up to 3 continuation bdes */ - RCV_ELS_REQ rcvels; /* RCV_ELS_REQ template */ - AC_XRI acxri; /* ABORT / CLOSE_XRI template */ - A_MXRI64 amxri; /* abort multiple xri command overlay */ - GET_RPI getrpi; /* GET_RPI template */ - FCPI_FIELDS fcpi; /* FCP Initiator template */ - FCPT_FIELDS fcpt; /* FCP target template */ - - /* SLI-2 structures */ - - struct ulp_bde64 cont64[2]; /* up to 2 64 bit continuation - * bde_64s */ - ELS_REQUEST64 elsreq64; /* ELS_REQUEST template */ - GEN_REQUEST64 genreq64; /* GEN_REQUEST template */ - RCV_ELS_REQ64 rcvels64; /* RCV_ELS_REQ template */ - XMT_SEQ_FIELDS64 xseq64; /* XMIT / BCAST cmd */ - FCPI_FIELDS64 fcpi64; /* FCP 64 bit Initiator template */ - FCPT_FIELDS64 fcpt64; /* FCP 64 bit target template */ - ASYNCSTAT_FIELDS asyncstat; /* async_status iocb */ - QUE_XRI64_CX_FIELDS quexri64cx; /* que_xri64_cx fields */ - struct rcv_seq64 rcvseq64; /* RCV_SEQ64 and RCV_CONT64 */ - struct sli4_bls_rsp bls_rsp; /* UNSOL ABTS BLS_RSP params */ - uint32_t ulpWord[IOCB_WORD_SZ - 2]; /* generic 6 'words' */ - } un; - union { - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t ulpContext; /* High order bits word 6 */ - uint16_t ulpIoTag; /* Low order bits word 6 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t ulpIoTag; /* Low order bits word 6 */ - uint16_t ulpContext; /* High order bits word 6 */ -#endif - } t1; - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint16_t ulpContext; /* High order bits word 6 */ - uint16_t ulpIoTag1:2; /* Low order bits word 6 */ - uint16_t ulpIoTag0:14; /* Low order bits word 6 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint16_t ulpIoTag0:14; /* Low order bits word 6 */ - uint16_t ulpIoTag1:2; /* Low order bits word 6 */ - uint16_t ulpContext; /* High order bits word 6 */ -#endif - } t2; - } un1; -#define ulpContext un1.t1.ulpContext -#define ulpIoTag un1.t1.ulpIoTag -#define ulpIoTag0 un1.t2.ulpIoTag0 - -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t ulpTimeout:8; - uint32_t ulpXS:1; - uint32_t ulpFCP2Rcvy:1; - uint32_t ulpPU:2; - uint32_t ulpIr:1; - uint32_t ulpClass:3; - uint32_t ulpCommand:8; - uint32_t ulpStatus:4; - uint32_t ulpBdeCount:2; - uint32_t ulpLe:1; - uint32_t ulpOwner:1; /* Low order bit word 7 */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t ulpOwner:1; /* Low order bit word 7 */ - uint32_t ulpLe:1; - uint32_t ulpBdeCount:2; - uint32_t ulpStatus:4; - uint32_t ulpCommand:8; - uint32_t ulpClass:3; - uint32_t ulpIr:1; - uint32_t ulpPU:2; - uint32_t ulpFCP2Rcvy:1; - uint32_t ulpXS:1; - uint32_t ulpTimeout:8; -#endif - - union { - struct rcv_sli3 rcvsli3; /* words 8 - 15 */ - - /* words 8-31 used for que_xri_cx iocb */ - struct que_xri64cx_ext_fields que_xri64cx_ext_words; - struct fcp_irw_ext fcp_ext; - uint32_t sli3Words[24]; /* 96 extra bytes for SLI-3 */ - - /* words 8-15 for BlockGuard */ - struct sli3_bg_fields sli3_bg; - } unsli3; - -#define ulpCt_h ulpXS -#define ulpCt_l ulpFCP2Rcvy - -#define IOCB_FCP 1 /* IOCB is used for FCP ELS cmds-ulpRsvByte */ -#define IOCB_IP 2 /* IOCB is used for IP ELS cmds */ -#define PARM_UNUSED 0 /* PU field (Word 4) not used */ -#define PARM_REL_OFF 1 /* PU field (Word 4) = R. O. */ -#define PARM_READ_CHECK 2 /* PU field (Word 4) = Data Transfer Length */ -#define PARM_NPIV_DID 3 -#define CLASS1 0 /* Class 1 */ -#define CLASS2 1 /* Class 2 */ -#define CLASS3 2 /* Class 3 */ -#define CLASS_FCP_INTERMIX 7 /* FCP Data->Cls 1, all else->Cls 2 */ - -#define IOSTAT_SUCCESS 0x0 /* ulpStatus - HBA defined */ -#define IOSTAT_FCP_RSP_ERROR 0x1 -#define IOSTAT_REMOTE_STOP 0x2 -#define IOSTAT_LOCAL_REJECT 0x3 -#define IOSTAT_NPORT_RJT 0x4 -#define IOSTAT_FABRIC_RJT 0x5 -#define IOSTAT_NPORT_BSY 0x6 -#define IOSTAT_FABRIC_BSY 0x7 -#define IOSTAT_INTERMED_RSP 0x8 -#define IOSTAT_LS_RJT 0x9 -#define IOSTAT_BA_RJT 0xA -#define IOSTAT_RSVD1 0xB -#define IOSTAT_RSVD2 0xC -#define IOSTAT_RSVD3 0xD -#define IOSTAT_RSVD4 0xE -#define IOSTAT_NEED_BUFFER 0xF -#define IOSTAT_DRIVER_REJECT 0x10 /* ulpStatus - Driver defined */ -#define IOSTAT_DEFAULT 0xF /* Same as rsvd5 for now */ -#define IOSTAT_CNT 0x11 - -} IOCB_t; - - -#define SLI1_SLIM_SIZE (4 * 1024) - -/* Up to 498 IOCBs will fit into 16k - * 256 (MAILBOX_t) + 140 (PCB_t) + ( 32 (IOCB_t) * 498 ) = < 16384 - */ -#define SLI2_SLIM_SIZE (64 * 1024) - -/* Maximum IOCBs that will fit in SLI2 slim */ -#define MAX_SLI2_IOCB 498 -#define MAX_SLIM_IOCB_SIZE (SLI2_SLIM_SIZE - \ - (sizeof(MAILBOX_t) + sizeof(PCB_t) + \ - sizeof(uint32_t) * MAILBOX_EXT_WSIZE)) - -/* HBQ entries are 4 words each = 4k */ -#define LPFC_TOTAL_HBQ_SIZE (sizeof(struct lpfc_hbq_entry) * \ - lpfc_sli_hbq_count()) - -struct lpfc_sli2_slim { - MAILBOX_t mbx; - uint32_t mbx_ext_words[MAILBOX_EXT_WSIZE]; - PCB_t pcb; - IOCB_t IOCBs[MAX_SLIM_IOCB_SIZE]; -}; - -/* - * This function checks PCI device to allow special handling for LC HBAs. - * - * Parameters: - * device : struct pci_dev 's device field - * - * return 1 => TRUE - * 0 => FALSE - */ -static inline int -lpfc_is_LC_HBA(unsigned short device) -{ - if ((device == PCI_DEVICE_ID_TFLY) || - (device == PCI_DEVICE_ID_PFLY) || - (device == PCI_DEVICE_ID_LP101) || - (device == PCI_DEVICE_ID_BMID) || - (device == PCI_DEVICE_ID_BSMB) || - (device == PCI_DEVICE_ID_ZMID) || - (device == PCI_DEVICE_ID_ZSMB) || - (device == PCI_DEVICE_ID_SAT_MID) || - (device == PCI_DEVICE_ID_SAT_SMB) || - (device == PCI_DEVICE_ID_RFLY)) - return 1; - else - return 0; -} - -/* - * Determine if an IOCB failed because of a link event or firmware reset. - */ - -static inline int -lpfc_error_lost_link(IOCB_t *iocbp) -{ - return (iocbp->ulpStatus == IOSTAT_LOCAL_REJECT && - (iocbp->un.ulpWord[4] == IOERR_SLI_ABORTED || - iocbp->un.ulpWord[4] == IOERR_LINK_DOWN || - iocbp->un.ulpWord[4] == IOERR_SLI_DOWN)); -} - -#define MENLO_TRANSPORT_TYPE 0xfe -#define MENLO_CONTEXT 0 -#define MENLO_PU 3 -#define MENLO_TIMEOUT 30 -#define SETVAR_MLOMNT 0x103107 -#define SETVAR_MLORST 0x103007 - -#define BPL_ALIGN_SZ 8 /* 8 byte alignment for bpl and mbufs */ diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw4.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw4.h deleted file mode 100644 index 91f09761..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_hw4.h +++ /dev/null @@ -1,3505 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -/* Macros to deal with bit fields. Each bit field must have 3 #defines - * associated with it (_SHIFT, _MASK, and _WORD). - * EG. For a bit field that is in the 7th bit of the "field4" field of a - * structure and is 2 bits in size the following #defines must exist: - * struct temp { - * uint32_t field1; - * uint32_t field2; - * uint32_t field3; - * uint32_t field4; - * #define example_bit_field_SHIFT 7 - * #define example_bit_field_MASK 0x03 - * #define example_bit_field_WORD field4 - * uint32_t field5; - * }; - * Then the macros below may be used to get or set the value of that field. - * EG. To get the value of the bit field from the above example: - * struct temp t1; - * value = bf_get(example_bit_field, &t1); - * And then to set that bit field: - * bf_set(example_bit_field, &t1, 2); - * Or clear that bit field: - * bf_set(example_bit_field, &t1, 0); - */ -#define bf_get_be32(name, ptr) \ - ((be32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK) -#define bf_get_le32(name, ptr) \ - ((le32_to_cpu((ptr)->name##_WORD) >> name##_SHIFT) & name##_MASK) -#define bf_get(name, ptr) \ - (((ptr)->name##_WORD >> name##_SHIFT) & name##_MASK) -#define bf_set_le32(name, ptr, value) \ - ((ptr)->name##_WORD = cpu_to_le32(((((value) & \ - name##_MASK) << name##_SHIFT) | (le32_to_cpu((ptr)->name##_WORD) & \ - ~(name##_MASK << name##_SHIFT))))) -#define bf_set(name, ptr, value) \ - ((ptr)->name##_WORD = ((((value) & name##_MASK) << name##_SHIFT) | \ - ((ptr)->name##_WORD & ~(name##_MASK << name##_SHIFT)))) - -struct dma_address { - uint32_t addr_lo; - uint32_t addr_hi; -}; - -struct lpfc_sli_intf { - uint32_t word0; -#define lpfc_sli_intf_valid_SHIFT 29 -#define lpfc_sli_intf_valid_MASK 0x00000007 -#define lpfc_sli_intf_valid_WORD word0 -#define LPFC_SLI_INTF_VALID 6 -#define lpfc_sli_intf_sli_hint2_SHIFT 24 -#define lpfc_sli_intf_sli_hint2_MASK 0x0000001F -#define lpfc_sli_intf_sli_hint2_WORD word0 -#define LPFC_SLI_INTF_SLI_HINT2_NONE 0 -#define lpfc_sli_intf_sli_hint1_SHIFT 16 -#define lpfc_sli_intf_sli_hint1_MASK 0x000000FF -#define lpfc_sli_intf_sli_hint1_WORD word0 -#define LPFC_SLI_INTF_SLI_HINT1_NONE 0 -#define LPFC_SLI_INTF_SLI_HINT1_1 1 -#define LPFC_SLI_INTF_SLI_HINT1_2 2 -#define lpfc_sli_intf_if_type_SHIFT 12 -#define lpfc_sli_intf_if_type_MASK 0x0000000F -#define lpfc_sli_intf_if_type_WORD word0 -#define LPFC_SLI_INTF_IF_TYPE_0 0 -#define LPFC_SLI_INTF_IF_TYPE_1 1 -#define LPFC_SLI_INTF_IF_TYPE_2 2 -#define lpfc_sli_intf_sli_family_SHIFT 8 -#define lpfc_sli_intf_sli_family_MASK 0x0000000F -#define lpfc_sli_intf_sli_family_WORD word0 -#define LPFC_SLI_INTF_FAMILY_BE2 0x0 -#define LPFC_SLI_INTF_FAMILY_BE3 0x1 -#define LPFC_SLI_INTF_FAMILY_LNCR_A0 0xa -#define LPFC_SLI_INTF_FAMILY_LNCR_B0 0xb -#define lpfc_sli_intf_slirev_SHIFT 4 -#define lpfc_sli_intf_slirev_MASK 0x0000000F -#define lpfc_sli_intf_slirev_WORD word0 -#define LPFC_SLI_INTF_REV_SLI3 3 -#define LPFC_SLI_INTF_REV_SLI4 4 -#define lpfc_sli_intf_func_type_SHIFT 0 -#define lpfc_sli_intf_func_type_MASK 0x00000001 -#define lpfc_sli_intf_func_type_WORD word0 -#define LPFC_SLI_INTF_IF_TYPE_PHYS 0 -#define LPFC_SLI_INTF_IF_TYPE_VIRT 1 -}; - -#define LPFC_SLI4_MBX_EMBED true -#define LPFC_SLI4_MBX_NEMBED false - -#define LPFC_SLI4_MB_WORD_COUNT 64 -#define LPFC_MAX_MQ_PAGE 8 -#define LPFC_MAX_WQ_PAGE 8 -#define LPFC_MAX_CQ_PAGE 4 -#define LPFC_MAX_EQ_PAGE 8 - -#define LPFC_VIR_FUNC_MAX 32 /* Maximum number of virtual functions */ -#define LPFC_PCI_FUNC_MAX 5 /* Maximum number of PCI functions */ -#define LPFC_VFR_PAGE_SIZE 0x1000 /* 4KB BAR2 per-VF register page size */ - -/* Define SLI4 Alignment requirements. */ -#define LPFC_ALIGN_16_BYTE 16 -#define LPFC_ALIGN_64_BYTE 64 - -/* Define SLI4 specific definitions. */ -#define LPFC_MQ_CQE_BYTE_OFFSET 256 -#define LPFC_MBX_CMD_HDR_LENGTH 16 -#define LPFC_MBX_ERROR_RANGE 0x4000 -#define LPFC_BMBX_BIT1_ADDR_HI 0x2 -#define LPFC_BMBX_BIT1_ADDR_LO 0 -#define LPFC_RPI_HDR_COUNT 64 -#define LPFC_HDR_TEMPLATE_SIZE 4096 -#define LPFC_RPI_ALLOC_ERROR 0xFFFF -#define LPFC_FCF_RECORD_WD_CNT 132 -#define LPFC_ENTIRE_FCF_DATABASE 0 -#define LPFC_DFLT_FCF_INDEX 0 - -/* Virtual function numbers */ -#define LPFC_VF0 0 -#define LPFC_VF1 1 -#define LPFC_VF2 2 -#define LPFC_VF3 3 -#define LPFC_VF4 4 -#define LPFC_VF5 5 -#define LPFC_VF6 6 -#define LPFC_VF7 7 -#define LPFC_VF8 8 -#define LPFC_VF9 9 -#define LPFC_VF10 10 -#define LPFC_VF11 11 -#define LPFC_VF12 12 -#define LPFC_VF13 13 -#define LPFC_VF14 14 -#define LPFC_VF15 15 -#define LPFC_VF16 16 -#define LPFC_VF17 17 -#define LPFC_VF18 18 -#define LPFC_VF19 19 -#define LPFC_VF20 20 -#define LPFC_VF21 21 -#define LPFC_VF22 22 -#define LPFC_VF23 23 -#define LPFC_VF24 24 -#define LPFC_VF25 25 -#define LPFC_VF26 26 -#define LPFC_VF27 27 -#define LPFC_VF28 28 -#define LPFC_VF29 29 -#define LPFC_VF30 30 -#define LPFC_VF31 31 - -/* PCI function numbers */ -#define LPFC_PCI_FUNC0 0 -#define LPFC_PCI_FUNC1 1 -#define LPFC_PCI_FUNC2 2 -#define LPFC_PCI_FUNC3 3 -#define LPFC_PCI_FUNC4 4 - -/* SLI4 interface type-2 PDEV_CTL register */ -#define LPFC_CTL_PDEV_CTL_OFFSET 0x414 -#define LPFC_CTL_PDEV_CTL_DRST 0x00000001 -#define LPFC_CTL_PDEV_CTL_FRST 0x00000002 -#define LPFC_CTL_PDEV_CTL_DD 0x00000004 -#define LPFC_CTL_PDEV_CTL_LC 0x00000008 -#define LPFC_CTL_PDEV_CTL_FRL_ALL 0x00 -#define LPFC_CTL_PDEV_CTL_FRL_FC_FCOE 0x10 -#define LPFC_CTL_PDEV_CTL_FRL_NIC 0x20 - -#define LPFC_FW_DUMP_REQUEST (LPFC_CTL_PDEV_CTL_DD | LPFC_CTL_PDEV_CTL_FRST) - -/* Active interrupt test count */ -#define LPFC_ACT_INTR_CNT 4 - -/* Delay Multiplier constant */ -#define LPFC_DMULT_CONST 651042 -#define LPFC_MIM_IMAX 636 -#define LPFC_FP_DEF_IMAX 10000 -#define LPFC_SP_DEF_IMAX 10000 - -/* PORT_CAPABILITIES constants. */ -#define LPFC_MAX_SUPPORTED_PAGES 8 - -struct ulp_bde64 { - union ULP_BDE_TUS { - uint32_t w; - struct { -#ifdef __BIG_ENDIAN_BITFIELD - uint32_t bdeFlags:8; /* BDE Flags 0 IS A SUPPORTED - VALUE !! */ - uint32_t bdeSize:24; /* Size of buffer (in bytes) */ -#else /* __LITTLE_ENDIAN_BITFIELD */ - uint32_t bdeSize:24; /* Size of buffer (in bytes) */ - uint32_t bdeFlags:8; /* BDE Flags 0 IS A SUPPORTED - VALUE !! */ -#endif -#define BUFF_TYPE_BDE_64 0x00 /* BDE (Host_resident) */ -#define BUFF_TYPE_BDE_IMMED 0x01 /* Immediate Data BDE */ -#define BUFF_TYPE_BDE_64P 0x02 /* BDE (Port-resident) */ -#define BUFF_TYPE_BDE_64I 0x08 /* Input BDE (Host-resident) */ -#define BUFF_TYPE_BDE_64IP 0x0A /* Input BDE (Port-resident) */ -#define BUFF_TYPE_BLP_64 0x40 /* BLP (Host-resident) */ -#define BUFF_TYPE_BLP_64P 0x42 /* BLP (Port-resident) */ - } f; - } tus; - uint32_t addrLow; - uint32_t addrHigh; -}; - -struct lpfc_sli4_flags { - uint32_t word0; -#define lpfc_idx_rsrc_rdy_SHIFT 0 -#define lpfc_idx_rsrc_rdy_MASK 0x00000001 -#define lpfc_idx_rsrc_rdy_WORD word0 -#define LPFC_IDX_RSRC_RDY 1 -#define lpfc_xri_rsrc_rdy_SHIFT 1 -#define lpfc_xri_rsrc_rdy_MASK 0x00000001 -#define lpfc_xri_rsrc_rdy_WORD word0 -#define LPFC_XRI_RSRC_RDY 1 -#define lpfc_rpi_rsrc_rdy_SHIFT 2 -#define lpfc_rpi_rsrc_rdy_MASK 0x00000001 -#define lpfc_rpi_rsrc_rdy_WORD word0 -#define LPFC_RPI_RSRC_RDY 1 -#define lpfc_vpi_rsrc_rdy_SHIFT 3 -#define lpfc_vpi_rsrc_rdy_MASK 0x00000001 -#define lpfc_vpi_rsrc_rdy_WORD word0 -#define LPFC_VPI_RSRC_RDY 1 -#define lpfc_vfi_rsrc_rdy_SHIFT 4 -#define lpfc_vfi_rsrc_rdy_MASK 0x00000001 -#define lpfc_vfi_rsrc_rdy_WORD word0 -#define LPFC_VFI_RSRC_RDY 1 -}; - -struct sli4_bls_rsp { - uint32_t word0_rsvd; /* Word0 must be reserved */ - uint32_t word1; -#define lpfc_abts_orig_SHIFT 0 -#define lpfc_abts_orig_MASK 0x00000001 -#define lpfc_abts_orig_WORD word1 -#define LPFC_ABTS_UNSOL_RSP 1 -#define LPFC_ABTS_UNSOL_INT 0 - uint32_t word2; -#define lpfc_abts_rxid_SHIFT 0 -#define lpfc_abts_rxid_MASK 0x0000FFFF -#define lpfc_abts_rxid_WORD word2 -#define lpfc_abts_oxid_SHIFT 16 -#define lpfc_abts_oxid_MASK 0x0000FFFF -#define lpfc_abts_oxid_WORD word2 - uint32_t word3; -#define lpfc_vndr_code_SHIFT 0 -#define lpfc_vndr_code_MASK 0x000000FF -#define lpfc_vndr_code_WORD word3 -#define lpfc_rsn_expln_SHIFT 8 -#define lpfc_rsn_expln_MASK 0x000000FF -#define lpfc_rsn_expln_WORD word3 -#define lpfc_rsn_code_SHIFT 16 -#define lpfc_rsn_code_MASK 0x000000FF -#define lpfc_rsn_code_WORD word3 - - uint32_t word4; - uint32_t word5_rsvd; /* Word5 must be reserved */ -}; - -/* event queue entry structure */ -struct lpfc_eqe { - uint32_t word0; -#define lpfc_eqe_resource_id_SHIFT 16 -#define lpfc_eqe_resource_id_MASK 0x000000FF -#define lpfc_eqe_resource_id_WORD word0 -#define lpfc_eqe_minor_code_SHIFT 4 -#define lpfc_eqe_minor_code_MASK 0x00000FFF -#define lpfc_eqe_minor_code_WORD word0 -#define lpfc_eqe_major_code_SHIFT 1 -#define lpfc_eqe_major_code_MASK 0x00000007 -#define lpfc_eqe_major_code_WORD word0 -#define lpfc_eqe_valid_SHIFT 0 -#define lpfc_eqe_valid_MASK 0x00000001 -#define lpfc_eqe_valid_WORD word0 -}; - -/* completion queue entry structure (common fields for all cqe types) */ -struct lpfc_cqe { - uint32_t reserved0; - uint32_t reserved1; - uint32_t reserved2; - uint32_t word3; -#define lpfc_cqe_valid_SHIFT 31 -#define lpfc_cqe_valid_MASK 0x00000001 -#define lpfc_cqe_valid_WORD word3 -#define lpfc_cqe_code_SHIFT 16 -#define lpfc_cqe_code_MASK 0x000000FF -#define lpfc_cqe_code_WORD word3 -}; - -/* Completion Queue Entry Status Codes */ -#define CQE_STATUS_SUCCESS 0x0 -#define CQE_STATUS_FCP_RSP_FAILURE 0x1 -#define CQE_STATUS_REMOTE_STOP 0x2 -#define CQE_STATUS_LOCAL_REJECT 0x3 -#define CQE_STATUS_NPORT_RJT 0x4 -#define CQE_STATUS_FABRIC_RJT 0x5 -#define CQE_STATUS_NPORT_BSY 0x6 -#define CQE_STATUS_FABRIC_BSY 0x7 -#define CQE_STATUS_INTERMED_RSP 0x8 -#define CQE_STATUS_LS_RJT 0x9 -#define CQE_STATUS_CMD_REJECT 0xb -#define CQE_STATUS_FCP_TGT_LENCHECK 0xc -#define CQE_STATUS_NEED_BUFF_ENTRY 0xf -#define CQE_STATUS_DI_ERROR 0x16 - -/* Used when mapping CQE status to IOCB */ -#define LPFC_IOCB_STATUS_MASK 0xf - -/* Status returned by hardware (valid only if status = CQE_STATUS_SUCCESS). */ -#define CQE_HW_STATUS_NO_ERR 0x0 -#define CQE_HW_STATUS_UNDERRUN 0x1 -#define CQE_HW_STATUS_OVERRUN 0x2 - -/* Completion Queue Entry Codes */ -#define CQE_CODE_COMPL_WQE 0x1 -#define CQE_CODE_RELEASE_WQE 0x2 -#define CQE_CODE_RECEIVE 0x4 -#define CQE_CODE_XRI_ABORTED 0x5 -#define CQE_CODE_RECEIVE_V1 0x9 - -/* - * Define mask value for xri_aborted and wcqe completed CQE extended status. - * Currently, extended status is limited to 9 bits (0x0 -> 0x103) . - */ -#define WCQE_PARAM_MASK 0x1FF; - -/* completion queue entry for wqe completions */ -struct lpfc_wcqe_complete { - uint32_t word0; -#define lpfc_wcqe_c_request_tag_SHIFT 16 -#define lpfc_wcqe_c_request_tag_MASK 0x0000FFFF -#define lpfc_wcqe_c_request_tag_WORD word0 -#define lpfc_wcqe_c_status_SHIFT 8 -#define lpfc_wcqe_c_status_MASK 0x000000FF -#define lpfc_wcqe_c_status_WORD word0 -#define lpfc_wcqe_c_hw_status_SHIFT 0 -#define lpfc_wcqe_c_hw_status_MASK 0x000000FF -#define lpfc_wcqe_c_hw_status_WORD word0 - uint32_t total_data_placed; - uint32_t parameter; -#define lpfc_wcqe_c_bg_edir_SHIFT 5 -#define lpfc_wcqe_c_bg_edir_MASK 0x00000001 -#define lpfc_wcqe_c_bg_edir_WORD parameter -#define lpfc_wcqe_c_bg_tdpv_SHIFT 3 -#define lpfc_wcqe_c_bg_tdpv_MASK 0x00000001 -#define lpfc_wcqe_c_bg_tdpv_WORD parameter -#define lpfc_wcqe_c_bg_re_SHIFT 2 -#define lpfc_wcqe_c_bg_re_MASK 0x00000001 -#define lpfc_wcqe_c_bg_re_WORD parameter -#define lpfc_wcqe_c_bg_ae_SHIFT 1 -#define lpfc_wcqe_c_bg_ae_MASK 0x00000001 -#define lpfc_wcqe_c_bg_ae_WORD parameter -#define lpfc_wcqe_c_bg_ge_SHIFT 0 -#define lpfc_wcqe_c_bg_ge_MASK 0x00000001 -#define lpfc_wcqe_c_bg_ge_WORD parameter - uint32_t word3; -#define lpfc_wcqe_c_valid_SHIFT lpfc_cqe_valid_SHIFT -#define lpfc_wcqe_c_valid_MASK lpfc_cqe_valid_MASK -#define lpfc_wcqe_c_valid_WORD lpfc_cqe_valid_WORD -#define lpfc_wcqe_c_xb_SHIFT 28 -#define lpfc_wcqe_c_xb_MASK 0x00000001 -#define lpfc_wcqe_c_xb_WORD word3 -#define lpfc_wcqe_c_pv_SHIFT 27 -#define lpfc_wcqe_c_pv_MASK 0x00000001 -#define lpfc_wcqe_c_pv_WORD word3 -#define lpfc_wcqe_c_priority_SHIFT 24 -#define lpfc_wcqe_c_priority_MASK 0x00000007 -#define lpfc_wcqe_c_priority_WORD word3 -#define lpfc_wcqe_c_code_SHIFT lpfc_cqe_code_SHIFT -#define lpfc_wcqe_c_code_MASK lpfc_cqe_code_MASK -#define lpfc_wcqe_c_code_WORD lpfc_cqe_code_WORD -}; - -/* completion queue entry for wqe release */ -struct lpfc_wcqe_release { - uint32_t reserved0; - uint32_t reserved1; - uint32_t word2; -#define lpfc_wcqe_r_wq_id_SHIFT 16 -#define lpfc_wcqe_r_wq_id_MASK 0x0000FFFF -#define lpfc_wcqe_r_wq_id_WORD word2 -#define lpfc_wcqe_r_wqe_index_SHIFT 0 -#define lpfc_wcqe_r_wqe_index_MASK 0x0000FFFF -#define lpfc_wcqe_r_wqe_index_WORD word2 - uint32_t word3; -#define lpfc_wcqe_r_valid_SHIFT lpfc_cqe_valid_SHIFT -#define lpfc_wcqe_r_valid_MASK lpfc_cqe_valid_MASK -#define lpfc_wcqe_r_valid_WORD lpfc_cqe_valid_WORD -#define lpfc_wcqe_r_code_SHIFT lpfc_cqe_code_SHIFT -#define lpfc_wcqe_r_code_MASK lpfc_cqe_code_MASK -#define lpfc_wcqe_r_code_WORD lpfc_cqe_code_WORD -}; - -struct sli4_wcqe_xri_aborted { - uint32_t word0; -#define lpfc_wcqe_xa_status_SHIFT 8 -#define lpfc_wcqe_xa_status_MASK 0x000000FF -#define lpfc_wcqe_xa_status_WORD word0 - uint32_t parameter; - uint32_t word2; -#define lpfc_wcqe_xa_remote_xid_SHIFT 16 -#define lpfc_wcqe_xa_remote_xid_MASK 0x0000FFFF -#define lpfc_wcqe_xa_remote_xid_WORD word2 -#define lpfc_wcqe_xa_xri_SHIFT 0 -#define lpfc_wcqe_xa_xri_MASK 0x0000FFFF -#define lpfc_wcqe_xa_xri_WORD word2 - uint32_t word3; -#define lpfc_wcqe_xa_valid_SHIFT lpfc_cqe_valid_SHIFT -#define lpfc_wcqe_xa_valid_MASK lpfc_cqe_valid_MASK -#define lpfc_wcqe_xa_valid_WORD lpfc_cqe_valid_WORD -#define lpfc_wcqe_xa_ia_SHIFT 30 -#define lpfc_wcqe_xa_ia_MASK 0x00000001 -#define lpfc_wcqe_xa_ia_WORD word3 -#define CQE_XRI_ABORTED_IA_REMOTE 0 -#define CQE_XRI_ABORTED_IA_LOCAL 1 -#define lpfc_wcqe_xa_br_SHIFT 29 -#define lpfc_wcqe_xa_br_MASK 0x00000001 -#define lpfc_wcqe_xa_br_WORD word3 -#define CQE_XRI_ABORTED_BR_BA_ACC 0 -#define CQE_XRI_ABORTED_BR_BA_RJT 1 -#define lpfc_wcqe_xa_eo_SHIFT 28 -#define lpfc_wcqe_xa_eo_MASK 0x00000001 -#define lpfc_wcqe_xa_eo_WORD word3 -#define CQE_XRI_ABORTED_EO_REMOTE 0 -#define CQE_XRI_ABORTED_EO_LOCAL 1 -#define lpfc_wcqe_xa_code_SHIFT lpfc_cqe_code_SHIFT -#define lpfc_wcqe_xa_code_MASK lpfc_cqe_code_MASK -#define lpfc_wcqe_xa_code_WORD lpfc_cqe_code_WORD -}; - -/* completion queue entry structure for rqe completion */ -struct lpfc_rcqe { - uint32_t word0; -#define lpfc_rcqe_bindex_SHIFT 16 -#define lpfc_rcqe_bindex_MASK 0x0000FFF -#define lpfc_rcqe_bindex_WORD word0 -#define lpfc_rcqe_status_SHIFT 8 -#define lpfc_rcqe_status_MASK 0x000000FF -#define lpfc_rcqe_status_WORD word0 -#define FC_STATUS_RQ_SUCCESS 0x10 /* Async receive successful */ -#define FC_STATUS_RQ_BUF_LEN_EXCEEDED 0x11 /* payload truncated */ -#define FC_STATUS_INSUFF_BUF_NEED_BUF 0x12 /* Insufficient buffers */ -#define FC_STATUS_INSUFF_BUF_FRM_DISC 0x13 /* Frame Discard */ - uint32_t word1; -#define lpfc_rcqe_fcf_id_v1_SHIFT 0 -#define lpfc_rcqe_fcf_id_v1_MASK 0x0000003F -#define lpfc_rcqe_fcf_id_v1_WORD word1 - uint32_t word2; -#define lpfc_rcqe_length_SHIFT 16 -#define lpfc_rcqe_length_MASK 0x0000FFFF -#define lpfc_rcqe_length_WORD word2 -#define lpfc_rcqe_rq_id_SHIFT 6 -#define lpfc_rcqe_rq_id_MASK 0x000003FF -#define lpfc_rcqe_rq_id_WORD word2 -#define lpfc_rcqe_fcf_id_SHIFT 0 -#define lpfc_rcqe_fcf_id_MASK 0x0000003F -#define lpfc_rcqe_fcf_id_WORD word2 -#define lpfc_rcqe_rq_id_v1_SHIFT 0 -#define lpfc_rcqe_rq_id_v1_MASK 0x0000FFFF -#define lpfc_rcqe_rq_id_v1_WORD word2 - uint32_t word3; -#define lpfc_rcqe_valid_SHIFT lpfc_cqe_valid_SHIFT -#define lpfc_rcqe_valid_MASK lpfc_cqe_valid_MASK -#define lpfc_rcqe_valid_WORD lpfc_cqe_valid_WORD -#define lpfc_rcqe_port_SHIFT 30 -#define lpfc_rcqe_port_MASK 0x00000001 -#define lpfc_rcqe_port_WORD word3 -#define lpfc_rcqe_hdr_length_SHIFT 24 -#define lpfc_rcqe_hdr_length_MASK 0x0000001F -#define lpfc_rcqe_hdr_length_WORD word3 -#define lpfc_rcqe_code_SHIFT lpfc_cqe_code_SHIFT -#define lpfc_rcqe_code_MASK lpfc_cqe_code_MASK -#define lpfc_rcqe_code_WORD lpfc_cqe_code_WORD -#define lpfc_rcqe_eof_SHIFT 8 -#define lpfc_rcqe_eof_MASK 0x000000FF -#define lpfc_rcqe_eof_WORD word3 -#define FCOE_EOFn 0x41 -#define FCOE_EOFt 0x42 -#define FCOE_EOFni 0x49 -#define FCOE_EOFa 0x50 -#define lpfc_rcqe_sof_SHIFT 0 -#define lpfc_rcqe_sof_MASK 0x000000FF -#define lpfc_rcqe_sof_WORD word3 -#define FCOE_SOFi2 0x2d -#define FCOE_SOFi3 0x2e -#define FCOE_SOFn2 0x35 -#define FCOE_SOFn3 0x36 -}; - -struct lpfc_rqe { - uint32_t address_hi; - uint32_t address_lo; -}; - -/* buffer descriptors */ -struct lpfc_bde4 { - uint32_t addr_hi; - uint32_t addr_lo; - uint32_t word2; -#define lpfc_bde4_last_SHIFT 31 -#define lpfc_bde4_last_MASK 0x00000001 -#define lpfc_bde4_last_WORD word2 -#define lpfc_bde4_sge_offset_SHIFT 0 -#define lpfc_bde4_sge_offset_MASK 0x000003FF -#define lpfc_bde4_sge_offset_WORD word2 - uint32_t word3; -#define lpfc_bde4_length_SHIFT 0 -#define lpfc_bde4_length_MASK 0x000000FF -#define lpfc_bde4_length_WORD word3 -}; - -struct lpfc_register { - uint32_t word0; -}; - -/* The following BAR0 Registers apply to SLI4 if_type 0 UCNAs. */ -#define LPFC_UERR_STATUS_HI 0x00A4 -#define LPFC_UERR_STATUS_LO 0x00A0 -#define LPFC_UE_MASK_HI 0x00AC -#define LPFC_UE_MASK_LO 0x00A8 - -/* The following BAR0 register sets are defined for if_type 0 and 2 UCNAs. */ -#define LPFC_SLI_INTF 0x0058 - -#define LPFC_CTL_PORT_SEM_OFFSET 0x400 -#define lpfc_port_smphr_perr_SHIFT 31 -#define lpfc_port_smphr_perr_MASK 0x1 -#define lpfc_port_smphr_perr_WORD word0 -#define lpfc_port_smphr_sfi_SHIFT 30 -#define lpfc_port_smphr_sfi_MASK 0x1 -#define lpfc_port_smphr_sfi_WORD word0 -#define lpfc_port_smphr_nip_SHIFT 29 -#define lpfc_port_smphr_nip_MASK 0x1 -#define lpfc_port_smphr_nip_WORD word0 -#define lpfc_port_smphr_ipc_SHIFT 28 -#define lpfc_port_smphr_ipc_MASK 0x1 -#define lpfc_port_smphr_ipc_WORD word0 -#define lpfc_port_smphr_scr1_SHIFT 27 -#define lpfc_port_smphr_scr1_MASK 0x1 -#define lpfc_port_smphr_scr1_WORD word0 -#define lpfc_port_smphr_scr2_SHIFT 26 -#define lpfc_port_smphr_scr2_MASK 0x1 -#define lpfc_port_smphr_scr2_WORD word0 -#define lpfc_port_smphr_host_scratch_SHIFT 16 -#define lpfc_port_smphr_host_scratch_MASK 0xFF -#define lpfc_port_smphr_host_scratch_WORD word0 -#define lpfc_port_smphr_port_status_SHIFT 0 -#define lpfc_port_smphr_port_status_MASK 0xFFFF -#define lpfc_port_smphr_port_status_WORD word0 - -#define LPFC_POST_STAGE_POWER_ON_RESET 0x0000 -#define LPFC_POST_STAGE_AWAITING_HOST_RDY 0x0001 -#define LPFC_POST_STAGE_HOST_RDY 0x0002 -#define LPFC_POST_STAGE_BE_RESET 0x0003 -#define LPFC_POST_STAGE_SEEPROM_CS_START 0x0100 -#define LPFC_POST_STAGE_SEEPROM_CS_DONE 0x0101 -#define LPFC_POST_STAGE_DDR_CONFIG_START 0x0200 -#define LPFC_POST_STAGE_DDR_CONFIG_DONE 0x0201 -#define LPFC_POST_STAGE_DDR_CALIBRATE_START 0x0300 -#define LPFC_POST_STAGE_DDR_CALIBRATE_DONE 0x0301 -#define LPFC_POST_STAGE_DDR_TEST_START 0x0400 -#define LPFC_POST_STAGE_DDR_TEST_DONE 0x0401 -#define LPFC_POST_STAGE_REDBOOT_INIT_START 0x0600 -#define LPFC_POST_STAGE_REDBOOT_INIT_DONE 0x0601 -#define LPFC_POST_STAGE_FW_IMAGE_LOAD_START 0x0700 -#define LPFC_POST_STAGE_FW_IMAGE_LOAD_DONE 0x0701 -#define LPFC_POST_STAGE_ARMFW_START 0x0800 -#define LPFC_POST_STAGE_DHCP_QUERY_START 0x0900 -#define LPFC_POST_STAGE_DHCP_QUERY_DONE 0x0901 -#define LPFC_POST_STAGE_BOOT_TARGET_DISCOVERY_START 0x0A00 -#define LPFC_POST_STAGE_BOOT_TARGET_DISCOVERY_DONE 0x0A01 -#define LPFC_POST_STAGE_RC_OPTION_SET 0x0B00 -#define LPFC_POST_STAGE_SWITCH_LINK 0x0B01 -#define LPFC_POST_STAGE_SEND_ICDS_MESSAGE 0x0B02 -#define LPFC_POST_STAGE_PERFROM_TFTP 0x0B03 -#define LPFC_POST_STAGE_PARSE_XML 0x0B04 -#define LPFC_POST_STAGE_DOWNLOAD_IMAGE 0x0B05 -#define LPFC_POST_STAGE_FLASH_IMAGE 0x0B06 -#define LPFC_POST_STAGE_RC_DONE 0x0B07 -#define LPFC_POST_STAGE_REBOOT_SYSTEM 0x0B08 -#define LPFC_POST_STAGE_MAC_ADDRESS 0x0C00 -#define LPFC_POST_STAGE_PORT_READY 0xC000 -#define LPFC_POST_STAGE_PORT_UE 0xF000 - -#define LPFC_CTL_PORT_STA_OFFSET 0x404 -#define lpfc_sliport_status_err_SHIFT 31 -#define lpfc_sliport_status_err_MASK 0x1 -#define lpfc_sliport_status_err_WORD word0 -#define lpfc_sliport_status_end_SHIFT 30 -#define lpfc_sliport_status_end_MASK 0x1 -#define lpfc_sliport_status_end_WORD word0 -#define lpfc_sliport_status_oti_SHIFT 29 -#define lpfc_sliport_status_oti_MASK 0x1 -#define lpfc_sliport_status_oti_WORD word0 -#define lpfc_sliport_status_rn_SHIFT 24 -#define lpfc_sliport_status_rn_MASK 0x1 -#define lpfc_sliport_status_rn_WORD word0 -#define lpfc_sliport_status_rdy_SHIFT 23 -#define lpfc_sliport_status_rdy_MASK 0x1 -#define lpfc_sliport_status_rdy_WORD word0 -#define MAX_IF_TYPE_2_RESETS 1000 - -#define LPFC_CTL_PORT_CTL_OFFSET 0x408 -#define lpfc_sliport_ctrl_end_SHIFT 30 -#define lpfc_sliport_ctrl_end_MASK 0x1 -#define lpfc_sliport_ctrl_end_WORD word0 -#define LPFC_SLIPORT_LITTLE_ENDIAN 0 -#define LPFC_SLIPORT_BIG_ENDIAN 1 -#define lpfc_sliport_ctrl_ip_SHIFT 27 -#define lpfc_sliport_ctrl_ip_MASK 0x1 -#define lpfc_sliport_ctrl_ip_WORD word0 -#define LPFC_SLIPORT_INIT_PORT 1 - -#define LPFC_CTL_PORT_ER1_OFFSET 0x40C -#define LPFC_CTL_PORT_ER2_OFFSET 0x410 - -/* The following Registers apply to SLI4 if_type 0 UCNAs. They typically - * reside in BAR 2. - */ -#define LPFC_SLIPORT_IF0_SMPHR 0x00AC - -#define LPFC_IMR_MASK_ALL 0xFFFFFFFF -#define LPFC_ISCR_CLEAR_ALL 0xFFFFFFFF - -#define LPFC_HST_ISR0 0x0C18 -#define LPFC_HST_ISR1 0x0C1C -#define LPFC_HST_ISR2 0x0C20 -#define LPFC_HST_ISR3 0x0C24 -#define LPFC_HST_ISR4 0x0C28 - -#define LPFC_HST_IMR0 0x0C48 -#define LPFC_HST_IMR1 0x0C4C -#define LPFC_HST_IMR2 0x0C50 -#define LPFC_HST_IMR3 0x0C54 -#define LPFC_HST_IMR4 0x0C58 - -#define LPFC_HST_ISCR0 0x0C78 -#define LPFC_HST_ISCR1 0x0C7C -#define LPFC_HST_ISCR2 0x0C80 -#define LPFC_HST_ISCR3 0x0C84 -#define LPFC_HST_ISCR4 0x0C88 - -#define LPFC_SLI4_INTR0 BIT0 -#define LPFC_SLI4_INTR1 BIT1 -#define LPFC_SLI4_INTR2 BIT2 -#define LPFC_SLI4_INTR3 BIT3 -#define LPFC_SLI4_INTR4 BIT4 -#define LPFC_SLI4_INTR5 BIT5 -#define LPFC_SLI4_INTR6 BIT6 -#define LPFC_SLI4_INTR7 BIT7 -#define LPFC_SLI4_INTR8 BIT8 -#define LPFC_SLI4_INTR9 BIT9 -#define LPFC_SLI4_INTR10 BIT10 -#define LPFC_SLI4_INTR11 BIT11 -#define LPFC_SLI4_INTR12 BIT12 -#define LPFC_SLI4_INTR13 BIT13 -#define LPFC_SLI4_INTR14 BIT14 -#define LPFC_SLI4_INTR15 BIT15 -#define LPFC_SLI4_INTR16 BIT16 -#define LPFC_SLI4_INTR17 BIT17 -#define LPFC_SLI4_INTR18 BIT18 -#define LPFC_SLI4_INTR19 BIT19 -#define LPFC_SLI4_INTR20 BIT20 -#define LPFC_SLI4_INTR21 BIT21 -#define LPFC_SLI4_INTR22 BIT22 -#define LPFC_SLI4_INTR23 BIT23 -#define LPFC_SLI4_INTR24 BIT24 -#define LPFC_SLI4_INTR25 BIT25 -#define LPFC_SLI4_INTR26 BIT26 -#define LPFC_SLI4_INTR27 BIT27 -#define LPFC_SLI4_INTR28 BIT28 -#define LPFC_SLI4_INTR29 BIT29 -#define LPFC_SLI4_INTR30 BIT30 -#define LPFC_SLI4_INTR31 BIT31 - -/* - * The Doorbell registers defined here exist in different BAR - * register sets depending on the UCNA Port's reported if_type - * value. For UCNA ports running SLI4 and if_type 0, they reside in - * BAR4. For UCNA ports running SLI4 and if_type 2, they reside in - * BAR0. The offsets are the same so the driver must account for - * any base address difference. - */ -#define LPFC_RQ_DOORBELL 0x00A0 -#define lpfc_rq_doorbell_num_posted_SHIFT 16 -#define lpfc_rq_doorbell_num_posted_MASK 0x3FFF -#define lpfc_rq_doorbell_num_posted_WORD word0 -#define lpfc_rq_doorbell_id_SHIFT 0 -#define lpfc_rq_doorbell_id_MASK 0xFFFF -#define lpfc_rq_doorbell_id_WORD word0 - -#define LPFC_WQ_DOORBELL 0x0040 -#define lpfc_wq_doorbell_num_posted_SHIFT 24 -#define lpfc_wq_doorbell_num_posted_MASK 0x00FF -#define lpfc_wq_doorbell_num_posted_WORD word0 -#define lpfc_wq_doorbell_index_SHIFT 16 -#define lpfc_wq_doorbell_index_MASK 0x00FF -#define lpfc_wq_doorbell_index_WORD word0 -#define lpfc_wq_doorbell_id_SHIFT 0 -#define lpfc_wq_doorbell_id_MASK 0xFFFF -#define lpfc_wq_doorbell_id_WORD word0 - -#define LPFC_EQCQ_DOORBELL 0x0120 -#define lpfc_eqcq_doorbell_se_SHIFT 31 -#define lpfc_eqcq_doorbell_se_MASK 0x0001 -#define lpfc_eqcq_doorbell_se_WORD word0 -#define LPFC_EQCQ_SOLICIT_ENABLE_OFF 0 -#define LPFC_EQCQ_SOLICIT_ENABLE_ON 1 -#define lpfc_eqcq_doorbell_arm_SHIFT 29 -#define lpfc_eqcq_doorbell_arm_MASK 0x0001 -#define lpfc_eqcq_doorbell_arm_WORD word0 -#define lpfc_eqcq_doorbell_num_released_SHIFT 16 -#define lpfc_eqcq_doorbell_num_released_MASK 0x1FFF -#define lpfc_eqcq_doorbell_num_released_WORD word0 -#define lpfc_eqcq_doorbell_qt_SHIFT 10 -#define lpfc_eqcq_doorbell_qt_MASK 0x0001 -#define lpfc_eqcq_doorbell_qt_WORD word0 -#define LPFC_QUEUE_TYPE_COMPLETION 0 -#define LPFC_QUEUE_TYPE_EVENT 1 -#define lpfc_eqcq_doorbell_eqci_SHIFT 9 -#define lpfc_eqcq_doorbell_eqci_MASK 0x0001 -#define lpfc_eqcq_doorbell_eqci_WORD word0 -#define lpfc_eqcq_doorbell_cqid_lo_SHIFT 0 -#define lpfc_eqcq_doorbell_cqid_lo_MASK 0x03FF -#define lpfc_eqcq_doorbell_cqid_lo_WORD word0 -#define lpfc_eqcq_doorbell_cqid_hi_SHIFT 11 -#define lpfc_eqcq_doorbell_cqid_hi_MASK 0x001F -#define lpfc_eqcq_doorbell_cqid_hi_WORD word0 -#define lpfc_eqcq_doorbell_eqid_lo_SHIFT 0 -#define lpfc_eqcq_doorbell_eqid_lo_MASK 0x01FF -#define lpfc_eqcq_doorbell_eqid_lo_WORD word0 -#define lpfc_eqcq_doorbell_eqid_hi_SHIFT 11 -#define lpfc_eqcq_doorbell_eqid_hi_MASK 0x001F -#define lpfc_eqcq_doorbell_eqid_hi_WORD word0 -#define LPFC_CQID_HI_FIELD_SHIFT 10 -#define LPFC_EQID_HI_FIELD_SHIFT 9 - -#define LPFC_BMBX 0x0160 -#define lpfc_bmbx_addr_SHIFT 2 -#define lpfc_bmbx_addr_MASK 0x3FFFFFFF -#define lpfc_bmbx_addr_WORD word0 -#define lpfc_bmbx_hi_SHIFT 1 -#define lpfc_bmbx_hi_MASK 0x0001 -#define lpfc_bmbx_hi_WORD word0 -#define lpfc_bmbx_rdy_SHIFT 0 -#define lpfc_bmbx_rdy_MASK 0x0001 -#define lpfc_bmbx_rdy_WORD word0 - -#define LPFC_MQ_DOORBELL 0x0140 -#define lpfc_mq_doorbell_num_posted_SHIFT 16 -#define lpfc_mq_doorbell_num_posted_MASK 0x3FFF -#define lpfc_mq_doorbell_num_posted_WORD word0 -#define lpfc_mq_doorbell_id_SHIFT 0 -#define lpfc_mq_doorbell_id_MASK 0xFFFF -#define lpfc_mq_doorbell_id_WORD word0 - -struct lpfc_sli4_cfg_mhdr { - uint32_t word1; -#define lpfc_mbox_hdr_emb_SHIFT 0 -#define lpfc_mbox_hdr_emb_MASK 0x00000001 -#define lpfc_mbox_hdr_emb_WORD word1 -#define lpfc_mbox_hdr_sge_cnt_SHIFT 3 -#define lpfc_mbox_hdr_sge_cnt_MASK 0x0000001F -#define lpfc_mbox_hdr_sge_cnt_WORD word1 - uint32_t payload_length; - uint32_t tag_lo; - uint32_t tag_hi; - uint32_t reserved5; -}; - -union lpfc_sli4_cfg_shdr { - struct { - uint32_t word6; -#define lpfc_mbox_hdr_opcode_SHIFT 0 -#define lpfc_mbox_hdr_opcode_MASK 0x000000FF -#define lpfc_mbox_hdr_opcode_WORD word6 -#define lpfc_mbox_hdr_subsystem_SHIFT 8 -#define lpfc_mbox_hdr_subsystem_MASK 0x000000FF -#define lpfc_mbox_hdr_subsystem_WORD word6 -#define lpfc_mbox_hdr_port_number_SHIFT 16 -#define lpfc_mbox_hdr_port_number_MASK 0x000000FF -#define lpfc_mbox_hdr_port_number_WORD word6 -#define lpfc_mbox_hdr_domain_SHIFT 24 -#define lpfc_mbox_hdr_domain_MASK 0x000000FF -#define lpfc_mbox_hdr_domain_WORD word6 - uint32_t timeout; - uint32_t request_length; - uint32_t word9; -#define lpfc_mbox_hdr_version_SHIFT 0 -#define lpfc_mbox_hdr_version_MASK 0x000000FF -#define lpfc_mbox_hdr_version_WORD word9 -#define lpfc_mbox_hdr_pf_num_SHIFT 16 -#define lpfc_mbox_hdr_pf_num_MASK 0x000000FF -#define lpfc_mbox_hdr_pf_num_WORD word9 -#define lpfc_mbox_hdr_vh_num_SHIFT 24 -#define lpfc_mbox_hdr_vh_num_MASK 0x000000FF -#define lpfc_mbox_hdr_vh_num_WORD word9 -#define LPFC_Q_CREATE_VERSION_2 2 -#define LPFC_Q_CREATE_VERSION_1 1 -#define LPFC_Q_CREATE_VERSION_0 0 -#define LPFC_OPCODE_VERSION_0 0 -#define LPFC_OPCODE_VERSION_1 1 - } request; - struct { - uint32_t word6; -#define lpfc_mbox_hdr_opcode_SHIFT 0 -#define lpfc_mbox_hdr_opcode_MASK 0x000000FF -#define lpfc_mbox_hdr_opcode_WORD word6 -#define lpfc_mbox_hdr_subsystem_SHIFT 8 -#define lpfc_mbox_hdr_subsystem_MASK 0x000000FF -#define lpfc_mbox_hdr_subsystem_WORD word6 -#define lpfc_mbox_hdr_domain_SHIFT 24 -#define lpfc_mbox_hdr_domain_MASK 0x000000FF -#define lpfc_mbox_hdr_domain_WORD word6 - uint32_t word7; -#define lpfc_mbox_hdr_status_SHIFT 0 -#define lpfc_mbox_hdr_status_MASK 0x000000FF -#define lpfc_mbox_hdr_status_WORD word7 -#define lpfc_mbox_hdr_add_status_SHIFT 8 -#define lpfc_mbox_hdr_add_status_MASK 0x000000FF -#define lpfc_mbox_hdr_add_status_WORD word7 - uint32_t response_length; - uint32_t actual_response_length; - } response; -}; - -/* Mailbox Header structures. - * struct mbox_header is defined for first generation SLI4_CFG mailbox - * calls deployed for BE-based ports. - * - * struct sli4_mbox_header is defined for second generation SLI4 - * ports that don't deploy the SLI4_CFG mechanism. - */ -struct mbox_header { - struct lpfc_sli4_cfg_mhdr cfg_mhdr; - union lpfc_sli4_cfg_shdr cfg_shdr; -}; - -#define LPFC_EXTENT_LOCAL 0 -#define LPFC_TIMEOUT_DEFAULT 0 -#define LPFC_EXTENT_VERSION_DEFAULT 0 - -/* Subsystem Definitions */ -#define LPFC_MBOX_SUBSYSTEM_NA 0x0 -#define LPFC_MBOX_SUBSYSTEM_COMMON 0x1 -#define LPFC_MBOX_SUBSYSTEM_FCOE 0xC - -/* Device Specific Definitions */ - -/* The HOST ENDIAN defines are in Big Endian format. */ -#define HOST_ENDIAN_LOW_WORD0 0xFF3412FF -#define HOST_ENDIAN_HIGH_WORD1 0xFF7856FF - -/* Common Opcodes */ -#define LPFC_MBOX_OPCODE_NA 0x00 -#define LPFC_MBOX_OPCODE_CQ_CREATE 0x0C -#define LPFC_MBOX_OPCODE_EQ_CREATE 0x0D -#define LPFC_MBOX_OPCODE_MQ_CREATE 0x15 -#define LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES 0x20 -#define LPFC_MBOX_OPCODE_NOP 0x21 -#define LPFC_MBOX_OPCODE_MQ_DESTROY 0x35 -#define LPFC_MBOX_OPCODE_CQ_DESTROY 0x36 -#define LPFC_MBOX_OPCODE_EQ_DESTROY 0x37 -#define LPFC_MBOX_OPCODE_QUERY_FW_CFG 0x3A -#define LPFC_MBOX_OPCODE_FUNCTION_RESET 0x3D -#define LPFC_MBOX_OPCODE_GET_PORT_NAME 0x4D -#define LPFC_MBOX_OPCODE_MQ_CREATE_EXT 0x5A -#define LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO 0x9A -#define LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT 0x9B -#define LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT 0x9C -#define LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT 0x9D -#define LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG 0xA0 -#define LPFC_MBOX_OPCODE_GET_PROFILE_CONFIG 0xA4 -#define LPFC_MBOX_OPCODE_SET_PROFILE_CONFIG 0xA5 -#define LPFC_MBOX_OPCODE_GET_PROFILE_LIST 0xA6 -#define LPFC_MBOX_OPCODE_SET_ACT_PROFILE 0xA8 -#define LPFC_MBOX_OPCODE_GET_FACTORY_PROFILE_CONFIG 0xA9 -#define LPFC_MBOX_OPCODE_READ_OBJECT 0xAB -#define LPFC_MBOX_OPCODE_WRITE_OBJECT 0xAC -#define LPFC_MBOX_OPCODE_READ_OBJECT_LIST 0xAD -#define LPFC_MBOX_OPCODE_DELETE_OBJECT 0xAE -#define LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS 0xB5 - -/* FCoE Opcodes */ -#define LPFC_MBOX_OPCODE_FCOE_WQ_CREATE 0x01 -#define LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY 0x02 -#define LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES 0x03 -#define LPFC_MBOX_OPCODE_FCOE_REMOVE_SGL_PAGES 0x04 -#define LPFC_MBOX_OPCODE_FCOE_RQ_CREATE 0x05 -#define LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY 0x06 -#define LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE 0x08 -#define LPFC_MBOX_OPCODE_FCOE_ADD_FCF 0x09 -#define LPFC_MBOX_OPCODE_FCOE_DELETE_FCF 0x0A -#define LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE 0x0B -#define LPFC_MBOX_OPCODE_FCOE_REDISCOVER_FCF 0x10 -#define LPFC_MBOX_OPCODE_FCOE_SET_FCLINK_SETTINGS 0x21 -#define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_STATE 0x22 -#define LPFC_MBOX_OPCODE_FCOE_LINK_DIAG_LOOPBACK 0x23 - -/* Mailbox command structures */ -struct eq_context { - uint32_t word0; -#define lpfc_eq_context_size_SHIFT 31 -#define lpfc_eq_context_size_MASK 0x00000001 -#define lpfc_eq_context_size_WORD word0 -#define LPFC_EQE_SIZE_4 0x0 -#define LPFC_EQE_SIZE_16 0x1 -#define lpfc_eq_context_valid_SHIFT 29 -#define lpfc_eq_context_valid_MASK 0x00000001 -#define lpfc_eq_context_valid_WORD word0 - uint32_t word1; -#define lpfc_eq_context_count_SHIFT 26 -#define lpfc_eq_context_count_MASK 0x00000003 -#define lpfc_eq_context_count_WORD word1 -#define LPFC_EQ_CNT_256 0x0 -#define LPFC_EQ_CNT_512 0x1 -#define LPFC_EQ_CNT_1024 0x2 -#define LPFC_EQ_CNT_2048 0x3 -#define LPFC_EQ_CNT_4096 0x4 - uint32_t word2; -#define lpfc_eq_context_delay_multi_SHIFT 13 -#define lpfc_eq_context_delay_multi_MASK 0x000003FF -#define lpfc_eq_context_delay_multi_WORD word2 - uint32_t reserved3; -}; - -struct sgl_page_pairs { - uint32_t sgl_pg0_addr_lo; - uint32_t sgl_pg0_addr_hi; - uint32_t sgl_pg1_addr_lo; - uint32_t sgl_pg1_addr_hi; -}; - -struct lpfc_mbx_post_sgl_pages { - struct mbox_header header; - uint32_t word0; -#define lpfc_post_sgl_pages_xri_SHIFT 0 -#define lpfc_post_sgl_pages_xri_MASK 0x0000FFFF -#define lpfc_post_sgl_pages_xri_WORD word0 -#define lpfc_post_sgl_pages_xricnt_SHIFT 16 -#define lpfc_post_sgl_pages_xricnt_MASK 0x0000FFFF -#define lpfc_post_sgl_pages_xricnt_WORD word0 - struct sgl_page_pairs sgl_pg_pairs[1]; -}; - -/* word0 of page-1 struct shares the same SHIFT/MASK/WORD defines as above */ -struct lpfc_mbx_post_uembed_sgl_page1 { - union lpfc_sli4_cfg_shdr cfg_shdr; - uint32_t word0; - struct sgl_page_pairs sgl_pg_pairs; -}; - -struct lpfc_mbx_sge { - uint32_t pa_lo; - uint32_t pa_hi; - uint32_t length; -}; - -struct lpfc_mbx_nembed_cmd { - struct lpfc_sli4_cfg_mhdr cfg_mhdr; -#define LPFC_SLI4_MBX_SGE_MAX_PAGES 19 - struct lpfc_mbx_sge sge[LPFC_SLI4_MBX_SGE_MAX_PAGES]; -}; - -struct lpfc_mbx_nembed_sge_virt { - void *addr[LPFC_SLI4_MBX_SGE_MAX_PAGES]; -}; - -struct lpfc_mbx_eq_create { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_eq_create_num_pages_SHIFT 0 -#define lpfc_mbx_eq_create_num_pages_MASK 0x0000FFFF -#define lpfc_mbx_eq_create_num_pages_WORD word0 - struct eq_context context; - struct dma_address page[LPFC_MAX_EQ_PAGE]; - } request; - struct { - uint32_t word0; -#define lpfc_mbx_eq_create_q_id_SHIFT 0 -#define lpfc_mbx_eq_create_q_id_MASK 0x0000FFFF -#define lpfc_mbx_eq_create_q_id_WORD word0 - } response; - } u; -}; - -struct lpfc_mbx_eq_destroy { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_eq_destroy_q_id_SHIFT 0 -#define lpfc_mbx_eq_destroy_q_id_MASK 0x0000FFFF -#define lpfc_mbx_eq_destroy_q_id_WORD word0 - } request; - struct { - uint32_t word0; - } response; - } u; -}; - -struct lpfc_mbx_nop { - struct mbox_header header; - uint32_t context[2]; -}; - -struct cq_context { - uint32_t word0; -#define lpfc_cq_context_event_SHIFT 31 -#define lpfc_cq_context_event_MASK 0x00000001 -#define lpfc_cq_context_event_WORD word0 -#define lpfc_cq_context_valid_SHIFT 29 -#define lpfc_cq_context_valid_MASK 0x00000001 -#define lpfc_cq_context_valid_WORD word0 -#define lpfc_cq_context_count_SHIFT 27 -#define lpfc_cq_context_count_MASK 0x00000003 -#define lpfc_cq_context_count_WORD word0 -#define LPFC_CQ_CNT_256 0x0 -#define LPFC_CQ_CNT_512 0x1 -#define LPFC_CQ_CNT_1024 0x2 - uint32_t word1; -#define lpfc_cq_eq_id_SHIFT 22 /* Version 0 Only */ -#define lpfc_cq_eq_id_MASK 0x000000FF -#define lpfc_cq_eq_id_WORD word1 -#define lpfc_cq_eq_id_2_SHIFT 0 /* Version 2 Only */ -#define lpfc_cq_eq_id_2_MASK 0x0000FFFF -#define lpfc_cq_eq_id_2_WORD word1 - uint32_t reserved0; - uint32_t reserved1; -}; - -struct lpfc_mbx_cq_create { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_cq_create_page_size_SHIFT 16 /* Version 2 Only */ -#define lpfc_mbx_cq_create_page_size_MASK 0x000000FF -#define lpfc_mbx_cq_create_page_size_WORD word0 -#define lpfc_mbx_cq_create_num_pages_SHIFT 0 -#define lpfc_mbx_cq_create_num_pages_MASK 0x0000FFFF -#define lpfc_mbx_cq_create_num_pages_WORD word0 - struct cq_context context; - struct dma_address page[LPFC_MAX_CQ_PAGE]; - } request; - struct { - uint32_t word0; -#define lpfc_mbx_cq_create_q_id_SHIFT 0 -#define lpfc_mbx_cq_create_q_id_MASK 0x0000FFFF -#define lpfc_mbx_cq_create_q_id_WORD word0 - } response; - } u; -}; - -struct lpfc_mbx_cq_destroy { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_cq_destroy_q_id_SHIFT 0 -#define lpfc_mbx_cq_destroy_q_id_MASK 0x0000FFFF -#define lpfc_mbx_cq_destroy_q_id_WORD word0 - } request; - struct { - uint32_t word0; - } response; - } u; -}; - -struct wq_context { - uint32_t reserved0; - uint32_t reserved1; - uint32_t reserved2; - uint32_t reserved3; -}; - -struct lpfc_mbx_wq_create { - struct mbox_header header; - union { - struct { /* Version 0 Request */ - uint32_t word0; -#define lpfc_mbx_wq_create_num_pages_SHIFT 0 -#define lpfc_mbx_wq_create_num_pages_MASK 0x0000FFFF -#define lpfc_mbx_wq_create_num_pages_WORD word0 -#define lpfc_mbx_wq_create_cq_id_SHIFT 16 -#define lpfc_mbx_wq_create_cq_id_MASK 0x0000FFFF -#define lpfc_mbx_wq_create_cq_id_WORD word0 - struct dma_address page[LPFC_MAX_WQ_PAGE]; - } request; - struct { /* Version 1 Request */ - uint32_t word0; /* Word 0 is the same as in v0 */ - uint32_t word1; -#define lpfc_mbx_wq_create_page_size_SHIFT 0 -#define lpfc_mbx_wq_create_page_size_MASK 0x000000FF -#define lpfc_mbx_wq_create_page_size_WORD word1 -#define lpfc_mbx_wq_create_wqe_size_SHIFT 8 -#define lpfc_mbx_wq_create_wqe_size_MASK 0x0000000F -#define lpfc_mbx_wq_create_wqe_size_WORD word1 -#define LPFC_WQ_WQE_SIZE_64 0x5 -#define LPFC_WQ_WQE_SIZE_128 0x6 -#define lpfc_mbx_wq_create_wqe_count_SHIFT 16 -#define lpfc_mbx_wq_create_wqe_count_MASK 0x0000FFFF -#define lpfc_mbx_wq_create_wqe_count_WORD word1 - uint32_t word2; - struct dma_address page[LPFC_MAX_WQ_PAGE-1]; - } request_1; - struct { - uint32_t word0; -#define lpfc_mbx_wq_create_q_id_SHIFT 0 -#define lpfc_mbx_wq_create_q_id_MASK 0x0000FFFF -#define lpfc_mbx_wq_create_q_id_WORD word0 - } response; - } u; -}; - -struct lpfc_mbx_wq_destroy { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_wq_destroy_q_id_SHIFT 0 -#define lpfc_mbx_wq_destroy_q_id_MASK 0x0000FFFF -#define lpfc_mbx_wq_destroy_q_id_WORD word0 - } request; - struct { - uint32_t word0; - } response; - } u; -}; - -#define LPFC_HDR_BUF_SIZE 128 -#define LPFC_DATA_BUF_SIZE 2048 -struct rq_context { - uint32_t word0; -#define lpfc_rq_context_rqe_count_SHIFT 16 /* Version 0 Only */ -#define lpfc_rq_context_rqe_count_MASK 0x0000000F -#define lpfc_rq_context_rqe_count_WORD word0 -#define LPFC_RQ_RING_SIZE_512 9 /* 512 entries */ -#define LPFC_RQ_RING_SIZE_1024 10 /* 1024 entries */ -#define LPFC_RQ_RING_SIZE_2048 11 /* 2048 entries */ -#define LPFC_RQ_RING_SIZE_4096 12 /* 4096 entries */ -#define lpfc_rq_context_rqe_count_1_SHIFT 16 /* Version 1 Only */ -#define lpfc_rq_context_rqe_count_1_MASK 0x0000FFFF -#define lpfc_rq_context_rqe_count_1_WORD word0 -#define lpfc_rq_context_rqe_size_SHIFT 8 /* Version 1 Only */ -#define lpfc_rq_context_rqe_size_MASK 0x0000000F -#define lpfc_rq_context_rqe_size_WORD word0 -#define LPFC_RQE_SIZE_8 2 -#define LPFC_RQE_SIZE_16 3 -#define LPFC_RQE_SIZE_32 4 -#define LPFC_RQE_SIZE_64 5 -#define LPFC_RQE_SIZE_128 6 -#define lpfc_rq_context_page_size_SHIFT 0 /* Version 1 Only */ -#define lpfc_rq_context_page_size_MASK 0x000000FF -#define lpfc_rq_context_page_size_WORD word0 - uint32_t reserved1; - uint32_t word2; -#define lpfc_rq_context_cq_id_SHIFT 16 -#define lpfc_rq_context_cq_id_MASK 0x000003FF -#define lpfc_rq_context_cq_id_WORD word2 -#define lpfc_rq_context_buf_size_SHIFT 0 -#define lpfc_rq_context_buf_size_MASK 0x0000FFFF -#define lpfc_rq_context_buf_size_WORD word2 - uint32_t buffer_size; /* Version 1 Only */ -}; - -struct lpfc_mbx_rq_create { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_rq_create_num_pages_SHIFT 0 -#define lpfc_mbx_rq_create_num_pages_MASK 0x0000FFFF -#define lpfc_mbx_rq_create_num_pages_WORD word0 - struct rq_context context; - struct dma_address page[LPFC_MAX_WQ_PAGE]; - } request; - struct { - uint32_t word0; -#define lpfc_mbx_rq_create_q_id_SHIFT 0 -#define lpfc_mbx_rq_create_q_id_MASK 0x0000FFFF -#define lpfc_mbx_rq_create_q_id_WORD word0 - } response; - } u; -}; - -struct lpfc_mbx_rq_destroy { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_rq_destroy_q_id_SHIFT 0 -#define lpfc_mbx_rq_destroy_q_id_MASK 0x0000FFFF -#define lpfc_mbx_rq_destroy_q_id_WORD word0 - } request; - struct { - uint32_t word0; - } response; - } u; -}; - -struct mq_context { - uint32_t word0; -#define lpfc_mq_context_cq_id_SHIFT 22 /* Version 0 Only */ -#define lpfc_mq_context_cq_id_MASK 0x000003FF -#define lpfc_mq_context_cq_id_WORD word0 -#define lpfc_mq_context_ring_size_SHIFT 16 -#define lpfc_mq_context_ring_size_MASK 0x0000000F -#define lpfc_mq_context_ring_size_WORD word0 -#define LPFC_MQ_RING_SIZE_16 0x5 -#define LPFC_MQ_RING_SIZE_32 0x6 -#define LPFC_MQ_RING_SIZE_64 0x7 -#define LPFC_MQ_RING_SIZE_128 0x8 - uint32_t word1; -#define lpfc_mq_context_valid_SHIFT 31 -#define lpfc_mq_context_valid_MASK 0x00000001 -#define lpfc_mq_context_valid_WORD word1 - uint32_t reserved2; - uint32_t reserved3; -}; - -struct lpfc_mbx_mq_create { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_mq_create_num_pages_SHIFT 0 -#define lpfc_mbx_mq_create_num_pages_MASK 0x0000FFFF -#define lpfc_mbx_mq_create_num_pages_WORD word0 - struct mq_context context; - struct dma_address page[LPFC_MAX_MQ_PAGE]; - } request; - struct { - uint32_t word0; -#define lpfc_mbx_mq_create_q_id_SHIFT 0 -#define lpfc_mbx_mq_create_q_id_MASK 0x0000FFFF -#define lpfc_mbx_mq_create_q_id_WORD word0 - } response; - } u; -}; - -struct lpfc_mbx_mq_create_ext { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_mq_create_ext_num_pages_SHIFT 0 -#define lpfc_mbx_mq_create_ext_num_pages_MASK 0x0000FFFF -#define lpfc_mbx_mq_create_ext_num_pages_WORD word0 -#define lpfc_mbx_mq_create_ext_cq_id_SHIFT 16 /* Version 1 Only */ -#define lpfc_mbx_mq_create_ext_cq_id_MASK 0x0000FFFF -#define lpfc_mbx_mq_create_ext_cq_id_WORD word0 - uint32_t async_evt_bmap; -#define lpfc_mbx_mq_create_ext_async_evt_link_SHIFT LPFC_TRAILER_CODE_LINK -#define lpfc_mbx_mq_create_ext_async_evt_link_MASK 0x00000001 -#define lpfc_mbx_mq_create_ext_async_evt_link_WORD async_evt_bmap -#define lpfc_mbx_mq_create_ext_async_evt_fip_SHIFT LPFC_TRAILER_CODE_FCOE -#define lpfc_mbx_mq_create_ext_async_evt_fip_MASK 0x00000001 -#define lpfc_mbx_mq_create_ext_async_evt_fip_WORD async_evt_bmap -#define lpfc_mbx_mq_create_ext_async_evt_group5_SHIFT LPFC_TRAILER_CODE_GRP5 -#define lpfc_mbx_mq_create_ext_async_evt_group5_MASK 0x00000001 -#define lpfc_mbx_mq_create_ext_async_evt_group5_WORD async_evt_bmap -#define lpfc_mbx_mq_create_ext_async_evt_fc_SHIFT LPFC_TRAILER_CODE_FC -#define lpfc_mbx_mq_create_ext_async_evt_fc_MASK 0x00000001 -#define lpfc_mbx_mq_create_ext_async_evt_fc_WORD async_evt_bmap -#define lpfc_mbx_mq_create_ext_async_evt_sli_SHIFT LPFC_TRAILER_CODE_SLI -#define lpfc_mbx_mq_create_ext_async_evt_sli_MASK 0x00000001 -#define lpfc_mbx_mq_create_ext_async_evt_sli_WORD async_evt_bmap - struct mq_context context; - struct dma_address page[LPFC_MAX_MQ_PAGE]; - } request; - struct { - uint32_t word0; -#define lpfc_mbx_mq_create_q_id_SHIFT 0 -#define lpfc_mbx_mq_create_q_id_MASK 0x0000FFFF -#define lpfc_mbx_mq_create_q_id_WORD word0 - } response; - } u; -#define LPFC_ASYNC_EVENT_LINK_STATE 0x2 -#define LPFC_ASYNC_EVENT_FCF_STATE 0x4 -#define LPFC_ASYNC_EVENT_GROUP5 0x20 -}; - -struct lpfc_mbx_mq_destroy { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_mq_destroy_q_id_SHIFT 0 -#define lpfc_mbx_mq_destroy_q_id_MASK 0x0000FFFF -#define lpfc_mbx_mq_destroy_q_id_WORD word0 - } request; - struct { - uint32_t word0; - } response; - } u; -}; - -/* Start Gen 2 SLI4 Mailbox definitions: */ - -/* Define allocate-ready Gen 2 SLI4 FCoE Resource Extent Types. */ -#define LPFC_RSC_TYPE_FCOE_VFI 0x20 -#define LPFC_RSC_TYPE_FCOE_VPI 0x21 -#define LPFC_RSC_TYPE_FCOE_RPI 0x22 -#define LPFC_RSC_TYPE_FCOE_XRI 0x23 - -struct lpfc_mbx_get_rsrc_extent_info { - struct mbox_header header; - union { - struct { - uint32_t word4; -#define lpfc_mbx_get_rsrc_extent_info_type_SHIFT 0 -#define lpfc_mbx_get_rsrc_extent_info_type_MASK 0x0000FFFF -#define lpfc_mbx_get_rsrc_extent_info_type_WORD word4 - } req; - struct { - uint32_t word4; -#define lpfc_mbx_get_rsrc_extent_info_cnt_SHIFT 0 -#define lpfc_mbx_get_rsrc_extent_info_cnt_MASK 0x0000FFFF -#define lpfc_mbx_get_rsrc_extent_info_cnt_WORD word4 -#define lpfc_mbx_get_rsrc_extent_info_size_SHIFT 16 -#define lpfc_mbx_get_rsrc_extent_info_size_MASK 0x0000FFFF -#define lpfc_mbx_get_rsrc_extent_info_size_WORD word4 - } rsp; - } u; -}; - -struct lpfc_id_range { - uint32_t word5; -#define lpfc_mbx_rsrc_id_word4_0_SHIFT 0 -#define lpfc_mbx_rsrc_id_word4_0_MASK 0x0000FFFF -#define lpfc_mbx_rsrc_id_word4_0_WORD word5 -#define lpfc_mbx_rsrc_id_word4_1_SHIFT 16 -#define lpfc_mbx_rsrc_id_word4_1_MASK 0x0000FFFF -#define lpfc_mbx_rsrc_id_word4_1_WORD word5 -}; - -struct lpfc_mbx_set_link_diag_state { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_set_diag_state_diag_SHIFT 0 -#define lpfc_mbx_set_diag_state_diag_MASK 0x00000001 -#define lpfc_mbx_set_diag_state_diag_WORD word0 -#define lpfc_mbx_set_diag_state_link_num_SHIFT 16 -#define lpfc_mbx_set_diag_state_link_num_MASK 0x0000003F -#define lpfc_mbx_set_diag_state_link_num_WORD word0 -#define lpfc_mbx_set_diag_state_link_type_SHIFT 22 -#define lpfc_mbx_set_diag_state_link_type_MASK 0x00000003 -#define lpfc_mbx_set_diag_state_link_type_WORD word0 - } req; - struct { - uint32_t word0; - } rsp; - } u; -}; - -struct lpfc_mbx_set_link_diag_loopback { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_set_diag_lpbk_type_SHIFT 0 -#define lpfc_mbx_set_diag_lpbk_type_MASK 0x00000003 -#define lpfc_mbx_set_diag_lpbk_type_WORD word0 -#define LPFC_DIAG_LOOPBACK_TYPE_DISABLE 0x0 -#define LPFC_DIAG_LOOPBACK_TYPE_INTERNAL 0x1 -#define LPFC_DIAG_LOOPBACK_TYPE_SERDES 0x2 -#define lpfc_mbx_set_diag_lpbk_link_num_SHIFT 16 -#define lpfc_mbx_set_diag_lpbk_link_num_MASK 0x0000003F -#define lpfc_mbx_set_diag_lpbk_link_num_WORD word0 -#define lpfc_mbx_set_diag_lpbk_link_type_SHIFT 22 -#define lpfc_mbx_set_diag_lpbk_link_type_MASK 0x00000003 -#define lpfc_mbx_set_diag_lpbk_link_type_WORD word0 - } req; - struct { - uint32_t word0; - } rsp; - } u; -}; - -struct lpfc_mbx_run_link_diag_test { - struct mbox_header header; - union { - struct { - uint32_t word0; -#define lpfc_mbx_run_diag_test_link_num_SHIFT 16 -#define lpfc_mbx_run_diag_test_link_num_MASK 0x0000003F -#define lpfc_mbx_run_diag_test_link_num_WORD word0 -#define lpfc_mbx_run_diag_test_link_type_SHIFT 22 -#define lpfc_mbx_run_diag_test_link_type_MASK 0x00000003 -#define lpfc_mbx_run_diag_test_link_type_WORD word0 - uint32_t word1; -#define lpfc_mbx_run_diag_test_test_id_SHIFT 0 -#define lpfc_mbx_run_diag_test_test_id_MASK 0x0000FFFF -#define lpfc_mbx_run_diag_test_test_id_WORD word1 -#define lpfc_mbx_run_diag_test_loops_SHIFT 16 -#define lpfc_mbx_run_diag_test_loops_MASK 0x0000FFFF -#define lpfc_mbx_run_diag_test_loops_WORD word1 - uint32_t word2; -#define lpfc_mbx_run_diag_test_test_ver_SHIFT 0 -#define lpfc_mbx_run_diag_test_test_ver_MASK 0x0000FFFF -#define lpfc_mbx_run_diag_test_test_ver_WORD word2 -#define lpfc_mbx_run_diag_test_err_act_SHIFT 16 -#define lpfc_mbx_run_diag_test_err_act_MASK 0x000000FF -#define lpfc_mbx_run_diag_test_err_act_WORD word2 - } req; - struct { - uint32_t word0; - } rsp; - } u; -}; - -/* - * struct lpfc_mbx_alloc_rsrc_extents: - * A mbox is generically 256 bytes long. An SLI4_CONFIG mailbox requires - * 6 words of header + 4 words of shared subcommand header + - * 1 words of Extent-Opcode-specific header = 11 words or 44 bytes total. - * - * An embedded version of SLI4_CONFIG therefore has 256 - 44 = 212 bytes - * for extents payload. - * - * 212/2 (bytes per extent) = 106 extents. - * 106/2 (extents per word) = 53 words. - * lpfc_id_range id is statically size to 53. - * - * This mailbox definition is used for ALLOC or GET_ALLOCATED - * extent ranges. For ALLOC, the type and cnt are required. - * For GET_ALLOCATED, only the type is required. - */ -struct lpfc_mbx_alloc_rsrc_extents { - struct mbox_header header; - union { - struct { - uint32_t word4; -#define lpfc_mbx_alloc_rsrc_extents_type_SHIFT 0 -#define lpfc_mbx_alloc_rsrc_extents_type_MASK 0x0000FFFF -#define lpfc_mbx_alloc_rsrc_extents_type_WORD word4 -#define lpfc_mbx_alloc_rsrc_extents_cnt_SHIFT 16 -#define lpfc_mbx_alloc_rsrc_extents_cnt_MASK 0x0000FFFF -#define lpfc_mbx_alloc_rsrc_extents_cnt_WORD word4 - } req; - struct { - uint32_t word4; -#define lpfc_mbx_rsrc_cnt_SHIFT 0 -#define lpfc_mbx_rsrc_cnt_MASK 0x0000FFFF -#define lpfc_mbx_rsrc_cnt_WORD word4 - struct lpfc_id_range id[53]; - } rsp; - } u; -}; - -/* - * This is the non-embedded version of ALLOC or GET RSRC_EXTENTS. Word4 in this - * structure shares the same SHIFT/MASK/WORD defines provided in the - * mbx_alloc_rsrc_extents and mbx_get_alloc_rsrc_extents, word4, provided in - * the structures defined above. This non-embedded structure provides for the - * maximum number of extents supported by the port. - */ -struct lpfc_mbx_nembed_rsrc_extent { - union lpfc_sli4_cfg_shdr cfg_shdr; - uint32_t word4; - struct lpfc_id_range id; -}; - -struct lpfc_mbx_dealloc_rsrc_extents { - struct mbox_header header; - struct { - uint32_t word4; -#define lpfc_mbx_dealloc_rsrc_extents_type_SHIFT 0 -#define lpfc_mbx_dealloc_rsrc_extents_type_MASK 0x0000FFFF -#define lpfc_mbx_dealloc_rsrc_extents_type_WORD word4 - } req; - -}; - -/* Start SLI4 FCoE specific mbox structures. */ - -struct lpfc_mbx_post_hdr_tmpl { - struct mbox_header header; - uint32_t word10; -#define lpfc_mbx_post_hdr_tmpl_rpi_offset_SHIFT 0 -#define lpfc_mbx_post_hdr_tmpl_rpi_offset_MASK 0x0000FFFF -#define lpfc_mbx_post_hdr_tmpl_rpi_offset_WORD word10 -#define lpfc_mbx_post_hdr_tmpl_page_cnt_SHIFT 16 -#define lpfc_mbx_post_hdr_tmpl_page_cnt_MASK 0x0000FFFF -#define lpfc_mbx_post_hdr_tmpl_page_cnt_WORD word10 - uint32_t rpi_paddr_lo; - uint32_t rpi_paddr_hi; -}; - -struct sli4_sge { /* SLI-4 */ - uint32_t addr_hi; - uint32_t addr_lo; - - uint32_t word2; -#define lpfc_sli4_sge_offset_SHIFT 0 -#define lpfc_sli4_sge_offset_MASK 0x07FFFFFF -#define lpfc_sli4_sge_offset_WORD word2 -#define lpfc_sli4_sge_type_SHIFT 27 -#define lpfc_sli4_sge_type_MASK 0x0000000F -#define lpfc_sli4_sge_type_WORD word2 -#define LPFC_SGE_TYPE_DATA 0x0 -#define LPFC_SGE_TYPE_DIF 0x4 -#define LPFC_SGE_TYPE_LSP 0x5 -#define LPFC_SGE_TYPE_PEDIF 0x6 -#define LPFC_SGE_TYPE_PESEED 0x7 -#define LPFC_SGE_TYPE_DISEED 0x8 -#define LPFC_SGE_TYPE_ENC 0x9 -#define LPFC_SGE_TYPE_ATM 0xA -#define LPFC_SGE_TYPE_SKIP 0xC -#define lpfc_sli4_sge_last_SHIFT 31 /* Last SEG in the SGL sets it */ -#define lpfc_sli4_sge_last_MASK 0x00000001 -#define lpfc_sli4_sge_last_WORD word2 - uint32_t sge_len; -}; - -struct sli4_sge_diseed { /* SLI-4 */ - uint32_t ref_tag; - uint32_t ref_tag_tran; - - uint32_t word2; -#define lpfc_sli4_sge_dif_apptran_SHIFT 0 -#define lpfc_sli4_sge_dif_apptran_MASK 0x0000FFFF -#define lpfc_sli4_sge_dif_apptran_WORD word2 -#define lpfc_sli4_sge_dif_af_SHIFT 24 -#define lpfc_sli4_sge_dif_af_MASK 0x00000001 -#define lpfc_sli4_sge_dif_af_WORD word2 -#define lpfc_sli4_sge_dif_na_SHIFT 25 -#define lpfc_sli4_sge_dif_na_MASK 0x00000001 -#define lpfc_sli4_sge_dif_na_WORD word2 -#define lpfc_sli4_sge_dif_hi_SHIFT 26 -#define lpfc_sli4_sge_dif_hi_MASK 0x00000001 -#define lpfc_sli4_sge_dif_hi_WORD word2 -#define lpfc_sli4_sge_dif_type_SHIFT 27 -#define lpfc_sli4_sge_dif_type_MASK 0x0000000F -#define lpfc_sli4_sge_dif_type_WORD word2 -#define lpfc_sli4_sge_dif_last_SHIFT 31 /* Last SEG in the SGL sets it */ -#define lpfc_sli4_sge_dif_last_MASK 0x00000001 -#define lpfc_sli4_sge_dif_last_WORD word2 - uint32_t word3; -#define lpfc_sli4_sge_dif_apptag_SHIFT 0 -#define lpfc_sli4_sge_dif_apptag_MASK 0x0000FFFF -#define lpfc_sli4_sge_dif_apptag_WORD word3 -#define lpfc_sli4_sge_dif_bs_SHIFT 16 -#define lpfc_sli4_sge_dif_bs_MASK 0x00000007 -#define lpfc_sli4_sge_dif_bs_WORD word3 -#define lpfc_sli4_sge_dif_ai_SHIFT 19 -#define lpfc_sli4_sge_dif_ai_MASK 0x00000001 -#define lpfc_sli4_sge_dif_ai_WORD word3 -#define lpfc_sli4_sge_dif_me_SHIFT 20 -#define lpfc_sli4_sge_dif_me_MASK 0x00000001 -#define lpfc_sli4_sge_dif_me_WORD word3 -#define lpfc_sli4_sge_dif_re_SHIFT 21 -#define lpfc_sli4_sge_dif_re_MASK 0x00000001 -#define lpfc_sli4_sge_dif_re_WORD word3 -#define lpfc_sli4_sge_dif_ce_SHIFT 22 -#define lpfc_sli4_sge_dif_ce_MASK 0x00000001 -#define lpfc_sli4_sge_dif_ce_WORD word3 -#define lpfc_sli4_sge_dif_nr_SHIFT 23 -#define lpfc_sli4_sge_dif_nr_MASK 0x00000001 -#define lpfc_sli4_sge_dif_nr_WORD word3 -#define lpfc_sli4_sge_dif_oprx_SHIFT 24 -#define lpfc_sli4_sge_dif_oprx_MASK 0x0000000F -#define lpfc_sli4_sge_dif_oprx_WORD word3 -#define lpfc_sli4_sge_dif_optx_SHIFT 28 -#define lpfc_sli4_sge_dif_optx_MASK 0x0000000F -#define lpfc_sli4_sge_dif_optx_WORD word3 -/* optx and oprx use BG_OP_IN defines in lpfc_hw.h */ -}; - -struct fcf_record { - uint32_t max_rcv_size; - uint32_t fka_adv_period; - uint32_t fip_priority; - uint32_t word3; -#define lpfc_fcf_record_mac_0_SHIFT 0 -#define lpfc_fcf_record_mac_0_MASK 0x000000FF -#define lpfc_fcf_record_mac_0_WORD word3 -#define lpfc_fcf_record_mac_1_SHIFT 8 -#define lpfc_fcf_record_mac_1_MASK 0x000000FF -#define lpfc_fcf_record_mac_1_WORD word3 -#define lpfc_fcf_record_mac_2_SHIFT 16 -#define lpfc_fcf_record_mac_2_MASK 0x000000FF -#define lpfc_fcf_record_mac_2_WORD word3 -#define lpfc_fcf_record_mac_3_SHIFT 24 -#define lpfc_fcf_record_mac_3_MASK 0x000000FF -#define lpfc_fcf_record_mac_3_WORD word3 - uint32_t word4; -#define lpfc_fcf_record_mac_4_SHIFT 0 -#define lpfc_fcf_record_mac_4_MASK 0x000000FF -#define lpfc_fcf_record_mac_4_WORD word4 -#define lpfc_fcf_record_mac_5_SHIFT 8 -#define lpfc_fcf_record_mac_5_MASK 0x000000FF -#define lpfc_fcf_record_mac_5_WORD word4 -#define lpfc_fcf_record_fcf_avail_SHIFT 16 -#define lpfc_fcf_record_fcf_avail_MASK 0x000000FF -#define lpfc_fcf_record_fcf_avail_WORD word4 -#define lpfc_fcf_record_mac_addr_prov_SHIFT 24 -#define lpfc_fcf_record_mac_addr_prov_MASK 0x000000FF -#define lpfc_fcf_record_mac_addr_prov_WORD word4 -#define LPFC_FCF_FPMA 1 /* Fabric Provided MAC Address */ -#define LPFC_FCF_SPMA 2 /* Server Provided MAC Address */ - uint32_t word5; -#define lpfc_fcf_record_fab_name_0_SHIFT 0 -#define lpfc_fcf_record_fab_name_0_MASK 0x000000FF -#define lpfc_fcf_record_fab_name_0_WORD word5 -#define lpfc_fcf_record_fab_name_1_SHIFT 8 -#define lpfc_fcf_record_fab_name_1_MASK 0x000000FF -#define lpfc_fcf_record_fab_name_1_WORD word5 -#define lpfc_fcf_record_fab_name_2_SHIFT 16 -#define lpfc_fcf_record_fab_name_2_MASK 0x000000FF -#define lpfc_fcf_record_fab_name_2_WORD word5 -#define lpfc_fcf_record_fab_name_3_SHIFT 24 -#define lpfc_fcf_record_fab_name_3_MASK 0x000000FF -#define lpfc_fcf_record_fab_name_3_WORD word5 - uint32_t word6; -#define lpfc_fcf_record_fab_name_4_SHIFT 0 -#define lpfc_fcf_record_fab_name_4_MASK 0x000000FF -#define lpfc_fcf_record_fab_name_4_WORD word6 -#define lpfc_fcf_record_fab_name_5_SHIFT 8 -#define lpfc_fcf_record_fab_name_5_MASK 0x000000FF -#define lpfc_fcf_record_fab_name_5_WORD word6 -#define lpfc_fcf_record_fab_name_6_SHIFT 16 -#define lpfc_fcf_record_fab_name_6_MASK 0x000000FF -#define lpfc_fcf_record_fab_name_6_WORD word6 -#define lpfc_fcf_record_fab_name_7_SHIFT 24 -#define lpfc_fcf_record_fab_name_7_MASK 0x000000FF -#define lpfc_fcf_record_fab_name_7_WORD word6 - uint32_t word7; -#define lpfc_fcf_record_fc_map_0_SHIFT 0 -#define lpfc_fcf_record_fc_map_0_MASK 0x000000FF -#define lpfc_fcf_record_fc_map_0_WORD word7 -#define lpfc_fcf_record_fc_map_1_SHIFT 8 -#define lpfc_fcf_record_fc_map_1_MASK 0x000000FF -#define lpfc_fcf_record_fc_map_1_WORD word7 -#define lpfc_fcf_record_fc_map_2_SHIFT 16 -#define lpfc_fcf_record_fc_map_2_MASK 0x000000FF -#define lpfc_fcf_record_fc_map_2_WORD word7 -#define lpfc_fcf_record_fcf_valid_SHIFT 24 -#define lpfc_fcf_record_fcf_valid_MASK 0x000000FF -#define lpfc_fcf_record_fcf_valid_WORD word7 - uint32_t word8; -#define lpfc_fcf_record_fcf_index_SHIFT 0 -#define lpfc_fcf_record_fcf_index_MASK 0x0000FFFF -#define lpfc_fcf_record_fcf_index_WORD word8 -#define lpfc_fcf_record_fcf_state_SHIFT 16 -#define lpfc_fcf_record_fcf_state_MASK 0x0000FFFF -#define lpfc_fcf_record_fcf_state_WORD word8 - uint8_t vlan_bitmap[512]; - uint32_t word137; -#define lpfc_fcf_record_switch_name_0_SHIFT 0 -#define lpfc_fcf_record_switch_name_0_MASK 0x000000FF -#define lpfc_fcf_record_switch_name_0_WORD word137 -#define lpfc_fcf_record_switch_name_1_SHIFT 8 -#define lpfc_fcf_record_switch_name_1_MASK 0x000000FF -#define lpfc_fcf_record_switch_name_1_WORD word137 -#define lpfc_fcf_record_switch_name_2_SHIFT 16 -#define lpfc_fcf_record_switch_name_2_MASK 0x000000FF -#define lpfc_fcf_record_switch_name_2_WORD word137 -#define lpfc_fcf_record_switch_name_3_SHIFT 24 -#define lpfc_fcf_record_switch_name_3_MASK 0x000000FF -#define lpfc_fcf_record_switch_name_3_WORD word137 - uint32_t word138; -#define lpfc_fcf_record_switch_name_4_SHIFT 0 -#define lpfc_fcf_record_switch_name_4_MASK 0x000000FF -#define lpfc_fcf_record_switch_name_4_WORD word138 -#define lpfc_fcf_record_switch_name_5_SHIFT 8 -#define lpfc_fcf_record_switch_name_5_MASK 0x000000FF -#define lpfc_fcf_record_switch_name_5_WORD word138 -#define lpfc_fcf_record_switch_name_6_SHIFT 16 -#define lpfc_fcf_record_switch_name_6_MASK 0x000000FF -#define lpfc_fcf_record_switch_name_6_WORD word138 -#define lpfc_fcf_record_switch_name_7_SHIFT 24 -#define lpfc_fcf_record_switch_name_7_MASK 0x000000FF -#define lpfc_fcf_record_switch_name_7_WORD word138 -}; - -struct lpfc_mbx_read_fcf_tbl { - union lpfc_sli4_cfg_shdr cfg_shdr; - union { - struct { - uint32_t word10; -#define lpfc_mbx_read_fcf_tbl_indx_SHIFT 0 -#define lpfc_mbx_read_fcf_tbl_indx_MASK 0x0000FFFF -#define lpfc_mbx_read_fcf_tbl_indx_WORD word10 - } request; - struct { - uint32_t eventag; - } response; - } u; - uint32_t word11; -#define lpfc_mbx_read_fcf_tbl_nxt_vindx_SHIFT 0 -#define lpfc_mbx_read_fcf_tbl_nxt_vindx_MASK 0x0000FFFF -#define lpfc_mbx_read_fcf_tbl_nxt_vindx_WORD word11 -}; - -struct lpfc_mbx_add_fcf_tbl_entry { - union lpfc_sli4_cfg_shdr cfg_shdr; - uint32_t word10; -#define lpfc_mbx_add_fcf_tbl_fcfi_SHIFT 0 -#define lpfc_mbx_add_fcf_tbl_fcfi_MASK 0x0000FFFF -#define lpfc_mbx_add_fcf_tbl_fcfi_WORD word10 - struct lpfc_mbx_sge fcf_sge; -}; - -struct lpfc_mbx_del_fcf_tbl_entry { - struct mbox_header header; - uint32_t word10; -#define lpfc_mbx_del_fcf_tbl_count_SHIFT 0 -#define lpfc_mbx_del_fcf_tbl_count_MASK 0x0000FFFF -#define lpfc_mbx_del_fcf_tbl_count_WORD word10 -#define lpfc_mbx_del_fcf_tbl_index_SHIFT 16 -#define lpfc_mbx_del_fcf_tbl_index_MASK 0x0000FFFF -#define lpfc_mbx_del_fcf_tbl_index_WORD word10 -}; - -struct lpfc_mbx_redisc_fcf_tbl { - struct mbox_header header; - uint32_t word10; -#define lpfc_mbx_redisc_fcf_count_SHIFT 0 -#define lpfc_mbx_redisc_fcf_count_MASK 0x0000FFFF -#define lpfc_mbx_redisc_fcf_count_WORD word10 - uint32_t resvd; - uint32_t word12; -#define lpfc_mbx_redisc_fcf_index_SHIFT 0 -#define lpfc_mbx_redisc_fcf_index_MASK 0x0000FFFF -#define lpfc_mbx_redisc_fcf_index_WORD word12 -}; - -struct lpfc_mbx_query_fw_cfg { - struct mbox_header header; - uint32_t config_number; - uint32_t asic_rev; - uint32_t phys_port; - uint32_t function_mode; -/* firmware Function Mode */ -#define lpfc_function_mode_toe_SHIFT 0 -#define lpfc_function_mode_toe_MASK 0x00000001 -#define lpfc_function_mode_toe_WORD function_mode -#define lpfc_function_mode_nic_SHIFT 1 -#define lpfc_function_mode_nic_MASK 0x00000001 -#define lpfc_function_mode_nic_WORD function_mode -#define lpfc_function_mode_rdma_SHIFT 2 -#define lpfc_function_mode_rdma_MASK 0x00000001 -#define lpfc_function_mode_rdma_WORD function_mode -#define lpfc_function_mode_vm_SHIFT 3 -#define lpfc_function_mode_vm_MASK 0x00000001 -#define lpfc_function_mode_vm_WORD function_mode -#define lpfc_function_mode_iscsi_i_SHIFT 4 -#define lpfc_function_mode_iscsi_i_MASK 0x00000001 -#define lpfc_function_mode_iscsi_i_WORD function_mode -#define lpfc_function_mode_iscsi_t_SHIFT 5 -#define lpfc_function_mode_iscsi_t_MASK 0x00000001 -#define lpfc_function_mode_iscsi_t_WORD function_mode -#define lpfc_function_mode_fcoe_i_SHIFT 6 -#define lpfc_function_mode_fcoe_i_MASK 0x00000001 -#define lpfc_function_mode_fcoe_i_WORD function_mode -#define lpfc_function_mode_fcoe_t_SHIFT 7 -#define lpfc_function_mode_fcoe_t_MASK 0x00000001 -#define lpfc_function_mode_fcoe_t_WORD function_mode -#define lpfc_function_mode_dal_SHIFT 8 -#define lpfc_function_mode_dal_MASK 0x00000001 -#define lpfc_function_mode_dal_WORD function_mode -#define lpfc_function_mode_lro_SHIFT 9 -#define lpfc_function_mode_lro_MASK 0x00000001 -#define lpfc_function_mode_lro_WORD function_mode -#define lpfc_function_mode_flex10_SHIFT 10 -#define lpfc_function_mode_flex10_MASK 0x00000001 -#define lpfc_function_mode_flex10_WORD function_mode -#define lpfc_function_mode_ncsi_SHIFT 11 -#define lpfc_function_mode_ncsi_MASK 0x00000001 -#define lpfc_function_mode_ncsi_WORD function_mode -}; - -/* Status field for embedded SLI_CONFIG mailbox command */ -#define STATUS_SUCCESS 0x0 -#define STATUS_FAILED 0x1 -#define STATUS_ILLEGAL_REQUEST 0x2 -#define STATUS_ILLEGAL_FIELD 0x3 -#define STATUS_INSUFFICIENT_BUFFER 0x4 -#define STATUS_UNAUTHORIZED_REQUEST 0x5 -#define STATUS_FLASHROM_SAVE_FAILED 0x17 -#define STATUS_FLASHROM_RESTORE_FAILED 0x18 -#define STATUS_ICCBINDEX_ALLOC_FAILED 0x1a -#define STATUS_IOCTLHANDLE_ALLOC_FAILED 0x1b -#define STATUS_INVALID_PHY_ADDR_FROM_OSM 0x1c -#define STATUS_INVALID_PHY_ADDR_LEN_FROM_OSM 0x1d -#define STATUS_ASSERT_FAILED 0x1e -#define STATUS_INVALID_SESSION 0x1f -#define STATUS_INVALID_CONNECTION 0x20 -#define STATUS_BTL_PATH_EXCEEDS_OSM_LIMIT 0x21 -#define STATUS_BTL_NO_FREE_SLOT_PATH 0x24 -#define STATUS_BTL_NO_FREE_SLOT_TGTID 0x25 -#define STATUS_OSM_DEVSLOT_NOT_FOUND 0x26 -#define STATUS_FLASHROM_READ_FAILED 0x27 -#define STATUS_POLL_IOCTL_TIMEOUT 0x28 -#define STATUS_ERROR_ACITMAIN 0x2a -#define STATUS_REBOOT_REQUIRED 0x2c -#define STATUS_FCF_IN_USE 0x3a -#define STATUS_FCF_TABLE_EMPTY 0x43 - -struct lpfc_mbx_sli4_config { - struct mbox_header header; -}; - -struct lpfc_mbx_init_vfi { - uint32_t word1; -#define lpfc_init_vfi_vr_SHIFT 31 -#define lpfc_init_vfi_vr_MASK 0x00000001 -#define lpfc_init_vfi_vr_WORD word1 -#define lpfc_init_vfi_vt_SHIFT 30 -#define lpfc_init_vfi_vt_MASK 0x00000001 -#define lpfc_init_vfi_vt_WORD word1 -#define lpfc_init_vfi_vf_SHIFT 29 -#define lpfc_init_vfi_vf_MASK 0x00000001 -#define lpfc_init_vfi_vf_WORD word1 -#define lpfc_init_vfi_vp_SHIFT 28 -#define lpfc_init_vfi_vp_MASK 0x00000001 -#define lpfc_init_vfi_vp_WORD word1 -#define lpfc_init_vfi_vfi_SHIFT 0 -#define lpfc_init_vfi_vfi_MASK 0x0000FFFF -#define lpfc_init_vfi_vfi_WORD word1 - uint32_t word2; -#define lpfc_init_vfi_vpi_SHIFT 16 -#define lpfc_init_vfi_vpi_MASK 0x0000FFFF -#define lpfc_init_vfi_vpi_WORD word2 -#define lpfc_init_vfi_fcfi_SHIFT 0 -#define lpfc_init_vfi_fcfi_MASK 0x0000FFFF -#define lpfc_init_vfi_fcfi_WORD word2 - uint32_t word3; -#define lpfc_init_vfi_pri_SHIFT 13 -#define lpfc_init_vfi_pri_MASK 0x00000007 -#define lpfc_init_vfi_pri_WORD word3 -#define lpfc_init_vfi_vf_id_SHIFT 1 -#define lpfc_init_vfi_vf_id_MASK 0x00000FFF -#define lpfc_init_vfi_vf_id_WORD word3 - uint32_t word4; -#define lpfc_init_vfi_hop_count_SHIFT 24 -#define lpfc_init_vfi_hop_count_MASK 0x000000FF -#define lpfc_init_vfi_hop_count_WORD word4 -}; -#define MBX_VFI_IN_USE 0x9F02 - - -struct lpfc_mbx_reg_vfi { - uint32_t word1; -#define lpfc_reg_vfi_vp_SHIFT 28 -#define lpfc_reg_vfi_vp_MASK 0x00000001 -#define lpfc_reg_vfi_vp_WORD word1 -#define lpfc_reg_vfi_vfi_SHIFT 0 -#define lpfc_reg_vfi_vfi_MASK 0x0000FFFF -#define lpfc_reg_vfi_vfi_WORD word1 - uint32_t word2; -#define lpfc_reg_vfi_vpi_SHIFT 16 -#define lpfc_reg_vfi_vpi_MASK 0x0000FFFF -#define lpfc_reg_vfi_vpi_WORD word2 -#define lpfc_reg_vfi_fcfi_SHIFT 0 -#define lpfc_reg_vfi_fcfi_MASK 0x0000FFFF -#define lpfc_reg_vfi_fcfi_WORD word2 - uint32_t wwn[2]; - struct ulp_bde64 bde; - uint32_t e_d_tov; - uint32_t r_a_tov; - uint32_t word10; -#define lpfc_reg_vfi_nport_id_SHIFT 0 -#define lpfc_reg_vfi_nport_id_MASK 0x00FFFFFF -#define lpfc_reg_vfi_nport_id_WORD word10 -}; - -struct lpfc_mbx_init_vpi { - uint32_t word1; -#define lpfc_init_vpi_vfi_SHIFT 16 -#define lpfc_init_vpi_vfi_MASK 0x0000FFFF -#define lpfc_init_vpi_vfi_WORD word1 -#define lpfc_init_vpi_vpi_SHIFT 0 -#define lpfc_init_vpi_vpi_MASK 0x0000FFFF -#define lpfc_init_vpi_vpi_WORD word1 -}; - -struct lpfc_mbx_read_vpi { - uint32_t word1_rsvd; - uint32_t word2; -#define lpfc_mbx_read_vpi_vnportid_SHIFT 0 -#define lpfc_mbx_read_vpi_vnportid_MASK 0x00FFFFFF -#define lpfc_mbx_read_vpi_vnportid_WORD word2 - uint32_t word3_rsvd; - uint32_t word4; -#define lpfc_mbx_read_vpi_acq_alpa_SHIFT 0 -#define lpfc_mbx_read_vpi_acq_alpa_MASK 0x000000FF -#define lpfc_mbx_read_vpi_acq_alpa_WORD word4 -#define lpfc_mbx_read_vpi_pb_SHIFT 15 -#define lpfc_mbx_read_vpi_pb_MASK 0x00000001 -#define lpfc_mbx_read_vpi_pb_WORD word4 -#define lpfc_mbx_read_vpi_spec_alpa_SHIFT 16 -#define lpfc_mbx_read_vpi_spec_alpa_MASK 0x000000FF -#define lpfc_mbx_read_vpi_spec_alpa_WORD word4 -#define lpfc_mbx_read_vpi_ns_SHIFT 30 -#define lpfc_mbx_read_vpi_ns_MASK 0x00000001 -#define lpfc_mbx_read_vpi_ns_WORD word4 -#define lpfc_mbx_read_vpi_hl_SHIFT 31 -#define lpfc_mbx_read_vpi_hl_MASK 0x00000001 -#define lpfc_mbx_read_vpi_hl_WORD word4 - uint32_t word5_rsvd; - uint32_t word6; -#define lpfc_mbx_read_vpi_vpi_SHIFT 0 -#define lpfc_mbx_read_vpi_vpi_MASK 0x0000FFFF -#define lpfc_mbx_read_vpi_vpi_WORD word6 - uint32_t word7; -#define lpfc_mbx_read_vpi_mac_0_SHIFT 0 -#define lpfc_mbx_read_vpi_mac_0_MASK 0x000000FF -#define lpfc_mbx_read_vpi_mac_0_WORD word7 -#define lpfc_mbx_read_vpi_mac_1_SHIFT 8 -#define lpfc_mbx_read_vpi_mac_1_MASK 0x000000FF -#define lpfc_mbx_read_vpi_mac_1_WORD word7 -#define lpfc_mbx_read_vpi_mac_2_SHIFT 16 -#define lpfc_mbx_read_vpi_mac_2_MASK 0x000000FF -#define lpfc_mbx_read_vpi_mac_2_WORD word7 -#define lpfc_mbx_read_vpi_mac_3_SHIFT 24 -#define lpfc_mbx_read_vpi_mac_3_MASK 0x000000FF -#define lpfc_mbx_read_vpi_mac_3_WORD word7 - uint32_t word8; -#define lpfc_mbx_read_vpi_mac_4_SHIFT 0 -#define lpfc_mbx_read_vpi_mac_4_MASK 0x000000FF -#define lpfc_mbx_read_vpi_mac_4_WORD word8 -#define lpfc_mbx_read_vpi_mac_5_SHIFT 8 -#define lpfc_mbx_read_vpi_mac_5_MASK 0x000000FF -#define lpfc_mbx_read_vpi_mac_5_WORD word8 -#define lpfc_mbx_read_vpi_vlan_tag_SHIFT 16 -#define lpfc_mbx_read_vpi_vlan_tag_MASK 0x00000FFF -#define lpfc_mbx_read_vpi_vlan_tag_WORD word8 -#define lpfc_mbx_read_vpi_vv_SHIFT 28 -#define lpfc_mbx_read_vpi_vv_MASK 0x0000001 -#define lpfc_mbx_read_vpi_vv_WORD word8 -}; - -struct lpfc_mbx_unreg_vfi { - uint32_t word1_rsvd; - uint32_t word2; -#define lpfc_unreg_vfi_vfi_SHIFT 0 -#define lpfc_unreg_vfi_vfi_MASK 0x0000FFFF -#define lpfc_unreg_vfi_vfi_WORD word2 -}; - -struct lpfc_mbx_resume_rpi { - uint32_t word1; -#define lpfc_resume_rpi_index_SHIFT 0 -#define lpfc_resume_rpi_index_MASK 0x0000FFFF -#define lpfc_resume_rpi_index_WORD word1 -#define lpfc_resume_rpi_ii_SHIFT 30 -#define lpfc_resume_rpi_ii_MASK 0x00000003 -#define lpfc_resume_rpi_ii_WORD word1 -#define RESUME_INDEX_RPI 0 -#define RESUME_INDEX_VPI 1 -#define RESUME_INDEX_VFI 2 -#define RESUME_INDEX_FCFI 3 - uint32_t event_tag; -}; - -#define REG_FCF_INVALID_QID 0xFFFF -struct lpfc_mbx_reg_fcfi { - uint32_t word1; -#define lpfc_reg_fcfi_info_index_SHIFT 0 -#define lpfc_reg_fcfi_info_index_MASK 0x0000FFFF -#define lpfc_reg_fcfi_info_index_WORD word1 -#define lpfc_reg_fcfi_fcfi_SHIFT 16 -#define lpfc_reg_fcfi_fcfi_MASK 0x0000FFFF -#define lpfc_reg_fcfi_fcfi_WORD word1 - uint32_t word2; -#define lpfc_reg_fcfi_rq_id1_SHIFT 0 -#define lpfc_reg_fcfi_rq_id1_MASK 0x0000FFFF -#define lpfc_reg_fcfi_rq_id1_WORD word2 -#define lpfc_reg_fcfi_rq_id0_SHIFT 16 -#define lpfc_reg_fcfi_rq_id0_MASK 0x0000FFFF -#define lpfc_reg_fcfi_rq_id0_WORD word2 - uint32_t word3; -#define lpfc_reg_fcfi_rq_id3_SHIFT 0 -#define lpfc_reg_fcfi_rq_id3_MASK 0x0000FFFF -#define lpfc_reg_fcfi_rq_id3_WORD word3 -#define lpfc_reg_fcfi_rq_id2_SHIFT 16 -#define lpfc_reg_fcfi_rq_id2_MASK 0x0000FFFF -#define lpfc_reg_fcfi_rq_id2_WORD word3 - uint32_t word4; -#define lpfc_reg_fcfi_type_match0_SHIFT 24 -#define lpfc_reg_fcfi_type_match0_MASK 0x000000FF -#define lpfc_reg_fcfi_type_match0_WORD word4 -#define lpfc_reg_fcfi_type_mask0_SHIFT 16 -#define lpfc_reg_fcfi_type_mask0_MASK 0x000000FF -#define lpfc_reg_fcfi_type_mask0_WORD word4 -#define lpfc_reg_fcfi_rctl_match0_SHIFT 8 -#define lpfc_reg_fcfi_rctl_match0_MASK 0x000000FF -#define lpfc_reg_fcfi_rctl_match0_WORD word4 -#define lpfc_reg_fcfi_rctl_mask0_SHIFT 0 -#define lpfc_reg_fcfi_rctl_mask0_MASK 0x000000FF -#define lpfc_reg_fcfi_rctl_mask0_WORD word4 - uint32_t word5; -#define lpfc_reg_fcfi_type_match1_SHIFT 24 -#define lpfc_reg_fcfi_type_match1_MASK 0x000000FF -#define lpfc_reg_fcfi_type_match1_WORD word5 -#define lpfc_reg_fcfi_type_mask1_SHIFT 16 -#define lpfc_reg_fcfi_type_mask1_MASK 0x000000FF -#define lpfc_reg_fcfi_type_mask1_WORD word5 -#define lpfc_reg_fcfi_rctl_match1_SHIFT 8 -#define lpfc_reg_fcfi_rctl_match1_MASK 0x000000FF -#define lpfc_reg_fcfi_rctl_match1_WORD word5 -#define lpfc_reg_fcfi_rctl_mask1_SHIFT 0 -#define lpfc_reg_fcfi_rctl_mask1_MASK 0x000000FF -#define lpfc_reg_fcfi_rctl_mask1_WORD word5 - uint32_t word6; -#define lpfc_reg_fcfi_type_match2_SHIFT 24 -#define lpfc_reg_fcfi_type_match2_MASK 0x000000FF -#define lpfc_reg_fcfi_type_match2_WORD word6 -#define lpfc_reg_fcfi_type_mask2_SHIFT 16 -#define lpfc_reg_fcfi_type_mask2_MASK 0x000000FF -#define lpfc_reg_fcfi_type_mask2_WORD word6 -#define lpfc_reg_fcfi_rctl_match2_SHIFT 8 -#define lpfc_reg_fcfi_rctl_match2_MASK 0x000000FF -#define lpfc_reg_fcfi_rctl_match2_WORD word6 -#define lpfc_reg_fcfi_rctl_mask2_SHIFT 0 -#define lpfc_reg_fcfi_rctl_mask2_MASK 0x000000FF -#define lpfc_reg_fcfi_rctl_mask2_WORD word6 - uint32_t word7; -#define lpfc_reg_fcfi_type_match3_SHIFT 24 -#define lpfc_reg_fcfi_type_match3_MASK 0x000000FF -#define lpfc_reg_fcfi_type_match3_WORD word7 -#define lpfc_reg_fcfi_type_mask3_SHIFT 16 -#define lpfc_reg_fcfi_type_mask3_MASK 0x000000FF -#define lpfc_reg_fcfi_type_mask3_WORD word7 -#define lpfc_reg_fcfi_rctl_match3_SHIFT 8 -#define lpfc_reg_fcfi_rctl_match3_MASK 0x000000FF -#define lpfc_reg_fcfi_rctl_match3_WORD word7 -#define lpfc_reg_fcfi_rctl_mask3_SHIFT 0 -#define lpfc_reg_fcfi_rctl_mask3_MASK 0x000000FF -#define lpfc_reg_fcfi_rctl_mask3_WORD word7 - uint32_t word8; -#define lpfc_reg_fcfi_mam_SHIFT 13 -#define lpfc_reg_fcfi_mam_MASK 0x00000003 -#define lpfc_reg_fcfi_mam_WORD word8 -#define LPFC_MAM_BOTH 0 /* Both SPMA and FPMA */ -#define LPFC_MAM_SPMA 1 /* Server Provided MAC Address */ -#define LPFC_MAM_FPMA 2 /* Fabric Provided MAC Address */ -#define lpfc_reg_fcfi_vv_SHIFT 12 -#define lpfc_reg_fcfi_vv_MASK 0x00000001 -#define lpfc_reg_fcfi_vv_WORD word8 -#define lpfc_reg_fcfi_vlan_tag_SHIFT 0 -#define lpfc_reg_fcfi_vlan_tag_MASK 0x00000FFF -#define lpfc_reg_fcfi_vlan_tag_WORD word8 -}; - -struct lpfc_mbx_unreg_fcfi { - uint32_t word1_rsv; - uint32_t word2; -#define lpfc_unreg_fcfi_SHIFT 0 -#define lpfc_unreg_fcfi_MASK 0x0000FFFF -#define lpfc_unreg_fcfi_WORD word2 -}; - -struct lpfc_mbx_read_rev { - uint32_t word1; -#define lpfc_mbx_rd_rev_sli_lvl_SHIFT 16 -#define lpfc_mbx_rd_rev_sli_lvl_MASK 0x0000000F -#define lpfc_mbx_rd_rev_sli_lvl_WORD word1 -#define lpfc_mbx_rd_rev_fcoe_SHIFT 20 -#define lpfc_mbx_rd_rev_fcoe_MASK 0x00000001 -#define lpfc_mbx_rd_rev_fcoe_WORD word1 -#define lpfc_mbx_rd_rev_cee_ver_SHIFT 21 -#define lpfc_mbx_rd_rev_cee_ver_MASK 0x00000003 -#define lpfc_mbx_rd_rev_cee_ver_WORD word1 -#define LPFC_PREDCBX_CEE_MODE 0 -#define LPFC_DCBX_CEE_MODE 1 -#define lpfc_mbx_rd_rev_vpd_SHIFT 29 -#define lpfc_mbx_rd_rev_vpd_MASK 0x00000001 -#define lpfc_mbx_rd_rev_vpd_WORD word1 - uint32_t first_hw_rev; - uint32_t second_hw_rev; - uint32_t word4_rsvd; - uint32_t third_hw_rev; - uint32_t word6; -#define lpfc_mbx_rd_rev_fcph_low_SHIFT 0 -#define lpfc_mbx_rd_rev_fcph_low_MASK 0x000000FF -#define lpfc_mbx_rd_rev_fcph_low_WORD word6 -#define lpfc_mbx_rd_rev_fcph_high_SHIFT 8 -#define lpfc_mbx_rd_rev_fcph_high_MASK 0x000000FF -#define lpfc_mbx_rd_rev_fcph_high_WORD word6 -#define lpfc_mbx_rd_rev_ftr_lvl_low_SHIFT 16 -#define lpfc_mbx_rd_rev_ftr_lvl_low_MASK 0x000000FF -#define lpfc_mbx_rd_rev_ftr_lvl_low_WORD word6 -#define lpfc_mbx_rd_rev_ftr_lvl_high_SHIFT 24 -#define lpfc_mbx_rd_rev_ftr_lvl_high_MASK 0x000000FF -#define lpfc_mbx_rd_rev_ftr_lvl_high_WORD word6 - uint32_t word7_rsvd; - uint32_t fw_id_rev; - uint8_t fw_name[16]; - uint32_t ulp_fw_id_rev; - uint8_t ulp_fw_name[16]; - uint32_t word18_47_rsvd[30]; - uint32_t word48; -#define lpfc_mbx_rd_rev_avail_len_SHIFT 0 -#define lpfc_mbx_rd_rev_avail_len_MASK 0x00FFFFFF -#define lpfc_mbx_rd_rev_avail_len_WORD word48 - uint32_t vpd_paddr_low; - uint32_t vpd_paddr_high; - uint32_t avail_vpd_len; - uint32_t rsvd_52_63[12]; -}; - -struct lpfc_mbx_read_config { - uint32_t word1; -#define lpfc_mbx_rd_conf_extnts_inuse_SHIFT 31 -#define lpfc_mbx_rd_conf_extnts_inuse_MASK 0x00000001 -#define lpfc_mbx_rd_conf_extnts_inuse_WORD word1 - uint32_t word2; -#define lpfc_mbx_rd_conf_lnk_numb_SHIFT 0 -#define lpfc_mbx_rd_conf_lnk_numb_MASK 0x0000003F -#define lpfc_mbx_rd_conf_lnk_numb_WORD word2 -#define lpfc_mbx_rd_conf_lnk_type_SHIFT 6 -#define lpfc_mbx_rd_conf_lnk_type_MASK 0x00000003 -#define lpfc_mbx_rd_conf_lnk_type_WORD word2 -#define LPFC_LNK_TYPE_GE 0 -#define LPFC_LNK_TYPE_FC 1 -#define lpfc_mbx_rd_conf_lnk_ldv_SHIFT 8 -#define lpfc_mbx_rd_conf_lnk_ldv_MASK 0x00000001 -#define lpfc_mbx_rd_conf_lnk_ldv_WORD word2 -#define lpfc_mbx_rd_conf_topology_SHIFT 24 -#define lpfc_mbx_rd_conf_topology_MASK 0x000000FF -#define lpfc_mbx_rd_conf_topology_WORD word2 - uint32_t rsvd_3; - uint32_t word4; -#define lpfc_mbx_rd_conf_e_d_tov_SHIFT 0 -#define lpfc_mbx_rd_conf_e_d_tov_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_e_d_tov_WORD word4 - uint32_t rsvd_5; - uint32_t word6; -#define lpfc_mbx_rd_conf_r_a_tov_SHIFT 0 -#define lpfc_mbx_rd_conf_r_a_tov_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_r_a_tov_WORD word6 - uint32_t rsvd_7; - uint32_t rsvd_8; - uint32_t word9; -#define lpfc_mbx_rd_conf_lmt_SHIFT 0 -#define lpfc_mbx_rd_conf_lmt_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_lmt_WORD word9 - uint32_t rsvd_10; - uint32_t rsvd_11; - uint32_t word12; -#define lpfc_mbx_rd_conf_xri_base_SHIFT 0 -#define lpfc_mbx_rd_conf_xri_base_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_xri_base_WORD word12 -#define lpfc_mbx_rd_conf_xri_count_SHIFT 16 -#define lpfc_mbx_rd_conf_xri_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_xri_count_WORD word12 - uint32_t word13; -#define lpfc_mbx_rd_conf_rpi_base_SHIFT 0 -#define lpfc_mbx_rd_conf_rpi_base_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_rpi_base_WORD word13 -#define lpfc_mbx_rd_conf_rpi_count_SHIFT 16 -#define lpfc_mbx_rd_conf_rpi_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_rpi_count_WORD word13 - uint32_t word14; -#define lpfc_mbx_rd_conf_vpi_base_SHIFT 0 -#define lpfc_mbx_rd_conf_vpi_base_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_vpi_base_WORD word14 -#define lpfc_mbx_rd_conf_vpi_count_SHIFT 16 -#define lpfc_mbx_rd_conf_vpi_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_vpi_count_WORD word14 - uint32_t word15; -#define lpfc_mbx_rd_conf_vfi_base_SHIFT 0 -#define lpfc_mbx_rd_conf_vfi_base_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_vfi_base_WORD word15 -#define lpfc_mbx_rd_conf_vfi_count_SHIFT 16 -#define lpfc_mbx_rd_conf_vfi_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_vfi_count_WORD word15 - uint32_t word16; -#define lpfc_mbx_rd_conf_fcfi_count_SHIFT 16 -#define lpfc_mbx_rd_conf_fcfi_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_fcfi_count_WORD word16 - uint32_t word17; -#define lpfc_mbx_rd_conf_rq_count_SHIFT 0 -#define lpfc_mbx_rd_conf_rq_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_rq_count_WORD word17 -#define lpfc_mbx_rd_conf_eq_count_SHIFT 16 -#define lpfc_mbx_rd_conf_eq_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_eq_count_WORD word17 - uint32_t word18; -#define lpfc_mbx_rd_conf_wq_count_SHIFT 0 -#define lpfc_mbx_rd_conf_wq_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_wq_count_WORD word18 -#define lpfc_mbx_rd_conf_cq_count_SHIFT 16 -#define lpfc_mbx_rd_conf_cq_count_MASK 0x0000FFFF -#define lpfc_mbx_rd_conf_cq_count_WORD word18 -}; - -struct lpfc_mbx_request_features { - uint32_t word1; -#define lpfc_mbx_rq_ftr_qry_SHIFT 0 -#define lpfc_mbx_rq_ftr_qry_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_qry_WORD word1 - uint32_t word2; -#define lpfc_mbx_rq_ftr_rq_iaab_SHIFT 0 -#define lpfc_mbx_rq_ftr_rq_iaab_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_iaab_WORD word2 -#define lpfc_mbx_rq_ftr_rq_npiv_SHIFT 1 -#define lpfc_mbx_rq_ftr_rq_npiv_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_npiv_WORD word2 -#define lpfc_mbx_rq_ftr_rq_dif_SHIFT 2 -#define lpfc_mbx_rq_ftr_rq_dif_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_dif_WORD word2 -#define lpfc_mbx_rq_ftr_rq_vf_SHIFT 3 -#define lpfc_mbx_rq_ftr_rq_vf_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_vf_WORD word2 -#define lpfc_mbx_rq_ftr_rq_fcpi_SHIFT 4 -#define lpfc_mbx_rq_ftr_rq_fcpi_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_fcpi_WORD word2 -#define lpfc_mbx_rq_ftr_rq_fcpt_SHIFT 5 -#define lpfc_mbx_rq_ftr_rq_fcpt_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_fcpt_WORD word2 -#define lpfc_mbx_rq_ftr_rq_fcpc_SHIFT 6 -#define lpfc_mbx_rq_ftr_rq_fcpc_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_fcpc_WORD word2 -#define lpfc_mbx_rq_ftr_rq_ifip_SHIFT 7 -#define lpfc_mbx_rq_ftr_rq_ifip_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_ifip_WORD word2 -#define lpfc_mbx_rq_ftr_rq_perfh_SHIFT 11 -#define lpfc_mbx_rq_ftr_rq_perfh_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rq_perfh_WORD word2 - uint32_t word3; -#define lpfc_mbx_rq_ftr_rsp_iaab_SHIFT 0 -#define lpfc_mbx_rq_ftr_rsp_iaab_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_iaab_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_npiv_SHIFT 1 -#define lpfc_mbx_rq_ftr_rsp_npiv_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_npiv_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_dif_SHIFT 2 -#define lpfc_mbx_rq_ftr_rsp_dif_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_dif_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_vf_SHIFT 3 -#define lpfc_mbx_rq_ftr_rsp_vf__MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_vf_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_fcpi_SHIFT 4 -#define lpfc_mbx_rq_ftr_rsp_fcpi_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_fcpi_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_fcpt_SHIFT 5 -#define lpfc_mbx_rq_ftr_rsp_fcpt_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_fcpt_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_fcpc_SHIFT 6 -#define lpfc_mbx_rq_ftr_rsp_fcpc_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_fcpc_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_ifip_SHIFT 7 -#define lpfc_mbx_rq_ftr_rsp_ifip_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_ifip_WORD word3 -#define lpfc_mbx_rq_ftr_rsp_perfh_SHIFT 11 -#define lpfc_mbx_rq_ftr_rsp_perfh_MASK 0x00000001 -#define lpfc_mbx_rq_ftr_rsp_perfh_WORD word3 -}; - -struct lpfc_mbx_supp_pages { - uint32_t word1; -#define qs_SHIFT 0 -#define qs_MASK 0x00000001 -#define qs_WORD word1 -#define wr_SHIFT 1 -#define wr_MASK 0x00000001 -#define wr_WORD word1 -#define pf_SHIFT 8 -#define pf_MASK 0x000000ff -#define pf_WORD word1 -#define cpn_SHIFT 16 -#define cpn_MASK 0x000000ff -#define cpn_WORD word1 - uint32_t word2; -#define list_offset_SHIFT 0 -#define list_offset_MASK 0x000000ff -#define list_offset_WORD word2 -#define next_offset_SHIFT 8 -#define next_offset_MASK 0x000000ff -#define next_offset_WORD word2 -#define elem_cnt_SHIFT 16 -#define elem_cnt_MASK 0x000000ff -#define elem_cnt_WORD word2 - uint32_t word3; -#define pn_0_SHIFT 24 -#define pn_0_MASK 0x000000ff -#define pn_0_WORD word3 -#define pn_1_SHIFT 16 -#define pn_1_MASK 0x000000ff -#define pn_1_WORD word3 -#define pn_2_SHIFT 8 -#define pn_2_MASK 0x000000ff -#define pn_2_WORD word3 -#define pn_3_SHIFT 0 -#define pn_3_MASK 0x000000ff -#define pn_3_WORD word3 - uint32_t word4; -#define pn_4_SHIFT 24 -#define pn_4_MASK 0x000000ff -#define pn_4_WORD word4 -#define pn_5_SHIFT 16 -#define pn_5_MASK 0x000000ff -#define pn_5_WORD word4 -#define pn_6_SHIFT 8 -#define pn_6_MASK 0x000000ff -#define pn_6_WORD word4 -#define pn_7_SHIFT 0 -#define pn_7_MASK 0x000000ff -#define pn_7_WORD word4 - uint32_t rsvd[27]; -#define LPFC_SUPP_PAGES 0 -#define LPFC_BLOCK_GUARD_PROFILES 1 -#define LPFC_SLI4_PARAMETERS 2 -}; - -struct lpfc_mbx_pc_sli4_params { - uint32_t word1; -#define qs_SHIFT 0 -#define qs_MASK 0x00000001 -#define qs_WORD word1 -#define wr_SHIFT 1 -#define wr_MASK 0x00000001 -#define wr_WORD word1 -#define pf_SHIFT 8 -#define pf_MASK 0x000000ff -#define pf_WORD word1 -#define cpn_SHIFT 16 -#define cpn_MASK 0x000000ff -#define cpn_WORD word1 - uint32_t word2; -#define if_type_SHIFT 0 -#define if_type_MASK 0x00000007 -#define if_type_WORD word2 -#define sli_rev_SHIFT 4 -#define sli_rev_MASK 0x0000000f -#define sli_rev_WORD word2 -#define sli_family_SHIFT 8 -#define sli_family_MASK 0x000000ff -#define sli_family_WORD word2 -#define featurelevel_1_SHIFT 16 -#define featurelevel_1_MASK 0x000000ff -#define featurelevel_1_WORD word2 -#define featurelevel_2_SHIFT 24 -#define featurelevel_2_MASK 0x0000001f -#define featurelevel_2_WORD word2 - uint32_t word3; -#define fcoe_SHIFT 0 -#define fcoe_MASK 0x00000001 -#define fcoe_WORD word3 -#define fc_SHIFT 1 -#define fc_MASK 0x00000001 -#define fc_WORD word3 -#define nic_SHIFT 2 -#define nic_MASK 0x00000001 -#define nic_WORD word3 -#define iscsi_SHIFT 3 -#define iscsi_MASK 0x00000001 -#define iscsi_WORD word3 -#define rdma_SHIFT 4 -#define rdma_MASK 0x00000001 -#define rdma_WORD word3 - uint32_t sge_supp_len; -#define SLI4_PAGE_SIZE 4096 - uint32_t word5; -#define if_page_sz_SHIFT 0 -#define if_page_sz_MASK 0x0000ffff -#define if_page_sz_WORD word5 -#define loopbk_scope_SHIFT 24 -#define loopbk_scope_MASK 0x0000000f -#define loopbk_scope_WORD word5 -#define rq_db_window_SHIFT 28 -#define rq_db_window_MASK 0x0000000f -#define rq_db_window_WORD word5 - uint32_t word6; -#define eq_pages_SHIFT 0 -#define eq_pages_MASK 0x0000000f -#define eq_pages_WORD word6 -#define eqe_size_SHIFT 8 -#define eqe_size_MASK 0x000000ff -#define eqe_size_WORD word6 - uint32_t word7; -#define cq_pages_SHIFT 0 -#define cq_pages_MASK 0x0000000f -#define cq_pages_WORD word7 -#define cqe_size_SHIFT 8 -#define cqe_size_MASK 0x000000ff -#define cqe_size_WORD word7 - uint32_t word8; -#define mq_pages_SHIFT 0 -#define mq_pages_MASK 0x0000000f -#define mq_pages_WORD word8 -#define mqe_size_SHIFT 8 -#define mqe_size_MASK 0x000000ff -#define mqe_size_WORD word8 -#define mq_elem_cnt_SHIFT 16 -#define mq_elem_cnt_MASK 0x000000ff -#define mq_elem_cnt_WORD word8 - uint32_t word9; -#define wq_pages_SHIFT 0 -#define wq_pages_MASK 0x0000ffff -#define wq_pages_WORD word9 -#define wqe_size_SHIFT 8 -#define wqe_size_MASK 0x000000ff -#define wqe_size_WORD word9 - uint32_t word10; -#define rq_pages_SHIFT 0 -#define rq_pages_MASK 0x0000ffff -#define rq_pages_WORD word10 -#define rqe_size_SHIFT 8 -#define rqe_size_MASK 0x000000ff -#define rqe_size_WORD word10 - uint32_t word11; -#define hdr_pages_SHIFT 0 -#define hdr_pages_MASK 0x0000000f -#define hdr_pages_WORD word11 -#define hdr_size_SHIFT 8 -#define hdr_size_MASK 0x0000000f -#define hdr_size_WORD word11 -#define hdr_pp_align_SHIFT 16 -#define hdr_pp_align_MASK 0x0000ffff -#define hdr_pp_align_WORD word11 - uint32_t word12; -#define sgl_pages_SHIFT 0 -#define sgl_pages_MASK 0x0000000f -#define sgl_pages_WORD word12 -#define sgl_pp_align_SHIFT 16 -#define sgl_pp_align_MASK 0x0000ffff -#define sgl_pp_align_WORD word12 - uint32_t rsvd_13_63[51]; -}; -#define SLI4_PAGE_ALIGN(addr) (((addr)+((SLI4_PAGE_SIZE)-1)) \ - &(~((SLI4_PAGE_SIZE)-1))) - -struct lpfc_sli4_parameters { - uint32_t word0; -#define cfg_prot_type_SHIFT 0 -#define cfg_prot_type_MASK 0x000000FF -#define cfg_prot_type_WORD word0 - uint32_t word1; -#define cfg_ft_SHIFT 0 -#define cfg_ft_MASK 0x00000001 -#define cfg_ft_WORD word1 -#define cfg_sli_rev_SHIFT 4 -#define cfg_sli_rev_MASK 0x0000000f -#define cfg_sli_rev_WORD word1 -#define cfg_sli_family_SHIFT 8 -#define cfg_sli_family_MASK 0x0000000f -#define cfg_sli_family_WORD word1 -#define cfg_if_type_SHIFT 12 -#define cfg_if_type_MASK 0x0000000f -#define cfg_if_type_WORD word1 -#define cfg_sli_hint_1_SHIFT 16 -#define cfg_sli_hint_1_MASK 0x000000ff -#define cfg_sli_hint_1_WORD word1 -#define cfg_sli_hint_2_SHIFT 24 -#define cfg_sli_hint_2_MASK 0x0000001f -#define cfg_sli_hint_2_WORD word1 - uint32_t word2; - uint32_t word3; - uint32_t word4; -#define cfg_cqv_SHIFT 14 -#define cfg_cqv_MASK 0x00000003 -#define cfg_cqv_WORD word4 - uint32_t word5; - uint32_t word6; -#define cfg_mqv_SHIFT 14 -#define cfg_mqv_MASK 0x00000003 -#define cfg_mqv_WORD word6 - uint32_t word7; - uint32_t word8; -#define cfg_wqv_SHIFT 14 -#define cfg_wqv_MASK 0x00000003 -#define cfg_wqv_WORD word8 - uint32_t word9; - uint32_t word10; -#define cfg_rqv_SHIFT 14 -#define cfg_rqv_MASK 0x00000003 -#define cfg_rqv_WORD word10 - uint32_t word11; -#define cfg_rq_db_window_SHIFT 28 -#define cfg_rq_db_window_MASK 0x0000000f -#define cfg_rq_db_window_WORD word11 - uint32_t word12; -#define cfg_fcoe_SHIFT 0 -#define cfg_fcoe_MASK 0x00000001 -#define cfg_fcoe_WORD word12 -#define cfg_ext_SHIFT 1 -#define cfg_ext_MASK 0x00000001 -#define cfg_ext_WORD word12 -#define cfg_hdrr_SHIFT 2 -#define cfg_hdrr_MASK 0x00000001 -#define cfg_hdrr_WORD word12 -#define cfg_phwq_SHIFT 15 -#define cfg_phwq_MASK 0x00000001 -#define cfg_phwq_WORD word12 -#define cfg_loopbk_scope_SHIFT 28 -#define cfg_loopbk_scope_MASK 0x0000000f -#define cfg_loopbk_scope_WORD word12 - uint32_t sge_supp_len; - uint32_t word14; -#define cfg_sgl_page_cnt_SHIFT 0 -#define cfg_sgl_page_cnt_MASK 0x0000000f -#define cfg_sgl_page_cnt_WORD word14 -#define cfg_sgl_page_size_SHIFT 8 -#define cfg_sgl_page_size_MASK 0x000000ff -#define cfg_sgl_page_size_WORD word14 -#define cfg_sgl_pp_align_SHIFT 16 -#define cfg_sgl_pp_align_MASK 0x000000ff -#define cfg_sgl_pp_align_WORD word14 - uint32_t word15; - uint32_t word16; - uint32_t word17; - uint32_t word18; - uint32_t word19; -}; - -struct lpfc_mbx_get_sli4_parameters { - struct mbox_header header; - struct lpfc_sli4_parameters sli4_parameters; -}; - -struct lpfc_rscr_desc_generic { -#define LPFC_RSRC_DESC_WSIZE 18 - uint32_t desc[LPFC_RSRC_DESC_WSIZE]; -}; - -struct lpfc_rsrc_desc_pcie { - uint32_t word0; -#define lpfc_rsrc_desc_pcie_type_SHIFT 0 -#define lpfc_rsrc_desc_pcie_type_MASK 0x000000ff -#define lpfc_rsrc_desc_pcie_type_WORD word0 -#define LPFC_RSRC_DESC_TYPE_PCIE 0x40 - uint32_t word1; -#define lpfc_rsrc_desc_pcie_pfnum_SHIFT 0 -#define lpfc_rsrc_desc_pcie_pfnum_MASK 0x000000ff -#define lpfc_rsrc_desc_pcie_pfnum_WORD word1 - uint32_t reserved; - uint32_t word3; -#define lpfc_rsrc_desc_pcie_sriov_sta_SHIFT 0 -#define lpfc_rsrc_desc_pcie_sriov_sta_MASK 0x000000ff -#define lpfc_rsrc_desc_pcie_sriov_sta_WORD word3 -#define lpfc_rsrc_desc_pcie_pf_sta_SHIFT 8 -#define lpfc_rsrc_desc_pcie_pf_sta_MASK 0x000000ff -#define lpfc_rsrc_desc_pcie_pf_sta_WORD word3 -#define lpfc_rsrc_desc_pcie_pf_type_SHIFT 16 -#define lpfc_rsrc_desc_pcie_pf_type_MASK 0x000000ff -#define lpfc_rsrc_desc_pcie_pf_type_WORD word3 - uint32_t word4; -#define lpfc_rsrc_desc_pcie_nr_virtfn_SHIFT 0 -#define lpfc_rsrc_desc_pcie_nr_virtfn_MASK 0x0000ffff -#define lpfc_rsrc_desc_pcie_nr_virtfn_WORD word4 -}; - -struct lpfc_rsrc_desc_fcfcoe { - uint32_t word0; -#define lpfc_rsrc_desc_fcfcoe_type_SHIFT 0 -#define lpfc_rsrc_desc_fcfcoe_type_MASK 0x000000ff -#define lpfc_rsrc_desc_fcfcoe_type_WORD word0 -#define LPFC_RSRC_DESC_TYPE_FCFCOE 0x43 - uint32_t word1; -#define lpfc_rsrc_desc_fcfcoe_vfnum_SHIFT 0 -#define lpfc_rsrc_desc_fcfcoe_vfnum_MASK 0x000000ff -#define lpfc_rsrc_desc_fcfcoe_vfnum_WORD word1 -#define lpfc_rsrc_desc_fcfcoe_pfnum_SHIFT 16 -#define lpfc_rsrc_desc_fcfcoe_pfnum_MASK 0x000007ff -#define lpfc_rsrc_desc_fcfcoe_pfnum_WORD word1 - uint32_t word2; -#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_SHIFT 0 -#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_rpi_cnt_WORD word2 -#define lpfc_rsrc_desc_fcfcoe_xri_cnt_SHIFT 16 -#define lpfc_rsrc_desc_fcfcoe_xri_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_xri_cnt_WORD word2 - uint32_t word3; -#define lpfc_rsrc_desc_fcfcoe_wq_cnt_SHIFT 0 -#define lpfc_rsrc_desc_fcfcoe_wq_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_wq_cnt_WORD word3 -#define lpfc_rsrc_desc_fcfcoe_rq_cnt_SHIFT 16 -#define lpfc_rsrc_desc_fcfcoe_rq_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_rq_cnt_WORD word3 - uint32_t word4; -#define lpfc_rsrc_desc_fcfcoe_cq_cnt_SHIFT 0 -#define lpfc_rsrc_desc_fcfcoe_cq_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_cq_cnt_WORD word4 -#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_SHIFT 16 -#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_vpi_cnt_WORD word4 - uint32_t word5; -#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_SHIFT 0 -#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_fcfi_cnt_WORD word5 -#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_SHIFT 16 -#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_vfi_cnt_WORD word5 - uint32_t word6; - uint32_t word7; - uint32_t word8; - uint32_t word9; - uint32_t word10; - uint32_t word11; - uint32_t word12; - uint32_t word13; -#define lpfc_rsrc_desc_fcfcoe_lnk_nr_SHIFT 0 -#define lpfc_rsrc_desc_fcfcoe_lnk_nr_MASK 0x0000003f -#define lpfc_rsrc_desc_fcfcoe_lnk_nr_WORD word13 -#define lpfc_rsrc_desc_fcfcoe_lnk_tp_SHIFT 6 -#define lpfc_rsrc_desc_fcfcoe_lnk_tp_MASK 0x00000003 -#define lpfc_rsrc_desc_fcfcoe_lnk_tp_WORD word13 -#define lpfc_rsrc_desc_fcfcoe_lmc_SHIFT 8 -#define lpfc_rsrc_desc_fcfcoe_lmc_MASK 0x00000001 -#define lpfc_rsrc_desc_fcfcoe_lmc_WORD word13 -#define lpfc_rsrc_desc_fcfcoe_lld_SHIFT 9 -#define lpfc_rsrc_desc_fcfcoe_lld_MASK 0x00000001 -#define lpfc_rsrc_desc_fcfcoe_lld_WORD word13 -#define lpfc_rsrc_desc_fcfcoe_eq_cnt_SHIFT 16 -#define lpfc_rsrc_desc_fcfcoe_eq_cnt_MASK 0x0000ffff -#define lpfc_rsrc_desc_fcfcoe_eq_cnt_WORD word13 -}; - -struct lpfc_func_cfg { -#define LPFC_RSRC_DESC_MAX_NUM 2 - uint32_t rsrc_desc_count; - struct lpfc_rscr_desc_generic desc[LPFC_RSRC_DESC_MAX_NUM]; -}; - -struct lpfc_mbx_get_func_cfg { - struct mbox_header header; -#define LPFC_CFG_TYPE_PERSISTENT_OVERRIDE 0x0 -#define LPFC_CFG_TYPE_FACTURY_DEFAULT 0x1 -#define LPFC_CFG_TYPE_CURRENT_ACTIVE 0x2 - struct lpfc_func_cfg func_cfg; -}; - -struct lpfc_prof_cfg { -#define LPFC_RSRC_DESC_MAX_NUM 2 - uint32_t rsrc_desc_count; - struct lpfc_rscr_desc_generic desc[LPFC_RSRC_DESC_MAX_NUM]; -}; - -struct lpfc_mbx_get_prof_cfg { - struct mbox_header header; -#define LPFC_CFG_TYPE_PERSISTENT_OVERRIDE 0x0 -#define LPFC_CFG_TYPE_FACTURY_DEFAULT 0x1 -#define LPFC_CFG_TYPE_CURRENT_ACTIVE 0x2 - union { - struct { - uint32_t word10; -#define lpfc_mbx_get_prof_cfg_prof_id_SHIFT 0 -#define lpfc_mbx_get_prof_cfg_prof_id_MASK 0x000000ff -#define lpfc_mbx_get_prof_cfg_prof_id_WORD word10 -#define lpfc_mbx_get_prof_cfg_prof_tp_SHIFT 8 -#define lpfc_mbx_get_prof_cfg_prof_tp_MASK 0x00000003 -#define lpfc_mbx_get_prof_cfg_prof_tp_WORD word10 - } request; - struct { - struct lpfc_prof_cfg prof_cfg; - } response; - } u; -}; - -struct lpfc_controller_attribute { - uint32_t version_string[8]; - uint32_t manufacturer_name[8]; - uint32_t supported_modes; - uint32_t word17; -#define lpfc_cntl_attr_eprom_ver_lo_SHIFT 0 -#define lpfc_cntl_attr_eprom_ver_lo_MASK 0x000000ff -#define lpfc_cntl_attr_eprom_ver_lo_WORD word17 -#define lpfc_cntl_attr_eprom_ver_hi_SHIFT 8 -#define lpfc_cntl_attr_eprom_ver_hi_MASK 0x000000ff -#define lpfc_cntl_attr_eprom_ver_hi_WORD word17 - uint32_t mbx_da_struct_ver; - uint32_t ep_fw_da_struct_ver; - uint32_t ncsi_ver_str[3]; - uint32_t dflt_ext_timeout; - uint32_t model_number[8]; - uint32_t description[16]; - uint32_t serial_number[8]; - uint32_t ip_ver_str[8]; - uint32_t fw_ver_str[8]; - uint32_t bios_ver_str[8]; - uint32_t redboot_ver_str[8]; - uint32_t driver_ver_str[8]; - uint32_t flash_fw_ver_str[8]; - uint32_t functionality; - uint32_t word105; -#define lpfc_cntl_attr_max_cbd_len_SHIFT 0 -#define lpfc_cntl_attr_max_cbd_len_MASK 0x0000ffff -#define lpfc_cntl_attr_max_cbd_len_WORD word105 -#define lpfc_cntl_attr_asic_rev_SHIFT 16 -#define lpfc_cntl_attr_asic_rev_MASK 0x000000ff -#define lpfc_cntl_attr_asic_rev_WORD word105 -#define lpfc_cntl_attr_gen_guid0_SHIFT 24 -#define lpfc_cntl_attr_gen_guid0_MASK 0x000000ff -#define lpfc_cntl_attr_gen_guid0_WORD word105 - uint32_t gen_guid1_12[3]; - uint32_t word109; -#define lpfc_cntl_attr_gen_guid13_14_SHIFT 0 -#define lpfc_cntl_attr_gen_guid13_14_MASK 0x0000ffff -#define lpfc_cntl_attr_gen_guid13_14_WORD word109 -#define lpfc_cntl_attr_gen_guid15_SHIFT 16 -#define lpfc_cntl_attr_gen_guid15_MASK 0x000000ff -#define lpfc_cntl_attr_gen_guid15_WORD word109 -#define lpfc_cntl_attr_hba_port_cnt_SHIFT 24 -#define lpfc_cntl_attr_hba_port_cnt_MASK 0x000000ff -#define lpfc_cntl_attr_hba_port_cnt_WORD word109 - uint32_t word110; -#define lpfc_cntl_attr_dflt_lnk_tmo_SHIFT 0 -#define lpfc_cntl_attr_dflt_lnk_tmo_MASK 0x0000ffff -#define lpfc_cntl_attr_dflt_lnk_tmo_WORD word110 -#define lpfc_cntl_attr_multi_func_dev_SHIFT 24 -#define lpfc_cntl_attr_multi_func_dev_MASK 0x000000ff -#define lpfc_cntl_attr_multi_func_dev_WORD word110 - uint32_t word111; -#define lpfc_cntl_attr_cache_valid_SHIFT 0 -#define lpfc_cntl_attr_cache_valid_MASK 0x000000ff -#define lpfc_cntl_attr_cache_valid_WORD word111 -#define lpfc_cntl_attr_hba_status_SHIFT 8 -#define lpfc_cntl_attr_hba_status_MASK 0x000000ff -#define lpfc_cntl_attr_hba_status_WORD word111 -#define lpfc_cntl_attr_max_domain_SHIFT 16 -#define lpfc_cntl_attr_max_domain_MASK 0x000000ff -#define lpfc_cntl_attr_max_domain_WORD word111 -#define lpfc_cntl_attr_lnk_numb_SHIFT 24 -#define lpfc_cntl_attr_lnk_numb_MASK 0x0000003f -#define lpfc_cntl_attr_lnk_numb_WORD word111 -#define lpfc_cntl_attr_lnk_type_SHIFT 30 -#define lpfc_cntl_attr_lnk_type_MASK 0x00000003 -#define lpfc_cntl_attr_lnk_type_WORD word111 - uint32_t fw_post_status; - uint32_t hba_mtu[8]; - uint32_t word121; - uint32_t reserved1[3]; - uint32_t word125; -#define lpfc_cntl_attr_pci_vendor_id_SHIFT 0 -#define lpfc_cntl_attr_pci_vendor_id_MASK 0x0000ffff -#define lpfc_cntl_attr_pci_vendor_id_WORD word125 -#define lpfc_cntl_attr_pci_device_id_SHIFT 16 -#define lpfc_cntl_attr_pci_device_id_MASK 0x0000ffff -#define lpfc_cntl_attr_pci_device_id_WORD word125 - uint32_t word126; -#define lpfc_cntl_attr_pci_subvdr_id_SHIFT 0 -#define lpfc_cntl_attr_pci_subvdr_id_MASK 0x0000ffff -#define lpfc_cntl_attr_pci_subvdr_id_WORD word126 -#define lpfc_cntl_attr_pci_subsys_id_SHIFT 16 -#define lpfc_cntl_attr_pci_subsys_id_MASK 0x0000ffff -#define lpfc_cntl_attr_pci_subsys_id_WORD word126 - uint32_t word127; -#define lpfc_cntl_attr_pci_bus_num_SHIFT 0 -#define lpfc_cntl_attr_pci_bus_num_MASK 0x000000ff -#define lpfc_cntl_attr_pci_bus_num_WORD word127 -#define lpfc_cntl_attr_pci_dev_num_SHIFT 8 -#define lpfc_cntl_attr_pci_dev_num_MASK 0x000000ff -#define lpfc_cntl_attr_pci_dev_num_WORD word127 -#define lpfc_cntl_attr_pci_fnc_num_SHIFT 16 -#define lpfc_cntl_attr_pci_fnc_num_MASK 0x000000ff -#define lpfc_cntl_attr_pci_fnc_num_WORD word127 -#define lpfc_cntl_attr_inf_type_SHIFT 24 -#define lpfc_cntl_attr_inf_type_MASK 0x000000ff -#define lpfc_cntl_attr_inf_type_WORD word127 - uint32_t unique_id[2]; - uint32_t word130; -#define lpfc_cntl_attr_num_netfil_SHIFT 0 -#define lpfc_cntl_attr_num_netfil_MASK 0x000000ff -#define lpfc_cntl_attr_num_netfil_WORD word130 - uint32_t reserved2[4]; -}; - -struct lpfc_mbx_get_cntl_attributes { - union lpfc_sli4_cfg_shdr cfg_shdr; - struct lpfc_controller_attribute cntl_attr; -}; - -struct lpfc_mbx_get_port_name { - struct mbox_header header; - union { - struct { - uint32_t word4; -#define lpfc_mbx_get_port_name_lnk_type_SHIFT 0 -#define lpfc_mbx_get_port_name_lnk_type_MASK 0x00000003 -#define lpfc_mbx_get_port_name_lnk_type_WORD word4 - } request; - struct { - uint32_t word4; -#define lpfc_mbx_get_port_name_name0_SHIFT 0 -#define lpfc_mbx_get_port_name_name0_MASK 0x000000FF -#define lpfc_mbx_get_port_name_name0_WORD word4 -#define lpfc_mbx_get_port_name_name1_SHIFT 8 -#define lpfc_mbx_get_port_name_name1_MASK 0x000000FF -#define lpfc_mbx_get_port_name_name1_WORD word4 -#define lpfc_mbx_get_port_name_name2_SHIFT 16 -#define lpfc_mbx_get_port_name_name2_MASK 0x000000FF -#define lpfc_mbx_get_port_name_name2_WORD word4 -#define lpfc_mbx_get_port_name_name3_SHIFT 24 -#define lpfc_mbx_get_port_name_name3_MASK 0x000000FF -#define lpfc_mbx_get_port_name_name3_WORD word4 -#define LPFC_LINK_NUMBER_0 0 -#define LPFC_LINK_NUMBER_1 1 -#define LPFC_LINK_NUMBER_2 2 -#define LPFC_LINK_NUMBER_3 3 - } response; - } u; -}; - -/* Mailbox Completion Queue Error Messages */ -#define MB_CQE_STATUS_SUCCESS 0x0 -#define MB_CQE_STATUS_INSUFFICIENT_PRIVILEGES 0x1 -#define MB_CQE_STATUS_INVALID_PARAMETER 0x2 -#define MB_CQE_STATUS_INSUFFICIENT_RESOURCES 0x3 -#define MB_CEQ_STATUS_QUEUE_FLUSHING 0x4 -#define MB_CQE_STATUS_DMA_FAILED 0x5 - -#define LPFC_MBX_WR_CONFIG_MAX_BDE 8 -struct lpfc_mbx_wr_object { - struct mbox_header header; - union { - struct { - uint32_t word4; -#define lpfc_wr_object_eof_SHIFT 31 -#define lpfc_wr_object_eof_MASK 0x00000001 -#define lpfc_wr_object_eof_WORD word4 -#define lpfc_wr_object_write_length_SHIFT 0 -#define lpfc_wr_object_write_length_MASK 0x00FFFFFF -#define lpfc_wr_object_write_length_WORD word4 - uint32_t write_offset; - uint32_t object_name[26]; - uint32_t bde_count; - struct ulp_bde64 bde[LPFC_MBX_WR_CONFIG_MAX_BDE]; - } request; - struct { - uint32_t actual_write_length; - } response; - } u; -}; - -/* mailbox queue entry structure */ -struct lpfc_mqe { - uint32_t word0; -#define lpfc_mqe_status_SHIFT 16 -#define lpfc_mqe_status_MASK 0x0000FFFF -#define lpfc_mqe_status_WORD word0 -#define lpfc_mqe_command_SHIFT 8 -#define lpfc_mqe_command_MASK 0x000000FF -#define lpfc_mqe_command_WORD word0 - union { - uint32_t mb_words[LPFC_SLI4_MB_WORD_COUNT - 1]; - /* sli4 mailbox commands */ - struct lpfc_mbx_sli4_config sli4_config; - struct lpfc_mbx_init_vfi init_vfi; - struct lpfc_mbx_reg_vfi reg_vfi; - struct lpfc_mbx_reg_vfi unreg_vfi; - struct lpfc_mbx_init_vpi init_vpi; - struct lpfc_mbx_resume_rpi resume_rpi; - struct lpfc_mbx_read_fcf_tbl read_fcf_tbl; - struct lpfc_mbx_add_fcf_tbl_entry add_fcf_entry; - struct lpfc_mbx_del_fcf_tbl_entry del_fcf_entry; - struct lpfc_mbx_redisc_fcf_tbl redisc_fcf_tbl; - struct lpfc_mbx_reg_fcfi reg_fcfi; - struct lpfc_mbx_unreg_fcfi unreg_fcfi; - struct lpfc_mbx_mq_create mq_create; - struct lpfc_mbx_mq_create_ext mq_create_ext; - struct lpfc_mbx_eq_create eq_create; - struct lpfc_mbx_cq_create cq_create; - struct lpfc_mbx_wq_create wq_create; - struct lpfc_mbx_rq_create rq_create; - struct lpfc_mbx_mq_destroy mq_destroy; - struct lpfc_mbx_eq_destroy eq_destroy; - struct lpfc_mbx_cq_destroy cq_destroy; - struct lpfc_mbx_wq_destroy wq_destroy; - struct lpfc_mbx_rq_destroy rq_destroy; - struct lpfc_mbx_get_rsrc_extent_info rsrc_extent_info; - struct lpfc_mbx_alloc_rsrc_extents alloc_rsrc_extents; - struct lpfc_mbx_dealloc_rsrc_extents dealloc_rsrc_extents; - struct lpfc_mbx_post_sgl_pages post_sgl_pages; - struct lpfc_mbx_nembed_cmd nembed_cmd; - struct lpfc_mbx_read_rev read_rev; - struct lpfc_mbx_read_vpi read_vpi; - struct lpfc_mbx_read_config rd_config; - struct lpfc_mbx_request_features req_ftrs; - struct lpfc_mbx_post_hdr_tmpl hdr_tmpl; - struct lpfc_mbx_query_fw_cfg query_fw_cfg; - struct lpfc_mbx_supp_pages supp_pages; - struct lpfc_mbx_pc_sli4_params sli4_params; - struct lpfc_mbx_get_sli4_parameters get_sli4_parameters; - struct lpfc_mbx_set_link_diag_state link_diag_state; - struct lpfc_mbx_set_link_diag_loopback link_diag_loopback; - struct lpfc_mbx_run_link_diag_test link_diag_test; - struct lpfc_mbx_get_func_cfg get_func_cfg; - struct lpfc_mbx_get_prof_cfg get_prof_cfg; - struct lpfc_mbx_wr_object wr_object; - struct lpfc_mbx_get_port_name get_port_name; - struct lpfc_mbx_nop nop; - } un; -}; - -struct lpfc_mcqe { - uint32_t word0; -#define lpfc_mcqe_status_SHIFT 0 -#define lpfc_mcqe_status_MASK 0x0000FFFF -#define lpfc_mcqe_status_WORD word0 -#define lpfc_mcqe_ext_status_SHIFT 16 -#define lpfc_mcqe_ext_status_MASK 0x0000FFFF -#define lpfc_mcqe_ext_status_WORD word0 - uint32_t mcqe_tag0; - uint32_t mcqe_tag1; - uint32_t trailer; -#define lpfc_trailer_valid_SHIFT 31 -#define lpfc_trailer_valid_MASK 0x00000001 -#define lpfc_trailer_valid_WORD trailer -#define lpfc_trailer_async_SHIFT 30 -#define lpfc_trailer_async_MASK 0x00000001 -#define lpfc_trailer_async_WORD trailer -#define lpfc_trailer_hpi_SHIFT 29 -#define lpfc_trailer_hpi_MASK 0x00000001 -#define lpfc_trailer_hpi_WORD trailer -#define lpfc_trailer_completed_SHIFT 28 -#define lpfc_trailer_completed_MASK 0x00000001 -#define lpfc_trailer_completed_WORD trailer -#define lpfc_trailer_consumed_SHIFT 27 -#define lpfc_trailer_consumed_MASK 0x00000001 -#define lpfc_trailer_consumed_WORD trailer -#define lpfc_trailer_type_SHIFT 16 -#define lpfc_trailer_type_MASK 0x000000FF -#define lpfc_trailer_type_WORD trailer -#define lpfc_trailer_code_SHIFT 8 -#define lpfc_trailer_code_MASK 0x000000FF -#define lpfc_trailer_code_WORD trailer -#define LPFC_TRAILER_CODE_LINK 0x1 -#define LPFC_TRAILER_CODE_FCOE 0x2 -#define LPFC_TRAILER_CODE_DCBX 0x3 -#define LPFC_TRAILER_CODE_GRP5 0x5 -#define LPFC_TRAILER_CODE_FC 0x10 -#define LPFC_TRAILER_CODE_SLI 0x11 -}; - -struct lpfc_acqe_link { - uint32_t word0; -#define lpfc_acqe_link_speed_SHIFT 24 -#define lpfc_acqe_link_speed_MASK 0x000000FF -#define lpfc_acqe_link_speed_WORD word0 -#define LPFC_ASYNC_LINK_SPEED_ZERO 0x0 -#define LPFC_ASYNC_LINK_SPEED_10MBPS 0x1 -#define LPFC_ASYNC_LINK_SPEED_100MBPS 0x2 -#define LPFC_ASYNC_LINK_SPEED_1GBPS 0x3 -#define LPFC_ASYNC_LINK_SPEED_10GBPS 0x4 -#define lpfc_acqe_link_duplex_SHIFT 16 -#define lpfc_acqe_link_duplex_MASK 0x000000FF -#define lpfc_acqe_link_duplex_WORD word0 -#define LPFC_ASYNC_LINK_DUPLEX_NONE 0x0 -#define LPFC_ASYNC_LINK_DUPLEX_HALF 0x1 -#define LPFC_ASYNC_LINK_DUPLEX_FULL 0x2 -#define lpfc_acqe_link_status_SHIFT 8 -#define lpfc_acqe_link_status_MASK 0x000000FF -#define lpfc_acqe_link_status_WORD word0 -#define LPFC_ASYNC_LINK_STATUS_DOWN 0x0 -#define LPFC_ASYNC_LINK_STATUS_UP 0x1 -#define LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN 0x2 -#define LPFC_ASYNC_LINK_STATUS_LOGICAL_UP 0x3 -#define lpfc_acqe_link_type_SHIFT 6 -#define lpfc_acqe_link_type_MASK 0x00000003 -#define lpfc_acqe_link_type_WORD word0 -#define lpfc_acqe_link_number_SHIFT 0 -#define lpfc_acqe_link_number_MASK 0x0000003F -#define lpfc_acqe_link_number_WORD word0 - uint32_t word1; -#define lpfc_acqe_link_fault_SHIFT 0 -#define lpfc_acqe_link_fault_MASK 0x000000FF -#define lpfc_acqe_link_fault_WORD word1 -#define LPFC_ASYNC_LINK_FAULT_NONE 0x0 -#define LPFC_ASYNC_LINK_FAULT_LOCAL 0x1 -#define LPFC_ASYNC_LINK_FAULT_REMOTE 0x2 -#define lpfc_acqe_logical_link_speed_SHIFT 16 -#define lpfc_acqe_logical_link_speed_MASK 0x0000FFFF -#define lpfc_acqe_logical_link_speed_WORD word1 - uint32_t event_tag; - uint32_t trailer; -#define LPFC_LINK_EVENT_TYPE_PHYSICAL 0x0 -#define LPFC_LINK_EVENT_TYPE_VIRTUAL 0x1 -}; - -struct lpfc_acqe_fip { - uint32_t index; - uint32_t word1; -#define lpfc_acqe_fip_fcf_count_SHIFT 0 -#define lpfc_acqe_fip_fcf_count_MASK 0x0000FFFF -#define lpfc_acqe_fip_fcf_count_WORD word1 -#define lpfc_acqe_fip_event_type_SHIFT 16 -#define lpfc_acqe_fip_event_type_MASK 0x0000FFFF -#define lpfc_acqe_fip_event_type_WORD word1 - uint32_t event_tag; - uint32_t trailer; -#define LPFC_FIP_EVENT_TYPE_NEW_FCF 0x1 -#define LPFC_FIP_EVENT_TYPE_FCF_TABLE_FULL 0x2 -#define LPFC_FIP_EVENT_TYPE_FCF_DEAD 0x3 -#define LPFC_FIP_EVENT_TYPE_CVL 0x4 -#define LPFC_FIP_EVENT_TYPE_FCF_PARAM_MOD 0x5 -}; - -struct lpfc_acqe_dcbx { - uint32_t tlv_ttl; - uint32_t reserved; - uint32_t event_tag; - uint32_t trailer; -}; - -struct lpfc_acqe_grp5 { - uint32_t word0; -#define lpfc_acqe_grp5_type_SHIFT 6 -#define lpfc_acqe_grp5_type_MASK 0x00000003 -#define lpfc_acqe_grp5_type_WORD word0 -#define lpfc_acqe_grp5_number_SHIFT 0 -#define lpfc_acqe_grp5_number_MASK 0x0000003F -#define lpfc_acqe_grp5_number_WORD word0 - uint32_t word1; -#define lpfc_acqe_grp5_llink_spd_SHIFT 16 -#define lpfc_acqe_grp5_llink_spd_MASK 0x0000FFFF -#define lpfc_acqe_grp5_llink_spd_WORD word1 - uint32_t event_tag; - uint32_t trailer; -}; - -struct lpfc_acqe_fc_la { - uint32_t word0; -#define lpfc_acqe_fc_la_speed_SHIFT 24 -#define lpfc_acqe_fc_la_speed_MASK 0x000000FF -#define lpfc_acqe_fc_la_speed_WORD word0 -#define LPFC_FC_LA_SPEED_UNKOWN 0x0 -#define LPFC_FC_LA_SPEED_1G 0x1 -#define LPFC_FC_LA_SPEED_2G 0x2 -#define LPFC_FC_LA_SPEED_4G 0x4 -#define LPFC_FC_LA_SPEED_8G 0x8 -#define LPFC_FC_LA_SPEED_10G 0xA -#define LPFC_FC_LA_SPEED_16G 0x10 -#define lpfc_acqe_fc_la_topology_SHIFT 16 -#define lpfc_acqe_fc_la_topology_MASK 0x000000FF -#define lpfc_acqe_fc_la_topology_WORD word0 -#define LPFC_FC_LA_TOP_UNKOWN 0x0 -#define LPFC_FC_LA_TOP_P2P 0x1 -#define LPFC_FC_LA_TOP_FCAL 0x2 -#define LPFC_FC_LA_TOP_INTERNAL_LOOP 0x3 -#define LPFC_FC_LA_TOP_SERDES_LOOP 0x4 -#define lpfc_acqe_fc_la_att_type_SHIFT 8 -#define lpfc_acqe_fc_la_att_type_MASK 0x000000FF -#define lpfc_acqe_fc_la_att_type_WORD word0 -#define LPFC_FC_LA_TYPE_LINK_UP 0x1 -#define LPFC_FC_LA_TYPE_LINK_DOWN 0x2 -#define LPFC_FC_LA_TYPE_NO_HARD_ALPA 0x3 -#define lpfc_acqe_fc_la_port_type_SHIFT 6 -#define lpfc_acqe_fc_la_port_type_MASK 0x00000003 -#define lpfc_acqe_fc_la_port_type_WORD word0 -#define LPFC_LINK_TYPE_ETHERNET 0x0 -#define LPFC_LINK_TYPE_FC 0x1 -#define lpfc_acqe_fc_la_port_number_SHIFT 0 -#define lpfc_acqe_fc_la_port_number_MASK 0x0000003F -#define lpfc_acqe_fc_la_port_number_WORD word0 - uint32_t word1; -#define lpfc_acqe_fc_la_llink_spd_SHIFT 16 -#define lpfc_acqe_fc_la_llink_spd_MASK 0x0000FFFF -#define lpfc_acqe_fc_la_llink_spd_WORD word1 -#define lpfc_acqe_fc_la_fault_SHIFT 0 -#define lpfc_acqe_fc_la_fault_MASK 0x000000FF -#define lpfc_acqe_fc_la_fault_WORD word1 -#define LPFC_FC_LA_FAULT_NONE 0x0 -#define LPFC_FC_LA_FAULT_LOCAL 0x1 -#define LPFC_FC_LA_FAULT_REMOTE 0x2 - uint32_t event_tag; - uint32_t trailer; -#define LPFC_FC_LA_EVENT_TYPE_FC_LINK 0x1 -#define LPFC_FC_LA_EVENT_TYPE_SHARED_LINK 0x2 -}; - -struct lpfc_acqe_sli { - uint32_t event_data1; - uint32_t event_data2; - uint32_t reserved; - uint32_t trailer; -#define LPFC_SLI_EVENT_TYPE_PORT_ERROR 0x1 -#define LPFC_SLI_EVENT_TYPE_OVER_TEMP 0x2 -#define LPFC_SLI_EVENT_TYPE_NORM_TEMP 0x3 -#define LPFC_SLI_EVENT_TYPE_NVLOG_POST 0x4 -#define LPFC_SLI_EVENT_TYPE_DIAG_DUMP 0x5 -}; - -/* - * Define the bootstrap mailbox (bmbx) region used to communicate - * mailbox command between the host and port. The mailbox consists - * of a payload area of 256 bytes and a completion queue of length - * 16 bytes. - */ -struct lpfc_bmbx_create { - struct lpfc_mqe mqe; - struct lpfc_mcqe mcqe; -}; - -#define SGL_ALIGN_SZ 64 -#define SGL_PAGE_SIZE 4096 -/* align SGL addr on a size boundary - adjust address up */ -#define NO_XRI 0xffff - -struct wqe_common { - uint32_t word6; -#define wqe_xri_tag_SHIFT 0 -#define wqe_xri_tag_MASK 0x0000FFFF -#define wqe_xri_tag_WORD word6 -#define wqe_ctxt_tag_SHIFT 16 -#define wqe_ctxt_tag_MASK 0x0000FFFF -#define wqe_ctxt_tag_WORD word6 - uint32_t word7; -#define wqe_dif_SHIFT 0 -#define wqe_dif_MASK 0x00000003 -#define wqe_dif_WORD word7 -#define wqe_ct_SHIFT 2 -#define wqe_ct_MASK 0x00000003 -#define wqe_ct_WORD word7 -#define wqe_status_SHIFT 4 -#define wqe_status_MASK 0x0000000f -#define wqe_status_WORD word7 -#define wqe_cmnd_SHIFT 8 -#define wqe_cmnd_MASK 0x000000ff -#define wqe_cmnd_WORD word7 -#define wqe_class_SHIFT 16 -#define wqe_class_MASK 0x00000007 -#define wqe_class_WORD word7 -#define wqe_ar_SHIFT 19 -#define wqe_ar_MASK 0x00000001 -#define wqe_ar_WORD word7 -#define wqe_ag_SHIFT wqe_ar_SHIFT -#define wqe_ag_MASK wqe_ar_MASK -#define wqe_ag_WORD wqe_ar_WORD -#define wqe_pu_SHIFT 20 -#define wqe_pu_MASK 0x00000003 -#define wqe_pu_WORD word7 -#define wqe_erp_SHIFT 22 -#define wqe_erp_MASK 0x00000001 -#define wqe_erp_WORD word7 -#define wqe_conf_SHIFT wqe_erp_SHIFT -#define wqe_conf_MASK wqe_erp_MASK -#define wqe_conf_WORD wqe_erp_WORD -#define wqe_lnk_SHIFT 23 -#define wqe_lnk_MASK 0x00000001 -#define wqe_lnk_WORD word7 -#define wqe_tmo_SHIFT 24 -#define wqe_tmo_MASK 0x000000ff -#define wqe_tmo_WORD word7 - uint32_t abort_tag; /* word 8 in WQE */ - uint32_t word9; -#define wqe_reqtag_SHIFT 0 -#define wqe_reqtag_MASK 0x0000FFFF -#define wqe_reqtag_WORD word9 -#define wqe_temp_rpi_SHIFT 16 -#define wqe_temp_rpi_MASK 0x0000FFFF -#define wqe_temp_rpi_WORD word9 -#define wqe_rcvoxid_SHIFT 16 -#define wqe_rcvoxid_MASK 0x0000FFFF -#define wqe_rcvoxid_WORD word9 - uint32_t word10; -#define wqe_ebde_cnt_SHIFT 0 -#define wqe_ebde_cnt_MASK 0x0000000f -#define wqe_ebde_cnt_WORD word10 -#define wqe_lenloc_SHIFT 7 -#define wqe_lenloc_MASK 0x00000003 -#define wqe_lenloc_WORD word10 -#define LPFC_WQE_LENLOC_NONE 0 -#define LPFC_WQE_LENLOC_WORD3 1 -#define LPFC_WQE_LENLOC_WORD12 2 -#define LPFC_WQE_LENLOC_WORD4 3 -#define wqe_qosd_SHIFT 9 -#define wqe_qosd_MASK 0x00000001 -#define wqe_qosd_WORD word10 -#define wqe_xbl_SHIFT 11 -#define wqe_xbl_MASK 0x00000001 -#define wqe_xbl_WORD word10 -#define wqe_iod_SHIFT 13 -#define wqe_iod_MASK 0x00000001 -#define wqe_iod_WORD word10 -#define LPFC_WQE_IOD_WRITE 0 -#define LPFC_WQE_IOD_READ 1 -#define wqe_dbde_SHIFT 14 -#define wqe_dbde_MASK 0x00000001 -#define wqe_dbde_WORD word10 -#define wqe_wqes_SHIFT 15 -#define wqe_wqes_MASK 0x00000001 -#define wqe_wqes_WORD word10 -/* Note that this field overlaps above fields */ -#define wqe_wqid_SHIFT 1 -#define wqe_wqid_MASK 0x00007fff -#define wqe_wqid_WORD word10 -#define wqe_pri_SHIFT 16 -#define wqe_pri_MASK 0x00000007 -#define wqe_pri_WORD word10 -#define wqe_pv_SHIFT 19 -#define wqe_pv_MASK 0x00000001 -#define wqe_pv_WORD word10 -#define wqe_xc_SHIFT 21 -#define wqe_xc_MASK 0x00000001 -#define wqe_xc_WORD word10 -#define wqe_sr_SHIFT 22 -#define wqe_sr_MASK 0x00000001 -#define wqe_sr_WORD word10 -#define wqe_ccpe_SHIFT 23 -#define wqe_ccpe_MASK 0x00000001 -#define wqe_ccpe_WORD word10 -#define wqe_ccp_SHIFT 24 -#define wqe_ccp_MASK 0x000000ff -#define wqe_ccp_WORD word10 - uint32_t word11; -#define wqe_cmd_type_SHIFT 0 -#define wqe_cmd_type_MASK 0x0000000f -#define wqe_cmd_type_WORD word11 -#define wqe_els_id_SHIFT 4 -#define wqe_els_id_MASK 0x00000003 -#define wqe_els_id_WORD word11 -#define LPFC_ELS_ID_FLOGI 3 -#define LPFC_ELS_ID_FDISC 2 -#define LPFC_ELS_ID_LOGO 1 -#define LPFC_ELS_ID_DEFAULT 0 -#define wqe_wqec_SHIFT 7 -#define wqe_wqec_MASK 0x00000001 -#define wqe_wqec_WORD word11 -#define wqe_cqid_SHIFT 16 -#define wqe_cqid_MASK 0x0000ffff -#define wqe_cqid_WORD word11 -#define LPFC_WQE_CQ_ID_DEFAULT 0xffff -}; - -struct wqe_did { - uint32_t word5; -#define wqe_els_did_SHIFT 0 -#define wqe_els_did_MASK 0x00FFFFFF -#define wqe_els_did_WORD word5 -#define wqe_xmit_bls_pt_SHIFT 28 -#define wqe_xmit_bls_pt_MASK 0x00000003 -#define wqe_xmit_bls_pt_WORD word5 -#define wqe_xmit_bls_ar_SHIFT 30 -#define wqe_xmit_bls_ar_MASK 0x00000001 -#define wqe_xmit_bls_ar_WORD word5 -#define wqe_xmit_bls_xo_SHIFT 31 -#define wqe_xmit_bls_xo_MASK 0x00000001 -#define wqe_xmit_bls_xo_WORD word5 -}; - -struct lpfc_wqe_generic{ - struct ulp_bde64 bde; - uint32_t word3; - uint32_t word4; - uint32_t word5; - struct wqe_common wqe_com; - uint32_t payload[4]; -}; - -struct els_request64_wqe { - struct ulp_bde64 bde; - uint32_t payload_len; - uint32_t word4; -#define els_req64_sid_SHIFT 0 -#define els_req64_sid_MASK 0x00FFFFFF -#define els_req64_sid_WORD word4 -#define els_req64_sp_SHIFT 24 -#define els_req64_sp_MASK 0x00000001 -#define els_req64_sp_WORD word4 -#define els_req64_vf_SHIFT 25 -#define els_req64_vf_MASK 0x00000001 -#define els_req64_vf_WORD word4 - struct wqe_did wqe_dest; - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t word12; -#define els_req64_vfid_SHIFT 1 -#define els_req64_vfid_MASK 0x00000FFF -#define els_req64_vfid_WORD word12 -#define els_req64_pri_SHIFT 13 -#define els_req64_pri_MASK 0x00000007 -#define els_req64_pri_WORD word12 - uint32_t word13; -#define els_req64_hopcnt_SHIFT 24 -#define els_req64_hopcnt_MASK 0x000000ff -#define els_req64_hopcnt_WORD word13 - uint32_t reserved[2]; -}; - -struct xmit_els_rsp64_wqe { - struct ulp_bde64 bde; - uint32_t response_payload_len; - uint32_t rsvd4; - struct wqe_did wqe_dest; - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t word12; -#define wqe_rsp_temp_rpi_SHIFT 0 -#define wqe_rsp_temp_rpi_MASK 0x0000FFFF -#define wqe_rsp_temp_rpi_WORD word12 - uint32_t rsvd_13_15[3]; -}; - -struct xmit_bls_rsp64_wqe { - uint32_t payload0; -/* Payload0 for BA_ACC */ -#define xmit_bls_rsp64_acc_seq_id_SHIFT 16 -#define xmit_bls_rsp64_acc_seq_id_MASK 0x000000ff -#define xmit_bls_rsp64_acc_seq_id_WORD payload0 -#define xmit_bls_rsp64_acc_seq_id_vald_SHIFT 24 -#define xmit_bls_rsp64_acc_seq_id_vald_MASK 0x000000ff -#define xmit_bls_rsp64_acc_seq_id_vald_WORD payload0 -/* Payload0 for BA_RJT */ -#define xmit_bls_rsp64_rjt_vspec_SHIFT 0 -#define xmit_bls_rsp64_rjt_vspec_MASK 0x000000ff -#define xmit_bls_rsp64_rjt_vspec_WORD payload0 -#define xmit_bls_rsp64_rjt_expc_SHIFT 8 -#define xmit_bls_rsp64_rjt_expc_MASK 0x000000ff -#define xmit_bls_rsp64_rjt_expc_WORD payload0 -#define xmit_bls_rsp64_rjt_rsnc_SHIFT 16 -#define xmit_bls_rsp64_rjt_rsnc_MASK 0x000000ff -#define xmit_bls_rsp64_rjt_rsnc_WORD payload0 - uint32_t word1; -#define xmit_bls_rsp64_rxid_SHIFT 0 -#define xmit_bls_rsp64_rxid_MASK 0x0000ffff -#define xmit_bls_rsp64_rxid_WORD word1 -#define xmit_bls_rsp64_oxid_SHIFT 16 -#define xmit_bls_rsp64_oxid_MASK 0x0000ffff -#define xmit_bls_rsp64_oxid_WORD word1 - uint32_t word2; -#define xmit_bls_rsp64_seqcnthi_SHIFT 0 -#define xmit_bls_rsp64_seqcnthi_MASK 0x0000ffff -#define xmit_bls_rsp64_seqcnthi_WORD word2 -#define xmit_bls_rsp64_seqcntlo_SHIFT 16 -#define xmit_bls_rsp64_seqcntlo_MASK 0x0000ffff -#define xmit_bls_rsp64_seqcntlo_WORD word2 - uint32_t rsrvd3; - uint32_t rsrvd4; - struct wqe_did wqe_dest; - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t word12; -#define xmit_bls_rsp64_temprpi_SHIFT 0 -#define xmit_bls_rsp64_temprpi_MASK 0x0000ffff -#define xmit_bls_rsp64_temprpi_WORD word12 - uint32_t rsvd_13_15[3]; -}; - -struct wqe_rctl_dfctl { - uint32_t word5; -#define wqe_si_SHIFT 2 -#define wqe_si_MASK 0x000000001 -#define wqe_si_WORD word5 -#define wqe_la_SHIFT 3 -#define wqe_la_MASK 0x000000001 -#define wqe_la_WORD word5 -#define wqe_xo_SHIFT 6 -#define wqe_xo_MASK 0x000000001 -#define wqe_xo_WORD word5 -#define wqe_ls_SHIFT 7 -#define wqe_ls_MASK 0x000000001 -#define wqe_ls_WORD word5 -#define wqe_dfctl_SHIFT 8 -#define wqe_dfctl_MASK 0x0000000ff -#define wqe_dfctl_WORD word5 -#define wqe_type_SHIFT 16 -#define wqe_type_MASK 0x0000000ff -#define wqe_type_WORD word5 -#define wqe_rctl_SHIFT 24 -#define wqe_rctl_MASK 0x0000000ff -#define wqe_rctl_WORD word5 -}; - -struct xmit_seq64_wqe { - struct ulp_bde64 bde; - uint32_t rsvd3; - uint32_t relative_offset; - struct wqe_rctl_dfctl wge_ctl; - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t xmit_len; - uint32_t rsvd_12_15[3]; -}; -struct xmit_bcast64_wqe { - struct ulp_bde64 bde; - uint32_t seq_payload_len; - uint32_t rsvd4; - struct wqe_rctl_dfctl wge_ctl; /* word 5 */ - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsvd_12_15[4]; -}; - -struct gen_req64_wqe { - struct ulp_bde64 bde; - uint32_t request_payload_len; - uint32_t relative_offset; - struct wqe_rctl_dfctl wge_ctl; /* word 5 */ - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsvd_12_15[4]; -}; - -struct create_xri_wqe { - uint32_t rsrvd[5]; /* words 0-4 */ - struct wqe_did wqe_dest; /* word 5 */ - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsvd_12_15[4]; /* word 12-15 */ -}; - -#define T_REQUEST_TAG 3 -#define T_XRI_TAG 1 - -struct abort_cmd_wqe { - uint32_t rsrvd[3]; - uint32_t word3; -#define abort_cmd_ia_SHIFT 0 -#define abort_cmd_ia_MASK 0x000000001 -#define abort_cmd_ia_WORD word3 -#define abort_cmd_criteria_SHIFT 8 -#define abort_cmd_criteria_MASK 0x0000000ff -#define abort_cmd_criteria_WORD word3 - uint32_t rsrvd4; - uint32_t rsrvd5; - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsvd_12_15[4]; /* word 12-15 */ -}; - -struct fcp_iwrite64_wqe { - struct ulp_bde64 bde; - uint32_t payload_offset_len; - uint32_t total_xfer_len; - uint32_t initial_xfer_len; - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsrvd12; - struct ulp_bde64 ph_bde; /* words 13-15 */ -}; - -struct fcp_iread64_wqe { - struct ulp_bde64 bde; - uint32_t payload_offset_len; /* word 3 */ - uint32_t total_xfer_len; /* word 4 */ - uint32_t rsrvd5; /* word 5 */ - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsrvd12; - struct ulp_bde64 ph_bde; /* words 13-15 */ -}; - -struct fcp_icmnd64_wqe { - struct ulp_bde64 bde; /* words 0-2 */ - uint32_t rsrvd3; /* word 3 */ - uint32_t rsrvd4; /* word 4 */ - uint32_t rsrvd5; /* word 5 */ - struct wqe_common wqe_com; /* words 6-11 */ - uint32_t rsvd_12_15[4]; /* word 12-15 */ -}; - - -union lpfc_wqe { - uint32_t words[16]; - struct lpfc_wqe_generic generic; - struct fcp_icmnd64_wqe fcp_icmd; - struct fcp_iread64_wqe fcp_iread; - struct fcp_iwrite64_wqe fcp_iwrite; - struct abort_cmd_wqe abort_cmd; - struct create_xri_wqe create_xri; - struct xmit_bcast64_wqe xmit_bcast64; - struct xmit_seq64_wqe xmit_sequence; - struct xmit_bls_rsp64_wqe xmit_bls_rsp; - struct xmit_els_rsp64_wqe xmit_els_rsp; - struct els_request64_wqe els_req; - struct gen_req64_wqe gen_req; -}; - -#define LPFC_GROUP_OJECT_MAGIC_NUM 0xfeaa0001 -#define LPFC_FILE_TYPE_GROUP 0xf7 -#define LPFC_FILE_ID_GROUP 0xa2 -struct lpfc_grp_hdr { - uint32_t size; - uint32_t magic_number; - uint32_t word2; -#define lpfc_grp_hdr_file_type_SHIFT 24 -#define lpfc_grp_hdr_file_type_MASK 0x000000FF -#define lpfc_grp_hdr_file_type_WORD word2 -#define lpfc_grp_hdr_id_SHIFT 16 -#define lpfc_grp_hdr_id_MASK 0x000000FF -#define lpfc_grp_hdr_id_WORD word2 - uint8_t rev_name[128]; - uint8_t date[12]; - uint8_t revision[32]; -}; - -#define FCP_COMMAND 0x0 -#define FCP_COMMAND_DATA_OUT 0x1 -#define ELS_COMMAND_NON_FIP 0xC -#define ELS_COMMAND_FIP 0xD -#define OTHER_COMMAND 0x8 - -#define LPFC_FW_DUMP 1 -#define LPFC_FW_RESET 2 -#define LPFC_DV_RESET 3 diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_init.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_init.c deleted file mode 100644 index 9598fdcb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_init.c +++ /dev/null @@ -1,10329 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_vport.h" -#include "lpfc_version.h" - -char *_dump_buf_data; -unsigned long _dump_buf_data_order; -char *_dump_buf_dif; -unsigned long _dump_buf_dif_order; -spinlock_t _dump_buf_lock; - -static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); -static int lpfc_post_rcv_buf(struct lpfc_hba *); -static int lpfc_sli4_queue_verify(struct lpfc_hba *); -static int lpfc_create_bootstrap_mbox(struct lpfc_hba *); -static int lpfc_setup_endian_order(struct lpfc_hba *); -static void lpfc_destroy_bootstrap_mbox(struct lpfc_hba *); -static void lpfc_free_sgl_list(struct lpfc_hba *); -static int lpfc_init_sgl_list(struct lpfc_hba *); -static int lpfc_init_active_sgl_array(struct lpfc_hba *); -static void lpfc_free_active_sgl(struct lpfc_hba *); -static int lpfc_hba_down_post_s3(struct lpfc_hba *phba); -static int lpfc_hba_down_post_s4(struct lpfc_hba *phba); -static int lpfc_sli4_cq_event_pool_create(struct lpfc_hba *); -static void lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *); -static void lpfc_sli4_cq_event_release_all(struct lpfc_hba *); - -static struct scsi_transport_template *lpfc_transport_template = NULL; -static struct scsi_transport_template *lpfc_vport_transport_template = NULL; -static DEFINE_IDR(lpfc_hba_index); - -/** - * lpfc_config_port_prep - Perform lpfc initialization prior to config port - * @phba: pointer to lpfc hba data structure. - * - * This routine will do LPFC initialization prior to issuing the CONFIG_PORT - * mailbox command. It retrieves the revision information from the HBA and - * collects the Vital Product Data (VPD) about the HBA for preparing the - * configuration of the HBA. - * - * Return codes: - * 0 - success. - * -ERESTART - requests the SLI layer to reset the HBA and try again. - * Any other value - indicates an error. - **/ -int -lpfc_config_port_prep(struct lpfc_hba *phba) -{ - lpfc_vpd_t *vp = &phba->vpd; - int i = 0, rc; - LPFC_MBOXQ_t *pmb; - MAILBOX_t *mb; - char *lpfc_vpd_data = NULL; - uint16_t offset = 0; - static char licensed[56] = - "key unlock for use with gnu public licensed code only\0"; - static int init_key = 1; - - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - phba->link_state = LPFC_HBA_ERROR; - return -ENOMEM; - } - - mb = &pmb->u.mb; - phba->link_state = LPFC_INIT_MBX_CMDS; - - if (lpfc_is_LC_HBA(phba->pcidev->device)) { - if (init_key) { - uint32_t *ptext = (uint32_t *) licensed; - - for (i = 0; i < 56; i += sizeof (uint32_t), ptext++) - *ptext = cpu_to_be32(*ptext); - init_key = 0; - } - - lpfc_read_nv(phba, pmb); - memset((char*)mb->un.varRDnvp.rsvd3, 0, - sizeof (mb->un.varRDnvp.rsvd3)); - memcpy((char*)mb->un.varRDnvp.rsvd3, licensed, - sizeof (licensed)); - - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "0324 Config Port initialization " - "error, mbxCmd x%x READ_NVPARM, " - "mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); - mempool_free(pmb, phba->mbox_mem_pool); - return -ERESTART; - } - memcpy(phba->wwnn, (char *)mb->un.varRDnvp.nodename, - sizeof(phba->wwnn)); - memcpy(phba->wwpn, (char *)mb->un.varRDnvp.portname, - sizeof(phba->wwpn)); - } - - phba->sli3_options = 0x0; - - /* Setup and issue mailbox READ REV command */ - lpfc_read_rev(phba, pmb); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0439 Adapter failed to init, mbxCmd x%x " - "READ_REV, mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); - mempool_free( pmb, phba->mbox_mem_pool); - return -ERESTART; - } - - - /* - * The value of rr must be 1 since the driver set the cv field to 1. - * This setting requires the FW to set all revision fields. - */ - if (mb->un.varRdRev.rr == 0) { - vp->rev.rBit = 0; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0440 Adapter failed to init, READ_REV has " - "missing revision information.\n"); - mempool_free(pmb, phba->mbox_mem_pool); - return -ERESTART; - } - - if (phba->sli_rev == 3 && !mb->un.varRdRev.v3rsp) { - mempool_free(pmb, phba->mbox_mem_pool); - return -EINVAL; - } - - /* Save information as VPD data */ - vp->rev.rBit = 1; - memcpy(&vp->sli3Feat, &mb->un.varRdRev.sli3Feat, sizeof(uint32_t)); - vp->rev.sli1FwRev = mb->un.varRdRev.sli1FwRev; - memcpy(vp->rev.sli1FwName, (char*) mb->un.varRdRev.sli1FwName, 16); - vp->rev.sli2FwRev = mb->un.varRdRev.sli2FwRev; - memcpy(vp->rev.sli2FwName, (char *) mb->un.varRdRev.sli2FwName, 16); - vp->rev.biuRev = mb->un.varRdRev.biuRev; - vp->rev.smRev = mb->un.varRdRev.smRev; - vp->rev.smFwRev = mb->un.varRdRev.un.smFwRev; - vp->rev.endecRev = mb->un.varRdRev.endecRev; - vp->rev.fcphHigh = mb->un.varRdRev.fcphHigh; - vp->rev.fcphLow = mb->un.varRdRev.fcphLow; - vp->rev.feaLevelHigh = mb->un.varRdRev.feaLevelHigh; - vp->rev.feaLevelLow = mb->un.varRdRev.feaLevelLow; - vp->rev.postKernRev = mb->un.varRdRev.postKernRev; - vp->rev.opFwRev = mb->un.varRdRev.opFwRev; - - /* If the sli feature level is less then 9, we must - * tear down all RPIs and VPIs on link down if NPIV - * is enabled. - */ - if (vp->rev.feaLevelHigh < 9) - phba->sli3_options |= LPFC_SLI3_VPORT_TEARDOWN; - - if (lpfc_is_LC_HBA(phba->pcidev->device)) - memcpy(phba->RandomData, (char *)&mb->un.varWords[24], - sizeof (phba->RandomData)); - - /* Get adapter VPD information */ - lpfc_vpd_data = kmalloc(DMP_VPD_SIZE, GFP_KERNEL); - if (!lpfc_vpd_data) - goto out_free_mbox; - do { - lpfc_dump_mem(phba, pmb, offset, DMP_REGION_VPD); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0441 VPD not present on adapter, " - "mbxCmd x%x DUMP VPD, mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); - mb->un.varDmp.word_cnt = 0; - } - /* dump mem may return a zero when finished or we got a - * mailbox error, either way we are done. - */ - if (mb->un.varDmp.word_cnt == 0) - break; - if (mb->un.varDmp.word_cnt > DMP_VPD_SIZE - offset) - mb->un.varDmp.word_cnt = DMP_VPD_SIZE - offset; - lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - lpfc_vpd_data + offset, - mb->un.varDmp.word_cnt); - offset += mb->un.varDmp.word_cnt; - } while (mb->un.varDmp.word_cnt && offset < DMP_VPD_SIZE); - lpfc_parse_vpd(phba, lpfc_vpd_data, offset); - - kfree(lpfc_vpd_data); -out_free_mbox: - mempool_free(pmb, phba->mbox_mem_pool); - return 0; -} - -/** - * lpfc_config_async_cmpl - Completion handler for config async event mbox cmd - * @phba: pointer to lpfc hba data structure. - * @pmboxq: pointer to the driver internal queue element for mailbox command. - * - * This is the completion handler for driver's configuring asynchronous event - * mailbox command to the device. If the mailbox command returns successfully, - * it will set internal async event support flag to 1; otherwise, it will - * set internal async event support flag to 0. - **/ -static void -lpfc_config_async_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) -{ - if (pmboxq->u.mb.mbxStatus == MBX_SUCCESS) - phba->temp_sensor_support = 1; - else - phba->temp_sensor_support = 0; - mempool_free(pmboxq, phba->mbox_mem_pool); - return; -} - -/** - * lpfc_dump_wakeup_param_cmpl - dump memory mailbox command completion handler - * @phba: pointer to lpfc hba data structure. - * @pmboxq: pointer to the driver internal queue element for mailbox command. - * - * This is the completion handler for dump mailbox command for getting - * wake up parameters. When this command complete, the response contain - * Option rom version of the HBA. This function translate the version number - * into a human readable string and store it in OptionROMVersion. - **/ -static void -lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) -{ - struct prog_id *prg; - uint32_t prog_id_word; - char dist = ' '; - /* character array used for decoding dist type. */ - char dist_char[] = "nabx"; - - if (pmboxq->u.mb.mbxStatus != MBX_SUCCESS) { - mempool_free(pmboxq, phba->mbox_mem_pool); - return; - } - - prg = (struct prog_id *) &prog_id_word; - - /* word 7 contain option rom version */ - prog_id_word = pmboxq->u.mb.un.varWords[7]; - - /* Decode the Option rom version word to a readable string */ - if (prg->dist < 4) - dist = dist_char[prg->dist]; - - if ((prg->dist == 3) && (prg->num == 0)) - sprintf(phba->OptionROMVersion, "%d.%d%d", - prg->ver, prg->rev, prg->lev); - else - sprintf(phba->OptionROMVersion, "%d.%d%d%c%d", - prg->ver, prg->rev, prg->lev, - dist, prg->num); - mempool_free(pmboxq, phba->mbox_mem_pool); - return; -} - -/** - * lpfc_update_vport_wwn - Updates the fc_nodename, fc_portname, - * cfg_soft_wwnn, cfg_soft_wwpn - * @vport: pointer to lpfc vport data structure. - * - * - * Return codes - * None. - **/ -void -lpfc_update_vport_wwn(struct lpfc_vport *vport) -{ - /* If the soft name exists then update it using the service params */ - if (vport->phba->cfg_soft_wwnn) - u64_to_wwn(vport->phba->cfg_soft_wwnn, - vport->fc_sparam.nodeName.u.wwn); - if (vport->phba->cfg_soft_wwpn) - u64_to_wwn(vport->phba->cfg_soft_wwpn, - vport->fc_sparam.portName.u.wwn); - - /* - * If the name is empty or there exists a soft name - * then copy the service params name, otherwise use the fc name - */ - if (vport->fc_nodename.u.wwn[0] == 0 || vport->phba->cfg_soft_wwnn) - memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, - sizeof(struct lpfc_name)); - else - memcpy(&vport->fc_sparam.nodeName, &vport->fc_nodename, - sizeof(struct lpfc_name)); - - if (vport->fc_portname.u.wwn[0] == 0 || vport->phba->cfg_soft_wwpn) - memcpy(&vport->fc_portname, &vport->fc_sparam.portName, - sizeof(struct lpfc_name)); - else - memcpy(&vport->fc_sparam.portName, &vport->fc_portname, - sizeof(struct lpfc_name)); -} - -/** - * lpfc_config_port_post - Perform lpfc initialization after config port - * @phba: pointer to lpfc hba data structure. - * - * This routine will do LPFC initialization after the CONFIG_PORT mailbox - * command call. It performs all internal resource and state setups on the - * port: post IOCB buffers, enable appropriate host interrupt attentions, - * ELS ring timers, etc. - * - * Return codes - * 0 - success. - * Any other value - error. - **/ -int -lpfc_config_port_post(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport = phba->pport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - LPFC_MBOXQ_t *pmb; - MAILBOX_t *mb; - struct lpfc_dmabuf *mp; - struct lpfc_sli *psli = &phba->sli; - uint32_t status, timeout; - int i, j; - int rc; - - spin_lock_irq(&phba->hbalock); - /* - * If the Config port completed correctly the HBA is not - * over heated any more. - */ - if (phba->over_temp_state == HBA_OVER_TEMP) - phba->over_temp_state = HBA_NORMAL_TEMP; - spin_unlock_irq(&phba->hbalock); - - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - phba->link_state = LPFC_HBA_ERROR; - return -ENOMEM; - } - mb = &pmb->u.mb; - - /* Get login parameters for NID. */ - rc = lpfc_read_sparam(phba, pmb, 0); - if (rc) { - mempool_free(pmb, phba->mbox_mem_pool); - return -ENOMEM; - } - - pmb->vport = vport; - if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0448 Adapter failed init, mbxCmd x%x " - "READ_SPARM mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); - phba->link_state = LPFC_HBA_ERROR; - mp = (struct lpfc_dmabuf *) pmb->context1; - mempool_free(pmb, phba->mbox_mem_pool); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - return -EIO; - } - - mp = (struct lpfc_dmabuf *) pmb->context1; - - memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm)); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - pmb->context1 = NULL; - lpfc_update_vport_wwn(vport); - - /* Update the fc_host data structures with new wwn. */ - fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); - fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); - fc_host_max_npiv_vports(shost) = phba->max_vpi; - - /* If no serial number in VPD data, use low 6 bytes of WWNN */ - /* This should be consolidated into parse_vpd ? - mr */ - if (phba->SerialNumber[0] == 0) { - uint8_t *outptr; - - outptr = &vport->fc_nodename.u.s.IEEE[0]; - for (i = 0; i < 12; i++) { - status = *outptr++; - j = ((status & 0xf0) >> 4); - if (j <= 9) - phba->SerialNumber[i] = - (char)((uint8_t) 0x30 + (uint8_t) j); - else - phba->SerialNumber[i] = - (char)((uint8_t) 0x61 + (uint8_t) (j - 10)); - i++; - j = (status & 0xf); - if (j <= 9) - phba->SerialNumber[i] = - (char)((uint8_t) 0x30 + (uint8_t) j); - else - phba->SerialNumber[i] = - (char)((uint8_t) 0x61 + (uint8_t) (j - 10)); - } - } - - lpfc_read_config(phba, pmb); - pmb->vport = vport; - if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0453 Adapter failed to init, mbxCmd x%x " - "READ_CONFIG, mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); - phba->link_state = LPFC_HBA_ERROR; - mempool_free( pmb, phba->mbox_mem_pool); - return -EIO; - } - - /* Check if the port is disabled */ - lpfc_sli_read_link_ste(phba); - - /* Reset the DFT_HBA_Q_DEPTH to the max xri */ - if (phba->cfg_hba_queue_depth > (mb->un.varRdConfig.max_xri+1)) - phba->cfg_hba_queue_depth = - (mb->un.varRdConfig.max_xri + 1) - - lpfc_sli4_get_els_iocb_cnt(phba); - - phba->lmt = mb->un.varRdConfig.lmt; - - /* Get the default values for Model Name and Description */ - lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); - - phba->link_state = LPFC_LINK_DOWN; - - /* Only process IOCBs on ELS ring till hba_state is READY */ - if (psli->ring[psli->extra_ring].cmdringaddr) - psli->ring[psli->extra_ring].flag |= LPFC_STOP_IOCB_EVENT; - if (psli->ring[psli->fcp_ring].cmdringaddr) - psli->ring[psli->fcp_ring].flag |= LPFC_STOP_IOCB_EVENT; - if (psli->ring[psli->next_ring].cmdringaddr) - psli->ring[psli->next_ring].flag |= LPFC_STOP_IOCB_EVENT; - - /* Post receive buffers for desired rings */ - if (phba->sli_rev != 3) - lpfc_post_rcv_buf(phba); - - /* - * Configure HBA MSI-X attention conditions to messages if MSI-X mode - */ - if (phba->intr_type == MSIX) { - rc = lpfc_config_msi(phba, pmb); - if (rc) { - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; - } - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "0352 Config MSI mailbox command " - "failed, mbxCmd x%x, mbxStatus x%x\n", - pmb->u.mb.mbxCommand, - pmb->u.mb.mbxStatus); - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; - } - } - - spin_lock_irq(&phba->hbalock); - /* Initialize ERATT handling flag */ - phba->hba_flag &= ~HBA_ERATT_HANDLED; - - /* Enable appropriate host interrupts */ - if (lpfc_readl(phba->HCregaddr, &status)) { - spin_unlock_irq(&phba->hbalock); - return -EIO; - } - status |= HC_MBINT_ENA | HC_ERINT_ENA | HC_LAINT_ENA; - if (psli->num_rings > 0) - status |= HC_R0INT_ENA; - if (psli->num_rings > 1) - status |= HC_R1INT_ENA; - if (psli->num_rings > 2) - status |= HC_R2INT_ENA; - if (psli->num_rings > 3) - status |= HC_R3INT_ENA; - - if ((phba->cfg_poll & ENABLE_FCP_RING_POLLING) && - (phba->cfg_poll & DISABLE_FCP_RING_INT)) - status &= ~(HC_R0INT_ENA); - - writel(status, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - spin_unlock_irq(&phba->hbalock); - - /* Set up ring-0 (ELS) timer */ - timeout = phba->fc_ratov * 2; - mod_timer(&vport->els_tmofunc, jiffies + HZ * timeout); - /* Set up heart beat (HB) timer */ - mod_timer(&phba->hb_tmofunc, jiffies + HZ * LPFC_HB_MBOX_INTERVAL); - phba->hb_outstanding = 0; - phba->last_completion_time = jiffies; - /* Set up error attention (ERATT) polling timer */ - mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); - - if (phba->hba_flag & LINK_DISABLED) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2598 Adapter Link is disabled.\n"); - lpfc_down_link(phba, pmb); - pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2599 Adapter failed to issue DOWN_LINK" - " mbox command rc 0x%x\n", rc); - - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; - } - } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { - mempool_free(pmb, phba->mbox_mem_pool); - rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); - if (rc) - return rc; - } - /* MBOX buffer will be freed in mbox compl */ - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - phba->link_state = LPFC_HBA_ERROR; - return -ENOMEM; - } - - lpfc_config_async(phba, pmb, LPFC_ELS_RING); - pmb->mbox_cmpl = lpfc_config_async_cmpl; - pmb->vport = phba->pport; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - - if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_INIT, - "0456 Adapter failed to issue " - "ASYNCEVT_ENABLE mbox status x%x\n", - rc); - mempool_free(pmb, phba->mbox_mem_pool); - } - - /* Get Option rom version */ - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - phba->link_state = LPFC_HBA_ERROR; - return -ENOMEM; - } - - lpfc_dump_wakeup_param(phba, pmb); - pmb->mbox_cmpl = lpfc_dump_wakeup_param_cmpl; - pmb->vport = phba->pport; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - - if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "0435 Adapter failed " - "to get Option ROM version status x%x\n", rc); - mempool_free(pmb, phba->mbox_mem_pool); - } - - return 0; -} - -/** - * lpfc_hba_init_link - Initialize the FC link - * @phba: pointer to lpfc hba data structure. - * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT - * - * This routine will issue the INIT_LINK mailbox command call. - * It is available to other drivers through the lpfc_hba data - * structure for use as a delayed link up mechanism with the - * module parameter lpfc_suppress_link_up. - * - * Return code - * 0 - success - * Any other value - error - **/ -int -lpfc_hba_init_link(struct lpfc_hba *phba, uint32_t flag) -{ - return lpfc_hba_init_link_fc_topology(phba, phba->cfg_topology, flag); -} - -/** - * lpfc_hba_init_link_fc_topology - Initialize FC link with desired topology - * @phba: pointer to lpfc hba data structure. - * @fc_topology: desired fc topology. - * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT - * - * This routine will issue the INIT_LINK mailbox command call. - * It is available to other drivers through the lpfc_hba data - * structure for use as a delayed link up mechanism with the - * module parameter lpfc_suppress_link_up. - * - * Return code - * 0 - success - * Any other value - error - **/ -int -lpfc_hba_init_link_fc_topology(struct lpfc_hba *phba, uint32_t fc_topology, - uint32_t flag) -{ - struct lpfc_vport *vport = phba->pport; - LPFC_MBOXQ_t *pmb; - MAILBOX_t *mb; - int rc; - - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - phba->link_state = LPFC_HBA_ERROR; - return -ENOMEM; - } - mb = &pmb->u.mb; - pmb->vport = vport; - - if ((phba->cfg_link_speed > LPFC_USER_LINK_SPEED_MAX) || - ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_1G) && - !(phba->lmt & LMT_1Gb)) || - ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_2G) && - !(phba->lmt & LMT_2Gb)) || - ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_4G) && - !(phba->lmt & LMT_4Gb)) || - ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_8G) && - !(phba->lmt & LMT_8Gb)) || - ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_10G) && - !(phba->lmt & LMT_10Gb)) || - ((phba->cfg_link_speed == LPFC_USER_LINK_SPEED_16G) && - !(phba->lmt & LMT_16Gb))) { - /* Reset link speed to auto */ - lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1302 Invalid speed for this board:%d " - "Reset link speed to auto.\n", - phba->cfg_link_speed); - phba->cfg_link_speed = LPFC_USER_LINK_SPEED_AUTO; - } - lpfc_init_link(phba, pmb, fc_topology, phba->cfg_link_speed); - pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - if (phba->sli_rev < LPFC_SLI_REV4) - lpfc_set_loopback_flag(phba); - rc = lpfc_sli_issue_mbox(phba, pmb, flag); - if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0498 Adapter failed to init, mbxCmd x%x " - "INIT_LINK, mbxStatus x%x\n", - mb->mbxCommand, mb->mbxStatus); - if (phba->sli_rev <= LPFC_SLI_REV3) { - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - /* Clear all pending interrupts */ - writel(0xffffffff, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - } - phba->link_state = LPFC_HBA_ERROR; - if (rc != MBX_BUSY || flag == MBX_POLL) - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; - } - phba->cfg_suppress_link_up = LPFC_INITIALIZE_LINK; - if (flag == MBX_POLL) - mempool_free(pmb, phba->mbox_mem_pool); - - return 0; -} - -/** - * lpfc_hba_down_link - this routine downs the FC link - * @phba: pointer to lpfc hba data structure. - * @flag: mailbox command issue mode - either MBX_POLL or MBX_NOWAIT - * - * This routine will issue the DOWN_LINK mailbox command call. - * It is available to other drivers through the lpfc_hba data - * structure for use to stop the link. - * - * Return code - * 0 - success - * Any other value - error - **/ -int -lpfc_hba_down_link(struct lpfc_hba *phba, uint32_t flag) -{ - LPFC_MBOXQ_t *pmb; - int rc; - - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - phba->link_state = LPFC_HBA_ERROR; - return -ENOMEM; - } - - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "0491 Adapter Link is disabled.\n"); - lpfc_down_link(phba, pmb); - pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, pmb, flag); - if ((rc != MBX_SUCCESS) && (rc != MBX_BUSY)) { - lpfc_printf_log(phba, - KERN_ERR, LOG_INIT, - "2522 Adapter failed to issue DOWN_LINK" - " mbox command rc 0x%x\n", rc); - - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; - } - if (flag == MBX_POLL) - mempool_free(pmb, phba->mbox_mem_pool); - - return 0; -} - -/** - * lpfc_hba_down_prep - Perform lpfc uninitialization prior to HBA reset - * @phba: pointer to lpfc HBA data structure. - * - * This routine will do LPFC uninitialization before the HBA is reset when - * bringing down the SLI Layer. - * - * Return codes - * 0 - success. - * Any other value - error. - **/ -int -lpfc_hba_down_prep(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - int i; - - if (phba->sli_rev <= LPFC_SLI_REV3) { - /* Disable interrupts */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - - if (phba->pport->load_flag & FC_UNLOADING) - lpfc_cleanup_discovery_resources(phba->pport); - else { - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && - vports[i] != NULL; i++) - lpfc_cleanup_discovery_resources(vports[i]); - lpfc_destroy_vport_work_array(phba, vports); - } - return 0; -} - -/** - * lpfc_hba_down_post_s3 - Perform lpfc uninitialization after HBA reset - * @phba: pointer to lpfc HBA data structure. - * - * This routine will do uninitialization after the HBA is reset when bring - * down the SLI Layer. - * - * Return codes - * 0 - success. - * Any other value - error. - **/ -static int -lpfc_hba_down_post_s3(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - struct lpfc_dmabuf *mp, *next_mp; - LIST_HEAD(completions); - int i; - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) - lpfc_sli_hbqbuf_free_all(phba); - else { - /* Cleanup preposted buffers on the ELS ring */ - pring = &psli->ring[LPFC_ELS_RING]; - list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { - list_del(&mp->list); - pring->postbufq_cnt--; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - } - - spin_lock_irq(&phba->hbalock); - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - - /* At this point in time the HBA is either reset or DOA. Either - * way, nothing should be on txcmplq as it will NEVER complete. - */ - list_splice_init(&pring->txcmplq, &completions); - pring->txcmplq_cnt = 0; - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); - - lpfc_sli_abort_iocb_ring(phba, pring); - spin_lock_irq(&phba->hbalock); - } - spin_unlock_irq(&phba->hbalock); - - return 0; -} - -/** - * lpfc_hba_down_post_s4 - Perform lpfc uninitialization after HBA reset - * @phba: pointer to lpfc HBA data structure. - * - * This routine will do uninitialization after the HBA is reset when bring - * down the SLI Layer. - * - * Return codes - * 0 - success. - * Any other value - error. - **/ -static int -lpfc_hba_down_post_s4(struct lpfc_hba *phba) -{ - struct lpfc_scsi_buf *psb, *psb_next; - LIST_HEAD(aborts); - int ret; - unsigned long iflag = 0; - struct lpfc_sglq *sglq_entry = NULL; - - ret = lpfc_hba_down_post_s3(phba); - if (ret) - return ret; - /* At this point in time the HBA is either reset or DOA. Either - * way, nothing should be on lpfc_abts_els_sgl_list, it needs to be - * on the lpfc_sgl_list so that it can either be freed if the - * driver is unloading or reposted if the driver is restarting - * the port. - */ - spin_lock_irq(&phba->hbalock); /* required for lpfc_sgl_list and */ - /* scsl_buf_list */ - /* abts_sgl_list_lock required because worker thread uses this - * list. - */ - spin_lock(&phba->sli4_hba.abts_sgl_list_lock); - list_for_each_entry(sglq_entry, - &phba->sli4_hba.lpfc_abts_els_sgl_list, list) - sglq_entry->state = SGL_FREED; - - list_splice_init(&phba->sli4_hba.lpfc_abts_els_sgl_list, - &phba->sli4_hba.lpfc_sgl_list); - spin_unlock(&phba->sli4_hba.abts_sgl_list_lock); - /* abts_scsi_buf_list_lock required because worker thread uses this - * list. - */ - spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock); - list_splice_init(&phba->sli4_hba.lpfc_abts_scsi_buf_list, - &aborts); - spin_unlock(&phba->sli4_hba.abts_scsi_buf_list_lock); - spin_unlock_irq(&phba->hbalock); - - list_for_each_entry_safe(psb, psb_next, &aborts, list) { - psb->pCmd = NULL; - psb->status = IOSTAT_SUCCESS; - } - spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); - list_splice(&aborts, &phba->lpfc_scsi_buf_list); - spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag); - return 0; -} - -/** - * lpfc_hba_down_post - Wrapper func for hba down post routine - * @phba: pointer to lpfc HBA data structure. - * - * This routine wraps the actual SLI3 or SLI4 routine for performing - * uninitialization after the HBA is reset when bring down the SLI Layer. - * - * Return codes - * 0 - success. - * Any other value - error. - **/ -int -lpfc_hba_down_post(struct lpfc_hba *phba) -{ - return (*phba->lpfc_hba_down_post)(phba); -} - -/** - * lpfc_hb_timeout - The HBA-timer timeout handler - * @ptr: unsigned long holds the pointer to lpfc hba data structure. - * - * This is the HBA-timer timeout handler registered to the lpfc driver. When - * this timer fires, a HBA timeout event shall be posted to the lpfc driver - * work-port-events bitmap and the worker thread is notified. This timeout - * event will be used by the worker thread to invoke the actual timeout - * handler routine, lpfc_hb_timeout_handler. Any periodical operations will - * be performed in the timeout handler and the HBA timeout event bit shall - * be cleared by the worker thread after it has taken the event bitmap out. - **/ -static void -lpfc_hb_timeout(unsigned long ptr) -{ - struct lpfc_hba *phba; - uint32_t tmo_posted; - unsigned long iflag; - - phba = (struct lpfc_hba *)ptr; - - /* Check for heart beat timeout conditions */ - spin_lock_irqsave(&phba->pport->work_port_lock, iflag); - tmo_posted = phba->pport->work_port_events & WORKER_HB_TMO; - if (!tmo_posted) - phba->pport->work_port_events |= WORKER_HB_TMO; - spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); - - /* Tell the worker thread there is work to do */ - if (!tmo_posted) - lpfc_worker_wake_up(phba); - return; -} - -/** - * lpfc_rrq_timeout - The RRQ-timer timeout handler - * @ptr: unsigned long holds the pointer to lpfc hba data structure. - * - * This is the RRQ-timer timeout handler registered to the lpfc driver. When - * this timer fires, a RRQ timeout event shall be posted to the lpfc driver - * work-port-events bitmap and the worker thread is notified. This timeout - * event will be used by the worker thread to invoke the actual timeout - * handler routine, lpfc_rrq_handler. Any periodical operations will - * be performed in the timeout handler and the RRQ timeout event bit shall - * be cleared by the worker thread after it has taken the event bitmap out. - **/ -static void -lpfc_rrq_timeout(unsigned long ptr) -{ - struct lpfc_hba *phba; - unsigned long iflag; - - phba = (struct lpfc_hba *)ptr; - spin_lock_irqsave(&phba->pport->work_port_lock, iflag); - phba->hba_flag |= HBA_RRQ_ACTIVE; - spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); - lpfc_worker_wake_up(phba); -} - -/** - * lpfc_hb_mbox_cmpl - The lpfc heart-beat mailbox command callback function - * @phba: pointer to lpfc hba data structure. - * @pmboxq: pointer to the driver internal queue element for mailbox command. - * - * This is the callback function to the lpfc heart-beat mailbox command. - * If configured, the lpfc driver issues the heart-beat mailbox command to - * the HBA every LPFC_HB_MBOX_INTERVAL (current 5) seconds. At the time the - * heart-beat mailbox command is issued, the driver shall set up heart-beat - * timeout timer to LPFC_HB_MBOX_TIMEOUT (current 30) seconds and marks - * heart-beat outstanding state. Once the mailbox command comes back and - * no error conditions detected, the heart-beat mailbox command timer is - * reset to LPFC_HB_MBOX_INTERVAL seconds and the heart-beat outstanding - * state is cleared for the next heart-beat. If the timer expired with the - * heart-beat outstanding state set, the driver will put the HBA offline. - **/ -static void -lpfc_hb_mbox_cmpl(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq) -{ - unsigned long drvr_flag; - - spin_lock_irqsave(&phba->hbalock, drvr_flag); - phba->hb_outstanding = 0; - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - - /* Check and reset heart-beat timer is necessary */ - mempool_free(pmboxq, phba->mbox_mem_pool); - if (!(phba->pport->fc_flag & FC_OFFLINE_MODE) && - !(phba->link_state == LPFC_HBA_ERROR) && - !(phba->pport->load_flag & FC_UNLOADING)) - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); - return; -} - -/** - * lpfc_hb_timeout_handler - The HBA-timer timeout handler - * @phba: pointer to lpfc hba data structure. - * - * This is the actual HBA-timer timeout handler to be invoked by the worker - * thread whenever the HBA timer fired and HBA-timeout event posted. This - * handler performs any periodic operations needed for the device. If such - * periodic event has already been attended to either in the interrupt handler - * or by processing slow-ring or fast-ring events within the HBA-timer - * timeout window (LPFC_HB_MBOX_INTERVAL), this handler just simply resets - * the timer for the next timeout period. If lpfc heart-beat mailbox command - * is configured and there is no heart-beat mailbox command outstanding, a - * heart-beat mailbox is issued and timer set properly. Otherwise, if there - * has been a heart-beat mailbox command outstanding, the HBA shall be put - * to offline. - **/ -void -lpfc_hb_timeout_handler(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - LPFC_MBOXQ_t *pmboxq; - struct lpfc_dmabuf *buf_ptr; - int retval, i; - struct lpfc_sli *psli = &phba->sli; - LIST_HEAD(completions); - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) - lpfc_rcv_seq_check_edtov(vports[i]); - lpfc_destroy_vport_work_array(phba, vports); - - if ((phba->link_state == LPFC_HBA_ERROR) || - (phba->pport->load_flag & FC_UNLOADING) || - (phba->pport->fc_flag & FC_OFFLINE_MODE)) - return; - - spin_lock_irq(&phba->pport->work_port_lock); - - if (time_after(phba->last_completion_time + LPFC_HB_MBOX_INTERVAL * HZ, - jiffies)) { - spin_unlock_irq(&phba->pport->work_port_lock); - if (!phba->hb_outstanding) - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); - else - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); - return; - } - spin_unlock_irq(&phba->pport->work_port_lock); - - if (phba->elsbuf_cnt && - (phba->elsbuf_cnt == phba->elsbuf_prev_cnt)) { - spin_lock_irq(&phba->hbalock); - list_splice_init(&phba->elsbuf, &completions); - phba->elsbuf_cnt = 0; - phba->elsbuf_prev_cnt = 0; - spin_unlock_irq(&phba->hbalock); - - while (!list_empty(&completions)) { - list_remove_head(&completions, buf_ptr, - struct lpfc_dmabuf, list); - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - } - } - phba->elsbuf_prev_cnt = phba->elsbuf_cnt; - - /* If there is no heart beat outstanding, issue a heartbeat command */ - if (phba->cfg_enable_hba_heartbeat) { - if (!phba->hb_outstanding) { - if ((!(psli->sli_flag & LPFC_SLI_MBOX_ACTIVE)) && - (list_empty(&psli->mboxq))) { - pmboxq = mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!pmboxq) { - mod_timer(&phba->hb_tmofunc, - jiffies + - HZ * LPFC_HB_MBOX_INTERVAL); - return; - } - - lpfc_heart_beat(phba, pmboxq); - pmboxq->mbox_cmpl = lpfc_hb_mbox_cmpl; - pmboxq->vport = phba->pport; - retval = lpfc_sli_issue_mbox(phba, pmboxq, - MBX_NOWAIT); - - if (retval != MBX_BUSY && - retval != MBX_SUCCESS) { - mempool_free(pmboxq, - phba->mbox_mem_pool); - mod_timer(&phba->hb_tmofunc, - jiffies + - HZ * LPFC_HB_MBOX_INTERVAL); - return; - } - phba->skipped_hb = 0; - phba->hb_outstanding = 1; - } else if (time_before_eq(phba->last_completion_time, - phba->skipped_hb)) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2857 Last completion time not " - " updated in %d ms\n", - jiffies_to_msecs(jiffies - - phba->last_completion_time)); - } else - phba->skipped_hb = jiffies; - - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); - return; - } else { - /* - * If heart beat timeout called with hb_outstanding set - * we need to give the hb mailbox cmd a chance to - * complete or TMO. - */ - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0459 Adapter heartbeat still out" - "standing:last compl time was %d ms.\n", - jiffies_to_msecs(jiffies - - phba->last_completion_time)); - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_TIMEOUT); - } - } -} - -/** - * lpfc_offline_eratt - Bring lpfc offline on hardware error attention - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to bring the HBA offline when HBA hardware error - * other than Port Error 6 has been detected. - **/ -static void -lpfc_offline_eratt(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - lpfc_offline_prep(phba); - - lpfc_offline(phba); - lpfc_reset_barrier(phba); - spin_lock_irq(&phba->hbalock); - lpfc_sli_brdreset(phba); - spin_unlock_irq(&phba->hbalock); - lpfc_hba_down_post(phba); - lpfc_sli_brdready(phba, HS_MBRDY); - lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; - return; -} - -/** - * lpfc_sli4_offline_eratt - Bring lpfc offline on SLI4 hardware error attention - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to bring a SLI4 HBA offline when HBA hardware error - * other than Port Error 6 has been detected. - **/ -static void -lpfc_sli4_offline_eratt(struct lpfc_hba *phba) -{ - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_sli4_brdreset(phba); - lpfc_hba_down_post(phba); - lpfc_sli4_post_status_check(phba); - lpfc_unblock_mgmt_io(phba); - phba->link_state = LPFC_HBA_ERROR; -} - -/** - * lpfc_handle_deferred_eratt - The HBA hardware deferred error handler - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to handle the deferred HBA hardware error - * conditions. This type of error is indicated by HBA by setting ER1 - * and another ER bit in the host status register. The driver will - * wait until the ER1 bit clears before handling the error condition. - **/ -static void -lpfc_handle_deferred_eratt(struct lpfc_hba *phba) -{ - uint32_t old_host_status = phba->work_hs; - struct lpfc_sli_ring *pring; - struct lpfc_sli *psli = &phba->sli; - - /* If the pci channel is offline, ignore possible errors, - * since we cannot communicate with the pci card anyway. - */ - if (pci_channel_offline(phba->pcidev)) { - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~DEFER_ERATT; - spin_unlock_irq(&phba->hbalock); - return; - } - - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0479 Deferred Adapter Hardware Error " - "Data: x%x x%x x%x\n", - phba->work_hs, - phba->work_status[0], phba->work_status[1]); - - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - - - /* - * Firmware stops when it triggred erratt. That could cause the I/Os - * dropped by the firmware. Error iocb (I/O) on txcmplq and let the - * SCSI layer retry it after re-establishing link. - */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); - - /* - * There was a firmware error. Take the hba offline and then - * attempt to restart it. - */ - lpfc_offline_prep(phba); - lpfc_offline(phba); - - /* Wait for the ER1 bit to clear.*/ - while (phba->work_hs & HS_FFER1) { - msleep(100); - if (lpfc_readl(phba->HSregaddr, &phba->work_hs)) { - phba->work_hs = UNPLUG_ERR ; - break; - } - /* If driver is unloading let the worker thread continue */ - if (phba->pport->load_flag & FC_UNLOADING) { - phba->work_hs = 0; - break; - } - } - - /* - * This is to ptrotect against a race condition in which - * first write to the host attention register clear the - * host status register. - */ - if ((!phba->work_hs) && (!(phba->pport->load_flag & FC_UNLOADING))) - phba->work_hs = old_host_status & ~HS_FFER1; - - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~DEFER_ERATT; - spin_unlock_irq(&phba->hbalock); - phba->work_status[0] = readl(phba->MBslimaddr + 0xa8); - phba->work_status[1] = readl(phba->MBslimaddr + 0xac); -} - -static void -lpfc_board_errevt_to_mgmt(struct lpfc_hba *phba) -{ - struct lpfc_board_event_header board_event; - struct Scsi_Host *shost; - - board_event.event_type = FC_REG_BOARD_EVENT; - board_event.subcategory = LPFC_EVENT_PORTINTERR; - shost = lpfc_shost_from_vport(phba->pport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(board_event), - (char *) &board_event, - LPFC_NL_VENDOR_ID); -} - -/** - * lpfc_handle_eratt_s3 - The SLI3 HBA hardware error handler - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to handle the following HBA hardware error - * conditions: - * 1 - HBA error attention interrupt - * 2 - DMA ring index out of range - * 3 - Mailbox command came back as unknown - **/ -static void -lpfc_handle_eratt_s3(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport = phba->pport; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - uint32_t event_data; - unsigned long temperature; - struct temp_event temp_event_data; - struct Scsi_Host *shost; - - /* If the pci channel is offline, ignore possible errors, - * since we cannot communicate with the pci card anyway. - */ - if (pci_channel_offline(phba->pcidev)) { - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~DEFER_ERATT; - spin_unlock_irq(&phba->hbalock); - return; - } - - /* If resets are disabled then leave the HBA alone and return */ - if (!phba->cfg_enable_hba_reset) - return; - - /* Send an internal error event to mgmt application */ - lpfc_board_errevt_to_mgmt(phba); - - if (phba->hba_flag & DEFER_ERATT) - lpfc_handle_deferred_eratt(phba); - - if ((phba->work_hs & HS_FFER6) || (phba->work_hs & HS_FFER8)) { - if (phba->work_hs & HS_FFER6) - /* Re-establishing Link */ - lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, - "1301 Re-establishing Link " - "Data: x%x x%x x%x\n", - phba->work_hs, phba->work_status[0], - phba->work_status[1]); - if (phba->work_hs & HS_FFER8) - /* Device Zeroization */ - lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, - "2861 Host Authentication device " - "zeroization Data:x%x x%x x%x\n", - phba->work_hs, phba->work_status[0], - phba->work_status[1]); - - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - - /* - * Firmware stops when it triggled erratt with HS_FFER6. - * That could cause the I/Os dropped by the firmware. - * Error iocb (I/O) on txcmplq and let the SCSI layer - * retry it after re-establishing link. - */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); - - /* - * There was a firmware error. Take the hba offline and then - * attempt to restart it. - */ - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_sli_brdrestart(phba); - if (lpfc_online(phba) == 0) { /* Initialize the HBA */ - lpfc_unblock_mgmt_io(phba); - return; - } - lpfc_unblock_mgmt_io(phba); - } else if (phba->work_hs & HS_CRIT_TEMP) { - temperature = readl(phba->MBslimaddr + TEMPERATURE_OFFSET); - temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; - temp_event_data.event_code = LPFC_CRIT_TEMP; - temp_event_data.data = (uint32_t)temperature; - - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0406 Adapter maximum temperature exceeded " - "(%ld), taking this port offline " - "Data: x%x x%x x%x\n", - temperature, phba->work_hs, - phba->work_status[0], phba->work_status[1]); - - shost = lpfc_shost_from_vport(phba->pport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(temp_event_data), - (char *) &temp_event_data, - SCSI_NL_VID_TYPE_PCI - | PCI_VENDOR_ID_EMULEX); - - spin_lock_irq(&phba->hbalock); - phba->over_temp_state = HBA_OVER_TEMP; - spin_unlock_irq(&phba->hbalock); - lpfc_offline_eratt(phba); - - } else { - /* The if clause above forces this code path when the status - * failure is a value other than FFER6. Do not call the offline - * twice. This is the adapter hardware error path. - */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0457 Adapter Hardware Error " - "Data: x%x x%x x%x\n", - phba->work_hs, - phba->work_status[0], phba->work_status[1]); - - event_data = FC_REG_DUMP_EVENT; - shost = lpfc_shost_from_vport(vport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(event_data), (char *) &event_data, - SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); - - lpfc_offline_eratt(phba); - } - return; -} - -/** - * lpfc_handle_eratt_s4 - The SLI4 HBA hardware error handler - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to handle the SLI4 HBA hardware error attention - * conditions. - **/ -static void -lpfc_handle_eratt_s4(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport = phba->pport; - uint32_t event_data; - struct Scsi_Host *shost; - uint32_t if_type; - struct lpfc_register portstat_reg = {0}; - uint32_t reg_err1, reg_err2; - uint32_t uerrlo_reg, uemasklo_reg; - uint32_t pci_rd_rc1, pci_rd_rc2; - int rc; - - /* If the pci channel is offline, ignore possible errors, since - * we cannot communicate with the pci card anyway. - */ - if (pci_channel_offline(phba->pcidev)) - return; - /* If resets are disabled then leave the HBA alone and return */ - if (!phba->cfg_enable_hba_reset) - return; - - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - switch (if_type) { - case LPFC_SLI_INTF_IF_TYPE_0: - pci_rd_rc1 = lpfc_readl( - phba->sli4_hba.u.if_type0.UERRLOregaddr, - &uerrlo_reg); - pci_rd_rc2 = lpfc_readl( - phba->sli4_hba.u.if_type0.UEMASKLOregaddr, - &uemasklo_reg); - /* consider PCI bus read error as pci_channel_offline */ - if (pci_rd_rc1 == -EIO && pci_rd_rc2 == -EIO) - return; - lpfc_sli4_offline_eratt(phba); - break; - case LPFC_SLI_INTF_IF_TYPE_2: - pci_rd_rc1 = lpfc_readl( - phba->sli4_hba.u.if_type2.STATUSregaddr, - &portstat_reg.word0); - /* consider PCI bus read error as pci_channel_offline */ - if (pci_rd_rc1 == -EIO) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3151 PCI bus read access failure: x%x\n", - readl(phba->sli4_hba.u.if_type2.STATUSregaddr)); - return; - } - reg_err1 = readl(phba->sli4_hba.u.if_type2.ERR1regaddr); - reg_err2 = readl(phba->sli4_hba.u.if_type2.ERR2regaddr); - if (bf_get(lpfc_sliport_status_oti, &portstat_reg)) { - /* TODO: Register for Overtemp async events. */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2889 Port Overtemperature event, " - "taking port offline\n"); - spin_lock_irq(&phba->hbalock); - phba->over_temp_state = HBA_OVER_TEMP; - spin_unlock_irq(&phba->hbalock); - lpfc_sli4_offline_eratt(phba); - break; - } - if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && - reg_err2 == SLIPORT_ERR2_REG_FW_RESTART) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3143 Port Down: Firmware Restarted\n"); - else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && - reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3144 Port Down: Debug Dump\n"); - else if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && - reg_err2 == SLIPORT_ERR2_REG_FUNC_PROVISON) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3145 Port Down: Provisioning\n"); - /* - * On error status condition, driver need to wait for port - * ready before performing reset. - */ - rc = lpfc_sli4_pdev_status_reg_wait(phba); - if (!rc) { - /* need reset: attempt for port recovery */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2887 Reset Needed: Attempting Port " - "Recovery...\n"); - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_sli_brdrestart(phba); - if (lpfc_online(phba) == 0) { - lpfc_unblock_mgmt_io(phba); - /* don't report event on forced debug dump */ - if (reg_err1 == SLIPORT_ERR1_REG_ERR_CODE_2 && - reg_err2 == SLIPORT_ERR2_REG_FORCED_DUMP) - return; - else - break; - } - /* fall through for not able to recover */ - } - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3152 Unrecoverable error, bring the port " - "offline\n"); - lpfc_sli4_offline_eratt(phba); - break; - case LPFC_SLI_INTF_IF_TYPE_1: - default: - break; - } - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3123 Report dump event to upper layer\n"); - /* Send an internal error event to mgmt application */ - lpfc_board_errevt_to_mgmt(phba); - - event_data = FC_REG_DUMP_EVENT; - shost = lpfc_shost_from_vport(vport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(event_data), (char *) &event_data, - SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_EMULEX); -} - -/** - * lpfc_handle_eratt - Wrapper func for handling hba error attention - * @phba: pointer to lpfc HBA data structure. - * - * This routine wraps the actual SLI3 or SLI4 hba error attention handling - * routine from the API jump table function pointer from the lpfc_hba struct. - * - * Return codes - * 0 - success. - * Any other value - error. - **/ -void -lpfc_handle_eratt(struct lpfc_hba *phba) -{ - (*phba->lpfc_handle_eratt)(phba); -} - -/** - * lpfc_handle_latt - The HBA link event handler - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked from the worker thread to handle a HBA host - * attention link event. - **/ -void -lpfc_handle_latt(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport = phba->pport; - struct lpfc_sli *psli = &phba->sli; - LPFC_MBOXQ_t *pmb; - volatile uint32_t control; - struct lpfc_dmabuf *mp; - int rc = 0; - - pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - rc = 1; - goto lpfc_handle_latt_err_exit; - } - - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) { - rc = 2; - goto lpfc_handle_latt_free_pmb; - } - - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp->virt) { - rc = 3; - goto lpfc_handle_latt_free_mp; - } - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_all_cmd(phba); - - psli->slistat.link_event++; - lpfc_read_topology(phba, pmb, mp); - pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology; - pmb->vport = vport; - /* Block ELS IOCBs until we have processed this mbox command */ - phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT; - rc = lpfc_sli_issue_mbox (phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - rc = 4; - goto lpfc_handle_latt_free_mbuf; - } - - /* Clear Link Attention in HA REG */ - spin_lock_irq(&phba->hbalock); - writel(HA_LATT, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - spin_unlock_irq(&phba->hbalock); - - return; - -lpfc_handle_latt_free_mbuf: - phba->sli.ring[LPFC_ELS_RING].flag &= ~LPFC_STOP_IOCB_EVENT; - lpfc_mbuf_free(phba, mp->virt, mp->phys); -lpfc_handle_latt_free_mp: - kfree(mp); -lpfc_handle_latt_free_pmb: - mempool_free(pmb, phba->mbox_mem_pool); -lpfc_handle_latt_err_exit: - /* Enable Link attention interrupts */ - spin_lock_irq(&phba->hbalock); - psli->sli_flag |= LPFC_PROCESS_LA; - control = readl(phba->HCregaddr); - control |= HC_LAINT_ENA; - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - - /* Clear Link Attention in HA REG */ - writel(HA_LATT, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - spin_unlock_irq(&phba->hbalock); - lpfc_linkdown(phba); - phba->link_state = LPFC_HBA_ERROR; - - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "0300 LATT: Cannot issue READ_LA: Data:%d\n", rc); - - return; -} - -/** - * lpfc_parse_vpd - Parse VPD (Vital Product Data) - * @phba: pointer to lpfc hba data structure. - * @vpd: pointer to the vital product data. - * @len: length of the vital product data in bytes. - * - * This routine parses the Vital Product Data (VPD). The VPD is treated as - * an array of characters. In this routine, the ModelName, ProgramType, and - * ModelDesc, etc. fields of the phba data structure will be populated. - * - * Return codes - * 0 - pointer to the VPD passed in is NULL - * 1 - success - **/ -int -lpfc_parse_vpd(struct lpfc_hba *phba, uint8_t *vpd, int len) -{ - uint8_t lenlo, lenhi; - int Length; - int i, j; - int finished = 0; - int index = 0; - - if (!vpd) - return 0; - - /* Vital Product */ - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0455 Vital Product Data: x%x x%x x%x x%x\n", - (uint32_t) vpd[0], (uint32_t) vpd[1], (uint32_t) vpd[2], - (uint32_t) vpd[3]); - while (!finished && (index < (len - 4))) { - switch (vpd[index]) { - case 0x82: - case 0x91: - index += 1; - lenlo = vpd[index]; - index += 1; - lenhi = vpd[index]; - index += 1; - i = ((((unsigned short)lenhi) << 8) + lenlo); - index += i; - break; - case 0x90: - index += 1; - lenlo = vpd[index]; - index += 1; - lenhi = vpd[index]; - index += 1; - Length = ((((unsigned short)lenhi) << 8) + lenlo); - if (Length > len - index) - Length = len - index; - while (Length > 0) { - /* Look for Serial Number */ - if ((vpd[index] == 'S') && (vpd[index+1] == 'N')) { - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - phba->SerialNumber[j++] = vpd[index++]; - if (j == 31) - break; - } - phba->SerialNumber[j] = 0; - continue; - } - else if ((vpd[index] == 'V') && (vpd[index+1] == '1')) { - phba->vpd_flag |= VPD_MODEL_DESC; - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - phba->ModelDesc[j++] = vpd[index++]; - if (j == 255) - break; - } - phba->ModelDesc[j] = 0; - continue; - } - else if ((vpd[index] == 'V') && (vpd[index+1] == '2')) { - phba->vpd_flag |= VPD_MODEL_NAME; - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - phba->ModelName[j++] = vpd[index++]; - if (j == 79) - break; - } - phba->ModelName[j] = 0; - continue; - } - else if ((vpd[index] == 'V') && (vpd[index+1] == '3')) { - phba->vpd_flag |= VPD_PROGRAM_TYPE; - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - phba->ProgramType[j++] = vpd[index++]; - if (j == 255) - break; - } - phba->ProgramType[j] = 0; - continue; - } - else if ((vpd[index] == 'V') && (vpd[index+1] == '4')) { - phba->vpd_flag |= VPD_PORT; - index += 2; - i = vpd[index]; - index += 1; - j = 0; - Length -= (3+i); - while(i--) { - if ((phba->sli_rev == LPFC_SLI_REV4) && - (phba->sli4_hba.pport_name_sta == - LPFC_SLI4_PPNAME_GET)) { - j++; - index++; - } else - phba->Port[j++] = vpd[index++]; - if (j == 19) - break; - } - if ((phba->sli_rev != LPFC_SLI_REV4) || - (phba->sli4_hba.pport_name_sta == - LPFC_SLI4_PPNAME_NON)) - phba->Port[j] = 0; - continue; - } - else { - index += 2; - i = vpd[index]; - index += 1; - index += i; - Length -= (3 + i); - } - } - finished = 0; - break; - case 0x78: - finished = 1; - break; - default: - index ++; - break; - } - } - - return(1); -} - -/** - * lpfc_get_hba_model_desc - Retrieve HBA device model name and description - * @phba: pointer to lpfc hba data structure. - * @mdp: pointer to the data structure to hold the derived model name. - * @descp: pointer to the data structure to hold the derived description. - * - * This routine retrieves HBA's description based on its registered PCI device - * ID. The @descp passed into this function points to an array of 256 chars. It - * shall be returned with the model name, maximum speed, and the host bus type. - * The @mdp passed into this function points to an array of 80 chars. When the - * function returns, the @mdp will be filled with the model name. - **/ -static void -lpfc_get_hba_model_desc(struct lpfc_hba *phba, uint8_t *mdp, uint8_t *descp) -{ - lpfc_vpd_t *vp; - uint16_t dev_id = phba->pcidev->device; - int max_speed; - int GE = 0; - int oneConnect = 0; /* default is not a oneConnect */ - struct { - char *name; - char *bus; - char *function; - } m = {"", "", ""}; - - if (mdp && mdp[0] != '\0' - && descp && descp[0] != '\0') - return; - - if (phba->lmt & LMT_16Gb) - max_speed = 16; - else if (phba->lmt & LMT_10Gb) - max_speed = 10; - else if (phba->lmt & LMT_8Gb) - max_speed = 8; - else if (phba->lmt & LMT_4Gb) - max_speed = 4; - else if (phba->lmt & LMT_2Gb) - max_speed = 2; - else - max_speed = 1; - - vp = &phba->vpd; - - switch (dev_id) { - case PCI_DEVICE_ID_FIREFLY: - m = (typeof(m)){"LP6000", "PCI", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_SUPERFLY: - if (vp->rev.biuRev >= 1 && vp->rev.biuRev <= 3) - m = (typeof(m)){"LP7000", "PCI", - "Fibre Channel Adapter"}; - else - m = (typeof(m)){"LP7000E", "PCI", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_DRAGONFLY: - m = (typeof(m)){"LP8000", "PCI", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_CENTAUR: - if (FC_JEDEC_ID(vp->rev.biuRev) == CENTAUR_2G_JEDEC_ID) - m = (typeof(m)){"LP9002", "PCI", - "Fibre Channel Adapter"}; - else - m = (typeof(m)){"LP9000", "PCI", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_RFLY: - m = (typeof(m)){"LP952", "PCI", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_PEGASUS: - m = (typeof(m)){"LP9802", "PCI-X", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_THOR: - m = (typeof(m)){"LP10000", "PCI-X", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_VIPER: - m = (typeof(m)){"LPX1000", "PCI-X", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_PFLY: - m = (typeof(m)){"LP982", "PCI-X", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_TFLY: - m = (typeof(m)){"LP1050", "PCI-X", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_HELIOS: - m = (typeof(m)){"LP11000", "PCI-X2", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_HELIOS_SCSP: - m = (typeof(m)){"LP11000-SP", "PCI-X2", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_HELIOS_DCSP: - m = (typeof(m)){"LP11002-SP", "PCI-X2", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_NEPTUNE: - m = (typeof(m)){"LPe1000", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_NEPTUNE_SCSP: - m = (typeof(m)){"LPe1000-SP", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_NEPTUNE_DCSP: - m = (typeof(m)){"LPe1002-SP", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_BMID: - m = (typeof(m)){"LP1150", "PCI-X2", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_BSMB: - m = (typeof(m)){"LP111", "PCI-X2", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_ZEPHYR: - m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_ZEPHYR_SCSP: - m = (typeof(m)){"LPe11000", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_ZEPHYR_DCSP: - m = (typeof(m)){"LP2105", "PCIe", "FCoE Adapter"}; - GE = 1; - break; - case PCI_DEVICE_ID_ZMID: - m = (typeof(m)){"LPe1150", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_ZSMB: - m = (typeof(m)){"LPe111", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_LP101: - m = (typeof(m)){"LP101", "PCI-X", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_LP10000S: - m = (typeof(m)){"LP10000-S", "PCI", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_LP11000S: - m = (typeof(m)){"LP11000-S", "PCI-X2", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_LPE11000S: - m = (typeof(m)){"LPe11000-S", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_SAT: - m = (typeof(m)){"LPe12000", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_SAT_MID: - m = (typeof(m)){"LPe1250", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_SAT_SMB: - m = (typeof(m)){"LPe121", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_SAT_DCSP: - m = (typeof(m)){"LPe12002-SP", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_SAT_SCSP: - m = (typeof(m)){"LPe12000-SP", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_SAT_S: - m = (typeof(m)){"LPe12000-S", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_HORNET: - m = (typeof(m)){"LP21000", "PCIe", "FCoE Adapter"}; - GE = 1; - break; - case PCI_DEVICE_ID_PROTEUS_VF: - m = (typeof(m)){"LPev12000", "PCIe IOV", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_PROTEUS_PF: - m = (typeof(m)){"LPev12000", "PCIe IOV", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_PROTEUS_S: - m = (typeof(m)){"LPemv12002-S", "PCIe IOV", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_TIGERSHARK: - oneConnect = 1; - m = (typeof(m)){"OCe10100", "PCIe", "FCoE"}; - break; - case PCI_DEVICE_ID_TOMCAT: - oneConnect = 1; - m = (typeof(m)){"OCe11100", "PCIe", "FCoE"}; - break; - case PCI_DEVICE_ID_FALCON: - m = (typeof(m)){"LPSe12002-ML1-E", "PCIe", - "EmulexSecure Fibre"}; - break; - case PCI_DEVICE_ID_BALIUS: - m = (typeof(m)){"LPVe12002", "PCIe Shared I/O", - "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_LANCER_FC: - case PCI_DEVICE_ID_LANCER_FC_VF: - m = (typeof(m)){"LPe16000", "PCIe", "Fibre Channel Adapter"}; - break; - case PCI_DEVICE_ID_LANCER_FCOE: - case PCI_DEVICE_ID_LANCER_FCOE_VF: - oneConnect = 1; - m = (typeof(m)){"OCe15100", "PCIe", "FCoE"}; - break; - default: - m = (typeof(m)){"Unknown", "", ""}; - break; - } - - if (mdp && mdp[0] == '\0') - snprintf(mdp, 79,"%s", m.name); - /* - * oneConnect hba requires special processing, they are all initiators - * and we put the port number on the end - */ - if (descp && descp[0] == '\0') { - if (oneConnect) - snprintf(descp, 255, - "Emulex OneConnect %s, %s Initiator, Port %s", - m.name, m.function, - phba->Port); - else - snprintf(descp, 255, - "Emulex %s %d%s %s %s", - m.name, max_speed, (GE) ? "GE" : "Gb", - m.bus, m.function); - } -} - -/** - * lpfc_post_buffer - Post IOCB(s) with DMA buffer descriptor(s) to a IOCB ring - * @phba: pointer to lpfc hba data structure. - * @pring: pointer to a IOCB ring. - * @cnt: the number of IOCBs to be posted to the IOCB ring. - * - * This routine posts a given number of IOCBs with the associated DMA buffer - * descriptors specified by the cnt argument to the given IOCB ring. - * - * Return codes - * The number of IOCBs NOT able to be posted to the IOCB ring. - **/ -int -lpfc_post_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, int cnt) -{ - IOCB_t *icmd; - struct lpfc_iocbq *iocb; - struct lpfc_dmabuf *mp1, *mp2; - - cnt += pring->missbufcnt; - - /* While there are buffers to post */ - while (cnt > 0) { - /* Allocate buffer for command iocb */ - iocb = lpfc_sli_get_iocbq(phba); - if (iocb == NULL) { - pring->missbufcnt = cnt; - return cnt; - } - icmd = &iocb->iocb; - - /* 2 buffers can be posted per command */ - /* Allocate buffer to post */ - mp1 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (mp1) - mp1->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &mp1->phys); - if (!mp1 || !mp1->virt) { - kfree(mp1); - lpfc_sli_release_iocbq(phba, iocb); - pring->missbufcnt = cnt; - return cnt; - } - - INIT_LIST_HEAD(&mp1->list); - /* Allocate buffer to post */ - if (cnt > 1) { - mp2 = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (mp2) - mp2->virt = lpfc_mbuf_alloc(phba, MEM_PRI, - &mp2->phys); - if (!mp2 || !mp2->virt) { - kfree(mp2); - lpfc_mbuf_free(phba, mp1->virt, mp1->phys); - kfree(mp1); - lpfc_sli_release_iocbq(phba, iocb); - pring->missbufcnt = cnt; - return cnt; - } - - INIT_LIST_HEAD(&mp2->list); - } else { - mp2 = NULL; - } - - icmd->un.cont64[0].addrHigh = putPaddrHigh(mp1->phys); - icmd->un.cont64[0].addrLow = putPaddrLow(mp1->phys); - icmd->un.cont64[0].tus.f.bdeSize = FCELSSIZE; - icmd->ulpBdeCount = 1; - cnt--; - if (mp2) { - icmd->un.cont64[1].addrHigh = putPaddrHigh(mp2->phys); - icmd->un.cont64[1].addrLow = putPaddrLow(mp2->phys); - icmd->un.cont64[1].tus.f.bdeSize = FCELSSIZE; - cnt--; - icmd->ulpBdeCount = 2; - } - - icmd->ulpCommand = CMD_QUE_RING_BUF64_CN; - icmd->ulpLe = 1; - - if (lpfc_sli_issue_iocb(phba, pring->ringno, iocb, 0) == - IOCB_ERROR) { - lpfc_mbuf_free(phba, mp1->virt, mp1->phys); - kfree(mp1); - cnt++; - if (mp2) { - lpfc_mbuf_free(phba, mp2->virt, mp2->phys); - kfree(mp2); - cnt++; - } - lpfc_sli_release_iocbq(phba, iocb); - pring->missbufcnt = cnt; - return cnt; - } - lpfc_sli_ringpostbuf_put(phba, pring, mp1); - if (mp2) - lpfc_sli_ringpostbuf_put(phba, pring, mp2); - } - pring->missbufcnt = 0; - return 0; -} - -/** - * lpfc_post_rcv_buf - Post the initial receive IOCB buffers to ELS ring - * @phba: pointer to lpfc hba data structure. - * - * This routine posts initial receive IOCB buffers to the ELS ring. The - * current number of initial IOCB buffers specified by LPFC_BUF_RING0 is - * set to 64 IOCBs. - * - * Return codes - * 0 - success (currently always success) - **/ -static int -lpfc_post_rcv_buf(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - - /* Ring 0, ELS / CT buffers */ - lpfc_post_buffer(phba, &psli->ring[LPFC_ELS_RING], LPFC_BUF_RING0); - /* Ring 2 - FCP no buffers needed */ - - return 0; -} - -#define S(N,V) (((V)<<(N))|((V)>>(32-(N)))) - -/** - * lpfc_sha_init - Set up initial array of hash table entries - * @HashResultPointer: pointer to an array as hash table. - * - * This routine sets up the initial values to the array of hash table entries - * for the LC HBAs. - **/ -static void -lpfc_sha_init(uint32_t * HashResultPointer) -{ - HashResultPointer[0] = 0x67452301; - HashResultPointer[1] = 0xEFCDAB89; - HashResultPointer[2] = 0x98BADCFE; - HashResultPointer[3] = 0x10325476; - HashResultPointer[4] = 0xC3D2E1F0; -} - -/** - * lpfc_sha_iterate - Iterate initial hash table with the working hash table - * @HashResultPointer: pointer to an initial/result hash table. - * @HashWorkingPointer: pointer to an working hash table. - * - * This routine iterates an initial hash table pointed by @HashResultPointer - * with the values from the working hash table pointeed by @HashWorkingPointer. - * The results are putting back to the initial hash table, returned through - * the @HashResultPointer as the result hash table. - **/ -static void -lpfc_sha_iterate(uint32_t * HashResultPointer, uint32_t * HashWorkingPointer) -{ - int t; - uint32_t TEMP; - uint32_t A, B, C, D, E; - t = 16; - do { - HashWorkingPointer[t] = - S(1, - HashWorkingPointer[t - 3] ^ HashWorkingPointer[t - - 8] ^ - HashWorkingPointer[t - 14] ^ HashWorkingPointer[t - 16]); - } while (++t <= 79); - t = 0; - A = HashResultPointer[0]; - B = HashResultPointer[1]; - C = HashResultPointer[2]; - D = HashResultPointer[3]; - E = HashResultPointer[4]; - - do { - if (t < 20) { - TEMP = ((B & C) | ((~B) & D)) + 0x5A827999; - } else if (t < 40) { - TEMP = (B ^ C ^ D) + 0x6ED9EBA1; - } else if (t < 60) { - TEMP = ((B & C) | (B & D) | (C & D)) + 0x8F1BBCDC; - } else { - TEMP = (B ^ C ^ D) + 0xCA62C1D6; - } - TEMP += S(5, A) + E + HashWorkingPointer[t]; - E = D; - D = C; - C = S(30, B); - B = A; - A = TEMP; - } while (++t <= 79); - - HashResultPointer[0] += A; - HashResultPointer[1] += B; - HashResultPointer[2] += C; - HashResultPointer[3] += D; - HashResultPointer[4] += E; - -} - -/** - * lpfc_challenge_key - Create challenge key based on WWPN of the HBA - * @RandomChallenge: pointer to the entry of host challenge random number array. - * @HashWorking: pointer to the entry of the working hash array. - * - * This routine calculates the working hash array referred by @HashWorking - * from the challenge random numbers associated with the host, referred by - * @RandomChallenge. The result is put into the entry of the working hash - * array and returned by reference through @HashWorking. - **/ -static void -lpfc_challenge_key(uint32_t * RandomChallenge, uint32_t * HashWorking) -{ - *HashWorking = (*RandomChallenge ^ *HashWorking); -} - -/** - * lpfc_hba_init - Perform special handling for LC HBA initialization - * @phba: pointer to lpfc hba data structure. - * @hbainit: pointer to an array of unsigned 32-bit integers. - * - * This routine performs the special handling for LC HBA initialization. - **/ -void -lpfc_hba_init(struct lpfc_hba *phba, uint32_t *hbainit) -{ - int t; - uint32_t *HashWorking; - uint32_t *pwwnn = (uint32_t *) phba->wwnn; - - HashWorking = kcalloc(80, sizeof(uint32_t), GFP_KERNEL); - if (!HashWorking) - return; - - HashWorking[0] = HashWorking[78] = *pwwnn++; - HashWorking[1] = HashWorking[79] = *pwwnn; - - for (t = 0; t < 7; t++) - lpfc_challenge_key(phba->RandomData + t, HashWorking + t); - - lpfc_sha_init(hbainit); - lpfc_sha_iterate(hbainit, HashWorking); - kfree(HashWorking); -} - -/** - * lpfc_cleanup - Performs vport cleanups before deleting a vport - * @vport: pointer to a virtual N_Port data structure. - * - * This routine performs the necessary cleanups before deleting the @vport. - * It invokes the discovery state machine to perform necessary state - * transitions and to release the ndlps associated with the @vport. Note, - * the physical port is treated as @vport 0. - **/ -void -lpfc_cleanup(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_nodelist *ndlp, *next_ndlp; - int i = 0; - - if (phba->link_state > LPFC_LINK_DOWN) - lpfc_port_link_failure(vport); - - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - continue; - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - /* Trigger the release of the ndlp memory */ - lpfc_nlp_put(ndlp); - continue; - } - spin_lock_irq(&phba->ndlp_lock); - if (NLP_CHK_FREE_REQ(ndlp)) { - /* The ndlp should not be in memory free mode already */ - spin_unlock_irq(&phba->ndlp_lock); - continue; - } else - /* Indicate request for freeing ndlp memory */ - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - - if (vport->port_type != LPFC_PHYSICAL_PORT && - ndlp->nlp_DID == Fabric_DID) { - /* Just free up ndlp with Fabric_DID for vports */ - lpfc_nlp_put(ndlp); - continue; - } - - /* take care of nodes in unused state before the state - * machine taking action. - */ - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) { - lpfc_nlp_put(ndlp); - continue; - } - - if (ndlp->nlp_type & NLP_FABRIC) - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RM); - } - - /* At this point, ALL ndlp's should be gone - * because of the previous NLP_EVT_DEVICE_RM. - * Lets wait for this to happen, if needed. - */ - while (!list_empty(&vport->fc_nodes)) { - if (i++ > 3000) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0233 Nodelist not empty\n"); - list_for_each_entry_safe(ndlp, next_ndlp, - &vport->fc_nodes, nlp_listp) { - lpfc_printf_vlog(ndlp->vport, KERN_ERR, - LOG_NODE, - "0282 did:x%x ndlp:x%p " - "usgmap:x%x refcnt:%d\n", - ndlp->nlp_DID, (void *)ndlp, - ndlp->nlp_usg_map, - atomic_read( - &ndlp->kref.refcount)); - } - break; - } - - /* Wait for any activity on ndlps to settle */ - msleep(10); - } - lpfc_cleanup_vports_rrqs(vport, NULL); -} - -/** - * lpfc_stop_vport_timers - Stop all the timers associated with a vport - * @vport: pointer to a virtual N_Port data structure. - * - * This routine stops all the timers associated with a @vport. This function - * is invoked before disabling or deleting a @vport. Note that the physical - * port is treated as @vport 0. - **/ -void -lpfc_stop_vport_timers(struct lpfc_vport *vport) -{ - del_timer_sync(&vport->els_tmofunc); - del_timer_sync(&vport->fc_fdmitmo); - del_timer_sync(&vport->delayed_disc_tmo); - lpfc_can_disctmo(vport); - return; -} - -/** - * __lpfc_sli4_stop_fcf_redisc_wait_timer - Stop FCF rediscovery wait timer - * @phba: pointer to lpfc hba data structure. - * - * This routine stops the SLI4 FCF rediscover wait timer if it's on. The - * caller of this routine should already hold the host lock. - **/ -void -__lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba) -{ - /* Clear pending FCF rediscovery wait flag */ - phba->fcf.fcf_flag &= ~FCF_REDISC_PEND; - - /* Now, try to stop the timer */ - del_timer(&phba->fcf.redisc_wait); -} - -/** - * lpfc_sli4_stop_fcf_redisc_wait_timer - Stop FCF rediscovery wait timer - * @phba: pointer to lpfc hba data structure. - * - * This routine stops the SLI4 FCF rediscover wait timer if it's on. It - * checks whether the FCF rediscovery wait timer is pending with the host - * lock held before proceeding with disabling the timer and clearing the - * wait timer pendig flag. - **/ -void -lpfc_sli4_stop_fcf_redisc_wait_timer(struct lpfc_hba *phba) -{ - spin_lock_irq(&phba->hbalock); - if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND)) { - /* FCF rediscovery timer already fired or stopped */ - spin_unlock_irq(&phba->hbalock); - return; - } - __lpfc_sli4_stop_fcf_redisc_wait_timer(phba); - /* Clear failover in progress flags */ - phba->fcf.fcf_flag &= ~(FCF_DEAD_DISC | FCF_ACVL_DISC); - spin_unlock_irq(&phba->hbalock); -} - -/** - * lpfc_stop_hba_timers - Stop all the timers associated with an HBA - * @phba: pointer to lpfc hba data structure. - * - * This routine stops all the timers associated with a HBA. This function is - * invoked before either putting a HBA offline or unloading the driver. - **/ -void -lpfc_stop_hba_timers(struct lpfc_hba *phba) -{ - lpfc_stop_vport_timers(phba->pport); - del_timer_sync(&phba->sli.mbox_tmo); - del_timer_sync(&phba->fabric_block_timer); - del_timer_sync(&phba->eratt_poll); - del_timer_sync(&phba->hb_tmofunc); - if (phba->sli_rev == LPFC_SLI_REV4) { - del_timer_sync(&phba->rrq_tmr); - phba->hba_flag &= ~HBA_RRQ_ACTIVE; - } - phba->hb_outstanding = 0; - - switch (phba->pci_dev_grp) { - case LPFC_PCI_DEV_LP: - /* Stop any LightPulse device specific driver timers */ - del_timer_sync(&phba->fcp_poll_timer); - break; - case LPFC_PCI_DEV_OC: - /* Stop any OneConnect device sepcific driver timers */ - lpfc_sli4_stop_fcf_redisc_wait_timer(phba); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0297 Invalid device group (x%x)\n", - phba->pci_dev_grp); - break; - } - return; -} - -/** - * lpfc_block_mgmt_io - Mark a HBA's management interface as blocked - * @phba: pointer to lpfc hba data structure. - * - * This routine marks a HBA's management interface as blocked. Once the HBA's - * management interface is marked as blocked, all the user space access to - * the HBA, whether they are from sysfs interface or libdfc interface will - * all be blocked. The HBA is set to block the management interface when the - * driver prepares the HBA interface for online or offline. - **/ -static void -lpfc_block_mgmt_io(struct lpfc_hba * phba) -{ - unsigned long iflag; - uint8_t actcmd = MBX_HEARTBEAT; - unsigned long timeout; - - timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies; - spin_lock_irqsave(&phba->hbalock, iflag); - phba->sli.sli_flag |= LPFC_BLOCK_MGMT_IO; - if (phba->sli.mbox_active) { - actcmd = phba->sli.mbox_active->u.mb.mbxCommand; - /* Determine how long we might wait for the active mailbox - * command to be gracefully completed by firmware. - */ - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, - phba->sli.mbox_active) * 1000) + jiffies; - } - spin_unlock_irqrestore(&phba->hbalock, iflag); - - /* Wait for the outstnading mailbox command to complete */ - while (phba->sli.mbox_active) { - /* Check active mailbox complete status every 2ms */ - msleep(2); - if (time_after(jiffies, timeout)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2813 Mgmt IO is Blocked %x " - "- mbox cmd %x still active\n", - phba->sli.sli_flag, actcmd); - break; - } - } -} - -/** - * lpfc_sli4_node_prep - Assign RPIs for active nodes. - * @phba: pointer to lpfc hba data structure. - * - * Allocate RPIs for all active remote nodes. This is needed whenever - * an SLI4 adapter is reset and the driver is not unloading. Its purpose - * is to fixup the temporary rpi assignments. - **/ -void -lpfc_sli4_node_prep(struct lpfc_hba *phba) -{ - struct lpfc_nodelist *ndlp, *next_ndlp; - struct lpfc_vport **vports; - int i; - - if (phba->sli_rev != LPFC_SLI_REV4) - return; - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) { - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - if (vports[i]->load_flag & FC_UNLOADING) - continue; - - list_for_each_entry_safe(ndlp, next_ndlp, - &vports[i]->fc_nodes, - nlp_listp) { - if (NLP_CHK_NODE_ACT(ndlp)) - ndlp->nlp_rpi = - lpfc_sli4_alloc_rpi(phba); - } - } - } - lpfc_destroy_vport_work_array(phba, vports); -} - -/** - * lpfc_online - Initialize and bring a HBA online - * @phba: pointer to lpfc hba data structure. - * - * This routine initializes the HBA and brings a HBA online. During this - * process, the management interface is blocked to prevent user space access - * to the HBA interfering with the driver initialization. - * - * Return codes - * 0 - successful - * 1 - failed - **/ -int -lpfc_online(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport; - struct lpfc_vport **vports; - int i; - - if (!phba) - return 0; - vport = phba->pport; - - if (!(vport->fc_flag & FC_OFFLINE_MODE)) - return 0; - - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0458 Bring Adapter online\n"); - - lpfc_block_mgmt_io(phba); - - if (!lpfc_sli_queue_setup(phba)) { - lpfc_unblock_mgmt_io(phba); - return 1; - } - - if (phba->sli_rev == LPFC_SLI_REV4) { - if (lpfc_sli4_hba_setup(phba)) { /* Initialize SLI4 HBA */ - lpfc_unblock_mgmt_io(phba); - return 1; - } - } else { - if (lpfc_sli_hba_setup(phba)) { /* Initialize SLI2/SLI3 HBA */ - lpfc_unblock_mgmt_io(phba); - return 1; - } - } - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - struct Scsi_Host *shost; - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - vports[i]->fc_flag &= ~FC_OFFLINE_MODE; - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) - vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - if (phba->sli_rev == LPFC_SLI_REV4) - vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); - - lpfc_unblock_mgmt_io(phba); - return 0; -} - -/** - * lpfc_unblock_mgmt_io - Mark a HBA's management interface to be not blocked - * @phba: pointer to lpfc hba data structure. - * - * This routine marks a HBA's management interface as not blocked. Once the - * HBA's management interface is marked as not blocked, all the user space - * access to the HBA, whether they are from sysfs interface or libdfc - * interface will be allowed. The HBA is set to block the management interface - * when the driver prepares the HBA interface for online or offline and then - * set to unblock the management interface afterwards. - **/ -void -lpfc_unblock_mgmt_io(struct lpfc_hba * phba) -{ - unsigned long iflag; - - spin_lock_irqsave(&phba->hbalock, iflag); - phba->sli.sli_flag &= ~LPFC_BLOCK_MGMT_IO; - spin_unlock_irqrestore(&phba->hbalock, iflag); -} - -/** - * lpfc_offline_prep - Prepare a HBA to be brought offline - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to prepare a HBA to be brought offline. It performs - * unregistration login to all the nodes on all vports and flushes the mailbox - * queue to make it ready to be brought offline. - **/ -void -lpfc_offline_prep(struct lpfc_hba * phba) -{ - struct lpfc_vport *vport = phba->pport; - struct lpfc_nodelist *ndlp, *next_ndlp; - struct lpfc_vport **vports; - struct Scsi_Host *shost; - int i; - - if (vport->fc_flag & FC_OFFLINE_MODE) - return; - - lpfc_block_mgmt_io(phba); - - lpfc_linkdown(phba); - - /* Issue an unreg_login to all nodes on all vports */ - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) { - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - if (vports[i]->load_flag & FC_UNLOADING) - continue; - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED; - vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - vports[i]->fc_flag &= ~FC_VFI_REGISTERED; - spin_unlock_irq(shost->host_lock); - - shost = lpfc_shost_from_vport(vports[i]); - list_for_each_entry_safe(ndlp, next_ndlp, - &vports[i]->fc_nodes, - nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - continue; - if (ndlp->nlp_type & NLP_FABRIC) { - lpfc_disc_state_machine(vports[i], ndlp, - NULL, NLP_EVT_DEVICE_RECOVERY); - lpfc_disc_state_machine(vports[i], ndlp, - NULL, NLP_EVT_DEVICE_RM); - } - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - /* - * Whenever an SLI4 port goes offline, free the - * RPI. Get a new RPI when the adapter port - * comes back online. - */ - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); - lpfc_unreg_rpi(vports[i], ndlp); - } - } - } - lpfc_destroy_vport_work_array(phba, vports); - - lpfc_sli_mbox_sys_shutdown(phba); -} - -/** - * lpfc_offline - Bring a HBA offline - * @phba: pointer to lpfc hba data structure. - * - * This routine actually brings a HBA offline. It stops all the timers - * associated with the HBA, brings down the SLI layer, and eventually - * marks the HBA as in offline state for the upper layer protocol. - **/ -void -lpfc_offline(struct lpfc_hba *phba) -{ - struct Scsi_Host *shost; - struct lpfc_vport **vports; - int i; - - if (phba->pport->fc_flag & FC_OFFLINE_MODE) - return; - - /* stop port and all timers associated with this hba */ - lpfc_stop_port(phba); - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) - lpfc_stop_vport_timers(vports[i]); - lpfc_destroy_vport_work_array(phba, vports); - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0460 Bring Adapter offline\n"); - /* Bring down the SLI Layer and cleanup. The HBA is offline - now. */ - lpfc_sli_hba_down(phba); - spin_lock_irq(&phba->hbalock); - phba->work_ha = 0; - spin_unlock_irq(&phba->hbalock); - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - spin_lock_irq(shost->host_lock); - vports[i]->work_port_events = 0; - vports[i]->fc_flag |= FC_OFFLINE_MODE; - spin_unlock_irq(shost->host_lock); - } - lpfc_destroy_vport_work_array(phba, vports); -} - -/** - * lpfc_scsi_buf_update - Update the scsi_buffers that are already allocated. - * @phba: pointer to lpfc hba data structure. - * - * This routine goes through all the scsi buffers in the system and updates the - * Physical XRIs assigned to the SCSI buffer because these may change after any - * firmware reset - * - * Return codes - * 0 - successful (for now, it always returns 0) - **/ -int -lpfc_scsi_buf_update(struct lpfc_hba *phba) -{ - struct lpfc_scsi_buf *sb, *sb_next; - - spin_lock_irq(&phba->hbalock); - spin_lock(&phba->scsi_buf_list_lock); - list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { - sb->cur_iocbq.sli4_xritag = - phba->sli4_hba.xri_ids[sb->cur_iocbq.sli4_lxritag]; - set_bit(sb->cur_iocbq.sli4_lxritag, phba->sli4_hba.xri_bmask); - phba->sli4_hba.max_cfg_param.xri_used++; - phba->sli4_hba.xri_count++; - } - spin_unlock(&phba->scsi_buf_list_lock); - spin_unlock_irq(&phba->hbalock); - return 0; -} - -/** - * lpfc_scsi_free - Free all the SCSI buffers and IOCBs from driver lists - * @phba: pointer to lpfc hba data structure. - * - * This routine is to free all the SCSI buffers and IOCBs from the driver - * list back to kernel. It is called from lpfc_pci_remove_one to free - * the internal resources before the device is removed from the system. - * - * Return codes - * 0 - successful (for now, it always returns 0) - **/ -static int -lpfc_scsi_free(struct lpfc_hba *phba) -{ - struct lpfc_scsi_buf *sb, *sb_next; - struct lpfc_iocbq *io, *io_next; - - spin_lock_irq(&phba->hbalock); - /* Release all the lpfc_scsi_bufs maintained by this host. */ - spin_lock(&phba->scsi_buf_list_lock); - list_for_each_entry_safe(sb, sb_next, &phba->lpfc_scsi_buf_list, list) { - list_del(&sb->list); - pci_pool_free(phba->lpfc_scsi_dma_buf_pool, sb->data, - sb->dma_handle); - kfree(sb); - phba->total_scsi_bufs--; - } - spin_unlock(&phba->scsi_buf_list_lock); - - /* Release all the lpfc_iocbq entries maintained by this host. */ - list_for_each_entry_safe(io, io_next, &phba->lpfc_iocb_list, list) { - list_del(&io->list); - kfree(io); - phba->total_iocbq_bufs--; - } - - spin_unlock_irq(&phba->hbalock); - return 0; -} - -/** - * lpfc_create_port - Create an FC port - * @phba: pointer to lpfc hba data structure. - * @instance: a unique integer ID to this FC port. - * @dev: pointer to the device data structure. - * - * This routine creates a FC port for the upper layer protocol. The FC port - * can be created on top of either a physical port or a virtual port provided - * by the HBA. This routine also allocates a SCSI host data structure (shost) - * and associates the FC port created before adding the shost into the SCSI - * layer. - * - * Return codes - * @vport - pointer to the virtual N_Port data structure. - * NULL - port create failed. - **/ -struct lpfc_vport * -lpfc_create_port(struct lpfc_hba *phba, int instance, struct device *dev) -{ - struct lpfc_vport *vport; - struct Scsi_Host *shost; - int error = 0; - - if (dev != &phba->pcidev->dev) - shost = scsi_host_alloc(&lpfc_vport_template, - sizeof(struct lpfc_vport)); - else - shost = scsi_host_alloc(&lpfc_template, - sizeof(struct lpfc_vport)); - if (!shost) - goto out; - - vport = (struct lpfc_vport *) shost->hostdata; - vport->phba = phba; - vport->load_flag |= FC_LOADING; - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - vport->fc_rscn_flush = 0; - - lpfc_get_vport_cfgparam(vport); - shost->unique_id = instance; - shost->max_id = LPFC_MAX_TARGET; - shost->max_lun = vport->cfg_max_luns; - shost->this_id = -1; - shost->max_cmd_len = 16; - if (phba->sli_rev == LPFC_SLI_REV4) { - shost->dma_boundary = - phba->sli4_hba.pc_sli4_params.sge_supp_len-1; - shost->sg_tablesize = phba->cfg_sg_seg_cnt; - } - - /* - * Set initial can_queue value since 0 is no longer supported and - * scsi_add_host will fail. This will be adjusted later based on the - * max xri value determined in hba setup. - */ - shost->can_queue = phba->cfg_hba_queue_depth - 10; - if (dev != &phba->pcidev->dev) { - shost->transportt = lpfc_vport_transport_template; - vport->port_type = LPFC_NPIV_PORT; - } else { - shost->transportt = lpfc_transport_template; - vport->port_type = LPFC_PHYSICAL_PORT; - } - - /* Initialize all internally managed lists. */ - INIT_LIST_HEAD(&vport->fc_nodes); - INIT_LIST_HEAD(&vport->rcv_buffer_list); - spin_lock_init(&vport->work_port_lock); - - init_timer(&vport->fc_disctmo); - vport->fc_disctmo.function = lpfc_disc_timeout; - vport->fc_disctmo.data = (unsigned long)vport; - - init_timer(&vport->fc_fdmitmo); - vport->fc_fdmitmo.function = lpfc_fdmi_tmo; - vport->fc_fdmitmo.data = (unsigned long)vport; - - init_timer(&vport->els_tmofunc); - vport->els_tmofunc.function = lpfc_els_timeout; - vport->els_tmofunc.data = (unsigned long)vport; - - init_timer(&vport->delayed_disc_tmo); - vport->delayed_disc_tmo.function = lpfc_delayed_disc_tmo; - vport->delayed_disc_tmo.data = (unsigned long)vport; - - error = scsi_add_host_with_dma(shost, dev, &phba->pcidev->dev); - if (error) - goto out_put_shost; - - spin_lock_irq(&phba->hbalock); - list_add_tail(&vport->listentry, &phba->port_list); - spin_unlock_irq(&phba->hbalock); - return vport; - -out_put_shost: - scsi_host_put(shost); -out: - return NULL; -} - -/** - * destroy_port - destroy an FC port - * @vport: pointer to an lpfc virtual N_Port data structure. - * - * This routine destroys a FC port from the upper layer protocol. All the - * resources associated with the port are released. - **/ -void -destroy_port(struct lpfc_vport *vport) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - - lpfc_debugfs_terminate(vport); - fc_remove_host(shost); - scsi_remove_host(shost); - - spin_lock_irq(&phba->hbalock); - list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); - - lpfc_cleanup(vport); - return; -} - -/** - * lpfc_get_instance - Get a unique integer ID - * - * This routine allocates a unique integer ID from lpfc_hba_index pool. It - * uses the kernel idr facility to perform the task. - * - * Return codes: - * instance - a unique integer ID allocated as the new instance. - * -1 - lpfc get instance failed. - **/ -int -lpfc_get_instance(void) -{ - int instance = 0; - - /* Assign an unused number */ - if (!idr_pre_get(&lpfc_hba_index, GFP_KERNEL)) - return -1; - if (idr_get_new(&lpfc_hba_index, NULL, &instance)) - return -1; - return instance; -} - -/** - * lpfc_scan_finished - method for SCSI layer to detect whether scan is done - * @shost: pointer to SCSI host data structure. - * @time: elapsed time of the scan in jiffies. - * - * This routine is called by the SCSI layer with a SCSI host to determine - * whether the scan host is finished. - * - * Note: there is no scan_start function as adapter initialization will have - * asynchronously kicked off the link initialization. - * - * Return codes - * 0 - SCSI host scan is not over yet. - * 1 - SCSI host scan is over. - **/ -int lpfc_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - int stat = 0; - - spin_lock_irq(shost->host_lock); - - if (vport->load_flag & FC_UNLOADING) { - stat = 1; - goto finished; - } - if (time >= 30 * HZ) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0461 Scanning longer than 30 " - "seconds. Continuing initialization\n"); - stat = 1; - goto finished; - } - if (time >= 15 * HZ && phba->link_state <= LPFC_LINK_DOWN) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0465 Link down longer than 15 " - "seconds. Continuing initialization\n"); - stat = 1; - goto finished; - } - - if (vport->port_state != LPFC_VPORT_READY) - goto finished; - if (vport->num_disc_nodes || vport->fc_prli_sent) - goto finished; - if (vport->fc_map_cnt == 0 && time < 2 * HZ) - goto finished; - if ((phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) != 0) - goto finished; - - stat = 1; - -finished: - spin_unlock_irq(shost->host_lock); - return stat; -} - -/** - * lpfc_host_attrib_init - Initialize SCSI host attributes on a FC port - * @shost: pointer to SCSI host data structure. - * - * This routine initializes a given SCSI host attributes on a FC port. The - * SCSI host can be either on top of a physical port or a virtual port. - **/ -void lpfc_host_attrib_init(struct Scsi_Host *shost) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - /* - * Set fixed host attributes. Must done after lpfc_sli_hba_setup(). - */ - - fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); - fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); - fc_host_supported_classes(shost) = FC_COS_CLASS3; - - memset(fc_host_supported_fc4s(shost), 0, - sizeof(fc_host_supported_fc4s(shost))); - fc_host_supported_fc4s(shost)[2] = 1; - fc_host_supported_fc4s(shost)[7] = 1; - - lpfc_vport_symbolic_node_name(vport, fc_host_symbolic_name(shost), - sizeof fc_host_symbolic_name(shost)); - - fc_host_supported_speeds(shost) = 0; - if (phba->lmt & LMT_16Gb) - fc_host_supported_speeds(shost) |= FC_PORTSPEED_16GBIT; - if (phba->lmt & LMT_10Gb) - fc_host_supported_speeds(shost) |= FC_PORTSPEED_10GBIT; - if (phba->lmt & LMT_8Gb) - fc_host_supported_speeds(shost) |= FC_PORTSPEED_8GBIT; - if (phba->lmt & LMT_4Gb) - fc_host_supported_speeds(shost) |= FC_PORTSPEED_4GBIT; - if (phba->lmt & LMT_2Gb) - fc_host_supported_speeds(shost) |= FC_PORTSPEED_2GBIT; - if (phba->lmt & LMT_1Gb) - fc_host_supported_speeds(shost) |= FC_PORTSPEED_1GBIT; - - fc_host_maxframe_size(shost) = - (((uint32_t) vport->fc_sparam.cmn.bbRcvSizeMsb & 0x0F) << 8) | - (uint32_t) vport->fc_sparam.cmn.bbRcvSizeLsb; - - fc_host_dev_loss_tmo(shost) = vport->cfg_devloss_tmo; - - /* This value is also unchanging */ - memset(fc_host_active_fc4s(shost), 0, - sizeof(fc_host_active_fc4s(shost))); - fc_host_active_fc4s(shost)[2] = 1; - fc_host_active_fc4s(shost)[7] = 1; - - fc_host_max_npiv_vports(shost) = phba->max_vpi; - spin_lock_irq(shost->host_lock); - vport->load_flag &= ~FC_LOADING; - spin_unlock_irq(shost->host_lock); -} - -/** - * lpfc_stop_port_s3 - Stop SLI3 device port - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to stop an SLI3 device port, it stops the device - * from generating interrupts and stops the device driver's timers for the - * device. - **/ -static void -lpfc_stop_port_s3(struct lpfc_hba *phba) -{ - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - /* Clear all pending interrupts */ - writel(0xffffffff, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - - /* Reset some HBA SLI setup states */ - lpfc_stop_hba_timers(phba); - phba->pport->work_port_events = 0; -} - -/** - * lpfc_stop_port_s4 - Stop SLI4 device port - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to stop an SLI4 device port, it stops the device - * from generating interrupts and stops the device driver's timers for the - * device. - **/ -static void -lpfc_stop_port_s4(struct lpfc_hba *phba) -{ - /* Reset some HBA SLI4 setup states */ - lpfc_stop_hba_timers(phba); - phba->pport->work_port_events = 0; - phba->sli4_hba.intr_enable = 0; -} - -/** - * lpfc_stop_port - Wrapper function for stopping hba port - * @phba: Pointer to HBA context object. - * - * This routine wraps the actual SLI3 or SLI4 hba stop port routine from - * the API jump table function pointer from the lpfc_hba struct. - **/ -void -lpfc_stop_port(struct lpfc_hba *phba) -{ - phba->lpfc_stop_port(phba); -} - -/** - * lpfc_fcf_redisc_wait_start_timer - Start fcf rediscover wait timer - * @phba: Pointer to hba for which this call is being executed. - * - * This routine starts the timer waiting for the FCF rediscovery to complete. - **/ -void -lpfc_fcf_redisc_wait_start_timer(struct lpfc_hba *phba) -{ - unsigned long fcf_redisc_wait_tmo = - (jiffies + msecs_to_jiffies(LPFC_FCF_REDISCOVER_WAIT_TMO)); - /* Start fcf rediscovery wait period timer */ - mod_timer(&phba->fcf.redisc_wait, fcf_redisc_wait_tmo); - spin_lock_irq(&phba->hbalock); - /* Allow action to new fcf asynchronous event */ - phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE); - /* Mark the FCF rediscovery pending state */ - phba->fcf.fcf_flag |= FCF_REDISC_PEND; - spin_unlock_irq(&phba->hbalock); -} - -/** - * lpfc_sli4_fcf_redisc_wait_tmo - FCF table rediscover wait timeout - * @ptr: Map to lpfc_hba data structure pointer. - * - * This routine is invoked when waiting for FCF table rediscover has been - * timed out. If new FCF record(s) has (have) been discovered during the - * wait period, a new FCF event shall be added to the FCOE async event - * list, and then worker thread shall be waked up for processing from the - * worker thread context. - **/ -void -lpfc_sli4_fcf_redisc_wait_tmo(unsigned long ptr) -{ - struct lpfc_hba *phba = (struct lpfc_hba *)ptr; - - /* Don't send FCF rediscovery event if timer cancelled */ - spin_lock_irq(&phba->hbalock); - if (!(phba->fcf.fcf_flag & FCF_REDISC_PEND)) { - spin_unlock_irq(&phba->hbalock); - return; - } - /* Clear FCF rediscovery timer pending flag */ - phba->fcf.fcf_flag &= ~FCF_REDISC_PEND; - /* FCF rediscovery event to worker thread */ - phba->fcf.fcf_flag |= FCF_REDISC_EVT; - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2776 FCF rediscover quiescent timer expired\n"); - /* wake up worker thread */ - lpfc_worker_wake_up(phba); -} - -/** - * lpfc_sli4_parse_latt_fault - Parse sli4 link-attention link fault code - * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async link completion queue entry. - * - * This routine is to parse the SLI4 link-attention link fault code and - * translate it into the base driver's read link attention mailbox command - * status. - * - * Return: Link-attention status in terms of base driver's coding. - **/ -static uint16_t -lpfc_sli4_parse_latt_fault(struct lpfc_hba *phba, - struct lpfc_acqe_link *acqe_link) -{ - uint16_t latt_fault; - - switch (bf_get(lpfc_acqe_link_fault, acqe_link)) { - case LPFC_ASYNC_LINK_FAULT_NONE: - case LPFC_ASYNC_LINK_FAULT_LOCAL: - case LPFC_ASYNC_LINK_FAULT_REMOTE: - latt_fault = 0; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0398 Invalid link fault code: x%x\n", - bf_get(lpfc_acqe_link_fault, acqe_link)); - latt_fault = MBXERR_ERROR; - break; - } - return latt_fault; -} - -/** - * lpfc_sli4_parse_latt_type - Parse sli4 link attention type - * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async link completion queue entry. - * - * This routine is to parse the SLI4 link attention type and translate it - * into the base driver's link attention type coding. - * - * Return: Link attention type in terms of base driver's coding. - **/ -static uint8_t -lpfc_sli4_parse_latt_type(struct lpfc_hba *phba, - struct lpfc_acqe_link *acqe_link) -{ - uint8_t att_type; - - switch (bf_get(lpfc_acqe_link_status, acqe_link)) { - case LPFC_ASYNC_LINK_STATUS_DOWN: - case LPFC_ASYNC_LINK_STATUS_LOGICAL_DOWN: - att_type = LPFC_ATT_LINK_DOWN; - break; - case LPFC_ASYNC_LINK_STATUS_UP: - /* Ignore physical link up events - wait for logical link up */ - att_type = LPFC_ATT_RESERVED; - break; - case LPFC_ASYNC_LINK_STATUS_LOGICAL_UP: - att_type = LPFC_ATT_LINK_UP; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0399 Invalid link attention type: x%x\n", - bf_get(lpfc_acqe_link_status, acqe_link)); - att_type = LPFC_ATT_RESERVED; - break; - } - return att_type; -} - -/** - * lpfc_sli4_parse_latt_link_speed - Parse sli4 link-attention link speed - * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async link completion queue entry. - * - * This routine is to parse the SLI4 link-attention link speed and translate - * it into the base driver's link-attention link speed coding. - * - * Return: Link-attention link speed in terms of base driver's coding. - **/ -static uint8_t -lpfc_sli4_parse_latt_link_speed(struct lpfc_hba *phba, - struct lpfc_acqe_link *acqe_link) -{ - uint8_t link_speed; - - switch (bf_get(lpfc_acqe_link_speed, acqe_link)) { - case LPFC_ASYNC_LINK_SPEED_ZERO: - case LPFC_ASYNC_LINK_SPEED_10MBPS: - case LPFC_ASYNC_LINK_SPEED_100MBPS: - link_speed = LPFC_LINK_SPEED_UNKNOWN; - break; - case LPFC_ASYNC_LINK_SPEED_1GBPS: - link_speed = LPFC_LINK_SPEED_1GHZ; - break; - case LPFC_ASYNC_LINK_SPEED_10GBPS: - link_speed = LPFC_LINK_SPEED_10GHZ; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0483 Invalid link-attention link speed: x%x\n", - bf_get(lpfc_acqe_link_speed, acqe_link)); - link_speed = LPFC_LINK_SPEED_UNKNOWN; - break; - } - return link_speed; -} - -/** - * lpfc_sli4_async_link_evt - Process the asynchronous FCoE link event - * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async link completion queue entry. - * - * This routine is to handle the SLI4 asynchronous FCoE link event. - **/ -static void -lpfc_sli4_async_link_evt(struct lpfc_hba *phba, - struct lpfc_acqe_link *acqe_link) -{ - struct lpfc_dmabuf *mp; - LPFC_MBOXQ_t *pmb; - MAILBOX_t *mb; - struct lpfc_mbx_read_top *la; - uint8_t att_type; - int rc; - - att_type = lpfc_sli4_parse_latt_type(phba, acqe_link); - if (att_type != LPFC_ATT_LINK_DOWN && att_type != LPFC_ATT_LINK_UP) - return; - phba->fcoe_eventtag = acqe_link->event_tag; - pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0395 The mboxq allocation failed\n"); - return; - } - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0396 The lpfc_dmabuf allocation failed\n"); - goto out_free_pmb; - } - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp->virt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0397 The mbuf allocation failed\n"); - goto out_free_dmabuf; - } - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_all_cmd(phba); - - /* Block ELS IOCBs until we have done process link event */ - phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT; - - /* Update link event statistics */ - phba->sli.slistat.link_event++; - - /* Create lpfc_handle_latt mailbox command from link ACQE */ - lpfc_read_topology(phba, pmb, mp); - pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology; - pmb->vport = phba->pport; - - /* Keep the link status for extra SLI4 state machine reference */ - phba->sli4_hba.link_state.speed = - bf_get(lpfc_acqe_link_speed, acqe_link); - phba->sli4_hba.link_state.duplex = - bf_get(lpfc_acqe_link_duplex, acqe_link); - phba->sli4_hba.link_state.status = - bf_get(lpfc_acqe_link_status, acqe_link); - phba->sli4_hba.link_state.type = - bf_get(lpfc_acqe_link_type, acqe_link); - phba->sli4_hba.link_state.number = - bf_get(lpfc_acqe_link_number, acqe_link); - phba->sli4_hba.link_state.fault = - bf_get(lpfc_acqe_link_fault, acqe_link); - phba->sli4_hba.link_state.logical_speed = - bf_get(lpfc_acqe_logical_link_speed, acqe_link); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2900 Async FC/FCoE Link event - Speed:%dGBit " - "duplex:x%x LA Type:x%x Port Type:%d Port Number:%d " - "Logical speed:%dMbps Fault:%d\n", - phba->sli4_hba.link_state.speed, - phba->sli4_hba.link_state.topology, - phba->sli4_hba.link_state.status, - phba->sli4_hba.link_state.type, - phba->sli4_hba.link_state.number, - phba->sli4_hba.link_state.logical_speed * 10, - phba->sli4_hba.link_state.fault); - /* - * For FC Mode: issue the READ_TOPOLOGY mailbox command to fetch - * topology info. Note: Optional for non FC-AL ports. - */ - if (!(phba->hba_flag & HBA_FCOE_MODE)) { - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - goto out_free_dmabuf; - return; - } - /* - * For FCoE Mode: fill in all the topology information we need and call - * the READ_TOPOLOGY completion routine to continue without actually - * sending the READ_TOPOLOGY mailbox command to the port. - */ - /* Parse and translate status field */ - mb = &pmb->u.mb; - mb->mbxStatus = lpfc_sli4_parse_latt_fault(phba, acqe_link); - - /* Parse and translate link attention fields */ - la = (struct lpfc_mbx_read_top *) &pmb->u.mb.un.varReadTop; - la->eventTag = acqe_link->event_tag; - bf_set(lpfc_mbx_read_top_att_type, la, att_type); - bf_set(lpfc_mbx_read_top_link_spd, la, - lpfc_sli4_parse_latt_link_speed(phba, acqe_link)); - - /* Fake the the following irrelvant fields */ - bf_set(lpfc_mbx_read_top_topology, la, LPFC_TOPOLOGY_PT_PT); - bf_set(lpfc_mbx_read_top_alpa_granted, la, 0); - bf_set(lpfc_mbx_read_top_il, la, 0); - bf_set(lpfc_mbx_read_top_pb, la, 0); - bf_set(lpfc_mbx_read_top_fa, la, 0); - bf_set(lpfc_mbx_read_top_mm, la, 0); - - /* Invoke the lpfc_handle_latt mailbox command callback function */ - lpfc_mbx_cmpl_read_topology(phba, pmb); - - return; - -out_free_dmabuf: - kfree(mp); -out_free_pmb: - mempool_free(pmb, phba->mbox_mem_pool); -} - -/** - * lpfc_sli4_async_fc_evt - Process the asynchronous FC link event - * @phba: pointer to lpfc hba data structure. - * @acqe_fc: pointer to the async fc completion queue entry. - * - * This routine is to handle the SLI4 asynchronous FC event. It will simply log - * that the event was received and then issue a read_topology mailbox command so - * that the rest of the driver will treat it the same as SLI3. - **/ -static void -lpfc_sli4_async_fc_evt(struct lpfc_hba *phba, struct lpfc_acqe_fc_la *acqe_fc) -{ - struct lpfc_dmabuf *mp; - LPFC_MBOXQ_t *pmb; - int rc; - - if (bf_get(lpfc_trailer_type, acqe_fc) != - LPFC_FC_LA_EVENT_TYPE_FC_LINK) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2895 Non FC link Event detected.(%d)\n", - bf_get(lpfc_trailer_type, acqe_fc)); - return; - } - /* Keep the link status for extra SLI4 state machine reference */ - phba->sli4_hba.link_state.speed = - bf_get(lpfc_acqe_fc_la_speed, acqe_fc); - phba->sli4_hba.link_state.duplex = LPFC_ASYNC_LINK_DUPLEX_FULL; - phba->sli4_hba.link_state.topology = - bf_get(lpfc_acqe_fc_la_topology, acqe_fc); - phba->sli4_hba.link_state.status = - bf_get(lpfc_acqe_fc_la_att_type, acqe_fc); - phba->sli4_hba.link_state.type = - bf_get(lpfc_acqe_fc_la_port_type, acqe_fc); - phba->sli4_hba.link_state.number = - bf_get(lpfc_acqe_fc_la_port_number, acqe_fc); - phba->sli4_hba.link_state.fault = - bf_get(lpfc_acqe_link_fault, acqe_fc); - phba->sli4_hba.link_state.logical_speed = - bf_get(lpfc_acqe_fc_la_llink_spd, acqe_fc); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2896 Async FC event - Speed:%dGBaud Topology:x%x " - "LA Type:x%x Port Type:%d Port Number:%d Logical speed:" - "%dMbps Fault:%d\n", - phba->sli4_hba.link_state.speed, - phba->sli4_hba.link_state.topology, - phba->sli4_hba.link_state.status, - phba->sli4_hba.link_state.type, - phba->sli4_hba.link_state.number, - phba->sli4_hba.link_state.logical_speed * 10, - phba->sli4_hba.link_state.fault); - pmb = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2897 The mboxq allocation failed\n"); - return; - } - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!mp) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2898 The lpfc_dmabuf allocation failed\n"); - goto out_free_pmb; - } - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp->virt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2899 The mbuf allocation failed\n"); - goto out_free_dmabuf; - } - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_all_cmd(phba); - - /* Block ELS IOCBs until we have done process link event */ - phba->sli.ring[LPFC_ELS_RING].flag |= LPFC_STOP_IOCB_EVENT; - - /* Update link event statistics */ - phba->sli.slistat.link_event++; - - /* Create lpfc_handle_latt mailbox command from link ACQE */ - lpfc_read_topology(phba, pmb, mp); - pmb->mbox_cmpl = lpfc_mbx_cmpl_read_topology; - pmb->vport = phba->pport; - - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - goto out_free_dmabuf; - return; - -out_free_dmabuf: - kfree(mp); -out_free_pmb: - mempool_free(pmb, phba->mbox_mem_pool); -} - -/** - * lpfc_sli4_async_sli_evt - Process the asynchronous SLI link event - * @phba: pointer to lpfc hba data structure. - * @acqe_fc: pointer to the async SLI completion queue entry. - * - * This routine is to handle the SLI4 asynchronous SLI events. - **/ -static void -lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) -{ - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2901 Async SLI event - Event Data1:x%08x Event Data2:" - "x%08x SLI Event Type:%d", - acqe_sli->event_data1, acqe_sli->event_data2, - bf_get(lpfc_trailer_type, acqe_sli)); - return; -} - -/** - * lpfc_sli4_perform_vport_cvl - Perform clear virtual link on a vport - * @vport: pointer to vport data structure. - * - * This routine is to perform Clear Virtual Link (CVL) on a vport in - * response to a CVL event. - * - * Return the pointer to the ndlp with the vport if successful, otherwise - * return NULL. - **/ -static struct lpfc_nodelist * -lpfc_sli4_perform_vport_cvl(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; - struct lpfc_hba *phba; - - if (!vport) - return NULL; - phba = vport->phba; - if (!phba) - return NULL; - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) { - /* Cannot find existing Fabric ndlp, so allocate a new one */ - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - return 0; - lpfc_nlp_init(vport, ndlp, Fabric_DID); - /* Set the node type */ - ndlp->nlp_type |= NLP_FABRIC; - /* Put ndlp onto node list */ - lpfc_enqueue_node(vport, ndlp); - } else if (!NLP_CHK_NODE_ACT(ndlp)) { - /* re-setup ndlp without removing from node list */ - ndlp = lpfc_enable_node(vport, ndlp, NLP_STE_UNUSED_NODE); - if (!ndlp) - return 0; - } - if ((phba->pport->port_state < LPFC_FLOGI) && - (phba->pport->port_state != LPFC_VPORT_FAILED)) - return NULL; - /* If virtual link is not yet instantiated ignore CVL */ - if ((vport != phba->pport) && (vport->port_state < LPFC_FDISC) - && (vport->port_state != LPFC_VPORT_FAILED)) - return NULL; - shost = lpfc_shost_from_vport(vport); - if (!shost) - return NULL; - lpfc_linkdown_port(vport); - lpfc_cleanup_pending_mbox(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_CVL_RCVD; - spin_unlock_irq(shost->host_lock); - - return ndlp; -} - -/** - * lpfc_sli4_perform_all_vport_cvl - Perform clear virtual link on all vports - * @vport: pointer to lpfc hba data structure. - * - * This routine is to perform Clear Virtual Link (CVL) on all vports in - * response to a FCF dead event. - **/ -static void -lpfc_sli4_perform_all_vport_cvl(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - int i; - - vports = lpfc_create_vport_work_array(phba); - if (vports) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) - lpfc_sli4_perform_vport_cvl(vports[i]); - lpfc_destroy_vport_work_array(phba, vports); -} - -/** - * lpfc_sli4_async_fip_evt - Process the asynchronous FCoE FIP event - * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async fcoe completion queue entry. - * - * This routine is to handle the SLI4 asynchronous fcoe event. - **/ -static void -lpfc_sli4_async_fip_evt(struct lpfc_hba *phba, - struct lpfc_acqe_fip *acqe_fip) -{ - uint8_t event_type = bf_get(lpfc_trailer_type, acqe_fip); - int rc; - struct lpfc_vport *vport; - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; - int active_vlink_present; - struct lpfc_vport **vports; - int i; - - phba->fc_eventTag = acqe_fip->event_tag; - phba->fcoe_eventtag = acqe_fip->event_tag; - switch (event_type) { - case LPFC_FIP_EVENT_TYPE_NEW_FCF: - case LPFC_FIP_EVENT_TYPE_FCF_PARAM_MOD: - if (event_type == LPFC_FIP_EVENT_TYPE_NEW_FCF) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, - "2546 New FCF event, evt_tag:x%x, " - "index:x%x\n", - acqe_fip->event_tag, - acqe_fip->index); - else - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP | - LOG_DISCOVERY, - "2788 FCF param modified event, " - "evt_tag:x%x, index:x%x\n", - acqe_fip->event_tag, - acqe_fip->index); - if (phba->fcf.fcf_flag & FCF_DISCOVERY) { - /* - * During period of FCF discovery, read the FCF - * table record indexed by the event to update - * FCF roundrobin failover eligible FCF bmask. - */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | - LOG_DISCOVERY, - "2779 Read FCF (x%x) for updating " - "roundrobin FCF failover bmask\n", - acqe_fip->index); - rc = lpfc_sli4_read_fcf_rec(phba, acqe_fip->index); - } - - /* If the FCF discovery is in progress, do nothing. */ - spin_lock_irq(&phba->hbalock); - if (phba->hba_flag & FCF_TS_INPROG) { - spin_unlock_irq(&phba->hbalock); - break; - } - /* If fast FCF failover rescan event is pending, do nothing */ - if (phba->fcf.fcf_flag & FCF_REDISC_EVT) { - spin_unlock_irq(&phba->hbalock); - break; - } - - /* If the FCF has been in discovered state, do nothing. */ - if (phba->fcf.fcf_flag & FCF_SCAN_DONE) { - spin_unlock_irq(&phba->hbalock); - break; - } - spin_unlock_irq(&phba->hbalock); - - /* Otherwise, scan the entire FCF table and re-discover SAN */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, - "2770 Start FCF table scan per async FCF " - "event, evt_tag:x%x, index:x%x\n", - acqe_fip->event_tag, acqe_fip->index); - rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, - LPFC_FCOE_FCF_GET_FIRST); - if (rc) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, - "2547 Issue FCF scan read FCF mailbox " - "command failed (x%x)\n", rc); - break; - - case LPFC_FIP_EVENT_TYPE_FCF_TABLE_FULL: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2548 FCF Table full count 0x%x tag 0x%x\n", - bf_get(lpfc_acqe_fip_fcf_count, acqe_fip), - acqe_fip->event_tag); - break; - - case LPFC_FIP_EVENT_TYPE_FCF_DEAD: - phba->fcoe_cvl_eventtag = acqe_fip->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, - "2549 FCF (x%x) disconnected from network, " - "tag:x%x\n", acqe_fip->index, acqe_fip->event_tag); - /* - * If we are in the middle of FCF failover process, clear - * the corresponding FCF bit in the roundrobin bitmap. - */ - spin_lock_irq(&phba->hbalock); - if (phba->fcf.fcf_flag & FCF_DISCOVERY) { - spin_unlock_irq(&phba->hbalock); - /* Update FLOGI FCF failover eligible FCF bmask */ - lpfc_sli4_fcf_rr_index_clear(phba, acqe_fip->index); - break; - } - spin_unlock_irq(&phba->hbalock); - - /* If the event is not for currently used fcf do nothing */ - if (phba->fcf.current_rec.fcf_indx != acqe_fip->index) - break; - - /* - * Otherwise, request the port to rediscover the entire FCF - * table for a fast recovery from case that the current FCF - * is no longer valid as we are not in the middle of FCF - * failover process already. - */ - spin_lock_irq(&phba->hbalock); - /* Mark the fast failover process in progress */ - phba->fcf.fcf_flag |= FCF_DEAD_DISC; - spin_unlock_irq(&phba->hbalock); - - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, - "2771 Start FCF fast failover process due to " - "FCF DEAD event: evt_tag:x%x, fcf_index:x%x " - "\n", acqe_fip->event_tag, acqe_fip->index); - rc = lpfc_sli4_redisc_fcf_table(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, - "2772 Issue FCF rediscover mabilbox " - "command failed, fail through to FCF " - "dead event\n"); - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_DEAD_DISC; - spin_unlock_irq(&phba->hbalock); - /* - * Last resort will fail over by treating this - * as a link down to FCF registration. - */ - lpfc_sli4_fcf_dead_failthrough(phba); - } else { - /* Reset FCF roundrobin bmask for new discovery */ - lpfc_sli4_clear_fcf_rr_bmask(phba); - /* - * Handling fast FCF failover to a DEAD FCF event is - * considered equalivant to receiving CVL to all vports. - */ - lpfc_sli4_perform_all_vport_cvl(phba); - } - break; - case LPFC_FIP_EVENT_TYPE_CVL: - phba->fcoe_cvl_eventtag = acqe_fip->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, - "2718 Clear Virtual Link Received for VPI 0x%x" - " tag 0x%x\n", acqe_fip->index, acqe_fip->event_tag); - - vport = lpfc_find_vport_by_vpid(phba, - acqe_fip->index); - ndlp = lpfc_sli4_perform_vport_cvl(vport); - if (!ndlp) - break; - active_vlink_present = 0; - - vports = lpfc_create_vport_work_array(phba); - if (vports) { - for (i = 0; i <= phba->max_vports && vports[i] != NULL; - i++) { - if ((!(vports[i]->fc_flag & - FC_VPORT_CVL_RCVD)) && - (vports[i]->port_state > LPFC_FDISC)) { - active_vlink_present = 1; - break; - } - } - lpfc_destroy_vport_work_array(phba, vports); - } - - if (active_vlink_present) { - /* - * If there are other active VLinks present, - * re-instantiate the Vlink using FDISC. - */ - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_FDISC; - vport->port_state = LPFC_FDISC; - } else { - /* - * Otherwise, we request port to rediscover - * the entire FCF table for a fast recovery - * from possible case that the current FCF - * is no longer valid if we are not already - * in the FCF failover process. - */ - spin_lock_irq(&phba->hbalock); - if (phba->fcf.fcf_flag & FCF_DISCOVERY) { - spin_unlock_irq(&phba->hbalock); - break; - } - /* Mark the fast failover process in progress */ - phba->fcf.fcf_flag |= FCF_ACVL_DISC; - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | - LOG_DISCOVERY, - "2773 Start FCF failover per CVL, " - "evt_tag:x%x\n", acqe_fip->event_tag); - rc = lpfc_sli4_redisc_fcf_table(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | - LOG_DISCOVERY, - "2774 Issue FCF rediscover " - "mabilbox command failed, " - "through to CVL event\n"); - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_ACVL_DISC; - spin_unlock_irq(&phba->hbalock); - /* - * Last resort will be re-try on the - * the current registered FCF entry. - */ - lpfc_retry_pport_discovery(phba); - } else - /* - * Reset FCF roundrobin bmask for new - * discovery. - */ - lpfc_sli4_clear_fcf_rr_bmask(phba); - } - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0288 Unknown FCoE event type 0x%x event tag " - "0x%x\n", event_type, acqe_fip->event_tag); - break; - } -} - -/** - * lpfc_sli4_async_dcbx_evt - Process the asynchronous dcbx event - * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async dcbx completion queue entry. - * - * This routine is to handle the SLI4 asynchronous dcbx event. - **/ -static void -lpfc_sli4_async_dcbx_evt(struct lpfc_hba *phba, - struct lpfc_acqe_dcbx *acqe_dcbx) -{ - phba->fc_eventTag = acqe_dcbx->event_tag; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0290 The SLI4 DCBX asynchronous event is not " - "handled yet\n"); -} - -/** - * lpfc_sli4_async_grp5_evt - Process the asynchronous group5 event - * @phba: pointer to lpfc hba data structure. - * @acqe_link: pointer to the async grp5 completion queue entry. - * - * This routine is to handle the SLI4 asynchronous grp5 event. A grp5 event - * is an asynchronous notified of a logical link speed change. The Port - * reports the logical link speed in units of 10Mbps. - **/ -static void -lpfc_sli4_async_grp5_evt(struct lpfc_hba *phba, - struct lpfc_acqe_grp5 *acqe_grp5) -{ - uint16_t prev_ll_spd; - - phba->fc_eventTag = acqe_grp5->event_tag; - phba->fcoe_eventtag = acqe_grp5->event_tag; - prev_ll_spd = phba->sli4_hba.link_state.logical_speed; - phba->sli4_hba.link_state.logical_speed = - (bf_get(lpfc_acqe_grp5_llink_spd, acqe_grp5)); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2789 GRP5 Async Event: Updating logical link speed " - "from %dMbps to %dMbps\n", (prev_ll_spd * 10), - (phba->sli4_hba.link_state.logical_speed*10)); -} - -/** - * lpfc_sli4_async_event_proc - Process all the pending asynchronous event - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked by the worker thread to process all the pending - * SLI4 asynchronous events. - **/ -void lpfc_sli4_async_event_proc(struct lpfc_hba *phba) -{ - struct lpfc_cq_event *cq_event; - - /* First, declare the async event has been handled */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~ASYNC_EVENT; - spin_unlock_irq(&phba->hbalock); - /* Now, handle all the async events */ - while (!list_empty(&phba->sli4_hba.sp_asynce_work_queue)) { - /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); - list_remove_head(&phba->sli4_hba.sp_asynce_work_queue, - cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); - /* Process the asynchronous event */ - switch (bf_get(lpfc_trailer_code, &cq_event->cqe.mcqe_cmpl)) { - case LPFC_TRAILER_CODE_LINK: - lpfc_sli4_async_link_evt(phba, - &cq_event->cqe.acqe_link); - break; - case LPFC_TRAILER_CODE_FCOE: - lpfc_sli4_async_fip_evt(phba, &cq_event->cqe.acqe_fip); - break; - case LPFC_TRAILER_CODE_DCBX: - lpfc_sli4_async_dcbx_evt(phba, - &cq_event->cqe.acqe_dcbx); - break; - case LPFC_TRAILER_CODE_GRP5: - lpfc_sli4_async_grp5_evt(phba, - &cq_event->cqe.acqe_grp5); - break; - case LPFC_TRAILER_CODE_FC: - lpfc_sli4_async_fc_evt(phba, &cq_event->cqe.acqe_fc); - break; - case LPFC_TRAILER_CODE_SLI: - lpfc_sli4_async_sli_evt(phba, &cq_event->cqe.acqe_sli); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "1804 Invalid asynchrous event code: " - "x%x\n", bf_get(lpfc_trailer_code, - &cq_event->cqe.mcqe_cmpl)); - break; - } - /* Free the completion event processed to the free pool */ - lpfc_sli4_cq_event_release(phba, cq_event); - } -} - -/** - * lpfc_sli4_fcf_redisc_event_proc - Process fcf table rediscovery event - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked by the worker thread to process FCF table - * rediscovery pending completion event. - **/ -void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *phba) -{ - int rc; - - spin_lock_irq(&phba->hbalock); - /* Clear FCF rediscovery timeout event */ - phba->fcf.fcf_flag &= ~FCF_REDISC_EVT; - /* Clear driver fast failover FCF record flag */ - phba->fcf.failover_rec.flag = 0; - /* Set state for FCF fast failover */ - phba->fcf.fcf_flag |= FCF_REDISC_FOV; - spin_unlock_irq(&phba->hbalock); - - /* Scan FCF table from the first entry to re-discover SAN */ - lpfc_printf_log(phba, KERN_INFO, LOG_FIP | LOG_DISCOVERY, - "2777 Start post-quiescent FCF table scan\n"); - rc = lpfc_sli4_fcf_scan_read_fcf_rec(phba, LPFC_FCOE_FCF_GET_FIRST); - if (rc) - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_DISCOVERY, - "2747 Issue FCF scan read FCF mailbox " - "command failed 0x%x\n", rc); -} - -/** - * lpfc_api_table_setup - Set up per hba pci-device group func api jump table - * @phba: pointer to lpfc hba data structure. - * @dev_grp: The HBA PCI-Device group number. - * - * This routine is invoked to set up the per HBA PCI-Device group function - * API jump table entries. - * - * Return: 0 if success, otherwise -ENODEV - **/ -int -lpfc_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) -{ - int rc; - - /* Set up lpfc PCI-device group */ - phba->pci_dev_grp = dev_grp; - - /* The LPFC_PCI_DEV_OC uses SLI4 */ - if (dev_grp == LPFC_PCI_DEV_OC) - phba->sli_rev = LPFC_SLI_REV4; - - /* Set up device INIT API function jump table */ - rc = lpfc_init_api_table_setup(phba, dev_grp); - if (rc) - return -ENODEV; - /* Set up SCSI API function jump table */ - rc = lpfc_scsi_api_table_setup(phba, dev_grp); - if (rc) - return -ENODEV; - /* Set up SLI API function jump table */ - rc = lpfc_sli_api_table_setup(phba, dev_grp); - if (rc) - return -ENODEV; - /* Set up MBOX API function jump table */ - rc = lpfc_mbox_api_table_setup(phba, dev_grp); - if (rc) - return -ENODEV; - - return 0; -} - -/** - * lpfc_log_intr_mode - Log the active interrupt mode - * @phba: pointer to lpfc hba data structure. - * @intr_mode: active interrupt mode adopted. - * - * This routine it invoked to log the currently used active interrupt mode - * to the device. - **/ -static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode) -{ - switch (intr_mode) { - case 0: - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0470 Enable INTx interrupt mode.\n"); - break; - case 1: - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0481 Enabled MSI interrupt mode.\n"); - break; - case 2: - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0480 Enabled MSI-X interrupt mode.\n"); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0482 Illegal interrupt mode.\n"); - break; - } - return; -} - -/** - * lpfc_enable_pci_dev - Enable a generic PCI device. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to enable the PCI device that is common to all - * PCI devices. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_enable_pci_dev(struct lpfc_hba *phba) -{ - struct pci_dev *pdev; - int bars = 0; - - /* Obtain PCI device reference */ - if (!phba->pcidev) - goto out_error; - else - pdev = phba->pcidev; - /* Select PCI BARs */ - bars = pci_select_bars(pdev, IORESOURCE_MEM); - /* Enable PCI device */ - if (pci_enable_device_mem(pdev)) - goto out_error; - /* Request PCI resource for the device */ - if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME)) - goto out_disable_device; - /* Set up device as PCI master and save state for EEH */ - pci_set_master(pdev); - pci_try_set_mwi(pdev); - pci_save_state(pdev); - - /* PCIe EEH recovery on powerpc platforms needs fundamental reset */ - if (pci_find_capability(pdev, PCI_CAP_ID_EXP)) - pdev->needs_freset = 1; - - return 0; - -out_disable_device: - pci_disable_device(pdev); -out_error: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1401 Failed to enable pci device, bars:x%x\n", bars); - return -ENODEV; -} - -/** - * lpfc_disable_pci_dev - Disable a generic PCI device. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to disable the PCI device that is common to all - * PCI devices. - **/ -static void -lpfc_disable_pci_dev(struct lpfc_hba *phba) -{ - struct pci_dev *pdev; - int bars; - - /* Obtain PCI device reference */ - if (!phba->pcidev) - return; - else - pdev = phba->pcidev; - /* Select PCI BARs */ - bars = pci_select_bars(pdev, IORESOURCE_MEM); - /* Release PCI resource and disable PCI device */ - pci_release_selected_regions(pdev, bars); - pci_disable_device(pdev); - /* Null out PCI private reference to driver */ - pci_set_drvdata(pdev, NULL); - - return; -} - -/** - * lpfc_reset_hba - Reset a hba - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to reset a hba device. It brings the HBA - * offline, performs a board restart, and then brings the board back - * online. The lpfc_offline calls lpfc_sli_hba_down which will clean up - * on outstanding mailbox commands. - **/ -void -lpfc_reset_hba(struct lpfc_hba *phba) -{ - /* If resets are disabled then set error state and return. */ - if (!phba->cfg_enable_hba_reset) { - phba->link_state = LPFC_HBA_ERROR; - return; - } - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_sli_brdrestart(phba); - lpfc_online(phba); - lpfc_unblock_mgmt_io(phba); -} - -/** - * lpfc_sli_sriov_nr_virtfn_get - Get the number of sr-iov virtual functions - * @phba: pointer to lpfc hba data structure. - * - * This function enables the PCI SR-IOV virtual functions to a physical - * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to - * enable the number of virtual functions to the physical function. As - * not all devices support SR-IOV, the return code from the pci_enable_sriov() - * API call does not considered as an error condition for most of the device. - **/ -uint16_t -lpfc_sli_sriov_nr_virtfn_get(struct lpfc_hba *phba) -{ - struct pci_dev *pdev = phba->pcidev; - uint16_t nr_virtfn; - int pos; - - pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); - if (pos == 0) - return 0; - - pci_read_config_word(pdev, pos + PCI_SRIOV_TOTAL_VF, &nr_virtfn); - return nr_virtfn; -} - -/** - * lpfc_sli_probe_sriov_nr_virtfn - Enable a number of sr-iov virtual functions - * @phba: pointer to lpfc hba data structure. - * @nr_vfn: number of virtual functions to be enabled. - * - * This function enables the PCI SR-IOV virtual functions to a physical - * function. It invokes the PCI SR-IOV api with the @nr_vfn provided to - * enable the number of virtual functions to the physical function. As - * not all devices support SR-IOV, the return code from the pci_enable_sriov() - * API call does not considered as an error condition for most of the device. - **/ -int -lpfc_sli_probe_sriov_nr_virtfn(struct lpfc_hba *phba, int nr_vfn) -{ - struct pci_dev *pdev = phba->pcidev; - uint16_t max_nr_vfn; - int rc; - - max_nr_vfn = lpfc_sli_sriov_nr_virtfn_get(phba); - if (nr_vfn > max_nr_vfn) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3057 Requested vfs (%d) greater than " - "supported vfs (%d)", nr_vfn, max_nr_vfn); - return -EINVAL; - } - - rc = pci_enable_sriov(pdev, nr_vfn); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2806 Failed to enable sriov on this device " - "with vfn number nr_vf:%d, rc:%d\n", - nr_vfn, rc); - } else - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2807 Successful enable sriov on this device " - "with vfn number nr_vf:%d\n", nr_vfn); - return rc; -} - -/** - * lpfc_sli_driver_resource_setup - Setup driver internal resources for SLI3 dev. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to set up the driver internal resources specific to - * support the SLI-3 HBA device it attached to. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_sli_driver_resource_setup(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli; - int rc; - - /* - * Initialize timers used by driver - */ - - /* Heartbeat timer */ - init_timer(&phba->hb_tmofunc); - phba->hb_tmofunc.function = lpfc_hb_timeout; - phba->hb_tmofunc.data = (unsigned long)phba; - - psli = &phba->sli; - /* MBOX heartbeat timer */ - init_timer(&psli->mbox_tmo); - psli->mbox_tmo.function = lpfc_mbox_timeout; - psli->mbox_tmo.data = (unsigned long) phba; - /* FCP polling mode timer */ - init_timer(&phba->fcp_poll_timer); - phba->fcp_poll_timer.function = lpfc_poll_timeout; - phba->fcp_poll_timer.data = (unsigned long) phba; - /* Fabric block timer */ - init_timer(&phba->fabric_block_timer); - phba->fabric_block_timer.function = lpfc_fabric_block_timeout; - phba->fabric_block_timer.data = (unsigned long) phba; - /* EA polling mode timer */ - init_timer(&phba->eratt_poll); - phba->eratt_poll.function = lpfc_poll_eratt; - phba->eratt_poll.data = (unsigned long) phba; - - /* Host attention work mask setup */ - phba->work_ha_mask = (HA_ERATT | HA_MBATT | HA_LATT); - phba->work_ha_mask |= (HA_RXMASK << (LPFC_ELS_RING * 4)); - - /* Get all the module params for configuring this host */ - lpfc_get_cfgparam(phba); - if (phba->pcidev->device == PCI_DEVICE_ID_HORNET) { - phba->menlo_flag |= HBA_MENLO_SUPPORT; - /* check for menlo minimum sg count */ - if (phba->cfg_sg_seg_cnt < LPFC_DEFAULT_MENLO_SG_SEG_CNT) - phba->cfg_sg_seg_cnt = LPFC_DEFAULT_MENLO_SG_SEG_CNT; - } - - /* - * Since the sg_tablesize is module parameter, the sg_dma_buf_size - * used to create the sg_dma_buf_pool must be dynamically calculated. - * 2 segments are added since the IOCB needs a command and response bde. - */ - phba->cfg_sg_dma_buf_size = sizeof(struct fcp_cmnd) + - sizeof(struct fcp_rsp) + - ((phba->cfg_sg_seg_cnt + 2) * sizeof(struct ulp_bde64)); - - if (phba->cfg_enable_bg) { - phba->cfg_sg_seg_cnt = LPFC_MAX_SG_SEG_CNT; - phba->cfg_sg_dma_buf_size += - phba->cfg_prot_sg_seg_cnt * sizeof(struct ulp_bde64); - } - - /* Also reinitialize the host templates with new values. */ - lpfc_vport_template.sg_tablesize = phba->cfg_sg_seg_cnt; - lpfc_template.sg_tablesize = phba->cfg_sg_seg_cnt; - - phba->max_vpi = LPFC_MAX_VPI; - /* This will be set to correct value after config_port mbox */ - phba->max_vports = 0; - - /* - * Initialize the SLI Layer to run with lpfc HBAs. - */ - lpfc_sli_setup(phba); - lpfc_sli_queue_setup(phba); - - /* Allocate device driver memory */ - if (lpfc_mem_alloc(phba, BPL_ALIGN_SZ)) - return -ENOMEM; - - /* - * Enable sr-iov virtual functions if supported and configured - * through the module parameter. - */ - if (phba->cfg_sriov_nr_virtfn > 0) { - rc = lpfc_sli_probe_sriov_nr_virtfn(phba, - phba->cfg_sriov_nr_virtfn); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2808 Requested number of SR-IOV " - "virtual functions (%d) is not " - "supported\n", - phba->cfg_sriov_nr_virtfn); - phba->cfg_sriov_nr_virtfn = 0; - } - } - - return 0; -} - -/** - * lpfc_sli_driver_resource_unset - Unset drvr internal resources for SLI3 dev - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unset the driver internal resources set up - * specific for supporting the SLI-3 HBA device it attached to. - **/ -static void -lpfc_sli_driver_resource_unset(struct lpfc_hba *phba) -{ - /* Free device driver memory allocated */ - lpfc_mem_free_all(phba); - - return; -} - -/** - * lpfc_sli4_driver_resource_setup - Setup drvr internal resources for SLI4 dev - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to set up the driver internal resources specific to - * support the SLI-4 HBA device it attached to. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli; - LPFC_MBOXQ_t *mboxq; - int rc, i, hbq_count, buf_size, dma_buf_size, max_buf_size; - uint8_t pn_page[LPFC_MAX_SUPPORTED_PAGES] = {0}; - struct lpfc_mqe *mqe; - int longs, sli_family; - int sges_per_segment; - - /* Before proceed, wait for POST done and device ready */ - rc = lpfc_sli4_post_status_check(phba); - if (rc) - return -ENODEV; - - /* - * Initialize timers used by driver - */ - - /* Heartbeat timer */ - init_timer(&phba->hb_tmofunc); - phba->hb_tmofunc.function = lpfc_hb_timeout; - phba->hb_tmofunc.data = (unsigned long)phba; - init_timer(&phba->rrq_tmr); - phba->rrq_tmr.function = lpfc_rrq_timeout; - phba->rrq_tmr.data = (unsigned long)phba; - - psli = &phba->sli; - /* MBOX heartbeat timer */ - init_timer(&psli->mbox_tmo); - psli->mbox_tmo.function = lpfc_mbox_timeout; - psli->mbox_tmo.data = (unsigned long) phba; - /* Fabric block timer */ - init_timer(&phba->fabric_block_timer); - phba->fabric_block_timer.function = lpfc_fabric_block_timeout; - phba->fabric_block_timer.data = (unsigned long) phba; - /* EA polling mode timer */ - init_timer(&phba->eratt_poll); - phba->eratt_poll.function = lpfc_poll_eratt; - phba->eratt_poll.data = (unsigned long) phba; - /* FCF rediscover timer */ - init_timer(&phba->fcf.redisc_wait); - phba->fcf.redisc_wait.function = lpfc_sli4_fcf_redisc_wait_tmo; - phba->fcf.redisc_wait.data = (unsigned long)phba; - - /* - * Control structure for handling external multi-buffer mailbox - * command pass-through. - */ - memset((uint8_t *)&phba->mbox_ext_buf_ctx, 0, - sizeof(struct lpfc_mbox_ext_buf_ctx)); - INIT_LIST_HEAD(&phba->mbox_ext_buf_ctx.ext_dmabuf_list); - - /* - * We need to do a READ_CONFIG mailbox command here before - * calling lpfc_get_cfgparam. For VFs this will report the - * MAX_XRI, MAX_VPI, MAX_RPI, MAX_IOCB, and MAX_VFI settings. - * All of the resources allocated - * for this Port are tied to these values. - */ - /* Get all the module params for configuring this host */ - lpfc_get_cfgparam(phba); - phba->max_vpi = LPFC_MAX_VPI; - /* This will be set to correct value after the read_config mbox */ - phba->max_vports = 0; - - /* Program the default value of vlan_id and fc_map */ - phba->valid_vlan = 0; - phba->fc_map[0] = LPFC_FCOE_FCF_MAP0; - phba->fc_map[1] = LPFC_FCOE_FCF_MAP1; - phba->fc_map[2] = LPFC_FCOE_FCF_MAP2; - - /* With BlockGuard we can have multiple SGEs per Data Segemnt */ - sges_per_segment = 1; - if (phba->cfg_enable_bg) - sges_per_segment = 2; - - /* - * Since the sg_tablesize is module parameter, the sg_dma_buf_size - * used to create the sg_dma_buf_pool must be dynamically calculated. - * 2 segments are added since the IOCB needs a command and response bde. - * To insure that the scsi sgl does not cross a 4k page boundary only - * sgl sizes of must be a power of 2. - */ - buf_size = (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp) + - (((phba->cfg_sg_seg_cnt * sges_per_segment) + 2) * - sizeof(struct sli4_sge))); - - sli_family = bf_get(lpfc_sli_intf_sli_family, &phba->sli4_hba.sli_intf); - max_buf_size = LPFC_SLI4_MAX_BUF_SIZE; - switch (sli_family) { - case LPFC_SLI_INTF_FAMILY_BE2: - case LPFC_SLI_INTF_FAMILY_BE3: - /* There is a single hint for BE - 2 pages per BPL. */ - if (bf_get(lpfc_sli_intf_sli_hint1, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_SLI_HINT1_1) - max_buf_size = LPFC_SLI4_FL1_MAX_BUF_SIZE; - break; - case LPFC_SLI_INTF_FAMILY_LNCR_A0: - case LPFC_SLI_INTF_FAMILY_LNCR_B0: - default: - break; - } - - for (dma_buf_size = LPFC_SLI4_MIN_BUF_SIZE; - dma_buf_size < max_buf_size && buf_size > dma_buf_size; - dma_buf_size = dma_buf_size << 1) - ; - if (dma_buf_size == max_buf_size) - phba->cfg_sg_seg_cnt = (dma_buf_size - - sizeof(struct fcp_cmnd) - sizeof(struct fcp_rsp) - - (2 * sizeof(struct sli4_sge))) / - sizeof(struct sli4_sge); - phba->cfg_sg_dma_buf_size = dma_buf_size; - - /* Initialize buffer queue management fields */ - hbq_count = lpfc_sli_hbq_count(); - for (i = 0; i < hbq_count; ++i) - INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list); - INIT_LIST_HEAD(&phba->rb_pend_list); - phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_sli4_rb_alloc; - phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_sli4_rb_free; - - /* - * Initialize the SLI Layer to run with lpfc SLI4 HBAs. - */ - /* Initialize the Abort scsi buffer list used by driver */ - spin_lock_init(&phba->sli4_hba.abts_scsi_buf_list_lock); - INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_scsi_buf_list); - /* This abort list used by worker thread */ - spin_lock_init(&phba->sli4_hba.abts_sgl_list_lock); - - /* - * Initialize driver internal slow-path work queues - */ - - /* Driver internel slow-path CQ Event pool */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_cqe_event_pool); - /* Response IOCB work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_queue_event); - /* Asynchronous event CQ Event work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_asynce_work_queue); - /* Fast-path XRI aborted CQ Event work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue); - /* Slow-path XRI aborted CQ Event work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_els_xri_aborted_work_queue); - /* Receive queue CQ Event work queue list */ - INIT_LIST_HEAD(&phba->sli4_hba.sp_unsol_work_queue); - - /* Initialize extent block lists. */ - INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_blk_list); - INIT_LIST_HEAD(&phba->sli4_hba.lpfc_xri_blk_list); - INIT_LIST_HEAD(&phba->sli4_hba.lpfc_vfi_blk_list); - INIT_LIST_HEAD(&phba->lpfc_vpi_blk_list); - - /* Initialize the driver internal SLI layer lists. */ - lpfc_sli_setup(phba); - lpfc_sli_queue_setup(phba); - - /* Allocate device driver memory */ - rc = lpfc_mem_alloc(phba, SGL_ALIGN_SZ); - if (rc) - return -ENOMEM; - - /* IF Type 2 ports get initialized now. */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_IF_TYPE_2) { - rc = lpfc_pci_function_reset(phba); - if (unlikely(rc)) - return -ENODEV; - } - - /* Create the bootstrap mailbox command */ - rc = lpfc_create_bootstrap_mbox(phba); - if (unlikely(rc)) - goto out_free_mem; - - /* Set up the host's endian order with the device. */ - rc = lpfc_setup_endian_order(phba); - if (unlikely(rc)) - goto out_free_bsmbx; - - /* Set up the hba's configuration parameters. */ - rc = lpfc_sli4_read_config(phba); - if (unlikely(rc)) - goto out_free_bsmbx; - - /* IF Type 0 ports get initialized now. */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_IF_TYPE_0) { - rc = lpfc_pci_function_reset(phba); - if (unlikely(rc)) - goto out_free_bsmbx; - } - - mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!mboxq) { - rc = -ENOMEM; - goto out_free_bsmbx; - } - - /* Get the Supported Pages if PORT_CAPABILITIES is supported by port. */ - lpfc_supported_pages(mboxq); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (!rc) { - mqe = &mboxq->u.mqe; - memcpy(&pn_page[0], ((uint8_t *)&mqe->un.supp_pages.word3), - LPFC_MAX_SUPPORTED_PAGES); - for (i = 0; i < LPFC_MAX_SUPPORTED_PAGES; i++) { - switch (pn_page[i]) { - case LPFC_SLI4_PARAMETERS: - phba->sli4_hba.pc_sli4_params.supported = 1; - break; - default: - break; - } - } - /* Read the port's SLI4 Parameters capabilities if supported. */ - if (phba->sli4_hba.pc_sli4_params.supported) - rc = lpfc_pc_sli4_params_get(phba, mboxq); - if (rc) { - mempool_free(mboxq, phba->mbox_mem_pool); - rc = -EIO; - goto out_free_bsmbx; - } - } - /* - * Get sli4 parameters that override parameters from Port capabilities. - * If this call fails, it isn't critical unless the SLI4 parameters come - * back in conflict. - */ - rc = lpfc_get_sli4_parameters(phba, mboxq); - if (rc) { - if (phba->sli4_hba.extents_in_use && - phba->sli4_hba.rpi_hdrs_in_use) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2999 Unsupported SLI4 Parameters " - "Extents and RPI headers enabled.\n"); - goto out_free_bsmbx; - } - } - mempool_free(mboxq, phba->mbox_mem_pool); - /* Verify all the SLI4 queues */ - rc = lpfc_sli4_queue_verify(phba); - if (rc) - goto out_free_bsmbx; - - /* Create driver internal CQE event pool */ - rc = lpfc_sli4_cq_event_pool_create(phba); - if (rc) - goto out_free_bsmbx; - - /* Initialize and populate the iocb list per host */ - rc = lpfc_init_sgl_list(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1400 Failed to initialize sgl list.\n"); - goto out_destroy_cq_event_pool; - } - rc = lpfc_init_active_sgl_array(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1430 Failed to initialize sgl list.\n"); - goto out_free_sgl_list; - } - rc = lpfc_sli4_init_rpi_hdrs(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1432 Failed to initialize rpi headers.\n"); - goto out_free_active_sgl; - } - - /* Allocate eligible FCF bmask memory for FCF roundrobin failover */ - longs = (LPFC_SLI4_FCF_TBL_INDX_MAX + BITS_PER_LONG - 1)/BITS_PER_LONG; - phba->fcf.fcf_rr_bmask = kzalloc(longs * sizeof(unsigned long), - GFP_KERNEL); - if (!phba->fcf.fcf_rr_bmask) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2759 Failed allocate memory for FCF round " - "robin failover bmask\n"); - rc = -ENOMEM; - goto out_remove_rpi_hdrs; - } - - /* - * The cfg_fcp_eq_count can be zero whenever there is exactly one - * interrupt vector. This is not an error - */ - if (phba->cfg_fcp_eq_count) { - phba->sli4_hba.fcp_eq_hdl = - kzalloc((sizeof(struct lpfc_fcp_eq_hdl) * - phba->cfg_fcp_eq_count), GFP_KERNEL); - if (!phba->sli4_hba.fcp_eq_hdl) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2572 Failed allocate memory for " - "fast-path per-EQ handle array\n"); - rc = -ENOMEM; - goto out_free_fcf_rr_bmask; - } - } - - phba->sli4_hba.msix_entries = kzalloc((sizeof(struct msix_entry) * - phba->sli4_hba.cfg_eqn), GFP_KERNEL); - if (!phba->sli4_hba.msix_entries) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2573 Failed allocate memory for msi-x " - "interrupt vector entries\n"); - rc = -ENOMEM; - goto out_free_fcp_eq_hdl; - } - - /* - * Enable sr-iov virtual functions if supported and configured - * through the module parameter. - */ - if (phba->cfg_sriov_nr_virtfn > 0) { - rc = lpfc_sli_probe_sriov_nr_virtfn(phba, - phba->cfg_sriov_nr_virtfn); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3020 Requested number of SR-IOV " - "virtual functions (%d) is not " - "supported\n", - phba->cfg_sriov_nr_virtfn); - phba->cfg_sriov_nr_virtfn = 0; - } - } - - return 0; - -out_free_fcp_eq_hdl: - kfree(phba->sli4_hba.fcp_eq_hdl); -out_free_fcf_rr_bmask: - kfree(phba->fcf.fcf_rr_bmask); -out_remove_rpi_hdrs: - lpfc_sli4_remove_rpi_hdrs(phba); -out_free_active_sgl: - lpfc_free_active_sgl(phba); -out_free_sgl_list: - lpfc_free_sgl_list(phba); -out_destroy_cq_event_pool: - lpfc_sli4_cq_event_pool_destroy(phba); -out_free_bsmbx: - lpfc_destroy_bootstrap_mbox(phba); -out_free_mem: - lpfc_mem_free(phba); - return rc; -} - -/** - * lpfc_sli4_driver_resource_unset - Unset drvr internal resources for SLI4 dev - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unset the driver internal resources set up - * specific for supporting the SLI-4 HBA device it attached to. - **/ -static void -lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) -{ - struct lpfc_fcf_conn_entry *conn_entry, *next_conn_entry; - - /* Free memory allocated for msi-x interrupt vector entries */ - kfree(phba->sli4_hba.msix_entries); - - /* Free memory allocated for fast-path work queue handles */ - kfree(phba->sli4_hba.fcp_eq_hdl); - - /* Free the allocated rpi headers. */ - lpfc_sli4_remove_rpi_hdrs(phba); - lpfc_sli4_remove_rpis(phba); - - /* Free eligible FCF index bmask */ - kfree(phba->fcf.fcf_rr_bmask); - - /* Free the ELS sgl list */ - lpfc_free_active_sgl(phba); - lpfc_free_sgl_list(phba); - - /* Free the SCSI sgl management array */ - kfree(phba->sli4_hba.lpfc_scsi_psb_array); - - /* Free the completion queue EQ event pool */ - lpfc_sli4_cq_event_release_all(phba); - lpfc_sli4_cq_event_pool_destroy(phba); - - /* Release resource identifiers. */ - lpfc_sli4_dealloc_resource_identifiers(phba); - - /* Free the bsmbx region. */ - lpfc_destroy_bootstrap_mbox(phba); - - /* Free the SLI Layer memory with SLI4 HBAs */ - lpfc_mem_free_all(phba); - - /* Free the current connect table */ - list_for_each_entry_safe(conn_entry, next_conn_entry, - &phba->fcf_conn_rec_list, list) { - list_del_init(&conn_entry->list); - kfree(conn_entry); - } - - return; -} - -/** - * lpfc_init_api_table_setup - Set up init api function jump table - * @phba: The hba struct for which this call is being executed. - * @dev_grp: The HBA PCI-Device group number. - * - * This routine sets up the device INIT interface API function jump table - * in @phba struct. - * - * Returns: 0 - success, -ENODEV - failure. - **/ -int -lpfc_init_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) -{ - phba->lpfc_hba_init_link = lpfc_hba_init_link; - phba->lpfc_hba_down_link = lpfc_hba_down_link; - phba->lpfc_selective_reset = lpfc_selective_reset; - switch (dev_grp) { - case LPFC_PCI_DEV_LP: - phba->lpfc_hba_down_post = lpfc_hba_down_post_s3; - phba->lpfc_handle_eratt = lpfc_handle_eratt_s3; - phba->lpfc_stop_port = lpfc_stop_port_s3; - break; - case LPFC_PCI_DEV_OC: - phba->lpfc_hba_down_post = lpfc_hba_down_post_s4; - phba->lpfc_handle_eratt = lpfc_handle_eratt_s4; - phba->lpfc_stop_port = lpfc_stop_port_s4; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1431 Invalid HBA PCI-device group: 0x%x\n", - dev_grp); - return -ENODEV; - break; - } - return 0; -} - -/** - * lpfc_setup_driver_resource_phase1 - Phase1 etup driver internal resources. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to set up the driver internal resources before the - * device specific resource setup to support the HBA device it attached to. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_setup_driver_resource_phase1(struct lpfc_hba *phba) -{ - /* - * Driver resources common to all SLI revisions - */ - atomic_set(&phba->fast_event_count, 0); - spin_lock_init(&phba->hbalock); - - /* Initialize ndlp management spinlock */ - spin_lock_init(&phba->ndlp_lock); - - INIT_LIST_HEAD(&phba->port_list); - INIT_LIST_HEAD(&phba->work_list); - init_waitqueue_head(&phba->wait_4_mlo_m_q); - - /* Initialize the wait queue head for the kernel thread */ - init_waitqueue_head(&phba->work_waitq); - - /* Initialize the scsi buffer list used by driver for scsi IO */ - spin_lock_init(&phba->scsi_buf_list_lock); - INIT_LIST_HEAD(&phba->lpfc_scsi_buf_list); - - /* Initialize the fabric iocb list */ - INIT_LIST_HEAD(&phba->fabric_iocb_list); - - /* Initialize list to save ELS buffers */ - INIT_LIST_HEAD(&phba->elsbuf); - - /* Initialize FCF connection rec list */ - INIT_LIST_HEAD(&phba->fcf_conn_rec_list); - - return 0; -} - -/** - * lpfc_setup_driver_resource_phase2 - Phase2 setup driver internal resources. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to set up the driver internal resources after the - * device specific resource setup to support the HBA device it attached to. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_setup_driver_resource_phase2(struct lpfc_hba *phba) -{ - int error; - - /* Startup the kernel thread for this host adapter. */ - phba->worker_thread = kthread_run(lpfc_do_work, phba, - "lpfc_worker_%d", phba->brd_no); - if (IS_ERR(phba->worker_thread)) { - error = PTR_ERR(phba->worker_thread); - return error; - } - - return 0; -} - -/** - * lpfc_unset_driver_resource_phase2 - Phase2 unset driver internal resources. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unset the driver internal resources set up after - * the device specific resource setup for supporting the HBA device it - * attached to. - **/ -static void -lpfc_unset_driver_resource_phase2(struct lpfc_hba *phba) -{ - /* Stop kernel worker thread */ - kthread_stop(phba->worker_thread); -} - -/** - * lpfc_free_iocb_list - Free iocb list. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to free the driver's IOCB list and memory. - **/ -static void -lpfc_free_iocb_list(struct lpfc_hba *phba) -{ - struct lpfc_iocbq *iocbq_entry = NULL, *iocbq_next = NULL; - - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(iocbq_entry, iocbq_next, - &phba->lpfc_iocb_list, list) { - list_del(&iocbq_entry->list); - kfree(iocbq_entry); - phba->total_iocbq_bufs--; - } - spin_unlock_irq(&phba->hbalock); - - return; -} - -/** - * lpfc_init_iocb_list - Allocate and initialize iocb list. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to allocate and initizlize the driver's IOCB - * list and set up the IOCB tag array accordingly. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count) -{ - struct lpfc_iocbq *iocbq_entry = NULL; - uint16_t iotag; - int i; - - /* Initialize and populate the iocb list per host. */ - INIT_LIST_HEAD(&phba->lpfc_iocb_list); - for (i = 0; i < iocb_count; i++) { - iocbq_entry = kzalloc(sizeof(struct lpfc_iocbq), GFP_KERNEL); - if (iocbq_entry == NULL) { - printk(KERN_ERR "%s: only allocated %d iocbs of " - "expected %d count. Unloading driver.\n", - __func__, i, LPFC_IOCB_LIST_CNT); - goto out_free_iocbq; - } - - iotag = lpfc_sli_next_iotag(phba, iocbq_entry); - if (iotag == 0) { - kfree(iocbq_entry); - printk(KERN_ERR "%s: failed to allocate IOTAG. " - "Unloading driver.\n", __func__); - goto out_free_iocbq; - } - iocbq_entry->sli4_lxritag = NO_XRI; - iocbq_entry->sli4_xritag = NO_XRI; - - spin_lock_irq(&phba->hbalock); - list_add(&iocbq_entry->list, &phba->lpfc_iocb_list); - phba->total_iocbq_bufs++; - spin_unlock_irq(&phba->hbalock); - } - - return 0; - -out_free_iocbq: - lpfc_free_iocb_list(phba); - - return -ENOMEM; -} - -/** - * lpfc_free_sgl_list - Free sgl list. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to free the driver's sgl list and memory. - **/ -static void -lpfc_free_sgl_list(struct lpfc_hba *phba) -{ - struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; - LIST_HEAD(sglq_list); - - spin_lock_irq(&phba->hbalock); - list_splice_init(&phba->sli4_hba.lpfc_sgl_list, &sglq_list); - spin_unlock_irq(&phba->hbalock); - - list_for_each_entry_safe(sglq_entry, sglq_next, - &sglq_list, list) { - list_del(&sglq_entry->list); - lpfc_mbuf_free(phba, sglq_entry->virt, sglq_entry->phys); - kfree(sglq_entry); - phba->sli4_hba.total_sglq_bufs--; - } - kfree(phba->sli4_hba.lpfc_els_sgl_array); -} - -/** - * lpfc_init_active_sgl_array - Allocate the buf to track active ELS XRIs. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to allocate the driver's active sgl memory. - * This array will hold the sglq_entry's for active IOs. - **/ -static int -lpfc_init_active_sgl_array(struct lpfc_hba *phba) -{ - int size; - size = sizeof(struct lpfc_sglq *); - size *= phba->sli4_hba.max_cfg_param.max_xri; - - phba->sli4_hba.lpfc_sglq_active_list = - kzalloc(size, GFP_KERNEL); - if (!phba->sli4_hba.lpfc_sglq_active_list) - return -ENOMEM; - return 0; -} - -/** - * lpfc_free_active_sgl - Free the buf that tracks active ELS XRIs. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to walk through the array of active sglq entries - * and free all of the resources. - * This is just a place holder for now. - **/ -static void -lpfc_free_active_sgl(struct lpfc_hba *phba) -{ - kfree(phba->sli4_hba.lpfc_sglq_active_list); -} - -/** - * lpfc_init_sgl_list - Allocate and initialize sgl list. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to allocate and initizlize the driver's sgl - * list and set up the sgl xritag tag array accordingly. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_init_sgl_list(struct lpfc_hba *phba) -{ - struct lpfc_sglq *sglq_entry = NULL; - int i; - int els_xri_cnt; - - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2400 ELS XRI count %d.\n", - els_xri_cnt); - /* Initialize and populate the sglq list per host/VF. */ - INIT_LIST_HEAD(&phba->sli4_hba.lpfc_sgl_list); - INIT_LIST_HEAD(&phba->sli4_hba.lpfc_abts_els_sgl_list); - - /* Sanity check on XRI management */ - if (phba->sli4_hba.max_cfg_param.max_xri <= els_xri_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2562 No room left for SCSI XRI allocation: " - "max_xri=%d, els_xri=%d\n", - phba->sli4_hba.max_cfg_param.max_xri, - els_xri_cnt); - return -ENOMEM; - } - - /* Allocate memory for the ELS XRI management array */ - phba->sli4_hba.lpfc_els_sgl_array = - kzalloc((sizeof(struct lpfc_sglq *) * els_xri_cnt), - GFP_KERNEL); - - if (!phba->sli4_hba.lpfc_els_sgl_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2401 Failed to allocate memory for ELS " - "XRI management array of size %d.\n", - els_xri_cnt); - return -ENOMEM; - } - - /* Keep the SCSI XRI into the XRI management array */ - phba->sli4_hba.scsi_xri_max = - phba->sli4_hba.max_cfg_param.max_xri - els_xri_cnt; - phba->sli4_hba.scsi_xri_cnt = 0; - phba->sli4_hba.lpfc_scsi_psb_array = - kzalloc((sizeof(struct lpfc_scsi_buf *) * - phba->sli4_hba.scsi_xri_max), GFP_KERNEL); - - if (!phba->sli4_hba.lpfc_scsi_psb_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2563 Failed to allocate memory for SCSI " - "XRI management array of size %d.\n", - phba->sli4_hba.scsi_xri_max); - kfree(phba->sli4_hba.lpfc_els_sgl_array); - return -ENOMEM; - } - - for (i = 0; i < els_xri_cnt; i++) { - sglq_entry = kzalloc(sizeof(struct lpfc_sglq), GFP_KERNEL); - if (sglq_entry == NULL) { - printk(KERN_ERR "%s: only allocated %d sgls of " - "expected %d count. Unloading driver.\n", - __func__, i, els_xri_cnt); - goto out_free_mem; - } - - sglq_entry->buff_type = GEN_BUFF_TYPE; - sglq_entry->virt = lpfc_mbuf_alloc(phba, 0, &sglq_entry->phys); - if (sglq_entry->virt == NULL) { - kfree(sglq_entry); - printk(KERN_ERR "%s: failed to allocate mbuf.\n" - "Unloading driver.\n", __func__); - goto out_free_mem; - } - sglq_entry->sgl = sglq_entry->virt; - memset(sglq_entry->sgl, 0, LPFC_BPL_SIZE); - - /* The list order is used by later block SGL registraton */ - spin_lock_irq(&phba->hbalock); - sglq_entry->state = SGL_FREED; - list_add_tail(&sglq_entry->list, &phba->sli4_hba.lpfc_sgl_list); - phba->sli4_hba.lpfc_els_sgl_array[i] = sglq_entry; - phba->sli4_hba.total_sglq_bufs++; - spin_unlock_irq(&phba->hbalock); - } - return 0; - -out_free_mem: - kfree(phba->sli4_hba.lpfc_scsi_psb_array); - lpfc_free_sgl_list(phba); - return -ENOMEM; -} - -/** - * lpfc_sli4_init_rpi_hdrs - Post the rpi header memory region to the port - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post rpi header templates to the - * port for those SLI4 ports that do not support extents. This routine - * posts a PAGE_SIZE memory region to the port to hold up to - * PAGE_SIZE modulo 64 rpi context headers. This is an initialization routine - * and should be called only when interrupts are disabled. - * - * Return codes - * 0 - successful - * -ERROR - otherwise. - **/ -int -lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *phba) -{ - int rc = 0; - struct lpfc_rpi_hdr *rpi_hdr; - - INIT_LIST_HEAD(&phba->sli4_hba.lpfc_rpi_hdr_list); - if (!phba->sli4_hba.rpi_hdrs_in_use) - return rc; - if (phba->sli4_hba.extents_in_use) - return -EIO; - - rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); - if (!rpi_hdr) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0391 Error during rpi post operation\n"); - lpfc_sli4_remove_rpis(phba); - rc = -ENODEV; - } - - return rc; -} - -/** - * lpfc_sli4_create_rpi_hdr - Allocate an rpi header memory region - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to allocate a single 4KB memory region to - * support rpis and stores them in the phba. This single region - * provides support for up to 64 rpis. The region is used globally - * by the device. - * - * Returns: - * A valid rpi hdr on success. - * A NULL pointer on any failure. - **/ -struct lpfc_rpi_hdr * -lpfc_sli4_create_rpi_hdr(struct lpfc_hba *phba) -{ - uint16_t rpi_limit, curr_rpi_range; - struct lpfc_dmabuf *dmabuf; - struct lpfc_rpi_hdr *rpi_hdr; - uint32_t rpi_count; - - /* - * If the SLI4 port supports extents, posting the rpi header isn't - * required. Set the expected maximum count and let the actual value - * get set when extents are fully allocated. - */ - if (!phba->sli4_hba.rpi_hdrs_in_use) - return NULL; - if (phba->sli4_hba.extents_in_use) - return NULL; - - /* The limit on the logical index is just the max_rpi count. */ - rpi_limit = phba->sli4_hba.max_cfg_param.rpi_base + - phba->sli4_hba.max_cfg_param.max_rpi - 1; - - spin_lock_irq(&phba->hbalock); - /* - * Establish the starting RPI in this header block. The starting - * rpi is normalized to a zero base because the physical rpi is - * port based. - */ - curr_rpi_range = phba->sli4_hba.next_rpi; - spin_unlock_irq(&phba->hbalock); - - /* - * The port has a limited number of rpis. The increment here - * is LPFC_RPI_HDR_COUNT - 1 to account for the starting value - * and to allow the full max_rpi range per port. - */ - if ((curr_rpi_range + (LPFC_RPI_HDR_COUNT - 1)) > rpi_limit) - rpi_count = rpi_limit - curr_rpi_range; - else - rpi_count = LPFC_RPI_HDR_COUNT; - - if (!rpi_count) - return NULL; - /* - * First allocate the protocol header region for the port. The - * port expects a 4KB DMA-mapped memory region that is 4K aligned. - */ - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!dmabuf) - return NULL; - - dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, - LPFC_HDR_TEMPLATE_SIZE, - &dmabuf->phys, - GFP_KERNEL); - if (!dmabuf->virt) { - rpi_hdr = NULL; - goto err_free_dmabuf; - } - - memset(dmabuf->virt, 0, LPFC_HDR_TEMPLATE_SIZE); - if (!IS_ALIGNED(dmabuf->phys, LPFC_HDR_TEMPLATE_SIZE)) { - rpi_hdr = NULL; - goto err_free_coherent; - } - - /* Save the rpi header data for cleanup later. */ - rpi_hdr = kzalloc(sizeof(struct lpfc_rpi_hdr), GFP_KERNEL); - if (!rpi_hdr) - goto err_free_coherent; - - rpi_hdr->dmabuf = dmabuf; - rpi_hdr->len = LPFC_HDR_TEMPLATE_SIZE; - rpi_hdr->page_count = 1; - spin_lock_irq(&phba->hbalock); - - /* The rpi_hdr stores the logical index only. */ - rpi_hdr->start_rpi = curr_rpi_range; - list_add_tail(&rpi_hdr->list, &phba->sli4_hba.lpfc_rpi_hdr_list); - - /* - * The next_rpi stores the next logical module-64 rpi value used - * to post physical rpis in subsequent rpi postings. - */ - phba->sli4_hba.next_rpi += rpi_count; - spin_unlock_irq(&phba->hbalock); - return rpi_hdr; - - err_free_coherent: - dma_free_coherent(&phba->pcidev->dev, LPFC_HDR_TEMPLATE_SIZE, - dmabuf->virt, dmabuf->phys); - err_free_dmabuf: - kfree(dmabuf); - return NULL; -} - -/** - * lpfc_sli4_remove_rpi_hdrs - Remove all rpi header memory regions - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to remove all memory resources allocated - * to support rpis for SLI4 ports not supporting extents. This routine - * presumes the caller has released all rpis consumed by fabric or port - * logins and is prepared to have the header pages removed. - **/ -void -lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *phba) -{ - struct lpfc_rpi_hdr *rpi_hdr, *next_rpi_hdr; - - if (!phba->sli4_hba.rpi_hdrs_in_use) - goto exit; - - list_for_each_entry_safe(rpi_hdr, next_rpi_hdr, - &phba->sli4_hba.lpfc_rpi_hdr_list, list) { - list_del(&rpi_hdr->list); - dma_free_coherent(&phba->pcidev->dev, rpi_hdr->len, - rpi_hdr->dmabuf->virt, rpi_hdr->dmabuf->phys); - kfree(rpi_hdr->dmabuf); - kfree(rpi_hdr); - } - exit: - /* There are no rpis available to the port now. */ - phba->sli4_hba.next_rpi = 0; -} - -/** - * lpfc_hba_alloc - Allocate driver hba data structure for a device. - * @pdev: pointer to pci device data structure. - * - * This routine is invoked to allocate the driver hba data structure for an - * HBA device. If the allocation is successful, the phba reference to the - * PCI device data structure is set. - * - * Return codes - * pointer to @phba - successful - * NULL - error - **/ -static struct lpfc_hba * -lpfc_hba_alloc(struct pci_dev *pdev) -{ - struct lpfc_hba *phba; - - /* Allocate memory for HBA structure */ - phba = kzalloc(sizeof(struct lpfc_hba), GFP_KERNEL); - if (!phba) { - dev_err(&pdev->dev, "failed to allocate hba struct\n"); - return NULL; - } - - /* Set reference to PCI device in HBA structure */ - phba->pcidev = pdev; - - /* Assign an unused board number */ - phba->brd_no = lpfc_get_instance(); - if (phba->brd_no < 0) { - kfree(phba); - return NULL; - } - - spin_lock_init(&phba->ct_ev_lock); - INIT_LIST_HEAD(&phba->ct_ev_waiters); - - return phba; -} - -/** - * lpfc_hba_free - Free driver hba data structure with a device. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to free the driver hba data structure with an - * HBA device. - **/ -static void -lpfc_hba_free(struct lpfc_hba *phba) -{ - /* Release the driver assigned board number */ - idr_remove(&lpfc_hba_index, phba->brd_no); - - kfree(phba); - return; -} - -/** - * lpfc_create_shost - Create hba physical port with associated scsi host. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to create HBA physical port and associate a SCSI - * host with it. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_create_shost(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport; - struct Scsi_Host *shost; - - /* Initialize HBA FC structure */ - phba->fc_edtov = FF_DEF_EDTOV; - phba->fc_ratov = FF_DEF_RATOV; - phba->fc_altov = FF_DEF_ALTOV; - phba->fc_arbtov = FF_DEF_ARBTOV; - - atomic_set(&phba->sdev_cnt, 0); - vport = lpfc_create_port(phba, phba->brd_no, &phba->pcidev->dev); - if (!vport) - return -ENODEV; - - shost = lpfc_shost_from_vport(vport); - phba->pport = vport; - lpfc_debugfs_initialize(vport); - /* Put reference to SCSI host to driver's device private data */ - pci_set_drvdata(phba->pcidev, shost); - - return 0; -} - -/** - * lpfc_destroy_shost - Destroy hba physical port with associated scsi host. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to destroy HBA physical port and the associated - * SCSI host. - **/ -static void -lpfc_destroy_shost(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport = phba->pport; - - /* Destroy physical port that associated with the SCSI host */ - destroy_port(vport); - - return; -} - -/** - * lpfc_setup_bg - Setup Block guard structures and debug areas. - * @phba: pointer to lpfc hba data structure. - * @shost: the shost to be used to detect Block guard settings. - * - * This routine sets up the local Block guard protocol settings for @shost. - * This routine also allocates memory for debugging bg buffers. - **/ -static void -lpfc_setup_bg(struct lpfc_hba *phba, struct Scsi_Host *shost) -{ - int pagecnt = 10; - if (lpfc_prot_mask && lpfc_prot_guard) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "1478 Registering BlockGuard with the " - "SCSI layer\n"); - scsi_host_set_prot(shost, lpfc_prot_mask); - scsi_host_set_guard(shost, lpfc_prot_guard); - } - if (!_dump_buf_data) { - while (pagecnt) { - spin_lock_init(&_dump_buf_lock); - _dump_buf_data = - (char *) __get_free_pages(GFP_KERNEL, pagecnt); - if (_dump_buf_data) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9043 BLKGRD: allocated %d pages for " - "_dump_buf_data at 0x%p\n", - (1 << pagecnt), _dump_buf_data); - _dump_buf_data_order = pagecnt; - memset(_dump_buf_data, 0, - ((1 << PAGE_SHIFT) << pagecnt)); - break; - } else - --pagecnt; - } - if (!_dump_buf_data_order) - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9044 BLKGRD: ERROR unable to allocate " - "memory for hexdump\n"); - } else - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9045 BLKGRD: already allocated _dump_buf_data=0x%p" - "\n", _dump_buf_data); - if (!_dump_buf_dif) { - while (pagecnt) { - _dump_buf_dif = - (char *) __get_free_pages(GFP_KERNEL, pagecnt); - if (_dump_buf_dif) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9046 BLKGRD: allocated %d pages for " - "_dump_buf_dif at 0x%p\n", - (1 << pagecnt), _dump_buf_dif); - _dump_buf_dif_order = pagecnt; - memset(_dump_buf_dif, 0, - ((1 << PAGE_SHIFT) << pagecnt)); - break; - } else - --pagecnt; - } - if (!_dump_buf_dif_order) - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9047 BLKGRD: ERROR unable to allocate " - "memory for hexdump\n"); - } else - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9048 BLKGRD: already allocated _dump_buf_dif=0x%p\n", - _dump_buf_dif); -} - -/** - * lpfc_post_init_setup - Perform necessary device post initialization setup. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to perform all the necessary post initialization - * setup for the device. - **/ -static void -lpfc_post_init_setup(struct lpfc_hba *phba) -{ - struct Scsi_Host *shost; - struct lpfc_adapter_event_header adapter_event; - - /* Get the default values for Model Name and Description */ - lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); - - /* - * hba setup may have changed the hba_queue_depth so we need to - * adjust the value of can_queue. - */ - shost = pci_get_drvdata(phba->pcidev); - shost->can_queue = phba->cfg_hba_queue_depth - 10; - if (phba->sli3_options & LPFC_SLI3_BG_ENABLED) - lpfc_setup_bg(phba, shost); - - lpfc_host_attrib_init(shost); - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - spin_lock_irq(shost->host_lock); - lpfc_poll_start_timer(phba); - spin_unlock_irq(shost->host_lock); - } - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0428 Perform SCSI scan\n"); - /* Send board arrival event to upper layer */ - adapter_event.event_type = FC_REG_ADAPTER_EVENT; - adapter_event.subcategory = LPFC_EVENT_ARRIVAL; - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(adapter_event), - (char *) &adapter_event, - LPFC_NL_VENDOR_ID); - return; -} - -/** - * lpfc_sli_pci_mem_setup - Setup SLI3 HBA PCI memory space. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to set up the PCI device memory space for device - * with SLI-3 interface spec. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_sli_pci_mem_setup(struct lpfc_hba *phba) -{ - struct pci_dev *pdev; - unsigned long bar0map_len, bar2map_len; - int i, hbq_count; - void *ptr; - int error = -ENODEV; - - /* Obtain PCI device reference */ - if (!phba->pcidev) - return error; - else - pdev = phba->pcidev; - - /* Set the device DMA mask size */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0 - || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(64)) != 0) { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0 - || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(32)) != 0) { - return error; - } - } - - /* Get the bus address of Bar0 and Bar2 and the number of bytes - * required by each mapping. - */ - phba->pci_bar0_map = pci_resource_start(pdev, 0); - bar0map_len = pci_resource_len(pdev, 0); - - phba->pci_bar2_map = pci_resource_start(pdev, 2); - bar2map_len = pci_resource_len(pdev, 2); - - /* Map HBA SLIM to a kernel virtual address. */ - phba->slim_memmap_p = ioremap(phba->pci_bar0_map, bar0map_len); - if (!phba->slim_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLIM memory.\n"); - goto out; - } - - /* Map HBA Control Registers to a kernel virtual address. */ - phba->ctrl_regs_memmap_p = ioremap(phba->pci_bar2_map, bar2map_len); - if (!phba->ctrl_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for HBA control registers.\n"); - goto out_iounmap_slim; - } - - /* Allocate memory for SLI-2 structures */ - phba->slim2p.virt = dma_alloc_coherent(&pdev->dev, - SLI2_SLIM_SIZE, - &phba->slim2p.phys, - GFP_KERNEL); - if (!phba->slim2p.virt) - goto out_iounmap; - - memset(phba->slim2p.virt, 0, SLI2_SLIM_SIZE); - phba->mbox = phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, mbx); - phba->mbox_ext = (phba->slim2p.virt + - offsetof(struct lpfc_sli2_slim, mbx_ext_words)); - phba->pcb = (phba->slim2p.virt + offsetof(struct lpfc_sli2_slim, pcb)); - phba->IOCBs = (phba->slim2p.virt + - offsetof(struct lpfc_sli2_slim, IOCBs)); - - phba->hbqslimp.virt = dma_alloc_coherent(&pdev->dev, - lpfc_sli_hbq_size(), - &phba->hbqslimp.phys, - GFP_KERNEL); - if (!phba->hbqslimp.virt) - goto out_free_slim; - - hbq_count = lpfc_sli_hbq_count(); - ptr = phba->hbqslimp.virt; - for (i = 0; i < hbq_count; ++i) { - phba->hbqs[i].hbq_virt = ptr; - INIT_LIST_HEAD(&phba->hbqs[i].hbq_buffer_list); - ptr += (lpfc_hbq_defs[i]->entry_count * - sizeof(struct lpfc_hbq_entry)); - } - phba->hbqs[LPFC_ELS_HBQ].hbq_alloc_buffer = lpfc_els_hbq_alloc; - phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer = lpfc_els_hbq_free; - - memset(phba->hbqslimp.virt, 0, lpfc_sli_hbq_size()); - - INIT_LIST_HEAD(&phba->rb_pend_list); - - phba->MBslimaddr = phba->slim_memmap_p; - phba->HAregaddr = phba->ctrl_regs_memmap_p + HA_REG_OFFSET; - phba->CAregaddr = phba->ctrl_regs_memmap_p + CA_REG_OFFSET; - phba->HSregaddr = phba->ctrl_regs_memmap_p + HS_REG_OFFSET; - phba->HCregaddr = phba->ctrl_regs_memmap_p + HC_REG_OFFSET; - - return 0; - -out_free_slim: - dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, - phba->slim2p.virt, phba->slim2p.phys); -out_iounmap: - iounmap(phba->ctrl_regs_memmap_p); -out_iounmap_slim: - iounmap(phba->slim_memmap_p); -out: - return error; -} - -/** - * lpfc_sli_pci_mem_unset - Unset SLI3 HBA PCI memory space. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unset the PCI device memory space for device - * with SLI-3 interface spec. - **/ -static void -lpfc_sli_pci_mem_unset(struct lpfc_hba *phba) -{ - struct pci_dev *pdev; - - /* Obtain PCI device reference */ - if (!phba->pcidev) - return; - else - pdev = phba->pcidev; - - /* Free coherent DMA memory allocated */ - dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), - phba->hbqslimp.virt, phba->hbqslimp.phys); - dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, - phba->slim2p.virt, phba->slim2p.phys); - - /* I/O memory unmap */ - iounmap(phba->ctrl_regs_memmap_p); - iounmap(phba->slim_memmap_p); - - return; -} - -/** - * lpfc_sli4_post_status_check - Wait for SLI4 POST done and check status - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to wait for SLI4 device Power On Self Test (POST) - * done and check status. - * - * Return 0 if successful, otherwise -ENODEV. - **/ -int -lpfc_sli4_post_status_check(struct lpfc_hba *phba) -{ - struct lpfc_register portsmphr_reg, uerrlo_reg, uerrhi_reg; - struct lpfc_register reg_data; - int i, port_error = 0; - uint32_t if_type; - - memset(&portsmphr_reg, 0, sizeof(portsmphr_reg)); - memset(®_data, 0, sizeof(reg_data)); - if (!phba->sli4_hba.PSMPHRregaddr) - return -ENODEV; - - /* Wait up to 30 seconds for the SLI Port POST done and ready */ - for (i = 0; i < 3000; i++) { - if (lpfc_readl(phba->sli4_hba.PSMPHRregaddr, - &portsmphr_reg.word0) || - (bf_get(lpfc_port_smphr_perr, &portsmphr_reg))) { - /* Port has a fatal POST error, break out */ - port_error = -ENODEV; - break; - } - if (LPFC_POST_STAGE_PORT_READY == - bf_get(lpfc_port_smphr_port_status, &portsmphr_reg)) - break; - msleep(10); - } - - /* - * If there was a port error during POST, then don't proceed with - * other register reads as the data may not be valid. Just exit. - */ - if (port_error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1408 Port Failed POST - portsmphr=0x%x, " - "perr=x%x, sfi=x%x, nip=x%x, ipc=x%x, scr1=x%x, " - "scr2=x%x, hscratch=x%x, pstatus=x%x\n", - portsmphr_reg.word0, - bf_get(lpfc_port_smphr_perr, &portsmphr_reg), - bf_get(lpfc_port_smphr_sfi, &portsmphr_reg), - bf_get(lpfc_port_smphr_nip, &portsmphr_reg), - bf_get(lpfc_port_smphr_ipc, &portsmphr_reg), - bf_get(lpfc_port_smphr_scr1, &portsmphr_reg), - bf_get(lpfc_port_smphr_scr2, &portsmphr_reg), - bf_get(lpfc_port_smphr_host_scratch, &portsmphr_reg), - bf_get(lpfc_port_smphr_port_status, &portsmphr_reg)); - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2534 Device Info: SLIFamily=0x%x, " - "SLIRev=0x%x, IFType=0x%x, SLIHint_1=0x%x, " - "SLIHint_2=0x%x, FT=0x%x\n", - bf_get(lpfc_sli_intf_sli_family, - &phba->sli4_hba.sli_intf), - bf_get(lpfc_sli_intf_slirev, - &phba->sli4_hba.sli_intf), - bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf), - bf_get(lpfc_sli_intf_sli_hint1, - &phba->sli4_hba.sli_intf), - bf_get(lpfc_sli_intf_sli_hint2, - &phba->sli4_hba.sli_intf), - bf_get(lpfc_sli_intf_func_type, - &phba->sli4_hba.sli_intf)); - /* - * Check for other Port errors during the initialization - * process. Fail the load if the port did not come up - * correctly. - */ - if_type = bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf); - switch (if_type) { - case LPFC_SLI_INTF_IF_TYPE_0: - phba->sli4_hba.ue_mask_lo = - readl(phba->sli4_hba.u.if_type0.UEMASKLOregaddr); - phba->sli4_hba.ue_mask_hi = - readl(phba->sli4_hba.u.if_type0.UEMASKHIregaddr); - uerrlo_reg.word0 = - readl(phba->sli4_hba.u.if_type0.UERRLOregaddr); - uerrhi_reg.word0 = - readl(phba->sli4_hba.u.if_type0.UERRHIregaddr); - if ((~phba->sli4_hba.ue_mask_lo & uerrlo_reg.word0) || - (~phba->sli4_hba.ue_mask_hi & uerrhi_reg.word0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1422 Unrecoverable Error " - "Detected during POST " - "uerr_lo_reg=0x%x, " - "uerr_hi_reg=0x%x, " - "ue_mask_lo_reg=0x%x, " - "ue_mask_hi_reg=0x%x\n", - uerrlo_reg.word0, - uerrhi_reg.word0, - phba->sli4_hba.ue_mask_lo, - phba->sli4_hba.ue_mask_hi); - port_error = -ENODEV; - } - break; - case LPFC_SLI_INTF_IF_TYPE_2: - /* Final checks. The port status should be clean. */ - if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, - ®_data.word0) || - (bf_get(lpfc_sliport_status_err, ®_data) && - !bf_get(lpfc_sliport_status_rn, ®_data))) { - phba->work_status[0] = - readl(phba->sli4_hba.u.if_type2. - ERR1regaddr); - phba->work_status[1] = - readl(phba->sli4_hba.u.if_type2. - ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2888 Unrecoverable port error " - "following POST: port status reg " - "0x%x, port_smphr reg 0x%x, " - "error 1=0x%x, error 2=0x%x\n", - reg_data.word0, - portsmphr_reg.word0, - phba->work_status[0], - phba->work_status[1]); - port_error = -ENODEV; - } - break; - case LPFC_SLI_INTF_IF_TYPE_1: - default: - break; - } - } - return port_error; -} - -/** - * lpfc_sli4_bar0_register_memmap - Set up SLI4 BAR0 register memory map. - * @phba: pointer to lpfc hba data structure. - * @if_type: The SLI4 interface type getting configured. - * - * This routine is invoked to set up SLI4 BAR0 PCI config space register - * memory map. - **/ -static void -lpfc_sli4_bar0_register_memmap(struct lpfc_hba *phba, uint32_t if_type) -{ - switch (if_type) { - case LPFC_SLI_INTF_IF_TYPE_0: - phba->sli4_hba.u.if_type0.UERRLOregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_LO; - phba->sli4_hba.u.if_type0.UERRHIregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_UERR_STATUS_HI; - phba->sli4_hba.u.if_type0.UEMASKLOregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_UE_MASK_LO; - phba->sli4_hba.u.if_type0.UEMASKHIregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_UE_MASK_HI; - phba->sli4_hba.SLIINTFregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF; - break; - case LPFC_SLI_INTF_IF_TYPE_2: - phba->sli4_hba.u.if_type2.ERR1regaddr = - phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_ER1_OFFSET; - phba->sli4_hba.u.if_type2.ERR2regaddr = - phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_ER2_OFFSET; - phba->sli4_hba.u.if_type2.CTRLregaddr = - phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_CTL_OFFSET; - phba->sli4_hba.u.if_type2.STATUSregaddr = - phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_STA_OFFSET; - phba->sli4_hba.SLIINTFregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_SLI_INTF; - phba->sli4_hba.PSMPHRregaddr = - phba->sli4_hba.conf_regs_memmap_p + - LPFC_CTL_PORT_SEM_OFFSET; - phba->sli4_hba.RQDBregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_RQ_DOORBELL; - phba->sli4_hba.WQDBregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_WQ_DOORBELL; - phba->sli4_hba.EQCQDBregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_EQCQ_DOORBELL; - phba->sli4_hba.MQDBregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_MQ_DOORBELL; - phba->sli4_hba.BMBXregaddr = - phba->sli4_hba.conf_regs_memmap_p + LPFC_BMBX; - break; - case LPFC_SLI_INTF_IF_TYPE_1: - default: - dev_printk(KERN_ERR, &phba->pcidev->dev, - "FATAL - unsupported SLI4 interface type - %d\n", - if_type); - break; - } -} - -/** - * lpfc_sli4_bar1_register_memmap - Set up SLI4 BAR1 register memory map. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to set up SLI4 BAR1 control status register (CSR) - * memory map. - **/ -static void -lpfc_sli4_bar1_register_memmap(struct lpfc_hba *phba) -{ - phba->sli4_hba.PSMPHRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_SLIPORT_IF0_SMPHR; - phba->sli4_hba.ISRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_ISR0; - phba->sli4_hba.IMRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_IMR0; - phba->sli4_hba.ISCRregaddr = phba->sli4_hba.ctrl_regs_memmap_p + - LPFC_HST_ISCR0; -} - -/** - * lpfc_sli4_bar2_register_memmap - Set up SLI4 BAR2 register memory map. - * @phba: pointer to lpfc hba data structure. - * @vf: virtual function number - * - * This routine is invoked to set up SLI4 BAR2 doorbell register memory map - * based on the given viftual function number, @vf. - * - * Return 0 if successful, otherwise -ENODEV. - **/ -static int -lpfc_sli4_bar2_register_memmap(struct lpfc_hba *phba, uint32_t vf) -{ - if (vf > LPFC_VIR_FUNC_MAX) - return -ENODEV; - - phba->sli4_hba.RQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + - vf * LPFC_VFR_PAGE_SIZE + LPFC_RQ_DOORBELL); - phba->sli4_hba.WQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + - vf * LPFC_VFR_PAGE_SIZE + LPFC_WQ_DOORBELL); - phba->sli4_hba.EQCQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + - vf * LPFC_VFR_PAGE_SIZE + LPFC_EQCQ_DOORBELL); - phba->sli4_hba.MQDBregaddr = (phba->sli4_hba.drbl_regs_memmap_p + - vf * LPFC_VFR_PAGE_SIZE + LPFC_MQ_DOORBELL); - phba->sli4_hba.BMBXregaddr = (phba->sli4_hba.drbl_regs_memmap_p + - vf * LPFC_VFR_PAGE_SIZE + LPFC_BMBX); - return 0; -} - -/** - * lpfc_create_bootstrap_mbox - Create the bootstrap mailbox - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to create the bootstrap mailbox - * region consistent with the SLI-4 interface spec. This - * routine allocates all memory necessary to communicate - * mailbox commands to the port and sets up all alignment - * needs. No locks are expected to be held when calling - * this routine. - * - * Return codes - * 0 - successful - * -ENOMEM - could not allocated memory. - **/ -static int -lpfc_create_bootstrap_mbox(struct lpfc_hba *phba) -{ - uint32_t bmbx_size; - struct lpfc_dmabuf *dmabuf; - struct dma_address *dma_address; - uint32_t pa_addr; - uint64_t phys_addr; - - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!dmabuf) - return -ENOMEM; - - /* - * The bootstrap mailbox region is comprised of 2 parts - * plus an alignment restriction of 16 bytes. - */ - bmbx_size = sizeof(struct lpfc_bmbx_create) + (LPFC_ALIGN_16_BYTE - 1); - dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, - bmbx_size, - &dmabuf->phys, - GFP_KERNEL); - if (!dmabuf->virt) { - kfree(dmabuf); - return -ENOMEM; - } - memset(dmabuf->virt, 0, bmbx_size); - - /* - * Initialize the bootstrap mailbox pointers now so that the register - * operations are simple later. The mailbox dma address is required - * to be 16-byte aligned. Also align the virtual memory as each - * maibox is copied into the bmbx mailbox region before issuing the - * command to the port. - */ - phba->sli4_hba.bmbx.dmabuf = dmabuf; - phba->sli4_hba.bmbx.bmbx_size = bmbx_size; - - phba->sli4_hba.bmbx.avirt = PTR_ALIGN(dmabuf->virt, - LPFC_ALIGN_16_BYTE); - phba->sli4_hba.bmbx.aphys = ALIGN(dmabuf->phys, - LPFC_ALIGN_16_BYTE); - - /* - * Set the high and low physical addresses now. The SLI4 alignment - * requirement is 16 bytes and the mailbox is posted to the port - * as two 30-bit addresses. The other data is a bit marking whether - * the 30-bit address is the high or low address. - * Upcast bmbx aphys to 64bits so shift instruction compiles - * clean on 32 bit machines. - */ - dma_address = &phba->sli4_hba.bmbx.dma_address; - phys_addr = (uint64_t)phba->sli4_hba.bmbx.aphys; - pa_addr = (uint32_t) ((phys_addr >> 34) & 0x3fffffff); - dma_address->addr_hi = (uint32_t) ((pa_addr << 2) | - LPFC_BMBX_BIT1_ADDR_HI); - - pa_addr = (uint32_t) ((phba->sli4_hba.bmbx.aphys >> 4) & 0x3fffffff); - dma_address->addr_lo = (uint32_t) ((pa_addr << 2) | - LPFC_BMBX_BIT1_ADDR_LO); - return 0; -} - -/** - * lpfc_destroy_bootstrap_mbox - Destroy all bootstrap mailbox resources - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to teardown the bootstrap mailbox - * region and release all host resources. This routine requires - * the caller to ensure all mailbox commands recovered, no - * additional mailbox comands are sent, and interrupts are disabled - * before calling this routine. - * - **/ -static void -lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba) -{ - dma_free_coherent(&phba->pcidev->dev, - phba->sli4_hba.bmbx.bmbx_size, - phba->sli4_hba.bmbx.dmabuf->virt, - phba->sli4_hba.bmbx.dmabuf->phys); - - kfree(phba->sli4_hba.bmbx.dmabuf); - memset(&phba->sli4_hba.bmbx, 0, sizeof(struct lpfc_bmbx)); -} - -/** - * lpfc_sli4_read_config - Get the config parameters. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to read the configuration parameters from the HBA. - * The configuration parameters are used to set the base and maximum values - * for RPI's XRI's VPI's VFI's and FCFIs. These values also affect the resource - * allocation for the port. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. - **/ -int -lpfc_sli4_read_config(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *pmb; - struct lpfc_mbx_read_config *rd_config; - union lpfc_sli4_cfg_shdr *shdr; - uint32_t shdr_status, shdr_add_status; - struct lpfc_mbx_get_func_cfg *get_func_cfg; - struct lpfc_rsrc_desc_fcfcoe *desc; - uint32_t desc_count; - int length, i, rc = 0; - - pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2011 Unable to allocate memory for issuing " - "SLI_CONFIG_SPECIAL mailbox command\n"); - return -ENOMEM; - } - - lpfc_read_config(phba, pmb); - - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2012 Mailbox failed , mbxCmd x%x " - "READ_CONFIG, mbxStatus x%x\n", - bf_get(lpfc_mqe_command, &pmb->u.mqe), - bf_get(lpfc_mqe_status, &pmb->u.mqe)); - rc = -EIO; - } else { - rd_config = &pmb->u.mqe.un.rd_config; - if (bf_get(lpfc_mbx_rd_conf_lnk_ldv, rd_config)) { - phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL; - phba->sli4_hba.lnk_info.lnk_tp = - bf_get(lpfc_mbx_rd_conf_lnk_type, rd_config); - phba->sli4_hba.lnk_info.lnk_no = - bf_get(lpfc_mbx_rd_conf_lnk_numb, rd_config); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3081 lnk_type:%d, lnk_numb:%d\n", - phba->sli4_hba.lnk_info.lnk_tp, - phba->sli4_hba.lnk_info.lnk_no); - } else - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3082 Mailbox (x%x) returned ldv:x0\n", - bf_get(lpfc_mqe_command, &pmb->u.mqe)); - phba->sli4_hba.extents_in_use = - bf_get(lpfc_mbx_rd_conf_extnts_inuse, rd_config); - phba->sli4_hba.max_cfg_param.max_xri = - bf_get(lpfc_mbx_rd_conf_xri_count, rd_config); - phba->sli4_hba.max_cfg_param.xri_base = - bf_get(lpfc_mbx_rd_conf_xri_base, rd_config); - phba->sli4_hba.max_cfg_param.max_vpi = - bf_get(lpfc_mbx_rd_conf_vpi_count, rd_config); - phba->sli4_hba.max_cfg_param.vpi_base = - bf_get(lpfc_mbx_rd_conf_vpi_base, rd_config); - phba->sli4_hba.max_cfg_param.max_rpi = - bf_get(lpfc_mbx_rd_conf_rpi_count, rd_config); - phba->sli4_hba.max_cfg_param.rpi_base = - bf_get(lpfc_mbx_rd_conf_rpi_base, rd_config); - phba->sli4_hba.max_cfg_param.max_vfi = - bf_get(lpfc_mbx_rd_conf_vfi_count, rd_config); - phba->sli4_hba.max_cfg_param.vfi_base = - bf_get(lpfc_mbx_rd_conf_vfi_base, rd_config); - phba->sli4_hba.max_cfg_param.max_fcfi = - bf_get(lpfc_mbx_rd_conf_fcfi_count, rd_config); - phba->sli4_hba.max_cfg_param.max_eq = - bf_get(lpfc_mbx_rd_conf_eq_count, rd_config); - phba->sli4_hba.max_cfg_param.max_rq = - bf_get(lpfc_mbx_rd_conf_rq_count, rd_config); - phba->sli4_hba.max_cfg_param.max_wq = - bf_get(lpfc_mbx_rd_conf_wq_count, rd_config); - phba->sli4_hba.max_cfg_param.max_cq = - bf_get(lpfc_mbx_rd_conf_cq_count, rd_config); - phba->lmt = bf_get(lpfc_mbx_rd_conf_lmt, rd_config); - phba->sli4_hba.next_xri = phba->sli4_hba.max_cfg_param.xri_base; - phba->vpi_base = phba->sli4_hba.max_cfg_param.vpi_base; - phba->vfi_base = phba->sli4_hba.max_cfg_param.vfi_base; - phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ? - (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; - phba->max_vports = phba->max_vpi; - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2003 cfg params Extents? %d " - "XRI(B:%d M:%d), " - "VPI(B:%d M:%d) " - "VFI(B:%d M:%d) " - "RPI(B:%d M:%d) " - "FCFI(Count:%d)\n", - phba->sli4_hba.extents_in_use, - phba->sli4_hba.max_cfg_param.xri_base, - phba->sli4_hba.max_cfg_param.max_xri, - phba->sli4_hba.max_cfg_param.vpi_base, - phba->sli4_hba.max_cfg_param.max_vpi, - phba->sli4_hba.max_cfg_param.vfi_base, - phba->sli4_hba.max_cfg_param.max_vfi, - phba->sli4_hba.max_cfg_param.rpi_base, - phba->sli4_hba.max_cfg_param.max_rpi, - phba->sli4_hba.max_cfg_param.max_fcfi); - } - - if (rc) - goto read_cfg_out; - - /* Reset the DFT_HBA_Q_DEPTH to the max xri */ - if (phba->cfg_hba_queue_depth > - (phba->sli4_hba.max_cfg_param.max_xri - - lpfc_sli4_get_els_iocb_cnt(phba))) - phba->cfg_hba_queue_depth = - phba->sli4_hba.max_cfg_param.max_xri - - lpfc_sli4_get_els_iocb_cnt(phba); - - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_IF_TYPE_2) - goto read_cfg_out; - - /* get the pf# and vf# for SLI4 if_type 2 port */ - length = (sizeof(struct lpfc_mbx_get_func_cfg) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, pmb, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG, - length, LPFC_SLI4_MBX_EMBED); - - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) - &pmb->u.mqe.un.sli4_config.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc || shdr_status || shdr_add_status) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3026 Mailbox failed , mbxCmd x%x " - "GET_FUNCTION_CONFIG, mbxStatus x%x\n", - bf_get(lpfc_mqe_command, &pmb->u.mqe), - bf_get(lpfc_mqe_status, &pmb->u.mqe)); - rc = -EIO; - goto read_cfg_out; - } - - /* search for fc_fcoe resrouce descriptor */ - get_func_cfg = &pmb->u.mqe.un.get_func_cfg; - desc_count = get_func_cfg->func_cfg.rsrc_desc_count; - - for (i = 0; i < LPFC_RSRC_DESC_MAX_NUM; i++) { - desc = (struct lpfc_rsrc_desc_fcfcoe *) - &get_func_cfg->func_cfg.desc[i]; - if (LPFC_RSRC_DESC_TYPE_FCFCOE == - bf_get(lpfc_rsrc_desc_pcie_type, desc)) { - phba->sli4_hba.iov.pf_number = - bf_get(lpfc_rsrc_desc_fcfcoe_pfnum, desc); - phba->sli4_hba.iov.vf_number = - bf_get(lpfc_rsrc_desc_fcfcoe_vfnum, desc); - break; - } - } - - if (i < LPFC_RSRC_DESC_MAX_NUM) - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3027 GET_FUNCTION_CONFIG: pf_number:%d, " - "vf_number:%d\n", phba->sli4_hba.iov.pf_number, - phba->sli4_hba.iov.vf_number); - else { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3028 GET_FUNCTION_CONFIG: failed to find " - "Resrouce Descriptor:x%x\n", - LPFC_RSRC_DESC_TYPE_FCFCOE); - rc = -EIO; - } - -read_cfg_out: - mempool_free(pmb, phba->mbox_mem_pool); - return rc; -} - -/** - * lpfc_setup_endian_order - Write endian order to an SLI4 if_type 0 port. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to setup the port-side endian order when - * the port if_type is 0. This routine has no function for other - * if_types. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. - **/ -static int -lpfc_setup_endian_order(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *mboxq; - uint32_t if_type, rc = 0; - uint32_t endian_mb_data[2] = {HOST_ENDIAN_LOW_WORD0, - HOST_ENDIAN_HIGH_WORD1}; - - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - switch (if_type) { - case LPFC_SLI_INTF_IF_TYPE_0: - mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0492 Unable to allocate memory for " - "issuing SLI_CONFIG_SPECIAL mailbox " - "command\n"); - return -ENOMEM; - } - - /* - * The SLI4_CONFIG_SPECIAL mailbox command requires the first - * two words to contain special data values and no other data. - */ - memset(mboxq, 0, sizeof(LPFC_MBOXQ_t)); - memcpy(&mboxq->u.mqe, &endian_mb_data, sizeof(endian_mb_data)); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0493 SLI_CONFIG_SPECIAL mailbox " - "failed with status x%x\n", - rc); - rc = -EIO; - } - mempool_free(mboxq, phba->mbox_mem_pool); - break; - case LPFC_SLI_INTF_IF_TYPE_2: - case LPFC_SLI_INTF_IF_TYPE_1: - default: - break; - } - return rc; -} - -/** - * lpfc_sli4_queue_verify - Verify and update EQ and CQ counts - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to check the user settable queue counts for EQs and - * CQs. after this routine is called the counts will be set to valid values that - * adhere to the constraints of the system's interrupt vectors and the port's - * queue resources. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - **/ -static int -lpfc_sli4_queue_verify(struct lpfc_hba *phba) -{ - int cfg_fcp_wq_count; - int cfg_fcp_eq_count; - - /* - * Sanity check for confiugred queue parameters against the run-time - * device parameters - */ - - /* Sanity check on FCP fast-path WQ parameters */ - cfg_fcp_wq_count = phba->cfg_fcp_wq_count; - if (cfg_fcp_wq_count > - (phba->sli4_hba.max_cfg_param.max_wq - LPFC_SP_WQN_DEF)) { - cfg_fcp_wq_count = phba->sli4_hba.max_cfg_param.max_wq - - LPFC_SP_WQN_DEF; - if (cfg_fcp_wq_count < LPFC_FP_WQN_MIN) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2581 Not enough WQs (%d) from " - "the pci function for supporting " - "FCP WQs (%d)\n", - phba->sli4_hba.max_cfg_param.max_wq, - phba->cfg_fcp_wq_count); - goto out_error; - } - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2582 Not enough WQs (%d) from the pci " - "function for supporting the requested " - "FCP WQs (%d), the actual FCP WQs can " - "be supported: %d\n", - phba->sli4_hba.max_cfg_param.max_wq, - phba->cfg_fcp_wq_count, cfg_fcp_wq_count); - } - /* The actual number of FCP work queues adopted */ - phba->cfg_fcp_wq_count = cfg_fcp_wq_count; - - /* Sanity check on FCP fast-path EQ parameters */ - cfg_fcp_eq_count = phba->cfg_fcp_eq_count; - if (cfg_fcp_eq_count > - (phba->sli4_hba.max_cfg_param.max_eq - LPFC_SP_EQN_DEF)) { - cfg_fcp_eq_count = phba->sli4_hba.max_cfg_param.max_eq - - LPFC_SP_EQN_DEF; - if (cfg_fcp_eq_count < LPFC_FP_EQN_MIN) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2574 Not enough EQs (%d) from the " - "pci function for supporting FCP " - "EQs (%d)\n", - phba->sli4_hba.max_cfg_param.max_eq, - phba->cfg_fcp_eq_count); - goto out_error; - } - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2575 Not enough EQs (%d) from the pci " - "function for supporting the requested " - "FCP EQs (%d), the actual FCP EQs can " - "be supported: %d\n", - phba->sli4_hba.max_cfg_param.max_eq, - phba->cfg_fcp_eq_count, cfg_fcp_eq_count); - } - /* It does not make sense to have more EQs than WQs */ - if (cfg_fcp_eq_count > phba->cfg_fcp_wq_count) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2593 The FCP EQ count(%d) cannot be greater " - "than the FCP WQ count(%d), limiting the " - "FCP EQ count to %d\n", cfg_fcp_eq_count, - phba->cfg_fcp_wq_count, - phba->cfg_fcp_wq_count); - cfg_fcp_eq_count = phba->cfg_fcp_wq_count; - } - /* The actual number of FCP event queues adopted */ - phba->cfg_fcp_eq_count = cfg_fcp_eq_count; - /* The overall number of event queues used */ - phba->sli4_hba.cfg_eqn = phba->cfg_fcp_eq_count + LPFC_SP_EQN_DEF; - - /* Get EQ depth from module parameter, fake the default for now */ - phba->sli4_hba.eq_esize = LPFC_EQE_SIZE_4B; - phba->sli4_hba.eq_ecount = LPFC_EQE_DEF_COUNT; - - /* Get CQ depth from module parameter, fake the default for now */ - phba->sli4_hba.cq_esize = LPFC_CQE_SIZE; - phba->sli4_hba.cq_ecount = LPFC_CQE_DEF_COUNT; - - return 0; -out_error: - return -ENOMEM; -} - -/** - * lpfc_sli4_queue_create - Create all the SLI4 queues - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to allocate all the SLI4 queues for the FCoE HBA - * operation. For each SLI4 queue type, the parameters such as queue entry - * count (queue depth) shall be taken from the module parameter. For now, - * we just use some constant number as place holder. - * - * Return codes - * 0 - sucessful - * -ENOMEM - No availble memory - * -EIO - The mailbox failed to complete successfully. - **/ -int -lpfc_sli4_queue_create(struct lpfc_hba *phba) -{ - struct lpfc_queue *qdesc; - int fcp_eqidx, fcp_cqidx, fcp_wqidx; - - /* - * Create Event Queues (EQs) - */ - - /* Create slow path event queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, - phba->sli4_hba.eq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0496 Failed allocate slow-path EQ\n"); - goto out_error; - } - phba->sli4_hba.sp_eq = qdesc; - - /* - * Create fast-path FCP Event Queue(s). The cfg_fcp_eq_count can be - * zero whenever there is exactly one interrupt vector. This is not - * an error. - */ - if (phba->cfg_fcp_eq_count) { - phba->sli4_hba.fp_eq = kzalloc((sizeof(struct lpfc_queue *) * - phba->cfg_fcp_eq_count), GFP_KERNEL); - if (!phba->sli4_hba.fp_eq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2576 Failed allocate memory for " - "fast-path EQ record array\n"); - goto out_free_sp_eq; - } - } - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.eq_esize, - phba->sli4_hba.eq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0497 Failed allocate fast-path EQ\n"); - goto out_free_fp_eq; - } - phba->sli4_hba.fp_eq[fcp_eqidx] = qdesc; - } - - /* - * Create Complete Queues (CQs) - */ - - /* Create slow-path Mailbox Command Complete Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0500 Failed allocate slow-path mailbox CQ\n"); - goto out_free_fp_eq; - } - phba->sli4_hba.mbx_cq = qdesc; - - /* Create slow-path ELS Complete Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0501 Failed allocate slow-path ELS CQ\n"); - goto out_free_mbx_cq; - } - phba->sli4_hba.els_cq = qdesc; - - - /* - * Create fast-path FCP Completion Queue(s), one-to-one with FCP EQs. - * If there are no FCP EQs then create exactly one FCP CQ. - */ - if (phba->cfg_fcp_eq_count) - phba->sli4_hba.fcp_cq = kzalloc((sizeof(struct lpfc_queue *) * - phba->cfg_fcp_eq_count), - GFP_KERNEL); - else - phba->sli4_hba.fcp_cq = kzalloc(sizeof(struct lpfc_queue *), - GFP_KERNEL); - if (!phba->sli4_hba.fcp_cq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2577 Failed allocate memory for fast-path " - "CQ record array\n"); - goto out_free_els_cq; - } - fcp_cqidx = 0; - do { - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.cq_esize, - phba->sli4_hba.cq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0499 Failed allocate fast-path FCP " - "CQ (%d)\n", fcp_cqidx); - goto out_free_fcp_cq; - } - phba->sli4_hba.fcp_cq[fcp_cqidx] = qdesc; - } while (++fcp_cqidx < phba->cfg_fcp_eq_count); - - /* Create Mailbox Command Queue */ - phba->sli4_hba.mq_esize = LPFC_MQE_SIZE; - phba->sli4_hba.mq_ecount = LPFC_MQE_DEF_COUNT; - - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.mq_esize, - phba->sli4_hba.mq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0505 Failed allocate slow-path MQ\n"); - goto out_free_fcp_cq; - } - phba->sli4_hba.mbx_wq = qdesc; - - /* - * Create all the Work Queues (WQs) - */ - phba->sli4_hba.wq_esize = LPFC_WQE_SIZE; - phba->sli4_hba.wq_ecount = LPFC_WQE_DEF_COUNT; - - /* Create slow-path ELS Work Queue */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, - phba->sli4_hba.wq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0504 Failed allocate slow-path ELS WQ\n"); - goto out_free_mbx_wq; - } - phba->sli4_hba.els_wq = qdesc; - - /* Create fast-path FCP Work Queue(s) */ - phba->sli4_hba.fcp_wq = kzalloc((sizeof(struct lpfc_queue *) * - phba->cfg_fcp_wq_count), GFP_KERNEL); - if (!phba->sli4_hba.fcp_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2578 Failed allocate memory for fast-path " - "WQ record array\n"); - goto out_free_els_wq; - } - for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.wq_esize, - phba->sli4_hba.wq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0503 Failed allocate fast-path FCP " - "WQ (%d)\n", fcp_wqidx); - goto out_free_fcp_wq; - } - phba->sli4_hba.fcp_wq[fcp_wqidx] = qdesc; - } - - /* - * Create Receive Queue (RQ) - */ - phba->sli4_hba.rq_esize = LPFC_RQE_SIZE; - phba->sli4_hba.rq_ecount = LPFC_RQE_DEF_COUNT; - - /* Create Receive Queue for header */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize, - phba->sli4_hba.rq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0506 Failed allocate receive HRQ\n"); - goto out_free_fcp_wq; - } - phba->sli4_hba.hdr_rq = qdesc; - - /* Create Receive Queue for data */ - qdesc = lpfc_sli4_queue_alloc(phba, phba->sli4_hba.rq_esize, - phba->sli4_hba.rq_ecount); - if (!qdesc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0507 Failed allocate receive DRQ\n"); - goto out_free_hdr_rq; - } - phba->sli4_hba.dat_rq = qdesc; - - return 0; - -out_free_hdr_rq: - lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq); - phba->sli4_hba.hdr_rq = NULL; -out_free_fcp_wq: - for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) { - lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_wqidx]); - phba->sli4_hba.fcp_wq[fcp_wqidx] = NULL; - } - kfree(phba->sli4_hba.fcp_wq); - phba->sli4_hba.fcp_wq = NULL; -out_free_els_wq: - lpfc_sli4_queue_free(phba->sli4_hba.els_wq); - phba->sli4_hba.els_wq = NULL; -out_free_mbx_wq: - lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq); - phba->sli4_hba.mbx_wq = NULL; -out_free_fcp_cq: - for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) { - lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_cqidx]); - phba->sli4_hba.fcp_cq[fcp_cqidx] = NULL; - } - kfree(phba->sli4_hba.fcp_cq); - phba->sli4_hba.fcp_cq = NULL; -out_free_els_cq: - lpfc_sli4_queue_free(phba->sli4_hba.els_cq); - phba->sli4_hba.els_cq = NULL; -out_free_mbx_cq: - lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq); - phba->sli4_hba.mbx_cq = NULL; -out_free_fp_eq: - for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) { - lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_eqidx]); - phba->sli4_hba.fp_eq[fcp_eqidx] = NULL; - } - kfree(phba->sli4_hba.fp_eq); - phba->sli4_hba.fp_eq = NULL; -out_free_sp_eq: - lpfc_sli4_queue_free(phba->sli4_hba.sp_eq); - phba->sli4_hba.sp_eq = NULL; -out_error: - return -ENOMEM; -} - -/** - * lpfc_sli4_queue_destroy - Destroy all the SLI4 queues - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to release all the SLI4 queues with the FCoE HBA - * operation. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. - **/ -void -lpfc_sli4_queue_destroy(struct lpfc_hba *phba) -{ - int fcp_qidx; - - /* Release mailbox command work queue */ - lpfc_sli4_queue_free(phba->sli4_hba.mbx_wq); - phba->sli4_hba.mbx_wq = NULL; - - /* Release ELS work queue */ - lpfc_sli4_queue_free(phba->sli4_hba.els_wq); - phba->sli4_hba.els_wq = NULL; - - /* Release FCP work queue */ - if (phba->sli4_hba.fcp_wq != NULL) - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; - fcp_qidx++) - lpfc_sli4_queue_free(phba->sli4_hba.fcp_wq[fcp_qidx]); - kfree(phba->sli4_hba.fcp_wq); - phba->sli4_hba.fcp_wq = NULL; - - /* Release unsolicited receive queue */ - lpfc_sli4_queue_free(phba->sli4_hba.hdr_rq); - phba->sli4_hba.hdr_rq = NULL; - lpfc_sli4_queue_free(phba->sli4_hba.dat_rq); - phba->sli4_hba.dat_rq = NULL; - - /* Release ELS complete queue */ - lpfc_sli4_queue_free(phba->sli4_hba.els_cq); - phba->sli4_hba.els_cq = NULL; - - /* Release mailbox command complete queue */ - lpfc_sli4_queue_free(phba->sli4_hba.mbx_cq); - phba->sli4_hba.mbx_cq = NULL; - - /* Release FCP response complete queue */ - fcp_qidx = 0; - if (phba->sli4_hba.fcp_cq != NULL) - do - lpfc_sli4_queue_free(phba->sli4_hba.fcp_cq[fcp_qidx]); - while (++fcp_qidx < phba->cfg_fcp_eq_count); - kfree(phba->sli4_hba.fcp_cq); - phba->sli4_hba.fcp_cq = NULL; - - /* Release fast-path event queue */ - if (phba->sli4_hba.fp_eq != NULL) - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; - fcp_qidx++) - lpfc_sli4_queue_free(phba->sli4_hba.fp_eq[fcp_qidx]); - kfree(phba->sli4_hba.fp_eq); - phba->sli4_hba.fp_eq = NULL; - - /* Release slow-path event queue */ - lpfc_sli4_queue_free(phba->sli4_hba.sp_eq); - phba->sli4_hba.sp_eq = NULL; - - return; -} - -/** - * lpfc_sli4_queue_setup - Set up all the SLI4 queues - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to set up all the SLI4 queues for the FCoE HBA - * operation. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. - **/ -int -lpfc_sli4_queue_setup(struct lpfc_hba *phba) -{ - int rc = -ENOMEM; - int fcp_eqidx, fcp_cqidx, fcp_wqidx; - int fcp_cq_index = 0; - - /* - * Set up Event Queues (EQs) - */ - - /* Set up slow-path event queue */ - if (!phba->sli4_hba.sp_eq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0520 Slow-path EQ not allocated\n"); - goto out_error; - } - rc = lpfc_eq_create(phba, phba->sli4_hba.sp_eq, - LPFC_SP_DEF_IMAX); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0521 Failed setup of slow-path EQ: " - "rc = 0x%x\n", rc); - goto out_error; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2583 Slow-path EQ setup: queue-id=%d\n", - phba->sli4_hba.sp_eq->queue_id); - - /* Set up fast-path event queue */ - if (phba->cfg_fcp_eq_count && !phba->sli4_hba.fp_eq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3147 Fast-path EQs not allocated\n"); - rc = -ENOMEM; - goto out_destroy_sp_eq; - } - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { - if (!phba->sli4_hba.fp_eq[fcp_eqidx]) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0522 Fast-path EQ (%d) not " - "allocated\n", fcp_eqidx); - rc = -ENOMEM; - goto out_destroy_fp_eq; - } - rc = lpfc_eq_create(phba, phba->sli4_hba.fp_eq[fcp_eqidx], - phba->cfg_fcp_imax); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0523 Failed setup of fast-path EQ " - "(%d), rc = 0x%x\n", fcp_eqidx, rc); - goto out_destroy_fp_eq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2584 Fast-path EQ setup: " - "queue[%d]-id=%d\n", fcp_eqidx, - phba->sli4_hba.fp_eq[fcp_eqidx]->queue_id); - } - - /* - * Set up Complete Queues (CQs) - */ - - /* Set up slow-path MBOX Complete Queue as the first CQ */ - if (!phba->sli4_hba.mbx_cq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0528 Mailbox CQ not allocated\n"); - rc = -ENOMEM; - goto out_destroy_fp_eq; - } - rc = lpfc_cq_create(phba, phba->sli4_hba.mbx_cq, phba->sli4_hba.sp_eq, - LPFC_MCQ, LPFC_MBOX); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0529 Failed setup of slow-path mailbox CQ: " - "rc = 0x%x\n", rc); - goto out_destroy_fp_eq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2585 MBX CQ setup: cq-id=%d, parent eq-id=%d\n", - phba->sli4_hba.mbx_cq->queue_id, - phba->sli4_hba.sp_eq->queue_id); - - /* Set up slow-path ELS Complete Queue */ - if (!phba->sli4_hba.els_cq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0530 ELS CQ not allocated\n"); - rc = -ENOMEM; - goto out_destroy_mbx_cq; - } - rc = lpfc_cq_create(phba, phba->sli4_hba.els_cq, phba->sli4_hba.sp_eq, - LPFC_WCQ, LPFC_ELS); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0531 Failed setup of slow-path ELS CQ: " - "rc = 0x%x\n", rc); - goto out_destroy_mbx_cq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2586 ELS CQ setup: cq-id=%d, parent eq-id=%d\n", - phba->sli4_hba.els_cq->queue_id, - phba->sli4_hba.sp_eq->queue_id); - - /* Set up fast-path FCP Response Complete Queue */ - if (!phba->sli4_hba.fcp_cq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3148 Fast-path FCP CQ array not " - "allocated\n"); - rc = -ENOMEM; - goto out_destroy_els_cq; - } - fcp_cqidx = 0; - do { - if (!phba->sli4_hba.fcp_cq[fcp_cqidx]) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0526 Fast-path FCP CQ (%d) not " - "allocated\n", fcp_cqidx); - rc = -ENOMEM; - goto out_destroy_fcp_cq; - } - if (phba->cfg_fcp_eq_count) - rc = lpfc_cq_create(phba, - phba->sli4_hba.fcp_cq[fcp_cqidx], - phba->sli4_hba.fp_eq[fcp_cqidx], - LPFC_WCQ, LPFC_FCP); - else - rc = lpfc_cq_create(phba, - phba->sli4_hba.fcp_cq[fcp_cqidx], - phba->sli4_hba.sp_eq, - LPFC_WCQ, LPFC_FCP); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0527 Failed setup of fast-path FCP " - "CQ (%d), rc = 0x%x\n", fcp_cqidx, rc); - goto out_destroy_fcp_cq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2588 FCP CQ setup: cq[%d]-id=%d, " - "parent %seq[%d]-id=%d\n", - fcp_cqidx, - phba->sli4_hba.fcp_cq[fcp_cqidx]->queue_id, - (phba->cfg_fcp_eq_count) ? "" : "sp_", - fcp_cqidx, - (phba->cfg_fcp_eq_count) ? - phba->sli4_hba.fp_eq[fcp_cqidx]->queue_id : - phba->sli4_hba.sp_eq->queue_id); - } while (++fcp_cqidx < phba->cfg_fcp_eq_count); - - /* - * Set up all the Work Queues (WQs) - */ - - /* Set up Mailbox Command Queue */ - if (!phba->sli4_hba.mbx_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0538 Slow-path MQ not allocated\n"); - rc = -ENOMEM; - goto out_destroy_fcp_cq; - } - rc = lpfc_mq_create(phba, phba->sli4_hba.mbx_wq, - phba->sli4_hba.mbx_cq, LPFC_MBOX); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0539 Failed setup of slow-path MQ: " - "rc = 0x%x\n", rc); - goto out_destroy_fcp_cq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2589 MBX MQ setup: wq-id=%d, parent cq-id=%d\n", - phba->sli4_hba.mbx_wq->queue_id, - phba->sli4_hba.mbx_cq->queue_id); - - /* Set up slow-path ELS Work Queue */ - if (!phba->sli4_hba.els_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0536 Slow-path ELS WQ not allocated\n"); - rc = -ENOMEM; - goto out_destroy_mbx_wq; - } - rc = lpfc_wq_create(phba, phba->sli4_hba.els_wq, - phba->sli4_hba.els_cq, LPFC_ELS); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0537 Failed setup of slow-path ELS WQ: " - "rc = 0x%x\n", rc); - goto out_destroy_mbx_wq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2590 ELS WQ setup: wq-id=%d, parent cq-id=%d\n", - phba->sli4_hba.els_wq->queue_id, - phba->sli4_hba.els_cq->queue_id); - - /* Set up fast-path FCP Work Queue */ - if (!phba->sli4_hba.fcp_wq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3149 Fast-path FCP WQ array not " - "allocated\n"); - rc = -ENOMEM; - goto out_destroy_els_wq; - } - for (fcp_wqidx = 0; fcp_wqidx < phba->cfg_fcp_wq_count; fcp_wqidx++) { - if (!phba->sli4_hba.fcp_wq[fcp_wqidx]) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0534 Fast-path FCP WQ (%d) not " - "allocated\n", fcp_wqidx); - rc = -ENOMEM; - goto out_destroy_fcp_wq; - } - rc = lpfc_wq_create(phba, phba->sli4_hba.fcp_wq[fcp_wqidx], - phba->sli4_hba.fcp_cq[fcp_cq_index], - LPFC_FCP); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0535 Failed setup of fast-path FCP " - "WQ (%d), rc = 0x%x\n", fcp_wqidx, rc); - goto out_destroy_fcp_wq; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2591 FCP WQ setup: wq[%d]-id=%d, " - "parent cq[%d]-id=%d\n", - fcp_wqidx, - phba->sli4_hba.fcp_wq[fcp_wqidx]->queue_id, - fcp_cq_index, - phba->sli4_hba.fcp_cq[fcp_cq_index]->queue_id); - /* Round robin FCP Work Queue's Completion Queue assignment */ - if (phba->cfg_fcp_eq_count) - fcp_cq_index = ((fcp_cq_index + 1) % - phba->cfg_fcp_eq_count); - } - - /* - * Create Receive Queue (RQ) - */ - if (!phba->sli4_hba.hdr_rq || !phba->sli4_hba.dat_rq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0540 Receive Queue not allocated\n"); - rc = -ENOMEM; - goto out_destroy_fcp_wq; - } - - lpfc_rq_adjust_repost(phba, phba->sli4_hba.hdr_rq, LPFC_ELS_HBQ); - lpfc_rq_adjust_repost(phba, phba->sli4_hba.dat_rq, LPFC_ELS_HBQ); - - rc = lpfc_rq_create(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq, - phba->sli4_hba.els_cq, LPFC_USOL); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0541 Failed setup of Receive Queue: " - "rc = 0x%x\n", rc); - goto out_destroy_fcp_wq; - } - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2592 USL RQ setup: hdr-rq-id=%d, dat-rq-id=%d " - "parent cq-id=%d\n", - phba->sli4_hba.hdr_rq->queue_id, - phba->sli4_hba.dat_rq->queue_id, - phba->sli4_hba.els_cq->queue_id); - return 0; - -out_destroy_fcp_wq: - for (--fcp_wqidx; fcp_wqidx >= 0; fcp_wqidx--) - lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_wqidx]); -out_destroy_els_wq: - lpfc_wq_destroy(phba, phba->sli4_hba.els_wq); -out_destroy_mbx_wq: - lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq); -out_destroy_fcp_cq: - for (--fcp_cqidx; fcp_cqidx >= 0; fcp_cqidx--) - lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_cqidx]); -out_destroy_els_cq: - lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); -out_destroy_mbx_cq: - lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); -out_destroy_fp_eq: - for (--fcp_eqidx; fcp_eqidx >= 0; fcp_eqidx--) - lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_eqidx]); -out_destroy_sp_eq: - lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); -out_error: - return rc; -} - -/** - * lpfc_sli4_queue_unset - Unset all the SLI4 queues - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unset all the SLI4 queues with the FCoE HBA - * operation. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. - **/ -void -lpfc_sli4_queue_unset(struct lpfc_hba *phba) -{ - int fcp_qidx; - - /* Unset mailbox command work queue */ - lpfc_mq_destroy(phba, phba->sli4_hba.mbx_wq); - /* Unset ELS work queue */ - lpfc_wq_destroy(phba, phba->sli4_hba.els_wq); - /* Unset unsolicited receive queue */ - lpfc_rq_destroy(phba, phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq); - /* Unset FCP work queue */ - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_wq_count; fcp_qidx++) - lpfc_wq_destroy(phba, phba->sli4_hba.fcp_wq[fcp_qidx]); - /* Unset mailbox command complete queue */ - lpfc_cq_destroy(phba, phba->sli4_hba.mbx_cq); - /* Unset ELS complete queue */ - lpfc_cq_destroy(phba, phba->sli4_hba.els_cq); - /* Unset FCP response complete queue */ - if (phba->sli4_hba.fcp_cq) { - fcp_qidx = 0; - do { - lpfc_cq_destroy(phba, phba->sli4_hba.fcp_cq[fcp_qidx]); - } while (++fcp_qidx < phba->cfg_fcp_eq_count); - } - /* Unset fast-path event queue */ - if (phba->sli4_hba.fp_eq) { - for (fcp_qidx = 0; fcp_qidx < phba->cfg_fcp_eq_count; - fcp_qidx++) - lpfc_eq_destroy(phba, phba->sli4_hba.fp_eq[fcp_qidx]); - } - /* Unset slow-path event queue */ - lpfc_eq_destroy(phba, phba->sli4_hba.sp_eq); -} - -/** - * lpfc_sli4_cq_event_pool_create - Create completion-queue event free pool - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to allocate and set up a pool of completion queue - * events. The body of the completion queue event is a completion queue entry - * CQE. For now, this pool is used for the interrupt service routine to queue - * the following HBA completion queue events for the worker thread to process: - * - Mailbox asynchronous events - * - Receive queue completion unsolicited events - * Later, this can be used for all the slow-path events. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - **/ -static int -lpfc_sli4_cq_event_pool_create(struct lpfc_hba *phba) -{ - struct lpfc_cq_event *cq_event; - int i; - - for (i = 0; i < (4 * phba->sli4_hba.cq_ecount); i++) { - cq_event = kmalloc(sizeof(struct lpfc_cq_event), GFP_KERNEL); - if (!cq_event) - goto out_pool_create_fail; - list_add_tail(&cq_event->list, - &phba->sli4_hba.sp_cqe_event_pool); - } - return 0; - -out_pool_create_fail: - lpfc_sli4_cq_event_pool_destroy(phba); - return -ENOMEM; -} - -/** - * lpfc_sli4_cq_event_pool_destroy - Free completion-queue event free pool - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to free the pool of completion queue events at - * driver unload time. Note that, it is the responsibility of the driver - * cleanup routine to free all the outstanding completion-queue events - * allocated from this pool back into the pool before invoking this routine - * to destroy the pool. - **/ -static void -lpfc_sli4_cq_event_pool_destroy(struct lpfc_hba *phba) -{ - struct lpfc_cq_event *cq_event, *next_cq_event; - - list_for_each_entry_safe(cq_event, next_cq_event, - &phba->sli4_hba.sp_cqe_event_pool, list) { - list_del(&cq_event->list); - kfree(cq_event); - } -} - -/** - * __lpfc_sli4_cq_event_alloc - Allocate a completion-queue event from free pool - * @phba: pointer to lpfc hba data structure. - * - * This routine is the lock free version of the API invoked to allocate a - * completion-queue event from the free pool. - * - * Return: Pointer to the newly allocated completion-queue event if successful - * NULL otherwise. - **/ -struct lpfc_cq_event * -__lpfc_sli4_cq_event_alloc(struct lpfc_hba *phba) -{ - struct lpfc_cq_event *cq_event = NULL; - - list_remove_head(&phba->sli4_hba.sp_cqe_event_pool, cq_event, - struct lpfc_cq_event, list); - return cq_event; -} - -/** - * lpfc_sli4_cq_event_alloc - Allocate a completion-queue event from free pool - * @phba: pointer to lpfc hba data structure. - * - * This routine is the lock version of the API invoked to allocate a - * completion-queue event from the free pool. - * - * Return: Pointer to the newly allocated completion-queue event if successful - * NULL otherwise. - **/ -struct lpfc_cq_event * -lpfc_sli4_cq_event_alloc(struct lpfc_hba *phba) -{ - struct lpfc_cq_event *cq_event; - unsigned long iflags; - - spin_lock_irqsave(&phba->hbalock, iflags); - cq_event = __lpfc_sli4_cq_event_alloc(phba); - spin_unlock_irqrestore(&phba->hbalock, iflags); - return cq_event; -} - -/** - * __lpfc_sli4_cq_event_release - Release a completion-queue event to free pool - * @phba: pointer to lpfc hba data structure. - * @cq_event: pointer to the completion queue event to be freed. - * - * This routine is the lock free version of the API invoked to release a - * completion-queue event back into the free pool. - **/ -void -__lpfc_sli4_cq_event_release(struct lpfc_hba *phba, - struct lpfc_cq_event *cq_event) -{ - list_add_tail(&cq_event->list, &phba->sli4_hba.sp_cqe_event_pool); -} - -/** - * lpfc_sli4_cq_event_release - Release a completion-queue event to free pool - * @phba: pointer to lpfc hba data structure. - * @cq_event: pointer to the completion queue event to be freed. - * - * This routine is the lock version of the API invoked to release a - * completion-queue event back into the free pool. - **/ -void -lpfc_sli4_cq_event_release(struct lpfc_hba *phba, - struct lpfc_cq_event *cq_event) -{ - unsigned long iflags; - spin_lock_irqsave(&phba->hbalock, iflags); - __lpfc_sli4_cq_event_release(phba, cq_event); - spin_unlock_irqrestore(&phba->hbalock, iflags); -} - -/** - * lpfc_sli4_cq_event_release_all - Release all cq events to the free pool - * @phba: pointer to lpfc hba data structure. - * - * This routine is to free all the pending completion-queue events to the - * back into the free pool for device reset. - **/ -static void -lpfc_sli4_cq_event_release_all(struct lpfc_hba *phba) -{ - LIST_HEAD(cqelist); - struct lpfc_cq_event *cqe; - unsigned long iflags; - - /* Retrieve all the pending WCQEs from pending WCQE lists */ - spin_lock_irqsave(&phba->hbalock, iflags); - /* Pending FCP XRI abort events */ - list_splice_init(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue, - &cqelist); - /* Pending ELS XRI abort events */ - list_splice_init(&phba->sli4_hba.sp_els_xri_aborted_work_queue, - &cqelist); - /* Pending asynnc events */ - list_splice_init(&phba->sli4_hba.sp_asynce_work_queue, - &cqelist); - spin_unlock_irqrestore(&phba->hbalock, iflags); - - while (!list_empty(&cqelist)) { - list_remove_head(&cqelist, cqe, struct lpfc_cq_event, list); - lpfc_sli4_cq_event_release(phba, cqe); - } -} - -/** - * lpfc_pci_function_reset - Reset pci function. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to request a PCI function reset. It will destroys - * all resources assigned to the PCI function which originates this request. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. - **/ -int -lpfc_pci_function_reset(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *mboxq; - uint32_t rc = 0, if_type; - uint32_t shdr_status, shdr_add_status; - uint32_t rdy_chk, num_resets = 0, reset_again = 0; - union lpfc_sli4_cfg_shdr *shdr; - struct lpfc_register reg_data; - uint16_t devid; - - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - switch (if_type) { - case LPFC_SLI_INTF_IF_TYPE_0: - mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0494 Unable to allocate memory for " - "issuing SLI_FUNCTION_RESET mailbox " - "command\n"); - return -ENOMEM; - } - - /* Setup PCI function reset mailbox-ioctl command */ - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_FUNCTION_RESET, 0, - LPFC_SLI4_MBX_EMBED); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) - &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0495 SLI_FUNCTION_RESET mailbox " - "failed with status x%x add_status x%x," - " mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - } - break; - case LPFC_SLI_INTF_IF_TYPE_2: - for (num_resets = 0; - num_resets < MAX_IF_TYPE_2_RESETS; - num_resets++) { - reg_data.word0 = 0; - bf_set(lpfc_sliport_ctrl_end, ®_data, - LPFC_SLIPORT_LITTLE_ENDIAN); - bf_set(lpfc_sliport_ctrl_ip, ®_data, - LPFC_SLIPORT_INIT_PORT); - writel(reg_data.word0, phba->sli4_hba.u.if_type2. - CTRLregaddr); - /* flush */ - pci_read_config_word(phba->pcidev, - PCI_DEVICE_ID, &devid); - /* - * Poll the Port Status Register and wait for RDY for - * up to 10 seconds. If the port doesn't respond, treat - * it as an error. If the port responds with RN, start - * the loop again. - */ - for (rdy_chk = 0; rdy_chk < 1000; rdy_chk++) { - msleep(10); - if (lpfc_readl(phba->sli4_hba.u.if_type2. - STATUSregaddr, ®_data.word0)) { - rc = -ENODEV; - goto out; - } - if (bf_get(lpfc_sliport_status_rn, ®_data)) - reset_again++; - if (bf_get(lpfc_sliport_status_rdy, ®_data)) - break; - } - - /* - * If the port responds to the init request with - * reset needed, delay for a bit and restart the loop. - */ - if (reset_again && (rdy_chk < 1000)) { - msleep(10); - reset_again = 0; - continue; - } - - /* Detect any port errors. */ - if ((bf_get(lpfc_sliport_status_err, ®_data)) || - (rdy_chk >= 1000)) { - phba->work_status[0] = readl( - phba->sli4_hba.u.if_type2.ERR1regaddr); - phba->work_status[1] = readl( - phba->sli4_hba.u.if_type2.ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2890 Port error detected during port " - "reset(%d): port status reg 0x%x, " - "error 1=0x%x, error 2=0x%x\n", - num_resets, reg_data.word0, - phba->work_status[0], - phba->work_status[1]); - rc = -ENODEV; - } - - /* - * Terminate the outer loop provided the Port indicated - * ready within 10 seconds. - */ - if (rdy_chk < 1000) - break; - } - /* delay driver action following IF_TYPE_2 function reset */ - msleep(100); - break; - case LPFC_SLI_INTF_IF_TYPE_1: - default: - break; - } - -out: - /* Catch the not-ready port failure after a port reset. */ - if (num_resets >= MAX_IF_TYPE_2_RESETS) - rc = -ENODEV; - - return rc; -} - -/** - * lpfc_sli4_send_nop_mbox_cmds - Send sli-4 nop mailbox commands - * @phba: pointer to lpfc hba data structure. - * @cnt: number of nop mailbox commands to send. - * - * This routine is invoked to send a number @cnt of NOP mailbox command and - * wait for each command to complete. - * - * Return: the number of NOP mailbox command completed. - **/ -static int -lpfc_sli4_send_nop_mbox_cmds(struct lpfc_hba *phba, uint32_t cnt) -{ - LPFC_MBOXQ_t *mboxq; - int length, cmdsent; - uint32_t mbox_tmo; - uint32_t rc = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - if (cnt == 0) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2518 Requested to send 0 NOP mailbox cmd\n"); - return cnt; - } - - mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2519 Unable to allocate memory for issuing " - "NOP mailbox command\n"); - return 0; - } - - /* Set up NOP SLI4_CONFIG mailbox-ioctl command */ - length = (sizeof(struct lpfc_mbx_nop) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_NOP, length, LPFC_SLI4_MBX_EMBED); - - for (cmdsent = 0; cmdsent < cnt; cmdsent++) { - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); - } - if (rc == MBX_TIMEOUT) - break; - /* Check return status */ - shdr = (union lpfc_sli4_cfg_shdr *) - &mboxq->u.mqe.un.sli4_config.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2520 NOP mailbox command failed " - "status x%x add_status x%x mbx " - "status x%x\n", shdr_status, - shdr_add_status, rc); - break; - } - } - - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); - - return cmdsent; -} - -/** - * lpfc_sli4_pci_mem_setup - Setup SLI4 HBA PCI memory space. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to set up the PCI device memory space for device - * with SLI-4 interface spec. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_sli4_pci_mem_setup(struct lpfc_hba *phba) -{ - struct pci_dev *pdev; - unsigned long bar0map_len, bar1map_len, bar2map_len; - int error = -ENODEV; - uint32_t if_type; - - /* Obtain PCI device reference */ - if (!phba->pcidev) - return error; - else - pdev = phba->pcidev; - - /* Set the device DMA mask size */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0 - || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(64)) != 0) { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0 - || pci_set_consistent_dma_mask(pdev,DMA_BIT_MASK(32)) != 0) { - return error; - } - } - - /* - * The BARs and register set definitions and offset locations are - * dependent on the if_type. - */ - if (pci_read_config_dword(pdev, LPFC_SLI_INTF, - &phba->sli4_hba.sli_intf.word0)) { - return error; - } - - /* There is no SLI3 failback for SLI4 devices. */ - if (bf_get(lpfc_sli_intf_valid, &phba->sli4_hba.sli_intf) != - LPFC_SLI_INTF_VALID) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2894 SLI_INTF reg contents invalid " - "sli_intf reg 0x%x\n", - phba->sli4_hba.sli_intf.word0); - return error; - } - - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - /* - * Get the bus address of SLI4 device Bar regions and the - * number of bytes required by each mapping. The mapping of the - * particular PCI BARs regions is dependent on the type of - * SLI4 device. - */ - if (pci_resource_start(pdev, 0)) { - phba->pci_bar0_map = pci_resource_start(pdev, 0); - bar0map_len = pci_resource_len(pdev, 0); - - /* - * Map SLI4 PCI Config Space Register base to a kernel virtual - * addr - */ - phba->sli4_hba.conf_regs_memmap_p = - ioremap(phba->pci_bar0_map, bar0map_len); - if (!phba->sli4_hba.conf_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLI4 PCI config " - "registers.\n"); - goto out; - } - /* Set up BAR0 PCI config space register memory map */ - lpfc_sli4_bar0_register_memmap(phba, if_type); - } else { - phba->pci_bar0_map = pci_resource_start(pdev, 1); - bar0map_len = pci_resource_len(pdev, 1); - if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { - dev_printk(KERN_ERR, &pdev->dev, - "FATAL - No BAR0 mapping for SLI4, if_type 2\n"); - goto out; - } - phba->sli4_hba.conf_regs_memmap_p = - ioremap(phba->pci_bar0_map, bar0map_len); - if (!phba->sli4_hba.conf_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLI4 PCI config " - "registers.\n"); - goto out; - } - lpfc_sli4_bar0_register_memmap(phba, if_type); - } - - if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) && - (pci_resource_start(pdev, 2))) { - /* - * Map SLI4 if type 0 HBA Control Register base to a kernel - * virtual address and setup the registers. - */ - phba->pci_bar1_map = pci_resource_start(pdev, 2); - bar1map_len = pci_resource_len(pdev, 2); - phba->sli4_hba.ctrl_regs_memmap_p = - ioremap(phba->pci_bar1_map, bar1map_len); - if (!phba->sli4_hba.ctrl_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLI4 HBA control registers.\n"); - goto out_iounmap_conf; - } - lpfc_sli4_bar1_register_memmap(phba); - } - - if ((if_type == LPFC_SLI_INTF_IF_TYPE_0) && - (pci_resource_start(pdev, 4))) { - /* - * Map SLI4 if type 0 HBA Doorbell Register base to a kernel - * virtual address and setup the registers. - */ - phba->pci_bar2_map = pci_resource_start(pdev, 4); - bar2map_len = pci_resource_len(pdev, 4); - phba->sli4_hba.drbl_regs_memmap_p = - ioremap(phba->pci_bar2_map, bar2map_len); - if (!phba->sli4_hba.drbl_regs_memmap_p) { - dev_printk(KERN_ERR, &pdev->dev, - "ioremap failed for SLI4 HBA doorbell registers.\n"); - goto out_iounmap_ctrl; - } - error = lpfc_sli4_bar2_register_memmap(phba, LPFC_VF0); - if (error) - goto out_iounmap_all; - } - - return 0; - -out_iounmap_all: - iounmap(phba->sli4_hba.drbl_regs_memmap_p); -out_iounmap_ctrl: - iounmap(phba->sli4_hba.ctrl_regs_memmap_p); -out_iounmap_conf: - iounmap(phba->sli4_hba.conf_regs_memmap_p); -out: - return error; -} - -/** - * lpfc_sli4_pci_mem_unset - Unset SLI4 HBA PCI memory space. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unset the PCI device memory space for device - * with SLI-4 interface spec. - **/ -static void -lpfc_sli4_pci_mem_unset(struct lpfc_hba *phba) -{ - uint32_t if_type; - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - - switch (if_type) { - case LPFC_SLI_INTF_IF_TYPE_0: - iounmap(phba->sli4_hba.drbl_regs_memmap_p); - iounmap(phba->sli4_hba.ctrl_regs_memmap_p); - iounmap(phba->sli4_hba.conf_regs_memmap_p); - break; - case LPFC_SLI_INTF_IF_TYPE_2: - iounmap(phba->sli4_hba.conf_regs_memmap_p); - break; - case LPFC_SLI_INTF_IF_TYPE_1: - default: - dev_printk(KERN_ERR, &phba->pcidev->dev, - "FATAL - unsupported SLI4 interface type - %d\n", - if_type); - break; - } -} - -/** - * lpfc_sli_enable_msix - Enable MSI-X interrupt mode on SLI-3 device - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to enable the MSI-X interrupt vectors to device - * with SLI-3 interface specs. The kernel function pci_enable_msix() is - * called to enable the MSI-X vectors. Note that pci_enable_msix(), once - * invoked, enables either all or nothing, depending on the current - * availability of PCI vector resources. The device driver is responsible - * for calling the individual request_irq() to register each MSI-X vector - * with a interrupt handler, which is done in this function. Note that - * later when device is unloading, the driver should always call free_irq() - * on all MSI-X vectors it has done request_irq() on before calling - * pci_disable_msix(). Failure to do so results in a BUG_ON() and a device - * will be left with MSI-X enabled and leaks its vectors. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_sli_enable_msix(struct lpfc_hba *phba) -{ - int rc, i; - LPFC_MBOXQ_t *pmb; - - /* Set up MSI-X multi-message vectors */ - for (i = 0; i < LPFC_MSIX_VECTORS; i++) - phba->msix_entries[i].entry = i; - - /* Configure MSI-X capability structure */ - rc = pci_enable_msix(phba->pcidev, phba->msix_entries, - ARRAY_SIZE(phba->msix_entries)); - if (rc) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0420 PCI enable MSI-X failed (%d)\n", rc); - goto msi_fail_out; - } - for (i = 0; i < LPFC_MSIX_VECTORS; i++) - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0477 MSI-X entry[%d]: vector=x%x " - "message=%d\n", i, - phba->msix_entries[i].vector, - phba->msix_entries[i].entry); - /* - * Assign MSI-X vectors to interrupt handlers - */ - - /* vector-0 is associated to slow-path handler */ - rc = request_irq(phba->msix_entries[0].vector, - &lpfc_sli_sp_intr_handler, IRQF_SHARED, - LPFC_SP_DRIVER_HANDLER_NAME, phba); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0421 MSI-X slow-path request_irq failed " - "(%d)\n", rc); - goto msi_fail_out; - } - - /* vector-1 is associated to fast-path handler */ - rc = request_irq(phba->msix_entries[1].vector, - &lpfc_sli_fp_intr_handler, IRQF_SHARED, - LPFC_FP_DRIVER_HANDLER_NAME, phba); - - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0429 MSI-X fast-path request_irq failed " - "(%d)\n", rc); - goto irq_fail_out; - } - - /* - * Configure HBA MSI-X attention conditions to messages - */ - pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - - if (!pmb) { - rc = -ENOMEM; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0474 Unable to allocate memory for issuing " - "MBOX_CONFIG_MSI command\n"); - goto mem_fail_out; - } - rc = lpfc_config_msi(phba, pmb); - if (rc) - goto mbx_fail_out; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "0351 Config MSI mailbox command failed, " - "mbxCmd x%x, mbxStatus x%x\n", - pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus); - goto mbx_fail_out; - } - - /* Free memory allocated for mailbox command */ - mempool_free(pmb, phba->mbox_mem_pool); - return rc; - -mbx_fail_out: - /* Free memory allocated for mailbox command */ - mempool_free(pmb, phba->mbox_mem_pool); - -mem_fail_out: - /* free the irq already requested */ - free_irq(phba->msix_entries[1].vector, phba); - -irq_fail_out: - /* free the irq already requested */ - free_irq(phba->msix_entries[0].vector, phba); - -msi_fail_out: - /* Unconfigure MSI-X capability structure */ - pci_disable_msix(phba->pcidev); - return rc; -} - -/** - * lpfc_sli_disable_msix - Disable MSI-X interrupt mode on SLI-3 device. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to release the MSI-X vectors and then disable the - * MSI-X interrupt mode to device with SLI-3 interface spec. - **/ -static void -lpfc_sli_disable_msix(struct lpfc_hba *phba) -{ - int i; - - /* Free up MSI-X multi-message vectors */ - for (i = 0; i < LPFC_MSIX_VECTORS; i++) - free_irq(phba->msix_entries[i].vector, phba); - /* Disable MSI-X */ - pci_disable_msix(phba->pcidev); - - return; -} - -/** - * lpfc_sli_enable_msi - Enable MSI interrupt mode on SLI-3 device. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to enable the MSI interrupt mode to device with - * SLI-3 interface spec. The kernel function pci_enable_msi() is called to - * enable the MSI vector. The device driver is responsible for calling the - * request_irq() to register MSI vector with a interrupt the handler, which - * is done in this function. - * - * Return codes - * 0 - successful - * other values - error - */ -static int -lpfc_sli_enable_msi(struct lpfc_hba *phba) -{ - int rc; - - rc = pci_enable_msi(phba->pcidev); - if (!rc) - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0462 PCI enable MSI mode success.\n"); - else { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0471 PCI enable MSI mode failed (%d)\n", rc); - return rc; - } - - rc = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler, - IRQF_SHARED, LPFC_DRIVER_NAME, phba); - if (rc) { - pci_disable_msi(phba->pcidev); - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0478 MSI request_irq failed (%d)\n", rc); - } - return rc; -} - -/** - * lpfc_sli_disable_msi - Disable MSI interrupt mode to SLI-3 device. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to disable the MSI interrupt mode to device with - * SLI-3 interface spec. The driver calls free_irq() on MSI vector it has - * done request_irq() on before calling pci_disable_msi(). Failure to do so - * results in a BUG_ON() and a device will be left with MSI enabled and leaks - * its vector. - */ -static void -lpfc_sli_disable_msi(struct lpfc_hba *phba) -{ - free_irq(phba->pcidev->irq, phba); - pci_disable_msi(phba->pcidev); - return; -} - -/** - * lpfc_sli_enable_intr - Enable device interrupt to SLI-3 device. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to enable device interrupt and associate driver's - * interrupt handler(s) to interrupt vector(s) to device with SLI-3 interface - * spec. Depends on the interrupt mode configured to the driver, the driver - * will try to fallback from the configured interrupt mode to an interrupt - * mode which is supported by the platform, kernel, and device in the order - * of: - * MSI-X -> MSI -> IRQ. - * - * Return codes - * 0 - successful - * other values - error - **/ -static uint32_t -lpfc_sli_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) -{ - uint32_t intr_mode = LPFC_INTR_ERROR; - int retval; - - if (cfg_mode == 2) { - /* Need to issue conf_port mbox cmd before conf_msi mbox cmd */ - retval = lpfc_sli_config_port(phba, LPFC_SLI_REV3); - if (!retval) { - /* Now, try to enable MSI-X interrupt mode */ - retval = lpfc_sli_enable_msix(phba); - if (!retval) { - /* Indicate initialization to MSI-X mode */ - phba->intr_type = MSIX; - intr_mode = 2; - } - } - } - - /* Fallback to MSI if MSI-X initialization failed */ - if (cfg_mode >= 1 && phba->intr_type == NONE) { - retval = lpfc_sli_enable_msi(phba); - if (!retval) { - /* Indicate initialization to MSI mode */ - phba->intr_type = MSI; - intr_mode = 1; - } - } - - /* Fallback to INTx if both MSI-X/MSI initalization failed */ - if (phba->intr_type == NONE) { - retval = request_irq(phba->pcidev->irq, lpfc_sli_intr_handler, - IRQF_SHARED, LPFC_DRIVER_NAME, phba); - if (!retval) { - /* Indicate initialization to INTx mode */ - phba->intr_type = INTx; - intr_mode = 0; - } - } - return intr_mode; -} - -/** - * lpfc_sli_disable_intr - Disable device interrupt to SLI-3 device. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to disable device interrupt and disassociate the - * driver's interrupt handler(s) from interrupt vector(s) to device with - * SLI-3 interface spec. Depending on the interrupt mode, the driver will - * release the interrupt vector(s) for the message signaled interrupt. - **/ -static void -lpfc_sli_disable_intr(struct lpfc_hba *phba) -{ - /* Disable the currently initialized interrupt mode */ - if (phba->intr_type == MSIX) - lpfc_sli_disable_msix(phba); - else if (phba->intr_type == MSI) - lpfc_sli_disable_msi(phba); - else if (phba->intr_type == INTx) - free_irq(phba->pcidev->irq, phba); - - /* Reset interrupt management states */ - phba->intr_type = NONE; - phba->sli.slistat.sli_intr = 0; - - return; -} - -/** - * lpfc_sli4_enable_msix - Enable MSI-X interrupt mode to SLI-4 device - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to enable the MSI-X interrupt vectors to device - * with SLI-4 interface spec. The kernel function pci_enable_msix() is called - * to enable the MSI-X vectors. Note that pci_enable_msix(), once invoked, - * enables either all or nothing, depending on the current availability of - * PCI vector resources. The device driver is responsible for calling the - * individual request_irq() to register each MSI-X vector with a interrupt - * handler, which is done in this function. Note that later when device is - * unloading, the driver should always call free_irq() on all MSI-X vectors - * it has done request_irq() on before calling pci_disable_msix(). Failure - * to do so results in a BUG_ON() and a device will be left with MSI-X - * enabled and leaks its vectors. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_sli4_enable_msix(struct lpfc_hba *phba) -{ - int vectors, rc, index; - - /* Set up MSI-X multi-message vectors */ - for (index = 0; index < phba->sli4_hba.cfg_eqn; index++) - phba->sli4_hba.msix_entries[index].entry = index; - - /* Configure MSI-X capability structure */ - vectors = phba->sli4_hba.cfg_eqn; -enable_msix_vectors: - rc = pci_enable_msix(phba->pcidev, phba->sli4_hba.msix_entries, - vectors); - if (rc > 1) { - vectors = rc; - goto enable_msix_vectors; - } else if (rc) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0484 PCI enable MSI-X failed (%d)\n", rc); - goto msi_fail_out; - } - - /* Log MSI-X vector assignment */ - for (index = 0; index < vectors; index++) - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0489 MSI-X entry[%d]: vector=x%x " - "message=%d\n", index, - phba->sli4_hba.msix_entries[index].vector, - phba->sli4_hba.msix_entries[index].entry); - /* - * Assign MSI-X vectors to interrupt handlers - */ - if (vectors > 1) - rc = request_irq(phba->sli4_hba.msix_entries[0].vector, - &lpfc_sli4_sp_intr_handler, IRQF_SHARED, - LPFC_SP_DRIVER_HANDLER_NAME, phba); - else - /* All Interrupts need to be handled by one EQ */ - rc = request_irq(phba->sli4_hba.msix_entries[0].vector, - &lpfc_sli4_intr_handler, IRQF_SHARED, - LPFC_DRIVER_NAME, phba); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0485 MSI-X slow-path request_irq failed " - "(%d)\n", rc); - goto msi_fail_out; - } - - /* The rest of the vector(s) are associated to fast-path handler(s) */ - for (index = 1; index < vectors; index++) { - phba->sli4_hba.fcp_eq_hdl[index - 1].idx = index - 1; - phba->sli4_hba.fcp_eq_hdl[index - 1].phba = phba; - rc = request_irq(phba->sli4_hba.msix_entries[index].vector, - &lpfc_sli4_fp_intr_handler, IRQF_SHARED, - LPFC_FP_DRIVER_HANDLER_NAME, - &phba->sli4_hba.fcp_eq_hdl[index - 1]); - if (rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0486 MSI-X fast-path (%d) " - "request_irq failed (%d)\n", index, rc); - goto cfg_fail_out; - } - } - phba->sli4_hba.msix_vec_nr = vectors; - - return rc; - -cfg_fail_out: - /* free the irq already requested */ - for (--index; index >= 1; index--) - free_irq(phba->sli4_hba.msix_entries[index - 1].vector, - &phba->sli4_hba.fcp_eq_hdl[index - 1]); - - /* free the irq already requested */ - free_irq(phba->sli4_hba.msix_entries[0].vector, phba); - -msi_fail_out: - /* Unconfigure MSI-X capability structure */ - pci_disable_msix(phba->pcidev); - return rc; -} - -/** - * lpfc_sli4_disable_msix - Disable MSI-X interrupt mode to SLI-4 device - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to release the MSI-X vectors and then disable the - * MSI-X interrupt mode to device with SLI-4 interface spec. - **/ -static void -lpfc_sli4_disable_msix(struct lpfc_hba *phba) -{ - int index; - - /* Free up MSI-X multi-message vectors */ - free_irq(phba->sli4_hba.msix_entries[0].vector, phba); - - for (index = 1; index < phba->sli4_hba.msix_vec_nr; index++) - free_irq(phba->sli4_hba.msix_entries[index].vector, - &phba->sli4_hba.fcp_eq_hdl[index - 1]); - - /* Disable MSI-X */ - pci_disable_msix(phba->pcidev); - - return; -} - -/** - * lpfc_sli4_enable_msi - Enable MSI interrupt mode to SLI-4 device - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to enable the MSI interrupt mode to device with - * SLI-4 interface spec. The kernel function pci_enable_msi() is called - * to enable the MSI vector. The device driver is responsible for calling - * the request_irq() to register MSI vector with a interrupt the handler, - * which is done in this function. - * - * Return codes - * 0 - successful - * other values - error - **/ -static int -lpfc_sli4_enable_msi(struct lpfc_hba *phba) -{ - int rc, index; - - rc = pci_enable_msi(phba->pcidev); - if (!rc) - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0487 PCI enable MSI mode success.\n"); - else { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0488 PCI enable MSI mode failed (%d)\n", rc); - return rc; - } - - rc = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler, - IRQF_SHARED, LPFC_DRIVER_NAME, phba); - if (rc) { - pci_disable_msi(phba->pcidev); - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0490 MSI request_irq failed (%d)\n", rc); - return rc; - } - - for (index = 0; index < phba->cfg_fcp_eq_count; index++) { - phba->sli4_hba.fcp_eq_hdl[index].idx = index; - phba->sli4_hba.fcp_eq_hdl[index].phba = phba; - } - - return 0; -} - -/** - * lpfc_sli4_disable_msi - Disable MSI interrupt mode to SLI-4 device - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to disable the MSI interrupt mode to device with - * SLI-4 interface spec. The driver calls free_irq() on MSI vector it has - * done request_irq() on before calling pci_disable_msi(). Failure to do so - * results in a BUG_ON() and a device will be left with MSI enabled and leaks - * its vector. - **/ -static void -lpfc_sli4_disable_msi(struct lpfc_hba *phba) -{ - free_irq(phba->pcidev->irq, phba); - pci_disable_msi(phba->pcidev); - return; -} - -/** - * lpfc_sli4_enable_intr - Enable device interrupt to SLI-4 device - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to enable device interrupt and associate driver's - * interrupt handler(s) to interrupt vector(s) to device with SLI-4 - * interface spec. Depends on the interrupt mode configured to the driver, - * the driver will try to fallback from the configured interrupt mode to an - * interrupt mode which is supported by the platform, kernel, and device in - * the order of: - * MSI-X -> MSI -> IRQ. - * - * Return codes - * 0 - successful - * other values - error - **/ -static uint32_t -lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) -{ - uint32_t intr_mode = LPFC_INTR_ERROR; - int retval, index; - - if (cfg_mode == 2) { - /* Preparation before conf_msi mbox cmd */ - retval = 0; - if (!retval) { - /* Now, try to enable MSI-X interrupt mode */ - retval = lpfc_sli4_enable_msix(phba); - if (!retval) { - /* Indicate initialization to MSI-X mode */ - phba->intr_type = MSIX; - intr_mode = 2; - } - } - } - - /* Fallback to MSI if MSI-X initialization failed */ - if (cfg_mode >= 1 && phba->intr_type == NONE) { - retval = lpfc_sli4_enable_msi(phba); - if (!retval) { - /* Indicate initialization to MSI mode */ - phba->intr_type = MSI; - intr_mode = 1; - } - } - - /* Fallback to INTx if both MSI-X/MSI initalization failed */ - if (phba->intr_type == NONE) { - retval = request_irq(phba->pcidev->irq, lpfc_sli4_intr_handler, - IRQF_SHARED, LPFC_DRIVER_NAME, phba); - if (!retval) { - /* Indicate initialization to INTx mode */ - phba->intr_type = INTx; - intr_mode = 0; - for (index = 0; index < phba->cfg_fcp_eq_count; - index++) { - phba->sli4_hba.fcp_eq_hdl[index].idx = index; - phba->sli4_hba.fcp_eq_hdl[index].phba = phba; - } - } - } - return intr_mode; -} - -/** - * lpfc_sli4_disable_intr - Disable device interrupt to SLI-4 device - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to disable device interrupt and disassociate - * the driver's interrupt handler(s) from interrupt vector(s) to device - * with SLI-4 interface spec. Depending on the interrupt mode, the driver - * will release the interrupt vector(s) for the message signaled interrupt. - **/ -static void -lpfc_sli4_disable_intr(struct lpfc_hba *phba) -{ - /* Disable the currently initialized interrupt mode */ - if (phba->intr_type == MSIX) - lpfc_sli4_disable_msix(phba); - else if (phba->intr_type == MSI) - lpfc_sli4_disable_msi(phba); - else if (phba->intr_type == INTx) - free_irq(phba->pcidev->irq, phba); - - /* Reset interrupt management states */ - phba->intr_type = NONE; - phba->sli.slistat.sli_intr = 0; - - return; -} - -/** - * lpfc_unset_hba - Unset SLI3 hba device initialization - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unset the HBA device initialization steps to - * a device with SLI-3 interface spec. - **/ -static void -lpfc_unset_hba(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport = phba->pport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - spin_lock_irq(shost->host_lock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(shost->host_lock); - - kfree(phba->vpi_bmask); - kfree(phba->vpi_ids); - - lpfc_stop_hba_timers(phba); - - phba->pport->work_port_events = 0; - - lpfc_sli_hba_down(phba); - - lpfc_sli_brdrestart(phba); - - lpfc_sli_disable_intr(phba); - - return; -} - -/** - * lpfc_sli4_unset_hba - Unset SLI4 hba device initialization. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to unset the HBA device initialization steps to - * a device with SLI-4 interface spec. - **/ -static void -lpfc_sli4_unset_hba(struct lpfc_hba *phba) -{ - struct lpfc_vport *vport = phba->pport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - spin_lock_irq(shost->host_lock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(shost->host_lock); - - phba->pport->work_port_events = 0; - - /* Stop the SLI4 device port */ - lpfc_stop_port(phba); - - lpfc_sli4_disable_intr(phba); - - /* Reset SLI4 HBA FCoE function */ - lpfc_pci_function_reset(phba); - lpfc_sli4_queue_destroy(phba); - - return; -} - -/** - * lpfc_sli4_xri_exchange_busy_wait - Wait for device XRI exchange busy - * @phba: Pointer to HBA context object. - * - * This function is called in the SLI4 code path to wait for completion - * of device's XRIs exchange busy. It will check the XRI exchange busy - * on outstanding FCP and ELS I/Os every 10ms for up to 10 seconds; after - * that, it will check the XRI exchange busy on outstanding FCP and ELS - * I/Os every 30 seconds, log error message, and wait forever. Only when - * all XRI exchange busy complete, the driver unload shall proceed with - * invoking the function reset ioctl mailbox command to the CNA and the - * the rest of the driver unload resource release. - **/ -static void -lpfc_sli4_xri_exchange_busy_wait(struct lpfc_hba *phba) -{ - int wait_time = 0; - int fcp_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list); - int els_xri_cmpl = list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list); - - while (!fcp_xri_cmpl || !els_xri_cmpl) { - if (wait_time > LPFC_XRI_EXCH_BUSY_WAIT_TMO) { - if (!fcp_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2877 FCP XRI exchange busy " - "wait time: %d seconds.\n", - wait_time/1000); - if (!els_xri_cmpl) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2878 ELS XRI exchange busy " - "wait time: %d seconds.\n", - wait_time/1000); - msleep(LPFC_XRI_EXCH_BUSY_WAIT_T2); - wait_time += LPFC_XRI_EXCH_BUSY_WAIT_T2; - } else { - msleep(LPFC_XRI_EXCH_BUSY_WAIT_T1); - wait_time += LPFC_XRI_EXCH_BUSY_WAIT_T1; - } - fcp_xri_cmpl = - list_empty(&phba->sli4_hba.lpfc_abts_scsi_buf_list); - els_xri_cmpl = - list_empty(&phba->sli4_hba.lpfc_abts_els_sgl_list); - } -} - -/** - * lpfc_sli4_hba_unset - Unset the fcoe hba - * @phba: Pointer to HBA context object. - * - * This function is called in the SLI4 code path to reset the HBA's FCoE - * function. The caller is not required to hold any lock. This routine - * issues PCI function reset mailbox command to reset the FCoE function. - * At the end of the function, it calls lpfc_hba_down_post function to - * free any pending commands. - **/ -static void -lpfc_sli4_hba_unset(struct lpfc_hba *phba) -{ - int wait_cnt = 0; - LPFC_MBOXQ_t *mboxq; - struct pci_dev *pdev = phba->pcidev; - - lpfc_stop_hba_timers(phba); - phba->sli4_hba.intr_enable = 0; - - /* - * Gracefully wait out the potential current outstanding asynchronous - * mailbox command. - */ - - /* First, block any pending async mailbox command from posted */ - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; - spin_unlock_irq(&phba->hbalock); - /* Now, trying to wait it out if we can */ - while (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) { - msleep(10); - if (++wait_cnt > LPFC_ACTIVE_MBOX_WAIT_CNT) - break; - } - /* Forcefully release the outstanding mailbox command if timed out */ - if (phba->sli.sli_flag & LPFC_SLI_MBOX_ACTIVE) { - spin_lock_irq(&phba->hbalock); - mboxq = phba->sli.mbox_active; - mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; - __lpfc_mbox_cmpl_put(phba, mboxq); - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - phba->sli.mbox_active = NULL; - spin_unlock_irq(&phba->hbalock); - } - - /* Abort all iocbs associated with the hba */ - lpfc_sli_hba_iocb_abort(phba); - - /* Wait for completion of device XRI exchange busy */ - lpfc_sli4_xri_exchange_busy_wait(phba); - - /* Disable PCI subsystem interrupt */ - lpfc_sli4_disable_intr(phba); - - /* Disable SR-IOV if enabled */ - if (phba->cfg_sriov_nr_virtfn) - pci_disable_sriov(pdev); - - /* Stop kthread signal shall trigger work_done one more time */ - kthread_stop(phba->worker_thread); - - /* Reset SLI4 HBA FCoE function */ - lpfc_pci_function_reset(phba); - lpfc_sli4_queue_destroy(phba); - - /* Stop the SLI4 device port */ - phba->pport->work_port_events = 0; -} - - /** - * lpfc_pc_sli4_params_get - Get the SLI4_PARAMS port capabilities. - * @phba: Pointer to HBA context object. - * @mboxq: Pointer to the mailboxq memory for the mailbox command response. - * - * This function is called in the SLI4 code path to read the port's - * sli4 capabilities. - * - * This function may be be called from any context that can block-wait - * for the completion. The expectation is that this routine is called - * typically from probe_one or from the online routine. - **/ -int -lpfc_pc_sli4_params_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - int rc; - struct lpfc_mqe *mqe; - struct lpfc_pc_sli4_params *sli4_params; - uint32_t mbox_tmo; - - rc = 0; - mqe = &mboxq->u.mqe; - - /* Read the port's SLI4 Parameters port capabilities */ - lpfc_pc_sli4_params(mboxq); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); - } - - if (unlikely(rc)) - return 1; - - sli4_params = &phba->sli4_hba.pc_sli4_params; - sli4_params->if_type = bf_get(if_type, &mqe->un.sli4_params); - sli4_params->sli_rev = bf_get(sli_rev, &mqe->un.sli4_params); - sli4_params->sli_family = bf_get(sli_family, &mqe->un.sli4_params); - sli4_params->featurelevel_1 = bf_get(featurelevel_1, - &mqe->un.sli4_params); - sli4_params->featurelevel_2 = bf_get(featurelevel_2, - &mqe->un.sli4_params); - sli4_params->proto_types = mqe->un.sli4_params.word3; - sli4_params->sge_supp_len = mqe->un.sli4_params.sge_supp_len; - sli4_params->if_page_sz = bf_get(if_page_sz, &mqe->un.sli4_params); - sli4_params->rq_db_window = bf_get(rq_db_window, &mqe->un.sli4_params); - sli4_params->loopbk_scope = bf_get(loopbk_scope, &mqe->un.sli4_params); - sli4_params->eq_pages_max = bf_get(eq_pages, &mqe->un.sli4_params); - sli4_params->eqe_size = bf_get(eqe_size, &mqe->un.sli4_params); - sli4_params->cq_pages_max = bf_get(cq_pages, &mqe->un.sli4_params); - sli4_params->cqe_size = bf_get(cqe_size, &mqe->un.sli4_params); - sli4_params->mq_pages_max = bf_get(mq_pages, &mqe->un.sli4_params); - sli4_params->mqe_size = bf_get(mqe_size, &mqe->un.sli4_params); - sli4_params->mq_elem_cnt = bf_get(mq_elem_cnt, &mqe->un.sli4_params); - sli4_params->wq_pages_max = bf_get(wq_pages, &mqe->un.sli4_params); - sli4_params->wqe_size = bf_get(wqe_size, &mqe->un.sli4_params); - sli4_params->rq_pages_max = bf_get(rq_pages, &mqe->un.sli4_params); - sli4_params->rqe_size = bf_get(rqe_size, &mqe->un.sli4_params); - sli4_params->hdr_pages_max = bf_get(hdr_pages, &mqe->un.sli4_params); - sli4_params->hdr_size = bf_get(hdr_size, &mqe->un.sli4_params); - sli4_params->hdr_pp_align = bf_get(hdr_pp_align, &mqe->un.sli4_params); - sli4_params->sgl_pages_max = bf_get(sgl_pages, &mqe->un.sli4_params); - sli4_params->sgl_pp_align = bf_get(sgl_pp_align, &mqe->un.sli4_params); - - /* Make sure that sge_supp_len can be handled by the driver */ - if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE) - sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE; - - return rc; -} - -/** - * lpfc_get_sli4_parameters - Get the SLI4 Config PARAMETERS. - * @phba: Pointer to HBA context object. - * @mboxq: Pointer to the mailboxq memory for the mailbox command response. - * - * This function is called in the SLI4 code path to read the port's - * sli4 capabilities. - * - * This function may be be called from any context that can block-wait - * for the completion. The expectation is that this routine is called - * typically from probe_one or from the online routine. - **/ -int -lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - int rc; - struct lpfc_mqe *mqe = &mboxq->u.mqe; - struct lpfc_pc_sli4_params *sli4_params; - uint32_t mbox_tmo; - int length; - struct lpfc_sli4_parameters *mbx_sli4_parameters; - - /* - * By default, the driver assumes the SLI4 port requires RPI - * header postings. The SLI4_PARAM response will correct this - * assumption. - */ - phba->sli4_hba.rpi_hdrs_in_use = 1; - - /* Read the port's SLI4 Config Parameters */ - length = (sizeof(struct lpfc_mbx_get_sli4_parameters) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_GET_SLI4_PARAMETERS, - length, LPFC_SLI4_MBX_EMBED); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); - } - if (unlikely(rc)) - return rc; - sli4_params = &phba->sli4_hba.pc_sli4_params; - mbx_sli4_parameters = &mqe->un.get_sli4_parameters.sli4_parameters; - sli4_params->if_type = bf_get(cfg_if_type, mbx_sli4_parameters); - sli4_params->sli_rev = bf_get(cfg_sli_rev, mbx_sli4_parameters); - sli4_params->sli_family = bf_get(cfg_sli_family, mbx_sli4_parameters); - sli4_params->featurelevel_1 = bf_get(cfg_sli_hint_1, - mbx_sli4_parameters); - sli4_params->featurelevel_2 = bf_get(cfg_sli_hint_2, - mbx_sli4_parameters); - if (bf_get(cfg_phwq, mbx_sli4_parameters)) - phba->sli3_options |= LPFC_SLI4_PHWQ_ENABLED; - else - phba->sli3_options &= ~LPFC_SLI4_PHWQ_ENABLED; - sli4_params->sge_supp_len = mbx_sli4_parameters->sge_supp_len; - sli4_params->loopbk_scope = bf_get(loopbk_scope, mbx_sli4_parameters); - sli4_params->cqv = bf_get(cfg_cqv, mbx_sli4_parameters); - sli4_params->mqv = bf_get(cfg_mqv, mbx_sli4_parameters); - sli4_params->wqv = bf_get(cfg_wqv, mbx_sli4_parameters); - sli4_params->rqv = bf_get(cfg_rqv, mbx_sli4_parameters); - sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt, - mbx_sli4_parameters); - sli4_params->sgl_pp_align = bf_get(cfg_sgl_pp_align, - mbx_sli4_parameters); - phba->sli4_hba.extents_in_use = bf_get(cfg_ext, mbx_sli4_parameters); - phba->sli4_hba.rpi_hdrs_in_use = bf_get(cfg_hdrr, mbx_sli4_parameters); - - /* Make sure that sge_supp_len can be handled by the driver */ - if (sli4_params->sge_supp_len > LPFC_MAX_SGE_SIZE) - sli4_params->sge_supp_len = LPFC_MAX_SGE_SIZE; - - return 0; -} - -/** - * lpfc_pci_probe_one_s3 - PCI probe func to reg SLI-3 device to PCI subsystem. - * @pdev: pointer to PCI device - * @pid: pointer to PCI device identifier - * - * This routine is to be called to attach a device with SLI-3 interface spec - * to the PCI subsystem. When an Emulex HBA with SLI-3 interface spec is - * presented on PCI bus, the kernel PCI subsystem looks at PCI device-specific - * information of the device and driver to see if the driver state that it can - * support this kind of device. If the match is successful, the driver core - * invokes this routine. If this routine determines it can claim the HBA, it - * does all the initialization that it needs to do to handle the HBA properly. - * - * Return code - * 0 - driver can claim the device - * negative value - driver can not claim the device - **/ -static int __devinit -lpfc_pci_probe_one_s3(struct pci_dev *pdev, const struct pci_device_id *pid) -{ - struct lpfc_hba *phba; - struct lpfc_vport *vport = NULL; - struct Scsi_Host *shost = NULL; - int error; - uint32_t cfg_mode, intr_mode; - - /* Allocate memory for HBA structure */ - phba = lpfc_hba_alloc(pdev); - if (!phba) - return -ENOMEM; - - /* Perform generic PCI device enabling operation */ - error = lpfc_enable_pci_dev(phba); - if (error) - goto out_free_phba; - - /* Set up SLI API function jump table for PCI-device group-0 HBAs */ - error = lpfc_api_table_setup(phba, LPFC_PCI_DEV_LP); - if (error) - goto out_disable_pci_dev; - - /* Set up SLI-3 specific device PCI memory space */ - error = lpfc_sli_pci_mem_setup(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1402 Failed to set up pci memory space.\n"); - goto out_disable_pci_dev; - } - - /* Set up phase-1 common device driver resources */ - error = lpfc_setup_driver_resource_phase1(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1403 Failed to set up driver resource.\n"); - goto out_unset_pci_mem_s3; - } - - /* Set up SLI-3 specific device driver resources */ - error = lpfc_sli_driver_resource_setup(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1404 Failed to set up driver resource.\n"); - goto out_unset_pci_mem_s3; - } - - /* Initialize and populate the iocb list per host */ - error = lpfc_init_iocb_list(phba, LPFC_IOCB_LIST_CNT); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1405 Failed to initialize iocb list.\n"); - goto out_unset_driver_resource_s3; - } - - /* Set up common device driver resources */ - error = lpfc_setup_driver_resource_phase2(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1406 Failed to set up driver resource.\n"); - goto out_free_iocb_list; - } - - /* Get the default values for Model Name and Description */ - lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); - - /* Create SCSI host to the physical port */ - error = lpfc_create_shost(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1407 Failed to create scsi host.\n"); - goto out_unset_driver_resource; - } - - /* Configure sysfs attributes */ - vport = phba->pport; - error = lpfc_alloc_sysfs_attr(vport); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1476 Failed to allocate sysfs attr\n"); - goto out_destroy_shost; - } - - shost = lpfc_shost_from_vport(vport); /* save shost for error cleanup */ - /* Now, trying to enable interrupt and bring up the device */ - cfg_mode = phba->cfg_use_msi; - while (true) { - /* Put device to a known state before enabling interrupt */ - lpfc_stop_port(phba); - /* Configure and enable interrupt */ - intr_mode = lpfc_sli_enable_intr(phba, cfg_mode); - if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0431 Failed to enable interrupt.\n"); - error = -ENODEV; - goto out_free_sysfs_attr; - } - /* SLI-3 HBA setup */ - if (lpfc_sli_hba_setup(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1477 Failed to set up hba\n"); - error = -ENODEV; - goto out_remove_device; - } - - /* Wait 50ms for the interrupts of previous mailbox commands */ - msleep(50); - /* Check active interrupts on message signaled interrupts */ - if (intr_mode == 0 || - phba->sli.slistat.sli_intr > LPFC_MSIX_VECTORS) { - /* Log the current active interrupt mode */ - phba->intr_mode = intr_mode; - lpfc_log_intr_mode(phba, intr_mode); - break; - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0447 Configure interrupt mode (%d) " - "failed active interrupt test.\n", - intr_mode); - /* Disable the current interrupt mode */ - lpfc_sli_disable_intr(phba); - /* Try next level of interrupt mode */ - cfg_mode = --intr_mode; - } - } - - /* Perform post initialization setup */ - lpfc_post_init_setup(phba); - - /* Check if there are static vports to be created. */ - lpfc_create_static_vport(phba); - - return 0; - -out_remove_device: - lpfc_unset_hba(phba); -out_free_sysfs_attr: - lpfc_free_sysfs_attr(vport); -out_destroy_shost: - lpfc_destroy_shost(phba); -out_unset_driver_resource: - lpfc_unset_driver_resource_phase2(phba); -out_free_iocb_list: - lpfc_free_iocb_list(phba); -out_unset_driver_resource_s3: - lpfc_sli_driver_resource_unset(phba); -out_unset_pci_mem_s3: - lpfc_sli_pci_mem_unset(phba); -out_disable_pci_dev: - lpfc_disable_pci_dev(phba); - if (shost) - scsi_host_put(shost); -out_free_phba: - lpfc_hba_free(phba); - return error; -} - -/** - * lpfc_pci_remove_one_s3 - PCI func to unreg SLI-3 device from PCI subsystem. - * @pdev: pointer to PCI device - * - * This routine is to be called to disattach a device with SLI-3 interface - * spec from PCI subsystem. When an Emulex HBA with SLI-3 interface spec is - * removed from PCI bus, it performs all the necessary cleanup for the HBA - * device to be removed from the PCI subsystem properly. - **/ -static void __devexit -lpfc_pci_remove_one_s3(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_vport **vports; - struct lpfc_hba *phba = vport->phba; - int i; - int bars = pci_select_bars(pdev, IORESOURCE_MEM); - - spin_lock_irq(&phba->hbalock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(&phba->hbalock); - - lpfc_free_sysfs_attr(vport); - - /* Release all the vports against this physical port */ - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) - fc_vport_terminate(vports[i]->fc_vport); - lpfc_destroy_vport_work_array(phba, vports); - - /* Remove FC host and then SCSI host with the physical port */ - fc_remove_host(shost); - scsi_remove_host(shost); - lpfc_cleanup(vport); - - /* - * Bring down the SLI Layer. This step disable all interrupts, - * clears the rings, discards all mailbox commands, and resets - * the HBA. - */ - - /* HBA interrupt will be disabled after this call */ - lpfc_sli_hba_down(phba); - /* Stop kthread signal shall trigger work_done one more time */ - kthread_stop(phba->worker_thread); - /* Final cleanup of txcmplq and reset the HBA */ - lpfc_sli_brdrestart(phba); - - kfree(phba->vpi_bmask); - kfree(phba->vpi_ids); - - lpfc_stop_hba_timers(phba); - spin_lock_irq(&phba->hbalock); - list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); - - lpfc_debugfs_terminate(vport); - - /* Disable SR-IOV if enabled */ - if (phba->cfg_sriov_nr_virtfn) - pci_disable_sriov(pdev); - - /* Disable interrupt */ - lpfc_sli_disable_intr(phba); - - pci_set_drvdata(pdev, NULL); - scsi_host_put(shost); - - /* - * Call scsi_free before mem_free since scsi bufs are released to their - * corresponding pools here. - */ - lpfc_scsi_free(phba); - lpfc_mem_free_all(phba); - - dma_free_coherent(&pdev->dev, lpfc_sli_hbq_size(), - phba->hbqslimp.virt, phba->hbqslimp.phys); - - /* Free resources associated with SLI2 interface */ - dma_free_coherent(&pdev->dev, SLI2_SLIM_SIZE, - phba->slim2p.virt, phba->slim2p.phys); - - /* unmap adapter SLIM and Control Registers */ - iounmap(phba->ctrl_regs_memmap_p); - iounmap(phba->slim_memmap_p); - - lpfc_hba_free(phba); - - pci_release_selected_regions(pdev, bars); - pci_disable_device(pdev); -} - -/** - * lpfc_pci_suspend_one_s3 - PCI func to suspend SLI-3 device for power mgmnt - * @pdev: pointer to PCI device - * @msg: power management message - * - * This routine is to be called from the kernel's PCI subsystem to support - * system Power Management (PM) to device with SLI-3 interface spec. When - * PM invokes this method, it quiesces the device by stopping the driver's - * worker thread for the device, turning off device's interrupt and DMA, - * and bring the device offline. Note that as the driver implements the - * minimum PM requirements to a power-aware driver's PM support for the - * suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, FREEZE) - * to the suspend() method call will be treated as SUSPEND and the driver will - * fully reinitialize its device during resume() method call, the driver will - * set device to PCI_D3hot state in PCI config space instead of setting it - * according to the @msg provided by the PM. - * - * Return code - * 0 - driver suspended the device - * Error otherwise - **/ -static int -lpfc_pci_suspend_one_s3(struct pci_dev *pdev, pm_message_t msg) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0473 PCI device Power Management suspend.\n"); - - /* Bring down the device */ - lpfc_offline_prep(phba); - lpfc_offline(phba); - kthread_stop(phba->worker_thread); - - /* Disable interrupt from device */ - lpfc_sli_disable_intr(phba); - - /* Save device state to PCI config space */ - pci_save_state(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -/** - * lpfc_pci_resume_one_s3 - PCI func to resume SLI-3 device for power mgmnt - * @pdev: pointer to PCI device - * - * This routine is to be called from the kernel's PCI subsystem to support - * system Power Management (PM) to device with SLI-3 interface spec. When PM - * invokes this method, it restores the device's PCI config space state and - * fully reinitializes the device and brings it online. Note that as the - * driver implements the minimum PM requirements to a power-aware driver's - * PM for suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, - * FREEZE) to the suspend() method call will be treated as SUSPEND and the - * driver will fully reinitialize its device during resume() method call, - * the device will be set to PCI_D0 directly in PCI config space before - * restoring the state. - * - * Return code - * 0 - driver suspended the device - * Error otherwise - **/ -static int -lpfc_pci_resume_one_s3(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - uint32_t intr_mode; - int error; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0452 PCI device Power Management resume.\n"); - - /* Restore device state from PCI config space */ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - - if (pdev->is_busmaster) - pci_set_master(pdev); - - /* Startup the kernel thread for this host adapter. */ - phba->worker_thread = kthread_run(lpfc_do_work, phba, - "lpfc_worker_%d", phba->brd_no); - if (IS_ERR(phba->worker_thread)) { - error = PTR_ERR(phba->worker_thread); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0434 PM resume failed to start worker " - "thread: error=x%x.\n", error); - return error; - } - - /* Configure and enable interrupt */ - intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); - if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0430 PM resume Failed to enable interrupt\n"); - return -EIO; - } else - phba->intr_mode = intr_mode; - - /* Restart HBA and bring it online */ - lpfc_sli_brdrestart(phba); - lpfc_online(phba); - - /* Log the current active interrupt mode */ - lpfc_log_intr_mode(phba, phba->intr_mode); - - return 0; -} - -/** - * lpfc_sli_prep_dev_for_recover - Prepare SLI3 device for pci slot recover - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to prepare the SLI3 device for PCI slot recover. It - * aborts all the outstanding SCSI I/Os to the pci device. - **/ -static void -lpfc_sli_prep_dev_for_recover(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2723 PCI channel I/O abort preparing for recovery\n"); - - /* - * There may be errored I/Os through HBA, abort all I/Os on txcmplq - * and let the SCSI mid-layer to retry them to recover. - */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); -} - -/** - * lpfc_sli_prep_dev_for_reset - Prepare SLI3 device for pci slot reset - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to prepare the SLI3 device for PCI slot reset. It - * disables the device interrupt and pci device, and aborts the internal FCP - * pending I/Os. - **/ -static void -lpfc_sli_prep_dev_for_reset(struct lpfc_hba *phba) -{ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2710 PCI channel disable preparing for reset\n"); - - /* Block any management I/Os to the device */ - lpfc_block_mgmt_io(phba); - - /* Block all SCSI devices' I/Os on the host */ - lpfc_scsi_dev_block(phba); - - /* stop all timers */ - lpfc_stop_hba_timers(phba); - - /* Disable interrupt and pci device */ - lpfc_sli_disable_intr(phba); - pci_disable_device(phba->pcidev); - - /* Flush all driver's outstanding SCSI I/Os as we are to reset */ - lpfc_sli_flush_fcp_rings(phba); -} - -/** - * lpfc_sli_prep_dev_for_perm_failure - Prepare SLI3 dev for pci slot disable - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to prepare the SLI3 device for PCI slot permanently - * disabling. It blocks the SCSI transport layer traffic and flushes the FCP - * pending I/Os. - **/ -static void -lpfc_sli_prep_dev_for_perm_failure(struct lpfc_hba *phba) -{ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2711 PCI channel permanent disable for failure\n"); - /* Block all SCSI devices' I/Os on the host */ - lpfc_scsi_dev_block(phba); - - /* stop all timers */ - lpfc_stop_hba_timers(phba); - - /* Clean up all driver's outstanding SCSI I/Os */ - lpfc_sli_flush_fcp_rings(phba); -} - -/** - * lpfc_io_error_detected_s3 - Method for handling SLI-3 device PCI I/O error - * @pdev: pointer to PCI device. - * @state: the current PCI connection state. - * - * This routine is called from the PCI subsystem for I/O error handling to - * device with SLI-3 interface spec. This function is called by the PCI - * subsystem after a PCI bus error affecting this device has been detected. - * When this function is invoked, it will need to stop all the I/Os and - * interrupt(s) to the device. Once that is done, it will return - * PCI_ERS_RESULT_NEED_RESET for the PCI subsystem to perform proper recovery - * as desired. - * - * Return codes - * PCI_ERS_RESULT_CAN_RECOVER - can be recovered with reset_link - * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery - * PCI_ERS_RESULT_DISCONNECT - device could not be recovered - **/ -static pci_ers_result_t -lpfc_io_error_detected_s3(struct pci_dev *pdev, pci_channel_state_t state) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - - switch (state) { - case pci_channel_io_normal: - /* Non-fatal error, prepare for recovery */ - lpfc_sli_prep_dev_for_recover(phba); - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - /* Fatal error, prepare for slot reset */ - lpfc_sli_prep_dev_for_reset(phba); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - /* Permanent failure, prepare for device down */ - lpfc_sli_prep_dev_for_perm_failure(phba); - return PCI_ERS_RESULT_DISCONNECT; - default: - /* Unknown state, prepare and request slot reset */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0472 Unknown PCI error state: x%x\n", state); - lpfc_sli_prep_dev_for_reset(phba); - return PCI_ERS_RESULT_NEED_RESET; - } -} - -/** - * lpfc_io_slot_reset_s3 - Method for restarting PCI SLI-3 device from scratch. - * @pdev: pointer to PCI device. - * - * This routine is called from the PCI subsystem for error handling to - * device with SLI-3 interface spec. This is called after PCI bus has been - * reset to restart the PCI card from scratch, as if from a cold-boot. - * During the PCI subsystem error recovery, after driver returns - * PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform proper error - * recovery and then call this routine before calling the .resume method - * to recover the device. This function will initialize the HBA device, - * enable the interrupt, but it will just put the HBA to offline state - * without passing any I/O traffic. - * - * Return codes - * PCI_ERS_RESULT_RECOVERED - the device has been recovered - * PCI_ERS_RESULT_DISCONNECT - device could not be recovered - */ -static pci_ers_result_t -lpfc_io_slot_reset_s3(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - struct lpfc_sli *psli = &phba->sli; - uint32_t intr_mode; - - dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); - if (pci_enable_device_mem(pdev)) { - printk(KERN_ERR "lpfc: Cannot re-enable " - "PCI device after reset.\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - - pci_restore_state(pdev); - - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - - if (pdev->is_busmaster) - pci_set_master(pdev); - - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - - /* Configure and enable interrupt */ - intr_mode = lpfc_sli_enable_intr(phba, phba->intr_mode); - if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0427 Cannot re-enable interrupt after " - "slot reset.\n"); - return PCI_ERS_RESULT_DISCONNECT; - } else - phba->intr_mode = intr_mode; - - /* Take device offline, it will perform cleanup */ - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_sli_brdrestart(phba); - - /* Log the current active interrupt mode */ - lpfc_log_intr_mode(phba, phba->intr_mode); - - return PCI_ERS_RESULT_RECOVERED; -} - -/** - * lpfc_io_resume_s3 - Method for resuming PCI I/O operation on SLI-3 device. - * @pdev: pointer to PCI device - * - * This routine is called from the PCI subsystem for error handling to device - * with SLI-3 interface spec. It is called when kernel error recovery tells - * the lpfc driver that it is ok to resume normal PCI operation after PCI bus - * error recovery. After this call, traffic can start to flow from this device - * again. - */ -static void -lpfc_io_resume_s3(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - - /* Bring device online, it will be no-op for non-fatal error resume */ - lpfc_online(phba); - - /* Clean up Advanced Error Reporting (AER) if needed */ - if (phba->hba_flag & HBA_AER_ENABLED) - pci_cleanup_aer_uncorrect_error_status(pdev); -} - -/** - * lpfc_sli4_get_els_iocb_cnt - Calculate the # of ELS IOCBs to reserve - * @phba: pointer to lpfc hba data structure. - * - * returns the number of ELS/CT IOCBs to reserve - **/ -int -lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *phba) -{ - int max_xri = phba->sli4_hba.max_cfg_param.max_xri; - - if (phba->sli_rev == LPFC_SLI_REV4) { - if (max_xri <= 100) - return 10; - else if (max_xri <= 256) - return 25; - else if (max_xri <= 512) - return 50; - else if (max_xri <= 1024) - return 100; - else - return 150; - } else - return 0; -} - -/** - * lpfc_write_firmware - attempt to write a firmware image to the port - * @phba: pointer to lpfc hba data structure. - * @fw: pointer to firmware image returned from request_firmware. - * - * returns the number of bytes written if write is successful. - * returns a negative error value if there were errors. - * returns 0 if firmware matches currently active firmware on port. - **/ -int -lpfc_write_firmware(struct lpfc_hba *phba, const struct firmware *fw) -{ - char fwrev[FW_REV_STR_SIZE]; - struct lpfc_grp_hdr *image = (struct lpfc_grp_hdr *)fw->data; - struct list_head dma_buffer_list; - int i, rc = 0; - struct lpfc_dmabuf *dmabuf, *next; - uint32_t offset = 0, temp_offset = 0; - - INIT_LIST_HEAD(&dma_buffer_list); - if ((be32_to_cpu(image->magic_number) != LPFC_GROUP_OJECT_MAGIC_NUM) || - (bf_get_be32(lpfc_grp_hdr_file_type, image) != - LPFC_FILE_TYPE_GROUP) || - (bf_get_be32(lpfc_grp_hdr_id, image) != LPFC_FILE_ID_GROUP) || - (be32_to_cpu(image->size) != fw->size)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3022 Invalid FW image found. " - "Magic:%x Type:%x ID:%x\n", - be32_to_cpu(image->magic_number), - bf_get_be32(lpfc_grp_hdr_file_type, image), - bf_get_be32(lpfc_grp_hdr_id, image)); - return -EINVAL; - } - lpfc_decode_firmware_rev(phba, fwrev, 1); - if (strncmp(fwrev, image->revision, strnlen(image->revision, 16))) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3023 Updating Firmware. Current Version:%s " - "New Version:%s\n", - fwrev, image->revision); - for (i = 0; i < LPFC_MBX_WR_CONFIG_MAX_BDE; i++) { - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), - GFP_KERNEL); - if (!dmabuf) { - rc = -ENOMEM; - goto out; - } - dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, - SLI4_PAGE_SIZE, - &dmabuf->phys, - GFP_KERNEL); - if (!dmabuf->virt) { - kfree(dmabuf); - rc = -ENOMEM; - goto out; - } - list_add_tail(&dmabuf->list, &dma_buffer_list); - } - while (offset < fw->size) { - temp_offset = offset; - list_for_each_entry(dmabuf, &dma_buffer_list, list) { - if (temp_offset + SLI4_PAGE_SIZE > fw->size) { - memcpy(dmabuf->virt, - fw->data + temp_offset, - fw->size - temp_offset); - temp_offset = fw->size; - break; - } - memcpy(dmabuf->virt, fw->data + temp_offset, - SLI4_PAGE_SIZE); - temp_offset += SLI4_PAGE_SIZE; - } - rc = lpfc_wr_object(phba, &dma_buffer_list, - (fw->size - offset), &offset); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3024 Firmware update failed. " - "%d\n", rc); - goto out; - } - } - rc = offset; - } -out: - list_for_each_entry_safe(dmabuf, next, &dma_buffer_list, list) { - list_del(&dmabuf->list); - dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, - dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - } - return rc; -} - -/** - * lpfc_pci_probe_one_s4 - PCI probe func to reg SLI-4 device to PCI subsys - * @pdev: pointer to PCI device - * @pid: pointer to PCI device identifier - * - * This routine is called from the kernel's PCI subsystem to device with - * SLI-4 interface spec. When an Emulex HBA with SLI-4 interface spec is - * presented on PCI bus, the kernel PCI subsystem looks at PCI device-specific - * information of the device and driver to see if the driver state that it - * can support this kind of device. If the match is successful, the driver - * core invokes this routine. If this routine determines it can claim the HBA, - * it does all the initialization that it needs to do to handle the HBA - * properly. - * - * Return code - * 0 - driver can claim the device - * negative value - driver can not claim the device - **/ -static int __devinit -lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) -{ - struct lpfc_hba *phba; - struct lpfc_vport *vport = NULL; - struct Scsi_Host *shost = NULL; - int error; - uint32_t cfg_mode, intr_mode; - int mcnt; - int adjusted_fcp_eq_count; - const struct firmware *fw; - uint8_t file_name[16]; - - /* Allocate memory for HBA structure */ - phba = lpfc_hba_alloc(pdev); - if (!phba) - return -ENOMEM; - - /* Perform generic PCI device enabling operation */ - error = lpfc_enable_pci_dev(phba); - if (error) - goto out_free_phba; - - /* Set up SLI API function jump table for PCI-device group-1 HBAs */ - error = lpfc_api_table_setup(phba, LPFC_PCI_DEV_OC); - if (error) - goto out_disable_pci_dev; - - /* Set up SLI-4 specific device PCI memory space */ - error = lpfc_sli4_pci_mem_setup(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1410 Failed to set up pci memory space.\n"); - goto out_disable_pci_dev; - } - - /* Set up phase-1 common device driver resources */ - error = lpfc_setup_driver_resource_phase1(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1411 Failed to set up driver resource.\n"); - goto out_unset_pci_mem_s4; - } - - /* Set up SLI-4 Specific device driver resources */ - error = lpfc_sli4_driver_resource_setup(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1412 Failed to set up driver resource.\n"); - goto out_unset_pci_mem_s4; - } - - /* Initialize and populate the iocb list per host */ - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2821 initialize iocb list %d.\n", - phba->cfg_iocb_cnt*1024); - error = lpfc_init_iocb_list(phba, phba->cfg_iocb_cnt*1024); - - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1413 Failed to initialize iocb list.\n"); - goto out_unset_driver_resource_s4; - } - - INIT_LIST_HEAD(&phba->active_rrq_list); - INIT_LIST_HEAD(&phba->fcf.fcf_pri_list); - - /* Set up common device driver resources */ - error = lpfc_setup_driver_resource_phase2(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1414 Failed to set up driver resource.\n"); - goto out_free_iocb_list; - } - - /* Get the default values for Model Name and Description */ - lpfc_get_hba_model_desc(phba, phba->ModelName, phba->ModelDesc); - - /* Create SCSI host to the physical port */ - error = lpfc_create_shost(phba); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1415 Failed to create scsi host.\n"); - goto out_unset_driver_resource; - } - - /* Configure sysfs attributes */ - vport = phba->pport; - error = lpfc_alloc_sysfs_attr(vport); - if (error) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1416 Failed to allocate sysfs attr\n"); - goto out_destroy_shost; - } - - shost = lpfc_shost_from_vport(vport); /* save shost for error cleanup */ - /* Now, trying to enable interrupt and bring up the device */ - cfg_mode = phba->cfg_use_msi; - while (true) { - /* Put device to a known state before enabling interrupt */ - lpfc_stop_port(phba); - /* Configure and enable interrupt */ - intr_mode = lpfc_sli4_enable_intr(phba, cfg_mode); - if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0426 Failed to enable interrupt.\n"); - error = -ENODEV; - goto out_free_sysfs_attr; - } - /* Default to single EQ for non-MSI-X */ - if (phba->intr_type != MSIX) - adjusted_fcp_eq_count = 0; - else if (phba->sli4_hba.msix_vec_nr < - phba->cfg_fcp_eq_count + 1) - adjusted_fcp_eq_count = phba->sli4_hba.msix_vec_nr - 1; - else - adjusted_fcp_eq_count = phba->cfg_fcp_eq_count; - phba->cfg_fcp_eq_count = adjusted_fcp_eq_count; - /* Set up SLI-4 HBA */ - if (lpfc_sli4_hba_setup(phba)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1421 Failed to set up hba\n"); - error = -ENODEV; - goto out_disable_intr; - } - - /* Send NOP mbx cmds for non-INTx mode active interrupt test */ - if (intr_mode != 0) - mcnt = lpfc_sli4_send_nop_mbox_cmds(phba, - LPFC_ACT_INTR_CNT); - - /* Check active interrupts received only for MSI/MSI-X */ - if (intr_mode == 0 || - phba->sli.slistat.sli_intr >= LPFC_ACT_INTR_CNT) { - /* Log the current active interrupt mode */ - phba->intr_mode = intr_mode; - lpfc_log_intr_mode(phba, intr_mode); - break; - } - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0451 Configure interrupt mode (%d) " - "failed active interrupt test.\n", - intr_mode); - /* Unset the previous SLI-4 HBA setup. */ - /* - * TODO: Is this operation compatible with IF TYPE 2 - * devices? All port state is deleted and cleared. - */ - lpfc_sli4_unset_hba(phba); - /* Try next level of interrupt mode */ - cfg_mode = --intr_mode; - } - - /* Perform post initialization setup */ - lpfc_post_init_setup(phba); - - /* check for firmware upgrade or downgrade (if_type 2 only) */ - if (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) == - LPFC_SLI_INTF_IF_TYPE_2) { - snprintf(file_name, 16, "%s.grp", phba->ModelName); - error = request_firmware(&fw, file_name, &phba->pcidev->dev); - if (!error) { - lpfc_write_firmware(phba, fw); - release_firmware(fw); - } - } - - /* Check if there are static vports to be created. */ - lpfc_create_static_vport(phba); - return 0; - -out_disable_intr: - lpfc_sli4_disable_intr(phba); -out_free_sysfs_attr: - lpfc_free_sysfs_attr(vport); -out_destroy_shost: - lpfc_destroy_shost(phba); -out_unset_driver_resource: - lpfc_unset_driver_resource_phase2(phba); -out_free_iocb_list: - lpfc_free_iocb_list(phba); -out_unset_driver_resource_s4: - lpfc_sli4_driver_resource_unset(phba); -out_unset_pci_mem_s4: - lpfc_sli4_pci_mem_unset(phba); -out_disable_pci_dev: - lpfc_disable_pci_dev(phba); - if (shost) - scsi_host_put(shost); -out_free_phba: - lpfc_hba_free(phba); - return error; -} - -/** - * lpfc_pci_remove_one_s4 - PCI func to unreg SLI-4 device from PCI subsystem - * @pdev: pointer to PCI device - * - * This routine is called from the kernel's PCI subsystem to device with - * SLI-4 interface spec. When an Emulex HBA with SLI-4 interface spec is - * removed from PCI bus, it performs all the necessary cleanup for the HBA - * device to be removed from the PCI subsystem properly. - **/ -static void __devexit -lpfc_pci_remove_one_s4(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_vport **vports; - struct lpfc_hba *phba = vport->phba; - int i; - - /* Mark the device unloading flag */ - spin_lock_irq(&phba->hbalock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(&phba->hbalock); - - /* Free the HBA sysfs attributes */ - lpfc_free_sysfs_attr(vport); - - /* Release all the vports against this physical port */ - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 1; i <= phba->max_vports && vports[i] != NULL; i++) - fc_vport_terminate(vports[i]->fc_vport); - lpfc_destroy_vport_work_array(phba, vports); - - /* Remove FC host and then SCSI host with the physical port */ - fc_remove_host(shost); - scsi_remove_host(shost); - - /* Perform cleanup on the physical port */ - lpfc_cleanup(vport); - - /* - * Bring down the SLI Layer. This step disables all interrupts, - * clears the rings, discards all mailbox commands, and resets - * the HBA FCoE function. - */ - lpfc_debugfs_terminate(vport); - lpfc_sli4_hba_unset(phba); - - spin_lock_irq(&phba->hbalock); - list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); - - /* Perform scsi free before driver resource_unset since scsi - * buffers are released to their corresponding pools here. - */ - lpfc_scsi_free(phba); - lpfc_sli4_driver_resource_unset(phba); - - /* Unmap adapter Control and Doorbell registers */ - lpfc_sli4_pci_mem_unset(phba); - - /* Release PCI resources and disable device's PCI function */ - scsi_host_put(shost); - lpfc_disable_pci_dev(phba); - - /* Finally, free the driver's device data structure */ - lpfc_hba_free(phba); - - return; -} - -/** - * lpfc_pci_suspend_one_s4 - PCI func to suspend SLI-4 device for power mgmnt - * @pdev: pointer to PCI device - * @msg: power management message - * - * This routine is called from the kernel's PCI subsystem to support system - * Power Management (PM) to device with SLI-4 interface spec. When PM invokes - * this method, it quiesces the device by stopping the driver's worker - * thread for the device, turning off device's interrupt and DMA, and bring - * the device offline. Note that as the driver implements the minimum PM - * requirements to a power-aware driver's PM support for suspend/resume -- all - * the possible PM messages (SUSPEND, HIBERNATE, FREEZE) to the suspend() - * method call will be treated as SUSPEND and the driver will fully - * reinitialize its device during resume() method call, the driver will set - * device to PCI_D3hot state in PCI config space instead of setting it - * according to the @msg provided by the PM. - * - * Return code - * 0 - driver suspended the device - * Error otherwise - **/ -static int -lpfc_pci_suspend_one_s4(struct pci_dev *pdev, pm_message_t msg) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2843 PCI device Power Management suspend.\n"); - - /* Bring down the device */ - lpfc_offline_prep(phba); - lpfc_offline(phba); - kthread_stop(phba->worker_thread); - - /* Disable interrupt from device */ - lpfc_sli4_disable_intr(phba); - lpfc_sli4_queue_destroy(phba); - - /* Save device state to PCI config space */ - pci_save_state(pdev); - pci_set_power_state(pdev, PCI_D3hot); - - return 0; -} - -/** - * lpfc_pci_resume_one_s4 - PCI func to resume SLI-4 device for power mgmnt - * @pdev: pointer to PCI device - * - * This routine is called from the kernel's PCI subsystem to support system - * Power Management (PM) to device with SLI-4 interface spac. When PM invokes - * this method, it restores the device's PCI config space state and fully - * reinitializes the device and brings it online. Note that as the driver - * implements the minimum PM requirements to a power-aware driver's PM for - * suspend/resume -- all the possible PM messages (SUSPEND, HIBERNATE, FREEZE) - * to the suspend() method call will be treated as SUSPEND and the driver - * will fully reinitialize its device during resume() method call, the device - * will be set to PCI_D0 directly in PCI config space before restoring the - * state. - * - * Return code - * 0 - driver suspended the device - * Error otherwise - **/ -static int -lpfc_pci_resume_one_s4(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - uint32_t intr_mode; - int error; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0292 PCI device Power Management resume.\n"); - - /* Restore device state from PCI config space */ - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - - if (pdev->is_busmaster) - pci_set_master(pdev); - - /* Startup the kernel thread for this host adapter. */ - phba->worker_thread = kthread_run(lpfc_do_work, phba, - "lpfc_worker_%d", phba->brd_no); - if (IS_ERR(phba->worker_thread)) { - error = PTR_ERR(phba->worker_thread); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0293 PM resume failed to start worker " - "thread: error=x%x.\n", error); - return error; - } - - /* Configure and enable interrupt */ - intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); - if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0294 PM resume Failed to enable interrupt\n"); - return -EIO; - } else - phba->intr_mode = intr_mode; - - /* Restart HBA and bring it online */ - lpfc_sli_brdrestart(phba); - lpfc_online(phba); - - /* Log the current active interrupt mode */ - lpfc_log_intr_mode(phba, phba->intr_mode); - - return 0; -} - -/** - * lpfc_sli4_prep_dev_for_recover - Prepare SLI4 device for pci slot recover - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to prepare the SLI4 device for PCI slot recover. It - * aborts all the outstanding SCSI I/Os to the pci device. - **/ -static void -lpfc_sli4_prep_dev_for_recover(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2828 PCI channel I/O abort preparing for recovery\n"); - /* - * There may be errored I/Os through HBA, abort all I/Os on txcmplq - * and let the SCSI mid-layer to retry them to recover. - */ - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); -} - -/** - * lpfc_sli4_prep_dev_for_reset - Prepare SLI4 device for pci slot reset - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to prepare the SLI4 device for PCI slot reset. It - * disables the device interrupt and pci device, and aborts the internal FCP - * pending I/Os. - **/ -static void -lpfc_sli4_prep_dev_for_reset(struct lpfc_hba *phba) -{ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2826 PCI channel disable preparing for reset\n"); - - /* Block any management I/Os to the device */ - lpfc_block_mgmt_io(phba); - - /* Block all SCSI devices' I/Os on the host */ - lpfc_scsi_dev_block(phba); - - /* stop all timers */ - lpfc_stop_hba_timers(phba); - - /* Disable interrupt and pci device */ - lpfc_sli4_disable_intr(phba); - lpfc_sli4_queue_destroy(phba); - pci_disable_device(phba->pcidev); - - /* Flush all driver's outstanding SCSI I/Os as we are to reset */ - lpfc_sli_flush_fcp_rings(phba); -} - -/** - * lpfc_sli4_prep_dev_for_perm_failure - Prepare SLI4 dev for pci slot disable - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to prepare the SLI4 device for PCI slot permanently - * disabling. It blocks the SCSI transport layer traffic and flushes the FCP - * pending I/Os. - **/ -static void -lpfc_sli4_prep_dev_for_perm_failure(struct lpfc_hba *phba) -{ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2827 PCI channel permanent disable for failure\n"); - - /* Block all SCSI devices' I/Os on the host */ - lpfc_scsi_dev_block(phba); - - /* stop all timers */ - lpfc_stop_hba_timers(phba); - - /* Clean up all driver's outstanding SCSI I/Os */ - lpfc_sli_flush_fcp_rings(phba); -} - -/** - * lpfc_io_error_detected_s4 - Method for handling PCI I/O error to SLI-4 device - * @pdev: pointer to PCI device. - * @state: the current PCI connection state. - * - * This routine is called from the PCI subsystem for error handling to device - * with SLI-4 interface spec. This function is called by the PCI subsystem - * after a PCI bus error affecting this device has been detected. When this - * function is invoked, it will need to stop all the I/Os and interrupt(s) - * to the device. Once that is done, it will return PCI_ERS_RESULT_NEED_RESET - * for the PCI subsystem to perform proper recovery as desired. - * - * Return codes - * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery - * PCI_ERS_RESULT_DISCONNECT - device could not be recovered - **/ -static pci_ers_result_t -lpfc_io_error_detected_s4(struct pci_dev *pdev, pci_channel_state_t state) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - - switch (state) { - case pci_channel_io_normal: - /* Non-fatal error, prepare for recovery */ - lpfc_sli4_prep_dev_for_recover(phba); - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - /* Fatal error, prepare for slot reset */ - lpfc_sli4_prep_dev_for_reset(phba); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - /* Permanent failure, prepare for device down */ - lpfc_sli4_prep_dev_for_perm_failure(phba); - return PCI_ERS_RESULT_DISCONNECT; - default: - /* Unknown state, prepare and request slot reset */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2825 Unknown PCI error state: x%x\n", state); - lpfc_sli4_prep_dev_for_reset(phba); - return PCI_ERS_RESULT_NEED_RESET; - } -} - -/** - * lpfc_io_slot_reset_s4 - Method for restart PCI SLI-4 device from scratch - * @pdev: pointer to PCI device. - * - * This routine is called from the PCI subsystem for error handling to device - * with SLI-4 interface spec. It is called after PCI bus has been reset to - * restart the PCI card from scratch, as if from a cold-boot. During the - * PCI subsystem error recovery, after the driver returns - * PCI_ERS_RESULT_NEED_RESET, the PCI subsystem will perform proper error - * recovery and then call this routine before calling the .resume method to - * recover the device. This function will initialize the HBA device, enable - * the interrupt, but it will just put the HBA to offline state without - * passing any I/O traffic. - * - * Return codes - * PCI_ERS_RESULT_RECOVERED - the device has been recovered - * PCI_ERS_RESULT_DISCONNECT - device could not be recovered - */ -static pci_ers_result_t -lpfc_io_slot_reset_s4(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - struct lpfc_sli *psli = &phba->sli; - uint32_t intr_mode; - - dev_printk(KERN_INFO, &pdev->dev, "recovering from a slot reset.\n"); - if (pci_enable_device_mem(pdev)) { - printk(KERN_ERR "lpfc: Cannot re-enable " - "PCI device after reset.\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - - pci_restore_state(pdev); - - /* - * As the new kernel behavior of pci_restore_state() API call clears - * device saved_state flag, need to save the restored state again. - */ - pci_save_state(pdev); - - if (pdev->is_busmaster) - pci_set_master(pdev); - - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - - /* Configure and enable interrupt */ - intr_mode = lpfc_sli4_enable_intr(phba, phba->intr_mode); - if (intr_mode == LPFC_INTR_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2824 Cannot re-enable interrupt after " - "slot reset.\n"); - return PCI_ERS_RESULT_DISCONNECT; - } else - phba->intr_mode = intr_mode; - - /* Log the current active interrupt mode */ - lpfc_log_intr_mode(phba, phba->intr_mode); - - return PCI_ERS_RESULT_RECOVERED; -} - -/** - * lpfc_io_resume_s4 - Method for resuming PCI I/O operation to SLI-4 device - * @pdev: pointer to PCI device - * - * This routine is called from the PCI subsystem for error handling to device - * with SLI-4 interface spec. It is called when kernel error recovery tells - * the lpfc driver that it is ok to resume normal PCI operation after PCI bus - * error recovery. After this call, traffic can start to flow from this device - * again. - **/ -static void -lpfc_io_resume_s4(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - - /* - * In case of slot reset, as function reset is performed through - * mailbox command which needs DMA to be enabled, this operation - * has to be moved to the io resume phase. Taking device offline - * will perform the necessary cleanup. - */ - if (!(phba->sli.sli_flag & LPFC_SLI_ACTIVE)) { - /* Perform device reset */ - lpfc_offline_prep(phba); - lpfc_offline(phba); - lpfc_sli_brdrestart(phba); - /* Bring the device back online */ - lpfc_online(phba); - } - - /* Clean up Advanced Error Reporting (AER) if needed */ - if (phba->hba_flag & HBA_AER_ENABLED) - pci_cleanup_aer_uncorrect_error_status(pdev); -} - -/** - * lpfc_pci_probe_one - lpfc PCI probe func to reg dev to PCI subsystem - * @pdev: pointer to PCI device - * @pid: pointer to PCI device identifier - * - * This routine is to be registered to the kernel's PCI subsystem. When an - * Emulex HBA device is presented on PCI bus, the kernel PCI subsystem looks - * at PCI device-specific information of the device and driver to see if the - * driver state that it can support this kind of device. If the match is - * successful, the driver core invokes this routine. This routine dispatches - * the action to the proper SLI-3 or SLI-4 device probing routine, which will - * do all the initialization that it needs to do to handle the HBA device - * properly. - * - * Return code - * 0 - driver can claim the device - * negative value - driver can not claim the device - **/ -static int __devinit -lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) -{ - int rc; - struct lpfc_sli_intf intf; - - if (pci_read_config_dword(pdev, LPFC_SLI_INTF, &intf.word0)) - return -ENODEV; - - if ((bf_get(lpfc_sli_intf_valid, &intf) == LPFC_SLI_INTF_VALID) && - (bf_get(lpfc_sli_intf_slirev, &intf) == LPFC_SLI_INTF_REV_SLI4)) - rc = lpfc_pci_probe_one_s4(pdev, pid); - else - rc = lpfc_pci_probe_one_s3(pdev, pid); - - return rc; -} - -/** - * lpfc_pci_remove_one - lpfc PCI func to unreg dev from PCI subsystem - * @pdev: pointer to PCI device - * - * This routine is to be registered to the kernel's PCI subsystem. When an - * Emulex HBA is removed from PCI bus, the driver core invokes this routine. - * This routine dispatches the action to the proper SLI-3 or SLI-4 device - * remove routine, which will perform all the necessary cleanup for the - * device to be removed from the PCI subsystem properly. - **/ -static void __devexit -lpfc_pci_remove_one(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - - switch (phba->pci_dev_grp) { - case LPFC_PCI_DEV_LP: - lpfc_pci_remove_one_s3(pdev); - break; - case LPFC_PCI_DEV_OC: - lpfc_pci_remove_one_s4(pdev); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1424 Invalid PCI device group: 0x%x\n", - phba->pci_dev_grp); - break; - } - return; -} - -/** - * lpfc_pci_suspend_one - lpfc PCI func to suspend dev for power management - * @pdev: pointer to PCI device - * @msg: power management message - * - * This routine is to be registered to the kernel's PCI subsystem to support - * system Power Management (PM). When PM invokes this method, it dispatches - * the action to the proper SLI-3 or SLI-4 device suspend routine, which will - * suspend the device. - * - * Return code - * 0 - driver suspended the device - * Error otherwise - **/ -static int -lpfc_pci_suspend_one(struct pci_dev *pdev, pm_message_t msg) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - int rc = -ENODEV; - - switch (phba->pci_dev_grp) { - case LPFC_PCI_DEV_LP: - rc = lpfc_pci_suspend_one_s3(pdev, msg); - break; - case LPFC_PCI_DEV_OC: - rc = lpfc_pci_suspend_one_s4(pdev, msg); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1425 Invalid PCI device group: 0x%x\n", - phba->pci_dev_grp); - break; - } - return rc; -} - -/** - * lpfc_pci_resume_one - lpfc PCI func to resume dev for power management - * @pdev: pointer to PCI device - * - * This routine is to be registered to the kernel's PCI subsystem to support - * system Power Management (PM). When PM invokes this method, it dispatches - * the action to the proper SLI-3 or SLI-4 device resume routine, which will - * resume the device. - * - * Return code - * 0 - driver suspended the device - * Error otherwise - **/ -static int -lpfc_pci_resume_one(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - int rc = -ENODEV; - - switch (phba->pci_dev_grp) { - case LPFC_PCI_DEV_LP: - rc = lpfc_pci_resume_one_s3(pdev); - break; - case LPFC_PCI_DEV_OC: - rc = lpfc_pci_resume_one_s4(pdev); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1426 Invalid PCI device group: 0x%x\n", - phba->pci_dev_grp); - break; - } - return rc; -} - -/** - * lpfc_io_error_detected - lpfc method for handling PCI I/O error - * @pdev: pointer to PCI device. - * @state: the current PCI connection state. - * - * This routine is registered to the PCI subsystem for error handling. This - * function is called by the PCI subsystem after a PCI bus error affecting - * this device has been detected. When this routine is invoked, it dispatches - * the action to the proper SLI-3 or SLI-4 device error detected handling - * routine, which will perform the proper error detected operation. - * - * Return codes - * PCI_ERS_RESULT_NEED_RESET - need to reset before recovery - * PCI_ERS_RESULT_DISCONNECT - device could not be recovered - **/ -static pci_ers_result_t -lpfc_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; - - switch (phba->pci_dev_grp) { - case LPFC_PCI_DEV_LP: - rc = lpfc_io_error_detected_s3(pdev, state); - break; - case LPFC_PCI_DEV_OC: - rc = lpfc_io_error_detected_s4(pdev, state); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1427 Invalid PCI device group: 0x%x\n", - phba->pci_dev_grp); - break; - } - return rc; -} - -/** - * lpfc_io_slot_reset - lpfc method for restart PCI dev from scratch - * @pdev: pointer to PCI device. - * - * This routine is registered to the PCI subsystem for error handling. This - * function is called after PCI bus has been reset to restart the PCI card - * from scratch, as if from a cold-boot. When this routine is invoked, it - * dispatches the action to the proper SLI-3 or SLI-4 device reset handling - * routine, which will perform the proper device reset. - * - * Return codes - * PCI_ERS_RESULT_RECOVERED - the device has been recovered - * PCI_ERS_RESULT_DISCONNECT - device could not be recovered - **/ -static pci_ers_result_t -lpfc_io_slot_reset(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - pci_ers_result_t rc = PCI_ERS_RESULT_DISCONNECT; - - switch (phba->pci_dev_grp) { - case LPFC_PCI_DEV_LP: - rc = lpfc_io_slot_reset_s3(pdev); - break; - case LPFC_PCI_DEV_OC: - rc = lpfc_io_slot_reset_s4(pdev); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1428 Invalid PCI device group: 0x%x\n", - phba->pci_dev_grp); - break; - } - return rc; -} - -/** - * lpfc_io_resume - lpfc method for resuming PCI I/O operation - * @pdev: pointer to PCI device - * - * This routine is registered to the PCI subsystem for error handling. It - * is called when kernel error recovery tells the lpfc driver that it is - * OK to resume normal PCI operation after PCI bus error recovery. When - * this routine is invoked, it dispatches the action to the proper SLI-3 - * or SLI-4 device io_resume routine, which will resume the device operation. - **/ -static void -lpfc_io_resume(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; - - switch (phba->pci_dev_grp) { - case LPFC_PCI_DEV_LP: - lpfc_io_resume_s3(pdev); - break; - case LPFC_PCI_DEV_OC: - lpfc_io_resume_s4(pdev); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1429 Invalid PCI device group: 0x%x\n", - phba->pci_dev_grp); - break; - } - return; -} - -/** - * lpfc_mgmt_open - method called when 'lpfcmgmt' is opened from userspace - * @inode: pointer to the inode representing the lpfcmgmt device - * @filep: pointer to the file representing the open lpfcmgmt device - * - * This routine puts a reference count on the lpfc module whenever the - * character device is opened - **/ -static int -lpfc_mgmt_open(struct inode *inode, struct file *filep) -{ - try_module_get(THIS_MODULE); - return 0; -} - -/** - * lpfc_mgmt_release - method called when 'lpfcmgmt' is closed in userspace - * @inode: pointer to the inode representing the lpfcmgmt device - * @filep: pointer to the file representing the open lpfcmgmt device - * - * This routine removes a reference count from the lpfc module when the - * character device is closed - **/ -static int -lpfc_mgmt_release(struct inode *inode, struct file *filep) -{ - module_put(THIS_MODULE); - return 0; -} - -static struct pci_device_id lpfc_id_table[] = { - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_VIPER, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FIREFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_THOR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PEGASUS, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_CENTAUR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_DRAGONFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SUPERFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_RFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_NEPTUNE_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HELIOS_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BMID, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BSMB, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_HORNET, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZEPHYR_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZMID, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_ZSMB, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_TFLY, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP101, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP10000S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LP11000S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LPE11000S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_MID, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SMB, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_DCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_SCSP, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_SAT_S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_VF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_PF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_PROTEUS_S, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TIGERSHARK, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_SERVERENGINE, PCI_DEVICE_ID_TOMCAT, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_FALCON, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_BALIUS, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FC_VF, - PCI_ANY_ID, PCI_ANY_ID, }, - {PCI_VENDOR_ID_EMULEX, PCI_DEVICE_ID_LANCER_FCOE_VF, - PCI_ANY_ID, PCI_ANY_ID, }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, lpfc_id_table); - -static struct pci_error_handlers lpfc_err_handler = { - .error_detected = lpfc_io_error_detected, - .slot_reset = lpfc_io_slot_reset, - .resume = lpfc_io_resume, -}; - -static struct pci_driver lpfc_driver = { - .name = LPFC_DRIVER_NAME, - .id_table = lpfc_id_table, - .probe = lpfc_pci_probe_one, - .remove = __devexit_p(lpfc_pci_remove_one), - .suspend = lpfc_pci_suspend_one, - .resume = lpfc_pci_resume_one, - .err_handler = &lpfc_err_handler, -}; - -static const struct file_operations lpfc_mgmt_fop = { - .open = lpfc_mgmt_open, - .release = lpfc_mgmt_release, -}; - -static struct miscdevice lpfc_mgmt_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "lpfcmgmt", - .fops = &lpfc_mgmt_fop, -}; - -/** - * lpfc_init - lpfc module initialization routine - * - * This routine is to be invoked when the lpfc module is loaded into the - * kernel. The special kernel macro module_init() is used to indicate the - * role of this routine to the kernel as lpfc module entry point. - * - * Return codes - * 0 - successful - * -ENOMEM - FC attach transport failed - * all others - failed - */ -static int __init -lpfc_init(void) -{ - int error = 0; - - printk(LPFC_MODULE_DESC "\n"); - printk(LPFC_COPYRIGHT "\n"); - - error = misc_register(&lpfc_mgmt_dev); - if (error) - printk(KERN_ERR "Could not register lpfcmgmt device, " - "misc_register returned with status %d", error); - - if (lpfc_enable_npiv) { - lpfc_transport_functions.vport_create = lpfc_vport_create; - lpfc_transport_functions.vport_delete = lpfc_vport_delete; - } - lpfc_transport_template = - fc_attach_transport(&lpfc_transport_functions); - if (lpfc_transport_template == NULL) - return -ENOMEM; - if (lpfc_enable_npiv) { - lpfc_vport_transport_template = - fc_attach_transport(&lpfc_vport_transport_functions); - if (lpfc_vport_transport_template == NULL) { - fc_release_transport(lpfc_transport_template); - return -ENOMEM; - } - } - error = pci_register_driver(&lpfc_driver); - if (error) { - fc_release_transport(lpfc_transport_template); - if (lpfc_enable_npiv) - fc_release_transport(lpfc_vport_transport_template); - } - - return error; -} - -/** - * lpfc_exit - lpfc module removal routine - * - * This routine is invoked when the lpfc module is removed from the kernel. - * The special kernel macro module_exit() is used to indicate the role of - * this routine to the kernel as lpfc module exit point. - */ -static void __exit -lpfc_exit(void) -{ - misc_deregister(&lpfc_mgmt_dev); - pci_unregister_driver(&lpfc_driver); - fc_release_transport(lpfc_transport_template); - if (lpfc_enable_npiv) - fc_release_transport(lpfc_vport_transport_template); - if (_dump_buf_data) { - printk(KERN_ERR "9062 BLKGRD: freeing %lu pages for " - "_dump_buf_data at 0x%p\n", - (1L << _dump_buf_data_order), _dump_buf_data); - free_pages((unsigned long)_dump_buf_data, _dump_buf_data_order); - } - - if (_dump_buf_dif) { - printk(KERN_ERR "9049 BLKGRD: freeing %lu pages for " - "_dump_buf_dif at 0x%p\n", - (1L << _dump_buf_dif_order), _dump_buf_dif); - free_pages((unsigned long)_dump_buf_dif, _dump_buf_dif_order); - } -} - -module_init(lpfc_init); -module_exit(lpfc_exit); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION(LPFC_MODULE_DESC); -MODULE_AUTHOR("Emulex Corporation - tech.support@emulex.com"); -MODULE_VERSION("0:" LPFC_DRIVER_VERSION); diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_logmsg.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_logmsg.h deleted file mode 100644 index baf53e6c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_logmsg.h +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#define LOG_ELS 0x00000001 /* ELS events */ -#define LOG_DISCOVERY 0x00000002 /* Link discovery events */ -#define LOG_MBOX 0x00000004 /* Mailbox events */ -#define LOG_INIT 0x00000008 /* Initialization events */ -#define LOG_LINK_EVENT 0x00000010 /* Link events */ -#define LOG_IP 0x00000020 /* IP traffic history */ -#define LOG_FCP 0x00000040 /* FCP traffic history */ -#define LOG_NODE 0x00000080 /* Node table events */ -#define LOG_TEMP 0x00000100 /* Temperature sensor events */ -#define LOG_BG 0x00000200 /* BlockGuard events */ -#define LOG_MISC 0x00000400 /* Miscellaneous events */ -#define LOG_SLI 0x00000800 /* SLI events */ -#define LOG_FCP_ERROR 0x00001000 /* log errors, not underruns */ -#define LOG_LIBDFC 0x00002000 /* Libdfc events */ -#define LOG_VPORT 0x00004000 /* NPIV events */ -#define LOG_SECURITY 0x00008000 /* Security events */ -#define LOG_EVENT 0x00010000 /* CT,TEMP,DUMP, logging */ -#define LOG_FIP 0x00020000 /* FIP events */ -#define LOG_FCP_UNDER 0x00040000 /* FCP underruns errors */ -#define LOG_ALL_MSG 0xffffffff /* LOG all messages */ - -#define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \ -do { \ - { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) \ - dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \ - fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } \ -} while (0) - -#define lpfc_printf_log(phba, level, mask, fmt, arg...) \ -do { \ - { uint32_t log_verbose = (phba)->pport ? \ - (phba)->pport->cfg_log_verbose : \ - (phba)->cfg_log_verbose; \ - if (((mask) & log_verbose) || (level[1] <= '3')) \ - dev_printk(level, &((phba)->pcidev)->dev, "%d:" \ - fmt, phba->brd_no, ##arg); \ - } \ -} while (0) diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mbox.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mbox.c deleted file mode 100644 index 20336f09..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mbox.c +++ /dev/null @@ -1,2344 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_compat.h" - -/** - * lpfc_dump_static_vport - Dump HBA's static vport information. - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * @offset: offset for dumping vport info. - * - * The dump mailbox command provides a method for the device driver to obtain - * various types of information from the HBA device. - * - * This routine prepares the mailbox command for dumping list of static - * vports to be created. - **/ -int -lpfc_dump_static_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, - uint16_t offset) -{ - MAILBOX_t *mb; - struct lpfc_dmabuf *mp; - - mb = &pmb->u.mb; - - /* Setup to dump vport info region */ - memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_DUMP_MEMORY; - mb->un.varDmp.type = DMP_NV_PARAMS; - mb->un.varDmp.entry_index = offset; - mb->un.varDmp.region_id = DMP_REGION_VPORT; - mb->mbxOwner = OWN_HOST; - - /* For SLI3 HBAs data is embedded in mailbox */ - if (phba->sli_rev != LPFC_SLI_REV4) { - mb->un.varDmp.cv = 1; - mb->un.varDmp.word_cnt = DMP_RSP_SIZE/sizeof(uint32_t); - return 0; - } - - /* For SLI4 HBAs driver need to allocate memory */ - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - - if (!mp || !mp->virt) { - kfree(mp); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2605 lpfc_dump_static_vport: memory" - " allocation failed\n"); - return 1; - } - memset(mp->virt, 0, LPFC_BPL_SIZE); - INIT_LIST_HEAD(&mp->list); - /* save address for completion */ - pmb->context2 = (uint8_t *) mp; - mb->un.varWords[3] = putPaddrLow(mp->phys); - mb->un.varWords[4] = putPaddrHigh(mp->phys); - mb->un.varDmp.sli4_length = sizeof(struct static_vport_info); - - return 0; -} - -/** - * lpfc_down_link - Bring down HBAs link. - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This routine prepares a mailbox command to bring down HBA link. - **/ -void -lpfc_down_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb; - memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); - mb = &pmb->u.mb; - mb->mbxCommand = MBX_DOWN_LINK; - mb->mbxOwner = OWN_HOST; -} - -/** - * lpfc_dump_mem - Prepare a mailbox command for reading a region. - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * @offset: offset into the region. - * @region_id: config region id. - * - * The dump mailbox command provides a method for the device driver to obtain - * various types of information from the HBA device. - * - * This routine prepares the mailbox command for dumping HBA's config region. - **/ -void -lpfc_dump_mem(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, uint16_t offset, - uint16_t region_id) -{ - MAILBOX_t *mb; - void *ctx; - - mb = &pmb->u.mb; - ctx = pmb->context2; - - /* Setup to dump VPD region */ - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_DUMP_MEMORY; - mb->un.varDmp.cv = 1; - mb->un.varDmp.type = DMP_NV_PARAMS; - mb->un.varDmp.entry_index = offset; - mb->un.varDmp.region_id = region_id; - mb->un.varDmp.word_cnt = (DMP_RSP_SIZE / sizeof (uint32_t)); - mb->un.varDmp.co = 0; - mb->un.varDmp.resp_offset = 0; - pmb->context2 = ctx; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_dump_wakeup_param - Prepare mailbox command for retrieving wakeup params - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * This function create a dump memory mailbox command to dump wake up - * parameters. - */ -void -lpfc_dump_wakeup_param(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb; - void *ctx; - - mb = &pmb->u.mb; - /* Save context so that we can restore after memset */ - ctx = pmb->context2; - - /* Setup to dump VPD region */ - memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_DUMP_MEMORY; - mb->mbxOwner = OWN_HOST; - mb->un.varDmp.cv = 1; - mb->un.varDmp.type = DMP_NV_PARAMS; - mb->un.varDmp.entry_index = 0; - mb->un.varDmp.region_id = WAKE_UP_PARMS_REGION_ID; - mb->un.varDmp.word_cnt = WAKE_UP_PARMS_WORD_SIZE; - mb->un.varDmp.co = 0; - mb->un.varDmp.resp_offset = 0; - pmb->context2 = ctx; - return; -} - -/** - * lpfc_read_nv - Prepare a mailbox command for reading HBA's NVRAM param - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The read NVRAM mailbox command returns the HBA's non-volatile parameters - * that are used as defaults when the Fibre Channel link is brought on-line. - * - * This routine prepares the mailbox command for reading information stored - * in the HBA's NVRAM. Specifically, the HBA's WWNN and WWPN. - **/ -void -lpfc_read_nv(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_READ_NV; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_config_async - Prepare a mailbox command for enabling HBA async event - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * @ring: ring number for the asynchronous event to be configured. - * - * The asynchronous event enable mailbox command is used to enable the - * asynchronous event posting via the ASYNC_STATUS_CN IOCB response and - * specifies the default ring to which events are posted. - * - * This routine prepares the mailbox command for enabling HBA asynchronous - * event support on a IOCB ring. - **/ -void -lpfc_config_async(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb, - uint32_t ring) -{ - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_ASYNCEVT_ENABLE; - mb->un.varCfgAsyncEvent.ring = ring; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_heart_beat - Prepare a mailbox command for heart beat - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The heart beat mailbox command is used to detect an unresponsive HBA, which - * is defined as any device where no error attention is sent and both mailbox - * and rings are not processed. - * - * This routine prepares the mailbox command for issuing a heart beat in the - * form of mailbox command to the HBA. The timely completion of the heart - * beat mailbox command indicates the health of the HBA. - **/ -void -lpfc_heart_beat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_HEARTBEAT; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_read_topology - Prepare a mailbox command for reading HBA topology - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * @mp: DMA buffer memory for reading the link attention information into. - * - * The read topology mailbox command is issued to read the link topology - * information indicated by the HBA port when the Link Event bit of the Host - * Attention (HSTATT) register is set to 1 (For SLI-3) or when an FC Link - * Attention ACQE is received from the port (For SLI-4). A Link Event - * Attention occurs based on an exception detected at the Fibre Channel link - * interface. - * - * This routine prepares the mailbox command for reading HBA link topology - * information. A DMA memory has been set aside and address passed to the - * HBA through @mp for the HBA to DMA link attention information into the - * memory as part of the execution of the mailbox command. - * - * Return codes - * 0 - Success (currently always return 0) - **/ -int -lpfc_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, - struct lpfc_dmabuf *mp) -{ - MAILBOX_t *mb; - struct lpfc_sli *psli; - - psli = &phba->sli; - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - INIT_LIST_HEAD(&mp->list); - mb->mbxCommand = MBX_READ_TOPOLOGY; - mb->un.varReadTop.lilpBde64.tus.f.bdeSize = LPFC_ALPA_MAP_SIZE; - mb->un.varReadTop.lilpBde64.addrHigh = putPaddrHigh(mp->phys); - mb->un.varReadTop.lilpBde64.addrLow = putPaddrLow(mp->phys); - - /* Save address for later completion and set the owner to host so that - * the FW knows this mailbox is available for processing. - */ - pmb->context1 = (uint8_t *)mp; - mb->mbxOwner = OWN_HOST; - return (0); -} - -/** - * lpfc_clear_la - Prepare a mailbox command for clearing HBA link attention - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The clear link attention mailbox command is issued to clear the link event - * attention condition indicated by the Link Event bit of the Host Attention - * (HSTATT) register. The link event attention condition is cleared only if - * the event tag specified matches that of the current link event counter. - * The current event tag is read using the read link attention event mailbox - * command. - * - * This routine prepares the mailbox command for clearing HBA link attention - * information. - **/ -void -lpfc_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - mb->un.varClearLA.eventTag = phba->fc_eventTag; - mb->mbxCommand = MBX_CLEAR_LA; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_config_link - Prepare a mailbox command for configuring link on a HBA - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The configure link mailbox command is used before the initialize link - * mailbox command to override default value and to configure link-oriented - * parameters such as DID address and various timers. Typically, this - * command would be used after an F_Port login to set the returned DID address - * and the fabric timeout values. This command is not valid before a configure - * port command has configured the HBA port. - * - * This routine prepares the mailbox command for configuring link on a HBA. - **/ -void -lpfc_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) -{ - struct lpfc_vport *vport = phba->pport; - MAILBOX_t *mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - /* NEW_FEATURE - * SLI-2, Coalescing Response Feature. - */ - if (phba->cfg_cr_delay) { - mb->un.varCfgLnk.cr = 1; - mb->un.varCfgLnk.ci = 1; - mb->un.varCfgLnk.cr_delay = phba->cfg_cr_delay; - mb->un.varCfgLnk.cr_count = phba->cfg_cr_count; - } - - mb->un.varCfgLnk.myId = vport->fc_myDID; - mb->un.varCfgLnk.edtov = phba->fc_edtov; - mb->un.varCfgLnk.arbtov = phba->fc_arbtov; - mb->un.varCfgLnk.ratov = phba->fc_ratov; - mb->un.varCfgLnk.rttov = phba->fc_rttov; - mb->un.varCfgLnk.altov = phba->fc_altov; - mb->un.varCfgLnk.crtov = phba->fc_crtov; - mb->un.varCfgLnk.citov = phba->fc_citov; - - if (phba->cfg_ack0) - mb->un.varCfgLnk.ack0_enable = 1; - - mb->mbxCommand = MBX_CONFIG_LINK; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_config_msi - Prepare a mailbox command for configuring msi-x - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The configure MSI-X mailbox command is used to configure the HBA's SLI-3 - * MSI-X multi-message interrupt vector association to interrupt attention - * conditions. - * - * Return codes - * 0 - Success - * -EINVAL - Failure - **/ -int -lpfc_config_msi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - uint32_t attentionConditions[2]; - - /* Sanity check */ - if (phba->cfg_use_msi != 2) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0475 Not configured for supporting MSI-X " - "cfg_use_msi: 0x%x\n", phba->cfg_use_msi); - return -EINVAL; - } - - if (phba->sli_rev < 3) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0476 HBA not supporting SLI-3 or later " - "SLI Revision: 0x%x\n", phba->sli_rev); - return -EINVAL; - } - - /* Clear mailbox command fields */ - memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); - - /* - * SLI-3, Message Signaled Interrupt Fearure. - */ - - /* Multi-message attention configuration */ - attentionConditions[0] = (HA_R0ATT | HA_R1ATT | HA_R2ATT | HA_ERATT | - HA_LATT | HA_MBATT); - attentionConditions[1] = 0; - - mb->un.varCfgMSI.attentionConditions[0] = attentionConditions[0]; - mb->un.varCfgMSI.attentionConditions[1] = attentionConditions[1]; - - /* - * Set up message number to HA bit association - */ -#ifdef __BIG_ENDIAN_BITFIELD - /* RA0 (FCP Ring) */ - mb->un.varCfgMSI.messageNumberByHA[HA_R0_POS] = 1; - /* RA1 (Other Protocol Extra Ring) */ - mb->un.varCfgMSI.messageNumberByHA[HA_R1_POS] = 1; -#else /* __LITTLE_ENDIAN_BITFIELD */ - /* RA0 (FCP Ring) */ - mb->un.varCfgMSI.messageNumberByHA[HA_R0_POS^3] = 1; - /* RA1 (Other Protocol Extra Ring) */ - mb->un.varCfgMSI.messageNumberByHA[HA_R1_POS^3] = 1; -#endif - /* Multi-message interrupt autoclear configuration*/ - mb->un.varCfgMSI.autoClearHA[0] = attentionConditions[0]; - mb->un.varCfgMSI.autoClearHA[1] = attentionConditions[1]; - - /* For now, HBA autoclear does not work reliably, disable it */ - mb->un.varCfgMSI.autoClearHA[0] = 0; - mb->un.varCfgMSI.autoClearHA[1] = 0; - - /* Set command and owner bit */ - mb->mbxCommand = MBX_CONFIG_MSI; - mb->mbxOwner = OWN_HOST; - - return 0; -} - -/** - * lpfc_init_link - Prepare a mailbox command for initialize link on a HBA - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * @topology: the link topology for the link to be initialized to. - * @linkspeed: the link speed for the link to be initialized to. - * - * The initialize link mailbox command is used to initialize the Fibre - * Channel link. This command must follow a configure port command that - * establishes the mode of operation. - * - * This routine prepares the mailbox command for initializing link on a HBA - * with the specified link topology and speed. - **/ -void -lpfc_init_link(struct lpfc_hba * phba, - LPFC_MBOXQ_t * pmb, uint32_t topology, uint32_t linkspeed) -{ - lpfc_vpd_t *vpd; - struct lpfc_sli *psli; - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - psli = &phba->sli; - switch (topology) { - case FLAGS_TOPOLOGY_MODE_LOOP_PT: - mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP; - mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER; - break; - case FLAGS_TOPOLOGY_MODE_PT_PT: - mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; - break; - case FLAGS_TOPOLOGY_MODE_LOOP: - mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_LOOP; - break; - case FLAGS_TOPOLOGY_MODE_PT_LOOP: - mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; - mb->un.varInitLnk.link_flags |= FLAGS_TOPOLOGY_FAILOVER; - break; - case FLAGS_LOCAL_LB: - mb->un.varInitLnk.link_flags = FLAGS_LOCAL_LB; - break; - } - - /* Enable asynchronous ABTS responses from firmware */ - mb->un.varInitLnk.link_flags |= FLAGS_IMED_ABORT; - - /* NEW_FEATURE - * Setting up the link speed - */ - vpd = &phba->vpd; - if (vpd->rev.feaLevelHigh >= 0x02){ - switch(linkspeed){ - case LPFC_USER_LINK_SPEED_1G: - mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; - mb->un.varInitLnk.link_speed = LINK_SPEED_1G; - break; - case LPFC_USER_LINK_SPEED_2G: - mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; - mb->un.varInitLnk.link_speed = LINK_SPEED_2G; - break; - case LPFC_USER_LINK_SPEED_4G: - mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; - mb->un.varInitLnk.link_speed = LINK_SPEED_4G; - break; - case LPFC_USER_LINK_SPEED_8G: - mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; - mb->un.varInitLnk.link_speed = LINK_SPEED_8G; - break; - case LPFC_USER_LINK_SPEED_10G: - mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; - mb->un.varInitLnk.link_speed = LINK_SPEED_10G; - break; - case LPFC_USER_LINK_SPEED_16G: - mb->un.varInitLnk.link_flags |= FLAGS_LINK_SPEED; - mb->un.varInitLnk.link_speed = LINK_SPEED_16G; - break; - case LPFC_USER_LINK_SPEED_AUTO: - default: - mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO; - break; - } - - } - else - mb->un.varInitLnk.link_speed = LINK_SPEED_AUTO; - - mb->mbxCommand = (volatile uint8_t)MBX_INIT_LINK; - mb->mbxOwner = OWN_HOST; - mb->un.varInitLnk.fabric_AL_PA = phba->fc_pref_ALPA; - return; -} - -/** - * lpfc_read_sparam - Prepare a mailbox command for reading HBA parameters - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * @vpi: virtual N_Port identifier. - * - * The read service parameter mailbox command is used to read the HBA port - * service parameters. The service parameters are read into the buffer - * specified directly by a BDE in the mailbox command. These service - * parameters may then be used to build the payload of an N_Port/F_POrt - * login request and reply (LOGI/ACC). - * - * This routine prepares the mailbox command for reading HBA port service - * parameters. The DMA memory is allocated in this function and the addresses - * are populated into the mailbox command for the HBA to DMA the service - * parameters into. - * - * Return codes - * 0 - Success - * 1 - DMA memory allocation failed - **/ -int -lpfc_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb, int vpi) -{ - struct lpfc_dmabuf *mp; - MAILBOX_t *mb; - struct lpfc_sli *psli; - - psli = &phba->sli; - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - mb->mbxOwner = OWN_HOST; - - /* Get a buffer to hold the HBAs Service Parameters */ - - mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp || !mp->virt) { - kfree(mp); - mb->mbxCommand = MBX_READ_SPARM64; - /* READ_SPARAM: no buffers */ - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "0301 READ_SPARAM: no buffers\n"); - return (1); - } - INIT_LIST_HEAD(&mp->list); - mb->mbxCommand = MBX_READ_SPARM64; - mb->un.varRdSparm.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm); - mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(mp->phys); - mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(mp->phys); - if (phba->sli_rev >= LPFC_SLI_REV3) - mb->un.varRdSparm.vpi = phba->vpi_ids[vpi]; - - /* save address for completion */ - pmb->context1 = mp; - - return (0); -} - -/** - * lpfc_unreg_did - Prepare a mailbox command for unregistering DID - * @phba: pointer to lpfc hba data structure. - * @vpi: virtual N_Port identifier. - * @did: remote port identifier. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The unregister DID mailbox command is used to unregister an N_Port/F_Port - * login for an unknown RPI by specifying the DID of a remote port. This - * command frees an RPI context in the HBA port. This has the effect of - * performing an implicit N_Port/F_Port logout. - * - * This routine prepares the mailbox command for unregistering a remote - * N_Port/F_Port (DID) login. - **/ -void -lpfc_unreg_did(struct lpfc_hba * phba, uint16_t vpi, uint32_t did, - LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - mb->un.varUnregDID.did = did; - mb->un.varUnregDID.vpi = vpi; - if ((vpi != 0xffff) && - (phba->sli_rev == LPFC_SLI_REV4)) - mb->un.varUnregDID.vpi = phba->vpi_ids[vpi]; - - mb->mbxCommand = MBX_UNREG_D_ID; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_read_config - Prepare a mailbox command for reading HBA configuration - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The read configuration mailbox command is used to read the HBA port - * configuration parameters. This mailbox command provides a method for - * seeing any parameters that may have changed via various configuration - * mailbox commands. - * - * This routine prepares the mailbox command for reading out HBA configuration - * parameters. - **/ -void -lpfc_read_config(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - mb->mbxCommand = MBX_READ_CONFIG; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_read_lnk_stat - Prepare a mailbox command for reading HBA link stats - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The read link status mailbox command is used to read the link status from - * the HBA. Link status includes all link-related error counters. These - * counters are maintained by the HBA and originated in the link hardware - * unit. Note that all of these counters wrap. - * - * This routine prepares the mailbox command for reading out HBA link status. - **/ -void -lpfc_read_lnk_stat(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - mb->mbxCommand = MBX_READ_LNK_STAT; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_reg_rpi - Prepare a mailbox command for registering remote login - * @phba: pointer to lpfc hba data structure. - * @vpi: virtual N_Port identifier. - * @did: remote port identifier. - * @param: pointer to memory holding the server parameters. - * @pmb: pointer to the driver internal queue element for mailbox command. - * @rpi: the rpi to use in the registration (usually only used for SLI4. - * - * The registration login mailbox command is used to register an N_Port or - * F_Port login. This registration allows the HBA to cache the remote N_Port - * service parameters internally and thereby make the appropriate FC-2 - * decisions. The remote port service parameters are handed off by the driver - * to the HBA using a descriptor entry that directly identifies a buffer in - * host memory. In exchange, the HBA returns an RPI identifier. - * - * This routine prepares the mailbox command for registering remote port login. - * The function allocates DMA buffer for passing the service parameters to the - * HBA with the mailbox command. - * - * Return codes - * 0 - Success - * 1 - DMA memory allocation failed - **/ -int -lpfc_reg_rpi(struct lpfc_hba *phba, uint16_t vpi, uint32_t did, - uint8_t *param, LPFC_MBOXQ_t *pmb, uint16_t rpi) -{ - MAILBOX_t *mb = &pmb->u.mb; - uint8_t *sparam; - struct lpfc_dmabuf *mp; - - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - mb->un.varRegLogin.rpi = 0; - if (phba->sli_rev == LPFC_SLI_REV4) - mb->un.varRegLogin.rpi = phba->sli4_hba.rpi_ids[rpi]; - if (phba->sli_rev >= LPFC_SLI_REV3) - mb->un.varRegLogin.vpi = phba->vpi_ids[vpi]; - mb->un.varRegLogin.did = did; - mb->mbxOwner = OWN_HOST; - /* Get a buffer to hold NPorts Service Parameters */ - mp = kmalloc(sizeof (struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - if (!mp || !mp->virt) { - kfree(mp); - mb->mbxCommand = MBX_REG_LOGIN64; - /* REG_LOGIN: no buffers */ - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "0302 REG_LOGIN: no buffers, VPI:%d DID:x%x, " - "rpi x%x\n", vpi, did, rpi); - return 1; - } - INIT_LIST_HEAD(&mp->list); - sparam = mp->virt; - - /* Copy param's into a new buffer */ - memcpy(sparam, param, sizeof (struct serv_parm)); - - /* save address for completion */ - pmb->context1 = (uint8_t *) mp; - - mb->mbxCommand = MBX_REG_LOGIN64; - mb->un.varRegLogin.un.sp64.tus.f.bdeSize = sizeof (struct serv_parm); - mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(mp->phys); - mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(mp->phys); - - return 0; -} - -/** - * lpfc_unreg_login - Prepare a mailbox command for unregistering remote login - * @phba: pointer to lpfc hba data structure. - * @vpi: virtual N_Port identifier. - * @rpi: remote port identifier - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The unregistration login mailbox command is used to unregister an N_Port - * or F_Port login. This command frees an RPI context in the HBA. It has the - * effect of performing an implicit N_Port/F_Port logout. - * - * This routine prepares the mailbox command for unregistering remote port - * login. - * - * For SLI4 ports, the rpi passed to this function must be the physical - * rpi value, not the logical index. - **/ -void -lpfc_unreg_login(struct lpfc_hba *phba, uint16_t vpi, uint32_t rpi, - LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb; - - mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - mb->un.varUnregLogin.rpi = rpi; - mb->un.varUnregLogin.rsvd1 = 0; - if (phba->sli_rev >= LPFC_SLI_REV3) - mb->un.varUnregLogin.vpi = phba->vpi_ids[vpi]; - - mb->mbxCommand = MBX_UNREG_LOGIN; - mb->mbxOwner = OWN_HOST; - - return; -} - -/** - * lpfc_sli4_unreg_all_rpis - unregister all RPIs for a vport on SLI4 HBA. - * @vport: pointer to a vport object. - * - * This routine sends mailbox command to unregister all active RPIs for - * a vport. - **/ -void -lpfc_sli4_unreg_all_rpis(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mbox; - int rc; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox) { - /* - * For SLI4 functions, the rpi field is overloaded for - * the vport context unreg all. This routine passes - * 0 for the rpi field in lpfc_unreg_login for compatibility - * with SLI3 and then overrides the rpi field with the - * expected value for SLI4. - */ - lpfc_unreg_login(phba, vport->vpi, phba->vpi_ids[vport->vpi], - mbox); - mbox->u.mb.un.varUnregLogin.rsvd1 = 0x4000; - mbox->vport = vport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->context1 = NULL; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - mempool_free(mbox, phba->mbox_mem_pool); - } -} - -/** - * lpfc_reg_vpi - Prepare a mailbox command for registering vport identifier - * @phba: pointer to lpfc hba data structure. - * @vpi: virtual N_Port identifier. - * @sid: Fibre Channel S_ID (N_Port_ID assigned to a virtual N_Port). - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The registration vport identifier mailbox command is used to activate a - * virtual N_Port after it has acquired an N_Port_ID. The HBA validates the - * N_Port_ID against the information in the selected virtual N_Port context - * block and marks it active to allow normal processing of IOCB commands and - * received unsolicited exchanges. - * - * This routine prepares the mailbox command for registering a virtual N_Port. - **/ -void -lpfc_reg_vpi(struct lpfc_vport *vport, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_hba *phba = vport->phba; - - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - /* - * Set the re-reg VPI bit for f/w to update the MAC address. - */ - if ((phba->sli_rev == LPFC_SLI_REV4) && - !(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) - mb->un.varRegVpi.upd = 1; - - mb->un.varRegVpi.vpi = phba->vpi_ids[vport->vpi]; - mb->un.varRegVpi.sid = vport->fc_myDID; - if (phba->sli_rev == LPFC_SLI_REV4) - mb->un.varRegVpi.vfi = phba->sli4_hba.vfi_ids[vport->vfi]; - else - mb->un.varRegVpi.vfi = vport->vfi + vport->phba->vfi_base; - memcpy(mb->un.varRegVpi.wwn, &vport->fc_portname, - sizeof(struct lpfc_name)); - mb->un.varRegVpi.wwn[0] = cpu_to_le32(mb->un.varRegVpi.wwn[0]); - mb->un.varRegVpi.wwn[1] = cpu_to_le32(mb->un.varRegVpi.wwn[1]); - - mb->mbxCommand = MBX_REG_VPI; - mb->mbxOwner = OWN_HOST; - return; - -} - -/** - * lpfc_unreg_vpi - Prepare a mailbox command for unregistering vport id - * @phba: pointer to lpfc hba data structure. - * @vpi: virtual N_Port identifier. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The unregistration vport identifier mailbox command is used to inactivate - * a virtual N_Port. The driver must have logged out and unregistered all - * remote N_Ports to abort any activity on the virtual N_Port. The HBA will - * unregisters any default RPIs associated with the specified vpi, aborting - * any active exchanges. The HBA will post the mailbox response after making - * the virtual N_Port inactive. - * - * This routine prepares the mailbox command for unregistering a virtual - * N_Port. - **/ -void -lpfc_unreg_vpi(struct lpfc_hba *phba, uint16_t vpi, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - if (phba->sli_rev == LPFC_SLI_REV3) - mb->un.varUnregVpi.vpi = phba->vpi_ids[vpi]; - else if (phba->sli_rev >= LPFC_SLI_REV4) - mb->un.varUnregVpi.sli4_vpi = phba->vpi_ids[vpi]; - - mb->mbxCommand = MBX_UNREG_VPI; - mb->mbxOwner = OWN_HOST; - return; - -} - -/** - * lpfc_config_pcb_setup - Set up IOCB rings in the Port Control Block (PCB) - * @phba: pointer to lpfc hba data structure. - * - * This routine sets up and initializes the IOCB rings in the Port Control - * Block (PCB). - **/ -static void -lpfc_config_pcb_setup(struct lpfc_hba * phba) -{ - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - PCB_t *pcbp = phba->pcb; - dma_addr_t pdma_addr; - uint32_t offset; - uint32_t iocbCnt = 0; - int i; - - pcbp->maxRing = (psli->num_rings - 1); - - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - - pring->sizeCiocb = phba->sli_rev == 3 ? SLI3_IOCB_CMD_SIZE: - SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = phba->sli_rev == 3 ? SLI3_IOCB_RSP_SIZE: - SLI2_IOCB_RSP_SIZE; - /* A ring MUST have both cmd and rsp entries defined to be - valid */ - if ((pring->numCiocb == 0) || (pring->numRiocb == 0)) { - pcbp->rdsc[i].cmdEntries = 0; - pcbp->rdsc[i].rspEntries = 0; - pcbp->rdsc[i].cmdAddrHigh = 0; - pcbp->rdsc[i].rspAddrHigh = 0; - pcbp->rdsc[i].cmdAddrLow = 0; - pcbp->rdsc[i].rspAddrLow = 0; - pring->cmdringaddr = NULL; - pring->rspringaddr = NULL; - continue; - } - /* Command ring setup for ring */ - pring->cmdringaddr = (void *)&phba->IOCBs[iocbCnt]; - pcbp->rdsc[i].cmdEntries = pring->numCiocb; - - offset = (uint8_t *) &phba->IOCBs[iocbCnt] - - (uint8_t *) phba->slim2p.virt; - pdma_addr = phba->slim2p.phys + offset; - pcbp->rdsc[i].cmdAddrHigh = putPaddrHigh(pdma_addr); - pcbp->rdsc[i].cmdAddrLow = putPaddrLow(pdma_addr); - iocbCnt += pring->numCiocb; - - /* Response ring setup for ring */ - pring->rspringaddr = (void *) &phba->IOCBs[iocbCnt]; - - pcbp->rdsc[i].rspEntries = pring->numRiocb; - offset = (uint8_t *)&phba->IOCBs[iocbCnt] - - (uint8_t *)phba->slim2p.virt; - pdma_addr = phba->slim2p.phys + offset; - pcbp->rdsc[i].rspAddrHigh = putPaddrHigh(pdma_addr); - pcbp->rdsc[i].rspAddrLow = putPaddrLow(pdma_addr); - iocbCnt += pring->numRiocb; - } -} - -/** - * lpfc_read_rev - Prepare a mailbox command for reading HBA revision - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The read revision mailbox command is used to read the revision levels of - * the HBA components. These components include hardware units, resident - * firmware, and available firmware. HBAs that supports SLI-3 mode of - * operation provide different response information depending on the version - * requested by the driver. - * - * This routine prepares the mailbox command for reading HBA revision - * information. - **/ -void -lpfc_read_rev(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - mb->un.varRdRev.cv = 1; - mb->un.varRdRev.v3req = 1; /* Request SLI3 info */ - mb->mbxCommand = MBX_READ_REV; - mb->mbxOwner = OWN_HOST; - return; -} - -void -lpfc_sli4_swap_str(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_mqe *mqe; - - switch (mb->mbxCommand) { - case MBX_READ_REV: - mqe = &pmb->u.mqe; - lpfc_sli_pcimem_bcopy(mqe->un.read_rev.fw_name, - mqe->un.read_rev.fw_name, 16); - lpfc_sli_pcimem_bcopy(mqe->un.read_rev.ulp_fw_name, - mqe->un.read_rev.ulp_fw_name, 16); - break; - default: - break; - } - return; -} - -/** - * lpfc_build_hbq_profile2 - Set up the HBQ Selection Profile 2 - * @hbqmb: pointer to the HBQ configuration data structure in mailbox command. - * @hbq_desc: pointer to the HBQ selection profile descriptor. - * - * The Host Buffer Queue (HBQ) Selection Profile 2 specifies that the HBA - * tests the incoming frames' R_CTL/TYPE fields with works 10:15 and performs - * the Sequence Length Test using the fields in the Selection Profile 2 - * extension in words 20:31. - **/ -static void -lpfc_build_hbq_profile2(struct config_hbq_var *hbqmb, - struct lpfc_hbq_init *hbq_desc) -{ - hbqmb->profiles.profile2.seqlenbcnt = hbq_desc->seqlenbcnt; - hbqmb->profiles.profile2.maxlen = hbq_desc->maxlen; - hbqmb->profiles.profile2.seqlenoff = hbq_desc->seqlenoff; -} - -/** - * lpfc_build_hbq_profile3 - Set up the HBQ Selection Profile 3 - * @hbqmb: pointer to the HBQ configuration data structure in mailbox command. - * @hbq_desc: pointer to the HBQ selection profile descriptor. - * - * The Host Buffer Queue (HBQ) Selection Profile 3 specifies that the HBA - * tests the incoming frame's R_CTL/TYPE fields with words 10:15 and performs - * the Sequence Length Test and Byte Field Test using the fields in the - * Selection Profile 3 extension in words 20:31. - **/ -static void -lpfc_build_hbq_profile3(struct config_hbq_var *hbqmb, - struct lpfc_hbq_init *hbq_desc) -{ - hbqmb->profiles.profile3.seqlenbcnt = hbq_desc->seqlenbcnt; - hbqmb->profiles.profile3.maxlen = hbq_desc->maxlen; - hbqmb->profiles.profile3.cmdcodeoff = hbq_desc->cmdcodeoff; - hbqmb->profiles.profile3.seqlenoff = hbq_desc->seqlenoff; - memcpy(&hbqmb->profiles.profile3.cmdmatch, hbq_desc->cmdmatch, - sizeof(hbqmb->profiles.profile3.cmdmatch)); -} - -/** - * lpfc_build_hbq_profile5 - Set up the HBQ Selection Profile 5 - * @hbqmb: pointer to the HBQ configuration data structure in mailbox command. - * @hbq_desc: pointer to the HBQ selection profile descriptor. - * - * The Host Buffer Queue (HBQ) Selection Profile 5 specifies a header HBQ. The - * HBA tests the initial frame of an incoming sequence using the frame's - * R_CTL/TYPE fields with words 10:15 and performs the Sequence Length Test - * and Byte Field Test using the fields in the Selection Profile 5 extension - * words 20:31. - **/ -static void -lpfc_build_hbq_profile5(struct config_hbq_var *hbqmb, - struct lpfc_hbq_init *hbq_desc) -{ - hbqmb->profiles.profile5.seqlenbcnt = hbq_desc->seqlenbcnt; - hbqmb->profiles.profile5.maxlen = hbq_desc->maxlen; - hbqmb->profiles.profile5.cmdcodeoff = hbq_desc->cmdcodeoff; - hbqmb->profiles.profile5.seqlenoff = hbq_desc->seqlenoff; - memcpy(&hbqmb->profiles.profile5.cmdmatch, hbq_desc->cmdmatch, - sizeof(hbqmb->profiles.profile5.cmdmatch)); -} - -/** - * lpfc_config_hbq - Prepare a mailbox command for configuring an HBQ - * @phba: pointer to lpfc hba data structure. - * @id: HBQ identifier. - * @hbq_desc: pointer to the HBA descriptor data structure. - * @hbq_entry_index: index of the HBQ entry data structures. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The configure HBQ (Host Buffer Queue) mailbox command is used to configure - * an HBQ. The configuration binds events that require buffers to a particular - * ring and HBQ based on a selection profile. - * - * This routine prepares the mailbox command for configuring an HBQ. - **/ -void -lpfc_config_hbq(struct lpfc_hba *phba, uint32_t id, - struct lpfc_hbq_init *hbq_desc, - uint32_t hbq_entry_index, LPFC_MBOXQ_t *pmb) -{ - int i; - MAILBOX_t *mb = &pmb->u.mb; - struct config_hbq_var *hbqmb = &mb->un.varCfgHbq; - - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - hbqmb->hbqId = id; - hbqmb->entry_count = hbq_desc->entry_count; /* # entries in HBQ */ - hbqmb->recvNotify = hbq_desc->rn; /* Receive - * Notification */ - hbqmb->numMask = hbq_desc->mask_count; /* # R_CTL/TYPE masks - * # in words 0-19 */ - hbqmb->profile = hbq_desc->profile; /* Selection profile: - * 0 = all, - * 7 = logentry */ - hbqmb->ringMask = hbq_desc->ring_mask; /* Binds HBQ to a ring - * e.g. Ring0=b0001, - * ring2=b0100 */ - hbqmb->headerLen = hbq_desc->headerLen; /* 0 if not profile 4 - * or 5 */ - hbqmb->logEntry = hbq_desc->logEntry; /* Set to 1 if this - * HBQ will be used - * for LogEntry - * buffers */ - hbqmb->hbqaddrLow = putPaddrLow(phba->hbqslimp.phys) + - hbq_entry_index * sizeof(struct lpfc_hbq_entry); - hbqmb->hbqaddrHigh = putPaddrHigh(phba->hbqslimp.phys); - - mb->mbxCommand = MBX_CONFIG_HBQ; - mb->mbxOwner = OWN_HOST; - - /* Copy info for profiles 2,3,5. Other - * profiles this area is reserved - */ - if (hbq_desc->profile == 2) - lpfc_build_hbq_profile2(hbqmb, hbq_desc); - else if (hbq_desc->profile == 3) - lpfc_build_hbq_profile3(hbqmb, hbq_desc); - else if (hbq_desc->profile == 5) - lpfc_build_hbq_profile5(hbqmb, hbq_desc); - - /* Return if no rctl / type masks for this HBQ */ - if (!hbq_desc->mask_count) - return; - - /* Otherwise we setup specific rctl / type masks for this HBQ */ - for (i = 0; i < hbq_desc->mask_count; i++) { - hbqmb->hbqMasks[i].tmatch = hbq_desc->hbqMasks[i].tmatch; - hbqmb->hbqMasks[i].tmask = hbq_desc->hbqMasks[i].tmask; - hbqmb->hbqMasks[i].rctlmatch = hbq_desc->hbqMasks[i].rctlmatch; - hbqmb->hbqMasks[i].rctlmask = hbq_desc->hbqMasks[i].rctlmask; - } - - return; -} - -/** - * lpfc_config_ring - Prepare a mailbox command for configuring an IOCB ring - * @phba: pointer to lpfc hba data structure. - * @ring: - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The configure ring mailbox command is used to configure an IOCB ring. This - * configuration binds from one to six of HBA RC_CTL/TYPE mask entries to the - * ring. This is used to map incoming sequences to a particular ring whose - * RC_CTL/TYPE mask entry matches that of the sequence. The driver should not - * attempt to configure a ring whose number is greater than the number - * specified in the Port Control Block (PCB). It is an error to issue the - * configure ring command more than once with the same ring number. The HBA - * returns an error if the driver attempts this. - * - * This routine prepares the mailbox command for configuring IOCB ring. - **/ -void -lpfc_config_ring(struct lpfc_hba * phba, int ring, LPFC_MBOXQ_t * pmb) -{ - int i; - MAILBOX_t *mb = &pmb->u.mb; - struct lpfc_sli *psli; - struct lpfc_sli_ring *pring; - - memset(pmb, 0, sizeof (LPFC_MBOXQ_t)); - - mb->un.varCfgRing.ring = ring; - mb->un.varCfgRing.maxOrigXchg = 0; - mb->un.varCfgRing.maxRespXchg = 0; - mb->un.varCfgRing.recvNotify = 1; - - psli = &phba->sli; - pring = &psli->ring[ring]; - mb->un.varCfgRing.numMask = pring->num_mask; - mb->mbxCommand = MBX_CONFIG_RING; - mb->mbxOwner = OWN_HOST; - - /* Is this ring configured for a specific profile */ - if (pring->prt[0].profile) { - mb->un.varCfgRing.profile = pring->prt[0].profile; - return; - } - - /* Otherwise we setup specific rctl / type masks for this ring */ - for (i = 0; i < pring->num_mask; i++) { - mb->un.varCfgRing.rrRegs[i].rval = pring->prt[i].rctl; - if (mb->un.varCfgRing.rrRegs[i].rval != FC_RCTL_ELS_REQ) - mb->un.varCfgRing.rrRegs[i].rmask = 0xff; - else - mb->un.varCfgRing.rrRegs[i].rmask = 0xfe; - mb->un.varCfgRing.rrRegs[i].tval = pring->prt[i].type; - mb->un.varCfgRing.rrRegs[i].tmask = 0xff; - } - - return; -} - -/** - * lpfc_config_port - Prepare a mailbox command for configuring port - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The configure port mailbox command is used to identify the Port Control - * Block (PCB) in the driver memory. After this command is issued, the - * driver must not access the mailbox in the HBA without first resetting - * the HBA. The HBA may copy the PCB information to internal storage for - * subsequent use; the driver can not change the PCB information unless it - * resets the HBA. - * - * This routine prepares the mailbox command for configuring port. - **/ -void -lpfc_config_port(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - MAILBOX_t __iomem *mb_slim = (MAILBOX_t __iomem *) phba->MBslimaddr; - MAILBOX_t *mb = &pmb->u.mb; - dma_addr_t pdma_addr; - uint32_t bar_low, bar_high; - size_t offset; - struct lpfc_hgp hgp; - int i; - uint32_t pgp_offset; - - memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_CONFIG_PORT; - mb->mbxOwner = OWN_HOST; - - mb->un.varCfgPort.pcbLen = sizeof(PCB_t); - - offset = (uint8_t *)phba->pcb - (uint8_t *)phba->slim2p.virt; - pdma_addr = phba->slim2p.phys + offset; - mb->un.varCfgPort.pcbLow = putPaddrLow(pdma_addr); - mb->un.varCfgPort.pcbHigh = putPaddrHigh(pdma_addr); - - /* Always Host Group Pointer is in SLIM */ - mb->un.varCfgPort.hps = 1; - - /* If HBA supports SLI=3 ask for it */ - - if (phba->sli_rev == LPFC_SLI_REV3 && phba->vpd.sli3Feat.cerbm) { - if (phba->cfg_enable_bg) - mb->un.varCfgPort.cbg = 1; /* configure BlockGuard */ - if (phba->cfg_enable_dss) - mb->un.varCfgPort.cdss = 1; /* Configure Security */ - mb->un.varCfgPort.cerbm = 1; /* Request HBQs */ - mb->un.varCfgPort.ccrp = 1; /* Command Ring Polling */ - mb->un.varCfgPort.max_hbq = lpfc_sli_hbq_count(); - if (phba->max_vpi && phba->cfg_enable_npiv && - phba->vpd.sli3Feat.cmv) { - mb->un.varCfgPort.max_vpi = LPFC_MAX_VPI; - mb->un.varCfgPort.cmv = 1; - } else - mb->un.varCfgPort.max_vpi = phba->max_vpi = 0; - } else - phba->sli_rev = LPFC_SLI_REV2; - mb->un.varCfgPort.sli_mode = phba->sli_rev; - - /* If this is an SLI3 port, configure async status notification. */ - if (phba->sli_rev == LPFC_SLI_REV3) - mb->un.varCfgPort.casabt = 1; - - /* Now setup pcb */ - phba->pcb->type = TYPE_NATIVE_SLI2; - phba->pcb->feature = FEATURE_INITIAL_SLI2; - - /* Setup Mailbox pointers */ - phba->pcb->mailBoxSize = sizeof(MAILBOX_t) + MAILBOX_EXT_SIZE; - offset = (uint8_t *)phba->mbox - (uint8_t *)phba->slim2p.virt; - pdma_addr = phba->slim2p.phys + offset; - phba->pcb->mbAddrHigh = putPaddrHigh(pdma_addr); - phba->pcb->mbAddrLow = putPaddrLow(pdma_addr); - - /* - * Setup Host Group ring pointer. - * - * For efficiency reasons, the ring get/put pointers can be - * placed in adapter memory (SLIM) rather than in host memory. - * This allows firmware to avoid PCI reads/writes when updating - * and checking pointers. - * - * The firmware recognizes the use of SLIM memory by comparing - * the address of the get/put pointers structure with that of - * the SLIM BAR (BAR0). - * - * Caution: be sure to use the PCI config space value of BAR0/BAR1 - * (the hardware's view of the base address), not the OS's - * value of pci_resource_start() as the OS value may be a cookie - * for ioremap/iomap. - */ - - - pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_0, &bar_low); - pci_read_config_dword(phba->pcidev, PCI_BASE_ADDRESS_1, &bar_high); - - /* - * Set up HGP - Port Memory - * - * The port expects the host get/put pointers to reside in memory - * following the "non-diagnostic" mode mailbox (32 words, 0x80 bytes) - * area of SLIM. In SLI-2 mode, there's an additional 16 reserved - * words (0x40 bytes). This area is not reserved if HBQs are - * configured in SLI-3. - * - * CR0Put - SLI2(no HBQs) = 0xc0, With HBQs = 0x80 - * RR0Get 0xc4 0x84 - * CR1Put 0xc8 0x88 - * RR1Get 0xcc 0x8c - * CR2Put 0xd0 0x90 - * RR2Get 0xd4 0x94 - * CR3Put 0xd8 0x98 - * RR3Get 0xdc 0x9c - * - * Reserved 0xa0-0xbf - * If HBQs configured: - * HBQ 0 Put ptr 0xc0 - * HBQ 1 Put ptr 0xc4 - * HBQ 2 Put ptr 0xc8 - * ...... - * HBQ(M-1)Put Pointer 0xc0+(M-1)*4 - * - */ - - if (phba->cfg_hostmem_hgp && phba->sli_rev != 3) { - phba->host_gp = &phba->mbox->us.s2.host[0]; - phba->hbq_put = NULL; - offset = (uint8_t *)&phba->mbox->us.s2.host - - (uint8_t *)phba->slim2p.virt; - pdma_addr = phba->slim2p.phys + offset; - phba->pcb->hgpAddrHigh = putPaddrHigh(pdma_addr); - phba->pcb->hgpAddrLow = putPaddrLow(pdma_addr); - } else { - /* Always Host Group Pointer is in SLIM */ - mb->un.varCfgPort.hps = 1; - - if (phba->sli_rev == 3) { - phba->host_gp = &mb_slim->us.s3.host[0]; - phba->hbq_put = &mb_slim->us.s3.hbq_put[0]; - } else { - phba->host_gp = &mb_slim->us.s2.host[0]; - phba->hbq_put = NULL; - } - - /* mask off BAR0's flag bits 0 - 3 */ - phba->pcb->hgpAddrLow = (bar_low & PCI_BASE_ADDRESS_MEM_MASK) + - (void __iomem *)phba->host_gp - - (void __iomem *)phba->MBslimaddr; - if (bar_low & PCI_BASE_ADDRESS_MEM_TYPE_64) - phba->pcb->hgpAddrHigh = bar_high; - else - phba->pcb->hgpAddrHigh = 0; - /* write HGP data to SLIM at the required longword offset */ - memset(&hgp, 0, sizeof(struct lpfc_hgp)); - - for (i = 0; i < phba->sli.num_rings; i++) { - lpfc_memcpy_to_slim(phba->host_gp + i, &hgp, - sizeof(*phba->host_gp)); - } - } - - /* Setup Port Group offset */ - if (phba->sli_rev == 3) - pgp_offset = offsetof(struct lpfc_sli2_slim, - mbx.us.s3_pgp.port); - else - pgp_offset = offsetof(struct lpfc_sli2_slim, mbx.us.s2.port); - pdma_addr = phba->slim2p.phys + pgp_offset; - phba->pcb->pgpAddrHigh = putPaddrHigh(pdma_addr); - phba->pcb->pgpAddrLow = putPaddrLow(pdma_addr); - - /* Use callback routine to setp rings in the pcb */ - lpfc_config_pcb_setup(phba); - - /* special handling for LC HBAs */ - if (lpfc_is_LC_HBA(phba->pcidev->device)) { - uint32_t hbainit[5]; - - lpfc_hba_init(phba, hbainit); - - memcpy(&mb->un.varCfgPort.hbainit, hbainit, 20); - } - - /* Swap PCB if needed */ - lpfc_sli_pcimem_bcopy(phba->pcb, phba->pcb, sizeof(PCB_t)); -} - -/** - * lpfc_kill_board - Prepare a mailbox command for killing board - * @phba: pointer to lpfc hba data structure. - * @pmb: pointer to the driver internal queue element for mailbox command. - * - * The kill board mailbox command is used to tell firmware to perform a - * graceful shutdown of a channel on a specified board to prepare for reset. - * When the kill board mailbox command is received, the ER3 bit is set to 1 - * in the Host Status register and the ER Attention bit is set to 1 in the - * Host Attention register of the HBA function that received the kill board - * command. - * - * This routine prepares the mailbox command for killing the board in - * preparation for a graceful shutdown. - **/ -void -lpfc_kill_board(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) -{ - MAILBOX_t *mb = &pmb->u.mb; - - memset(pmb, 0, sizeof(LPFC_MBOXQ_t)); - mb->mbxCommand = MBX_KILL_BOARD; - mb->mbxOwner = OWN_HOST; - return; -} - -/** - * lpfc_mbox_put - Put a mailbox cmd into the tail of driver's mailbox queue - * @phba: pointer to lpfc hba data structure. - * @mbq: pointer to the driver internal queue element for mailbox command. - * - * Driver maintains a internal mailbox command queue implemented as a linked - * list. When a mailbox command is issued, it shall be put into the mailbox - * command queue such that they shall be processed orderly as HBA can process - * one mailbox command at a time. - **/ -void -lpfc_mbox_put(struct lpfc_hba * phba, LPFC_MBOXQ_t * mbq) -{ - struct lpfc_sli *psli; - - psli = &phba->sli; - - list_add_tail(&mbq->list, &psli->mboxq); - - psli->mboxq_cnt++; - - return; -} - -/** - * lpfc_mbox_get - Remove a mailbox cmd from the head of driver's mailbox queue - * @phba: pointer to lpfc hba data structure. - * - * Driver maintains a internal mailbox command queue implemented as a linked - * list. When a mailbox command is issued, it shall be put into the mailbox - * command queue such that they shall be processed orderly as HBA can process - * one mailbox command at a time. After HBA finished processing a mailbox - * command, the driver will remove a pending mailbox command from the head of - * the mailbox command queue and send to the HBA for processing. - * - * Return codes - * pointer to the driver internal queue element for mailbox command. - **/ -LPFC_MBOXQ_t * -lpfc_mbox_get(struct lpfc_hba * phba) -{ - LPFC_MBOXQ_t *mbq = NULL; - struct lpfc_sli *psli = &phba->sli; - - list_remove_head((&psli->mboxq), mbq, LPFC_MBOXQ_t, list); - if (mbq) - psli->mboxq_cnt--; - - return mbq; -} - -/** - * __lpfc_mbox_cmpl_put - Put mailbox cmd into mailbox cmd complete list - * @phba: pointer to lpfc hba data structure. - * @mbq: pointer to the driver internal queue element for mailbox command. - * - * This routine put the completed mailbox command into the mailbox command - * complete list. This is the unlocked version of the routine. The mailbox - * complete list is used by the driver worker thread to process mailbox - * complete callback functions outside the driver interrupt handler. - **/ -void -__lpfc_mbox_cmpl_put(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbq) -{ - list_add_tail(&mbq->list, &phba->sli.mboxq_cmpl); -} - -/** - * lpfc_mbox_cmpl_put - Put mailbox command into mailbox command complete list - * @phba: pointer to lpfc hba data structure. - * @mbq: pointer to the driver internal queue element for mailbox command. - * - * This routine put the completed mailbox command into the mailbox command - * complete list. This is the locked version of the routine. The mailbox - * complete list is used by the driver worker thread to process mailbox - * complete callback functions outside the driver interrupt handler. - **/ -void -lpfc_mbox_cmpl_put(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbq) -{ - unsigned long iflag; - - /* This function expects to be called from interrupt context */ - spin_lock_irqsave(&phba->hbalock, iflag); - __lpfc_mbox_cmpl_put(phba, mbq); - spin_unlock_irqrestore(&phba->hbalock, iflag); - return; -} - -/** - * lpfc_mbox_cmd_check - Check the validality of a mailbox command - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to the driver internal queue element for mailbox command. - * - * This routine is to check whether a mailbox command is valid to be issued. - * This check will be performed by both the mailbox issue API when a client - * is to issue a mailbox command to the mailbox transport. - * - * Return 0 - pass the check, -ENODEV - fail the check - **/ -int -lpfc_mbox_cmd_check(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - /* Mailbox command that have a completion handler must also have a - * vport specified. - */ - if (mboxq->mbox_cmpl && mboxq->mbox_cmpl != lpfc_sli_def_mbox_cmpl && - mboxq->mbox_cmpl != lpfc_sli_wake_mbox_wait) { - if (!mboxq->vport) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT, - "1814 Mbox x%x failed, no vport\n", - mboxq->u.mb.mbxCommand); - dump_stack(); - return -ENODEV; - } - } - return 0; -} - -/** - * lpfc_mbox_dev_check - Check the device state for issuing a mailbox command - * @phba: pointer to lpfc hba data structure. - * - * This routine is to check whether the HBA device is ready for posting a - * mailbox command. It is used by the mailbox transport API at the time the - * to post a mailbox command to the device. - * - * Return 0 - pass the check, -ENODEV - fail the check - **/ -int -lpfc_mbox_dev_check(struct lpfc_hba *phba) -{ - /* If the PCI channel is in offline state, do not issue mbox */ - if (unlikely(pci_channel_offline(phba->pcidev))) - return -ENODEV; - - /* If the HBA is in error state, do not issue mbox */ - if (phba->link_state == LPFC_HBA_ERROR) - return -ENODEV; - - return 0; -} - -/** - * lpfc_mbox_tmo_val - Retrieve mailbox command timeout value - * @phba: pointer to lpfc hba data structure. - * @cmd: mailbox command code. - * - * This routine retrieves the proper timeout value according to the mailbox - * command code. - * - * Return codes - * Timeout value to be used for the given mailbox command - **/ -int -lpfc_mbox_tmo_val(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - MAILBOX_t *mbox = &mboxq->u.mb; - uint8_t subsys, opcode; - - switch (mbox->mbxCommand) { - case MBX_WRITE_NV: /* 0x03 */ - case MBX_UPDATE_CFG: /* 0x1B */ - case MBX_DOWN_LOAD: /* 0x1C */ - case MBX_DEL_LD_ENTRY: /* 0x1D */ - case MBX_LOAD_AREA: /* 0x81 */ - case MBX_WRITE_WWN: /* 0x98 */ - case MBX_LOAD_EXP_ROM: /* 0x9C */ - return LPFC_MBOX_TMO_FLASH_CMD; - case MBX_SLI4_CONFIG: /* 0x9b */ - subsys = lpfc_sli_config_mbox_subsys_get(phba, mboxq); - opcode = lpfc_sli_config_mbox_opcode_get(phba, mboxq); - if (subsys == LPFC_MBOX_SUBSYSTEM_COMMON) { - switch (opcode) { - case LPFC_MBOX_OPCODE_READ_OBJECT: - case LPFC_MBOX_OPCODE_WRITE_OBJECT: - case LPFC_MBOX_OPCODE_READ_OBJECT_LIST: - case LPFC_MBOX_OPCODE_DELETE_OBJECT: - case LPFC_MBOX_OPCODE_GET_FUNCTION_CONFIG: - case LPFC_MBOX_OPCODE_GET_PROFILE_LIST: - case LPFC_MBOX_OPCODE_SET_ACT_PROFILE: - case LPFC_MBOX_OPCODE_SET_PROFILE_CONFIG: - case LPFC_MBOX_OPCODE_GET_FACTORY_PROFILE_CONFIG: - return LPFC_MBOX_SLI4_CONFIG_EXTENDED_TMO; - } - } - if (subsys == LPFC_MBOX_SUBSYSTEM_FCOE) { - switch (opcode) { - case LPFC_MBOX_OPCODE_FCOE_SET_FCLINK_SETTINGS: - return LPFC_MBOX_SLI4_CONFIG_EXTENDED_TMO; - } - } - return LPFC_MBOX_SLI4_CONFIG_TMO; - } - return LPFC_MBOX_TMO; -} - -/** - * lpfc_sli4_mbx_sge_set - Set a sge entry in non-embedded mailbox command - * @mbox: pointer to lpfc mbox command. - * @sgentry: sge entry index. - * @phyaddr: physical address for the sge - * @length: Length of the sge. - * - * This routine sets up an entry in the non-embedded mailbox command at the sge - * index location. - **/ -void -lpfc_sli4_mbx_sge_set(struct lpfcMboxq *mbox, uint32_t sgentry, - dma_addr_t phyaddr, uint32_t length) -{ - struct lpfc_mbx_nembed_cmd *nembed_sge; - - nembed_sge = (struct lpfc_mbx_nembed_cmd *) - &mbox->u.mqe.un.nembed_cmd; - nembed_sge->sge[sgentry].pa_lo = putPaddrLow(phyaddr); - nembed_sge->sge[sgentry].pa_hi = putPaddrHigh(phyaddr); - nembed_sge->sge[sgentry].length = length; -} - -/** - * lpfc_sli4_mbx_sge_get - Get a sge entry from non-embedded mailbox command - * @mbox: pointer to lpfc mbox command. - * @sgentry: sge entry index. - * - * This routine gets an entry from the non-embedded mailbox command at the sge - * index location. - **/ -void -lpfc_sli4_mbx_sge_get(struct lpfcMboxq *mbox, uint32_t sgentry, - struct lpfc_mbx_sge *sge) -{ - struct lpfc_mbx_nembed_cmd *nembed_sge; - - nembed_sge = (struct lpfc_mbx_nembed_cmd *) - &mbox->u.mqe.un.nembed_cmd; - sge->pa_lo = nembed_sge->sge[sgentry].pa_lo; - sge->pa_hi = nembed_sge->sge[sgentry].pa_hi; - sge->length = nembed_sge->sge[sgentry].length; -} - -/** - * lpfc_sli4_mbox_cmd_free - Free a sli4 mailbox command - * @phba: pointer to lpfc hba data structure. - * @mbox: pointer to lpfc mbox command. - * - * This routine frees SLI4 specific mailbox command for sending IOCTL command. - **/ -void -lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox) -{ - struct lpfc_mbx_sli4_config *sli4_cfg; - struct lpfc_mbx_sge sge; - dma_addr_t phyaddr; - uint32_t sgecount, sgentry; - - sli4_cfg = &mbox->u.mqe.un.sli4_config; - - /* For embedded mbox command, just free the mbox command */ - if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) { - mempool_free(mbox, phba->mbox_mem_pool); - return; - } - - /* For non-embedded mbox command, we need to free the pages first */ - sgecount = bf_get(lpfc_mbox_hdr_sge_cnt, &sli4_cfg->header.cfg_mhdr); - /* There is nothing we can do if there is no sge address array */ - if (unlikely(!mbox->sge_array)) { - mempool_free(mbox, phba->mbox_mem_pool); - return; - } - /* Each non-embedded DMA memory was allocated in the length of a page */ - for (sgentry = 0; sgentry < sgecount; sgentry++) { - lpfc_sli4_mbx_sge_get(mbox, sgentry, &sge); - phyaddr = getPaddr(sge.pa_hi, sge.pa_lo); - dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, - mbox->sge_array->addr[sgentry], phyaddr); - } - /* Free the sge address array memory */ - kfree(mbox->sge_array); - /* Finally, free the mailbox command itself */ - mempool_free(mbox, phba->mbox_mem_pool); -} - -/** - * lpfc_sli4_config - Initialize the SLI4 Config Mailbox command - * @phba: pointer to lpfc hba data structure. - * @mbox: pointer to lpfc mbox command. - * @subsystem: The sli4 config sub mailbox subsystem. - * @opcode: The sli4 config sub mailbox command opcode. - * @length: Length of the sli4 config mailbox command (including sub-header). - * - * This routine sets up the header fields of SLI4 specific mailbox command - * for sending IOCTL command. - * - * Return: the actual length of the mbox command allocated (mostly useful - * for none embedded mailbox command). - **/ -int -lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox, - uint8_t subsystem, uint8_t opcode, uint32_t length, bool emb) -{ - struct lpfc_mbx_sli4_config *sli4_config; - union lpfc_sli4_cfg_shdr *cfg_shdr = NULL; - uint32_t alloc_len; - uint32_t resid_len; - uint32_t pagen, pcount; - void *viraddr; - dma_addr_t phyaddr; - - /* Set up SLI4 mailbox command header fields */ - memset(mbox, 0, sizeof(*mbox)); - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_SLI4_CONFIG); - - /* Set up SLI4 ioctl command header fields */ - sli4_config = &mbox->u.mqe.un.sli4_config; - - /* Setup for the embedded mbox command */ - if (emb) { - /* Set up main header fields */ - bf_set(lpfc_mbox_hdr_emb, &sli4_config->header.cfg_mhdr, 1); - sli4_config->header.cfg_mhdr.payload_length = length; - /* Set up sub-header fields following main header */ - bf_set(lpfc_mbox_hdr_opcode, - &sli4_config->header.cfg_shdr.request, opcode); - bf_set(lpfc_mbox_hdr_subsystem, - &sli4_config->header.cfg_shdr.request, subsystem); - sli4_config->header.cfg_shdr.request.request_length = - length - LPFC_MBX_CMD_HDR_LENGTH; - return length; - } - - /* Setup for the non-embedded mbox command */ - pcount = (SLI4_PAGE_ALIGN(length))/SLI4_PAGE_SIZE; - pcount = (pcount > LPFC_SLI4_MBX_SGE_MAX_PAGES) ? - LPFC_SLI4_MBX_SGE_MAX_PAGES : pcount; - /* Allocate record for keeping SGE virtual addresses */ - mbox->sge_array = kzalloc(sizeof(struct lpfc_mbx_nembed_sge_virt), - GFP_KERNEL); - if (!mbox->sge_array) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2527 Failed to allocate non-embedded SGE " - "array.\n"); - return 0; - } - for (pagen = 0, alloc_len = 0; pagen < pcount; pagen++) { - /* The DMA memory is always allocated in the length of a - * page even though the last SGE might not fill up to a - * page, this is used as a priori size of SLI4_PAGE_SIZE for - * the later DMA memory free. - */ - viraddr = dma_alloc_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, - &phyaddr, GFP_KERNEL); - /* In case of malloc fails, proceed with whatever we have */ - if (!viraddr) - break; - memset(viraddr, 0, SLI4_PAGE_SIZE); - mbox->sge_array->addr[pagen] = viraddr; - /* Keep the first page for later sub-header construction */ - if (pagen == 0) - cfg_shdr = (union lpfc_sli4_cfg_shdr *)viraddr; - resid_len = length - alloc_len; - if (resid_len > SLI4_PAGE_SIZE) { - lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr, - SLI4_PAGE_SIZE); - alloc_len += SLI4_PAGE_SIZE; - } else { - lpfc_sli4_mbx_sge_set(mbox, pagen, phyaddr, - resid_len); - alloc_len = length; - } - } - - /* Set up main header fields in mailbox command */ - sli4_config->header.cfg_mhdr.payload_length = alloc_len; - bf_set(lpfc_mbox_hdr_sge_cnt, &sli4_config->header.cfg_mhdr, pagen); - - /* Set up sub-header fields into the first page */ - if (pagen > 0) { - bf_set(lpfc_mbox_hdr_opcode, &cfg_shdr->request, opcode); - bf_set(lpfc_mbox_hdr_subsystem, &cfg_shdr->request, subsystem); - cfg_shdr->request.request_length = - alloc_len - sizeof(union lpfc_sli4_cfg_shdr); - } - /* The sub-header is in DMA memory, which needs endian converstion */ - if (cfg_shdr) - lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr, - sizeof(union lpfc_sli4_cfg_shdr)); - return alloc_len; -} - -/** - * lpfc_sli4_mbox_rsrc_extent - Initialize the opcode resource extent. - * @phba: pointer to lpfc hba data structure. - * @mbox: pointer to an allocated lpfc mbox resource. - * @exts_count: the number of extents, if required, to allocate. - * @rsrc_type: the resource extent type. - * @emb: true if LPFC_SLI4_MBX_EMBED. false if LPFC_SLI4_MBX_NEMBED. - * - * This routine completes the subcommand header for SLI4 resource extent - * mailbox commands. It is called after lpfc_sli4_config. The caller must - * pass an allocated mailbox and the attributes required to initialize the - * mailbox correctly. - * - * Return: the actual length of the mbox command allocated. - **/ -int -lpfc_sli4_mbox_rsrc_extent(struct lpfc_hba *phba, struct lpfcMboxq *mbox, - uint16_t exts_count, uint16_t rsrc_type, bool emb) -{ - uint8_t opcode = 0; - struct lpfc_mbx_nembed_rsrc_extent *n_rsrc_extnt = NULL; - void *virtaddr = NULL; - - /* Set up SLI4 ioctl command header fields */ - if (emb == LPFC_SLI4_MBX_NEMBED) { - /* Get the first SGE entry from the non-embedded DMA memory */ - virtaddr = mbox->sge_array->addr[0]; - if (virtaddr == NULL) - return 1; - n_rsrc_extnt = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr; - } - - /* - * The resource type is common to all extent Opcodes and resides in the - * same position. - */ - if (emb == LPFC_SLI4_MBX_EMBED) - bf_set(lpfc_mbx_alloc_rsrc_extents_type, - &mbox->u.mqe.un.alloc_rsrc_extents.u.req, - rsrc_type); - else { - /* This is DMA data. Byteswap is required. */ - bf_set(lpfc_mbx_alloc_rsrc_extents_type, - n_rsrc_extnt, rsrc_type); - lpfc_sli_pcimem_bcopy(&n_rsrc_extnt->word4, - &n_rsrc_extnt->word4, - sizeof(uint32_t)); - } - - /* Complete the initialization for the particular Opcode. */ - opcode = lpfc_sli_config_mbox_opcode_get(phba, mbox); - switch (opcode) { - case LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT: - if (emb == LPFC_SLI4_MBX_EMBED) - bf_set(lpfc_mbx_alloc_rsrc_extents_cnt, - &mbox->u.mqe.un.alloc_rsrc_extents.u.req, - exts_count); - else - bf_set(lpfc_mbx_alloc_rsrc_extents_cnt, - n_rsrc_extnt, exts_count); - break; - case LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT: - case LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO: - case LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT: - /* Initialization is complete.*/ - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "2929 Resource Extent Opcode x%x is " - "unsupported\n", opcode); - return 1; - } - - return 0; -} - -/** - * lpfc_sli_config_mbox_subsys_get - Get subsystem from a sli_config mbox cmd - * @phba: pointer to lpfc hba data structure. - * @mbox: pointer to lpfc mbox command queue entry. - * - * This routine gets the subsystem from a SLI4 specific SLI_CONFIG mailbox - * command. If the mailbox command is not MBX_SLI4_CONFIG (0x9B) or if the - * sub-header is not present, subsystem LPFC_MBOX_SUBSYSTEM_NA (0x0) shall - * be returned. - **/ -uint8_t -lpfc_sli_config_mbox_subsys_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) -{ - struct lpfc_mbx_sli4_config *sli4_cfg; - union lpfc_sli4_cfg_shdr *cfg_shdr; - - if (mbox->u.mb.mbxCommand != MBX_SLI4_CONFIG) - return LPFC_MBOX_SUBSYSTEM_NA; - sli4_cfg = &mbox->u.mqe.un.sli4_config; - - /* For embedded mbox command, get opcode from embedded sub-header*/ - if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) { - cfg_shdr = &mbox->u.mqe.un.sli4_config.header.cfg_shdr; - return bf_get(lpfc_mbox_hdr_subsystem, &cfg_shdr->request); - } - - /* For non-embedded mbox command, get opcode from first dma page */ - if (unlikely(!mbox->sge_array)) - return LPFC_MBOX_SUBSYSTEM_NA; - cfg_shdr = (union lpfc_sli4_cfg_shdr *)mbox->sge_array->addr[0]; - return bf_get(lpfc_mbox_hdr_subsystem, &cfg_shdr->request); -} - -/** - * lpfc_sli_config_mbox_opcode_get - Get opcode from a sli_config mbox cmd - * @phba: pointer to lpfc hba data structure. - * @mbox: pointer to lpfc mbox command queue entry. - * - * This routine gets the opcode from a SLI4 specific SLI_CONFIG mailbox - * command. If the mailbox command is not MBX_SLI4_CONFIG (0x9B) or if - * the sub-header is not present, opcode LPFC_MBOX_OPCODE_NA (0x0) be - * returned. - **/ -uint8_t -lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) -{ - struct lpfc_mbx_sli4_config *sli4_cfg; - union lpfc_sli4_cfg_shdr *cfg_shdr; - - if (mbox->u.mb.mbxCommand != MBX_SLI4_CONFIG) - return LPFC_MBOX_OPCODE_NA; - sli4_cfg = &mbox->u.mqe.un.sli4_config; - - /* For embedded mbox command, get opcode from embedded sub-header*/ - if (bf_get(lpfc_mbox_hdr_emb, &sli4_cfg->header.cfg_mhdr)) { - cfg_shdr = &mbox->u.mqe.un.sli4_config.header.cfg_shdr; - return bf_get(lpfc_mbox_hdr_opcode, &cfg_shdr->request); - } - - /* For non-embedded mbox command, get opcode from first dma page */ - if (unlikely(!mbox->sge_array)) - return LPFC_MBOX_OPCODE_NA; - cfg_shdr = (union lpfc_sli4_cfg_shdr *)mbox->sge_array->addr[0]; - return bf_get(lpfc_mbox_hdr_opcode, &cfg_shdr->request); -} - -/** - * lpfc_sli4_mbx_read_fcf_rec - Allocate and construct read fcf mbox cmd - * @phba: pointer to lpfc hba data structure. - * @fcf_index: index to fcf table. - * - * This routine routine allocates and constructs non-embedded mailbox command - * for reading a FCF table entry referred by @fcf_index. - * - * Return: pointer to the mailbox command constructed if successful, otherwise - * NULL. - **/ -int -lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *phba, - struct lpfcMboxq *mboxq, - uint16_t fcf_index) -{ - void *virt_addr; - dma_addr_t phys_addr; - uint8_t *bytep; - struct lpfc_mbx_sge sge; - uint32_t alloc_len, req_len; - struct lpfc_mbx_read_fcf_tbl *read_fcf; - - if (!mboxq) - return -ENOMEM; - - req_len = sizeof(struct fcf_record) + - sizeof(union lpfc_sli4_cfg_shdr) + 2 * sizeof(uint32_t); - - /* Set up READ_FCF SLI4_CONFIG mailbox-ioctl command */ - alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_READ_FCF_TABLE, req_len, - LPFC_SLI4_MBX_NEMBED); - - if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "0291 Allocated DMA memory size (x%x) is " - "less than the requested DMA memory " - "size (x%x)\n", alloc_len, req_len); - return -ENOMEM; - } - - /* Get the first SGE entry from the non-embedded DMA memory. This - * routine only uses a single SGE. - */ - lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); - virt_addr = mboxq->sge_array->addr[0]; - read_fcf = (struct lpfc_mbx_read_fcf_tbl *)virt_addr; - - /* Set up command fields */ - bf_set(lpfc_mbx_read_fcf_tbl_indx, &read_fcf->u.request, fcf_index); - /* Perform necessary endian conversion */ - bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr); - lpfc_sli_pcimem_bcopy(bytep, bytep, sizeof(uint32_t)); - - return 0; -} - -/** - * lpfc_request_features: Configure SLI4 REQUEST_FEATURES mailbox - * @mboxq: pointer to lpfc mbox command. - * - * This routine sets up the mailbox for an SLI4 REQUEST_FEATURES - * mailbox command. - **/ -void -lpfc_request_features(struct lpfc_hba *phba, struct lpfcMboxq *mboxq) -{ - /* Set up SLI4 mailbox command header fields */ - memset(mboxq, 0, sizeof(LPFC_MBOXQ_t)); - bf_set(lpfc_mqe_command, &mboxq->u.mqe, MBX_SLI4_REQ_FTRS); - - /* Set up host requested features. */ - bf_set(lpfc_mbx_rq_ftr_rq_fcpi, &mboxq->u.mqe.un.req_ftrs, 1); - bf_set(lpfc_mbx_rq_ftr_rq_perfh, &mboxq->u.mqe.un.req_ftrs, 1); - - /* Enable DIF (block guard) only if configured to do so. */ - if (phba->cfg_enable_bg) - bf_set(lpfc_mbx_rq_ftr_rq_dif, &mboxq->u.mqe.un.req_ftrs, 1); - - /* Enable NPIV only if configured to do so. */ - if (phba->max_vpi && phba->cfg_enable_npiv) - bf_set(lpfc_mbx_rq_ftr_rq_npiv, &mboxq->u.mqe.un.req_ftrs, 1); - - return; -} - -/** - * lpfc_init_vfi - Initialize the INIT_VFI mailbox command - * @mbox: pointer to lpfc mbox command to initialize. - * @vport: Vport associated with the VF. - * - * This routine initializes @mbox to all zeros and then fills in the mailbox - * fields from @vport. INIT_VFI configures virtual fabrics identified by VFI - * in the context of an FCF. The driver issues this command to setup a VFI - * before issuing a FLOGI to login to the VSAN. The driver should also issue a - * REG_VFI after a successful VSAN login. - **/ -void -lpfc_init_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport) -{ - struct lpfc_mbx_init_vfi *init_vfi; - - memset(mbox, 0, sizeof(*mbox)); - mbox->vport = vport; - init_vfi = &mbox->u.mqe.un.init_vfi; - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VFI); - bf_set(lpfc_init_vfi_vr, init_vfi, 1); - bf_set(lpfc_init_vfi_vt, init_vfi, 1); - bf_set(lpfc_init_vfi_vp, init_vfi, 1); - bf_set(lpfc_init_vfi_vfi, init_vfi, - vport->phba->sli4_hba.vfi_ids[vport->vfi]); - bf_set(lpfc_init_vfi_vpi, init_vfi, - vport->phba->vpi_ids[vport->vpi]); - bf_set(lpfc_init_vfi_fcfi, init_vfi, - vport->phba->fcf.fcfi); -} - -/** - * lpfc_reg_vfi - Initialize the REG_VFI mailbox command - * @mbox: pointer to lpfc mbox command to initialize. - * @vport: vport associated with the VF. - * @phys: BDE DMA bus address used to send the service parameters to the HBA. - * - * This routine initializes @mbox to all zeros and then fills in the mailbox - * fields from @vport, and uses @buf as a DMAable buffer to send the vport's - * fc service parameters to the HBA for this VFI. REG_VFI configures virtual - * fabrics identified by VFI in the context of an FCF. - **/ -void -lpfc_reg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport, dma_addr_t phys) -{ - struct lpfc_mbx_reg_vfi *reg_vfi; - - memset(mbox, 0, sizeof(*mbox)); - reg_vfi = &mbox->u.mqe.un.reg_vfi; - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_VFI); - bf_set(lpfc_reg_vfi_vp, reg_vfi, 1); - bf_set(lpfc_reg_vfi_vfi, reg_vfi, - vport->phba->sli4_hba.vfi_ids[vport->vfi]); - bf_set(lpfc_reg_vfi_fcfi, reg_vfi, vport->phba->fcf.fcfi); - bf_set(lpfc_reg_vfi_vpi, reg_vfi, vport->phba->vpi_ids[vport->vpi]); - memcpy(reg_vfi->wwn, &vport->fc_portname, sizeof(struct lpfc_name)); - reg_vfi->wwn[0] = cpu_to_le32(reg_vfi->wwn[0]); - reg_vfi->wwn[1] = cpu_to_le32(reg_vfi->wwn[1]); - reg_vfi->e_d_tov = vport->phba->fc_edtov; - reg_vfi->r_a_tov = vport->phba->fc_ratov; - reg_vfi->bde.addrHigh = putPaddrHigh(phys); - reg_vfi->bde.addrLow = putPaddrLow(phys); - reg_vfi->bde.tus.f.bdeSize = sizeof(vport->fc_sparam); - reg_vfi->bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bf_set(lpfc_reg_vfi_nport_id, reg_vfi, vport->fc_myDID); - lpfc_printf_vlog(vport, KERN_INFO, LOG_MBOX, - "3134 Register VFI, mydid:x%x, fcfi:%d, " - " vfi:%d, vpi:%d, fc_pname:%x%x\n", - vport->fc_myDID, - vport->phba->fcf.fcfi, - vport->phba->sli4_hba.vfi_ids[vport->vfi], - vport->phba->vpi_ids[vport->vpi], - reg_vfi->wwn[0], reg_vfi->wwn[1]); -} - -/** - * lpfc_init_vpi - Initialize the INIT_VPI mailbox command - * @phba: pointer to the hba structure to init the VPI for. - * @mbox: pointer to lpfc mbox command to initialize. - * @vpi: VPI to be initialized. - * - * The INIT_VPI mailbox command supports virtual N_Ports. The driver uses the - * command to activate a virtual N_Port. The HBA assigns a MAC address to use - * with the virtual N Port. The SLI Host issues this command before issuing a - * FDISC to connect to the Fabric. The SLI Host should issue a REG_VPI after a - * successful virtual NPort login. - **/ -void -lpfc_init_vpi(struct lpfc_hba *phba, struct lpfcMboxq *mbox, uint16_t vpi) -{ - memset(mbox, 0, sizeof(*mbox)); - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_INIT_VPI); - bf_set(lpfc_init_vpi_vpi, &mbox->u.mqe.un.init_vpi, - phba->vpi_ids[vpi]); - bf_set(lpfc_init_vpi_vfi, &mbox->u.mqe.un.init_vpi, - phba->sli4_hba.vfi_ids[phba->pport->vfi]); -} - -/** - * lpfc_unreg_vfi - Initialize the UNREG_VFI mailbox command - * @mbox: pointer to lpfc mbox command to initialize. - * @vport: vport associated with the VF. - * - * The UNREG_VFI mailbox command causes the SLI Host to put a virtual fabric - * (logical NPort) into the inactive state. The SLI Host must have logged out - * and unregistered all remote N_Ports to abort any activity on the virtual - * fabric. The SLI Port posts the mailbox response after marking the virtual - * fabric inactive. - **/ -void -lpfc_unreg_vfi(struct lpfcMboxq *mbox, struct lpfc_vport *vport) -{ - memset(mbox, 0, sizeof(*mbox)); - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_VFI); - bf_set(lpfc_unreg_vfi_vfi, &mbox->u.mqe.un.unreg_vfi, - vport->phba->sli4_hba.vfi_ids[vport->vfi]); -} - -/** - * lpfc_sli4_dump_cfg_rg23 - Dump sli4 port config region 23 - * @phba: pointer to the hba structure containing. - * @mbox: pointer to lpfc mbox command to initialize. - * - * This function create a SLI4 dump mailbox command to dump configure - * region 23. - **/ -int -lpfc_sli4_dump_cfg_rg23(struct lpfc_hba *phba, struct lpfcMboxq *mbox) -{ - struct lpfc_dmabuf *mp = NULL; - MAILBOX_t *mb; - - memset(mbox, 0, sizeof(*mbox)); - mb = &mbox->u.mb; - - mp = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (mp) - mp->virt = lpfc_mbuf_alloc(phba, 0, &mp->phys); - - if (!mp || !mp->virt) { - kfree(mp); - /* dump config region 23 failed to allocate memory */ - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX, - "2569 lpfc dump config region 23: memory" - " allocation failed\n"); - return 1; - } - - memset(mp->virt, 0, LPFC_BPL_SIZE); - INIT_LIST_HEAD(&mp->list); - - /* save address for completion */ - mbox->context1 = (uint8_t *) mp; - - mb->mbxCommand = MBX_DUMP_MEMORY; - mb->un.varDmp.type = DMP_NV_PARAMS; - mb->un.varDmp.region_id = DMP_REGION_23; - mb->un.varDmp.sli4_length = DMP_RGN23_SIZE; - mb->un.varWords[3] = putPaddrLow(mp->phys); - mb->un.varWords[4] = putPaddrHigh(mp->phys); - return 0; -} - -/** - * lpfc_reg_fcfi - Initialize the REG_FCFI mailbox command - * @phba: pointer to the hba structure containing the FCF index and RQ ID. - * @mbox: pointer to lpfc mbox command to initialize. - * - * The REG_FCFI mailbox command supports Fibre Channel Forwarders (FCFs). The - * SLI Host uses the command to activate an FCF after it has acquired FCF - * information via a READ_FCF mailbox command. This mailbox command also is used - * to indicate where received unsolicited frames from this FCF will be sent. By - * default this routine will set up the FCF to forward all unsolicited frames - * the the RQ ID passed in the @phba. This can be overridden by the caller for - * more complicated setups. - **/ -void -lpfc_reg_fcfi(struct lpfc_hba *phba, struct lpfcMboxq *mbox) -{ - struct lpfc_mbx_reg_fcfi *reg_fcfi; - - memset(mbox, 0, sizeof(*mbox)); - reg_fcfi = &mbox->u.mqe.un.reg_fcfi; - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_REG_FCFI); - bf_set(lpfc_reg_fcfi_rq_id0, reg_fcfi, phba->sli4_hba.hdr_rq->queue_id); - bf_set(lpfc_reg_fcfi_rq_id1, reg_fcfi, REG_FCF_INVALID_QID); - bf_set(lpfc_reg_fcfi_rq_id2, reg_fcfi, REG_FCF_INVALID_QID); - bf_set(lpfc_reg_fcfi_rq_id3, reg_fcfi, REG_FCF_INVALID_QID); - bf_set(lpfc_reg_fcfi_info_index, reg_fcfi, - phba->fcf.current_rec.fcf_indx); - /* reg_fcf addr mode is bit wise inverted value of fcf addr_mode */ - bf_set(lpfc_reg_fcfi_mam, reg_fcfi, (~phba->fcf.addr_mode) & 0x3); - if (phba->fcf.current_rec.vlan_id != LPFC_FCOE_NULL_VID) { - bf_set(lpfc_reg_fcfi_vv, reg_fcfi, 1); - bf_set(lpfc_reg_fcfi_vlan_tag, reg_fcfi, - phba->fcf.current_rec.vlan_id); - } -} - -/** - * lpfc_unreg_fcfi - Initialize the UNREG_FCFI mailbox command - * @mbox: pointer to lpfc mbox command to initialize. - * @fcfi: FCFI to be unregistered. - * - * The UNREG_FCFI mailbox command supports Fibre Channel Forwarders (FCFs). - * The SLI Host uses the command to inactivate an FCFI. - **/ -void -lpfc_unreg_fcfi(struct lpfcMboxq *mbox, uint16_t fcfi) -{ - memset(mbox, 0, sizeof(*mbox)); - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_UNREG_FCFI); - bf_set(lpfc_unreg_fcfi, &mbox->u.mqe.un.unreg_fcfi, fcfi); -} - -/** - * lpfc_resume_rpi - Initialize the RESUME_RPI mailbox command - * @mbox: pointer to lpfc mbox command to initialize. - * @ndlp: The nodelist structure that describes the RPI to resume. - * - * The RESUME_RPI mailbox command is used to restart I/O to an RPI after a - * link event. - **/ -void -lpfc_resume_rpi(struct lpfcMboxq *mbox, struct lpfc_nodelist *ndlp) -{ - struct lpfc_hba *phba = ndlp->phba; - struct lpfc_mbx_resume_rpi *resume_rpi; - - memset(mbox, 0, sizeof(*mbox)); - resume_rpi = &mbox->u.mqe.un.resume_rpi; - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_RESUME_RPI); - bf_set(lpfc_resume_rpi_index, resume_rpi, - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); - bf_set(lpfc_resume_rpi_ii, resume_rpi, RESUME_INDEX_RPI); - resume_rpi->event_tag = ndlp->phba->fc_eventTag; -} - -/** - * lpfc_supported_pages - Initialize the PORT_CAPABILITIES supported pages - * mailbox command. - * @mbox: pointer to lpfc mbox command to initialize. - * - * The PORT_CAPABILITIES supported pages mailbox command is issued to - * retrieve the particular feature pages supported by the port. - **/ -void -lpfc_supported_pages(struct lpfcMboxq *mbox) -{ - struct lpfc_mbx_supp_pages *supp_pages; - - memset(mbox, 0, sizeof(*mbox)); - supp_pages = &mbox->u.mqe.un.supp_pages; - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_PORT_CAPABILITIES); - bf_set(cpn, supp_pages, LPFC_SUPP_PAGES); -} - -/** - * lpfc_pc_sli4_params - Initialize the PORT_CAPABILITIES SLI4 Params mbox cmd. - * @mbox: pointer to lpfc mbox command to initialize. - * - * The PORT_CAPABILITIES SLI4 parameters mailbox command is issued to - * retrieve the particular SLI4 features supported by the port. - **/ -void -lpfc_pc_sli4_params(struct lpfcMboxq *mbox) -{ - struct lpfc_mbx_pc_sli4_params *sli4_params; - - memset(mbox, 0, sizeof(*mbox)); - sli4_params = &mbox->u.mqe.un.sli4_params; - bf_set(lpfc_mqe_command, &mbox->u.mqe, MBX_PORT_CAPABILITIES); - bf_set(cpn, sli4_params, LPFC_SLI4_PARAMETERS); -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mem.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mem.c deleted file mode 100644 index ade763d3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_mem.c +++ /dev/null @@ -1,529 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2009 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include - -#include -#include - -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_crtn.h" - -#define LPFC_MBUF_POOL_SIZE 64 /* max elements in MBUF safety pool */ -#define LPFC_MEM_POOL_SIZE 64 /* max elem in non-DMA safety pool */ - - -/** - * lpfc_mem_alloc - create and allocate all PCI and memory pools - * @phba: HBA to allocate pools for - * - * Description: Creates and allocates PCI pools lpfc_scsi_dma_buf_pool, - * lpfc_mbuf_pool, lpfc_hrb_pool. Creates and allocates kmalloc-backed mempools - * for LPFC_MBOXQ_t and lpfc_nodelist. Also allocates the VPI bitmask. - * - * Notes: Not interrupt-safe. Must be called with no locks held. If any - * allocation fails, frees all successfully allocated memory before returning. - * - * Returns: - * 0 on success - * -ENOMEM on failure (if any memory allocations fail) - **/ -int -lpfc_mem_alloc(struct lpfc_hba *phba, int align) -{ - struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; - int i; - - if (phba->sli_rev == LPFC_SLI_REV4) - phba->lpfc_scsi_dma_buf_pool = - pci_pool_create("lpfc_scsi_dma_buf_pool", - phba->pcidev, - phba->cfg_sg_dma_buf_size, - phba->cfg_sg_dma_buf_size, - 0); - else - phba->lpfc_scsi_dma_buf_pool = - pci_pool_create("lpfc_scsi_dma_buf_pool", - phba->pcidev, phba->cfg_sg_dma_buf_size, - align, 0); - if (!phba->lpfc_scsi_dma_buf_pool) - goto fail; - - phba->lpfc_mbuf_pool = pci_pool_create("lpfc_mbuf_pool", phba->pcidev, - LPFC_BPL_SIZE, - align, 0); - if (!phba->lpfc_mbuf_pool) - goto fail_free_dma_buf_pool; - - pool->elements = kmalloc(sizeof(struct lpfc_dmabuf) * - LPFC_MBUF_POOL_SIZE, GFP_KERNEL); - if (!pool->elements) - goto fail_free_lpfc_mbuf_pool; - - pool->max_count = 0; - pool->current_count = 0; - for ( i = 0; i < LPFC_MBUF_POOL_SIZE; i++) { - pool->elements[i].virt = pci_pool_alloc(phba->lpfc_mbuf_pool, - GFP_KERNEL, &pool->elements[i].phys); - if (!pool->elements[i].virt) - goto fail_free_mbuf_pool; - pool->max_count++; - pool->current_count++; - } - - phba->mbox_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE, - sizeof(LPFC_MBOXQ_t)); - if (!phba->mbox_mem_pool) - goto fail_free_mbuf_pool; - - phba->nlp_mem_pool = mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE, - sizeof(struct lpfc_nodelist)); - if (!phba->nlp_mem_pool) - goto fail_free_mbox_pool; - - if (phba->sli_rev == LPFC_SLI_REV4) { - phba->rrq_pool = - mempool_create_kmalloc_pool(LPFC_MEM_POOL_SIZE, - sizeof(struct lpfc_node_rrq)); - if (!phba->rrq_pool) - goto fail_free_nlp_mem_pool; - phba->lpfc_hrb_pool = pci_pool_create("lpfc_hrb_pool", - phba->pcidev, - LPFC_HDR_BUF_SIZE, align, 0); - if (!phba->lpfc_hrb_pool) - goto fail_free_rrq_mem_pool; - - phba->lpfc_drb_pool = pci_pool_create("lpfc_drb_pool", - phba->pcidev, - LPFC_DATA_BUF_SIZE, align, 0); - if (!phba->lpfc_drb_pool) - goto fail_free_hrb_pool; - phba->lpfc_hbq_pool = NULL; - } else { - phba->lpfc_hbq_pool = pci_pool_create("lpfc_hbq_pool", - phba->pcidev, LPFC_BPL_SIZE, align, 0); - if (!phba->lpfc_hbq_pool) - goto fail_free_nlp_mem_pool; - phba->lpfc_hrb_pool = NULL; - phba->lpfc_drb_pool = NULL; - } - - return 0; - fail_free_hrb_pool: - pci_pool_destroy(phba->lpfc_hrb_pool); - phba->lpfc_hrb_pool = NULL; - fail_free_rrq_mem_pool: - mempool_destroy(phba->rrq_pool); - phba->rrq_pool = NULL; - fail_free_nlp_mem_pool: - mempool_destroy(phba->nlp_mem_pool); - phba->nlp_mem_pool = NULL; - fail_free_mbox_pool: - mempool_destroy(phba->mbox_mem_pool); - phba->mbox_mem_pool = NULL; - fail_free_mbuf_pool: - while (i--) - pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt, - pool->elements[i].phys); - kfree(pool->elements); - fail_free_lpfc_mbuf_pool: - pci_pool_destroy(phba->lpfc_mbuf_pool); - phba->lpfc_mbuf_pool = NULL; - fail_free_dma_buf_pool: - pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool); - phba->lpfc_scsi_dma_buf_pool = NULL; - fail: - return -ENOMEM; -} - -/** - * lpfc_mem_free - Frees memory allocated by lpfc_mem_alloc - * @phba: HBA to free memory for - * - * Description: Free the memory allocated by lpfc_mem_alloc routine. This - * routine is a the counterpart of lpfc_mem_alloc. - * - * Returns: None - **/ -void -lpfc_mem_free(struct lpfc_hba *phba) -{ - int i; - struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; - - /* Free HBQ pools */ - lpfc_sli_hbqbuf_free_all(phba); - if (phba->lpfc_drb_pool) - pci_pool_destroy(phba->lpfc_drb_pool); - phba->lpfc_drb_pool = NULL; - if (phba->lpfc_hrb_pool) - pci_pool_destroy(phba->lpfc_hrb_pool); - phba->lpfc_hrb_pool = NULL; - - if (phba->lpfc_hbq_pool) - pci_pool_destroy(phba->lpfc_hbq_pool); - phba->lpfc_hbq_pool = NULL; - - /* Free NLP memory pool */ - mempool_destroy(phba->nlp_mem_pool); - phba->nlp_mem_pool = NULL; - - /* Free mbox memory pool */ - mempool_destroy(phba->mbox_mem_pool); - phba->mbox_mem_pool = NULL; - - /* Free MBUF memory pool */ - for (i = 0; i < pool->current_count; i++) - pci_pool_free(phba->lpfc_mbuf_pool, pool->elements[i].virt, - pool->elements[i].phys); - kfree(pool->elements); - - pci_pool_destroy(phba->lpfc_mbuf_pool); - phba->lpfc_mbuf_pool = NULL; - - /* Free DMA buffer memory pool */ - pci_pool_destroy(phba->lpfc_scsi_dma_buf_pool); - phba->lpfc_scsi_dma_buf_pool = NULL; - - return; -} - -/** - * lpfc_mem_free_all - Frees all PCI and driver memory - * @phba: HBA to free memory for - * - * Description: Free memory from PCI and driver memory pools and also those - * used : lpfc_scsi_dma_buf_pool, lpfc_mbuf_pool, lpfc_hrb_pool. Frees - * kmalloc-backed mempools for LPFC_MBOXQ_t and lpfc_nodelist. Also frees - * the VPI bitmask. - * - * Returns: None - **/ -void -lpfc_mem_free_all(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - LPFC_MBOXQ_t *mbox, *next_mbox; - struct lpfc_dmabuf *mp; - - /* Free memory used in mailbox queue back to mailbox memory pool */ - list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { - mp = (struct lpfc_dmabuf *) (mbox->context1); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - list_del(&mbox->list); - mempool_free(mbox, phba->mbox_mem_pool); - } - /* Free memory used in mailbox cmpl list back to mailbox memory pool */ - list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) { - mp = (struct lpfc_dmabuf *) (mbox->context1); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - list_del(&mbox->list); - mempool_free(mbox, phba->mbox_mem_pool); - } - /* Free the active mailbox command back to the mailbox memory pool */ - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock_irq(&phba->hbalock); - if (psli->mbox_active) { - mbox = psli->mbox_active; - mp = (struct lpfc_dmabuf *) (mbox->context1); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mempool_free(mbox, phba->mbox_mem_pool); - psli->mbox_active = NULL; - } - - /* Free and destroy all the allocated memory pools */ - lpfc_mem_free(phba); - - /* Free the iocb lookup array */ - kfree(psli->iocbq_lookup); - psli->iocbq_lookup = NULL; - - return; -} - -/** - * lpfc_mbuf_alloc - Allocate an mbuf from the lpfc_mbuf_pool PCI pool - * @phba: HBA which owns the pool to allocate from - * @mem_flags: indicates if this is a priority (MEM_PRI) allocation - * @handle: used to return the DMA-mapped address of the mbuf - * - * Description: Allocates a DMA-mapped buffer from the lpfc_mbuf_pool PCI pool. - * Allocates from generic pci_pool_alloc function first and if that fails and - * mem_flags has MEM_PRI set (the only defined flag), returns an mbuf from the - * HBA's pool. - * - * Notes: Not interrupt-safe. Must be called with no locks held. Takes - * phba->hbalock. - * - * Returns: - * pointer to the allocated mbuf on success - * NULL on failure - **/ -void * -lpfc_mbuf_alloc(struct lpfc_hba *phba, int mem_flags, dma_addr_t *handle) -{ - struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; - unsigned long iflags; - void *ret; - - ret = pci_pool_alloc(phba->lpfc_mbuf_pool, GFP_KERNEL, handle); - - spin_lock_irqsave(&phba->hbalock, iflags); - if (!ret && (mem_flags & MEM_PRI) && pool->current_count) { - pool->current_count--; - ret = pool->elements[pool->current_count].virt; - *handle = pool->elements[pool->current_count].phys; - } - spin_unlock_irqrestore(&phba->hbalock, iflags); - return ret; -} - -/** - * __lpfc_mbuf_free - Free an mbuf from the lpfc_mbuf_pool PCI pool (locked) - * @phba: HBA which owns the pool to return to - * @virt: mbuf to free - * @dma: the DMA-mapped address of the lpfc_mbuf_pool to be freed - * - * Description: Returns an mbuf lpfc_mbuf_pool to the lpfc_mbuf_safety_pool if - * it is below its max_count, frees the mbuf otherwise. - * - * Notes: Must be called with phba->hbalock held to synchronize access to - * lpfc_mbuf_safety_pool. - * - * Returns: None - **/ -void -__lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) -{ - struct lpfc_dma_pool *pool = &phba->lpfc_mbuf_safety_pool; - - if (pool->current_count < pool->max_count) { - pool->elements[pool->current_count].virt = virt; - pool->elements[pool->current_count].phys = dma; - pool->current_count++; - } else { - pci_pool_free(phba->lpfc_mbuf_pool, virt, dma); - } - return; -} - -/** - * lpfc_mbuf_free - Free an mbuf from the lpfc_mbuf_pool PCI pool (unlocked) - * @phba: HBA which owns the pool to return to - * @virt: mbuf to free - * @dma: the DMA-mapped address of the lpfc_mbuf_pool to be freed - * - * Description: Returns an mbuf lpfc_mbuf_pool to the lpfc_mbuf_safety_pool if - * it is below its max_count, frees the mbuf otherwise. - * - * Notes: Takes phba->hbalock. Can be called with or without other locks held. - * - * Returns: None - **/ -void -lpfc_mbuf_free(struct lpfc_hba * phba, void *virt, dma_addr_t dma) -{ - unsigned long iflags; - - spin_lock_irqsave(&phba->hbalock, iflags); - __lpfc_mbuf_free(phba, virt, dma); - spin_unlock_irqrestore(&phba->hbalock, iflags); - return; -} - -/** - * lpfc_els_hbq_alloc - Allocate an HBQ buffer - * @phba: HBA to allocate HBQ buffer for - * - * Description: Allocates a DMA-mapped HBQ buffer from the lpfc_hrb_pool PCI - * pool along a non-DMA-mapped container for it. - * - * Notes: Not interrupt-safe. Must be called with no locks held. - * - * Returns: - * pointer to HBQ on success - * NULL on failure - **/ -struct hbq_dmabuf * -lpfc_els_hbq_alloc(struct lpfc_hba *phba) -{ - struct hbq_dmabuf *hbqbp; - - hbqbp = kzalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); - if (!hbqbp) - return NULL; - - hbqbp->dbuf.virt = pci_pool_alloc(phba->lpfc_hbq_pool, GFP_KERNEL, - &hbqbp->dbuf.phys); - if (!hbqbp->dbuf.virt) { - kfree(hbqbp); - return NULL; - } - hbqbp->size = LPFC_BPL_SIZE; - return hbqbp; -} - -/** - * lpfc_els_hbq_free - Frees an HBQ buffer allocated with lpfc_els_hbq_alloc - * @phba: HBA buffer was allocated for - * @hbqbp: HBQ container returned by lpfc_els_hbq_alloc - * - * Description: Frees both the container and the DMA-mapped buffer returned by - * lpfc_els_hbq_alloc. - * - * Notes: Can be called with or without locks held. - * - * Returns: None - **/ -void -lpfc_els_hbq_free(struct lpfc_hba *phba, struct hbq_dmabuf *hbqbp) -{ - pci_pool_free(phba->lpfc_hbq_pool, hbqbp->dbuf.virt, hbqbp->dbuf.phys); - kfree(hbqbp); - return; -} - -/** - * lpfc_sli4_rb_alloc - Allocate an SLI4 Receive buffer - * @phba: HBA to allocate a receive buffer for - * - * Description: Allocates a DMA-mapped receive buffer from the lpfc_hrb_pool PCI - * pool along a non-DMA-mapped container for it. - * - * Notes: Not interrupt-safe. Must be called with no locks held. - * - * Returns: - * pointer to HBQ on success - * NULL on failure - **/ -struct hbq_dmabuf * -lpfc_sli4_rb_alloc(struct lpfc_hba *phba) -{ - struct hbq_dmabuf *dma_buf; - - dma_buf = kzalloc(sizeof(struct hbq_dmabuf), GFP_KERNEL); - if (!dma_buf) - return NULL; - - dma_buf->hbuf.virt = pci_pool_alloc(phba->lpfc_hrb_pool, GFP_KERNEL, - &dma_buf->hbuf.phys); - if (!dma_buf->hbuf.virt) { - kfree(dma_buf); - return NULL; - } - dma_buf->dbuf.virt = pci_pool_alloc(phba->lpfc_drb_pool, GFP_KERNEL, - &dma_buf->dbuf.phys); - if (!dma_buf->dbuf.virt) { - pci_pool_free(phba->lpfc_hrb_pool, dma_buf->hbuf.virt, - dma_buf->hbuf.phys); - kfree(dma_buf); - return NULL; - } - dma_buf->size = LPFC_BPL_SIZE; - return dma_buf; -} - -/** - * lpfc_sli4_rb_free - Frees a receive buffer - * @phba: HBA buffer was allocated for - * @dmab: DMA Buffer container returned by lpfc_sli4_hbq_alloc - * - * Description: Frees both the container and the DMA-mapped buffers returned by - * lpfc_sli4_rb_alloc. - * - * Notes: Can be called with or without locks held. - * - * Returns: None - **/ -void -lpfc_sli4_rb_free(struct lpfc_hba *phba, struct hbq_dmabuf *dmab) -{ - pci_pool_free(phba->lpfc_hrb_pool, dmab->hbuf.virt, dmab->hbuf.phys); - pci_pool_free(phba->lpfc_drb_pool, dmab->dbuf.virt, dmab->dbuf.phys); - kfree(dmab); - return; -} - -/** - * lpfc_in_buf_free - Free a DMA buffer - * @phba: HBA buffer is associated with - * @mp: Buffer to free - * - * Description: Frees the given DMA buffer in the appropriate way given if the - * HBA is running in SLI3 mode with HBQs enabled. - * - * Notes: Takes phba->hbalock. Can be called with or without other locks held. - * - * Returns: None - **/ -void -lpfc_in_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp) -{ - struct hbq_dmabuf *hbq_entry; - unsigned long flags; - - if (!mp) - return; - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - /* Check whether HBQ is still in use */ - spin_lock_irqsave(&phba->hbalock, flags); - if (!phba->hbq_in_use) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return; - } - hbq_entry = container_of(mp, struct hbq_dmabuf, dbuf); - list_del(&hbq_entry->dbuf.list); - if (hbq_entry->tag == -1) { - (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) - (phba, hbq_entry); - } else { - lpfc_sli_free_hbq(phba, hbq_entry); - } - spin_unlock_irqrestore(&phba->hbalock, flags); - } else { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - return; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nl.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nl.h deleted file mode 100644 index f2b1bbcb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nl.h +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2010 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -/* Event definitions for RegisterForEvent */ -#define FC_REG_LINK_EVENT 0x0001 /* link up / down events */ -#define FC_REG_RSCN_EVENT 0x0002 /* RSCN events */ -#define FC_REG_CT_EVENT 0x0004 /* CT request events */ -#define FC_REG_DUMP_EVENT 0x0010 /* Dump events */ -#define FC_REG_TEMPERATURE_EVENT 0x0020 /* temperature events */ -#define FC_REG_VPORTRSCN_EVENT 0x0040 /* Vport RSCN events */ -#define FC_REG_ELS_EVENT 0x0080 /* lpfc els events */ -#define FC_REG_FABRIC_EVENT 0x0100 /* lpfc fabric events */ -#define FC_REG_SCSI_EVENT 0x0200 /* lpfc scsi events */ -#define FC_REG_BOARD_EVENT 0x0400 /* lpfc board events */ -#define FC_REG_ADAPTER_EVENT 0x0800 /* lpfc adapter events */ -#define FC_REG_EVENT_MASK (FC_REG_LINK_EVENT | \ - FC_REG_RSCN_EVENT | \ - FC_REG_CT_EVENT | \ - FC_REG_DUMP_EVENT | \ - FC_REG_TEMPERATURE_EVENT | \ - FC_REG_VPORTRSCN_EVENT | \ - FC_REG_ELS_EVENT | \ - FC_REG_FABRIC_EVENT | \ - FC_REG_SCSI_EVENT | \ - FC_REG_BOARD_EVENT | \ - FC_REG_ADAPTER_EVENT) -/* Temperature events */ -#define LPFC_CRIT_TEMP 0x1 -#define LPFC_THRESHOLD_TEMP 0x2 -#define LPFC_NORMAL_TEMP 0x3 -/* - * All net link event payloads will begin with and event type - * and subcategory. The event type must come first. - * The subcategory further defines the data that follows in the rest - * of the payload. Each category will have its own unique header plus - * any additional data unique to the subcategory. - * The payload sent via the fc transport is one-way driver->application. - */ - -/* RSCN event header */ -struct lpfc_rscn_event_header { - uint32_t event_type; - uint32_t payload_length; /* RSCN data length in bytes */ - uint32_t rscn_payload[]; -}; - -/* els event header */ -struct lpfc_els_event_header { - uint32_t event_type; - uint32_t subcategory; - uint8_t wwpn[8]; - uint8_t wwnn[8]; -}; - -/* subcategory codes for FC_REG_ELS_EVENT */ -#define LPFC_EVENT_PLOGI_RCV 0x01 -#define LPFC_EVENT_PRLO_RCV 0x02 -#define LPFC_EVENT_ADISC_RCV 0x04 -#define LPFC_EVENT_LSRJT_RCV 0x08 -#define LPFC_EVENT_LOGO_RCV 0x10 - -/* special els lsrjt event */ -struct lpfc_lsrjt_event { - struct lpfc_els_event_header header; - uint32_t command; - uint32_t reason_code; - uint32_t explanation; -}; - -/* special els logo event */ -struct lpfc_logo_event { - struct lpfc_els_event_header header; - uint8_t logo_wwpn[8]; -}; - -/* fabric event header */ -struct lpfc_fabric_event_header { - uint32_t event_type; - uint32_t subcategory; - uint8_t wwpn[8]; - uint8_t wwnn[8]; -}; - -/* subcategory codes for FC_REG_FABRIC_EVENT */ -#define LPFC_EVENT_FABRIC_BUSY 0x01 -#define LPFC_EVENT_PORT_BUSY 0x02 -#define LPFC_EVENT_FCPRDCHKERR 0x04 - -/* special case fabric fcprdchkerr event */ -struct lpfc_fcprdchkerr_event { - struct lpfc_fabric_event_header header; - uint32_t lun; - uint32_t opcode; - uint32_t fcpiparam; -}; - - -/* scsi event header */ -struct lpfc_scsi_event_header { - uint32_t event_type; - uint32_t subcategory; - uint32_t lun; - uint8_t wwpn[8]; - uint8_t wwnn[8]; -}; - -/* subcategory codes for FC_REG_SCSI_EVENT */ -#define LPFC_EVENT_QFULL 0x0001 -#define LPFC_EVENT_DEVBSY 0x0002 -#define LPFC_EVENT_CHECK_COND 0x0004 -#define LPFC_EVENT_LUNRESET 0x0008 -#define LPFC_EVENT_TGTRESET 0x0010 -#define LPFC_EVENT_BUSRESET 0x0020 -#define LPFC_EVENT_VARQUEDEPTH 0x0040 - -/* special case scsi varqueuedepth event */ -struct lpfc_scsi_varqueuedepth_event { - struct lpfc_scsi_event_header scsi_event; - uint32_t oldval; - uint32_t newval; -}; - -/* special case scsi check condition event */ -struct lpfc_scsi_check_condition_event { - struct lpfc_scsi_event_header scsi_event; - uint8_t opcode; - uint8_t sense_key; - uint8_t asc; - uint8_t ascq; -}; - -/* event codes for FC_REG_BOARD_EVENT */ -#define LPFC_EVENT_PORTINTERR 0x01 - -/* board event header */ -struct lpfc_board_event_header { - uint32_t event_type; - uint32_t subcategory; -}; - - -/* event codes for FC_REG_ADAPTER_EVENT */ -#define LPFC_EVENT_ARRIVAL 0x01 - -/* adapter event header */ -struct lpfc_adapter_event_header { - uint32_t event_type; - uint32_t subcategory; -}; - - -/* event codes for temp_event */ -#define LPFC_CRIT_TEMP 0x1 -#define LPFC_THRESHOLD_TEMP 0x2 -#define LPFC_NORMAL_TEMP 0x3 - -struct temp_event { - uint32_t event_type; - uint32_t event_code; - uint32_t data; -}; - diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nportdisc.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nportdisc.c deleted file mode 100644 index 15ca2a9a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_nportdisc.c +++ /dev/null @@ -1,2382 +0,0 @@ - /******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_vport.h" -#include "lpfc_debugfs.h" - - -/* Called to verify a rcv'ed ADISC was intended for us. */ -static int -lpfc_check_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct lpfc_name *nn, struct lpfc_name *pn) -{ - /* First, we MUST have a RPI registered */ - if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) - return 0; - - /* Compare the ADISC rsp WWNN / WWPN matches our internal node - * table entry for that node. - */ - if (memcmp(nn, &ndlp->nlp_nodename, sizeof (struct lpfc_name))) - return 0; - - if (memcmp(pn, &ndlp->nlp_portname, sizeof (struct lpfc_name))) - return 0; - - /* we match, return success */ - return 1; -} - -int -lpfc_check_sparm(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct serv_parm *sp, uint32_t class, int flogi) -{ - volatile struct serv_parm *hsp = &vport->fc_sparam; - uint16_t hsp_value, ssp_value = 0; - - /* - * The receive data field size and buffer-to-buffer receive data field - * size entries are 16 bits but are represented as two 8-bit fields in - * the driver data structure to account for rsvd bits and other control - * bits. Reconstruct and compare the fields as a 16-bit values before - * correcting the byte values. - */ - if (sp->cls1.classValid) { - if (!flogi) { - hsp_value = ((hsp->cls1.rcvDataSizeMsb << 8) | - hsp->cls1.rcvDataSizeLsb); - ssp_value = ((sp->cls1.rcvDataSizeMsb << 8) | - sp->cls1.rcvDataSizeLsb); - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls1.rcvDataSizeLsb = - hsp->cls1.rcvDataSizeLsb; - sp->cls1.rcvDataSizeMsb = - hsp->cls1.rcvDataSizeMsb; - } - } - } else if (class == CLASS1) - goto bad_service_param; - if (sp->cls2.classValid) { - if (!flogi) { - hsp_value = ((hsp->cls2.rcvDataSizeMsb << 8) | - hsp->cls2.rcvDataSizeLsb); - ssp_value = ((sp->cls2.rcvDataSizeMsb << 8) | - sp->cls2.rcvDataSizeLsb); - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls2.rcvDataSizeLsb = - hsp->cls2.rcvDataSizeLsb; - sp->cls2.rcvDataSizeMsb = - hsp->cls2.rcvDataSizeMsb; - } - } - } else if (class == CLASS2) - goto bad_service_param; - if (sp->cls3.classValid) { - if (!flogi) { - hsp_value = ((hsp->cls3.rcvDataSizeMsb << 8) | - hsp->cls3.rcvDataSizeLsb); - ssp_value = ((sp->cls3.rcvDataSizeMsb << 8) | - sp->cls3.rcvDataSizeLsb); - if (!ssp_value) - goto bad_service_param; - if (ssp_value > hsp_value) { - sp->cls3.rcvDataSizeLsb = - hsp->cls3.rcvDataSizeLsb; - sp->cls3.rcvDataSizeMsb = - hsp->cls3.rcvDataSizeMsb; - } - } - } else if (class == CLASS3) - goto bad_service_param; - - /* - * Preserve the upper four bits of the MSB from the PLOGI response. - * These bits contain the Buffer-to-Buffer State Change Number - * from the target and need to be passed to the FW. - */ - hsp_value = (hsp->cmn.bbRcvSizeMsb << 8) | hsp->cmn.bbRcvSizeLsb; - ssp_value = (sp->cmn.bbRcvSizeMsb << 8) | sp->cmn.bbRcvSizeLsb; - if (ssp_value > hsp_value) { - sp->cmn.bbRcvSizeLsb = hsp->cmn.bbRcvSizeLsb; - sp->cmn.bbRcvSizeMsb = (sp->cmn.bbRcvSizeMsb & 0xF0) | - (hsp->cmn.bbRcvSizeMsb & 0x0F); - } - - memcpy(&ndlp->nlp_nodename, &sp->nodeName, sizeof (struct lpfc_name)); - memcpy(&ndlp->nlp_portname, &sp->portName, sizeof (struct lpfc_name)); - return 1; -bad_service_param: - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0207 Device %x " - "(%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x) sent " - "invalid service parameters. Ignoring device.\n", - ndlp->nlp_DID, - sp->nodeName.u.wwn[0], sp->nodeName.u.wwn[1], - sp->nodeName.u.wwn[2], sp->nodeName.u.wwn[3], - sp->nodeName.u.wwn[4], sp->nodeName.u.wwn[5], - sp->nodeName.u.wwn[6], sp->nodeName.u.wwn[7]); - return 0; -} - -static void * -lpfc_check_elscmpl_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - struct lpfc_dmabuf *pcmd, *prsp; - uint32_t *lp; - void *ptr = NULL; - IOCB_t *irsp; - - irsp = &rspiocb->iocb; - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - - /* For lpfc_els_abort, context2 could be zero'ed to delay - * freeing associated memory till after ABTS completes. - */ - if (pcmd) { - prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, - list); - if (prsp) { - lp = (uint32_t *) prsp->virt; - ptr = (void *)((uint8_t *)lp + sizeof(uint32_t)); - } - } else { - /* Force ulpStatus error since we are returning NULL ptr */ - if (!(irsp->ulpStatus)) { - irsp->ulpStatus = IOSTAT_LOCAL_REJECT; - irsp->un.ulpWord[4] = IOERR_SLI_ABORTED; - } - ptr = NULL; - } - return ptr; -} - - - -/* - * Free resources / clean up outstanding I/Os - * associated with a LPFC_NODELIST entry. This - * routine effectively results in a "software abort". - */ -int -lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) -{ - LIST_HEAD(completions); - LIST_HEAD(txcmplq_completions); - LIST_HEAD(abort_list); - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring = &psli->ring[LPFC_ELS_RING]; - struct lpfc_iocbq *iocb, *next_iocb; - - /* Abort outstanding I/O on NPort */ - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_DISCOVERY, - "2819 Abort outstanding I/O on NPort x%x " - "Data: x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, - ndlp->nlp_rpi); - - lpfc_fabric_abort_nport(ndlp); - - /* First check the txq */ - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { - /* Check to see if iocb matches the nport we are looking for */ - if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) { - /* It matches, so deque and call compl with anp error */ - list_move_tail(&iocb->list, &completions); - pring->txq_cnt--; - } - } - - /* Next check the txcmplq */ - list_splice_init(&pring->txcmplq, &txcmplq_completions); - spin_unlock_irq(&phba->hbalock); - - list_for_each_entry_safe(iocb, next_iocb, &txcmplq_completions, list) { - /* Check to see if iocb matches the nport we are looking for */ - if (lpfc_check_sli_ndlp(phba, pring, iocb, ndlp)) - list_add_tail(&iocb->dlist, &abort_list); - } - spin_lock_irq(&phba->hbalock); - list_splice(&txcmplq_completions, &pring->txcmplq); - spin_unlock_irq(&phba->hbalock); - - list_for_each_entry_safe(iocb, next_iocb, &abort_list, dlist) { - spin_lock_irq(&phba->hbalock); - list_del_init(&iocb->dlist); - lpfc_sli_issue_abort_iotag(phba, pring, iocb); - spin_unlock_irq(&phba->hbalock); - } - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); - - lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); - return 0; -} - -static int -lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct lpfc_iocbq *cmdiocb) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_dmabuf *pcmd; - uint32_t *lp; - IOCB_t *icmd; - struct serv_parm *sp; - LPFC_MBOXQ_t *mbox; - struct ls_rjt stat; - int rc; - - memset(&stat, 0, sizeof (struct ls_rjt)); - if (vport->port_state <= LPFC_FDISC) { - /* Before responding to PLOGI, check for pt2pt mode. - * If we are pt2pt, with an outstanding FLOGI, abort - * the FLOGI and resend it first. - */ - if (vport->fc_flag & FC_PT2PT) { - lpfc_els_abort_flogi(phba); - if (!(vport->fc_flag & FC_PT2PT_PLOGI)) { - /* If the other side is supposed to initiate - * the PLOGI anyway, just ACC it now and - * move on with discovery. - */ - phba->fc_edtov = FF_DEF_EDTOV; - phba->fc_ratov = FF_DEF_RATOV; - /* Start discovery - this should just do - CLEAR_LA */ - lpfc_disc_start(vport); - } else - lpfc_initial_flogi(vport); - } else { - stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; - stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, - ndlp, NULL); - return 0; - } - } - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); - if (wwn_to_u64(sp->portName.u.wwn) == 0) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0140 PLOGI Reject: invalid nname\n"); - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_PNAME; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, - NULL); - return 0; - } - if (wwn_to_u64(sp->nodeName.u.wwn) == 0) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0141 PLOGI Reject: invalid pname\n"); - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_INVALID_NNAME; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, - NULL); - return 0; - } - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0) == 0)) { - /* Reject this request because invalid parameters */ - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, - NULL); - return 0; - } - icmd = &cmdiocb->iocb; - - /* PLOGI chkparm OK */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0114 PLOGI chkparm OK Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_state, ndlp->nlp_flag, - ndlp->nlp_rpi); - - if (vport->cfg_fcp_class == 2 && sp->cls2.classValid) - ndlp->nlp_fcp_info |= CLASS2; - else - ndlp->nlp_fcp_info |= CLASS3; - - ndlp->nlp_class_sup = 0; - if (sp->cls1.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS1; - if (sp->cls2.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS2; - if (sp->cls3.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; - ndlp->nlp_maxframe = - ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; - - /* no need to reg_login if we are already in one of these states */ - switch (ndlp->nlp_state) { - case NLP_STE_NPR_NODE: - if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) - break; - case NLP_STE_REG_LOGIN_ISSUE: - case NLP_STE_PRLI_ISSUE: - case NLP_STE_UNMAPPED_NODE: - case NLP_STE_MAPPED_NODE: - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, NULL); - return 1; - } - - if ((vport->fc_flag & FC_PT2PT) && - !(vport->fc_flag & FC_PT2PT_PLOGI)) { - /* rcv'ed PLOGI decides what our NPortId will be */ - vport->fc_myDID = icmd->un.rcvels.parmRo; - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox == NULL) - goto out; - lpfc_config_link(phba, mbox); - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - goto out; - } - - lpfc_can_disctmo(vport); - } - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - goto out; - - /* Registering an existing RPI behaves differently for SLI3 vs SLI4 */ - if (phba->sli_rev == LPFC_SLI_REV4) - lpfc_unreg_rpi(vport, ndlp); - - rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID, - (uint8_t *) sp, mbox, ndlp->nlp_rpi); - if (rc) { - mempool_free(mbox, phba->mbox_mem_pool); - goto out; - } - - /* ACC PLOGI rsp command needs to execute first, - * queue this mbox command to be processed later. - */ - mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; - /* - * mbox->context2 = lpfc_nlp_get(ndlp) deferred until mailbox - * command issued in lpfc_cmpl_els_acc(). - */ - mbox->vport = vport; - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); - spin_unlock_irq(shost->host_lock); - - /* - * If there is an outstanding PLOGI issued, abort it before - * sending ACC rsp for received PLOGI. If pending plogi - * is not canceled here, the plogi will be rejected by - * remote port and will be retried. On a configuration with - * single discovery thread, this will cause a huge delay in - * discovery. Also this will cause multiple state machines - * running in parallel for this node. - */ - if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) { - /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp); - } - - if ((vport->port_type == LPFC_NPIV_PORT && - vport->cfg_restrict_login)) { - - /* In order to preserve RPIs, we want to cleanup - * the default RPI the firmware created to rcv - * this ELS request. The only way to do this is - * to register, then unregister the RPI. - */ - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_RM_DFLT_RPI; - spin_unlock_irq(shost->host_lock); - stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD; - stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; - rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, - ndlp, mbox); - if (rc) - mempool_free(mbox, phba->mbox_mem_pool); - return 1; - } - rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); - if (rc) - mempool_free(mbox, phba->mbox_mem_pool); - return 1; -out: - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return 0; -} - -/** - * lpfc_mbx_cmpl_resume_rpi - Resume RPI completion routine - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to mailbox object - * - * This routine is invoked to issue a completion to a rcv'ed - * ADISC or PDISC after the paused RPI has been resumed. - **/ -static void -lpfc_mbx_cmpl_resume_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - struct lpfc_vport *vport; - struct lpfc_iocbq *elsiocb; - struct lpfc_nodelist *ndlp; - uint32_t cmd; - - elsiocb = (struct lpfc_iocbq *)mboxq->context1; - ndlp = (struct lpfc_nodelist *) mboxq->context2; - vport = mboxq->vport; - cmd = elsiocb->drvrTimeout; - - if (cmd == ELS_CMD_ADISC) { - lpfc_els_rsp_adisc_acc(vport, elsiocb, ndlp); - } else { - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, elsiocb, - ndlp, NULL); - } - kfree(elsiocb); - mempool_free(mboxq, phba->mbox_mem_pool); -} - -static int -lpfc_rcv_padisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct lpfc_iocbq *cmdiocb) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_iocbq *elsiocb; - struct lpfc_dmabuf *pcmd; - struct serv_parm *sp; - struct lpfc_name *pnn, *ppn; - struct ls_rjt stat; - ADISC *ap; - IOCB_t *icmd; - uint32_t *lp; - uint32_t cmd; - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - - cmd = *lp++; - if (cmd == ELS_CMD_ADISC) { - ap = (ADISC *) lp; - pnn = (struct lpfc_name *) & ap->nodeName; - ppn = (struct lpfc_name *) & ap->portName; - } else { - sp = (struct serv_parm *) lp; - pnn = (struct lpfc_name *) & sp->nodeName; - ppn = (struct lpfc_name *) & sp->portName; - } - - icmd = &cmdiocb->iocb; - if (icmd->ulpStatus == 0 && lpfc_check_adisc(vport, ndlp, pnn, ppn)) { - - /* - * As soon as we send ACC, the remote NPort can - * start sending us data. Thus, for SLI4 we must - * resume the RPI before the ACC goes out. - */ - if (vport->phba->sli_rev == LPFC_SLI_REV4) { - elsiocb = kmalloc(sizeof(struct lpfc_iocbq), - GFP_KERNEL); - if (elsiocb) { - - /* Save info from cmd IOCB used in rsp */ - memcpy((uint8_t *)elsiocb, (uint8_t *)cmdiocb, - sizeof(struct lpfc_iocbq)); - - /* Save the ELS cmd */ - elsiocb->drvrTimeout = cmd; - - lpfc_sli4_resume_rpi(ndlp, - lpfc_mbx_cmpl_resume_rpi, elsiocb); - goto out; - } - } - - if (cmd == ELS_CMD_ADISC) { - lpfc_els_rsp_adisc_acc(vport, cmdiocb, ndlp); - } else { - lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, - ndlp, NULL); - } -out: - /* If we are authenticated, move to the proper state */ - if (ndlp->nlp_type & NLP_FCP_TARGET) - lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); - else - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - - return 1; - } - /* Reject this request because invalid parameters */ - stat.un.b.lsRjtRsvd0 = 0; - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_SPARM_OPTIONS; - stat.un.b.vendorUnique = 0; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - - /* 1 sec timeout */ - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); - - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - return 0; -} - -static int -lpfc_rcv_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct lpfc_iocbq *cmdiocb, uint32_t els_cmd) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_vport **vports; - int i, active_vlink_present = 0 ; - - /* Put ndlp in NPR state with 1 sec timeout for plogi, ACC logo */ - /* Only call LOGO ACC for first LOGO, this avoids sending unnecessary - * PLOGIs during LOGO storms from a device. - */ - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); - if (els_cmd == ELS_CMD_PRLO) - lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); - else - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - if (ndlp->nlp_DID == Fabric_DID) { - if (vport->port_state <= LPFC_FDISC) - goto out; - lpfc_linkdown_port(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_LOGO_RCVD; - spin_unlock_irq(shost->host_lock); - vports = lpfc_create_vport_work_array(phba); - if (vports) { - for (i = 0; i <= phba->max_vports && vports[i] != NULL; - i++) { - if ((!(vports[i]->fc_flag & - FC_VPORT_LOGO_RCVD)) && - (vports[i]->port_state > LPFC_FDISC)) { - active_vlink_present = 1; - break; - } - } - lpfc_destroy_vport_work_array(phba, vports); - } - - if (active_vlink_present) { - /* - * If there are other active VLinks present, - * re-instantiate the Vlink using FDISC. - */ - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_FDISC; - vport->port_state = LPFC_FDISC; - } else { - spin_lock_irq(shost->host_lock); - phba->pport->fc_flag &= ~FC_LOGO_RCVD_DID_CHNG; - spin_unlock_irq(shost->host_lock); - lpfc_retry_pport_discovery(phba); - } - } else if ((!(ndlp->nlp_type & NLP_FABRIC) && - ((ndlp->nlp_type & NLP_FCP_TARGET) || - !(ndlp->nlp_type & NLP_FCP_INITIATOR))) || - (ndlp->nlp_state == NLP_STE_ADISC_ISSUE)) { - /* Only try to re-login if this is NOT a Fabric Node */ - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - - ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - } -out: - ndlp->nlp_prev_state = ndlp->nlp_state; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - /* The driver has to wait until the ACC completes before it continues - * processing the LOGO. The action will resume in - * lpfc_cmpl_els_logo_acc routine. Since part of processing includes an - * unreg_login, the driver waits so the ACC does not get aborted. - */ - return 0; -} - -static void -lpfc_rcv_prli(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - struct lpfc_iocbq *cmdiocb) -{ - struct lpfc_dmabuf *pcmd; - uint32_t *lp; - PRLI *npr; - struct fc_rport *rport = ndlp->rport; - u32 roles; - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - lp = (uint32_t *) pcmd->virt; - npr = (PRLI *) ((uint8_t *) lp + sizeof (uint32_t)); - - ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - if (npr->prliType == PRLI_FCP_TYPE) { - if (npr->initiatorFunc) - ndlp->nlp_type |= NLP_FCP_INITIATOR; - if (npr->targetFunc) - ndlp->nlp_type |= NLP_FCP_TARGET; - if (npr->Retry) - ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; - } - if (rport) { - /* We need to update the rport role values */ - roles = FC_RPORT_ROLE_UNKNOWN; - if (ndlp->nlp_type & NLP_FCP_INITIATOR) - roles |= FC_RPORT_ROLE_FCP_INITIATOR; - if (ndlp->nlp_type & NLP_FCP_TARGET) - roles |= FC_RPORT_ROLE_FCP_TARGET; - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, - "rport rolechg: role:x%x did:x%x flg:x%x", - roles, ndlp->nlp_DID, ndlp->nlp_flag); - - fc_remote_port_rolechg(rport, roles); - } -} - -static uint32_t -lpfc_disc_set_adisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (!(ndlp->nlp_flag & NLP_RPI_REGISTERED)) { - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - return 0; - } - - if (!(vport->fc_flag & FC_PT2PT)) { - /* Check config parameter use-adisc or FCP-2 */ - if ((vport->cfg_use_adisc && (vport->fc_flag & FC_RSCN_MODE)) || - ((ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) && - (ndlp->nlp_type & NLP_FCP_TARGET))) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - return 1; - } - } - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - lpfc_unreg_rpi(vport, ndlp); - return 0; -} - -/** - * lpfc_release_rpi - Release a RPI by issuing unreg_login mailbox cmd. - * @phba : Pointer to lpfc_hba structure. - * @vport: Pointer to lpfc_vport structure. - * @rpi : rpi to be release. - * - * This function will send a unreg_login mailbox command to the firmware - * to release a rpi. - **/ -void -lpfc_release_rpi(struct lpfc_hba *phba, - struct lpfc_vport *vport, - uint16_t rpi) -{ - LPFC_MBOXQ_t *pmb; - int rc; - - pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, - GFP_KERNEL); - if (!pmb) - lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX, - "2796 mailbox memory allocation failed \n"); - else { - lpfc_unreg_login(phba, vport->vpi, rpi, pmb); - pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - mempool_free(pmb, phba->mbox_mem_pool); - } -} - -static uint32_t -lpfc_disc_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_hba *phba; - LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; - MAILBOX_t *mb; - uint16_t rpi; - - phba = vport->phba; - /* Release the RPI if reglogin completing */ - if (!(phba->pport->load_flag & FC_UNLOADING) && - (evt == NLP_EVT_CMPL_REG_LOGIN) && - (!pmb->u.mb.mbxStatus)) { - mb = &pmb->u.mb; - rpi = pmb->u.mb.un.varWords[0]; - lpfc_release_rpi(phba, vport, rpi); - } - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0271 Illegal State Transition: node x%x " - "event x%x, state x%x Data: x%x x%x\n", - ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, - ndlp->nlp_flag); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_plogi_illegal(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - /* This transition is only legal if we previously - * rcv'ed a PLOGI. Since we don't want 2 discovery threads - * working on the same NPortID, do nothing for this thread - * to stop it. - */ - if (!(ndlp->nlp_flag & NLP_RCV_PLOGI)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0272 Illegal State Transition: node x%x " - "event x%x, state x%x Data: x%x x%x\n", - ndlp->nlp_DID, evt, ndlp->nlp_state, ndlp->nlp_rpi, - ndlp->nlp_flag); - } - return ndlp->nlp_state; -} - -/* Start of Discovery State Machine routines */ - -static uint32_t -lpfc_rcv_plogi_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb; - - cmdiocb = (struct lpfc_iocbq *) arg; - - if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { - return ndlp->nlp_state; - } - return NLP_STE_FREED_NODE; -} - -static uint32_t -lpfc_rcv_els_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - lpfc_issue_els_logo(vport, ndlp, 0); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_logo_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - return NLP_STE_FREED_NODE; -} - -static uint32_t -lpfc_device_rm_unused_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - return NLP_STE_FREED_NODE; -} - -static uint32_t -lpfc_device_recov_unused_node(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_plogi_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb = arg; - struct lpfc_dmabuf *pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - uint32_t *lp = (uint32_t *) pcmd->virt; - struct serv_parm *sp = (struct serv_parm *) (lp + 1); - struct ls_rjt stat; - int port_cmp; - - memset(&stat, 0, sizeof (struct ls_rjt)); - - /* For a PLOGI, we only accept if our portname is less - * than the remote portname. - */ - phba->fc_stat.elsLogiCol++; - port_cmp = memcmp(&vport->fc_portname, &sp->portName, - sizeof(struct lpfc_name)); - - if (port_cmp >= 0) { - /* Reject this request because the remote node will accept - ours */ - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_CMD_IN_PROGRESS; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, - NULL); - } else { - if (lpfc_rcv_plogi(vport, ndlp, cmdiocb) && - (ndlp->nlp_flag & NLP_NPR_2B_DISC) && - (vport->num_disc_nodes)) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - /* Check if there are more PLOGIs to be sent */ - lpfc_more_plogi(vport); - if (vport->num_disc_nodes == 0) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_NDISC_ACTIVE; - spin_unlock_irq(shost->host_lock); - lpfc_can_disctmo(vport); - lpfc_end_rscn(vport); - } - } - } /* If our portname was less */ - - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prli_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - struct ls_rjt stat; - - memset(&stat, 0, sizeof (struct ls_rjt)); - stat.un.b.lsRjtRsnCode = LSRJT_LOGICAL_BSY; - stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - /* software abort outstanding PLOGI */ - lpfc_els_abort(vport->phba, ndlp); - - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_els_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp); - - if (evt == NLP_EVT_RCV_LOGO) { - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - } else { - lpfc_issue_els_logo(vport, ndlp, 0); - } - - /* Put ndlp in npr state set plogi timer for 1 sec */ - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_plogi_plogi_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct lpfc_hba *phba = vport->phba; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_iocbq *cmdiocb, *rspiocb; - struct lpfc_dmabuf *pcmd, *prsp, *mp; - uint32_t *lp; - IOCB_t *irsp; - struct serv_parm *sp; - LPFC_MBOXQ_t *mbox; - - cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; - - if (ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - /* Recovery from PLOGI collision logic */ - return ndlp->nlp_state; - } - - irsp = &rspiocb->iocb; - - if (irsp->ulpStatus) - goto out; - - pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; - - prsp = list_get_first(&pcmd->list, struct lpfc_dmabuf, list); - - lp = (uint32_t *) prsp->virt; - sp = (struct serv_parm *) ((uint8_t *) lp + sizeof (uint32_t)); - - /* Some switches have FDMI servers returning 0 for WWN */ - if ((ndlp->nlp_DID != FDMI_DID) && - (wwn_to_u64(sp->portName.u.wwn) == 0 || - wwn_to_u64(sp->nodeName.u.wwn) == 0)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0142 PLOGI RSP: Invalid WWN.\n"); - goto out; - } - if (!lpfc_check_sparm(vport, ndlp, sp, CLASS3, 0)) - goto out; - /* PLOGI chkparm OK */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0121 PLOGI chkparm OK Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_state, - ndlp->nlp_flag, ndlp->nlp_rpi); - if (vport->cfg_fcp_class == 2 && (sp->cls2.classValid)) - ndlp->nlp_fcp_info |= CLASS2; - else - ndlp->nlp_fcp_info |= CLASS3; - - ndlp->nlp_class_sup = 0; - if (sp->cls1.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS1; - if (sp->cls2.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS2; - if (sp->cls3.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS3; - if (sp->cls4.classValid) - ndlp->nlp_class_sup |= FC_COS_CLASS4; - ndlp->nlp_maxframe = - ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0133 PLOGI: no memory for reg_login " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_state, - ndlp->nlp_flag, ndlp->nlp_rpi); - goto out; - } - - lpfc_unreg_rpi(vport, ndlp); - - if (lpfc_reg_rpi(phba, vport->vpi, irsp->un.elsreq64.remoteID, - (uint8_t *) sp, mbox, ndlp->nlp_rpi) == 0) { - switch (ndlp->nlp_DID) { - case NameServer_DID: - mbox->mbox_cmpl = lpfc_mbx_cmpl_ns_reg_login; - break; - case FDMI_DID: - mbox->mbox_cmpl = lpfc_mbx_cmpl_fdmi_reg_login; - break; - default: - ndlp->nlp_flag |= NLP_REG_LOGIN_SEND; - mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; - } - mbox->context2 = lpfc_nlp_get(ndlp); - mbox->vport = vport; - if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) - != MBX_NOT_FINISHED) { - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_REG_LOGIN_ISSUE); - return ndlp->nlp_state; - } - if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) - ndlp->nlp_flag &= ~NLP_REG_LOGIN_SEND; - /* decrement node reference count to the failed mbox - * command - */ - lpfc_nlp_put(ndlp); - mp = (struct lpfc_dmabuf *) mbox->context1; - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(mbox, phba->mbox_mem_pool); - - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0134 PLOGI: cannot issue reg_login " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_state, - ndlp->nlp_flag, ndlp->nlp_rpi); - } else { - mempool_free(mbox, phba->mbox_mem_pool); - - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0135 PLOGI: cannot format reg_login " - "Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_state, - ndlp->nlp_flag, ndlp->nlp_rpi); - } - - -out: - if (ndlp->nlp_DID == NameServer_DID) { - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0261 Cannot Register NameServer login\n"); - } - - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DEFER_RM; - spin_unlock_irq(shost->host_lock); - return NLP_STE_FREED_NODE; -} - -static uint32_t -lpfc_cmpl_logo_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_reglogin_plogi_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, void *arg, uint32_t evt) -{ - struct lpfc_hba *phba; - LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; - MAILBOX_t *mb = &pmb->u.mb; - uint16_t rpi; - - phba = vport->phba; - /* Release the RPI */ - if (!(phba->pport->load_flag & FC_UNLOADING) && - !mb->mbxStatus) { - rpi = pmb->u.mb.un.varWords[0]; - lpfc_release_rpi(phba, vport, rpi); - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_device_rm_plogi_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); - return ndlp->nlp_state; - } else { - /* software abort outstanding PLOGI */ - lpfc_els_abort(vport->phba, ndlp); - - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; - } -} - -static uint32_t -lpfc_device_recov_plogi_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - - /* Don't do anything that will mess up processing of the - * previous RSCN. - */ - if (vport->fc_flag & FC_RSCN_DEFERRED) - return ndlp->nlp_state; - - /* software abort outstanding PLOGI */ - lpfc_els_abort(phba, ndlp); - - ndlp->nlp_prev_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_plogi_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb; - - /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp); - - cmdiocb = (struct lpfc_iocbq *) arg; - - if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; - spin_unlock_irq(shost->host_lock); - if (vport->num_disc_nodes) - lpfc_more_adisc(vport); - } - return ndlp->nlp_state; - } - ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prli_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_logo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb; - - cmdiocb = (struct lpfc_iocbq *) arg; - - /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp); - - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_padisc_adisc_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb; - - cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_padisc(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prlo_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb; - - cmdiocb = (struct lpfc_iocbq *) arg; - - /* Treat like rcv logo */ - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_adisc_adisc_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb, *rspiocb; - IOCB_t *irsp; - ADISC *ap; - int rc; - - cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; - - ap = (ADISC *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb); - irsp = &rspiocb->iocb; - - if ((irsp->ulpStatus) || - (!lpfc_check_adisc(vport, ndlp, &ap->nodeName, &ap->portName))) { - /* 1 sec timeout */ - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - - memset(&ndlp->nlp_nodename, 0, sizeof(struct lpfc_name)); - memset(&ndlp->nlp_portname, 0, sizeof(struct lpfc_name)); - - ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - lpfc_unreg_rpi(vport, ndlp); - return ndlp->nlp_state; - } - - if (phba->sli_rev == LPFC_SLI_REV4) { - rc = lpfc_sli4_resume_rpi(ndlp, NULL, NULL); - if (rc) { - /* Stay in state and retry. */ - ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - return ndlp->nlp_state; - } - } - - if (ndlp->nlp_type & NLP_FCP_TARGET) { - ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); - } else { - ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - } - - return ndlp->nlp_state; -} - -static uint32_t -lpfc_device_rm_adisc_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); - return ndlp->nlp_state; - } else { - /* software abort outstanding ADISC */ - lpfc_els_abort(vport->phba, ndlp); - - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; - } -} - -static uint32_t -lpfc_device_recov_adisc_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - - /* Don't do anything that will mess up processing of the - * previous RSCN. - */ - if (vport->fc_flag & FC_RSCN_DEFERRED) - return ndlp->nlp_state; - - /* software abort outstanding ADISC */ - lpfc_els_abort(phba, ndlp); - - ndlp->nlp_prev_state = NLP_STE_ADISC_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - lpfc_disc_set_adisc(vport, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_plogi_reglogin_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_plogi(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prli_reglogin_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_logo_reglogin_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - LPFC_MBOXQ_t *mb; - LPFC_MBOXQ_t *nextmb; - struct lpfc_dmabuf *mp; - - cmdiocb = (struct lpfc_iocbq *) arg; - - /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ - if ((mb = phba->sli.mbox_active)) { - if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && - (ndlp == (struct lpfc_nodelist *) mb->context2)) { - lpfc_nlp_put(ndlp); - mb->context2 = NULL; - mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - } - } - - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { - if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) && - (ndlp == (struct lpfc_nodelist *) mb->context2)) { - mp = (struct lpfc_dmabuf *) (mb->context1); - if (mp) { - __lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - lpfc_nlp_put(ndlp); - list_del(&mb->list); - phba->sli.mboxq_cnt--; - mempool_free(mb, phba->mbox_mem_pool); - } - } - spin_unlock_irq(&phba->hbalock); - - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_padisc_reglogin_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_padisc(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prlo_reglogin_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb; - - cmdiocb = (struct lpfc_iocbq *) arg; - lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_reglogin_reglogin_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; - MAILBOX_t *mb = &pmb->u.mb; - uint32_t did = mb->un.varWords[1]; - - if (mb->mbxStatus) { - /* RegLogin failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_DISCOVERY, - "0246 RegLogin failed Data: x%x x%x x%x x%x " - "x%x\n", - did, mb->mbxStatus, vport->port_state, - mb->un.varRegLogin.vpi, - mb->un.varRegLogin.rpi); - /* - * If RegLogin failed due to lack of HBA resources do not - * retry discovery. - */ - if (mb->mbxStatus == MBXERR_RPI_FULL) { - ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - return ndlp->nlp_state; - } - - /* Put ndlp in npr state set plogi timer for 1 sec */ - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - - lpfc_issue_els_logo(vport, ndlp, 0); - ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - return ndlp->nlp_state; - } - - /* SLI4 ports have preallocated logical rpis. */ - if (vport->phba->sli_rev < LPFC_SLI_REV4) - ndlp->nlp_rpi = mb->un.varWords[0]; - - ndlp->nlp_flag |= NLP_RPI_REGISTERED; - - /* Only if we are not a fabric nport do we issue PRLI */ - if (!(ndlp->nlp_type & NLP_FABRIC)) { - ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PRLI_ISSUE); - lpfc_issue_els_prli(vport, ndlp, 0); - } else { - ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_device_rm_reglogin_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); - return ndlp->nlp_state; - } else { - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; - } -} - -static uint32_t -lpfc_device_recov_reglogin_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - /* Don't do anything that will mess up processing of the - * previous RSCN. - */ - if (vport->fc_flag & FC_RSCN_DEFERRED) - return ndlp->nlp_state; - - ndlp->nlp_prev_state = NLP_STE_REG_LOGIN_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_IGNR_REG_CMPL; - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - lpfc_disc_set_adisc(vport, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_plogi_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb; - - cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_plogi(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_logo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - /* Software abort outstanding PRLI before sending acc */ - lpfc_els_abort(vport->phba, ndlp); - - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_padisc_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_padisc(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -/* This routine is envoked when we rcv a PRLO request from a nport - * we are logged into. We should send back a PRLO rsp setting the - * appropriate bits. - * NEXT STATE = PRLI_ISSUE - */ -static uint32_t -lpfc_rcv_prlo_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_iocbq *cmdiocb, *rspiocb; - struct lpfc_hba *phba = vport->phba; - IOCB_t *irsp; - PRLI *npr; - - cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; - npr = (PRLI *)lpfc_check_elscmpl_iocb(phba, cmdiocb, rspiocb); - - irsp = &rspiocb->iocb; - if (irsp->ulpStatus) { - if ((vport->port_type == LPFC_NPIV_PORT) && - vport->cfg_restrict_login) { - goto out; - } - ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - return ndlp->nlp_state; - } - - /* Check out PRLI rsp */ - ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) && - (npr->prliType == PRLI_FCP_TYPE)) { - if (npr->initiatorFunc) - ndlp->nlp_type |= NLP_FCP_INITIATOR; - if (npr->targetFunc) - ndlp->nlp_type |= NLP_FCP_TARGET; - if (npr->Retry) - ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; - } - if (!(ndlp->nlp_type & NLP_FCP_TARGET) && - (vport->port_type == LPFC_NPIV_PORT) && - vport->cfg_restrict_login) { -out: - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_TARGET_REMOVE; - spin_unlock_irq(shost->host_lock); - lpfc_issue_els_logo(vport, ndlp, 0); - - ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - return ndlp->nlp_state; - } - - ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - if (ndlp->nlp_type & NLP_FCP_TARGET) - lpfc_nlp_set_state(vport, ndlp, NLP_STE_MAPPED_NODE); - else - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - return ndlp->nlp_state; -} - -/*! lpfc_device_rm_prli_issue - * - * \pre - * \post - * \param phba - * \param ndlp - * \param arg - * \param evt - * \return uint32_t - * - * \b Description: - * This routine is envoked when we a request to remove a nport we are in the - * process of PRLIing. We should software abort outstanding prli, unreg - * login, send a logout. We will change node state to UNUSED_NODE, put it - * on plogi list so it can be freed when LOGO completes. - * - */ - -static uint32_t -lpfc_device_rm_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); - return ndlp->nlp_state; - } else { - /* software abort outstanding PLOGI */ - lpfc_els_abort(vport->phba, ndlp); - - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; - } -} - - -/*! lpfc_device_recov_prli_issue - * - * \pre - * \post - * \param phba - * \param ndlp - * \param arg - * \param evt - * \return uint32_t - * - * \b Description: - * The routine is envoked when the state of a device is unknown, like - * during a link down. We should remove the nodelist entry from the - * unmapped list, issue a UNREG_LOGIN, do a software abort of the - * outstanding PRLI command, then free the node entry. - */ -static uint32_t -lpfc_device_recov_prli_issue(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; - - /* Don't do anything that will mess up processing of the - * previous RSCN. - */ - if (vport->fc_flag & FC_RSCN_DEFERRED) - return ndlp->nlp_state; - - /* software abort outstanding PRLI */ - lpfc_els_abort(phba, ndlp); - - ndlp->nlp_prev_state = NLP_STE_PRLI_ISSUE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - lpfc_disc_set_adisc(vport, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_plogi_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_plogi(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prli_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_prli(vport, ndlp, cmdiocb); - lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_logo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_padisc_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_padisc(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prlo_unmap_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_els_rsp_acc(vport, ELS_CMD_PRLO, cmdiocb, ndlp, NULL); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_device_recov_unmap_node(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - ndlp->nlp_prev_state = NLP_STE_UNMAPPED_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - lpfc_disc_set_adisc(vport, ndlp); - - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_plogi_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_plogi(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prli_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_els_rsp_prli_acc(vport, cmdiocb, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_logo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_padisc_mapped_node(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_padisc(vport, ndlp, cmdiocb); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prlo_mapped_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - /* flush the target */ - lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], - ndlp->nlp_sid, 0, LPFC_CTX_TGT); - - /* Treat like rcv logo */ - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_PRLO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_device_recov_mapped_node(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, - uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - ndlp->nlp_prev_state = NLP_STE_MAPPED_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - lpfc_disc_set_adisc(vport, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - /* Ignore PLOGI if we have an outstanding LOGO */ - if (ndlp->nlp_flag & (NLP_LOGO_SND | NLP_LOGO_ACC)) - return ndlp->nlp_state; - if (lpfc_rcv_plogi(vport, ndlp, cmdiocb)) { - lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_NPR_ADISC | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - } else if (!(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { - /* send PLOGI immediately, move to PLOGI issue state */ - if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { - ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - } - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - struct ls_rjt stat; - - memset(&stat, 0, sizeof (struct ls_rjt)); - stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; - stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; - lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); - - if (!(ndlp->nlp_flag & NLP_DELAY_TMO)) { - if (ndlp->nlp_flag & NLP_NPR_ADISC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - spin_unlock_irq(shost->host_lock); - lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); - lpfc_issue_els_adisc(vport, ndlp, 0); - } else { - ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - } - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_logo(vport, ndlp, cmdiocb, ELS_CMD_LOGO); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_padisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - lpfc_rcv_padisc(vport, ndlp, cmdiocb); - /* - * Do not start discovery if discovery is about to start - * or discovery in progress for this node. Starting discovery - * here will affect the counting of discovery threads. - */ - if (!(ndlp->nlp_flag & NLP_DELAY_TMO) && - !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { - if (ndlp->nlp_flag & NLP_NPR_ADISC) { - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_ADISC_ISSUE); - lpfc_issue_els_adisc(vport, ndlp, 0); - } else { - ndlp->nlp_prev_state = NLP_STE_NPR_NODE; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, ndlp->nlp_DID, 0); - } - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_rcv_prlo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_iocbq *cmdiocb = (struct lpfc_iocbq *) arg; - - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_LOGO_ACC; - spin_unlock_irq(shost->host_lock); - - lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); - - if ((ndlp->nlp_flag & NLP_DELAY_TMO) == 0) { - mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ * 1); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_DELAY_TMO; - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - ndlp->nlp_last_elscmd = ELS_CMD_PLOGI; - } else { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_plogi_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb, *rspiocb; - IOCB_t *irsp; - - cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; - - irsp = &rspiocb->iocb; - if (irsp->ulpStatus) { - ndlp->nlp_flag |= NLP_DEFER_RM; - return NLP_STE_FREED_NODE; - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_prli_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb, *rspiocb; - IOCB_t *irsp; - - cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; - - irsp = &rspiocb->iocb; - if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_logo_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - if (ndlp->nlp_DID == Fabric_DID) { - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); - spin_unlock_irq(shost->host_lock); - } - lpfc_unreg_rpi(vport, ndlp); - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_adisc_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct lpfc_iocbq *cmdiocb, *rspiocb; - IOCB_t *irsp; - - cmdiocb = (struct lpfc_iocbq *) arg; - rspiocb = cmdiocb->context_un.rsp_iocb; - - irsp = &rspiocb->iocb; - if (irsp->ulpStatus && (ndlp->nlp_flag & NLP_NODEV_REMOVE)) { - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_cmpl_reglogin_npr_node(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - LPFC_MBOXQ_t *pmb = (LPFC_MBOXQ_t *) arg; - MAILBOX_t *mb = &pmb->u.mb; - - if (!mb->mbxStatus) { - /* SLI4 ports have preallocated logical rpis. */ - if (vport->phba->sli_rev < LPFC_SLI_REV4) - ndlp->nlp_rpi = mb->un.varWords[0]; - ndlp->nlp_flag |= NLP_RPI_REGISTERED; - } else { - if (ndlp->nlp_flag & NLP_NODEV_REMOVE) { - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; - } - } - return ndlp->nlp_state; -} - -static uint32_t -lpfc_device_rm_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if (ndlp->nlp_flag & NLP_NPR_2B_DISC) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag |= NLP_NODEV_REMOVE; - spin_unlock_irq(shost->host_lock); - return ndlp->nlp_state; - } - lpfc_drop_node(vport, ndlp); - return NLP_STE_FREED_NODE; -} - -static uint32_t -lpfc_device_recov_npr_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - /* Don't do anything that will mess up processing of the - * previous RSCN. - */ - if (vport->fc_flag & FC_RSCN_DEFERRED) - return ndlp->nlp_state; - - lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~(NLP_NODEV_REMOVE | NLP_NPR_2B_DISC); - spin_unlock_irq(shost->host_lock); - return ndlp->nlp_state; -} - - -/* This next section defines the NPort Discovery State Machine */ - -/* There are 4 different double linked lists nodelist entries can reside on. - * The plogi list and adisc list are used when Link Up discovery or RSCN - * processing is needed. Each list holds the nodes that we will send PLOGI - * or ADISC on. These lists will keep track of what nodes will be effected - * by an RSCN, or a Link Up (Typically, all nodes are effected on Link Up). - * The unmapped_list will contain all nodes that we have successfully logged - * into at the Fibre Channel level. The mapped_list will contain all nodes - * that are mapped FCP targets. - */ -/* - * The bind list is a list of undiscovered (potentially non-existent) nodes - * that we have saved binding information on. This information is used when - * nodes transition from the unmapped to the mapped list. - */ -/* For UNUSED_NODE state, the node has just been allocated . - * For PLOGI_ISSUE and REG_LOGIN_ISSUE, the node is on - * the PLOGI list. For REG_LOGIN_COMPL, the node is taken off the PLOGI list - * and put on the unmapped list. For ADISC processing, the node is taken off - * the ADISC list and placed on either the mapped or unmapped list (depending - * on its previous state). Once on the unmapped list, a PRLI is issued and the - * state changed to PRLI_ISSUE. When the PRLI completion occurs, the state is - * changed to UNMAPPED_NODE. If the completion indicates a mapped - * node, the node is taken off the unmapped list. The binding list is checked - * for a valid binding, or a binding is automatically assigned. If binding - * assignment is unsuccessful, the node is left on the unmapped list. If - * binding assignment is successful, the associated binding list entry (if - * any) is removed, and the node is placed on the mapped list. - */ -/* - * For a Link Down, all nodes on the ADISC, PLOGI, unmapped or mapped - * lists will receive a DEVICE_RECOVERY event. If the linkdown or devloss timers - * expire, all effected nodes will receive a DEVICE_RM event. - */ -/* - * For a Link Up or RSCN, all nodes will move from the mapped / unmapped lists - * to either the ADISC or PLOGI list. After a Nameserver query or ALPA loopmap - * check, additional nodes may be added or removed (via DEVICE_RM) to / from - * the PLOGI or ADISC lists. Once the PLOGI and ADISC lists are populated, - * we will first process the ADISC list. 32 entries are processed initially and - * ADISC is initited for each one. Completions / Events for each node are - * funnelled thru the state machine. As each node finishes ADISC processing, it - * starts ADISC for any nodes waiting for ADISC processing. If no nodes are - * waiting, and the ADISC list count is identically 0, then we are done. For - * Link Up discovery, since all nodes on the PLOGI list are UNREG_LOGIN'ed, we - * can issue a CLEAR_LA and reenable Link Events. Next we will process the PLOGI - * list. 32 entries are processed initially and PLOGI is initited for each one. - * Completions / Events for each node are funnelled thru the state machine. As - * each node finishes PLOGI processing, it starts PLOGI for any nodes waiting - * for PLOGI processing. If no nodes are waiting, and the PLOGI list count is - * indentically 0, then we are done. We have now completed discovery / RSCN - * handling. Upon completion, ALL nodes should be on either the mapped or - * unmapped lists. - */ - -static uint32_t (*lpfc_disc_action[NLP_STE_MAX_STATE * NLP_EVT_MAX_EVENT]) - (struct lpfc_vport *, struct lpfc_nodelist *, void *, uint32_t) = { - /* Action routine Event Current State */ - lpfc_rcv_plogi_unused_node, /* RCV_PLOGI UNUSED_NODE */ - lpfc_rcv_els_unused_node, /* RCV_PRLI */ - lpfc_rcv_logo_unused_node, /* RCV_LOGO */ - lpfc_rcv_els_unused_node, /* RCV_ADISC */ - lpfc_rcv_els_unused_node, /* RCV_PDISC */ - lpfc_rcv_els_unused_node, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ - lpfc_disc_illegal, /* CMPL_PRLI */ - lpfc_cmpl_logo_unused_node, /* CMPL_LOGO */ - lpfc_disc_illegal, /* CMPL_ADISC */ - lpfc_disc_illegal, /* CMPL_REG_LOGIN */ - lpfc_device_rm_unused_node, /* DEVICE_RM */ - lpfc_device_recov_unused_node, /* DEVICE_RECOVERY */ - - lpfc_rcv_plogi_plogi_issue, /* RCV_PLOGI PLOGI_ISSUE */ - lpfc_rcv_prli_plogi_issue, /* RCV_PRLI */ - lpfc_rcv_logo_plogi_issue, /* RCV_LOGO */ - lpfc_rcv_els_plogi_issue, /* RCV_ADISC */ - lpfc_rcv_els_plogi_issue, /* RCV_PDISC */ - lpfc_rcv_els_plogi_issue, /* RCV_PRLO */ - lpfc_cmpl_plogi_plogi_issue, /* CMPL_PLOGI */ - lpfc_disc_illegal, /* CMPL_PRLI */ - lpfc_cmpl_logo_plogi_issue, /* CMPL_LOGO */ - lpfc_disc_illegal, /* CMPL_ADISC */ - lpfc_cmpl_reglogin_plogi_issue,/* CMPL_REG_LOGIN */ - lpfc_device_rm_plogi_issue, /* DEVICE_RM */ - lpfc_device_recov_plogi_issue, /* DEVICE_RECOVERY */ - - lpfc_rcv_plogi_adisc_issue, /* RCV_PLOGI ADISC_ISSUE */ - lpfc_rcv_prli_adisc_issue, /* RCV_PRLI */ - lpfc_rcv_logo_adisc_issue, /* RCV_LOGO */ - lpfc_rcv_padisc_adisc_issue, /* RCV_ADISC */ - lpfc_rcv_padisc_adisc_issue, /* RCV_PDISC */ - lpfc_rcv_prlo_adisc_issue, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ - lpfc_disc_illegal, /* CMPL_PRLI */ - lpfc_disc_illegal, /* CMPL_LOGO */ - lpfc_cmpl_adisc_adisc_issue, /* CMPL_ADISC */ - lpfc_disc_illegal, /* CMPL_REG_LOGIN */ - lpfc_device_rm_adisc_issue, /* DEVICE_RM */ - lpfc_device_recov_adisc_issue, /* DEVICE_RECOVERY */ - - lpfc_rcv_plogi_reglogin_issue, /* RCV_PLOGI REG_LOGIN_ISSUE */ - lpfc_rcv_prli_reglogin_issue, /* RCV_PLOGI */ - lpfc_rcv_logo_reglogin_issue, /* RCV_LOGO */ - lpfc_rcv_padisc_reglogin_issue, /* RCV_ADISC */ - lpfc_rcv_padisc_reglogin_issue, /* RCV_PDISC */ - lpfc_rcv_prlo_reglogin_issue, /* RCV_PRLO */ - lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ - lpfc_disc_illegal, /* CMPL_PRLI */ - lpfc_disc_illegal, /* CMPL_LOGO */ - lpfc_disc_illegal, /* CMPL_ADISC */ - lpfc_cmpl_reglogin_reglogin_issue,/* CMPL_REG_LOGIN */ - lpfc_device_rm_reglogin_issue, /* DEVICE_RM */ - lpfc_device_recov_reglogin_issue,/* DEVICE_RECOVERY */ - - lpfc_rcv_plogi_prli_issue, /* RCV_PLOGI PRLI_ISSUE */ - lpfc_rcv_prli_prli_issue, /* RCV_PRLI */ - lpfc_rcv_logo_prli_issue, /* RCV_LOGO */ - lpfc_rcv_padisc_prli_issue, /* RCV_ADISC */ - lpfc_rcv_padisc_prli_issue, /* RCV_PDISC */ - lpfc_rcv_prlo_prli_issue, /* RCV_PRLO */ - lpfc_cmpl_plogi_illegal, /* CMPL_PLOGI */ - lpfc_cmpl_prli_prli_issue, /* CMPL_PRLI */ - lpfc_disc_illegal, /* CMPL_LOGO */ - lpfc_disc_illegal, /* CMPL_ADISC */ - lpfc_disc_illegal, /* CMPL_REG_LOGIN */ - lpfc_device_rm_prli_issue, /* DEVICE_RM */ - lpfc_device_recov_prli_issue, /* DEVICE_RECOVERY */ - - lpfc_rcv_plogi_unmap_node, /* RCV_PLOGI UNMAPPED_NODE */ - lpfc_rcv_prli_unmap_node, /* RCV_PRLI */ - lpfc_rcv_logo_unmap_node, /* RCV_LOGO */ - lpfc_rcv_padisc_unmap_node, /* RCV_ADISC */ - lpfc_rcv_padisc_unmap_node, /* RCV_PDISC */ - lpfc_rcv_prlo_unmap_node, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ - lpfc_disc_illegal, /* CMPL_PRLI */ - lpfc_disc_illegal, /* CMPL_LOGO */ - lpfc_disc_illegal, /* CMPL_ADISC */ - lpfc_disc_illegal, /* CMPL_REG_LOGIN */ - lpfc_disc_illegal, /* DEVICE_RM */ - lpfc_device_recov_unmap_node, /* DEVICE_RECOVERY */ - - lpfc_rcv_plogi_mapped_node, /* RCV_PLOGI MAPPED_NODE */ - lpfc_rcv_prli_mapped_node, /* RCV_PRLI */ - lpfc_rcv_logo_mapped_node, /* RCV_LOGO */ - lpfc_rcv_padisc_mapped_node, /* RCV_ADISC */ - lpfc_rcv_padisc_mapped_node, /* RCV_PDISC */ - lpfc_rcv_prlo_mapped_node, /* RCV_PRLO */ - lpfc_disc_illegal, /* CMPL_PLOGI */ - lpfc_disc_illegal, /* CMPL_PRLI */ - lpfc_disc_illegal, /* CMPL_LOGO */ - lpfc_disc_illegal, /* CMPL_ADISC */ - lpfc_disc_illegal, /* CMPL_REG_LOGIN */ - lpfc_disc_illegal, /* DEVICE_RM */ - lpfc_device_recov_mapped_node, /* DEVICE_RECOVERY */ - - lpfc_rcv_plogi_npr_node, /* RCV_PLOGI NPR_NODE */ - lpfc_rcv_prli_npr_node, /* RCV_PRLI */ - lpfc_rcv_logo_npr_node, /* RCV_LOGO */ - lpfc_rcv_padisc_npr_node, /* RCV_ADISC */ - lpfc_rcv_padisc_npr_node, /* RCV_PDISC */ - lpfc_rcv_prlo_npr_node, /* RCV_PRLO */ - lpfc_cmpl_plogi_npr_node, /* CMPL_PLOGI */ - lpfc_cmpl_prli_npr_node, /* CMPL_PRLI */ - lpfc_cmpl_logo_npr_node, /* CMPL_LOGO */ - lpfc_cmpl_adisc_npr_node, /* CMPL_ADISC */ - lpfc_cmpl_reglogin_npr_node, /* CMPL_REG_LOGIN */ - lpfc_device_rm_npr_node, /* DEVICE_RM */ - lpfc_device_recov_npr_node, /* DEVICE_RECOVERY */ -}; - -int -lpfc_disc_state_machine(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, - void *arg, uint32_t evt) -{ - uint32_t cur_state, rc; - uint32_t(*func) (struct lpfc_vport *, struct lpfc_nodelist *, void *, - uint32_t); - uint32_t got_ndlp = 0; - - if (lpfc_nlp_get(ndlp)) - got_ndlp = 1; - - cur_state = ndlp->nlp_state; - - /* DSM in event on NPort in state */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0211 DSM in event x%x on NPort x%x in " - "state %d Data: x%x\n", - evt, ndlp->nlp_DID, cur_state, ndlp->nlp_flag); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, - "DSM in: evt:%d ste:%d did:x%x", - evt, cur_state, ndlp->nlp_DID); - - func = lpfc_disc_action[(cur_state * NLP_EVT_MAX_EVENT) + evt]; - rc = (func) (vport, ndlp, arg, evt); - - /* DSM out state on NPort */ - if (got_ndlp) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0212 DSM out state %d on NPort x%x Data: x%x\n", - rc, ndlp->nlp_DID, ndlp->nlp_flag); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, - "DSM out: ste:%d did:x%x flg:x%x", - rc, ndlp->nlp_DID, ndlp->nlp_flag); - /* Decrement the ndlp reference count held for this function */ - lpfc_nlp_put(ndlp); - } else { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0213 DSM out state %d on NPort free\n", rc); - - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_DSM, - "DSM out: ste:%d did:x%x flg:x%x", - rc, 0, 0); - } - - return rc; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.c deleted file mode 100644 index 88f3a83d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.c +++ /dev/null @@ -1,5031 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "lpfc_version.h" -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc.h" -#include "lpfc_scsi.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_vport.h" - -#define LPFC_RESET_WAIT 2 -#define LPFC_ABORT_WAIT 2 - -int _dump_buf_done; - -static char *dif_op_str[] = { - "PROT_NORMAL", - "PROT_READ_INSERT", - "PROT_WRITE_STRIP", - "PROT_READ_STRIP", - "PROT_WRITE_INSERT", - "PROT_READ_PASS", - "PROT_WRITE_PASS", -}; - -static char *dif_grd_str[] = { - "NO_GUARD", - "DIF_CRC", - "DIX_IP", -}; - -struct scsi_dif_tuple { - __be16 guard_tag; /* Checksum */ - __be16 app_tag; /* Opaque storage */ - __be32 ref_tag; /* Target LBA or indirect LBA */ -}; - -static void -lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); -static void -lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb); - -static void -lpfc_debug_save_data(struct lpfc_hba *phba, struct scsi_cmnd *cmnd) -{ - void *src, *dst; - struct scatterlist *sgde = scsi_sglist(cmnd); - - if (!_dump_buf_data) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9050 BLKGRD: ERROR %s _dump_buf_data is NULL\n", - __func__); - return; - } - - - if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9051 BLKGRD: ERROR: data scatterlist is null\n"); - return; - } - - dst = (void *) _dump_buf_data; - while (sgde) { - src = sg_virt(sgde); - memcpy(dst, src, sgde->length); - dst += sgde->length; - sgde = sg_next(sgde); - } -} - -static void -lpfc_debug_save_dif(struct lpfc_hba *phba, struct scsi_cmnd *cmnd) -{ - void *src, *dst; - struct scatterlist *sgde = scsi_prot_sglist(cmnd); - - if (!_dump_buf_dif) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9052 BLKGRD: ERROR %s _dump_buf_data is NULL\n", - __func__); - return; - } - - if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9053 BLKGRD: ERROR: prot scatterlist is null\n"); - return; - } - - dst = _dump_buf_dif; - while (sgde) { - src = sg_virt(sgde); - memcpy(dst, src, sgde->length); - dst += sgde->length; - sgde = sg_next(sgde); - } -} - -/** - * lpfc_sli4_set_rsp_sgl_last - Set the last bit in the response sge. - * @phba: Pointer to HBA object. - * @lpfc_cmd: lpfc scsi command object pointer. - * - * This function is called from the lpfc_prep_task_mgmt_cmd function to - * set the last bit in the response sge entry. - **/ -static void -lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, - struct lpfc_scsi_buf *lpfc_cmd) -{ - struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; - if (sgl) { - sgl += 1; - sgl->word2 = le32_to_cpu(sgl->word2); - bf_set(lpfc_sli4_sge_last, sgl, 1); - sgl->word2 = cpu_to_le32(sgl->word2); - } -} - -/** - * lpfc_update_stats - Update statistical data for the command completion - * @phba: Pointer to HBA object. - * @lpfc_cmd: lpfc scsi command object pointer. - * - * This function is called when there is a command completion and this - * function updates the statistical data for the command completion. - **/ -static void -lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) -{ - struct lpfc_rport_data *rdata = lpfc_cmd->rdata; - struct lpfc_nodelist *pnode = rdata->pnode; - struct scsi_cmnd *cmd = lpfc_cmd->pCmd; - unsigned long flags; - struct Scsi_Host *shost = cmd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - unsigned long latency; - int i; - - if (cmd->result) - return; - - latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time); - - spin_lock_irqsave(shost->host_lock, flags); - if (!vport->stat_data_enabled || - vport->stat_data_blocked || - !pnode || - !pnode->lat_data || - (phba->bucket_type == LPFC_NO_BUCKET)) { - spin_unlock_irqrestore(shost->host_lock, flags); - return; - } - - if (phba->bucket_type == LPFC_LINEAR_BUCKET) { - i = (latency + phba->bucket_step - 1 - phba->bucket_base)/ - phba->bucket_step; - /* check array subscript bounds */ - if (i < 0) - i = 0; - else if (i >= LPFC_MAX_BUCKET_COUNT) - i = LPFC_MAX_BUCKET_COUNT - 1; - } else { - for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++) - if (latency <= (phba->bucket_base + - ((1<bucket_step))) - break; - } - - pnode->lat_data[i].cmd_count++; - spin_unlock_irqrestore(shost->host_lock, flags); -} - -/** - * lpfc_send_sdev_queuedepth_change_event - Posts a queuedepth change event - * @phba: Pointer to HBA context object. - * @vport: Pointer to vport object. - * @ndlp: Pointer to FC node associated with the target. - * @lun: Lun number of the scsi device. - * @old_val: Old value of the queue depth. - * @new_val: New value of the queue depth. - * - * This function sends an event to the mgmt application indicating - * there is a change in the scsi device queue depth. - **/ -static void -lpfc_send_sdev_queuedepth_change_event(struct lpfc_hba *phba, - struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp, - uint32_t lun, - uint32_t old_val, - uint32_t new_val) -{ - struct lpfc_fast_path_event *fast_path_evt; - unsigned long flags; - - fast_path_evt = lpfc_alloc_fast_evt(phba); - if (!fast_path_evt) - return; - - fast_path_evt->un.queue_depth_evt.scsi_event.event_type = - FC_REG_SCSI_EVENT; - fast_path_evt->un.queue_depth_evt.scsi_event.subcategory = - LPFC_EVENT_VARQUEDEPTH; - - /* Report all luns with change in queue depth */ - fast_path_evt->un.queue_depth_evt.scsi_event.lun = lun; - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { - memcpy(&fast_path_evt->un.queue_depth_evt.scsi_event.wwpn, - &ndlp->nlp_portname, sizeof(struct lpfc_name)); - memcpy(&fast_path_evt->un.queue_depth_evt.scsi_event.wwnn, - &ndlp->nlp_nodename, sizeof(struct lpfc_name)); - } - - fast_path_evt->un.queue_depth_evt.oldval = old_val; - fast_path_evt->un.queue_depth_evt.newval = new_val; - fast_path_evt->vport = vport; - - fast_path_evt->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT; - spin_lock_irqsave(&phba->hbalock, flags); - list_add_tail(&fast_path_evt->work_evt.evt_listp, &phba->work_list); - spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_worker_wake_up(phba); - - return; -} - -/** - * lpfc_change_queue_depth - Alter scsi device queue depth - * @sdev: Pointer the scsi device on which to change the queue depth. - * @qdepth: New queue depth to set the sdev to. - * @reason: The reason for the queue depth change. - * - * This function is called by the midlayer and the LLD to alter the queue - * depth for a scsi device. This function sets the queue depth to the new - * value and sends an event out to log the queue depth change. - **/ -int -lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_rport_data *rdata; - unsigned long new_queue_depth, old_queue_depth; - - old_queue_depth = sdev->queue_depth; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); - new_queue_depth = sdev->queue_depth; - rdata = sdev->hostdata; - if (rdata) - lpfc_send_sdev_queuedepth_change_event(phba, vport, - rdata->pnode, sdev->lun, - old_queue_depth, - new_queue_depth); - return sdev->queue_depth; -} - -/** - * lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread - * @phba: The Hba for which this call is being executed. - * - * This routine is called when there is resource error in driver or firmware. - * This routine posts WORKER_RAMP_DOWN_QUEUE event for @phba. This routine - * posts at most 1 event each second. This routine wakes up worker thread of - * @phba to process WORKER_RAM_DOWN_EVENT event. - * - * This routine should be called with no lock held. - **/ -void -lpfc_rampdown_queue_depth(struct lpfc_hba *phba) -{ - unsigned long flags; - uint32_t evt_posted; - - spin_lock_irqsave(&phba->hbalock, flags); - atomic_inc(&phba->num_rsrc_err); - phba->last_rsrc_error_time = jiffies; - - if ((phba->last_ramp_down_time + QUEUE_RAMP_DOWN_INTERVAL) > jiffies) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return; - } - - phba->last_ramp_down_time = jiffies; - - spin_unlock_irqrestore(&phba->hbalock, flags); - - spin_lock_irqsave(&phba->pport->work_port_lock, flags); - evt_posted = phba->pport->work_port_events & WORKER_RAMP_DOWN_QUEUE; - if (!evt_posted) - phba->pport->work_port_events |= WORKER_RAMP_DOWN_QUEUE; - spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); - - if (!evt_posted) - lpfc_worker_wake_up(phba); - return; -} - -/** - * lpfc_rampup_queue_depth - Post RAMP_UP_QUEUE event for worker thread - * @phba: The Hba for which this call is being executed. - * - * This routine post WORKER_RAMP_UP_QUEUE event for @phba vport. This routine - * post at most 1 event every 5 minute after last_ramp_up_time or - * last_rsrc_error_time. This routine wakes up worker thread of @phba - * to process WORKER_RAM_DOWN_EVENT event. - * - * This routine should be called with no lock held. - **/ -static inline void -lpfc_rampup_queue_depth(struct lpfc_vport *vport, - uint32_t queue_depth) -{ - unsigned long flags; - struct lpfc_hba *phba = vport->phba; - uint32_t evt_posted; - atomic_inc(&phba->num_cmd_success); - - if (vport->cfg_lun_queue_depth <= queue_depth) - return; - spin_lock_irqsave(&phba->hbalock, flags); - if (time_before(jiffies, - phba->last_ramp_up_time + QUEUE_RAMP_UP_INTERVAL) || - time_before(jiffies, - phba->last_rsrc_error_time + QUEUE_RAMP_UP_INTERVAL)) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return; - } - phba->last_ramp_up_time = jiffies; - spin_unlock_irqrestore(&phba->hbalock, flags); - - spin_lock_irqsave(&phba->pport->work_port_lock, flags); - evt_posted = phba->pport->work_port_events & WORKER_RAMP_UP_QUEUE; - if (!evt_posted) - phba->pport->work_port_events |= WORKER_RAMP_UP_QUEUE; - spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); - - if (!evt_posted) - lpfc_worker_wake_up(phba); - return; -} - -/** - * lpfc_ramp_down_queue_handler - WORKER_RAMP_DOWN_QUEUE event handler - * @phba: The Hba for which this call is being executed. - * - * This routine is called to process WORKER_RAMP_DOWN_QUEUE event for worker - * thread.This routine reduces queue depth for all scsi device on each vport - * associated with @phba. - **/ -void -lpfc_ramp_down_queue_handler(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - struct Scsi_Host *shost; - struct scsi_device *sdev; - unsigned long new_queue_depth; - unsigned long num_rsrc_err, num_cmd_success; - int i; - - num_rsrc_err = atomic_read(&phba->num_rsrc_err); - num_cmd_success = atomic_read(&phba->num_cmd_success); - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - shost_for_each_device(sdev, shost) { - new_queue_depth = - sdev->queue_depth * num_rsrc_err / - (num_rsrc_err + num_cmd_success); - if (!new_queue_depth) - new_queue_depth = sdev->queue_depth - 1; - else - new_queue_depth = sdev->queue_depth - - new_queue_depth; - lpfc_change_queue_depth(sdev, new_queue_depth, - SCSI_QDEPTH_DEFAULT); - } - } - lpfc_destroy_vport_work_array(phba, vports); - atomic_set(&phba->num_rsrc_err, 0); - atomic_set(&phba->num_cmd_success, 0); -} - -/** - * lpfc_ramp_up_queue_handler - WORKER_RAMP_UP_QUEUE event handler - * @phba: The Hba for which this call is being executed. - * - * This routine is called to process WORKER_RAMP_UP_QUEUE event for worker - * thread.This routine increases queue depth for all scsi device on each vport - * associated with @phba by 1. This routine also sets @phba num_rsrc_err and - * num_cmd_success to zero. - **/ -void -lpfc_ramp_up_queue_handler(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - struct Scsi_Host *shost; - struct scsi_device *sdev; - int i; - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - shost_for_each_device(sdev, shost) { - if (vports[i]->cfg_lun_queue_depth <= - sdev->queue_depth) - continue; - lpfc_change_queue_depth(sdev, - sdev->queue_depth+1, - SCSI_QDEPTH_RAMP_UP); - } - } - lpfc_destroy_vport_work_array(phba, vports); - atomic_set(&phba->num_rsrc_err, 0); - atomic_set(&phba->num_cmd_success, 0); -} - -/** - * lpfc_scsi_dev_block - set all scsi hosts to block state - * @phba: Pointer to HBA context object. - * - * This function walks vport list and set each SCSI host to block state - * by invoking fc_remote_port_delete() routine. This function is invoked - * with EEH when device's PCI slot has been permanently disabled. - **/ -void -lpfc_scsi_dev_block(struct lpfc_hba *phba) -{ - struct lpfc_vport **vports; - struct Scsi_Host *shost; - struct scsi_device *sdev; - struct fc_rport *rport; - int i; - - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { - shost = lpfc_shost_from_vport(vports[i]); - shost_for_each_device(sdev, shost) { - rport = starget_to_rport(scsi_target(sdev)); - fc_remote_port_delete(rport); - } - } - lpfc_destroy_vport_work_array(phba, vports); -} - -/** - * lpfc_new_scsi_buf_s3 - Scsi buffer allocator for HBA with SLI3 IF spec - * @vport: The virtual port for which this call being executed. - * @num_to_allocate: The requested number of buffers to allocate. - * - * This routine allocates a scsi buffer for device with SLI-3 interface spec, - * the scsi buffer contains all the necessary information needed to initiate - * a SCSI I/O. The non-DMAable buffer region contains information to build - * the IOCB. The DMAable region contains memory for the FCP CMND, FCP RSP, - * and the initial BPL. In addition to allocating memory, the FCP CMND and - * FCP RSP BDEs are setup in the BPL and the BPL BDE is setup in the IOCB. - * - * Return codes: - * int - number of scsi buffers that were allocated. - * 0 = failure, less than num_to_alloc is a partial failure. - **/ -static int -lpfc_new_scsi_buf_s3(struct lpfc_vport *vport, int num_to_alloc) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_scsi_buf *psb; - struct ulp_bde64 *bpl; - IOCB_t *iocb; - dma_addr_t pdma_phys_fcp_cmd; - dma_addr_t pdma_phys_fcp_rsp; - dma_addr_t pdma_phys_bpl; - uint16_t iotag; - int bcnt; - - for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { - psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); - if (!psb) - break; - - /* - * Get memory from the pci pool to map the virt space to pci - * bus space for an I/O. The DMA buffer includes space for the - * struct fcp_cmnd, struct fcp_rsp and the number of bde's - * necessary to support the sg_tablesize. - */ - psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, - GFP_KERNEL, &psb->dma_handle); - if (!psb->data) { - kfree(psb); - break; - } - - /* Initialize virtual ptrs to dma_buf region. */ - memset(psb->data, 0, phba->cfg_sg_dma_buf_size); - - /* Allocate iotag for psb->cur_iocbq. */ - iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); - if (iotag == 0) { - pci_pool_free(phba->lpfc_scsi_dma_buf_pool, - psb->data, psb->dma_handle); - kfree(psb); - break; - } - psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; - - psb->fcp_cmnd = psb->data; - psb->fcp_rsp = psb->data + sizeof(struct fcp_cmnd); - psb->fcp_bpl = psb->data + sizeof(struct fcp_cmnd) + - sizeof(struct fcp_rsp); - - /* Initialize local short-hand pointers. */ - bpl = psb->fcp_bpl; - pdma_phys_fcp_cmd = psb->dma_handle; - pdma_phys_fcp_rsp = psb->dma_handle + sizeof(struct fcp_cmnd); - pdma_phys_bpl = psb->dma_handle + sizeof(struct fcp_cmnd) + - sizeof(struct fcp_rsp); - - /* - * The first two bdes are the FCP_CMD and FCP_RSP. The balance - * are sg list bdes. Initialize the first two and leave the - * rest for queuecommand. - */ - bpl[0].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_cmd)); - bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd)); - bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd); - bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w); - - /* Setup the physical region for the FCP RSP */ - bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp)); - bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp)); - bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp); - bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w); - - /* - * Since the IOCB for the FCP I/O is built into this - * lpfc_scsi_buf, initialize it with all known data now. - */ - iocb = &psb->cur_iocbq.iocb; - iocb->un.fcpi64.bdl.ulpIoTag32 = 0; - if ((phba->sli_rev == 3) && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) { - /* fill in immediate fcp command BDE */ - iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_IMMED; - iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); - iocb->un.fcpi64.bdl.addrLow = offsetof(IOCB_t, - unsli3.fcp_ext.icd); - iocb->un.fcpi64.bdl.addrHigh = 0; - iocb->ulpBdeCount = 0; - iocb->ulpLe = 0; - /* fill in response BDE */ - iocb->unsli3.fcp_ext.rbde.tus.f.bdeFlags = - BUFF_TYPE_BDE_64; - iocb->unsli3.fcp_ext.rbde.tus.f.bdeSize = - sizeof(struct fcp_rsp); - iocb->unsli3.fcp_ext.rbde.addrLow = - putPaddrLow(pdma_phys_fcp_rsp); - iocb->unsli3.fcp_ext.rbde.addrHigh = - putPaddrHigh(pdma_phys_fcp_rsp); - } else { - iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BLP_64; - iocb->un.fcpi64.bdl.bdeSize = - (2 * sizeof(struct ulp_bde64)); - iocb->un.fcpi64.bdl.addrLow = - putPaddrLow(pdma_phys_bpl); - iocb->un.fcpi64.bdl.addrHigh = - putPaddrHigh(pdma_phys_bpl); - iocb->ulpBdeCount = 1; - iocb->ulpLe = 1; - } - iocb->ulpClass = CLASS3; - psb->status = IOSTAT_SUCCESS; - /* Put it back into the SCSI buffer list */ - psb->cur_iocbq.context1 = psb; - lpfc_release_scsi_buf_s3(phba, psb); - - } - - return bcnt; -} - -/** - * lpfc_sli4_vport_delete_fcp_xri_aborted -Remove all ndlp references for vport - * @vport: pointer to lpfc vport data structure. - * - * This routine is invoked by the vport cleanup for deletions and the cleanup - * for an ndlp on removal. - **/ -void -lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_scsi_buf *psb, *next_psb; - unsigned long iflag = 0; - - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock); - list_for_each_entry_safe(psb, next_psb, - &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { - if (psb->rdata && psb->rdata->pnode - && psb->rdata->pnode->vport == vport) - psb->rdata = NULL; - } - spin_unlock(&phba->sli4_hba.abts_scsi_buf_list_lock); - spin_unlock_irqrestore(&phba->hbalock, iflag); -} - -/** - * lpfc_sli4_fcp_xri_aborted - Fast-path process of fcp xri abort - * @phba: pointer to lpfc hba data structure. - * @axri: pointer to the fcp xri abort wcqe structure. - * - * This routine is invoked by the worker thread to process a SLI4 fast-path - * FCP aborted xri. - **/ -void -lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *phba, - struct sli4_wcqe_xri_aborted *axri) -{ - uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); - uint16_t rxid = bf_get(lpfc_wcqe_xa_remote_xid, axri); - struct lpfc_scsi_buf *psb, *next_psb; - unsigned long iflag = 0; - struct lpfc_iocbq *iocbq; - int i; - struct lpfc_nodelist *ndlp; - int rrq_empty = 0; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - - spin_lock_irqsave(&phba->hbalock, iflag); - spin_lock(&phba->sli4_hba.abts_scsi_buf_list_lock); - list_for_each_entry_safe(psb, next_psb, - &phba->sli4_hba.lpfc_abts_scsi_buf_list, list) { - if (psb->cur_iocbq.sli4_xritag == xri) { - list_del(&psb->list); - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - spin_unlock( - &phba->sli4_hba.abts_scsi_buf_list_lock); - if (psb->rdata && psb->rdata->pnode) - ndlp = psb->rdata->pnode; - else - ndlp = NULL; - - rrq_empty = list_empty(&phba->active_rrq_list); - spin_unlock_irqrestore(&phba->hbalock, iflag); - if (ndlp) { - lpfc_set_rrq_active(phba, ndlp, xri, rxid, 1); - lpfc_sli4_abts_err_handler(phba, ndlp, axri); - } - lpfc_release_scsi_buf_s4(phba, psb); - if (rrq_empty) - lpfc_worker_wake_up(phba); - return; - } - } - spin_unlock(&phba->sli4_hba.abts_scsi_buf_list_lock); - for (i = 1; i <= phba->sli.last_iotag; i++) { - iocbq = phba->sli.iocbq_lookup[i]; - - if (!(iocbq->iocb_flag & LPFC_IO_FCP) || - (iocbq->iocb_flag & LPFC_IO_LIBDFC)) - continue; - if (iocbq->sli4_xritag != xri) - continue; - psb = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); - psb->exch_busy = 0; - spin_unlock_irqrestore(&phba->hbalock, iflag); - if (pring->txq_cnt) - lpfc_worker_wake_up(phba); - return; - - } - spin_unlock_irqrestore(&phba->hbalock, iflag); -} - -/** - * lpfc_sli4_repost_scsi_sgl_list - Repsot the Scsi buffers sgl pages as block - * @phba: pointer to lpfc hba data structure. - * - * This routine walks the list of scsi buffers that have been allocated and - * repost them to the HBA by using SGL block post. This is needed after a - * pci_function_reset/warm_start or start. The lpfc_hba_down_post_s4 routine - * is responsible for moving all scsi buffers on the lpfc_abts_scsi_sgl_list - * to the lpfc_scsi_buf_list. If the repost fails, reject all scsi buffers. - * - * Returns: 0 = success, non-zero failure. - **/ -int -lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *phba) -{ - struct lpfc_scsi_buf *psb; - int index, status, bcnt = 0, rcnt = 0, rc = 0; - LIST_HEAD(sblist); - - for (index = 0; index < phba->sli4_hba.scsi_xri_cnt; index++) { - psb = phba->sli4_hba.lpfc_scsi_psb_array[index]; - if (psb) { - /* Remove from SCSI buffer list */ - list_del(&psb->list); - /* Add it to a local SCSI buffer list */ - list_add_tail(&psb->list, &sblist); - if (++rcnt == LPFC_NEMBED_MBOX_SGL_CNT) { - bcnt = rcnt; - rcnt = 0; - } - } else - /* A hole present in the XRI array, need to skip */ - bcnt = rcnt; - - if (index == phba->sli4_hba.scsi_xri_cnt - 1) - /* End of XRI array for SCSI buffer, complete */ - bcnt = rcnt; - - /* Continue until collect up to a nembed page worth of sgls */ - if (bcnt == 0) - continue; - /* Now, post the SCSI buffer list sgls as a block */ - if (!phba->sli4_hba.extents_in_use) - status = lpfc_sli4_post_scsi_sgl_block(phba, - &sblist, - bcnt); - else - status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, - &sblist, - bcnt); - /* Reset SCSI buffer count for next round of posting */ - bcnt = 0; - while (!list_empty(&sblist)) { - list_remove_head(&sblist, psb, struct lpfc_scsi_buf, - list); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - rc++; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - } - } - return rc; -} - -/** - * lpfc_new_scsi_buf_s4 - Scsi buffer allocator for HBA with SLI4 IF spec - * @vport: The virtual port for which this call being executed. - * @num_to_allocate: The requested number of buffers to allocate. - * - * This routine allocates a scsi buffer for device with SLI-4 interface spec, - * the scsi buffer contains all the necessary information needed to initiate - * a SCSI I/O. - * - * Return codes: - * int - number of scsi buffers that were allocated. - * 0 = failure, less than num_to_alloc is a partial failure. - **/ -static int -lpfc_new_scsi_buf_s4(struct lpfc_vport *vport, int num_to_alloc) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_scsi_buf *psb; - struct sli4_sge *sgl; - IOCB_t *iocb; - dma_addr_t pdma_phys_fcp_cmd; - dma_addr_t pdma_phys_fcp_rsp; - dma_addr_t pdma_phys_bpl, pdma_phys_bpl1; - uint16_t iotag, last_xritag = NO_XRI, lxri = 0; - int status = 0, index; - int bcnt; - int non_sequential_xri = 0; - LIST_HEAD(sblist); - - for (bcnt = 0; bcnt < num_to_alloc; bcnt++) { - psb = kzalloc(sizeof(struct lpfc_scsi_buf), GFP_KERNEL); - if (!psb) - break; - - /* - * Get memory from the pci pool to map the virt space to pci bus - * space for an I/O. The DMA buffer includes space for the - * struct fcp_cmnd, struct fcp_rsp and the number of bde's - * necessary to support the sg_tablesize. - */ - psb->data = pci_pool_alloc(phba->lpfc_scsi_dma_buf_pool, - GFP_KERNEL, &psb->dma_handle); - if (!psb->data) { - kfree(psb); - break; - } - - /* Initialize virtual ptrs to dma_buf region. */ - memset(psb->data, 0, phba->cfg_sg_dma_buf_size); - - /* Allocate iotag for psb->cur_iocbq. */ - iotag = lpfc_sli_next_iotag(phba, &psb->cur_iocbq); - if (iotag == 0) { - pci_pool_free(phba->lpfc_scsi_dma_buf_pool, - psb->data, psb->dma_handle); - kfree(psb); - break; - } - - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - pci_pool_free(phba->lpfc_scsi_dma_buf_pool, - psb->data, psb->dma_handle); - kfree(psb); - break; - } - psb->cur_iocbq.sli4_lxritag = lxri; - psb->cur_iocbq.sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - if (last_xritag != NO_XRI - && psb->cur_iocbq.sli4_xritag != (last_xritag+1)) { - non_sequential_xri = 1; - } else - list_add_tail(&psb->list, &sblist); - last_xritag = psb->cur_iocbq.sli4_xritag; - - index = phba->sli4_hba.scsi_xri_cnt++; - psb->cur_iocbq.iocb_flag |= LPFC_IO_FCP; - - psb->fcp_bpl = psb->data; - psb->fcp_cmnd = (psb->data + phba->cfg_sg_dma_buf_size) - - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); - psb->fcp_rsp = (struct fcp_rsp *)((uint8_t *)psb->fcp_cmnd + - sizeof(struct fcp_cmnd)); - - /* Initialize local short-hand pointers. */ - sgl = (struct sli4_sge *)psb->fcp_bpl; - pdma_phys_bpl = psb->dma_handle; - pdma_phys_fcp_cmd = - (psb->dma_handle + phba->cfg_sg_dma_buf_size) - - (sizeof(struct fcp_cmnd) + sizeof(struct fcp_rsp)); - pdma_phys_fcp_rsp = pdma_phys_fcp_cmd + sizeof(struct fcp_cmnd); - - /* - * The first two bdes are the FCP_CMD and FCP_RSP. The balance - * are sg list bdes. Initialize the first two and leave the - * rest for queuecommand. - */ - sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_cmd)); - sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_cmd)); - sgl->word2 = le32_to_cpu(sgl->word2); - bf_set(lpfc_sli4_sge_last, sgl, 0); - sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32(sizeof(struct fcp_cmnd)); - sgl++; - - /* Setup the physical region for the FCP RSP */ - sgl->addr_hi = cpu_to_le32(putPaddrHigh(pdma_phys_fcp_rsp)); - sgl->addr_lo = cpu_to_le32(putPaddrLow(pdma_phys_fcp_rsp)); - sgl->word2 = le32_to_cpu(sgl->word2); - bf_set(lpfc_sli4_sge_last, sgl, 1); - sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32(sizeof(struct fcp_rsp)); - - /* - * Since the IOCB for the FCP I/O is built into this - * lpfc_scsi_buf, initialize it with all known data now. - */ - iocb = &psb->cur_iocbq.iocb; - iocb->un.fcpi64.bdl.ulpIoTag32 = 0; - iocb->un.fcpi64.bdl.bdeFlags = BUFF_TYPE_BDE_64; - /* setting the BLP size to 2 * sizeof BDE may not be correct. - * We are setting the bpl to point to out sgl. An sgl's - * entries are 16 bytes, a bpl entries are 12 bytes. - */ - iocb->un.fcpi64.bdl.bdeSize = sizeof(struct fcp_cmnd); - iocb->un.fcpi64.bdl.addrLow = putPaddrLow(pdma_phys_fcp_cmd); - iocb->un.fcpi64.bdl.addrHigh = putPaddrHigh(pdma_phys_fcp_cmd); - iocb->ulpBdeCount = 1; - iocb->ulpLe = 1; - iocb->ulpClass = CLASS3; - psb->cur_iocbq.context1 = psb; - if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) - pdma_phys_bpl1 = pdma_phys_bpl + SGL_PAGE_SIZE; - else - pdma_phys_bpl1 = 0; - psb->dma_phys_bpl = pdma_phys_bpl; - phba->sli4_hba.lpfc_scsi_psb_array[index] = psb; - if (non_sequential_xri) { - status = lpfc_sli4_post_sgl(phba, pdma_phys_bpl, - pdma_phys_bpl1, - psb->cur_iocbq.sli4_xritag); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - break; - } - } - if (bcnt) { - if (!phba->sli4_hba.extents_in_use) - status = lpfc_sli4_post_scsi_sgl_block(phba, - &sblist, - bcnt); - else - status = lpfc_sli4_post_scsi_sgl_blk_ext(phba, - &sblist, - bcnt); - - if (status) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "3021 SCSI SGL post error %d\n", - status); - bcnt = 0; - } - /* Reset SCSI buffer count for next round of posting */ - while (!list_empty(&sblist)) { - list_remove_head(&sblist, psb, struct lpfc_scsi_buf, - list); - if (status) { - /* Put this back on the abort scsi list */ - psb->exch_busy = 1; - } else { - psb->exch_busy = 0; - psb->status = IOSTAT_SUCCESS; - } - /* Put it back into the SCSI buffer list */ - lpfc_release_scsi_buf_s4(phba, psb); - } - } - - return bcnt + non_sequential_xri; -} - -/** - * lpfc_new_scsi_buf - Wrapper funciton for scsi buffer allocator - * @vport: The virtual port for which this call being executed. - * @num_to_allocate: The requested number of buffers to allocate. - * - * This routine wraps the actual SCSI buffer allocator function pointer from - * the lpfc_hba struct. - * - * Return codes: - * int - number of scsi buffers that were allocated. - * 0 = failure, less than num_to_alloc is a partial failure. - **/ -static inline int -lpfc_new_scsi_buf(struct lpfc_vport *vport, int num_to_alloc) -{ - return vport->phba->lpfc_new_scsi_buf(vport, num_to_alloc); -} - -/** - * lpfc_get_scsi_buf_s3 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA - * @phba: The HBA for which this call is being executed. - * - * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list - * and returns to caller. - * - * Return codes: - * NULL - Error - * Pointer to lpfc_scsi_buf - Success - **/ -static struct lpfc_scsi_buf* -lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) -{ - struct lpfc_scsi_buf * lpfc_cmd = NULL; - struct list_head *scsi_buf_list = &phba->lpfc_scsi_buf_list; - unsigned long iflag = 0; - - spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); - list_remove_head(scsi_buf_list, lpfc_cmd, struct lpfc_scsi_buf, list); - if (lpfc_cmd) { - lpfc_cmd->seg_cnt = 0; - lpfc_cmd->nonsg_phys = 0; - lpfc_cmd->prot_seg_cnt = 0; - } - spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag); - return lpfc_cmd; -} -/** - * lpfc_get_scsi_buf_s4 - Get a scsi buffer from lpfc_scsi_buf_list of the HBA - * @phba: The HBA for which this call is being executed. - * - * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list - * and returns to caller. - * - * Return codes: - * NULL - Error - * Pointer to lpfc_scsi_buf - Success - **/ -static struct lpfc_scsi_buf* -lpfc_get_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) -{ - struct lpfc_scsi_buf *lpfc_cmd ; - unsigned long iflag = 0; - int found = 0; - - spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); - list_for_each_entry(lpfc_cmd, &phba->lpfc_scsi_buf_list, - list) { - if (lpfc_test_rrq_active(phba, ndlp, - lpfc_cmd->cur_iocbq.sli4_xritag)) - continue; - list_del(&lpfc_cmd->list); - found = 1; - lpfc_cmd->seg_cnt = 0; - lpfc_cmd->nonsg_phys = 0; - lpfc_cmd->prot_seg_cnt = 0; - break; - } - spin_unlock_irqrestore(&phba->scsi_buf_list_lock, - iflag); - if (!found) - return NULL; - else - return lpfc_cmd; -} -/** - * lpfc_get_scsi_buf - Get a scsi buffer from lpfc_scsi_buf_list of the HBA - * @phba: The HBA for which this call is being executed. - * - * This routine removes a scsi buffer from head of @phba lpfc_scsi_buf_list list - * and returns to caller. - * - * Return codes: - * NULL - Error - * Pointer to lpfc_scsi_buf - Success - **/ -static struct lpfc_scsi_buf* -lpfc_get_scsi_buf(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) -{ - return phba->lpfc_get_scsi_buf(phba, ndlp); -} - -/** - * lpfc_release_scsi_buf - Return a scsi buffer back to hba scsi buf list - * @phba: The Hba for which this call is being executed. - * @psb: The scsi buffer which is being released. - * - * This routine releases @psb scsi buffer by adding it to tail of @phba - * lpfc_scsi_buf_list list. - **/ -static void -lpfc_release_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) -{ - unsigned long iflag = 0; - - spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); - psb->pCmd = NULL; - list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list); - spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag); -} - -/** - * lpfc_release_scsi_buf_s4: Return a scsi buffer back to hba scsi buf list. - * @phba: The Hba for which this call is being executed. - * @psb: The scsi buffer which is being released. - * - * This routine releases @psb scsi buffer by adding it to tail of @phba - * lpfc_scsi_buf_list list. For SLI4 XRI's are tied to the scsi buffer - * and cannot be reused for at least RA_TOV amount of time if it was - * aborted. - **/ -static void -lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) -{ - unsigned long iflag = 0; - - if (psb->exch_busy) { - spin_lock_irqsave(&phba->sli4_hba.abts_scsi_buf_list_lock, - iflag); - psb->pCmd = NULL; - list_add_tail(&psb->list, - &phba->sli4_hba.lpfc_abts_scsi_buf_list); - spin_unlock_irqrestore(&phba->sli4_hba.abts_scsi_buf_list_lock, - iflag); - } else { - - spin_lock_irqsave(&phba->scsi_buf_list_lock, iflag); - psb->pCmd = NULL; - list_add_tail(&psb->list, &phba->lpfc_scsi_buf_list); - spin_unlock_irqrestore(&phba->scsi_buf_list_lock, iflag); - } -} - -/** - * lpfc_release_scsi_buf: Return a scsi buffer back to hba scsi buf list. - * @phba: The Hba for which this call is being executed. - * @psb: The scsi buffer which is being released. - * - * This routine releases @psb scsi buffer by adding it to tail of @phba - * lpfc_scsi_buf_list list. - **/ -static void -lpfc_release_scsi_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) -{ - - phba->lpfc_release_scsi_buf(phba, psb); -} - -/** - * lpfc_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec - * @phba: The Hba for which this call is being executed. - * @lpfc_cmd: The scsi buffer which is going to be mapped. - * - * This routine does the pci dma mapping for scatter-gather list of scsi cmnd - * field of @lpfc_cmd for device with SLI-3 interface spec. This routine scans - * through sg elements and format the bdea. This routine also initializes all - * IOCB fields which are dependent on scsi command request buffer. - * - * Return codes: - * 1 - Error - * 0 - Success - **/ -static int -lpfc_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) -{ - struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; - struct scatterlist *sgel = NULL; - struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; - struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl; - struct lpfc_iocbq *iocbq = &lpfc_cmd->cur_iocbq; - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; - struct ulp_bde64 *data_bde = iocb_cmd->unsli3.fcp_ext.dbde; - dma_addr_t physaddr; - uint32_t num_bde = 0; - int nseg, datadir = scsi_cmnd->sc_data_direction; - - /* - * There are three possibilities here - use scatter-gather segment, use - * the single mapping, or neither. Start the lpfc command prep by - * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first - * data bde entry. - */ - bpl += 2; - if (scsi_sg_count(scsi_cmnd)) { - /* - * The driver stores the segment count returned from pci_map_sg - * because this a count of dma-mappings used to map the use_sg - * pages. They are not guaranteed to be the same for those - * architectures that implement an IOMMU. - */ - - nseg = dma_map_sg(&phba->pcidev->dev, scsi_sglist(scsi_cmnd), - scsi_sg_count(scsi_cmnd), datadir); - if (unlikely(!nseg)) - return 1; - - lpfc_cmd->seg_cnt = nseg; - if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9064 BLKGRD: %s: Too many sg segments from " - "dma_map_sg. Config %d, seg_cnt %d\n", - __func__, phba->cfg_sg_seg_cnt, - lpfc_cmd->seg_cnt); - scsi_dma_unmap(scsi_cmnd); - return 1; - } - - /* - * The driver established a maximum scatter-gather segment count - * during probe that limits the number of sg elements in any - * single scsi command. Just run through the seg_cnt and format - * the bde's. - * When using SLI-3 the driver will try to fit all the BDEs into - * the IOCB. If it can't then the BDEs get added to a BPL as it - * does for SLI-2 mode. - */ - scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) { - physaddr = sg_dma_address(sgel); - if (phba->sli_rev == 3 && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED) && - !(iocbq->iocb_flag & DSS_SECURITY_OP) && - nseg <= LPFC_EXT_DATA_BDE_COUNT) { - data_bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - data_bde->tus.f.bdeSize = sg_dma_len(sgel); - data_bde->addrLow = putPaddrLow(physaddr); - data_bde->addrHigh = putPaddrHigh(physaddr); - data_bde++; - } else { - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bpl->tus.f.bdeSize = sg_dma_len(sgel); - bpl->tus.w = le32_to_cpu(bpl->tus.w); - bpl->addrLow = - le32_to_cpu(putPaddrLow(physaddr)); - bpl->addrHigh = - le32_to_cpu(putPaddrHigh(physaddr)); - bpl++; - } - } - } - - /* - * Finish initializing those IOCB fields that are dependent on the - * scsi_cmnd request_buffer. Note that for SLI-2 the bdeSize is - * explicitly reinitialized and for SLI-3 the extended bde count is - * explicitly reinitialized since all iocb memory resources are reused. - */ - if (phba->sli_rev == 3 && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED) && - !(iocbq->iocb_flag & DSS_SECURITY_OP)) { - if (num_bde > LPFC_EXT_DATA_BDE_COUNT) { - /* - * The extended IOCB format can only fit 3 BDE or a BPL. - * This I/O has more than 3 BDE so the 1st data bde will - * be a BPL that is filled in here. - */ - physaddr = lpfc_cmd->dma_handle; - data_bde->tus.f.bdeFlags = BUFF_TYPE_BLP_64; - data_bde->tus.f.bdeSize = (num_bde * - sizeof(struct ulp_bde64)); - physaddr += (sizeof(struct fcp_cmnd) + - sizeof(struct fcp_rsp) + - (2 * sizeof(struct ulp_bde64))); - data_bde->addrHigh = putPaddrHigh(physaddr); - data_bde->addrLow = putPaddrLow(physaddr); - /* ebde count includes the response bde and data bpl */ - iocb_cmd->unsli3.fcp_ext.ebde_count = 2; - } else { - /* ebde count includes the response bde and data bdes */ - iocb_cmd->unsli3.fcp_ext.ebde_count = (num_bde + 1); - } - } else { - iocb_cmd->un.fcpi64.bdl.bdeSize = - ((num_bde + 2) * sizeof(struct ulp_bde64)); - iocb_cmd->unsli3.fcp_ext.ebde_count = (num_bde + 1); - } - fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); - - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of IOCB here - */ - iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); - return 0; -} - -static inline unsigned -lpfc_cmd_blksize(struct scsi_cmnd *sc) -{ - return sc->device->sector_size; -} - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - -/* Return if if error injection is detected by Initiator */ -#define BG_ERR_INIT 0x1 -/* Return if if error injection is detected by Target */ -#define BG_ERR_TGT 0x2 -/* Return if if swapping CSUM<-->CRC is required for error injection */ -#define BG_ERR_SWAP 0x10 -/* Return if disabling Guard/Ref/App checking is required for error injection */ -#define BG_ERR_CHECK 0x20 - -/** - * lpfc_bg_err_inject - Determine if we should inject an error - * @phba: The Hba for which this call is being executed. - * @sc: The SCSI command to examine - * @reftag: (out) BlockGuard reference tag for transmitted data - * @apptag: (out) BlockGuard application tag for transmitted data - * @new_guard (in) Value to replace CRC with if needed - * - * Returns BG_ERR_* bit mask or 0 if request ignored - **/ -static int -lpfc_bg_err_inject(struct lpfc_hba *phba, struct scsi_cmnd *sc, - uint32_t *reftag, uint16_t *apptag, uint32_t new_guard) -{ - struct scatterlist *sgpe; /* s/g prot entry */ - struct scatterlist *sgde; /* s/g data entry */ - struct lpfc_scsi_buf *lpfc_cmd = NULL; - struct scsi_dif_tuple *src = NULL; - struct lpfc_nodelist *ndlp; - struct lpfc_rport_data *rdata; - uint32_t op = scsi_get_prot_op(sc); - uint32_t blksize; - uint32_t numblks; - sector_t lba; - int rc = 0; - int blockoff = 0; - - if (op == SCSI_PROT_NORMAL) - return 0; - - sgpe = scsi_prot_sglist(sc); - sgde = scsi_sglist(sc); - lba = scsi_get_lba(sc); - - /* First check if we need to match the LBA */ - if (phba->lpfc_injerr_lba != LPFC_INJERR_LBA_OFF) { - blksize = lpfc_cmd_blksize(sc); - numblks = (scsi_bufflen(sc) + blksize - 1) / blksize; - - /* Make sure we have the right LBA if one is specified */ - if ((phba->lpfc_injerr_lba < lba) || - (phba->lpfc_injerr_lba >= (lba + numblks))) - return 0; - if (sgpe) { - blockoff = phba->lpfc_injerr_lba - lba; - numblks = sg_dma_len(sgpe) / - sizeof(struct scsi_dif_tuple); - if (numblks < blockoff) - blockoff = numblks; - } - } - - /* Next check if we need to match the remote NPortID or WWPN */ - rdata = sc->device->hostdata; - if (rdata && rdata->pnode) { - ndlp = rdata->pnode; - - /* Make sure we have the right NPortID if one is specified */ - if (phba->lpfc_injerr_nportid && - (phba->lpfc_injerr_nportid != ndlp->nlp_DID)) - return 0; - - /* - * Make sure we have the right WWPN if one is specified. - * wwn[0] should be a non-zero NAA in a good WWPN. - */ - if (phba->lpfc_injerr_wwpn.u.wwn[0] && - (memcmp(&ndlp->nlp_portname, &phba->lpfc_injerr_wwpn, - sizeof(struct lpfc_name)) != 0)) - return 0; - } - - /* Setup a ptr to the protection data if the SCSI host provides it */ - if (sgpe) { - src = (struct scsi_dif_tuple *)sg_virt(sgpe); - src += blockoff; - lpfc_cmd = (struct lpfc_scsi_buf *)sc->host_scribble; - } - - /* Should we change the Reference Tag */ - if (reftag) { - if (phba->lpfc_injerr_wref_cnt) { - switch (op) { - case SCSI_PROT_WRITE_PASS: - if (src) { - /* - * For WRITE_PASS, force the error - * to be sent on the wire. It should - * be detected by the Target. - * If blockoff != 0 error will be - * inserted in middle of the IO. - */ - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9076 BLKGRD: Injecting reftag error: " - "write lba x%lx + x%x oldrefTag x%x\n", - (unsigned long)lba, blockoff, - be32_to_cpu(src->ref_tag)); - - /* - * Save the old ref_tag so we can - * restore it on completion. - */ - if (lpfc_cmd) { - lpfc_cmd->prot_data_type = - LPFC_INJERR_REFTAG; - lpfc_cmd->prot_data_segment = - src; - lpfc_cmd->prot_data = - src->ref_tag; - } - src->ref_tag = cpu_to_be32(0xDEADBEEF); - phba->lpfc_injerr_wref_cnt--; - if (phba->lpfc_injerr_wref_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - rc = BG_ERR_TGT | BG_ERR_CHECK; - - break; - } - /* Drop thru */ - case SCSI_PROT_WRITE_INSERT: - /* - * For WRITE_INSERT, force the error - * to be sent on the wire. It should be - * detected by the Target. - */ - /* DEADBEEF will be the reftag on the wire */ - *reftag = 0xDEADBEEF; - phba->lpfc_injerr_wref_cnt--; - if (phba->lpfc_injerr_wref_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - rc = BG_ERR_TGT | BG_ERR_CHECK; - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9078 BLKGRD: Injecting reftag error: " - "write lba x%lx\n", (unsigned long)lba); - break; - case SCSI_PROT_WRITE_STRIP: - /* - * For WRITE_STRIP and WRITE_PASS, - * force the error on data - * being copied from SLI-Host to SLI-Port. - */ - *reftag = 0xDEADBEEF; - phba->lpfc_injerr_wref_cnt--; - if (phba->lpfc_injerr_wref_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - rc = BG_ERR_INIT; - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9077 BLKGRD: Injecting reftag error: " - "write lba x%lx\n", (unsigned long)lba); - break; - } - } - if (phba->lpfc_injerr_rref_cnt) { - switch (op) { - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_READ_PASS: - /* - * For READ_STRIP and READ_PASS, force the - * error on data being read off the wire. It - * should force an IO error to the driver. - */ - *reftag = 0xDEADBEEF; - phba->lpfc_injerr_rref_cnt--; - if (phba->lpfc_injerr_rref_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - rc = BG_ERR_INIT; - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9079 BLKGRD: Injecting reftag error: " - "read lba x%lx\n", (unsigned long)lba); - break; - } - } - } - - /* Should we change the Application Tag */ - if (apptag) { - if (phba->lpfc_injerr_wapp_cnt) { - switch (op) { - case SCSI_PROT_WRITE_PASS: - if (src) { - /* - * For WRITE_PASS, force the error - * to be sent on the wire. It should - * be detected by the Target. - * If blockoff != 0 error will be - * inserted in middle of the IO. - */ - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9080 BLKGRD: Injecting apptag error: " - "write lba x%lx + x%x oldappTag x%x\n", - (unsigned long)lba, blockoff, - be16_to_cpu(src->app_tag)); - - /* - * Save the old app_tag so we can - * restore it on completion. - */ - if (lpfc_cmd) { - lpfc_cmd->prot_data_type = - LPFC_INJERR_APPTAG; - lpfc_cmd->prot_data_segment = - src; - lpfc_cmd->prot_data = - src->app_tag; - } - src->app_tag = cpu_to_be16(0xDEAD); - phba->lpfc_injerr_wapp_cnt--; - if (phba->lpfc_injerr_wapp_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - rc = BG_ERR_TGT | BG_ERR_CHECK; - break; - } - /* Drop thru */ - case SCSI_PROT_WRITE_INSERT: - /* - * For WRITE_INSERT, force the - * error to be sent on the wire. It should be - * detected by the Target. - */ - /* DEAD will be the apptag on the wire */ - *apptag = 0xDEAD; - phba->lpfc_injerr_wapp_cnt--; - if (phba->lpfc_injerr_wapp_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - rc = BG_ERR_TGT | BG_ERR_CHECK; - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0813 BLKGRD: Injecting apptag error: " - "write lba x%lx\n", (unsigned long)lba); - break; - case SCSI_PROT_WRITE_STRIP: - /* - * For WRITE_STRIP and WRITE_PASS, - * force the error on data - * being copied from SLI-Host to SLI-Port. - */ - *apptag = 0xDEAD; - phba->lpfc_injerr_wapp_cnt--; - if (phba->lpfc_injerr_wapp_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - rc = BG_ERR_INIT; - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0812 BLKGRD: Injecting apptag error: " - "write lba x%lx\n", (unsigned long)lba); - break; - } - } - if (phba->lpfc_injerr_rapp_cnt) { - switch (op) { - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_READ_PASS: - /* - * For READ_STRIP and READ_PASS, force the - * error on data being read off the wire. It - * should force an IO error to the driver. - */ - *apptag = 0xDEAD; - phba->lpfc_injerr_rapp_cnt--; - if (phba->lpfc_injerr_rapp_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - rc = BG_ERR_INIT; - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0814 BLKGRD: Injecting apptag error: " - "read lba x%lx\n", (unsigned long)lba); - break; - } - } - } - - - /* Should we change the Guard Tag */ - if (new_guard) { - if (phba->lpfc_injerr_wgrd_cnt) { - switch (op) { - case SCSI_PROT_WRITE_PASS: - rc = BG_ERR_CHECK; - /* Drop thru */ - - case SCSI_PROT_WRITE_INSERT: - /* - * For WRITE_INSERT, force the - * error to be sent on the wire. It should be - * detected by the Target. - */ - phba->lpfc_injerr_wgrd_cnt--; - if (phba->lpfc_injerr_wgrd_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - - rc |= BG_ERR_TGT | BG_ERR_SWAP; - /* Signals the caller to swap CRC->CSUM */ - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0817 BLKGRD: Injecting guard error: " - "write lba x%lx\n", (unsigned long)lba); - break; - case SCSI_PROT_WRITE_STRIP: - /* - * For WRITE_STRIP and WRITE_PASS, - * force the error on data - * being copied from SLI-Host to SLI-Port. - */ - phba->lpfc_injerr_wgrd_cnt--; - if (phba->lpfc_injerr_wgrd_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - - rc = BG_ERR_INIT | BG_ERR_SWAP; - /* Signals the caller to swap CRC->CSUM */ - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0816 BLKGRD: Injecting guard error: " - "write lba x%lx\n", (unsigned long)lba); - break; - } - } - if (phba->lpfc_injerr_rgrd_cnt) { - switch (op) { - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_READ_PASS: - /* - * For READ_STRIP and READ_PASS, force the - * error on data being read off the wire. It - * should force an IO error to the driver. - */ - phba->lpfc_injerr_rgrd_cnt--; - if (phba->lpfc_injerr_rgrd_cnt == 0) { - phba->lpfc_injerr_nportid = 0; - phba->lpfc_injerr_lba = - LPFC_INJERR_LBA_OFF; - memset(&phba->lpfc_injerr_wwpn, - 0, sizeof(struct lpfc_name)); - } - - rc = BG_ERR_INIT | BG_ERR_SWAP; - /* Signals the caller to swap CRC->CSUM */ - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "0818 BLKGRD: Injecting guard error: " - "read lba x%lx\n", (unsigned long)lba); - } - } - } - - return rc; -} -#endif - -/** - * lpfc_sc_to_bg_opcodes - Determine the BlockGuard opcodes to be used with - * the specified SCSI command. - * @phba: The Hba for which this call is being executed. - * @sc: The SCSI command to examine - * @txopt: (out) BlockGuard operation for transmitted data - * @rxopt: (out) BlockGuard operation for received data - * - * Returns: zero on success; non-zero if tx and/or rx op cannot be determined - * - **/ -static int -lpfc_sc_to_bg_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, - uint8_t *txop, uint8_t *rxop) -{ - uint8_t guard_type = scsi_host_get_guard(sc->device->host); - uint8_t ret = 0; - - if (guard_type == SHOST_DIX_GUARD_IP) { - switch (scsi_get_prot_op(sc)) { - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_WRITE_STRIP: - *rxop = BG_OP_IN_NODIF_OUT_CSUM; - *txop = BG_OP_IN_CSUM_OUT_NODIF; - break; - - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_WRITE_INSERT: - *rxop = BG_OP_IN_CRC_OUT_NODIF; - *txop = BG_OP_IN_NODIF_OUT_CRC; - break; - - case SCSI_PROT_READ_PASS: - case SCSI_PROT_WRITE_PASS: - *rxop = BG_OP_IN_CRC_OUT_CSUM; - *txop = BG_OP_IN_CSUM_OUT_CRC; - break; - - case SCSI_PROT_NORMAL: - default: - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9063 BLKGRD: Bad op/guard:%d/IP combination\n", - scsi_get_prot_op(sc)); - ret = 1; - break; - - } - } else { - switch (scsi_get_prot_op(sc)) { - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_WRITE_INSERT: - *rxop = BG_OP_IN_CRC_OUT_NODIF; - *txop = BG_OP_IN_NODIF_OUT_CRC; - break; - - case SCSI_PROT_READ_PASS: - case SCSI_PROT_WRITE_PASS: - *rxop = BG_OP_IN_CRC_OUT_CRC; - *txop = BG_OP_IN_CRC_OUT_CRC; - break; - - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_WRITE_STRIP: - *rxop = BG_OP_IN_NODIF_OUT_CRC; - *txop = BG_OP_IN_CRC_OUT_NODIF; - break; - - case SCSI_PROT_NORMAL: - default: - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9075 BLKGRD: Bad op/guard:%d/CRC combination\n", - scsi_get_prot_op(sc)); - ret = 1; - break; - } - } - - return ret; -} - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS -/** - * lpfc_bg_err_opcodes - reDetermine the BlockGuard opcodes to be used with - * the specified SCSI command in order to force a guard tag error. - * @phba: The Hba for which this call is being executed. - * @sc: The SCSI command to examine - * @txopt: (out) BlockGuard operation for transmitted data - * @rxopt: (out) BlockGuard operation for received data - * - * Returns: zero on success; non-zero if tx and/or rx op cannot be determined - * - **/ -static int -lpfc_bg_err_opcodes(struct lpfc_hba *phba, struct scsi_cmnd *sc, - uint8_t *txop, uint8_t *rxop) -{ - uint8_t guard_type = scsi_host_get_guard(sc->device->host); - uint8_t ret = 0; - - if (guard_type == SHOST_DIX_GUARD_IP) { - switch (scsi_get_prot_op(sc)) { - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_WRITE_STRIP: - *rxop = BG_OP_IN_NODIF_OUT_CRC; - *txop = BG_OP_IN_CRC_OUT_NODIF; - break; - - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_WRITE_INSERT: - *rxop = BG_OP_IN_CSUM_OUT_NODIF; - *txop = BG_OP_IN_NODIF_OUT_CSUM; - break; - - case SCSI_PROT_READ_PASS: - case SCSI_PROT_WRITE_PASS: - *rxop = BG_OP_IN_CSUM_OUT_CRC; - *txop = BG_OP_IN_CRC_OUT_CSUM; - break; - - case SCSI_PROT_NORMAL: - default: - break; - - } - } else { - switch (scsi_get_prot_op(sc)) { - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_WRITE_INSERT: - *rxop = BG_OP_IN_CSUM_OUT_NODIF; - *txop = BG_OP_IN_NODIF_OUT_CSUM; - break; - - case SCSI_PROT_READ_PASS: - case SCSI_PROT_WRITE_PASS: - *rxop = BG_OP_IN_CSUM_OUT_CSUM; - *txop = BG_OP_IN_CSUM_OUT_CSUM; - break; - - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_WRITE_STRIP: - *rxop = BG_OP_IN_NODIF_OUT_CSUM; - *txop = BG_OP_IN_CSUM_OUT_NODIF; - break; - - case SCSI_PROT_NORMAL: - default: - break; - } - } - - return ret; -} -#endif - -/** - * lpfc_bg_setup_bpl - Setup BlockGuard BPL with no protection data - * @phba: The Hba for which this call is being executed. - * @sc: pointer to scsi command we're working on - * @bpl: pointer to buffer list for protection groups - * @datacnt: number of segments of data that have been dma mapped - * - * This function sets up BPL buffer list for protection groups of - * type LPFC_PG_TYPE_NO_DIF - * - * This is usually used when the HBA is instructed to generate - * DIFs and insert them into data stream (or strip DIF from - * incoming data stream) - * - * The buffer list consists of just one protection group described - * below: - * +-------------------------+ - * start of prot group --> | PDE_5 | - * +-------------------------+ - * | PDE_6 | - * +-------------------------+ - * | Data BDE | - * +-------------------------+ - * |more Data BDE's ... (opt)| - * +-------------------------+ - * - * - * Note: Data s/g buffers have been dma mapped - * - * Returns the number of BDEs added to the BPL. - **/ -static int -lpfc_bg_setup_bpl(struct lpfc_hba *phba, struct scsi_cmnd *sc, - struct ulp_bde64 *bpl, int datasegcnt) -{ - struct scatterlist *sgde = NULL; /* s/g data entry */ - struct lpfc_pde5 *pde5 = NULL; - struct lpfc_pde6 *pde6 = NULL; - dma_addr_t physaddr; - int i = 0, num_bde = 0, status; - int datadir = sc->sc_data_direction; - uint32_t rc; - uint32_t checking = 1; - uint32_t reftag; - unsigned blksize; - uint8_t txop, rxop; - - status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); - if (status) - goto out; - - /* extract some info from the scsi command for pde*/ - blksize = lpfc_cmd_blksize(sc); - reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); - if (rc) { - if (rc & BG_ERR_SWAP) - lpfc_bg_err_opcodes(phba, sc, &txop, &rxop); - if (rc & BG_ERR_CHECK) - checking = 0; - } -#endif - - /* setup PDE5 with what we have */ - pde5 = (struct lpfc_pde5 *) bpl; - memset(pde5, 0, sizeof(struct lpfc_pde5)); - bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); - - /* Endianness conversion if necessary for PDE5 */ - pde5->word0 = cpu_to_le32(pde5->word0); - pde5->reftag = cpu_to_le32(reftag); - - /* advance bpl and increment bde count */ - num_bde++; - bpl++; - pde6 = (struct lpfc_pde6 *) bpl; - - /* setup PDE6 with the rest of the info */ - memset(pde6, 0, sizeof(struct lpfc_pde6)); - bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR); - bf_set(pde6_optx, pde6, txop); - bf_set(pde6_oprx, pde6, rxop); - if (datadir == DMA_FROM_DEVICE) { - bf_set(pde6_ce, pde6, checking); - bf_set(pde6_re, pde6, checking); - } - bf_set(pde6_ai, pde6, 1); - bf_set(pde6_ae, pde6, 0); - bf_set(pde6_apptagval, pde6, 0); - - /* Endianness conversion if necessary for PDE6 */ - pde6->word0 = cpu_to_le32(pde6->word0); - pde6->word1 = cpu_to_le32(pde6->word1); - pde6->word2 = cpu_to_le32(pde6->word2); - - /* advance bpl and increment bde count */ - num_bde++; - bpl++; - - /* assumption: caller has already run dma_map_sg on command data */ - scsi_for_each_sg(sc, sgde, datasegcnt, i) { - physaddr = sg_dma_address(sgde); - bpl->addrLow = le32_to_cpu(putPaddrLow(physaddr)); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(physaddr)); - bpl->tus.f.bdeSize = sg_dma_len(sgde); - if (datadir == DMA_TO_DEVICE) - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - else - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - bpl++; - num_bde++; - } - -out: - return num_bde; -} - -/** - * lpfc_bg_setup_bpl_prot - Setup BlockGuard BPL with protection data - * @phba: The Hba for which this call is being executed. - * @sc: pointer to scsi command we're working on - * @bpl: pointer to buffer list for protection groups - * @datacnt: number of segments of data that have been dma mapped - * @protcnt: number of segment of protection data that have been dma mapped - * - * This function sets up BPL buffer list for protection groups of - * type LPFC_PG_TYPE_DIF - * - * This is usually used when DIFs are in their own buffers, - * separate from the data. The HBA can then by instructed - * to place the DIFs in the outgoing stream. For read operations, - * The HBA could extract the DIFs and place it in DIF buffers. - * - * The buffer list for this type consists of one or more of the - * protection groups described below: - * +-------------------------+ - * start of first prot group --> | PDE_5 | - * +-------------------------+ - * | PDE_6 | - * +-------------------------+ - * | PDE_7 (Prot BDE) | - * +-------------------------+ - * | Data BDE | - * +-------------------------+ - * |more Data BDE's ... (opt)| - * +-------------------------+ - * start of new prot group --> | PDE_5 | - * +-------------------------+ - * | ... | - * +-------------------------+ - * - * Note: It is assumed that both data and protection s/g buffers have been - * mapped for DMA - * - * Returns the number of BDEs added to the BPL. - **/ -static int -lpfc_bg_setup_bpl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, - struct ulp_bde64 *bpl, int datacnt, int protcnt) -{ - struct scatterlist *sgde = NULL; /* s/g data entry */ - struct scatterlist *sgpe = NULL; /* s/g prot entry */ - struct lpfc_pde5 *pde5 = NULL; - struct lpfc_pde6 *pde6 = NULL; - struct lpfc_pde7 *pde7 = NULL; - dma_addr_t dataphysaddr, protphysaddr; - unsigned short curr_data = 0, curr_prot = 0; - unsigned int split_offset; - unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder; - unsigned int protgrp_blks, protgrp_bytes; - unsigned int remainder, subtotal; - int status; - int datadir = sc->sc_data_direction; - unsigned char pgdone = 0, alldone = 0; - unsigned blksize; - uint32_t rc; - uint32_t checking = 1; - uint32_t reftag; - uint8_t txop, rxop; - int num_bde = 0; - - sgpe = scsi_prot_sglist(sc); - sgde = scsi_sglist(sc); - - if (!sgpe || !sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9020 Invalid s/g entry: data=0x%p prot=0x%p\n", - sgpe, sgde); - return 0; - } - - status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); - if (status) - goto out; - - /* extract some info from the scsi command */ - blksize = lpfc_cmd_blksize(sc); - reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); - if (rc) { - if (rc & BG_ERR_SWAP) - lpfc_bg_err_opcodes(phba, sc, &txop, &rxop); - if (rc & BG_ERR_CHECK) - checking = 0; - } -#endif - - split_offset = 0; - do { - /* setup PDE5 with what we have */ - pde5 = (struct lpfc_pde5 *) bpl; - memset(pde5, 0, sizeof(struct lpfc_pde5)); - bf_set(pde5_type, pde5, LPFC_PDE5_DESCRIPTOR); - - /* Endianness conversion if necessary for PDE5 */ - pde5->word0 = cpu_to_le32(pde5->word0); - pde5->reftag = cpu_to_le32(reftag); - - /* advance bpl and increment bde count */ - num_bde++; - bpl++; - pde6 = (struct lpfc_pde6 *) bpl; - - /* setup PDE6 with the rest of the info */ - memset(pde6, 0, sizeof(struct lpfc_pde6)); - bf_set(pde6_type, pde6, LPFC_PDE6_DESCRIPTOR); - bf_set(pde6_optx, pde6, txop); - bf_set(pde6_oprx, pde6, rxop); - bf_set(pde6_ce, pde6, checking); - bf_set(pde6_re, pde6, checking); - bf_set(pde6_ai, pde6, 1); - bf_set(pde6_ae, pde6, 0); - bf_set(pde6_apptagval, pde6, 0); - - /* Endianness conversion if necessary for PDE6 */ - pde6->word0 = cpu_to_le32(pde6->word0); - pde6->word1 = cpu_to_le32(pde6->word1); - pde6->word2 = cpu_to_le32(pde6->word2); - - /* advance bpl and increment bde count */ - num_bde++; - bpl++; - - /* setup the first BDE that points to protection buffer */ - protphysaddr = sg_dma_address(sgpe) + protgroup_offset; - protgroup_len = sg_dma_len(sgpe) - protgroup_offset; - - /* must be integer multiple of the DIF block length */ - BUG_ON(protgroup_len % 8); - - pde7 = (struct lpfc_pde7 *) bpl; - memset(pde7, 0, sizeof(struct lpfc_pde7)); - bf_set(pde7_type, pde7, LPFC_PDE7_DESCRIPTOR); - - pde7->addrHigh = le32_to_cpu(putPaddrHigh(protphysaddr)); - pde7->addrLow = le32_to_cpu(putPaddrLow(protphysaddr)); - - protgrp_blks = protgroup_len / 8; - protgrp_bytes = protgrp_blks * blksize; - - /* check if this pde is crossing the 4K boundary; if so split */ - if ((pde7->addrLow & 0xfff) + protgroup_len > 0x1000) { - protgroup_remainder = 0x1000 - (pde7->addrLow & 0xfff); - protgroup_offset += protgroup_remainder; - protgrp_blks = protgroup_remainder / 8; - protgrp_bytes = protgrp_blks * blksize; - } else { - protgroup_offset = 0; - curr_prot++; - } - - num_bde++; - - /* setup BDE's for data blocks associated with DIF data */ - pgdone = 0; - subtotal = 0; /* total bytes processed for current prot grp */ - while (!pgdone) { - if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9065 BLKGRD:%s Invalid data segment\n", - __func__); - return 0; - } - bpl++; - dataphysaddr = sg_dma_address(sgde) + split_offset; - bpl->addrLow = le32_to_cpu(putPaddrLow(dataphysaddr)); - bpl->addrHigh = le32_to_cpu(putPaddrHigh(dataphysaddr)); - - remainder = sg_dma_len(sgde) - split_offset; - - if ((subtotal + remainder) <= protgrp_bytes) { - /* we can use this whole buffer */ - bpl->tus.f.bdeSize = remainder; - split_offset = 0; - - if ((subtotal + remainder) == protgrp_bytes) - pgdone = 1; - } else { - /* must split this buffer with next prot grp */ - bpl->tus.f.bdeSize = protgrp_bytes - subtotal; - split_offset += bpl->tus.f.bdeSize; - } - - subtotal += bpl->tus.f.bdeSize; - - if (datadir == DMA_TO_DEVICE) - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - else - bpl->tus.f.bdeFlags = BUFF_TYPE_BDE_64I; - bpl->tus.w = le32_to_cpu(bpl->tus.w); - - num_bde++; - curr_data++; - - if (split_offset) - break; - - /* Move to the next s/g segment if possible */ - sgde = sg_next(sgde); - - } - - if (protgroup_offset) { - /* update the reference tag */ - reftag += protgrp_blks; - bpl++; - continue; - } - - /* are we done ? */ - if (curr_prot == protcnt) { - alldone = 1; - } else if (curr_prot < protcnt) { - /* advance to next prot buffer */ - sgpe = sg_next(sgpe); - bpl++; - - /* update the reference tag */ - reftag += protgrp_blks; - } else { - /* if we're here, we have a bug */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9054 BLKGRD: bug in %s\n", __func__); - } - - } while (!alldone); -out: - - return num_bde; -} - -/** - * lpfc_bg_setup_sgl - Setup BlockGuard SGL with no protection data - * @phba: The Hba for which this call is being executed. - * @sc: pointer to scsi command we're working on - * @sgl: pointer to buffer list for protection groups - * @datacnt: number of segments of data that have been dma mapped - * - * This function sets up SGL buffer list for protection groups of - * type LPFC_PG_TYPE_NO_DIF - * - * This is usually used when the HBA is instructed to generate - * DIFs and insert them into data stream (or strip DIF from - * incoming data stream) - * - * The buffer list consists of just one protection group described - * below: - * +-------------------------+ - * start of prot group --> | DI_SEED | - * +-------------------------+ - * | Data SGE | - * +-------------------------+ - * |more Data SGE's ... (opt)| - * +-------------------------+ - * - * - * Note: Data s/g buffers have been dma mapped - * - * Returns the number of SGEs added to the SGL. - **/ -static int -lpfc_bg_setup_sgl(struct lpfc_hba *phba, struct scsi_cmnd *sc, - struct sli4_sge *sgl, int datasegcnt) -{ - struct scatterlist *sgde = NULL; /* s/g data entry */ - struct sli4_sge_diseed *diseed = NULL; - dma_addr_t physaddr; - int i = 0, num_sge = 0, status; - int datadir = sc->sc_data_direction; - uint32_t reftag; - unsigned blksize; - uint8_t txop, rxop; - uint32_t rc; - uint32_t checking = 1; - uint32_t dma_len; - uint32_t dma_offset = 0; - - status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); - if (status) - goto out; - - /* extract some info from the scsi command for pde*/ - blksize = lpfc_cmd_blksize(sc); - reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); - if (rc) { - if (rc & BG_ERR_SWAP) - lpfc_bg_err_opcodes(phba, sc, &txop, &rxop); - if (rc & BG_ERR_CHECK) - checking = 0; - } -#endif - - /* setup DISEED with what we have */ - diseed = (struct sli4_sge_diseed *) sgl; - memset(diseed, 0, sizeof(struct sli4_sge_diseed)); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DISEED); - - /* Endianness conversion if necessary */ - diseed->ref_tag = cpu_to_le32(reftag); - diseed->ref_tag_tran = diseed->ref_tag; - - /* setup DISEED with the rest of the info */ - bf_set(lpfc_sli4_sge_dif_optx, diseed, txop); - bf_set(lpfc_sli4_sge_dif_oprx, diseed, rxop); - if (datadir == DMA_FROM_DEVICE) { - bf_set(lpfc_sli4_sge_dif_ce, diseed, checking); - bf_set(lpfc_sli4_sge_dif_re, diseed, checking); - } - bf_set(lpfc_sli4_sge_dif_ai, diseed, 1); - bf_set(lpfc_sli4_sge_dif_me, diseed, 0); - - /* Endianness conversion if necessary for DISEED */ - diseed->word2 = cpu_to_le32(diseed->word2); - diseed->word3 = cpu_to_le32(diseed->word3); - - /* advance bpl and increment sge count */ - num_sge++; - sgl++; - - /* assumption: caller has already run dma_map_sg on command data */ - scsi_for_each_sg(sc, sgde, datasegcnt, i) { - physaddr = sg_dma_address(sgde); - dma_len = sg_dma_len(sgde); - sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr)); - sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr)); - if ((i + 1) == datasegcnt) - bf_set(lpfc_sli4_sge_last, sgl, 1); - else - bf_set(lpfc_sli4_sge_last, sgl, 0); - bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); - - sgl->sge_len = cpu_to_le32(dma_len); - dma_offset += dma_len; - - sgl++; - num_sge++; - } - -out: - return num_sge; -} - -/** - * lpfc_bg_setup_sgl_prot - Setup BlockGuard SGL with protection data - * @phba: The Hba for which this call is being executed. - * @sc: pointer to scsi command we're working on - * @sgl: pointer to buffer list for protection groups - * @datacnt: number of segments of data that have been dma mapped - * @protcnt: number of segment of protection data that have been dma mapped - * - * This function sets up SGL buffer list for protection groups of - * type LPFC_PG_TYPE_DIF - * - * This is usually used when DIFs are in their own buffers, - * separate from the data. The HBA can then by instructed - * to place the DIFs in the outgoing stream. For read operations, - * The HBA could extract the DIFs and place it in DIF buffers. - * - * The buffer list for this type consists of one or more of the - * protection groups described below: - * +-------------------------+ - * start of first prot group --> | DISEED | - * +-------------------------+ - * | DIF (Prot SGE) | - * +-------------------------+ - * | Data SGE | - * +-------------------------+ - * |more Data SGE's ... (opt)| - * +-------------------------+ - * start of new prot group --> | DISEED | - * +-------------------------+ - * | ... | - * +-------------------------+ - * - * Note: It is assumed that both data and protection s/g buffers have been - * mapped for DMA - * - * Returns the number of SGEs added to the SGL. - **/ -static int -lpfc_bg_setup_sgl_prot(struct lpfc_hba *phba, struct scsi_cmnd *sc, - struct sli4_sge *sgl, int datacnt, int protcnt) -{ - struct scatterlist *sgde = NULL; /* s/g data entry */ - struct scatterlist *sgpe = NULL; /* s/g prot entry */ - struct sli4_sge_diseed *diseed = NULL; - dma_addr_t dataphysaddr, protphysaddr; - unsigned short curr_data = 0, curr_prot = 0; - unsigned int split_offset; - unsigned int protgroup_len, protgroup_offset = 0, protgroup_remainder; - unsigned int protgrp_blks, protgrp_bytes; - unsigned int remainder, subtotal; - int status; - unsigned char pgdone = 0, alldone = 0; - unsigned blksize; - uint32_t reftag; - uint8_t txop, rxop; - uint32_t dma_len; - uint32_t rc; - uint32_t checking = 1; - uint32_t dma_offset = 0; - int num_sge = 0; - - sgpe = scsi_prot_sglist(sc); - sgde = scsi_sglist(sc); - - if (!sgpe || !sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9082 Invalid s/g entry: data=0x%p prot=0x%p\n", - sgpe, sgde); - return 0; - } - - status = lpfc_sc_to_bg_opcodes(phba, sc, &txop, &rxop); - if (status) - goto out; - - /* extract some info from the scsi command */ - blksize = lpfc_cmd_blksize(sc); - reftag = (uint32_t)scsi_get_lba(sc); /* Truncate LBA */ - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - rc = lpfc_bg_err_inject(phba, sc, &reftag, NULL, 1); - if (rc) { - if (rc & BG_ERR_SWAP) - lpfc_bg_err_opcodes(phba, sc, &txop, &rxop); - if (rc & BG_ERR_CHECK) - checking = 0; - } -#endif - - split_offset = 0; - do { - /* setup DISEED with what we have */ - diseed = (struct sli4_sge_diseed *) sgl; - memset(diseed, 0, sizeof(struct sli4_sge_diseed)); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DISEED); - - /* Endianness conversion if necessary */ - diseed->ref_tag = cpu_to_le32(reftag); - diseed->ref_tag_tran = diseed->ref_tag; - - /* setup DISEED with the rest of the info */ - bf_set(lpfc_sli4_sge_dif_optx, diseed, txop); - bf_set(lpfc_sli4_sge_dif_oprx, diseed, rxop); - bf_set(lpfc_sli4_sge_dif_ce, diseed, checking); - bf_set(lpfc_sli4_sge_dif_re, diseed, checking); - bf_set(lpfc_sli4_sge_dif_ai, diseed, 1); - bf_set(lpfc_sli4_sge_dif_me, diseed, 0); - - /* Endianness conversion if necessary for DISEED */ - diseed->word2 = cpu_to_le32(diseed->word2); - diseed->word3 = cpu_to_le32(diseed->word3); - - /* advance sgl and increment bde count */ - num_sge++; - sgl++; - - /* setup the first BDE that points to protection buffer */ - protphysaddr = sg_dma_address(sgpe) + protgroup_offset; - protgroup_len = sg_dma_len(sgpe) - protgroup_offset; - - /* must be integer multiple of the DIF block length */ - BUG_ON(protgroup_len % 8); - - /* Now setup DIF SGE */ - sgl->word2 = 0; - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DIF); - sgl->addr_hi = le32_to_cpu(putPaddrHigh(protphysaddr)); - sgl->addr_lo = le32_to_cpu(putPaddrLow(protphysaddr)); - sgl->word2 = cpu_to_le32(sgl->word2); - - protgrp_blks = protgroup_len / 8; - protgrp_bytes = protgrp_blks * blksize; - - /* check if DIF SGE is crossing the 4K boundary; if so split */ - if ((sgl->addr_lo & 0xfff) + protgroup_len > 0x1000) { - protgroup_remainder = 0x1000 - (sgl->addr_lo & 0xfff); - protgroup_offset += protgroup_remainder; - protgrp_blks = protgroup_remainder / 8; - protgrp_bytes = protgrp_blks * blksize; - } else { - protgroup_offset = 0; - curr_prot++; - } - - num_sge++; - - /* setup SGE's for data blocks associated with DIF data */ - pgdone = 0; - subtotal = 0; /* total bytes processed for current prot grp */ - while (!pgdone) { - if (!sgde) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9086 BLKGRD:%s Invalid data segment\n", - __func__); - return 0; - } - sgl++; - dataphysaddr = sg_dma_address(sgde) + split_offset; - - remainder = sg_dma_len(sgde) - split_offset; - - if ((subtotal + remainder) <= protgrp_bytes) { - /* we can use this whole buffer */ - dma_len = remainder; - split_offset = 0; - - if ((subtotal + remainder) == protgrp_bytes) - pgdone = 1; - } else { - /* must split this buffer with next prot grp */ - dma_len = protgrp_bytes - subtotal; - split_offset += dma_len; - } - - subtotal += dma_len; - - sgl->addr_lo = cpu_to_le32(putPaddrLow(dataphysaddr)); - sgl->addr_hi = cpu_to_le32(putPaddrHigh(dataphysaddr)); - bf_set(lpfc_sli4_sge_last, sgl, 0); - bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); - - sgl->sge_len = cpu_to_le32(dma_len); - dma_offset += dma_len; - - num_sge++; - curr_data++; - - if (split_offset) - break; - - /* Move to the next s/g segment if possible */ - sgde = sg_next(sgde); - } - - if (protgroup_offset) { - /* update the reference tag */ - reftag += protgrp_blks; - sgl++; - continue; - } - - /* are we done ? */ - if (curr_prot == protcnt) { - bf_set(lpfc_sli4_sge_last, sgl, 1); - alldone = 1; - } else if (curr_prot < protcnt) { - /* advance to next prot buffer */ - sgpe = sg_next(sgpe); - sgl++; - - /* update the reference tag */ - reftag += protgrp_blks; - } else { - /* if we're here, we have a bug */ - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9085 BLKGRD: bug in %s\n", __func__); - } - - } while (!alldone); - -out: - - return num_sge; -} - -/** - * lpfc_prot_group_type - Get prtotection group type of SCSI command - * @phba: The Hba for which this call is being executed. - * @sc: pointer to scsi command we're working on - * - * Given a SCSI command that supports DIF, determine composition of protection - * groups involved in setting up buffer lists - * - * Returns: Protection group type (with or without DIF) - * - **/ -static int -lpfc_prot_group_type(struct lpfc_hba *phba, struct scsi_cmnd *sc) -{ - int ret = LPFC_PG_TYPE_INVALID; - unsigned char op = scsi_get_prot_op(sc); - - switch (op) { - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_WRITE_INSERT: - ret = LPFC_PG_TYPE_NO_DIF; - break; - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_WRITE_STRIP: - case SCSI_PROT_READ_PASS: - case SCSI_PROT_WRITE_PASS: - ret = LPFC_PG_TYPE_DIF_BUF; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9021 Unsupported protection op:%d\n", op); - break; - } - - return ret; -} - -/** - * lpfc_bg_scsi_prep_dma_buf_s3 - DMA mapping for scsi buffer to SLI3 IF spec - * @phba: The Hba for which this call is being executed. - * @lpfc_cmd: The scsi buffer which is going to be prep'ed. - * - * This is the protection/DIF aware version of - * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the - * two functions eventually, but for now, it's here - **/ -static int -lpfc_bg_scsi_prep_dma_buf_s3(struct lpfc_hba *phba, - struct lpfc_scsi_buf *lpfc_cmd) -{ - struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; - struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; - struct ulp_bde64 *bpl = lpfc_cmd->fcp_bpl; - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; - uint32_t num_bde = 0; - int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction; - int prot_group_type = 0; - int diflen, fcpdl; - unsigned blksize; - - /* - * Start the lpfc command prep by bumping the bpl beyond fcp_cmnd - * fcp_rsp regions to the first data bde entry - */ - bpl += 2; - if (scsi_sg_count(scsi_cmnd)) { - /* - * The driver stores the segment count returned from pci_map_sg - * because this a count of dma-mappings used to map the use_sg - * pages. They are not guaranteed to be the same for those - * architectures that implement an IOMMU. - */ - datasegcnt = dma_map_sg(&phba->pcidev->dev, - scsi_sglist(scsi_cmnd), - scsi_sg_count(scsi_cmnd), datadir); - if (unlikely(!datasegcnt)) - return 1; - - lpfc_cmd->seg_cnt = datasegcnt; - if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9067 BLKGRD: %s: Too many sg segments" - " from dma_map_sg. Config %d, seg_cnt" - " %d\n", - __func__, phba->cfg_sg_seg_cnt, - lpfc_cmd->seg_cnt); - scsi_dma_unmap(scsi_cmnd); - return 1; - } - - prot_group_type = lpfc_prot_group_type(phba, scsi_cmnd); - - switch (prot_group_type) { - case LPFC_PG_TYPE_NO_DIF: - num_bde = lpfc_bg_setup_bpl(phba, scsi_cmnd, bpl, - datasegcnt); - /* we should have 2 or more entries in buffer list */ - if (num_bde < 2) - goto err; - break; - case LPFC_PG_TYPE_DIF_BUF:{ - /* - * This type indicates that protection buffers are - * passed to the driver, so that needs to be prepared - * for DMA - */ - protsegcnt = dma_map_sg(&phba->pcidev->dev, - scsi_prot_sglist(scsi_cmnd), - scsi_prot_sg_count(scsi_cmnd), datadir); - if (unlikely(!protsegcnt)) { - scsi_dma_unmap(scsi_cmnd); - return 1; - } - - lpfc_cmd->prot_seg_cnt = protsegcnt; - if (lpfc_cmd->prot_seg_cnt - > phba->cfg_prot_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9068 BLKGRD: %s: Too many prot sg " - "segments from dma_map_sg. Config %d," - "prot_seg_cnt %d\n", __func__, - phba->cfg_prot_sg_seg_cnt, - lpfc_cmd->prot_seg_cnt); - dma_unmap_sg(&phba->pcidev->dev, - scsi_prot_sglist(scsi_cmnd), - scsi_prot_sg_count(scsi_cmnd), - datadir); - scsi_dma_unmap(scsi_cmnd); - return 1; - } - - num_bde = lpfc_bg_setup_bpl_prot(phba, scsi_cmnd, bpl, - datasegcnt, protsegcnt); - /* we should have 3 or more entries in buffer list */ - if (num_bde < 3) - goto err; - break; - } - case LPFC_PG_TYPE_INVALID: - default: - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9022 Unexpected protection group %i\n", - prot_group_type); - return 1; - } - } - - /* - * Finish initializing those IOCB fields that are dependent on the - * scsi_cmnd request_buffer. Note that the bdeSize is explicitly - * reinitialized since all iocb memory resources are used many times - * for transmit, receive, and continuation bpl's. - */ - iocb_cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof(struct ulp_bde64)); - iocb_cmd->un.fcpi64.bdl.bdeSize += (num_bde * sizeof(struct ulp_bde64)); - iocb_cmd->ulpBdeCount = 1; - iocb_cmd->ulpLe = 1; - - fcpdl = scsi_bufflen(scsi_cmnd); - - if (scsi_get_prot_type(scsi_cmnd) == SCSI_PROT_DIF_TYPE1) { - /* - * We are in DIF Type 1 mode - * Every data block has a 8 byte DIF (trailer) - * attached to it. Must ajust FCP data length - */ - blksize = lpfc_cmd_blksize(scsi_cmnd); - diflen = (fcpdl / blksize) * 8; - fcpdl += diflen; - } - fcp_cmnd->fcpDl = be32_to_cpu(fcpdl); - - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of IOCB here - */ - iocb_cmd->un.fcpi.fcpi_parm = fcpdl; - - return 0; -err: - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9023 Could not setup all needed BDE's" - "prot_group_type=%d, num_bde=%d\n", - prot_group_type, num_bde); - return 1; -} - -/* - * This function checks for BlockGuard errors detected by - * the HBA. In case of errors, the ASC/ASCQ fields in the - * sense buffer will be set accordingly, paired with - * ILLEGAL_REQUEST to signal to the kernel that the HBA - * detected corruption. - * - * Returns: - * 0 - No error found - * 1 - BlockGuard error found - * -1 - Internal error (bad profile, ...etc) - */ -static int -lpfc_parse_bg_err(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd, - struct lpfc_iocbq *pIocbOut) -{ - struct scsi_cmnd *cmd = lpfc_cmd->pCmd; - struct sli3_bg_fields *bgf = &pIocbOut->iocb.unsli3.sli3_bg; - int ret = 0; - uint32_t bghm = bgf->bghm; - uint32_t bgstat = bgf->bgstat; - uint64_t failing_sector = 0; - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9069 BLKGRD: BG ERROR in cmd" - " 0x%x lba 0x%llx blk cnt 0x%x " - "bgstat=0x%x bghm=0x%x\n", - cmd->cmnd[0], (unsigned long long)scsi_get_lba(cmd), - blk_rq_sectors(cmd->request), bgstat, bghm); - - spin_lock(&_dump_buf_lock); - if (!_dump_buf_done) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9070 BLKGRD: Saving" - " Data for %u blocks to debugfs\n", - (cmd->cmnd[7] << 8 | cmd->cmnd[8])); - lpfc_debug_save_data(phba, cmd); - - /* If we have a prot sgl, save the DIF buffer */ - if (lpfc_prot_group_type(phba, cmd) == - LPFC_PG_TYPE_DIF_BUF) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9071 BLKGRD: " - "Saving DIF for %u blocks to debugfs\n", - (cmd->cmnd[7] << 8 | cmd->cmnd[8])); - lpfc_debug_save_dif(phba, cmd); - } - - _dump_buf_done = 1; - } - spin_unlock(&_dump_buf_lock); - - if (lpfc_bgs_get_invalid_prof(bgstat)) { - cmd->result = ScsiResult(DID_ERROR, 0); - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9072 BLKGRD: Invalid" - " BlockGuard profile. bgstat:0x%x\n", - bgstat); - ret = (-1); - goto out; - } - - if (lpfc_bgs_get_uninit_dif_block(bgstat)) { - cmd->result = ScsiResult(DID_ERROR, 0); - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9073 BLKGRD: " - "Invalid BlockGuard DIF Block. bgstat:0x%x\n", - bgstat); - ret = (-1); - goto out; - } - - if (lpfc_bgs_get_guard_err(bgstat)) { - ret = 1; - - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x1); - cmd->result = DRIVER_SENSE << 24 - | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); - phba->bg_guard_err_cnt++; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9055 BLKGRD: guard_tag error\n"); - } - - if (lpfc_bgs_get_reftag_err(bgstat)) { - ret = 1; - - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x3); - cmd->result = DRIVER_SENSE << 24 - | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); - - phba->bg_reftag_err_cnt++; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9056 BLKGRD: ref_tag error\n"); - } - - if (lpfc_bgs_get_apptag_err(bgstat)) { - ret = 1; - - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x2); - cmd->result = DRIVER_SENSE << 24 - | ScsiResult(DID_ABORT, SAM_STAT_CHECK_CONDITION); - - phba->bg_apptag_err_cnt++; - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9061 BLKGRD: app_tag error\n"); - } - - if (lpfc_bgs_get_hi_water_mark_present(bgstat)) { - /* - * setup sense data descriptor 0 per SPC-4 as an information - * field, and put the failing LBA in it. - * This code assumes there was also a guard/app/ref tag error - * indication. - */ - cmd->sense_buffer[7] = 0xc; /* Additional sense length */ - cmd->sense_buffer[8] = 0; /* Information descriptor type */ - cmd->sense_buffer[9] = 0xa; /* Additional descriptor length */ - cmd->sense_buffer[10] = 0x80; /* Validity bit */ - - /* bghm is a "on the wire" FC frame based count */ - switch (scsi_get_prot_op(cmd)) { - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_WRITE_STRIP: - bghm /= cmd->device->sector_size; - break; - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_WRITE_INSERT: - case SCSI_PROT_READ_PASS: - case SCSI_PROT_WRITE_PASS: - bghm /= (cmd->device->sector_size + - sizeof(struct scsi_dif_tuple)); - break; - } - - failing_sector = scsi_get_lba(cmd); - failing_sector += bghm; - - /* Descriptor Information */ - put_unaligned_be64(failing_sector, &cmd->sense_buffer[12]); - } - - if (!ret) { - /* No error was reported - problem in FW? */ - cmd->result = ScsiResult(DID_ERROR, 0); - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9057 BLKGRD: Unknown error reported!\n"); - } - -out: - return ret; -} - -/** - * lpfc_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec - * @phba: The Hba for which this call is being executed. - * @lpfc_cmd: The scsi buffer which is going to be mapped. - * - * This routine does the pci dma mapping for scatter-gather list of scsi cmnd - * field of @lpfc_cmd for device with SLI-4 interface spec. - * - * Return codes: - * 1 - Error - * 0 - Success - **/ -static int -lpfc_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) -{ - struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; - struct scatterlist *sgel = NULL; - struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; - struct sli4_sge *sgl = (struct sli4_sge *)lpfc_cmd->fcp_bpl; - struct sli4_sge *first_data_sgl; - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; - dma_addr_t physaddr; - uint32_t num_bde = 0; - uint32_t dma_len; - uint32_t dma_offset = 0; - int nseg; - struct ulp_bde64 *bde; - - /* - * There are three possibilities here - use scatter-gather segment, use - * the single mapping, or neither. Start the lpfc command prep by - * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first - * data bde entry. - */ - if (scsi_sg_count(scsi_cmnd)) { - /* - * The driver stores the segment count returned from pci_map_sg - * because this a count of dma-mappings used to map the use_sg - * pages. They are not guaranteed to be the same for those - * architectures that implement an IOMMU. - */ - - nseg = scsi_dma_map(scsi_cmnd); - if (unlikely(!nseg)) - return 1; - sgl += 1; - /* clear the last flag in the fcp_rsp map entry */ - sgl->word2 = le32_to_cpu(sgl->word2); - bf_set(lpfc_sli4_sge_last, sgl, 0); - sgl->word2 = cpu_to_le32(sgl->word2); - sgl += 1; - first_data_sgl = sgl; - lpfc_cmd->seg_cnt = nseg; - if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, "9074 BLKGRD:" - " %s: Too many sg segments from " - "dma_map_sg. Config %d, seg_cnt %d\n", - __func__, phba->cfg_sg_seg_cnt, - lpfc_cmd->seg_cnt); - scsi_dma_unmap(scsi_cmnd); - return 1; - } - - /* - * The driver established a maximum scatter-gather segment count - * during probe that limits the number of sg elements in any - * single scsi command. Just run through the seg_cnt and format - * the sge's. - * When using SLI-3 the driver will try to fit all the BDEs into - * the IOCB. If it can't then the BDEs get added to a BPL as it - * does for SLI-2 mode. - */ - scsi_for_each_sg(scsi_cmnd, sgel, nseg, num_bde) { - physaddr = sg_dma_address(sgel); - dma_len = sg_dma_len(sgel); - sgl->addr_lo = cpu_to_le32(putPaddrLow(physaddr)); - sgl->addr_hi = cpu_to_le32(putPaddrHigh(physaddr)); - sgl->word2 = le32_to_cpu(sgl->word2); - if ((num_bde + 1) == nseg) - bf_set(lpfc_sli4_sge_last, sgl, 1); - else - bf_set(lpfc_sli4_sge_last, sgl, 0); - bf_set(lpfc_sli4_sge_offset, sgl, dma_offset); - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); - sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32(dma_len); - dma_offset += dma_len; - sgl++; - } - /* setup the performance hint (first data BDE) if enabled */ - if (phba->sli3_options & LPFC_SLI4_PERFH_ENABLED) { - bde = (struct ulp_bde64 *) - &(iocb_cmd->unsli3.sli3Words[5]); - bde->addrLow = first_data_sgl->addr_lo; - bde->addrHigh = first_data_sgl->addr_hi; - bde->tus.f.bdeSize = - le32_to_cpu(first_data_sgl->sge_len); - bde->tus.f.bdeFlags = BUFF_TYPE_BDE_64; - bde->tus.w = cpu_to_le32(bde->tus.w); - } - } else { - sgl += 1; - /* clear the last flag in the fcp_rsp map entry */ - sgl->word2 = le32_to_cpu(sgl->word2); - bf_set(lpfc_sli4_sge_last, sgl, 1); - sgl->word2 = cpu_to_le32(sgl->word2); - } - - /* - * Finish initializing those IOCB fields that are dependent on the - * scsi_cmnd request_buffer. Note that for SLI-2 the bdeSize is - * explicitly reinitialized. - * all iocb memory resources are reused. - */ - fcp_cmnd->fcpDl = cpu_to_be32(scsi_bufflen(scsi_cmnd)); - - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of IOCB here - */ - iocb_cmd->un.fcpi.fcpi_parm = scsi_bufflen(scsi_cmnd); - return 0; -} - -/** - * lpfc_bg_scsi_adjust_dl - Adjust SCSI data length for BlockGuard - * @phba: The Hba for which this call is being executed. - * @lpfc_cmd: The scsi buffer which is going to be adjusted. - * - * Adjust the data length to account for how much data - * is actually on the wire. - * - * returns the adjusted data length - **/ -static int -lpfc_bg_scsi_adjust_dl(struct lpfc_hba *phba, - struct lpfc_scsi_buf *lpfc_cmd) -{ - struct scsi_cmnd *sc = lpfc_cmd->pCmd; - int diflen, fcpdl; - unsigned blksize; - - fcpdl = scsi_bufflen(sc); - - /* Check if there is protection data on the wire */ - if (sc->sc_data_direction == DMA_FROM_DEVICE) { - /* Read */ - if (scsi_get_prot_op(sc) == SCSI_PROT_READ_INSERT) - return fcpdl; - - } else { - /* Write */ - if (scsi_get_prot_op(sc) == SCSI_PROT_WRITE_STRIP) - return fcpdl; - } - - /* If protection data on the wire, adjust the count accordingly */ - blksize = lpfc_cmd_blksize(sc); - diflen = (fcpdl / blksize) * 8; - fcpdl += diflen; - return fcpdl; -} - -/** - * lpfc_bg_scsi_prep_dma_buf_s4 - DMA mapping for scsi buffer to SLI4 IF spec - * @phba: The Hba for which this call is being executed. - * @lpfc_cmd: The scsi buffer which is going to be mapped. - * - * This is the protection/DIF aware version of - * lpfc_scsi_prep_dma_buf(). It may be a good idea to combine the - * two functions eventually, but for now, it's here - **/ -static int -lpfc_bg_scsi_prep_dma_buf_s4(struct lpfc_hba *phba, - struct lpfc_scsi_buf *lpfc_cmd) -{ - struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; - struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; - struct sli4_sge *sgl = (struct sli4_sge *)(lpfc_cmd->fcp_bpl); - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; - uint32_t num_bde = 0; - int datasegcnt, protsegcnt, datadir = scsi_cmnd->sc_data_direction; - int prot_group_type = 0; - int fcpdl; - - /* - * Start the lpfc command prep by bumping the sgl beyond fcp_cmnd - * fcp_rsp regions to the first data bde entry - */ - if (scsi_sg_count(scsi_cmnd)) { - /* - * The driver stores the segment count returned from pci_map_sg - * because this a count of dma-mappings used to map the use_sg - * pages. They are not guaranteed to be the same for those - * architectures that implement an IOMMU. - */ - datasegcnt = dma_map_sg(&phba->pcidev->dev, - scsi_sglist(scsi_cmnd), - scsi_sg_count(scsi_cmnd), datadir); - if (unlikely(!datasegcnt)) - return 1; - - sgl += 1; - /* clear the last flag in the fcp_rsp map entry */ - sgl->word2 = le32_to_cpu(sgl->word2); - bf_set(lpfc_sli4_sge_last, sgl, 0); - sgl->word2 = cpu_to_le32(sgl->word2); - - sgl += 1; - lpfc_cmd->seg_cnt = datasegcnt; - if (lpfc_cmd->seg_cnt > phba->cfg_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9087 BLKGRD: %s: Too many sg segments" - " from dma_map_sg. Config %d, seg_cnt" - " %d\n", - __func__, phba->cfg_sg_seg_cnt, - lpfc_cmd->seg_cnt); - scsi_dma_unmap(scsi_cmnd); - return 1; - } - - prot_group_type = lpfc_prot_group_type(phba, scsi_cmnd); - - switch (prot_group_type) { - case LPFC_PG_TYPE_NO_DIF: - num_bde = lpfc_bg_setup_sgl(phba, scsi_cmnd, sgl, - datasegcnt); - /* we should have 2 or more entries in buffer list */ - if (num_bde < 2) - goto err; - break; - case LPFC_PG_TYPE_DIF_BUF:{ - /* - * This type indicates that protection buffers are - * passed to the driver, so that needs to be prepared - * for DMA - */ - protsegcnt = dma_map_sg(&phba->pcidev->dev, - scsi_prot_sglist(scsi_cmnd), - scsi_prot_sg_count(scsi_cmnd), datadir); - if (unlikely(!protsegcnt)) { - scsi_dma_unmap(scsi_cmnd); - return 1; - } - - lpfc_cmd->prot_seg_cnt = protsegcnt; - if (lpfc_cmd->prot_seg_cnt - > phba->cfg_prot_sg_seg_cnt) { - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9088 BLKGRD: %s: Too many prot sg " - "segments from dma_map_sg. Config %d," - "prot_seg_cnt %d\n", __func__, - phba->cfg_prot_sg_seg_cnt, - lpfc_cmd->prot_seg_cnt); - dma_unmap_sg(&phba->pcidev->dev, - scsi_prot_sglist(scsi_cmnd), - scsi_prot_sg_count(scsi_cmnd), - datadir); - scsi_dma_unmap(scsi_cmnd); - return 1; - } - - num_bde = lpfc_bg_setup_sgl_prot(phba, scsi_cmnd, sgl, - datasegcnt, protsegcnt); - /* we should have 3 or more entries in buffer list */ - if (num_bde < 3) - goto err; - break; - } - case LPFC_PG_TYPE_INVALID: - default: - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9083 Unexpected protection group %i\n", - prot_group_type); - return 1; - } - } - - fcpdl = lpfc_bg_scsi_adjust_dl(phba, lpfc_cmd); - - fcp_cmnd->fcpDl = be32_to_cpu(fcpdl); - - /* - * Due to difference in data length between DIF/non-DIF paths, - * we need to set word 4 of IOCB here - */ - iocb_cmd->un.fcpi.fcpi_parm = fcpdl; - lpfc_cmd->cur_iocbq.iocb_flag |= LPFC_IO_DIF; - - return 0; -err: - lpfc_printf_log(phba, KERN_ERR, LOG_FCP, - "9084 Could not setup all needed BDE's" - "prot_group_type=%d, num_bde=%d\n", - prot_group_type, num_bde); - return 1; -} - -/** - * lpfc_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer - * @phba: The Hba for which this call is being executed. - * @lpfc_cmd: The scsi buffer which is going to be mapped. - * - * This routine wraps the actual DMA mapping function pointer from the - * lpfc_hba struct. - * - * Return codes: - * 1 - Error - * 0 - Success - **/ -static inline int -lpfc_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) -{ - return phba->lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); -} - -/** - * lpfc_bg_scsi_prep_dma_buf - Wrapper function for DMA mapping of scsi buffer - * using BlockGuard. - * @phba: The Hba for which this call is being executed. - * @lpfc_cmd: The scsi buffer which is going to be mapped. - * - * This routine wraps the actual DMA mapping function pointer from the - * lpfc_hba struct. - * - * Return codes: - * 1 - Error - * 0 - Success - **/ -static inline int -lpfc_bg_scsi_prep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd) -{ - return phba->lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); -} - -/** - * lpfc_send_scsi_error_event - Posts an event when there is SCSI error - * @phba: Pointer to hba context object. - * @vport: Pointer to vport object. - * @lpfc_cmd: Pointer to lpfc scsi command which reported the error. - * @rsp_iocb: Pointer to response iocb object which reported error. - * - * This function posts an event when there is a SCSI command reporting - * error from the scsi device. - **/ -static void -lpfc_send_scsi_error_event(struct lpfc_hba *phba, struct lpfc_vport *vport, - struct lpfc_scsi_buf *lpfc_cmd, struct lpfc_iocbq *rsp_iocb) { - struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; - struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; - uint32_t resp_info = fcprsp->rspStatus2; - uint32_t scsi_status = fcprsp->rspStatus3; - uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; - struct lpfc_fast_path_event *fast_path_evt = NULL; - struct lpfc_nodelist *pnode = lpfc_cmd->rdata->pnode; - unsigned long flags; - - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return; - - /* If there is queuefull or busy condition send a scsi event */ - if ((cmnd->result == SAM_STAT_TASK_SET_FULL) || - (cmnd->result == SAM_STAT_BUSY)) { - fast_path_evt = lpfc_alloc_fast_evt(phba); - if (!fast_path_evt) - return; - fast_path_evt->un.scsi_evt.event_type = - FC_REG_SCSI_EVENT; - fast_path_evt->un.scsi_evt.subcategory = - (cmnd->result == SAM_STAT_TASK_SET_FULL) ? - LPFC_EVENT_QFULL : LPFC_EVENT_DEVBSY; - fast_path_evt->un.scsi_evt.lun = cmnd->device->lun; - memcpy(&fast_path_evt->un.scsi_evt.wwpn, - &pnode->nlp_portname, sizeof(struct lpfc_name)); - memcpy(&fast_path_evt->un.scsi_evt.wwnn, - &pnode->nlp_nodename, sizeof(struct lpfc_name)); - } else if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen && - ((cmnd->cmnd[0] == READ_10) || (cmnd->cmnd[0] == WRITE_10))) { - fast_path_evt = lpfc_alloc_fast_evt(phba); - if (!fast_path_evt) - return; - fast_path_evt->un.check_cond_evt.scsi_event.event_type = - FC_REG_SCSI_EVENT; - fast_path_evt->un.check_cond_evt.scsi_event.subcategory = - LPFC_EVENT_CHECK_COND; - fast_path_evt->un.check_cond_evt.scsi_event.lun = - cmnd->device->lun; - memcpy(&fast_path_evt->un.check_cond_evt.scsi_event.wwpn, - &pnode->nlp_portname, sizeof(struct lpfc_name)); - memcpy(&fast_path_evt->un.check_cond_evt.scsi_event.wwnn, - &pnode->nlp_nodename, sizeof(struct lpfc_name)); - fast_path_evt->un.check_cond_evt.sense_key = - cmnd->sense_buffer[2] & 0xf; - fast_path_evt->un.check_cond_evt.asc = cmnd->sense_buffer[12]; - fast_path_evt->un.check_cond_evt.ascq = cmnd->sense_buffer[13]; - } else if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) && - fcpi_parm && - ((be32_to_cpu(fcprsp->rspResId) != fcpi_parm) || - ((scsi_status == SAM_STAT_GOOD) && - !(resp_info & (RESID_UNDER | RESID_OVER))))) { - /* - * If status is good or resid does not match with fcp_param and - * there is valid fcpi_parm, then there is a read_check error - */ - fast_path_evt = lpfc_alloc_fast_evt(phba); - if (!fast_path_evt) - return; - fast_path_evt->un.read_check_error.header.event_type = - FC_REG_FABRIC_EVENT; - fast_path_evt->un.read_check_error.header.subcategory = - LPFC_EVENT_FCPRDCHKERR; - memcpy(&fast_path_evt->un.read_check_error.header.wwpn, - &pnode->nlp_portname, sizeof(struct lpfc_name)); - memcpy(&fast_path_evt->un.read_check_error.header.wwnn, - &pnode->nlp_nodename, sizeof(struct lpfc_name)); - fast_path_evt->un.read_check_error.lun = cmnd->device->lun; - fast_path_evt->un.read_check_error.opcode = cmnd->cmnd[0]; - fast_path_evt->un.read_check_error.fcpiparam = - fcpi_parm; - } else - return; - - fast_path_evt->vport = vport; - spin_lock_irqsave(&phba->hbalock, flags); - list_add_tail(&fast_path_evt->work_evt.evt_listp, &phba->work_list); - spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_worker_wake_up(phba); - return; -} - -/** - * lpfc_scsi_unprep_dma_buf - Un-map DMA mapping of SG-list for dev - * @phba: The HBA for which this call is being executed. - * @psb: The scsi buffer which is going to be un-mapped. - * - * This routine does DMA un-mapping of scatter gather list of scsi command - * field of @lpfc_cmd for device with SLI-3 interface spec. - **/ -static void -lpfc_scsi_unprep_dma_buf(struct lpfc_hba *phba, struct lpfc_scsi_buf *psb) -{ - /* - * There are only two special cases to consider. (1) the scsi command - * requested scatter-gather usage or (2) the scsi command allocated - * a request buffer, but did not request use_sg. There is a third - * case, but it does not require resource deallocation. - */ - if (psb->seg_cnt > 0) - scsi_dma_unmap(psb->pCmd); - if (psb->prot_seg_cnt > 0) - dma_unmap_sg(&phba->pcidev->dev, scsi_prot_sglist(psb->pCmd), - scsi_prot_sg_count(psb->pCmd), - psb->pCmd->sc_data_direction); -} - -/** - * lpfc_handler_fcp_err - FCP response handler - * @vport: The virtual port for which this call is being executed. - * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. - * @rsp_iocb: The response IOCB which contains FCP error. - * - * This routine is called to process response IOCB with status field - * IOSTAT_FCP_RSP_ERROR. This routine sets result field of scsi command - * based upon SCSI and FCP error. - **/ -static void -lpfc_handle_fcp_err(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, - struct lpfc_iocbq *rsp_iocb) -{ - struct scsi_cmnd *cmnd = lpfc_cmd->pCmd; - struct fcp_cmnd *fcpcmd = lpfc_cmd->fcp_cmnd; - struct fcp_rsp *fcprsp = lpfc_cmd->fcp_rsp; - uint32_t fcpi_parm = rsp_iocb->iocb.un.fcpi.fcpi_parm; - uint32_t resp_info = fcprsp->rspStatus2; - uint32_t scsi_status = fcprsp->rspStatus3; - uint32_t *lp; - uint32_t host_status = DID_OK; - uint32_t rsplen = 0; - uint32_t logit = LOG_FCP | LOG_FCP_ERROR; - - - /* - * If this is a task management command, there is no - * scsi packet associated with this lpfc_cmd. The driver - * consumes it. - */ - if (fcpcmd->fcpCntl2) { - scsi_status = 0; - goto out; - } - - if (resp_info & RSP_LEN_VALID) { - rsplen = be32_to_cpu(fcprsp->rspRspLen); - if (rsplen != 0 && rsplen != 4 && rsplen != 8) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "2719 Invalid response length: " - "tgt x%x lun x%x cmnd x%x rsplen x%x\n", - cmnd->device->id, - cmnd->device->lun, cmnd->cmnd[0], - rsplen); - host_status = DID_ERROR; - goto out; - } - if (fcprsp->rspInfo3 != RSP_NO_FAILURE) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "2757 Protocol failure detected during " - "processing of FCP I/O op: " - "tgt x%x lun x%x cmnd x%x rspInfo3 x%x\n", - cmnd->device->id, - cmnd->device->lun, cmnd->cmnd[0], - fcprsp->rspInfo3); - host_status = DID_ERROR; - goto out; - } - } - - if ((resp_info & SNS_LEN_VALID) && fcprsp->rspSnsLen) { - uint32_t snslen = be32_to_cpu(fcprsp->rspSnsLen); - if (snslen > SCSI_SENSE_BUFFERSIZE) - snslen = SCSI_SENSE_BUFFERSIZE; - - if (resp_info & RSP_LEN_VALID) - rsplen = be32_to_cpu(fcprsp->rspRspLen); - memcpy(cmnd->sense_buffer, &fcprsp->rspInfo0 + rsplen, snslen); - } - lp = (uint32_t *)cmnd->sense_buffer; - - if (!scsi_status && (resp_info & RESID_UNDER) && - vport->cfg_log_verbose & LOG_FCP_UNDER) - logit = LOG_FCP_UNDER; - - lpfc_printf_vlog(vport, KERN_WARNING, logit, - "9024 FCP command x%x failed: x%x SNS x%x x%x " - "Data: x%x x%x x%x x%x x%x\n", - cmnd->cmnd[0], scsi_status, - be32_to_cpu(*lp), be32_to_cpu(*(lp + 3)), resp_info, - be32_to_cpu(fcprsp->rspResId), - be32_to_cpu(fcprsp->rspSnsLen), - be32_to_cpu(fcprsp->rspRspLen), - fcprsp->rspInfo3); - - scsi_set_resid(cmnd, 0); - if (resp_info & RESID_UNDER) { - scsi_set_resid(cmnd, be32_to_cpu(fcprsp->rspResId)); - - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP_UNDER, - "9025 FCP Read Underrun, expected %d, " - "residual %d Data: x%x x%x x%x\n", - be32_to_cpu(fcpcmd->fcpDl), - scsi_get_resid(cmnd), fcpi_parm, cmnd->cmnd[0], - cmnd->underflow); - - /* - * If there is an under run check if under run reported by - * storage array is same as the under run reported by HBA. - * If this is not same, there is a dropped frame. - */ - if ((cmnd->sc_data_direction == DMA_FROM_DEVICE) && - fcpi_parm && - (scsi_get_resid(cmnd) != fcpi_parm)) { - lpfc_printf_vlog(vport, KERN_WARNING, - LOG_FCP | LOG_FCP_ERROR, - "9026 FCP Read Check Error " - "and Underrun Data: x%x x%x x%x x%x\n", - be32_to_cpu(fcpcmd->fcpDl), - scsi_get_resid(cmnd), fcpi_parm, - cmnd->cmnd[0]); - scsi_set_resid(cmnd, scsi_bufflen(cmnd)); - host_status = DID_ERROR; - } - /* - * The cmnd->underflow is the minimum number of bytes that must - * be transferred for this command. Provided a sense condition - * is not present, make sure the actual amount transferred is at - * least the underflow value or fail. - */ - if (!(resp_info & SNS_LEN_VALID) && - (scsi_status == SAM_STAT_GOOD) && - (scsi_bufflen(cmnd) - scsi_get_resid(cmnd) - < cmnd->underflow)) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "9027 FCP command x%x residual " - "underrun converted to error " - "Data: x%x x%x x%x\n", - cmnd->cmnd[0], scsi_bufflen(cmnd), - scsi_get_resid(cmnd), cmnd->underflow); - host_status = DID_ERROR; - } - } else if (resp_info & RESID_OVER) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, - "9028 FCP command x%x residual overrun error. " - "Data: x%x x%x\n", cmnd->cmnd[0], - scsi_bufflen(cmnd), scsi_get_resid(cmnd)); - host_status = DID_ERROR; - - /* - * Check SLI validation that all the transfer was actually done - * (fcpi_parm should be zero). Apply check only to reads. - */ - } else if (fcpi_parm && (cmnd->sc_data_direction == DMA_FROM_DEVICE)) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP | LOG_FCP_ERROR, - "9029 FCP Read Check Error Data: " - "x%x x%x x%x x%x x%x\n", - be32_to_cpu(fcpcmd->fcpDl), - be32_to_cpu(fcprsp->rspResId), - fcpi_parm, cmnd->cmnd[0], scsi_status); - switch (scsi_status) { - case SAM_STAT_GOOD: - case SAM_STAT_CHECK_CONDITION: - /* Fabric dropped a data frame. Fail any successful - * command in which we detected dropped frames. - * A status of good or some check conditions could - * be considered a successful command. - */ - host_status = DID_ERROR; - break; - } - scsi_set_resid(cmnd, scsi_bufflen(cmnd)); - } - - out: - cmnd->result = ScsiResult(host_status, scsi_status); - lpfc_send_scsi_error_event(vport->phba, vport, lpfc_cmd, rsp_iocb); -} - -/** - * lpfc_scsi_cmd_iocb_cmpl - Scsi cmnd IOCB completion routine - * @phba: The Hba for which this call is being executed. - * @pIocbIn: The command IOCBQ for the scsi cmnd. - * @pIocbOut: The response IOCBQ for the scsi cmnd. - * - * This routine assigns scsi command result by looking into response IOCB - * status field appropriately. This routine handles QUEUE FULL condition as - * well by ramping down device queue depth. - **/ -static void -lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, - struct lpfc_iocbq *pIocbOut) -{ - struct lpfc_scsi_buf *lpfc_cmd = - (struct lpfc_scsi_buf *) pIocbIn->context1; - struct lpfc_vport *vport = pIocbIn->vport; - struct lpfc_rport_data *rdata = lpfc_cmd->rdata; - struct lpfc_nodelist *pnode = rdata->pnode; - struct scsi_cmnd *cmd; - int result; - struct scsi_device *tmp_sdev; - int depth; - unsigned long flags; - struct lpfc_fast_path_event *fast_path_evt; - struct Scsi_Host *shost; - uint32_t queue_depth, scsi_id; - uint32_t logit = LOG_FCP; - - /* Sanity check on return of outstanding command */ - if (!(lpfc_cmd->pCmd)) - return; - cmd = lpfc_cmd->pCmd; - shost = cmd->device->host; - - lpfc_cmd->result = pIocbOut->iocb.un.ulpWord[4]; - lpfc_cmd->status = pIocbOut->iocb.ulpStatus; - /* pick up SLI4 exhange busy status from HBA */ - lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY; - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (lpfc_cmd->prot_data_type) { - struct scsi_dif_tuple *src = NULL; - - src = (struct scsi_dif_tuple *)lpfc_cmd->prot_data_segment; - /* - * Used to restore any changes to protection - * data for error injection. - */ - switch (lpfc_cmd->prot_data_type) { - case LPFC_INJERR_REFTAG: - src->ref_tag = - lpfc_cmd->prot_data; - break; - case LPFC_INJERR_APPTAG: - src->app_tag = - (uint16_t)lpfc_cmd->prot_data; - break; - case LPFC_INJERR_GUARD: - src->guard_tag = - (uint16_t)lpfc_cmd->prot_data; - break; - default: - break; - } - - lpfc_cmd->prot_data = 0; - lpfc_cmd->prot_data_type = 0; - lpfc_cmd->prot_data_segment = NULL; - } -#endif - if (pnode && NLP_CHK_NODE_ACT(pnode)) - atomic_dec(&pnode->cmd_pending); - - if (lpfc_cmd->status) { - if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && - (lpfc_cmd->result & IOERR_DRVR_MASK)) - lpfc_cmd->status = IOSTAT_DRIVER_REJECT; - else if (lpfc_cmd->status >= IOSTAT_CNT) - lpfc_cmd->status = IOSTAT_DEFAULT; - if (lpfc_cmd->status == IOSTAT_FCP_RSP_ERROR - && !lpfc_cmd->fcp_rsp->rspStatus3 - && (lpfc_cmd->fcp_rsp->rspStatus2 & RESID_UNDER) - && !(phba->cfg_log_verbose & LOG_FCP_UNDER)) - logit = 0; - else - logit = LOG_FCP | LOG_FCP_UNDER; - lpfc_printf_vlog(vport, KERN_WARNING, logit, - "9030 FCP cmd x%x failed <%d/%d> " - "status: x%x result: x%x Data: x%x x%x\n", - cmd->cmnd[0], - cmd->device ? cmd->device->id : 0xffff, - cmd->device ? cmd->device->lun : 0xffff, - lpfc_cmd->status, lpfc_cmd->result, - pIocbOut->iocb.ulpContext, - lpfc_cmd->cur_iocbq.iocb.ulpIoTag); - - switch (lpfc_cmd->status) { - case IOSTAT_FCP_RSP_ERROR: - /* Call FCP RSP handler to determine result */ - lpfc_handle_fcp_err(vport, lpfc_cmd, pIocbOut); - break; - case IOSTAT_NPORT_BSY: - case IOSTAT_FABRIC_BSY: - cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, 0); - fast_path_evt = lpfc_alloc_fast_evt(phba); - if (!fast_path_evt) - break; - fast_path_evt->un.fabric_evt.event_type = - FC_REG_FABRIC_EVENT; - fast_path_evt->un.fabric_evt.subcategory = - (lpfc_cmd->status == IOSTAT_NPORT_BSY) ? - LPFC_EVENT_PORT_BUSY : LPFC_EVENT_FABRIC_BUSY; - if (pnode && NLP_CHK_NODE_ACT(pnode)) { - memcpy(&fast_path_evt->un.fabric_evt.wwpn, - &pnode->nlp_portname, - sizeof(struct lpfc_name)); - memcpy(&fast_path_evt->un.fabric_evt.wwnn, - &pnode->nlp_nodename, - sizeof(struct lpfc_name)); - } - fast_path_evt->vport = vport; - fast_path_evt->work_evt.evt = - LPFC_EVT_FASTPATH_MGMT_EVT; - spin_lock_irqsave(&phba->hbalock, flags); - list_add_tail(&fast_path_evt->work_evt.evt_listp, - &phba->work_list); - spin_unlock_irqrestore(&phba->hbalock, flags); - lpfc_worker_wake_up(phba); - break; - case IOSTAT_LOCAL_REJECT: - case IOSTAT_REMOTE_STOP: - if (lpfc_cmd->result == IOERR_ELXSEC_KEY_UNWRAP_ERROR || - lpfc_cmd->result == - IOERR_ELXSEC_KEY_UNWRAP_COMPARE_ERROR || - lpfc_cmd->result == IOERR_ELXSEC_CRYPTO_ERROR || - lpfc_cmd->result == - IOERR_ELXSEC_CRYPTO_COMPARE_ERROR) { - cmd->result = ScsiResult(DID_NO_CONNECT, 0); - break; - } - if (lpfc_cmd->result == IOERR_INVALID_RPI || - lpfc_cmd->result == IOERR_NO_RESOURCES || - lpfc_cmd->result == IOERR_ABORT_REQUESTED || - lpfc_cmd->result == IOERR_SLER_CMD_RCV_FAILURE) { - cmd->result = ScsiResult(DID_REQUEUE, 0); - break; - } - if ((lpfc_cmd->result == IOERR_RX_DMA_FAILED || - lpfc_cmd->result == IOERR_TX_DMA_FAILED) && - pIocbOut->iocb.unsli3.sli3_bg.bgstat) { - if (scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { - /* - * This is a response for a BG enabled - * cmd. Parse BG error - */ - lpfc_parse_bg_err(phba, lpfc_cmd, - pIocbOut); - break; - } else { - lpfc_printf_vlog(vport, KERN_WARNING, - LOG_BG, - "9031 non-zero BGSTAT " - "on unprotected cmd\n"); - } - } - if ((lpfc_cmd->status == IOSTAT_REMOTE_STOP) - && (phba->sli_rev == LPFC_SLI_REV4) - && (pnode && NLP_CHK_NODE_ACT(pnode))) { - /* This IO was aborted by the target, we don't - * know the rxid and because we did not send the - * ABTS we cannot generate and RRQ. - */ - lpfc_set_rrq_active(phba, pnode, - lpfc_cmd->cur_iocbq.sli4_xritag, - 0, 0); - } - /* else: fall through */ - default: - cmd->result = ScsiResult(DID_ERROR, 0); - break; - } - - if (!pnode || !NLP_CHK_NODE_ACT(pnode) - || (pnode->nlp_state != NLP_STE_MAPPED_NODE)) - cmd->result = ScsiResult(DID_TRANSPORT_DISRUPTED, - SAM_STAT_BUSY); - } else - cmd->result = ScsiResult(DID_OK, 0); - - if (cmd->result || lpfc_cmd->fcp_rsp->rspSnsLen) { - uint32_t *lp = (uint32_t *)cmd->sense_buffer; - - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0710 Iodone <%d/%d> cmd %p, error " - "x%x SNS x%x x%x Data: x%x x%x\n", - cmd->device->id, cmd->device->lun, cmd, - cmd->result, *lp, *(lp + 3), cmd->retries, - scsi_get_resid(cmd)); - } - - lpfc_update_stats(phba, lpfc_cmd); - result = cmd->result; - if (vport->cfg_max_scsicmpl_time && - time_after(jiffies, lpfc_cmd->start_time + - msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { - spin_lock_irqsave(shost->host_lock, flags); - if (pnode && NLP_CHK_NODE_ACT(pnode)) { - if (pnode->cmd_qdepth > - atomic_read(&pnode->cmd_pending) && - (atomic_read(&pnode->cmd_pending) > - LPFC_MIN_TGT_QDEPTH) && - ((cmd->cmnd[0] == READ_10) || - (cmd->cmnd[0] == WRITE_10))) - pnode->cmd_qdepth = - atomic_read(&pnode->cmd_pending); - - pnode->last_change_time = jiffies; - } - spin_unlock_irqrestore(shost->host_lock, flags); - } else if (pnode && NLP_CHK_NODE_ACT(pnode)) { - if ((pnode->cmd_qdepth < vport->cfg_tgt_queue_depth) && - time_after(jiffies, pnode->last_change_time + - msecs_to_jiffies(LPFC_TGTQ_INTERVAL))) { - spin_lock_irqsave(shost->host_lock, flags); - depth = pnode->cmd_qdepth * LPFC_TGTQ_RAMPUP_PCENT - / 100; - depth = depth ? depth : 1; - pnode->cmd_qdepth += depth; - if (pnode->cmd_qdepth > vport->cfg_tgt_queue_depth) - pnode->cmd_qdepth = vport->cfg_tgt_queue_depth; - pnode->last_change_time = jiffies; - spin_unlock_irqrestore(shost->host_lock, flags); - } - } - - lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); - - /* The sdev is not guaranteed to be valid post scsi_done upcall. */ - queue_depth = cmd->device->queue_depth; - scsi_id = cmd->device->id; - cmd->scsi_done(cmd); - - if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - /* - * If there is a thread waiting for command completion - * wake up the thread. - */ - spin_lock_irqsave(shost->host_lock, flags); - lpfc_cmd->pCmd = NULL; - if (lpfc_cmd->waitq) - wake_up(lpfc_cmd->waitq); - spin_unlock_irqrestore(shost->host_lock, flags); - lpfc_release_scsi_buf(phba, lpfc_cmd); - return; - } - - if (!result) - lpfc_rampup_queue_depth(vport, queue_depth); - - /* - * Check for queue full. If the lun is reporting queue full, then - * back off the lun queue depth to prevent target overloads. - */ - if (result == SAM_STAT_TASK_SET_FULL && pnode && - NLP_CHK_NODE_ACT(pnode)) { - shost_for_each_device(tmp_sdev, shost) { - if (tmp_sdev->id != scsi_id) - continue; - depth = scsi_track_queue_full(tmp_sdev, - tmp_sdev->queue_depth-1); - if (depth <= 0) - continue; - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, - "0711 detected queue full - lun queue " - "depth adjusted to %d.\n", depth); - lpfc_send_sdev_queuedepth_change_event(phba, vport, - pnode, - tmp_sdev->lun, - depth+1, depth); - } - } - - /* - * If there is a thread waiting for command completion - * wake up the thread. - */ - spin_lock_irqsave(shost->host_lock, flags); - lpfc_cmd->pCmd = NULL; - if (lpfc_cmd->waitq) - wake_up(lpfc_cmd->waitq); - spin_unlock_irqrestore(shost->host_lock, flags); - - lpfc_release_scsi_buf(phba, lpfc_cmd); -} - -/** - * lpfc_fcpcmd_to_iocb - copy the fcp_cmd data into the IOCB - * @data: A pointer to the immediate command data portion of the IOCB. - * @fcp_cmnd: The FCP Command that is provided by the SCSI layer. - * - * The routine copies the entire FCP command from @fcp_cmnd to @data while - * byte swapping the data to big endian format for transmission on the wire. - **/ -static void -lpfc_fcpcmd_to_iocb(uint8_t *data, struct fcp_cmnd *fcp_cmnd) -{ - int i, j; - for (i = 0, j = 0; i < sizeof(struct fcp_cmnd); - i += sizeof(uint32_t), j++) { - ((uint32_t *)data)[j] = cpu_to_be32(((uint32_t *)fcp_cmnd)[j]); - } -} - -/** - * lpfc_scsi_prep_cmnd - Wrapper func for convert scsi cmnd to FCP info unit - * @vport: The virtual port for which this call is being executed. - * @lpfc_cmd: The scsi command which needs to send. - * @pnode: Pointer to lpfc_nodelist. - * - * This routine initializes fcp_cmnd and iocb data structure from scsi command - * to transfer for device with SLI3 interface spec. - **/ -static void -lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd, - struct lpfc_nodelist *pnode) -{ - struct lpfc_hba *phba = vport->phba; - struct scsi_cmnd *scsi_cmnd = lpfc_cmd->pCmd; - struct fcp_cmnd *fcp_cmnd = lpfc_cmd->fcp_cmnd; - IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb; - struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq); - int datadir = scsi_cmnd->sc_data_direction; - char tag[2]; - - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return; - - lpfc_cmd->fcp_rsp->rspSnsLen = 0; - /* clear task management bits */ - lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; - - int_to_scsilun(lpfc_cmd->pCmd->device->lun, - &lpfc_cmd->fcp_cmnd->fcp_lun); - - memset(&fcp_cmnd->fcpCdb[0], 0, LPFC_FCP_CDB_LEN); - memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, scsi_cmnd->cmd_len); - if (scsi_populate_tag_msg(scsi_cmnd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - fcp_cmnd->fcpCntl1 = HEAD_OF_Q; - break; - case ORDERED_QUEUE_TAG: - fcp_cmnd->fcpCntl1 = ORDERED_Q; - break; - default: - fcp_cmnd->fcpCntl1 = SIMPLE_Q; - break; - } - } else - fcp_cmnd->fcpCntl1 = 0; - - /* - * There are three possibilities here - use scatter-gather segment, use - * the single mapping, or neither. Start the lpfc command prep by - * bumping the bpl beyond the fcp_cmnd and fcp_rsp regions to the first - * data bde entry. - */ - if (scsi_sg_count(scsi_cmnd)) { - if (datadir == DMA_TO_DEVICE) { - iocb_cmd->ulpCommand = CMD_FCP_IWRITE64_CR; - if (phba->sli_rev < LPFC_SLI_REV4) { - iocb_cmd->un.fcpi.fcpi_parm = 0; - iocb_cmd->ulpPU = 0; - } else - iocb_cmd->ulpPU = PARM_READ_CHECK; - fcp_cmnd->fcpCntl3 = WRITE_DATA; - phba->fc4OutputRequests++; - } else { - iocb_cmd->ulpCommand = CMD_FCP_IREAD64_CR; - iocb_cmd->ulpPU = PARM_READ_CHECK; - fcp_cmnd->fcpCntl3 = READ_DATA; - phba->fc4InputRequests++; - } - } else { - iocb_cmd->ulpCommand = CMD_FCP_ICMND64_CR; - iocb_cmd->un.fcpi.fcpi_parm = 0; - iocb_cmd->ulpPU = 0; - fcp_cmnd->fcpCntl3 = 0; - phba->fc4ControlRequests++; - } - if (phba->sli_rev == 3 && - !(phba->sli3_options & LPFC_SLI3_BG_ENABLED)) - lpfc_fcpcmd_to_iocb(iocb_cmd->unsli3.fcp_ext.icd, fcp_cmnd); - /* - * Finish initializing those IOCB fields that are independent - * of the scsi_cmnd request_buffer - */ - piocbq->iocb.ulpContext = pnode->nlp_rpi; - if (phba->sli_rev == LPFC_SLI_REV4) - piocbq->iocb.ulpContext = - phba->sli4_hba.rpi_ids[pnode->nlp_rpi]; - if (pnode->nlp_fcp_info & NLP_FCP_2_DEVICE) - piocbq->iocb.ulpFCP2Rcvy = 1; - else - piocbq->iocb.ulpFCP2Rcvy = 0; - - piocbq->iocb.ulpClass = (pnode->nlp_fcp_info & 0x0f); - piocbq->context1 = lpfc_cmd; - piocbq->iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; - piocbq->iocb.ulpTimeout = lpfc_cmd->timeout; - piocbq->vport = vport; -} - -/** - * lpfc_scsi_prep_task_mgmt_cmd - Convert SLI3 scsi TM cmd to FCP info unit - * @vport: The virtual port for which this call is being executed. - * @lpfc_cmd: Pointer to lpfc_scsi_buf data structure. - * @lun: Logical unit number. - * @task_mgmt_cmd: SCSI task management command. - * - * This routine creates FCP information unit corresponding to @task_mgmt_cmd - * for device with SLI-3 interface spec. - * - * Return codes: - * 0 - Error - * 1 - Success - **/ -static int -lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_vport *vport, - struct lpfc_scsi_buf *lpfc_cmd, - unsigned int lun, - uint8_t task_mgmt_cmd) -{ - struct lpfc_iocbq *piocbq; - IOCB_t *piocb; - struct fcp_cmnd *fcp_cmnd; - struct lpfc_rport_data *rdata = lpfc_cmd->rdata; - struct lpfc_nodelist *ndlp = rdata->pnode; - - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp) || - ndlp->nlp_state != NLP_STE_MAPPED_NODE) - return 0; - - piocbq = &(lpfc_cmd->cur_iocbq); - piocbq->vport = vport; - - piocb = &piocbq->iocb; - - fcp_cmnd = lpfc_cmd->fcp_cmnd; - /* Clear out any old data in the FCP command area */ - memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd)); - int_to_scsilun(lun, &fcp_cmnd->fcp_lun); - fcp_cmnd->fcpCntl2 = task_mgmt_cmd; - if (vport->phba->sli_rev == 3 && - !(vport->phba->sli3_options & LPFC_SLI3_BG_ENABLED)) - lpfc_fcpcmd_to_iocb(piocb->unsli3.fcp_ext.icd, fcp_cmnd); - piocb->ulpCommand = CMD_FCP_ICMND64_CR; - piocb->ulpContext = ndlp->nlp_rpi; - if (vport->phba->sli_rev == LPFC_SLI_REV4) { - piocb->ulpContext = - vport->phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - } - if (ndlp->nlp_fcp_info & NLP_FCP_2_DEVICE) { - piocb->ulpFCP2Rcvy = 1; - } - piocb->ulpClass = (ndlp->nlp_fcp_info & 0x0f); - - /* ulpTimeout is only one byte */ - if (lpfc_cmd->timeout > 0xff) { - /* - * Do not timeout the command at the firmware level. - * The driver will provide the timeout mechanism. - */ - piocb->ulpTimeout = 0; - } else - piocb->ulpTimeout = lpfc_cmd->timeout; - - if (vport->phba->sli_rev == LPFC_SLI_REV4) - lpfc_sli4_set_rsp_sgl_last(vport->phba, lpfc_cmd); - - return 1; -} - -/** - * lpfc_scsi_api_table_setup - Set up scsi api function jump table - * @phba: The hba struct for which this call is being executed. - * @dev_grp: The HBA PCI-Device group number. - * - * This routine sets up the SCSI interface API function jump table in @phba - * struct. - * Returns: 0 - success, -ENODEV - failure. - **/ -int -lpfc_scsi_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) -{ - - phba->lpfc_scsi_unprep_dma_buf = lpfc_scsi_unprep_dma_buf; - phba->lpfc_scsi_prep_cmnd = lpfc_scsi_prep_cmnd; - - switch (dev_grp) { - case LPFC_PCI_DEV_LP: - phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s3; - phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s3; - phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s3; - phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s3; - phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s3; - break; - case LPFC_PCI_DEV_OC: - phba->lpfc_new_scsi_buf = lpfc_new_scsi_buf_s4; - phba->lpfc_scsi_prep_dma_buf = lpfc_scsi_prep_dma_buf_s4; - phba->lpfc_bg_scsi_prep_dma_buf = lpfc_bg_scsi_prep_dma_buf_s4; - phba->lpfc_release_scsi_buf = lpfc_release_scsi_buf_s4; - phba->lpfc_get_scsi_buf = lpfc_get_scsi_buf_s4; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1418 Invalid HBA PCI-device group: 0x%x\n", - dev_grp); - return -ENODEV; - break; - } - phba->lpfc_rampdown_queue_depth = lpfc_rampdown_queue_depth; - phba->lpfc_scsi_cmd_iocb_cmpl = lpfc_scsi_cmd_iocb_cmpl; - return 0; -} - -/** - * lpfc_taskmgmt_def_cmpl - IOCB completion routine for task management command - * @phba: The Hba for which this call is being executed. - * @cmdiocbq: Pointer to lpfc_iocbq data structure. - * @rspiocbq: Pointer to lpfc_iocbq data structure. - * - * This routine is IOCB completion routine for device reset and target reset - * routine. This routine release scsi buffer associated with lpfc_cmd. - **/ -static void -lpfc_tskmgmt_def_cmpl(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocbq, - struct lpfc_iocbq *rspiocbq) -{ - struct lpfc_scsi_buf *lpfc_cmd = - (struct lpfc_scsi_buf *) cmdiocbq->context1; - if (lpfc_cmd) - lpfc_release_scsi_buf(phba, lpfc_cmd); - return; -} - -/** - * lpfc_info - Info entry point of scsi_host_template data structure - * @host: The scsi host for which this call is being executed. - * - * This routine provides module information about hba. - * - * Reutrn code: - * Pointer to char - Success. - **/ -const char * -lpfc_info(struct Scsi_Host *host) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) host->hostdata; - struct lpfc_hba *phba = vport->phba; - int len; - static char lpfcinfobuf[384]; - - memset(lpfcinfobuf,0,384); - if (phba && phba->pcidev){ - strncpy(lpfcinfobuf, phba->ModelDesc, 256); - len = strlen(lpfcinfobuf); - snprintf(lpfcinfobuf + len, - 384-len, - " on PCI bus %02x device %02x irq %d", - phba->pcidev->bus->number, - phba->pcidev->devfn, - phba->pcidev->irq); - len = strlen(lpfcinfobuf); - if (phba->Port[0]) { - snprintf(lpfcinfobuf + len, - 384-len, - " port %s", - phba->Port); - } - len = strlen(lpfcinfobuf); - if (phba->sli4_hba.link_state.logical_speed) { - snprintf(lpfcinfobuf + len, - 384-len, - " Logical Link Speed: %d Mbps", - phba->sli4_hba.link_state.logical_speed * 10); - } - } - return lpfcinfobuf; -} - -/** - * lpfc_poll_rearm_time - Routine to modify fcp_poll timer of hba - * @phba: The Hba for which this call is being executed. - * - * This routine modifies fcp_poll_timer field of @phba by cfg_poll_tmo. - * The default value of cfg_poll_tmo is 10 milliseconds. - **/ -static __inline__ void lpfc_poll_rearm_timer(struct lpfc_hba * phba) -{ - unsigned long poll_tmo_expires = - (jiffies + msecs_to_jiffies(phba->cfg_poll_tmo)); - - if (phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt) - mod_timer(&phba->fcp_poll_timer, - poll_tmo_expires); -} - -/** - * lpfc_poll_start_timer - Routine to start fcp_poll_timer of HBA - * @phba: The Hba for which this call is being executed. - * - * This routine starts the fcp_poll_timer of @phba. - **/ -void lpfc_poll_start_timer(struct lpfc_hba * phba) -{ - lpfc_poll_rearm_timer(phba); -} - -/** - * lpfc_poll_timeout - Restart polling timer - * @ptr: Map to lpfc_hba data structure pointer. - * - * This routine restarts fcp_poll timer, when FCP ring polling is enable - * and FCP Ring interrupt is disable. - **/ - -void lpfc_poll_timeout(unsigned long ptr) -{ - struct lpfc_hba *phba = (struct lpfc_hba *) ptr; - - if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_sli_handle_fast_ring_event(phba, - &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) - lpfc_poll_rearm_timer(phba); - } -} - -/** - * lpfc_queuecommand - scsi_host_template queuecommand entry point - * @cmnd: Pointer to scsi_cmnd data structure. - * @done: Pointer to done routine. - * - * Driver registers this routine to scsi midlayer to submit a @cmd to process. - * This routine prepares an IOCB from scsi command and provides to firmware. - * The @done callback is invoked after driver finished processing the command. - * - * Return value : - * 0 - Success - * SCSI_MLQUEUE_HOST_BUSY - Block all devices served by this host temporarily. - **/ -static int -lpfc_queuecommand_lck(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *ndlp; - struct lpfc_scsi_buf *lpfc_cmd; - struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); - int err; - - err = fc_remote_port_chkready(rport); - if (err) { - cmnd->result = err; - goto out_fail_command; - } - ndlp = rdata->pnode; - - if ((scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) && - (!(phba->sli3_options & LPFC_SLI3_BG_ENABLED))) { - - lpfc_printf_log(phba, KERN_ERR, LOG_BG, - "9058 BLKGRD: ERROR: rcvd protected cmd:%02x" - " op:%02x str=%s without registering for" - " BlockGuard - Rejecting command\n", - cmnd->cmnd[0], scsi_get_prot_op(cmnd), - dif_op_str[scsi_get_prot_op(cmnd)]); - goto out_fail_command; - } - - /* - * Catch race where our node has transitioned, but the - * transport is still transitioning. - */ - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - cmnd->result = ScsiResult(DID_IMM_RETRY, 0); - goto out_fail_command; - } - if (atomic_read(&ndlp->cmd_pending) >= ndlp->cmd_qdepth) - goto out_tgt_busy; - - lpfc_cmd = lpfc_get_scsi_buf(phba, ndlp); - if (lpfc_cmd == NULL) { - lpfc_rampdown_queue_depth(phba); - - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0707 driver's buffer pool is empty, " - "IO busied\n"); - goto out_host_busy; - } - - /* - * Store the midlayer's command structure for the completion phase - * and complete the command initialization. - */ - lpfc_cmd->pCmd = cmnd; - lpfc_cmd->rdata = rdata; - lpfc_cmd->timeout = 0; - lpfc_cmd->start_time = jiffies; - cmnd->host_scribble = (unsigned char *)lpfc_cmd; - cmnd->scsi_done = done; - - if (scsi_get_prot_op(cmnd) != SCSI_PROT_NORMAL) { - if (vport->phba->cfg_enable_bg) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9033 BLKGRD: rcvd protected cmd:%02x op=%s " - "guard=%s\n", cmnd->cmnd[0], - dif_op_str[scsi_get_prot_op(cmnd)], - dif_grd_str[scsi_host_get_guard(shost)]); - if (cmnd->cmnd[0] == READ_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9035 BLKGRD: READ @ sector %llu, " - "cnt %u, rpt %d\n", - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), - (cmnd->cmnd[1]>>5)); - else if (cmnd->cmnd[0] == WRITE_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9036 BLKGRD: WRITE @ sector %llu, " - "cnt %u, wpt %d\n", - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), - (cmnd->cmnd[1]>>5)); - } - - err = lpfc_bg_scsi_prep_dma_buf(phba, lpfc_cmd); - } else { - if (vport->phba->cfg_enable_bg) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9038 BLKGRD: rcvd unprotected cmd:" - "%02x op=%s guard=%s\n", cmnd->cmnd[0], - dif_op_str[scsi_get_prot_op(cmnd)], - dif_grd_str[scsi_host_get_guard(shost)]); - if (cmnd->cmnd[0] == READ_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9040 dbg: READ @ sector %llu, " - "cnt %u, rpt %d\n", - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), - (cmnd->cmnd[1]>>5)); - else if (cmnd->cmnd[0] == WRITE_10) - lpfc_printf_vlog(vport, KERN_WARNING, LOG_BG, - "9041 dbg: WRITE @ sector %llu, " - "cnt %u, wpt %d\n", - (unsigned long long)scsi_get_lba(cmnd), - blk_rq_sectors(cmnd->request), - (cmnd->cmnd[1]>>5)); - } - err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); - } - - if (err) - goto out_host_busy_free_buf; - - lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); - - atomic_inc(&ndlp->cmd_pending); - err = lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, - &lpfc_cmd->cur_iocbq, SLI_IOCB_RET_IOCB); - if (err) { - atomic_dec(&ndlp->cmd_pending); - goto out_host_busy_free_buf; - } - if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - spin_unlock(shost->host_lock); - lpfc_sli_handle_fast_ring_event(phba, - &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); - - spin_lock(shost->host_lock); - if (phba->cfg_poll & DISABLE_FCP_RING_INT) - lpfc_poll_rearm_timer(phba); - } - - return 0; - - out_host_busy_free_buf: - lpfc_scsi_unprep_dma_buf(phba, lpfc_cmd); - lpfc_release_scsi_buf(phba, lpfc_cmd); - out_host_busy: - return SCSI_MLQUEUE_HOST_BUSY; - - out_tgt_busy: - return SCSI_MLQUEUE_TARGET_BUSY; - - out_fail_command: - done(cmnd); - return 0; -} - -static DEF_SCSI_QCMD(lpfc_queuecommand) - -/** - * lpfc_abort_handler - scsi_host_template eh_abort_handler entry point - * @cmnd: Pointer to scsi_cmnd data structure. - * - * This routine aborts @cmnd pending in base driver. - * - * Return code : - * 0x2003 - Error - * 0x2002 - Success - **/ -static int -lpfc_abort_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *iocb; - struct lpfc_iocbq *abtsiocb; - struct lpfc_scsi_buf *lpfc_cmd; - IOCB_t *cmd, *icmd; - int ret = SUCCESS; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waitq); - - ret = fc_block_scsi_eh(cmnd); - if (ret) - return ret; - lpfc_cmd = (struct lpfc_scsi_buf *)cmnd->host_scribble; - if (!lpfc_cmd) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, - "2873 SCSI Layer I/O Abort Request IO CMPL Status " - "x%x ID %d LUN %d\n", - ret, cmnd->device->id, cmnd->device->lun); - return SUCCESS; - } - - /* - * If pCmd field of the corresponding lpfc_scsi_buf structure - * points to a different SCSI command, then the driver has - * already completed this command, but the midlayer did not - * see the completion before the eh fired. Just return - * SUCCESS. - */ - iocb = &lpfc_cmd->cur_iocbq; - if (lpfc_cmd->pCmd != cmnd) - goto out; - - BUG_ON(iocb->context1 != lpfc_cmd); - - abtsiocb = lpfc_sli_get_iocbq(phba); - if (abtsiocb == NULL) { - ret = FAILED; - goto out; - } - - /* - * The scsi command can not be in txq and it is in flight because the - * pCmd is still pointig at the SCSI command we have to abort. There - * is no need to search the txcmplq. Just send an abort to the FW. - */ - - cmd = &iocb->iocb; - icmd = &abtsiocb->iocb; - icmd->un.acxri.abortType = ABORT_TYPE_ABTS; - icmd->un.acxri.abortContextTag = cmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) - icmd->un.acxri.abortIoTag = iocb->sli4_xritag; - else - icmd->un.acxri.abortIoTag = cmd->ulpIoTag; - - icmd->ulpLe = 1; - icmd->ulpClass = cmd->ulpClass; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocb->fcp_wqidx = iocb->fcp_wqidx; - abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; - - if (lpfc_is_link_up(phba)) - icmd->ulpCommand = CMD_ABORT_XRI_CN; - else - icmd->ulpCommand = CMD_CLOSE_XRI_CN; - - abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - abtsiocb->vport = vport; - if (lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0) == - IOCB_ERROR) { - lpfc_sli_release_iocbq(phba, abtsiocb); - ret = FAILED; - goto out; - } - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) - lpfc_sli_handle_fast_ring_event(phba, - &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); - - lpfc_cmd->waitq = &waitq; - /* Wait for abort to complete */ - wait_event_timeout(waitq, - (lpfc_cmd->pCmd != cmnd), - (2*vport->cfg_devloss_tmo*HZ)); - - spin_lock_irq(shost->host_lock); - lpfc_cmd->waitq = NULL; - spin_unlock_irq(shost->host_lock); - - if (lpfc_cmd->pCmd == cmnd) { - ret = FAILED; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0748 abort handler timed out waiting " - "for abort to complete: ret %#x, ID %d, " - "LUN %d\n", - ret, cmnd->device->id, cmnd->device->lun); - } - - out: - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, - "0749 SCSI Layer I/O Abort Request Status x%x ID %d " - "LUN %d\n", ret, cmnd->device->id, - cmnd->device->lun); - return ret; -} - -static char * -lpfc_taskmgmt_name(uint8_t task_mgmt_cmd) -{ - switch (task_mgmt_cmd) { - case FCP_ABORT_TASK_SET: - return "ABORT_TASK_SET"; - case FCP_CLEAR_TASK_SET: - return "FCP_CLEAR_TASK_SET"; - case FCP_BUS_RESET: - return "FCP_BUS_RESET"; - case FCP_LUN_RESET: - return "FCP_LUN_RESET"; - case FCP_TARGET_RESET: - return "FCP_TARGET_RESET"; - case FCP_CLEAR_ACA: - return "FCP_CLEAR_ACA"; - case FCP_TERMINATE_TASK: - return "FCP_TERMINATE_TASK"; - default: - return "unknown"; - } -} - -/** - * lpfc_send_taskmgmt - Generic SCSI Task Mgmt Handler - * @vport: The virtual port for which this call is being executed. - * @rdata: Pointer to remote port local data - * @tgt_id: Target ID of remote device. - * @lun_id: Lun number for the TMF - * @task_mgmt_cmd: type of TMF to send - * - * This routine builds and sends a TMF (SCSI Task Mgmt Function) to - * a remote port. - * - * Return Code: - * 0x2003 - Error - * 0x2002 - Success. - **/ -static int -lpfc_send_taskmgmt(struct lpfc_vport *vport, struct lpfc_rport_data *rdata, - unsigned tgt_id, unsigned int lun_id, - uint8_t task_mgmt_cmd) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_scsi_buf *lpfc_cmd; - struct lpfc_iocbq *iocbq; - struct lpfc_iocbq *iocbqrsp; - struct lpfc_nodelist *pnode = rdata->pnode; - int ret; - int status; - - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return FAILED; - - lpfc_cmd = lpfc_get_scsi_buf(phba, rdata->pnode); - if (lpfc_cmd == NULL) - return FAILED; - lpfc_cmd->timeout = 60; - lpfc_cmd->rdata = rdata; - - status = lpfc_scsi_prep_task_mgmt_cmd(vport, lpfc_cmd, lun_id, - task_mgmt_cmd); - if (!status) { - lpfc_release_scsi_buf(phba, lpfc_cmd); - return FAILED; - } - - iocbq = &lpfc_cmd->cur_iocbq; - iocbqrsp = lpfc_sli_get_iocbq(phba); - if (iocbqrsp == NULL) { - lpfc_release_scsi_buf(phba, lpfc_cmd); - return FAILED; - } - - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0702 Issue %s to TGT %d LUN %d " - "rpi x%x nlp_flag x%x Data: x%x x%x\n", - lpfc_taskmgmt_name(task_mgmt_cmd), tgt_id, lun_id, - pnode->nlp_rpi, pnode->nlp_flag, iocbq->sli4_xritag, - iocbq->iocb_flag); - - status = lpfc_sli_issue_iocb_wait(phba, LPFC_FCP_RING, - iocbq, iocbqrsp, lpfc_cmd->timeout); - if (status != IOCB_SUCCESS) { - if (status == IOCB_TIMEDOUT) { - iocbq->iocb_cmpl = lpfc_tskmgmt_def_cmpl; - ret = TIMEOUT_ERROR; - } else - ret = FAILED; - lpfc_cmd->status = IOSTAT_DRIVER_REJECT; - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0727 TMF %s to TGT %d LUN %d failed (%d, %d) " - "iocb_flag x%x\n", - lpfc_taskmgmt_name(task_mgmt_cmd), - tgt_id, lun_id, iocbqrsp->iocb.ulpStatus, - iocbqrsp->iocb.un.ulpWord[4], - iocbq->iocb_flag); - } else if (status == IOCB_BUSY) - ret = FAILED; - else - ret = SUCCESS; - - lpfc_sli_release_iocbq(phba, iocbqrsp); - - if (ret != TIMEOUT_ERROR) - lpfc_release_scsi_buf(phba, lpfc_cmd); - - return ret; -} - -/** - * lpfc_chk_tgt_mapped - - * @vport: The virtual port to check on - * @cmnd: Pointer to scsi_cmnd data structure. - * - * This routine delays until the scsi target (aka rport) for the - * command exists (is present and logged in) or we declare it non-existent. - * - * Return code : - * 0x2003 - Error - * 0x2002 - Success - **/ -static int -lpfc_chk_tgt_mapped(struct lpfc_vport *vport, struct scsi_cmnd *cmnd) -{ - struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *pnode; - unsigned long later; - - if (!rdata) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_FCP, - "0797 Tgt Map rport failure: rdata x%p\n", rdata); - return FAILED; - } - pnode = rdata->pnode; - /* - * If target is not in a MAPPED state, delay until - * target is rediscovered or devloss timeout expires. - */ - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; - while (time_after(later, jiffies)) { - if (!pnode || !NLP_CHK_NODE_ACT(pnode)) - return FAILED; - if (pnode->nlp_state == NLP_STE_MAPPED_NODE) - return SUCCESS; - schedule_timeout_uninterruptible(msecs_to_jiffies(500)); - rdata = cmnd->device->hostdata; - if (!rdata) - return FAILED; - pnode = rdata->pnode; - } - if (!pnode || !NLP_CHK_NODE_ACT(pnode) || - (pnode->nlp_state != NLP_STE_MAPPED_NODE)) - return FAILED; - return SUCCESS; -} - -/** - * lpfc_reset_flush_io_context - - * @vport: The virtual port (scsi_host) for the flush context - * @tgt_id: If aborting by Target contect - specifies the target id - * @lun_id: If aborting by Lun context - specifies the lun id - * @context: specifies the context level to flush at. - * - * After a reset condition via TMF, we need to flush orphaned i/o - * contexts from the adapter. This routine aborts any contexts - * outstanding, then waits for their completions. The wait is - * bounded by devloss_tmo though. - * - * Return code : - * 0x2003 - Error - * 0x2002 - Success - **/ -static int -lpfc_reset_flush_io_context(struct lpfc_vport *vport, uint16_t tgt_id, - uint64_t lun_id, lpfc_ctx_cmd context) -{ - struct lpfc_hba *phba = vport->phba; - unsigned long later; - int cnt; - - cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); - if (cnt) - lpfc_sli_abort_iocb(vport, &phba->sli.ring[phba->sli.fcp_ring], - tgt_id, lun_id, context); - later = msecs_to_jiffies(2 * vport->cfg_devloss_tmo * 1000) + jiffies; - while (time_after(later, jiffies) && cnt) { - schedule_timeout_uninterruptible(msecs_to_jiffies(20)); - cnt = lpfc_sli_sum_iocb(vport, tgt_id, lun_id, context); - } - if (cnt) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0724 I/O flush failure for context %s : cnt x%x\n", - ((context == LPFC_CTX_LUN) ? "LUN" : - ((context == LPFC_CTX_TGT) ? "TGT" : - ((context == LPFC_CTX_HOST) ? "HOST" : "Unknown"))), - cnt); - return FAILED; - } - return SUCCESS; -} - -/** - * lpfc_device_reset_handler - scsi_host_template eh_device_reset entry point - * @cmnd: Pointer to scsi_cmnd data structure. - * - * This routine does a device reset by sending a LUN_RESET task management - * command. - * - * Return code : - * 0x2003 - Error - * 0x2002 - Success - **/ -static int -lpfc_device_reset_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *pnode; - unsigned tgt_id = cmnd->device->id; - unsigned int lun_id = cmnd->device->lun; - struct lpfc_scsi_event_header scsi_event; - int status; - - if (!rdata) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0798 Device Reset rport failure: rdata x%p\n", rdata); - return FAILED; - } - pnode = rdata->pnode; - status = fc_block_scsi_eh(cmnd); - if (status) - return status; - - status = lpfc_chk_tgt_mapped(vport, cmnd); - if (status == FAILED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0721 Device Reset rport failure: rdata x%p\n", rdata); - return FAILED; - } - - scsi_event.event_type = FC_REG_SCSI_EVENT; - scsi_event.subcategory = LPFC_EVENT_LUNRESET; - scsi_event.lun = lun_id; - memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); - memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); - - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - - status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id, - FCP_LUN_RESET); - - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0713 SCSI layer issued Device Reset (%d, %d) " - "return x%x\n", tgt_id, lun_id, status); - - /* - * We have to clean up i/o as : they may be orphaned by the TMF; - * or if the TMF failed, they may be in an indeterminate state. - * So, continue on. - * We will report success if all the i/o aborts successfully. - */ - status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, - LPFC_CTX_LUN); - return status; -} - -/** - * lpfc_target_reset_handler - scsi_host_template eh_target_reset entry point - * @cmnd: Pointer to scsi_cmnd data structure. - * - * This routine does a target reset by sending a TARGET_RESET task management - * command. - * - * Return code : - * 0x2003 - Error - * 0x2002 - Success - **/ -static int -lpfc_target_reset_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_rport_data *rdata = cmnd->device->hostdata; - struct lpfc_nodelist *pnode; - unsigned tgt_id = cmnd->device->id; - unsigned int lun_id = cmnd->device->lun; - struct lpfc_scsi_event_header scsi_event; - int status; - - if (!rdata) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0799 Target Reset rport failure: rdata x%p\n", rdata); - return FAILED; - } - pnode = rdata->pnode; - status = fc_block_scsi_eh(cmnd); - if (status) - return status; - - status = lpfc_chk_tgt_mapped(vport, cmnd); - if (status == FAILED) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0722 Target Reset rport failure: rdata x%p\n", rdata); - return FAILED; - } - - scsi_event.event_type = FC_REG_SCSI_EVENT; - scsi_event.subcategory = LPFC_EVENT_TGTRESET; - scsi_event.lun = 0; - memcpy(scsi_event.wwpn, &pnode->nlp_portname, sizeof(struct lpfc_name)); - memcpy(scsi_event.wwnn, &pnode->nlp_nodename, sizeof(struct lpfc_name)); - - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - - status = lpfc_send_taskmgmt(vport, rdata, tgt_id, lun_id, - FCP_TARGET_RESET); - - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0723 SCSI layer issued Target Reset (%d, %d) " - "return x%x\n", tgt_id, lun_id, status); - - /* - * We have to clean up i/o as : they may be orphaned by the TMF; - * or if the TMF failed, they may be in an indeterminate state. - * So, continue on. - * We will report success if all the i/o aborts successfully. - */ - status = lpfc_reset_flush_io_context(vport, tgt_id, lun_id, - LPFC_CTX_TGT); - return status; -} - -/** - * lpfc_bus_reset_handler - scsi_host_template eh_bus_reset_handler entry point - * @cmnd: Pointer to scsi_cmnd data structure. - * - * This routine does target reset to all targets on @cmnd->device->host. - * This emulates Parallel SCSI Bus Reset Semantics. - * - * Return code : - * 0x2003 - Error - * 0x2002 - Success - **/ -static int -lpfc_bus_reset_handler(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_nodelist *ndlp = NULL; - struct lpfc_scsi_event_header scsi_event; - int match; - int ret = SUCCESS, status, i; - - scsi_event.event_type = FC_REG_SCSI_EVENT; - scsi_event.subcategory = LPFC_EVENT_BUSRESET; - scsi_event.lun = 0; - memcpy(scsi_event.wwpn, &vport->fc_portname, sizeof(struct lpfc_name)); - memcpy(scsi_event.wwnn, &vport->fc_nodename, sizeof(struct lpfc_name)); - - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(scsi_event), (char *)&scsi_event, LPFC_NL_VENDOR_ID); - - status = fc_block_scsi_eh(cmnd); - if (status) - return status; - - /* - * Since the driver manages a single bus device, reset all - * targets known to the driver. Should any target reset - * fail, this routine returns failure to the midlayer. - */ - for (i = 0; i < LPFC_MAX_TARGET; i++) { - /* Search for mapped node by target ID */ - match = 0; - spin_lock_irq(shost->host_lock); - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_MAPPED_NODE && - ndlp->nlp_sid == i && - ndlp->rport) { - match = 1; - break; - } - } - spin_unlock_irq(shost->host_lock); - if (!match) - continue; - - status = lpfc_send_taskmgmt(vport, ndlp->rport->dd_data, - i, 0, FCP_TARGET_RESET); - - if (status != SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0700 Bus Reset on target %d failed\n", - i); - ret = FAILED; - } - } - /* - * We have to clean up i/o as : they may be orphaned by the TMFs - * above; or if any of the TMFs failed, they may be in an - * indeterminate state. - * We will report success if all the i/o aborts successfully. - */ - - status = lpfc_reset_flush_io_context(vport, 0, 0, LPFC_CTX_HOST); - if (status != SUCCESS) - ret = FAILED; - - lpfc_printf_vlog(vport, KERN_ERR, LOG_FCP, - "0714 SCSI layer issued Bus Reset Data: x%x\n", ret); - return ret; -} - -/** - * lpfc_slave_alloc - scsi_host_template slave_alloc entry point - * @sdev: Pointer to scsi_device. - * - * This routine populates the cmds_per_lun count + 2 scsi_bufs into this host's - * globally available list of scsi buffers. This routine also makes sure scsi - * buffer is not allocated more than HBA limit conveyed to midlayer. This list - * of scsi buffer exists for the lifetime of the driver. - * - * Return codes: - * non-0 - Error - * 0 - Success - **/ -static int -lpfc_slave_alloc(struct scsi_device *sdev) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; - struct lpfc_hba *phba = vport->phba; - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - uint32_t total = 0; - uint32_t num_to_alloc = 0; - int num_allocated = 0; - uint32_t sdev_cnt; - - if (!rport || fc_remote_port_chkready(rport)) - return -ENXIO; - - sdev->hostdata = rport->dd_data; - sdev_cnt = atomic_inc_return(&phba->sdev_cnt); - - /* - * Populate the cmds_per_lun count scsi_bufs into this host's globally - * available list of scsi buffers. Don't allocate more than the - * HBA limit conveyed to the midlayer via the host structure. The - * formula accounts for the lun_queue_depth + error handlers + 1 - * extra. This list of scsi bufs exists for the lifetime of the driver. - */ - total = phba->total_scsi_bufs; - num_to_alloc = vport->cfg_lun_queue_depth + 2; - - /* If allocated buffers are enough do nothing */ - if ((sdev_cnt * (vport->cfg_lun_queue_depth + 2)) < total) - return 0; - - /* Allow some exchanges to be available always to complete discovery */ - if (total >= phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, - "0704 At limitation of %d preallocated " - "command buffers\n", total); - return 0; - /* Allow some exchanges to be available always to complete discovery */ - } else if (total + num_to_alloc > - phba->cfg_hba_queue_depth - LPFC_DISC_IOCB_BUFF_COUNT ) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, - "0705 Allocation request of %d " - "command buffers will exceed max of %d. " - "Reducing allocation request to %d.\n", - num_to_alloc, phba->cfg_hba_queue_depth, - (phba->cfg_hba_queue_depth - total)); - num_to_alloc = phba->cfg_hba_queue_depth - total; - } - num_allocated = lpfc_new_scsi_buf(vport, num_to_alloc); - if (num_to_alloc != num_allocated) { - lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP, - "0708 Allocation request of %d " - "command buffers did not succeed. " - "Allocated %d buffers.\n", - num_to_alloc, num_allocated); - } - if (num_allocated > 0) - phba->total_scsi_bufs += num_allocated; - return 0; -} - -/** - * lpfc_slave_configure - scsi_host_template slave_configure entry point - * @sdev: Pointer to scsi_device. - * - * This routine configures following items - * - Tag command queuing support for @sdev if supported. - * - Enable SLI polling for fcp ring if ENABLE_FCP_RING_POLLING flag is set. - * - * Return codes: - * 0 - Success - **/ -static int -lpfc_slave_configure(struct scsi_device *sdev) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; - struct lpfc_hba *phba = vport->phba; - - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, vport->cfg_lun_queue_depth); - else - scsi_deactivate_tcq(sdev, vport->cfg_lun_queue_depth); - - if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) { - lpfc_sli_handle_fast_ring_event(phba, - &phba->sli.ring[LPFC_FCP_RING], HA_R0RE_REQ); - if (phba->cfg_poll & DISABLE_FCP_RING_INT) - lpfc_poll_rearm_timer(phba); - } - - return 0; -} - -/** - * lpfc_slave_destroy - slave_destroy entry point of SHT data structure - * @sdev: Pointer to scsi_device. - * - * This routine sets @sdev hostatdata filed to null. - **/ -static void -lpfc_slave_destroy(struct scsi_device *sdev) -{ - struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata; - struct lpfc_hba *phba = vport->phba; - atomic_dec(&phba->sdev_cnt); - sdev->hostdata = NULL; - return; -} - - -struct scsi_host_template lpfc_template = { - .module = THIS_MODULE, - .name = LPFC_DRIVER_NAME, - .info = lpfc_info, - .queuecommand = lpfc_queuecommand, - .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler = lpfc_device_reset_handler, - .eh_target_reset_handler = lpfc_target_reset_handler, - .eh_bus_reset_handler = lpfc_bus_reset_handler, - .slave_alloc = lpfc_slave_alloc, - .slave_configure = lpfc_slave_configure, - .slave_destroy = lpfc_slave_destroy, - .scan_finished = lpfc_scan_finished, - .this_id = -1, - .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, - .cmd_per_lun = LPFC_CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = lpfc_hba_attrs, - .max_sectors = 0xFFFF, - .vendor_id = LPFC_NL_VENDOR_ID, - .change_queue_depth = lpfc_change_queue_depth, -}; - -struct scsi_host_template lpfc_vport_template = { - .module = THIS_MODULE, - .name = LPFC_DRIVER_NAME, - .info = lpfc_info, - .queuecommand = lpfc_queuecommand, - .eh_abort_handler = lpfc_abort_handler, - .eh_device_reset_handler = lpfc_device_reset_handler, - .eh_target_reset_handler = lpfc_target_reset_handler, - .eh_bus_reset_handler = lpfc_bus_reset_handler, - .slave_alloc = lpfc_slave_alloc, - .slave_configure = lpfc_slave_configure, - .slave_destroy = lpfc_slave_destroy, - .scan_finished = lpfc_scan_finished, - .this_id = -1, - .sg_tablesize = LPFC_DEFAULT_SG_SEG_CNT, - .cmd_per_lun = LPFC_CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = lpfc_vport_attrs, - .max_sectors = 0xFFFF, - .change_queue_depth = lpfc_change_queue_depth, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.h deleted file mode 100644 index 21a2ffe6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_scsi.h +++ /dev/null @@ -1,167 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include - -struct lpfc_hba; -#define LPFC_FCP_CDB_LEN 16 - -#define list_remove_head(list, entry, type, member) \ - do { \ - entry = NULL; \ - if (!list_empty(list)) { \ - entry = list_entry((list)->next, type, member); \ - list_del_init(&entry->member); \ - } \ - } while(0) - -#define list_get_first(list, type, member) \ - (list_empty(list)) ? NULL : \ - list_entry((list)->next, type, member) - -/* per-port data that is allocated in the FC transport for us */ -struct lpfc_rport_data { - struct lpfc_nodelist *pnode; /* Pointer to the node structure. */ -}; - -struct fcp_rsp { - uint32_t rspRsvd1; /* FC Word 0, byte 0:3 */ - uint32_t rspRsvd2; /* FC Word 1, byte 0:3 */ - - uint8_t rspStatus0; /* FCP_STATUS byte 0 (reserved) */ - uint8_t rspStatus1; /* FCP_STATUS byte 1 (reserved) */ - uint8_t rspStatus2; /* FCP_STATUS byte 2 field validity */ -#define RSP_LEN_VALID 0x01 /* bit 0 */ -#define SNS_LEN_VALID 0x02 /* bit 1 */ -#define RESID_OVER 0x04 /* bit 2 */ -#define RESID_UNDER 0x08 /* bit 3 */ - uint8_t rspStatus3; /* FCP_STATUS byte 3 SCSI status byte */ - - uint32_t rspResId; /* Residual xfer if residual count field set in - fcpStatus2 */ - /* Received in Big Endian format */ - uint32_t rspSnsLen; /* Length of sense data in fcpSnsInfo */ - /* Received in Big Endian format */ - uint32_t rspRspLen; /* Length of FCP response data in fcpRspInfo */ - /* Received in Big Endian format */ - - uint8_t rspInfo0; /* FCP_RSP_INFO byte 0 (reserved) */ - uint8_t rspInfo1; /* FCP_RSP_INFO byte 1 (reserved) */ - uint8_t rspInfo2; /* FCP_RSP_INFO byte 2 (reserved) */ - uint8_t rspInfo3; /* FCP_RSP_INFO RSP_CODE byte 3 */ - -#define RSP_NO_FAILURE 0x00 -#define RSP_DATA_BURST_ERR 0x01 -#define RSP_CMD_FIELD_ERR 0x02 -#define RSP_RO_MISMATCH_ERR 0x03 -#define RSP_TM_NOT_SUPPORTED 0x04 /* Task mgmt function not supported */ -#define RSP_TM_NOT_COMPLETED 0x05 /* Task mgmt function not performed */ - - uint32_t rspInfoRsvd; /* FCP_RSP_INFO bytes 4-7 (reserved) */ - - uint8_t rspSnsInfo[128]; -#define SNS_ILLEGAL_REQ 0x05 /* sense key is byte 3 ([2]) */ -#define SNSCOD_BADCMD 0x20 /* sense code is byte 13 ([12]) */ -}; - -struct fcp_cmnd { - struct scsi_lun fcp_lun; - - uint8_t fcpCntl0; /* FCP_CNTL byte 0 (reserved) */ - uint8_t fcpCntl1; /* FCP_CNTL byte 1 task codes */ -#define SIMPLE_Q 0x00 -#define HEAD_OF_Q 0x01 -#define ORDERED_Q 0x02 -#define ACA_Q 0x04 -#define UNTAGGED 0x05 - uint8_t fcpCntl2; /* FCP_CTL byte 2 task management codes */ -#define FCP_ABORT_TASK_SET 0x02 /* Bit 1 */ -#define FCP_CLEAR_TASK_SET 0x04 /* bit 2 */ -#define FCP_BUS_RESET 0x08 /* bit 3 */ -#define FCP_LUN_RESET 0x10 /* bit 4 */ -#define FCP_TARGET_RESET 0x20 /* bit 5 */ -#define FCP_CLEAR_ACA 0x40 /* bit 6 */ -#define FCP_TERMINATE_TASK 0x80 /* bit 7 */ - uint8_t fcpCntl3; -#define WRITE_DATA 0x01 /* Bit 0 */ -#define READ_DATA 0x02 /* Bit 1 */ - - uint8_t fcpCdb[LPFC_FCP_CDB_LEN]; /* SRB cdb field is copied here */ - uint32_t fcpDl; /* Total transfer length */ - -}; - -struct lpfc_scsicmd_bkt { - uint32_t cmd_count; -}; - -struct lpfc_scsi_buf { - struct list_head list; - struct scsi_cmnd *pCmd; - struct lpfc_rport_data *rdata; - - uint32_t timeout; - - uint16_t exch_busy; /* SLI4 hba reported XB on complete WCQE */ - uint16_t status; /* From IOCB Word 7- ulpStatus */ - uint32_t result; /* From IOCB Word 4. */ - - uint32_t seg_cnt; /* Number of scatter-gather segments returned by - * dma_map_sg. The driver needs this for calls - * to dma_unmap_sg. */ - uint32_t prot_seg_cnt; /* seg_cnt's counterpart for protection data */ - - dma_addr_t nonsg_phys; /* Non scatter-gather physical address. */ - - /* - * data and dma_handle are the kernel virtual and bus address of the - * dma-able buffer containing the fcp_cmd, fcp_rsp and a scatter - * gather bde list that supports the sg_tablesize value. - */ - void *data; - dma_addr_t dma_handle; - - struct fcp_cmnd *fcp_cmnd; - struct fcp_rsp *fcp_rsp; - struct ulp_bde64 *fcp_bpl; - - dma_addr_t dma_phys_bpl; - - /* cur_iocbq has phys of the dma-able buffer. - * Iotag is in here - */ - struct lpfc_iocbq cur_iocbq; - wait_queue_head_t *waitq; - unsigned long start_time; - -#ifdef CONFIG_SCSI_LPFC_DEBUG_FS - /* Used to restore any changes to protection data for error injection */ - void *prot_data_segment; - uint32_t prot_data; - uint32_t prot_data_type; -#define LPFC_INJERR_REFTAG 1 -#define LPFC_INJERR_APPTAG 2 -#define LPFC_INJERR_GUARD 3 -#endif -}; - -#define LPFC_SCSI_DMA_EXT_SIZE 264 -#define LPFC_BPL_SIZE 1024 -#define MDAC_DIRECT_CMD 0x22 diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.c deleted file mode 100644 index dbaf5b96..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.c +++ /dev/null @@ -1,16044 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_crtn.h" -#include "lpfc_logmsg.h" -#include "lpfc_compat.h" -#include "lpfc_debugfs.h" -#include "lpfc_vport.h" - -/* There are only four IOCB completion types. */ -typedef enum _lpfc_iocb_type { - LPFC_UNKNOWN_IOCB, - LPFC_UNSOL_IOCB, - LPFC_SOL_IOCB, - LPFC_ABORT_IOCB -} lpfc_iocb_type; - - -/* Provide function prototypes local to this module. */ -static int lpfc_sli_issue_mbox_s4(struct lpfc_hba *, LPFC_MBOXQ_t *, - uint32_t); -static int lpfc_sli4_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *, - uint8_t *, uint32_t *); -static struct lpfc_iocbq *lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *, - struct lpfc_iocbq *); -static void lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *, - struct hbq_dmabuf *); -static int lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_cqe *); - -static IOCB_t * -lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) -{ - return &iocbq->iocb; -} - -/** - * lpfc_sli4_wq_put - Put a Work Queue Entry on an Work Queue - * @q: The Work Queue to operate on. - * @wqe: The work Queue Entry to put on the Work queue. - * - * This routine will copy the contents of @wqe to the next available entry on - * the @q. This function will then ring the Work Queue Doorbell to signal the - * HBA to start processing the Work Queue Entry. This function returns 0 if - * successful. If no entries are available on @q then this function will return - * -ENOMEM. - * The caller is expected to hold the hbalock when calling this routine. - **/ -static uint32_t -lpfc_sli4_wq_put(struct lpfc_queue *q, union lpfc_wqe *wqe) -{ - union lpfc_wqe *temp_wqe; - struct lpfc_register doorbell; - uint32_t host_index; - - /* sanity check on queue memory */ - if (unlikely(!q)) - return -ENOMEM; - temp_wqe = q->qe[q->host_index].wqe; - - /* If the host has not yet processed the next entry then we are done */ - if (((q->host_index + 1) % q->entry_count) == q->hba_index) - return -ENOMEM; - /* set consumption flag every once in a while */ - if (!((q->host_index + 1) % q->entry_repost)) - bf_set(wqe_wqec, &wqe->generic.wqe_com, 1); - if (q->phba->sli3_options & LPFC_SLI4_PHWQ_ENABLED) - bf_set(wqe_wqid, &wqe->generic.wqe_com, q->queue_id); - lpfc_sli_pcimem_bcopy(wqe, temp_wqe, q->entry_size); - - /* Update the host index before invoking device */ - host_index = q->host_index; - q->host_index = ((q->host_index + 1) % q->entry_count); - - /* Ring Doorbell */ - doorbell.word0 = 0; - bf_set(lpfc_wq_doorbell_num_posted, &doorbell, 1); - bf_set(lpfc_wq_doorbell_index, &doorbell, host_index); - bf_set(lpfc_wq_doorbell_id, &doorbell, q->queue_id); - writel(doorbell.word0, q->phba->sli4_hba.WQDBregaddr); - readl(q->phba->sli4_hba.WQDBregaddr); /* Flush */ - - return 0; -} - -/** - * lpfc_sli4_wq_release - Updates internal hba index for WQ - * @q: The Work Queue to operate on. - * @index: The index to advance the hba index to. - * - * This routine will update the HBA index of a queue to reflect consumption of - * Work Queue Entries by the HBA. When the HBA indicates that it has consumed - * an entry the host calls this function to update the queue's internal - * pointers. This routine returns the number of entries that were consumed by - * the HBA. - **/ -static uint32_t -lpfc_sli4_wq_release(struct lpfc_queue *q, uint32_t index) -{ - uint32_t released = 0; - - /* sanity check on queue memory */ - if (unlikely(!q)) - return 0; - - if (q->hba_index == index) - return 0; - do { - q->hba_index = ((q->hba_index + 1) % q->entry_count); - released++; - } while (q->hba_index != index); - return released; -} - -/** - * lpfc_sli4_mq_put - Put a Mailbox Queue Entry on an Mailbox Queue - * @q: The Mailbox Queue to operate on. - * @wqe: The Mailbox Queue Entry to put on the Work queue. - * - * This routine will copy the contents of @mqe to the next available entry on - * the @q. This function will then ring the Work Queue Doorbell to signal the - * HBA to start processing the Work Queue Entry. This function returns 0 if - * successful. If no entries are available on @q then this function will return - * -ENOMEM. - * The caller is expected to hold the hbalock when calling this routine. - **/ -static uint32_t -lpfc_sli4_mq_put(struct lpfc_queue *q, struct lpfc_mqe *mqe) -{ - struct lpfc_mqe *temp_mqe; - struct lpfc_register doorbell; - uint32_t host_index; - - /* sanity check on queue memory */ - if (unlikely(!q)) - return -ENOMEM; - temp_mqe = q->qe[q->host_index].mqe; - - /* If the host has not yet processed the next entry then we are done */ - if (((q->host_index + 1) % q->entry_count) == q->hba_index) - return -ENOMEM; - lpfc_sli_pcimem_bcopy(mqe, temp_mqe, q->entry_size); - /* Save off the mailbox pointer for completion */ - q->phba->mbox = (MAILBOX_t *)temp_mqe; - - /* Update the host index before invoking device */ - host_index = q->host_index; - q->host_index = ((q->host_index + 1) % q->entry_count); - - /* Ring Doorbell */ - doorbell.word0 = 0; - bf_set(lpfc_mq_doorbell_num_posted, &doorbell, 1); - bf_set(lpfc_mq_doorbell_id, &doorbell, q->queue_id); - writel(doorbell.word0, q->phba->sli4_hba.MQDBregaddr); - readl(q->phba->sli4_hba.MQDBregaddr); /* Flush */ - return 0; -} - -/** - * lpfc_sli4_mq_release - Updates internal hba index for MQ - * @q: The Mailbox Queue to operate on. - * - * This routine will update the HBA index of a queue to reflect consumption of - * a Mailbox Queue Entry by the HBA. When the HBA indicates that it has consumed - * an entry the host calls this function to update the queue's internal - * pointers. This routine returns the number of entries that were consumed by - * the HBA. - **/ -static uint32_t -lpfc_sli4_mq_release(struct lpfc_queue *q) -{ - /* sanity check on queue memory */ - if (unlikely(!q)) - return 0; - - /* Clear the mailbox pointer for completion */ - q->phba->mbox = NULL; - q->hba_index = ((q->hba_index + 1) % q->entry_count); - return 1; -} - -/** - * lpfc_sli4_eq_get - Gets the next valid EQE from a EQ - * @q: The Event Queue to get the first valid EQE from - * - * This routine will get the first valid Event Queue Entry from @q, update - * the queue's internal hba index, and return the EQE. If no valid EQEs are in - * the Queue (no more work to do), or the Queue is full of EQEs that have been - * processed, but not popped back to the HBA then this routine will return NULL. - **/ -static struct lpfc_eqe * -lpfc_sli4_eq_get(struct lpfc_queue *q) -{ - struct lpfc_eqe *eqe; - - /* sanity check on queue memory */ - if (unlikely(!q)) - return NULL; - eqe = q->qe[q->hba_index].eqe; - - /* If the next EQE is not valid then we are done */ - if (!bf_get_le32(lpfc_eqe_valid, eqe)) - return NULL; - /* If the host has not yet processed the next entry then we are done */ - if (((q->hba_index + 1) % q->entry_count) == q->host_index) - return NULL; - - q->hba_index = ((q->hba_index + 1) % q->entry_count); - return eqe; -} - -/** - * lpfc_sli4_eq_release - Indicates the host has finished processing an EQ - * @q: The Event Queue that the host has completed processing for. - * @arm: Indicates whether the host wants to arms this CQ. - * - * This routine will mark all Event Queue Entries on @q, from the last - * known completed entry to the last entry that was processed, as completed - * by clearing the valid bit for each completion queue entry. Then it will - * notify the HBA, by ringing the doorbell, that the EQEs have been processed. - * The internal host index in the @q will be updated by this routine to indicate - * that the host has finished processing the entries. The @arm parameter - * indicates that the queue should be rearmed when ringing the doorbell. - * - * This function will return the number of EQEs that were popped. - **/ -uint32_t -lpfc_sli4_eq_release(struct lpfc_queue *q, bool arm) -{ - uint32_t released = 0; - struct lpfc_eqe *temp_eqe; - struct lpfc_register doorbell; - - /* sanity check on queue memory */ - if (unlikely(!q)) - return 0; - - /* while there are valid entries */ - while (q->hba_index != q->host_index) { - temp_eqe = q->qe[q->host_index].eqe; - bf_set_le32(lpfc_eqe_valid, temp_eqe, 0); - released++; - q->host_index = ((q->host_index + 1) % q->entry_count); - } - if (unlikely(released == 0 && !arm)) - return 0; - - /* ring doorbell for number popped */ - doorbell.word0 = 0; - if (arm) { - bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1); - bf_set(lpfc_eqcq_doorbell_eqci, &doorbell, 1); - } - bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released); - bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_EVENT); - bf_set(lpfc_eqcq_doorbell_eqid_hi, &doorbell, - (q->queue_id >> LPFC_EQID_HI_FIELD_SHIFT)); - bf_set(lpfc_eqcq_doorbell_eqid_lo, &doorbell, q->queue_id); - writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); - /* PCI read to flush PCI pipeline on re-arming for INTx mode */ - if ((q->phba->intr_type == INTx) && (arm == LPFC_QUEUE_REARM)) - readl(q->phba->sli4_hba.EQCQDBregaddr); - return released; -} - -/** - * lpfc_sli4_cq_get - Gets the next valid CQE from a CQ - * @q: The Completion Queue to get the first valid CQE from - * - * This routine will get the first valid Completion Queue Entry from @q, update - * the queue's internal hba index, and return the CQE. If no valid CQEs are in - * the Queue (no more work to do), or the Queue is full of CQEs that have been - * processed, but not popped back to the HBA then this routine will return NULL. - **/ -static struct lpfc_cqe * -lpfc_sli4_cq_get(struct lpfc_queue *q) -{ - struct lpfc_cqe *cqe; - - /* sanity check on queue memory */ - if (unlikely(!q)) - return NULL; - - /* If the next CQE is not valid then we are done */ - if (!bf_get_le32(lpfc_cqe_valid, q->qe[q->hba_index].cqe)) - return NULL; - /* If the host has not yet processed the next entry then we are done */ - if (((q->hba_index + 1) % q->entry_count) == q->host_index) - return NULL; - - cqe = q->qe[q->hba_index].cqe; - q->hba_index = ((q->hba_index + 1) % q->entry_count); - return cqe; -} - -/** - * lpfc_sli4_cq_release - Indicates the host has finished processing a CQ - * @q: The Completion Queue that the host has completed processing for. - * @arm: Indicates whether the host wants to arms this CQ. - * - * This routine will mark all Completion queue entries on @q, from the last - * known completed entry to the last entry that was processed, as completed - * by clearing the valid bit for each completion queue entry. Then it will - * notify the HBA, by ringing the doorbell, that the CQEs have been processed. - * The internal host index in the @q will be updated by this routine to indicate - * that the host has finished processing the entries. The @arm parameter - * indicates that the queue should be rearmed when ringing the doorbell. - * - * This function will return the number of CQEs that were released. - **/ -uint32_t -lpfc_sli4_cq_release(struct lpfc_queue *q, bool arm) -{ - uint32_t released = 0; - struct lpfc_cqe *temp_qe; - struct lpfc_register doorbell; - - /* sanity check on queue memory */ - if (unlikely(!q)) - return 0; - /* while there are valid entries */ - while (q->hba_index != q->host_index) { - temp_qe = q->qe[q->host_index].cqe; - bf_set_le32(lpfc_cqe_valid, temp_qe, 0); - released++; - q->host_index = ((q->host_index + 1) % q->entry_count); - } - if (unlikely(released == 0 && !arm)) - return 0; - - /* ring doorbell for number popped */ - doorbell.word0 = 0; - if (arm) - bf_set(lpfc_eqcq_doorbell_arm, &doorbell, 1); - bf_set(lpfc_eqcq_doorbell_num_released, &doorbell, released); - bf_set(lpfc_eqcq_doorbell_qt, &doorbell, LPFC_QUEUE_TYPE_COMPLETION); - bf_set(lpfc_eqcq_doorbell_cqid_hi, &doorbell, - (q->queue_id >> LPFC_CQID_HI_FIELD_SHIFT)); - bf_set(lpfc_eqcq_doorbell_cqid_lo, &doorbell, q->queue_id); - writel(doorbell.word0, q->phba->sli4_hba.EQCQDBregaddr); - return released; -} - -/** - * lpfc_sli4_rq_put - Put a Receive Buffer Queue Entry on a Receive Queue - * @q: The Header Receive Queue to operate on. - * @wqe: The Receive Queue Entry to put on the Receive queue. - * - * This routine will copy the contents of @wqe to the next available entry on - * the @q. This function will then ring the Receive Queue Doorbell to signal the - * HBA to start processing the Receive Queue Entry. This function returns the - * index that the rqe was copied to if successful. If no entries are available - * on @q then this function will return -ENOMEM. - * The caller is expected to hold the hbalock when calling this routine. - **/ -static int -lpfc_sli4_rq_put(struct lpfc_queue *hq, struct lpfc_queue *dq, - struct lpfc_rqe *hrqe, struct lpfc_rqe *drqe) -{ - struct lpfc_rqe *temp_hrqe; - struct lpfc_rqe *temp_drqe; - struct lpfc_register doorbell; - int put_index = hq->host_index; - - /* sanity check on queue memory */ - if (unlikely(!hq) || unlikely(!dq)) - return -ENOMEM; - temp_hrqe = hq->qe[hq->host_index].rqe; - temp_drqe = dq->qe[dq->host_index].rqe; - - if (hq->type != LPFC_HRQ || dq->type != LPFC_DRQ) - return -EINVAL; - if (hq->host_index != dq->host_index) - return -EINVAL; - /* If the host has not yet processed the next entry then we are done */ - if (((hq->host_index + 1) % hq->entry_count) == hq->hba_index) - return -EBUSY; - lpfc_sli_pcimem_bcopy(hrqe, temp_hrqe, hq->entry_size); - lpfc_sli_pcimem_bcopy(drqe, temp_drqe, dq->entry_size); - - /* Update the host index to point to the next slot */ - hq->host_index = ((hq->host_index + 1) % hq->entry_count); - dq->host_index = ((dq->host_index + 1) % dq->entry_count); - - /* Ring The Header Receive Queue Doorbell */ - if (!(hq->host_index % hq->entry_repost)) { - doorbell.word0 = 0; - bf_set(lpfc_rq_doorbell_num_posted, &doorbell, - hq->entry_repost); - bf_set(lpfc_rq_doorbell_id, &doorbell, hq->queue_id); - writel(doorbell.word0, hq->phba->sli4_hba.RQDBregaddr); - } - return put_index; -} - -/** - * lpfc_sli4_rq_release - Updates internal hba index for RQ - * @q: The Header Receive Queue to operate on. - * - * This routine will update the HBA index of a queue to reflect consumption of - * one Receive Queue Entry by the HBA. When the HBA indicates that it has - * consumed an entry the host calls this function to update the queue's - * internal pointers. This routine returns the number of entries that were - * consumed by the HBA. - **/ -static uint32_t -lpfc_sli4_rq_release(struct lpfc_queue *hq, struct lpfc_queue *dq) -{ - /* sanity check on queue memory */ - if (unlikely(!hq) || unlikely(!dq)) - return 0; - - if ((hq->type != LPFC_HRQ) || (dq->type != LPFC_DRQ)) - return 0; - hq->hba_index = ((hq->hba_index + 1) % hq->entry_count); - dq->hba_index = ((dq->hba_index + 1) % dq->entry_count); - return 1; -} - -/** - * lpfc_cmd_iocb - Get next command iocb entry in the ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function returns pointer to next command iocb entry - * in the command ring. The caller must hold hbalock to prevent - * other threads consume the next command iocb. - * SLI-2/SLI-3 provide different sized iocbs. - **/ -static inline IOCB_t * -lpfc_cmd_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - return (IOCB_t *) (((char *) pring->cmdringaddr) + - pring->cmdidx * phba->iocb_cmd_size); -} - -/** - * lpfc_resp_iocb - Get next response iocb entry in the ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function returns pointer to next response iocb entry - * in the response ring. The caller must hold hbalock to make sure - * that no other thread consume the next response iocb. - * SLI-2/SLI-3 provide different sized iocbs. - **/ -static inline IOCB_t * -lpfc_resp_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - return (IOCB_t *) (((char *) pring->rspringaddr) + - pring->rspidx * phba->iocb_rsp_size); -} - -/** - * __lpfc_sli_get_iocbq - Allocates an iocb object from iocb pool - * @phba: Pointer to HBA context object. - * - * This function is called with hbalock held. This function - * allocates a new driver iocb object from the iocb pool. If the - * allocation is successful, it returns pointer to the newly - * allocated iocb object else it returns NULL. - **/ -static struct lpfc_iocbq * -__lpfc_sli_get_iocbq(struct lpfc_hba *phba) -{ - struct list_head *lpfc_iocb_list = &phba->lpfc_iocb_list; - struct lpfc_iocbq * iocbq = NULL; - - list_remove_head(lpfc_iocb_list, iocbq, struct lpfc_iocbq, list); - if (iocbq) - phba->iocb_cnt++; - if (phba->iocb_cnt > phba->iocb_max) - phba->iocb_max = phba->iocb_cnt; - return iocbq; -} - -/** - * __lpfc_clear_active_sglq - Remove the active sglq for this XRI. - * @phba: Pointer to HBA context object. - * @xritag: XRI value. - * - * This function clears the sglq pointer from the array of acive - * sglq's. The xritag that is passed in is used to index into the - * array. Before the xritag can be used it needs to be adjusted - * by subtracting the xribase. - * - * Returns sglq ponter = success, NULL = Failure. - **/ -static struct lpfc_sglq * -__lpfc_clear_active_sglq(struct lpfc_hba *phba, uint16_t xritag) -{ - struct lpfc_sglq *sglq; - - sglq = phba->sli4_hba.lpfc_sglq_active_list[xritag]; - phba->sli4_hba.lpfc_sglq_active_list[xritag] = NULL; - return sglq; -} - -/** - * __lpfc_get_active_sglq - Get the active sglq for this XRI. - * @phba: Pointer to HBA context object. - * @xritag: XRI value. - * - * This function returns the sglq pointer from the array of acive - * sglq's. The xritag that is passed in is used to index into the - * array. Before the xritag can be used it needs to be adjusted - * by subtracting the xribase. - * - * Returns sglq ponter = success, NULL = Failure. - **/ -struct lpfc_sglq * -__lpfc_get_active_sglq(struct lpfc_hba *phba, uint16_t xritag) -{ - struct lpfc_sglq *sglq; - - sglq = phba->sli4_hba.lpfc_sglq_active_list[xritag]; - return sglq; -} - -/** - * lpfc_clr_rrq_active - Clears RRQ active bit in xri_bitmap. - * @phba: Pointer to HBA context object. - * @xritag: xri used in this exchange. - * @rrq: The RRQ to be cleared. - * - **/ -void -lpfc_clr_rrq_active(struct lpfc_hba *phba, - uint16_t xritag, - struct lpfc_node_rrq *rrq) -{ - struct lpfc_nodelist *ndlp = NULL; - - if ((rrq->vport) && NLP_CHK_NODE_ACT(rrq->ndlp)) - ndlp = lpfc_findnode_did(rrq->vport, rrq->nlp_DID); - - /* The target DID could have been swapped (cable swap) - * we should use the ndlp from the findnode if it is - * available. - */ - if ((!ndlp) && rrq->ndlp) - ndlp = rrq->ndlp; - - if (!ndlp) - goto out; - - if (test_and_clear_bit(xritag, ndlp->active_rrqs.xri_bitmap)) { - rrq->send_rrq = 0; - rrq->xritag = 0; - rrq->rrq_stop_time = 0; - } -out: - mempool_free(rrq, phba->rrq_pool); -} - -/** - * lpfc_handle_rrq_active - Checks if RRQ has waithed RATOV. - * @phba: Pointer to HBA context object. - * - * This function is called with hbalock held. This function - * Checks if stop_time (ratov from setting rrq active) has - * been reached, if it has and the send_rrq flag is set then - * it will call lpfc_send_rrq. If the send_rrq flag is not set - * then it will just call the routine to clear the rrq and - * free the rrq resource. - * The timer is set to the next rrq that is going to expire before - * leaving the routine. - * - **/ -void -lpfc_handle_rrq_active(struct lpfc_hba *phba) -{ - struct lpfc_node_rrq *rrq; - struct lpfc_node_rrq *nextrrq; - unsigned long next_time; - unsigned long iflags; - LIST_HEAD(send_rrq); - - spin_lock_irqsave(&phba->hbalock, iflags); - phba->hba_flag &= ~HBA_RRQ_ACTIVE; - next_time = jiffies + HZ * (phba->fc_ratov + 1); - list_for_each_entry_safe(rrq, nextrrq, - &phba->active_rrq_list, list) { - if (time_after(jiffies, rrq->rrq_stop_time)) - list_move(&rrq->list, &send_rrq); - else if (time_before(rrq->rrq_stop_time, next_time)) - next_time = rrq->rrq_stop_time; - } - spin_unlock_irqrestore(&phba->hbalock, iflags); - if (!list_empty(&phba->active_rrq_list)) - mod_timer(&phba->rrq_tmr, next_time); - list_for_each_entry_safe(rrq, nextrrq, &send_rrq, list) { - list_del(&rrq->list); - if (!rrq->send_rrq) - /* this call will free the rrq */ - lpfc_clr_rrq_active(phba, rrq->xritag, rrq); - else if (lpfc_send_rrq(phba, rrq)) { - /* if we send the rrq then the completion handler - * will clear the bit in the xribitmap. - */ - lpfc_clr_rrq_active(phba, rrq->xritag, - rrq); - } - } -} - -/** - * lpfc_get_active_rrq - Get the active RRQ for this exchange. - * @vport: Pointer to vport context object. - * @xri: The xri used in the exchange. - * @did: The targets DID for this exchange. - * - * returns NULL = rrq not found in the phba->active_rrq_list. - * rrq = rrq for this xri and target. - **/ -struct lpfc_node_rrq * -lpfc_get_active_rrq(struct lpfc_vport *vport, uint16_t xri, uint32_t did) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_node_rrq *rrq; - struct lpfc_node_rrq *nextrrq; - unsigned long iflags; - - if (phba->sli_rev != LPFC_SLI_REV4) - return NULL; - spin_lock_irqsave(&phba->hbalock, iflags); - list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) { - if (rrq->vport == vport && rrq->xritag == xri && - rrq->nlp_DID == did){ - list_del(&rrq->list); - spin_unlock_irqrestore(&phba->hbalock, iflags); - return rrq; - } - } - spin_unlock_irqrestore(&phba->hbalock, iflags); - return NULL; -} - -/** - * lpfc_cleanup_vports_rrqs - Remove and clear the active RRQ for this vport. - * @vport: Pointer to vport context object. - * @ndlp: Pointer to the lpfc_node_list structure. - * If ndlp is NULL Remove all active RRQs for this vport from the - * phba->active_rrq_list and clear the rrq. - * If ndlp is not NULL then only remove rrqs for this vport & this ndlp. - **/ -void -lpfc_cleanup_vports_rrqs(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) - -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_node_rrq *rrq; - struct lpfc_node_rrq *nextrrq; - unsigned long iflags; - LIST_HEAD(rrq_list); - - if (phba->sli_rev != LPFC_SLI_REV4) - return; - if (!ndlp) { - lpfc_sli4_vport_delete_els_xri_aborted(vport); - lpfc_sli4_vport_delete_fcp_xri_aborted(vport); - } - spin_lock_irqsave(&phba->hbalock, iflags); - list_for_each_entry_safe(rrq, nextrrq, &phba->active_rrq_list, list) - if ((rrq->vport == vport) && (!ndlp || rrq->ndlp == ndlp)) - list_move(&rrq->list, &rrq_list); - spin_unlock_irqrestore(&phba->hbalock, iflags); - - list_for_each_entry_safe(rrq, nextrrq, &rrq_list, list) { - list_del(&rrq->list); - lpfc_clr_rrq_active(phba, rrq->xritag, rrq); - } -} - -/** - * lpfc_cleanup_wt_rrqs - Remove all rrq's from the active list. - * @phba: Pointer to HBA context object. - * - * Remove all rrqs from the phba->active_rrq_list and free them by - * calling __lpfc_clr_active_rrq - * - **/ -void -lpfc_cleanup_wt_rrqs(struct lpfc_hba *phba) -{ - struct lpfc_node_rrq *rrq; - struct lpfc_node_rrq *nextrrq; - unsigned long next_time; - unsigned long iflags; - LIST_HEAD(rrq_list); - - if (phba->sli_rev != LPFC_SLI_REV4) - return; - spin_lock_irqsave(&phba->hbalock, iflags); - phba->hba_flag &= ~HBA_RRQ_ACTIVE; - next_time = jiffies + HZ * (phba->fc_ratov * 2); - list_splice_init(&phba->active_rrq_list, &rrq_list); - spin_unlock_irqrestore(&phba->hbalock, iflags); - - list_for_each_entry_safe(rrq, nextrrq, &rrq_list, list) { - list_del(&rrq->list); - lpfc_clr_rrq_active(phba, rrq->xritag, rrq); - } - if (!list_empty(&phba->active_rrq_list)) - mod_timer(&phba->rrq_tmr, next_time); -} - - -/** - * lpfc_test_rrq_active - Test RRQ bit in xri_bitmap. - * @phba: Pointer to HBA context object. - * @ndlp: Targets nodelist pointer for this exchange. - * @xritag the xri in the bitmap to test. - * - * This function is called with hbalock held. This function - * returns 0 = rrq not active for this xri - * 1 = rrq is valid for this xri. - **/ -int -lpfc_test_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, - uint16_t xritag) -{ - if (!ndlp) - return 0; - if (test_bit(xritag, ndlp->active_rrqs.xri_bitmap)) - return 1; - else - return 0; -} - -/** - * lpfc_set_rrq_active - set RRQ active bit in xri_bitmap. - * @phba: Pointer to HBA context object. - * @ndlp: nodelist pointer for this target. - * @xritag: xri used in this exchange. - * @rxid: Remote Exchange ID. - * @send_rrq: Flag used to determine if we should send rrq els cmd. - * - * This function takes the hbalock. - * The active bit is always set in the active rrq xri_bitmap even - * if there is no slot avaiable for the other rrq information. - * - * returns 0 rrq actived for this xri - * < 0 No memory or invalid ndlp. - **/ -int -lpfc_set_rrq_active(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, - uint16_t xritag, uint16_t rxid, uint16_t send_rrq) -{ - unsigned long iflags; - struct lpfc_node_rrq *rrq; - int empty; - - if (!ndlp) - return -EINVAL; - - if (!phba->cfg_enable_rrq) - return -EINVAL; - - spin_lock_irqsave(&phba->hbalock, iflags); - if (phba->pport->load_flag & FC_UNLOADING) { - phba->hba_flag &= ~HBA_RRQ_ACTIVE; - goto out; - } - - /* - * set the active bit even if there is no mem available. - */ - if (NLP_CHK_FREE_REQ(ndlp)) - goto out; - - if (ndlp->vport && (ndlp->vport->load_flag & FC_UNLOADING)) - goto out; - - if (test_and_set_bit(xritag, ndlp->active_rrqs.xri_bitmap)) - goto out; - - spin_unlock_irqrestore(&phba->hbalock, iflags); - rrq = mempool_alloc(phba->rrq_pool, GFP_KERNEL); - if (!rrq) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3155 Unable to allocate RRQ xri:0x%x rxid:0x%x" - " DID:0x%x Send:%d\n", - xritag, rxid, ndlp->nlp_DID, send_rrq); - return -EINVAL; - } - rrq->send_rrq = send_rrq; - rrq->xritag = xritag; - rrq->rrq_stop_time = jiffies + HZ * (phba->fc_ratov + 1); - rrq->ndlp = ndlp; - rrq->nlp_DID = ndlp->nlp_DID; - rrq->vport = ndlp->vport; - rrq->rxid = rxid; - rrq->send_rrq = send_rrq; - spin_lock_irqsave(&phba->hbalock, iflags); - empty = list_empty(&phba->active_rrq_list); - list_add_tail(&rrq->list, &phba->active_rrq_list); - phba->hba_flag |= HBA_RRQ_ACTIVE; - if (empty) - lpfc_worker_wake_up(phba); - spin_unlock_irqrestore(&phba->hbalock, iflags); - return 0; -out: - spin_unlock_irqrestore(&phba->hbalock, iflags); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2921 Can't set rrq active xri:0x%x rxid:0x%x" - " DID:0x%x Send:%d\n", - xritag, rxid, ndlp->nlp_DID, send_rrq); - return -EINVAL; -} - -/** - * __lpfc_sli_get_sglq - Allocates an iocb object from sgl pool - * @phba: Pointer to HBA context object. - * @piocb: Pointer to the iocbq. - * - * This function is called with hbalock held. This function - * gets a new driver sglq object from the sglq list. If the - * list is not empty then it is successful, it returns pointer to the newly - * allocated sglq object else it returns NULL. - **/ -static struct lpfc_sglq * -__lpfc_sli_get_sglq(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq) -{ - struct list_head *lpfc_sgl_list = &phba->sli4_hba.lpfc_sgl_list; - struct lpfc_sglq *sglq = NULL; - struct lpfc_sglq *start_sglq = NULL; - struct lpfc_scsi_buf *lpfc_cmd; - struct lpfc_nodelist *ndlp; - int found = 0; - - if (piocbq->iocb_flag & LPFC_IO_FCP) { - lpfc_cmd = (struct lpfc_scsi_buf *) piocbq->context1; - ndlp = lpfc_cmd->rdata->pnode; - } else if ((piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) && - !(piocbq->iocb_flag & LPFC_IO_LIBDFC)) - ndlp = piocbq->context_un.ndlp; - else - ndlp = piocbq->context1; - - list_remove_head(lpfc_sgl_list, sglq, struct lpfc_sglq, list); - start_sglq = sglq; - while (!found) { - if (!sglq) - return NULL; - if (lpfc_test_rrq_active(phba, ndlp, sglq->sli4_xritag)) { - /* This xri has an rrq outstanding for this DID. - * put it back in the list and get another xri. - */ - list_add_tail(&sglq->list, lpfc_sgl_list); - sglq = NULL; - list_remove_head(lpfc_sgl_list, sglq, - struct lpfc_sglq, list); - if (sglq == start_sglq) { - sglq = NULL; - break; - } else - continue; - } - sglq->ndlp = ndlp; - found = 1; - phba->sli4_hba.lpfc_sglq_active_list[sglq->sli4_lxritag] = sglq; - sglq->state = SGL_ALLOCATED; - } - return sglq; -} - -/** - * lpfc_sli_get_iocbq - Allocates an iocb object from iocb pool - * @phba: Pointer to HBA context object. - * - * This function is called with no lock held. This function - * allocates a new driver iocb object from the iocb pool. If the - * allocation is successful, it returns pointer to the newly - * allocated iocb object else it returns NULL. - **/ -struct lpfc_iocbq * -lpfc_sli_get_iocbq(struct lpfc_hba *phba) -{ - struct lpfc_iocbq * iocbq = NULL; - unsigned long iflags; - - spin_lock_irqsave(&phba->hbalock, iflags); - iocbq = __lpfc_sli_get_iocbq(phba); - spin_unlock_irqrestore(&phba->hbalock, iflags); - return iocbq; -} - -/** - * __lpfc_sli_release_iocbq_s4 - Release iocb to the iocb pool - * @phba: Pointer to HBA context object. - * @iocbq: Pointer to driver iocb object. - * - * This function is called with hbalock held to release driver - * iocb object to the iocb pool. The iotag in the iocb object - * does not change for each use of the iocb object. This function - * clears all other fields of the iocb object when it is freed. - * The sqlq structure that holds the xritag and phys and virtual - * mappings for the scatter gather list is retrieved from the - * active array of sglq. The get of the sglq pointer also clears - * the entry in the array. If the status of the IO indiactes that - * this IO was aborted then the sglq entry it put on the - * lpfc_abts_els_sgl_list until the CQ_ABORTED_XRI is received. If the - * IO has good status or fails for any other reason then the sglq - * entry is added to the free list (lpfc_sgl_list). - **/ -static void -__lpfc_sli_release_iocbq_s4(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) -{ - struct lpfc_sglq *sglq; - size_t start_clean = offsetof(struct lpfc_iocbq, iocb); - unsigned long iflag = 0; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - - if (iocbq->sli4_xritag == NO_XRI) - sglq = NULL; - else - sglq = __lpfc_clear_active_sglq(phba, iocbq->sli4_lxritag); - - if (sglq) { - if ((iocbq->iocb_flag & LPFC_EXCHANGE_BUSY) && - (sglq->state != SGL_XRI_ABORTED)) { - spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, - iflag); - list_add(&sglq->list, - &phba->sli4_hba.lpfc_abts_els_sgl_list); - spin_unlock_irqrestore( - &phba->sli4_hba.abts_sgl_list_lock, iflag); - } else { - sglq->state = SGL_FREED; - sglq->ndlp = NULL; - list_add_tail(&sglq->list, - &phba->sli4_hba.lpfc_sgl_list); - - /* Check if TXQ queue needs to be serviced */ - if (pring->txq_cnt) - lpfc_worker_wake_up(phba); - } - } - - - /* - * Clean all volatile data fields, preserve iotag and node struct. - */ - memset((char *)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); - iocbq->sli4_lxritag = NO_XRI; - iocbq->sli4_xritag = NO_XRI; - list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); -} - - -/** - * __lpfc_sli_release_iocbq_s3 - Release iocb to the iocb pool - * @phba: Pointer to HBA context object. - * @iocbq: Pointer to driver iocb object. - * - * This function is called with hbalock held to release driver - * iocb object to the iocb pool. The iotag in the iocb object - * does not change for each use of the iocb object. This function - * clears all other fields of the iocb object when it is freed. - **/ -static void -__lpfc_sli_release_iocbq_s3(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) -{ - size_t start_clean = offsetof(struct lpfc_iocbq, iocb); - - /* - * Clean all volatile data fields, preserve iotag and node struct. - */ - memset((char*)iocbq + start_clean, 0, sizeof(*iocbq) - start_clean); - iocbq->sli4_xritag = NO_XRI; - list_add_tail(&iocbq->list, &phba->lpfc_iocb_list); -} - -/** - * __lpfc_sli_release_iocbq - Release iocb to the iocb pool - * @phba: Pointer to HBA context object. - * @iocbq: Pointer to driver iocb object. - * - * This function is called with hbalock held to release driver - * iocb object to the iocb pool. The iotag in the iocb object - * does not change for each use of the iocb object. This function - * clears all other fields of the iocb object when it is freed. - **/ -static void -__lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) -{ - phba->__lpfc_sli_release_iocbq(phba, iocbq); - phba->iocb_cnt--; -} - -/** - * lpfc_sli_release_iocbq - Release iocb to the iocb pool - * @phba: Pointer to HBA context object. - * @iocbq: Pointer to driver iocb object. - * - * This function is called with no lock held to release the iocb to - * iocb pool. - **/ -void -lpfc_sli_release_iocbq(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) -{ - unsigned long iflags; - - /* - * Clean all volatile data fields, preserve iotag and node struct. - */ - spin_lock_irqsave(&phba->hbalock, iflags); - __lpfc_sli_release_iocbq(phba, iocbq); - spin_unlock_irqrestore(&phba->hbalock, iflags); -} - -/** - * lpfc_sli_cancel_iocbs - Cancel all iocbs from a list. - * @phba: Pointer to HBA context object. - * @iocblist: List of IOCBs. - * @ulpstatus: ULP status in IOCB command field. - * @ulpWord4: ULP word-4 in IOCB command field. - * - * This function is called with a list of IOCBs to cancel. It cancels the IOCB - * on the list by invoking the complete callback function associated with the - * IOCB with the provided @ulpstatus and @ulpword4 set to the IOCB commond - * fields. - **/ -void -lpfc_sli_cancel_iocbs(struct lpfc_hba *phba, struct list_head *iocblist, - uint32_t ulpstatus, uint32_t ulpWord4) -{ - struct lpfc_iocbq *piocb; - - while (!list_empty(iocblist)) { - list_remove_head(iocblist, piocb, struct lpfc_iocbq, list); - - if (!piocb->iocb_cmpl) - lpfc_sli_release_iocbq(phba, piocb); - else { - piocb->iocb.ulpStatus = ulpstatus; - piocb->iocb.un.ulpWord[4] = ulpWord4; - (piocb->iocb_cmpl) (phba, piocb, piocb); - } - } - return; -} - -/** - * lpfc_sli_iocb_cmd_type - Get the iocb type - * @iocb_cmnd: iocb command code. - * - * This function is called by ring event handler function to get the iocb type. - * This function translates the iocb command to an iocb command type used to - * decide the final disposition of each completed IOCB. - * The function returns - * LPFC_UNKNOWN_IOCB if it is an unsupported iocb - * LPFC_SOL_IOCB if it is a solicited iocb completion - * LPFC_ABORT_IOCB if it is an abort iocb - * LPFC_UNSOL_IOCB if it is an unsolicited iocb - * - * The caller is not required to hold any lock. - **/ -static lpfc_iocb_type -lpfc_sli_iocb_cmd_type(uint8_t iocb_cmnd) -{ - lpfc_iocb_type type = LPFC_UNKNOWN_IOCB; - - if (iocb_cmnd > CMD_MAX_IOCB_CMD) - return 0; - - switch (iocb_cmnd) { - case CMD_XMIT_SEQUENCE_CR: - case CMD_XMIT_SEQUENCE_CX: - case CMD_XMIT_BCAST_CN: - case CMD_XMIT_BCAST_CX: - case CMD_ELS_REQUEST_CR: - case CMD_ELS_REQUEST_CX: - case CMD_CREATE_XRI_CR: - case CMD_CREATE_XRI_CX: - case CMD_GET_RPI_CN: - case CMD_XMIT_ELS_RSP_CX: - case CMD_GET_RPI_CR: - case CMD_FCP_IWRITE_CR: - case CMD_FCP_IWRITE_CX: - case CMD_FCP_IREAD_CR: - case CMD_FCP_IREAD_CX: - case CMD_FCP_ICMND_CR: - case CMD_FCP_ICMND_CX: - case CMD_FCP_TSEND_CX: - case CMD_FCP_TRSP_CX: - case CMD_FCP_TRECEIVE_CX: - case CMD_FCP_AUTO_TRSP_CX: - case CMD_ADAPTER_MSG: - case CMD_ADAPTER_DUMP: - case CMD_XMIT_SEQUENCE64_CR: - case CMD_XMIT_SEQUENCE64_CX: - case CMD_XMIT_BCAST64_CN: - case CMD_XMIT_BCAST64_CX: - case CMD_ELS_REQUEST64_CR: - case CMD_ELS_REQUEST64_CX: - case CMD_FCP_IWRITE64_CR: - case CMD_FCP_IWRITE64_CX: - case CMD_FCP_IREAD64_CR: - case CMD_FCP_IREAD64_CX: - case CMD_FCP_ICMND64_CR: - case CMD_FCP_ICMND64_CX: - case CMD_FCP_TSEND64_CX: - case CMD_FCP_TRSP64_CX: - case CMD_FCP_TRECEIVE64_CX: - case CMD_GEN_REQUEST64_CR: - case CMD_GEN_REQUEST64_CX: - case CMD_XMIT_ELS_RSP64_CX: - case DSSCMD_IWRITE64_CR: - case DSSCMD_IWRITE64_CX: - case DSSCMD_IREAD64_CR: - case DSSCMD_IREAD64_CX: - type = LPFC_SOL_IOCB; - break; - case CMD_ABORT_XRI_CN: - case CMD_ABORT_XRI_CX: - case CMD_CLOSE_XRI_CN: - case CMD_CLOSE_XRI_CX: - case CMD_XRI_ABORTED_CX: - case CMD_ABORT_MXRI64_CN: - case CMD_XMIT_BLS_RSP64_CX: - type = LPFC_ABORT_IOCB; - break; - case CMD_RCV_SEQUENCE_CX: - case CMD_RCV_ELS_REQ_CX: - case CMD_RCV_SEQUENCE64_CX: - case CMD_RCV_ELS_REQ64_CX: - case CMD_ASYNC_STATUS: - case CMD_IOCB_RCV_SEQ64_CX: - case CMD_IOCB_RCV_ELS64_CX: - case CMD_IOCB_RCV_CONT64_CX: - case CMD_IOCB_RET_XRI64_CX: - type = LPFC_UNSOL_IOCB; - break; - case CMD_IOCB_XMIT_MSEQ64_CR: - case CMD_IOCB_XMIT_MSEQ64_CX: - case CMD_IOCB_RCV_SEQ_LIST64_CX: - case CMD_IOCB_RCV_ELS_LIST64_CX: - case CMD_IOCB_CLOSE_EXTENDED_CN: - case CMD_IOCB_ABORT_EXTENDED_CN: - case CMD_IOCB_RET_HBQE64_CN: - case CMD_IOCB_FCP_IBIDIR64_CR: - case CMD_IOCB_FCP_IBIDIR64_CX: - case CMD_IOCB_FCP_ITASKMGT64_CX: - case CMD_IOCB_LOGENTRY_CN: - case CMD_IOCB_LOGENTRY_ASYNC_CN: - printk("%s - Unhandled SLI-3 Command x%x\n", - __func__, iocb_cmnd); - type = LPFC_UNKNOWN_IOCB; - break; - default: - type = LPFC_UNKNOWN_IOCB; - break; - } - - return type; -} - -/** - * lpfc_sli_ring_map - Issue config_ring mbox for all rings - * @phba: Pointer to HBA context object. - * - * This function is called from SLI initialization code - * to configure every ring of the HBA's SLI interface. The - * caller is not required to hold any lock. This function issues - * a config_ring mailbox command for each ring. - * This function returns zero if successful else returns a negative - * error code. - **/ -static int -lpfc_sli_ring_map(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - LPFC_MBOXQ_t *pmb; - MAILBOX_t *pmbox; - int i, rc, ret = 0; - - pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) - return -ENOMEM; - pmbox = &pmb->u.mb; - phba->link_state = LPFC_INIT_MBX_CMDS; - for (i = 0; i < psli->num_rings; i++) { - lpfc_config_ring(phba, i, pmb); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0446 Adapter failed to init (%d), " - "mbxCmd x%x CFG_RING, mbxStatus x%x, " - "ring %d\n", - rc, pmbox->mbxCommand, - pmbox->mbxStatus, i); - phba->link_state = LPFC_HBA_ERROR; - ret = -ENXIO; - break; - } - } - mempool_free(pmb, phba->mbox_mem_pool); - return ret; -} - -/** - * lpfc_sli_ringtxcmpl_put - Adds new iocb to the txcmplq - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @piocb: Pointer to the driver iocb object. - * - * This function is called with hbalock held. The function adds the - * new iocb to txcmplq of the given ring. This function always returns - * 0. If this function is called for ELS ring, this function checks if - * there is a vport associated with the ELS command. This function also - * starts els_tmofunc timer if this is an ELS command. - **/ -static int -lpfc_sli_ringtxcmpl_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocb) -{ - list_add_tail(&piocb->list, &pring->txcmplq); - piocb->iocb_flag |= LPFC_IO_ON_Q; - pring->txcmplq_cnt++; - if (pring->txcmplq_cnt > pring->txcmplq_max) - pring->txcmplq_max = pring->txcmplq_cnt; - - if ((unlikely(pring->ringno == LPFC_ELS_RING)) && - (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && - (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) { - if (!piocb->vport) - BUG(); - else - mod_timer(&piocb->vport->els_tmofunc, - jiffies + HZ * (phba->fc_ratov << 1)); - } - - - return 0; -} - -/** - * lpfc_sli_ringtx_get - Get first element of the txq - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function is called with hbalock held to get next - * iocb in txq of the given ring. If there is any iocb in - * the txq, the function returns first iocb in the list after - * removing the iocb from the list, else it returns NULL. - **/ -struct lpfc_iocbq * -lpfc_sli_ringtx_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - struct lpfc_iocbq *cmd_iocb; - - list_remove_head((&pring->txq), cmd_iocb, struct lpfc_iocbq, list); - if (cmd_iocb != NULL) - pring->txq_cnt--; - return cmd_iocb; -} - -/** - * lpfc_sli_next_iocb_slot - Get next iocb slot in the ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function is called with hbalock held and the caller must post the - * iocb without releasing the lock. If the caller releases the lock, - * iocb slot returned by the function is not guaranteed to be available. - * The function returns pointer to the next available iocb slot if there - * is available slot in the ring, else it returns NULL. - * If the get index of the ring is ahead of the put index, the function - * will post an error attention event to the worker thread to take the - * HBA to offline state. - **/ -static IOCB_t * -lpfc_sli_next_iocb_slot (struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; - uint32_t max_cmd_idx = pring->numCiocb; - if ((pring->next_cmdidx == pring->cmdidx) && - (++pring->next_cmdidx >= max_cmd_idx)) - pring->next_cmdidx = 0; - - if (unlikely(pring->local_getidx == pring->next_cmdidx)) { - - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); - - if (unlikely(pring->local_getidx >= max_cmd_idx)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0315 Ring %d issue: portCmdGet %d " - "is bigger than cmd ring %d\n", - pring->ringno, - pring->local_getidx, max_cmd_idx); - - phba->link_state = LPFC_HBA_ERROR; - /* - * All error attention handlers are posted to - * worker thread - */ - phba->work_ha |= HA_ERATT; - phba->work_hs = HS_FFER3; - - lpfc_worker_wake_up(phba); - - return NULL; - } - - if (pring->local_getidx == pring->next_cmdidx) - return NULL; - } - - return lpfc_cmd_iocb(phba, pring); -} - -/** - * lpfc_sli_next_iotag - Get an iotag for the iocb - * @phba: Pointer to HBA context object. - * @iocbq: Pointer to driver iocb object. - * - * This function gets an iotag for the iocb. If there is no unused iotag and - * the iocbq_lookup_len < 0xffff, this function allocates a bigger iotag_lookup - * array and assigns a new iotag. - * The function returns the allocated iotag if successful, else returns zero. - * Zero is not a valid iotag. - * The caller is not required to hold any lock. - **/ -uint16_t -lpfc_sli_next_iotag(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq) -{ - struct lpfc_iocbq **new_arr; - struct lpfc_iocbq **old_arr; - size_t new_len; - struct lpfc_sli *psli = &phba->sli; - uint16_t iotag; - - spin_lock_irq(&phba->hbalock); - iotag = psli->last_iotag; - if(++iotag < psli->iocbq_lookup_len) { - psli->last_iotag = iotag; - psli->iocbq_lookup[iotag] = iocbq; - spin_unlock_irq(&phba->hbalock); - iocbq->iotag = iotag; - return iotag; - } else if (psli->iocbq_lookup_len < (0xffff - - LPFC_IOCBQ_LOOKUP_INCREMENT)) { - new_len = psli->iocbq_lookup_len + LPFC_IOCBQ_LOOKUP_INCREMENT; - spin_unlock_irq(&phba->hbalock); - new_arr = kzalloc(new_len * sizeof (struct lpfc_iocbq *), - GFP_KERNEL); - if (new_arr) { - spin_lock_irq(&phba->hbalock); - old_arr = psli->iocbq_lookup; - if (new_len <= psli->iocbq_lookup_len) { - /* highly unprobable case */ - kfree(new_arr); - iotag = psli->last_iotag; - if(++iotag < psli->iocbq_lookup_len) { - psli->last_iotag = iotag; - psli->iocbq_lookup[iotag] = iocbq; - spin_unlock_irq(&phba->hbalock); - iocbq->iotag = iotag; - return iotag; - } - spin_unlock_irq(&phba->hbalock); - return 0; - } - if (psli->iocbq_lookup) - memcpy(new_arr, old_arr, - ((psli->last_iotag + 1) * - sizeof (struct lpfc_iocbq *))); - psli->iocbq_lookup = new_arr; - psli->iocbq_lookup_len = new_len; - psli->last_iotag = iotag; - psli->iocbq_lookup[iotag] = iocbq; - spin_unlock_irq(&phba->hbalock); - iocbq->iotag = iotag; - kfree(old_arr); - return iotag; - } - } else - spin_unlock_irq(&phba->hbalock); - - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0318 Failed to allocate IOTAG.last IOTAG is %d\n", - psli->last_iotag); - - return 0; -} - -/** - * lpfc_sli_submit_iocb - Submit an iocb to the firmware - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @iocb: Pointer to iocb slot in the ring. - * @nextiocb: Pointer to driver iocb object which need to be - * posted to firmware. - * - * This function is called with hbalock held to post a new iocb to - * the firmware. This function copies the new iocb to ring iocb slot and - * updates the ring pointers. It adds the new iocb to txcmplq if there is - * a completion call back for this iocb else the function will free the - * iocb object. - **/ -static void -lpfc_sli_submit_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - IOCB_t *iocb, struct lpfc_iocbq *nextiocb) -{ - /* - * Set up an iotag - */ - nextiocb->iocb.ulpIoTag = (nextiocb->iocb_cmpl) ? nextiocb->iotag : 0; - - - if (pring->ringno == LPFC_ELS_RING) { - lpfc_debugfs_slow_ring_trc(phba, - "IOCB cmd ring: wd4:x%08x wd6:x%08x wd7:x%08x", - *(((uint32_t *) &nextiocb->iocb) + 4), - *(((uint32_t *) &nextiocb->iocb) + 6), - *(((uint32_t *) &nextiocb->iocb) + 7)); - } - - /* - * Issue iocb command to adapter - */ - lpfc_sli_pcimem_bcopy(&nextiocb->iocb, iocb, phba->iocb_cmd_size); - wmb(); - pring->stats.iocb_cmd++; - - /* - * If there is no completion routine to call, we can release the - * IOCB buffer back right now. For IOCBs, like QUE_RING_BUF, - * that have no rsp ring completion, iocb_cmpl MUST be NULL. - */ - if (nextiocb->iocb_cmpl) - lpfc_sli_ringtxcmpl_put(phba, pring, nextiocb); - else - __lpfc_sli_release_iocbq(phba, nextiocb); - - /* - * Let the HBA know what IOCB slot will be the next one the - * driver will put a command into. - */ - pring->cmdidx = pring->next_cmdidx; - writel(pring->cmdidx, &phba->host_gp[pring->ringno].cmdPutInx); -} - -/** - * lpfc_sli_update_full_ring - Update the chip attention register - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * The caller is not required to hold any lock for calling this function. - * This function updates the chip attention bits for the ring to inform firmware - * that there are pending work to be done for this ring and requests an - * interrupt when there is space available in the ring. This function is - * called when the driver is unable to post more iocbs to the ring due - * to unavailability of space in the ring. - **/ -static void -lpfc_sli_update_full_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - int ringno = pring->ringno; - - pring->flag |= LPFC_CALL_RING_AVAILABLE; - - wmb(); - - /* - * Set ring 'ringno' to SET R0CE_REQ in Chip Att register. - * The HBA will tell us when an IOCB entry is available. - */ - writel((CA_R0ATT|CA_R0CE_REQ) << (ringno*4), phba->CAregaddr); - readl(phba->CAregaddr); /* flush */ - - pring->stats.iocb_cmd_full++; -} - -/** - * lpfc_sli_update_ring - Update chip attention register - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function updates the chip attention register bit for the - * given ring to inform HBA that there is more work to be done - * in this ring. The caller is not required to hold any lock. - **/ -static void -lpfc_sli_update_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - int ringno = pring->ringno; - - /* - * Tell the HBA that there is work to do in this ring. - */ - if (!(phba->sli3_options & LPFC_SLI3_CRP_ENABLED)) { - wmb(); - writel(CA_R0ATT << (ringno * 4), phba->CAregaddr); - readl(phba->CAregaddr); /* flush */ - } -} - -/** - * lpfc_sli_resume_iocb - Process iocbs in the txq - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function is called with hbalock held to post pending iocbs - * in the txq to the firmware. This function is called when driver - * detects space available in the ring. - **/ -static void -lpfc_sli_resume_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - IOCB_t *iocb; - struct lpfc_iocbq *nextiocb; - - /* - * Check to see if: - * (a) there is anything on the txq to send - * (b) link is up - * (c) link attention events can be processed (fcp ring only) - * (d) IOCB processing is not blocked by the outstanding mbox command. - */ - if (pring->txq_cnt && - lpfc_is_link_up(phba) && - (pring->ringno != phba->sli.fcp_ring || - phba->sli.sli_flag & LPFC_PROCESS_LA)) { - - while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) && - (nextiocb = lpfc_sli_ringtx_get(phba, pring))) - lpfc_sli_submit_iocb(phba, pring, iocb, nextiocb); - - if (iocb) - lpfc_sli_update_ring(phba, pring); - else - lpfc_sli_update_full_ring(phba, pring); - } - - return; -} - -/** - * lpfc_sli_next_hbq_slot - Get next hbq entry for the HBQ - * @phba: Pointer to HBA context object. - * @hbqno: HBQ number. - * - * This function is called with hbalock held to get the next - * available slot for the given HBQ. If there is free slot - * available for the HBQ it will return pointer to the next available - * HBQ entry else it will return NULL. - **/ -static struct lpfc_hbq_entry * -lpfc_sli_next_hbq_slot(struct lpfc_hba *phba, uint32_t hbqno) -{ - struct hbq_s *hbqp = &phba->hbqs[hbqno]; - - if (hbqp->next_hbqPutIdx == hbqp->hbqPutIdx && - ++hbqp->next_hbqPutIdx >= hbqp->entry_count) - hbqp->next_hbqPutIdx = 0; - - if (unlikely(hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx)) { - uint32_t raw_index = phba->hbq_get[hbqno]; - uint32_t getidx = le32_to_cpu(raw_index); - - hbqp->local_hbqGetIdx = getidx; - - if (unlikely(hbqp->local_hbqGetIdx >= hbqp->entry_count)) { - lpfc_printf_log(phba, KERN_ERR, - LOG_SLI | LOG_VPORT, - "1802 HBQ %d: local_hbqGetIdx " - "%u is > than hbqp->entry_count %u\n", - hbqno, hbqp->local_hbqGetIdx, - hbqp->entry_count); - - phba->link_state = LPFC_HBA_ERROR; - return NULL; - } - - if (hbqp->local_hbqGetIdx == hbqp->next_hbqPutIdx) - return NULL; - } - - return (struct lpfc_hbq_entry *) phba->hbqs[hbqno].hbq_virt + - hbqp->hbqPutIdx; -} - -/** - * lpfc_sli_hbqbuf_free_all - Free all the hbq buffers - * @phba: Pointer to HBA context object. - * - * This function is called with no lock held to free all the - * hbq buffers while uninitializing the SLI interface. It also - * frees the HBQ buffers returned by the firmware but not yet - * processed by the upper layers. - **/ -void -lpfc_sli_hbqbuf_free_all(struct lpfc_hba *phba) -{ - struct lpfc_dmabuf *dmabuf, *next_dmabuf; - struct hbq_dmabuf *hbq_buf; - unsigned long flags; - int i, hbq_count; - uint32_t hbqno; - - hbq_count = lpfc_sli_hbq_count(); - /* Return all memory used by all HBQs */ - spin_lock_irqsave(&phba->hbalock, flags); - for (i = 0; i < hbq_count; ++i) { - list_for_each_entry_safe(dmabuf, next_dmabuf, - &phba->hbqs[i].hbq_buffer_list, list) { - hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf); - list_del(&hbq_buf->dbuf.list); - (phba->hbqs[i].hbq_free_buffer)(phba, hbq_buf); - } - phba->hbqs[i].buffer_count = 0; - } - /* Return all HBQ buffer that are in-fly */ - list_for_each_entry_safe(dmabuf, next_dmabuf, &phba->rb_pend_list, - list) { - hbq_buf = container_of(dmabuf, struct hbq_dmabuf, dbuf); - list_del(&hbq_buf->dbuf.list); - if (hbq_buf->tag == -1) { - (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) - (phba, hbq_buf); - } else { - hbqno = hbq_buf->tag >> 16; - if (hbqno >= LPFC_MAX_HBQS) - (phba->hbqs[LPFC_ELS_HBQ].hbq_free_buffer) - (phba, hbq_buf); - else - (phba->hbqs[hbqno].hbq_free_buffer)(phba, - hbq_buf); - } - } - - /* Mark the HBQs not in use */ - phba->hbq_in_use = 0; - spin_unlock_irqrestore(&phba->hbalock, flags); -} - -/** - * lpfc_sli_hbq_to_firmware - Post the hbq buffer to firmware - * @phba: Pointer to HBA context object. - * @hbqno: HBQ number. - * @hbq_buf: Pointer to HBQ buffer. - * - * This function is called with the hbalock held to post a - * hbq buffer to the firmware. If the function finds an empty - * slot in the HBQ, it will post the buffer. The function will return - * pointer to the hbq entry if it successfully post the buffer - * else it will return NULL. - **/ -static int -lpfc_sli_hbq_to_firmware(struct lpfc_hba *phba, uint32_t hbqno, - struct hbq_dmabuf *hbq_buf) -{ - return phba->lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buf); -} - -/** - * lpfc_sli_hbq_to_firmware_s3 - Post the hbq buffer to SLI3 firmware - * @phba: Pointer to HBA context object. - * @hbqno: HBQ number. - * @hbq_buf: Pointer to HBQ buffer. - * - * This function is called with the hbalock held to post a hbq buffer to the - * firmware. If the function finds an empty slot in the HBQ, it will post the - * buffer and place it on the hbq_buffer_list. The function will return zero if - * it successfully post the buffer else it will return an error. - **/ -static int -lpfc_sli_hbq_to_firmware_s3(struct lpfc_hba *phba, uint32_t hbqno, - struct hbq_dmabuf *hbq_buf) -{ - struct lpfc_hbq_entry *hbqe; - dma_addr_t physaddr = hbq_buf->dbuf.phys; - - /* Get next HBQ entry slot to use */ - hbqe = lpfc_sli_next_hbq_slot(phba, hbqno); - if (hbqe) { - struct hbq_s *hbqp = &phba->hbqs[hbqno]; - - hbqe->bde.addrHigh = le32_to_cpu(putPaddrHigh(physaddr)); - hbqe->bde.addrLow = le32_to_cpu(putPaddrLow(physaddr)); - hbqe->bde.tus.f.bdeSize = hbq_buf->size; - hbqe->bde.tus.f.bdeFlags = 0; - hbqe->bde.tus.w = le32_to_cpu(hbqe->bde.tus.w); - hbqe->buffer_tag = le32_to_cpu(hbq_buf->tag); - /* Sync SLIM */ - hbqp->hbqPutIdx = hbqp->next_hbqPutIdx; - writel(hbqp->hbqPutIdx, phba->hbq_put + hbqno); - /* flush */ - readl(phba->hbq_put + hbqno); - list_add_tail(&hbq_buf->dbuf.list, &hbqp->hbq_buffer_list); - return 0; - } else - return -ENOMEM; -} - -/** - * lpfc_sli_hbq_to_firmware_s4 - Post the hbq buffer to SLI4 firmware - * @phba: Pointer to HBA context object. - * @hbqno: HBQ number. - * @hbq_buf: Pointer to HBQ buffer. - * - * This function is called with the hbalock held to post an RQE to the SLI4 - * firmware. If able to post the RQE to the RQ it will queue the hbq entry to - * the hbq_buffer_list and return zero, otherwise it will return an error. - **/ -static int -lpfc_sli_hbq_to_firmware_s4(struct lpfc_hba *phba, uint32_t hbqno, - struct hbq_dmabuf *hbq_buf) -{ - int rc; - struct lpfc_rqe hrqe; - struct lpfc_rqe drqe; - - hrqe.address_lo = putPaddrLow(hbq_buf->hbuf.phys); - hrqe.address_hi = putPaddrHigh(hbq_buf->hbuf.phys); - drqe.address_lo = putPaddrLow(hbq_buf->dbuf.phys); - drqe.address_hi = putPaddrHigh(hbq_buf->dbuf.phys); - rc = lpfc_sli4_rq_put(phba->sli4_hba.hdr_rq, phba->sli4_hba.dat_rq, - &hrqe, &drqe); - if (rc < 0) - return rc; - hbq_buf->tag = rc; - list_add_tail(&hbq_buf->dbuf.list, &phba->hbqs[hbqno].hbq_buffer_list); - return 0; -} - -/* HBQ for ELS and CT traffic. */ -static struct lpfc_hbq_init lpfc_els_hbq = { - .rn = 1, - .entry_count = 256, - .mask_count = 0, - .profile = 0, - .ring_mask = (1 << LPFC_ELS_RING), - .buffer_count = 0, - .init_count = 40, - .add_count = 40, -}; - -/* HBQ for the extra ring if needed */ -static struct lpfc_hbq_init lpfc_extra_hbq = { - .rn = 1, - .entry_count = 200, - .mask_count = 0, - .profile = 0, - .ring_mask = (1 << LPFC_EXTRA_RING), - .buffer_count = 0, - .init_count = 0, - .add_count = 5, -}; - -/* Array of HBQs */ -struct lpfc_hbq_init *lpfc_hbq_defs[] = { - &lpfc_els_hbq, - &lpfc_extra_hbq, -}; - -/** - * lpfc_sli_hbqbuf_fill_hbqs - Post more hbq buffers to HBQ - * @phba: Pointer to HBA context object. - * @hbqno: HBQ number. - * @count: Number of HBQ buffers to be posted. - * - * This function is called with no lock held to post more hbq buffers to the - * given HBQ. The function returns the number of HBQ buffers successfully - * posted. - **/ -static int -lpfc_sli_hbqbuf_fill_hbqs(struct lpfc_hba *phba, uint32_t hbqno, uint32_t count) -{ - uint32_t i, posted = 0; - unsigned long flags; - struct hbq_dmabuf *hbq_buffer; - LIST_HEAD(hbq_buf_list); - if (!phba->hbqs[hbqno].hbq_alloc_buffer) - return 0; - - if ((phba->hbqs[hbqno].buffer_count + count) > - lpfc_hbq_defs[hbqno]->entry_count) - count = lpfc_hbq_defs[hbqno]->entry_count - - phba->hbqs[hbqno].buffer_count; - if (!count) - return 0; - /* Allocate HBQ entries */ - for (i = 0; i < count; i++) { - hbq_buffer = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba); - if (!hbq_buffer) - break; - list_add_tail(&hbq_buffer->dbuf.list, &hbq_buf_list); - } - /* Check whether HBQ is still in use */ - spin_lock_irqsave(&phba->hbalock, flags); - if (!phba->hbq_in_use) - goto err; - while (!list_empty(&hbq_buf_list)) { - list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf, - dbuf.list); - hbq_buffer->tag = (phba->hbqs[hbqno].buffer_count | - (hbqno << 16)); - if (!lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) { - phba->hbqs[hbqno].buffer_count++; - posted++; - } else - (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); - } - spin_unlock_irqrestore(&phba->hbalock, flags); - return posted; -err: - spin_unlock_irqrestore(&phba->hbalock, flags); - while (!list_empty(&hbq_buf_list)) { - list_remove_head(&hbq_buf_list, hbq_buffer, struct hbq_dmabuf, - dbuf.list); - (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); - } - return 0; -} - -/** - * lpfc_sli_hbqbuf_add_hbqs - Post more HBQ buffers to firmware - * @phba: Pointer to HBA context object. - * @qno: HBQ number. - * - * This function posts more buffers to the HBQ. This function - * is called with no lock held. The function returns the number of HBQ entries - * successfully allocated. - **/ -int -lpfc_sli_hbqbuf_add_hbqs(struct lpfc_hba *phba, uint32_t qno) -{ - if (phba->sli_rev == LPFC_SLI_REV4) - return 0; - else - return lpfc_sli_hbqbuf_fill_hbqs(phba, qno, - lpfc_hbq_defs[qno]->add_count); -} - -/** - * lpfc_sli_hbqbuf_init_hbqs - Post initial buffers to the HBQ - * @phba: Pointer to HBA context object. - * @qno: HBQ queue number. - * - * This function is called from SLI initialization code path with - * no lock held to post initial HBQ buffers to firmware. The - * function returns the number of HBQ entries successfully allocated. - **/ -static int -lpfc_sli_hbqbuf_init_hbqs(struct lpfc_hba *phba, uint32_t qno) -{ - if (phba->sli_rev == LPFC_SLI_REV4) - return lpfc_sli_hbqbuf_fill_hbqs(phba, qno, - lpfc_hbq_defs[qno]->entry_count); - else - return lpfc_sli_hbqbuf_fill_hbqs(phba, qno, - lpfc_hbq_defs[qno]->init_count); -} - -/** - * lpfc_sli_hbqbuf_get - Remove the first hbq off of an hbq list - * @phba: Pointer to HBA context object. - * @hbqno: HBQ number. - * - * This function removes the first hbq buffer on an hbq list and returns a - * pointer to that buffer. If it finds no buffers on the list it returns NULL. - **/ -static struct hbq_dmabuf * -lpfc_sli_hbqbuf_get(struct list_head *rb_list) -{ - struct lpfc_dmabuf *d_buf; - - list_remove_head(rb_list, d_buf, struct lpfc_dmabuf, list); - if (!d_buf) - return NULL; - return container_of(d_buf, struct hbq_dmabuf, dbuf); -} - -/** - * lpfc_sli_hbqbuf_find - Find the hbq buffer associated with a tag - * @phba: Pointer to HBA context object. - * @tag: Tag of the hbq buffer. - * - * This function is called with hbalock held. This function searches - * for the hbq buffer associated with the given tag in the hbq buffer - * list. If it finds the hbq buffer, it returns the hbq_buffer other wise - * it returns NULL. - **/ -static struct hbq_dmabuf * -lpfc_sli_hbqbuf_find(struct lpfc_hba *phba, uint32_t tag) -{ - struct lpfc_dmabuf *d_buf; - struct hbq_dmabuf *hbq_buf; - uint32_t hbqno; - - hbqno = tag >> 16; - if (hbqno >= LPFC_MAX_HBQS) - return NULL; - - spin_lock_irq(&phba->hbalock); - list_for_each_entry(d_buf, &phba->hbqs[hbqno].hbq_buffer_list, list) { - hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); - if (hbq_buf->tag == tag) { - spin_unlock_irq(&phba->hbalock); - return hbq_buf; - } - } - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_VPORT, - "1803 Bad hbq tag. Data: x%x x%x\n", - tag, phba->hbqs[tag >> 16].buffer_count); - return NULL; -} - -/** - * lpfc_sli_free_hbq - Give back the hbq buffer to firmware - * @phba: Pointer to HBA context object. - * @hbq_buffer: Pointer to HBQ buffer. - * - * This function is called with hbalock. This function gives back - * the hbq buffer to firmware. If the HBQ does not have space to - * post the buffer, it will free the buffer. - **/ -void -lpfc_sli_free_hbq(struct lpfc_hba *phba, struct hbq_dmabuf *hbq_buffer) -{ - uint32_t hbqno; - - if (hbq_buffer) { - hbqno = hbq_buffer->tag >> 16; - if (lpfc_sli_hbq_to_firmware(phba, hbqno, hbq_buffer)) - (phba->hbqs[hbqno].hbq_free_buffer)(phba, hbq_buffer); - } -} - -/** - * lpfc_sli_chk_mbx_command - Check if the mailbox is a legitimate mailbox - * @mbxCommand: mailbox command code. - * - * This function is called by the mailbox event handler function to verify - * that the completed mailbox command is a legitimate mailbox command. If the - * completed mailbox is not known to the function, it will return MBX_SHUTDOWN - * and the mailbox event handler will take the HBA offline. - **/ -static int -lpfc_sli_chk_mbx_command(uint8_t mbxCommand) -{ - uint8_t ret; - - switch (mbxCommand) { - case MBX_LOAD_SM: - case MBX_READ_NV: - case MBX_WRITE_NV: - case MBX_WRITE_VPARMS: - case MBX_RUN_BIU_DIAG: - case MBX_INIT_LINK: - case MBX_DOWN_LINK: - case MBX_CONFIG_LINK: - case MBX_CONFIG_RING: - case MBX_RESET_RING: - case MBX_READ_CONFIG: - case MBX_READ_RCONFIG: - case MBX_READ_SPARM: - case MBX_READ_STATUS: - case MBX_READ_RPI: - case MBX_READ_XRI: - case MBX_READ_REV: - case MBX_READ_LNK_STAT: - case MBX_REG_LOGIN: - case MBX_UNREG_LOGIN: - case MBX_CLEAR_LA: - case MBX_DUMP_MEMORY: - case MBX_DUMP_CONTEXT: - case MBX_RUN_DIAGS: - case MBX_RESTART: - case MBX_UPDATE_CFG: - case MBX_DOWN_LOAD: - case MBX_DEL_LD_ENTRY: - case MBX_RUN_PROGRAM: - case MBX_SET_MASK: - case MBX_SET_VARIABLE: - case MBX_UNREG_D_ID: - case MBX_KILL_BOARD: - case MBX_CONFIG_FARP: - case MBX_BEACON: - case MBX_LOAD_AREA: - case MBX_RUN_BIU_DIAG64: - case MBX_CONFIG_PORT: - case MBX_READ_SPARM64: - case MBX_READ_RPI64: - case MBX_REG_LOGIN64: - case MBX_READ_TOPOLOGY: - case MBX_WRITE_WWN: - case MBX_SET_DEBUG: - case MBX_LOAD_EXP_ROM: - case MBX_ASYNCEVT_ENABLE: - case MBX_REG_VPI: - case MBX_UNREG_VPI: - case MBX_HEARTBEAT: - case MBX_PORT_CAPABILITIES: - case MBX_PORT_IOV_CONTROL: - case MBX_SLI4_CONFIG: - case MBX_SLI4_REQ_FTRS: - case MBX_REG_FCFI: - case MBX_UNREG_FCFI: - case MBX_REG_VFI: - case MBX_UNREG_VFI: - case MBX_INIT_VPI: - case MBX_INIT_VFI: - case MBX_RESUME_RPI: - case MBX_READ_EVENT_LOG_STATUS: - case MBX_READ_EVENT_LOG: - case MBX_SECURITY_MGMT: - case MBX_AUTH_PORT: - ret = mbxCommand; - break; - default: - ret = MBX_SHUTDOWN; - break; - } - return ret; -} - -/** - * lpfc_sli_wake_mbox_wait - lpfc_sli_issue_mbox_wait mbox completion handler - * @phba: Pointer to HBA context object. - * @pmboxq: Pointer to mailbox command. - * - * This is completion handler function for mailbox commands issued from - * lpfc_sli_issue_mbox_wait function. This function is called by the - * mailbox event handler function with no lock held. This function - * will wake up thread waiting on the wait queue pointed by context1 - * of the mailbox. - **/ -void -lpfc_sli_wake_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq) -{ - wait_queue_head_t *pdone_q; - unsigned long drvr_flag; - - /* - * If pdone_q is empty, the driver thread gave up waiting and - * continued running. - */ - pmboxq->mbox_flag |= LPFC_MBX_WAKE; - spin_lock_irqsave(&phba->hbalock, drvr_flag); - pdone_q = (wait_queue_head_t *) pmboxq->context1; - if (pdone_q) - wake_up_interruptible(pdone_q); - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - return; -} - - -/** - * lpfc_sli_def_mbox_cmpl - Default mailbox completion handler - * @phba: Pointer to HBA context object. - * @pmb: Pointer to mailbox object. - * - * This function is the default mailbox completion handler. It - * frees the memory resources associated with the completed mailbox - * command. If the completed command is a REG_LOGIN mailbox command, - * this function will issue a UREG_LOGIN to re-claim the RPI. - **/ -void -lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) -{ - struct lpfc_vport *vport = pmb->vport; - struct lpfc_dmabuf *mp; - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost; - uint16_t rpi, vpi; - int rc; - - mp = (struct lpfc_dmabuf *) (pmb->context1); - - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - - /* - * If a REG_LOGIN succeeded after node is destroyed or node - * is in re-discovery driver need to cleanup the RPI. - */ - if (!(phba->pport->load_flag & FC_UNLOADING) && - pmb->u.mb.mbxCommand == MBX_REG_LOGIN64 && - !pmb->u.mb.mbxStatus) { - rpi = pmb->u.mb.un.varWords[0]; - vpi = pmb->u.mb.un.varRegLogin.vpi; - lpfc_unreg_login(phba, vpi, rpi, pmb); - pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc != MBX_NOT_FINISHED) - return; - } - - if ((pmb->u.mb.mbxCommand == MBX_REG_VPI) && - !(phba->pport->load_flag & FC_UNLOADING) && - !pmb->u.mb.mbxStatus) { - shost = lpfc_shost_from_vport(vport); - spin_lock_irq(shost->host_lock); - vport->vpi_state |= LPFC_VPI_REGISTERED; - vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - } - - if (pmb->u.mb.mbxCommand == MBX_REG_LOGIN64) { - ndlp = (struct lpfc_nodelist *)pmb->context2; - lpfc_nlp_put(ndlp); - pmb->context2 = NULL; - } - - /* Check security permission status on INIT_LINK mailbox command */ - if ((pmb->u.mb.mbxCommand == MBX_INIT_LINK) && - (pmb->u.mb.mbxStatus == MBXERR_SEC_NO_PERMISSION)) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2860 SLI authentication is required " - "for INIT_LINK but has not done yet\n"); - - if (bf_get(lpfc_mqe_command, &pmb->u.mqe) == MBX_SLI4_CONFIG) - lpfc_sli4_mbox_cmd_free(phba, pmb); - else - mempool_free(pmb, phba->mbox_mem_pool); -} - -/** - * lpfc_sli_handle_mb_event - Handle mailbox completions from firmware - * @phba: Pointer to HBA context object. - * - * This function is called with no lock held. This function processes all - * the completed mailbox commands and gives it to upper layers. The interrupt - * service routine processes mailbox completion interrupt and adds completed - * mailbox commands to the mboxq_cmpl queue and signals the worker thread. - * Worker thread call lpfc_sli_handle_mb_event, which will return the - * completed mailbox commands in mboxq_cmpl queue to the upper layers. This - * function returns the mailbox commands to the upper layer by calling the - * completion handler function of each mailbox. - **/ -int -lpfc_sli_handle_mb_event(struct lpfc_hba *phba) -{ - MAILBOX_t *pmbox; - LPFC_MBOXQ_t *pmb; - int rc; - LIST_HEAD(cmplq); - - phba->sli.slistat.mbox_event++; - - /* Get all completed mailboxe buffers into the cmplq */ - spin_lock_irq(&phba->hbalock); - list_splice_init(&phba->sli.mboxq_cmpl, &cmplq); - spin_unlock_irq(&phba->hbalock); - - /* Get a Mailbox buffer to setup mailbox commands for callback */ - do { - list_remove_head(&cmplq, pmb, LPFC_MBOXQ_t, list); - if (pmb == NULL) - break; - - pmbox = &pmb->u.mb; - - if (pmbox->mbxCommand != MBX_HEARTBEAT) { - if (pmb->vport) { - lpfc_debugfs_disc_trc(pmb->vport, - LPFC_DISC_TRC_MBOX_VPORT, - "MBOX cmpl vport: cmd:x%x mb:x%x x%x", - (uint32_t)pmbox->mbxCommand, - pmbox->un.varWords[0], - pmbox->un.varWords[1]); - } - else { - lpfc_debugfs_disc_trc(phba->pport, - LPFC_DISC_TRC_MBOX, - "MBOX cmpl: cmd:x%x mb:x%x x%x", - (uint32_t)pmbox->mbxCommand, - pmbox->un.varWords[0], - pmbox->un.varWords[1]); - } - } - - /* - * It is a fatal error if unknown mbox command completion. - */ - if (lpfc_sli_chk_mbx_command(pmbox->mbxCommand) == - MBX_SHUTDOWN) { - /* Unknown mailbox command compl */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):0323 Unknown Mailbox command " - "x%x (x%x/x%x) Cmpl\n", - pmb->vport ? pmb->vport->vpi : 0, - pmbox->mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, - pmb), - lpfc_sli_config_mbox_opcode_get(phba, - pmb)); - phba->link_state = LPFC_HBA_ERROR; - phba->work_hs = HS_FFER3; - lpfc_handle_eratt(phba); - continue; - } - - if (pmbox->mbxStatus) { - phba->sli.slistat.mbox_stat_err++; - if (pmbox->mbxStatus == MBXERR_NO_RESOURCES) { - /* Mbox cmd cmpl error - RETRYing */ - lpfc_printf_log(phba, KERN_INFO, - LOG_MBOX | LOG_SLI, - "(%d):0305 Mbox cmd cmpl " - "error - RETRYing Data: x%x " - "(x%x/x%x) x%x x%x x%x\n", - pmb->vport ? pmb->vport->vpi : 0, - pmbox->mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, - pmb), - lpfc_sli_config_mbox_opcode_get(phba, - pmb), - pmbox->mbxStatus, - pmbox->un.varWords[0], - pmb->vport->port_state); - pmbox->mbxStatus = 0; - pmbox->mbxOwner = OWN_HOST; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc != MBX_NOT_FINISHED) - continue; - } - } - - /* Mailbox cmd Cmpl */ - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0307 Mailbox cmd x%x (x%x/x%x) Cmpl x%p " - "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x\n", - pmb->vport ? pmb->vport->vpi : 0, - pmbox->mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, pmb), - lpfc_sli_config_mbox_opcode_get(phba, pmb), - pmb->mbox_cmpl, - *((uint32_t *) pmbox), - pmbox->un.varWords[0], - pmbox->un.varWords[1], - pmbox->un.varWords[2], - pmbox->un.varWords[3], - pmbox->un.varWords[4], - pmbox->un.varWords[5], - pmbox->un.varWords[6], - pmbox->un.varWords[7]); - - if (pmb->mbox_cmpl) - pmb->mbox_cmpl(phba,pmb); - } while (1); - return 0; -} - -/** - * lpfc_sli_get_buff - Get the buffer associated with the buffer tag - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @tag: buffer tag. - * - * This function is called with no lock held. When QUE_BUFTAG_BIT bit - * is set in the tag the buffer is posted for a particular exchange, - * the function will return the buffer without replacing the buffer. - * If the buffer is for unsolicited ELS or CT traffic, this function - * returns the buffer and also posts another buffer to the firmware. - **/ -static struct lpfc_dmabuf * -lpfc_sli_get_buff(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, - uint32_t tag) -{ - struct hbq_dmabuf *hbq_entry; - - if (tag & QUE_BUFTAG_BIT) - return lpfc_sli_ring_taggedbuf_get(phba, pring, tag); - hbq_entry = lpfc_sli_hbqbuf_find(phba, tag); - if (!hbq_entry) - return NULL; - return &hbq_entry->dbuf; -} - -/** - * lpfc_complete_unsol_iocb - Complete an unsolicited sequence - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @saveq: Pointer to the iocbq struct representing the sequence starting frame. - * @fch_r_ctl: the r_ctl for the first frame of the sequence. - * @fch_type: the type for the first frame of the sequence. - * - * This function is called with no lock held. This function uses the r_ctl and - * type of the received sequence to find the correct callback function to call - * to process the sequence. - **/ -static int -lpfc_complete_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *saveq, uint32_t fch_r_ctl, - uint32_t fch_type) -{ - int i; - - /* unSolicited Responses */ - if (pring->prt[0].profile) { - if (pring->prt[0].lpfc_sli_rcv_unsol_event) - (pring->prt[0].lpfc_sli_rcv_unsol_event) (phba, pring, - saveq); - return 1; - } - /* We must search, based on rctl / type - for the right routine */ - for (i = 0; i < pring->num_mask; i++) { - if ((pring->prt[i].rctl == fch_r_ctl) && - (pring->prt[i].type == fch_type)) { - if (pring->prt[i].lpfc_sli_rcv_unsol_event) - (pring->prt[i].lpfc_sli_rcv_unsol_event) - (phba, pring, saveq); - return 1; - } - } - return 0; -} - -/** - * lpfc_sli_process_unsol_iocb - Unsolicited iocb handler - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @saveq: Pointer to the unsolicited iocb. - * - * This function is called with no lock held by the ring event handler - * when there is an unsolicited iocb posted to the response ring by the - * firmware. This function gets the buffer associated with the iocbs - * and calls the event handler for the ring. This function handles both - * qring buffers and hbq buffers. - * When the function returns 1 the caller can free the iocb object otherwise - * upper layer functions will free the iocb objects. - **/ -static int -lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *saveq) -{ - IOCB_t * irsp; - WORD5 * w5p; - uint32_t Rctl, Type; - uint32_t match; - struct lpfc_iocbq *iocbq; - struct lpfc_dmabuf *dmzbuf; - - match = 0; - irsp = &(saveq->iocb); - - if (irsp->ulpCommand == CMD_ASYNC_STATUS) { - if (pring->lpfc_sli_rcv_async_status) - pring->lpfc_sli_rcv_async_status(phba, pring, saveq); - else - lpfc_printf_log(phba, - KERN_WARNING, - LOG_SLI, - "0316 Ring %d handler: unexpected " - "ASYNC_STATUS iocb received evt_code " - "0x%x\n", - pring->ringno, - irsp->un.asyncstat.evt_code); - return 1; - } - - if ((irsp->ulpCommand == CMD_IOCB_RET_XRI64_CX) && - (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED)) { - if (irsp->ulpBdeCount > 0) { - dmzbuf = lpfc_sli_get_buff(phba, pring, - irsp->un.ulpWord[3]); - lpfc_in_buf_free(phba, dmzbuf); - } - - if (irsp->ulpBdeCount > 1) { - dmzbuf = lpfc_sli_get_buff(phba, pring, - irsp->unsli3.sli3Words[3]); - lpfc_in_buf_free(phba, dmzbuf); - } - - if (irsp->ulpBdeCount > 2) { - dmzbuf = lpfc_sli_get_buff(phba, pring, - irsp->unsli3.sli3Words[7]); - lpfc_in_buf_free(phba, dmzbuf); - } - - return 1; - } - - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - if (irsp->ulpBdeCount != 0) { - saveq->context2 = lpfc_sli_get_buff(phba, pring, - irsp->un.ulpWord[3]); - if (!saveq->context2) - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, - "0341 Ring %d Cannot find buffer for " - "an unsolicited iocb. tag 0x%x\n", - pring->ringno, - irsp->un.ulpWord[3]); - } - if (irsp->ulpBdeCount == 2) { - saveq->context3 = lpfc_sli_get_buff(phba, pring, - irsp->unsli3.sli3Words[7]); - if (!saveq->context3) - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, - "0342 Ring %d Cannot find buffer for an" - " unsolicited iocb. tag 0x%x\n", - pring->ringno, - irsp->unsli3.sli3Words[7]); - } - list_for_each_entry(iocbq, &saveq->list, list) { - irsp = &(iocbq->iocb); - if (irsp->ulpBdeCount != 0) { - iocbq->context2 = lpfc_sli_get_buff(phba, pring, - irsp->un.ulpWord[3]); - if (!iocbq->context2) - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, - "0343 Ring %d Cannot find " - "buffer for an unsolicited iocb" - ". tag 0x%x\n", pring->ringno, - irsp->un.ulpWord[3]); - } - if (irsp->ulpBdeCount == 2) { - iocbq->context3 = lpfc_sli_get_buff(phba, pring, - irsp->unsli3.sli3Words[7]); - if (!iocbq->context3) - lpfc_printf_log(phba, - KERN_ERR, - LOG_SLI, - "0344 Ring %d Cannot find " - "buffer for an unsolicited " - "iocb. tag 0x%x\n", - pring->ringno, - irsp->unsli3.sli3Words[7]); - } - } - } - if (irsp->ulpBdeCount != 0 && - (irsp->ulpCommand == CMD_IOCB_RCV_CONT64_CX || - irsp->ulpStatus == IOSTAT_INTERMED_RSP)) { - int found = 0; - - /* search continue save q for same XRI */ - list_for_each_entry(iocbq, &pring->iocb_continue_saveq, clist) { - if (iocbq->iocb.unsli3.rcvsli3.ox_id == - saveq->iocb.unsli3.rcvsli3.ox_id) { - list_add_tail(&saveq->list, &iocbq->list); - found = 1; - break; - } - } - if (!found) - list_add_tail(&saveq->clist, - &pring->iocb_continue_saveq); - if (saveq->iocb.ulpStatus != IOSTAT_INTERMED_RSP) { - list_del_init(&iocbq->clist); - saveq = iocbq; - irsp = &(saveq->iocb); - } else - return 0; - } - if ((irsp->ulpCommand == CMD_RCV_ELS_REQ64_CX) || - (irsp->ulpCommand == CMD_RCV_ELS_REQ_CX) || - (irsp->ulpCommand == CMD_IOCB_RCV_ELS64_CX)) { - Rctl = FC_RCTL_ELS_REQ; - Type = FC_TYPE_ELS; - } else { - w5p = (WORD5 *)&(saveq->iocb.un.ulpWord[5]); - Rctl = w5p->hcsw.Rctl; - Type = w5p->hcsw.Type; - - /* Firmware Workaround */ - if ((Rctl == 0) && (pring->ringno == LPFC_ELS_RING) && - (irsp->ulpCommand == CMD_RCV_SEQUENCE64_CX || - irsp->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) { - Rctl = FC_RCTL_ELS_REQ; - Type = FC_TYPE_ELS; - w5p->hcsw.Rctl = Rctl; - w5p->hcsw.Type = Type; - } - } - - if (!lpfc_complete_unsol_iocb(phba, pring, saveq, Rctl, Type)) - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0313 Ring %d handler: unexpected Rctl x%x " - "Type x%x received\n", - pring->ringno, Rctl, Type); - - return 1; -} - -/** - * lpfc_sli_iocbq_lookup - Find command iocb for the given response iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @prspiocb: Pointer to response iocb object. - * - * This function looks up the iocb_lookup table to get the command iocb - * corresponding to the given response iocb using the iotag of the - * response iocb. This function is called with the hbalock held. - * This function returns the command iocb object if it finds the command - * iocb else returns NULL. - **/ -static struct lpfc_iocbq * -lpfc_sli_iocbq_lookup(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, - struct lpfc_iocbq *prspiocb) -{ - struct lpfc_iocbq *cmd_iocb = NULL; - uint16_t iotag; - - iotag = prspiocb->iocb.ulpIoTag; - - if (iotag != 0 && iotag <= phba->sli.last_iotag) { - cmd_iocb = phba->sli.iocbq_lookup[iotag]; - list_del_init(&cmd_iocb->list); - if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { - pring->txcmplq_cnt--; - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; - } - return cmd_iocb; - } - - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0317 iotag x%x is out off " - "range: max iotag x%x wd0 x%x\n", - iotag, phba->sli.last_iotag, - *(((uint32_t *) &prspiocb->iocb) + 7)); - return NULL; -} - -/** - * lpfc_sli_iocbq_lookup_by_tag - Find command iocb for the iotag - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @iotag: IOCB tag. - * - * This function looks up the iocb_lookup table to get the command iocb - * corresponding to the given iotag. This function is called with the - * hbalock held. - * This function returns the command iocb object if it finds the command - * iocb else returns NULL. - **/ -static struct lpfc_iocbq * -lpfc_sli_iocbq_lookup_by_tag(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, uint16_t iotag) -{ - struct lpfc_iocbq *cmd_iocb; - - if (iotag != 0 && iotag <= phba->sli.last_iotag) { - cmd_iocb = phba->sli.iocbq_lookup[iotag]; - list_del_init(&cmd_iocb->list); - if (cmd_iocb->iocb_flag & LPFC_IO_ON_Q) { - cmd_iocb->iocb_flag &= ~LPFC_IO_ON_Q; - pring->txcmplq_cnt--; - } - return cmd_iocb; - } - - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0372 iotag x%x is out off range: max iotag (x%x)\n", - iotag, phba->sli.last_iotag); - return NULL; -} - -/** - * lpfc_sli_process_sol_iocb - process solicited iocb completion - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @saveq: Pointer to the response iocb to be processed. - * - * This function is called by the ring event handler for non-fcp - * rings when there is a new response iocb in the response ring. - * The caller is not required to hold any locks. This function - * gets the command iocb associated with the response iocb and - * calls the completion handler for the command iocb. If there - * is no completion handler, the function will free the resources - * associated with command iocb. If the response iocb is for - * an already aborted command iocb, the status of the completion - * is changed to IOSTAT_LOCAL_REJECT/IOERR_SLI_ABORTED. - * This function always returns 1. - **/ -static int -lpfc_sli_process_sol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *saveq) -{ - struct lpfc_iocbq *cmdiocbp; - int rc = 1; - unsigned long iflag; - - /* Based on the iotag field, get the cmd IOCB from the txcmplq */ - spin_lock_irqsave(&phba->hbalock, iflag); - cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, saveq); - spin_unlock_irqrestore(&phba->hbalock, iflag); - - if (cmdiocbp) { - if (cmdiocbp->iocb_cmpl) { - /* - * If an ELS command failed send an event to mgmt - * application. - */ - if (saveq->iocb.ulpStatus && - (pring->ringno == LPFC_ELS_RING) && - (cmdiocbp->iocb.ulpCommand == - CMD_ELS_REQUEST64_CR)) - lpfc_send_els_failure_event(phba, - cmdiocbp, saveq); - - /* - * Post all ELS completions to the worker thread. - * All other are passed to the completion callback. - */ - if (pring->ringno == LPFC_ELS_RING) { - if ((phba->sli_rev < LPFC_SLI_REV4) && - (cmdiocbp->iocb_flag & - LPFC_DRIVER_ABORTED)) { - spin_lock_irqsave(&phba->hbalock, - iflag); - cmdiocbp->iocb_flag &= - ~LPFC_DRIVER_ABORTED; - spin_unlock_irqrestore(&phba->hbalock, - iflag); - saveq->iocb.ulpStatus = - IOSTAT_LOCAL_REJECT; - saveq->iocb.un.ulpWord[4] = - IOERR_SLI_ABORTED; - - /* Firmware could still be in progress - * of DMAing payload, so don't free data - * buffer till after a hbeat. - */ - spin_lock_irqsave(&phba->hbalock, - iflag); - saveq->iocb_flag |= LPFC_DELAY_MEM_FREE; - spin_unlock_irqrestore(&phba->hbalock, - iflag); - } - if (phba->sli_rev == LPFC_SLI_REV4) { - if (saveq->iocb_flag & - LPFC_EXCHANGE_BUSY) { - /* Set cmdiocb flag for the - * exchange busy so sgl (xri) - * will not be released until - * the abort xri is received - * from hba. - */ - spin_lock_irqsave( - &phba->hbalock, iflag); - cmdiocbp->iocb_flag |= - LPFC_EXCHANGE_BUSY; - spin_unlock_irqrestore( - &phba->hbalock, iflag); - } - if (cmdiocbp->iocb_flag & - LPFC_DRIVER_ABORTED) { - /* - * Clear LPFC_DRIVER_ABORTED - * bit in case it was driver - * initiated abort. - */ - spin_lock_irqsave( - &phba->hbalock, iflag); - cmdiocbp->iocb_flag &= - ~LPFC_DRIVER_ABORTED; - spin_unlock_irqrestore( - &phba->hbalock, iflag); - cmdiocbp->iocb.ulpStatus = - IOSTAT_LOCAL_REJECT; - cmdiocbp->iocb.un.ulpWord[4] = - IOERR_ABORT_REQUESTED; - /* - * For SLI4, irsiocb contains - * NO_XRI in sli_xritag, it - * shall not affect releasing - * sgl (xri) process. - */ - saveq->iocb.ulpStatus = - IOSTAT_LOCAL_REJECT; - saveq->iocb.un.ulpWord[4] = - IOERR_SLI_ABORTED; - spin_lock_irqsave( - &phba->hbalock, iflag); - saveq->iocb_flag |= - LPFC_DELAY_MEM_FREE; - spin_unlock_irqrestore( - &phba->hbalock, iflag); - } - } - } - (cmdiocbp->iocb_cmpl) (phba, cmdiocbp, saveq); - } else - lpfc_sli_release_iocbq(phba, cmdiocbp); - } else { - /* - * Unknown initiating command based on the response iotag. - * This could be the case on the ELS ring because of - * lpfc_els_abort(). - */ - if (pring->ringno != LPFC_ELS_RING) { - /* - * Ring handler: unexpected completion IoTag - * - */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0322 Ring %d handler: " - "unexpected completion IoTag x%x " - "Data: x%x x%x x%x x%x\n", - pring->ringno, - saveq->iocb.ulpIoTag, - saveq->iocb.ulpStatus, - saveq->iocb.un.ulpWord[4], - saveq->iocb.ulpCommand, - saveq->iocb.ulpContext); - } - } - - return rc; -} - -/** - * lpfc_sli_rsp_pointers_error - Response ring pointer error handler - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function is called from the iocb ring event handlers when - * put pointer is ahead of the get pointer for a ring. This function signal - * an error attention condition to the worker thread and the worker - * thread will transition the HBA to offline state. - **/ -static void -lpfc_sli_rsp_pointers_error(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; - /* - * Ring handler: portRspPut is bigger than - * rsp ring - */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0312 Ring %d handler: portRspPut %d " - "is bigger than rsp ring %d\n", - pring->ringno, le32_to_cpu(pgp->rspPutInx), - pring->numRiocb); - - phba->link_state = LPFC_HBA_ERROR; - - /* - * All error attention handlers are posted to - * worker thread - */ - phba->work_ha |= HA_ERATT; - phba->work_hs = HS_FFER3; - - lpfc_worker_wake_up(phba); - - return; -} - -/** - * lpfc_poll_eratt - Error attention polling timer timeout handler - * @ptr: Pointer to address of HBA context object. - * - * This function is invoked by the Error Attention polling timer when the - * timer times out. It will check the SLI Error Attention register for - * possible attention events. If so, it will post an Error Attention event - * and wake up worker thread to process it. Otherwise, it will set up the - * Error Attention polling timer for the next poll. - **/ -void lpfc_poll_eratt(unsigned long ptr) -{ - struct lpfc_hba *phba; - uint32_t eratt = 0; - - phba = (struct lpfc_hba *)ptr; - - /* Check chip HA register for error event */ - eratt = lpfc_sli_check_eratt(phba); - - if (eratt) - /* Tell the worker thread there is work to do */ - lpfc_worker_wake_up(phba); - else - /* Restart the timer for next eratt poll */ - mod_timer(&phba->eratt_poll, jiffies + - HZ * LPFC_ERATT_POLL_INTERVAL); - return; -} - - -/** - * lpfc_sli_handle_fast_ring_event - Handle ring events on FCP ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @mask: Host attention register mask for this ring. - * - * This function is called from the interrupt context when there is a ring - * event for the fcp ring. The caller does not hold any lock. - * The function processes each response iocb in the response ring until it - * finds an iocb with LE bit set and chains all the iocbs up to the iocb with - * LE bit set. The function will call the completion handler of the command iocb - * if the response iocb indicates a completion for a command iocb or it is - * an abort completion. The function will call lpfc_sli_process_unsol_iocb - * function if this is an unsolicited iocb. - * This routine presumes LPFC_FCP_RING handling and doesn't bother - * to check it explicitly. - */ -int -lpfc_sli_handle_fast_ring_event(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, uint32_t mask) -{ - struct lpfc_pgp *pgp = &phba->port_gp[pring->ringno]; - IOCB_t *irsp = NULL; - IOCB_t *entry = NULL; - struct lpfc_iocbq *cmdiocbq = NULL; - struct lpfc_iocbq rspiocbq; - uint32_t status; - uint32_t portRspPut, portRspMax; - int rc = 1; - lpfc_iocb_type type; - unsigned long iflag; - uint32_t rsp_cmpl = 0; - - spin_lock_irqsave(&phba->hbalock, iflag); - pring->stats.iocb_event++; - - /* - * The next available response entry should never exceed the maximum - * entries. If it does, treat it as an adapter hardware error. - */ - portRspMax = pring->numRiocb; - portRspPut = le32_to_cpu(pgp->rspPutInx); - if (unlikely(portRspPut >= portRspMax)) { - lpfc_sli_rsp_pointers_error(phba, pring); - spin_unlock_irqrestore(&phba->hbalock, iflag); - return 1; - } - if (phba->fcp_ring_in_use) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - return 1; - } else - phba->fcp_ring_in_use = 1; - - rmb(); - while (pring->rspidx != portRspPut) { - /* - * Fetch an entry off the ring and copy it into a local data - * structure. The copy involves a byte-swap since the - * network byte order and pci byte orders are different. - */ - entry = lpfc_resp_iocb(phba, pring); - phba->last_completion_time = jiffies; - - if (++pring->rspidx >= portRspMax) - pring->rspidx = 0; - - lpfc_sli_pcimem_bcopy((uint32_t *) entry, - (uint32_t *) &rspiocbq.iocb, - phba->iocb_rsp_size); - INIT_LIST_HEAD(&(rspiocbq.list)); - irsp = &rspiocbq.iocb; - - type = lpfc_sli_iocb_cmd_type(irsp->ulpCommand & CMD_IOCB_MASK); - pring->stats.iocb_rsp++; - rsp_cmpl++; - - if (unlikely(irsp->ulpStatus)) { - /* - * If resource errors reported from HBA, reduce - * queuedepths of the SCSI device. - */ - if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - phba->lpfc_rampdown_queue_depth(phba); - spin_lock_irqsave(&phba->hbalock, iflag); - } - - /* Rsp ring error: IOCB */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0336 Rsp Ring %d error: IOCB Data: " - "x%x x%x x%x x%x x%x x%x x%x x%x\n", - pring->ringno, - irsp->un.ulpWord[0], - irsp->un.ulpWord[1], - irsp->un.ulpWord[2], - irsp->un.ulpWord[3], - irsp->un.ulpWord[4], - irsp->un.ulpWord[5], - *(uint32_t *)&irsp->un1, - *((uint32_t *)&irsp->un1 + 1)); - } - - switch (type) { - case LPFC_ABORT_IOCB: - case LPFC_SOL_IOCB: - /* - * Idle exchange closed via ABTS from port. No iocb - * resources need to be recovered. - */ - if (unlikely(irsp->ulpCommand == CMD_XRI_ABORTED_CX)) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0333 IOCB cmd 0x%x" - " processed. Skipping" - " completion\n", - irsp->ulpCommand); - break; - } - - cmdiocbq = lpfc_sli_iocbq_lookup(phba, pring, - &rspiocbq); - if (unlikely(!cmdiocbq)) - break; - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) - cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; - if (cmdiocbq->iocb_cmpl) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, - &rspiocbq); - spin_lock_irqsave(&phba->hbalock, iflag); - } - break; - case LPFC_UNSOL_IOCB: - spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_sli_process_unsol_iocb(phba, pring, &rspiocbq); - spin_lock_irqsave(&phba->hbalock, iflag); - break; - default: - if (irsp->ulpCommand == CMD_ADAPTER_MSG) { - char adaptermsg[LPFC_MAX_ADPTMSG]; - memset(adaptermsg, 0, LPFC_MAX_ADPTMSG); - memcpy(&adaptermsg[0], (uint8_t *) irsp, - MAX_MSG_DATA); - dev_warn(&((phba->pcidev)->dev), - "lpfc%d: %s\n", - phba->brd_no, adaptermsg); - } else { - /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0334 Unknown IOCB command " - "Data: x%x, x%x x%x x%x x%x\n", - type, irsp->ulpCommand, - irsp->ulpStatus, - irsp->ulpIoTag, - irsp->ulpContext); - } - break; - } - - /* - * The response IOCB has been processed. Update the ring - * pointer in SLIM. If the port response put pointer has not - * been updated, sync the pgp->rspPutInx and fetch the new port - * response put pointer. - */ - writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); - - if (pring->rspidx == portRspPut) - portRspPut = le32_to_cpu(pgp->rspPutInx); - } - - if ((rsp_cmpl > 0) && (mask & HA_R0RE_REQ)) { - pring->stats.iocb_rsp_full++; - status = ((CA_R0ATT | CA_R0RE_RSP) << (pring->ringno * 4)); - writel(status, phba->CAregaddr); - readl(phba->CAregaddr); - } - if ((mask & HA_R0CE_RSP) && (pring->flag & LPFC_CALL_RING_AVAILABLE)) { - pring->flag &= ~LPFC_CALL_RING_AVAILABLE; - pring->stats.iocb_cmd_empty++; - - /* Force update of the local copy of cmdGetInx */ - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); - lpfc_sli_resume_iocb(phba, pring); - - if ((pring->lpfc_sli_cmd_available)) - (pring->lpfc_sli_cmd_available) (phba, pring); - - } - - phba->fcp_ring_in_use = 0; - spin_unlock_irqrestore(&phba->hbalock, iflag); - return rc; -} - -/** - * lpfc_sli_sp_handle_rspiocb - Handle slow-path response iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @rspiocbp: Pointer to driver response IOCB object. - * - * This function is called from the worker thread when there is a slow-path - * response IOCB to process. This function chains all the response iocbs until - * seeing the iocb with the LE bit set. The function will call - * lpfc_sli_process_sol_iocb function if the response iocb indicates a - * completion of a command iocb. The function will call the - * lpfc_sli_process_unsol_iocb function if this is an unsolicited iocb. - * The function frees the resources or calls the completion handler if this - * iocb is an abort completion. The function returns NULL when the response - * iocb has the LE bit set and all the chained iocbs are processed, otherwise - * this function shall chain the iocb on to the iocb_continueq and return the - * response iocb passed in. - **/ -static struct lpfc_iocbq * -lpfc_sli_sp_handle_rspiocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *rspiocbp) -{ - struct lpfc_iocbq *saveq; - struct lpfc_iocbq *cmdiocbp; - struct lpfc_iocbq *next_iocb; - IOCB_t *irsp = NULL; - uint32_t free_saveq; - uint8_t iocb_cmd_type; - lpfc_iocb_type type; - unsigned long iflag; - int rc; - - spin_lock_irqsave(&phba->hbalock, iflag); - /* First add the response iocb to the countinueq list */ - list_add_tail(&rspiocbp->list, &(pring->iocb_continueq)); - pring->iocb_continueq_cnt++; - - /* Now, determine whether the list is completed for processing */ - irsp = &rspiocbp->iocb; - if (irsp->ulpLe) { - /* - * By default, the driver expects to free all resources - * associated with this iocb completion. - */ - free_saveq = 1; - saveq = list_get_first(&pring->iocb_continueq, - struct lpfc_iocbq, list); - irsp = &(saveq->iocb); - list_del_init(&pring->iocb_continueq); - pring->iocb_continueq_cnt = 0; - - pring->stats.iocb_rsp++; - - /* - * If resource errors reported from HBA, reduce - * queuedepths of the SCSI device. - */ - if ((irsp->ulpStatus == IOSTAT_LOCAL_REJECT) && - (irsp->un.ulpWord[4] == IOERR_NO_RESOURCES)) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - phba->lpfc_rampdown_queue_depth(phba); - spin_lock_irqsave(&phba->hbalock, iflag); - } - - if (irsp->ulpStatus) { - /* Rsp ring error: IOCB */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0328 Rsp Ring %d error: " - "IOCB Data: " - "x%x x%x x%x x%x " - "x%x x%x x%x x%x " - "x%x x%x x%x x%x " - "x%x x%x x%x x%x\n", - pring->ringno, - irsp->un.ulpWord[0], - irsp->un.ulpWord[1], - irsp->un.ulpWord[2], - irsp->un.ulpWord[3], - irsp->un.ulpWord[4], - irsp->un.ulpWord[5], - *(((uint32_t *) irsp) + 6), - *(((uint32_t *) irsp) + 7), - *(((uint32_t *) irsp) + 8), - *(((uint32_t *) irsp) + 9), - *(((uint32_t *) irsp) + 10), - *(((uint32_t *) irsp) + 11), - *(((uint32_t *) irsp) + 12), - *(((uint32_t *) irsp) + 13), - *(((uint32_t *) irsp) + 14), - *(((uint32_t *) irsp) + 15)); - } - - /* - * Fetch the IOCB command type and call the correct completion - * routine. Solicited and Unsolicited IOCBs on the ELS ring - * get freed back to the lpfc_iocb_list by the discovery - * kernel thread. - */ - iocb_cmd_type = irsp->ulpCommand & CMD_IOCB_MASK; - type = lpfc_sli_iocb_cmd_type(iocb_cmd_type); - switch (type) { - case LPFC_SOL_IOCB: - spin_unlock_irqrestore(&phba->hbalock, iflag); - rc = lpfc_sli_process_sol_iocb(phba, pring, saveq); - spin_lock_irqsave(&phba->hbalock, iflag); - break; - - case LPFC_UNSOL_IOCB: - spin_unlock_irqrestore(&phba->hbalock, iflag); - rc = lpfc_sli_process_unsol_iocb(phba, pring, saveq); - spin_lock_irqsave(&phba->hbalock, iflag); - if (!rc) - free_saveq = 0; - break; - - case LPFC_ABORT_IOCB: - cmdiocbp = NULL; - if (irsp->ulpCommand != CMD_XRI_ABORTED_CX) - cmdiocbp = lpfc_sli_iocbq_lookup(phba, pring, - saveq); - if (cmdiocbp) { - /* Call the specified completion routine */ - if (cmdiocbp->iocb_cmpl) { - spin_unlock_irqrestore(&phba->hbalock, - iflag); - (cmdiocbp->iocb_cmpl)(phba, cmdiocbp, - saveq); - spin_lock_irqsave(&phba->hbalock, - iflag); - } else - __lpfc_sli_release_iocbq(phba, - cmdiocbp); - } - break; - - case LPFC_UNKNOWN_IOCB: - if (irsp->ulpCommand == CMD_ADAPTER_MSG) { - char adaptermsg[LPFC_MAX_ADPTMSG]; - memset(adaptermsg, 0, LPFC_MAX_ADPTMSG); - memcpy(&adaptermsg[0], (uint8_t *)irsp, - MAX_MSG_DATA); - dev_warn(&((phba->pcidev)->dev), - "lpfc%d: %s\n", - phba->brd_no, adaptermsg); - } else { - /* Unknown IOCB command */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0335 Unknown IOCB " - "command Data: x%x " - "x%x x%x x%x\n", - irsp->ulpCommand, - irsp->ulpStatus, - irsp->ulpIoTag, - irsp->ulpContext); - } - break; - } - - if (free_saveq) { - list_for_each_entry_safe(rspiocbp, next_iocb, - &saveq->list, list) { - list_del(&rspiocbp->list); - __lpfc_sli_release_iocbq(phba, rspiocbp); - } - __lpfc_sli_release_iocbq(phba, saveq); - } - rspiocbp = NULL; - } - spin_unlock_irqrestore(&phba->hbalock, iflag); - return rspiocbp; -} - -/** - * lpfc_sli_handle_slow_ring_event - Wrapper func for handling slow-path iocbs - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @mask: Host attention register mask for this ring. - * - * This routine wraps the actual slow_ring event process routine from the - * API jump table function pointer from the lpfc_hba struct. - **/ -void -lpfc_sli_handle_slow_ring_event(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, uint32_t mask) -{ - phba->lpfc_sli_handle_slow_ring_event(phba, pring, mask); -} - -/** - * lpfc_sli_handle_slow_ring_event_s3 - Handle SLI3 ring event for non-FCP rings - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @mask: Host attention register mask for this ring. - * - * This function is called from the worker thread when there is a ring event - * for non-fcp rings. The caller does not hold any lock. The function will - * remove each response iocb in the response ring and calls the handle - * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it. - **/ -static void -lpfc_sli_handle_slow_ring_event_s3(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, uint32_t mask) -{ - struct lpfc_pgp *pgp; - IOCB_t *entry; - IOCB_t *irsp = NULL; - struct lpfc_iocbq *rspiocbp = NULL; - uint32_t portRspPut, portRspMax; - unsigned long iflag; - uint32_t status; - - pgp = &phba->port_gp[pring->ringno]; - spin_lock_irqsave(&phba->hbalock, iflag); - pring->stats.iocb_event++; - - /* - * The next available response entry should never exceed the maximum - * entries. If it does, treat it as an adapter hardware error. - */ - portRspMax = pring->numRiocb; - portRspPut = le32_to_cpu(pgp->rspPutInx); - if (portRspPut >= portRspMax) { - /* - * Ring handler: portRspPut is bigger than - * rsp ring - */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0303 Ring %d handler: portRspPut %d " - "is bigger than rsp ring %d\n", - pring->ringno, portRspPut, portRspMax); - - phba->link_state = LPFC_HBA_ERROR; - spin_unlock_irqrestore(&phba->hbalock, iflag); - - phba->work_hs = HS_FFER3; - lpfc_handle_eratt(phba); - - return; - } - - rmb(); - while (pring->rspidx != portRspPut) { - /* - * Build a completion list and call the appropriate handler. - * The process is to get the next available response iocb, get - * a free iocb from the list, copy the response data into the - * free iocb, insert to the continuation list, and update the - * next response index to slim. This process makes response - * iocb's in the ring available to DMA as fast as possible but - * pays a penalty for a copy operation. Since the iocb is - * only 32 bytes, this penalty is considered small relative to - * the PCI reads for register values and a slim write. When - * the ulpLe field is set, the entire Command has been - * received. - */ - entry = lpfc_resp_iocb(phba, pring); - - phba->last_completion_time = jiffies; - rspiocbp = __lpfc_sli_get_iocbq(phba); - if (rspiocbp == NULL) { - printk(KERN_ERR "%s: out of buffers! Failing " - "completion.\n", __func__); - break; - } - - lpfc_sli_pcimem_bcopy(entry, &rspiocbp->iocb, - phba->iocb_rsp_size); - irsp = &rspiocbp->iocb; - - if (++pring->rspidx >= portRspMax) - pring->rspidx = 0; - - if (pring->ringno == LPFC_ELS_RING) { - lpfc_debugfs_slow_ring_trc(phba, - "IOCB rsp ring: wd4:x%08x wd6:x%08x wd7:x%08x", - *(((uint32_t *) irsp) + 4), - *(((uint32_t *) irsp) + 6), - *(((uint32_t *) irsp) + 7)); - } - - writel(pring->rspidx, &phba->host_gp[pring->ringno].rspGetInx); - - spin_unlock_irqrestore(&phba->hbalock, iflag); - /* Handle the response IOCB */ - rspiocbp = lpfc_sli_sp_handle_rspiocb(phba, pring, rspiocbp); - spin_lock_irqsave(&phba->hbalock, iflag); - - /* - * If the port response put pointer has not been updated, sync - * the pgp->rspPutInx in the MAILBOX_tand fetch the new port - * response put pointer. - */ - if (pring->rspidx == portRspPut) { - portRspPut = le32_to_cpu(pgp->rspPutInx); - } - } /* while (pring->rspidx != portRspPut) */ - - if ((rspiocbp != NULL) && (mask & HA_R0RE_REQ)) { - /* At least one response entry has been freed */ - pring->stats.iocb_rsp_full++; - /* SET RxRE_RSP in Chip Att register */ - status = ((CA_R0ATT | CA_R0RE_RSP) << (pring->ringno * 4)); - writel(status, phba->CAregaddr); - readl(phba->CAregaddr); /* flush */ - } - if ((mask & HA_R0CE_RSP) && (pring->flag & LPFC_CALL_RING_AVAILABLE)) { - pring->flag &= ~LPFC_CALL_RING_AVAILABLE; - pring->stats.iocb_cmd_empty++; - - /* Force update of the local copy of cmdGetInx */ - pring->local_getidx = le32_to_cpu(pgp->cmdGetInx); - lpfc_sli_resume_iocb(phba, pring); - - if ((pring->lpfc_sli_cmd_available)) - (pring->lpfc_sli_cmd_available) (phba, pring); - - } - - spin_unlock_irqrestore(&phba->hbalock, iflag); - return; -} - -/** - * lpfc_sli_handle_slow_ring_event_s4 - Handle SLI4 slow-path els events - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @mask: Host attention register mask for this ring. - * - * This function is called from the worker thread when there is a pending - * ELS response iocb on the driver internal slow-path response iocb worker - * queue. The caller does not hold any lock. The function will remove each - * response iocb from the response worker queue and calls the handle - * response iocb routine (lpfc_sli_sp_handle_rspiocb) to process it. - **/ -static void -lpfc_sli_handle_slow_ring_event_s4(struct lpfc_hba *phba, - struct lpfc_sli_ring *pring, uint32_t mask) -{ - struct lpfc_iocbq *irspiocbq; - struct hbq_dmabuf *dmabuf; - struct lpfc_cq_event *cq_event; - unsigned long iflag; - - spin_lock_irqsave(&phba->hbalock, iflag); - phba->hba_flag &= ~HBA_SP_QUEUE_EVT; - spin_unlock_irqrestore(&phba->hbalock, iflag); - while (!list_empty(&phba->sli4_hba.sp_queue_event)) { - /* Get the response iocb from the head of work queue */ - spin_lock_irqsave(&phba->hbalock, iflag); - list_remove_head(&phba->sli4_hba.sp_queue_event, - cq_event, struct lpfc_cq_event, list); - spin_unlock_irqrestore(&phba->hbalock, iflag); - - switch (bf_get(lpfc_wcqe_c_code, &cq_event->cqe.wcqe_cmpl)) { - case CQE_CODE_COMPL_WQE: - irspiocbq = container_of(cq_event, struct lpfc_iocbq, - cq_event); - /* Translate ELS WCQE to response IOCBQ */ - irspiocbq = lpfc_sli4_els_wcqe_to_rspiocbq(phba, - irspiocbq); - if (irspiocbq) - lpfc_sli_sp_handle_rspiocb(phba, pring, - irspiocbq); - break; - case CQE_CODE_RECEIVE: - case CQE_CODE_RECEIVE_V1: - dmabuf = container_of(cq_event, struct hbq_dmabuf, - cq_event); - lpfc_sli4_handle_received_buffer(phba, dmabuf); - break; - default: - break; - } - } -} - -/** - * lpfc_sli_abort_iocb_ring - Abort all iocbs in the ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function aborts all iocbs in the given ring and frees all the iocb - * objects in txq. This function issues an abort iocb for all the iocb commands - * in txcmplq. The iocbs in the txcmplq is not guaranteed to complete before - * the return of this function. The caller is not required to hold any locks. - **/ -void -lpfc_sli_abort_iocb_ring(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - LIST_HEAD(completions); - struct lpfc_iocbq *iocb, *next_iocb; - - if (pring->ringno == LPFC_ELS_RING) { - lpfc_fabric_abort_hba(phba); - } - - /* Error everything on txq and txcmplq - * First do the txq. - */ - spin_lock_irq(&phba->hbalock); - list_splice_init(&pring->txq, &completions); - pring->txq_cnt = 0; - - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_issue_abort_iotag(phba, pring, iocb); - - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); -} - -/** - * lpfc_sli_flush_fcp_rings - flush all iocbs in the fcp ring - * @phba: Pointer to HBA context object. - * - * This function flushes all iocbs in the fcp ring and frees all the iocb - * objects in txq and txcmplq. This function will not issue abort iocbs - * for all the iocb commands in txcmplq, they will just be returned with - * IOERR_SLI_DOWN. This function is invoked with EEH when device's PCI - * slot has been permanently disabled. - **/ -void -lpfc_sli_flush_fcp_rings(struct lpfc_hba *phba) -{ - LIST_HEAD(txq); - LIST_HEAD(txcmplq); - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - - /* Currently, only one fcp ring */ - pring = &psli->ring[psli->fcp_ring]; - - spin_lock_irq(&phba->hbalock); - /* Retrieve everything on txq */ - list_splice_init(&pring->txq, &txq); - pring->txq_cnt = 0; - - /* Retrieve everything on the txcmplq */ - list_splice_init(&pring->txcmplq, &txcmplq); - pring->txcmplq_cnt = 0; - spin_unlock_irq(&phba->hbalock); - - /* Flush the txq */ - lpfc_sli_cancel_iocbs(phba, &txq, IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); - - /* Flush the txcmpq */ - lpfc_sli_cancel_iocbs(phba, &txcmplq, IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); -} - -/** - * lpfc_sli_brdready_s3 - Check for sli3 host ready status - * @phba: Pointer to HBA context object. - * @mask: Bit mask to be checked. - * - * This function reads the host status register and compares - * with the provided bit mask to check if HBA completed - * the restart. This function will wait in a loop for the - * HBA to complete restart. If the HBA does not restart within - * 15 iterations, the function will reset the HBA again. The - * function returns 1 when HBA fail to restart otherwise returns - * zero. - **/ -static int -lpfc_sli_brdready_s3(struct lpfc_hba *phba, uint32_t mask) -{ - uint32_t status; - int i = 0; - int retval = 0; - - /* Read the HBA Host Status Register */ - if (lpfc_readl(phba->HSregaddr, &status)) - return 1; - - /* - * Check status register every 100ms for 5 retries, then every - * 500ms for 5, then every 2.5 sec for 5, then reset board and - * every 2.5 sec for 4. - * Break our of the loop if errors occurred during init. - */ - while (((status & mask) != mask) && - !(status & HS_FFERM) && - i++ < 20) { - - if (i <= 5) - msleep(10); - else if (i <= 10) - msleep(500); - else - msleep(2500); - - if (i == 15) { - /* Do post */ - phba->pport->port_state = LPFC_VPORT_UNKNOWN; - lpfc_sli_brdrestart(phba); - } - /* Read the HBA Host Status Register */ - if (lpfc_readl(phba->HSregaddr, &status)) { - retval = 1; - break; - } - } - - /* Check to see if any errors occurred during init */ - if ((status & HS_FFERM) || (i >= 20)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2751 Adapter failed to restart, " - "status reg x%x, FW Data: A8 x%x AC x%x\n", - status, - readl(phba->MBslimaddr + 0xa8), - readl(phba->MBslimaddr + 0xac)); - phba->link_state = LPFC_HBA_ERROR; - retval = 1; - } - - return retval; -} - -/** - * lpfc_sli_brdready_s4 - Check for sli4 host ready status - * @phba: Pointer to HBA context object. - * @mask: Bit mask to be checked. - * - * This function checks the host status register to check if HBA is - * ready. This function will wait in a loop for the HBA to be ready - * If the HBA is not ready , the function will will reset the HBA PCI - * function again. The function returns 1 when HBA fail to be ready - * otherwise returns zero. - **/ -static int -lpfc_sli_brdready_s4(struct lpfc_hba *phba, uint32_t mask) -{ - uint32_t status; - int retval = 0; - - /* Read the HBA Host Status Register */ - status = lpfc_sli4_post_status_check(phba); - - if (status) { - phba->pport->port_state = LPFC_VPORT_UNKNOWN; - lpfc_sli_brdrestart(phba); - status = lpfc_sli4_post_status_check(phba); - } - - /* Check to see if any errors occurred during init */ - if (status) { - phba->link_state = LPFC_HBA_ERROR; - retval = 1; - } else - phba->sli4_hba.intr_enable = 0; - - return retval; -} - -/** - * lpfc_sli_brdready - Wrapper func for checking the hba readyness - * @phba: Pointer to HBA context object. - * @mask: Bit mask to be checked. - * - * This routine wraps the actual SLI3 or SLI4 hba readyness check routine - * from the API jump table function pointer from the lpfc_hba struct. - **/ -int -lpfc_sli_brdready(struct lpfc_hba *phba, uint32_t mask) -{ - return phba->lpfc_sli_brdready(phba, mask); -} - -#define BARRIER_TEST_PATTERN (0xdeadbeef) - -/** - * lpfc_reset_barrier - Make HBA ready for HBA reset - * @phba: Pointer to HBA context object. - * - * This function is called before resetting an HBA. This function is called - * with hbalock held and requests HBA to quiesce DMAs before a reset. - **/ -void lpfc_reset_barrier(struct lpfc_hba *phba) -{ - uint32_t __iomem *resp_buf; - uint32_t __iomem *mbox_buf; - volatile uint32_t mbox; - uint32_t hc_copy, ha_copy, resp_data; - int i; - uint8_t hdrtype; - - pci_read_config_byte(phba->pcidev, PCI_HEADER_TYPE, &hdrtype); - if (hdrtype != 0x80 || - (FC_JEDEC_ID(phba->vpd.rev.biuRev) != HELIOS_JEDEC_ID && - FC_JEDEC_ID(phba->vpd.rev.biuRev) != THOR_JEDEC_ID)) - return; - - /* - * Tell the other part of the chip to suspend temporarily all - * its DMA activity. - */ - resp_buf = phba->MBslimaddr; - - /* Disable the error attention */ - if (lpfc_readl(phba->HCregaddr, &hc_copy)) - return; - writel((hc_copy & ~HC_ERINT_ENA), phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - phba->link_flag |= LS_IGNORE_ERATT; - - if (lpfc_readl(phba->HAregaddr, &ha_copy)) - return; - if (ha_copy & HA_ERATT) { - /* Clear Chip error bit */ - writel(HA_ERATT, phba->HAregaddr); - phba->pport->stopped = 1; - } - - mbox = 0; - ((MAILBOX_t *)&mbox)->mbxCommand = MBX_KILL_BOARD; - ((MAILBOX_t *)&mbox)->mbxOwner = OWN_CHIP; - - writel(BARRIER_TEST_PATTERN, (resp_buf + 1)); - mbox_buf = phba->MBslimaddr; - writel(mbox, mbox_buf); - - for (i = 0; i < 50; i++) { - if (lpfc_readl((resp_buf + 1), &resp_data)) - return; - if (resp_data != ~(BARRIER_TEST_PATTERN)) - mdelay(1); - else - break; - } - resp_data = 0; - if (lpfc_readl((resp_buf + 1), &resp_data)) - return; - if (resp_data != ~(BARRIER_TEST_PATTERN)) { - if (phba->sli.sli_flag & LPFC_SLI_ACTIVE || - phba->pport->stopped) - goto restore_hc; - else - goto clear_errat; - } - - ((MAILBOX_t *)&mbox)->mbxOwner = OWN_HOST; - resp_data = 0; - for (i = 0; i < 500; i++) { - if (lpfc_readl(resp_buf, &resp_data)) - return; - if (resp_data != mbox) - mdelay(1); - else - break; - } - -clear_errat: - - while (++i < 500) { - if (lpfc_readl(phba->HAregaddr, &ha_copy)) - return; - if (!(ha_copy & HA_ERATT)) - mdelay(1); - else - break; - } - - if (readl(phba->HAregaddr) & HA_ERATT) { - writel(HA_ERATT, phba->HAregaddr); - phba->pport->stopped = 1; - } - -restore_hc: - phba->link_flag &= ~LS_IGNORE_ERATT; - writel(hc_copy, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ -} - -/** - * lpfc_sli_brdkill - Issue a kill_board mailbox command - * @phba: Pointer to HBA context object. - * - * This function issues a kill_board mailbox command and waits for - * the error attention interrupt. This function is called for stopping - * the firmware processing. The caller is not required to hold any - * locks. This function calls lpfc_hba_down_post function to free - * any pending commands after the kill. The function will return 1 when it - * fails to kill the board else will return 0. - **/ -int -lpfc_sli_brdkill(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli; - LPFC_MBOXQ_t *pmb; - uint32_t status; - uint32_t ha_copy; - int retval; - int i = 0; - - psli = &phba->sli; - - /* Kill HBA */ - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0329 Kill HBA Data: x%x x%x\n", - phba->pport->port_state, psli->sli_flag); - - pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) - return 1; - - /* Disable the error attention */ - spin_lock_irq(&phba->hbalock); - if (lpfc_readl(phba->HCregaddr, &status)) { - spin_unlock_irq(&phba->hbalock); - mempool_free(pmb, phba->mbox_mem_pool); - return 1; - } - status &= ~HC_ERINT_ENA; - writel(status, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - phba->link_flag |= LS_IGNORE_ERATT; - spin_unlock_irq(&phba->hbalock); - - lpfc_kill_board(phba, pmb); - pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - retval = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - - if (retval != MBX_SUCCESS) { - if (retval != MBX_BUSY) - mempool_free(pmb, phba->mbox_mem_pool); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2752 KILL_BOARD command failed retval %d\n", - retval); - spin_lock_irq(&phba->hbalock); - phba->link_flag &= ~LS_IGNORE_ERATT; - spin_unlock_irq(&phba->hbalock); - return 1; - } - - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - - mempool_free(pmb, phba->mbox_mem_pool); - - /* There is no completion for a KILL_BOARD mbox cmd. Check for an error - * attention every 100ms for 3 seconds. If we don't get ERATT after - * 3 seconds we still set HBA_ERROR state because the status of the - * board is now undefined. - */ - if (lpfc_readl(phba->HAregaddr, &ha_copy)) - return 1; - while ((i++ < 30) && !(ha_copy & HA_ERATT)) { - mdelay(100); - if (lpfc_readl(phba->HAregaddr, &ha_copy)) - return 1; - } - - del_timer_sync(&psli->mbox_tmo); - if (ha_copy & HA_ERATT) { - writel(HA_ERATT, phba->HAregaddr); - phba->pport->stopped = 1; - } - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - psli->mbox_active = NULL; - phba->link_flag &= ~LS_IGNORE_ERATT; - spin_unlock_irq(&phba->hbalock); - - lpfc_hba_down_post(phba); - phba->link_state = LPFC_HBA_ERROR; - - return ha_copy & HA_ERATT ? 0 : 1; -} - -/** - * lpfc_sli_brdreset - Reset a sli-2 or sli-3 HBA - * @phba: Pointer to HBA context object. - * - * This function resets the HBA by writing HC_INITFF to the control - * register. After the HBA resets, this function resets all the iocb ring - * indices. This function disables PCI layer parity checking during - * the reset. - * This function returns 0 always. - * The caller is not required to hold any locks. - **/ -int -lpfc_sli_brdreset(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli; - struct lpfc_sli_ring *pring; - uint16_t cfg_value; - int i; - - psli = &phba->sli; - - /* Reset HBA */ - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0325 Reset HBA Data: x%x x%x\n", - phba->pport->port_state, psli->sli_flag); - - /* perform board reset */ - phba->fc_eventTag = 0; - phba->link_events = 0; - phba->pport->fc_myDID = 0; - phba->pport->fc_prevDID = 0; - - /* Turn off parity checking and serr during the physical reset */ - pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); - pci_write_config_word(phba->pcidev, PCI_COMMAND, - (cfg_value & - ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); - - psli->sli_flag &= ~(LPFC_SLI_ACTIVE | LPFC_PROCESS_LA); - - /* Now toggle INITFF bit in the Host Control Register */ - writel(HC_INITFF, phba->HCregaddr); - mdelay(1); - readl(phba->HCregaddr); /* flush */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - - /* Restore PCI cmd register */ - pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value); - - /* Initialize relevant SLI info */ - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - pring->flag = 0; - pring->rspidx = 0; - pring->next_cmdidx = 0; - pring->local_getidx = 0; - pring->cmdidx = 0; - pring->missbufcnt = 0; - } - - phba->link_state = LPFC_WARM_START; - return 0; -} - -/** - * lpfc_sli4_brdreset - Reset a sli-4 HBA - * @phba: Pointer to HBA context object. - * - * This function resets a SLI4 HBA. This function disables PCI layer parity - * checking during resets the device. The caller is not required to hold - * any locks. - * - * This function returns 0 always. - **/ -int -lpfc_sli4_brdreset(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - uint16_t cfg_value; - - /* Reset HBA */ - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0295 Reset HBA Data: x%x x%x\n", - phba->pport->port_state, psli->sli_flag); - - /* perform board reset */ - phba->fc_eventTag = 0; - phba->link_events = 0; - phba->pport->fc_myDID = 0; - phba->pport->fc_prevDID = 0; - - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~(LPFC_PROCESS_LA); - phba->fcf.fcf_flag = 0; - spin_unlock_irq(&phba->hbalock); - - /* Now physically reset the device */ - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0389 Performing PCI function reset!\n"); - - /* Turn off parity checking and serr during the physical reset */ - pci_read_config_word(phba->pcidev, PCI_COMMAND, &cfg_value); - pci_write_config_word(phba->pcidev, PCI_COMMAND, (cfg_value & - ~(PCI_COMMAND_PARITY | PCI_COMMAND_SERR))); - - /* Perform FCoE PCI function reset */ - lpfc_sli4_queue_destroy(phba); - lpfc_pci_function_reset(phba); - - /* Restore PCI cmd register */ - pci_write_config_word(phba->pcidev, PCI_COMMAND, cfg_value); - - return 0; -} - -/** - * lpfc_sli_brdrestart_s3 - Restart a sli-3 hba - * @phba: Pointer to HBA context object. - * - * This function is called in the SLI initialization code path to - * restart the HBA. The caller is not required to hold any lock. - * This function writes MBX_RESTART mailbox command to the SLIM and - * resets the HBA. At the end of the function, it calls lpfc_hba_down_post - * function to free any pending commands. The function enables - * POST only during the first initialization. The function returns zero. - * The function does not guarantee completion of MBX_RESTART mailbox - * command before the return of this function. - **/ -static int -lpfc_sli_brdrestart_s3(struct lpfc_hba *phba) -{ - MAILBOX_t *mb; - struct lpfc_sli *psli; - volatile uint32_t word0; - void __iomem *to_slim; - uint32_t hba_aer_enabled; - - spin_lock_irq(&phba->hbalock); - - /* Take PCIe device Advanced Error Reporting (AER) state */ - hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; - - psli = &phba->sli; - - /* Restart HBA */ - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0337 Restart HBA Data: x%x x%x\n", - phba->pport->port_state, psli->sli_flag); - - word0 = 0; - mb = (MAILBOX_t *) &word0; - mb->mbxCommand = MBX_RESTART; - mb->mbxHc = 1; - - lpfc_reset_barrier(phba); - - to_slim = phba->MBslimaddr; - writel(*(uint32_t *) mb, to_slim); - readl(to_slim); /* flush */ - - /* Only skip post after fc_ffinit is completed */ - if (phba->pport->port_state) - word0 = 1; /* This is really setting up word1 */ - else - word0 = 0; /* This is really setting up word1 */ - to_slim = phba->MBslimaddr + sizeof (uint32_t); - writel(*(uint32_t *) mb, to_slim); - readl(to_slim); /* flush */ - - lpfc_sli_brdreset(phba); - phba->pport->stopped = 0; - phba->link_state = LPFC_INIT_START; - phba->hba_flag = 0; - spin_unlock_irq(&phba->hbalock); - - memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); - psli->stats_start = get_seconds(); - - /* Give the INITFF and Post time to settle. */ - mdelay(100); - - /* Reset HBA AER if it was enabled, note hba_flag was reset above */ - if (hba_aer_enabled) - pci_disable_pcie_error_reporting(phba->pcidev); - - lpfc_hba_down_post(phba); - - return 0; -} - -/** - * lpfc_sli_brdrestart_s4 - Restart the sli-4 hba - * @phba: Pointer to HBA context object. - * - * This function is called in the SLI initialization code path to restart - * a SLI4 HBA. The caller is not required to hold any lock. - * At the end of the function, it calls lpfc_hba_down_post function to - * free any pending commands. - **/ -static int -lpfc_sli_brdrestart_s4(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - uint32_t hba_aer_enabled; - - /* Restart HBA */ - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0296 Restart HBA Data: x%x x%x\n", - phba->pport->port_state, psli->sli_flag); - - /* Take PCIe device Advanced Error Reporting (AER) state */ - hba_aer_enabled = phba->hba_flag & HBA_AER_ENABLED; - - lpfc_sli4_brdreset(phba); - - spin_lock_irq(&phba->hbalock); - phba->pport->stopped = 0; - phba->link_state = LPFC_INIT_START; - phba->hba_flag = 0; - spin_unlock_irq(&phba->hbalock); - - memset(&psli->lnk_stat_offsets, 0, sizeof(psli->lnk_stat_offsets)); - psli->stats_start = get_seconds(); - - /* Reset HBA AER if it was enabled, note hba_flag was reset above */ - if (hba_aer_enabled) - pci_disable_pcie_error_reporting(phba->pcidev); - - lpfc_hba_down_post(phba); - - return 0; -} - -/** - * lpfc_sli_brdrestart - Wrapper func for restarting hba - * @phba: Pointer to HBA context object. - * - * This routine wraps the actual SLI3 or SLI4 hba restart routine from the - * API jump table function pointer from the lpfc_hba struct. -**/ -int -lpfc_sli_brdrestart(struct lpfc_hba *phba) -{ - return phba->lpfc_sli_brdrestart(phba); -} - -/** - * lpfc_sli_chipset_init - Wait for the restart of the HBA after a restart - * @phba: Pointer to HBA context object. - * - * This function is called after a HBA restart to wait for successful - * restart of the HBA. Successful restart of the HBA is indicated by - * HS_FFRDY and HS_MBRDY bits. If the HBA fails to restart even after 15 - * iteration, the function will restart the HBA again. The function returns - * zero if HBA successfully restarted else returns negative error code. - **/ -static int -lpfc_sli_chipset_init(struct lpfc_hba *phba) -{ - uint32_t status, i = 0; - - /* Read the HBA Host Status Register */ - if (lpfc_readl(phba->HSregaddr, &status)) - return -EIO; - - /* Check status register to see what current state is */ - i = 0; - while ((status & (HS_FFRDY | HS_MBRDY)) != (HS_FFRDY | HS_MBRDY)) { - - /* Check every 10ms for 10 retries, then every 100ms for 90 - * retries, then every 1 sec for 50 retires for a total of - * ~60 seconds before reset the board again and check every - * 1 sec for 50 retries. The up to 60 seconds before the - * board ready is required by the Falcon FIPS zeroization - * complete, and any reset the board in between shall cause - * restart of zeroization, further delay the board ready. - */ - if (i++ >= 200) { - /* Adapter failed to init, timeout, status reg - */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0436 Adapter failed to init, " - "timeout, status reg x%x, " - "FW Data: A8 x%x AC x%x\n", status, - readl(phba->MBslimaddr + 0xa8), - readl(phba->MBslimaddr + 0xac)); - phba->link_state = LPFC_HBA_ERROR; - return -ETIMEDOUT; - } - - /* Check to see if any errors occurred during init */ - if (status & HS_FFERM) { - /* ERROR: During chipset initialization */ - /* Adapter failed to init, chipset, status reg - */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0437 Adapter failed to init, " - "chipset, status reg x%x, " - "FW Data: A8 x%x AC x%x\n", status, - readl(phba->MBslimaddr + 0xa8), - readl(phba->MBslimaddr + 0xac)); - phba->link_state = LPFC_HBA_ERROR; - return -EIO; - } - - if (i <= 10) - msleep(10); - else if (i <= 100) - msleep(100); - else - msleep(1000); - - if (i == 150) { - /* Do post */ - phba->pport->port_state = LPFC_VPORT_UNKNOWN; - lpfc_sli_brdrestart(phba); - } - /* Read the HBA Host Status Register */ - if (lpfc_readl(phba->HSregaddr, &status)) - return -EIO; - } - - /* Check to see if any errors occurred during init */ - if (status & HS_FFERM) { - /* ERROR: During chipset initialization */ - /* Adapter failed to init, chipset, status reg */ - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0438 Adapter failed to init, chipset, " - "status reg x%x, " - "FW Data: A8 x%x AC x%x\n", status, - readl(phba->MBslimaddr + 0xa8), - readl(phba->MBslimaddr + 0xac)); - phba->link_state = LPFC_HBA_ERROR; - return -EIO; - } - - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - - /* setup host attn register */ - writel(0xffffffff, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - return 0; -} - -/** - * lpfc_sli_hbq_count - Get the number of HBQs to be configured - * - * This function calculates and returns the number of HBQs required to be - * configured. - **/ -int -lpfc_sli_hbq_count(void) -{ - return ARRAY_SIZE(lpfc_hbq_defs); -} - -/** - * lpfc_sli_hbq_entry_count - Calculate total number of hbq entries - * - * This function adds the number of hbq entries in every HBQ to get - * the total number of hbq entries required for the HBA and returns - * the total count. - **/ -static int -lpfc_sli_hbq_entry_count(void) -{ - int hbq_count = lpfc_sli_hbq_count(); - int count = 0; - int i; - - for (i = 0; i < hbq_count; ++i) - count += lpfc_hbq_defs[i]->entry_count; - return count; -} - -/** - * lpfc_sli_hbq_size - Calculate memory required for all hbq entries - * - * This function calculates amount of memory required for all hbq entries - * to be configured and returns the total memory required. - **/ -int -lpfc_sli_hbq_size(void) -{ - return lpfc_sli_hbq_entry_count() * sizeof(struct lpfc_hbq_entry); -} - -/** - * lpfc_sli_hbq_setup - configure and initialize HBQs - * @phba: Pointer to HBA context object. - * - * This function is called during the SLI initialization to configure - * all the HBQs and post buffers to the HBQ. The caller is not - * required to hold any locks. This function will return zero if successful - * else it will return negative error code. - **/ -static int -lpfc_sli_hbq_setup(struct lpfc_hba *phba) -{ - int hbq_count = lpfc_sli_hbq_count(); - LPFC_MBOXQ_t *pmb; - MAILBOX_t *pmbox; - uint32_t hbqno; - uint32_t hbq_entry_index; - - /* Get a Mailbox buffer to setup mailbox - * commands for HBA initialization - */ - pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - - if (!pmb) - return -ENOMEM; - - pmbox = &pmb->u.mb; - - /* Initialize the struct lpfc_sli_hbq structure for each hbq */ - phba->link_state = LPFC_INIT_MBX_CMDS; - phba->hbq_in_use = 1; - - hbq_entry_index = 0; - for (hbqno = 0; hbqno < hbq_count; ++hbqno) { - phba->hbqs[hbqno].next_hbqPutIdx = 0; - phba->hbqs[hbqno].hbqPutIdx = 0; - phba->hbqs[hbqno].local_hbqGetIdx = 0; - phba->hbqs[hbqno].entry_count = - lpfc_hbq_defs[hbqno]->entry_count; - lpfc_config_hbq(phba, hbqno, lpfc_hbq_defs[hbqno], - hbq_entry_index, pmb); - hbq_entry_index += phba->hbqs[hbqno].entry_count; - - if (lpfc_sli_issue_mbox(phba, pmb, MBX_POLL) != MBX_SUCCESS) { - /* Adapter failed to init, mbxCmd CFG_RING, - mbxStatus , ring */ - - lpfc_printf_log(phba, KERN_ERR, - LOG_SLI | LOG_VPORT, - "1805 Adapter failed to init. " - "Data: x%x x%x x%x\n", - pmbox->mbxCommand, - pmbox->mbxStatus, hbqno); - - phba->link_state = LPFC_HBA_ERROR; - mempool_free(pmb, phba->mbox_mem_pool); - return -ENXIO; - } - } - phba->hbq_count = hbq_count; - - mempool_free(pmb, phba->mbox_mem_pool); - - /* Initially populate or replenish the HBQs */ - for (hbqno = 0; hbqno < hbq_count; ++hbqno) - lpfc_sli_hbqbuf_init_hbqs(phba, hbqno); - return 0; -} - -/** - * lpfc_sli4_rb_setup - Initialize and post RBs to HBA - * @phba: Pointer to HBA context object. - * - * This function is called during the SLI initialization to configure - * all the HBQs and post buffers to the HBQ. The caller is not - * required to hold any locks. This function will return zero if successful - * else it will return negative error code. - **/ -static int -lpfc_sli4_rb_setup(struct lpfc_hba *phba) -{ - phba->hbq_in_use = 1; - phba->hbqs[0].entry_count = lpfc_hbq_defs[0]->entry_count; - phba->hbq_count = 1; - /* Initially populate or replenish the HBQs */ - lpfc_sli_hbqbuf_init_hbqs(phba, 0); - return 0; -} - -/** - * lpfc_sli_config_port - Issue config port mailbox command - * @phba: Pointer to HBA context object. - * @sli_mode: sli mode - 2/3 - * - * This function is called by the sli intialization code path - * to issue config_port mailbox command. This function restarts the - * HBA firmware and issues a config_port mailbox command to configure - * the SLI interface in the sli mode specified by sli_mode - * variable. The caller is not required to hold any locks. - * The function returns 0 if successful, else returns negative error - * code. - **/ -int -lpfc_sli_config_port(struct lpfc_hba *phba, int sli_mode) -{ - LPFC_MBOXQ_t *pmb; - uint32_t resetcount = 0, rc = 0, done = 0; - - pmb = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - phba->link_state = LPFC_HBA_ERROR; - return -ENOMEM; - } - - phba->sli_rev = sli_mode; - while (resetcount < 2 && !done) { - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag |= LPFC_SLI_MBOX_ACTIVE; - spin_unlock_irq(&phba->hbalock); - phba->pport->port_state = LPFC_VPORT_UNKNOWN; - lpfc_sli_brdrestart(phba); - rc = lpfc_sli_chipset_init(phba); - if (rc) - break; - - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock_irq(&phba->hbalock); - resetcount++; - - /* Call pre CONFIG_PORT mailbox command initialization. A - * value of 0 means the call was successful. Any other - * nonzero value is a failure, but if ERESTART is returned, - * the driver may reset the HBA and try again. - */ - rc = lpfc_config_port_prep(phba); - if (rc == -ERESTART) { - phba->link_state = LPFC_LINK_UNKNOWN; - continue; - } else if (rc) - break; - - phba->link_state = LPFC_INIT_MBX_CMDS; - lpfc_config_port(phba, pmb); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - phba->sli3_options &= ~(LPFC_SLI3_NPIV_ENABLED | - LPFC_SLI3_HBQ_ENABLED | - LPFC_SLI3_CRP_ENABLED | - LPFC_SLI3_BG_ENABLED | - LPFC_SLI3_DSS_ENABLED); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0442 Adapter failed to init, mbxCmd x%x " - "CONFIG_PORT, mbxStatus x%x Data: x%x\n", - pmb->u.mb.mbxCommand, pmb->u.mb.mbxStatus, 0); - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - rc = -ENXIO; - } else { - /* Allow asynchronous mailbox command to go through */ - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; - spin_unlock_irq(&phba->hbalock); - done = 1; - - if ((pmb->u.mb.un.varCfgPort.casabt == 1) && - (pmb->u.mb.un.varCfgPort.gasabt == 0)) - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "3110 Port did not grant ASABT\n"); - } - } - if (!done) { - rc = -EINVAL; - goto do_prep_failed; - } - if (pmb->u.mb.un.varCfgPort.sli_mode == 3) { - if (!pmb->u.mb.un.varCfgPort.cMA) { - rc = -ENXIO; - goto do_prep_failed; - } - if (phba->max_vpi && pmb->u.mb.un.varCfgPort.gmv) { - phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; - phba->max_vpi = pmb->u.mb.un.varCfgPort.max_vpi; - phba->max_vports = (phba->max_vpi > phba->max_vports) ? - phba->max_vpi : phba->max_vports; - - } else - phba->max_vpi = 0; - phba->fips_level = 0; - phba->fips_spec_rev = 0; - if (pmb->u.mb.un.varCfgPort.gdss) { - phba->sli3_options |= LPFC_SLI3_DSS_ENABLED; - phba->fips_level = pmb->u.mb.un.varCfgPort.fips_level; - phba->fips_spec_rev = pmb->u.mb.un.varCfgPort.fips_rev; - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2850 Security Crypto Active. FIPS x%d " - "(Spec Rev: x%d)", - phba->fips_level, phba->fips_spec_rev); - } - if (pmb->u.mb.un.varCfgPort.sec_err) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2856 Config Port Security Crypto " - "Error: x%x ", - pmb->u.mb.un.varCfgPort.sec_err); - } - if (pmb->u.mb.un.varCfgPort.gerbm) - phba->sli3_options |= LPFC_SLI3_HBQ_ENABLED; - if (pmb->u.mb.un.varCfgPort.gcrp) - phba->sli3_options |= LPFC_SLI3_CRP_ENABLED; - - phba->hbq_get = phba->mbox->us.s3_pgp.hbq_get; - phba->port_gp = phba->mbox->us.s3_pgp.port; - - if (phba->cfg_enable_bg) { - if (pmb->u.mb.un.varCfgPort.gbg) - phba->sli3_options |= LPFC_SLI3_BG_ENABLED; - else - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0443 Adapter did not grant " - "BlockGuard\n"); - } - } else { - phba->hbq_get = NULL; - phba->port_gp = phba->mbox->us.s2.port; - phba->max_vpi = 0; - } -do_prep_failed: - mempool_free(pmb, phba->mbox_mem_pool); - return rc; -} - - -/** - * lpfc_sli_hba_setup - SLI intialization function - * @phba: Pointer to HBA context object. - * - * This function is the main SLI intialization function. This function - * is called by the HBA intialization code, HBA reset code and HBA - * error attention handler code. Caller is not required to hold any - * locks. This function issues config_port mailbox command to configure - * the SLI, setup iocb rings and HBQ rings. In the end the function - * calls the config_port_post function to issue init_link mailbox - * command and to start the discovery. The function will return zero - * if successful, else it will return negative error code. - **/ -int -lpfc_sli_hba_setup(struct lpfc_hba *phba) -{ - uint32_t rc; - int mode = 3, i; - int longs; - - switch (lpfc_sli_mode) { - case 2: - if (phba->cfg_enable_npiv) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, - "1824 NPIV enabled: Override lpfc_sli_mode " - "parameter (%d) to auto (0).\n", - lpfc_sli_mode); - break; - } - mode = 2; - break; - case 0: - case 3: - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, - "1819 Unrecognized lpfc_sli_mode " - "parameter: %d.\n", lpfc_sli_mode); - - break; - } - - rc = lpfc_sli_config_port(phba, mode); - - if (rc && lpfc_sli_mode == 3) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_VPORT, - "1820 Unable to select SLI-3. " - "Not supported by adapter.\n"); - if (rc && mode != 2) - rc = lpfc_sli_config_port(phba, 2); - if (rc) - goto lpfc_sli_hba_setup_error; - - /* Enable PCIe device Advanced Error Reporting (AER) if configured */ - if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) { - rc = pci_enable_pcie_error_reporting(phba->pcidev); - if (!rc) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2709 This device supports " - "Advanced Error Reporting (AER)\n"); - spin_lock_irq(&phba->hbalock); - phba->hba_flag |= HBA_AER_ENABLED; - spin_unlock_irq(&phba->hbalock); - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2708 This device does not support " - "Advanced Error Reporting (AER)\n"); - phba->cfg_aer_support = 0; - } - } - - if (phba->sli_rev == 3) { - phba->iocb_cmd_size = SLI3_IOCB_CMD_SIZE; - phba->iocb_rsp_size = SLI3_IOCB_RSP_SIZE; - } else { - phba->iocb_cmd_size = SLI2_IOCB_CMD_SIZE; - phba->iocb_rsp_size = SLI2_IOCB_RSP_SIZE; - phba->sli3_options = 0; - } - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "0444 Firmware in SLI %x mode. Max_vpi %d\n", - phba->sli_rev, phba->max_vpi); - rc = lpfc_sli_ring_map(phba); - - if (rc) - goto lpfc_sli_hba_setup_error; - - /* Initialize VPIs. */ - if (phba->sli_rev == LPFC_SLI_REV3) { - /* - * The VPI bitmask and physical ID array are allocated - * and initialized once only - at driver load. A port - * reset doesn't need to reinitialize this memory. - */ - if ((phba->vpi_bmask == NULL) && (phba->vpi_ids == NULL)) { - longs = (phba->max_vpi + BITS_PER_LONG) / BITS_PER_LONG; - phba->vpi_bmask = kzalloc(longs * sizeof(unsigned long), - GFP_KERNEL); - if (!phba->vpi_bmask) { - rc = -ENOMEM; - goto lpfc_sli_hba_setup_error; - } - - phba->vpi_ids = kzalloc( - (phba->max_vpi+1) * sizeof(uint16_t), - GFP_KERNEL); - if (!phba->vpi_ids) { - kfree(phba->vpi_bmask); - rc = -ENOMEM; - goto lpfc_sli_hba_setup_error; - } - for (i = 0; i < phba->max_vpi; i++) - phba->vpi_ids[i] = i; - } - } - - /* Init HBQs */ - if (phba->sli3_options & LPFC_SLI3_HBQ_ENABLED) { - rc = lpfc_sli_hbq_setup(phba); - if (rc) - goto lpfc_sli_hba_setup_error; - } - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag |= LPFC_PROCESS_LA; - spin_unlock_irq(&phba->hbalock); - - rc = lpfc_config_port_post(phba); - if (rc) - goto lpfc_sli_hba_setup_error; - - return rc; - -lpfc_sli_hba_setup_error: - phba->link_state = LPFC_HBA_ERROR; - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0445 Firmware initialization failed\n"); - return rc; -} - -/** - * lpfc_sli4_read_fcoe_params - Read fcoe params from conf region - * @phba: Pointer to HBA context object. - * @mboxq: mailbox pointer. - * This function issue a dump mailbox command to read config region - * 23 and parse the records in the region and populate driver - * data structure. - **/ -static int -lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *mboxq; - struct lpfc_dmabuf *mp; - struct lpfc_mqe *mqe; - uint32_t data_length; - int rc; - - /* Program the default value of vlan_id and fc_map */ - phba->valid_vlan = 0; - phba->fc_map[0] = LPFC_FCOE_FCF_MAP0; - phba->fc_map[1] = LPFC_FCOE_FCF_MAP1; - phba->fc_map[2] = LPFC_FCOE_FCF_MAP2; - - mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) - return -ENOMEM; - - mqe = &mboxq->u.mqe; - if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) { - rc = -ENOMEM; - goto out_free_mboxq; - } - - mp = (struct lpfc_dmabuf *) mboxq->context1; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):2571 Mailbox cmd x%x Status x%x " - "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x " - "x%x x%x x%x x%x x%x x%x x%x x%x x%x " - "CQ: x%x x%x x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - bf_get(lpfc_mqe_command, mqe), - bf_get(lpfc_mqe_status, mqe), - mqe->un.mb_words[0], mqe->un.mb_words[1], - mqe->un.mb_words[2], mqe->un.mb_words[3], - mqe->un.mb_words[4], mqe->un.mb_words[5], - mqe->un.mb_words[6], mqe->un.mb_words[7], - mqe->un.mb_words[8], mqe->un.mb_words[9], - mqe->un.mb_words[10], mqe->un.mb_words[11], - mqe->un.mb_words[12], mqe->un.mb_words[13], - mqe->un.mb_words[14], mqe->un.mb_words[15], - mqe->un.mb_words[16], mqe->un.mb_words[50], - mboxq->mcqe.word0, - mboxq->mcqe.mcqe_tag0, mboxq->mcqe.mcqe_tag1, - mboxq->mcqe.trailer); - - if (rc) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - rc = -EIO; - goto out_free_mboxq; - } - data_length = mqe->un.mb_words[5]; - if (data_length > DMP_RGN23_SIZE) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - rc = -EIO; - goto out_free_mboxq; - } - - lpfc_parse_fcoe_conf(phba, mp->virt, data_length); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - rc = 0; - -out_free_mboxq: - mempool_free(mboxq, phba->mbox_mem_pool); - return rc; -} - -/** - * lpfc_sli4_read_rev - Issue READ_REV and collect vpd data - * @phba: pointer to lpfc hba data structure. - * @mboxq: pointer to the LPFC_MBOXQ_t structure. - * @vpd: pointer to the memory to hold resulting port vpd data. - * @vpd_size: On input, the number of bytes allocated to @vpd. - * On output, the number of data bytes in @vpd. - * - * This routine executes a READ_REV SLI4 mailbox command. In - * addition, this routine gets the port vpd data. - * - * Return codes - * 0 - successful - * -ENOMEM - could not allocated memory. - **/ -static int -lpfc_sli4_read_rev(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, - uint8_t *vpd, uint32_t *vpd_size) -{ - int rc = 0; - uint32_t dma_size; - struct lpfc_dmabuf *dmabuf; - struct lpfc_mqe *mqe; - - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!dmabuf) - return -ENOMEM; - - /* - * Get a DMA buffer for the vpd data resulting from the READ_REV - * mailbox command. - */ - dma_size = *vpd_size; - dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, - dma_size, - &dmabuf->phys, - GFP_KERNEL); - if (!dmabuf->virt) { - kfree(dmabuf); - return -ENOMEM; - } - memset(dmabuf->virt, 0, dma_size); - - /* - * The SLI4 implementation of READ_REV conflicts at word1, - * bits 31:16 and SLI4 adds vpd functionality not present - * in SLI3. This code corrects the conflicts. - */ - lpfc_read_rev(phba, mboxq); - mqe = &mboxq->u.mqe; - mqe->un.read_rev.vpd_paddr_high = putPaddrHigh(dmabuf->phys); - mqe->un.read_rev.vpd_paddr_low = putPaddrLow(dmabuf->phys); - mqe->un.read_rev.word1 &= 0x0000FFFF; - bf_set(lpfc_mbx_rd_rev_vpd, &mqe->un.read_rev, 1); - bf_set(lpfc_mbx_rd_rev_avail_len, &mqe->un.read_rev, dma_size); - - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc) { - dma_free_coherent(&phba->pcidev->dev, dma_size, - dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - return -EIO; - } - - /* - * The available vpd length cannot be bigger than the - * DMA buffer passed to the port. Catch the less than - * case and update the caller's size. - */ - if (mqe->un.read_rev.avail_vpd_len < *vpd_size) - *vpd_size = mqe->un.read_rev.avail_vpd_len; - - memcpy(vpd, dmabuf->virt, *vpd_size); - - dma_free_coherent(&phba->pcidev->dev, dma_size, - dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - return 0; -} - -/** - * lpfc_sli4_retrieve_pport_name - Retrieve SLI4 device physical port name - * @phba: pointer to lpfc hba data structure. - * - * This routine retrieves SLI4 device physical port name this PCI function - * is attached to. - * - * Return codes - * 0 - sucessful - * otherwise - failed to retrieve physical port name - **/ -static int -lpfc_sli4_retrieve_pport_name(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *mboxq; - struct lpfc_mbx_get_cntl_attributes *mbx_cntl_attr; - struct lpfc_controller_attribute *cntl_attr; - struct lpfc_mbx_get_port_name *get_port_name; - void *virtaddr = NULL; - uint32_t alloclen, reqlen; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - char cport_name = 0; - int rc; - - /* We assume nothing at this point */ - phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; - phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_NON; - - mboxq = (LPFC_MBOXQ_t *)mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) - return -ENOMEM; - /* obtain link type and link number via READ_CONFIG */ - phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_INVAL; - lpfc_sli4_read_config(phba); - if (phba->sli4_hba.lnk_info.lnk_dv == LPFC_LNK_DAT_VAL) - goto retrieve_ppname; - - /* obtain link type and link number via COMMON_GET_CNTL_ATTRIBUTES */ - reqlen = sizeof(struct lpfc_mbx_get_cntl_attributes); - alloclen = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_GET_CNTL_ATTRIBUTES, reqlen, - LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3084 Allocated DMA memory size (%d) is " - "less than the requested DMA memory size " - "(%d)\n", alloclen, reqlen); - rc = -ENOMEM; - goto out_free_mboxq; - } - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - virtaddr = mboxq->sge_array->addr[0]; - mbx_cntl_attr = (struct lpfc_mbx_get_cntl_attributes *)virtaddr; - shdr = &mbx_cntl_attr->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3085 Mailbox x%x (x%x/x%x) failed, " - "rc:x%x, status:x%x, add_status:x%x\n", - bf_get(lpfc_mqe_command, &mboxq->u.mqe), - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - rc, shdr_status, shdr_add_status); - rc = -ENXIO; - goto out_free_mboxq; - } - cntl_attr = &mbx_cntl_attr->cntl_attr; - phba->sli4_hba.lnk_info.lnk_dv = LPFC_LNK_DAT_VAL; - phba->sli4_hba.lnk_info.lnk_tp = - bf_get(lpfc_cntl_attr_lnk_type, cntl_attr); - phba->sli4_hba.lnk_info.lnk_no = - bf_get(lpfc_cntl_attr_lnk_numb, cntl_attr); - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3086 lnk_type:%d, lnk_numb:%d\n", - phba->sli4_hba.lnk_info.lnk_tp, - phba->sli4_hba.lnk_info.lnk_no); - -retrieve_ppname: - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_GET_PORT_NAME, - sizeof(struct lpfc_mbx_get_port_name) - - sizeof(struct lpfc_sli4_cfg_mhdr), - LPFC_SLI4_MBX_EMBED); - get_port_name = &mboxq->u.mqe.un.get_port_name; - shdr = (union lpfc_sli4_cfg_shdr *)&get_port_name->header.cfg_shdr; - bf_set(lpfc_mbox_hdr_version, &shdr->request, LPFC_OPCODE_VERSION_1); - bf_set(lpfc_mbx_get_port_name_lnk_type, &get_port_name->u.request, - phba->sli4_hba.lnk_info.lnk_tp); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3087 Mailbox x%x (x%x/x%x) failed: " - "rc:x%x, status:x%x, add_status:x%x\n", - bf_get(lpfc_mqe_command, &mboxq->u.mqe), - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - rc, shdr_status, shdr_add_status); - rc = -ENXIO; - goto out_free_mboxq; - } - switch (phba->sli4_hba.lnk_info.lnk_no) { - case LPFC_LINK_NUMBER_0: - cport_name = bf_get(lpfc_mbx_get_port_name_name0, - &get_port_name->u.response); - phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_GET; - break; - case LPFC_LINK_NUMBER_1: - cport_name = bf_get(lpfc_mbx_get_port_name_name1, - &get_port_name->u.response); - phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_GET; - break; - case LPFC_LINK_NUMBER_2: - cport_name = bf_get(lpfc_mbx_get_port_name_name2, - &get_port_name->u.response); - phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_GET; - break; - case LPFC_LINK_NUMBER_3: - cport_name = bf_get(lpfc_mbx_get_port_name_name3, - &get_port_name->u.response); - phba->sli4_hba.pport_name_sta = LPFC_SLI4_PPNAME_GET; - break; - default: - break; - } - - if (phba->sli4_hba.pport_name_sta == LPFC_SLI4_PPNAME_GET) { - phba->Port[0] = cport_name; - phba->Port[1] = '\0'; - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3091 SLI get port name: %s\n", phba->Port); - } - -out_free_mboxq: - if (rc != MBX_TIMEOUT) { - if (bf_get(lpfc_mqe_command, &mboxq->u.mqe) == MBX_SLI4_CONFIG) - lpfc_sli4_mbox_cmd_free(phba, mboxq); - else - mempool_free(mboxq, phba->mbox_mem_pool); - } - return rc; -} - -/** - * lpfc_sli4_arm_cqeq_intr - Arm sli-4 device completion and event queues - * @phba: pointer to lpfc hba data structure. - * - * This routine is called to explicitly arm the SLI4 device's completion and - * event queues - **/ -static void -lpfc_sli4_arm_cqeq_intr(struct lpfc_hba *phba) -{ - uint8_t fcp_eqidx; - - lpfc_sli4_cq_release(phba->sli4_hba.mbx_cq, LPFC_QUEUE_REARM); - lpfc_sli4_cq_release(phba->sli4_hba.els_cq, LPFC_QUEUE_REARM); - fcp_eqidx = 0; - if (phba->sli4_hba.fcp_cq) { - do - lpfc_sli4_cq_release(phba->sli4_hba.fcp_cq[fcp_eqidx], - LPFC_QUEUE_REARM); - while (++fcp_eqidx < phba->cfg_fcp_eq_count); - } - lpfc_sli4_eq_release(phba->sli4_hba.sp_eq, LPFC_QUEUE_REARM); - if (phba->sli4_hba.fp_eq) { - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; - fcp_eqidx++) - lpfc_sli4_eq_release(phba->sli4_hba.fp_eq[fcp_eqidx], - LPFC_QUEUE_REARM); - } -} - -/** - * lpfc_sli4_get_avail_extnt_rsrc - Get available resource extent count. - * @phba: Pointer to HBA context object. - * @type: The resource extent type. - * @extnt_count: buffer to hold port available extent count. - * @extnt_size: buffer to hold element count per extent. - * - * This function calls the port and retrievs the number of available - * extents and their size for a particular extent type. - * - * Returns: 0 if successful. Nonzero otherwise. - **/ -int -lpfc_sli4_get_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type, - uint16_t *extnt_count, uint16_t *extnt_size) -{ - int rc = 0; - uint32_t length; - uint32_t mbox_tmo; - struct lpfc_mbx_get_rsrc_extent_info *rsrc_info; - LPFC_MBOXQ_t *mbox; - - mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - - /* Find out how many extents are available for this resource type */ - length = (sizeof(struct lpfc_mbx_get_rsrc_extent_info) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_GET_RSRC_EXTENT_INFO, - length, LPFC_SLI4_MBX_EMBED); - - /* Send an extents count of 0 - the GET doesn't use it. */ - rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, 0, type, - LPFC_SLI4_MBX_EMBED); - if (unlikely(rc)) { - rc = -EIO; - goto err_exit; - } - - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - if (unlikely(rc)) { - rc = -EIO; - goto err_exit; - } - - rsrc_info = &mbox->u.mqe.un.rsrc_extent_info; - if (bf_get(lpfc_mbox_hdr_status, - &rsrc_info->header.cfg_shdr.response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, - "2930 Failed to get resource extents " - "Status 0x%x Add'l Status 0x%x\n", - bf_get(lpfc_mbox_hdr_status, - &rsrc_info->header.cfg_shdr.response), - bf_get(lpfc_mbox_hdr_add_status, - &rsrc_info->header.cfg_shdr.response)); - rc = -EIO; - goto err_exit; - } - - *extnt_count = bf_get(lpfc_mbx_get_rsrc_extent_info_cnt, - &rsrc_info->u.rsp); - *extnt_size = bf_get(lpfc_mbx_get_rsrc_extent_info_size, - &rsrc_info->u.rsp); - err_exit: - mempool_free(mbox, phba->mbox_mem_pool); - return rc; -} - -/** - * lpfc_sli4_chk_avail_extnt_rsrc - Check for available SLI4 resource extents. - * @phba: Pointer to HBA context object. - * @type: The extent type to check. - * - * This function reads the current available extents from the port and checks - * if the extent count or extent size has changed since the last access. - * Callers use this routine post port reset to understand if there is a - * extent reprovisioning requirement. - * - * Returns: - * -Error: error indicates problem. - * 1: Extent count or size has changed. - * 0: No changes. - **/ -static int -lpfc_sli4_chk_avail_extnt_rsrc(struct lpfc_hba *phba, uint16_t type) -{ - uint16_t curr_ext_cnt, rsrc_ext_cnt; - uint16_t size_diff, rsrc_ext_size; - int rc = 0; - struct lpfc_rsrc_blks *rsrc_entry; - struct list_head *rsrc_blk_list = NULL; - - size_diff = 0; - curr_ext_cnt = 0; - rc = lpfc_sli4_get_avail_extnt_rsrc(phba, type, - &rsrc_ext_cnt, - &rsrc_ext_size); - if (unlikely(rc)) - return -EIO; - - switch (type) { - case LPFC_RSC_TYPE_FCOE_RPI: - rsrc_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_VPI: - rsrc_blk_list = &phba->lpfc_vpi_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_XRI: - rsrc_blk_list = &phba->sli4_hba.lpfc_xri_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_VFI: - rsrc_blk_list = &phba->sli4_hba.lpfc_vfi_blk_list; - break; - default: - break; - } - - list_for_each_entry(rsrc_entry, rsrc_blk_list, list) { - curr_ext_cnt++; - if (rsrc_entry->rsrc_size != rsrc_ext_size) - size_diff++; - } - - if (curr_ext_cnt != rsrc_ext_cnt || size_diff != 0) - rc = 1; - - return rc; -} - -/** - * lpfc_sli4_cfg_post_extnts - - * @phba: Pointer to HBA context object. - * @extnt_cnt - number of available extents. - * @type - the extent type (rpi, xri, vfi, vpi). - * @emb - buffer to hold either MBX_EMBED or MBX_NEMBED operation. - * @mbox - pointer to the caller's allocated mailbox structure. - * - * This function executes the extents allocation request. It also - * takes care of the amount of memory needed to allocate or get the - * allocated extents. It is the caller's responsibility to evaluate - * the response. - * - * Returns: - * -Error: Error value describes the condition found. - * 0: if successful - **/ -static int -lpfc_sli4_cfg_post_extnts(struct lpfc_hba *phba, uint16_t *extnt_cnt, - uint16_t type, bool *emb, LPFC_MBOXQ_t *mbox) -{ - int rc = 0; - uint32_t req_len; - uint32_t emb_len; - uint32_t alloc_len, mbox_tmo; - - /* Calculate the total requested length of the dma memory */ - req_len = *extnt_cnt * sizeof(uint16_t); - - /* - * Calculate the size of an embedded mailbox. The uint32_t - * accounts for extents-specific word. - */ - emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) - - sizeof(uint32_t); - - /* - * Presume the allocation and response will fit into an embedded - * mailbox. If not true, reconfigure to a non-embedded mailbox. - */ - *emb = LPFC_SLI4_MBX_EMBED; - if (req_len > emb_len) { - req_len = *extnt_cnt * sizeof(uint16_t) + - sizeof(union lpfc_sli4_cfg_shdr) + - sizeof(uint32_t); - *emb = LPFC_SLI4_MBX_NEMBED; - } - - alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_ALLOC_RSRC_EXTENT, - req_len, *emb); - if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2982 Allocated DMA memory size (x%x) is " - "less than the requested DMA memory " - "size (x%x)\n", alloc_len, req_len); - return -ENOMEM; - } - rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, *extnt_cnt, type, *emb); - if (unlikely(rc)) - return -EIO; - - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - - if (unlikely(rc)) - rc = -EIO; - return rc; -} - -/** - * lpfc_sli4_alloc_extent - Allocate an SLI4 resource extent. - * @phba: Pointer to HBA context object. - * @type: The resource extent type to allocate. - * - * This function allocates the number of elements for the specified - * resource type. - **/ -static int -lpfc_sli4_alloc_extent(struct lpfc_hba *phba, uint16_t type) -{ - bool emb = false; - uint16_t rsrc_id_cnt, rsrc_cnt, rsrc_size; - uint16_t rsrc_id, rsrc_start, j, k; - uint16_t *ids; - int i, rc; - unsigned long longs; - unsigned long *bmask; - struct lpfc_rsrc_blks *rsrc_blks; - LPFC_MBOXQ_t *mbox; - uint32_t length; - struct lpfc_id_range *id_array = NULL; - void *virtaddr = NULL; - struct lpfc_mbx_nembed_rsrc_extent *n_rsrc; - struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext; - struct list_head *ext_blk_list; - - rc = lpfc_sli4_get_avail_extnt_rsrc(phba, type, - &rsrc_cnt, - &rsrc_size); - if (unlikely(rc)) - return -EIO; - - if ((rsrc_cnt == 0) || (rsrc_size == 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, - "3009 No available Resource Extents " - "for resource type 0x%x: Count: 0x%x, " - "Size 0x%x\n", type, rsrc_cnt, - rsrc_size); - return -ENOMEM; - } - - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_INIT, - "2903 Available Resource Extents " - "for resource type 0x%x: Count: 0x%x, " - "Size 0x%x\n", type, rsrc_cnt, - rsrc_size); - - mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - - rc = lpfc_sli4_cfg_post_extnts(phba, &rsrc_cnt, type, &emb, mbox); - if (unlikely(rc)) { - rc = -EIO; - goto err_exit; - } - - /* - * Figure out where the response is located. Then get local pointers - * to the response data. The port does not guarantee to respond to - * all extents counts request so update the local variable with the - * allocated count from the port. - */ - if (emb == LPFC_SLI4_MBX_EMBED) { - rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents; - id_array = &rsrc_ext->u.rsp.id[0]; - rsrc_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp); - } else { - virtaddr = mbox->sge_array->addr[0]; - n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr; - rsrc_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc); - id_array = &n_rsrc->id; - } - - longs = ((rsrc_cnt * rsrc_size) + BITS_PER_LONG - 1) / BITS_PER_LONG; - rsrc_id_cnt = rsrc_cnt * rsrc_size; - - /* - * Based on the resource size and count, correct the base and max - * resource values. - */ - length = sizeof(struct lpfc_rsrc_blks); - switch (type) { - case LPFC_RSC_TYPE_FCOE_RPI: - phba->sli4_hba.rpi_bmask = kzalloc(longs * - sizeof(unsigned long), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.rpi_bmask)) { - rc = -ENOMEM; - goto err_exit; - } - phba->sli4_hba.rpi_ids = kzalloc(rsrc_id_cnt * - sizeof(uint16_t), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.rpi_ids)) { - kfree(phba->sli4_hba.rpi_bmask); - rc = -ENOMEM; - goto err_exit; - } - - /* - * The next_rpi was initialized with the maximum available - * count but the port may allocate a smaller number. Catch - * that case and update the next_rpi. - */ - phba->sli4_hba.next_rpi = rsrc_id_cnt; - - /* Initialize local ptrs for common extent processing later. */ - bmask = phba->sli4_hba.rpi_bmask; - ids = phba->sli4_hba.rpi_ids; - ext_blk_list = &phba->sli4_hba.lpfc_rpi_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_VPI: - phba->vpi_bmask = kzalloc(longs * - sizeof(unsigned long), - GFP_KERNEL); - if (unlikely(!phba->vpi_bmask)) { - rc = -ENOMEM; - goto err_exit; - } - phba->vpi_ids = kzalloc(rsrc_id_cnt * - sizeof(uint16_t), - GFP_KERNEL); - if (unlikely(!phba->vpi_ids)) { - kfree(phba->vpi_bmask); - rc = -ENOMEM; - goto err_exit; - } - - /* Initialize local ptrs for common extent processing later. */ - bmask = phba->vpi_bmask; - ids = phba->vpi_ids; - ext_blk_list = &phba->lpfc_vpi_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_XRI: - phba->sli4_hba.xri_bmask = kzalloc(longs * - sizeof(unsigned long), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.xri_bmask)) { - rc = -ENOMEM; - goto err_exit; - } - phba->sli4_hba.xri_ids = kzalloc(rsrc_id_cnt * - sizeof(uint16_t), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.xri_ids)) { - kfree(phba->sli4_hba.xri_bmask); - rc = -ENOMEM; - goto err_exit; - } - - /* Initialize local ptrs for common extent processing later. */ - bmask = phba->sli4_hba.xri_bmask; - ids = phba->sli4_hba.xri_ids; - ext_blk_list = &phba->sli4_hba.lpfc_xri_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_VFI: - phba->sli4_hba.vfi_bmask = kzalloc(longs * - sizeof(unsigned long), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.vfi_bmask)) { - rc = -ENOMEM; - goto err_exit; - } - phba->sli4_hba.vfi_ids = kzalloc(rsrc_id_cnt * - sizeof(uint16_t), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.vfi_ids)) { - kfree(phba->sli4_hba.vfi_bmask); - rc = -ENOMEM; - goto err_exit; - } - - /* Initialize local ptrs for common extent processing later. */ - bmask = phba->sli4_hba.vfi_bmask; - ids = phba->sli4_hba.vfi_ids; - ext_blk_list = &phba->sli4_hba.lpfc_vfi_blk_list; - break; - default: - /* Unsupported Opcode. Fail call. */ - id_array = NULL; - bmask = NULL; - ids = NULL; - ext_blk_list = NULL; - goto err_exit; - } - - /* - * Complete initializing the extent configuration with the - * allocated ids assigned to this function. The bitmask serves - * as an index into the array and manages the available ids. The - * array just stores the ids communicated to the port via the wqes. - */ - for (i = 0, j = 0, k = 0; i < rsrc_cnt; i++) { - if ((i % 2) == 0) - rsrc_id = bf_get(lpfc_mbx_rsrc_id_word4_0, - &id_array[k]); - else - rsrc_id = bf_get(lpfc_mbx_rsrc_id_word4_1, - &id_array[k]); - - rsrc_blks = kzalloc(length, GFP_KERNEL); - if (unlikely(!rsrc_blks)) { - rc = -ENOMEM; - kfree(bmask); - kfree(ids); - goto err_exit; - } - rsrc_blks->rsrc_start = rsrc_id; - rsrc_blks->rsrc_size = rsrc_size; - list_add_tail(&rsrc_blks->list, ext_blk_list); - rsrc_start = rsrc_id; - if ((type == LPFC_RSC_TYPE_FCOE_XRI) && (j == 0)) - phba->sli4_hba.scsi_xri_start = rsrc_start + - lpfc_sli4_get_els_iocb_cnt(phba); - - while (rsrc_id < (rsrc_start + rsrc_size)) { - ids[j] = rsrc_id; - rsrc_id++; - j++; - } - /* Entire word processed. Get next word.*/ - if ((i % 2) == 1) - k++; - } - err_exit: - lpfc_sli4_mbox_cmd_free(phba, mbox); - return rc; -} - -/** - * lpfc_sli4_dealloc_extent - Deallocate an SLI4 resource extent. - * @phba: Pointer to HBA context object. - * @type: the extent's type. - * - * This function deallocates all extents of a particular resource type. - * SLI4 does not allow for deallocating a particular extent range. It - * is the caller's responsibility to release all kernel memory resources. - **/ -static int -lpfc_sli4_dealloc_extent(struct lpfc_hba *phba, uint16_t type) -{ - int rc; - uint32_t length, mbox_tmo = 0; - LPFC_MBOXQ_t *mbox; - struct lpfc_mbx_dealloc_rsrc_extents *dealloc_rsrc; - struct lpfc_rsrc_blks *rsrc_blk, *rsrc_blk_next; - - mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - - /* - * This function sends an embedded mailbox because it only sends the - * the resource type. All extents of this type are released by the - * port. - */ - length = (sizeof(struct lpfc_mbx_dealloc_rsrc_extents) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_DEALLOC_RSRC_EXTENT, - length, LPFC_SLI4_MBX_EMBED); - - /* Send an extents count of 0 - the dealloc doesn't use it. */ - rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, 0, type, - LPFC_SLI4_MBX_EMBED); - if (unlikely(rc)) { - rc = -EIO; - goto out_free_mbox; - } - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - if (unlikely(rc)) { - rc = -EIO; - goto out_free_mbox; - } - - dealloc_rsrc = &mbox->u.mqe.un.dealloc_rsrc_extents; - if (bf_get(lpfc_mbox_hdr_status, - &dealloc_rsrc->header.cfg_shdr.response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, - "2919 Failed to release resource extents " - "for type %d - Status 0x%x Add'l Status 0x%x. " - "Resource memory not released.\n", - type, - bf_get(lpfc_mbox_hdr_status, - &dealloc_rsrc->header.cfg_shdr.response), - bf_get(lpfc_mbox_hdr_add_status, - &dealloc_rsrc->header.cfg_shdr.response)); - rc = -EIO; - goto out_free_mbox; - } - - /* Release kernel memory resources for the specific type. */ - switch (type) { - case LPFC_RSC_TYPE_FCOE_VPI: - kfree(phba->vpi_bmask); - kfree(phba->vpi_ids); - bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); - list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, - &phba->lpfc_vpi_blk_list, list) { - list_del_init(&rsrc_blk->list); - kfree(rsrc_blk); - } - break; - case LPFC_RSC_TYPE_FCOE_XRI: - kfree(phba->sli4_hba.xri_bmask); - kfree(phba->sli4_hba.xri_ids); - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); - list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, - &phba->sli4_hba.lpfc_xri_blk_list, list) { - list_del_init(&rsrc_blk->list); - kfree(rsrc_blk); - } - break; - case LPFC_RSC_TYPE_FCOE_VFI: - kfree(phba->sli4_hba.vfi_bmask); - kfree(phba->sli4_hba.vfi_ids); - bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); - list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, - &phba->sli4_hba.lpfc_vfi_blk_list, list) { - list_del_init(&rsrc_blk->list); - kfree(rsrc_blk); - } - break; - case LPFC_RSC_TYPE_FCOE_RPI: - /* RPI bitmask and physical id array are cleaned up earlier. */ - list_for_each_entry_safe(rsrc_blk, rsrc_blk_next, - &phba->sli4_hba.lpfc_rpi_blk_list, list) { - list_del_init(&rsrc_blk->list); - kfree(rsrc_blk); - } - break; - default: - break; - } - - bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); - - out_free_mbox: - mempool_free(mbox, phba->mbox_mem_pool); - return rc; -} - -/** - * lpfc_sli4_alloc_resource_identifiers - Allocate all SLI4 resource extents. - * @phba: Pointer to HBA context object. - * - * This function allocates all SLI4 resource identifiers. - **/ -int -lpfc_sli4_alloc_resource_identifiers(struct lpfc_hba *phba) -{ - int i, rc, error = 0; - uint16_t count, base; - unsigned long longs; - - if (!phba->sli4_hba.rpi_hdrs_in_use) - phba->sli4_hba.next_rpi = phba->sli4_hba.max_cfg_param.max_rpi; - if (phba->sli4_hba.extents_in_use) { - /* - * The port supports resource extents. The XRI, VPI, VFI, RPI - * resource extent count must be read and allocated before - * provisioning the resource id arrays. - */ - if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) == - LPFC_IDX_RSRC_RDY) { - /* - * Extent-based resources are set - the driver could - * be in a port reset. Figure out if any corrective - * actions need to be taken. - */ - rc = lpfc_sli4_chk_avail_extnt_rsrc(phba, - LPFC_RSC_TYPE_FCOE_VFI); - if (rc != 0) - error++; - rc = lpfc_sli4_chk_avail_extnt_rsrc(phba, - LPFC_RSC_TYPE_FCOE_VPI); - if (rc != 0) - error++; - rc = lpfc_sli4_chk_avail_extnt_rsrc(phba, - LPFC_RSC_TYPE_FCOE_XRI); - if (rc != 0) - error++; - rc = lpfc_sli4_chk_avail_extnt_rsrc(phba, - LPFC_RSC_TYPE_FCOE_RPI); - if (rc != 0) - error++; - - /* - * It's possible that the number of resources - * provided to this port instance changed between - * resets. Detect this condition and reallocate - * resources. Otherwise, there is no action. - */ - if (error) { - lpfc_printf_log(phba, KERN_INFO, - LOG_MBOX | LOG_INIT, - "2931 Detected extent resource " - "change. Reallocating all " - "extents.\n"); - rc = lpfc_sli4_dealloc_extent(phba, - LPFC_RSC_TYPE_FCOE_VFI); - rc = lpfc_sli4_dealloc_extent(phba, - LPFC_RSC_TYPE_FCOE_VPI); - rc = lpfc_sli4_dealloc_extent(phba, - LPFC_RSC_TYPE_FCOE_XRI); - rc = lpfc_sli4_dealloc_extent(phba, - LPFC_RSC_TYPE_FCOE_RPI); - } else - return 0; - } - - rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI); - if (unlikely(rc)) - goto err_exit; - - rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_VPI); - if (unlikely(rc)) - goto err_exit; - - rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_RPI); - if (unlikely(rc)) - goto err_exit; - - rc = lpfc_sli4_alloc_extent(phba, LPFC_RSC_TYPE_FCOE_XRI); - if (unlikely(rc)) - goto err_exit; - bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_IDX_RSRC_RDY); - return rc; - } else { - /* - * The port does not support resource extents. The XRI, VPI, - * VFI, RPI resource ids were determined from READ_CONFIG. - * Just allocate the bitmasks and provision the resource id - * arrays. If a port reset is active, the resources don't - * need any action - just exit. - */ - if (bf_get(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags) == - LPFC_IDX_RSRC_RDY) { - lpfc_sli4_dealloc_resource_identifiers(phba); - lpfc_sli4_remove_rpis(phba); - } - /* RPIs. */ - count = phba->sli4_hba.max_cfg_param.max_rpi; - base = phba->sli4_hba.max_cfg_param.rpi_base; - longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.rpi_bmask = kzalloc(longs * - sizeof(unsigned long), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.rpi_bmask)) { - rc = -ENOMEM; - goto err_exit; - } - phba->sli4_hba.rpi_ids = kzalloc(count * - sizeof(uint16_t), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.rpi_ids)) { - rc = -ENOMEM; - goto free_rpi_bmask; - } - - for (i = 0; i < count; i++) - phba->sli4_hba.rpi_ids[i] = base + i; - - /* VPIs. */ - count = phba->sli4_hba.max_cfg_param.max_vpi; - base = phba->sli4_hba.max_cfg_param.vpi_base; - longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->vpi_bmask = kzalloc(longs * - sizeof(unsigned long), - GFP_KERNEL); - if (unlikely(!phba->vpi_bmask)) { - rc = -ENOMEM; - goto free_rpi_ids; - } - phba->vpi_ids = kzalloc(count * - sizeof(uint16_t), - GFP_KERNEL); - if (unlikely(!phba->vpi_ids)) { - rc = -ENOMEM; - goto free_vpi_bmask; - } - - for (i = 0; i < count; i++) - phba->vpi_ids[i] = base + i; - - /* XRIs. */ - count = phba->sli4_hba.max_cfg_param.max_xri; - base = phba->sli4_hba.max_cfg_param.xri_base; - longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.xri_bmask = kzalloc(longs * - sizeof(unsigned long), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.xri_bmask)) { - rc = -ENOMEM; - goto free_vpi_ids; - } - phba->sli4_hba.max_cfg_param.xri_used = 0; - phba->sli4_hba.xri_count = 0; - phba->sli4_hba.xri_ids = kzalloc(count * - sizeof(uint16_t), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.xri_ids)) { - rc = -ENOMEM; - goto free_xri_bmask; - } - - for (i = 0; i < count; i++) - phba->sli4_hba.xri_ids[i] = base + i; - - /* VFIs. */ - count = phba->sli4_hba.max_cfg_param.max_vfi; - base = phba->sli4_hba.max_cfg_param.vfi_base; - longs = (count + BITS_PER_LONG - 1) / BITS_PER_LONG; - phba->sli4_hba.vfi_bmask = kzalloc(longs * - sizeof(unsigned long), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.vfi_bmask)) { - rc = -ENOMEM; - goto free_xri_ids; - } - phba->sli4_hba.vfi_ids = kzalloc(count * - sizeof(uint16_t), - GFP_KERNEL); - if (unlikely(!phba->sli4_hba.vfi_ids)) { - rc = -ENOMEM; - goto free_vfi_bmask; - } - - for (i = 0; i < count; i++) - phba->sli4_hba.vfi_ids[i] = base + i; - - /* - * Mark all resources ready. An HBA reset doesn't need - * to reset the initialization. - */ - bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_IDX_RSRC_RDY); - return 0; - } - - free_vfi_bmask: - kfree(phba->sli4_hba.vfi_bmask); - free_xri_ids: - kfree(phba->sli4_hba.xri_ids); - free_xri_bmask: - kfree(phba->sli4_hba.xri_bmask); - free_vpi_ids: - kfree(phba->vpi_ids); - free_vpi_bmask: - kfree(phba->vpi_bmask); - free_rpi_ids: - kfree(phba->sli4_hba.rpi_ids); - free_rpi_bmask: - kfree(phba->sli4_hba.rpi_bmask); - err_exit: - return rc; -} - -/** - * lpfc_sli4_dealloc_resource_identifiers - Deallocate all SLI4 resource extents. - * @phba: Pointer to HBA context object. - * - * This function allocates the number of elements for the specified - * resource type. - **/ -int -lpfc_sli4_dealloc_resource_identifiers(struct lpfc_hba *phba) -{ - if (phba->sli4_hba.extents_in_use) { - lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VPI); - lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_RPI); - lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_XRI); - lpfc_sli4_dealloc_extent(phba, LPFC_RSC_TYPE_FCOE_VFI); - } else { - kfree(phba->vpi_bmask); - kfree(phba->vpi_ids); - bf_set(lpfc_vpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); - kfree(phba->sli4_hba.xri_bmask); - kfree(phba->sli4_hba.xri_ids); - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); - kfree(phba->sli4_hba.vfi_bmask); - kfree(phba->sli4_hba.vfi_ids); - bf_set(lpfc_vfi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); - bf_set(lpfc_idx_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); - } - - return 0; -} - -/** - * lpfc_sli4_get_allocated_extnts - Get the port's allocated extents. - * @phba: Pointer to HBA context object. - * @type: The resource extent type. - * @extnt_count: buffer to hold port extent count response - * @extnt_size: buffer to hold port extent size response. - * - * This function calls the port to read the host allocated extents - * for a particular type. - **/ -int -lpfc_sli4_get_allocated_extnts(struct lpfc_hba *phba, uint16_t type, - uint16_t *extnt_cnt, uint16_t *extnt_size) -{ - bool emb; - int rc = 0; - uint16_t curr_blks = 0; - uint32_t req_len, emb_len; - uint32_t alloc_len, mbox_tmo; - struct list_head *blk_list_head; - struct lpfc_rsrc_blks *rsrc_blk; - LPFC_MBOXQ_t *mbox; - void *virtaddr = NULL; - struct lpfc_mbx_nembed_rsrc_extent *n_rsrc; - struct lpfc_mbx_alloc_rsrc_extents *rsrc_ext; - union lpfc_sli4_cfg_shdr *shdr; - - switch (type) { - case LPFC_RSC_TYPE_FCOE_VPI: - blk_list_head = &phba->lpfc_vpi_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_XRI: - blk_list_head = &phba->sli4_hba.lpfc_xri_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_VFI: - blk_list_head = &phba->sli4_hba.lpfc_vfi_blk_list; - break; - case LPFC_RSC_TYPE_FCOE_RPI: - blk_list_head = &phba->sli4_hba.lpfc_rpi_blk_list; - break; - default: - return -EIO; - } - - /* Count the number of extents currently allocatd for this type. */ - list_for_each_entry(rsrc_blk, blk_list_head, list) { - if (curr_blks == 0) { - /* - * The GET_ALLOCATED mailbox does not return the size, - * just the count. The size should be just the size - * stored in the current allocated block and all sizes - * for an extent type are the same so set the return - * value now. - */ - *extnt_size = rsrc_blk->rsrc_size; - } - curr_blks++; - } - - /* Calculate the total requested length of the dma memory. */ - req_len = curr_blks * sizeof(uint16_t); - - /* - * Calculate the size of an embedded mailbox. The uint32_t - * accounts for extents-specific word. - */ - emb_len = sizeof(MAILBOX_t) - sizeof(struct mbox_header) - - sizeof(uint32_t); - - /* - * Presume the allocation and response will fit into an embedded - * mailbox. If not true, reconfigure to a non-embedded mailbox. - */ - emb = LPFC_SLI4_MBX_EMBED; - req_len = emb_len; - if (req_len > emb_len) { - req_len = curr_blks * sizeof(uint16_t) + - sizeof(union lpfc_sli4_cfg_shdr) + - sizeof(uint32_t); - emb = LPFC_SLI4_MBX_NEMBED; - } - - mbox = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - memset(mbox, 0, sizeof(LPFC_MBOXQ_t)); - - alloc_len = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_GET_ALLOC_RSRC_EXTENT, - req_len, emb); - if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2983 Allocated DMA memory size (x%x) is " - "less than the requested DMA memory " - "size (x%x)\n", alloc_len, req_len); - rc = -ENOMEM; - goto err_exit; - } - rc = lpfc_sli4_mbox_rsrc_extent(phba, mbox, curr_blks, type, emb); - if (unlikely(rc)) { - rc = -EIO; - goto err_exit; - } - - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - - if (unlikely(rc)) { - rc = -EIO; - goto err_exit; - } - - /* - * Figure out where the response is located. Then get local pointers - * to the response data. The port does not guarantee to respond to - * all extents counts request so update the local variable with the - * allocated count from the port. - */ - if (emb == LPFC_SLI4_MBX_EMBED) { - rsrc_ext = &mbox->u.mqe.un.alloc_rsrc_extents; - shdr = &rsrc_ext->header.cfg_shdr; - *extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, &rsrc_ext->u.rsp); - } else { - virtaddr = mbox->sge_array->addr[0]; - n_rsrc = (struct lpfc_mbx_nembed_rsrc_extent *) virtaddr; - shdr = &n_rsrc->cfg_shdr; - *extnt_cnt = bf_get(lpfc_mbx_rsrc_cnt, n_rsrc); - } - - if (bf_get(lpfc_mbox_hdr_status, &shdr->response)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_INIT, - "2984 Failed to read allocated resources " - "for type %d - Status 0x%x Add'l Status 0x%x.\n", - type, - bf_get(lpfc_mbox_hdr_status, &shdr->response), - bf_get(lpfc_mbox_hdr_add_status, &shdr->response)); - rc = -EIO; - goto err_exit; - } - err_exit: - lpfc_sli4_mbox_cmd_free(phba, mbox); - return rc; -} - -/** - * lpfc_sli4_hba_setup - SLI4 device intialization PCI function - * @phba: Pointer to HBA context object. - * - * This function is the main SLI4 device intialization PCI function. This - * function is called by the HBA intialization code, HBA reset code and - * HBA error attention handler code. Caller is not required to hold any - * locks. - **/ -int -lpfc_sli4_hba_setup(struct lpfc_hba *phba) -{ - int rc; - LPFC_MBOXQ_t *mboxq; - struct lpfc_mqe *mqe; - uint8_t *vpd; - uint32_t vpd_size; - uint32_t ftr_rsp = 0; - struct Scsi_Host *shost = lpfc_shost_from_vport(phba->pport); - struct lpfc_vport *vport = phba->pport; - struct lpfc_dmabuf *mp; - - /* Perform a PCI function reset to start from clean */ - rc = lpfc_pci_function_reset(phba); - if (unlikely(rc)) - return -ENODEV; - - /* Check the HBA Host Status Register for readyness */ - rc = lpfc_sli4_post_status_check(phba); - if (unlikely(rc)) - return -ENODEV; - else { - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag |= LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - } - - /* - * Allocate a single mailbox container for initializing the - * port. - */ - mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) - return -ENOMEM; - - /* Issue READ_REV to collect vpd and FW information. */ - vpd_size = SLI4_PAGE_SIZE; - vpd = kzalloc(vpd_size, GFP_KERNEL); - if (!vpd) { - rc = -ENOMEM; - goto out_free_mbox; - } - - rc = lpfc_sli4_read_rev(phba, mboxq, vpd, &vpd_size); - if (unlikely(rc)) { - kfree(vpd); - goto out_free_mbox; - } - mqe = &mboxq->u.mqe; - phba->sli_rev = bf_get(lpfc_mbx_rd_rev_sli_lvl, &mqe->un.read_rev); - if (bf_get(lpfc_mbx_rd_rev_fcoe, &mqe->un.read_rev)) - phba->hba_flag |= HBA_FCOE_MODE; - else - phba->hba_flag &= ~HBA_FCOE_MODE; - - if (bf_get(lpfc_mbx_rd_rev_cee_ver, &mqe->un.read_rev) == - LPFC_DCBX_CEE_MODE) - phba->hba_flag |= HBA_FIP_SUPPORT; - else - phba->hba_flag &= ~HBA_FIP_SUPPORT; - - if (phba->sli_rev != LPFC_SLI_REV4) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0376 READ_REV Error. SLI Level %d " - "FCoE enabled %d\n", - phba->sli_rev, phba->hba_flag & HBA_FCOE_MODE); - rc = -EIO; - kfree(vpd); - goto out_free_mbox; - } - - /* - * Continue initialization with default values even if driver failed - * to read FCoE param config regions, only read parameters if the - * board is FCoE - */ - if (phba->hba_flag & HBA_FCOE_MODE && - lpfc_sli4_read_fcoe_params(phba)) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_INIT, - "2570 Failed to read FCoE parameters\n"); - - /* - * Retrieve sli4 device physical port name, failure of doing it - * is considered as non-fatal. - */ - rc = lpfc_sli4_retrieve_pport_name(phba); - if (!rc) - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "3080 Successful retrieving SLI4 device " - "physical port name: %s.\n", phba->Port); - - /* - * Evaluate the read rev and vpd data. Populate the driver - * state with the results. If this routine fails, the failure - * is not fatal as the driver will use generic values. - */ - rc = lpfc_parse_vpd(phba, vpd, vpd_size); - if (unlikely(!rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0377 Error %d parsing vpd. " - "Using defaults.\n", rc); - rc = 0; - } - kfree(vpd); - - /* Save information as VPD data */ - phba->vpd.rev.biuRev = mqe->un.read_rev.first_hw_rev; - phba->vpd.rev.smRev = mqe->un.read_rev.second_hw_rev; - phba->vpd.rev.endecRev = mqe->un.read_rev.third_hw_rev; - phba->vpd.rev.fcphHigh = bf_get(lpfc_mbx_rd_rev_fcph_high, - &mqe->un.read_rev); - phba->vpd.rev.fcphLow = bf_get(lpfc_mbx_rd_rev_fcph_low, - &mqe->un.read_rev); - phba->vpd.rev.feaLevelHigh = bf_get(lpfc_mbx_rd_rev_ftr_lvl_high, - &mqe->un.read_rev); - phba->vpd.rev.feaLevelLow = bf_get(lpfc_mbx_rd_rev_ftr_lvl_low, - &mqe->un.read_rev); - phba->vpd.rev.sli1FwRev = mqe->un.read_rev.fw_id_rev; - memcpy(phba->vpd.rev.sli1FwName, mqe->un.read_rev.fw_name, 16); - phba->vpd.rev.sli2FwRev = mqe->un.read_rev.ulp_fw_id_rev; - memcpy(phba->vpd.rev.sli2FwName, mqe->un.read_rev.ulp_fw_name, 16); - phba->vpd.rev.opFwRev = mqe->un.read_rev.fw_id_rev; - memcpy(phba->vpd.rev.opFwName, mqe->un.read_rev.fw_name, 16); - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0380 READ_REV Status x%x " - "fw_rev:%s fcphHi:%x fcphLo:%x flHi:%x flLo:%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - bf_get(lpfc_mqe_status, mqe), - phba->vpd.rev.opFwName, - phba->vpd.rev.fcphHigh, phba->vpd.rev.fcphLow, - phba->vpd.rev.feaLevelHigh, phba->vpd.rev.feaLevelLow); - - /* - * Discover the port's supported feature set and match it against the - * hosts requests. - */ - lpfc_request_features(phba, mboxq); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (unlikely(rc)) { - rc = -EIO; - goto out_free_mbox; - } - - /* - * The port must support FCP initiator mode as this is the - * only mode running in the host. - */ - if (!(bf_get(lpfc_mbx_rq_ftr_rsp_fcpi, &mqe->un.req_ftrs))) { - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "0378 No support for fcpi mode.\n"); - ftr_rsp++; - } - if (bf_get(lpfc_mbx_rq_ftr_rsp_perfh, &mqe->un.req_ftrs)) - phba->sli3_options |= LPFC_SLI4_PERFH_ENABLED; - else - phba->sli3_options &= ~LPFC_SLI4_PERFH_ENABLED; - /* - * If the port cannot support the host's requested features - * then turn off the global config parameters to disable the - * feature in the driver. This is not a fatal error. - */ - phba->sli3_options &= ~LPFC_SLI3_BG_ENABLED; - if (phba->cfg_enable_bg) { - if (bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs)) - phba->sli3_options |= LPFC_SLI3_BG_ENABLED; - else - ftr_rsp++; - } - - if (phba->max_vpi && phba->cfg_enable_npiv && - !(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs))) - ftr_rsp++; - - if (ftr_rsp) { - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "0379 Feature Mismatch Data: x%08x %08x " - "x%x x%x x%x\n", mqe->un.req_ftrs.word2, - mqe->un.req_ftrs.word3, phba->cfg_enable_bg, - phba->cfg_enable_npiv, phba->max_vpi); - if (!(bf_get(lpfc_mbx_rq_ftr_rsp_dif, &mqe->un.req_ftrs))) - phba->cfg_enable_bg = 0; - if (!(bf_get(lpfc_mbx_rq_ftr_rsp_npiv, &mqe->un.req_ftrs))) - phba->cfg_enable_npiv = 0; - } - - /* These SLI3 features are assumed in SLI4 */ - spin_lock_irq(&phba->hbalock); - phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED); - spin_unlock_irq(&phba->hbalock); - - /* - * Allocate all resources (xri,rpi,vpi,vfi) now. Subsequent - * calls depends on these resources to complete port setup. - */ - rc = lpfc_sli4_alloc_resource_identifiers(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2920 Failed to alloc Resource IDs " - "rc = x%x\n", rc); - goto out_free_mbox; - } - /* update physical xri mappings in the scsi buffers */ - lpfc_scsi_buf_update(phba); - - /* Read the port's service parameters. */ - rc = lpfc_read_sparam(phba, mboxq, vport->vpi); - if (rc) { - phba->link_state = LPFC_HBA_ERROR; - rc = -ENOMEM; - goto out_free_mbox; - } - - mboxq->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - mp = (struct lpfc_dmabuf *) mboxq->context1; - if (rc == MBX_SUCCESS) { - memcpy(&vport->fc_sparam, mp->virt, sizeof(struct serv_parm)); - rc = 0; - } - - /* - * This memory was allocated by the lpfc_read_sparam routine. Release - * it to the mbuf pool. - */ - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mboxq->context1 = NULL; - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0382 READ_SPARAM command failed " - "status %d, mbxStatus x%x\n", - rc, bf_get(lpfc_mqe_status, mqe)); - phba->link_state = LPFC_HBA_ERROR; - rc = -EIO; - goto out_free_mbox; - } - - lpfc_update_vport_wwn(vport); - - /* Update the fc_host data structures with new wwn. */ - fc_host_node_name(shost) = wwn_to_u64(vport->fc_nodename.u.wwn); - fc_host_port_name(shost) = wwn_to_u64(vport->fc_portname.u.wwn); - - /* Register SGL pool to the device using non-embedded mailbox command */ - if (!phba->sli4_hba.extents_in_use) { - rc = lpfc_sli4_post_els_sgl_list(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0582 Error %d during els sgl post " - "operation\n", rc); - rc = -ENODEV; - goto out_free_mbox; - } - } else { - rc = lpfc_sli4_post_els_sgl_list_ext(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "2560 Error %d during els sgl post " - "operation\n", rc); - rc = -ENODEV; - goto out_free_mbox; - } - } - - /* Register SCSI SGL pool to the device */ - rc = lpfc_sli4_repost_scsi_sgl_list(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0383 Error %d during scsi sgl post " - "operation\n", rc); - /* Some Scsi buffers were moved to the abort scsi list */ - /* A pci function reset will repost them */ - rc = -ENODEV; - goto out_free_mbox; - } - - /* Post the rpi header region to the device. */ - rc = lpfc_sli4_post_all_rpi_hdrs(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0393 Error %d during rpi post operation\n", - rc); - rc = -ENODEV; - goto out_free_mbox; - } - lpfc_sli4_node_prep(phba); - - /* Create all the SLI4 queues */ - rc = lpfc_sli4_queue_create(phba); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3089 Failed to allocate queues\n"); - rc = -ENODEV; - goto out_stop_timers; - } - /* Set up all the queues to the device */ - rc = lpfc_sli4_queue_setup(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0381 Error %d during queue setup.\n ", rc); - goto out_destroy_queue; - } - - /* Arm the CQs and then EQs on device */ - lpfc_sli4_arm_cqeq_intr(phba); - - /* Indicate device interrupt mode */ - phba->sli4_hba.intr_enable = 1; - - /* Allow asynchronous mailbox command to go through */ - spin_lock_irq(&phba->hbalock); - phba->sli.sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; - spin_unlock_irq(&phba->hbalock); - - /* Post receive buffers to the device */ - lpfc_sli4_rb_setup(phba); - - /* Reset HBA FCF states after HBA reset */ - phba->fcf.fcf_flag = 0; - phba->fcf.current_rec.flag = 0; - - /* Start the ELS watchdog timer */ - mod_timer(&vport->els_tmofunc, - jiffies + HZ * (phba->fc_ratov * 2)); - - /* Start heart beat timer */ - mod_timer(&phba->hb_tmofunc, - jiffies + HZ * LPFC_HB_MBOX_INTERVAL); - phba->hb_outstanding = 0; - phba->last_completion_time = jiffies; - - /* Start error attention (ERATT) polling timer */ - mod_timer(&phba->eratt_poll, jiffies + HZ * LPFC_ERATT_POLL_INTERVAL); - - /* Enable PCIe device Advanced Error Reporting (AER) if configured */ - if (phba->cfg_aer_support == 1 && !(phba->hba_flag & HBA_AER_ENABLED)) { - rc = pci_enable_pcie_error_reporting(phba->pcidev); - if (!rc) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2829 This device supports " - "Advanced Error Reporting (AER)\n"); - spin_lock_irq(&phba->hbalock); - phba->hba_flag |= HBA_AER_ENABLED; - spin_unlock_irq(&phba->hbalock); - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2830 This device does not support " - "Advanced Error Reporting (AER)\n"); - phba->cfg_aer_support = 0; - } - rc = 0; - } - - if (!(phba->hba_flag & HBA_FCOE_MODE)) { - /* - * The FC Port needs to register FCFI (index 0) - */ - lpfc_reg_fcfi(phba, mboxq); - mboxq->vport = phba->pport; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc != MBX_SUCCESS) - goto out_unset_queue; - rc = 0; - phba->fcf.fcfi = bf_get(lpfc_reg_fcfi_fcfi, - &mboxq->u.mqe.un.reg_fcfi); - - /* Check if the port is configured to be disabled */ - lpfc_sli_read_link_ste(phba); - } - - /* - * The port is ready, set the host's link state to LINK_DOWN - * in preparation for link interrupts. - */ - spin_lock_irq(&phba->hbalock); - phba->link_state = LPFC_LINK_DOWN; - spin_unlock_irq(&phba->hbalock); - if (!(phba->hba_flag & HBA_FCOE_MODE) && - (phba->hba_flag & LINK_DISABLED)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, - "3103 Adapter Link is disabled.\n"); - lpfc_down_link(phba, mboxq); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT | LOG_SLI, - "3104 Adapter failed to issue " - "DOWN_LINK mbox cmd, rc:x%x\n", rc); - goto out_unset_queue; - } - } else if (phba->cfg_suppress_link_up == LPFC_INITIALIZE_LINK) { - /* don't perform init_link on SLI4 FC port loopback test */ - if (!(phba->link_flag & LS_LOOPBACK_MODE)) { - rc = phba->lpfc_hba_init_link(phba, MBX_NOWAIT); - if (rc) - goto out_unset_queue; - } - } - mempool_free(mboxq, phba->mbox_mem_pool); - return rc; -out_unset_queue: - /* Unset all the queues set up in this routine when error out */ - lpfc_sli4_queue_unset(phba); -out_destroy_queue: - lpfc_sli4_queue_destroy(phba); -out_stop_timers: - lpfc_stop_hba_timers(phba); -out_free_mbox: - mempool_free(mboxq, phba->mbox_mem_pool); - return rc; -} - -/** - * lpfc_mbox_timeout - Timeout call back function for mbox timer - * @ptr: context object - pointer to hba structure. - * - * This is the callback function for mailbox timer. The mailbox - * timer is armed when a new mailbox command is issued and the timer - * is deleted when the mailbox complete. The function is called by - * the kernel timer code when a mailbox does not complete within - * expected time. This function wakes up the worker thread to - * process the mailbox timeout and returns. All the processing is - * done by the worker thread function lpfc_mbox_timeout_handler. - **/ -void -lpfc_mbox_timeout(unsigned long ptr) -{ - struct lpfc_hba *phba = (struct lpfc_hba *) ptr; - unsigned long iflag; - uint32_t tmo_posted; - - spin_lock_irqsave(&phba->pport->work_port_lock, iflag); - tmo_posted = phba->pport->work_port_events & WORKER_MBOX_TMO; - if (!tmo_posted) - phba->pport->work_port_events |= WORKER_MBOX_TMO; - spin_unlock_irqrestore(&phba->pport->work_port_lock, iflag); - - if (!tmo_posted) - lpfc_worker_wake_up(phba); - return; -} - - -/** - * lpfc_mbox_timeout_handler - Worker thread function to handle mailbox timeout - * @phba: Pointer to HBA context object. - * - * This function is called from worker thread when a mailbox command times out. - * The caller is not required to hold any locks. This function will reset the - * HBA and recover all the pending commands. - **/ -void -lpfc_mbox_timeout_handler(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *pmbox = phba->sli.mbox_active; - MAILBOX_t *mb = &pmbox->u.mb; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - - /* Check the pmbox pointer first. There is a race condition - * between the mbox timeout handler getting executed in the - * worklist and the mailbox actually completing. When this - * race condition occurs, the mbox_active will be NULL. - */ - spin_lock_irq(&phba->hbalock); - if (pmbox == NULL) { - lpfc_printf_log(phba, KERN_WARNING, - LOG_MBOX | LOG_SLI, - "0353 Active Mailbox cleared - mailbox timeout " - "exiting\n"); - spin_unlock_irq(&phba->hbalock); - return; - } - - /* Mbox cmd timeout */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0310 Mailbox command x%x timeout Data: x%x x%x x%p\n", - mb->mbxCommand, - phba->pport->port_state, - phba->sli.sli_flag, - phba->sli.mbox_active); - spin_unlock_irq(&phba->hbalock); - - /* Setting state unknown so lpfc_sli_abort_iocb_ring - * would get IOCB_ERROR from lpfc_sli_issue_iocb, allowing - * it to fail all outstanding SCSI IO. - */ - spin_lock_irq(&phba->pport->work_port_lock); - phba->pport->work_port_events &= ~WORKER_MBOX_TMO; - spin_unlock_irq(&phba->pport->work_port_lock); - spin_lock_irq(&phba->hbalock); - phba->link_state = LPFC_LINK_UNKNOWN; - psli->sli_flag &= ~LPFC_SLI_ACTIVE; - spin_unlock_irq(&phba->hbalock); - - pring = &psli->ring[psli->fcp_ring]; - lpfc_sli_abort_iocb_ring(phba, pring); - - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0345 Resetting board due to mailbox timeout\n"); - - /* Reset the HBA device */ - lpfc_reset_hba(phba); -} - -/** - * lpfc_sli_issue_mbox_s3 - Issue an SLI3 mailbox command to firmware - * @phba: Pointer to HBA context object. - * @pmbox: Pointer to mailbox object. - * @flag: Flag indicating how the mailbox need to be processed. - * - * This function is called by discovery code and HBA management code - * to submit a mailbox command to firmware with SLI-3 interface spec. This - * function gets the hbalock to protect the data structures. - * The mailbox command can be submitted in polling mode, in which case - * this function will wait in a polling loop for the completion of the - * mailbox. - * If the mailbox is submitted in no_wait mode (not polling) the - * function will submit the command and returns immediately without waiting - * for the mailbox completion. The no_wait is supported only when HBA - * is in SLI2/SLI3 mode - interrupts are enabled. - * The SLI interface allows only one mailbox pending at a time. If the - * mailbox is issued in polling mode and there is already a mailbox - * pending, then the function will return an error. If the mailbox is issued - * in NO_WAIT mode and there is a mailbox pending already, the function - * will return MBX_BUSY after queuing the mailbox into mailbox queue. - * The sli layer owns the mailbox object until the completion of mailbox - * command if this function return MBX_BUSY or MBX_SUCCESS. For all other - * return codes the caller owns the mailbox command after the return of - * the function. - **/ -static int -lpfc_sli_issue_mbox_s3(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, - uint32_t flag) -{ - MAILBOX_t *mb; - struct lpfc_sli *psli = &phba->sli; - uint32_t status, evtctr; - uint32_t ha_copy, hc_copy; - int i; - unsigned long timeout; - unsigned long drvr_flag = 0; - uint32_t word0, ldata; - void __iomem *to_slim; - int processing_queue = 0; - - spin_lock_irqsave(&phba->hbalock, drvr_flag); - if (!pmbox) { - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - /* processing mbox queue from intr_handler */ - if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - return MBX_SUCCESS; - } - processing_queue = 1; - pmbox = lpfc_mbox_get(phba); - if (!pmbox) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - return MBX_SUCCESS; - } - } - - if (pmbox->mbox_cmpl && pmbox->mbox_cmpl != lpfc_sli_def_mbox_cmpl && - pmbox->mbox_cmpl != lpfc_sli_wake_mbox_wait) { - if(!pmbox->vport) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_VPORT, - "1806 Mbox x%x failed. No vport\n", - pmbox->u.mb.mbxCommand); - dump_stack(); - goto out_not_finished; - } - } - - /* If the PCI channel is in offline state, do not post mbox. */ - if (unlikely(pci_channel_offline(phba->pcidev))) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - goto out_not_finished; - } - - /* If HBA has a deferred error attention, fail the iocb. */ - if (unlikely(phba->hba_flag & DEFER_ERATT)) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - goto out_not_finished; - } - - psli = &phba->sli; - - mb = &pmbox->u.mb; - status = MBX_SUCCESS; - - if (phba->link_state == LPFC_HBA_ERROR) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - - /* Mbox command cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):0311 Mailbox command x%x cannot " - "issue Data: x%x x%x\n", - pmbox->vport ? pmbox->vport->vpi : 0, - pmbox->u.mb.mbxCommand, psli->sli_flag, flag); - goto out_not_finished; - } - - if (mb->mbxCommand != MBX_KILL_BOARD && flag & MBX_NOWAIT) { - if (lpfc_readl(phba->HCregaddr, &hc_copy) || - !(hc_copy & HC_MBINT_ENA)) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2528 Mailbox command x%x cannot " - "issue Data: x%x x%x\n", - pmbox->vport ? pmbox->vport->vpi : 0, - pmbox->u.mb.mbxCommand, psli->sli_flag, flag); - goto out_not_finished; - } - } - - if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { - /* Polling for a mbox command when another one is already active - * is not allowed in SLI. Also, the driver must have established - * SLI2 mode to queue and process multiple mbox commands. - */ - - if (flag & MBX_POLL) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - - /* Mbox command cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2529 Mailbox command x%x " - "cannot issue Data: x%x x%x\n", - pmbox->vport ? pmbox->vport->vpi : 0, - pmbox->u.mb.mbxCommand, - psli->sli_flag, flag); - goto out_not_finished; - } - - if (!(psli->sli_flag & LPFC_SLI_ACTIVE)) { - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - /* Mbox command cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2530 Mailbox command x%x " - "cannot issue Data: x%x x%x\n", - pmbox->vport ? pmbox->vport->vpi : 0, - pmbox->u.mb.mbxCommand, - psli->sli_flag, flag); - goto out_not_finished; - } - - /* Another mailbox command is still being processed, queue this - * command to be processed later. - */ - lpfc_mbox_put(phba, pmbox); - - /* Mbox cmd issue - BUSY */ - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0308 Mbox cmd issue - BUSY Data: " - "x%x x%x x%x x%x\n", - pmbox->vport ? pmbox->vport->vpi : 0xffffff, - mb->mbxCommand, phba->pport->port_state, - psli->sli_flag, flag); - - psli->slistat.mbox_busy++; - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - - if (pmbox->vport) { - lpfc_debugfs_disc_trc(pmbox->vport, - LPFC_DISC_TRC_MBOX_VPORT, - "MBOX Bsy vport: cmd:x%x mb:x%x x%x", - (uint32_t)mb->mbxCommand, - mb->un.varWords[0], mb->un.varWords[1]); - } - else { - lpfc_debugfs_disc_trc(phba->pport, - LPFC_DISC_TRC_MBOX, - "MBOX Bsy: cmd:x%x mb:x%x x%x", - (uint32_t)mb->mbxCommand, - mb->un.varWords[0], mb->un.varWords[1]); - } - - return MBX_BUSY; - } - - psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE; - - /* If we are not polling, we MUST be in SLI2 mode */ - if (flag != MBX_POLL) { - if (!(psli->sli_flag & LPFC_SLI_ACTIVE) && - (mb->mbxCommand != MBX_KILL_BOARD)) { - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - /* Mbox command cannot issue */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2531 Mailbox command x%x " - "cannot issue Data: x%x x%x\n", - pmbox->vport ? pmbox->vport->vpi : 0, - pmbox->u.mb.mbxCommand, - psli->sli_flag, flag); - goto out_not_finished; - } - /* timeout active mbox command */ - mod_timer(&psli->mbox_tmo, (jiffies + - (HZ * lpfc_mbox_tmo_val(phba, pmbox)))); - } - - /* Mailbox cmd issue */ - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0309 Mailbox cmd x%x issue Data: x%x x%x " - "x%x\n", - pmbox->vport ? pmbox->vport->vpi : 0, - mb->mbxCommand, phba->pport->port_state, - psli->sli_flag, flag); - - if (mb->mbxCommand != MBX_HEARTBEAT) { - if (pmbox->vport) { - lpfc_debugfs_disc_trc(pmbox->vport, - LPFC_DISC_TRC_MBOX_VPORT, - "MBOX Send vport: cmd:x%x mb:x%x x%x", - (uint32_t)mb->mbxCommand, - mb->un.varWords[0], mb->un.varWords[1]); - } - else { - lpfc_debugfs_disc_trc(phba->pport, - LPFC_DISC_TRC_MBOX, - "MBOX Send: cmd:x%x mb:x%x x%x", - (uint32_t)mb->mbxCommand, - mb->un.varWords[0], mb->un.varWords[1]); - } - } - - psli->slistat.mbox_cmd++; - evtctr = psli->slistat.mbox_event; - - /* next set own bit for the adapter and copy over command word */ - mb->mbxOwner = OWN_CHIP; - - if (psli->sli_flag & LPFC_SLI_ACTIVE) { - /* Populate mbox extension offset word. */ - if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) { - *(((uint32_t *)mb) + pmbox->mbox_offset_word) - = (uint8_t *)phba->mbox_ext - - (uint8_t *)phba->mbox; - } - - /* Copy the mailbox extension data */ - if (pmbox->in_ext_byte_len && pmbox->context2) { - lpfc_sli_pcimem_bcopy(pmbox->context2, - (uint8_t *)phba->mbox_ext, - pmbox->in_ext_byte_len); - } - /* Copy command data to host SLIM area */ - lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); - } else { - /* Populate mbox extension offset word. */ - if (pmbox->in_ext_byte_len || pmbox->out_ext_byte_len) - *(((uint32_t *)mb) + pmbox->mbox_offset_word) - = MAILBOX_HBA_EXT_OFFSET; - - /* Copy the mailbox extension data */ - if (pmbox->in_ext_byte_len && pmbox->context2) { - lpfc_memcpy_to_slim(phba->MBslimaddr + - MAILBOX_HBA_EXT_OFFSET, - pmbox->context2, pmbox->in_ext_byte_len); - - } - if (mb->mbxCommand == MBX_CONFIG_PORT) { - /* copy command data into host mbox for cmpl */ - lpfc_sli_pcimem_bcopy(mb, phba->mbox, MAILBOX_CMD_SIZE); - } - - /* First copy mbox command data to HBA SLIM, skip past first - word */ - to_slim = phba->MBslimaddr + sizeof (uint32_t); - lpfc_memcpy_to_slim(to_slim, &mb->un.varWords[0], - MAILBOX_CMD_SIZE - sizeof (uint32_t)); - - /* Next copy over first word, with mbxOwner set */ - ldata = *((uint32_t *)mb); - to_slim = phba->MBslimaddr; - writel(ldata, to_slim); - readl(to_slim); /* flush */ - - if (mb->mbxCommand == MBX_CONFIG_PORT) { - /* switch over to host mailbox */ - psli->sli_flag |= LPFC_SLI_ACTIVE; - } - } - - wmb(); - - switch (flag) { - case MBX_NOWAIT: - /* Set up reference to mailbox command */ - psli->mbox_active = pmbox; - /* Interrupt board to do it */ - writel(CA_MBATT, phba->CAregaddr); - readl(phba->CAregaddr); /* flush */ - /* Don't wait for it to finish, just return */ - break; - - case MBX_POLL: - /* Set up null reference to mailbox command */ - psli->mbox_active = NULL; - /* Interrupt board to do it */ - writel(CA_MBATT, phba->CAregaddr); - readl(phba->CAregaddr); /* flush */ - - if (psli->sli_flag & LPFC_SLI_ACTIVE) { - /* First read mbox status word */ - word0 = *((uint32_t *)phba->mbox); - word0 = le32_to_cpu(word0); - } else { - /* First read mbox status word */ - if (lpfc_readl(phba->MBslimaddr, &word0)) { - spin_unlock_irqrestore(&phba->hbalock, - drvr_flag); - goto out_not_finished; - } - } - - /* Read the HBA Host Attention Register */ - if (lpfc_readl(phba->HAregaddr, &ha_copy)) { - spin_unlock_irqrestore(&phba->hbalock, - drvr_flag); - goto out_not_finished; - } - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, pmbox) * - 1000) + jiffies; - i = 0; - /* Wait for command to complete */ - while (((word0 & OWN_CHIP) == OWN_CHIP) || - (!(ha_copy & HA_MBATT) && - (phba->link_state > LPFC_WARM_START))) { - if (time_after(jiffies, timeout)) { - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock_irqrestore(&phba->hbalock, - drvr_flag); - goto out_not_finished; - } - - /* Check if we took a mbox interrupt while we were - polling */ - if (((word0 & OWN_CHIP) != OWN_CHIP) - && (evtctr != psli->slistat.mbox_event)) - break; - - if (i++ > 10) { - spin_unlock_irqrestore(&phba->hbalock, - drvr_flag); - msleep(1); - spin_lock_irqsave(&phba->hbalock, drvr_flag); - } - - if (psli->sli_flag & LPFC_SLI_ACTIVE) { - /* First copy command data */ - word0 = *((uint32_t *)phba->mbox); - word0 = le32_to_cpu(word0); - if (mb->mbxCommand == MBX_CONFIG_PORT) { - MAILBOX_t *slimmb; - uint32_t slimword0; - /* Check real SLIM for any errors */ - slimword0 = readl(phba->MBslimaddr); - slimmb = (MAILBOX_t *) & slimword0; - if (((slimword0 & OWN_CHIP) != OWN_CHIP) - && slimmb->mbxStatus) { - psli->sli_flag &= - ~LPFC_SLI_ACTIVE; - word0 = slimword0; - } - } - } else { - /* First copy command data */ - word0 = readl(phba->MBslimaddr); - } - /* Read the HBA Host Attention Register */ - if (lpfc_readl(phba->HAregaddr, &ha_copy)) { - spin_unlock_irqrestore(&phba->hbalock, - drvr_flag); - goto out_not_finished; - } - } - - if (psli->sli_flag & LPFC_SLI_ACTIVE) { - /* copy results back to user */ - lpfc_sli_pcimem_bcopy(phba->mbox, mb, MAILBOX_CMD_SIZE); - /* Copy the mailbox extension data */ - if (pmbox->out_ext_byte_len && pmbox->context2) { - lpfc_sli_pcimem_bcopy(phba->mbox_ext, - pmbox->context2, - pmbox->out_ext_byte_len); - } - } else { - /* First copy command data */ - lpfc_memcpy_from_slim(mb, phba->MBslimaddr, - MAILBOX_CMD_SIZE); - /* Copy the mailbox extension data */ - if (pmbox->out_ext_byte_len && pmbox->context2) { - lpfc_memcpy_from_slim(pmbox->context2, - phba->MBslimaddr + - MAILBOX_HBA_EXT_OFFSET, - pmbox->out_ext_byte_len); - } - } - - writel(HA_MBATT, phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - status = mb->mbxStatus; - } - - spin_unlock_irqrestore(&phba->hbalock, drvr_flag); - return status; - -out_not_finished: - if (processing_queue) { - pmbox->u.mb.mbxStatus = MBX_NOT_FINISHED; - lpfc_mbox_cmpl_put(phba, pmbox); - } - return MBX_NOT_FINISHED; -} - -/** - * lpfc_sli4_async_mbox_block - Block posting SLI4 asynchronous mailbox command - * @phba: Pointer to HBA context object. - * - * The function blocks the posting of SLI4 asynchronous mailbox commands from - * the driver internal pending mailbox queue. It will then try to wait out the - * possible outstanding mailbox command before return. - * - * Returns: - * 0 - the outstanding mailbox command completed; otherwise, the wait for - * the outstanding mailbox command timed out. - **/ -static int -lpfc_sli4_async_mbox_block(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - int rc = 0; - unsigned long timeout = 0; - - /* Mark the asynchronous mailbox command posting as blocked */ - spin_lock_irq(&phba->hbalock); - psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; - /* Determine how long we might wait for the active mailbox - * command to be gracefully completed by firmware. - */ - if (phba->sli.mbox_active) - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, - phba->sli.mbox_active) * - 1000) + jiffies; - spin_unlock_irq(&phba->hbalock); - - /* Wait for the outstnading mailbox command to complete */ - while (phba->sli.mbox_active) { - /* Check active mailbox complete status every 2ms */ - msleep(2); - if (time_after(jiffies, timeout)) { - /* Timeout, marked the outstanding cmd not complete */ - rc = 1; - break; - } - } - - /* Can not cleanly block async mailbox command, fails it */ - if (rc) { - spin_lock_irq(&phba->hbalock); - psli->sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; - spin_unlock_irq(&phba->hbalock); - } - return rc; -} - -/** - * lpfc_sli4_async_mbox_unblock - Block posting SLI4 async mailbox command - * @phba: Pointer to HBA context object. - * - * The function unblocks and resume posting of SLI4 asynchronous mailbox - * commands from the driver internal pending mailbox queue. It makes sure - * that there is no outstanding mailbox command before resuming posting - * asynchronous mailbox commands. If, for any reason, there is outstanding - * mailbox command, it will try to wait it out before resuming asynchronous - * mailbox command posting. - **/ -static void -lpfc_sli4_async_mbox_unblock(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - - spin_lock_irq(&phba->hbalock); - if (!(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) { - /* Asynchronous mailbox posting is not blocked, do nothing */ - spin_unlock_irq(&phba->hbalock); - return; - } - - /* Outstanding synchronous mailbox command is guaranteed to be done, - * successful or timeout, after timing-out the outstanding mailbox - * command shall always be removed, so just unblock posting async - * mailbox command and resume - */ - psli->sli_flag &= ~LPFC_SLI_ASYNC_MBX_BLK; - spin_unlock_irq(&phba->hbalock); - - /* wake up worker thread to post asynchronlous mailbox command */ - lpfc_worker_wake_up(phba); -} - -/** - * lpfc_sli4_post_sync_mbox - Post an SLI4 mailbox to the bootstrap mailbox - * @phba: Pointer to HBA context object. - * @mboxq: Pointer to mailbox object. - * - * The function posts a mailbox to the port. The mailbox is expected - * to be comletely filled in and ready for the port to operate on it. - * This routine executes a synchronous completion operation on the - * mailbox by polling for its completion. - * - * The caller must not be holding any locks when calling this routine. - * - * Returns: - * MBX_SUCCESS - mailbox posted successfully - * Any of the MBX error values. - **/ -static int -lpfc_sli4_post_sync_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - int rc = MBX_SUCCESS; - unsigned long iflag; - uint32_t db_ready; - uint32_t mcqe_status; - uint32_t mbx_cmnd; - unsigned long timeout; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_mqe *mb = &mboxq->u.mqe; - struct lpfc_bmbx_create *mbox_rgn; - struct dma_address *dma_address; - struct lpfc_register bmbx_reg; - - /* - * Only one mailbox can be active to the bootstrap mailbox region - * at a time and there is no queueing provided. - */ - spin_lock_irqsave(&phba->hbalock, iflag); - if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2532 Mailbox command x%x (x%x/x%x) " - "cannot issue Data: x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - mboxq->u.mb.mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - psli->sli_flag, MBX_POLL); - return MBXERR_ERROR; - } - /* The server grabs the token and owns it until release */ - psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE; - phba->sli.mbox_active = mboxq; - spin_unlock_irqrestore(&phba->hbalock, iflag); - - /* - * Initialize the bootstrap memory region to avoid stale data areas - * in the mailbox post. Then copy the caller's mailbox contents to - * the bmbx mailbox region. - */ - mbx_cmnd = bf_get(lpfc_mqe_command, mb); - memset(phba->sli4_hba.bmbx.avirt, 0, sizeof(struct lpfc_bmbx_create)); - lpfc_sli_pcimem_bcopy(mb, phba->sli4_hba.bmbx.avirt, - sizeof(struct lpfc_mqe)); - - /* Post the high mailbox dma address to the port and wait for ready. */ - dma_address = &phba->sli4_hba.bmbx.dma_address; - writel(dma_address->addr_hi, phba->sli4_hba.BMBXregaddr); - - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) - * 1000) + jiffies; - do { - bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); - db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); - if (!db_ready) - msleep(2); - - if (time_after(jiffies, timeout)) { - rc = MBXERR_ERROR; - goto exit; - } - } while (!db_ready); - - /* Post the low mailbox dma address to the port. */ - writel(dma_address->addr_lo, phba->sli4_hba.BMBXregaddr); - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, mboxq) - * 1000) + jiffies; - do { - bmbx_reg.word0 = readl(phba->sli4_hba.BMBXregaddr); - db_ready = bf_get(lpfc_bmbx_rdy, &bmbx_reg); - if (!db_ready) - msleep(2); - - if (time_after(jiffies, timeout)) { - rc = MBXERR_ERROR; - goto exit; - } - } while (!db_ready); - - /* - * Read the CQ to ensure the mailbox has completed. - * If so, update the mailbox status so that the upper layers - * can complete the request normally. - */ - lpfc_sli_pcimem_bcopy(phba->sli4_hba.bmbx.avirt, mb, - sizeof(struct lpfc_mqe)); - mbox_rgn = (struct lpfc_bmbx_create *) phba->sli4_hba.bmbx.avirt; - lpfc_sli_pcimem_bcopy(&mbox_rgn->mcqe, &mboxq->mcqe, - sizeof(struct lpfc_mcqe)); - mcqe_status = bf_get(lpfc_mcqe_status, &mbox_rgn->mcqe); - /* - * When the CQE status indicates a failure and the mailbox status - * indicates success then copy the CQE status into the mailbox status - * (and prefix it with x4000). - */ - if (mcqe_status != MB_CQE_STATUS_SUCCESS) { - if (bf_get(lpfc_mqe_status, mb) == MBX_SUCCESS) - bf_set(lpfc_mqe_status, mb, - (LPFC_MBX_ERROR_RANGE | mcqe_status)); - rc = MBXERR_ERROR; - } else - lpfc_sli4_swap_str(phba, mboxq); - - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0356 Mailbox cmd x%x (x%x/x%x) Status x%x " - "Data: x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x x%x" - " x%x x%x CQ: x%x x%x x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, mbx_cmnd, - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - bf_get(lpfc_mqe_status, mb), - mb->un.mb_words[0], mb->un.mb_words[1], - mb->un.mb_words[2], mb->un.mb_words[3], - mb->un.mb_words[4], mb->un.mb_words[5], - mb->un.mb_words[6], mb->un.mb_words[7], - mb->un.mb_words[8], mb->un.mb_words[9], - mb->un.mb_words[10], mb->un.mb_words[11], - mb->un.mb_words[12], mboxq->mcqe.word0, - mboxq->mcqe.mcqe_tag0, mboxq->mcqe.mcqe_tag1, - mboxq->mcqe.trailer); -exit: - /* We are holding the token, no needed for lock when release */ - spin_lock_irqsave(&phba->hbalock, iflag); - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - phba->sli.mbox_active = NULL; - spin_unlock_irqrestore(&phba->hbalock, iflag); - return rc; -} - -/** - * lpfc_sli_issue_mbox_s4 - Issue an SLI4 mailbox command to firmware - * @phba: Pointer to HBA context object. - * @pmbox: Pointer to mailbox object. - * @flag: Flag indicating how the mailbox need to be processed. - * - * This function is called by discovery code and HBA management code to submit - * a mailbox command to firmware with SLI-4 interface spec. - * - * Return codes the caller owns the mailbox command after the return of the - * function. - **/ -static int -lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, - uint32_t flag) -{ - struct lpfc_sli *psli = &phba->sli; - unsigned long iflags; - int rc; - - /* dump from issue mailbox command if setup */ - lpfc_idiag_mbxacc_dump_issue_mbox(phba, &mboxq->u.mb); - - rc = lpfc_mbox_dev_check(phba); - if (unlikely(rc)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2544 Mailbox command x%x (x%x/x%x) " - "cannot issue Data: x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - mboxq->u.mb.mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - psli->sli_flag, flag); - goto out_not_finished; - } - - /* Detect polling mode and jump to a handler */ - if (!phba->sli4_hba.intr_enable) { - if (flag == MBX_POLL) - rc = lpfc_sli4_post_sync_mbox(phba, mboxq); - else - rc = -EIO; - if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "(%d):2541 Mailbox command x%x " - "(x%x/x%x) cannot issue Data: " - "x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - mboxq->u.mb.mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, - mboxq), - lpfc_sli_config_mbox_opcode_get(phba, - mboxq), - psli->sli_flag, flag); - return rc; - } else if (flag == MBX_POLL) { - lpfc_printf_log(phba, KERN_WARNING, LOG_MBOX | LOG_SLI, - "(%d):2542 Try to issue mailbox command " - "x%x (x%x/x%x) synchronously ahead of async" - "mailbox command queue: x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - mboxq->u.mb.mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - psli->sli_flag, flag); - /* Try to block the asynchronous mailbox posting */ - rc = lpfc_sli4_async_mbox_block(phba); - if (!rc) { - /* Successfully blocked, now issue sync mbox cmd */ - rc = lpfc_sli4_post_sync_mbox(phba, mboxq); - if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_ERR, - LOG_MBOX | LOG_SLI, - "(%d):2597 Mailbox command " - "x%x (x%x/x%x) cannot issue " - "Data: x%x x%x\n", - mboxq->vport ? - mboxq->vport->vpi : 0, - mboxq->u.mb.mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, - mboxq), - lpfc_sli_config_mbox_opcode_get(phba, - mboxq), - psli->sli_flag, flag); - /* Unblock the async mailbox posting afterward */ - lpfc_sli4_async_mbox_unblock(phba); - } - return rc; - } - - /* Now, interrupt mode asynchrous mailbox command */ - rc = lpfc_mbox_cmd_check(phba, mboxq); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2543 Mailbox command x%x (x%x/x%x) " - "cannot issue Data: x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - mboxq->u.mb.mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - psli->sli_flag, flag); - goto out_not_finished; - } - - /* Put the mailbox command to the driver internal FIFO */ - psli->slistat.mbox_busy++; - spin_lock_irqsave(&phba->hbalock, iflags); - lpfc_mbox_put(phba, mboxq); - spin_unlock_irqrestore(&phba->hbalock, iflags); - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0354 Mbox cmd issue - Enqueue Data: " - "x%x (x%x/x%x) x%x x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0xffffff, - bf_get(lpfc_mqe_command, &mboxq->u.mqe), - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - phba->pport->port_state, - psli->sli_flag, MBX_NOWAIT); - /* Wake up worker thread to transport mailbox command from head */ - lpfc_worker_wake_up(phba); - - return MBX_BUSY; - -out_not_finished: - return MBX_NOT_FINISHED; -} - -/** - * lpfc_sli4_post_async_mbox - Post an SLI4 mailbox command to device - * @phba: Pointer to HBA context object. - * - * This function is called by worker thread to send a mailbox command to - * SLI4 HBA firmware. - * - **/ -int -lpfc_sli4_post_async_mbox(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - LPFC_MBOXQ_t *mboxq; - int rc = MBX_SUCCESS; - unsigned long iflags; - struct lpfc_mqe *mqe; - uint32_t mbx_cmnd; - - /* Check interrupt mode before post async mailbox command */ - if (unlikely(!phba->sli4_hba.intr_enable)) - return MBX_NOT_FINISHED; - - /* Check for mailbox command service token */ - spin_lock_irqsave(&phba->hbalock, iflags); - if (unlikely(psli->sli_flag & LPFC_SLI_ASYNC_MBX_BLK)) { - spin_unlock_irqrestore(&phba->hbalock, iflags); - return MBX_NOT_FINISHED; - } - if (psli->sli_flag & LPFC_SLI_MBOX_ACTIVE) { - spin_unlock_irqrestore(&phba->hbalock, iflags); - return MBX_NOT_FINISHED; - } - if (unlikely(phba->sli.mbox_active)) { - spin_unlock_irqrestore(&phba->hbalock, iflags); - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "0384 There is pending active mailbox cmd\n"); - return MBX_NOT_FINISHED; - } - /* Take the mailbox command service token */ - psli->sli_flag |= LPFC_SLI_MBOX_ACTIVE; - - /* Get the next mailbox command from head of queue */ - mboxq = lpfc_mbox_get(phba); - - /* If no more mailbox command waiting for post, we're done */ - if (!mboxq) { - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - spin_unlock_irqrestore(&phba->hbalock, iflags); - return MBX_SUCCESS; - } - phba->sli.mbox_active = mboxq; - spin_unlock_irqrestore(&phba->hbalock, iflags); - - /* Check device readiness for posting mailbox command */ - rc = lpfc_mbox_dev_check(phba); - if (unlikely(rc)) - /* Driver clean routine will clean up pending mailbox */ - goto out_not_finished; - - /* Prepare the mbox command to be posted */ - mqe = &mboxq->u.mqe; - mbx_cmnd = bf_get(lpfc_mqe_command, mqe); - - /* Start timer for the mbox_tmo and log some mailbox post messages */ - mod_timer(&psli->mbox_tmo, (jiffies + - (HZ * lpfc_mbox_tmo_val(phba, mboxq)))); - - lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, - "(%d):0355 Mailbox cmd x%x (x%x/x%x) issue Data: " - "x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, mbx_cmnd, - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - phba->pport->port_state, psli->sli_flag); - - if (mbx_cmnd != MBX_HEARTBEAT) { - if (mboxq->vport) { - lpfc_debugfs_disc_trc(mboxq->vport, - LPFC_DISC_TRC_MBOX_VPORT, - "MBOX Send vport: cmd:x%x mb:x%x x%x", - mbx_cmnd, mqe->un.mb_words[0], - mqe->un.mb_words[1]); - } else { - lpfc_debugfs_disc_trc(phba->pport, - LPFC_DISC_TRC_MBOX, - "MBOX Send: cmd:x%x mb:x%x x%x", - mbx_cmnd, mqe->un.mb_words[0], - mqe->un.mb_words[1]); - } - } - psli->slistat.mbox_cmd++; - - /* Post the mailbox command to the port */ - rc = lpfc_sli4_mq_put(phba->sli4_hba.mbx_wq, mqe); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, - "(%d):2533 Mailbox command x%x (x%x/x%x) " - "cannot issue Data: x%x x%x\n", - mboxq->vport ? mboxq->vport->vpi : 0, - mboxq->u.mb.mbxCommand, - lpfc_sli_config_mbox_subsys_get(phba, mboxq), - lpfc_sli_config_mbox_opcode_get(phba, mboxq), - psli->sli_flag, MBX_NOWAIT); - goto out_not_finished; - } - - return rc; - -out_not_finished: - spin_lock_irqsave(&phba->hbalock, iflags); - if (phba->sli.mbox_active) { - mboxq->u.mb.mbxStatus = MBX_NOT_FINISHED; - __lpfc_mbox_cmpl_put(phba, mboxq); - /* Release the token */ - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - phba->sli.mbox_active = NULL; - } - spin_unlock_irqrestore(&phba->hbalock, iflags); - - return MBX_NOT_FINISHED; -} - -/** - * lpfc_sli_issue_mbox - Wrapper func for issuing mailbox command - * @phba: Pointer to HBA context object. - * @pmbox: Pointer to mailbox object. - * @flag: Flag indicating how the mailbox need to be processed. - * - * This routine wraps the actual SLI3 or SLI4 mailbox issuing routine from - * the API jump table function pointer from the lpfc_hba struct. - * - * Return codes the caller owns the mailbox command after the return of the - * function. - **/ -int -lpfc_sli_issue_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmbox, uint32_t flag) -{ - return phba->lpfc_sli_issue_mbox(phba, pmbox, flag); -} - -/** - * lpfc_mbox_api_table_setup - Set up mbox api function jump table - * @phba: The hba struct for which this call is being executed. - * @dev_grp: The HBA PCI-Device group number. - * - * This routine sets up the mbox interface API function jump table in @phba - * struct. - * Returns: 0 - success, -ENODEV - failure. - **/ -int -lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) -{ - - switch (dev_grp) { - case LPFC_PCI_DEV_LP: - phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s3; - phba->lpfc_sli_handle_slow_ring_event = - lpfc_sli_handle_slow_ring_event_s3; - phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s3; - phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s3; - phba->lpfc_sli_brdready = lpfc_sli_brdready_s3; - break; - case LPFC_PCI_DEV_OC: - phba->lpfc_sli_issue_mbox = lpfc_sli_issue_mbox_s4; - phba->lpfc_sli_handle_slow_ring_event = - lpfc_sli_handle_slow_ring_event_s4; - phba->lpfc_sli_hbq_to_firmware = lpfc_sli_hbq_to_firmware_s4; - phba->lpfc_sli_brdrestart = lpfc_sli_brdrestart_s4; - phba->lpfc_sli_brdready = lpfc_sli_brdready_s4; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1420 Invalid HBA PCI-device group: 0x%x\n", - dev_grp); - return -ENODEV; - break; - } - return 0; -} - -/** - * __lpfc_sli_ringtx_put - Add an iocb to the txq - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @piocb: Pointer to address of newly added command iocb. - * - * This function is called with hbalock held to add a command - * iocb to the txq when SLI layer cannot submit the command iocb - * to the ring. - **/ -void -__lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *piocb) -{ - /* Insert the caller's iocb in the txq tail for later processing. */ - list_add_tail(&piocb->list, &pring->txq); - pring->txq_cnt++; -} - -/** - * lpfc_sli_next_iocb - Get the next iocb in the txq - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @piocb: Pointer to address of newly added command iocb. - * - * This function is called with hbalock held before a new - * iocb is submitted to the firmware. This function checks - * txq to flush the iocbs in txq to Firmware before - * submitting new iocbs to the Firmware. - * If there are iocbs in the txq which need to be submitted - * to firmware, lpfc_sli_next_iocb returns the first element - * of the txq after dequeuing it from txq. - * If there is no iocb in the txq then the function will return - * *piocb and *piocb is set to NULL. Caller needs to check - * *piocb to find if there are more commands in the txq. - **/ -static struct lpfc_iocbq * -lpfc_sli_next_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq **piocb) -{ - struct lpfc_iocbq * nextiocb; - - nextiocb = lpfc_sli_ringtx_get(phba, pring); - if (!nextiocb) { - nextiocb = *piocb; - *piocb = NULL; - } - - return nextiocb; -} - -/** - * __lpfc_sli_issue_iocb_s3 - SLI3 device lockless ver of lpfc_sli_issue_iocb - * @phba: Pointer to HBA context object. - * @ring_number: SLI ring number to issue iocb on. - * @piocb: Pointer to command iocb. - * @flag: Flag indicating if this command can be put into txq. - * - * __lpfc_sli_issue_iocb_s3 is used by other functions in the driver to issue - * an iocb command to an HBA with SLI-3 interface spec. If the PCI slot is - * recovering from error state, if HBA is resetting or if LPFC_STOP_IOCB_EVENT - * flag is turned on, the function returns IOCB_ERROR. When the link is down, - * this function allows only iocbs for posting buffers. This function finds - * next available slot in the command ring and posts the command to the - * available slot and writes the port attention register to request HBA start - * processing new iocb. If there is no slot available in the ring and - * flag & SLI_IOCB_RET_IOCB is set, the new iocb is added to the txq, otherwise - * the function returns IOCB_BUSY. - * - * This function is called with hbalock held. The function will return success - * after it successfully submit the iocb to firmware or after adding to the - * txq. - **/ -static int -__lpfc_sli_issue_iocb_s3(struct lpfc_hba *phba, uint32_t ring_number, - struct lpfc_iocbq *piocb, uint32_t flag) -{ - struct lpfc_iocbq *nextiocb; - IOCB_t *iocb; - struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number]; - - if (piocb->iocb_cmpl && (!piocb->vport) && - (piocb->iocb.ulpCommand != CMD_ABORT_XRI_CN) && - (piocb->iocb.ulpCommand != CMD_CLOSE_XRI_CN)) { - lpfc_printf_log(phba, KERN_ERR, - LOG_SLI | LOG_VPORT, - "1807 IOCB x%x failed. No vport\n", - piocb->iocb.ulpCommand); - dump_stack(); - return IOCB_ERROR; - } - - - /* If the PCI channel is in offline state, do not post iocbs. */ - if (unlikely(pci_channel_offline(phba->pcidev))) - return IOCB_ERROR; - - /* If HBA has a deferred error attention, fail the iocb. */ - if (unlikely(phba->hba_flag & DEFER_ERATT)) - return IOCB_ERROR; - - /* - * We should never get an IOCB if we are in a < LINK_DOWN state - */ - if (unlikely(phba->link_state < LPFC_LINK_DOWN)) - return IOCB_ERROR; - - /* - * Check to see if we are blocking IOCB processing because of a - * outstanding event. - */ - if (unlikely(pring->flag & LPFC_STOP_IOCB_EVENT)) - goto iocb_busy; - - if (unlikely(phba->link_state == LPFC_LINK_DOWN)) { - /* - * Only CREATE_XRI, CLOSE_XRI, and QUE_RING_BUF - * can be issued if the link is not up. - */ - switch (piocb->iocb.ulpCommand) { - case CMD_GEN_REQUEST64_CR: - case CMD_GEN_REQUEST64_CX: - if (!(phba->sli.sli_flag & LPFC_MENLO_MAINT) || - (piocb->iocb.un.genreq64.w5.hcsw.Rctl != - FC_RCTL_DD_UNSOL_CMD) || - (piocb->iocb.un.genreq64.w5.hcsw.Type != - MENLO_TRANSPORT_TYPE)) - - goto iocb_busy; - break; - case CMD_QUE_RING_BUF_CN: - case CMD_QUE_RING_BUF64_CN: - /* - * For IOCBs, like QUE_RING_BUF, that have no rsp ring - * completion, iocb_cmpl MUST be 0. - */ - if (piocb->iocb_cmpl) - piocb->iocb_cmpl = NULL; - /*FALLTHROUGH*/ - case CMD_CREATE_XRI_CR: - case CMD_CLOSE_XRI_CN: - case CMD_CLOSE_XRI_CX: - break; - default: - goto iocb_busy; - } - - /* - * For FCP commands, we must be in a state where we can process link - * attention events. - */ - } else if (unlikely(pring->ringno == phba->sli.fcp_ring && - !(phba->sli.sli_flag & LPFC_PROCESS_LA))) { - goto iocb_busy; - } - - while ((iocb = lpfc_sli_next_iocb_slot(phba, pring)) && - (nextiocb = lpfc_sli_next_iocb(phba, pring, &piocb))) - lpfc_sli_submit_iocb(phba, pring, iocb, nextiocb); - - if (iocb) - lpfc_sli_update_ring(phba, pring); - else - lpfc_sli_update_full_ring(phba, pring); - - if (!piocb) - return IOCB_SUCCESS; - - goto out_busy; - - iocb_busy: - pring->stats.iocb_cmd_delay++; - - out_busy: - - if (!(flag & SLI_IOCB_RET_IOCB)) { - __lpfc_sli_ringtx_put(phba, pring, piocb); - return IOCB_SUCCESS; - } - - return IOCB_BUSY; -} - -/** - * lpfc_sli4_bpl2sgl - Convert the bpl/bde to a sgl. - * @phba: Pointer to HBA context object. - * @piocb: Pointer to command iocb. - * @sglq: Pointer to the scatter gather queue object. - * - * This routine converts the bpl or bde that is in the IOCB - * to a sgl list for the sli4 hardware. The physical address - * of the bpl/bde is converted back to a virtual address. - * If the IOCB contains a BPL then the list of BDE's is - * converted to sli4_sge's. If the IOCB contains a single - * BDE then it is converted to a single sli_sge. - * The IOCB is still in cpu endianess so the contents of - * the bpl can be used without byte swapping. - * - * Returns valid XRI = Success, NO_XRI = Failure. -**/ -static uint16_t -lpfc_sli4_bpl2sgl(struct lpfc_hba *phba, struct lpfc_iocbq *piocbq, - struct lpfc_sglq *sglq) -{ - uint16_t xritag = NO_XRI; - struct ulp_bde64 *bpl = NULL; - struct ulp_bde64 bde; - struct sli4_sge *sgl = NULL; - struct lpfc_dmabuf *dmabuf; - IOCB_t *icmd; - int numBdes = 0; - int i = 0; - uint32_t offset = 0; /* accumulated offset in the sg request list */ - int inbound = 0; /* number of sg reply entries inbound from firmware */ - - if (!piocbq || !sglq) - return xritag; - - sgl = (struct sli4_sge *)sglq->sgl; - icmd = &piocbq->iocb; - if (icmd->ulpCommand == CMD_XMIT_BLS_RSP64_CX) - return sglq->sli4_xritag; - if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { - numBdes = icmd->un.genreq64.bdl.bdeSize / - sizeof(struct ulp_bde64); - /* The addrHigh and addrLow fields within the IOCB - * have not been byteswapped yet so there is no - * need to swap them back. - */ - if (piocbq->context3) - dmabuf = (struct lpfc_dmabuf *)piocbq->context3; - else - return xritag; - - bpl = (struct ulp_bde64 *)dmabuf->virt; - if (!bpl) - return xritag; - - for (i = 0; i < numBdes; i++) { - /* Should already be byte swapped. */ - sgl->addr_hi = bpl->addrHigh; - sgl->addr_lo = bpl->addrLow; - - sgl->word2 = le32_to_cpu(sgl->word2); - if ((i+1) == numBdes) - bf_set(lpfc_sli4_sge_last, sgl, 1); - else - bf_set(lpfc_sli4_sge_last, sgl, 0); - /* swap the size field back to the cpu so we - * can assign it to the sgl. - */ - bde.tus.w = le32_to_cpu(bpl->tus.w); - sgl->sge_len = cpu_to_le32(bde.tus.f.bdeSize); - /* The offsets in the sgl need to be accumulated - * separately for the request and reply lists. - * The request is always first, the reply follows. - */ - if (piocbq->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) { - /* add up the reply sg entries */ - if (bpl->tus.f.bdeFlags == BUFF_TYPE_BDE_64I) - inbound++; - /* first inbound? reset the offset */ - if (inbound == 1) - offset = 0; - bf_set(lpfc_sli4_sge_offset, sgl, offset); - bf_set(lpfc_sli4_sge_type, sgl, - LPFC_SGE_TYPE_DATA); - offset += bde.tus.f.bdeSize; - } - sgl->word2 = cpu_to_le32(sgl->word2); - bpl++; - sgl++; - } - } else if (icmd->un.genreq64.bdl.bdeFlags == BUFF_TYPE_BDE_64) { - /* The addrHigh and addrLow fields of the BDE have not - * been byteswapped yet so they need to be swapped - * before putting them in the sgl. - */ - sgl->addr_hi = - cpu_to_le32(icmd->un.genreq64.bdl.addrHigh); - sgl->addr_lo = - cpu_to_le32(icmd->un.genreq64.bdl.addrLow); - sgl->word2 = le32_to_cpu(sgl->word2); - bf_set(lpfc_sli4_sge_last, sgl, 1); - sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = - cpu_to_le32(icmd->un.genreq64.bdl.bdeSize); - } - return sglq->sli4_xritag; -} - -/** - * lpfc_sli4_scmd_to_wqidx_distr - scsi command to SLI4 WQ index distribution - * @phba: Pointer to HBA context object. - * - * This routine performs a roundrobin SCSI command to SLI4 FCP WQ index - * distribution. This is called by __lpfc_sli_issue_iocb_s4() with the hbalock - * held. - * - * Return: index into SLI4 fast-path FCP queue index. - **/ -static uint32_t -lpfc_sli4_scmd_to_wqidx_distr(struct lpfc_hba *phba) -{ - ++phba->fcp_qidx; - if (phba->fcp_qidx >= phba->cfg_fcp_wq_count) - phba->fcp_qidx = 0; - - return phba->fcp_qidx; -} - -/** - * lpfc_sli_iocb2wqe - Convert the IOCB to a work queue entry. - * @phba: Pointer to HBA context object. - * @piocb: Pointer to command iocb. - * @wqe: Pointer to the work queue entry. - * - * This routine converts the iocb command to its Work Queue Entry - * equivalent. The wqe pointer should not have any fields set when - * this routine is called because it will memcpy over them. - * This routine does not set the CQ_ID or the WQEC bits in the - * wqe. - * - * Returns: 0 = Success, IOCB_ERROR = Failure. - **/ -static int -lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, - union lpfc_wqe *wqe) -{ - uint32_t xmit_len = 0, total_len = 0; - uint8_t ct = 0; - uint32_t fip; - uint32_t abort_tag; - uint8_t command_type = ELS_COMMAND_NON_FIP; - uint8_t cmnd; - uint16_t xritag; - uint16_t abrt_iotag; - struct lpfc_iocbq *abrtiocbq; - struct ulp_bde64 *bpl = NULL; - uint32_t els_id = LPFC_ELS_ID_DEFAULT; - int numBdes, i; - struct ulp_bde64 bde; - struct lpfc_nodelist *ndlp; - uint32_t *pcmd; - uint32_t if_type; - - fip = phba->hba_flag & HBA_FIP_SUPPORT; - /* The fcp commands will set command type */ - if (iocbq->iocb_flag & LPFC_IO_FCP) - command_type = FCP_COMMAND; - else if (fip && (iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK)) - command_type = ELS_COMMAND_FIP; - else - command_type = ELS_COMMAND_NON_FIP; - - /* Some of the fields are in the right position already */ - memcpy(wqe, &iocbq->iocb, sizeof(union lpfc_wqe)); - abort_tag = (uint32_t) iocbq->iotag; - xritag = iocbq->sli4_xritag; - wqe->generic.wqe_com.word7 = 0; /* The ct field has moved so reset */ - /* words0-2 bpl convert bde */ - if (iocbq->iocb.un.genreq64.bdl.bdeFlags == BUFF_TYPE_BLP_64) { - numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / - sizeof(struct ulp_bde64); - bpl = (struct ulp_bde64 *) - ((struct lpfc_dmabuf *)iocbq->context3)->virt; - if (!bpl) - return IOCB_ERROR; - - /* Should already be byte swapped. */ - wqe->generic.bde.addrHigh = le32_to_cpu(bpl->addrHigh); - wqe->generic.bde.addrLow = le32_to_cpu(bpl->addrLow); - /* swap the size field back to the cpu so we - * can assign it to the sgl. - */ - wqe->generic.bde.tus.w = le32_to_cpu(bpl->tus.w); - xmit_len = wqe->generic.bde.tus.f.bdeSize; - total_len = 0; - for (i = 0; i < numBdes; i++) { - bde.tus.w = le32_to_cpu(bpl[i].tus.w); - total_len += bde.tus.f.bdeSize; - } - } else - xmit_len = iocbq->iocb.un.fcpi64.bdl.bdeSize; - - iocbq->iocb.ulpIoTag = iocbq->iotag; - cmnd = iocbq->iocb.ulpCommand; - - switch (iocbq->iocb.ulpCommand) { - case CMD_ELS_REQUEST64_CR: - ndlp = (struct lpfc_nodelist *)iocbq->context1; - if (!iocbq->iocb.ulpLe) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2007 Only Limited Edition cmd Format" - " supported 0x%x\n", - iocbq->iocb.ulpCommand); - return IOCB_ERROR; - } - - wqe->els_req.payload_len = xmit_len; - /* Els_reguest64 has a TMO */ - bf_set(wqe_tmo, &wqe->els_req.wqe_com, - iocbq->iocb.ulpTimeout); - /* Need a VF for word 4 set the vf bit*/ - bf_set(els_req64_vf, &wqe->els_req, 0); - /* And a VFID for word 12 */ - bf_set(els_req64_vfid, &wqe->els_req, 0); - ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - iocbq->iocb.ulpContext); - bf_set(wqe_ct, &wqe->els_req.wqe_com, ct); - bf_set(wqe_pu, &wqe->els_req.wqe_com, 0); - /* CCP CCPE PV PRI in word10 were set in the memcpy */ - if (command_type == ELS_COMMAND_FIP) - els_id = ((iocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK) - >> LPFC_FIP_ELS_ID_SHIFT); - pcmd = (uint32_t *) (((struct lpfc_dmabuf *) - iocbq->context2)->virt); - if_type = bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf); - if (if_type == LPFC_SLI_INTF_IF_TYPE_2) { - if (pcmd && (*pcmd == ELS_CMD_FLOGI || - *pcmd == ELS_CMD_SCR || - *pcmd == ELS_CMD_FDISC || - *pcmd == ELS_CMD_LOGO || - *pcmd == ELS_CMD_PLOGI)) { - bf_set(els_req64_sp, &wqe->els_req, 1); - bf_set(els_req64_sid, &wqe->els_req, - iocbq->vport->fc_myDID); - bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - phba->vpi_ids[phba->pport->vpi]); - } else if (pcmd && iocbq->context1) { - bf_set(wqe_ct, &wqe->els_req.wqe_com, 0); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); - } - } - bf_set(wqe_temp_rpi, &wqe->els_req.wqe_com, - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); - bf_set(wqe_els_id, &wqe->els_req.wqe_com, els_id); - bf_set(wqe_dbde, &wqe->els_req.wqe_com, 1); - bf_set(wqe_iod, &wqe->els_req.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_qosd, &wqe->els_req.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->els_req.wqe_com, LPFC_WQE_LENLOC_NONE); - bf_set(wqe_ebde_cnt, &wqe->els_req.wqe_com, 0); - break; - case CMD_XMIT_SEQUENCE64_CX: - bf_set(wqe_ctxt_tag, &wqe->xmit_sequence.wqe_com, - iocbq->iocb.un.ulpWord[3]); - bf_set(wqe_rcvoxid, &wqe->xmit_sequence.wqe_com, - iocbq->iocb.unsli3.rcvsli3.ox_id); - /* The entire sequence is transmitted for this IOCB */ - xmit_len = total_len; - cmnd = CMD_XMIT_SEQUENCE64_CR; - if (phba->link_flag & LS_LOOPBACK_MODE) - bf_set(wqe_xo, &wqe->xmit_sequence.wge_ctl, 1); - case CMD_XMIT_SEQUENCE64_CR: - /* word3 iocb=io_tag32 wqe=reserved */ - wqe->xmit_sequence.rsvd3 = 0; - /* word4 relative_offset memcpy */ - /* word5 r_ctl/df_ctl memcpy */ - bf_set(wqe_pu, &wqe->xmit_sequence.wqe_com, 0); - bf_set(wqe_dbde, &wqe->xmit_sequence.wqe_com, 1); - bf_set(wqe_iod, &wqe->xmit_sequence.wqe_com, - LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->xmit_sequence.wqe_com, - LPFC_WQE_LENLOC_WORD12); - bf_set(wqe_ebde_cnt, &wqe->xmit_sequence.wqe_com, 0); - wqe->xmit_sequence.xmit_len = xmit_len; - command_type = OTHER_COMMAND; - break; - case CMD_XMIT_BCAST64_CN: - /* word3 iocb=iotag32 wqe=seq_payload_len */ - wqe->xmit_bcast64.seq_payload_len = xmit_len; - /* word4 iocb=rsvd wqe=rsvd */ - /* word5 iocb=rctl/type/df_ctl wqe=rctl/type/df_ctl memcpy */ - /* word6 iocb=ctxt_tag/io_tag wqe=ctxt_tag/xri */ - bf_set(wqe_ct, &wqe->xmit_bcast64.wqe_com, - ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); - bf_set(wqe_dbde, &wqe->xmit_bcast64.wqe_com, 1); - bf_set(wqe_iod, &wqe->xmit_bcast64.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->xmit_bcast64.wqe_com, - LPFC_WQE_LENLOC_WORD3); - bf_set(wqe_ebde_cnt, &wqe->xmit_bcast64.wqe_com, 0); - break; - case CMD_FCP_IWRITE64_CR: - command_type = FCP_COMMAND_DATA_OUT; - /* word3 iocb=iotag wqe=payload_offset_len */ - /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ - wqe->fcp_iwrite.payload_offset_len = - xmit_len + sizeof(struct fcp_rsp); - /* word4 iocb=parameter wqe=total_xfer_length memcpy */ - /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */ - bf_set(wqe_erp, &wqe->fcp_iwrite.wqe_com, - iocbq->iocb.ulpFCP2Rcvy); - bf_set(wqe_lnk, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpXS); - /* Always open the exchange */ - bf_set(wqe_xc, &wqe->fcp_iwrite.wqe_com, 0); - bf_set(wqe_iod, &wqe->fcp_iwrite.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_lenloc, &wqe->fcp_iwrite.wqe_com, - LPFC_WQE_LENLOC_WORD4); - bf_set(wqe_ebde_cnt, &wqe->fcp_iwrite.wqe_com, 0); - bf_set(wqe_pu, &wqe->fcp_iwrite.wqe_com, iocbq->iocb.ulpPU); - if (iocbq->iocb_flag & LPFC_IO_DIF) { - iocbq->iocb_flag &= ~LPFC_IO_DIF; - bf_set(wqe_dif, &wqe->generic.wqe_com, 1); - } - bf_set(wqe_dbde, &wqe->fcp_iwrite.wqe_com, 1); - break; - case CMD_FCP_IREAD64_CR: - /* word3 iocb=iotag wqe=payload_offset_len */ - /* Add the FCP_CMD and FCP_RSP sizes to get the offset */ - wqe->fcp_iread.payload_offset_len = - xmit_len + sizeof(struct fcp_rsp); - /* word4 iocb=parameter wqe=total_xfer_length memcpy */ - /* word5 iocb=initial_xfer_len wqe=initial_xfer_len memcpy */ - bf_set(wqe_erp, &wqe->fcp_iread.wqe_com, - iocbq->iocb.ulpFCP2Rcvy); - bf_set(wqe_lnk, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpXS); - /* Always open the exchange */ - bf_set(wqe_xc, &wqe->fcp_iread.wqe_com, 0); - bf_set(wqe_iod, &wqe->fcp_iread.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_lenloc, &wqe->fcp_iread.wqe_com, - LPFC_WQE_LENLOC_WORD4); - bf_set(wqe_ebde_cnt, &wqe->fcp_iread.wqe_com, 0); - bf_set(wqe_pu, &wqe->fcp_iread.wqe_com, iocbq->iocb.ulpPU); - if (iocbq->iocb_flag & LPFC_IO_DIF) { - iocbq->iocb_flag &= ~LPFC_IO_DIF; - bf_set(wqe_dif, &wqe->generic.wqe_com, 1); - } - bf_set(wqe_dbde, &wqe->fcp_iread.wqe_com, 1); - break; - case CMD_FCP_ICMND64_CR: - /* word3 iocb=IO_TAG wqe=reserved */ - wqe->fcp_icmd.rsrvd3 = 0; - bf_set(wqe_pu, &wqe->fcp_icmd.wqe_com, 0); - /* Always open the exchange */ - bf_set(wqe_xc, &wqe->fcp_icmd.wqe_com, 0); - bf_set(wqe_dbde, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_iod, &wqe->fcp_icmd.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_qosd, &wqe->fcp_icmd.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->fcp_icmd.wqe_com, - LPFC_WQE_LENLOC_NONE); - bf_set(wqe_ebde_cnt, &wqe->fcp_icmd.wqe_com, 0); - break; - case CMD_GEN_REQUEST64_CR: - /* For this command calculate the xmit length of the - * request bde. - */ - xmit_len = 0; - numBdes = iocbq->iocb.un.genreq64.bdl.bdeSize / - sizeof(struct ulp_bde64); - for (i = 0; i < numBdes; i++) { - bde.tus.w = le32_to_cpu(bpl[i].tus.w); - if (bde.tus.f.bdeFlags != BUFF_TYPE_BDE_64) - break; - xmit_len += bde.tus.f.bdeSize; - } - /* word3 iocb=IO_TAG wqe=request_payload_len */ - wqe->gen_req.request_payload_len = xmit_len; - /* word4 iocb=parameter wqe=relative_offset memcpy */ - /* word5 [rctl, type, df_ctl, la] copied in memcpy */ - /* word6 context tag copied in memcpy */ - if (iocbq->iocb.ulpCt_h || iocbq->iocb.ulpCt_l) { - ct = ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2015 Invalid CT %x command 0x%x\n", - ct, iocbq->iocb.ulpCommand); - return IOCB_ERROR; - } - bf_set(wqe_ct, &wqe->gen_req.wqe_com, 0); - bf_set(wqe_tmo, &wqe->gen_req.wqe_com, iocbq->iocb.ulpTimeout); - bf_set(wqe_pu, &wqe->gen_req.wqe_com, iocbq->iocb.ulpPU); - bf_set(wqe_dbde, &wqe->gen_req.wqe_com, 1); - bf_set(wqe_iod, &wqe->gen_req.wqe_com, LPFC_WQE_IOD_READ); - bf_set(wqe_qosd, &wqe->gen_req.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->gen_req.wqe_com, LPFC_WQE_LENLOC_NONE); - bf_set(wqe_ebde_cnt, &wqe->gen_req.wqe_com, 0); - command_type = OTHER_COMMAND; - break; - case CMD_XMIT_ELS_RSP64_CX: - ndlp = (struct lpfc_nodelist *)iocbq->context1; - /* words0-2 BDE memcpy */ - /* word3 iocb=iotag32 wqe=response_payload_len */ - wqe->xmit_els_rsp.response_payload_len = xmit_len; - /* word4 iocb=did wge=rsvd. */ - wqe->xmit_els_rsp.rsvd4 = 0; - /* word5 iocb=rsvd wge=did */ - bf_set(wqe_els_did, &wqe->xmit_els_rsp.wqe_dest, - iocbq->iocb.un.elsreq64.remoteID); - bf_set(wqe_ct, &wqe->xmit_els_rsp.wqe_com, - ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); - bf_set(wqe_pu, &wqe->xmit_els_rsp.wqe_com, iocbq->iocb.ulpPU); - bf_set(wqe_rcvoxid, &wqe->xmit_els_rsp.wqe_com, - iocbq->iocb.unsli3.rcvsli3.ox_id); - if (!iocbq->iocb.ulpCt_h && iocbq->iocb.ulpCt_l) - bf_set(wqe_ctxt_tag, &wqe->xmit_els_rsp.wqe_com, - phba->vpi_ids[iocbq->vport->vpi]); - bf_set(wqe_dbde, &wqe->xmit_els_rsp.wqe_com, 1); - bf_set(wqe_iod, &wqe->xmit_els_rsp.wqe_com, LPFC_WQE_IOD_WRITE); - bf_set(wqe_qosd, &wqe->xmit_els_rsp.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->xmit_els_rsp.wqe_com, - LPFC_WQE_LENLOC_WORD3); - bf_set(wqe_ebde_cnt, &wqe->xmit_els_rsp.wqe_com, 0); - bf_set(wqe_rsp_temp_rpi, &wqe->xmit_els_rsp, - phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]); - pcmd = (uint32_t *) (((struct lpfc_dmabuf *) - iocbq->context2)->virt); - if (phba->fc_topology == LPFC_TOPOLOGY_LOOP) { - bf_set(els_req64_sp, &wqe->els_req, 1); - bf_set(els_req64_sid, &wqe->els_req, - iocbq->vport->fc_myDID); - bf_set(wqe_ct, &wqe->els_req.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->els_req.wqe_com, - phba->vpi_ids[phba->pport->vpi]); - } - command_type = OTHER_COMMAND; - break; - case CMD_CLOSE_XRI_CN: - case CMD_ABORT_XRI_CN: - case CMD_ABORT_XRI_CX: - /* words 0-2 memcpy should be 0 rserved */ - /* port will send abts */ - abrt_iotag = iocbq->iocb.un.acxri.abortContextTag; - if (abrt_iotag != 0 && abrt_iotag <= phba->sli.last_iotag) { - abrtiocbq = phba->sli.iocbq_lookup[abrt_iotag]; - fip = abrtiocbq->iocb_flag & LPFC_FIP_ELS_ID_MASK; - } else - fip = 0; - - if ((iocbq->iocb.ulpCommand == CMD_CLOSE_XRI_CN) || fip) - /* - * The link is down, or the command was ELS_FIP - * so the fw does not need to send abts - * on the wire. - */ - bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); - else - bf_set(abort_cmd_ia, &wqe->abort_cmd, 0); - bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); - /* word5 iocb=CONTEXT_TAG|IO_TAG wqe=reserved */ - wqe->abort_cmd.rsrvd5 = 0; - bf_set(wqe_ct, &wqe->abort_cmd.wqe_com, - ((iocbq->iocb.ulpCt_h << 1) | iocbq->iocb.ulpCt_l)); - abort_tag = iocbq->iocb.un.acxri.abortIoTag; - /* - * The abort handler will send us CMD_ABORT_XRI_CN or - * CMD_CLOSE_XRI_CN and the fw only accepts CMD_ABORT_XRI_CX - */ - bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com, - LPFC_WQE_LENLOC_NONE); - cmnd = CMD_ABORT_XRI_CX; - command_type = OTHER_COMMAND; - xritag = 0; - break; - case CMD_XMIT_BLS_RSP64_CX: - ndlp = (struct lpfc_nodelist *)iocbq->context1; - /* As BLS ABTS RSP WQE is very different from other WQEs, - * we re-construct this WQE here based on information in - * iocbq from scratch. - */ - memset(wqe, 0, sizeof(union lpfc_wqe)); - /* OX_ID is invariable to who sent ABTS to CT exchange */ - bf_set(xmit_bls_rsp64_oxid, &wqe->xmit_bls_rsp, - bf_get(lpfc_abts_oxid, &iocbq->iocb.un.bls_rsp)); - if (bf_get(lpfc_abts_orig, &iocbq->iocb.un.bls_rsp) == - LPFC_ABTS_UNSOL_INT) { - /* ABTS sent by initiator to CT exchange, the - * RX_ID field will be filled with the newly - * allocated responder XRI. - */ - bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, - iocbq->sli4_xritag); - } else { - /* ABTS sent by responder to CT exchange, the - * RX_ID field will be filled with the responder - * RX_ID from ABTS. - */ - bf_set(xmit_bls_rsp64_rxid, &wqe->xmit_bls_rsp, - bf_get(lpfc_abts_rxid, &iocbq->iocb.un.bls_rsp)); - } - bf_set(xmit_bls_rsp64_seqcnthi, &wqe->xmit_bls_rsp, 0xffff); - bf_set(wqe_xmit_bls_pt, &wqe->xmit_bls_rsp.wqe_dest, 0x1); - - /* Use CT=VPI */ - bf_set(wqe_els_did, &wqe->xmit_bls_rsp.wqe_dest, - ndlp->nlp_DID); - bf_set(xmit_bls_rsp64_temprpi, &wqe->xmit_bls_rsp, - iocbq->iocb.ulpContext); - bf_set(wqe_ct, &wqe->xmit_bls_rsp.wqe_com, 1); - bf_set(wqe_ctxt_tag, &wqe->xmit_bls_rsp.wqe_com, - phba->vpi_ids[phba->pport->vpi]); - bf_set(wqe_qosd, &wqe->xmit_bls_rsp.wqe_com, 1); - bf_set(wqe_lenloc, &wqe->xmit_bls_rsp.wqe_com, - LPFC_WQE_LENLOC_NONE); - /* Overwrite the pre-set comnd type with OTHER_COMMAND */ - command_type = OTHER_COMMAND; - if (iocbq->iocb.un.xseq64.w5.hcsw.Rctl == FC_RCTL_BA_RJT) { - bf_set(xmit_bls_rsp64_rjt_vspec, &wqe->xmit_bls_rsp, - bf_get(lpfc_vndr_code, &iocbq->iocb.un.bls_rsp)); - bf_set(xmit_bls_rsp64_rjt_expc, &wqe->xmit_bls_rsp, - bf_get(lpfc_rsn_expln, &iocbq->iocb.un.bls_rsp)); - bf_set(xmit_bls_rsp64_rjt_rsnc, &wqe->xmit_bls_rsp, - bf_get(lpfc_rsn_code, &iocbq->iocb.un.bls_rsp)); - } - - break; - case CMD_XRI_ABORTED_CX: - case CMD_CREATE_XRI_CR: /* Do we expect to use this? */ - case CMD_IOCB_FCP_IBIDIR64_CR: /* bidirectional xfer */ - case CMD_FCP_TSEND64_CX: /* Target mode send xfer-ready */ - case CMD_FCP_TRSP64_CX: /* Target mode rcv */ - case CMD_FCP_AUTO_TRSP_CX: /* Auto target rsp */ - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2014 Invalid command 0x%x\n", - iocbq->iocb.ulpCommand); - return IOCB_ERROR; - break; - } - - bf_set(wqe_xri_tag, &wqe->generic.wqe_com, xritag); - bf_set(wqe_reqtag, &wqe->generic.wqe_com, iocbq->iotag); - wqe->generic.wqe_com.abort_tag = abort_tag; - bf_set(wqe_cmd_type, &wqe->generic.wqe_com, command_type); - bf_set(wqe_cmnd, &wqe->generic.wqe_com, cmnd); - bf_set(wqe_class, &wqe->generic.wqe_com, iocbq->iocb.ulpClass); - bf_set(wqe_cqid, &wqe->generic.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); - return 0; -} - -/** - * __lpfc_sli_issue_iocb_s4 - SLI4 device lockless ver of lpfc_sli_issue_iocb - * @phba: Pointer to HBA context object. - * @ring_number: SLI ring number to issue iocb on. - * @piocb: Pointer to command iocb. - * @flag: Flag indicating if this command can be put into txq. - * - * __lpfc_sli_issue_iocb_s4 is used by other functions in the driver to issue - * an iocb command to an HBA with SLI-4 interface spec. - * - * This function is called with hbalock held. The function will return success - * after it successfully submit the iocb to firmware or after adding to the - * txq. - **/ -static int -__lpfc_sli_issue_iocb_s4(struct lpfc_hba *phba, uint32_t ring_number, - struct lpfc_iocbq *piocb, uint32_t flag) -{ - struct lpfc_sglq *sglq; - union lpfc_wqe wqe; - struct lpfc_sli_ring *pring = &phba->sli.ring[ring_number]; - - if (piocb->sli4_xritag == NO_XRI) { - if (piocb->iocb.ulpCommand == CMD_ABORT_XRI_CN || - piocb->iocb.ulpCommand == CMD_CLOSE_XRI_CN) - sglq = NULL; - else { - if (pring->txq_cnt) { - if (!(flag & SLI_IOCB_RET_IOCB)) { - __lpfc_sli_ringtx_put(phba, - pring, piocb); - return IOCB_SUCCESS; - } else { - return IOCB_BUSY; - } - } else { - sglq = __lpfc_sli_get_sglq(phba, piocb); - if (!sglq) { - if (!(flag & SLI_IOCB_RET_IOCB)) { - __lpfc_sli_ringtx_put(phba, - pring, - piocb); - return IOCB_SUCCESS; - } else - return IOCB_BUSY; - } - } - } - } else if (piocb->iocb_flag & LPFC_IO_FCP) { - /* These IO's already have an XRI and a mapped sgl. */ - sglq = NULL; - } else { - /* - * This is a continuation of a commandi,(CX) so this - * sglq is on the active list - */ - sglq = __lpfc_get_active_sglq(phba, piocb->sli4_xritag); - if (!sglq) - return IOCB_ERROR; - } - - if (sglq) { - piocb->sli4_lxritag = sglq->sli4_lxritag; - piocb->sli4_xritag = sglq->sli4_xritag; - if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocb, sglq)) - return IOCB_ERROR; - } - - if (lpfc_sli4_iocb2wqe(phba, piocb, &wqe)) - return IOCB_ERROR; - - if ((piocb->iocb_flag & LPFC_IO_FCP) || - (piocb->iocb_flag & LPFC_USE_FCPWQIDX)) { - /* - * For FCP command IOCB, get a new WQ index to distribute - * WQE across the WQsr. On the other hand, for abort IOCB, - * it carries the same WQ index to the original command - * IOCB. - */ - if (piocb->iocb_flag & LPFC_IO_FCP) - piocb->fcp_wqidx = lpfc_sli4_scmd_to_wqidx_distr(phba); - if (unlikely(!phba->sli4_hba.fcp_wq)) - return IOCB_ERROR; - if (lpfc_sli4_wq_put(phba->sli4_hba.fcp_wq[piocb->fcp_wqidx], - &wqe)) - return IOCB_ERROR; - } else { - if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) - return IOCB_ERROR; - } - lpfc_sli_ringtxcmpl_put(phba, pring, piocb); - - return 0; -} - -/** - * __lpfc_sli_issue_iocb - Wrapper func of lockless version for issuing iocb - * - * This routine wraps the actual lockless version for issusing IOCB function - * pointer from the lpfc_hba struct. - * - * Return codes: - * IOCB_ERROR - Error - * IOCB_SUCCESS - Success - * IOCB_BUSY - Busy - **/ -int -__lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, - struct lpfc_iocbq *piocb, uint32_t flag) -{ - return phba->__lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); -} - -/** - * lpfc_sli_api_table_setup - Set up sli api function jump table - * @phba: The hba struct for which this call is being executed. - * @dev_grp: The HBA PCI-Device group number. - * - * This routine sets up the SLI interface API function jump table in @phba - * struct. - * Returns: 0 - success, -ENODEV - failure. - **/ -int -lpfc_sli_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) -{ - - switch (dev_grp) { - case LPFC_PCI_DEV_LP: - phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s3; - phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s3; - break; - case LPFC_PCI_DEV_OC: - phba->__lpfc_sli_issue_iocb = __lpfc_sli_issue_iocb_s4; - phba->__lpfc_sli_release_iocbq = __lpfc_sli_release_iocbq_s4; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1419 Invalid HBA PCI-device group: 0x%x\n", - dev_grp); - return -ENODEV; - break; - } - phba->lpfc_get_iocb_from_iocbq = lpfc_get_iocb_from_iocbq; - return 0; -} - -/** - * lpfc_sli_issue_iocb - Wrapper function for __lpfc_sli_issue_iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @piocb: Pointer to command iocb. - * @flag: Flag indicating if this command can be put into txq. - * - * lpfc_sli_issue_iocb is a wrapper around __lpfc_sli_issue_iocb - * function. This function gets the hbalock and calls - * __lpfc_sli_issue_iocb function and will return the error returned - * by __lpfc_sli_issue_iocb function. This wrapper is used by - * functions which do not hold hbalock. - **/ -int -lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, - struct lpfc_iocbq *piocb, uint32_t flag) -{ - unsigned long iflags; - int rc; - - spin_lock_irqsave(&phba->hbalock, iflags); - rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); - spin_unlock_irqrestore(&phba->hbalock, iflags); - - return rc; -} - -/** - * lpfc_extra_ring_setup - Extra ring setup function - * @phba: Pointer to HBA context object. - * - * This function is called while driver attaches with the - * HBA to setup the extra ring. The extra ring is used - * only when driver needs to support target mode functionality - * or IP over FC functionalities. - * - * This function is called with no lock held. - **/ -static int -lpfc_extra_ring_setup( struct lpfc_hba *phba) -{ - struct lpfc_sli *psli; - struct lpfc_sli_ring *pring; - - psli = &phba->sli; - - /* Adjust cmd/rsp ring iocb entries more evenly */ - - /* Take some away from the FCP ring */ - pring = &psli->ring[psli->fcp_ring]; - pring->numCiocb -= SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb -= SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb -= SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb -= SLI2_IOCB_RSP_R3XTRA_ENTRIES; - - /* and give them to the extra ring */ - pring = &psli->ring[psli->extra_ring]; - - pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; - - /* Setup default profile for this ring */ - pring->iotag_max = 4096; - pring->num_mask = 1; - pring->prt[0].profile = 0; /* Mask 0 */ - pring->prt[0].rctl = phba->cfg_multi_ring_rctl; - pring->prt[0].type = phba->cfg_multi_ring_type; - pring->prt[0].lpfc_sli_rcv_unsol_event = NULL; - return 0; -} - -/* lpfc_sli_abts_recover_port - Recover a port that failed an ABTS. - * @vport: pointer to virtual port object. - * @ndlp: nodelist pointer for the impacted rport. - * - * The driver calls this routine in response to a XRI ABORT CQE - * event from the port. In this event, the driver is required to - * recover its login to the rport even though its login may be valid - * from the driver's perspective. The failed ABTS notice from the - * port indicates the rport is not responding. - */ -static void -lpfc_sli_abts_recover_port(struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp) -{ - struct Scsi_Host *shost; - struct lpfc_hba *phba; - unsigned long flags = 0; - - shost = lpfc_shost_from_vport(vport); - phba = vport->phba; - if (ndlp->nlp_state != NLP_STE_MAPPED_NODE) { - lpfc_printf_log(phba, KERN_INFO, - LOG_SLI, "3093 No rport recovery needed. " - "rport in state 0x%x\n", - ndlp->nlp_state); - return; - } - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3094 Start rport recovery on shost id 0x%x " - "fc_id 0x%06x vpi 0x%x rpi 0x%x state 0x%x " - "flags 0x%x\n", - shost->host_no, ndlp->nlp_DID, - vport->vpi, ndlp->nlp_rpi, ndlp->nlp_state, - ndlp->nlp_flag); - /* - * The rport is not responding. Don't attempt ADISC recovery. - * Remove the FCP-2 flag to force a PLOGI. - */ - spin_lock_irqsave(shost->host_lock, flags); - ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; - spin_unlock_irqrestore(shost->host_lock, flags); - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - lpfc_cancel_retry_delay_tmo(vport, ndlp); - spin_lock_irqsave(shost->host_lock, flags); - ndlp->nlp_flag |= NLP_NPR_2B_DISC; - spin_unlock_irqrestore(shost->host_lock, flags); - lpfc_disc_start(vport); -} - -/* lpfc_sli_abts_err_handler - handle a failed ABTS request from an SLI3 port. - * @phba: Pointer to HBA context object. - * @iocbq: Pointer to iocb object. - * - * The async_event handler calls this routine when it receives - * an ASYNC_STATUS_CN event from the port. The port generates - * this event when an Abort Sequence request to an rport fails - * twice in succession. The abort could be originated by the - * driver or by the port. The ABTS could have been for an ELS - * or FCP IO. The port only generates this event when an ABTS - * fails to complete after one retry. - */ -static void -lpfc_sli_abts_err_handler(struct lpfc_hba *phba, - struct lpfc_iocbq *iocbq) -{ - struct lpfc_nodelist *ndlp = NULL; - uint16_t rpi = 0, vpi = 0; - struct lpfc_vport *vport = NULL; - - /* The rpi in the ulpContext is vport-sensitive. */ - vpi = iocbq->iocb.un.asyncstat.sub_ctxt_tag; - rpi = iocbq->iocb.ulpContext; - - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3092 Port generated ABTS async event " - "on vpi %d rpi %d status 0x%x\n", - vpi, rpi, iocbq->iocb.ulpStatus); - - vport = lpfc_find_vport_by_vpid(phba, vpi); - if (!vport) - goto err_exit; - ndlp = lpfc_findnode_rpi(vport, rpi); - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) - goto err_exit; - - if (iocbq->iocb.ulpStatus == IOSTAT_LOCAL_REJECT) - lpfc_sli_abts_recover_port(vport, ndlp); - return; - - err_exit: - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3095 Event Context not found, no " - "action on vpi %d rpi %d status 0x%x, reason 0x%x\n", - iocbq->iocb.ulpContext, iocbq->iocb.ulpStatus, - vpi, rpi); -} - -/* lpfc_sli4_abts_err_handler - handle a failed ABTS request from an SLI4 port. - * @phba: pointer to HBA context object. - * @ndlp: nodelist pointer for the impacted rport. - * @axri: pointer to the wcqe containing the failed exchange. - * - * The driver calls this routine when it receives an ABORT_XRI_FCP CQE from the - * port. The port generates this event when an abort exchange request to an - * rport fails twice in succession with no reply. The abort could be originated - * by the driver or by the port. The ABTS could have been for an ELS or FCP IO. - */ -void -lpfc_sli4_abts_err_handler(struct lpfc_hba *phba, - struct lpfc_nodelist *ndlp, - struct sli4_wcqe_xri_aborted *axri) -{ - struct lpfc_vport *vport; - uint32_t ext_status = 0; - - if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3115 Node Context not found, driver " - "ignoring abts err event\n"); - return; - } - - vport = ndlp->vport; - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3116 Port generated FCP XRI ABORT event on " - "vpi %d rpi %d xri x%x status 0x%x parameter x%x\n", - ndlp->vport->vpi, ndlp->nlp_rpi, - bf_get(lpfc_wcqe_xa_xri, axri), - bf_get(lpfc_wcqe_xa_status, axri), - axri->parameter); - - /* - * Catch the ABTS protocol failure case. Older OCe FW releases returned - * LOCAL_REJECT and 0 for a failed ABTS exchange and later OCe and - * LPe FW releases returned LOCAL_REJECT and SEQUENCE_TIMEOUT. - */ - ext_status = axri->parameter & WCQE_PARAM_MASK; - if ((bf_get(lpfc_wcqe_xa_status, axri) == IOSTAT_LOCAL_REJECT) && - ((ext_status == IOERR_SEQUENCE_TIMEOUT) || (ext_status == 0))) - lpfc_sli_abts_recover_port(vport, ndlp); -} - -/** - * lpfc_sli_async_event_handler - ASYNC iocb handler function - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @iocbq: Pointer to iocb object. - * - * This function is called by the slow ring event handler - * function when there is an ASYNC event iocb in the ring. - * This function is called with no lock held. - * Currently this function handles only temperature related - * ASYNC events. The function decodes the temperature sensor - * event message and posts events for the management applications. - **/ -static void -lpfc_sli_async_event_handler(struct lpfc_hba * phba, - struct lpfc_sli_ring * pring, struct lpfc_iocbq * iocbq) -{ - IOCB_t *icmd; - uint16_t evt_code; - struct temp_event temp_event_data; - struct Scsi_Host *shost; - uint32_t *iocb_w; - - icmd = &iocbq->iocb; - evt_code = icmd->un.asyncstat.evt_code; - - switch (evt_code) { - case ASYNC_TEMP_WARN: - case ASYNC_TEMP_SAFE: - temp_event_data.data = (uint32_t) icmd->ulpContext; - temp_event_data.event_type = FC_REG_TEMPERATURE_EVENT; - if (evt_code == ASYNC_TEMP_WARN) { - temp_event_data.event_code = LPFC_THRESHOLD_TEMP; - lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, - "0347 Adapter is very hot, please take " - "corrective action. temperature : %d Celsius\n", - (uint32_t) icmd->ulpContext); - } else { - temp_event_data.event_code = LPFC_NORMAL_TEMP; - lpfc_printf_log(phba, KERN_ERR, LOG_TEMP, - "0340 Adapter temperature is OK now. " - "temperature : %d Celsius\n", - (uint32_t) icmd->ulpContext); - } - - /* Send temperature change event to applications */ - shost = lpfc_shost_from_vport(phba->pport); - fc_host_post_vendor_event(shost, fc_get_event_number(), - sizeof(temp_event_data), (char *) &temp_event_data, - LPFC_NL_VENDOR_ID); - break; - case ASYNC_STATUS_CN: - lpfc_sli_abts_err_handler(phba, iocbq); - break; - default: - iocb_w = (uint32_t *) icmd; - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0346 Ring %d handler: unexpected ASYNC_STATUS" - " evt_code 0x%x\n" - "W0 0x%08x W1 0x%08x W2 0x%08x W3 0x%08x\n" - "W4 0x%08x W5 0x%08x W6 0x%08x W7 0x%08x\n" - "W8 0x%08x W9 0x%08x W10 0x%08x W11 0x%08x\n" - "W12 0x%08x W13 0x%08x W14 0x%08x W15 0x%08x\n", - pring->ringno, icmd->un.asyncstat.evt_code, - iocb_w[0], iocb_w[1], iocb_w[2], iocb_w[3], - iocb_w[4], iocb_w[5], iocb_w[6], iocb_w[7], - iocb_w[8], iocb_w[9], iocb_w[10], iocb_w[11], - iocb_w[12], iocb_w[13], iocb_w[14], iocb_w[15]); - - break; - } -} - - -/** - * lpfc_sli_setup - SLI ring setup function - * @phba: Pointer to HBA context object. - * - * lpfc_sli_setup sets up rings of the SLI interface with - * number of iocbs per ring and iotags. This function is - * called while driver attach to the HBA and before the - * interrupts are enabled. So there is no need for locking. - * - * This function always returns 0. - **/ -int -lpfc_sli_setup(struct lpfc_hba *phba) -{ - int i, totiocbsize = 0; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - - psli->num_rings = MAX_CONFIGURED_RINGS; - psli->sli_flag = 0; - psli->fcp_ring = LPFC_FCP_RING; - psli->next_ring = LPFC_FCP_NEXT_RING; - psli->extra_ring = LPFC_EXTRA_RING; - - psli->iocbq_lookup = NULL; - psli->iocbq_lookup_len = 0; - psli->last_iotag = 0; - - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - switch (i) { - case LPFC_FCP_RING: /* ring 0 - FCP */ - /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R0_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R0_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R1XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R1XTRA_ENTRIES; - pring->numCiocb += SLI2_IOCB_CMD_R3XTRA_ENTRIES; - pring->numRiocb += SLI2_IOCB_RSP_R3XTRA_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? - SLI3_IOCB_CMD_SIZE : - SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? - SLI3_IOCB_RSP_SIZE : - SLI2_IOCB_RSP_SIZE; - pring->iotag_ctr = 0; - pring->iotag_max = - (phba->cfg_hba_queue_depth * 2); - pring->fast_iotag = pring->iotag_max; - pring->num_mask = 0; - break; - case LPFC_EXTRA_RING: /* ring 1 - EXTRA */ - /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R1_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R1_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? - SLI3_IOCB_CMD_SIZE : - SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? - SLI3_IOCB_RSP_SIZE : - SLI2_IOCB_RSP_SIZE; - pring->iotag_max = phba->cfg_hba_queue_depth; - pring->num_mask = 0; - break; - case LPFC_ELS_RING: /* ring 2 - ELS / CT */ - /* numCiocb and numRiocb are used in config_port */ - pring->numCiocb = SLI2_IOCB_CMD_R2_ENTRIES; - pring->numRiocb = SLI2_IOCB_RSP_R2_ENTRIES; - pring->sizeCiocb = (phba->sli_rev == 3) ? - SLI3_IOCB_CMD_SIZE : - SLI2_IOCB_CMD_SIZE; - pring->sizeRiocb = (phba->sli_rev == 3) ? - SLI3_IOCB_RSP_SIZE : - SLI2_IOCB_RSP_SIZE; - pring->fast_iotag = 0; - pring->iotag_ctr = 0; - pring->iotag_max = 4096; - pring->lpfc_sli_rcv_async_status = - lpfc_sli_async_event_handler; - pring->num_mask = LPFC_MAX_RING_MASK; - pring->prt[0].profile = 0; /* Mask 0 */ - pring->prt[0].rctl = FC_RCTL_ELS_REQ; - pring->prt[0].type = FC_TYPE_ELS; - pring->prt[0].lpfc_sli_rcv_unsol_event = - lpfc_els_unsol_event; - pring->prt[1].profile = 0; /* Mask 1 */ - pring->prt[1].rctl = FC_RCTL_ELS_REP; - pring->prt[1].type = FC_TYPE_ELS; - pring->prt[1].lpfc_sli_rcv_unsol_event = - lpfc_els_unsol_event; - pring->prt[2].profile = 0; /* Mask 2 */ - /* NameServer Inquiry */ - pring->prt[2].rctl = FC_RCTL_DD_UNSOL_CTL; - /* NameServer */ - pring->prt[2].type = FC_TYPE_CT; - pring->prt[2].lpfc_sli_rcv_unsol_event = - lpfc_ct_unsol_event; - pring->prt[3].profile = 0; /* Mask 3 */ - /* NameServer response */ - pring->prt[3].rctl = FC_RCTL_DD_SOL_CTL; - /* NameServer */ - pring->prt[3].type = FC_TYPE_CT; - pring->prt[3].lpfc_sli_rcv_unsol_event = - lpfc_ct_unsol_event; - /* abort unsolicited sequence */ - pring->prt[4].profile = 0; /* Mask 4 */ - pring->prt[4].rctl = FC_RCTL_BA_ABTS; - pring->prt[4].type = FC_TYPE_BLS; - pring->prt[4].lpfc_sli_rcv_unsol_event = - lpfc_sli4_ct_abort_unsol_event; - break; - } - totiocbsize += (pring->numCiocb * pring->sizeCiocb) + - (pring->numRiocb * pring->sizeRiocb); - } - if (totiocbsize > MAX_SLIM_IOCB_SIZE) { - /* Too many cmd / rsp ring entries in SLI2 SLIM */ - printk(KERN_ERR "%d:0462 Too many cmd / rsp ring entries in " - "SLI2 SLIM Data: x%x x%lx\n", - phba->brd_no, totiocbsize, - (unsigned long) MAX_SLIM_IOCB_SIZE); - } - if (phba->cfg_multi_ring_support == 2) - lpfc_extra_ring_setup(phba); - - return 0; -} - -/** - * lpfc_sli_queue_setup - Queue initialization function - * @phba: Pointer to HBA context object. - * - * lpfc_sli_queue_setup sets up mailbox queues and iocb queues for each - * ring. This function also initializes ring indices of each ring. - * This function is called during the initialization of the SLI - * interface of an HBA. - * This function is called with no lock held and always returns - * 1. - **/ -int -lpfc_sli_queue_setup(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli; - struct lpfc_sli_ring *pring; - int i; - - psli = &phba->sli; - spin_lock_irq(&phba->hbalock); - INIT_LIST_HEAD(&psli->mboxq); - INIT_LIST_HEAD(&psli->mboxq_cmpl); - /* Initialize list headers for txq and txcmplq as double linked lists */ - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - pring->ringno = i; - pring->next_cmdidx = 0; - pring->local_getidx = 0; - pring->cmdidx = 0; - INIT_LIST_HEAD(&pring->txq); - INIT_LIST_HEAD(&pring->txcmplq); - INIT_LIST_HEAD(&pring->iocb_continueq); - INIT_LIST_HEAD(&pring->iocb_continue_saveq); - INIT_LIST_HEAD(&pring->postbufq); - } - spin_unlock_irq(&phba->hbalock); - return 1; -} - -/** - * lpfc_sli_mbox_sys_flush - Flush mailbox command sub-system - * @phba: Pointer to HBA context object. - * - * This routine flushes the mailbox command subsystem. It will unconditionally - * flush all the mailbox commands in the three possible stages in the mailbox - * command sub-system: pending mailbox command queue; the outstanding mailbox - * command; and completed mailbox command queue. It is caller's responsibility - * to make sure that the driver is in the proper state to flush the mailbox - * command sub-system. Namely, the posting of mailbox commands into the - * pending mailbox command queue from the various clients must be stopped; - * either the HBA is in a state that it will never works on the outstanding - * mailbox command (such as in EEH or ERATT conditions) or the outstanding - * mailbox command has been completed. - **/ -static void -lpfc_sli_mbox_sys_flush(struct lpfc_hba *phba) -{ - LIST_HEAD(completions); - struct lpfc_sli *psli = &phba->sli; - LPFC_MBOXQ_t *pmb; - unsigned long iflag; - - /* Flush all the mailbox commands in the mbox system */ - spin_lock_irqsave(&phba->hbalock, iflag); - /* The pending mailbox command queue */ - list_splice_init(&phba->sli.mboxq, &completions); - /* The outstanding active mailbox command */ - if (psli->mbox_active) { - list_add_tail(&psli->mbox_active->list, &completions); - psli->mbox_active = NULL; - psli->sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - } - /* The completed mailbox command queue */ - list_splice_init(&phba->sli.mboxq_cmpl, &completions); - spin_unlock_irqrestore(&phba->hbalock, iflag); - - /* Return all flushed mailbox commands with MBX_NOT_FINISHED status */ - while (!list_empty(&completions)) { - list_remove_head(&completions, pmb, LPFC_MBOXQ_t, list); - pmb->u.mb.mbxStatus = MBX_NOT_FINISHED; - if (pmb->mbox_cmpl) - pmb->mbox_cmpl(phba, pmb); - } -} - -/** - * lpfc_sli_host_down - Vport cleanup function - * @vport: Pointer to virtual port object. - * - * lpfc_sli_host_down is called to clean up the resources - * associated with a vport before destroying virtual - * port data structures. - * This function does following operations: - * - Free discovery resources associated with this virtual - * port. - * - Free iocbs associated with this virtual port in - * the txq. - * - Send abort for all iocb commands associated with this - * vport in txcmplq. - * - * This function is called with no lock held and always returns 1. - **/ -int -lpfc_sli_host_down(struct lpfc_vport *vport) -{ - LIST_HEAD(completions); - struct lpfc_hba *phba = vport->phba; - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - struct lpfc_iocbq *iocb, *next_iocb; - int i; - unsigned long flags = 0; - uint16_t prev_pring_flag; - - lpfc_cleanup_discovery_resources(vport); - - spin_lock_irqsave(&phba->hbalock, flags); - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - prev_pring_flag = pring->flag; - /* Only slow rings */ - if (pring->ringno == LPFC_ELS_RING) { - pring->flag |= LPFC_DEFERRED_RING_EVENT; - /* Set the lpfc data pending flag */ - set_bit(LPFC_DATA_READY, &phba->data_flags); - } - /* - * Error everything on the txq since these iocbs have not been - * given to the FW yet. - */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { - if (iocb->vport != vport) - continue; - list_move_tail(&iocb->list, &completions); - pring->txq_cnt--; - } - - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, - list) { - if (iocb->vport != vport) - continue; - lpfc_sli_issue_abort_iotag(phba, pring, iocb); - } - - pring->flag = prev_pring_flag; - } - - spin_unlock_irqrestore(&phba->hbalock, flags); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); - return 1; -} - -/** - * lpfc_sli_hba_down - Resource cleanup function for the HBA - * @phba: Pointer to HBA context object. - * - * This function cleans up all iocb, buffers, mailbox commands - * while shutting down the HBA. This function is called with no - * lock held and always returns 1. - * This function does the following to cleanup driver resources: - * - Free discovery resources for each virtual port - * - Cleanup any pending fabric iocbs - * - Iterate through the iocb txq and free each entry - * in the list. - * - Free up any buffer posted to the HBA - * - Free mailbox commands in the mailbox queue. - **/ -int -lpfc_sli_hba_down(struct lpfc_hba *phba) -{ - LIST_HEAD(completions); - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - struct lpfc_dmabuf *buf_ptr; - unsigned long flags = 0; - int i; - - /* Shutdown the mailbox command sub-system */ - lpfc_sli_mbox_sys_shutdown(phba); - - lpfc_hba_down_prep(phba); - - lpfc_fabric_abort_hba(phba); - - spin_lock_irqsave(&phba->hbalock, flags); - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - /* Only slow rings */ - if (pring->ringno == LPFC_ELS_RING) { - pring->flag |= LPFC_DEFERRED_RING_EVENT; - /* Set the lpfc data pending flag */ - set_bit(LPFC_DATA_READY, &phba->data_flags); - } - - /* - * Error everything on the txq since these iocbs have not been - * given to the FW yet. - */ - list_splice_init(&pring->txq, &completions); - pring->txq_cnt = 0; - - } - spin_unlock_irqrestore(&phba->hbalock, flags); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_DOWN); - - spin_lock_irqsave(&phba->hbalock, flags); - list_splice_init(&phba->elsbuf, &completions); - phba->elsbuf_cnt = 0; - phba->elsbuf_prev_cnt = 0; - spin_unlock_irqrestore(&phba->hbalock, flags); - - while (!list_empty(&completions)) { - list_remove_head(&completions, buf_ptr, - struct lpfc_dmabuf, list); - lpfc_mbuf_free(phba, buf_ptr->virt, buf_ptr->phys); - kfree(buf_ptr); - } - - /* Return any active mbox cmds */ - del_timer_sync(&psli->mbox_tmo); - - spin_lock_irqsave(&phba->pport->work_port_lock, flags); - phba->pport->work_port_events &= ~WORKER_MBOX_TMO; - spin_unlock_irqrestore(&phba->pport->work_port_lock, flags); - - return 1; -} - -/** - * lpfc_sli_pcimem_bcopy - SLI memory copy function - * @srcp: Source memory pointer. - * @destp: Destination memory pointer. - * @cnt: Number of words required to be copied. - * - * This function is used for copying data between driver memory - * and the SLI memory. This function also changes the endianness - * of each word if native endianness is different from SLI - * endianness. This function can be called with or without - * lock. - **/ -void -lpfc_sli_pcimem_bcopy(void *srcp, void *destp, uint32_t cnt) -{ - uint32_t *src = srcp; - uint32_t *dest = destp; - uint32_t ldata; - int i; - - for (i = 0; i < (int)cnt; i += sizeof (uint32_t)) { - ldata = *src; - ldata = le32_to_cpu(ldata); - *dest = ldata; - src++; - dest++; - } -} - - -/** - * lpfc_sli_bemem_bcopy - SLI memory copy function - * @srcp: Source memory pointer. - * @destp: Destination memory pointer. - * @cnt: Number of words required to be copied. - * - * This function is used for copying data between a data structure - * with big endian representation to local endianness. - * This function can be called with or without lock. - **/ -void -lpfc_sli_bemem_bcopy(void *srcp, void *destp, uint32_t cnt) -{ - uint32_t *src = srcp; - uint32_t *dest = destp; - uint32_t ldata; - int i; - - for (i = 0; i < (int)cnt; i += sizeof(uint32_t)) { - ldata = *src; - ldata = be32_to_cpu(ldata); - *dest = ldata; - src++; - dest++; - } -} - -/** - * lpfc_sli_ringpostbuf_put - Function to add a buffer to postbufq - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @mp: Pointer to driver buffer object. - * - * This function is called with no lock held. - * It always return zero after adding the buffer to the postbufq - * buffer list. - **/ -int -lpfc_sli_ringpostbuf_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_dmabuf *mp) -{ - /* Stick struct lpfc_dmabuf at end of postbufq so driver can look it up - later */ - spin_lock_irq(&phba->hbalock); - list_add_tail(&mp->list, &pring->postbufq); - pring->postbufq_cnt++; - spin_unlock_irq(&phba->hbalock); - return 0; -} - -/** - * lpfc_sli_get_buffer_tag - allocates a tag for a CMD_QUE_XRI64_CX buffer - * @phba: Pointer to HBA context object. - * - * When HBQ is enabled, buffers are searched based on tags. This function - * allocates a tag for buffer posted using CMD_QUE_XRI64_CX iocb. The - * tag is bit wise or-ed with QUE_BUFTAG_BIT to make sure that the tag - * does not conflict with tags of buffer posted for unsolicited events. - * The function returns the allocated tag. The function is called with - * no locks held. - **/ -uint32_t -lpfc_sli_get_buffer_tag(struct lpfc_hba *phba) -{ - spin_lock_irq(&phba->hbalock); - phba->buffer_tag_count++; - /* - * Always set the QUE_BUFTAG_BIT to distiguish between - * a tag assigned by HBQ. - */ - phba->buffer_tag_count |= QUE_BUFTAG_BIT; - spin_unlock_irq(&phba->hbalock); - return phba->buffer_tag_count; -} - -/** - * lpfc_sli_ring_taggedbuf_get - find HBQ buffer associated with given tag - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @tag: Buffer tag. - * - * Buffers posted using CMD_QUE_XRI64_CX iocb are in pring->postbufq - * list. After HBA DMA data to these buffers, CMD_IOCB_RET_XRI64_CX - * iocb is posted to the response ring with the tag of the buffer. - * This function searches the pring->postbufq list using the tag - * to find buffer associated with CMD_IOCB_RET_XRI64_CX - * iocb. If the buffer is found then lpfc_dmabuf object of the - * buffer is returned to the caller else NULL is returned. - * This function is called with no lock held. - **/ -struct lpfc_dmabuf * -lpfc_sli_ring_taggedbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - uint32_t tag) -{ - struct lpfc_dmabuf *mp, *next_mp; - struct list_head *slp = &pring->postbufq; - - /* Search postbufq, from the beginning, looking for a match on tag */ - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { - if (mp->buffer_tag == tag) { - list_del_init(&mp->list); - pring->postbufq_cnt--; - spin_unlock_irq(&phba->hbalock); - return mp; - } - } - - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0402 Cannot find virtual addr for buffer tag on " - "ring %d Data x%lx x%p x%p x%x\n", - pring->ringno, (unsigned long) tag, - slp->next, slp->prev, pring->postbufq_cnt); - - return NULL; -} - -/** - * lpfc_sli_ringpostbuf_get - search buffers for unsolicited CT and ELS events - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @phys: DMA address of the buffer. - * - * This function searches the buffer list using the dma_address - * of unsolicited event to find the driver's lpfc_dmabuf object - * corresponding to the dma_address. The function returns the - * lpfc_dmabuf object if a buffer is found else it returns NULL. - * This function is called by the ct and els unsolicited event - * handlers to get the buffer associated with the unsolicited - * event. - * - * This function is called with no lock held. - **/ -struct lpfc_dmabuf * -lpfc_sli_ringpostbuf_get(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - dma_addr_t phys) -{ - struct lpfc_dmabuf *mp, *next_mp; - struct list_head *slp = &pring->postbufq; - - /* Search postbufq, from the beginning, looking for a match on phys */ - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(mp, next_mp, &pring->postbufq, list) { - if (mp->phys == phys) { - list_del_init(&mp->list); - pring->postbufq_cnt--; - spin_unlock_irq(&phba->hbalock); - return mp; - } - } - - spin_unlock_irq(&phba->hbalock); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0410 Cannot find virtual addr for mapped buf on " - "ring %d Data x%llx x%p x%p x%x\n", - pring->ringno, (unsigned long long)phys, - slp->next, slp->prev, pring->postbufq_cnt); - return NULL; -} - -/** - * lpfc_sli_abort_els_cmpl - Completion handler for the els abort iocbs - * @phba: Pointer to HBA context object. - * @cmdiocb: Pointer to driver command iocb object. - * @rspiocb: Pointer to driver response iocb object. - * - * This function is the completion handler for the abort iocbs for - * ELS commands. This function is called from the ELS ring event - * handler with no lock held. This function frees memory resources - * associated with the abort iocb. - **/ -static void -lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - IOCB_t *irsp = &rspiocb->iocb; - uint16_t abort_iotag, abort_context; - struct lpfc_iocbq *abort_iocb = NULL; - - if (irsp->ulpStatus) { - - /* - * Assume that the port already completed and returned, or - * will return the iocb. Just Log the message. - */ - abort_context = cmdiocb->iocb.un.acxri.abortContextTag; - abort_iotag = cmdiocb->iocb.un.acxri.abortIoTag; - - spin_lock_irq(&phba->hbalock); - if (phba->sli_rev < LPFC_SLI_REV4) { - if (abort_iotag != 0 && - abort_iotag <= phba->sli.last_iotag) - abort_iocb = - phba->sli.iocbq_lookup[abort_iotag]; - } else - /* For sli4 the abort_tag is the XRI, - * so the abort routine puts the iotag of the iocb - * being aborted in the context field of the abort - * IOCB. - */ - abort_iocb = phba->sli.iocbq_lookup[abort_context]; - - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS | LOG_SLI, - "0327 Cannot abort els iocb %p " - "with tag %x context %x, abort status %x, " - "abort code %x\n", - abort_iocb, abort_iotag, abort_context, - irsp->ulpStatus, irsp->un.ulpWord[4]); - - spin_unlock_irq(&phba->hbalock); - } - lpfc_sli_release_iocbq(phba, cmdiocb); - return; -} - -/** - * lpfc_ignore_els_cmpl - Completion handler for aborted ELS command - * @phba: Pointer to HBA context object. - * @cmdiocb: Pointer to driver command iocb object. - * @rspiocb: Pointer to driver response iocb object. - * - * The function is called from SLI ring event handler with no - * lock held. This function is the completion handler for ELS commands - * which are aborted. The function frees memory resources used for - * the aborted ELS commands. - **/ -static void -lpfc_ignore_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - IOCB_t *irsp = &rspiocb->iocb; - - /* ELS cmd tag completes */ - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "0139 Ignoring ELS cmd tag x%x completion Data: " - "x%x x%x x%x\n", - irsp->ulpIoTag, irsp->ulpStatus, - irsp->un.ulpWord[4], irsp->ulpTimeout); - if (cmdiocb->iocb.ulpCommand == CMD_GEN_REQUEST64_CR) - lpfc_ct_free_iocb(phba, cmdiocb); - else - lpfc_els_free_iocb(phba, cmdiocb); - return; -} - -/** - * lpfc_sli_abort_iotag_issue - Issue abort for a command iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @cmdiocb: Pointer to driver command iocb object. - * - * This function issues an abort iocb for the provided command iocb down to - * the port. Other than the case the outstanding command iocb is an abort - * request, this function issues abort out unconditionally. This function is - * called with hbalock held. The function returns 0 when it fails due to - * memory allocation failure or when the command iocb is an abort request. - **/ -static int -lpfc_sli_abort_iotag_issue(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - struct lpfc_iocbq *abtsiocbp; - IOCB_t *icmd = NULL; - IOCB_t *iabt = NULL; - int retval; - - /* - * There are certain command types we don't want to abort. And we - * don't want to abort commands that are already in the process of - * being aborted. - */ - icmd = &cmdiocb->iocb; - if (icmd->ulpCommand == CMD_ABORT_XRI_CN || - icmd->ulpCommand == CMD_CLOSE_XRI_CN || - (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; - - /* issue ABTS for this IOCB based on iotag */ - abtsiocbp = __lpfc_sli_get_iocbq(phba); - if (abtsiocbp == NULL) - return 0; - - /* This signals the response to set the correct status - * before calling the completion handler - */ - cmdiocb->iocb_flag |= LPFC_DRIVER_ABORTED; - - iabt = &abtsiocbp->iocb; - iabt->un.acxri.abortType = ABORT_TYPE_ABTS; - iabt->un.acxri.abortContextTag = icmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) { - iabt->un.acxri.abortIoTag = cmdiocb->sli4_xritag; - iabt->un.acxri.abortContextTag = cmdiocb->iotag; - } - else - iabt->un.acxri.abortIoTag = icmd->ulpIoTag; - iabt->ulpLe = 1; - iabt->ulpClass = icmd->ulpClass; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocbp->fcp_wqidx = cmdiocb->fcp_wqidx; - if (cmdiocb->iocb_flag & LPFC_IO_FCP) - abtsiocbp->iocb_flag |= LPFC_USE_FCPWQIDX; - - if (phba->link_state >= LPFC_LINK_UP) - iabt->ulpCommand = CMD_ABORT_XRI_CN; - else - iabt->ulpCommand = CMD_CLOSE_XRI_CN; - - abtsiocbp->iocb_cmpl = lpfc_sli_abort_els_cmpl; - - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, - "0339 Abort xri x%x, original iotag x%x, " - "abort cmd iotag x%x\n", - iabt->un.acxri.abortIoTag, - iabt->un.acxri.abortContextTag, - abtsiocbp->iotag); - retval = __lpfc_sli_issue_iocb(phba, pring->ringno, abtsiocbp, 0); - - if (retval) - __lpfc_sli_release_iocbq(phba, abtsiocbp); - - /* - * Caller to this routine should check for IOCB_ERROR - * and handle it properly. This routine no longer removes - * iocb off txcmplq and call compl in case of IOCB_ERROR. - */ - return retval; -} - -/** - * lpfc_sli_issue_abort_iotag - Abort function for a command iocb - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * @cmdiocb: Pointer to driver command iocb object. - * - * This function issues an abort iocb for the provided command iocb. In case - * of unloading, the abort iocb will not be issued to commands on the ELS - * ring. Instead, the callback function shall be changed to those commands - * so that nothing happens when them finishes. This function is called with - * hbalock held. The function returns 0 when the command iocb is an abort - * request. - **/ -int -lpfc_sli_issue_abort_iotag(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, - struct lpfc_iocbq *cmdiocb) -{ - struct lpfc_vport *vport = cmdiocb->vport; - int retval = IOCB_ERROR; - IOCB_t *icmd = NULL; - - /* - * There are certain command types we don't want to abort. And we - * don't want to abort commands that are already in the process of - * being aborted. - */ - icmd = &cmdiocb->iocb; - if (icmd->ulpCommand == CMD_ABORT_XRI_CN || - icmd->ulpCommand == CMD_CLOSE_XRI_CN || - (cmdiocb->iocb_flag & LPFC_DRIVER_ABORTED) != 0) - return 0; - - /* - * If we're unloading, don't abort iocb on the ELS ring, but change - * the callback so that nothing happens when it finishes. - */ - if ((vport->load_flag & FC_UNLOADING) && - (pring->ringno == LPFC_ELS_RING)) { - if (cmdiocb->iocb_flag & LPFC_IO_FABRIC) - cmdiocb->fabric_iocb_cmpl = lpfc_ignore_els_cmpl; - else - cmdiocb->iocb_cmpl = lpfc_ignore_els_cmpl; - goto abort_iotag_exit; - } - - /* Now, we try to issue the abort to the cmdiocb out */ - retval = lpfc_sli_abort_iotag_issue(phba, pring, cmdiocb); - -abort_iotag_exit: - /* - * Caller to this routine should check for IOCB_ERROR - * and handle it properly. This routine no longer removes - * iocb off txcmplq and call compl in case of IOCB_ERROR. - */ - return retval; -} - -/** - * lpfc_sli_iocb_ring_abort - Unconditionally abort all iocbs on an iocb ring - * @phba: Pointer to HBA context object. - * @pring: Pointer to driver SLI ring object. - * - * This function aborts all iocbs in the given ring and frees all the iocb - * objects in txq. This function issues abort iocbs unconditionally for all - * the iocb commands in txcmplq. The iocbs in the txcmplq is not guaranteed - * to complete before the return of this function. The caller is not required - * to hold any locks. - **/ -static void -lpfc_sli_iocb_ring_abort(struct lpfc_hba *phba, struct lpfc_sli_ring *pring) -{ - LIST_HEAD(completions); - struct lpfc_iocbq *iocb, *next_iocb; - - if (pring->ringno == LPFC_ELS_RING) - lpfc_fabric_abort_hba(phba); - - spin_lock_irq(&phba->hbalock); - - /* Take off all the iocbs on txq for cancelling */ - list_splice_init(&pring->txq, &completions); - pring->txq_cnt = 0; - - /* Next issue ABTS for everything on the txcmplq */ - list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) - lpfc_sli_abort_iotag_issue(phba, pring, iocb); - - spin_unlock_irq(&phba->hbalock); - - /* Cancel all the IOCBs from the completions list */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); -} - -/** - * lpfc_sli_hba_iocb_abort - Abort all iocbs to an hba. - * @phba: pointer to lpfc HBA data structure. - * - * This routine will abort all pending and outstanding iocbs to an HBA. - **/ -void -lpfc_sli_hba_iocb_abort(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - struct lpfc_sli_ring *pring; - int i; - - for (i = 0; i < psli->num_rings; i++) { - pring = &psli->ring[i]; - lpfc_sli_iocb_ring_abort(phba, pring); - } -} - -/** - * lpfc_sli_validate_fcp_iocb - find commands associated with a vport or LUN - * @iocbq: Pointer to driver iocb object. - * @vport: Pointer to driver virtual port object. - * @tgt_id: SCSI ID of the target. - * @lun_id: LUN ID of the scsi device. - * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST - * - * This function acts as an iocb filter for functions which abort or count - * all FCP iocbs pending on a lun/SCSI target/SCSI host. It will return - * 0 if the filtering criteria is met for the given iocb and will return - * 1 if the filtering criteria is not met. - * If ctx_cmd == LPFC_CTX_LUN, the function returns 0 only if the - * given iocb is for the SCSI device specified by vport, tgt_id and - * lun_id parameter. - * If ctx_cmd == LPFC_CTX_TGT, the function returns 0 only if the - * given iocb is for the SCSI target specified by vport and tgt_id - * parameters. - * If ctx_cmd == LPFC_CTX_HOST, the function returns 0 only if the - * given iocb is for the SCSI host associated with the given vport. - * This function is called with no locks held. - **/ -static int -lpfc_sli_validate_fcp_iocb(struct lpfc_iocbq *iocbq, struct lpfc_vport *vport, - uint16_t tgt_id, uint64_t lun_id, - lpfc_ctx_cmd ctx_cmd) -{ - struct lpfc_scsi_buf *lpfc_cmd; - int rc = 1; - - if (!(iocbq->iocb_flag & LPFC_IO_FCP)) - return rc; - - if (iocbq->vport != vport) - return rc; - - lpfc_cmd = container_of(iocbq, struct lpfc_scsi_buf, cur_iocbq); - - if (lpfc_cmd->pCmd == NULL) - return rc; - - switch (ctx_cmd) { - case LPFC_CTX_LUN: - if ((lpfc_cmd->rdata->pnode) && - (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id) && - (scsilun_to_int(&lpfc_cmd->fcp_cmnd->fcp_lun) == lun_id)) - rc = 0; - break; - case LPFC_CTX_TGT: - if ((lpfc_cmd->rdata->pnode) && - (lpfc_cmd->rdata->pnode->nlp_sid == tgt_id)) - rc = 0; - break; - case LPFC_CTX_HOST: - rc = 0; - break; - default: - printk(KERN_ERR "%s: Unknown context cmd type, value %d\n", - __func__, ctx_cmd); - break; - } - - return rc; -} - -/** - * lpfc_sli_sum_iocb - Function to count the number of FCP iocbs pending - * @vport: Pointer to virtual port. - * @tgt_id: SCSI ID of the target. - * @lun_id: LUN ID of the scsi device. - * @ctx_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. - * - * This function returns number of FCP commands pending for the vport. - * When ctx_cmd == LPFC_CTX_LUN, the function returns number of FCP - * commands pending on the vport associated with SCSI device specified - * by tgt_id and lun_id parameters. - * When ctx_cmd == LPFC_CTX_TGT, the function returns number of FCP - * commands pending on the vport associated with SCSI target specified - * by tgt_id parameter. - * When ctx_cmd == LPFC_CTX_HOST, the function returns number of FCP - * commands pending on the vport. - * This function returns the number of iocbs which satisfy the filter. - * This function is called without any lock held. - **/ -int -lpfc_sli_sum_iocb(struct lpfc_vport *vport, uint16_t tgt_id, uint64_t lun_id, - lpfc_ctx_cmd ctx_cmd) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *iocbq; - int sum, i; - - for (i = 1, sum = 0; i <= phba->sli.last_iotag; i++) { - iocbq = phba->sli.iocbq_lookup[i]; - - if (lpfc_sli_validate_fcp_iocb (iocbq, vport, tgt_id, lun_id, - ctx_cmd) == 0) - sum++; - } - - return sum; -} - -/** - * lpfc_sli_abort_fcp_cmpl - Completion handler function for aborted FCP IOCBs - * @phba: Pointer to HBA context object - * @cmdiocb: Pointer to command iocb object. - * @rspiocb: Pointer to response iocb object. - * - * This function is called when an aborted FCP iocb completes. This - * function is called by the ring event handler with no lock held. - * This function frees the iocb. - **/ -void -lpfc_sli_abort_fcp_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, - struct lpfc_iocbq *rspiocb) -{ - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3096 ABORT_XRI_CN completing on xri x%x " - "original iotag x%x, abort cmd iotag x%x " - "status 0x%x, reason 0x%x\n", - cmdiocb->iocb.un.acxri.abortContextTag, - cmdiocb->iocb.un.acxri.abortIoTag, - cmdiocb->iotag, rspiocb->iocb.ulpStatus, - rspiocb->iocb.un.ulpWord[4]); - lpfc_sli_release_iocbq(phba, cmdiocb); - return; -} - -/** - * lpfc_sli_abort_iocb - issue abort for all commands on a host/target/LUN - * @vport: Pointer to virtual port. - * @pring: Pointer to driver SLI ring object. - * @tgt_id: SCSI ID of the target. - * @lun_id: LUN ID of the scsi device. - * @abort_cmd: LPFC_CTX_LUN/LPFC_CTX_TGT/LPFC_CTX_HOST. - * - * This function sends an abort command for every SCSI command - * associated with the given virtual port pending on the ring - * filtered by lpfc_sli_validate_fcp_iocb function. - * When abort_cmd == LPFC_CTX_LUN, the function sends abort only to the - * FCP iocbs associated with lun specified by tgt_id and lun_id - * parameters - * When abort_cmd == LPFC_CTX_TGT, the function sends abort only to the - * FCP iocbs associated with SCSI target specified by tgt_id parameter. - * When abort_cmd == LPFC_CTX_HOST, the function sends abort to all - * FCP iocbs associated with virtual port. - * This function returns number of iocbs it failed to abort. - * This function is called with no locks held. - **/ -int -lpfc_sli_abort_iocb(struct lpfc_vport *vport, struct lpfc_sli_ring *pring, - uint16_t tgt_id, uint64_t lun_id, lpfc_ctx_cmd abort_cmd) -{ - struct lpfc_hba *phba = vport->phba; - struct lpfc_iocbq *iocbq; - struct lpfc_iocbq *abtsiocb; - IOCB_t *cmd = NULL; - int errcnt = 0, ret_val = 0; - int i; - - for (i = 1; i <= phba->sli.last_iotag; i++) { - iocbq = phba->sli.iocbq_lookup[i]; - - if (lpfc_sli_validate_fcp_iocb(iocbq, vport, tgt_id, lun_id, - abort_cmd) != 0) - continue; - - /* issue ABTS for this IOCB based on iotag */ - abtsiocb = lpfc_sli_get_iocbq(phba); - if (abtsiocb == NULL) { - errcnt++; - continue; - } - - cmd = &iocbq->iocb; - abtsiocb->iocb.un.acxri.abortType = ABORT_TYPE_ABTS; - abtsiocb->iocb.un.acxri.abortContextTag = cmd->ulpContext; - if (phba->sli_rev == LPFC_SLI_REV4) - abtsiocb->iocb.un.acxri.abortIoTag = iocbq->sli4_xritag; - else - abtsiocb->iocb.un.acxri.abortIoTag = cmd->ulpIoTag; - abtsiocb->iocb.ulpLe = 1; - abtsiocb->iocb.ulpClass = cmd->ulpClass; - abtsiocb->vport = phba->pport; - - /* ABTS WQE must go to the same WQ as the WQE to be aborted */ - abtsiocb->fcp_wqidx = iocbq->fcp_wqidx; - if (iocbq->iocb_flag & LPFC_IO_FCP) - abtsiocb->iocb_flag |= LPFC_USE_FCPWQIDX; - - if (lpfc_is_link_up(phba)) - abtsiocb->iocb.ulpCommand = CMD_ABORT_XRI_CN; - else - abtsiocb->iocb.ulpCommand = CMD_CLOSE_XRI_CN; - - /* Setup callback routine and issue the command. */ - abtsiocb->iocb_cmpl = lpfc_sli_abort_fcp_cmpl; - ret_val = lpfc_sli_issue_iocb(phba, pring->ringno, - abtsiocb, 0); - if (ret_val == IOCB_ERROR) { - lpfc_sli_release_iocbq(phba, abtsiocb); - errcnt++; - continue; - } - } - - return errcnt; -} - -/** - * lpfc_sli_wake_iocb_wait - lpfc_sli_issue_iocb_wait's completion handler - * @phba: Pointer to HBA context object. - * @cmdiocbq: Pointer to command iocb. - * @rspiocbq: Pointer to response iocb. - * - * This function is the completion handler for iocbs issued using - * lpfc_sli_issue_iocb_wait function. This function is called by the - * ring event handler function without any lock held. This function - * can be called from both worker thread context and interrupt - * context. This function also can be called from other thread which - * cleans up the SLI layer objects. - * This function copy the contents of the response iocb to the - * response iocb memory object provided by the caller of - * lpfc_sli_issue_iocb_wait and then wakes up the thread which - * sleeps for the iocb completion. - **/ -static void -lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, - struct lpfc_iocbq *cmdiocbq, - struct lpfc_iocbq *rspiocbq) -{ - wait_queue_head_t *pdone_q; - unsigned long iflags; - struct lpfc_scsi_buf *lpfc_cmd; - - spin_lock_irqsave(&phba->hbalock, iflags); - cmdiocbq->iocb_flag |= LPFC_IO_WAKE; - if (cmdiocbq->context2 && rspiocbq) - memcpy(&((struct lpfc_iocbq *)cmdiocbq->context2)->iocb, - &rspiocbq->iocb, sizeof(IOCB_t)); - - /* Set the exchange busy flag for task management commands */ - if ((cmdiocbq->iocb_flag & LPFC_IO_FCP) && - !(cmdiocbq->iocb_flag & LPFC_IO_LIBDFC)) { - lpfc_cmd = container_of(cmdiocbq, struct lpfc_scsi_buf, - cur_iocbq); - lpfc_cmd->exch_busy = rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY; - } - - pdone_q = cmdiocbq->context_un.wait_queue; - if (pdone_q) - wake_up(pdone_q); - spin_unlock_irqrestore(&phba->hbalock, iflags); - return; -} - -/** - * lpfc_chk_iocb_flg - Test IOCB flag with lock held. - * @phba: Pointer to HBA context object.. - * @piocbq: Pointer to command iocb. - * @flag: Flag to test. - * - * This routine grabs the hbalock and then test the iocb_flag to - * see if the passed in flag is set. - * Returns: - * 1 if flag is set. - * 0 if flag is not set. - **/ -static int -lpfc_chk_iocb_flg(struct lpfc_hba *phba, - struct lpfc_iocbq *piocbq, uint32_t flag) -{ - unsigned long iflags; - int ret; - - spin_lock_irqsave(&phba->hbalock, iflags); - ret = piocbq->iocb_flag & flag; - spin_unlock_irqrestore(&phba->hbalock, iflags); - return ret; - -} - -/** - * lpfc_sli_issue_iocb_wait - Synchronous function to issue iocb commands - * @phba: Pointer to HBA context object.. - * @pring: Pointer to sli ring. - * @piocb: Pointer to command iocb. - * @prspiocbq: Pointer to response iocb. - * @timeout: Timeout in number of seconds. - * - * This function issues the iocb to firmware and waits for the - * iocb to complete. If the iocb command is not - * completed within timeout seconds, it returns IOCB_TIMEDOUT. - * Caller should not free the iocb resources if this function - * returns IOCB_TIMEDOUT. - * The function waits for the iocb completion using an - * non-interruptible wait. - * This function will sleep while waiting for iocb completion. - * So, this function should not be called from any context which - * does not allow sleeping. Due to the same reason, this function - * cannot be called with interrupt disabled. - * This function assumes that the iocb completions occur while - * this function sleep. So, this function cannot be called from - * the thread which process iocb completion for this ring. - * This function clears the iocb_flag of the iocb object before - * issuing the iocb and the iocb completion handler sets this - * flag and wakes this thread when the iocb completes. - * The contents of the response iocb will be copied to prspiocbq - * by the completion handler when the command completes. - * This function returns IOCB_SUCCESS when success. - * This function is called with no lock held. - **/ -int -lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba, - uint32_t ring_number, - struct lpfc_iocbq *piocb, - struct lpfc_iocbq *prspiocbq, - uint32_t timeout) -{ - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); - long timeleft, timeout_req = 0; - int retval = IOCB_SUCCESS; - uint32_t creg_val; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - /* - * If the caller has provided a response iocbq buffer, then context2 - * is NULL or its an error. - */ - if (prspiocbq) { - if (piocb->context2) - return IOCB_ERROR; - piocb->context2 = prspiocbq; - } - - piocb->iocb_cmpl = lpfc_sli_wake_iocb_wait; - piocb->context_un.wait_queue = &done_q; - piocb->iocb_flag &= ~LPFC_IO_WAKE; - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - if (lpfc_readl(phba->HCregaddr, &creg_val)) - return IOCB_ERROR; - creg_val |= (HC_R0INT_ENA << LPFC_FCP_RING); - writel(creg_val, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - - retval = lpfc_sli_issue_iocb(phba, ring_number, piocb, - SLI_IOCB_RET_IOCB); - if (retval == IOCB_SUCCESS) { - timeout_req = timeout * HZ; - timeleft = wait_event_timeout(done_q, - lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE), - timeout_req); - - if (piocb->iocb_flag & LPFC_IO_WAKE) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0331 IOCB wake signaled\n"); - } else if (timeleft == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0338 IOCB wait timeout error - no " - "wake response Data x%x\n", timeout); - retval = IOCB_TIMEDOUT; - } else { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0330 IOCB wake NOT set, " - "Data x%x x%lx\n", - timeout, (timeleft / jiffies)); - retval = IOCB_TIMEDOUT; - } - } else if (retval == IOCB_BUSY) { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2818 Max IOCBs %d txq cnt %d txcmplq cnt %d\n", - phba->iocb_cnt, pring->txq_cnt, pring->txcmplq_cnt); - return retval; - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0332 IOCB wait issue failed, Data x%x\n", - retval); - retval = IOCB_ERROR; - } - - if (phba->cfg_poll & DISABLE_FCP_RING_INT) { - if (lpfc_readl(phba->HCregaddr, &creg_val)) - return IOCB_ERROR; - creg_val &= ~(HC_R0INT_ENA << LPFC_FCP_RING); - writel(creg_val, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - - if (prspiocbq) - piocb->context2 = NULL; - - piocb->context_un.wait_queue = NULL; - piocb->iocb_cmpl = NULL; - return retval; -} - -/** - * lpfc_sli_issue_mbox_wait - Synchronous function to issue mailbox - * @phba: Pointer to HBA context object. - * @pmboxq: Pointer to driver mailbox object. - * @timeout: Timeout in number of seconds. - * - * This function issues the mailbox to firmware and waits for the - * mailbox command to complete. If the mailbox command is not - * completed within timeout seconds, it returns MBX_TIMEOUT. - * The function waits for the mailbox completion using an - * interruptible wait. If the thread is woken up due to a - * signal, MBX_TIMEOUT error is returned to the caller. Caller - * should not free the mailbox resources, if this function returns - * MBX_TIMEOUT. - * This function will sleep while waiting for mailbox completion. - * So, this function should not be called from any context which - * does not allow sleeping. Due to the same reason, this function - * cannot be called with interrupt disabled. - * This function assumes that the mailbox completion occurs while - * this function sleep. So, this function cannot be called from - * the worker thread which processes mailbox completion. - * This function is called in the context of HBA management - * applications. - * This function returns MBX_SUCCESS when successful. - * This function is called with no lock held. - **/ -int -lpfc_sli_issue_mbox_wait(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq, - uint32_t timeout) -{ - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(done_q); - int retval; - unsigned long flag; - - /* The caller must leave context1 empty. */ - if (pmboxq->context1) - return MBX_NOT_FINISHED; - - pmboxq->mbox_flag &= ~LPFC_MBX_WAKE; - /* setup wake call as IOCB callback */ - pmboxq->mbox_cmpl = lpfc_sli_wake_mbox_wait; - /* setup context field to pass wait_queue pointer to wake function */ - pmboxq->context1 = &done_q; - - /* now issue the command */ - retval = lpfc_sli_issue_mbox(phba, pmboxq, MBX_NOWAIT); - if (retval == MBX_BUSY || retval == MBX_SUCCESS) { - wait_event_interruptible_timeout(done_q, - pmboxq->mbox_flag & LPFC_MBX_WAKE, - timeout * HZ); - - spin_lock_irqsave(&phba->hbalock, flag); - pmboxq->context1 = NULL; - /* - * if LPFC_MBX_WAKE flag is set the mailbox is completed - * else do not free the resources. - */ - if (pmboxq->mbox_flag & LPFC_MBX_WAKE) { - retval = MBX_SUCCESS; - lpfc_sli4_swap_str(phba, pmboxq); - } else { - retval = MBX_TIMEOUT; - pmboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - } - spin_unlock_irqrestore(&phba->hbalock, flag); - } - - return retval; -} - -/** - * lpfc_sli_mbox_sys_shutdown - shutdown mailbox command sub-system - * @phba: Pointer to HBA context. - * - * This function is called to shutdown the driver's mailbox sub-system. - * It first marks the mailbox sub-system is in a block state to prevent - * the asynchronous mailbox command from issued off the pending mailbox - * command queue. If the mailbox command sub-system shutdown is due to - * HBA error conditions such as EEH or ERATT, this routine shall invoke - * the mailbox sub-system flush routine to forcefully bring down the - * mailbox sub-system. Otherwise, if it is due to normal condition (such - * as with offline or HBA function reset), this routine will wait for the - * outstanding mailbox command to complete before invoking the mailbox - * sub-system flush routine to gracefully bring down mailbox sub-system. - **/ -void -lpfc_sli_mbox_sys_shutdown(struct lpfc_hba *phba) -{ - struct lpfc_sli *psli = &phba->sli; - unsigned long timeout; - - timeout = msecs_to_jiffies(LPFC_MBOX_TMO * 1000) + jiffies; - - spin_lock_irq(&phba->hbalock); - psli->sli_flag |= LPFC_SLI_ASYNC_MBX_BLK; - - if (psli->sli_flag & LPFC_SLI_ACTIVE) { - /* Determine how long we might wait for the active mailbox - * command to be gracefully completed by firmware. - */ - if (phba->sli.mbox_active) - timeout = msecs_to_jiffies(lpfc_mbox_tmo_val(phba, - phba->sli.mbox_active) * - 1000) + jiffies; - spin_unlock_irq(&phba->hbalock); - - while (phba->sli.mbox_active) { - /* Check active mailbox complete status every 2ms */ - msleep(2); - if (time_after(jiffies, timeout)) - /* Timeout, let the mailbox flush routine to - * forcefully release active mailbox command - */ - break; - } - } else - spin_unlock_irq(&phba->hbalock); - - lpfc_sli_mbox_sys_flush(phba); -} - -/** - * lpfc_sli_eratt_read - read sli-3 error attention events - * @phba: Pointer to HBA context. - * - * This function is called to read the SLI3 device error attention registers - * for possible error attention events. The caller must hold the hostlock - * with spin_lock_irq(). - * - * This function returns 1 when there is Error Attention in the Host Attention - * Register and returns 0 otherwise. - **/ -static int -lpfc_sli_eratt_read(struct lpfc_hba *phba) -{ - uint32_t ha_copy; - - /* Read chip Host Attention (HA) register */ - if (lpfc_readl(phba->HAregaddr, &ha_copy)) - goto unplug_err; - - if (ha_copy & HA_ERATT) { - /* Read host status register to retrieve error event */ - if (lpfc_sli_read_hs(phba)) - goto unplug_err; - - /* Check if there is a deferred error condition is active */ - if ((HS_FFER1 & phba->work_hs) && - ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | - HS_FFER6 | HS_FFER7 | HS_FFER8) & phba->work_hs)) { - phba->hba_flag |= DEFER_ERATT; - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); - } - - /* Set the driver HA work bitmap */ - phba->work_ha |= HA_ERATT; - /* Indicate polling handles this ERATT */ - phba->hba_flag |= HBA_ERATT_HANDLED; - return 1; - } - return 0; - -unplug_err: - /* Set the driver HS work bitmap */ - phba->work_hs |= UNPLUG_ERR; - /* Set the driver HA work bitmap */ - phba->work_ha |= HA_ERATT; - /* Indicate polling handles this ERATT */ - phba->hba_flag |= HBA_ERATT_HANDLED; - return 1; -} - -/** - * lpfc_sli4_eratt_read - read sli-4 error attention events - * @phba: Pointer to HBA context. - * - * This function is called to read the SLI4 device error attention registers - * for possible error attention events. The caller must hold the hostlock - * with spin_lock_irq(). - * - * This function returns 1 when there is Error Attention in the Host Attention - * Register and returns 0 otherwise. - **/ -static int -lpfc_sli4_eratt_read(struct lpfc_hba *phba) -{ - uint32_t uerr_sta_hi, uerr_sta_lo; - uint32_t if_type, portsmphr; - struct lpfc_register portstat_reg; - - /* - * For now, use the SLI4 device internal unrecoverable error - * registers for error attention. This can be changed later. - */ - if_type = bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf); - switch (if_type) { - case LPFC_SLI_INTF_IF_TYPE_0: - if (lpfc_readl(phba->sli4_hba.u.if_type0.UERRLOregaddr, - &uerr_sta_lo) || - lpfc_readl(phba->sli4_hba.u.if_type0.UERRHIregaddr, - &uerr_sta_hi)) { - phba->work_hs |= UNPLUG_ERR; - phba->work_ha |= HA_ERATT; - phba->hba_flag |= HBA_ERATT_HANDLED; - return 1; - } - if ((~phba->sli4_hba.ue_mask_lo & uerr_sta_lo) || - (~phba->sli4_hba.ue_mask_hi & uerr_sta_hi)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "1423 HBA Unrecoverable error: " - "uerr_lo_reg=0x%x, uerr_hi_reg=0x%x, " - "ue_mask_lo_reg=0x%x, " - "ue_mask_hi_reg=0x%x\n", - uerr_sta_lo, uerr_sta_hi, - phba->sli4_hba.ue_mask_lo, - phba->sli4_hba.ue_mask_hi); - phba->work_status[0] = uerr_sta_lo; - phba->work_status[1] = uerr_sta_hi; - phba->work_ha |= HA_ERATT; - phba->hba_flag |= HBA_ERATT_HANDLED; - return 1; - } - break; - case LPFC_SLI_INTF_IF_TYPE_2: - if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, - &portstat_reg.word0) || - lpfc_readl(phba->sli4_hba.PSMPHRregaddr, - &portsmphr)){ - phba->work_hs |= UNPLUG_ERR; - phba->work_ha |= HA_ERATT; - phba->hba_flag |= HBA_ERATT_HANDLED; - return 1; - } - if (bf_get(lpfc_sliport_status_err, &portstat_reg)) { - phba->work_status[0] = - readl(phba->sli4_hba.u.if_type2.ERR1regaddr); - phba->work_status[1] = - readl(phba->sli4_hba.u.if_type2.ERR2regaddr); - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2885 Port Status Event: " - "port status reg 0x%x, " - "port smphr reg 0x%x, " - "error 1=0x%x, error 2=0x%x\n", - portstat_reg.word0, - portsmphr, - phba->work_status[0], - phba->work_status[1]); - phba->work_ha |= HA_ERATT; - phba->hba_flag |= HBA_ERATT_HANDLED; - return 1; - } - break; - case LPFC_SLI_INTF_IF_TYPE_1: - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2886 HBA Error Attention on unsupported " - "if type %d.", if_type); - return 1; - } - - return 0; -} - -/** - * lpfc_sli_check_eratt - check error attention events - * @phba: Pointer to HBA context. - * - * This function is called from timer soft interrupt context to check HBA's - * error attention register bit for error attention events. - * - * This function returns 1 when there is Error Attention in the Host Attention - * Register and returns 0 otherwise. - **/ -int -lpfc_sli_check_eratt(struct lpfc_hba *phba) -{ - uint32_t ha_copy; - - /* If somebody is waiting to handle an eratt, don't process it - * here. The brdkill function will do this. - */ - if (phba->link_flag & LS_IGNORE_ERATT) - return 0; - - /* Check if interrupt handler handles this ERATT */ - spin_lock_irq(&phba->hbalock); - if (phba->hba_flag & HBA_ERATT_HANDLED) { - /* Interrupt handler has handled ERATT */ - spin_unlock_irq(&phba->hbalock); - return 0; - } - - /* - * If there is deferred error attention, do not check for error - * attention - */ - if (unlikely(phba->hba_flag & DEFER_ERATT)) { - spin_unlock_irq(&phba->hbalock); - return 0; - } - - /* If PCI channel is offline, don't process it */ - if (unlikely(pci_channel_offline(phba->pcidev))) { - spin_unlock_irq(&phba->hbalock); - return 0; - } - - switch (phba->sli_rev) { - case LPFC_SLI_REV2: - case LPFC_SLI_REV3: - /* Read chip Host Attention (HA) register */ - ha_copy = lpfc_sli_eratt_read(phba); - break; - case LPFC_SLI_REV4: - /* Read device Uncoverable Error (UERR) registers */ - ha_copy = lpfc_sli4_eratt_read(phba); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0299 Invalid SLI revision (%d)\n", - phba->sli_rev); - ha_copy = 0; - break; - } - spin_unlock_irq(&phba->hbalock); - - return ha_copy; -} - -/** - * lpfc_intr_state_check - Check device state for interrupt handling - * @phba: Pointer to HBA context. - * - * This inline routine checks whether a device or its PCI slot is in a state - * that the interrupt should be handled. - * - * This function returns 0 if the device or the PCI slot is in a state that - * interrupt should be handled, otherwise -EIO. - */ -static inline int -lpfc_intr_state_check(struct lpfc_hba *phba) -{ - /* If the pci channel is offline, ignore all the interrupts */ - if (unlikely(pci_channel_offline(phba->pcidev))) - return -EIO; - - /* Update device level interrupt statistics */ - phba->sli.slistat.sli_intr++; - - /* Ignore all interrupts during initialization. */ - if (unlikely(phba->link_state < LPFC_LINK_DOWN)) - return -EIO; - - return 0; -} - -/** - * lpfc_sli_sp_intr_handler - Slow-path interrupt handler to SLI-3 device - * @irq: Interrupt number. - * @dev_id: The device context pointer. - * - * This function is directly called from the PCI layer as an interrupt - * service routine when device with SLI-3 interface spec is enabled with - * MSI-X multi-message interrupt mode and there are slow-path events in - * the HBA. However, when the device is enabled with either MSI or Pin-IRQ - * interrupt mode, this function is called as part of the device-level - * interrupt handler. When the PCI slot is in error recovery or the HBA - * is undergoing initialization, the interrupt handler will not process - * the interrupt. The link attention and ELS ring attention events are - * handled by the worker thread. The interrupt handler signals the worker - * thread and returns for these events. This function is called without - * any lock held. It gets the hbalock to access and update SLI data - * structures. - * - * This function returns IRQ_HANDLED when interrupt is handled else it - * returns IRQ_NONE. - **/ -irqreturn_t -lpfc_sli_sp_intr_handler(int irq, void *dev_id) -{ - struct lpfc_hba *phba; - uint32_t ha_copy, hc_copy; - uint32_t work_ha_copy; - unsigned long status; - unsigned long iflag; - uint32_t control; - - MAILBOX_t *mbox, *pmbox; - struct lpfc_vport *vport; - struct lpfc_nodelist *ndlp; - struct lpfc_dmabuf *mp; - LPFC_MBOXQ_t *pmb; - int rc; - - /* - * Get the driver's phba structure from the dev_id and - * assume the HBA is not interrupting. - */ - phba = (struct lpfc_hba *)dev_id; - - if (unlikely(!phba)) - return IRQ_NONE; - - /* - * Stuff needs to be attented to when this function is invoked as an - * individual interrupt handler in MSI-X multi-message interrupt mode - */ - if (phba->intr_type == MSIX) { - /* Check device state for handling interrupt */ - if (lpfc_intr_state_check(phba)) - return IRQ_NONE; - /* Need to read HA REG for slow-path events */ - spin_lock_irqsave(&phba->hbalock, iflag); - if (lpfc_readl(phba->HAregaddr, &ha_copy)) - goto unplug_error; - /* If somebody is waiting to handle an eratt don't process it - * here. The brdkill function will do this. - */ - if (phba->link_flag & LS_IGNORE_ERATT) - ha_copy &= ~HA_ERATT; - /* Check the need for handling ERATT in interrupt handler */ - if (ha_copy & HA_ERATT) { - if (phba->hba_flag & HBA_ERATT_HANDLED) - /* ERATT polling has handled ERATT */ - ha_copy &= ~HA_ERATT; - else - /* Indicate interrupt handler handles ERATT */ - phba->hba_flag |= HBA_ERATT_HANDLED; - } - - /* - * If there is deferred error attention, do not check for any - * interrupt. - */ - if (unlikely(phba->hba_flag & DEFER_ERATT)) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - return IRQ_NONE; - } - - /* Clear up only attention source related to slow-path */ - if (lpfc_readl(phba->HCregaddr, &hc_copy)) - goto unplug_error; - - writel(hc_copy & ~(HC_MBINT_ENA | HC_R2INT_ENA | - HC_LAINT_ENA | HC_ERINT_ENA), - phba->HCregaddr); - writel((ha_copy & (HA_MBATT | HA_R2_CLR_MSK)), - phba->HAregaddr); - writel(hc_copy, phba->HCregaddr); - readl(phba->HAregaddr); /* flush */ - spin_unlock_irqrestore(&phba->hbalock, iflag); - } else - ha_copy = phba->ha_copy; - - work_ha_copy = ha_copy & phba->work_ha_mask; - - if (work_ha_copy) { - if (work_ha_copy & HA_LATT) { - if (phba->sli.sli_flag & LPFC_PROCESS_LA) { - /* - * Turn off Link Attention interrupts - * until CLEAR_LA done - */ - spin_lock_irqsave(&phba->hbalock, iflag); - phba->sli.sli_flag &= ~LPFC_PROCESS_LA; - if (lpfc_readl(phba->HCregaddr, &control)) - goto unplug_error; - control &= ~HC_LAINT_ENA; - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - spin_unlock_irqrestore(&phba->hbalock, iflag); - } - else - work_ha_copy &= ~HA_LATT; - } - - if (work_ha_copy & ~(HA_ERATT | HA_MBATT | HA_LATT)) { - /* - * Turn off Slow Rings interrupts, LPFC_ELS_RING is - * the only slow ring. - */ - status = (work_ha_copy & - (HA_RXMASK << (4*LPFC_ELS_RING))); - status >>= (4*LPFC_ELS_RING); - if (status & HA_RXMASK) { - spin_lock_irqsave(&phba->hbalock, iflag); - if (lpfc_readl(phba->HCregaddr, &control)) - goto unplug_error; - - lpfc_debugfs_slow_ring_trc(phba, - "ISR slow ring: ctl:x%x stat:x%x isrcnt:x%x", - control, status, - (uint32_t)phba->sli.slistat.sli_intr); - - if (control & (HC_R0INT_ENA << LPFC_ELS_RING)) { - lpfc_debugfs_slow_ring_trc(phba, - "ISR Disable ring:" - "pwork:x%x hawork:x%x wait:x%x", - phba->work_ha, work_ha_copy, - (uint32_t)((unsigned long) - &phba->work_waitq)); - - control &= - ~(HC_R0INT_ENA << LPFC_ELS_RING); - writel(control, phba->HCregaddr); - readl(phba->HCregaddr); /* flush */ - } - else { - lpfc_debugfs_slow_ring_trc(phba, - "ISR slow ring: pwork:" - "x%x hawork:x%x wait:x%x", - phba->work_ha, work_ha_copy, - (uint32_t)((unsigned long) - &phba->work_waitq)); - } - spin_unlock_irqrestore(&phba->hbalock, iflag); - } - } - spin_lock_irqsave(&phba->hbalock, iflag); - if (work_ha_copy & HA_ERATT) { - if (lpfc_sli_read_hs(phba)) - goto unplug_error; - /* - * Check if there is a deferred error condition - * is active - */ - if ((HS_FFER1 & phba->work_hs) && - ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 | - HS_FFER6 | HS_FFER7 | HS_FFER8) & - phba->work_hs)) { - phba->hba_flag |= DEFER_ERATT; - /* Clear all interrupt enable conditions */ - writel(0, phba->HCregaddr); - readl(phba->HCregaddr); - } - } - - if ((work_ha_copy & HA_MBATT) && (phba->sli.mbox_active)) { - pmb = phba->sli.mbox_active; - pmbox = &pmb->u.mb; - mbox = phba->mbox; - vport = pmb->vport; - - /* First check out the status word */ - lpfc_sli_pcimem_bcopy(mbox, pmbox, sizeof(uint32_t)); - if (pmbox->mbxOwner != OWN_HOST) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - /* - * Stray Mailbox Interrupt, mbxCommand - * mbxStatus - */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, - "(%d):0304 Stray Mailbox " - "Interrupt mbxCommand x%x " - "mbxStatus x%x\n", - (vport ? vport->vpi : 0), - pmbox->mbxCommand, - pmbox->mbxStatus); - /* clear mailbox attention bit */ - work_ha_copy &= ~HA_MBATT; - } else { - phba->sli.mbox_active = NULL; - spin_unlock_irqrestore(&phba->hbalock, iflag); - phba->last_completion_time = jiffies; - del_timer(&phba->sli.mbox_tmo); - if (pmb->mbox_cmpl) { - lpfc_sli_pcimem_bcopy(mbox, pmbox, - MAILBOX_CMD_SIZE); - if (pmb->out_ext_byte_len && - pmb->context2) - lpfc_sli_pcimem_bcopy( - phba->mbox_ext, - pmb->context2, - pmb->out_ext_byte_len); - } - if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { - pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; - - lpfc_debugfs_disc_trc(vport, - LPFC_DISC_TRC_MBOX_VPORT, - "MBOX dflt rpi: : " - "status:x%x rpi:x%x", - (uint32_t)pmbox->mbxStatus, - pmbox->un.varWords[0], 0); - - if (!pmbox->mbxStatus) { - mp = (struct lpfc_dmabuf *) - (pmb->context1); - ndlp = (struct lpfc_nodelist *) - pmb->context2; - - /* Reg_LOGIN of dflt RPI was - * successful. new lets get - * rid of the RPI using the - * same mbox buffer. - */ - lpfc_unreg_login(phba, - vport->vpi, - pmbox->un.varWords[0], - pmb); - pmb->mbox_cmpl = - lpfc_mbx_cmpl_dflt_rpi; - pmb->context1 = mp; - pmb->context2 = ndlp; - pmb->vport = vport; - rc = lpfc_sli_issue_mbox(phba, - pmb, - MBX_NOWAIT); - if (rc != MBX_BUSY) - lpfc_printf_log(phba, - KERN_ERR, - LOG_MBOX | LOG_SLI, - "0350 rc should have" - "been MBX_BUSY\n"); - if (rc != MBX_NOT_FINISHED) - goto send_current_mbox; - } - } - spin_lock_irqsave( - &phba->pport->work_port_lock, - iflag); - phba->pport->work_port_events &= - ~WORKER_MBOX_TMO; - spin_unlock_irqrestore( - &phba->pport->work_port_lock, - iflag); - lpfc_mbox_cmpl_put(phba, pmb); - } - } else - spin_unlock_irqrestore(&phba->hbalock, iflag); - - if ((work_ha_copy & HA_MBATT) && - (phba->sli.mbox_active == NULL)) { -send_current_mbox: - /* Process next mailbox command if there is one */ - do { - rc = lpfc_sli_issue_mbox(phba, NULL, - MBX_NOWAIT); - } while (rc == MBX_NOT_FINISHED); - if (rc != MBX_SUCCESS) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, "0349 rc should be " - "MBX_SUCCESS\n"); - } - - spin_lock_irqsave(&phba->hbalock, iflag); - phba->work_ha |= work_ha_copy; - spin_unlock_irqrestore(&phba->hbalock, iflag); - lpfc_worker_wake_up(phba); - } - return IRQ_HANDLED; -unplug_error: - spin_unlock_irqrestore(&phba->hbalock, iflag); - return IRQ_HANDLED; - -} /* lpfc_sli_sp_intr_handler */ - -/** - * lpfc_sli_fp_intr_handler - Fast-path interrupt handler to SLI-3 device. - * @irq: Interrupt number. - * @dev_id: The device context pointer. - * - * This function is directly called from the PCI layer as an interrupt - * service routine when device with SLI-3 interface spec is enabled with - * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB - * ring event in the HBA. However, when the device is enabled with either - * MSI or Pin-IRQ interrupt mode, this function is called as part of the - * device-level interrupt handler. When the PCI slot is in error recovery - * or the HBA is undergoing initialization, the interrupt handler will not - * process the interrupt. The SCSI FCP fast-path ring event are handled in - * the intrrupt context. This function is called without any lock held. - * It gets the hbalock to access and update SLI data structures. - * - * This function returns IRQ_HANDLED when interrupt is handled else it - * returns IRQ_NONE. - **/ -irqreturn_t -lpfc_sli_fp_intr_handler(int irq, void *dev_id) -{ - struct lpfc_hba *phba; - uint32_t ha_copy; - unsigned long status; - unsigned long iflag; - - /* Get the driver's phba structure from the dev_id and - * assume the HBA is not interrupting. - */ - phba = (struct lpfc_hba *) dev_id; - - if (unlikely(!phba)) - return IRQ_NONE; - - /* - * Stuff needs to be attented to when this function is invoked as an - * individual interrupt handler in MSI-X multi-message interrupt mode - */ - if (phba->intr_type == MSIX) { - /* Check device state for handling interrupt */ - if (lpfc_intr_state_check(phba)) - return IRQ_NONE; - /* Need to read HA REG for FCP ring and other ring events */ - if (lpfc_readl(phba->HAregaddr, &ha_copy)) - return IRQ_HANDLED; - /* Clear up only attention source related to fast-path */ - spin_lock_irqsave(&phba->hbalock, iflag); - /* - * If there is deferred error attention, do not check for - * any interrupt. - */ - if (unlikely(phba->hba_flag & DEFER_ERATT)) { - spin_unlock_irqrestore(&phba->hbalock, iflag); - return IRQ_NONE; - } - writel((ha_copy & (HA_R0_CLR_MSK | HA_R1_CLR_MSK)), - phba->HAregaddr); - readl(phba->HAregaddr); /* flush */ - spin_unlock_irqrestore(&phba->hbalock, iflag); - } else - ha_copy = phba->ha_copy; - - /* - * Process all events on FCP ring. Take the optimized path for FCP IO. - */ - ha_copy &= ~(phba->work_ha_mask); - - status = (ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING))); - status >>= (4*LPFC_FCP_RING); - if (status & HA_RXMASK) - lpfc_sli_handle_fast_ring_event(phba, - &phba->sli.ring[LPFC_FCP_RING], - status); - - if (phba->cfg_multi_ring_support == 2) { - /* - * Process all events on extra ring. Take the optimized path - * for extra ring IO. - */ - status = (ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); - status >>= (4*LPFC_EXTRA_RING); - if (status & HA_RXMASK) { - lpfc_sli_handle_fast_ring_event(phba, - &phba->sli.ring[LPFC_EXTRA_RING], - status); - } - } - return IRQ_HANDLED; -} /* lpfc_sli_fp_intr_handler */ - -/** - * lpfc_sli_intr_handler - Device-level interrupt handler to SLI-3 device - * @irq: Interrupt number. - * @dev_id: The device context pointer. - * - * This function is the HBA device-level interrupt handler to device with - * SLI-3 interface spec, called from the PCI layer when either MSI or - * Pin-IRQ interrupt mode is enabled and there is an event in the HBA which - * requires driver attention. This function invokes the slow-path interrupt - * attention handling function and fast-path interrupt attention handling - * function in turn to process the relevant HBA attention events. This - * function is called without any lock held. It gets the hbalock to access - * and update SLI data structures. - * - * This function returns IRQ_HANDLED when interrupt is handled, else it - * returns IRQ_NONE. - **/ -irqreturn_t -lpfc_sli_intr_handler(int irq, void *dev_id) -{ - struct lpfc_hba *phba; - irqreturn_t sp_irq_rc, fp_irq_rc; - unsigned long status1, status2; - uint32_t hc_copy; - - /* - * Get the driver's phba structure from the dev_id and - * assume the HBA is not interrupting. - */ - phba = (struct lpfc_hba *) dev_id; - - if (unlikely(!phba)) - return IRQ_NONE; - - /* Check device state for handling interrupt */ - if (lpfc_intr_state_check(phba)) - return IRQ_NONE; - - spin_lock(&phba->hbalock); - if (lpfc_readl(phba->HAregaddr, &phba->ha_copy)) { - spin_unlock(&phba->hbalock); - return IRQ_HANDLED; - } - - if (unlikely(!phba->ha_copy)) { - spin_unlock(&phba->hbalock); - return IRQ_NONE; - } else if (phba->ha_copy & HA_ERATT) { - if (phba->hba_flag & HBA_ERATT_HANDLED) - /* ERATT polling has handled ERATT */ - phba->ha_copy &= ~HA_ERATT; - else - /* Indicate interrupt handler handles ERATT */ - phba->hba_flag |= HBA_ERATT_HANDLED; - } - - /* - * If there is deferred error attention, do not check for any interrupt. - */ - if (unlikely(phba->hba_flag & DEFER_ERATT)) { - spin_unlock(&phba->hbalock); - return IRQ_NONE; - } - - /* Clear attention sources except link and error attentions */ - if (lpfc_readl(phba->HCregaddr, &hc_copy)) { - spin_unlock(&phba->hbalock); - return IRQ_HANDLED; - } - writel(hc_copy & ~(HC_MBINT_ENA | HC_R0INT_ENA | HC_R1INT_ENA - | HC_R2INT_ENA | HC_LAINT_ENA | HC_ERINT_ENA), - phba->HCregaddr); - writel((phba->ha_copy & ~(HA_LATT | HA_ERATT)), phba->HAregaddr); - writel(hc_copy, phba->HCregaddr); - readl(phba->HAregaddr); /* flush */ - spin_unlock(&phba->hbalock); - - /* - * Invokes slow-path host attention interrupt handling as appropriate. - */ - - /* status of events with mailbox and link attention */ - status1 = phba->ha_copy & (HA_MBATT | HA_LATT | HA_ERATT); - - /* status of events with ELS ring */ - status2 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); - status2 >>= (4*LPFC_ELS_RING); - - if (status1 || (status2 & HA_RXMASK)) - sp_irq_rc = lpfc_sli_sp_intr_handler(irq, dev_id); - else - sp_irq_rc = IRQ_NONE; - - /* - * Invoke fast-path host attention interrupt handling as appropriate. - */ - - /* status of events with FCP ring */ - status1 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_FCP_RING))); - status1 >>= (4*LPFC_FCP_RING); - - /* status of events with extra ring */ - if (phba->cfg_multi_ring_support == 2) { - status2 = (phba->ha_copy & (HA_RXMASK << (4*LPFC_EXTRA_RING))); - status2 >>= (4*LPFC_EXTRA_RING); - } else - status2 = 0; - - if ((status1 & HA_RXMASK) || (status2 & HA_RXMASK)) - fp_irq_rc = lpfc_sli_fp_intr_handler(irq, dev_id); - else - fp_irq_rc = IRQ_NONE; - - /* Return device-level interrupt handling status */ - return (sp_irq_rc == IRQ_HANDLED) ? sp_irq_rc : fp_irq_rc; -} /* lpfc_sli_intr_handler */ - -/** - * lpfc_sli4_fcp_xri_abort_event_proc - Process fcp xri abort event - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked by the worker thread to process all the pending - * SLI4 FCP abort XRI events. - **/ -void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *phba) -{ - struct lpfc_cq_event *cq_event; - - /* First, declare the fcp xri abort event has been handled */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~FCP_XRI_ABORT_EVENT; - spin_unlock_irq(&phba->hbalock); - /* Now, handle all the fcp xri abort events */ - while (!list_empty(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue)) { - /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); - list_remove_head(&phba->sli4_hba.sp_fcp_xri_aborted_work_queue, - cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); - /* Notify aborted XRI for FCP work queue */ - lpfc_sli4_fcp_xri_aborted(phba, &cq_event->cqe.wcqe_axri); - /* Free the event processed back to the free pool */ - lpfc_sli4_cq_event_release(phba, cq_event); - } -} - -/** - * lpfc_sli4_els_xri_abort_event_proc - Process els xri abort event - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked by the worker thread to process all the pending - * SLI4 els abort xri events. - **/ -void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *phba) -{ - struct lpfc_cq_event *cq_event; - - /* First, declare the els xri abort event has been handled */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~ELS_XRI_ABORT_EVENT; - spin_unlock_irq(&phba->hbalock); - /* Now, handle all the els xri abort events */ - while (!list_empty(&phba->sli4_hba.sp_els_xri_aborted_work_queue)) { - /* Get the first event from the head of the event queue */ - spin_lock_irq(&phba->hbalock); - list_remove_head(&phba->sli4_hba.sp_els_xri_aborted_work_queue, - cq_event, struct lpfc_cq_event, list); - spin_unlock_irq(&phba->hbalock); - /* Notify aborted XRI for ELS work queue */ - lpfc_sli4_els_xri_aborted(phba, &cq_event->cqe.wcqe_axri); - /* Free the event processed back to the free pool */ - lpfc_sli4_cq_event_release(phba, cq_event); - } -} - -/** - * lpfc_sli4_iocb_param_transfer - Transfer pIocbOut and cmpl status to pIocbIn - * @phba: pointer to lpfc hba data structure - * @pIocbIn: pointer to the rspiocbq - * @pIocbOut: pointer to the cmdiocbq - * @wcqe: pointer to the complete wcqe - * - * This routine transfers the fields of a command iocbq to a response iocbq - * by copying all the IOCB fields from command iocbq and transferring the - * completion status information from the complete wcqe. - **/ -static void -lpfc_sli4_iocb_param_transfer(struct lpfc_hba *phba, - struct lpfc_iocbq *pIocbIn, - struct lpfc_iocbq *pIocbOut, - struct lpfc_wcqe_complete *wcqe) -{ - unsigned long iflags; - uint32_t status; - size_t offset = offsetof(struct lpfc_iocbq, iocb); - - memcpy((char *)pIocbIn + offset, (char *)pIocbOut + offset, - sizeof(struct lpfc_iocbq) - offset); - /* Map WCQE parameters into irspiocb parameters */ - status = bf_get(lpfc_wcqe_c_status, wcqe); - pIocbIn->iocb.ulpStatus = (status & LPFC_IOCB_STATUS_MASK); - if (pIocbOut->iocb_flag & LPFC_IO_FCP) - if (pIocbIn->iocb.ulpStatus == IOSTAT_FCP_RSP_ERROR) - pIocbIn->iocb.un.fcpi.fcpi_parm = - pIocbOut->iocb.un.fcpi.fcpi_parm - - wcqe->total_data_placed; - else - pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; - else { - pIocbIn->iocb.un.ulpWord[4] = wcqe->parameter; - pIocbIn->iocb.un.genreq64.bdl.bdeSize = wcqe->total_data_placed; - } - - /* Convert BG errors for completion status */ - if (status == CQE_STATUS_DI_ERROR) { - pIocbIn->iocb.ulpStatus = IOSTAT_LOCAL_REJECT; - - if (bf_get(lpfc_wcqe_c_bg_edir, wcqe)) - pIocbIn->iocb.un.ulpWord[4] = IOERR_RX_DMA_FAILED; - else - pIocbIn->iocb.un.ulpWord[4] = IOERR_TX_DMA_FAILED; - - pIocbIn->iocb.unsli3.sli3_bg.bgstat = 0; - if (bf_get(lpfc_wcqe_c_bg_ge, wcqe)) /* Guard Check failed */ - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - BGS_GUARD_ERR_MASK; - if (bf_get(lpfc_wcqe_c_bg_ae, wcqe)) /* App Tag Check failed */ - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - BGS_APPTAG_ERR_MASK; - if (bf_get(lpfc_wcqe_c_bg_re, wcqe)) /* Ref Tag Check failed */ - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - BGS_REFTAG_ERR_MASK; - - /* Check to see if there was any good data before the error */ - if (bf_get(lpfc_wcqe_c_bg_tdpv, wcqe)) { - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - BGS_HI_WATER_MARK_PRESENT_MASK; - pIocbIn->iocb.unsli3.sli3_bg.bghm = - wcqe->total_data_placed; - } - - /* - * Set ALL the error bits to indicate we don't know what - * type of error it is. - */ - if (!pIocbIn->iocb.unsli3.sli3_bg.bgstat) - pIocbIn->iocb.unsli3.sli3_bg.bgstat |= - (BGS_REFTAG_ERR_MASK | BGS_APPTAG_ERR_MASK | - BGS_GUARD_ERR_MASK); - } - - /* Pick up HBA exchange busy condition */ - if (bf_get(lpfc_wcqe_c_xb, wcqe)) { - spin_lock_irqsave(&phba->hbalock, iflags); - pIocbIn->iocb_flag |= LPFC_EXCHANGE_BUSY; - spin_unlock_irqrestore(&phba->hbalock, iflags); - } -} - -/** - * lpfc_sli4_els_wcqe_to_rspiocbq - Get response iocbq from els wcqe - * @phba: Pointer to HBA context object. - * @wcqe: Pointer to work-queue completion queue entry. - * - * This routine handles an ELS work-queue completion event and construct - * a pseudo response ELS IODBQ from the SLI4 ELS WCQE for the common - * discovery engine to handle. - * - * Return: Pointer to the receive IOCBQ, NULL otherwise. - **/ -static struct lpfc_iocbq * -lpfc_sli4_els_wcqe_to_rspiocbq(struct lpfc_hba *phba, - struct lpfc_iocbq *irspiocbq) -{ - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct lpfc_iocbq *cmdiocbq; - struct lpfc_wcqe_complete *wcqe; - unsigned long iflags; - - wcqe = &irspiocbq->cq_event.cqe.wcqe_cmpl; - spin_lock_irqsave(&phba->hbalock, iflags); - pring->stats.iocb_event++; - /* Look up the ELS command IOCB and create pseudo response IOCB */ - cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, - bf_get(lpfc_wcqe_c_request_tag, wcqe)); - spin_unlock_irqrestore(&phba->hbalock, iflags); - - if (unlikely(!cmdiocbq)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0386 ELS complete with no corresponding " - "cmdiocb: iotag (%d)\n", - bf_get(lpfc_wcqe_c_request_tag, wcqe)); - lpfc_sli_release_iocbq(phba, irspiocbq); - return NULL; - } - - /* Fake the irspiocbq and copy necessary response information */ - lpfc_sli4_iocb_param_transfer(phba, irspiocbq, cmdiocbq, wcqe); - - return irspiocbq; -} - -/** - * lpfc_sli4_sp_handle_async_event - Handle an asynchroous event - * @phba: Pointer to HBA context object. - * @cqe: Pointer to mailbox completion queue entry. - * - * This routine process a mailbox completion queue entry with asynchrous - * event. - * - * Return: true if work posted to worker thread, otherwise false. - **/ -static bool -lpfc_sli4_sp_handle_async_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) -{ - struct lpfc_cq_event *cq_event; - unsigned long iflags; - - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0392 Async Event: word0:x%x, word1:x%x, " - "word2:x%x, word3:x%x\n", mcqe->word0, - mcqe->mcqe_tag0, mcqe->mcqe_tag1, mcqe->trailer); - - /* Allocate a new internal CQ_EVENT entry */ - cq_event = lpfc_sli4_cq_event_alloc(phba); - if (!cq_event) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0394 Failed to allocate CQ_EVENT entry\n"); - return false; - } - - /* Move the CQE into an asynchronous event entry */ - memcpy(&cq_event->cqe, mcqe, sizeof(struct lpfc_mcqe)); - spin_lock_irqsave(&phba->hbalock, iflags); - list_add_tail(&cq_event->list, &phba->sli4_hba.sp_asynce_work_queue); - /* Set the async event flag */ - phba->hba_flag |= ASYNC_EVENT; - spin_unlock_irqrestore(&phba->hbalock, iflags); - - return true; -} - -/** - * lpfc_sli4_sp_handle_mbox_event - Handle a mailbox completion event - * @phba: Pointer to HBA context object. - * @cqe: Pointer to mailbox completion queue entry. - * - * This routine process a mailbox completion queue entry with mailbox - * completion event. - * - * Return: true if work posted to worker thread, otherwise false. - **/ -static bool -lpfc_sli4_sp_handle_mbox_event(struct lpfc_hba *phba, struct lpfc_mcqe *mcqe) -{ - uint32_t mcqe_status; - MAILBOX_t *mbox, *pmbox; - struct lpfc_mqe *mqe; - struct lpfc_vport *vport; - struct lpfc_nodelist *ndlp; - struct lpfc_dmabuf *mp; - unsigned long iflags; - LPFC_MBOXQ_t *pmb; - bool workposted = false; - int rc; - - /* If not a mailbox complete MCQE, out by checking mailbox consume */ - if (!bf_get(lpfc_trailer_completed, mcqe)) - goto out_no_mqe_complete; - - /* Get the reference to the active mbox command */ - spin_lock_irqsave(&phba->hbalock, iflags); - pmb = phba->sli.mbox_active; - if (unlikely(!pmb)) { - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "1832 No pending MBOX command to handle\n"); - spin_unlock_irqrestore(&phba->hbalock, iflags); - goto out_no_mqe_complete; - } - spin_unlock_irqrestore(&phba->hbalock, iflags); - mqe = &pmb->u.mqe; - pmbox = (MAILBOX_t *)&pmb->u.mqe; - mbox = phba->mbox; - vport = pmb->vport; - - /* Reset heartbeat timer */ - phba->last_completion_time = jiffies; - del_timer(&phba->sli.mbox_tmo); - - /* Move mbox data to caller's mailbox region, do endian swapping */ - if (pmb->mbox_cmpl && mbox) - lpfc_sli_pcimem_bcopy(mbox, mqe, sizeof(struct lpfc_mqe)); - - /* - * For mcqe errors, conditionally move a modified error code to - * the mbox so that the error will not be missed. - */ - mcqe_status = bf_get(lpfc_mcqe_status, mcqe); - if (mcqe_status != MB_CQE_STATUS_SUCCESS) { - if (bf_get(lpfc_mqe_status, mqe) == MBX_SUCCESS) - bf_set(lpfc_mqe_status, mqe, - (LPFC_MBX_ERROR_RANGE | mcqe_status)); - } - if (pmb->mbox_flag & LPFC_MBX_IMED_UNREG) { - pmb->mbox_flag &= ~LPFC_MBX_IMED_UNREG; - lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_MBOX_VPORT, - "MBOX dflt rpi: status:x%x rpi:x%x", - mcqe_status, - pmbox->un.varWords[0], 0); - if (mcqe_status == MB_CQE_STATUS_SUCCESS) { - mp = (struct lpfc_dmabuf *)(pmb->context1); - ndlp = (struct lpfc_nodelist *)pmb->context2; - /* Reg_LOGIN of dflt RPI was successful. Now lets get - * RID of the PPI using the same mbox buffer. - */ - lpfc_unreg_login(phba, vport->vpi, - pmbox->un.varWords[0], pmb); - pmb->mbox_cmpl = lpfc_mbx_cmpl_dflt_rpi; - pmb->context1 = mp; - pmb->context2 = ndlp; - pmb->vport = vport; - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); - if (rc != MBX_BUSY) - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | - LOG_SLI, "0385 rc should " - "have been MBX_BUSY\n"); - if (rc != MBX_NOT_FINISHED) - goto send_current_mbox; - } - } - spin_lock_irqsave(&phba->pport->work_port_lock, iflags); - phba->pport->work_port_events &= ~WORKER_MBOX_TMO; - spin_unlock_irqrestore(&phba->pport->work_port_lock, iflags); - - /* There is mailbox completion work to do */ - spin_lock_irqsave(&phba->hbalock, iflags); - __lpfc_mbox_cmpl_put(phba, pmb); - phba->work_ha |= HA_MBATT; - spin_unlock_irqrestore(&phba->hbalock, iflags); - workposted = true; - -send_current_mbox: - spin_lock_irqsave(&phba->hbalock, iflags); - /* Release the mailbox command posting token */ - phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; - /* Setting active mailbox pointer need to be in sync to flag clear */ - phba->sli.mbox_active = NULL; - spin_unlock_irqrestore(&phba->hbalock, iflags); - /* Wake up worker thread to post the next pending mailbox command */ - lpfc_worker_wake_up(phba); -out_no_mqe_complete: - if (bf_get(lpfc_trailer_consumed, mcqe)) - lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq); - return workposted; -} - -/** - * lpfc_sli4_sp_handle_mcqe - Process a mailbox completion queue entry - * @phba: Pointer to HBA context object. - * @cqe: Pointer to mailbox completion queue entry. - * - * This routine process a mailbox completion queue entry, it invokes the - * proper mailbox complete handling or asynchrous event handling routine - * according to the MCQE's async bit. - * - * Return: true if work posted to worker thread, otherwise false. - **/ -static bool -lpfc_sli4_sp_handle_mcqe(struct lpfc_hba *phba, struct lpfc_cqe *cqe) -{ - struct lpfc_mcqe mcqe; - bool workposted; - - /* Copy the mailbox MCQE and convert endian order as needed */ - lpfc_sli_pcimem_bcopy(cqe, &mcqe, sizeof(struct lpfc_mcqe)); - - /* Invoke the proper event handling routine */ - if (!bf_get(lpfc_trailer_async, &mcqe)) - workposted = lpfc_sli4_sp_handle_mbox_event(phba, &mcqe); - else - workposted = lpfc_sli4_sp_handle_async_event(phba, &mcqe); - return workposted; -} - -/** - * lpfc_sli4_sp_handle_els_wcqe - Handle els work-queue completion event - * @phba: Pointer to HBA context object. - * @wcqe: Pointer to work-queue completion queue entry. - * - * This routine handles an ELS work-queue completion event. - * - * Return: true if work posted to worker thread, otherwise false. - **/ -static bool -lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, - struct lpfc_wcqe_complete *wcqe) -{ - struct lpfc_iocbq *irspiocbq; - unsigned long iflags; - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING]; - - /* Get an irspiocbq for later ELS response processing use */ - irspiocbq = lpfc_sli_get_iocbq(phba); - if (!irspiocbq) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d " - "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n", - pring->txq_cnt, phba->iocb_cnt, - phba->sli.ring[LPFC_FCP_RING].txcmplq_cnt, - phba->sli.ring[LPFC_ELS_RING].txcmplq_cnt); - return false; - } - - /* Save off the slow-path queue event for work thread to process */ - memcpy(&irspiocbq->cq_event.cqe.wcqe_cmpl, wcqe, sizeof(*wcqe)); - spin_lock_irqsave(&phba->hbalock, iflags); - list_add_tail(&irspiocbq->cq_event.list, - &phba->sli4_hba.sp_queue_event); - phba->hba_flag |= HBA_SP_QUEUE_EVT; - spin_unlock_irqrestore(&phba->hbalock, iflags); - - return true; -} - -/** - * lpfc_sli4_sp_handle_rel_wcqe - Handle slow-path WQ entry consumed event - * @phba: Pointer to HBA context object. - * @wcqe: Pointer to work-queue completion queue entry. - * - * This routine handles slow-path WQ entry comsumed event by invoking the - * proper WQ release routine to the slow-path WQ. - **/ -static void -lpfc_sli4_sp_handle_rel_wcqe(struct lpfc_hba *phba, - struct lpfc_wcqe_release *wcqe) -{ - /* sanity check on queue memory */ - if (unlikely(!phba->sli4_hba.els_wq)) - return; - /* Check for the slow-path ELS work queue */ - if (bf_get(lpfc_wcqe_r_wq_id, wcqe) == phba->sli4_hba.els_wq->queue_id) - lpfc_sli4_wq_release(phba->sli4_hba.els_wq, - bf_get(lpfc_wcqe_r_wqe_index, wcqe)); - else - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "2579 Slow-path wqe consume event carries " - "miss-matched qid: wcqe-qid=x%x, sp-qid=x%x\n", - bf_get(lpfc_wcqe_r_wqe_index, wcqe), - phba->sli4_hba.els_wq->queue_id); -} - -/** - * lpfc_sli4_sp_handle_abort_xri_wcqe - Handle a xri abort event - * @phba: Pointer to HBA context object. - * @cq: Pointer to a WQ completion queue. - * @wcqe: Pointer to work-queue completion queue entry. - * - * This routine handles an XRI abort event. - * - * Return: true if work posted to worker thread, otherwise false. - **/ -static bool -lpfc_sli4_sp_handle_abort_xri_wcqe(struct lpfc_hba *phba, - struct lpfc_queue *cq, - struct sli4_wcqe_xri_aborted *wcqe) -{ - bool workposted = false; - struct lpfc_cq_event *cq_event; - unsigned long iflags; - - /* Allocate a new internal CQ_EVENT entry */ - cq_event = lpfc_sli4_cq_event_alloc(phba); - if (!cq_event) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0602 Failed to allocate CQ_EVENT entry\n"); - return false; - } - - /* Move the CQE into the proper xri abort event list */ - memcpy(&cq_event->cqe, wcqe, sizeof(struct sli4_wcqe_xri_aborted)); - switch (cq->subtype) { - case LPFC_FCP: - spin_lock_irqsave(&phba->hbalock, iflags); - list_add_tail(&cq_event->list, - &phba->sli4_hba.sp_fcp_xri_aborted_work_queue); - /* Set the fcp xri abort event flag */ - phba->hba_flag |= FCP_XRI_ABORT_EVENT; - spin_unlock_irqrestore(&phba->hbalock, iflags); - workposted = true; - break; - case LPFC_ELS: - spin_lock_irqsave(&phba->hbalock, iflags); - list_add_tail(&cq_event->list, - &phba->sli4_hba.sp_els_xri_aborted_work_queue); - /* Set the els xri abort event flag */ - phba->hba_flag |= ELS_XRI_ABORT_EVENT; - spin_unlock_irqrestore(&phba->hbalock, iflags); - workposted = true; - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0603 Invalid work queue CQE subtype (x%x)\n", - cq->subtype); - workposted = false; - break; - } - return workposted; -} - -/** - * lpfc_sli4_sp_handle_rcqe - Process a receive-queue completion queue entry - * @phba: Pointer to HBA context object. - * @rcqe: Pointer to receive-queue completion queue entry. - * - * This routine process a receive-queue completion queue entry. - * - * Return: true if work posted to worker thread, otherwise false. - **/ -static bool -lpfc_sli4_sp_handle_rcqe(struct lpfc_hba *phba, struct lpfc_rcqe *rcqe) -{ - bool workposted = false; - struct lpfc_queue *hrq = phba->sli4_hba.hdr_rq; - struct lpfc_queue *drq = phba->sli4_hba.dat_rq; - struct hbq_dmabuf *dma_buf; - uint32_t status, rq_id; - unsigned long iflags; - - /* sanity check on queue memory */ - if (unlikely(!hrq) || unlikely(!drq)) - return workposted; - - if (bf_get(lpfc_cqe_code, rcqe) == CQE_CODE_RECEIVE_V1) - rq_id = bf_get(lpfc_rcqe_rq_id_v1, rcqe); - else - rq_id = bf_get(lpfc_rcqe_rq_id, rcqe); - if (rq_id != hrq->queue_id) - goto out; - - status = bf_get(lpfc_rcqe_status, rcqe); - switch (status) { - case FC_STATUS_RQ_BUF_LEN_EXCEEDED: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2537 Receive Frame Truncated!!\n"); - case FC_STATUS_RQ_SUCCESS: - lpfc_sli4_rq_release(hrq, drq); - spin_lock_irqsave(&phba->hbalock, iflags); - dma_buf = lpfc_sli_hbqbuf_get(&phba->hbqs[0].hbq_buffer_list); - if (!dma_buf) { - spin_unlock_irqrestore(&phba->hbalock, iflags); - goto out; - } - memcpy(&dma_buf->cq_event.cqe.rcqe_cmpl, rcqe, sizeof(*rcqe)); - /* save off the frame for the word thread to process */ - list_add_tail(&dma_buf->cq_event.list, - &phba->sli4_hba.sp_queue_event); - /* Frame received */ - phba->hba_flag |= HBA_SP_QUEUE_EVT; - spin_unlock_irqrestore(&phba->hbalock, iflags); - workposted = true; - break; - case FC_STATUS_INSUFF_BUF_NEED_BUF: - case FC_STATUS_INSUFF_BUF_FRM_DISC: - /* Post more buffers if possible */ - spin_lock_irqsave(&phba->hbalock, iflags); - phba->hba_flag |= HBA_POST_RECEIVE_BUFFER; - spin_unlock_irqrestore(&phba->hbalock, iflags); - workposted = true; - break; - } -out: - return workposted; -} - -/** - * lpfc_sli4_sp_handle_cqe - Process a slow path completion queue entry - * @phba: Pointer to HBA context object. - * @cq: Pointer to the completion queue. - * @wcqe: Pointer to a completion queue entry. - * - * This routine process a slow-path work-queue or receive queue completion queue - * entry. - * - * Return: true if work posted to worker thread, otherwise false. - **/ -static bool -lpfc_sli4_sp_handle_cqe(struct lpfc_hba *phba, struct lpfc_queue *cq, - struct lpfc_cqe *cqe) -{ - struct lpfc_cqe cqevt; - bool workposted = false; - - /* Copy the work queue CQE and convert endian order if needed */ - lpfc_sli_pcimem_bcopy(cqe, &cqevt, sizeof(struct lpfc_cqe)); - - /* Check and process for different type of WCQE and dispatch */ - switch (bf_get(lpfc_cqe_code, &cqevt)) { - case CQE_CODE_COMPL_WQE: - /* Process the WQ/RQ complete event */ - phba->last_completion_time = jiffies; - workposted = lpfc_sli4_sp_handle_els_wcqe(phba, - (struct lpfc_wcqe_complete *)&cqevt); - break; - case CQE_CODE_RELEASE_WQE: - /* Process the WQ release event */ - lpfc_sli4_sp_handle_rel_wcqe(phba, - (struct lpfc_wcqe_release *)&cqevt); - break; - case CQE_CODE_XRI_ABORTED: - /* Process the WQ XRI abort event */ - phba->last_completion_time = jiffies; - workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, - (struct sli4_wcqe_xri_aborted *)&cqevt); - break; - case CQE_CODE_RECEIVE: - case CQE_CODE_RECEIVE_V1: - /* Process the RQ event */ - phba->last_completion_time = jiffies; - workposted = lpfc_sli4_sp_handle_rcqe(phba, - (struct lpfc_rcqe *)&cqevt); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0388 Not a valid WCQE code: x%x\n", - bf_get(lpfc_cqe_code, &cqevt)); - break; - } - return workposted; -} - -/** - * lpfc_sli4_sp_handle_eqe - Process a slow-path event queue entry - * @phba: Pointer to HBA context object. - * @eqe: Pointer to fast-path event queue entry. - * - * This routine process a event queue entry from the slow-path event queue. - * It will check the MajorCode and MinorCode to determine this is for a - * completion event on a completion queue, if not, an error shall be logged - * and just return. Otherwise, it will get to the corresponding completion - * queue and process all the entries on that completion queue, rearm the - * completion queue, and then return. - * - **/ -static void -lpfc_sli4_sp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe) -{ - struct lpfc_queue *cq = NULL, *childq, *speq; - struct lpfc_cqe *cqe; - bool workposted = false; - int ecount = 0; - uint16_t cqid; - - if (bf_get_le32(lpfc_eqe_major_code, eqe) != 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0359 Not a valid slow-path completion " - "event: majorcode=x%x, minorcode=x%x\n", - bf_get_le32(lpfc_eqe_major_code, eqe), - bf_get_le32(lpfc_eqe_minor_code, eqe)); - return; - } - - /* Get the reference to the corresponding CQ */ - cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); - - /* Search for completion queue pointer matching this cqid */ - speq = phba->sli4_hba.sp_eq; - /* sanity check on queue memory */ - if (unlikely(!speq)) - return; - list_for_each_entry(childq, &speq->child_list, list) { - if (childq->queue_id == cqid) { - cq = childq; - break; - } - } - if (unlikely(!cq)) { - if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0365 Slow-path CQ identifier " - "(%d) does not exist\n", cqid); - return; - } - - /* Process all the entries to the CQ */ - switch (cq->type) { - case LPFC_MCQ: - while ((cqe = lpfc_sli4_cq_get(cq))) { - workposted |= lpfc_sli4_sp_handle_mcqe(phba, cqe); - if (!(++ecount % cq->entry_repost)) - lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); - } - break; - case LPFC_WCQ: - while ((cqe = lpfc_sli4_cq_get(cq))) { - if (cq->subtype == LPFC_FCP) - workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq, - cqe); - else - workposted |= lpfc_sli4_sp_handle_cqe(phba, cq, - cqe); - if (!(++ecount % cq->entry_repost)) - lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); - } - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0370 Invalid completion queue type (%d)\n", - cq->type); - return; - } - - /* Catch the no cq entry condition, log an error */ - if (unlikely(ecount == 0)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0371 No entry from the CQ: identifier " - "(x%x), type (%d)\n", cq->queue_id, cq->type); - - /* In any case, flash and re-arm the RCQ */ - lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM); - - /* wake up worker thread if there are works to be done */ - if (workposted) - lpfc_worker_wake_up(phba); -} - -/** - * lpfc_sli4_fp_handle_fcp_wcqe - Process fast-path work queue completion entry - * @eqe: Pointer to fast-path completion queue entry. - * - * This routine process a fast-path work queue completion entry from fast-path - * event queue for FCP command response completion. - **/ -static void -lpfc_sli4_fp_handle_fcp_wcqe(struct lpfc_hba *phba, - struct lpfc_wcqe_complete *wcqe) -{ - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_FCP_RING]; - struct lpfc_iocbq *cmdiocbq; - struct lpfc_iocbq irspiocbq; - unsigned long iflags; - - spin_lock_irqsave(&phba->hbalock, iflags); - pring->stats.iocb_event++; - spin_unlock_irqrestore(&phba->hbalock, iflags); - - /* Check for response status */ - if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) { - /* If resource errors reported from HBA, reduce queue - * depth of the SCSI device. - */ - if ((bf_get(lpfc_wcqe_c_status, wcqe) == - IOSTAT_LOCAL_REJECT) && - (wcqe->parameter == IOERR_NO_RESOURCES)) { - phba->lpfc_rampdown_queue_depth(phba); - } - /* Log the error status */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0373 FCP complete error: status=x%x, " - "hw_status=x%x, total_data_specified=%d, " - "parameter=x%x, word3=x%x\n", - bf_get(lpfc_wcqe_c_status, wcqe), - bf_get(lpfc_wcqe_c_hw_status, wcqe), - wcqe->total_data_placed, wcqe->parameter, - wcqe->word3); - } - - /* Look up the FCP command IOCB and create pseudo response IOCB */ - spin_lock_irqsave(&phba->hbalock, iflags); - cmdiocbq = lpfc_sli_iocbq_lookup_by_tag(phba, pring, - bf_get(lpfc_wcqe_c_request_tag, wcqe)); - spin_unlock_irqrestore(&phba->hbalock, iflags); - if (unlikely(!cmdiocbq)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0374 FCP complete with no corresponding " - "cmdiocb: iotag (%d)\n", - bf_get(lpfc_wcqe_c_request_tag, wcqe)); - return; - } - if (unlikely(!cmdiocbq->iocb_cmpl)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0375 FCP cmdiocb not callback function " - "iotag: (%d)\n", - bf_get(lpfc_wcqe_c_request_tag, wcqe)); - return; - } - - /* Fake the irspiocb and copy necessary response information */ - lpfc_sli4_iocb_param_transfer(phba, &irspiocbq, cmdiocbq, wcqe); - - if (cmdiocbq->iocb_flag & LPFC_DRIVER_ABORTED) { - spin_lock_irqsave(&phba->hbalock, iflags); - cmdiocbq->iocb_flag &= ~LPFC_DRIVER_ABORTED; - spin_unlock_irqrestore(&phba->hbalock, iflags); - } - - /* Pass the cmd_iocb and the rsp state to the upper layer */ - (cmdiocbq->iocb_cmpl)(phba, cmdiocbq, &irspiocbq); -} - -/** - * lpfc_sli4_fp_handle_rel_wcqe - Handle fast-path WQ entry consumed event - * @phba: Pointer to HBA context object. - * @cq: Pointer to completion queue. - * @wcqe: Pointer to work-queue completion queue entry. - * - * This routine handles an fast-path WQ entry comsumed event by invoking the - * proper WQ release routine to the slow-path WQ. - **/ -static void -lpfc_sli4_fp_handle_rel_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, - struct lpfc_wcqe_release *wcqe) -{ - struct lpfc_queue *childwq; - bool wqid_matched = false; - uint16_t fcp_wqid; - - /* Check for fast-path FCP work queue release */ - fcp_wqid = bf_get(lpfc_wcqe_r_wq_id, wcqe); - list_for_each_entry(childwq, &cq->child_list, list) { - if (childwq->queue_id == fcp_wqid) { - lpfc_sli4_wq_release(childwq, - bf_get(lpfc_wcqe_r_wqe_index, wcqe)); - wqid_matched = true; - break; - } - } - /* Report warning log message if no match found */ - if (wqid_matched != true) - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "2580 Fast-path wqe consume event carries " - "miss-matched qid: wcqe-qid=x%x\n", fcp_wqid); -} - -/** - * lpfc_sli4_fp_handle_wcqe - Process fast-path work queue completion entry - * @cq: Pointer to the completion queue. - * @eqe: Pointer to fast-path completion queue entry. - * - * This routine process a fast-path work queue completion entry from fast-path - * event queue for FCP command response completion. - **/ -static int -lpfc_sli4_fp_handle_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, - struct lpfc_cqe *cqe) -{ - struct lpfc_wcqe_release wcqe; - bool workposted = false; - - /* Copy the work queue CQE and convert endian order if needed */ - lpfc_sli_pcimem_bcopy(cqe, &wcqe, sizeof(struct lpfc_cqe)); - - /* Check and process for different type of WCQE and dispatch */ - switch (bf_get(lpfc_wcqe_c_code, &wcqe)) { - case CQE_CODE_COMPL_WQE: - /* Process the WQ complete event */ - phba->last_completion_time = jiffies; - lpfc_sli4_fp_handle_fcp_wcqe(phba, - (struct lpfc_wcqe_complete *)&wcqe); - break; - case CQE_CODE_RELEASE_WQE: - /* Process the WQ release event */ - lpfc_sli4_fp_handle_rel_wcqe(phba, cq, - (struct lpfc_wcqe_release *)&wcqe); - break; - case CQE_CODE_XRI_ABORTED: - /* Process the WQ XRI abort event */ - phba->last_completion_time = jiffies; - workposted = lpfc_sli4_sp_handle_abort_xri_wcqe(phba, cq, - (struct sli4_wcqe_xri_aborted *)&wcqe); - break; - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0144 Not a valid WCQE code: x%x\n", - bf_get(lpfc_wcqe_c_code, &wcqe)); - break; - } - return workposted; -} - -/** - * lpfc_sli4_fp_handle_eqe - Process a fast-path event queue entry - * @phba: Pointer to HBA context object. - * @eqe: Pointer to fast-path event queue entry. - * - * This routine process a event queue entry from the fast-path event queue. - * It will check the MajorCode and MinorCode to determine this is for a - * completion event on a completion queue, if not, an error shall be logged - * and just return. Otherwise, it will get to the corresponding completion - * queue and process all the entries on the completion queue, rearm the - * completion queue, and then return. - **/ -static void -lpfc_sli4_fp_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe, - uint32_t fcp_cqidx) -{ - struct lpfc_queue *cq; - struct lpfc_cqe *cqe; - bool workposted = false; - uint16_t cqid; - int ecount = 0; - - if (unlikely(bf_get_le32(lpfc_eqe_major_code, eqe) != 0)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0366 Not a valid fast-path completion " - "event: majorcode=x%x, minorcode=x%x\n", - bf_get_le32(lpfc_eqe_major_code, eqe), - bf_get_le32(lpfc_eqe_minor_code, eqe)); - return; - } - - if (unlikely(!phba->sli4_hba.fcp_cq)) { - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "3146 Fast-path completion queues " - "does not exist\n"); - return; - } - cq = phba->sli4_hba.fcp_cq[fcp_cqidx]; - if (unlikely(!cq)) { - if (phba->sli.sli_flag & LPFC_SLI_ACTIVE) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0367 Fast-path completion queue " - "(%d) does not exist\n", fcp_cqidx); - return; - } - - /* Get the reference to the corresponding CQ */ - cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); - if (unlikely(cqid != cq->queue_id)) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0368 Miss-matched fast-path completion " - "queue identifier: eqcqid=%d, fcpcqid=%d\n", - cqid, cq->queue_id); - return; - } - - /* Process all the entries to the CQ */ - while ((cqe = lpfc_sli4_cq_get(cq))) { - workposted |= lpfc_sli4_fp_handle_wcqe(phba, cq, cqe); - if (!(++ecount % cq->entry_repost)) - lpfc_sli4_cq_release(cq, LPFC_QUEUE_NOARM); - } - - /* Catch the no cq entry condition */ - if (unlikely(ecount == 0)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0369 No entry from fast-path completion " - "queue fcpcqid=%d\n", cq->queue_id); - - /* In any case, flash and re-arm the CQ */ - lpfc_sli4_cq_release(cq, LPFC_QUEUE_REARM); - - /* wake up worker thread if there are works to be done */ - if (workposted) - lpfc_worker_wake_up(phba); -} - -static void -lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) -{ - struct lpfc_eqe *eqe; - - /* walk all the EQ entries and drop on the floor */ - while ((eqe = lpfc_sli4_eq_get(eq))) - ; - - /* Clear and re-arm the EQ */ - lpfc_sli4_eq_release(eq, LPFC_QUEUE_REARM); -} - -/** - * lpfc_sli4_sp_intr_handler - Slow-path interrupt handler to SLI-4 device - * @irq: Interrupt number. - * @dev_id: The device context pointer. - * - * This function is directly called from the PCI layer as an interrupt - * service routine when device with SLI-4 interface spec is enabled with - * MSI-X multi-message interrupt mode and there are slow-path events in - * the HBA. However, when the device is enabled with either MSI or Pin-IRQ - * interrupt mode, this function is called as part of the device-level - * interrupt handler. When the PCI slot is in error recovery or the HBA is - * undergoing initialization, the interrupt handler will not process the - * interrupt. The link attention and ELS ring attention events are handled - * by the worker thread. The interrupt handler signals the worker thread - * and returns for these events. This function is called without any lock - * held. It gets the hbalock to access and update SLI data structures. - * - * This function returns IRQ_HANDLED when interrupt is handled else it - * returns IRQ_NONE. - **/ -irqreturn_t -lpfc_sli4_sp_intr_handler(int irq, void *dev_id) -{ - struct lpfc_hba *phba; - struct lpfc_queue *speq; - struct lpfc_eqe *eqe; - unsigned long iflag; - int ecount = 0; - - /* - * Get the driver's phba structure from the dev_id - */ - phba = (struct lpfc_hba *)dev_id; - - if (unlikely(!phba)) - return IRQ_NONE; - - /* Get to the EQ struct associated with this vector */ - speq = phba->sli4_hba.sp_eq; - if (unlikely(!speq)) - return IRQ_NONE; - - /* Check device state for handling interrupt */ - if (unlikely(lpfc_intr_state_check(phba))) { - /* Check again for link_state with lock held */ - spin_lock_irqsave(&phba->hbalock, iflag); - if (phba->link_state < LPFC_LINK_DOWN) - /* Flush, clear interrupt, and rearm the EQ */ - lpfc_sli4_eq_flush(phba, speq); - spin_unlock_irqrestore(&phba->hbalock, iflag); - return IRQ_NONE; - } - - /* - * Process all the event on FCP slow-path EQ - */ - while ((eqe = lpfc_sli4_eq_get(speq))) { - lpfc_sli4_sp_handle_eqe(phba, eqe); - if (!(++ecount % speq->entry_repost)) - lpfc_sli4_eq_release(speq, LPFC_QUEUE_NOARM); - } - - /* Always clear and re-arm the slow-path EQ */ - lpfc_sli4_eq_release(speq, LPFC_QUEUE_REARM); - - /* Catch the no cq entry condition */ - if (unlikely(ecount == 0)) { - if (phba->intr_type == MSIX) - /* MSI-X treated interrupt served as no EQ share INT */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0357 MSI-X interrupt with no EQE\n"); - else - /* Non MSI-X treated on interrupt as EQ share INT */ - return IRQ_NONE; - } - - return IRQ_HANDLED; -} /* lpfc_sli4_sp_intr_handler */ - -/** - * lpfc_sli4_fp_intr_handler - Fast-path interrupt handler to SLI-4 device - * @irq: Interrupt number. - * @dev_id: The device context pointer. - * - * This function is directly called from the PCI layer as an interrupt - * service routine when device with SLI-4 interface spec is enabled with - * MSI-X multi-message interrupt mode and there is a fast-path FCP IOCB - * ring event in the HBA. However, when the device is enabled with either - * MSI or Pin-IRQ interrupt mode, this function is called as part of the - * device-level interrupt handler. When the PCI slot is in error recovery - * or the HBA is undergoing initialization, the interrupt handler will not - * process the interrupt. The SCSI FCP fast-path ring event are handled in - * the intrrupt context. This function is called without any lock held. - * It gets the hbalock to access and update SLI data structures. Note that, - * the FCP EQ to FCP CQ are one-to-one map such that the FCP EQ index is - * equal to that of FCP CQ index. - * - * This function returns IRQ_HANDLED when interrupt is handled else it - * returns IRQ_NONE. - **/ -irqreturn_t -lpfc_sli4_fp_intr_handler(int irq, void *dev_id) -{ - struct lpfc_hba *phba; - struct lpfc_fcp_eq_hdl *fcp_eq_hdl; - struct lpfc_queue *fpeq; - struct lpfc_eqe *eqe; - unsigned long iflag; - int ecount = 0; - uint32_t fcp_eqidx; - - /* Get the driver's phba structure from the dev_id */ - fcp_eq_hdl = (struct lpfc_fcp_eq_hdl *)dev_id; - phba = fcp_eq_hdl->phba; - fcp_eqidx = fcp_eq_hdl->idx; - - if (unlikely(!phba)) - return IRQ_NONE; - if (unlikely(!phba->sli4_hba.fp_eq)) - return IRQ_NONE; - - /* Get to the EQ struct associated with this vector */ - fpeq = phba->sli4_hba.fp_eq[fcp_eqidx]; - if (unlikely(!fpeq)) - return IRQ_NONE; - - /* Check device state for handling interrupt */ - if (unlikely(lpfc_intr_state_check(phba))) { - /* Check again for link_state with lock held */ - spin_lock_irqsave(&phba->hbalock, iflag); - if (phba->link_state < LPFC_LINK_DOWN) - /* Flush, clear interrupt, and rearm the EQ */ - lpfc_sli4_eq_flush(phba, fpeq); - spin_unlock_irqrestore(&phba->hbalock, iflag); - return IRQ_NONE; - } - - /* - * Process all the event on FCP fast-path EQ - */ - while ((eqe = lpfc_sli4_eq_get(fpeq))) { - lpfc_sli4_fp_handle_eqe(phba, eqe, fcp_eqidx); - if (!(++ecount % fpeq->entry_repost)) - lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_NOARM); - } - - /* Always clear and re-arm the fast-path EQ */ - lpfc_sli4_eq_release(fpeq, LPFC_QUEUE_REARM); - - if (unlikely(ecount == 0)) { - if (phba->intr_type == MSIX) - /* MSI-X treated interrupt served as no EQ share INT */ - lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, - "0358 MSI-X interrupt with no EQE\n"); - else - /* Non MSI-X treated on interrupt as EQ share INT */ - return IRQ_NONE; - } - - return IRQ_HANDLED; -} /* lpfc_sli4_fp_intr_handler */ - -/** - * lpfc_sli4_intr_handler - Device-level interrupt handler for SLI-4 device - * @irq: Interrupt number. - * @dev_id: The device context pointer. - * - * This function is the device-level interrupt handler to device with SLI-4 - * interface spec, called from the PCI layer when either MSI or Pin-IRQ - * interrupt mode is enabled and there is an event in the HBA which requires - * driver attention. This function invokes the slow-path interrupt attention - * handling function and fast-path interrupt attention handling function in - * turn to process the relevant HBA attention events. This function is called - * without any lock held. It gets the hbalock to access and update SLI data - * structures. - * - * This function returns IRQ_HANDLED when interrupt is handled, else it - * returns IRQ_NONE. - **/ -irqreturn_t -lpfc_sli4_intr_handler(int irq, void *dev_id) -{ - struct lpfc_hba *phba; - irqreturn_t sp_irq_rc, fp_irq_rc; - bool fp_handled = false; - uint32_t fcp_eqidx; - - /* Get the driver's phba structure from the dev_id */ - phba = (struct lpfc_hba *)dev_id; - - if (unlikely(!phba)) - return IRQ_NONE; - - /* - * Invokes slow-path host attention interrupt handling as appropriate. - */ - sp_irq_rc = lpfc_sli4_sp_intr_handler(irq, dev_id); - - /* - * Invoke fast-path host attention interrupt handling as appropriate. - */ - for (fcp_eqidx = 0; fcp_eqidx < phba->cfg_fcp_eq_count; fcp_eqidx++) { - fp_irq_rc = lpfc_sli4_fp_intr_handler(irq, - &phba->sli4_hba.fcp_eq_hdl[fcp_eqidx]); - if (fp_irq_rc == IRQ_HANDLED) - fp_handled |= true; - } - - return (fp_handled == true) ? IRQ_HANDLED : sp_irq_rc; -} /* lpfc_sli4_intr_handler */ - -/** - * lpfc_sli4_queue_free - free a queue structure and associated memory - * @queue: The queue structure to free. - * - * This function frees a queue structure and the DMAable memory used for - * the host resident queue. This function must be called after destroying the - * queue on the HBA. - **/ -void -lpfc_sli4_queue_free(struct lpfc_queue *queue) -{ - struct lpfc_dmabuf *dmabuf; - - if (!queue) - return; - - while (!list_empty(&queue->page_list)) { - list_remove_head(&queue->page_list, dmabuf, struct lpfc_dmabuf, - list); - dma_free_coherent(&queue->phba->pcidev->dev, SLI4_PAGE_SIZE, - dmabuf->virt, dmabuf->phys); - kfree(dmabuf); - } - kfree(queue); - return; -} - -/** - * lpfc_sli4_queue_alloc - Allocate and initialize a queue structure - * @phba: The HBA that this queue is being created on. - * @entry_size: The size of each queue entry for this queue. - * @entry count: The number of entries that this queue will handle. - * - * This function allocates a queue structure and the DMAable memory used for - * the host resident queue. This function must be called before creating the - * queue on the HBA. - **/ -struct lpfc_queue * -lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size, - uint32_t entry_count) -{ - struct lpfc_queue *queue; - struct lpfc_dmabuf *dmabuf; - int x, total_qe_count; - void *dma_pointer; - uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; - - if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; - - queue = kzalloc(sizeof(struct lpfc_queue) + - (sizeof(union sli4_qe) * entry_count), GFP_KERNEL); - if (!queue) - return NULL; - queue->page_count = (ALIGN(entry_size * entry_count, - hw_page_size))/hw_page_size; - INIT_LIST_HEAD(&queue->list); - INIT_LIST_HEAD(&queue->page_list); - INIT_LIST_HEAD(&queue->child_list); - for (x = 0, total_qe_count = 0; x < queue->page_count; x++) { - dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); - if (!dmabuf) - goto out_fail; - dmabuf->virt = dma_alloc_coherent(&phba->pcidev->dev, - hw_page_size, &dmabuf->phys, - GFP_KERNEL); - if (!dmabuf->virt) { - kfree(dmabuf); - goto out_fail; - } - memset(dmabuf->virt, 0, hw_page_size); - dmabuf->buffer_tag = x; - list_add_tail(&dmabuf->list, &queue->page_list); - /* initialize queue's entry array */ - dma_pointer = dmabuf->virt; - for (; total_qe_count < entry_count && - dma_pointer < (hw_page_size + dmabuf->virt); - total_qe_count++, dma_pointer += entry_size) { - queue->qe[total_qe_count].address = dma_pointer; - } - } - queue->entry_size = entry_size; - queue->entry_count = entry_count; - - /* - * entry_repost is calculated based on the number of entries in the - * queue. This works out except for RQs. If buffers are NOT initially - * posted for every RQE, entry_repost should be adjusted accordingly. - */ - queue->entry_repost = (entry_count >> 3); - if (queue->entry_repost < LPFC_QUEUE_MIN_REPOST) - queue->entry_repost = LPFC_QUEUE_MIN_REPOST; - queue->phba = phba; - - return queue; -out_fail: - lpfc_sli4_queue_free(queue); - return NULL; -} - -/** - * lpfc_eq_create - Create an Event Queue on the HBA - * @phba: HBA structure that indicates port to create a queue on. - * @eq: The queue structure to use to create the event queue. - * @imax: The maximum interrupt per second limit. - * - * This function creates an event queue, as detailed in @eq, on a port, - * described by @phba by sending an EQ_CREATE mailbox command to the HBA. - * - * The @phba struct is used to send mailbox command to HBA. The @eq struct - * is used to get the entry count and entry size that are necessary to - * determine the number of pages to allocate and use for this queue. This - * function will send the EQ_CREATE mailbox command to the HBA to setup the - * event queue. This function is asynchronous and will wait for the mailbox - * command to finish before continuing. - * - * On success this function will return a zero. If unable to allocate enough - * memory this function will return -ENOMEM. If the queue create mailbox command - * fails this function will return -ENXIO. - **/ -uint32_t -lpfc_eq_create(struct lpfc_hba *phba, struct lpfc_queue *eq, uint16_t imax) -{ - struct lpfc_mbx_eq_create *eq_create; - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - struct lpfc_dmabuf *dmabuf; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - uint16_t dmult; - uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; - - /* sanity check on queue memory */ - if (!eq) - return -ENODEV; - if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_eq_create) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_EQ_CREATE, - length, LPFC_SLI4_MBX_EMBED); - eq_create = &mbox->u.mqe.un.eq_create; - bf_set(lpfc_mbx_eq_create_num_pages, &eq_create->u.request, - eq->page_count); - bf_set(lpfc_eq_context_size, &eq_create->u.request.context, - LPFC_EQE_SIZE); - bf_set(lpfc_eq_context_valid, &eq_create->u.request.context, 1); - /* Calculate delay multiper from maximum interrupt per second */ - dmult = LPFC_DMULT_CONST/imax - 1; - bf_set(lpfc_eq_context_delay_multi, &eq_create->u.request.context, - dmult); - switch (eq->entry_count) { - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0360 Unsupported EQ count. (%d)\n", - eq->entry_count); - if (eq->entry_count < 256) - return -EINVAL; - /* otherwise default to smallest count (drop through) */ - case 256: - bf_set(lpfc_eq_context_count, &eq_create->u.request.context, - LPFC_EQ_CNT_256); - break; - case 512: - bf_set(lpfc_eq_context_count, &eq_create->u.request.context, - LPFC_EQ_CNT_512); - break; - case 1024: - bf_set(lpfc_eq_context_count, &eq_create->u.request.context, - LPFC_EQ_CNT_1024); - break; - case 2048: - bf_set(lpfc_eq_context_count, &eq_create->u.request.context, - LPFC_EQ_CNT_2048); - break; - case 4096: - bf_set(lpfc_eq_context_count, &eq_create->u.request.context, - LPFC_EQ_CNT_4096); - break; - } - list_for_each_entry(dmabuf, &eq->page_list, list) { - memset(dmabuf->virt, 0, hw_page_size); - eq_create->u.request.page[dmabuf->buffer_tag].addr_lo = - putPaddrLow(dmabuf->phys); - eq_create->u.request.page[dmabuf->buffer_tag].addr_hi = - putPaddrHigh(dmabuf->phys); - } - mbox->vport = phba->pport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->context1 = NULL; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) &eq_create->header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2500 EQ_CREATE mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - } - eq->type = LPFC_EQ; - eq->subtype = LPFC_NONE; - eq->queue_id = bf_get(lpfc_mbx_eq_create_q_id, &eq_create->u.response); - if (eq->queue_id == 0xFFFF) - status = -ENXIO; - eq->host_index = 0; - eq->hba_index = 0; - - mempool_free(mbox, phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_cq_create - Create a Completion Queue on the HBA - * @phba: HBA structure that indicates port to create a queue on. - * @cq: The queue structure to use to create the completion queue. - * @eq: The event queue to bind this completion queue to. - * - * This function creates a completion queue, as detailed in @wq, on a port, - * described by @phba by sending a CQ_CREATE mailbox command to the HBA. - * - * The @phba struct is used to send mailbox command to HBA. The @cq struct - * is used to get the entry count and entry size that are necessary to - * determine the number of pages to allocate and use for this queue. The @eq - * is used to indicate which event queue to bind this completion queue to. This - * function will send the CQ_CREATE mailbox command to the HBA to setup the - * completion queue. This function is asynchronous and will wait for the mailbox - * command to finish before continuing. - * - * On success this function will return a zero. If unable to allocate enough - * memory this function will return -ENOMEM. If the queue create mailbox command - * fails this function will return -ENXIO. - **/ -uint32_t -lpfc_cq_create(struct lpfc_hba *phba, struct lpfc_queue *cq, - struct lpfc_queue *eq, uint32_t type, uint32_t subtype) -{ - struct lpfc_mbx_cq_create *cq_create; - struct lpfc_dmabuf *dmabuf; - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; - - /* sanity check on queue memory */ - if (!cq || !eq) - return -ENODEV; - if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_cq_create) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_CQ_CREATE, - length, LPFC_SLI4_MBX_EMBED); - cq_create = &mbox->u.mqe.un.cq_create; - shdr = (union lpfc_sli4_cfg_shdr *) &cq_create->header.cfg_shdr; - bf_set(lpfc_mbx_cq_create_num_pages, &cq_create->u.request, - cq->page_count); - bf_set(lpfc_cq_context_event, &cq_create->u.request.context, 1); - bf_set(lpfc_cq_context_valid, &cq_create->u.request.context, 1); - bf_set(lpfc_mbox_hdr_version, &shdr->request, - phba->sli4_hba.pc_sli4_params.cqv); - if (phba->sli4_hba.pc_sli4_params.cqv == LPFC_Q_CREATE_VERSION_2) { - /* FW only supports 1. Should be PAGE_SIZE/SLI4_PAGE_SIZE */ - bf_set(lpfc_mbx_cq_create_page_size, &cq_create->u.request, 1); - bf_set(lpfc_cq_eq_id_2, &cq_create->u.request.context, - eq->queue_id); - } else { - bf_set(lpfc_cq_eq_id, &cq_create->u.request.context, - eq->queue_id); - } - switch (cq->entry_count) { - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0361 Unsupported CQ count. (%d)\n", - cq->entry_count); - if (cq->entry_count < 256) - return -EINVAL; - /* otherwise default to smallest count (drop through) */ - case 256: - bf_set(lpfc_cq_context_count, &cq_create->u.request.context, - LPFC_CQ_CNT_256); - break; - case 512: - bf_set(lpfc_cq_context_count, &cq_create->u.request.context, - LPFC_CQ_CNT_512); - break; - case 1024: - bf_set(lpfc_cq_context_count, &cq_create->u.request.context, - LPFC_CQ_CNT_1024); - break; - } - list_for_each_entry(dmabuf, &cq->page_list, list) { - memset(dmabuf->virt, 0, hw_page_size); - cq_create->u.request.page[dmabuf->buffer_tag].addr_lo = - putPaddrLow(dmabuf->phys); - cq_create->u.request.page[dmabuf->buffer_tag].addr_hi = - putPaddrHigh(dmabuf->phys); - } - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2501 CQ_CREATE mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - goto out; - } - cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response); - if (cq->queue_id == 0xFFFF) { - status = -ENXIO; - goto out; - } - /* link the cq onto the parent eq child list */ - list_add_tail(&cq->list, &eq->child_list); - /* Set up completion queue's type and subtype */ - cq->type = type; - cq->subtype = subtype; - cq->queue_id = bf_get(lpfc_mbx_cq_create_q_id, &cq_create->u.response); - cq->assoc_qid = eq->queue_id; - cq->host_index = 0; - cq->hba_index = 0; - -out: - mempool_free(mbox, phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_mq_create_fb_init - Send MCC_CREATE without async events registration - * @phba: HBA structure that indicates port to create a queue on. - * @mq: The queue structure to use to create the mailbox queue. - * @mbox: An allocated pointer to type LPFC_MBOXQ_t - * @cq: The completion queue to associate with this cq. - * - * This function provides failback (fb) functionality when the - * mq_create_ext fails on older FW generations. It's purpose is identical - * to mq_create_ext otherwise. - * - * This routine cannot fail as all attributes were previously accessed and - * initialized in mq_create_ext. - **/ -static void -lpfc_mq_create_fb_init(struct lpfc_hba *phba, struct lpfc_queue *mq, - LPFC_MBOXQ_t *mbox, struct lpfc_queue *cq) -{ - struct lpfc_mbx_mq_create *mq_create; - struct lpfc_dmabuf *dmabuf; - int length; - - length = (sizeof(struct lpfc_mbx_mq_create) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_MQ_CREATE, - length, LPFC_SLI4_MBX_EMBED); - mq_create = &mbox->u.mqe.un.mq_create; - bf_set(lpfc_mbx_mq_create_num_pages, &mq_create->u.request, - mq->page_count); - bf_set(lpfc_mq_context_cq_id, &mq_create->u.request.context, - cq->queue_id); - bf_set(lpfc_mq_context_valid, &mq_create->u.request.context, 1); - switch (mq->entry_count) { - case 16: - bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, - LPFC_MQ_RING_SIZE_16); - break; - case 32: - bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, - LPFC_MQ_RING_SIZE_32); - break; - case 64: - bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, - LPFC_MQ_RING_SIZE_64); - break; - case 128: - bf_set(lpfc_mq_context_ring_size, &mq_create->u.request.context, - LPFC_MQ_RING_SIZE_128); - break; - } - list_for_each_entry(dmabuf, &mq->page_list, list) { - mq_create->u.request.page[dmabuf->buffer_tag].addr_lo = - putPaddrLow(dmabuf->phys); - mq_create->u.request.page[dmabuf->buffer_tag].addr_hi = - putPaddrHigh(dmabuf->phys); - } -} - -/** - * lpfc_mq_create - Create a mailbox Queue on the HBA - * @phba: HBA structure that indicates port to create a queue on. - * @mq: The queue structure to use to create the mailbox queue. - * @cq: The completion queue to associate with this cq. - * @subtype: The queue's subtype. - * - * This function creates a mailbox queue, as detailed in @mq, on a port, - * described by @phba by sending a MQ_CREATE mailbox command to the HBA. - * - * The @phba struct is used to send mailbox command to HBA. The @cq struct - * is used to get the entry count and entry size that are necessary to - * determine the number of pages to allocate and use for this queue. This - * function will send the MQ_CREATE mailbox command to the HBA to setup the - * mailbox queue. This function is asynchronous and will wait for the mailbox - * command to finish before continuing. - * - * On success this function will return a zero. If unable to allocate enough - * memory this function will return -ENOMEM. If the queue create mailbox command - * fails this function will return -ENXIO. - **/ -int32_t -lpfc_mq_create(struct lpfc_hba *phba, struct lpfc_queue *mq, - struct lpfc_queue *cq, uint32_t subtype) -{ - struct lpfc_mbx_mq_create *mq_create; - struct lpfc_mbx_mq_create_ext *mq_create_ext; - struct lpfc_dmabuf *dmabuf; - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; - - /* sanity check on queue memory */ - if (!mq || !cq) - return -ENODEV; - if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_mq_create_ext) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_MQ_CREATE_EXT, - length, LPFC_SLI4_MBX_EMBED); - - mq_create_ext = &mbox->u.mqe.un.mq_create_ext; - shdr = (union lpfc_sli4_cfg_shdr *) &mq_create_ext->header.cfg_shdr; - bf_set(lpfc_mbx_mq_create_ext_num_pages, - &mq_create_ext->u.request, mq->page_count); - bf_set(lpfc_mbx_mq_create_ext_async_evt_link, - &mq_create_ext->u.request, 1); - bf_set(lpfc_mbx_mq_create_ext_async_evt_fip, - &mq_create_ext->u.request, 1); - bf_set(lpfc_mbx_mq_create_ext_async_evt_group5, - &mq_create_ext->u.request, 1); - bf_set(lpfc_mbx_mq_create_ext_async_evt_fc, - &mq_create_ext->u.request, 1); - bf_set(lpfc_mbx_mq_create_ext_async_evt_sli, - &mq_create_ext->u.request, 1); - bf_set(lpfc_mq_context_valid, &mq_create_ext->u.request.context, 1); - bf_set(lpfc_mbox_hdr_version, &shdr->request, - phba->sli4_hba.pc_sli4_params.mqv); - if (phba->sli4_hba.pc_sli4_params.mqv == LPFC_Q_CREATE_VERSION_1) - bf_set(lpfc_mbx_mq_create_ext_cq_id, &mq_create_ext->u.request, - cq->queue_id); - else - bf_set(lpfc_mq_context_cq_id, &mq_create_ext->u.request.context, - cq->queue_id); - switch (mq->entry_count) { - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0362 Unsupported MQ count. (%d)\n", - mq->entry_count); - if (mq->entry_count < 16) - return -EINVAL; - /* otherwise default to smallest count (drop through) */ - case 16: - bf_set(lpfc_mq_context_ring_size, - &mq_create_ext->u.request.context, - LPFC_MQ_RING_SIZE_16); - break; - case 32: - bf_set(lpfc_mq_context_ring_size, - &mq_create_ext->u.request.context, - LPFC_MQ_RING_SIZE_32); - break; - case 64: - bf_set(lpfc_mq_context_ring_size, - &mq_create_ext->u.request.context, - LPFC_MQ_RING_SIZE_64); - break; - case 128: - bf_set(lpfc_mq_context_ring_size, - &mq_create_ext->u.request.context, - LPFC_MQ_RING_SIZE_128); - break; - } - list_for_each_entry(dmabuf, &mq->page_list, list) { - memset(dmabuf->virt, 0, hw_page_size); - mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_lo = - putPaddrLow(dmabuf->phys); - mq_create_ext->u.request.page[dmabuf->buffer_tag].addr_hi = - putPaddrHigh(dmabuf->phys); - } - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, - &mq_create_ext->u.response); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2795 MQ_CREATE_EXT failed with " - "status x%x. Failback to MQ_CREATE.\n", - rc); - lpfc_mq_create_fb_init(phba, mq, mbox, cq); - mq_create = &mbox->u.mqe.un.mq_create; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) &mq_create->header.cfg_shdr; - mq->queue_id = bf_get(lpfc_mbx_mq_create_q_id, - &mq_create->u.response); - } - - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2502 MQ_CREATE mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - goto out; - } - if (mq->queue_id == 0xFFFF) { - status = -ENXIO; - goto out; - } - mq->type = LPFC_MQ; - mq->assoc_qid = cq->queue_id; - mq->subtype = subtype; - mq->host_index = 0; - mq->hba_index = 0; - - /* link the mq onto the parent cq child list */ - list_add_tail(&mq->list, &cq->child_list); -out: - mempool_free(mbox, phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_wq_create - Create a Work Queue on the HBA - * @phba: HBA structure that indicates port to create a queue on. - * @wq: The queue structure to use to create the work queue. - * @cq: The completion queue to bind this work queue to. - * @subtype: The subtype of the work queue indicating its functionality. - * - * This function creates a work queue, as detailed in @wq, on a port, described - * by @phba by sending a WQ_CREATE mailbox command to the HBA. - * - * The @phba struct is used to send mailbox command to HBA. The @wq struct - * is used to get the entry count and entry size that are necessary to - * determine the number of pages to allocate and use for this queue. The @cq - * is used to indicate which completion queue to bind this work queue to. This - * function will send the WQ_CREATE mailbox command to the HBA to setup the - * work queue. This function is asynchronous and will wait for the mailbox - * command to finish before continuing. - * - * On success this function will return a zero. If unable to allocate enough - * memory this function will return -ENOMEM. If the queue create mailbox command - * fails this function will return -ENXIO. - **/ -uint32_t -lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq, - struct lpfc_queue *cq, uint32_t subtype) -{ - struct lpfc_mbx_wq_create *wq_create; - struct lpfc_dmabuf *dmabuf; - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; - struct dma_address *page; - - /* sanity check on queue memory */ - if (!wq || !cq) - return -ENODEV; - if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_wq_create) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_WQ_CREATE, - length, LPFC_SLI4_MBX_EMBED); - wq_create = &mbox->u.mqe.un.wq_create; - shdr = (union lpfc_sli4_cfg_shdr *) &wq_create->header.cfg_shdr; - bf_set(lpfc_mbx_wq_create_num_pages, &wq_create->u.request, - wq->page_count); - bf_set(lpfc_mbx_wq_create_cq_id, &wq_create->u.request, - cq->queue_id); - bf_set(lpfc_mbox_hdr_version, &shdr->request, - phba->sli4_hba.pc_sli4_params.wqv); - if (phba->sli4_hba.pc_sli4_params.wqv == LPFC_Q_CREATE_VERSION_1) { - bf_set(lpfc_mbx_wq_create_wqe_count, &wq_create->u.request_1, - wq->entry_count); - switch (wq->entry_size) { - default: - case 64: - bf_set(lpfc_mbx_wq_create_wqe_size, - &wq_create->u.request_1, - LPFC_WQ_WQE_SIZE_64); - break; - case 128: - bf_set(lpfc_mbx_wq_create_wqe_size, - &wq_create->u.request_1, - LPFC_WQ_WQE_SIZE_128); - break; - } - bf_set(lpfc_mbx_wq_create_page_size, &wq_create->u.request_1, - (PAGE_SIZE/SLI4_PAGE_SIZE)); - page = wq_create->u.request_1.page; - } else { - page = wq_create->u.request.page; - } - list_for_each_entry(dmabuf, &wq->page_list, list) { - memset(dmabuf->virt, 0, hw_page_size); - page[dmabuf->buffer_tag].addr_lo = putPaddrLow(dmabuf->phys); - page[dmabuf->buffer_tag].addr_hi = putPaddrHigh(dmabuf->phys); - } - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2503 WQ_CREATE mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - goto out; - } - wq->queue_id = bf_get(lpfc_mbx_wq_create_q_id, &wq_create->u.response); - if (wq->queue_id == 0xFFFF) { - status = -ENXIO; - goto out; - } - wq->type = LPFC_WQ; - wq->assoc_qid = cq->queue_id; - wq->subtype = subtype; - wq->host_index = 0; - wq->hba_index = 0; - wq->entry_repost = LPFC_RELEASE_NOTIFICATION_INTERVAL; - - /* link the wq onto the parent cq child list */ - list_add_tail(&wq->list, &cq->child_list); -out: - mempool_free(mbox, phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_rq_adjust_repost - Adjust entry_repost for an RQ - * @phba: HBA structure that indicates port to create a queue on. - * @rq: The queue structure to use for the receive queue. - * @qno: The associated HBQ number - * - * - * For SLI4 we need to adjust the RQ repost value based on - * the number of buffers that are initially posted to the RQ. - */ -void -lpfc_rq_adjust_repost(struct lpfc_hba *phba, struct lpfc_queue *rq, int qno) -{ - uint32_t cnt; - - /* sanity check on queue memory */ - if (!rq) - return; - cnt = lpfc_hbq_defs[qno]->entry_count; - - /* Recalc repost for RQs based on buffers initially posted */ - cnt = (cnt >> 3); - if (cnt < LPFC_QUEUE_MIN_REPOST) - cnt = LPFC_QUEUE_MIN_REPOST; - - rq->entry_repost = cnt; -} - -/** - * lpfc_rq_create - Create a Receive Queue on the HBA - * @phba: HBA structure that indicates port to create a queue on. - * @hrq: The queue structure to use to create the header receive queue. - * @drq: The queue structure to use to create the data receive queue. - * @cq: The completion queue to bind this work queue to. - * - * This function creates a receive buffer queue pair , as detailed in @hrq and - * @drq, on a port, described by @phba by sending a RQ_CREATE mailbox command - * to the HBA. - * - * The @phba struct is used to send mailbox command to HBA. The @drq and @hrq - * struct is used to get the entry count that is necessary to determine the - * number of pages to use for this queue. The @cq is used to indicate which - * completion queue to bind received buffers that are posted to these queues to. - * This function will send the RQ_CREATE mailbox command to the HBA to setup the - * receive queue pair. This function is asynchronous and will wait for the - * mailbox command to finish before continuing. - * - * On success this function will return a zero. If unable to allocate enough - * memory this function will return -ENOMEM. If the queue create mailbox command - * fails this function will return -ENXIO. - **/ -uint32_t -lpfc_rq_create(struct lpfc_hba *phba, struct lpfc_queue *hrq, - struct lpfc_queue *drq, struct lpfc_queue *cq, uint32_t subtype) -{ - struct lpfc_mbx_rq_create *rq_create; - struct lpfc_dmabuf *dmabuf; - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - uint32_t hw_page_size = phba->sli4_hba.pc_sli4_params.if_page_sz; - - /* sanity check on queue memory */ - if (!hrq || !drq || !cq) - return -ENODEV; - if (!phba->sli4_hba.pc_sli4_params.supported) - hw_page_size = SLI4_PAGE_SIZE; - - if (hrq->entry_count != drq->entry_count) - return -EINVAL; - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_rq_create) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, - length, LPFC_SLI4_MBX_EMBED); - rq_create = &mbox->u.mqe.un.rq_create; - shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; - bf_set(lpfc_mbox_hdr_version, &shdr->request, - phba->sli4_hba.pc_sli4_params.rqv); - if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) { - bf_set(lpfc_rq_context_rqe_count_1, - &rq_create->u.request.context, - hrq->entry_count); - rq_create->u.request.context.buffer_size = LPFC_HDR_BUF_SIZE; - bf_set(lpfc_rq_context_rqe_size, - &rq_create->u.request.context, - LPFC_RQE_SIZE_8); - bf_set(lpfc_rq_context_page_size, - &rq_create->u.request.context, - (PAGE_SIZE/SLI4_PAGE_SIZE)); - } else { - switch (hrq->entry_count) { - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2535 Unsupported RQ count. (%d)\n", - hrq->entry_count); - if (hrq->entry_count < 512) - return -EINVAL; - /* otherwise default to smallest count (drop through) */ - case 512: - bf_set(lpfc_rq_context_rqe_count, - &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_512); - break; - case 1024: - bf_set(lpfc_rq_context_rqe_count, - &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_1024); - break; - case 2048: - bf_set(lpfc_rq_context_rqe_count, - &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_2048); - break; - case 4096: - bf_set(lpfc_rq_context_rqe_count, - &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_4096); - break; - } - bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, - LPFC_HDR_BUF_SIZE); - } - bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, - cq->queue_id); - bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, - hrq->page_count); - list_for_each_entry(dmabuf, &hrq->page_list, list) { - memset(dmabuf->virt, 0, hw_page_size); - rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = - putPaddrLow(dmabuf->phys); - rq_create->u.request.page[dmabuf->buffer_tag].addr_hi = - putPaddrHigh(dmabuf->phys); - } - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2504 RQ_CREATE mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - goto out; - } - hrq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response); - if (hrq->queue_id == 0xFFFF) { - status = -ENXIO; - goto out; - } - hrq->type = LPFC_HRQ; - hrq->assoc_qid = cq->queue_id; - hrq->subtype = subtype; - hrq->host_index = 0; - hrq->hba_index = 0; - - /* now create the data queue */ - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_RQ_CREATE, - length, LPFC_SLI4_MBX_EMBED); - bf_set(lpfc_mbox_hdr_version, &shdr->request, - phba->sli4_hba.pc_sli4_params.rqv); - if (phba->sli4_hba.pc_sli4_params.rqv == LPFC_Q_CREATE_VERSION_1) { - bf_set(lpfc_rq_context_rqe_count_1, - &rq_create->u.request.context, hrq->entry_count); - rq_create->u.request.context.buffer_size = LPFC_DATA_BUF_SIZE; - bf_set(lpfc_rq_context_rqe_size, &rq_create->u.request.context, - LPFC_RQE_SIZE_8); - bf_set(lpfc_rq_context_page_size, &rq_create->u.request.context, - (PAGE_SIZE/SLI4_PAGE_SIZE)); - } else { - switch (drq->entry_count) { - default: - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2536 Unsupported RQ count. (%d)\n", - drq->entry_count); - if (drq->entry_count < 512) - return -EINVAL; - /* otherwise default to smallest count (drop through) */ - case 512: - bf_set(lpfc_rq_context_rqe_count, - &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_512); - break; - case 1024: - bf_set(lpfc_rq_context_rqe_count, - &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_1024); - break; - case 2048: - bf_set(lpfc_rq_context_rqe_count, - &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_2048); - break; - case 4096: - bf_set(lpfc_rq_context_rqe_count, - &rq_create->u.request.context, - LPFC_RQ_RING_SIZE_4096); - break; - } - bf_set(lpfc_rq_context_buf_size, &rq_create->u.request.context, - LPFC_DATA_BUF_SIZE); - } - bf_set(lpfc_rq_context_cq_id, &rq_create->u.request.context, - cq->queue_id); - bf_set(lpfc_mbx_rq_create_num_pages, &rq_create->u.request, - drq->page_count); - list_for_each_entry(dmabuf, &drq->page_list, list) { - rq_create->u.request.page[dmabuf->buffer_tag].addr_lo = - putPaddrLow(dmabuf->phys); - rq_create->u.request.page[dmabuf->buffer_tag].addr_hi = - putPaddrHigh(dmabuf->phys); - } - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) &rq_create->header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - status = -ENXIO; - goto out; - } - drq->queue_id = bf_get(lpfc_mbx_rq_create_q_id, &rq_create->u.response); - if (drq->queue_id == 0xFFFF) { - status = -ENXIO; - goto out; - } - drq->type = LPFC_DRQ; - drq->assoc_qid = cq->queue_id; - drq->subtype = subtype; - drq->host_index = 0; - drq->hba_index = 0; - - /* link the header and data RQs onto the parent cq child list */ - list_add_tail(&hrq->list, &cq->child_list); - list_add_tail(&drq->list, &cq->child_list); - -out: - mempool_free(mbox, phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_eq_destroy - Destroy an event Queue on the HBA - * @eq: The queue structure associated with the queue to destroy. - * - * This function destroys a queue, as detailed in @eq by sending an mailbox - * command, specific to the type of queue, to the HBA. - * - * The @eq struct is used to get the queue ID of the queue to destroy. - * - * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return -ENXIO. - **/ -uint32_t -lpfc_eq_destroy(struct lpfc_hba *phba, struct lpfc_queue *eq) -{ - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* sanity check on queue memory */ - if (!eq) - return -ENODEV; - mbox = mempool_alloc(eq->phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_eq_destroy) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_EQ_DESTROY, - length, LPFC_SLI4_MBX_EMBED); - bf_set(lpfc_mbx_eq_destroy_q_id, &mbox->u.mqe.un.eq_destroy.u.request, - eq->queue_id); - mbox->vport = eq->phba->pport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - - rc = lpfc_sli_issue_mbox(eq->phba, mbox, MBX_POLL); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) - &mbox->u.mqe.un.eq_destroy.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2505 EQ_DESTROY mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - } - - /* Remove eq from any list */ - list_del_init(&eq->list); - mempool_free(mbox, eq->phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_cq_destroy - Destroy a Completion Queue on the HBA - * @cq: The queue structure associated with the queue to destroy. - * - * This function destroys a queue, as detailed in @cq by sending an mailbox - * command, specific to the type of queue, to the HBA. - * - * The @cq struct is used to get the queue ID of the queue to destroy. - * - * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return -ENXIO. - **/ -uint32_t -lpfc_cq_destroy(struct lpfc_hba *phba, struct lpfc_queue *cq) -{ - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* sanity check on queue memory */ - if (!cq) - return -ENODEV; - mbox = mempool_alloc(cq->phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_cq_destroy) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_CQ_DESTROY, - length, LPFC_SLI4_MBX_EMBED); - bf_set(lpfc_mbx_cq_destroy_q_id, &mbox->u.mqe.un.cq_destroy.u.request, - cq->queue_id); - mbox->vport = cq->phba->pport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(cq->phba, mbox, MBX_POLL); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) - &mbox->u.mqe.un.wq_create.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2506 CQ_DESTROY mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - } - /* Remove cq from any list */ - list_del_init(&cq->list); - mempool_free(mbox, cq->phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_mq_destroy - Destroy a Mailbox Queue on the HBA - * @qm: The queue structure associated with the queue to destroy. - * - * This function destroys a queue, as detailed in @mq by sending an mailbox - * command, specific to the type of queue, to the HBA. - * - * The @mq struct is used to get the queue ID of the queue to destroy. - * - * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return -ENXIO. - **/ -uint32_t -lpfc_mq_destroy(struct lpfc_hba *phba, struct lpfc_queue *mq) -{ - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* sanity check on queue memory */ - if (!mq) - return -ENODEV; - mbox = mempool_alloc(mq->phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_mq_destroy) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_MQ_DESTROY, - length, LPFC_SLI4_MBX_EMBED); - bf_set(lpfc_mbx_mq_destroy_q_id, &mbox->u.mqe.un.mq_destroy.u.request, - mq->queue_id); - mbox->vport = mq->phba->pport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(mq->phba, mbox, MBX_POLL); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) - &mbox->u.mqe.un.mq_destroy.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2507 MQ_DESTROY mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - } - /* Remove mq from any list */ - list_del_init(&mq->list); - mempool_free(mbox, mq->phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_wq_destroy - Destroy a Work Queue on the HBA - * @wq: The queue structure associated with the queue to destroy. - * - * This function destroys a queue, as detailed in @wq by sending an mailbox - * command, specific to the type of queue, to the HBA. - * - * The @wq struct is used to get the queue ID of the queue to destroy. - * - * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return -ENXIO. - **/ -uint32_t -lpfc_wq_destroy(struct lpfc_hba *phba, struct lpfc_queue *wq) -{ - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* sanity check on queue memory */ - if (!wq) - return -ENODEV; - mbox = mempool_alloc(wq->phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_wq_destroy) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_WQ_DESTROY, - length, LPFC_SLI4_MBX_EMBED); - bf_set(lpfc_mbx_wq_destroy_q_id, &mbox->u.mqe.un.wq_destroy.u.request, - wq->queue_id); - mbox->vport = wq->phba->pport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(wq->phba, mbox, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) - &mbox->u.mqe.un.wq_destroy.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2508 WQ_DESTROY mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - } - /* Remove wq from any list */ - list_del_init(&wq->list); - mempool_free(mbox, wq->phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_rq_destroy - Destroy a Receive Queue on the HBA - * @rq: The queue structure associated with the queue to destroy. - * - * This function destroys a queue, as detailed in @rq by sending an mailbox - * command, specific to the type of queue, to the HBA. - * - * The @rq struct is used to get the queue ID of the queue to destroy. - * - * On success this function will return a zero. If the queue destroy mailbox - * command fails this function will return -ENXIO. - **/ -uint32_t -lpfc_rq_destroy(struct lpfc_hba *phba, struct lpfc_queue *hrq, - struct lpfc_queue *drq) -{ - LPFC_MBOXQ_t *mbox; - int rc, length, status = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* sanity check on queue memory */ - if (!hrq || !drq) - return -ENODEV; - mbox = mempool_alloc(hrq->phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - length = (sizeof(struct lpfc_mbx_rq_destroy) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_RQ_DESTROY, - length, LPFC_SLI4_MBX_EMBED); - bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request, - hrq->queue_id); - mbox->vport = hrq->phba->pport; - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox(hrq->phba, mbox, MBX_POLL); - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) - &mbox->u.mqe.un.rq_destroy.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2509 RQ_DESTROY mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, hrq->phba->mbox_mem_pool); - return -ENXIO; - } - bf_set(lpfc_mbx_rq_destroy_q_id, &mbox->u.mqe.un.rq_destroy.u.request, - drq->queue_id); - rc = lpfc_sli_issue_mbox(drq->phba, mbox, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) - &mbox->u.mqe.un.rq_destroy.header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2510 RQ_DESTROY mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - status = -ENXIO; - } - list_del_init(&hrq->list); - list_del_init(&drq->list); - mempool_free(mbox, hrq->phba->mbox_mem_pool); - return status; -} - -/** - * lpfc_sli4_post_sgl - Post scatter gather list for an XRI to HBA - * @phba: The virtual port for which this call being executed. - * @pdma_phys_addr0: Physical address of the 1st SGL page. - * @pdma_phys_addr1: Physical address of the 2nd SGL page. - * @xritag: the xritag that ties this io to the SGL pages. - * - * This routine will post the sgl pages for the IO that has the xritag - * that is in the iocbq structure. The xritag is assigned during iocbq - * creation and persists for as long as the driver is loaded. - * if the caller has fewer than 256 scatter gather segments to map then - * pdma_phys_addr1 should be 0. - * If the caller needs to map more than 256 scatter gather segment then - * pdma_phys_addr1 should be a valid physical address. - * physical address for SGLs must be 64 byte aligned. - * If you are going to map 2 SGL's then the first one must have 256 entries - * the second sgl can have between 1 and 256 entries. - * - * Return codes: - * 0 - Success - * -ENXIO, -ENOMEM - Failure - **/ -int -lpfc_sli4_post_sgl(struct lpfc_hba *phba, - dma_addr_t pdma_phys_addr0, - dma_addr_t pdma_phys_addr1, - uint16_t xritag) -{ - struct lpfc_mbx_post_sgl_pages *post_sgl_pages; - LPFC_MBOXQ_t *mbox; - int rc; - uint32_t shdr_status, shdr_add_status; - uint32_t mbox_tmo; - union lpfc_sli4_cfg_shdr *shdr; - - if (xritag == NO_XRI) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "0364 Invalid param:\n"); - return -EINVAL; - } - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - sizeof(struct lpfc_mbx_post_sgl_pages) - - sizeof(struct lpfc_sli4_cfg_mhdr), LPFC_SLI4_MBX_EMBED); - - post_sgl_pages = (struct lpfc_mbx_post_sgl_pages *) - &mbox->u.mqe.un.post_sgl_pages; - bf_set(lpfc_post_sgl_pages_xri, post_sgl_pages, xritag); - bf_set(lpfc_post_sgl_pages_xricnt, post_sgl_pages, 1); - - post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(pdma_phys_addr0)); - post_sgl_pages->sgl_pg_pairs[0].sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(pdma_phys_addr0)); - - post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(pdma_phys_addr1)); - post_sgl_pages->sgl_pg_pairs[0].sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(pdma_phys_addr1)); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) &post_sgl_pages->header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2511 POST_SGL mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - } - return 0; -} - -/** - * lpfc_sli4_alloc_xri - Get an available rpi in the device's range - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post rpi header templates to the - * HBA consistent with the SLI-4 interface spec. This routine - * posts a SLI4_PAGE_SIZE memory region to the port to hold up to - * SLI4_PAGE_SIZE modulo 64 rpi context headers. - * - * Returns - * A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful - * LPFC_RPI_ALLOC_ERROR if no rpis are available. - **/ -uint16_t -lpfc_sli4_alloc_xri(struct lpfc_hba *phba) -{ - unsigned long xri; - - /* - * Fetch the next logical xri. Because this index is logical, - * the driver starts at 0 each time. - */ - spin_lock_irq(&phba->hbalock); - xri = find_next_zero_bit(phba->sli4_hba.xri_bmask, - phba->sli4_hba.max_cfg_param.max_xri, 0); - if (xri >= phba->sli4_hba.max_cfg_param.max_xri) { - spin_unlock_irq(&phba->hbalock); - return NO_XRI; - } else { - set_bit(xri, phba->sli4_hba.xri_bmask); - phba->sli4_hba.max_cfg_param.xri_used++; - phba->sli4_hba.xri_count++; - } - - spin_unlock_irq(&phba->hbalock); - return xri; -} - -/** - * lpfc_sli4_free_xri - Release an xri for reuse. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to release an xri to the pool of - * available rpis maintained by the driver. - **/ -void -__lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri) -{ - if (test_and_clear_bit(xri, phba->sli4_hba.xri_bmask)) { - phba->sli4_hba.xri_count--; - phba->sli4_hba.max_cfg_param.xri_used--; - } -} - -/** - * lpfc_sli4_free_xri - Release an xri for reuse. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to release an xri to the pool of - * available rpis maintained by the driver. - **/ -void -lpfc_sli4_free_xri(struct lpfc_hba *phba, int xri) -{ - spin_lock_irq(&phba->hbalock); - __lpfc_sli4_free_xri(phba, xri); - spin_unlock_irq(&phba->hbalock); -} - -/** - * lpfc_sli4_next_xritag - Get an xritag for the io - * @phba: Pointer to HBA context object. - * - * This function gets an xritag for the iocb. If there is no unused xritag - * it will return 0xffff. - * The function returns the allocated xritag if successful, else returns zero. - * Zero is not a valid xritag. - * The caller is not required to hold any lock. - **/ -uint16_t -lpfc_sli4_next_xritag(struct lpfc_hba *phba) -{ - uint16_t xri_index; - - xri_index = lpfc_sli4_alloc_xri(phba); - if (xri_index != NO_XRI) - return xri_index; - - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2004 Failed to allocate XRI.last XRITAG is %d" - " Max XRI is %d, Used XRI is %d\n", - xri_index, - phba->sli4_hba.max_cfg_param.max_xri, - phba->sli4_hba.max_cfg_param.xri_used); - return NO_XRI; -} - -/** - * lpfc_sli4_post_els_sgl_list - post a block of ELS sgls to the port. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post a block of driver's sgl pages to the - * HBA using non-embedded mailbox command. No Lock is held. This routine - * is only called when the driver is loading and after all IO has been - * stopped. - **/ -int -lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba) -{ - struct lpfc_sglq *sglq_entry; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, pg_pairs; - uint32_t mbox_tmo; - uint16_t xritag_start = 0, lxri = 0; - int els_xri_cnt, rc = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* The number of sgls to be posted */ - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - - reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2559 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - - /* Allocate DMA memory and set up the non-embedded mailbox command */ - alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen, - LPFC_SLI4_MBX_NEMBED); - - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0285 Allocated DMA memory size (%d) is " - "less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - /* Set up the SGL pages in the non-embedded DMA pages */ - viraddr = mbox->sge_array->addr[0]; - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - for (pg_pairs = 0; pg_pairs < els_xri_cnt; pg_pairs++) { - sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[pg_pairs]; - - /* - * Assign the sglq a physical xri only if the driver has not - * initialized those resources. A port reset only needs - * the sglq's posted. - */ - if (bf_get(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags) != - LPFC_XRI_RSRC_RDY) { - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - sglq_entry->sli4_lxritag = lxri; - sglq_entry->sli4_xritag = phba->sli4_hba.xri_ids[lxri]; - } - - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(0)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(0)); - - /* Keep the first xritag on the list */ - if (pg_pairs == 0) - xritag_start = sglq_entry->sli4_xritag; - sgl_pg_pairs++; - } - - /* Complete initialization and perform endian conversion. */ - bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, els_xri_cnt); - sgl->word0 = cpu_to_le32(sgl->word0); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2513 POST_SGL_BLOCK mailbox command failed " - "status x%x add_status x%x mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - } - - if (rc == 0) - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_XRI_RSRC_RDY); - return rc; -} - -/** - * lpfc_sli4_post_els_sgl_list_ext - post a block of ELS sgls to the port. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post a block of driver's sgl pages to the - * HBA using non-embedded mailbox command. No Lock is held. This routine - * is only called when the driver is loading and after all IO has been - * stopped. - **/ -int -lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba) -{ - struct lpfc_sglq *sglq_entry; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, index; - uint32_t mbox_tmo; - uint16_t rsrc_start, rsrc_size, els_xri_cnt, post_els_xri_cnt; - uint16_t xritag_start = 0, lxri = 0; - struct lpfc_rsrc_blks *rsrc_blk; - int cnt, ttl_cnt, rc = 0; - int loop_cnt; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* The number of sgls to be posted */ - els_xri_cnt = lpfc_sli4_get_els_iocb_cnt(phba); - - reqlen = els_xri_cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2989 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - - cnt = 0; - ttl_cnt = 0; - post_els_xri_cnt = els_xri_cnt; - list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - rsrc_start = rsrc_blk->rsrc_start; - rsrc_size = rsrc_blk->rsrc_size; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3014 Working ELS Extent start %d, cnt %d\n", - rsrc_start, rsrc_size); - - loop_cnt = min(post_els_xri_cnt, rsrc_size); - if (loop_cnt < post_els_xri_cnt) { - post_els_xri_cnt -= loop_cnt; - ttl_cnt += loop_cnt; - } else - ttl_cnt += post_els_xri_cnt; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - /* - * Allocate DMA memory and set up the non-embedded mailbox - * command. - */ - alloclen = lpfc_sli4_config(phba, mbox, - LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - reqlen, LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2987 Allocated DMA memory size (%d) " - "is less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Set up the SGL pages in the non-embedded DMA pages */ - viraddr = mbox->sge_array->addr[0]; - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - /* - * The starting resource may not begin at zero. Control - * the loop variants via the block resource parameters, - * but handle the sge pointers with a zero-based index - * that doesn't get reset per loop pass. - */ - for (index = rsrc_start; - index < rsrc_start + loop_cnt; - index++) { - sglq_entry = phba->sli4_hba.lpfc_els_sgl_array[cnt]; - - /* - * Assign the sglq a physical xri only if the driver - * has not initialized those resources. A port reset - * only needs the sglq's posted. - */ - if (bf_get(lpfc_xri_rsrc_rdy, - &phba->sli4_hba.sli4_flags) != - LPFC_XRI_RSRC_RDY) { - lxri = lpfc_sli4_next_xritag(phba); - if (lxri == NO_XRI) { - lpfc_sli4_mbox_cmd_free(phba, mbox); - rc = -ENOMEM; - goto err_exit; - } - sglq_entry->sli4_lxritag = lxri; - sglq_entry->sli4_xritag = - phba->sli4_hba.xri_ids[lxri]; - } - - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(sglq_entry->phys)); - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(0)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(0)); - - /* Track the starting physical XRI for the mailbox. */ - if (index == rsrc_start) - xritag_start = sglq_entry->sli4_xritag; - sgl_pg_pairs++; - cnt++; - } - - /* Complete initialization and perform endian conversion. */ - rsrc_blk->rsrc_used += loop_cnt; - bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, loop_cnt); - sgl->word0 = cpu_to_le32(sgl->word0); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3015 Post ELS Extent SGL, start %d, " - "cnt %d, used %d\n", - xritag_start, loop_cnt, rsrc_blk->rsrc_used); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, - &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2988 POST_SGL_BLOCK mailbox " - "command failed status x%x " - "add_status x%x mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - goto err_exit; - } - if (ttl_cnt >= els_xri_cnt) - break; - } - - err_exit: - if (rc == 0) - bf_set(lpfc_xri_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_XRI_RSRC_RDY); - return rc; -} - -/** - * lpfc_sli4_post_scsi_sgl_block - post a block of scsi sgl list to firmware - * @phba: pointer to lpfc hba data structure. - * @sblist: pointer to scsi buffer list. - * @count: number of scsi buffers on the list. - * - * This routine is invoked to post a block of @count scsi sgl pages from a - * SCSI buffer list @sblist to the HBA using non-embedded mailbox command. - * No Lock is held. - * - **/ -int -lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *phba, struct list_head *sblist, - int cnt) -{ - struct lpfc_scsi_buf *psb; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, pg_pairs; - uint32_t mbox_tmo; - uint16_t xritag_start = 0; - int rc = 0; - uint32_t shdr_status, shdr_add_status; - dma_addr_t pdma_phys_bpl1; - union lpfc_sli4_cfg_shdr *shdr; - - /* Calculate the requested length of the dma memory */ - reqlen = cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "0217 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "0283 Failed to allocate mbox cmd memory\n"); - return -ENOMEM; - } - - /* Allocate DMA memory and set up the non-embedded mailbox command */ - alloclen = lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, reqlen, - LPFC_SLI4_MBX_NEMBED); - - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2561 Allocated DMA memory size (%d) is " - "less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Get the first SGE entry from the non-embedded DMA memory */ - viraddr = mbox->sge_array->addr[0]; - - /* Set up the SGL pages in the non-embedded DMA pages */ - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - pg_pairs = 0; - list_for_each_entry(psb, sblist, list) { - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(psb->dma_phys_bpl)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl)); - if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) - pdma_phys_bpl1 = psb->dma_phys_bpl + SGL_PAGE_SIZE; - else - pdma_phys_bpl1 = 0; - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(pdma_phys_bpl1)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(pdma_phys_bpl1)); - /* Keep the first xritag on the list */ - if (pg_pairs == 0) - xritag_start = psb->cur_iocbq.sli4_xritag; - sgl_pg_pairs++; - pg_pairs++; - } - bf_set(lpfc_post_sgl_pages_xri, sgl, xritag_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs); - /* Perform endian conversion if necessary */ - sgl->word0 = cpu_to_le32(sgl->word0); - - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2564 POST_SGL_BLOCK mailbox command failed " - "status x%x add_status x%x mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - } - return rc; -} - -/** - * lpfc_sli4_post_scsi_sgl_blk_ext - post a block of scsi sgls to the port. - * @phba: pointer to lpfc hba data structure. - * @sblist: pointer to scsi buffer list. - * @count: number of scsi buffers on the list. - * - * This routine is invoked to post a block of @count scsi sgl pages from a - * SCSI buffer list @sblist to the HBA using non-embedded mailbox command. - * No Lock is held. - * - **/ -int -lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *phba, struct list_head *sblist, - int cnt) -{ - struct lpfc_scsi_buf *psb = NULL; - struct lpfc_mbx_post_uembed_sgl_page1 *sgl; - struct sgl_page_pairs *sgl_pg_pairs; - void *viraddr; - LPFC_MBOXQ_t *mbox; - uint32_t reqlen, alloclen, pg_pairs; - uint32_t mbox_tmo; - uint16_t xri_start = 0, scsi_xri_start; - uint16_t rsrc_range; - int rc = 0, avail_cnt; - uint32_t shdr_status, shdr_add_status; - dma_addr_t pdma_phys_bpl1; - union lpfc_sli4_cfg_shdr *shdr; - struct lpfc_rsrc_blks *rsrc_blk; - uint32_t xri_cnt = 0; - - /* Calculate the total requested length of the dma memory */ - reqlen = cnt * sizeof(struct sgl_page_pairs) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - if (reqlen > SLI4_PAGE_SIZE) { - lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, - "2932 Block sgl registration required DMA " - "size (%d) great than a page\n", reqlen); - return -ENOMEM; - } - - /* - * The use of extents requires the driver to post the sgl headers - * in multiple postings to meet the contiguous resource assignment. - */ - psb = list_prepare_entry(psb, sblist, list); - scsi_xri_start = phba->sli4_hba.scsi_xri_start; - list_for_each_entry(rsrc_blk, &phba->sli4_hba.lpfc_xri_blk_list, - list) { - rsrc_range = rsrc_blk->rsrc_start + rsrc_blk->rsrc_size; - if (rsrc_range < scsi_xri_start) - continue; - else if (rsrc_blk->rsrc_used >= rsrc_blk->rsrc_size) - continue; - else - avail_cnt = rsrc_blk->rsrc_size - rsrc_blk->rsrc_used; - - reqlen = (avail_cnt * sizeof(struct sgl_page_pairs)) + - sizeof(union lpfc_sli4_cfg_shdr) + sizeof(uint32_t); - /* - * Allocate DMA memory and set up the non-embedded mailbox - * command. The mbox is used to post an SGL page per loop - * but the DMA memory has a use-once semantic so the mailbox - * is used and freed per loop pass. - */ - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2933 Failed to allocate mbox cmd " - "memory\n"); - return -ENOMEM; - } - alloclen = lpfc_sli4_config(phba, mbox, - LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_SGL_PAGES, - reqlen, - LPFC_SLI4_MBX_NEMBED); - if (alloclen < reqlen) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2934 Allocated DMA memory size (%d) " - "is less than the requested DMA memory " - "size (%d)\n", alloclen, reqlen); - lpfc_sli4_mbox_cmd_free(phba, mbox); - return -ENOMEM; - } - - /* Get the first SGE entry from the non-embedded DMA memory */ - viraddr = mbox->sge_array->addr[0]; - - /* Set up the SGL pages in the non-embedded DMA pages */ - sgl = (struct lpfc_mbx_post_uembed_sgl_page1 *)viraddr; - sgl_pg_pairs = &sgl->sgl_pg_pairs; - - /* pg_pairs tracks posted SGEs per loop iteration. */ - pg_pairs = 0; - list_for_each_entry_continue(psb, sblist, list) { - /* Set up the sge entry */ - sgl_pg_pairs->sgl_pg0_addr_lo = - cpu_to_le32(putPaddrLow(psb->dma_phys_bpl)); - sgl_pg_pairs->sgl_pg0_addr_hi = - cpu_to_le32(putPaddrHigh(psb->dma_phys_bpl)); - if (phba->cfg_sg_dma_buf_size > SGL_PAGE_SIZE) - pdma_phys_bpl1 = psb->dma_phys_bpl + - SGL_PAGE_SIZE; - else - pdma_phys_bpl1 = 0; - sgl_pg_pairs->sgl_pg1_addr_lo = - cpu_to_le32(putPaddrLow(pdma_phys_bpl1)); - sgl_pg_pairs->sgl_pg1_addr_hi = - cpu_to_le32(putPaddrHigh(pdma_phys_bpl1)); - /* Keep the first xri for this extent. */ - if (pg_pairs == 0) - xri_start = psb->cur_iocbq.sli4_xritag; - sgl_pg_pairs++; - pg_pairs++; - xri_cnt++; - - /* - * Track two exit conditions - the loop has constructed - * all of the caller's SGE pairs or all available - * resource IDs in this extent are consumed. - */ - if ((xri_cnt == cnt) || (pg_pairs >= avail_cnt)) - break; - } - rsrc_blk->rsrc_used += pg_pairs; - bf_set(lpfc_post_sgl_pages_xri, sgl, xri_start); - bf_set(lpfc_post_sgl_pages_xricnt, sgl, pg_pairs); - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3016 Post SCSI Extent SGL, start %d, cnt %d " - "blk use %d\n", - xri_start, pg_pairs, rsrc_blk->rsrc_used); - /* Perform endian conversion if necessary */ - sgl->word0 = cpu_to_le32(sgl->word0); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - shdr = (union lpfc_sli4_cfg_shdr *) &sgl->cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &shdr->response); - if (rc != MBX_TIMEOUT) - lpfc_sli4_mbox_cmd_free(phba, mbox); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2935 POST_SGL_BLOCK mailbox command " - "failed status x%x add_status x%x " - "mbx status x%x\n", - shdr_status, shdr_add_status, rc); - return -ENXIO; - } - - /* Post only what is requested. */ - if (xri_cnt >= cnt) - break; - } - return rc; -} - -/** - * lpfc_fc_frame_check - Check that this frame is a valid frame to handle - * @phba: pointer to lpfc_hba struct that the frame was received on - * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) - * - * This function checks the fields in the @fc_hdr to see if the FC frame is a - * valid type of frame that the LPFC driver will handle. This function will - * return a zero if the frame is a valid frame or a non zero value when the - * frame does not pass the check. - **/ -static int -lpfc_fc_frame_check(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr) -{ - /* make rctl_names static to save stack space */ - static char *rctl_names[] = FC_RCTL_NAMES_INIT; - char *type_names[] = FC_TYPE_NAMES_INIT; - struct fc_vft_header *fc_vft_hdr; - uint32_t *header = (uint32_t *) fc_hdr; - - switch (fc_hdr->fh_r_ctl) { - case FC_RCTL_DD_UNCAT: /* uncategorized information */ - case FC_RCTL_DD_SOL_DATA: /* solicited data */ - case FC_RCTL_DD_UNSOL_CTL: /* unsolicited control */ - case FC_RCTL_DD_SOL_CTL: /* solicited control or reply */ - case FC_RCTL_DD_UNSOL_DATA: /* unsolicited data */ - case FC_RCTL_DD_DATA_DESC: /* data descriptor */ - case FC_RCTL_DD_UNSOL_CMD: /* unsolicited command */ - case FC_RCTL_DD_CMD_STATUS: /* command status */ - case FC_RCTL_ELS_REQ: /* extended link services request */ - case FC_RCTL_ELS_REP: /* extended link services reply */ - case FC_RCTL_ELS4_REQ: /* FC-4 ELS request */ - case FC_RCTL_ELS4_REP: /* FC-4 ELS reply */ - case FC_RCTL_BA_NOP: /* basic link service NOP */ - case FC_RCTL_BA_ABTS: /* basic link service abort */ - case FC_RCTL_BA_RMC: /* remove connection */ - case FC_RCTL_BA_ACC: /* basic accept */ - case FC_RCTL_BA_RJT: /* basic reject */ - case FC_RCTL_BA_PRMT: - case FC_RCTL_ACK_1: /* acknowledge_1 */ - case FC_RCTL_ACK_0: /* acknowledge_0 */ - case FC_RCTL_P_RJT: /* port reject */ - case FC_RCTL_F_RJT: /* fabric reject */ - case FC_RCTL_P_BSY: /* port busy */ - case FC_RCTL_F_BSY: /* fabric busy to data frame */ - case FC_RCTL_F_BSYL: /* fabric busy to link control frame */ - case FC_RCTL_LCR: /* link credit reset */ - case FC_RCTL_END: /* end */ - break; - case FC_RCTL_VFTH: /* Virtual Fabric tagging Header */ - fc_vft_hdr = (struct fc_vft_header *)fc_hdr; - fc_hdr = &((struct fc_frame_header *)fc_vft_hdr)[1]; - return lpfc_fc_frame_check(phba, fc_hdr); - default: - goto drop; - } - switch (fc_hdr->fh_type) { - case FC_TYPE_BLS: - case FC_TYPE_ELS: - case FC_TYPE_FCP: - case FC_TYPE_CT: - break; - case FC_TYPE_IP: - case FC_TYPE_ILS: - default: - goto drop; - } - - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "2538 Received frame rctl:%s type:%s " - "Frame Data:%08x %08x %08x %08x %08x %08x\n", - rctl_names[fc_hdr->fh_r_ctl], - type_names[fc_hdr->fh_type], - be32_to_cpu(header[0]), be32_to_cpu(header[1]), - be32_to_cpu(header[2]), be32_to_cpu(header[3]), - be32_to_cpu(header[4]), be32_to_cpu(header[5])); - return 0; -drop: - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, - "2539 Dropped frame rctl:%s type:%s\n", - rctl_names[fc_hdr->fh_r_ctl], - type_names[fc_hdr->fh_type]); - return 1; -} - -/** - * lpfc_fc_hdr_get_vfi - Get the VFI from an FC frame - * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) - * - * This function processes the FC header to retrieve the VFI from the VF - * header, if one exists. This function will return the VFI if one exists - * or 0 if no VSAN Header exists. - **/ -static uint32_t -lpfc_fc_hdr_get_vfi(struct fc_frame_header *fc_hdr) -{ - struct fc_vft_header *fc_vft_hdr = (struct fc_vft_header *)fc_hdr; - - if (fc_hdr->fh_r_ctl != FC_RCTL_VFTH) - return 0; - return bf_get(fc_vft_hdr_vf_id, fc_vft_hdr); -} - -/** - * lpfc_fc_frame_to_vport - Finds the vport that a frame is destined to - * @phba: Pointer to the HBA structure to search for the vport on - * @fc_hdr: A pointer to the FC Header data (In Big Endian Format) - * @fcfi: The FC Fabric ID that the frame came from - * - * This function searches the @phba for a vport that matches the content of the - * @fc_hdr passed in and the @fcfi. This function uses the @fc_hdr to fetch the - * VFI, if the Virtual Fabric Tagging Header exists, and the DID. This function - * returns the matching vport pointer or NULL if unable to match frame to a - * vport. - **/ -static struct lpfc_vport * -lpfc_fc_frame_to_vport(struct lpfc_hba *phba, struct fc_frame_header *fc_hdr, - uint16_t fcfi) -{ - struct lpfc_vport **vports; - struct lpfc_vport *vport = NULL; - int i; - uint32_t did = (fc_hdr->fh_d_id[0] << 16 | - fc_hdr->fh_d_id[1] << 8 | - fc_hdr->fh_d_id[2]); - if (did == Fabric_DID) - return phba->pport; - vports = lpfc_create_vport_work_array(phba); - if (vports != NULL) - for (i = 0; i <= phba->max_vpi && vports[i] != NULL; i++) { - if (phba->fcf.fcfi == fcfi && - vports[i]->vfi == lpfc_fc_hdr_get_vfi(fc_hdr) && - vports[i]->fc_myDID == did) { - vport = vports[i]; - break; - } - } - lpfc_destroy_vport_work_array(phba, vports); - return vport; -} - -/** - * lpfc_update_rcv_time_stamp - Update vport's rcv seq time stamp - * @vport: The vport to work on. - * - * This function updates the receive sequence time stamp for this vport. The - * receive sequence time stamp indicates the time that the last frame of the - * the sequence that has been idle for the longest amount of time was received. - * the driver uses this time stamp to indicate if any received sequences have - * timed out. - **/ -void -lpfc_update_rcv_time_stamp(struct lpfc_vport *vport) -{ - struct lpfc_dmabuf *h_buf; - struct hbq_dmabuf *dmabuf = NULL; - - /* get the oldest sequence on the rcv list */ - h_buf = list_get_first(&vport->rcv_buffer_list, - struct lpfc_dmabuf, list); - if (!h_buf) - return; - dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); - vport->rcv_buffer_time_stamp = dmabuf->time_stamp; -} - -/** - * lpfc_cleanup_rcv_buffers - Cleans up all outstanding receive sequences. - * @vport: The vport that the received sequences were sent to. - * - * This function cleans up all outstanding received sequences. This is called - * by the driver when a link event or user action invalidates all the received - * sequences. - **/ -void -lpfc_cleanup_rcv_buffers(struct lpfc_vport *vport) -{ - struct lpfc_dmabuf *h_buf, *hnext; - struct lpfc_dmabuf *d_buf, *dnext; - struct hbq_dmabuf *dmabuf = NULL; - - /* start with the oldest sequence on the rcv list */ - list_for_each_entry_safe(h_buf, hnext, &vport->rcv_buffer_list, list) { - dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); - list_del_init(&dmabuf->hbuf.list); - list_for_each_entry_safe(d_buf, dnext, - &dmabuf->dbuf.list, list) { - list_del_init(&d_buf->list); - lpfc_in_buf_free(vport->phba, d_buf); - } - lpfc_in_buf_free(vport->phba, &dmabuf->dbuf); - } -} - -/** - * lpfc_rcv_seq_check_edtov - Cleans up timed out receive sequences. - * @vport: The vport that the received sequences were sent to. - * - * This function determines whether any received sequences have timed out by - * first checking the vport's rcv_buffer_time_stamp. If this time_stamp - * indicates that there is at least one timed out sequence this routine will - * go through the received sequences one at a time from most inactive to most - * active to determine which ones need to be cleaned up. Once it has determined - * that a sequence needs to be cleaned up it will simply free up the resources - * without sending an abort. - **/ -void -lpfc_rcv_seq_check_edtov(struct lpfc_vport *vport) -{ - struct lpfc_dmabuf *h_buf, *hnext; - struct lpfc_dmabuf *d_buf, *dnext; - struct hbq_dmabuf *dmabuf = NULL; - unsigned long timeout; - int abort_count = 0; - - timeout = (msecs_to_jiffies(vport->phba->fc_edtov) + - vport->rcv_buffer_time_stamp); - if (list_empty(&vport->rcv_buffer_list) || - time_before(jiffies, timeout)) - return; - /* start with the oldest sequence on the rcv list */ - list_for_each_entry_safe(h_buf, hnext, &vport->rcv_buffer_list, list) { - dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); - timeout = (msecs_to_jiffies(vport->phba->fc_edtov) + - dmabuf->time_stamp); - if (time_before(jiffies, timeout)) - break; - abort_count++; - list_del_init(&dmabuf->hbuf.list); - list_for_each_entry_safe(d_buf, dnext, - &dmabuf->dbuf.list, list) { - list_del_init(&d_buf->list); - lpfc_in_buf_free(vport->phba, d_buf); - } - lpfc_in_buf_free(vport->phba, &dmabuf->dbuf); - } - if (abort_count) - lpfc_update_rcv_time_stamp(vport); -} - -/** - * lpfc_fc_frame_add - Adds a frame to the vport's list of received sequences - * @dmabuf: pointer to a dmabuf that describes the hdr and data of the FC frame - * - * This function searches through the existing incomplete sequences that have - * been sent to this @vport. If the frame matches one of the incomplete - * sequences then the dbuf in the @dmabuf is added to the list of frames that - * make up that sequence. If no sequence is found that matches this frame then - * the function will add the hbuf in the @dmabuf to the @vport's rcv_buffer_list - * This function returns a pointer to the first dmabuf in the sequence list that - * the frame was linked to. - **/ -static struct hbq_dmabuf * -lpfc_fc_frame_add(struct lpfc_vport *vport, struct hbq_dmabuf *dmabuf) -{ - struct fc_frame_header *new_hdr; - struct fc_frame_header *temp_hdr; - struct lpfc_dmabuf *d_buf; - struct lpfc_dmabuf *h_buf; - struct hbq_dmabuf *seq_dmabuf = NULL; - struct hbq_dmabuf *temp_dmabuf = NULL; - - INIT_LIST_HEAD(&dmabuf->dbuf.list); - dmabuf->time_stamp = jiffies; - new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; - /* Use the hdr_buf to find the sequence that this frame belongs to */ - list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) { - temp_hdr = (struct fc_frame_header *)h_buf->virt; - if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) || - (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) || - (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3))) - continue; - /* found a pending sequence that matches this frame */ - seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); - break; - } - if (!seq_dmabuf) { - /* - * This indicates first frame received for this sequence. - * Queue the buffer on the vport's rcv_buffer_list. - */ - list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list); - lpfc_update_rcv_time_stamp(vport); - return dmabuf; - } - temp_hdr = seq_dmabuf->hbuf.virt; - if (be16_to_cpu(new_hdr->fh_seq_cnt) < - be16_to_cpu(temp_hdr->fh_seq_cnt)) { - list_del_init(&seq_dmabuf->hbuf.list); - list_add_tail(&dmabuf->hbuf.list, &vport->rcv_buffer_list); - list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list); - lpfc_update_rcv_time_stamp(vport); - return dmabuf; - } - /* move this sequence to the tail to indicate a young sequence */ - list_move_tail(&seq_dmabuf->hbuf.list, &vport->rcv_buffer_list); - seq_dmabuf->time_stamp = jiffies; - lpfc_update_rcv_time_stamp(vport); - if (list_empty(&seq_dmabuf->dbuf.list)) { - temp_hdr = dmabuf->hbuf.virt; - list_add_tail(&dmabuf->dbuf.list, &seq_dmabuf->dbuf.list); - return seq_dmabuf; - } - /* find the correct place in the sequence to insert this frame */ - list_for_each_entry_reverse(d_buf, &seq_dmabuf->dbuf.list, list) { - temp_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); - temp_hdr = (struct fc_frame_header *)temp_dmabuf->hbuf.virt; - /* - * If the frame's sequence count is greater than the frame on - * the list then insert the frame right after this frame - */ - if (be16_to_cpu(new_hdr->fh_seq_cnt) > - be16_to_cpu(temp_hdr->fh_seq_cnt)) { - list_add(&dmabuf->dbuf.list, &temp_dmabuf->dbuf.list); - return seq_dmabuf; - } - } - return NULL; -} - -/** - * lpfc_sli4_abort_partial_seq - Abort partially assembled unsol sequence - * @vport: pointer to a vitural port - * @dmabuf: pointer to a dmabuf that describes the FC sequence - * - * This function tries to abort from the partially assembed sequence, described - * by the information from basic abbort @dmabuf. It checks to see whether such - * partially assembled sequence held by the driver. If so, it shall free up all - * the frames from the partially assembled sequence. - * - * Return - * true -- if there is matching partially assembled sequence present and all - * the frames freed with the sequence; - * false -- if there is no matching partially assembled sequence present so - * nothing got aborted in the lower layer driver - **/ -static bool -lpfc_sli4_abort_partial_seq(struct lpfc_vport *vport, - struct hbq_dmabuf *dmabuf) -{ - struct fc_frame_header *new_hdr; - struct fc_frame_header *temp_hdr; - struct lpfc_dmabuf *d_buf, *n_buf, *h_buf; - struct hbq_dmabuf *seq_dmabuf = NULL; - - /* Use the hdr_buf to find the sequence that matches this frame */ - INIT_LIST_HEAD(&dmabuf->dbuf.list); - INIT_LIST_HEAD(&dmabuf->hbuf.list); - new_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; - list_for_each_entry(h_buf, &vport->rcv_buffer_list, list) { - temp_hdr = (struct fc_frame_header *)h_buf->virt; - if ((temp_hdr->fh_seq_id != new_hdr->fh_seq_id) || - (temp_hdr->fh_ox_id != new_hdr->fh_ox_id) || - (memcmp(&temp_hdr->fh_s_id, &new_hdr->fh_s_id, 3))) - continue; - /* found a pending sequence that matches this frame */ - seq_dmabuf = container_of(h_buf, struct hbq_dmabuf, hbuf); - break; - } - - /* Free up all the frames from the partially assembled sequence */ - if (seq_dmabuf) { - list_for_each_entry_safe(d_buf, n_buf, - &seq_dmabuf->dbuf.list, list) { - list_del_init(&d_buf->list); - lpfc_in_buf_free(vport->phba, d_buf); - } - return true; - } - return false; -} - -/** - * lpfc_sli4_seq_abort_rsp_cmpl - BLS ABORT RSP seq abort iocb complete handler - * @phba: Pointer to HBA context object. - * @cmd_iocbq: pointer to the command iocbq structure. - * @rsp_iocbq: pointer to the response iocbq structure. - * - * This function handles the sequence abort response iocb command complete - * event. It properly releases the memory allocated to the sequence abort - * accept iocb. - **/ -static void -lpfc_sli4_seq_abort_rsp_cmpl(struct lpfc_hba *phba, - struct lpfc_iocbq *cmd_iocbq, - struct lpfc_iocbq *rsp_iocbq) -{ - if (cmd_iocbq) - lpfc_sli_release_iocbq(phba, cmd_iocbq); - - /* Failure means BLS ABORT RSP did not get delivered to remote node*/ - if (rsp_iocbq && rsp_iocbq->iocb.ulpStatus) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "3154 BLS ABORT RSP failed, data: x%x/x%x\n", - rsp_iocbq->iocb.ulpStatus, - rsp_iocbq->iocb.un.ulpWord[4]); -} - -/** - * lpfc_sli4_xri_inrange - check xri is in range of xris owned by driver. - * @phba: Pointer to HBA context object. - * @xri: xri id in transaction. - * - * This function validates the xri maps to the known range of XRIs allocated an - * used by the driver. - **/ -uint16_t -lpfc_sli4_xri_inrange(struct lpfc_hba *phba, - uint16_t xri) -{ - int i; - - for (i = 0; i < phba->sli4_hba.max_cfg_param.max_xri; i++) { - if (xri == phba->sli4_hba.xri_ids[i]) - return i; - } - return NO_XRI; -} - - -/** - * lpfc_sli4_seq_abort_rsp - bls rsp to sequence abort - * @phba: Pointer to HBA context object. - * @fc_hdr: pointer to a FC frame header. - * - * This function sends a basic response to a previous unsol sequence abort - * event after aborting the sequence handling. - **/ -static void -lpfc_sli4_seq_abort_rsp(struct lpfc_hba *phba, - struct fc_frame_header *fc_hdr) -{ - struct lpfc_iocbq *ctiocb = NULL; - struct lpfc_nodelist *ndlp; - uint16_t oxid, rxid; - uint32_t sid, fctl; - IOCB_t *icmd; - int rc; - - if (!lpfc_is_link_up(phba)) - return; - - sid = sli4_sid_from_fc_hdr(fc_hdr); - oxid = be16_to_cpu(fc_hdr->fh_ox_id); - rxid = be16_to_cpu(fc_hdr->fh_rx_id); - - ndlp = lpfc_findnode_did(phba->pport, sid); - if (!ndlp) { - lpfc_printf_log(phba, KERN_WARNING, LOG_ELS, - "1268 Find ndlp returned NULL for oxid:x%x " - "SID:x%x\n", oxid, sid); - return; - } - if (lpfc_sli4_xri_inrange(phba, rxid)) - lpfc_set_rrq_active(phba, ndlp, rxid, oxid, 0); - - /* Allocate buffer for rsp iocb */ - ctiocb = lpfc_sli_get_iocbq(phba); - if (!ctiocb) - return; - - /* Extract the F_CTL field from FC_HDR */ - fctl = sli4_fctl_from_fc_hdr(fc_hdr); - - icmd = &ctiocb->iocb; - icmd->un.xseq64.bdl.bdeSize = 0; - icmd->un.xseq64.bdl.ulpIoTag32 = 0; - icmd->un.xseq64.w5.hcsw.Dfctl = 0; - icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_ACC; - icmd->un.xseq64.w5.hcsw.Type = FC_TYPE_BLS; - - /* Fill in the rest of iocb fields */ - icmd->ulpCommand = CMD_XMIT_BLS_RSP64_CX; - icmd->ulpBdeCount = 0; - icmd->ulpLe = 1; - icmd->ulpClass = CLASS3; - icmd->ulpContext = phba->sli4_hba.rpi_ids[ndlp->nlp_rpi]; - ctiocb->context1 = ndlp; - - ctiocb->iocb_cmpl = NULL; - ctiocb->vport = phba->pport; - ctiocb->iocb_cmpl = lpfc_sli4_seq_abort_rsp_cmpl; - ctiocb->sli4_lxritag = NO_XRI; - ctiocb->sli4_xritag = NO_XRI; - - /* If the oxid maps to the FCP XRI range or if it is out of range, - * send a BLS_RJT. The driver no longer has that exchange. - * Override the IOCB for a BA_RJT. - */ - if (oxid > (phba->sli4_hba.max_cfg_param.max_xri + - phba->sli4_hba.max_cfg_param.xri_base) || - oxid > (lpfc_sli4_get_els_iocb_cnt(phba) + - phba->sli4_hba.max_cfg_param.xri_base)) { - icmd->un.xseq64.w5.hcsw.Rctl = FC_RCTL_BA_RJT; - bf_set(lpfc_vndr_code, &icmd->un.bls_rsp, 0); - bf_set(lpfc_rsn_expln, &icmd->un.bls_rsp, FC_BA_RJT_INV_XID); - bf_set(lpfc_rsn_code, &icmd->un.bls_rsp, FC_BA_RJT_UNABLE); - } - - if (fctl & FC_FC_EX_CTX) { - /* ABTS sent by responder to CT exchange, construction - * of BA_ACC will use OX_ID from ABTS for the XRI_TAG - * field and RX_ID from ABTS for RX_ID field. - */ - bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_RSP); - } else { - /* ABTS sent by initiator to CT exchange, construction - * of BA_ACC will need to allocate a new XRI as for the - * XRI_TAG field. - */ - bf_set(lpfc_abts_orig, &icmd->un.bls_rsp, LPFC_ABTS_UNSOL_INT); - } - bf_set(lpfc_abts_rxid, &icmd->un.bls_rsp, rxid); - bf_set(lpfc_abts_oxid, &icmd->un.bls_rsp, oxid); - - /* Xmit CT abts response on exchange */ - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, - "1200 Send BLS cmd x%x on oxid x%x Data: x%x\n", - icmd->un.xseq64.w5.hcsw.Rctl, oxid, phba->link_state); - - rc = lpfc_sli_issue_iocb(phba, LPFC_ELS_RING, ctiocb, 0); - if (rc == IOCB_ERROR) { - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "2925 Failed to issue CT ABTS RSP x%x on " - "xri x%x, Data x%x\n", - icmd->un.xseq64.w5.hcsw.Rctl, oxid, - phba->link_state); - lpfc_sli_release_iocbq(phba, ctiocb); - } -} - -/** - * lpfc_sli4_handle_unsol_abort - Handle sli-4 unsolicited abort event - * @vport: Pointer to the vport on which this sequence was received - * @dmabuf: pointer to a dmabuf that describes the FC sequence - * - * This function handles an SLI-4 unsolicited abort event. If the unsolicited - * receive sequence is only partially assembed by the driver, it shall abort - * the partially assembled frames for the sequence. Otherwise, if the - * unsolicited receive sequence has been completely assembled and passed to - * the Upper Layer Protocol (UPL), it then mark the per oxid status for the - * unsolicited sequence has been aborted. After that, it will issue a basic - * accept to accept the abort. - **/ -void -lpfc_sli4_handle_unsol_abort(struct lpfc_vport *vport, - struct hbq_dmabuf *dmabuf) -{ - struct lpfc_hba *phba = vport->phba; - struct fc_frame_header fc_hdr; - uint32_t fctl; - bool abts_par; - - /* Make a copy of fc_hdr before the dmabuf being released */ - memcpy(&fc_hdr, dmabuf->hbuf.virt, sizeof(struct fc_frame_header)); - fctl = sli4_fctl_from_fc_hdr(&fc_hdr); - - if (fctl & FC_FC_EX_CTX) { - /* - * ABTS sent by responder to exchange, just free the buffer - */ - lpfc_in_buf_free(phba, &dmabuf->dbuf); - } else { - /* - * ABTS sent by initiator to exchange, need to do cleanup - */ - /* Try to abort partially assembled seq */ - abts_par = lpfc_sli4_abort_partial_seq(vport, dmabuf); - - /* Send abort to ULP if partially seq abort failed */ - if (abts_par == false) - lpfc_sli4_send_seq_to_ulp(vport, dmabuf); - else - lpfc_in_buf_free(phba, &dmabuf->dbuf); - } - /* Send basic accept (BA_ACC) to the abort requester */ - lpfc_sli4_seq_abort_rsp(phba, &fc_hdr); -} - -/** - * lpfc_seq_complete - Indicates if a sequence is complete - * @dmabuf: pointer to a dmabuf that describes the FC sequence - * - * This function checks the sequence, starting with the frame described by - * @dmabuf, to see if all the frames associated with this sequence are present. - * the frames associated with this sequence are linked to the @dmabuf using the - * dbuf list. This function looks for two major things. 1) That the first frame - * has a sequence count of zero. 2) There is a frame with last frame of sequence - * set. 3) That there are no holes in the sequence count. The function will - * return 1 when the sequence is complete, otherwise it will return 0. - **/ -static int -lpfc_seq_complete(struct hbq_dmabuf *dmabuf) -{ - struct fc_frame_header *hdr; - struct lpfc_dmabuf *d_buf; - struct hbq_dmabuf *seq_dmabuf; - uint32_t fctl; - int seq_count = 0; - - hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; - /* make sure first fame of sequence has a sequence count of zero */ - if (hdr->fh_seq_cnt != seq_count) - return 0; - fctl = (hdr->fh_f_ctl[0] << 16 | - hdr->fh_f_ctl[1] << 8 | - hdr->fh_f_ctl[2]); - /* If last frame of sequence we can return success. */ - if (fctl & FC_FC_END_SEQ) - return 1; - list_for_each_entry(d_buf, &dmabuf->dbuf.list, list) { - seq_dmabuf = container_of(d_buf, struct hbq_dmabuf, dbuf); - hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; - /* If there is a hole in the sequence count then fail. */ - if (++seq_count != be16_to_cpu(hdr->fh_seq_cnt)) - return 0; - fctl = (hdr->fh_f_ctl[0] << 16 | - hdr->fh_f_ctl[1] << 8 | - hdr->fh_f_ctl[2]); - /* If last frame of sequence we can return success. */ - if (fctl & FC_FC_END_SEQ) - return 1; - } - return 0; -} - -/** - * lpfc_prep_seq - Prep sequence for ULP processing - * @vport: Pointer to the vport on which this sequence was received - * @dmabuf: pointer to a dmabuf that describes the FC sequence - * - * This function takes a sequence, described by a list of frames, and creates - * a list of iocbq structures to describe the sequence. This iocbq list will be - * used to issue to the generic unsolicited sequence handler. This routine - * returns a pointer to the first iocbq in the list. If the function is unable - * to allocate an iocbq then it throw out the received frames that were not - * able to be described and return a pointer to the first iocbq. If unable to - * allocate any iocbqs (including the first) this function will return NULL. - **/ -static struct lpfc_iocbq * -lpfc_prep_seq(struct lpfc_vport *vport, struct hbq_dmabuf *seq_dmabuf) -{ - struct hbq_dmabuf *hbq_buf; - struct lpfc_dmabuf *d_buf, *n_buf; - struct lpfc_iocbq *first_iocbq, *iocbq; - struct fc_frame_header *fc_hdr; - uint32_t sid; - uint32_t len, tot_len; - struct ulp_bde64 *pbde; - - fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; - /* remove from receive buffer list */ - list_del_init(&seq_dmabuf->hbuf.list); - lpfc_update_rcv_time_stamp(vport); - /* get the Remote Port's SID */ - sid = sli4_sid_from_fc_hdr(fc_hdr); - tot_len = 0; - /* Get an iocbq struct to fill in. */ - first_iocbq = lpfc_sli_get_iocbq(vport->phba); - if (first_iocbq) { - /* Initialize the first IOCB. */ - first_iocbq->iocb.unsli3.rcvsli3.acc_len = 0; - first_iocbq->iocb.ulpStatus = IOSTAT_SUCCESS; - first_iocbq->iocb.ulpCommand = CMD_IOCB_RCV_SEQ64_CX; - first_iocbq->iocb.ulpContext = NO_XRI; - first_iocbq->iocb.unsli3.rcvsli3.ox_id = - be16_to_cpu(fc_hdr->fh_ox_id); - /* iocbq is prepped for internal consumption. Physical vpi. */ - first_iocbq->iocb.unsli3.rcvsli3.vpi = - vport->phba->vpi_ids[vport->vpi]; - /* put the first buffer into the first IOCBq */ - first_iocbq->context2 = &seq_dmabuf->dbuf; - first_iocbq->context3 = NULL; - first_iocbq->iocb.ulpBdeCount = 1; - first_iocbq->iocb.un.cont64[0].tus.f.bdeSize = - LPFC_DATA_BUF_SIZE; - first_iocbq->iocb.un.rcvels.remoteID = sid; - tot_len = bf_get(lpfc_rcqe_length, - &seq_dmabuf->cq_event.cqe.rcqe_cmpl); - first_iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len; - } - iocbq = first_iocbq; - /* - * Each IOCBq can have two Buffers assigned, so go through the list - * of buffers for this sequence and save two buffers in each IOCBq - */ - list_for_each_entry_safe(d_buf, n_buf, &seq_dmabuf->dbuf.list, list) { - if (!iocbq) { - lpfc_in_buf_free(vport->phba, d_buf); - continue; - } - if (!iocbq->context3) { - iocbq->context3 = d_buf; - iocbq->iocb.ulpBdeCount++; - pbde = (struct ulp_bde64 *) - &iocbq->iocb.unsli3.sli3Words[4]; - pbde->tus.f.bdeSize = LPFC_DATA_BUF_SIZE; - - /* We need to get the size out of the right CQE */ - hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); - len = bf_get(lpfc_rcqe_length, - &hbq_buf->cq_event.cqe.rcqe_cmpl); - iocbq->iocb.unsli3.rcvsli3.acc_len += len; - tot_len += len; - } else { - iocbq = lpfc_sli_get_iocbq(vport->phba); - if (!iocbq) { - if (first_iocbq) { - first_iocbq->iocb.ulpStatus = - IOSTAT_FCP_RSP_ERROR; - first_iocbq->iocb.un.ulpWord[4] = - IOERR_NO_RESOURCES; - } - lpfc_in_buf_free(vport->phba, d_buf); - continue; - } - iocbq->context2 = d_buf; - iocbq->context3 = NULL; - iocbq->iocb.ulpBdeCount = 1; - iocbq->iocb.un.cont64[0].tus.f.bdeSize = - LPFC_DATA_BUF_SIZE; - - /* We need to get the size out of the right CQE */ - hbq_buf = container_of(d_buf, struct hbq_dmabuf, dbuf); - len = bf_get(lpfc_rcqe_length, - &hbq_buf->cq_event.cqe.rcqe_cmpl); - tot_len += len; - iocbq->iocb.unsli3.rcvsli3.acc_len = tot_len; - - iocbq->iocb.un.rcvels.remoteID = sid; - list_add_tail(&iocbq->list, &first_iocbq->list); - } - } - return first_iocbq; -} - -static void -lpfc_sli4_send_seq_to_ulp(struct lpfc_vport *vport, - struct hbq_dmabuf *seq_dmabuf) -{ - struct fc_frame_header *fc_hdr; - struct lpfc_iocbq *iocbq, *curr_iocb, *next_iocb; - struct lpfc_hba *phba = vport->phba; - - fc_hdr = (struct fc_frame_header *)seq_dmabuf->hbuf.virt; - iocbq = lpfc_prep_seq(vport, seq_dmabuf); - if (!iocbq) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2707 Ring %d handler: Failed to allocate " - "iocb Rctl x%x Type x%x received\n", - LPFC_ELS_RING, - fc_hdr->fh_r_ctl, fc_hdr->fh_type); - return; - } - if (!lpfc_complete_unsol_iocb(phba, - &phba->sli.ring[LPFC_ELS_RING], - iocbq, fc_hdr->fh_r_ctl, - fc_hdr->fh_type)) - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2540 Ring %d handler: unexpected Rctl " - "x%x Type x%x received\n", - LPFC_ELS_RING, - fc_hdr->fh_r_ctl, fc_hdr->fh_type); - - /* Free iocb created in lpfc_prep_seq */ - list_for_each_entry_safe(curr_iocb, next_iocb, - &iocbq->list, list) { - list_del_init(&curr_iocb->list); - lpfc_sli_release_iocbq(phba, curr_iocb); - } - lpfc_sli_release_iocbq(phba, iocbq); -} - -/** - * lpfc_sli4_handle_received_buffer - Handle received buffers from firmware - * @phba: Pointer to HBA context object. - * - * This function is called with no lock held. This function processes all - * the received buffers and gives it to upper layers when a received buffer - * indicates that it is the final frame in the sequence. The interrupt - * service routine processes received buffers at interrupt contexts and adds - * received dma buffers to the rb_pend_list queue and signals the worker thread. - * Worker thread calls lpfc_sli4_handle_received_buffer, which will call the - * appropriate receive function when the final frame in a sequence is received. - **/ -void -lpfc_sli4_handle_received_buffer(struct lpfc_hba *phba, - struct hbq_dmabuf *dmabuf) -{ - struct hbq_dmabuf *seq_dmabuf; - struct fc_frame_header *fc_hdr; - struct lpfc_vport *vport; - uint32_t fcfi; - - /* Process each received buffer */ - fc_hdr = (struct fc_frame_header *)dmabuf->hbuf.virt; - /* check to see if this a valid type of frame */ - if (lpfc_fc_frame_check(phba, fc_hdr)) { - lpfc_in_buf_free(phba, &dmabuf->dbuf); - return; - } - if ((bf_get(lpfc_cqe_code, - &dmabuf->cq_event.cqe.rcqe_cmpl) == CQE_CODE_RECEIVE_V1)) - fcfi = bf_get(lpfc_rcqe_fcf_id_v1, - &dmabuf->cq_event.cqe.rcqe_cmpl); - else - fcfi = bf_get(lpfc_rcqe_fcf_id, - &dmabuf->cq_event.cqe.rcqe_cmpl); - vport = lpfc_fc_frame_to_vport(phba, fc_hdr, fcfi); - if (!vport || !(vport->vpi_state & LPFC_VPI_REGISTERED)) { - /* throw out the frame */ - lpfc_in_buf_free(phba, &dmabuf->dbuf); - return; - } - /* Handle the basic abort sequence (BA_ABTS) event */ - if (fc_hdr->fh_r_ctl == FC_RCTL_BA_ABTS) { - lpfc_sli4_handle_unsol_abort(vport, dmabuf); - return; - } - - /* Link this frame */ - seq_dmabuf = lpfc_fc_frame_add(vport, dmabuf); - if (!seq_dmabuf) { - /* unable to add frame to vport - throw it out */ - lpfc_in_buf_free(phba, &dmabuf->dbuf); - return; - } - /* If not last frame in sequence continue processing frames. */ - if (!lpfc_seq_complete(seq_dmabuf)) - return; - - /* Send the complete sequence to the upper layer protocol */ - lpfc_sli4_send_seq_to_ulp(vport, seq_dmabuf); -} - -/** - * lpfc_sli4_post_all_rpi_hdrs - Post the rpi header memory region to the port - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post rpi header templates to the - * HBA consistent with the SLI-4 interface spec. This routine - * posts a SLI4_PAGE_SIZE memory region to the port to hold up to - * SLI4_PAGE_SIZE modulo 64 rpi context headers. - * - * This routine does not require any locks. It's usage is expected - * to be driver load or reset recovery when the driver is - * sequential. - * - * Return codes - * 0 - successful - * -EIO - The mailbox failed to complete successfully. - * When this error occurs, the driver is not guaranteed - * to have any rpi regions posted to the device and - * must either attempt to repost the regions or take a - * fatal error. - **/ -int -lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *phba) -{ - struct lpfc_rpi_hdr *rpi_page; - uint32_t rc = 0; - uint16_t lrpi = 0; - - /* SLI4 ports that support extents do not require RPI headers. */ - if (!phba->sli4_hba.rpi_hdrs_in_use) - goto exit; - if (phba->sli4_hba.extents_in_use) - return -EIO; - - list_for_each_entry(rpi_page, &phba->sli4_hba.lpfc_rpi_hdr_list, list) { - /* - * Assign the rpi headers a physical rpi only if the driver - * has not initialized those resources. A port reset only - * needs the headers posted. - */ - if (bf_get(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags) != - LPFC_RPI_RSRC_RDY) - rpi_page->start_rpi = phba->sli4_hba.rpi_ids[lrpi]; - - rc = lpfc_sli4_post_rpi_hdr(phba, rpi_page); - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2008 Error %d posting all rpi " - "headers\n", rc); - rc = -EIO; - break; - } - } - - exit: - bf_set(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, - LPFC_RPI_RSRC_RDY); - return rc; -} - -/** - * lpfc_sli4_post_rpi_hdr - Post an rpi header memory region to the port - * @phba: pointer to lpfc hba data structure. - * @rpi_page: pointer to the rpi memory region. - * - * This routine is invoked to post a single rpi header to the - * HBA consistent with the SLI-4 interface spec. This memory region - * maps up to 64 rpi context regions. - * - * Return codes - * 0 - successful - * -ENOMEM - No available memory - * -EIO - The mailbox failed to complete successfully. - **/ -int -lpfc_sli4_post_rpi_hdr(struct lpfc_hba *phba, struct lpfc_rpi_hdr *rpi_page) -{ - LPFC_MBOXQ_t *mboxq; - struct lpfc_mbx_post_hdr_tmpl *hdr_tmpl; - uint32_t rc = 0; - uint32_t shdr_status, shdr_add_status; - union lpfc_sli4_cfg_shdr *shdr; - - /* SLI4 ports that support extents do not require RPI headers. */ - if (!phba->sli4_hba.rpi_hdrs_in_use) - return rc; - if (phba->sli4_hba.extents_in_use) - return -EIO; - - /* The port is notified of the header region via a mailbox command. */ - mboxq = (LPFC_MBOXQ_t *) mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2001 Unable to allocate memory for issuing " - "SLI_CONFIG_SPECIAL mailbox command\n"); - return -ENOMEM; - } - - /* Post all rpi memory regions to the port. */ - hdr_tmpl = &mboxq->u.mqe.un.hdr_tmpl; - lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_POST_HDR_TEMPLATE, - sizeof(struct lpfc_mbx_post_hdr_tmpl) - - sizeof(struct lpfc_sli4_cfg_mhdr), - LPFC_SLI4_MBX_EMBED); - - - /* Post the physical rpi to the port for this rpi header. */ - bf_set(lpfc_mbx_post_hdr_tmpl_rpi_offset, hdr_tmpl, - rpi_page->start_rpi); - bf_set(lpfc_mbx_post_hdr_tmpl_page_cnt, - hdr_tmpl, rpi_page->page_count); - - hdr_tmpl->rpi_paddr_lo = putPaddrLow(rpi_page->dmabuf->phys); - hdr_tmpl->rpi_paddr_hi = putPaddrHigh(rpi_page->dmabuf->phys); - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - shdr = (union lpfc_sli4_cfg_shdr *) &hdr_tmpl->header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, phba->mbox_mem_pool); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2514 POST_RPI_HDR mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - } - return rc; -} - -/** - * lpfc_sli4_alloc_rpi - Get an available rpi in the device's range - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to post rpi header templates to the - * HBA consistent with the SLI-4 interface spec. This routine - * posts a SLI4_PAGE_SIZE memory region to the port to hold up to - * SLI4_PAGE_SIZE modulo 64 rpi context headers. - * - * Returns - * A nonzero rpi defined as rpi_base <= rpi < max_rpi if successful - * LPFC_RPI_ALLOC_ERROR if no rpis are available. - **/ -int -lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) -{ - unsigned long rpi; - uint16_t max_rpi, rpi_limit; - uint16_t rpi_remaining, lrpi = 0; - struct lpfc_rpi_hdr *rpi_hdr; - - max_rpi = phba->sli4_hba.max_cfg_param.max_rpi; - rpi_limit = phba->sli4_hba.next_rpi; - - /* - * Fetch the next logical rpi. Because this index is logical, - * the driver starts at 0 each time. - */ - spin_lock_irq(&phba->hbalock); - rpi = find_next_zero_bit(phba->sli4_hba.rpi_bmask, rpi_limit, 0); - if (rpi >= rpi_limit) - rpi = LPFC_RPI_ALLOC_ERROR; - else { - set_bit(rpi, phba->sli4_hba.rpi_bmask); - phba->sli4_hba.max_cfg_param.rpi_used++; - phba->sli4_hba.rpi_count++; - } - - /* - * Don't try to allocate more rpi header regions if the device limit - * has been exhausted. - */ - if ((rpi == LPFC_RPI_ALLOC_ERROR) && - (phba->sli4_hba.rpi_count >= max_rpi)) { - spin_unlock_irq(&phba->hbalock); - return rpi; - } - - /* - * RPI header postings are not required for SLI4 ports capable of - * extents. - */ - if (!phba->sli4_hba.rpi_hdrs_in_use) { - spin_unlock_irq(&phba->hbalock); - return rpi; - } - - /* - * If the driver is running low on rpi resources, allocate another - * page now. Note that the next_rpi value is used because - * it represents how many are actually in use whereas max_rpi notes - * how many are supported max by the device. - */ - rpi_remaining = phba->sli4_hba.next_rpi - phba->sli4_hba.rpi_count; - spin_unlock_irq(&phba->hbalock); - if (rpi_remaining < LPFC_RPI_LOW_WATER_MARK) { - rpi_hdr = lpfc_sli4_create_rpi_hdr(phba); - if (!rpi_hdr) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2002 Error Could not grow rpi " - "count\n"); - } else { - lrpi = rpi_hdr->start_rpi; - rpi_hdr->start_rpi = phba->sli4_hba.rpi_ids[lrpi]; - lpfc_sli4_post_rpi_hdr(phba, rpi_hdr); - } - } - - return rpi; -} - -/** - * lpfc_sli4_free_rpi - Release an rpi for reuse. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to release an rpi to the pool of - * available rpis maintained by the driver. - **/ -void -__lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) -{ - if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) { - phba->sli4_hba.rpi_count--; - phba->sli4_hba.max_cfg_param.rpi_used--; - } -} - -/** - * lpfc_sli4_free_rpi - Release an rpi for reuse. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to release an rpi to the pool of - * available rpis maintained by the driver. - **/ -void -lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) -{ - spin_lock_irq(&phba->hbalock); - __lpfc_sli4_free_rpi(phba, rpi); - spin_unlock_irq(&phba->hbalock); -} - -/** - * lpfc_sli4_remove_rpis - Remove the rpi bitmask region - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to remove the memory region that - * provided rpi via a bitmask. - **/ -void -lpfc_sli4_remove_rpis(struct lpfc_hba *phba) -{ - kfree(phba->sli4_hba.rpi_bmask); - kfree(phba->sli4_hba.rpi_ids); - bf_set(lpfc_rpi_rsrc_rdy, &phba->sli4_hba.sli4_flags, 0); -} - -/** - * lpfc_sli4_resume_rpi - Remove the rpi bitmask region - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to remove the memory region that - * provided rpi via a bitmask. - **/ -int -lpfc_sli4_resume_rpi(struct lpfc_nodelist *ndlp, - void (*cmpl)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *arg) -{ - LPFC_MBOXQ_t *mboxq; - struct lpfc_hba *phba = ndlp->phba; - int rc; - - /* The port is notified of the header region via a mailbox command. */ - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) - return -ENOMEM; - - /* Post all rpi memory regions to the port. */ - lpfc_resume_rpi(mboxq, ndlp); - if (cmpl) { - mboxq->mbox_cmpl = cmpl; - mboxq->context1 = arg; - mboxq->context2 = ndlp; - } else - mboxq->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mboxq->vport = ndlp->vport; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2010 Resume RPI Mailbox failed " - "status %d, mbxStatus x%x\n", rc, - bf_get(lpfc_mqe_status, &mboxq->u.mqe)); - mempool_free(mboxq, phba->mbox_mem_pool); - return -EIO; - } - return 0; -} - -/** - * lpfc_sli4_init_vpi - Initialize a vpi with the port - * @vport: Pointer to the vport for which the vpi is being initialized - * - * This routine is invoked to activate a vpi with the port. - * - * Returns: - * 0 success - * -Evalue otherwise - **/ -int -lpfc_sli4_init_vpi(struct lpfc_vport *vport) -{ - LPFC_MBOXQ_t *mboxq; - int rc = 0; - int retval = MBX_SUCCESS; - uint32_t mbox_tmo; - struct lpfc_hba *phba = vport->phba; - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) - return -ENOMEM; - lpfc_init_vpi(phba, mboxq, vport->vpi); - mbox_tmo = lpfc_mbox_tmo_val(phba, mboxq); - rc = lpfc_sli_issue_mbox_wait(phba, mboxq, mbox_tmo); - if (rc != MBX_SUCCESS) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_SLI, - "2022 INIT VPI Mailbox failed " - "status %d, mbxStatus x%x\n", rc, - bf_get(lpfc_mqe_status, &mboxq->u.mqe)); - retval = -EIO; - } - if (rc != MBX_TIMEOUT) - mempool_free(mboxq, vport->phba->mbox_mem_pool); - - return retval; -} - -/** - * lpfc_mbx_cmpl_add_fcf_record - add fcf mbox completion handler. - * @phba: pointer to lpfc hba data structure. - * @mboxq: Pointer to mailbox object. - * - * This routine is invoked to manually add a single FCF record. The caller - * must pass a completely initialized FCF_Record. This routine takes - * care of the nonembedded mailbox operations. - **/ -static void -lpfc_mbx_cmpl_add_fcf_record(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) -{ - void *virt_addr; - union lpfc_sli4_cfg_shdr *shdr; - uint32_t shdr_status, shdr_add_status; - - virt_addr = mboxq->sge_array->addr[0]; - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) virt_addr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - - if ((shdr_status || shdr_add_status) && - (shdr_status != STATUS_FCF_IN_USE)) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2558 ADD_FCF_RECORD mailbox failed with " - "status x%x add_status x%x\n", - shdr_status, shdr_add_status); - - lpfc_sli4_mbox_cmd_free(phba, mboxq); -} - -/** - * lpfc_sli4_add_fcf_record - Manually add an FCF Record. - * @phba: pointer to lpfc hba data structure. - * @fcf_record: pointer to the initialized fcf record to add. - * - * This routine is invoked to manually add a single FCF record. The caller - * must pass a completely initialized FCF_Record. This routine takes - * care of the nonembedded mailbox operations. - **/ -int -lpfc_sli4_add_fcf_record(struct lpfc_hba *phba, struct fcf_record *fcf_record) -{ - int rc = 0; - LPFC_MBOXQ_t *mboxq; - uint8_t *bytep; - void *virt_addr; - dma_addr_t phys_addr; - struct lpfc_mbx_sge sge; - uint32_t alloc_len, req_len; - uint32_t fcfindex; - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2009 Failed to allocate mbox for ADD_FCF cmd\n"); - return -ENOMEM; - } - - req_len = sizeof(struct fcf_record) + sizeof(union lpfc_sli4_cfg_shdr) + - sizeof(uint32_t); - - /* Allocate DMA memory and set up the non-embedded mailbox command */ - alloc_len = lpfc_sli4_config(phba, mboxq, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_ADD_FCF, - req_len, LPFC_SLI4_MBX_NEMBED); - if (alloc_len < req_len) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2523 Allocated DMA memory size (x%x) is " - "less than the requested DMA memory " - "size (x%x)\n", alloc_len, req_len); - lpfc_sli4_mbox_cmd_free(phba, mboxq); - return -ENOMEM; - } - - /* - * Get the first SGE entry from the non-embedded DMA memory. This - * routine only uses a single SGE. - */ - lpfc_sli4_mbx_sge_get(mboxq, 0, &sge); - phys_addr = getPaddr(sge.pa_hi, sge.pa_lo); - virt_addr = mboxq->sge_array->addr[0]; - /* - * Configure the FCF record for FCFI 0. This is the driver's - * hardcoded default and gets used in nonFIP mode. - */ - fcfindex = bf_get(lpfc_fcf_record_fcf_index, fcf_record); - bytep = virt_addr + sizeof(union lpfc_sli4_cfg_shdr); - lpfc_sli_pcimem_bcopy(&fcfindex, bytep, sizeof(uint32_t)); - - /* - * Copy the fcf_index and the FCF Record Data. The data starts after - * the FCoE header plus word10. The data copy needs to be endian - * correct. - */ - bytep += sizeof(uint32_t); - lpfc_sli_pcimem_bcopy(fcf_record, bytep, sizeof(struct fcf_record)); - mboxq->vport = phba->pport; - mboxq->mbox_cmpl = lpfc_mbx_cmpl_add_fcf_record; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2515 ADD_FCF_RECORD mailbox failed with " - "status 0x%x\n", rc); - lpfc_sli4_mbox_cmd_free(phba, mboxq); - rc = -EIO; - } else - rc = 0; - - return rc; -} - -/** - * lpfc_sli4_build_dflt_fcf_record - Build the driver's default FCF Record. - * @phba: pointer to lpfc hba data structure. - * @fcf_record: pointer to the fcf record to write the default data. - * @fcf_index: FCF table entry index. - * - * This routine is invoked to build the driver's default FCF record. The - * values used are hardcoded. This routine handles memory initialization. - * - **/ -void -lpfc_sli4_build_dflt_fcf_record(struct lpfc_hba *phba, - struct fcf_record *fcf_record, - uint16_t fcf_index) -{ - memset(fcf_record, 0, sizeof(struct fcf_record)); - fcf_record->max_rcv_size = LPFC_FCOE_MAX_RCV_SIZE; - fcf_record->fka_adv_period = LPFC_FCOE_FKA_ADV_PER; - fcf_record->fip_priority = LPFC_FCOE_FIP_PRIORITY; - bf_set(lpfc_fcf_record_mac_0, fcf_record, phba->fc_map[0]); - bf_set(lpfc_fcf_record_mac_1, fcf_record, phba->fc_map[1]); - bf_set(lpfc_fcf_record_mac_2, fcf_record, phba->fc_map[2]); - bf_set(lpfc_fcf_record_mac_3, fcf_record, LPFC_FCOE_FCF_MAC3); - bf_set(lpfc_fcf_record_mac_4, fcf_record, LPFC_FCOE_FCF_MAC4); - bf_set(lpfc_fcf_record_mac_5, fcf_record, LPFC_FCOE_FCF_MAC5); - bf_set(lpfc_fcf_record_fc_map_0, fcf_record, phba->fc_map[0]); - bf_set(lpfc_fcf_record_fc_map_1, fcf_record, phba->fc_map[1]); - bf_set(lpfc_fcf_record_fc_map_2, fcf_record, phba->fc_map[2]); - bf_set(lpfc_fcf_record_fcf_valid, fcf_record, 1); - bf_set(lpfc_fcf_record_fcf_avail, fcf_record, 1); - bf_set(lpfc_fcf_record_fcf_index, fcf_record, fcf_index); - bf_set(lpfc_fcf_record_mac_addr_prov, fcf_record, - LPFC_FCF_FPMA | LPFC_FCF_SPMA); - /* Set the VLAN bit map */ - if (phba->valid_vlan) { - fcf_record->vlan_bitmap[phba->vlan_id / 8] - = 1 << (phba->vlan_id % 8); - } -} - -/** - * lpfc_sli4_fcf_scan_read_fcf_rec - Read hba fcf record for fcf scan. - * @phba: pointer to lpfc hba data structure. - * @fcf_index: FCF table entry offset. - * - * This routine is invoked to scan the entire FCF table by reading FCF - * record and processing it one at a time starting from the @fcf_index - * for initial FCF discovery or fast FCF failover rediscovery. - * - * Return 0 if the mailbox command is submitted successfully, none 0 - * otherwise. - **/ -int -lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) -{ - int rc = 0, error; - LPFC_MBOXQ_t *mboxq; - - phba->fcoe_eventtag_at_fcf_scan = phba->fcoe_eventtag; - phba->fcoe_cvl_eventtag_attn = phba->fcoe_cvl_eventtag; - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2000 Failed to allocate mbox for " - "READ_FCF cmd\n"); - error = -ENOMEM; - goto fail_fcf_scan; - } - /* Construct the read FCF record mailbox command */ - rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index); - if (rc) { - error = -EINVAL; - goto fail_fcf_scan; - } - /* Issue the mailbox command asynchronously */ - mboxq->vport = phba->pport; - mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_scan_read_fcf_rec; - - spin_lock_irq(&phba->hbalock); - phba->hba_flag |= FCF_TS_INPROG; - spin_unlock_irq(&phba->hbalock); - - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - error = -EIO; - else { - /* Reset eligible FCF count for new scan */ - if (fcf_index == LPFC_FCOE_FCF_GET_FIRST) - phba->fcf.eligible_fcf_cnt = 0; - error = 0; - } -fail_fcf_scan: - if (error) { - if (mboxq) - lpfc_sli4_mbox_cmd_free(phba, mboxq); - /* FCF scan failed, clear FCF_TS_INPROG flag */ - spin_lock_irq(&phba->hbalock); - phba->hba_flag &= ~FCF_TS_INPROG; - spin_unlock_irq(&phba->hbalock); - } - return error; -} - -/** - * lpfc_sli4_fcf_rr_read_fcf_rec - Read hba fcf record for roundrobin fcf. - * @phba: pointer to lpfc hba data structure. - * @fcf_index: FCF table entry offset. - * - * This routine is invoked to read an FCF record indicated by @fcf_index - * and to use it for FLOGI roundrobin FCF failover. - * - * Return 0 if the mailbox command is submitted successfully, none 0 - * otherwise. - **/ -int -lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) -{ - int rc = 0, error; - LPFC_MBOXQ_t *mboxq; - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_INIT, - "2763 Failed to allocate mbox for " - "READ_FCF cmd\n"); - error = -ENOMEM; - goto fail_fcf_read; - } - /* Construct the read FCF record mailbox command */ - rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index); - if (rc) { - error = -EINVAL; - goto fail_fcf_read; - } - /* Issue the mailbox command asynchronously */ - mboxq->vport = phba->pport; - mboxq->mbox_cmpl = lpfc_mbx_cmpl_fcf_rr_read_fcf_rec; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - error = -EIO; - else - error = 0; - -fail_fcf_read: - if (error && mboxq) - lpfc_sli4_mbox_cmd_free(phba, mboxq); - return error; -} - -/** - * lpfc_sli4_read_fcf_rec - Read hba fcf record for update eligible fcf bmask. - * @phba: pointer to lpfc hba data structure. - * @fcf_index: FCF table entry offset. - * - * This routine is invoked to read an FCF record indicated by @fcf_index to - * determine whether it's eligible for FLOGI roundrobin failover list. - * - * Return 0 if the mailbox command is submitted successfully, none 0 - * otherwise. - **/ -int -lpfc_sli4_read_fcf_rec(struct lpfc_hba *phba, uint16_t fcf_index) -{ - int rc = 0, error; - LPFC_MBOXQ_t *mboxq; - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP | LOG_INIT, - "2758 Failed to allocate mbox for " - "READ_FCF cmd\n"); - error = -ENOMEM; - goto fail_fcf_read; - } - /* Construct the read FCF record mailbox command */ - rc = lpfc_sli4_mbx_read_fcf_rec(phba, mboxq, fcf_index); - if (rc) { - error = -EINVAL; - goto fail_fcf_read; - } - /* Issue the mailbox command asynchronously */ - mboxq->vport = phba->pport; - mboxq->mbox_cmpl = lpfc_mbx_cmpl_read_fcf_rec; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) - error = -EIO; - else - error = 0; - -fail_fcf_read: - if (error && mboxq) - lpfc_sli4_mbox_cmd_free(phba, mboxq); - return error; -} - -/** - * lpfc_check_next_fcf_pri - * phba pointer to the lpfc_hba struct for this port. - * This routine is called from the lpfc_sli4_fcf_rr_next_index_get - * routine when the rr_bmask is empty. The FCF indecies are put into the - * rr_bmask based on their priority level. Starting from the highest priority - * to the lowest. The most likely FCF candidate will be in the highest - * priority group. When this routine is called it searches the fcf_pri list for - * next lowest priority group and repopulates the rr_bmask with only those - * fcf_indexes. - * returns: - * 1=success 0=failure - **/ -int -lpfc_check_next_fcf_pri_level(struct lpfc_hba *phba) -{ - uint16_t next_fcf_pri; - uint16_t last_index; - struct lpfc_fcf_pri *fcf_pri; - int rc; - int ret = 0; - - last_index = find_first_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX); - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "3060 Last IDX %d\n", last_index); - if (list_empty(&phba->fcf.fcf_pri_list)) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "3061 Last IDX %d\n", last_index); - return 0; /* Empty rr list */ - } - next_fcf_pri = 0; - /* - * Clear the rr_bmask and set all of the bits that are at this - * priority. - */ - memset(phba->fcf.fcf_rr_bmask, 0, - sizeof(*phba->fcf.fcf_rr_bmask)); - spin_lock_irq(&phba->hbalock); - list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { - if (fcf_pri->fcf_rec.flag & LPFC_FCF_FLOGI_FAILED) - continue; - /* - * the 1st priority that has not FLOGI failed - * will be the highest. - */ - if (!next_fcf_pri) - next_fcf_pri = fcf_pri->fcf_rec.priority; - spin_unlock_irq(&phba->hbalock); - if (fcf_pri->fcf_rec.priority == next_fcf_pri) { - rc = lpfc_sli4_fcf_rr_index_set(phba, - fcf_pri->fcf_rec.fcf_index); - if (rc) - return 0; - } - spin_lock_irq(&phba->hbalock); - } - /* - * if next_fcf_pri was not set above and the list is not empty then - * we have failed flogis on all of them. So reset flogi failed - * and start at the begining. - */ - if (!next_fcf_pri && !list_empty(&phba->fcf.fcf_pri_list)) { - list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { - fcf_pri->fcf_rec.flag &= ~LPFC_FCF_FLOGI_FAILED; - /* - * the 1st priority that has not FLOGI failed - * will be the highest. - */ - if (!next_fcf_pri) - next_fcf_pri = fcf_pri->fcf_rec.priority; - spin_unlock_irq(&phba->hbalock); - if (fcf_pri->fcf_rec.priority == next_fcf_pri) { - rc = lpfc_sli4_fcf_rr_index_set(phba, - fcf_pri->fcf_rec.fcf_index); - if (rc) - return 0; - } - spin_lock_irq(&phba->hbalock); - } - } else - ret = 1; - spin_unlock_irq(&phba->hbalock); - - return ret; -} -/** - * lpfc_sli4_fcf_rr_next_index_get - Get next eligible fcf record index - * @phba: pointer to lpfc hba data structure. - * - * This routine is to get the next eligible FCF record index in a round - * robin fashion. If the next eligible FCF record index equals to the - * initial roundrobin FCF record index, LPFC_FCOE_FCF_NEXT_NONE (0xFFFF) - * shall be returned, otherwise, the next eligible FCF record's index - * shall be returned. - **/ -uint16_t -lpfc_sli4_fcf_rr_next_index_get(struct lpfc_hba *phba) -{ - uint16_t next_fcf_index; - - /* Search start from next bit of currently registered FCF index */ -next_priority: - next_fcf_index = (phba->fcf.current_rec.fcf_indx + 1) % - LPFC_SLI4_FCF_TBL_INDX_MAX; - next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX, - next_fcf_index); - - /* Wrap around condition on phba->fcf.fcf_rr_bmask */ - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { - /* - * If we have wrapped then we need to clear the bits that - * have been tested so that we can detect when we should - * change the priority level. - */ - next_fcf_index = find_next_bit(phba->fcf.fcf_rr_bmask, - LPFC_SLI4_FCF_TBL_INDX_MAX, 0); - } - - - /* Check roundrobin failover list empty condition */ - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX || - next_fcf_index == phba->fcf.current_rec.fcf_indx) { - /* - * If next fcf index is not found check if there are lower - * Priority level fcf's in the fcf_priority list. - * Set up the rr_bmask with all of the avaiable fcf bits - * at that level and continue the selection process. - */ - if (lpfc_check_next_fcf_pri_level(phba)) - goto next_priority; - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "2844 No roundrobin failover FCF available\n"); - if (next_fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) - return LPFC_FCOE_FCF_NEXT_NONE; - else { - lpfc_printf_log(phba, KERN_WARNING, LOG_FIP, - "3063 Only FCF available idx %d, flag %x\n", - next_fcf_index, - phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag); - return next_fcf_index; - } - } - - if (next_fcf_index < LPFC_SLI4_FCF_TBL_INDX_MAX && - phba->fcf.fcf_pri[next_fcf_index].fcf_rec.flag & - LPFC_FCF_FLOGI_FAILED) - goto next_priority; - - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2845 Get next roundrobin failover FCF (x%x)\n", - next_fcf_index); - - return next_fcf_index; -} - -/** - * lpfc_sli4_fcf_rr_index_set - Set bmask with eligible fcf record index - * @phba: pointer to lpfc hba data structure. - * - * This routine sets the FCF record index in to the eligible bmask for - * roundrobin failover search. It checks to make sure that the index - * does not go beyond the range of the driver allocated bmask dimension - * before setting the bit. - * - * Returns 0 if the index bit successfully set, otherwise, it returns - * -EINVAL. - **/ -int -lpfc_sli4_fcf_rr_index_set(struct lpfc_hba *phba, uint16_t fcf_index) -{ - if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "2610 FCF (x%x) reached driver's book " - "keeping dimension:x%x\n", - fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX); - return -EINVAL; - } - /* Set the eligible FCF record index bmask */ - set_bit(fcf_index, phba->fcf.fcf_rr_bmask); - - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2790 Set FCF (x%x) to roundrobin FCF failover " - "bmask\n", fcf_index); - - return 0; -} - -/** - * lpfc_sli4_fcf_rr_index_clear - Clear bmask from eligible fcf record index - * @phba: pointer to lpfc hba data structure. - * - * This routine clears the FCF record index from the eligible bmask for - * roundrobin failover search. It checks to make sure that the index - * does not go beyond the range of the driver allocated bmask dimension - * before clearing the bit. - **/ -void -lpfc_sli4_fcf_rr_index_clear(struct lpfc_hba *phba, uint16_t fcf_index) -{ - struct lpfc_fcf_pri *fcf_pri; - if (fcf_index >= LPFC_SLI4_FCF_TBL_INDX_MAX) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "2762 FCF (x%x) reached driver's book " - "keeping dimension:x%x\n", - fcf_index, LPFC_SLI4_FCF_TBL_INDX_MAX); - return; - } - /* Clear the eligible FCF record index bmask */ - spin_lock_irq(&phba->hbalock); - list_for_each_entry(fcf_pri, &phba->fcf.fcf_pri_list, list) { - if (fcf_pri->fcf_rec.fcf_index == fcf_index) { - list_del_init(&fcf_pri->list); - break; - } - } - spin_unlock_irq(&phba->hbalock); - clear_bit(fcf_index, phba->fcf.fcf_rr_bmask); - - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2791 Clear FCF (x%x) from roundrobin failover " - "bmask\n", fcf_index); -} - -/** - * lpfc_mbx_cmpl_redisc_fcf_table - completion routine for rediscover FCF table - * @phba: pointer to lpfc hba data structure. - * - * This routine is the completion routine for the rediscover FCF table mailbox - * command. If the mailbox command returned failure, it will try to stop the - * FCF rediscover wait timer. - **/ -void -lpfc_mbx_cmpl_redisc_fcf_table(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) -{ - struct lpfc_mbx_redisc_fcf_tbl *redisc_fcf; - uint32_t shdr_status, shdr_add_status; - - redisc_fcf = &mbox->u.mqe.un.redisc_fcf_tbl; - - shdr_status = bf_get(lpfc_mbox_hdr_status, - &redisc_fcf->header.cfg_shdr.response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, - &redisc_fcf->header.cfg_shdr.response); - if (shdr_status || shdr_add_status) { - lpfc_printf_log(phba, KERN_ERR, LOG_FIP, - "2746 Requesting for FCF rediscovery failed " - "status x%x add_status x%x\n", - shdr_status, shdr_add_status); - if (phba->fcf.fcf_flag & FCF_ACVL_DISC) { - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_ACVL_DISC; - spin_unlock_irq(&phba->hbalock); - /* - * CVL event triggered FCF rediscover request failed, - * last resort to re-try current registered FCF entry. - */ - lpfc_retry_pport_discovery(phba); - } else { - spin_lock_irq(&phba->hbalock); - phba->fcf.fcf_flag &= ~FCF_DEAD_DISC; - spin_unlock_irq(&phba->hbalock); - /* - * DEAD FCF event triggered FCF rediscover request - * failed, last resort to fail over as a link down - * to FCF registration. - */ - lpfc_sli4_fcf_dead_failthrough(phba); - } - } else { - lpfc_printf_log(phba, KERN_INFO, LOG_FIP, - "2775 Start FCF rediscover quiescent timer\n"); - /* - * Start FCF rediscovery wait timer for pending FCF - * before rescan FCF record table. - */ - lpfc_fcf_redisc_wait_start_timer(phba); - } - - mempool_free(mbox, phba->mbox_mem_pool); -} - -/** - * lpfc_sli4_redisc_fcf_table - Request to rediscover entire FCF table by port. - * @phba: pointer to lpfc hba data structure. - * - * This routine is invoked to request for rediscovery of the entire FCF table - * by the port. - **/ -int -lpfc_sli4_redisc_fcf_table(struct lpfc_hba *phba) -{ - LPFC_MBOXQ_t *mbox; - struct lpfc_mbx_redisc_fcf_tbl *redisc_fcf; - int rc, length; - - /* Cancel retry delay timers to all vports before FCF rediscover */ - lpfc_cancel_all_vport_retry_delay_timer(phba); - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) { - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2745 Failed to allocate mbox for " - "requesting FCF rediscover.\n"); - return -ENOMEM; - } - - length = (sizeof(struct lpfc_mbx_redisc_fcf_tbl) - - sizeof(struct lpfc_sli4_cfg_mhdr)); - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_FCOE, - LPFC_MBOX_OPCODE_FCOE_REDISCOVER_FCF, - length, LPFC_SLI4_MBX_EMBED); - - redisc_fcf = &mbox->u.mqe.un.redisc_fcf_tbl; - /* Set count to 0 for invalidating the entire FCF database */ - bf_set(lpfc_mbx_redisc_fcf_count, redisc_fcf, 0); - - /* Issue the mailbox command asynchronously */ - mbox->vport = phba->pport; - mbox->mbox_cmpl = lpfc_mbx_cmpl_redisc_fcf_table; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); - return -EIO; - } - return 0; -} - -/** - * lpfc_sli4_fcf_dead_failthrough - Failthrough routine to fcf dead event - * @phba: pointer to lpfc hba data structure. - * - * This function is the failover routine as a last resort to the FCF DEAD - * event when driver failed to perform fast FCF failover. - **/ -void -lpfc_sli4_fcf_dead_failthrough(struct lpfc_hba *phba) -{ - uint32_t link_state; - - /* - * Last resort as FCF DEAD event failover will treat this as - * a link down, but save the link state because we don't want - * it to be changed to Link Down unless it is already down. - */ - link_state = phba->link_state; - lpfc_linkdown(phba); - phba->link_state = link_state; - - /* Unregister FCF if no devices connected to it */ - lpfc_unregister_unused_fcf(phba); -} - -/** - * lpfc_sli_get_config_region23 - Get sli3 port region 23 data. - * @phba: pointer to lpfc hba data structure. - * @rgn23_data: pointer to configure region 23 data. - * - * This function gets SLI3 port configure region 23 data through memory dump - * mailbox command. When it successfully retrieves data, the size of the data - * will be returned, otherwise, 0 will be returned. - **/ -static uint32_t -lpfc_sli_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) -{ - LPFC_MBOXQ_t *pmb = NULL; - MAILBOX_t *mb; - uint32_t offset = 0; - int rc; - - if (!rgn23_data) - return 0; - - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2600 failed to allocate mailbox memory\n"); - return 0; - } - mb = &pmb->u.mb; - - do { - lpfc_dump_mem(phba, pmb, offset, DMP_REGION_23); - rc = lpfc_sli_issue_mbox(phba, pmb, MBX_POLL); - - if (rc != MBX_SUCCESS) { - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2601 failed to read config " - "region 23, rc 0x%x Status 0x%x\n", - rc, mb->mbxStatus); - mb->un.varDmp.word_cnt = 0; - } - /* - * dump mem may return a zero when finished or we got a - * mailbox error, either way we are done. - */ - if (mb->un.varDmp.word_cnt == 0) - break; - if (mb->un.varDmp.word_cnt > DMP_RGN23_SIZE - offset) - mb->un.varDmp.word_cnt = DMP_RGN23_SIZE - offset; - - lpfc_sli_pcimem_bcopy(((uint8_t *)mb) + DMP_RSP_OFFSET, - rgn23_data + offset, - mb->un.varDmp.word_cnt); - offset += mb->un.varDmp.word_cnt; - } while (mb->un.varDmp.word_cnt && offset < DMP_RGN23_SIZE); - - mempool_free(pmb, phba->mbox_mem_pool); - return offset; -} - -/** - * lpfc_sli4_get_config_region23 - Get sli4 port region 23 data. - * @phba: pointer to lpfc hba data structure. - * @rgn23_data: pointer to configure region 23 data. - * - * This function gets SLI4 port configure region 23 data through memory dump - * mailbox command. When it successfully retrieves data, the size of the data - * will be returned, otherwise, 0 will be returned. - **/ -static uint32_t -lpfc_sli4_get_config_region23(struct lpfc_hba *phba, char *rgn23_data) -{ - LPFC_MBOXQ_t *mboxq = NULL; - struct lpfc_dmabuf *mp = NULL; - struct lpfc_mqe *mqe; - uint32_t data_length = 0; - int rc; - - if (!rgn23_data) - return 0; - - mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mboxq) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3105 failed to allocate mailbox memory\n"); - return 0; - } - - if (lpfc_sli4_dump_cfg_rg23(phba, mboxq)) - goto out; - mqe = &mboxq->u.mqe; - mp = (struct lpfc_dmabuf *) mboxq->context1; - rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); - if (rc) - goto out; - data_length = mqe->un.mb_words[5]; - if (data_length == 0) - goto out; - if (data_length > DMP_RGN23_SIZE) { - data_length = 0; - goto out; - } - lpfc_sli_pcimem_bcopy((char *)mp->virt, rgn23_data, data_length); -out: - mempool_free(mboxq, phba->mbox_mem_pool); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - return data_length; -} - -/** - * lpfc_sli_read_link_ste - Read region 23 to decide if link is disabled. - * @phba: pointer to lpfc hba data structure. - * - * This function read region 23 and parse TLV for port status to - * decide if the user disaled the port. If the TLV indicates the - * port is disabled, the hba_flag is set accordingly. - **/ -void -lpfc_sli_read_link_ste(struct lpfc_hba *phba) -{ - uint8_t *rgn23_data = NULL; - uint32_t if_type, data_size, sub_tlv_len, tlv_offset; - uint32_t offset = 0; - - /* Get adapter Region 23 data */ - rgn23_data = kzalloc(DMP_RGN23_SIZE, GFP_KERNEL); - if (!rgn23_data) - goto out; - - if (phba->sli_rev < LPFC_SLI_REV4) - data_size = lpfc_sli_get_config_region23(phba, rgn23_data); - else { - if_type = bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf); - if (if_type == LPFC_SLI_INTF_IF_TYPE_0) - goto out; - data_size = lpfc_sli4_get_config_region23(phba, rgn23_data); - } - - if (!data_size) - goto out; - - /* Check the region signature first */ - if (memcmp(&rgn23_data[offset], LPFC_REGION23_SIGNATURE, 4)) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2619 Config region 23 has bad signature\n"); - goto out; - } - offset += 4; - - /* Check the data structure version */ - if (rgn23_data[offset] != LPFC_REGION23_VERSION) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "2620 Config region 23 has bad version\n"); - goto out; - } - offset += 4; - - /* Parse TLV entries in the region */ - while (offset < data_size) { - if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) - break; - /* - * If the TLV is not driver specific TLV or driver id is - * not linux driver id, skip the record. - */ - if ((rgn23_data[offset] != DRIVER_SPECIFIC_TYPE) || - (rgn23_data[offset + 2] != LINUX_DRIVER_ID) || - (rgn23_data[offset + 3] != 0)) { - offset += rgn23_data[offset + 1] * 4 + 4; - continue; - } - - /* Driver found a driver specific TLV in the config region */ - sub_tlv_len = rgn23_data[offset + 1] * 4; - offset += 4; - tlv_offset = 0; - - /* - * Search for configured port state sub-TLV. - */ - while ((offset < data_size) && - (tlv_offset < sub_tlv_len)) { - if (rgn23_data[offset] == LPFC_REGION23_LAST_REC) { - offset += 4; - tlv_offset += 4; - break; - } - if (rgn23_data[offset] != PORT_STE_TYPE) { - offset += rgn23_data[offset + 1] * 4 + 4; - tlv_offset += rgn23_data[offset + 1] * 4 + 4; - continue; - } - - /* This HBA contains PORT_STE configured */ - if (!rgn23_data[offset + 2]) - phba->hba_flag |= LINK_DISABLED; - - goto out; - } - } - -out: - kfree(rgn23_data); - return; -} - -/** - * lpfc_wr_object - write an object to the firmware - * @phba: HBA structure that indicates port to create a queue on. - * @dmabuf_list: list of dmabufs to write to the port. - * @size: the total byte value of the objects to write to the port. - * @offset: the current offset to be used to start the transfer. - * - * This routine will create a wr_object mailbox command to send to the port. - * the mailbox command will be constructed using the dma buffers described in - * @dmabuf_list to create a list of BDEs. This routine will fill in as many - * BDEs that the imbedded mailbox can support. The @offset variable will be - * used to indicate the starting offset of the transfer and will also return - * the offset after the write object mailbox has completed. @size is used to - * determine the end of the object and whether the eof bit should be set. - * - * Return 0 is successful and offset will contain the the new offset to use - * for the next write. - * Return negative value for error cases. - **/ -int -lpfc_wr_object(struct lpfc_hba *phba, struct list_head *dmabuf_list, - uint32_t size, uint32_t *offset) -{ - struct lpfc_mbx_wr_object *wr_object; - LPFC_MBOXQ_t *mbox; - int rc = 0, i = 0; - uint32_t shdr_status, shdr_add_status; - uint32_t mbox_tmo; - union lpfc_sli4_cfg_shdr *shdr; - struct lpfc_dmabuf *dmabuf; - uint32_t written = 0; - - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) - return -ENOMEM; - - lpfc_sli4_config(phba, mbox, LPFC_MBOX_SUBSYSTEM_COMMON, - LPFC_MBOX_OPCODE_WRITE_OBJECT, - sizeof(struct lpfc_mbx_wr_object) - - sizeof(struct lpfc_sli4_cfg_mhdr), LPFC_SLI4_MBX_EMBED); - - wr_object = (struct lpfc_mbx_wr_object *)&mbox->u.mqe.un.wr_object; - wr_object->u.request.write_offset = *offset; - sprintf((uint8_t *)wr_object->u.request.object_name, "/"); - wr_object->u.request.object_name[0] = - cpu_to_le32(wr_object->u.request.object_name[0]); - bf_set(lpfc_wr_object_eof, &wr_object->u.request, 0); - list_for_each_entry(dmabuf, dmabuf_list, list) { - if (i >= LPFC_MBX_WR_CONFIG_MAX_BDE || written >= size) - break; - wr_object->u.request.bde[i].addrLow = putPaddrLow(dmabuf->phys); - wr_object->u.request.bde[i].addrHigh = - putPaddrHigh(dmabuf->phys); - if (written + SLI4_PAGE_SIZE >= size) { - wr_object->u.request.bde[i].tus.f.bdeSize = - (size - written); - written += (size - written); - bf_set(lpfc_wr_object_eof, &wr_object->u.request, 1); - } else { - wr_object->u.request.bde[i].tus.f.bdeSize = - SLI4_PAGE_SIZE; - written += SLI4_PAGE_SIZE; - } - i++; - } - wr_object->u.request.bde_count = i; - bf_set(lpfc_wr_object_write_length, &wr_object->u.request, written); - if (!phba->sli4_hba.intr_enable) - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_POLL); - else { - mbox_tmo = lpfc_mbox_tmo_val(phba, mbox); - rc = lpfc_sli_issue_mbox_wait(phba, mbox, mbox_tmo); - } - /* The IOCTL status is embedded in the mailbox subheader. */ - shdr = (union lpfc_sli4_cfg_shdr *) &wr_object->header.cfg_shdr; - shdr_status = bf_get(lpfc_mbox_hdr_status, &shdr->response); - shdr_add_status = bf_get(lpfc_mbox_hdr_add_status, &shdr->response); - if (rc != MBX_TIMEOUT) - mempool_free(mbox, phba->mbox_mem_pool); - if (shdr_status || shdr_add_status || rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3025 Write Object mailbox failed with " - "status x%x add_status x%x, mbx status x%x\n", - shdr_status, shdr_add_status, rc); - rc = -ENXIO; - } else - *offset += wr_object->u.response.actual_write_length; - return rc; -} - -/** - * lpfc_cleanup_pending_mbox - Free up vport discovery mailbox commands. - * @vport: pointer to vport data structure. - * - * This function iterate through the mailboxq and clean up all REG_LOGIN - * and REG_VPI mailbox commands associated with the vport. This function - * is called when driver want to restart discovery of the vport due to - * a Clear Virtual Link event. - **/ -void -lpfc_cleanup_pending_mbox(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - LPFC_MBOXQ_t *mb, *nextmb; - struct lpfc_dmabuf *mp; - struct lpfc_nodelist *ndlp; - struct lpfc_nodelist *act_mbx_ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - LIST_HEAD(mbox_cmd_list); - uint8_t restart_loop; - - /* Clean up internally queued mailbox commands with the vport */ - spin_lock_irq(&phba->hbalock); - list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { - if (mb->vport != vport) - continue; - - if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) && - (mb->u.mb.mbxCommand != MBX_REG_VPI)) - continue; - - list_del(&mb->list); - list_add_tail(&mb->list, &mbox_cmd_list); - } - /* Clean up active mailbox command with the vport */ - mb = phba->sli.mbox_active; - if (mb && (mb->vport == vport)) { - if ((mb->u.mb.mbxCommand == MBX_REG_LOGIN64) || - (mb->u.mb.mbxCommand == MBX_REG_VPI)) - mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { - act_mbx_ndlp = (struct lpfc_nodelist *)mb->context2; - /* Put reference count for delayed processing */ - act_mbx_ndlp = lpfc_nlp_get(act_mbx_ndlp); - /* Unregister the RPI when mailbox complete */ - mb->mbox_flag |= LPFC_MBX_IMED_UNREG; - } - } - /* Cleanup any mailbox completions which are not yet processed */ - do { - restart_loop = 0; - list_for_each_entry(mb, &phba->sli.mboxq_cmpl, list) { - /* - * If this mailox is already processed or it is - * for another vport ignore it. - */ - if ((mb->vport != vport) || - (mb->mbox_flag & LPFC_MBX_IMED_UNREG)) - continue; - - if ((mb->u.mb.mbxCommand != MBX_REG_LOGIN64) && - (mb->u.mb.mbxCommand != MBX_REG_VPI)) - continue; - - mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { - ndlp = (struct lpfc_nodelist *)mb->context2; - /* Unregister the RPI when mailbox complete */ - mb->mbox_flag |= LPFC_MBX_IMED_UNREG; - restart_loop = 1; - spin_unlock_irq(&phba->hbalock); - spin_lock(shost->host_lock); - ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); - spin_lock_irq(&phba->hbalock); - break; - } - } - } while (restart_loop); - - spin_unlock_irq(&phba->hbalock); - - /* Release the cleaned-up mailbox commands */ - while (!list_empty(&mbox_cmd_list)) { - list_remove_head(&mbox_cmd_list, mb, LPFC_MBOXQ_t, list); - if (mb->u.mb.mbxCommand == MBX_REG_LOGIN64) { - mp = (struct lpfc_dmabuf *) (mb->context1); - if (mp) { - __lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - ndlp = (struct lpfc_nodelist *) mb->context2; - mb->context2 = NULL; - if (ndlp) { - spin_lock(shost->host_lock); - ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); - lpfc_nlp_put(ndlp); - } - } - mempool_free(mb, phba->mbox_mem_pool); - } - - /* Release the ndlp with the cleaned-up active mailbox command */ - if (act_mbx_ndlp) { - spin_lock(shost->host_lock); - act_mbx_ndlp->nlp_flag &= ~NLP_IGNR_REG_CMPL; - spin_unlock(shost->host_lock); - lpfc_nlp_put(act_mbx_ndlp); - } -} - -/** - * lpfc_drain_txq - Drain the txq - * @phba: Pointer to HBA context object. - * - * This function attempt to submit IOCBs on the txq - * to the adapter. For SLI4 adapters, the txq contains - * ELS IOCBs that have been deferred because the there - * are no SGLs. This congestion can occur with large - * vport counts during node discovery. - **/ - -uint32_t -lpfc_drain_txq(struct lpfc_hba *phba) -{ - LIST_HEAD(completions); - struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING]; - struct lpfc_iocbq *piocbq = 0; - unsigned long iflags = 0; - char *fail_msg = NULL; - struct lpfc_sglq *sglq; - union lpfc_wqe wqe; - - spin_lock_irqsave(&phba->hbalock, iflags); - if (pring->txq_cnt > pring->txq_max) - pring->txq_max = pring->txq_cnt; - - spin_unlock_irqrestore(&phba->hbalock, iflags); - - while (pring->txq_cnt) { - spin_lock_irqsave(&phba->hbalock, iflags); - - piocbq = lpfc_sli_ringtx_get(phba, pring); - sglq = __lpfc_sli_get_sglq(phba, piocbq); - if (!sglq) { - __lpfc_sli_ringtx_put(phba, pring, piocbq); - spin_unlock_irqrestore(&phba->hbalock, iflags); - break; - } else { - if (!piocbq) { - /* The txq_cnt out of sync. This should - * never happen - */ - sglq = __lpfc_clear_active_sglq(phba, - sglq->sli4_lxritag); - spin_unlock_irqrestore(&phba->hbalock, iflags); - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2823 txq empty and txq_cnt is %d\n ", - pring->txq_cnt); - break; - } - } - - /* The xri and iocb resources secured, - * attempt to issue request - */ - piocbq->sli4_lxritag = sglq->sli4_lxritag; - piocbq->sli4_xritag = sglq->sli4_xritag; - if (NO_XRI == lpfc_sli4_bpl2sgl(phba, piocbq, sglq)) - fail_msg = "to convert bpl to sgl"; - else if (lpfc_sli4_iocb2wqe(phba, piocbq, &wqe)) - fail_msg = "to convert iocb to wqe"; - else if (lpfc_sli4_wq_put(phba->sli4_hba.els_wq, &wqe)) - fail_msg = " - Wq is full"; - else - lpfc_sli_ringtxcmpl_put(phba, pring, piocbq); - - if (fail_msg) { - /* Failed means we can't issue and need to cancel */ - lpfc_printf_log(phba, KERN_ERR, LOG_SLI, - "2822 IOCB failed %s iotag 0x%x " - "xri 0x%x\n", - fail_msg, - piocbq->iotag, piocbq->sli4_xritag); - list_add_tail(&piocbq->list, &completions); - } - spin_unlock_irqrestore(&phba->hbalock, iflags); - } - - /* Cancel all the IOCBs that cannot be issued */ - lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, - IOERR_SLI_ABORTED); - - return pring->txq_cnt; -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.h deleted file mode 100644 index 3290b8e7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli.h +++ /dev/null @@ -1,304 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2007 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -/* forward declaration for LPFC_IOCB_t's use */ -struct lpfc_hba; -struct lpfc_vport; - -/* Define the context types that SLI handles for abort and sums. */ -typedef enum _lpfc_ctx_cmd { - LPFC_CTX_LUN, - LPFC_CTX_TGT, - LPFC_CTX_HOST -} lpfc_ctx_cmd; - -struct lpfc_cq_event { - struct list_head list; - union { - struct lpfc_mcqe mcqe_cmpl; - struct lpfc_acqe_link acqe_link; - struct lpfc_acqe_fip acqe_fip; - struct lpfc_acqe_dcbx acqe_dcbx; - struct lpfc_acqe_grp5 acqe_grp5; - struct lpfc_acqe_fc_la acqe_fc; - struct lpfc_acqe_sli acqe_sli; - struct lpfc_rcqe rcqe_cmpl; - struct sli4_wcqe_xri_aborted wcqe_axri; - struct lpfc_wcqe_complete wcqe_cmpl; - } cqe; -}; - -/* This structure is used to handle IOCB requests / responses */ -struct lpfc_iocbq { - /* lpfc_iocbqs are used in double linked lists */ - struct list_head list; - struct list_head clist; - struct list_head dlist; - uint16_t iotag; /* pre-assigned IO tag */ - uint16_t sli4_lxritag; /* logical pre-assigned XRI. */ - uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */ - struct lpfc_cq_event cq_event; - - IOCB_t iocb; /* IOCB cmd */ - uint8_t retry; /* retry counter for IOCB cmd - if needed */ - uint16_t iocb_flag; -#define LPFC_IO_LIBDFC 1 /* libdfc iocb */ -#define LPFC_IO_WAKE 2 /* High Priority Queue signal flag */ -#define LPFC_IO_FCP 4 /* FCP command -- iocbq in scsi_buf */ -#define LPFC_DRIVER_ABORTED 8 /* driver aborted this request */ -#define LPFC_IO_FABRIC 0x10 /* Iocb send using fabric scheduler */ -#define LPFC_DELAY_MEM_FREE 0x20 /* Defer free'ing of FC data */ -#define LPFC_EXCHANGE_BUSY 0x40 /* SLI4 hba reported XB in response */ -#define LPFC_USE_FCPWQIDX 0x80 /* Submit to specified FCPWQ index */ -#define DSS_SECURITY_OP 0x100 /* security IO */ -#define LPFC_IO_ON_Q 0x200 /* The IO is still on the TXCMPLQ */ -#define LPFC_IO_DIF 0x400 /* T10 DIF IO */ - -#define LPFC_FIP_ELS_ID_MASK 0xc000 /* ELS_ID range 0-3, non-shifted mask */ -#define LPFC_FIP_ELS_ID_SHIFT 14 - - uint8_t rsvd2; - uint32_t drvrTimeout; /* driver timeout in seconds */ - uint32_t fcp_wqidx; /* index to FCP work queue */ - struct lpfc_vport *vport;/* virtual port pointer */ - void *context1; /* caller context information */ - void *context2; /* caller context information */ - void *context3; /* caller context information */ - union { - wait_queue_head_t *wait_queue; - struct lpfc_iocbq *rsp_iocb; - struct lpfcMboxq *mbox; - struct lpfc_nodelist *ndlp; - struct lpfc_node_rrq *rrq; - } context_un; - - void (*fabric_iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); - void (*iocb_cmpl) (struct lpfc_hba *, struct lpfc_iocbq *, - struct lpfc_iocbq *); -}; - -#define SLI_IOCB_RET_IOCB 1 /* Return IOCB if cmd ring full */ - -#define IOCB_SUCCESS 0 -#define IOCB_BUSY 1 -#define IOCB_ERROR 2 -#define IOCB_TIMEDOUT 3 - -#define LPFC_MBX_WAKE 1 -#define LPFC_MBX_IMED_UNREG 2 - -typedef struct lpfcMboxq { - /* MBOXQs are used in single linked lists */ - struct list_head list; /* ptr to next mailbox command */ - union { - MAILBOX_t mb; /* Mailbox cmd */ - struct lpfc_mqe mqe; - } u; - struct lpfc_vport *vport;/* virtual port pointer */ - void *context1; /* caller context information */ - void *context2; /* caller context information */ - - void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); - uint8_t mbox_flag; - uint16_t in_ext_byte_len; - uint16_t out_ext_byte_len; - uint8_t mbox_offset_word; - struct lpfc_mcqe mcqe; - struct lpfc_mbx_nembed_sge_virt *sge_array; -} LPFC_MBOXQ_t; - -#define MBX_POLL 1 /* poll mailbox till command done, then - return */ -#define MBX_NOWAIT 2 /* issue command then return immediately */ - -#define LPFC_MAX_RING_MASK 5 /* max num of rctl/type masks allowed per - ring */ -#define LPFC_MAX_RING 4 /* max num of SLI rings used by driver */ - -struct lpfc_sli_ring; - -struct lpfc_sli_ring_mask { - uint8_t profile; /* profile associated with ring */ - uint8_t rctl; /* rctl / type pair configured for ring */ - uint8_t type; /* rctl / type pair configured for ring */ - uint8_t rsvd; - /* rcv'd unsol event */ - void (*lpfc_sli_rcv_unsol_event) (struct lpfc_hba *, - struct lpfc_sli_ring *, - struct lpfc_iocbq *); -}; - - -/* Structure used to hold SLI statistical counters and info */ -struct lpfc_sli_ring_stat { - uint64_t iocb_event; /* IOCB event counters */ - uint64_t iocb_cmd; /* IOCB cmd issued */ - uint64_t iocb_rsp; /* IOCB rsp received */ - uint64_t iocb_cmd_delay; /* IOCB cmd ring delay */ - uint64_t iocb_cmd_full; /* IOCB cmd ring full */ - uint64_t iocb_cmd_empty; /* IOCB cmd ring is now empty */ - uint64_t iocb_rsp_full; /* IOCB rsp ring full */ -}; - -/* Structure used to hold SLI ring information */ -struct lpfc_sli_ring { - uint16_t flag; /* ring flags */ -#define LPFC_DEFERRED_RING_EVENT 0x001 /* Deferred processing a ring event */ -#define LPFC_CALL_RING_AVAILABLE 0x002 /* indicates cmd was full */ -#define LPFC_STOP_IOCB_EVENT 0x020 /* Stop processing IOCB cmds event */ - uint16_t abtsiotag; /* tracks next iotag to use for ABTS */ - - uint32_t local_getidx; /* last available cmd index (from cmdGetInx) */ - uint32_t next_cmdidx; /* next_cmd index */ - uint32_t rspidx; /* current index in response ring */ - uint32_t cmdidx; /* current index in command ring */ - uint8_t rsvd; - uint8_t ringno; /* ring number */ - uint16_t numCiocb; /* number of command iocb's per ring */ - uint16_t numRiocb; /* number of rsp iocb's per ring */ - uint16_t sizeCiocb; /* Size of command iocb's in this ring */ - uint16_t sizeRiocb; /* Size of response iocb's in this ring */ - - uint32_t fast_iotag; /* max fastlookup based iotag */ - uint32_t iotag_ctr; /* keeps track of the next iotag to use */ - uint32_t iotag_max; /* max iotag value to use */ - struct list_head txq; - uint16_t txq_cnt; /* current length of queue */ - uint16_t txq_max; /* max length */ - struct list_head txcmplq; - uint16_t txcmplq_cnt; /* current length of queue */ - uint16_t txcmplq_max; /* max length */ - uint32_t *cmdringaddr; /* virtual address for cmd rings */ - uint32_t *rspringaddr; /* virtual address for rsp rings */ - uint32_t missbufcnt; /* keep track of buffers to post */ - struct list_head postbufq; - uint16_t postbufq_cnt; /* current length of queue */ - uint16_t postbufq_max; /* max length */ - struct list_head iocb_continueq; - uint16_t iocb_continueq_cnt; /* current length of queue */ - uint16_t iocb_continueq_max; /* max length */ - struct list_head iocb_continue_saveq; - - struct lpfc_sli_ring_mask prt[LPFC_MAX_RING_MASK]; - uint32_t num_mask; /* number of mask entries in prt array */ - void (*lpfc_sli_rcv_async_status) (struct lpfc_hba *, - struct lpfc_sli_ring *, struct lpfc_iocbq *); - - struct lpfc_sli_ring_stat stats; /* SLI statistical info */ - - /* cmd ring available */ - void (*lpfc_sli_cmd_available) (struct lpfc_hba *, - struct lpfc_sli_ring *); -}; - -/* Structure used for configuring rings to a specific profile or rctl / type */ -struct lpfc_hbq_init { - uint32_t rn; /* Receive buffer notification */ - uint32_t entry_count; /* max # of entries in HBQ */ - uint32_t headerLen; /* 0 if not profile 4 or 5 */ - uint32_t logEntry; /* Set to 1 if this HBQ used for LogEntry */ - uint32_t profile; /* Selection profile 0=all, 7=logentry */ - uint32_t ring_mask; /* Binds HBQ to a ring e.g. Ring0=b0001, - * ring2=b0100 */ - uint32_t hbq_index; /* index of this hbq in ring .HBQs[] */ - - uint32_t seqlenoff; - uint32_t maxlen; - uint32_t seqlenbcnt; - uint32_t cmdcodeoff; - uint32_t cmdmatch[8]; - uint32_t mask_count; /* number of mask entries in prt array */ - struct hbq_mask hbqMasks[6]; - - /* Non-config rings fields to keep track of buffer allocations */ - uint32_t buffer_count; /* number of buffers allocated */ - uint32_t init_count; /* number to allocate when initialized */ - uint32_t add_count; /* number to allocate when starved */ -} ; - -/* Structure used to hold SLI statistical counters and info */ -struct lpfc_sli_stat { - uint64_t mbox_stat_err; /* Mbox cmds completed status error */ - uint64_t mbox_cmd; /* Mailbox commands issued */ - uint64_t sli_intr; /* Count of Host Attention interrupts */ - uint32_t err_attn_event; /* Error Attn event counters */ - uint32_t link_event; /* Link event counters */ - uint32_t mbox_event; /* Mailbox event counters */ - uint32_t mbox_busy; /* Mailbox cmd busy */ -}; - -/* Structure to store link status values when port stats are reset */ -struct lpfc_lnk_stat { - uint32_t link_failure_count; - uint32_t loss_of_sync_count; - uint32_t loss_of_signal_count; - uint32_t prim_seq_protocol_err_count; - uint32_t invalid_tx_word_count; - uint32_t invalid_crc_count; - uint32_t error_frames; - uint32_t link_events; -}; - -/* Structure used to hold SLI information */ -struct lpfc_sli { - uint32_t num_rings; - uint32_t sli_flag; - - /* Additional sli_flags */ -#define LPFC_SLI_MBOX_ACTIVE 0x100 /* HBA mailbox is currently active */ -#define LPFC_SLI_ACTIVE 0x200 /* SLI in firmware is active */ -#define LPFC_PROCESS_LA 0x400 /* Able to process link attention */ -#define LPFC_BLOCK_MGMT_IO 0x800 /* Don't allow mgmt mbx or iocb cmds */ -#define LPFC_MENLO_MAINT 0x1000 /* need for menl fw download */ -#define LPFC_SLI_ASYNC_MBX_BLK 0x2000 /* Async mailbox is blocked */ - - struct lpfc_sli_ring ring[LPFC_MAX_RING]; - int fcp_ring; /* ring used for FCP initiator commands */ - int next_ring; - - int extra_ring; /* extra ring used for other protocols */ - - struct lpfc_sli_stat slistat; /* SLI statistical info */ - struct list_head mboxq; - uint16_t mboxq_cnt; /* current length of queue */ - uint16_t mboxq_max; /* max length */ - LPFC_MBOXQ_t *mbox_active; /* active mboxq information */ - struct list_head mboxq_cmpl; - - struct timer_list mbox_tmo; /* Hold clk to timeout active mbox - cmd */ - -#define LPFC_IOCBQ_LOOKUP_INCREMENT 1024 - struct lpfc_iocbq ** iocbq_lookup; /* array to lookup IOCB by IOTAG */ - size_t iocbq_lookup_len; /* current lengs of the array */ - uint16_t last_iotag; /* last allocated IOTAG */ - unsigned long stats_start; /* in seconds */ - struct lpfc_lnk_stat lnk_stat_offsets; -}; - -/* Timeout for normal outstanding mbox command (Seconds) */ -#define LPFC_MBOX_TMO 30 -/* Timeout for non-flash-based outstanding sli_config mbox command (Seconds) */ -#define LPFC_MBOX_SLI4_CONFIG_TMO 60 -/* Timeout for flash-based outstanding sli_config mbox command (Seconds) */ -#define LPFC_MBOX_SLI4_CONFIG_EXTENDED_TMO 300 -/* Timeout for other flash-based outstanding mbox command (Seconds) */ -#define LPFC_MBOX_TMO_FLASH_CMD 300 diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli4.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli4.h deleted file mode 100644 index c19d1396..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_sli4.h +++ /dev/null @@ -1,663 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2009-2011 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#define LPFC_ACTIVE_MBOX_WAIT_CNT 100 -#define LPFC_XRI_EXCH_BUSY_WAIT_TMO 10000 -#define LPFC_XRI_EXCH_BUSY_WAIT_T1 10 -#define LPFC_XRI_EXCH_BUSY_WAIT_T2 30000 -#define LPFC_RELEASE_NOTIFICATION_INTERVAL 32 -#define LPFC_RPI_LOW_WATER_MARK 10 - -#define LPFC_UNREG_FCF 1 -#define LPFC_SKIP_UNREG_FCF 0 - -/* Amount of time in seconds for waiting FCF rediscovery to complete */ -#define LPFC_FCF_REDISCOVER_WAIT_TMO 2000 /* msec */ - -/* Number of SGL entries can be posted in a 4KB nonembedded mbox command */ -#define LPFC_NEMBED_MBOX_SGL_CNT 254 - -/* Multi-queue arrangement for fast-path FCP work queues */ -#define LPFC_FN_EQN_MAX 8 -#define LPFC_SP_EQN_DEF 1 -#define LPFC_FP_EQN_DEF 4 -#define LPFC_FP_EQN_MIN 1 -#define LPFC_FP_EQN_MAX (LPFC_FN_EQN_MAX - LPFC_SP_EQN_DEF) - -#define LPFC_FN_WQN_MAX 32 -#define LPFC_SP_WQN_DEF 1 -#define LPFC_FP_WQN_DEF 4 -#define LPFC_FP_WQN_MIN 1 -#define LPFC_FP_WQN_MAX (LPFC_FN_WQN_MAX - LPFC_SP_WQN_DEF) - -/* - * Provide the default FCF Record attributes used by the driver - * when nonFIP mode is configured and there is no other default - * FCF Record attributes. - */ -#define LPFC_FCOE_FCF_DEF_INDEX 0 -#define LPFC_FCOE_FCF_GET_FIRST 0xFFFF -#define LPFC_FCOE_FCF_NEXT_NONE 0xFFFF - -#define LPFC_FCOE_NULL_VID 0xFFF -#define LPFC_FCOE_IGNORE_VID 0xFFFF - -/* First 3 bytes of default FCF MAC is specified by FC_MAP */ -#define LPFC_FCOE_FCF_MAC3 0xFF -#define LPFC_FCOE_FCF_MAC4 0xFF -#define LPFC_FCOE_FCF_MAC5 0xFE -#define LPFC_FCOE_FCF_MAP0 0x0E -#define LPFC_FCOE_FCF_MAP1 0xFC -#define LPFC_FCOE_FCF_MAP2 0x00 -#define LPFC_FCOE_MAX_RCV_SIZE 0x800 -#define LPFC_FCOE_FKA_ADV_PER 0 -#define LPFC_FCOE_FIP_PRIORITY 0x80 - -#define sli4_sid_from_fc_hdr(fc_hdr) \ - ((fc_hdr)->fh_s_id[0] << 16 | \ - (fc_hdr)->fh_s_id[1] << 8 | \ - (fc_hdr)->fh_s_id[2]) - -#define sli4_fctl_from_fc_hdr(fc_hdr) \ - ((fc_hdr)->fh_f_ctl[0] << 16 | \ - (fc_hdr)->fh_f_ctl[1] << 8 | \ - (fc_hdr)->fh_f_ctl[2]) - -#define LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT 12000 - -enum lpfc_sli4_queue_type { - LPFC_EQ, - LPFC_GCQ, - LPFC_MCQ, - LPFC_WCQ, - LPFC_RCQ, - LPFC_MQ, - LPFC_WQ, - LPFC_HRQ, - LPFC_DRQ -}; - -/* The queue sub-type defines the functional purpose of the queue */ -enum lpfc_sli4_queue_subtype { - LPFC_NONE, - LPFC_MBOX, - LPFC_FCP, - LPFC_ELS, - LPFC_USOL -}; - -union sli4_qe { - void *address; - struct lpfc_eqe *eqe; - struct lpfc_cqe *cqe; - struct lpfc_mcqe *mcqe; - struct lpfc_wcqe_complete *wcqe_complete; - struct lpfc_wcqe_release *wcqe_release; - struct sli4_wcqe_xri_aborted *wcqe_xri_aborted; - struct lpfc_rcqe_complete *rcqe_complete; - struct lpfc_mqe *mqe; - union lpfc_wqe *wqe; - struct lpfc_rqe *rqe; -}; - -struct lpfc_queue { - struct list_head list; - enum lpfc_sli4_queue_type type; - enum lpfc_sli4_queue_subtype subtype; - struct lpfc_hba *phba; - struct list_head child_list; - uint32_t entry_count; /* Number of entries to support on the queue */ - uint32_t entry_size; /* Size of each queue entry. */ - uint32_t entry_repost; /* Count of entries before doorbell is rung */ -#define LPFC_QUEUE_MIN_REPOST 8 - uint32_t queue_id; /* Queue ID assigned by the hardware */ - uint32_t assoc_qid; /* Queue ID associated with, for CQ/WQ/MQ */ - struct list_head page_list; - uint32_t page_count; /* Number of pages allocated for this queue */ - uint32_t host_index; /* The host's index for putting or getting */ - uint32_t hba_index; /* The last known hba index for get or put */ - union sli4_qe qe[1]; /* array to index entries (must be last) */ -}; - -struct lpfc_sli4_link { - uint8_t speed; - uint8_t duplex; - uint8_t status; - uint8_t type; - uint8_t number; - uint8_t fault; - uint16_t logical_speed; - uint16_t topology; -}; - -struct lpfc_fcf_rec { - uint8_t fabric_name[8]; - uint8_t switch_name[8]; - uint8_t mac_addr[6]; - uint16_t fcf_indx; - uint32_t priority; - uint16_t vlan_id; - uint32_t addr_mode; - uint32_t flag; -#define BOOT_ENABLE 0x01 -#define RECORD_VALID 0x02 -}; - -struct lpfc_fcf_pri_rec { - uint16_t fcf_index; -#define LPFC_FCF_ON_PRI_LIST 0x0001 -#define LPFC_FCF_FLOGI_FAILED 0x0002 - uint16_t flag; - uint32_t priority; -}; - -struct lpfc_fcf_pri { - struct list_head list; - struct lpfc_fcf_pri_rec fcf_rec; -}; - -/* - * Maximum FCF table index, it is for driver internal book keeping, it - * just needs to be no less than the supported HBA's FCF table size. - */ -#define LPFC_SLI4_FCF_TBL_INDX_MAX 32 - -struct lpfc_fcf { - uint16_t fcfi; - uint32_t fcf_flag; -#define FCF_AVAILABLE 0x01 /* FCF available for discovery */ -#define FCF_REGISTERED 0x02 /* FCF registered with FW */ -#define FCF_SCAN_DONE 0x04 /* FCF table scan done */ -#define FCF_IN_USE 0x08 /* Atleast one discovery completed */ -#define FCF_INIT_DISC 0x10 /* Initial FCF discovery */ -#define FCF_DEAD_DISC 0x20 /* FCF DEAD fast FCF failover discovery */ -#define FCF_ACVL_DISC 0x40 /* All CVL fast FCF failover discovery */ -#define FCF_DISCOVERY (FCF_INIT_DISC | FCF_DEAD_DISC | FCF_ACVL_DISC) -#define FCF_REDISC_PEND 0x80 /* FCF rediscovery pending */ -#define FCF_REDISC_EVT 0x100 /* FCF rediscovery event to worker thread */ -#define FCF_REDISC_FOV 0x200 /* Post FCF rediscovery fast failover */ -#define FCF_REDISC_PROG (FCF_REDISC_PEND | FCF_REDISC_EVT) - uint32_t addr_mode; - uint32_t eligible_fcf_cnt; - struct lpfc_fcf_rec current_rec; - struct lpfc_fcf_rec failover_rec; - struct list_head fcf_pri_list; - struct lpfc_fcf_pri fcf_pri[LPFC_SLI4_FCF_TBL_INDX_MAX]; - uint32_t current_fcf_scan_pri; - struct timer_list redisc_wait; - unsigned long *fcf_rr_bmask; /* Eligible FCF indexes for RR failover */ -}; - - -#define LPFC_REGION23_SIGNATURE "RG23" -#define LPFC_REGION23_VERSION 1 -#define LPFC_REGION23_LAST_REC 0xff -#define DRIVER_SPECIFIC_TYPE 0xA2 -#define LINUX_DRIVER_ID 0x20 -#define PORT_STE_TYPE 0x1 - -struct lpfc_fip_param_hdr { - uint8_t type; -#define FCOE_PARAM_TYPE 0xA0 - uint8_t length; -#define FCOE_PARAM_LENGTH 2 - uint8_t parm_version; -#define FIPP_VERSION 0x01 - uint8_t parm_flags; -#define lpfc_fip_param_hdr_fipp_mode_SHIFT 6 -#define lpfc_fip_param_hdr_fipp_mode_MASK 0x3 -#define lpfc_fip_param_hdr_fipp_mode_WORD parm_flags -#define FIPP_MODE_ON 0x1 -#define FIPP_MODE_OFF 0x0 -#define FIPP_VLAN_VALID 0x1 -}; - -struct lpfc_fcoe_params { - uint8_t fc_map[3]; - uint8_t reserved1; - uint16_t vlan_tag; - uint8_t reserved[2]; -}; - -struct lpfc_fcf_conn_hdr { - uint8_t type; -#define FCOE_CONN_TBL_TYPE 0xA1 - uint8_t length; /* words */ - uint8_t reserved[2]; -}; - -struct lpfc_fcf_conn_rec { - uint16_t flags; -#define FCFCNCT_VALID 0x0001 -#define FCFCNCT_BOOT 0x0002 -#define FCFCNCT_PRIMARY 0x0004 /* if not set, Secondary */ -#define FCFCNCT_FBNM_VALID 0x0008 -#define FCFCNCT_SWNM_VALID 0x0010 -#define FCFCNCT_VLAN_VALID 0x0020 -#define FCFCNCT_AM_VALID 0x0040 -#define FCFCNCT_AM_PREFERRED 0x0080 /* if not set, AM Required */ -#define FCFCNCT_AM_SPMA 0x0100 /* if not set, FPMA */ - - uint16_t vlan_tag; - uint8_t fabric_name[8]; - uint8_t switch_name[8]; -}; - -struct lpfc_fcf_conn_entry { - struct list_head list; - struct lpfc_fcf_conn_rec conn_rec; -}; - -/* - * Define the host's bootstrap mailbox. This structure contains - * the member attributes needed to create, use, and destroy the - * bootstrap mailbox region. - * - * The macro definitions for the bmbx data structure are defined - * in lpfc_hw4.h with the register definition. - */ -struct lpfc_bmbx { - struct lpfc_dmabuf *dmabuf; - struct dma_address dma_address; - void *avirt; - dma_addr_t aphys; - uint32_t bmbx_size; -}; - -#define LPFC_EQE_SIZE LPFC_EQE_SIZE_4 - -#define LPFC_EQE_SIZE_4B 4 -#define LPFC_EQE_SIZE_16B 16 -#define LPFC_CQE_SIZE 16 -#define LPFC_WQE_SIZE 64 -#define LPFC_MQE_SIZE 256 -#define LPFC_RQE_SIZE 8 - -#define LPFC_EQE_DEF_COUNT 1024 -#define LPFC_CQE_DEF_COUNT 1024 -#define LPFC_WQE_DEF_COUNT 256 -#define LPFC_MQE_DEF_COUNT 16 -#define LPFC_RQE_DEF_COUNT 512 - -#define LPFC_QUEUE_NOARM false -#define LPFC_QUEUE_REARM true - - -/* - * SLI4 CT field defines - */ -#define SLI4_CT_RPI 0 -#define SLI4_CT_VPI 1 -#define SLI4_CT_VFI 2 -#define SLI4_CT_FCFI 3 - -#define LPFC_SLI4_FL1_MAX_SEGMENT_SIZE 0x10000 -#define LPFC_SLI4_FL1_MAX_BUF_SIZE 0X2000 -#define LPFC_SLI4_MIN_BUF_SIZE 0x400 -#define LPFC_SLI4_MAX_BUF_SIZE 0x20000 - -/* - * SLI4 specific data structures - */ -struct lpfc_max_cfg_param { - uint16_t max_xri; - uint16_t xri_base; - uint16_t xri_used; - uint16_t max_rpi; - uint16_t rpi_base; - uint16_t rpi_used; - uint16_t max_vpi; - uint16_t vpi_base; - uint16_t vpi_used; - uint16_t max_vfi; - uint16_t vfi_base; - uint16_t vfi_used; - uint16_t max_fcfi; - uint16_t fcfi_used; - uint16_t max_eq; - uint16_t max_rq; - uint16_t max_cq; - uint16_t max_wq; -}; - -struct lpfc_hba; -/* SLI4 HBA multi-fcp queue handler struct */ -struct lpfc_fcp_eq_hdl { - uint32_t idx; - struct lpfc_hba *phba; -}; - -/* Port Capabilities for SLI4 Parameters */ -struct lpfc_pc_sli4_params { - uint32_t supported; - uint32_t if_type; - uint32_t sli_rev; - uint32_t sli_family; - uint32_t featurelevel_1; - uint32_t featurelevel_2; - uint32_t proto_types; -#define LPFC_SLI4_PROTO_FCOE 0x0000001 -#define LPFC_SLI4_PROTO_FC 0x0000002 -#define LPFC_SLI4_PROTO_NIC 0x0000004 -#define LPFC_SLI4_PROTO_ISCSI 0x0000008 -#define LPFC_SLI4_PROTO_RDMA 0x0000010 - uint32_t sge_supp_len; - uint32_t if_page_sz; - uint32_t rq_db_window; - uint32_t loopbk_scope; - uint32_t eq_pages_max; - uint32_t eqe_size; - uint32_t cq_pages_max; - uint32_t cqe_size; - uint32_t mq_pages_max; - uint32_t mqe_size; - uint32_t mq_elem_cnt; - uint32_t wq_pages_max; - uint32_t wqe_size; - uint32_t rq_pages_max; - uint32_t rqe_size; - uint32_t hdr_pages_max; - uint32_t hdr_size; - uint32_t hdr_pp_align; - uint32_t sgl_pages_max; - uint32_t sgl_pp_align; - uint8_t cqv; - uint8_t mqv; - uint8_t wqv; - uint8_t rqv; -}; - -struct lpfc_iov { - uint32_t pf_number; - uint32_t vf_number; -}; - -struct lpfc_sli4_lnk_info { - uint8_t lnk_dv; -#define LPFC_LNK_DAT_INVAL 0 -#define LPFC_LNK_DAT_VAL 1 - uint8_t lnk_tp; -#define LPFC_LNK_GE 0x0 /* FCoE */ -#define LPFC_LNK_FC 0x1 /* FC */ - uint8_t lnk_no; -}; - -/* SLI4 HBA data structure entries */ -struct lpfc_sli4_hba { - void __iomem *conf_regs_memmap_p; /* Kernel memory mapped address for - PCI BAR0, config space registers */ - void __iomem *ctrl_regs_memmap_p; /* Kernel memory mapped address for - PCI BAR1, control registers */ - void __iomem *drbl_regs_memmap_p; /* Kernel memory mapped address for - PCI BAR2, doorbell registers */ - union { - struct { - /* IF Type 0, BAR 0 PCI cfg space reg mem map */ - void __iomem *UERRLOregaddr; - void __iomem *UERRHIregaddr; - void __iomem *UEMASKLOregaddr; - void __iomem *UEMASKHIregaddr; - } if_type0; - struct { - /* IF Type 2, BAR 0 PCI cfg space reg mem map. */ - void __iomem *STATUSregaddr; - void __iomem *CTRLregaddr; - void __iomem *ERR1regaddr; -#define SLIPORT_ERR1_REG_ERR_CODE_1 0x1 -#define SLIPORT_ERR1_REG_ERR_CODE_2 0x2 - void __iomem *ERR2regaddr; -#define SLIPORT_ERR2_REG_FW_RESTART 0x0 -#define SLIPORT_ERR2_REG_FUNC_PROVISON 0x1 -#define SLIPORT_ERR2_REG_FORCED_DUMP 0x2 -#define SLIPORT_ERR2_REG_FAILURE_EQ 0x3 -#define SLIPORT_ERR2_REG_FAILURE_CQ 0x4 -#define SLIPORT_ERR2_REG_FAILURE_BUS 0x5 -#define SLIPORT_ERR2_REG_FAILURE_RQ 0x6 - } if_type2; - } u; - - /* IF type 0, BAR1 and if type 2, Bar 0 CSR register memory map */ - void __iomem *PSMPHRregaddr; - - /* Well-known SLI INTF register memory map. */ - void __iomem *SLIINTFregaddr; - - /* IF type 0, BAR 1 function CSR register memory map */ - void __iomem *ISRregaddr; /* HST_ISR register */ - void __iomem *IMRregaddr; /* HST_IMR register */ - void __iomem *ISCRregaddr; /* HST_ISCR register */ - /* IF type 0, BAR 0 and if type 2, BAR 0 doorbell register memory map */ - void __iomem *RQDBregaddr; /* RQ_DOORBELL register */ - void __iomem *WQDBregaddr; /* WQ_DOORBELL register */ - void __iomem *EQCQDBregaddr; /* EQCQ_DOORBELL register */ - void __iomem *MQDBregaddr; /* MQ_DOORBELL register */ - void __iomem *BMBXregaddr; /* BootStrap MBX register */ - - uint32_t ue_mask_lo; - uint32_t ue_mask_hi; - struct lpfc_register sli_intf; - struct lpfc_pc_sli4_params pc_sli4_params; - struct msix_entry *msix_entries; - uint32_t cfg_eqn; - uint32_t msix_vec_nr; - struct lpfc_fcp_eq_hdl *fcp_eq_hdl; /* FCP per-WQ handle */ - /* Pointers to the constructed SLI4 queues */ - struct lpfc_queue **fp_eq; /* Fast-path event queue */ - struct lpfc_queue *sp_eq; /* Slow-path event queue */ - struct lpfc_queue **fcp_wq;/* Fast-path FCP work queue */ - struct lpfc_queue *mbx_wq; /* Slow-path MBOX work queue */ - struct lpfc_queue *els_wq; /* Slow-path ELS work queue */ - struct lpfc_queue *hdr_rq; /* Slow-path Header Receive queue */ - struct lpfc_queue *dat_rq; /* Slow-path Data Receive queue */ - struct lpfc_queue **fcp_cq;/* Fast-path FCP compl queue */ - struct lpfc_queue *mbx_cq; /* Slow-path mailbox complete queue */ - struct lpfc_queue *els_cq; /* Slow-path ELS response complete queue */ - - /* Setup information for various queue parameters */ - int eq_esize; - int eq_ecount; - int cq_esize; - int cq_ecount; - int wq_esize; - int wq_ecount; - int mq_esize; - int mq_ecount; - int rq_esize; - int rq_ecount; -#define LPFC_SP_EQ_MAX_INTR_SEC 10000 -#define LPFC_FP_EQ_MAX_INTR_SEC 10000 - - uint32_t intr_enable; - struct lpfc_bmbx bmbx; - struct lpfc_max_cfg_param max_cfg_param; - uint16_t extents_in_use; /* must allocate resource extents. */ - uint16_t rpi_hdrs_in_use; /* must post rpi hdrs if set. */ - uint16_t next_xri; /* last_xri - max_cfg_param.xri_base = used */ - uint16_t next_rpi; - uint16_t scsi_xri_max; - uint16_t scsi_xri_cnt; - uint16_t scsi_xri_start; - struct list_head lpfc_free_sgl_list; - struct list_head lpfc_sgl_list; - struct lpfc_sglq **lpfc_els_sgl_array; - struct list_head lpfc_abts_els_sgl_list; - struct lpfc_scsi_buf **lpfc_scsi_psb_array; - struct list_head lpfc_abts_scsi_buf_list; - uint32_t total_sglq_bufs; - struct lpfc_sglq **lpfc_sglq_active_list; - struct list_head lpfc_rpi_hdr_list; - unsigned long *rpi_bmask; - uint16_t *rpi_ids; - uint16_t rpi_count; - struct list_head lpfc_rpi_blk_list; - unsigned long *xri_bmask; - uint16_t *xri_ids; - uint16_t xri_count; - struct list_head lpfc_xri_blk_list; - unsigned long *vfi_bmask; - uint16_t *vfi_ids; - uint16_t vfi_count; - struct list_head lpfc_vfi_blk_list; - struct lpfc_sli4_flags sli4_flags; - struct list_head sp_queue_event; - struct list_head sp_cqe_event_pool; - struct list_head sp_asynce_work_queue; - struct list_head sp_fcp_xri_aborted_work_queue; - struct list_head sp_els_xri_aborted_work_queue; - struct list_head sp_unsol_work_queue; - struct lpfc_sli4_link link_state; - struct lpfc_sli4_lnk_info lnk_info; - uint32_t pport_name_sta; -#define LPFC_SLI4_PPNAME_NON 0 -#define LPFC_SLI4_PPNAME_GET 1 - struct lpfc_iov iov; - spinlock_t abts_scsi_buf_list_lock; /* list of aborted SCSI IOs */ - spinlock_t abts_sgl_list_lock; /* list of aborted els IOs */ -}; - -enum lpfc_sge_type { - GEN_BUFF_TYPE, - SCSI_BUFF_TYPE -}; - -enum lpfc_sgl_state { - SGL_FREED, - SGL_ALLOCATED, - SGL_XRI_ABORTED -}; - -struct lpfc_sglq { - /* lpfc_sglqs are used in double linked lists */ - struct list_head list; - struct list_head clist; - enum lpfc_sge_type buff_type; /* is this a scsi sgl */ - enum lpfc_sgl_state state; - struct lpfc_nodelist *ndlp; /* ndlp associated with IO */ - uint16_t iotag; /* pre-assigned IO tag */ - uint16_t sli4_lxritag; /* logical pre-assigned xri. */ - uint16_t sli4_xritag; /* pre-assigned XRI, (OXID) tag. */ - struct sli4_sge *sgl; /* pre-assigned SGL */ - void *virt; /* virtual address. */ - dma_addr_t phys; /* physical address */ -}; - -struct lpfc_rpi_hdr { - struct list_head list; - uint32_t len; - struct lpfc_dmabuf *dmabuf; - uint32_t page_count; - uint32_t start_rpi; -}; - -struct lpfc_rsrc_blks { - struct list_head list; - uint16_t rsrc_start; - uint16_t rsrc_size; - uint16_t rsrc_used; -}; - -/* - * SLI4 specific function prototypes - */ -int lpfc_pci_function_reset(struct lpfc_hba *); -int lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *); -int lpfc_sli4_hba_setup(struct lpfc_hba *); -int lpfc_sli4_config(struct lpfc_hba *, struct lpfcMboxq *, uint8_t, - uint8_t, uint32_t, bool); -void lpfc_sli4_mbox_cmd_free(struct lpfc_hba *, struct lpfcMboxq *); -void lpfc_sli4_mbx_sge_set(struct lpfcMboxq *, uint32_t, dma_addr_t, uint32_t); -void lpfc_sli4_mbx_sge_get(struct lpfcMboxq *, uint32_t, - struct lpfc_mbx_sge *); -int lpfc_sli4_mbx_read_fcf_rec(struct lpfc_hba *, struct lpfcMboxq *, - uint16_t); - -void lpfc_sli4_hba_reset(struct lpfc_hba *); -struct lpfc_queue *lpfc_sli4_queue_alloc(struct lpfc_hba *, uint32_t, - uint32_t); -void lpfc_sli4_queue_free(struct lpfc_queue *); -uint32_t lpfc_eq_create(struct lpfc_hba *, struct lpfc_queue *, uint16_t); -uint32_t lpfc_cq_create(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_queue *, uint32_t, uint32_t); -int32_t lpfc_mq_create(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_queue *, uint32_t); -uint32_t lpfc_wq_create(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_queue *, uint32_t); -uint32_t lpfc_rq_create(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_queue *, struct lpfc_queue *, uint32_t); -void lpfc_rq_adjust_repost(struct lpfc_hba *, struct lpfc_queue *, int); -uint32_t lpfc_eq_destroy(struct lpfc_hba *, struct lpfc_queue *); -uint32_t lpfc_cq_destroy(struct lpfc_hba *, struct lpfc_queue *); -uint32_t lpfc_mq_destroy(struct lpfc_hba *, struct lpfc_queue *); -uint32_t lpfc_wq_destroy(struct lpfc_hba *, struct lpfc_queue *); -uint32_t lpfc_rq_destroy(struct lpfc_hba *, struct lpfc_queue *, - struct lpfc_queue *); -int lpfc_sli4_queue_setup(struct lpfc_hba *); -void lpfc_sli4_queue_unset(struct lpfc_hba *); -int lpfc_sli4_post_sgl(struct lpfc_hba *, dma_addr_t, dma_addr_t, uint16_t); -int lpfc_sli4_repost_scsi_sgl_list(struct lpfc_hba *); -uint16_t lpfc_sli4_next_xritag(struct lpfc_hba *); -int lpfc_sli4_post_async_mbox(struct lpfc_hba *); -int lpfc_sli4_post_els_sgl_list(struct lpfc_hba *phba); -int lpfc_sli4_post_els_sgl_list_ext(struct lpfc_hba *phba); -int lpfc_sli4_post_scsi_sgl_block(struct lpfc_hba *, struct list_head *, int); -int lpfc_sli4_post_scsi_sgl_blk_ext(struct lpfc_hba *, struct list_head *, - int); -struct lpfc_cq_event *__lpfc_sli4_cq_event_alloc(struct lpfc_hba *); -struct lpfc_cq_event *lpfc_sli4_cq_event_alloc(struct lpfc_hba *); -void __lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *); -void lpfc_sli4_cq_event_release(struct lpfc_hba *, struct lpfc_cq_event *); -int lpfc_sli4_init_rpi_hdrs(struct lpfc_hba *); -int lpfc_sli4_post_rpi_hdr(struct lpfc_hba *, struct lpfc_rpi_hdr *); -int lpfc_sli4_post_all_rpi_hdrs(struct lpfc_hba *); -struct lpfc_rpi_hdr *lpfc_sli4_create_rpi_hdr(struct lpfc_hba *); -void lpfc_sli4_remove_rpi_hdrs(struct lpfc_hba *); -int lpfc_sli4_alloc_rpi(struct lpfc_hba *); -void lpfc_sli4_free_rpi(struct lpfc_hba *, int); -void lpfc_sli4_remove_rpis(struct lpfc_hba *); -void lpfc_sli4_async_event_proc(struct lpfc_hba *); -void lpfc_sli4_fcf_redisc_event_proc(struct lpfc_hba *); -int lpfc_sli4_resume_rpi(struct lpfc_nodelist *, - void (*)(struct lpfc_hba *, LPFC_MBOXQ_t *), void *); -void lpfc_sli4_fcp_xri_abort_event_proc(struct lpfc_hba *); -void lpfc_sli4_els_xri_abort_event_proc(struct lpfc_hba *); -void lpfc_sli4_fcp_xri_aborted(struct lpfc_hba *, - struct sli4_wcqe_xri_aborted *); -void lpfc_sli4_els_xri_aborted(struct lpfc_hba *, - struct sli4_wcqe_xri_aborted *); -void lpfc_sli4_vport_delete_els_xri_aborted(struct lpfc_vport *); -void lpfc_sli4_vport_delete_fcp_xri_aborted(struct lpfc_vport *); -int lpfc_sli4_brdreset(struct lpfc_hba *); -int lpfc_sli4_add_fcf_record(struct lpfc_hba *, struct fcf_record *); -void lpfc_sli_remove_dflt_fcf(struct lpfc_hba *); -int lpfc_sli4_get_els_iocb_cnt(struct lpfc_hba *); -int lpfc_sli4_init_vpi(struct lpfc_vport *); -uint32_t lpfc_sli4_cq_release(struct lpfc_queue *, bool); -uint32_t lpfc_sli4_eq_release(struct lpfc_queue *, bool); -void lpfc_sli4_fcfi_unreg(struct lpfc_hba *, uint16_t); -int lpfc_sli4_fcf_scan_read_fcf_rec(struct lpfc_hba *, uint16_t); -int lpfc_sli4_fcf_rr_read_fcf_rec(struct lpfc_hba *, uint16_t); -int lpfc_sli4_read_fcf_rec(struct lpfc_hba *, uint16_t); -void lpfc_mbx_cmpl_fcf_scan_read_fcf_rec(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbx_cmpl_fcf_rr_read_fcf_rec(struct lpfc_hba *, LPFC_MBOXQ_t *); -void lpfc_mbx_cmpl_read_fcf_rec(struct lpfc_hba *, LPFC_MBOXQ_t *); -int lpfc_sli4_unregister_fcf(struct lpfc_hba *); -int lpfc_sli4_post_status_check(struct lpfc_hba *); -uint8_t lpfc_sli_config_mbox_subsys_get(struct lpfc_hba *, LPFC_MBOXQ_t *); -uint8_t lpfc_sli_config_mbox_opcode_get(struct lpfc_hba *, LPFC_MBOXQ_t *); diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_version.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_version.h deleted file mode 100644 index 25cefc25..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_version.h +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2012 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#define LPFC_DRIVER_VERSION "8.3.30" -#define LPFC_DRIVER_NAME "lpfc" -#define LPFC_SP_DRIVER_HANDLER_NAME "lpfc:sp" -#define LPFC_FP_DRIVER_HANDLER_NAME "lpfc:fp" - -#define LPFC_MODULE_DESC "Emulex LightPulse Fibre Channel SCSI driver " \ - LPFC_DRIVER_VERSION -#define LPFC_COPYRIGHT "Copyright(c) 2004-2009 Emulex. All rights reserved." diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.c b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.c deleted file mode 100644 index 0fe188e6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.c +++ /dev/null @@ -1,877 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "lpfc_hw4.h" -#include "lpfc_hw.h" -#include "lpfc_sli.h" -#include "lpfc_sli4.h" -#include "lpfc_nl.h" -#include "lpfc_disc.h" -#include "lpfc_scsi.h" -#include "lpfc.h" -#include "lpfc_logmsg.h" -#include "lpfc_crtn.h" -#include "lpfc_version.h" -#include "lpfc_vport.h" - -inline void lpfc_vport_set_state(struct lpfc_vport *vport, - enum fc_vport_state new_state) -{ - struct fc_vport *fc_vport = vport->fc_vport; - - if (fc_vport) { - /* - * When the transport defines fc_vport_set state we will replace - * this code with the following line - */ - /* fc_vport_set_state(fc_vport, new_state); */ - if (new_state != FC_VPORT_INITIALIZING) - fc_vport->vport_last_state = fc_vport->vport_state; - fc_vport->vport_state = new_state; - } - - /* for all the error states we will set the invternal state to FAILED */ - switch (new_state) { - case FC_VPORT_NO_FABRIC_SUPP: - case FC_VPORT_NO_FABRIC_RSCS: - case FC_VPORT_FABRIC_LOGOUT: - case FC_VPORT_FABRIC_REJ_WWN: - case FC_VPORT_FAILED: - vport->port_state = LPFC_VPORT_FAILED; - break; - case FC_VPORT_LINKDOWN: - vport->port_state = LPFC_VPORT_UNKNOWN; - break; - default: - /* do nothing */ - break; - } -} - -static int -lpfc_alloc_vpi(struct lpfc_hba *phba) -{ - unsigned long vpi; - - spin_lock_irq(&phba->hbalock); - /* Start at bit 1 because vpi zero is reserved for the physical port */ - vpi = find_next_zero_bit(phba->vpi_bmask, (phba->max_vpi + 1), 1); - if (vpi > phba->max_vpi) - vpi = 0; - else - set_bit(vpi, phba->vpi_bmask); - if (phba->sli_rev == LPFC_SLI_REV4) - phba->sli4_hba.max_cfg_param.vpi_used++; - spin_unlock_irq(&phba->hbalock); - return vpi; -} - -static void -lpfc_free_vpi(struct lpfc_hba *phba, int vpi) -{ - if (vpi == 0) - return; - spin_lock_irq(&phba->hbalock); - clear_bit(vpi, phba->vpi_bmask); - if (phba->sli_rev == LPFC_SLI_REV4) - phba->sli4_hba.max_cfg_param.vpi_used--; - spin_unlock_irq(&phba->hbalock); -} - -static int -lpfc_vport_sparm(struct lpfc_hba *phba, struct lpfc_vport *vport) -{ - LPFC_MBOXQ_t *pmb; - MAILBOX_t *mb; - struct lpfc_dmabuf *mp; - int rc; - - pmb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!pmb) { - return -ENOMEM; - } - mb = &pmb->u.mb; - - rc = lpfc_read_sparam(phba, pmb, vport->vpi); - if (rc) { - mempool_free(pmb, phba->mbox_mem_pool); - return -ENOMEM; - } - - /* - * Grab buffer pointer and clear context1 so we can use - * lpfc_sli_issue_box_wait - */ - mp = (struct lpfc_dmabuf *) pmb->context1; - pmb->context1 = NULL; - - pmb->vport = vport; - rc = lpfc_sli_issue_mbox_wait(phba, pmb, phba->fc_ratov * 2); - if (rc != MBX_SUCCESS) { - if (signal_pending(current)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, - "1830 Signal aborted mbxCmd x%x\n", - mb->mbxCommand); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - if (rc != MBX_TIMEOUT) - mempool_free(pmb, phba->mbox_mem_pool); - return -EINTR; - } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT | LOG_VPORT, - "1818 VPort failed init, mbxCmd x%x " - "READ_SPARM mbxStatus x%x, rc = x%x\n", - mb->mbxCommand, mb->mbxStatus, rc); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - if (rc != MBX_TIMEOUT) - mempool_free(pmb, phba->mbox_mem_pool); - return -EIO; - } - } - - memcpy(&vport->fc_sparam, mp->virt, sizeof (struct serv_parm)); - memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, - sizeof (struct lpfc_name)); - memcpy(&vport->fc_portname, &vport->fc_sparam.portName, - sizeof (struct lpfc_name)); - - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - - return 0; -} - -static int -lpfc_valid_wwn_format(struct lpfc_hba *phba, struct lpfc_name *wwn, - const char *name_type) -{ - /* ensure that IEEE format 1 addresses - * contain zeros in bits 59-48 - */ - if (!((wwn->u.wwn[0] >> 4) == 1 && - ((wwn->u.wwn[0] & 0xf) != 0 || (wwn->u.wwn[1] & 0xf) != 0))) - return 1; - - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, - "1822 Invalid %s: %02x:%02x:%02x:%02x:" - "%02x:%02x:%02x:%02x\n", - name_type, - wwn->u.wwn[0], wwn->u.wwn[1], - wwn->u.wwn[2], wwn->u.wwn[3], - wwn->u.wwn[4], wwn->u.wwn[5], - wwn->u.wwn[6], wwn->u.wwn[7]); - return 0; -} - -static int -lpfc_unique_wwpn(struct lpfc_hba *phba, struct lpfc_vport *new_vport) -{ - struct lpfc_vport *vport; - unsigned long flags; - - spin_lock_irqsave(&phba->hbalock, flags); - list_for_each_entry(vport, &phba->port_list, listentry) { - if (vport == new_vport) - continue; - /* If they match, return not unique */ - if (memcmp(&vport->fc_sparam.portName, - &new_vport->fc_sparam.portName, - sizeof(struct lpfc_name)) == 0) { - spin_unlock_irqrestore(&phba->hbalock, flags); - return 0; - } - } - spin_unlock_irqrestore(&phba->hbalock, flags); - return 1; -} - -/** - * lpfc_discovery_wait - Wait for driver discovery to quiesce - * @vport: The virtual port for which this call is being executed. - * - * This driver calls this routine specifically from lpfc_vport_delete - * to enforce a synchronous execution of vport - * delete relative to discovery activities. The - * lpfc_vport_delete routine should not return until it - * can reasonably guarantee that discovery has quiesced. - * Post FDISC LOGO, the driver must wait until its SAN teardown is - * complete and all resources recovered before allowing - * cleanup. - * - * This routine does not require any locks held. - **/ -static void lpfc_discovery_wait(struct lpfc_vport *vport) -{ - struct lpfc_hba *phba = vport->phba; - uint32_t wait_flags = 0; - unsigned long wait_time_max; - unsigned long start_time; - - wait_flags = FC_RSCN_MODE | FC_RSCN_DISCOVERY | FC_NLP_MORE | - FC_RSCN_DEFERRED | FC_NDISC_ACTIVE | FC_DISC_TMO; - - /* - * The time constraint on this loop is a balance between the - * fabric RA_TOV value and dev_loss tmo. The driver's - * devloss_tmo is 10 giving this loop a 3x multiplier minimally. - */ - wait_time_max = msecs_to_jiffies(((phba->fc_ratov * 3) + 3) * 1000); - wait_time_max += jiffies; - start_time = jiffies; - while (time_before(jiffies, wait_time_max)) { - if ((vport->num_disc_nodes > 0) || - (vport->fc_flag & wait_flags) || - ((vport->port_state > LPFC_VPORT_FAILED) && - (vport->port_state < LPFC_VPORT_READY))) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT, - "1833 Vport discovery quiesce Wait:" - " state x%x fc_flags x%x" - " num_nodes x%x, waiting 1000 msecs" - " total wait msecs x%x\n", - vport->port_state, vport->fc_flag, - vport->num_disc_nodes, - jiffies_to_msecs(jiffies - start_time)); - msleep(1000); - } else { - /* Base case. Wait variants satisfied. Break out */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_VPORT, - "1834 Vport discovery quiesced:" - " state x%x fc_flags x%x" - " wait msecs x%x\n", - vport->port_state, vport->fc_flag, - jiffies_to_msecs(jiffies - - start_time)); - break; - } - } - - if (time_after(jiffies, wait_time_max)) - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1835 Vport discovery quiesce failed:" - " state x%x fc_flags x%x wait msecs x%x\n", - vport->port_state, vport->fc_flag, - jiffies_to_msecs(jiffies - start_time)); -} - -int -lpfc_vport_create(struct fc_vport *fc_vport, bool disable) -{ - struct lpfc_nodelist *ndlp; - struct Scsi_Host *shost = fc_vport->shost; - struct lpfc_vport *pport = (struct lpfc_vport *) shost->hostdata; - struct lpfc_hba *phba = pport->phba; - struct lpfc_vport *vport = NULL; - int instance; - int vpi; - int rc = VPORT_ERROR; - int status; - - if ((phba->sli_rev < 3) || !(phba->cfg_enable_npiv)) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, - "1808 Create VPORT failed: " - "NPIV is not enabled: SLImode:%d\n", - phba->sli_rev); - rc = VPORT_INVAL; - goto error_out; - } - - vpi = lpfc_alloc_vpi(phba); - if (vpi == 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, - "1809 Create VPORT failed: " - "Max VPORTs (%d) exceeded\n", - phba->max_vpi); - rc = VPORT_NORESOURCES; - goto error_out; - } - - /* Assign an unused board number */ - if ((instance = lpfc_get_instance()) < 0) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, - "1810 Create VPORT failed: Cannot get " - "instance number\n"); - lpfc_free_vpi(phba, vpi); - rc = VPORT_NORESOURCES; - goto error_out; - } - - vport = lpfc_create_port(phba, instance, &fc_vport->dev); - if (!vport) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, - "1811 Create VPORT failed: vpi x%x\n", vpi); - lpfc_free_vpi(phba, vpi); - rc = VPORT_NORESOURCES; - goto error_out; - } - - vport->vpi = vpi; - lpfc_debugfs_initialize(vport); - - if ((status = lpfc_vport_sparm(phba, vport))) { - if (status == -EINTR) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1831 Create VPORT Interrupted.\n"); - rc = VPORT_ERROR; - } else { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1813 Create VPORT failed. " - "Cannot get sparam\n"); - rc = VPORT_NORESOURCES; - } - lpfc_free_vpi(phba, vpi); - destroy_port(vport); - goto error_out; - } - - u64_to_wwn(fc_vport->node_name, vport->fc_nodename.u.wwn); - u64_to_wwn(fc_vport->port_name, vport->fc_portname.u.wwn); - - memcpy(&vport->fc_sparam.portName, vport->fc_portname.u.wwn, 8); - memcpy(&vport->fc_sparam.nodeName, vport->fc_nodename.u.wwn, 8); - - if (!lpfc_valid_wwn_format(phba, &vport->fc_sparam.nodeName, "WWNN") || - !lpfc_valid_wwn_format(phba, &vport->fc_sparam.portName, "WWPN")) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1821 Create VPORT failed. " - "Invalid WWN format\n"); - lpfc_free_vpi(phba, vpi); - destroy_port(vport); - rc = VPORT_INVAL; - goto error_out; - } - - if (!lpfc_unique_wwpn(phba, vport)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1823 Create VPORT failed. " - "Duplicate WWN on HBA\n"); - lpfc_free_vpi(phba, vpi); - destroy_port(vport); - rc = VPORT_INVAL; - goto error_out; - } - - /* Create binary sysfs attribute for vport */ - lpfc_alloc_sysfs_attr(vport); - - *(struct lpfc_vport **)fc_vport->dd_data = vport; - vport->fc_vport = fc_vport; - - /* - * In SLI4, the vpi must be activated before it can be used - * by the port. - */ - if ((phba->sli_rev == LPFC_SLI_REV4) && - (pport->fc_flag & FC_VFI_REGISTERED)) { - rc = lpfc_sli4_init_vpi(vport); - if (rc) { - lpfc_printf_log(phba, KERN_ERR, LOG_VPORT, - "1838 Failed to INIT_VPI on vpi %d " - "status %d\n", vpi, rc); - rc = VPORT_NORESOURCES; - lpfc_free_vpi(phba, vpi); - goto error_out; - } - } else if (phba->sli_rev == LPFC_SLI_REV4) { - /* - * Driver cannot INIT_VPI now. Set the flags to - * init_vpi when reg_vfi complete. - */ - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); - rc = VPORT_OK; - goto out; - } - - if ((phba->link_state < LPFC_LINK_UP) || - (pport->port_state < LPFC_FABRIC_CFG_LINK) || - (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) { - lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); - rc = VPORT_OK; - goto out; - } - - if (disable) { - lpfc_vport_set_state(vport, FC_VPORT_DISABLED); - rc = VPORT_OK; - goto out; - } - - /* Use the Physical nodes Fabric NDLP to determine if the link is - * up and ready to FDISC. - */ - ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { - if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { - lpfc_set_disctmo(vport); - lpfc_initial_fdisc(vport); - } else { - lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0262 No NPIV Fabric support\n"); - } - } else { - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - } - rc = VPORT_OK; - -out: - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1825 Vport Created.\n"); - lpfc_host_attrib_init(lpfc_shost_from_vport(vport)); -error_out: - return rc; -} - -static int -disable_vport(struct fc_vport *fc_vport) -{ - struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; - struct lpfc_hba *phba = vport->phba; - struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - long timeout; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && phba->link_state >= LPFC_LINK_UP) { - vport->unreg_vpi_cmpl = VPORT_INVAL; - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_issue_els_npiv_logo(vport, ndlp)) - while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) - timeout = schedule_timeout(timeout); - } - - lpfc_sli_host_down(vport); - - /* Mark all nodes for discovery so we can remove them by - * calling lpfc_cleanup_rpis(vport, 1) - */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - continue; - lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - } - lpfc_cleanup_rpis(vport, 1); - - lpfc_stop_vport_timers(vport); - lpfc_unreg_all_rpis(vport); - lpfc_unreg_default_rpis(vport); - /* - * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) does the - * scsi_host_put() to release the vport. - */ - lpfc_mbx_unreg_vpi(vport); - spin_lock_irq(shost->host_lock); - vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; - spin_unlock_irq(shost->host_lock); - - lpfc_vport_set_state(vport, FC_VPORT_DISABLED); - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1826 Vport Disabled.\n"); - return VPORT_OK; -} - -static int -enable_vport(struct fc_vport *fc_vport) -{ - struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; - struct lpfc_hba *phba = vport->phba; - struct lpfc_nodelist *ndlp = NULL; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - - if ((phba->link_state < LPFC_LINK_UP) || - (phba->fc_topology == LPFC_TOPOLOGY_LOOP)) { - lpfc_vport_set_state(vport, FC_VPORT_LINKDOWN); - return VPORT_OK; - } - - spin_lock_irq(shost->host_lock); - vport->load_flag |= FC_LOADING; - vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; - spin_unlock_irq(shost->host_lock); - - /* Use the Physical nodes Fabric NDLP to determine if the link is - * up and ready to FDISC. - */ - ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - if (ndlp && NLP_CHK_NODE_ACT(ndlp) - && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { - if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) { - lpfc_set_disctmo(vport); - lpfc_initial_fdisc(vport); - } else { - lpfc_vport_set_state(vport, FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0264 No NPIV Fabric support\n"); - } - } else { - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - } - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1827 Vport Enabled.\n"); - return VPORT_OK; -} - -int -lpfc_vport_disable(struct fc_vport *fc_vport, bool disable) -{ - if (disable) - return disable_vport(fc_vport); - else - return enable_vport(fc_vport); -} - - -int -lpfc_vport_delete(struct fc_vport *fc_vport) -{ - struct lpfc_nodelist *ndlp = NULL; - struct Scsi_Host *shost = (struct Scsi_Host *) fc_vport->shost; - struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data; - struct lpfc_hba *phba = vport->phba; - long timeout; - - if (vport->port_type == LPFC_PHYSICAL_PORT) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1812 vport_delete failed: Cannot delete " - "physical host\n"); - return VPORT_ERROR; - } - - /* If the vport is a static vport fail the deletion. */ - if ((vport->vport_flag & STATIC_VPORT) && - !(phba->pport->load_flag & FC_UNLOADING)) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1837 vport_delete failed: Cannot delete " - "static vport.\n"); - return VPORT_ERROR; - } - spin_lock_irq(&phba->hbalock); - vport->load_flag |= FC_UNLOADING; - spin_unlock_irq(&phba->hbalock); - /* - * If we are not unloading the driver then prevent the vport_delete - * from happening until after this vport's discovery is finished. - */ - if (!(phba->pport->load_flag & FC_UNLOADING)) { - int check_count = 0; - while (check_count < ((phba->fc_ratov * 3) + 3) && - vport->port_state > LPFC_VPORT_FAILED && - vport->port_state < LPFC_VPORT_READY) { - check_count++; - msleep(1000); - } - if (vport->port_state > LPFC_VPORT_FAILED && - vport->port_state < LPFC_VPORT_READY) - return -EAGAIN; - } - /* - * This is a bit of a mess. We want to ensure the shost doesn't get - * torn down until we're done with the embedded lpfc_vport structure. - * - * Beyond holding a reference for this function, we also need a - * reference for outstanding I/O requests we schedule during delete - * processing. But once we scsi_remove_host() we can no longer obtain - * a reference through scsi_host_get(). - * - * So we take two references here. We release one reference at the - * bottom of the function -- after delinking the vport. And we - * release the other at the completion of the unreg_vpi that get's - * initiated after we've disposed of all other resources associated - * with the port. - */ - if (!scsi_host_get(shost)) - return VPORT_INVAL; - if (!scsi_host_get(shost)) { - scsi_host_put(shost); - return VPORT_INVAL; - } - lpfc_free_sysfs_attr(vport); - - lpfc_debugfs_terminate(vport); - - /* Remove FC host and then SCSI host with the vport */ - fc_remove_host(lpfc_shost_from_vport(vport)); - scsi_remove_host(lpfc_shost_from_vport(vport)); - - ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); - - /* In case of driver unload, we shall not perform fabric logo as the - * worker thread already stopped at this stage and, in this case, we - * can safely skip the fabric logo. - */ - if (phba->pport->load_flag & FC_UNLOADING) { - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && - phba->link_state >= LPFC_LINK_UP) { - /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) - goto skip_logo; - else if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto skip_logo; - } - /* Remove ndlp from vport npld list */ - lpfc_dequeue_node(vport, ndlp); - - /* Indicate free memory when release */ - spin_lock_irq(&phba->ndlp_lock); - NLP_SET_FREE_REQ(ndlp); - spin_unlock_irq(&phba->ndlp_lock); - /* Kick off release ndlp when it can be safely done */ - lpfc_nlp_put(ndlp); - } - goto skip_logo; - } - - /* Otherwise, we will perform fabric logo as needed */ - if (ndlp && NLP_CHK_NODE_ACT(ndlp) && - ndlp->nlp_state == NLP_STE_UNMAPPED_NODE && - phba->link_state >= LPFC_LINK_UP && - phba->fc_topology != LPFC_TOPOLOGY_LOOP) { - if (vport->cfg_enable_da_id) { - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_ns_cmd(vport, SLI_CTNS_DA_ID, 0, 0)) - while (vport->ct_flags && timeout) - timeout = schedule_timeout(timeout); - else - lpfc_printf_log(vport->phba, KERN_WARNING, - LOG_VPORT, - "1829 CT command failed to " - "delete objects on fabric\n"); - } - /* First look for the Fabric ndlp */ - ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) { - /* Cannot find existing Fabric ndlp, allocate one */ - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) - goto skip_logo; - lpfc_nlp_init(vport, ndlp, Fabric_DID); - /* Indicate free memory when release */ - NLP_SET_FREE_REQ(ndlp); - } else { - if (!NLP_CHK_NODE_ACT(ndlp)) { - ndlp = lpfc_enable_node(vport, ndlp, - NLP_STE_UNUSED_NODE); - if (!ndlp) - goto skip_logo; - } - - /* Remove ndlp from vport list */ - lpfc_dequeue_node(vport, ndlp); - spin_lock_irq(&phba->ndlp_lock); - if (!NLP_CHK_FREE_REQ(ndlp)) - /* Indicate free memory when release */ - NLP_SET_FREE_REQ(ndlp); - else { - /* Skip this if ndlp is already in free mode */ - spin_unlock_irq(&phba->ndlp_lock); - goto skip_logo; - } - spin_unlock_irq(&phba->ndlp_lock); - } - - /* - * If the vpi is not registered, then a valid FDISC doesn't - * exist and there is no need for a ELS LOGO. Just cleanup - * the ndlp. - */ - if (!(vport->vpi_state & LPFC_VPI_REGISTERED)) { - lpfc_nlp_put(ndlp); - goto skip_logo; - } - - vport->unreg_vpi_cmpl = VPORT_INVAL; - timeout = msecs_to_jiffies(phba->fc_ratov * 2000); - if (!lpfc_issue_els_npiv_logo(vport, ndlp)) - while (vport->unreg_vpi_cmpl == VPORT_INVAL && timeout) - timeout = schedule_timeout(timeout); - } - - if (!(phba->pport->load_flag & FC_UNLOADING)) - lpfc_discovery_wait(vport); - -skip_logo: - lpfc_cleanup(vport); - lpfc_sli_host_down(vport); - - lpfc_stop_vport_timers(vport); - - if (!(phba->pport->load_flag & FC_UNLOADING)) { - lpfc_unreg_all_rpis(vport); - lpfc_unreg_default_rpis(vport); - /* - * Completion of unreg_vpi (lpfc_mbx_cmpl_unreg_vpi) - * does the scsi_host_put() to release the vport. - */ - if (lpfc_mbx_unreg_vpi(vport)) - scsi_host_put(shost); - } else - scsi_host_put(shost); - - lpfc_free_vpi(phba, vport->vpi); - vport->work_port_events = 0; - spin_lock_irq(&phba->hbalock); - list_del_init(&vport->listentry); - spin_unlock_irq(&phba->hbalock); - lpfc_printf_vlog(vport, KERN_ERR, LOG_VPORT, - "1828 Vport Deleted.\n"); - scsi_host_put(shost); - return VPORT_OK; -} - -struct lpfc_vport ** -lpfc_create_vport_work_array(struct lpfc_hba *phba) -{ - struct lpfc_vport *port_iterator; - struct lpfc_vport **vports; - int index = 0; - vports = kzalloc((phba->max_vports + 1) * sizeof(struct lpfc_vport *), - GFP_KERNEL); - if (vports == NULL) - return NULL; - spin_lock_irq(&phba->hbalock); - list_for_each_entry(port_iterator, &phba->port_list, listentry) { - if (port_iterator->load_flag & FC_UNLOADING) - continue; - if (!scsi_host_get(lpfc_shost_from_vport(port_iterator))) { - lpfc_printf_vlog(port_iterator, KERN_ERR, LOG_VPORT, - "1801 Create vport work array FAILED: " - "cannot do scsi_host_get\n"); - continue; - } - vports[index++] = port_iterator; - } - spin_unlock_irq(&phba->hbalock); - return vports; -} - -void -lpfc_destroy_vport_work_array(struct lpfc_hba *phba, struct lpfc_vport **vports) -{ - int i; - if (vports == NULL) - return; - for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) - scsi_host_put(lpfc_shost_from_vport(vports[i])); - kfree(vports); -} - - -/** - * lpfc_vport_reset_stat_data - Reset the statistical data for the vport - * @vport: Pointer to vport object. - * - * This function resets the statistical data for the vport. This function - * is called with the host_lock held - **/ -void -lpfc_vport_reset_stat_data(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->lat_data) - memset(ndlp->lat_data, 0, LPFC_MAX_BUCKET_COUNT * - sizeof(struct lpfc_scsicmd_bkt)); - } -} - - -/** - * lpfc_alloc_bucket - Allocate data buffer required for statistical data - * @vport: Pointer to vport object. - * - * This function allocates data buffer required for all the FC - * nodes of the vport to collect statistical data. - **/ -void -lpfc_alloc_bucket(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - - kfree(ndlp->lat_data); - ndlp->lat_data = NULL; - - if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) { - ndlp->lat_data = kcalloc(LPFC_MAX_BUCKET_COUNT, - sizeof(struct lpfc_scsicmd_bkt), - GFP_ATOMIC); - - if (!ndlp->lat_data) - lpfc_printf_vlog(vport, KERN_ERR, LOG_NODE, - "0287 lpfc_alloc_bucket failed to " - "allocate statistical data buffer DID " - "0x%x\n", ndlp->nlp_DID); - } - } -} - -/** - * lpfc_free_bucket - Free data buffer required for statistical data - * @vport: Pointer to vport object. - * - * Th function frees statistical data buffer of all the FC - * nodes of the vport. - **/ -void -lpfc_free_bucket(struct lpfc_vport *vport) -{ - struct lpfc_nodelist *ndlp = NULL, *next_ndlp = NULL; - - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - - kfree(ndlp->lat_data); - ndlp->lat_data = NULL; - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.h b/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.h deleted file mode 100644 index 90828340..00000000 --- a/ANDROID_3.4.5/drivers/scsi/lpfc/lpfc_vport.h +++ /dev/null @@ -1,119 +0,0 @@ -/******************************************************************* - * This file is part of the Emulex Linux Device Driver for * - * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2006 Emulex. All rights reserved. * - * EMULEX and SLI are trademarks of Emulex. * - * www.emulex.com * - * Portions Copyright (C) 2004-2005 Christoph Hellwig * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of version 2 of the GNU General * - * Public License as published by the Free Software Foundation. * - * This program is distributed in the hope that it will be useful. * - * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND * - * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, * - * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE * - * DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD * - * TO BE LEGALLY INVALID. See the GNU General Public License for * - * more details, a copy of which can be found in the file COPYING * - * included with this package. * - *******************************************************************/ - -#ifndef _H_LPFC_VPORT -#define _H_LPFC_VPORT - -/* API version values (each will be an individual bit) */ -#define VPORT_API_VERSION_1 0x01 - -/* Values returned via lpfc_vport_getinfo() */ -struct vport_info { - - uint32_t api_versions; - uint8_t linktype; -#define VPORT_TYPE_PHYSICAL 0 -#define VPORT_TYPE_VIRTUAL 1 - - uint8_t state; -#define VPORT_STATE_OFFLINE 0 -#define VPORT_STATE_ACTIVE 1 -#define VPORT_STATE_FAILED 2 - - uint8_t fail_reason; - uint8_t prev_fail_reason; -#define VPORT_FAIL_UNKNOWN 0 -#define VPORT_FAIL_LINKDOWN 1 -#define VPORT_FAIL_FAB_UNSUPPORTED 2 -#define VPORT_FAIL_FAB_NORESOURCES 3 -#define VPORT_FAIL_FAB_LOGOUT 4 -#define VPORT_FAIL_ADAP_NORESOURCES 5 - - uint8_t node_name[8]; /* WWNN */ - uint8_t port_name[8]; /* WWPN */ - - struct Scsi_Host *shost; - -/* Following values are valid only on physical links */ - uint32_t vports_max; - uint32_t vports_inuse; - uint32_t rpi_max; - uint32_t rpi_inuse; -#define VPORT_CNT_INVALID 0xFFFFFFFF -}; - -/* data used in link creation */ -struct vport_data { - uint32_t api_version; - - uint32_t options; -#define VPORT_OPT_AUTORETRY 0x01 - - uint8_t node_name[8]; /* WWNN */ - uint8_t port_name[8]; /* WWPN */ - -/* - * Upon successful creation, vport_shost will point to the new Scsi_Host - * structure for the new virtual link. - */ - struct Scsi_Host *vport_shost; -}; - -/* API function return codes */ -#define VPORT_OK 0 -#define VPORT_ERROR -1 -#define VPORT_INVAL -2 -#define VPORT_NOMEM -3 -#define VPORT_NORESOURCES -4 - -int lpfc_vport_create(struct fc_vport *, bool); -int lpfc_vport_delete(struct fc_vport *); -int lpfc_vport_getinfo(struct Scsi_Host *, struct vport_info *); -int lpfc_vport_tgt_remove(struct Scsi_Host *, uint, uint); -struct lpfc_vport **lpfc_create_vport_work_array(struct lpfc_hba *); -void lpfc_destroy_vport_work_array(struct lpfc_hba *, struct lpfc_vport **); - -/* - * queuecommand VPORT-specific return codes. Specified in the host byte code. - * Returned when the virtual link has failed or is not active. - */ -#define DID_VPORT_ERROR 0x0f - -#define VPORT_INFO 0x1 -#define VPORT_CREATE 0x2 -#define VPORT_DELETE 0x4 - -struct vport_cmd_tag { - uint32_t cmd; - struct vport_data cdata; - struct vport_info cinfo; - void *vport; - int vport_num; -}; - -void lpfc_vport_set_state(struct lpfc_vport *vport, - enum fc_vport_state new_state); - -void lpfc_vport_reset_stat_data(struct lpfc_vport *); -void lpfc_alloc_bucket(struct lpfc_vport *); -void lpfc_free_bucket(struct lpfc_vport *); - -#endif /* H_LPFC_VPORT */ diff --git a/ANDROID_3.4.5/drivers/scsi/mac53c94.c b/ANDROID_3.4.5/drivers/scsi/mac53c94.c deleted file mode 100644 index e5cd8d8d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mac53c94.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * SCSI low-level driver for the 53c94 SCSI bus adaptor found - * on Power Macintosh computers, controlling the external SCSI chain. - * We assume the 53c94 is connected to a DBDMA (descriptor-based DMA) - * controller. - * - * Paul Mackerras, August 1996. - * Copyright (C) 1996 Paul Mackerras. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "mac53c94.h" - -enum fsc_phase { - idle, - selecting, - dataing, - completing, - busfreeing, -}; - -struct fsc_state { - struct mac53c94_regs __iomem *regs; - int intr; - struct dbdma_regs __iomem *dma; - int dmaintr; - int clk_freq; - struct Scsi_Host *host; - struct scsi_cmnd *request_q; - struct scsi_cmnd *request_qtail; - struct scsi_cmnd *current_req; /* req we're currently working on */ - enum fsc_phase phase; /* what we're currently trying to do */ - struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */ - void *dma_cmd_space; - struct pci_dev *pdev; - dma_addr_t dma_addr; - struct macio_dev *mdev; -}; - -static void mac53c94_init(struct fsc_state *); -static void mac53c94_start(struct fsc_state *); -static void mac53c94_interrupt(int, void *); -static irqreturn_t do_mac53c94_interrupt(int, void *); -static void cmd_done(struct fsc_state *, int result); -static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *); - - -static int mac53c94_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct fsc_state *state; - -#if 0 - if (cmd->sc_data_direction == DMA_TO_DEVICE) { - int i; - printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd); - for (i = 0; i < cmd->cmd_len; ++i) - printk(KERN_CONT " %.2x", cmd->cmnd[i]); - printk(KERN_CONT "\n"); - printk(KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n", - scsi_sg_count(cmd), scsi_bufflen(cmd), scsi_sglist(cmd)); - } -#endif - - cmd->scsi_done = done; - cmd->host_scribble = NULL; - - state = (struct fsc_state *) cmd->device->host->hostdata; - - if (state->request_q == NULL) - state->request_q = cmd; - else - state->request_qtail->host_scribble = (void *) cmd; - state->request_qtail = cmd; - - if (state->phase == idle) - mac53c94_start(state); - - return 0; -} - -static DEF_SCSI_QCMD(mac53c94_queue) - -static int mac53c94_host_reset(struct scsi_cmnd *cmd) -{ - struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata; - struct mac53c94_regs __iomem *regs = state->regs; - struct dbdma_regs __iomem *dma = state->dma; - unsigned long flags; - - spin_lock_irqsave(cmd->device->host->host_lock, flags); - - writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control); - writeb(CMD_SCSI_RESET, ®s->command); /* assert RST */ - udelay(100); /* leave it on for a while (>= 25us) */ - writeb(CMD_RESET, ®s->command); - udelay(20); - mac53c94_init(state); - writeb(CMD_NOP, ®s->command); - - spin_unlock_irqrestore(cmd->device->host->host_lock, flags); - return SUCCESS; -} - -static void mac53c94_init(struct fsc_state *state) -{ - struct mac53c94_regs __iomem *regs = state->regs; - struct dbdma_regs __iomem *dma = state->dma; - int x; - - writeb(state->host->this_id | CF1_PAR_ENABLE, ®s->config1); - writeb(TIMO_VAL(250), ®s->sel_timeout); /* 250ms */ - writeb(CLKF_VAL(state->clk_freq), ®s->clk_factor); - writeb(CF2_FEATURE_EN, ®s->config2); - writeb(0, ®s->config3); - writeb(0, ®s->sync_period); - writeb(0, ®s->sync_offset); - x = readb(®s->interrupt); - writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control); -} - -/* - * Start the next command for a 53C94. - * Should be called with interrupts disabled. - */ -static void mac53c94_start(struct fsc_state *state) -{ - struct scsi_cmnd *cmd; - struct mac53c94_regs __iomem *regs = state->regs; - int i; - - if (state->phase != idle || state->current_req != NULL) - panic("inappropriate mac53c94_start (state=%p)", state); - if (state->request_q == NULL) - return; - state->current_req = cmd = state->request_q; - state->request_q = (struct scsi_cmnd *) cmd->host_scribble; - - /* Off we go */ - writeb(0, ®s->count_lo); - writeb(0, ®s->count_mid); - writeb(0, ®s->count_hi); - writeb(CMD_NOP + CMD_DMA_MODE, ®s->command); - udelay(1); - writeb(CMD_FLUSH, ®s->command); - udelay(1); - writeb(cmd->device->id, ®s->dest_id); - writeb(0, ®s->sync_period); - writeb(0, ®s->sync_offset); - - /* load the command into the FIFO */ - for (i = 0; i < cmd->cmd_len; ++i) - writeb(cmd->cmnd[i], ®s->fifo); - - /* do select without ATN XXX */ - writeb(CMD_SELECT, ®s->command); - state->phase = selecting; - - set_dma_cmds(state, cmd); -} - -static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host; - - spin_lock_irqsave(dev->host_lock, flags); - mac53c94_interrupt(irq, dev_id); - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} - -static void mac53c94_interrupt(int irq, void *dev_id) -{ - struct fsc_state *state = (struct fsc_state *) dev_id; - struct mac53c94_regs __iomem *regs = state->regs; - struct dbdma_regs __iomem *dma = state->dma; - struct scsi_cmnd *cmd = state->current_req; - int nb, stat, seq, intr; - static int mac53c94_errors; - - /* - * Apparently, reading the interrupt register unlatches - * the status and sequence step registers. - */ - seq = readb(®s->seqstep); - stat = readb(®s->status); - intr = readb(®s->interrupt); - -#if 0 - printk(KERN_DEBUG "mac53c94_intr, intr=%x stat=%x seq=%x phase=%d\n", - intr, stat, seq, state->phase); -#endif - - if (intr & INTR_RESET) { - /* SCSI bus was reset */ - printk(KERN_INFO "external SCSI bus reset detected\n"); - writeb(CMD_NOP, ®s->command); - writel(RUN << 16, &dma->control); /* stop dma */ - cmd_done(state, DID_RESET << 16); - return; - } - if (intr & INTR_ILL_CMD) { - printk(KERN_ERR "53c94: invalid cmd, intr=%x stat=%x seq=%x phase=%d\n", - intr, stat, seq, state->phase); - cmd_done(state, DID_ERROR << 16); - return; - } - if (stat & STAT_ERROR) { -#if 0 - /* XXX these seem to be harmless? */ - printk("53c94: bad error, intr=%x stat=%x seq=%x phase=%d\n", - intr, stat, seq, state->phase); -#endif - ++mac53c94_errors; - writeb(CMD_NOP + CMD_DMA_MODE, ®s->command); - } - if (cmd == 0) { - printk(KERN_DEBUG "53c94: interrupt with no command active?\n"); - return; - } - if (stat & STAT_PARITY) { - printk(KERN_ERR "mac53c94: parity error\n"); - cmd_done(state, DID_PARITY << 16); - return; - } - switch (state->phase) { - case selecting: - if (intr & INTR_DISCONNECT) { - /* selection timed out */ - cmd_done(state, DID_BAD_TARGET << 16); - return; - } - if (intr != INTR_BUS_SERV + INTR_DONE) { - printk(KERN_DEBUG "got intr %x during selection\n", intr); - cmd_done(state, DID_ERROR << 16); - return; - } - if ((seq & SS_MASK) != SS_DONE) { - printk(KERN_DEBUG "seq step %x after command\n", seq); - cmd_done(state, DID_ERROR << 16); - return; - } - writeb(CMD_NOP, ®s->command); - /* set DMA controller going if any data to transfer */ - if ((stat & (STAT_MSG|STAT_CD)) == 0 - && (scsi_sg_count(cmd) > 0 || scsi_bufflen(cmd))) { - nb = cmd->SCp.this_residual; - if (nb > 0xfff0) - nb = 0xfff0; - cmd->SCp.this_residual -= nb; - writeb(nb, ®s->count_lo); - writeb(nb >> 8, ®s->count_mid); - writeb(CMD_DMA_MODE + CMD_NOP, ®s->command); - writel(virt_to_phys(state->dma_cmds), &dma->cmdptr); - writel((RUN << 16) | RUN, &dma->control); - writeb(CMD_DMA_MODE + CMD_XFER_DATA, ®s->command); - state->phase = dataing; - break; - } else if ((stat & STAT_PHASE) == STAT_CD + STAT_IO) { - /* up to status phase already */ - writeb(CMD_I_COMPLETE, ®s->command); - state->phase = completing; - } else { - printk(KERN_DEBUG "in unexpected phase %x after cmd\n", - stat & STAT_PHASE); - cmd_done(state, DID_ERROR << 16); - return; - } - break; - - case dataing: - if (intr != INTR_BUS_SERV) { - printk(KERN_DEBUG "got intr %x before status\n", intr); - cmd_done(state, DID_ERROR << 16); - return; - } - if (cmd->SCp.this_residual != 0 - && (stat & (STAT_MSG|STAT_CD)) == 0) { - /* Set up the count regs to transfer more */ - nb = cmd->SCp.this_residual; - if (nb > 0xfff0) - nb = 0xfff0; - cmd->SCp.this_residual -= nb; - writeb(nb, ®s->count_lo); - writeb(nb >> 8, ®s->count_mid); - writeb(CMD_DMA_MODE + CMD_NOP, ®s->command); - writeb(CMD_DMA_MODE + CMD_XFER_DATA, ®s->command); - break; - } - if ((stat & STAT_PHASE) != STAT_CD + STAT_IO) { - printk(KERN_DEBUG "intr %x before data xfer complete\n", intr); - } - writel(RUN << 16, &dma->control); /* stop dma */ - scsi_dma_unmap(cmd); - /* should check dma status */ - writeb(CMD_I_COMPLETE, ®s->command); - state->phase = completing; - break; - case completing: - if (intr != INTR_DONE) { - printk(KERN_DEBUG "got intr %x on completion\n", intr); - cmd_done(state, DID_ERROR << 16); - return; - } - cmd->SCp.Status = readb(®s->fifo); - cmd->SCp.Message = readb(®s->fifo); - cmd->result = CMD_ACCEPT_MSG; - writeb(CMD_ACCEPT_MSG, ®s->command); - state->phase = busfreeing; - break; - case busfreeing: - if (intr != INTR_DISCONNECT) { - printk(KERN_DEBUG "got intr %x when expected disconnect\n", intr); - } - cmd_done(state, (DID_OK << 16) + (cmd->SCp.Message << 8) - + cmd->SCp.Status); - break; - default: - printk(KERN_DEBUG "don't know about phase %d\n", state->phase); - } -} - -static void cmd_done(struct fsc_state *state, int result) -{ - struct scsi_cmnd *cmd; - - cmd = state->current_req; - if (cmd != 0) { - cmd->result = result; - (*cmd->scsi_done)(cmd); - state->current_req = NULL; - } - state->phase = idle; - mac53c94_start(state); -} - -/* - * Set up DMA commands for transferring data. - */ -static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd) -{ - int i, dma_cmd, total, nseg; - struct scatterlist *scl; - struct dbdma_cmd *dcmds; - dma_addr_t dma_addr; - u32 dma_len; - - nseg = scsi_dma_map(cmd); - BUG_ON(nseg < 0); - if (!nseg) - return; - - dma_cmd = cmd->sc_data_direction == DMA_TO_DEVICE ? - OUTPUT_MORE : INPUT_MORE; - dcmds = state->dma_cmds; - total = 0; - - scsi_for_each_sg(cmd, scl, nseg, i) { - dma_addr = sg_dma_address(scl); - dma_len = sg_dma_len(scl); - if (dma_len > 0xffff) - panic("mac53c94: scatterlist element >= 64k"); - total += dma_len; - st_le16(&dcmds->req_count, dma_len); - st_le16(&dcmds->command, dma_cmd); - st_le32(&dcmds->phy_addr, dma_addr); - dcmds->xfer_status = 0; - ++dcmds; - } - - dma_cmd += OUTPUT_LAST - OUTPUT_MORE; - st_le16(&dcmds[-1].command, dma_cmd); - st_le16(&dcmds->command, DBDMA_STOP); - cmd->SCp.this_residual = total; -} - -static struct scsi_host_template mac53c94_template = { - .proc_name = "53c94", - .name = "53C94", - .queuecommand = mac53c94_queue, - .eh_host_reset_handler = mac53c94_host_reset, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; - -static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match) -{ - struct device_node *node = macio_get_of_node(mdev); - struct pci_dev *pdev = macio_get_pci_dev(mdev); - struct fsc_state *state; - struct Scsi_Host *host; - void *dma_cmd_space; - const unsigned char *clkprop; - int proplen, rc = -ENODEV; - - if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) { - printk(KERN_ERR "mac53c94: expected 2 addrs and intrs" - " (got %d/%d)\n", - macio_resource_count(mdev), macio_irq_count(mdev)); - return -ENODEV; - } - - if (macio_request_resources(mdev, "mac53c94") != 0) { - printk(KERN_ERR "mac53c94: unable to request memory resources"); - return -EBUSY; - } - - host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state)); - if (host == NULL) { - printk(KERN_ERR "mac53c94: couldn't register host"); - rc = -ENOMEM; - goto out_release; - } - - state = (struct fsc_state *) host->hostdata; - macio_set_drvdata(mdev, state); - state->host = host; - state->pdev = pdev; - state->mdev = mdev; - - state->regs = (struct mac53c94_regs __iomem *) - ioremap(macio_resource_start(mdev, 0), 0x1000); - state->intr = macio_irq(mdev, 0); - state->dma = (struct dbdma_regs __iomem *) - ioremap(macio_resource_start(mdev, 1), 0x1000); - state->dmaintr = macio_irq(mdev, 1); - if (state->regs == NULL || state->dma == NULL) { - printk(KERN_ERR "mac53c94: ioremap failed for %s\n", - node->full_name); - goto out_free; - } - - clkprop = of_get_property(node, "clock-frequency", &proplen); - if (clkprop == NULL || proplen != sizeof(int)) { - printk(KERN_ERR "%s: can't get clock frequency, " - "assuming 25MHz\n", node->full_name); - state->clk_freq = 25000000; - } else - state->clk_freq = *(int *)clkprop; - - /* Space for dma command list: +1 for stop command, - * +1 to allow for aligning. - * XXX FIXME: Use DMA consistent routines - */ - dma_cmd_space = kmalloc((host->sg_tablesize + 2) * - sizeof(struct dbdma_cmd), GFP_KERNEL); - if (dma_cmd_space == 0) { - printk(KERN_ERR "mac53c94: couldn't allocate dma " - "command space for %s\n", node->full_name); - rc = -ENOMEM; - goto out_free; - } - state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space); - memset(state->dma_cmds, 0, (host->sg_tablesize + 1) - * sizeof(struct dbdma_cmd)); - state->dma_cmd_space = dma_cmd_space; - - mac53c94_init(state); - - if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94",state)) { - printk(KERN_ERR "mac53C94: can't get irq %d for %s\n", - state->intr, node->full_name); - goto out_free_dma; - } - - rc = scsi_add_host(host, &mdev->ofdev.dev); - if (rc != 0) - goto out_release_irq; - - scsi_scan_host(host); - return 0; - - out_release_irq: - free_irq(state->intr, state); - out_free_dma: - kfree(state->dma_cmd_space); - out_free: - if (state->dma != NULL) - iounmap(state->dma); - if (state->regs != NULL) - iounmap(state->regs); - scsi_host_put(host); - out_release: - macio_release_resources(mdev); - - return rc; -} - -static int mac53c94_remove(struct macio_dev *mdev) -{ - struct fsc_state *fp = (struct fsc_state *)macio_get_drvdata(mdev); - struct Scsi_Host *host = fp->host; - - scsi_remove_host(host); - - free_irq(fp->intr, fp); - - if (fp->regs) - iounmap(fp->regs); - if (fp->dma) - iounmap(fp->dma); - kfree(fp->dma_cmd_space); - - scsi_host_put(host); - - macio_release_resources(mdev); - - return 0; -} - - -static struct of_device_id mac53c94_match[] = -{ - { - .name = "53c94", - }, - {}, -}; -MODULE_DEVICE_TABLE (of, mac53c94_match); - -static struct macio_driver mac53c94_driver = -{ - .driver = { - .name = "mac53c94", - .owner = THIS_MODULE, - .of_match_table = mac53c94_match, - }, - .probe = mac53c94_probe, - .remove = mac53c94_remove, -}; - - -static int __init init_mac53c94(void) -{ - return macio_register_driver(&mac53c94_driver); -} - -static void __exit exit_mac53c94(void) -{ - return macio_unregister_driver(&mac53c94_driver); -} - -module_init(init_mac53c94); -module_exit(exit_mac53c94); - -MODULE_DESCRIPTION("PowerMac 53c94 SCSI driver"); -MODULE_AUTHOR("Paul Mackerras "); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/mac53c94.h b/ANDROID_3.4.5/drivers/scsi/mac53c94.h deleted file mode 100644 index 1ad24e4f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mac53c94.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * mac53c94.h: definitions for the driver for the 53c94 SCSI bus adaptor - * found on Power Macintosh computers, controlling the external SCSI chain. - * - * Copyright (C) 1996 Paul Mackerras. - */ -#ifndef _MAC53C94_H -#define _MAC53C94_H - -/* - * Registers in the 53C94 controller. - */ - -struct mac53c94_regs { - unsigned char count_lo; - char pad0[15]; - unsigned char count_mid; - char pad1[15]; - unsigned char fifo; - char pad2[15]; - unsigned char command; - char pad3[15]; - unsigned char status; - char pad4[15]; - unsigned char interrupt; - char pad5[15]; - unsigned char seqstep; - char pad6[15]; - unsigned char flags; - char pad7[15]; - unsigned char config1; - char pad8[15]; - unsigned char clk_factor; - char pad9[15]; - unsigned char test; - char pad10[15]; - unsigned char config2; - char pad11[15]; - unsigned char config3; - char pad12[15]; - unsigned char config4; - char pad13[15]; - unsigned char count_hi; - char pad14[15]; - unsigned char fifo_res; - char pad15[15]; -}; - -/* - * Alternate functions for some registers. - */ -#define dest_id status -#define sel_timeout interrupt -#define sync_period seqstep -#define sync_offset flags - -/* - * Bits in command register. - */ -#define CMD_DMA_MODE 0x80 -#define CMD_MODE_MASK 0x70 -#define CMD_MODE_INIT 0x10 -#define CMD_MODE_TARG 0x20 -#define CMD_MODE_DISC 0x40 - -#define CMD_NOP 0 -#define CMD_FLUSH 1 -#define CMD_RESET 2 -#define CMD_SCSI_RESET 3 - -#define CMD_XFER_DATA 0x10 -#define CMD_I_COMPLETE 0x11 -#define CMD_ACCEPT_MSG 0x12 -#define CMD_XFER_PAD 0x18 -#define CMD_SET_ATN 0x1a -#define CMD_CLR_ATN 0x1b - -#define CMD_SEND_MSG 0x20 -#define CMD_SEND_STATUS 0x21 -#define CMD_SEND_DATA 0x22 -#define CMD_DISC_SEQ 0x23 -#define CMD_TERMINATE 0x24 -#define CMD_T_COMPLETE 0x25 -#define CMD_DISCONNECT 0x27 -#define CMD_RECV_MSG 0x28 -#define CMD_RECV_CDB 0x29 -#define CMD_RECV_DATA 0x2a -#define CMD_RECV_CMD 0x2b -#define CMD_ABORT_DMA 0x04 - -#define CMD_RESELECT 0x40 -#define CMD_SELECT 0x41 -#define CMD_SELECT_ATN 0x42 -#define CMD_SELATN_STOP 0x43 -#define CMD_ENABLE_SEL 0x44 -#define CMD_DISABLE_SEL 0x45 -#define CMD_SEL_ATN3 0x46 -#define CMD_RESEL_ATN3 0x47 - -/* - * Bits in status register. - */ -#define STAT_IRQ 0x80 -#define STAT_ERROR 0x40 -#define STAT_PARITY 0x20 -#define STAT_TC_ZERO 0x10 -#define STAT_DONE 0x08 -#define STAT_PHASE 0x07 -#define STAT_MSG 0x04 -#define STAT_CD 0x02 -#define STAT_IO 0x01 - -/* - * Bits in interrupt register. - */ -#define INTR_RESET 0x80 /* SCSI bus was reset */ -#define INTR_ILL_CMD 0x40 /* illegal command */ -#define INTR_DISCONNECT 0x20 /* we got disconnected */ -#define INTR_BUS_SERV 0x10 /* bus service requested */ -#define INTR_DONE 0x08 /* function completed */ -#define INTR_RESELECTED 0x04 /* we were reselected */ -#define INTR_SEL_ATN 0x02 /* we were selected, ATN asserted */ -#define INTR_SELECT 0x01 /* we were selected, ATN negated */ - -/* - * Encoding for the select timeout. - */ -#define TIMO_VAL(x) ((x) * 5000 / 7682) - -/* - * Bits in sequence step register. - */ -#define SS_MASK 7 -#define SS_ARB_SEL 0 /* Selection & arbitration complete */ -#define SS_MSG_SENT 1 /* One message byte sent */ -#define SS_NOT_CMD 2 /* Not in command phase */ -#define SS_PHASE_CHG 3 /* Early phase change, cmd bytes lost */ -#define SS_DONE 4 /* Command was sent OK */ - -/* - * Encoding for sync transfer period. - */ -#define SYNCP_MASK 0x1f -#define SYNCP_MIN 4 -#define SYNCP_MAX 31 - -/* - * Bits in flags register. - */ -#define FLAGS_FIFO_LEV 0x1f -#define FLAGS_SEQ_STEP 0xe0 - -/* - * Encoding for sync offset. - */ -#define SYNCO_MASK 0x0f -#define SYNCO_ASS_CTRL 0x30 /* REQ/ACK assertion control */ -#define SYNCO_NEG_CTRL 0xc0 /* REQ/ACK negation control */ - -/* - * Bits in config1 register. - */ -#define CF1_SLOW_CABLE 0x80 /* Slow cable mode */ -#define CF1_NO_RES_REP 0x40 /* Disable SCSI reset reports */ -#define CF1_PAR_TEST 0x20 /* Parity test mode enable */ -#define CF1_PAR_ENABLE 0x10 /* Enable parity checks */ -#define CF1_TEST 0x08 /* Chip tests */ -#define CF1_MY_ID 0x07 /* Controller's address on bus */ - -/* - * Encoding for clk_factor register. - */ -#define CLKF_MASK 7 -#define CLKF_VAL(freq) ((((freq) + 4999999) / 5000000) & CLKF_MASK) - -/* - * Bits in test mode register. - */ -#define TEST_TARGET 1 /* target test mode */ -#define TEST_INITIATOR 2 /* initiator test mode */ -#define TEST_TRISTATE 4 /* tristate (hi-z) test mode */ - -/* - * Bits in config2 register. - */ -#define CF2_RFB 0x80 -#define CF2_FEATURE_EN 0x40 /* enable features / phase latch */ -#define CF2_BYTECTRL 0x20 -#define CF2_DREQ_HIZ 0x10 -#define CF2_SCSI2 0x08 -#define CF2_PAR_ABORT 0x04 /* bad parity target abort */ -#define CF2_REG_PARERR 0x02 /* register parity error */ -#define CF2_DMA_PARERR 0x01 /* DMA parity error */ - -/* - * Bits in the config3 register. - */ -#define CF3_ID_MSG_CHK 0x80 -#define CF3_3B_MSGS 0x40 -#define CF3_CDB10 0x20 -#define CF3_FASTSCSI 0x10 /* enable fast SCSI support */ -#define CF3_FASTCLOCK 0x08 -#define CF3_SAVERESID 0x04 -#define CF3_ALT_DMA 0x02 -#define CF3_THRESH_8 0x01 - -/* - * Bits in the config4 register. - */ -#define CF4_EAN 0x04 -#define CF4_TEST 0x02 -#define CF4_BBTE 0x01 - -#endif /* _MAC53C94_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/mac_esp.c b/ANDROID_3.4.5/drivers/scsi/mac_esp.c deleted file mode 100644 index 70eb1f79..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mac_esp.c +++ /dev/null @@ -1,641 +0,0 @@ -/* mac_esp.c: ESP front-end for Macintosh Quadra systems. - * - * Adapted from jazz_esp.c and the old mac_esp.c. - * - * The pseudo DMA algorithm is based on the one used in NetBSD. - * See sys/arch/mac68k/obio/esp.c for some background information. - * - * Copyright (C) 2007-2008 Finn Thain - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "esp_scsi.h" - -#define DRV_MODULE_NAME "mac_esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.000" -#define DRV_MODULE_RELDATE "Sept 15, 2007" - -#define MAC_ESP_IO_BASE 0x50F00000 -#define MAC_ESP_REGS_QUADRA (MAC_ESP_IO_BASE + 0x10000) -#define MAC_ESP_REGS_QUADRA2 (MAC_ESP_IO_BASE + 0xF000) -#define MAC_ESP_REGS_QUADRA3 (MAC_ESP_IO_BASE + 0x18000) -#define MAC_ESP_REGS_SPACING 0x402 -#define MAC_ESP_PDMA_REG 0xF9800024 -#define MAC_ESP_PDMA_REG_SPACING 0x4 -#define MAC_ESP_PDMA_IO_OFFSET 0x100 - -#define esp_read8(REG) mac_esp_read8(esp, REG) -#define esp_write8(VAL, REG) mac_esp_write8(esp, VAL, REG) - -struct mac_esp_priv { - struct esp *esp; - void __iomem *pdma_regs; - void __iomem *pdma_io; - int error; -}; -static struct esp *esp_chips[2]; - -#define MAC_ESP_GET_PRIV(esp) ((struct mac_esp_priv *) \ - platform_get_drvdata((struct platform_device *) \ - (esp->dev))) - -static inline void mac_esp_write8(struct esp *esp, u8 val, unsigned long reg) -{ - nubus_writeb(val, esp->regs + reg * 16); -} - -static inline u8 mac_esp_read8(struct esp *esp, unsigned long reg) -{ - return nubus_readb(esp->regs + reg * 16); -} - -/* For pseudo DMA and PIO we need the virtual address - * so this address mapping is the identity mapping. - */ - -static dma_addr_t mac_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return (dma_addr_t)buf; -} - -static int mac_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - int i; - - for (i = 0; i < num_sg; i++) - sg[i].dma_address = (u32)sg_virt(&sg[i]); - return num_sg; -} - -static void mac_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - /* Nothing to do. */ -} - -static void mac_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - /* Nothing to do. */ -} - -static void mac_esp_reset_dma(struct esp *esp) -{ - /* Nothing to do. */ -} - -static void mac_esp_dma_drain(struct esp *esp) -{ - /* Nothing to do. */ -} - -static void mac_esp_dma_invalidate(struct esp *esp) -{ - /* Nothing to do. */ -} - -static int mac_esp_dma_error(struct esp *esp) -{ - return MAC_ESP_GET_PRIV(esp)->error; -} - -static inline int mac_esp_wait_for_empty_fifo(struct esp *esp) -{ - struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - int i = 500000; - - do { - if (!(esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES)) - return 0; - - if (esp_read8(ESP_STATUS) & ESP_STAT_INTR) - return 1; - - udelay(2); - } while (--i); - - printk(KERN_ERR PFX "FIFO is not empty (sreg %02x)\n", - esp_read8(ESP_STATUS)); - mep->error = 1; - return 1; -} - -static inline int mac_esp_wait_for_dreq(struct esp *esp) -{ - struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - int i = 500000; - - do { - if (mep->pdma_regs == NULL) { - if (via2_scsi_drq_pending()) - return 0; - } else { - if (nubus_readl(mep->pdma_regs) & 0x200) - return 0; - } - - if (esp_read8(ESP_STATUS) & ESP_STAT_INTR) - return 1; - - udelay(2); - } while (--i); - - printk(KERN_ERR PFX "PDMA timeout (sreg %02x)\n", - esp_read8(ESP_STATUS)); - mep->error = 1; - return 1; -} - -#define MAC_ESP_PDMA_LOOP(operands) \ - asm volatile ( \ - " tstw %1 \n" \ - " jbeq 20f \n" \ - "1: movew " operands " \n" \ - "2: movew " operands " \n" \ - "3: movew " operands " \n" \ - "4: movew " operands " \n" \ - "5: movew " operands " \n" \ - "6: movew " operands " \n" \ - "7: movew " operands " \n" \ - "8: movew " operands " \n" \ - "9: movew " operands " \n" \ - "10: movew " operands " \n" \ - "11: movew " operands " \n" \ - "12: movew " operands " \n" \ - "13: movew " operands " \n" \ - "14: movew " operands " \n" \ - "15: movew " operands " \n" \ - "16: movew " operands " \n" \ - " subqw #1,%1 \n" \ - " jbne 1b \n" \ - "20: tstw %2 \n" \ - " jbeq 30f \n" \ - "21: movew " operands " \n" \ - " subqw #1,%2 \n" \ - " jbne 21b \n" \ - "30: tstw %3 \n" \ - " jbeq 40f \n" \ - "31: moveb " operands " \n" \ - "32: nop \n" \ - "40: \n" \ - " \n" \ - " .section __ex_table,\"a\" \n" \ - " .align 4 \n" \ - " .long 1b,40b \n" \ - " .long 2b,40b \n" \ - " .long 3b,40b \n" \ - " .long 4b,40b \n" \ - " .long 5b,40b \n" \ - " .long 6b,40b \n" \ - " .long 7b,40b \n" \ - " .long 8b,40b \n" \ - " .long 9b,40b \n" \ - " .long 10b,40b \n" \ - " .long 11b,40b \n" \ - " .long 12b,40b \n" \ - " .long 13b,40b \n" \ - " .long 14b,40b \n" \ - " .long 15b,40b \n" \ - " .long 16b,40b \n" \ - " .long 21b,40b \n" \ - " .long 31b,40b \n" \ - " .long 32b,40b \n" \ - " .previous \n" \ - : "+a" (addr), "+r" (count32), "+r" (count2) \ - : "g" (count1), "a" (mep->pdma_io)) - -static void mac_esp_send_pdma_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) -{ - struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - - mep->error = 0; - - if (!write) - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - - esp_write8((esp_count >> 0) & 0xFF, ESP_TCLOW); - esp_write8((esp_count >> 8) & 0xFF, ESP_TCMED); - - scsi_esp_cmd(esp, cmd); - - do { - unsigned int count32 = esp_count >> 5; - unsigned int count2 = (esp_count & 0x1F) >> 1; - unsigned int count1 = esp_count & 1; - unsigned int start_addr = addr; - - if (mac_esp_wait_for_dreq(esp)) - break; - - if (write) { - MAC_ESP_PDMA_LOOP("%4@,%0@+"); - - esp_count -= addr - start_addr; - } else { - unsigned int n; - - MAC_ESP_PDMA_LOOP("%0@+,%4@"); - - if (mac_esp_wait_for_empty_fifo(esp)) - break; - - n = (esp_read8(ESP_TCMED) << 8) + esp_read8(ESP_TCLOW); - addr = start_addr + esp_count - n; - esp_count = n; - } - } while (esp_count); -} - -/* - * Programmed IO routines follow. - */ - -static inline unsigned int mac_esp_wait_for_fifo(struct esp *esp) -{ - int i = 500000; - - do { - unsigned int fbytes = esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES; - - if (fbytes) - return fbytes; - - udelay(2); - } while (--i); - - printk(KERN_ERR PFX "FIFO is empty (sreg %02x)\n", - esp_read8(ESP_STATUS)); - return 0; -} - -static inline int mac_esp_wait_for_intr(struct esp *esp) -{ - struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - int i = 500000; - - do { - esp->sreg = esp_read8(ESP_STATUS); - if (esp->sreg & ESP_STAT_INTR) - return 0; - - udelay(2); - } while (--i); - - printk(KERN_ERR PFX "IRQ timeout (sreg %02x)\n", esp->sreg); - mep->error = 1; - return 1; -} - -#define MAC_ESP_PIO_LOOP(operands, reg1) \ - asm volatile ( \ - "1: moveb " operands " \n" \ - " subqw #1,%1 \n" \ - " jbne 1b \n" \ - : "+a" (addr), "+r" (reg1) \ - : "a" (fifo)) - -#define MAC_ESP_PIO_FILL(operands, reg1) \ - asm volatile ( \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " moveb " operands " \n" \ - " subqw #8,%1 \n" \ - " subqw #8,%1 \n" \ - : "+a" (addr), "+r" (reg1) \ - : "a" (fifo)) - -#define MAC_ESP_FIFO_SIZE 16 - -static void mac_esp_send_pio_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) -{ - struct mac_esp_priv *mep = MAC_ESP_GET_PRIV(esp); - u8 *fifo = esp->regs + ESP_FDATA * 16; - - cmd &= ~ESP_CMD_DMA; - mep->error = 0; - - if (write) { - scsi_esp_cmd(esp, cmd); - - while (1) { - unsigned int n; - - n = mac_esp_wait_for_fifo(esp); - if (!n) - break; - - if (n > esp_count) - n = esp_count; - esp_count -= n; - - MAC_ESP_PIO_LOOP("%2@,%0@+", n); - - if (!esp_count) - break; - - if (mac_esp_wait_for_intr(esp)) - break; - - if (((esp->sreg & ESP_STAT_PMASK) != ESP_DIP) && - ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)) - break; - - esp->ireg = esp_read8(ESP_INTRPT); - if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) != - ESP_INTR_BSERV) - break; - - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } else { - scsi_esp_cmd(esp, ESP_CMD_FLUSH); - - if (esp_count >= MAC_ESP_FIFO_SIZE) - MAC_ESP_PIO_FILL("%0@+,%2@", esp_count); - else - MAC_ESP_PIO_LOOP("%0@+,%2@", esp_count); - - scsi_esp_cmd(esp, cmd); - - while (esp_count) { - unsigned int n; - - if (mac_esp_wait_for_intr(esp)) - break; - - if (((esp->sreg & ESP_STAT_PMASK) != ESP_DOP) && - ((esp->sreg & ESP_STAT_PMASK) != ESP_MOP)) - break; - - esp->ireg = esp_read8(ESP_INTRPT); - if ((esp->ireg & (ESP_INTR_DC | ESP_INTR_BSERV)) != - ESP_INTR_BSERV) - break; - - n = MAC_ESP_FIFO_SIZE - - (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES); - if (n > esp_count) - n = esp_count; - - if (n == MAC_ESP_FIFO_SIZE) { - MAC_ESP_PIO_FILL("%0@+,%2@", esp_count); - } else { - esp_count -= n; - MAC_ESP_PIO_LOOP("%0@+,%2@", n); - } - - scsi_esp_cmd(esp, ESP_CMD_TI); - } - } -} - -static int mac_esp_irq_pending(struct esp *esp) -{ - if (esp_read8(ESP_STATUS) & ESP_STAT_INTR) - return 1; - return 0; -} - -static u32 mac_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) -{ - return dma_len > 0xFFFF ? 0xFFFF : dma_len; -} - -static irqreturn_t mac_scsi_esp_intr(int irq, void *dev_id) -{ - int got_intr; - - /* - * This is an edge triggered IRQ, so we have to be careful to - * avoid missing a transition when it is shared by two ESP devices. - */ - - do { - got_intr = 0; - if (esp_chips[0] && - (mac_esp_read8(esp_chips[0], ESP_STATUS) & ESP_STAT_INTR)) { - (void)scsi_esp_intr(irq, esp_chips[0]); - got_intr = 1; - } - if (esp_chips[1] && - (mac_esp_read8(esp_chips[1], ESP_STATUS) & ESP_STAT_INTR)) { - (void)scsi_esp_intr(irq, esp_chips[1]); - got_intr = 1; - } - } while (got_intr); - - return IRQ_HANDLED; -} - -static struct esp_driver_ops mac_esp_ops = { - .esp_write8 = mac_esp_write8, - .esp_read8 = mac_esp_read8, - .map_single = mac_esp_map_single, - .map_sg = mac_esp_map_sg, - .unmap_single = mac_esp_unmap_single, - .unmap_sg = mac_esp_unmap_sg, - .irq_pending = mac_esp_irq_pending, - .dma_length_limit = mac_esp_dma_length_limit, - .reset_dma = mac_esp_reset_dma, - .dma_drain = mac_esp_dma_drain, - .dma_invalidate = mac_esp_dma_invalidate, - .send_dma_cmd = mac_esp_send_pdma_cmd, - .dma_error = mac_esp_dma_error, -}; - -static int __devinit esp_mac_probe(struct platform_device *dev) -{ - struct scsi_host_template *tpnt = &scsi_esp_template; - struct Scsi_Host *host; - struct esp *esp; - int err; - struct mac_esp_priv *mep; - - if (!MACH_IS_MAC) - return -ENODEV; - - if (dev->id > 1) - return -ENODEV; - - host = scsi_host_alloc(tpnt, sizeof(struct esp)); - - err = -ENOMEM; - if (!host) - goto fail; - - host->max_id = 8; - host->use_clustering = DISABLE_CLUSTERING; - esp = shost_priv(host); - - esp->host = host; - esp->dev = dev; - - esp->command_block = kzalloc(16, GFP_KERNEL); - if (!esp->command_block) - goto fail_unlink; - esp->command_block_dma = (dma_addr_t)esp->command_block; - - esp->scsi_id = 7; - host->this_id = esp->scsi_id; - esp->scsi_id_mask = 1 << esp->scsi_id; - - mep = kzalloc(sizeof(struct mac_esp_priv), GFP_KERNEL); - if (!mep) - goto fail_free_command_block; - mep->esp = esp; - platform_set_drvdata(dev, mep); - - switch (macintosh_config->scsi_type) { - case MAC_SCSI_QUADRA: - esp->cfreq = 16500000; - esp->regs = (void __iomem *)MAC_ESP_REGS_QUADRA; - mep->pdma_io = esp->regs + MAC_ESP_PDMA_IO_OFFSET; - mep->pdma_regs = NULL; - break; - case MAC_SCSI_QUADRA2: - esp->cfreq = 25000000; - esp->regs = (void __iomem *)(MAC_ESP_REGS_QUADRA2 + - dev->id * MAC_ESP_REGS_SPACING); - mep->pdma_io = esp->regs + MAC_ESP_PDMA_IO_OFFSET; - mep->pdma_regs = (void __iomem *)(MAC_ESP_PDMA_REG + - dev->id * MAC_ESP_PDMA_REG_SPACING); - nubus_writel(0x1d1, mep->pdma_regs); - break; - case MAC_SCSI_QUADRA3: - /* These quadras have a real DMA controller (the PSC) but we - * don't know how to drive it so we must use PIO instead. - */ - esp->cfreq = 25000000; - esp->regs = (void __iomem *)MAC_ESP_REGS_QUADRA3; - mep->pdma_io = NULL; - mep->pdma_regs = NULL; - break; - } - - esp->ops = &mac_esp_ops; - if (mep->pdma_io == NULL) { - printk(KERN_INFO PFX "using PIO for controller %d\n", dev->id); - esp_write8(0, ESP_TCLOW); - esp_write8(0, ESP_TCMED); - esp->flags = ESP_FLAG_DISABLE_SYNC; - mac_esp_ops.send_dma_cmd = mac_esp_send_pio_cmd; - } else { - printk(KERN_INFO PFX "using PDMA for controller %d\n", dev->id); - } - - host->irq = IRQ_MAC_SCSI; - esp_chips[dev->id] = esp; - mb(); - if (esp_chips[!dev->id] == NULL) { - err = request_irq(host->irq, mac_scsi_esp_intr, 0, "ESP", NULL); - if (err < 0) { - esp_chips[dev->id] = NULL; - goto fail_free_priv; - } - } - - err = scsi_esp_register(esp, &dev->dev); - if (err) - goto fail_free_irq; - - return 0; - -fail_free_irq: - if (esp_chips[!dev->id] == NULL) - free_irq(host->irq, esp); -fail_free_priv: - kfree(mep); -fail_free_command_block: - kfree(esp->command_block); -fail_unlink: - scsi_host_put(host); -fail: - return err; -} - -static int __devexit esp_mac_remove(struct platform_device *dev) -{ - struct mac_esp_priv *mep = platform_get_drvdata(dev); - struct esp *esp = mep->esp; - unsigned int irq = esp->host->irq; - - scsi_esp_unregister(esp); - - esp_chips[dev->id] = NULL; - if (!(esp_chips[0] || esp_chips[1])) - free_irq(irq, NULL); - - kfree(mep); - - kfree(esp->command_block); - - scsi_host_put(esp->host); - - return 0; -} - -static struct platform_driver esp_mac_driver = { - .probe = esp_mac_probe, - .remove = __devexit_p(esp_mac_remove), - .driver = { - .name = DRV_MODULE_NAME, - .owner = THIS_MODULE, - }, -}; - -static int __init mac_esp_init(void) -{ - return platform_driver_register(&esp_mac_driver); -} - -static void __exit mac_esp_exit(void) -{ - platform_driver_unregister(&esp_mac_driver); -} - -MODULE_DESCRIPTION("Mac ESP SCSI driver"); -MODULE_AUTHOR("Finn Thain "); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(DRV_VERSION); -MODULE_ALIAS("platform:" DRV_MODULE_NAME); - -module_init(mac_esp_init); -module_exit(mac_esp_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/mac_scsi.c b/ANDROID_3.4.5/drivers/scsi/mac_scsi.c deleted file mode 100644 index 24828b54..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mac_scsi.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - * Generic Macintosh NCR5380 driver - * - * Copyright 1998, Michael Schmitz - * - * derived in part from: - */ -/* - * Generic Generic NCR5380 driver - * - * Copyright 1995, Russell King - * - * ALPHA RELEASE 1. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * $Log: mac_NCR5380.c,v $ - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include "scsi.h" -#include -#include "mac_scsi.h" - -/* These control the behaviour of the generic 5380 core */ -#define AUTOSENSE -#define PSEUDO_DMA - -#include "NCR5380.h" - -#if 0 -#define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION) -#else -#define NDEBUG (NDEBUG_ABORT) -#endif - -#define RESET_BOOT -#define DRIVER_SETUP - -extern void via_scsi_clear(void); - -#ifdef RESET_BOOT -static void mac_scsi_reset_boot(struct Scsi_Host *instance); -#endif - -static int setup_called = 0; -static int setup_can_queue = -1; -static int setup_cmd_per_lun = -1; -static int setup_sg_tablesize = -1; -static int setup_use_pdma = -1; -#ifdef SUPPORT_TAGS -static int setup_use_tagged_queuing = -1; -#endif -static int setup_hostid = -1; - -/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms, - * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more - * need ten times the standard value... */ -#define TOSHIBA_DELAY - -#ifdef TOSHIBA_DELAY -#define AFTER_RESET_DELAY (5*HZ/2) -#else -#define AFTER_RESET_DELAY (HZ/2) -#endif - -static volatile unsigned char *mac_scsi_regp = NULL; -static volatile unsigned char *mac_scsi_drq = NULL; -static volatile unsigned char *mac_scsi_nodrq = NULL; - - -/* - * NCR 5380 register access functions - */ - -#if 0 -/* Debug versions */ -#define CTRL(p,v) (*ctrl = (v)) - -static char macscsi_read(struct Scsi_Host *instance, int reg) -{ - int iobase = instance->io_port; - int i; - int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; - - CTRL(iobase, 0); - i = in_8(iobase + (reg<<4)); - CTRL(iobase, 0x40); - - return i; -} - -static void macscsi_write(struct Scsi_Host *instance, int reg, int value) -{ - int iobase = instance->io_port; - int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl; - - CTRL(iobase, 0); - out_8(iobase + (reg<<4), value); - CTRL(iobase, 0x40); -} -#else - -/* Fast versions */ -static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg) -{ - return in_8(instance->io_port + (reg<<4)); -} - -static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value) -{ - out_8(instance->io_port + (reg<<4), value); -} -#endif - - -/* - * Function : mac_scsi_setup(char *str) - * - * Purpose : booter command line initialization of the overrides array, - * - * Inputs : str - comma delimited list of options - * - */ - -static int __init mac_scsi_setup(char *str) { -#ifdef DRIVER_SETUP - int ints[7]; - - (void)get_options( str, ARRAY_SIZE(ints), ints); - - if (setup_called++ || ints[0] < 1 || ints[0] > 6) { - printk(KERN_WARNING "scsi: " - " Usage: mac5380=[,,,,,]\n"); - printk(KERN_ALERT "scsi: Bad Penguin parameters?\n"); - return 0; - } - - if (ints[0] >= 1) { - if (ints[1] > 0) - /* no limits on this, just > 0 */ - setup_can_queue = ints[1]; - } - if (ints[0] >= 2) { - if (ints[2] > 0) - setup_cmd_per_lun = ints[2]; - } - if (ints[0] >= 3) { - if (ints[3] >= 0) { - setup_sg_tablesize = ints[3]; - /* Must be <= SG_ALL (255) */ - if (setup_sg_tablesize > SG_ALL) - setup_sg_tablesize = SG_ALL; - } - } - if (ints[0] >= 4) { - /* Must be between 0 and 7 */ - if (ints[4] >= 0 && ints[4] <= 7) - setup_hostid = ints[4]; - else if (ints[4] > 7) - printk(KERN_WARNING "mac_scsi_setup: invalid host ID %d !\n", ints[4] ); - } -#ifdef SUPPORT_TAGS - if (ints[0] >= 5) { - if (ints[5] >= 0) - setup_use_tagged_queuing = !!ints[5]; - } - - if (ints[0] == 6) { - if (ints[6] >= 0) - setup_use_pdma = ints[6]; - } -#else - if (ints[0] == 5) { - if (ints[5] >= 0) - setup_use_pdma = ints[5]; - } -#endif /* SUPPORT_TAGS */ - -#endif /* DRIVER_SETUP */ - return 1; -} - -__setup("mac5380=", mac_scsi_setup); - -/* - * Function : int macscsi_detect(struct scsi_host_template * tpnt) - * - * Purpose : initializes mac NCR5380 driver based on the - * command line / compile time port and irq definitions. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * - */ - -int __init macscsi_detect(struct scsi_host_template * tpnt) -{ - static int called = 0; - int flags = 0; - struct Scsi_Host *instance; - - if (!MACH_IS_MAC || called) - return( 0 ); - - if (macintosh_config->scsi_type != MAC_SCSI_OLD) - return( 0 ); - - /* setup variables */ - tpnt->can_queue = - (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE; - tpnt->cmd_per_lun = - (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN; - tpnt->sg_tablesize = - (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE; - - if (setup_hostid >= 0) - tpnt->this_id = setup_hostid; - else { - /* use 7 as default */ - tpnt->this_id = 7; - } - -#ifdef SUPPORT_TAGS - if (setup_use_tagged_queuing < 0) - setup_use_tagged_queuing = USE_TAGGED_QUEUING; -#endif - - /* Once we support multiple 5380s (e.g. DuoDock) we'll do - something different here */ - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - - if (macintosh_config->ident == MAC_MODEL_IIFX) { - mac_scsi_regp = via1+0x8000; - mac_scsi_drq = via1+0xE000; - mac_scsi_nodrq = via1+0xC000; - /* The IIFX should be able to do true DMA, but pseudo-dma doesn't work */ - flags = FLAG_NO_PSEUDO_DMA; - } else { - mac_scsi_regp = via1+0x10000; - mac_scsi_drq = via1+0x6000; - mac_scsi_nodrq = via1+0x12000; - } - - if (! setup_use_pdma) - flags = FLAG_NO_PSEUDO_DMA; - - instance->io_port = (unsigned long) mac_scsi_regp; - instance->irq = IRQ_MAC_SCSI; - -#ifdef RESET_BOOT - mac_scsi_reset_boot(instance); -#endif - - NCR5380_init(instance, flags); - - instance->n_io_port = 255; - - ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; - - if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, NCR5380_intr, 0, "ncr5380", instance)) { - printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = SCSI_IRQ_NONE; - } - - printk(KERN_INFO "scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port); - if (instance->irq == SCSI_IRQ_NONE) - printk (KERN_INFO "s disabled"); - else - printk (KERN_INFO " %d", instance->irq); - printk(KERN_INFO " options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE); - printk(KERN_INFO "\nscsi%d:", instance->host_no); - NCR5380_print_options(instance); - printk("\n"); - called = 1; - return 1; -} - -int macscsi_release (struct Scsi_Host *shpnt) -{ - if (shpnt->irq != SCSI_IRQ_NONE) - free_irq(shpnt->irq, shpnt); - NCR5380_exit(shpnt); - - return 0; -} - -#ifdef RESET_BOOT -/* - * Our 'bus reset on boot' function - */ - -static void mac_scsi_reset_boot(struct Scsi_Host *instance) -{ - unsigned long end; - - NCR5380_local_declare(); - NCR5380_setup(instance); - - /* - * Do a SCSI reset to clean up the bus during initialization. No messing - * with the queues, interrupts, or locks necessary here. - */ - - printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." ); - - /* get in phase */ - NCR5380_write( TARGET_COMMAND_REG, - PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); - - /* assert RST */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); - /* The min. reset hold time is 25us, so 40us should be enough */ - udelay( 50 ); - /* reset RST and interrupt */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); - NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - - for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) - barrier(); - - printk(KERN_INFO " done\n" ); -} -#endif - -const char * macscsi_info (struct Scsi_Host *spnt) { - return ""; -} - -/* - Pseudo-DMA: (Ove Edlund) - The code attempts to catch bus errors that occur if one for example - "trips over the cable". - XXX: Since bus errors in the PDMA routines never happen on my - computer, the bus error code is untested. - If the code works as intended, a bus error results in Pseudo-DMA - beeing disabled, meaning that the driver switches to slow handshake. - If bus errors are NOT extremely rare, this has to be changed. -*/ - -#define CP_IO_TO_MEM(s,d,len) \ -__asm__ __volatile__ \ - (" cmp.w #4,%2\n" \ - " bls 8f\n" \ - " move.w %1,%%d0\n" \ - " neg.b %%d0\n" \ - " and.w #3,%%d0\n" \ - " sub.w %%d0,%2\n" \ - " bra 2f\n" \ - " 1: move.b (%0),(%1)+\n" \ - " 2: dbf %%d0,1b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #5,%%d0\n" \ - " bra 4f\n" \ - " 3: move.l (%0),(%1)+\n" \ - "31: move.l (%0),(%1)+\n" \ - "32: move.l (%0),(%1)+\n" \ - "33: move.l (%0),(%1)+\n" \ - "34: move.l (%0),(%1)+\n" \ - "35: move.l (%0),(%1)+\n" \ - "36: move.l (%0),(%1)+\n" \ - "37: move.l (%0),(%1)+\n" \ - " 4: dbf %%d0,3b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #2,%%d0\n" \ - " and.w #7,%%d0\n" \ - " bra 6f\n" \ - " 5: move.l (%0),(%1)+\n" \ - " 6: dbf %%d0,5b\n" \ - " and.w #3,%2\n" \ - " bra 8f\n" \ - " 7: move.b (%0),(%1)+\n" \ - " 8: dbf %2,7b\n" \ - " moveq.l #0, %2\n" \ - " 9: \n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "90: moveq.l #1, %2\n" \ - " jra 9b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,90b\n" \ - " .long 3b,90b\n" \ - " .long 31b,90b\n" \ - " .long 32b,90b\n" \ - " .long 33b,90b\n" \ - " .long 34b,90b\n" \ - " .long 35b,90b\n" \ - " .long 36b,90b\n" \ - " .long 37b,90b\n" \ - " .long 5b,90b\n" \ - " .long 7b,90b\n" \ - ".previous" \ - : "=a"(s), "=a"(d), "=d"(len) \ - : "0"(s), "1"(d), "2"(len) \ - : "d0") - - -static int macscsi_pread (struct Scsi_Host *instance, - unsigned char *dst, int len) -{ - unsigned char *d; - volatile unsigned char *s; - - NCR5380_local_declare(); - NCR5380_setup(instance); - - s = mac_scsi_drq+0x60; - d = dst; - -/* These conditions are derived from MacOS */ - - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) - && !(NCR5380_read(STATUS_REG) & SR_REQ)) - ; - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) - && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) { - printk(KERN_ERR "Error in macscsi_pread\n"); - return -1; - } - - CP_IO_TO_MEM(s, d, len); - - if (len != 0) { - printk(KERN_NOTICE "Bus error in macscsi_pread\n"); - return -1; - } - - return 0; -} - - -#define CP_MEM_TO_IO(s,d,len) \ -__asm__ __volatile__ \ - (" cmp.w #4,%2\n" \ - " bls 8f\n" \ - " move.w %0,%%d0\n" \ - " neg.b %%d0\n" \ - " and.w #3,%%d0\n" \ - " sub.w %%d0,%2\n" \ - " bra 2f\n" \ - " 1: move.b (%0)+,(%1)\n" \ - " 2: dbf %%d0,1b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #5,%%d0\n" \ - " bra 4f\n" \ - " 3: move.l (%0)+,(%1)\n" \ - "31: move.l (%0)+,(%1)\n" \ - "32: move.l (%0)+,(%1)\n" \ - "33: move.l (%0)+,(%1)\n" \ - "34: move.l (%0)+,(%1)\n" \ - "35: move.l (%0)+,(%1)\n" \ - "36: move.l (%0)+,(%1)\n" \ - "37: move.l (%0)+,(%1)\n" \ - " 4: dbf %%d0,3b\n" \ - " move.w %2,%%d0\n" \ - " lsr.w #2,%%d0\n" \ - " and.w #7,%%d0\n" \ - " bra 6f\n" \ - " 5: move.l (%0)+,(%1)\n" \ - " 6: dbf %%d0,5b\n" \ - " and.w #3,%2\n" \ - " bra 8f\n" \ - " 7: move.b (%0)+,(%1)\n" \ - " 8: dbf %2,7b\n" \ - " moveq.l #0, %2\n" \ - " 9: \n" \ - ".section .fixup,\"ax\"\n" \ - " .even\n" \ - "90: moveq.l #1, %2\n" \ - " jra 9b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 1b,90b\n" \ - " .long 3b,90b\n" \ - " .long 31b,90b\n" \ - " .long 32b,90b\n" \ - " .long 33b,90b\n" \ - " .long 34b,90b\n" \ - " .long 35b,90b\n" \ - " .long 36b,90b\n" \ - " .long 37b,90b\n" \ - " .long 5b,90b\n" \ - " .long 7b,90b\n" \ - ".previous" \ - : "=a"(s), "=a"(d), "=d"(len) \ - : "0"(s), "1"(d), "2"(len) \ - : "d0") - -static int macscsi_pwrite (struct Scsi_Host *instance, - unsigned char *src, int len) -{ - unsigned char *s; - volatile unsigned char *d; - - NCR5380_local_declare(); - NCR5380_setup(instance); - - s = src; - d = mac_scsi_drq; - -/* These conditions are derived from MacOS */ - - while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) - && (!(NCR5380_read(STATUS_REG) & SR_REQ) - || (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))) - ; - if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) { - printk(KERN_ERR "Error in macscsi_pwrite\n"); - return -1; - } - - CP_MEM_TO_IO(s, d, len); - - if (len != 0) { - printk(KERN_NOTICE "Bus error in macscsi_pwrite\n"); - return -1; - } - - return 0; -} - - -#include "NCR5380.c" - -static struct scsi_host_template driver_template = { - .proc_name = "Mac5380", - .proc_info = macscsi_proc_info, - .name = "Macintosh NCR5380 SCSI", - .detect = macscsi_detect, - .release = macscsi_release, - .info = macscsi_info, - .queuecommand = macscsi_queue_command, - .eh_abort_handler = macscsi_abort, - .eh_bus_reset_handler = macscsi_bus_reset, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING -}; - - -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/mac_scsi.h b/ANDROID_3.4.5/drivers/scsi/mac_scsi.h deleted file mode 100644 index d26e331c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mac_scsi.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Cumana Generic NCR5380 driver defines - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * ALPHA RELEASE 1. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * $Log: cumana_NCR5380.h,v $ - */ - -#ifndef MAC_NCR5380_H -#define MAC_NCR5380_H - -#define MACSCSI_PUBLIC_RELEASE 2 - -#ifndef ASM - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 16 -#endif - -#ifndef SG_TABLESIZE -#define SG_TABLESIZE SG_NONE -#endif - -#ifndef USE_TAGGED_QUEUING -#define USE_TAGGED_QUEUING 0 -#endif - -#include - -#ifndef HOSTS_C - -#define NCR5380_implementation_fields \ - int port, ctrl - -#define NCR5380_local_declare() \ - struct Scsi_Host *_instance - -#define NCR5380_setup(instance) \ - _instance = instance - -#define NCR5380_read(reg) macscsi_read(_instance, reg) -#define NCR5380_write(reg, value) macscsi_write(_instance, reg, value) - -#define NCR5380_pread macscsi_pread -#define NCR5380_pwrite macscsi_pwrite - -#define NCR5380_intr macscsi_intr -#define NCR5380_queue_command macscsi_queue_command -#define NCR5380_abort macscsi_abort -#define NCR5380_bus_reset macscsi_bus_reset -#define NCR5380_proc_info macscsi_proc_info - -#define BOARD_NORMAL 0 -#define BOARD_NCR53C400 1 - -#endif /* ndef HOSTS_C */ -#endif /* ndef ASM */ -#endif /* MAC_NCR5380_H */ - diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid.c b/ANDROID_3.4.5/drivers/scsi/megaraid.c deleted file mode 100644 index 4d39a9ff..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid.c +++ /dev/null @@ -1,5072 +0,0 @@ -/* - * - * Linux MegaRAID device driver - * - * Copyright (c) 2002 LSI Logic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Copyright (c) 2002 Red Hat, Inc. All rights reserved. - * - fixes - * - speed-ups (list handling fixes, issued_list, optimizations.) - * - lots of cleanups. - * - * Copyright (c) 2003 Christoph Hellwig - * - new-style, hotplug-aware pci probing and scsi registration - * - * Version : v2.00.4 Mon Nov 14 14:02:43 EST 2005 - Seokmann Ju - * - * - * Description: Linux device driver for LSI Logic MegaRAID controller - * - * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490, 493 - * 518, 520, 531, 532 - * - * This driver is supported by LSI Logic, with assistance from Red Hat, Dell, - * and others. Please send updates to the mailing list - * linux-scsi@vger.kernel.org . - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include - -#include "megaraid.h" - -#define MEGARAID_MODULE_VERSION "2.00.4" - -MODULE_AUTHOR ("sju@lsil.com"); -MODULE_DESCRIPTION ("LSI Logic MegaRAID legacy driver"); -MODULE_LICENSE ("GPL"); -MODULE_VERSION(MEGARAID_MODULE_VERSION); - -static DEFINE_MUTEX(megadev_mutex); -static unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN; -module_param(max_cmd_per_lun, uint, 0); -MODULE_PARM_DESC(max_cmd_per_lun, "Maximum number of commands which can be issued to a single LUN (default=DEF_CMD_PER_LUN=63)"); - -static unsigned short int max_sectors_per_io = MAX_SECTORS_PER_IO; -module_param(max_sectors_per_io, ushort, 0); -MODULE_PARM_DESC(max_sectors_per_io, "Maximum number of sectors per I/O request (default=MAX_SECTORS_PER_IO=128)"); - - -static unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT; -module_param(max_mbox_busy_wait, ushort, 0); -MODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)"); - -#define RDINDOOR(adapter) readl((adapter)->mmio_base + 0x20) -#define RDOUTDOOR(adapter) readl((adapter)->mmio_base + 0x2C) -#define WRINDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x20) -#define WROUTDOOR(adapter,value) writel(value, (adapter)->mmio_base + 0x2C) - -/* - * Global variables - */ - -static int hba_count; -static adapter_t *hba_soft_state[MAX_CONTROLLERS]; -static struct proc_dir_entry *mega_proc_dir_entry; - -/* For controller re-ordering */ -static struct mega_hbas mega_hbas[MAX_CONTROLLERS]; - -static long -megadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); - -/* - * The File Operations structure for the serial/ioctl interface of the driver - */ -static const struct file_operations megadev_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = megadev_unlocked_ioctl, - .open = megadev_open, - .llseek = noop_llseek, -}; - -/* - * Array to structures for storing the information about the controllers. This - * information is sent to the user level applications, when they do an ioctl - * for this information. - */ -static struct mcontroller mcontroller[MAX_CONTROLLERS]; - -/* The current driver version */ -static u32 driver_ver = 0x02000000; - -/* major number used by the device for character interface */ -static int major; - -#define IS_RAID_CH(hba, ch) (((hba)->mega_ch_class >> (ch)) & 0x01) - - -/* - * Debug variable to print some diagnostic messages - */ -static int trace_level; - -/** - * mega_setup_mailbox() - * @adapter - pointer to our soft state - * - * Allocates a 8 byte aligned memory for the handshake mailbox. - */ -static int -mega_setup_mailbox(adapter_t *adapter) -{ - unsigned long align; - - adapter->una_mbox64 = pci_alloc_consistent(adapter->dev, - sizeof(mbox64_t), &adapter->una_mbox64_dma); - - if( !adapter->una_mbox64 ) return -1; - - adapter->mbox = &adapter->una_mbox64->mbox; - - adapter->mbox = (mbox_t *)((((unsigned long) adapter->mbox) + 15) & - (~0UL ^ 0xFUL)); - - adapter->mbox64 = (mbox64_t *)(((unsigned long)adapter->mbox) - 8); - - align = ((void *)adapter->mbox) - ((void *)&adapter->una_mbox64->mbox); - - adapter->mbox_dma = adapter->una_mbox64_dma + 8 + align; - - /* - * Register the mailbox if the controller is an io-mapped controller - */ - if( adapter->flag & BOARD_IOMAP ) { - - outb(adapter->mbox_dma & 0xFF, - adapter->host->io_port + MBOX_PORT0); - - outb((adapter->mbox_dma >> 8) & 0xFF, - adapter->host->io_port + MBOX_PORT1); - - outb((adapter->mbox_dma >> 16) & 0xFF, - adapter->host->io_port + MBOX_PORT2); - - outb((adapter->mbox_dma >> 24) & 0xFF, - adapter->host->io_port + MBOX_PORT3); - - outb(ENABLE_MBOX_BYTE, - adapter->host->io_port + ENABLE_MBOX_REGION); - - irq_ack(adapter); - - irq_enable(adapter); - } - - return 0; -} - - -/* - * mega_query_adapter() - * @adapter - pointer to our soft state - * - * Issue the adapter inquiry commands to the controller and find out - * information and parameter about the devices attached - */ -static int -mega_query_adapter(adapter_t *adapter) -{ - dma_addr_t prod_info_dma_handle; - mega_inquiry3 *inquiry3; - u8 raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox; - int retval; - - /* Initialize adapter inquiry mailbox */ - - mbox = (mbox_t *)raw_mbox; - - memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - memset(&mbox->m_out, 0, sizeof(raw_mbox)); - - /* - * Try to issue Inquiry3 command - * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and - * update enquiry3 structure - */ - mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; - - inquiry3 = (mega_inquiry3 *)adapter->mega_buffer; - - raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ - raw_mbox[2] = NC_SUBOP_ENQUIRY3; /* i.e. 0x0F */ - raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; /* i.e. 0x02 */ - - /* Issue a blocking command to the card */ - if ((retval = issue_scb_block(adapter, raw_mbox))) { - /* the adapter does not support 40ld */ - - mraid_ext_inquiry *ext_inq; - mraid_inquiry *inq; - dma_addr_t dma_handle; - - ext_inq = pci_alloc_consistent(adapter->dev, - sizeof(mraid_ext_inquiry), &dma_handle); - - if( ext_inq == NULL ) return -1; - - inq = &ext_inq->raid_inq; - - mbox->m_out.xferaddr = (u32)dma_handle; - - /*issue old 0x04 command to adapter */ - mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ; - - issue_scb_block(adapter, raw_mbox); - - /* - * update Enquiry3 and ProductInfo structures with - * mraid_inquiry structure - */ - mega_8_to_40ld(inq, inquiry3, - (mega_product_info *)&adapter->product_info); - - pci_free_consistent(adapter->dev, sizeof(mraid_ext_inquiry), - ext_inq, dma_handle); - - } else { /*adapter supports 40ld */ - adapter->flag |= BOARD_40LD; - - /* - * get product_info, which is static information and will be - * unchanged - */ - prod_info_dma_handle = pci_map_single(adapter->dev, (void *) - &adapter->product_info, - sizeof(mega_product_info), PCI_DMA_FROMDEVICE); - - mbox->m_out.xferaddr = prod_info_dma_handle; - - raw_mbox[0] = FC_NEW_CONFIG; /* i.e. mbox->cmd=0xA1 */ - raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ - - if ((retval = issue_scb_block(adapter, raw_mbox))) - printk(KERN_WARNING - "megaraid: Product_info cmd failed with error: %d\n", - retval); - - pci_unmap_single(adapter->dev, prod_info_dma_handle, - sizeof(mega_product_info), PCI_DMA_FROMDEVICE); - } - - - /* - * kernel scans the channels from 0 to <= max_channel - */ - adapter->host->max_channel = - adapter->product_info.nchannels + NVIRT_CHAN -1; - - adapter->host->max_id = 16; /* max targets per channel */ - - adapter->host->max_lun = 7; /* Up to 7 luns for non disk devices */ - - adapter->host->cmd_per_lun = max_cmd_per_lun; - - adapter->numldrv = inquiry3->num_ldrv; - - adapter->max_cmds = adapter->product_info.max_commands; - - if(adapter->max_cmds > MAX_COMMANDS) - adapter->max_cmds = MAX_COMMANDS; - - adapter->host->can_queue = adapter->max_cmds - 1; - - /* - * Get the maximum number of scatter-gather elements supported by this - * firmware - */ - mega_get_max_sgl(adapter); - - adapter->host->sg_tablesize = adapter->sglen; - - - /* use HP firmware and bios version encoding - Note: fw_version[0|1] and bios_version[0|1] were originally shifted - right 8 bits making them zero. This 0 value was hardcoded to fix - sparse warnings. */ - if (adapter->product_info.subsysvid == HP_SUBSYS_VID) { - sprintf (adapter->fw_version, "%c%d%d.%d%d", - adapter->product_info.fw_version[2], - 0, - adapter->product_info.fw_version[1] & 0x0f, - 0, - adapter->product_info.fw_version[0] & 0x0f); - sprintf (adapter->bios_version, "%c%d%d.%d%d", - adapter->product_info.bios_version[2], - 0, - adapter->product_info.bios_version[1] & 0x0f, - 0, - adapter->product_info.bios_version[0] & 0x0f); - } else { - memcpy(adapter->fw_version, - (char *)adapter->product_info.fw_version, 4); - adapter->fw_version[4] = 0; - - memcpy(adapter->bios_version, - (char *)adapter->product_info.bios_version, 4); - - adapter->bios_version[4] = 0; - } - - printk(KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives.\n", - adapter->fw_version, adapter->bios_version, adapter->numldrv); - - /* - * Do we support extended (>10 bytes) cdbs - */ - adapter->support_ext_cdb = mega_support_ext_cdb(adapter); - if (adapter->support_ext_cdb) - printk(KERN_NOTICE "megaraid: supports extended CDBs.\n"); - - - return 0; -} - -/** - * mega_runpendq() - * @adapter - pointer to our soft state - * - * Runs through the list of pending requests. - */ -static inline void -mega_runpendq(adapter_t *adapter) -{ - if(!list_empty(&adapter->pending_list)) - __mega_runpendq(adapter); -} - -/* - * megaraid_queue() - * @scmd - Issue this scsi command - * @done - the callback hook into the scsi mid-layer - * - * The command queuing entry point for the mid-layer. - */ -static int -megaraid_queue_lck(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *)) -{ - adapter_t *adapter; - scb_t *scb; - int busy=0; - unsigned long flags; - - adapter = (adapter_t *)scmd->device->host->hostdata; - - scmd->scsi_done = done; - - - /* - * Allocate and build a SCB request - * busy flag will be set if mega_build_cmd() command could not - * allocate scb. We will return non-zero status in that case. - * NOTE: scb can be null even though certain commands completed - * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would - * return 0 in that case. - */ - - spin_lock_irqsave(&adapter->lock, flags); - scb = mega_build_cmd(adapter, scmd, &busy); - if (!scb) - goto out; - - scb->state |= SCB_PENDQ; - list_add_tail(&scb->list, &adapter->pending_list); - - /* - * Check if the HBA is in quiescent state, e.g., during a - * delete logical drive opertion. If it is, don't run - * the pending_list. - */ - if (atomic_read(&adapter->quiescent) == 0) - mega_runpendq(adapter); - - busy = 0; - out: - spin_unlock_irqrestore(&adapter->lock, flags); - return busy; -} - -static DEF_SCSI_QCMD(megaraid_queue) - -/** - * mega_allocate_scb() - * @adapter - pointer to our soft state - * @cmd - scsi command from the mid-layer - * - * Allocate a SCB structure. This is the central structure for controller - * commands. - */ -static inline scb_t * -mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd) -{ - struct list_head *head = &adapter->free_list; - scb_t *scb; - - /* Unlink command from Free List */ - if( !list_empty(head) ) { - - scb = list_entry(head->next, scb_t, list); - - list_del_init(head->next); - - scb->state = SCB_ACTIVE; - scb->cmd = cmd; - scb->dma_type = MEGA_DMA_TYPE_NONE; - - return scb; - } - - return NULL; -} - -/** - * mega_get_ldrv_num() - * @adapter - pointer to our soft state - * @cmd - scsi mid layer command - * @channel - channel on the controller - * - * Calculate the logical drive number based on the information in scsi command - * and the channel number. - */ -static inline int -mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel) -{ - int tgt; - int ldrv_num; - - tgt = cmd->device->id; - - if ( tgt > adapter->this_id ) - tgt--; /* we do not get inquires for initiator id */ - - ldrv_num = (channel * 15) + tgt; - - - /* - * If we have a logical drive with boot enabled, project it first - */ - if( adapter->boot_ldrv_enabled ) { - if( ldrv_num == 0 ) { - ldrv_num = adapter->boot_ldrv; - } - else { - if( ldrv_num <= adapter->boot_ldrv ) { - ldrv_num--; - } - } - } - - /* - * If "delete logical drive" feature is enabled on this controller. - * Do only if at least one delete logical drive operation was done. - * - * Also, after logical drive deletion, instead of logical drive number, - * the value returned should be 0x80+logical drive id. - * - * These is valid only for IO commands. - */ - - if (adapter->support_random_del && adapter->read_ldidmap ) - switch (cmd->cmnd[0]) { - case READ_6: /* fall through */ - case WRITE_6: /* fall through */ - case READ_10: /* fall through */ - case WRITE_10: - ldrv_num += 0x80; - } - - return ldrv_num; -} - -/** - * mega_build_cmd() - * @adapter - pointer to our soft state - * @cmd - Prepare using this scsi command - * @busy - busy flag if no resources - * - * Prepares a command and scatter gather list for the controller. This routine - * also finds out if the commands is intended for a logical drive or a - * physical device and prepares the controller command accordingly. - * - * We also re-order the logical drives and physical devices based on their - * boot settings. - */ -static scb_t * -mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) -{ - mega_ext_passthru *epthru; - mega_passthru *pthru; - scb_t *scb; - mbox_t *mbox; - long seg; - char islogical; - int max_ldrv_num; - int channel = 0; - int target = 0; - int ldrv_num = 0; /* logical drive number */ - - - /* - * filter the internal and ioctl commands - */ - if((cmd->cmnd[0] == MEGA_INTERNAL_CMD)) - return (scb_t *)cmd->host_scribble; - - /* - * We know what channels our logical drives are on - mega_find_card() - */ - islogical = adapter->logdrv_chan[cmd->device->channel]; - - /* - * The theory: If physical drive is chosen for boot, all the physical - * devices are exported before the logical drives, otherwise physical - * devices are pushed after logical drives, in which case - Kernel sees - * the physical devices on virtual channel which is obviously converted - * to actual channel on the HBA. - */ - if( adapter->boot_pdrv_enabled ) { - if( islogical ) { - /* logical channel */ - channel = cmd->device->channel - - adapter->product_info.nchannels; - } - else { - /* this is physical channel */ - channel = cmd->device->channel; - target = cmd->device->id; - - /* - * boot from a physical disk, that disk needs to be - * exposed first IF both the channels are SCSI, then - * booting from the second channel is not allowed. - */ - if( target == 0 ) { - target = adapter->boot_pdrv_tgt; - } - else if( target == adapter->boot_pdrv_tgt ) { - target = 0; - } - } - } - else { - if( islogical ) { - /* this is the logical channel */ - channel = cmd->device->channel; - } - else { - /* physical channel */ - channel = cmd->device->channel - NVIRT_CHAN; - target = cmd->device->id; - } - } - - - if(islogical) { - - /* have just LUN 0 for each target on virtual channels */ - if (cmd->device->lun) { - cmd->result = (DID_BAD_TARGET << 16); - cmd->scsi_done(cmd); - return NULL; - } - - ldrv_num = mega_get_ldrv_num(adapter, cmd, channel); - - - max_ldrv_num = (adapter->flag & BOARD_40LD) ? - MAX_LOGICAL_DRIVES_40LD : MAX_LOGICAL_DRIVES_8LD; - - /* - * max_ldrv_num increases by 0x80 if some logical drive was - * deleted. - */ - if(adapter->read_ldidmap) - max_ldrv_num += 0x80; - - if(ldrv_num > max_ldrv_num ) { - cmd->result = (DID_BAD_TARGET << 16); - cmd->scsi_done(cmd); - return NULL; - } - - } - else { - if( cmd->device->lun > 7) { - /* - * Do not support lun >7 for physically accessed - * devices - */ - cmd->result = (DID_BAD_TARGET << 16); - cmd->scsi_done(cmd); - return NULL; - } - } - - /* - * - * Logical drive commands - * - */ - if(islogical) { - switch (cmd->cmnd[0]) { - case TEST_UNIT_READY: -#if MEGA_HAVE_CLUSTERING - /* - * Do we support clustering and is the support enabled - * If no, return success always - */ - if( !adapter->has_cluster ) { - cmd->result = (DID_OK << 16); - cmd->scsi_done(cmd); - return NULL; - } - - if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; - return NULL; - } - - scb->raw_mbox[0] = MEGA_CLUSTER_CMD; - scb->raw_mbox[2] = MEGA_RESERVATION_STATUS; - scb->raw_mbox[3] = ldrv_num; - - scb->dma_direction = PCI_DMA_NONE; - - return scb; -#else - cmd->result = (DID_OK << 16); - cmd->scsi_done(cmd); - return NULL; -#endif - - case MODE_SENSE: { - char *buf; - struct scatterlist *sg; - - sg = scsi_sglist(cmd); - buf = kmap_atomic(sg_page(sg)) + sg->offset; - - memset(buf, 0, cmd->cmnd[4]); - kunmap_atomic(buf - sg->offset); - - cmd->result = (DID_OK << 16); - cmd->scsi_done(cmd); - return NULL; - } - - case READ_CAPACITY: - case INQUIRY: - - if(!(adapter->flag & (1L << cmd->device->channel))) { - - printk(KERN_NOTICE - "scsi%d: scanning scsi channel %d ", - adapter->host->host_no, - cmd->device->channel); - printk("for logical drives.\n"); - - adapter->flag |= (1L << cmd->device->channel); - } - - /* Allocate a SCB and initialize passthru */ - if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; - return NULL; - } - pthru = scb->pthru; - - mbox = (mbox_t *)scb->raw_mbox; - memset(mbox, 0, sizeof(scb->raw_mbox)); - memset(pthru, 0, sizeof(mega_passthru)); - - pthru->timeout = 0; - pthru->ars = 1; - pthru->reqsenselen = 14; - pthru->islogical = 1; - pthru->logdrv = ldrv_num; - pthru->cdblen = cmd->cmd_len; - memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len); - - if( adapter->has_64bit_addr ) { - mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; - } - else { - mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; - } - - scb->dma_direction = PCI_DMA_FROMDEVICE; - - pthru->numsgelements = mega_build_sglist(adapter, scb, - &pthru->dataxferaddr, &pthru->dataxferlen); - - mbox->m_out.xferaddr = scb->pthru_dma_addr; - - return scb; - - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - - /* Allocate a SCB and initialize mailbox */ - if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; - return NULL; - } - mbox = (mbox_t *)scb->raw_mbox; - - memset(mbox, 0, sizeof(scb->raw_mbox)); - mbox->m_out.logdrv = ldrv_num; - - /* - * A little hack: 2nd bit is zero for all scsi read - * commands and is set for all scsi write commands - */ - if( adapter->has_64bit_addr ) { - mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? - MEGA_MBOXCMD_LWRITE64: - MEGA_MBOXCMD_LREAD64 ; - } - else { - mbox->m_out.cmd = (*cmd->cmnd & 0x02) ? - MEGA_MBOXCMD_LWRITE: - MEGA_MBOXCMD_LREAD ; - } - - /* - * 6-byte READ(0x08) or WRITE(0x0A) cdb - */ - if( cmd->cmd_len == 6 ) { - mbox->m_out.numsectors = (u32) cmd->cmnd[4]; - mbox->m_out.lba = - ((u32)cmd->cmnd[1] << 16) | - ((u32)cmd->cmnd[2] << 8) | - (u32)cmd->cmnd[3]; - - mbox->m_out.lba &= 0x1FFFFF; - -#if MEGA_HAVE_STATS - /* - * Take modulo 0x80, since the logical drive - * number increases by 0x80 when a logical - * drive was deleted - */ - if (*cmd->cmnd == READ_6) { - adapter->nreads[ldrv_num%0x80]++; - adapter->nreadblocks[ldrv_num%0x80] += - mbox->m_out.numsectors; - } else { - adapter->nwrites[ldrv_num%0x80]++; - adapter->nwriteblocks[ldrv_num%0x80] += - mbox->m_out.numsectors; - } -#endif - } - - /* - * 10-byte READ(0x28) or WRITE(0x2A) cdb - */ - if( cmd->cmd_len == 10 ) { - mbox->m_out.numsectors = - (u32)cmd->cmnd[8] | - ((u32)cmd->cmnd[7] << 8); - mbox->m_out.lba = - ((u32)cmd->cmnd[2] << 24) | - ((u32)cmd->cmnd[3] << 16) | - ((u32)cmd->cmnd[4] << 8) | - (u32)cmd->cmnd[5]; - -#if MEGA_HAVE_STATS - if (*cmd->cmnd == READ_10) { - adapter->nreads[ldrv_num%0x80]++; - adapter->nreadblocks[ldrv_num%0x80] += - mbox->m_out.numsectors; - } else { - adapter->nwrites[ldrv_num%0x80]++; - adapter->nwriteblocks[ldrv_num%0x80] += - mbox->m_out.numsectors; - } -#endif - } - - /* - * 12-byte READ(0xA8) or WRITE(0xAA) cdb - */ - if( cmd->cmd_len == 12 ) { - mbox->m_out.lba = - ((u32)cmd->cmnd[2] << 24) | - ((u32)cmd->cmnd[3] << 16) | - ((u32)cmd->cmnd[4] << 8) | - (u32)cmd->cmnd[5]; - - mbox->m_out.numsectors = - ((u32)cmd->cmnd[6] << 24) | - ((u32)cmd->cmnd[7] << 16) | - ((u32)cmd->cmnd[8] << 8) | - (u32)cmd->cmnd[9]; - -#if MEGA_HAVE_STATS - if (*cmd->cmnd == READ_12) { - adapter->nreads[ldrv_num%0x80]++; - adapter->nreadblocks[ldrv_num%0x80] += - mbox->m_out.numsectors; - } else { - adapter->nwrites[ldrv_num%0x80]++; - adapter->nwriteblocks[ldrv_num%0x80] += - mbox->m_out.numsectors; - } -#endif - } - - /* - * If it is a read command - */ - if( (*cmd->cmnd & 0x0F) == 0x08 ) { - scb->dma_direction = PCI_DMA_FROMDEVICE; - } - else { - scb->dma_direction = PCI_DMA_TODEVICE; - } - - /* Calculate Scatter-Gather info */ - mbox->m_out.numsgelements = mega_build_sglist(adapter, scb, - (u32 *)&mbox->m_out.xferaddr, (u32 *)&seg); - - return scb; - -#if MEGA_HAVE_CLUSTERING - case RESERVE: /* Fall through */ - case RELEASE: - - /* - * Do we support clustering and is the support enabled - */ - if( ! adapter->has_cluster ) { - - cmd->result = (DID_BAD_TARGET << 16); - cmd->scsi_done(cmd); - return NULL; - } - - /* Allocate a SCB and initialize mailbox */ - if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; - return NULL; - } - - scb->raw_mbox[0] = MEGA_CLUSTER_CMD; - scb->raw_mbox[2] = ( *cmd->cmnd == RESERVE ) ? - MEGA_RESERVE_LD : MEGA_RELEASE_LD; - - scb->raw_mbox[3] = ldrv_num; - - scb->dma_direction = PCI_DMA_NONE; - - return scb; -#endif - - default: - cmd->result = (DID_BAD_TARGET << 16); - cmd->scsi_done(cmd); - return NULL; - } - } - - /* - * Passthru drive commands - */ - else { - /* Allocate a SCB and initialize passthru */ - if(!(scb = mega_allocate_scb(adapter, cmd))) { - *busy = 1; - return NULL; - } - - mbox = (mbox_t *)scb->raw_mbox; - memset(mbox, 0, sizeof(scb->raw_mbox)); - - if( adapter->support_ext_cdb ) { - - epthru = mega_prepare_extpassthru(adapter, scb, cmd, - channel, target); - - mbox->m_out.cmd = MEGA_MBOXCMD_EXTPTHRU; - - mbox->m_out.xferaddr = scb->epthru_dma_addr; - - } - else { - - pthru = mega_prepare_passthru(adapter, scb, cmd, - channel, target); - - /* Initialize mailbox */ - if( adapter->has_64bit_addr ) { - mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64; - } - else { - mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU; - } - - mbox->m_out.xferaddr = scb->pthru_dma_addr; - - } - return scb; - } - return NULL; -} - - -/** - * mega_prepare_passthru() - * @adapter - pointer to our soft state - * @scb - our scsi control block - * @cmd - scsi command from the mid-layer - * @channel - actual channel on the controller - * @target - actual id on the controller. - * - * prepare a command for the scsi physical devices. - */ -static mega_passthru * -mega_prepare_passthru(adapter_t *adapter, scb_t *scb, Scsi_Cmnd *cmd, - int channel, int target) -{ - mega_passthru *pthru; - - pthru = scb->pthru; - memset(pthru, 0, sizeof (mega_passthru)); - - /* 0=6sec/1=60sec/2=10min/3=3hrs */ - pthru->timeout = 2; - - pthru->ars = 1; - pthru->reqsenselen = 14; - pthru->islogical = 0; - - pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : channel; - - pthru->target = (adapter->flag & BOARD_40LD) ? - (channel << 4) | target : target; - - pthru->cdblen = cmd->cmd_len; - pthru->logdrv = cmd->device->lun; - - memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len); - - /* Not sure about the direction */ - scb->dma_direction = PCI_DMA_BIDIRECTIONAL; - - /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */ - switch (cmd->cmnd[0]) { - case INQUIRY: - case READ_CAPACITY: - if(!(adapter->flag & (1L << cmd->device->channel))) { - - printk(KERN_NOTICE - "scsi%d: scanning scsi channel %d [P%d] ", - adapter->host->host_no, - cmd->device->channel, channel); - printk("for physical devices.\n"); - - adapter->flag |= (1L << cmd->device->channel); - } - /* Fall through */ - default: - pthru->numsgelements = mega_build_sglist(adapter, scb, - &pthru->dataxferaddr, &pthru->dataxferlen); - break; - } - return pthru; -} - - -/** - * mega_prepare_extpassthru() - * @adapter - pointer to our soft state - * @scb - our scsi control block - * @cmd - scsi command from the mid-layer - * @channel - actual channel on the controller - * @target - actual id on the controller. - * - * prepare a command for the scsi physical devices. This rountine prepares - * commands for devices which can take extended CDBs (>10 bytes) - */ -static mega_ext_passthru * -mega_prepare_extpassthru(adapter_t *adapter, scb_t *scb, Scsi_Cmnd *cmd, - int channel, int target) -{ - mega_ext_passthru *epthru; - - epthru = scb->epthru; - memset(epthru, 0, sizeof(mega_ext_passthru)); - - /* 0=6sec/1=60sec/2=10min/3=3hrs */ - epthru->timeout = 2; - - epthru->ars = 1; - epthru->reqsenselen = 14; - epthru->islogical = 0; - - epthru->channel = (adapter->flag & BOARD_40LD) ? 0 : channel; - epthru->target = (adapter->flag & BOARD_40LD) ? - (channel << 4) | target : target; - - epthru->cdblen = cmd->cmd_len; - epthru->logdrv = cmd->device->lun; - - memcpy(epthru->cdb, cmd->cmnd, cmd->cmd_len); - - /* Not sure about the direction */ - scb->dma_direction = PCI_DMA_BIDIRECTIONAL; - - switch(cmd->cmnd[0]) { - case INQUIRY: - case READ_CAPACITY: - if(!(adapter->flag & (1L << cmd->device->channel))) { - - printk(KERN_NOTICE - "scsi%d: scanning scsi channel %d [P%d] ", - adapter->host->host_no, - cmd->device->channel, channel); - printk("for physical devices.\n"); - - adapter->flag |= (1L << cmd->device->channel); - } - /* Fall through */ - default: - epthru->numsgelements = mega_build_sglist(adapter, scb, - &epthru->dataxferaddr, &epthru->dataxferlen); - break; - } - - return epthru; -} - -static void -__mega_runpendq(adapter_t *adapter) -{ - scb_t *scb; - struct list_head *pos, *next; - - /* Issue any pending commands to the card */ - list_for_each_safe(pos, next, &adapter->pending_list) { - - scb = list_entry(pos, scb_t, list); - - if( !(scb->state & SCB_ISSUED) ) { - - if( issue_scb(adapter, scb) != 0 ) - return; - } - } - - return; -} - - -/** - * issue_scb() - * @adapter - pointer to our soft state - * @scb - scsi control block - * - * Post a command to the card if the mailbox is available, otherwise return - * busy. We also take the scb from the pending list if the mailbox is - * available. - */ -static int -issue_scb(adapter_t *adapter, scb_t *scb) -{ - volatile mbox64_t *mbox64 = adapter->mbox64; - volatile mbox_t *mbox = adapter->mbox; - unsigned int i = 0; - - if(unlikely(mbox->m_in.busy)) { - do { - udelay(1); - i++; - } while( mbox->m_in.busy && (i < max_mbox_busy_wait) ); - - if(mbox->m_in.busy) return -1; - } - - /* Copy mailbox data into host structure */ - memcpy((char *)&mbox->m_out, (char *)scb->raw_mbox, - sizeof(struct mbox_out)); - - mbox->m_out.cmdid = scb->idx; /* Set cmdid */ - mbox->m_in.busy = 1; /* Set busy */ - - - /* - * Increment the pending queue counter - */ - atomic_inc(&adapter->pend_cmds); - - switch (mbox->m_out.cmd) { - case MEGA_MBOXCMD_LREAD64: - case MEGA_MBOXCMD_LWRITE64: - case MEGA_MBOXCMD_PASSTHRU64: - case MEGA_MBOXCMD_EXTPTHRU: - mbox64->xfer_segment_lo = mbox->m_out.xferaddr; - mbox64->xfer_segment_hi = 0; - mbox->m_out.xferaddr = 0xFFFFFFFF; - break; - default: - mbox64->xfer_segment_lo = 0; - mbox64->xfer_segment_hi = 0; - } - - /* - * post the command - */ - scb->state |= SCB_ISSUED; - - if( likely(adapter->flag & BOARD_MEMMAP) ) { - mbox->m_in.poll = 0; - mbox->m_in.ack = 0; - WRINDOOR(adapter, adapter->mbox_dma | 0x1); - } - else { - irq_enable(adapter); - issue_command(adapter); - } - - return 0; -} - -/* - * Wait until the controller's mailbox is available - */ -static inline int -mega_busywait_mbox (adapter_t *adapter) -{ - if (adapter->mbox->m_in.busy) - return __mega_busywait_mbox(adapter); - return 0; -} - -/** - * issue_scb_block() - * @adapter - pointer to our soft state - * @raw_mbox - the mailbox - * - * Issue a scb in synchronous and non-interrupt mode - */ -static int -issue_scb_block(adapter_t *adapter, u_char *raw_mbox) -{ - volatile mbox64_t *mbox64 = adapter->mbox64; - volatile mbox_t *mbox = adapter->mbox; - u8 byte; - - /* Wait until mailbox is free */ - if(mega_busywait_mbox (adapter)) - goto bug_blocked_mailbox; - - /* Copy mailbox data into host structure */ - memcpy((char *) mbox, raw_mbox, sizeof(struct mbox_out)); - mbox->m_out.cmdid = 0xFE; - mbox->m_in.busy = 1; - - switch (raw_mbox[0]) { - case MEGA_MBOXCMD_LREAD64: - case MEGA_MBOXCMD_LWRITE64: - case MEGA_MBOXCMD_PASSTHRU64: - case MEGA_MBOXCMD_EXTPTHRU: - mbox64->xfer_segment_lo = mbox->m_out.xferaddr; - mbox64->xfer_segment_hi = 0; - mbox->m_out.xferaddr = 0xFFFFFFFF; - break; - default: - mbox64->xfer_segment_lo = 0; - mbox64->xfer_segment_hi = 0; - } - - if( likely(adapter->flag & BOARD_MEMMAP) ) { - mbox->m_in.poll = 0; - mbox->m_in.ack = 0; - mbox->m_in.numstatus = 0xFF; - mbox->m_in.status = 0xFF; - WRINDOOR(adapter, adapter->mbox_dma | 0x1); - - while((volatile u8)mbox->m_in.numstatus == 0xFF) - cpu_relax(); - - mbox->m_in.numstatus = 0xFF; - - while( (volatile u8)mbox->m_in.poll != 0x77 ) - cpu_relax(); - - mbox->m_in.poll = 0; - mbox->m_in.ack = 0x77; - - WRINDOOR(adapter, adapter->mbox_dma | 0x2); - - while(RDINDOOR(adapter) & 0x2) - cpu_relax(); - } - else { - irq_disable(adapter); - issue_command(adapter); - - while (!((byte = irq_state(adapter)) & INTR_VALID)) - cpu_relax(); - - set_irq_state(adapter, byte); - irq_enable(adapter); - irq_ack(adapter); - } - - return mbox->m_in.status; - -bug_blocked_mailbox: - printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n"); - udelay (1000); - return -1; -} - - -/** - * megaraid_isr_iomapped() - * @irq - irq - * @devp - pointer to our soft state - * - * Interrupt service routine for io-mapped controllers. - * Find out if our device is interrupting. If yes, acknowledge the interrupt - * and service the completed commands. - */ -static irqreturn_t -megaraid_isr_iomapped(int irq, void *devp) -{ - adapter_t *adapter = devp; - unsigned long flags; - u8 status; - u8 nstatus; - u8 completed[MAX_FIRMWARE_STATUS]; - u8 byte; - int handled = 0; - - - /* - * loop till F/W has more commands for us to complete. - */ - spin_lock_irqsave(&adapter->lock, flags); - - do { - /* Check if a valid interrupt is pending */ - byte = irq_state(adapter); - if( (byte & VALID_INTR_BYTE) == 0 ) { - /* - * No more pending commands - */ - goto out_unlock; - } - set_irq_state(adapter, byte); - - while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) - == 0xFF) - cpu_relax(); - adapter->mbox->m_in.numstatus = 0xFF; - - status = adapter->mbox->m_in.status; - - /* - * decrement the pending queue counter - */ - atomic_sub(nstatus, &adapter->pend_cmds); - - memcpy(completed, (void *)adapter->mbox->m_in.completed, - nstatus); - - /* Acknowledge interrupt */ - irq_ack(adapter); - - mega_cmd_done(adapter, completed, nstatus, status); - - mega_rundoneq(adapter); - - handled = 1; - - /* Loop through any pending requests */ - if(atomic_read(&adapter->quiescent) == 0) { - mega_runpendq(adapter); - } - - } while(1); - - out_unlock: - - spin_unlock_irqrestore(&adapter->lock, flags); - - return IRQ_RETVAL(handled); -} - - -/** - * megaraid_isr_memmapped() - * @irq - irq - * @devp - pointer to our soft state - * - * Interrupt service routine for memory-mapped controllers. - * Find out if our device is interrupting. If yes, acknowledge the interrupt - * and service the completed commands. - */ -static irqreturn_t -megaraid_isr_memmapped(int irq, void *devp) -{ - adapter_t *adapter = devp; - unsigned long flags; - u8 status; - u32 dword = 0; - u8 nstatus; - u8 completed[MAX_FIRMWARE_STATUS]; - int handled = 0; - - - /* - * loop till F/W has more commands for us to complete. - */ - spin_lock_irqsave(&adapter->lock, flags); - - do { - /* Check if a valid interrupt is pending */ - dword = RDOUTDOOR(adapter); - if(dword != 0x10001234) { - /* - * No more pending commands - */ - goto out_unlock; - } - WROUTDOOR(adapter, 0x10001234); - - while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus) - == 0xFF) { - cpu_relax(); - } - adapter->mbox->m_in.numstatus = 0xFF; - - status = adapter->mbox->m_in.status; - - /* - * decrement the pending queue counter - */ - atomic_sub(nstatus, &adapter->pend_cmds); - - memcpy(completed, (void *)adapter->mbox->m_in.completed, - nstatus); - - /* Acknowledge interrupt */ - WRINDOOR(adapter, 0x2); - - handled = 1; - - while( RDINDOOR(adapter) & 0x02 ) - cpu_relax(); - - mega_cmd_done(adapter, completed, nstatus, status); - - mega_rundoneq(adapter); - - /* Loop through any pending requests */ - if(atomic_read(&adapter->quiescent) == 0) { - mega_runpendq(adapter); - } - - } while(1); - - out_unlock: - - spin_unlock_irqrestore(&adapter->lock, flags); - - return IRQ_RETVAL(handled); -} -/** - * mega_cmd_done() - * @adapter - pointer to our soft state - * @completed - array of ids of completed commands - * @nstatus - number of completed commands - * @status - status of the last command completed - * - * Complete the commands and call the scsi mid-layer callback hooks. - */ -static void -mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) -{ - mega_ext_passthru *epthru = NULL; - struct scatterlist *sgl; - Scsi_Cmnd *cmd = NULL; - mega_passthru *pthru = NULL; - mbox_t *mbox = NULL; - u8 c; - scb_t *scb; - int islogical; - int cmdid; - int i; - - /* - * for all the commands completed, call the mid-layer callback routine - * and free the scb. - */ - for( i = 0; i < nstatus; i++ ) { - - cmdid = completed[i]; - - if( cmdid == CMDID_INT_CMDS ) { /* internal command */ - scb = &adapter->int_scb; - cmd = scb->cmd; - mbox = (mbox_t *)scb->raw_mbox; - - /* - * Internal command interface do not fire the extended - * passthru or 64-bit passthru - */ - pthru = scb->pthru; - - } - else { - scb = &adapter->scb_list[cmdid]; - - /* - * Make sure f/w has completed a valid command - */ - if( !(scb->state & SCB_ISSUED) || scb->cmd == NULL ) { - printk(KERN_CRIT - "megaraid: invalid command "); - printk("Id %d, scb->state:%x, scsi cmd:%p\n", - cmdid, scb->state, scb->cmd); - - continue; - } - - /* - * Was a abort issued for this command - */ - if( scb->state & SCB_ABORT ) { - - printk(KERN_WARNING - "megaraid: aborted cmd [%x] complete.\n", - scb->idx); - - scb->cmd->result = (DID_ABORT << 16); - - list_add_tail(SCSI_LIST(scb->cmd), - &adapter->completed_list); - - mega_free_scb(adapter, scb); - - continue; - } - - /* - * Was a reset issued for this command - */ - if( scb->state & SCB_RESET ) { - - printk(KERN_WARNING - "megaraid: reset cmd [%x] complete.\n", - scb->idx); - - scb->cmd->result = (DID_RESET << 16); - - list_add_tail(SCSI_LIST(scb->cmd), - &adapter->completed_list); - - mega_free_scb (adapter, scb); - - continue; - } - - cmd = scb->cmd; - pthru = scb->pthru; - epthru = scb->epthru; - mbox = (mbox_t *)scb->raw_mbox; - -#if MEGA_HAVE_STATS - { - - int logdrv = mbox->m_out.logdrv; - - islogical = adapter->logdrv_chan[cmd->channel]; - /* - * Maintain an error counter for the logical drive. - * Some application like SNMP agent need such - * statistics - */ - if( status && islogical && (cmd->cmnd[0] == READ_6 || - cmd->cmnd[0] == READ_10 || - cmd->cmnd[0] == READ_12)) { - /* - * Logical drive number increases by 0x80 when - * a logical drive is deleted - */ - adapter->rd_errors[logdrv%0x80]++; - } - - if( status && islogical && (cmd->cmnd[0] == WRITE_6 || - cmd->cmnd[0] == WRITE_10 || - cmd->cmnd[0] == WRITE_12)) { - /* - * Logical drive number increases by 0x80 when - * a logical drive is deleted - */ - adapter->wr_errors[logdrv%0x80]++; - } - - } -#endif - } - - /* - * Do not return the presence of hard disk on the channel so, - * inquiry sent, and returned data==hard disk or removable - * hard disk and not logical, request should return failure! - - * PJ - */ - islogical = adapter->logdrv_chan[cmd->device->channel]; - if( cmd->cmnd[0] == INQUIRY && !islogical ) { - - sgl = scsi_sglist(cmd); - if( sg_page(sgl) ) { - c = *(unsigned char *) sg_virt(&sgl[0]); - } else { - printk(KERN_WARNING - "megaraid: invalid sg.\n"); - c = 0; - } - - if(IS_RAID_CH(adapter, cmd->device->channel) && - ((c & 0x1F ) == TYPE_DISK)) { - status = 0xF0; - } - } - - /* clear result; otherwise, success returns corrupt value */ - cmd->result = 0; - - /* Convert MegaRAID status to Linux error code */ - switch (status) { - case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD */ - cmd->result |= (DID_OK << 16); - break; - - case 0x02: /* ERROR_ABORTED, i.e. - SCSI_STATUS_CHECK_CONDITION */ - - /* set sense_buffer and result fields */ - if( mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU || - mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU64 ) { - - memcpy(cmd->sense_buffer, pthru->reqsensearea, - 14); - - cmd->result = (DRIVER_SENSE << 24) | - (DID_OK << 16) | - (CHECK_CONDITION << 1); - } - else { - if (mbox->m_out.cmd == MEGA_MBOXCMD_EXTPTHRU) { - - memcpy(cmd->sense_buffer, - epthru->reqsensearea, 14); - - cmd->result = (DRIVER_SENSE << 24) | - (DID_OK << 16) | - (CHECK_CONDITION << 1); - } else { - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = ABORTED_COMMAND; - cmd->result |= (CHECK_CONDITION << 1); - } - } - break; - - case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. - SCSI_STATUS_BUSY */ - cmd->result |= (DID_BUS_BUSY << 16) | status; - break; - - default: -#if MEGA_HAVE_CLUSTERING - /* - * If TEST_UNIT_READY fails, we know - * MEGA_RESERVATION_STATUS failed - */ - if( cmd->cmnd[0] == TEST_UNIT_READY ) { - cmd->result |= (DID_ERROR << 16) | - (RESERVATION_CONFLICT << 1); - } - else - /* - * Error code returned is 1 if Reserve or Release - * failed or the input parameter is invalid - */ - if( status == 1 && - (cmd->cmnd[0] == RESERVE || - cmd->cmnd[0] == RELEASE) ) { - - cmd->result |= (DID_ERROR << 16) | - (RESERVATION_CONFLICT << 1); - } - else -#endif - cmd->result |= (DID_BAD_TARGET << 16)|status; - } - - /* - * Only free SCBs for the commands coming down from the - * mid-layer, not for which were issued internally - * - * For internal command, restore the status returned by the - * firmware so that user can interpret it. - */ - if( cmdid == CMDID_INT_CMDS ) { /* internal command */ - cmd->result = status; - - /* - * Remove the internal command from the pending list - */ - list_del_init(&scb->list); - scb->state = SCB_FREE; - } - else { - mega_free_scb(adapter, scb); - } - - /* Add Scsi_Command to end of completed queue */ - list_add_tail(SCSI_LIST(cmd), &adapter->completed_list); - } -} - - -/* - * mega_runpendq() - * - * Run through the list of completed requests and finish it - */ -static void -mega_rundoneq (adapter_t *adapter) -{ - Scsi_Cmnd *cmd; - struct list_head *pos; - - list_for_each(pos, &adapter->completed_list) { - - struct scsi_pointer* spos = (struct scsi_pointer *)pos; - - cmd = list_entry(spos, Scsi_Cmnd, SCp); - cmd->scsi_done(cmd); - } - - INIT_LIST_HEAD(&adapter->completed_list); -} - - -/* - * Free a SCB structure - * Note: We assume the scsi commands associated with this scb is not free yet. - */ -static void -mega_free_scb(adapter_t *adapter, scb_t *scb) -{ - switch( scb->dma_type ) { - - case MEGA_DMA_TYPE_NONE: - break; - - case MEGA_SGLIST: - scsi_dma_unmap(scb->cmd); - break; - default: - break; - } - - /* - * Remove from the pending list - */ - list_del_init(&scb->list); - - /* Link the scb back into free list */ - scb->state = SCB_FREE; - scb->cmd = NULL; - - list_add(&scb->list, &adapter->free_list); -} - - -static int -__mega_busywait_mbox (adapter_t *adapter) -{ - volatile mbox_t *mbox = adapter->mbox; - long counter; - - for (counter = 0; counter < 10000; counter++) { - if (!mbox->m_in.busy) - return 0; - udelay(100); - cond_resched(); - } - return -1; /* give up after 1 second */ -} - -/* - * Copies data to SGLIST - * Note: For 64 bit cards, we need a minimum of one SG element for read/write - */ -static int -mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len) -{ - struct scatterlist *sg; - Scsi_Cmnd *cmd; - int sgcnt; - int idx; - - cmd = scb->cmd; - - /* - * Copy Scatter-Gather list info into controller structure. - * - * The number of sg elements returned must not exceed our limit - */ - sgcnt = scsi_dma_map(cmd); - - scb->dma_type = MEGA_SGLIST; - - BUG_ON(sgcnt > adapter->sglen || sgcnt < 0); - - *len = 0; - - if (scsi_sg_count(cmd) == 1 && !adapter->has_64bit_addr) { - sg = scsi_sglist(cmd); - scb->dma_h_bulkdata = sg_dma_address(sg); - *buf = (u32)scb->dma_h_bulkdata; - *len = sg_dma_len(sg); - return 0; - } - - scsi_for_each_sg(cmd, sg, sgcnt, idx) { - if (adapter->has_64bit_addr) { - scb->sgl64[idx].address = sg_dma_address(sg); - *len += scb->sgl64[idx].length = sg_dma_len(sg); - } else { - scb->sgl[idx].address = sg_dma_address(sg); - *len += scb->sgl[idx].length = sg_dma_len(sg); - } - } - - /* Reset pointer and length fields */ - *buf = scb->sgl_dma_addr; - - /* Return count of SG requests */ - return sgcnt; -} - - -/* - * mega_8_to_40ld() - * - * takes all info in AdapterInquiry structure and puts it into ProductInfo and - * Enquiry3 structures for later use - */ -static void -mega_8_to_40ld(mraid_inquiry *inquiry, mega_inquiry3 *enquiry3, - mega_product_info *product_info) -{ - int i; - - product_info->max_commands = inquiry->adapter_info.max_commands; - enquiry3->rebuild_rate = inquiry->adapter_info.rebuild_rate; - product_info->nchannels = inquiry->adapter_info.nchannels; - - for (i = 0; i < 4; i++) { - product_info->fw_version[i] = - inquiry->adapter_info.fw_version[i]; - - product_info->bios_version[i] = - inquiry->adapter_info.bios_version[i]; - } - enquiry3->cache_flush_interval = - inquiry->adapter_info.cache_flush_interval; - - product_info->dram_size = inquiry->adapter_info.dram_size; - - enquiry3->num_ldrv = inquiry->logdrv_info.num_ldrv; - - for (i = 0; i < MAX_LOGICAL_DRIVES_8LD; i++) { - enquiry3->ldrv_size[i] = inquiry->logdrv_info.ldrv_size[i]; - enquiry3->ldrv_prop[i] = inquiry->logdrv_info.ldrv_prop[i]; - enquiry3->ldrv_state[i] = inquiry->logdrv_info.ldrv_state[i]; - } - - for (i = 0; i < (MAX_PHYSICAL_DRIVES); i++) - enquiry3->pdrv_state[i] = inquiry->pdrv_info.pdrv_state[i]; -} - -static inline void -mega_free_sgl(adapter_t *adapter) -{ - scb_t *scb; - int i; - - for(i = 0; i < adapter->max_cmds; i++) { - - scb = &adapter->scb_list[i]; - - if( scb->sgl64 ) { - pci_free_consistent(adapter->dev, - sizeof(mega_sgl64) * adapter->sglen, - scb->sgl64, - scb->sgl_dma_addr); - - scb->sgl64 = NULL; - } - - if( scb->pthru ) { - pci_free_consistent(adapter->dev, sizeof(mega_passthru), - scb->pthru, scb->pthru_dma_addr); - - scb->pthru = NULL; - } - - if( scb->epthru ) { - pci_free_consistent(adapter->dev, - sizeof(mega_ext_passthru), - scb->epthru, scb->epthru_dma_addr); - - scb->epthru = NULL; - } - - } -} - - -/* - * Get information about the card/driver - */ -const char * -megaraid_info(struct Scsi_Host *host) -{ - static char buffer[512]; - adapter_t *adapter; - - adapter = (adapter_t *)host->hostdata; - - sprintf (buffer, - "LSI Logic MegaRAID %s %d commands %d targs %d chans %d luns", - adapter->fw_version, adapter->product_info.max_commands, - adapter->host->max_id, adapter->host->max_channel, - adapter->host->max_lun); - return buffer; -} - -/* - * Abort a previous SCSI request. Only commands on the pending list can be - * aborted. All the commands issued to the F/W must complete. - */ -static int -megaraid_abort(Scsi_Cmnd *cmd) -{ - adapter_t *adapter; - int rval; - - adapter = (adapter_t *)cmd->device->host->hostdata; - - rval = megaraid_abort_and_reset(adapter, cmd, SCB_ABORT); - - /* - * This is required here to complete any completed requests - * to be communicated over to the mid layer. - */ - mega_rundoneq(adapter); - - return rval; -} - - -static int -megaraid_reset(struct scsi_cmnd *cmd) -{ - adapter_t *adapter; - megacmd_t mc; - int rval; - - adapter = (adapter_t *)cmd->device->host->hostdata; - -#if MEGA_HAVE_CLUSTERING - mc.cmd = MEGA_CLUSTER_CMD; - mc.opcode = MEGA_RESET_RESERVATIONS; - - if( mega_internal_command(adapter, &mc, NULL) != 0 ) { - printk(KERN_WARNING - "megaraid: reservation reset failed.\n"); - } - else { - printk(KERN_INFO "megaraid: reservation reset.\n"); - } -#endif - - spin_lock_irq(&adapter->lock); - - rval = megaraid_abort_and_reset(adapter, cmd, SCB_RESET); - - /* - * This is required here to complete any completed requests - * to be communicated over to the mid layer. - */ - mega_rundoneq(adapter); - spin_unlock_irq(&adapter->lock); - - return rval; -} - -/** - * megaraid_abort_and_reset() - * @adapter - megaraid soft state - * @cmd - scsi command to be aborted or reset - * @aor - abort or reset flag - * - * Try to locate the scsi command in the pending queue. If found and is not - * issued to the controller, abort/reset it. Otherwise return failure - */ -static int -megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) -{ - struct list_head *pos, *next; - scb_t *scb; - - printk(KERN_WARNING "megaraid: %s cmd=%x \n", - (aor == SCB_ABORT)? "ABORTING":"RESET", - cmd->cmnd[0], cmd->device->channel, - cmd->device->id, cmd->device->lun); - - if(list_empty(&adapter->pending_list)) - return FALSE; - - list_for_each_safe(pos, next, &adapter->pending_list) { - - scb = list_entry(pos, scb_t, list); - - if (scb->cmd == cmd) { /* Found command */ - - scb->state |= aor; - - /* - * Check if this command has firmware ownership. If - * yes, we cannot reset this command. Whenever f/w - * completes this command, we will return appropriate - * status from ISR. - */ - if( scb->state & SCB_ISSUED ) { - - printk(KERN_WARNING - "megaraid: %s[%x], fw owner.\n", - (aor==SCB_ABORT) ? "ABORTING":"RESET", - scb->idx); - - return FALSE; - } - else { - - /* - * Not yet issued! Remove from the pending - * list - */ - printk(KERN_WARNING - "megaraid: %s-[%x], driver owner.\n", - (aor==SCB_ABORT) ? "ABORTING":"RESET", - scb->idx); - - mega_free_scb(adapter, scb); - - if( aor == SCB_ABORT ) { - cmd->result = (DID_ABORT << 16); - } - else { - cmd->result = (DID_RESET << 16); - } - - list_add_tail(SCSI_LIST(cmd), - &adapter->completed_list); - - return TRUE; - } - } - } - - return FALSE; -} - -static inline int -make_local_pdev(adapter_t *adapter, struct pci_dev **pdev) -{ - *pdev = alloc_pci_dev(); - - if( *pdev == NULL ) return -1; - - memcpy(*pdev, adapter->dev, sizeof(struct pci_dev)); - - if( pci_set_dma_mask(*pdev, DMA_BIT_MASK(32)) != 0 ) { - kfree(*pdev); - return -1; - } - - return 0; -} - -static inline void -free_local_pdev(struct pci_dev *pdev) -{ - kfree(pdev); -} - -/** - * mega_allocate_inquiry() - * @dma_handle - handle returned for dma address - * @pdev - handle to pci device - * - * allocates memory for inquiry structure - */ -static inline void * -mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev) -{ - return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle); -} - - -static inline void -mega_free_inquiry(void *inquiry, dma_addr_t dma_handle, struct pci_dev *pdev) -{ - pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle); -} - - -#ifdef CONFIG_PROC_FS -/* Following code handles /proc fs */ - -#define CREATE_READ_PROC(string, func) create_proc_read_entry(string, \ - S_IRUSR | S_IFREG, \ - controller_proc_dir_entry, \ - func, adapter) - -/** - * mega_create_proc_entry() - * @index - index in soft state array - * @parent - parent node for this /proc entry - * - * Creates /proc entries for our controllers. - */ -static void -mega_create_proc_entry(int index, struct proc_dir_entry *parent) -{ - struct proc_dir_entry *controller_proc_dir_entry = NULL; - u8 string[64] = { 0 }; - adapter_t *adapter = hba_soft_state[index]; - - sprintf(string, "hba%d", adapter->host->host_no); - - controller_proc_dir_entry = - adapter->controller_proc_dir_entry = proc_mkdir(string, parent); - - if(!controller_proc_dir_entry) { - printk(KERN_WARNING "\nmegaraid: proc_mkdir failed\n"); - return; - } - adapter->proc_read = CREATE_READ_PROC("config", proc_read_config); - adapter->proc_stat = CREATE_READ_PROC("stat", proc_read_stat); - adapter->proc_mbox = CREATE_READ_PROC("mailbox", proc_read_mbox); -#if MEGA_HAVE_ENH_PROC - adapter->proc_rr = CREATE_READ_PROC("rebuild-rate", proc_rebuild_rate); - adapter->proc_battery = CREATE_READ_PROC("battery-status", - proc_battery); - - /* - * Display each physical drive on its channel - */ - adapter->proc_pdrvstat[0] = CREATE_READ_PROC("diskdrives-ch0", - proc_pdrv_ch0); - adapter->proc_pdrvstat[1] = CREATE_READ_PROC("diskdrives-ch1", - proc_pdrv_ch1); - adapter->proc_pdrvstat[2] = CREATE_READ_PROC("diskdrives-ch2", - proc_pdrv_ch2); - adapter->proc_pdrvstat[3] = CREATE_READ_PROC("diskdrives-ch3", - proc_pdrv_ch3); - - /* - * Display a set of up to 10 logical drive through each of following - * /proc entries - */ - adapter->proc_rdrvstat[0] = CREATE_READ_PROC("raiddrives-0-9", - proc_rdrv_10); - adapter->proc_rdrvstat[1] = CREATE_READ_PROC("raiddrives-10-19", - proc_rdrv_20); - adapter->proc_rdrvstat[2] = CREATE_READ_PROC("raiddrives-20-29", - proc_rdrv_30); - adapter->proc_rdrvstat[3] = CREATE_READ_PROC("raiddrives-30-39", - proc_rdrv_40); -#endif -} - - -/** - * proc_read_config() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display configuration information about the controller. - */ -static int -proc_read_config(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - - adapter_t *adapter = (adapter_t *)data; - int len = 0; - - len += sprintf(page+len, "%s", MEGARAID_VERSION); - - if(adapter->product_info.product_name[0]) - len += sprintf(page+len, "%s\n", - adapter->product_info.product_name); - - len += sprintf(page+len, "Controller Type: "); - - if( adapter->flag & BOARD_MEMMAP ) { - len += sprintf(page+len, - "438/466/467/471/493/518/520/531/532\n"); - } - else { - len += sprintf(page+len, - "418/428/434\n"); - } - - if(adapter->flag & BOARD_40LD) { - len += sprintf(page+len, - "Controller Supports 40 Logical Drives\n"); - } - - if(adapter->flag & BOARD_64BIT) { - len += sprintf(page+len, - "Controller capable of 64-bit memory addressing\n"); - } - if( adapter->has_64bit_addr ) { - len += sprintf(page+len, - "Controller using 64-bit memory addressing\n"); - } - else { - len += sprintf(page+len, - "Controller is not using 64-bit memory addressing\n"); - } - - len += sprintf(page+len, "Base = %08lx, Irq = %d, ", adapter->base, - adapter->host->irq); - - len += sprintf(page+len, "Logical Drives = %d, Channels = %d\n", - adapter->numldrv, adapter->product_info.nchannels); - - len += sprintf(page+len, "Version =%s:%s, DRAM = %dMb\n", - adapter->fw_version, adapter->bios_version, - adapter->product_info.dram_size); - - len += sprintf(page+len, - "Controller Queue Depth = %d, Driver Queue Depth = %d\n", - adapter->product_info.max_commands, adapter->max_cmds); - - len += sprintf(page+len, "support_ext_cdb = %d\n", - adapter->support_ext_cdb); - len += sprintf(page+len, "support_random_del = %d\n", - adapter->support_random_del); - len += sprintf(page+len, "boot_ldrv_enabled = %d\n", - adapter->boot_ldrv_enabled); - len += sprintf(page+len, "boot_ldrv = %d\n", - adapter->boot_ldrv); - len += sprintf(page+len, "boot_pdrv_enabled = %d\n", - adapter->boot_pdrv_enabled); - len += sprintf(page+len, "boot_pdrv_ch = %d\n", - adapter->boot_pdrv_ch); - len += sprintf(page+len, "boot_pdrv_tgt = %d\n", - adapter->boot_pdrv_tgt); - len += sprintf(page+len, "quiescent = %d\n", - atomic_read(&adapter->quiescent)); - len += sprintf(page+len, "has_cluster = %d\n", - adapter->has_cluster); - - len += sprintf(page+len, "\nModule Parameters:\n"); - len += sprintf(page+len, "max_cmd_per_lun = %d\n", - max_cmd_per_lun); - len += sprintf(page+len, "max_sectors_per_io = %d\n", - max_sectors_per_io); - - *eof = 1; - - return len; -} - - - -/** - * proc_read_stat() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Diaplay statistical information about the I/O activity. - */ -static int -proc_read_stat(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter; - int len; - int i; - - i = 0; /* avoid compilation warnings */ - len = 0; - adapter = (adapter_t *)data; - - len = sprintf(page, "Statistical Information for this controller\n"); - len += sprintf(page+len, "pend_cmds = %d\n", - atomic_read(&adapter->pend_cmds)); -#if MEGA_HAVE_STATS - for(i = 0; i < adapter->numldrv; i++) { - len += sprintf(page+len, "Logical Drive %d:\n", i); - - len += sprintf(page+len, - "\tReads Issued = %lu, Writes Issued = %lu\n", - adapter->nreads[i], adapter->nwrites[i]); - - len += sprintf(page+len, - "\tSectors Read = %lu, Sectors Written = %lu\n", - adapter->nreadblocks[i], adapter->nwriteblocks[i]); - - len += sprintf(page+len, - "\tRead errors = %lu, Write errors = %lu\n\n", - adapter->rd_errors[i], adapter->wr_errors[i]); - } -#else - len += sprintf(page+len, - "IO and error counters not compiled in driver.\n"); -#endif - - *eof = 1; - - return len; -} - - -/** - * proc_read_mbox() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display mailbox information for the last command issued. This information - * is good for debugging. - */ -static int -proc_read_mbox(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - - adapter_t *adapter = (adapter_t *)data; - volatile mbox_t *mbox = adapter->mbox; - int len = 0; - - len = sprintf(page, "Contents of Mail Box Structure\n"); - len += sprintf(page+len, " Fw Command = 0x%02x\n", - mbox->m_out.cmd); - len += sprintf(page+len, " Cmd Sequence = 0x%02x\n", - mbox->m_out.cmdid); - len += sprintf(page+len, " No of Sectors= %04d\n", - mbox->m_out.numsectors); - len += sprintf(page+len, " LBA = 0x%02x\n", - mbox->m_out.lba); - len += sprintf(page+len, " DTA = 0x%08x\n", - mbox->m_out.xferaddr); - len += sprintf(page+len, " Logical Drive= 0x%02x\n", - mbox->m_out.logdrv); - len += sprintf(page+len, " No of SG Elmt= 0x%02x\n", - mbox->m_out.numsgelements); - len += sprintf(page+len, " Busy = %01x\n", - mbox->m_in.busy); - len += sprintf(page+len, " Status = 0x%02x\n", - mbox->m_in.status); - - *eof = 1; - - return len; -} - - -/** - * proc_rebuild_rate() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display current rebuild rate - */ -static int -proc_rebuild_rate(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - dma_addr_t dma_handle; - caddr_t inquiry; - struct pci_dev *pdev; - int len = 0; - - if( make_local_pdev(adapter, &pdev) != 0 ) { - *eof = 1; - return len; - } - - if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) { - free_local_pdev(pdev); - *eof = 1; - return len; - } - - if( mega_adapinq(adapter, dma_handle) != 0 ) { - - len = sprintf(page, "Adapter inquiry failed.\n"); - - printk(KERN_WARNING "megaraid: inquiry failed.\n"); - - mega_free_inquiry(inquiry, dma_handle, pdev); - - free_local_pdev(pdev); - - *eof = 1; - - return len; - } - - if( adapter->flag & BOARD_40LD ) { - len = sprintf(page, "Rebuild Rate: [%d%%]\n", - ((mega_inquiry3 *)inquiry)->rebuild_rate); - } - else { - len = sprintf(page, "Rebuild Rate: [%d%%]\n", - ((mraid_ext_inquiry *) - inquiry)->raid_inq.adapter_info.rebuild_rate); - } - - - mega_free_inquiry(inquiry, dma_handle, pdev); - - free_local_pdev(pdev); - - *eof = 1; - - return len; -} - - -/** - * proc_battery() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display information about the battery module on the controller. - */ -static int -proc_battery(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - dma_addr_t dma_handle; - caddr_t inquiry; - struct pci_dev *pdev; - u8 battery_status = 0; - char str[256]; - int len = 0; - - if( make_local_pdev(adapter, &pdev) != 0 ) { - *eof = 1; - return len; - } - - if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) { - free_local_pdev(pdev); - *eof = 1; - return len; - } - - if( mega_adapinq(adapter, dma_handle) != 0 ) { - - len = sprintf(page, "Adapter inquiry failed.\n"); - - printk(KERN_WARNING "megaraid: inquiry failed.\n"); - - mega_free_inquiry(inquiry, dma_handle, pdev); - - free_local_pdev(pdev); - - *eof = 1; - - return len; - } - - if( adapter->flag & BOARD_40LD ) { - battery_status = ((mega_inquiry3 *)inquiry)->battery_status; - } - else { - battery_status = ((mraid_ext_inquiry *)inquiry)-> - raid_inq.adapter_info.battery_status; - } - - /* - * Decode the battery status - */ - sprintf(str, "Battery Status:[%d]", battery_status); - - if(battery_status == MEGA_BATT_CHARGE_DONE) - strcat(str, " Charge Done"); - - if(battery_status & MEGA_BATT_MODULE_MISSING) - strcat(str, " Module Missing"); - - if(battery_status & MEGA_BATT_LOW_VOLTAGE) - strcat(str, " Low Voltage"); - - if(battery_status & MEGA_BATT_TEMP_HIGH) - strcat(str, " Temperature High"); - - if(battery_status & MEGA_BATT_PACK_MISSING) - strcat(str, " Pack Missing"); - - if(battery_status & MEGA_BATT_CHARGE_INPROG) - strcat(str, " Charge In-progress"); - - if(battery_status & MEGA_BATT_CHARGE_FAIL) - strcat(str, " Charge Fail"); - - if(battery_status & MEGA_BATT_CYCLES_EXCEEDED) - strcat(str, " Cycles Exceeded"); - - len = sprintf(page, "%s\n", str); - - - mega_free_inquiry(inquiry, dma_handle, pdev); - - free_local_pdev(pdev); - - *eof = 1; - - return len; -} - - -/** - * proc_pdrv_ch0() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display information about the physical drives on physical channel 0. - */ -static int -proc_pdrv_ch0(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - - *eof = 1; - - return (proc_pdrv(adapter, page, 0)); -} - - -/** - * proc_pdrv_ch1() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display information about the physical drives on physical channel 1. - */ -static int -proc_pdrv_ch1(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - - *eof = 1; - - return (proc_pdrv(adapter, page, 1)); -} - - -/** - * proc_pdrv_ch2() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display information about the physical drives on physical channel 2. - */ -static int -proc_pdrv_ch2(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - - *eof = 1; - - return (proc_pdrv(adapter, page, 2)); -} - - -/** - * proc_pdrv_ch3() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display information about the physical drives on physical channel 3. - */ -static int -proc_pdrv_ch3(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - - *eof = 1; - - return (proc_pdrv(adapter, page, 3)); -} - - -/** - * proc_pdrv() - * @page - buffer to write the data in - * @adapter - pointer to our soft state - * - * Display information about the physical drives. - */ -static int -proc_pdrv(adapter_t *adapter, char *page, int channel) -{ - dma_addr_t dma_handle; - char *scsi_inq; - dma_addr_t scsi_inq_dma_handle; - caddr_t inquiry; - struct pci_dev *pdev; - u8 *pdrv_state; - u8 state; - int tgt; - int max_channels; - int len = 0; - char str[80]; - int i; - - if( make_local_pdev(adapter, &pdev) != 0 ) { - return len; - } - - if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) { - goto free_pdev; - } - - if( mega_adapinq(adapter, dma_handle) != 0 ) { - len = sprintf(page, "Adapter inquiry failed.\n"); - - printk(KERN_WARNING "megaraid: inquiry failed.\n"); - - goto free_inquiry; - } - - - scsi_inq = pci_alloc_consistent(pdev, 256, &scsi_inq_dma_handle); - - if( scsi_inq == NULL ) { - len = sprintf(page, "memory not available for scsi inq.\n"); - - goto free_inquiry; - } - - if( adapter->flag & BOARD_40LD ) { - pdrv_state = ((mega_inquiry3 *)inquiry)->pdrv_state; - } - else { - pdrv_state = ((mraid_ext_inquiry *)inquiry)-> - raid_inq.pdrv_info.pdrv_state; - } - - max_channels = adapter->product_info.nchannels; - - if( channel >= max_channels ) { - goto free_pci; - } - - for( tgt = 0; tgt <= MAX_TARGET; tgt++ ) { - - i = channel*16 + tgt; - - state = *(pdrv_state + i); - - switch( state & 0x0F ) { - - case PDRV_ONLINE: - sprintf(str, - "Channel:%2d Id:%2d State: Online", - channel, tgt); - break; - - case PDRV_FAILED: - sprintf(str, - "Channel:%2d Id:%2d State: Failed", - channel, tgt); - break; - - case PDRV_RBLD: - sprintf(str, - "Channel:%2d Id:%2d State: Rebuild", - channel, tgt); - break; - - case PDRV_HOTSPARE: - sprintf(str, - "Channel:%2d Id:%2d State: Hot spare", - channel, tgt); - break; - - default: - sprintf(str, - "Channel:%2d Id:%2d State: Un-configured", - channel, tgt); - break; - - } - - /* - * This interface displays inquiries for disk drives - * only. Inquries for logical drives and non-disk - * devices are available through /proc/scsi/scsi - */ - memset(scsi_inq, 0, 256); - if( mega_internal_dev_inquiry(adapter, channel, tgt, - scsi_inq_dma_handle) || - (scsi_inq[0] & 0x1F) != TYPE_DISK ) { - continue; - } - - /* - * Check for overflow. We print less than 240 - * characters for inquiry - */ - if( (len + 240) >= PAGE_SIZE ) break; - - len += sprintf(page+len, "%s.\n", str); - - len += mega_print_inquiry(page+len, scsi_inq); - } - -free_pci: - pci_free_consistent(pdev, 256, scsi_inq, scsi_inq_dma_handle); -free_inquiry: - mega_free_inquiry(inquiry, dma_handle, pdev); -free_pdev: - free_local_pdev(pdev); - - return len; -} - - -/* - * Display scsi inquiry - */ -static int -mega_print_inquiry(char *page, char *scsi_inq) -{ - int len = 0; - int i; - - len = sprintf(page, " Vendor: "); - for( i = 8; i < 16; i++ ) { - len += sprintf(page+len, "%c", scsi_inq[i]); - } - - len += sprintf(page+len, " Model: "); - - for( i = 16; i < 32; i++ ) { - len += sprintf(page+len, "%c", scsi_inq[i]); - } - - len += sprintf(page+len, " Rev: "); - - for( i = 32; i < 36; i++ ) { - len += sprintf(page+len, "%c", scsi_inq[i]); - } - - len += sprintf(page+len, "\n"); - - i = scsi_inq[0] & 0x1f; - - len += sprintf(page+len, " Type: %s ", scsi_device_type(i)); - - len += sprintf(page+len, - " ANSI SCSI revision: %02x", scsi_inq[2] & 0x07); - - if( (scsi_inq[2] & 0x07) == 1 && (scsi_inq[3] & 0x0f) == 1 ) - len += sprintf(page+len, " CCS\n"); - else - len += sprintf(page+len, "\n"); - - return len; -} - - -/** - * proc_rdrv_10() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display real time information about the logical drives 0 through 9. - */ -static int -proc_rdrv_10(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - - *eof = 1; - - return (proc_rdrv(adapter, page, 0, 9)); -} - - -/** - * proc_rdrv_20() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display real time information about the logical drives 0 through 9. - */ -static int -proc_rdrv_20(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - - *eof = 1; - - return (proc_rdrv(adapter, page, 10, 19)); -} - - -/** - * proc_rdrv_30() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display real time information about the logical drives 0 through 9. - */ -static int -proc_rdrv_30(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - - *eof = 1; - - return (proc_rdrv(adapter, page, 20, 29)); -} - - -/** - * proc_rdrv_40() - * @page - buffer to write the data in - * @start - where the actual data has been written in page - * @offset - same meaning as the read system call - * @count - same meaning as the read system call - * @eof - set if no more data needs to be returned - * @data - pointer to our soft state - * - * Display real time information about the logical drives 0 through 9. - */ -static int -proc_rdrv_40(char *page, char **start, off_t offset, int count, int *eof, - void *data) -{ - adapter_t *adapter = (adapter_t *)data; - - *eof = 1; - - return (proc_rdrv(adapter, page, 30, 39)); -} - - -/** - * proc_rdrv() - * @page - buffer to write the data in - * @adapter - pointer to our soft state - * @start - starting logical drive to display - * @end - ending logical drive to display - * - * We do not print the inquiry information since its already available through - * /proc/scsi/scsi interface - */ -static int -proc_rdrv(adapter_t *adapter, char *page, int start, int end ) -{ - dma_addr_t dma_handle; - logdrv_param *lparam; - megacmd_t mc; - char *disk_array; - dma_addr_t disk_array_dma_handle; - caddr_t inquiry; - struct pci_dev *pdev; - u8 *rdrv_state; - int num_ldrv; - u32 array_sz; - int len = 0; - int i; - - if( make_local_pdev(adapter, &pdev) != 0 ) { - return len; - } - - if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) { - free_local_pdev(pdev); - return len; - } - - if( mega_adapinq(adapter, dma_handle) != 0 ) { - - len = sprintf(page, "Adapter inquiry failed.\n"); - - printk(KERN_WARNING "megaraid: inquiry failed.\n"); - - mega_free_inquiry(inquiry, dma_handle, pdev); - - free_local_pdev(pdev); - - return len; - } - - memset(&mc, 0, sizeof(megacmd_t)); - - if( adapter->flag & BOARD_40LD ) { - array_sz = sizeof(disk_array_40ld); - - rdrv_state = ((mega_inquiry3 *)inquiry)->ldrv_state; - - num_ldrv = ((mega_inquiry3 *)inquiry)->num_ldrv; - } - else { - array_sz = sizeof(disk_array_8ld); - - rdrv_state = ((mraid_ext_inquiry *)inquiry)-> - raid_inq.logdrv_info.ldrv_state; - - num_ldrv = ((mraid_ext_inquiry *)inquiry)-> - raid_inq.logdrv_info.num_ldrv; - } - - disk_array = pci_alloc_consistent(pdev, array_sz, - &disk_array_dma_handle); - - if( disk_array == NULL ) { - len = sprintf(page, "memory not available.\n"); - - mega_free_inquiry(inquiry, dma_handle, pdev); - - free_local_pdev(pdev); - - return len; - } - - mc.xferaddr = (u32)disk_array_dma_handle; - - if( adapter->flag & BOARD_40LD ) { - mc.cmd = FC_NEW_CONFIG; - mc.opcode = OP_DCMD_READ_CONFIG; - - if( mega_internal_command(adapter, &mc, NULL) ) { - - len = sprintf(page, "40LD read config failed.\n"); - - mega_free_inquiry(inquiry, dma_handle, pdev); - - pci_free_consistent(pdev, array_sz, disk_array, - disk_array_dma_handle); - - free_local_pdev(pdev); - - return len; - } - - } - else { - mc.cmd = NEW_READ_CONFIG_8LD; - - if( mega_internal_command(adapter, &mc, NULL) ) { - - mc.cmd = READ_CONFIG_8LD; - - if( mega_internal_command(adapter, &mc, - NULL) ){ - - len = sprintf(page, - "8LD read config failed.\n"); - - mega_free_inquiry(inquiry, dma_handle, pdev); - - pci_free_consistent(pdev, array_sz, - disk_array, - disk_array_dma_handle); - - free_local_pdev(pdev); - - return len; - } - } - } - - for( i = start; i < ( (end+1 < num_ldrv) ? end+1 : num_ldrv ); i++ ) { - - if( adapter->flag & BOARD_40LD ) { - lparam = - &((disk_array_40ld *)disk_array)->ldrv[i].lparam; - } - else { - lparam = - &((disk_array_8ld *)disk_array)->ldrv[i].lparam; - } - - /* - * Check for overflow. We print less than 240 characters for - * information about each logical drive. - */ - if( (len + 240) >= PAGE_SIZE ) break; - - len += sprintf(page+len, "Logical drive:%2d:, ", i); - - switch( rdrv_state[i] & 0x0F ) { - case RDRV_OFFLINE: - len += sprintf(page+len, "state: offline"); - break; - - case RDRV_DEGRADED: - len += sprintf(page+len, "state: degraded"); - break; - - case RDRV_OPTIMAL: - len += sprintf(page+len, "state: optimal"); - break; - - case RDRV_DELETED: - len += sprintf(page+len, "state: deleted"); - break; - - default: - len += sprintf(page+len, "state: unknown"); - break; - } - - /* - * Check if check consistency or initialization is going on - * for this logical drive. - */ - if( (rdrv_state[i] & 0xF0) == 0x20 ) { - len += sprintf(page+len, - ", check-consistency in progress"); - } - else if( (rdrv_state[i] & 0xF0) == 0x10 ) { - len += sprintf(page+len, - ", initialization in progress"); - } - - len += sprintf(page+len, "\n"); - - len += sprintf(page+len, "Span depth:%3d, ", - lparam->span_depth); - - len += sprintf(page+len, "RAID level:%3d, ", - lparam->level); - - len += sprintf(page+len, "Stripe size:%3d, ", - lparam->stripe_sz ? lparam->stripe_sz/2: 128); - - len += sprintf(page+len, "Row size:%3d\n", - lparam->row_size); - - - len += sprintf(page+len, "Read Policy: "); - - switch(lparam->read_ahead) { - - case NO_READ_AHEAD: - len += sprintf(page+len, "No read ahead, "); - break; - - case READ_AHEAD: - len += sprintf(page+len, "Read ahead, "); - break; - - case ADAP_READ_AHEAD: - len += sprintf(page+len, "Adaptive, "); - break; - - } - - len += sprintf(page+len, "Write Policy: "); - - switch(lparam->write_mode) { - - case WRMODE_WRITE_THRU: - len += sprintf(page+len, "Write thru, "); - break; - - case WRMODE_WRITE_BACK: - len += sprintf(page+len, "Write back, "); - break; - } - - len += sprintf(page+len, "Cache Policy: "); - - switch(lparam->direct_io) { - - case CACHED_IO: - len += sprintf(page+len, "Cached IO\n\n"); - break; - - case DIRECT_IO: - len += sprintf(page+len, "Direct IO\n\n"); - break; - } - } - - mega_free_inquiry(inquiry, dma_handle, pdev); - - pci_free_consistent(pdev, array_sz, disk_array, - disk_array_dma_handle); - - free_local_pdev(pdev); - - return len; -} -#else -static inline void mega_create_proc_entry(int index, struct proc_dir_entry *parent) -{ -} -#endif - - -/** - * megaraid_biosparam() - * - * Return the disk geometry for a particular disk - */ -static int -megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - adapter_t *adapter; - unsigned char *bh; - int heads; - int sectors; - int cylinders; - int rval; - - /* Get pointer to host config structure */ - adapter = (adapter_t *)sdev->host->hostdata; - - if (IS_RAID_CH(adapter, sdev->channel)) { - /* Default heads (64) & sectors (32) */ - heads = 64; - sectors = 32; - cylinders = (ulong)capacity / (heads * sectors); - - /* - * Handle extended translation size for logical drives - * > 1Gb - */ - if ((ulong)capacity >= 0x200000) { - heads = 255; - sectors = 63; - cylinders = (ulong)capacity / (heads * sectors); - } - - /* return result */ - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - } - else { - bh = scsi_bios_ptable(bdev); - - if( bh ) { - rval = scsi_partsize(bh, capacity, - &geom[2], &geom[0], &geom[1]); - kfree(bh); - if( rval != -1 ) - return rval; - } - - printk(KERN_INFO - "megaraid: invalid partition on this disk on channel %d\n", - sdev->channel); - - /* Default heads (64) & sectors (32) */ - heads = 64; - sectors = 32; - cylinders = (ulong)capacity / (heads * sectors); - - /* Handle extended translation size for logical drives > 1Gb */ - if ((ulong)capacity >= 0x200000) { - heads = 255; - sectors = 63; - cylinders = (ulong)capacity / (heads * sectors); - } - - /* return result */ - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - } - - return 0; -} - -/** - * mega_init_scb() - * @adapter - pointer to our soft state - * - * Allocate memory for the various pointers in the scb structures: - * scatter-gather list pointer, passthru and extended passthru structure - * pointers. - */ -static int -mega_init_scb(adapter_t *adapter) -{ - scb_t *scb; - int i; - - for( i = 0; i < adapter->max_cmds; i++ ) { - - scb = &adapter->scb_list[i]; - - scb->sgl64 = NULL; - scb->sgl = NULL; - scb->pthru = NULL; - scb->epthru = NULL; - } - - for( i = 0; i < adapter->max_cmds; i++ ) { - - scb = &adapter->scb_list[i]; - - scb->idx = i; - - scb->sgl64 = pci_alloc_consistent(adapter->dev, - sizeof(mega_sgl64) * adapter->sglen, - &scb->sgl_dma_addr); - - scb->sgl = (mega_sglist *)scb->sgl64; - - if( !scb->sgl ) { - printk(KERN_WARNING "RAID: Can't allocate sglist.\n"); - mega_free_sgl(adapter); - return -1; - } - - scb->pthru = pci_alloc_consistent(adapter->dev, - sizeof(mega_passthru), - &scb->pthru_dma_addr); - - if( !scb->pthru ) { - printk(KERN_WARNING "RAID: Can't allocate passthru.\n"); - mega_free_sgl(adapter); - return -1; - } - - scb->epthru = pci_alloc_consistent(adapter->dev, - sizeof(mega_ext_passthru), - &scb->epthru_dma_addr); - - if( !scb->epthru ) { - printk(KERN_WARNING - "Can't allocate extended passthru.\n"); - mega_free_sgl(adapter); - return -1; - } - - - scb->dma_type = MEGA_DMA_TYPE_NONE; - - /* - * Link to free list - * lock not required since we are loading the driver, so no - * commands possible right now. - */ - scb->state = SCB_FREE; - scb->cmd = NULL; - list_add(&scb->list, &adapter->free_list); - } - - return 0; -} - - -/** - * megadev_open() - * @inode - unused - * @filep - unused - * - * Routines for the character/ioctl interface to the driver. Find out if this - * is a valid open. - */ -static int -megadev_open (struct inode *inode, struct file *filep) -{ - /* - * Only allow superuser to access private ioctl interface - */ - if( !capable(CAP_SYS_ADMIN) ) return -EACCES; - - return 0; -} - - -/** - * megadev_ioctl() - * @inode - Our device inode - * @filep - unused - * @cmd - ioctl command - * @arg - user buffer - * - * ioctl entry point for our private ioctl interface. We move the data in from - * the user space, prepare the command (if necessary, convert the old MIMD - * ioctl to new ioctl command), and issue a synchronous command to the - * controller. - */ -static int -megadev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - adapter_t *adapter; - nitioctl_t uioc; - int adapno; - int rval; - mega_passthru __user *upthru; /* user address for passthru */ - mega_passthru *pthru; /* copy user passthru here */ - dma_addr_t pthru_dma_hndl; - void *data = NULL; /* data to be transferred */ - dma_addr_t data_dma_hndl; /* dma handle for data xfer area */ - megacmd_t mc; - megastat_t __user *ustats; - int num_ldrv; - u32 uxferaddr = 0; - struct pci_dev *pdev; - - ustats = NULL; /* avoid compilation warnings */ - num_ldrv = 0; - - /* - * Make sure only USCSICMD are issued through this interface. - * MIMD application would still fire different command. - */ - if( (_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD) ) { - return -EINVAL; - } - - /* - * Check and convert a possible MIMD command to NIT command. - * mega_m_to_n() copies the data from the user space, so we do not - * have to do it here. - * NOTE: We will need some user address to copyout the data, therefore - * the inteface layer will also provide us with the required user - * addresses. - */ - memset(&uioc, 0, sizeof(nitioctl_t)); - if( (rval = mega_m_to_n( (void __user *)arg, &uioc)) != 0 ) - return rval; - - - switch( uioc.opcode ) { - - case GET_DRIVER_VER: - if( put_user(driver_ver, (u32 __user *)uioc.uioc_uaddr) ) - return (-EFAULT); - - break; - - case GET_N_ADAP: - if( put_user(hba_count, (u32 __user *)uioc.uioc_uaddr) ) - return (-EFAULT); - - /* - * Shucks. MIMD interface returns a positive value for number - * of adapters. TODO: Change it to return 0 when there is no - * applicatio using mimd interface. - */ - return hba_count; - - case GET_ADAP_INFO: - - /* - * Which adapter - */ - if( (adapno = GETADAP(uioc.adapno)) >= hba_count ) - return (-ENODEV); - - if( copy_to_user(uioc.uioc_uaddr, mcontroller+adapno, - sizeof(struct mcontroller)) ) - return (-EFAULT); - break; - -#if MEGA_HAVE_STATS - - case GET_STATS: - /* - * Which adapter - */ - if( (adapno = GETADAP(uioc.adapno)) >= hba_count ) - return (-ENODEV); - - adapter = hba_soft_state[adapno]; - - ustats = uioc.uioc_uaddr; - - if( copy_from_user(&num_ldrv, &ustats->num_ldrv, sizeof(int)) ) - return (-EFAULT); - - /* - * Check for the validity of the logical drive number - */ - if( num_ldrv >= MAX_LOGICAL_DRIVES_40LD ) return -EINVAL; - - if( copy_to_user(ustats->nreads, adapter->nreads, - num_ldrv*sizeof(u32)) ) - return -EFAULT; - - if( copy_to_user(ustats->nreadblocks, adapter->nreadblocks, - num_ldrv*sizeof(u32)) ) - return -EFAULT; - - if( copy_to_user(ustats->nwrites, adapter->nwrites, - num_ldrv*sizeof(u32)) ) - return -EFAULT; - - if( copy_to_user(ustats->nwriteblocks, adapter->nwriteblocks, - num_ldrv*sizeof(u32)) ) - return -EFAULT; - - if( copy_to_user(ustats->rd_errors, adapter->rd_errors, - num_ldrv*sizeof(u32)) ) - return -EFAULT; - - if( copy_to_user(ustats->wr_errors, adapter->wr_errors, - num_ldrv*sizeof(u32)) ) - return -EFAULT; - - return 0; - -#endif - case MBOX_CMD: - - /* - * Which adapter - */ - if( (adapno = GETADAP(uioc.adapno)) >= hba_count ) - return (-ENODEV); - - adapter = hba_soft_state[adapno]; - - /* - * Deletion of logical drive is a special case. The adapter - * should be quiescent before this command is issued. - */ - if( uioc.uioc_rmbox[0] == FC_DEL_LOGDRV && - uioc.uioc_rmbox[2] == OP_DEL_LOGDRV ) { - - /* - * Do we support this feature - */ - if( !adapter->support_random_del ) { - printk(KERN_WARNING "megaraid: logdrv "); - printk("delete on non-supporting F/W.\n"); - - return (-EINVAL); - } - - rval = mega_del_logdrv( adapter, uioc.uioc_rmbox[3] ); - - if( rval == 0 ) { - memset(&mc, 0, sizeof(megacmd_t)); - - mc.status = rval; - - rval = mega_n_to_m((void __user *)arg, &mc); - } - - return rval; - } - /* - * This interface only support the regular passthru commands. - * Reject extended passthru and 64-bit passthru - */ - if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU64 || - uioc.uioc_rmbox[0] == MEGA_MBOXCMD_EXTPTHRU ) { - - printk(KERN_WARNING "megaraid: rejected passthru.\n"); - - return (-EINVAL); - } - - /* - * For all internal commands, the buffer must be allocated in - * <4GB address range - */ - if( make_local_pdev(adapter, &pdev) != 0 ) - return -EIO; - - /* Is it a passthru command or a DCMD */ - if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU ) { - /* Passthru commands */ - - pthru = pci_alloc_consistent(pdev, - sizeof(mega_passthru), - &pthru_dma_hndl); - - if( pthru == NULL ) { - free_local_pdev(pdev); - return (-ENOMEM); - } - - /* - * The user passthru structure - */ - upthru = (mega_passthru __user *)(unsigned long)MBOX(uioc)->xferaddr; - - /* - * Copy in the user passthru here. - */ - if( copy_from_user(pthru, upthru, - sizeof(mega_passthru)) ) { - - pci_free_consistent(pdev, - sizeof(mega_passthru), pthru, - pthru_dma_hndl); - - free_local_pdev(pdev); - - return (-EFAULT); - } - - /* - * Is there a data transfer - */ - if( pthru->dataxferlen ) { - data = pci_alloc_consistent(pdev, - pthru->dataxferlen, - &data_dma_hndl); - - if( data == NULL ) { - pci_free_consistent(pdev, - sizeof(mega_passthru), - pthru, - pthru_dma_hndl); - - free_local_pdev(pdev); - - return (-ENOMEM); - } - - /* - * Save the user address and point the kernel - * address at just allocated memory - */ - uxferaddr = pthru->dataxferaddr; - pthru->dataxferaddr = data_dma_hndl; - } - - - /* - * Is data coming down-stream - */ - if( pthru->dataxferlen && (uioc.flags & UIOC_WR) ) { - /* - * Get the user data - */ - if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr, - pthru->dataxferlen) ) { - rval = (-EFAULT); - goto freemem_and_return; - } - } - - memset(&mc, 0, sizeof(megacmd_t)); - - mc.cmd = MEGA_MBOXCMD_PASSTHRU; - mc.xferaddr = (u32)pthru_dma_hndl; - - /* - * Issue the command - */ - mega_internal_command(adapter, &mc, pthru); - - rval = mega_n_to_m((void __user *)arg, &mc); - - if( rval ) goto freemem_and_return; - - - /* - * Is data going up-stream - */ - if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) { - if( copy_to_user((char __user *)(unsigned long) uxferaddr, data, - pthru->dataxferlen) ) { - rval = (-EFAULT); - } - } - - /* - * Send the request sense data also, irrespective of - * whether the user has asked for it or not. - */ - if (copy_to_user(upthru->reqsensearea, - pthru->reqsensearea, 14)) - rval = -EFAULT; - -freemem_and_return: - if( pthru->dataxferlen ) { - pci_free_consistent(pdev, - pthru->dataxferlen, data, - data_dma_hndl); - } - - pci_free_consistent(pdev, sizeof(mega_passthru), - pthru, pthru_dma_hndl); - - free_local_pdev(pdev); - - return rval; - } - else { - /* DCMD commands */ - - /* - * Is there a data transfer - */ - if( uioc.xferlen ) { - data = pci_alloc_consistent(pdev, - uioc.xferlen, &data_dma_hndl); - - if( data == NULL ) { - free_local_pdev(pdev); - return (-ENOMEM); - } - - uxferaddr = MBOX(uioc)->xferaddr; - } - - /* - * Is data coming down-stream - */ - if( uioc.xferlen && (uioc.flags & UIOC_WR) ) { - /* - * Get the user data - */ - if( copy_from_user(data, (char __user *)(unsigned long) uxferaddr, - uioc.xferlen) ) { - - pci_free_consistent(pdev, - uioc.xferlen, - data, data_dma_hndl); - - free_local_pdev(pdev); - - return (-EFAULT); - } - } - - memcpy(&mc, MBOX(uioc), sizeof(megacmd_t)); - - mc.xferaddr = (u32)data_dma_hndl; - - /* - * Issue the command - */ - mega_internal_command(adapter, &mc, NULL); - - rval = mega_n_to_m((void __user *)arg, &mc); - - if( rval ) { - if( uioc.xferlen ) { - pci_free_consistent(pdev, - uioc.xferlen, data, - data_dma_hndl); - } - - free_local_pdev(pdev); - - return rval; - } - - /* - * Is data going up-stream - */ - if( uioc.xferlen && (uioc.flags & UIOC_RD) ) { - if( copy_to_user((char __user *)(unsigned long) uxferaddr, data, - uioc.xferlen) ) { - - rval = (-EFAULT); - } - } - - if( uioc.xferlen ) { - pci_free_consistent(pdev, - uioc.xferlen, data, - data_dma_hndl); - } - - free_local_pdev(pdev); - - return rval; - } - - default: - return (-EINVAL); - } - - return 0; -} - -static long -megadev_unlocked_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - int ret; - - mutex_lock(&megadev_mutex); - ret = megadev_ioctl(filep, cmd, arg); - mutex_unlock(&megadev_mutex); - - return ret; -} - -/** - * mega_m_to_n() - * @arg - user address - * @uioc - new ioctl structure - * - * A thin layer to convert older mimd interface ioctl structure to NIT ioctl - * structure - * - * Converts the older mimd ioctl structure to newer NIT structure - */ -static int -mega_m_to_n(void __user *arg, nitioctl_t *uioc) -{ - struct uioctl_t uioc_mimd; - char signature[8] = {0}; - u8 opcode; - u8 subopcode; - - - /* - * check is the application conforms to NIT. We do not have to do much - * in that case. - * We exploit the fact that the signature is stored in the very - * beginning of the structure. - */ - - if( copy_from_user(signature, arg, 7) ) - return (-EFAULT); - - if( memcmp(signature, "MEGANIT", 7) == 0 ) { - - /* - * NOTE NOTE: The nit ioctl is still under flux because of - * change of mailbox definition, in HPE. No applications yet - * use this interface and let's not have applications use this - * interface till the new specifitions are in place. - */ - return -EINVAL; -#if 0 - if( copy_from_user(uioc, arg, sizeof(nitioctl_t)) ) - return (-EFAULT); - return 0; -#endif - } - - /* - * Else assume we have mimd uioctl_t as arg. Convert to nitioctl_t - * - * Get the user ioctl structure - */ - if( copy_from_user(&uioc_mimd, arg, sizeof(struct uioctl_t)) ) - return (-EFAULT); - - - /* - * Get the opcode and subopcode for the commands - */ - opcode = uioc_mimd.ui.fcs.opcode; - subopcode = uioc_mimd.ui.fcs.subopcode; - - switch (opcode) { - case 0x82: - - switch (subopcode) { - - case MEGAIOC_QDRVRVER: /* Query driver version */ - uioc->opcode = GET_DRIVER_VER; - uioc->uioc_uaddr = uioc_mimd.data; - break; - - case MEGAIOC_QNADAP: /* Get # of adapters */ - uioc->opcode = GET_N_ADAP; - uioc->uioc_uaddr = uioc_mimd.data; - break; - - case MEGAIOC_QADAPINFO: /* Get adapter information */ - uioc->opcode = GET_ADAP_INFO; - uioc->adapno = uioc_mimd.ui.fcs.adapno; - uioc->uioc_uaddr = uioc_mimd.data; - break; - - default: - return(-EINVAL); - } - - break; - - - case 0x81: - - uioc->opcode = MBOX_CMD; - uioc->adapno = uioc_mimd.ui.fcs.adapno; - - memcpy(uioc->uioc_rmbox, uioc_mimd.mbox, 18); - - uioc->xferlen = uioc_mimd.ui.fcs.length; - - if( uioc_mimd.outlen ) uioc->flags = UIOC_RD; - if( uioc_mimd.inlen ) uioc->flags |= UIOC_WR; - - break; - - case 0x80: - - uioc->opcode = MBOX_CMD; - uioc->adapno = uioc_mimd.ui.fcs.adapno; - - memcpy(uioc->uioc_rmbox, uioc_mimd.mbox, 18); - - /* - * Choose the xferlen bigger of input and output data - */ - uioc->xferlen = uioc_mimd.outlen > uioc_mimd.inlen ? - uioc_mimd.outlen : uioc_mimd.inlen; - - if( uioc_mimd.outlen ) uioc->flags = UIOC_RD; - if( uioc_mimd.inlen ) uioc->flags |= UIOC_WR; - - break; - - default: - return (-EINVAL); - - } - - return 0; -} - -/* - * mega_n_to_m() - * @arg - user address - * @mc - mailbox command - * - * Updates the status information to the application, depending on application - * conforms to older mimd ioctl interface or newer NIT ioctl interface - */ -static int -mega_n_to_m(void __user *arg, megacmd_t *mc) -{ - nitioctl_t __user *uiocp; - megacmd_t __user *umc; - mega_passthru __user *upthru; - struct uioctl_t __user *uioc_mimd; - char signature[8] = {0}; - - /* - * check is the application conforms to NIT. - */ - if( copy_from_user(signature, arg, 7) ) - return -EFAULT; - - if( memcmp(signature, "MEGANIT", 7) == 0 ) { - - uiocp = arg; - - if( put_user(mc->status, (u8 __user *)&MBOX_P(uiocp)->status) ) - return (-EFAULT); - - if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) { - - umc = MBOX_P(uiocp); - - if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr)) - return -EFAULT; - - if( put_user(mc->status, (u8 __user *)&upthru->scsistatus)) - return (-EFAULT); - } - } - else { - uioc_mimd = arg; - - if( put_user(mc->status, (u8 __user *)&uioc_mimd->mbox[17]) ) - return (-EFAULT); - - if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) { - - umc = (megacmd_t __user *)uioc_mimd->mbox; - - if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr)) - return (-EFAULT); - - if( put_user(mc->status, (u8 __user *)&upthru->scsistatus) ) - return (-EFAULT); - } - } - - return 0; -} - - -/* - * MEGARAID 'FW' commands. - */ - -/** - * mega_is_bios_enabled() - * @adapter - pointer to our soft state - * - * issue command to find out if the BIOS is enabled for this controller - */ -static int -mega_is_bios_enabled(adapter_t *adapter) -{ - unsigned char raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox; - int ret; - - mbox = (mbox_t *)raw_mbox; - - memset(&mbox->m_out, 0, sizeof(raw_mbox)); - - memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - - mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; - - raw_mbox[0] = IS_BIOS_ENABLED; - raw_mbox[2] = GET_BIOS; - - - ret = issue_scb_block(adapter, raw_mbox); - - return *(char *)adapter->mega_buffer; -} - - -/** - * mega_enum_raid_scsi() - * @adapter - pointer to our soft state - * - * Find out what channels are RAID/SCSI. This information is used to - * differentiate the virtual channels and physical channels and to support - * ROMB feature and non-disk devices. - */ -static void -mega_enum_raid_scsi(adapter_t *adapter) -{ - unsigned char raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox; - int i; - - mbox = (mbox_t *)raw_mbox; - - memset(&mbox->m_out, 0, sizeof(raw_mbox)); - - /* - * issue command to find out what channels are raid/scsi - */ - raw_mbox[0] = CHNL_CLASS; - raw_mbox[2] = GET_CHNL_CLASS; - - memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - - mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; - - /* - * Non-ROMB firmware fail this command, so all channels - * must be shown RAID - */ - adapter->mega_ch_class = 0xFF; - - if(!issue_scb_block(adapter, raw_mbox)) { - adapter->mega_ch_class = *((char *)adapter->mega_buffer); - - } - - for( i = 0; i < adapter->product_info.nchannels; i++ ) { - if( (adapter->mega_ch_class >> i) & 0x01 ) { - printk(KERN_INFO "megaraid: channel[%d] is raid.\n", - i); - } - else { - printk(KERN_INFO "megaraid: channel[%d] is scsi.\n", - i); - } - } - - return; -} - - -/** - * mega_get_boot_drv() - * @adapter - pointer to our soft state - * - * Find out which device is the boot device. Note, any logical drive or any - * phyical device (e.g., a CDROM) can be designated as a boot device. - */ -static void -mega_get_boot_drv(adapter_t *adapter) -{ - struct private_bios_data *prv_bios_data; - unsigned char raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox; - u16 cksum = 0; - u8 *cksum_p; - u8 boot_pdrv; - int i; - - mbox = (mbox_t *)raw_mbox; - - memset(&mbox->m_out, 0, sizeof(raw_mbox)); - - raw_mbox[0] = BIOS_PVT_DATA; - raw_mbox[2] = GET_BIOS_PVT_DATA; - - memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - - mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; - - adapter->boot_ldrv_enabled = 0; - adapter->boot_ldrv = 0; - - adapter->boot_pdrv_enabled = 0; - adapter->boot_pdrv_ch = 0; - adapter->boot_pdrv_tgt = 0; - - if(issue_scb_block(adapter, raw_mbox) == 0) { - prv_bios_data = - (struct private_bios_data *)adapter->mega_buffer; - - cksum = 0; - cksum_p = (char *)prv_bios_data; - for (i = 0; i < 14; i++ ) { - cksum += (u16)(*cksum_p++); - } - - if (prv_bios_data->cksum == (u16)(0-cksum) ) { - - /* - * If MSB is set, a physical drive is set as boot - * device - */ - if( prv_bios_data->boot_drv & 0x80 ) { - adapter->boot_pdrv_enabled = 1; - boot_pdrv = prv_bios_data->boot_drv & 0x7F; - adapter->boot_pdrv_ch = boot_pdrv / 16; - adapter->boot_pdrv_tgt = boot_pdrv % 16; - } - else { - adapter->boot_ldrv_enabled = 1; - adapter->boot_ldrv = prv_bios_data->boot_drv; - } - } - } - -} - -/** - * mega_support_random_del() - * @adapter - pointer to our soft state - * - * Find out if this controller supports random deletion and addition of - * logical drives - */ -static int -mega_support_random_del(adapter_t *adapter) -{ - unsigned char raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox; - int rval; - - mbox = (mbox_t *)raw_mbox; - - memset(&mbox->m_out, 0, sizeof(raw_mbox)); - - /* - * issue command - */ - raw_mbox[0] = FC_DEL_LOGDRV; - raw_mbox[2] = OP_SUP_DEL_LOGDRV; - - rval = issue_scb_block(adapter, raw_mbox); - - return !rval; -} - - -/** - * mega_support_ext_cdb() - * @adapter - pointer to our soft state - * - * Find out if this firmware support cdblen > 10 - */ -static int -mega_support_ext_cdb(adapter_t *adapter) -{ - unsigned char raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox; - int rval; - - mbox = (mbox_t *)raw_mbox; - - memset(&mbox->m_out, 0, sizeof(raw_mbox)); - /* - * issue command to find out if controller supports extended CDBs. - */ - raw_mbox[0] = 0xA4; - raw_mbox[2] = 0x16; - - rval = issue_scb_block(adapter, raw_mbox); - - return !rval; -} - - -/** - * mega_del_logdrv() - * @adapter - pointer to our soft state - * @logdrv - logical drive to be deleted - * - * Delete the specified logical drive. It is the responsibility of the user - * app to let the OS know about this operation. - */ -static int -mega_del_logdrv(adapter_t *adapter, int logdrv) -{ - unsigned long flags; - scb_t *scb; - int rval; - - /* - * Stop sending commands to the controller, queue them internally. - * When deletion is complete, ISR will flush the queue. - */ - atomic_set(&adapter->quiescent, 1); - - /* - * Wait till all the issued commands are complete and there are no - * commands in the pending queue - */ - while (atomic_read(&adapter->pend_cmds) > 0 || - !list_empty(&adapter->pending_list)) - msleep(1000); /* sleep for 1s */ - - rval = mega_do_del_logdrv(adapter, logdrv); - - spin_lock_irqsave(&adapter->lock, flags); - - /* - * If delete operation was successful, add 0x80 to the logical drive - * ids for commands in the pending queue. - */ - if (adapter->read_ldidmap) { - struct list_head *pos; - list_for_each(pos, &adapter->pending_list) { - scb = list_entry(pos, scb_t, list); - if (scb->pthru->logdrv < 0x80 ) - scb->pthru->logdrv += 0x80; - } - } - - atomic_set(&adapter->quiescent, 0); - - mega_runpendq(adapter); - - spin_unlock_irqrestore(&adapter->lock, flags); - - return rval; -} - - -static int -mega_do_del_logdrv(adapter_t *adapter, int logdrv) -{ - megacmd_t mc; - int rval; - - memset( &mc, 0, sizeof(megacmd_t)); - - mc.cmd = FC_DEL_LOGDRV; - mc.opcode = OP_DEL_LOGDRV; - mc.subopcode = logdrv; - - rval = mega_internal_command(adapter, &mc, NULL); - - /* log this event */ - if(rval) { - printk(KERN_WARNING "megaraid: Delete LD-%d failed.", logdrv); - return rval; - } - - /* - * After deleting first logical drive, the logical drives must be - * addressed by adding 0x80 to the logical drive id. - */ - adapter->read_ldidmap = 1; - - return rval; -} - - -/** - * mega_get_max_sgl() - * @adapter - pointer to our soft state - * - * Find out the maximum number of scatter-gather elements supported by this - * version of the firmware - */ -static void -mega_get_max_sgl(adapter_t *adapter) -{ - unsigned char raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox; - - mbox = (mbox_t *)raw_mbox; - - memset(mbox, 0, sizeof(raw_mbox)); - - memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - - mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; - - raw_mbox[0] = MAIN_MISC_OPCODE; - raw_mbox[2] = GET_MAX_SG_SUPPORT; - - - if( issue_scb_block(adapter, raw_mbox) ) { - /* - * f/w does not support this command. Choose the default value - */ - adapter->sglen = MIN_SGLIST; - } - else { - adapter->sglen = *((char *)adapter->mega_buffer); - - /* - * Make sure this is not more than the resources we are - * planning to allocate - */ - if ( adapter->sglen > MAX_SGLIST ) - adapter->sglen = MAX_SGLIST; - } - - return; -} - - -/** - * mega_support_cluster() - * @adapter - pointer to our soft state - * - * Find out if this firmware support cluster calls. - */ -static int -mega_support_cluster(adapter_t *adapter) -{ - unsigned char raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox; - - mbox = (mbox_t *)raw_mbox; - - memset(mbox, 0, sizeof(raw_mbox)); - - memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - - mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle; - - /* - * Try to get the initiator id. This command will succeed iff the - * clustering is available on this HBA. - */ - raw_mbox[0] = MEGA_GET_TARGET_ID; - - if( issue_scb_block(adapter, raw_mbox) == 0 ) { - - /* - * Cluster support available. Get the initiator target id. - * Tell our id to mid-layer too. - */ - adapter->this_id = *(u32 *)adapter->mega_buffer; - adapter->host->this_id = adapter->this_id; - - return 1; - } - - return 0; -} - -#ifdef CONFIG_PROC_FS -/** - * mega_adapinq() - * @adapter - pointer to our soft state - * @dma_handle - DMA address of the buffer - * - * Issue internal commands while interrupts are available. - * We only issue direct mailbox commands from within the driver. ioctl() - * interface using these routines can issue passthru commands. - */ -static int -mega_adapinq(adapter_t *adapter, dma_addr_t dma_handle) -{ - megacmd_t mc; - - memset(&mc, 0, sizeof(megacmd_t)); - - if( adapter->flag & BOARD_40LD ) { - mc.cmd = FC_NEW_CONFIG; - mc.opcode = NC_SUBOP_ENQUIRY3; - mc.subopcode = ENQ3_GET_SOLICITED_FULL; - } - else { - mc.cmd = MEGA_MBOXCMD_ADPEXTINQ; - } - - mc.xferaddr = (u32)dma_handle; - - if ( mega_internal_command(adapter, &mc, NULL) != 0 ) { - return -1; - } - - return 0; -} - - -/** mega_internal_dev_inquiry() - * @adapter - pointer to our soft state - * @ch - channel for this device - * @tgt - ID of this device - * @buf_dma_handle - DMA address of the buffer - * - * Issue the scsi inquiry for the specified device. - */ -static int -mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt, - dma_addr_t buf_dma_handle) -{ - mega_passthru *pthru; - dma_addr_t pthru_dma_handle; - megacmd_t mc; - int rval; - struct pci_dev *pdev; - - - /* - * For all internal commands, the buffer must be allocated in <4GB - * address range - */ - if( make_local_pdev(adapter, &pdev) != 0 ) return -1; - - pthru = pci_alloc_consistent(pdev, sizeof(mega_passthru), - &pthru_dma_handle); - - if( pthru == NULL ) { - free_local_pdev(pdev); - return -1; - } - - pthru->timeout = 2; - pthru->ars = 1; - pthru->reqsenselen = 14; - pthru->islogical = 0; - - pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : ch; - - pthru->target = (adapter->flag & BOARD_40LD) ? (ch << 4)|tgt : tgt; - - pthru->cdblen = 6; - - pthru->cdb[0] = INQUIRY; - pthru->cdb[1] = 0; - pthru->cdb[2] = 0; - pthru->cdb[3] = 0; - pthru->cdb[4] = 255; - pthru->cdb[5] = 0; - - - pthru->dataxferaddr = (u32)buf_dma_handle; - pthru->dataxferlen = 256; - - memset(&mc, 0, sizeof(megacmd_t)); - - mc.cmd = MEGA_MBOXCMD_PASSTHRU; - mc.xferaddr = (u32)pthru_dma_handle; - - rval = mega_internal_command(adapter, &mc, pthru); - - pci_free_consistent(pdev, sizeof(mega_passthru), pthru, - pthru_dma_handle); - - free_local_pdev(pdev); - - return rval; -} -#endif - -/** - * mega_internal_command() - * @adapter - pointer to our soft state - * @mc - the mailbox command - * @pthru - Passthru structure for DCDB commands - * - * Issue the internal commands in interrupt mode. - * The last argument is the address of the passthru structure if the command - * to be fired is a passthru command - * - * lockscope specifies whether the caller has already acquired the lock. Of - * course, the caller must know which lock we are talking about. - * - * Note: parameter 'pthru' is null for non-passthru commands. - */ -static int -mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru) -{ - Scsi_Cmnd *scmd; - struct scsi_device *sdev; - scb_t *scb; - int rval; - - scmd = scsi_allocate_command(GFP_KERNEL); - if (!scmd) - return -ENOMEM; - - /* - * The internal commands share one command id and hence are - * serialized. This is so because we want to reserve maximum number of - * available command ids for the I/O commands. - */ - mutex_lock(&adapter->int_mtx); - - scb = &adapter->int_scb; - memset(scb, 0, sizeof(scb_t)); - - sdev = kzalloc(sizeof(struct scsi_device), GFP_KERNEL); - scmd->device = sdev; - - memset(adapter->int_cdb, 0, sizeof(adapter->int_cdb)); - scmd->cmnd = adapter->int_cdb; - scmd->device->host = adapter->host; - scmd->host_scribble = (void *)scb; - scmd->cmnd[0] = MEGA_INTERNAL_CMD; - - scb->state |= SCB_ACTIVE; - scb->cmd = scmd; - - memcpy(scb->raw_mbox, mc, sizeof(megacmd_t)); - - /* - * Is it a passthru command - */ - if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) { - - scb->pthru = pthru; - } - - scb->idx = CMDID_INT_CMDS; - - megaraid_queue_lck(scmd, mega_internal_done); - - wait_for_completion(&adapter->int_waitq); - - rval = scmd->result; - mc->status = scmd->result; - kfree(sdev); - - /* - * Print a debug message for all failed commands. Applications can use - * this information. - */ - if( scmd->result && trace_level ) { - printk("megaraid: cmd [%x, %x, %x] status:[%x]\n", - mc->cmd, mc->opcode, mc->subopcode, scmd->result); - } - - mutex_unlock(&adapter->int_mtx); - - scsi_free_command(GFP_KERNEL, scmd); - - return rval; -} - - -/** - * mega_internal_done() - * @scmd - internal scsi command - * - * Callback routine for internal commands. - */ -static void -mega_internal_done(Scsi_Cmnd *scmd) -{ - adapter_t *adapter; - - adapter = (adapter_t *)scmd->device->host->hostdata; - - complete(&adapter->int_waitq); - -} - - -static struct scsi_host_template megaraid_template = { - .module = THIS_MODULE, - .name = "MegaRAID", - .proc_name = "megaraid_legacy", - .info = megaraid_info, - .queuecommand = megaraid_queue, - .bios_param = megaraid_biosparam, - .max_sectors = MAX_SECTORS_PER_IO, - .can_queue = MAX_COMMANDS, - .this_id = DEFAULT_INITIATOR_ID, - .sg_tablesize = MAX_SGLIST, - .cmd_per_lun = DEF_CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .eh_abort_handler = megaraid_abort, - .eh_device_reset_handler = megaraid_reset, - .eh_bus_reset_handler = megaraid_reset, - .eh_host_reset_handler = megaraid_reset, -}; - -static int __devinit -megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct Scsi_Host *host; - adapter_t *adapter; - unsigned long mega_baseport, tbase, flag = 0; - u16 subsysid, subsysvid; - u8 pci_bus, pci_dev_func; - int irq, i, j; - int error = -ENODEV; - - if (pci_enable_device(pdev)) - goto out; - pci_set_master(pdev); - - pci_bus = pdev->bus->number; - pci_dev_func = pdev->devfn; - - /* - * The megaraid3 stuff reports the ID of the Intel part which is not - * remotely specific to the megaraid - */ - if (pdev->vendor == PCI_VENDOR_ID_INTEL) { - u16 magic; - /* - * Don't fall over the Compaq management cards using the same - * PCI identifier - */ - if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ && - pdev->subsystem_device == 0xC000) - return -ENODEV; - /* Now check the magic signature byte */ - pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic); - if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE) - return -ENODEV; - /* Ok it is probably a megaraid */ - } - - /* - * For these vendor and device ids, signature offsets are not - * valid and 64 bit is implicit - */ - if (id->driver_data & BOARD_64BIT) - flag |= BOARD_64BIT; - else { - u32 magic64; - - pci_read_config_dword(pdev, PCI_CONF_AMISIG64, &magic64); - if (magic64 == HBA_SIGNATURE_64BIT) - flag |= BOARD_64BIT; - } - - subsysvid = pdev->subsystem_vendor; - subsysid = pdev->subsystem_device; - - printk(KERN_NOTICE "megaraid: found 0x%4.04x:0x%4.04x:bus %d:", - id->vendor, id->device, pci_bus); - - printk("slot %d:func %d\n", - PCI_SLOT(pci_dev_func), PCI_FUNC(pci_dev_func)); - - /* Read the base port and IRQ from PCI */ - mega_baseport = pci_resource_start(pdev, 0); - irq = pdev->irq; - - tbase = mega_baseport; - if (pci_resource_flags(pdev, 0) & IORESOURCE_MEM) { - flag |= BOARD_MEMMAP; - - if (!request_mem_region(mega_baseport, 128, "megaraid")) { - printk(KERN_WARNING "megaraid: mem region busy!\n"); - goto out_disable_device; - } - - mega_baseport = (unsigned long)ioremap(mega_baseport, 128); - if (!mega_baseport) { - printk(KERN_WARNING - "megaraid: could not map hba memory\n"); - goto out_release_region; - } - } else { - flag |= BOARD_IOMAP; - mega_baseport += 0x10; - - if (!request_region(mega_baseport, 16, "megaraid")) - goto out_disable_device; - } - - /* Initialize SCSI Host structure */ - host = scsi_host_alloc(&megaraid_template, sizeof(adapter_t)); - if (!host) - goto out_iounmap; - - adapter = (adapter_t *)host->hostdata; - memset(adapter, 0, sizeof(adapter_t)); - - printk(KERN_NOTICE - "scsi%d:Found MegaRAID controller at 0x%lx, IRQ:%d\n", - host->host_no, mega_baseport, irq); - - adapter->base = mega_baseport; - if (flag & BOARD_MEMMAP) - adapter->mmio_base = (void __iomem *) mega_baseport; - - INIT_LIST_HEAD(&adapter->free_list); - INIT_LIST_HEAD(&adapter->pending_list); - INIT_LIST_HEAD(&adapter->completed_list); - - adapter->flag = flag; - spin_lock_init(&adapter->lock); - - host->cmd_per_lun = max_cmd_per_lun; - host->max_sectors = max_sectors_per_io; - - adapter->dev = pdev; - adapter->host = host; - - adapter->host->irq = irq; - - if (flag & BOARD_MEMMAP) - adapter->host->base = tbase; - else { - adapter->host->io_port = tbase; - adapter->host->n_io_port = 16; - } - - adapter->host->unique_id = (pci_bus << 8) | pci_dev_func; - - /* - * Allocate buffer to issue internal commands. - */ - adapter->mega_buffer = pci_alloc_consistent(adapter->dev, - MEGA_BUFFER_SIZE, &adapter->buf_dma_handle); - if (!adapter->mega_buffer) { - printk(KERN_WARNING "megaraid: out of RAM.\n"); - goto out_host_put; - } - - adapter->scb_list = kmalloc(sizeof(scb_t) * MAX_COMMANDS, GFP_KERNEL); - if (!adapter->scb_list) { - printk(KERN_WARNING "megaraid: out of RAM.\n"); - goto out_free_cmd_buffer; - } - - if (request_irq(irq, (adapter->flag & BOARD_MEMMAP) ? - megaraid_isr_memmapped : megaraid_isr_iomapped, - IRQF_SHARED, "megaraid", adapter)) { - printk(KERN_WARNING - "megaraid: Couldn't register IRQ %d!\n", irq); - goto out_free_scb_list; - } - - if (mega_setup_mailbox(adapter)) - goto out_free_irq; - - if (mega_query_adapter(adapter)) - goto out_free_mbox; - - /* - * Have checks for some buggy f/w - */ - if ((subsysid == 0x1111) && (subsysvid == 0x1111)) { - /* - * Which firmware - */ - if (!strcmp(adapter->fw_version, "3.00") || - !strcmp(adapter->fw_version, "3.01")) { - - printk( KERN_WARNING - "megaraid: Your card is a Dell PERC " - "2/SC RAID controller with " - "firmware\nmegaraid: 3.00 or 3.01. " - "This driver is known to have " - "corruption issues\nmegaraid: with " - "those firmware versions on this " - "specific card. In order\nmegaraid: " - "to protect your data, please upgrade " - "your firmware to version\nmegaraid: " - "3.10 or later, available from the " - "Dell Technical Support web\n" - "megaraid: site at\nhttp://support." - "dell.com/us/en/filelib/download/" - "index.asp?fileid=2940\n" - ); - } - } - - /* - * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with - * firmware H.01.07, H.01.08, and H.01.09 disable 64 bit - * support, since this firmware cannot handle 64 bit - * addressing - */ - if ((subsysvid == HP_SUBSYS_VID) && - ((subsysid == 0x60E7) || (subsysid == 0x60E8))) { - /* - * which firmware - */ - if (!strcmp(adapter->fw_version, "H01.07") || - !strcmp(adapter->fw_version, "H01.08") || - !strcmp(adapter->fw_version, "H01.09") ) { - printk(KERN_WARNING - "megaraid: Firmware H.01.07, " - "H.01.08, and H.01.09 on 1M/2M " - "controllers\n" - "megaraid: do not support 64 bit " - "addressing.\nmegaraid: DISABLING " - "64 bit support.\n"); - adapter->flag &= ~BOARD_64BIT; - } - } - - if (mega_is_bios_enabled(adapter)) - mega_hbas[hba_count].is_bios_enabled = 1; - mega_hbas[hba_count].hostdata_addr = adapter; - - /* - * Find out which channel is raid and which is scsi. This is - * for ROMB support. - */ - mega_enum_raid_scsi(adapter); - - /* - * Find out if a logical drive is set as the boot drive. If - * there is one, will make that as the first logical drive. - * ROMB: Do we have to boot from a physical drive. Then all - * the physical drives would appear before the logical disks. - * Else, all the physical drives would be exported to the mid - * layer after logical drives. - */ - mega_get_boot_drv(adapter); - - if (adapter->boot_pdrv_enabled) { - j = adapter->product_info.nchannels; - for( i = 0; i < j; i++ ) - adapter->logdrv_chan[i] = 0; - for( i = j; i < NVIRT_CHAN + j; i++ ) - adapter->logdrv_chan[i] = 1; - } else { - for (i = 0; i < NVIRT_CHAN; i++) - adapter->logdrv_chan[i] = 1; - for (i = NVIRT_CHAN; i < MAX_CHANNELS+NVIRT_CHAN; i++) - adapter->logdrv_chan[i] = 0; - adapter->mega_ch_class <<= NVIRT_CHAN; - } - - /* - * Do we support random deletion and addition of logical - * drives - */ - adapter->read_ldidmap = 0; /* set it after first logdrv - delete cmd */ - adapter->support_random_del = mega_support_random_del(adapter); - - /* Initialize SCBs */ - if (mega_init_scb(adapter)) - goto out_free_mbox; - - /* - * Reset the pending commands counter - */ - atomic_set(&adapter->pend_cmds, 0); - - /* - * Reset the adapter quiescent flag - */ - atomic_set(&adapter->quiescent, 0); - - hba_soft_state[hba_count] = adapter; - - /* - * Fill in the structure which needs to be passed back to the - * application when it does an ioctl() for controller related - * information. - */ - i = hba_count; - - mcontroller[i].base = mega_baseport; - mcontroller[i].irq = irq; - mcontroller[i].numldrv = adapter->numldrv; - mcontroller[i].pcibus = pci_bus; - mcontroller[i].pcidev = id->device; - mcontroller[i].pcifun = PCI_FUNC (pci_dev_func); - mcontroller[i].pciid = -1; - mcontroller[i].pcivendor = id->vendor; - mcontroller[i].pcislot = PCI_SLOT(pci_dev_func); - mcontroller[i].uid = (pci_bus << 8) | pci_dev_func; - - - /* Set the Mode of addressing to 64 bit if we can */ - if ((adapter->flag & BOARD_64BIT) && (sizeof(dma_addr_t) == 8)) { - pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - adapter->has_64bit_addr = 1; - } else { - pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - adapter->has_64bit_addr = 0; - } - - mutex_init(&adapter->int_mtx); - init_completion(&adapter->int_waitq); - - adapter->this_id = DEFAULT_INITIATOR_ID; - adapter->host->this_id = DEFAULT_INITIATOR_ID; - -#if MEGA_HAVE_CLUSTERING - /* - * Is cluster support enabled on this controller - * Note: In a cluster the HBAs ( the initiators ) will have - * different target IDs and we cannot assume it to be 7. Call - * to mega_support_cluster() will get the target ids also if - * the cluster support is available - */ - adapter->has_cluster = mega_support_cluster(adapter); - if (adapter->has_cluster) { - printk(KERN_NOTICE - "megaraid: Cluster driver, initiator id:%d\n", - adapter->this_id); - } -#endif - - pci_set_drvdata(pdev, host); - - mega_create_proc_entry(hba_count, mega_proc_dir_entry); - - error = scsi_add_host(host, &pdev->dev); - if (error) - goto out_free_mbox; - - scsi_scan_host(host); - hba_count++; - return 0; - - out_free_mbox: - pci_free_consistent(adapter->dev, sizeof(mbox64_t), - adapter->una_mbox64, adapter->una_mbox64_dma); - out_free_irq: - free_irq(adapter->host->irq, adapter); - out_free_scb_list: - kfree(adapter->scb_list); - out_free_cmd_buffer: - pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE, - adapter->mega_buffer, adapter->buf_dma_handle); - out_host_put: - scsi_host_put(host); - out_iounmap: - if (flag & BOARD_MEMMAP) - iounmap((void *)mega_baseport); - out_release_region: - if (flag & BOARD_MEMMAP) - release_mem_region(tbase, 128); - else - release_region(mega_baseport, 16); - out_disable_device: - pci_disable_device(pdev); - out: - return error; -} - -static void -__megaraid_shutdown(adapter_t *adapter) -{ - u_char raw_mbox[sizeof(struct mbox_out)]; - mbox_t *mbox = (mbox_t *)raw_mbox; - int i; - - /* Flush adapter cache */ - memset(&mbox->m_out, 0, sizeof(raw_mbox)); - raw_mbox[0] = FLUSH_ADAPTER; - - free_irq(adapter->host->irq, adapter); - - /* Issue a blocking (interrupts disabled) command to the card */ - issue_scb_block(adapter, raw_mbox); - - /* Flush disks cache */ - memset(&mbox->m_out, 0, sizeof(raw_mbox)); - raw_mbox[0] = FLUSH_SYSTEM; - - /* Issue a blocking (interrupts disabled) command to the card */ - issue_scb_block(adapter, raw_mbox); - - if (atomic_read(&adapter->pend_cmds) > 0) - printk(KERN_WARNING "megaraid: pending commands!!\n"); - - /* - * Have a delibrate delay to make sure all the caches are - * actually flushed. - */ - for (i = 0; i <= 10; i++) - mdelay(1000); -} - -static void __devexit -megaraid_remove_one(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - adapter_t *adapter = (adapter_t *)host->hostdata; - - scsi_remove_host(host); - - __megaraid_shutdown(adapter); - - /* Free our resources */ - if (adapter->flag & BOARD_MEMMAP) { - iounmap((void *)adapter->base); - release_mem_region(adapter->host->base, 128); - } else - release_region(adapter->base, 16); - - mega_free_sgl(adapter); - -#ifdef CONFIG_PROC_FS - if (adapter->controller_proc_dir_entry) { - remove_proc_entry("stat", adapter->controller_proc_dir_entry); - remove_proc_entry("config", - adapter->controller_proc_dir_entry); - remove_proc_entry("mailbox", - adapter->controller_proc_dir_entry); -#if MEGA_HAVE_ENH_PROC - remove_proc_entry("rebuild-rate", - adapter->controller_proc_dir_entry); - remove_proc_entry("battery-status", - adapter->controller_proc_dir_entry); - - remove_proc_entry("diskdrives-ch0", - adapter->controller_proc_dir_entry); - remove_proc_entry("diskdrives-ch1", - adapter->controller_proc_dir_entry); - remove_proc_entry("diskdrives-ch2", - adapter->controller_proc_dir_entry); - remove_proc_entry("diskdrives-ch3", - adapter->controller_proc_dir_entry); - - remove_proc_entry("raiddrives-0-9", - adapter->controller_proc_dir_entry); - remove_proc_entry("raiddrives-10-19", - adapter->controller_proc_dir_entry); - remove_proc_entry("raiddrives-20-29", - adapter->controller_proc_dir_entry); - remove_proc_entry("raiddrives-30-39", - adapter->controller_proc_dir_entry); -#endif - { - char buf[12] = { 0 }; - sprintf(buf, "hba%d", adapter->host->host_no); - remove_proc_entry(buf, mega_proc_dir_entry); - } - } -#endif - - pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE, - adapter->mega_buffer, adapter->buf_dma_handle); - kfree(adapter->scb_list); - pci_free_consistent(adapter->dev, sizeof(mbox64_t), - adapter->una_mbox64, adapter->una_mbox64_dma); - - scsi_host_put(host); - pci_disable_device(pdev); - - hba_count--; -} - -static void -megaraid_shutdown(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - adapter_t *adapter = (adapter_t *)host->hostdata; - - __megaraid_shutdown(adapter); -} - -static struct pci_device_id megaraid_pci_tbl[] = { - {PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_AMI_MEGARAID3, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; -MODULE_DEVICE_TABLE(pci, megaraid_pci_tbl); - -static struct pci_driver megaraid_pci_driver = { - .name = "megaraid_legacy", - .id_table = megaraid_pci_tbl, - .probe = megaraid_probe_one, - .remove = __devexit_p(megaraid_remove_one), - .shutdown = megaraid_shutdown, -}; - -static int __init megaraid_init(void) -{ - int error; - - if ((max_cmd_per_lun <= 0) || (max_cmd_per_lun > MAX_CMD_PER_LUN)) - max_cmd_per_lun = MAX_CMD_PER_LUN; - if (max_mbox_busy_wait > MBOX_BUSY_WAIT) - max_mbox_busy_wait = MBOX_BUSY_WAIT; - -#ifdef CONFIG_PROC_FS - mega_proc_dir_entry = proc_mkdir("megaraid", NULL); - if (!mega_proc_dir_entry) { - printk(KERN_WARNING - "megaraid: failed to create megaraid root\n"); - } -#endif - error = pci_register_driver(&megaraid_pci_driver); - if (error) { -#ifdef CONFIG_PROC_FS - remove_proc_entry("megaraid", NULL); -#endif - return error; - } - - /* - * Register the driver as a character device, for applications - * to access it for ioctls. - * First argument (major) to register_chrdev implies a dynamic - * major number allocation. - */ - major = register_chrdev(0, "megadev_legacy", &megadev_fops); - if (!major) { - printk(KERN_WARNING - "megaraid: failed to register char device\n"); - } - - return 0; -} - -static void __exit megaraid_exit(void) -{ - /* - * Unregister the character device interface to the driver. - */ - unregister_chrdev(major, "megadev_legacy"); - - pci_unregister_driver(&megaraid_pci_driver); - -#ifdef CONFIG_PROC_FS - remove_proc_entry("megaraid", NULL); -#endif -} - -module_init(megaraid_init); -module_exit(megaraid_exit); - -/* vi: set ts=8 sw=8 tw=78: */ diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid.h b/ANDROID_3.4.5/drivers/scsi/megaraid.h deleted file mode 100644 index 9a7897f8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid.h +++ /dev/null @@ -1,1063 +0,0 @@ -#ifndef __MEGARAID_H__ -#define __MEGARAID_H__ - -#include -#include - -#define MEGARAID_VERSION \ - "v2.00.4 (Release Date: Thu Feb 9 08:51:30 EST 2006)\n" - -/* - * Driver features - change the values to enable or disable features in the - * driver. - */ - -/* - * Command coalescing - This feature allows the driver to be able to combine - * two or more commands and issue as one command in order to boost I/O - * performance. Useful if the nature of the I/O is sequential. It is not very - * useful for random natured I/Os. - */ -#define MEGA_HAVE_COALESCING 0 - -/* - * Clustering support - Set this flag if you are planning to use the - * clustering services provided by the megaraid controllers and planning to - * setup a cluster - */ -#define MEGA_HAVE_CLUSTERING 1 - -/* - * Driver statistics - Set this flag if you are interested in statics about - * number of I/O completed on each logical drive and how many interrupts - * generated. If enabled, this information is available through /proc - * interface and through the private ioctl. Setting this flag has a - * performance penalty. - */ -#define MEGA_HAVE_STATS 0 - -/* - * Enhanced /proc interface - This feature will allow you to have a more - * detailed /proc interface for megaraid driver. E.g., a real time update of - * the status of the logical drives, battery status, physical drives etc. - */ -#define MEGA_HAVE_ENH_PROC 1 - -#define MAX_DEV_TYPE 32 - -#ifndef PCI_VENDOR_ID_LSI_LOGIC -#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 -#endif - -#ifndef PCI_VENDOR_ID_AMI -#define PCI_VENDOR_ID_AMI 0x101E -#endif - -#ifndef PCI_VENDOR_ID_DELL -#define PCI_VENDOR_ID_DELL 0x1028 -#endif - -#ifndef PCI_VENDOR_ID_INTEL -#define PCI_VENDOR_ID_INTEL 0x8086 -#endif - -#ifndef PCI_DEVICE_ID_AMI_MEGARAID -#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 -#endif - -#ifndef PCI_DEVICE_ID_AMI_MEGARAID2 -#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060 -#endif - -#ifndef PCI_DEVICE_ID_AMI_MEGARAID3 -#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960 -#endif - -#define PCI_DEVICE_ID_DISCOVERY 0x000E -#define PCI_DEVICE_ID_PERC4_DI 0x000F -#define PCI_DEVICE_ID_PERC4_QC_VERDE 0x0407 - -/* Sub-System Vendor IDs */ -#define AMI_SUBSYS_VID 0x101E -#define DELL_SUBSYS_VID 0x1028 -#define HP_SUBSYS_VID 0x103C -#define LSI_SUBSYS_VID 0x1000 -#define INTEL_SUBSYS_VID 0x8086 - -#define HBA_SIGNATURE 0x3344 -#define HBA_SIGNATURE_471 0xCCCC -#define HBA_SIGNATURE_64BIT 0x0299 - -#define MBOX_BUSY_WAIT 10 /* wait for up to 10 usec for - mailbox to be free */ -#define DEFAULT_INITIATOR_ID 7 - -#define MAX_SGLIST 64 /* max supported in f/w */ -#define MIN_SGLIST 26 /* guaranteed to support these many */ -#define MAX_COMMANDS 126 -#define CMDID_INT_CMDS MAX_COMMANDS+1 /* make sure CMDID_INT_CMDS - is less than max commands - supported by any f/w */ - -#define MAX_CDB_LEN 10 -#define MAX_EXT_CDB_LEN 16 /* we support cdb length up to 16 */ - -#define DEF_CMD_PER_LUN 63 -#define MAX_CMD_PER_LUN MAX_COMMANDS -#define MAX_FIRMWARE_STATUS 46 -#define MAX_XFER_PER_CMD (64*1024) -#define MAX_SECTORS_PER_IO 128 - -#define MAX_LOGICAL_DRIVES_40LD 40 -#define FC_MAX_PHYSICAL_DEVICES 256 -#define MAX_LOGICAL_DRIVES_8LD 8 -#define MAX_CHANNELS 5 -#define MAX_TARGET 15 -#define MAX_PHYSICAL_DRIVES MAX_CHANNELS*MAX_TARGET -#define MAX_ROW_SIZE_40LD 32 -#define MAX_ROW_SIZE_8LD 8 -#define MAX_SPAN_DEPTH 8 - -#define NVIRT_CHAN 4 /* # of virtual channels to represent - up to 60 logical drives */ -struct mbox_out { - /* 0x0 */ u8 cmd; - /* 0x1 */ u8 cmdid; - /* 0x2 */ u16 numsectors; - /* 0x4 */ u32 lba; - /* 0x8 */ u32 xferaddr; - /* 0xC */ u8 logdrv; - /* 0xD */ u8 numsgelements; - /* 0xE */ u8 resvd; -} __attribute__ ((packed)); - -struct mbox_in { - /* 0xF */ volatile u8 busy; - /* 0x10 */ volatile u8 numstatus; - /* 0x11 */ volatile u8 status; - /* 0x12 */ volatile u8 completed[MAX_FIRMWARE_STATUS]; - volatile u8 poll; - volatile u8 ack; -} __attribute__ ((packed)); - -typedef struct { - struct mbox_out m_out; - struct mbox_in m_in; -} __attribute__ ((packed)) mbox_t; - -typedef struct { - u32 xfer_segment_lo; - u32 xfer_segment_hi; - mbox_t mbox; -} __attribute__ ((packed)) mbox64_t; - - -/* - * Passthru definitions - */ -#define MAX_REQ_SENSE_LEN 0x20 - -typedef struct { - u8 timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ - u8 ars:1; - u8 reserved:3; - u8 islogical:1; - u8 logdrv; /* if islogical == 1 */ - u8 channel; /* if islogical == 0 */ - u8 target; /* if islogical == 0 */ - u8 queuetag; /* unused */ - u8 queueaction; /* unused */ - u8 cdb[MAX_CDB_LEN]; - u8 cdblen; - u8 reqsenselen; - u8 reqsensearea[MAX_REQ_SENSE_LEN]; - u8 numsgelements; - u8 scsistatus; - u32 dataxferaddr; - u32 dataxferlen; -} __attribute__ ((packed)) mega_passthru; - - -/* - * Extended passthru: support CDB > 10 bytes - */ -typedef struct { - u8 timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ - u8 ars:1; - u8 rsvd1:1; - u8 cd_rom:1; - u8 rsvd2:1; - u8 islogical:1; - u8 logdrv; /* if islogical == 1 */ - u8 channel; /* if islogical == 0 */ - u8 target; /* if islogical == 0 */ - u8 queuetag; /* unused */ - u8 queueaction; /* unused */ - u8 cdblen; - u8 rsvd3; - u8 cdb[MAX_EXT_CDB_LEN]; - u8 numsgelements; - u8 status; - u8 reqsenselen; - u8 reqsensearea[MAX_REQ_SENSE_LEN]; - u8 rsvd4; - u32 dataxferaddr; - u32 dataxferlen; -} __attribute__ ((packed)) mega_ext_passthru; - -typedef struct { - u64 address; - u32 length; -} __attribute__ ((packed)) mega_sgl64; - -typedef struct { - u32 address; - u32 length; -} __attribute__ ((packed)) mega_sglist; - - -/* Queued command data */ -typedef struct { - int idx; - u32 state; - struct list_head list; - u8 raw_mbox[66]; - u32 dma_type; - u32 dma_direction; - - Scsi_Cmnd *cmd; - dma_addr_t dma_h_bulkdata; - dma_addr_t dma_h_sgdata; - - mega_sglist *sgl; - mega_sgl64 *sgl64; - dma_addr_t sgl_dma_addr; - - mega_passthru *pthru; - dma_addr_t pthru_dma_addr; - mega_ext_passthru *epthru; - dma_addr_t epthru_dma_addr; -} scb_t; - -/* - * Flags to follow the scb as it transitions between various stages - */ -#define SCB_FREE 0x0000 /* on the free list */ -#define SCB_ACTIVE 0x0001 /* off the free list */ -#define SCB_PENDQ 0x0002 /* on the pending queue */ -#define SCB_ISSUED 0x0004 /* issued - owner f/w */ -#define SCB_ABORT 0x0008 /* Got an abort for this one */ -#define SCB_RESET 0x0010 /* Got a reset for this one */ - -/* - * Utilities declare this strcture size as 1024 bytes. So more fields can - * be added in future. - */ -typedef struct { - u32 data_size; /* current size in bytes (not including resvd) */ - - u32 config_signature; - /* Current value is 0x00282008 - * 0x28=MAX_LOGICAL_DRIVES, - * 0x20=Number of stripes and - * 0x08=Number of spans */ - - u8 fw_version[16]; /* printable ASCI string */ - u8 bios_version[16]; /* printable ASCI string */ - u8 product_name[80]; /* printable ASCI string */ - - u8 max_commands; /* Max. concurrent commands supported */ - u8 nchannels; /* Number of SCSI Channels detected */ - u8 fc_loop_present; /* Number of Fibre Loops detected */ - u8 mem_type; /* EDO, FPM, SDRAM etc */ - - u32 signature; - u16 dram_size; /* In terms of MB */ - u16 subsysid; - - u16 subsysvid; - u8 notify_counters; - u8 pad1k[889]; /* 135 + 889 resvd = 1024 total size */ -} __attribute__ ((packed)) mega_product_info; - -struct notify { - u32 global_counter; /* Any change increments this counter */ - - u8 param_counter; /* Indicates any params changed */ - u8 param_id; /* Param modified - defined below */ - u16 param_val; /* New val of last param modified */ - - u8 write_config_counter; /* write config occurred */ - u8 write_config_rsvd[3]; - - u8 ldrv_op_counter; /* Indicates ldrv op started/completed */ - u8 ldrv_opid; /* ldrv num */ - u8 ldrv_opcmd; /* ldrv operation - defined below */ - u8 ldrv_opstatus; /* status of the operation */ - - u8 ldrv_state_counter; /* Indicates change of ldrv state */ - u8 ldrv_state_id; /* ldrv num */ - u8 ldrv_state_new; /* New state */ - u8 ldrv_state_old; /* old state */ - - u8 pdrv_state_counter; /* Indicates change of ldrv state */ - u8 pdrv_state_id; /* pdrv id */ - u8 pdrv_state_new; /* New state */ - u8 pdrv_state_old; /* old state */ - - u8 pdrv_fmt_counter; /* Indicates pdrv format started/over */ - u8 pdrv_fmt_id; /* pdrv id */ - u8 pdrv_fmt_val; /* format started/over */ - u8 pdrv_fmt_rsvd; - - u8 targ_xfer_counter; /* Indicates SCSI-2 Xfer rate change */ - u8 targ_xfer_id; /* pdrv Id */ - u8 targ_xfer_val; /* new Xfer params of last pdrv */ - u8 targ_xfer_rsvd; - - u8 fcloop_id_chg_counter; /* Indicates loopid changed */ - u8 fcloopid_pdrvid; /* pdrv id */ - u8 fcloop_id0; /* loopid on fc loop 0 */ - u8 fcloop_id1; /* loopid on fc loop 1 */ - - u8 fcloop_state_counter; /* Indicates loop state changed */ - u8 fcloop_state0; /* state of fc loop 0 */ - u8 fcloop_state1; /* state of fc loop 1 */ - u8 fcloop_state_rsvd; -} __attribute__ ((packed)); - -#define MAX_NOTIFY_SIZE 0x80 -#define CUR_NOTIFY_SIZE sizeof(struct notify) - -typedef struct { - u32 data_size; /* current size in bytes (not including resvd) */ - - struct notify notify; - - u8 notify_rsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE]; - - u8 rebuild_rate; /* Rebuild rate (0% - 100%) */ - u8 cache_flush_interval; /* In terms of Seconds */ - u8 sense_alert; - u8 drive_insert_count; /* drive insertion count */ - - u8 battery_status; - u8 num_ldrv; /* No. of Log Drives configured */ - u8 recon_state[MAX_LOGICAL_DRIVES_40LD / 8]; /* State of - reconstruct */ - u16 ldrv_op_status[MAX_LOGICAL_DRIVES_40LD / 8]; /* logdrv - Status */ - - u32 ldrv_size[MAX_LOGICAL_DRIVES_40LD];/* Size of each log drv */ - u8 ldrv_prop[MAX_LOGICAL_DRIVES_40LD]; - u8 ldrv_state[MAX_LOGICAL_DRIVES_40LD];/* State of log drives */ - u8 pdrv_state[FC_MAX_PHYSICAL_DEVICES];/* State of phys drvs. */ - u16 pdrv_format[FC_MAX_PHYSICAL_DEVICES / 16]; - - u8 targ_xfer[80]; /* phys device transfer rate */ - u8 pad1k[263]; /* 761 + 263reserved = 1024 bytes total size */ -} __attribute__ ((packed)) mega_inquiry3; - - -/* Structures */ -typedef struct { - u8 max_commands; /* Max concurrent commands supported */ - u8 rebuild_rate; /* Rebuild rate - 0% thru 100% */ - u8 max_targ_per_chan; /* Max targ per channel */ - u8 nchannels; /* Number of channels on HBA */ - u8 fw_version[4]; /* Firmware version */ - u16 age_of_flash; /* Number of times FW has been flashed */ - u8 chip_set_value; /* Contents of 0xC0000832 */ - u8 dram_size; /* In MB */ - u8 cache_flush_interval; /* in seconds */ - u8 bios_version[4]; - u8 board_type; - u8 sense_alert; - u8 write_config_count; /* Increase with every configuration - change */ - u8 drive_inserted_count; /* Increase with every drive inserted - */ - u8 inserted_drive; /* Channel:Id of inserted drive */ - u8 battery_status; /* - * BIT 0: battery module missing - * BIT 1: VBAD - * BIT 2: temperature high - * BIT 3: battery pack missing - * BIT 4,5: - * 00 - charge complete - * 01 - fast charge in progress - * 10 - fast charge fail - * 11 - undefined - * Bit 6: counter > 1000 - * Bit 7: Undefined - */ - u8 dec_fault_bus_info; -} __attribute__ ((packed)) mega_adp_info; - - -typedef struct { - u8 num_ldrv; /* Number of logical drives configured */ - u8 rsvd[3]; - u32 ldrv_size[MAX_LOGICAL_DRIVES_8LD]; - u8 ldrv_prop[MAX_LOGICAL_DRIVES_8LD]; - u8 ldrv_state[MAX_LOGICAL_DRIVES_8LD]; -} __attribute__ ((packed)) mega_ldrv_info; - -typedef struct { - u8 pdrv_state[MAX_PHYSICAL_DRIVES]; - u8 rsvd; -} __attribute__ ((packed)) mega_pdrv_info; - -/* RAID inquiry: Mailbox command 0x05*/ -typedef struct { - mega_adp_info adapter_info; - mega_ldrv_info logdrv_info; - mega_pdrv_info pdrv_info; -} __attribute__ ((packed)) mraid_inquiry; - - -/* RAID extended inquiry: Mailbox command 0x04*/ -typedef struct { - mraid_inquiry raid_inq; - u16 phys_drv_format[MAX_CHANNELS]; - u8 stack_attn; - u8 modem_status; - u8 rsvd[2]; -} __attribute__ ((packed)) mraid_ext_inquiry; - - -typedef struct { - u8 channel; - u8 target; -}__attribute__ ((packed)) adp_device; - -typedef struct { - u32 start_blk; /* starting block */ - u32 num_blks; /* # of blocks */ - adp_device device[MAX_ROW_SIZE_40LD]; -}__attribute__ ((packed)) adp_span_40ld; - -typedef struct { - u32 start_blk; /* starting block */ - u32 num_blks; /* # of blocks */ - adp_device device[MAX_ROW_SIZE_8LD]; -}__attribute__ ((packed)) adp_span_8ld; - -typedef struct { - u8 span_depth; /* Total # of spans */ - u8 level; /* RAID level */ - u8 read_ahead; /* read ahead, no read ahead, adaptive read - ahead */ - u8 stripe_sz; /* Encoded stripe size */ - u8 status; /* Status of the logical drive */ - u8 write_mode; /* write mode, write_through/write_back */ - u8 direct_io; /* direct io or through cache */ - u8 row_size; /* Number of stripes in a row */ -} __attribute__ ((packed)) logdrv_param; - -typedef struct { - logdrv_param lparam; - adp_span_40ld span[MAX_SPAN_DEPTH]; -}__attribute__ ((packed)) logdrv_40ld; - -typedef struct { - logdrv_param lparam; - adp_span_8ld span[MAX_SPAN_DEPTH]; -}__attribute__ ((packed)) logdrv_8ld; - -typedef struct { - u8 type; /* Type of the device */ - u8 cur_status; /* current status of the device */ - u8 tag_depth; /* Level of tagging */ - u8 sync_neg; /* sync negotiation - ENABLE or DISABLE */ - u32 size; /* configurable size in terms of 512 byte - blocks */ -}__attribute__ ((packed)) phys_drv; - -typedef struct { - u8 nlog_drives; /* number of logical drives */ - u8 resvd[3]; - logdrv_40ld ldrv[MAX_LOGICAL_DRIVES_40LD]; - phys_drv pdrv[MAX_PHYSICAL_DRIVES]; -}__attribute__ ((packed)) disk_array_40ld; - -typedef struct { - u8 nlog_drives; /* number of logical drives */ - u8 resvd[3]; - logdrv_8ld ldrv[MAX_LOGICAL_DRIVES_8LD]; - phys_drv pdrv[MAX_PHYSICAL_DRIVES]; -}__attribute__ ((packed)) disk_array_8ld; - - -/* - * User ioctl structure. - * This structure will be used for Traditional Method ioctl interface - * commands (0x80),Alternate Buffer Method (0x81) ioctl commands and the - * Driver ioctls. - * The Driver ioctl interface handles the commands at the driver level, - * without being sent to the card. - */ -/* system call imposed limit. Change accordingly */ -#define IOCTL_MAX_DATALEN 4096 - -struct uioctl_t { - u32 inlen; - u32 outlen; - union { - u8 fca[16]; - struct { - u8 opcode; - u8 subopcode; - u16 adapno; -#if BITS_PER_LONG == 32 - u8 *buffer; - u8 pad[4]; -#endif -#if BITS_PER_LONG == 64 - u8 *buffer; -#endif - u32 length; - } __attribute__ ((packed)) fcs; - } __attribute__ ((packed)) ui; - u8 mbox[18]; /* 16 bytes + 2 status bytes */ - mega_passthru pthru; -#if BITS_PER_LONG == 32 - char __user *data; /* buffer <= 4096 for 0x80 commands */ - char pad[4]; -#endif -#if BITS_PER_LONG == 64 - char __user *data; -#endif -} __attribute__ ((packed)); - -/* - * struct mcontroller is used to pass information about the controllers in the - * system. Its up to the application how to use the information. We are passing - * as much info about the cards as possible and useful. Before issuing the - * call to find information about the cards, the application needs to issue a - * ioctl first to find out the number of controllers in the system. - */ -#define MAX_CONTROLLERS 32 - -struct mcontroller { - u64 base; - u8 irq; - u8 numldrv; - u8 pcibus; - u16 pcidev; - u8 pcifun; - u16 pciid; - u16 pcivendor; - u8 pcislot; - u32 uid; -}; - -/* - * mailbox structure used for internal commands - */ -typedef struct { - u8 cmd; - u8 cmdid; - u8 opcode; - u8 subopcode; - u32 lba; - u32 xferaddr; - u8 logdrv; - u8 rsvd[3]; - u8 numstatus; - u8 status; -} __attribute__ ((packed)) megacmd_t; - -/* - * Defines for Driver IOCTL interface - */ -#define MEGAIOC_MAGIC 'm' - -#define MEGAIOC_QNADAP 'm' /* Query # of adapters */ -#define MEGAIOC_QDRVRVER 'e' /* Query driver version */ -#define MEGAIOC_QADAPINFO 'g' /* Query adapter information */ -#define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | (adapno) ) -#define GETADAP(mkadap) ( (mkadap) ^ MEGAIOC_MAGIC << 8 ) - -/* - * Definition for the new ioctl interface (NIT) - */ - -/* - * Vendor specific Group-7 commands - */ -#define VENDOR_SPECIFIC_COMMANDS 0xE0 -#define MEGA_INTERNAL_CMD VENDOR_SPECIFIC_COMMANDS + 0x01 - -/* - * The ioctl command. No other command shall be used for this interface - */ -#define USCSICMD VENDOR_SPECIFIC_COMMANDS - -/* - * Data direction flags - */ -#define UIOC_RD 0x00001 -#define UIOC_WR 0x00002 - -/* - * ioctl opcodes - */ -#define MBOX_CMD 0x00000 /* DCMD or passthru command */ -#define GET_DRIVER_VER 0x10000 /* Get driver version */ -#define GET_N_ADAP 0x20000 /* Get number of adapters */ -#define GET_ADAP_INFO 0x30000 /* Get information about a adapter */ -#define GET_CAP 0x40000 /* Get ioctl capabilities */ -#define GET_STATS 0x50000 /* Get statistics, including error info */ - - -/* - * The ioctl structure. - * MBOX macro converts a nitioctl_t structure to megacmd_t pointer and - * MBOX_P macro converts a nitioctl_t pointer to megacmd_t pointer. - */ -typedef struct { - char signature[8]; /* Must contain "MEGANIT" */ - u32 opcode; /* opcode for the command */ - u32 adapno; /* adapter number */ - union { - u8 __raw_mbox[18]; - void __user *__uaddr; /* xferaddr for non-mbox cmds */ - }__ua; - -#define uioc_rmbox __ua.__raw_mbox -#define MBOX(uioc) ((megacmd_t *)&((uioc).__ua.__raw_mbox[0])) -#define MBOX_P(uioc) ((megacmd_t __user *)&((uioc)->__ua.__raw_mbox[0])) -#define uioc_uaddr __ua.__uaddr - - u32 xferlen; /* xferlen for DCMD and non-mbox - commands */ - u32 flags; /* data direction flags */ -}nitioctl_t; - - -/* - * I/O statistics for some applications like SNMP agent. The caller must - * provide the number of logical drives for which status should be reported. - */ -typedef struct { - int num_ldrv; /* Number for logical drives for which the - status should be reported. */ - u32 nreads[MAX_LOGICAL_DRIVES_40LD]; /* number of reads for - each logical drive */ - u32 nreadblocks[MAX_LOGICAL_DRIVES_40LD]; /* number of blocks - read for each logical - drive */ - u32 nwrites[MAX_LOGICAL_DRIVES_40LD]; /* number of writes - for each logical - drive */ - u32 nwriteblocks[MAX_LOGICAL_DRIVES_40LD]; /* number of blocks - writes for each - logical drive */ - u32 rd_errors[MAX_LOGICAL_DRIVES_40LD]; /* number of read - errors for each - logical drive */ - u32 wr_errors[MAX_LOGICAL_DRIVES_40LD]; /* number of write - errors for each - logical drive */ -}megastat_t; - - -struct private_bios_data { - u8 geometry:4; /* - * bits 0-3 - BIOS geometry - * 0x0001 - 1GB - * 0x0010 - 2GB - * 0x1000 - 8GB - * Others values are invalid - */ - u8 unused:4; /* bits 4-7 are unused */ - u8 boot_drv; /* - * logical drive set as boot drive - * 0..7 - for 8LD cards - * 0..39 - for 40LD cards - */ - u8 rsvd[12]; - u16 cksum; /* 0-(sum of first 13 bytes of this structure) */ -} __attribute__ ((packed)); - - - - -/* - * Mailbox and firmware commands and subopcodes used in this driver. - */ - -#define MEGA_MBOXCMD_LREAD 0x01 -#define MEGA_MBOXCMD_LWRITE 0x02 -#define MEGA_MBOXCMD_PASSTHRU 0x03 -#define MEGA_MBOXCMD_ADPEXTINQ 0x04 -#define MEGA_MBOXCMD_ADAPTERINQ 0x05 -#define MEGA_MBOXCMD_LREAD64 0xA7 -#define MEGA_MBOXCMD_LWRITE64 0xA8 -#define MEGA_MBOXCMD_PASSTHRU64 0xC3 -#define MEGA_MBOXCMD_EXTPTHRU 0xE3 - -#define MAIN_MISC_OPCODE 0xA4 /* f/w misc opcode */ -#define GET_MAX_SG_SUPPORT 0x01 /* get max sg len supported by f/w */ - -#define FC_NEW_CONFIG 0xA1 -#define NC_SUBOP_PRODUCT_INFO 0x0E -#define NC_SUBOP_ENQUIRY3 0x0F -#define ENQ3_GET_SOLICITED_FULL 0x02 -#define OP_DCMD_READ_CONFIG 0x04 -#define NEW_READ_CONFIG_8LD 0x67 -#define READ_CONFIG_8LD 0x07 -#define FLUSH_ADAPTER 0x0A -#define FLUSH_SYSTEM 0xFE - -/* - * Command for random deletion of logical drives - */ -#define FC_DEL_LOGDRV 0xA4 /* f/w command */ -#define OP_SUP_DEL_LOGDRV 0x2A /* is feature supported */ -#define OP_GET_LDID_MAP 0x18 /* get ldid and logdrv number map */ -#define OP_DEL_LOGDRV 0x1C /* delete logical drive */ - -/* - * BIOS commands - */ -#define IS_BIOS_ENABLED 0x62 -#define GET_BIOS 0x01 -#define CHNL_CLASS 0xA9 -#define GET_CHNL_CLASS 0x00 -#define SET_CHNL_CLASS 0x01 -#define CH_RAID 0x01 -#define CH_SCSI 0x00 -#define BIOS_PVT_DATA 0x40 -#define GET_BIOS_PVT_DATA 0x00 - - -/* - * Commands to support clustering - */ -#define MEGA_GET_TARGET_ID 0x7D -#define MEGA_CLUSTER_OP 0x70 -#define MEGA_GET_CLUSTER_MODE 0x02 -#define MEGA_CLUSTER_CMD 0x6E -#define MEGA_RESERVE_LD 0x01 -#define MEGA_RELEASE_LD 0x02 -#define MEGA_RESET_RESERVATIONS 0x03 -#define MEGA_RESERVATION_STATUS 0x04 -#define MEGA_RESERVE_PD 0x05 -#define MEGA_RELEASE_PD 0x06 - - -/* - * Module battery status - */ -#define MEGA_BATT_MODULE_MISSING 0x01 -#define MEGA_BATT_LOW_VOLTAGE 0x02 -#define MEGA_BATT_TEMP_HIGH 0x04 -#define MEGA_BATT_PACK_MISSING 0x08 -#define MEGA_BATT_CHARGE_MASK 0x30 -#define MEGA_BATT_CHARGE_DONE 0x00 -#define MEGA_BATT_CHARGE_INPROG 0x10 -#define MEGA_BATT_CHARGE_FAIL 0x20 -#define MEGA_BATT_CYCLES_EXCEEDED 0x40 - -/* - * Physical drive states. - */ -#define PDRV_UNCNF 0 -#define PDRV_ONLINE 3 -#define PDRV_FAILED 4 -#define PDRV_RBLD 5 -#define PDRV_HOTSPARE 6 - - -/* - * Raid logical drive states. - */ -#define RDRV_OFFLINE 0 -#define RDRV_DEGRADED 1 -#define RDRV_OPTIMAL 2 -#define RDRV_DELETED 3 - -/* - * Read, write and cache policies - */ -#define NO_READ_AHEAD 0 -#define READ_AHEAD 1 -#define ADAP_READ_AHEAD 2 -#define WRMODE_WRITE_THRU 0 -#define WRMODE_WRITE_BACK 1 -#define CACHED_IO 0 -#define DIRECT_IO 1 - - -#define SCSI_LIST(scp) ((struct list_head *)(&(scp)->SCp)) - -/* - * Each controller's soft state - */ -typedef struct { - int this_id; /* our id, may set to different than 7 if - clustering is available */ - u32 flag; - - unsigned long base; - void __iomem *mmio_base; - - /* mbox64 with mbox not aligned on 16-byte boundary */ - mbox64_t *una_mbox64; - dma_addr_t una_mbox64_dma; - - volatile mbox64_t *mbox64;/* ptr to 64-bit mailbox */ - volatile mbox_t *mbox; /* ptr to standard mailbox */ - dma_addr_t mbox_dma; - - struct pci_dev *dev; - - struct list_head free_list; - struct list_head pending_list; - struct list_head completed_list; - - struct Scsi_Host *host; - -#define MEGA_BUFFER_SIZE (2*1024) - u8 *mega_buffer; - dma_addr_t buf_dma_handle; - - mega_product_info product_info; - - u8 max_cmds; - scb_t *scb_list; - - atomic_t pend_cmds; /* maintain a counter for pending - commands in firmware */ - -#if MEGA_HAVE_STATS - u32 nreads[MAX_LOGICAL_DRIVES_40LD]; - u32 nreadblocks[MAX_LOGICAL_DRIVES_40LD]; - u32 nwrites[MAX_LOGICAL_DRIVES_40LD]; - u32 nwriteblocks[MAX_LOGICAL_DRIVES_40LD]; - u32 rd_errors[MAX_LOGICAL_DRIVES_40LD]; - u32 wr_errors[MAX_LOGICAL_DRIVES_40LD]; -#endif - - /* Host adapter parameters */ - u8 numldrv; - u8 fw_version[7]; - u8 bios_version[7]; - -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *controller_proc_dir_entry; - struct proc_dir_entry *proc_read; - struct proc_dir_entry *proc_stat; - struct proc_dir_entry *proc_mbox; - -#if MEGA_HAVE_ENH_PROC - struct proc_dir_entry *proc_rr; - struct proc_dir_entry *proc_battery; -#define MAX_PROC_CHANNELS 4 - struct proc_dir_entry *proc_pdrvstat[MAX_PROC_CHANNELS]; - struct proc_dir_entry *proc_rdrvstat[MAX_PROC_CHANNELS]; -#endif - -#endif - - int has_64bit_addr; /* are we using 64-bit addressing */ - int support_ext_cdb; - int boot_ldrv_enabled; - int boot_ldrv; - int boot_pdrv_enabled; /* boot from physical drive */ - int boot_pdrv_ch; /* boot physical drive channel */ - int boot_pdrv_tgt; /* boot physical drive target */ - - - int support_random_del; /* Do we support random deletion of - logdrvs */ - int read_ldidmap; /* set after logical drive deltion. The - logical drive number must be read from the - map */ - atomic_t quiescent; /* a stage reached when delete logical - drive needs to be done. Stop - sending requests to the hba till - delete operation is completed */ - spinlock_t lock; - - u8 logdrv_chan[MAX_CHANNELS+NVIRT_CHAN]; /* logical drive are on - what channels. */ - int mega_ch_class; - - u8 sglen; /* f/w supported scatter-gather list length */ - - unsigned char int_cdb[MAX_COMMAND_SIZE]; - scb_t int_scb; - struct mutex int_mtx; /* To synchronize the internal - commands */ - struct completion int_waitq; /* wait queue for internal - cmds */ - - int has_cluster; /* cluster support on this HBA */ -}adapter_t; - - -struct mega_hbas { - int is_bios_enabled; - adapter_t *hostdata_addr; -}; - - -/* - * For state flag. Do not use LSB(8 bits) which are - * reserved for storing info about channels. - */ -#define IN_ABORT 0x80000000L -#define IN_RESET 0x40000000L -#define BOARD_MEMMAP 0x20000000L -#define BOARD_IOMAP 0x10000000L -#define BOARD_40LD 0x08000000L -#define BOARD_64BIT 0x04000000L - -#define INTR_VALID 0x40 - -#define PCI_CONF_AMISIG 0xa0 -#define PCI_CONF_AMISIG64 0xa4 - - -#define MEGA_DMA_TYPE_NONE 0xFFFF -#define MEGA_BULK_DATA 0x0001 -#define MEGA_SGLIST 0x0002 - -/* - * Parameters for the io-mapped controllers - */ - -/* I/O Port offsets */ -#define CMD_PORT 0x00 -#define ACK_PORT 0x00 -#define TOGGLE_PORT 0x01 -#define INTR_PORT 0x0a - -#define MBOX_BUSY_PORT 0x00 -#define MBOX_PORT0 0x04 -#define MBOX_PORT1 0x05 -#define MBOX_PORT2 0x06 -#define MBOX_PORT3 0x07 -#define ENABLE_MBOX_REGION 0x0B - -/* I/O Port Values */ -#define ISSUE_BYTE 0x10 -#define ACK_BYTE 0x08 -#define ENABLE_INTR_BYTE 0xc0 -#define DISABLE_INTR_BYTE 0x00 -#define VALID_INTR_BYTE 0x40 -#define MBOX_BUSY_BYTE 0x10 -#define ENABLE_MBOX_BYTE 0x00 - - -/* Setup some port macros here */ -#define issue_command(adapter) \ - outb_p(ISSUE_BYTE, (adapter)->base + CMD_PORT) - -#define irq_state(adapter) inb_p((adapter)->base + INTR_PORT) - -#define set_irq_state(adapter, value) \ - outb_p((value), (adapter)->base + INTR_PORT) - -#define irq_ack(adapter) \ - outb_p(ACK_BYTE, (adapter)->base + ACK_PORT) - -#define irq_enable(adapter) \ - outb_p(ENABLE_INTR_BYTE, (adapter)->base + TOGGLE_PORT) - -#define irq_disable(adapter) \ - outb_p(DISABLE_INTR_BYTE, (adapter)->base + TOGGLE_PORT) - - -/* - * This is our SYSDEP area. All kernel specific detail should be placed here - - * as much as possible - */ - -/* - * End of SYSDEP area - */ - -const char *megaraid_info (struct Scsi_Host *); - -static int mega_query_adapter(adapter_t *); -static int issue_scb(adapter_t *, scb_t *); -static int mega_setup_mailbox(adapter_t *); - -static int megaraid_queue (struct Scsi_Host *, struct scsi_cmnd *); -static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *); -static void __mega_runpendq(adapter_t *); -static int issue_scb_block(adapter_t *, u_char *); - -static irqreturn_t megaraid_isr_memmapped(int, void *); -static irqreturn_t megaraid_isr_iomapped(int, void *); - -static void mega_free_scb(adapter_t *, scb_t *); - -static int megaraid_abort(Scsi_Cmnd *); -static int megaraid_reset(Scsi_Cmnd *); -static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int); -static int megaraid_biosparam(struct scsi_device *, struct block_device *, - sector_t, int []); - -static int mega_build_sglist (adapter_t *adapter, scb_t *scb, - u32 *buffer, u32 *length); -static int __mega_busywait_mbox (adapter_t *); -static void mega_rundoneq (adapter_t *); -static void mega_cmd_done(adapter_t *, u8 [], int, int); -static inline void mega_free_sgl (adapter_t *adapter); -static void mega_8_to_40ld (mraid_inquiry *inquiry, - mega_inquiry3 *enquiry3, mega_product_info *); - -static int megadev_open (struct inode *, struct file *); -static int megadev_ioctl (struct file *, unsigned int, unsigned long); -static int mega_m_to_n(void __user *, nitioctl_t *); -static int mega_n_to_m(void __user *, megacmd_t *); - -static int mega_init_scb (adapter_t *); - -static int mega_is_bios_enabled (adapter_t *); - -#ifdef CONFIG_PROC_FS -static int mega_print_inquiry(char *, char *); -static void mega_create_proc_entry(int, struct proc_dir_entry *); -static int proc_read_config(char *, char **, off_t, int, int *, void *); -static int proc_read_stat(char *, char **, off_t, int, int *, void *); -static int proc_read_mbox(char *, char **, off_t, int, int *, void *); -static int proc_rebuild_rate(char *, char **, off_t, int, int *, void *); -static int proc_battery(char *, char **, off_t, int, int *, void *); -static int proc_pdrv_ch0(char *, char **, off_t, int, int *, void *); -static int proc_pdrv_ch1(char *, char **, off_t, int, int *, void *); -static int proc_pdrv_ch2(char *, char **, off_t, int, int *, void *); -static int proc_pdrv_ch3(char *, char **, off_t, int, int *, void *); -static int proc_pdrv(adapter_t *, char *, int); -static int proc_rdrv_10(char *, char **, off_t, int, int *, void *); -static int proc_rdrv_20(char *, char **, off_t, int, int *, void *); -static int proc_rdrv_30(char *, char **, off_t, int, int *, void *); -static int proc_rdrv_40(char *, char **, off_t, int, int *, void *); -static int proc_rdrv(adapter_t *, char *, int, int); - -static int mega_adapinq(adapter_t *, dma_addr_t); -static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t); -#endif - -static int mega_support_ext_cdb(adapter_t *); -static mega_passthru* mega_prepare_passthru(adapter_t *, scb_t *, - Scsi_Cmnd *, int, int); -static mega_ext_passthru* mega_prepare_extpassthru(adapter_t *, - scb_t *, Scsi_Cmnd *, int, int); -static void mega_enum_raid_scsi(adapter_t *); -static void mega_get_boot_drv(adapter_t *); -static int mega_support_random_del(adapter_t *); -static int mega_del_logdrv(adapter_t *, int); -static int mega_do_del_logdrv(adapter_t *, int); -static void mega_get_max_sgl(adapter_t *); -static int mega_internal_command(adapter_t *, megacmd_t *, mega_passthru *); -static void mega_internal_done(Scsi_Cmnd *); -static int mega_support_cluster(adapter_t *); -#endif - -/* vi: set ts=8 sw=8 tw=78: */ diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/Kconfig.megaraid b/ANDROID_3.4.5/drivers/scsi/megaraid/Kconfig.megaraid deleted file mode 100644 index 17419e30..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/Kconfig.megaraid +++ /dev/null @@ -1,85 +0,0 @@ -config MEGARAID_NEWGEN - bool "LSI Logic New Generation RAID Device Drivers" - depends on PCI && SCSI - help - LSI Logic RAID Device Drivers - -config MEGARAID_MM - tristate "LSI Logic Management Module (New Driver)" - depends on PCI && SCSI && MEGARAID_NEWGEN - help - Management Module provides ioctl, sysfs support for LSI Logic - RAID controllers. - To compile this driver as a module, choose M here: the - module will be called megaraid_mm - - -config MEGARAID_MAILBOX - tristate "LSI Logic MegaRAID Driver (New Driver)" - depends on PCI && SCSI && MEGARAID_MM - help - List of supported controllers - - OEM Product Name VID :DID :SVID:SSID - --- ------------ ---- ---- ---- ---- - Dell PERC3/QC 101E:1960:1028:0471 - Dell PERC3/DC 101E:1960:1028:0493 - Dell PERC3/SC 101E:1960:1028:0475 - Dell PERC3/Di 1028:000E:1028:0123 - Dell PERC4/SC 1000:1960:1028:0520 - Dell PERC4/DC 1000:1960:1028:0518 - Dell PERC4/QC 1000:0407:1028:0531 - Dell PERC4/Di 1028:000F:1028:014A - Dell PERC 4e/Si 1028:0013:1028:016c - Dell PERC 4e/Di 1028:0013:1028:016d - Dell PERC 4e/Di 1028:0013:1028:016e - Dell PERC 4e/Di 1028:0013:1028:016f - Dell PERC 4e/Di 1028:0013:1028:0170 - Dell PERC 4e/DC 1000:0408:1028:0002 - Dell PERC 4e/SC 1000:0408:1028:0001 - LSI MegaRAID SCSI 320-0 1000:1960:1000:A520 - LSI MegaRAID SCSI 320-1 1000:1960:1000:0520 - LSI MegaRAID SCSI 320-2 1000:1960:1000:0518 - LSI MegaRAID SCSI 320-0X 1000:0407:1000:0530 - LSI MegaRAID SCSI 320-2X 1000:0407:1000:0532 - LSI MegaRAID SCSI 320-4X 1000:0407:1000:0531 - LSI MegaRAID SCSI 320-1E 1000:0408:1000:0001 - LSI MegaRAID SCSI 320-2E 1000:0408:1000:0002 - LSI MegaRAID SATA 150-4 1000:1960:1000:4523 - LSI MegaRAID SATA 150-6 1000:1960:1000:0523 - LSI MegaRAID SATA 300-4X 1000:0409:1000:3004 - LSI MegaRAID SATA 300-8X 1000:0409:1000:3008 - INTEL RAID Controller SRCU42X 1000:0407:8086:0532 - INTEL RAID Controller SRCS16 1000:1960:8086:0523 - INTEL RAID Controller SRCU42E 1000:0408:8086:0002 - INTEL RAID Controller SRCZCRX 1000:0407:8086:0530 - INTEL RAID Controller SRCS28X 1000:0409:8086:3008 - INTEL RAID Controller SROMBU42E 1000:0408:8086:3431 - INTEL RAID Controller SROMBU42E 1000:0408:8086:3499 - INTEL RAID Controller SRCU51L 1000:1960:8086:0520 - FSC MegaRAID PCI Express ROMB 1000:0408:1734:1065 - ACER MegaRAID ROMB-2E 1000:0408:1025:004D - NEC MegaRAID PCI Express ROMB 1000:0408:1033:8287 - - To compile this driver as a module, choose M here: the - module will be called megaraid_mbox - -config MEGARAID_LEGACY - tristate "LSI Logic Legacy MegaRAID Driver" - depends on PCI && SCSI - help - This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490 - and 467 SCSI host adapters. This driver also support the all U320 - RAID controllers - - To compile this driver as a module, choose M here: the - module will be called megaraid - -config MEGARAID_SAS - tristate "LSI Logic MegaRAID SAS RAID Module" - depends on PCI && SCSI - help - Module for LSI Logic's SAS based RAID controllers. - To compile this driver as a module, choose 'm' here. - Module will be called megaraid_sas - diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/Makefile b/ANDROID_3.4.5/drivers/scsi/megaraid/Makefile deleted file mode 100644 index 5826ed50..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-$(CONFIG_MEGARAID_MM) += megaraid_mm.o -obj-$(CONFIG_MEGARAID_MAILBOX) += megaraid_mbox.o -obj-$(CONFIG_MEGARAID_SAS) += megaraid_sas.o -megaraid_sas-objs := megaraid_sas_base.o megaraid_sas_fusion.o \ - megaraid_sas_fp.o diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/mbox_defs.h b/ANDROID_3.4.5/drivers/scsi/megaraid/mbox_defs.h deleted file mode 100644 index e01c6f7c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/mbox_defs.h +++ /dev/null @@ -1,790 +0,0 @@ -/* - * - * Linux MegaRAID Unified device driver - * - * Copyright (c) 2003-2004 LSI Logic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * FILE : mbox_defs.h - * - */ -#ifndef _MRAID_MBOX_DEFS_H_ -#define _MRAID_MBOX_DEFS_H_ - -#include - -/* - * Commands and states for mailbox based controllers - */ - -#define MBOXCMD_LREAD 0x01 -#define MBOXCMD_LWRITE 0x02 -#define MBOXCMD_PASSTHRU 0x03 -#define MBOXCMD_ADPEXTINQ 0x04 -#define MBOXCMD_ADAPTERINQ 0x05 -#define MBOXCMD_LREAD64 0xA7 -#define MBOXCMD_LWRITE64 0xA8 -#define MBOXCMD_PASSTHRU64 0xC3 -#define MBOXCMD_EXTPTHRU 0xE3 - -#define MAIN_MISC_OPCODE 0xA4 -#define GET_MAX_SG_SUPPORT 0x01 -#define SUPPORT_EXT_CDB 0x16 - -#define FC_NEW_CONFIG 0xA1 -#define NC_SUBOP_PRODUCT_INFO 0x0E -#define NC_SUBOP_ENQUIRY3 0x0F -#define ENQ3_GET_SOLICITED_FULL 0x02 -#define OP_DCMD_READ_CONFIG 0x04 -#define NEW_READ_CONFIG_8LD 0x67 -#define READ_CONFIG_8LD 0x07 -#define FLUSH_ADAPTER 0x0A -#define FLUSH_SYSTEM 0xFE - -/* - * Command for random deletion of logical drives - */ -#define FC_DEL_LOGDRV 0xA4 -#define OP_SUP_DEL_LOGDRV 0x2A -#define OP_GET_LDID_MAP 0x18 -#define OP_DEL_LOGDRV 0x1C - -/* - * BIOS commands - */ -#define IS_BIOS_ENABLED 0x62 -#define GET_BIOS 0x01 -#define CHNL_CLASS 0xA9 -#define GET_CHNL_CLASS 0x00 -#define SET_CHNL_CLASS 0x01 -#define CH_RAID 0x01 -#define CH_SCSI 0x00 -#define BIOS_PVT_DATA 0x40 -#define GET_BIOS_PVT_DATA 0x00 - - -/* - * Commands to support clustering - */ -#define GET_TARGET_ID 0x7D -#define CLUSTER_OP 0x70 -#define GET_CLUSTER_MODE 0x02 -#define CLUSTER_CMD 0x6E -#define RESERVE_LD 0x01 -#define RELEASE_LD 0x02 -#define RESET_RESERVATIONS 0x03 -#define RESERVATION_STATUS 0x04 -#define RESERVE_PD 0x05 -#define RELEASE_PD 0x06 - - -/* - * Module battery status - */ -#define BATTERY_MODULE_MISSING 0x01 -#define BATTERY_LOW_VOLTAGE 0x02 -#define BATTERY_TEMP_HIGH 0x04 -#define BATTERY_PACK_MISSING 0x08 -#define BATTERY_CHARGE_MASK 0x30 -#define BATTERY_CHARGE_DONE 0x00 -#define BATTERY_CHARGE_INPROG 0x10 -#define BATTERY_CHARGE_FAIL 0x20 -#define BATTERY_CYCLES_EXCEEDED 0x40 - -/* - * Physical drive states. - */ -#define PDRV_UNCNF 0 -#define PDRV_ONLINE 3 -#define PDRV_FAILED 4 -#define PDRV_RBLD 5 -#define PDRV_HOTSPARE 6 - - -/* - * Raid logical drive states. - */ -#define RDRV_OFFLINE 0 -#define RDRV_DEGRADED 1 -#define RDRV_OPTIMAL 2 -#define RDRV_DELETED 3 - -/* - * Read, write and cache policies - */ -#define NO_READ_AHEAD 0 -#define READ_AHEAD 1 -#define ADAP_READ_AHEAD 2 -#define WRMODE_WRITE_THRU 0 -#define WRMODE_WRITE_BACK 1 -#define CACHED_IO 0 -#define DIRECT_IO 1 - -#define MAX_LOGICAL_DRIVES_8LD 8 -#define MAX_LOGICAL_DRIVES_40LD 40 -#define FC_MAX_PHYSICAL_DEVICES 256 -#define MAX_MBOX_CHANNELS 5 -#define MAX_MBOX_TARGET 15 -#define MBOX_MAX_PHYSICAL_DRIVES MAX_MBOX_CHANNELS*MAX_MBOX_TARGET -#define MAX_ROW_SIZE_40LD 32 -#define MAX_ROW_SIZE_8LD 8 -#define SPAN_DEPTH_8_SPANS 8 -#define SPAN_DEPTH_4_SPANS 4 -#define MAX_REQ_SENSE_LEN 0x20 - - - -/** - * struct mbox_t - Driver and f/w handshake structure. - * @cmd : firmware command - * @cmdid : command id - * @numsectors : number of sectors to be transferred - * @lba : Logical Block Address on LD - * @xferaddr : DMA address for data transfer - * @logdrv : logical drive number - * @numsge : number of scatter gather elements in sg list - * @resvd : reserved - * @busy : f/w busy, must wait to issue more commands. - * @numstatus : number of commands completed. - * @status : status of the commands completed - * @completed : array of completed command ids. - * @poll : poll and ack sequence - * @ack : poll and ack sequence - * - * The central handshake structure between the driver and the firmware. This - * structure must be allocated by the driver and aligned at 8-byte boundary. - */ -#define MBOX_MAX_FIRMWARE_STATUS 46 -typedef struct { - uint8_t cmd; - uint8_t cmdid; - uint16_t numsectors; - uint32_t lba; - uint32_t xferaddr; - uint8_t logdrv; - uint8_t numsge; - uint8_t resvd; - uint8_t busy; - uint8_t numstatus; - uint8_t status; - uint8_t completed[MBOX_MAX_FIRMWARE_STATUS]; - uint8_t poll; - uint8_t ack; -} __attribute__ ((packed)) mbox_t; - - -/** - * mbox64_t - 64-bit extension for the mailbox - * @segment_lo : the low 32-bits of the address of the scatter-gather list - * @segment_hi : the upper 32-bits of the address of the scatter-gather list - * @mbox : 32-bit mailbox, whose xferadder field must be set to - * 0xFFFFFFFF - * - * This is the extension of the 32-bit mailbox to be able to perform DMA - * beyond 4GB address range. - */ -typedef struct { - uint32_t xferaddr_lo; - uint32_t xferaddr_hi; - mbox_t mbox32; -} __attribute__ ((packed)) mbox64_t; - -/* - * mailbox structure used for internal commands - */ -typedef struct { - u8 cmd; - u8 cmdid; - u8 opcode; - u8 subopcode; - u32 lba; - u32 xferaddr; - u8 logdrv; - u8 rsvd[3]; - u8 numstatus; - u8 status; -} __attribute__ ((packed)) int_mbox_t; - -/** - * mraid_passthru_t - passthru structure to issue commands to physical devices - * @timeout : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr - * @ars : set if ARS required after check condition - * @islogical : set if command meant for logical devices - * @logdrv : logical drive number if command for LD - * @channel : Channel on which physical device is located - * @target : SCSI target of the device - * @queuetag : unused - * @queueaction : unused - * @cdb : SCSI CDB - * @cdblen : length of the CDB - * @reqsenselen : amount of request sense data to be returned - * @reqsensearea : Sense information buffer - * @numsge : number of scatter-gather elements in the sg list - * @scsistatus : SCSI status of the command completed. - * @dataxferaddr : DMA data transfer address - * @dataxferlen : amount of the data to be transferred. - */ -typedef struct { - uint8_t timeout :3; - uint8_t ars :1; - uint8_t reserved :3; - uint8_t islogical :1; - uint8_t logdrv; - uint8_t channel; - uint8_t target; - uint8_t queuetag; - uint8_t queueaction; - uint8_t cdb[10]; - uint8_t cdblen; - uint8_t reqsenselen; - uint8_t reqsensearea[MAX_REQ_SENSE_LEN]; - uint8_t numsge; - uint8_t scsistatus; - uint32_t dataxferaddr; - uint32_t dataxferlen; -} __attribute__ ((packed)) mraid_passthru_t; - -typedef struct { - - uint32_t dataxferaddr_lo; - uint32_t dataxferaddr_hi; - mraid_passthru_t pthru32; - -} __attribute__ ((packed)) mega_passthru64_t; - -/** - * mraid_epassthru_t - passthru structure to issue commands to physical devices - * @timeout : command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr - * @ars : set if ARS required after check condition - * @rsvd1 : reserved field - * @cd_rom : (?) - * @rsvd2 : reserved field - * @islogical : set if command meant for logical devices - * @logdrv : logical drive number if command for LD - * @channel : Channel on which physical device is located - * @target : SCSI target of the device - * @queuetag : unused - * @queueaction : unused - * @cdblen : length of the CDB - * @rsvd3 : reserved field - * @cdb : SCSI CDB - * @numsge : number of scatter-gather elements in the sg list - * @status : SCSI status of the command completed. - * @reqsenselen : amount of request sense data to be returned - * @reqsensearea : Sense information buffer - * @rsvd4 : reserved field - * @dataxferaddr : DMA data transfer address - * @dataxferlen : amount of the data to be transferred. - */ -typedef struct { - uint8_t timeout :3; - uint8_t ars :1; - uint8_t rsvd1 :1; - uint8_t cd_rom :1; - uint8_t rsvd2 :1; - uint8_t islogical :1; - uint8_t logdrv; - uint8_t channel; - uint8_t target; - uint8_t queuetag; - uint8_t queueaction; - uint8_t cdblen; - uint8_t rsvd3; - uint8_t cdb[16]; - uint8_t numsge; - uint8_t status; - uint8_t reqsenselen; - uint8_t reqsensearea[MAX_REQ_SENSE_LEN]; - uint8_t rsvd4; - uint32_t dataxferaddr; - uint32_t dataxferlen; -} __attribute__ ((packed)) mraid_epassthru_t; - - -/** - * mraid_pinfo_t - product info, static information about the controller - * @data_size : current size in bytes (not including resvd) - * @config_signature : Current value is 0x00282008 - * @fw_version : Firmware version - * @bios_version : version of the BIOS - * @product_name : Name given to the controller - * @max_commands : Maximum concurrent commands supported - * @nchannels : Number of SCSI Channels detected - * @fc_loop_present : Number of Fibre Loops detected - * @mem_type : EDO, FPM, SDRAM etc - * @signature : - * @dram_size : In terms of MB - * @subsysid : device PCI subsystem ID - * @subsysvid : device PCI subsystem vendor ID - * @notify_counters : - * @pad1k : 135 + 889 resvd = 1024 total size - * - * This structures holds the information about the controller which is not - * expected to change dynamically. - * - * The current value of config signature is 0x00282008: - * 0x28 = MAX_LOGICAL_DRIVES, - * 0x20 = Number of stripes and - * 0x08 = Number of spans - */ -typedef struct { - uint32_t data_size; - uint32_t config_signature; - uint8_t fw_version[16]; - uint8_t bios_version[16]; - uint8_t product_name[80]; - uint8_t max_commands; - uint8_t nchannels; - uint8_t fc_loop_present; - uint8_t mem_type; - uint32_t signature; - uint16_t dram_size; - uint16_t subsysid; - uint16_t subsysvid; - uint8_t notify_counters; - uint8_t pad1k[889]; -} __attribute__ ((packed)) mraid_pinfo_t; - - -/** - * mraid_notify_t - the notification structure - * @global_counter : Any change increments this counter - * @param_counter : Indicates any params changed - * @param_id : Param modified - defined below - * @param_val : New val of last param modified - * @write_config_counter : write config occurred - * @write_config_rsvd : - * @ldrv_op_counter : Indicates ldrv op started/completed - * @ldrv_opid : ldrv num - * @ldrv_opcmd : ldrv operation - defined below - * @ldrv_opstatus : status of the operation - * @ldrv_state_counter : Indicates change of ldrv state - * @ldrv_state_id : ldrv num - * @ldrv_state_new : New state - * @ldrv_state_old : old state - * @pdrv_state_counter : Indicates change of ldrv state - * @pdrv_state_id : pdrv id - * @pdrv_state_new : New state - * @pdrv_state_old : old state - * @pdrv_fmt_counter : Indicates pdrv format started/over - * @pdrv_fmt_id : pdrv id - * @pdrv_fmt_val : format started/over - * @pdrv_fmt_rsvd : - * @targ_xfer_counter : Indicates SCSI-2 Xfer rate change - * @targ_xfer_id : pdrv Id - * @targ_xfer_val : new Xfer params of last pdrv - * @targ_xfer_rsvd : - * @fcloop_id_chg_counter : Indicates loopid changed - * @fcloopid_pdrvid : pdrv id - * @fcloop_id0 : loopid on fc loop 0 - * @fcloop_id1 : loopid on fc loop 1 - * @fcloop_state_counter : Indicates loop state changed - * @fcloop_state0 : state of fc loop 0 - * @fcloop_state1 : state of fc loop 1 - * @fcloop_state_rsvd : - */ -typedef struct { - uint32_t global_counter; - uint8_t param_counter; - uint8_t param_id; - uint16_t param_val; - uint8_t write_config_counter; - uint8_t write_config_rsvd[3]; - uint8_t ldrv_op_counter; - uint8_t ldrv_opid; - uint8_t ldrv_opcmd; - uint8_t ldrv_opstatus; - uint8_t ldrv_state_counter; - uint8_t ldrv_state_id; - uint8_t ldrv_state_new; - uint8_t ldrv_state_old; - uint8_t pdrv_state_counter; - uint8_t pdrv_state_id; - uint8_t pdrv_state_new; - uint8_t pdrv_state_old; - uint8_t pdrv_fmt_counter; - uint8_t pdrv_fmt_id; - uint8_t pdrv_fmt_val; - uint8_t pdrv_fmt_rsvd; - uint8_t targ_xfer_counter; - uint8_t targ_xfer_id; - uint8_t targ_xfer_val; - uint8_t targ_xfer_rsvd; - uint8_t fcloop_id_chg_counter; - uint8_t fcloopid_pdrvid; - uint8_t fcloop_id0; - uint8_t fcloop_id1; - uint8_t fcloop_state_counter; - uint8_t fcloop_state0; - uint8_t fcloop_state1; - uint8_t fcloop_state_rsvd; -} __attribute__ ((packed)) mraid_notify_t; - - -/** - * mraid_inquiry3_t - enquiry for device information - * - * @data_size : current size in bytes (not including resvd) - * @notify : - * @notify_rsvd : - * @rebuild_rate : rebuild rate (0% - 100%) - * @cache_flush_int : cache flush interval in seconds - * @sense_alert : - * @drive_insert_count : drive insertion count - * @battery_status : - * @num_ldrv : no. of Log Drives configured - * @recon_state : state of reconstruct - * @ldrv_op_status : logdrv Status - * @ldrv_size : size of each log drv - * @ldrv_prop : - * @ldrv_state : state of log drives - * @pdrv_state : state of phys drvs. - * @pdrv_format : - * @targ_xfer : phys device transfer rate - * @pad1k : 761 + 263reserved = 1024 bytes total size - */ -#define MAX_NOTIFY_SIZE 0x80 -#define CUR_NOTIFY_SIZE sizeof(mraid_notify_t) - -typedef struct { - uint32_t data_size; - - mraid_notify_t notify; - - uint8_t notify_rsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE]; - - uint8_t rebuild_rate; - uint8_t cache_flush_int; - uint8_t sense_alert; - uint8_t drive_insert_count; - - uint8_t battery_status; - uint8_t num_ldrv; - uint8_t recon_state[MAX_LOGICAL_DRIVES_40LD / 8]; - uint16_t ldrv_op_status[MAX_LOGICAL_DRIVES_40LD / 8]; - - uint32_t ldrv_size[MAX_LOGICAL_DRIVES_40LD]; - uint8_t ldrv_prop[MAX_LOGICAL_DRIVES_40LD]; - uint8_t ldrv_state[MAX_LOGICAL_DRIVES_40LD]; - uint8_t pdrv_state[FC_MAX_PHYSICAL_DEVICES]; - uint16_t pdrv_format[FC_MAX_PHYSICAL_DEVICES / 16]; - - uint8_t targ_xfer[80]; - uint8_t pad1k[263]; -} __attribute__ ((packed)) mraid_inquiry3_t; - - -/** - * mraid_adapinfo_t - information about the adapter - * @max_commands : max concurrent commands supported - * @rebuild_rate : rebuild rate - 0% thru 100% - * @max_targ_per_chan : max targ per channel - * @nchannels : number of channels on HBA - * @fw_version : firmware version - * @age_of_flash : number of times FW has been flashed - * @chip_set_value : contents of 0xC0000832 - * @dram_size : in MB - * @cache_flush_interval : in seconds - * @bios_version : - * @board_type : - * @sense_alert : - * @write_config_count : increase with every configuration change - * @drive_inserted_count : increase with every drive inserted - * @inserted_drive : channel:Id of inserted drive - * @battery_status : bit 0: battery module missing - * bit 1: VBAD - * bit 2: temperature high - * bit 3: battery pack missing - * bit 4,5: - * 00 - charge complete - * 01 - fast charge in progress - * 10 - fast charge fail - * 11 - undefined - * bit 6: counter > 1000 - * bit 7: Undefined - * @dec_fault_bus_info : - */ -typedef struct { - uint8_t max_commands; - uint8_t rebuild_rate; - uint8_t max_targ_per_chan; - uint8_t nchannels; - uint8_t fw_version[4]; - uint16_t age_of_flash; - uint8_t chip_set_value; - uint8_t dram_size; - uint8_t cache_flush_interval; - uint8_t bios_version[4]; - uint8_t board_type; - uint8_t sense_alert; - uint8_t write_config_count; - uint8_t battery_status; - uint8_t dec_fault_bus_info; -} __attribute__ ((packed)) mraid_adapinfo_t; - - -/** - * mraid_ldrv_info_t - information about the logical drives - * @nldrv : Number of logical drives configured - * @rsvd : - * @size : size of each logical drive - * @prop : - * @state : state of each logical drive - */ -typedef struct { - uint8_t nldrv; - uint8_t rsvd[3]; - uint32_t size[MAX_LOGICAL_DRIVES_8LD]; - uint8_t prop[MAX_LOGICAL_DRIVES_8LD]; - uint8_t state[MAX_LOGICAL_DRIVES_8LD]; -} __attribute__ ((packed)) mraid_ldrv_info_t; - - -/** - * mraid_pdrv_info_t - information about the physical drives - * @pdrv_state : state of each physical drive - */ -typedef struct { - uint8_t pdrv_state[MBOX_MAX_PHYSICAL_DRIVES]; - uint8_t rsvd; -} __attribute__ ((packed)) mraid_pdrv_info_t; - - -/** - * mraid_inquiry_t - RAID inquiry, mailbox command 0x05 - * @mraid_adapinfo_t : adapter information - * @mraid_ldrv_info_t : logical drives information - * @mraid_pdrv_info_t : physical drives information - */ -typedef struct { - mraid_adapinfo_t adapter_info; - mraid_ldrv_info_t logdrv_info; - mraid_pdrv_info_t pdrv_info; -} __attribute__ ((packed)) mraid_inquiry_t; - - -/** - * mraid_extinq_t - RAID extended inquiry, mailbox command 0x04 - * - * @raid_inq : raid inquiry - * @phys_drv_format : - * @stack_attn : - * @modem_status : - * @rsvd : - */ -typedef struct { - mraid_inquiry_t raid_inq; - uint16_t phys_drv_format[MAX_MBOX_CHANNELS]; - uint8_t stack_attn; - uint8_t modem_status; - uint8_t rsvd[2]; -} __attribute__ ((packed)) mraid_extinq_t; - - -/** - * adap_device_t - device information - * @channel : channel fpor the device - * @target : target ID of the device - */ -typedef struct { - uint8_t channel; - uint8_t target; -}__attribute__ ((packed)) adap_device_t; - - -/** - * adap_span_40ld_t - 40LD span - * @start_blk : starting block - * @num_blks : number of blocks - */ -typedef struct { - uint32_t start_blk; - uint32_t num_blks; - adap_device_t device[MAX_ROW_SIZE_40LD]; -}__attribute__ ((packed)) adap_span_40ld_t; - - -/** - * adap_span_8ld_t - 8LD span - * @start_blk : starting block - * @num_blks : number of blocks - */ -typedef struct { - uint32_t start_blk; - uint32_t num_blks; - adap_device_t device[MAX_ROW_SIZE_8LD]; -}__attribute__ ((packed)) adap_span_8ld_t; - - -/** - * logdrv_param_t - logical drives parameters - * - * @span_depth : total number of spans - * @level : RAID level - * @read_ahead : read ahead, no read ahead, adaptive read ahead - * @stripe_sz : encoded stripe size - * @status : status of the logical drive - * @write_mode : write mode, write_through/write_back - * @direct_io : direct io or through cache - * @row_size : number of stripes in a row - */ -typedef struct { - uint8_t span_depth; - uint8_t level; - uint8_t read_ahead; - uint8_t stripe_sz; - uint8_t status; - uint8_t write_mode; - uint8_t direct_io; - uint8_t row_size; -} __attribute__ ((packed)) logdrv_param_t; - - -/** - * logdrv_40ld_t - logical drive definition for 40LD controllers - * @lparam : logical drives parameters - * @span : span - */ -typedef struct { - logdrv_param_t lparam; - adap_span_40ld_t span[SPAN_DEPTH_8_SPANS]; -}__attribute__ ((packed)) logdrv_40ld_t; - - -/** - * logdrv_8ld_span8_t - logical drive definition for 8LD controllers - * @lparam : logical drives parameters - * @span : span - * - * 8-LD logical drive with up to 8 spans - */ -typedef struct { - logdrv_param_t lparam; - adap_span_8ld_t span[SPAN_DEPTH_8_SPANS]; -}__attribute__ ((packed)) logdrv_8ld_span8_t; - - -/** - * logdrv_8ld_span4_t - logical drive definition for 8LD controllers - * @lparam : logical drives parameters - * @span : span - * - * 8-LD logical drive with up to 4 spans - */ -typedef struct { - logdrv_param_t lparam; - adap_span_8ld_t span[SPAN_DEPTH_4_SPANS]; -}__attribute__ ((packed)) logdrv_8ld_span4_t; - - -/** - * phys_drive_t - physical device information - * @type : Type of the device - * @cur_status : current status of the device - * @tag_depth : Level of tagging - * @sync_neg : sync negotiation - ENABLE or DISABLE - * @size : configurable size in terms of 512 byte - */ -typedef struct { - uint8_t type; - uint8_t cur_status; - uint8_t tag_depth; - uint8_t sync_neg; - uint32_t size; -}__attribute__ ((packed)) phys_drive_t; - - -/** - * disk_array_40ld_t - disk array for 40LD controllers - * @numldrv : number of logical drives - * @resvd : - * @ldrv : logical drives information - * @pdrv : physical drives information - */ -typedef struct { - uint8_t numldrv; - uint8_t resvd[3]; - logdrv_40ld_t ldrv[MAX_LOGICAL_DRIVES_40LD]; - phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; -}__attribute__ ((packed)) disk_array_40ld_t; - - -/** - * disk_array_8ld_span8_t - disk array for 8LD controllers - * @numldrv : number of logical drives - * @resvd : - * @ldrv : logical drives information - * @pdrv : physical drives information - * - * Disk array for 8LD logical drives with up to 8 spans - */ -typedef struct { - uint8_t numldrv; - uint8_t resvd[3]; - logdrv_8ld_span8_t ldrv[MAX_LOGICAL_DRIVES_8LD]; - phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; -}__attribute__ ((packed)) disk_array_8ld_span8_t; - - -/** - * disk_array_8ld_span4_t - disk array for 8LD controllers - * @numldrv : number of logical drives - * @resvd : - * @ldrv : logical drives information - * @pdrv : physical drives information - * - * Disk array for 8LD logical drives with up to 4 spans - */ -typedef struct { - uint8_t numldrv; - uint8_t resvd[3]; - logdrv_8ld_span4_t ldrv[MAX_LOGICAL_DRIVES_8LD]; - phys_drive_t pdrv[MBOX_MAX_PHYSICAL_DRIVES]; -}__attribute__ ((packed)) disk_array_8ld_span4_t; - - -/** - * struct private_bios_data - bios private data for boot devices - * @geometry : bits 0-3 - BIOS geometry, 0x0001 - 1GB, 0x0010 - 2GB, - * 0x1000 - 8GB, Others values are invalid - * @unused : bits 4-7 are unused - * @boot_drv : logical drive set as boot drive, 0..7 - for 8LD cards, - * 0..39 - for 40LD cards - * @cksum : 0-(sum of first 13 bytes of this structure) - */ -struct private_bios_data { - uint8_t geometry :4; - uint8_t unused :4; - uint8_t boot_drv; - uint8_t rsvd[12]; - uint16_t cksum; -} __attribute__ ((packed)); - - -/** - * mbox_sgl64 - 64-bit scatter list for mailbox based controllers - * @address : address of the buffer - * @length : data transfer length - */ -typedef struct { - uint64_t address; - uint32_t length; -} __attribute__ ((packed)) mbox_sgl64; - -/** - * mbox_sgl32 - 32-bit scatter list for mailbox based controllers - * @address : address of the buffer - * @length : data transfer length - */ -typedef struct { - uint32_t address; - uint32_t length; -} __attribute__ ((packed)) mbox_sgl32; - -#endif // _MRAID_MBOX_DEFS_H_ - -/* vim: set ts=8 sw=8 tw=78: */ diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/mega_common.h b/ANDROID_3.4.5/drivers/scsi/megaraid/mega_common.h deleted file mode 100644 index 5ead1283..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/mega_common.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * - * Linux MegaRAID device driver - * - * Copyright (c) 2003-2004 LSI Logic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * FILE : mega_common.h - * - * Libaray of common routine used by all low-level megaraid drivers - */ - -#ifndef _MEGA_COMMON_H_ -#define _MEGA_COMMON_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define LSI_MAX_CHANNELS 16 -#define LSI_MAX_LOGICAL_DRIVES_64LD (64+1) - -#define HBA_SIGNATURE_64_BIT 0x299 -#define PCI_CONF_AMISIG64 0xa4 - -#define MEGA_SCSI_INQ_EVPD 1 -#define MEGA_INVALID_FIELD_IN_CDB 0x24 - - -/** - * scb_t - scsi command control block - * @ccb : command control block for individual driver - * @list : list of control blocks - * @gp : general purpose field for LLDs - * @sno : all SCBs have a serial number - * @scp : associated scsi command - * @state : current state of scb - * @dma_dir : direction of data transfer - * @dma_type : transfer with sg list, buffer, or no data transfer - * @dev_channel : actual channel on the device - * @dev_target : actual target on the device - * @status : completion status - * - * This is our central data structure to issue commands the each driver. - * Driver specific data structures are maintained in the ccb field. - * scb provides a field 'gp', which can be used by LLD for its own purposes - * - * dev_channel and dev_target must be initialized with the actual channel and - * target on the controller. - */ -typedef struct { - caddr_t ccb; - struct list_head list; - unsigned long gp; - unsigned int sno; - struct scsi_cmnd *scp; - uint32_t state; - uint32_t dma_direction; - uint32_t dma_type; - uint16_t dev_channel; - uint16_t dev_target; - uint32_t status; -} scb_t; - -/* - * SCB states as it transitions from one state to another - */ -#define SCB_FREE 0x0000 /* on the free list */ -#define SCB_ACTIVE 0x0001 /* off the free list */ -#define SCB_PENDQ 0x0002 /* on the pending queue */ -#define SCB_ISSUED 0x0004 /* issued - owner f/w */ -#define SCB_ABORT 0x0008 /* Got an abort for this one */ -#define SCB_RESET 0x0010 /* Got a reset for this one */ - -/* - * DMA types for scb - */ -#define MRAID_DMA_NONE 0x0000 /* no data transfer for this command */ -#define MRAID_DMA_WSG 0x0001 /* data transfer using a sg list */ -#define MRAID_DMA_WBUF 0x0002 /* data transfer using a contiguous buffer */ - - -/** - * struct adapter_t - driver's initialization structure - * @aram dpc_h : tasklet handle - * @pdev : pci configuration pointer for kernel - * @host : pointer to host structure of mid-layer - * @lock : synchronization lock for mid-layer and driver - * @quiescent : driver is quiescent for now. - * @outstanding_cmds : number of commands pending in the driver - * @kscb_list : pointer to the bulk of SCBs pointers for IO - * @kscb_pool : pool of free scbs for IO - * @kscb_pool_lock : lock for pool of free scbs - * @pend_list : pending commands list - * @pend_list_lock : exclusion lock for pending commands list - * @completed_list : list of completed commands - * @completed_list_lock : exclusion lock for list of completed commands - * @sglen : max sg elements supported - * @device_ids : to convert kernel device addr to our devices. - * @raid_device : raid adapter specific pointer - * @max_channel : maximum channel number supported - inclusive - * @max_target : max target supported - inclusive - * @max_lun : max lun supported - inclusive - * @unique_id : unique identifier for each adapter - * @irq : IRQ for this adapter - * @ito : internal timeout value, (-1) means no timeout - * @ibuf : buffer to issue internal commands - * @ibuf_dma_h : dma handle for the above buffer - * @uscb_list : SCB pointers for user cmds, common mgmt module - * @uscb_pool : pool of SCBs for user commands - * @uscb_pool_lock : exclusion lock for these SCBs - * @max_cmds : max outstanding commands - * @fw_version : firmware version - * @bios_version : bios version - * @max_cdb_sz : biggest CDB size supported. - * @ha : is high availability present - clustering - * @init_id : initiator ID, the default value should be 7 - * @max_sectors : max sectors per request - * @cmd_per_lun : max outstanding commands per LUN - * @being_detached : set when unloading, no more mgmt calls - * - * - * mraid_setup_device_map() can be called anytime after the device map is - * available and MRAID_GET_DEVICE_MAP() can be called whenever the mapping is - * required, usually from LLD's queue entry point. The formar API sets up the - * MRAID_IS_LOGICAL(adapter_t *, struct scsi_cmnd *) to find out if the - * device in question is a logical drive. - * - * quiescent flag should be set by the driver if it is not accepting more - * commands - * - * NOTE: The fields of this structures are placed to minimize cache misses - */ - -// amount of space required to store the bios and firmware version strings -#define VERSION_SIZE 16 - -typedef struct { - struct tasklet_struct dpc_h; - struct pci_dev *pdev; - struct Scsi_Host *host; - spinlock_t lock; - uint8_t quiescent; - int outstanding_cmds; - scb_t *kscb_list; - struct list_head kscb_pool; - spinlock_t kscb_pool_lock; - struct list_head pend_list; - spinlock_t pend_list_lock; - struct list_head completed_list; - spinlock_t completed_list_lock; - uint16_t sglen; - int device_ids[LSI_MAX_CHANNELS] - [LSI_MAX_LOGICAL_DRIVES_64LD]; - caddr_t raid_device; - uint8_t max_channel; - uint16_t max_target; - uint8_t max_lun; - - uint32_t unique_id; - int irq; - uint8_t ito; - caddr_t ibuf; - dma_addr_t ibuf_dma_h; - scb_t *uscb_list; - struct list_head uscb_pool; - spinlock_t uscb_pool_lock; - int max_cmds; - uint8_t fw_version[VERSION_SIZE]; - uint8_t bios_version[VERSION_SIZE]; - uint8_t max_cdb_sz; - uint8_t ha; - uint16_t init_id; - uint16_t max_sectors; - uint16_t cmd_per_lun; - atomic_t being_detached; -} adapter_t; - -#define SCSI_FREE_LIST_LOCK(adapter) (&adapter->kscb_pool_lock) -#define USER_FREE_LIST_LOCK(adapter) (&adapter->uscb_pool_lock) -#define PENDING_LIST_LOCK(adapter) (&adapter->pend_list_lock) -#define COMPLETED_LIST_LOCK(adapter) (&adapter->completed_list_lock) - - -// conversion from scsi command -#define SCP2HOST(scp) (scp)->device->host // to host -#define SCP2HOSTDATA(scp) SCP2HOST(scp)->hostdata // to soft state -#define SCP2CHANNEL(scp) (scp)->device->channel // to channel -#define SCP2TARGET(scp) (scp)->device->id // to target -#define SCP2LUN(scp) (scp)->device->lun // to LUN - -// generic macro to convert scsi command and host to controller's soft state -#define SCSIHOST2ADAP(host) (((caddr_t *)(host->hostdata))[0]) -#define SCP2ADAPTER(scp) (adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp)) - - -#define MRAID_IS_LOGICAL(adp, scp) \ - (SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0 - -#define MRAID_IS_LOGICAL_SDEV(adp, sdev) \ - (sdev->channel == (adp)->max_channel) ? 1 : 0 - -/** - * MRAID_GET_DEVICE_MAP - device ids - * @adp : adapter's soft state - * @scp : mid-layer scsi command pointer - * @p_chan : physical channel on the controller - * @target : target id of the device or logical drive number - * @islogical : set if the command is for the logical drive - * - * Macro to retrieve information about device class, logical or physical and - * the corresponding physical channel and target or logical drive number - */ -#define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical) \ - /* \ - * Is the request coming for the virtual channel \ - */ \ - islogical = MRAID_IS_LOGICAL(adp, scp); \ - \ - /* \ - * Get an index into our table of drive ids mapping \ - */ \ - if (islogical) { \ - p_chan = 0xFF; \ - target = \ - (adp)->device_ids[(adp)->max_channel][SCP2TARGET(scp)]; \ - } \ - else { \ - p_chan = ((adp)->device_ids[SCP2CHANNEL(scp)] \ - [SCP2TARGET(scp)] >> 8) & 0xFF; \ - target = ((adp)->device_ids[SCP2CHANNEL(scp)] \ - [SCP2TARGET(scp)] & 0xFF); \ - } - -/* - * ### Helper routines ### - */ -#define LSI_DBGLVL mraid_debug_level // each LLD must define a global - // mraid_debug_level - -#ifdef DEBUG -#if defined (_ASSERT_PANIC) -#define ASSERT_ACTION panic -#else -#define ASSERT_ACTION printk -#endif - -#define ASSERT(expression) \ - if (!(expression)) { \ - ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n", \ - #expression, __FILE__, __LINE__, __func__); \ - } -#else -#define ASSERT(expression) -#endif - -/** - * struct mraid_pci_blk - structure holds DMA memory block info - * @vaddr : virtual address to a memory block - * @dma_addr : DMA handle to a memory block - * - * This structure is filled up for the caller. It is the responsibilty of the - * caller to allocate this array big enough to store addresses for all - * requested elements - */ -struct mraid_pci_blk { - caddr_t vaddr; - dma_addr_t dma_addr; -}; - -#endif // _MEGA_COMMON_H_ - -// vim: set ts=8 sw=8 tw=78: diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_ioctl.h b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_ioctl.h deleted file mode 100644 index 05f6e4ec..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_ioctl.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * - * Linux MegaRAID device driver - * - * Copyright (c) 2003-2004 LSI Logic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * FILE : megaraid_ioctl.h - * - * Definitions to interface with user level applications - */ - -#ifndef _MEGARAID_IOCTL_H_ -#define _MEGARAID_IOCTL_H_ - -#include -#include - -#include "mbox_defs.h" - -/* - * console messages debug levels - */ -#define CL_ANN 0 /* print unconditionally, announcements */ -#define CL_DLEVEL1 1 /* debug level 1, informative */ -#define CL_DLEVEL2 2 /* debug level 2, verbose */ -#define CL_DLEVEL3 3 /* debug level 3, very verbose */ - -/** - * con_log() - console log routine - * @level : indicates the severity of the message. - * @fmt : format string - * - * con_log displays the error messages on the console based on the current - * debug level. Also it attaches the appropriate kernel severity level with - * the message. - */ -#define con_log(level, fmt) if (LSI_DBGLVL >= level) printk fmt; - -/* - * Definitions & Declarations needed to use common management module - */ - -#define MEGAIOC_MAGIC 'm' -#define MEGAIOCCMD _IOWR(MEGAIOC_MAGIC, 0, mimd_t) - -#define MEGAIOC_QNADAP 'm' /* Query # of adapters */ -#define MEGAIOC_QDRVRVER 'e' /* Query driver version */ -#define MEGAIOC_QADAPINFO 'g' /* Query adapter information */ - -#define USCSICMD 0x80 -#define UIOC_RD 0x00001 -#define UIOC_WR 0x00002 - -#define MBOX_CMD 0x00000 -#define GET_DRIVER_VER 0x10000 -#define GET_N_ADAP 0x20000 -#define GET_ADAP_INFO 0x30000 -#define GET_CAP 0x40000 -#define GET_STATS 0x50000 -#define GET_IOCTL_VERSION 0x01 - -#define EXT_IOCTL_SIGN_SZ 16 -#define EXT_IOCTL_SIGN "$$_EXTD_IOCTL_$$" - -#define MBOX_LEGACY 0x00 /* ioctl has legacy mbox*/ -#define MBOX_HPE 0x01 /* ioctl has hpe mbox */ - -#define APPTYPE_MIMD 0x00 /* old existing apps */ -#define APPTYPE_UIOC 0x01 /* new apps using uioc */ - -#define IOCTL_ISSUE 0x00000001 /* Issue ioctl */ -#define IOCTL_ABORT 0x00000002 /* Abort previous ioctl */ - -#define DRVRTYPE_MBOX 0x00000001 /* regular mbox driver */ -#define DRVRTYPE_HPE 0x00000002 /* new hpe driver */ - -#define MKADAP(adapno) (MEGAIOC_MAGIC << 8 | (adapno) ) -#define GETADAP(mkadap) ((mkadap) ^ MEGAIOC_MAGIC << 8) - -#define MAX_DMA_POOLS 5 /* 4k, 8k, 16k, 32k, 64k*/ - - -/** - * struct uioc_t - the common ioctl packet structure - * - * @signature : Must be "$$_EXTD_IOCTL_$$" - * @mb_type : Type of the mail box (MB_LEGACY or MB_HPE) - * @app_type : Type of the issuing application (existing or new) - * @opcode : Opcode of the command - * @adapno : Adapter number - * @cmdbuf : Pointer to buffer - can point to mbox or plain data buffer - * @xferlen : xferlen for DCMD and non mailbox commands - * @data_dir : Direction of the data transfer - * @status : Status from the driver - * @reserved : reserved bytes for future expansion - * - * @user_data : user data transfer address is saved in this - * @user_data_len: length of the data buffer sent by user app - * @user_pthru : user passthru address is saves in this (null if DCMD) - * @pthru32 : kernel address passthru (allocated per kioc) - * @pthru32_h : physicall address of @pthru32 - * @list : for kioc free pool list maintenance - * @done : call back routine for llds to call when kioc is completed - * @buf_vaddr : dma pool buffer attached to kioc for data transfer - * @buf_paddr : physical address of the dma pool buffer - * @pool_index : index of the dma pool that @buf_vaddr is taken from - * @free_buf : indicates if buffer needs to be freed after kioc completes - * - * Note : All LSI drivers understand only this packet. Any other - * : format sent by applications would be converted to this. - */ -typedef struct uioc { - -/* User Apps: */ - - uint8_t signature[EXT_IOCTL_SIGN_SZ]; - uint16_t mb_type; - uint16_t app_type; - uint32_t opcode; - uint32_t adapno; - uint64_t cmdbuf; - uint32_t xferlen; - uint32_t data_dir; - int32_t status; - uint8_t reserved[128]; - -/* Driver Data: */ - void __user * user_data; - uint32_t user_data_len; - - /* 64bit alignment */ - uint32_t pad_for_64bit_align; - - mraid_passthru_t __user *user_pthru; - - mraid_passthru_t *pthru32; - dma_addr_t pthru32_h; - - struct list_head list; - void (*done)(struct uioc*); - - caddr_t buf_vaddr; - dma_addr_t buf_paddr; - int8_t pool_index; - uint8_t free_buf; - - uint8_t timedout; - -} __attribute__ ((aligned(1024),packed)) uioc_t; - - -/** - * struct mraid_hba_info - information about the controller - * - * @pci_vendor_id : PCI vendor id - * @pci_device_id : PCI device id - * @subsystem_vendor_id : PCI subsystem vendor id - * @subsystem_device_id : PCI subsystem device id - * @baseport : base port of hba memory - * @pci_bus : PCI bus - * @pci_dev_fn : PCI device/function values - * @irq : interrupt vector for the device - * - * Extended information of 256 bytes about the controller. Align on the single - * byte boundary so that 32-bit applications can be run on 64-bit platform - * drivers withoug re-compilation. - * NOTE: reduce the number of reserved bytes whenever new field are added, so - * that total size of the structure remains 256 bytes. - */ -typedef struct mraid_hba_info { - - uint16_t pci_vendor_id; - uint16_t pci_device_id; - uint16_t subsys_vendor_id; - uint16_t subsys_device_id; - - uint64_t baseport; - uint8_t pci_bus; - uint8_t pci_dev_fn; - uint8_t pci_slot; - uint8_t irq; - - uint32_t unique_id; - uint32_t host_no; - - uint8_t num_ldrv; -} __attribute__ ((aligned(256), packed)) mraid_hba_info_t; - - -/** - * mcontroller : adapter info structure for old mimd_t apps - * - * @base : base address - * @irq : irq number - * @numldrv : number of logical drives - * @pcibus : pci bus - * @pcidev : pci device - * @pcifun : pci function - * @pciid : pci id - * @pcivendor : vendor id - * @pcislot : slot number - * @uid : unique id - */ -typedef struct mcontroller { - - uint64_t base; - uint8_t irq; - uint8_t numldrv; - uint8_t pcibus; - uint16_t pcidev; - uint8_t pcifun; - uint16_t pciid; - uint16_t pcivendor; - uint8_t pcislot; - uint32_t uid; - -} __attribute__ ((packed)) mcontroller_t; - - -/** - * mm_dmapool_t : Represents one dma pool with just one buffer - * - * @vaddr : Virtual address - * @paddr : DMA physicall address - * @bufsize : In KB - 4 = 4k, 8 = 8k etc. - * @handle : Handle to the dma pool - * @lock : lock to synchronize access to the pool - * @in_use : If pool already in use, attach new block - */ -typedef struct mm_dmapool { - caddr_t vaddr; - dma_addr_t paddr; - uint32_t buf_size; - struct dma_pool *handle; - spinlock_t lock; - uint8_t in_use; -} mm_dmapool_t; - - -/** - * mraid_mmadp_t: Structure that drivers pass during (un)registration - * - * @unique_id : Any unique id (usually PCI bus+dev+fn) - * @drvr_type : megaraid or hpe (DRVRTYPE_MBOX or DRVRTYPE_HPE) - * @drv_data : Driver specific; not touched by the common module - * @timeout : timeout for issued kiocs - * @max_kioc : Maximum ioctl packets acceptable by the lld - * @pdev : pci dev; used for allocating dma'ble memory - * @issue_uioc : Driver supplied routine to issue uioc_t commands - * : issue_uioc(drvr_data, kioc, ISSUE/ABORT, uioc_done) - * @quiescent : flag to indicate if ioctl can be issued to this adp - * @list : attach with the global list of adapters - * @kioc_list : block of mem for @max_kioc number of kiocs - * @kioc_pool : pool of free kiocs - * @kioc_pool_lock : protection for free pool - * @kioc_semaphore : so as not to exceed @max_kioc parallel ioctls - * @mbox_list : block of mem for @max_kioc number of mboxes - * @pthru_dma_pool : DMA pool to allocate passthru packets - * @dma_pool_list : array of dma pools - */ - -typedef struct mraid_mmadp { - -/* Filled by driver */ - - uint32_t unique_id; - uint32_t drvr_type; - unsigned long drvr_data; - uint16_t timeout; - uint8_t max_kioc; - - struct pci_dev *pdev; - - int(*issue_uioc)(unsigned long, uioc_t *, uint32_t); - -/* Maintained by common module */ - uint32_t quiescent; - - struct list_head list; - uioc_t *kioc_list; - struct list_head kioc_pool; - spinlock_t kioc_pool_lock; - struct semaphore kioc_semaphore; - - mbox64_t *mbox_list; - struct dma_pool *pthru_dma_pool; - mm_dmapool_t dma_pool_list[MAX_DMA_POOLS]; - -} mraid_mmadp_t; - -int mraid_mm_register_adp(mraid_mmadp_t *); -int mraid_mm_unregister_adp(uint32_t); -uint32_t mraid_mm_adapter_app_handle(uint32_t); - -#endif /* _MEGARAID_IOCTL_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mbox.c b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mbox.c deleted file mode 100644 index 35bd1387..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mbox.c +++ /dev/null @@ -1,4173 +0,0 @@ -/* - * - * Linux MegaRAID device driver - * - * Copyright (c) 2003-2004 LSI Logic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * FILE : megaraid_mbox.c - * Version : v2.20.5.1 (Nov 16 2006) - * - * Authors: - * Atul Mukker - * Sreenivas Bagalkote - * Manoj Jose - * Seokmann Ju - * - * List of supported controllers - * - * OEM Product Name VID DID SSVID SSID - * --- ------------ --- --- ---- ---- - * Dell PERC3/QC 101E 1960 1028 0471 - * Dell PERC3/DC 101E 1960 1028 0493 - * Dell PERC3/SC 101E 1960 1028 0475 - * Dell PERC3/Di 1028 1960 1028 0123 - * Dell PERC4/SC 1000 1960 1028 0520 - * Dell PERC4/DC 1000 1960 1028 0518 - * Dell PERC4/QC 1000 0407 1028 0531 - * Dell PERC4/Di 1028 000F 1028 014A - * Dell PERC 4e/Si 1028 0013 1028 016c - * Dell PERC 4e/Di 1028 0013 1028 016d - * Dell PERC 4e/Di 1028 0013 1028 016e - * Dell PERC 4e/Di 1028 0013 1028 016f - * Dell PERC 4e/Di 1028 0013 1028 0170 - * Dell PERC 4e/DC 1000 0408 1028 0002 - * Dell PERC 4e/SC 1000 0408 1028 0001 - * - * - * LSI MegaRAID SCSI 320-0 1000 1960 1000 A520 - * LSI MegaRAID SCSI 320-1 1000 1960 1000 0520 - * LSI MegaRAID SCSI 320-2 1000 1960 1000 0518 - * LSI MegaRAID SCSI 320-0X 1000 0407 1000 0530 - * LSI MegaRAID SCSI 320-2X 1000 0407 1000 0532 - * LSI MegaRAID SCSI 320-4X 1000 0407 1000 0531 - * LSI MegaRAID SCSI 320-1E 1000 0408 1000 0001 - * LSI MegaRAID SCSI 320-2E 1000 0408 1000 0002 - * LSI MegaRAID SATA 150-4 1000 1960 1000 4523 - * LSI MegaRAID SATA 150-6 1000 1960 1000 0523 - * LSI MegaRAID SATA 300-4X 1000 0409 1000 3004 - * LSI MegaRAID SATA 300-8X 1000 0409 1000 3008 - * - * INTEL RAID Controller SRCU42X 1000 0407 8086 0532 - * INTEL RAID Controller SRCS16 1000 1960 8086 0523 - * INTEL RAID Controller SRCU42E 1000 0408 8086 0002 - * INTEL RAID Controller SRCZCRX 1000 0407 8086 0530 - * INTEL RAID Controller SRCS28X 1000 0409 8086 3008 - * INTEL RAID Controller SROMBU42E 1000 0408 8086 3431 - * INTEL RAID Controller SROMBU42E 1000 0408 8086 3499 - * INTEL RAID Controller SRCU51L 1000 1960 8086 0520 - * - * FSC MegaRAID PCI Express ROMB 1000 0408 1734 1065 - * - * ACER MegaRAID ROMB-2E 1000 0408 1025 004D - * - * NEC MegaRAID PCI Express ROMB 1000 0408 1033 8287 - * - * For history of changes, see Documentation/scsi/ChangeLog.megaraid - */ - -#include -#include -#include "megaraid_mbox.h" - -static int megaraid_init(void); -static void megaraid_exit(void); - -static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *); -static void megaraid_detach_one(struct pci_dev *); -static void megaraid_mbox_shutdown(struct pci_dev *); - -static int megaraid_io_attach(adapter_t *); -static void megaraid_io_detach(adapter_t *); - -static int megaraid_init_mbox(adapter_t *); -static void megaraid_fini_mbox(adapter_t *); - -static int megaraid_alloc_cmd_packets(adapter_t *); -static void megaraid_free_cmd_packets(adapter_t *); - -static int megaraid_mbox_setup_dma_pools(adapter_t *); -static void megaraid_mbox_teardown_dma_pools(adapter_t *); - -static int megaraid_sysfs_alloc_resources(adapter_t *); -static void megaraid_sysfs_free_resources(adapter_t *); - -static int megaraid_abort_handler(struct scsi_cmnd *); -static int megaraid_reset_handler(struct scsi_cmnd *); - -static int mbox_post_sync_cmd(adapter_t *, uint8_t []); -static int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []); -static int megaraid_busywait_mbox(mraid_device_t *); -static int megaraid_mbox_product_info(adapter_t *); -static int megaraid_mbox_extended_cdb(adapter_t *); -static int megaraid_mbox_support_ha(adapter_t *, uint16_t *); -static int megaraid_mbox_support_random_del(adapter_t *); -static int megaraid_mbox_get_max_sg(adapter_t *); -static void megaraid_mbox_enum_raid_scsi(adapter_t *); -static void megaraid_mbox_flush_cache(adapter_t *); -static int megaraid_mbox_fire_sync_cmd(adapter_t *); - -static void megaraid_mbox_display_scb(adapter_t *, scb_t *); -static void megaraid_mbox_setup_device_map(adapter_t *); - -static int megaraid_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *); -static void megaraid_mbox_runpendq(adapter_t *, scb_t *); -static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *, - struct scsi_cmnd *); -static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *, - struct scsi_cmnd *); - -static irqreturn_t megaraid_isr(int, void *); - -static void megaraid_mbox_dpc(unsigned long); - -static ssize_t megaraid_sysfs_show_app_hndl(struct device *, struct device_attribute *attr, char *); -static ssize_t megaraid_sysfs_show_ldnum(struct device *, struct device_attribute *attr, char *); - -static int megaraid_cmm_register(adapter_t *); -static int megaraid_cmm_unregister(adapter_t *); -static int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t); -static int megaraid_mbox_mm_command(adapter_t *, uioc_t *); -static void megaraid_mbox_mm_done(adapter_t *, scb_t *); -static int gather_hbainfo(adapter_t *, mraid_hba_info_t *); -static int wait_till_fw_empty(adapter_t *); - - - -MODULE_AUTHOR("megaraidlinux@lsi.com"); -MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MEGARAID_VERSION); - -/* - * ### modules parameters for driver ### - */ - -/* - * Set to enable driver to expose unconfigured disk to kernel - */ -static int megaraid_expose_unconf_disks = 0; -module_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0); -MODULE_PARM_DESC(unconf_disks, - "Set to expose unconfigured disks to kernel (default=0)"); - -/* - * driver wait time if the adapter's mailbox is busy - */ -static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT; -module_param_named(busy_wait, max_mbox_busy_wait, int, 0); -MODULE_PARM_DESC(busy_wait, - "Max wait for mailbox in microseconds if busy (default=10)"); - -/* - * number of sectors per IO command - */ -static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS; -module_param_named(max_sectors, megaraid_max_sectors, int, 0); -MODULE_PARM_DESC(max_sectors, - "Maximum number of sectors per IO command (default=128)"); - -/* - * number of commands per logical unit - */ -static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN; -module_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0); -MODULE_PARM_DESC(cmd_per_lun, - "Maximum number of commands per logical unit (default=64)"); - - -/* - * Fast driver load option, skip scanning for physical devices during load. - * This would result in non-disk devices being skipped during driver load - * time. These can be later added though, using /proc/scsi/scsi - */ -static unsigned int megaraid_fast_load = 0; -module_param_named(fast_load, megaraid_fast_load, int, 0); -MODULE_PARM_DESC(fast_load, - "Faster loading of the driver, skips physical devices! (default=0)"); - - -/* - * mraid_debug level - threshold for amount of information to be displayed by - * the driver. This level can be changed through modules parameters, ioctl or - * sysfs/proc interface. By default, print the announcement messages only. - */ -int mraid_debug_level = CL_ANN; -module_param_named(debug_level, mraid_debug_level, int, 0); -MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)"); - -/* - * ### global data ### - */ -static uint8_t megaraid_mbox_version[8] = - { 0x02, 0x20, 0x04, 0x06, 3, 7, 20, 5 }; - - -/* - * PCI table for all supported controllers. - */ -static struct pci_device_id pci_id_table_g[] = { - { - PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_PERC4_DI_DISCOVERY, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4_DI_DISCOVERY, - }, - { - PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_PERC4_SC, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4_SC, - }, - { - PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_PERC4_DC, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4_DC, - }, - { - PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_VERDE, - PCI_ANY_ID, - PCI_ANY_ID, - }, - { - PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_PERC4_DI_EVERGLADES, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4_DI_EVERGLADES, - }, - { - PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_PERC4E_SI_BIGBEND, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4E_SI_BIGBEND, - }, - { - PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_PERC4E_DI_KOBUK, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4E_DI_KOBUK, - }, - { - PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_PERC4E_DI_CORVETTE, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4E_DI_CORVETTE, - }, - { - PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_PERC4E_DI_EXPEDITION, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION, - }, - { - PCI_VENDOR_ID_DELL, - PCI_DEVICE_ID_PERC4E_DI_GUADALUPE, - PCI_VENDOR_ID_DELL, - PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE, - }, - { - PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_DOBSON, - PCI_ANY_ID, - PCI_ANY_ID, - }, - { - PCI_VENDOR_ID_AMI, - PCI_DEVICE_ID_AMI_MEGARAID3, - PCI_ANY_ID, - PCI_ANY_ID, - }, - { - PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_AMI_MEGARAID3, - PCI_ANY_ID, - PCI_ANY_ID, - }, - { - PCI_VENDOR_ID_LSI_LOGIC, - PCI_DEVICE_ID_LINDSAY, - PCI_ANY_ID, - PCI_ANY_ID, - }, - {0} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, pci_id_table_g); - - -static struct pci_driver megaraid_pci_driver = { - .name = "megaraid", - .id_table = pci_id_table_g, - .probe = megaraid_probe_one, - .remove = __devexit_p(megaraid_detach_one), - .shutdown = megaraid_mbox_shutdown, -}; - - - -// definitions for the device attributes for exporting logical drive number -// for a scsi address (Host, Channel, Id, Lun) - -DEVICE_ATTR(megaraid_mbox_app_hndl, S_IRUSR, megaraid_sysfs_show_app_hndl, - NULL); - -// Host template initializer for megaraid mbox sysfs device attributes -static struct device_attribute *megaraid_shost_attrs[] = { - &dev_attr_megaraid_mbox_app_hndl, - NULL, -}; - - -DEVICE_ATTR(megaraid_mbox_ld, S_IRUSR, megaraid_sysfs_show_ldnum, NULL); - -// Host template initializer for megaraid mbox sysfs device attributes -static struct device_attribute *megaraid_sdev_attrs[] = { - &dev_attr_megaraid_mbox_ld, - NULL, -}; - -/** - * megaraid_change_queue_depth - Change the device's queue depth - * @sdev: scsi device struct - * @qdepth: depth to set - * @reason: calling context - * - * Return value: - * actual depth set - */ -static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (qdepth > MBOX_MAX_SCSI_CMDS) - qdepth = MBOX_MAX_SCSI_CMDS; - scsi_adjust_queue_depth(sdev, 0, qdepth); - return sdev->queue_depth; -} - -/* - * Scsi host template for megaraid unified driver - */ -static struct scsi_host_template megaraid_template_g = { - .module = THIS_MODULE, - .name = "LSI Logic MegaRAID driver", - .proc_name = "megaraid", - .queuecommand = megaraid_queue_command, - .eh_abort_handler = megaraid_abort_handler, - .eh_device_reset_handler = megaraid_reset_handler, - .eh_bus_reset_handler = megaraid_reset_handler, - .eh_host_reset_handler = megaraid_reset_handler, - .change_queue_depth = megaraid_change_queue_depth, - .use_clustering = ENABLE_CLUSTERING, - .sdev_attrs = megaraid_sdev_attrs, - .shost_attrs = megaraid_shost_attrs, -}; - - -/** - * megaraid_init - module load hook - * - * We register ourselves as hotplug enabled module and let PCI subsystem - * discover our adapters. - */ -static int __init -megaraid_init(void) -{ - int rval; - - // Announce the driver version - con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION, - MEGARAID_EXT_VERSION)); - - // check validity of module parameters - if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid mailbox: max commands per lun reset to %d\n", - MBOX_MAX_SCSI_CMDS)); - - megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS; - } - - - // register as a PCI hot-plug driver module - rval = pci_register_driver(&megaraid_pci_driver); - if (rval < 0) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: could not register hotplug support.\n")); - } - - return rval; -} - - -/** - * megaraid_exit - driver unload entry point - * - * We simply unwrap the megaraid_init routine here. - */ -static void __exit -megaraid_exit(void) -{ - con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n")); - - // unregister as PCI hotplug driver - pci_unregister_driver(&megaraid_pci_driver); - - return; -} - - -/** - * megaraid_probe_one - PCI hotplug entry point - * @pdev : handle to this controller's PCI configuration space - * @id : pci device id of the class of controllers - * - * This routine should be called whenever a new adapter is detected by the - * PCI hotplug susbsystem. - */ -static int __devinit -megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - adapter_t *adapter; - - - // detected a new controller - con_log(CL_ANN, (KERN_INFO - "megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", - pdev->vendor, pdev->device, pdev->subsystem_vendor, - pdev->subsystem_device)); - - con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn))); - - if (pci_enable_device(pdev)) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: pci_enable_device failed\n")); - - return -ENODEV; - } - - // Enable bus-mastering on this controller - pci_set_master(pdev); - - // Allocate the per driver initialization structure - adapter = kzalloc(sizeof(adapter_t), GFP_KERNEL); - - if (adapter == NULL) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: out of memory, %s %d.\n", __func__, __LINE__)); - - goto out_probe_one; - } - - - // set up PCI related soft state and other pre-known parameters - adapter->unique_id = pdev->bus->number << 8 | pdev->devfn; - adapter->irq = pdev->irq; - adapter->pdev = pdev; - - atomic_set(&adapter->being_detached, 0); - - // Setup the default DMA mask. This would be changed later on - // depending on hardware capabilities - if (pci_set_dma_mask(adapter->pdev, DMA_BIT_MASK(32)) != 0) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: pci_set_dma_mask failed:%d\n", __LINE__)); - - goto out_free_adapter; - } - - - // Initialize the synchronization lock for kernel and LLD - spin_lock_init(&adapter->lock); - - // Initialize the command queues: the list of free SCBs and the list - // of pending SCBs. - INIT_LIST_HEAD(&adapter->kscb_pool); - spin_lock_init(SCSI_FREE_LIST_LOCK(adapter)); - - INIT_LIST_HEAD(&adapter->pend_list); - spin_lock_init(PENDING_LIST_LOCK(adapter)); - - INIT_LIST_HEAD(&adapter->completed_list); - spin_lock_init(COMPLETED_LIST_LOCK(adapter)); - - - // Start the mailbox based controller - if (megaraid_init_mbox(adapter) != 0) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: maibox adapter did not initialize\n")); - - goto out_free_adapter; - } - - // Register with LSI Common Management Module - if (megaraid_cmm_register(adapter) != 0) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: could not register with management module\n")); - - goto out_fini_mbox; - } - - // setup adapter handle in PCI soft state - pci_set_drvdata(pdev, adapter); - - // attach with scsi mid-layer - if (megaraid_io_attach(adapter) != 0) { - - con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n")); - - goto out_cmm_unreg; - } - - return 0; - -out_cmm_unreg: - pci_set_drvdata(pdev, NULL); - megaraid_cmm_unregister(adapter); -out_fini_mbox: - megaraid_fini_mbox(adapter); -out_free_adapter: - kfree(adapter); -out_probe_one: - pci_disable_device(pdev); - - return -ENODEV; -} - - -/** - * megaraid_detach_one - release framework resources and call LLD release routine - * @pdev : handle for our PCI cofiguration space - * - * This routine is called during driver unload. We free all the allocated - * resources and call the corresponding LLD so that it can also release all - * its resources. - * - * This routine is also called from the PCI hotplug system. - */ -static void -megaraid_detach_one(struct pci_dev *pdev) -{ - adapter_t *adapter; - struct Scsi_Host *host; - - - // Start a rollback on this adapter - adapter = pci_get_drvdata(pdev); - - if (!adapter) { - con_log(CL_ANN, (KERN_CRIT - "megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", - pdev->vendor, pdev->device, pdev->subsystem_vendor, - pdev->subsystem_device)); - - return; - } - else { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", - pdev->vendor, pdev->device, pdev->subsystem_vendor, - pdev->subsystem_device)); - } - - - host = adapter->host; - - // do not allow any more requests from the management module for this - // adapter. - // FIXME: How do we account for the request which might still be - // pending with us? - atomic_set(&adapter->being_detached, 1); - - // detach from the IO sub-system - megaraid_io_detach(adapter); - - // reset the device state in the PCI structure. We check this - // condition when we enter here. If the device state is NULL, - // that would mean the device has already been removed - pci_set_drvdata(pdev, NULL); - - // Unregister from common management module - // - // FIXME: this must return success or failure for conditions if there - // is a command pending with LLD or not. - megaraid_cmm_unregister(adapter); - - // finalize the mailbox based controller and release all resources - megaraid_fini_mbox(adapter); - - kfree(adapter); - - scsi_host_put(host); - - pci_disable_device(pdev); - - return; -} - - -/** - * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA - * @pdev : generic driver model device - * - * Shutdown notification, perform flush cache. - */ -static void -megaraid_mbox_shutdown(struct pci_dev *pdev) -{ - adapter_t *adapter = pci_get_drvdata(pdev); - static int counter; - - if (!adapter) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: null device in shutdown\n")); - return; - } - - // flush caches now - con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...", - counter++)); - - megaraid_mbox_flush_cache(adapter); - - con_log(CL_ANN, ("done\n")); -} - - -/** - * megaraid_io_attach - attach a device with the IO subsystem - * @adapter : controller's soft state - * - * Attach this device with the IO subsystem. - */ -static int -megaraid_io_attach(adapter_t *adapter) -{ - struct Scsi_Host *host; - - // Initialize SCSI Host structure - host = scsi_host_alloc(&megaraid_template_g, 8); - if (!host) { - con_log(CL_ANN, (KERN_WARNING - "megaraid mbox: scsi_register failed\n")); - - return -1; - } - - SCSIHOST2ADAP(host) = (caddr_t)adapter; - adapter->host = host; - - host->irq = adapter->irq; - host->unique_id = adapter->unique_id; - host->can_queue = adapter->max_cmds; - host->this_id = adapter->init_id; - host->sg_tablesize = adapter->sglen; - host->max_sectors = adapter->max_sectors; - host->cmd_per_lun = adapter->cmd_per_lun; - host->max_channel = adapter->max_channel; - host->max_id = adapter->max_target; - host->max_lun = adapter->max_lun; - - - // notify mid-layer about the new controller - if (scsi_add_host(host, &adapter->pdev->dev)) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid mbox: scsi_add_host failed\n")); - - scsi_host_put(host); - - return -1; - } - - scsi_scan_host(host); - - return 0; -} - - -/** - * megaraid_io_detach - detach a device from the IO subsystem - * @adapter : controller's soft state - * - * Detach this device from the IO subsystem. - */ -static void -megaraid_io_detach(adapter_t *adapter) -{ - struct Scsi_Host *host; - - con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n")); - - host = adapter->host; - - scsi_remove_host(host); - - return; -} - - -/* - * START: Mailbox Low Level Driver - * - * This is section specific to the single mailbox based controllers - */ - -/** - * megaraid_init_mbox - initialize controller - * @adapter : our soft state - * - * - Allocate 16-byte aligned mailbox memory for firmware handshake - * - Allocate controller's memory resources - * - Find out all initialization data - * - Allocate memory required for all the commands - * - Use internal library of FW routines, build up complete soft state - */ -static int __devinit -megaraid_init_mbox(adapter_t *adapter) -{ - struct pci_dev *pdev; - mraid_device_t *raid_dev; - int i; - uint32_t magic64; - - - adapter->ito = MBOX_TIMEOUT; - pdev = adapter->pdev; - - /* - * Allocate and initialize the init data structure for mailbox - * controllers - */ - raid_dev = kzalloc(sizeof(mraid_device_t), GFP_KERNEL); - if (raid_dev == NULL) return -1; - - - /* - * Attach the adapter soft state to raid device soft state - */ - adapter->raid_device = (caddr_t)raid_dev; - raid_dev->fast_load = megaraid_fast_load; - - - // our baseport - raid_dev->baseport = pci_resource_start(pdev, 0); - - if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: mem region busy\n")); - - goto out_free_raid_dev; - } - - raid_dev->baseaddr = ioremap_nocache(raid_dev->baseport, 128); - - if (!raid_dev->baseaddr) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: could not map hba memory\n") ); - - goto out_release_regions; - } - - /* initialize the mutual exclusion lock for the mailbox */ - spin_lock_init(&raid_dev->mailbox_lock); - - /* allocate memory required for commands */ - if (megaraid_alloc_cmd_packets(adapter) != 0) - goto out_iounmap; - - /* - * Issue SYNC cmd to flush the pending cmds in the adapter - * and initialize its internal state - */ - - if (megaraid_mbox_fire_sync_cmd(adapter)) - con_log(CL_ANN, ("megaraid: sync cmd failed\n")); - - /* - * Setup the rest of the soft state using the library of - * FW routines - */ - - /* request IRQ and register the interrupt service routine */ - if (request_irq(adapter->irq, megaraid_isr, IRQF_SHARED, "megaraid", - adapter)) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: Couldn't register IRQ %d!\n", adapter->irq)); - goto out_alloc_cmds; - - } - - // Product info - if (megaraid_mbox_product_info(adapter) != 0) - goto out_free_irq; - - // Do we support extended CDBs - adapter->max_cdb_sz = 10; - if (megaraid_mbox_extended_cdb(adapter) == 0) { - adapter->max_cdb_sz = 16; - } - - /* - * Do we support cluster environment, if we do, what is the initiator - * id. - * NOTE: In a non-cluster aware firmware environment, the LLD should - * return 7 as initiator id. - */ - adapter->ha = 0; - adapter->init_id = -1; - if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) { - adapter->ha = 1; - } - - /* - * Prepare the device ids array to have the mapping between the kernel - * device address and megaraid device address. - * We export the physical devices on their actual addresses. The - * logical drives are exported on a virtual SCSI channel - */ - megaraid_mbox_setup_device_map(adapter); - - // If the firmware supports random deletion, update the device id map - if (megaraid_mbox_support_random_del(adapter)) { - - // Change the logical drives numbers in device_ids array one - // slot in device_ids is reserved for target id, that's why - // "<=" below - for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) { - adapter->device_ids[adapter->max_channel][i] += 0x80; - } - adapter->device_ids[adapter->max_channel][adapter->init_id] = - 0xFF; - - raid_dev->random_del_supported = 1; - } - - /* - * find out the maximum number of scatter-gather elements supported by - * this firmware - */ - adapter->sglen = megaraid_mbox_get_max_sg(adapter); - - // enumerate RAID and SCSI channels so that all devices on SCSI - // channels can later be exported, including disk devices - megaraid_mbox_enum_raid_scsi(adapter); - - /* - * Other parameters required by upper layer - * - * maximum number of sectors per IO command - */ - adapter->max_sectors = megaraid_max_sectors; - - /* - * number of queued commands per LUN. - */ - adapter->cmd_per_lun = megaraid_cmd_per_lun; - - /* - * Allocate resources required to issue FW calls, when sysfs is - * accessed - */ - if (megaraid_sysfs_alloc_resources(adapter) != 0) - goto out_free_irq; - - // Set the DMA mask to 64-bit. All supported controllers as capable of - // DMA in this range - pci_read_config_dword(adapter->pdev, PCI_CONF_AMISIG64, &magic64); - - if (((magic64 == HBA_SIGNATURE_64_BIT) && - ((adapter->pdev->subsystem_device != - PCI_SUBSYS_ID_MEGARAID_SATA_150_6) && - (adapter->pdev->subsystem_device != - PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) || - (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && - adapter->pdev->device == PCI_DEVICE_ID_VERDE) || - (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && - adapter->pdev->device == PCI_DEVICE_ID_DOBSON) || - (adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC && - adapter->pdev->device == PCI_DEVICE_ID_LINDSAY) || - (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && - adapter->pdev->device == PCI_DEVICE_ID_PERC4_DI_EVERGLADES) || - (adapter->pdev->vendor == PCI_VENDOR_ID_DELL && - adapter->pdev->device == PCI_DEVICE_ID_PERC4E_DI_KOBUK)) { - if (pci_set_dma_mask(adapter->pdev, DMA_BIT_MASK(64))) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: DMA mask for 64-bit failed\n")); - - if (pci_set_dma_mask (adapter->pdev, DMA_BIT_MASK(32))) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: 32-bit DMA mask failed\n")); - goto out_free_sysfs_res; - } - } - } - - // setup tasklet for DPC - tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc, - (unsigned long)adapter); - - con_log(CL_DLEVEL1, (KERN_INFO - "megaraid mbox hba successfully initialized\n")); - - return 0; - -out_free_sysfs_res: - megaraid_sysfs_free_resources(adapter); -out_free_irq: - free_irq(adapter->irq, adapter); -out_alloc_cmds: - megaraid_free_cmd_packets(adapter); -out_iounmap: - iounmap(raid_dev->baseaddr); -out_release_regions: - pci_release_regions(pdev); -out_free_raid_dev: - kfree(raid_dev); - - return -1; -} - - -/** - * megaraid_fini_mbox - undo controller initialization - * @adapter : our soft state - */ -static void -megaraid_fini_mbox(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - - // flush all caches - megaraid_mbox_flush_cache(adapter); - - tasklet_kill(&adapter->dpc_h); - - megaraid_sysfs_free_resources(adapter); - - megaraid_free_cmd_packets(adapter); - - free_irq(adapter->irq, adapter); - - iounmap(raid_dev->baseaddr); - - pci_release_regions(adapter->pdev); - - kfree(raid_dev); - - return; -} - - -/** - * megaraid_alloc_cmd_packets - allocate shared mailbox - * @adapter : soft state of the raid controller - * - * Allocate and align the shared mailbox. This maibox is used to issue - * all the commands. For IO based controllers, the mailbox is also regsitered - * with the FW. Allocate memory for all commands as well. - * This is our big allocator. - */ -static int -megaraid_alloc_cmd_packets(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - struct pci_dev *pdev; - unsigned long align; - scb_t *scb; - mbox_ccb_t *ccb; - struct mraid_pci_blk *epthru_pci_blk; - struct mraid_pci_blk *sg_pci_blk; - struct mraid_pci_blk *mbox_pci_blk; - int i; - - pdev = adapter->pdev; - - /* - * Setup the mailbox - * Allocate the common 16-byte aligned memory for the handshake - * mailbox. - */ - raid_dev->una_mbox64 = pci_alloc_consistent(adapter->pdev, - sizeof(mbox64_t), &raid_dev->una_mbox64_dma); - - if (!raid_dev->una_mbox64) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: out of memory, %s %d\n", __func__, - __LINE__)); - return -1; - } - memset(raid_dev->una_mbox64, 0, sizeof(mbox64_t)); - - /* - * Align the mailbox at 16-byte boundary - */ - raid_dev->mbox = &raid_dev->una_mbox64->mbox32; - - raid_dev->mbox = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) & - (~0UL ^ 0xFUL)); - - raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8); - - align = ((void *)raid_dev->mbox - - ((void *)&raid_dev->una_mbox64->mbox32)); - - raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 + - align; - - // Allocate memory for commands issued internally - adapter->ibuf = pci_alloc_consistent(pdev, MBOX_IBUF_SIZE, - &adapter->ibuf_dma_h); - if (!adapter->ibuf) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: out of memory, %s %d\n", __func__, - __LINE__)); - - goto out_free_common_mbox; - } - memset(adapter->ibuf, 0, MBOX_IBUF_SIZE); - - // Allocate memory for our SCSI Command Blocks and their associated - // memory - - /* - * Allocate memory for the base list of scb. Later allocate memory for - * CCBs and embedded components of each CCB and point the pointers in - * scb to the allocated components - * NOTE: The code to allocate SCB will be duplicated in all the LLD - * since the calling routine does not yet know the number of available - * commands. - */ - adapter->kscb_list = kcalloc(MBOX_MAX_SCSI_CMDS, sizeof(scb_t), GFP_KERNEL); - - if (adapter->kscb_list == NULL) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: out of memory, %s %d\n", __func__, - __LINE__)); - goto out_free_ibuf; - } - - // memory allocation for our command packets - if (megaraid_mbox_setup_dma_pools(adapter) != 0) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: out of memory, %s %d\n", __func__, - __LINE__)); - goto out_free_scb_list; - } - - // Adjust the scb pointers and link in the free pool - epthru_pci_blk = raid_dev->epthru_pool; - sg_pci_blk = raid_dev->sg_pool; - mbox_pci_blk = raid_dev->mbox_pool; - - for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { - scb = adapter->kscb_list + i; - ccb = raid_dev->ccb_list + i; - - ccb->mbox = (mbox_t *)(mbox_pci_blk[i].vaddr + 16); - ccb->raw_mbox = (uint8_t *)ccb->mbox; - ccb->mbox64 = (mbox64_t *)(mbox_pci_blk[i].vaddr + 8); - ccb->mbox_dma_h = (unsigned long)mbox_pci_blk[i].dma_addr + 16; - - // make sure the mailbox is aligned properly - if (ccb->mbox_dma_h & 0x0F) { - con_log(CL_ANN, (KERN_CRIT - "megaraid mbox: not aligned on 16-bytes\n")); - - goto out_teardown_dma_pools; - } - - ccb->epthru = (mraid_epassthru_t *) - epthru_pci_blk[i].vaddr; - ccb->epthru_dma_h = epthru_pci_blk[i].dma_addr; - ccb->pthru = (mraid_passthru_t *)ccb->epthru; - ccb->pthru_dma_h = ccb->epthru_dma_h; - - - ccb->sgl64 = (mbox_sgl64 *)sg_pci_blk[i].vaddr; - ccb->sgl_dma_h = sg_pci_blk[i].dma_addr; - ccb->sgl32 = (mbox_sgl32 *)ccb->sgl64; - - scb->ccb = (caddr_t)ccb; - scb->gp = 0; - - scb->sno = i; // command index - - scb->scp = NULL; - scb->state = SCB_FREE; - scb->dma_direction = PCI_DMA_NONE; - scb->dma_type = MRAID_DMA_NONE; - scb->dev_channel = -1; - scb->dev_target = -1; - - // put scb in the free pool - list_add_tail(&scb->list, &adapter->kscb_pool); - } - - return 0; - -out_teardown_dma_pools: - megaraid_mbox_teardown_dma_pools(adapter); -out_free_scb_list: - kfree(adapter->kscb_list); -out_free_ibuf: - pci_free_consistent(pdev, MBOX_IBUF_SIZE, (void *)adapter->ibuf, - adapter->ibuf_dma_h); -out_free_common_mbox: - pci_free_consistent(adapter->pdev, sizeof(mbox64_t), - (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); - - return -1; -} - - -/** - * megaraid_free_cmd_packets - free memory - * @adapter : soft state of the raid controller - * - * Release memory resources allocated for commands. - */ -static void -megaraid_free_cmd_packets(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - - megaraid_mbox_teardown_dma_pools(adapter); - - kfree(adapter->kscb_list); - - pci_free_consistent(adapter->pdev, MBOX_IBUF_SIZE, - (void *)adapter->ibuf, adapter->ibuf_dma_h); - - pci_free_consistent(adapter->pdev, sizeof(mbox64_t), - (caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma); - return; -} - - -/** - * megaraid_mbox_setup_dma_pools - setup dma pool for command packets - * @adapter : HBA soft state - * - * Setup the dma pools for mailbox, passthru and extended passthru structures, - * and scatter-gather lists. - */ -static int -megaraid_mbox_setup_dma_pools(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - struct mraid_pci_blk *epthru_pci_blk; - struct mraid_pci_blk *sg_pci_blk; - struct mraid_pci_blk *mbox_pci_blk; - int i; - - - - // Allocate memory for 16-bytes aligned mailboxes - raid_dev->mbox_pool_handle = pci_pool_create("megaraid mbox pool", - adapter->pdev, - sizeof(mbox64_t) + 16, - 16, 0); - - if (raid_dev->mbox_pool_handle == NULL) { - goto fail_setup_dma_pool; - } - - mbox_pci_blk = raid_dev->mbox_pool; - for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { - mbox_pci_blk[i].vaddr = pci_pool_alloc( - raid_dev->mbox_pool_handle, - GFP_KERNEL, - &mbox_pci_blk[i].dma_addr); - if (!mbox_pci_blk[i].vaddr) { - goto fail_setup_dma_pool; - } - } - - /* - * Allocate memory for each embedded passthru strucuture pointer - * Request for a 128 bytes aligned structure for each passthru command - * structure - * Since passthru and extended passthru commands are exclusive, they - * share common memory pool. Passthru structures piggyback on memory - * allocted to extended passthru since passthru is smaller of the two - */ - raid_dev->epthru_pool_handle = pci_pool_create("megaraid mbox pthru", - adapter->pdev, sizeof(mraid_epassthru_t), 128, 0); - - if (raid_dev->epthru_pool_handle == NULL) { - goto fail_setup_dma_pool; - } - - epthru_pci_blk = raid_dev->epthru_pool; - for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { - epthru_pci_blk[i].vaddr = pci_pool_alloc( - raid_dev->epthru_pool_handle, - GFP_KERNEL, - &epthru_pci_blk[i].dma_addr); - if (!epthru_pci_blk[i].vaddr) { - goto fail_setup_dma_pool; - } - } - - - // Allocate memory for each scatter-gather list. Request for 512 bytes - // alignment for each sg list - raid_dev->sg_pool_handle = pci_pool_create("megaraid mbox sg", - adapter->pdev, - sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE, - 512, 0); - - if (raid_dev->sg_pool_handle == NULL) { - goto fail_setup_dma_pool; - } - - sg_pci_blk = raid_dev->sg_pool; - for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { - sg_pci_blk[i].vaddr = pci_pool_alloc( - raid_dev->sg_pool_handle, - GFP_KERNEL, - &sg_pci_blk[i].dma_addr); - if (!sg_pci_blk[i].vaddr) { - goto fail_setup_dma_pool; - } - } - - return 0; - -fail_setup_dma_pool: - megaraid_mbox_teardown_dma_pools(adapter); - return -1; -} - - -/** - * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets - * @adapter : HBA soft state - * - * Teardown the dma pool for mailbox, passthru and extended passthru - * structures, and scatter-gather lists. - */ -static void -megaraid_mbox_teardown_dma_pools(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - struct mraid_pci_blk *epthru_pci_blk; - struct mraid_pci_blk *sg_pci_blk; - struct mraid_pci_blk *mbox_pci_blk; - int i; - - - sg_pci_blk = raid_dev->sg_pool; - for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) { - pci_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr, - sg_pci_blk[i].dma_addr); - } - if (raid_dev->sg_pool_handle) - pci_pool_destroy(raid_dev->sg_pool_handle); - - - epthru_pci_blk = raid_dev->epthru_pool; - for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) { - pci_pool_free(raid_dev->epthru_pool_handle, - epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr); - } - if (raid_dev->epthru_pool_handle) - pci_pool_destroy(raid_dev->epthru_pool_handle); - - - mbox_pci_blk = raid_dev->mbox_pool; - for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) { - pci_pool_free(raid_dev->mbox_pool_handle, - mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr); - } - if (raid_dev->mbox_pool_handle) - pci_pool_destroy(raid_dev->mbox_pool_handle); - - return; -} - - -/** - * megaraid_alloc_scb - detach and return a scb from the free list - * @adapter : controller's soft state - * @scp : pointer to the scsi command to be executed - * - * Return the scb from the head of the free list. %NULL if there are none - * available. - */ -static scb_t * -megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp) -{ - struct list_head *head = &adapter->kscb_pool; - scb_t *scb = NULL; - unsigned long flags; - - // detach scb from free pool - spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); - - if (list_empty(head)) { - spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); - return NULL; - } - - scb = list_entry(head->next, scb_t, list); - list_del_init(&scb->list); - - spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); - - scb->state = SCB_ACTIVE; - scb->scp = scp; - scb->dma_type = MRAID_DMA_NONE; - - return scb; -} - - -/** - * megaraid_dealloc_scb - return the scb to the free pool - * @adapter : controller's soft state - * @scb : scb to be freed - * - * Return the scb back to the free list of scbs. The caller must 'flush' the - * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc. - * NOTE NOTE: Make sure the scb is not on any list before calling this - * routine. - */ -static inline void -megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb) -{ - unsigned long flags; - - // put scb in the free pool - scb->state = SCB_FREE; - scb->scp = NULL; - spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags); - - list_add(&scb->list, &adapter->kscb_pool); - - spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags); - - return; -} - - -/** - * megaraid_mbox_mksgl - make the scatter-gather list - * @adapter : controller's soft state - * @scb : scsi control block - * - * Prepare the scatter-gather list. - */ -static int -megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb) -{ - struct scatterlist *sgl; - mbox_ccb_t *ccb; - struct scsi_cmnd *scp; - int sgcnt; - int i; - - - scp = scb->scp; - ccb = (mbox_ccb_t *)scb->ccb; - - sgcnt = scsi_dma_map(scp); - BUG_ON(sgcnt < 0 || sgcnt > adapter->sglen); - - // no mapping required if no data to be transferred - if (!sgcnt) - return 0; - - scb->dma_type = MRAID_DMA_WSG; - - scsi_for_each_sg(scp, sgl, sgcnt, i) { - ccb->sgl64[i].address = sg_dma_address(sgl); - ccb->sgl64[i].length = sg_dma_len(sgl); - } - - // Return count of SG nodes - return sgcnt; -} - - -/** - * mbox_post_cmd - issue a mailbox command - * @adapter : controller's soft state - * @scb : command to be issued - * - * Post the command to the controller if mailbox is available. - */ -static int -mbox_post_cmd(adapter_t *adapter, scb_t *scb) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox64_t *mbox64; - mbox_t *mbox; - mbox_ccb_t *ccb; - unsigned long flags; - unsigned int i = 0; - - - ccb = (mbox_ccb_t *)scb->ccb; - mbox = raid_dev->mbox; - mbox64 = raid_dev->mbox64; - - /* - * Check for busy mailbox. If it is, return failure - the caller - * should retry later. - */ - spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); - - if (unlikely(mbox->busy)) { - do { - udelay(1); - i++; - rmb(); - } while(mbox->busy && (i < max_mbox_busy_wait)); - - if (mbox->busy) { - - spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); - - return -1; - } - } - - - // Copy this command's mailbox data into "adapter's" mailbox - memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22); - mbox->cmdid = scb->sno; - - adapter->outstanding_cmds++; - - if (scb->dma_direction == PCI_DMA_TODEVICE) - pci_dma_sync_sg_for_device(adapter->pdev, - scsi_sglist(scb->scp), - scsi_sg_count(scb->scp), - PCI_DMA_TODEVICE); - - mbox->busy = 1; // Set busy - mbox->poll = 0; - mbox->ack = 0; - wmb(); - - WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); - - spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); - - return 0; -} - - -/** - * megaraid_queue_command - generic queue entry point for all LLDs - * @scp : pointer to the scsi command to be executed - * @done : callback routine to be called after the cmd has be completed - * - * Queue entry point for mailbox based controllers. - */ -static int -megaraid_queue_command_lck(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *)) -{ - adapter_t *adapter; - scb_t *scb; - int if_busy; - - adapter = SCP2ADAPTER(scp); - scp->scsi_done = done; - scp->result = 0; - - /* - * Allocate and build a SCB request - * if_busy flag will be set if megaraid_mbox_build_cmd() command could - * not allocate scb. We will return non-zero status in that case. - * NOTE: scb can be null even though certain commands completed - * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would - * return 0 in that case, and we would do the callback right away. - */ - if_busy = 0; - scb = megaraid_mbox_build_cmd(adapter, scp, &if_busy); - if (!scb) { // command already completed - done(scp); - return 0; - } - - megaraid_mbox_runpendq(adapter, scb); - return if_busy; -} - -static DEF_SCSI_QCMD(megaraid_queue_command) - -/** - * megaraid_mbox_build_cmd - transform the mid-layer scsi commands - * @adapter : controller's soft state - * @scp : mid-layer scsi command pointer - * @busy : set if request could not be completed because of lack of - * resources - * - * Transform the mid-layer scsi command to megaraid firmware lingua. - * Convert the command issued by mid-layer to format understood by megaraid - * firmware. We also complete certain commands without sending them to firmware. - */ -static scb_t * -megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy) -{ - mraid_device_t *rdev = ADAP2RAIDDEV(adapter); - int channel; - int target; - int islogical; - mbox_ccb_t *ccb; - mraid_passthru_t *pthru; - mbox64_t *mbox64; - mbox_t *mbox; - scb_t *scb; - char skip[] = "skipping"; - char scan[] = "scanning"; - char *ss; - - - /* - * Get the appropriate device map for the device this command is - * intended for - */ - MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical); - - /* - * Logical drive commands - */ - if (islogical) { - switch (scp->cmnd[0]) { - case TEST_UNIT_READY: - /* - * Do we support clustering and is the support enabled - * If no, return success always - */ - if (!adapter->ha) { - scp->result = (DID_OK << 16); - return NULL; - } - - if (!(scb = megaraid_alloc_scb(adapter, scp))) { - scp->result = (DID_ERROR << 16); - *busy = 1; - return NULL; - } - - scb->dma_direction = scp->sc_data_direction; - scb->dev_channel = 0xFF; - scb->dev_target = target; - ccb = (mbox_ccb_t *)scb->ccb; - - /* - * The command id will be provided by the command - * issuance routine - */ - ccb->raw_mbox[0] = CLUSTER_CMD; - ccb->raw_mbox[2] = RESERVATION_STATUS; - ccb->raw_mbox[3] = target; - - return scb; - - case MODE_SENSE: - { - struct scatterlist *sgl; - caddr_t vaddr; - - sgl = scsi_sglist(scp); - if (sg_page(sgl)) { - vaddr = (caddr_t) sg_virt(&sgl[0]); - - memset(vaddr, 0, scp->cmnd[4]); - } - else { - con_log(CL_ANN, (KERN_WARNING - "megaraid mailbox: invalid sg:%d\n", - __LINE__)); - } - } - scp->result = (DID_OK << 16); - return NULL; - - case INQUIRY: - /* - * Display the channel scan for logical drives - * Do not display scan for a channel if already done. - */ - if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { - - con_log(CL_ANN, (KERN_INFO - "scsi[%d]: scanning scsi channel %d", - adapter->host->host_no, - SCP2CHANNEL(scp))); - - con_log(CL_ANN, ( - " [virtual] for logical drives\n")); - - rdev->last_disp |= (1L << SCP2CHANNEL(scp)); - } - - if (scp->cmnd[1] & MEGA_SCSI_INQ_EVPD) { - scp->sense_buffer[0] = 0x70; - scp->sense_buffer[2] = ILLEGAL_REQUEST; - scp->sense_buffer[12] = MEGA_INVALID_FIELD_IN_CDB; - scp->result = CHECK_CONDITION << 1; - return NULL; - } - - /* Fall through */ - - case READ_CAPACITY: - /* - * Do not allow LUN > 0 for logical drives and - * requests for more than 40 logical drives - */ - if (SCP2LUN(scp)) { - scp->result = (DID_BAD_TARGET << 16); - return NULL; - } - if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) { - scp->result = (DID_BAD_TARGET << 16); - return NULL; - } - - - /* Allocate a SCB and initialize passthru */ - if (!(scb = megaraid_alloc_scb(adapter, scp))) { - scp->result = (DID_ERROR << 16); - *busy = 1; - return NULL; - } - - ccb = (mbox_ccb_t *)scb->ccb; - scb->dev_channel = 0xFF; - scb->dev_target = target; - pthru = ccb->pthru; - mbox = ccb->mbox; - mbox64 = ccb->mbox64; - - pthru->timeout = 0; - pthru->ars = 1; - pthru->reqsenselen = 14; - pthru->islogical = 1; - pthru->logdrv = target; - pthru->cdblen = scp->cmd_len; - memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); - - mbox->cmd = MBOXCMD_PASSTHRU64; - scb->dma_direction = scp->sc_data_direction; - - pthru->dataxferlen = scsi_bufflen(scp); - pthru->dataxferaddr = ccb->sgl_dma_h; - pthru->numsge = megaraid_mbox_mksgl(adapter, - scb); - - mbox->xferaddr = 0xFFFFFFFF; - mbox64->xferaddr_lo = (uint32_t )ccb->pthru_dma_h; - mbox64->xferaddr_hi = 0; - - return scb; - - case READ_6: - case WRITE_6: - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - - /* - * Allocate a SCB and initialize mailbox - */ - if (!(scb = megaraid_alloc_scb(adapter, scp))) { - scp->result = (DID_ERROR << 16); - *busy = 1; - return NULL; - } - ccb = (mbox_ccb_t *)scb->ccb; - scb->dev_channel = 0xFF; - scb->dev_target = target; - mbox = ccb->mbox; - mbox64 = ccb->mbox64; - mbox->logdrv = target; - - /* - * A little HACK: 2nd bit is zero for all scsi read - * commands and is set for all scsi write commands - */ - mbox->cmd = (scp->cmnd[0] & 0x02) ? MBOXCMD_LWRITE64: - MBOXCMD_LREAD64 ; - - /* - * 6-byte READ(0x08) or WRITE(0x0A) cdb - */ - if (scp->cmd_len == 6) { - mbox->numsectors = (uint32_t)scp->cmnd[4]; - mbox->lba = - ((uint32_t)scp->cmnd[1] << 16) | - ((uint32_t)scp->cmnd[2] << 8) | - (uint32_t)scp->cmnd[3]; - - mbox->lba &= 0x1FFFFF; - } - - /* - * 10-byte READ(0x28) or WRITE(0x2A) cdb - */ - else if (scp->cmd_len == 10) { - mbox->numsectors = - (uint32_t)scp->cmnd[8] | - ((uint32_t)scp->cmnd[7] << 8); - mbox->lba = - ((uint32_t)scp->cmnd[2] << 24) | - ((uint32_t)scp->cmnd[3] << 16) | - ((uint32_t)scp->cmnd[4] << 8) | - (uint32_t)scp->cmnd[5]; - } - - /* - * 12-byte READ(0xA8) or WRITE(0xAA) cdb - */ - else if (scp->cmd_len == 12) { - mbox->lba = - ((uint32_t)scp->cmnd[2] << 24) | - ((uint32_t)scp->cmnd[3] << 16) | - ((uint32_t)scp->cmnd[4] << 8) | - (uint32_t)scp->cmnd[5]; - - mbox->numsectors = - ((uint32_t)scp->cmnd[6] << 24) | - ((uint32_t)scp->cmnd[7] << 16) | - ((uint32_t)scp->cmnd[8] << 8) | - (uint32_t)scp->cmnd[9]; - } - else { - con_log(CL_ANN, (KERN_WARNING - "megaraid: unsupported CDB length\n")); - - megaraid_dealloc_scb(adapter, scb); - - scp->result = (DID_ERROR << 16); - return NULL; - } - - scb->dma_direction = scp->sc_data_direction; - - // Calculate Scatter-Gather info - mbox64->xferaddr_lo = (uint32_t )ccb->sgl_dma_h; - mbox->numsge = megaraid_mbox_mksgl(adapter, - scb); - mbox->xferaddr = 0xFFFFFFFF; - mbox64->xferaddr_hi = 0; - - return scb; - - case RESERVE: - case RELEASE: - /* - * Do we support clustering and is the support enabled - */ - if (!adapter->ha) { - scp->result = (DID_BAD_TARGET << 16); - return NULL; - } - - /* - * Allocate a SCB and initialize mailbox - */ - if (!(scb = megaraid_alloc_scb(adapter, scp))) { - scp->result = (DID_ERROR << 16); - *busy = 1; - return NULL; - } - - ccb = (mbox_ccb_t *)scb->ccb; - scb->dev_channel = 0xFF; - scb->dev_target = target; - ccb->raw_mbox[0] = CLUSTER_CMD; - ccb->raw_mbox[2] = (scp->cmnd[0] == RESERVE) ? - RESERVE_LD : RELEASE_LD; - - ccb->raw_mbox[3] = target; - scb->dma_direction = scp->sc_data_direction; - - return scb; - - default: - scp->result = (DID_BAD_TARGET << 16); - return NULL; - } - } - else { // Passthru device commands - - // Do not allow access to target id > 15 or LUN > 7 - if (target > 15 || SCP2LUN(scp) > 7) { - scp->result = (DID_BAD_TARGET << 16); - return NULL; - } - - // if fast load option was set and scan for last device is - // over, reset the fast_load flag so that during a possible - // next scan, devices can be made available - if (rdev->fast_load && (target == 15) && - (SCP2CHANNEL(scp) == adapter->max_channel -1)) { - - con_log(CL_ANN, (KERN_INFO - "megaraid[%d]: physical device scan re-enabled\n", - adapter->host->host_no)); - rdev->fast_load = 0; - } - - /* - * Display the channel scan for physical devices - */ - if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) { - - ss = rdev->fast_load ? skip : scan; - - con_log(CL_ANN, (KERN_INFO - "scsi[%d]: %s scsi channel %d [Phy %d]", - adapter->host->host_no, ss, SCP2CHANNEL(scp), - channel)); - - con_log(CL_ANN, ( - " for non-raid devices\n")); - - rdev->last_disp |= (1L << SCP2CHANNEL(scp)); - } - - // disable channel sweep if fast load option given - if (rdev->fast_load) { - scp->result = (DID_BAD_TARGET << 16); - return NULL; - } - - // Allocate a SCB and initialize passthru - if (!(scb = megaraid_alloc_scb(adapter, scp))) { - scp->result = (DID_ERROR << 16); - *busy = 1; - return NULL; - } - - ccb = (mbox_ccb_t *)scb->ccb; - scb->dev_channel = channel; - scb->dev_target = target; - scb->dma_direction = scp->sc_data_direction; - mbox = ccb->mbox; - mbox64 = ccb->mbox64; - - // Does this firmware support extended CDBs - if (adapter->max_cdb_sz == 16) { - mbox->cmd = MBOXCMD_EXTPTHRU; - - megaraid_mbox_prepare_epthru(adapter, scb, scp); - - mbox64->xferaddr_lo = (uint32_t)ccb->epthru_dma_h; - mbox64->xferaddr_hi = 0; - mbox->xferaddr = 0xFFFFFFFF; - } - else { - mbox->cmd = MBOXCMD_PASSTHRU64; - - megaraid_mbox_prepare_pthru(adapter, scb, scp); - - mbox64->xferaddr_lo = (uint32_t)ccb->pthru_dma_h; - mbox64->xferaddr_hi = 0; - mbox->xferaddr = 0xFFFFFFFF; - } - return scb; - } - - // NOT REACHED -} - - -/** - * megaraid_mbox_runpendq - execute commands queued in the pending queue - * @adapter : controller's soft state - * @scb_q : SCB to be queued in the pending list - * - * Scan the pending list for commands which are not yet issued and try to - * post to the controller. The SCB can be a null pointer, which would indicate - * no SCB to be queue, just try to execute the ones in the pending list. - * - * NOTE: We do not actually traverse the pending list. The SCBs are plucked - * out from the head of the pending list. If it is successfully issued, the - * next SCB is at the head now. - */ -static void -megaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q) -{ - scb_t *scb; - unsigned long flags; - - spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); - - if (scb_q) { - scb_q->state = SCB_PENDQ; - list_add_tail(&scb_q->list, &adapter->pend_list); - } - - // if the adapter in not in quiescent mode, post the commands to FW - if (adapter->quiescent) { - spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); - return; - } - - while (!list_empty(&adapter->pend_list)) { - - assert_spin_locked(PENDING_LIST_LOCK(adapter)); - - scb = list_entry(adapter->pend_list.next, scb_t, list); - - // remove the scb from the pending list and try to - // issue. If we are unable to issue it, put back in - // the pending list and return - - list_del_init(&scb->list); - - spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); - - // if mailbox was busy, return SCB back to pending - // list. Make sure to add at the head, since that's - // where it would have been removed from - - scb->state = SCB_ISSUED; - - if (mbox_post_cmd(adapter, scb) != 0) { - - spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); - - scb->state = SCB_PENDQ; - - list_add(&scb->list, &adapter->pend_list); - - spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), - flags); - - return; - } - - spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); - } - - spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); - - - return; -} - - -/** - * megaraid_mbox_prepare_pthru - prepare a command for physical devices - * @adapter : pointer to controller's soft state - * @scb : scsi control block - * @scp : scsi command from the mid-layer - * - * Prepare a command for the scsi physical devices. - */ -static void -megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb, - struct scsi_cmnd *scp) -{ - mbox_ccb_t *ccb; - mraid_passthru_t *pthru; - uint8_t channel; - uint8_t target; - - ccb = (mbox_ccb_t *)scb->ccb; - pthru = ccb->pthru; - channel = scb->dev_channel; - target = scb->dev_target; - - // 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout - pthru->timeout = 4; - pthru->ars = 1; - pthru->islogical = 0; - pthru->channel = 0; - pthru->target = (channel << 4) | target; - pthru->logdrv = SCP2LUN(scp); - pthru->reqsenselen = 14; - pthru->cdblen = scp->cmd_len; - - memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); - - if (scsi_bufflen(scp)) { - pthru->dataxferlen = scsi_bufflen(scp); - pthru->dataxferaddr = ccb->sgl_dma_h; - pthru->numsge = megaraid_mbox_mksgl(adapter, scb); - } - else { - pthru->dataxferaddr = 0; - pthru->dataxferlen = 0; - pthru->numsge = 0; - } - return; -} - - -/** - * megaraid_mbox_prepare_epthru - prepare a command for physical devices - * @adapter : pointer to controller's soft state - * @scb : scsi control block - * @scp : scsi command from the mid-layer - * - * Prepare a command for the scsi physical devices. This rountine prepares - * commands for devices which can take extended CDBs (>10 bytes). - */ -static void -megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb, - struct scsi_cmnd *scp) -{ - mbox_ccb_t *ccb; - mraid_epassthru_t *epthru; - uint8_t channel; - uint8_t target; - - ccb = (mbox_ccb_t *)scb->ccb; - epthru = ccb->epthru; - channel = scb->dev_channel; - target = scb->dev_target; - - // 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout - epthru->timeout = 4; - epthru->ars = 1; - epthru->islogical = 0; - epthru->channel = 0; - epthru->target = (channel << 4) | target; - epthru->logdrv = SCP2LUN(scp); - epthru->reqsenselen = 14; - epthru->cdblen = scp->cmd_len; - - memcpy(epthru->cdb, scp->cmnd, scp->cmd_len); - - if (scsi_bufflen(scp)) { - epthru->dataxferlen = scsi_bufflen(scp); - epthru->dataxferaddr = ccb->sgl_dma_h; - epthru->numsge = megaraid_mbox_mksgl(adapter, scb); - } - else { - epthru->dataxferaddr = 0; - epthru->dataxferlen = 0; - epthru->numsge = 0; - } - return; -} - - -/** - * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs - * @adapter : controller's soft state - * - * Interrupt acknowledgement sequence for memory mapped HBAs. Find out the - * completed command and put them on the completed list for later processing. - * - * Returns: 1 if the interrupt is valid, 0 otherwise - */ -static int -megaraid_ack_sequence(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox_t *mbox; - scb_t *scb; - uint8_t nstatus; - uint8_t completed[MBOX_MAX_FIRMWARE_STATUS]; - struct list_head clist; - int handled; - uint32_t dword; - unsigned long flags; - int i, j; - - - mbox = raid_dev->mbox; - - // move the SCBs from the firmware completed array to our local list - INIT_LIST_HEAD(&clist); - - // loop till F/W has more commands for us to complete - handled = 0; - spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags); - do { - /* - * Check if a valid interrupt is pending. If found, force the - * interrupt line low. - */ - dword = RDOUTDOOR(raid_dev); - if (dword != 0x10001234) break; - - handled = 1; - - WROUTDOOR(raid_dev, 0x10001234); - - nstatus = 0; - // wait for valid numstatus to post - for (i = 0; i < 0xFFFFF; i++) { - if (mbox->numstatus != 0xFF) { - nstatus = mbox->numstatus; - break; - } - rmb(); - } - mbox->numstatus = 0xFF; - - adapter->outstanding_cmds -= nstatus; - - for (i = 0; i < nstatus; i++) { - - // wait for valid command index to post - for (j = 0; j < 0xFFFFF; j++) { - if (mbox->completed[i] != 0xFF) break; - rmb(); - } - completed[i] = mbox->completed[i]; - mbox->completed[i] = 0xFF; - - if (completed[i] == 0xFF) { - con_log(CL_ANN, (KERN_CRIT - "megaraid: command posting timed out\n")); - - BUG(); - continue; - } - - // Get SCB associated with this command id - if (completed[i] >= MBOX_MAX_SCSI_CMDS) { - // a cmm command - scb = adapter->uscb_list + (completed[i] - - MBOX_MAX_SCSI_CMDS); - } - else { - // an os command - scb = adapter->kscb_list + completed[i]; - } - - scb->status = mbox->status; - list_add_tail(&scb->list, &clist); - } - - // Acknowledge interrupt - WRINDOOR(raid_dev, 0x02); - - } while(1); - - spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags); - - - // put the completed commands in the completed list. DPC would - // complete these commands later - spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); - - list_splice(&clist, &adapter->completed_list); - - spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); - - - // schedule the DPC if there is some work for it - if (handled) - tasklet_schedule(&adapter->dpc_h); - - return handled; -} - - -/** - * megaraid_isr - isr for memory based mailbox based controllers - * @irq : irq - * @devp : pointer to our soft state - * - * Interrupt service routine for memory-mapped mailbox controllers. - */ -static irqreturn_t -megaraid_isr(int irq, void *devp) -{ - adapter_t *adapter = devp; - int handled; - - handled = megaraid_ack_sequence(adapter); - - /* Loop through any pending requests */ - if (!adapter->quiescent) { - megaraid_mbox_runpendq(adapter, NULL); - } - - return IRQ_RETVAL(handled); -} - - -/** - * megaraid_mbox_sync_scb - sync kernel buffers - * @adapter : controller's soft state - * @scb : pointer to the resource packet - * - * DMA sync if required. - */ -static void -megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb) -{ - mbox_ccb_t *ccb; - - ccb = (mbox_ccb_t *)scb->ccb; - - if (scb->dma_direction == PCI_DMA_FROMDEVICE) - pci_dma_sync_sg_for_cpu(adapter->pdev, - scsi_sglist(scb->scp), - scsi_sg_count(scb->scp), - PCI_DMA_FROMDEVICE); - - scsi_dma_unmap(scb->scp); - return; -} - - -/** - * megaraid_mbox_dpc - the tasklet to complete the commands from completed list - * @devp : pointer to HBA soft state - * - * Pick up the commands from the completed list and send back to the owners. - * This is a reentrant function and does not assume any locks are held while - * it is being called. - */ -static void -megaraid_mbox_dpc(unsigned long devp) -{ - adapter_t *adapter = (adapter_t *)devp; - mraid_device_t *raid_dev; - struct list_head clist; - struct scatterlist *sgl; - scb_t *scb; - scb_t *tmp; - struct scsi_cmnd *scp; - mraid_passthru_t *pthru; - mraid_epassthru_t *epthru; - mbox_ccb_t *ccb; - int islogical; - int pdev_index; - int pdev_state; - mbox_t *mbox; - unsigned long flags; - uint8_t c; - int status; - uioc_t *kioc; - - - if (!adapter) return; - - raid_dev = ADAP2RAIDDEV(adapter); - - // move the SCBs from the completed list to our local list - INIT_LIST_HEAD(&clist); - - spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); - - list_splice_init(&adapter->completed_list, &clist); - - spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); - - - list_for_each_entry_safe(scb, tmp, &clist, list) { - - status = scb->status; - scp = scb->scp; - ccb = (mbox_ccb_t *)scb->ccb; - pthru = ccb->pthru; - epthru = ccb->epthru; - mbox = ccb->mbox; - - // Make sure f/w has completed a valid command - if (scb->state != SCB_ISSUED) { - con_log(CL_ANN, (KERN_CRIT - "megaraid critical err: invalid command %d:%d:%p\n", - scb->sno, scb->state, scp)); - BUG(); - continue; // Must never happen! - } - - // check for the management command and complete it right away - if (scb->sno >= MBOX_MAX_SCSI_CMDS) { - scb->state = SCB_FREE; - scb->status = status; - - // remove from local clist - list_del_init(&scb->list); - - kioc = (uioc_t *)scb->gp; - kioc->status = 0; - - megaraid_mbox_mm_done(adapter, scb); - - continue; - } - - // Was an abort issued for this command earlier - if (scb->state & SCB_ABORT) { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: aborted cmd [%x] completed\n", - scb->sno)); - } - - /* - * If the inquiry came of a disk drive which is not part of - * any RAID array, expose it to the kernel. For this to be - * enabled, user must set the "megaraid_expose_unconf_disks" - * flag to 1 by specifying it on module parameter list. - * This would enable data migration off drives from other - * configurations. - */ - islogical = MRAID_IS_LOGICAL(adapter, scp); - if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0 - && IS_RAID_CH(raid_dev, scb->dev_channel)) { - - sgl = scsi_sglist(scp); - if (sg_page(sgl)) { - c = *(unsigned char *) sg_virt(&sgl[0]); - } else { - con_log(CL_ANN, (KERN_WARNING - "megaraid mailbox: invalid sg:%d\n", - __LINE__)); - c = 0; - } - - if ((c & 0x1F ) == TYPE_DISK) { - pdev_index = (scb->dev_channel * 16) + - scb->dev_target; - pdev_state = - raid_dev->pdrv_state[pdev_index] & 0x0F; - - if (pdev_state == PDRV_ONLINE || - pdev_state == PDRV_FAILED || - pdev_state == PDRV_RBLD || - pdev_state == PDRV_HOTSPARE || - megaraid_expose_unconf_disks == 0) { - - status = 0xF0; - } - } - } - - // Convert MegaRAID status to Linux error code - switch (status) { - - case 0x00: - - scp->result = (DID_OK << 16); - break; - - case 0x02: - - /* set sense_buffer and result fields */ - if (mbox->cmd == MBOXCMD_PASSTHRU || - mbox->cmd == MBOXCMD_PASSTHRU64) { - - memcpy(scp->sense_buffer, pthru->reqsensearea, - 14); - - scp->result = DRIVER_SENSE << 24 | - DID_OK << 16 | CHECK_CONDITION << 1; - } - else { - if (mbox->cmd == MBOXCMD_EXTPTHRU) { - - memcpy(scp->sense_buffer, - epthru->reqsensearea, 14); - - scp->result = DRIVER_SENSE << 24 | - DID_OK << 16 | - CHECK_CONDITION << 1; - } else { - scp->sense_buffer[0] = 0x70; - scp->sense_buffer[2] = ABORTED_COMMAND; - scp->result = CHECK_CONDITION << 1; - } - } - break; - - case 0x08: - - scp->result = DID_BUS_BUSY << 16 | status; - break; - - default: - - /* - * If TEST_UNIT_READY fails, we know RESERVATION_STATUS - * failed - */ - if (scp->cmnd[0] == TEST_UNIT_READY) { - scp->result = DID_ERROR << 16 | - RESERVATION_CONFLICT << 1; - } - else - /* - * Error code returned is 1 if Reserve or Release - * failed or the input parameter is invalid - */ - if (status == 1 && (scp->cmnd[0] == RESERVE || - scp->cmnd[0] == RELEASE)) { - - scp->result = DID_ERROR << 16 | - RESERVATION_CONFLICT << 1; - } - else { - scp->result = DID_BAD_TARGET << 16 | status; - } - } - - // print a debug message for all failed commands - if (status) { - megaraid_mbox_display_scb(adapter, scb); - } - - // Free our internal resources and call the mid-layer callback - // routine - megaraid_mbox_sync_scb(adapter, scb); - - // remove from local clist - list_del_init(&scb->list); - - // put back in free list - megaraid_dealloc_scb(adapter, scb); - - // send the scsi packet back to kernel - scp->scsi_done(scp); - } - - return; -} - - -/** - * megaraid_abort_handler - abort the scsi command - * @scp : command to be aborted - * - * Abort a previous SCSI request. Only commands on the pending list can be - * aborted. All the commands issued to the F/W must complete. - **/ -static int -megaraid_abort_handler(struct scsi_cmnd *scp) -{ - adapter_t *adapter; - mraid_device_t *raid_dev; - scb_t *scb; - scb_t *tmp; - int found; - unsigned long flags; - int i; - - - adapter = SCP2ADAPTER(scp); - raid_dev = ADAP2RAIDDEV(adapter); - - con_log(CL_ANN, (KERN_WARNING - "megaraid: aborting cmd=%x \n", - scp->cmnd[0], SCP2CHANNEL(scp), - SCP2TARGET(scp), SCP2LUN(scp))); - - // If FW has stopped responding, simply return failure - if (raid_dev->hw_error) { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: hw error, not aborting\n")); - return FAILED; - } - - // There might a race here, where the command was completed by the - // firmware and now it is on the completed list. Before we could - // complete the command to the kernel in dpc, the abort came. - // Find out if this is the case to avoid the race. - scb = NULL; - spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags); - list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) { - - if (scb->scp == scp) { // Found command - - list_del_init(&scb->list); // from completed list - - con_log(CL_ANN, (KERN_WARNING - "megaraid: %d[%d:%d], abort from completed list\n", - scb->sno, scb->dev_channel, scb->dev_target)); - - scp->result = (DID_ABORT << 16); - scp->scsi_done(scp); - - megaraid_dealloc_scb(adapter, scb); - - spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), - flags); - - return SUCCESS; - } - } - spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags); - - - // Find out if this command is still on the pending list. If it is and - // was never issued, abort and return success. If the command is owned - // by the firmware, we must wait for it to complete by the FW. - spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); - list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { - - if (scb->scp == scp) { // Found command - - list_del_init(&scb->list); // from pending list - - ASSERT(!(scb->state & SCB_ISSUED)); - - con_log(CL_ANN, (KERN_WARNING - "megaraid abort: [%d:%d], driver owner\n", - scb->dev_channel, scb->dev_target)); - - scp->result = (DID_ABORT << 16); - scp->scsi_done(scp); - - megaraid_dealloc_scb(adapter, scb); - - spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), - flags); - - return SUCCESS; - } - } - spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); - - - // Check do we even own this command, in which case this would be - // owned by the firmware. The only way to locate the FW scb is to - // traverse through the list of all SCB, since driver does not - // maintain these SCBs on any list - found = 0; - spin_lock_irq(&adapter->lock); - for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) { - scb = adapter->kscb_list + i; - - if (scb->scp == scp) { - - found = 1; - - if (!(scb->state & SCB_ISSUED)) { - con_log(CL_ANN, (KERN_WARNING - "megaraid abort: %d[%d:%d], invalid state\n", - scb->sno, scb->dev_channel, scb->dev_target)); - BUG(); - } - else { - con_log(CL_ANN, (KERN_WARNING - "megaraid abort: %d[%d:%d], fw owner\n", - scb->sno, scb->dev_channel, scb->dev_target)); - } - } - } - spin_unlock_irq(&adapter->lock); - - if (!found) { - con_log(CL_ANN, (KERN_WARNING "megaraid abort: do now own\n")); - - // FIXME: Should there be a callback for this command? - return SUCCESS; - } - - // We cannot actually abort a command owned by firmware, return - // failure and wait for reset. In host reset handler, we will find out - // if the HBA is still live - return FAILED; -} - -/** - * megaraid_reset_handler - device reset hadler for mailbox based driver - * @scp : reference command - * - * Reset handler for the mailbox based controller. First try to find out if - * the FW is still live, in which case the outstanding commands counter mut go - * down to 0. If that happens, also issue the reservation reset command to - * relinquish (possible) reservations on the logical drives connected to this - * host. - **/ -static int -megaraid_reset_handler(struct scsi_cmnd *scp) -{ - adapter_t *adapter; - scb_t *scb; - scb_t *tmp; - mraid_device_t *raid_dev; - unsigned long flags; - uint8_t raw_mbox[sizeof(mbox_t)]; - int rval; - int recovery_window; - int recovering; - int i; - uioc_t *kioc; - - adapter = SCP2ADAPTER(scp); - raid_dev = ADAP2RAIDDEV(adapter); - - // return failure if adapter is not responding - if (raid_dev->hw_error) { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: hw error, cannot reset\n")); - return FAILED; - } - - - // Under exceptional conditions, FW can take up to 3 minutes to - // complete command processing. Wait for additional 2 minutes for the - // pending commands counter to go down to 0. If it doesn't, let the - // controller be marked offline - // Also, reset all the commands currently owned by the driver - spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags); - list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) { - list_del_init(&scb->list); // from pending list - - if (scb->sno >= MBOX_MAX_SCSI_CMDS) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: IOCTL packet with %d[%d:%d] being reset\n", - scb->sno, scb->dev_channel, scb->dev_target)); - - scb->status = -1; - - kioc = (uioc_t *)scb->gp; - kioc->status = -EFAULT; - - megaraid_mbox_mm_done(adapter, scb); - } else { - if (scb->scp == scp) { // Found command - con_log(CL_ANN, (KERN_WARNING - "megaraid: %d[%d:%d], reset from pending list\n", - scb->sno, scb->dev_channel, scb->dev_target)); - } else { - con_log(CL_ANN, (KERN_WARNING - "megaraid: IO packet with %d[%d:%d] being reset\n", - scb->sno, scb->dev_channel, scb->dev_target)); - } - - scb->scp->result = (DID_RESET << 16); - scb->scp->scsi_done(scb->scp); - - megaraid_dealloc_scb(adapter, scb); - } - } - spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags); - - if (adapter->outstanding_cmds) { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: %d outstanding commands. Max wait %d sec\n", - adapter->outstanding_cmds, - (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT))); - } - - recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; - - recovering = adapter->outstanding_cmds; - - for (i = 0; i < recovery_window; i++) { - - megaraid_ack_sequence(adapter); - - // print a message once every 5 seconds only - if (!(i % 5)) { - con_log(CL_ANN, ( - "megaraid mbox: Wait for %d commands to complete:%d\n", - adapter->outstanding_cmds, - (MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT) - i)); - } - - // bailout if no recovery happened in reset time - if (adapter->outstanding_cmds == 0) { - break; - } - - msleep(1000); - } - - spin_lock(&adapter->lock); - - // If still outstanding commands, bail out - if (adapter->outstanding_cmds) { - con_log(CL_ANN, (KERN_WARNING - "megaraid mbox: critical hardware error!\n")); - - raid_dev->hw_error = 1; - - rval = FAILED; - goto out; - } - else { - con_log(CL_ANN, (KERN_NOTICE - "megaraid mbox: reset sequence completed successfully\n")); - } - - - // If the controller supports clustering, reset reservations - if (!adapter->ha) { - rval = SUCCESS; - goto out; - } - - // clear reservations if any - raw_mbox[0] = CLUSTER_CMD; - raw_mbox[2] = RESET_RESERVATIONS; - - rval = SUCCESS; - if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) { - con_log(CL_ANN, - (KERN_INFO "megaraid: reservation reset\n")); - } - else { - rval = FAILED; - con_log(CL_ANN, (KERN_WARNING - "megaraid: reservation reset failed\n")); - } - - out: - spin_unlock_irq(&adapter->lock); - return rval; -} - -/* - * START: internal commands library - * - * This section of the driver has the common routine used by the driver and - * also has all the FW routines - */ - -/** - * mbox_post_sync_cmd() - blocking command to the mailbox based controllers - * @adapter : controller's soft state - * @raw_mbox : the mailbox - * - * Issue a scb in synchronous and non-interrupt mode for mailbox based - * controllers. - */ -static int -mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[]) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox64_t *mbox64; - mbox_t *mbox; - uint8_t status; - int i; - - - mbox64 = raid_dev->mbox64; - mbox = raid_dev->mbox; - - /* - * Wait until mailbox is free - */ - if (megaraid_busywait_mbox(raid_dev) != 0) - goto blocked_mailbox; - - /* - * Copy mailbox data into host structure - */ - memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); - mbox->cmdid = 0xFE; - mbox->busy = 1; - mbox->poll = 0; - mbox->ack = 0; - mbox->numstatus = 0xFF; - mbox->status = 0xFF; - - wmb(); - WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); - - // wait for maximum 1 second for status to post. If the status is not - // available within 1 second, assume FW is initializing and wait - // for an extended amount of time - if (mbox->numstatus == 0xFF) { // status not yet available - udelay(25); - - for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) { - rmb(); - msleep(1); - } - - - if (i == 1000) { - con_log(CL_ANN, (KERN_NOTICE - "megaraid mailbox: wait for FW to boot ")); - - for (i = 0; (mbox->numstatus == 0xFF) && - (i < MBOX_RESET_WAIT); i++) { - rmb(); - con_log(CL_ANN, ("\b\b\b\b\b[%03d]", - MBOX_RESET_WAIT - i)); - msleep(1000); - } - - if (i == MBOX_RESET_WAIT) { - - con_log(CL_ANN, ( - "\nmegaraid mailbox: status not available\n")); - - return -1; - } - con_log(CL_ANN, ("\b\b\b\b\b[ok] \n")); - } - } - - // wait for maximum 1 second for poll semaphore - if (mbox->poll != 0x77) { - udelay(25); - - for (i = 0; (mbox->poll != 0x77) && (i < 1000); i++) { - rmb(); - msleep(1); - } - - if (i == 1000) { - con_log(CL_ANN, (KERN_WARNING - "megaraid mailbox: could not get poll semaphore\n")); - return -1; - } - } - - WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); - wmb(); - - // wait for maximum 1 second for acknowledgement - if (RDINDOOR(raid_dev) & 0x2) { - udelay(25); - - for (i = 0; (RDINDOOR(raid_dev) & 0x2) && (i < 1000); i++) { - rmb(); - msleep(1); - } - - if (i == 1000) { - con_log(CL_ANN, (KERN_WARNING - "megaraid mailbox: could not acknowledge\n")); - return -1; - } - } - mbox->poll = 0; - mbox->ack = 0x77; - - status = mbox->status; - - // invalidate the completed command id array. After command - // completion, firmware would write the valid id. - mbox->numstatus = 0xFF; - mbox->status = 0xFF; - for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) { - mbox->completed[i] = 0xFF; - } - - return status; - -blocked_mailbox: - - con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") ); - return -1; -} - - -/** - * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers - * @adapter : controller's soft state - * @raw_mbox : the mailbox - * - * Issue a scb in synchronous and non-interrupt mode for mailbox based - * controllers. This is a faster version of the synchronous command and - * therefore can be called in interrupt-context as well. - */ -static int -mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[]) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox_t *mbox; - long i; - - - mbox = raid_dev->mbox; - - // return immediately if the mailbox is busy - if (mbox->busy) return -1; - - // Copy mailbox data into host structure - memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 14); - mbox->cmdid = 0xFE; - mbox->busy = 1; - mbox->poll = 0; - mbox->ack = 0; - mbox->numstatus = 0xFF; - mbox->status = 0xFF; - - wmb(); - WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); - - for (i = 0; i < MBOX_SYNC_WAIT_CNT; i++) { - if (mbox->numstatus != 0xFF) break; - rmb(); - udelay(MBOX_SYNC_DELAY_200); - } - - if (i == MBOX_SYNC_WAIT_CNT) { - // We may need to re-calibrate the counter - con_log(CL_ANN, (KERN_CRIT - "megaraid: fast sync command timed out\n")); - } - - WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2); - wmb(); - - return mbox->status; -} - - -/** - * megaraid_busywait_mbox() - Wait until the controller's mailbox is available - * @raid_dev : RAID device (HBA) soft state - * - * Wait until the controller's mailbox is available to accept more commands. - * Wait for at most 1 second. - */ -static int -megaraid_busywait_mbox(mraid_device_t *raid_dev) -{ - mbox_t *mbox = raid_dev->mbox; - int i = 0; - - if (mbox->busy) { - udelay(25); - for (i = 0; mbox->busy && i < 1000; i++) - msleep(1); - } - - if (i < 1000) return 0; - else return -1; -} - - -/** - * megaraid_mbox_product_info - some static information about the controller - * @adapter : our soft state - * - * Issue commands to the controller to grab some parameters required by our - * caller. - */ -static int -megaraid_mbox_product_info(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox_t *mbox; - uint8_t raw_mbox[sizeof(mbox_t)]; - mraid_pinfo_t *pinfo; - dma_addr_t pinfo_dma_h; - mraid_inquiry3_t *mraid_inq3; - int i; - - - memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); - mbox = (mbox_t *)raw_mbox; - - /* - * Issue an ENQUIRY3 command to find out certain adapter parameters, - * e.g., max channels, max commands etc. - */ - pinfo = pci_alloc_consistent(adapter->pdev, sizeof(mraid_pinfo_t), - &pinfo_dma_h); - - if (pinfo == NULL) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: out of memory, %s %d\n", __func__, - __LINE__)); - - return -1; - } - memset(pinfo, 0, sizeof(mraid_pinfo_t)); - - mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; - memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); - - raw_mbox[0] = FC_NEW_CONFIG; - raw_mbox[2] = NC_SUBOP_ENQUIRY3; - raw_mbox[3] = ENQ3_GET_SOLICITED_FULL; - - // Issue the command - if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { - - con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n")); - - pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), - pinfo, pinfo_dma_h); - - return -1; - } - - /* - * Collect information about state of each physical drive - * attached to the controller. We will expose all the disks - * which are not part of RAID - */ - mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf; - for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) { - raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i]; - } - - /* - * Get product info for information like number of channels, - * maximum commands supported. - */ - memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); - mbox->xferaddr = (uint32_t)pinfo_dma_h; - - raw_mbox[0] = FC_NEW_CONFIG; - raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; - - if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: product info failed\n")); - - pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), - pinfo, pinfo_dma_h); - - return -1; - } - - /* - * Setup some parameters for host, as required by our caller - */ - adapter->max_channel = pinfo->nchannels; - - /* - * we will export all the logical drives on a single channel. - * Add 1 since inquires do not come for inititor ID - */ - adapter->max_target = MAX_LOGICAL_DRIVES_40LD + 1; - adapter->max_lun = 8; // up to 8 LUNs for non-disk devices - - /* - * These are the maximum outstanding commands for the scsi-layer - */ - adapter->max_cmds = MBOX_MAX_SCSI_CMDS; - - memset(adapter->fw_version, 0, VERSION_SIZE); - memset(adapter->bios_version, 0, VERSION_SIZE); - - memcpy(adapter->fw_version, pinfo->fw_version, 4); - adapter->fw_version[4] = 0; - - memcpy(adapter->bios_version, pinfo->bios_version, 4); - adapter->bios_version[4] = 0; - - con_log(CL_ANN, (KERN_NOTICE - "megaraid: fw version:[%s] bios version:[%s]\n", - adapter->fw_version, adapter->bios_version)); - - pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), pinfo, - pinfo_dma_h); - - return 0; -} - - - -/** - * megaraid_mbox_extended_cdb - check for support for extended CDBs - * @adapter : soft state for the controller - * - * This routine check whether the controller in question supports extended - * ( > 10 bytes ) CDBs. - */ -static int -megaraid_mbox_extended_cdb(adapter_t *adapter) -{ - mbox_t *mbox; - uint8_t raw_mbox[sizeof(mbox_t)]; - int rval; - - mbox = (mbox_t *)raw_mbox; - - memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); - mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; - - memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); - - raw_mbox[0] = MAIN_MISC_OPCODE; - raw_mbox[2] = SUPPORT_EXT_CDB; - - /* - * Issue the command - */ - rval = 0; - if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { - rval = -1; - } - - return rval; -} - - -/** - * megaraid_mbox_support_ha - Do we support clustering - * @adapter : soft state for the controller - * @init_id : ID of the initiator - * - * Determine if the firmware supports clustering and the ID of the initiator. - */ -static int -megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id) -{ - mbox_t *mbox; - uint8_t raw_mbox[sizeof(mbox_t)]; - int rval; - - - mbox = (mbox_t *)raw_mbox; - - memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox)); - - mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; - - memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); - - raw_mbox[0] = GET_TARGET_ID; - - // Issue the command - *init_id = 7; - rval = -1; - if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { - - *init_id = *(uint8_t *)adapter->ibuf; - - con_log(CL_ANN, (KERN_INFO - "megaraid: cluster firmware, initiator ID: %d\n", - *init_id)); - - rval = 0; - } - - return rval; -} - - -/** - * megaraid_mbox_support_random_del - Do we support random deletion - * @adapter : soft state for the controller - * - * Determine if the firmware supports random deletion. - * Return: 1 is operation supported, 0 otherwise - */ -static int -megaraid_mbox_support_random_del(adapter_t *adapter) -{ - mbox_t *mbox; - uint8_t raw_mbox[sizeof(mbox_t)]; - int rval; - - /* - * Newer firmware on Dell CERC expect a different - * random deletion handling, so disable it. - */ - if (adapter->pdev->vendor == PCI_VENDOR_ID_AMI && - adapter->pdev->device == PCI_DEVICE_ID_AMI_MEGARAID3 && - adapter->pdev->subsystem_vendor == PCI_VENDOR_ID_DELL && - adapter->pdev->subsystem_device == PCI_SUBSYS_ID_CERC_ATA100_4CH && - (adapter->fw_version[0] > '6' || - (adapter->fw_version[0] == '6' && - adapter->fw_version[2] > '6') || - (adapter->fw_version[0] == '6' - && adapter->fw_version[2] == '6' - && adapter->fw_version[3] > '1'))) { - con_log(CL_DLEVEL1, ("megaraid: disable random deletion\n")); - return 0; - } - - mbox = (mbox_t *)raw_mbox; - - memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); - - raw_mbox[0] = FC_DEL_LOGDRV; - raw_mbox[2] = OP_SUP_DEL_LOGDRV; - - // Issue the command - rval = 0; - if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { - - con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n")); - - rval = 1; - } - - return rval; -} - - -/** - * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware - * @adapter : soft state for the controller - * - * Find out the maximum number of scatter-gather elements supported by the - * firmware. - */ -static int -megaraid_mbox_get_max_sg(adapter_t *adapter) -{ - mbox_t *mbox; - uint8_t raw_mbox[sizeof(mbox_t)]; - int nsg; - - - mbox = (mbox_t *)raw_mbox; - - memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); - - mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; - - memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); - - raw_mbox[0] = MAIN_MISC_OPCODE; - raw_mbox[2] = GET_MAX_SG_SUPPORT; - - // Issue the command - if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { - nsg = *(uint8_t *)adapter->ibuf; - } - else { - nsg = MBOX_DEFAULT_SG_SIZE; - } - - if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE; - - return nsg; -} - - -/** - * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels - * @adapter : soft state for the controller - * - * Enumerate the RAID and SCSI channels for ROMB platforms so that channels - * can be exported as regular SCSI channels. - */ -static void -megaraid_mbox_enum_raid_scsi(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox_t *mbox; - uint8_t raw_mbox[sizeof(mbox_t)]; - - - mbox = (mbox_t *)raw_mbox; - - memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); - - mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h; - - memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE); - - raw_mbox[0] = CHNL_CLASS; - raw_mbox[2] = GET_CHNL_CLASS; - - // Issue the command. If the command fails, all channels are RAID - // channels - raid_dev->channel_class = 0xFF; - if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) { - raid_dev->channel_class = *(uint8_t *)adapter->ibuf; - } - - return; -} - - -/** - * megaraid_mbox_flush_cache - flush adapter and disks cache - * @adapter : soft state for the controller - * - * Flush adapter cache followed by disks cache. - */ -static void -megaraid_mbox_flush_cache(adapter_t *adapter) -{ - mbox_t *mbox; - uint8_t raw_mbox[sizeof(mbox_t)]; - - - mbox = (mbox_t *)raw_mbox; - - memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); - - raw_mbox[0] = FLUSH_ADAPTER; - - if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { - con_log(CL_ANN, ("megaraid: flush adapter failed\n")); - } - - raw_mbox[0] = FLUSH_SYSTEM; - - if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) { - con_log(CL_ANN, ("megaraid: flush disks cache failed\n")); - } - - return; -} - - -/** - * megaraid_mbox_fire_sync_cmd - fire the sync cmd - * @adapter : soft state for the controller - * - * Clears the pending cmds in FW and reinits its RAID structs. - */ -static int -megaraid_mbox_fire_sync_cmd(adapter_t *adapter) -{ - mbox_t *mbox; - uint8_t raw_mbox[sizeof(mbox_t)]; - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mbox64_t *mbox64; - int status = 0; - int i; - uint32_t dword; - - mbox = (mbox_t *)raw_mbox; - - memset((caddr_t)raw_mbox, 0, sizeof(mbox_t)); - - raw_mbox[0] = 0xFF; - - mbox64 = raid_dev->mbox64; - mbox = raid_dev->mbox; - - /* Wait until mailbox is free */ - if (megaraid_busywait_mbox(raid_dev) != 0) { - status = 1; - goto blocked_mailbox; - } - - /* Copy mailbox data into host structure */ - memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16); - mbox->cmdid = 0xFE; - mbox->busy = 1; - mbox->poll = 0; - mbox->ack = 0; - mbox->numstatus = 0; - mbox->status = 0; - - wmb(); - WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1); - - /* Wait for maximum 1 min for status to post. - * If the Firmware SUPPORTS the ABOVE COMMAND, - * mbox->cmd will be set to 0 - * else - * the firmware will reject the command with - * mbox->numstatus set to 1 - */ - - i = 0; - status = 0; - while (!mbox->numstatus && mbox->cmd == 0xFF) { - rmb(); - msleep(1); - i++; - if (i > 1000 * 60) { - status = 1; - break; - } - } - if (mbox->numstatus == 1) - status = 1; /*cmd not supported*/ - - /* Check for interrupt line */ - dword = RDOUTDOOR(raid_dev); - WROUTDOOR(raid_dev, dword); - WRINDOOR(raid_dev,2); - - return status; - -blocked_mailbox: - con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n")); - return status; -} - -/** - * megaraid_mbox_display_scb - display SCB information, mostly debug purposes - * @adapter : controller's soft state - * @scb : SCB to be displayed - * @level : debug level for console print - * - * Diplay information about the given SCB iff the current debug level is - * verbose. - */ -static void -megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb) -{ - mbox_ccb_t *ccb; - struct scsi_cmnd *scp; - mbox_t *mbox; - int level; - int i; - - - ccb = (mbox_ccb_t *)scb->ccb; - scp = scb->scp; - mbox = ccb->mbox; - - level = CL_DLEVEL3; - - con_log(level, (KERN_NOTICE - "megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status, - mbox->cmd, scb->sno)); - - con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n", - mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv, - mbox->numsge)); - - if (!scp) return; - - con_log(level, (KERN_NOTICE "scsi cmnd: ")); - - for (i = 0; i < scp->cmd_len; i++) { - con_log(level, ("%#2.02x ", scp->cmnd[i])); - } - - con_log(level, ("\n")); - - return; -} - - -/** - * megaraid_mbox_setup_device_map - manage device ids - * @adapter : Driver's soft state - * - * Manange the device ids to have an appropriate mapping between the kernel - * scsi addresses and megaraid scsi and logical drive addresses. We export - * scsi devices on their actual addresses, whereas the logical drives are - * exported on a virtual scsi channel. - */ -static void -megaraid_mbox_setup_device_map(adapter_t *adapter) -{ - uint8_t c; - uint8_t t; - - /* - * First fill the values on the logical drive channel - */ - for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) - adapter->device_ids[adapter->max_channel][t] = - (t < adapter->init_id) ? t : t - 1; - - adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF; - - /* - * Fill the values on the physical devices channels - */ - for (c = 0; c < adapter->max_channel; c++) - for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++) - adapter->device_ids[c][t] = (c << 8) | t; -} - - -/* - * END: internal commands library - */ - -/* - * START: Interface for the common management module - * - * This is the module, which interfaces with the common management module to - * provide support for ioctl and sysfs - */ - -/** - * megaraid_cmm_register - register with the management module - * @adapter : HBA soft state - * - * Register with the management module, which allows applications to issue - * ioctl calls to the drivers. This interface is used by the management module - * to setup sysfs support as well. - */ -static int -megaraid_cmm_register(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - mraid_mmadp_t adp; - scb_t *scb; - mbox_ccb_t *ccb; - int rval; - int i; - - // Allocate memory for the base list of scb for management module. - adapter->uscb_list = kcalloc(MBOX_MAX_USER_CMDS, sizeof(scb_t), GFP_KERNEL); - - if (adapter->uscb_list == NULL) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: out of memory, %s %d\n", __func__, - __LINE__)); - return -1; - } - - - // Initialize the synchronization parameters for resources for - // commands for management module - INIT_LIST_HEAD(&adapter->uscb_pool); - - spin_lock_init(USER_FREE_LIST_LOCK(adapter)); - - - - // link all the packets. Note, CCB for commands, coming from the - // commom management module, mailbox physical address are already - // setup by it. We just need placeholder for that in our local command - // control blocks - for (i = 0; i < MBOX_MAX_USER_CMDS; i++) { - - scb = adapter->uscb_list + i; - ccb = raid_dev->uccb_list + i; - - scb->ccb = (caddr_t)ccb; - ccb->mbox64 = raid_dev->umbox64 + i; - ccb->mbox = &ccb->mbox64->mbox32; - ccb->raw_mbox = (uint8_t *)ccb->mbox; - - scb->gp = 0; - - // COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR - // COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER) - scb->sno = i + MBOX_MAX_SCSI_CMDS; - - scb->scp = NULL; - scb->state = SCB_FREE; - scb->dma_direction = PCI_DMA_NONE; - scb->dma_type = MRAID_DMA_NONE; - scb->dev_channel = -1; - scb->dev_target = -1; - - // put scb in the free pool - list_add_tail(&scb->list, &adapter->uscb_pool); - } - - adp.unique_id = adapter->unique_id; - adp.drvr_type = DRVRTYPE_MBOX; - adp.drvr_data = (unsigned long)adapter; - adp.pdev = adapter->pdev; - adp.issue_uioc = megaraid_mbox_mm_handler; - adp.timeout = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT; - adp.max_kioc = MBOX_MAX_USER_CMDS; - - if ((rval = mraid_mm_register_adp(&adp)) != 0) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid mbox: did not register with CMM\n")); - - kfree(adapter->uscb_list); - } - - return rval; -} - - -/** - * megaraid_cmm_unregister - un-register with the management module - * @adapter : HBA soft state - * - * Un-register with the management module. - * FIXME: mgmt module must return failure for unregister if it has pending - * commands in LLD. - */ -static int -megaraid_cmm_unregister(adapter_t *adapter) -{ - kfree(adapter->uscb_list); - mraid_mm_unregister_adp(adapter->unique_id); - return 0; -} - - -/** - * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD - * @drvr_data : LLD specific data - * @kioc : CMM interface packet - * @action : command action - * - * This routine is invoked whenever the Common Management Module (CMM) has a - * command for us. The 'action' parameter specifies if this is a new command - * or otherwise. - */ -static int -megaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action) -{ - adapter_t *adapter; - - if (action != IOCTL_ISSUE) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: unsupported management action:%#2x\n", - action)); - return (-ENOTSUPP); - } - - adapter = (adapter_t *)drvr_data; - - // make sure this adapter is not being detached right now. - if (atomic_read(&adapter->being_detached)) { - con_log(CL_ANN, (KERN_WARNING - "megaraid: reject management request, detaching\n")); - return (-ENODEV); - } - - switch (kioc->opcode) { - - case GET_ADAP_INFO: - - kioc->status = gather_hbainfo(adapter, (mraid_hba_info_t *) - (unsigned long)kioc->buf_vaddr); - - kioc->done(kioc); - - return kioc->status; - - case MBOX_CMD: - - return megaraid_mbox_mm_command(adapter, kioc); - - default: - kioc->status = (-EINVAL); - kioc->done(kioc); - return (-EINVAL); - } - - return 0; // not reached -} - -/** - * megaraid_mbox_mm_command - issues commands routed through CMM - * @adapter : HBA soft state - * @kioc : management command packet - * - * Issues commands, which are routed through the management module. - */ -static int -megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc) -{ - struct list_head *head = &adapter->uscb_pool; - mbox64_t *mbox64; - uint8_t *raw_mbox; - scb_t *scb; - mbox_ccb_t *ccb; - unsigned long flags; - - // detach one scb from free pool - spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); - - if (list_empty(head)) { // should never happen because of CMM - - con_log(CL_ANN, (KERN_WARNING - "megaraid mbox: bug in cmm handler, lost resources\n")); - - spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); - - return (-EINVAL); - } - - scb = list_entry(head->next, scb_t, list); - list_del_init(&scb->list); - - spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); - - scb->state = SCB_ACTIVE; - scb->dma_type = MRAID_DMA_NONE; - scb->dma_direction = PCI_DMA_NONE; - - ccb = (mbox_ccb_t *)scb->ccb; - mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; - raw_mbox = (uint8_t *)&mbox64->mbox32; - - memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t)); - - scb->gp = (unsigned long)kioc; - - /* - * If it is a logdrv random delete operation, we have to wait till - * there are no outstanding cmds at the fw and then issue it directly - */ - if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { - - if (wait_till_fw_empty(adapter)) { - con_log(CL_ANN, (KERN_NOTICE - "megaraid mbox: LD delete, timed out\n")); - - kioc->status = -ETIME; - - scb->status = -1; - - megaraid_mbox_mm_done(adapter, scb); - - return (-ETIME); - } - - INIT_LIST_HEAD(&scb->list); - - scb->state = SCB_ISSUED; - if (mbox_post_cmd(adapter, scb) != 0) { - - con_log(CL_ANN, (KERN_NOTICE - "megaraid mbox: LD delete, mailbox busy\n")); - - kioc->status = -EBUSY; - - scb->status = -1; - - megaraid_mbox_mm_done(adapter, scb); - - return (-EBUSY); - } - - return 0; - } - - // put the command on the pending list and execute - megaraid_mbox_runpendq(adapter, scb); - - return 0; -} - - -static int -wait_till_fw_empty(adapter_t *adapter) -{ - unsigned long flags = 0; - int i; - - - /* - * Set the quiescent flag to stop issuing cmds to FW. - */ - spin_lock_irqsave(&adapter->lock, flags); - adapter->quiescent++; - spin_unlock_irqrestore(&adapter->lock, flags); - - /* - * Wait till there are no more cmds outstanding at FW. Try for at most - * 60 seconds - */ - for (i = 0; i < 60 && adapter->outstanding_cmds; i++) { - con_log(CL_DLEVEL1, (KERN_INFO - "megaraid: FW has %d pending commands\n", - adapter->outstanding_cmds)); - - msleep(1000); - } - - return adapter->outstanding_cmds; -} - - -/** - * megaraid_mbox_mm_done - callback for CMM commands - * @adapter : HBA soft state - * @scb : completed command - * - * Callback routine for internal commands originated from the management - * module. - */ -static void -megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb) -{ - uioc_t *kioc; - mbox64_t *mbox64; - uint8_t *raw_mbox; - unsigned long flags; - - kioc = (uioc_t *)scb->gp; - mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; - mbox64->mbox32.status = scb->status; - raw_mbox = (uint8_t *)&mbox64->mbox32; - - - // put scb in the free pool - scb->state = SCB_FREE; - scb->scp = NULL; - - spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags); - - list_add(&scb->list, &adapter->uscb_pool); - - spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags); - - // if a delete logical drive operation succeeded, restart the - // controller - if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) { - - adapter->quiescent--; - - megaraid_mbox_runpendq(adapter, NULL); - } - - kioc->done(kioc); - - return; -} - - -/** - * gather_hbainfo - HBA characteristics for the applications - * @adapter : HBA soft state - * @hinfo : pointer to the caller's host info strucuture - */ -static int -gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo) -{ - uint8_t dmajor; - - dmajor = megaraid_mbox_version[0]; - - hinfo->pci_vendor_id = adapter->pdev->vendor; - hinfo->pci_device_id = adapter->pdev->device; - hinfo->subsys_vendor_id = adapter->pdev->subsystem_vendor; - hinfo->subsys_device_id = adapter->pdev->subsystem_device; - - hinfo->pci_bus = adapter->pdev->bus->number; - hinfo->pci_dev_fn = adapter->pdev->devfn; - hinfo->pci_slot = PCI_SLOT(adapter->pdev->devfn); - hinfo->irq = adapter->host->irq; - hinfo->baseport = ADAP2RAIDDEV(adapter)->baseport; - - hinfo->unique_id = (hinfo->pci_bus << 8) | adapter->pdev->devfn; - hinfo->host_no = adapter->host->host_no; - - return 0; -} - -/* - * END: Interface for the common management module - */ - - - -/** - * megaraid_sysfs_alloc_resources - allocate sysfs related resources - * @adapter : controller's soft state - * - * Allocate packets required to issue FW calls whenever the sysfs attributes - * are read. These attributes would require up-to-date information from the - * FW. Also set up resources for mutual exclusion to share these resources and - * the wait queue. - * - * Return 0 on success. - * Return -ERROR_CODE on failure. - */ -static int -megaraid_sysfs_alloc_resources(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - int rval = 0; - - raid_dev->sysfs_uioc = kmalloc(sizeof(uioc_t), GFP_KERNEL); - - raid_dev->sysfs_mbox64 = kmalloc(sizeof(mbox64_t), GFP_KERNEL); - - raid_dev->sysfs_buffer = pci_alloc_consistent(adapter->pdev, - PAGE_SIZE, &raid_dev->sysfs_buffer_dma); - - if (!raid_dev->sysfs_uioc || !raid_dev->sysfs_mbox64 || - !raid_dev->sysfs_buffer) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid: out of memory, %s %d\n", __func__, - __LINE__)); - - rval = -ENOMEM; - - megaraid_sysfs_free_resources(adapter); - } - - mutex_init(&raid_dev->sysfs_mtx); - - init_waitqueue_head(&raid_dev->sysfs_wait_q); - - return rval; -} - - -/** - * megaraid_sysfs_free_resources - free sysfs related resources - * @adapter : controller's soft state - * - * Free packets allocated for sysfs FW commands - */ -static void -megaraid_sysfs_free_resources(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - - kfree(raid_dev->sysfs_uioc); - kfree(raid_dev->sysfs_mbox64); - - if (raid_dev->sysfs_buffer) { - pci_free_consistent(adapter->pdev, PAGE_SIZE, - raid_dev->sysfs_buffer, raid_dev->sysfs_buffer_dma); - } -} - - -/** - * megaraid_sysfs_get_ldmap_done - callback for get ldmap - * @uioc : completed packet - * - * Callback routine called in the ISR/tasklet context for get ldmap call - */ -static void -megaraid_sysfs_get_ldmap_done(uioc_t *uioc) -{ - adapter_t *adapter = (adapter_t *)uioc->buf_vaddr; - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - - uioc->status = 0; - - wake_up(&raid_dev->sysfs_wait_q); -} - - -/** - * megaraid_sysfs_get_ldmap_timeout - timeout handling for get ldmap - * @data : timed out packet - * - * Timeout routine to recover and return to application, in case the adapter - * has stopped responding. A timeout of 60 seconds for this command seems like - * a good value. - */ -static void -megaraid_sysfs_get_ldmap_timeout(unsigned long data) -{ - uioc_t *uioc = (uioc_t *)data; - adapter_t *adapter = (adapter_t *)uioc->buf_vaddr; - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - - uioc->status = -ETIME; - - wake_up(&raid_dev->sysfs_wait_q); -} - - -/** - * megaraid_sysfs_get_ldmap - get update logical drive map - * @adapter : controller's soft state - * - * This routine will be called whenever user reads the logical drive - * attributes, go get the current logical drive mapping table from the - * firmware. We use the management API's to issue commands to the controller. - * - * NOTE: The commands issuance functionality is not generalized and - * implemented in context of "get ld map" command only. If required, the - * command issuance logical can be trivially pulled out and implemented as a - * standalone library. For now, this should suffice since there is no other - * user of this interface. - * - * Return 0 on success. - * Return -1 on failure. - */ -static int -megaraid_sysfs_get_ldmap(adapter_t *adapter) -{ - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - uioc_t *uioc; - mbox64_t *mbox64; - mbox_t *mbox; - char *raw_mbox; - struct timer_list sysfs_timer; - struct timer_list *timerp; - caddr_t ldmap; - int rval = 0; - - /* - * Allow only one read at a time to go through the sysfs attributes - */ - mutex_lock(&raid_dev->sysfs_mtx); - - uioc = raid_dev->sysfs_uioc; - mbox64 = raid_dev->sysfs_mbox64; - ldmap = raid_dev->sysfs_buffer; - - memset(uioc, 0, sizeof(uioc_t)); - memset(mbox64, 0, sizeof(mbox64_t)); - memset(ldmap, 0, sizeof(raid_dev->curr_ldmap)); - - mbox = &mbox64->mbox32; - raw_mbox = (char *)mbox; - uioc->cmdbuf = (uint64_t)(unsigned long)mbox64; - uioc->buf_vaddr = (caddr_t)adapter; - uioc->status = -ENODATA; - uioc->done = megaraid_sysfs_get_ldmap_done; - - /* - * Prepare the mailbox packet to get the current logical drive mapping - * table - */ - mbox->xferaddr = (uint32_t)raid_dev->sysfs_buffer_dma; - - raw_mbox[0] = FC_DEL_LOGDRV; - raw_mbox[2] = OP_GET_LDID_MAP; - - /* - * Setup a timer to recover from a non-responding controller - */ - timerp = &sysfs_timer; - init_timer(timerp); - - timerp->function = megaraid_sysfs_get_ldmap_timeout; - timerp->data = (unsigned long)uioc; - timerp->expires = jiffies + 60 * HZ; - - add_timer(timerp); - - /* - * Send the command to the firmware - */ - rval = megaraid_mbox_mm_command(adapter, uioc); - - if (rval == 0) { // command successfully issued - wait_event(raid_dev->sysfs_wait_q, (uioc->status != -ENODATA)); - - /* - * Check if the command timed out - */ - if (uioc->status == -ETIME) { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: sysfs get ld map timed out\n")); - - rval = -ETIME; - } - else { - rval = mbox->status; - } - - if (rval == 0) { - memcpy(raid_dev->curr_ldmap, ldmap, - sizeof(raid_dev->curr_ldmap)); - } - else { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: get ld map failed with %x\n", rval)); - } - } - else { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: could not issue ldmap command:%x\n", rval)); - } - - - del_timer_sync(timerp); - - mutex_unlock(&raid_dev->sysfs_mtx); - - return rval; -} - - -/** - * megaraid_sysfs_show_app_hndl - display application handle for this adapter - * @cdev : class device object representation for the host - * @buf : buffer to send data to - * - * Display the handle used by the applications while executing management - * tasks on the adapter. We invoke a management module API to get the adapter - * handle, since we do not interface with applications directly. - */ -static ssize_t -megaraid_sysfs_show_app_hndl(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(shost); - uint32_t app_hndl; - - app_hndl = mraid_mm_adapter_app_handle(adapter->unique_id); - - return snprintf(buf, 8, "%u\n", app_hndl); -} - - -/** - * megaraid_sysfs_show_ldnum - display the logical drive number for this device - * @dev : device object representation for the scsi device - * @attr : device attribute to show - * @buf : buffer to send data to - * - * Display the logical drive number for the device in question, if it a valid - * logical drive. For physical devices, "-1" is returned. - * - * The logical drive number is displayed in following format: - * - * - * - * - */ -static ssize_t -megaraid_sysfs_show_ldnum(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - adapter_t *adapter = (adapter_t *)SCSIHOST2ADAP(sdev->host); - mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); - int scsi_id = -1; - int logical_drv = -1; - int ldid_map = -1; - uint32_t app_hndl = 0; - int mapped_sdev_id; - int rval; - int i; - - if (raid_dev->random_del_supported && - MRAID_IS_LOGICAL_SDEV(adapter, sdev)) { - - rval = megaraid_sysfs_get_ldmap(adapter); - if (rval == 0) { - - for (i = 0; i < MAX_LOGICAL_DRIVES_40LD; i++) { - - mapped_sdev_id = sdev->id; - - if (sdev->id > adapter->init_id) { - mapped_sdev_id -= 1; - } - - if (raid_dev->curr_ldmap[i] == mapped_sdev_id) { - - scsi_id = sdev->id; - - logical_drv = i; - - ldid_map = raid_dev->curr_ldmap[i]; - - app_hndl = mraid_mm_adapter_app_handle( - adapter->unique_id); - - break; - } - } - } - else { - con_log(CL_ANN, (KERN_NOTICE - "megaraid: sysfs get ld map failed: %x\n", - rval)); - } - } - - return snprintf(buf, 36, "%d %d %d %d\n", scsi_id, logical_drv, - ldid_map, app_hndl); -} - - -/* - * END: Mailbox Low Level Driver - */ -module_init(megaraid_init); -module_exit(megaraid_exit); - -/* vim: set ts=8 sw=8 tw=78 ai si: */ diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mbox.h b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mbox.h deleted file mode 100644 index c1d86d96..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mbox.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * - * Linux MegaRAID device driver - * - * Copyright (c) 2003-2004 LSI Logic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * FILE : megaraid_mbox.h - */ - -#ifndef _MEGARAID_H_ -#define _MEGARAID_H_ - - -#include "mega_common.h" -#include "mbox_defs.h" -#include "megaraid_ioctl.h" - - -#define MEGARAID_VERSION "2.20.5.1" -#define MEGARAID_EXT_VERSION "(Release Date: Thu Nov 16 15:32:35 EST 2006)" - - -/* - * Define some PCI values here until they are put in the kernel - */ -#define PCI_DEVICE_ID_PERC4_DI_DISCOVERY 0x000E -#define PCI_SUBSYS_ID_PERC4_DI_DISCOVERY 0x0123 - -#define PCI_DEVICE_ID_PERC4_SC 0x1960 -#define PCI_SUBSYS_ID_PERC4_SC 0x0520 - -#define PCI_DEVICE_ID_PERC4_DC 0x1960 -#define PCI_SUBSYS_ID_PERC4_DC 0x0518 - -#define PCI_DEVICE_ID_VERDE 0x0407 - -#define PCI_DEVICE_ID_PERC4_DI_EVERGLADES 0x000F -#define PCI_SUBSYS_ID_PERC4_DI_EVERGLADES 0x014A - -#define PCI_DEVICE_ID_PERC4E_SI_BIGBEND 0x0013 -#define PCI_SUBSYS_ID_PERC4E_SI_BIGBEND 0x016c - -#define PCI_DEVICE_ID_PERC4E_DI_KOBUK 0x0013 -#define PCI_SUBSYS_ID_PERC4E_DI_KOBUK 0x016d - -#define PCI_DEVICE_ID_PERC4E_DI_CORVETTE 0x0013 -#define PCI_SUBSYS_ID_PERC4E_DI_CORVETTE 0x016e - -#define PCI_DEVICE_ID_PERC4E_DI_EXPEDITION 0x0013 -#define PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION 0x016f - -#define PCI_DEVICE_ID_PERC4E_DI_GUADALUPE 0x0013 -#define PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE 0x0170 - -#define PCI_DEVICE_ID_DOBSON 0x0408 - -#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0 0x1960 -#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0 0xA520 - -#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1 0x1960 -#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1 0x0520 - -#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2 0x1960 -#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2 0x0518 - -#define PCI_DEVICE_ID_MEGARAID_I4_133_RAID 0x1960 -#define PCI_SUBSYS_ID_MEGARAID_I4_133_RAID 0x0522 - -#define PCI_DEVICE_ID_MEGARAID_SATA_150_4 0x1960 -#define PCI_SUBSYS_ID_MEGARAID_SATA_150_4 0x4523 - -#define PCI_DEVICE_ID_MEGARAID_SATA_150_6 0x1960 -#define PCI_SUBSYS_ID_MEGARAID_SATA_150_6 0x0523 - -#define PCI_DEVICE_ID_LINDSAY 0x0409 - -#define PCI_DEVICE_ID_INTEL_RAID_SRCS16 0x1960 -#define PCI_SUBSYS_ID_INTEL_RAID_SRCS16 0x0523 - -#define PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK 0x1960 -#define PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK 0x0520 - -#define PCI_SUBSYS_ID_PERC3_QC 0x0471 -#define PCI_SUBSYS_ID_PERC3_DC 0x0493 -#define PCI_SUBSYS_ID_PERC3_SC 0x0475 -#define PCI_SUBSYS_ID_CERC_ATA100_4CH 0x0511 - - -#define MBOX_MAX_SCSI_CMDS 128 // number of cmds reserved for kernel -#define MBOX_MAX_USER_CMDS 32 // number of cmds for applications -#define MBOX_DEF_CMD_PER_LUN 64 // default commands per lun -#define MBOX_DEFAULT_SG_SIZE 26 // default sg size supported by all fw -#define MBOX_MAX_SG_SIZE 32 // maximum scatter-gather list size -#define MBOX_MAX_SECTORS 128 // maximum sectors per IO -#define MBOX_TIMEOUT 30 // timeout value for internal cmds -#define MBOX_BUSY_WAIT 10 // max usec to wait for busy mailbox -#define MBOX_RESET_WAIT 180 // wait these many seconds in reset -#define MBOX_RESET_EXT_WAIT 120 // extended wait reset -#define MBOX_SYNC_WAIT_CNT 0xFFFF // wait loop index for synchronous mode - -#define MBOX_SYNC_DELAY_200 200 // 200 micro-seconds - -/* - * maximum transfer that can happen through the firmware commands issued - * internnaly from the driver. - */ -#define MBOX_IBUF_SIZE 4096 - - -/** - * mbox_ccb_t - command control block specific to mailbox based controllers - * @raw_mbox : raw mailbox pointer - * @mbox : mailbox - * @mbox64 : extended mailbox - * @mbox_dma_h : maibox dma address - * @sgl64 : 64-bit scatter-gather list - * @sgl32 : 32-bit scatter-gather list - * @sgl_dma_h : dma handle for the scatter-gather list - * @pthru : passthru structure - * @pthru_dma_h : dma handle for the passthru structure - * @epthru : extended passthru structure - * @epthru_dma_h : dma handle for extended passthru structure - * @buf_dma_h : dma handle for buffers w/o sg list - * - * command control block specific to the mailbox based controllers - */ -typedef struct { - uint8_t *raw_mbox; - mbox_t *mbox; - mbox64_t *mbox64; - dma_addr_t mbox_dma_h; - mbox_sgl64 *sgl64; - mbox_sgl32 *sgl32; - dma_addr_t sgl_dma_h; - mraid_passthru_t *pthru; - dma_addr_t pthru_dma_h; - mraid_epassthru_t *epthru; - dma_addr_t epthru_dma_h; - dma_addr_t buf_dma_h; -} mbox_ccb_t; - - -/** - * mraid_device_t - adapter soft state structure for mailbox controllers - * @una_mbox64 : 64-bit mbox - unaligned - * @una_mbox64_dma : mbox dma addr - unaligned - * @mbox : 32-bit mbox - aligned - * @mbox64 : 64-bit mbox - aligned - * @mbox_dma : mbox dma addr - aligned - * @mailbox_lock : exclusion lock for the mailbox - * @baseport : base port of hba memory - * @baseaddr : mapped addr of hba memory - * @mbox_pool : pool of mailboxes - * @mbox_pool_handle : handle for the mailbox pool memory - * @epthru_pool : a pool for extended passthru commands - * @epthru_pool_handle : handle to the pool above - * @sg_pool : pool of scatter-gather lists for this driver - * @sg_pool_handle : handle to the pool above - * @ccb_list : list of our command control blocks - * @uccb_list : list of cmd control blocks for mgmt module - * @umbox64 : array of mailbox for user commands (cmm) - * @pdrv_state : array for state of each physical drive. - * @last_disp : flag used to show device scanning - * @hw_error : set if FW not responding - * @fast_load : If set, skip physical device scanning - * @channel_class : channel class, RAID or SCSI - * @sysfs_mtx : mutex to serialize access to sysfs res. - * @sysfs_uioc : management packet to issue FW calls from sysfs - * @sysfs_mbox64 : mailbox packet to issue FW calls from sysfs - * @sysfs_buffer : data buffer for FW commands issued from sysfs - * @sysfs_buffer_dma : DMA buffer for FW commands issued from sysfs - * @sysfs_wait_q : wait queue for sysfs operations - * @random_del_supported : set if the random deletion is supported - * @curr_ldmap : current LDID map - * - * Initialization structure for mailbox controllers: memory based and IO based - * All the fields in this structure are LLD specific and may be discovered at - * init() or start() time. - * - * NOTE: The fields of this structures are placed to minimize cache misses - */ -#define MAX_LD_EXTENDED64 64 -typedef struct { - mbox64_t *una_mbox64; - dma_addr_t una_mbox64_dma; - mbox_t *mbox; - mbox64_t *mbox64; - dma_addr_t mbox_dma; - spinlock_t mailbox_lock; - unsigned long baseport; - void __iomem * baseaddr; - struct mraid_pci_blk mbox_pool[MBOX_MAX_SCSI_CMDS]; - struct dma_pool *mbox_pool_handle; - struct mraid_pci_blk epthru_pool[MBOX_MAX_SCSI_CMDS]; - struct dma_pool *epthru_pool_handle; - struct mraid_pci_blk sg_pool[MBOX_MAX_SCSI_CMDS]; - struct dma_pool *sg_pool_handle; - mbox_ccb_t ccb_list[MBOX_MAX_SCSI_CMDS]; - mbox_ccb_t uccb_list[MBOX_MAX_USER_CMDS]; - mbox64_t umbox64[MBOX_MAX_USER_CMDS]; - - uint8_t pdrv_state[MBOX_MAX_PHYSICAL_DRIVES]; - uint32_t last_disp; - int hw_error; - int fast_load; - uint8_t channel_class; - struct mutex sysfs_mtx; - uioc_t *sysfs_uioc; - mbox64_t *sysfs_mbox64; - caddr_t sysfs_buffer; - dma_addr_t sysfs_buffer_dma; - wait_queue_head_t sysfs_wait_q; - int random_del_supported; - uint16_t curr_ldmap[MAX_LD_EXTENDED64]; -} mraid_device_t; - -// route to raid device from adapter -#define ADAP2RAIDDEV(adp) ((mraid_device_t *)((adp)->raid_device)) - -#define MAILBOX_LOCK(rdev) (&(rdev)->mailbox_lock) - -// Find out if this channel is a RAID or SCSI -#define IS_RAID_CH(rdev, ch) (((rdev)->channel_class >> (ch)) & 0x01) - - -#define RDINDOOR(rdev) readl((rdev)->baseaddr + 0x20) -#define RDOUTDOOR(rdev) readl((rdev)->baseaddr + 0x2C) -#define WRINDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x20) -#define WROUTDOOR(rdev, value) writel(value, (rdev)->baseaddr + 0x2C) - -#endif // _MEGARAID_H_ - -// vim: set ts=8 sw=8 tw=78: diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.c b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.c deleted file mode 100644 index 25506c77..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.c +++ /dev/null @@ -1,1261 +0,0 @@ -/* - * - * Linux MegaRAID device driver - * - * Copyright (c) 2003-2004 LSI Logic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * FILE : megaraid_mm.c - * Version : v2.20.2.7 (Jul 16 2006) - * - * Common management module - */ -#include -#include -#include -#include "megaraid_mm.h" - - -// Entry points for char node driver -static DEFINE_MUTEX(mraid_mm_mutex); -static int mraid_mm_open(struct inode *, struct file *); -static long mraid_mm_unlocked_ioctl(struct file *, uint, unsigned long); - - -// routines to convert to and from the old the format -static int mimd_to_kioc(mimd_t __user *, mraid_mmadp_t *, uioc_t *); -static int kioc_to_mimd(uioc_t *, mimd_t __user *); - - -// Helper functions -static int handle_drvrcmd(void __user *, uint8_t, int *); -static int lld_ioctl(mraid_mmadp_t *, uioc_t *); -static void ioctl_done(uioc_t *); -static void lld_timedout(unsigned long); -static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *); -static mraid_mmadp_t *mraid_mm_get_adapter(mimd_t __user *, int *); -static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *); -static void mraid_mm_dealloc_kioc(mraid_mmadp_t *, uioc_t *); -static int mraid_mm_attach_buf(mraid_mmadp_t *, uioc_t *, int); -static int mraid_mm_setup_dma_pools(mraid_mmadp_t *); -static void mraid_mm_free_adp_resources(mraid_mmadp_t *); -static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *); - -#ifdef CONFIG_COMPAT -static long mraid_mm_compat_ioctl(struct file *, unsigned int, unsigned long); -#endif - -MODULE_AUTHOR("LSI Logic Corporation"); -MODULE_DESCRIPTION("LSI Logic Management Module"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(LSI_COMMON_MOD_VERSION); - -static int dbglevel = CL_ANN; -module_param_named(dlevel, dbglevel, int, 0); -MODULE_PARM_DESC(dlevel, "Debug level (default=0)"); - -EXPORT_SYMBOL(mraid_mm_register_adp); -EXPORT_SYMBOL(mraid_mm_unregister_adp); -EXPORT_SYMBOL(mraid_mm_adapter_app_handle); - -static uint32_t drvr_ver = 0x02200207; - -static int adapters_count_g; -static struct list_head adapters_list_g; - -static wait_queue_head_t wait_q; - -static const struct file_operations lsi_fops = { - .open = mraid_mm_open, - .unlocked_ioctl = mraid_mm_unlocked_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = mraid_mm_compat_ioctl, -#endif - .owner = THIS_MODULE, - .llseek = noop_llseek, -}; - -static struct miscdevice megaraid_mm_dev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "megadev0", - .fops = &lsi_fops, -}; - -/** - * mraid_mm_open - open routine for char node interface - * @inode : unused - * @filep : unused - * - * Allow ioctl operations by apps only if they have superuser privilege. - */ -static int -mraid_mm_open(struct inode *inode, struct file *filep) -{ - /* - * Only allow superuser to access private ioctl interface - */ - if (!capable(CAP_SYS_ADMIN)) return (-EACCES); - - return 0; -} - -/** - * mraid_mm_ioctl - module entry-point for ioctls - * @inode : inode (ignored) - * @filep : file operations pointer (ignored) - * @cmd : ioctl command - * @arg : user ioctl packet - */ -static int -mraid_mm_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) -{ - uioc_t *kioc; - char signature[EXT_IOCTL_SIGN_SZ] = {0}; - int rval; - mraid_mmadp_t *adp; - uint8_t old_ioctl; - int drvrcmd_rval; - void __user *argp = (void __user *)arg; - - /* - * Make sure only USCSICMD are issued through this interface. - * MIMD application would still fire different command. - */ - - if ((_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD)) { - return (-EINVAL); - } - - /* - * Look for signature to see if this is the new or old ioctl format. - */ - if (copy_from_user(signature, argp, EXT_IOCTL_SIGN_SZ)) { - con_log(CL_ANN, (KERN_WARNING - "megaraid cmm: copy from usr addr failed\n")); - return (-EFAULT); - } - - if (memcmp(signature, EXT_IOCTL_SIGN, EXT_IOCTL_SIGN_SZ) == 0) - old_ioctl = 0; - else - old_ioctl = 1; - - /* - * At present, we don't support the new ioctl packet - */ - if (!old_ioctl ) - return (-EINVAL); - - /* - * If it is a driver ioctl (as opposed to fw ioctls), then we can - * handle the command locally. rval > 0 means it is not a drvr cmd - */ - rval = handle_drvrcmd(argp, old_ioctl, &drvrcmd_rval); - - if (rval < 0) - return rval; - else if (rval == 0) - return drvrcmd_rval; - - rval = 0; - if ((adp = mraid_mm_get_adapter(argp, &rval)) == NULL) { - return rval; - } - - /* - * Check if adapter can accept ioctl. We may have marked it offline - * if any previous kioc had timedout on this controller. - */ - if (!adp->quiescent) { - con_log(CL_ANN, (KERN_WARNING - "megaraid cmm: controller cannot accept cmds due to " - "earlier errors\n" )); - return -EFAULT; - } - - /* - * The following call will block till a kioc is available - */ - kioc = mraid_mm_alloc_kioc(adp); - - /* - * User sent the old mimd_t ioctl packet. Convert it to uioc_t. - */ - if ((rval = mimd_to_kioc(argp, adp, kioc))) { - mraid_mm_dealloc_kioc(adp, kioc); - return rval; - } - - kioc->done = ioctl_done; - - /* - * Issue the IOCTL to the low level driver. After the IOCTL completes - * release the kioc if and only if it was _not_ timedout. If it was - * timedout, that means that resources are still with low level driver. - */ - if ((rval = lld_ioctl(adp, kioc))) { - - if (!kioc->timedout) - mraid_mm_dealloc_kioc(adp, kioc); - - return rval; - } - - /* - * Convert the kioc back to user space - */ - rval = kioc_to_mimd(kioc, argp); - - /* - * Return the kioc to free pool - */ - mraid_mm_dealloc_kioc(adp, kioc); - - return rval; -} - -static long -mraid_mm_unlocked_ioctl(struct file *filep, unsigned int cmd, - unsigned long arg) -{ - int err; - - /* inconsistent: mraid_mm_compat_ioctl doesn't take the BKL */ - mutex_lock(&mraid_mm_mutex); - err = mraid_mm_ioctl(filep, cmd, arg); - mutex_unlock(&mraid_mm_mutex); - - return err; -} - -/** - * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet - * @umimd : User space mimd_t ioctl packet - * @rval : returned success/error status - * - * The function return value is a pointer to the located @adapter. - */ -static mraid_mmadp_t * -mraid_mm_get_adapter(mimd_t __user *umimd, int *rval) -{ - mraid_mmadp_t *adapter; - mimd_t mimd; - uint32_t adapno; - int iterator; - - - if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) { - *rval = -EFAULT; - return NULL; - } - - adapno = GETADAP(mimd.ui.fcs.adapno); - - if (adapno >= adapters_count_g) { - *rval = -ENODEV; - return NULL; - } - - adapter = NULL; - iterator = 0; - - list_for_each_entry(adapter, &adapters_list_g, list) { - if (iterator++ == adapno) break; - } - - if (!adapter) { - *rval = -ENODEV; - return NULL; - } - - return adapter; -} - -/** - * handle_drvrcmd - Checks if the opcode is a driver cmd and if it is, handles it. - * @arg : packet sent by the user app - * @old_ioctl : mimd if 1; uioc otherwise - * @rval : pointer for command's returned value (not function status) - */ -static int -handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval) -{ - mimd_t __user *umimd; - mimd_t kmimd; - uint8_t opcode; - uint8_t subopcode; - - if (old_ioctl) - goto old_packet; - else - goto new_packet; - -new_packet: - return (-ENOTSUPP); - -old_packet: - *rval = 0; - umimd = arg; - - if (copy_from_user(&kmimd, umimd, sizeof(mimd_t))) - return (-EFAULT); - - opcode = kmimd.ui.fcs.opcode; - subopcode = kmimd.ui.fcs.subopcode; - - /* - * If the opcode is 0x82 and the subopcode is either GET_DRVRVER or - * GET_NUMADP, then we can handle. Otherwise we should return 1 to - * indicate that we cannot handle this. - */ - if (opcode != 0x82) - return 1; - - switch (subopcode) { - - case MEGAIOC_QDRVRVER: - - if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t))) - return (-EFAULT); - - return 0; - - case MEGAIOC_QNADAP: - - *rval = adapters_count_g; - - if (copy_to_user(kmimd.data, &adapters_count_g, - sizeof(uint32_t))) - return (-EFAULT); - - return 0; - - default: - /* cannot handle */ - return 1; - } - - return 0; -} - - -/** - * mimd_to_kioc - Converter from old to new ioctl format - * @umimd : user space old MIMD IOCTL - * @adp : adapter softstate - * @kioc : kernel space new format IOCTL - * - * Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The - * new packet is in kernel space so that driver can perform operations on it - * freely. - */ - -static int -mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc) -{ - mbox64_t *mbox64; - mbox_t *mbox; - mraid_passthru_t *pthru32; - uint32_t adapno; - uint8_t opcode; - uint8_t subopcode; - mimd_t mimd; - - if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) - return (-EFAULT); - - /* - * Applications are not allowed to send extd pthru - */ - if ((mimd.mbox[0] == MBOXCMD_PASSTHRU64) || - (mimd.mbox[0] == MBOXCMD_EXTPTHRU)) - return (-EINVAL); - - opcode = mimd.ui.fcs.opcode; - subopcode = mimd.ui.fcs.subopcode; - adapno = GETADAP(mimd.ui.fcs.adapno); - - if (adapno >= adapters_count_g) - return (-ENODEV); - - kioc->adapno = adapno; - kioc->mb_type = MBOX_LEGACY; - kioc->app_type = APPTYPE_MIMD; - - switch (opcode) { - - case 0x82: - - if (subopcode == MEGAIOC_QADAPINFO) { - - kioc->opcode = GET_ADAP_INFO; - kioc->data_dir = UIOC_RD; - kioc->xferlen = sizeof(mraid_hba_info_t); - - if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) - return (-ENOMEM); - } - else { - con_log(CL_ANN, (KERN_WARNING - "megaraid cmm: Invalid subop\n")); - return (-EINVAL); - } - - break; - - case 0x81: - - kioc->opcode = MBOX_CMD; - kioc->xferlen = mimd.ui.fcs.length; - kioc->user_data_len = kioc->xferlen; - kioc->user_data = mimd.ui.fcs.buffer; - - if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) - return (-ENOMEM); - - if (mimd.outlen) kioc->data_dir = UIOC_RD; - if (mimd.inlen) kioc->data_dir |= UIOC_WR; - - break; - - case 0x80: - - kioc->opcode = MBOX_CMD; - kioc->xferlen = (mimd.outlen > mimd.inlen) ? - mimd.outlen : mimd.inlen; - kioc->user_data_len = kioc->xferlen; - kioc->user_data = mimd.data; - - if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen)) - return (-ENOMEM); - - if (mimd.outlen) kioc->data_dir = UIOC_RD; - if (mimd.inlen) kioc->data_dir |= UIOC_WR; - - break; - - default: - return (-EINVAL); - } - - /* - * If driver command, nothing else to do - */ - if (opcode == 0x82) - return 0; - - /* - * This is a mailbox cmd; copy the mailbox from mimd - */ - mbox64 = (mbox64_t *)((unsigned long)kioc->cmdbuf); - mbox = &mbox64->mbox32; - memcpy(mbox, mimd.mbox, 14); - - if (mbox->cmd != MBOXCMD_PASSTHRU) { // regular DCMD - - mbox->xferaddr = (uint32_t)kioc->buf_paddr; - - if (kioc->data_dir & UIOC_WR) { - if (copy_from_user(kioc->buf_vaddr, kioc->user_data, - kioc->xferlen)) { - return (-EFAULT); - } - } - - return 0; - } - - /* - * This is a regular 32-bit pthru cmd; mbox points to pthru struct. - * Just like in above case, the beginning for memblk is treated as - * a mailbox. The passthru will begin at next 1K boundary. And the - * data will start 1K after that. - */ - pthru32 = kioc->pthru32; - kioc->user_pthru = &umimd->pthru; - mbox->xferaddr = (uint32_t)kioc->pthru32_h; - - if (copy_from_user(pthru32, kioc->user_pthru, - sizeof(mraid_passthru_t))) { - return (-EFAULT); - } - - pthru32->dataxferaddr = kioc->buf_paddr; - if (kioc->data_dir & UIOC_WR) { - if (copy_from_user(kioc->buf_vaddr, kioc->user_data, - pthru32->dataxferlen)) { - return (-EFAULT); - } - } - - return 0; -} - -/** - * mraid_mm_attch_buf - Attach a free dma buffer for required size - * @adp : Adapter softstate - * @kioc : kioc that the buffer needs to be attached to - * @xferlen : required length for buffer - * - * First we search for a pool with smallest buffer that is >= @xferlen. If - * that pool has no free buffer, we will try for the next bigger size. If none - * is available, we will try to allocate the smallest buffer that is >= - * @xferlen and attach it the pool. - */ -static int -mraid_mm_attach_buf(mraid_mmadp_t *adp, uioc_t *kioc, int xferlen) -{ - mm_dmapool_t *pool; - int right_pool = -1; - unsigned long flags; - int i; - - kioc->pool_index = -1; - kioc->buf_vaddr = NULL; - kioc->buf_paddr = 0; - kioc->free_buf = 0; - - /* - * We need xferlen amount of memory. See if we can get it from our - * dma pools. If we don't get exact size, we will try bigger buffer - */ - - for (i = 0; i < MAX_DMA_POOLS; i++) { - - pool = &adp->dma_pool_list[i]; - - if (xferlen > pool->buf_size) - continue; - - if (right_pool == -1) - right_pool = i; - - spin_lock_irqsave(&pool->lock, flags); - - if (!pool->in_use) { - - pool->in_use = 1; - kioc->pool_index = i; - kioc->buf_vaddr = pool->vaddr; - kioc->buf_paddr = pool->paddr; - - spin_unlock_irqrestore(&pool->lock, flags); - return 0; - } - else { - spin_unlock_irqrestore(&pool->lock, flags); - continue; - } - } - - /* - * If xferlen doesn't match any of our pools, return error - */ - if (right_pool == -1) - return -EINVAL; - - /* - * We did not get any buffer from the preallocated pool. Let us try - * to allocate one new buffer. NOTE: This is a blocking call. - */ - pool = &adp->dma_pool_list[right_pool]; - - spin_lock_irqsave(&pool->lock, flags); - - kioc->pool_index = right_pool; - kioc->free_buf = 1; - kioc->buf_vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, - &kioc->buf_paddr); - spin_unlock_irqrestore(&pool->lock, flags); - - if (!kioc->buf_vaddr) - return -ENOMEM; - - return 0; -} - -/** - * mraid_mm_alloc_kioc - Returns a uioc_t from free list - * @adp : Adapter softstate for this module - * - * The kioc_semaphore is initialized with number of kioc nodes in the - * free kioc pool. If the kioc pool is empty, this function blocks till - * a kioc becomes free. - */ -static uioc_t * -mraid_mm_alloc_kioc(mraid_mmadp_t *adp) -{ - uioc_t *kioc; - struct list_head* head; - unsigned long flags; - - down(&adp->kioc_semaphore); - - spin_lock_irqsave(&adp->kioc_pool_lock, flags); - - head = &adp->kioc_pool; - - if (list_empty(head)) { - up(&adp->kioc_semaphore); - spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); - - con_log(CL_ANN, ("megaraid cmm: kioc list empty!\n")); - return NULL; - } - - kioc = list_entry(head->next, uioc_t, list); - list_del_init(&kioc->list); - - spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); - - memset((caddr_t)(unsigned long)kioc->cmdbuf, 0, sizeof(mbox64_t)); - memset((caddr_t) kioc->pthru32, 0, sizeof(mraid_passthru_t)); - - kioc->buf_vaddr = NULL; - kioc->buf_paddr = 0; - kioc->pool_index =-1; - kioc->free_buf = 0; - kioc->user_data = NULL; - kioc->user_data_len = 0; - kioc->user_pthru = NULL; - kioc->timedout = 0; - - return kioc; -} - -/** - * mraid_mm_dealloc_kioc - Return kioc to free pool - * @adp : Adapter softstate - * @kioc : uioc_t node to be returned to free pool - */ -static void -mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc) -{ - mm_dmapool_t *pool; - unsigned long flags; - - if (kioc->pool_index != -1) { - pool = &adp->dma_pool_list[kioc->pool_index]; - - /* This routine may be called in non-isr context also */ - spin_lock_irqsave(&pool->lock, flags); - - /* - * While attaching the dma buffer, if we didn't get the - * required buffer from the pool, we would have allocated - * it at the run time and set the free_buf flag. We must - * free that buffer. Otherwise, just mark that the buffer is - * not in use - */ - if (kioc->free_buf == 1) - pci_pool_free(pool->handle, kioc->buf_vaddr, - kioc->buf_paddr); - else - pool->in_use = 0; - - spin_unlock_irqrestore(&pool->lock, flags); - } - - /* Return the kioc to the free pool */ - spin_lock_irqsave(&adp->kioc_pool_lock, flags); - list_add(&kioc->list, &adp->kioc_pool); - spin_unlock_irqrestore(&adp->kioc_pool_lock, flags); - - /* increment the free kioc count */ - up(&adp->kioc_semaphore); - - return; -} - -/** - * lld_ioctl - Routine to issue ioctl to low level drvr - * @adp : The adapter handle - * @kioc : The ioctl packet with kernel addresses - */ -static int -lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc) -{ - int rval; - struct timer_list timer; - struct timer_list *tp = NULL; - - kioc->status = -ENODATA; - rval = adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE); - - if (rval) return rval; - - /* - * Start the timer - */ - if (adp->timeout > 0) { - tp = &timer; - init_timer(tp); - - tp->function = lld_timedout; - tp->data = (unsigned long)kioc; - tp->expires = jiffies + adp->timeout * HZ; - - add_timer(tp); - } - - /* - * Wait till the low level driver completes the ioctl. After this - * call, the ioctl either completed successfully or timedout. - */ - wait_event(wait_q, (kioc->status != -ENODATA)); - if (tp) { - del_timer_sync(tp); - } - - /* - * If the command had timedout, we mark the controller offline - * before returning - */ - if (kioc->timedout) { - adp->quiescent = 0; - } - - return kioc->status; -} - - -/** - * ioctl_done - callback from the low level driver - * @kioc : completed ioctl packet - */ -static void -ioctl_done(uioc_t *kioc) -{ - uint32_t adapno; - int iterator; - mraid_mmadp_t* adapter; - - /* - * When the kioc returns from driver, make sure it still doesn't - * have ENODATA in status. Otherwise, driver will hang on wait_event - * forever - */ - if (kioc->status == -ENODATA) { - con_log(CL_ANN, (KERN_WARNING - "megaraid cmm: lld didn't change status!\n")); - - kioc->status = -EINVAL; - } - - /* - * Check if this kioc was timedout before. If so, nobody is waiting - * on this kioc. We don't have to wake up anybody. Instead, we just - * have to free the kioc - */ - if (kioc->timedout) { - iterator = 0; - adapter = NULL; - adapno = kioc->adapno; - - con_log(CL_ANN, ( KERN_WARNING "megaraid cmm: completed " - "ioctl that was timedout before\n")); - - list_for_each_entry(adapter, &adapters_list_g, list) { - if (iterator++ == adapno) break; - } - - kioc->timedout = 0; - - if (adapter) { - mraid_mm_dealloc_kioc( adapter, kioc ); - } - } - else { - wake_up(&wait_q); - } -} - - -/** - * lld_timedout - callback from the expired timer - * @ptr : ioctl packet that timed out - */ -static void -lld_timedout(unsigned long ptr) -{ - uioc_t *kioc = (uioc_t *)ptr; - - kioc->status = -ETIME; - kioc->timedout = 1; - - con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n")); - - wake_up(&wait_q); -} - - -/** - * kioc_to_mimd - Converter from new back to old format - * @kioc : Kernel space IOCTL packet (successfully issued) - * @mimd : User space MIMD packet - */ -static int -kioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd) -{ - mimd_t kmimd; - uint8_t opcode; - uint8_t subopcode; - - mbox64_t *mbox64; - mraid_passthru_t __user *upthru32; - mraid_passthru_t *kpthru32; - mcontroller_t cinfo; - mraid_hba_info_t *hinfo; - - - if (copy_from_user(&kmimd, mimd, sizeof(mimd_t))) - return (-EFAULT); - - opcode = kmimd.ui.fcs.opcode; - subopcode = kmimd.ui.fcs.subopcode; - - if (opcode == 0x82) { - switch (subopcode) { - - case MEGAIOC_QADAPINFO: - - hinfo = (mraid_hba_info_t *)(unsigned long) - kioc->buf_vaddr; - - hinfo_to_cinfo(hinfo, &cinfo); - - if (copy_to_user(kmimd.data, &cinfo, sizeof(cinfo))) - return (-EFAULT); - - return 0; - - default: - return (-EINVAL); - } - - return 0; - } - - mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf; - - if (kioc->user_pthru) { - - upthru32 = kioc->user_pthru; - kpthru32 = kioc->pthru32; - - if (copy_to_user(&upthru32->scsistatus, - &kpthru32->scsistatus, - sizeof(uint8_t))) { - return (-EFAULT); - } - } - - if (kioc->user_data) { - if (copy_to_user(kioc->user_data, kioc->buf_vaddr, - kioc->user_data_len)) { - return (-EFAULT); - } - } - - if (copy_to_user(&mimd->mbox[17], - &mbox64->mbox32.status, sizeof(uint8_t))) { - return (-EFAULT); - } - - return 0; -} - - -/** - * hinfo_to_cinfo - Convert new format hba info into old format - * @hinfo : New format, more comprehensive adapter info - * @cinfo : Old format adapter info to support mimd_t apps - */ -static void -hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo) -{ - if (!hinfo || !cinfo) - return; - - cinfo->base = hinfo->baseport; - cinfo->irq = hinfo->irq; - cinfo->numldrv = hinfo->num_ldrv; - cinfo->pcibus = hinfo->pci_bus; - cinfo->pcidev = hinfo->pci_slot; - cinfo->pcifun = PCI_FUNC(hinfo->pci_dev_fn); - cinfo->pciid = hinfo->pci_device_id; - cinfo->pcivendor = hinfo->pci_vendor_id; - cinfo->pcislot = hinfo->pci_slot; - cinfo->uid = hinfo->unique_id; -} - - -/** - * mraid_mm_register_adp - Registration routine for low level drivers - * @lld_adp : Adapter objejct - */ -int -mraid_mm_register_adp(mraid_mmadp_t *lld_adp) -{ - mraid_mmadp_t *adapter; - mbox64_t *mbox_list; - uioc_t *kioc; - uint32_t rval; - int i; - - - if (lld_adp->drvr_type != DRVRTYPE_MBOX) - return (-EINVAL); - - adapter = kzalloc(sizeof(mraid_mmadp_t), GFP_KERNEL); - - if (!adapter) - return -ENOMEM; - - - adapter->unique_id = lld_adp->unique_id; - adapter->drvr_type = lld_adp->drvr_type; - adapter->drvr_data = lld_adp->drvr_data; - adapter->pdev = lld_adp->pdev; - adapter->issue_uioc = lld_adp->issue_uioc; - adapter->timeout = lld_adp->timeout; - adapter->max_kioc = lld_adp->max_kioc; - adapter->quiescent = 1; - - /* - * Allocate single blocks of memory for all required kiocs, - * mailboxes and passthru structures. - */ - adapter->kioc_list = kmalloc(sizeof(uioc_t) * lld_adp->max_kioc, - GFP_KERNEL); - adapter->mbox_list = kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc, - GFP_KERNEL); - adapter->pthru_dma_pool = pci_pool_create("megaraid mm pthru pool", - adapter->pdev, - sizeof(mraid_passthru_t), - 16, 0); - - if (!adapter->kioc_list || !adapter->mbox_list || - !adapter->pthru_dma_pool) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid cmm: out of memory, %s %d\n", __func__, - __LINE__)); - - rval = (-ENOMEM); - - goto memalloc_error; - } - - /* - * Slice kioc_list and make a kioc_pool with the individiual kiocs - */ - INIT_LIST_HEAD(&adapter->kioc_pool); - spin_lock_init(&adapter->kioc_pool_lock); - sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc); - - mbox_list = (mbox64_t *)adapter->mbox_list; - - for (i = 0; i < lld_adp->max_kioc; i++) { - - kioc = adapter->kioc_list + i; - kioc->cmdbuf = (uint64_t)(unsigned long)(mbox_list + i); - kioc->pthru32 = pci_pool_alloc(adapter->pthru_dma_pool, - GFP_KERNEL, &kioc->pthru32_h); - - if (!kioc->pthru32) { - - con_log(CL_ANN, (KERN_WARNING - "megaraid cmm: out of memory, %s %d\n", - __func__, __LINE__)); - - rval = (-ENOMEM); - - goto pthru_dma_pool_error; - } - - list_add_tail(&kioc->list, &adapter->kioc_pool); - } - - // Setup the dma pools for data buffers - if ((rval = mraid_mm_setup_dma_pools(adapter)) != 0) { - goto dma_pool_error; - } - - list_add_tail(&adapter->list, &adapters_list_g); - - adapters_count_g++; - - return 0; - -dma_pool_error: - /* Do nothing */ - -pthru_dma_pool_error: - - for (i = 0; i < lld_adp->max_kioc; i++) { - kioc = adapter->kioc_list + i; - if (kioc->pthru32) { - pci_pool_free(adapter->pthru_dma_pool, kioc->pthru32, - kioc->pthru32_h); - } - } - -memalloc_error: - - kfree(adapter->kioc_list); - kfree(adapter->mbox_list); - - if (adapter->pthru_dma_pool) - pci_pool_destroy(adapter->pthru_dma_pool); - - kfree(adapter); - - return rval; -} - - -/** - * mraid_mm_adapter_app_handle - return the application handle for this adapter - * @unique_id : adapter unique identifier - * - * For the given driver data, locate the adapter in our global list and - * return the corresponding handle, which is also used by applications to - * uniquely identify an adapter. - * - * Return adapter handle if found in the list. - * Return 0 if adapter could not be located, should never happen though. - */ -uint32_t -mraid_mm_adapter_app_handle(uint32_t unique_id) -{ - mraid_mmadp_t *adapter; - mraid_mmadp_t *tmp; - int index = 0; - - list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) { - - if (adapter->unique_id == unique_id) { - - return MKADAP(index); - } - - index++; - } - - return 0; -} - - -/** - * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter - * @adp : Adapter softstate - * - * We maintain a pool of dma buffers per each adapter. Each pool has one - * buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers. - * We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We - * dont' want to waste too much memory by allocating more buffers per each - * pool. - */ -static int -mraid_mm_setup_dma_pools(mraid_mmadp_t *adp) -{ - mm_dmapool_t *pool; - int bufsize; - int i; - - /* - * Create MAX_DMA_POOLS number of pools - */ - bufsize = MRAID_MM_INIT_BUFF_SIZE; - - for (i = 0; i < MAX_DMA_POOLS; i++){ - - pool = &adp->dma_pool_list[i]; - - pool->buf_size = bufsize; - spin_lock_init(&pool->lock); - - pool->handle = pci_pool_create("megaraid mm data buffer", - adp->pdev, bufsize, 16, 0); - - if (!pool->handle) { - goto dma_pool_setup_error; - } - - pool->vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL, - &pool->paddr); - - if (!pool->vaddr) - goto dma_pool_setup_error; - - bufsize = bufsize * 2; - } - - return 0; - -dma_pool_setup_error: - - mraid_mm_teardown_dma_pools(adp); - return (-ENOMEM); -} - - -/** - * mraid_mm_unregister_adp - Unregister routine for low level drivers - * @unique_id : UID of the adpater - * - * Assumes no outstanding ioctls to llds. - */ -int -mraid_mm_unregister_adp(uint32_t unique_id) -{ - mraid_mmadp_t *adapter; - mraid_mmadp_t *tmp; - - list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) { - - - if (adapter->unique_id == unique_id) { - - adapters_count_g--; - - list_del_init(&adapter->list); - - mraid_mm_free_adp_resources(adapter); - - kfree(adapter); - - con_log(CL_ANN, ( - "megaraid cmm: Unregistered one adapter:%#x\n", - unique_id)); - - return 0; - } - } - - return (-ENODEV); -} - -/** - * mraid_mm_free_adp_resources - Free adapter softstate - * @adp : Adapter softstate - */ -static void -mraid_mm_free_adp_resources(mraid_mmadp_t *adp) -{ - uioc_t *kioc; - int i; - - mraid_mm_teardown_dma_pools(adp); - - for (i = 0; i < adp->max_kioc; i++) { - - kioc = adp->kioc_list + i; - - pci_pool_free(adp->pthru_dma_pool, kioc->pthru32, - kioc->pthru32_h); - } - - kfree(adp->kioc_list); - kfree(adp->mbox_list); - - pci_pool_destroy(adp->pthru_dma_pool); - - - return; -} - - -/** - * mraid_mm_teardown_dma_pools - Free all per adapter dma buffers - * @adp : Adapter softstate - */ -static void -mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp) -{ - int i; - mm_dmapool_t *pool; - - for (i = 0; i < MAX_DMA_POOLS; i++) { - - pool = &adp->dma_pool_list[i]; - - if (pool->handle) { - - if (pool->vaddr) - pci_pool_free(pool->handle, pool->vaddr, - pool->paddr); - - pci_pool_destroy(pool->handle); - pool->handle = NULL; - } - } - - return; -} - -/** - * mraid_mm_init - Module entry point - */ -static int __init -mraid_mm_init(void) -{ - int err; - - // Announce the driver version - con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n", - LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION)); - - err = misc_register(&megaraid_mm_dev); - if (err < 0) { - con_log(CL_ANN, ("megaraid cmm: cannot register misc device\n")); - return err; - } - - init_waitqueue_head(&wait_q); - - INIT_LIST_HEAD(&adapters_list_g); - - return 0; -} - - -#ifdef CONFIG_COMPAT -/** - * mraid_mm_compat_ioctl - 32bit to 64bit ioctl conversion routine - * @filep : file operations pointer (ignored) - * @cmd : ioctl command - * @arg : user ioctl packet - */ -static long -mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd, - unsigned long arg) -{ - int err; - - err = mraid_mm_ioctl(filep, cmd, arg); - - return err; -} -#endif - -/** - * mraid_mm_exit - Module exit point - */ -static void __exit -mraid_mm_exit(void) -{ - con_log(CL_DLEVEL1 , ("exiting common mod\n")); - - misc_deregister(&megaraid_mm_dev); -} - -module_init(mraid_mm_init); -module_exit(mraid_mm_exit); - -/* vi: set ts=8 sw=8 tw=78: */ diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.h b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.h deleted file mode 100644 index 55b425c0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_mm.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Linux MegaRAID device driver - * - * Copyright (c) 2003-2004 LSI Logic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * FILE : megaraid_mm.h - */ - -#ifndef MEGARAID_MM_H -#define MEGARAID_MM_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mbox_defs.h" -#include "megaraid_ioctl.h" - - -#define LSI_COMMON_MOD_VERSION "2.20.2.7" -#define LSI_COMMON_MOD_EXT_VERSION \ - "(Release Date: Sun Jul 16 00:01:03 EST 2006)" - - -#define LSI_DBGLVL dbglevel - -// The smallest dma pool -#define MRAID_MM_INIT_BUFF_SIZE 4096 - -/** - * mimd_t : Old style ioctl packet structure (deprecated) - * - * @inlen : - * @outlen : - * @fca : - * @opcode : - * @subopcode : - * @adapno : - * @buffer : - * @pad : - * @length : - * @mbox : - * @pthru : - * @data : - * @pad : - * - * Note : This structure is DEPRECATED. New applications must use - * : uioc_t structure instead. All new hba drivers use the new - * : format. If we get this mimd packet, we will convert it into - * : new uioc_t format and send it to the hba drivers. - */ - -typedef struct mimd { - - uint32_t inlen; - uint32_t outlen; - - union { - uint8_t fca[16]; - struct { - uint8_t opcode; - uint8_t subopcode; - uint16_t adapno; -#if BITS_PER_LONG == 32 - uint8_t __user *buffer; - uint8_t pad[4]; -#endif -#if BITS_PER_LONG == 64 - uint8_t __user *buffer; -#endif - uint32_t length; - } __attribute__ ((packed)) fcs; - } __attribute__ ((packed)) ui; - - uint8_t mbox[18]; /* 16 bytes + 2 status bytes */ - mraid_passthru_t pthru; - -#if BITS_PER_LONG == 32 - char __user *data; /* buffer <= 4096 for 0x80 commands */ - char pad[4]; -#endif -#if BITS_PER_LONG == 64 - char __user *data; -#endif - -} __attribute__ ((packed))mimd_t; - -#endif // MEGARAID_MM_H - -// vi: set ts=8 sw=8 tw=78: diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas.h b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas.h deleted file mode 100644 index e5f416f8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas.h +++ /dev/null @@ -1,1492 +0,0 @@ -/* - * Linux MegaRAID driver for SAS based RAID controllers - * - * Copyright (c) 2009-2011 LSI Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * FILE: megaraid_sas.h - * - * Authors: LSI Corporation - * - * Send feedback to: - * - * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 - * ATTN: Linuxraid - */ - -#ifndef LSI_MEGARAID_SAS_H -#define LSI_MEGARAID_SAS_H - -/* - * MegaRAID SAS Driver meta data - */ -#define MEGASAS_VERSION "00.00.06.14-rc1" -#define MEGASAS_RELDATE "Jan. 6, 2012" -#define MEGASAS_EXT_VERSION "Fri. Jan. 6 17:00:00 PDT 2012" - -/* - * Device IDs - */ -#define PCI_DEVICE_ID_LSI_SAS1078R 0x0060 -#define PCI_DEVICE_ID_LSI_SAS1078DE 0x007C -#define PCI_DEVICE_ID_LSI_VERDE_ZCR 0x0413 -#define PCI_DEVICE_ID_LSI_SAS1078GEN2 0x0078 -#define PCI_DEVICE_ID_LSI_SAS0079GEN2 0x0079 -#define PCI_DEVICE_ID_LSI_SAS0073SKINNY 0x0073 -#define PCI_DEVICE_ID_LSI_SAS0071SKINNY 0x0071 -#define PCI_DEVICE_ID_LSI_FUSION 0x005b -#define PCI_DEVICE_ID_LSI_INVADER 0x005d - -/* - * ===================================== - * MegaRAID SAS MFI firmware definitions - * ===================================== - */ - -/* - * MFI stands for MegaRAID SAS FW Interface. This is just a moniker for - * protocol between the software and firmware. Commands are issued using - * "message frames" - */ - -/* - * FW posts its state in upper 4 bits of outbound_msg_0 register - */ -#define MFI_STATE_MASK 0xF0000000 -#define MFI_STATE_UNDEFINED 0x00000000 -#define MFI_STATE_BB_INIT 0x10000000 -#define MFI_STATE_FW_INIT 0x40000000 -#define MFI_STATE_WAIT_HANDSHAKE 0x60000000 -#define MFI_STATE_FW_INIT_2 0x70000000 -#define MFI_STATE_DEVICE_SCAN 0x80000000 -#define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000 -#define MFI_STATE_FLUSH_CACHE 0xA0000000 -#define MFI_STATE_READY 0xB0000000 -#define MFI_STATE_OPERATIONAL 0xC0000000 -#define MFI_STATE_FAULT 0xF0000000 -#define MFI_RESET_REQUIRED 0x00000001 -#define MFI_RESET_ADAPTER 0x00000002 -#define MEGAMFI_FRAME_SIZE 64 - -/* - * During FW init, clear pending cmds & reset state using inbound_msg_0 - * - * ABORT : Abort all pending cmds - * READY : Move from OPERATIONAL to READY state; discard queue info - * MFIMODE : Discard (possible) low MFA posted in 64-bit mode (??) - * CLR_HANDSHAKE: FW is waiting for HANDSHAKE from BIOS or Driver - * HOTPLUG : Resume from Hotplug - * MFI_STOP_ADP : Send signal to FW to stop processing - */ -#define WRITE_SEQUENCE_OFFSET (0x0000000FC) /* I20 */ -#define HOST_DIAGNOSTIC_OFFSET (0x000000F8) /* I20 */ -#define DIAG_WRITE_ENABLE (0x00000080) -#define DIAG_RESET_ADAPTER (0x00000004) - -#define MFI_ADP_RESET 0x00000040 -#define MFI_INIT_ABORT 0x00000001 -#define MFI_INIT_READY 0x00000002 -#define MFI_INIT_MFIMODE 0x00000004 -#define MFI_INIT_CLEAR_HANDSHAKE 0x00000008 -#define MFI_INIT_HOTPLUG 0x00000010 -#define MFI_STOP_ADP 0x00000020 -#define MFI_RESET_FLAGS MFI_INIT_READY| \ - MFI_INIT_MFIMODE| \ - MFI_INIT_ABORT - -/* - * MFI frame flags - */ -#define MFI_FRAME_POST_IN_REPLY_QUEUE 0x0000 -#define MFI_FRAME_DONT_POST_IN_REPLY_QUEUE 0x0001 -#define MFI_FRAME_SGL32 0x0000 -#define MFI_FRAME_SGL64 0x0002 -#define MFI_FRAME_SENSE32 0x0000 -#define MFI_FRAME_SENSE64 0x0004 -#define MFI_FRAME_DIR_NONE 0x0000 -#define MFI_FRAME_DIR_WRITE 0x0008 -#define MFI_FRAME_DIR_READ 0x0010 -#define MFI_FRAME_DIR_BOTH 0x0018 -#define MFI_FRAME_IEEE 0x0020 - -/* - * Definition for cmd_status - */ -#define MFI_CMD_STATUS_POLL_MODE 0xFF - -/* - * MFI command opcodes - */ -#define MFI_CMD_INIT 0x00 -#define MFI_CMD_LD_READ 0x01 -#define MFI_CMD_LD_WRITE 0x02 -#define MFI_CMD_LD_SCSI_IO 0x03 -#define MFI_CMD_PD_SCSI_IO 0x04 -#define MFI_CMD_DCMD 0x05 -#define MFI_CMD_ABORT 0x06 -#define MFI_CMD_SMP 0x07 -#define MFI_CMD_STP 0x08 -#define MFI_CMD_INVALID 0xff - -#define MR_DCMD_CTRL_GET_INFO 0x01010000 -#define MR_DCMD_LD_GET_LIST 0x03010000 - -#define MR_DCMD_CTRL_CACHE_FLUSH 0x01101000 -#define MR_FLUSH_CTRL_CACHE 0x01 -#define MR_FLUSH_DISK_CACHE 0x02 - -#define MR_DCMD_CTRL_SHUTDOWN 0x01050000 -#define MR_DCMD_HIBERNATE_SHUTDOWN 0x01060000 -#define MR_ENABLE_DRIVE_SPINDOWN 0x01 - -#define MR_DCMD_CTRL_EVENT_GET_INFO 0x01040100 -#define MR_DCMD_CTRL_EVENT_GET 0x01040300 -#define MR_DCMD_CTRL_EVENT_WAIT 0x01040500 -#define MR_DCMD_LD_GET_PROPERTIES 0x03030000 - -#define MR_DCMD_CLUSTER 0x08000000 -#define MR_DCMD_CLUSTER_RESET_ALL 0x08010100 -#define MR_DCMD_CLUSTER_RESET_LD 0x08010200 -#define MR_DCMD_PD_LIST_QUERY 0x02010100 - -/* - * MFI command completion codes - */ -enum MFI_STAT { - MFI_STAT_OK = 0x00, - MFI_STAT_INVALID_CMD = 0x01, - MFI_STAT_INVALID_DCMD = 0x02, - MFI_STAT_INVALID_PARAMETER = 0x03, - MFI_STAT_INVALID_SEQUENCE_NUMBER = 0x04, - MFI_STAT_ABORT_NOT_POSSIBLE = 0x05, - MFI_STAT_APP_HOST_CODE_NOT_FOUND = 0x06, - MFI_STAT_APP_IN_USE = 0x07, - MFI_STAT_APP_NOT_INITIALIZED = 0x08, - MFI_STAT_ARRAY_INDEX_INVALID = 0x09, - MFI_STAT_ARRAY_ROW_NOT_EMPTY = 0x0a, - MFI_STAT_CONFIG_RESOURCE_CONFLICT = 0x0b, - MFI_STAT_DEVICE_NOT_FOUND = 0x0c, - MFI_STAT_DRIVE_TOO_SMALL = 0x0d, - MFI_STAT_FLASH_ALLOC_FAIL = 0x0e, - MFI_STAT_FLASH_BUSY = 0x0f, - MFI_STAT_FLASH_ERROR = 0x10, - MFI_STAT_FLASH_IMAGE_BAD = 0x11, - MFI_STAT_FLASH_IMAGE_INCOMPLETE = 0x12, - MFI_STAT_FLASH_NOT_OPEN = 0x13, - MFI_STAT_FLASH_NOT_STARTED = 0x14, - MFI_STAT_FLUSH_FAILED = 0x15, - MFI_STAT_HOST_CODE_NOT_FOUNT = 0x16, - MFI_STAT_LD_CC_IN_PROGRESS = 0x17, - MFI_STAT_LD_INIT_IN_PROGRESS = 0x18, - MFI_STAT_LD_LBA_OUT_OF_RANGE = 0x19, - MFI_STAT_LD_MAX_CONFIGURED = 0x1a, - MFI_STAT_LD_NOT_OPTIMAL = 0x1b, - MFI_STAT_LD_RBLD_IN_PROGRESS = 0x1c, - MFI_STAT_LD_RECON_IN_PROGRESS = 0x1d, - MFI_STAT_LD_WRONG_RAID_LEVEL = 0x1e, - MFI_STAT_MAX_SPARES_EXCEEDED = 0x1f, - MFI_STAT_MEMORY_NOT_AVAILABLE = 0x20, - MFI_STAT_MFC_HW_ERROR = 0x21, - MFI_STAT_NO_HW_PRESENT = 0x22, - MFI_STAT_NOT_FOUND = 0x23, - MFI_STAT_NOT_IN_ENCL = 0x24, - MFI_STAT_PD_CLEAR_IN_PROGRESS = 0x25, - MFI_STAT_PD_TYPE_WRONG = 0x26, - MFI_STAT_PR_DISABLED = 0x27, - MFI_STAT_ROW_INDEX_INVALID = 0x28, - MFI_STAT_SAS_CONFIG_INVALID_ACTION = 0x29, - MFI_STAT_SAS_CONFIG_INVALID_DATA = 0x2a, - MFI_STAT_SAS_CONFIG_INVALID_PAGE = 0x2b, - MFI_STAT_SAS_CONFIG_INVALID_TYPE = 0x2c, - MFI_STAT_SCSI_DONE_WITH_ERROR = 0x2d, - MFI_STAT_SCSI_IO_FAILED = 0x2e, - MFI_STAT_SCSI_RESERVATION_CONFLICT = 0x2f, - MFI_STAT_SHUTDOWN_FAILED = 0x30, - MFI_STAT_TIME_NOT_SET = 0x31, - MFI_STAT_WRONG_STATE = 0x32, - MFI_STAT_LD_OFFLINE = 0x33, - MFI_STAT_PEER_NOTIFICATION_REJECTED = 0x34, - MFI_STAT_PEER_NOTIFICATION_FAILED = 0x35, - MFI_STAT_RESERVATION_IN_PROGRESS = 0x36, - MFI_STAT_I2C_ERRORS_DETECTED = 0x37, - MFI_STAT_PCI_ERRORS_DETECTED = 0x38, - MFI_STAT_CONFIG_SEQ_MISMATCH = 0x67, - - MFI_STAT_INVALID_STATUS = 0xFF -}; - -/* - * Number of mailbox bytes in DCMD message frame - */ -#define MFI_MBOX_SIZE 12 - -enum MR_EVT_CLASS { - - MR_EVT_CLASS_DEBUG = -2, - MR_EVT_CLASS_PROGRESS = -1, - MR_EVT_CLASS_INFO = 0, - MR_EVT_CLASS_WARNING = 1, - MR_EVT_CLASS_CRITICAL = 2, - MR_EVT_CLASS_FATAL = 3, - MR_EVT_CLASS_DEAD = 4, - -}; - -enum MR_EVT_LOCALE { - - MR_EVT_LOCALE_LD = 0x0001, - MR_EVT_LOCALE_PD = 0x0002, - MR_EVT_LOCALE_ENCL = 0x0004, - MR_EVT_LOCALE_BBU = 0x0008, - MR_EVT_LOCALE_SAS = 0x0010, - MR_EVT_LOCALE_CTRL = 0x0020, - MR_EVT_LOCALE_CONFIG = 0x0040, - MR_EVT_LOCALE_CLUSTER = 0x0080, - MR_EVT_LOCALE_ALL = 0xffff, - -}; - -enum MR_EVT_ARGS { - - MR_EVT_ARGS_NONE, - MR_EVT_ARGS_CDB_SENSE, - MR_EVT_ARGS_LD, - MR_EVT_ARGS_LD_COUNT, - MR_EVT_ARGS_LD_LBA, - MR_EVT_ARGS_LD_OWNER, - MR_EVT_ARGS_LD_LBA_PD_LBA, - MR_EVT_ARGS_LD_PROG, - MR_EVT_ARGS_LD_STATE, - MR_EVT_ARGS_LD_STRIP, - MR_EVT_ARGS_PD, - MR_EVT_ARGS_PD_ERR, - MR_EVT_ARGS_PD_LBA, - MR_EVT_ARGS_PD_LBA_LD, - MR_EVT_ARGS_PD_PROG, - MR_EVT_ARGS_PD_STATE, - MR_EVT_ARGS_PCI, - MR_EVT_ARGS_RATE, - MR_EVT_ARGS_STR, - MR_EVT_ARGS_TIME, - MR_EVT_ARGS_ECC, - MR_EVT_ARGS_LD_PROP, - MR_EVT_ARGS_PD_SPARE, - MR_EVT_ARGS_PD_INDEX, - MR_EVT_ARGS_DIAG_PASS, - MR_EVT_ARGS_DIAG_FAIL, - MR_EVT_ARGS_PD_LBA_LBA, - MR_EVT_ARGS_PORT_PHY, - MR_EVT_ARGS_PD_MISSING, - MR_EVT_ARGS_PD_ADDRESS, - MR_EVT_ARGS_BITMAP, - MR_EVT_ARGS_CONNECTOR, - MR_EVT_ARGS_PD_PD, - MR_EVT_ARGS_PD_FRU, - MR_EVT_ARGS_PD_PATHINFO, - MR_EVT_ARGS_PD_POWER_STATE, - MR_EVT_ARGS_GENERIC, -}; - -/* - * define constants for device list query options - */ -enum MR_PD_QUERY_TYPE { - MR_PD_QUERY_TYPE_ALL = 0, - MR_PD_QUERY_TYPE_STATE = 1, - MR_PD_QUERY_TYPE_POWER_STATE = 2, - MR_PD_QUERY_TYPE_MEDIA_TYPE = 3, - MR_PD_QUERY_TYPE_SPEED = 4, - MR_PD_QUERY_TYPE_EXPOSED_TO_HOST = 5, -}; - -#define MR_EVT_CFG_CLEARED 0x0004 -#define MR_EVT_LD_STATE_CHANGE 0x0051 -#define MR_EVT_PD_INSERTED 0x005b -#define MR_EVT_PD_REMOVED 0x0070 -#define MR_EVT_LD_CREATED 0x008a -#define MR_EVT_LD_DELETED 0x008b -#define MR_EVT_FOREIGN_CFG_IMPORTED 0x00db -#define MR_EVT_LD_OFFLINE 0x00fc -#define MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED 0x0152 -#define MAX_LOGICAL_DRIVES 64 - -enum MR_PD_STATE { - MR_PD_STATE_UNCONFIGURED_GOOD = 0x00, - MR_PD_STATE_UNCONFIGURED_BAD = 0x01, - MR_PD_STATE_HOT_SPARE = 0x02, - MR_PD_STATE_OFFLINE = 0x10, - MR_PD_STATE_FAILED = 0x11, - MR_PD_STATE_REBUILD = 0x14, - MR_PD_STATE_ONLINE = 0x18, - MR_PD_STATE_COPYBACK = 0x20, - MR_PD_STATE_SYSTEM = 0x40, - }; - - - /* - * defines the physical drive address structure - */ -struct MR_PD_ADDRESS { - u16 deviceId; - u16 enclDeviceId; - - union { - struct { - u8 enclIndex; - u8 slotNumber; - } mrPdAddress; - struct { - u8 enclPosition; - u8 enclConnectorIndex; - } mrEnclAddress; - }; - u8 scsiDevType; - union { - u8 connectedPortBitmap; - u8 connectedPortNumbers; - }; - u64 sasAddr[2]; -} __packed; - -/* - * defines the physical drive list structure - */ -struct MR_PD_LIST { - u32 size; - u32 count; - struct MR_PD_ADDRESS addr[1]; -} __packed; - -struct megasas_pd_list { - u16 tid; - u8 driveType; - u8 driveState; -} __packed; - - /* - * defines the logical drive reference structure - */ -union MR_LD_REF { - struct { - u8 targetId; - u8 reserved; - u16 seqNum; - }; - u32 ref; -} __packed; - -/* - * defines the logical drive list structure - */ -struct MR_LD_LIST { - u32 ldCount; - u32 reserved; - struct { - union MR_LD_REF ref; - u8 state; - u8 reserved[3]; - u64 size; - } ldList[MAX_LOGICAL_DRIVES]; -} __packed; - -/* - * SAS controller properties - */ -struct megasas_ctrl_prop { - - u16 seq_num; - u16 pred_fail_poll_interval; - u16 intr_throttle_count; - u16 intr_throttle_timeouts; - u8 rebuild_rate; - u8 patrol_read_rate; - u8 bgi_rate; - u8 cc_rate; - u8 recon_rate; - u8 cache_flush_interval; - u8 spinup_drv_count; - u8 spinup_delay; - u8 cluster_enable; - u8 coercion_mode; - u8 alarm_enable; - u8 disable_auto_rebuild; - u8 disable_battery_warn; - u8 ecc_bucket_size; - u16 ecc_bucket_leak_rate; - u8 restore_hotspare_on_insertion; - u8 expose_encl_devices; - u8 maintainPdFailHistory; - u8 disallowHostRequestReordering; - u8 abortCCOnError; - u8 loadBalanceMode; - u8 disableAutoDetectBackplane; - - u8 snapVDSpace; - - /* - * Add properties that can be controlled by - * a bit in the following structure. - */ - struct { - u32 copyBackDisabled : 1; - u32 SMARTerEnabled : 1; - u32 prCorrectUnconfiguredAreas : 1; - u32 useFdeOnly : 1; - u32 disableNCQ : 1; - u32 SSDSMARTerEnabled : 1; - u32 SSDPatrolReadEnabled : 1; - u32 enableSpinDownUnconfigured : 1; - u32 autoEnhancedImport : 1; - u32 enableSecretKeyControl : 1; - u32 disableOnlineCtrlReset : 1; - u32 allowBootWithPinnedCache : 1; - u32 disableSpinDownHS : 1; - u32 enableJBOD : 1; - u32 reserved :18; - } OnOffProperties; - u8 autoSnapVDSpace; - u8 viewSpace; - u16 spinDownTime; - u8 reserved[24]; -} __packed; - -/* - * SAS controller information - */ -struct megasas_ctrl_info { - - /* - * PCI device information - */ - struct { - - u16 vendor_id; - u16 device_id; - u16 sub_vendor_id; - u16 sub_device_id; - u8 reserved[24]; - - } __attribute__ ((packed)) pci; - - /* - * Host interface information - */ - struct { - - u8 PCIX:1; - u8 PCIE:1; - u8 iSCSI:1; - u8 SAS_3G:1; - u8 reserved_0:4; - u8 reserved_1[6]; - u8 port_count; - u64 port_addr[8]; - - } __attribute__ ((packed)) host_interface; - - /* - * Device (backend) interface information - */ - struct { - - u8 SPI:1; - u8 SAS_3G:1; - u8 SATA_1_5G:1; - u8 SATA_3G:1; - u8 reserved_0:4; - u8 reserved_1[6]; - u8 port_count; - u64 port_addr[8]; - - } __attribute__ ((packed)) device_interface; - - /* - * List of components residing in flash. All str are null terminated - */ - u32 image_check_word; - u32 image_component_count; - - struct { - - char name[8]; - char version[32]; - char build_date[16]; - char built_time[16]; - - } __attribute__ ((packed)) image_component[8]; - - /* - * List of flash components that have been flashed on the card, but - * are not in use, pending reset of the adapter. This list will be - * empty if a flash operation has not occurred. All stings are null - * terminated - */ - u32 pending_image_component_count; - - struct { - - char name[8]; - char version[32]; - char build_date[16]; - char build_time[16]; - - } __attribute__ ((packed)) pending_image_component[8]; - - u8 max_arms; - u8 max_spans; - u8 max_arrays; - u8 max_lds; - - char product_name[80]; - char serial_no[32]; - - /* - * Other physical/controller/operation information. Indicates the - * presence of the hardware - */ - struct { - - u32 bbu:1; - u32 alarm:1; - u32 nvram:1; - u32 uart:1; - u32 reserved:28; - - } __attribute__ ((packed)) hw_present; - - u32 current_fw_time; - - /* - * Maximum data transfer sizes - */ - u16 max_concurrent_cmds; - u16 max_sge_count; - u32 max_request_size; - - /* - * Logical and physical device counts - */ - u16 ld_present_count; - u16 ld_degraded_count; - u16 ld_offline_count; - - u16 pd_present_count; - u16 pd_disk_present_count; - u16 pd_disk_pred_failure_count; - u16 pd_disk_failed_count; - - /* - * Memory size information - */ - u16 nvram_size; - u16 memory_size; - u16 flash_size; - - /* - * Error counters - */ - u16 mem_correctable_error_count; - u16 mem_uncorrectable_error_count; - - /* - * Cluster information - */ - u8 cluster_permitted; - u8 cluster_active; - - /* - * Additional max data transfer sizes - */ - u16 max_strips_per_io; - - /* - * Controller capabilities structures - */ - struct { - - u32 raid_level_0:1; - u32 raid_level_1:1; - u32 raid_level_5:1; - u32 raid_level_1E:1; - u32 raid_level_6:1; - u32 reserved:27; - - } __attribute__ ((packed)) raid_levels; - - struct { - - u32 rbld_rate:1; - u32 cc_rate:1; - u32 bgi_rate:1; - u32 recon_rate:1; - u32 patrol_rate:1; - u32 alarm_control:1; - u32 cluster_supported:1; - u32 bbu:1; - u32 spanning_allowed:1; - u32 dedicated_hotspares:1; - u32 revertible_hotspares:1; - u32 foreign_config_import:1; - u32 self_diagnostic:1; - u32 mixed_redundancy_arr:1; - u32 global_hot_spares:1; - u32 reserved:17; - - } __attribute__ ((packed)) adapter_operations; - - struct { - - u32 read_policy:1; - u32 write_policy:1; - u32 io_policy:1; - u32 access_policy:1; - u32 disk_cache_policy:1; - u32 reserved:27; - - } __attribute__ ((packed)) ld_operations; - - struct { - - u8 min; - u8 max; - u8 reserved[2]; - - } __attribute__ ((packed)) stripe_sz_ops; - - struct { - - u32 force_online:1; - u32 force_offline:1; - u32 force_rebuild:1; - u32 reserved:29; - - } __attribute__ ((packed)) pd_operations; - - struct { - - u32 ctrl_supports_sas:1; - u32 ctrl_supports_sata:1; - u32 allow_mix_in_encl:1; - u32 allow_mix_in_ld:1; - u32 allow_sata_in_cluster:1; - u32 reserved:27; - - } __attribute__ ((packed)) pd_mix_support; - - /* - * Define ECC single-bit-error bucket information - */ - u8 ecc_bucket_count; - u8 reserved_2[11]; - - /* - * Include the controller properties (changeable items) - */ - struct megasas_ctrl_prop properties; - - /* - * Define FW pkg version (set in envt v'bles on OEM basis) - */ - char package_version[0x60]; - - u8 pad[0x800 - 0x6a0]; - -} __packed; - -/* - * =============================== - * MegaRAID SAS driver definitions - * =============================== - */ -#define MEGASAS_MAX_PD_CHANNELS 2 -#define MEGASAS_MAX_LD_CHANNELS 2 -#define MEGASAS_MAX_CHANNELS (MEGASAS_MAX_PD_CHANNELS + \ - MEGASAS_MAX_LD_CHANNELS) -#define MEGASAS_MAX_DEV_PER_CHANNEL 128 -#define MEGASAS_DEFAULT_INIT_ID -1 -#define MEGASAS_MAX_LUN 8 -#define MEGASAS_MAX_LD 64 -#define MEGASAS_DEFAULT_CMD_PER_LUN 256 -#define MEGASAS_MAX_PD (MEGASAS_MAX_PD_CHANNELS * \ - MEGASAS_MAX_DEV_PER_CHANNEL) -#define MEGASAS_MAX_LD_IDS (MEGASAS_MAX_LD_CHANNELS * \ - MEGASAS_MAX_DEV_PER_CHANNEL) - -#define MEGASAS_MAX_SECTORS (2*1024) -#define MEGASAS_MAX_SECTORS_IEEE (2*128) -#define MEGASAS_DBG_LVL 1 - -#define MEGASAS_FW_BUSY 1 - -/* Frame Type */ -#define IO_FRAME 0 -#define PTHRU_FRAME 1 - -/* - * When SCSI mid-layer calls driver's reset routine, driver waits for - * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note - * that the driver cannot _actually_ abort or reset pending commands. While - * it is waiting for the commands to complete, it prints a diagnostic message - * every MEGASAS_RESET_NOTICE_INTERVAL seconds - */ -#define MEGASAS_RESET_WAIT_TIME 180 -#define MEGASAS_INTERNAL_CMD_WAIT_TIME 180 -#define MEGASAS_RESET_NOTICE_INTERVAL 5 -#define MEGASAS_IOCTL_CMD 0 -#define MEGASAS_DEFAULT_CMD_TIMEOUT 90 - -/* - * FW reports the maximum of number of commands that it can accept (maximum - * commands that can be outstanding) at any time. The driver must report a - * lower number to the mid layer because it can issue a few internal commands - * itself (E.g, AEN, abort cmd, IOCTLs etc). The number of commands it needs - * is shown below - */ -#define MEGASAS_INT_CMDS 32 -#define MEGASAS_SKINNY_INT_CMDS 5 - -#define MEGASAS_MAX_MSIX_QUEUES 16 -/* - * FW can accept both 32 and 64 bit SGLs. We want to allocate 32/64 bit - * SGLs based on the size of dma_addr_t - */ -#define IS_DMA64 (sizeof(dma_addr_t) == 8) - -#define MFI_XSCALE_OMR0_CHANGE_INTERRUPT 0x00000001 - -#define MFI_INTR_FLAG_REPLY_MESSAGE 0x00000001 -#define MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE 0x00000002 -#define MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT 0x00000004 - -#define MFI_OB_INTR_STATUS_MASK 0x00000002 -#define MFI_POLL_TIMEOUT_SECS 60 - -#define MFI_REPLY_1078_MESSAGE_INTERRUPT 0x80000000 -#define MFI_REPLY_GEN2_MESSAGE_INTERRUPT 0x00000001 -#define MFI_GEN2_ENABLE_INTERRUPT_MASK (0x00000001 | 0x00000004) -#define MFI_REPLY_SKINNY_MESSAGE_INTERRUPT 0x40000000 -#define MFI_SKINNY_ENABLE_INTERRUPT_MASK (0x00000001) - -#define MFI_1068_PCSR_OFFSET 0x84 -#define MFI_1068_FW_HANDSHAKE_OFFSET 0x64 -#define MFI_1068_FW_READY 0xDDDD0000 -/* -* register set for both 1068 and 1078 controllers -* structure extended for 1078 registers -*/ - -struct megasas_register_set { - u32 doorbell; /*0000h*/ - u32 fusion_seq_offset; /*0004h*/ - u32 fusion_host_diag; /*0008h*/ - u32 reserved_01; /*000Ch*/ - - u32 inbound_msg_0; /*0010h*/ - u32 inbound_msg_1; /*0014h*/ - u32 outbound_msg_0; /*0018h*/ - u32 outbound_msg_1; /*001Ch*/ - - u32 inbound_doorbell; /*0020h*/ - u32 inbound_intr_status; /*0024h*/ - u32 inbound_intr_mask; /*0028h*/ - - u32 outbound_doorbell; /*002Ch*/ - u32 outbound_intr_status; /*0030h*/ - u32 outbound_intr_mask; /*0034h*/ - - u32 reserved_1[2]; /*0038h*/ - - u32 inbound_queue_port; /*0040h*/ - u32 outbound_queue_port; /*0044h*/ - - u32 reserved_2[9]; /*0048h*/ - u32 reply_post_host_index; /*006Ch*/ - u32 reserved_2_2[12]; /*0070h*/ - - u32 outbound_doorbell_clear; /*00A0h*/ - - u32 reserved_3[3]; /*00A4h*/ - - u32 outbound_scratch_pad ; /*00B0h*/ - u32 outbound_scratch_pad_2; /*00B4h*/ - - u32 reserved_4[2]; /*00B8h*/ - - u32 inbound_low_queue_port ; /*00C0h*/ - - u32 inbound_high_queue_port ; /*00C4h*/ - - u32 reserved_5; /*00C8h*/ - u32 res_6[11]; /*CCh*/ - u32 host_diag; - u32 seq_offset; - u32 index_registers[807]; /*00CCh*/ -} __attribute__ ((packed)); - -struct megasas_sge32 { - - u32 phys_addr; - u32 length; - -} __attribute__ ((packed)); - -struct megasas_sge64 { - - u64 phys_addr; - u32 length; - -} __attribute__ ((packed)); - -struct megasas_sge_skinny { - u64 phys_addr; - u32 length; - u32 flag; -} __packed; - -union megasas_sgl { - - struct megasas_sge32 sge32[1]; - struct megasas_sge64 sge64[1]; - struct megasas_sge_skinny sge_skinny[1]; - -} __attribute__ ((packed)); - -struct megasas_header { - - u8 cmd; /*00h */ - u8 sense_len; /*01h */ - u8 cmd_status; /*02h */ - u8 scsi_status; /*03h */ - - u8 target_id; /*04h */ - u8 lun; /*05h */ - u8 cdb_len; /*06h */ - u8 sge_count; /*07h */ - - u32 context; /*08h */ - u32 pad_0; /*0Ch */ - - u16 flags; /*10h */ - u16 timeout; /*12h */ - u32 data_xferlen; /*14h */ - -} __attribute__ ((packed)); - -union megasas_sgl_frame { - - struct megasas_sge32 sge32[8]; - struct megasas_sge64 sge64[5]; - -} __attribute__ ((packed)); - -struct megasas_init_frame { - - u8 cmd; /*00h */ - u8 reserved_0; /*01h */ - u8 cmd_status; /*02h */ - - u8 reserved_1; /*03h */ - u32 reserved_2; /*04h */ - - u32 context; /*08h */ - u32 pad_0; /*0Ch */ - - u16 flags; /*10h */ - u16 reserved_3; /*12h */ - u32 data_xfer_len; /*14h */ - - u32 queue_info_new_phys_addr_lo; /*18h */ - u32 queue_info_new_phys_addr_hi; /*1Ch */ - u32 queue_info_old_phys_addr_lo; /*20h */ - u32 queue_info_old_phys_addr_hi; /*24h */ - - u32 reserved_4[6]; /*28h */ - -} __attribute__ ((packed)); - -struct megasas_init_queue_info { - - u32 init_flags; /*00h */ - u32 reply_queue_entries; /*04h */ - - u32 reply_queue_start_phys_addr_lo; /*08h */ - u32 reply_queue_start_phys_addr_hi; /*0Ch */ - u32 producer_index_phys_addr_lo; /*10h */ - u32 producer_index_phys_addr_hi; /*14h */ - u32 consumer_index_phys_addr_lo; /*18h */ - u32 consumer_index_phys_addr_hi; /*1Ch */ - -} __attribute__ ((packed)); - -struct megasas_io_frame { - - u8 cmd; /*00h */ - u8 sense_len; /*01h */ - u8 cmd_status; /*02h */ - u8 scsi_status; /*03h */ - - u8 target_id; /*04h */ - u8 access_byte; /*05h */ - u8 reserved_0; /*06h */ - u8 sge_count; /*07h */ - - u32 context; /*08h */ - u32 pad_0; /*0Ch */ - - u16 flags; /*10h */ - u16 timeout; /*12h */ - u32 lba_count; /*14h */ - - u32 sense_buf_phys_addr_lo; /*18h */ - u32 sense_buf_phys_addr_hi; /*1Ch */ - - u32 start_lba_lo; /*20h */ - u32 start_lba_hi; /*24h */ - - union megasas_sgl sgl; /*28h */ - -} __attribute__ ((packed)); - -struct megasas_pthru_frame { - - u8 cmd; /*00h */ - u8 sense_len; /*01h */ - u8 cmd_status; /*02h */ - u8 scsi_status; /*03h */ - - u8 target_id; /*04h */ - u8 lun; /*05h */ - u8 cdb_len; /*06h */ - u8 sge_count; /*07h */ - - u32 context; /*08h */ - u32 pad_0; /*0Ch */ - - u16 flags; /*10h */ - u16 timeout; /*12h */ - u32 data_xfer_len; /*14h */ - - u32 sense_buf_phys_addr_lo; /*18h */ - u32 sense_buf_phys_addr_hi; /*1Ch */ - - u8 cdb[16]; /*20h */ - union megasas_sgl sgl; /*30h */ - -} __attribute__ ((packed)); - -struct megasas_dcmd_frame { - - u8 cmd; /*00h */ - u8 reserved_0; /*01h */ - u8 cmd_status; /*02h */ - u8 reserved_1[4]; /*03h */ - u8 sge_count; /*07h */ - - u32 context; /*08h */ - u32 pad_0; /*0Ch */ - - u16 flags; /*10h */ - u16 timeout; /*12h */ - - u32 data_xfer_len; /*14h */ - u32 opcode; /*18h */ - - union { /*1Ch */ - u8 b[12]; - u16 s[6]; - u32 w[3]; - } mbox; - - union megasas_sgl sgl; /*28h */ - -} __attribute__ ((packed)); - -struct megasas_abort_frame { - - u8 cmd; /*00h */ - u8 reserved_0; /*01h */ - u8 cmd_status; /*02h */ - - u8 reserved_1; /*03h */ - u32 reserved_2; /*04h */ - - u32 context; /*08h */ - u32 pad_0; /*0Ch */ - - u16 flags; /*10h */ - u16 reserved_3; /*12h */ - u32 reserved_4; /*14h */ - - u32 abort_context; /*18h */ - u32 pad_1; /*1Ch */ - - u32 abort_mfi_phys_addr_lo; /*20h */ - u32 abort_mfi_phys_addr_hi; /*24h */ - - u32 reserved_5[6]; /*28h */ - -} __attribute__ ((packed)); - -struct megasas_smp_frame { - - u8 cmd; /*00h */ - u8 reserved_1; /*01h */ - u8 cmd_status; /*02h */ - u8 connection_status; /*03h */ - - u8 reserved_2[3]; /*04h */ - u8 sge_count; /*07h */ - - u32 context; /*08h */ - u32 pad_0; /*0Ch */ - - u16 flags; /*10h */ - u16 timeout; /*12h */ - - u32 data_xfer_len; /*14h */ - u64 sas_addr; /*18h */ - - union { - struct megasas_sge32 sge32[2]; /* [0]: resp [1]: req */ - struct megasas_sge64 sge64[2]; /* [0]: resp [1]: req */ - } sgl; - -} __attribute__ ((packed)); - -struct megasas_stp_frame { - - u8 cmd; /*00h */ - u8 reserved_1; /*01h */ - u8 cmd_status; /*02h */ - u8 reserved_2; /*03h */ - - u8 target_id; /*04h */ - u8 reserved_3[2]; /*05h */ - u8 sge_count; /*07h */ - - u32 context; /*08h */ - u32 pad_0; /*0Ch */ - - u16 flags; /*10h */ - u16 timeout; /*12h */ - - u32 data_xfer_len; /*14h */ - - u16 fis[10]; /*18h */ - u32 stp_flags; - - union { - struct megasas_sge32 sge32[2]; /* [0]: resp [1]: data */ - struct megasas_sge64 sge64[2]; /* [0]: resp [1]: data */ - } sgl; - -} __attribute__ ((packed)); - -union megasas_frame { - - struct megasas_header hdr; - struct megasas_init_frame init; - struct megasas_io_frame io; - struct megasas_pthru_frame pthru; - struct megasas_dcmd_frame dcmd; - struct megasas_abort_frame abort; - struct megasas_smp_frame smp; - struct megasas_stp_frame stp; - - u8 raw_bytes[64]; -}; - -struct megasas_cmd; - -union megasas_evt_class_locale { - - struct { - u16 locale; - u8 reserved; - s8 class; - } __attribute__ ((packed)) members; - - u32 word; - -} __attribute__ ((packed)); - -struct megasas_evt_log_info { - u32 newest_seq_num; - u32 oldest_seq_num; - u32 clear_seq_num; - u32 shutdown_seq_num; - u32 boot_seq_num; - -} __attribute__ ((packed)); - -struct megasas_progress { - - u16 progress; - u16 elapsed_seconds; - -} __attribute__ ((packed)); - -struct megasas_evtarg_ld { - - u16 target_id; - u8 ld_index; - u8 reserved; - -} __attribute__ ((packed)); - -struct megasas_evtarg_pd { - u16 device_id; - u8 encl_index; - u8 slot_number; - -} __attribute__ ((packed)); - -struct megasas_evt_detail { - - u32 seq_num; - u32 time_stamp; - u32 code; - union megasas_evt_class_locale cl; - u8 arg_type; - u8 reserved1[15]; - - union { - struct { - struct megasas_evtarg_pd pd; - u8 cdb_length; - u8 sense_length; - u8 reserved[2]; - u8 cdb[16]; - u8 sense[64]; - } __attribute__ ((packed)) cdbSense; - - struct megasas_evtarg_ld ld; - - struct { - struct megasas_evtarg_ld ld; - u64 count; - } __attribute__ ((packed)) ld_count; - - struct { - u64 lba; - struct megasas_evtarg_ld ld; - } __attribute__ ((packed)) ld_lba; - - struct { - struct megasas_evtarg_ld ld; - u32 prevOwner; - u32 newOwner; - } __attribute__ ((packed)) ld_owner; - - struct { - u64 ld_lba; - u64 pd_lba; - struct megasas_evtarg_ld ld; - struct megasas_evtarg_pd pd; - } __attribute__ ((packed)) ld_lba_pd_lba; - - struct { - struct megasas_evtarg_ld ld; - struct megasas_progress prog; - } __attribute__ ((packed)) ld_prog; - - struct { - struct megasas_evtarg_ld ld; - u32 prev_state; - u32 new_state; - } __attribute__ ((packed)) ld_state; - - struct { - u64 strip; - struct megasas_evtarg_ld ld; - } __attribute__ ((packed)) ld_strip; - - struct megasas_evtarg_pd pd; - - struct { - struct megasas_evtarg_pd pd; - u32 err; - } __attribute__ ((packed)) pd_err; - - struct { - u64 lba; - struct megasas_evtarg_pd pd; - } __attribute__ ((packed)) pd_lba; - - struct { - u64 lba; - struct megasas_evtarg_pd pd; - struct megasas_evtarg_ld ld; - } __attribute__ ((packed)) pd_lba_ld; - - struct { - struct megasas_evtarg_pd pd; - struct megasas_progress prog; - } __attribute__ ((packed)) pd_prog; - - struct { - struct megasas_evtarg_pd pd; - u32 prevState; - u32 newState; - } __attribute__ ((packed)) pd_state; - - struct { - u16 vendorId; - u16 deviceId; - u16 subVendorId; - u16 subDeviceId; - } __attribute__ ((packed)) pci; - - u32 rate; - char str[96]; - - struct { - u32 rtc; - u32 elapsedSeconds; - } __attribute__ ((packed)) time; - - struct { - u32 ecar; - u32 elog; - char str[64]; - } __attribute__ ((packed)) ecc; - - u8 b[96]; - u16 s[48]; - u32 w[24]; - u64 d[12]; - } args; - - char description[128]; - -} __attribute__ ((packed)); - -struct megasas_aen_event { - struct work_struct hotplug_work; - struct megasas_instance *instance; -}; - -struct megasas_irq_context { - struct megasas_instance *instance; - u32 MSIxIndex; -}; - -struct megasas_instance { - - u32 *producer; - dma_addr_t producer_h; - u32 *consumer; - dma_addr_t consumer_h; - - u32 *reply_queue; - dma_addr_t reply_queue_h; - - unsigned long base_addr; - struct megasas_register_set __iomem *reg_set; - - struct megasas_pd_list pd_list[MEGASAS_MAX_PD]; - u8 ld_ids[MEGASAS_MAX_LD_IDS]; - s8 init_id; - - u16 max_num_sge; - u16 max_fw_cmds; - /* For Fusion its num IOCTL cmds, for others MFI based its - max_fw_cmds */ - u16 max_mfi_cmds; - u32 max_sectors_per_req; - struct megasas_aen_event *ev; - - struct megasas_cmd **cmd_list; - struct list_head cmd_pool; - /* used to sync fire the cmd to fw */ - spinlock_t cmd_pool_lock; - /* used to sync fire the cmd to fw */ - spinlock_t hba_lock; - /* used to synch producer, consumer ptrs in dpc */ - spinlock_t completion_lock; - struct dma_pool *frame_dma_pool; - struct dma_pool *sense_dma_pool; - - struct megasas_evt_detail *evt_detail; - dma_addr_t evt_detail_h; - struct megasas_cmd *aen_cmd; - struct mutex aen_mutex; - struct semaphore ioctl_sem; - - struct Scsi_Host *host; - - wait_queue_head_t int_cmd_wait_q; - wait_queue_head_t abort_cmd_wait_q; - - struct pci_dev *pdev; - u32 unique_id; - u32 fw_support_ieee; - - atomic_t fw_outstanding; - atomic_t fw_reset_no_pci_access; - - struct megasas_instance_template *instancet; - struct tasklet_struct isr_tasklet; - struct work_struct work_init; - - u8 flag; - u8 unload; - u8 flag_ieee; - u8 issuepend_done; - u8 disableOnlineCtrlReset; - u8 adprecovery; - unsigned long last_time; - u32 mfiStatus; - u32 last_seq_num; - - struct list_head internal_reset_pending_q; - - /* Ptr to hba specific information */ - void *ctrl_context; - unsigned int msix_vectors; - struct msix_entry msixentry[MEGASAS_MAX_MSIX_QUEUES]; - struct megasas_irq_context irq_context[MEGASAS_MAX_MSIX_QUEUES]; - u64 map_id; - struct megasas_cmd *map_update_cmd; - unsigned long bar; - long reset_flags; - struct mutex reset_mutex; -}; - -enum { - MEGASAS_HBA_OPERATIONAL = 0, - MEGASAS_ADPRESET_SM_INFAULT = 1, - MEGASAS_ADPRESET_SM_FW_RESET_SUCCESS = 2, - MEGASAS_ADPRESET_SM_OPERATIONAL = 3, - MEGASAS_HW_CRITICAL_ERROR = 4, - MEGASAS_ADPRESET_INPROG_SIGN = 0xDEADDEAD, -}; - -struct megasas_instance_template { - void (*fire_cmd)(struct megasas_instance *, dma_addr_t, \ - u32, struct megasas_register_set __iomem *); - - void (*enable_intr)(struct megasas_register_set __iomem *) ; - void (*disable_intr)(struct megasas_register_set __iomem *); - - int (*clear_intr)(struct megasas_register_set __iomem *); - - u32 (*read_fw_status_reg)(struct megasas_register_set __iomem *); - int (*adp_reset)(struct megasas_instance *, \ - struct megasas_register_set __iomem *); - int (*check_reset)(struct megasas_instance *, \ - struct megasas_register_set __iomem *); - irqreturn_t (*service_isr)(int irq, void *devp); - void (*tasklet)(unsigned long); - u32 (*init_adapter)(struct megasas_instance *); - u32 (*build_and_issue_cmd) (struct megasas_instance *, - struct scsi_cmnd *); - void (*issue_dcmd) (struct megasas_instance *instance, - struct megasas_cmd *cmd); -}; - -#define MEGASAS_IS_LOGICAL(scp) \ - (scp->device->channel < MEGASAS_MAX_PD_CHANNELS) ? 0 : 1 - -#define MEGASAS_DEV_INDEX(inst, scp) \ - ((scp->device->channel % 2) * MEGASAS_MAX_DEV_PER_CHANNEL) + \ - scp->device->id - -struct megasas_cmd { - - union megasas_frame *frame; - dma_addr_t frame_phys_addr; - u8 *sense; - dma_addr_t sense_phys_addr; - - u32 index; - u8 sync_cmd; - u8 cmd_status; - u8 abort_aen; - u8 retry_for_fw_reset; - - - struct list_head list; - struct scsi_cmnd *scmd; - struct megasas_instance *instance; - union { - struct { - u16 smid; - u16 resvd; - } context; - u32 frame_count; - }; -}; - -#define MAX_MGMT_ADAPTERS 1024 -#define MAX_IOCTL_SGE 16 - -struct megasas_iocpacket { - - u16 host_no; - u16 __pad1; - u32 sgl_off; - u32 sge_count; - u32 sense_off; - u32 sense_len; - union { - u8 raw[128]; - struct megasas_header hdr; - } frame; - - struct iovec sgl[MAX_IOCTL_SGE]; - -} __attribute__ ((packed)); - -struct megasas_aen { - u16 host_no; - u16 __pad1; - u32 seq_num; - u32 class_locale_word; -} __attribute__ ((packed)); - -#ifdef CONFIG_COMPAT -struct compat_megasas_iocpacket { - u16 host_no; - u16 __pad1; - u32 sgl_off; - u32 sge_count; - u32 sense_off; - u32 sense_len; - union { - u8 raw[128]; - struct megasas_header hdr; - } frame; - struct compat_iovec sgl[MAX_IOCTL_SGE]; -} __attribute__ ((packed)); - -#define MEGASAS_IOC_FIRMWARE32 _IOWR('M', 1, struct compat_megasas_iocpacket) -#endif - -#define MEGASAS_IOC_FIRMWARE _IOWR('M', 1, struct megasas_iocpacket) -#define MEGASAS_IOC_GET_AEN _IOW('M', 3, struct megasas_aen) - -struct megasas_mgmt_info { - - u16 count; - struct megasas_instance *instance[MAX_MGMT_ADAPTERS]; - int max_index; -}; - -#define msi_control_reg(base) (base + PCI_MSI_FLAGS) -#define PCI_MSIX_FLAGS_ENABLE (1 << 15) - -#endif /*LSI_MEGARAID_SAS_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_base.c b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_base.c deleted file mode 100644 index 8b300be4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_base.c +++ /dev/null @@ -1,5487 +0,0 @@ -/* - * Linux MegaRAID driver for SAS based RAID controllers - * - * Copyright (c) 2009-2011 LSI Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * FILE: megaraid_sas_base.c - * Version : v00.00.06.14-rc1 - * - * Authors: LSI Corporation - * Sreenivas Bagalkote - * Sumant Patro - * Bo Yang - * Adam Radford - * - * Send feedback to: - * - * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 - * ATTN: Linuxraid - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "megaraid_sas_fusion.h" -#include "megaraid_sas.h" - -/* - * Number of sectors per IO command - * Will be set in megasas_init_mfi if user does not provide - */ -static unsigned int max_sectors; -module_param_named(max_sectors, max_sectors, int, 0); -MODULE_PARM_DESC(max_sectors, - "Maximum number of sectors per IO command"); - -static int msix_disable; -module_param(msix_disable, int, S_IRUGO); -MODULE_PARM_DESC(msix_disable, "Disable MSI-X interrupt handling. Default: 0"); - -MODULE_LICENSE("GPL"); -MODULE_VERSION(MEGASAS_VERSION); -MODULE_AUTHOR("megaraidlinux@lsi.com"); -MODULE_DESCRIPTION("LSI MegaRAID SAS Driver"); - -int megasas_transition_to_ready(struct megasas_instance *instance, int ocr); -static int megasas_get_pd_list(struct megasas_instance *instance); -static int megasas_issue_init_mfi(struct megasas_instance *instance); -static int megasas_register_aen(struct megasas_instance *instance, - u32 seq_num, u32 class_locale_word); -/* - * PCI ID table for all supported controllers - */ -static struct pci_device_id megasas_pci_table[] = { - - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1064R)}, - /* xscale IOP */ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078R)}, - /* ppc IOP */ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078DE)}, - /* ppc IOP */ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS1078GEN2)}, - /* gen2*/ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0079GEN2)}, - /* gen2*/ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0073SKINNY)}, - /* skinny*/ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_SAS0071SKINNY)}, - /* skinny*/ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_VERDE_ZCR)}, - /* xscale IOP, vega */ - {PCI_DEVICE(PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DELL_PERC5)}, - /* xscale IOP */ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_FUSION)}, - /* Fusion */ - {PCI_DEVICE(PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_INVADER)}, - /* Invader */ - {} -}; - -MODULE_DEVICE_TABLE(pci, megasas_pci_table); - -static int megasas_mgmt_majorno; -static struct megasas_mgmt_info megasas_mgmt_info; -static struct fasync_struct *megasas_async_queue; -static DEFINE_MUTEX(megasas_async_queue_mutex); - -static int megasas_poll_wait_aen; -static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait); -static u32 support_poll_for_event; -u32 megasas_dbg_lvl; -static u32 support_device_change; - -/* define lock for aen poll */ -spinlock_t poll_aen_lock; - -void -megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, - u8 alt_status); -static u32 -megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs); -static int -megasas_adp_reset_gen2(struct megasas_instance *instance, - struct megasas_register_set __iomem *reg_set); -static irqreturn_t megasas_isr(int irq, void *devp); -static u32 -megasas_init_adapter_mfi(struct megasas_instance *instance); -u32 -megasas_build_and_issue_cmd(struct megasas_instance *instance, - struct scsi_cmnd *scmd); -static void megasas_complete_cmd_dpc(unsigned long instance_addr); -void -megasas_release_fusion(struct megasas_instance *instance); -int -megasas_ioc_init_fusion(struct megasas_instance *instance); -void -megasas_free_cmds_fusion(struct megasas_instance *instance); -u8 -megasas_get_map_info(struct megasas_instance *instance); -int -megasas_sync_map_info(struct megasas_instance *instance); -int -wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd); -void megasas_reset_reply_desc(struct megasas_instance *instance); -u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map, - struct LD_LOAD_BALANCE_INFO *lbInfo); -int megasas_reset_fusion(struct Scsi_Host *shost); -void megasas_fusion_ocr_wq(struct work_struct *work); - -void -megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd) -{ - instance->instancet->fire_cmd(instance, - cmd->frame_phys_addr, 0, instance->reg_set); -} - -/** - * megasas_get_cmd - Get a command from the free pool - * @instance: Adapter soft state - * - * Returns a free command from the pool - */ -struct megasas_cmd *megasas_get_cmd(struct megasas_instance - *instance) -{ - unsigned long flags; - struct megasas_cmd *cmd = NULL; - - spin_lock_irqsave(&instance->cmd_pool_lock, flags); - - if (!list_empty(&instance->cmd_pool)) { - cmd = list_entry((&instance->cmd_pool)->next, - struct megasas_cmd, list); - list_del_init(&cmd->list); - } else { - printk(KERN_ERR "megasas: Command pool empty!\n"); - } - - spin_unlock_irqrestore(&instance->cmd_pool_lock, flags); - return cmd; -} - -/** - * megasas_return_cmd - Return a cmd to free command pool - * @instance: Adapter soft state - * @cmd: Command packet to be returned to free command pool - */ -inline void -megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) -{ - unsigned long flags; - - spin_lock_irqsave(&instance->cmd_pool_lock, flags); - - cmd->scmd = NULL; - cmd->frame_count = 0; - if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) && - (reset_devices)) - cmd->frame->hdr.cmd = MFI_CMD_INVALID; - list_add_tail(&cmd->list, &instance->cmd_pool); - - spin_unlock_irqrestore(&instance->cmd_pool_lock, flags); -} - - -/** -* The following functions are defined for xscale -* (deviceid : 1064R, PERC5) controllers -*/ - -/** - * megasas_enable_intr_xscale - Enables interrupts - * @regs: MFI register set - */ -static inline void -megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs) -{ - writel(0, &(regs)->outbound_intr_mask); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_disable_intr_xscale -Disables interrupt - * @regs: MFI register set - */ -static inline void -megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs) -{ - u32 mask = 0x1f; - writel(mask, ®s->outbound_intr_mask); - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_read_fw_status_reg_xscale - returns the current FW status value - * @regs: MFI register set - */ -static u32 -megasas_read_fw_status_reg_xscale(struct megasas_register_set __iomem * regs) -{ - return readl(&(regs)->outbound_msg_0); -} -/** - * megasas_clear_interrupt_xscale - Check & clear interrupt - * @regs: MFI register set - */ -static int -megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs) -{ - u32 status; - u32 mfiStatus = 0; - /* - * Check if it is our interrupt - */ - status = readl(®s->outbound_intr_status); - - if (status & MFI_OB_INTR_STATUS_MASK) - mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; - if (status & MFI_XSCALE_OMR0_CHANGE_INTERRUPT) - mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; - - /* - * Clear the interrupt by writing back the same value - */ - if (mfiStatus) - writel(status, ®s->outbound_intr_status); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_status); - - return mfiStatus; -} - -/** - * megasas_fire_cmd_xscale - Sends command to the FW - * @frame_phys_addr : Physical address of cmd - * @frame_count : Number of frames for the command - * @regs : MFI register set - */ -static inline void -megasas_fire_cmd_xscale(struct megasas_instance *instance, - dma_addr_t frame_phys_addr, - u32 frame_count, - struct megasas_register_set __iomem *regs) -{ - unsigned long flags; - spin_lock_irqsave(&instance->hba_lock, flags); - writel((frame_phys_addr >> 3)|(frame_count), - &(regs)->inbound_queue_port); - spin_unlock_irqrestore(&instance->hba_lock, flags); -} - -/** - * megasas_adp_reset_xscale - For controller reset - * @regs: MFI register set - */ -static int -megasas_adp_reset_xscale(struct megasas_instance *instance, - struct megasas_register_set __iomem *regs) -{ - u32 i; - u32 pcidata; - writel(MFI_ADP_RESET, ®s->inbound_doorbell); - - for (i = 0; i < 3; i++) - msleep(1000); /* sleep for 3 secs */ - pcidata = 0; - pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata); - printk(KERN_NOTICE "pcidata = %x\n", pcidata); - if (pcidata & 0x2) { - printk(KERN_NOTICE "mfi 1068 offset read=%x\n", pcidata); - pcidata &= ~0x2; - pci_write_config_dword(instance->pdev, - MFI_1068_PCSR_OFFSET, pcidata); - - for (i = 0; i < 2; i++) - msleep(1000); /* need to wait 2 secs again */ - - pcidata = 0; - pci_read_config_dword(instance->pdev, - MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata); - printk(KERN_NOTICE "1068 offset handshake read=%x\n", pcidata); - if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) { - printk(KERN_NOTICE "1068 offset pcidt=%x\n", pcidata); - pcidata = 0; - pci_write_config_dword(instance->pdev, - MFI_1068_FW_HANDSHAKE_OFFSET, pcidata); - } - } - return 0; -} - -/** - * megasas_check_reset_xscale - For controller reset check - * @regs: MFI register set - */ -static int -megasas_check_reset_xscale(struct megasas_instance *instance, - struct megasas_register_set __iomem *regs) -{ - u32 consumer; - consumer = *instance->consumer; - - if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) && - (*instance->consumer == MEGASAS_ADPRESET_INPROG_SIGN)) { - return 1; - } - return 0; -} - -static struct megasas_instance_template megasas_instance_template_xscale = { - - .fire_cmd = megasas_fire_cmd_xscale, - .enable_intr = megasas_enable_intr_xscale, - .disable_intr = megasas_disable_intr_xscale, - .clear_intr = megasas_clear_intr_xscale, - .read_fw_status_reg = megasas_read_fw_status_reg_xscale, - .adp_reset = megasas_adp_reset_xscale, - .check_reset = megasas_check_reset_xscale, - .service_isr = megasas_isr, - .tasklet = megasas_complete_cmd_dpc, - .init_adapter = megasas_init_adapter_mfi, - .build_and_issue_cmd = megasas_build_and_issue_cmd, - .issue_dcmd = megasas_issue_dcmd, -}; - -/** -* This is the end of set of functions & definitions specific -* to xscale (deviceid : 1064R, PERC5) controllers -*/ - -/** -* The following functions are defined for ppc (deviceid : 0x60) -* controllers -*/ - -/** - * megasas_enable_intr_ppc - Enables interrupts - * @regs: MFI register set - */ -static inline void -megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs) -{ - writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); - - writel(~0x80000000, &(regs)->outbound_intr_mask); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_disable_intr_ppc - Disable interrupt - * @regs: MFI register set - */ -static inline void -megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs) -{ - u32 mask = 0xFFFFFFFF; - writel(mask, ®s->outbound_intr_mask); - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_read_fw_status_reg_ppc - returns the current FW status value - * @regs: MFI register set - */ -static u32 -megasas_read_fw_status_reg_ppc(struct megasas_register_set __iomem * regs) -{ - return readl(&(regs)->outbound_scratch_pad); -} - -/** - * megasas_clear_interrupt_ppc - Check & clear interrupt - * @regs: MFI register set - */ -static int -megasas_clear_intr_ppc(struct megasas_register_set __iomem * regs) -{ - u32 status, mfiStatus = 0; - - /* - * Check if it is our interrupt - */ - status = readl(®s->outbound_intr_status); - - if (status & MFI_REPLY_1078_MESSAGE_INTERRUPT) - mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; - - if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) - mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; - - /* - * Clear the interrupt by writing back the same value - */ - writel(status, ®s->outbound_doorbell_clear); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_doorbell_clear); - - return mfiStatus; -} - -/** - * megasas_fire_cmd_ppc - Sends command to the FW - * @frame_phys_addr : Physical address of cmd - * @frame_count : Number of frames for the command - * @regs : MFI register set - */ -static inline void -megasas_fire_cmd_ppc(struct megasas_instance *instance, - dma_addr_t frame_phys_addr, - u32 frame_count, - struct megasas_register_set __iomem *regs) -{ - unsigned long flags; - spin_lock_irqsave(&instance->hba_lock, flags); - writel((frame_phys_addr | (frame_count<<1))|1, - &(regs)->inbound_queue_port); - spin_unlock_irqrestore(&instance->hba_lock, flags); -} - -/** - * megasas_check_reset_ppc - For controller reset check - * @regs: MFI register set - */ -static int -megasas_check_reset_ppc(struct megasas_instance *instance, - struct megasas_register_set __iomem *regs) -{ - if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) - return 1; - - return 0; -} - -static struct megasas_instance_template megasas_instance_template_ppc = { - - .fire_cmd = megasas_fire_cmd_ppc, - .enable_intr = megasas_enable_intr_ppc, - .disable_intr = megasas_disable_intr_ppc, - .clear_intr = megasas_clear_intr_ppc, - .read_fw_status_reg = megasas_read_fw_status_reg_ppc, - .adp_reset = megasas_adp_reset_xscale, - .check_reset = megasas_check_reset_ppc, - .service_isr = megasas_isr, - .tasklet = megasas_complete_cmd_dpc, - .init_adapter = megasas_init_adapter_mfi, - .build_and_issue_cmd = megasas_build_and_issue_cmd, - .issue_dcmd = megasas_issue_dcmd, -}; - -/** - * megasas_enable_intr_skinny - Enables interrupts - * @regs: MFI register set - */ -static inline void -megasas_enable_intr_skinny(struct megasas_register_set __iomem *regs) -{ - writel(0xFFFFFFFF, &(regs)->outbound_intr_mask); - - writel(~MFI_SKINNY_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_disable_intr_skinny - Disables interrupt - * @regs: MFI register set - */ -static inline void -megasas_disable_intr_skinny(struct megasas_register_set __iomem *regs) -{ - u32 mask = 0xFFFFFFFF; - writel(mask, ®s->outbound_intr_mask); - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_read_fw_status_reg_skinny - returns the current FW status value - * @regs: MFI register set - */ -static u32 -megasas_read_fw_status_reg_skinny(struct megasas_register_set __iomem *regs) -{ - return readl(&(regs)->outbound_scratch_pad); -} - -/** - * megasas_clear_interrupt_skinny - Check & clear interrupt - * @regs: MFI register set - */ -static int -megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs) -{ - u32 status; - u32 mfiStatus = 0; - - /* - * Check if it is our interrupt - */ - status = readl(®s->outbound_intr_status); - - if (!(status & MFI_SKINNY_ENABLE_INTERRUPT_MASK)) { - return 0; - } - - /* - * Check if it is our interrupt - */ - if ((megasas_read_fw_status_reg_gen2(regs) & MFI_STATE_MASK) == - MFI_STATE_FAULT) { - mfiStatus = MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; - } else - mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; - - /* - * Clear the interrupt by writing back the same value - */ - writel(status, ®s->outbound_intr_status); - - /* - * dummy read to flush PCI - */ - readl(®s->outbound_intr_status); - - return mfiStatus; -} - -/** - * megasas_fire_cmd_skinny - Sends command to the FW - * @frame_phys_addr : Physical address of cmd - * @frame_count : Number of frames for the command - * @regs : MFI register set - */ -static inline void -megasas_fire_cmd_skinny(struct megasas_instance *instance, - dma_addr_t frame_phys_addr, - u32 frame_count, - struct megasas_register_set __iomem *regs) -{ - unsigned long flags; - spin_lock_irqsave(&instance->hba_lock, flags); - writel(0, &(regs)->inbound_high_queue_port); - writel((frame_phys_addr | (frame_count<<1))|1, - &(regs)->inbound_low_queue_port); - spin_unlock_irqrestore(&instance->hba_lock, flags); -} - -/** - * megasas_check_reset_skinny - For controller reset check - * @regs: MFI register set - */ -static int -megasas_check_reset_skinny(struct megasas_instance *instance, - struct megasas_register_set __iomem *regs) -{ - if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) - return 1; - - return 0; -} - -static struct megasas_instance_template megasas_instance_template_skinny = { - - .fire_cmd = megasas_fire_cmd_skinny, - .enable_intr = megasas_enable_intr_skinny, - .disable_intr = megasas_disable_intr_skinny, - .clear_intr = megasas_clear_intr_skinny, - .read_fw_status_reg = megasas_read_fw_status_reg_skinny, - .adp_reset = megasas_adp_reset_gen2, - .check_reset = megasas_check_reset_skinny, - .service_isr = megasas_isr, - .tasklet = megasas_complete_cmd_dpc, - .init_adapter = megasas_init_adapter_mfi, - .build_and_issue_cmd = megasas_build_and_issue_cmd, - .issue_dcmd = megasas_issue_dcmd, -}; - - -/** -* The following functions are defined for gen2 (deviceid : 0x78 0x79) -* controllers -*/ - -/** - * megasas_enable_intr_gen2 - Enables interrupts - * @regs: MFI register set - */ -static inline void -megasas_enable_intr_gen2(struct megasas_register_set __iomem *regs) -{ - writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); - - /* write ~0x00000005 (4 & 1) to the intr mask*/ - writel(~MFI_GEN2_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_disable_intr_gen2 - Disables interrupt - * @regs: MFI register set - */ -static inline void -megasas_disable_intr_gen2(struct megasas_register_set __iomem *regs) -{ - u32 mask = 0xFFFFFFFF; - writel(mask, ®s->outbound_intr_mask); - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_read_fw_status_reg_gen2 - returns the current FW status value - * @regs: MFI register set - */ -static u32 -megasas_read_fw_status_reg_gen2(struct megasas_register_set __iomem *regs) -{ - return readl(&(regs)->outbound_scratch_pad); -} - -/** - * megasas_clear_interrupt_gen2 - Check & clear interrupt - * @regs: MFI register set - */ -static int -megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs) -{ - u32 status; - u32 mfiStatus = 0; - /* - * Check if it is our interrupt - */ - status = readl(®s->outbound_intr_status); - - if (status & MFI_GEN2_ENABLE_INTERRUPT_MASK) { - mfiStatus = MFI_INTR_FLAG_REPLY_MESSAGE; - } - if (status & MFI_G2_OUTBOUND_DOORBELL_CHANGE_INTERRUPT) { - mfiStatus |= MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE; - } - - /* - * Clear the interrupt by writing back the same value - */ - if (mfiStatus) - writel(status, ®s->outbound_doorbell_clear); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_status); - - return mfiStatus; -} -/** - * megasas_fire_cmd_gen2 - Sends command to the FW - * @frame_phys_addr : Physical address of cmd - * @frame_count : Number of frames for the command - * @regs : MFI register set - */ -static inline void -megasas_fire_cmd_gen2(struct megasas_instance *instance, - dma_addr_t frame_phys_addr, - u32 frame_count, - struct megasas_register_set __iomem *regs) -{ - unsigned long flags; - spin_lock_irqsave(&instance->hba_lock, flags); - writel((frame_phys_addr | (frame_count<<1))|1, - &(regs)->inbound_queue_port); - spin_unlock_irqrestore(&instance->hba_lock, flags); -} - -/** - * megasas_adp_reset_gen2 - For controller reset - * @regs: MFI register set - */ -static int -megasas_adp_reset_gen2(struct megasas_instance *instance, - struct megasas_register_set __iomem *reg_set) -{ - u32 retry = 0 ; - u32 HostDiag; - u32 *seq_offset = ®_set->seq_offset; - u32 *hostdiag_offset = ®_set->host_diag; - - if (instance->instancet == &megasas_instance_template_skinny) { - seq_offset = ®_set->fusion_seq_offset; - hostdiag_offset = ®_set->fusion_host_diag; - } - - writel(0, seq_offset); - writel(4, seq_offset); - writel(0xb, seq_offset); - writel(2, seq_offset); - writel(7, seq_offset); - writel(0xd, seq_offset); - - msleep(1000); - - HostDiag = (u32)readl(hostdiag_offset); - - while ( !( HostDiag & DIAG_WRITE_ENABLE) ) { - msleep(100); - HostDiag = (u32)readl(hostdiag_offset); - printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n", - retry, HostDiag); - - if (retry++ >= 100) - return 1; - - } - - printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag); - - writel((HostDiag | DIAG_RESET_ADAPTER), hostdiag_offset); - - ssleep(10); - - HostDiag = (u32)readl(hostdiag_offset); - while ( ( HostDiag & DIAG_RESET_ADAPTER) ) { - msleep(100); - HostDiag = (u32)readl(hostdiag_offset); - printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n", - retry, HostDiag); - - if (retry++ >= 1000) - return 1; - - } - return 0; -} - -/** - * megasas_check_reset_gen2 - For controller reset check - * @regs: MFI register set - */ -static int -megasas_check_reset_gen2(struct megasas_instance *instance, - struct megasas_register_set __iomem *regs) -{ - if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { - return 1; - } - - return 0; -} - -static struct megasas_instance_template megasas_instance_template_gen2 = { - - .fire_cmd = megasas_fire_cmd_gen2, - .enable_intr = megasas_enable_intr_gen2, - .disable_intr = megasas_disable_intr_gen2, - .clear_intr = megasas_clear_intr_gen2, - .read_fw_status_reg = megasas_read_fw_status_reg_gen2, - .adp_reset = megasas_adp_reset_gen2, - .check_reset = megasas_check_reset_gen2, - .service_isr = megasas_isr, - .tasklet = megasas_complete_cmd_dpc, - .init_adapter = megasas_init_adapter_mfi, - .build_and_issue_cmd = megasas_build_and_issue_cmd, - .issue_dcmd = megasas_issue_dcmd, -}; - -/** -* This is the end of set of functions & definitions -* specific to gen2 (deviceid : 0x78, 0x79) controllers -*/ - -/* - * Template added for TB (Fusion) - */ -extern struct megasas_instance_template megasas_instance_template_fusion; - -/** - * megasas_issue_polled - Issues a polling command - * @instance: Adapter soft state - * @cmd: Command packet to be issued - * - * For polling, MFI requires the cmd_status to be set to 0xFF before posting. - */ -int -megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) -{ - - struct megasas_header *frame_hdr = &cmd->frame->hdr; - - frame_hdr->cmd_status = 0xFF; - frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; - - /* - * Issue the frame using inbound queue port - */ - instance->instancet->issue_dcmd(instance, cmd); - - /* - * Wait for cmd_status to change - */ - return wait_and_poll(instance, cmd); -} - -/** - * megasas_issue_blocked_cmd - Synchronous wrapper around regular FW cmds - * @instance: Adapter soft state - * @cmd: Command to be issued - * - * This function waits on an event for the command to be returned from ISR. - * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs - * Used to issue ioctl commands. - */ -static int -megasas_issue_blocked_cmd(struct megasas_instance *instance, - struct megasas_cmd *cmd) -{ - cmd->cmd_status = ENODATA; - - instance->instancet->issue_dcmd(instance, cmd); - - wait_event(instance->int_cmd_wait_q, cmd->cmd_status != ENODATA); - - return 0; -} - -/** - * megasas_issue_blocked_abort_cmd - Aborts previously issued cmd - * @instance: Adapter soft state - * @cmd_to_abort: Previously issued cmd to be aborted - * - * MFI firmware can abort previously issued AEN command (automatic event - * notification). The megasas_issue_blocked_abort_cmd() issues such abort - * cmd and waits for return status. - * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs - */ -static int -megasas_issue_blocked_abort_cmd(struct megasas_instance *instance, - struct megasas_cmd *cmd_to_abort) -{ - struct megasas_cmd *cmd; - struct megasas_abort_frame *abort_fr; - - cmd = megasas_get_cmd(instance); - - if (!cmd) - return -1; - - abort_fr = &cmd->frame->abort; - - /* - * Prepare and issue the abort frame - */ - abort_fr->cmd = MFI_CMD_ABORT; - abort_fr->cmd_status = 0xFF; - abort_fr->flags = 0; - abort_fr->abort_context = cmd_to_abort->index; - abort_fr->abort_mfi_phys_addr_lo = cmd_to_abort->frame_phys_addr; - abort_fr->abort_mfi_phys_addr_hi = 0; - - cmd->sync_cmd = 1; - cmd->cmd_status = 0xFF; - - instance->instancet->issue_dcmd(instance, cmd); - - /* - * Wait for this cmd to complete - */ - wait_event(instance->abort_cmd_wait_q, cmd->cmd_status != 0xFF); - cmd->sync_cmd = 0; - - megasas_return_cmd(instance, cmd); - return 0; -} - -/** - * megasas_make_sgl32 - Prepares 32-bit SGL - * @instance: Adapter soft state - * @scp: SCSI command from the mid-layer - * @mfi_sgl: SGL to be filled in - * - * If successful, this function returns the number of SG elements. Otherwise, - * it returnes -1. - */ -static int -megasas_make_sgl32(struct megasas_instance *instance, struct scsi_cmnd *scp, - union megasas_sgl *mfi_sgl) -{ - int i; - int sge_count; - struct scatterlist *os_sgl; - - sge_count = scsi_dma_map(scp); - BUG_ON(sge_count < 0); - - if (sge_count) { - scsi_for_each_sg(scp, os_sgl, sge_count, i) { - mfi_sgl->sge32[i].length = sg_dma_len(os_sgl); - mfi_sgl->sge32[i].phys_addr = sg_dma_address(os_sgl); - } - } - return sge_count; -} - -/** - * megasas_make_sgl64 - Prepares 64-bit SGL - * @instance: Adapter soft state - * @scp: SCSI command from the mid-layer - * @mfi_sgl: SGL to be filled in - * - * If successful, this function returns the number of SG elements. Otherwise, - * it returnes -1. - */ -static int -megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp, - union megasas_sgl *mfi_sgl) -{ - int i; - int sge_count; - struct scatterlist *os_sgl; - - sge_count = scsi_dma_map(scp); - BUG_ON(sge_count < 0); - - if (sge_count) { - scsi_for_each_sg(scp, os_sgl, sge_count, i) { - mfi_sgl->sge64[i].length = sg_dma_len(os_sgl); - mfi_sgl->sge64[i].phys_addr = sg_dma_address(os_sgl); - } - } - return sge_count; -} - -/** - * megasas_make_sgl_skinny - Prepares IEEE SGL - * @instance: Adapter soft state - * @scp: SCSI command from the mid-layer - * @mfi_sgl: SGL to be filled in - * - * If successful, this function returns the number of SG elements. Otherwise, - * it returnes -1. - */ -static int -megasas_make_sgl_skinny(struct megasas_instance *instance, - struct scsi_cmnd *scp, union megasas_sgl *mfi_sgl) -{ - int i; - int sge_count; - struct scatterlist *os_sgl; - - sge_count = scsi_dma_map(scp); - - if (sge_count) { - scsi_for_each_sg(scp, os_sgl, sge_count, i) { - mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl); - mfi_sgl->sge_skinny[i].phys_addr = - sg_dma_address(os_sgl); - mfi_sgl->sge_skinny[i].flag = 0; - } - } - return sge_count; -} - - /** - * megasas_get_frame_count - Computes the number of frames - * @frame_type : type of frame- io or pthru frame - * @sge_count : number of sg elements - * - * Returns the number of frames required for numnber of sge's (sge_count) - */ - -static u32 megasas_get_frame_count(struct megasas_instance *instance, - u8 sge_count, u8 frame_type) -{ - int num_cnt; - int sge_bytes; - u32 sge_sz; - u32 frame_count=0; - - sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : - sizeof(struct megasas_sge32); - - if (instance->flag_ieee) { - sge_sz = sizeof(struct megasas_sge_skinny); - } - - /* - * Main frame can contain 2 SGEs for 64-bit SGLs and - * 3 SGEs for 32-bit SGLs for ldio & - * 1 SGEs for 64-bit SGLs and - * 2 SGEs for 32-bit SGLs for pthru frame - */ - if (unlikely(frame_type == PTHRU_FRAME)) { - if (instance->flag_ieee == 1) { - num_cnt = sge_count - 1; - } else if (IS_DMA64) - num_cnt = sge_count - 1; - else - num_cnt = sge_count - 2; - } else { - if (instance->flag_ieee == 1) { - num_cnt = sge_count - 1; - } else if (IS_DMA64) - num_cnt = sge_count - 2; - else - num_cnt = sge_count - 3; - } - - if(num_cnt>0){ - sge_bytes = sge_sz * num_cnt; - - frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) + - ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ; - } - /* Main frame */ - frame_count +=1; - - if (frame_count > 7) - frame_count = 8; - return frame_count; -} - -/** - * megasas_build_dcdb - Prepares a direct cdb (DCDB) command - * @instance: Adapter soft state - * @scp: SCSI command - * @cmd: Command to be prepared in - * - * This function prepares CDB commands. These are typcially pass-through - * commands to the devices. - */ -static int -megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, - struct megasas_cmd *cmd) -{ - u32 is_logical; - u32 device_id; - u16 flags = 0; - struct megasas_pthru_frame *pthru; - - is_logical = MEGASAS_IS_LOGICAL(scp); - device_id = MEGASAS_DEV_INDEX(instance, scp); - pthru = (struct megasas_pthru_frame *)cmd->frame; - - if (scp->sc_data_direction == PCI_DMA_TODEVICE) - flags = MFI_FRAME_DIR_WRITE; - else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) - flags = MFI_FRAME_DIR_READ; - else if (scp->sc_data_direction == PCI_DMA_NONE) - flags = MFI_FRAME_DIR_NONE; - - if (instance->flag_ieee == 1) { - flags |= MFI_FRAME_IEEE; - } - - /* - * Prepare the DCDB frame - */ - pthru->cmd = (is_logical) ? MFI_CMD_LD_SCSI_IO : MFI_CMD_PD_SCSI_IO; - pthru->cmd_status = 0x0; - pthru->scsi_status = 0x0; - pthru->target_id = device_id; - pthru->lun = scp->device->lun; - pthru->cdb_len = scp->cmd_len; - pthru->timeout = 0; - pthru->pad_0 = 0; - pthru->flags = flags; - pthru->data_xfer_len = scsi_bufflen(scp); - - memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); - - /* - * If the command is for the tape device, set the - * pthru timeout to the os layer timeout value. - */ - if (scp->device->type == TYPE_TAPE) { - if ((scp->request->timeout / HZ) > 0xFFFF) - pthru->timeout = 0xFFFF; - else - pthru->timeout = scp->request->timeout / HZ; - } - - /* - * Construct SGL - */ - if (instance->flag_ieee == 1) { - pthru->flags |= MFI_FRAME_SGL64; - pthru->sge_count = megasas_make_sgl_skinny(instance, scp, - &pthru->sgl); - } else if (IS_DMA64) { - pthru->flags |= MFI_FRAME_SGL64; - pthru->sge_count = megasas_make_sgl64(instance, scp, - &pthru->sgl); - } else - pthru->sge_count = megasas_make_sgl32(instance, scp, - &pthru->sgl); - - if (pthru->sge_count > instance->max_num_sge) { - printk(KERN_ERR "megasas: DCDB two many SGE NUM=%x\n", - pthru->sge_count); - return 0; - } - - /* - * Sense info specific - */ - pthru->sense_len = SCSI_SENSE_BUFFERSIZE; - pthru->sense_buf_phys_addr_hi = 0; - pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr; - - /* - * Compute the total number of frames this command consumes. FW uses - * this number to pull sufficient number of frames from host memory. - */ - cmd->frame_count = megasas_get_frame_count(instance, pthru->sge_count, - PTHRU_FRAME); - - return cmd->frame_count; -} - -/** - * megasas_build_ldio - Prepares IOs to logical devices - * @instance: Adapter soft state - * @scp: SCSI command - * @cmd: Command to be prepared - * - * Frames (and accompanying SGLs) for regular SCSI IOs use this function. - */ -static int -megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, - struct megasas_cmd *cmd) -{ - u32 device_id; - u8 sc = scp->cmnd[0]; - u16 flags = 0; - struct megasas_io_frame *ldio; - - device_id = MEGASAS_DEV_INDEX(instance, scp); - ldio = (struct megasas_io_frame *)cmd->frame; - - if (scp->sc_data_direction == PCI_DMA_TODEVICE) - flags = MFI_FRAME_DIR_WRITE; - else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) - flags = MFI_FRAME_DIR_READ; - - if (instance->flag_ieee == 1) { - flags |= MFI_FRAME_IEEE; - } - - /* - * Prepare the Logical IO frame: 2nd bit is zero for all read cmds - */ - ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ; - ldio->cmd_status = 0x0; - ldio->scsi_status = 0x0; - ldio->target_id = device_id; - ldio->timeout = 0; - ldio->reserved_0 = 0; - ldio->pad_0 = 0; - ldio->flags = flags; - ldio->start_lba_hi = 0; - ldio->access_byte = (scp->cmd_len != 6) ? scp->cmnd[1] : 0; - - /* - * 6-byte READ(0x08) or WRITE(0x0A) cdb - */ - if (scp->cmd_len == 6) { - ldio->lba_count = (u32) scp->cmnd[4]; - ldio->start_lba_lo = ((u32) scp->cmnd[1] << 16) | - ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3]; - - ldio->start_lba_lo &= 0x1FFFFF; - } - - /* - * 10-byte READ(0x28) or WRITE(0x2A) cdb - */ - else if (scp->cmd_len == 10) { - ldio->lba_count = (u32) scp->cmnd[8] | - ((u32) scp->cmnd[7] << 8); - ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) | - ((u32) scp->cmnd[3] << 16) | - ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; - } - - /* - * 12-byte READ(0xA8) or WRITE(0xAA) cdb - */ - else if (scp->cmd_len == 12) { - ldio->lba_count = ((u32) scp->cmnd[6] << 24) | - ((u32) scp->cmnd[7] << 16) | - ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; - - ldio->start_lba_lo = ((u32) scp->cmnd[2] << 24) | - ((u32) scp->cmnd[3] << 16) | - ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; - } - - /* - * 16-byte READ(0x88) or WRITE(0x8A) cdb - */ - else if (scp->cmd_len == 16) { - ldio->lba_count = ((u32) scp->cmnd[10] << 24) | - ((u32) scp->cmnd[11] << 16) | - ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13]; - - ldio->start_lba_lo = ((u32) scp->cmnd[6] << 24) | - ((u32) scp->cmnd[7] << 16) | - ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; - - ldio->start_lba_hi = ((u32) scp->cmnd[2] << 24) | - ((u32) scp->cmnd[3] << 16) | - ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; - - } - - /* - * Construct SGL - */ - if (instance->flag_ieee) { - ldio->flags |= MFI_FRAME_SGL64; - ldio->sge_count = megasas_make_sgl_skinny(instance, scp, - &ldio->sgl); - } else if (IS_DMA64) { - ldio->flags |= MFI_FRAME_SGL64; - ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl); - } else - ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl); - - if (ldio->sge_count > instance->max_num_sge) { - printk(KERN_ERR "megasas: build_ld_io: sge_count = %x\n", - ldio->sge_count); - return 0; - } - - /* - * Sense info specific - */ - ldio->sense_len = SCSI_SENSE_BUFFERSIZE; - ldio->sense_buf_phys_addr_hi = 0; - ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr; - - /* - * Compute the total number of frames this command consumes. FW uses - * this number to pull sufficient number of frames from host memory. - */ - cmd->frame_count = megasas_get_frame_count(instance, - ldio->sge_count, IO_FRAME); - - return cmd->frame_count; -} - -/** - * megasas_is_ldio - Checks if the cmd is for logical drive - * @scmd: SCSI command - * - * Called by megasas_queue_command to find out if the command to be queued - * is a logical drive command - */ -inline int megasas_is_ldio(struct scsi_cmnd *cmd) -{ - if (!MEGASAS_IS_LOGICAL(cmd)) - return 0; - switch (cmd->cmnd[0]) { - case READ_10: - case WRITE_10: - case READ_12: - case WRITE_12: - case READ_6: - case WRITE_6: - case READ_16: - case WRITE_16: - return 1; - default: - return 0; - } -} - - /** - * megasas_dump_pending_frames - Dumps the frame address of all pending cmds - * in FW - * @instance: Adapter soft state - */ -static inline void -megasas_dump_pending_frames(struct megasas_instance *instance) -{ - struct megasas_cmd *cmd; - int i,n; - union megasas_sgl *mfi_sgl; - struct megasas_io_frame *ldio; - struct megasas_pthru_frame *pthru; - u32 sgcount; - u32 max_cmd = instance->max_fw_cmds; - - printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no); - printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding)); - if (IS_DMA64) - printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no); - else - printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no); - - printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no); - for (i = 0; i < max_cmd; i++) { - cmd = instance->cmd_list[i]; - if(!cmd->scmd) - continue; - printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr); - if (megasas_is_ldio(cmd->scmd)){ - ldio = (struct megasas_io_frame *)cmd->frame; - mfi_sgl = &ldio->sgl; - sgcount = ldio->sge_count; - printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount); - } - else { - pthru = (struct megasas_pthru_frame *) cmd->frame; - mfi_sgl = &pthru->sgl; - sgcount = pthru->sge_count; - printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount); - } - if(megasas_dbg_lvl & MEGASAS_DBG_LVL){ - for (n = 0; n < sgcount; n++){ - if (IS_DMA64) - printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ; - else - printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ; - } - } - printk(KERN_ERR "\n"); - } /*for max_cmd*/ - printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no); - for (i = 0; i < max_cmd; i++) { - - cmd = instance->cmd_list[i]; - - if(cmd->sync_cmd == 1){ - printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr); - } - } - printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no); -} - -u32 -megasas_build_and_issue_cmd(struct megasas_instance *instance, - struct scsi_cmnd *scmd) -{ - struct megasas_cmd *cmd; - u32 frame_count; - - cmd = megasas_get_cmd(instance); - if (!cmd) - return SCSI_MLQUEUE_HOST_BUSY; - - /* - * Logical drive command - */ - if (megasas_is_ldio(scmd)) - frame_count = megasas_build_ldio(instance, scmd, cmd); - else - frame_count = megasas_build_dcdb(instance, scmd, cmd); - - if (!frame_count) - goto out_return_cmd; - - cmd->scmd = scmd; - scmd->SCp.ptr = (char *)cmd; - - /* - * Issue the command to the FW - */ - atomic_inc(&instance->fw_outstanding); - - instance->instancet->fire_cmd(instance, cmd->frame_phys_addr, - cmd->frame_count-1, instance->reg_set); - - return 0; -out_return_cmd: - megasas_return_cmd(instance, cmd); - return 1; -} - - -/** - * megasas_queue_command - Queue entry point - * @scmd: SCSI command to be queued - * @done: Callback entry point - */ -static int -megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) -{ - struct megasas_instance *instance; - unsigned long flags; - - instance = (struct megasas_instance *) - scmd->device->host->hostdata; - - if (instance->issuepend_done == 0) - return SCSI_MLQUEUE_HOST_BUSY; - - spin_lock_irqsave(&instance->hba_lock, flags); - if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { - spin_unlock_irqrestore(&instance->hba_lock, flags); - return SCSI_MLQUEUE_HOST_BUSY; - } - - spin_unlock_irqrestore(&instance->hba_lock, flags); - - scmd->scsi_done = done; - scmd->result = 0; - - if (MEGASAS_IS_LOGICAL(scmd) && - (scmd->device->id >= MEGASAS_MAX_LD || scmd->device->lun)) { - scmd->result = DID_BAD_TARGET << 16; - goto out_done; - } - - switch (scmd->cmnd[0]) { - case SYNCHRONIZE_CACHE: - /* - * FW takes care of flush cache on its own - * No need to send it down - */ - scmd->result = DID_OK << 16; - goto out_done; - default: - break; - } - - if (instance->instancet->build_and_issue_cmd(instance, scmd)) { - printk(KERN_ERR "megasas: Err returned from build_and_issue_cmd\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - - return 0; - - out_done: - done(scmd); - return 0; -} - -static DEF_SCSI_QCMD(megasas_queue_command) - -static struct megasas_instance *megasas_lookup_instance(u16 host_no) -{ - int i; - - for (i = 0; i < megasas_mgmt_info.max_index; i++) { - - if ((megasas_mgmt_info.instance[i]) && - (megasas_mgmt_info.instance[i]->host->host_no == host_no)) - return megasas_mgmt_info.instance[i]; - } - - return NULL; -} - -static int megasas_slave_configure(struct scsi_device *sdev) -{ - u16 pd_index = 0; - struct megasas_instance *instance ; - - instance = megasas_lookup_instance(sdev->host->host_no); - - /* - * Don't export physical disk devices to the disk driver. - * - * FIXME: Currently we don't export them to the midlayer at all. - * That will be fixed once LSI engineers have audited the - * firmware for possible issues. - */ - if (sdev->channel < MEGASAS_MAX_PD_CHANNELS && - sdev->type == TYPE_DISK) { - pd_index = (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + - sdev->id; - if (instance->pd_list[pd_index].driveState == - MR_PD_STATE_SYSTEM) { - blk_queue_rq_timeout(sdev->request_queue, - MEGASAS_DEFAULT_CMD_TIMEOUT * HZ); - return 0; - } - return -ENXIO; - } - - /* - * The RAID firmware may require extended timeouts. - */ - blk_queue_rq_timeout(sdev->request_queue, - MEGASAS_DEFAULT_CMD_TIMEOUT * HZ); - return 0; -} - -static int megasas_slave_alloc(struct scsi_device *sdev) -{ - u16 pd_index = 0; - struct megasas_instance *instance ; - instance = megasas_lookup_instance(sdev->host->host_no); - if ((sdev->channel < MEGASAS_MAX_PD_CHANNELS) && - (sdev->type == TYPE_DISK)) { - /* - * Open the OS scan to the SYSTEM PD - */ - pd_index = - (sdev->channel * MEGASAS_MAX_DEV_PER_CHANNEL) + - sdev->id; - if ((instance->pd_list[pd_index].driveState == - MR_PD_STATE_SYSTEM) && - (instance->pd_list[pd_index].driveType == - TYPE_DISK)) { - return 0; - } - return -ENXIO; - } - return 0; -} - -void megaraid_sas_kill_hba(struct megasas_instance *instance) -{ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) { - writel(MFI_STOP_ADP, &instance->reg_set->doorbell); - } else { - writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell); - } -} - - /** - * megasas_check_and_restore_queue_depth - Check if queue depth needs to be - * restored to max value - * @instance: Adapter soft state - * - */ -void -megasas_check_and_restore_queue_depth(struct megasas_instance *instance) -{ - unsigned long flags; - if (instance->flag & MEGASAS_FW_BUSY - && time_after(jiffies, instance->last_time + 5 * HZ) - && atomic_read(&instance->fw_outstanding) < 17) { - - spin_lock_irqsave(instance->host->host_lock, flags); - instance->flag &= ~MEGASAS_FW_BUSY; - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; - } else - instance->host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; - - spin_unlock_irqrestore(instance->host->host_lock, flags); - } -} - -/** - * megasas_complete_cmd_dpc - Returns FW's controller structure - * @instance_addr: Address of adapter soft state - * - * Tasklet to complete cmds - */ -static void megasas_complete_cmd_dpc(unsigned long instance_addr) -{ - u32 producer; - u32 consumer; - u32 context; - struct megasas_cmd *cmd; - struct megasas_instance *instance = - (struct megasas_instance *)instance_addr; - unsigned long flags; - - /* If we have already declared adapter dead, donot complete cmds */ - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR ) - return; - - spin_lock_irqsave(&instance->completion_lock, flags); - - producer = *instance->producer; - consumer = *instance->consumer; - - while (consumer != producer) { - context = instance->reply_queue[consumer]; - if (context >= instance->max_fw_cmds) { - printk(KERN_ERR "Unexpected context value %x\n", - context); - BUG(); - } - - cmd = instance->cmd_list[context]; - - megasas_complete_cmd(instance, cmd, DID_OK); - - consumer++; - if (consumer == (instance->max_fw_cmds + 1)) { - consumer = 0; - } - } - - *instance->consumer = producer; - - spin_unlock_irqrestore(&instance->completion_lock, flags); - - /* - * Check if we can restore can_queue - */ - megasas_check_and_restore_queue_depth(instance); -} - -static void -megasas_internal_reset_defer_cmds(struct megasas_instance *instance); - -static void -process_fw_state_change_wq(struct work_struct *work); - -void megasas_do_ocr(struct megasas_instance *instance) -{ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || - (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) { - *instance->consumer = MEGASAS_ADPRESET_INPROG_SIGN; - } - instance->instancet->disable_intr(instance->reg_set); - instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; - instance->issuepend_done = 0; - - atomic_set(&instance->fw_outstanding, 0); - megasas_internal_reset_defer_cmds(instance); - process_fw_state_change_wq(&instance->work_init); -} - -/** - * megasas_wait_for_outstanding - Wait for all outstanding cmds - * @instance: Adapter soft state - * - * This function waits for up to MEGASAS_RESET_WAIT_TIME seconds for FW to - * complete all its outstanding commands. Returns error if one or more IOs - * are pending after this time period. It also marks the controller dead. - */ -static int megasas_wait_for_outstanding(struct megasas_instance *instance) -{ - int i; - u32 reset_index; - u32 wait_time = MEGASAS_RESET_WAIT_TIME; - u8 adprecovery; - unsigned long flags; - struct list_head clist_local; - struct megasas_cmd *reset_cmd; - u32 fw_state; - u8 kill_adapter_flag; - - spin_lock_irqsave(&instance->hba_lock, flags); - adprecovery = instance->adprecovery; - spin_unlock_irqrestore(&instance->hba_lock, flags); - - if (adprecovery != MEGASAS_HBA_OPERATIONAL) { - - INIT_LIST_HEAD(&clist_local); - spin_lock_irqsave(&instance->hba_lock, flags); - list_splice_init(&instance->internal_reset_pending_q, - &clist_local); - spin_unlock_irqrestore(&instance->hba_lock, flags); - - printk(KERN_NOTICE "megasas: HBA reset wait ...\n"); - for (i = 0; i < wait_time; i++) { - msleep(1000); - spin_lock_irqsave(&instance->hba_lock, flags); - adprecovery = instance->adprecovery; - spin_unlock_irqrestore(&instance->hba_lock, flags); - if (adprecovery == MEGASAS_HBA_OPERATIONAL) - break; - } - - if (adprecovery != MEGASAS_HBA_OPERATIONAL) { - printk(KERN_NOTICE "megasas: reset: Stopping HBA.\n"); - spin_lock_irqsave(&instance->hba_lock, flags); - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; - spin_unlock_irqrestore(&instance->hba_lock, flags); - return FAILED; - } - - reset_index = 0; - while (!list_empty(&clist_local)) { - reset_cmd = list_entry((&clist_local)->next, - struct megasas_cmd, list); - list_del_init(&reset_cmd->list); - if (reset_cmd->scmd) { - reset_cmd->scmd->result = DID_RESET << 16; - printk(KERN_NOTICE "%d:%p reset [%02x]\n", - reset_index, reset_cmd, - reset_cmd->scmd->cmnd[0]); - - reset_cmd->scmd->scsi_done(reset_cmd->scmd); - megasas_return_cmd(instance, reset_cmd); - } else if (reset_cmd->sync_cmd) { - printk(KERN_NOTICE "megasas:%p synch cmds" - "reset queue\n", - reset_cmd); - - reset_cmd->cmd_status = ENODATA; - instance->instancet->fire_cmd(instance, - reset_cmd->frame_phys_addr, - 0, instance->reg_set); - } else { - printk(KERN_NOTICE "megasas: %p unexpected" - "cmds lst\n", - reset_cmd); - } - reset_index++; - } - - return SUCCESS; - } - - for (i = 0; i < wait_time; i++) { - - int outstanding = atomic_read(&instance->fw_outstanding); - - if (!outstanding) - break; - - if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: [%2d]waiting for %d " - "commands to complete\n",i,outstanding); - /* - * Call cmd completion routine. Cmd to be - * be completed directly without depending on isr. - */ - megasas_complete_cmd_dpc((unsigned long)instance); - } - - msleep(1000); - } - - i = 0; - kill_adapter_flag = 0; - do { - fw_state = instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - if ((fw_state == MFI_STATE_FAULT) && - (instance->disableOnlineCtrlReset == 0)) { - if (i == 3) { - kill_adapter_flag = 2; - break; - } - megasas_do_ocr(instance); - kill_adapter_flag = 1; - - /* wait for 1 secs to let FW finish the pending cmds */ - msleep(1000); - } - i++; - } while (i <= 3); - - if (atomic_read(&instance->fw_outstanding) && - !kill_adapter_flag) { - if (instance->disableOnlineCtrlReset == 0) { - - megasas_do_ocr(instance); - - /* wait for 5 secs to let FW finish the pending cmds */ - for (i = 0; i < wait_time; i++) { - int outstanding = - atomic_read(&instance->fw_outstanding); - if (!outstanding) - return SUCCESS; - msleep(1000); - } - } - } - - if (atomic_read(&instance->fw_outstanding) || - (kill_adapter_flag == 2)) { - printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n"); - /* - * Send signal to FW to stop processing any pending cmds. - * The controller will be taken offline by the OS now. - */ - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { - writel(MFI_STOP_ADP, - &instance->reg_set->doorbell); - } else { - writel(MFI_STOP_ADP, - &instance->reg_set->inbound_doorbell); - } - megasas_dump_pending_frames(instance); - spin_lock_irqsave(&instance->hba_lock, flags); - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; - spin_unlock_irqrestore(&instance->hba_lock, flags); - return FAILED; - } - - printk(KERN_NOTICE "megaraid_sas: no pending cmds after reset\n"); - - return SUCCESS; -} - -/** - * megasas_generic_reset - Generic reset routine - * @scmd: Mid-layer SCSI command - * - * This routine implements a generic reset handler for device, bus and host - * reset requests. Device, bus and host specific reset handlers can use this - * function after they do their specific tasks. - */ -static int megasas_generic_reset(struct scsi_cmnd *scmd) -{ - int ret_val; - struct megasas_instance *instance; - - instance = (struct megasas_instance *)scmd->device->host->hostdata; - - scmd_printk(KERN_NOTICE, scmd, "megasas: RESET cmd=%x retries=%x\n", - scmd->cmnd[0], scmd->retries); - - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { - printk(KERN_ERR "megasas: cannot recover from previous reset " - "failures\n"); - return FAILED; - } - - ret_val = megasas_wait_for_outstanding(instance); - if (ret_val == SUCCESS) - printk(KERN_NOTICE "megasas: reset successful \n"); - else - printk(KERN_ERR "megasas: failed to do reset\n"); - - return ret_val; -} - -/** - * megasas_reset_timer - quiesce the adapter if required - * @scmd: scsi cmnd - * - * Sets the FW busy flag and reduces the host->can_queue if the - * cmd has not been completed within the timeout period. - */ -static enum -blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) -{ - struct megasas_instance *instance; - unsigned long flags; - - if (time_after(jiffies, scmd->jiffies_at_alloc + - (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) { - return BLK_EH_NOT_HANDLED; - } - - instance = (struct megasas_instance *)scmd->device->host->hostdata; - if (!(instance->flag & MEGASAS_FW_BUSY)) { - /* FW is busy, throttle IO */ - spin_lock_irqsave(instance->host->host_lock, flags); - - instance->host->can_queue = 16; - instance->last_time = jiffies; - instance->flag |= MEGASAS_FW_BUSY; - - spin_unlock_irqrestore(instance->host->host_lock, flags); - } - return BLK_EH_RESET_TIMER; -} - -/** - * megasas_reset_device - Device reset handler entry point - */ -static int megasas_reset_device(struct scsi_cmnd *scmd) -{ - int ret; - - /* - * First wait for all commands to complete - */ - ret = megasas_generic_reset(scmd); - - return ret; -} - -/** - * megasas_reset_bus_host - Bus & host reset handler entry point - */ -static int megasas_reset_bus_host(struct scsi_cmnd *scmd) -{ - int ret; - struct megasas_instance *instance; - instance = (struct megasas_instance *)scmd->device->host->hostdata; - - /* - * First wait for all commands to complete - */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) - ret = megasas_reset_fusion(scmd->device->host); - else - ret = megasas_generic_reset(scmd); - - return ret; -} - -/** - * megasas_bios_param - Returns disk geometry for a disk - * @sdev: device handle - * @bdev: block device - * @capacity: drive capacity - * @geom: geometry parameters - */ -static int -megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - int heads; - int sectors; - sector_t cylinders; - unsigned long tmp; - /* Default heads (64) & sectors (32) */ - heads = 64; - sectors = 32; - - tmp = heads * sectors; - cylinders = capacity; - - sector_div(cylinders, tmp); - - /* - * Handle extended translation size for logical drives > 1Gb - */ - - if (capacity >= 0x200000) { - heads = 255; - sectors = 63; - tmp = heads*sectors; - cylinders = capacity; - sector_div(cylinders, tmp); - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return 0; -} - -static void megasas_aen_polling(struct work_struct *work); - -/** - * megasas_service_aen - Processes an event notification - * @instance: Adapter soft state - * @cmd: AEN command completed by the ISR - * - * For AEN, driver sends a command down to FW that is held by the FW till an - * event occurs. When an event of interest occurs, FW completes the command - * that it was previously holding. - * - * This routines sends SIGIO signal to processes that have registered with the - * driver for AEN. - */ -static void -megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) -{ - unsigned long flags; - /* - * Don't signal app if it is just an aborted previously registered aen - */ - if ((!cmd->abort_aen) && (instance->unload == 0)) { - spin_lock_irqsave(&poll_aen_lock, flags); - megasas_poll_wait_aen = 1; - spin_unlock_irqrestore(&poll_aen_lock, flags); - wake_up(&megasas_poll_wait); - kill_fasync(&megasas_async_queue, SIGIO, POLL_IN); - } - else - cmd->abort_aen = 0; - - instance->aen_cmd = NULL; - megasas_return_cmd(instance, cmd); - - if ((instance->unload == 0) && - ((instance->issuepend_done == 1))) { - struct megasas_aen_event *ev; - ev = kzalloc(sizeof(*ev), GFP_ATOMIC); - if (!ev) { - printk(KERN_ERR "megasas_service_aen: out of memory\n"); - } else { - ev->instance = instance; - instance->ev = ev; - INIT_WORK(&ev->hotplug_work, megasas_aen_polling); - schedule_delayed_work( - (struct delayed_work *)&ev->hotplug_work, 0); - } - } -} - -static int megasas_change_queue_depth(struct scsi_device *sdev, - int queue_depth, int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (queue_depth > sdev->host->can_queue) - queue_depth = sdev->host->can_queue; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), - queue_depth); - - return queue_depth; -} - -/* - * Scsi host template for megaraid_sas driver - */ -static struct scsi_host_template megasas_template = { - - .module = THIS_MODULE, - .name = "LSI SAS based MegaRAID driver", - .proc_name = "megaraid_sas", - .slave_configure = megasas_slave_configure, - .slave_alloc = megasas_slave_alloc, - .queuecommand = megasas_queue_command, - .eh_device_reset_handler = megasas_reset_device, - .eh_bus_reset_handler = megasas_reset_bus_host, - .eh_host_reset_handler = megasas_reset_bus_host, - .eh_timed_out = megasas_reset_timer, - .bios_param = megasas_bios_param, - .use_clustering = ENABLE_CLUSTERING, - .change_queue_depth = megasas_change_queue_depth, -}; - -/** - * megasas_complete_int_cmd - Completes an internal command - * @instance: Adapter soft state - * @cmd: Command to be completed - * - * The megasas_issue_blocked_cmd() function waits for a command to complete - * after it issues a command. This function wakes up that waiting routine by - * calling wake_up() on the wait queue. - */ -static void -megasas_complete_int_cmd(struct megasas_instance *instance, - struct megasas_cmd *cmd) -{ - cmd->cmd_status = cmd->frame->io.cmd_status; - - if (cmd->cmd_status == ENODATA) { - cmd->cmd_status = 0; - } - wake_up(&instance->int_cmd_wait_q); -} - -/** - * megasas_complete_abort - Completes aborting a command - * @instance: Adapter soft state - * @cmd: Cmd that was issued to abort another cmd - * - * The megasas_issue_blocked_abort_cmd() function waits on abort_cmd_wait_q - * after it issues an abort on a previously issued command. This function - * wakes up all functions waiting on the same wait queue. - */ -static void -megasas_complete_abort(struct megasas_instance *instance, - struct megasas_cmd *cmd) -{ - if (cmd->sync_cmd) { - cmd->sync_cmd = 0; - cmd->cmd_status = 0; - wake_up(&instance->abort_cmd_wait_q); - } - - return; -} - -/** - * megasas_complete_cmd - Completes a command - * @instance: Adapter soft state - * @cmd: Command to be completed - * @alt_status: If non-zero, use this value as status to - * SCSI mid-layer instead of the value returned - * by the FW. This should be used if caller wants - * an alternate status (as in the case of aborted - * commands) - */ -void -megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, - u8 alt_status) -{ - int exception = 0; - struct megasas_header *hdr = &cmd->frame->hdr; - unsigned long flags; - struct fusion_context *fusion = instance->ctrl_context; - - /* flag for the retry reset */ - cmd->retry_for_fw_reset = 0; - - if (cmd->scmd) - cmd->scmd->SCp.ptr = NULL; - - switch (hdr->cmd) { - case MFI_CMD_INVALID: - /* Some older 1068 controller FW may keep a pended - MR_DCMD_CTRL_EVENT_GET_INFO left over from the main kernel - when booting the kdump kernel. Ignore this command to - prevent a kernel panic on shutdown of the kdump kernel. */ - printk(KERN_WARNING "megaraid_sas: MFI_CMD_INVALID command " - "completed.\n"); - printk(KERN_WARNING "megaraid_sas: If you have a controller " - "other than PERC5, please upgrade your firmware.\n"); - break; - case MFI_CMD_PD_SCSI_IO: - case MFI_CMD_LD_SCSI_IO: - - /* - * MFI_CMD_PD_SCSI_IO and MFI_CMD_LD_SCSI_IO could have been - * issued either through an IO path or an IOCTL path. If it - * was via IOCTL, we will send it to internal completion. - */ - if (cmd->sync_cmd) { - cmd->sync_cmd = 0; - megasas_complete_int_cmd(instance, cmd); - break; - } - - case MFI_CMD_LD_READ: - case MFI_CMD_LD_WRITE: - - if (alt_status) { - cmd->scmd->result = alt_status << 16; - exception = 1; - } - - if (exception) { - - atomic_dec(&instance->fw_outstanding); - - scsi_dma_unmap(cmd->scmd); - cmd->scmd->scsi_done(cmd->scmd); - megasas_return_cmd(instance, cmd); - - break; - } - - switch (hdr->cmd_status) { - - case MFI_STAT_OK: - cmd->scmd->result = DID_OK << 16; - break; - - case MFI_STAT_SCSI_IO_FAILED: - case MFI_STAT_LD_INIT_IN_PROGRESS: - cmd->scmd->result = - (DID_ERROR << 16) | hdr->scsi_status; - break; - - case MFI_STAT_SCSI_DONE_WITH_ERROR: - - cmd->scmd->result = (DID_OK << 16) | hdr->scsi_status; - - if (hdr->scsi_status == SAM_STAT_CHECK_CONDITION) { - memset(cmd->scmd->sense_buffer, 0, - SCSI_SENSE_BUFFERSIZE); - memcpy(cmd->scmd->sense_buffer, cmd->sense, - hdr->sense_len); - - cmd->scmd->result |= DRIVER_SENSE << 24; - } - - break; - - case MFI_STAT_LD_OFFLINE: - case MFI_STAT_DEVICE_NOT_FOUND: - cmd->scmd->result = DID_BAD_TARGET << 16; - break; - - default: - printk(KERN_DEBUG "megasas: MFI FW status %#x\n", - hdr->cmd_status); - cmd->scmd->result = DID_ERROR << 16; - break; - } - - atomic_dec(&instance->fw_outstanding); - - scsi_dma_unmap(cmd->scmd); - cmd->scmd->scsi_done(cmd->scmd); - megasas_return_cmd(instance, cmd); - - break; - - case MFI_CMD_SMP: - case MFI_CMD_STP: - case MFI_CMD_DCMD: - /* Check for LD map update */ - if ((cmd->frame->dcmd.opcode == MR_DCMD_LD_MAP_GET_INFO) && - (cmd->frame->dcmd.mbox.b[1] == 1)) { - spin_lock_irqsave(instance->host->host_lock, flags); - if (cmd->frame->hdr.cmd_status != 0) { - if (cmd->frame->hdr.cmd_status != - MFI_STAT_NOT_FOUND) - printk(KERN_WARNING "megasas: map sync" - "failed, status = 0x%x.\n", - cmd->frame->hdr.cmd_status); - else { - megasas_return_cmd(instance, cmd); - spin_unlock_irqrestore( - instance->host->host_lock, - flags); - break; - } - } else - instance->map_id++; - megasas_return_cmd(instance, cmd); - if (MR_ValidateMapInfo( - fusion->ld_map[(instance->map_id & 1)], - fusion->load_balance_info)) - fusion->fast_path_io = 1; - else - fusion->fast_path_io = 0; - megasas_sync_map_info(instance); - spin_unlock_irqrestore(instance->host->host_lock, - flags); - break; - } - if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET_INFO || - cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_GET) { - spin_lock_irqsave(&poll_aen_lock, flags); - megasas_poll_wait_aen = 0; - spin_unlock_irqrestore(&poll_aen_lock, flags); - } - - /* - * See if got an event notification - */ - if (cmd->frame->dcmd.opcode == MR_DCMD_CTRL_EVENT_WAIT) - megasas_service_aen(instance, cmd); - else - megasas_complete_int_cmd(instance, cmd); - - break; - - case MFI_CMD_ABORT: - /* - * Cmd issued to abort another cmd returned - */ - megasas_complete_abort(instance, cmd); - break; - - default: - printk("megasas: Unknown command completed! [0x%X]\n", - hdr->cmd); - break; - } -} - -/** - * megasas_issue_pending_cmds_again - issue all pending cmds - * in FW again because of the fw reset - * @instance: Adapter soft state - */ -static inline void -megasas_issue_pending_cmds_again(struct megasas_instance *instance) -{ - struct megasas_cmd *cmd; - struct list_head clist_local; - union megasas_evt_class_locale class_locale; - unsigned long flags; - u32 seq_num; - - INIT_LIST_HEAD(&clist_local); - spin_lock_irqsave(&instance->hba_lock, flags); - list_splice_init(&instance->internal_reset_pending_q, &clist_local); - spin_unlock_irqrestore(&instance->hba_lock, flags); - - while (!list_empty(&clist_local)) { - cmd = list_entry((&clist_local)->next, - struct megasas_cmd, list); - list_del_init(&cmd->list); - - if (cmd->sync_cmd || cmd->scmd) { - printk(KERN_NOTICE "megaraid_sas: command %p, %p:%d" - "detected to be pending while HBA reset.\n", - cmd, cmd->scmd, cmd->sync_cmd); - - cmd->retry_for_fw_reset++; - - if (cmd->retry_for_fw_reset == 3) { - printk(KERN_NOTICE "megaraid_sas: cmd %p, %p:%d" - "was tried multiple times during reset." - "Shutting down the HBA\n", - cmd, cmd->scmd, cmd->sync_cmd); - megaraid_sas_kill_hba(instance); - - instance->adprecovery = - MEGASAS_HW_CRITICAL_ERROR; - return; - } - } - - if (cmd->sync_cmd == 1) { - if (cmd->scmd) { - printk(KERN_NOTICE "megaraid_sas: unexpected" - "cmd attached to internal command!\n"); - } - printk(KERN_NOTICE "megasas: %p synchronous cmd" - "on the internal reset queue," - "issue it again.\n", cmd); - cmd->cmd_status = ENODATA; - instance->instancet->fire_cmd(instance, - cmd->frame_phys_addr , - 0, instance->reg_set); - } else if (cmd->scmd) { - printk(KERN_NOTICE "megasas: %p scsi cmd [%02x]" - "detected on the internal queue, issue again.\n", - cmd, cmd->scmd->cmnd[0]); - - atomic_inc(&instance->fw_outstanding); - instance->instancet->fire_cmd(instance, - cmd->frame_phys_addr, - cmd->frame_count-1, instance->reg_set); - } else { - printk(KERN_NOTICE "megasas: %p unexpected cmd on the" - "internal reset defer list while re-issue!!\n", - cmd); - } - } - - if (instance->aen_cmd) { - printk(KERN_NOTICE "megaraid_sas: aen_cmd in def process\n"); - megasas_return_cmd(instance, instance->aen_cmd); - - instance->aen_cmd = NULL; - } - - /* - * Initiate AEN (Asynchronous Event Notification) - */ - seq_num = instance->last_seq_num; - class_locale.members.reserved = 0; - class_locale.members.locale = MR_EVT_LOCALE_ALL; - class_locale.members.class = MR_EVT_CLASS_DEBUG; - - megasas_register_aen(instance, seq_num, class_locale.word); -} - -/** - * Move the internal reset pending commands to a deferred queue. - * - * We move the commands pending at internal reset time to a - * pending queue. This queue would be flushed after successful - * completion of the internal reset sequence. if the internal reset - * did not complete in time, the kernel reset handler would flush - * these commands. - **/ -static void -megasas_internal_reset_defer_cmds(struct megasas_instance *instance) -{ - struct megasas_cmd *cmd; - int i; - u32 max_cmd = instance->max_fw_cmds; - u32 defer_index; - unsigned long flags; - - defer_index = 0; - spin_lock_irqsave(&instance->cmd_pool_lock, flags); - for (i = 0; i < max_cmd; i++) { - cmd = instance->cmd_list[i]; - if (cmd->sync_cmd == 1 || cmd->scmd) { - printk(KERN_NOTICE "megasas: moving cmd[%d]:%p:%d:%p" - "on the defer queue as internal\n", - defer_index, cmd, cmd->sync_cmd, cmd->scmd); - - if (!list_empty(&cmd->list)) { - printk(KERN_NOTICE "megaraid_sas: ERROR while" - " moving this cmd:%p, %d %p, it was" - "discovered on some list?\n", - cmd, cmd->sync_cmd, cmd->scmd); - - list_del_init(&cmd->list); - } - defer_index++; - list_add_tail(&cmd->list, - &instance->internal_reset_pending_q); - } - } - spin_unlock_irqrestore(&instance->cmd_pool_lock, flags); -} - - -static void -process_fw_state_change_wq(struct work_struct *work) -{ - struct megasas_instance *instance = - container_of(work, struct megasas_instance, work_init); - u32 wait; - unsigned long flags; - - if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) { - printk(KERN_NOTICE "megaraid_sas: error, recovery st %x \n", - instance->adprecovery); - return ; - } - - if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) { - printk(KERN_NOTICE "megaraid_sas: FW detected to be in fault" - "state, restarting it...\n"); - - instance->instancet->disable_intr(instance->reg_set); - atomic_set(&instance->fw_outstanding, 0); - - atomic_set(&instance->fw_reset_no_pci_access, 1); - instance->instancet->adp_reset(instance, instance->reg_set); - atomic_set(&instance->fw_reset_no_pci_access, 0 ); - - printk(KERN_NOTICE "megaraid_sas: FW restarted successfully," - "initiating next stage...\n"); - - printk(KERN_NOTICE "megaraid_sas: HBA recovery state machine," - "state 2 starting...\n"); - - /*waitting for about 20 second before start the second init*/ - for (wait = 0; wait < 30; wait++) { - msleep(1000); - } - - if (megasas_transition_to_ready(instance, 1)) { - printk(KERN_NOTICE "megaraid_sas:adapter not ready\n"); - - megaraid_sas_kill_hba(instance); - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; - return ; - } - - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || - (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR) - ) { - *instance->consumer = *instance->producer; - } else { - *instance->consumer = 0; - *instance->producer = 0; - } - - megasas_issue_init_mfi(instance); - - spin_lock_irqsave(&instance->hba_lock, flags); - instance->adprecovery = MEGASAS_HBA_OPERATIONAL; - spin_unlock_irqrestore(&instance->hba_lock, flags); - instance->instancet->enable_intr(instance->reg_set); - - megasas_issue_pending_cmds_again(instance); - instance->issuepend_done = 1; - } - return ; -} - -/** - * megasas_deplete_reply_queue - Processes all completed commands - * @instance: Adapter soft state - * @alt_status: Alternate status to be returned to - * SCSI mid-layer instead of the status - * returned by the FW - * Note: this must be called with hba lock held - */ -static int -megasas_deplete_reply_queue(struct megasas_instance *instance, - u8 alt_status) -{ - u32 mfiStatus; - u32 fw_state; - - if ((mfiStatus = instance->instancet->check_reset(instance, - instance->reg_set)) == 1) { - return IRQ_HANDLED; - } - - if ((mfiStatus = instance->instancet->clear_intr( - instance->reg_set) - ) == 0) { - /* Hardware may not set outbound_intr_status in MSI-X mode */ - if (!instance->msix_vectors) - return IRQ_NONE; - } - - instance->mfiStatus = mfiStatus; - - if ((mfiStatus & MFI_INTR_FLAG_FIRMWARE_STATE_CHANGE)) { - fw_state = instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - - if (fw_state != MFI_STATE_FAULT) { - printk(KERN_NOTICE "megaraid_sas: fw state:%x\n", - fw_state); - } - - if ((fw_state == MFI_STATE_FAULT) && - (instance->disableOnlineCtrlReset == 0)) { - printk(KERN_NOTICE "megaraid_sas: wait adp restart\n"); - - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS1064R) || - (instance->pdev->device == - PCI_DEVICE_ID_DELL_PERC5) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_VERDE_ZCR)) { - - *instance->consumer = - MEGASAS_ADPRESET_INPROG_SIGN; - } - - - instance->instancet->disable_intr(instance->reg_set); - instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; - instance->issuepend_done = 0; - - atomic_set(&instance->fw_outstanding, 0); - megasas_internal_reset_defer_cmds(instance); - - printk(KERN_NOTICE "megasas: fwState=%x, stage:%d\n", - fw_state, instance->adprecovery); - - schedule_work(&instance->work_init); - return IRQ_HANDLED; - - } else { - printk(KERN_NOTICE "megasas: fwstate:%x, dis_OCR=%x\n", - fw_state, instance->disableOnlineCtrlReset); - } - } - - tasklet_schedule(&instance->isr_tasklet); - return IRQ_HANDLED; -} -/** - * megasas_isr - isr entry point - */ -static irqreturn_t megasas_isr(int irq, void *devp) -{ - struct megasas_irq_context *irq_context = devp; - struct megasas_instance *instance = irq_context->instance; - unsigned long flags; - irqreturn_t rc; - - if (atomic_read(&instance->fw_reset_no_pci_access)) - return IRQ_HANDLED; - - spin_lock_irqsave(&instance->hba_lock, flags); - rc = megasas_deplete_reply_queue(instance, DID_OK); - spin_unlock_irqrestore(&instance->hba_lock, flags); - - return rc; -} - -/** - * megasas_transition_to_ready - Move the FW to READY state - * @instance: Adapter soft state - * - * During the initialization, FW passes can potentially be in any one of - * several possible states. If the FW in operational, waiting-for-handshake - * states, driver must take steps to bring it to ready state. Otherwise, it - * has to wait for the ready state. - */ -int -megasas_transition_to_ready(struct megasas_instance *instance, int ocr) -{ - int i; - u8 max_wait; - u32 fw_state; - u32 cur_state; - u32 abs_state, curr_abs_state; - - fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK; - - if (fw_state != MFI_STATE_READY) - printk(KERN_INFO "megasas: Waiting for FW to come to ready" - " state\n"); - - while (fw_state != MFI_STATE_READY) { - - abs_state = - instance->instancet->read_fw_status_reg(instance->reg_set); - - switch (fw_state) { - - case MFI_STATE_FAULT: - printk(KERN_DEBUG "megasas: FW in FAULT state!!\n"); - if (ocr) { - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FAULT; - break; - } else - return -ENODEV; - - case MFI_STATE_WAIT_HANDSHAKE: - /* - * Set the CLR bit in inbound doorbell - */ - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER)) { - writel( - MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, - &instance->reg_set->doorbell); - } else { - writel( - MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG, - &instance->reg_set->inbound_doorbell); - } - - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_WAIT_HANDSHAKE; - break; - - case MFI_STATE_BOOT_MESSAGE_PENDING: - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER)) { - writel(MFI_INIT_HOTPLUG, - &instance->reg_set->doorbell); - } else - writel(MFI_INIT_HOTPLUG, - &instance->reg_set->inbound_doorbell); - - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_BOOT_MESSAGE_PENDING; - break; - - case MFI_STATE_OPERATIONAL: - /* - * Bring it to READY state; assuming max wait 10 secs - */ - instance->instancet->disable_intr(instance->reg_set); - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0071SKINNY) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device - == PCI_DEVICE_ID_LSI_INVADER)) { - writel(MFI_RESET_FLAGS, - &instance->reg_set->doorbell); - if ((instance->pdev->device == - PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER)) { - for (i = 0; i < (10 * 1000); i += 20) { - if (readl( - &instance-> - reg_set-> - doorbell) & 1) - msleep(20); - else - break; - } - } - } else - writel(MFI_RESET_FLAGS, - &instance->reg_set->inbound_doorbell); - - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_OPERATIONAL; - break; - - case MFI_STATE_UNDEFINED: - /* - * This state should not last for more than 2 seconds - */ - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_UNDEFINED; - break; - - case MFI_STATE_BB_INIT: - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_BB_INIT; - break; - - case MFI_STATE_FW_INIT: - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FW_INIT; - break; - - case MFI_STATE_FW_INIT_2: - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FW_INIT_2; - break; - - case MFI_STATE_DEVICE_SCAN: - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_DEVICE_SCAN; - break; - - case MFI_STATE_FLUSH_CACHE: - max_wait = MEGASAS_RESET_WAIT_TIME; - cur_state = MFI_STATE_FLUSH_CACHE; - break; - - default: - printk(KERN_DEBUG "megasas: Unknown state 0x%x\n", - fw_state); - return -ENODEV; - } - - /* - * The cur_state should not last for more than max_wait secs - */ - for (i = 0; i < (max_wait * 1000); i++) { - fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & - MFI_STATE_MASK ; - curr_abs_state = - instance->instancet->read_fw_status_reg(instance->reg_set); - - if (abs_state == curr_abs_state) { - msleep(1); - } else - break; - } - - /* - * Return error if fw_state hasn't changed after max_wait - */ - if (curr_abs_state == abs_state) { - printk(KERN_DEBUG "FW state [%d] hasn't changed " - "in %d secs\n", fw_state, max_wait); - return -ENODEV; - } - } - printk(KERN_INFO "megasas: FW now in Ready state\n"); - - return 0; -} - -/** - * megasas_teardown_frame_pool - Destroy the cmd frame DMA pool - * @instance: Adapter soft state - */ -static void megasas_teardown_frame_pool(struct megasas_instance *instance) -{ - int i; - u32 max_cmd = instance->max_mfi_cmds; - struct megasas_cmd *cmd; - - if (!instance->frame_dma_pool) - return; - - /* - * Return all frames to pool - */ - for (i = 0; i < max_cmd; i++) { - - cmd = instance->cmd_list[i]; - - if (cmd->frame) - pci_pool_free(instance->frame_dma_pool, cmd->frame, - cmd->frame_phys_addr); - - if (cmd->sense) - pci_pool_free(instance->sense_dma_pool, cmd->sense, - cmd->sense_phys_addr); - } - - /* - * Now destroy the pool itself - */ - pci_pool_destroy(instance->frame_dma_pool); - pci_pool_destroy(instance->sense_dma_pool); - - instance->frame_dma_pool = NULL; - instance->sense_dma_pool = NULL; -} - -/** - * megasas_create_frame_pool - Creates DMA pool for cmd frames - * @instance: Adapter soft state - * - * Each command packet has an embedded DMA memory buffer that is used for - * filling MFI frame and the SG list that immediately follows the frame. This - * function creates those DMA memory buffers for each command packet by using - * PCI pool facility. - */ -static int megasas_create_frame_pool(struct megasas_instance *instance) -{ - int i; - u32 max_cmd; - u32 sge_sz; - u32 sgl_sz; - u32 total_sz; - u32 frame_count; - struct megasas_cmd *cmd; - - max_cmd = instance->max_mfi_cmds; - - /* - * Size of our frame is 64 bytes for MFI frame, followed by max SG - * elements and finally SCSI_SENSE_BUFFERSIZE bytes for sense buffer - */ - sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : - sizeof(struct megasas_sge32); - - if (instance->flag_ieee) { - sge_sz = sizeof(struct megasas_sge_skinny); - } - - /* - * Calculated the number of 64byte frames required for SGL - */ - sgl_sz = sge_sz * instance->max_num_sge; - frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE; - frame_count = 15; - - /* - * We need one extra frame for the MFI command - */ - frame_count++; - - total_sz = MEGAMFI_FRAME_SIZE * frame_count; - /* - * Use DMA pool facility provided by PCI layer - */ - instance->frame_dma_pool = pci_pool_create("megasas frame pool", - instance->pdev, total_sz, 64, - 0); - - if (!instance->frame_dma_pool) { - printk(KERN_DEBUG "megasas: failed to setup frame pool\n"); - return -ENOMEM; - } - - instance->sense_dma_pool = pci_pool_create("megasas sense pool", - instance->pdev, 128, 4, 0); - - if (!instance->sense_dma_pool) { - printk(KERN_DEBUG "megasas: failed to setup sense pool\n"); - - pci_pool_destroy(instance->frame_dma_pool); - instance->frame_dma_pool = NULL; - - return -ENOMEM; - } - - /* - * Allocate and attach a frame to each of the commands in cmd_list. - * By making cmd->index as the context instead of the &cmd, we can - * always use 32bit context regardless of the architecture - */ - for (i = 0; i < max_cmd; i++) { - - cmd = instance->cmd_list[i]; - - cmd->frame = pci_pool_alloc(instance->frame_dma_pool, - GFP_KERNEL, &cmd->frame_phys_addr); - - cmd->sense = pci_pool_alloc(instance->sense_dma_pool, - GFP_KERNEL, &cmd->sense_phys_addr); - - /* - * megasas_teardown_frame_pool() takes care of freeing - * whatever has been allocated - */ - if (!cmd->frame || !cmd->sense) { - printk(KERN_DEBUG "megasas: pci_pool_alloc failed \n"); - megasas_teardown_frame_pool(instance); - return -ENOMEM; - } - - memset(cmd->frame, 0, total_sz); - cmd->frame->io.context = cmd->index; - cmd->frame->io.pad_0 = 0; - if ((instance->pdev->device != PCI_DEVICE_ID_LSI_FUSION) && - (instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) && - (reset_devices)) - cmd->frame->hdr.cmd = MFI_CMD_INVALID; - } - - return 0; -} - -/** - * megasas_free_cmds - Free all the cmds in the free cmd pool - * @instance: Adapter soft state - */ -void megasas_free_cmds(struct megasas_instance *instance) -{ - int i; - /* First free the MFI frame pool */ - megasas_teardown_frame_pool(instance); - - /* Free all the commands in the cmd_list */ - for (i = 0; i < instance->max_mfi_cmds; i++) - - kfree(instance->cmd_list[i]); - - /* Free the cmd_list buffer itself */ - kfree(instance->cmd_list); - instance->cmd_list = NULL; - - INIT_LIST_HEAD(&instance->cmd_pool); -} - -/** - * megasas_alloc_cmds - Allocates the command packets - * @instance: Adapter soft state - * - * Each command that is issued to the FW, whether IO commands from the OS or - * internal commands like IOCTLs, are wrapped in local data structure called - * megasas_cmd. The frame embedded in this megasas_cmd is actually issued to - * the FW. - * - * Each frame has a 32-bit field called context (tag). This context is used - * to get back the megasas_cmd from the frame when a frame gets completed in - * the ISR. Typically the address of the megasas_cmd itself would be used as - * the context. But we wanted to keep the differences between 32 and 64 bit - * systems to the mininum. We always use 32 bit integers for the context. In - * this driver, the 32 bit values are the indices into an array cmd_list. - * This array is used only to look up the megasas_cmd given the context. The - * free commands themselves are maintained in a linked list called cmd_pool. - */ -int megasas_alloc_cmds(struct megasas_instance *instance) -{ - int i; - int j; - u32 max_cmd; - struct megasas_cmd *cmd; - - max_cmd = instance->max_mfi_cmds; - - /* - * instance->cmd_list is an array of struct megasas_cmd pointers. - * Allocate the dynamic array first and then allocate individual - * commands. - */ - instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL); - - if (!instance->cmd_list) { - printk(KERN_DEBUG "megasas: out of memory\n"); - return -ENOMEM; - } - - memset(instance->cmd_list, 0, sizeof(struct megasas_cmd *) *max_cmd); - - for (i = 0; i < max_cmd; i++) { - instance->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd), - GFP_KERNEL); - - if (!instance->cmd_list[i]) { - - for (j = 0; j < i; j++) - kfree(instance->cmd_list[j]); - - kfree(instance->cmd_list); - instance->cmd_list = NULL; - - return -ENOMEM; - } - } - - /* - * Add all the commands to command pool (instance->cmd_pool) - */ - for (i = 0; i < max_cmd; i++) { - cmd = instance->cmd_list[i]; - memset(cmd, 0, sizeof(struct megasas_cmd)); - cmd->index = i; - cmd->scmd = NULL; - cmd->instance = instance; - - list_add_tail(&cmd->list, &instance->cmd_pool); - } - - /* - * Create a frame pool and assign one frame to each cmd - */ - if (megasas_create_frame_pool(instance)) { - printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n"); - megasas_free_cmds(instance); - } - - return 0; -} - -/* - * megasas_get_pd_list_info - Returns FW's pd_list structure - * @instance: Adapter soft state - * @pd_list: pd_list structure - * - * Issues an internal command (DCMD) to get the FW's controller PD - * list structure. This information is mainly used to find out SYSTEM - * supported by the FW. - */ -static int -megasas_get_pd_list(struct megasas_instance *instance) -{ - int ret = 0, pd_index = 0; - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - struct MR_PD_LIST *ci; - struct MR_PD_ADDRESS *pd_addr; - dma_addr_t ci_h = 0; - - cmd = megasas_get_cmd(instance); - - if (!cmd) { - printk(KERN_DEBUG "megasas (get_pd_list): Failed to get cmd\n"); - return -ENOMEM; - } - - dcmd = &cmd->frame->dcmd; - - ci = pci_alloc_consistent(instance->pdev, - MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), &ci_h); - - if (!ci) { - printk(KERN_DEBUG "Failed to alloc mem for pd_list\n"); - megasas_return_cmd(instance, cmd); - return -ENOMEM; - } - - memset(ci, 0, sizeof(*ci)); - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - dcmd->mbox.b[0] = MR_PD_QUERY_TYPE_EXPOSED_TO_HOST; - dcmd->mbox.b[1] = 0; - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0xFF; - dcmd->sge_count = 1; - dcmd->flags = MFI_FRAME_DIR_READ; - dcmd->timeout = 0; - dcmd->pad_0 = 0; - dcmd->data_xfer_len = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST); - dcmd->opcode = MR_DCMD_PD_LIST_QUERY; - dcmd->sgl.sge32[0].phys_addr = ci_h; - dcmd->sgl.sge32[0].length = MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST); - - if (!megasas_issue_polled(instance, cmd)) { - ret = 0; - } else { - ret = -1; - } - - /* - * the following function will get the instance PD LIST. - */ - - pd_addr = ci->addr; - - if ( ret == 0 && - (ci->count < - (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) { - - memset(instance->pd_list, 0, - MEGASAS_MAX_PD * sizeof(struct megasas_pd_list)); - - for (pd_index = 0; pd_index < ci->count; pd_index++) { - - instance->pd_list[pd_addr->deviceId].tid = - pd_addr->deviceId; - instance->pd_list[pd_addr->deviceId].driveType = - pd_addr->scsiDevType; - instance->pd_list[pd_addr->deviceId].driveState = - MR_PD_STATE_SYSTEM; - pd_addr++; - } - } - - pci_free_consistent(instance->pdev, - MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), - ci, ci_h); - megasas_return_cmd(instance, cmd); - - return ret; -} - -/* - * megasas_get_ld_list_info - Returns FW's ld_list structure - * @instance: Adapter soft state - * @ld_list: ld_list structure - * - * Issues an internal command (DCMD) to get the FW's controller PD - * list structure. This information is mainly used to find out SYSTEM - * supported by the FW. - */ -static int -megasas_get_ld_list(struct megasas_instance *instance) -{ - int ret = 0, ld_index = 0, ids = 0; - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - struct MR_LD_LIST *ci; - dma_addr_t ci_h = 0; - - cmd = megasas_get_cmd(instance); - - if (!cmd) { - printk(KERN_DEBUG "megasas_get_ld_list: Failed to get cmd\n"); - return -ENOMEM; - } - - dcmd = &cmd->frame->dcmd; - - ci = pci_alloc_consistent(instance->pdev, - sizeof(struct MR_LD_LIST), - &ci_h); - - if (!ci) { - printk(KERN_DEBUG "Failed to alloc mem in get_ld_list\n"); - megasas_return_cmd(instance, cmd); - return -ENOMEM; - } - - memset(ci, 0, sizeof(*ci)); - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0xFF; - dcmd->sge_count = 1; - dcmd->flags = MFI_FRAME_DIR_READ; - dcmd->timeout = 0; - dcmd->data_xfer_len = sizeof(struct MR_LD_LIST); - dcmd->opcode = MR_DCMD_LD_GET_LIST; - dcmd->sgl.sge32[0].phys_addr = ci_h; - dcmd->sgl.sge32[0].length = sizeof(struct MR_LD_LIST); - dcmd->pad_0 = 0; - - if (!megasas_issue_polled(instance, cmd)) { - ret = 0; - } else { - ret = -1; - } - - /* the following function will get the instance PD LIST */ - - if ((ret == 0) && (ci->ldCount <= MAX_LOGICAL_DRIVES)) { - memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); - - for (ld_index = 0; ld_index < ci->ldCount; ld_index++) { - if (ci->ldList[ld_index].state != 0) { - ids = ci->ldList[ld_index].ref.targetId; - instance->ld_ids[ids] = - ci->ldList[ld_index].ref.targetId; - } - } - } - - pci_free_consistent(instance->pdev, - sizeof(struct MR_LD_LIST), - ci, - ci_h); - - megasas_return_cmd(instance, cmd); - return ret; -} - -/** - * megasas_get_controller_info - Returns FW's controller structure - * @instance: Adapter soft state - * @ctrl_info: Controller information structure - * - * Issues an internal command (DCMD) to get the FW's controller structure. - * This information is mainly used to find out the maximum IO transfer per - * command supported by the FW. - */ -static int -megasas_get_ctrl_info(struct megasas_instance *instance, - struct megasas_ctrl_info *ctrl_info) -{ - int ret = 0; - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - struct megasas_ctrl_info *ci; - dma_addr_t ci_h = 0; - - cmd = megasas_get_cmd(instance); - - if (!cmd) { - printk(KERN_DEBUG "megasas: Failed to get a free cmd\n"); - return -ENOMEM; - } - - dcmd = &cmd->frame->dcmd; - - ci = pci_alloc_consistent(instance->pdev, - sizeof(struct megasas_ctrl_info), &ci_h); - - if (!ci) { - printk(KERN_DEBUG "Failed to alloc mem for ctrl info\n"); - megasas_return_cmd(instance, cmd); - return -ENOMEM; - } - - memset(ci, 0, sizeof(*ci)); - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0xFF; - dcmd->sge_count = 1; - dcmd->flags = MFI_FRAME_DIR_READ; - dcmd->timeout = 0; - dcmd->pad_0 = 0; - dcmd->data_xfer_len = sizeof(struct megasas_ctrl_info); - dcmd->opcode = MR_DCMD_CTRL_GET_INFO; - dcmd->sgl.sge32[0].phys_addr = ci_h; - dcmd->sgl.sge32[0].length = sizeof(struct megasas_ctrl_info); - - if (!megasas_issue_polled(instance, cmd)) { - ret = 0; - memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info)); - } else { - ret = -1; - } - - pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info), - ci, ci_h); - - megasas_return_cmd(instance, cmd); - return ret; -} - -/** - * megasas_issue_init_mfi - Initializes the FW - * @instance: Adapter soft state - * - * Issues the INIT MFI cmd - */ -static int -megasas_issue_init_mfi(struct megasas_instance *instance) -{ - u32 context; - - struct megasas_cmd *cmd; - - struct megasas_init_frame *init_frame; - struct megasas_init_queue_info *initq_info; - dma_addr_t init_frame_h; - dma_addr_t initq_info_h; - - /* - * Prepare a init frame. Note the init frame points to queue info - * structure. Each frame has SGL allocated after first 64 bytes. For - * this frame - since we don't need any SGL - we use SGL's space as - * queue info structure - * - * We will not get a NULL command below. We just created the pool. - */ - cmd = megasas_get_cmd(instance); - - init_frame = (struct megasas_init_frame *)cmd->frame; - initq_info = (struct megasas_init_queue_info *) - ((unsigned long)init_frame + 64); - - init_frame_h = cmd->frame_phys_addr; - initq_info_h = init_frame_h + 64; - - context = init_frame->context; - memset(init_frame, 0, MEGAMFI_FRAME_SIZE); - memset(initq_info, 0, sizeof(struct megasas_init_queue_info)); - init_frame->context = context; - - initq_info->reply_queue_entries = instance->max_fw_cmds + 1; - initq_info->reply_queue_start_phys_addr_lo = instance->reply_queue_h; - - initq_info->producer_index_phys_addr_lo = instance->producer_h; - initq_info->consumer_index_phys_addr_lo = instance->consumer_h; - - init_frame->cmd = MFI_CMD_INIT; - init_frame->cmd_status = 0xFF; - init_frame->queue_info_new_phys_addr_lo = initq_info_h; - - init_frame->data_xfer_len = sizeof(struct megasas_init_queue_info); - - /* - * disable the intr before firing the init frame to FW - */ - instance->instancet->disable_intr(instance->reg_set); - - /* - * Issue the init frame in polled mode - */ - - if (megasas_issue_polled(instance, cmd)) { - printk(KERN_ERR "megasas: Failed to init firmware\n"); - megasas_return_cmd(instance, cmd); - goto fail_fw_init; - } - - megasas_return_cmd(instance, cmd); - - return 0; - -fail_fw_init: - return -EINVAL; -} - -static u32 -megasas_init_adapter_mfi(struct megasas_instance *instance) -{ - struct megasas_register_set __iomem *reg_set; - u32 context_sz; - u32 reply_q_sz; - - reg_set = instance->reg_set; - - /* - * Get various operational parameters from status register - */ - instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; - /* - * Reduce the max supported cmds by 1. This is to ensure that the - * reply_q_sz (1 more than the max cmd that driver may send) - * does not exceed max cmds that the FW can support - */ - instance->max_fw_cmds = instance->max_fw_cmds-1; - instance->max_mfi_cmds = instance->max_fw_cmds; - instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >> - 0x10; - /* - * Create a pool of commands - */ - if (megasas_alloc_cmds(instance)) - goto fail_alloc_cmds; - - /* - * Allocate memory for reply queue. Length of reply queue should - * be _one_ more than the maximum commands handled by the firmware. - * - * Note: When FW completes commands, it places corresponding contex - * values in this circular reply queue. This circular queue is a fairly - * typical producer-consumer queue. FW is the producer (of completed - * commands) and the driver is the consumer. - */ - context_sz = sizeof(u32); - reply_q_sz = context_sz * (instance->max_fw_cmds + 1); - - instance->reply_queue = pci_alloc_consistent(instance->pdev, - reply_q_sz, - &instance->reply_queue_h); - - if (!instance->reply_queue) { - printk(KERN_DEBUG "megasas: Out of DMA mem for reply queue\n"); - goto fail_reply_queue; - } - - if (megasas_issue_init_mfi(instance)) - goto fail_fw_init; - - instance->fw_support_ieee = 0; - instance->fw_support_ieee = - (instance->instancet->read_fw_status_reg(reg_set) & - 0x04000000); - - printk(KERN_NOTICE "megasas_init_mfi: fw_support_ieee=%d", - instance->fw_support_ieee); - - if (instance->fw_support_ieee) - instance->flag_ieee = 1; - - return 0; - -fail_fw_init: - - pci_free_consistent(instance->pdev, reply_q_sz, - instance->reply_queue, instance->reply_queue_h); -fail_reply_queue: - megasas_free_cmds(instance); - -fail_alloc_cmds: - return 1; -} - -/** - * megasas_init_fw - Initializes the FW - * @instance: Adapter soft state - * - * This is the main function for initializing firmware - */ - -static int megasas_init_fw(struct megasas_instance *instance) -{ - u32 max_sectors_1; - u32 max_sectors_2; - u32 tmp_sectors, msix_enable; - struct megasas_register_set __iomem *reg_set; - struct megasas_ctrl_info *ctrl_info; - unsigned long bar_list; - int i; - - /* Find first memory bar */ - bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM); - instance->bar = find_first_bit(&bar_list, sizeof(unsigned long)); - instance->base_addr = pci_resource_start(instance->pdev, instance->bar); - if (pci_request_selected_regions(instance->pdev, instance->bar, - "megasas: LSI")) { - printk(KERN_DEBUG "megasas: IO memory region busy!\n"); - return -EBUSY; - } - - instance->reg_set = ioremap_nocache(instance->base_addr, 8192); - - if (!instance->reg_set) { - printk(KERN_DEBUG "megasas: Failed to map IO mem\n"); - goto fail_ioremap; - } - - reg_set = instance->reg_set; - - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_INVADER: - instance->instancet = &megasas_instance_template_fusion; - break; - case PCI_DEVICE_ID_LSI_SAS1078R: - case PCI_DEVICE_ID_LSI_SAS1078DE: - instance->instancet = &megasas_instance_template_ppc; - break; - case PCI_DEVICE_ID_LSI_SAS1078GEN2: - case PCI_DEVICE_ID_LSI_SAS0079GEN2: - instance->instancet = &megasas_instance_template_gen2; - break; - case PCI_DEVICE_ID_LSI_SAS0073SKINNY: - case PCI_DEVICE_ID_LSI_SAS0071SKINNY: - instance->instancet = &megasas_instance_template_skinny; - break; - case PCI_DEVICE_ID_LSI_SAS1064R: - case PCI_DEVICE_ID_DELL_PERC5: - default: - instance->instancet = &megasas_instance_template_xscale; - break; - } - - /* - * We expect the FW state to be READY - */ - if (megasas_transition_to_ready(instance, 0)) - goto fail_ready_state; - - /* Check if MSI-X is supported while in ready state */ - msix_enable = (instance->instancet->read_fw_status_reg(reg_set) & - 0x4000000) >> 0x1a; - if (msix_enable && !msix_disable) { - /* Check max MSI-X vectors */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) { - instance->msix_vectors = (readl(&instance->reg_set-> - outbound_scratch_pad_2 - ) & 0x1F) + 1; - } else - instance->msix_vectors = 1; - /* Don't bother allocating more MSI-X vectors than cpus */ - instance->msix_vectors = min(instance->msix_vectors, - (unsigned int)num_online_cpus()); - for (i = 0; i < instance->msix_vectors; i++) - instance->msixentry[i].entry = i; - i = pci_enable_msix(instance->pdev, instance->msixentry, - instance->msix_vectors); - if (i >= 0) { - if (i) { - if (!pci_enable_msix(instance->pdev, - instance->msixentry, i)) - instance->msix_vectors = i; - else - instance->msix_vectors = 0; - } - } else - instance->msix_vectors = 0; - } - - /* Get operational params, sge flags, send init cmd to controller */ - if (instance->instancet->init_adapter(instance)) - goto fail_init_adapter; - - printk(KERN_ERR "megasas: INIT adapter done\n"); - - /** for passthrough - * the following function will get the PD LIST. - */ - - memset(instance->pd_list, 0 , - (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list))); - megasas_get_pd_list(instance); - - memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS); - megasas_get_ld_list(instance); - - ctrl_info = kmalloc(sizeof(struct megasas_ctrl_info), GFP_KERNEL); - - /* - * Compute the max allowed sectors per IO: The controller info has two - * limits on max sectors. Driver should use the minimum of these two. - * - * 1 << stripe_sz_ops.min = max sectors per strip - * - * Note that older firmwares ( < FW ver 30) didn't report information - * to calculate max_sectors_1. So the number ended up as zero always. - */ - tmp_sectors = 0; - if (ctrl_info && !megasas_get_ctrl_info(instance, ctrl_info)) { - - max_sectors_1 = (1 << ctrl_info->stripe_sz_ops.min) * - ctrl_info->max_strips_per_io; - max_sectors_2 = ctrl_info->max_request_size; - - tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2); - instance->disableOnlineCtrlReset = - ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; - } - - instance->max_sectors_per_req = instance->max_num_sge * - PAGE_SIZE / 512; - if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors)) - instance->max_sectors_per_req = tmp_sectors; - - kfree(ctrl_info); - - /* - * Setup tasklet for cmd completion - */ - - tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, - (unsigned long)instance); - - return 0; - -fail_init_adapter: -fail_ready_state: - iounmap(instance->reg_set); - - fail_ioremap: - pci_release_selected_regions(instance->pdev, instance->bar); - - return -EINVAL; -} - -/** - * megasas_release_mfi - Reverses the FW initialization - * @intance: Adapter soft state - */ -static void megasas_release_mfi(struct megasas_instance *instance) -{ - u32 reply_q_sz = sizeof(u32) *(instance->max_mfi_cmds + 1); - - if (instance->reply_queue) - pci_free_consistent(instance->pdev, reply_q_sz, - instance->reply_queue, instance->reply_queue_h); - - megasas_free_cmds(instance); - - iounmap(instance->reg_set); - - pci_release_selected_regions(instance->pdev, instance->bar); -} - -/** - * megasas_get_seq_num - Gets latest event sequence numbers - * @instance: Adapter soft state - * @eli: FW event log sequence numbers information - * - * FW maintains a log of all events in a non-volatile area. Upper layers would - * usually find out the latest sequence number of the events, the seq number at - * the boot etc. They would "read" all the events below the latest seq number - * by issuing a direct fw cmd (DCMD). For the future events (beyond latest seq - * number), they would subsribe to AEN (asynchronous event notification) and - * wait for the events to happen. - */ -static int -megasas_get_seq_num(struct megasas_instance *instance, - struct megasas_evt_log_info *eli) -{ - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - struct megasas_evt_log_info *el_info; - dma_addr_t el_info_h = 0; - - cmd = megasas_get_cmd(instance); - - if (!cmd) { - return -ENOMEM; - } - - dcmd = &cmd->frame->dcmd; - el_info = pci_alloc_consistent(instance->pdev, - sizeof(struct megasas_evt_log_info), - &el_info_h); - - if (!el_info) { - megasas_return_cmd(instance, cmd); - return -ENOMEM; - } - - memset(el_info, 0, sizeof(*el_info)); - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0x0; - dcmd->sge_count = 1; - dcmd->flags = MFI_FRAME_DIR_READ; - dcmd->timeout = 0; - dcmd->pad_0 = 0; - dcmd->data_xfer_len = sizeof(struct megasas_evt_log_info); - dcmd->opcode = MR_DCMD_CTRL_EVENT_GET_INFO; - dcmd->sgl.sge32[0].phys_addr = el_info_h; - dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_log_info); - - megasas_issue_blocked_cmd(instance, cmd); - - /* - * Copy the data back into callers buffer - */ - memcpy(eli, el_info, sizeof(struct megasas_evt_log_info)); - - pci_free_consistent(instance->pdev, sizeof(struct megasas_evt_log_info), - el_info, el_info_h); - - megasas_return_cmd(instance, cmd); - - return 0; -} - -/** - * megasas_register_aen - Registers for asynchronous event notification - * @instance: Adapter soft state - * @seq_num: The starting sequence number - * @class_locale: Class of the event - * - * This function subscribes for AEN for events beyond the @seq_num. It requests - * to be notified if and only if the event is of type @class_locale - */ -static int -megasas_register_aen(struct megasas_instance *instance, u32 seq_num, - u32 class_locale_word) -{ - int ret_val; - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - union megasas_evt_class_locale curr_aen; - union megasas_evt_class_locale prev_aen; - - /* - * If there an AEN pending already (aen_cmd), check if the - * class_locale of that pending AEN is inclusive of the new - * AEN request we currently have. If it is, then we don't have - * to do anything. In other words, whichever events the current - * AEN request is subscribing to, have already been subscribed - * to. - * - * If the old_cmd is _not_ inclusive, then we have to abort - * that command, form a class_locale that is superset of both - * old and current and re-issue to the FW - */ - - curr_aen.word = class_locale_word; - - if (instance->aen_cmd) { - - prev_aen.word = instance->aen_cmd->frame->dcmd.mbox.w[1]; - - /* - * A class whose enum value is smaller is inclusive of all - * higher values. If a PROGRESS (= -1) was previously - * registered, then a new registration requests for higher - * classes need not be sent to FW. They are automatically - * included. - * - * Locale numbers don't have such hierarchy. They are bitmap - * values - */ - if ((prev_aen.members.class <= curr_aen.members.class) && - !((prev_aen.members.locale & curr_aen.members.locale) ^ - curr_aen.members.locale)) { - /* - * Previously issued event registration includes - * current request. Nothing to do. - */ - return 0; - } else { - curr_aen.members.locale |= prev_aen.members.locale; - - if (prev_aen.members.class < curr_aen.members.class) - curr_aen.members.class = prev_aen.members.class; - - instance->aen_cmd->abort_aen = 1; - ret_val = megasas_issue_blocked_abort_cmd(instance, - instance-> - aen_cmd); - - if (ret_val) { - printk(KERN_DEBUG "megasas: Failed to abort " - "previous AEN command\n"); - return ret_val; - } - } - } - - cmd = megasas_get_cmd(instance); - - if (!cmd) - return -ENOMEM; - - dcmd = &cmd->frame->dcmd; - - memset(instance->evt_detail, 0, sizeof(struct megasas_evt_detail)); - - /* - * Prepare DCMD for aen registration - */ - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0x0; - dcmd->sge_count = 1; - dcmd->flags = MFI_FRAME_DIR_READ; - dcmd->timeout = 0; - dcmd->pad_0 = 0; - instance->last_seq_num = seq_num; - dcmd->data_xfer_len = sizeof(struct megasas_evt_detail); - dcmd->opcode = MR_DCMD_CTRL_EVENT_WAIT; - dcmd->mbox.w[0] = seq_num; - dcmd->mbox.w[1] = curr_aen.word; - dcmd->sgl.sge32[0].phys_addr = (u32) instance->evt_detail_h; - dcmd->sgl.sge32[0].length = sizeof(struct megasas_evt_detail); - - if (instance->aen_cmd != NULL) { - megasas_return_cmd(instance, cmd); - return 0; - } - - /* - * Store reference to the cmd used to register for AEN. When an - * application wants us to register for AEN, we have to abort this - * cmd and re-register with a new EVENT LOCALE supplied by that app - */ - instance->aen_cmd = cmd; - - /* - * Issue the aen registration frame - */ - instance->instancet->issue_dcmd(instance, cmd); - - return 0; -} - -/** - * megasas_start_aen - Subscribes to AEN during driver load time - * @instance: Adapter soft state - */ -static int megasas_start_aen(struct megasas_instance *instance) -{ - struct megasas_evt_log_info eli; - union megasas_evt_class_locale class_locale; - - /* - * Get the latest sequence number from FW - */ - memset(&eli, 0, sizeof(eli)); - - if (megasas_get_seq_num(instance, &eli)) - return -1; - - /* - * Register AEN with FW for latest sequence number plus 1 - */ - class_locale.members.reserved = 0; - class_locale.members.locale = MR_EVT_LOCALE_ALL; - class_locale.members.class = MR_EVT_CLASS_DEBUG; - - return megasas_register_aen(instance, eli.newest_seq_num + 1, - class_locale.word); -} - -/** - * megasas_io_attach - Attaches this driver to SCSI mid-layer - * @instance: Adapter soft state - */ -static int megasas_io_attach(struct megasas_instance *instance) -{ - struct Scsi_Host *host = instance->host; - - /* - * Export parameters required by SCSI mid-layer - */ - host->irq = instance->pdev->irq; - host->unique_id = instance->unique_id; - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { - host->can_queue = - instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS; - } else - host->can_queue = - instance->max_fw_cmds - MEGASAS_INT_CMDS; - host->this_id = instance->init_id; - host->sg_tablesize = instance->max_num_sge; - - if (instance->fw_support_ieee) - instance->max_sectors_per_req = MEGASAS_MAX_SECTORS_IEEE; - - /* - * Check if the module parameter value for max_sectors can be used - */ - if (max_sectors && max_sectors < instance->max_sectors_per_req) - instance->max_sectors_per_req = max_sectors; - else { - if (max_sectors) { - if (((instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS1078GEN2) || - (instance->pdev->device == - PCI_DEVICE_ID_LSI_SAS0079GEN2)) && - (max_sectors <= MEGASAS_MAX_SECTORS)) { - instance->max_sectors_per_req = max_sectors; - } else { - printk(KERN_INFO "megasas: max_sectors should be > 0" - "and <= %d (or < 1MB for GEN2 controller)\n", - instance->max_sectors_per_req); - } - } - } - - host->max_sectors = instance->max_sectors_per_req; - host->cmd_per_lun = MEGASAS_DEFAULT_CMD_PER_LUN; - host->max_channel = MEGASAS_MAX_CHANNELS - 1; - host->max_id = MEGASAS_MAX_DEV_PER_CHANNEL; - host->max_lun = MEGASAS_MAX_LUN; - host->max_cmd_len = 16; - - /* Fusion only supports host reset */ - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) { - host->hostt->eh_device_reset_handler = NULL; - host->hostt->eh_bus_reset_handler = NULL; - } - - /* - * Notify the mid-layer about the new controller - */ - if (scsi_add_host(host, &instance->pdev->dev)) { - printk(KERN_DEBUG "megasas: scsi_add_host failed\n"); - return -ENODEV; - } - - /* - * Trigger SCSI to scan our drives - */ - scsi_scan_host(host); - return 0; -} - -static int -megasas_set_dma_mask(struct pci_dev *pdev) -{ - /* - * All our contollers are capable of performing 64-bit DMA - */ - if (IS_DMA64) { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { - - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) - goto fail_set_dma_mask; - } - } else { - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) - goto fail_set_dma_mask; - } - return 0; - -fail_set_dma_mask: - return 1; -} - -/** - * megasas_probe_one - PCI hotplug entry point - * @pdev: PCI device structure - * @id: PCI ids of supported hotplugged adapter - */ -static int __devinit -megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int rval, pos, i, j; - struct Scsi_Host *host; - struct megasas_instance *instance; - u16 control = 0; - - /* Reset MSI-X in the kdump kernel */ - if (reset_devices) { - pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX); - if (pos) { - pci_read_config_word(pdev, msi_control_reg(pos), - &control); - if (control & PCI_MSIX_FLAGS_ENABLE) { - dev_info(&pdev->dev, "resetting MSI-X\n"); - pci_write_config_word(pdev, - msi_control_reg(pos), - control & - ~PCI_MSIX_FLAGS_ENABLE); - } - } - } - - /* - * Announce PCI information - */ - printk(KERN_INFO "megasas: %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", - pdev->vendor, pdev->device, pdev->subsystem_vendor, - pdev->subsystem_device); - - printk("bus %d:slot %d:func %d\n", - pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); - - /* - * PCI prepping: enable device set bus mastering and dma mask - */ - rval = pci_enable_device_mem(pdev); - - if (rval) { - return rval; - } - - pci_set_master(pdev); - - if (megasas_set_dma_mask(pdev)) - goto fail_set_dma_mask; - - host = scsi_host_alloc(&megasas_template, - sizeof(struct megasas_instance)); - - if (!host) { - printk(KERN_DEBUG "megasas: scsi_host_alloc failed\n"); - goto fail_alloc_instance; - } - - instance = (struct megasas_instance *)host->hostdata; - memset(instance, 0, sizeof(*instance)); - atomic_set( &instance->fw_reset_no_pci_access, 0 ); - instance->pdev = pdev; - - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_INVADER: - { - struct fusion_context *fusion; - - instance->ctrl_context = - kzalloc(sizeof(struct fusion_context), GFP_KERNEL); - if (!instance->ctrl_context) { - printk(KERN_DEBUG "megasas: Failed to allocate " - "memory for Fusion context info\n"); - goto fail_alloc_dma_buf; - } - fusion = instance->ctrl_context; - INIT_LIST_HEAD(&fusion->cmd_pool); - spin_lock_init(&fusion->cmd_pool_lock); - } - break; - default: /* For all other supported controllers */ - - instance->producer = - pci_alloc_consistent(pdev, sizeof(u32), - &instance->producer_h); - instance->consumer = - pci_alloc_consistent(pdev, sizeof(u32), - &instance->consumer_h); - - if (!instance->producer || !instance->consumer) { - printk(KERN_DEBUG "megasas: Failed to allocate" - "memory for producer, consumer\n"); - goto fail_alloc_dma_buf; - } - - *instance->producer = 0; - *instance->consumer = 0; - break; - } - - megasas_poll_wait_aen = 0; - instance->flag_ieee = 0; - instance->ev = NULL; - instance->issuepend_done = 1; - instance->adprecovery = MEGASAS_HBA_OPERATIONAL; - megasas_poll_wait_aen = 0; - - instance->evt_detail = pci_alloc_consistent(pdev, - sizeof(struct - megasas_evt_detail), - &instance->evt_detail_h); - - if (!instance->evt_detail) { - printk(KERN_DEBUG "megasas: Failed to allocate memory for " - "event detail structure\n"); - goto fail_alloc_dma_buf; - } - - /* - * Initialize locks and queues - */ - INIT_LIST_HEAD(&instance->cmd_pool); - INIT_LIST_HEAD(&instance->internal_reset_pending_q); - - atomic_set(&instance->fw_outstanding,0); - - init_waitqueue_head(&instance->int_cmd_wait_q); - init_waitqueue_head(&instance->abort_cmd_wait_q); - - spin_lock_init(&instance->cmd_pool_lock); - spin_lock_init(&instance->hba_lock); - spin_lock_init(&instance->completion_lock); - spin_lock_init(&poll_aen_lock); - - mutex_init(&instance->aen_mutex); - mutex_init(&instance->reset_mutex); - - /* - * Initialize PCI related and misc parameters - */ - instance->host = host; - instance->unique_id = pdev->bus->number << 8 | pdev->devfn; - instance->init_id = MEGASAS_DEFAULT_INIT_ID; - - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) { - instance->flag_ieee = 1; - sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS); - } else - sema_init(&instance->ioctl_sem, MEGASAS_INT_CMDS); - - megasas_dbg_lvl = 0; - instance->flag = 0; - instance->unload = 1; - instance->last_time = 0; - instance->disableOnlineCtrlReset = 1; - - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) - INIT_WORK(&instance->work_init, megasas_fusion_ocr_wq); - else - INIT_WORK(&instance->work_init, process_fw_state_change_wq); - - /* - * Initialize MFI Firmware - */ - if (megasas_init_fw(instance)) - goto fail_init_mfi; - - /* - * Register IRQ - */ - if (instance->msix_vectors) { - for (i = 0 ; i < instance->msix_vectors; i++) { - instance->irq_context[i].instance = instance; - instance->irq_context[i].MSIxIndex = i; - if (request_irq(instance->msixentry[i].vector, - instance->instancet->service_isr, 0, - "megasas", - &instance->irq_context[i])) { - printk(KERN_DEBUG "megasas: Failed to " - "register IRQ for vector %d.\n", i); - for (j = 0 ; j < i ; j++) - free_irq( - instance->msixentry[j].vector, - &instance->irq_context[j]); - goto fail_irq; - } - } - } else { - instance->irq_context[0].instance = instance; - instance->irq_context[0].MSIxIndex = 0; - if (request_irq(pdev->irq, instance->instancet->service_isr, - IRQF_SHARED, "megasas", - &instance->irq_context[0])) { - printk(KERN_DEBUG "megasas: Failed to register IRQ\n"); - goto fail_irq; - } - } - - instance->instancet->enable_intr(instance->reg_set); - - /* - * Store instance in PCI softstate - */ - pci_set_drvdata(pdev, instance); - - /* - * Add this controller to megasas_mgmt_info structure so that it - * can be exported to management applications - */ - megasas_mgmt_info.count++; - megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = instance; - megasas_mgmt_info.max_index++; - - /* - * Register with SCSI mid-layer - */ - if (megasas_io_attach(instance)) - goto fail_io_attach; - - instance->unload = 0; - - /* - * Initiate AEN (Asynchronous Event Notification) - */ - if (megasas_start_aen(instance)) { - printk(KERN_DEBUG "megasas: start aen failed\n"); - goto fail_start_aen; - } - - return 0; - - fail_start_aen: - fail_io_attach: - megasas_mgmt_info.count--; - megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL; - megasas_mgmt_info.max_index--; - - pci_set_drvdata(pdev, NULL); - instance->instancet->disable_intr(instance->reg_set); - if (instance->msix_vectors) - for (i = 0 ; i < instance->msix_vectors; i++) - free_irq(instance->msixentry[i].vector, - &instance->irq_context[i]); - else - free_irq(instance->pdev->irq, &instance->irq_context[0]); -fail_irq: - if ((instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER)) - megasas_release_fusion(instance); - else - megasas_release_mfi(instance); - fail_init_mfi: - if (instance->msix_vectors) - pci_disable_msix(instance->pdev); - fail_alloc_dma_buf: - if (instance->evt_detail) - pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), - instance->evt_detail, - instance->evt_detail_h); - - if (instance->producer) - pci_free_consistent(pdev, sizeof(u32), instance->producer, - instance->producer_h); - if (instance->consumer) - pci_free_consistent(pdev, sizeof(u32), instance->consumer, - instance->consumer_h); - scsi_host_put(host); - - fail_alloc_instance: - fail_set_dma_mask: - pci_disable_device(pdev); - - return -ENODEV; -} - -/** - * megasas_flush_cache - Requests FW to flush all its caches - * @instance: Adapter soft state - */ -static void megasas_flush_cache(struct megasas_instance *instance) -{ - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) - return; - - cmd = megasas_get_cmd(instance); - - if (!cmd) - return; - - dcmd = &cmd->frame->dcmd; - - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0x0; - dcmd->sge_count = 0; - dcmd->flags = MFI_FRAME_DIR_NONE; - dcmd->timeout = 0; - dcmd->pad_0 = 0; - dcmd->data_xfer_len = 0; - dcmd->opcode = MR_DCMD_CTRL_CACHE_FLUSH; - dcmd->mbox.b[0] = MR_FLUSH_CTRL_CACHE | MR_FLUSH_DISK_CACHE; - - megasas_issue_blocked_cmd(instance, cmd); - - megasas_return_cmd(instance, cmd); - - return; -} - -/** - * megasas_shutdown_controller - Instructs FW to shutdown the controller - * @instance: Adapter soft state - * @opcode: Shutdown/Hibernate - */ -static void megasas_shutdown_controller(struct megasas_instance *instance, - u32 opcode) -{ - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) - return; - - cmd = megasas_get_cmd(instance); - - if (!cmd) - return; - - if (instance->aen_cmd) - megasas_issue_blocked_abort_cmd(instance, instance->aen_cmd); - if (instance->map_update_cmd) - megasas_issue_blocked_abort_cmd(instance, - instance->map_update_cmd); - dcmd = &cmd->frame->dcmd; - - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0x0; - dcmd->sge_count = 0; - dcmd->flags = MFI_FRAME_DIR_NONE; - dcmd->timeout = 0; - dcmd->pad_0 = 0; - dcmd->data_xfer_len = 0; - dcmd->opcode = opcode; - - megasas_issue_blocked_cmd(instance, cmd); - - megasas_return_cmd(instance, cmd); - - return; -} - -#ifdef CONFIG_PM -/** - * megasas_suspend - driver suspend entry point - * @pdev: PCI device structure - * @state: PCI power state to suspend routine - */ -static int -megasas_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct Scsi_Host *host; - struct megasas_instance *instance; - int i; - - instance = pci_get_drvdata(pdev); - host = instance->host; - instance->unload = 1; - - megasas_flush_cache(instance); - megasas_shutdown_controller(instance, MR_DCMD_HIBERNATE_SHUTDOWN); - - /* cancel the delayed work if this work still in queue */ - if (instance->ev != NULL) { - struct megasas_aen_event *ev = instance->ev; - cancel_delayed_work_sync( - (struct delayed_work *)&ev->hotplug_work); - instance->ev = NULL; - } - - tasklet_kill(&instance->isr_tasklet); - - pci_set_drvdata(instance->pdev, instance); - instance->instancet->disable_intr(instance->reg_set); - - if (instance->msix_vectors) - for (i = 0 ; i < instance->msix_vectors; i++) - free_irq(instance->msixentry[i].vector, - &instance->irq_context[i]); - else - free_irq(instance->pdev->irq, &instance->irq_context[0]); - if (instance->msix_vectors) - pci_disable_msix(instance->pdev); - - pci_save_state(pdev); - pci_disable_device(pdev); - - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -/** - * megasas_resume- driver resume entry point - * @pdev: PCI device structure - */ -static int -megasas_resume(struct pci_dev *pdev) -{ - int rval, i, j; - struct Scsi_Host *host; - struct megasas_instance *instance; - - instance = pci_get_drvdata(pdev); - host = instance->host; - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - /* - * PCI prepping: enable device set bus mastering and dma mask - */ - rval = pci_enable_device_mem(pdev); - - if (rval) { - printk(KERN_ERR "megasas: Enable device failed\n"); - return rval; - } - - pci_set_master(pdev); - - if (megasas_set_dma_mask(pdev)) - goto fail_set_dma_mask; - - /* - * Initialize MFI Firmware - */ - - atomic_set(&instance->fw_outstanding, 0); - - /* - * We expect the FW state to be READY - */ - if (megasas_transition_to_ready(instance, 0)) - goto fail_ready_state; - - /* Now re-enable MSI-X */ - if (instance->msix_vectors) - pci_enable_msix(instance->pdev, instance->msixentry, - instance->msix_vectors); - - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_INVADER: - { - megasas_reset_reply_desc(instance); - if (megasas_ioc_init_fusion(instance)) { - megasas_free_cmds(instance); - megasas_free_cmds_fusion(instance); - goto fail_init_mfi; - } - if (!megasas_get_map_info(instance)) - megasas_sync_map_info(instance); - } - break; - default: - *instance->producer = 0; - *instance->consumer = 0; - if (megasas_issue_init_mfi(instance)) - goto fail_init_mfi; - break; - } - - tasklet_init(&instance->isr_tasklet, instance->instancet->tasklet, - (unsigned long)instance); - - /* - * Register IRQ - */ - if (instance->msix_vectors) { - for (i = 0 ; i < instance->msix_vectors; i++) { - instance->irq_context[i].instance = instance; - instance->irq_context[i].MSIxIndex = i; - if (request_irq(instance->msixentry[i].vector, - instance->instancet->service_isr, 0, - "megasas", - &instance->irq_context[i])) { - printk(KERN_DEBUG "megasas: Failed to " - "register IRQ for vector %d.\n", i); - for (j = 0 ; j < i ; j++) - free_irq( - instance->msixentry[j].vector, - &instance->irq_context[j]); - goto fail_irq; - } - } - } else { - instance->irq_context[0].instance = instance; - instance->irq_context[0].MSIxIndex = 0; - if (request_irq(pdev->irq, instance->instancet->service_isr, - IRQF_SHARED, "megasas", - &instance->irq_context[0])) { - printk(KERN_DEBUG "megasas: Failed to register IRQ\n"); - goto fail_irq; - } - } - - instance->instancet->enable_intr(instance->reg_set); - instance->unload = 0; - - /* - * Initiate AEN (Asynchronous Event Notification) - */ - if (megasas_start_aen(instance)) - printk(KERN_ERR "megasas: Start AEN failed\n"); - - return 0; - -fail_irq: -fail_init_mfi: - if (instance->evt_detail) - pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), - instance->evt_detail, - instance->evt_detail_h); - - if (instance->producer) - pci_free_consistent(pdev, sizeof(u32), instance->producer, - instance->producer_h); - if (instance->consumer) - pci_free_consistent(pdev, sizeof(u32), instance->consumer, - instance->consumer_h); - scsi_host_put(host); - -fail_set_dma_mask: -fail_ready_state: - - pci_disable_device(pdev); - - return -ENODEV; -} -#else -#define megasas_suspend NULL -#define megasas_resume NULL -#endif - -/** - * megasas_detach_one - PCI hot"un"plug entry point - * @pdev: PCI device structure - */ -static void __devexit megasas_detach_one(struct pci_dev *pdev) -{ - int i; - struct Scsi_Host *host; - struct megasas_instance *instance; - struct fusion_context *fusion; - - instance = pci_get_drvdata(pdev); - instance->unload = 1; - host = instance->host; - fusion = instance->ctrl_context; - - scsi_remove_host(instance->host); - megasas_flush_cache(instance); - megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); - - /* cancel the delayed work if this work still in queue*/ - if (instance->ev != NULL) { - struct megasas_aen_event *ev = instance->ev; - cancel_delayed_work_sync( - (struct delayed_work *)&ev->hotplug_work); - instance->ev = NULL; - } - - tasklet_kill(&instance->isr_tasklet); - - /* - * Take the instance off the instance array. Note that we will not - * decrement the max_index. We let this array be sparse array - */ - for (i = 0; i < megasas_mgmt_info.max_index; i++) { - if (megasas_mgmt_info.instance[i] == instance) { - megasas_mgmt_info.count--; - megasas_mgmt_info.instance[i] = NULL; - - break; - } - } - - pci_set_drvdata(instance->pdev, NULL); - - instance->instancet->disable_intr(instance->reg_set); - - if (instance->msix_vectors) - for (i = 0 ; i < instance->msix_vectors; i++) - free_irq(instance->msixentry[i].vector, - &instance->irq_context[i]); - else - free_irq(instance->pdev->irq, &instance->irq_context[0]); - if (instance->msix_vectors) - pci_disable_msix(instance->pdev); - - switch (instance->pdev->device) { - case PCI_DEVICE_ID_LSI_FUSION: - case PCI_DEVICE_ID_LSI_INVADER: - megasas_release_fusion(instance); - for (i = 0; i < 2 ; i++) - if (fusion->ld_map[i]) - dma_free_coherent(&instance->pdev->dev, - fusion->map_sz, - fusion->ld_map[i], - fusion-> - ld_map_phys[i]); - kfree(instance->ctrl_context); - break; - default: - megasas_release_mfi(instance); - pci_free_consistent(pdev, - sizeof(struct megasas_evt_detail), - instance->evt_detail, - instance->evt_detail_h); - pci_free_consistent(pdev, sizeof(u32), - instance->producer, - instance->producer_h); - pci_free_consistent(pdev, sizeof(u32), - instance->consumer, - instance->consumer_h); - break; - } - - scsi_host_put(host); - - pci_set_drvdata(pdev, NULL); - - pci_disable_device(pdev); - - return; -} - -/** - * megasas_shutdown - Shutdown entry point - * @device: Generic device structure - */ -static void megasas_shutdown(struct pci_dev *pdev) -{ - int i; - struct megasas_instance *instance = pci_get_drvdata(pdev); - - instance->unload = 1; - megasas_flush_cache(instance); - megasas_shutdown_controller(instance, MR_DCMD_CTRL_SHUTDOWN); - instance->instancet->disable_intr(instance->reg_set); - if (instance->msix_vectors) - for (i = 0 ; i < instance->msix_vectors; i++) - free_irq(instance->msixentry[i].vector, - &instance->irq_context[i]); - else - free_irq(instance->pdev->irq, &instance->irq_context[0]); - if (instance->msix_vectors) - pci_disable_msix(instance->pdev); -} - -/** - * megasas_mgmt_open - char node "open" entry point - */ -static int megasas_mgmt_open(struct inode *inode, struct file *filep) -{ - /* - * Allow only those users with admin rights - */ - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - return 0; -} - -/** - * megasas_mgmt_fasync - Async notifier registration from applications - * - * This function adds the calling process to a driver global queue. When an - * event occurs, SIGIO will be sent to all processes in this queue. - */ -static int megasas_mgmt_fasync(int fd, struct file *filep, int mode) -{ - int rc; - - mutex_lock(&megasas_async_queue_mutex); - - rc = fasync_helper(fd, filep, mode, &megasas_async_queue); - - mutex_unlock(&megasas_async_queue_mutex); - - if (rc >= 0) { - /* For sanity check when we get ioctl */ - filep->private_data = filep; - return 0; - } - - printk(KERN_DEBUG "megasas: fasync_helper failed [%d]\n", rc); - - return rc; -} - -/** - * megasas_mgmt_poll - char node "poll" entry point - * */ -static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait) -{ - unsigned int mask; - unsigned long flags; - poll_wait(file, &megasas_poll_wait, wait); - spin_lock_irqsave(&poll_aen_lock, flags); - if (megasas_poll_wait_aen) - mask = (POLLIN | POLLRDNORM); - else - mask = 0; - spin_unlock_irqrestore(&poll_aen_lock, flags); - return mask; -} - -/** - * megasas_mgmt_fw_ioctl - Issues management ioctls to FW - * @instance: Adapter soft state - * @argp: User's ioctl packet - */ -static int -megasas_mgmt_fw_ioctl(struct megasas_instance *instance, - struct megasas_iocpacket __user * user_ioc, - struct megasas_iocpacket *ioc) -{ - struct megasas_sge32 *kern_sge32; - struct megasas_cmd *cmd; - void *kbuff_arr[MAX_IOCTL_SGE]; - dma_addr_t buf_handle = 0; - int error = 0, i; - void *sense = NULL; - dma_addr_t sense_handle; - unsigned long *sense_ptr; - - memset(kbuff_arr, 0, sizeof(kbuff_arr)); - - if (ioc->sge_count > MAX_IOCTL_SGE) { - printk(KERN_DEBUG "megasas: SGE count [%d] > max limit [%d]\n", - ioc->sge_count, MAX_IOCTL_SGE); - return -EINVAL; - } - - cmd = megasas_get_cmd(instance); - if (!cmd) { - printk(KERN_DEBUG "megasas: Failed to get a cmd packet\n"); - return -ENOMEM; - } - - /* - * User's IOCTL packet has 2 frames (maximum). Copy those two - * frames into our cmd's frames. cmd->frame's context will get - * overwritten when we copy from user's frames. So set that value - * alone separately - */ - memcpy(cmd->frame, ioc->frame.raw, 2 * MEGAMFI_FRAME_SIZE); - cmd->frame->hdr.context = cmd->index; - cmd->frame->hdr.pad_0 = 0; - cmd->frame->hdr.flags &= ~(MFI_FRAME_IEEE | MFI_FRAME_SGL64 | - MFI_FRAME_SENSE64); - - /* - * The management interface between applications and the fw uses - * MFI frames. E.g, RAID configuration changes, LD property changes - * etc are accomplishes through different kinds of MFI frames. The - * driver needs to care only about substituting user buffers with - * kernel buffers in SGLs. The location of SGL is embedded in the - * struct iocpacket itself. - */ - kern_sge32 = (struct megasas_sge32 *) - ((unsigned long)cmd->frame + ioc->sgl_off); - - /* - * For each user buffer, create a mirror buffer and copy in - */ - for (i = 0; i < ioc->sge_count; i++) { - if (!ioc->sgl[i].iov_len) - continue; - - kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev, - ioc->sgl[i].iov_len, - &buf_handle, GFP_KERNEL); - if (!kbuff_arr[i]) { - printk(KERN_DEBUG "megasas: Failed to alloc " - "kernel SGL buffer for IOCTL \n"); - error = -ENOMEM; - goto out; - } - - /* - * We don't change the dma_coherent_mask, so - * pci_alloc_consistent only returns 32bit addresses - */ - kern_sge32[i].phys_addr = (u32) buf_handle; - kern_sge32[i].length = ioc->sgl[i].iov_len; - - /* - * We created a kernel buffer corresponding to the - * user buffer. Now copy in from the user buffer - */ - if (copy_from_user(kbuff_arr[i], ioc->sgl[i].iov_base, - (u32) (ioc->sgl[i].iov_len))) { - error = -EFAULT; - goto out; - } - } - - if (ioc->sense_len) { - sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len, - &sense_handle, GFP_KERNEL); - if (!sense) { - error = -ENOMEM; - goto out; - } - - sense_ptr = - (unsigned long *) ((unsigned long)cmd->frame + ioc->sense_off); - *sense_ptr = sense_handle; - } - - /* - * Set the sync_cmd flag so that the ISR knows not to complete this - * cmd to the SCSI mid-layer - */ - cmd->sync_cmd = 1; - megasas_issue_blocked_cmd(instance, cmd); - cmd->sync_cmd = 0; - - /* - * copy out the kernel buffers to user buffers - */ - for (i = 0; i < ioc->sge_count; i++) { - if (copy_to_user(ioc->sgl[i].iov_base, kbuff_arr[i], - ioc->sgl[i].iov_len)) { - error = -EFAULT; - goto out; - } - } - - /* - * copy out the sense - */ - if (ioc->sense_len) { - /* - * sense_ptr points to the location that has the user - * sense buffer address - */ - sense_ptr = (unsigned long *) ((unsigned long)ioc->frame.raw + - ioc->sense_off); - - if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)), - sense, ioc->sense_len)) { - printk(KERN_ERR "megasas: Failed to copy out to user " - "sense data\n"); - error = -EFAULT; - goto out; - } - } - - /* - * copy the status codes returned by the fw - */ - if (copy_to_user(&user_ioc->frame.hdr.cmd_status, - &cmd->frame->hdr.cmd_status, sizeof(u8))) { - printk(KERN_DEBUG "megasas: Error copying out cmd_status\n"); - error = -EFAULT; - } - - out: - if (sense) { - dma_free_coherent(&instance->pdev->dev, ioc->sense_len, - sense, sense_handle); - } - - for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) { - dma_free_coherent(&instance->pdev->dev, - kern_sge32[i].length, - kbuff_arr[i], kern_sge32[i].phys_addr); - } - - megasas_return_cmd(instance, cmd); - return error; -} - -static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) -{ - struct megasas_iocpacket __user *user_ioc = - (struct megasas_iocpacket __user *)arg; - struct megasas_iocpacket *ioc; - struct megasas_instance *instance; - int error; - int i; - unsigned long flags; - u32 wait_time = MEGASAS_RESET_WAIT_TIME; - - ioc = kmalloc(sizeof(*ioc), GFP_KERNEL); - if (!ioc) - return -ENOMEM; - - if (copy_from_user(ioc, user_ioc, sizeof(*ioc))) { - error = -EFAULT; - goto out_kfree_ioc; - } - - instance = megasas_lookup_instance(ioc->host_no); - if (!instance) { - error = -ENODEV; - goto out_kfree_ioc; - } - - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { - printk(KERN_ERR "Controller in crit error\n"); - error = -ENODEV; - goto out_kfree_ioc; - } - - if (instance->unload == 1) { - error = -ENODEV; - goto out_kfree_ioc; - } - - /* - * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds - */ - if (down_interruptible(&instance->ioctl_sem)) { - error = -ERESTARTSYS; - goto out_kfree_ioc; - } - - for (i = 0; i < wait_time; i++) { - - spin_lock_irqsave(&instance->hba_lock, flags); - if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) { - spin_unlock_irqrestore(&instance->hba_lock, flags); - break; - } - spin_unlock_irqrestore(&instance->hba_lock, flags); - - if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: waiting" - "for controller reset to finish\n"); - } - - msleep(1000); - } - - spin_lock_irqsave(&instance->hba_lock, flags); - if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { - spin_unlock_irqrestore(&instance->hba_lock, flags); - - printk(KERN_ERR "megaraid_sas: timed out while" - "waiting for HBA to recover\n"); - error = -ENODEV; - goto out_kfree_ioc; - } - spin_unlock_irqrestore(&instance->hba_lock, flags); - - error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc); - up(&instance->ioctl_sem); - - out_kfree_ioc: - kfree(ioc); - return error; -} - -static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) -{ - struct megasas_instance *instance; - struct megasas_aen aen; - int error; - int i; - unsigned long flags; - u32 wait_time = MEGASAS_RESET_WAIT_TIME; - - if (file->private_data != file) { - printk(KERN_DEBUG "megasas: fasync_helper was not " - "called first\n"); - return -EINVAL; - } - - if (copy_from_user(&aen, (void __user *)arg, sizeof(aen))) - return -EFAULT; - - instance = megasas_lookup_instance(aen.host_no); - - if (!instance) - return -ENODEV; - - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { - return -ENODEV; - } - - if (instance->unload == 1) { - return -ENODEV; - } - - for (i = 0; i < wait_time; i++) { - - spin_lock_irqsave(&instance->hba_lock, flags); - if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) { - spin_unlock_irqrestore(&instance->hba_lock, - flags); - break; - } - - spin_unlock_irqrestore(&instance->hba_lock, flags); - - if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: waiting for" - "controller reset to finish\n"); - } - - msleep(1000); - } - - spin_lock_irqsave(&instance->hba_lock, flags); - if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { - spin_unlock_irqrestore(&instance->hba_lock, flags); - printk(KERN_ERR "megaraid_sas: timed out while waiting" - "for HBA to recover.\n"); - return -ENODEV; - } - spin_unlock_irqrestore(&instance->hba_lock, flags); - - mutex_lock(&instance->aen_mutex); - error = megasas_register_aen(instance, aen.seq_num, - aen.class_locale_word); - mutex_unlock(&instance->aen_mutex); - return error; -} - -/** - * megasas_mgmt_ioctl - char node ioctl entry point - */ -static long -megasas_mgmt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case MEGASAS_IOC_FIRMWARE: - return megasas_mgmt_ioctl_fw(file, arg); - - case MEGASAS_IOC_GET_AEN: - return megasas_mgmt_ioctl_aen(file, arg); - } - - return -ENOTTY; -} - -#ifdef CONFIG_COMPAT -static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg) -{ - struct compat_megasas_iocpacket __user *cioc = - (struct compat_megasas_iocpacket __user *)arg; - struct megasas_iocpacket __user *ioc = - compat_alloc_user_space(sizeof(struct megasas_iocpacket)); - int i; - int error = 0; - compat_uptr_t ptr; - - if (clear_user(ioc, sizeof(*ioc))) - return -EFAULT; - - if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) || - copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) || - copy_in_user(&ioc->sense_off, &cioc->sense_off, sizeof(u32)) || - copy_in_user(&ioc->sense_len, &cioc->sense_len, sizeof(u32)) || - copy_in_user(ioc->frame.raw, cioc->frame.raw, 128) || - copy_in_user(&ioc->sge_count, &cioc->sge_count, sizeof(u32))) - return -EFAULT; - - /* - * The sense_ptr is used in megasas_mgmt_fw_ioctl only when - * sense_len is not null, so prepare the 64bit value under - * the same condition. - */ - if (ioc->sense_len) { - void __user **sense_ioc_ptr = - (void __user **)(ioc->frame.raw + ioc->sense_off); - compat_uptr_t *sense_cioc_ptr = - (compat_uptr_t *)(cioc->frame.raw + cioc->sense_off); - if (get_user(ptr, sense_cioc_ptr) || - put_user(compat_ptr(ptr), sense_ioc_ptr)) - return -EFAULT; - } - - for (i = 0; i < MAX_IOCTL_SGE; i++) { - if (get_user(ptr, &cioc->sgl[i].iov_base) || - put_user(compat_ptr(ptr), &ioc->sgl[i].iov_base) || - copy_in_user(&ioc->sgl[i].iov_len, - &cioc->sgl[i].iov_len, sizeof(compat_size_t))) - return -EFAULT; - } - - error = megasas_mgmt_ioctl_fw(file, (unsigned long)ioc); - - if (copy_in_user(&cioc->frame.hdr.cmd_status, - &ioc->frame.hdr.cmd_status, sizeof(u8))) { - printk(KERN_DEBUG "megasas: error copy_in_user cmd_status\n"); - return -EFAULT; - } - return error; -} - -static long -megasas_mgmt_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - switch (cmd) { - case MEGASAS_IOC_FIRMWARE32: - return megasas_mgmt_compat_ioctl_fw(file, arg); - case MEGASAS_IOC_GET_AEN: - return megasas_mgmt_ioctl_aen(file, arg); - } - - return -ENOTTY; -} -#endif - -/* - * File operations structure for management interface - */ -static const struct file_operations megasas_mgmt_fops = { - .owner = THIS_MODULE, - .open = megasas_mgmt_open, - .fasync = megasas_mgmt_fasync, - .unlocked_ioctl = megasas_mgmt_ioctl, - .poll = megasas_mgmt_poll, -#ifdef CONFIG_COMPAT - .compat_ioctl = megasas_mgmt_compat_ioctl, -#endif - .llseek = noop_llseek, -}; - -/* - * PCI hotplug support registration structure - */ -static struct pci_driver megasas_pci_driver = { - - .name = "megaraid_sas", - .id_table = megasas_pci_table, - .probe = megasas_probe_one, - .remove = __devexit_p(megasas_detach_one), - .suspend = megasas_suspend, - .resume = megasas_resume, - .shutdown = megasas_shutdown, -}; - -/* - * Sysfs driver attributes - */ -static ssize_t megasas_sysfs_show_version(struct device_driver *dd, char *buf) -{ - return snprintf(buf, strlen(MEGASAS_VERSION) + 2, "%s\n", - MEGASAS_VERSION); -} - -static DRIVER_ATTR(version, S_IRUGO, megasas_sysfs_show_version, NULL); - -static ssize_t -megasas_sysfs_show_release_date(struct device_driver *dd, char *buf) -{ - return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n", - MEGASAS_RELDATE); -} - -static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date, - NULL); - -static ssize_t -megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf) -{ - return sprintf(buf, "%u\n", support_poll_for_event); -} - -static DRIVER_ATTR(support_poll_for_event, S_IRUGO, - megasas_sysfs_show_support_poll_for_event, NULL); - - static ssize_t -megasas_sysfs_show_support_device_change(struct device_driver *dd, char *buf) -{ - return sprintf(buf, "%u\n", support_device_change); -} - -static DRIVER_ATTR(support_device_change, S_IRUGO, - megasas_sysfs_show_support_device_change, NULL); - -static ssize_t -megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf) -{ - return sprintf(buf, "%u\n", megasas_dbg_lvl); -} - -static ssize_t -megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count) -{ - int retval = count; - if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){ - printk(KERN_ERR "megasas: could not set dbg_lvl\n"); - retval = -EINVAL; - } - return retval; -} - -static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUSR, megasas_sysfs_show_dbg_lvl, - megasas_sysfs_set_dbg_lvl); - -static void -megasas_aen_polling(struct work_struct *work) -{ - struct megasas_aen_event *ev = - container_of(work, struct megasas_aen_event, hotplug_work); - struct megasas_instance *instance = ev->instance; - union megasas_evt_class_locale class_locale; - struct Scsi_Host *host; - struct scsi_device *sdev1; - u16 pd_index = 0; - u16 ld_index = 0; - int i, j, doscan = 0; - u32 seq_num; - int error; - - if (!instance) { - printk(KERN_ERR "invalid instance!\n"); - kfree(ev); - return; - } - instance->ev = NULL; - host = instance->host; - if (instance->evt_detail) { - - switch (instance->evt_detail->code) { - case MR_EVT_PD_INSERTED: - if (megasas_get_pd_list(instance) == 0) { - for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) { - for (j = 0; - j < MEGASAS_MAX_DEV_PER_CHANNEL; - j++) { - - pd_index = - (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; - - sdev1 = - scsi_device_lookup(host, i, j, 0); - - if (instance->pd_list[pd_index].driveState - == MR_PD_STATE_SYSTEM) { - if (!sdev1) { - scsi_add_device(host, i, j, 0); - } - - if (sdev1) - scsi_device_put(sdev1); - } - } - } - } - doscan = 0; - break; - - case MR_EVT_PD_REMOVED: - if (megasas_get_pd_list(instance) == 0) { - megasas_get_pd_list(instance); - for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) { - for (j = 0; - j < MEGASAS_MAX_DEV_PER_CHANNEL; - j++) { - - pd_index = - (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; - - sdev1 = - scsi_device_lookup(host, i, j, 0); - - if (instance->pd_list[pd_index].driveState - == MR_PD_STATE_SYSTEM) { - if (sdev1) { - scsi_device_put(sdev1); - } - } else { - if (sdev1) { - scsi_remove_device(sdev1); - scsi_device_put(sdev1); - } - } - } - } - } - doscan = 0; - break; - - case MR_EVT_LD_OFFLINE: - case MR_EVT_CFG_CLEARED: - case MR_EVT_LD_DELETED: - megasas_get_ld_list(instance); - for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { - for (j = 0; - j < MEGASAS_MAX_DEV_PER_CHANNEL; - j++) { - - ld_index = - (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; - - sdev1 = scsi_device_lookup(host, - i + MEGASAS_MAX_LD_CHANNELS, - j, - 0); - - if (instance->ld_ids[ld_index] != 0xff) { - if (sdev1) { - scsi_device_put(sdev1); - } - } else { - if (sdev1) { - scsi_remove_device(sdev1); - scsi_device_put(sdev1); - } - } - } - } - doscan = 0; - break; - case MR_EVT_LD_CREATED: - megasas_get_ld_list(instance); - for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { - for (j = 0; - j < MEGASAS_MAX_DEV_PER_CHANNEL; - j++) { - ld_index = - (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; - - sdev1 = scsi_device_lookup(host, - i+MEGASAS_MAX_LD_CHANNELS, - j, 0); - - if (instance->ld_ids[ld_index] != - 0xff) { - if (!sdev1) { - scsi_add_device(host, - i + 2, - j, 0); - } - } - if (sdev1) { - scsi_device_put(sdev1); - } - } - } - doscan = 0; - break; - case MR_EVT_CTRL_HOST_BUS_SCAN_REQUESTED: - case MR_EVT_FOREIGN_CFG_IMPORTED: - case MR_EVT_LD_STATE_CHANGE: - doscan = 1; - break; - default: - doscan = 0; - break; - } - } else { - printk(KERN_ERR "invalid evt_detail!\n"); - kfree(ev); - return; - } - - if (doscan) { - printk(KERN_INFO "scanning ...\n"); - megasas_get_pd_list(instance); - for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) { - for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) { - pd_index = i*MEGASAS_MAX_DEV_PER_CHANNEL + j; - sdev1 = scsi_device_lookup(host, i, j, 0); - if (instance->pd_list[pd_index].driveState == - MR_PD_STATE_SYSTEM) { - if (!sdev1) { - scsi_add_device(host, i, j, 0); - } - if (sdev1) - scsi_device_put(sdev1); - } else { - if (sdev1) { - scsi_remove_device(sdev1); - scsi_device_put(sdev1); - } - } - } - } - - megasas_get_ld_list(instance); - for (i = 0; i < MEGASAS_MAX_LD_CHANNELS; i++) { - for (j = 0; j < MEGASAS_MAX_DEV_PER_CHANNEL; j++) { - ld_index = - (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; - - sdev1 = scsi_device_lookup(host, - i+MEGASAS_MAX_LD_CHANNELS, j, 0); - if (instance->ld_ids[ld_index] != 0xff) { - if (!sdev1) { - scsi_add_device(host, - i+2, - j, 0); - } else { - scsi_device_put(sdev1); - } - } else { - if (sdev1) { - scsi_remove_device(sdev1); - scsi_device_put(sdev1); - } - } - } - } - } - - if ( instance->aen_cmd != NULL ) { - kfree(ev); - return ; - } - - seq_num = instance->evt_detail->seq_num + 1; - - /* Register AEN with FW for latest sequence number plus 1 */ - class_locale.members.reserved = 0; - class_locale.members.locale = MR_EVT_LOCALE_ALL; - class_locale.members.class = MR_EVT_CLASS_DEBUG; - mutex_lock(&instance->aen_mutex); - error = megasas_register_aen(instance, seq_num, - class_locale.word); - mutex_unlock(&instance->aen_mutex); - - if (error) - printk(KERN_ERR "register aen failed error %x\n", error); - - kfree(ev); -} - -/** - * megasas_init - Driver load entry point - */ -static int __init megasas_init(void) -{ - int rval; - - /* - * Announce driver version and other information - */ - printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION, - MEGASAS_EXT_VERSION); - - support_poll_for_event = 2; - support_device_change = 1; - - memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info)); - - /* - * Register character device node - */ - rval = register_chrdev(0, "megaraid_sas_ioctl", &megasas_mgmt_fops); - - if (rval < 0) { - printk(KERN_DEBUG "megasas: failed to open device node\n"); - return rval; - } - - megasas_mgmt_majorno = rval; - - /* - * Register ourselves as PCI hotplug module - */ - rval = pci_register_driver(&megasas_pci_driver); - - if (rval) { - printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n"); - goto err_pcidrv; - } - - rval = driver_create_file(&megasas_pci_driver.driver, - &driver_attr_version); - if (rval) - goto err_dcf_attr_ver; - rval = driver_create_file(&megasas_pci_driver.driver, - &driver_attr_release_date); - if (rval) - goto err_dcf_rel_date; - - rval = driver_create_file(&megasas_pci_driver.driver, - &driver_attr_support_poll_for_event); - if (rval) - goto err_dcf_support_poll_for_event; - - rval = driver_create_file(&megasas_pci_driver.driver, - &driver_attr_dbg_lvl); - if (rval) - goto err_dcf_dbg_lvl; - rval = driver_create_file(&megasas_pci_driver.driver, - &driver_attr_support_device_change); - if (rval) - goto err_dcf_support_device_change; - - return rval; - -err_dcf_support_device_change: - driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_dbg_lvl); -err_dcf_dbg_lvl: - driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_support_poll_for_event); - -err_dcf_support_poll_for_event: - driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_release_date); - -err_dcf_rel_date: - driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); -err_dcf_attr_ver: - pci_unregister_driver(&megasas_pci_driver); -err_pcidrv: - unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); - return rval; -} - -/** - * megasas_exit - Driver unload entry point - */ -static void __exit megasas_exit(void) -{ - driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_dbg_lvl); - driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_support_poll_for_event); - driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_support_device_change); - driver_remove_file(&megasas_pci_driver.driver, - &driver_attr_release_date); - driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version); - - pci_unregister_driver(&megasas_pci_driver); - unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl"); -} - -module_init(megasas_init); -module_exit(megasas_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fp.c b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fp.c deleted file mode 100644 index 294abb0d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fp.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Linux MegaRAID driver for SAS based RAID controllers - * - * Copyright (c) 2009-2011 LSI Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * FILE: megaraid_sas_fp.c - * - * Authors: LSI Corporation - * Sumant Patro - * Varad Talamacki - * Manoj Jose - * - * Send feedback to: - * - * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 - * ATTN: Linuxraid - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "megaraid_sas_fusion.h" -#include "megaraid_sas.h" -#include - -#define ABS_DIFF(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) -#define MR_LD_STATE_OPTIMAL 3 -#define FALSE 0 -#define TRUE 1 - -/* Prototypes */ -void -mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map, - struct LD_LOAD_BALANCE_INFO *lbInfo); - -u32 mega_mod64(u64 dividend, u32 divisor) -{ - u64 d; - u32 remainder; - - if (!divisor) - printk(KERN_ERR "megasas : DIVISOR is zero, in div fn\n"); - d = dividend; - remainder = do_div(d, divisor); - return remainder; -} - -/** - * @param dividend : Dividend - * @param divisor : Divisor - * - * @return quotient - **/ -u64 mega_div64_32(uint64_t dividend, uint32_t divisor) -{ - u32 remainder; - u64 d; - - if (!divisor) - printk(KERN_ERR "megasas : DIVISOR is zero in mod fn\n"); - - d = dividend; - remainder = do_div(d, divisor); - - return d; -} - -struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map) -{ - return &map->raidMap.ldSpanMap[ld].ldRaid; -} - -static struct MR_SPAN_BLOCK_INFO *MR_LdSpanInfoGet(u32 ld, - struct MR_FW_RAID_MAP_ALL - *map) -{ - return &map->raidMap.ldSpanMap[ld].spanBlock[0]; -} - -static u8 MR_LdDataArmGet(u32 ld, u32 armIdx, struct MR_FW_RAID_MAP_ALL *map) -{ - return map->raidMap.ldSpanMap[ld].dataArmMap[armIdx]; -} - -static u16 MR_ArPdGet(u32 ar, u32 arm, struct MR_FW_RAID_MAP_ALL *map) -{ - return map->raidMap.arMapInfo[ar].pd[arm]; -} - -static u16 MR_LdSpanArrayGet(u32 ld, u32 span, struct MR_FW_RAID_MAP_ALL *map) -{ - return map->raidMap.ldSpanMap[ld].spanBlock[span].span.arrayRef; -} - -static u16 MR_PdDevHandleGet(u32 pd, struct MR_FW_RAID_MAP_ALL *map) -{ - return map->raidMap.devHndlInfo[pd].curDevHdl; -} - -u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map) -{ - return map->raidMap.ldSpanMap[ld].ldRaid.targetId; -} - -u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map) -{ - return map->raidMap.ldTgtIdToLd[ldTgtId]; -} - -static struct MR_LD_SPAN *MR_LdSpanPtrGet(u32 ld, u32 span, - struct MR_FW_RAID_MAP_ALL *map) -{ - return &map->raidMap.ldSpanMap[ld].spanBlock[span].span; -} - -/* - * This function will validate Map info data provided by FW - */ -u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map, - struct LD_LOAD_BALANCE_INFO *lbInfo) -{ - struct MR_FW_RAID_MAP *pFwRaidMap = &map->raidMap; - - if (pFwRaidMap->totalSize != - (sizeof(struct MR_FW_RAID_MAP) -sizeof(struct MR_LD_SPAN_MAP) + - (sizeof(struct MR_LD_SPAN_MAP) *pFwRaidMap->ldCount))) { - printk(KERN_ERR "megasas: map info structure size 0x%x is not matching with ld count\n", - (unsigned int)((sizeof(struct MR_FW_RAID_MAP) - - sizeof(struct MR_LD_SPAN_MAP)) + - (sizeof(struct MR_LD_SPAN_MAP) * - pFwRaidMap->ldCount))); - printk(KERN_ERR "megasas: span map %x, pFwRaidMap->totalSize " - ": %x\n", (unsigned int)sizeof(struct MR_LD_SPAN_MAP), - pFwRaidMap->totalSize); - return 0; - } - - mr_update_load_balance_params(map, lbInfo); - - return 1; -} - -u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk, - struct MR_FW_RAID_MAP_ALL *map, int *div_error) -{ - struct MR_SPAN_BLOCK_INFO *pSpanBlock = MR_LdSpanInfoGet(ld, map); - struct MR_QUAD_ELEMENT *quad; - struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); - u32 span, j; - - for (span = 0; span < raid->spanDepth; span++, pSpanBlock++) { - - for (j = 0; j < pSpanBlock->block_span_info.noElements; j++) { - quad = &pSpanBlock->block_span_info.quad[j]; - - if (quad->diff == 0) { - *div_error = 1; - return span; - } - if (quad->logStart <= row && row <= quad->logEnd && - (mega_mod64(row-quad->logStart, quad->diff)) == 0) { - if (span_blk != NULL) { - u64 blk, debugBlk; - blk = - mega_div64_32( - (row-quad->logStart), - quad->diff); - debugBlk = blk; - - blk = (blk + quad->offsetInSpan) << - raid->stripeShift; - *span_blk = blk; - } - return span; - } - } - } - return span; -} - -/* -****************************************************************************** -* -* This routine calculates the arm, span and block for the specified stripe and -* reference in stripe. -* -* Inputs : -* -* ld - Logical drive number -* stripRow - Stripe number -* stripRef - Reference in stripe -* -* Outputs : -* -* span - Span number -* block - Absolute Block number in the physical disk -*/ -u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, - u16 stripRef, u64 *pdBlock, u16 *pDevHandle, - struct RAID_CONTEXT *pRAID_Context, - struct MR_FW_RAID_MAP_ALL *map) -{ - struct MR_LD_RAID *raid = MR_LdRaidGet(ld, map); - u32 pd, arRef; - u8 physArm, span; - u64 row; - u8 retval = TRUE; - int error_code = 0; - - row = mega_div64_32(stripRow, raid->rowDataSize); - - if (raid->level == 6) { - /* logical arm within row */ - u32 logArm = mega_mod64(stripRow, raid->rowDataSize); - u32 rowMod, armQ, arm; - - if (raid->rowSize == 0) - return FALSE; - /* get logical row mod */ - rowMod = mega_mod64(row, raid->rowSize); - armQ = raid->rowSize-1-rowMod; /* index of Q drive */ - arm = armQ+1+logArm; /* data always logically follows Q */ - if (arm >= raid->rowSize) /* handle wrap condition */ - arm -= raid->rowSize; - physArm = (u8)arm; - } else { - if (raid->modFactor == 0) - return FALSE; - physArm = MR_LdDataArmGet(ld, mega_mod64(stripRow, - raid->modFactor), - map); - } - - if (raid->spanDepth == 1) { - span = 0; - *pdBlock = row << raid->stripeShift; - } else { - span = (u8)MR_GetSpanBlock(ld, row, pdBlock, map, &error_code); - if (error_code == 1) - return FALSE; - } - - /* Get the array on which this span is present */ - arRef = MR_LdSpanArrayGet(ld, span, map); - pd = MR_ArPdGet(arRef, physArm, map); /* Get the pd */ - - if (pd != MR_PD_INVALID) - /* Get dev handle from Pd. */ - *pDevHandle = MR_PdDevHandleGet(pd, map); - else { - *pDevHandle = MR_PD_INVALID; /* set dev handle as invalid. */ - if ((raid->level >= 5) && - ((instance->pdev->device != PCI_DEVICE_ID_LSI_INVADER) || - (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER && - raid->regTypeReqOnRead != REGION_TYPE_UNUSED))) - pRAID_Context->regLockFlags = REGION_TYPE_EXCLUSIVE; - else if (raid->level == 1) { - /* Get alternate Pd. */ - pd = MR_ArPdGet(arRef, physArm + 1, map); - if (pd != MR_PD_INVALID) - /* Get dev handle from Pd */ - *pDevHandle = MR_PdDevHandleGet(pd, map); - } - } - - *pdBlock += stripRef + MR_LdSpanPtrGet(ld, span, map)->startBlk; - pRAID_Context->spanArm = (span << RAID_CTX_SPANARM_SPAN_SHIFT) | - physArm; - return retval; -} - -/* -****************************************************************************** -* -* MR_BuildRaidContext function -* -* This function will initiate command processing. The start/end row and strip -* information is calculated then the lock is acquired. -* This function will return 0 if region lock was acquired OR return num strips -*/ -u8 -MR_BuildRaidContext(struct megasas_instance *instance, - struct IO_REQUEST_INFO *io_info, - struct RAID_CONTEXT *pRAID_Context, - struct MR_FW_RAID_MAP_ALL *map) -{ - struct MR_LD_RAID *raid; - u32 ld, stripSize, stripe_mask; - u64 endLba, endStrip, endRow, start_row, start_strip; - u64 regStart; - u32 regSize; - u8 num_strips, numRows; - u16 ref_in_start_stripe, ref_in_end_stripe; - u64 ldStartBlock; - u32 numBlocks, ldTgtId; - u8 isRead; - u8 retval = 0; - - ldStartBlock = io_info->ldStartBlock; - numBlocks = io_info->numBlocks; - ldTgtId = io_info->ldTgtId; - isRead = io_info->isRead; - - ld = MR_TargetIdToLdGet(ldTgtId, map); - raid = MR_LdRaidGet(ld, map); - - stripSize = 1 << raid->stripeShift; - stripe_mask = stripSize-1; - /* - * calculate starting row and stripe, and number of strips and rows - */ - start_strip = ldStartBlock >> raid->stripeShift; - ref_in_start_stripe = (u16)(ldStartBlock & stripe_mask); - endLba = ldStartBlock + numBlocks - 1; - ref_in_end_stripe = (u16)(endLba & stripe_mask); - endStrip = endLba >> raid->stripeShift; - num_strips = (u8)(endStrip - start_strip + 1); /* End strip */ - if (raid->rowDataSize == 0) - return FALSE; - start_row = mega_div64_32(start_strip, raid->rowDataSize); - endRow = mega_div64_32(endStrip, raid->rowDataSize); - numRows = (u8)(endRow - start_row + 1); - - /* - * calculate region info. - */ - - /* assume region is at the start of the first row */ - regStart = start_row << raid->stripeShift; - /* assume this IO needs the full row - we'll adjust if not true */ - regSize = stripSize; - - /* If IO spans more than 1 strip, fp is not possible - FP is not possible for writes on non-0 raid levels - FP is not possible if LD is not capable */ - if (num_strips > 1 || (!isRead && raid->level != 0) || - !raid->capability.fpCapable) { - io_info->fpOkForIo = FALSE; - } else { - io_info->fpOkForIo = TRUE; - } - - if (numRows == 1) { - /* single-strip IOs can always lock only the data needed */ - if (num_strips == 1) { - regStart += ref_in_start_stripe; - regSize = numBlocks; - } - /* multi-strip IOs always need to full stripe locked */ - } else { - if (start_strip == (start_row + 1) * raid->rowDataSize - 1) { - /* If the start strip is the last in the start row */ - regStart += ref_in_start_stripe; - regSize = stripSize - ref_in_start_stripe; - /* initialize count to sectors from startref to end - of strip */ - } - - if (numRows > 2) - /* Add complete rows in the middle of the transfer */ - regSize += (numRows-2) << raid->stripeShift; - - /* if IO ends within first strip of last row */ - if (endStrip == endRow*raid->rowDataSize) - regSize += ref_in_end_stripe+1; - else - regSize += stripSize; - } - - pRAID_Context->timeoutValue = map->raidMap.fpPdIoTimeoutSec; - if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) - pRAID_Context->regLockFlags = (isRead) ? - raid->regTypeReqOnRead : raid->regTypeReqOnWrite; - else - pRAID_Context->regLockFlags = (isRead) ? - REGION_TYPE_SHARED_READ : raid->regTypeReqOnWrite; - pRAID_Context->VirtualDiskTgtId = raid->targetId; - pRAID_Context->regLockRowLBA = regStart; - pRAID_Context->regLockLength = regSize; - pRAID_Context->configSeqNum = raid->seqNum; - - /*Get Phy Params only if FP capable, or else leave it to MR firmware - to do the calculation.*/ - if (io_info->fpOkForIo) { - retval = MR_GetPhyParams(instance, ld, start_strip, - ref_in_start_stripe, - &io_info->pdBlock, - &io_info->devHandle, pRAID_Context, - map); - /* If IO on an invalid Pd, then FP i snot possible */ - if (io_info->devHandle == MR_PD_INVALID) - io_info->fpOkForIo = FALSE; - return retval; - } else if (isRead) { - uint stripIdx; - for (stripIdx = 0; stripIdx < num_strips; stripIdx++) { - if (!MR_GetPhyParams(instance, ld, - start_strip + stripIdx, - ref_in_start_stripe, - &io_info->pdBlock, - &io_info->devHandle, - pRAID_Context, map)) - return TRUE; - } - } - return TRUE; -} - -void -mr_update_load_balance_params(struct MR_FW_RAID_MAP_ALL *map, - struct LD_LOAD_BALANCE_INFO *lbInfo) -{ - int ldCount; - u16 ld; - struct MR_LD_RAID *raid; - - for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES; ldCount++) { - ld = MR_TargetIdToLdGet(ldCount, map); - if (ld >= MAX_LOGICAL_DRIVES) { - lbInfo[ldCount].loadBalanceFlag = 0; - continue; - } - - raid = MR_LdRaidGet(ld, map); - - /* Two drive Optimal RAID 1 */ - if ((raid->level == 1) && (raid->rowSize == 2) && - (raid->spanDepth == 1) && raid->ldState == - MR_LD_STATE_OPTIMAL) { - u32 pd, arRef; - - lbInfo[ldCount].loadBalanceFlag = 1; - - /* Get the array on which this span is present */ - arRef = MR_LdSpanArrayGet(ld, 0, map); - - /* Get the Pd */ - pd = MR_ArPdGet(arRef, 0, map); - /* Get dev handle from Pd */ - lbInfo[ldCount].raid1DevHandle[0] = - MR_PdDevHandleGet(pd, map); - /* Get the Pd */ - pd = MR_ArPdGet(arRef, 1, map); - - /* Get the dev handle from Pd */ - lbInfo[ldCount].raid1DevHandle[1] = - MR_PdDevHandleGet(pd, map); - } else - lbInfo[ldCount].loadBalanceFlag = 0; - } -} - -u8 megasas_get_best_arm(struct LD_LOAD_BALANCE_INFO *lbInfo, u8 arm, u64 block, - u32 count) -{ - u16 pend0, pend1; - u64 diff0, diff1; - u8 bestArm; - - /* get the pending cmds for the data and mirror arms */ - pend0 = atomic_read(&lbInfo->scsi_pending_cmds[0]); - pend1 = atomic_read(&lbInfo->scsi_pending_cmds[1]); - - /* Determine the disk whose head is nearer to the req. block */ - diff0 = ABS_DIFF(block, lbInfo->last_accessed_block[0]); - diff1 = ABS_DIFF(block, lbInfo->last_accessed_block[1]); - bestArm = (diff0 <= diff1 ? 0 : 1); - - if ((bestArm == arm && pend0 > pend1 + 16) || - (bestArm != arm && pend1 > pend0 + 16)) - bestArm ^= 1; - - /* Update the last accessed block on the correct pd */ - lbInfo->last_accessed_block[bestArm] = block + count - 1; - - return bestArm; -} - -u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo, - struct IO_REQUEST_INFO *io_info) -{ - u8 arm, old_arm; - u16 devHandle; - - old_arm = lbInfo->raid1DevHandle[0] == io_info->devHandle ? 0 : 1; - - /* get best new arm */ - arm = megasas_get_best_arm(lbInfo, old_arm, io_info->ldStartBlock, - io_info->numBlocks); - devHandle = lbInfo->raid1DevHandle[arm]; - atomic_inc(&lbInfo->scsi_pending_cmds[arm]); - - return devHandle; -} diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fusion.c b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fusion.c deleted file mode 100644 index bfd87fab..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ /dev/null @@ -1,2358 +0,0 @@ -/* - * Linux MegaRAID driver for SAS based RAID controllers - * - * Copyright (c) 2009-2011 LSI Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * FILE: megaraid_sas_fusion.c - * - * Authors: LSI Corporation - * Sumant Patro - * Adam Radford - * - * Send feedback to: - * - * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 - * ATTN: Linuxraid - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "megaraid_sas_fusion.h" -#include "megaraid_sas.h" - -extern void megasas_free_cmds(struct megasas_instance *instance); -extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance - *instance); -extern void -megasas_complete_cmd(struct megasas_instance *instance, - struct megasas_cmd *cmd, u8 alt_status); -int megasas_is_ldio(struct scsi_cmnd *cmd); -int -wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd); - -void -megasas_return_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd); -int megasas_alloc_cmds(struct megasas_instance *instance); -int -megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs); -int -megasas_issue_polled(struct megasas_instance *instance, - struct megasas_cmd *cmd); - -u8 -MR_BuildRaidContext(struct megasas_instance *instance, - struct IO_REQUEST_INFO *io_info, - struct RAID_CONTEXT *pRAID_Context, - struct MR_FW_RAID_MAP_ALL *map); -u16 MR_TargetIdToLdGet(u32 ldTgtId, struct MR_FW_RAID_MAP_ALL *map); -struct MR_LD_RAID *MR_LdRaidGet(u32 ld, struct MR_FW_RAID_MAP_ALL *map); - -u16 MR_GetLDTgtId(u32 ld, struct MR_FW_RAID_MAP_ALL *map); - -void -megasas_check_and_restore_queue_depth(struct megasas_instance *instance); - -u8 MR_ValidateMapInfo(struct MR_FW_RAID_MAP_ALL *map, - struct LD_LOAD_BALANCE_INFO *lbInfo); -u16 get_updated_dev_handle(struct LD_LOAD_BALANCE_INFO *lbInfo, - struct IO_REQUEST_INFO *in_info); -int megasas_transition_to_ready(struct megasas_instance *instance, int ocr); -void megaraid_sas_kill_hba(struct megasas_instance *instance); - -extern u32 megasas_dbg_lvl; - -/** - * megasas_enable_intr_fusion - Enables interrupts - * @regs: MFI register set - */ -void -megasas_enable_intr_fusion(struct megasas_register_set __iomem *regs) -{ - /* For Thunderbolt/Invader also clear intr on enable */ - writel(~0, ®s->outbound_intr_status); - readl(®s->outbound_intr_status); - - writel(~MFI_FUSION_ENABLE_INTERRUPT_MASK, &(regs)->outbound_intr_mask); - - /* Dummy readl to force pci flush */ - readl(®s->outbound_intr_mask); -} - -/** - * megasas_disable_intr_fusion - Disables interrupt - * @regs: MFI register set - */ -void -megasas_disable_intr_fusion(struct megasas_register_set __iomem *regs) -{ - u32 mask = 0xFFFFFFFF; - u32 status; - - writel(mask, ®s->outbound_intr_mask); - /* Dummy readl to force pci flush */ - status = readl(®s->outbound_intr_mask); -} - -int -megasas_clear_intr_fusion(struct megasas_register_set __iomem *regs) -{ - u32 status; - /* - * Check if it is our interrupt - */ - status = readl(®s->outbound_intr_status); - - if (status & 1) { - writel(status, ®s->outbound_intr_status); - readl(®s->outbound_intr_status); - return 1; - } - if (!(status & MFI_FUSION_ENABLE_INTERRUPT_MASK)) - return 0; - - return 1; -} - -/** - * megasas_get_cmd_fusion - Get a command from the free pool - * @instance: Adapter soft state - * - * Returns a free command from the pool - */ -struct megasas_cmd_fusion *megasas_get_cmd_fusion(struct megasas_instance - *instance) -{ - unsigned long flags; - struct fusion_context *fusion = - (struct fusion_context *)instance->ctrl_context; - struct megasas_cmd_fusion *cmd = NULL; - - spin_lock_irqsave(&fusion->cmd_pool_lock, flags); - - if (!list_empty(&fusion->cmd_pool)) { - cmd = list_entry((&fusion->cmd_pool)->next, - struct megasas_cmd_fusion, list); - list_del_init(&cmd->list); - } else { - printk(KERN_ERR "megasas: Command pool (fusion) empty!\n"); - } - - spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags); - return cmd; -} - -/** - * megasas_return_cmd_fusion - Return a cmd to free command pool - * @instance: Adapter soft state - * @cmd: Command packet to be returned to free command pool - */ -static inline void -megasas_return_cmd_fusion(struct megasas_instance *instance, - struct megasas_cmd_fusion *cmd) -{ - unsigned long flags; - struct fusion_context *fusion = - (struct fusion_context *)instance->ctrl_context; - - spin_lock_irqsave(&fusion->cmd_pool_lock, flags); - - cmd->scmd = NULL; - cmd->sync_cmd_idx = (u32)ULONG_MAX; - list_add_tail(&cmd->list, &fusion->cmd_pool); - - spin_unlock_irqrestore(&fusion->cmd_pool_lock, flags); -} - -/** - * megasas_teardown_frame_pool_fusion - Destroy the cmd frame DMA pool - * @instance: Adapter soft state - */ -static void megasas_teardown_frame_pool_fusion( - struct megasas_instance *instance) -{ - int i; - struct fusion_context *fusion = instance->ctrl_context; - - u16 max_cmd = instance->max_fw_cmds; - - struct megasas_cmd_fusion *cmd; - - if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) { - printk(KERN_ERR "megasas: dma pool is null. SG Pool %p, " - "sense pool : %p\n", fusion->sg_dma_pool, - fusion->sense_dma_pool); - return; - } - - /* - * Return all frames to pool - */ - for (i = 0; i < max_cmd; i++) { - - cmd = fusion->cmd_list[i]; - - if (cmd->sg_frame) - pci_pool_free(fusion->sg_dma_pool, cmd->sg_frame, - cmd->sg_frame_phys_addr); - - if (cmd->sense) - pci_pool_free(fusion->sense_dma_pool, cmd->sense, - cmd->sense_phys_addr); - } - - /* - * Now destroy the pool itself - */ - pci_pool_destroy(fusion->sg_dma_pool); - pci_pool_destroy(fusion->sense_dma_pool); - - fusion->sg_dma_pool = NULL; - fusion->sense_dma_pool = NULL; -} - -/** - * megasas_free_cmds_fusion - Free all the cmds in the free cmd pool - * @instance: Adapter soft state - */ -void -megasas_free_cmds_fusion(struct megasas_instance *instance) -{ - int i; - struct fusion_context *fusion = instance->ctrl_context; - - u32 max_cmds, req_sz, reply_sz, io_frames_sz; - - - req_sz = fusion->request_alloc_sz; - reply_sz = fusion->reply_alloc_sz; - io_frames_sz = fusion->io_frames_alloc_sz; - - max_cmds = instance->max_fw_cmds; - - /* Free descriptors and request Frames memory */ - if (fusion->req_frames_desc) - dma_free_coherent(&instance->pdev->dev, req_sz, - fusion->req_frames_desc, - fusion->req_frames_desc_phys); - - if (fusion->reply_frames_desc) { - pci_pool_free(fusion->reply_frames_desc_pool, - fusion->reply_frames_desc, - fusion->reply_frames_desc_phys); - pci_pool_destroy(fusion->reply_frames_desc_pool); - } - - if (fusion->io_request_frames) { - pci_pool_free(fusion->io_request_frames_pool, - fusion->io_request_frames, - fusion->io_request_frames_phys); - pci_pool_destroy(fusion->io_request_frames_pool); - } - - /* Free the Fusion frame pool */ - megasas_teardown_frame_pool_fusion(instance); - - /* Free all the commands in the cmd_list */ - for (i = 0; i < max_cmds; i++) - kfree(fusion->cmd_list[i]); - - /* Free the cmd_list buffer itself */ - kfree(fusion->cmd_list); - fusion->cmd_list = NULL; - - INIT_LIST_HEAD(&fusion->cmd_pool); -} - -/** - * megasas_create_frame_pool_fusion - Creates DMA pool for cmd frames - * @instance: Adapter soft state - * - */ -static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) -{ - int i; - u32 max_cmd; - struct fusion_context *fusion; - struct megasas_cmd_fusion *cmd; - u32 total_sz_chain_frame; - - fusion = instance->ctrl_context; - max_cmd = instance->max_fw_cmds; - - total_sz_chain_frame = MEGASAS_MAX_SZ_CHAIN_FRAME; - - /* - * Use DMA pool facility provided by PCI layer - */ - - fusion->sg_dma_pool = pci_pool_create("megasas sg pool fusion", - instance->pdev, - total_sz_chain_frame, 4, - 0); - if (!fusion->sg_dma_pool) { - printk(KERN_DEBUG "megasas: failed to setup request pool " - "fusion\n"); - return -ENOMEM; - } - fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion", - instance->pdev, - SCSI_SENSE_BUFFERSIZE, 64, 0); - - if (!fusion->sense_dma_pool) { - printk(KERN_DEBUG "megasas: failed to setup sense pool " - "fusion\n"); - pci_pool_destroy(fusion->sg_dma_pool); - fusion->sg_dma_pool = NULL; - return -ENOMEM; - } - - /* - * Allocate and attach a frame to each of the commands in cmd_list - */ - for (i = 0; i < max_cmd; i++) { - - cmd = fusion->cmd_list[i]; - - cmd->sg_frame = pci_pool_alloc(fusion->sg_dma_pool, - GFP_KERNEL, - &cmd->sg_frame_phys_addr); - - cmd->sense = pci_pool_alloc(fusion->sense_dma_pool, - GFP_KERNEL, &cmd->sense_phys_addr); - /* - * megasas_teardown_frame_pool_fusion() takes care of freeing - * whatever has been allocated - */ - if (!cmd->sg_frame || !cmd->sense) { - printk(KERN_DEBUG "megasas: pci_pool_alloc failed\n"); - megasas_teardown_frame_pool_fusion(instance); - return -ENOMEM; - } - } - return 0; -} - -/** - * megasas_alloc_cmds_fusion - Allocates the command packets - * @instance: Adapter soft state - * - * - * Each frame has a 32-bit field called context. This context is used to get - * back the megasas_cmd_fusion from the frame when a frame gets completed - * In this driver, the 32 bit values are the indices into an array cmd_list. - * This array is used only to look up the megasas_cmd_fusion given the context. - * The free commands themselves are maintained in a linked list called cmd_pool. - * - * cmds are formed in the io_request and sg_frame members of the - * megasas_cmd_fusion. The context field is used to get a request descriptor - * and is used as SMID of the cmd. - * SMID value range is from 1 to max_fw_cmds. - */ -int -megasas_alloc_cmds_fusion(struct megasas_instance *instance) -{ - int i, j, count; - u32 max_cmd, io_frames_sz; - struct fusion_context *fusion; - struct megasas_cmd_fusion *cmd; - union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; - u32 offset; - dma_addr_t io_req_base_phys; - u8 *io_req_base; - - fusion = instance->ctrl_context; - - max_cmd = instance->max_fw_cmds; - - fusion->req_frames_desc = - dma_alloc_coherent(&instance->pdev->dev, - fusion->request_alloc_sz, - &fusion->req_frames_desc_phys, GFP_KERNEL); - - if (!fusion->req_frames_desc) { - printk(KERN_ERR "megasas; Could not allocate memory for " - "request_frames\n"); - goto fail_req_desc; - } - - count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; - fusion->reply_frames_desc_pool = - pci_pool_create("reply_frames pool", instance->pdev, - fusion->reply_alloc_sz * count, 16, 0); - - if (!fusion->reply_frames_desc_pool) { - printk(KERN_ERR "megasas; Could not allocate memory for " - "reply_frame pool\n"); - goto fail_reply_desc; - } - - fusion->reply_frames_desc = - pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL, - &fusion->reply_frames_desc_phys); - if (!fusion->reply_frames_desc) { - printk(KERN_ERR "megasas; Could not allocate memory for " - "reply_frame pool\n"); - pci_pool_destroy(fusion->reply_frames_desc_pool); - goto fail_reply_desc; - } - - reply_desc = fusion->reply_frames_desc; - for (i = 0; i < fusion->reply_q_depth * count; i++, reply_desc++) - reply_desc->Words = ULLONG_MAX; - - io_frames_sz = fusion->io_frames_alloc_sz; - - fusion->io_request_frames_pool = - pci_pool_create("io_request_frames pool", instance->pdev, - fusion->io_frames_alloc_sz, 16, 0); - - if (!fusion->io_request_frames_pool) { - printk(KERN_ERR "megasas: Could not allocate memory for " - "io_request_frame pool\n"); - goto fail_io_frames; - } - - fusion->io_request_frames = - pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL, - &fusion->io_request_frames_phys); - if (!fusion->io_request_frames) { - printk(KERN_ERR "megasas: Could not allocate memory for " - "io_request_frames frames\n"); - pci_pool_destroy(fusion->io_request_frames_pool); - goto fail_io_frames; - } - - /* - * fusion->cmd_list is an array of struct megasas_cmd_fusion pointers. - * Allocate the dynamic array first and then allocate individual - * commands. - */ - fusion->cmd_list = kmalloc(sizeof(struct megasas_cmd_fusion *) - *max_cmd, GFP_KERNEL); - - if (!fusion->cmd_list) { - printk(KERN_DEBUG "megasas: out of memory. Could not alloc " - "memory for cmd_list_fusion\n"); - goto fail_cmd_list; - } - - memset(fusion->cmd_list, 0, sizeof(struct megasas_cmd_fusion *) - *max_cmd); - - max_cmd = instance->max_fw_cmds; - for (i = 0; i < max_cmd; i++) { - fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion), - GFP_KERNEL); - if (!fusion->cmd_list[i]) { - printk(KERN_ERR "Could not alloc cmd list fusion\n"); - - for (j = 0; j < i; j++) - kfree(fusion->cmd_list[j]); - - kfree(fusion->cmd_list); - fusion->cmd_list = NULL; - goto fail_cmd_list; - } - } - - /* The first 256 bytes (SMID 0) is not used. Don't add to cmd list */ - io_req_base = fusion->io_request_frames + - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; - io_req_base_phys = fusion->io_request_frames_phys + - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE; - - /* - * Add all the commands to command pool (fusion->cmd_pool) - */ - - /* SMID 0 is reserved. Set SMID/index from 1 */ - for (i = 0; i < max_cmd; i++) { - cmd = fusion->cmd_list[i]; - offset = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * i; - memset(cmd, 0, sizeof(struct megasas_cmd_fusion)); - cmd->index = i + 1; - cmd->scmd = NULL; - cmd->sync_cmd_idx = (u32)ULONG_MAX; /* Set to Invalid */ - cmd->instance = instance; - cmd->io_request = - (struct MPI2_RAID_SCSI_IO_REQUEST *) - (io_req_base + offset); - memset(cmd->io_request, 0, - sizeof(struct MPI2_RAID_SCSI_IO_REQUEST)); - cmd->io_request_phys_addr = io_req_base_phys + offset; - - list_add_tail(&cmd->list, &fusion->cmd_pool); - } - - /* - * Create a frame pool and assign one frame to each cmd - */ - if (megasas_create_frame_pool_fusion(instance)) { - printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n"); - megasas_free_cmds_fusion(instance); - goto fail_req_desc; - } - - return 0; - -fail_cmd_list: - pci_pool_free(fusion->io_request_frames_pool, fusion->io_request_frames, - fusion->io_request_frames_phys); - pci_pool_destroy(fusion->io_request_frames_pool); -fail_io_frames: - dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, - fusion->reply_frames_desc, - fusion->reply_frames_desc_phys); - pci_pool_free(fusion->reply_frames_desc_pool, - fusion->reply_frames_desc, - fusion->reply_frames_desc_phys); - pci_pool_destroy(fusion->reply_frames_desc_pool); - -fail_reply_desc: - dma_free_coherent(&instance->pdev->dev, fusion->request_alloc_sz, - fusion->req_frames_desc, - fusion->req_frames_desc_phys); -fail_req_desc: - return -ENOMEM; -} - -/** - * wait_and_poll - Issues a polling command - * @instance: Adapter soft state - * @cmd: Command packet to be issued - * - * For polling, MFI requires the cmd_status to be set to 0xFF before posting. - */ -int -wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd) -{ - int i; - struct megasas_header *frame_hdr = &cmd->frame->hdr; - - u32 msecs = MFI_POLL_TIMEOUT_SECS * 1000; - - /* - * Wait for cmd_status to change - */ - for (i = 0; (i < msecs) && (frame_hdr->cmd_status == 0xff); i += 20) { - rmb(); - msleep(20); - } - - if (frame_hdr->cmd_status == 0xff) - return -ETIME; - - return 0; -} - -/** - * megasas_ioc_init_fusion - Initializes the FW - * @instance: Adapter soft state - * - * Issues the IOC Init cmd - */ -int -megasas_ioc_init_fusion(struct megasas_instance *instance) -{ - struct megasas_init_frame *init_frame; - struct MPI2_IOC_INIT_REQUEST *IOCInitMessage; - dma_addr_t ioc_init_handle; - struct megasas_cmd *cmd; - u8 ret; - struct fusion_context *fusion; - union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; - int i; - struct megasas_header *frame_hdr; - - fusion = instance->ctrl_context; - - cmd = megasas_get_cmd(instance); - - if (!cmd) { - printk(KERN_ERR "Could not allocate cmd for INIT Frame\n"); - ret = 1; - goto fail_get_cmd; - } - - IOCInitMessage = - dma_alloc_coherent(&instance->pdev->dev, - sizeof(struct MPI2_IOC_INIT_REQUEST), - &ioc_init_handle, GFP_KERNEL); - - if (!IOCInitMessage) { - printk(KERN_ERR "Could not allocate memory for " - "IOCInitMessage\n"); - ret = 1; - goto fail_fw_init; - } - - memset(IOCInitMessage, 0, sizeof(struct MPI2_IOC_INIT_REQUEST)); - - IOCInitMessage->Function = MPI2_FUNCTION_IOC_INIT; - IOCInitMessage->WhoInit = MPI2_WHOINIT_HOST_DRIVER; - IOCInitMessage->MsgVersion = MPI2_VERSION; - IOCInitMessage->HeaderVersion = MPI2_HEADER_VERSION; - IOCInitMessage->SystemRequestFrameSize = - MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE / 4; - - IOCInitMessage->ReplyDescriptorPostQueueDepth = fusion->reply_q_depth; - IOCInitMessage->ReplyDescriptorPostQueueAddress = - fusion->reply_frames_desc_phys; - IOCInitMessage->SystemRequestFrameBaseAddress = - fusion->io_request_frames_phys; - /* Set to 0 for none or 1 MSI-X vectors */ - IOCInitMessage->HostMSIxVectors = (instance->msix_vectors > 0 ? - instance->msix_vectors : 0); - init_frame = (struct megasas_init_frame *)cmd->frame; - memset(init_frame, 0, MEGAMFI_FRAME_SIZE); - - frame_hdr = &cmd->frame->hdr; - frame_hdr->cmd_status = 0xFF; - frame_hdr->flags |= MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; - - init_frame->cmd = MFI_CMD_INIT; - init_frame->cmd_status = 0xFF; - - init_frame->queue_info_new_phys_addr_lo = ioc_init_handle; - init_frame->data_xfer_len = sizeof(struct MPI2_IOC_INIT_REQUEST); - - req_desc = - (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)fusion->req_frames_desc; - - req_desc->Words = cmd->frame_phys_addr; - req_desc->MFAIo.RequestFlags = - (MEGASAS_REQ_DESCRIPT_FLAGS_MFA << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - - /* - * disable the intr before firing the init frame - */ - instance->instancet->disable_intr(instance->reg_set); - - for (i = 0; i < (10 * 1000); i += 20) { - if (readl(&instance->reg_set->doorbell) & 1) - msleep(20); - else - break; - } - - instance->instancet->fire_cmd(instance, req_desc->u.low, - req_desc->u.high, instance->reg_set); - - wait_and_poll(instance, cmd); - - frame_hdr = &cmd->frame->hdr; - if (frame_hdr->cmd_status != 0) { - ret = 1; - goto fail_fw_init; - } - printk(KERN_ERR "megasas:IOC Init cmd success\n"); - - ret = 0; - -fail_fw_init: - megasas_return_cmd(instance, cmd); - if (IOCInitMessage) - dma_free_coherent(&instance->pdev->dev, - sizeof(struct MPI2_IOC_INIT_REQUEST), - IOCInitMessage, ioc_init_handle); -fail_get_cmd: - return ret; -} - -/* - * megasas_get_ld_map_info - Returns FW's ld_map structure - * @instance: Adapter soft state - * @pend: Pend the command or not - * Issues an internal command (DCMD) to get the FW's controller PD - * list structure. This information is mainly used to find out SYSTEM - * supported by the FW. - */ -static int -megasas_get_ld_map_info(struct megasas_instance *instance) -{ - int ret = 0; - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - struct MR_FW_RAID_MAP_ALL *ci; - dma_addr_t ci_h = 0; - u32 size_map_info; - struct fusion_context *fusion; - - cmd = megasas_get_cmd(instance); - - if (!cmd) { - printk(KERN_DEBUG "megasas: Failed to get cmd for map info.\n"); - return -ENOMEM; - } - - fusion = instance->ctrl_context; - - if (!fusion) { - megasas_return_cmd(instance, cmd); - return 1; - } - - dcmd = &cmd->frame->dcmd; - - size_map_info = sizeof(struct MR_FW_RAID_MAP) + - (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1)); - - ci = fusion->ld_map[(instance->map_id & 1)]; - ci_h = fusion->ld_map_phys[(instance->map_id & 1)]; - - if (!ci) { - printk(KERN_DEBUG "Failed to alloc mem for ld_map_info\n"); - megasas_return_cmd(instance, cmd); - return -ENOMEM; - } - - memset(ci, 0, sizeof(*ci)); - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0xFF; - dcmd->sge_count = 1; - dcmd->flags = MFI_FRAME_DIR_READ; - dcmd->timeout = 0; - dcmd->pad_0 = 0; - dcmd->data_xfer_len = size_map_info; - dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO; - dcmd->sgl.sge32[0].phys_addr = ci_h; - dcmd->sgl.sge32[0].length = size_map_info; - - if (!megasas_issue_polled(instance, cmd)) - ret = 0; - else { - printk(KERN_ERR "megasas: Get LD Map Info Failed\n"); - ret = -1; - } - - megasas_return_cmd(instance, cmd); - - return ret; -} - -u8 -megasas_get_map_info(struct megasas_instance *instance) -{ - struct fusion_context *fusion = instance->ctrl_context; - - fusion->fast_path_io = 0; - if (!megasas_get_ld_map_info(instance)) { - if (MR_ValidateMapInfo(fusion->ld_map[(instance->map_id & 1)], - fusion->load_balance_info)) { - fusion->fast_path_io = 1; - return 0; - } - } - return 1; -} - -/* - * megasas_sync_map_info - Returns FW's ld_map structure - * @instance: Adapter soft state - * - * Issues an internal command (DCMD) to get the FW's controller PD - * list structure. This information is mainly used to find out SYSTEM - * supported by the FW. - */ -int -megasas_sync_map_info(struct megasas_instance *instance) -{ - int ret = 0, i; - struct megasas_cmd *cmd; - struct megasas_dcmd_frame *dcmd; - u32 size_sync_info, num_lds; - struct fusion_context *fusion; - struct MR_LD_TARGET_SYNC *ci = NULL; - struct MR_FW_RAID_MAP_ALL *map; - struct MR_LD_RAID *raid; - struct MR_LD_TARGET_SYNC *ld_sync; - dma_addr_t ci_h = 0; - u32 size_map_info; - - cmd = megasas_get_cmd(instance); - - if (!cmd) { - printk(KERN_DEBUG "megasas: Failed to get cmd for sync" - "info.\n"); - return -ENOMEM; - } - - fusion = instance->ctrl_context; - - if (!fusion) { - megasas_return_cmd(instance, cmd); - return 1; - } - - map = fusion->ld_map[instance->map_id & 1]; - - num_lds = map->raidMap.ldCount; - - dcmd = &cmd->frame->dcmd; - - size_sync_info = sizeof(struct MR_LD_TARGET_SYNC) *num_lds; - - memset(dcmd->mbox.b, 0, MFI_MBOX_SIZE); - - ci = (struct MR_LD_TARGET_SYNC *) - fusion->ld_map[(instance->map_id - 1) & 1]; - memset(ci, 0, sizeof(struct MR_FW_RAID_MAP_ALL)); - - ci_h = fusion->ld_map_phys[(instance->map_id - 1) & 1]; - - ld_sync = (struct MR_LD_TARGET_SYNC *)ci; - - for (i = 0; i < num_lds; i++, ld_sync++) { - raid = MR_LdRaidGet(i, map); - ld_sync->targetId = MR_GetLDTgtId(i, map); - ld_sync->seqNum = raid->seqNum; - } - - size_map_info = sizeof(struct MR_FW_RAID_MAP) + - (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1)); - - dcmd->cmd = MFI_CMD_DCMD; - dcmd->cmd_status = 0xFF; - dcmd->sge_count = 1; - dcmd->flags = MFI_FRAME_DIR_WRITE; - dcmd->timeout = 0; - dcmd->pad_0 = 0; - dcmd->data_xfer_len = size_map_info; - dcmd->mbox.b[0] = num_lds; - dcmd->mbox.b[1] = MEGASAS_DCMD_MBOX_PEND_FLAG; - dcmd->opcode = MR_DCMD_LD_MAP_GET_INFO; - dcmd->sgl.sge32[0].phys_addr = ci_h; - dcmd->sgl.sge32[0].length = size_map_info; - - instance->map_update_cmd = cmd; - - instance->instancet->issue_dcmd(instance, cmd); - - return ret; -} - -/** - * megasas_init_adapter_fusion - Initializes the FW - * @instance: Adapter soft state - * - * This is the main function for initializing firmware. - */ -u32 -megasas_init_adapter_fusion(struct megasas_instance *instance) -{ - struct megasas_register_set __iomem *reg_set; - struct fusion_context *fusion; - u32 max_cmd; - int i = 0, count; - - fusion = instance->ctrl_context; - - reg_set = instance->reg_set; - - /* - * Get various operational parameters from status register - */ - instance->max_fw_cmds = - instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF; - instance->max_fw_cmds = min(instance->max_fw_cmds, (u16)1008); - - /* - * Reduce the max supported cmds by 1. This is to ensure that the - * reply_q_sz (1 more than the max cmd that driver may send) - * does not exceed max cmds that the FW can support - */ - instance->max_fw_cmds = instance->max_fw_cmds-1; - /* Only internal cmds (DCMD) need to have MFI frames */ - instance->max_mfi_cmds = MEGASAS_INT_CMDS; - - max_cmd = instance->max_fw_cmds; - - fusion->reply_q_depth = ((max_cmd + 1 + 15)/16)*16; - - fusion->request_alloc_sz = - sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *max_cmd; - fusion->reply_alloc_sz = sizeof(union MPI2_REPLY_DESCRIPTORS_UNION) - *(fusion->reply_q_depth); - fusion->io_frames_alloc_sz = MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE + - (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE * - (max_cmd + 1)); /* Extra 1 for SMID 0 */ - - fusion->max_sge_in_main_msg = - (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL))/16; - - fusion->max_sge_in_chain = - MEGASAS_MAX_SZ_CHAIN_FRAME / sizeof(union MPI2_SGE_IO_UNION); - - instance->max_num_sge = fusion->max_sge_in_main_msg + - fusion->max_sge_in_chain - 2; - - /* Used for pass thru MFI frame (DCMD) */ - fusion->chain_offset_mfi_pthru = - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL)/16; - - fusion->chain_offset_io_request = - (MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE - - sizeof(union MPI2_SGE_IO_UNION))/16; - - count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; - for (i = 0 ; i < count; i++) - fusion->last_reply_idx[i] = 0; - - /* - * Allocate memory for descriptors - * Create a pool of commands - */ - if (megasas_alloc_cmds(instance)) - goto fail_alloc_mfi_cmds; - if (megasas_alloc_cmds_fusion(instance)) - goto fail_alloc_cmds; - - if (megasas_ioc_init_fusion(instance)) - goto fail_ioc_init; - - instance->flag_ieee = 1; - - fusion->map_sz = sizeof(struct MR_FW_RAID_MAP) + - (sizeof(struct MR_LD_SPAN_MAP) *(MAX_LOGICAL_DRIVES - 1)); - - fusion->fast_path_io = 0; - - for (i = 0; i < 2; i++) { - fusion->ld_map[i] = dma_alloc_coherent(&instance->pdev->dev, - fusion->map_sz, - &fusion->ld_map_phys[i], - GFP_KERNEL); - if (!fusion->ld_map[i]) { - printk(KERN_ERR "megasas: Could not allocate memory " - "for map info\n"); - goto fail_map_info; - } - } - - if (!megasas_get_map_info(instance)) - megasas_sync_map_info(instance); - - return 0; - -fail_map_info: - if (i == 1) - dma_free_coherent(&instance->pdev->dev, fusion->map_sz, - fusion->ld_map[0], fusion->ld_map_phys[0]); -fail_ioc_init: - megasas_free_cmds_fusion(instance); -fail_alloc_cmds: - megasas_free_cmds(instance); -fail_alloc_mfi_cmds: - return 1; -} - -/** - * megasas_fire_cmd_fusion - Sends command to the FW - * @frame_phys_addr : Physical address of cmd - * @frame_count : Number of frames for the command - * @regs : MFI register set - */ -void -megasas_fire_cmd_fusion(struct megasas_instance *instance, - dma_addr_t req_desc_lo, - u32 req_desc_hi, - struct megasas_register_set __iomem *regs) -{ - unsigned long flags; - - spin_lock_irqsave(&instance->hba_lock, flags); - - writel(req_desc_lo, - &(regs)->inbound_low_queue_port); - writel(req_desc_hi, &(regs)->inbound_high_queue_port); - spin_unlock_irqrestore(&instance->hba_lock, flags); -} - -/** - * map_cmd_status - Maps FW cmd status to OS cmd status - * @cmd : Pointer to cmd - * @status : status of cmd returned by FW - * @ext_status : ext status of cmd returned by FW - */ - -void -map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status) -{ - - switch (status) { - - case MFI_STAT_OK: - cmd->scmd->result = DID_OK << 16; - break; - - case MFI_STAT_SCSI_IO_FAILED: - case MFI_STAT_LD_INIT_IN_PROGRESS: - cmd->scmd->result = (DID_ERROR << 16) | ext_status; - break; - - case MFI_STAT_SCSI_DONE_WITH_ERROR: - - cmd->scmd->result = (DID_OK << 16) | ext_status; - if (ext_status == SAM_STAT_CHECK_CONDITION) { - memset(cmd->scmd->sense_buffer, 0, - SCSI_SENSE_BUFFERSIZE); - memcpy(cmd->scmd->sense_buffer, cmd->sense, - SCSI_SENSE_BUFFERSIZE); - cmd->scmd->result |= DRIVER_SENSE << 24; - } - break; - - case MFI_STAT_LD_OFFLINE: - case MFI_STAT_DEVICE_NOT_FOUND: - cmd->scmd->result = DID_BAD_TARGET << 16; - break; - case MFI_STAT_CONFIG_SEQ_MISMATCH: - cmd->scmd->result = DID_IMM_RETRY << 16; - break; - default: - printk(KERN_DEBUG "megasas: FW status %#x\n", status); - cmd->scmd->result = DID_ERROR << 16; - break; - } -} - -/** - * megasas_make_sgl_fusion - Prepares 32-bit SGL - * @instance: Adapter soft state - * @scp: SCSI command from the mid-layer - * @sgl_ptr: SGL to be filled in - * @cmd: cmd we are working on - * - * If successful, this function returns the number of SG elements. - */ -static int -megasas_make_sgl_fusion(struct megasas_instance *instance, - struct scsi_cmnd *scp, - struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr, - struct megasas_cmd_fusion *cmd) -{ - int i, sg_processed, sge_count; - struct scatterlist *os_sgl; - struct fusion_context *fusion; - - fusion = instance->ctrl_context; - - if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) { - struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = sgl_ptr; - sgl_ptr_end += fusion->max_sge_in_main_msg - 1; - sgl_ptr_end->Flags = 0; - } - - sge_count = scsi_dma_map(scp); - - BUG_ON(sge_count < 0); - - if (sge_count > instance->max_num_sge || !sge_count) - return sge_count; - - scsi_for_each_sg(scp, os_sgl, sge_count, i) { - sgl_ptr->Length = sg_dma_len(os_sgl); - sgl_ptr->Address = sg_dma_address(os_sgl); - sgl_ptr->Flags = 0; - if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) { - if (i == sge_count - 1) - sgl_ptr->Flags = IEEE_SGE_FLAGS_END_OF_LIST; - } - sgl_ptr++; - - sg_processed = i + 1; - - if ((sg_processed == (fusion->max_sge_in_main_msg - 1)) && - (sge_count > fusion->max_sge_in_main_msg)) { - - struct MPI25_IEEE_SGE_CHAIN64 *sg_chain; - if (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) { - if ((cmd->io_request->IoFlags & - MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) != - MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH) - cmd->io_request->ChainOffset = - fusion-> - chain_offset_io_request; - else - cmd->io_request->ChainOffset = 0; - } else - cmd->io_request->ChainOffset = - fusion->chain_offset_io_request; - - sg_chain = sgl_ptr; - /* Prepare chain element */ - sg_chain->NextChainOffset = 0; - if (instance->pdev->device == - PCI_DEVICE_ID_LSI_INVADER) - sg_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT; - else - sg_chain->Flags = - (IEEE_SGE_FLAGS_CHAIN_ELEMENT | - MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR); - sg_chain->Length = (sizeof(union MPI2_SGE_IO_UNION) - *(sge_count - sg_processed)); - sg_chain->Address = cmd->sg_frame_phys_addr; - - sgl_ptr = - (struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame; - } - } - - return sge_count; -} - -/** - * megasas_set_pd_lba - Sets PD LBA - * @cdb: CDB - * @cdb_len: cdb length - * @start_blk: Start block of IO - * - * Used to set the PD LBA in CDB for FP IOs - */ -void -megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len, - struct IO_REQUEST_INFO *io_info, struct scsi_cmnd *scp, - struct MR_FW_RAID_MAP_ALL *local_map_ptr, u32 ref_tag) -{ - struct MR_LD_RAID *raid; - u32 ld; - u64 start_blk = io_info->pdBlock; - u8 *cdb = io_request->CDB.CDB32; - u32 num_blocks = io_info->numBlocks; - u8 opcode = 0, flagvals = 0, groupnum = 0, control = 0; - - /* Check if T10 PI (DIF) is enabled for this LD */ - ld = MR_TargetIdToLdGet(io_info->ldTgtId, local_map_ptr); - raid = MR_LdRaidGet(ld, local_map_ptr); - if (raid->capability.ldPiMode == MR_PROT_INFO_TYPE_CONTROLLER) { - memset(cdb, 0, sizeof(io_request->CDB.CDB32)); - cdb[0] = MEGASAS_SCSI_VARIABLE_LENGTH_CMD; - cdb[7] = MEGASAS_SCSI_ADDL_CDB_LEN; - - if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) - cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_READ32; - else - cdb[9] = MEGASAS_SCSI_SERVICE_ACTION_WRITE32; - cdb[10] = MEGASAS_RD_WR_PROTECT_CHECK_ALL; - - /* LBA */ - cdb[12] = (u8)((start_blk >> 56) & 0xff); - cdb[13] = (u8)((start_blk >> 48) & 0xff); - cdb[14] = (u8)((start_blk >> 40) & 0xff); - cdb[15] = (u8)((start_blk >> 32) & 0xff); - cdb[16] = (u8)((start_blk >> 24) & 0xff); - cdb[17] = (u8)((start_blk >> 16) & 0xff); - cdb[18] = (u8)((start_blk >> 8) & 0xff); - cdb[19] = (u8)(start_blk & 0xff); - - /* Logical block reference tag */ - io_request->CDB.EEDP32.PrimaryReferenceTag = - cpu_to_be32(ref_tag); - io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff; - - io_request->DataLength = num_blocks * 512; - io_request->IoFlags = 32; /* Specify 32-byte cdb */ - - /* Transfer length */ - cdb[28] = (u8)((num_blocks >> 24) & 0xff); - cdb[29] = (u8)((num_blocks >> 16) & 0xff); - cdb[30] = (u8)((num_blocks >> 8) & 0xff); - cdb[31] = (u8)(num_blocks & 0xff); - - /* set SCSI IO EEDPFlags */ - if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) { - io_request->EEDPFlags = - MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP | - MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - } else { - io_request->EEDPFlags = - MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; - } - io_request->Control |= (0x4 << 26); - io_request->EEDPBlockSize = MEGASAS_EEDPBLOCKSIZE; - } else { - /* Some drives don't support 16/12 byte CDB's, convert to 10 */ - if (((cdb_len == 12) || (cdb_len == 16)) && - (start_blk <= 0xffffffff)) { - if (cdb_len == 16) { - opcode = cdb[0] == READ_16 ? READ_10 : WRITE_10; - flagvals = cdb[1]; - groupnum = cdb[14]; - control = cdb[15]; - } else { - opcode = cdb[0] == READ_12 ? READ_10 : WRITE_10; - flagvals = cdb[1]; - groupnum = cdb[10]; - control = cdb[11]; - } - - memset(cdb, 0, sizeof(io_request->CDB.CDB32)); - - cdb[0] = opcode; - cdb[1] = flagvals; - cdb[6] = groupnum; - cdb[9] = control; - - /* Transfer length */ - cdb[8] = (u8)(num_blocks & 0xff); - cdb[7] = (u8)((num_blocks >> 8) & 0xff); - - io_request->IoFlags = 10; /* Specify 10-byte cdb */ - cdb_len = 10; - } else if ((cdb_len < 16) && (start_blk > 0xffffffff)) { - /* Convert to 16 byte CDB for large LBA's */ - switch (cdb_len) { - case 6: - opcode = cdb[0] == READ_6 ? READ_16 : WRITE_16; - control = cdb[5]; - break; - case 10: - opcode = - cdb[0] == READ_10 ? READ_16 : WRITE_16; - flagvals = cdb[1]; - groupnum = cdb[6]; - control = cdb[9]; - break; - case 12: - opcode = - cdb[0] == READ_12 ? READ_16 : WRITE_16; - flagvals = cdb[1]; - groupnum = cdb[10]; - control = cdb[11]; - break; - } - - memset(cdb, 0, sizeof(io_request->CDB.CDB32)); - - cdb[0] = opcode; - cdb[1] = flagvals; - cdb[14] = groupnum; - cdb[15] = control; - - /* Transfer length */ - cdb[13] = (u8)(num_blocks & 0xff); - cdb[12] = (u8)((num_blocks >> 8) & 0xff); - cdb[11] = (u8)((num_blocks >> 16) & 0xff); - cdb[10] = (u8)((num_blocks >> 24) & 0xff); - - io_request->IoFlags = 16; /* Specify 16-byte cdb */ - cdb_len = 16; - } - - /* Normal case, just load LBA here */ - switch (cdb_len) { - case 6: - { - u8 val = cdb[1] & 0xE0; - cdb[3] = (u8)(start_blk & 0xff); - cdb[2] = (u8)((start_blk >> 8) & 0xff); - cdb[1] = val | ((u8)(start_blk >> 16) & 0x1f); - break; - } - case 10: - cdb[5] = (u8)(start_blk & 0xff); - cdb[4] = (u8)((start_blk >> 8) & 0xff); - cdb[3] = (u8)((start_blk >> 16) & 0xff); - cdb[2] = (u8)((start_blk >> 24) & 0xff); - break; - case 12: - cdb[5] = (u8)(start_blk & 0xff); - cdb[4] = (u8)((start_blk >> 8) & 0xff); - cdb[3] = (u8)((start_blk >> 16) & 0xff); - cdb[2] = (u8)((start_blk >> 24) & 0xff); - break; - case 16: - cdb[9] = (u8)(start_blk & 0xff); - cdb[8] = (u8)((start_blk >> 8) & 0xff); - cdb[7] = (u8)((start_blk >> 16) & 0xff); - cdb[6] = (u8)((start_blk >> 24) & 0xff); - cdb[5] = (u8)((start_blk >> 32) & 0xff); - cdb[4] = (u8)((start_blk >> 40) & 0xff); - cdb[3] = (u8)((start_blk >> 48) & 0xff); - cdb[2] = (u8)((start_blk >> 56) & 0xff); - break; - } - } -} - -/** - * megasas_build_ldio_fusion - Prepares IOs to devices - * @instance: Adapter soft state - * @scp: SCSI command - * @cmd: Command to be prepared - * - * Prepares the io_request and chain elements (sg_frame) for IO - * The IO can be for PD (Fast Path) or LD - */ -void -megasas_build_ldio_fusion(struct megasas_instance *instance, - struct scsi_cmnd *scp, - struct megasas_cmd_fusion *cmd) -{ - u8 fp_possible; - u32 start_lba_lo, start_lba_hi, device_id; - struct MPI2_RAID_SCSI_IO_REQUEST *io_request; - union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; - struct IO_REQUEST_INFO io_info; - struct fusion_context *fusion; - struct MR_FW_RAID_MAP_ALL *local_map_ptr; - - device_id = MEGASAS_DEV_INDEX(instance, scp); - - fusion = instance->ctrl_context; - - io_request = cmd->io_request; - io_request->RaidContext.VirtualDiskTgtId = device_id; - io_request->RaidContext.status = 0; - io_request->RaidContext.exStatus = 0; - - req_desc = (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)cmd->request_desc; - - start_lba_lo = 0; - start_lba_hi = 0; - fp_possible = 0; - - /* - * 6-byte READ(0x08) or WRITE(0x0A) cdb - */ - if (scp->cmd_len == 6) { - io_request->DataLength = (u32) scp->cmnd[4]; - start_lba_lo = ((u32) scp->cmnd[1] << 16) | - ((u32) scp->cmnd[2] << 8) | (u32) scp->cmnd[3]; - - start_lba_lo &= 0x1FFFFF; - } - - /* - * 10-byte READ(0x28) or WRITE(0x2A) cdb - */ - else if (scp->cmd_len == 10) { - io_request->DataLength = (u32) scp->cmnd[8] | - ((u32) scp->cmnd[7] << 8); - start_lba_lo = ((u32) scp->cmnd[2] << 24) | - ((u32) scp->cmnd[3] << 16) | - ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; - } - - /* - * 12-byte READ(0xA8) or WRITE(0xAA) cdb - */ - else if (scp->cmd_len == 12) { - io_request->DataLength = ((u32) scp->cmnd[6] << 24) | - ((u32) scp->cmnd[7] << 16) | - ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; - start_lba_lo = ((u32) scp->cmnd[2] << 24) | - ((u32) scp->cmnd[3] << 16) | - ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; - } - - /* - * 16-byte READ(0x88) or WRITE(0x8A) cdb - */ - else if (scp->cmd_len == 16) { - io_request->DataLength = ((u32) scp->cmnd[10] << 24) | - ((u32) scp->cmnd[11] << 16) | - ((u32) scp->cmnd[12] << 8) | (u32) scp->cmnd[13]; - start_lba_lo = ((u32) scp->cmnd[6] << 24) | - ((u32) scp->cmnd[7] << 16) | - ((u32) scp->cmnd[8] << 8) | (u32) scp->cmnd[9]; - - start_lba_hi = ((u32) scp->cmnd[2] << 24) | - ((u32) scp->cmnd[3] << 16) | - ((u32) scp->cmnd[4] << 8) | (u32) scp->cmnd[5]; - } - - memset(&io_info, 0, sizeof(struct IO_REQUEST_INFO)); - io_info.ldStartBlock = ((u64)start_lba_hi << 32) | start_lba_lo; - io_info.numBlocks = io_request->DataLength; - io_info.ldTgtId = device_id; - - if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) - io_info.isRead = 1; - - local_map_ptr = fusion->ld_map[(instance->map_id & 1)]; - - if ((MR_TargetIdToLdGet(device_id, local_map_ptr) >= - MAX_LOGICAL_DRIVES) || (!fusion->fast_path_io)) { - io_request->RaidContext.regLockFlags = 0; - fp_possible = 0; - } else { - if (MR_BuildRaidContext(instance, &io_info, - &io_request->RaidContext, - local_map_ptr)) - fp_possible = io_info.fpOkForIo; - } - - /* Use smp_processor_id() for now until cmd->request->cpu is CPU - id by default, not CPU group id, otherwise all MSI-X queues won't - be utilized */ - cmd->request_desc->SCSIIO.MSIxIndex = instance->msix_vectors ? - smp_processor_id() % instance->msix_vectors : 0; - - if (fp_possible) { - megasas_set_pd_lba(io_request, scp->cmd_len, &io_info, scp, - local_map_ptr, start_lba_lo); - io_request->DataLength = scsi_bufflen(scp); - io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; - cmd->request_desc->SCSIIO.RequestFlags = - (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY - << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) { - if (io_request->RaidContext.regLockFlags == - REGION_TYPE_UNUSED) - cmd->request_desc->SCSIIO.RequestFlags = - (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - io_request->RaidContext.Type = MPI2_TYPE_CUDA; - io_request->RaidContext.nseg = 0x1; - io_request->IoFlags |= - MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH; - io_request->RaidContext.regLockFlags |= - (MR_RL_FLAGS_GRANT_DESTINATION_CUDA | - MR_RL_FLAGS_SEQ_NUM_ENABLE); - } - if ((fusion->load_balance_info[device_id].loadBalanceFlag) && - (io_info.isRead)) { - io_info.devHandle = - get_updated_dev_handle( - &fusion->load_balance_info[device_id], - &io_info); - scp->SCp.Status |= MEGASAS_LOAD_BALANCE_FLAG; - } else - scp->SCp.Status &= ~MEGASAS_LOAD_BALANCE_FLAG; - cmd->request_desc->SCSIIO.DevHandle = io_info.devHandle; - io_request->DevHandle = io_info.devHandle; - } else { - io_request->RaidContext.timeoutValue = - local_map_ptr->raidMap.fpPdIoTimeoutSec; - cmd->request_desc->SCSIIO.RequestFlags = - (MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO - << MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) { - if (io_request->RaidContext.regLockFlags == - REGION_TYPE_UNUSED) - cmd->request_desc->SCSIIO.RequestFlags = - (MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - io_request->RaidContext.Type = MPI2_TYPE_CUDA; - io_request->RaidContext.regLockFlags |= - (MR_RL_FLAGS_GRANT_DESTINATION_CPU0 | - MR_RL_FLAGS_SEQ_NUM_ENABLE); - io_request->RaidContext.nseg = 0x1; - } - io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; - io_request->DevHandle = device_id; - } /* Not FP */ -} - -/** - * megasas_build_dcdb_fusion - Prepares IOs to devices - * @instance: Adapter soft state - * @scp: SCSI command - * @cmd: Command to be prepared - * - * Prepares the io_request frame for non-io cmds - */ -static void -megasas_build_dcdb_fusion(struct megasas_instance *instance, - struct scsi_cmnd *scmd, - struct megasas_cmd_fusion *cmd) -{ - u32 device_id; - struct MPI2_RAID_SCSI_IO_REQUEST *io_request; - u16 pd_index = 0; - struct MR_FW_RAID_MAP_ALL *local_map_ptr; - struct fusion_context *fusion = instance->ctrl_context; - - io_request = cmd->io_request; - device_id = MEGASAS_DEV_INDEX(instance, scmd); - pd_index = (scmd->device->channel * MEGASAS_MAX_DEV_PER_CHANNEL) - +scmd->device->id; - local_map_ptr = fusion->ld_map[(instance->map_id & 1)]; - - /* Check if this is a system PD I/O */ - if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) { - io_request->Function = 0; - io_request->DevHandle = - local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl; - io_request->RaidContext.timeoutValue = - local_map_ptr->raidMap.fpPdIoTimeoutSec; - io_request->RaidContext.regLockFlags = 0; - io_request->RaidContext.regLockRowLBA = 0; - io_request->RaidContext.regLockLength = 0; - io_request->RaidContext.RAIDFlags = - MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD << - MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT; - cmd->request_desc->SCSIIO.RequestFlags = - (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - } else { - io_request->Function = MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST; - io_request->DevHandle = device_id; - cmd->request_desc->SCSIIO.RequestFlags = - (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - } - io_request->RaidContext.VirtualDiskTgtId = device_id; - io_request->LUN[1] = scmd->device->lun; - io_request->DataLength = scsi_bufflen(scmd); -} - -/** - * megasas_build_io_fusion - Prepares IOs to devices - * @instance: Adapter soft state - * @scp: SCSI command - * @cmd: Command to be prepared - * - * Invokes helper functions to prepare request frames - * and sets flags appropriate for IO/Non-IO cmd - */ -int -megasas_build_io_fusion(struct megasas_instance *instance, - struct scsi_cmnd *scp, - struct megasas_cmd_fusion *cmd) -{ - u32 device_id, sge_count; - struct MPI2_RAID_SCSI_IO_REQUEST *io_request = cmd->io_request; - - device_id = MEGASAS_DEV_INDEX(instance, scp); - - /* Zero out some fields so they don't get reused */ - io_request->LUN[1] = 0; - io_request->CDB.EEDP32.PrimaryReferenceTag = 0; - io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0; - io_request->EEDPFlags = 0; - io_request->Control = 0; - io_request->EEDPBlockSize = 0; - io_request->ChainOffset = 0; - io_request->RaidContext.RAIDFlags = 0; - io_request->RaidContext.Type = 0; - io_request->RaidContext.nseg = 0; - - memcpy(io_request->CDB.CDB32, scp->cmnd, scp->cmd_len); - /* - * Just the CDB length,rest of the Flags are zero - * This will be modified for FP in build_ldio_fusion - */ - io_request->IoFlags = scp->cmd_len; - - if (megasas_is_ldio(scp)) - megasas_build_ldio_fusion(instance, scp, cmd); - else - megasas_build_dcdb_fusion(instance, scp, cmd); - - /* - * Construct SGL - */ - - sge_count = - megasas_make_sgl_fusion(instance, scp, - (struct MPI25_IEEE_SGE_CHAIN64 *) - &io_request->SGL, cmd); - - if (sge_count > instance->max_num_sge) { - printk(KERN_ERR "megasas: Error. sge_count (0x%x) exceeds " - "max (0x%x) allowed\n", sge_count, - instance->max_num_sge); - return 1; - } - - io_request->RaidContext.numSGE = sge_count; - - io_request->SGLFlags = MPI2_SGE_FLAGS_64_BIT_ADDRESSING; - - if (scp->sc_data_direction == PCI_DMA_TODEVICE) - io_request->Control |= MPI2_SCSIIO_CONTROL_WRITE; - else if (scp->sc_data_direction == PCI_DMA_FROMDEVICE) - io_request->Control |= MPI2_SCSIIO_CONTROL_READ; - - io_request->SGLOffset0 = - offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, SGL) / 4; - - io_request->SenseBufferLowAddress = cmd->sense_phys_addr; - io_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; - - cmd->scmd = scp; - scp->SCp.ptr = (char *)cmd; - - return 0; -} - -union MEGASAS_REQUEST_DESCRIPTOR_UNION * -megasas_get_request_descriptor(struct megasas_instance *instance, u16 index) -{ - u8 *p; - struct fusion_context *fusion; - - if (index >= instance->max_fw_cmds) { - printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for " - "descriptor\n", index); - return NULL; - } - fusion = instance->ctrl_context; - p = fusion->req_frames_desc - +sizeof(union MEGASAS_REQUEST_DESCRIPTOR_UNION) *index; - - return (union MEGASAS_REQUEST_DESCRIPTOR_UNION *)p; -} - -/** - * megasas_build_and_issue_cmd_fusion -Main routine for building and - * issuing non IOCTL cmd - * @instance: Adapter soft state - * @scmd: pointer to scsi cmd from OS - */ -static u32 -megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, - struct scsi_cmnd *scmd) -{ - struct megasas_cmd_fusion *cmd; - union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; - u32 index; - struct fusion_context *fusion; - - fusion = instance->ctrl_context; - - cmd = megasas_get_cmd_fusion(instance); - if (!cmd) - return SCSI_MLQUEUE_HOST_BUSY; - - index = cmd->index; - - req_desc = megasas_get_request_descriptor(instance, index-1); - if (!req_desc) - return 1; - - req_desc->Words = 0; - cmd->request_desc = req_desc; - - if (megasas_build_io_fusion(instance, scmd, cmd)) { - megasas_return_cmd_fusion(instance, cmd); - printk(KERN_ERR "megasas: Error building command.\n"); - cmd->request_desc = NULL; - return 1; - } - - req_desc = cmd->request_desc; - req_desc->SCSIIO.SMID = index; - - if (cmd->io_request->ChainOffset != 0 && - cmd->io_request->ChainOffset != 0xF) - printk(KERN_ERR "megasas: The chain offset value is not " - "correct : %x\n", cmd->io_request->ChainOffset); - - /* - * Issue the command to the FW - */ - atomic_inc(&instance->fw_outstanding); - - instance->instancet->fire_cmd(instance, - req_desc->u.low, req_desc->u.high, - instance->reg_set); - - return 0; -} - -/** - * complete_cmd_fusion - Completes command - * @instance: Adapter soft state - * Completes all commands that is in reply descriptor queue - */ -int -complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) -{ - union MPI2_REPLY_DESCRIPTORS_UNION *desc; - struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *reply_desc; - struct MPI2_RAID_SCSI_IO_REQUEST *scsi_io_req; - struct fusion_context *fusion; - struct megasas_cmd *cmd_mfi; - struct megasas_cmd_fusion *cmd_fusion; - u16 smid, num_completed; - u8 reply_descript_type, arm; - u32 status, extStatus, device_id; - union desc_value d_val; - struct LD_LOAD_BALANCE_INFO *lbinfo; - - fusion = instance->ctrl_context; - - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) - return IRQ_HANDLED; - - desc = fusion->reply_frames_desc; - desc += ((MSIxIndex * fusion->reply_alloc_sz)/ - sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)) + - fusion->last_reply_idx[MSIxIndex]; - - reply_desc = (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; - - d_val.word = desc->Words; - - reply_descript_type = reply_desc->ReplyFlags & - MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - - if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) - return IRQ_NONE; - - d_val.word = desc->Words; - - num_completed = 0; - - while ((d_val.u.low != UINT_MAX) && (d_val.u.high != UINT_MAX)) { - smid = reply_desc->SMID; - - cmd_fusion = fusion->cmd_list[smid - 1]; - - scsi_io_req = - (struct MPI2_RAID_SCSI_IO_REQUEST *) - cmd_fusion->io_request; - - if (cmd_fusion->scmd) - cmd_fusion->scmd->SCp.ptr = NULL; - - status = scsi_io_req->RaidContext.status; - extStatus = scsi_io_req->RaidContext.exStatus; - - switch (scsi_io_req->Function) { - case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/ - /* Update load balancing info */ - device_id = MEGASAS_DEV_INDEX(instance, - cmd_fusion->scmd); - lbinfo = &fusion->load_balance_info[device_id]; - if (cmd_fusion->scmd->SCp.Status & - MEGASAS_LOAD_BALANCE_FLAG) { - arm = lbinfo->raid1DevHandle[0] == - cmd_fusion->io_request->DevHandle ? 0 : - 1; - atomic_dec(&lbinfo->scsi_pending_cmds[arm]); - cmd_fusion->scmd->SCp.Status &= - ~MEGASAS_LOAD_BALANCE_FLAG; - } - if (reply_descript_type == - MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { - if (megasas_dbg_lvl == 5) - printk(KERN_ERR "\nmegasas: FAST Path " - "IO Success\n"); - } - /* Fall thru and complete IO */ - case MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST: /* LD-IO Path */ - /* Map the FW Cmd Status */ - map_cmd_status(cmd_fusion, status, extStatus); - scsi_dma_unmap(cmd_fusion->scmd); - cmd_fusion->scmd->scsi_done(cmd_fusion->scmd); - scsi_io_req->RaidContext.status = 0; - scsi_io_req->RaidContext.exStatus = 0; - megasas_return_cmd_fusion(instance, cmd_fusion); - atomic_dec(&instance->fw_outstanding); - - break; - case MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST: /*MFI command */ - cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx]; - megasas_complete_cmd(instance, cmd_mfi, DID_OK); - cmd_fusion->flags = 0; - megasas_return_cmd_fusion(instance, cmd_fusion); - - break; - } - - fusion->last_reply_idx[MSIxIndex]++; - if (fusion->last_reply_idx[MSIxIndex] >= - fusion->reply_q_depth) - fusion->last_reply_idx[MSIxIndex] = 0; - - desc->Words = ULLONG_MAX; - num_completed++; - - /* Get the next reply descriptor */ - if (!fusion->last_reply_idx[MSIxIndex]) - desc = fusion->reply_frames_desc + - ((MSIxIndex * fusion->reply_alloc_sz)/ - sizeof(union MPI2_REPLY_DESCRIPTORS_UNION)); - else - desc++; - - reply_desc = - (struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR *)desc; - - d_val.word = desc->Words; - - reply_descript_type = reply_desc->ReplyFlags & - MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - - if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) - break; - } - - if (!num_completed) - return IRQ_NONE; - - wmb(); - writel((MSIxIndex << 24) | fusion->last_reply_idx[MSIxIndex], - &instance->reg_set->reply_post_host_index); - megasas_check_and_restore_queue_depth(instance); - return IRQ_HANDLED; -} - -/** - * megasas_complete_cmd_dpc_fusion - Completes command - * @instance: Adapter soft state - * - * Tasklet to complete cmds - */ -void -megasas_complete_cmd_dpc_fusion(unsigned long instance_addr) -{ - struct megasas_instance *instance = - (struct megasas_instance *)instance_addr; - unsigned long flags; - u32 count, MSIxIndex; - - count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; - - /* If we have already declared adapter dead, donot complete cmds */ - spin_lock_irqsave(&instance->hba_lock, flags); - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { - spin_unlock_irqrestore(&instance->hba_lock, flags); - return; - } - spin_unlock_irqrestore(&instance->hba_lock, flags); - - spin_lock_irqsave(&instance->completion_lock, flags); - for (MSIxIndex = 0 ; MSIxIndex < count; MSIxIndex++) - complete_cmd_fusion(instance, MSIxIndex); - spin_unlock_irqrestore(&instance->completion_lock, flags); -} - -/** - * megasas_isr_fusion - isr entry point - */ -irqreturn_t megasas_isr_fusion(int irq, void *devp) -{ - struct megasas_irq_context *irq_context = devp; - struct megasas_instance *instance = irq_context->instance; - u32 mfiStatus, fw_state; - - if (!instance->msix_vectors) { - mfiStatus = instance->instancet->clear_intr(instance->reg_set); - if (!mfiStatus) - return IRQ_NONE; - } - - /* If we are resetting, bail */ - if (test_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags)) { - instance->instancet->clear_intr(instance->reg_set); - return IRQ_HANDLED; - } - - if (!complete_cmd_fusion(instance, irq_context->MSIxIndex)) { - instance->instancet->clear_intr(instance->reg_set); - /* If we didn't complete any commands, check for FW fault */ - fw_state = instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - if (fw_state == MFI_STATE_FAULT) - schedule_work(&instance->work_init); - } - - return IRQ_HANDLED; -} - -/** - * build_mpt_mfi_pass_thru - builds a cmd fo MFI Pass thru - * @instance: Adapter soft state - * mfi_cmd: megasas_cmd pointer - * - */ -u8 -build_mpt_mfi_pass_thru(struct megasas_instance *instance, - struct megasas_cmd *mfi_cmd) -{ - struct MPI25_IEEE_SGE_CHAIN64 *mpi25_ieee_chain; - struct MPI2_RAID_SCSI_IO_REQUEST *io_req; - struct megasas_cmd_fusion *cmd; - struct fusion_context *fusion; - struct megasas_header *frame_hdr = &mfi_cmd->frame->hdr; - - cmd = megasas_get_cmd_fusion(instance); - if (!cmd) - return 1; - - /* Save the smid. To be used for returning the cmd */ - mfi_cmd->context.smid = cmd->index; - - cmd->sync_cmd_idx = mfi_cmd->index; - - /* - * For cmds where the flag is set, store the flag and check - * on completion. For cmds with this flag, don't call - * megasas_complete_cmd - */ - - if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE) - cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE; - - fusion = instance->ctrl_context; - io_req = cmd->io_request; - - if (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) { - struct MPI25_IEEE_SGE_CHAIN64 *sgl_ptr_end = - (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL; - sgl_ptr_end += fusion->max_sge_in_main_msg - 1; - sgl_ptr_end->Flags = 0; - } - - mpi25_ieee_chain = - (struct MPI25_IEEE_SGE_CHAIN64 *)&io_req->SGL.IeeeChain; - - io_req->Function = MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST; - io_req->SGLOffset0 = offsetof(struct MPI2_RAID_SCSI_IO_REQUEST, - SGL) / 4; - io_req->ChainOffset = fusion->chain_offset_mfi_pthru; - - mpi25_ieee_chain->Address = mfi_cmd->frame_phys_addr; - - mpi25_ieee_chain->Flags = IEEE_SGE_FLAGS_CHAIN_ELEMENT | - MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR; - - mpi25_ieee_chain->Length = MEGASAS_MAX_SZ_CHAIN_FRAME; - - return 0; -} - -/** - * build_mpt_cmd - Calls helper function to build a cmd MFI Pass thru cmd - * @instance: Adapter soft state - * @cmd: mfi cmd to build - * - */ -union MEGASAS_REQUEST_DESCRIPTOR_UNION * -build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) -{ - union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; - u16 index; - - if (build_mpt_mfi_pass_thru(instance, cmd)) { - printk(KERN_ERR "Couldn't build MFI pass thru cmd\n"); - return NULL; - } - - index = cmd->context.smid; - - req_desc = megasas_get_request_descriptor(instance, index - 1); - - if (!req_desc) - return NULL; - - req_desc->Words = 0; - req_desc->SCSIIO.RequestFlags = (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO << - MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT); - - req_desc->SCSIIO.SMID = index; - - return req_desc; -} - -/** - * megasas_issue_dcmd_fusion - Issues a MFI Pass thru cmd - * @instance: Adapter soft state - * @cmd: mfi cmd pointer - * - */ -void -megasas_issue_dcmd_fusion(struct megasas_instance *instance, - struct megasas_cmd *cmd) -{ - union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; - - req_desc = build_mpt_cmd(instance, cmd); - if (!req_desc) { - printk(KERN_ERR "Couldn't issue MFI pass thru cmd\n"); - return; - } - instance->instancet->fire_cmd(instance, req_desc->u.low, - req_desc->u.high, instance->reg_set); -} - -/** - * megasas_release_fusion - Reverses the FW initialization - * @intance: Adapter soft state - */ -void -megasas_release_fusion(struct megasas_instance *instance) -{ - megasas_free_cmds(instance); - megasas_free_cmds_fusion(instance); - - iounmap(instance->reg_set); - - pci_release_selected_regions(instance->pdev, instance->bar); -} - -/** - * megasas_read_fw_status_reg_fusion - returns the current FW status value - * @regs: MFI register set - */ -static u32 -megasas_read_fw_status_reg_fusion(struct megasas_register_set __iomem *regs) -{ - return readl(&(regs)->outbound_scratch_pad); -} - -/** - * megasas_adp_reset_fusion - For controller reset - * @regs: MFI register set - */ -static int -megasas_adp_reset_fusion(struct megasas_instance *instance, - struct megasas_register_set __iomem *regs) -{ - return 0; -} - -/** - * megasas_check_reset_fusion - For controller reset check - * @regs: MFI register set - */ -static int -megasas_check_reset_fusion(struct megasas_instance *instance, - struct megasas_register_set __iomem *regs) -{ - return 0; -} - -/* This function waits for outstanding commands on fusion to complete */ -int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance) -{ - int i, outstanding, retval = 0; - u32 fw_state, wait_time = MEGASAS_RESET_WAIT_TIME; - - for (i = 0; i < wait_time; i++) { - /* Check if firmware is in fault state */ - fw_state = instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - if (fw_state == MFI_STATE_FAULT) { - printk(KERN_WARNING "megasas: Found FW in FAULT state," - " will reset adapter.\n"); - retval = 1; - goto out; - } - - outstanding = atomic_read(&instance->fw_outstanding); - if (!outstanding) - goto out; - - if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: [%2d]waiting for %d " - "commands to complete\n", i, outstanding); - megasas_complete_cmd_dpc_fusion( - (unsigned long)instance); - } - msleep(1000); - } - - if (atomic_read(&instance->fw_outstanding)) { - printk("megaraid_sas: pending commands remain after waiting, " - "will reset adapter.\n"); - retval = 1; - } -out: - return retval; -} - -void megasas_reset_reply_desc(struct megasas_instance *instance) -{ - int i, count; - struct fusion_context *fusion; - union MPI2_REPLY_DESCRIPTORS_UNION *reply_desc; - - fusion = instance->ctrl_context; - count = instance->msix_vectors > 0 ? instance->msix_vectors : 1; - for (i = 0 ; i < count ; i++) - fusion->last_reply_idx[i] = 0; - reply_desc = fusion->reply_frames_desc; - for (i = 0 ; i < fusion->reply_q_depth * count; i++, reply_desc++) - reply_desc->Words = ULLONG_MAX; -} - -/* Core fusion reset function */ -int megasas_reset_fusion(struct Scsi_Host *shost) -{ - int retval = SUCCESS, i, j, retry = 0; - struct megasas_instance *instance; - struct megasas_cmd_fusion *cmd_fusion; - struct fusion_context *fusion; - struct megasas_cmd *cmd_mfi; - union MEGASAS_REQUEST_DESCRIPTOR_UNION *req_desc; - u32 host_diag, abs_state, status_reg, reset_adapter; - - instance = (struct megasas_instance *)shost->hostdata; - fusion = instance->ctrl_context; - - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { - printk(KERN_WARNING "megaraid_sas: Hardware critical error, " - "returning FAILED.\n"); - return FAILED; - } - - mutex_lock(&instance->reset_mutex); - set_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); - instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; - instance->instancet->disable_intr(instance->reg_set); - msleep(1000); - - /* First try waiting for commands to complete */ - if (megasas_wait_for_outstanding_fusion(instance)) { - printk(KERN_WARNING "megaraid_sas: resetting fusion " - "adapter.\n"); - /* Now return commands back to the OS */ - for (i = 0 ; i < instance->max_fw_cmds; i++) { - cmd_fusion = fusion->cmd_list[i]; - if (cmd_fusion->scmd) { - scsi_dma_unmap(cmd_fusion->scmd); - cmd_fusion->scmd->result = (DID_RESET << 16); - cmd_fusion->scmd->scsi_done(cmd_fusion->scmd); - megasas_return_cmd_fusion(instance, cmd_fusion); - atomic_dec(&instance->fw_outstanding); - } - } - - status_reg = instance->instancet->read_fw_status_reg( - instance->reg_set); - abs_state = status_reg & MFI_STATE_MASK; - reset_adapter = status_reg & MFI_RESET_ADAPTER; - if (instance->disableOnlineCtrlReset || - (abs_state == MFI_STATE_FAULT && !reset_adapter)) { - /* Reset not supported, kill adapter */ - printk(KERN_WARNING "megaraid_sas: Reset not supported" - ", killing adapter.\n"); - megaraid_sas_kill_hba(instance); - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; - retval = FAILED; - goto out; - } - - /* Now try to reset the chip */ - for (i = 0; i < MEGASAS_FUSION_MAX_RESET_TRIES; i++) { - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_1ST_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_2ND_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_3RD_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_4TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_5TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - writel(MPI2_WRSEQ_6TH_KEY_VALUE, - &instance->reg_set->fusion_seq_offset); - - /* Check that the diag write enable (DRWE) bit is on */ - host_diag = readl(&instance->reg_set->fusion_host_diag); - retry = 0; - while (!(host_diag & HOST_DIAG_WRITE_ENABLE)) { - msleep(100); - host_diag = - readl(&instance->reg_set->fusion_host_diag); - if (retry++ == 100) { - printk(KERN_WARNING "megaraid_sas: " - "Host diag unlock failed!\n"); - break; - } - } - if (!(host_diag & HOST_DIAG_WRITE_ENABLE)) - continue; - - /* Send chip reset command */ - writel(host_diag | HOST_DIAG_RESET_ADAPTER, - &instance->reg_set->fusion_host_diag); - msleep(3000); - - /* Make sure reset adapter bit is cleared */ - host_diag = readl(&instance->reg_set->fusion_host_diag); - retry = 0; - while (host_diag & HOST_DIAG_RESET_ADAPTER) { - msleep(100); - host_diag = - readl(&instance->reg_set->fusion_host_diag); - if (retry++ == 1000) { - printk(KERN_WARNING "megaraid_sas: " - "Diag reset adapter never " - "cleared!\n"); - break; - } - } - if (host_diag & HOST_DIAG_RESET_ADAPTER) - continue; - - abs_state = - instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - retry = 0; - - while ((abs_state <= MFI_STATE_FW_INIT) && - (retry++ < 1000)) { - msleep(100); - abs_state = - instance->instancet->read_fw_status_reg( - instance->reg_set) & MFI_STATE_MASK; - } - if (abs_state <= MFI_STATE_FW_INIT) { - printk(KERN_WARNING "megaraid_sas: firmware " - "state < MFI_STATE_FW_INIT, state = " - "0x%x\n", abs_state); - continue; - } - - /* Wait for FW to become ready */ - if (megasas_transition_to_ready(instance, 1)) { - printk(KERN_WARNING "megaraid_sas: Failed to " - "transition controller to ready.\n"); - continue; - } - - megasas_reset_reply_desc(instance); - if (megasas_ioc_init_fusion(instance)) { - printk(KERN_WARNING "megaraid_sas: " - "megasas_ioc_init_fusion() failed!\n"); - continue; - } - - clear_bit(MEGASAS_FUSION_IN_RESET, - &instance->reset_flags); - instance->instancet->enable_intr(instance->reg_set); - instance->adprecovery = MEGASAS_HBA_OPERATIONAL; - - /* Re-fire management commands */ - for (j = 0 ; j < instance->max_fw_cmds; j++) { - cmd_fusion = fusion->cmd_list[j]; - if (cmd_fusion->sync_cmd_idx != - (u32)ULONG_MAX) { - cmd_mfi = - instance-> - cmd_list[cmd_fusion->sync_cmd_idx]; - if (cmd_mfi->frame->dcmd.opcode == - MR_DCMD_LD_MAP_GET_INFO) { - megasas_return_cmd(instance, - cmd_mfi); - megasas_return_cmd_fusion( - instance, cmd_fusion); - } else { - req_desc = - megasas_get_request_descriptor( - instance, - cmd_mfi->context.smid - -1); - if (!req_desc) - printk(KERN_WARNING - "req_desc NULL" - "\n"); - else { - instance->instancet-> - fire_cmd(instance, - req_desc-> - u.low, - req_desc-> - u.high, - instance-> - reg_set); - } - } - } - } - - /* Reset load balance info */ - memset(fusion->load_balance_info, 0, - sizeof(struct LD_LOAD_BALANCE_INFO) - *MAX_LOGICAL_DRIVES); - - if (!megasas_get_map_info(instance)) - megasas_sync_map_info(instance); - - /* Adapter reset completed successfully */ - printk(KERN_WARNING "megaraid_sas: Reset " - "successful.\n"); - retval = SUCCESS; - goto out; - } - /* Reset failed, kill the adapter */ - printk(KERN_WARNING "megaraid_sas: Reset failed, killing " - "adapter.\n"); - megaraid_sas_kill_hba(instance); - retval = FAILED; - } else { - clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); - instance->instancet->enable_intr(instance->reg_set); - instance->adprecovery = MEGASAS_HBA_OPERATIONAL; - } -out: - clear_bit(MEGASAS_FUSION_IN_RESET, &instance->reset_flags); - mutex_unlock(&instance->reset_mutex); - return retval; -} - -/* Fusion OCR work queue */ -void megasas_fusion_ocr_wq(struct work_struct *work) -{ - struct megasas_instance *instance = - container_of(work, struct megasas_instance, work_init); - - megasas_reset_fusion(instance->host); -} - -struct megasas_instance_template megasas_instance_template_fusion = { - .fire_cmd = megasas_fire_cmd_fusion, - .enable_intr = megasas_enable_intr_fusion, - .disable_intr = megasas_disable_intr_fusion, - .clear_intr = megasas_clear_intr_fusion, - .read_fw_status_reg = megasas_read_fw_status_reg_fusion, - .adp_reset = megasas_adp_reset_fusion, - .check_reset = megasas_check_reset_fusion, - .service_isr = megasas_isr_fusion, - .tasklet = megasas_complete_cmd_dpc_fusion, - .init_adapter = megasas_init_adapter_fusion, - .build_and_issue_cmd = megasas_build_and_issue_cmd_fusion, - .issue_dcmd = megasas_issue_dcmd_fusion, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fusion.h b/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fusion.h deleted file mode 100644 index 088c9f91..00000000 --- a/ANDROID_3.4.5/drivers/scsi/megaraid/megaraid_sas_fusion.h +++ /dev/null @@ -1,706 +0,0 @@ -/* - * Linux MegaRAID driver for SAS based RAID controllers - * - * Copyright (c) 2009-2011 LSI Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * FILE: megaraid_sas_fusion.h - * - * Authors: LSI Corporation - * Manoj Jose - * Sumant Patro - * - * Send feedback to: - * - * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035 - * ATTN: Linuxraid - */ - -#ifndef _MEGARAID_SAS_FUSION_H_ -#define _MEGARAID_SAS_FUSION_H_ - -/* Fusion defines */ -#define MEGASAS_MAX_SZ_CHAIN_FRAME 1024 -#define MFI_FUSION_ENABLE_INTERRUPT_MASK (0x00000009) -#define MEGA_MPI2_RAID_DEFAULT_IO_FRAME_SIZE 256 -#define MEGASAS_MPI2_FUNCTION_PASSTHRU_IO_REQUEST 0xF0 -#define MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST 0xF1 -#define MEGASAS_LOAD_BALANCE_FLAG 0x1 -#define MEGASAS_DCMD_MBOX_PEND_FLAG 0x1 -#define HOST_DIAG_WRITE_ENABLE 0x80 -#define HOST_DIAG_RESET_ADAPTER 0x4 -#define MEGASAS_FUSION_MAX_RESET_TRIES 3 -#define MAX_MSIX_QUEUES_FUSION 16 - -/* Invader defines */ -#define MPI2_TYPE_CUDA 0x2 -#define MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH 0x4000 -#define MR_RL_FLAGS_GRANT_DESTINATION_CPU0 0x00 -#define MR_RL_FLAGS_GRANT_DESTINATION_CPU1 0x10 -#define MR_RL_FLAGS_GRANT_DESTINATION_CUDA 0x80 -#define MR_RL_FLAGS_SEQ_NUM_ENABLE 0x8 - -/* T10 PI defines */ -#define MR_PROT_INFO_TYPE_CONTROLLER 0x8 -#define MEGASAS_SCSI_VARIABLE_LENGTH_CMD 0x7f -#define MEGASAS_SCSI_SERVICE_ACTION_READ32 0x9 -#define MEGASAS_SCSI_SERVICE_ACTION_WRITE32 0xB -#define MEGASAS_SCSI_ADDL_CDB_LEN 0x18 -#define MEGASAS_RD_WR_PROTECT_CHECK_ALL 0x20 -#define MEGASAS_RD_WR_PROTECT_CHECK_NONE 0x60 -#define MEGASAS_EEDPBLOCKSIZE 512 - -/* - * Raid context flags - */ - -#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT 0x4 -#define MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_MASK 0x30 -enum MR_RAID_FLAGS_IO_SUB_TYPE { - MR_RAID_FLAGS_IO_SUB_TYPE_NONE = 0, - MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD = 1, -}; - -/* - * Request descriptor types - */ -#define MEGASAS_REQ_DESCRIPT_FLAGS_LD_IO 0x7 -#define MEGASAS_REQ_DESCRIPT_FLAGS_MFA 0x1 -#define MEGASAS_REQ_DESCRIPT_FLAGS_NO_LOCK 0x2 -#define MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT 1 - -#define MEGASAS_FP_CMD_LEN 16 -#define MEGASAS_FUSION_IN_RESET 0 - -/* - * Raid Context structure which describes MegaRAID specific IO Paramenters - * This resides at offset 0x60 where the SGL normally starts in MPT IO Frames - */ - -struct RAID_CONTEXT { - u8 Type:4; - u8 nseg:4; - u8 resvd0; - u16 timeoutValue; - u8 regLockFlags; - u8 resvd1; - u16 VirtualDiskTgtId; - u64 regLockRowLBA; - u32 regLockLength; - u16 nextLMId; - u8 exStatus; - u8 status; - u8 RAIDFlags; - u8 numSGE; - u16 configSeqNum; - u8 spanArm; - u8 resvd2[3]; -}; - -#define RAID_CTX_SPANARM_ARM_SHIFT (0) -#define RAID_CTX_SPANARM_ARM_MASK (0x1f) - -#define RAID_CTX_SPANARM_SPAN_SHIFT (5) -#define RAID_CTX_SPANARM_SPAN_MASK (0xE0) - -/* - * define region lock types - */ -enum REGION_TYPE { - REGION_TYPE_UNUSED = 0, - REGION_TYPE_SHARED_READ = 1, - REGION_TYPE_SHARED_WRITE = 2, - REGION_TYPE_EXCLUSIVE = 3, -}; - -/* MPI2 defines */ -#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ -#define MPI2_WHOINIT_HOST_DRIVER (0x04) -#define MPI2_VERSION_MAJOR (0x02) -#define MPI2_VERSION_MINOR (0x00) -#define MPI2_VERSION_MAJOR_MASK (0xFF00) -#define MPI2_VERSION_MAJOR_SHIFT (8) -#define MPI2_VERSION_MINOR_MASK (0x00FF) -#define MPI2_VERSION_MINOR_SHIFT (0) -#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ - MPI2_VERSION_MINOR) -#define MPI2_HEADER_VERSION_UNIT (0x10) -#define MPI2_HEADER_VERSION_DEV (0x00) -#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) -#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) -#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) -#define MPI2_HEADER_VERSION_DEV_SHIFT (0) -#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | \ - MPI2_HEADER_VERSION_DEV) -#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) -#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) -#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) -#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ -#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) -#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) -#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) -#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) -#define MPI2_SCSIIO_CONTROL_READ (0x02000000) -#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) -#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) -#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) -#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) -#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) -#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) -#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) -#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) -#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) -#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) -#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) -#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) - -struct MPI25_IEEE_SGE_CHAIN64 { - u64 Address; - u32 Length; - u16 Reserved1; - u8 NextChainOffset; - u8 Flags; -}; - -struct MPI2_SGE_SIMPLE_UNION { - u32 FlagsLength; - union { - u32 Address32; - u64 Address64; - } u; -}; - -struct MPI2_SCSI_IO_CDB_EEDP32 { - u8 CDB[20]; /* 0x00 */ - u32 PrimaryReferenceTag; /* 0x14 */ - u16 PrimaryApplicationTag; /* 0x18 */ - u16 PrimaryApplicationTagMask; /* 0x1A */ - u32 TransferLength; /* 0x1C */ -}; - -struct MPI2_SGE_CHAIN_UNION { - u16 Length; - u8 NextChainOffset; - u8 Flags; - union { - u32 Address32; - u64 Address64; - } u; -}; - -struct MPI2_IEEE_SGE_SIMPLE32 { - u32 Address; - u32 FlagsLength; -}; - -struct MPI2_IEEE_SGE_CHAIN32 { - u32 Address; - u32 FlagsLength; -}; - -struct MPI2_IEEE_SGE_SIMPLE64 { - u64 Address; - u32 Length; - u16 Reserved1; - u8 Reserved2; - u8 Flags; -}; - -struct MPI2_IEEE_SGE_CHAIN64 { - u64 Address; - u32 Length; - u16 Reserved1; - u8 Reserved2; - u8 Flags; -}; - -union MPI2_IEEE_SGE_SIMPLE_UNION { - struct MPI2_IEEE_SGE_SIMPLE32 Simple32; - struct MPI2_IEEE_SGE_SIMPLE64 Simple64; -}; - -union MPI2_IEEE_SGE_CHAIN_UNION { - struct MPI2_IEEE_SGE_CHAIN32 Chain32; - struct MPI2_IEEE_SGE_CHAIN64 Chain64; -}; - -union MPI2_SGE_IO_UNION { - struct MPI2_SGE_SIMPLE_UNION MpiSimple; - struct MPI2_SGE_CHAIN_UNION MpiChain; - union MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; - union MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; -}; - -union MPI2_SCSI_IO_CDB_UNION { - u8 CDB32[32]; - struct MPI2_SCSI_IO_CDB_EEDP32 EEDP32; - struct MPI2_SGE_SIMPLE_UNION SGE; -}; - -/* - * RAID SCSI IO Request Message - * Total SGE count will be one less than _MPI2_SCSI_IO_REQUEST - */ -struct MPI2_RAID_SCSI_IO_REQUEST { - u16 DevHandle; /* 0x00 */ - u8 ChainOffset; /* 0x02 */ - u8 Function; /* 0x03 */ - u16 Reserved1; /* 0x04 */ - u8 Reserved2; /* 0x06 */ - u8 MsgFlags; /* 0x07 */ - u8 VP_ID; /* 0x08 */ - u8 VF_ID; /* 0x09 */ - u16 Reserved3; /* 0x0A */ - u32 SenseBufferLowAddress; /* 0x0C */ - u16 SGLFlags; /* 0x10 */ - u8 SenseBufferLength; /* 0x12 */ - u8 Reserved4; /* 0x13 */ - u8 SGLOffset0; /* 0x14 */ - u8 SGLOffset1; /* 0x15 */ - u8 SGLOffset2; /* 0x16 */ - u8 SGLOffset3; /* 0x17 */ - u32 SkipCount; /* 0x18 */ - u32 DataLength; /* 0x1C */ - u32 BidirectionalDataLength; /* 0x20 */ - u16 IoFlags; /* 0x24 */ - u16 EEDPFlags; /* 0x26 */ - u32 EEDPBlockSize; /* 0x28 */ - u32 SecondaryReferenceTag; /* 0x2C */ - u16 SecondaryApplicationTag; /* 0x30 */ - u16 ApplicationTagTranslationMask; /* 0x32 */ - u8 LUN[8]; /* 0x34 */ - u32 Control; /* 0x3C */ - union MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ - struct RAID_CONTEXT RaidContext; /* 0x60 */ - union MPI2_SGE_IO_UNION SGL; /* 0x80 */ -}; - -/* - * MPT RAID MFA IO Descriptor. - */ -struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR { - u32 RequestFlags:8; - u32 MessageAddress1:24; /* bits 31:8*/ - u32 MessageAddress2; /* bits 61:32 */ -}; - -/* Default Request Descriptor */ -struct MPI2_DEFAULT_REQUEST_DESCRIPTOR { - u8 RequestFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u16 LMID; /* 0x04 */ - u16 DescriptorTypeDependent; /* 0x06 */ -}; - -/* High Priority Request Descriptor */ -struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR { - u8 RequestFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u16 LMID; /* 0x04 */ - u16 Reserved1; /* 0x06 */ -}; - -/* SCSI IO Request Descriptor */ -struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR { - u8 RequestFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u16 LMID; /* 0x04 */ - u16 DevHandle; /* 0x06 */ -}; - -/* SCSI Target Request Descriptor */ -struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR { - u8 RequestFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u16 LMID; /* 0x04 */ - u16 IoIndex; /* 0x06 */ -}; - -/* RAID Accelerator Request Descriptor */ -struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { - u8 RequestFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u16 LMID; /* 0x04 */ - u16 Reserved; /* 0x06 */ -}; - -/* union of Request Descriptors */ -union MEGASAS_REQUEST_DESCRIPTOR_UNION { - struct MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; - struct MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; - struct MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; - struct MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; - struct MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; - struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR MFAIo; - union { - struct { - u32 low; - u32 high; - } u; - u64 Words; - }; -}; - -/* Default Reply Descriptor */ -struct MPI2_DEFAULT_REPLY_DESCRIPTOR { - u8 ReplyFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 DescriptorTypeDependent1; /* 0x02 */ - u32 DescriptorTypeDependent2; /* 0x04 */ -}; - -/* Address Reply Descriptor */ -struct MPI2_ADDRESS_REPLY_DESCRIPTOR { - u8 ReplyFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u32 ReplyFrameAddress; /* 0x04 */ -}; - -/* SCSI IO Success Reply Descriptor */ -struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR { - u8 ReplyFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u16 TaskTag; /* 0x04 */ - u16 Reserved1; /* 0x06 */ -}; - -/* TargetAssist Success Reply Descriptor */ -struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR { - u8 ReplyFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u8 SequenceNumber; /* 0x04 */ - u8 Reserved1; /* 0x05 */ - u16 IoIndex; /* 0x06 */ -}; - -/* Target Command Buffer Reply Descriptor */ -struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR { - u8 ReplyFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u8 VP_ID; /* 0x02 */ - u8 Flags; /* 0x03 */ - u16 InitiatorDevHandle; /* 0x04 */ - u16 IoIndex; /* 0x06 */ -}; - -/* RAID Accelerator Success Reply Descriptor */ -struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { - u8 ReplyFlags; /* 0x00 */ - u8 MSIxIndex; /* 0x01 */ - u16 SMID; /* 0x02 */ - u32 Reserved; /* 0x04 */ -}; - -/* union of Reply Descriptors */ -union MPI2_REPLY_DESCRIPTORS_UNION { - struct MPI2_DEFAULT_REPLY_DESCRIPTOR Default; - struct MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; - struct MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; - struct MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; - struct MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; - struct MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR - RAIDAcceleratorSuccess; - u64 Words; -}; - -/* IOCInit Request message */ -struct MPI2_IOC_INIT_REQUEST { - u8 WhoInit; /* 0x00 */ - u8 Reserved1; /* 0x01 */ - u8 ChainOffset; /* 0x02 */ - u8 Function; /* 0x03 */ - u16 Reserved2; /* 0x04 */ - u8 Reserved3; /* 0x06 */ - u8 MsgFlags; /* 0x07 */ - u8 VP_ID; /* 0x08 */ - u8 VF_ID; /* 0x09 */ - u16 Reserved4; /* 0x0A */ - u16 MsgVersion; /* 0x0C */ - u16 HeaderVersion; /* 0x0E */ - u32 Reserved5; /* 0x10 */ - u16 Reserved6; /* 0x14 */ - u8 Reserved7; /* 0x16 */ - u8 HostMSIxVectors; /* 0x17 */ - u16 Reserved8; /* 0x18 */ - u16 SystemRequestFrameSize; /* 0x1A */ - u16 ReplyDescriptorPostQueueDepth; /* 0x1C */ - u16 ReplyFreeQueueDepth; /* 0x1E */ - u32 SenseBufferAddressHigh; /* 0x20 */ - u32 SystemReplyAddressHigh; /* 0x24 */ - u64 SystemRequestFrameBaseAddress; /* 0x28 */ - u64 ReplyDescriptorPostQueueAddress;/* 0x30 */ - u64 ReplyFreeQueueAddress; /* 0x38 */ - u64 TimeStamp; /* 0x40 */ -}; - -/* mrpriv defines */ -#define MR_PD_INVALID 0xFFFF -#define MAX_SPAN_DEPTH 8 -#define MAX_RAIDMAP_SPAN_DEPTH (MAX_SPAN_DEPTH) -#define MAX_ROW_SIZE 32 -#define MAX_RAIDMAP_ROW_SIZE (MAX_ROW_SIZE) -#define MAX_LOGICAL_DRIVES 64 -#define MAX_RAIDMAP_LOGICAL_DRIVES (MAX_LOGICAL_DRIVES) -#define MAX_RAIDMAP_VIEWS (MAX_LOGICAL_DRIVES) -#define MAX_ARRAYS 128 -#define MAX_RAIDMAP_ARRAYS (MAX_ARRAYS) -#define MAX_PHYSICAL_DEVICES 256 -#define MAX_RAIDMAP_PHYSICAL_DEVICES (MAX_PHYSICAL_DEVICES) -#define MR_DCMD_LD_MAP_GET_INFO 0x0300e101 - -struct MR_DEV_HANDLE_INFO { - u16 curDevHdl; - u8 validHandles; - u8 reserved; - u16 devHandle[2]; -}; - -struct MR_ARRAY_INFO { - u16 pd[MAX_RAIDMAP_ROW_SIZE]; -}; - -struct MR_QUAD_ELEMENT { - u64 logStart; - u64 logEnd; - u64 offsetInSpan; - u32 diff; - u32 reserved1; -}; - -struct MR_SPAN_INFO { - u32 noElements; - u32 reserved1; - struct MR_QUAD_ELEMENT quad[MAX_RAIDMAP_SPAN_DEPTH]; -}; - -struct MR_LD_SPAN { - u64 startBlk; - u64 numBlks; - u16 arrayRef; - u8 reserved[6]; -}; - -struct MR_SPAN_BLOCK_INFO { - u64 num_rows; - struct MR_LD_SPAN span; - struct MR_SPAN_INFO block_span_info; -}; - -struct MR_LD_RAID { - struct { - u32 fpCapable:1; - u32 reserved5:3; - u32 ldPiMode:4; - u32 pdPiMode:4; - u32 encryptionType:8; - u32 fpWriteCapable:1; - u32 fpReadCapable:1; - u32 fpWriteAcrossStripe:1; - u32 fpReadAcrossStripe:1; - u32 reserved4:8; - } capability; - u32 reserved6; - u64 size; - u8 spanDepth; - u8 level; - u8 stripeShift; - u8 rowSize; - u8 rowDataSize; - u8 writeMode; - u8 PRL; - u8 SRL; - u16 targetId; - u8 ldState; - u8 regTypeReqOnWrite; - u8 modFactor; - u8 regTypeReqOnRead; - u16 seqNum; - - struct { - u32 ldSyncRequired:1; - u32 reserved:31; - } flags; - - u8 reserved3[0x5C]; -}; - -struct MR_LD_SPAN_MAP { - struct MR_LD_RAID ldRaid; - u8 dataArmMap[MAX_RAIDMAP_ROW_SIZE]; - struct MR_SPAN_BLOCK_INFO spanBlock[MAX_RAIDMAP_SPAN_DEPTH]; -}; - -struct MR_FW_RAID_MAP { - u32 totalSize; - union { - struct { - u32 maxLd; - u32 maxSpanDepth; - u32 maxRowSize; - u32 maxPdCount; - u32 maxArrays; - } validationInfo; - u32 version[5]; - u32 reserved1[5]; - }; - - u32 ldCount; - u32 Reserved1; - u8 ldTgtIdToLd[MAX_RAIDMAP_LOGICAL_DRIVES+ - MAX_RAIDMAP_VIEWS]; - u8 fpPdIoTimeoutSec; - u8 reserved2[7]; - struct MR_ARRAY_INFO arMapInfo[MAX_RAIDMAP_ARRAYS]; - struct MR_DEV_HANDLE_INFO devHndlInfo[MAX_RAIDMAP_PHYSICAL_DEVICES]; - struct MR_LD_SPAN_MAP ldSpanMap[1]; -}; - -struct IO_REQUEST_INFO { - u64 ldStartBlock; - u32 numBlocks; - u16 ldTgtId; - u8 isRead; - u16 devHandle; - u64 pdBlock; - u8 fpOkForIo; -}; - -struct MR_LD_TARGET_SYNC { - u8 targetId; - u8 reserved; - u16 seqNum; -}; - -#define IEEE_SGE_FLAGS_ADDR_MASK (0x03) -#define IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) -#define IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) -#define IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) -#define IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) -#define IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) -#define IEEE_SGE_FLAGS_END_OF_LIST (0x40) - -struct megasas_register_set; -struct megasas_instance; - -union desc_word { - u64 word; - struct { - u32 low; - u32 high; - } u; -}; - -struct megasas_cmd_fusion { - struct MPI2_RAID_SCSI_IO_REQUEST *io_request; - dma_addr_t io_request_phys_addr; - - union MPI2_SGE_IO_UNION *sg_frame; - dma_addr_t sg_frame_phys_addr; - - u8 *sense; - dma_addr_t sense_phys_addr; - - struct list_head list; - struct scsi_cmnd *scmd; - struct megasas_instance *instance; - - u8 retry_for_fw_reset; - union MEGASAS_REQUEST_DESCRIPTOR_UNION *request_desc; - - /* - * Context for a MFI frame. - * Used to get the mfi cmd from list when a MFI cmd is completed - */ - u32 sync_cmd_idx; - u32 index; - u8 flags; -}; - -struct LD_LOAD_BALANCE_INFO { - u8 loadBalanceFlag; - u8 reserved1; - u16 raid1DevHandle[2]; - atomic_t scsi_pending_cmds[2]; - u64 last_accessed_block[2]; -}; - -struct MR_FW_RAID_MAP_ALL { - struct MR_FW_RAID_MAP raidMap; - struct MR_LD_SPAN_MAP ldSpanMap[MAX_LOGICAL_DRIVES - 1]; -} __attribute__ ((packed)); - -struct fusion_context { - struct megasas_cmd_fusion **cmd_list; - struct list_head cmd_pool; - - spinlock_t cmd_pool_lock; - - dma_addr_t req_frames_desc_phys; - u8 *req_frames_desc; - - struct dma_pool *io_request_frames_pool; - dma_addr_t io_request_frames_phys; - u8 *io_request_frames; - - struct dma_pool *sg_dma_pool; - struct dma_pool *sense_dma_pool; - - dma_addr_t reply_frames_desc_phys; - union MPI2_REPLY_DESCRIPTORS_UNION *reply_frames_desc; - struct dma_pool *reply_frames_desc_pool; - - u16 last_reply_idx[MAX_MSIX_QUEUES_FUSION]; - - u32 reply_q_depth; - u32 request_alloc_sz; - u32 reply_alloc_sz; - u32 io_frames_alloc_sz; - - u16 max_sge_in_main_msg; - u16 max_sge_in_chain; - - u8 chain_offset_io_request; - u8 chain_offset_mfi_pthru; - - struct MR_FW_RAID_MAP_ALL *ld_map[2]; - dma_addr_t ld_map_phys[2]; - - u32 map_sz; - u8 fast_path_io; - struct LD_LOAD_BALANCE_INFO load_balance_info[MAX_LOGICAL_DRIVES]; -}; - -union desc_value { - u64 word; - struct { - u32 low; - u32 high; - } u; -}; - -#endif /* _MEGARAID_SAS_FUSION_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/mesh.c b/ANDROID_3.4.5/drivers/scsi/mesh.c deleted file mode 100644 index e8a04ae3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mesh.c +++ /dev/null @@ -1,2076 +0,0 @@ -/* - * SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware) - * bus adaptor found on Power Macintosh computers. - * We assume the MESH is connected to a DBDMA (descriptor-based DMA) - * controller. - * - * Paul Mackerras, August 1996. - * Copyright (C) 1996 Paul Mackerras. - * - * Apr. 21 2002 - BenH Rework bus reset code for new error handler - * Add delay after initial bus reset - * Add module parameters - * - * Sep. 27 2003 - BenH Move to new driver model, fix some write posting - * issues - * To do: - * - handle aborts correctly - * - retry arbitration if lost (unless higher levels do this for us) - * - power down the chip when no device is detected - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "mesh.h" - -#if 1 -#undef KERN_DEBUG -#define KERN_DEBUG KERN_WARNING -#endif - -MODULE_AUTHOR("Paul Mackerras (paulus@samba.org)"); -MODULE_DESCRIPTION("PowerMac MESH SCSI driver"); -MODULE_LICENSE("GPL"); - -static int sync_rate = CONFIG_SCSI_MESH_SYNC_RATE; -static int sync_targets = 0xff; -static int resel_targets = 0xff; -static int debug_targets = 0; /* print debug for these targets */ -static int init_reset_delay = CONFIG_SCSI_MESH_RESET_DELAY_MS; - -module_param(sync_rate, int, 0); -MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)"); -module_param(sync_targets, int, 0); -MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous"); -module_param(resel_targets, int, 0); -MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect"); -module_param(debug_targets, int, 0644); -MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets"); -module_param(init_reset_delay, int, 0); -MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)"); - -static int mesh_sync_period = 100; -static int mesh_sync_offset = 0; -static unsigned char use_active_neg = 0; /* bit mask for SEQ_ACTIVE_NEG if used */ - -#define ALLOW_SYNC(tgt) ((sync_targets >> (tgt)) & 1) -#define ALLOW_RESEL(tgt) ((resel_targets >> (tgt)) & 1) -#define ALLOW_DEBUG(tgt) ((debug_targets >> (tgt)) & 1) -#define DEBUG_TARGET(cmd) ((cmd) && ALLOW_DEBUG((cmd)->device->id)) - -#undef MESH_DBG -#define N_DBG_LOG 50 -#define N_DBG_SLOG 20 -#define NUM_DBG_EVENTS 13 -#undef DBG_USE_TB /* bombs on 601 */ - -struct dbglog { - char *fmt; - u32 tb; - u8 phase; - u8 bs0; - u8 bs1; - u8 tgt; - int d; -}; - -enum mesh_phase { - idle, - arbitrating, - selecting, - commanding, - dataing, - statusing, - busfreeing, - disconnecting, - reselecting, - sleeping -}; - -enum msg_phase { - msg_none, - msg_out, - msg_out_xxx, - msg_out_last, - msg_in, - msg_in_bad, -}; - -enum sdtr_phase { - do_sdtr, - sdtr_sent, - sdtr_done -}; - -struct mesh_target { - enum sdtr_phase sdtr_state; - int sync_params; - int data_goes_out; /* guess as to data direction */ - struct scsi_cmnd *current_req; - u32 saved_ptr; -#ifdef MESH_DBG - int log_ix; - int n_log; - struct dbglog log[N_DBG_LOG]; -#endif -}; - -struct mesh_state { - volatile struct mesh_regs __iomem *mesh; - int meshintr; - volatile struct dbdma_regs __iomem *dma; - int dmaintr; - struct Scsi_Host *host; - struct mesh_state *next; - struct scsi_cmnd *request_q; - struct scsi_cmnd *request_qtail; - enum mesh_phase phase; /* what we're currently trying to do */ - enum msg_phase msgphase; - int conn_tgt; /* target we're connected to */ - struct scsi_cmnd *current_req; /* req we're currently working on */ - int data_ptr; - int dma_started; - int dma_count; - int stat; - int aborting; - int expect_reply; - int n_msgin; - u8 msgin[16]; - int n_msgout; - int last_n_msgout; - u8 msgout[16]; - struct dbdma_cmd *dma_cmds; /* space for dbdma commands, aligned */ - dma_addr_t dma_cmd_bus; - void *dma_cmd_space; - int dma_cmd_size; - int clk_freq; - struct mesh_target tgts[8]; - struct macio_dev *mdev; - struct pci_dev* pdev; -#ifdef MESH_DBG - int log_ix; - int n_log; - struct dbglog log[N_DBG_SLOG]; -#endif -}; - -/* - * Driver is too messy, we need a few prototypes... - */ -static void mesh_done(struct mesh_state *ms, int start_next); -static void mesh_interrupt(struct mesh_state *ms); -static void cmd_complete(struct mesh_state *ms); -static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd); -static void halt_dma(struct mesh_state *ms); -static void phase_mismatch(struct mesh_state *ms); - - -/* - * Some debugging & logging routines - */ - -#ifdef MESH_DBG - -static inline u32 readtb(void) -{ - u32 tb; - -#ifdef DBG_USE_TB - /* Beware: if you enable this, it will crash on 601s. */ - asm ("mftb %0" : "=r" (tb) : ); -#else - tb = 0; -#endif - return tb; -} - -static void dlog(struct mesh_state *ms, char *fmt, int a) -{ - struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; - struct dbglog *tlp, *slp; - - tlp = &tp->log[tp->log_ix]; - slp = &ms->log[ms->log_ix]; - tlp->fmt = fmt; - tlp->tb = readtb(); - tlp->phase = (ms->msgphase << 4) + ms->phase; - tlp->bs0 = ms->mesh->bus_status0; - tlp->bs1 = ms->mesh->bus_status1; - tlp->tgt = ms->conn_tgt; - tlp->d = a; - *slp = *tlp; - if (++tp->log_ix >= N_DBG_LOG) - tp->log_ix = 0; - if (tp->n_log < N_DBG_LOG) - ++tp->n_log; - if (++ms->log_ix >= N_DBG_SLOG) - ms->log_ix = 0; - if (ms->n_log < N_DBG_SLOG) - ++ms->n_log; -} - -static void dumplog(struct mesh_state *ms, int t) -{ - struct mesh_target *tp = &ms->tgts[t]; - struct dbglog *lp; - int i; - - if (tp->n_log == 0) - return; - i = tp->log_ix - tp->n_log; - if (i < 0) - i += N_DBG_LOG; - tp->n_log = 0; - do { - lp = &tp->log[i]; - printk(KERN_DEBUG "mesh log %d: bs=%.2x%.2x ph=%.2x ", - t, lp->bs1, lp->bs0, lp->phase); -#ifdef DBG_USE_TB - printk("tb=%10u ", lp->tb); -#endif - printk(lp->fmt, lp->d); - printk("\n"); - if (++i >= N_DBG_LOG) - i = 0; - } while (i != tp->log_ix); -} - -static void dumpslog(struct mesh_state *ms) -{ - struct dbglog *lp; - int i; - - if (ms->n_log == 0) - return; - i = ms->log_ix - ms->n_log; - if (i < 0) - i += N_DBG_SLOG; - ms->n_log = 0; - do { - lp = &ms->log[i]; - printk(KERN_DEBUG "mesh log: bs=%.2x%.2x ph=%.2x t%d ", - lp->bs1, lp->bs0, lp->phase, lp->tgt); -#ifdef DBG_USE_TB - printk("tb=%10u ", lp->tb); -#endif - printk(lp->fmt, lp->d); - printk("\n"); - if (++i >= N_DBG_SLOG) - i = 0; - } while (i != ms->log_ix); -} - -#else - -static inline void dlog(struct mesh_state *ms, char *fmt, int a) -{} -static inline void dumplog(struct mesh_state *ms, int tgt) -{} -static inline void dumpslog(struct mesh_state *ms) -{} - -#endif /* MESH_DBG */ - -#define MKWORD(a, b, c, d) (((a) << 24) + ((b) << 16) + ((c) << 8) + (d)) - -static void -mesh_dump_regs(struct mesh_state *ms) -{ - volatile struct mesh_regs __iomem *mr = ms->mesh; - volatile struct dbdma_regs __iomem *md = ms->dma; - int t; - struct mesh_target *tp; - - printk(KERN_DEBUG "mesh: state at %p, regs at %p, dma at %p\n", - ms, mr, md); - printk(KERN_DEBUG " ct=%4x seq=%2x bs=%4x fc=%2x " - "exc=%2x err=%2x im=%2x int=%2x sp=%2x\n", - (mr->count_hi << 8) + mr->count_lo, mr->sequence, - (mr->bus_status1 << 8) + mr->bus_status0, mr->fifo_count, - mr->exception, mr->error, mr->intr_mask, mr->interrupt, - mr->sync_params); - while(in_8(&mr->fifo_count)) - printk(KERN_DEBUG " fifo data=%.2x\n",in_8(&mr->fifo)); - printk(KERN_DEBUG " dma stat=%x cmdptr=%x\n", - in_le32(&md->status), in_le32(&md->cmdptr)); - printk(KERN_DEBUG " phase=%d msgphase=%d conn_tgt=%d data_ptr=%d\n", - ms->phase, ms->msgphase, ms->conn_tgt, ms->data_ptr); - printk(KERN_DEBUG " dma_st=%d dma_ct=%d n_msgout=%d\n", - ms->dma_started, ms->dma_count, ms->n_msgout); - for (t = 0; t < 8; ++t) { - tp = &ms->tgts[t]; - if (tp->current_req == NULL) - continue; - printk(KERN_DEBUG " target %d: req=%p goes_out=%d saved_ptr=%d\n", - t, tp->current_req, tp->data_goes_out, tp->saved_ptr); - } -} - - -/* - * Flush write buffers on the bus path to the mesh - */ -static inline void mesh_flush_io(volatile struct mesh_regs __iomem *mr) -{ - (void)in_8(&mr->mesh_id); -} - - -/* - * Complete a SCSI command - */ -static void mesh_completed(struct mesh_state *ms, struct scsi_cmnd *cmd) -{ - (*cmd->scsi_done)(cmd); -} - - -/* Called with meshinterrupt disabled, initialize the chipset - * and eventually do the initial bus reset. The lock must not be - * held since we can schedule. - */ -static void mesh_init(struct mesh_state *ms) -{ - volatile struct mesh_regs __iomem *mr = ms->mesh; - volatile struct dbdma_regs __iomem *md = ms->dma; - - mesh_flush_io(mr); - udelay(100); - - /* Reset controller */ - out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */ - out_8(&mr->exception, 0xff); /* clear all exception bits */ - out_8(&mr->error, 0xff); /* clear all error bits */ - out_8(&mr->sequence, SEQ_RESETMESH); - mesh_flush_io(mr); - udelay(10); - out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - out_8(&mr->source_id, ms->host->this_id); - out_8(&mr->sel_timeout, 25); /* 250ms */ - out_8(&mr->sync_params, ASYNC_PARAMS); - - if (init_reset_delay) { - printk(KERN_INFO "mesh: performing initial bus reset...\n"); - - /* Reset bus */ - out_8(&mr->bus_status1, BS1_RST); /* assert RST */ - mesh_flush_io(mr); - udelay(30); /* leave it on for >= 25us */ - out_8(&mr->bus_status1, 0); /* negate RST */ - mesh_flush_io(mr); - - /* Wait for bus to come back */ - msleep(init_reset_delay); - } - - /* Reconfigure controller */ - out_8(&mr->interrupt, 0xff); /* clear all interrupt bits */ - out_8(&mr->sequence, SEQ_FLUSHFIFO); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->sync_params, ASYNC_PARAMS); - out_8(&mr->sequence, SEQ_ENBRESEL); - - ms->phase = idle; - ms->msgphase = msg_none; -} - - -static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd) -{ - volatile struct mesh_regs __iomem *mr = ms->mesh; - int t, id; - - id = cmd->device->id; - ms->current_req = cmd; - ms->tgts[id].data_goes_out = cmd->sc_data_direction == DMA_TO_DEVICE; - ms->tgts[id].current_req = cmd; - -#if 1 - if (DEBUG_TARGET(cmd)) { - int i; - printk(KERN_DEBUG "mesh_start: %p tgt=%d cmd=", cmd, id); - for (i = 0; i < cmd->cmd_len; ++i) - printk(" %x", cmd->cmnd[i]); - printk(" use_sg=%d buffer=%p bufflen=%u\n", - scsi_sg_count(cmd), scsi_sglist(cmd), scsi_bufflen(cmd)); - } -#endif - if (ms->dma_started) - panic("mesh: double DMA start !\n"); - - ms->phase = arbitrating; - ms->msgphase = msg_none; - ms->data_ptr = 0; - ms->dma_started = 0; - ms->n_msgout = 0; - ms->last_n_msgout = 0; - ms->expect_reply = 0; - ms->conn_tgt = id; - ms->tgts[id].saved_ptr = 0; - ms->stat = DID_OK; - ms->aborting = 0; -#ifdef MESH_DBG - ms->tgts[id].n_log = 0; - dlog(ms, "start cmd=%x", (int) cmd); -#endif - - /* Off we go */ - dlog(ms, "about to arb, intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); - out_8(&mr->interrupt, INT_CMDDONE); - out_8(&mr->sequence, SEQ_ENBRESEL); - mesh_flush_io(mr); - udelay(1); - - if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) { - /* - * Some other device has the bus or is arbitrating for it - - * probably a target which is about to reselect us. - */ - dlog(ms, "busy b4 arb, intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, - mr->error, mr->fifo_count)); - for (t = 100; t > 0; --t) { - if ((in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) == 0) - break; - if (in_8(&mr->interrupt) != 0) { - dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, - mr->error, mr->fifo_count)); - mesh_interrupt(ms); - if (ms->phase != arbitrating) - return; - } - udelay(1); - } - if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) { - /* XXX should try again in a little while */ - ms->stat = DID_BUS_BUSY; - ms->phase = idle; - mesh_done(ms, 0); - return; - } - } - - /* - * Apparently the mesh has a bug where it will assert both its - * own bit and the target's bit on the bus during arbitration. - */ - out_8(&mr->dest_id, mr->source_id); - - /* - * There appears to be a race with reselection sometimes, - * where a target reselects us just as we issue the - * arbitrate command. It seems that then the arbitrate - * command just hangs waiting for the bus to be free - * without giving us a reselection exception. - * The only way I have found to get it to respond correctly - * is this: disable reselection before issuing the arbitrate - * command, then after issuing it, if it looks like a target - * is trying to reselect us, reset the mesh and then enable - * reselection. - */ - out_8(&mr->sequence, SEQ_DISRESEL); - if (in_8(&mr->interrupt) != 0) { - dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, - mr->error, mr->fifo_count)); - mesh_interrupt(ms); - if (ms->phase != arbitrating) - return; - dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, - mr->error, mr->fifo_count)); - } - - out_8(&mr->sequence, SEQ_ARBITRATE); - - for (t = 230; t > 0; --t) { - if (in_8(&mr->interrupt) != 0) - break; - udelay(1); - } - dlog(ms, "after arb, intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); - if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL) - && (in_8(&mr->bus_status0) & BS0_IO)) { - /* looks like a reselection - try resetting the mesh */ - dlog(ms, "resel? after arb, intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); - out_8(&mr->sequence, SEQ_RESETMESH); - mesh_flush_io(mr); - udelay(10); - out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - out_8(&mr->sequence, SEQ_ENBRESEL); - mesh_flush_io(mr); - for (t = 10; t > 0 && in_8(&mr->interrupt) == 0; --t) - udelay(1); - dlog(ms, "tried reset after arb, intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count)); -#ifndef MESH_MULTIPLE_HOSTS - if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL) - && (in_8(&mr->bus_status0) & BS0_IO)) { - printk(KERN_ERR "mesh: controller not responding" - " to reselection!\n"); - /* - * If this is a target reselecting us, and the - * mesh isn't responding, the higher levels of - * the scsi code will eventually time out and - * reset the bus. - */ - } -#endif - } -} - -/* - * Start the next command for a MESH. - * Should be called with interrupts disabled. - */ -static void mesh_start(struct mesh_state *ms) -{ - struct scsi_cmnd *cmd, *prev, *next; - - if (ms->phase != idle || ms->current_req != NULL) { - printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)", - ms->phase, ms); - return; - } - - while (ms->phase == idle) { - prev = NULL; - for (cmd = ms->request_q; ; cmd = (struct scsi_cmnd *) cmd->host_scribble) { - if (cmd == NULL) - return; - if (ms->tgts[cmd->device->id].current_req == NULL) - break; - prev = cmd; - } - next = (struct scsi_cmnd *) cmd->host_scribble; - if (prev == NULL) - ms->request_q = next; - else - prev->host_scribble = (void *) next; - if (next == NULL) - ms->request_qtail = prev; - - mesh_start_cmd(ms, cmd); - } -} - -static void mesh_done(struct mesh_state *ms, int start_next) -{ - struct scsi_cmnd *cmd; - struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; - - cmd = ms->current_req; - ms->current_req = NULL; - tp->current_req = NULL; - if (cmd) { - cmd->result = (ms->stat << 16) + cmd->SCp.Status; - if (ms->stat == DID_OK) - cmd->result += (cmd->SCp.Message << 8); - if (DEBUG_TARGET(cmd)) { - printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n", - cmd->result, ms->data_ptr, scsi_bufflen(cmd)); -#if 0 - /* needs to use sg? */ - if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3) - && cmd->request_buffer != 0) { - unsigned char *b = cmd->request_buffer; - printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n", - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]); - } -#endif - } - cmd->SCp.this_residual -= ms->data_ptr; - mesh_completed(ms, cmd); - } - if (start_next) { - out_8(&ms->mesh->sequence, SEQ_ENBRESEL); - mesh_flush_io(ms->mesh); - udelay(1); - ms->phase = idle; - mesh_start(ms); - } -} - -static inline void add_sdtr_msg(struct mesh_state *ms) -{ - int i = ms->n_msgout; - - ms->msgout[i] = EXTENDED_MESSAGE; - ms->msgout[i+1] = 3; - ms->msgout[i+2] = EXTENDED_SDTR; - ms->msgout[i+3] = mesh_sync_period/4; - ms->msgout[i+4] = (ALLOW_SYNC(ms->conn_tgt)? mesh_sync_offset: 0); - ms->n_msgout = i + 5; -} - -static void set_sdtr(struct mesh_state *ms, int period, int offset) -{ - struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; - volatile struct mesh_regs __iomem *mr = ms->mesh; - int v, tr; - - tp->sdtr_state = sdtr_done; - if (offset == 0) { - /* asynchronous */ - if (SYNC_OFF(tp->sync_params)) - printk(KERN_INFO "mesh: target %d now asynchronous\n", - ms->conn_tgt); - tp->sync_params = ASYNC_PARAMS; - out_8(&mr->sync_params, ASYNC_PARAMS); - return; - } - /* - * We need to compute ceil(clk_freq * period / 500e6) - 2 - * without incurring overflow. - */ - v = (ms->clk_freq / 5000) * period; - if (v <= 250000) { - /* special case: sync_period == 5 * clk_period */ - v = 0; - /* units of tr are 100kB/s */ - tr = (ms->clk_freq + 250000) / 500000; - } else { - /* sync_period == (v + 2) * 2 * clk_period */ - v = (v + 99999) / 100000 - 2; - if (v > 15) - v = 15; /* oops */ - tr = ((ms->clk_freq / (v + 2)) + 199999) / 200000; - } - if (offset > 15) - offset = 15; /* can't happen */ - tp->sync_params = SYNC_PARAMS(offset, v); - out_8(&mr->sync_params, tp->sync_params); - printk(KERN_INFO "mesh: target %d synchronous at %d.%d MB/s\n", - ms->conn_tgt, tr/10, tr%10); -} - -static void start_phase(struct mesh_state *ms) -{ - int i, seq, nb; - volatile struct mesh_regs __iomem *mr = ms->mesh; - volatile struct dbdma_regs __iomem *md = ms->dma; - struct scsi_cmnd *cmd = ms->current_req; - struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; - - dlog(ms, "start_phase nmo/exc/fc/seq = %.8x", - MKWORD(ms->n_msgout, mr->exception, mr->fifo_count, mr->sequence)); - out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0); - switch (ms->msgphase) { - case msg_none: - break; - - case msg_in: - out_8(&mr->count_hi, 0); - out_8(&mr->count_lo, 1); - out_8(&mr->sequence, SEQ_MSGIN + seq); - ms->n_msgin = 0; - return; - - case msg_out: - /* - * To make sure ATN drops before we assert ACK for - * the last byte of the message, we have to do the - * last byte specially. - */ - if (ms->n_msgout <= 0) { - printk(KERN_ERR "mesh: msg_out but n_msgout=%d\n", - ms->n_msgout); - mesh_dump_regs(ms); - ms->msgphase = msg_none; - break; - } - if (ALLOW_DEBUG(ms->conn_tgt)) { - printk(KERN_DEBUG "mesh: sending %d msg bytes:", - ms->n_msgout); - for (i = 0; i < ms->n_msgout; ++i) - printk(" %x", ms->msgout[i]); - printk("\n"); - } - dlog(ms, "msgout msg=%.8x", MKWORD(ms->n_msgout, ms->msgout[0], - ms->msgout[1], ms->msgout[2])); - out_8(&mr->count_hi, 0); - out_8(&mr->sequence, SEQ_FLUSHFIFO); - mesh_flush_io(mr); - udelay(1); - /* - * If ATN is not already asserted, we assert it, then - * issue a SEQ_MSGOUT to get the mesh to drop ACK. - */ - if ((in_8(&mr->bus_status0) & BS0_ATN) == 0) { - dlog(ms, "bus0 was %.2x explicitly asserting ATN", mr->bus_status0); - out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */ - mesh_flush_io(mr); - udelay(1); - out_8(&mr->count_lo, 1); - out_8(&mr->sequence, SEQ_MSGOUT + seq); - out_8(&mr->bus_status0, 0); /* release explicit ATN */ - dlog(ms,"hace: after explicit ATN bus0=%.2x",mr->bus_status0); - } - if (ms->n_msgout == 1) { - /* - * We can't issue the SEQ_MSGOUT without ATN - * until the target has asserted REQ. The logic - * in cmd_complete handles both situations: - * REQ already asserted or not. - */ - cmd_complete(ms); - } else { - out_8(&mr->count_lo, ms->n_msgout - 1); - out_8(&mr->sequence, SEQ_MSGOUT + seq); - for (i = 0; i < ms->n_msgout - 1; ++i) - out_8(&mr->fifo, ms->msgout[i]); - } - return; - - default: - printk(KERN_ERR "mesh bug: start_phase msgphase=%d\n", - ms->msgphase); - } - - switch (ms->phase) { - case selecting: - out_8(&mr->dest_id, ms->conn_tgt); - out_8(&mr->sequence, SEQ_SELECT + SEQ_ATN); - break; - case commanding: - out_8(&mr->sync_params, tp->sync_params); - out_8(&mr->count_hi, 0); - if (cmd) { - out_8(&mr->count_lo, cmd->cmd_len); - out_8(&mr->sequence, SEQ_COMMAND + seq); - for (i = 0; i < cmd->cmd_len; ++i) - out_8(&mr->fifo, cmd->cmnd[i]); - } else { - out_8(&mr->count_lo, 6); - out_8(&mr->sequence, SEQ_COMMAND + seq); - for (i = 0; i < 6; ++i) - out_8(&mr->fifo, 0); - } - break; - case dataing: - /* transfer data, if any */ - if (!ms->dma_started) { - set_dma_cmds(ms, cmd); - out_le32(&md->cmdptr, virt_to_phys(ms->dma_cmds)); - out_le32(&md->control, (RUN << 16) | RUN); - ms->dma_started = 1; - } - nb = ms->dma_count; - if (nb > 0xfff0) - nb = 0xfff0; - ms->dma_count -= nb; - ms->data_ptr += nb; - out_8(&mr->count_lo, nb); - out_8(&mr->count_hi, nb >> 8); - out_8(&mr->sequence, (tp->data_goes_out? - SEQ_DATAOUT: SEQ_DATAIN) + SEQ_DMA_MODE + seq); - break; - case statusing: - out_8(&mr->count_hi, 0); - out_8(&mr->count_lo, 1); - out_8(&mr->sequence, SEQ_STATUS + seq); - break; - case busfreeing: - case disconnecting: - out_8(&mr->sequence, SEQ_ENBRESEL); - mesh_flush_io(mr); - udelay(1); - dlog(ms, "enbresel intr/exc/err/fc=%.8x", - MKWORD(mr->interrupt, mr->exception, mr->error, - mr->fifo_count)); - out_8(&mr->sequence, SEQ_BUSFREE); - break; - default: - printk(KERN_ERR "mesh: start_phase called with phase=%d\n", - ms->phase); - dumpslog(ms); - } - -} - -static inline void get_msgin(struct mesh_state *ms) -{ - volatile struct mesh_regs __iomem *mr = ms->mesh; - int i, n; - - n = mr->fifo_count; - if (n != 0) { - i = ms->n_msgin; - ms->n_msgin = i + n; - for (; n > 0; --n) - ms->msgin[i++] = in_8(&mr->fifo); - } -} - -static inline int msgin_length(struct mesh_state *ms) -{ - int b, n; - - n = 1; - if (ms->n_msgin > 0) { - b = ms->msgin[0]; - if (b == 1) { - /* extended message */ - n = ms->n_msgin < 2? 2: ms->msgin[1] + 2; - } else if (0x20 <= b && b <= 0x2f) { - /* 2-byte message */ - n = 2; - } - } - return n; -} - -static void reselected(struct mesh_state *ms) -{ - volatile struct mesh_regs __iomem *mr = ms->mesh; - struct scsi_cmnd *cmd; - struct mesh_target *tp; - int b, t, prev; - - switch (ms->phase) { - case idle: - break; - case arbitrating: - if ((cmd = ms->current_req) != NULL) { - /* put the command back on the queue */ - cmd->host_scribble = (void *) ms->request_q; - if (ms->request_q == NULL) - ms->request_qtail = cmd; - ms->request_q = cmd; - tp = &ms->tgts[cmd->device->id]; - tp->current_req = NULL; - } - break; - case busfreeing: - ms->phase = reselecting; - mesh_done(ms, 0); - break; - case disconnecting: - break; - default: - printk(KERN_ERR "mesh: reselected in phase %d/%d tgt %d\n", - ms->msgphase, ms->phase, ms->conn_tgt); - dumplog(ms, ms->conn_tgt); - dumpslog(ms); - } - - if (ms->dma_started) { - printk(KERN_ERR "mesh: reselected with DMA started !\n"); - halt_dma(ms); - } - ms->current_req = NULL; - ms->phase = dataing; - ms->msgphase = msg_in; - ms->n_msgout = 0; - ms->last_n_msgout = 0; - prev = ms->conn_tgt; - - /* - * We seem to get abortive reselections sometimes. - */ - while ((in_8(&mr->bus_status1) & BS1_BSY) == 0) { - static int mesh_aborted_resels; - mesh_aborted_resels++; - out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->sequence, SEQ_ENBRESEL); - mesh_flush_io(mr); - udelay(5); - dlog(ms, "extra resel err/exc/fc = %.6x", - MKWORD(0, mr->error, mr->exception, mr->fifo_count)); - } - out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->sequence, SEQ_ENBRESEL); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->sync_params, ASYNC_PARAMS); - - /* - * Find out who reselected us. - */ - if (in_8(&mr->fifo_count) == 0) { - printk(KERN_ERR "mesh: reselection but nothing in fifo?\n"); - ms->conn_tgt = ms->host->this_id; - goto bogus; - } - /* get the last byte in the fifo */ - do { - b = in_8(&mr->fifo); - dlog(ms, "reseldata %x", b); - } while (in_8(&mr->fifo_count)); - for (t = 0; t < 8; ++t) - if ((b & (1 << t)) != 0 && t != ms->host->this_id) - break; - if (b != (1 << t) + (1 << ms->host->this_id)) { - printk(KERN_ERR "mesh: bad reselection data %x\n", b); - ms->conn_tgt = ms->host->this_id; - goto bogus; - } - - - /* - * Set up to continue with that target's transfer. - */ - ms->conn_tgt = t; - tp = &ms->tgts[t]; - out_8(&mr->sync_params, tp->sync_params); - if (ALLOW_DEBUG(t)) { - printk(KERN_DEBUG "mesh: reselected by target %d\n", t); - printk(KERN_DEBUG "mesh: saved_ptr=%x goes_out=%d cmd=%p\n", - tp->saved_ptr, tp->data_goes_out, tp->current_req); - } - ms->current_req = tp->current_req; - if (tp->current_req == NULL) { - printk(KERN_ERR "mesh: reselected by tgt %d but no cmd!\n", t); - goto bogus; - } - ms->data_ptr = tp->saved_ptr; - dlog(ms, "resel prev tgt=%d", prev); - dlog(ms, "resel err/exc=%.4x", MKWORD(0, 0, mr->error, mr->exception)); - start_phase(ms); - return; - -bogus: - dumplog(ms, ms->conn_tgt); - dumpslog(ms); - ms->data_ptr = 0; - ms->aborting = 1; - start_phase(ms); -} - -static void do_abort(struct mesh_state *ms) -{ - ms->msgout[0] = ABORT; - ms->n_msgout = 1; - ms->aborting = 1; - ms->stat = DID_ABORT; - dlog(ms, "abort", 0); -} - -static void handle_reset(struct mesh_state *ms) -{ - int tgt; - struct mesh_target *tp; - struct scsi_cmnd *cmd; - volatile struct mesh_regs __iomem *mr = ms->mesh; - - for (tgt = 0; tgt < 8; ++tgt) { - tp = &ms->tgts[tgt]; - if ((cmd = tp->current_req) != NULL) { - cmd->result = DID_RESET << 16; - tp->current_req = NULL; - mesh_completed(ms, cmd); - } - ms->tgts[tgt].sdtr_state = do_sdtr; - ms->tgts[tgt].sync_params = ASYNC_PARAMS; - } - ms->current_req = NULL; - while ((cmd = ms->request_q) != NULL) { - ms->request_q = (struct scsi_cmnd *) cmd->host_scribble; - cmd->result = DID_RESET << 16; - mesh_completed(ms, cmd); - } - ms->phase = idle; - ms->msgphase = msg_none; - out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - out_8(&mr->sequence, SEQ_FLUSHFIFO); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->sync_params, ASYNC_PARAMS); - out_8(&mr->sequence, SEQ_ENBRESEL); -} - -static irqreturn_t do_mesh_interrupt(int irq, void *dev_id) -{ - unsigned long flags; - struct mesh_state *ms = dev_id; - struct Scsi_Host *dev = ms->host; - - spin_lock_irqsave(dev->host_lock, flags); - mesh_interrupt(ms); - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} - -static void handle_error(struct mesh_state *ms) -{ - int err, exc, count; - volatile struct mesh_regs __iomem *mr = ms->mesh; - - err = in_8(&mr->error); - exc = in_8(&mr->exception); - out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - dlog(ms, "error err/exc/fc/cl=%.8x", - MKWORD(err, exc, mr->fifo_count, mr->count_lo)); - if (err & ERR_SCSIRESET) { - /* SCSI bus was reset */ - printk(KERN_INFO "mesh: SCSI bus reset detected: " - "waiting for end..."); - while ((in_8(&mr->bus_status1) & BS1_RST) != 0) - udelay(1); - printk("done\n"); - handle_reset(ms); - /* request_q is empty, no point in mesh_start() */ - return; - } - if (err & ERR_UNEXPDISC) { - /* Unexpected disconnect */ - if (exc & EXC_RESELECTED) { - reselected(ms); - return; - } - if (!ms->aborting) { - printk(KERN_WARNING "mesh: target %d aborted\n", - ms->conn_tgt); - dumplog(ms, ms->conn_tgt); - dumpslog(ms); - } - out_8(&mr->interrupt, INT_CMDDONE); - ms->stat = DID_ABORT; - mesh_done(ms, 1); - return; - } - if (err & ERR_PARITY) { - if (ms->msgphase == msg_in) { - printk(KERN_ERR "mesh: msg parity error, target %d\n", - ms->conn_tgt); - ms->msgout[0] = MSG_PARITY_ERROR; - ms->n_msgout = 1; - ms->msgphase = msg_in_bad; - cmd_complete(ms); - return; - } - if (ms->stat == DID_OK) { - printk(KERN_ERR "mesh: parity error, target %d\n", - ms->conn_tgt); - ms->stat = DID_PARITY; - } - count = (mr->count_hi << 8) + mr->count_lo; - if (count == 0) { - cmd_complete(ms); - } else { - /* reissue the data transfer command */ - out_8(&mr->sequence, mr->sequence); - } - return; - } - if (err & ERR_SEQERR) { - if (exc & EXC_RESELECTED) { - /* This can happen if we issue a command to - get the bus just after the target reselects us. */ - static int mesh_resel_seqerr; - mesh_resel_seqerr++; - reselected(ms); - return; - } - if (exc == EXC_PHASEMM) { - static int mesh_phasemm_seqerr; - mesh_phasemm_seqerr++; - phase_mismatch(ms); - return; - } - printk(KERN_ERR "mesh: sequence error (err=%x exc=%x)\n", - err, exc); - } else { - printk(KERN_ERR "mesh: unknown error %x (exc=%x)\n", err, exc); - } - mesh_dump_regs(ms); - dumplog(ms, ms->conn_tgt); - if (ms->phase > selecting && (in_8(&mr->bus_status1) & BS1_BSY)) { - /* try to do what the target wants */ - do_abort(ms); - phase_mismatch(ms); - return; - } - ms->stat = DID_ERROR; - mesh_done(ms, 1); -} - -static void handle_exception(struct mesh_state *ms) -{ - int exc; - volatile struct mesh_regs __iomem *mr = ms->mesh; - - exc = in_8(&mr->exception); - out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE); - if (exc & EXC_RESELECTED) { - static int mesh_resel_exc; - mesh_resel_exc++; - reselected(ms); - } else if (exc == EXC_ARBLOST) { - printk(KERN_DEBUG "mesh: lost arbitration\n"); - ms->stat = DID_BUS_BUSY; - mesh_done(ms, 1); - } else if (exc == EXC_SELTO) { - /* selection timed out */ - ms->stat = DID_BAD_TARGET; - mesh_done(ms, 1); - } else if (exc == EXC_PHASEMM) { - /* target wants to do something different: - find out what it wants and do it. */ - phase_mismatch(ms); - } else { - printk(KERN_ERR "mesh: can't cope with exception %x\n", exc); - mesh_dump_regs(ms); - dumplog(ms, ms->conn_tgt); - do_abort(ms); - phase_mismatch(ms); - } -} - -static void handle_msgin(struct mesh_state *ms) -{ - int i, code; - struct scsi_cmnd *cmd = ms->current_req; - struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; - - if (ms->n_msgin == 0) - return; - code = ms->msgin[0]; - if (ALLOW_DEBUG(ms->conn_tgt)) { - printk(KERN_DEBUG "got %d message bytes:", ms->n_msgin); - for (i = 0; i < ms->n_msgin; ++i) - printk(" %x", ms->msgin[i]); - printk("\n"); - } - dlog(ms, "msgin msg=%.8x", - MKWORD(ms->n_msgin, code, ms->msgin[1], ms->msgin[2])); - - ms->expect_reply = 0; - ms->n_msgout = 0; - if (ms->n_msgin < msgin_length(ms)) - goto reject; - if (cmd) - cmd->SCp.Message = code; - switch (code) { - case COMMAND_COMPLETE: - break; - case EXTENDED_MESSAGE: - switch (ms->msgin[2]) { - case EXTENDED_MODIFY_DATA_POINTER: - ms->data_ptr += (ms->msgin[3] << 24) + ms->msgin[6] - + (ms->msgin[4] << 16) + (ms->msgin[5] << 8); - break; - case EXTENDED_SDTR: - if (tp->sdtr_state != sdtr_sent) { - /* reply with an SDTR */ - add_sdtr_msg(ms); - /* limit period to at least his value, - offset to no more than his */ - if (ms->msgout[3] < ms->msgin[3]) - ms->msgout[3] = ms->msgin[3]; - if (ms->msgout[4] > ms->msgin[4]) - ms->msgout[4] = ms->msgin[4]; - set_sdtr(ms, ms->msgout[3], ms->msgout[4]); - ms->msgphase = msg_out; - } else { - set_sdtr(ms, ms->msgin[3], ms->msgin[4]); - } - break; - default: - goto reject; - } - break; - case SAVE_POINTERS: - tp->saved_ptr = ms->data_ptr; - break; - case RESTORE_POINTERS: - ms->data_ptr = tp->saved_ptr; - break; - case DISCONNECT: - ms->phase = disconnecting; - break; - case ABORT: - break; - case MESSAGE_REJECT: - if (tp->sdtr_state == sdtr_sent) - set_sdtr(ms, 0, 0); - break; - case NOP: - break; - default: - if (IDENTIFY_BASE <= code && code <= IDENTIFY_BASE + 7) { - if (cmd == NULL) { - do_abort(ms); - ms->msgphase = msg_out; - } else if (code != cmd->device->lun + IDENTIFY_BASE) { - printk(KERN_WARNING "mesh: lun mismatch " - "(%d != %d) on reselection from " - "target %d\n", code - IDENTIFY_BASE, - cmd->device->lun, ms->conn_tgt); - } - break; - } - goto reject; - } - return; - - reject: - printk(KERN_WARNING "mesh: rejecting message from target %d:", - ms->conn_tgt); - for (i = 0; i < ms->n_msgin; ++i) - printk(" %x", ms->msgin[i]); - printk("\n"); - ms->msgout[0] = MESSAGE_REJECT; - ms->n_msgout = 1; - ms->msgphase = msg_out; -} - -/* - * Set up DMA commands for transferring data. - */ -static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd) -{ - int i, dma_cmd, total, off, dtot; - struct scatterlist *scl; - struct dbdma_cmd *dcmds; - - dma_cmd = ms->tgts[ms->conn_tgt].data_goes_out? - OUTPUT_MORE: INPUT_MORE; - dcmds = ms->dma_cmds; - dtot = 0; - if (cmd) { - int nseg; - - cmd->SCp.this_residual = scsi_bufflen(cmd); - - nseg = scsi_dma_map(cmd); - BUG_ON(nseg < 0); - - if (nseg) { - total = 0; - off = ms->data_ptr; - - scsi_for_each_sg(cmd, scl, nseg, i) { - u32 dma_addr = sg_dma_address(scl); - u32 dma_len = sg_dma_len(scl); - - total += scl->length; - if (off >= dma_len) { - off -= dma_len; - continue; - } - if (dma_len > 0xffff) - panic("mesh: scatterlist element >= 64k"); - st_le16(&dcmds->req_count, dma_len - off); - st_le16(&dcmds->command, dma_cmd); - st_le32(&dcmds->phy_addr, dma_addr + off); - dcmds->xfer_status = 0; - ++dcmds; - dtot += dma_len - off; - off = 0; - } - } - } - if (dtot == 0) { - /* Either the target has overrun our buffer, - or the caller didn't provide a buffer. */ - static char mesh_extra_buf[64]; - - dtot = sizeof(mesh_extra_buf); - st_le16(&dcmds->req_count, dtot); - st_le32(&dcmds->phy_addr, virt_to_phys(mesh_extra_buf)); - dcmds->xfer_status = 0; - ++dcmds; - } - dma_cmd += OUTPUT_LAST - OUTPUT_MORE; - st_le16(&dcmds[-1].command, dma_cmd); - memset(dcmds, 0, sizeof(*dcmds)); - st_le16(&dcmds->command, DBDMA_STOP); - ms->dma_count = dtot; -} - -static void halt_dma(struct mesh_state *ms) -{ - volatile struct dbdma_regs __iomem *md = ms->dma; - volatile struct mesh_regs __iomem *mr = ms->mesh; - struct scsi_cmnd *cmd = ms->current_req; - int t, nb; - - if (!ms->tgts[ms->conn_tgt].data_goes_out) { - /* wait a little while until the fifo drains */ - t = 50; - while (t > 0 && in_8(&mr->fifo_count) != 0 - && (in_le32(&md->status) & ACTIVE) != 0) { - --t; - udelay(1); - } - } - out_le32(&md->control, RUN << 16); /* turn off RUN bit */ - nb = (mr->count_hi << 8) + mr->count_lo; - dlog(ms, "halt_dma fc/count=%.6x", - MKWORD(0, mr->fifo_count, 0, nb)); - if (ms->tgts[ms->conn_tgt].data_goes_out) - nb += mr->fifo_count; - /* nb is the number of bytes not yet transferred - to/from the target. */ - ms->data_ptr -= nb; - dlog(ms, "data_ptr %x", ms->data_ptr); - if (ms->data_ptr < 0) { - printk(KERN_ERR "mesh: halt_dma: data_ptr=%d (nb=%d, ms=%p)\n", - ms->data_ptr, nb, ms); - ms->data_ptr = 0; -#ifdef MESH_DBG - dumplog(ms, ms->conn_tgt); - dumpslog(ms); -#endif /* MESH_DBG */ - } else if (cmd && scsi_bufflen(cmd) && - ms->data_ptr > scsi_bufflen(cmd)) { - printk(KERN_DEBUG "mesh: target %d overrun, " - "data_ptr=%x total=%x goes_out=%d\n", - ms->conn_tgt, ms->data_ptr, scsi_bufflen(cmd), - ms->tgts[ms->conn_tgt].data_goes_out); - } - scsi_dma_unmap(cmd); - ms->dma_started = 0; -} - -static void phase_mismatch(struct mesh_state *ms) -{ - volatile struct mesh_regs __iomem *mr = ms->mesh; - int phase; - - dlog(ms, "phasemm ch/cl/seq/fc=%.8x", - MKWORD(mr->count_hi, mr->count_lo, mr->sequence, mr->fifo_count)); - phase = in_8(&mr->bus_status0) & BS0_PHASE; - if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) { - /* output the last byte of the message, without ATN */ - out_8(&mr->count_lo, 1); - out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]); - ms->msgphase = msg_out_last; - return; - } - - if (ms->msgphase == msg_in) { - get_msgin(ms); - if (ms->n_msgin) - handle_msgin(ms); - } - - if (ms->dma_started) - halt_dma(ms); - if (mr->fifo_count) { - out_8(&mr->sequence, SEQ_FLUSHFIFO); - mesh_flush_io(mr); - udelay(1); - } - - ms->msgphase = msg_none; - switch (phase) { - case BP_DATAIN: - ms->tgts[ms->conn_tgt].data_goes_out = 0; - ms->phase = dataing; - break; - case BP_DATAOUT: - ms->tgts[ms->conn_tgt].data_goes_out = 1; - ms->phase = dataing; - break; - case BP_COMMAND: - ms->phase = commanding; - break; - case BP_STATUS: - ms->phase = statusing; - break; - case BP_MSGIN: - ms->msgphase = msg_in; - ms->n_msgin = 0; - break; - case BP_MSGOUT: - ms->msgphase = msg_out; - if (ms->n_msgout == 0) { - if (ms->aborting) { - do_abort(ms); - } else { - if (ms->last_n_msgout == 0) { - printk(KERN_DEBUG - "mesh: no msg to repeat\n"); - ms->msgout[0] = NOP; - ms->last_n_msgout = 1; - } - ms->n_msgout = ms->last_n_msgout; - } - } - break; - default: - printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase); - ms->stat = DID_ERROR; - mesh_done(ms, 1); - return; - } - - start_phase(ms); -} - -static void cmd_complete(struct mesh_state *ms) -{ - volatile struct mesh_regs __iomem *mr = ms->mesh; - struct scsi_cmnd *cmd = ms->current_req; - struct mesh_target *tp = &ms->tgts[ms->conn_tgt]; - int seq, n, t; - - dlog(ms, "cmd_complete fc=%x", mr->fifo_count); - seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0); - switch (ms->msgphase) { - case msg_out_xxx: - /* huh? we expected a phase mismatch */ - ms->n_msgin = 0; - ms->msgphase = msg_in; - /* fall through */ - - case msg_in: - /* should have some message bytes in fifo */ - get_msgin(ms); - n = msgin_length(ms); - if (ms->n_msgin < n) { - out_8(&mr->count_lo, n - ms->n_msgin); - out_8(&mr->sequence, SEQ_MSGIN + seq); - } else { - ms->msgphase = msg_none; - handle_msgin(ms); - start_phase(ms); - } - break; - - case msg_in_bad: - out_8(&mr->sequence, SEQ_FLUSHFIFO); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->count_lo, 1); - out_8(&mr->sequence, SEQ_MSGIN + SEQ_ATN + use_active_neg); - break; - - case msg_out: - /* - * To get the right timing on ATN wrt ACK, we have - * to get the MESH to drop ACK, wait until REQ gets - * asserted, then drop ATN. To do this we first - * issue a SEQ_MSGOUT with ATN and wait for REQ, - * then change the command to a SEQ_MSGOUT w/o ATN. - * If we don't see REQ in a reasonable time, we - * change the command to SEQ_MSGIN with ATN, - * wait for the phase mismatch interrupt, then - * issue the SEQ_MSGOUT without ATN. - */ - out_8(&mr->count_lo, 1); - out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg + SEQ_ATN); - t = 30; /* wait up to 30us */ - while ((in_8(&mr->bus_status0) & BS0_REQ) == 0 && --t >= 0) - udelay(1); - dlog(ms, "last_mbyte err/exc/fc/cl=%.8x", - MKWORD(mr->error, mr->exception, - mr->fifo_count, mr->count_lo)); - if (in_8(&mr->interrupt) & (INT_ERROR | INT_EXCEPTION)) { - /* whoops, target didn't do what we expected */ - ms->last_n_msgout = ms->n_msgout; - ms->n_msgout = 0; - if (in_8(&mr->interrupt) & INT_ERROR) { - printk(KERN_ERR "mesh: error %x in msg_out\n", - in_8(&mr->error)); - handle_error(ms); - return; - } - if (in_8(&mr->exception) != EXC_PHASEMM) - printk(KERN_ERR "mesh: exc %x in msg_out\n", - in_8(&mr->exception)); - else - printk(KERN_DEBUG "mesh: bs0=%x in msg_out\n", - in_8(&mr->bus_status0)); - handle_exception(ms); - return; - } - if (in_8(&mr->bus_status0) & BS0_REQ) { - out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]); - ms->msgphase = msg_out_last; - } else { - out_8(&mr->sequence, SEQ_MSGIN + use_active_neg + SEQ_ATN); - ms->msgphase = msg_out_xxx; - } - break; - - case msg_out_last: - ms->last_n_msgout = ms->n_msgout; - ms->n_msgout = 0; - ms->msgphase = ms->expect_reply? msg_in: msg_none; - start_phase(ms); - break; - - case msg_none: - switch (ms->phase) { - case idle: - printk(KERN_ERR "mesh: interrupt in idle phase?\n"); - dumpslog(ms); - return; - case selecting: - dlog(ms, "Selecting phase at command completion",0); - ms->msgout[0] = IDENTIFY(ALLOW_RESEL(ms->conn_tgt), - (cmd? cmd->device->lun: 0)); - ms->n_msgout = 1; - ms->expect_reply = 0; - if (ms->aborting) { - ms->msgout[0] = ABORT; - ms->n_msgout++; - } else if (tp->sdtr_state == do_sdtr) { - /* add SDTR message */ - add_sdtr_msg(ms); - ms->expect_reply = 1; - tp->sdtr_state = sdtr_sent; - } - ms->msgphase = msg_out; - /* - * We need to wait for REQ before dropping ATN. - * We wait for at most 30us, then fall back to - * a scheme where we issue a SEQ_COMMAND with ATN, - * which will give us a phase mismatch interrupt - * when REQ does come, and then we send the message. - */ - t = 230; /* wait up to 230us */ - while ((in_8(&mr->bus_status0) & BS0_REQ) == 0) { - if (--t < 0) { - dlog(ms, "impatient for req", ms->n_msgout); - ms->msgphase = msg_none; - break; - } - udelay(1); - } - break; - case dataing: - if (ms->dma_count != 0) { - start_phase(ms); - return; - } - /* - * We can get a phase mismatch here if the target - * changes to the status phase, even though we have - * had a command complete interrupt. Then, if we - * issue the SEQ_STATUS command, we'll get a sequence - * error interrupt. Which isn't so bad except that - * occasionally the mesh actually executes the - * SEQ_STATUS *as well as* giving us the sequence - * error and phase mismatch exception. - */ - out_8(&mr->sequence, 0); - out_8(&mr->interrupt, - INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - halt_dma(ms); - break; - case statusing: - if (cmd) { - cmd->SCp.Status = mr->fifo; - if (DEBUG_TARGET(cmd)) - printk(KERN_DEBUG "mesh: status is %x\n", - cmd->SCp.Status); - } - ms->msgphase = msg_in; - break; - case busfreeing: - mesh_done(ms, 1); - return; - case disconnecting: - ms->current_req = NULL; - ms->phase = idle; - mesh_start(ms); - return; - default: - break; - } - ++ms->phase; - start_phase(ms); - break; - } -} - - -/* - * Called by midlayer with host locked to queue a new - * request - */ -static int mesh_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct mesh_state *ms; - - cmd->scsi_done = done; - cmd->host_scribble = NULL; - - ms = (struct mesh_state *) cmd->device->host->hostdata; - - if (ms->request_q == NULL) - ms->request_q = cmd; - else - ms->request_qtail->host_scribble = (void *) cmd; - ms->request_qtail = cmd; - - if (ms->phase == idle) - mesh_start(ms); - - return 0; -} - -static DEF_SCSI_QCMD(mesh_queue) - -/* - * Called to handle interrupts, either call by the interrupt - * handler (do_mesh_interrupt) or by other functions in - * exceptional circumstances - */ -static void mesh_interrupt(struct mesh_state *ms) -{ - volatile struct mesh_regs __iomem *mr = ms->mesh; - int intr; - -#if 0 - if (ALLOW_DEBUG(ms->conn_tgt)) - printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x " - "phase=%d msgphase=%d\n", mr->bus_status0, - mr->interrupt, mr->exception, mr->error, - ms->phase, ms->msgphase); -#endif - while ((intr = in_8(&mr->interrupt)) != 0) { - dlog(ms, "interrupt intr/err/exc/seq=%.8x", - MKWORD(intr, mr->error, mr->exception, mr->sequence)); - if (intr & INT_ERROR) { - handle_error(ms); - } else if (intr & INT_EXCEPTION) { - handle_exception(ms); - } else if (intr & INT_CMDDONE) { - out_8(&mr->interrupt, INT_CMDDONE); - cmd_complete(ms); - } - } -} - -/* Todo: here we can at least try to remove the command from the - * queue if it isn't connected yet, and for pending command, assert - * ATN until the bus gets freed. - */ -static int mesh_abort(struct scsi_cmnd *cmd) -{ - struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata; - - printk(KERN_DEBUG "mesh_abort(%p)\n", cmd); - mesh_dump_regs(ms); - dumplog(ms, cmd->device->id); - dumpslog(ms); - return FAILED; -} - -/* - * Called by the midlayer with the lock held to reset the - * SCSI host and bus. - * The midlayer will wait for devices to come back, we don't need - * to do that ourselves - */ -static int mesh_host_reset(struct scsi_cmnd *cmd) -{ - struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata; - volatile struct mesh_regs __iomem *mr = ms->mesh; - volatile struct dbdma_regs __iomem *md = ms->dma; - unsigned long flags; - - printk(KERN_DEBUG "mesh_host_reset\n"); - - spin_lock_irqsave(ms->host->host_lock, flags); - - /* Reset the controller & dbdma channel */ - out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16); /* stop dma */ - out_8(&mr->exception, 0xff); /* clear all exception bits */ - out_8(&mr->error, 0xff); /* clear all error bits */ - out_8(&mr->sequence, SEQ_RESETMESH); - mesh_flush_io(mr); - udelay(1); - out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - out_8(&mr->source_id, ms->host->this_id); - out_8(&mr->sel_timeout, 25); /* 250ms */ - out_8(&mr->sync_params, ASYNC_PARAMS); - - /* Reset the bus */ - out_8(&mr->bus_status1, BS1_RST); /* assert RST */ - mesh_flush_io(mr); - udelay(30); /* leave it on for >= 25us */ - out_8(&mr->bus_status1, 0); /* negate RST */ - - /* Complete pending commands */ - handle_reset(ms); - - spin_unlock_irqrestore(ms->host->host_lock, flags); - return SUCCESS; -} - -static void set_mesh_power(struct mesh_state *ms, int state) -{ - if (!machine_is(powermac)) - return; - if (state) { - pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1); - msleep(200); - } else { - pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0); - msleep(10); - } -} - - -#ifdef CONFIG_PM -static int mesh_suspend(struct macio_dev *mdev, pm_message_t mesg) -{ - struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); - unsigned long flags; - - switch (mesg.event) { - case PM_EVENT_SUSPEND: - case PM_EVENT_HIBERNATE: - case PM_EVENT_FREEZE: - break; - default: - return 0; - } - if (ms->phase == sleeping) - return 0; - - scsi_block_requests(ms->host); - spin_lock_irqsave(ms->host->host_lock, flags); - while(ms->phase != idle) { - spin_unlock_irqrestore(ms->host->host_lock, flags); - msleep(10); - spin_lock_irqsave(ms->host->host_lock, flags); - } - ms->phase = sleeping; - spin_unlock_irqrestore(ms->host->host_lock, flags); - disable_irq(ms->meshintr); - set_mesh_power(ms, 0); - - return 0; -} - -static int mesh_resume(struct macio_dev *mdev) -{ - struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); - unsigned long flags; - - if (ms->phase != sleeping) - return 0; - - set_mesh_power(ms, 1); - mesh_init(ms); - spin_lock_irqsave(ms->host->host_lock, flags); - mesh_start(ms); - spin_unlock_irqrestore(ms->host->host_lock, flags); - enable_irq(ms->meshintr); - scsi_unblock_requests(ms->host); - - return 0; -} - -#endif /* CONFIG_PM */ - -/* - * If we leave drives set for synchronous transfers (especially - * CDROMs), and reboot to MacOS, it gets confused, poor thing. - * So, on reboot we reset the SCSI bus. - */ -static int mesh_shutdown(struct macio_dev *mdev) -{ - struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); - volatile struct mesh_regs __iomem *mr; - unsigned long flags; - - printk(KERN_INFO "resetting MESH scsi bus(es)\n"); - spin_lock_irqsave(ms->host->host_lock, flags); - mr = ms->mesh; - out_8(&mr->intr_mask, 0); - out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE); - out_8(&mr->bus_status1, BS1_RST); - mesh_flush_io(mr); - udelay(30); - out_8(&mr->bus_status1, 0); - spin_unlock_irqrestore(ms->host->host_lock, flags); - - return 0; -} - -static struct scsi_host_template mesh_template = { - .proc_name = "mesh", - .name = "MESH", - .queuecommand = mesh_queue, - .eh_abort_handler = mesh_abort, - .eh_host_reset_handler = mesh_host_reset, - .can_queue = 20, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 2, - .use_clustering = DISABLE_CLUSTERING, -}; - -static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match) -{ - struct device_node *mesh = macio_get_of_node(mdev); - struct pci_dev* pdev = macio_get_pci_dev(mdev); - int tgt, minper; - const int *cfp; - struct mesh_state *ms; - struct Scsi_Host *mesh_host; - void *dma_cmd_space; - dma_addr_t dma_cmd_bus; - - switch (mdev->bus->chip->type) { - case macio_heathrow: - case macio_gatwick: - case macio_paddington: - use_active_neg = 0; - break; - default: - use_active_neg = SEQ_ACTIVE_NEG; - } - - if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) { - printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs" - " (got %d,%d)\n", macio_resource_count(mdev), - macio_irq_count(mdev)); - return -ENODEV; - } - - if (macio_request_resources(mdev, "mesh") != 0) { - printk(KERN_ERR "mesh: unable to request memory resources"); - return -EBUSY; - } - mesh_host = scsi_host_alloc(&mesh_template, sizeof(struct mesh_state)); - if (mesh_host == NULL) { - printk(KERN_ERR "mesh: couldn't register host"); - goto out_release; - } - - /* Old junk for root discovery, that will die ultimately */ -#if !defined(MODULE) - note_scsi_host(mesh, mesh_host); -#endif - - mesh_host->base = macio_resource_start(mdev, 0); - mesh_host->irq = macio_irq(mdev, 0); - ms = (struct mesh_state *) mesh_host->hostdata; - macio_set_drvdata(mdev, ms); - ms->host = mesh_host; - ms->mdev = mdev; - ms->pdev = pdev; - - ms->mesh = ioremap(macio_resource_start(mdev, 0), 0x1000); - if (ms->mesh == NULL) { - printk(KERN_ERR "mesh: can't map registers\n"); - goto out_free; - } - ms->dma = ioremap(macio_resource_start(mdev, 1), 0x1000); - if (ms->dma == NULL) { - printk(KERN_ERR "mesh: can't map registers\n"); - iounmap(ms->mesh); - goto out_free; - } - - ms->meshintr = macio_irq(mdev, 0); - ms->dmaintr = macio_irq(mdev, 1); - - /* Space for dma command list: +1 for stop command, - * +1 to allow for aligning. - */ - ms->dma_cmd_size = (mesh_host->sg_tablesize + 2) * sizeof(struct dbdma_cmd); - - /* We use the PCI APIs for now until the generic one gets fixed - * enough or until we get some macio-specific versions - */ - dma_cmd_space = pci_alloc_consistent(macio_get_pci_dev(mdev), - ms->dma_cmd_size, - &dma_cmd_bus); - if (dma_cmd_space == NULL) { - printk(KERN_ERR "mesh: can't allocate DMA table\n"); - goto out_unmap; - } - memset(dma_cmd_space, 0, ms->dma_cmd_size); - - ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space); - ms->dma_cmd_space = dma_cmd_space; - ms->dma_cmd_bus = dma_cmd_bus + ((unsigned long)ms->dma_cmds) - - (unsigned long)dma_cmd_space; - ms->current_req = NULL; - for (tgt = 0; tgt < 8; ++tgt) { - ms->tgts[tgt].sdtr_state = do_sdtr; - ms->tgts[tgt].sync_params = ASYNC_PARAMS; - ms->tgts[tgt].current_req = NULL; - } - - if ((cfp = of_get_property(mesh, "clock-frequency", NULL))) - ms->clk_freq = *cfp; - else { - printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n"); - ms->clk_freq = 50000000; - } - - /* The maximum sync rate is clock / 5; increase - * mesh_sync_period if necessary. - */ - minper = 1000000000 / (ms->clk_freq / 5); /* ns */ - if (mesh_sync_period < minper) - mesh_sync_period = minper; - - /* Power up the chip */ - set_mesh_power(ms, 1); - - /* Set it up */ - mesh_init(ms); - - /* Request interrupt */ - if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms)) { - printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr); - goto out_shutdown; - } - - /* Add scsi host & scan */ - if (scsi_add_host(mesh_host, &mdev->ofdev.dev)) - goto out_release_irq; - scsi_scan_host(mesh_host); - - return 0; - - out_release_irq: - free_irq(ms->meshintr, ms); - out_shutdown: - /* shutdown & reset bus in case of error or macos can be confused - * at reboot if the bus was set to synchronous mode already - */ - mesh_shutdown(mdev); - set_mesh_power(ms, 0); - pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size, - ms->dma_cmd_space, ms->dma_cmd_bus); - out_unmap: - iounmap(ms->dma); - iounmap(ms->mesh); - out_free: - scsi_host_put(mesh_host); - out_release: - macio_release_resources(mdev); - - return -ENODEV; -} - -static int mesh_remove(struct macio_dev *mdev) -{ - struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev); - struct Scsi_Host *mesh_host = ms->host; - - scsi_remove_host(mesh_host); - - free_irq(ms->meshintr, ms); - - /* Reset scsi bus */ - mesh_shutdown(mdev); - - /* Shut down chip & termination */ - set_mesh_power(ms, 0); - - /* Unmap registers & dma controller */ - iounmap(ms->mesh); - iounmap(ms->dma); - - /* Free DMA commands memory */ - pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size, - ms->dma_cmd_space, ms->dma_cmd_bus); - - /* Release memory resources */ - macio_release_resources(mdev); - - scsi_host_put(mesh_host); - - return 0; -} - - -static struct of_device_id mesh_match[] = -{ - { - .name = "mesh", - }, - { - .type = "scsi", - .compatible = "chrp,mesh0" - }, - {}, -}; -MODULE_DEVICE_TABLE (of, mesh_match); - -static struct macio_driver mesh_driver = -{ - .driver = { - .name = "mesh", - .owner = THIS_MODULE, - .of_match_table = mesh_match, - }, - .probe = mesh_probe, - .remove = mesh_remove, - .shutdown = mesh_shutdown, -#ifdef CONFIG_PM - .suspend = mesh_suspend, - .resume = mesh_resume, -#endif -}; - - -static int __init init_mesh(void) -{ - - /* Calculate sync rate from module parameters */ - if (sync_rate > 10) - sync_rate = 10; - if (sync_rate > 0) { - printk(KERN_INFO "mesh: configured for synchronous %d MB/s\n", sync_rate); - mesh_sync_period = 1000 / sync_rate; /* ns */ - mesh_sync_offset = 15; - } else - printk(KERN_INFO "mesh: configured for asynchronous\n"); - - return macio_register_driver(&mesh_driver); -} - -static void __exit exit_mesh(void) -{ - return macio_unregister_driver(&mesh_driver); -} - -module_init(init_mesh); -module_exit(exit_mesh); diff --git a/ANDROID_3.4.5/drivers/scsi/mesh.h b/ANDROID_3.4.5/drivers/scsi/mesh.h deleted file mode 100644 index 4fdb81fa..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mesh.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * mesh.h: definitions for the driver for the MESH SCSI bus adaptor - * (Macintosh Enhanced SCSI Hardware) found on Power Macintosh computers. - * - * Copyright (C) 1996 Paul Mackerras. - */ -#ifndef _MESH_H -#define _MESH_H - -/* - * Registers in the MESH controller. - */ - -struct mesh_regs { - unsigned char count_lo; - char pad0[15]; - unsigned char count_hi; - char pad1[15]; - unsigned char fifo; - char pad2[15]; - unsigned char sequence; - char pad3[15]; - unsigned char bus_status0; - char pad4[15]; - unsigned char bus_status1; - char pad5[15]; - unsigned char fifo_count; - char pad6[15]; - unsigned char exception; - char pad7[15]; - unsigned char error; - char pad8[15]; - unsigned char intr_mask; - char pad9[15]; - unsigned char interrupt; - char pad10[15]; - unsigned char source_id; - char pad11[15]; - unsigned char dest_id; - char pad12[15]; - unsigned char sync_params; - char pad13[15]; - unsigned char mesh_id; - char pad14[15]; - unsigned char sel_timeout; - char pad15[15]; -}; - -/* Bits in the sequence register. */ -#define SEQ_DMA_MODE 0x80 /* use DMA for data transfer */ -#define SEQ_TARGET 0x40 /* put the controller into target mode */ -#define SEQ_ATN 0x20 /* assert ATN signal */ -#define SEQ_ACTIVE_NEG 0x10 /* use active negation on REQ/ACK */ -#define SEQ_CMD 0x0f /* command bits: */ -#define SEQ_ARBITRATE 1 /* get the bus */ -#define SEQ_SELECT 2 /* select a target */ -#define SEQ_COMMAND 3 /* send a command */ -#define SEQ_STATUS 4 /* receive status */ -#define SEQ_DATAOUT 5 /* send data */ -#define SEQ_DATAIN 6 /* receive data */ -#define SEQ_MSGOUT 7 /* send a message */ -#define SEQ_MSGIN 8 /* receive a message */ -#define SEQ_BUSFREE 9 /* look for bus free */ -#define SEQ_ENBPARITY 0x0a /* enable parity checking */ -#define SEQ_DISPARITY 0x0b /* disable parity checking */ -#define SEQ_ENBRESEL 0x0c /* enable reselection */ -#define SEQ_DISRESEL 0x0d /* disable reselection */ -#define SEQ_RESETMESH 0x0e /* reset the controller */ -#define SEQ_FLUSHFIFO 0x0f /* clear out the FIFO */ - -/* Bits in the bus_status0 and bus_status1 registers: - these correspond directly to the SCSI bus control signals. */ -#define BS0_REQ 0x20 -#define BS0_ACK 0x10 -#define BS0_ATN 0x08 -#define BS0_MSG 0x04 -#define BS0_CD 0x02 -#define BS0_IO 0x01 -#define BS1_RST 0x80 -#define BS1_BSY 0x40 -#define BS1_SEL 0x20 - -/* Bus phases defined by the bits in bus_status0 */ -#define BS0_PHASE (BS0_MSG+BS0_CD+BS0_IO) -#define BP_DATAOUT 0 -#define BP_DATAIN BS0_IO -#define BP_COMMAND BS0_CD -#define BP_STATUS (BS0_CD+BS0_IO) -#define BP_MSGOUT (BS0_MSG+BS0_CD) -#define BP_MSGIN (BS0_MSG+BS0_CD+BS0_IO) - -/* Bits in the exception register. */ -#define EXC_SELWATN 0x20 /* (as target) we were selected with ATN */ -#define EXC_SELECTED 0x10 /* (as target) we were selected w/o ATN */ -#define EXC_RESELECTED 0x08 /* (as initiator) we were reselected */ -#define EXC_ARBLOST 0x04 /* we lost arbitration */ -#define EXC_PHASEMM 0x02 /* SCSI phase mismatch */ -#define EXC_SELTO 0x01 /* selection timeout */ - -/* Bits in the error register */ -#define ERR_UNEXPDISC 0x40 /* target unexpectedly disconnected */ -#define ERR_SCSIRESET 0x20 /* SCSI bus got reset on us */ -#define ERR_SEQERR 0x10 /* we did something the chip didn't like */ -#define ERR_PARITY 0x01 /* parity error was detected */ - -/* Bits in the interrupt and intr_mask registers */ -#define INT_ERROR 0x04 /* error interrupt */ -#define INT_EXCEPTION 0x02 /* exception interrupt */ -#define INT_CMDDONE 0x01 /* command done interrupt */ - -/* Fields in the sync_params register */ -#define SYNC_OFF(x) ((x) >> 4) /* offset field */ -#define SYNC_PER(x) ((x) & 0xf) /* period field */ -#define SYNC_PARAMS(o, p) (((o) << 4) | (p)) -#define ASYNC_PARAMS 2 /* sync_params value for async xfers */ - -/* - * Assuming a clock frequency of 50MHz: - * - * The transfer period with SYNC_PER(sync_params) == x - * is (x + 2) * 40ns, except that x == 0 gives 100ns. - * - * The units of the sel_timeout register are 10ms. - */ - - -#endif /* _MESH_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/Kconfig b/ANDROID_3.4.5/drivers/scsi/mpt2sas/Kconfig deleted file mode 100644 index bbb7e4bf..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/Kconfig +++ /dev/null @@ -1,67 +0,0 @@ -# -# Kernel configuration file for the MPT2SAS -# -# This code is based on drivers/scsi/mpt2sas/Kconfig -# Copyright (C) 2007-2010 LSI Corporation -# (mailto:DL-MPTFusionLinux@lsi.com) - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# NO WARRANTY -# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -# solely responsible for determining the appropriateness of using and -# distributing the Program and assumes all risks associated with its -# exercise of rights under this Agreement, including but not limited to -# the risks and costs of program errors, damage to or loss of data, -# programs or equipment, and unavailability or interruption of operations. - -# DISCLAIMER OF LIABILITY -# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -config SCSI_MPT2SAS - tristate "LSI MPT Fusion SAS 2.0 Device Driver" - depends on PCI && SCSI - select SCSI_SAS_ATTRS - select RAID_ATTRS - ---help--- - This driver supports PCI-Express SAS 6Gb/s Host Adapters. - -config SCSI_MPT2SAS_MAX_SGE - int "LSI MPT Fusion Max number of SG Entries (16 - 128)" - depends on PCI && SCSI && SCSI_MPT2SAS - default "128" - range 16 128 - ---help--- - This option allows you to specify the maximum number of scatter- - gather entries per I/O. The driver default is 128, which matches - SAFE_PHYS_SEGMENTS. However, it may decreased down to 16. - Decreasing this parameter will reduce memory requirements - on a per controller instance. - -config SCSI_MPT2SAS_LOGGING - bool "LSI MPT Fusion logging facility" - depends on PCI && SCSI && SCSI_MPT2SAS - ---help--- - This turns on a logging facility. diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/Makefile b/ANDROID_3.4.5/drivers/scsi/mpt2sas/Makefile deleted file mode 100644 index 728f0475..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# mpt2sas makefile -obj-$(CONFIG_SCSI_MPT2SAS) += mpt2sas.o -mpt2sas-y += mpt2sas_base.o \ - mpt2sas_config.o \ - mpt2sas_scsih.o \ - mpt2sas_transport.o \ - mpt2sas_ctl.o diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2.h deleted file mode 100644 index a01f0aa6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2.h +++ /dev/null @@ -1,1149 +0,0 @@ -/* - * Copyright (c) 2000-2011 LSI Corporation. - * - * - * Name: mpi2.h - * Title: MPI Message independent structures and definitions - * including System Interface Register Set and - * scatter/gather formats. - * Creation Date: June 21, 2006 - * - * mpi2.h Version: 02.00.22 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 06-04-07 02.00.01 Bumped MPI2_HEADER_VERSION_UNIT. - * 06-26-07 02.00.02 Bumped MPI2_HEADER_VERSION_UNIT. - * 08-31-07 02.00.03 Bumped MPI2_HEADER_VERSION_UNIT. - * Moved ReplyPostHostIndex register to offset 0x6C of the - * MPI2_SYSTEM_INTERFACE_REGS and modified the define for - * MPI2_REPLY_POST_HOST_INDEX_OFFSET. - * Added union of request descriptors. - * Added union of reply descriptors. - * 10-31-07 02.00.04 Bumped MPI2_HEADER_VERSION_UNIT. - * Added define for MPI2_VERSION_02_00. - * Fixed the size of the FunctionDependent5 field in the - * MPI2_DEFAULT_REPLY structure. - * 12-18-07 02.00.05 Bumped MPI2_HEADER_VERSION_UNIT. - * Removed the MPI-defined Fault Codes and extended the - * product specific codes up to 0xEFFF. - * Added a sixth key value for the WriteSequence register - * and changed the flush value to 0x0. - * Added message function codes for Diagnostic Buffer Post - * and Diagnsotic Release. - * New IOCStatus define: MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED - * Moved MPI2_VERSION_UNION from mpi2_ioc.h. - * 02-29-08 02.00.06 Bumped MPI2_HEADER_VERSION_UNIT. - * 03-03-08 02.00.07 Bumped MPI2_HEADER_VERSION_UNIT. - * 05-21-08 02.00.08 Bumped MPI2_HEADER_VERSION_UNIT. - * Added #defines for marking a reply descriptor as unused. - * 06-27-08 02.00.09 Bumped MPI2_HEADER_VERSION_UNIT. - * 10-02-08 02.00.10 Bumped MPI2_HEADER_VERSION_UNIT. - * Moved LUN field defines from mpi2_init.h. - * 01-19-09 02.00.11 Bumped MPI2_HEADER_VERSION_UNIT. - * 05-06-09 02.00.12 Bumped MPI2_HEADER_VERSION_UNIT. - * In all request and reply descriptors, replaced VF_ID - * field with MSIxIndex field. - * Removed DevHandle field from - * MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR and made those - * bytes reserved. - * Added RAID Accelerator functionality. - * 07-30-09 02.00.13 Bumped MPI2_HEADER_VERSION_UNIT. - * 10-28-09 02.00.14 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MSI-x index mask and shift for Reply Post Host - * Index register. - * Added function code for Host Based Discovery Action. - * 02-10-10 02.00.15 Bumped MPI2_HEADER_VERSION_UNIT. - * Added define for MPI2_FUNCTION_PWR_MGMT_CONTROL. - * Added defines for product-specific range of message - * function codes, 0xF0 to 0xFF. - * 05-12-10 02.00.16 Bumped MPI2_HEADER_VERSION_UNIT. - * Added alternative defines for the SGE Direction bit. - * 08-11-10 02.00.17 Bumped MPI2_HEADER_VERSION_UNIT. - * 11-10-10 02.00.18 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR define. - * 02-23-11 02.00.19 Bumped MPI2_HEADER_VERSION_UNIT. - * Added MPI2_FUNCTION_SEND_HOST_MESSAGE. - * 03-09-11 02.00.20 Bumped MPI2_HEADER_VERSION_UNIT. - * 05-25-11 02.00.21 Bumped MPI2_HEADER_VERSION_UNIT. - * 08-24-11 02.00.22 Bumped MPI2_HEADER_VERSION_UNIT. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_H -#define MPI2_H - - -/***************************************************************************** -* -* MPI Version Definitions -* -*****************************************************************************/ - -#define MPI2_VERSION_MAJOR (0x02) -#define MPI2_VERSION_MINOR (0x00) -#define MPI2_VERSION_MAJOR_MASK (0xFF00) -#define MPI2_VERSION_MAJOR_SHIFT (8) -#define MPI2_VERSION_MINOR_MASK (0x00FF) -#define MPI2_VERSION_MINOR_SHIFT (0) -#define MPI2_VERSION ((MPI2_VERSION_MAJOR << MPI2_VERSION_MAJOR_SHIFT) | \ - MPI2_VERSION_MINOR) - -#define MPI2_VERSION_02_00 (0x0200) - -/* versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x16) -#define MPI2_HEADER_VERSION_DEV (0x00) -#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) -#define MPI2_HEADER_VERSION_UNIT_SHIFT (8) -#define MPI2_HEADER_VERSION_DEV_MASK (0x00FF) -#define MPI2_HEADER_VERSION_DEV_SHIFT (0) -#define MPI2_HEADER_VERSION ((MPI2_HEADER_VERSION_UNIT << 8) | MPI2_HEADER_VERSION_DEV) - - -/***************************************************************************** -* -* IOC State Definitions -* -*****************************************************************************/ - -#define MPI2_IOC_STATE_RESET (0x00000000) -#define MPI2_IOC_STATE_READY (0x10000000) -#define MPI2_IOC_STATE_OPERATIONAL (0x20000000) -#define MPI2_IOC_STATE_FAULT (0x40000000) - -#define MPI2_IOC_STATE_MASK (0xF0000000) -#define MPI2_IOC_STATE_SHIFT (28) - -/* Fault state range for prodcut specific codes */ -#define MPI2_FAULT_PRODUCT_SPECIFIC_MIN (0x0000) -#define MPI2_FAULT_PRODUCT_SPECIFIC_MAX (0xEFFF) - - -/***************************************************************************** -* -* System Interface Register Definitions -* -*****************************************************************************/ - -typedef volatile struct _MPI2_SYSTEM_INTERFACE_REGS -{ - U32 Doorbell; /* 0x00 */ - U32 WriteSequence; /* 0x04 */ - U32 HostDiagnostic; /* 0x08 */ - U32 Reserved1; /* 0x0C */ - U32 DiagRWData; /* 0x10 */ - U32 DiagRWAddressLow; /* 0x14 */ - U32 DiagRWAddressHigh; /* 0x18 */ - U32 Reserved2[5]; /* 0x1C */ - U32 HostInterruptStatus; /* 0x30 */ - U32 HostInterruptMask; /* 0x34 */ - U32 DCRData; /* 0x38 */ - U32 DCRAddress; /* 0x3C */ - U32 Reserved3[2]; /* 0x40 */ - U32 ReplyFreeHostIndex; /* 0x48 */ - U32 Reserved4[8]; /* 0x4C */ - U32 ReplyPostHostIndex; /* 0x6C */ - U32 Reserved5; /* 0x70 */ - U32 HCBSize; /* 0x74 */ - U32 HCBAddressLow; /* 0x78 */ - U32 HCBAddressHigh; /* 0x7C */ - U32 Reserved6[16]; /* 0x80 */ - U32 RequestDescriptorPostLow; /* 0xC0 */ - U32 RequestDescriptorPostHigh; /* 0xC4 */ - U32 Reserved7[14]; /* 0xC8 */ -} MPI2_SYSTEM_INTERFACE_REGS, MPI2_POINTER PTR_MPI2_SYSTEM_INTERFACE_REGS, - Mpi2SystemInterfaceRegs_t, MPI2_POINTER pMpi2SystemInterfaceRegs_t; - -/* - * Defines for working with the Doorbell register. - */ -#define MPI2_DOORBELL_OFFSET (0x00000000) - -/* IOC --> System values */ -#define MPI2_DOORBELL_USED (0x08000000) -#define MPI2_DOORBELL_WHO_INIT_MASK (0x07000000) -#define MPI2_DOORBELL_WHO_INIT_SHIFT (24) -#define MPI2_DOORBELL_FAULT_CODE_MASK (0x0000FFFF) -#define MPI2_DOORBELL_DATA_MASK (0x0000FFFF) - -/* System --> IOC values */ -#define MPI2_DOORBELL_FUNCTION_MASK (0xFF000000) -#define MPI2_DOORBELL_FUNCTION_SHIFT (24) -#define MPI2_DOORBELL_ADD_DWORDS_MASK (0x00FF0000) -#define MPI2_DOORBELL_ADD_DWORDS_SHIFT (16) - - -/* - * Defines for the WriteSequence register - */ -#define MPI2_WRITE_SEQUENCE_OFFSET (0x00000004) -#define MPI2_WRSEQ_KEY_VALUE_MASK (0x0000000F) -#define MPI2_WRSEQ_FLUSH_KEY_VALUE (0x0) -#define MPI2_WRSEQ_1ST_KEY_VALUE (0xF) -#define MPI2_WRSEQ_2ND_KEY_VALUE (0x4) -#define MPI2_WRSEQ_3RD_KEY_VALUE (0xB) -#define MPI2_WRSEQ_4TH_KEY_VALUE (0x2) -#define MPI2_WRSEQ_5TH_KEY_VALUE (0x7) -#define MPI2_WRSEQ_6TH_KEY_VALUE (0xD) - -/* - * Defines for the HostDiagnostic register - */ -#define MPI2_HOST_DIAGNOSTIC_OFFSET (0x00000008) - -#define MPI2_DIAG_BOOT_DEVICE_SELECT_MASK (0x00001800) -#define MPI2_DIAG_BOOT_DEVICE_SELECT_DEFAULT (0x00000000) -#define MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW (0x00000800) - -#define MPI2_DIAG_CLEAR_FLASH_BAD_SIG (0x00000400) -#define MPI2_DIAG_FORCE_HCB_ON_RESET (0x00000200) -#define MPI2_DIAG_HCB_MODE (0x00000100) -#define MPI2_DIAG_DIAG_WRITE_ENABLE (0x00000080) -#define MPI2_DIAG_FLASH_BAD_SIG (0x00000040) -#define MPI2_DIAG_RESET_HISTORY (0x00000020) -#define MPI2_DIAG_DIAG_RW_ENABLE (0x00000010) -#define MPI2_DIAG_RESET_ADAPTER (0x00000004) -#define MPI2_DIAG_HOLD_IOC_RESET (0x00000002) - -/* - * Offsets for DiagRWData and address - */ -#define MPI2_DIAG_RW_DATA_OFFSET (0x00000010) -#define MPI2_DIAG_RW_ADDRESS_LOW_OFFSET (0x00000014) -#define MPI2_DIAG_RW_ADDRESS_HIGH_OFFSET (0x00000018) - -/* - * Defines for the HostInterruptStatus register - */ -#define MPI2_HOST_INTERRUPT_STATUS_OFFSET (0x00000030) -#define MPI2_HIS_SYS2IOC_DB_STATUS (0x80000000) -#define MPI2_HIS_IOP_DOORBELL_STATUS MPI2_HIS_SYS2IOC_DB_STATUS -#define MPI2_HIS_RESET_IRQ_STATUS (0x40000000) -#define MPI2_HIS_REPLY_DESCRIPTOR_INTERRUPT (0x00000008) -#define MPI2_HIS_IOC2SYS_DB_STATUS (0x00000001) -#define MPI2_HIS_DOORBELL_INTERRUPT MPI2_HIS_IOC2SYS_DB_STATUS - -/* - * Defines for the HostInterruptMask register - */ -#define MPI2_HOST_INTERRUPT_MASK_OFFSET (0x00000034) -#define MPI2_HIM_RESET_IRQ_MASK (0x40000000) -#define MPI2_HIM_REPLY_INT_MASK (0x00000008) -#define MPI2_HIM_RIM MPI2_HIM_REPLY_INT_MASK -#define MPI2_HIM_IOC2SYS_DB_MASK (0x00000001) -#define MPI2_HIM_DIM MPI2_HIM_IOC2SYS_DB_MASK - -/* - * Offsets for DCRData and address - */ -#define MPI2_DCR_DATA_OFFSET (0x00000038) -#define MPI2_DCR_ADDRESS_OFFSET (0x0000003C) - -/* - * Offset for the Reply Free Queue - */ -#define MPI2_REPLY_FREE_HOST_INDEX_OFFSET (0x00000048) - -/* - * Defines for the Reply Descriptor Post Queue - */ -#define MPI2_REPLY_POST_HOST_INDEX_OFFSET (0x0000006C) -#define MPI2_REPLY_POST_HOST_INDEX_MASK (0x00FFFFFF) -#define MPI2_RPHI_MSIX_INDEX_MASK (0xFF000000) -#define MPI2_RPHI_MSIX_INDEX_SHIFT (24) - -/* - * Defines for the HCBSize and address - */ -#define MPI2_HCB_SIZE_OFFSET (0x00000074) -#define MPI2_HCB_SIZE_SIZE_MASK (0xFFFFF000) -#define MPI2_HCB_SIZE_HCB_ENABLE (0x00000001) - -#define MPI2_HCB_ADDRESS_LOW_OFFSET (0x00000078) -#define MPI2_HCB_ADDRESS_HIGH_OFFSET (0x0000007C) - -/* - * Offsets for the Request Queue - */ -#define MPI2_REQUEST_DESCRIPTOR_POST_LOW_OFFSET (0x000000C0) -#define MPI2_REQUEST_DESCRIPTOR_POST_HIGH_OFFSET (0x000000C4) - - -/***************************************************************************** -* -* Message Descriptors -* -*****************************************************************************/ - -/* Request Descriptors */ - -/* Default Request Descriptor */ -typedef struct _MPI2_DEFAULT_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 DescriptorTypeDependent; /* 0x06 */ -} MPI2_DEFAULT_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_DEFAULT_REQUEST_DESCRIPTOR, - Mpi2DefaultRequestDescriptor_t, MPI2_POINTER pMpi2DefaultRequestDescriptor_t; - -/* defines for the RequestFlags field */ -#define MPI2_REQ_DESCRIPT_FLAGS_TYPE_MASK (0x0E) -#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO (0x00) -#define MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET (0x02) -#define MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY (0x06) -#define MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE (0x08) -#define MPI2_REQ_DESCRIPT_FLAGS_RAID_ACCELERATOR (0x0A) - -#define MPI2_REQ_DESCRIPT_FLAGS_IOC_FIFO_MARKER (0x01) - - -/* High Priority Request Descriptor */ -typedef struct _MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 Reserved1; /* 0x06 */ -} MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR, - Mpi2HighPriorityRequestDescriptor_t, - MPI2_POINTER pMpi2HighPriorityRequestDescriptor_t; - - -/* SCSI IO Request Descriptor */ -typedef struct _MPI2_SCSI_IO_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 DevHandle; /* 0x06 */ -} MPI2_SCSI_IO_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST_DESCRIPTOR, - Mpi2SCSIIORequestDescriptor_t, MPI2_POINTER pMpi2SCSIIORequestDescriptor_t; - - -/* SCSI Target Request Descriptor */ -typedef struct _MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR -{ - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 IoIndex; /* 0x06 */ -} MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR, - Mpi2SCSITargetRequestDescriptor_t, - MPI2_POINTER pMpi2SCSITargetRequestDescriptor_t; - - -/* RAID Accelerator Request Descriptor */ -typedef struct _MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR { - U8 RequestFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 LMID; /* 0x04 */ - U16 Reserved; /* 0x06 */ -} MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR, - Mpi2RAIDAcceleratorRequestDescriptor_t, - MPI2_POINTER pMpi2RAIDAcceleratorRequestDescriptor_t; - - -/* union of Request Descriptors */ -typedef union _MPI2_REQUEST_DESCRIPTOR_UNION -{ - MPI2_DEFAULT_REQUEST_DESCRIPTOR Default; - MPI2_HIGH_PRIORITY_REQUEST_DESCRIPTOR HighPriority; - MPI2_SCSI_IO_REQUEST_DESCRIPTOR SCSIIO; - MPI2_SCSI_TARGET_REQUEST_DESCRIPTOR SCSITarget; - MPI2_RAID_ACCEL_REQUEST_DESCRIPTOR RAIDAccelerator; - U64 Words; -} MPI2_REQUEST_DESCRIPTOR_UNION, MPI2_POINTER PTR_MPI2_REQUEST_DESCRIPTOR_UNION, - Mpi2RequestDescriptorUnion_t, MPI2_POINTER pMpi2RequestDescriptorUnion_t; - - -/* Reply Descriptors */ - -/* Default Reply Descriptor */ -typedef struct _MPI2_DEFAULT_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 DescriptorTypeDependent1; /* 0x02 */ - U32 DescriptorTypeDependent2; /* 0x04 */ -} MPI2_DEFAULT_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY_DESCRIPTOR, - Mpi2DefaultReplyDescriptor_t, MPI2_POINTER pMpi2DefaultReplyDescriptor_t; - -/* defines for the ReplyFlags field */ -#define MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK (0x0F) -#define MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS (0x00) -#define MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY (0x01) -#define MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS (0x02) -#define MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER (0x03) -#define MPI2_RPY_DESCRIPT_FLAGS_RAID_ACCELERATOR_SUCCESS (0x05) -#define MPI2_RPY_DESCRIPT_FLAGS_UNUSED (0x0F) - -/* values for marking a reply descriptor as unused */ -#define MPI2_RPY_DESCRIPT_UNUSED_WORD0_MARK (0xFFFFFFFF) -#define MPI2_RPY_DESCRIPT_UNUSED_WORD1_MARK (0xFFFFFFFF) - -/* Address Reply Descriptor */ -typedef struct _MPI2_ADDRESS_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U32 ReplyFrameAddress; /* 0x04 */ -} MPI2_ADDRESS_REPLY_DESCRIPTOR, MPI2_POINTER PTR_MPI2_ADDRESS_REPLY_DESCRIPTOR, - Mpi2AddressReplyDescriptor_t, MPI2_POINTER pMpi2AddressReplyDescriptor_t; - -#define MPI2_ADDRESS_REPLY_SMID_INVALID (0x00) - - -/* SCSI IO Success Reply Descriptor */ -typedef struct _MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U16 TaskTag; /* 0x04 */ - U16 Reserved1; /* 0x06 */ -} MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR, - Mpi2SCSIIOSuccessReplyDescriptor_t, - MPI2_POINTER pMpi2SCSIIOSuccessReplyDescriptor_t; - - -/* TargetAssist Success Reply Descriptor */ -typedef struct _MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U8 SequenceNumber; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 IoIndex; /* 0x06 */ -} MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR, - Mpi2TargetAssistSuccessReplyDescriptor_t, - MPI2_POINTER pMpi2TargetAssistSuccessReplyDescriptor_t; - - -/* Target Command Buffer Reply Descriptor */ -typedef struct _MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR -{ - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U8 VP_ID; /* 0x02 */ - U8 Flags; /* 0x03 */ - U16 InitiatorDevHandle; /* 0x04 */ - U16 IoIndex; /* 0x06 */ -} MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR, - Mpi2TargetCommandBufferReplyDescriptor_t, - MPI2_POINTER pMpi2TargetCommandBufferReplyDescriptor_t; - -/* defines for Flags field */ -#define MPI2_RPY_DESCRIPT_TCB_FLAGS_PHYNUM_MASK (0x3F) - - -/* RAID Accelerator Success Reply Descriptor */ -typedef struct _MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR { - U8 ReplyFlags; /* 0x00 */ - U8 MSIxIndex; /* 0x01 */ - U16 SMID; /* 0x02 */ - U32 Reserved; /* 0x04 */ -} MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, - MPI2_POINTER PTR_MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR, - Mpi2RAIDAcceleratorSuccessReplyDescriptor_t, - MPI2_POINTER pMpi2RAIDAcceleratorSuccessReplyDescriptor_t; - - -/* union of Reply Descriptors */ -typedef union _MPI2_REPLY_DESCRIPTORS_UNION -{ - MPI2_DEFAULT_REPLY_DESCRIPTOR Default; - MPI2_ADDRESS_REPLY_DESCRIPTOR AddressReply; - MPI2_SCSI_IO_SUCCESS_REPLY_DESCRIPTOR SCSIIOSuccess; - MPI2_TARGETASSIST_SUCCESS_REPLY_DESCRIPTOR TargetAssistSuccess; - MPI2_TARGET_COMMAND_BUFFER_REPLY_DESCRIPTOR TargetCommandBuffer; - MPI2_RAID_ACCELERATOR_SUCCESS_REPLY_DESCRIPTOR RAIDAcceleratorSuccess; - U64 Words; -} MPI2_REPLY_DESCRIPTORS_UNION, MPI2_POINTER PTR_MPI2_REPLY_DESCRIPTORS_UNION, - Mpi2ReplyDescriptorsUnion_t, MPI2_POINTER pMpi2ReplyDescriptorsUnion_t; - - - -/***************************************************************************** -* -* Message Functions -* -*****************************************************************************/ - -#define MPI2_FUNCTION_SCSI_IO_REQUEST (0x00) /* SCSI IO */ -#define MPI2_FUNCTION_SCSI_TASK_MGMT (0x01) /* SCSI Task Management */ -#define MPI2_FUNCTION_IOC_INIT (0x02) /* IOC Init */ -#define MPI2_FUNCTION_IOC_FACTS (0x03) /* IOC Facts */ -#define MPI2_FUNCTION_CONFIG (0x04) /* Configuration */ -#define MPI2_FUNCTION_PORT_FACTS (0x05) /* Port Facts */ -#define MPI2_FUNCTION_PORT_ENABLE (0x06) /* Port Enable */ -#define MPI2_FUNCTION_EVENT_NOTIFICATION (0x07) /* Event Notification */ -#define MPI2_FUNCTION_EVENT_ACK (0x08) /* Event Acknowledge */ -#define MPI2_FUNCTION_FW_DOWNLOAD (0x09) /* FW Download */ -#define MPI2_FUNCTION_TARGET_ASSIST (0x0B) /* Target Assist */ -#define MPI2_FUNCTION_TARGET_STATUS_SEND (0x0C) /* Target Status Send */ -#define MPI2_FUNCTION_TARGET_MODE_ABORT (0x0D) /* Target Mode Abort */ -#define MPI2_FUNCTION_FW_UPLOAD (0x12) /* FW Upload */ -#define MPI2_FUNCTION_RAID_ACTION (0x15) /* RAID Action */ -#define MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH (0x16) /* SCSI IO RAID Passthrough */ -#define MPI2_FUNCTION_TOOLBOX (0x17) /* Toolbox */ -#define MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR (0x18) /* SCSI Enclosure Processor */ -#define MPI2_FUNCTION_SMP_PASSTHROUGH (0x1A) /* SMP Passthrough */ -#define MPI2_FUNCTION_SAS_IO_UNIT_CONTROL (0x1B) /* SAS IO Unit Control */ -#define MPI2_FUNCTION_SATA_PASSTHROUGH (0x1C) /* SATA Passthrough */ -#define MPI2_FUNCTION_DIAG_BUFFER_POST (0x1D) /* Diagnostic Buffer Post */ -#define MPI2_FUNCTION_DIAG_RELEASE (0x1E) /* Diagnostic Release */ -#define MPI2_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) /* Target Command Buffer Post Base */ -#define MPI2_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) /* Target Command Buffer Post List */ -#define MPI2_FUNCTION_RAID_ACCELERATOR (0x2C) /* RAID Accelerator*/ -/* Host Based Discovery Action */ -#define MPI2_FUNCTION_HOST_BASED_DISCOVERY_ACTION (0x2F) -/* Power Management Control */ -#define MPI2_FUNCTION_PWR_MGMT_CONTROL (0x30) -/* Send Host Message */ -#define MPI2_FUNCTION_SEND_HOST_MESSAGE (0x31) -/* beginning of product-specific range */ -#define MPI2_FUNCTION_MIN_PRODUCT_SPECIFIC (0xF0) -/* end of product-specific range */ -#define MPI2_FUNCTION_MAX_PRODUCT_SPECIFIC (0xFF) - - - - -/* Doorbell functions */ -#define MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET (0x40) -#define MPI2_FUNCTION_HANDSHAKE (0x42) - - -/***************************************************************************** -* -* IOC Status Values -* -*****************************************************************************/ - -/* mask for IOCStatus status value */ -#define MPI2_IOCSTATUS_MASK (0x7FFF) - -/**************************************************************************** -* Common IOCStatus values for all replies -****************************************************************************/ - -#define MPI2_IOCSTATUS_SUCCESS (0x0000) -#define MPI2_IOCSTATUS_INVALID_FUNCTION (0x0001) -#define MPI2_IOCSTATUS_BUSY (0x0002) -#define MPI2_IOCSTATUS_INVALID_SGL (0x0003) -#define MPI2_IOCSTATUS_INTERNAL_ERROR (0x0004) -#define MPI2_IOCSTATUS_INVALID_VPID (0x0005) -#define MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES (0x0006) -#define MPI2_IOCSTATUS_INVALID_FIELD (0x0007) -#define MPI2_IOCSTATUS_INVALID_STATE (0x0008) -#define MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED (0x0009) - -/**************************************************************************** -* Config IOCStatus values -****************************************************************************/ - -#define MPI2_IOCSTATUS_CONFIG_INVALID_ACTION (0x0020) -#define MPI2_IOCSTATUS_CONFIG_INVALID_TYPE (0x0021) -#define MPI2_IOCSTATUS_CONFIG_INVALID_PAGE (0x0022) -#define MPI2_IOCSTATUS_CONFIG_INVALID_DATA (0x0023) -#define MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS (0x0024) -#define MPI2_IOCSTATUS_CONFIG_CANT_COMMIT (0x0025) - -/**************************************************************************** -* SCSI IO Reply -****************************************************************************/ - -#define MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR (0x0040) -#define MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE (0x0042) -#define MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE (0x0043) -#define MPI2_IOCSTATUS_SCSI_DATA_OVERRUN (0x0044) -#define MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN (0x0045) -#define MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR (0x0046) -#define MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR (0x0047) -#define MPI2_IOCSTATUS_SCSI_TASK_TERMINATED (0x0048) -#define MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH (0x0049) -#define MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED (0x004A) -#define MPI2_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) -#define MPI2_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) - -/**************************************************************************** -* For use by SCSI Initiator and SCSI Target end-to-end data protection -****************************************************************************/ - -#define MPI2_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) -#define MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) -#define MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) - -/**************************************************************************** -* SCSI Target values -****************************************************************************/ - -#define MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX (0x0062) -#define MPI2_IOCSTATUS_TARGET_ABORTED (0x0063) -#define MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE (0x0064) -#define MPI2_IOCSTATUS_TARGET_NO_CONNECTION (0x0065) -#define MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH (0x006A) -#define MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR (0x006D) -#define MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA (0x006E) -#define MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT (0x006F) -#define MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT (0x0070) -#define MPI2_IOCSTATUS_TARGET_NAK_RECEIVED (0x0071) - -/**************************************************************************** -* Serial Attached SCSI values -****************************************************************************/ - -#define MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED (0x0090) -#define MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN (0x0091) - -/**************************************************************************** -* Diagnostic Buffer Post / Diagnostic Release values -****************************************************************************/ - -#define MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED (0x00A0) - -/**************************************************************************** -* RAID Accelerator values -****************************************************************************/ - -#define MPI2_IOCSTATUS_RAID_ACCEL_ERROR (0x00B0) - -/**************************************************************************** -* IOCStatus flag to indicate that log info is available -****************************************************************************/ - -#define MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE (0x8000) - -/**************************************************************************** -* IOCLogInfo Types -****************************************************************************/ - -#define MPI2_IOCLOGINFO_TYPE_MASK (0xF0000000) -#define MPI2_IOCLOGINFO_TYPE_SHIFT (28) -#define MPI2_IOCLOGINFO_TYPE_NONE (0x0) -#define MPI2_IOCLOGINFO_TYPE_SCSI (0x1) -#define MPI2_IOCLOGINFO_TYPE_FC (0x2) -#define MPI2_IOCLOGINFO_TYPE_SAS (0x3) -#define MPI2_IOCLOGINFO_TYPE_ISCSI (0x4) -#define MPI2_IOCLOGINFO_LOG_DATA_MASK (0x0FFFFFFF) - - -/***************************************************************************** -* -* Standard Message Structures -* -*****************************************************************************/ - -/**************************************************************************** -* Request Message Header for all request messages -****************************************************************************/ - -typedef struct _MPI2_REQUEST_HEADER -{ - U16 FunctionDependent1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 FunctionDependent2; /* 0x04 */ - U8 FunctionDependent3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ -} MPI2_REQUEST_HEADER, MPI2_POINTER PTR_MPI2_REQUEST_HEADER, - MPI2RequestHeader_t, MPI2_POINTER pMPI2RequestHeader_t; - - -/**************************************************************************** -* Default Reply -****************************************************************************/ - -typedef struct _MPI2_DEFAULT_REPLY -{ - U16 FunctionDependent1; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 FunctionDependent2; /* 0x04 */ - U8 FunctionDependent3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U16 FunctionDependent5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_DEFAULT_REPLY, MPI2_POINTER PTR_MPI2_DEFAULT_REPLY, - MPI2DefaultReply_t, MPI2_POINTER pMPI2DefaultReply_t; - - -/* common version structure/union used in messages and configuration pages */ - -typedef struct _MPI2_VERSION_STRUCT -{ - U8 Dev; /* 0x00 */ - U8 Unit; /* 0x01 */ - U8 Minor; /* 0x02 */ - U8 Major; /* 0x03 */ -} MPI2_VERSION_STRUCT; - -typedef union _MPI2_VERSION_UNION -{ - MPI2_VERSION_STRUCT Struct; - U32 Word; -} MPI2_VERSION_UNION; - - -/* LUN field defines, common to many structures */ -#define MPI2_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) -#define MPI2_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) -#define MPI2_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) -#define MPI2_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) -#define MPI2_LUN_LEVEL_1_WORD (0xFF00) -#define MPI2_LUN_LEVEL_1_DWORD (0x0000FF00) - - -/***************************************************************************** -* -* Fusion-MPT MPI Scatter Gather Elements -* -*****************************************************************************/ - -/**************************************************************************** -* MPI Simple Element structures -****************************************************************************/ - -typedef struct _MPI2_SGE_SIMPLE32 -{ - U32 FlagsLength; - U32 Address; -} MPI2_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_SGE_SIMPLE32, - Mpi2SGESimple32_t, MPI2_POINTER pMpi2SGESimple32_t; - -typedef struct _MPI2_SGE_SIMPLE64 -{ - U32 FlagsLength; - U64 Address; -} MPI2_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_SGE_SIMPLE64, - Mpi2SGESimple64_t, MPI2_POINTER pMpi2SGESimple64_t; - -typedef struct _MPI2_SGE_SIMPLE_UNION -{ - U32 FlagsLength; - union - { - U32 Address32; - U64 Address64; - } u; -} MPI2_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_SIMPLE_UNION, - Mpi2SGESimpleUnion_t, MPI2_POINTER pMpi2SGESimpleUnion_t; - - -/**************************************************************************** -* MPI Chain Element structures -****************************************************************************/ - -typedef struct _MPI2_SGE_CHAIN32 -{ - U16 Length; - U8 NextChainOffset; - U8 Flags; - U32 Address; -} MPI2_SGE_CHAIN32, MPI2_POINTER PTR_MPI2_SGE_CHAIN32, - Mpi2SGEChain32_t, MPI2_POINTER pMpi2SGEChain32_t; - -typedef struct _MPI2_SGE_CHAIN64 -{ - U16 Length; - U8 NextChainOffset; - U8 Flags; - U64 Address; -} MPI2_SGE_CHAIN64, MPI2_POINTER PTR_MPI2_SGE_CHAIN64, - Mpi2SGEChain64_t, MPI2_POINTER pMpi2SGEChain64_t; - -typedef struct _MPI2_SGE_CHAIN_UNION -{ - U16 Length; - U8 NextChainOffset; - U8 Flags; - union - { - U32 Address32; - U64 Address64; - } u; -} MPI2_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_SGE_CHAIN_UNION, - Mpi2SGEChainUnion_t, MPI2_POINTER pMpi2SGEChainUnion_t; - - -/**************************************************************************** -* MPI Transaction Context Element structures -****************************************************************************/ - -typedef struct _MPI2_SGE_TRANSACTION32 -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - U32 TransactionContext[1]; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION32, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION32, - Mpi2SGETransaction32_t, MPI2_POINTER pMpi2SGETransaction32_t; - -typedef struct _MPI2_SGE_TRANSACTION64 -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - U32 TransactionContext[2]; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION64, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION64, - Mpi2SGETransaction64_t, MPI2_POINTER pMpi2SGETransaction64_t; - -typedef struct _MPI2_SGE_TRANSACTION96 -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - U32 TransactionContext[3]; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION96, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION96, - Mpi2SGETransaction96_t, MPI2_POINTER pMpi2SGETransaction96_t; - -typedef struct _MPI2_SGE_TRANSACTION128 -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - U32 TransactionContext[4]; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION128, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION128, - Mpi2SGETransaction_t128, MPI2_POINTER pMpi2SGETransaction_t128; - -typedef struct _MPI2_SGE_TRANSACTION_UNION -{ - U8 Reserved; - U8 ContextSize; - U8 DetailsLength; - U8 Flags; - union - { - U32 TransactionContext32[1]; - U32 TransactionContext64[2]; - U32 TransactionContext96[3]; - U32 TransactionContext128[4]; - } u; - U32 TransactionDetails[1]; -} MPI2_SGE_TRANSACTION_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANSACTION_UNION, - Mpi2SGETransactionUnion_t, MPI2_POINTER pMpi2SGETransactionUnion_t; - - -/**************************************************************************** -* MPI SGE union for IO SGL's -****************************************************************************/ - -typedef struct _MPI2_MPI_SGE_IO_UNION -{ - union - { - MPI2_SGE_SIMPLE_UNION Simple; - MPI2_SGE_CHAIN_UNION Chain; - } u; -} MPI2_MPI_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_IO_UNION, - Mpi2MpiSGEIOUnion_t, MPI2_POINTER pMpi2MpiSGEIOUnion_t; - - -/**************************************************************************** -* MPI SGE union for SGL's with Simple and Transaction elements -****************************************************************************/ - -typedef struct _MPI2_SGE_TRANS_SIMPLE_UNION -{ - union - { - MPI2_SGE_SIMPLE_UNION Simple; - MPI2_SGE_TRANSACTION_UNION Transaction; - } u; -} MPI2_SGE_TRANS_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_SGE_TRANS_SIMPLE_UNION, - Mpi2SGETransSimpleUnion_t, MPI2_POINTER pMpi2SGETransSimpleUnion_t; - - -/**************************************************************************** -* All MPI SGE types union -****************************************************************************/ - -typedef struct _MPI2_MPI_SGE_UNION -{ - union - { - MPI2_SGE_SIMPLE_UNION Simple; - MPI2_SGE_CHAIN_UNION Chain; - MPI2_SGE_TRANSACTION_UNION Transaction; - } u; -} MPI2_MPI_SGE_UNION, MPI2_POINTER PTR_MPI2_MPI_SGE_UNION, - Mpi2MpiSgeUnion_t, MPI2_POINTER pMpi2MpiSgeUnion_t; - - -/**************************************************************************** -* MPI SGE field definition and masks -****************************************************************************/ - -/* Flags field bit definitions */ - -#define MPI2_SGE_FLAGS_LAST_ELEMENT (0x80) -#define MPI2_SGE_FLAGS_END_OF_BUFFER (0x40) -#define MPI2_SGE_FLAGS_ELEMENT_TYPE_MASK (0x30) -#define MPI2_SGE_FLAGS_LOCAL_ADDRESS (0x08) -#define MPI2_SGE_FLAGS_DIRECTION (0x04) -#define MPI2_SGE_FLAGS_ADDRESS_SIZE (0x02) -#define MPI2_SGE_FLAGS_END_OF_LIST (0x01) - -#define MPI2_SGE_FLAGS_SHIFT (24) - -#define MPI2_SGE_LENGTH_MASK (0x00FFFFFF) -#define MPI2_SGE_CHAIN_LENGTH_MASK (0x0000FFFF) - -/* Element Type */ - -#define MPI2_SGE_FLAGS_TRANSACTION_ELEMENT (0x00) -#define MPI2_SGE_FLAGS_SIMPLE_ELEMENT (0x10) -#define MPI2_SGE_FLAGS_CHAIN_ELEMENT (0x30) -#define MPI2_SGE_FLAGS_ELEMENT_MASK (0x30) - -/* Address location */ - -#define MPI2_SGE_FLAGS_SYSTEM_ADDRESS (0x00) - -/* Direction */ - -#define MPI2_SGE_FLAGS_IOC_TO_HOST (0x00) -#define MPI2_SGE_FLAGS_HOST_TO_IOC (0x04) - -#define MPI2_SGE_FLAGS_DEST (MPI2_SGE_FLAGS_IOC_TO_HOST) -#define MPI2_SGE_FLAGS_SOURCE (MPI2_SGE_FLAGS_HOST_TO_IOC) - -/* Address Size */ - -#define MPI2_SGE_FLAGS_32_BIT_ADDRESSING (0x00) -#define MPI2_SGE_FLAGS_64_BIT_ADDRESSING (0x02) - -/* Context Size */ - -#define MPI2_SGE_FLAGS_32_BIT_CONTEXT (0x00) -#define MPI2_SGE_FLAGS_64_BIT_CONTEXT (0x02) -#define MPI2_SGE_FLAGS_96_BIT_CONTEXT (0x04) -#define MPI2_SGE_FLAGS_128_BIT_CONTEXT (0x06) - -#define MPI2_SGE_CHAIN_OFFSET_MASK (0x00FF0000) -#define MPI2_SGE_CHAIN_OFFSET_SHIFT (16) - -/**************************************************************************** -* MPI SGE operation Macros -****************************************************************************/ - -/* SIMPLE FlagsLength manipulations... */ -#define MPI2_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_SGE_FLAGS_SHIFT) -#define MPI2_SGE_GET_FLAGS(f) (((f) & ~MPI2_SGE_LENGTH_MASK) >> MPI2_SGE_FLAGS_SHIFT) -#define MPI2_SGE_LENGTH(f) ((f) & MPI2_SGE_LENGTH_MASK) -#define MPI2_SGE_CHAIN_LENGTH(f) ((f) & MPI2_SGE_CHAIN_LENGTH_MASK) - -#define MPI2_SGE_SET_FLAGS_LENGTH(f,l) (MPI2_SGE_SET_FLAGS(f) | MPI2_SGE_LENGTH(l)) - -#define MPI2_pSGE_GET_FLAGS(psg) MPI2_SGE_GET_FLAGS((psg)->FlagsLength) -#define MPI2_pSGE_GET_LENGTH(psg) MPI2_SGE_LENGTH((psg)->FlagsLength) -#define MPI2_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_SGE_SET_FLAGS_LENGTH(f,l) - -/* CAUTION - The following are READ-MODIFY-WRITE! */ -#define MPI2_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_SGE_SET_FLAGS(f) -#define MPI2_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_SGE_LENGTH(l) - -#define MPI2_GET_CHAIN_OFFSET(x) ((x & MPI2_SGE_CHAIN_OFFSET_MASK) >> MPI2_SGE_CHAIN_OFFSET_SHIFT) - - -/***************************************************************************** -* -* Fusion-MPT IEEE Scatter Gather Elements -* -*****************************************************************************/ - -/**************************************************************************** -* IEEE Simple Element structures -****************************************************************************/ - -typedef struct _MPI2_IEEE_SGE_SIMPLE32 -{ - U32 Address; - U32 FlagsLength; -} MPI2_IEEE_SGE_SIMPLE32, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE32, - Mpi2IeeeSgeSimple32_t, MPI2_POINTER pMpi2IeeeSgeSimple32_t; - -typedef struct _MPI2_IEEE_SGE_SIMPLE64 -{ - U64 Address; - U32 Length; - U16 Reserved1; - U8 Reserved2; - U8 Flags; -} MPI2_IEEE_SGE_SIMPLE64, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE64, - Mpi2IeeeSgeSimple64_t, MPI2_POINTER pMpi2IeeeSgeSimple64_t; - -typedef union _MPI2_IEEE_SGE_SIMPLE_UNION -{ - MPI2_IEEE_SGE_SIMPLE32 Simple32; - MPI2_IEEE_SGE_SIMPLE64 Simple64; -} MPI2_IEEE_SGE_SIMPLE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_SIMPLE_UNION, - Mpi2IeeeSgeSimpleUnion_t, MPI2_POINTER pMpi2IeeeSgeSimpleUnion_t; - - -/**************************************************************************** -* IEEE Chain Element structures -****************************************************************************/ - -typedef MPI2_IEEE_SGE_SIMPLE32 MPI2_IEEE_SGE_CHAIN32; - -typedef MPI2_IEEE_SGE_SIMPLE64 MPI2_IEEE_SGE_CHAIN64; - -typedef union _MPI2_IEEE_SGE_CHAIN_UNION -{ - MPI2_IEEE_SGE_CHAIN32 Chain32; - MPI2_IEEE_SGE_CHAIN64 Chain64; -} MPI2_IEEE_SGE_CHAIN_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_CHAIN_UNION, - Mpi2IeeeSgeChainUnion_t, MPI2_POINTER pMpi2IeeeSgeChainUnion_t; - - -/**************************************************************************** -* All IEEE SGE types union -****************************************************************************/ - -typedef struct _MPI2_IEEE_SGE_UNION -{ - union - { - MPI2_IEEE_SGE_SIMPLE_UNION Simple; - MPI2_IEEE_SGE_CHAIN_UNION Chain; - } u; -} MPI2_IEEE_SGE_UNION, MPI2_POINTER PTR_MPI2_IEEE_SGE_UNION, - Mpi2IeeeSgeUnion_t, MPI2_POINTER pMpi2IeeeSgeUnion_t; - - -/**************************************************************************** -* IEEE SGE field definitions and masks -****************************************************************************/ - -/* Flags field bit definitions */ - -#define MPI2_IEEE_SGE_FLAGS_ELEMENT_TYPE_MASK (0x80) - -#define MPI2_IEEE32_SGE_FLAGS_SHIFT (24) - -#define MPI2_IEEE32_SGE_LENGTH_MASK (0x00FFFFFF) - -/* Element Type */ - -#define MPI2_IEEE_SGE_FLAGS_SIMPLE_ELEMENT (0x00) -#define MPI2_IEEE_SGE_FLAGS_CHAIN_ELEMENT (0x80) - -/* Data Location Address Space */ - -#define MPI2_IEEE_SGE_FLAGS_ADDR_MASK (0x03) -#define MPI2_IEEE_SGE_FLAGS_SYSTEM_ADDR (0x00) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_IOCDDR_ADDR (0x01) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_IOCPLB_ADDR (0x02) -#define MPI2_IEEE_SGE_FLAGS_IOCPLBNTA_ADDR (0x03) - /* IEEE Simple Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR (0x03) - /* IEEE Chain Element only */ -#define MPI2_IEEE_SGE_FLAGS_SYSTEMPLBCPI_ADDR \ - (MPI2_IEEE_SGE_FLAGS_SYSTEMPLBPCI_ADDR) /* typo in name */ - -/**************************************************************************** -* IEEE SGE operation Macros -****************************************************************************/ - -/* SIMPLE FlagsLength manipulations... */ -#define MPI2_IEEE32_SGE_SET_FLAGS(f) ((U32)(f) << MPI2_IEEE32_SGE_FLAGS_SHIFT) -#define MPI2_IEEE32_SGE_GET_FLAGS(f) (((f) & ~MPI2_IEEE32_SGE_LENGTH_MASK) >> MPI2_IEEE32_SGE_FLAGS_SHIFT) -#define MPI2_IEEE32_SGE_LENGTH(f) ((f) & MPI2_IEEE32_SGE_LENGTH_MASK) - -#define MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f, l) (MPI2_IEEE32_SGE_SET_FLAGS(f) | MPI2_IEEE32_SGE_LENGTH(l)) - -#define MPI2_IEEE32_pSGE_GET_FLAGS(psg) MPI2_IEEE32_SGE_GET_FLAGS((psg)->FlagsLength) -#define MPI2_IEEE32_pSGE_GET_LENGTH(psg) MPI2_IEEE32_SGE_LENGTH((psg)->FlagsLength) -#define MPI2_IEEE32_pSGE_SET_FLAGS_LENGTH(psg,f,l) (psg)->FlagsLength = MPI2_IEEE32_SGE_SET_FLAGS_LENGTH(f,l) - -/* CAUTION - The following are READ-MODIFY-WRITE! */ -#define MPI2_IEEE32_pSGE_SET_FLAGS(psg,f) (psg)->FlagsLength |= MPI2_IEEE32_SGE_SET_FLAGS(f) -#define MPI2_IEEE32_pSGE_SET_LENGTH(psg,l) (psg)->FlagsLength |= MPI2_IEEE32_SGE_LENGTH(l) - - - - -/***************************************************************************** -* -* Fusion-MPT MPI/IEEE Scatter Gather Unions -* -*****************************************************************************/ - -typedef union _MPI2_SIMPLE_SGE_UNION -{ - MPI2_SGE_SIMPLE_UNION MpiSimple; - MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; -} MPI2_SIMPLE_SGE_UNION, MPI2_POINTER PTR_MPI2_SIMPLE_SGE_UNION, - Mpi2SimpleSgeUntion_t, MPI2_POINTER pMpi2SimpleSgeUntion_t; - - -typedef union _MPI2_SGE_IO_UNION -{ - MPI2_SGE_SIMPLE_UNION MpiSimple; - MPI2_SGE_CHAIN_UNION MpiChain; - MPI2_IEEE_SGE_SIMPLE_UNION IeeeSimple; - MPI2_IEEE_SGE_CHAIN_UNION IeeeChain; -} MPI2_SGE_IO_UNION, MPI2_POINTER PTR_MPI2_SGE_IO_UNION, - Mpi2SGEIOUnion_t, MPI2_POINTER pMpi2SGEIOUnion_t; - - -/**************************************************************************** -* -* Values for SGLFlags field, used in many request messages with an SGL -* -****************************************************************************/ - -/* values for MPI SGL Data Location Address Space subfield */ -#define MPI2_SGLFLAGS_ADDRESS_SPACE_MASK (0x0C) -#define MPI2_SGLFLAGS_SYSTEM_ADDRESS_SPACE (0x00) -#define MPI2_SGLFLAGS_IOCDDR_ADDRESS_SPACE (0x04) -#define MPI2_SGLFLAGS_IOCPLB_ADDRESS_SPACE (0x08) -#define MPI2_SGLFLAGS_IOCPLBNTA_ADDRESS_SPACE (0x0C) -/* values for SGL Type subfield */ -#define MPI2_SGLFLAGS_SGL_TYPE_MASK (0x03) -#define MPI2_SGLFLAGS_SGL_TYPE_MPI (0x00) -#define MPI2_SGLFLAGS_SGL_TYPE_IEEE32 (0x01) -#define MPI2_SGLFLAGS_SGL_TYPE_IEEE64 (0x02) - - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h deleted file mode 100644 index 3a023dad..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h +++ /dev/null @@ -1,2978 +0,0 @@ -/* - * Copyright (c) 2000-2011 LSI Corporation. - * - * - * Name: mpi2_cnfg.h - * Title: MPI Configuration messages and pages - * Creation Date: November 10, 2006 - * - * mpi2_cnfg.h Version: 02.00.21 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 06-04-07 02.00.01 Added defines for SAS IO Unit Page 2 PhyFlags. - * Added Manufacturing Page 11. - * Added MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE - * define. - * 06-26-07 02.00.02 Adding generic structure for product-specific - * Manufacturing pages: MPI2_CONFIG_PAGE_MANUFACTURING_PS. - * Rework of BIOS Page 2 configuration page. - * Fixed MPI2_BIOSPAGE2_BOOT_DEVICE to be a union of the - * forms. - * Added configuration pages IOC Page 8 and Driver - * Persistent Mapping Page 0. - * 08-31-07 02.00.03 Modified configuration pages dealing with Integrated - * RAID (Manufacturing Page 4, RAID Volume Pages 0 and 1, - * RAID Physical Disk Pages 0 and 1, RAID Configuration - * Page 0). - * Added new value for AccessStatus field of SAS Device - * Page 0 (_SATA_NEEDS_INITIALIZATION). - * 10-31-07 02.00.04 Added missing SEPDevHandle field to - * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. - * 12-18-07 02.00.05 Modified IO Unit Page 0 to use 32-bit version fields for - * NVDATA. - * Modified IOC Page 7 to use masks and added field for - * SASBroadcastPrimitiveMasks. - * Added MPI2_CONFIG_PAGE_BIOS_4. - * Added MPI2_CONFIG_PAGE_LOG_0. - * 02-29-08 02.00.06 Modified various names to make them 32-character unique. - * Added SAS Device IDs. - * Updated Integrated RAID configuration pages including - * Manufacturing Page 4, IOC Page 6, and RAID Configuration - * Page 0. - * 05-21-08 02.00.07 Added define MPI2_MANPAGE4_MIX_SSD_SAS_SATA. - * Added define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION. - * Fixed define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING. - * Added missing MaxNumRoutedSasAddresses field to - * MPI2_CONFIG_PAGE_EXPANDER_0. - * Added SAS Port Page 0. - * Modified structure layout for - * MPI2_CONFIG_PAGE_DRIVER_MAPPING_0. - * 06-27-08 02.00.08 Changed MPI2_CONFIG_PAGE_RD_PDISK_1 to use - * MPI2_RAID_PHYS_DISK1_PATH_MAX to size the array. - * 10-02-08 02.00.09 Changed MPI2_RAID_PGAD_CONFIGNUM_MASK from 0x0000FFFF - * to 0x000000FF. - * Added two new values for the Physical Disk Coercion Size - * bits in the Flags field of Manufacturing Page 4. - * Added product-specific Manufacturing pages 16 to 31. - * Modified Flags bits for controlling write cache on SATA - * drives in IO Unit Page 1. - * Added new bit to AdditionalControlFlags of SAS IO Unit - * Page 1 to control Invalid Topology Correction. - * Added additional defines for RAID Volume Page 0 - * VolumeStatusFlags field. - * Modified meaning of RAID Volume Page 0 VolumeSettings - * define for auto-configure of hot-swap drives. - * Added SupportedPhysDisks field to RAID Volume Page 1 and - * added related defines. - * Added PhysDiskAttributes field (and related defines) to - * RAID Physical Disk Page 0. - * Added MPI2_SAS_PHYINFO_PHY_VACANT define. - * Added three new DiscoveryStatus bits for SAS IO Unit - * Page 0 and SAS Expander Page 0. - * Removed multiplexing information from SAS IO Unit pages. - * Added BootDeviceWaitTime field to SAS IO Unit Page 4. - * Removed Zone Address Resolved bit from PhyInfo and from - * Expander Page 0 Flags field. - * Added two new AccessStatus values to SAS Device Page 0 - * for indicating routing problems. Added 3 reserved words - * to this page. - * 01-19-09 02.00.10 Fixed defines for GPIOVal field of IO Unit Page 3. - * Inserted missing reserved field into structure for IOC - * Page 6. - * Added more pending task bits to RAID Volume Page 0 - * VolumeStatusFlags defines. - * Added MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED define. - * Added a new DiscoveryStatus bit for SAS IO Unit Page 0 - * and SAS Expander Page 0 to flag a downstream initiator - * when in simplified routing mode. - * Removed SATA Init Failure defines for DiscoveryStatus - * fields of SAS IO Unit Page 0 and SAS Expander Page 0. - * Added MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED define. - * Added PortGroups, DmaGroup, and ControlGroup fields to - * SAS Device Page 0. - * 05-06-09 02.00.11 Added structures and defines for IO Unit Page 5 and IO - * Unit Page 6. - * Added expander reduced functionality data to SAS - * Expander Page 0. - * Added SAS PHY Page 2 and SAS PHY Page 3. - * 07-30-09 02.00.12 Added IO Unit Page 7. - * Added new device ids. - * Added SAS IO Unit Page 5. - * Added partial and slumber power management capable flags - * to SAS Device Page 0 Flags field. - * Added PhyInfo defines for power condition. - * Added Ethernet configuration pages. - * 10-28-09 02.00.13 Added MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY. - * Added SAS PHY Page 4 structure and defines. - * 02-10-10 02.00.14 Modified the comments for the configuration page - * structures that contain an array of data. The host - * should use the "count" field in the page data (e.g. the - * NumPhys field) to determine the number of valid elements - * in the array. - * Added/modified some MPI2_MFGPAGE_DEVID_SAS defines. - * Added PowerManagementCapabilities to IO Unit Page 7. - * Added PortWidthModGroup field to - * MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_6 and related defines. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_7 and related defines. - * Added MPI2_CONFIG_PAGE_SASIOUNIT_8 and related defines. - * 05-12-10 02.00.15 Added MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT - * define. - * Added MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE define. - * Added MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY define. - * 08-11-10 02.00.16 Removed IO Unit Page 1 device path (multi-pathing) - * defines. - * 11-10-10 02.00.17 Added ReceptacleID field (replacing Reserved1) to - * MPI2_MANPAGE7_CONNECTOR_INFO and reworked defines for - * the Pinout field. - * Added BoardTemperature and BoardTemperatureUnits fields - * to MPI2_CONFIG_PAGE_IO_UNIT_7. - * Added MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING define - * and MPI2_CONFIG_PAGE_EXT_MAN_PS structure. - * 02-23-11 02.00.18 Added ProxyVF_ID field to MPI2_CONFIG_REQUEST. - * Added IO Unit Page 8, IO Unit Page 9, - * and IO Unit Page 10. - * Added SASNotifyPrimitiveMasks field to - * MPI2_CONFIG_PAGE_IOC_7. - * 03-09-11 02.00.19 Fixed IO Unit Page 10 (to match the spec). - * 05-25-11 02.00.20 Cleaned up a few comments. - * 08-24-11 02.00.21 Marked the IO Unit Page 7 PowerManagementCapabilities - * for PCIe link as obsolete. - * Added SpinupFlags field containing a Disable Spin-up - * bit to the MPI2_SAS_IOUNIT4_SPINUP_GROUP fields of - * SAS IO Unit Page 4. - - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_CNFG_H -#define MPI2_CNFG_H - -/***************************************************************************** -* Configuration Page Header and defines -*****************************************************************************/ - -/* Config Page Header */ -typedef struct _MPI2_CONFIG_PAGE_HEADER -{ - U8 PageVersion; /* 0x00 */ - U8 PageLength; /* 0x01 */ - U8 PageNumber; /* 0x02 */ - U8 PageType; /* 0x03 */ -} MPI2_CONFIG_PAGE_HEADER, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER, - Mpi2ConfigPageHeader_t, MPI2_POINTER pMpi2ConfigPageHeader_t; - -typedef union _MPI2_CONFIG_PAGE_HEADER_UNION -{ - MPI2_CONFIG_PAGE_HEADER Struct; - U8 Bytes[4]; - U16 Word16[2]; - U32 Word32; -} MPI2_CONFIG_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_HEADER_UNION, - Mpi2ConfigPageHeaderUnion, MPI2_POINTER pMpi2ConfigPageHeaderUnion; - -/* Extended Config Page Header */ -typedef struct _MPI2_CONFIG_EXTENDED_PAGE_HEADER -{ - U8 PageVersion; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 PageNumber; /* 0x02 */ - U8 PageType; /* 0x03 */ - U16 ExtPageLength; /* 0x04 */ - U8 ExtPageType; /* 0x06 */ - U8 Reserved2; /* 0x07 */ -} MPI2_CONFIG_EXTENDED_PAGE_HEADER, - MPI2_POINTER PTR_MPI2_CONFIG_EXTENDED_PAGE_HEADER, - Mpi2ConfigExtendedPageHeader_t, MPI2_POINTER pMpi2ConfigExtendedPageHeader_t; - -typedef union _MPI2_CONFIG_EXT_PAGE_HEADER_UNION -{ - MPI2_CONFIG_PAGE_HEADER Struct; - MPI2_CONFIG_EXTENDED_PAGE_HEADER Ext; - U8 Bytes[8]; - U16 Word16[4]; - U32 Word32[2]; -} MPI2_CONFIG_EXT_PAGE_HEADER_UNION, MPI2_POINTER PTR_MPI2_CONFIG_EXT_PAGE_HEADER_UNION, - Mpi2ConfigPageExtendedHeaderUnion, MPI2_POINTER pMpi2ConfigPageExtendedHeaderUnion; - - -/* PageType field values */ -#define MPI2_CONFIG_PAGEATTR_READ_ONLY (0x00) -#define MPI2_CONFIG_PAGEATTR_CHANGEABLE (0x10) -#define MPI2_CONFIG_PAGEATTR_PERSISTENT (0x20) -#define MPI2_CONFIG_PAGEATTR_MASK (0xF0) - -#define MPI2_CONFIG_PAGETYPE_IO_UNIT (0x00) -#define MPI2_CONFIG_PAGETYPE_IOC (0x01) -#define MPI2_CONFIG_PAGETYPE_BIOS (0x02) -#define MPI2_CONFIG_PAGETYPE_RAID_VOLUME (0x08) -#define MPI2_CONFIG_PAGETYPE_MANUFACTURING (0x09) -#define MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK (0x0A) -#define MPI2_CONFIG_PAGETYPE_EXTENDED (0x0F) -#define MPI2_CONFIG_PAGETYPE_MASK (0x0F) - -#define MPI2_CONFIG_TYPENUM_MASK (0x0FFF) - - -/* ExtPageType field values */ -#define MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT (0x10) -#define MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER (0x11) -#define MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE (0x12) -#define MPI2_CONFIG_EXTPAGETYPE_SAS_PHY (0x13) -#define MPI2_CONFIG_EXTPAGETYPE_LOG (0x14) -#define MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE (0x15) -#define MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG (0x16) -#define MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING (0x17) -#define MPI2_CONFIG_EXTPAGETYPE_SAS_PORT (0x18) -#define MPI2_CONFIG_EXTPAGETYPE_ETHERNET (0x19) -#define MPI2_CONFIG_EXTPAGETYPE_EXT_MANUFACTURING (0x1A) - - -/***************************************************************************** -* PageAddress defines -*****************************************************************************/ - -/* RAID Volume PageAddress format */ -#define MPI2_RAID_VOLUME_PGAD_FORM_MASK (0xF0000000) -#define MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -#define MPI2_RAID_VOLUME_PGAD_FORM_HANDLE (0x10000000) - -#define MPI2_RAID_VOLUME_PGAD_HANDLE_MASK (0x0000FFFF) - - -/* RAID Physical Disk PageAddress format */ -#define MPI2_PHYSDISK_PGAD_FORM_MASK (0xF0000000) -#define MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM (0x00000000) -#define MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM (0x10000000) -#define MPI2_PHYSDISK_PGAD_FORM_DEVHANDLE (0x20000000) - -#define MPI2_PHYSDISK_PGAD_PHYSDISKNUM_MASK (0x000000FF) -#define MPI2_PHYSDISK_PGAD_DEVHANDLE_MASK (0x0000FFFF) - - -/* SAS Expander PageAddress format */ -#define MPI2_SAS_EXPAND_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL (0x00000000) -#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM (0x10000000) -#define MPI2_SAS_EXPAND_PGAD_FORM_HNDL (0x20000000) - -#define MPI2_SAS_EXPAND_PGAD_HANDLE_MASK (0x0000FFFF) -#define MPI2_SAS_EXPAND_PGAD_PHYNUM_MASK (0x00FF0000) -#define MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT (16) - - -/* SAS Device PageAddress format */ -#define MPI2_SAS_DEVICE_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -#define MPI2_SAS_DEVICE_PGAD_FORM_HANDLE (0x20000000) - -#define MPI2_SAS_DEVICE_PGAD_HANDLE_MASK (0x0000FFFF) - - -/* SAS PHY PageAddress format */ -#define MPI2_SAS_PHY_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER (0x00000000) -#define MPI2_SAS_PHY_PGAD_FORM_PHY_TBL_INDEX (0x10000000) - -#define MPI2_SAS_PHY_PGAD_PHY_NUMBER_MASK (0x000000FF) -#define MPI2_SAS_PHY_PGAD_PHY_TBL_INDEX_MASK (0x0000FFFF) - - -/* SAS Port PageAddress format */ -#define MPI2_SASPORT_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SASPORT_PGAD_FORM_GET_NEXT_PORT (0x00000000) -#define MPI2_SASPORT_PGAD_FORM_PORT_NUM (0x10000000) - -#define MPI2_SASPORT_PGAD_PORTNUMBER_MASK (0x00000FFF) - - -/* SAS Enclosure PageAddress format */ -#define MPI2_SAS_ENCLOS_PGAD_FORM_MASK (0xF0000000) -#define MPI2_SAS_ENCLOS_PGAD_FORM_GET_NEXT_HANDLE (0x00000000) -#define MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE (0x10000000) - -#define MPI2_SAS_ENCLOS_PGAD_HANDLE_MASK (0x0000FFFF) - - -/* RAID Configuration PageAddress format */ -#define MPI2_RAID_PGAD_FORM_MASK (0xF0000000) -#define MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM (0x00000000) -#define MPI2_RAID_PGAD_FORM_CONFIGNUM (0x10000000) -#define MPI2_RAID_PGAD_FORM_ACTIVE_CONFIG (0x20000000) - -#define MPI2_RAID_PGAD_CONFIGNUM_MASK (0x000000FF) - - -/* Driver Persistent Mapping PageAddress format */ -#define MPI2_DPM_PGAD_FORM_MASK (0xF0000000) -#define MPI2_DPM_PGAD_FORM_ENTRY_RANGE (0x00000000) - -#define MPI2_DPM_PGAD_ENTRY_COUNT_MASK (0x0FFF0000) -#define MPI2_DPM_PGAD_ENTRY_COUNT_SHIFT (16) -#define MPI2_DPM_PGAD_START_ENTRY_MASK (0x0000FFFF) - - -/* Ethernet PageAddress format */ -#define MPI2_ETHERNET_PGAD_FORM_MASK (0xF0000000) -#define MPI2_ETHERNET_PGAD_FORM_IF_NUM (0x00000000) - -#define MPI2_ETHERNET_PGAD_IF_NUMBER_MASK (0x000000FF) - - - -/**************************************************************************** -* Configuration messages -****************************************************************************/ - -/* Configuration Request Message */ -typedef struct _MPI2_CONFIG_REQUEST -{ - U8 Action; /* 0x00 */ - U8 SGLFlags; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 ExtPageLength; /* 0x04 */ - U8 ExtPageType; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U8 Reserved2; /* 0x0C */ - U8 ProxyVF_ID; /* 0x0D */ - U16 Reserved4; /* 0x0E */ - U32 Reserved3; /* 0x10 */ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ - U32 PageAddress; /* 0x18 */ - MPI2_SGE_IO_UNION PageBufferSGE; /* 0x1C */ -} MPI2_CONFIG_REQUEST, MPI2_POINTER PTR_MPI2_CONFIG_REQUEST, - Mpi2ConfigRequest_t, MPI2_POINTER pMpi2ConfigRequest_t; - -/* values for the Action field */ -#define MPI2_CONFIG_ACTION_PAGE_HEADER (0x00) -#define MPI2_CONFIG_ACTION_PAGE_READ_CURRENT (0x01) -#define MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT (0x02) -#define MPI2_CONFIG_ACTION_PAGE_DEFAULT (0x03) -#define MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM (0x04) -#define MPI2_CONFIG_ACTION_PAGE_READ_DEFAULT (0x05) -#define MPI2_CONFIG_ACTION_PAGE_READ_NVRAM (0x06) -#define MPI2_CONFIG_ACTION_PAGE_GET_CHANGEABLE (0x07) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* Config Reply Message */ -typedef struct _MPI2_CONFIG_REPLY -{ - U8 Action; /* 0x00 */ - U8 SGLFlags; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 ExtPageLength; /* 0x04 */ - U8 ExtPageType; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U16 Reserved2; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x14 */ -} MPI2_CONFIG_REPLY, MPI2_POINTER PTR_MPI2_CONFIG_REPLY, - Mpi2ConfigReply_t, MPI2_POINTER pMpi2ConfigReply_t; - - - -/***************************************************************************** -* -* C o n f i g u r a t i o n P a g e s -* -*****************************************************************************/ - -/**************************************************************************** -* Manufacturing Config pages -****************************************************************************/ - -#define MPI2_MFGPAGE_VENDORID_LSI (0x1000) - -/* SAS */ -#define MPI2_MFGPAGE_DEVID_SAS2004 (0x0070) -#define MPI2_MFGPAGE_DEVID_SAS2008 (0x0072) -#define MPI2_MFGPAGE_DEVID_SAS2108_1 (0x0074) -#define MPI2_MFGPAGE_DEVID_SAS2108_2 (0x0076) -#define MPI2_MFGPAGE_DEVID_SAS2108_3 (0x0077) -#define MPI2_MFGPAGE_DEVID_SAS2116_1 (0x0064) -#define MPI2_MFGPAGE_DEVID_SAS2116_2 (0x0065) - -#define MPI2_MFGPAGE_DEVID_SSS6200 (0x007E) - -#define MPI2_MFGPAGE_DEVID_SAS2208_1 (0x0080) -#define MPI2_MFGPAGE_DEVID_SAS2208_2 (0x0081) -#define MPI2_MFGPAGE_DEVID_SAS2208_3 (0x0082) -#define MPI2_MFGPAGE_DEVID_SAS2208_4 (0x0083) -#define MPI2_MFGPAGE_DEVID_SAS2208_5 (0x0084) -#define MPI2_MFGPAGE_DEVID_SAS2208_6 (0x0085) -#define MPI2_MFGPAGE_DEVID_SAS2308_1 (0x0086) -#define MPI2_MFGPAGE_DEVID_SAS2308_2 (0x0087) -#define MPI2_MFGPAGE_DEVID_SAS2308_3 (0x006E) - - - - -/* Manufacturing Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_MAN_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 ChipName[16]; /* 0x04 */ - U8 ChipRevision[8]; /* 0x14 */ - U8 BoardName[16]; /* 0x1C */ - U8 BoardAssembly[16]; /* 0x2C */ - U8 BoardTracerNumber[16]; /* 0x3C */ -} MPI2_CONFIG_PAGE_MAN_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_0, - Mpi2ManufacturingPage0_t, MPI2_POINTER pMpi2ManufacturingPage0_t; - -#define MPI2_MANUFACTURING0_PAGEVERSION (0x00) - - -/* Manufacturing Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_MAN_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 VPD[256]; /* 0x04 */ -} MPI2_CONFIG_PAGE_MAN_1, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_1, - Mpi2ManufacturingPage1_t, MPI2_POINTER pMpi2ManufacturingPage1_t; - -#define MPI2_MANUFACTURING1_PAGEVERSION (0x00) - - -typedef struct _MPI2_CHIP_REVISION_ID -{ - U16 DeviceID; /* 0x00 */ - U8 PCIRevisionID; /* 0x02 */ - U8 Reserved; /* 0x03 */ -} MPI2_CHIP_REVISION_ID, MPI2_POINTER PTR_MPI2_CHIP_REVISION_ID, - Mpi2ChipRevisionId_t, MPI2_POINTER pMpi2ChipRevisionId_t; - - -/* Manufacturing Page 2 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength at runtime. - */ -#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS -#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_MAN_2 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ - U32 HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/* 0x08 */ -} MPI2_CONFIG_PAGE_MAN_2, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_2, - Mpi2ManufacturingPage2_t, MPI2_POINTER pMpi2ManufacturingPage2_t; - -#define MPI2_MANUFACTURING2_PAGEVERSION (0x00) - - -/* Manufacturing Page 3 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check Header.PageLength at runtime. - */ -#ifndef MPI2_MAN_PAGE_3_INFO_WORDS -#define MPI2_MAN_PAGE_3_INFO_WORDS (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_MAN_3 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - MPI2_CHIP_REVISION_ID ChipId; /* 0x04 */ - U32 Info[MPI2_MAN_PAGE_3_INFO_WORDS];/* 0x08 */ -} MPI2_CONFIG_PAGE_MAN_3, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_3, - Mpi2ManufacturingPage3_t, MPI2_POINTER pMpi2ManufacturingPage3_t; - -#define MPI2_MANUFACTURING3_PAGEVERSION (0x00) - - -/* Manufacturing Page 4 */ - -typedef struct _MPI2_MANPAGE4_PWR_SAVE_SETTINGS -{ - U8 PowerSaveFlags; /* 0x00 */ - U8 InternalOperationsSleepTime; /* 0x01 */ - U8 InternalOperationsRunTime; /* 0x02 */ - U8 HostIdleTime; /* 0x03 */ -} MPI2_MANPAGE4_PWR_SAVE_SETTINGS, - MPI2_POINTER PTR_MPI2_MANPAGE4_PWR_SAVE_SETTINGS, - Mpi2ManPage4PwrSaveSettings_t, MPI2_POINTER pMpi2ManPage4PwrSaveSettings_t; - -/* defines for the PowerSaveFlags field */ -#define MPI2_MANPAGE4_MASK_POWERSAVE_MODE (0x03) -#define MPI2_MANPAGE4_POWERSAVE_MODE_DISABLED (0x00) -#define MPI2_MANPAGE4_CUSTOM_POWERSAVE_MODE (0x01) -#define MPI2_MANPAGE4_FULL_POWERSAVE_MODE (0x02) - -typedef struct _MPI2_CONFIG_PAGE_MAN_4 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Flags; /* 0x08 */ - U8 InquirySize; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - U8 InquiryData[56]; /* 0x10 */ - U32 RAID0VolumeSettings; /* 0x48 */ - U32 RAID1EVolumeSettings; /* 0x4C */ - U32 RAID1VolumeSettings; /* 0x50 */ - U32 RAID10VolumeSettings; /* 0x54 */ - U32 Reserved4; /* 0x58 */ - U32 Reserved5; /* 0x5C */ - MPI2_MANPAGE4_PWR_SAVE_SETTINGS PowerSaveSettings; /* 0x60 */ - U8 MaxOCEDisks; /* 0x64 */ - U8 ResyncRate; /* 0x65 */ - U16 DataScrubDuration; /* 0x66 */ - U8 MaxHotSpares; /* 0x68 */ - U8 MaxPhysDisksPerVol; /* 0x69 */ - U8 MaxPhysDisks; /* 0x6A */ - U8 MaxVolumes; /* 0x6B */ -} MPI2_CONFIG_PAGE_MAN_4, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_4, - Mpi2ManufacturingPage4_t, MPI2_POINTER pMpi2ManufacturingPage4_t; - -#define MPI2_MANUFACTURING4_PAGEVERSION (0x0A) - -/* Manufacturing Page 4 Flags field */ -#define MPI2_MANPAGE4_METADATA_SIZE_MASK (0x00030000) -#define MPI2_MANPAGE4_METADATA_512MB (0x00000000) - -#define MPI2_MANPAGE4_MIX_SSD_SAS_SATA (0x00008000) -#define MPI2_MANPAGE4_MIX_SSD_AND_NON_SSD (0x00004000) -#define MPI2_MANPAGE4_HIDE_PHYSDISK_NON_IR (0x00002000) - -#define MPI2_MANPAGE4_MASK_PHYSDISK_COERCION (0x00001C00) -#define MPI2_MANPAGE4_PHYSDISK_COERCION_1GB (0x00000000) -#define MPI2_MANPAGE4_PHYSDISK_128MB_COERCION (0x00000400) -#define MPI2_MANPAGE4_PHYSDISK_ADAPTIVE_COERCION (0x00000800) -#define MPI2_MANPAGE4_PHYSDISK_ZERO_COERCION (0x00000C00) - -#define MPI2_MANPAGE4_MASK_BAD_BLOCK_MARKING (0x00000300) -#define MPI2_MANPAGE4_DEFAULT_BAD_BLOCK_MARKING (0x00000000) -#define MPI2_MANPAGE4_TABLE_BAD_BLOCK_MARKING (0x00000100) -#define MPI2_MANPAGE4_WRITE_LONG_BAD_BLOCK_MARKING (0x00000200) - -#define MPI2_MANPAGE4_FORCE_OFFLINE_FAILOVER (0x00000080) -#define MPI2_MANPAGE4_RAID10_DISABLE (0x00000040) -#define MPI2_MANPAGE4_RAID1E_DISABLE (0x00000020) -#define MPI2_MANPAGE4_RAID1_DISABLE (0x00000010) -#define MPI2_MANPAGE4_RAID0_DISABLE (0x00000008) -#define MPI2_MANPAGE4_IR_MODEPAGE8_DISABLE (0x00000004) -#define MPI2_MANPAGE4_IM_RESYNC_CACHE_ENABLE (0x00000002) -#define MPI2_MANPAGE4_IR_NO_MIX_SAS_SATA (0x00000001) - - -/* Manufacturing Page 5 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES -#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) -#endif - -typedef struct _MPI2_MANUFACTURING5_ENTRY -{ - U64 WWID; /* 0x00 */ - U64 DeviceName; /* 0x08 */ -} MPI2_MANUFACTURING5_ENTRY, MPI2_POINTER PTR_MPI2_MANUFACTURING5_ENTRY, - Mpi2Manufacturing5Entry_t, MPI2_POINTER pMpi2Manufacturing5Entry_t; - -typedef struct _MPI2_CONFIG_PAGE_MAN_5 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhys; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ - MPI2_MANUFACTURING5_ENTRY Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/* 0x08 */ -} MPI2_CONFIG_PAGE_MAN_5, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_5, - Mpi2ManufacturingPage5_t, MPI2_POINTER pMpi2ManufacturingPage5_t; - -#define MPI2_MANUFACTURING5_PAGEVERSION (0x03) - - -/* Manufacturing Page 6 */ - -typedef struct _MPI2_CONFIG_PAGE_MAN_6 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo;/* 0x04 */ -} MPI2_CONFIG_PAGE_MAN_6, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_6, - Mpi2ManufacturingPage6_t, MPI2_POINTER pMpi2ManufacturingPage6_t; - -#define MPI2_MANUFACTURING6_PAGEVERSION (0x00) - - -/* Manufacturing Page 7 */ - -typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO -{ - U32 Pinout; /* 0x00 */ - U8 Connector[16]; /* 0x04 */ - U8 Location; /* 0x14 */ - U8 ReceptacleID; /* 0x15 */ - U16 Slot; /* 0x16 */ - U32 Reserved2; /* 0x18 */ -} MPI2_MANPAGE7_CONNECTOR_INFO, MPI2_POINTER PTR_MPI2_MANPAGE7_CONNECTOR_INFO, - Mpi2ManPage7ConnectorInfo_t, MPI2_POINTER pMpi2ManPage7ConnectorInfo_t; - -/* defines for the Pinout field */ -#define MPI2_MANPAGE7_PINOUT_LANE_MASK (0x0000FF00) -#define MPI2_MANPAGE7_PINOUT_LANE_SHIFT (8) - -#define MPI2_MANPAGE7_PINOUT_TYPE_MASK (0x000000FF) -#define MPI2_MANPAGE7_PINOUT_TYPE_UNKNOWN (0x00) -#define MPI2_MANPAGE7_PINOUT_SATA_SINGLE (0x01) -#define MPI2_MANPAGE7_PINOUT_SFF_8482 (0x02) -#define MPI2_MANPAGE7_PINOUT_SFF_8486 (0x03) -#define MPI2_MANPAGE7_PINOUT_SFF_8484 (0x04) -#define MPI2_MANPAGE7_PINOUT_SFF_8087 (0x05) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_4I (0x06) -#define MPI2_MANPAGE7_PINOUT_SFF_8643_8I (0x07) -#define MPI2_MANPAGE7_PINOUT_SFF_8470 (0x08) -#define MPI2_MANPAGE7_PINOUT_SFF_8088 (0x09) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_4X (0x0A) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_8X (0x0B) -#define MPI2_MANPAGE7_PINOUT_SFF_8644_16X (0x0C) -#define MPI2_MANPAGE7_PINOUT_SFF_8436 (0x0D) - -/* defines for the Location field */ -#define MPI2_MANPAGE7_LOCATION_UNKNOWN (0x01) -#define MPI2_MANPAGE7_LOCATION_INTERNAL (0x02) -#define MPI2_MANPAGE7_LOCATION_EXTERNAL (0x04) -#define MPI2_MANPAGE7_LOCATION_SWITCHABLE (0x08) -#define MPI2_MANPAGE7_LOCATION_AUTO (0x10) -#define MPI2_MANPAGE7_LOCATION_NOT_PRESENT (0x20) -#define MPI2_MANPAGE7_LOCATION_NOT_CONNECTED (0x80) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX -#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_MAN_7 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U32 Flags; /* 0x0C */ - U8 EnclosureName[16]; /* 0x10 */ - U8 NumPhys; /* 0x20 */ - U8 Reserved3; /* 0x21 */ - U16 Reserved4; /* 0x22 */ - MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /* 0x24 */ -} MPI2_CONFIG_PAGE_MAN_7, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_7, - Mpi2ManufacturingPage7_t, MPI2_POINTER pMpi2ManufacturingPage7_t; - -#define MPI2_MANUFACTURING7_PAGEVERSION (0x01) - -/* defines for the Flags field */ -#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) - - -/* - * Generic structure to use for product-specific manufacturing pages - * (currently Manufacturing Page 8 through Manufacturing Page 31). - */ - -typedef struct _MPI2_CONFIG_PAGE_MAN_PS -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo;/* 0x04 */ -} MPI2_CONFIG_PAGE_MAN_PS, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_PS, - Mpi2ManufacturingPagePS_t, MPI2_POINTER pMpi2ManufacturingPagePS_t; - -#define MPI2_MANUFACTURING8_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING9_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING10_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING11_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING12_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING13_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING14_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING15_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING16_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING17_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING18_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING19_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING20_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING21_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING22_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING23_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING24_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING25_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING26_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING27_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING28_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING29_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING30_PAGEVERSION (0x00) -#define MPI2_MANUFACTURING31_PAGEVERSION (0x00) - - -/**************************************************************************** -* IO Unit Config Pages -****************************************************************************/ - -/* IO Unit Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U64 UniqueValue; /* 0x04 */ - MPI2_VERSION_UNION NvdataVersionDefault; /* 0x08 */ - MPI2_VERSION_UNION NvdataVersionPersistent; /* 0x0A */ -} MPI2_CONFIG_PAGE_IO_UNIT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_0, - Mpi2IOUnitPage0_t, MPI2_POINTER pMpi2IOUnitPage0_t; - -#define MPI2_IOUNITPAGE0_PAGEVERSION (0x02) - - -/* IO Unit Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Flags; /* 0x04 */ -} MPI2_CONFIG_PAGE_IO_UNIT_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_1, - Mpi2IOUnitPage1_t, MPI2_POINTER pMpi2IOUnitPage1_t; - -#define MPI2_IOUNITPAGE1_PAGEVERSION (0x04) - -/* IO Unit Page 1 Flags defines */ -#define MPI2_IOUNITPAGE1_ENABLE_HOST_BASED_DISCOVERY (0x00000800) -#define MPI2_IOUNITPAGE1_MASK_SATA_WRITE_CACHE (0x00000600) -#define MPI2_IOUNITPAGE1_SATA_WRITE_CACHE_SHIFT (9) -#define MPI2_IOUNITPAGE1_ENABLE_SATA_WRITE_CACHE (0x00000000) -#define MPI2_IOUNITPAGE1_DISABLE_SATA_WRITE_CACHE (0x00000200) -#define MPI2_IOUNITPAGE1_UNCHANGED_SATA_WRITE_CACHE (0x00000400) -#define MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE (0x00000100) -#define MPI2_IOUNITPAGE1_DISABLE_IR (0x00000040) -#define MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING (0x00000020) -#define MPI2_IOUNITPAGE1_IR_USE_STATIC_VOLUME_ID (0x00000004) - - -/* IO Unit Page 3 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for GPIOCount at runtime. - */ -#ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX -#define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 GPIOCount; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U16 GPIOVal[MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX];/* 0x08 */ -} MPI2_CONFIG_PAGE_IO_UNIT_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_3, - Mpi2IOUnitPage3_t, MPI2_POINTER pMpi2IOUnitPage3_t; - -#define MPI2_IOUNITPAGE3_PAGEVERSION (0x01) - -/* defines for IO Unit Page 3 GPIOVal field */ -#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_MASK (0xFFFC) -#define MPI2_IOUNITPAGE3_GPIO_FUNCTION_SHIFT (2) -#define MPI2_IOUNITPAGE3_GPIO_SETTING_OFF (0x0000) -#define MPI2_IOUNITPAGE3_GPIO_SETTING_ON (0x0001) - - -/* IO Unit Page 5 */ - -/* - * Upper layer code (drivers, utilities, etc.) should leave this define set to - * one and check the value returned for NumDmaEngines at runtime. - */ -#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES -#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U64 RaidAcceleratorBufferBaseAddress; /* 0x04 */ - U64 RaidAcceleratorBufferSize; /* 0x0C */ - U64 RaidAcceleratorControlBaseAddress; /* 0x14 */ - U8 RAControlSize; /* 0x1C */ - U8 NumDmaEngines; /* 0x1D */ - U8 RAMinControlSize; /* 0x1E */ - U8 RAMaxControlSize; /* 0x1F */ - U32 Reserved1; /* 0x20 */ - U32 Reserved2; /* 0x24 */ - U32 Reserved3; /* 0x28 */ - U32 DmaEngineCapabilities - [MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /* 0x2C */ -} MPI2_CONFIG_PAGE_IO_UNIT_5, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, - Mpi2IOUnitPage5_t, MPI2_POINTER pMpi2IOUnitPage5_t; - -#define MPI2_IOUNITPAGE5_PAGEVERSION (0x00) - -/* defines for IO Unit Page 5 DmaEngineCapabilities field */ -#define MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS (0xFF00) -#define MPI2_IOUNITPAGE5_DMA_CAP_SHIFT_MAX_REQUESTS (16) - -#define MPI2_IOUNITPAGE5_DMA_CAP_EEDP (0x0008) -#define MPI2_IOUNITPAGE5_DMA_CAP_PARITY_GENERATION (0x0004) -#define MPI2_IOUNITPAGE5_DMA_CAP_HASHING (0x0002) -#define MPI2_IOUNITPAGE5_DMA_CAP_ENCRYPTION (0x0001) - - -/* IO Unit Page 6 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_6 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 Flags; /* 0x04 */ - U8 RAHostControlSize; /* 0x06 */ - U8 Reserved0; /* 0x07 */ - U64 RaidAcceleratorHostControlBaseAddress; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ - U32 Reserved3; /* 0x18 */ -} MPI2_CONFIG_PAGE_IO_UNIT_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_6, - Mpi2IOUnitPage6_t, MPI2_POINTER pMpi2IOUnitPage6_t; - -#define MPI2_IOUNITPAGE6_PAGEVERSION (0x00) - -/* defines for IO Unit Page 6 Flags field */ -#define MPI2_IOUNITPAGE6_FLAGS_ENABLE_RAID_ACCELERATOR (0x0001) - - -/* IO Unit Page 7 */ - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_7 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 Reserved1; /* 0x04 */ - U8 PCIeWidth; /* 0x06 */ - U8 PCIeSpeed; /* 0x07 */ - U32 ProcessorState; /* 0x08 */ - U32 PowerManagementCapabilities; /* 0x0C */ - U16 IOCTemperature; /* 0x10 */ - U8 IOCTemperatureUnits; /* 0x12 */ - U8 IOCSpeed; /* 0x13 */ - U16 BoardTemperature; /* 0x14 */ - U8 BoardTemperatureUnits; /* 0x16 */ - U8 Reserved3; /* 0x17 */ -} MPI2_CONFIG_PAGE_IO_UNIT_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_7, - Mpi2IOUnitPage7_t, MPI2_POINTER pMpi2IOUnitPage7_t; - -#define MPI2_IOUNITPAGE7_PAGEVERSION (0x02) - -/* defines for IO Unit Page 7 PCIeWidth field */ -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X1 (0x01) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X2 (0x02) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X4 (0x04) -#define MPI2_IOUNITPAGE7_PCIE_WIDTH_X8 (0x08) - -/* defines for IO Unit Page 7 PCIeSpeed field */ -#define MPI2_IOUNITPAGE7_PCIE_SPEED_2_5_GBPS (0x00) -#define MPI2_IOUNITPAGE7_PCIE_SPEED_5_0_GBPS (0x01) -#define MPI2_IOUNITPAGE7_PCIE_SPEED_8_0_GBPS (0x02) - -/* defines for IO Unit Page 7 ProcessorState field */ -#define MPI2_IOUNITPAGE7_PSTATE_MASK_SECOND (0x0000000F) -#define MPI2_IOUNITPAGE7_PSTATE_SHIFT_SECOND (0) - -#define MPI2_IOUNITPAGE7_PSTATE_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_PSTATE_DISABLED (0x01) -#define MPI2_IOUNITPAGE7_PSTATE_ENABLED (0x02) - -/* defines for IO Unit Page 7 PowerManagementCapabilities field */ -#define MPI2_IOUNITPAGE7_PMCAP_12_5_PCT_IOCSPEED (0x00000400) -#define MPI2_IOUNITPAGE7_PMCAP_25_0_PCT_IOCSPEED (0x00000200) -#define MPI2_IOUNITPAGE7_PMCAP_50_0_PCT_IOCSPEED (0x00000100) -#define MPI2_IOUNITPAGE7_PMCAP_PCIE_WIDTH_CHANGE (0x00000008) /* obsolete */ -#define MPI2_IOUNITPAGE7_PMCAP_PCIE_SPEED_CHANGE (0x00000004) /* obsolete */ - -/* defines for IO Unit Page 7 IOCTemperatureUnits field */ -#define MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT (0x01) -#define MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS (0x02) - -/* defines for IO Unit Page 7 IOCSpeed field */ -#define MPI2_IOUNITPAGE7_IOC_SPEED_FULL (0x01) -#define MPI2_IOUNITPAGE7_IOC_SPEED_HALF (0x02) -#define MPI2_IOUNITPAGE7_IOC_SPEED_QUARTER (0x04) -#define MPI2_IOUNITPAGE7_IOC_SPEED_EIGHTH (0x08) - -/* defines for IO Unit Page 7 BoardTemperatureUnits field */ -#define MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT (0x00) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_FAHRENHEIT (0x01) -#define MPI2_IOUNITPAGE7_BOARD_TEMP_CELSIUS (0x02) - -/* IO Unit Page 8 */ - -#define MPI2_IOUNIT8_NUM_THRESHOLDS (4) - -typedef struct _MPI2_IOUNIT8_SENSOR { - U16 Flags; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U16 - Threshold[MPI2_IOUNIT8_NUM_THRESHOLDS]; /* 0x04 */ - U32 Reserved2; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U32 Reserved4; /* 0x14 */ -} MPI2_IOUNIT8_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT8_SENSOR, -Mpi2IOUnit8Sensor_t, MPI2_POINTER pMpi2IOUnit8Sensor_t; - -/* defines for IO Unit Page 8 Sensor Flags field */ -#define MPI2_IOUNIT8_SENSOR_FLAGS_T3_ENABLE (0x0008) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T2_ENABLE (0x0004) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T1_ENABLE (0x0002) -#define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumSensors at runtime. - */ -#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U8 NumSensors; /* 0x0C */ - U8 PollingInterval; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_IOUNIT8_SENSOR - Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, -Mpi2IOUnitPage8_t, MPI2_POINTER pMpi2IOUnitPage8_t; - -#define MPI2_IOUNITPAGE8_PAGEVERSION (0x00) - - -/* IO Unit Page 9 */ - -typedef struct _MPI2_IOUNIT9_SENSOR { - U16 CurrentTemperature; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U8 Flags; /* 0x04 */ - U8 Reserved2; /* 0x05 */ - U16 Reserved3; /* 0x06 */ - U32 Reserved4; /* 0x08 */ - U32 Reserved5; /* 0x0C */ -} MPI2_IOUNIT9_SENSOR, MPI2_POINTER PTR_MPI2_IOUNIT9_SENSOR, -Mpi2IOUnit9Sensor_t, MPI2_POINTER pMpi2IOUnit9Sensor_t; - -/* defines for IO Unit Page 9 Sensor Flags field */ -#define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumSensors at runtime. - */ -#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U8 NumSensors; /* 0x0C */ - U8 Reserved4; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_IOUNIT9_SENSOR - Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_9, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, -Mpi2IOUnitPage9_t, MPI2_POINTER pMpi2IOUnitPage9_t; - -#define MPI2_IOUNITPAGE9_PAGEVERSION (0x00) - - -/* IO Unit Page 10 */ - -typedef struct _MPI2_IOUNIT10_FUNCTION { - U8 CreditPercent; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ -} MPI2_IOUNIT10_FUNCTION, MPI2_POINTER PTR_MPI2_IOUNIT10_FUNCTION, -Mpi2IOUnit10Function_t, MPI2_POINTER pMpi2IOUnit10Function_t; - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumFunctions at runtime. - */ -#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES -#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumFunctions; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ - MPI2_IOUNIT10_FUNCTION - Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/* 0x10 */ -} MPI2_CONFIG_PAGE_IO_UNIT_10, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, -Mpi2IOUnitPage10_t, MPI2_POINTER pMpi2IOUnitPage10_t; - -#define MPI2_IOUNITPAGE10_PAGEVERSION (0x01) - - - -/**************************************************************************** -* IOC Config Pages -****************************************************************************/ - -/* IOC Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_IOC_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U16 VendorID; /* 0x0C */ - U16 DeviceID; /* 0x0E */ - U8 RevisionID; /* 0x10 */ - U8 Reserved3; /* 0x11 */ - U16 Reserved4; /* 0x12 */ - U32 ClassCode; /* 0x14 */ - U16 SubsystemVendorID; /* 0x18 */ - U16 SubsystemID; /* 0x1A */ -} MPI2_CONFIG_PAGE_IOC_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_0, - Mpi2IOCPage0_t, MPI2_POINTER pMpi2IOCPage0_t; - -#define MPI2_IOCPAGE0_PAGEVERSION (0x02) - - -/* IOC Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_IOC_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Flags; /* 0x04 */ - U32 CoalescingTimeout; /* 0x08 */ - U8 CoalescingDepth; /* 0x0C */ - U8 PCISlotNum; /* 0x0D */ - U8 PCIBusNum; /* 0x0E */ - U8 PCIDomainSegment; /* 0x0F */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ -} MPI2_CONFIG_PAGE_IOC_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_1, - Mpi2IOCPage1_t, MPI2_POINTER pMpi2IOCPage1_t; - -#define MPI2_IOCPAGE1_PAGEVERSION (0x05) - -/* defines for IOC Page 1 Flags field */ -#define MPI2_IOCPAGE1_REPLY_COALESCING (0x00000001) - -#define MPI2_IOCPAGE1_PCISLOTNUM_UNKNOWN (0xFF) -#define MPI2_IOCPAGE1_PCIBUSNUM_UNKNOWN (0xFF) -#define MPI2_IOCPAGE1_PCIDOMAIN_UNKNOWN (0xFF) - -/* IOC Page 6 */ - -typedef struct _MPI2_CONFIG_PAGE_IOC_6 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 CapabilitiesFlags; /* 0x04 */ - U8 MaxDrivesRAID0; /* 0x08 */ - U8 MaxDrivesRAID1; /* 0x09 */ - U8 MaxDrivesRAID1E; /* 0x0A */ - U8 MaxDrivesRAID10; /* 0x0B */ - U8 MinDrivesRAID0; /* 0x0C */ - U8 MinDrivesRAID1; /* 0x0D */ - U8 MinDrivesRAID1E; /* 0x0E */ - U8 MinDrivesRAID10; /* 0x0F */ - U32 Reserved1; /* 0x10 */ - U8 MaxGlobalHotSpares; /* 0x14 */ - U8 MaxPhysDisks; /* 0x15 */ - U8 MaxVolumes; /* 0x16 */ - U8 MaxConfigs; /* 0x17 */ - U8 MaxOCEDisks; /* 0x18 */ - U8 Reserved2; /* 0x19 */ - U16 Reserved3; /* 0x1A */ - U32 SupportedStripeSizeMapRAID0; /* 0x1C */ - U32 SupportedStripeSizeMapRAID1E; /* 0x20 */ - U32 SupportedStripeSizeMapRAID10; /* 0x24 */ - U32 Reserved4; /* 0x28 */ - U32 Reserved5; /* 0x2C */ - U16 DefaultMetadataSize; /* 0x30 */ - U16 Reserved6; /* 0x32 */ - U16 MaxBadBlockTableEntries; /* 0x34 */ - U16 Reserved7; /* 0x36 */ - U32 IRNvsramVersion; /* 0x38 */ -} MPI2_CONFIG_PAGE_IOC_6, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_6, - Mpi2IOCPage6_t, MPI2_POINTER pMpi2IOCPage6_t; - -#define MPI2_IOCPAGE6_PAGEVERSION (0x04) - -/* defines for IOC Page 6 CapabilitiesFlags */ -#define MPI2_IOCPAGE6_CAP_FLAGS_RAID10_SUPPORT (0x00000010) -#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1_SUPPORT (0x00000008) -#define MPI2_IOCPAGE6_CAP_FLAGS_RAID1E_SUPPORT (0x00000004) -#define MPI2_IOCPAGE6_CAP_FLAGS_RAID0_SUPPORT (0x00000002) -#define MPI2_IOCPAGE6_CAP_FLAGS_GLOBAL_HOT_SPARE (0x00000001) - - -/* IOC Page 7 */ - -#define MPI2_IOCPAGE7_EVENTMASK_WORDS (4) - -typedef struct _MPI2_CONFIG_PAGE_IOC_7 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 EventMasks[MPI2_IOCPAGE7_EVENTMASK_WORDS];/* 0x08 */ - U16 SASBroadcastPrimitiveMasks; /* 0x18 */ - U16 SASNotifyPrimitiveMasks; /* 0x1A */ - U32 Reserved3; /* 0x1C */ -} MPI2_CONFIG_PAGE_IOC_7, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_7, - Mpi2IOCPage7_t, MPI2_POINTER pMpi2IOCPage7_t; - -#define MPI2_IOCPAGE7_PAGEVERSION (0x02) - - -/* IOC Page 8 */ - -typedef struct _MPI2_CONFIG_PAGE_IOC_8 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumDevsPerEnclosure; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U16 MaxPersistentEntries; /* 0x08 */ - U16 MaxNumPhysicalMappedIDs; /* 0x0A */ - U16 Flags; /* 0x0C */ - U16 Reserved3; /* 0x0E */ - U16 IRVolumeMappingFlags; /* 0x10 */ - U16 Reserved4; /* 0x12 */ - U32 Reserved5; /* 0x14 */ -} MPI2_CONFIG_PAGE_IOC_8, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_IOC_8, - Mpi2IOCPage8_t, MPI2_POINTER pMpi2IOCPage8_t; - -#define MPI2_IOCPAGE8_PAGEVERSION (0x00) - -/* defines for IOC Page 8 Flags field */ -#define MPI2_IOCPAGE8_FLAGS_DA_START_SLOT_1 (0x00000020) -#define MPI2_IOCPAGE8_FLAGS_RESERVED_TARGETID_0 (0x00000010) - -#define MPI2_IOCPAGE8_FLAGS_MASK_MAPPING_MODE (0x0000000E) -#define MPI2_IOCPAGE8_FLAGS_DEVICE_PERSISTENCE_MAPPING (0x00000000) -#define MPI2_IOCPAGE8_FLAGS_ENCLOSURE_SLOT_MAPPING (0x00000002) - -#define MPI2_IOCPAGE8_FLAGS_DISABLE_PERSISTENT_MAPPING (0x00000001) -#define MPI2_IOCPAGE8_FLAGS_ENABLE_PERSISTENT_MAPPING (0x00000000) - -/* defines for IOC Page 8 IRVolumeMappingFlags */ -#define MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE (0x00000003) -#define MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING (0x00000000) -#define MPI2_IOCPAGE8_IRFLAGS_HIGH_VOLUME_MAPPING (0x00000001) - - -/**************************************************************************** -* BIOS Config Pages -****************************************************************************/ - -/* BIOS Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_BIOS_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 BiosOptions; /* 0x04 */ - U32 IOCSettings; /* 0x08 */ - U32 Reserved1; /* 0x0C */ - U32 DeviceSettings; /* 0x10 */ - U16 NumberOfDevices; /* 0x14 */ - U16 Reserved2; /* 0x16 */ - U16 IOTimeoutBlockDevicesNonRM; /* 0x18 */ - U16 IOTimeoutSequential; /* 0x1A */ - U16 IOTimeoutOther; /* 0x1C */ - U16 IOTimeoutBlockDevicesRM; /* 0x1E */ -} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1, - Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t; - -#define MPI2_BIOSPAGE1_PAGEVERSION (0x04) - -/* values for BIOS Page 1 BiosOptions field */ -#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) - -/* values for BIOS Page 1 IOCSettings field */ -#define MPI2_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) -#define MPI2_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) -#define MPI2_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) - -#define MPI2_BIOSPAGE1_IOCSET_MASK_RM_SETTING (0x000000C0) -#define MPI2_BIOSPAGE1_IOCSET_NONE_RM_SETTING (0x00000000) -#define MPI2_BIOSPAGE1_IOCSET_BOOT_RM_SETTING (0x00000040) -#define MPI2_BIOSPAGE1_IOCSET_MEDIA_RM_SETTING (0x00000080) - -#define MPI2_BIOSPAGE1_IOCSET_MASK_ADAPTER_SUPPORT (0x00000030) -#define MPI2_BIOSPAGE1_IOCSET_NO_SUPPORT (0x00000000) -#define MPI2_BIOSPAGE1_IOCSET_BIOS_SUPPORT (0x00000010) -#define MPI2_BIOSPAGE1_IOCSET_OS_SUPPORT (0x00000020) -#define MPI2_BIOSPAGE1_IOCSET_ALL_SUPPORT (0x00000030) - -#define MPI2_BIOSPAGE1_IOCSET_ALTERNATE_CHS (0x00000008) - -/* values for BIOS Page 1 DeviceSettings field */ -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SMART_POLLING (0x00000010) -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_SEQ_LUN (0x00000008) -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_RM_LUN (0x00000004) -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_NON_RM_LUN (0x00000002) -#define MPI2_BIOSPAGE1_DEVSET_DISABLE_OTHER_LUN (0x00000001) - - -/* BIOS Page 2 */ - -typedef struct _MPI2_BOOT_DEVICE_ADAPTER_ORDER -{ - U32 Reserved1; /* 0x00 */ - U32 Reserved2; /* 0x04 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ - U32 Reserved5; /* 0x10 */ - U32 Reserved6; /* 0x14 */ -} MPI2_BOOT_DEVICE_ADAPTER_ORDER, - MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ADAPTER_ORDER, - Mpi2BootDeviceAdapterOrder_t, MPI2_POINTER pMpi2BootDeviceAdapterOrder_t; - -typedef struct _MPI2_BOOT_DEVICE_SAS_WWID -{ - U64 SASAddress; /* 0x00 */ - U8 LUN[8]; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ -} MPI2_BOOT_DEVICE_SAS_WWID, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_SAS_WWID, - Mpi2BootDeviceSasWwid_t, MPI2_POINTER pMpi2BootDeviceSasWwid_t; - -typedef struct _MPI2_BOOT_DEVICE_ENCLOSURE_SLOT -{ - U64 EnclosureLogicalID; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - U16 SlotNumber; /* 0x10 */ - U16 Reserved3; /* 0x12 */ - U32 Reserved4; /* 0x14 */ -} MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, - MPI2_POINTER PTR_MPI2_BOOT_DEVICE_ENCLOSURE_SLOT, - Mpi2BootDeviceEnclosureSlot_t, MPI2_POINTER pMpi2BootDeviceEnclosureSlot_t; - -typedef struct _MPI2_BOOT_DEVICE_DEVICE_NAME -{ - U64 DeviceName; /* 0x00 */ - U8 LUN[8]; /* 0x08 */ - U32 Reserved1; /* 0x10 */ - U32 Reserved2; /* 0x14 */ -} MPI2_BOOT_DEVICE_DEVICE_NAME, MPI2_POINTER PTR_MPI2_BOOT_DEVICE_DEVICE_NAME, - Mpi2BootDeviceDeviceName_t, MPI2_POINTER pMpi2BootDeviceDeviceName_t; - -typedef union _MPI2_MPI2_BIOSPAGE2_BOOT_DEVICE -{ - MPI2_BOOT_DEVICE_ADAPTER_ORDER AdapterOrder; - MPI2_BOOT_DEVICE_SAS_WWID SasWwid; - MPI2_BOOT_DEVICE_ENCLOSURE_SLOT EnclosureSlot; - MPI2_BOOT_DEVICE_DEVICE_NAME DeviceName; -} MPI2_BIOSPAGE2_BOOT_DEVICE, MPI2_POINTER PTR_MPI2_BIOSPAGE2_BOOT_DEVICE, - Mpi2BiosPage2BootDevice_t, MPI2_POINTER pMpi2BiosPage2BootDevice_t; - -typedef struct _MPI2_CONFIG_PAGE_BIOS_2 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U32 Reserved3; /* 0x0C */ - U32 Reserved4; /* 0x10 */ - U32 Reserved5; /* 0x14 */ - U32 Reserved6; /* 0x18 */ - U8 ReqBootDeviceForm; /* 0x1C */ - U8 Reserved7; /* 0x1D */ - U16 Reserved8; /* 0x1E */ - MPI2_BIOSPAGE2_BOOT_DEVICE RequestedBootDevice; /* 0x20 */ - U8 ReqAltBootDeviceForm; /* 0x38 */ - U8 Reserved9; /* 0x39 */ - U16 Reserved10; /* 0x3A */ - MPI2_BIOSPAGE2_BOOT_DEVICE RequestedAltBootDevice; /* 0x3C */ - U8 CurrentBootDeviceForm; /* 0x58 */ - U8 Reserved11; /* 0x59 */ - U16 Reserved12; /* 0x5A */ - MPI2_BIOSPAGE2_BOOT_DEVICE CurrentBootDevice; /* 0x58 */ -} MPI2_CONFIG_PAGE_BIOS_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_2, - Mpi2BiosPage2_t, MPI2_POINTER pMpi2BiosPage2_t; - -#define MPI2_BIOSPAGE2_PAGEVERSION (0x04) - -/* values for BIOS Page 2 BootDeviceForm fields */ -#define MPI2_BIOSPAGE2_FORM_MASK (0x0F) -#define MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED (0x00) -#define MPI2_BIOSPAGE2_FORM_SAS_WWID (0x05) -#define MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) -#define MPI2_BIOSPAGE2_FORM_DEVICE_NAME (0x07) - - -/* BIOS Page 3 */ - -typedef struct _MPI2_ADAPTER_INFO -{ - U8 PciBusNumber; /* 0x00 */ - U8 PciDeviceAndFunctionNumber; /* 0x01 */ - U16 AdapterFlags; /* 0x02 */ -} MPI2_ADAPTER_INFO, MPI2_POINTER PTR_MPI2_ADAPTER_INFO, - Mpi2AdapterInfo_t, MPI2_POINTER pMpi2AdapterInfo_t; - -#define MPI2_ADAPTER_INFO_FLAGS_EMBEDDED (0x0001) -#define MPI2_ADAPTER_INFO_FLAGS_INIT_STATUS (0x0002) - -typedef struct _MPI2_CONFIG_PAGE_BIOS_3 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U32 GlobalFlags; /* 0x04 */ - U32 BiosVersion; /* 0x08 */ - MPI2_ADAPTER_INFO AdapterOrder[4]; /* 0x0C */ - U32 Reserved1; /* 0x1C */ -} MPI2_CONFIG_PAGE_BIOS_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_3, - Mpi2BiosPage3_t, MPI2_POINTER pMpi2BiosPage3_t; - -#define MPI2_BIOSPAGE3_PAGEVERSION (0x00) - -/* values for BIOS Page 3 GlobalFlags */ -#define MPI2_BIOSPAGE3_FLAGS_PAUSE_ON_ERROR (0x00000002) -#define MPI2_BIOSPAGE3_FLAGS_VERBOSE_ENABLE (0x00000004) -#define MPI2_BIOSPAGE3_FLAGS_HOOK_INT_40_DISABLE (0x00000010) - -#define MPI2_BIOSPAGE3_FLAGS_DEV_LIST_DISPLAY_MASK (0x000000E0) -#define MPI2_BIOSPAGE3_FLAGS_INSTALLED_DEV_DISPLAY (0x00000000) -#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DISPLAY (0x00000020) -#define MPI2_BIOSPAGE3_FLAGS_ADAPTER_DEV_DISPLAY (0x00000040) - - -/* BIOS Page 4 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES -#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) -#endif - -typedef struct _MPI2_BIOS4_ENTRY -{ - U64 ReassignmentWWID; /* 0x00 */ - U64 ReassignmentDeviceName; /* 0x08 */ -} MPI2_BIOS4_ENTRY, MPI2_POINTER PTR_MPI2_BIOS4_ENTRY, - Mpi2MBios4Entry_t, MPI2_POINTER pMpi2Bios4Entry_t; - -typedef struct _MPI2_CONFIG_PAGE_BIOS_4 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhys; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - MPI2_BIOS4_ENTRY Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /* 0x08 */ -} MPI2_CONFIG_PAGE_BIOS_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_4, - Mpi2BiosPage4_t, MPI2_POINTER pMpi2BiosPage4_t; - -#define MPI2_BIOSPAGE4_PAGEVERSION (0x01) - - -/**************************************************************************** -* RAID Volume Config Pages -****************************************************************************/ - -/* RAID Volume Page 0 */ - -typedef struct _MPI2_RAIDVOL0_PHYS_DISK -{ - U8 RAIDSetNum; /* 0x00 */ - U8 PhysDiskMap; /* 0x01 */ - U8 PhysDiskNum; /* 0x02 */ - U8 Reserved; /* 0x03 */ -} MPI2_RAIDVOL0_PHYS_DISK, MPI2_POINTER PTR_MPI2_RAIDVOL0_PHYS_DISK, - Mpi2RaidVol0PhysDisk_t, MPI2_POINTER pMpi2RaidVol0PhysDisk_t; - -/* defines for the PhysDiskMap field */ -#define MPI2_RAIDVOL0_PHYSDISK_PRIMARY (0x01) -#define MPI2_RAIDVOL0_PHYSDISK_SECONDARY (0x02) - -typedef struct _MPI2_RAIDVOL0_SETTINGS -{ - U16 Settings; /* 0x00 */ - U8 HotSparePool; /* 0x01 */ - U8 Reserved; /* 0x02 */ -} MPI2_RAIDVOL0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDVOL0_SETTINGS, - Mpi2RaidVol0Settings_t, MPI2_POINTER pMpi2RaidVol0Settings_t; - -/* RAID Volume Page 0 HotSparePool defines, also used in RAID Physical Disk */ -#define MPI2_RAID_HOT_SPARE_POOL_0 (0x01) -#define MPI2_RAID_HOT_SPARE_POOL_1 (0x02) -#define MPI2_RAID_HOT_SPARE_POOL_2 (0x04) -#define MPI2_RAID_HOT_SPARE_POOL_3 (0x08) -#define MPI2_RAID_HOT_SPARE_POOL_4 (0x10) -#define MPI2_RAID_HOT_SPARE_POOL_5 (0x20) -#define MPI2_RAID_HOT_SPARE_POOL_6 (0x40) -#define MPI2_RAID_HOT_SPARE_POOL_7 (0x80) - -/* RAID Volume Page 0 VolumeSettings defines */ -#define MPI2_RAIDVOL0_SETTING_USE_PRODUCT_ID_SUFFIX (0x0008) -#define MPI2_RAIDVOL0_SETTING_AUTO_CONFIG_HSWAP_DISABLE (0x0004) - -#define MPI2_RAIDVOL0_SETTING_MASK_WRITE_CACHING (0x0003) -#define MPI2_RAIDVOL0_SETTING_UNCHANGED (0x0000) -#define MPI2_RAIDVOL0_SETTING_DISABLE_WRITE_CACHING (0x0001) -#define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhysDisks at runtime. - */ -#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX -#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 DevHandle; /* 0x04 */ - U8 VolumeState; /* 0x06 */ - U8 VolumeType; /* 0x07 */ - U32 VolumeStatusFlags; /* 0x08 */ - MPI2_RAIDVOL0_SETTINGS VolumeSettings; /* 0x0C */ - U64 MaxLBA; /* 0x10 */ - U32 StripeSize; /* 0x18 */ - U16 BlockSize; /* 0x1C */ - U16 Reserved1; /* 0x1E */ - U8 SupportedPhysDisks; /* 0x20 */ - U8 ResyncRate; /* 0x21 */ - U16 DataScrubDuration; /* 0x22 */ - U8 NumPhysDisks; /* 0x24 */ - U8 Reserved2; /* 0x25 */ - U8 Reserved3; /* 0x26 */ - U8 InactiveStatus; /* 0x27 */ - MPI2_RAIDVOL0_PHYS_DISK PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /* 0x28 */ -} MPI2_CONFIG_PAGE_RAID_VOL_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, - Mpi2RaidVolPage0_t, MPI2_POINTER pMpi2RaidVolPage0_t; - -#define MPI2_RAIDVOLPAGE0_PAGEVERSION (0x0A) - -/* values for RAID VolumeState */ -#define MPI2_RAID_VOL_STATE_MISSING (0x00) -#define MPI2_RAID_VOL_STATE_FAILED (0x01) -#define MPI2_RAID_VOL_STATE_INITIALIZING (0x02) -#define MPI2_RAID_VOL_STATE_ONLINE (0x03) -#define MPI2_RAID_VOL_STATE_DEGRADED (0x04) -#define MPI2_RAID_VOL_STATE_OPTIMAL (0x05) - -/* values for RAID VolumeType */ -#define MPI2_RAID_VOL_TYPE_RAID0 (0x00) -#define MPI2_RAID_VOL_TYPE_RAID1E (0x01) -#define MPI2_RAID_VOL_TYPE_RAID1 (0x02) -#define MPI2_RAID_VOL_TYPE_RAID10 (0x05) -#define MPI2_RAID_VOL_TYPE_UNKNOWN (0xFF) - -/* values for RAID Volume Page 0 VolumeStatusFlags field */ -#define MPI2_RAIDVOL0_STATUS_FLAG_PENDING_RESYNC (0x02000000) -#define MPI2_RAIDVOL0_STATUS_FLAG_BACKG_INIT_PENDING (0x01000000) -#define MPI2_RAIDVOL0_STATUS_FLAG_MDC_PENDING (0x00800000) -#define MPI2_RAIDVOL0_STATUS_FLAG_USER_CONSIST_PENDING (0x00400000) -#define MPI2_RAIDVOL0_STATUS_FLAG_MAKE_DATA_CONSISTENT (0x00200000) -#define MPI2_RAIDVOL0_STATUS_FLAG_DATA_SCRUB (0x00100000) -#define MPI2_RAIDVOL0_STATUS_FLAG_CONSISTENCY_CHECK (0x00080000) -#define MPI2_RAIDVOL0_STATUS_FLAG_CAPACITY_EXPANSION (0x00040000) -#define MPI2_RAIDVOL0_STATUS_FLAG_BACKGROUND_INIT (0x00020000) -#define MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x00010000) -#define MPI2_RAIDVOL0_STATUS_FLAG_VOL_NOT_CONSISTENT (0x00000080) -#define MPI2_RAIDVOL0_STATUS_FLAG_OCE_ALLOWED (0x00000040) -#define MPI2_RAIDVOL0_STATUS_FLAG_BGI_COMPLETE (0x00000020) -#define MPI2_RAIDVOL0_STATUS_FLAG_1E_OFFSET_MIRROR (0x00000000) -#define MPI2_RAIDVOL0_STATUS_FLAG_1E_ADJACENT_MIRROR (0x00000010) -#define MPI2_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x00000008) -#define MPI2_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x00000004) -#define MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED (0x00000002) -#define MPI2_RAIDVOL0_STATUS_FLAG_ENABLED (0x00000001) - -/* values for RAID Volume Page 0 SupportedPhysDisks field */ -#define MPI2_RAIDVOL0_SUPPORT_SOLID_STATE_DISKS (0x08) -#define MPI2_RAIDVOL0_SUPPORT_HARD_DISKS (0x04) -#define MPI2_RAIDVOL0_SUPPORT_SAS_PROTOCOL (0x02) -#define MPI2_RAIDVOL0_SUPPORT_SATA_PROTOCOL (0x01) - -/* values for RAID Volume Page 0 InactiveStatus field */ -#define MPI2_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) -#define MPI2_RAIDVOLPAGE0_STALE_METADATA_INACTIVE (0x01) -#define MPI2_RAIDVOLPAGE0_FOREIGN_VOLUME_INACTIVE (0x02) -#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_RESOURCE_INACTIVE (0x03) -#define MPI2_RAIDVOLPAGE0_CLONE_VOLUME_INACTIVE (0x04) -#define MPI2_RAIDVOLPAGE0_INSUFFICIENT_METADATA_INACTIVE (0x05) -#define MPI2_RAIDVOLPAGE0_PREVIOUSLY_DELETED (0x06) - - -/* RAID Volume Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 DevHandle; /* 0x04 */ - U16 Reserved0; /* 0x06 */ - U8 GUID[24]; /* 0x08 */ - U8 Name[16]; /* 0x20 */ - U64 WWID; /* 0x30 */ - U32 Reserved1; /* 0x38 */ - U32 Reserved2; /* 0x3C */ -} MPI2_CONFIG_PAGE_RAID_VOL_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_VOL_1, - Mpi2RaidVolPage1_t, MPI2_POINTER pMpi2RaidVolPage1_t; - -#define MPI2_RAIDVOLPAGE1_PAGEVERSION (0x03) - - -/**************************************************************************** -* RAID Physical Disk Config Pages -****************************************************************************/ - -/* RAID Physical Disk Page 0 */ - -typedef struct _MPI2_RAIDPHYSDISK0_SETTINGS -{ - U16 Reserved1; /* 0x00 */ - U8 HotSparePool; /* 0x02 */ - U8 Reserved2; /* 0x03 */ -} MPI2_RAIDPHYSDISK0_SETTINGS, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_SETTINGS, - Mpi2RaidPhysDisk0Settings_t, MPI2_POINTER pMpi2RaidPhysDisk0Settings_t; - -/* use MPI2_RAID_HOT_SPARE_POOL_ defines for the HotSparePool field */ - -typedef struct _MPI2_RAIDPHYSDISK0_INQUIRY_DATA -{ - U8 VendorID[8]; /* 0x00 */ - U8 ProductID[16]; /* 0x08 */ - U8 ProductRevLevel[4]; /* 0x18 */ - U8 SerialNum[32]; /* 0x1C */ -} MPI2_RAIDPHYSDISK0_INQUIRY_DATA, - MPI2_POINTER PTR_MPI2_RAIDPHYSDISK0_INQUIRY_DATA, - Mpi2RaidPhysDisk0InquiryData_t, MPI2_POINTER pMpi2RaidPhysDisk0InquiryData_t; - -typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U16 DevHandle; /* 0x04 */ - U8 Reserved1; /* 0x06 */ - U8 PhysDiskNum; /* 0x07 */ - MPI2_RAIDPHYSDISK0_SETTINGS PhysDiskSettings; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - MPI2_RAIDPHYSDISK0_INQUIRY_DATA InquiryData; /* 0x10 */ - U32 Reserved3; /* 0x4C */ - U8 PhysDiskState; /* 0x50 */ - U8 OfflineReason; /* 0x51 */ - U8 IncompatibleReason; /* 0x52 */ - U8 PhysDiskAttributes; /* 0x53 */ - U32 PhysDiskStatusFlags; /* 0x54 */ - U64 DeviceMaxLBA; /* 0x58 */ - U64 HostMaxLBA; /* 0x60 */ - U64 CoercedMaxLBA; /* 0x68 */ - U16 BlockSize; /* 0x70 */ - U16 Reserved5; /* 0x72 */ - U32 Reserved6; /* 0x74 */ -} MPI2_CONFIG_PAGE_RD_PDISK_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_0, - Mpi2RaidPhysDiskPage0_t, MPI2_POINTER pMpi2RaidPhysDiskPage0_t; - -#define MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION (0x05) - -/* PhysDiskState defines */ -#define MPI2_RAID_PD_STATE_NOT_CONFIGURED (0x00) -#define MPI2_RAID_PD_STATE_NOT_COMPATIBLE (0x01) -#define MPI2_RAID_PD_STATE_OFFLINE (0x02) -#define MPI2_RAID_PD_STATE_ONLINE (0x03) -#define MPI2_RAID_PD_STATE_HOT_SPARE (0x04) -#define MPI2_RAID_PD_STATE_DEGRADED (0x05) -#define MPI2_RAID_PD_STATE_REBUILDING (0x06) -#define MPI2_RAID_PD_STATE_OPTIMAL (0x07) - -/* OfflineReason defines */ -#define MPI2_PHYSDISK0_ONLINE (0x00) -#define MPI2_PHYSDISK0_OFFLINE_MISSING (0x01) -#define MPI2_PHYSDISK0_OFFLINE_FAILED (0x03) -#define MPI2_PHYSDISK0_OFFLINE_INITIALIZING (0x04) -#define MPI2_PHYSDISK0_OFFLINE_REQUESTED (0x05) -#define MPI2_PHYSDISK0_OFFLINE_FAILED_REQUESTED (0x06) -#define MPI2_PHYSDISK0_OFFLINE_OTHER (0xFF) - -/* IncompatibleReason defines */ -#define MPI2_PHYSDISK0_COMPATIBLE (0x00) -#define MPI2_PHYSDISK0_INCOMPATIBLE_PROTOCOL (0x01) -#define MPI2_PHYSDISK0_INCOMPATIBLE_BLOCKSIZE (0x02) -#define MPI2_PHYSDISK0_INCOMPATIBLE_MAX_LBA (0x03) -#define MPI2_PHYSDISK0_INCOMPATIBLE_SATA_EXTENDED_CMD (0x04) -#define MPI2_PHYSDISK0_INCOMPATIBLE_REMOVEABLE_MEDIA (0x05) -#define MPI2_PHYSDISK0_INCOMPATIBLE_MEDIA_TYPE (0x06) -#define MPI2_PHYSDISK0_INCOMPATIBLE_UNKNOWN (0xFF) - -/* PhysDiskAttributes defines */ -#define MPI2_PHYSDISK0_ATTRIB_MEDIA_MASK (0x0C) -#define MPI2_PHYSDISK0_ATTRIB_SOLID_STATE_DRIVE (0x08) -#define MPI2_PHYSDISK0_ATTRIB_HARD_DISK_DRIVE (0x04) - -#define MPI2_PHYSDISK0_ATTRIB_PROTOCOL_MASK (0x03) -#define MPI2_PHYSDISK0_ATTRIB_SAS_PROTOCOL (0x02) -#define MPI2_PHYSDISK0_ATTRIB_SATA_PROTOCOL (0x01) - -/* PhysDiskStatusFlags defines */ -#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_CERTIFIED (0x00000040) -#define MPI2_PHYSDISK0_STATUS_FLAG_OCE_TARGET (0x00000020) -#define MPI2_PHYSDISK0_STATUS_FLAG_WRITE_CACHE_ENABLED (0x00000010) -#define MPI2_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00000000) -#define MPI2_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x00000008) -#define MPI2_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x00000004) -#define MPI2_PHYSDISK0_STATUS_FLAG_QUIESCED (0x00000002) -#define MPI2_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x00000001) - - -/* RAID Physical Disk Page 1 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhysDiskPaths at runtime. - */ -#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX -#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) -#endif - -typedef struct _MPI2_RAIDPHYSDISK1_PATH -{ - U16 DevHandle; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U64 WWID; /* 0x04 */ - U64 OwnerWWID; /* 0x0C */ - U8 OwnerIdentifier; /* 0x14 */ - U8 Reserved2; /* 0x15 */ - U16 Flags; /* 0x16 */ -} MPI2_RAIDPHYSDISK1_PATH, MPI2_POINTER PTR_MPI2_RAIDPHYSDISK1_PATH, - Mpi2RaidPhysDisk1Path_t, MPI2_POINTER pMpi2RaidPhysDisk1Path_t; - -/* RAID Physical Disk Page 1 Physical Disk Path Flags field defines */ -#define MPI2_RAID_PHYSDISK1_FLAG_PRIMARY (0x0004) -#define MPI2_RAID_PHYSDISK1_FLAG_BROKEN (0x0002) -#define MPI2_RAID_PHYSDISK1_FLAG_INVALID (0x0001) - -typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 -{ - MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhysDiskPaths; /* 0x04 */ - U8 PhysDiskNum; /* 0x05 */ - U16 Reserved1; /* 0x06 */ - U32 Reserved2; /* 0x08 */ - MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/* 0x0C */ -} MPI2_CONFIG_PAGE_RD_PDISK_1, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, - Mpi2RaidPhysDiskPage1_t, MPI2_POINTER pMpi2RaidPhysDiskPage1_t; - -#define MPI2_RAIDPHYSDISKPAGE1_PAGEVERSION (0x02) - - -/**************************************************************************** -* values for fields used by several types of SAS Config Pages -****************************************************************************/ - -/* values for NegotiatedLinkRates fields */ -#define MPI2_SAS_NEG_LINK_RATE_MASK_LOGICAL (0xF0) -#define MPI2_SAS_NEG_LINK_RATE_SHIFT_LOGICAL (4) -#define MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL (0x0F) -/* link rates used for Negotiated Physical and Logical Link Rate */ -#define MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE (0x00) -#define MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED (0x01) -#define MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED (0x02) -#define MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE (0x03) -#define MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR (0x04) -#define MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS (0x05) -#define MPI2_SAS_NEG_LINK_RATE_UNSUPPORTED_PHY (0x06) -#define MPI2_SAS_NEG_LINK_RATE_1_5 (0x08) -#define MPI2_SAS_NEG_LINK_RATE_3_0 (0x09) -#define MPI2_SAS_NEG_LINK_RATE_6_0 (0x0A) - - -/* values for AttachedPhyInfo fields */ -#define MPI2_SAS_APHYINFO_INSIDE_ZPSDS_PERSISTENT (0x00000040) -#define MPI2_SAS_APHYINFO_REQUESTED_INSIDE_ZPSDS (0x00000020) -#define MPI2_SAS_APHYINFO_BREAK_REPLY_CAPABLE (0x00000010) - -#define MPI2_SAS_APHYINFO_REASON_MASK (0x0000000F) -#define MPI2_SAS_APHYINFO_REASON_UNKNOWN (0x00000000) -#define MPI2_SAS_APHYINFO_REASON_POWER_ON (0x00000001) -#define MPI2_SAS_APHYINFO_REASON_HARD_RESET (0x00000002) -#define MPI2_SAS_APHYINFO_REASON_SMP_PHY_CONTROL (0x00000003) -#define MPI2_SAS_APHYINFO_REASON_LOSS_OF_SYNC (0x00000004) -#define MPI2_SAS_APHYINFO_REASON_MULTIPLEXING_SEQ (0x00000005) -#define MPI2_SAS_APHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00000006) -#define MPI2_SAS_APHYINFO_REASON_BREAK_TIMEOUT (0x00000007) -#define MPI2_SAS_APHYINFO_REASON_PHY_TEST_STOPPED (0x00000008) - - -/* values for PhyInfo fields */ -#define MPI2_SAS_PHYINFO_PHY_VACANT (0x80000000) - -#define MPI2_SAS_PHYINFO_PHY_POWER_CONDITION_MASK (0x18000000) -#define MPI2_SAS_PHYINFO_SHIFT_PHY_POWER_CONDITION (27) -#define MPI2_SAS_PHYINFO_PHY_POWER_ACTIVE (0x00000000) -#define MPI2_SAS_PHYINFO_PHY_POWER_PARTIAL (0x08000000) -#define MPI2_SAS_PHYINFO_PHY_POWER_SLUMBER (0x10000000) - -#define MPI2_SAS_PHYINFO_CHANGED_REQ_INSIDE_ZPSDS (0x04000000) -#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS_PERSISTENT (0x02000000) -#define MPI2_SAS_PHYINFO_REQ_INSIDE_ZPSDS (0x01000000) -#define MPI2_SAS_PHYINFO_ZONE_GROUP_PERSISTENT (0x00400000) -#define MPI2_SAS_PHYINFO_INSIDE_ZPSDS (0x00200000) -#define MPI2_SAS_PHYINFO_ZONING_ENABLED (0x00100000) - -#define MPI2_SAS_PHYINFO_REASON_MASK (0x000F0000) -#define MPI2_SAS_PHYINFO_REASON_UNKNOWN (0x00000000) -#define MPI2_SAS_PHYINFO_REASON_POWER_ON (0x00010000) -#define MPI2_SAS_PHYINFO_REASON_HARD_RESET (0x00020000) -#define MPI2_SAS_PHYINFO_REASON_SMP_PHY_CONTROL (0x00030000) -#define MPI2_SAS_PHYINFO_REASON_LOSS_OF_SYNC (0x00040000) -#define MPI2_SAS_PHYINFO_REASON_MULTIPLEXING_SEQ (0x00050000) -#define MPI2_SAS_PHYINFO_REASON_IT_NEXUS_LOSS_TIMER (0x00060000) -#define MPI2_SAS_PHYINFO_REASON_BREAK_TIMEOUT (0x00070000) -#define MPI2_SAS_PHYINFO_REASON_PHY_TEST_STOPPED (0x00080000) - -#define MPI2_SAS_PHYINFO_MULTIPLEXING_SUPPORTED (0x00008000) -#define MPI2_SAS_PHYINFO_SATA_PORT_ACTIVE (0x00004000) -#define MPI2_SAS_PHYINFO_SATA_PORT_SELECTOR_PRESENT (0x00002000) -#define MPI2_SAS_PHYINFO_VIRTUAL_PHY (0x00001000) - -#define MPI2_SAS_PHYINFO_MASK_PARTIAL_PATHWAY_TIME (0x00000F00) -#define MPI2_SAS_PHYINFO_SHIFT_PARTIAL_PATHWAY_TIME (8) - -#define MPI2_SAS_PHYINFO_MASK_ROUTING_ATTRIBUTE (0x000000F0) -#define MPI2_SAS_PHYINFO_DIRECT_ROUTING (0x00000000) -#define MPI2_SAS_PHYINFO_SUBTRACTIVE_ROUTING (0x00000010) -#define MPI2_SAS_PHYINFO_TABLE_ROUTING (0x00000020) - - -/* values for SAS ProgrammedLinkRate fields */ -#define MPI2_SAS_PRATE_MAX_RATE_MASK (0xF0) -#define MPI2_SAS_PRATE_MAX_RATE_NOT_PROGRAMMABLE (0x00) -#define MPI2_SAS_PRATE_MAX_RATE_1_5 (0x80) -#define MPI2_SAS_PRATE_MAX_RATE_3_0 (0x90) -#define MPI2_SAS_PRATE_MAX_RATE_6_0 (0xA0) -#define MPI2_SAS_PRATE_MIN_RATE_MASK (0x0F) -#define MPI2_SAS_PRATE_MIN_RATE_NOT_PROGRAMMABLE (0x00) -#define MPI2_SAS_PRATE_MIN_RATE_1_5 (0x08) -#define MPI2_SAS_PRATE_MIN_RATE_3_0 (0x09) -#define MPI2_SAS_PRATE_MIN_RATE_6_0 (0x0A) - - -/* values for SAS HwLinkRate fields */ -#define MPI2_SAS_HWRATE_MAX_RATE_MASK (0xF0) -#define MPI2_SAS_HWRATE_MAX_RATE_1_5 (0x80) -#define MPI2_SAS_HWRATE_MAX_RATE_3_0 (0x90) -#define MPI2_SAS_HWRATE_MAX_RATE_6_0 (0xA0) -#define MPI2_SAS_HWRATE_MIN_RATE_MASK (0x0F) -#define MPI2_SAS_HWRATE_MIN_RATE_1_5 (0x08) -#define MPI2_SAS_HWRATE_MIN_RATE_3_0 (0x09) -#define MPI2_SAS_HWRATE_MIN_RATE_6_0 (0x0A) - - - -/**************************************************************************** -* SAS IO Unit Config Pages -****************************************************************************/ - -/* SAS IO Unit Page 0 */ - -typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA -{ - U8 Port; /* 0x00 */ - U8 PortFlags; /* 0x01 */ - U8 PhyFlags; /* 0x02 */ - U8 NegotiatedLinkRate; /* 0x03 */ - U32 ControllerPhyDeviceInfo;/* 0x04 */ - U16 AttachedDevHandle; /* 0x08 */ - U16 ControllerDevHandle; /* 0x0A */ - U32 DiscoveryStatus; /* 0x0C */ - U32 Reserved; /* 0x10 */ -} MPI2_SAS_IO_UNIT0_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT0_PHY_DATA, - Mpi2SasIOUnit0PhyData_t, MPI2_POINTER pMpi2SasIOUnit0PhyData_t; - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT0_PHY_MAX -#define MPI2_SAS_IOUNIT0_PHY_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 NumPhys; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /* 0x10 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, - Mpi2SasIOUnitPage0_t, MPI2_POINTER pMpi2SasIOUnitPage0_t; - -#define MPI2_SASIOUNITPAGE0_PAGEVERSION (0x05) - -/* values for SAS IO Unit Page 0 PortFlags */ -#define MPI2_SASIOUNIT0_PORTFLAGS_DISCOVERY_IN_PROGRESS (0x08) -#define MPI2_SASIOUNIT0_PORTFLAGS_AUTO_PORT_CONFIG (0x01) - -/* values for SAS IO Unit Page 0 PhyFlags */ -#define MPI2_SASIOUNIT0_PHYFLAGS_ZONING_ENABLED (0x10) -#define MPI2_SASIOUNIT0_PHYFLAGS_PHY_DISABLED (0x08) - -/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ - -/* see mpi2_sas.h for values for SAS IO Unit Page 0 ControllerPhyDeviceInfo values */ - -/* values for SAS IO Unit Page 0 DiscoveryStatus */ -#define MPI2_SASIOUNIT0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -#define MPI2_SASIOUNIT0_DS_MAX_EXPANDERS_EXCEED (0x40000000) -#define MPI2_SASIOUNIT0_DS_MAX_DEVICES_EXCEED (0x20000000) -#define MPI2_SASIOUNIT0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -#define MPI2_SASIOUNIT0_DS_DOWNSTREAM_INITIATOR (0x08000000) -#define MPI2_SASIOUNIT0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -#define MPI2_SASIOUNIT0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -#define MPI2_SASIOUNIT0_DS_MULTI_PORT_DOMAIN (0x00002000) -#define MPI2_SASIOUNIT0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -#define MPI2_SASIOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) -#define MPI2_SASIOUNIT0_DS_TABLE_LINK (0x00000400) -#define MPI2_SASIOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) -#define MPI2_SASIOUNIT0_DS_SMP_CRC_ERROR (0x00000100) -#define MPI2_SASIOUNIT0_DS_SMP_FUNCTION_FAILED (0x00000080) -#define MPI2_SASIOUNIT0_DS_INDEX_NOT_EXIST (0x00000040) -#define MPI2_SASIOUNIT0_DS_OUT_ROUTE_ENTRIES (0x00000020) -#define MPI2_SASIOUNIT0_DS_SMP_TIMEOUT (0x00000010) -#define MPI2_SASIOUNIT0_DS_MULTIPLE_PORTS (0x00000004) -#define MPI2_SASIOUNIT0_DS_UNADDRESSABLE_DEVICE (0x00000002) -#define MPI2_SASIOUNIT0_DS_LOOP_DETECTED (0x00000001) - - -/* SAS IO Unit Page 1 */ - -typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA -{ - U8 Port; /* 0x00 */ - U8 PortFlags; /* 0x01 */ - U8 PhyFlags; /* 0x02 */ - U8 MaxMinLinkRate; /* 0x03 */ - U32 ControllerPhyDeviceInfo; /* 0x04 */ - U16 MaxTargetPortConnectTime; /* 0x08 */ - U16 Reserved1; /* 0x0A */ -} MPI2_SAS_IO_UNIT1_PHY_DATA, MPI2_POINTER PTR_MPI2_SAS_IO_UNIT1_PHY_DATA, - Mpi2SasIOUnit1PhyData_t, MPI2_POINTER pMpi2SasIOUnit1PhyData_t; - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT1_PHY_MAX -#define MPI2_SAS_IOUNIT1_PHY_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 ControlFlags; /* 0x08 */ - U16 SASNarrowMaxQueueDepth; /* 0x0A */ - U16 AdditionalControlFlags; /* 0x0C */ - U16 SASWideMaxQueueDepth; /* 0x0E */ - U8 NumPhys; /* 0x10 */ - U8 SATAMaxQDepth; /* 0x11 */ - U8 ReportDeviceMissingDelay; /* 0x12 */ - U8 IODeviceMissingDelay; /* 0x13 */ - MPI2_SAS_IO_UNIT1_PHY_DATA PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /* 0x14 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_1, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, - Mpi2SasIOUnitPage1_t, MPI2_POINTER pMpi2SasIOUnitPage1_t; - -#define MPI2_SASIOUNITPAGE1_PAGEVERSION (0x09) - -/* values for SAS IO Unit Page 1 ControlFlags */ -#define MPI2_SASIOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) -#define MPI2_SASIOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) -#define MPI2_SASIOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) -#define MPI2_SASIOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) - -#define MPI2_SASIOUNIT1_CONTROL_MASK_DEV_SUPPORT (0x0600) -#define MPI2_SASIOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) -#define MPI2_SASIOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x0) -#define MPI2_SASIOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x1) -#define MPI2_SASIOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x2) - -#define MPI2_SASIOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) -#define MPI2_SASIOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) -#define MPI2_SASIOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) -#define MPI2_SASIOUNIT1_CONTROL_SATA_FUA_REQUIRED (0x0010) -#define MPI2_SASIOUNIT1_CONTROL_TABLE_SUBTRACTIVE_ILLEGAL (0x0008) -#define MPI2_SASIOUNIT1_CONTROL_SUBTRACTIVE_ILLEGAL (0x0004) -#define MPI2_SASIOUNIT1_CONTROL_FIRST_LVL_DISC_ONLY (0x0002) -#define MPI2_SASIOUNIT1_CONTROL_CLEAR_AFFILIATION (0x0001) - -/* values for SAS IO Unit Page 1 AdditionalControlFlags */ -#define MPI2_SASIOUNIT1_ACONTROL_MULTI_PORT_DOMAIN_ILLEGAL (0x0080) -#define MPI2_SASIOUNIT1_ACONTROL_SATA_ASYNCHROUNOUS_NOTIFICATION (0x0040) -#define MPI2_SASIOUNIT1_ACONTROL_INVALID_TOPOLOGY_CORRECTION (0x0020) -#define MPI2_SASIOUNIT1_ACONTROL_PORT_ENABLE_ONLY_SATA_LINK_RESET (0x0010) -#define MPI2_SASIOUNIT1_ACONTROL_OTHER_AFFILIATION_SATA_LINK_RESET (0x0008) -#define MPI2_SASIOUNIT1_ACONTROL_SELF_AFFILIATION_SATA_LINK_RESET (0x0004) -#define MPI2_SASIOUNIT1_ACONTROL_NO_AFFILIATION_SATA_LINK_RESET (0x0002) -#define MPI2_SASIOUNIT1_ACONTROL_ALLOW_TABLE_TO_TABLE (0x0001) - -/* defines for SAS IO Unit Page 1 ReportDeviceMissingDelay */ -#define MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK (0x7F) -#define MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16 (0x80) - -/* values for SAS IO Unit Page 1 PortFlags */ -#define MPI2_SASIOUNIT1_PORT_FLAGS_AUTO_PORT_CONFIG (0x01) - -/* values for SAS IO Unit Page 1 PhyFlags */ -#define MPI2_SASIOUNIT1_PHYFLAGS_ZONING_ENABLE (0x10) -#define MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE (0x08) - -/* values for SAS IO Unit Page 1 MaxMinLinkRate */ -#define MPI2_SASIOUNIT1_MAX_RATE_MASK (0xF0) -#define MPI2_SASIOUNIT1_MAX_RATE_1_5 (0x80) -#define MPI2_SASIOUNIT1_MAX_RATE_3_0 (0x90) -#define MPI2_SASIOUNIT1_MAX_RATE_6_0 (0xA0) -#define MPI2_SASIOUNIT1_MIN_RATE_MASK (0x0F) -#define MPI2_SASIOUNIT1_MIN_RATE_1_5 (0x08) -#define MPI2_SASIOUNIT1_MIN_RATE_3_0 (0x09) -#define MPI2_SASIOUNIT1_MIN_RATE_6_0 (0x0A) - -/* see mpi2_sas.h for values for SAS IO Unit Page 1 ControllerPhyDeviceInfo values */ - - -/* SAS IO Unit Page 4 */ - -typedef struct _MPI2_SAS_IOUNIT4_SPINUP_GROUP -{ - U8 MaxTargetSpinup; /* 0x00 */ - U8 SpinupDelay; /* 0x01 */ - U8 SpinupFlags; /* 0x02 */ - U8 Reserved1; /* 0x03 */ -} MPI2_SAS_IOUNIT4_SPINUP_GROUP, MPI2_POINTER PTR_MPI2_SAS_IOUNIT4_SPINUP_GROUP, - Mpi2SasIOUnit4SpinupGroup_t, MPI2_POINTER pMpi2SasIOUnit4SpinupGroup_t; - -/* defines for SAS IO Unit Page 4 SpinupFlags */ -#define MPI2_SASIOUNIT4_SPINUP_DISABLE_FLAG (0x01) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT4_PHY_MAX -#define MPI2_SAS_IOUNIT4_PHY_MAX (4) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_4 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - MPI2_SAS_IOUNIT4_SPINUP_GROUP SpinupGroupParameters[4]; /* 0x08 */ - U32 Reserved1; /* 0x18 */ - U32 Reserved2; /* 0x1C */ - U32 Reserved3; /* 0x20 */ - U8 BootDeviceWaitTime; /* 0x24 */ - U8 Reserved4; /* 0x25 */ - U16 Reserved5; /* 0x26 */ - U8 NumPhys; /* 0x28 */ - U8 PEInitialSpinupDelay; /* 0x29 */ - U8 PEReplyDelay; /* 0x2A */ - U8 Flags; /* 0x2B */ - U8 PHY[MPI2_SAS_IOUNIT4_PHY_MAX]; /* 0x2C */ -} MPI2_CONFIG_PAGE_SASIOUNIT_4, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_4, - Mpi2SasIOUnitPage4_t, MPI2_POINTER pMpi2SasIOUnitPage4_t; - -#define MPI2_SASIOUNITPAGE4_PAGEVERSION (0x02) - -/* defines for Flags field */ -#define MPI2_SASIOUNIT4_FLAGS_AUTO_PORTENABLE (0x01) - -/* defines for PHY field */ -#define MPI2_SASIOUNIT4_PHY_SPINUP_GROUP_MASK (0x03) - - -/* SAS IO Unit Page 5 */ - -typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { - U8 ControlFlags; /* 0x00 */ - U8 PortWidthModGroup; /* 0x01 */ - U16 InactivityTimerExponent; /* 0x02 */ - U8 SATAPartialTimeout; /* 0x04 */ - U8 Reserved2; /* 0x05 */ - U8 SATASlumberTimeout; /* 0x06 */ - U8 Reserved3; /* 0x07 */ - U8 SASPartialTimeout; /* 0x08 */ - U8 Reserved4; /* 0x09 */ - U8 SASSlumberTimeout; /* 0x0A */ - U8 Reserved5; /* 0x0B */ -} MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS, - Mpi2SasIOUnit5PhyPmSettings_t, MPI2_POINTER pMpi2SasIOUnit5PhyPmSettings_t; - -/* defines for ControlFlags field */ -#define MPI2_SASIOUNIT5_CONTROL_SAS_SLUMBER_ENABLE (0x08) -#define MPI2_SASIOUNIT5_CONTROL_SAS_PARTIAL_ENABLE (0x04) -#define MPI2_SASIOUNIT5_CONTROL_SATA_SLUMBER_ENABLE (0x02) -#define MPI2_SASIOUNIT5_CONTROL_SATA_PARTIAL_ENABLE (0x01) - -/* defines for PortWidthModeGroup field */ -#define MPI2_SASIOUNIT5_PWMG_DISABLE (0xFF) - -/* defines for InactivityTimerExponent field */ -#define MPI2_SASIOUNIT5_ITE_MASK_SAS_SLUMBER (0x7000) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_SLUMBER (12) -#define MPI2_SASIOUNIT5_ITE_MASK_SAS_PARTIAL (0x0700) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SAS_PARTIAL (8) -#define MPI2_SASIOUNIT5_ITE_MASK_SATA_SLUMBER (0x0070) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_SLUMBER (4) -#define MPI2_SASIOUNIT5_ITE_MASK_SATA_PARTIAL (0x0007) -#define MPI2_SASIOUNIT5_ITE_SHIFT_SATA_PARTIAL (0) - -#define MPI2_SASIOUNIT5_ITE_TEN_SECONDS (7) -#define MPI2_SASIOUNIT5_ITE_ONE_SECOND (6) -#define MPI2_SASIOUNIT5_ITE_HUNDRED_MILLISECONDS (5) -#define MPI2_SASIOUNIT5_ITE_TEN_MILLISECONDS (4) -#define MPI2_SASIOUNIT5_ITE_ONE_MILLISECOND (3) -#define MPI2_SASIOUNIT5_ITE_HUNDRED_MICROSECONDS (2) -#define MPI2_SASIOUNIT5_ITE_TEN_MICROSECONDS (1) -#define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhys at runtime. - */ -#ifndef MPI2_SAS_IOUNIT5_PHY_MAX -#define MPI2_SAS_IOUNIT5_PHY_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 NumPhys; /* 0x08 */ - U8 Reserved1; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 Reserved3; /* 0x0C */ - MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS SASPhyPowerManagementSettings - [MPI2_SAS_IOUNIT5_PHY_MAX]; /* 0x10 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_5, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, - Mpi2SasIOUnitPage5_t, MPI2_POINTER pMpi2SasIOUnitPage5_t; - -#define MPI2_SASIOUNITPAGE5_PAGEVERSION (0x01) - - -/* SAS IO Unit Page 6 */ - -typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { - U8 CurrentStatus; /* 0x00 */ - U8 CurrentModulation; /* 0x01 */ - U8 CurrentUtilization; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 Reserved2; /* 0x04 */ -} MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS, - Mpi2SasIOUnit6PortWidthModGroupStatus_t, - MPI2_POINTER pMpi2SasIOUnit6PortWidthModGroupStatus_t; - -/* defines for CurrentStatus field */ -#define MPI2_SASIOUNIT6_STATUS_UNAVAILABLE (0x00) -#define MPI2_SASIOUNIT6_STATUS_UNCONFIGURED (0x01) -#define MPI2_SASIOUNIT6_STATUS_INVALID_CONFIG (0x02) -#define MPI2_SASIOUNIT6_STATUS_LINK_DOWN (0x03) -#define MPI2_SASIOUNIT6_STATUS_OBSERVATION_ONLY (0x04) -#define MPI2_SASIOUNIT6_STATUS_INACTIVE (0x05) -#define MPI2_SASIOUNIT6_STATUS_ACTIVE_IOUNIT (0x06) -#define MPI2_SASIOUNIT6_STATUS_ACTIVE_HOST (0x07) - -/* defines for CurrentModulation field */ -#define MPI2_SASIOUNIT6_MODULATION_25_PERCENT (0x00) -#define MPI2_SASIOUNIT6_MODULATION_50_PERCENT (0x01) -#define MPI2_SASIOUNIT6_MODULATION_75_PERCENT (0x02) -#define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumGroups at runtime. - */ -#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX -#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - U8 NumGroups; /* 0x10 */ - U8 Reserved3; /* 0x11 */ - U16 Reserved4; /* 0x12 */ - MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS - PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /* 0x14 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_6, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, - Mpi2SasIOUnitPage6_t, MPI2_POINTER pMpi2SasIOUnitPage6_t; - -#define MPI2_SASIOUNITPAGE6_PAGEVERSION (0x00) - - -/* SAS IO Unit Page 7 */ - -typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { - U8 Flags; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U8 Threshold75Pct; /* 0x04 */ - U8 Threshold50Pct; /* 0x05 */ - U8 Threshold25Pct; /* 0x06 */ - U8 Reserved3; /* 0x07 */ -} MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, - MPI2_POINTER PTR_MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS, - Mpi2SasIOUnit7PortWidthModGroupSettings_t, - MPI2_POINTER pMpi2SasIOUnit7PortWidthModGroupSettings_t; - -/* defines for Flags field */ -#define MPI2_SASIOUNIT7_FLAGS_ENABLE_PORT_WIDTH_MODULATION (0x01) - - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumGroups at runtime. - */ -#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX -#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 SamplingInterval; /* 0x08 */ - U8 WindowLength; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Reserved2; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U8 NumGroups; /* 0x14 */ - U8 Reserved4; /* 0x15 */ - U16 Reserved5; /* 0x16 */ - MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS - PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX]; /* 0x18 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_7, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, - Mpi2SasIOUnitPage7_t, MPI2_POINTER pMpi2SasIOUnitPage7_t; - -#define MPI2_SASIOUNITPAGE7_PAGEVERSION (0x00) - - -/* SAS IO Unit Page 8 */ - -typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_8 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 PowerManagementCapabilities;/* 0x0C */ - U32 Reserved2; /* 0x10 */ -} MPI2_CONFIG_PAGE_SASIOUNIT_8, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SASIOUNIT_8, - Mpi2SasIOUnitPage8_t, MPI2_POINTER pMpi2SasIOUnitPage8_t; - -#define MPI2_SASIOUNITPAGE8_PAGEVERSION (0x00) - -/* defines for PowerManagementCapabilities field */ -#define MPI2_SASIOUNIT8_PM_HOST_PORT_WIDTH_MOD (0x00001000) -#define MPI2_SASIOUNIT8_PM_HOST_SAS_SLUMBER_MODE (0x00000800) -#define MPI2_SASIOUNIT8_PM_HOST_SAS_PARTIAL_MODE (0x00000400) -#define MPI2_SASIOUNIT8_PM_HOST_SATA_SLUMBER_MODE (0x00000200) -#define MPI2_SASIOUNIT8_PM_HOST_SATA_PARTIAL_MODE (0x00000100) -#define MPI2_SASIOUNIT8_PM_IOUNIT_PORT_WIDTH_MOD (0x00000010) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_SLUMBER_MODE (0x00000008) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SAS_PARTIAL_MODE (0x00000004) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_SLUMBER_MODE (0x00000002) -#define MPI2_SASIOUNIT8_PM_IOUNIT_SATA_PARTIAL_MODE (0x00000001) - - - - -/**************************************************************************** -* SAS Expander Config Pages -****************************************************************************/ - -/* SAS Expander Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_EXPANDER_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 PhysicalPort; /* 0x08 */ - U8 ReportGenLength; /* 0x09 */ - U16 EnclosureHandle; /* 0x0A */ - U64 SASAddress; /* 0x0C */ - U32 DiscoveryStatus; /* 0x14 */ - U16 DevHandle; /* 0x18 */ - U16 ParentDevHandle; /* 0x1A */ - U16 ExpanderChangeCount; /* 0x1C */ - U16 ExpanderRouteIndexes; /* 0x1E */ - U8 NumPhys; /* 0x20 */ - U8 SASLevel; /* 0x21 */ - U16 Flags; /* 0x22 */ - U16 STPBusInactivityTimeLimit; /* 0x24 */ - U16 STPMaxConnectTimeLimit; /* 0x26 */ - U16 STP_SMP_NexusLossTime; /* 0x28 */ - U16 MaxNumRoutedSasAddresses; /* 0x2A */ - U64 ActiveZoneManagerSASAddress;/* 0x2C */ - U16 ZoneLockInactivityLimit; /* 0x34 */ - U16 Reserved1; /* 0x36 */ - U8 TimeToReducedFunc; /* 0x38 */ - U8 InitialTimeToReducedFunc; /* 0x39 */ - U8 MaxReducedFuncTime; /* 0x3A */ - U8 Reserved2; /* 0x3B */ -} MPI2_CONFIG_PAGE_EXPANDER_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_0, - Mpi2ExpanderPage0_t, MPI2_POINTER pMpi2ExpanderPage0_t; - -#define MPI2_SASEXPANDER0_PAGEVERSION (0x06) - -/* values for SAS Expander Page 0 DiscoveryStatus field */ -#define MPI2_SAS_EXPANDER0_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -#define MPI2_SAS_EXPANDER0_DS_MAX_EXPANDERS_EXCEED (0x40000000) -#define MPI2_SAS_EXPANDER0_DS_MAX_DEVICES_EXCEED (0x20000000) -#define MPI2_SAS_EXPANDER0_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -#define MPI2_SAS_EXPANDER0_DS_DOWNSTREAM_INITIATOR (0x08000000) -#define MPI2_SAS_EXPANDER0_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -#define MPI2_SAS_EXPANDER0_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -#define MPI2_SAS_EXPANDER0_DS_MULTI_PORT_DOMAIN (0x00002000) -#define MPI2_SAS_EXPANDER0_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -#define MPI2_SAS_EXPANDER0_DS_UNSUPPORTED_DEVICE (0x00000800) -#define MPI2_SAS_EXPANDER0_DS_TABLE_LINK (0x00000400) -#define MPI2_SAS_EXPANDER0_DS_SUBTRACTIVE_LINK (0x00000200) -#define MPI2_SAS_EXPANDER0_DS_SMP_CRC_ERROR (0x00000100) -#define MPI2_SAS_EXPANDER0_DS_SMP_FUNCTION_FAILED (0x00000080) -#define MPI2_SAS_EXPANDER0_DS_INDEX_NOT_EXIST (0x00000040) -#define MPI2_SAS_EXPANDER0_DS_OUT_ROUTE_ENTRIES (0x00000020) -#define MPI2_SAS_EXPANDER0_DS_SMP_TIMEOUT (0x00000010) -#define MPI2_SAS_EXPANDER0_DS_MULTIPLE_PORTS (0x00000004) -#define MPI2_SAS_EXPANDER0_DS_UNADDRESSABLE_DEVICE (0x00000002) -#define MPI2_SAS_EXPANDER0_DS_LOOP_DETECTED (0x00000001) - -/* values for SAS Expander Page 0 Flags field */ -#define MPI2_SAS_EXPANDER0_FLAGS_REDUCED_FUNCTIONALITY (0x2000) -#define MPI2_SAS_EXPANDER0_FLAGS_ZONE_LOCKED (0x1000) -#define MPI2_SAS_EXPANDER0_FLAGS_SUPPORTED_PHYSICAL_PRES (0x0800) -#define MPI2_SAS_EXPANDER0_FLAGS_ASSERTED_PHYSICAL_PRES (0x0400) -#define MPI2_SAS_EXPANDER0_FLAGS_ZONING_SUPPORT (0x0200) -#define MPI2_SAS_EXPANDER0_FLAGS_ENABLED_ZONING (0x0100) -#define MPI2_SAS_EXPANDER0_FLAGS_TABLE_TO_TABLE_SUPPORT (0x0080) -#define MPI2_SAS_EXPANDER0_FLAGS_CONNECTOR_END_DEVICE (0x0010) -#define MPI2_SAS_EXPANDER0_FLAGS_OTHERS_CONFIG (0x0004) -#define MPI2_SAS_EXPANDER0_FLAGS_CONFIG_IN_PROGRESS (0x0002) -#define MPI2_SAS_EXPANDER0_FLAGS_ROUTE_TABLE_CONFIG (0x0001) - - -/* SAS Expander Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_EXPANDER_1 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 PhysicalPort; /* 0x08 */ - U8 Reserved1; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U8 NumPhys; /* 0x0C */ - U8 Phy; /* 0x0D */ - U16 NumTableEntriesProgrammed; /* 0x0E */ - U8 ProgrammedLinkRate; /* 0x10 */ - U8 HwLinkRate; /* 0x11 */ - U16 AttachedDevHandle; /* 0x12 */ - U32 PhyInfo; /* 0x14 */ - U32 AttachedDeviceInfo; /* 0x18 */ - U16 ExpanderDevHandle; /* 0x1C */ - U8 ChangeCount; /* 0x1E */ - U8 NegotiatedLinkRate; /* 0x1F */ - U8 PhyIdentifier; /* 0x20 */ - U8 AttachedPhyIdentifier; /* 0x21 */ - U8 Reserved3; /* 0x22 */ - U8 DiscoveryInfo; /* 0x23 */ - U32 AttachedPhyInfo; /* 0x24 */ - U8 ZoneGroup; /* 0x28 */ - U8 SelfConfigStatus; /* 0x29 */ - U16 Reserved4; /* 0x2A */ -} MPI2_CONFIG_PAGE_EXPANDER_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXPANDER_1, - Mpi2ExpanderPage1_t, MPI2_POINTER pMpi2ExpanderPage1_t; - -#define MPI2_SASEXPANDER1_PAGEVERSION (0x02) - -/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ - -/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ - -/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ - -/* see mpi2_sas.h for the MPI2_SAS_DEVICE_INFO_ defines used for the AttachedDeviceInfo field */ - -/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ - -/* values for SAS Expander Page 1 DiscoveryInfo field */ -#define MPI2_SAS_EXPANDER1_DISCINFO_BAD_PHY_DISABLED (0x04) -#define MPI2_SAS_EXPANDER1_DISCINFO_LINK_STATUS_CHANGE (0x02) -#define MPI2_SAS_EXPANDER1_DISCINFO_NO_ROUTING_ENTRIES (0x01) - -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ - -/**************************************************************************** -* SAS Device Config Pages -****************************************************************************/ - -/* SAS Device Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 Slot; /* 0x08 */ - U16 EnclosureHandle; /* 0x0A */ - U64 SASAddress; /* 0x0C */ - U16 ParentDevHandle; /* 0x14 */ - U8 PhyNum; /* 0x16 */ - U8 AccessStatus; /* 0x17 */ - U16 DevHandle; /* 0x18 */ - U8 AttachedPhyIdentifier; /* 0x1A */ - U8 ZoneGroup; /* 0x1B */ - U32 DeviceInfo; /* 0x1C */ - U16 Flags; /* 0x20 */ - U8 PhysicalPort; /* 0x22 */ - U8 MaxPortConnections; /* 0x23 */ - U64 DeviceName; /* 0x24 */ - U8 PortGroups; /* 0x2C */ - U8 DmaGroup; /* 0x2D */ - U8 ControlGroup; /* 0x2E */ - U8 Reserved1; /* 0x2F */ - U32 Reserved2; /* 0x30 */ - U32 Reserved3; /* 0x34 */ -} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0, - Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t; - -#define MPI2_SASDEVICE0_PAGEVERSION (0x08) - -/* values for SAS Device Page 0 AccessStatus field */ -#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) -#define MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED (0x01) -#define MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED (0x02) -#define MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT (0x03) -#define MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION (0x04) -#define MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE (0x05) -#define MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE (0x06) -#define MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED (0x07) -/* specific values for SATA Init failures */ -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN (0x10) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT (0x11) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG (0x12) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION (0x13) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER (0x14) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN (0x15) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN (0x16) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN (0x17) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION (0x18) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE (0x19) -#define MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX (0x1F) - -/* see mpi2_sas.h for values for SAS Device Page 0 DeviceInfo values */ - -/* values for SAS Device Page 0 Flags field */ -#define MPI2_SAS_DEVICE0_FLAGS_UNAUTHORIZED_DEVICE (0x8000) -#define MPI2_SAS_DEVICE0_FLAGS_SLUMBER_PM_CAPABLE (0x1000) -#define MPI2_SAS_DEVICE0_FLAGS_PARTIAL_PM_CAPABLE (0x0800) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY (0x0400) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE (0x0200) -#define MPI2_SAS_DEVICE0_FLAGS_UNSUPPORTED_DEVICE (0x0100) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_48BIT_LBA_SUPPORTED (0x0080) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED (0x0040) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) -#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) -#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) -#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) - - -/* SAS Device Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_1 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U64 SASAddress; /* 0x0C */ - U32 Reserved2; /* 0x14 */ - U16 DevHandle; /* 0x18 */ - U16 Reserved3; /* 0x1A */ - U8 InitialRegDeviceFIS[20];/* 0x1C */ -} MPI2_CONFIG_PAGE_SAS_DEV_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_1, - Mpi2SasDevicePage1_t, MPI2_POINTER pMpi2SasDevicePage1_t; - -#define MPI2_SASDEVICE1_PAGEVERSION (0x01) - - -/**************************************************************************** -* SAS PHY Config Pages -****************************************************************************/ - -/* SAS PHY Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 OwnerDevHandle; /* 0x08 */ - U16 Reserved1; /* 0x0A */ - U16 AttachedDevHandle; /* 0x0C */ - U8 AttachedPhyIdentifier; /* 0x0E */ - U8 Reserved2; /* 0x0F */ - U32 AttachedPhyInfo; /* 0x10 */ - U8 ProgrammedLinkRate; /* 0x14 */ - U8 HwLinkRate; /* 0x15 */ - U8 ChangeCount; /* 0x16 */ - U8 Flags; /* 0x17 */ - U32 PhyInfo; /* 0x18 */ - U8 NegotiatedLinkRate; /* 0x1C */ - U8 Reserved3; /* 0x1D */ - U16 Reserved4; /* 0x1E */ -} MPI2_CONFIG_PAGE_SAS_PHY_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_0, - Mpi2SasPhyPage0_t, MPI2_POINTER pMpi2SasPhyPage0_t; - -#define MPI2_SASPHY0_PAGEVERSION (0x03) - -/* use MPI2_SAS_APHYINFO_ defines for AttachedPhyInfo field */ - -/* use MPI2_SAS_PRATE_ defines for the ProgrammedLinkRate field */ - -/* use MPI2_SAS_HWRATE_ defines for the HwLinkRate field */ - -/* values for SAS PHY Page 0 Flags field */ -#define MPI2_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) - -/* use MPI2_SAS_PHYINFO_ for the PhyInfo field */ - -/* use MPI2_SAS_NEG_LINK_RATE_ defines for the NegotiatedLinkRate field */ - - -/* SAS PHY Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_1 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 InvalidDwordCount; /* 0x0C */ - U32 RunningDisparityErrorCount; /* 0x10 */ - U32 LossDwordSynchCount; /* 0x14 */ - U32 PhyResetProblemCount; /* 0x18 */ -} MPI2_CONFIG_PAGE_SAS_PHY_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_1, - Mpi2SasPhyPage1_t, MPI2_POINTER pMpi2SasPhyPage1_t; - -#define MPI2_SASPHY1_PAGEVERSION (0x01) - - -/* SAS PHY Page 2 */ - -typedef struct _MPI2_SASPHY2_PHY_EVENT { - U8 PhyEventCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 PhyEventInfo; /* 0x04 */ -} MPI2_SASPHY2_PHY_EVENT, MPI2_POINTER PTR_MPI2_SASPHY2_PHY_EVENT, - Mpi2SasPhy2PhyEvent_t, MPI2_POINTER pMpi2SasPhy2PhyEvent_t; - -/* use MPI2_SASPHY3_EVENT_CODE_ for the PhyEventCode field */ - - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhyEvents at runtime. - */ -#ifndef MPI2_SASPHY2_PHY_EVENT_MAX -#define MPI2_SASPHY2_PHY_EVENT_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 NumPhyEvents; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_SASPHY2_PHY_EVENT PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; - /* 0x10 */ -} MPI2_CONFIG_PAGE_SAS_PHY_2, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, - Mpi2SasPhyPage2_t, MPI2_POINTER pMpi2SasPhyPage2_t; - -#define MPI2_SASPHY2_PAGEVERSION (0x00) - - -/* SAS PHY Page 3 */ - -typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { - U8 PhyEventCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U8 CounterType; /* 0x04 */ - U8 ThresholdWindow; /* 0x05 */ - U8 TimeUnits; /* 0x06 */ - U8 Reserved3; /* 0x07 */ - U32 EventThreshold; /* 0x08 */ - U16 ThresholdFlags; /* 0x0C */ - U16 Reserved4; /* 0x0E */ -} MPI2_SASPHY3_PHY_EVENT_CONFIG, MPI2_POINTER PTR_MPI2_SASPHY3_PHY_EVENT_CONFIG, - Mpi2SasPhy3PhyEventConfig_t, MPI2_POINTER pMpi2SasPhy3PhyEventConfig_t; - -/* values for PhyEventCode field */ -#define MPI2_SASPHY3_EVENT_CODE_NO_EVENT (0x00) -#define MPI2_SASPHY3_EVENT_CODE_INVALID_DWORD (0x01) -#define MPI2_SASPHY3_EVENT_CODE_RUNNING_DISPARITY_ERROR (0x02) -#define MPI2_SASPHY3_EVENT_CODE_LOSS_DWORD_SYNC (0x03) -#define MPI2_SASPHY3_EVENT_CODE_PHY_RESET_PROBLEM (0x04) -#define MPI2_SASPHY3_EVENT_CODE_ELASTICITY_BUF_OVERFLOW (0x05) -#define MPI2_SASPHY3_EVENT_CODE_RX_ERROR (0x06) -#define MPI2_SASPHY3_EVENT_CODE_RX_ADDR_FRAME_ERROR (0x20) -#define MPI2_SASPHY3_EVENT_CODE_TX_AC_OPEN_REJECT (0x21) -#define MPI2_SASPHY3_EVENT_CODE_RX_AC_OPEN_REJECT (0x22) -#define MPI2_SASPHY3_EVENT_CODE_TX_RC_OPEN_REJECT (0x23) -#define MPI2_SASPHY3_EVENT_CODE_RX_RC_OPEN_REJECT (0x24) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_PARTIAL_WAITING_ON (0x25) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP_CONNECT_WAITING_ON (0x26) -#define MPI2_SASPHY3_EVENT_CODE_TX_BREAK (0x27) -#define MPI2_SASPHY3_EVENT_CODE_RX_BREAK (0x28) -#define MPI2_SASPHY3_EVENT_CODE_BREAK_TIMEOUT (0x29) -#define MPI2_SASPHY3_EVENT_CODE_CONNECTION (0x2A) -#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_PATHWAY_BLOCKED (0x2B) -#define MPI2_SASPHY3_EVENT_CODE_PEAKTX_ARB_WAIT_TIME (0x2C) -#define MPI2_SASPHY3_EVENT_CODE_PEAK_ARB_WAIT_TIME (0x2D) -#define MPI2_SASPHY3_EVENT_CODE_PEAK_CONNECT_TIME (0x2E) -#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_FRAMES (0x40) -#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_FRAMES (0x41) -#define MPI2_SASPHY3_EVENT_CODE_TX_SSP_ERROR_FRAMES (0x42) -#define MPI2_SASPHY3_EVENT_CODE_RX_SSP_ERROR_FRAMES (0x43) -#define MPI2_SASPHY3_EVENT_CODE_TX_CREDIT_BLOCKED (0x44) -#define MPI2_SASPHY3_EVENT_CODE_RX_CREDIT_BLOCKED (0x45) -#define MPI2_SASPHY3_EVENT_CODE_TX_SATA_FRAMES (0x50) -#define MPI2_SASPHY3_EVENT_CODE_RX_SATA_FRAMES (0x51) -#define MPI2_SASPHY3_EVENT_CODE_SATA_OVERFLOW (0x52) -#define MPI2_SASPHY3_EVENT_CODE_TX_SMP_FRAMES (0x60) -#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_FRAMES (0x61) -#define MPI2_SASPHY3_EVENT_CODE_RX_SMP_ERROR_FRAMES (0x63) -#define MPI2_SASPHY3_EVENT_CODE_HOTPLUG_TIMEOUT (0xD0) -#define MPI2_SASPHY3_EVENT_CODE_MISALIGNED_MUX_PRIMITIVE (0xD1) -#define MPI2_SASPHY3_EVENT_CODE_RX_AIP (0xD2) - -/* values for the CounterType field */ -#define MPI2_SASPHY3_COUNTER_TYPE_WRAPPING (0x00) -#define MPI2_SASPHY3_COUNTER_TYPE_SATURATING (0x01) -#define MPI2_SASPHY3_COUNTER_TYPE_PEAK_VALUE (0x02) - -/* values for the TimeUnits field */ -#define MPI2_SASPHY3_TIME_UNITS_10_MICROSECONDS (0x00) -#define MPI2_SASPHY3_TIME_UNITS_100_MICROSECONDS (0x01) -#define MPI2_SASPHY3_TIME_UNITS_1_MILLISECOND (0x02) -#define MPI2_SASPHY3_TIME_UNITS_10_MILLISECONDS (0x03) - -/* values for the ThresholdFlags field */ -#define MPI2_SASPHY3_TFLAGS_PHY_RESET (0x0002) -#define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumPhyEvents at runtime. - */ -#ifndef MPI2_SASPHY3_PHY_EVENT_MAX -#define MPI2_SASPHY3_PHY_EVENT_MAX (1) -#endif - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 NumPhyEvents; /* 0x0C */ - U8 Reserved2; /* 0x0D */ - U16 Reserved3; /* 0x0E */ - MPI2_SASPHY3_PHY_EVENT_CONFIG PhyEventConfig - [MPI2_SASPHY3_PHY_EVENT_MAX]; /* 0x10 */ -} MPI2_CONFIG_PAGE_SAS_PHY_3, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, - Mpi2SasPhyPage3_t, MPI2_POINTER pMpi2SasPhyPage3_t; - -#define MPI2_SASPHY3_PAGEVERSION (0x00) - - -/* SAS PHY Page 4 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_4 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U16 Reserved1; /* 0x08 */ - U8 Reserved2; /* 0x0A */ - U8 Flags; /* 0x0B */ - U8 InitialFrame[28]; /* 0x0C */ -} MPI2_CONFIG_PAGE_SAS_PHY_4, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PHY_4, - Mpi2SasPhyPage4_t, MPI2_POINTER pMpi2SasPhyPage4_t; - -#define MPI2_SASPHY4_PAGEVERSION (0x00) - -/* values for the Flags field */ -#define MPI2_SASPHY4_FLAGS_FRAME_VALID (0x02) -#define MPI2_SASPHY4_FLAGS_SATA_FRAME (0x01) - - - - -/**************************************************************************** -* SAS Port Config Pages -****************************************************************************/ - -/* SAS Port Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_PORT_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 PortNumber; /* 0x08 */ - U8 PhysicalPort; /* 0x09 */ - U8 PortWidth; /* 0x0A */ - U8 PhysicalPortWidth; /* 0x0B */ - U8 ZoneGroup; /* 0x0C */ - U8 Reserved1; /* 0x0D */ - U16 Reserved2; /* 0x0E */ - U64 SASAddress; /* 0x10 */ - U32 DeviceInfo; /* 0x18 */ - U32 Reserved3; /* 0x1C */ - U32 Reserved4; /* 0x20 */ -} MPI2_CONFIG_PAGE_SAS_PORT_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_PORT_0, - Mpi2SasPortPage0_t, MPI2_POINTER pMpi2SasPortPage0_t; - -#define MPI2_SASPORT0_PAGEVERSION (0x00) - -/* see mpi2_sas.h for values for SAS Port Page 0 DeviceInfo values */ - - -/**************************************************************************** -* SAS Enclosure Config Pages -****************************************************************************/ - -/* SAS Enclosure Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U64 EnclosureLogicalID; /* 0x0C */ - U16 Flags; /* 0x14 */ - U16 EnclosureHandle; /* 0x16 */ - U16 NumSlots; /* 0x18 */ - U16 StartSlot; /* 0x1A */ - U16 Reserved2; /* 0x1C */ - U16 SEPDevHandle; /* 0x1E */ - U32 Reserved3; /* 0x20 */ - U32 Reserved4; /* 0x24 */ -} MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, - Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t; - -#define MPI2_SASENCLOSURE0_PAGEVERSION (0x03) - -/* values for SAS Enclosure Page 0 Flags field */ -#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) -#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) - - -/**************************************************************************** -* Log Config Page -****************************************************************************/ - -/* Log Page 0 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumLogEntries at runtime. - */ -#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES -#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) -#endif - -#define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) - -typedef struct _MPI2_LOG_0_ENTRY -{ - U64 TimeStamp; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U16 LogSequence; /* 0x0C */ - U16 LogEntryQualifier; /* 0x0E */ - U8 VP_ID; /* 0x10 */ - U8 VF_ID; /* 0x11 */ - U16 Reserved2; /* 0x12 */ - U8 LogData[MPI2_LOG_0_LOG_DATA_LENGTH];/* 0x14 */ -} MPI2_LOG_0_ENTRY, MPI2_POINTER PTR_MPI2_LOG_0_ENTRY, - Mpi2Log0Entry_t, MPI2_POINTER pMpi2Log0Entry_t; - -/* values for Log Page 0 LogEntry LogEntryQualifier field */ -#define MPI2_LOG_0_ENTRY_QUAL_ENTRY_UNUSED (0x0000) -#define MPI2_LOG_0_ENTRY_QUAL_POWER_ON_RESET (0x0001) -#define MPI2_LOG_0_ENTRY_QUAL_TIMESTAMP_UPDATE (0x0002) -#define MPI2_LOG_0_ENTRY_QUAL_MIN_IMPLEMENT_SPEC (0x8000) -#define MPI2_LOG_0_ENTRY_QUAL_MAX_IMPLEMENT_SPEC (0xFFFF) - -typedef struct _MPI2_CONFIG_PAGE_LOG_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ - U16 NumLogEntries; /* 0x10 */ - U16 Reserved3; /* 0x12 */ - MPI2_LOG_0_ENTRY LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /* 0x14 */ -} MPI2_CONFIG_PAGE_LOG_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_LOG_0, - Mpi2LogPage0_t, MPI2_POINTER pMpi2LogPage0_t; - -#define MPI2_LOG_0_PAGEVERSION (0x02) - - -/**************************************************************************** -* RAID Config Page -****************************************************************************/ - -/* RAID Page 0 */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check the value returned for NumElements at runtime. - */ -#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS -#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) -#endif - -typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT -{ - U16 ElementFlags; /* 0x00 */ - U16 VolDevHandle; /* 0x02 */ - U8 HotSparePool; /* 0x04 */ - U8 PhysDiskNum; /* 0x05 */ - U16 PhysDiskDevHandle; /* 0x06 */ -} MPI2_RAIDCONFIG0_CONFIG_ELEMENT, - MPI2_POINTER PTR_MPI2_RAIDCONFIG0_CONFIG_ELEMENT, - Mpi2RaidConfig0ConfigElement_t, MPI2_POINTER pMpi2RaidConfig0ConfigElement_t; - -/* values for the ElementFlags field */ -#define MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE (0x000F) -#define MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT (0x0000) -#define MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT (0x0001) -#define MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT (0x0002) -#define MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT (0x0003) - - -typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 NumHotSpares; /* 0x08 */ - U8 NumPhysDisks; /* 0x09 */ - U8 NumVolumes; /* 0x0A */ - U8 ConfigNum; /* 0x0B */ - U32 Flags; /* 0x0C */ - U8 ConfigGUID[24]; /* 0x10 */ - U32 Reserved1; /* 0x28 */ - U8 NumElements; /* 0x2C */ - U8 Reserved2; /* 0x2D */ - U16 Reserved3; /* 0x2E */ - MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /* 0x30 */ -} MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, - Mpi2RaidConfigurationPage0_t, MPI2_POINTER pMpi2RaidConfigurationPage0_t; - -#define MPI2_RAIDCONFIG0_PAGEVERSION (0x00) - -/* values for RAID Configuration Page 0 Flags field */ -#define MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG (0x00000001) - - -/**************************************************************************** -* Driver Persistent Mapping Config Pages -****************************************************************************/ - -/* Driver Persistent Mapping Page 0 */ - -typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY -{ - U64 PhysicalIdentifier; /* 0x00 */ - U16 MappingInformation; /* 0x08 */ - U16 DeviceIndex; /* 0x0A */ - U32 PhysicalBitsMapping; /* 0x0C */ - U32 Reserved1; /* 0x10 */ -} MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY, - Mpi2DriverMap0Entry_t, MPI2_POINTER pMpi2DriverMap0Entry_t; - -typedef struct _MPI2_CONFIG_PAGE_DRIVER_MAPPING_0 -{ - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - MPI2_CONFIG_PAGE_DRIVER_MAP0_ENTRY Entry; /* 0x08 */ -} MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_DRIVER_MAPPING_0, - Mpi2DriverMappingPage0_t, MPI2_POINTER pMpi2DriverMappingPage0_t; - -#define MPI2_DRIVERMAPPING0_PAGEVERSION (0x00) - -/* values for Driver Persistent Mapping Page 0 MappingInformation field */ -#define MPI2_DRVMAP0_MAPINFO_SLOT_MASK (0x07F0) -#define MPI2_DRVMAP0_MAPINFO_SLOT_SHIFT (4) -#define MPI2_DRVMAP0_MAPINFO_MISSING_MASK (0x000F) - - -/**************************************************************************** -* Ethernet Config Pages -****************************************************************************/ - -/* Ethernet Page 0 */ - -/* IP address (union of IPv4 and IPv6) */ -typedef union _MPI2_ETHERNET_IP_ADDR { - U32 IPv4Addr; - U32 IPv6Addr[4]; -} MPI2_ETHERNET_IP_ADDR, MPI2_POINTER PTR_MPI2_ETHERNET_IP_ADDR, - Mpi2EthernetIpAddr_t, MPI2_POINTER pMpi2EthernetIpAddr_t; - -#define MPI2_ETHERNET_HOST_NAME_LENGTH (32) - -typedef struct _MPI2_CONFIG_PAGE_ETHERNET_0 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U8 NumInterfaces; /* 0x08 */ - U8 Reserved0; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Status; /* 0x0C */ - U8 MediaState; /* 0x10 */ - U8 Reserved2; /* 0x11 */ - U16 Reserved3; /* 0x12 */ - U8 MacAddress[6]; /* 0x14 */ - U8 Reserved4; /* 0x1A */ - U8 Reserved5; /* 0x1B */ - MPI2_ETHERNET_IP_ADDR IpAddress; /* 0x1C */ - MPI2_ETHERNET_IP_ADDR SubnetMask; /* 0x2C */ - MPI2_ETHERNET_IP_ADDR GatewayIpAddress; /* 0x3C */ - MPI2_ETHERNET_IP_ADDR DNS1IpAddress; /* 0x4C */ - MPI2_ETHERNET_IP_ADDR DNS2IpAddress; /* 0x5C */ - MPI2_ETHERNET_IP_ADDR DhcpIpAddress; /* 0x6C */ - U8 HostName - [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ -} MPI2_CONFIG_PAGE_ETHERNET_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_0, - Mpi2EthernetPage0_t, MPI2_POINTER pMpi2EthernetPage0_t; - -#define MPI2_ETHERNETPAGE0_PAGEVERSION (0x00) - -/* values for Ethernet Page 0 Status field */ -#define MPI2_ETHPG0_STATUS_IPV6_CAPABLE (0x80000000) -#define MPI2_ETHPG0_STATUS_IPV4_CAPABLE (0x40000000) -#define MPI2_ETHPG0_STATUS_CONSOLE_CONNECTED (0x20000000) -#define MPI2_ETHPG0_STATUS_DEFAULT_IF (0x00000100) -#define MPI2_ETHPG0_STATUS_FW_DWNLD_ENABLED (0x00000080) -#define MPI2_ETHPG0_STATUS_TELNET_ENABLED (0x00000040) -#define MPI2_ETHPG0_STATUS_SSH2_ENABLED (0x00000020) -#define MPI2_ETHPG0_STATUS_DHCP_CLIENT_ENABLED (0x00000010) -#define MPI2_ETHPG0_STATUS_IPV6_ENABLED (0x00000008) -#define MPI2_ETHPG0_STATUS_IPV4_ENABLED (0x00000004) -#define MPI2_ETHPG0_STATUS_IPV6_ADDRESSES (0x00000002) -#define MPI2_ETHPG0_STATUS_ETH_IF_ENABLED (0x00000001) - -/* values for Ethernet Page 0 MediaState field */ -#define MPI2_ETHPG0_MS_DUPLEX_MASK (0x80) -#define MPI2_ETHPG0_MS_HALF_DUPLEX (0x00) -#define MPI2_ETHPG0_MS_FULL_DUPLEX (0x80) - -#define MPI2_ETHPG0_MS_CONNECT_SPEED_MASK (0x07) -#define MPI2_ETHPG0_MS_NOT_CONNECTED (0x00) -#define MPI2_ETHPG0_MS_10MBIT (0x01) -#define MPI2_ETHPG0_MS_100MBIT (0x02) -#define MPI2_ETHPG0_MS_1GBIT (0x03) - - -/* Ethernet Page 1 */ - -typedef struct _MPI2_CONFIG_PAGE_ETHERNET_1 { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 Reserved0; /* 0x08 */ - U32 Flags; /* 0x0C */ - U8 MediaState; /* 0x10 */ - U8 Reserved1; /* 0x11 */ - U16 Reserved2; /* 0x12 */ - U8 MacAddress[6]; /* 0x14 */ - U8 Reserved3; /* 0x1A */ - U8 Reserved4; /* 0x1B */ - MPI2_ETHERNET_IP_ADDR StaticIpAddress; /* 0x1C */ - MPI2_ETHERNET_IP_ADDR StaticSubnetMask; /* 0x2C */ - MPI2_ETHERNET_IP_ADDR StaticGatewayIpAddress; /* 0x3C */ - MPI2_ETHERNET_IP_ADDR StaticDNS1IpAddress; /* 0x4C */ - MPI2_ETHERNET_IP_ADDR StaticDNS2IpAddress; /* 0x5C */ - U32 Reserved5; /* 0x6C */ - U32 Reserved6; /* 0x70 */ - U32 Reserved7; /* 0x74 */ - U32 Reserved8; /* 0x78 */ - U8 HostName - [MPI2_ETHERNET_HOST_NAME_LENGTH];/* 0x7C */ -} MPI2_CONFIG_PAGE_ETHERNET_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_ETHERNET_1, - Mpi2EthernetPage1_t, MPI2_POINTER pMpi2EthernetPage1_t; - -#define MPI2_ETHERNETPAGE1_PAGEVERSION (0x00) - -/* values for Ethernet Page 1 Flags field */ -#define MPI2_ETHPG1_FLAG_SET_DEFAULT_IF (0x00000100) -#define MPI2_ETHPG1_FLAG_ENABLE_FW_DOWNLOAD (0x00000080) -#define MPI2_ETHPG1_FLAG_ENABLE_TELNET (0x00000040) -#define MPI2_ETHPG1_FLAG_ENABLE_SSH2 (0x00000020) -#define MPI2_ETHPG1_FLAG_ENABLE_DHCP_CLIENT (0x00000010) -#define MPI2_ETHPG1_FLAG_ENABLE_IPV6 (0x00000008) -#define MPI2_ETHPG1_FLAG_ENABLE_IPV4 (0x00000004) -#define MPI2_ETHPG1_FLAG_USE_IPV6_ADDRESSES (0x00000002) -#define MPI2_ETHPG1_FLAG_ENABLE_ETH_IF (0x00000001) - -/* values for Ethernet Page 1 MediaState field */ -#define MPI2_ETHPG1_MS_DUPLEX_MASK (0x80) -#define MPI2_ETHPG1_MS_HALF_DUPLEX (0x00) -#define MPI2_ETHPG1_MS_FULL_DUPLEX (0x80) - -#define MPI2_ETHPG1_MS_DATA_RATE_MASK (0x07) -#define MPI2_ETHPG1_MS_DATA_RATE_AUTO (0x00) -#define MPI2_ETHPG1_MS_DATA_RATE_10MBIT (0x01) -#define MPI2_ETHPG1_MS_DATA_RATE_100MBIT (0x02) -#define MPI2_ETHPG1_MS_DATA_RATE_1GBIT (0x03) - - -/**************************************************************************** -* Extended Manufacturing Config Pages -****************************************************************************/ - -/* - * Generic structure to use for product-specific extended manufacturing pages - * (currently Extended Manufacturing Page 40 through Extended Manufacturing - * Page 60). - */ - -typedef struct _MPI2_CONFIG_PAGE_EXT_MAN_PS { - MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ - U32 ProductSpecificInfo; /* 0x08 */ -} MPI2_CONFIG_PAGE_EXT_MAN_PS, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_EXT_MAN_PS, - Mpi2ExtManufacturingPagePS_t, - MPI2_POINTER pMpi2ExtManufacturingPagePS_t; - -/* PageVersion should be provided by product-specific code */ - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_init.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_init.h deleted file mode 100644 index de901624..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_init.h +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Copyright (c) 2000-2010 LSI Corporation. - * - * - * Name: mpi2_init.h - * Title: MPI SCSI initiator mode messages and structures - * Creation Date: June 23, 2006 - * - * mpi2_init.h Version: 02.00.11 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 10-31-07 02.00.01 Fixed name for pMpi2SCSITaskManagementRequest_t. - * 12-18-07 02.00.02 Modified Task Management Target Reset Method defines. - * 02-29-08 02.00.03 Added Query Task Set and Query Unit Attention. - * 03-03-08 02.00.04 Fixed name of struct _MPI2_SCSI_TASK_MANAGE_REPLY. - * 05-21-08 02.00.05 Fixed typo in name of Mpi2SepRequest_t. - * 10-02-08 02.00.06 Removed Untagged and No Disconnect values from SCSI IO - * Control field Task Attribute flags. - * Moved LUN field defines to mpi2.h because they are - * common to many structures. - * 05-06-09 02.00.07 Changed task management type of Query Unit Attention to - * Query Asynchronous Event. - * Defined two new bits in the SlotStatus field of the SCSI - * Enclosure Processor Request and Reply. - * 10-28-09 02.00.08 Added defines for decoding the ResponseInfo bytes for - * both SCSI IO Error Reply and SCSI Task Management Reply. - * Added ResponseInfo field to MPI2_SCSI_TASK_MANAGE_REPLY. - * Added MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG define. - * 02-10-10 02.00.09 Removed unused structure that had "#if 0" around it. - * 05-12-10 02.00.10 Added optional vendor-unique region to SCSI IO Request. - * 11-10-10 02.00.11 Added MPI2_SCSIIO_NUM_SGLOFFSETS define. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_INIT_H -#define MPI2_INIT_H - -/***************************************************************************** -* -* SCSI Initiator Messages -* -*****************************************************************************/ - -/**************************************************************************** -* SCSI IO messages and associated structures -****************************************************************************/ - -typedef struct -{ - U8 CDB[20]; /* 0x00 */ - U32 PrimaryReferenceTag; /* 0x14 */ - U16 PrimaryApplicationTag; /* 0x18 */ - U16 PrimaryApplicationTagMask; /* 0x1A */ - U32 TransferLength; /* 0x1C */ -} MPI2_SCSI_IO_CDB_EEDP32, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_EEDP32, - Mpi2ScsiIoCdbEedp32_t, MPI2_POINTER pMpi2ScsiIoCdbEedp32_t; - -typedef union -{ - U8 CDB32[32]; - MPI2_SCSI_IO_CDB_EEDP32 EEDP32; - MPI2_SGE_SIMPLE_UNION SGE; -} MPI2_SCSI_IO_CDB_UNION, MPI2_POINTER PTR_MPI2_SCSI_IO_CDB_UNION, - Mpi2ScsiIoCdb_t, MPI2_POINTER pMpi2ScsiIoCdb_t; - -/* SCSI IO Request Message */ -typedef struct _MPI2_SCSI_IO_REQUEST -{ - U16 DevHandle; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U32 SenseBufferLowAddress; /* 0x0C */ - U16 SGLFlags; /* 0x10 */ - U8 SenseBufferLength; /* 0x12 */ - U8 Reserved4; /* 0x13 */ - U8 SGLOffset0; /* 0x14 */ - U8 SGLOffset1; /* 0x15 */ - U8 SGLOffset2; /* 0x16 */ - U8 SGLOffset3; /* 0x17 */ - U32 SkipCount; /* 0x18 */ - U32 DataLength; /* 0x1C */ - U32 BidirectionalDataLength; /* 0x20 */ - U16 IoFlags; /* 0x24 */ - U16 EEDPFlags; /* 0x26 */ - U32 EEDPBlockSize; /* 0x28 */ - U32 SecondaryReferenceTag; /* 0x2C */ - U16 SecondaryApplicationTag; /* 0x30 */ - U16 ApplicationTagTranslationMask; /* 0x32 */ - U8 LUN[8]; /* 0x34 */ - U32 Control; /* 0x3C */ - MPI2_SCSI_IO_CDB_UNION CDB; /* 0x40 */ - -#ifdef MPI2_SCSI_IO_VENDOR_UNIQUE_REGION /* typically this is left undefined */ - MPI2_SCSI_IO_VENDOR_UNIQUE VendorRegion; -#endif - - MPI2_SGE_IO_UNION SGL; /* 0x60 */ - -} MPI2_SCSI_IO_REQUEST, MPI2_POINTER PTR_MPI2_SCSI_IO_REQUEST, - Mpi2SCSIIORequest_t, MPI2_POINTER pMpi2SCSIIORequest_t; - -/* SCSI IO MsgFlags bits */ - -/* MsgFlags for SenseBufferAddressSpace */ -#define MPI2_SCSIIO_MSGFLAGS_MASK_SENSE_ADDR (0x0C) -#define MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR (0x00) -#define MPI2_SCSIIO_MSGFLAGS_IOCDDR_SENSE_ADDR (0x04) -#define MPI2_SCSIIO_MSGFLAGS_IOCPLB_SENSE_ADDR (0x08) -#define MPI2_SCSIIO_MSGFLAGS_IOCPLBNTA_SENSE_ADDR (0x0C) - -/* SCSI IO SGLFlags bits */ - -/* base values for Data Location Address Space */ -#define MPI2_SCSIIO_SGLFLAGS_ADDR_MASK (0x0C) -#define MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR (0x00) -#define MPI2_SCSIIO_SGLFLAGS_IOCDDR_ADDR (0x04) -#define MPI2_SCSIIO_SGLFLAGS_IOCPLB_ADDR (0x08) -#define MPI2_SCSIIO_SGLFLAGS_IOCPLBNTA_ADDR (0x0C) - -/* base values for Type */ -#define MPI2_SCSIIO_SGLFLAGS_TYPE_MASK (0x03) -#define MPI2_SCSIIO_SGLFLAGS_TYPE_MPI (0x00) -#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE32 (0x01) -#define MPI2_SCSIIO_SGLFLAGS_TYPE_IEEE64 (0x02) - -/* shift values for each sub-field */ -#define MPI2_SCSIIO_SGLFLAGS_SGL3_SHIFT (12) -#define MPI2_SCSIIO_SGLFLAGS_SGL2_SHIFT (8) -#define MPI2_SCSIIO_SGLFLAGS_SGL1_SHIFT (4) -#define MPI2_SCSIIO_SGLFLAGS_SGL0_SHIFT (0) - -/* number of SGLOffset fields */ -#define MPI2_SCSIIO_NUM_SGLOFFSETS (4) - -/* SCSI IO IoFlags bits */ - -/* Large CDB Address Space */ -#define MPI2_SCSIIO_CDB_ADDR_MASK (0x6000) -#define MPI2_SCSIIO_CDB_ADDR_SYSTEM (0x0000) -#define MPI2_SCSIIO_CDB_ADDR_IOCDDR (0x2000) -#define MPI2_SCSIIO_CDB_ADDR_IOCPLB (0x4000) -#define MPI2_SCSIIO_CDB_ADDR_IOCPLBNTA (0x6000) - -#define MPI2_SCSIIO_IOFLAGS_LARGE_CDB (0x1000) -#define MPI2_SCSIIO_IOFLAGS_BIDIRECTIONAL (0x0800) -#define MPI2_SCSIIO_IOFLAGS_MULTICAST (0x0400) -#define MPI2_SCSIIO_IOFLAGS_CMD_DETERMINES_DATA_DIR (0x0200) -#define MPI2_SCSIIO_IOFLAGS_CDBLENGTH_MASK (0x01FF) - -/* SCSI IO EEDPFlags bits */ - -#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG (0x8000) -#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_REFTAG (0x4000) -#define MPI2_SCSIIO_EEDPFLAGS_INC_PRI_APPTAG (0x2000) -#define MPI2_SCSIIO_EEDPFLAGS_INC_SEC_APPTAG (0x1000) - -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG (0x0400) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_APPTAG (0x0200) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD (0x0100) - -#define MPI2_SCSIIO_EEDPFLAGS_PASSTHRU_REFTAG (0x0008) - -#define MPI2_SCSIIO_EEDPFLAGS_MASK_OP (0x0007) -#define MPI2_SCSIIO_EEDPFLAGS_NOOP_OP (0x0000) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_OP (0x0001) -#define MPI2_SCSIIO_EEDPFLAGS_STRIP_OP (0x0002) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP (0x0003) -#define MPI2_SCSIIO_EEDPFLAGS_INSERT_OP (0x0004) -#define MPI2_SCSIIO_EEDPFLAGS_REPLACE_OP (0x0006) -#define MPI2_SCSIIO_EEDPFLAGS_CHECK_REGEN_OP (0x0007) - -/* SCSI IO LUN fields: use MPI2_LUN_ from mpi2.h */ - -/* SCSI IO Control bits */ -#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_MASK (0xFC000000) -#define MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT (26) - -#define MPI2_SCSIIO_CONTROL_DATADIRECTION_MASK (0x03000000) -#define MPI2_SCSIIO_CONTROL_NODATATRANSFER (0x00000000) -#define MPI2_SCSIIO_CONTROL_WRITE (0x01000000) -#define MPI2_SCSIIO_CONTROL_READ (0x02000000) -#define MPI2_SCSIIO_CONTROL_BIDIRECTIONAL (0x03000000) - -#define MPI2_SCSIIO_CONTROL_TASKPRI_MASK (0x00007800) -#define MPI2_SCSIIO_CONTROL_TASKPRI_SHIFT (11) - -#define MPI2_SCSIIO_CONTROL_TASKATTRIBUTE_MASK (0x00000700) -#define MPI2_SCSIIO_CONTROL_SIMPLEQ (0x00000000) -#define MPI2_SCSIIO_CONTROL_HEADOFQ (0x00000100) -#define MPI2_SCSIIO_CONTROL_ORDEREDQ (0x00000200) -#define MPI2_SCSIIO_CONTROL_ACAQ (0x00000400) - -#define MPI2_SCSIIO_CONTROL_TLR_MASK (0x000000C0) -#define MPI2_SCSIIO_CONTROL_NO_TLR (0x00000000) -#define MPI2_SCSIIO_CONTROL_TLR_ON (0x00000040) -#define MPI2_SCSIIO_CONTROL_TLR_OFF (0x00000080) - - -/* SCSI IO Error Reply Message */ -typedef struct _MPI2_SCSI_IO_REPLY -{ - U16 DevHandle; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U8 SCSIStatus; /* 0x0C */ - U8 SCSIState; /* 0x0D */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 TransferCount; /* 0x14 */ - U32 SenseCount; /* 0x18 */ - U32 ResponseInfo; /* 0x1C */ - U16 TaskTag; /* 0x20 */ - U16 Reserved4; /* 0x22 */ - U32 BidirectionalTransferCount; /* 0x24 */ - U32 Reserved5; /* 0x28 */ - U32 Reserved6; /* 0x2C */ -} MPI2_SCSI_IO_REPLY, MPI2_POINTER PTR_MPI2_SCSI_IO_REPLY, - Mpi2SCSIIOReply_t, MPI2_POINTER pMpi2SCSIIOReply_t; - -/* SCSI IO Reply SCSIStatus values (SAM-4 status codes) */ - -#define MPI2_SCSI_STATUS_GOOD (0x00) -#define MPI2_SCSI_STATUS_CHECK_CONDITION (0x02) -#define MPI2_SCSI_STATUS_CONDITION_MET (0x04) -#define MPI2_SCSI_STATUS_BUSY (0x08) -#define MPI2_SCSI_STATUS_INTERMEDIATE (0x10) -#define MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET (0x14) -#define MPI2_SCSI_STATUS_RESERVATION_CONFLICT (0x18) -#define MPI2_SCSI_STATUS_COMMAND_TERMINATED (0x22) /* obsolete */ -#define MPI2_SCSI_STATUS_TASK_SET_FULL (0x28) -#define MPI2_SCSI_STATUS_ACA_ACTIVE (0x30) -#define MPI2_SCSI_STATUS_TASK_ABORTED (0x40) - -/* SCSI IO Reply SCSIState flags */ - -#define MPI2_SCSI_STATE_RESPONSE_INFO_VALID (0x10) -#define MPI2_SCSI_STATE_TERMINATED (0x08) -#define MPI2_SCSI_STATE_NO_SCSI_STATUS (0x04) -#define MPI2_SCSI_STATE_AUTOSENSE_FAILED (0x02) -#define MPI2_SCSI_STATE_AUTOSENSE_VALID (0x01) - -/* masks and shifts for the ResponseInfo field */ - -#define MPI2_SCSI_RI_MASK_REASONCODE (0x000000FF) -#define MPI2_SCSI_RI_SHIFT_REASONCODE (0) - -#define MPI2_SCSI_TASKTAG_UNKNOWN (0xFFFF) - - -/**************************************************************************** -* SCSI Task Management messages -****************************************************************************/ - -/* SCSI Task Management Request Message */ -typedef struct _MPI2_SCSI_TASK_MANAGE_REQUEST -{ - U16 DevHandle; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Reserved1; /* 0x04 */ - U8 TaskType; /* 0x05 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U8 LUN[8]; /* 0x0C */ - U32 Reserved4[7]; /* 0x14 */ - U16 TaskMID; /* 0x30 */ - U16 Reserved5; /* 0x32 */ -} MPI2_SCSI_TASK_MANAGE_REQUEST, - MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REQUEST, - Mpi2SCSITaskManagementRequest_t, - MPI2_POINTER pMpi2SCSITaskManagementRequest_t; - -/* TaskType values */ - -#define MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK (0x01) -#define MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET (0x02) -#define MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET (0x03) -#define MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET (0x05) -#define MPI2_SCSITASKMGMT_TASKTYPE_CLEAR_TASK_SET (0x06) -#define MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK (0x07) -#define MPI2_SCSITASKMGMT_TASKTYPE_CLR_ACA (0x08) -#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_TASK_SET (0x09) -#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT (0x0A) - -/* obsolete TaskType name */ -#define MPI2_SCSITASKMGMT_TASKTYPE_QRY_UNIT_ATTENTION \ - (MPI2_SCSITASKMGMT_TASKTYPE_QRY_ASYNC_EVENT) - -/* MsgFlags bits */ - -#define MPI2_SCSITASKMGMT_MSGFLAGS_MASK_TARGET_RESET (0x18) -#define MPI2_SCSITASKMGMT_MSGFLAGS_LINK_RESET (0x00) -#define MPI2_SCSITASKMGMT_MSGFLAGS_NEXUS_RESET_SRST (0x08) -#define MPI2_SCSITASKMGMT_MSGFLAGS_SAS_HARD_LINK_RESET (0x10) - -#define MPI2_SCSITASKMGMT_MSGFLAGS_DO_NOT_SEND_TASK_IU (0x01) - - - -/* SCSI Task Management Reply Message */ -typedef struct _MPI2_SCSI_TASK_MANAGE_REPLY -{ - U16 DevHandle; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 ResponseCode; /* 0x04 */ - U8 TaskType; /* 0x05 */ - U8 Reserved1; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U16 Reserved3; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 TerminationCount; /* 0x14 */ - U32 ResponseInfo; /* 0x18 */ -} MPI2_SCSI_TASK_MANAGE_REPLY, - MPI2_POINTER PTR_MPI2_SCSI_TASK_MANAGE_REPLY, - Mpi2SCSITaskManagementReply_t, MPI2_POINTER pMpi2SCSIManagementReply_t; - -/* ResponseCode values */ - -#define MPI2_SCSITASKMGMT_RSP_TM_COMPLETE (0x00) -#define MPI2_SCSITASKMGMT_RSP_INVALID_FRAME (0x02) -#define MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED (0x04) -#define MPI2_SCSITASKMGMT_RSP_TM_FAILED (0x05) -#define MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED (0x08) -#define MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN (0x09) -#define MPI2_SCSITASKMGMT_RSP_TM_OVERLAPPED_TAG (0x0A) -#define MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC (0x80) - -/* masks and shifts for the ResponseInfo field */ - -#define MPI2_SCSITASKMGMT_RI_MASK_REASONCODE (0x000000FF) -#define MPI2_SCSITASKMGMT_RI_SHIFT_REASONCODE (0) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI2 (0x0000FF00) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI2 (8) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI1 (0x00FF0000) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI1 (16) -#define MPI2_SCSITASKMGMT_RI_MASK_ARI0 (0xFF000000) -#define MPI2_SCSITASKMGMT_RI_SHIFT_ARI0 (24) - - -/**************************************************************************** -* SCSI Enclosure Processor messages -****************************************************************************/ - -/* SCSI Enclosure Processor Request Message */ -typedef struct _MPI2_SEP_REQUEST -{ - U16 DevHandle; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Action; /* 0x04 */ - U8 Flags; /* 0x05 */ - U8 Reserved1; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 SlotStatus; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U32 Reserved4; /* 0x14 */ - U32 Reserved5; /* 0x18 */ - U16 Slot; /* 0x1C */ - U16 EnclosureHandle; /* 0x1E */ -} MPI2_SEP_REQUEST, MPI2_POINTER PTR_MPI2_SEP_REQUEST, - Mpi2SepRequest_t, MPI2_POINTER pMpi2SepRequest_t; - -/* Action defines */ -#define MPI2_SEP_REQ_ACTION_WRITE_STATUS (0x00) -#define MPI2_SEP_REQ_ACTION_READ_STATUS (0x01) - -/* Flags defines */ -#define MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS (0x00) -#define MPI2_SEP_REQ_FLAGS_ENCLOSURE_SLOT_ADDRESS (0x01) - -/* SlotStatus defines */ -#define MPI2_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) -#define MPI2_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) -#define MPI2_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) -#define MPI2_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) -#define MPI2_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) -#define MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT (0x00000040) -#define MPI2_SEP_REQ_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) -#define MPI2_SEP_REQ_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -#define MPI2_SEP_REQ_SLOTSTATUS_DEV_REBUILDING (0x00000004) -#define MPI2_SEP_REQ_SLOTSTATUS_DEV_FAULTY (0x00000002) -#define MPI2_SEP_REQ_SLOTSTATUS_NO_ERROR (0x00000001) - - -/* SCSI Enclosure Processor Reply Message */ -typedef struct _MPI2_SEP_REPLY -{ - U16 DevHandle; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Action; /* 0x04 */ - U8 Flags; /* 0x05 */ - U8 Reserved1; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U16 Reserved3; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 SlotStatus; /* 0x14 */ - U32 Reserved4; /* 0x18 */ - U16 Slot; /* 0x1C */ - U16 EnclosureHandle; /* 0x1E */ -} MPI2_SEP_REPLY, MPI2_POINTER PTR_MPI2_SEP_REPLY, - Mpi2SepReply_t, MPI2_POINTER pMpi2SepReply_t; - -/* SlotStatus defines */ -#define MPI2_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) -#define MPI2_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) -#define MPI2_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) -#define MPI2_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) -#define MPI2_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) -#define MPI2_SEP_REPLY_SLOTSTATUS_PREDICTED_FAULT (0x00000040) -#define MPI2_SEP_REPLY_SLOTSTATUS_IN_CRITICAL_ARRAY (0x00000010) -#define MPI2_SEP_REPLY_SLOTSTATUS_IN_FAILED_ARRAY (0x00000008) -#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_REBUILDING (0x00000004) -#define MPI2_SEP_REPLY_SLOTSTATUS_DEV_FAULTY (0x00000002) -#define MPI2_SEP_REPLY_SLOTSTATUS_NO_ERROR (0x00000001) - - -#endif - - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h deleted file mode 100644 index 9a925c07..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h +++ /dev/null @@ -1,1648 +0,0 @@ -/* - * Copyright (c) 2000-2011 LSI Corporation. - * - * - * Name: mpi2_ioc.h - * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages - * Creation Date: October 11, 2006 - * - * mpi2_ioc.h Version: 02.00.19 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 06-04-07 02.00.01 In IOCFacts Reply structure, renamed MaxDevices to - * MaxTargets. - * Added TotalImageSize field to FWDownload Request. - * Added reserved words to FWUpload Request. - * 06-26-07 02.00.02 Added IR Configuration Change List Event. - * 08-31-07 02.00.03 Removed SystemReplyQueueDepth field from the IOCInit - * request and replaced it with - * ReplyDescriptorPostQueueDepth and ReplyFreeQueueDepth. - * Replaced the MinReplyQueueDepth field of the IOCFacts - * reply with MaxReplyDescriptorPostQueueDepth. - * Added MPI2_RDPQ_DEPTH_MIN define to specify the minimum - * depth for the Reply Descriptor Post Queue. - * Added SASAddress field to Initiator Device Table - * Overflow Event data. - * 10-31-07 02.00.04 Added ReasonCode MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING - * for SAS Initiator Device Status Change Event data. - * Modified Reason Code defines for SAS Topology Change - * List Event data, including adding a bit for PHY Vacant - * status, and adding a mask for the Reason Code. - * Added define for - * MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING. - * Added define for MPI2_EXT_IMAGE_TYPE_MEGARAID. - * 12-18-07 02.00.05 Added Boot Status defines for the IOCExceptions field of - * the IOCFacts Reply. - * Removed MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. - * Moved MPI2_VERSION_UNION to mpi2.h. - * Changed MPI2_EVENT_NOTIFICATION_REQUEST to use masks - * instead of enables, and added SASBroadcastPrimitiveMasks - * field. - * Added Log Entry Added Event and related structure. - * 02-29-08 02.00.06 Added define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID. - * Removed define MPI2_IOCFACTS_PROTOCOL_SMP_TARGET. - * Added MaxVolumes and MaxPersistentEntries fields to - * IOCFacts reply. - * Added ProtocalFlags and IOCCapabilities fields to - * MPI2_FW_IMAGE_HEADER. - * Removed MPI2_PORTENABLE_FLAGS_ENABLE_SINGLE_PORT. - * 03-03-08 02.00.07 Fixed MPI2_FW_IMAGE_HEADER by changing Reserved26 to - * a U16 (from a U32). - * Removed extra 's' from EventMasks name. - * 06-27-08 02.00.08 Fixed an offset in a comment. - * 10-02-08 02.00.09 Removed SystemReplyFrameSize from MPI2_IOC_INIT_REQUEST. - * Removed CurReplyFrameSize from MPI2_IOC_FACTS_REPLY and - * renamed MinReplyFrameSize to ReplyFrameSize. - * Added MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX. - * Added two new RAIDOperation values for Integrated RAID - * Operations Status Event data. - * Added four new IR Configuration Change List Event data - * ReasonCode values. - * Added two new ReasonCode defines for SAS Device Status - * Change Event data. - * Added three new DiscoveryStatus bits for the SAS - * Discovery event data. - * Added Multiplexing Status Change bit to the PhyStatus - * field of the SAS Topology Change List event data. - * Removed define for MPI2_INIT_IMAGE_BOOTFLAGS_XMEMCOPY. - * BootFlags are now product-specific. - * Added defines for the indivdual signature bytes - * for MPI2_INIT_IMAGE_FOOTER. - * 01-19-09 02.00.10 Added MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY define. - * Added MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR - * define. - * Added MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE - * define. - * Removed MPI2_EVENT_SAS_DISC_DS_SATA_INIT_FAILURE define. - * 05-06-09 02.00.11 Added MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR define. - * Added MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX define. - * Added two new reason codes for SAS Device Status Change - * Event. - * Added new event: SAS PHY Counter. - * 07-30-09 02.00.12 Added GPIO Interrupt event define and structure. - * Added MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER define. - * Added new product id family for 2208. - * 10-28-09 02.00.13 Added HostMSIxVectors field to MPI2_IOC_INIT_REQUEST. - * Added MaxMSIxVectors field to MPI2_IOC_FACTS_REPLY. - * Added MinDevHandle field to MPI2_IOC_FACTS_REPLY. - * Added MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY. - * Added MPI2_EVENT_HOST_BASED_DISCOVERY_PHY define. - * Added MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER define. - * Added Host Based Discovery Phy Event data. - * Added defines for ProductID Product field - * (MPI2_FW_HEADER_PID_). - * Modified values for SAS ProductID Family - * (MPI2_FW_HEADER_PID_FAMILY_). - * 02-10-10 02.00.14 Added SAS Quiesce Event structure and defines. - * Added PowerManagementControl Request structures and - * defines. - * 05-12-10 02.00.15 Marked Task Set Full Event as obsolete. - * Added MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY define. - * 11-10-10 02.00.16 Added MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC. - * 02-23-11 02.00.17 Added SAS NOTIFY Primitive event, and added - * SASNotifyPrimitiveMasks field to - * MPI2_EVENT_NOTIFICATION_REQUEST. - * Added Temperature Threshold Event. - * Added Host Message Event. - * Added Send Host Message request and reply. - * 05-25-11 02.00.18 For Extended Image Header, added - * MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC and - * MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC defines. - * Deprecated MPI2_EXT_IMAGE_TYPE_MAX define. - * 08-24-11 02.00.19 Added PhysicalPort field to - * MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE structure. - * Marked MPI2_PM_CONTROL_FEATURE_PCIE_LINK as obsolete. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_IOC_H -#define MPI2_IOC_H - -/***************************************************************************** -* -* IOC Messages -* -*****************************************************************************/ - -/**************************************************************************** -* IOCInit message -****************************************************************************/ - -/* IOCInit Request message */ -typedef struct _MPI2_IOC_INIT_REQUEST -{ - U8 WhoInit; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 MsgVersion; /* 0x0C */ - U16 HeaderVersion; /* 0x0E */ - U32 Reserved5; /* 0x10 */ - U16 Reserved6; /* 0x14 */ - U8 Reserved7; /* 0x16 */ - U8 HostMSIxVectors; /* 0x17 */ - U16 Reserved8; /* 0x18 */ - U16 SystemRequestFrameSize; /* 0x1A */ - U16 ReplyDescriptorPostQueueDepth; /* 0x1C */ - U16 ReplyFreeQueueDepth; /* 0x1E */ - U32 SenseBufferAddressHigh; /* 0x20 */ - U32 SystemReplyAddressHigh; /* 0x24 */ - U64 SystemRequestFrameBaseAddress; /* 0x28 */ - U64 ReplyDescriptorPostQueueAddress;/* 0x30 */ - U64 ReplyFreeQueueAddress; /* 0x38 */ - U64 TimeStamp; /* 0x40 */ -} MPI2_IOC_INIT_REQUEST, MPI2_POINTER PTR_MPI2_IOC_INIT_REQUEST, - Mpi2IOCInitRequest_t, MPI2_POINTER pMpi2IOCInitRequest_t; - -/* WhoInit values */ -#define MPI2_WHOINIT_NOT_INITIALIZED (0x00) -#define MPI2_WHOINIT_SYSTEM_BIOS (0x01) -#define MPI2_WHOINIT_ROM_BIOS (0x02) -#define MPI2_WHOINIT_PCI_PEER (0x03) -#define MPI2_WHOINIT_HOST_DRIVER (0x04) -#define MPI2_WHOINIT_MANUFACTURER (0x05) - -/* MsgVersion */ -#define MPI2_IOCINIT_MSGVERSION_MAJOR_MASK (0xFF00) -#define MPI2_IOCINIT_MSGVERSION_MAJOR_SHIFT (8) -#define MPI2_IOCINIT_MSGVERSION_MINOR_MASK (0x00FF) -#define MPI2_IOCINIT_MSGVERSION_MINOR_SHIFT (0) - -/* HeaderVersion */ -#define MPI2_IOCINIT_HDRVERSION_UNIT_MASK (0xFF00) -#define MPI2_IOCINIT_HDRVERSION_UNIT_SHIFT (8) -#define MPI2_IOCINIT_HDRVERSION_DEV_MASK (0x00FF) -#define MPI2_IOCINIT_HDRVERSION_DEV_SHIFT (0) - -/* minimum depth for the Reply Descriptor Post Queue */ -#define MPI2_RDPQ_DEPTH_MIN (16) - - -/* IOCInit Reply message */ -typedef struct _MPI2_IOC_INIT_REPLY -{ - U8 WhoInit; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_IOC_INIT_REPLY, MPI2_POINTER PTR_MPI2_IOC_INIT_REPLY, - Mpi2IOCInitReply_t, MPI2_POINTER pMpi2IOCInitReply_t; - - -/**************************************************************************** -* IOCFacts message -****************************************************************************/ - -/* IOCFacts Request message */ -typedef struct _MPI2_IOC_FACTS_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ -} MPI2_IOC_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_IOC_FACTS_REQUEST, - Mpi2IOCFactsRequest_t, MPI2_POINTER pMpi2IOCFactsRequest_t; - - -/* IOCFacts Reply message */ -typedef struct _MPI2_IOC_FACTS_REPLY -{ - U16 MsgVersion; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 HeaderVersion; /* 0x04 */ - U8 IOCNumber; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U16 IOCExceptions; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U8 MaxChainDepth; /* 0x14 */ - U8 WhoInit; /* 0x15 */ - U8 NumberOfPorts; /* 0x16 */ - U8 MaxMSIxVectors; /* 0x17 */ - U16 RequestCredit; /* 0x18 */ - U16 ProductID; /* 0x1A */ - U32 IOCCapabilities; /* 0x1C */ - MPI2_VERSION_UNION FWVersion; /* 0x20 */ - U16 IOCRequestFrameSize; /* 0x24 */ - U16 Reserved3; /* 0x26 */ - U16 MaxInitiators; /* 0x28 */ - U16 MaxTargets; /* 0x2A */ - U16 MaxSasExpanders; /* 0x2C */ - U16 MaxEnclosures; /* 0x2E */ - U16 ProtocolFlags; /* 0x30 */ - U16 HighPriorityCredit; /* 0x32 */ - U16 MaxReplyDescriptorPostQueueDepth; /* 0x34 */ - U8 ReplyFrameSize; /* 0x36 */ - U8 MaxVolumes; /* 0x37 */ - U16 MaxDevHandle; /* 0x38 */ - U16 MaxPersistentEntries; /* 0x3A */ - U16 MinDevHandle; /* 0x3C */ - U16 Reserved4; /* 0x3E */ -} MPI2_IOC_FACTS_REPLY, MPI2_POINTER PTR_MPI2_IOC_FACTS_REPLY, - Mpi2IOCFactsReply_t, MPI2_POINTER pMpi2IOCFactsReply_t; - -/* MsgVersion */ -#define MPI2_IOCFACTS_MSGVERSION_MAJOR_MASK (0xFF00) -#define MPI2_IOCFACTS_MSGVERSION_MAJOR_SHIFT (8) -#define MPI2_IOCFACTS_MSGVERSION_MINOR_MASK (0x00FF) -#define MPI2_IOCFACTS_MSGVERSION_MINOR_SHIFT (0) - -/* HeaderVersion */ -#define MPI2_IOCFACTS_HDRVERSION_UNIT_MASK (0xFF00) -#define MPI2_IOCFACTS_HDRVERSION_UNIT_SHIFT (8) -#define MPI2_IOCFACTS_HDRVERSION_DEV_MASK (0x00FF) -#define MPI2_IOCFACTS_HDRVERSION_DEV_SHIFT (0) - -/* IOCExceptions */ -#define MPI2_IOCFACTS_EXCEPT_IR_FOREIGN_CONFIG_MAX (0x0100) - -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_MASK (0x00E0) -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_GOOD (0x0000) -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_BACKUP (0x0020) -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_RESTORED (0x0040) -#define MPI2_IOCFACTS_EXCEPT_BOOTSTAT_CORRUPT_BACKUP (0x0060) - -#define MPI2_IOCFACTS_EXCEPT_METADATA_UNSUPPORTED (0x0010) -#define MPI2_IOCFACTS_EXCEPT_MANUFACT_CHECKSUM_FAIL (0x0008) -#define MPI2_IOCFACTS_EXCEPT_FW_CHECKSUM_FAIL (0x0004) -#define MPI2_IOCFACTS_EXCEPT_RAID_CONFIG_INVALID (0x0002) -#define MPI2_IOCFACTS_EXCEPT_CONFIG_CHECKSUM_FAIL (0x0001) - -/* defines for WhoInit field are after the IOCInit Request */ - -/* ProductID field uses MPI2_FW_HEADER_PID_ */ - -/* IOCCapabilities */ -#define MPI2_IOCFACTS_CAPABILITY_HOST_BASED_DISCOVERY (0x00010000) -#define MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX (0x00008000) -#define MPI2_IOCFACTS_CAPABILITY_RAID_ACCELERATOR (0x00004000) -#define MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY (0x00002000) -#define MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID (0x00001000) -#define MPI2_IOCFACTS_CAPABILITY_TLR (0x00000800) -#define MPI2_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) -#define MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET (0x00000080) -#define MPI2_IOCFACTS_CAPABILITY_EEDP (0x00000040) -#define MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) -#define MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) -#define MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) -#define MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING (0x00000004) - -/* ProtocolFlags */ -#define MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET (0x0001) -#define MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR (0x0002) - - -/**************************************************************************** -* PortFacts message -****************************************************************************/ - -/* PortFacts Request message */ -typedef struct _MPI2_PORT_FACTS_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 PortNumber; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ -} MPI2_PORT_FACTS_REQUEST, MPI2_POINTER PTR_MPI2_PORT_FACTS_REQUEST, - Mpi2PortFactsRequest_t, MPI2_POINTER pMpi2PortFactsRequest_t; - -/* PortFacts Reply message */ -typedef struct _MPI2_PORT_FACTS_REPLY -{ - U16 Reserved1; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 PortNumber; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U16 Reserved4; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U8 Reserved5; /* 0x14 */ - U8 PortType; /* 0x15 */ - U16 Reserved6; /* 0x16 */ - U16 MaxPostedCmdBuffers; /* 0x18 */ - U16 Reserved7; /* 0x1A */ -} MPI2_PORT_FACTS_REPLY, MPI2_POINTER PTR_MPI2_PORT_FACTS_REPLY, - Mpi2PortFactsReply_t, MPI2_POINTER pMpi2PortFactsReply_t; - -/* PortType values */ -#define MPI2_PORTFACTS_PORTTYPE_INACTIVE (0x00) -#define MPI2_PORTFACTS_PORTTYPE_FC (0x10) -#define MPI2_PORTFACTS_PORTTYPE_ISCSI (0x20) -#define MPI2_PORTFACTS_PORTTYPE_SAS_PHYSICAL (0x30) -#define MPI2_PORTFACTS_PORTTYPE_SAS_VIRTUAL (0x31) - - -/**************************************************************************** -* PortEnable message -****************************************************************************/ - -/* PortEnable Request message */ -typedef struct _MPI2_PORT_ENABLE_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Reserved2; /* 0x04 */ - U8 PortFlags; /* 0x05 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ -} MPI2_PORT_ENABLE_REQUEST, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REQUEST, - Mpi2PortEnableRequest_t, MPI2_POINTER pMpi2PortEnableRequest_t; - - -/* PortEnable Reply message */ -typedef struct _MPI2_PORT_ENABLE_REPLY -{ - U16 Reserved1; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U8 Reserved2; /* 0x04 */ - U8 PortFlags; /* 0x05 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_PORT_ENABLE_REPLY, MPI2_POINTER PTR_MPI2_PORT_ENABLE_REPLY, - Mpi2PortEnableReply_t, MPI2_POINTER pMpi2PortEnableReply_t; - - -/**************************************************************************** -* EventNotification message -****************************************************************************/ - -/* EventNotification Request message */ -#define MPI2_EVENT_NOTIFY_EVENTMASK_WORDS (4) - -typedef struct _MPI2_EVENT_NOTIFICATION_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 Reserved5; /* 0x0C */ - U32 Reserved6; /* 0x10 */ - U32 EventMasks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS];/* 0x14 */ - U16 SASBroadcastPrimitiveMasks; /* 0x24 */ - U16 SASNotifyPrimitiveMasks; /* 0x26 */ - U32 Reserved8; /* 0x28 */ -} MPI2_EVENT_NOTIFICATION_REQUEST, - MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REQUEST, - Mpi2EventNotificationRequest_t, MPI2_POINTER pMpi2EventNotificationRequest_t; - - -/* EventNotification Reply message */ -typedef struct _MPI2_EVENT_NOTIFICATION_REPLY -{ - U16 EventDataLength; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 AckRequired; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U16 Reserved3; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U16 Event; /* 0x14 */ - U16 Reserved4; /* 0x16 */ - U32 EventContext; /* 0x18 */ - U32 EventData[1]; /* 0x1C */ -} MPI2_EVENT_NOTIFICATION_REPLY, MPI2_POINTER PTR_MPI2_EVENT_NOTIFICATION_REPLY, - Mpi2EventNotificationReply_t, MPI2_POINTER pMpi2EventNotificationReply_t; - -/* AckRequired */ -#define MPI2_EVENT_NOTIFICATION_ACK_NOT_REQUIRED (0x00) -#define MPI2_EVENT_NOTIFICATION_ACK_REQUIRED (0x01) - -/* Event */ -#define MPI2_EVENT_LOG_DATA (0x0001) -#define MPI2_EVENT_STATE_CHANGE (0x0002) -#define MPI2_EVENT_HARD_RESET_RECEIVED (0x0005) -#define MPI2_EVENT_EVENT_CHANGE (0x000A) -#define MPI2_EVENT_TASK_SET_FULL (0x000E) /* obsolete */ -#define MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE (0x000F) -#define MPI2_EVENT_IR_OPERATION_STATUS (0x0014) -#define MPI2_EVENT_SAS_DISCOVERY (0x0016) -#define MPI2_EVENT_SAS_BROADCAST_PRIMITIVE (0x0017) -#define MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE (0x0018) -#define MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW (0x0019) -#define MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST (0x001C) -#define MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE (0x001D) -#define MPI2_EVENT_IR_VOLUME (0x001E) -#define MPI2_EVENT_IR_PHYSICAL_DISK (0x001F) -#define MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST (0x0020) -#define MPI2_EVENT_LOG_ENTRY_ADDED (0x0021) -#define MPI2_EVENT_SAS_PHY_COUNTER (0x0022) -#define MPI2_EVENT_GPIO_INTERRUPT (0x0023) -#define MPI2_EVENT_HOST_BASED_DISCOVERY_PHY (0x0024) -#define MPI2_EVENT_SAS_QUIESCE (0x0025) -#define MPI2_EVENT_SAS_NOTIFY_PRIMITIVE (0x0026) -#define MPI2_EVENT_TEMP_THRESHOLD (0x0027) -#define MPI2_EVENT_HOST_MESSAGE (0x0028) - - -/* Log Entry Added Event data */ - -/* the following structure matches MPI2_LOG_0_ENTRY in mpi2_cnfg.h */ -#define MPI2_EVENT_DATA_LOG_DATA_LENGTH (0x1C) - -typedef struct _MPI2_EVENT_DATA_LOG_ENTRY_ADDED -{ - U64 TimeStamp; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U16 LogSequence; /* 0x0C */ - U16 LogEntryQualifier; /* 0x0E */ - U8 VP_ID; /* 0x10 */ - U8 VF_ID; /* 0x11 */ - U16 Reserved2; /* 0x12 */ - U8 LogData[MPI2_EVENT_DATA_LOG_DATA_LENGTH];/* 0x14 */ -} MPI2_EVENT_DATA_LOG_ENTRY_ADDED, - MPI2_POINTER PTR_MPI2_EVENT_DATA_LOG_ENTRY_ADDED, - Mpi2EventDataLogEntryAdded_t, MPI2_POINTER pMpi2EventDataLogEntryAdded_t; - -/* GPIO Interrupt Event data */ - -typedef struct _MPI2_EVENT_DATA_GPIO_INTERRUPT { - U8 GPIONum; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ -} MPI2_EVENT_DATA_GPIO_INTERRUPT, - MPI2_POINTER PTR_MPI2_EVENT_DATA_GPIO_INTERRUPT, - Mpi2EventDataGpioInterrupt_t, MPI2_POINTER pMpi2EventDataGpioInterrupt_t; - -/* Temperature Threshold Event data */ - -typedef struct _MPI2_EVENT_DATA_TEMPERATURE { - U16 Status; /* 0x00 */ - U8 SensorNum; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U16 CurrentTemperature; /* 0x04 */ - U16 Reserved2; /* 0x06 */ - U32 Reserved3; /* 0x08 */ - U32 Reserved4; /* 0x0C */ -} MPI2_EVENT_DATA_TEMPERATURE, -MPI2_POINTER PTR_MPI2_EVENT_DATA_TEMPERATURE, -Mpi2EventDataTemperature_t, MPI2_POINTER pMpi2EventDataTemperature_t; - -/* Temperature Threshold Event data Status bits */ -#define MPI2_EVENT_TEMPERATURE3_EXCEEDED (0x0008) -#define MPI2_EVENT_TEMPERATURE2_EXCEEDED (0x0004) -#define MPI2_EVENT_TEMPERATURE1_EXCEEDED (0x0002) -#define MPI2_EVENT_TEMPERATURE0_EXCEEDED (0x0001) - - -/* Host Message Event data */ - -typedef struct _MPI2_EVENT_DATA_HOST_MESSAGE { - U8 SourceVF_ID; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ - U32 HostData[1]; /* 0x08 */ -} MPI2_EVENT_DATA_HOST_MESSAGE, MPI2_POINTER PTR_MPI2_EVENT_DATA_HOST_MESSAGE, -Mpi2EventDataHostMessage_t, MPI2_POINTER pMpi2EventDataHostMessage_t; - - -/* Hard Reset Received Event data */ - -typedef struct _MPI2_EVENT_DATA_HARD_RESET_RECEIVED -{ - U8 Reserved1; /* 0x00 */ - U8 Port; /* 0x01 */ - U16 Reserved2; /* 0x02 */ -} MPI2_EVENT_DATA_HARD_RESET_RECEIVED, - MPI2_POINTER PTR_MPI2_EVENT_DATA_HARD_RESET_RECEIVED, - Mpi2EventDataHardResetReceived_t, - MPI2_POINTER pMpi2EventDataHardResetReceived_t; - -/* Task Set Full Event data */ -/* this event is obsolete */ - -typedef struct _MPI2_EVENT_DATA_TASK_SET_FULL -{ - U16 DevHandle; /* 0x00 */ - U16 CurrentDepth; /* 0x02 */ -} MPI2_EVENT_DATA_TASK_SET_FULL, MPI2_POINTER PTR_MPI2_EVENT_DATA_TASK_SET_FULL, - Mpi2EventDataTaskSetFull_t, MPI2_POINTER pMpi2EventDataTaskSetFull_t; - - -/* SAS Device Status Change Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE -{ - U16 TaskTag; /* 0x00 */ - U8 ReasonCode; /* 0x02 */ - U8 PhysicalPort; /* 0x03 */ - U8 ASC; /* 0x04 */ - U8 ASCQ; /* 0x05 */ - U16 DevHandle; /* 0x06 */ - U32 Reserved2; /* 0x08 */ - U64 SASAddress; /* 0x0C */ - U8 LUN[8]; /* 0x14 */ -} MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DEVICE_STATUS_CHANGE, - Mpi2EventDataSasDeviceStatusChange_t, - MPI2_POINTER pMpi2EventDataSasDeviceStatusChange_t; - -/* SAS Device Status Change Event data ReasonCode values */ -#define MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA (0x05) -#define MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED (0x07) -#define MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET (0x08) -#define MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL (0x09) -#define MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL (0x0A) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL (0x0B) -#define MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL (0x0C) -#define MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION (0x0D) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET (0x0E) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL (0x0F) -#define MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE (0x10) -#define MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY (0x11) -#define MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY (0x12) - - -/* Integrated RAID Operation Status Event data */ - -typedef struct _MPI2_EVENT_DATA_IR_OPERATION_STATUS -{ - U16 VolDevHandle; /* 0x00 */ - U16 Reserved1; /* 0x02 */ - U8 RAIDOperation; /* 0x04 */ - U8 PercentComplete; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U32 Resereved3; /* 0x08 */ -} MPI2_EVENT_DATA_IR_OPERATION_STATUS, - MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_OPERATION_STATUS, - Mpi2EventDataIrOperationStatus_t, - MPI2_POINTER pMpi2EventDataIrOperationStatus_t; - -/* Integrated RAID Operation Status Event data RAIDOperation values */ -#define MPI2_EVENT_IR_RAIDOP_RESYNC (0x00) -#define MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION (0x01) -#define MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK (0x02) -#define MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT (0x03) -#define MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT (0x04) - - -/* Integrated RAID Volume Event data */ - -typedef struct _MPI2_EVENT_DATA_IR_VOLUME -{ - U16 VolDevHandle; /* 0x00 */ - U8 ReasonCode; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 NewValue; /* 0x04 */ - U32 PreviousValue; /* 0x08 */ -} MPI2_EVENT_DATA_IR_VOLUME, MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_VOLUME, - Mpi2EventDataIrVolume_t, MPI2_POINTER pMpi2EventDataIrVolume_t; - -/* Integrated RAID Volume Event data ReasonCode values */ -#define MPI2_EVENT_IR_VOLUME_RC_SETTINGS_CHANGED (0x01) -#define MPI2_EVENT_IR_VOLUME_RC_STATUS_FLAGS_CHANGED (0x02) -#define MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED (0x03) - - -/* Integrated RAID Physical Disk Event data */ - -typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK -{ - U16 Reserved1; /* 0x00 */ - U8 ReasonCode; /* 0x02 */ - U8 PhysDiskNum; /* 0x03 */ - U16 PhysDiskDevHandle; /* 0x04 */ - U16 Reserved2; /* 0x06 */ - U16 Slot; /* 0x08 */ - U16 EnclosureHandle; /* 0x0A */ - U32 NewValue; /* 0x0C */ - U32 PreviousValue; /* 0x10 */ -} MPI2_EVENT_DATA_IR_PHYSICAL_DISK, - MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_PHYSICAL_DISK, - Mpi2EventDataIrPhysicalDisk_t, MPI2_POINTER pMpi2EventDataIrPhysicalDisk_t; - -/* Integrated RAID Physical Disk Event data ReasonCode values */ -#define MPI2_EVENT_IR_PHYSDISK_RC_SETTINGS_CHANGED (0x01) -#define MPI2_EVENT_IR_PHYSDISK_RC_STATUS_FLAGS_CHANGED (0x02) -#define MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED (0x03) - - -/* Integrated RAID Configuration Change List Event data */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumElements at runtime. - */ -#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT -#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) -#endif - -typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT -{ - U16 ElementFlags; /* 0x00 */ - U16 VolDevHandle; /* 0x02 */ - U8 ReasonCode; /* 0x04 */ - U8 PhysDiskNum; /* 0x05 */ - U16 PhysDiskDevHandle; /* 0x06 */ -} MPI2_EVENT_IR_CONFIG_ELEMENT, MPI2_POINTER PTR_MPI2_EVENT_IR_CONFIG_ELEMENT, - Mpi2EventIrConfigElement_t, MPI2_POINTER pMpi2EventIrConfigElement_t; - -/* IR Configuration Change List Event data ElementFlags values */ -#define MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK (0x000F) -#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT (0x0000) -#define MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT (0x0001) -#define MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT (0x0002) - -/* IR Configuration Change List Event data ReasonCode values */ -#define MPI2_EVENT_IR_CHANGE_RC_ADDED (0x01) -#define MPI2_EVENT_IR_CHANGE_RC_REMOVED (0x02) -#define MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE (0x03) -#define MPI2_EVENT_IR_CHANGE_RC_HIDE (0x04) -#define MPI2_EVENT_IR_CHANGE_RC_UNHIDE (0x05) -#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED (0x06) -#define MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED (0x07) -#define MPI2_EVENT_IR_CHANGE_RC_PD_CREATED (0x08) -#define MPI2_EVENT_IR_CHANGE_RC_PD_DELETED (0x09) - -typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST -{ - U8 NumElements; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 Reserved2; /* 0x02 */ - U8 ConfigNum; /* 0x03 */ - U32 Flags; /* 0x04 */ - MPI2_EVENT_IR_CONFIG_ELEMENT ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT]; /* 0x08 */ -} MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, - MPI2_POINTER PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, - Mpi2EventDataIrConfigChangeList_t, - MPI2_POINTER pMpi2EventDataIrConfigChangeList_t; - -/* IR Configuration Change List Event data Flags values */ -#define MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG (0x00000001) - - -/* SAS Discovery Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_DISCOVERY -{ - U8 Flags; /* 0x00 */ - U8 ReasonCode; /* 0x01 */ - U8 PhysicalPort; /* 0x02 */ - U8 Reserved1; /* 0x03 */ - U32 DiscoveryStatus; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_DISCOVERY, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_DISCOVERY, - Mpi2EventDataSasDiscovery_t, MPI2_POINTER pMpi2EventDataSasDiscovery_t; - -/* SAS Discovery Event data Flags values */ -#define MPI2_EVENT_SAS_DISC_DEVICE_CHANGE (0x02) -#define MPI2_EVENT_SAS_DISC_IN_PROGRESS (0x01) - -/* SAS Discovery Event data ReasonCode values */ -#define MPI2_EVENT_SAS_DISC_RC_STARTED (0x01) -#define MPI2_EVENT_SAS_DISC_RC_COMPLETED (0x02) - -/* SAS Discovery Event data DiscoveryStatus values */ -#define MPI2_EVENT_SAS_DISC_DS_MAX_ENCLOSURES_EXCEED (0x80000000) -#define MPI2_EVENT_SAS_DISC_DS_MAX_EXPANDERS_EXCEED (0x40000000) -#define MPI2_EVENT_SAS_DISC_DS_MAX_DEVICES_EXCEED (0x20000000) -#define MPI2_EVENT_SAS_DISC_DS_MAX_TOPO_PHYS_EXCEED (0x10000000) -#define MPI2_EVENT_SAS_DISC_DS_DOWNSTREAM_INITIATOR (0x08000000) -#define MPI2_EVENT_SAS_DISC_DS_MULTI_SUBTRACTIVE_SUBTRACTIVE (0x00008000) -#define MPI2_EVENT_SAS_DISC_DS_EXP_MULTI_SUBTRACTIVE (0x00004000) -#define MPI2_EVENT_SAS_DISC_DS_MULTI_PORT_DOMAIN (0x00002000) -#define MPI2_EVENT_SAS_DISC_DS_TABLE_TO_SUBTRACTIVE_LINK (0x00001000) -#define MPI2_EVENT_SAS_DISC_DS_UNSUPPORTED_DEVICE (0x00000800) -#define MPI2_EVENT_SAS_DISC_DS_TABLE_LINK (0x00000400) -#define MPI2_EVENT_SAS_DISC_DS_SUBTRACTIVE_LINK (0x00000200) -#define MPI2_EVENT_SAS_DISC_DS_SMP_CRC_ERROR (0x00000100) -#define MPI2_EVENT_SAS_DISC_DS_SMP_FUNCTION_FAILED (0x00000080) -#define MPI2_EVENT_SAS_DISC_DS_INDEX_NOT_EXIST (0x00000040) -#define MPI2_EVENT_SAS_DISC_DS_OUT_ROUTE_ENTRIES (0x00000020) -#define MPI2_EVENT_SAS_DISC_DS_SMP_TIMEOUT (0x00000010) -#define MPI2_EVENT_SAS_DISC_DS_MULTIPLE_PORTS (0x00000004) -#define MPI2_EVENT_SAS_DISC_DS_UNADDRESSABLE_DEVICE (0x00000002) -#define MPI2_EVENT_SAS_DISC_DS_LOOP_DETECTED (0x00000001) - - -/* SAS Broadcast Primitive Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE -{ - U8 PhyNum; /* 0x00 */ - U8 Port; /* 0x01 */ - U8 PortWidth; /* 0x02 */ - U8 Primitive; /* 0x03 */ -} MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_BROADCAST_PRIMITIVE, - Mpi2EventDataSasBroadcastPrimitive_t, - MPI2_POINTER pMpi2EventDataSasBroadcastPrimitive_t; - -/* defines for the Primitive field */ -#define MPI2_EVENT_PRIMITIVE_CHANGE (0x01) -#define MPI2_EVENT_PRIMITIVE_SES (0x02) -#define MPI2_EVENT_PRIMITIVE_EXPANDER (0x03) -#define MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT (0x04) -#define MPI2_EVENT_PRIMITIVE_RESERVED3 (0x05) -#define MPI2_EVENT_PRIMITIVE_RESERVED4 (0x06) -#define MPI2_EVENT_PRIMITIVE_CHANGE0_RESERVED (0x07) -#define MPI2_EVENT_PRIMITIVE_CHANGE1_RESERVED (0x08) - -/* SAS Notify Primitive Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE { - U8 PhyNum; /* 0x00 */ - U8 Port; /* 0x01 */ - U8 Reserved1; /* 0x02 */ - U8 Primitive; /* 0x03 */ -} MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_NOTIFY_PRIMITIVE, -Mpi2EventDataSasNotifyPrimitive_t, -MPI2_POINTER pMpi2EventDataSasNotifyPrimitive_t; - -/* defines for the Primitive field */ -#define MPI2_EVENT_NOTIFY_ENABLE_SPINUP (0x01) -#define MPI2_EVENT_NOTIFY_POWER_LOSS_EXPECTED (0x02) -#define MPI2_EVENT_NOTIFY_RESERVED1 (0x03) -#define MPI2_EVENT_NOTIFY_RESERVED2 (0x04) - - -/* SAS Initiator Device Status Change Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE -{ - U8 ReasonCode; /* 0x00 */ - U8 PhysicalPort; /* 0x01 */ - U16 DevHandle; /* 0x02 */ - U64 SASAddress; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_DEV_STATUS_CHANGE, - Mpi2EventDataSasInitDevStatusChange_t, - MPI2_POINTER pMpi2EventDataSasInitDevStatusChange_t; - -/* SAS Initiator Device Status Change event ReasonCode values */ -#define MPI2_EVENT_SAS_INIT_RC_ADDED (0x01) -#define MPI2_EVENT_SAS_INIT_RC_NOT_RESPONDING (0x02) - - -/* SAS Initiator Device Table Overflow Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW -{ - U16 MaxInit; /* 0x00 */ - U16 CurrentInit; /* 0x02 */ - U64 SASAddress; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW, - Mpi2EventDataSasInitTableOverflow_t, - MPI2_POINTER pMpi2EventDataSasInitTableOverflow_t; - - -/* SAS Topology Change List Event data */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumEntries at runtime. - */ -#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT -#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) -#endif - -typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY -{ - U16 AttachedDevHandle; /* 0x00 */ - U8 LinkRate; /* 0x02 */ - U8 PhyStatus; /* 0x03 */ -} MPI2_EVENT_SAS_TOPO_PHY_ENTRY, MPI2_POINTER PTR_MPI2_EVENT_SAS_TOPO_PHY_ENTRY, - Mpi2EventSasTopoPhyEntry_t, MPI2_POINTER pMpi2EventSasTopoPhyEntry_t; - -typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST -{ - U16 EnclosureHandle; /* 0x00 */ - U16 ExpanderDevHandle; /* 0x02 */ - U8 NumPhys; /* 0x04 */ - U8 Reserved1; /* 0x05 */ - U16 Reserved2; /* 0x06 */ - U8 NumEntries; /* 0x08 */ - U8 StartPhyNum; /* 0x09 */ - U8 ExpStatus; /* 0x0A */ - U8 PhysicalPort; /* 0x0B */ - MPI2_EVENT_SAS_TOPO_PHY_ENTRY PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /* 0x0C*/ -} MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, - Mpi2EventDataSasTopologyChangeList_t, - MPI2_POINTER pMpi2EventDataSasTopologyChangeList_t; - -/* values for the ExpStatus field */ -#define MPI2_EVENT_SAS_TOPO_ES_NO_EXPANDER (0x00) -#define MPI2_EVENT_SAS_TOPO_ES_ADDED (0x01) -#define MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING (0x02) -#define MPI2_EVENT_SAS_TOPO_ES_RESPONDING (0x03) -#define MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING (0x04) - -/* defines for the LinkRate field */ -#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_MASK (0xF0) -#define MPI2_EVENT_SAS_TOPO_LR_CURRENT_SHIFT (4) -#define MPI2_EVENT_SAS_TOPO_LR_PREV_MASK (0x0F) -#define MPI2_EVENT_SAS_TOPO_LR_PREV_SHIFT (0) - -#define MPI2_EVENT_SAS_TOPO_LR_UNKNOWN_LINK_RATE (0x00) -#define MPI2_EVENT_SAS_TOPO_LR_PHY_DISABLED (0x01) -#define MPI2_EVENT_SAS_TOPO_LR_NEGOTIATION_FAILED (0x02) -#define MPI2_EVENT_SAS_TOPO_LR_SATA_OOB_COMPLETE (0x03) -#define MPI2_EVENT_SAS_TOPO_LR_PORT_SELECTOR (0x04) -#define MPI2_EVENT_SAS_TOPO_LR_SMP_RESET_IN_PROGRESS (0x05) -#define MPI2_EVENT_SAS_TOPO_LR_UNSUPPORTED_PHY (0x06) -#define MPI2_EVENT_SAS_TOPO_LR_RATE_1_5 (0x08) -#define MPI2_EVENT_SAS_TOPO_LR_RATE_3_0 (0x09) -#define MPI2_EVENT_SAS_TOPO_LR_RATE_6_0 (0x0A) - -/* values for the PhyStatus field */ -#define MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT (0x80) -#define MPI2_EVENT_SAS_TOPO_PS_MULTIPLEX_CHANGE (0x10) -/* values for the PhyStatus ReasonCode sub-field */ -#define MPI2_EVENT_SAS_TOPO_RC_MASK (0x0F) -#define MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED (0x01) -#define MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING (0x02) -#define MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED (0x03) -#define MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE (0x04) -#define MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING (0x05) - - -/* SAS Enclosure Device Status Change Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE -{ - U16 EnclosureHandle; /* 0x00 */ - U8 ReasonCode; /* 0x02 */ - U8 PhysicalPort; /* 0x03 */ - U64 EnclosureLogicalID; /* 0x04 */ - U16 NumSlots; /* 0x0C */ - U16 StartSlot; /* 0x0E */ - U32 PhyBits; /* 0x10 */ -} MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_ENCL_DEV_STATUS_CHANGE, - Mpi2EventDataSasEnclDevStatusChange_t, - MPI2_POINTER pMpi2EventDataSasEnclDevStatusChange_t; - -/* SAS Enclosure Device Status Change event ReasonCode values */ -#define MPI2_EVENT_SAS_ENCL_RC_ADDED (0x01) -#define MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING (0x02) - - -/* SAS PHY Counter Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_PHY_COUNTER { - U64 TimeStamp; /* 0x00 */ - U32 Reserved1; /* 0x08 */ - U8 PhyEventCode; /* 0x0C */ - U8 PhyNum; /* 0x0D */ - U16 Reserved2; /* 0x0E */ - U32 PhyEventInfo; /* 0x10 */ - U8 CounterType; /* 0x14 */ - U8 ThresholdWindow; /* 0x15 */ - U8 TimeUnits; /* 0x16 */ - U8 Reserved3; /* 0x17 */ - U32 EventThreshold; /* 0x18 */ - U16 ThresholdFlags; /* 0x1C */ - U16 Reserved4; /* 0x1E */ -} MPI2_EVENT_DATA_SAS_PHY_COUNTER, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_PHY_COUNTER, - Mpi2EventDataSasPhyCounter_t, MPI2_POINTER pMpi2EventDataSasPhyCounter_t; - -/* use MPI2_SASPHY3_EVENT_CODE_ values from mpi2_cnfg.h for the - * PhyEventCode field - * use MPI2_SASPHY3_COUNTER_TYPE_ values from mpi2_cnfg.h for the - * CounterType field - * use MPI2_SASPHY3_TIME_UNITS_ values from mpi2_cnfg.h for the - * TimeUnits field - * use MPI2_SASPHY3_TFLAGS_ values from mpi2_cnfg.h for the - * ThresholdFlags field - * */ - - -/* SAS Quiesce Event data */ - -typedef struct _MPI2_EVENT_DATA_SAS_QUIESCE { - U8 ReasonCode; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ -} MPI2_EVENT_DATA_SAS_QUIESCE, - MPI2_POINTER PTR_MPI2_EVENT_DATA_SAS_QUIESCE, - Mpi2EventDataSasQuiesce_t, MPI2_POINTER pMpi2EventDataSasQuiesce_t; - -/* SAS Quiesce Event data ReasonCode values */ -#define MPI2_EVENT_SAS_QUIESCE_RC_STARTED (0x01) -#define MPI2_EVENT_SAS_QUIESCE_RC_COMPLETED (0x02) - - -/* Host Based Discovery Phy Event data */ - -typedef struct _MPI2_EVENT_HBD_PHY_SAS { - U8 Flags; /* 0x00 */ - U8 NegotiatedLinkRate; /* 0x01 */ - U8 PhyNum; /* 0x02 */ - U8 PhysicalPort; /* 0x03 */ - U32 Reserved1; /* 0x04 */ - U8 InitialFrame[28]; /* 0x08 */ -} MPI2_EVENT_HBD_PHY_SAS, MPI2_POINTER PTR_MPI2_EVENT_HBD_PHY_SAS, - Mpi2EventHbdPhySas_t, MPI2_POINTER pMpi2EventHbdPhySas_t; - -/* values for the Flags field */ -#define MPI2_EVENT_HBD_SAS_FLAGS_FRAME_VALID (0x02) -#define MPI2_EVENT_HBD_SAS_FLAGS_SATA_FRAME (0x01) - -/* use MPI2_SAS_NEG_LINK_RATE_ defines from mpi2_cnfg.h for - * the NegotiatedLinkRate field */ - -typedef union _MPI2_EVENT_HBD_DESCRIPTOR { - MPI2_EVENT_HBD_PHY_SAS Sas; -} MPI2_EVENT_HBD_DESCRIPTOR, MPI2_POINTER PTR_MPI2_EVENT_HBD_DESCRIPTOR, - Mpi2EventHbdDescriptor_t, MPI2_POINTER pMpi2EventHbdDescriptor_t; - -typedef struct _MPI2_EVENT_DATA_HBD_PHY { - U8 DescriptorType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Reserved3; /* 0x04 */ - MPI2_EVENT_HBD_DESCRIPTOR Descriptor; /* 0x08 */ -} MPI2_EVENT_DATA_HBD_PHY, MPI2_POINTER PTR_MPI2_EVENT_DATA_HBD_PHY, - Mpi2EventDataHbdPhy_t, MPI2_POINTER pMpi2EventDataMpi2EventDataHbdPhy_t; - -/* values for the DescriptorType field */ -#define MPI2_EVENT_HBD_DT_SAS (0x01) - - - -/**************************************************************************** -* EventAck message -****************************************************************************/ - -/* EventAck Request message */ -typedef struct _MPI2_EVENT_ACK_REQUEST -{ - U16 Reserved1; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Event; /* 0x0C */ - U16 Reserved5; /* 0x0E */ - U32 EventContext; /* 0x10 */ -} MPI2_EVENT_ACK_REQUEST, MPI2_POINTER PTR_MPI2_EVENT_ACK_REQUEST, - Mpi2EventAckRequest_t, MPI2_POINTER pMpi2EventAckRequest_t; - - -/* EventAck Reply message */ -typedef struct _MPI2_EVENT_ACK_REPLY -{ - U16 Reserved1; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_EVENT_ACK_REPLY, MPI2_POINTER PTR_MPI2_EVENT_ACK_REPLY, - Mpi2EventAckReply_t, MPI2_POINTER pMpi2EventAckReply_t; - - -/**************************************************************************** -* SendHostMessage message -****************************************************************************/ - -/* SendHostMessage Request message */ -typedef struct _MPI2_SEND_HOST_MESSAGE_REQUEST { - U16 HostDataLength; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U8 Reserved4; /* 0x0C */ - U8 DestVF_ID; /* 0x0D */ - U16 Reserved5; /* 0x0E */ - U32 Reserved6; /* 0x10 */ - U32 Reserved7; /* 0x14 */ - U32 Reserved8; /* 0x18 */ - U32 Reserved9; /* 0x1C */ - U32 Reserved10; /* 0x20 */ - U32 HostData[1]; /* 0x24 */ -} MPI2_SEND_HOST_MESSAGE_REQUEST, -MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REQUEST, -Mpi2SendHostMessageRequest_t, MPI2_POINTER pMpi2SendHostMessageRequest_t; - - -/* SendHostMessage Reply message */ -typedef struct _MPI2_SEND_HOST_MESSAGE_REPLY { - U16 HostDataLength; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved1; /* 0x04 */ - U8 Reserved2; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U16 Reserved4; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_SEND_HOST_MESSAGE_REPLY, MPI2_POINTER PTR_MPI2_SEND_HOST_MESSAGE_REPLY, -Mpi2SendHostMessageReply_t, MPI2_POINTER pMpi2SendHostMessageReply_t; - - -/**************************************************************************** -* FWDownload message -****************************************************************************/ - -/* FWDownload Request message */ -typedef struct _MPI2_FW_DOWNLOAD_REQUEST -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 TotalImageSize; /* 0x0C */ - U32 Reserved5; /* 0x10 */ - MPI2_MPI_SGE_UNION SGL; /* 0x14 */ -} MPI2_FW_DOWNLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REQUEST, - Mpi2FWDownloadRequest, MPI2_POINTER pMpi2FWDownloadRequest; - -#define MPI2_FW_DOWNLOAD_MSGFLGS_LAST_SEGMENT (0x01) - -#define MPI2_FW_DOWNLOAD_ITYPE_FW (0x01) -#define MPI2_FW_DOWNLOAD_ITYPE_BIOS (0x02) -#define MPI2_FW_DOWNLOAD_ITYPE_MANUFACTURING (0x06) -#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_1 (0x07) -#define MPI2_FW_DOWNLOAD_ITYPE_CONFIG_2 (0x08) -#define MPI2_FW_DOWNLOAD_ITYPE_MEGARAID (0x09) -#define MPI2_FW_DOWNLOAD_ITYPE_COMPLETE (0x0A) -#define MPI2_FW_DOWNLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) -#define MPI2_FW_DOWNLOAD_ITYPE_MIN_PRODUCT_SPECIFIC (0xF0) - -/* FWDownload TransactionContext Element */ -typedef struct _MPI2_FW_DOWNLOAD_TCSGE -{ - U8 Reserved1; /* 0x00 */ - U8 ContextSize; /* 0x01 */ - U8 DetailsLength; /* 0x02 */ - U8 Flags; /* 0x03 */ - U32 Reserved2; /* 0x04 */ - U32 ImageOffset; /* 0x08 */ - U32 ImageSize; /* 0x0C */ -} MPI2_FW_DOWNLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_TCSGE, - Mpi2FWDownloadTCSGE_t, MPI2_POINTER pMpi2FWDownloadTCSGE_t; - -/* FWDownload Reply message */ -typedef struct _MPI2_FW_DOWNLOAD_REPLY -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_FW_DOWNLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_DOWNLOAD_REPLY, - Mpi2FWDownloadReply_t, MPI2_POINTER pMpi2FWDownloadReply_t; - - -/**************************************************************************** -* FWUpload message -****************************************************************************/ - -/* FWUpload Request message */ -typedef struct _MPI2_FW_UPLOAD_REQUEST -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 Reserved5; /* 0x0C */ - U32 Reserved6; /* 0x10 */ - MPI2_MPI_SGE_UNION SGL; /* 0x14 */ -} MPI2_FW_UPLOAD_REQUEST, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REQUEST, - Mpi2FWUploadRequest_t, MPI2_POINTER pMpi2FWUploadRequest_t; - -#define MPI2_FW_UPLOAD_ITYPE_FW_CURRENT (0x00) -#define MPI2_FW_UPLOAD_ITYPE_FW_FLASH (0x01) -#define MPI2_FW_UPLOAD_ITYPE_BIOS_FLASH (0x02) -#define MPI2_FW_UPLOAD_ITYPE_FW_BACKUP (0x05) -#define MPI2_FW_UPLOAD_ITYPE_MANUFACTURING (0x06) -#define MPI2_FW_UPLOAD_ITYPE_CONFIG_1 (0x07) -#define MPI2_FW_UPLOAD_ITYPE_CONFIG_2 (0x08) -#define MPI2_FW_UPLOAD_ITYPE_MEGARAID (0x09) -#define MPI2_FW_UPLOAD_ITYPE_COMPLETE (0x0A) -#define MPI2_FW_UPLOAD_ITYPE_COMMON_BOOT_BLOCK (0x0B) - -typedef struct _MPI2_FW_UPLOAD_TCSGE -{ - U8 Reserved1; /* 0x00 */ - U8 ContextSize; /* 0x01 */ - U8 DetailsLength; /* 0x02 */ - U8 Flags; /* 0x03 */ - U32 Reserved2; /* 0x04 */ - U32 ImageOffset; /* 0x08 */ - U32 ImageSize; /* 0x0C */ -} MPI2_FW_UPLOAD_TCSGE, MPI2_POINTER PTR_MPI2_FW_UPLOAD_TCSGE, - Mpi2FWUploadTCSGE_t, MPI2_POINTER pMpi2FWUploadTCSGE_t; - -/* FWUpload Reply message */ -typedef struct _MPI2_FW_UPLOAD_REPLY -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 ActualImageSize; /* 0x14 */ -} MPI2_FW_UPLOAD_REPLY, MPI2_POINTER PTR_MPI2_FW_UPLOAD_REPLY, - Mpi2FWUploadReply_t, MPI2_POINTER pMPi2FWUploadReply_t; - - -/* FW Image Header */ -typedef struct _MPI2_FW_IMAGE_HEADER -{ - U32 Signature; /* 0x00 */ - U32 Signature0; /* 0x04 */ - U32 Signature1; /* 0x08 */ - U32 Signature2; /* 0x0C */ - MPI2_VERSION_UNION MPIVersion; /* 0x10 */ - MPI2_VERSION_UNION FWVersion; /* 0x14 */ - MPI2_VERSION_UNION NVDATAVersion; /* 0x18 */ - MPI2_VERSION_UNION PackageVersion; /* 0x1C */ - U16 VendorID; /* 0x20 */ - U16 ProductID; /* 0x22 */ - U16 ProtocolFlags; /* 0x24 */ - U16 Reserved26; /* 0x26 */ - U32 IOCCapabilities; /* 0x28 */ - U32 ImageSize; /* 0x2C */ - U32 NextImageHeaderOffset; /* 0x30 */ - U32 Checksum; /* 0x34 */ - U32 Reserved38; /* 0x38 */ - U32 Reserved3C; /* 0x3C */ - U32 Reserved40; /* 0x40 */ - U32 Reserved44; /* 0x44 */ - U32 Reserved48; /* 0x48 */ - U32 Reserved4C; /* 0x4C */ - U32 Reserved50; /* 0x50 */ - U32 Reserved54; /* 0x54 */ - U32 Reserved58; /* 0x58 */ - U32 Reserved5C; /* 0x5C */ - U32 Reserved60; /* 0x60 */ - U32 FirmwareVersionNameWhat; /* 0x64 */ - U8 FirmwareVersionName[32]; /* 0x68 */ - U32 VendorNameWhat; /* 0x88 */ - U8 VendorName[32]; /* 0x8C */ - U32 PackageNameWhat; /* 0x88 */ - U8 PackageName[32]; /* 0x8C */ - U32 ReservedD0; /* 0xD0 */ - U32 ReservedD4; /* 0xD4 */ - U32 ReservedD8; /* 0xD8 */ - U32 ReservedDC; /* 0xDC */ - U32 ReservedE0; /* 0xE0 */ - U32 ReservedE4; /* 0xE4 */ - U32 ReservedE8; /* 0xE8 */ - U32 ReservedEC; /* 0xEC */ - U32 ReservedF0; /* 0xF0 */ - U32 ReservedF4; /* 0xF4 */ - U32 ReservedF8; /* 0xF8 */ - U32 ReservedFC; /* 0xFC */ -} MPI2_FW_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_FW_IMAGE_HEADER, - Mpi2FWImageHeader_t, MPI2_POINTER pMpi2FWImageHeader_t; - -/* Signature field */ -#define MPI2_FW_HEADER_SIGNATURE_OFFSET (0x00) -#define MPI2_FW_HEADER_SIGNATURE_MASK (0xFF000000) -#define MPI2_FW_HEADER_SIGNATURE (0xEA000000) - -/* Signature0 field */ -#define MPI2_FW_HEADER_SIGNATURE0_OFFSET (0x04) -#define MPI2_FW_HEADER_SIGNATURE0 (0x5AFAA55A) - -/* Signature1 field */ -#define MPI2_FW_HEADER_SIGNATURE1_OFFSET (0x08) -#define MPI2_FW_HEADER_SIGNATURE1 (0xA55AFAA5) - -/* Signature2 field */ -#define MPI2_FW_HEADER_SIGNATURE2_OFFSET (0x0C) -#define MPI2_FW_HEADER_SIGNATURE2 (0x5AA55AFA) - - -/* defines for using the ProductID field */ -#define MPI2_FW_HEADER_PID_TYPE_MASK (0xF000) -#define MPI2_FW_HEADER_PID_TYPE_SAS (0x2000) - -#define MPI2_FW_HEADER_PID_PROD_MASK (0x0F00) -#define MPI2_FW_HEADER_PID_PROD_A (0x0000) -#define MPI2_FW_HEADER_PID_PROD_TARGET_INITIATOR_SCSI (0x0200) -#define MPI2_FW_HEADER_PID_PROD_IR_SCSI (0x0700) - - -#define MPI2_FW_HEADER_PID_FAMILY_MASK (0x00FF) -/* SAS */ -#define MPI2_FW_HEADER_PID_FAMILY_2108_SAS (0x0013) -#define MPI2_FW_HEADER_PID_FAMILY_2208_SAS (0x0014) - -/* use MPI2_IOCFACTS_PROTOCOL_ defines for ProtocolFlags field */ - -/* use MPI2_IOCFACTS_CAPABILITY_ defines for IOCCapabilities field */ - - -#define MPI2_FW_HEADER_IMAGESIZE_OFFSET (0x2C) -#define MPI2_FW_HEADER_NEXTIMAGE_OFFSET (0x30) -#define MPI2_FW_HEADER_VERNMHWAT_OFFSET (0x64) - -#define MPI2_FW_HEADER_WHAT_SIGNATURE (0x29232840) - -#define MPI2_FW_HEADER_SIZE (0x100) - - -/* Extended Image Header */ -typedef struct _MPI2_EXT_IMAGE_HEADER - -{ - U8 ImageType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 Checksum; /* 0x04 */ - U32 ImageSize; /* 0x08 */ - U32 NextImageHeaderOffset; /* 0x0C */ - U32 PackageVersion; /* 0x10 */ - U32 Reserved3; /* 0x14 */ - U32 Reserved4; /* 0x18 */ - U32 Reserved5; /* 0x1C */ - U8 IdentifyString[32]; /* 0x20 */ -} MPI2_EXT_IMAGE_HEADER, MPI2_POINTER PTR_MPI2_EXT_IMAGE_HEADER, - Mpi2ExtImageHeader_t, MPI2_POINTER pMpi2ExtImageHeader_t; - -/* useful offsets */ -#define MPI2_EXT_IMAGE_IMAGETYPE_OFFSET (0x00) -#define MPI2_EXT_IMAGE_IMAGESIZE_OFFSET (0x08) -#define MPI2_EXT_IMAGE_NEXTIMAGE_OFFSET (0x0C) - -#define MPI2_EXT_IMAGE_HEADER_SIZE (0x40) - -/* defines for the ImageType field */ -#define MPI2_EXT_IMAGE_TYPE_UNSPECIFIED (0x00) -#define MPI2_EXT_IMAGE_TYPE_FW (0x01) -#define MPI2_EXT_IMAGE_TYPE_NVDATA (0x03) -#define MPI2_EXT_IMAGE_TYPE_BOOTLOADER (0x04) -#define MPI2_EXT_IMAGE_TYPE_INITIALIZATION (0x05) -#define MPI2_EXT_IMAGE_TYPE_FLASH_LAYOUT (0x06) -#define MPI2_EXT_IMAGE_TYPE_SUPPORTED_DEVICES (0x07) -#define MPI2_EXT_IMAGE_TYPE_MEGARAID (0x08) -#define MPI2_EXT_IMAGE_TYPE_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC (0xFF) -#define MPI2_EXT_IMAGE_TYPE_MAX \ - (MPI2_EXT_IMAGE_TYPE_MAX_PRODUCT_SPECIFIC) /* deprecated */ - - - -/* FLASH Layout Extended Image Data */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check RegionsPerLayout at runtime. - */ -#ifndef MPI2_FLASH_NUMBER_OF_REGIONS -#define MPI2_FLASH_NUMBER_OF_REGIONS (1) -#endif - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumberOfLayouts at runtime. - */ -#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS -#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) -#endif - -typedef struct _MPI2_FLASH_REGION -{ - U8 RegionType; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 RegionOffset; /* 0x04 */ - U32 RegionSize; /* 0x08 */ - U32 Reserved3; /* 0x0C */ -} MPI2_FLASH_REGION, MPI2_POINTER PTR_MPI2_FLASH_REGION, - Mpi2FlashRegion_t, MPI2_POINTER pMpi2FlashRegion_t; - -typedef struct _MPI2_FLASH_LAYOUT -{ - U32 FlashSize; /* 0x00 */ - U32 Reserved1; /* 0x04 */ - U32 Reserved2; /* 0x08 */ - U32 Reserved3; /* 0x0C */ - MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS];/* 0x10 */ -} MPI2_FLASH_LAYOUT, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT, - Mpi2FlashLayout_t, MPI2_POINTER pMpi2FlashLayout_t; - -typedef struct _MPI2_FLASH_LAYOUT_DATA -{ - U8 ImageRevision; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 SizeOfRegion; /* 0x02 */ - U8 Reserved2; /* 0x03 */ - U16 NumberOfLayouts; /* 0x04 */ - U16 RegionsPerLayout; /* 0x06 */ - U16 MinimumSectorAlignment; /* 0x08 */ - U16 Reserved3; /* 0x0A */ - U32 Reserved4; /* 0x0C */ - MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS];/* 0x10 */ -} MPI2_FLASH_LAYOUT_DATA, MPI2_POINTER PTR_MPI2_FLASH_LAYOUT_DATA, - Mpi2FlashLayoutData_t, MPI2_POINTER pMpi2FlashLayoutData_t; - -/* defines for the RegionType field */ -#define MPI2_FLASH_REGION_UNUSED (0x00) -#define MPI2_FLASH_REGION_FIRMWARE (0x01) -#define MPI2_FLASH_REGION_BIOS (0x02) -#define MPI2_FLASH_REGION_NVDATA (0x03) -#define MPI2_FLASH_REGION_FIRMWARE_BACKUP (0x05) -#define MPI2_FLASH_REGION_MFG_INFORMATION (0x06) -#define MPI2_FLASH_REGION_CONFIG_1 (0x07) -#define MPI2_FLASH_REGION_CONFIG_2 (0x08) -#define MPI2_FLASH_REGION_MEGARAID (0x09) -#define MPI2_FLASH_REGION_INIT (0x0A) - -/* ImageRevision */ -#define MPI2_FLASH_LAYOUT_IMAGE_REVISION (0x00) - - - -/* Supported Devices Extended Image Data */ - -/* - * Host code (drivers, BIOS, utilities, etc.) should leave this define set to - * one and check NumberOfDevices at runtime. - */ -#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES -#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) -#endif - -typedef struct _MPI2_SUPPORTED_DEVICE -{ - U16 DeviceID; /* 0x00 */ - U16 VendorID; /* 0x02 */ - U16 DeviceIDMask; /* 0x04 */ - U16 Reserved1; /* 0x06 */ - U8 LowPCIRev; /* 0x08 */ - U8 HighPCIRev; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 Reserved3; /* 0x0C */ -} MPI2_SUPPORTED_DEVICE, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICE, - Mpi2SupportedDevice_t, MPI2_POINTER pMpi2SupportedDevice_t; - -typedef struct _MPI2_SUPPORTED_DEVICES_DATA -{ - U8 ImageRevision; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 NumberOfDevices; /* 0x02 */ - U8 Reserved2; /* 0x03 */ - U32 Reserved3; /* 0x04 */ - MPI2_SUPPORTED_DEVICE SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES]; /* 0x08 */ -} MPI2_SUPPORTED_DEVICES_DATA, MPI2_POINTER PTR_MPI2_SUPPORTED_DEVICES_DATA, - Mpi2SupportedDevicesData_t, MPI2_POINTER pMpi2SupportedDevicesData_t; - -/* ImageRevision */ -#define MPI2_SUPPORTED_DEVICES_IMAGE_REVISION (0x00) - - -/* Init Extended Image Data */ - -typedef struct _MPI2_INIT_IMAGE_FOOTER - -{ - U32 BootFlags; /* 0x00 */ - U32 ImageSize; /* 0x04 */ - U32 Signature0; /* 0x08 */ - U32 Signature1; /* 0x0C */ - U32 Signature2; /* 0x10 */ - U32 ResetVector; /* 0x14 */ -} MPI2_INIT_IMAGE_FOOTER, MPI2_POINTER PTR_MPI2_INIT_IMAGE_FOOTER, - Mpi2InitImageFooter_t, MPI2_POINTER pMpi2InitImageFooter_t; - -/* defines for the BootFlags field */ -#define MPI2_INIT_IMAGE_BOOTFLAGS_OFFSET (0x00) - -/* defines for the ImageSize field */ -#define MPI2_INIT_IMAGE_IMAGESIZE_OFFSET (0x04) - -/* defines for the Signature0 field */ -#define MPI2_INIT_IMAGE_SIGNATURE0_OFFSET (0x08) -#define MPI2_INIT_IMAGE_SIGNATURE0 (0x5AA55AEA) - -/* defines for the Signature1 field */ -#define MPI2_INIT_IMAGE_SIGNATURE1_OFFSET (0x0C) -#define MPI2_INIT_IMAGE_SIGNATURE1 (0xA55AEAA5) - -/* defines for the Signature2 field */ -#define MPI2_INIT_IMAGE_SIGNATURE2_OFFSET (0x10) -#define MPI2_INIT_IMAGE_SIGNATURE2 (0x5AEAA55A) - -/* Signature fields as individual bytes */ -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_0 (0xEA) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_1 (0x5A) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_2 (0xA5) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_3 (0x5A) - -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_4 (0xA5) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_5 (0xEA) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_6 (0x5A) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_7 (0xA5) - -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_8 (0x5A) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_9 (0xA5) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_A (0xEA) -#define MPI2_INIT_IMAGE_SIGNATURE_BYTE_B (0x5A) - -/* defines for the ResetVector field */ -#define MPI2_INIT_IMAGE_RESETVECTOR_OFFSET (0x14) - - -/**************************************************************************** -* PowerManagementControl message -****************************************************************************/ - -/* PowerManagementControl Request message */ -typedef struct _MPI2_PWR_MGMT_CONTROL_REQUEST { - U8 Feature; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 Parameter1; /* 0x0C */ - U8 Parameter2; /* 0x0D */ - U8 Parameter3; /* 0x0E */ - U8 Parameter4; /* 0x0F */ - U32 Reserved5; /* 0x10 */ - U32 Reserved6; /* 0x14 */ -} MPI2_PWR_MGMT_CONTROL_REQUEST, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REQUEST, - Mpi2PwrMgmtControlRequest_t, MPI2_POINTER pMpi2PwrMgmtControlRequest_t; - -/* defines for the Feature field */ -#define MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND (0x01) -#define MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION (0x02) -#define MPI2_PM_CONTROL_FEATURE_PCIE_LINK (0x03) /* obsolete */ -#define MPI2_PM_CONTROL_FEATURE_IOC_SPEED (0x04) -#define MPI2_PM_CONTROL_FEATURE_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_PM_CONTROL_FEATURE_MAX_PRODUCT_SPECIFIC (0xFF) - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_DA_PHY_POWER_COND Feature */ -/* Parameter1 contains a PHY number */ -/* Parameter2 indicates power condition action using these defines */ -#define MPI2_PM_CONTROL_PARAM2_PARTIAL (0x01) -#define MPI2_PM_CONTROL_PARAM2_SLUMBER (0x02) -#define MPI2_PM_CONTROL_PARAM2_EXIT_PWR_MGMT (0x03) -/* Parameter3 and Parameter4 are reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PORT_WIDTH_MODULATION - * Feature */ -/* Parameter1 contains SAS port width modulation group number */ -/* Parameter2 indicates IOC action using these defines */ -#define MPI2_PM_CONTROL_PARAM2_REQUEST_OWNERSHIP (0x01) -#define MPI2_PM_CONTROL_PARAM2_CHANGE_MODULATION (0x02) -#define MPI2_PM_CONTROL_PARAM2_RELINQUISH_OWNERSHIP (0x03) -/* Parameter3 indicates desired modulation level using these defines */ -#define MPI2_PM_CONTROL_PARAM3_25_PERCENT (0x00) -#define MPI2_PM_CONTROL_PARAM3_50_PERCENT (0x01) -#define MPI2_PM_CONTROL_PARAM3_75_PERCENT (0x02) -#define MPI2_PM_CONTROL_PARAM3_100_PERCENT (0x03) -/* Parameter4 is reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_PCIE_LINK Feature */ -/* Parameter1 indicates desired PCIe link speed using these defines */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_2_5_GBPS (0x00) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_5_0_GBPS (0x01) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM1_PCIE_8_0_GBPS (0x02) /* obsolete */ -/* Parameter2 indicates desired PCIe link width using these defines */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X1 (0x01) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X2 (0x02) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X4 (0x04) /* obsolete */ -#define MPI2_PM_CONTROL_PARAM2_WIDTH_X8 (0x08) /* obsolete */ -/* Parameter3 and Parameter4 are reserved */ - -/* parameter usage for the MPI2_PM_CONTROL_FEATURE_IOC_SPEED Feature */ -/* Parameter1 indicates desired IOC hardware clock speed using these defines */ -#define MPI2_PM_CONTROL_PARAM1_FULL_IOC_SPEED (0x01) -#define MPI2_PM_CONTROL_PARAM1_HALF_IOC_SPEED (0x02) -#define MPI2_PM_CONTROL_PARAM1_QUARTER_IOC_SPEED (0x04) -#define MPI2_PM_CONTROL_PARAM1_EIGHTH_IOC_SPEED (0x08) -/* Parameter2, Parameter3, and Parameter4 are reserved */ - - -/* PowerManagementControl Reply message */ -typedef struct _MPI2_PWR_MGMT_CONTROL_REPLY { - U8 Feature; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_PWR_MGMT_CONTROL_REPLY, MPI2_POINTER PTR_MPI2_PWR_MGMT_CONTROL_REPLY, - Mpi2PwrMgmtControlReply_t, MPI2_POINTER pMpi2PwrMgmtControlReply_t; - - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_raid.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_raid.h deleted file mode 100644 index 0601612b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_raid.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (c) 2000-2010 LSI Corporation. - * - * - * Name: mpi2_raid.h - * Title: MPI Integrated RAID messages and structures - * Creation Date: April 26, 2007 - * - * mpi2_raid.h Version: 02.00.06 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 08-31-07 02.00.01 Modifications to RAID Action request and reply, - * including the Actions and ActionData. - * 02-29-08 02.00.02 Added MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD. - * 05-21-08 02.00.03 Added MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS so that - * the PhysDisk array in MPI2_RAID_VOLUME_CREATION_STRUCT - * can be sized by the build environment. - * 07-30-09 02.00.04 Added proper define for the Use Default Settings bit of - * VolumeCreationFlags and marked the old one as obsolete. - * 05-12-10 02.00.05 Added MPI2_RAID_VOL_FLAGS_OP_MDC define. - * 08-24-10 02.00.06 Added MPI2_RAID_ACTION_COMPATIBILITY_CHECK along with - * related structures and defines. - * Added product-specific range to RAID Action values. - - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_RAID_H -#define MPI2_RAID_H - -/***************************************************************************** -* -* Integrated RAID Messages -* -*****************************************************************************/ - -/**************************************************************************** -* RAID Action messages -****************************************************************************/ - -/* ActionDataWord defines for use with MPI2_RAID_ACTION_DELETE_VOLUME action */ -#define MPI2_RAID_ACTION_ADATA_KEEP_LBA0 (0x00000000) -#define MPI2_RAID_ACTION_ADATA_ZERO_LBA0 (0x00000001) - -/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ - -/* ActionDataWord defines for use with MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES action */ -#define MPI2_RAID_ACTION_ADATA_DISABL_FULL_REBUILD (0x00000001) - -/* ActionDataWord for MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE Action */ -typedef struct _MPI2_RAID_ACTION_RATE_DATA -{ - U8 RateToChange; /* 0x00 */ - U8 RateOrMode; /* 0x01 */ - U16 DataScrubDuration; /* 0x02 */ -} MPI2_RAID_ACTION_RATE_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_RATE_DATA, - Mpi2RaidActionRateData_t, MPI2_POINTER pMpi2RaidActionRateData_t; - -#define MPI2_RAID_ACTION_SET_RATE_RESYNC (0x00) -#define MPI2_RAID_ACTION_SET_RATE_DATA_SCRUB (0x01) -#define MPI2_RAID_ACTION_SET_RATE_POWERSAVE_MODE (0x02) - -/* ActionDataWord for MPI2_RAID_ACTION_START_RAID_FUNCTION Action */ -typedef struct _MPI2_RAID_ACTION_START_RAID_FUNCTION -{ - U8 RAIDFunction; /* 0x00 */ - U8 Flags; /* 0x01 */ - U16 Reserved1; /* 0x02 */ -} MPI2_RAID_ACTION_START_RAID_FUNCTION, - MPI2_POINTER PTR_MPI2_RAID_ACTION_START_RAID_FUNCTION, - Mpi2RaidActionStartRaidFunction_t, - MPI2_POINTER pMpi2RaidActionStartRaidFunction_t; - -/* defines for the RAIDFunction field */ -#define MPI2_RAID_ACTION_START_BACKGROUND_INIT (0x00) -#define MPI2_RAID_ACTION_START_ONLINE_CAP_EXPANSION (0x01) -#define MPI2_RAID_ACTION_START_CONSISTENCY_CHECK (0x02) - -/* defines for the Flags field */ -#define MPI2_RAID_ACTION_START_NEW (0x00) -#define MPI2_RAID_ACTION_START_RESUME (0x01) - -/* ActionDataWord for MPI2_RAID_ACTION_STOP_RAID_FUNCTION Action */ -typedef struct _MPI2_RAID_ACTION_STOP_RAID_FUNCTION -{ - U8 RAIDFunction; /* 0x00 */ - U8 Flags; /* 0x01 */ - U16 Reserved1; /* 0x02 */ -} MPI2_RAID_ACTION_STOP_RAID_FUNCTION, - MPI2_POINTER PTR_MPI2_RAID_ACTION_STOP_RAID_FUNCTION, - Mpi2RaidActionStopRaidFunction_t, - MPI2_POINTER pMpi2RaidActionStopRaidFunction_t; - -/* defines for the RAIDFunction field */ -#define MPI2_RAID_ACTION_STOP_BACKGROUND_INIT (0x00) -#define MPI2_RAID_ACTION_STOP_ONLINE_CAP_EXPANSION (0x01) -#define MPI2_RAID_ACTION_STOP_CONSISTENCY_CHECK (0x02) - -/* defines for the Flags field */ -#define MPI2_RAID_ACTION_STOP_ABORT (0x00) -#define MPI2_RAID_ACTION_STOP_PAUSE (0x01) - -/* ActionDataWord for MPI2_RAID_ACTION_CREATE_HOT_SPARE Action */ -typedef struct _MPI2_RAID_ACTION_HOT_SPARE -{ - U8 HotSparePool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 DevHandle; /* 0x02 */ -} MPI2_RAID_ACTION_HOT_SPARE, MPI2_POINTER PTR_MPI2_RAID_ACTION_HOT_SPARE, - Mpi2RaidActionHotSpare_t, MPI2_POINTER pMpi2RaidActionHotSpare_t; - -/* ActionDataWord for MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE Action */ -typedef struct _MPI2_RAID_ACTION_FW_UPDATE_MODE -{ - U8 Flags; /* 0x00 */ - U8 DeviceFirmwareUpdateModeTimeout; /* 0x01 */ - U16 Reserved1; /* 0x02 */ -} MPI2_RAID_ACTION_FW_UPDATE_MODE, - MPI2_POINTER PTR_MPI2_RAID_ACTION_FW_UPDATE_MODE, - Mpi2RaidActionFwUpdateMode_t, MPI2_POINTER pMpi2RaidActionFwUpdateMode_t; - -/* ActionDataWord defines for use with MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE action */ -#define MPI2_RAID_ACTION_ADATA_DISABLE_FW_UPDATE (0x00) -#define MPI2_RAID_ACTION_ADATA_ENABLE_FW_UPDATE (0x01) - -typedef union _MPI2_RAID_ACTION_DATA -{ - U32 Word; - MPI2_RAID_ACTION_RATE_DATA Rates; - MPI2_RAID_ACTION_START_RAID_FUNCTION StartRaidFunction; - MPI2_RAID_ACTION_STOP_RAID_FUNCTION StopRaidFunction; - MPI2_RAID_ACTION_HOT_SPARE HotSpare; - MPI2_RAID_ACTION_FW_UPDATE_MODE FwUpdateMode; -} MPI2_RAID_ACTION_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_DATA, - Mpi2RaidActionData_t, MPI2_POINTER pMpi2RaidActionData_t; - - -/* RAID Action Request Message */ -typedef struct _MPI2_RAID_ACTION_REQUEST -{ - U8 Action; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 VolDevHandle; /* 0x04 */ - U8 PhysDiskNum; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U32 Reserved3; /* 0x0C */ - MPI2_RAID_ACTION_DATA ActionDataWord; /* 0x10 */ - MPI2_SGE_SIMPLE_UNION ActionDataSGE; /* 0x14 */ -} MPI2_RAID_ACTION_REQUEST, MPI2_POINTER PTR_MPI2_RAID_ACTION_REQUEST, - Mpi2RaidActionRequest_t, MPI2_POINTER pMpi2RaidActionRequest_t; - -/* RAID Action request Action values */ - -#define MPI2_RAID_ACTION_INDICATOR_STRUCT (0x01) -#define MPI2_RAID_ACTION_CREATE_VOLUME (0x02) -#define MPI2_RAID_ACTION_DELETE_VOLUME (0x03) -#define MPI2_RAID_ACTION_DISABLE_ALL_VOLUMES (0x04) -#define MPI2_RAID_ACTION_ENABLE_ALL_VOLUMES (0x05) -#define MPI2_RAID_ACTION_PHYSDISK_OFFLINE (0x0A) -#define MPI2_RAID_ACTION_PHYSDISK_ONLINE (0x0B) -#define MPI2_RAID_ACTION_FAIL_PHYSDISK (0x0F) -#define MPI2_RAID_ACTION_ACTIVATE_VOLUME (0x11) -#define MPI2_RAID_ACTION_DEVICE_FW_UPDATE_MODE (0x15) -#define MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE (0x17) -#define MPI2_RAID_ACTION_SET_VOLUME_NAME (0x18) -#define MPI2_RAID_ACTION_SET_RAID_FUNCTION_RATE (0x19) -#define MPI2_RAID_ACTION_ENABLE_FAILED_VOLUME (0x1C) -#define MPI2_RAID_ACTION_CREATE_HOT_SPARE (0x1D) -#define MPI2_RAID_ACTION_DELETE_HOT_SPARE (0x1E) -#define MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED (0x20) -#define MPI2_RAID_ACTION_START_RAID_FUNCTION (0x21) -#define MPI2_RAID_ACTION_STOP_RAID_FUNCTION (0x22) -#define MPI2_RAID_ACTION_COMPATIBILITY_CHECK (0x23) -#define MPI2_RAID_ACTION_MIN_PRODUCT_SPECIFIC (0x80) -#define MPI2_RAID_ACTION_MAX_PRODUCT_SPECIFIC (0xFF) - -/* RAID Volume Creation Structure */ - -/* - * The following define can be customized for the targeted product. - */ -#ifndef MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS -#define MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS (1) -#endif - -typedef struct _MPI2_RAID_VOLUME_PHYSDISK -{ - U8 RAIDSetNum; /* 0x00 */ - U8 PhysDiskMap; /* 0x01 */ - U16 PhysDiskDevHandle; /* 0x02 */ -} MPI2_RAID_VOLUME_PHYSDISK, MPI2_POINTER PTR_MPI2_RAID_VOLUME_PHYSDISK, - Mpi2RaidVolumePhysDisk_t, MPI2_POINTER pMpi2RaidVolumePhysDisk_t; - -/* defines for the PhysDiskMap field */ -#define MPI2_RAIDACTION_PHYSDISK_PRIMARY (0x01) -#define MPI2_RAIDACTION_PHYSDISK_SECONDARY (0x02) - -typedef struct _MPI2_RAID_VOLUME_CREATION_STRUCT -{ - U8 NumPhysDisks; /* 0x00 */ - U8 VolumeType; /* 0x01 */ - U16 Reserved1; /* 0x02 */ - U32 VolumeCreationFlags; /* 0x04 */ - U32 VolumeSettings; /* 0x08 */ - U8 Reserved2; /* 0x0C */ - U8 ResyncRate; /* 0x0D */ - U16 DataScrubDuration; /* 0x0E */ - U64 VolumeMaxLBA; /* 0x10 */ - U32 StripeSize; /* 0x18 */ - U8 Name[16]; /* 0x1C */ - MPI2_RAID_VOLUME_PHYSDISK PhysDisk[MPI2_RAID_VOL_CREATION_NUM_PHYSDISKS];/* 0x2C */ -} MPI2_RAID_VOLUME_CREATION_STRUCT, - MPI2_POINTER PTR_MPI2_RAID_VOLUME_CREATION_STRUCT, - Mpi2RaidVolumeCreationStruct_t, MPI2_POINTER pMpi2RaidVolumeCreationStruct_t; - -/* use MPI2_RAID_VOL_TYPE_ defines from mpi2_cnfg.h for VolumeType */ - -/* defines for the VolumeCreationFlags field */ -#define MPI2_RAID_VOL_CREATION_DEFAULT_SETTINGS (0x80000000) -#define MPI2_RAID_VOL_CREATION_BACKGROUND_INIT (0x00000004) -#define MPI2_RAID_VOL_CREATION_LOW_LEVEL_INIT (0x00000002) -#define MPI2_RAID_VOL_CREATION_MIGRATE_DATA (0x00000001) -/* The following is an obsolete define. - * It must be shifted left 24 bits in order to set the proper bit. - */ -#define MPI2_RAID_VOL_CREATION_USE_DEFAULT_SETTINGS (0x80) - - -/* RAID Online Capacity Expansion Structure */ - -typedef struct _MPI2_RAID_ONLINE_CAPACITY_EXPANSION -{ - U32 Flags; /* 0x00 */ - U16 DevHandle0; /* 0x04 */ - U16 Reserved1; /* 0x06 */ - U16 DevHandle1; /* 0x08 */ - U16 Reserved2; /* 0x0A */ -} MPI2_RAID_ONLINE_CAPACITY_EXPANSION, - MPI2_POINTER PTR_MPI2_RAID_ONLINE_CAPACITY_EXPANSION, - Mpi2RaidOnlineCapacityExpansion_t, - MPI2_POINTER pMpi2RaidOnlineCapacityExpansion_t; - -/* RAID Compatibility Input Structure */ - -typedef struct _MPI2_RAID_COMPATIBILITY_INPUT_STRUCT { - U16 SourceDevHandle; /* 0x00 */ - U16 CandidateDevHandle; /* 0x02 */ - U32 Flags; /* 0x04 */ - U32 Reserved1; /* 0x08 */ - U32 Reserved2; /* 0x0C */ -} MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_INPUT_STRUCT, -Mpi2RaidCompatibilityInputStruct_t, -MPI2_POINTER pMpi2RaidCompatibilityInputStruct_t; - -/* defines for RAID Compatibility Structure Flags field */ -#define MPI2_RAID_COMPAT_SOURCE_IS_VOLUME_FLAG (0x00000002) -#define MPI2_RAID_COMPAT_REPORT_SOURCE_INFO_FLAG (0x00000001) - - -/* RAID Volume Indicator Structure */ - -typedef struct _MPI2_RAID_VOL_INDICATOR -{ - U64 TotalBlocks; /* 0x00 */ - U64 BlocksRemaining; /* 0x08 */ - U32 Flags; /* 0x10 */ -} MPI2_RAID_VOL_INDICATOR, MPI2_POINTER PTR_MPI2_RAID_VOL_INDICATOR, - Mpi2RaidVolIndicator_t, MPI2_POINTER pMpi2RaidVolIndicator_t; - -/* defines for RAID Volume Indicator Flags field */ -#define MPI2_RAID_VOL_FLAGS_OP_MASK (0x0000000F) -#define MPI2_RAID_VOL_FLAGS_OP_BACKGROUND_INIT (0x00000000) -#define MPI2_RAID_VOL_FLAGS_OP_ONLINE_CAP_EXPANSION (0x00000001) -#define MPI2_RAID_VOL_FLAGS_OP_CONSISTENCY_CHECK (0x00000002) -#define MPI2_RAID_VOL_FLAGS_OP_RESYNC (0x00000003) -#define MPI2_RAID_VOL_FLAGS_OP_MDC (0x00000004) - -/* RAID Compatibility Result Structure */ - -typedef struct _MPI2_RAID_COMPATIBILITY_RESULT_STRUCT { - U8 State; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U16 Reserved2; /* 0x02 */ - U32 GenericAttributes; /* 0x04 */ - U32 OEMSpecificAttributes; /* 0x08 */ - U32 Reserved3; /* 0x0C */ - U32 Reserved4; /* 0x10 */ -} MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -MPI2_POINTER PTR_MPI2_RAID_COMPATIBILITY_RESULT_STRUCT, -Mpi2RaidCompatibilityResultStruct_t, -MPI2_POINTER pMpi2RaidCompatibilityResultStruct_t; - -/* defines for RAID Compatibility Result Structure State field */ -#define MPI2_RAID_COMPAT_STATE_COMPATIBLE (0x00) -#define MPI2_RAID_COMPAT_STATE_NOT_COMPATIBLE (0x01) - -/* defines for RAID Compatibility Result Structure GenericAttributes field */ -#define MPI2_RAID_COMPAT_GENATTRIB_4K_SECTOR (0x00000010) - -#define MPI2_RAID_COMPAT_GENATTRIB_MEDIA_MASK (0x0000000C) -#define MPI2_RAID_COMPAT_GENATTRIB_SOLID_STATE_DRIVE (0x00000008) -#define MPI2_RAID_COMPAT_GENATTRIB_HARD_DISK_DRIVE (0x00000004) - -#define MPI2_RAID_COMPAT_GENATTRIB_PROTOCOL_MASK (0x00000003) -#define MPI2_RAID_COMPAT_GENATTRIB_SAS_PROTOCOL (0x00000002) -#define MPI2_RAID_COMPAT_GENATTRIB_SATA_PROTOCOL (0x00000001) - -/* RAID Action Reply ActionData union */ -typedef union _MPI2_RAID_ACTION_REPLY_DATA -{ - U32 Word[5]; - MPI2_RAID_VOL_INDICATOR RaidVolumeIndicator; - U16 VolDevHandle; - U8 VolumeState; - U8 PhysDiskNum; - MPI2_RAID_COMPATIBILITY_RESULT_STRUCT RaidCompatibilityResult; -} MPI2_RAID_ACTION_REPLY_DATA, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY_DATA, - Mpi2RaidActionReplyData_t, MPI2_POINTER pMpi2RaidActionReplyData_t; - -/* use MPI2_RAIDVOL0_SETTING_ defines from mpi2_cnfg.h for MPI2_RAID_ACTION_CHANGE_VOL_WRITE_CACHE action */ - - -/* RAID Action Reply Message */ -typedef struct _MPI2_RAID_ACTION_REPLY -{ - U8 Action; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 VolDevHandle; /* 0x04 */ - U8 PhysDiskNum; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved2; /* 0x0A */ - U16 Reserved3; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - MPI2_RAID_ACTION_REPLY_DATA ActionData; /* 0x14 */ -} MPI2_RAID_ACTION_REPLY, MPI2_POINTER PTR_MPI2_RAID_ACTION_REPLY, - Mpi2RaidActionReply_t, MPI2_POINTER pMpi2RaidActionReply_t; - - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_sas.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_sas.h deleted file mode 100644 index fdffde1e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_sas.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (c) 2000-2010 LSI Corporation. - * - * - * Name: mpi2_sas.h - * Title: MPI Serial Attached SCSI structures and definitions - * Creation Date: February 9, 2007 - * - * mpi2_sas.h Version: 02.00.05 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 06-26-07 02.00.01 Added Clear All Persistent Operation to SAS IO Unit - * Control Request. - * 10-02-08 02.00.02 Added Set IOC Parameter Operation to SAS IO Unit Control - * Request. - * 10-28-09 02.00.03 Changed the type of SGL in MPI2_SATA_PASSTHROUGH_REQUEST - * to MPI2_SGE_IO_UNION since it supports chained SGLs. - * 05-12-10 02.00.04 Modified some comments. - * 08-11-10 02.00.05 Added NCQ operations to SAS IO Unit Control. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_SAS_H -#define MPI2_SAS_H - -/* - * Values for SASStatus. - */ -#define MPI2_SASSTATUS_SUCCESS (0x00) -#define MPI2_SASSTATUS_UNKNOWN_ERROR (0x01) -#define MPI2_SASSTATUS_INVALID_FRAME (0x02) -#define MPI2_SASSTATUS_UTC_BAD_DEST (0x03) -#define MPI2_SASSTATUS_UTC_BREAK_RECEIVED (0x04) -#define MPI2_SASSTATUS_UTC_CONNECT_RATE_NOT_SUPPORTED (0x05) -#define MPI2_SASSTATUS_UTC_PORT_LAYER_REQUEST (0x06) -#define MPI2_SASSTATUS_UTC_PROTOCOL_NOT_SUPPORTED (0x07) -#define MPI2_SASSTATUS_UTC_STP_RESOURCES_BUSY (0x08) -#define MPI2_SASSTATUS_UTC_WRONG_DESTINATION (0x09) -#define MPI2_SASSTATUS_SHORT_INFORMATION_UNIT (0x0A) -#define MPI2_SASSTATUS_LONG_INFORMATION_UNIT (0x0B) -#define MPI2_SASSTATUS_XFER_RDY_INCORRECT_WRITE_DATA (0x0C) -#define MPI2_SASSTATUS_XFER_RDY_REQUEST_OFFSET_ERROR (0x0D) -#define MPI2_SASSTATUS_XFER_RDY_NOT_EXPECTED (0x0E) -#define MPI2_SASSTATUS_DATA_INCORRECT_DATA_LENGTH (0x0F) -#define MPI2_SASSTATUS_DATA_TOO_MUCH_READ_DATA (0x10) -#define MPI2_SASSTATUS_DATA_OFFSET_ERROR (0x11) -#define MPI2_SASSTATUS_SDSF_NAK_RECEIVED (0x12) -#define MPI2_SASSTATUS_SDSF_CONNECTION_FAILED (0x13) -#define MPI2_SASSTATUS_INITIATOR_RESPONSE_TIMEOUT (0x14) - - -/* - * Values for the SAS DeviceInfo field used in SAS Device Status Change Event - * data and SAS Configuration pages. - */ -#define MPI2_SAS_DEVICE_INFO_SEP (0x00004000) -#define MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE (0x00002000) -#define MPI2_SAS_DEVICE_INFO_LSI_DEVICE (0x00001000) -#define MPI2_SAS_DEVICE_INFO_DIRECT_ATTACH (0x00000800) -#define MPI2_SAS_DEVICE_INFO_SSP_TARGET (0x00000400) -#define MPI2_SAS_DEVICE_INFO_STP_TARGET (0x00000200) -#define MPI2_SAS_DEVICE_INFO_SMP_TARGET (0x00000100) -#define MPI2_SAS_DEVICE_INFO_SATA_DEVICE (0x00000080) -#define MPI2_SAS_DEVICE_INFO_SSP_INITIATOR (0x00000040) -#define MPI2_SAS_DEVICE_INFO_STP_INITIATOR (0x00000020) -#define MPI2_SAS_DEVICE_INFO_SMP_INITIATOR (0x00000010) -#define MPI2_SAS_DEVICE_INFO_SATA_HOST (0x00000008) - -#define MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE (0x00000007) -#define MPI2_SAS_DEVICE_INFO_NO_DEVICE (0x00000000) -#define MPI2_SAS_DEVICE_INFO_END_DEVICE (0x00000001) -#define MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER (0x00000002) -#define MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER (0x00000003) - - -/***************************************************************************** -* -* SAS Messages -* -*****************************************************************************/ - -/**************************************************************************** -* SMP Passthrough messages -****************************************************************************/ - -/* SMP Passthrough Request Message */ -typedef struct _MPI2_SMP_PASSTHROUGH_REQUEST -{ - U8 PassthroughFlags; /* 0x00 */ - U8 PhysicalPort; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 RequestDataLength; /* 0x04 */ - U8 SGLFlags; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Reserved2; /* 0x0C */ - U64 SASAddress; /* 0x10 */ - U32 Reserved3; /* 0x18 */ - U32 Reserved4; /* 0x1C */ - MPI2_SIMPLE_SGE_UNION SGL; /* 0x20 */ -} MPI2_SMP_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REQUEST, - Mpi2SmpPassthroughRequest_t, MPI2_POINTER pMpi2SmpPassthroughRequest_t; - -/* values for PassthroughFlags field */ -#define MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE (0x80) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* SMP Passthrough Reply Message */ -typedef struct _MPI2_SMP_PASSTHROUGH_REPLY -{ - U8 PassthroughFlags; /* 0x00 */ - U8 PhysicalPort; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 ResponseDataLength; /* 0x04 */ - U8 SGLFlags; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U8 Reserved2; /* 0x0C */ - U8 SASStatus; /* 0x0D */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 Reserved3; /* 0x14 */ - U8 ResponseData[4]; /* 0x18 */ -} MPI2_SMP_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SMP_PASSTHROUGH_REPLY, - Mpi2SmpPassthroughReply_t, MPI2_POINTER pMpi2SmpPassthroughReply_t; - -/* values for PassthroughFlags field */ -#define MPI2_SMP_PT_REPLY_PT_FLAGS_IMMEDIATE (0x80) - -/* values for SASStatus field are at the top of this file */ - - -/**************************************************************************** -* SATA Passthrough messages -****************************************************************************/ - -/* SATA Passthrough Request Message */ -typedef struct _MPI2_SATA_PASSTHROUGH_REQUEST -{ - U16 DevHandle; /* 0x00 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 PassthroughFlags; /* 0x04 */ - U8 SGLFlags; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U32 Reserved2; /* 0x0C */ - U32 Reserved3; /* 0x10 */ - U32 Reserved4; /* 0x14 */ - U32 DataLength; /* 0x18 */ - U8 CommandFIS[20]; /* 0x1C */ - MPI2_SGE_IO_UNION SGL; /* 0x30 */ -} MPI2_SATA_PASSTHROUGH_REQUEST, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REQUEST, - Mpi2SataPassthroughRequest_t, MPI2_POINTER pMpi2SataPassthroughRequest_t; - -/* values for PassthroughFlags field */ -#define MPI2_SATA_PT_REQ_PT_FLAGS_EXECUTE_DIAG (0x0100) -#define MPI2_SATA_PT_REQ_PT_FLAGS_DMA (0x0020) -#define MPI2_SATA_PT_REQ_PT_FLAGS_PIO (0x0010) -#define MPI2_SATA_PT_REQ_PT_FLAGS_UNSPECIFIED_VU (0x0004) -#define MPI2_SATA_PT_REQ_PT_FLAGS_WRITE (0x0002) -#define MPI2_SATA_PT_REQ_PT_FLAGS_READ (0x0001) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* SATA Passthrough Reply Message */ -typedef struct _MPI2_SATA_PASSTHROUGH_REPLY -{ - U16 DevHandle; /* 0x00 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 PassthroughFlags; /* 0x04 */ - U8 SGLFlags; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved1; /* 0x0A */ - U8 Reserved2; /* 0x0C */ - U8 SASStatus; /* 0x0D */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U8 StatusFIS[20]; /* 0x14 */ - U32 StatusControlRegisters; /* 0x28 */ - U32 TransferCount; /* 0x2C */ -} MPI2_SATA_PASSTHROUGH_REPLY, MPI2_POINTER PTR_MPI2_SATA_PASSTHROUGH_REPLY, - Mpi2SataPassthroughReply_t, MPI2_POINTER pMpi2SataPassthroughReply_t; - -/* values for SASStatus field are at the top of this file */ - - -/**************************************************************************** -* SAS IO Unit Control messages -****************************************************************************/ - -/* SAS IO Unit Control Request Message */ -typedef struct _MPI2_SAS_IOUNIT_CONTROL_REQUEST -{ - U8 Operation; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 DevHandle; /* 0x04 */ - U8 IOCParameter; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U16 Reserved4; /* 0x0C */ - U8 PhyNum; /* 0x0E */ - U8 PrimFlags; /* 0x0F */ - U32 Primitive; /* 0x10 */ - U8 LookupMethod; /* 0x14 */ - U8 Reserved5; /* 0x15 */ - U16 SlotNumber; /* 0x16 */ - U64 LookupAddress; /* 0x18 */ - U32 IOCParameterValue; /* 0x20 */ - U32 Reserved7; /* 0x24 */ - U32 Reserved8; /* 0x28 */ -} MPI2_SAS_IOUNIT_CONTROL_REQUEST, - MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REQUEST, - Mpi2SasIoUnitControlRequest_t, MPI2_POINTER pMpi2SasIoUnitControlRequest_t; - -/* values for the Operation field */ -#define MPI2_SAS_OP_CLEAR_ALL_PERSISTENT (0x02) -#define MPI2_SAS_OP_PHY_LINK_RESET (0x06) -#define MPI2_SAS_OP_PHY_HARD_RESET (0x07) -#define MPI2_SAS_OP_PHY_CLEAR_ERROR_LOG (0x08) -#define MPI2_SAS_OP_SEND_PRIMITIVE (0x0A) -#define MPI2_SAS_OP_FORCE_FULL_DISCOVERY (0x0B) -#define MPI2_SAS_OP_TRANSMIT_PORT_SELECT_SIGNAL (0x0C) -#define MPI2_SAS_OP_REMOVE_DEVICE (0x0D) -#define MPI2_SAS_OP_LOOKUP_MAPPING (0x0E) -#define MPI2_SAS_OP_SET_IOC_PARAMETER (0x0F) -#define MPI2_SAS_OP_DEV_ENABLE_NCQ (0x14) -#define MPI2_SAS_OP_DEV_DISABLE_NCQ (0x15) -#define MPI2_SAS_OP_PRODUCT_SPECIFIC_MIN (0x80) - -/* values for the PrimFlags field */ -#define MPI2_SAS_PRIMFLAGS_SINGLE (0x08) -#define MPI2_SAS_PRIMFLAGS_TRIPLE (0x02) -#define MPI2_SAS_PRIMFLAGS_REDUNDANT (0x01) - -/* values for the LookupMethod field */ -#define MPI2_SAS_LOOKUP_METHOD_SAS_ADDRESS (0x01) -#define MPI2_SAS_LOOKUP_METHOD_SAS_ENCLOSURE_SLOT (0x02) -#define MPI2_SAS_LOOKUP_METHOD_SAS_DEVICE_NAME (0x03) - - -/* SAS IO Unit Control Reply Message */ -typedef struct _MPI2_SAS_IOUNIT_CONTROL_REPLY -{ - U8 Operation; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 DevHandle; /* 0x04 */ - U8 IOCParameter; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved3; /* 0x0A */ - U16 Reserved4; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_SAS_IOUNIT_CONTROL_REPLY, - MPI2_POINTER PTR_MPI2_SAS_IOUNIT_CONTROL_REPLY, - Mpi2SasIoUnitControlReply_t, MPI2_POINTER pMpi2SasIoUnitControlReply_t; - - -#endif - - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_tool.h deleted file mode 100644 index 3cbe677c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_tool.h +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Copyright (c) 2000-2010 LSI Corporation. - * - * - * Name: mpi2_tool.h - * Title: MPI diagnostic tool structures and definitions - * Creation Date: March 26, 2007 - * - * mpi2_tool.h Version: 02.00.07 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * 12-18-07 02.00.01 Added Diagnostic Buffer Post and Diagnostic Release - * structures and defines. - * 02-29-08 02.00.02 Modified various names to make them 32-character unique. - * 05-06-09 02.00.03 Added ISTWI Read Write Tool and Diagnostic CLI Tool. - * 07-30-09 02.00.04 Added ExtendedType field to DiagnosticBufferPost request - * and reply messages. - * Added MPI2_DIAG_BUF_TYPE_EXTENDED. - * Incremented MPI2_DIAG_BUF_TYPE_COUNT. - * 05-12-10 02.00.05 Added Diagnostic Data Upload tool. - * 08-11-10 02.00.06 Added defines that were missing for Diagnostic Buffer - * Post Request. - * 05-25-11 02.00.07 Added Flags field and related defines to - * MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_TOOL_H -#define MPI2_TOOL_H - -/***************************************************************************** -* -* Toolbox Messages -* -*****************************************************************************/ - -/* defines for the Tools */ -#define MPI2_TOOLBOX_CLEAN_TOOL (0x00) -#define MPI2_TOOLBOX_MEMORY_MOVE_TOOL (0x01) -#define MPI2_TOOLBOX_DIAG_DATA_UPLOAD_TOOL (0x02) -#define MPI2_TOOLBOX_ISTWI_READ_WRITE_TOOL (0x03) -#define MPI2_TOOLBOX_BEACON_TOOL (0x05) -#define MPI2_TOOLBOX_DIAGNOSTIC_CLI_TOOL (0x06) - - -/**************************************************************************** -* Toolbox reply -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_REPLY -{ - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_TOOLBOX_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_REPLY, - Mpi2ToolboxReply_t, MPI2_POINTER pMpi2ToolboxReply_t; - - -/**************************************************************************** -* Toolbox Clean Tool request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST -{ - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 Flags; /* 0x0C */ - } MPI2_TOOLBOX_CLEAN_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_CLEAN_REQUEST, - Mpi2ToolboxCleanRequest_t, MPI2_POINTER pMpi2ToolboxCleanRequest_t; - -/* values for the Flags field */ -#define MPI2_TOOLBOX_CLEAN_BOOT_SERVICES (0x80000000) -#define MPI2_TOOLBOX_CLEAN_PERSIST_MANUFACT_PAGES (0x40000000) -#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) -#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) -#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) -#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) -#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) -#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) -#define MPI2_TOOLBOX_CLEAN_SEEPROM (0x00000002) -#define MPI2_TOOLBOX_CLEAN_NVSRAM (0x00000001) - - -/**************************************************************************** -* Toolbox Memory Move request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_MEM_MOVE_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x0C */ -} MPI2_TOOLBOX_MEM_MOVE_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_MEM_MOVE_REQUEST, - Mpi2ToolboxMemMoveRequest_t, MPI2_POINTER pMpi2ToolboxMemMoveRequest_t; - - -/**************************************************************************** -* Toolbox Diagnostic Data Upload request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 SGLFlags; /* 0x0C */ - U8 Reserved5; /* 0x0D */ - U16 Reserved6; /* 0x0E */ - U32 Flags; /* 0x10 */ - U32 DataLength; /* 0x14 */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x18 */ -} MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_DATA_UPLOAD_REQUEST, -Mpi2ToolboxDiagDataUploadRequest_t, -MPI2_POINTER pMpi2ToolboxDiagDataUploadRequest_t; - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -typedef struct _MPI2_DIAG_DATA_UPLOAD_HEADER { - U32 DiagDataLength; /* 00h */ - U8 FormatCode; /* 04h */ - U8 Reserved1; /* 05h */ - U16 Reserved2; /* 06h */ -} MPI2_DIAG_DATA_UPLOAD_HEADER, MPI2_POINTER PTR_MPI2_DIAG_DATA_UPLOAD_HEADER, -Mpi2DiagDataUploadHeader_t, MPI2_POINTER pMpi2DiagDataUploadHeader_t; - - -/**************************************************************************** -* Toolbox ISTWI Read Write Tool -****************************************************************************/ - -/* Toolbox ISTWI Read Write Tool request message */ -typedef struct _MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U32 Reserved5; /* 0x0C */ - U32 Reserved6; /* 0x10 */ - U8 DevIndex; /* 0x14 */ - U8 Action; /* 0x15 */ - U8 SGLFlags; /* 0x16 */ - U8 Flags; /* 0x17 */ - U16 TxDataLength; /* 0x18 */ - U16 RxDataLength; /* 0x1A */ - U32 Reserved8; /* 0x1C */ - U32 Reserved9; /* 0x20 */ - U32 Reserved10; /* 0x24 */ - U32 Reserved11; /* 0x28 */ - U32 Reserved12; /* 0x2C */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x30 */ -} MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, - MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST, - Mpi2ToolboxIstwiReadWriteRequest_t, - MPI2_POINTER pMpi2ToolboxIstwiReadWriteRequest_t; - -/* values for the Action field */ -#define MPI2_TOOL_ISTWI_ACTION_READ_DATA (0x01) -#define MPI2_TOOL_ISTWI_ACTION_WRITE_DATA (0x02) -#define MPI2_TOOL_ISTWI_ACTION_SEQUENCE (0x03) -#define MPI2_TOOL_ISTWI_ACTION_RESERVE_BUS (0x10) -#define MPI2_TOOL_ISTWI_ACTION_RELEASE_BUS (0x11) -#define MPI2_TOOL_ISTWI_ACTION_RESET (0x12) - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - -/* values for the Flags field */ -#define MPI2_TOOL_ISTWI_FLAG_AUTO_RESERVE_RELEASE (0x80) -#define MPI2_TOOL_ISTWI_FLAG_PAGE_ADDR_MASK (0x07) - -/* Toolbox ISTWI Read Write Tool reply message */ -typedef struct _MPI2_TOOLBOX_ISTWI_REPLY { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U8 DevIndex; /* 0x14 */ - U8 Action; /* 0x15 */ - U8 IstwiStatus; /* 0x16 */ - U8 Reserved6; /* 0x17 */ - U16 TxDataCount; /* 0x18 */ - U16 RxDataCount; /* 0x1A */ -} MPI2_TOOLBOX_ISTWI_REPLY, MPI2_POINTER PTR_MPI2_TOOLBOX_ISTWI_REPLY, - Mpi2ToolboxIstwiReply_t, MPI2_POINTER pMpi2ToolboxIstwiReply_t; - - -/**************************************************************************** -* Toolbox Beacon Tool request -****************************************************************************/ - -typedef struct _MPI2_TOOLBOX_BEACON_REQUEST -{ - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 Reserved5; /* 0x0C */ - U8 PhysicalPort; /* 0x0D */ - U8 Reserved6; /* 0x0E */ - U8 Flags; /* 0x0F */ -} MPI2_TOOLBOX_BEACON_REQUEST, MPI2_POINTER PTR_MPI2_TOOLBOX_BEACON_REQUEST, - Mpi2ToolboxBeaconRequest_t, MPI2_POINTER pMpi2ToolboxBeaconRequest_t; - -/* values for the Flags field */ -#define MPI2_TOOLBOX_FLAGS_BEACONMODE_OFF (0x00) -#define MPI2_TOOLBOX_FLAGS_BEACONMODE_ON (0x01) - - -/**************************************************************************** -* Toolbox Diagnostic CLI Tool -****************************************************************************/ - -#define MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH (0x5C) - -/* Toolbox Diagnostic CLI Tool request message */ -typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U8 SGLFlags; /* 0x0C */ - U8 Reserved5; /* 0x0D */ - U16 Reserved6; /* 0x0E */ - U32 DataLength; /* 0x10 */ - U8 DiagnosticCliCommand - [MPI2_TOOLBOX_DIAG_CLI_CMD_LENGTH]; /* 0x14 */ - MPI2_SGE_SIMPLE_UNION SGL; /* 0x70 */ -} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, - MPI2_POINTER PTR_MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST, - Mpi2ToolboxDiagnosticCliRequest_t, - MPI2_POINTER pMpi2ToolboxDiagnosticCliRequest_t; - -/* use MPI2_SGLFLAGS_ defines from mpi2.h for the SGLFlags field */ - - -/* Toolbox Diagnostic CLI Tool reply message */ -typedef struct _MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY { - U8 Tool; /* 0x00 */ - U8 Reserved1; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 ReturnedDataLength; /* 0x14 */ -} MPI2_TOOLBOX_DIAGNOSTIC_CLI_REPLY, - MPI2_POINTER PTR_MPI2_TOOLBOX_DIAG_CLI_REPLY, - Mpi2ToolboxDiagnosticCliReply_t, - MPI2_POINTER pMpi2ToolboxDiagnosticCliReply_t; - - -/***************************************************************************** -* -* Diagnostic Buffer Messages -* -*****************************************************************************/ - - -/**************************************************************************** -* Diagnostic Buffer Post request -****************************************************************************/ - -typedef struct _MPI2_DIAG_BUFFER_POST_REQUEST -{ - U8 ExtendedType; /* 0x00 */ - U8 BufferType; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U64 BufferAddress; /* 0x0C */ - U32 BufferLength; /* 0x14 */ - U32 Reserved5; /* 0x18 */ - U32 Reserved6; /* 0x1C */ - U32 Flags; /* 0x20 */ - U32 ProductSpecific[23]; /* 0x24 */ -} MPI2_DIAG_BUFFER_POST_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REQUEST, - Mpi2DiagBufferPostRequest_t, MPI2_POINTER pMpi2DiagBufferPostRequest_t; - -/* values for the ExtendedType field */ -#define MPI2_DIAG_EXTENDED_TYPE_UTILIZATION (0x02) - -/* values for the BufferType field */ -#define MPI2_DIAG_BUF_TYPE_TRACE (0x00) -#define MPI2_DIAG_BUF_TYPE_SNAPSHOT (0x01) -#define MPI2_DIAG_BUF_TYPE_EXTENDED (0x02) -/* count of the number of buffer types */ -#define MPI2_DIAG_BUF_TYPE_COUNT (0x03) - -/* values for the Flags field */ -#define MPI2_DIAG_BUF_FLAG_RELEASE_ON_FULL (0x00000002) -#define MPI2_DIAG_BUF_FLAG_IMMEDIATE_RELEASE (0x00000001) - - -/**************************************************************************** -* Diagnostic Buffer Post reply -****************************************************************************/ - -typedef struct _MPI2_DIAG_BUFFER_POST_REPLY -{ - U8 ExtendedType; /* 0x00 */ - U8 BufferType; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ - U32 TransferLength; /* 0x14 */ -} MPI2_DIAG_BUFFER_POST_REPLY, MPI2_POINTER PTR_MPI2_DIAG_BUFFER_POST_REPLY, - Mpi2DiagBufferPostReply_t, MPI2_POINTER pMpi2DiagBufferPostReply_t; - - -/**************************************************************************** -* Diagnostic Release request -****************************************************************************/ - -typedef struct _MPI2_DIAG_RELEASE_REQUEST -{ - U8 Reserved1; /* 0x00 */ - U8 BufferType; /* 0x01 */ - U8 ChainOffset; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ -} MPI2_DIAG_RELEASE_REQUEST, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REQUEST, - Mpi2DiagReleaseRequest_t, MPI2_POINTER pMpi2DiagReleaseRequest_t; - - -/**************************************************************************** -* Diagnostic Buffer Post reply -****************************************************************************/ - -typedef struct _MPI2_DIAG_RELEASE_REPLY -{ - U8 Reserved1; /* 0x00 */ - U8 BufferType; /* 0x01 */ - U8 MsgLength; /* 0x02 */ - U8 Function; /* 0x03 */ - U16 Reserved2; /* 0x04 */ - U8 Reserved3; /* 0x06 */ - U8 MsgFlags; /* 0x07 */ - U8 VP_ID; /* 0x08 */ - U8 VF_ID; /* 0x09 */ - U16 Reserved4; /* 0x0A */ - U16 Reserved5; /* 0x0C */ - U16 IOCStatus; /* 0x0E */ - U32 IOCLogInfo; /* 0x10 */ -} MPI2_DIAG_RELEASE_REPLY, MPI2_POINTER PTR_MPI2_DIAG_RELEASE_REPLY, - Mpi2DiagReleaseReply_t, MPI2_POINTER pMpi2DiagReleaseReply_t; - - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_type.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_type.h deleted file mode 100644 index cfde017b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpi/mpi2_type.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2000-2007 LSI Corporation. - * - * - * Name: mpi2_type.h - * Title: MPI basic type definitions - * Creation Date: August 16, 2006 - * - * mpi2_type.h Version: 02.00.00 - * - * Version History - * --------------- - * - * Date Version Description - * -------- -------- ------------------------------------------------------ - * 04-30-07 02.00.00 Corresponds to Fusion-MPT MPI Specification Rev A. - * -------------------------------------------------------------------------- - */ - -#ifndef MPI2_TYPE_H -#define MPI2_TYPE_H - - -/******************************************************************************* - * Define MPI2_POINTER if it hasn't already been defined. By default - * MPI2_POINTER is defined to be a near pointer. MPI2_POINTER can be defined as - * a far pointer by defining MPI2_POINTER as "far *" before this header file is - * included. - */ -#ifndef MPI2_POINTER -#define MPI2_POINTER * -#endif - -/* the basic types may have already been included by mpi_type.h */ -#ifndef MPI_TYPE_H -/***************************************************************************** -* -* Basic Types -* -*****************************************************************************/ - -typedef u8 U8; -typedef __le16 U16; -typedef __le32 U32; -typedef __le64 U64 __attribute__((aligned(4))); - -/***************************************************************************** -* -* Pointer Types -* -*****************************************************************************/ - -typedef U8 *PU8; -typedef U16 *PU16; -typedef U32 *PU32; -typedef U64 *PU64; - -#endif - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.c b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.c deleted file mode 100644 index 3f03342b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.c +++ /dev/null @@ -1,4614 +0,0 @@ -/* - * This is the Fusion MPT base driver providing common API layer interface - * for access to MPT (Message Passing Technology) firmware. - * - * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2010 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_base.h" - -static MPT_CALLBACK mpt_callbacks[MPT_MAX_CALLBACKS]; - -#define FAULT_POLLING_INTERVAL 1000 /* in milliseconds */ - -#define MAX_HBA_QUEUE_DEPTH 30000 -#define MAX_CHAIN_DEPTH 100000 -static int max_queue_depth = -1; -module_param(max_queue_depth, int, 0); -MODULE_PARM_DESC(max_queue_depth, " max controller queue depth "); - -static int max_sgl_entries = -1; -module_param(max_sgl_entries, int, 0); -MODULE_PARM_DESC(max_sgl_entries, " max sg entries "); - -static int msix_disable = -1; -module_param(msix_disable, int, 0); -MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); - -static int missing_delay[2] = {-1, -1}; -module_param_array(missing_delay, int, NULL, 0); -MODULE_PARM_DESC(missing_delay, " device missing delay , io missing delay"); - -static int mpt2sas_fwfault_debug; -MODULE_PARM_DESC(mpt2sas_fwfault_debug, " enable detection of firmware fault " - "and halt firmware - (default=0)"); - -static int disable_discovery = -1; -module_param(disable_discovery, int, 0); -MODULE_PARM_DESC(disable_discovery, " disable discovery "); - -/** - * _scsih_set_fwfault_debug - global setting of ioc->fwfault_debug. - * - */ -static int -_scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) -{ - int ret = param_set_int(val, kp); - struct MPT2SAS_ADAPTER *ioc; - - if (ret) - return ret; - - printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) - ioc->fwfault_debug = mpt2sas_fwfault_debug; - return 0; -} - -module_param_call(mpt2sas_fwfault_debug, _scsih_set_fwfault_debug, - param_get_int, &mpt2sas_fwfault_debug, 0644); - -/** - * mpt2sas_remove_dead_ioc_func - kthread context to remove dead ioc - * @arg: input argument, used to derive ioc - * - * Return 0 if controller is removed from pci subsystem. - * Return -1 for other case. - */ -static int mpt2sas_remove_dead_ioc_func(void *arg) -{ - struct MPT2SAS_ADAPTER *ioc = (struct MPT2SAS_ADAPTER *)arg; - struct pci_dev *pdev; - - if ((ioc == NULL)) - return -1; - - pdev = ioc->pdev; - if ((pdev == NULL)) - return -1; - pci_stop_and_remove_bus_device(pdev); - return 0; -} - - -/** - * _base_fault_reset_work - workq handling ioc fault conditions - * @work: input argument, used to derive ioc - * Context: sleep. - * - * Return nothing. - */ -static void -_base_fault_reset_work(struct work_struct *work) -{ - struct MPT2SAS_ADAPTER *ioc = - container_of(work, struct MPT2SAS_ADAPTER, fault_reset_work.work); - unsigned long flags; - u32 doorbell; - int rc; - struct task_struct *p; - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->shost_recovery) - goto rearm_timer; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - - doorbell = mpt2sas_base_get_iocstate(ioc, 0); - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_MASK) { - printk(MPT2SAS_INFO_FMT "%s : SAS host is non-operational !!!!\n", - ioc->name, __func__); - - /* - * Call _scsih_flush_pending_cmds callback so that we flush all - * pending commands back to OS. This call is required to aovid - * deadlock at block layer. Dead IOC will fail to do diag reset, - * and this call is safe since dead ioc will never return any - * command back from HW. - */ - ioc->schedule_dead_ioc_flush_running_cmds(ioc); - /* - * Set remove_host flag early since kernel thread will - * take some time to execute. - */ - ioc->remove_host = 1; - /*Remove the Dead Host */ - p = kthread_run(mpt2sas_remove_dead_ioc_func, ioc, - "mpt2sas_dead_ioc_%d", ioc->id); - if (IS_ERR(p)) { - printk(MPT2SAS_ERR_FMT - "%s: Running mpt2sas_dead_ioc thread failed !!!!\n", - ioc->name, __func__); - } else { - printk(MPT2SAS_ERR_FMT - "%s: Running mpt2sas_dead_ioc thread success !!!!\n", - ioc->name, __func__); - } - - return; /* don't rearm timer */ - } - - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - printk(MPT2SAS_WARN_FMT "%s: hard reset: %s\n", ioc->name, - __func__, (rc == 0) ? "success" : "failed"); - doorbell = mpt2sas_base_get_iocstate(ioc, 0); - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) - mpt2sas_base_fault_info(ioc, doorbell & - MPI2_DOORBELL_DATA_MASK); - } - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - rearm_timer: - if (ioc->fault_reset_work_q) - queue_delayed_work(ioc->fault_reset_work_q, - &ioc->fault_reset_work, - msecs_to_jiffies(FAULT_POLLING_INTERVAL)); - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -} - -/** - * mpt2sas_base_start_watchdog - start the fault_reset_work_q - * @ioc: per adapter object - * Context: sleep. - * - * Return nothing. - */ -void -mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; - - if (ioc->fault_reset_work_q) - return; - - /* initialize fault polling */ - INIT_DELAYED_WORK(&ioc->fault_reset_work, _base_fault_reset_work); - snprintf(ioc->fault_reset_work_q_name, - sizeof(ioc->fault_reset_work_q_name), "poll_%d_status", ioc->id); - ioc->fault_reset_work_q = - create_singlethread_workqueue(ioc->fault_reset_work_q_name); - if (!ioc->fault_reset_work_q) { - printk(MPT2SAS_ERR_FMT "%s: failed (line=%d)\n", - ioc->name, __func__, __LINE__); - return; - } - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - if (ioc->fault_reset_work_q) - queue_delayed_work(ioc->fault_reset_work_q, - &ioc->fault_reset_work, - msecs_to_jiffies(FAULT_POLLING_INTERVAL)); - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); -} - -/** - * mpt2sas_base_stop_watchdog - stop the fault_reset_work_q - * @ioc: per adapter object - * Context: sleep. - * - * Return nothing. - */ -void -mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc) -{ - unsigned long flags; - struct workqueue_struct *wq; - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - wq = ioc->fault_reset_work_q; - ioc->fault_reset_work_q = NULL; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - if (wq) { - if (!cancel_delayed_work(&ioc->fault_reset_work)) - flush_workqueue(wq); - destroy_workqueue(wq); - } -} - -/** - * mpt2sas_base_fault_info - verbose translation of firmware FAULT code - * @ioc: per adapter object - * @fault_code: fault code - * - * Return nothing. - */ -void -mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code) -{ - printk(MPT2SAS_ERR_FMT "fault_state(0x%04x)!\n", - ioc->name, fault_code); -} - -/** - * mpt2sas_halt_firmware - halt's mpt controller firmware - * @ioc: per adapter object - * - * For debugging timeout related issues. Writing 0xCOFFEE00 - * to the doorbell register will halt controller firmware. With - * the purpose to stop both driver and firmware, the enduser can - * obtain a ring buffer from controller UART. - */ -void -mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc) -{ - u32 doorbell; - - if (!ioc->fwfault_debug) - return; - - dump_stack(); - - doorbell = readl(&ioc->chip->Doorbell); - if ((doorbell & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) - mpt2sas_base_fault_info(ioc , doorbell); - else { - writel(0xC0FFEE00, &ioc->chip->Doorbell); - printk(MPT2SAS_ERR_FMT "Firmware is halted due to command " - "timeout\n", ioc->name); - } - - panic("panic in %s\n", __func__); -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _base_sas_ioc_info - verbose translation of the ioc status - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @request_hdr: request mf - * - * Return nothing. - */ -static void -_base_sas_ioc_info(struct MPT2SAS_ADAPTER *ioc, MPI2DefaultReply_t *mpi_reply, - MPI2RequestHeader_t *request_hdr) -{ - u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & - MPI2_IOCSTATUS_MASK; - char *desc = NULL; - u16 frame_sz; - char *func_str = NULL; - - /* SCSI_IO, RAID_PASS are handled from _scsih_scsi_ioc_info */ - if (request_hdr->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - request_hdr->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH || - request_hdr->Function == MPI2_FUNCTION_EVENT_NOTIFICATION) - return; - - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - return; - - switch (ioc_status) { - -/**************************************************************************** -* Common IOCStatus values for all replies -****************************************************************************/ - - case MPI2_IOCSTATUS_INVALID_FUNCTION: - desc = "invalid function"; - break; - case MPI2_IOCSTATUS_BUSY: - desc = "busy"; - break; - case MPI2_IOCSTATUS_INVALID_SGL: - desc = "invalid sgl"; - break; - case MPI2_IOCSTATUS_INTERNAL_ERROR: - desc = "internal error"; - break; - case MPI2_IOCSTATUS_INVALID_VPID: - desc = "invalid vpid"; - break; - case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: - desc = "insufficient resources"; - break; - case MPI2_IOCSTATUS_INVALID_FIELD: - desc = "invalid field"; - break; - case MPI2_IOCSTATUS_INVALID_STATE: - desc = "invalid state"; - break; - case MPI2_IOCSTATUS_OP_STATE_NOT_SUPPORTED: - desc = "op state not supported"; - break; - -/**************************************************************************** -* Config IOCStatus values -****************************************************************************/ - - case MPI2_IOCSTATUS_CONFIG_INVALID_ACTION: - desc = "config invalid action"; - break; - case MPI2_IOCSTATUS_CONFIG_INVALID_TYPE: - desc = "config invalid type"; - break; - case MPI2_IOCSTATUS_CONFIG_INVALID_PAGE: - desc = "config invalid page"; - break; - case MPI2_IOCSTATUS_CONFIG_INVALID_DATA: - desc = "config invalid data"; - break; - case MPI2_IOCSTATUS_CONFIG_NO_DEFAULTS: - desc = "config no defaults"; - break; - case MPI2_IOCSTATUS_CONFIG_CANT_COMMIT: - desc = "config cant commit"; - break; - -/**************************************************************************** -* SCSI IO Reply -****************************************************************************/ - - case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: - case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: - case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: - case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: - case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: - case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: - case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: - case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: - case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: - case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: - case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: - case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: - break; - -/**************************************************************************** -* For use by SCSI Initiator and SCSI Target end-to-end data protection -****************************************************************************/ - - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - desc = "eedp guard error"; - break; - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - desc = "eedp ref tag error"; - break; - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - desc = "eedp app tag error"; - break; - -/**************************************************************************** -* SCSI Target values -****************************************************************************/ - - case MPI2_IOCSTATUS_TARGET_INVALID_IO_INDEX: - desc = "target invalid io index"; - break; - case MPI2_IOCSTATUS_TARGET_ABORTED: - desc = "target aborted"; - break; - case MPI2_IOCSTATUS_TARGET_NO_CONN_RETRYABLE: - desc = "target no conn retryable"; - break; - case MPI2_IOCSTATUS_TARGET_NO_CONNECTION: - desc = "target no connection"; - break; - case MPI2_IOCSTATUS_TARGET_XFER_COUNT_MISMATCH: - desc = "target xfer count mismatch"; - break; - case MPI2_IOCSTATUS_TARGET_DATA_OFFSET_ERROR: - desc = "target data offset error"; - break; - case MPI2_IOCSTATUS_TARGET_TOO_MUCH_WRITE_DATA: - desc = "target too much write data"; - break; - case MPI2_IOCSTATUS_TARGET_IU_TOO_SHORT: - desc = "target iu too short"; - break; - case MPI2_IOCSTATUS_TARGET_ACK_NAK_TIMEOUT: - desc = "target ack nak timeout"; - break; - case MPI2_IOCSTATUS_TARGET_NAK_RECEIVED: - desc = "target nak received"; - break; - -/**************************************************************************** -* Serial Attached SCSI values -****************************************************************************/ - - case MPI2_IOCSTATUS_SAS_SMP_REQUEST_FAILED: - desc = "smp request failed"; - break; - case MPI2_IOCSTATUS_SAS_SMP_DATA_OVERRUN: - desc = "smp data overrun"; - break; - -/**************************************************************************** -* Diagnostic Buffer Post / Diagnostic Release values -****************************************************************************/ - - case MPI2_IOCSTATUS_DIAGNOSTIC_RELEASED: - desc = "diagnostic released"; - break; - default: - break; - } - - if (!desc) - return; - - switch (request_hdr->Function) { - case MPI2_FUNCTION_CONFIG: - frame_sz = sizeof(Mpi2ConfigRequest_t) + ioc->sge_size; - func_str = "config_page"; - break; - case MPI2_FUNCTION_SCSI_TASK_MGMT: - frame_sz = sizeof(Mpi2SCSITaskManagementRequest_t); - func_str = "task_mgmt"; - break; - case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: - frame_sz = sizeof(Mpi2SasIoUnitControlRequest_t); - func_str = "sas_iounit_ctl"; - break; - case MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR: - frame_sz = sizeof(Mpi2SepRequest_t); - func_str = "enclosure"; - break; - case MPI2_FUNCTION_IOC_INIT: - frame_sz = sizeof(Mpi2IOCInitRequest_t); - func_str = "ioc_init"; - break; - case MPI2_FUNCTION_PORT_ENABLE: - frame_sz = sizeof(Mpi2PortEnableRequest_t); - func_str = "port_enable"; - break; - case MPI2_FUNCTION_SMP_PASSTHROUGH: - frame_sz = sizeof(Mpi2SmpPassthroughRequest_t) + ioc->sge_size; - func_str = "smp_passthru"; - break; - default: - frame_sz = 32; - func_str = "unknown"; - break; - } - - printk(MPT2SAS_WARN_FMT "ioc_status: %s(0x%04x), request(0x%p)," - " (%s)\n", ioc->name, desc, ioc_status, request_hdr, func_str); - - _debug_dump_mf(request_hdr, frame_sz/4); -} - -/** - * _base_display_event_data - verbose translation of firmware asyn events - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * - * Return nothing. - */ -static void -_base_display_event_data(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventNotificationReply_t *mpi_reply) -{ - char *desc = NULL; - u16 event; - - if (!(ioc->logging_level & MPT_DEBUG_EVENTS)) - return; - - event = le16_to_cpu(mpi_reply->Event); - - switch (event) { - case MPI2_EVENT_LOG_DATA: - desc = "Log Data"; - break; - case MPI2_EVENT_STATE_CHANGE: - desc = "Status Change"; - break; - case MPI2_EVENT_HARD_RESET_RECEIVED: - desc = "Hard Reset Received"; - break; - case MPI2_EVENT_EVENT_CHANGE: - desc = "Event Change"; - break; - case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - desc = "Device Status Change"; - break; - case MPI2_EVENT_IR_OPERATION_STATUS: - if (!ioc->hide_ir_msg) - desc = "IR Operation Status"; - break; - case MPI2_EVENT_SAS_DISCOVERY: - { - Mpi2EventDataSasDiscovery_t *event_data = - (Mpi2EventDataSasDiscovery_t *)mpi_reply->EventData; - printk(MPT2SAS_INFO_FMT "Discovery: (%s)", ioc->name, - (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? - "start" : "stop"); - if (event_data->DiscoveryStatus) - printk("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - printk("\n"); - return; - } - case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: - desc = "SAS Broadcast Primitive"; - break; - case MPI2_EVENT_SAS_INIT_DEVICE_STATUS_CHANGE: - desc = "SAS Init Device Status Change"; - break; - case MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW: - desc = "SAS Init Table Overflow"; - break; - case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - desc = "SAS Topology Change List"; - break; - case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - desc = "SAS Enclosure Device Status Change"; - break; - case MPI2_EVENT_IR_VOLUME: - if (!ioc->hide_ir_msg) - desc = "IR Volume"; - break; - case MPI2_EVENT_IR_PHYSICAL_DISK: - if (!ioc->hide_ir_msg) - desc = "IR Physical Disk"; - break; - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - if (!ioc->hide_ir_msg) - desc = "IR Configuration Change List"; - break; - case MPI2_EVENT_LOG_ENTRY_ADDED: - if (!ioc->hide_ir_msg) - desc = "Log Entry Added"; - break; - } - - if (!desc) - return; - - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, desc); -} -#endif - -/** - * _base_sas_log_info - verbose translation of firmware log info - * @ioc: per adapter object - * @log_info: log info - * - * Return nothing. - */ -static void -_base_sas_log_info(struct MPT2SAS_ADAPTER *ioc , u32 log_info) -{ - union loginfo_type { - u32 loginfo; - struct { - u32 subcode:16; - u32 code:8; - u32 originator:4; - u32 bus_type:4; - } dw; - }; - union loginfo_type sas_loginfo; - char *originator_str = NULL; - - sas_loginfo.loginfo = log_info; - if (sas_loginfo.dw.bus_type != 3 /*SAS*/) - return; - - /* each nexus loss loginfo */ - if (log_info == 0x31170000) - return; - - /* eat the loginfos associated with task aborts */ - if (ioc->ignore_loginfos && (log_info == 0x30050000 || log_info == - 0x31140000 || log_info == 0x31130000)) - return; - - switch (sas_loginfo.dw.originator) { - case 0: - originator_str = "IOP"; - break; - case 1: - originator_str = "PL"; - break; - case 2: - if (!ioc->hide_ir_msg) - originator_str = "IR"; - else - originator_str = "WarpDrive"; - break; - } - - printk(MPT2SAS_WARN_FMT "log_info(0x%08x): originator(%s), " - "code(0x%02x), sub_code(0x%04x)\n", ioc->name, log_info, - originator_str, sas_loginfo.dw.code, - sas_loginfo.dw.subcode); -} - -/** - * _base_display_reply_info - - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return nothing. - */ -static void -_base_display_reply_info(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - u16 ioc_status; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - ioc_status = le16_to_cpu(mpi_reply->IOCStatus); -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if ((ioc_status & MPI2_IOCSTATUS_MASK) && - (ioc->logging_level & MPT_DEBUG_REPLY)) { - _base_sas_ioc_info(ioc , mpi_reply, - mpt2sas_base_get_msg_frame(ioc, smid)); - } -#endif - if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) - _base_sas_log_info(ioc, le32_to_cpu(mpi_reply->IOCLogInfo)); -} - -/** - * mpt2sas_base_done - base internal command completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) - return 1; - - if (ioc->base_cmds.status == MPT2_CMD_NOT_USED) - return 1; - - ioc->base_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - ioc->base_cmds.status |= MPT2_CMD_REPLY_VALID; - memcpy(ioc->base_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); - } - ioc->base_cmds.status &= ~MPT2_CMD_PENDING; - - complete(&ioc->base_cmds.done); - return 1; -} - -/** - * _base_async_event - main callback handler for firmware asyn events - * @ioc: per adapter object - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_base_async_event(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, u32 reply) -{ - Mpi2EventNotificationReply_t *mpi_reply; - Mpi2EventAckRequest_t *ack_request; - u16 smid; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (!mpi_reply) - return 1; - if (mpi_reply->Function != MPI2_FUNCTION_EVENT_NOTIFICATION) - return 1; -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _base_display_event_data(ioc, mpi_reply); -#endif - if (!(mpi_reply->AckRequired & MPI2_EVENT_NOTIFICATION_ACK_REQUIRED)) - goto out; - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - goto out; - } - - ack_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(ack_request, 0, sizeof(Mpi2EventAckRequest_t)); - ack_request->Function = MPI2_FUNCTION_EVENT_ACK; - ack_request->Event = mpi_reply->Event; - ack_request->EventContext = mpi_reply->EventContext; - ack_request->VF_ID = 0; /* TODO */ - ack_request->VP_ID = 0; - mpt2sas_base_put_smid_default(ioc, smid); - - out: - - /* scsih callback handler */ - mpt2sas_scsih_event_callback(ioc, msix_index, reply); - - /* ctl callback handler */ - mpt2sas_ctl_event_callback(ioc, msix_index, reply); - - return 1; -} - -/** - * _base_get_cb_idx - obtain the callback index - * @ioc: per adapter object - * @smid: system request message index - * - * Return callback index. - */ -static u8 -_base_get_cb_idx(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - int i; - u8 cb_idx; - - if (smid < ioc->hi_priority_smid) { - i = smid - 1; - cb_idx = ioc->scsi_lookup[i].cb_idx; - } else if (smid < ioc->internal_smid) { - i = smid - ioc->hi_priority_smid; - cb_idx = ioc->hpr_lookup[i].cb_idx; - } else if (smid <= ioc->hba_queue_depth) { - i = smid - ioc->internal_smid; - cb_idx = ioc->internal_lookup[i].cb_idx; - } else - cb_idx = 0xFF; - return cb_idx; -} - -/** - * _base_mask_interrupts - disable interrupts - * @ioc: per adapter object - * - * Disabling ResetIRQ, Reply and Doorbell Interrupts - * - * Return nothing. - */ -static void -_base_mask_interrupts(struct MPT2SAS_ADAPTER *ioc) -{ - u32 him_register; - - ioc->mask_interrupts = 1; - him_register = readl(&ioc->chip->HostInterruptMask); - him_register |= MPI2_HIM_DIM + MPI2_HIM_RIM + MPI2_HIM_RESET_IRQ_MASK; - writel(him_register, &ioc->chip->HostInterruptMask); - readl(&ioc->chip->HostInterruptMask); -} - -/** - * _base_unmask_interrupts - enable interrupts - * @ioc: per adapter object - * - * Enabling only Reply Interrupts - * - * Return nothing. - */ -static void -_base_unmask_interrupts(struct MPT2SAS_ADAPTER *ioc) -{ - u32 him_register; - - him_register = readl(&ioc->chip->HostInterruptMask); - him_register &= ~MPI2_HIM_RIM; - writel(him_register, &ioc->chip->HostInterruptMask); - ioc->mask_interrupts = 0; -} - -union reply_descriptor { - u64 word; - struct { - u32 low; - u32 high; - } u; -}; - -/** - * _base_interrupt - MPT adapter (IOC) specific interrupt handler. - * @irq: irq number (not used) - * @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure - * @r: pt_regs pointer (not used) - * - * Return IRQ_HANDLE if processed, else IRQ_NONE. - */ -static irqreturn_t -_base_interrupt(int irq, void *bus_id) -{ - struct adapter_reply_queue *reply_q = bus_id; - union reply_descriptor rd; - u32 completed_cmds; - u8 request_desript_type; - u16 smid; - u8 cb_idx; - u32 reply; - u8 msix_index = reply_q->msix_index; - struct MPT2SAS_ADAPTER *ioc = reply_q->ioc; - Mpi2ReplyDescriptorsUnion_t *rpf; - u8 rc; - - if (ioc->mask_interrupts) - return IRQ_NONE; - - if (!atomic_add_unless(&reply_q->busy, 1, 1)) - return IRQ_NONE; - - rpf = &reply_q->reply_post_free[reply_q->reply_post_host_index]; - request_desript_type = rpf->Default.ReplyFlags - & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) { - atomic_dec(&reply_q->busy); - return IRQ_NONE; - } - - completed_cmds = 0; - cb_idx = 0xFF; - do { - rd.word = le64_to_cpu(rpf->Words); - if (rd.u.low == UINT_MAX || rd.u.high == UINT_MAX) - goto out; - reply = 0; - smid = le16_to_cpu(rpf->Default.DescriptorTypeDependent1); - if (request_desript_type == - MPI2_RPY_DESCRIPT_FLAGS_ADDRESS_REPLY) { - reply = le32_to_cpu - (rpf->AddressReply.ReplyFrameAddress); - if (reply > ioc->reply_dma_max_address || - reply < ioc->reply_dma_min_address) - reply = 0; - } else if (request_desript_type == - MPI2_RPY_DESCRIPT_FLAGS_TARGET_COMMAND_BUFFER) - goto next; - else if (request_desript_type == - MPI2_RPY_DESCRIPT_FLAGS_TARGETASSIST_SUCCESS) - goto next; - if (smid) - cb_idx = _base_get_cb_idx(ioc, smid); - if (smid && cb_idx != 0xFF) { - rc = mpt_callbacks[cb_idx](ioc, smid, msix_index, - reply); - if (reply) - _base_display_reply_info(ioc, smid, msix_index, - reply); - if (rc) - mpt2sas_base_free_smid(ioc, smid); - } - if (!smid) - _base_async_event(ioc, msix_index, reply); - - /* reply free queue handling */ - if (reply) { - ioc->reply_free_host_index = - (ioc->reply_free_host_index == - (ioc->reply_free_queue_depth - 1)) ? - 0 : ioc->reply_free_host_index + 1; - ioc->reply_free[ioc->reply_free_host_index] = - cpu_to_le32(reply); - wmb(); - writel(ioc->reply_free_host_index, - &ioc->chip->ReplyFreeHostIndex); - } - - next: - - rpf->Words = cpu_to_le64(ULLONG_MAX); - reply_q->reply_post_host_index = - (reply_q->reply_post_host_index == - (ioc->reply_post_queue_depth - 1)) ? 0 : - reply_q->reply_post_host_index + 1; - request_desript_type = - reply_q->reply_post_free[reply_q->reply_post_host_index]. - Default.ReplyFlags & MPI2_RPY_DESCRIPT_FLAGS_TYPE_MASK; - completed_cmds++; - if (request_desript_type == MPI2_RPY_DESCRIPT_FLAGS_UNUSED) - goto out; - if (!reply_q->reply_post_host_index) - rpf = reply_q->reply_post_free; - else - rpf++; - } while (1); - - out: - - if (!completed_cmds) { - atomic_dec(&reply_q->busy); - return IRQ_NONE; - } - wmb(); - if (ioc->is_warpdrive) { - writel(reply_q->reply_post_host_index, - ioc->reply_post_host_index[msix_index]); - atomic_dec(&reply_q->busy); - return IRQ_HANDLED; - } - writel(reply_q->reply_post_host_index | (msix_index << - MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex); - atomic_dec(&reply_q->busy); - return IRQ_HANDLED; -} - -/** - * _base_is_controller_msix_enabled - is controller support muli-reply queues - * @ioc: per adapter object - * - */ -static inline int -_base_is_controller_msix_enabled(struct MPT2SAS_ADAPTER *ioc) -{ - return (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable; -} - -/** - * mpt2sas_base_flush_reply_queues - flushing the MSIX reply queues - * @ioc: per adapter object - * Context: ISR conext - * - * Called when a Task Management request has completed. We want - * to flush the other reply queues so all the outstanding IO has been - * completed back to OS before we process the TM completetion. - * - * Return nothing. - */ -void -mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc) -{ - struct adapter_reply_queue *reply_q; - - /* If MSIX capability is turned off - * then multi-queues are not enabled - */ - if (!_base_is_controller_msix_enabled(ioc)) - return; - - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - if (ioc->shost_recovery) - return; - /* TMs are on msix_index == 0 */ - if (reply_q->msix_index == 0) - continue; - _base_interrupt(reply_q->vector, (void *)reply_q); - } -} - -/** - * mpt2sas_base_release_callback_handler - clear interrupt callback handler - * @cb_idx: callback index - * - * Return nothing. - */ -void -mpt2sas_base_release_callback_handler(u8 cb_idx) -{ - mpt_callbacks[cb_idx] = NULL; -} - -/** - * mpt2sas_base_register_callback_handler - obtain index for the interrupt callback handler - * @cb_func: callback function - * - * Returns cb_func. - */ -u8 -mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func) -{ - u8 cb_idx; - - for (cb_idx = MPT_MAX_CALLBACKS-1; cb_idx; cb_idx--) - if (mpt_callbacks[cb_idx] == NULL) - break; - - mpt_callbacks[cb_idx] = cb_func; - return cb_idx; -} - -/** - * mpt2sas_base_initialize_callback_handler - initialize the interrupt callback handler - * - * Return nothing. - */ -void -mpt2sas_base_initialize_callback_handler(void) -{ - u8 cb_idx; - - for (cb_idx = 0; cb_idx < MPT_MAX_CALLBACKS; cb_idx++) - mpt2sas_base_release_callback_handler(cb_idx); -} - -/** - * mpt2sas_base_build_zero_len_sge - build zero length sg entry - * @ioc: per adapter object - * @paddr: virtual address for SGE - * - * Create a zero length scatter gather entry to insure the IOCs hardware has - * something to use if the target device goes brain dead and tries - * to send data even when none is asked for. - * - * Return nothing. - */ -void -mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr) -{ - u32 flags_length = (u32)((MPI2_SGE_FLAGS_LAST_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST | - MPI2_SGE_FLAGS_SIMPLE_ELEMENT) << - MPI2_SGE_FLAGS_SHIFT); - ioc->base_add_sg_single(paddr, flags_length, -1); -} - -/** - * _base_add_sg_single_32 - Place a simple 32 bit SGE at address pAddr. - * @paddr: virtual address for SGE - * @flags_length: SGE flags and data transfer length - * @dma_addr: Physical address - * - * Return nothing. - */ -static void -_base_add_sg_single_32(void *paddr, u32 flags_length, dma_addr_t dma_addr) -{ - Mpi2SGESimple32_t *sgel = paddr; - - flags_length |= (MPI2_SGE_FLAGS_32_BIT_ADDRESSING | - MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; - sgel->FlagsLength = cpu_to_le32(flags_length); - sgel->Address = cpu_to_le32(dma_addr); -} - - -/** - * _base_add_sg_single_64 - Place a simple 64 bit SGE at address pAddr. - * @paddr: virtual address for SGE - * @flags_length: SGE flags and data transfer length - * @dma_addr: Physical address - * - * Return nothing. - */ -static void -_base_add_sg_single_64(void *paddr, u32 flags_length, dma_addr_t dma_addr) -{ - Mpi2SGESimple64_t *sgel = paddr; - - flags_length |= (MPI2_SGE_FLAGS_64_BIT_ADDRESSING | - MPI2_SGE_FLAGS_SYSTEM_ADDRESS) << MPI2_SGE_FLAGS_SHIFT; - sgel->FlagsLength = cpu_to_le32(flags_length); - sgel->Address = cpu_to_le64(dma_addr); -} - -#define convert_to_kb(x) ((x) << (PAGE_SHIFT - 10)) - -/** - * _base_config_dma_addressing - set dma addressing - * @ioc: per adapter object - * @pdev: PCI device struct - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_config_dma_addressing(struct MPT2SAS_ADAPTER *ioc, struct pci_dev *pdev) -{ - struct sysinfo s; - char *desc = NULL; - - if (sizeof(dma_addr_t) > 4) { - const uint64_t required_mask = - dma_get_required_mask(&pdev->dev); - if ((required_mask > DMA_BIT_MASK(32)) && !pci_set_dma_mask(pdev, - DMA_BIT_MASK(64)) && !pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(64))) { - ioc->base_add_sg_single = &_base_add_sg_single_64; - ioc->sge_size = sizeof(Mpi2SGESimple64_t); - desc = "64"; - goto out; - } - } - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) - && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) { - ioc->base_add_sg_single = &_base_add_sg_single_32; - ioc->sge_size = sizeof(Mpi2SGESimple32_t); - desc = "32"; - } else - return -ENODEV; - - out: - si_meminfo(&s); - printk(MPT2SAS_INFO_FMT "%s BIT PCI BUS DMA ADDRESSING SUPPORTED, " - "total mem (%ld kB)\n", ioc->name, desc, convert_to_kb(s.totalram)); - - return 0; -} - -/** - * _base_check_enable_msix - checks MSIX capabable. - * @ioc: per adapter object - * - * Check to see if card is capable of MSIX, and set number - * of available msix vectors - */ -static int -_base_check_enable_msix(struct MPT2SAS_ADAPTER *ioc) -{ - int base; - u16 message_control; - - - base = pci_find_capability(ioc->pdev, PCI_CAP_ID_MSIX); - if (!base) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "msix not " - "supported\n", ioc->name)); - return -EINVAL; - } - - /* get msix vector count */ - /* NUMA_IO not supported for older controllers */ - if (ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2004 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2008 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_1 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_2 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2108_3 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_1 || - ioc->pdev->device == MPI2_MFGPAGE_DEVID_SAS2116_2) - ioc->msix_vector_count = 1; - else { - pci_read_config_word(ioc->pdev, base + 2, &message_control); - ioc->msix_vector_count = (message_control & 0x3FF) + 1; - } - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "msix is supported, " - "vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); - - return 0; -} - -/** - * _base_free_irq - free irq - * @ioc: per adapter object - * - * Freeing respective reply_queue from the list. - */ -static void -_base_free_irq(struct MPT2SAS_ADAPTER *ioc) -{ - struct adapter_reply_queue *reply_q, *next; - - if (list_empty(&ioc->reply_queue_list)) - return; - - list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) { - list_del(&reply_q->list); - synchronize_irq(reply_q->vector); - free_irq(reply_q->vector, reply_q); - kfree(reply_q); - } -} - -/** - * _base_request_irq - request irq - * @ioc: per adapter object - * @index: msix index into vector table - * @vector: irq vector - * - * Inserting respective reply_queue into the list. - */ -static int -_base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector) -{ - struct adapter_reply_queue *reply_q; - int r; - - reply_q = kzalloc(sizeof(struct adapter_reply_queue), GFP_KERNEL); - if (!reply_q) { - printk(MPT2SAS_ERR_FMT "unable to allocate memory %d!\n", - ioc->name, (int)sizeof(struct adapter_reply_queue)); - return -ENOMEM; - } - reply_q->ioc = ioc; - reply_q->msix_index = index; - reply_q->vector = vector; - atomic_set(&reply_q->busy, 0); - if (ioc->msix_enable) - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d", - MPT2SAS_DRIVER_NAME, ioc->id, index); - else - snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d", - MPT2SAS_DRIVER_NAME, ioc->id); - r = request_irq(vector, _base_interrupt, IRQF_SHARED, reply_q->name, - reply_q); - if (r) { - printk(MPT2SAS_ERR_FMT "unable to allocate interrupt %d!\n", - reply_q->name, vector); - kfree(reply_q); - return -EBUSY; - } - - INIT_LIST_HEAD(&reply_q->list); - list_add_tail(&reply_q->list, &ioc->reply_queue_list); - return 0; -} - -/** - * _base_assign_reply_queues - assigning msix index for each cpu - * @ioc: per adapter object - * - * The enduser would need to set the affinity via /proc/irq/#/smp_affinity - * - * It would nice if we could call irq_set_affinity, however it is not - * an exported symbol - */ -static void -_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc) -{ - struct adapter_reply_queue *reply_q; - int cpu_id; - int cpu_grouping, loop, grouping, grouping_mod; - - if (!_base_is_controller_msix_enabled(ioc)) - return; - - memset(ioc->cpu_msix_table, 0, ioc->cpu_msix_table_sz); - /* when there are more cpus than available msix vectors, - * then group cpus togeather on same irq - */ - if (ioc->cpu_count > ioc->msix_vector_count) { - grouping = ioc->cpu_count / ioc->msix_vector_count; - grouping_mod = ioc->cpu_count % ioc->msix_vector_count; - if (grouping < 2 || (grouping == 2 && !grouping_mod)) - cpu_grouping = 2; - else if (grouping < 4 || (grouping == 4 && !grouping_mod)) - cpu_grouping = 4; - else if (grouping < 8 || (grouping == 8 && !grouping_mod)) - cpu_grouping = 8; - else - cpu_grouping = 16; - } else - cpu_grouping = 0; - - loop = 0; - reply_q = list_entry(ioc->reply_queue_list.next, - struct adapter_reply_queue, list); - for_each_online_cpu(cpu_id) { - if (!cpu_grouping) { - ioc->cpu_msix_table[cpu_id] = reply_q->msix_index; - reply_q = list_entry(reply_q->list.next, - struct adapter_reply_queue, list); - } else { - if (loop < cpu_grouping) { - ioc->cpu_msix_table[cpu_id] = - reply_q->msix_index; - loop++; - } else { - reply_q = list_entry(reply_q->list.next, - struct adapter_reply_queue, list); - ioc->cpu_msix_table[cpu_id] = - reply_q->msix_index; - loop = 1; - } - } - } -} - -/** - * _base_disable_msix - disables msix - * @ioc: per adapter object - * - */ -static void -_base_disable_msix(struct MPT2SAS_ADAPTER *ioc) -{ - if (ioc->msix_enable) { - pci_disable_msix(ioc->pdev); - ioc->msix_enable = 0; - } -} - -/** - * _base_enable_msix - enables msix, failback to io_apic - * @ioc: per adapter object - * - */ -static int -_base_enable_msix(struct MPT2SAS_ADAPTER *ioc) -{ - struct msix_entry *entries, *a; - int r; - int i; - u8 try_msix = 0; - - INIT_LIST_HEAD(&ioc->reply_queue_list); - - if (msix_disable == -1 || msix_disable == 0) - try_msix = 1; - - if (!try_msix) - goto try_ioapic; - - if (_base_check_enable_msix(ioc) != 0) - goto try_ioapic; - - ioc->reply_queue_count = min_t(int, ioc->cpu_count, - ioc->msix_vector_count); - - entries = kcalloc(ioc->reply_queue_count, sizeof(struct msix_entry), - GFP_KERNEL); - if (!entries) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "kcalloc " - "failed @ at %s:%d/%s() !!!\n", ioc->name, __FILE__, - __LINE__, __func__)); - goto try_ioapic; - } - - for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) - a->entry = i; - - r = pci_enable_msix(ioc->pdev, entries, ioc->reply_queue_count); - if (r) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "pci_enable_msix " - "failed (r=%d) !!!\n", ioc->name, r)); - kfree(entries); - goto try_ioapic; - } - - ioc->msix_enable = 1; - for (i = 0, a = entries; i < ioc->reply_queue_count; i++, a++) { - r = _base_request_irq(ioc, i, a->vector); - if (r) { - _base_free_irq(ioc); - _base_disable_msix(ioc); - kfree(entries); - goto try_ioapic; - } - } - - kfree(entries); - return 0; - -/* failback to io_apic interrupt routing */ - try_ioapic: - - r = _base_request_irq(ioc, 0, ioc->pdev->irq); - - return r; -} - -/** - * mpt2sas_base_map_resources - map in controller resources (io/irq/memap) - * @ioc: per adapter object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) -{ - struct pci_dev *pdev = ioc->pdev; - u32 memap_sz; - u32 pio_sz; - int i, r = 0; - u64 pio_chip = 0; - u64 chip_phys = 0; - struct adapter_reply_queue *reply_q; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", - ioc->name, __func__)); - - ioc->bars = pci_select_bars(pdev, IORESOURCE_MEM); - if (pci_enable_device_mem(pdev)) { - printk(MPT2SAS_WARN_FMT "pci_enable_device_mem: " - "failed\n", ioc->name); - return -ENODEV; - } - - - if (pci_request_selected_regions(pdev, ioc->bars, - MPT2SAS_DRIVER_NAME)) { - printk(MPT2SAS_WARN_FMT "pci_request_selected_regions: " - "failed\n", ioc->name); - r = -ENODEV; - goto out_fail; - } - - /* AER (Advanced Error Reporting) hooks */ - pci_enable_pcie_error_reporting(pdev); - - pci_set_master(pdev); - - if (_base_config_dma_addressing(ioc, pdev) != 0) { - printk(MPT2SAS_WARN_FMT "no suitable DMA mask for %s\n", - ioc->name, pci_name(pdev)); - r = -ENODEV; - goto out_fail; - } - - for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { - if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { - if (pio_sz) - continue; - pio_chip = (u64)pci_resource_start(pdev, i); - pio_sz = pci_resource_len(pdev, i); - } else { - if (memap_sz) - continue; - /* verify memory resource is valid before using */ - if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) { - ioc->chip_phys = pci_resource_start(pdev, i); - chip_phys = (u64)ioc->chip_phys; - memap_sz = pci_resource_len(pdev, i); - ioc->chip = ioremap(ioc->chip_phys, memap_sz); - if (ioc->chip == NULL) { - printk(MPT2SAS_ERR_FMT "unable to map " - "adapter memory!\n", ioc->name); - r = -EINVAL; - goto out_fail; - } - } - } - } - - _base_mask_interrupts(ioc); - r = _base_enable_msix(ioc); - if (r) - goto out_fail; - - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) - printk(MPT2SAS_INFO_FMT "%s: IRQ %d\n", - reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : - "IO-APIC enabled"), reply_q->vector); - - printk(MPT2SAS_INFO_FMT "iomem(0x%016llx), mapped(0x%p), size(%d)\n", - ioc->name, (unsigned long long)chip_phys, ioc->chip, memap_sz); - printk(MPT2SAS_INFO_FMT "ioport(0x%016llx), size(%d)\n", - ioc->name, (unsigned long long)pio_chip, pio_sz); - - /* Save PCI configuration state for recovery from PCI AER/EEH errors */ - pci_save_state(pdev); - - return 0; - - out_fail: - if (ioc->chip_phys) - iounmap(ioc->chip); - ioc->chip_phys = 0; - pci_release_selected_regions(ioc->pdev, ioc->bars); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - return r; -} - -/** - * mpt2sas_base_get_msg_frame - obtain request mf pointer - * @ioc: per adapter object - * @smid: system request message index(smid zero is invalid) - * - * Returns virt pointer to message frame. - */ -void * -mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return (void *)(ioc->request + (smid * ioc->request_sz)); -} - -/** - * mpt2sas_base_get_sense_buffer - obtain a sense buffer assigned to a mf request - * @ioc: per adapter object - * @smid: system request message index - * - * Returns virt pointer to sense buffer. - */ -void * -mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return (void *)(ioc->sense + ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); -} - -/** - * mpt2sas_base_get_sense_buffer_dma - obtain a sense buffer assigned to a mf request - * @ioc: per adapter object - * @smid: system request message index - * - * Returns phys pointer to the low 32bit address of the sense buffer. - */ -__le32 -mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return cpu_to_le32(ioc->sense_dma + - ((smid - 1) * SCSI_SENSE_BUFFERSIZE)); -} - -/** - * mpt2sas_base_get_reply_virt_addr - obtain reply frames virt address - * @ioc: per adapter object - * @phys_addr: lower 32 physical addr of the reply - * - * Converts 32bit lower physical addr into a virt address. - */ -void * -mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr) -{ - if (!phys_addr) - return NULL; - return ioc->reply + (phys_addr - (u32)ioc->reply_dma); -} - -/** - * mpt2sas_base_get_smid - obtain a free smid from internal queue - * @ioc: per adapter object - * @cb_idx: callback index - * - * Returns smid (zero is invalid) - */ -u16 -mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) -{ - unsigned long flags; - struct request_tracker *request; - u16 smid; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->internal_free_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - printk(MPT2SAS_ERR_FMT "%s: smid not available\n", - ioc->name, __func__); - return 0; - } - - request = list_entry(ioc->internal_free_list.next, - struct request_tracker, tracker_list); - request->cb_idx = cb_idx; - smid = request->smid; - list_del(&request->tracker_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return smid; -} - -/** - * mpt2sas_base_get_smid_scsiio - obtain a free smid from scsiio queue - * @ioc: per adapter object - * @cb_idx: callback index - * @scmd: pointer to scsi command object - * - * Returns smid (zero is invalid) - */ -u16 -mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, - struct scsi_cmnd *scmd) -{ - unsigned long flags; - struct scsiio_tracker *request; - u16 smid; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->free_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - printk(MPT2SAS_ERR_FMT "%s: smid not available\n", - ioc->name, __func__); - return 0; - } - - request = list_entry(ioc->free_list.next, - struct scsiio_tracker, tracker_list); - request->scmd = scmd; - request->cb_idx = cb_idx; - smid = request->smid; - list_del(&request->tracker_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return smid; -} - -/** - * mpt2sas_base_get_smid_hpr - obtain a free smid from hi-priority queue - * @ioc: per adapter object - * @cb_idx: callback index - * - * Returns smid (zero is invalid) - */ -u16 -mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx) -{ - unsigned long flags; - struct request_tracker *request; - u16 smid; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->hpr_free_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return 0; - } - - request = list_entry(ioc->hpr_free_list.next, - struct request_tracker, tracker_list); - request->cb_idx = cb_idx; - smid = request->smid; - list_del(&request->tracker_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return smid; -} - - -/** - * mpt2sas_base_free_smid - put smid back on free_list - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -void -mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - unsigned long flags; - int i; - struct chain_tracker *chain_req, *next; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (smid < ioc->hi_priority_smid) { - /* scsiio queue */ - i = smid - 1; - if (!list_empty(&ioc->scsi_lookup[i].chain_list)) { - list_for_each_entry_safe(chain_req, next, - &ioc->scsi_lookup[i].chain_list, tracker_list) { - list_del_init(&chain_req->tracker_list); - list_add_tail(&chain_req->tracker_list, - &ioc->free_chain_list); - } - } - ioc->scsi_lookup[i].cb_idx = 0xFF; - ioc->scsi_lookup[i].scmd = NULL; - ioc->scsi_lookup[i].direct_io = 0; - list_add_tail(&ioc->scsi_lookup[i].tracker_list, - &ioc->free_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - /* - * See _wait_for_commands_to_complete() call with regards - * to this code. - */ - if (ioc->shost_recovery && ioc->pending_io_count) { - if (ioc->pending_io_count == 1) - wake_up(&ioc->reset_wq); - ioc->pending_io_count--; - } - return; - } else if (smid < ioc->internal_smid) { - /* hi-priority */ - i = smid - ioc->hi_priority_smid; - ioc->hpr_lookup[i].cb_idx = 0xFF; - list_add_tail(&ioc->hpr_lookup[i].tracker_list, - &ioc->hpr_free_list); - } else if (smid <= ioc->hba_queue_depth) { - /* internal queue */ - i = smid - ioc->internal_smid; - ioc->internal_lookup[i].cb_idx = 0xFF; - list_add_tail(&ioc->internal_lookup[i].tracker_list, - &ioc->internal_free_list); - } - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); -} - -/** - * _base_writeq - 64 bit write to MMIO - * @ioc: per adapter object - * @b: data payload - * @addr: address in MMIO space - * @writeq_lock: spin lock - * - * Glue for handling an atomic 64 bit word to MMIO. This special handling takes - * care of 32 bit environment where its not quarenteed to send the entire word - * in one transfer. - */ -#ifndef writeq -static inline void _base_writeq(__u64 b, volatile void __iomem *addr, - spinlock_t *writeq_lock) -{ - unsigned long flags; - __u64 data_out = cpu_to_le64(b); - - spin_lock_irqsave(writeq_lock, flags); - writel((u32)(data_out), addr); - writel((u32)(data_out >> 32), (addr + 4)); - spin_unlock_irqrestore(writeq_lock, flags); -} -#else -static inline void _base_writeq(__u64 b, volatile void __iomem *addr, - spinlock_t *writeq_lock) -{ - writeq(cpu_to_le64(b), addr); -} -#endif - -static inline u8 -_base_get_msix_index(struct MPT2SAS_ADAPTER *ioc) -{ - return ioc->cpu_msix_table[raw_smp_processor_id()]; -} - -/** - * mpt2sas_base_put_smid_scsi_io - send SCSI_IO request to firmware - * @ioc: per adapter object - * @smid: system request message index - * @handle: device handle - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, u16 handle) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - - descriptor.SCSIIO.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; - descriptor.SCSIIO.MSIxIndex = _base_get_msix_index(ioc); - descriptor.SCSIIO.SMID = cpu_to_le16(smid); - descriptor.SCSIIO.DevHandle = cpu_to_le16(handle); - descriptor.SCSIIO.LMID = 0; - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - - -/** - * mpt2sas_base_put_smid_hi_priority - send Task Management request to firmware - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.HighPriority.RequestFlags = - MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY; - descriptor.HighPriority.MSIxIndex = 0; - descriptor.HighPriority.SMID = cpu_to_le16(smid); - descriptor.HighPriority.LMID = 0; - descriptor.HighPriority.Reserved1 = 0; - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - -/** - * mpt2sas_base_put_smid_default - Default, primarily used for config pages - * @ioc: per adapter object - * @smid: system request message index - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.Default.RequestFlags = MPI2_REQ_DESCRIPT_FLAGS_DEFAULT_TYPE; - descriptor.Default.MSIxIndex = _base_get_msix_index(ioc); - descriptor.Default.SMID = cpu_to_le16(smid); - descriptor.Default.LMID = 0; - descriptor.Default.DescriptorTypeDependent = 0; - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - -/** - * mpt2sas_base_put_smid_target_assist - send Target Assist/Status to firmware - * @ioc: per adapter object - * @smid: system request message index - * @io_index: value used to track the IO - * - * Return nothing. - */ -void -mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u16 io_index) -{ - Mpi2RequestDescriptorUnion_t descriptor; - u64 *request = (u64 *)&descriptor; - - descriptor.SCSITarget.RequestFlags = - MPI2_REQ_DESCRIPT_FLAGS_SCSI_TARGET; - descriptor.SCSITarget.MSIxIndex = _base_get_msix_index(ioc); - descriptor.SCSITarget.SMID = cpu_to_le16(smid); - descriptor.SCSITarget.LMID = 0; - descriptor.SCSITarget.IoIndex = cpu_to_le16(io_index); - _base_writeq(*request, &ioc->chip->RequestDescriptorPostLow, - &ioc->scsi_lookup_lock); -} - -/** - * _base_display_dell_branding - Disply branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_dell_branding(struct MPT2SAS_ADAPTER *ioc) -{ - char dell_branding[MPT2SAS_DELL_BRANDING_SIZE]; - - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL) - return; - - memset(dell_branding, 0, MPT2SAS_DELL_BRANDING_SIZE); - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_MODULAR_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID: - strncpy(dell_branding, - MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_PERC_H200_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_PERC_H200_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - case MPT2SAS_DELL_6GBPS_SAS_SSDID: - strncpy(dell_branding, MPT2SAS_DELL_6GBPS_SAS_BRANDING, - MPT2SAS_DELL_BRANDING_SIZE - 1); - break; - default: - sprintf(dell_branding, "0x%4X", ioc->pdev->subsystem_device); - break; - } - - printk(MPT2SAS_INFO_FMT "%s: Vendor(0x%04X), Device(0x%04X)," - " SSVID(0x%04X), SSDID(0x%04X)\n", ioc->name, dell_branding, - ioc->pdev->vendor, ioc->pdev->device, ioc->pdev->subsystem_vendor, - ioc->pdev->subsystem_device); -} - -/** - * _base_display_intel_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_intel_branding(struct MPT2SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_INTEL) - return; - - switch (ioc->pdev->device) { - case MPI2_MFGPAGE_DEVID_SAS2008: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_INTEL_RMS2LL080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS2LL080_BRANDING); - break; - case MPT2SAS_INTEL_RMS2LL040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS2LL040_BRANDING); - break; - case MPT2SAS_INTEL_RAMSDALE_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RAMSDALE_BRANDING); - break; - default: - break; - } - case MPI2_MFGPAGE_DEVID_SAS2308_2: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_INTEL_RS25GB008_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RS25GB008_BRANDING); - break; - case MPT2SAS_INTEL_RMS25JB080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25JB080_BRANDING); - break; - case MPT2SAS_INTEL_RMS25JB040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25JB040_BRANDING); - break; - case MPT2SAS_INTEL_RMS25KB080_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25KB080_BRANDING); - break; - case MPT2SAS_INTEL_RMS25KB040_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_INTEL_RMS25KB040_BRANDING); - break; - default: - break; - } - default: - break; - } -} - -/** - * _base_display_hp_branding - Display branding string - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_hp_branding(struct MPT2SAS_ADAPTER *ioc) -{ - if (ioc->pdev->subsystem_vendor != MPT2SAS_HP_3PAR_SSVID) - return; - - switch (ioc->pdev->device) { - case MPI2_MFGPAGE_DEVID_SAS2004: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING); - break; - default: - break; - } - case MPI2_MFGPAGE_DEVID_SAS2308_2: - switch (ioc->pdev->subsystem_device) { - case MPT2SAS_HP_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_2_4_INTERNAL_BRANDING); - break; - case MPT2SAS_HP_2_4_EXTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_2_4_EXTERNAL_BRANDING); - break; - case MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING); - break; - case MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID: - printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING); - break; - default: - break; - } - default: - break; - } -} - -/** - * _base_display_ioc_capabilities - Disply IOC's capabilities. - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_display_ioc_capabilities(struct MPT2SAS_ADAPTER *ioc) -{ - int i = 0; - char desc[16]; - u32 iounit_pg1_flags; - u32 bios_version; - - bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); - strncpy(desc, ioc->manu_pg0.ChipName, 16); - printk(MPT2SAS_INFO_FMT "%s: FWVersion(%02d.%02d.%02d.%02d), " - "ChipRevision(0x%02x), BiosVersion(%02d.%02d.%02d.%02d)\n", - ioc->name, desc, - (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, - (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, - (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, - ioc->facts.FWVersion.Word & 0x000000FF, - ioc->pdev->revision, - (bios_version & 0xFF000000) >> 24, - (bios_version & 0x00FF0000) >> 16, - (bios_version & 0x0000FF00) >> 8, - bios_version & 0x000000FF); - - _base_display_dell_branding(ioc); - _base_display_intel_branding(ioc); - _base_display_hp_branding(ioc); - - printk(MPT2SAS_INFO_FMT "Protocol=(", ioc->name); - - if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR) { - printk("Initiator"); - i++; - } - - if (ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_TARGET) { - printk("%sTarget", i ? "," : ""); - i++; - } - - i = 0; - printk("), "); - printk("Capabilities=("); - - if (!ioc->hide_ir_msg) { - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID) { - printk("Raid"); - i++; - } - } - - if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR) { - printk("%sTLR", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_MULTICAST) { - printk("%sMulticast", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_BIDIRECTIONAL_TARGET) { - printk("%sBIDI Target", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_EEDP) { - printk("%sEEDP", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) { - printk("%sSnapshot Buffer", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) { - printk("%sDiag Trace Buffer", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) { - printk(KERN_INFO "%sDiag Extended Buffer", i ? "," : ""); - i++; - } - - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING) { - printk("%sTask Set Full", i ? "," : ""); - i++; - } - - iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); - if (!(iounit_pg1_flags & MPI2_IOUNITPAGE1_NATIVE_COMMAND_Q_DISABLE)) { - printk("%sNCQ", i ? "," : ""); - i++; - } - - printk(")\n"); -} - -/** - * _base_update_missing_delay - change the missing delay timers - * @ioc: per adapter object - * @device_missing_delay: amount of time till device is reported missing - * @io_missing_delay: interval IO is returned when there is a missing device - * - * Return nothing. - * - * Passed on the command line, this function will modify the device missing - * delay, as well as the io missing delay. This should be called at driver - * load time. - */ -static void -_base_update_missing_delay(struct MPT2SAS_ADAPTER *ioc, - u16 device_missing_delay, u8 io_missing_delay) -{ - u16 dmd, dmd_new, dmd_orignal; - u8 io_missing_delay_original; - u16 sz; - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2ConfigReply_t mpi_reply; - u8 num_phys = 0; - u16 ioc_status; - - mpt2sas_config_get_number_hba_phys(ioc, &num_phys); - if (!num_phys) - return; - - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg1) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - /* device missing delay */ - dmd = sas_iounit_pg1->ReportDeviceMissingDelay; - if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) - dmd = (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; - else - dmd = dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - dmd_orignal = dmd; - if (device_missing_delay > 0x7F) { - dmd = (device_missing_delay > 0x7F0) ? 0x7F0 : - device_missing_delay; - dmd = dmd / 16; - dmd |= MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16; - } else - dmd = device_missing_delay; - sas_iounit_pg1->ReportDeviceMissingDelay = dmd; - - /* io missing delay */ - io_missing_delay_original = sas_iounit_pg1->IODeviceMissingDelay; - sas_iounit_pg1->IODeviceMissingDelay = io_missing_delay; - - if (!mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, - sz)) { - if (dmd & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) - dmd_new = (dmd & - MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; - else - dmd_new = - dmd & MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - printk(MPT2SAS_INFO_FMT "device_missing_delay: old(%d), " - "new(%d)\n", ioc->name, dmd_orignal, dmd_new); - printk(MPT2SAS_INFO_FMT "ioc_missing_delay: old(%d), " - "new(%d)\n", ioc->name, io_missing_delay_original, - io_missing_delay); - ioc->device_missing_delay = dmd_new; - ioc->io_missing_delay = io_missing_delay; - } - -out: - kfree(sas_iounit_pg1); -} - -/** - * _base_static_config_pages - static start of day config pages - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_base_static_config_pages(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2ConfigReply_t mpi_reply; - u32 iounit_pg1_flags; - - mpt2sas_config_get_manufacturing_pg0(ioc, &mpi_reply, &ioc->manu_pg0); - if (ioc->ir_firmware) - mpt2sas_config_get_manufacturing_pg10(ioc, &mpi_reply, - &ioc->manu_pg10); - mpt2sas_config_get_bios_pg2(ioc, &mpi_reply, &ioc->bios_pg2); - mpt2sas_config_get_bios_pg3(ioc, &mpi_reply, &ioc->bios_pg3); - mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8); - mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0); - mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); - _base_display_ioc_capabilities(ioc); - - /* - * Enable task_set_full handling in iounit_pg1 when the - * facts capabilities indicate that its supported. - */ - iounit_pg1_flags = le32_to_cpu(ioc->iounit_pg1.Flags); - if ((ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_TASK_SET_FULL_HANDLING)) - iounit_pg1_flags &= - ~MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; - else - iounit_pg1_flags |= - MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING; - ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags); - mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); - -} - -/** - * _base_release_memory_pools - release memory - * @ioc: per adapter object - * - * Free memory allocated from _base_allocate_memory_pools. - * - * Return nothing. - */ -static void -_base_release_memory_pools(struct MPT2SAS_ADAPTER *ioc) -{ - int i; - - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->request) { - pci_free_consistent(ioc->pdev, ioc->request_dma_sz, - ioc->request, ioc->request_dma); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "request_pool(0x%p)" - ": free\n", ioc->name, ioc->request)); - ioc->request = NULL; - } - - if (ioc->sense) { - pci_pool_free(ioc->sense_dma_pool, ioc->sense, ioc->sense_dma); - if (ioc->sense_dma_pool) - pci_pool_destroy(ioc->sense_dma_pool); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_pool(0x%p)" - ": free\n", ioc->name, ioc->sense)); - ioc->sense = NULL; - } - - if (ioc->reply) { - pci_pool_free(ioc->reply_dma_pool, ioc->reply, ioc->reply_dma); - if (ioc->reply_dma_pool) - pci_pool_destroy(ioc->reply_dma_pool); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_pool(0x%p)" - ": free\n", ioc->name, ioc->reply)); - ioc->reply = NULL; - } - - if (ioc->reply_free) { - pci_pool_free(ioc->reply_free_dma_pool, ioc->reply_free, - ioc->reply_free_dma); - if (ioc->reply_free_dma_pool) - pci_pool_destroy(ioc->reply_free_dma_pool); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_pool" - "(0x%p): free\n", ioc->name, ioc->reply_free)); - ioc->reply_free = NULL; - } - - if (ioc->reply_post_free) { - pci_pool_free(ioc->reply_post_free_dma_pool, - ioc->reply_post_free, ioc->reply_post_free_dma); - if (ioc->reply_post_free_dma_pool) - pci_pool_destroy(ioc->reply_post_free_dma_pool); - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT - "reply_post_free_pool(0x%p): free\n", ioc->name, - ioc->reply_post_free)); - ioc->reply_post_free = NULL; - } - - if (ioc->config_page) { - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT - "config_page(0x%p): free\n", ioc->name, - ioc->config_page)); - pci_free_consistent(ioc->pdev, ioc->config_page_sz, - ioc->config_page, ioc->config_page_dma); - } - - if (ioc->scsi_lookup) { - free_pages((ulong)ioc->scsi_lookup, ioc->scsi_lookup_pages); - ioc->scsi_lookup = NULL; - } - kfree(ioc->hpr_lookup); - kfree(ioc->internal_lookup); - if (ioc->chain_lookup) { - for (i = 0; i < ioc->chain_depth; i++) { - if (ioc->chain_lookup[i].chain_buffer) - pci_pool_free(ioc->chain_dma_pool, - ioc->chain_lookup[i].chain_buffer, - ioc->chain_lookup[i].chain_buffer_dma); - } - if (ioc->chain_dma_pool) - pci_pool_destroy(ioc->chain_dma_pool); - free_pages((ulong)ioc->chain_lookup, ioc->chain_pages); - ioc->chain_lookup = NULL; - } -} - - -/** - * _base_allocate_memory_pools - allocate start of day memory pools - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 success, anything else error - */ -static int -_base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - struct mpt2sas_facts *facts; - u16 max_sge_elements; - u16 chains_needed_per_io; - u32 sz, total_sz, reply_post_free_sz; - u32 retry_sz; - u16 max_request_credit; - int i; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - retry_sz = 0; - facts = &ioc->facts; - - /* command line tunables for max sgl entries */ - if (max_sgl_entries != -1) { - ioc->shost->sg_tablesize = (max_sgl_entries < - MPT2SAS_SG_DEPTH) ? max_sgl_entries : - MPT2SAS_SG_DEPTH; - } else { - ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH; - } - - /* command line tunables for max controller queue depth */ - if (max_queue_depth != -1) - max_request_credit = (max_queue_depth < facts->RequestCredit) - ? max_queue_depth : facts->RequestCredit; - else - max_request_credit = min_t(u16, facts->RequestCredit, - MAX_HBA_QUEUE_DEPTH); - - ioc->hba_queue_depth = max_request_credit; - ioc->hi_priority_depth = facts->HighPriorityCredit; - ioc->internal_depth = ioc->hi_priority_depth + 5; - - /* request frame size */ - ioc->request_sz = facts->IOCRequestFrameSize * 4; - - /* reply frame size */ - ioc->reply_sz = facts->ReplyFrameSize * 4; - - retry_allocation: - total_sz = 0; - /* calculate number of sg elements left over in the 1st frame */ - max_sge_elements = ioc->request_sz - ((sizeof(Mpi2SCSIIORequest_t) - - sizeof(Mpi2SGEIOUnion_t)) + ioc->sge_size); - ioc->max_sges_in_main_message = max_sge_elements/ioc->sge_size; - - /* now do the same for a chain buffer */ - max_sge_elements = ioc->request_sz - ioc->sge_size; - ioc->max_sges_in_chain_message = max_sge_elements/ioc->sge_size; - - ioc->chain_offset_value_for_main_message = - ((sizeof(Mpi2SCSIIORequest_t) - sizeof(Mpi2SGEIOUnion_t)) + - (ioc->max_sges_in_chain_message * ioc->sge_size)) / 4; - - /* - * MPT2SAS_SG_DEPTH = CONFIG_FUSION_MAX_SGE - */ - chains_needed_per_io = ((ioc->shost->sg_tablesize - - ioc->max_sges_in_main_message)/ioc->max_sges_in_chain_message) - + 1; - if (chains_needed_per_io > facts->MaxChainDepth) { - chains_needed_per_io = facts->MaxChainDepth; - ioc->shost->sg_tablesize = min_t(u16, - ioc->max_sges_in_main_message + (ioc->max_sges_in_chain_message - * chains_needed_per_io), ioc->shost->sg_tablesize); - } - ioc->chains_needed_per_io = chains_needed_per_io; - - /* reply free queue sizing - taking into account for 64 FW events */ - ioc->reply_free_queue_depth = ioc->hba_queue_depth + 64; - - /* align the reply post queue on the next 16 count boundary */ - if (!ioc->reply_free_queue_depth % 16) - ioc->reply_post_queue_depth = ioc->reply_free_queue_depth + 16; - else - ioc->reply_post_queue_depth = ioc->reply_free_queue_depth + - 32 - (ioc->reply_free_queue_depth % 16); - if (ioc->reply_post_queue_depth > - facts->MaxReplyDescriptorPostQueueDepth) { - ioc->reply_post_queue_depth = min_t(u16, - (facts->MaxReplyDescriptorPostQueueDepth - - (facts->MaxReplyDescriptorPostQueueDepth % 16)), - (ioc->hba_queue_depth - (ioc->hba_queue_depth % 16))); - ioc->reply_free_queue_depth = ioc->reply_post_queue_depth - 16; - ioc->hba_queue_depth = ioc->reply_free_queue_depth - 64; - } - - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scatter gather: " - "sge_in_main_msg(%d), sge_per_chain(%d), sge_per_io(%d), " - "chains_per_io(%d)\n", ioc->name, ioc->max_sges_in_main_message, - ioc->max_sges_in_chain_message, ioc->shost->sg_tablesize, - ioc->chains_needed_per_io)); - - ioc->scsiio_depth = ioc->hba_queue_depth - - ioc->hi_priority_depth - ioc->internal_depth; - - /* set the scsi host can_queue depth - * with some internal commands that could be outstanding - */ - ioc->shost->can_queue = ioc->scsiio_depth - (2); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsi host: " - "can_queue depth (%d)\n", ioc->name, ioc->shost->can_queue)); - - /* contiguous pool for request and chains, 16 byte align, one extra " - * "frame for smid=0 - */ - ioc->chain_depth = ioc->chains_needed_per_io * ioc->scsiio_depth; - sz = ((ioc->scsiio_depth + 1) * ioc->request_sz); - - /* hi-priority queue */ - sz += (ioc->hi_priority_depth * ioc->request_sz); - - /* internal queue */ - sz += (ioc->internal_depth * ioc->request_sz); - - ioc->request_dma_sz = sz; - ioc->request = pci_alloc_consistent(ioc->pdev, sz, &ioc->request_dma); - if (!ioc->request) { - printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " - "failed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kB)\n", ioc->name, ioc->hba_queue_depth, - ioc->chains_needed_per_io, ioc->request_sz, sz/1024); - if (ioc->scsiio_depth < MPT2SAS_SAS_QUEUE_DEPTH) - goto out; - retry_sz += 64; - ioc->hba_queue_depth = max_request_credit - retry_sz; - goto retry_allocation; - } - - if (retry_sz) - printk(MPT2SAS_ERR_FMT "request pool: pci_alloc_consistent " - "succeed: hba_depth(%d), chains_per_io(%d), frame_sz(%d), " - "total(%d kb)\n", ioc->name, ioc->hba_queue_depth, - ioc->chains_needed_per_io, ioc->request_sz, sz/1024); - - - /* hi-priority queue */ - ioc->hi_priority = ioc->request + ((ioc->scsiio_depth + 1) * - ioc->request_sz); - ioc->hi_priority_dma = ioc->request_dma + ((ioc->scsiio_depth + 1) * - ioc->request_sz); - - /* internal queue */ - ioc->internal = ioc->hi_priority + (ioc->hi_priority_depth * - ioc->request_sz); - ioc->internal_dma = ioc->hi_priority_dma + (ioc->hi_priority_depth * - ioc->request_sz); - - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool(0x%p): " - "depth(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->request, ioc->hba_queue_depth, ioc->request_sz, - (ioc->hba_queue_depth * ioc->request_sz)/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request pool: dma(0x%llx)\n", - ioc->name, (unsigned long long) ioc->request_dma)); - total_sz += sz; - - sz = ioc->scsiio_depth * sizeof(struct scsiio_tracker); - ioc->scsi_lookup_pages = get_order(sz); - ioc->scsi_lookup = (struct scsiio_tracker *)__get_free_pages( - GFP_KERNEL, ioc->scsi_lookup_pages); - if (!ioc->scsi_lookup) { - printk(MPT2SAS_ERR_FMT "scsi_lookup: get_free_pages failed, " - "sz(%d)\n", ioc->name, (int)sz); - goto out; - } - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "scsiio(0x%p): " - "depth(%d)\n", ioc->name, ioc->request, - ioc->scsiio_depth)); - - ioc->chain_depth = min_t(u32, ioc->chain_depth, MAX_CHAIN_DEPTH); - sz = ioc->chain_depth * sizeof(struct chain_tracker); - ioc->chain_pages = get_order(sz); - - ioc->chain_lookup = (struct chain_tracker *)__get_free_pages( - GFP_KERNEL, ioc->chain_pages); - if (!ioc->chain_lookup) { - printk(MPT2SAS_ERR_FMT "chain_lookup: get_free_pages failed, " - "sz(%d)\n", ioc->name, (int)sz); - goto out; - } - ioc->chain_dma_pool = pci_pool_create("chain pool", ioc->pdev, - ioc->request_sz, 16, 0); - if (!ioc->chain_dma_pool) { - printk(MPT2SAS_ERR_FMT "chain_dma_pool: pci_pool_create " - "failed\n", ioc->name); - goto out; - } - for (i = 0; i < ioc->chain_depth; i++) { - ioc->chain_lookup[i].chain_buffer = pci_pool_alloc( - ioc->chain_dma_pool , GFP_KERNEL, - &ioc->chain_lookup[i].chain_buffer_dma); - if (!ioc->chain_lookup[i].chain_buffer) { - ioc->chain_depth = i; - goto chain_done; - } - total_sz += ioc->request_sz; - } -chain_done: - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "chain pool depth" - "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->chain_depth, ioc->request_sz, ((ioc->chain_depth * - ioc->request_sz))/1024)); - - /* initialize hi-priority queue smid's */ - ioc->hpr_lookup = kcalloc(ioc->hi_priority_depth, - sizeof(struct request_tracker), GFP_KERNEL); - if (!ioc->hpr_lookup) { - printk(MPT2SAS_ERR_FMT "hpr_lookup: kcalloc failed\n", - ioc->name); - goto out; - } - ioc->hi_priority_smid = ioc->scsiio_depth + 1; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hi_priority(0x%p): " - "depth(%d), start smid(%d)\n", ioc->name, ioc->hi_priority, - ioc->hi_priority_depth, ioc->hi_priority_smid)); - - /* initialize internal queue smid's */ - ioc->internal_lookup = kcalloc(ioc->internal_depth, - sizeof(struct request_tracker), GFP_KERNEL); - if (!ioc->internal_lookup) { - printk(MPT2SAS_ERR_FMT "internal_lookup: kcalloc failed\n", - ioc->name); - goto out; - } - ioc->internal_smid = ioc->hi_priority_smid + ioc->hi_priority_depth; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "internal(0x%p): " - "depth(%d), start smid(%d)\n", ioc->name, ioc->internal, - ioc->internal_depth, ioc->internal_smid)); - - /* sense buffers, 4 byte align */ - sz = ioc->scsiio_depth * SCSI_SENSE_BUFFERSIZE; - ioc->sense_dma_pool = pci_pool_create("sense pool", ioc->pdev, sz, 4, - 0); - if (!ioc->sense_dma_pool) { - printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_create failed\n", - ioc->name); - goto out; - } - ioc->sense = pci_pool_alloc(ioc->sense_dma_pool , GFP_KERNEL, - &ioc->sense_dma); - if (!ioc->sense) { - printk(MPT2SAS_ERR_FMT "sense pool: pci_pool_alloc failed\n", - ioc->name); - goto out; - } - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "sense pool(0x%p): depth(%d), element_size(%d), pool_size" - "(%d kB)\n", ioc->name, ioc->sense, ioc->scsiio_depth, - SCSI_SENSE_BUFFERSIZE, sz/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "sense_dma(0x%llx)\n", - ioc->name, (unsigned long long)ioc->sense_dma)); - total_sz += sz; - - /* reply pool, 4 byte align */ - sz = ioc->reply_free_queue_depth * ioc->reply_sz; - ioc->reply_dma_pool = pci_pool_create("reply pool", ioc->pdev, sz, 4, - 0); - if (!ioc->reply_dma_pool) { - printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_create failed\n", - ioc->name); - goto out; - } - ioc->reply = pci_pool_alloc(ioc->reply_dma_pool , GFP_KERNEL, - &ioc->reply_dma); - if (!ioc->reply) { - printk(MPT2SAS_ERR_FMT "reply pool: pci_pool_alloc failed\n", - ioc->name); - goto out; - } - ioc->reply_dma_min_address = (u32)(ioc->reply_dma); - ioc->reply_dma_max_address = (u32)(ioc->reply_dma) + sz; - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply pool(0x%p): depth" - "(%d), frame_size(%d), pool_size(%d kB)\n", ioc->name, ioc->reply, - ioc->reply_free_queue_depth, ioc->reply_sz, sz/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_dma(0x%llx)\n", - ioc->name, (unsigned long long)ioc->reply_dma)); - total_sz += sz; - - /* reply free queue, 16 byte align */ - sz = ioc->reply_free_queue_depth * 4; - ioc->reply_free_dma_pool = pci_pool_create("reply_free pool", - ioc->pdev, sz, 16, 0); - if (!ioc->reply_free_dma_pool) { - printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_create " - "failed\n", ioc->name); - goto out; - } - ioc->reply_free = pci_pool_alloc(ioc->reply_free_dma_pool , GFP_KERNEL, - &ioc->reply_free_dma); - if (!ioc->reply_free) { - printk(MPT2SAS_ERR_FMT "reply_free pool: pci_pool_alloc " - "failed\n", ioc->name); - goto out; - } - memset(ioc->reply_free, 0, sz); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free pool(0x%p): " - "depth(%d), element_size(%d), pool_size(%d kB)\n", ioc->name, - ioc->reply_free, ioc->reply_free_queue_depth, 4, sz/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_free_dma" - "(0x%llx)\n", ioc->name, (unsigned long long)ioc->reply_free_dma)); - total_sz += sz; - - /* reply post queue, 16 byte align */ - reply_post_free_sz = ioc->reply_post_queue_depth * - sizeof(Mpi2DefaultReplyDescriptor_t); - if (_base_is_controller_msix_enabled(ioc)) - sz = reply_post_free_sz * ioc->reply_queue_count; - else - sz = reply_post_free_sz; - ioc->reply_post_free_dma_pool = pci_pool_create("reply_post_free pool", - ioc->pdev, sz, 16, 0); - if (!ioc->reply_post_free_dma_pool) { - printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_create " - "failed\n", ioc->name); - goto out; - } - ioc->reply_post_free = pci_pool_alloc(ioc->reply_post_free_dma_pool , - GFP_KERNEL, &ioc->reply_post_free_dma); - if (!ioc->reply_post_free) { - printk(MPT2SAS_ERR_FMT "reply_post_free pool: pci_pool_alloc " - "failed\n", ioc->name); - goto out; - } - memset(ioc->reply_post_free, 0, sz); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply post free pool" - "(0x%p): depth(%d), element_size(%d), pool_size(%d kB)\n", - ioc->name, ioc->reply_post_free, ioc->reply_post_queue_depth, 8, - sz/1024)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "reply_post_free_dma = " - "(0x%llx)\n", ioc->name, (unsigned long long) - ioc->reply_post_free_dma)); - total_sz += sz; - - ioc->config_page_sz = 512; - ioc->config_page = pci_alloc_consistent(ioc->pdev, - ioc->config_page_sz, &ioc->config_page_dma); - if (!ioc->config_page) { - printk(MPT2SAS_ERR_FMT "config page: pci_pool_alloc " - "failed\n", ioc->name); - goto out; - } - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config page(0x%p): size" - "(%d)\n", ioc->name, ioc->config_page, ioc->config_page_sz)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "config_page_dma" - "(0x%llx)\n", ioc->name, (unsigned long long)ioc->config_page_dma)); - total_sz += ioc->config_page_sz; - - printk(MPT2SAS_INFO_FMT "Allocated physical memory: size(%d kB)\n", - ioc->name, total_sz/1024); - printk(MPT2SAS_INFO_FMT "Current Controller Queue Depth(%d), " - "Max Controller Queue Depth(%d)\n", - ioc->name, ioc->shost->can_queue, facts->RequestCredit); - printk(MPT2SAS_INFO_FMT "Scatter Gather Elements per IO(%d)\n", - ioc->name, ioc->shost->sg_tablesize); - return 0; - - out: - return -ENOMEM; -} - - -/** - * mpt2sas_base_get_iocstate - Get the current state of a MPT adapter. - * @ioc: Pointer to MPT_ADAPTER structure - * @cooked: Request raw or cooked IOC state - * - * Returns all IOC Doorbell register bits if cooked==0, else just the - * Doorbell bits in MPI_IOC_STATE_MASK. - */ -u32 -mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked) -{ - u32 s, sc; - - s = readl(&ioc->chip->Doorbell); - sc = s & MPI2_IOC_STATE_MASK; - return cooked ? sc : s; -} - -/** - * _base_wait_on_iocstate - waiting on a particular ioc state - * @ioc_state: controller state { READY, OPERATIONAL, or RESET } - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_wait_on_iocstate(struct MPT2SAS_ADAPTER *ioc, u32 ioc_state, int timeout, - int sleep_flag) -{ - u32 count, cntdn; - u32 current_state; - - count = 0; - cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; - do { - current_state = mpt2sas_base_get_iocstate(ioc, 1); - if (current_state == ioc_state) - return 0; - if (count && current_state == MPI2_IOC_STATE_FAULT) - break; - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - udelay(500); - count++; - } while (--cntdn); - - return current_state; -} - -/** - * _base_wait_for_doorbell_int - waiting for controller interrupt(generated by - * a write to the doorbell) - * @ioc: per adapter object - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - * - * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. - */ -static int -_base_wait_for_doorbell_int(struct MPT2SAS_ADAPTER *ioc, int timeout, - int sleep_flag) -{ - u32 cntdn, count; - u32 int_status; - - count = 0; - cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; - do { - int_status = readl(&ioc->chip->HostInterruptStatus); - if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successful count(%d), timeout(%d)\n", ioc->name, - __func__, count, timeout)); - return 0; - } - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - udelay(500); - count++; - } while (--cntdn); - - printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " - "int_status(%x)!\n", ioc->name, __func__, count, int_status); - return -EFAULT; -} - -/** - * _base_wait_for_doorbell_ack - waiting for controller to read the doorbell. - * @ioc: per adapter object - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - * - * Notes: MPI2_HIS_SYS2IOC_DB_STATUS - set to one when host writes to - * doorbell. - */ -static int -_base_wait_for_doorbell_ack(struct MPT2SAS_ADAPTER *ioc, int timeout, - int sleep_flag) -{ - u32 cntdn, count; - u32 int_status; - u32 doorbell; - - count = 0; - cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; - do { - int_status = readl(&ioc->chip->HostInterruptStatus); - if (!(int_status & MPI2_HIS_SYS2IOC_DB_STATUS)) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successful count(%d), timeout(%d)\n", ioc->name, - __func__, count, timeout)); - return 0; - } else if (int_status & MPI2_HIS_IOC2SYS_DB_STATUS) { - doorbell = readl(&ioc->chip->Doorbell); - if ((doorbell & MPI2_IOC_STATE_MASK) == - MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc , doorbell); - return -EFAULT; - } - } else if (int_status == 0xFFFFFFFF) - goto out; - - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - udelay(500); - count++; - } while (--cntdn); - - out: - printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " - "int_status(%x)!\n", ioc->name, __func__, count, int_status); - return -EFAULT; -} - -/** - * _base_wait_for_doorbell_not_used - waiting for doorbell to not be in use - * @ioc: per adapter object - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_base_wait_for_doorbell_not_used(struct MPT2SAS_ADAPTER *ioc, int timeout, - int sleep_flag) -{ - u32 cntdn, count; - u32 doorbell_reg; - - count = 0; - cntdn = (sleep_flag == CAN_SLEEP) ? 1000*timeout : 2000*timeout; - do { - doorbell_reg = readl(&ioc->chip->Doorbell); - if (!(doorbell_reg & MPI2_DOORBELL_USED)) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "successful count(%d), timeout(%d)\n", ioc->name, - __func__, count, timeout)); - return 0; - } - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - udelay(500); - count++; - } while (--cntdn); - - printk(MPT2SAS_ERR_FMT "%s: failed due to timeout count(%d), " - "doorbell_reg(%x)!\n", ioc->name, __func__, count, doorbell_reg); - return -EFAULT; -} - -/** - * _base_send_ioc_reset - send doorbell reset - * @ioc: per adapter object - * @reset_type: currently only supports: MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_send_ioc_reset(struct MPT2SAS_ADAPTER *ioc, u8 reset_type, int timeout, - int sleep_flag) -{ - u32 ioc_state; - int r = 0; - - if (reset_type != MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET) { - printk(MPT2SAS_ERR_FMT "%s: unknown reset_type\n", - ioc->name, __func__); - return -EFAULT; - } - - if (!(ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_EVENT_REPLAY)) - return -EFAULT; - - printk(MPT2SAS_INFO_FMT "sending message unit reset !!\n", ioc->name); - - writel(reset_type << MPI2_DOORBELL_FUNCTION_SHIFT, - &ioc->chip->Doorbell); - if ((_base_wait_for_doorbell_ack(ioc, 15, sleep_flag))) { - r = -EFAULT; - goto out; - } - ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, - timeout, sleep_flag); - if (ioc_state) { - printk(MPT2SAS_ERR_FMT "%s: failed going to ready state " - " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); - r = -EFAULT; - goto out; - } - out: - printk(MPT2SAS_INFO_FMT "message unit reset: %s\n", - ioc->name, ((r == 0) ? "SUCCESS" : "FAILED")); - return r; -} - -/** - * _base_handshake_req_reply_wait - send request thru doorbell interface - * @ioc: per adapter object - * @request_bytes: request length - * @request: pointer having request payload - * @reply_bytes: reply length - * @reply: pointer to reply payload - * @timeout: timeout in second - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_handshake_req_reply_wait(struct MPT2SAS_ADAPTER *ioc, int request_bytes, - u32 *request, int reply_bytes, u16 *reply, int timeout, int sleep_flag) -{ - MPI2DefaultReply_t *default_reply = (MPI2DefaultReply_t *)reply; - int i; - u8 failed; - u16 dummy; - __le32 *mfp; - - /* make sure doorbell is not in use */ - if ((readl(&ioc->chip->Doorbell) & MPI2_DOORBELL_USED)) { - printk(MPT2SAS_ERR_FMT "doorbell is in use " - " (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - - /* clear pending doorbell interrupts from previous state changes */ - if (readl(&ioc->chip->HostInterruptStatus) & - MPI2_HIS_IOC2SYS_DB_STATUS) - writel(0, &ioc->chip->HostInterruptStatus); - - /* send message to ioc */ - writel(((MPI2_FUNCTION_HANDSHAKE<chip->Doorbell); - - if ((_base_wait_for_doorbell_int(ioc, 5, NO_SLEEP))) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "int failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - writel(0, &ioc->chip->HostInterruptStatus); - - if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "ack failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - - /* send message 32-bits at a time */ - for (i = 0, failed = 0; i < request_bytes/4 && !failed; i++) { - writel(cpu_to_le32(request[i]), &ioc->chip->Doorbell); - if ((_base_wait_for_doorbell_ack(ioc, 5, sleep_flag))) - failed = 1; - } - - if (failed) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "sending request failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - - /* now wait for the reply */ - if ((_base_wait_for_doorbell_int(ioc, timeout, sleep_flag))) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "int failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - - /* read the first two 16-bits, it gives the total length of the reply */ - reply[0] = le16_to_cpu(readl(&ioc->chip->Doorbell) - & MPI2_DOORBELL_DATA_MASK); - writel(0, &ioc->chip->HostInterruptStatus); - if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { - printk(MPT2SAS_ERR_FMT "doorbell handshake " - "int failed (line=%d)\n", ioc->name, __LINE__); - return -EFAULT; - } - reply[1] = le16_to_cpu(readl(&ioc->chip->Doorbell) - & MPI2_DOORBELL_DATA_MASK); - writel(0, &ioc->chip->HostInterruptStatus); - - for (i = 2; i < default_reply->MsgLength * 2; i++) { - if ((_base_wait_for_doorbell_int(ioc, 5, sleep_flag))) { - printk(MPT2SAS_ERR_FMT "doorbell " - "handshake int failed (line=%d)\n", ioc->name, - __LINE__); - return -EFAULT; - } - if (i >= reply_bytes/2) /* overflow case */ - dummy = readl(&ioc->chip->Doorbell); - else - reply[i] = le16_to_cpu(readl(&ioc->chip->Doorbell) - & MPI2_DOORBELL_DATA_MASK); - writel(0, &ioc->chip->HostInterruptStatus); - } - - _base_wait_for_doorbell_int(ioc, 5, sleep_flag); - if (_base_wait_for_doorbell_not_used(ioc, 5, sleep_flag) != 0) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "doorbell is in use " - " (line=%d)\n", ioc->name, __LINE__)); - } - writel(0, &ioc->chip->HostInterruptStatus); - - if (ioc->logging_level & MPT_DEBUG_INIT) { - mfp = (__le32 *)reply; - printk(KERN_INFO "\toffset:data\n"); - for (i = 0; i < reply_bytes/4; i++) - printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, - le32_to_cpu(mfp[i])); - } - return 0; -} - -/** - * mpt2sas_base_sas_iounit_control - send sas iounit control to FW - * @ioc: per adapter object - * @mpi_reply: the reply payload from FW - * @mpi_request: the request payload sent to FW - * - * The SAS IO Unit Control Request message allows the host to perform low-level - * operations, such as resets on the PHYs of the IO Unit, also allows the host - * to obtain the IOC assigned device handles for a device if it has other - * identifying information about the device, in addition allows the host to - * remove IOC resources associated with the device. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, - Mpi2SasIoUnitControlReply_t *mpi_reply, - Mpi2SasIoUnitControlRequest_t *mpi_request) -{ - u16 smid; - u32 ioc_state; - unsigned long timeleft; - u8 issue_reset; - int rc; - void *request; - u16 wait_state_count; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mutex_lock(&ioc->base_cmds.mutex); - - if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - ioc->base_cmds.status = MPT2_CMD_PENDING; - request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->base_cmds.smid = smid; - memcpy(request, mpi_request, sizeof(Mpi2SasIoUnitControlRequest_t)); - if (mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || - mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) - ioc->ioc_link_reset_in_progress = 1; - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, - msecs_to_jiffies(10000)); - if ((mpi_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET || - mpi_request->Operation == MPI2_SAS_OP_PHY_LINK_RESET) && - ioc->ioc_link_reset_in_progress) - ioc->ioc_link_reset_in_progress = 0; - if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SasIoUnitControlRequest_t)/4); - if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) - memcpy(mpi_reply, ioc->base_cmds.reply, - sizeof(Mpi2SasIoUnitControlReply_t)); - else - memset(mpi_reply, 0, sizeof(Mpi2SasIoUnitControlReply_t)); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - goto out; - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - rc = -EFAULT; - out: - mutex_unlock(&ioc->base_cmds.mutex); - return rc; -} - - -/** - * mpt2sas_base_scsi_enclosure_processor - sending request to sep device - * @ioc: per adapter object - * @mpi_reply: the reply payload from FW - * @mpi_request: the request payload sent to FW - * - * The SCSI Enclosure Processor request message causes the IOC to - * communicate with SES devices to control LED status signals. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, - Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request) -{ - u16 smid; - u32 ioc_state; - unsigned long timeleft; - u8 issue_reset; - int rc; - void *request; - u16 wait_state_count; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mutex_lock(&ioc->base_cmds.mutex); - - if (ioc->base_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: base_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - ioc->base_cmds.status = MPT2_CMD_PENDING; - request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->base_cmds.smid = smid; - memcpy(request, mpi_request, sizeof(Mpi2SepReply_t)); - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, - msecs_to_jiffies(10000)); - if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SepRequest_t)/4); - if (!(ioc->base_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID) - memcpy(mpi_reply, ioc->base_cmds.reply, - sizeof(Mpi2SepReply_t)); - else - memset(mpi_reply, 0, sizeof(Mpi2SepReply_t)); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - goto out; - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - rc = -EFAULT; - out: - mutex_unlock(&ioc->base_cmds.mutex); - return rc; -} - -/** - * _base_get_port_facts - obtain port facts reply and save in ioc - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_get_port_facts(struct MPT2SAS_ADAPTER *ioc, int port, int sleep_flag) -{ - Mpi2PortFactsRequest_t mpi_request; - Mpi2PortFactsReply_t mpi_reply; - struct mpt2sas_port_facts *pfacts; - int mpi_reply_sz, mpi_request_sz, r; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mpi_reply_sz = sizeof(Mpi2PortFactsReply_t); - mpi_request_sz = sizeof(Mpi2PortFactsRequest_t); - memset(&mpi_request, 0, mpi_request_sz); - mpi_request.Function = MPI2_FUNCTION_PORT_FACTS; - mpi_request.PortNumber = port; - r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, - (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); - - if (r != 0) { - printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); - return r; - } - - pfacts = &ioc->pfacts[port]; - memset(pfacts, 0, sizeof(struct mpt2sas_port_facts)); - pfacts->PortNumber = mpi_reply.PortNumber; - pfacts->VP_ID = mpi_reply.VP_ID; - pfacts->VF_ID = mpi_reply.VF_ID; - pfacts->MaxPostedCmdBuffers = - le16_to_cpu(mpi_reply.MaxPostedCmdBuffers); - - return 0; -} - -/** - * _base_get_ioc_facts - obtain ioc facts reply and save in ioc - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_get_ioc_facts(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2IOCFactsRequest_t mpi_request; - Mpi2IOCFactsReply_t mpi_reply; - struct mpt2sas_facts *facts; - int mpi_reply_sz, mpi_request_sz, r; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); - mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t); - memset(&mpi_request, 0, mpi_request_sz); - mpi_request.Function = MPI2_FUNCTION_IOC_FACTS; - r = _base_handshake_req_reply_wait(ioc, mpi_request_sz, - (u32 *)&mpi_request, mpi_reply_sz, (u16 *)&mpi_reply, 5, CAN_SLEEP); - - if (r != 0) { - printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); - return r; - } - - facts = &ioc->facts; - memset(facts, 0, sizeof(struct mpt2sas_facts)); - facts->MsgVersion = le16_to_cpu(mpi_reply.MsgVersion); - facts->HeaderVersion = le16_to_cpu(mpi_reply.HeaderVersion); - facts->VP_ID = mpi_reply.VP_ID; - facts->VF_ID = mpi_reply.VF_ID; - facts->IOCExceptions = le16_to_cpu(mpi_reply.IOCExceptions); - facts->MaxChainDepth = mpi_reply.MaxChainDepth; - facts->WhoInit = mpi_reply.WhoInit; - facts->NumberOfPorts = mpi_reply.NumberOfPorts; - facts->MaxMSIxVectors = mpi_reply.MaxMSIxVectors; - facts->RequestCredit = le16_to_cpu(mpi_reply.RequestCredit); - facts->MaxReplyDescriptorPostQueueDepth = - le16_to_cpu(mpi_reply.MaxReplyDescriptorPostQueueDepth); - facts->ProductID = le16_to_cpu(mpi_reply.ProductID); - facts->IOCCapabilities = le32_to_cpu(mpi_reply.IOCCapabilities); - if ((facts->IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_INTEGRATED_RAID)) - ioc->ir_firmware = 1; - facts->FWVersion.Word = le32_to_cpu(mpi_reply.FWVersion.Word); - facts->IOCRequestFrameSize = - le16_to_cpu(mpi_reply.IOCRequestFrameSize); - facts->MaxInitiators = le16_to_cpu(mpi_reply.MaxInitiators); - facts->MaxTargets = le16_to_cpu(mpi_reply.MaxTargets); - ioc->shost->max_id = -1; - facts->MaxSasExpanders = le16_to_cpu(mpi_reply.MaxSasExpanders); - facts->MaxEnclosures = le16_to_cpu(mpi_reply.MaxEnclosures); - facts->ProtocolFlags = le16_to_cpu(mpi_reply.ProtocolFlags); - facts->HighPriorityCredit = - le16_to_cpu(mpi_reply.HighPriorityCredit); - facts->ReplyFrameSize = mpi_reply.ReplyFrameSize; - facts->MaxDevHandle = le16_to_cpu(mpi_reply.MaxDevHandle); - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "hba queue depth(%d), " - "max chains per io(%d)\n", ioc->name, facts->RequestCredit, - facts->MaxChainDepth)); - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "request frame size(%d), " - "reply frame size(%d)\n", ioc->name, - facts->IOCRequestFrameSize * 4, facts->ReplyFrameSize * 4)); - return 0; -} - -/** - * _base_send_ioc_init - send ioc_init to firmware - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_send_ioc_init(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2IOCInitRequest_t mpi_request; - Mpi2IOCInitReply_t mpi_reply; - int r; - struct timeval current_time; - u16 ioc_status; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - memset(&mpi_request, 0, sizeof(Mpi2IOCInitRequest_t)); - mpi_request.Function = MPI2_FUNCTION_IOC_INIT; - mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; - mpi_request.VF_ID = 0; /* TODO */ - mpi_request.VP_ID = 0; - mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); - mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); - - if (_base_is_controller_msix_enabled(ioc)) - mpi_request.HostMSIxVectors = ioc->reply_queue_count; - mpi_request.SystemRequestFrameSize = cpu_to_le16(ioc->request_sz/4); - mpi_request.ReplyDescriptorPostQueueDepth = - cpu_to_le16(ioc->reply_post_queue_depth); - mpi_request.ReplyFreeQueueDepth = - cpu_to_le16(ioc->reply_free_queue_depth); - - mpi_request.SenseBufferAddressHigh = - cpu_to_le32((u64)ioc->sense_dma >> 32); - mpi_request.SystemReplyAddressHigh = - cpu_to_le32((u64)ioc->reply_dma >> 32); - mpi_request.SystemRequestFrameBaseAddress = - cpu_to_le64((u64)ioc->request_dma); - mpi_request.ReplyFreeQueueAddress = - cpu_to_le64((u64)ioc->reply_free_dma); - mpi_request.ReplyDescriptorPostQueueAddress = - cpu_to_le64((u64)ioc->reply_post_free_dma); - - - /* This time stamp specifies number of milliseconds - * since epoch ~ midnight January 1, 1970. - */ - do_gettimeofday(¤t_time); - mpi_request.TimeStamp = cpu_to_le64((u64)current_time.tv_sec * 1000 + - (current_time.tv_usec / 1000)); - - if (ioc->logging_level & MPT_DEBUG_INIT) { - __le32 *mfp; - int i; - - mfp = (__le32 *)&mpi_request; - printk(KERN_INFO "\toffset:data\n"); - for (i = 0; i < sizeof(Mpi2IOCInitRequest_t)/4; i++) - printk(KERN_INFO "\t[0x%02x]:%08x\n", i*4, - le32_to_cpu(mfp[i])); - } - - r = _base_handshake_req_reply_wait(ioc, - sizeof(Mpi2IOCInitRequest_t), (u32 *)&mpi_request, - sizeof(Mpi2IOCInitReply_t), (u16 *)&mpi_reply, 10, - sleep_flag); - - if (r != 0) { - printk(MPT2SAS_ERR_FMT "%s: handshake failed (r=%d)\n", - ioc->name, __func__, r); - return r; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS || - mpi_reply.IOCLogInfo) { - printk(MPT2SAS_ERR_FMT "%s: failed\n", ioc->name, __func__); - r = -EIO; - } - - return 0; -} - -/** - * mpt2sas_port_enable_done - command completion routine for port enable - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - u16 ioc_status; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply && mpi_reply->Function == MPI2_FUNCTION_EVENT_ACK) - return 1; - - if (ioc->port_enable_cmds.status == MPT2_CMD_NOT_USED) - return 1; - - ioc->port_enable_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - ioc->port_enable_cmds.status |= MPT2_CMD_REPLY_VALID; - memcpy(ioc->port_enable_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - } - ioc->port_enable_cmds.status &= ~MPT2_CMD_PENDING; - - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - ioc->port_enable_failed = 1; - - if (ioc->is_driver_loading) { - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - mpt2sas_port_enable_complete(ioc); - return 1; - } else { - ioc->start_scan_failed = ioc_status; - ioc->start_scan = 0; - return 1; - } - } - complete(&ioc->port_enable_cmds.done); - return 1; -} - - -/** - * _base_send_port_enable - send port_enable(discovery stuff) to firmware - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_send_port_enable(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2PortEnableRequest_t *mpi_request; - Mpi2PortEnableReply_t *mpi_reply; - unsigned long timeleft; - int r = 0; - u16 smid; - u16 ioc_status; - - printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); - - if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { - printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", - ioc->name, __func__); - return -EAGAIN; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return -EAGAIN; - } - - ioc->port_enable_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->port_enable_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); - mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - - init_completion(&ioc->port_enable_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->port_enable_cmds.done, - 300*HZ); - if (!(ioc->port_enable_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2PortEnableRequest_t)/4); - if (ioc->port_enable_cmds.status & MPT2_CMD_RESET) - r = -EFAULT; - else - r = -ETIME; - goto out; - } - mpi_reply = ioc->port_enable_cmds.reply; - - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "%s: failed with (ioc_status=0x%08x)\n", - ioc->name, __func__, ioc_status); - r = -EFAULT; - goto out; - } - out: - ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; - printk(MPT2SAS_INFO_FMT "port enable: %s\n", ioc->name, ((r == 0) ? - "SUCCESS" : "FAILED")); - return r; -} - -/** - * mpt2sas_port_enable - initiate firmware discovery (don't wait for reply) - * @ioc: per adapter object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2PortEnableRequest_t *mpi_request; - u16 smid; - - printk(MPT2SAS_INFO_FMT "sending port enable !!\n", ioc->name); - - if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { - printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", - ioc->name, __func__); - return -EAGAIN; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->port_enable_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return -EAGAIN; - } - - ioc->port_enable_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->port_enable_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2PortEnableRequest_t)); - mpi_request->Function = MPI2_FUNCTION_PORT_ENABLE; - - mpt2sas_base_put_smid_default(ioc, smid); - return 0; -} - -/** - * _base_determine_wait_on_discovery - desposition - * @ioc: per adapter object - * - * Decide whether to wait on discovery to complete. Used to either - * locate boot device, or report volumes ahead of physical devices. - * - * Returns 1 for wait, 0 for don't wait - */ -static int -_base_determine_wait_on_discovery(struct MPT2SAS_ADAPTER *ioc) -{ - /* We wait for discovery to complete if IR firmware is loaded. - * The sas topology events arrive before PD events, so we need time to - * turn on the bit in ioc->pd_handles to indicate PD - * Also, it maybe required to report Volumes ahead of physical - * devices when MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING is set. - */ - if (ioc->ir_firmware) - return 1; - - /* if no Bios, then we don't need to wait */ - if (!ioc->bios_pg3.BiosVersion) - return 0; - - /* Bios is present, then we drop down here. - * - * If there any entries in the Bios Page 2, then we wait - * for discovery to complete. - */ - - /* Current Boot Device */ - if ((ioc->bios_pg2.CurrentBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && - /* Request Boot Device */ - (ioc->bios_pg2.ReqBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED && - /* Alternate Request Boot Device */ - (ioc->bios_pg2.ReqAltBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK) == - MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED) - return 0; - - return 1; -} - - -/** - * _base_unmask_events - turn on notification for this event - * @ioc: per adapter object - * @event: firmware event - * - * The mask is stored in ioc->event_masks. - */ -static void -_base_unmask_events(struct MPT2SAS_ADAPTER *ioc, u16 event) -{ - u32 desired_event; - - if (event >= 128) - return; - - desired_event = (1 << (event % 32)); - - if (event < 32) - ioc->event_masks[0] &= ~desired_event; - else if (event < 64) - ioc->event_masks[1] &= ~desired_event; - else if (event < 96) - ioc->event_masks[2] &= ~desired_event; - else if (event < 128) - ioc->event_masks[3] &= ~desired_event; -} - -/** - * _base_event_notification - send event notification - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_event_notification(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - Mpi2EventNotificationRequest_t *mpi_request; - unsigned long timeleft; - u16 smid; - int r = 0; - int i; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->base_cmds.status & MPT2_CMD_PENDING) { - printk(MPT2SAS_ERR_FMT "%s: internal command already in use\n", - ioc->name, __func__); - return -EAGAIN; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->base_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return -EAGAIN; - } - ioc->base_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->base_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2EventNotificationRequest_t)); - mpi_request->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) - mpi_request->EventMasks[i] = - cpu_to_le32(ioc->event_masks[i]); - init_completion(&ioc->base_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->base_cmds.done, 30*HZ); - if (!(ioc->base_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2EventNotificationRequest_t)/4); - if (ioc->base_cmds.status & MPT2_CMD_RESET) - r = -EFAULT; - else - r = -ETIME; - } else - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: complete\n", - ioc->name, __func__)); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - return r; -} - -/** - * mpt2sas_base_validate_event_type - validating event types - * @ioc: per adapter object - * @event: firmware event - * - * This will turn on firmware event notification when application - * ask for that event. We don't mask events that are already enabled. - */ -void -mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type) -{ - int i, j; - u32 event_mask, desired_event; - u8 send_update_to_fw; - - for (i = 0, send_update_to_fw = 0; i < - MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) { - event_mask = ~event_type[i]; - desired_event = 1; - for (j = 0; j < 32; j++) { - if (!(event_mask & desired_event) && - (ioc->event_masks[i] & desired_event)) { - ioc->event_masks[i] &= ~desired_event; - send_update_to_fw = 1; - } - desired_event = (desired_event << 1); - } - } - - if (!send_update_to_fw) - return; - - mutex_lock(&ioc->base_cmds.mutex); - _base_event_notification(ioc, CAN_SLEEP); - mutex_unlock(&ioc->base_cmds.mutex); -} - -/** - * _base_diag_reset - the "big hammer" start of day reset - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_diag_reset(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - u32 host_diagnostic; - u32 ioc_state; - u32 count; - u32 hcb_size; - - printk(MPT2SAS_INFO_FMT "sending diag reset !!\n", ioc->name); - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "clear interrupts\n", - ioc->name)); - - count = 0; - do { - /* Write magic sequence to WriteSequence register - * Loop until in diagnostic mode - */ - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "write magic " - "sequence\n", ioc->name)); - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_1ST_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_2ND_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_3RD_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_4TH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_5TH_KEY_VALUE, &ioc->chip->WriteSequence); - writel(MPI2_WRSEQ_6TH_KEY_VALUE, &ioc->chip->WriteSequence); - - /* wait 100 msec */ - if (sleep_flag == CAN_SLEEP) - msleep(100); - else - mdelay(100); - - if (count++ > 20) - goto out; - - host_diagnostic = readl(&ioc->chip->HostDiagnostic); - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "wrote magic " - "sequence: count(%d), host_diagnostic(0x%08x)\n", - ioc->name, count, host_diagnostic)); - - } while ((host_diagnostic & MPI2_DIAG_DIAG_WRITE_ENABLE) == 0); - - hcb_size = readl(&ioc->chip->HCBSize); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "diag reset: issued\n", - ioc->name)); - writel(host_diagnostic | MPI2_DIAG_RESET_ADAPTER, - &ioc->chip->HostDiagnostic); - - /* don't access any registers for 50 milliseconds */ - msleep(50); - - /* 300 second max wait */ - for (count = 0; count < 3000000 ; count++) { - - host_diagnostic = readl(&ioc->chip->HostDiagnostic); - - if (host_diagnostic == 0xFFFFFFFF) - goto out; - if (!(host_diagnostic & MPI2_DIAG_RESET_ADAPTER)) - break; - - /* wait 100 msec */ - if (sleep_flag == CAN_SLEEP) - msleep(1); - else - mdelay(1); - } - - if (host_diagnostic & MPI2_DIAG_HCB_MODE) { - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter " - "assuming the HCB Address points to good F/W\n", - ioc->name)); - host_diagnostic &= ~MPI2_DIAG_BOOT_DEVICE_SELECT_MASK; - host_diagnostic |= MPI2_DIAG_BOOT_DEVICE_SELECT_HCDW; - writel(host_diagnostic, &ioc->chip->HostDiagnostic); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT - "re-enable the HCDW\n", ioc->name)); - writel(hcb_size | MPI2_HCB_SIZE_HCB_ENABLE, - &ioc->chip->HCBSize); - } - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "restart the adapter\n", - ioc->name)); - writel(host_diagnostic & ~MPI2_DIAG_HOLD_IOC_RESET, - &ioc->chip->HostDiagnostic); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "disable writes to the " - "diagnostic register\n", ioc->name)); - writel(MPI2_WRSEQ_FLUSH_KEY_VALUE, &ioc->chip->WriteSequence); - - drsprintk(ioc, printk(MPT2SAS_INFO_FMT "Wait for FW to go to the " - "READY state\n", ioc->name)); - ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, 20, - sleep_flag); - if (ioc_state) { - printk(MPT2SAS_ERR_FMT "%s: failed going to ready state " - " (ioc_state=0x%x)\n", ioc->name, __func__, ioc_state); - goto out; - } - - printk(MPT2SAS_INFO_FMT "diag reset: SUCCESS\n", ioc->name); - return 0; - - out: - printk(MPT2SAS_ERR_FMT "diag reset: FAILED\n", ioc->name); - return -EFAULT; -} - -/** - * _base_make_ioc_ready - put controller in READY state - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * @type: FORCE_BIG_HAMMER or SOFT_RESET - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_make_ioc_ready(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, - enum reset_type type) -{ - u32 ioc_state; - int rc; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->pci_error_recovery) - return 0; - - ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: ioc_state(0x%08x)\n", - ioc->name, __func__, ioc_state)); - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) - return 0; - - if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " - "active!\n", ioc->name)); - goto issue_diag_reset; - } - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc, ioc_state & - MPI2_DOORBELL_DATA_MASK); - goto issue_diag_reset; - } - - if (type == FORCE_BIG_HAMMER) - goto issue_diag_reset; - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) - if (!(_base_send_ioc_reset(ioc, - MPI2_FUNCTION_IOC_MESSAGE_UNIT_RESET, 15, CAN_SLEEP))) { - ioc->ioc_reset_count++; - return 0; - } - - issue_diag_reset: - rc = _base_diag_reset(ioc, CAN_SLEEP); - ioc->ioc_reset_count++; - return rc; -} - -/** - * _base_make_ioc_operational - put controller in OPERATIONAL state - * @ioc: per adapter object - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * Returns 0 for success, non-zero for failure. - */ -static int -_base_make_ioc_operational(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - int r, i; - unsigned long flags; - u32 reply_address; - u16 smid; - struct _tr_list *delayed_tr, *delayed_tr_next; - u8 hide_flag; - struct adapter_reply_queue *reply_q; - long reply_post_free; - u32 reply_post_free_sz; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - /* clean the delayed target reset list */ - list_for_each_entry_safe(delayed_tr, delayed_tr_next, - &ioc->delayed_tr_list, list) { - list_del(&delayed_tr->list); - kfree(delayed_tr); - } - - list_for_each_entry_safe(delayed_tr, delayed_tr_next, - &ioc->delayed_tr_volume_list, list) { - list_del(&delayed_tr->list); - kfree(delayed_tr); - } - - /* initialize the scsi lookup free list */ - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - INIT_LIST_HEAD(&ioc->free_list); - smid = 1; - for (i = 0; i < ioc->scsiio_depth; i++, smid++) { - INIT_LIST_HEAD(&ioc->scsi_lookup[i].chain_list); - ioc->scsi_lookup[i].cb_idx = 0xFF; - ioc->scsi_lookup[i].smid = smid; - ioc->scsi_lookup[i].scmd = NULL; - ioc->scsi_lookup[i].direct_io = 0; - list_add_tail(&ioc->scsi_lookup[i].tracker_list, - &ioc->free_list); - } - - /* hi-priority queue */ - INIT_LIST_HEAD(&ioc->hpr_free_list); - smid = ioc->hi_priority_smid; - for (i = 0; i < ioc->hi_priority_depth; i++, smid++) { - ioc->hpr_lookup[i].cb_idx = 0xFF; - ioc->hpr_lookup[i].smid = smid; - list_add_tail(&ioc->hpr_lookup[i].tracker_list, - &ioc->hpr_free_list); - } - - /* internal queue */ - INIT_LIST_HEAD(&ioc->internal_free_list); - smid = ioc->internal_smid; - for (i = 0; i < ioc->internal_depth; i++, smid++) { - ioc->internal_lookup[i].cb_idx = 0xFF; - ioc->internal_lookup[i].smid = smid; - list_add_tail(&ioc->internal_lookup[i].tracker_list, - &ioc->internal_free_list); - } - - /* chain pool */ - INIT_LIST_HEAD(&ioc->free_chain_list); - for (i = 0; i < ioc->chain_depth; i++) - list_add_tail(&ioc->chain_lookup[i].tracker_list, - &ioc->free_chain_list); - - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - /* initialize Reply Free Queue */ - for (i = 0, reply_address = (u32)ioc->reply_dma ; - i < ioc->reply_free_queue_depth ; i++, reply_address += - ioc->reply_sz) - ioc->reply_free[i] = cpu_to_le32(reply_address); - - /* initialize reply queues */ - if (ioc->is_driver_loading) - _base_assign_reply_queues(ioc); - - /* initialize Reply Post Free Queue */ - reply_post_free = (long)ioc->reply_post_free; - reply_post_free_sz = ioc->reply_post_queue_depth * - sizeof(Mpi2DefaultReplyDescriptor_t); - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - reply_q->reply_post_host_index = 0; - reply_q->reply_post_free = (Mpi2ReplyDescriptorsUnion_t *) - reply_post_free; - for (i = 0; i < ioc->reply_post_queue_depth; i++) - reply_q->reply_post_free[i].Words = - cpu_to_le64(ULLONG_MAX); - if (!_base_is_controller_msix_enabled(ioc)) - goto skip_init_reply_post_free_queue; - reply_post_free += reply_post_free_sz; - } - skip_init_reply_post_free_queue: - - r = _base_send_ioc_init(ioc, sleep_flag); - if (r) - return r; - - /* initialize reply free host index */ - ioc->reply_free_host_index = ioc->reply_free_queue_depth - 1; - writel(ioc->reply_free_host_index, &ioc->chip->ReplyFreeHostIndex); - - /* initialize reply post host index */ - list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT, - &ioc->chip->ReplyPostHostIndex); - if (!_base_is_controller_msix_enabled(ioc)) - goto skip_init_reply_post_host_index; - } - - skip_init_reply_post_host_index: - - _base_unmask_interrupts(ioc); - - r = _base_event_notification(ioc, sleep_flag); - if (r) - return r; - - if (sleep_flag == CAN_SLEEP) - _base_static_config_pages(ioc); - - - if (ioc->is_driver_loading) { - if (ioc->is_warpdrive && ioc->manu_pg10.OEMIdentifier - == 0x80) { - hide_flag = (u8) (ioc->manu_pg10.OEMSpecificFlags0 & - MFG_PAGE10_HIDE_SSDS_MASK); - if (hide_flag != MFG_PAGE10_HIDE_SSDS_MASK) - ioc->mfg_pg10_hide_flag = hide_flag; - } - ioc->wait_for_discovery_to_complete = - _base_determine_wait_on_discovery(ioc); - return r; /* scan_start and scan_finished support */ - } - r = _base_send_port_enable(ioc, sleep_flag); - if (r) - return r; - - return r; -} - -/** - * mpt2sas_base_free_resources - free resources controller resources (io/irq/memap) - * @ioc: per adapter object - * - * Return nothing. - */ -void -mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) -{ - struct pci_dev *pdev = ioc->pdev; - - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - _base_mask_interrupts(ioc); - ioc->shost_recovery = 1; - _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); - ioc->shost_recovery = 0; - _base_free_irq(ioc); - _base_disable_msix(ioc); - if (ioc->chip_phys) - iounmap(ioc->chip); - ioc->chip_phys = 0; - pci_release_selected_regions(ioc->pdev, ioc->bars); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - return; -} - -/** - * mpt2sas_base_attach - attach controller instance - * @ioc: per adapter object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc) -{ - int r, i; - int cpu_id, last_cpu_id = 0; - - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - /* setup cpu_msix_table */ - ioc->cpu_count = num_online_cpus(); - for_each_online_cpu(cpu_id) - last_cpu_id = cpu_id; - ioc->cpu_msix_table_sz = last_cpu_id + 1; - ioc->cpu_msix_table = kzalloc(ioc->cpu_msix_table_sz, GFP_KERNEL); - ioc->reply_queue_count = 1; - if (!ioc->cpu_msix_table) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation for " - "cpu_msix_table failed!!!\n", ioc->name)); - r = -ENOMEM; - goto out_free_resources; - } - - if (ioc->is_warpdrive) { - ioc->reply_post_host_index = kcalloc(ioc->cpu_msix_table_sz, - sizeof(resource_size_t *), GFP_KERNEL); - if (!ioc->reply_post_host_index) { - dfailprintk(ioc, printk(MPT2SAS_INFO_FMT "allocation " - "for cpu_msix_table failed!!!\n", ioc->name)); - r = -ENOMEM; - goto out_free_resources; - } - } - - r = mpt2sas_base_map_resources(ioc); - if (r) - goto out_free_resources; - - if (ioc->is_warpdrive) { - ioc->reply_post_host_index[0] = - (resource_size_t *)&ioc->chip->ReplyPostHostIndex; - - for (i = 1; i < ioc->cpu_msix_table_sz; i++) - ioc->reply_post_host_index[i] = (resource_size_t *) - ((u8 *)&ioc->chip->Doorbell + (0x4000 + ((i - 1) - * 4))); - } - - pci_set_drvdata(ioc->pdev, ioc->shost); - r = _base_get_ioc_facts(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - r = _base_make_ioc_ready(ioc, CAN_SLEEP, SOFT_RESET); - if (r) - goto out_free_resources; - - ioc->pfacts = kcalloc(ioc->facts.NumberOfPorts, - sizeof(struct mpt2sas_port_facts), GFP_KERNEL); - if (!ioc->pfacts) { - r = -ENOMEM; - goto out_free_resources; - } - - for (i = 0 ; i < ioc->facts.NumberOfPorts; i++) { - r = _base_get_port_facts(ioc, i, CAN_SLEEP); - if (r) - goto out_free_resources; - } - - r = _base_allocate_memory_pools(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - init_waitqueue_head(&ioc->reset_wq); - - /* allocate memory pd handle bitmask list */ - ioc->pd_handles_sz = (ioc->facts.MaxDevHandle / 8); - if (ioc->facts.MaxDevHandle % 8) - ioc->pd_handles_sz++; - ioc->pd_handles = kzalloc(ioc->pd_handles_sz, - GFP_KERNEL); - if (!ioc->pd_handles) { - r = -ENOMEM; - goto out_free_resources; - } - - ioc->fwfault_debug = mpt2sas_fwfault_debug; - - /* base internal command bits */ - mutex_init(&ioc->base_cmds.mutex); - ioc->base_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - - /* port_enable command bits */ - ioc->port_enable_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->port_enable_cmds.status = MPT2_CMD_NOT_USED; - - /* transport internal command bits */ - ioc->transport_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->transport_cmds.mutex); - - /* scsih internal command bits */ - ioc->scsih_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->scsih_cmds.mutex); - - /* task management internal command bits */ - ioc->tm_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->tm_cmds.mutex); - - /* config page internal command bits */ - ioc->config_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->config_cmds.mutex); - - /* ctl module internal command bits */ - ioc->ctl_cmds.reply = kzalloc(ioc->reply_sz, GFP_KERNEL); - ioc->ctl_cmds.sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - mutex_init(&ioc->ctl_cmds.mutex); - - if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || - !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || - !ioc->config_cmds.reply || !ioc->ctl_cmds.reply || - !ioc->ctl_cmds.sense) { - r = -ENOMEM; - goto out_free_resources; - } - - if (!ioc->base_cmds.reply || !ioc->transport_cmds.reply || - !ioc->scsih_cmds.reply || !ioc->tm_cmds.reply || - !ioc->config_cmds.reply || !ioc->ctl_cmds.reply) { - r = -ENOMEM; - goto out_free_resources; - } - - for (i = 0; i < MPI2_EVENT_NOTIFY_EVENTMASK_WORDS; i++) - ioc->event_masks[i] = -1; - - /* here we enable the events we care about */ - _base_unmask_events(ioc, MPI2_EVENT_SAS_DISCOVERY); - _base_unmask_events(ioc, MPI2_EVENT_SAS_BROADCAST_PRIMITIVE); - _base_unmask_events(ioc, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); - _base_unmask_events(ioc, MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); - _base_unmask_events(ioc, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); - _base_unmask_events(ioc, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); - _base_unmask_events(ioc, MPI2_EVENT_IR_VOLUME); - _base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK); - _base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS); - _base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED); - r = _base_make_ioc_operational(ioc, CAN_SLEEP); - if (r) - goto out_free_resources; - - if (missing_delay[0] != -1 && missing_delay[1] != -1) - _base_update_missing_delay(ioc, missing_delay[0], - missing_delay[1]); - - return 0; - - out_free_resources: - - ioc->remove_host = 1; - mpt2sas_base_free_resources(ioc); - _base_release_memory_pools(ioc); - pci_set_drvdata(ioc->pdev, NULL); - kfree(ioc->cpu_msix_table); - if (ioc->is_warpdrive) - kfree(ioc->reply_post_host_index); - kfree(ioc->pd_handles); - kfree(ioc->tm_cmds.reply); - kfree(ioc->transport_cmds.reply); - kfree(ioc->scsih_cmds.reply); - kfree(ioc->config_cmds.reply); - kfree(ioc->base_cmds.reply); - kfree(ioc->port_enable_cmds.reply); - kfree(ioc->ctl_cmds.reply); - kfree(ioc->ctl_cmds.sense); - kfree(ioc->pfacts); - ioc->ctl_cmds.reply = NULL; - ioc->base_cmds.reply = NULL; - ioc->tm_cmds.reply = NULL; - ioc->scsih_cmds.reply = NULL; - ioc->transport_cmds.reply = NULL; - ioc->config_cmds.reply = NULL; - ioc->pfacts = NULL; - return r; -} - - -/** - * mpt2sas_base_detach - remove controller instance - * @ioc: per adapter object - * - * Return nothing. - */ -void -mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc) -{ - - dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - mpt2sas_base_stop_watchdog(ioc); - mpt2sas_base_free_resources(ioc); - _base_release_memory_pools(ioc); - pci_set_drvdata(ioc->pdev, NULL); - kfree(ioc->cpu_msix_table); - if (ioc->is_warpdrive) - kfree(ioc->reply_post_host_index); - kfree(ioc->pd_handles); - kfree(ioc->pfacts); - kfree(ioc->ctl_cmds.reply); - kfree(ioc->ctl_cmds.sense); - kfree(ioc->base_cmds.reply); - kfree(ioc->port_enable_cmds.reply); - kfree(ioc->tm_cmds.reply); - kfree(ioc->transport_cmds.reply); - kfree(ioc->scsih_cmds.reply); - kfree(ioc->config_cmds.reply); -} - -/** - * _base_reset_handler - reset callback handler (for base) - * @ioc: per adapter object - * @reset_phase: phase - * - * The handler for doing any required cleanup or initialization. - * - * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, - * MPT2_IOC_DONE_RESET - * - * Return nothing. - */ -static void -_base_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) -{ - mpt2sas_scsih_reset_handler(ioc, reset_phase); - mpt2sas_ctl_reset_handler(ioc, reset_phase); - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->transport_cmds.status & MPT2_CMD_PENDING) { - ioc->transport_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->transport_cmds.smid); - complete(&ioc->transport_cmds.done); - } - if (ioc->base_cmds.status & MPT2_CMD_PENDING) { - ioc->base_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->base_cmds.smid); - complete(&ioc->base_cmds.done); - } - if (ioc->port_enable_cmds.status & MPT2_CMD_PENDING) { - ioc->port_enable_failed = 1; - ioc->port_enable_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->port_enable_cmds.smid); - if (ioc->is_driver_loading) { - ioc->start_scan_failed = - MPI2_IOCSTATUS_INTERNAL_ERROR; - ioc->start_scan = 0; - ioc->port_enable_cmds.status = - MPT2_CMD_NOT_USED; - } else - complete(&ioc->port_enable_cmds.done); - - } - if (ioc->config_cmds.status & MPT2_CMD_PENDING) { - ioc->config_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->config_cmds.smid); - ioc->config_cmds.smid = USHRT_MAX; - complete(&ioc->config_cmds.done); - } - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - break; - } -} - -/** - * _wait_for_commands_to_complete - reset controller - * @ioc: Pointer to MPT_ADAPTER structure - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * - * This function waiting(3s) for all pending commands to complete - * prior to putting controller in reset. - */ -static void -_wait_for_commands_to_complete(struct MPT2SAS_ADAPTER *ioc, int sleep_flag) -{ - u32 ioc_state; - unsigned long flags; - u16 i; - - ioc->pending_io_count = 0; - if (sleep_flag != CAN_SLEEP) - return; - - ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - if ((ioc_state & MPI2_IOC_STATE_MASK) != MPI2_IOC_STATE_OPERATIONAL) - return; - - /* pending command count */ - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - for (i = 0; i < ioc->scsiio_depth; i++) - if (ioc->scsi_lookup[i].cb_idx != 0xFF) - ioc->pending_io_count++; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - if (!ioc->pending_io_count) - return; - - /* wait for pending commands to complete */ - wait_event_timeout(ioc->reset_wq, ioc->pending_io_count == 0, 10 * HZ); -} - -/** - * mpt2sas_base_hard_reset_handler - reset controller - * @ioc: Pointer to MPT_ADAPTER structure - * @sleep_flag: CAN_SLEEP or NO_SLEEP - * @type: FORCE_BIG_HAMMER or SOFT_RESET - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, - enum reset_type type) -{ - int r; - unsigned long flags; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - if (ioc->pci_error_recovery) { - printk(MPT2SAS_ERR_FMT "%s: pci error recovery reset\n", - ioc->name, __func__); - r = 0; - goto out_unlocked; - } - - if (mpt2sas_fwfault_debug) - mpt2sas_halt_firmware(ioc); - - /* TODO - What we really should be doing is pulling - * out all the code associated with NO_SLEEP; its never used. - * That is legacy code from mpt fusion driver, ported over. - * I will leave this BUG_ON here for now till its been resolved. - */ - BUG_ON(sleep_flag == NO_SLEEP); - - /* wait for an active reset in progress to complete */ - if (!mutex_trylock(&ioc->reset_in_progress_mutex)) { - do { - ssleep(1); - } while (ioc->shost_recovery == 1); - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, - __func__)); - return ioc->ioc_reset_in_progress_status; - } - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->shost_recovery = 1; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - - _base_reset_handler(ioc, MPT2_IOC_PRE_RESET); - _wait_for_commands_to_complete(ioc, sleep_flag); - _base_mask_interrupts(ioc); - r = _base_make_ioc_ready(ioc, sleep_flag, type); - if (r) - goto out; - _base_reset_handler(ioc, MPT2_IOC_AFTER_RESET); - - /* If this hard reset is called while port enable is active, then - * there is no reason to call make_ioc_operational - */ - if (ioc->is_driver_loading && ioc->port_enable_failed) { - ioc->remove_host = 1; - r = -EFAULT; - goto out; - } - r = _base_make_ioc_operational(ioc, sleep_flag); - if (!r) - _base_reset_handler(ioc, MPT2_IOC_DONE_RESET); - out: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %s\n", - ioc->name, __func__, ((r == 0) ? "SUCCESS" : "FAILED"))); - - spin_lock_irqsave(&ioc->ioc_reset_in_progress_lock, flags); - ioc->ioc_reset_in_progress_status = r; - ioc->shost_recovery = 0; - spin_unlock_irqrestore(&ioc->ioc_reset_in_progress_lock, flags); - mutex_unlock(&ioc->reset_in_progress_mutex); - - out_unlocked: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit\n", ioc->name, - __func__)); - return r; -} diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.h deleted file mode 100644 index c7459fdc..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_base.h +++ /dev/null @@ -1,1161 +0,0 @@ -/* - * This is the Fusion MPT base driver providing common API layer interface - * for access to MPT (Message Passing Technology) firmware. - * - * This code is based on drivers/scsi/mpt2sas/mpt2_base.h - * Copyright (C) 2007-2010 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef MPT2SAS_BASE_H_INCLUDED -#define MPT2SAS_BASE_H_INCLUDED - -#include "mpi/mpi2_type.h" -#include "mpi/mpi2.h" -#include "mpi/mpi2_ioc.h" -#include "mpi/mpi2_cnfg.h" -#include "mpi/mpi2_init.h" -#include "mpi/mpi2_raid.h" -#include "mpi/mpi2_tool.h" -#include "mpi/mpi2_sas.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_debug.h" - -/* driver versioning info */ -#define MPT2SAS_DRIVER_NAME "mpt2sas" -#define MPT2SAS_AUTHOR "LSI Corporation " -#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" -#define MPT2SAS_DRIVER_VERSION "12.100.00.00" -#define MPT2SAS_MAJOR_VERSION 12 -#define MPT2SAS_MINOR_VERSION 100 -#define MPT2SAS_BUILD_VERSION 00 -#define MPT2SAS_RELEASE_VERSION 00 - -/* - * Set MPT2SAS_SG_DEPTH value based on user input. - */ -#ifdef CONFIG_SCSI_MPT2SAS_MAX_SGE -#if CONFIG_SCSI_MPT2SAS_MAX_SGE < 16 -#define MPT2SAS_SG_DEPTH 16 -#elif CONFIG_SCSI_MPT2SAS_MAX_SGE > 128 -#define MPT2SAS_SG_DEPTH 128 -#else -#define MPT2SAS_SG_DEPTH CONFIG_SCSI_MPT2SAS_MAX_SGE -#endif -#else -#define MPT2SAS_SG_DEPTH 128 /* MAX_HW_SEGMENTS */ -#endif - - -/* - * Generic Defines - */ -#define MPT2SAS_SATA_QUEUE_DEPTH 32 -#define MPT2SAS_SAS_QUEUE_DEPTH 254 -#define MPT2SAS_RAID_QUEUE_DEPTH 128 - -#define MPT_NAME_LENGTH 32 /* generic length of strings */ -#define MPT_STRING_LENGTH 64 - -#define MPT_MAX_CALLBACKS 16 - - -#define CAN_SLEEP 1 -#define NO_SLEEP 0 - -#define INTERNAL_CMDS_COUNT 10 /* reserved cmds */ - -#define MPI2_HIM_MASK 0xFFFFFFFF /* mask every bit*/ - -#define MPT2SAS_INVALID_DEVICE_HANDLE 0xFFFF - - -/* - * reset phases - */ -#define MPT2_IOC_PRE_RESET 1 /* prior to host reset */ -#define MPT2_IOC_AFTER_RESET 2 /* just after host reset */ -#define MPT2_IOC_DONE_RESET 3 /* links re-initialized */ - -/* - * logging format - */ -#define MPT2SAS_FMT "%s: " -#define MPT2SAS_INFO_FMT KERN_INFO MPT2SAS_FMT -#define MPT2SAS_NOTE_FMT KERN_NOTICE MPT2SAS_FMT -#define MPT2SAS_WARN_FMT KERN_WARNING MPT2SAS_FMT -#define MPT2SAS_ERR_FMT KERN_ERR MPT2SAS_FMT - -/* - * Dell HBA branding - */ -#define MPT2SAS_DELL_BRANDING_SIZE 32 - -#define MPT2SAS_DELL_6GBPS_SAS_HBA_BRANDING "Dell 6Gbps SAS HBA" -#define MPT2SAS_DELL_PERC_H200_ADAPTER_BRANDING "Dell PERC H200 Adapter" -#define MPT2SAS_DELL_PERC_H200_INTEGRATED_BRANDING "Dell PERC H200 Integrated" -#define MPT2SAS_DELL_PERC_H200_MODULAR_BRANDING "Dell PERC H200 Modular" -#define MPT2SAS_DELL_PERC_H200_EMBEDDED_BRANDING "Dell PERC H200 Embedded" -#define MPT2SAS_DELL_PERC_H200_BRANDING "Dell PERC H200" -#define MPT2SAS_DELL_6GBPS_SAS_BRANDING "Dell 6Gbps SAS" - -/* - * Dell HBA SSDIDs - */ -#define MPT2SAS_DELL_6GBPS_SAS_HBA_SSDID 0x1F1C -#define MPT2SAS_DELL_PERC_H200_ADAPTER_SSDID 0x1F1D -#define MPT2SAS_DELL_PERC_H200_INTEGRATED_SSDID 0x1F1E -#define MPT2SAS_DELL_PERC_H200_MODULAR_SSDID 0x1F1F -#define MPT2SAS_DELL_PERC_H200_EMBEDDED_SSDID 0x1F20 -#define MPT2SAS_DELL_PERC_H200_SSDID 0x1F21 -#define MPT2SAS_DELL_6GBPS_SAS_SSDID 0x1F22 - -/* - * Intel HBA branding - */ -#define MPT2SAS_INTEL_RMS25JB080_BRANDING \ - "Intel(R) Integrated RAID Module RMS25JB080" -#define MPT2SAS_INTEL_RMS25JB040_BRANDING \ - "Intel(R) Integrated RAID Module RMS25JB040" -#define MPT2SAS_INTEL_RMS25KB080_BRANDING \ - "Intel(R) Integrated RAID Module RMS25KB080" -#define MPT2SAS_INTEL_RMS25KB040_BRANDING \ - "Intel(R) Integrated RAID Module RMS25KB040" -#define MPT2SAS_INTEL_RMS2LL080_BRANDING \ - "Intel Integrated RAID Module RMS2LL080" -#define MPT2SAS_INTEL_RMS2LL040_BRANDING \ - "Intel Integrated RAID Module RMS2LL040" -#define MPT2SAS_INTEL_RS25GB008_BRANDING \ - "Intel(R) RAID Controller RS25GB008" -#define MPT2SAS_INTEL_RAMSDALE_BRANDING \ - "Intel 720 Series SSD" -/* - * Intel HBA SSDIDs - */ -#define MPT2SAS_INTEL_RMS25JB080_SSDID 0x3516 -#define MPT2SAS_INTEL_RMS25JB040_SSDID 0x3517 -#define MPT2SAS_INTEL_RMS25KB080_SSDID 0x3518 -#define MPT2SAS_INTEL_RMS25KB040_SSDID 0x3519 -#define MPT2SAS_INTEL_RMS2LL080_SSDID 0x350E -#define MPT2SAS_INTEL_RMS2LL040_SSDID 0x350F -#define MPT2SAS_INTEL_RS25GB008_SSDID 0x3000 -#define MPT2SAS_INTEL_RAMSDALE_SSDID 0x3700 - -/* - * HP HBA branding - */ -#define MPT2SAS_HP_3PAR_SSVID 0x1590 -#define MPT2SAS_HP_2_4_INTERNAL_BRANDING "HP H220 Host Bus Adapter" -#define MPT2SAS_HP_2_4_EXTERNAL_BRANDING "HP H221 Host Bus Adapter" -#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_BRANDING "HP H222 Host Bus Adapter" -#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_BRANDING "HP H220i Host Bus Adapter" -#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_BRANDING "HP H210i Host Bus Adapter" - -/* - * HO HBA SSDIDs - */ -#define MPT2SAS_HP_2_4_INTERNAL_SSDID 0x0041 -#define MPT2SAS_HP_2_4_EXTERNAL_SSDID 0x0042 -#define MPT2SAS_HP_1_4_INTERNAL_1_4_EXTERNAL_SSDID 0x0043 -#define MPT2SAS_HP_EMBEDDED_2_4_INTERNAL_SSDID 0x0044 -#define MPT2SAS_HP_DAUGHTER_2_4_INTERNAL_SSDID 0x0046 - -/* - * WarpDrive Specific Log codes - */ - -#define MPT2_WARPDRIVE_LOGENTRY (0x8002) -#define MPT2_WARPDRIVE_LC_SSDT (0x41) -#define MPT2_WARPDRIVE_LC_SSDLW (0x43) -#define MPT2_WARPDRIVE_LC_SSDLF (0x44) -#define MPT2_WARPDRIVE_LC_BRMF (0x4D) - -/* - * per target private data - */ -#define MPT_TARGET_FLAGS_RAID_COMPONENT 0x01 -#define MPT_TARGET_FLAGS_VOLUME 0x02 -#define MPT_TARGET_FLAGS_DELETED 0x04 - -/** - * struct MPT2SAS_TARGET - starget private hostdata - * @starget: starget object - * @sas_address: target sas address - * @raid_device: raid_device pointer to access volume data - * @handle: device handle - * @num_luns: number luns - * @flags: MPT_TARGET_FLAGS_XXX flags - * @deleted: target flaged for deletion - * @tm_busy: target is busy with TM request. - */ -struct MPT2SAS_TARGET { - struct scsi_target *starget; - u64 sas_address; - struct _raid_device *raid_device; - u16 handle; - int num_luns; - u32 flags; - u8 deleted; - u8 tm_busy; -}; - - -/* - * per device private data - */ -#define MPT_DEVICE_FLAGS_INIT 0x01 -#define MPT_DEVICE_TLR_ON 0x02 - -/** - * struct MPT2SAS_DEVICE - sdev private hostdata - * @sas_target: starget private hostdata - * @lun: lun number - * @flags: MPT_DEVICE_XXX flags - * @configured_lun: lun is configured - * @block: device is in SDEV_BLOCK state - * @tlr_snoop_check: flag used in determining whether to disable TLR - */ - -/* OEM Identifiers */ -#define MFG10_OEM_ID_INVALID (0x00000000) -#define MFG10_OEM_ID_DELL (0x00000001) -#define MFG10_OEM_ID_FSC (0x00000002) -#define MFG10_OEM_ID_SUN (0x00000003) -#define MFG10_OEM_ID_IBM (0x00000004) - -/* GENERIC Flags 0*/ -#define MFG10_GF0_OCE_DISABLED (0x00000001) -#define MFG10_GF0_R1E_DRIVE_COUNT (0x00000002) -#define MFG10_GF0_R10_DISPLAY (0x00000004) -#define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008) -#define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010) - -/* OEM Specific Flags will come from OEM specific header files */ -typedef struct _MPI2_CONFIG_PAGE_MAN_10 { - MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ - U8 OEMIdentifier; /* 04h */ - U8 Reserved1; /* 05h */ - U16 Reserved2; /* 08h */ - U32 Reserved3; /* 0Ch */ - U32 GenericFlags0; /* 10h */ - U32 GenericFlags1; /* 14h */ - U32 Reserved4; /* 18h */ - U32 OEMSpecificFlags0; /* 1Ch */ - U32 OEMSpecificFlags1; /* 20h */ - U32 Reserved5[18]; /* 24h-60h*/ -} MPI2_CONFIG_PAGE_MAN_10, - MPI2_POINTER PTR_MPI2_CONFIG_PAGE_MAN_10, - Mpi2ManufacturingPage10_t, MPI2_POINTER pMpi2ManufacturingPage10_t; - -#define MFG_PAGE10_HIDE_SSDS_MASK (0x00000003) -#define MFG_PAGE10_HIDE_ALL_DISKS (0x00) -#define MFG_PAGE10_EXPOSE_ALL_DISKS (0x01) -#define MFG_PAGE10_HIDE_IF_VOL_PRESENT (0x02) - - -struct MPT2SAS_DEVICE { - struct MPT2SAS_TARGET *sas_target; - unsigned int lun; - u32 flags; - u8 configured_lun; - u8 block; - u8 tlr_snoop_check; -}; - -#define MPT2_CMD_NOT_USED 0x8000 /* free */ -#define MPT2_CMD_COMPLETE 0x0001 /* completed */ -#define MPT2_CMD_PENDING 0x0002 /* pending */ -#define MPT2_CMD_REPLY_VALID 0x0004 /* reply is valid */ -#define MPT2_CMD_RESET 0x0008 /* host reset dropped the command */ - -/** - * struct _internal_cmd - internal commands struct - * @mutex: mutex - * @done: completion - * @reply: reply message pointer - * @sense: sense data - * @status: MPT2_CMD_XXX status - * @smid: system message id - */ -struct _internal_cmd { - struct mutex mutex; - struct completion done; - void *reply; - void *sense; - u16 status; - u16 smid; -}; - - -/** - * struct _sas_device - attached device information - * @list: sas device list - * @starget: starget object - * @sas_address: device sas address - * @device_name: retrieved from the SAS IDENTIFY frame. - * @handle: device handle - * @sas_address_parent: sas address of parent expander or sas host - * @enclosure_handle: enclosure handle - * @enclosure_logical_id: enclosure logical identifier - * @volume_handle: volume handle (valid when hidden raid member) - * @volume_wwid: volume unique identifier - * @device_info: bitfield provides detailed info about the device - * @id: target id - * @channel: target channel - * @slot: number number - * @phy: phy identifier provided in sas device page 0 - * @responding: used in _scsih_sas_device_mark_responding - */ -struct _sas_device { - struct list_head list; - struct scsi_target *starget; - u64 sas_address; - u64 device_name; - u16 handle; - u64 sas_address_parent; - u16 enclosure_handle; - u64 enclosure_logical_id; - u16 volume_handle; - u64 volume_wwid; - u32 device_info; - int id; - int channel; - u16 slot; - u8 phy; - u8 responding; -}; - -/** - * struct _raid_device - raid volume link list - * @list: sas device list - * @starget: starget object - * @sdev: scsi device struct (volumes are single lun) - * @wwid: unique identifier for the volume - * @handle: device handle - * @block_size: Block size of the volume - * @id: target id - * @channel: target channel - * @volume_type: the raid level - * @device_info: bitfield provides detailed info about the hidden components - * @num_pds: number of hidden raid components - * @responding: used in _scsih_raid_device_mark_responding - * @percent_complete: resync percent complete - * @direct_io_enabled: Whether direct io to PDs are allowed or not - * @stripe_exponent: X where 2powX is the stripe sz in blocks - * @block_exponent: X where 2powX is the block sz in bytes - * @max_lba: Maximum number of LBA in the volume - * @stripe_sz: Stripe Size of the volume - * @device_info: Device info of the volume member disk - * @pd_handle: Array of handles of the physical drives for direct I/O in le16 - */ -#define MPT_MAX_WARPDRIVE_PDS 8 -struct _raid_device { - struct list_head list; - struct scsi_target *starget; - struct scsi_device *sdev; - u64 wwid; - u16 handle; - u16 block_sz; - int id; - int channel; - u8 volume_type; - u8 num_pds; - u8 responding; - u8 percent_complete; - u8 direct_io_enabled; - u8 stripe_exponent; - u8 block_exponent; - u64 max_lba; - u32 stripe_sz; - u32 device_info; - u16 pd_handle[MPT_MAX_WARPDRIVE_PDS]; -}; - -/** - * struct _boot_device - boot device info - * @is_raid: flag to indicate whether this is volume - * @device: holds pointer for either struct _sas_device or - * struct _raid_device - */ -struct _boot_device { - u8 is_raid; - void *device; -}; - -/** - * struct _sas_port - wide/narrow sas port information - * @port_list: list of ports belonging to expander - * @num_phys: number of phys belonging to this port - * @remote_identify: attached device identification - * @rphy: sas transport rphy object - * @port: sas transport wide/narrow port object - * @phy_list: _sas_phy list objects belonging to this port - */ -struct _sas_port { - struct list_head port_list; - u8 num_phys; - struct sas_identify remote_identify; - struct sas_rphy *rphy; - struct sas_port *port; - struct list_head phy_list; -}; - -/** - * struct _sas_phy - phy information - * @port_siblings: list of phys belonging to a port - * @identify: phy identification - * @remote_identify: attached device identification - * @phy: sas transport phy object - * @phy_id: unique phy id - * @handle: device handle for this phy - * @attached_handle: device handle for attached device - * @phy_belongs_to_port: port has been created for this phy - */ -struct _sas_phy { - struct list_head port_siblings; - struct sas_identify identify; - struct sas_identify remote_identify; - struct sas_phy *phy; - u8 phy_id; - u16 handle; - u16 attached_handle; - u8 phy_belongs_to_port; -}; - -/** - * struct _sas_node - sas_host/expander information - * @list: list of expanders - * @parent_dev: parent device class - * @num_phys: number phys belonging to this sas_host/expander - * @sas_address: sas address of this sas_host/expander - * @handle: handle for this sas_host/expander - * @sas_address_parent: sas address of parent expander or sas host - * @enclosure_handle: handle for this a member of an enclosure - * @device_info: bitwise defining capabilities of this sas_host/expander - * @responding: used in _scsih_expander_device_mark_responding - * @phy: a list of phys that make up this sas_host/expander - * @sas_port_list: list of ports attached to this sas_host/expander - */ -struct _sas_node { - struct list_head list; - struct device *parent_dev; - u8 num_phys; - u64 sas_address; - u16 handle; - u64 sas_address_parent; - u16 enclosure_handle; - u64 enclosure_logical_id; - u8 responding; - struct _sas_phy *phy; - struct list_head sas_port_list; -}; - -/** - * enum reset_type - reset state - * @FORCE_BIG_HAMMER: issue diagnostic reset - * @SOFT_RESET: issue message_unit_reset, if fails to to big hammer - */ -enum reset_type { - FORCE_BIG_HAMMER, - SOFT_RESET, -}; - -/** - * struct chain_tracker - firmware chain tracker - * @chain_buffer: chain buffer - * @chain_buffer_dma: physical address - * @tracker_list: list of free request (ioc->free_chain_list) - */ -struct chain_tracker { - void *chain_buffer; - dma_addr_t chain_buffer_dma; - struct list_head tracker_list; -}; - -/** - * struct scsiio_tracker - scsi mf request tracker - * @smid: system message id - * @scmd: scsi request pointer - * @cb_idx: callback index - * @direct_io: To indicate whether I/O is direct (WARPDRIVE) - * @chain_list: list of chains associated to this IO - * @tracker_list: list of free request (ioc->free_list) - */ -struct scsiio_tracker { - u16 smid; - struct scsi_cmnd *scmd; - u8 cb_idx; - u8 direct_io; - struct list_head chain_list; - struct list_head tracker_list; -}; - -/** - * struct request_tracker - firmware request tracker - * @smid: system message id - * @cb_idx: callback index - * @tracker_list: list of free request (ioc->free_list) - */ -struct request_tracker { - u16 smid; - u8 cb_idx; - struct list_head tracker_list; -}; - -/** - * struct _tr_list - target reset list - * @handle: device handle - * @state: state machine - */ -struct _tr_list { - struct list_head list; - u16 handle; - u16 state; -}; - -typedef void (*MPT_ADD_SGE)(void *paddr, u32 flags_length, dma_addr_t dma_addr); - -/** - * struct adapter_reply_queue - the reply queue struct - * @ioc: per adapter object - * @msix_index: msix index into vector table - * @vector: irq vector - * @reply_post_host_index: head index in the pool where FW completes IO - * @reply_post_free: reply post base virt address - * @name: the name registered to request_irq() - * @busy: isr is actively processing replies on another cpu - * @list: this list -*/ -struct adapter_reply_queue { - struct MPT2SAS_ADAPTER *ioc; - u8 msix_index; - unsigned int vector; - u32 reply_post_host_index; - Mpi2ReplyDescriptorsUnion_t *reply_post_free; - char name[MPT_NAME_LENGTH]; - atomic_t busy; - struct list_head list; -}; - -/* IOC Facts and Port Facts converted from little endian to cpu */ -union mpi2_version_union { - MPI2_VERSION_STRUCT Struct; - u32 Word; -}; - -struct mpt2sas_facts { - u16 MsgVersion; - u16 HeaderVersion; - u8 IOCNumber; - u8 VP_ID; - u8 VF_ID; - u16 IOCExceptions; - u16 IOCStatus; - u32 IOCLogInfo; - u8 MaxChainDepth; - u8 WhoInit; - u8 NumberOfPorts; - u8 MaxMSIxVectors; - u16 RequestCredit; - u16 ProductID; - u32 IOCCapabilities; - union mpi2_version_union FWVersion; - u16 IOCRequestFrameSize; - u16 Reserved3; - u16 MaxInitiators; - u16 MaxTargets; - u16 MaxSasExpanders; - u16 MaxEnclosures; - u16 ProtocolFlags; - u16 HighPriorityCredit; - u16 MaxReplyDescriptorPostQueueDepth; - u8 ReplyFrameSize; - u8 MaxVolumes; - u16 MaxDevHandle; - u16 MaxPersistentEntries; - u16 MinDevHandle; -}; - -struct mpt2sas_port_facts { - u8 PortNumber; - u8 VP_ID; - u8 VF_ID; - u8 PortType; - u16 MaxPostedCmdBuffers; -}; - -/** - * enum mutex_type - task management mutex type - * @TM_MUTEX_OFF: mutex is not required becuase calling function is acquiring it - * @TM_MUTEX_ON: mutex is required - */ -enum mutex_type { - TM_MUTEX_OFF = 0, - TM_MUTEX_ON = 1, -}; - -typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); -/** - * struct MPT2SAS_ADAPTER - per adapter struct - * @list: ioc_list - * @shost: shost object - * @id: unique adapter id - * @cpu_count: number online cpus - * @name: generic ioc string - * @tmp_string: tmp string used for logging - * @pdev: pci pdev object - * @chip: memory mapped register space - * @chip_phys: physical addrss prior to mapping - * @logging_level: see mpt2sas_debug.h - * @fwfault_debug: debuging FW timeouts - * @ir_firmware: IR firmware present - * @bars: bitmask of BAR's that must be configured - * @mask_interrupts: ignore interrupt - * @fault_reset_work_q_name: fw fault work queue - * @fault_reset_work_q: "" - * @fault_reset_work: "" - * @firmware_event_name: fw event work queue - * @firmware_event_thread: "" - * @fw_events_off: flag to turn off fw event handling - * @fw_event_lock: - * @fw_event_list: list of fw events - * @aen_event_read_flag: event log was read - * @broadcast_aen_busy: broadcast aen waiting to be serviced - * @shost_recovery: host reset in progress - * @ioc_reset_in_progress_lock: - * @ioc_link_reset_in_progress: phy/hard reset in progress - * @ignore_loginfos: ignore loginfos during task management - * @remove_host: flag for when driver unloads, to avoid sending dev resets - * @pci_error_recovery: flag to prevent ioc access until slot reset completes - * @wait_for_discovery_to_complete: flag set at driver load time when - * waiting on reporting devices - * @is_driver_loading: flag set at driver load time - * @port_enable_failed: flag set when port enable has failed - * @start_scan: flag set from scan_start callback, cleared from _mpt2sas_fw_work - * @start_scan_failed: means port enable failed, return's the ioc_status - * @msix_enable: flag indicating msix is enabled - * @msix_vector_count: number msix vectors - * @cpu_msix_table: table for mapping cpus to msix index - * @cpu_msix_table_sz: table size - * @schedule_dead_ioc_flush_running_cmds: callback to flush pending commands - * @scsi_io_cb_idx: shost generated commands - * @tm_cb_idx: task management commands - * @scsih_cb_idx: scsih internal commands - * @transport_cb_idx: transport internal commands - * @ctl_cb_idx: clt internal commands - * @base_cb_idx: base internal commands - * @config_cb_idx: base internal commands - * @tm_tr_cb_idx : device removal target reset handshake - * @tm_tr_volume_cb_idx : volume removal target reset - * @base_cmds: - * @transport_cmds: - * @scsih_cmds: - * @tm_cmds: - * @ctl_cmds: - * @config_cmds: - * @base_add_sg_single: handler for either 32/64 bit sgl's - * @event_type: bits indicating which events to log - * @event_context: unique id for each logged event - * @event_log: event log pointer - * @event_masks: events that are masked - * @facts: static facts data - * @pfacts: static port facts data - * @manu_pg0: static manufacturing page 0 - * @manu_pg10: static manufacturing page 10 - * @bios_pg2: static bios page 2 - * @bios_pg3: static bios page 3 - * @ioc_pg8: static ioc page 8 - * @iounit_pg0: static iounit page 0 - * @iounit_pg1: static iounit page 1 - * @sas_hba: sas host object - * @sas_expander_list: expander object list - * @sas_node_lock: - * @sas_device_list: sas device object list - * @sas_device_init_list: sas device object list (used only at init time) - * @sas_device_lock: - * @io_missing_delay: time for IO completed by fw when PDR enabled - * @device_missing_delay: time for device missing by fw when PDR enabled - * @sas_id : used for setting volume target IDs - * @pd_handles : bitmask for PD handles - * @pd_handles_sz : size of pd_handle bitmask - * @config_page_sz: config page size - * @config_page: reserve memory for config page payload - * @config_page_dma: - * @hba_queue_depth: hba request queue depth - * @sge_size: sg element size for either 32/64 bit - * @scsiio_depth: SCSI_IO queue depth - * @request_sz: per request frame size - * @request: pool of request frames - * @request_dma: - * @request_dma_sz: - * @scsi_lookup: firmware request tracker list - * @scsi_lookup_lock: - * @free_list: free list of request - * @chain: pool of chains - * @pending_io_count: - * @reset_wq: - * @chain_dma: - * @max_sges_in_main_message: number sg elements in main message - * @max_sges_in_chain_message: number sg elements per chain - * @chains_needed_per_io: max chains per io - * @chain_offset_value_for_main_message: location 1st sg in main - * @chain_depth: total chains allocated - * @hi_priority_smid: - * @hi_priority: - * @hi_priority_dma: - * @hi_priority_depth: - * @hpr_lookup: - * @hpr_free_list: - * @internal_smid: - * @internal: - * @internal_dma: - * @internal_depth: - * @internal_lookup: - * @internal_free_list: - * @sense: pool of sense - * @sense_dma: - * @sense_dma_pool: - * @reply_depth: hba reply queue depth: - * @reply_sz: per reply frame size: - * @reply: pool of replys: - * @reply_dma: - * @reply_dma_pool: - * @reply_free_queue_depth: reply free depth - * @reply_free: pool for reply free queue (32 bit addr) - * @reply_free_dma: - * @reply_free_dma_pool: - * @reply_free_host_index: tail index in pool to insert free replys - * @reply_post_queue_depth: reply post queue depth - * @reply_post_free: pool for reply post (64bit descriptor) - * @reply_post_free_dma: - * @reply_queue_count: number of reply queue's - * @reply_queue_list: link list contaning the reply queue info - * @reply_post_host_index: head index in the pool where FW completes IO - * @delayed_tr_list: target reset link list - * @delayed_tr_volume_list: volume target reset link list - */ -struct MPT2SAS_ADAPTER { - struct list_head list; - struct Scsi_Host *shost; - u8 id; - int cpu_count; - char name[MPT_NAME_LENGTH]; - char tmp_string[MPT_STRING_LENGTH]; - struct pci_dev *pdev; - Mpi2SystemInterfaceRegs_t __iomem *chip; - resource_size_t chip_phys; - int logging_level; - int fwfault_debug; - u8 ir_firmware; - int bars; - u8 mask_interrupts; - - /* fw fault handler */ - char fault_reset_work_q_name[20]; - struct workqueue_struct *fault_reset_work_q; - struct delayed_work fault_reset_work; - - /* fw event handler */ - char firmware_event_name[20]; - struct workqueue_struct *firmware_event_thread; - spinlock_t fw_event_lock; - struct list_head fw_event_list; - - /* misc flags */ - int aen_event_read_flag; - u8 broadcast_aen_busy; - u16 broadcast_aen_pending; - u8 shost_recovery; - - struct mutex reset_in_progress_mutex; - spinlock_t ioc_reset_in_progress_lock; - u8 ioc_link_reset_in_progress; - u8 ioc_reset_in_progress_status; - - u8 ignore_loginfos; - u8 remove_host; - u8 pci_error_recovery; - u8 wait_for_discovery_to_complete; - struct completion port_enable_done; - u8 is_driver_loading; - u8 port_enable_failed; - - u8 start_scan; - u16 start_scan_failed; - - u8 msix_enable; - u16 msix_vector_count; - u8 *cpu_msix_table; - resource_size_t **reply_post_host_index; - u16 cpu_msix_table_sz; - u32 ioc_reset_count; - MPT2SAS_FLUSH_RUNNING_CMDS schedule_dead_ioc_flush_running_cmds; - - /* internal commands, callback index */ - u8 scsi_io_cb_idx; - u8 tm_cb_idx; - u8 transport_cb_idx; - u8 scsih_cb_idx; - u8 ctl_cb_idx; - u8 base_cb_idx; - u8 port_enable_cb_idx; - u8 config_cb_idx; - u8 tm_tr_cb_idx; - u8 tm_tr_volume_cb_idx; - u8 tm_sas_control_cb_idx; - struct _internal_cmd base_cmds; - struct _internal_cmd port_enable_cmds; - struct _internal_cmd transport_cmds; - struct _internal_cmd scsih_cmds; - struct _internal_cmd tm_cmds; - struct _internal_cmd ctl_cmds; - struct _internal_cmd config_cmds; - - MPT_ADD_SGE base_add_sg_single; - - /* event log */ - u32 event_type[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; - u32 event_context; - void *event_log; - u32 event_masks[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; - - /* static config pages */ - struct mpt2sas_facts facts; - struct mpt2sas_port_facts *pfacts; - Mpi2ManufacturingPage0_t manu_pg0; - Mpi2BiosPage2_t bios_pg2; - Mpi2BiosPage3_t bios_pg3; - Mpi2IOCPage8_t ioc_pg8; - Mpi2IOUnitPage0_t iounit_pg0; - Mpi2IOUnitPage1_t iounit_pg1; - - struct _boot_device req_boot_device; - struct _boot_device req_alt_boot_device; - struct _boot_device current_boot_device; - - /* sas hba, expander, and device list */ - struct _sas_node sas_hba; - struct list_head sas_expander_list; - spinlock_t sas_node_lock; - struct list_head sas_device_list; - struct list_head sas_device_init_list; - spinlock_t sas_device_lock; - struct list_head raid_device_list; - spinlock_t raid_device_lock; - u8 io_missing_delay; - u16 device_missing_delay; - int sas_id; - - void *pd_handles; - u16 pd_handles_sz; - - /* config page */ - u16 config_page_sz; - void *config_page; - dma_addr_t config_page_dma; - - /* scsiio request */ - u16 hba_queue_depth; - u16 sge_size; - u16 scsiio_depth; - u16 request_sz; - u8 *request; - dma_addr_t request_dma; - u32 request_dma_sz; - struct scsiio_tracker *scsi_lookup; - ulong scsi_lookup_pages; - spinlock_t scsi_lookup_lock; - struct list_head free_list; - int pending_io_count; - wait_queue_head_t reset_wq; - - /* chain */ - struct chain_tracker *chain_lookup; - struct list_head free_chain_list; - struct dma_pool *chain_dma_pool; - ulong chain_pages; - u16 max_sges_in_main_message; - u16 max_sges_in_chain_message; - u16 chains_needed_per_io; - u16 chain_offset_value_for_main_message; - u32 chain_depth; - - /* hi-priority queue */ - u16 hi_priority_smid; - u8 *hi_priority; - dma_addr_t hi_priority_dma; - u16 hi_priority_depth; - struct request_tracker *hpr_lookup; - struct list_head hpr_free_list; - - /* internal queue */ - u16 internal_smid; - u8 *internal; - dma_addr_t internal_dma; - u16 internal_depth; - struct request_tracker *internal_lookup; - struct list_head internal_free_list; - - /* sense */ - u8 *sense; - dma_addr_t sense_dma; - struct dma_pool *sense_dma_pool; - - /* reply */ - u16 reply_sz; - u8 *reply; - dma_addr_t reply_dma; - u32 reply_dma_max_address; - u32 reply_dma_min_address; - struct dma_pool *reply_dma_pool; - - /* reply free queue */ - u16 reply_free_queue_depth; - __le32 *reply_free; - dma_addr_t reply_free_dma; - struct dma_pool *reply_free_dma_pool; - u32 reply_free_host_index; - - /* reply post queue */ - u16 reply_post_queue_depth; - Mpi2ReplyDescriptorsUnion_t *reply_post_free; - dma_addr_t reply_post_free_dma; - struct dma_pool *reply_post_free_dma_pool; - u8 reply_queue_count; - struct list_head reply_queue_list; - - struct list_head delayed_tr_list; - struct list_head delayed_tr_volume_list; - - /* diag buffer support */ - u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT]; - u32 diag_buffer_sz[MPI2_DIAG_BUF_TYPE_COUNT]; - dma_addr_t diag_buffer_dma[MPI2_DIAG_BUF_TYPE_COUNT]; - u8 diag_buffer_status[MPI2_DIAG_BUF_TYPE_COUNT]; - u32 unique_id[MPI2_DIAG_BUF_TYPE_COUNT]; - Mpi2ManufacturingPage10_t manu_pg10; - u32 product_specific[MPI2_DIAG_BUF_TYPE_COUNT][23]; - u32 diagnostic_flags[MPI2_DIAG_BUF_TYPE_COUNT]; - u32 ring_buffer_offset; - u32 ring_buffer_sz; - u8 is_warpdrive; - u8 hide_ir_msg; - u8 mfg_pg10_hide_flag; - u8 hide_drives; - -}; - -typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); - - -/* base shared API */ -extern struct list_head mpt2sas_ioc_list; -void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc); - -int mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_base_detach(struct MPT2SAS_ADAPTER *ioc); -int mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc); -void mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc); -int mpt2sas_base_hard_reset_handler(struct MPT2SAS_ADAPTER *ioc, int sleep_flag, - enum reset_type type); - -void *mpt2sas_base_get_msg_frame(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void *mpt2sas_base_get_sense_buffer(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_build_zero_len_sge(struct MPT2SAS_ADAPTER *ioc, void *paddr); -__le32 mpt2sas_base_get_sense_buffer_dma(struct MPT2SAS_ADAPTER *ioc, - u16 smid); -void mpt2sas_base_flush_reply_queues(struct MPT2SAS_ADAPTER *ioc); - -/* hi-priority queue */ -u16 mpt2sas_base_get_smid_hpr(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); -u16 mpt2sas_base_get_smid_scsiio(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx, - struct scsi_cmnd *scmd); - -u16 mpt2sas_base_get_smid(struct MPT2SAS_ADAPTER *ioc, u8 cb_idx); -void mpt2sas_base_free_smid(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_put_smid_scsi_io(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u16 handle); -void mpt2sas_base_put_smid_hi_priority(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_put_smid_target_assist(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u16 io_index); -void mpt2sas_base_put_smid_default(struct MPT2SAS_ADAPTER *ioc, u16 smid); -void mpt2sas_base_initialize_callback_handler(void); -u8 mpt2sas_base_register_callback_handler(MPT_CALLBACK cb_func); -void mpt2sas_base_release_callback_handler(u8 cb_idx); - -u8 mpt2sas_base_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -u8 mpt2sas_port_enable_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, u32 reply); -void *mpt2sas_base_get_reply_virt_addr(struct MPT2SAS_ADAPTER *ioc, u32 phys_addr); - -u32 mpt2sas_base_get_iocstate(struct MPT2SAS_ADAPTER *ioc, int cooked); - -void mpt2sas_base_fault_info(struct MPT2SAS_ADAPTER *ioc , u16 fault_code); -int mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc, - Mpi2SasIoUnitControlReply_t *mpi_reply, Mpi2SasIoUnitControlRequest_t - *mpi_request); -int mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc, - Mpi2SepReply_t *mpi_reply, Mpi2SepRequest_t *mpi_request); -void mpt2sas_base_validate_event_type(struct MPT2SAS_ADAPTER *ioc, u32 *event_type); - -void mpt2sas_halt_firmware(struct MPT2SAS_ADAPTER *ioc); - -int mpt2sas_port_enable(struct MPT2SAS_ADAPTER *ioc); - -/* scsih shared API */ -u8 mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply); -int mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, - uint channel, uint id, uint lun, u8 type, u16 smid_task, - ulong timeout, unsigned long serial_number, enum mutex_type m_type); -void mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); -void mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle); -void mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -void mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, - u16 handle); -struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER - *ioc, u64 sas_address); -struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address( - struct MPT2SAS_ADAPTER *ioc, u64 sas_address); - -void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc); - -void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); - -/* config shared API */ -u8 mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -int mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys); -int mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page); -int mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page); -int mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2BiosPage2_t *config_page); -int mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2BiosPage3_t *config_page); -int mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOUnitPage0_t *config_page); -int mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz); -int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOUnitPage1_t *config_page); -int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOUnitPage1_t *config_page); -int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); -int mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz); -int mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2IOCPage8_t *config_page); -int mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, u16 handle); -int mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number); -int mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number); -int mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, u32 handle); -int mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 *num_pds); -int mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, u32 handle, u16 sz); -int mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form, - u32 form_specific); -int mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, - u16 *volume_handle); -int mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle, - u64 *wwid); -/* ctl shared API */ -extern struct device_attribute *mpt2sas_host_attrs[]; -extern struct device_attribute *mpt2sas_dev_attrs[]; -void mpt2sas_ctl_init(void); -void mpt2sas_ctl_exit(void); -u8 mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -void mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); -u8 mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply); -void mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventNotificationReply_t *mpi_reply); - -void mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, - u8 bits_to_regsiter); - -/* transport shared API */ -u8 mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply); -struct _sas_port *mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, - u16 handle, u64 sas_address); -void mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u64 sas_address_parent); -int mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy - *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev); -int mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy - *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev); -void mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address, u16 handle, u8 phy_number, u8 link_rate); -extern struct sas_function_template mpt2sas_transport_functions; -extern struct scsi_transport_template *mpt2sas_transport_template; -extern int scsi_internal_device_block(struct scsi_device *sdev); -extern u8 mpt2sas_stm_zero_smid_handler(struct MPT2SAS_ADAPTER *ioc, - u8 msix_index, u32 reply); -extern int scsi_internal_device_unblock(struct scsi_device *sdev); - -#endif /* MPT2SAS_BASE_H_INCLUDED */ diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_config.c b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_config.c deleted file mode 100644 index 2b4d3761..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_config.c +++ /dev/null @@ -1,1454 +0,0 @@ -/* - * This module provides common API for accessing firmware configuration pages - * - * This code is based on drivers/scsi/mpt2sas/mpt2_base.c - * Copyright (C) 2007-2010 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_base.h" - -/* local definitions */ - -/* Timeout for config page request (in seconds) */ -#define MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT 15 - -/* Common sgl flags for READING a config page. */ -#define MPT2_CONFIG_COMMON_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ - | MPI2_SGE_FLAGS_END_OF_LIST) << MPI2_SGE_FLAGS_SHIFT) - -/* Common sgl flags for WRITING a config page. */ -#define MPT2_CONFIG_COMMON_WRITE_SGLFLAGS ((MPI2_SGE_FLAGS_SIMPLE_ELEMENT | \ - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER \ - | MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC) \ - << MPI2_SGE_FLAGS_SHIFT) - -/** - * struct config_request - obtain dma memory via routine - * @sz: size - * @page: virt pointer - * @page_dma: phys pointer - * - */ -struct config_request{ - u16 sz; - void *page; - dma_addr_t page_dma; -}; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _config_display_some_debug - debug routine - * @ioc: per adapter object - * @smid: system request message index - * @calling_function_name: string pass from calling function - * @mpi_reply: reply message frame - * Context: none. - * - * Function for displaying debug info helpful when debugging issues - * in this module. - */ -static void -_config_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, - char *calling_function_name, MPI2DefaultReply_t *mpi_reply) -{ - Mpi2ConfigRequest_t *mpi_request; - char *desc = NULL; - - if (!(ioc->logging_level & MPT_DEBUG_CONFIG)) - return; - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - switch (mpi_request->Header.PageType & MPI2_CONFIG_PAGETYPE_MASK) { - case MPI2_CONFIG_PAGETYPE_IO_UNIT: - desc = "io_unit"; - break; - case MPI2_CONFIG_PAGETYPE_IOC: - desc = "ioc"; - break; - case MPI2_CONFIG_PAGETYPE_BIOS: - desc = "bios"; - break; - case MPI2_CONFIG_PAGETYPE_RAID_VOLUME: - desc = "raid_volume"; - break; - case MPI2_CONFIG_PAGETYPE_MANUFACTURING: - desc = "manufaucturing"; - break; - case MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK: - desc = "physdisk"; - break; - case MPI2_CONFIG_PAGETYPE_EXTENDED: - switch (mpi_request->ExtPageType) { - case MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT: - desc = "sas_io_unit"; - break; - case MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER: - desc = "sas_expander"; - break; - case MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE: - desc = "sas_device"; - break; - case MPI2_CONFIG_EXTPAGETYPE_SAS_PHY: - desc = "sas_phy"; - break; - case MPI2_CONFIG_EXTPAGETYPE_LOG: - desc = "log"; - break; - case MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE: - desc = "enclosure"; - break; - case MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG: - desc = "raid_config"; - break; - case MPI2_CONFIG_EXTPAGETYPE_DRIVER_MAPPING: - desc = "driver_mapping"; - break; - } - break; - } - - if (!desc) - return; - - printk(MPT2SAS_INFO_FMT "%s: %s(%d), action(%d), form(0x%08x), " - "smid(%d)\n", ioc->name, calling_function_name, desc, - mpi_request->Header.PageNumber, mpi_request->Action, - le32_to_cpu(mpi_request->PageAddress), smid); - - if (!mpi_reply) - return; - - if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_INFO_FMT - "\tiocstatus(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); -} -#endif - -/** - * _config_alloc_config_dma_memory - obtain physical memory - * @ioc: per adapter object - * @mem: struct config_request - * - * A wrapper for obtaining dma-able memory for config page request. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_config_alloc_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, - struct config_request *mem) -{ - int r = 0; - - if (mem->sz > ioc->config_page_sz) { - mem->page = dma_alloc_coherent(&ioc->pdev->dev, mem->sz, - &mem->page_dma, GFP_KERNEL); - if (!mem->page) { - printk(MPT2SAS_ERR_FMT "%s: dma_alloc_coherent" - " failed asking for (%d) bytes!!\n", - ioc->name, __func__, mem->sz); - r = -ENOMEM; - } - } else { /* use tmp buffer if less than 512 bytes */ - mem->page = ioc->config_page; - mem->page_dma = ioc->config_page_dma; - } - return r; -} - -/** - * _config_free_config_dma_memory - wrapper to free the memory - * @ioc: per adapter object - * @mem: struct config_request - * - * A wrapper to free dma-able memory when using _config_alloc_config_dma_memory. - * - * Returns 0 for success, non-zero for failure. - */ -static void -_config_free_config_dma_memory(struct MPT2SAS_ADAPTER *ioc, - struct config_request *mem) -{ - if (mem->sz > ioc->config_page_sz) - dma_free_coherent(&ioc->pdev->dev, mem->sz, mem->page, - mem->page_dma); -} - -/** - * mpt2sas_config_done - config page completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using _config_request. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_config_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - if (ioc->config_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->config_cmds.smid != smid) - return 1; - ioc->config_cmds.status |= MPT2_CMD_COMPLETE; - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply) { - ioc->config_cmds.status |= MPT2_CMD_REPLY_VALID; - memcpy(ioc->config_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - } - ioc->config_cmds.status &= ~MPT2_CMD_PENDING; -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _config_display_some_debug(ioc, smid, "config_done", mpi_reply); -#endif - ioc->config_cmds.smid = USHRT_MAX; - complete(&ioc->config_cmds.done); - return 1; -} - -/** - * _config_request - main routine for sending config page requests - * @ioc: per adapter object - * @mpi_request: request message frame - * @mpi_reply: reply mf payload returned from firmware - * @timeout: timeout in seconds - * @config_page: contents of the config page - * @config_page_sz: size of config page - * Context: sleep - * - * A generic API for config page requests to firmware. - * - * The ioc->config_cmds.status flag should be MPT2_CMD_NOT_USED before calling - * this API. - * - * The callback index is set inside `ioc->config_cb_idx. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_config_request(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigRequest_t - *mpi_request, Mpi2ConfigReply_t *mpi_reply, int timeout, - void *config_page, u16 config_page_sz) -{ - u16 smid; - u32 ioc_state; - unsigned long timeleft; - Mpi2ConfigRequest_t *config_request; - int r; - u8 retry_count, issue_host_reset = 0; - u16 wait_state_count; - struct config_request mem; - - mutex_lock(&ioc->config_cmds.mutex); - if (ioc->config_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: config_cmd in use\n", - ioc->name, __func__); - mutex_unlock(&ioc->config_cmds.mutex); - return -EAGAIN; - } - - retry_count = 0; - memset(&mem, 0, sizeof(struct config_request)); - - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - if (config_page) { - mpi_request->Header.PageVersion = mpi_reply->Header.PageVersion; - mpi_request->Header.PageNumber = mpi_reply->Header.PageNumber; - mpi_request->Header.PageType = mpi_reply->Header.PageType; - mpi_request->Header.PageLength = mpi_reply->Header.PageLength; - mpi_request->ExtPageLength = mpi_reply->ExtPageLength; - mpi_request->ExtPageType = mpi_reply->ExtPageType; - if (mpi_request->Header.PageLength) - mem.sz = mpi_request->Header.PageLength * 4; - else - mem.sz = le16_to_cpu(mpi_reply->ExtPageLength) * 4; - r = _config_alloc_config_dma_memory(ioc, &mem); - if (r != 0) - goto out; - if (mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT || - mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM) { - ioc->base_add_sg_single(&mpi_request->PageBufferSGE, - MPT2_CONFIG_COMMON_WRITE_SGLFLAGS | mem.sz, - mem.page_dma); - memcpy(mem.page, config_page, min_t(u16, mem.sz, - config_page_sz)); - } else { - memset(config_page, 0, config_page_sz); - ioc->base_add_sg_single(&mpi_request->PageBufferSGE, - MPT2_CONFIG_COMMON_SGLFLAGS | mem.sz, mem.page_dma); - } - } - - retry_config: - if (retry_count) { - if (retry_count > 2) { /* attempt only 2 retries */ - r = -EFAULT; - goto free_mem; - } - printk(MPT2SAS_INFO_FMT "%s: attempting retry (%d)\n", - ioc->name, __func__, retry_count); - } - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - r = -EFAULT; - goto free_mem; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->config_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - r = -EAGAIN; - goto free_mem; - } - - r = 0; - memset(mpi_reply, 0, sizeof(Mpi2ConfigReply_t)); - ioc->config_cmds.status = MPT2_CMD_PENDING; - config_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->config_cmds.smid = smid; - memcpy(config_request, mpi_request, sizeof(Mpi2ConfigRequest_t)); -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _config_display_some_debug(ioc, smid, "config_request", NULL); -#endif - init_completion(&ioc->config_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->config_cmds.done, - timeout*HZ); - if (!(ioc->config_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2ConfigRequest_t)/4); - retry_count++; - if (ioc->config_cmds.smid == smid) - mpt2sas_base_free_smid(ioc, smid); - if ((ioc->shost_recovery) || (ioc->config_cmds.status & - MPT2_CMD_RESET) || ioc->pci_error_recovery) - goto retry_config; - issue_host_reset = 1; - r = -EFAULT; - goto free_mem; - } - - if (ioc->config_cmds.status & MPT2_CMD_REPLY_VALID) - memcpy(mpi_reply, ioc->config_cmds.reply, - sizeof(Mpi2ConfigReply_t)); - if (retry_count) - printk(MPT2SAS_INFO_FMT "%s: retry (%d) completed!!\n", - ioc->name, __func__, retry_count); - if (config_page && mpi_request->Action == - MPI2_CONFIG_ACTION_PAGE_READ_CURRENT) - memcpy(config_page, mem.page, min_t(u16, mem.sz, - config_page_sz)); - free_mem: - if (config_page) - _config_free_config_dma_memory(ioc, &mem); - out: - ioc->config_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->config_cmds.mutex); - - if (issue_host_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - return r; -} - -/** - * mpt2sas_config_get_manufacturing_pg0 - obtain manufacturing page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_manufacturing_pg0(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage0_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_manufacturing_pg10 - obtain manufacturing page 10 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_manufacturing_pg10(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2ManufacturingPage10_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_MANUFACTURING; - mpi_request.Header.PageNumber = 10; - mpi_request.Header.PageVersion = MPI2_MANUFACTURING0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_bios_pg2 - obtain bios page 2 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_bios_pg2(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2BiosPage2_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; - mpi_request.Header.PageNumber = 2; - mpi_request.Header.PageVersion = MPI2_BIOSPAGE2_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_bios_pg3 - obtain bios page 3 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_bios_pg3(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2BiosPage3_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_BIOS; - mpi_request.Header.PageNumber = 3; - mpi_request.Header.PageVersion = MPI2_BIOSPAGE3_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_iounit_pg0 - obtain iounit page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage0_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_iounit_pg1 - obtain iounit page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_set_iounit_pg1 - set iounit page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage1_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_IOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_ioc_pg8 - obtain ioc page 8 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_ioc_pg8(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2IOCPage8_t *config_page) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IOC; - mpi_request.Header.PageNumber = 8; - mpi_request.Header.PageVersion = MPI2_IOCPAGE8_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_sas_device_pg0 - obtain sas device page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: device handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_sas_device_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasDevicePage0_t *config_page, u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; - mpi_request.Header.PageVersion = MPI2_SASDEVICE0_PAGEVERSION; - mpi_request.Header.PageNumber = 0; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_sas_device_pg1 - obtain sas device page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: device handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_sas_device_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasDevicePage1_t *config_page, u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_DEVICE; - mpi_request.Header.PageVersion = MPI2_SASDEVICE1_PAGEVERSION; - mpi_request.Header.PageNumber = 1; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_number_hba_phys - obtain number of phys on the host - * @ioc: per adapter object - * @num_phys: pointer returned with the number of phys - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_number_hba_phys(struct MPT2SAS_ADAPTER *ioc, u8 *num_phys) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - u16 ioc_status; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage0_t config_page; - - *num_phys = 0; - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, - sizeof(Mpi2SasIOUnitPage0_t)); - if (!r) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) - *num_phys = config_page.NumPhys; - } - out: - return r; -} - -/** - * mpt2sas_config_get_sas_iounit_pg0 - obtain sas iounit page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Calling function should call config_get_number_hba_phys prior to - * this function, so enough memory is allocated for config_page. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_sas_iounit_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage0_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_sas_iounit_pg1 - obtain sas iounit page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Calling function should call config_get_number_hba_phys prior to - * this function, so enough memory is allocated for config_page. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_set_sas_iounit_pg1 - send sas iounit page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Calling function should call config_get_number_hba_phys prior to - * this function, so enough memory is allocated for config_page. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_set_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasIOUnitPage1_t *config_page, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_IO_UNIT; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASIOUNITPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_CURRENT; - _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_WRITE_NVRAM; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_expander_pg0 - obtain expander page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: expander handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_expander_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2ExpanderPage0_t *config_page, u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASEXPANDER0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_expander_pg1 - obtain expander page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @phy_number: phy number - * @handle: expander handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_expander_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2ExpanderPage1_t *config_page, u32 phy_number, - u16 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_EXPANDER; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASEXPANDER1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = - cpu_to_le32(MPI2_SAS_EXPAND_PGAD_FORM_HNDL_PHY_NUM | - (phy_number << MPI2_SAS_EXPAND_PGAD_PHYNUM_SHIFT) | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_enclosure_pg0 - obtain enclosure page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: expander handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_enclosure_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasEnclosurePage0_t *config_page, u32 form, u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_ENCLOSURE; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASENCLOSURE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_phy_pg0 - obtain phy page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @phy_number: phy number - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_phy_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasPhyPage0_t *config_page, u32 phy_number) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_SASPHY0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = - cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_phy_pg1 - obtain phy page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @phy_number: phy number - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_phy_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2SasPhyPage1_t *config_page, u32 phy_number) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_SAS_PHY; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_SASPHY1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = - cpu_to_le32(MPI2_SAS_PHY_PGAD_FORM_PHY_NUMBER | phy_number); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_raid_volume_pg1 - obtain raid volume page 1 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: volume handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_raid_volume_pg1(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage1_t *config_page, u32 form, - u32 handle) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; - mpi_request.Header.PageNumber = 1; - mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE1_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_number_pds - obtain number of phys disk assigned to volume - * @ioc: per adapter object - * @handle: volume handle - * @num_pds: returns pds count - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_number_pds(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u8 *num_pds) -{ - Mpi2ConfigRequest_t mpi_request; - Mpi2RaidVolPage0_t config_page; - Mpi2ConfigReply_t mpi_reply; - int r; - u16 ioc_status; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - *num_pds = 0; - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = - cpu_to_le32(MPI2_RAID_VOLUME_PGAD_FORM_HANDLE | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, &config_page, - sizeof(Mpi2RaidVolPage0_t)); - if (!r) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) - *num_pds = config_page.NumPhysDisks; - } - - out: - return r; -} - -/** - * mpt2sas_config_get_raid_volume_pg0 - obtain raid volume page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_HANDLE or HANDLE - * @handle: volume handle - * @sz: size of buffer passed in config_page - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_raid_volume_pg0(struct MPT2SAS_ADAPTER *ioc, - Mpi2ConfigReply_t *mpi_reply, Mpi2RaidVolPage0_t *config_page, u32 form, - u32 handle, u16 sz) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_VOLUME; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_RAIDVOLPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | handle); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, sz); - out: - return r; -} - -/** - * mpt2sas_config_get_phys_disk_pg0 - obtain phys disk page 0 - * @ioc: per adapter object - * @mpi_reply: reply mf payload returned from firmware - * @config_page: contents of the config page - * @form: GET_NEXT_PHYSDISKNUM, PHYSDISKNUM, DEVHANDLE - * @form_specific: specific to the form - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_phys_disk_pg0(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t - *mpi_reply, Mpi2RaidPhysDiskPage0_t *config_page, u32 form, - u32 form_specific) -{ - Mpi2ConfigRequest_t mpi_request; - int r; - - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK; - mpi_request.Header.PageNumber = 0; - mpi_request.Header.PageVersion = MPI2_RAIDPHYSDISKPAGE0_PAGEVERSION; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.PageAddress = cpu_to_le32(form | form_specific); - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - r = _config_request(ioc, &mpi_request, mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - sizeof(*config_page)); - out: - return r; -} - -/** - * mpt2sas_config_get_volume_handle - returns volume handle for give hidden raid components - * @ioc: per adapter object - * @pd_handle: phys disk handle - * @volume_handle: volume handle - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_volume_handle(struct MPT2SAS_ADAPTER *ioc, u16 pd_handle, - u16 *volume_handle) -{ - Mpi2RaidConfigurationPage0_t *config_page = NULL; - Mpi2ConfigRequest_t mpi_request; - Mpi2ConfigReply_t mpi_reply; - int r, i, config_page_sz; - u16 ioc_status; - int config_num; - u16 element_type; - u16 phys_disk_dev_handle; - - *volume_handle = 0; - memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t)); - mpi_request.Function = MPI2_FUNCTION_CONFIG; - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER; - mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_EXTENDED; - mpi_request.ExtPageType = MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG; - mpi_request.Header.PageVersion = MPI2_RAIDCONFIG0_PAGEVERSION; - mpi_request.Header.PageNumber = 0; - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0); - if (r) - goto out; - - mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT; - config_page_sz = (le16_to_cpu(mpi_reply.ExtPageLength) * 4); - config_page = kmalloc(config_page_sz, GFP_KERNEL); - if (!config_page) { - r = -1; - goto out; - } - config_num = 0xff; - while (1) { - mpi_request.PageAddress = cpu_to_le32(config_num + - MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM); - r = _config_request(ioc, &mpi_request, &mpi_reply, - MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page, - config_page_sz); - if (r) - goto out; - r = -1; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto out; - for (i = 0; i < config_page->NumElements; i++) { - element_type = le16_to_cpu(config_page-> - ConfigElement[i].ElementFlags) & - MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE; - if (element_type == - MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT || - element_type == - MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT) { - phys_disk_dev_handle = - le16_to_cpu(config_page->ConfigElement[i]. - PhysDiskDevHandle); - if (phys_disk_dev_handle == pd_handle) { - *volume_handle = - le16_to_cpu(config_page-> - ConfigElement[i].VolDevHandle); - r = 0; - goto out; - } - } else if (element_type == - MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT) { - *volume_handle = 0; - r = 0; - goto out; - } - } - config_num = config_page->ConfigNum; - } - out: - kfree(config_page); - return r; -} - -/** - * mpt2sas_config_get_volume_wwid - returns wwid given the volume handle - * @ioc: per adapter object - * @volume_handle: volume handle - * @wwid: volume wwid - * Context: sleep. - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_config_get_volume_wwid(struct MPT2SAS_ADAPTER *ioc, u16 volume_handle, - u64 *wwid) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2RaidVolPage1_t raid_vol_pg1; - - *wwid = 0; - if (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &raid_vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, - volume_handle))) { - *wwid = le64_to_cpu(raid_vol_pg1.WWID); - return 0; - } else - return -1; -} diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.c deleted file mode 100644 index 3b9a28ef..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ /dev/null @@ -1,3058 +0,0 @@ -/* - * Management Module Support for MPT (Message Passing Technology) based - * controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c - * Copyright (C) 2007-2010 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "mpt2sas_base.h" -#include "mpt2sas_ctl.h" - -static DEFINE_MUTEX(_ctl_mutex); -static struct fasync_struct *async_queue; -static DECLARE_WAIT_QUEUE_HEAD(ctl_poll_wait); - -static int _ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, - u8 *issue_reset); - -/** - * enum block_state - blocking state - * @NON_BLOCKING: non blocking - * @BLOCKING: blocking - * - * These states are for ioctls that need to wait for a response - * from firmware, so they probably require sleep. - */ -enum block_state { - NON_BLOCKING, - BLOCKING, -}; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _ctl_sas_device_find_by_handle - sas device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for sas_device based on sas_address, then return sas_device - * object. - */ -static struct _sas_device * -_ctl_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device, *r; - - r = NULL; - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->handle != handle) - continue; - r = sas_device; - goto out; - } - - out: - return r; -} - -/** - * _ctl_display_some_debug - debug routine - * @ioc: per adapter object - * @smid: system request message index - * @calling_function_name: string pass from calling function - * @mpi_reply: reply message frame - * Context: none. - * - * Function for displaying debug info helpful when debugging issues - * in this module. - */ -static void -_ctl_display_some_debug(struct MPT2SAS_ADAPTER *ioc, u16 smid, - char *calling_function_name, MPI2DefaultReply_t *mpi_reply) -{ - Mpi2ConfigRequest_t *mpi_request; - char *desc = NULL; - - if (!(ioc->logging_level & MPT_DEBUG_IOCTL)) - return; - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - switch (mpi_request->Function) { - case MPI2_FUNCTION_SCSI_IO_REQUEST: - { - Mpi2SCSIIORequest_t *scsi_request = - (Mpi2SCSIIORequest_t *)mpi_request; - - snprintf(ioc->tmp_string, MPT_STRING_LENGTH, - "scsi_io, cmd(0x%02x), cdb_len(%d)", - scsi_request->CDB.CDB32[0], - le16_to_cpu(scsi_request->IoFlags) & 0xF); - desc = ioc->tmp_string; - break; - } - case MPI2_FUNCTION_SCSI_TASK_MGMT: - desc = "task_mgmt"; - break; - case MPI2_FUNCTION_IOC_INIT: - desc = "ioc_init"; - break; - case MPI2_FUNCTION_IOC_FACTS: - desc = "ioc_facts"; - break; - case MPI2_FUNCTION_CONFIG: - { - Mpi2ConfigRequest_t *config_request = - (Mpi2ConfigRequest_t *)mpi_request; - - snprintf(ioc->tmp_string, MPT_STRING_LENGTH, - "config, type(0x%02x), ext_type(0x%02x), number(%d)", - (config_request->Header.PageType & - MPI2_CONFIG_PAGETYPE_MASK), config_request->ExtPageType, - config_request->Header.PageNumber); - desc = ioc->tmp_string; - break; - } - case MPI2_FUNCTION_PORT_FACTS: - desc = "port_facts"; - break; - case MPI2_FUNCTION_PORT_ENABLE: - desc = "port_enable"; - break; - case MPI2_FUNCTION_EVENT_NOTIFICATION: - desc = "event_notification"; - break; - case MPI2_FUNCTION_FW_DOWNLOAD: - desc = "fw_download"; - break; - case MPI2_FUNCTION_FW_UPLOAD: - desc = "fw_upload"; - break; - case MPI2_FUNCTION_RAID_ACTION: - desc = "raid_action"; - break; - case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: - { - Mpi2SCSIIORequest_t *scsi_request = - (Mpi2SCSIIORequest_t *)mpi_request; - - snprintf(ioc->tmp_string, MPT_STRING_LENGTH, - "raid_pass, cmd(0x%02x), cdb_len(%d)", - scsi_request->CDB.CDB32[0], - le16_to_cpu(scsi_request->IoFlags) & 0xF); - desc = ioc->tmp_string; - break; - } - case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: - desc = "sas_iounit_cntl"; - break; - case MPI2_FUNCTION_SATA_PASSTHROUGH: - desc = "sata_pass"; - break; - case MPI2_FUNCTION_DIAG_BUFFER_POST: - desc = "diag_buffer_post"; - break; - case MPI2_FUNCTION_DIAG_RELEASE: - desc = "diag_release"; - break; - case MPI2_FUNCTION_SMP_PASSTHROUGH: - desc = "smp_passthrough"; - break; - } - - if (!desc) - return; - - printk(MPT2SAS_INFO_FMT "%s: %s, smid(%d)\n", - ioc->name, calling_function_name, desc, smid); - - if (!mpi_reply) - return; - - if (mpi_reply->IOCStatus || mpi_reply->IOCLogInfo) - printk(MPT2SAS_INFO_FMT - "\tiocstatus(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); - - if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - Mpi2SCSIIOReply_t *scsi_reply = - (Mpi2SCSIIOReply_t *)mpi_reply; - struct _sas_device *sas_device = NULL; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _ctl_sas_device_find_by_handle(ioc, - le16_to_cpu(scsi_reply->DevHandle)); - if (sas_device) { - printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " - "phy(%d)\n", ioc->name, (unsigned long long) - sas_device->sas_address, sas_device->phy); - printk(MPT2SAS_WARN_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, sas_device->enclosure_logical_id, - sas_device->slot); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (scsi_reply->SCSIState || scsi_reply->SCSIStatus) - printk(MPT2SAS_INFO_FMT - "\tscsi_state(0x%02x), scsi_status" - "(0x%02x)\n", ioc->name, - scsi_reply->SCSIState, - scsi_reply->SCSIStatus); - } -} -#endif - -/** - * mpt2sas_ctl_done - ctl module completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using ioc->ctl_cb_idx. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_ctl_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - Mpi2SCSIIOReply_t *scsiio_reply; - const void *sense_data; - u32 sz; - - if (ioc->ctl_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->ctl_cmds.smid != smid) - return 1; - ioc->ctl_cmds.status |= MPT2_CMD_COMPLETE; - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply) { - memcpy(ioc->ctl_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); - ioc->ctl_cmds.status |= MPT2_CMD_REPLY_VALID; - /* get sense data */ - if (mpi_reply->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_reply->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - scsiio_reply = (Mpi2SCSIIOReply_t *)mpi_reply; - if (scsiio_reply->SCSIState & - MPI2_SCSI_STATE_AUTOSENSE_VALID) { - sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, - le32_to_cpu(scsiio_reply->SenseCount)); - sense_data = mpt2sas_base_get_sense_buffer(ioc, - smid); - memcpy(ioc->ctl_cmds.sense, sense_data, sz); - } - } - } -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _ctl_display_some_debug(ioc, smid, "ctl_done", mpi_reply); -#endif - ioc->ctl_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->ctl_cmds.done); - return 1; -} - -/** - * _ctl_check_event_type - determines when an event needs logging - * @ioc: per adapter object - * @event: firmware event - * - * The bitmask in ioc->event_type[] indicates which events should be - * be saved in the driver event_log. This bitmask is set by application. - * - * Returns 1 when event should be captured, or zero means no match. - */ -static int -_ctl_check_event_type(struct MPT2SAS_ADAPTER *ioc, u16 event) -{ - u16 i; - u32 desired_event; - - if (event >= 128 || !event || !ioc->event_log) - return 0; - - desired_event = (1 << (event % 32)); - if (!desired_event) - desired_event = 1; - i = event / 32; - return desired_event & ioc->event_type[i]; -} - -/** - * mpt2sas_ctl_add_to_event_log - add event - * @ioc: per adapter object - * @mpi_reply: reply message frame - * - * Return nothing. - */ -void -mpt2sas_ctl_add_to_event_log(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventNotificationReply_t *mpi_reply) -{ - struct MPT2_IOCTL_EVENTS *event_log; - u16 event; - int i; - u32 sz, event_data_sz; - u8 send_aen = 0; - - if (!ioc->event_log) - return; - - event = le16_to_cpu(mpi_reply->Event); - - if (_ctl_check_event_type(ioc, event)) { - - /* insert entry into circular event_log */ - i = ioc->event_context % MPT2SAS_CTL_EVENT_LOG_SIZE; - event_log = ioc->event_log; - event_log[i].event = event; - event_log[i].context = ioc->event_context++; - - event_data_sz = le16_to_cpu(mpi_reply->EventDataLength)*4; - sz = min_t(u32, event_data_sz, MPT2_EVENT_DATA_SIZE); - memset(event_log[i].data, 0, MPT2_EVENT_DATA_SIZE); - memcpy(event_log[i].data, mpi_reply->EventData, sz); - send_aen = 1; - } - - /* This aen_event_read_flag flag is set until the - * application has read the event log. - * For MPI2_EVENT_LOG_ENTRY_ADDED, we always notify. - */ - if (event == MPI2_EVENT_LOG_ENTRY_ADDED || - (send_aen && !ioc->aen_event_read_flag)) { - ioc->aen_event_read_flag = 1; - wake_up_interruptible(&ctl_poll_wait); - if (async_queue) - kill_fasync(&async_queue, SIGIO, POLL_IN); - } -} - -/** - * mpt2sas_ctl_event_callback - firmware event handler (called at ISR time) - * @ioc: per adapter object - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt. - * - * This function merely adds a new work task into ioc->firmware_event_thread. - * The tasks are worked from _firmware_event_work in user context. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_ctl_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply) -{ - Mpi2EventNotificationReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - mpt2sas_ctl_add_to_event_log(ioc, mpi_reply); - return 1; -} - -/** - * _ctl_verify_adapter - validates ioc_number passed from application - * @ioc: per adapter object - * @iocpp: The ioc pointer is returned in this. - * - * Return (-1) means error, else ioc_number. - */ -static int -_ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp) -{ - struct MPT2SAS_ADAPTER *ioc; - - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - if (ioc->id != ioc_number) - continue; - *iocpp = ioc; - return ioc_number; - } - *iocpp = NULL; - return -1; -} - -/** - * mpt2sas_ctl_reset_handler - reset callback handler (for ctl) - * @ioc: per adapter object - * @reset_phase: phase - * - * The handler for doing any required cleanup or initialization. - * - * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, - * MPT2_IOC_DONE_RESET - */ -void -mpt2sas_ctl_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) -{ - int i; - u8 issue_reset; - - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!(ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_REGISTERED)) - continue; - if ((ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - continue; - _ctl_send_release(ioc, i, &issue_reset); - } - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->ctl_cmds.status & MPT2_CMD_PENDING) { - ioc->ctl_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->ctl_cmds.smid); - complete(&ioc->ctl_cmds.done); - } - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!(ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_REGISTERED)) - continue; - if ((ioc->diag_buffer_status[i] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - continue; - ioc->diag_buffer_status[i] |= - MPT2_DIAG_BUFFER_IS_DIAG_RESET; - } - break; - } -} - -/** - * _ctl_fasync - - * @fd - - * @filep - - * @mode - - * - * Called when application request fasyn callback handler. - */ -static int -_ctl_fasync(int fd, struct file *filep, int mode) -{ - return fasync_helper(fd, filep, mode, &async_queue); -} - -/** - * _ctl_release - - * @inode - - * @filep - - * - * Called when application releases the fasyn callback handler. - */ -static int -_ctl_release(struct inode *inode, struct file *filep) -{ - return fasync_helper(-1, filep, 0, &async_queue); -} - -/** - * _ctl_poll - - * @file - - * @wait - - * - */ -static unsigned int -_ctl_poll(struct file *filep, poll_table *wait) -{ - struct MPT2SAS_ADAPTER *ioc; - - poll_wait(filep, &ctl_poll_wait, wait); - - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - if (ioc->aen_event_read_flag) - return POLLIN | POLLRDNORM; - } - return 0; -} - -/** - * _ctl_set_task_mid - assign an active smid to tm request - * @ioc: per adapter object - * @karg - (struct mpt2_ioctl_command) - * @tm_request - pointer to mf from user space - * - * Returns 0 when an smid if found, else fail. - * during failure, the reply frame is filled. - */ -static int -_ctl_set_task_mid(struct MPT2SAS_ADAPTER *ioc, struct mpt2_ioctl_command *karg, - Mpi2SCSITaskManagementRequest_t *tm_request) -{ - u8 found = 0; - u16 i; - u16 handle; - struct scsi_cmnd *scmd; - struct MPT2SAS_DEVICE *priv_data; - unsigned long flags; - Mpi2SCSITaskManagementReply_t *tm_reply; - u32 sz; - u32 lun; - char *desc = NULL; - - if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - desc = "abort_task"; - else if (tm_request->TaskType == MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) - desc = "query_task"; - else - return 0; - - lun = scsilun_to_int((struct scsi_lun *)tm_request->LUN); - - handle = le16_to_cpu(tm_request->DevHandle); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - for (i = ioc->scsiio_depth; i && !found; i--) { - scmd = ioc->scsi_lookup[i - 1].scmd; - if (scmd == NULL || scmd->device == NULL || - scmd->device->hostdata == NULL) - continue; - if (lun != scmd->device->lun) - continue; - priv_data = scmd->device->hostdata; - if (priv_data->sas_target == NULL) - continue; - if (priv_data->sas_target->handle != handle) - continue; - tm_request->TaskMID = cpu_to_le16(ioc->scsi_lookup[i - 1].smid); - found = 1; - } - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - if (!found) { - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "handle(0x%04x), lun(%d), no active mid!!\n", ioc->name, - desc, le16_to_cpu(tm_request->DevHandle), lun)); - tm_reply = ioc->ctl_cmds.reply; - tm_reply->DevHandle = tm_request->DevHandle; - tm_reply->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - tm_reply->TaskType = tm_request->TaskType; - tm_reply->MsgLength = sizeof(Mpi2SCSITaskManagementReply_t)/4; - tm_reply->VP_ID = tm_request->VP_ID; - tm_reply->VF_ID = tm_request->VF_ID; - sz = min_t(u32, karg->max_reply_bytes, ioc->reply_sz); - if (copy_to_user(karg->reply_frame_buf_ptr, ioc->ctl_cmds.reply, - sz)) - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - return 1; - } - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "handle(0x%04x), lun(%d), task_mid(%d)\n", ioc->name, - desc, le16_to_cpu(tm_request->DevHandle), lun, - le16_to_cpu(tm_request->TaskMID))); - return 0; -} - -/** - * _ctl_do_mpt_command - main handler for MPT2COMMAND opcode - * @ioc: per adapter object - * @karg - (struct mpt2_ioctl_command) - * @mf - pointer to mf in user space - * @state - NON_BLOCKING or BLOCKING - */ -static long -_ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_ioctl_command karg, void __user *mf, enum block_state state) -{ - MPI2RequestHeader_t *mpi_request = NULL, *request; - MPI2DefaultReply_t *mpi_reply; - u32 ioc_state; - u16 ioc_status; - u16 smid; - unsigned long timeout, timeleft; - u8 issue_reset; - u32 sz; - void *psge; - void *data_out = NULL; - dma_addr_t data_out_dma; - size_t data_out_sz = 0; - void *data_in = NULL; - dma_addr_t data_in_dma; - size_t data_in_sz = 0; - u32 sgl_flags; - long ret; - u16 wait_state_count; - - issue_reset = 0; - - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - ret = -EAGAIN; - goto out; - } - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - ret = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); - if (!mpi_request) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a memory for " - "mpi_request\n", ioc->name, __func__); - ret = -ENOMEM; - goto out; - } - - /* Check for overflow and wraparound */ - if (karg.data_sge_offset * 4 > ioc->request_sz || - karg.data_sge_offset > (UINT_MAX / 4)) { - ret = -EINVAL; - goto out; - } - - /* copy in request message frame from user */ - if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, __LINE__, - __func__); - ret = -EFAULT; - goto out; - } - - if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ret = -EAGAIN; - goto out; - } - } else { - - smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->ctl_cb_idx, NULL); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ret = -EAGAIN; - goto out; - } - } - - ret = 0; - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - request = mpt2sas_base_get_msg_frame(ioc, smid); - memcpy(request, mpi_request, karg.data_sge_offset*4); - ioc->ctl_cmds.smid = smid; - data_out_sz = karg.data_out_size; - data_in_sz = karg.data_in_size; - - if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_request->Function == MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH) { - if (!le16_to_cpu(mpi_request->FunctionDependent1) || - le16_to_cpu(mpi_request->FunctionDependent1) > - ioc->facts.MaxDevHandle) { - ret = -EINVAL; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - /* obtain dma-able memory for data transfer */ - if (data_out_sz) /* WRITE */ { - data_out = pci_alloc_consistent(ioc->pdev, data_out_sz, - &data_out_dma); - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - if (copy_from_user(data_out, karg.data_out_buf_ptr, - data_out_sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -EFAULT; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - if (data_in_sz) /* READ */ { - data_in = pci_alloc_consistent(ioc->pdev, data_in_sz, - &data_in_dma); - if (!data_in) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - /* add scatter gather elements */ - psge = (void *)request + (karg.data_sge_offset*4); - - if (!data_out_sz && !data_in_sz) { - mpt2sas_base_build_zero_len_sge(ioc, psge); - } else if (data_out_sz && data_in_sz) { - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - data_out_sz, data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - data_in_sz, data_in_dma); - } else if (data_out_sz) /* WRITE */ { - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - data_out_sz, data_out_dma); - } else if (data_in_sz) /* READ */ { - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - data_in_sz, data_in_dma); - } - - /* send command to firmware */ -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - _ctl_display_some_debug(ioc, smid, "ctl_request", NULL); -#endif - - init_completion(&ioc->ctl_cmds.done); - switch (mpi_request->Function) { - case MPI2_FUNCTION_SCSI_IO_REQUEST: - case MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH: - { - Mpi2SCSIIORequest_t *scsiio_request = - (Mpi2SCSIIORequest_t *)request; - scsiio_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; - scsiio_request->SenseBufferLowAddress = - mpt2sas_base_get_sense_buffer_dma(ioc, smid); - memset(ioc->ctl_cmds.sense, 0, SCSI_SENSE_BUFFERSIZE); - if (mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST) - mpt2sas_base_put_smid_scsi_io(ioc, smid, - le16_to_cpu(mpi_request->FunctionDependent1)); - else - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - case MPI2_FUNCTION_SCSI_TASK_MGMT: - { - Mpi2SCSITaskManagementRequest_t *tm_request = - (Mpi2SCSITaskManagementRequest_t *)request; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "TASK_MGMT: " - "handle(0x%04x), task_type(0x%02x)\n", ioc->name, - le16_to_cpu(tm_request->DevHandle), tm_request->TaskType)); - - if (tm_request->TaskType == - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK || - tm_request->TaskType == - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK) { - if (_ctl_set_task_mid(ioc, &karg, tm_request)) { - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - mpt2sas_scsih_set_tm_flag(ioc, le16_to_cpu( - tm_request->DevHandle)); - mpt2sas_base_put_smid_hi_priority(ioc, smid); - break; - } - case MPI2_FUNCTION_SMP_PASSTHROUGH: - { - Mpi2SmpPassthroughRequest_t *smp_request = - (Mpi2SmpPassthroughRequest_t *)mpi_request; - u8 *data; - - /* ioc determines which port to use */ - smp_request->PhysicalPort = 0xFF; - if (smp_request->PassthroughFlags & - MPI2_SMP_PT_REQ_PT_FLAGS_IMMEDIATE) - data = (u8 *)&smp_request->SGL; - else - data = data_out; - - if (data[1] == 0x91 && (data[10] == 1 || data[10] == 2)) { - ioc->ioc_link_reset_in_progress = 1; - ioc->ignore_loginfos = 1; - } - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - case MPI2_FUNCTION_SAS_IO_UNIT_CONTROL: - { - Mpi2SasIoUnitControlRequest_t *sasiounit_request = - (Mpi2SasIoUnitControlRequest_t *)mpi_request; - - if (sasiounit_request->Operation == MPI2_SAS_OP_PHY_HARD_RESET - || sasiounit_request->Operation == - MPI2_SAS_OP_PHY_LINK_RESET) { - ioc->ioc_link_reset_in_progress = 1; - ioc->ignore_loginfos = 1; - } - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - default: - mpt2sas_base_put_smid_default(ioc, smid); - break; - } - - if (karg.timeout < MPT2_IOCTL_DEFAULT_TIMEOUT) - timeout = MPT2_IOCTL_DEFAULT_TIMEOUT; - else - timeout = karg.timeout; - timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, - timeout*HZ); - if (mpi_request->Function == MPI2_FUNCTION_SCSI_TASK_MGMT) { - Mpi2SCSITaskManagementRequest_t *tm_request = - (Mpi2SCSITaskManagementRequest_t *)mpi_request; - mpt2sas_scsih_clear_tm_flag(ioc, le16_to_cpu( - tm_request->DevHandle)); - } else if ((mpi_request->Function == MPI2_FUNCTION_SMP_PASSTHROUGH || - mpi_request->Function == MPI2_FUNCTION_SAS_IO_UNIT_CONTROL) && - ioc->ioc_link_reset_in_progress) { - ioc->ioc_link_reset_in_progress = 0; - ioc->ignore_loginfos = 0; - } - if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, - __func__); - _debug_dump_mf(mpi_request, karg.data_sge_offset); - if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - mpi_reply = ioc->ctl_cmds.reply; - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (mpi_reply->Function == MPI2_FUNCTION_SCSI_TASK_MGMT && - (ioc->logging_level & MPT_DEBUG_TM)) { - Mpi2SCSITaskManagementReply_t *tm_reply = - (Mpi2SCSITaskManagementReply_t *)mpi_reply; - - printk(MPT2SAS_INFO_FMT "TASK_MGMT: " - "IOCStatus(0x%04x), IOCLogInfo(0x%08x), " - "TerminationCount(0x%08x)\n", ioc->name, - le16_to_cpu(tm_reply->IOCStatus), - le32_to_cpu(tm_reply->IOCLogInfo), - le32_to_cpu(tm_reply->TerminationCount)); - } -#endif - /* copy out xdata to user */ - if (data_in_sz) { - if (copy_to_user(karg.data_in_buf_ptr, data_in, - data_in_sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENODATA; - goto out; - } - } - - /* copy out reply message frame to user */ - if (karg.max_reply_bytes) { - sz = min_t(u32, karg.max_reply_bytes, ioc->reply_sz); - if (copy_to_user(karg.reply_frame_buf_ptr, ioc->ctl_cmds.reply, - sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENODATA; - goto out; - } - } - - /* copy out sense to user */ - if (karg.max_sense_bytes && (mpi_request->Function == - MPI2_FUNCTION_SCSI_IO_REQUEST || mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { - sz = min_t(u32, karg.max_sense_bytes, SCSI_SENSE_BUFFERSIZE); - if (copy_to_user(karg.sense_data_ptr, - ioc->ctl_cmds.sense, sz)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - ret = -ENODATA; - goto out; - } - } - - issue_host_reset: - if (issue_reset) { - ret = -ENODATA; - if ((mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST || - mpi_request->Function == - MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH)) { - printk(MPT2SAS_INFO_FMT "issue target reset: handle " - "= (0x%04x)\n", ioc->name, - le16_to_cpu(mpi_request->FunctionDependent1)); - mpt2sas_halt_firmware(ioc); - mpt2sas_scsih_issue_tm(ioc, - le16_to_cpu(mpi_request->FunctionDependent1), 0, 0, - 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, 10, - 0, TM_MUTEX_ON); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - } else - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - } - - out: - - /* free memory associated with sg buffers */ - if (data_in) - pci_free_consistent(ioc->pdev, data_in_sz, data_in, - data_in_dma); - - if (data_out) - pci_free_consistent(ioc->pdev, data_out_sz, data_out, - data_out_dma); - - kfree(mpi_request); - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->ctl_cmds.mutex); - return ret; -} - -/** - * _ctl_getiocinfo - main handler for MPT2IOCINFO opcode - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_getiocinfo(void __user *arg) -{ - struct mpt2_ioctl_iocinfo karg; - struct MPT2SAS_ADAPTER *ioc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - memset(&karg, 0 , sizeof(karg)); - if (ioc->is_warpdrive) - karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2_SSS6200; - else - karg.adapter_type = MPT2_IOCTL_INTERFACE_SAS2; - if (ioc->pfacts) - karg.port_number = ioc->pfacts[0].PortNumber; - karg.hw_rev = ioc->pdev->revision; - karg.pci_id = ioc->pdev->device; - karg.subsystem_device = ioc->pdev->subsystem_device; - karg.subsystem_vendor = ioc->pdev->subsystem_vendor; - karg.pci_information.u.bits.bus = ioc->pdev->bus->number; - karg.pci_information.u.bits.device = PCI_SLOT(ioc->pdev->devfn); - karg.pci_information.u.bits.function = PCI_FUNC(ioc->pdev->devfn); - karg.pci_information.segment_id = pci_domain_nr(ioc->pdev->bus); - karg.firmware_version = ioc->facts.FWVersion.Word; - strcpy(karg.driver_version, MPT2SAS_DRIVER_NAME); - strcat(karg.driver_version, "-"); - strcat(karg.driver_version, MPT2SAS_DRIVER_VERSION); - karg.bios_version = le32_to_cpu(ioc->bios_pg3.BiosVersion); - - if (copy_to_user(arg, &karg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - return 0; -} - -/** - * _ctl_eventquery - main handler for MPT2EVENTQUERY opcode - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventquery(void __user *arg) -{ - struct mpt2_ioctl_eventquery karg; - struct MPT2SAS_ADAPTER *ioc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - karg.event_entries = MPT2SAS_CTL_EVENT_LOG_SIZE; - memcpy(karg.event_types, ioc->event_type, - MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); - - if (copy_to_user(arg, &karg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - return 0; -} - -/** - * _ctl_eventenable - main handler for MPT2EVENTENABLE opcode - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventenable(void __user *arg) -{ - struct mpt2_ioctl_eventenable karg; - struct MPT2SAS_ADAPTER *ioc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - if (ioc->event_log) - return 0; - memcpy(ioc->event_type, karg.event_types, - MPI2_EVENT_NOTIFY_EVENTMASK_WORDS * sizeof(u32)); - mpt2sas_base_validate_event_type(ioc, ioc->event_type); - - /* initialize event_log */ - ioc->event_context = 0; - ioc->aen_event_read_flag = 0; - ioc->event_log = kcalloc(MPT2SAS_CTL_EVENT_LOG_SIZE, - sizeof(struct MPT2_IOCTL_EVENTS), GFP_KERNEL); - if (!ioc->event_log) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -ENOMEM; - } - return 0; -} - -/** - * _ctl_eventreport - main handler for MPT2EVENTREPORT opcode - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_eventreport(void __user *arg) -{ - struct mpt2_ioctl_eventreport karg; - struct MPT2SAS_ADAPTER *ioc; - u32 number_bytes, max_events, max; - struct mpt2_ioctl_eventreport __user *uarg = arg; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - number_bytes = karg.hdr.max_data_size - - sizeof(struct mpt2_ioctl_header); - max_events = number_bytes/sizeof(struct MPT2_IOCTL_EVENTS); - max = min_t(u32, MPT2SAS_CTL_EVENT_LOG_SIZE, max_events); - - /* If fewer than 1 event is requested, there must have - * been some type of error. - */ - if (!max || !ioc->event_log) - return -ENODATA; - - number_bytes = max * sizeof(struct MPT2_IOCTL_EVENTS); - if (copy_to_user(uarg->event_data, ioc->event_log, number_bytes)) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - /* reset flag so SIGIO can restart */ - ioc->aen_event_read_flag = 0; - return 0; -} - -/** - * _ctl_do_reset - main handler for MPT2HARDRESET opcode - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_do_reset(void __user *arg) -{ - struct mpt2_ioctl_diag_reset karg; - struct MPT2SAS_ADAPTER *ioc; - int retval; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter\n", ioc->name, - __func__)); - - retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - printk(MPT2SAS_INFO_FMT "host reset: %s\n", - ioc->name, ((!retval) ? "SUCCESS" : "FAILED")); - return 0; -} - -/** - * _ctl_btdh_search_sas_device - searching for sas device - * @ioc: per adapter object - * @btdh: btdh ioctl payload - */ -static int -_ctl_btdh_search_sas_device(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_ioctl_btdh_mapping *btdh) -{ - struct _sas_device *sas_device; - unsigned long flags; - int rc = 0; - - if (list_empty(&ioc->sas_device_list)) - return rc; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && - btdh->handle == sas_device->handle) { - btdh->bus = sas_device->channel; - btdh->id = sas_device->id; - rc = 1; - goto out; - } else if (btdh->bus == sas_device->channel && btdh->id == - sas_device->id && btdh->handle == 0xFFFF) { - btdh->handle = sas_device->handle; - rc = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return rc; -} - -/** - * _ctl_btdh_search_raid_device - searching for raid device - * @ioc: per adapter object - * @btdh: btdh ioctl payload - */ -static int -_ctl_btdh_search_raid_device(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_ioctl_btdh_mapping *btdh) -{ - struct _raid_device *raid_device; - unsigned long flags; - int rc = 0; - - if (list_empty(&ioc->raid_device_list)) - return rc; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (btdh->bus == 0xFFFFFFFF && btdh->id == 0xFFFFFFFF && - btdh->handle == raid_device->handle) { - btdh->bus = raid_device->channel; - btdh->id = raid_device->id; - rc = 1; - goto out; - } else if (btdh->bus == raid_device->channel && btdh->id == - raid_device->id && btdh->handle == 0xFFFF) { - btdh->handle = raid_device->handle; - rc = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - return rc; -} - -/** - * _ctl_btdh_mapping - main handler for MPT2BTDHMAPPING opcode - * @arg - user space buffer containing ioctl content - */ -static long -_ctl_btdh_mapping(void __user *arg) -{ - struct mpt2_ioctl_btdh_mapping karg; - struct MPT2SAS_ADAPTER *ioc; - int rc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - rc = _ctl_btdh_search_sas_device(ioc, &karg); - if (!rc) - _ctl_btdh_search_raid_device(ioc, &karg); - - if (copy_to_user(arg, &karg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - return 0; -} - -/** - * _ctl_diag_capability - return diag buffer capability - * @ioc: per adapter object - * @buffer_type: specifies either TRACE, SNAPSHOT, or EXTENDED - * - * returns 1 when diag buffer support is enabled in firmware - */ -static u8 -_ctl_diag_capability(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type) -{ - u8 rc = 0; - - switch (buffer_type) { - case MPI2_DIAG_BUF_TYPE_TRACE: - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER) - rc = 1; - break; - case MPI2_DIAG_BUF_TYPE_SNAPSHOT: - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER) - rc = 1; - break; - case MPI2_DIAG_BUF_TYPE_EXTENDED: - if (ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_EXTENDED_BUFFER) - rc = 1; - } - - return rc; -} - -/** - * _ctl_diag_register_2 - wrapper for registering diag buffer support - * @ioc: per adapter object - * @diag_register: the diag_register struct passed in from user space - * - */ -static long -_ctl_diag_register_2(struct MPT2SAS_ADAPTER *ioc, - struct mpt2_diag_register *diag_register) -{ - int rc, i; - void *request_data = NULL; - dma_addr_t request_data_dma; - u32 request_data_sz = 0; - Mpi2DiagBufferPostRequest_t *mpi_request; - Mpi2DiagBufferPostReply_t *mpi_reply; - u8 buffer_type; - unsigned long timeleft; - u16 smid; - u16 ioc_status; - u8 issue_reset = 0; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - buffer_type = diag_register->buffer_type; - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if (ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_REGISTERED) { - printk(MPT2SAS_ERR_FMT "%s: already has a registered " - "buffer for buffer_type(0x%02x)\n", ioc->name, __func__, - buffer_type); - return -EINVAL; - } - - if (diag_register->requested_buffer_size % 4) { - printk(MPT2SAS_ERR_FMT "%s: the requested_buffer_size " - "is not 4 byte aligned\n", ioc->name, __func__); - return -EINVAL; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->ctl_cmds.smid = smid; - - request_data = ioc->diag_buffer[buffer_type]; - request_data_sz = diag_register->requested_buffer_size; - ioc->unique_id[buffer_type] = diag_register->unique_id; - ioc->diag_buffer_status[buffer_type] = 0; - memcpy(ioc->product_specific[buffer_type], - diag_register->product_specific, MPT2_PRODUCT_SPECIFIC_DWORDS); - ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags; - - if (request_data) { - request_data_dma = ioc->diag_buffer_dma[buffer_type]; - if (request_data_sz != ioc->diag_buffer_sz[buffer_type]) { - pci_free_consistent(ioc->pdev, - ioc->diag_buffer_sz[buffer_type], - request_data, request_data_dma); - request_data = NULL; - } - } - - if (request_data == NULL) { - ioc->diag_buffer_sz[buffer_type] = 0; - ioc->diag_buffer_dma[buffer_type] = 0; - request_data = pci_alloc_consistent( - ioc->pdev, request_data_sz, &request_data_dma); - if (request_data == NULL) { - printk(MPT2SAS_ERR_FMT "%s: failed allocating memory" - " for diag buffers, requested size(%d)\n", - ioc->name, __func__, request_data_sz); - mpt2sas_base_free_smid(ioc, smid); - return -ENOMEM; - } - ioc->diag_buffer[buffer_type] = request_data; - ioc->diag_buffer_sz[buffer_type] = request_data_sz; - ioc->diag_buffer_dma[buffer_type] = request_data_dma; - } - - mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; - mpi_request->BufferType = diag_register->buffer_type; - mpi_request->Flags = cpu_to_le32(diag_register->diagnostic_flags); - mpi_request->BufferAddress = cpu_to_le64(request_data_dma); - mpi_request->BufferLength = cpu_to_le32(request_data_sz); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(0x%p), " - "dma(0x%llx), sz(%d)\n", ioc->name, __func__, request_data, - (unsigned long long)request_data_dma, - le32_to_cpu(mpi_request->BufferLength))); - - for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) - mpi_request->ProductSpecific[i] = - cpu_to_le32(ioc->product_specific[buffer_type][i]); - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, - MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); - - if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, - __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2DiagBufferPostRequest_t)/4); - if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - /* process the completed Reply Message Frame */ - if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { - printk(MPT2SAS_ERR_FMT "%s: no reply message\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - - mpi_reply = ioc->ctl_cmds.reply; - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_REGISTERED; - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - out: - - if (rc && request_data) - pci_free_consistent(ioc->pdev, request_data_sz, - request_data, request_data_dma); - - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - return rc; -} - -/** - * mpt2sas_enable_diag_buffer - enabling diag_buffers support driver load time - * @ioc: per adapter object - * @bits_to_register: bitwise field where trace is bit 0, and snapshot is bit 1 - * - * This is called when command line option diag_buffer_enable is enabled - * at driver load time. - */ -void -mpt2sas_enable_diag_buffer(struct MPT2SAS_ADAPTER *ioc, u8 bits_to_register) -{ - struct mpt2_diag_register diag_register; - - memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); - - if (bits_to_register & 1) { - printk(MPT2SAS_INFO_FMT "registering trace buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - /* register for 1MB buffers */ - diag_register.requested_buffer_size = (1024 * 1024); - diag_register.unique_id = 0x7075900; - _ctl_diag_register_2(ioc, &diag_register); - } - - if (bits_to_register & 2) { - printk(MPT2SAS_INFO_FMT "registering snapshot buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_SNAPSHOT; - /* register for 2MB buffers */ - diag_register.requested_buffer_size = 2 * (1024 * 1024); - diag_register.unique_id = 0x7075901; - _ctl_diag_register_2(ioc, &diag_register); - } - - if (bits_to_register & 4) { - printk(MPT2SAS_INFO_FMT "registering extended buffer support\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_EXTENDED; - /* register for 2MB buffers */ - diag_register.requested_buffer_size = 2 * (1024 * 1024); - diag_register.unique_id = 0x7075901; - _ctl_diag_register_2(ioc, &diag_register); - } -} - -/** - * _ctl_diag_register - application register with driver - * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING - * - * This will allow the driver to setup any required buffers that will be - * needed by firmware to communicate with the driver. - */ -static long -_ctl_diag_register(void __user *arg, enum block_state state) -{ - struct mpt2_diag_register karg; - struct MPT2SAS_ADAPTER *ioc; - long rc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; - rc = _ctl_diag_register_2(ioc, &karg); - mutex_unlock(&ioc->ctl_cmds.mutex); - return rc; -} - -/** - * _ctl_diag_unregister - application unregister with driver - * @arg - user space buffer containing ioctl content - * - * This will allow the driver to cleanup any memory allocated for diag - * messages and to free up any resources. - */ -static long -_ctl_diag_unregister(void __user *arg) -{ - struct mpt2_diag_unregister karg; - struct MPT2SAS_ADAPTER *ioc; - void *request_data; - dma_addr_t request_data_dma; - u32 request_data_sz; - u8 buffer_type; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - buffer_type = karg.unique_id & 0x000000ff; - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " - "registered\n", ioc->name, __func__, buffer_type); - return -EINVAL; - } - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) has not been " - "released\n", ioc->name, __func__, buffer_type); - return -EINVAL; - } - - if (karg.unique_id != ioc->unique_id[buffer_type]) { - printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " - "registered\n", ioc->name, __func__, karg.unique_id); - return -EINVAL; - } - - request_data = ioc->diag_buffer[buffer_type]; - if (!request_data) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -ENOMEM; - } - - request_data_sz = ioc->diag_buffer_sz[buffer_type]; - request_data_dma = ioc->diag_buffer_dma[buffer_type]; - pci_free_consistent(ioc->pdev, request_data_sz, - request_data, request_data_dma); - ioc->diag_buffer[buffer_type] = NULL; - ioc->diag_buffer_status[buffer_type] = 0; - return 0; -} - -/** - * _ctl_diag_query - query relevant info associated with diag buffers - * @arg - user space buffer containing ioctl content - * - * The application will send only buffer_type and unique_id. Driver will - * inspect unique_id first, if valid, fill in all the info. If unique_id is - * 0x00, the driver will return info specified by Buffer Type. - */ -static long -_ctl_diag_query(void __user *arg) -{ - struct mpt2_diag_query karg; - struct MPT2SAS_ADAPTER *ioc; - void *request_data; - int i; - u8 buffer_type; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - karg.application_flags = 0; - buffer_type = karg.buffer_type; - - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " - "registered\n", ioc->name, __func__, buffer_type); - return -EINVAL; - } - - if (karg.unique_id & 0xffffff00) { - if (karg.unique_id != ioc->unique_id[buffer_type]) { - printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " - "registered\n", ioc->name, __func__, - karg.unique_id); - return -EINVAL; - } - } - - request_data = ioc->diag_buffer[buffer_type]; - if (!request_data) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -ENOMEM; - } - - if (ioc->diag_buffer_status[buffer_type] & MPT2_DIAG_BUFFER_IS_RELEASED) - karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED | - MPT2_APP_FLAGS_BUFFER_VALID); - else - karg.application_flags = (MPT2_APP_FLAGS_APP_OWNED | - MPT2_APP_FLAGS_BUFFER_VALID | - MPT2_APP_FLAGS_FW_BUFFER_ACCESS); - - for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) - karg.product_specific[i] = - ioc->product_specific[buffer_type][i]; - - karg.total_buffer_size = ioc->diag_buffer_sz[buffer_type]; - karg.driver_added_buffer_size = 0; - karg.unique_id = ioc->unique_id[buffer_type]; - karg.diagnostic_flags = ioc->diagnostic_flags[buffer_type]; - - if (copy_to_user(arg, &karg, sizeof(struct mpt2_diag_query))) { - printk(MPT2SAS_ERR_FMT "%s: unable to write mpt2_diag_query " - "data @ %p\n", ioc->name, __func__, arg); - return -EFAULT; - } - return 0; -} - -/** - * _ctl_send_release - Diag Release Message - * @ioc: per adapter object - * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED - * @issue_reset - specifies whether host reset is required. - * - */ -static int -_ctl_send_release(struct MPT2SAS_ADAPTER *ioc, u8 buffer_type, u8 *issue_reset) -{ - Mpi2DiagReleaseRequest_t *mpi_request; - Mpi2DiagReleaseReply_t *mpi_reply; - u16 smid; - u16 ioc_status; - u32 ioc_state; - int rc; - unsigned long timeleft; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - rc = 0; - *issue_reset = 0; - - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "skipping due to FAULT state\n", ioc->name, - __func__)); - rc = -EAGAIN; - goto out; - } - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->ctl_cmds.smid = smid; - - mpi_request->Function = MPI2_FUNCTION_DIAG_RELEASE; - mpi_request->BufferType = buffer_type; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, - MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); - - if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, - __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2DiagReleaseRequest_t)/4); - if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) - *issue_reset = 1; - rc = -EFAULT; - goto out; - } - - /* process the completed Reply Message Frame */ - if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { - printk(MPT2SAS_ERR_FMT "%s: no reply message\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - - mpi_reply = ioc->ctl_cmds.reply; - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_RELEASED; - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - out: - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - return rc; -} - -/** - * _ctl_diag_release - request to send Diag Release Message to firmware - * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING - * - * This allows ownership of the specified buffer to returned to the driver, - * allowing an application to read the buffer without fear that firmware is - * overwritting information in the buffer. - */ -static long -_ctl_diag_release(void __user *arg, enum block_state state) -{ - struct mpt2_diag_release karg; - struct MPT2SAS_ADAPTER *ioc; - void *request_data; - int rc; - u8 buffer_type; - u8 issue_reset = 0; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - buffer_type = karg.unique_id & 0x000000ff; - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) is not " - "registered\n", ioc->name, __func__, buffer_type); - return -EINVAL; - } - - if (karg.unique_id != ioc->unique_id[buffer_type]) { - printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " - "registered\n", ioc->name, __func__, karg.unique_id); - return -EINVAL; - } - - if (ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_RELEASED) { - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " - "is already released\n", ioc->name, __func__, - buffer_type); - return 0; - } - - request_data = ioc->diag_buffer[buffer_type]; - - if (!request_data) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have memory allocated for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -ENOMEM; - } - - /* buffers were released by due to host reset */ - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_DIAG_RESET)) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_RELEASED; - ioc->diag_buffer_status[buffer_type] &= - ~MPT2_DIAG_BUFFER_IS_DIAG_RESET; - printk(MPT2SAS_ERR_FMT "%s: buffer_type(0x%02x) " - "was released due to host reset\n", ioc->name, __func__, - buffer_type); - return 0; - } - - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; - - rc = _ctl_send_release(ioc, buffer_type, &issue_reset); - - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - mutex_unlock(&ioc->ctl_cmds.mutex); - return rc; -} - -/** - * _ctl_diag_read_buffer - request for copy of the diag buffer - * @arg - user space buffer containing ioctl content - * @state - NON_BLOCKING or BLOCKING - */ -static long -_ctl_diag_read_buffer(void __user *arg, enum block_state state) -{ - struct mpt2_diag_read_buffer karg; - struct mpt2_diag_read_buffer __user *uarg = arg; - struct MPT2SAS_ADAPTER *ioc; - void *request_data, *diag_data; - Mpi2DiagBufferPostRequest_t *mpi_request; - Mpi2DiagBufferPostReply_t *mpi_reply; - int rc, i; - u8 buffer_type; - unsigned long timeleft, request_size, copy_size; - u16 smid; - u16 ioc_status; - u8 issue_reset = 0; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, - __func__)); - - buffer_type = karg.unique_id & 0x000000ff; - if (!_ctl_diag_capability(ioc, buffer_type)) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have capability for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -EPERM; - } - - if (karg.unique_id != ioc->unique_id[buffer_type]) { - printk(MPT2SAS_ERR_FMT "%s: unique_id(0x%08x) is not " - "registered\n", ioc->name, __func__, karg.unique_id); - return -EINVAL; - } - - request_data = ioc->diag_buffer[buffer_type]; - if (!request_data) { - printk(MPT2SAS_ERR_FMT "%s: doesn't have buffer for " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type); - return -ENOMEM; - } - - request_size = ioc->diag_buffer_sz[buffer_type]; - - if ((karg.starting_offset % 4) || (karg.bytes_to_read % 4)) { - printk(MPT2SAS_ERR_FMT "%s: either the starting_offset " - "or bytes_to_read are not 4 byte aligned\n", ioc->name, - __func__); - return -EINVAL; - } - - if (karg.starting_offset > request_size) - return -EINVAL; - - diag_data = (void *)(request_data + karg.starting_offset); - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: diag_buffer(%p), " - "offset(%d), sz(%d)\n", ioc->name, __func__, - diag_data, karg.starting_offset, karg.bytes_to_read)); - - /* Truncate data on requests that are too large */ - if ((diag_data + karg.bytes_to_read < diag_data) || - (diag_data + karg.bytes_to_read > request_data + request_size)) - copy_size = request_size - karg.starting_offset; - else - copy_size = karg.bytes_to_read; - - if (copy_to_user((void __user *)uarg->diagnostic_data, - diag_data, copy_size)) { - printk(MPT2SAS_ERR_FMT "%s: Unable to write " - "mpt_diag_read_buffer_t data @ %p\n", ioc->name, - __func__, diag_data); - return -EFAULT; - } - - if ((karg.flags & MPT2_FLAGS_REREGISTER) == 0) - return 0; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: Reregister " - "buffer_type(0x%02x)\n", ioc->name, __func__, buffer_type)); - if ((ioc->diag_buffer_status[buffer_type] & - MPT2_DIAG_BUFFER_IS_RELEASED) == 0) { - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "buffer_type(0x%02x) is still registered\n", ioc->name, - __func__, buffer_type)); - return 0; - } - /* Get a free request frame and save the message context. - */ - if (state == NON_BLOCKING && !mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; - else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) - return -ERESTARTSYS; - - if (ioc->ctl_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: ctl_cmd in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - smid = mpt2sas_base_get_smid(ioc, ioc->ctl_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - ioc->ctl_cmds.status = MPT2_CMD_PENDING; - memset(ioc->ctl_cmds.reply, 0, ioc->reply_sz); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->ctl_cmds.smid = smid; - - mpi_request->Function = MPI2_FUNCTION_DIAG_BUFFER_POST; - mpi_request->BufferType = buffer_type; - mpi_request->BufferLength = - cpu_to_le32(ioc->diag_buffer_sz[buffer_type]); - mpi_request->BufferAddress = - cpu_to_le64(ioc->diag_buffer_dma[buffer_type]); - for (i = 0; i < MPT2_PRODUCT_SPECIFIC_DWORDS; i++) - mpi_request->ProductSpecific[i] = - cpu_to_le32(ioc->product_specific[buffer_type][i]); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - - init_completion(&ioc->ctl_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->ctl_cmds.done, - MPT2_IOCTL_DEFAULT_TIMEOUT*HZ); - - if (!(ioc->ctl_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", ioc->name, - __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2DiagBufferPostRequest_t)/4); - if (!(ioc->ctl_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - /* process the completed Reply Message Frame */ - if ((ioc->ctl_cmds.status & MPT2_CMD_REPLY_VALID) == 0) { - printk(MPT2SAS_ERR_FMT "%s: no reply message\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - - mpi_reply = ioc->ctl_cmds.reply; - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & MPI2_IOCSTATUS_MASK; - - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - ioc->diag_buffer_status[buffer_type] |= - MPT2_DIAG_BUFFER_IS_REGISTERED; - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: success\n", - ioc->name, __func__)); - } else { - printk(MPT2SAS_INFO_FMT "%s: ioc_status(0x%04x) " - "log_info(0x%08x)\n", ioc->name, __func__, - ioc_status, le32_to_cpu(mpi_reply->IOCLogInfo)); - rc = -EFAULT; - } - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - out: - - ioc->ctl_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->ctl_cmds.mutex); - return rc; -} - -/** - * _ctl_ioctl_main - main ioctl entry point - * @file - (struct file) - * @cmd - ioctl opcode - * @arg - - */ -static long -_ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg) -{ - enum block_state state; - long ret = -EINVAL; - - state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : - BLOCKING; - - switch (cmd) { - case MPT2IOCINFO: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_iocinfo)) - ret = _ctl_getiocinfo(arg); - break; - case MPT2COMMAND: - { - struct mpt2_ioctl_command karg; - struct mpt2_ioctl_command __user *uarg; - struct MPT2SAS_ADAPTER *ioc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || - !ioc) - return -ENODEV; - - if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; - - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_command)) { - uarg = arg; - ret = _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); - } - break; - } - case MPT2EVENTQUERY: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventquery)) - ret = _ctl_eventquery(arg); - break; - case MPT2EVENTENABLE: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_eventenable)) - ret = _ctl_eventenable(arg); - break; - case MPT2EVENTREPORT: - ret = _ctl_eventreport(arg); - break; - case MPT2HARDRESET: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_diag_reset)) - ret = _ctl_do_reset(arg); - break; - case MPT2BTDHMAPPING: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_ioctl_btdh_mapping)) - ret = _ctl_btdh_mapping(arg); - break; - case MPT2DIAGREGISTER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_register)) - ret = _ctl_diag_register(arg, state); - break; - case MPT2DIAGUNREGISTER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_unregister)) - ret = _ctl_diag_unregister(arg); - break; - case MPT2DIAGQUERY: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_query)) - ret = _ctl_diag_query(arg); - break; - case MPT2DIAGRELEASE: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_release)) - ret = _ctl_diag_release(arg, state); - break; - case MPT2DIAGREADBUFFER: - if (_IOC_SIZE(cmd) == sizeof(struct mpt2_diag_read_buffer)) - ret = _ctl_diag_read_buffer(arg, state); - break; - default: - { - struct mpt2_ioctl_command karg; - struct MPT2SAS_ADAPTER *ioc; - - if (copy_from_user(&karg, arg, sizeof(karg))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - - if (_ctl_verify_adapter(karg.hdr.ioc_number, &ioc) == -1 || - !ioc) - return -ENODEV; - - dctlprintk(ioc, printk(MPT2SAS_INFO_FMT - "unsupported ioctl opcode(0x%08x)\n", ioc->name, cmd)); - break; - } - } - return ret; -} - -/** - * _ctl_ioctl - main ioctl entry point (unlocked) - * @file - (struct file) - * @cmd - ioctl opcode - * @arg - - */ -static long -_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long ret; - - mutex_lock(&_ctl_mutex); - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); - mutex_unlock(&_ctl_mutex); - return ret; -} - -#ifdef CONFIG_COMPAT -/** - * _ctl_compat_mpt_command - convert 32bit pointers to 64bit. - * @file - (struct file) - * @cmd - ioctl opcode - * @arg - (struct mpt2_ioctl_command32) - * - * MPT2COMMAND32 - Handle 32bit applications running on 64bit os. - */ -static long -_ctl_compat_mpt_command(struct file *file, unsigned cmd, unsigned long arg) -{ - struct mpt2_ioctl_command32 karg32; - struct mpt2_ioctl_command32 __user *uarg; - struct mpt2_ioctl_command karg; - struct MPT2SAS_ADAPTER *ioc; - enum block_state state; - - if (_IOC_SIZE(cmd) != sizeof(struct mpt2_ioctl_command32)) - return -EINVAL; - - uarg = (struct mpt2_ioctl_command32 __user *) arg; - - if (copy_from_user(&karg32, (char __user *)arg, sizeof(karg32))) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", - __FILE__, __LINE__, __func__); - return -EFAULT; - } - if (_ctl_verify_adapter(karg32.hdr.ioc_number, &ioc) == -1 || !ioc) - return -ENODEV; - - if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; - - memset(&karg, 0, sizeof(struct mpt2_ioctl_command)); - karg.hdr.ioc_number = karg32.hdr.ioc_number; - karg.hdr.port_number = karg32.hdr.port_number; - karg.hdr.max_data_size = karg32.hdr.max_data_size; - karg.timeout = karg32.timeout; - karg.max_reply_bytes = karg32.max_reply_bytes; - karg.data_in_size = karg32.data_in_size; - karg.data_out_size = karg32.data_out_size; - karg.max_sense_bytes = karg32.max_sense_bytes; - karg.data_sge_offset = karg32.data_sge_offset; - karg.reply_frame_buf_ptr = compat_ptr(karg32.reply_frame_buf_ptr); - karg.data_in_buf_ptr = compat_ptr(karg32.data_in_buf_ptr); - karg.data_out_buf_ptr = compat_ptr(karg32.data_out_buf_ptr); - karg.sense_data_ptr = compat_ptr(karg32.sense_data_ptr); - state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; - return _ctl_do_mpt_command(ioc, karg, &uarg->mf, state); -} - -/** - * _ctl_ioctl_compat - main ioctl entry point (compat) - * @file - - * @cmd - - * @arg - - * - * This routine handles 32 bit applications in 64bit os. - */ -static long -_ctl_ioctl_compat(struct file *file, unsigned cmd, unsigned long arg) -{ - long ret; - - mutex_lock(&_ctl_mutex); - if (cmd == MPT2COMMAND32) - ret = _ctl_compat_mpt_command(file, cmd, arg); - else - ret = _ctl_ioctl_main(file, cmd, (void __user *)arg); - mutex_unlock(&_ctl_mutex); - return ret; -} -#endif - -/* scsi host attributes */ - -/** - * _ctl_version_fw_show - firmware version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_fw_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", - (ioc->facts.FWVersion.Word & 0xFF000000) >> 24, - (ioc->facts.FWVersion.Word & 0x00FF0000) >> 16, - (ioc->facts.FWVersion.Word & 0x0000FF00) >> 8, - ioc->facts.FWVersion.Word & 0x000000FF); -} -static DEVICE_ATTR(version_fw, S_IRUGO, _ctl_version_fw_show, NULL); - -/** - * _ctl_version_bios_show - bios version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_bios_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - u32 version = le32_to_cpu(ioc->bios_pg3.BiosVersion); - - return snprintf(buf, PAGE_SIZE, "%02d.%02d.%02d.%02d\n", - (version & 0xFF000000) >> 24, - (version & 0x00FF0000) >> 16, - (version & 0x0000FF00) >> 8, - version & 0x000000FF); -} -static DEVICE_ATTR(version_bios, S_IRUGO, _ctl_version_bios_show, NULL); - -/** - * _ctl_version_mpi_show - MPI (message passing interface) version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_mpi_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%03x.%02x\n", - ioc->facts.MsgVersion, ioc->facts.HeaderVersion >> 8); -} -static DEVICE_ATTR(version_mpi, S_IRUGO, _ctl_version_mpi_show, NULL); - -/** - * _ctl_version_product_show - product name - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_product_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, 16, "%s\n", ioc->manu_pg0.ChipName); -} -static DEVICE_ATTR(version_product, S_IRUGO, - _ctl_version_product_show, NULL); - -/** - * _ctl_version_nvdata_persistent_show - ndvata persistent version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_nvdata_persistent_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08xh\n", - le32_to_cpu(ioc->iounit_pg0.NvdataVersionPersistent.Word)); -} -static DEVICE_ATTR(version_nvdata_persistent, S_IRUGO, - _ctl_version_nvdata_persistent_show, NULL); - -/** - * _ctl_version_nvdata_default_show - nvdata default version - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_version_nvdata_default_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08xh\n", - le32_to_cpu(ioc->iounit_pg0.NvdataVersionDefault.Word)); -} -static DEVICE_ATTR(version_nvdata_default, S_IRUGO, - _ctl_version_nvdata_default_show, NULL); - -/** - * _ctl_board_name_show - board name - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_board_name_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardName); -} -static DEVICE_ATTR(board_name, S_IRUGO, _ctl_board_name_show, NULL); - -/** - * _ctl_board_assembly_show - board assembly name - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_board_assembly_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardAssembly); -} -static DEVICE_ATTR(board_assembly, S_IRUGO, - _ctl_board_assembly_show, NULL); - -/** - * _ctl_board_tracer_show - board tracer number - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_board_tracer_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, 16, "%s\n", ioc->manu_pg0.BoardTracerNumber); -} -static DEVICE_ATTR(board_tracer, S_IRUGO, - _ctl_board_tracer_show, NULL); - -/** - * _ctl_io_delay_show - io missing delay - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is for firmware implemention for deboucing device - * removal events. - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_io_delay_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->io_missing_delay); -} -static DEVICE_ATTR(io_delay, S_IRUGO, - _ctl_io_delay_show, NULL); - -/** - * _ctl_device_delay_show - device missing delay - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is for firmware implemention for deboucing device - * removal events. - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_device_delay_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->device_missing_delay); -} -static DEVICE_ATTR(device_delay, S_IRUGO, - _ctl_device_delay_show, NULL); - -/** - * _ctl_fw_queue_depth_show - global credits - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is firmware queue depth limit - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_fw_queue_depth_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%02d\n", ioc->facts.RequestCredit); -} -static DEVICE_ATTR(fw_queue_depth, S_IRUGO, - _ctl_fw_queue_depth_show, NULL); - -/** - * _ctl_sas_address_show - sas address - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is the controller sas address - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_host_sas_address_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "0x%016llx\n", - (unsigned long long)ioc->sas_hba.sas_address); -} -static DEVICE_ATTR(host_sas_address, S_IRUGO, - _ctl_host_sas_address_show, NULL); - -/** - * _ctl_logging_level_show - logging level - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read/write' shost attribute. - */ -static ssize_t -_ctl_logging_level_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08xh\n", ioc->logging_level); -} -static ssize_t -_ctl_logging_level_store(struct device *cdev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int val = 0; - - if (sscanf(buf, "%x", &val) != 1) - return -EINVAL; - - ioc->logging_level = val; - printk(MPT2SAS_INFO_FMT "logging_level=%08xh\n", ioc->name, - ioc->logging_level); - return strlen(buf); -} -static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, - _ctl_logging_level_show, _ctl_logging_level_store); - -/* device attributes */ -/* - * _ctl_fwfault_debug_show - show/store fwfault_debug - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * mpt2sas_fwfault_debug is command line option - * A sysfs 'read/write' shost attribute. - */ -static ssize_t -_ctl_fwfault_debug_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%d\n", ioc->fwfault_debug); -} -static ssize_t -_ctl_fwfault_debug_store(struct device *cdev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int val = 0; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - ioc->fwfault_debug = val; - printk(MPT2SAS_INFO_FMT "fwfault_debug=%d\n", ioc->name, - ioc->fwfault_debug); - return strlen(buf); -} -static DEVICE_ATTR(fwfault_debug, S_IRUGO | S_IWUSR, - _ctl_fwfault_debug_show, _ctl_fwfault_debug_store); - - -/** - * _ctl_ioc_reset_count_show - ioc reset count - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is firmware queue depth limit - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_ioc_reset_count_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - return snprintf(buf, PAGE_SIZE, "%08d\n", ioc->ioc_reset_count); -} -static DEVICE_ATTR(ioc_reset_count, S_IRUGO, - _ctl_ioc_reset_count_show, NULL); - -/** - * _ctl_ioc_reply_queue_count_show - number of reply queues - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is number of reply queues - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_ioc_reply_queue_count_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - u8 reply_queue_count; - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if ((ioc->facts.IOCCapabilities & - MPI2_IOCFACTS_CAPABILITY_MSI_X_INDEX) && ioc->msix_enable) - reply_queue_count = ioc->reply_queue_count; - else - reply_queue_count = 1; - return snprintf(buf, PAGE_SIZE, "%d\n", reply_queue_count); -} -static DEVICE_ATTR(reply_queue_count, S_IRUGO, - _ctl_ioc_reply_queue_count_show, NULL); - -struct DIAG_BUFFER_START { - __le32 Size; - __le32 DiagVersion; - u8 BufferType; - u8 Reserved[3]; - __le32 Reserved1; - __le32 Reserved2; - __le32 Reserved3; -}; -/** - * _ctl_host_trace_buffer_size_show - host buffer size (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_host_trace_buffer_size_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - u32 size = 0; - struct DIAG_BUFFER_START *request_data; - - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - request_data = (struct DIAG_BUFFER_START *) - ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]; - if ((le32_to_cpu(request_data->DiagVersion) == 0x00000000 || - le32_to_cpu(request_data->DiagVersion) == 0x01000000) && - le32_to_cpu(request_data->Reserved3) == 0x4742444c) - size = le32_to_cpu(request_data->Size); - - ioc->ring_buffer_sz = size; - return snprintf(buf, PAGE_SIZE, "%d\n", size); -} -static DEVICE_ATTR(host_trace_buffer_size, S_IRUGO, - _ctl_host_trace_buffer_size_show, NULL); - -/** - * _ctl_host_trace_buffer_show - firmware ring buffer (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read/write' shost attribute. - * - * You will only be able to read 4k bytes of ring buffer at a time. - * In order to read beyond 4k bytes, you will have to write out the - * offset to the same attribute, it will move the pointer. - */ -static ssize_t -_ctl_host_trace_buffer_show(struct device *cdev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - void *request_data; - u32 size; - - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) { - printk(MPT2SAS_ERR_FMT "%s: host_trace_buffer is not " - "registered\n", ioc->name, __func__); - return 0; - } - - if (ioc->ring_buffer_offset > ioc->ring_buffer_sz) - return 0; - - size = ioc->ring_buffer_sz - ioc->ring_buffer_offset; - size = (size > PAGE_SIZE) ? PAGE_SIZE : size; - request_data = ioc->diag_buffer[0] + ioc->ring_buffer_offset; - memcpy(buf, request_data, size); - return size; -} - -static ssize_t -_ctl_host_trace_buffer_store(struct device *cdev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int val = 0; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - ioc->ring_buffer_offset = val; - return strlen(buf); -} -static DEVICE_ATTR(host_trace_buffer, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_show, _ctl_host_trace_buffer_store); - -/*****************************************/ - -/** - * _ctl_host_trace_buffer_enable_show - firmware ring buffer (trace only) - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * A sysfs 'read/write' shost attribute. - * - * This is a mechnism to post/release host_trace_buffers - */ -static ssize_t -_ctl_host_trace_buffer_enable_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if ((!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) || - ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0)) - return snprintf(buf, PAGE_SIZE, "off\n"); - else if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - return snprintf(buf, PAGE_SIZE, "release\n"); - else - return snprintf(buf, PAGE_SIZE, "post\n"); -} - -static ssize_t -_ctl_host_trace_buffer_enable_store(struct device *cdev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - char str[10] = ""; - struct mpt2_diag_register diag_register; - u8 issue_reset = 0; - - if (sscanf(buf, "%s", str) != 1) - return -EINVAL; - - if (!strcmp(str, "post")) { - /* exit out if host buffers are already posted */ - if ((ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) && - (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) && - ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED) == 0)) - goto out; - memset(&diag_register, 0, sizeof(struct mpt2_diag_register)); - printk(MPT2SAS_INFO_FMT "posting host trace buffers\n", - ioc->name); - diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - diag_register.requested_buffer_size = (1024 * 1024); - diag_register.unique_id = 0x7075900; - ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; - _ctl_diag_register_2(ioc, &diag_register); - } else if (!strcmp(str, "release")) { - /* exit out if host buffers are already released */ - if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) - goto out; - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_REGISTERED) == 0) - goto out; - if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & - MPT2_DIAG_BUFFER_IS_RELEASED)) - goto out; - printk(MPT2SAS_INFO_FMT "releasing host trace buffer\n", - ioc->name); - _ctl_send_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); - } - - out: - return strlen(buf); -} -static DEVICE_ATTR(host_trace_buffer_enable, S_IRUGO | S_IWUSR, - _ctl_host_trace_buffer_enable_show, _ctl_host_trace_buffer_enable_store); - -struct device_attribute *mpt2sas_host_attrs[] = { - &dev_attr_version_fw, - &dev_attr_version_bios, - &dev_attr_version_mpi, - &dev_attr_version_product, - &dev_attr_version_nvdata_persistent, - &dev_attr_version_nvdata_default, - &dev_attr_board_name, - &dev_attr_board_assembly, - &dev_attr_board_tracer, - &dev_attr_io_delay, - &dev_attr_device_delay, - &dev_attr_logging_level, - &dev_attr_fwfault_debug, - &dev_attr_fw_queue_depth, - &dev_attr_host_sas_address, - &dev_attr_ioc_reset_count, - &dev_attr_host_trace_buffer_size, - &dev_attr_host_trace_buffer, - &dev_attr_host_trace_buffer_enable, - &dev_attr_reply_queue_count, - NULL, -}; - -/** - * _ctl_device_sas_address_show - sas address - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is the sas address for the target - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_device_sas_address_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata; - - return snprintf(buf, PAGE_SIZE, "0x%016llx\n", - (unsigned long long)sas_device_priv_data->sas_target->sas_address); -} -static DEVICE_ATTR(sas_address, S_IRUGO, _ctl_device_sas_address_show, NULL); - -/** - * _ctl_device_handle_show - device handle - * @cdev - pointer to embedded class device - * @buf - the buffer returned - * - * This is the firmware assigned device handle - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t -_ctl_device_handle_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_DEVICE *sas_device_priv_data = sdev->hostdata; - - return snprintf(buf, PAGE_SIZE, "0x%04x\n", - sas_device_priv_data->sas_target->handle); -} -static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); - -struct device_attribute *mpt2sas_dev_attrs[] = { - &dev_attr_sas_address, - &dev_attr_sas_device_handle, - NULL, -}; - -static const struct file_operations ctl_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = _ctl_ioctl, - .release = _ctl_release, - .poll = _ctl_poll, - .fasync = _ctl_fasync, -#ifdef CONFIG_COMPAT - .compat_ioctl = _ctl_ioctl_compat, -#endif - .llseek = noop_llseek, -}; - -static struct miscdevice ctl_dev = { - .minor = MPT2SAS_MINOR, - .name = MPT2SAS_DEV_NAME, - .fops = &ctl_fops, -}; - -/** - * mpt2sas_ctl_init - main entry point for ctl. - * - */ -void -mpt2sas_ctl_init(void) -{ - async_queue = NULL; - if (misc_register(&ctl_dev) < 0) - printk(KERN_ERR "%s can't register misc device [minor=%d]\n", - MPT2SAS_DRIVER_NAME, MPT2SAS_MINOR); - - init_waitqueue_head(&ctl_poll_wait); -} - -/** - * mpt2sas_ctl_exit - exit point for ctl - * - */ -void -mpt2sas_ctl_exit(void) -{ - struct MPT2SAS_ADAPTER *ioc; - int i; - - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - - /* free memory associated to diag buffers */ - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!ioc->diag_buffer[i]) - continue; - pci_free_consistent(ioc->pdev, ioc->diag_buffer_sz[i], - ioc->diag_buffer[i], ioc->diag_buffer_dma[i]); - ioc->diag_buffer[i] = NULL; - ioc->diag_buffer_status[i] = 0; - } - - kfree(ioc->event_log); - } - misc_deregister(&ctl_dev); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.h deleted file mode 100644 index 11ff1d5f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_ctl.h +++ /dev/null @@ -1,418 +0,0 @@ -/* - * Management Module Support for MPT (Message Passing Technology) based - * controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h - * Copyright (C) 2007-2010 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef MPT2SAS_CTL_H_INCLUDED -#define MPT2SAS_CTL_H_INCLUDED - -#ifdef __KERNEL__ -#include -#endif - -#define MPT2SAS_DEV_NAME "mpt2ctl" -#define MPT2_MAGIC_NUMBER 'L' -#define MPT2_IOCTL_DEFAULT_TIMEOUT (10) /* in seconds */ - -/** - * IOCTL opcodes - */ -#define MPT2IOCINFO _IOWR(MPT2_MAGIC_NUMBER, 17, \ - struct mpt2_ioctl_iocinfo) -#define MPT2COMMAND _IOWR(MPT2_MAGIC_NUMBER, 20, \ - struct mpt2_ioctl_command) -#ifdef CONFIG_COMPAT -#define MPT2COMMAND32 _IOWR(MPT2_MAGIC_NUMBER, 20, \ - struct mpt2_ioctl_command32) -#endif -#define MPT2EVENTQUERY _IOWR(MPT2_MAGIC_NUMBER, 21, \ - struct mpt2_ioctl_eventquery) -#define MPT2EVENTENABLE _IOWR(MPT2_MAGIC_NUMBER, 22, \ - struct mpt2_ioctl_eventenable) -#define MPT2EVENTREPORT _IOWR(MPT2_MAGIC_NUMBER, 23, \ - struct mpt2_ioctl_eventreport) -#define MPT2HARDRESET _IOWR(MPT2_MAGIC_NUMBER, 24, \ - struct mpt2_ioctl_diag_reset) -#define MPT2BTDHMAPPING _IOWR(MPT2_MAGIC_NUMBER, 31, \ - struct mpt2_ioctl_btdh_mapping) - -/* diag buffer support */ -#define MPT2DIAGREGISTER _IOWR(MPT2_MAGIC_NUMBER, 26, \ - struct mpt2_diag_register) -#define MPT2DIAGRELEASE _IOWR(MPT2_MAGIC_NUMBER, 27, \ - struct mpt2_diag_release) -#define MPT2DIAGUNREGISTER _IOWR(MPT2_MAGIC_NUMBER, 28, \ - struct mpt2_diag_unregister) -#define MPT2DIAGQUERY _IOWR(MPT2_MAGIC_NUMBER, 29, \ - struct mpt2_diag_query) -#define MPT2DIAGREADBUFFER _IOWR(MPT2_MAGIC_NUMBER, 30, \ - struct mpt2_diag_read_buffer) - -/** - * struct mpt2_ioctl_header - main header structure - * @ioc_number - IOC unit number - * @port_number - IOC port number - * @max_data_size - maximum number bytes to transfer on read - */ -struct mpt2_ioctl_header { - uint32_t ioc_number; - uint32_t port_number; - uint32_t max_data_size; -}; - -/** - * struct mpt2_ioctl_diag_reset - diagnostic reset - * @hdr - generic header - */ -struct mpt2_ioctl_diag_reset { - struct mpt2_ioctl_header hdr; -}; - - -/** - * struct mpt2_ioctl_pci_info - pci device info - * @device - pci device id - * @function - pci function id - * @bus - pci bus id - * @segment_id - pci segment id - */ -struct mpt2_ioctl_pci_info { - union { - struct { - uint32_t device:5; - uint32_t function:3; - uint32_t bus:24; - } bits; - uint32_t word; - } u; - uint32_t segment_id; -}; - - -#define MPT2_IOCTL_INTERFACE_SCSI (0x00) -#define MPT2_IOCTL_INTERFACE_FC (0x01) -#define MPT2_IOCTL_INTERFACE_FC_IP (0x02) -#define MPT2_IOCTL_INTERFACE_SAS (0x03) -#define MPT2_IOCTL_INTERFACE_SAS2 (0x04) -#define MPT2_IOCTL_INTERFACE_SAS2_SSS6200 (0x05) -#define MPT2_IOCTL_VERSION_LENGTH (32) - -/** - * struct mpt2_ioctl_iocinfo - generic controller info - * @hdr - generic header - * @adapter_type - type of adapter (spi, fc, sas) - * @port_number - port number - * @pci_id - PCI Id - * @hw_rev - hardware revision - * @sub_system_device - PCI subsystem Device ID - * @sub_system_vendor - PCI subsystem Vendor ID - * @rsvd0 - reserved - * @firmware_version - firmware version - * @bios_version - BIOS version - * @driver_version - driver version - 32 ASCII characters - * @rsvd1 - reserved - * @scsi_id - scsi id of adapter 0 - * @rsvd2 - reserved - * @pci_information - pci info (2nd revision) - */ -struct mpt2_ioctl_iocinfo { - struct mpt2_ioctl_header hdr; - uint32_t adapter_type; - uint32_t port_number; - uint32_t pci_id; - uint32_t hw_rev; - uint32_t subsystem_device; - uint32_t subsystem_vendor; - uint32_t rsvd0; - uint32_t firmware_version; - uint32_t bios_version; - uint8_t driver_version[MPT2_IOCTL_VERSION_LENGTH]; - uint8_t rsvd1; - uint8_t scsi_id; - uint16_t rsvd2; - struct mpt2_ioctl_pci_info pci_information; -}; - - -/* number of event log entries */ -#define MPT2SAS_CTL_EVENT_LOG_SIZE (50) - -/** - * struct mpt2_ioctl_eventquery - query event count and type - * @hdr - generic header - * @event_entries - number of events returned by get_event_report - * @rsvd - reserved - * @event_types - type of events currently being captured - */ -struct mpt2_ioctl_eventquery { - struct mpt2_ioctl_header hdr; - uint16_t event_entries; - uint16_t rsvd; - uint32_t event_types[MPI2_EVENT_NOTIFY_EVENTMASK_WORDS]; -}; - -/** - * struct mpt2_ioctl_eventenable - enable/disable event capturing - * @hdr - generic header - * @event_types - toggle off/on type of events to be captured - */ -struct mpt2_ioctl_eventenable { - struct mpt2_ioctl_header hdr; - uint32_t event_types[4]; -}; - -#define MPT2_EVENT_DATA_SIZE (192) -/** - * struct MPT2_IOCTL_EVENTS - - * @event - the event that was reported - * @context - unique value for each event assigned by driver - * @data - event data returned in fw reply message - */ -struct MPT2_IOCTL_EVENTS { - uint32_t event; - uint32_t context; - uint8_t data[MPT2_EVENT_DATA_SIZE]; -}; - -/** - * struct mpt2_ioctl_eventreport - returing event log - * @hdr - generic header - * @event_data - (see struct MPT2_IOCTL_EVENTS) - */ -struct mpt2_ioctl_eventreport { - struct mpt2_ioctl_header hdr; - struct MPT2_IOCTL_EVENTS event_data[1]; -}; - -/** - * struct mpt2_ioctl_command - generic mpt firmware passthru ioclt - * @hdr - generic header - * @timeout - command timeout in seconds. (if zero then use driver default - * value). - * @reply_frame_buf_ptr - reply location - * @data_in_buf_ptr - destination for read - * @data_out_buf_ptr - data source for write - * @sense_data_ptr - sense data location - * @max_reply_bytes - maximum number of reply bytes to be sent to app. - * @data_in_size - number bytes for data transfer in (read) - * @data_out_size - number bytes for data transfer out (write) - * @max_sense_bytes - maximum number of bytes for auto sense buffers - * @data_sge_offset - offset in words from the start of the request message to - * the first SGL - * @mf[1]; - */ -struct mpt2_ioctl_command { - struct mpt2_ioctl_header hdr; - uint32_t timeout; - void __user *reply_frame_buf_ptr; - void __user *data_in_buf_ptr; - void __user *data_out_buf_ptr; - void __user *sense_data_ptr; - uint32_t max_reply_bytes; - uint32_t data_in_size; - uint32_t data_out_size; - uint32_t max_sense_bytes; - uint32_t data_sge_offset; - uint8_t mf[1]; -}; - -#ifdef CONFIG_COMPAT -struct mpt2_ioctl_command32 { - struct mpt2_ioctl_header hdr; - uint32_t timeout; - uint32_t reply_frame_buf_ptr; - uint32_t data_in_buf_ptr; - uint32_t data_out_buf_ptr; - uint32_t sense_data_ptr; - uint32_t max_reply_bytes; - uint32_t data_in_size; - uint32_t data_out_size; - uint32_t max_sense_bytes; - uint32_t data_sge_offset; - uint8_t mf[1]; -}; -#endif - -/** - * struct mpt2_ioctl_btdh_mapping - mapping info - * @hdr - generic header - * @id - target device identification number - * @bus - SCSI bus number that the target device exists on - * @handle - device handle for the target device - * @rsvd - reserved - * - * To obtain a bus/id the application sets - * handle to valid handle, and bus/id to 0xFFFF. - * - * To obtain the device handle the application sets - * bus/id valid value, and the handle to 0xFFFF. - */ -struct mpt2_ioctl_btdh_mapping { - struct mpt2_ioctl_header hdr; - uint32_t id; - uint32_t bus; - uint16_t handle; - uint16_t rsvd; -}; - - -/* status bits for ioc->diag_buffer_status */ -#define MPT2_DIAG_BUFFER_IS_REGISTERED (0x01) -#define MPT2_DIAG_BUFFER_IS_RELEASED (0x02) -#define MPT2_DIAG_BUFFER_IS_DIAG_RESET (0x04) - -/* application flags for mpt2_diag_register, mpt2_diag_query */ -#define MPT2_APP_FLAGS_APP_OWNED (0x0001) -#define MPT2_APP_FLAGS_BUFFER_VALID (0x0002) -#define MPT2_APP_FLAGS_FW_BUFFER_ACCESS (0x0004) - -/* flags for mpt2_diag_read_buffer */ -#define MPT2_FLAGS_REREGISTER (0x0001) - -#define MPT2_PRODUCT_SPECIFIC_DWORDS 23 - -/** - * struct mpt2_diag_register - application register with driver - * @hdr - generic header - * @reserved - - * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED - * @application_flags - misc flags - * @diagnostic_flags - specifies flags affecting command processing - * @product_specific - product specific information - * @requested_buffer_size - buffers size in bytes - * @unique_id - tag specified by application that is used to signal ownership - * of the buffer. - * - * This will allow the driver to setup any required buffers that will be - * needed by firmware to communicate with the driver. - */ -struct mpt2_diag_register { - struct mpt2_ioctl_header hdr; - uint8_t reserved; - uint8_t buffer_type; - uint16_t application_flags; - uint32_t diagnostic_flags; - uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS]; - uint32_t requested_buffer_size; - uint32_t unique_id; -}; - -/** - * struct mpt2_diag_unregister - application unregister with driver - * @hdr - generic header - * @unique_id - tag uniquely identifies the buffer to be unregistered - * - * This will allow the driver to cleanup any memory allocated for diag - * messages and to free up any resources. - */ -struct mpt2_diag_unregister { - struct mpt2_ioctl_header hdr; - uint32_t unique_id; -}; - -/** - * struct mpt2_diag_query - query relevant info associated with diag buffers - * @hdr - generic header - * @reserved - - * @buffer_type - specifies either TRACE, SNAPSHOT, or EXTENDED - * @application_flags - misc flags - * @diagnostic_flags - specifies flags affecting command processing - * @product_specific - product specific information - * @total_buffer_size - diag buffer size in bytes - * @driver_added_buffer_size - size of extra space appended to end of buffer - * @unique_id - unique id associated with this buffer. - * - * The application will send only buffer_type and unique_id. Driver will - * inspect unique_id first, if valid, fill in all the info. If unique_id is - * 0x00, the driver will return info specified by Buffer Type. - */ -struct mpt2_diag_query { - struct mpt2_ioctl_header hdr; - uint8_t reserved; - uint8_t buffer_type; - uint16_t application_flags; - uint32_t diagnostic_flags; - uint32_t product_specific[MPT2_PRODUCT_SPECIFIC_DWORDS]; - uint32_t total_buffer_size; - uint32_t driver_added_buffer_size; - uint32_t unique_id; -}; - -/** - * struct mpt2_diag_release - request to send Diag Release Message to firmware - * @hdr - generic header - * @unique_id - tag uniquely identifies the buffer to be released - * - * This allows ownership of the specified buffer to returned to the driver, - * allowing an application to read the buffer without fear that firmware is - * overwritting information in the buffer. - */ -struct mpt2_diag_release { - struct mpt2_ioctl_header hdr; - uint32_t unique_id; -}; - -/** - * struct mpt2_diag_read_buffer - request for copy of the diag buffer - * @hdr - generic header - * @status - - * @reserved - - * @flags - misc flags - * @starting_offset - starting offset within drivers buffer where to start - * reading data at into the specified application buffer - * @bytes_to_read - number of bytes to copy from the drivers buffer into the - * application buffer starting at starting_offset. - * @unique_id - unique id associated with this buffer. - * @diagnostic_data - data payload - */ -struct mpt2_diag_read_buffer { - struct mpt2_ioctl_header hdr; - uint8_t status; - uint8_t reserved; - uint16_t flags; - uint32_t starting_offset; - uint32_t bytes_to_read; - uint32_t unique_id; - uint32_t diagnostic_data[1]; -}; - -#endif /* MPT2SAS_CTL_H_INCLUDED */ diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_debug.h b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_debug.h deleted file mode 100644 index 9731f8e6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_debug.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Logging Support for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_debug.c - * Copyright (C) 2007-2010 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef MPT2SAS_DEBUG_H_INCLUDED -#define MPT2SAS_DEBUG_H_INCLUDED - -#define MPT_DEBUG 0x00000001 -#define MPT_DEBUG_MSG_FRAME 0x00000002 -#define MPT_DEBUG_SG 0x00000004 -#define MPT_DEBUG_EVENTS 0x00000008 -#define MPT_DEBUG_EVENT_WORK_TASK 0x00000010 -#define MPT_DEBUG_INIT 0x00000020 -#define MPT_DEBUG_EXIT 0x00000040 -#define MPT_DEBUG_FAIL 0x00000080 -#define MPT_DEBUG_TM 0x00000100 -#define MPT_DEBUG_REPLY 0x00000200 -#define MPT_DEBUG_HANDSHAKE 0x00000400 -#define MPT_DEBUG_CONFIG 0x00000800 -#define MPT_DEBUG_DL 0x00001000 -#define MPT_DEBUG_RESET 0x00002000 -#define MPT_DEBUG_SCSI 0x00004000 -#define MPT_DEBUG_IOCTL 0x00008000 -#define MPT_DEBUG_CSMISAS 0x00010000 -#define MPT_DEBUG_SAS 0x00020000 -#define MPT_DEBUG_TRANSPORT 0x00040000 -#define MPT_DEBUG_TASK_SET_FULL 0x00080000 - -#define MPT_DEBUG_TARGET_MODE 0x00100000 - - -/* - * CONFIG_SCSI_MPT2SAS_LOGGING - enabled in Kconfig - */ - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -#define MPT_CHECK_LOGGING(IOC, CMD, BITS) \ -{ \ - if (IOC->logging_level & BITS) \ - CMD; \ -} -#else -#define MPT_CHECK_LOGGING(IOC, CMD, BITS) -#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */ - - -/* - * debug macros - */ - -#define dprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG) - -#define dsgprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SG) - -#define devtprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENTS) - -#define dewtprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EVENT_WORK_TASK) - -#define dinitprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_INIT) - -#define dexitprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_EXIT) - -#define dfailprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_FAIL) - -#define dtmprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TM) - -#define dreplyprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_REPLY) - -#define dhsprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_HANDSHAKE) - -#define dcprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CONFIG) - -#define ddlprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_DL) - -#define drsprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_RESET) - -#define dsprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SCSI) - -#define dctlprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_IOCTL) - -#define dcsmisasprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_CSMISAS) - -#define dsasprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS) - -#define dsastransport(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_SAS_WIDE) - -#define dmfprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_MSG_FRAME) - -#define dtsfprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TASK_SET_FULL) - -#define dtransportprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TRANSPORT) - -#define dTMprintk(IOC, CMD) \ - MPT_CHECK_LOGGING(IOC, CMD, MPT_DEBUG_TARGET_MODE) - -/* inline functions for dumping debug data*/ -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _debug_dump_mf - print message frame contents - * @mpi_request: pointer to message frame - * @sz: number of dwords - */ -static inline void -_debug_dump_mf(void *mpi_request, int sz) -{ - int i; - __le32 *mfp = (__le32 *)mpi_request; - - printk(KERN_INFO "mf:\n\t"); - for (i = 0; i < sz; i++) { - if (i && ((i % 8) == 0)) - printk("\n\t"); - printk("%08x ", le32_to_cpu(mfp[i])); - } - printk("\n"); -} -#else -#define _debug_dump_mf(mpi_request, sz) -#endif /* CONFIG_SCSI_MPT2SAS_LOGGING */ - -#endif /* MPT2SAS_DEBUG_H_INCLUDED */ diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_scsih.c deleted file mode 100644 index d953a57e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ /dev/null @@ -1,8384 +0,0 @@ -/* - * Scsi Host Layer for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c - * Copyright (C) 2007-2010 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_base.h" - -MODULE_AUTHOR(MPT2SAS_AUTHOR); -MODULE_DESCRIPTION(MPT2SAS_DESCRIPTION); -MODULE_LICENSE("GPL"); -MODULE_VERSION(MPT2SAS_DRIVER_VERSION); - -#define RAID_CHANNEL 1 - -/* forward proto's */ -static void _scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander); -static void _firmware_event_work(struct work_struct *work); - -static u8 _scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid); - -static void _scsih_scan_start(struct Scsi_Host *shost); -static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); - -/* global parameters */ -LIST_HEAD(mpt2sas_ioc_list); - -/* local parameters */ -static u8 scsi_io_cb_idx = -1; -static u8 tm_cb_idx = -1; -static u8 ctl_cb_idx = -1; -static u8 base_cb_idx = -1; -static u8 port_enable_cb_idx = -1; -static u8 transport_cb_idx = -1; -static u8 scsih_cb_idx = -1; -static u8 config_cb_idx = -1; -static int mpt_ids; - -static u8 tm_tr_cb_idx = -1 ; -static u8 tm_tr_volume_cb_idx = -1 ; -static u8 tm_sas_control_cb_idx = -1; - -/* command line options */ -static u32 logging_level; -MODULE_PARM_DESC(logging_level, " bits for enabling additional logging info " - "(default=0)"); - -static ushort max_sectors = 0xFFFF; -module_param(max_sectors, ushort, 0); -MODULE_PARM_DESC(max_sectors, "max sectors, range 64 to 32767 default=32767"); - -/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ -#define MPT2SAS_MAX_LUN (16895) -static int max_lun = MPT2SAS_MAX_LUN; -module_param(max_lun, int, 0); -MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); - -/* diag_buffer_enable is bitwise - * bit 0 set = TRACE - * bit 1 set = SNAPSHOT - * bit 2 set = EXTENDED - * - * Either bit can be set, or both - */ -static int diag_buffer_enable = -1; -module_param(diag_buffer_enable, int, 0); -MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers " - "(TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); - -/** - * struct sense_info - common structure for obtaining sense keys - * @skey: sense key - * @asc: additional sense code - * @ascq: additional sense code qualifier - */ -struct sense_info { - u8 skey; - u8 asc; - u8 ascq; -}; - - -#define MPT2SAS_TURN_ON_FAULT_LED (0xFFFC) -#define MPT2SAS_PORT_ENABLE_COMPLETE (0xFFFD) -#define MPT2SAS_REMOVE_UNRESPONDING_DEVICES (0xFFFF) -/** - * struct fw_event_work - firmware event struct - * @list: link list framework - * @work: work object (ioc->fault_reset_work_q) - * @cancel_pending_work: flag set during reset handling - * @ioc: per adapter object - * @device_handle: device handle - * @VF_ID: virtual function id - * @VP_ID: virtual port id - * @ignore: flag meaning this event has been marked to ignore - * @event: firmware event MPI2_EVENT_XXX defined in mpt2_ioc.h - * @event_data: reply event data payload follows - * - * This object stored on ioc->fw_event_list. - */ -struct fw_event_work { - struct list_head list; - u8 cancel_pending_work; - struct delayed_work delayed_work; - struct MPT2SAS_ADAPTER *ioc; - u16 device_handle; - u8 VF_ID; - u8 VP_ID; - u8 ignore; - u16 event; - void *event_data; -}; - -/* raid transport support */ -static struct raid_template *mpt2sas_raid_template; - -/** - * struct _scsi_io_transfer - scsi io transfer - * @handle: sas device handle (assigned by firmware) - * @is_raid: flag set for hidden raid components - * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE, - * @data_length: data transfer length - * @data_dma: dma pointer to data - * @sense: sense data - * @lun: lun number - * @cdb_length: cdb length - * @cdb: cdb contents - * @timeout: timeout for this command - * @VF_ID: virtual function id - * @VP_ID: virtual port id - * @valid_reply: flag set for reply message - * @sense_length: sense length - * @ioc_status: ioc status - * @scsi_state: scsi state - * @scsi_status: scsi staus - * @log_info: log information - * @transfer_length: data length transfer when there is a reply message - * - * Used for sending internal scsi commands to devices within this module. - * Refer to _scsi_send_scsi_io(). - */ -struct _scsi_io_transfer { - u16 handle; - u8 is_raid; - enum dma_data_direction dir; - u32 data_length; - dma_addr_t data_dma; - u8 sense[SCSI_SENSE_BUFFERSIZE]; - u32 lun; - u8 cdb_length; - u8 cdb[32]; - u8 timeout; - u8 VF_ID; - u8 VP_ID; - u8 valid_reply; - /* the following bits are only valid when 'valid_reply = 1' */ - u32 sense_length; - u16 ioc_status; - u8 scsi_state; - u8 scsi_status; - u32 log_info; - u32 transfer_length; -}; - -/* - * The pci device ids are defined in mpi/mpi2_cnfg.h. - */ -static struct pci_device_id scsih_pci_table[] = { - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2004, - PCI_ANY_ID, PCI_ANY_ID }, - /* Falcon ~ 2008*/ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2008, - PCI_ANY_ID, PCI_ANY_ID }, - /* Liberator ~ 2108 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2108_3, - PCI_ANY_ID, PCI_ANY_ID }, - /* Meteor ~ 2116 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2116_2, - PCI_ANY_ID, PCI_ANY_ID }, - /* Thunderbolt ~ 2208 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_3, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_4, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_5, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2208_6, - PCI_ANY_ID, PCI_ANY_ID }, - /* Mustang ~ 2308 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_1, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_2, - PCI_ANY_ID, PCI_ANY_ID }, - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SAS2308_3, - PCI_ANY_ID, PCI_ANY_ID }, - /* SSS6200 */ - { MPI2_MFGPAGE_VENDORID_LSI, MPI2_MFGPAGE_DEVID_SSS6200, - PCI_ANY_ID, PCI_ANY_ID }, - {0} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, scsih_pci_table); - -/** - * _scsih_set_debug_level - global setting of ioc->logging_level. - * - * Note: The logging levels are defined in mpt2sas_debug.h. - */ -static int -_scsih_set_debug_level(const char *val, struct kernel_param *kp) -{ - int ret = param_set_int(val, kp); - struct MPT2SAS_ADAPTER *ioc; - - if (ret) - return ret; - - printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level); - list_for_each_entry(ioc, &mpt2sas_ioc_list, list) - ioc->logging_level = logging_level; - return 0; -} -module_param_call(logging_level, _scsih_set_debug_level, param_get_int, - &logging_level, 0644); - -/** - * _scsih_srch_boot_sas_address - search based on sas_address - * @sas_address: sas address - * @boot_device: boot device object from bios page 2 - * - * Returns 1 when there's a match, 0 means no match. - */ -static inline int -_scsih_srch_boot_sas_address(u64 sas_address, - Mpi2BootDeviceSasWwid_t *boot_device) -{ - return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0; -} - -/** - * _scsih_srch_boot_device_name - search based on device name - * @device_name: device name specified in INDENTIFY fram - * @boot_device: boot device object from bios page 2 - * - * Returns 1 when there's a match, 0 means no match. - */ -static inline int -_scsih_srch_boot_device_name(u64 device_name, - Mpi2BootDeviceDeviceName_t *boot_device) -{ - return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0; -} - -/** - * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot - * @enclosure_logical_id: enclosure logical id - * @slot_number: slot number - * @boot_device: boot device object from bios page 2 - * - * Returns 1 when there's a match, 0 means no match. - */ -static inline int -_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number, - Mpi2BootDeviceEnclosureSlot_t *boot_device) -{ - return (enclosure_logical_id == le64_to_cpu(boot_device-> - EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device-> - SlotNumber)) ? 1 : 0; -} - -/** - * _scsih_is_boot_device - search for matching boot device. - * @sas_address: sas address - * @device_name: device name specified in INDENTIFY fram - * @enclosure_logical_id: enclosure logical id - * @slot_number: slot number - * @form: specifies boot device form - * @boot_device: boot device object from bios page 2 - * - * Returns 1 when there's a match, 0 means no match. - */ -static int -_scsih_is_boot_device(u64 sas_address, u64 device_name, - u64 enclosure_logical_id, u16 slot, u8 form, - Mpi2BiosPage2BootDevice_t *boot_device) -{ - int rc = 0; - - switch (form) { - case MPI2_BIOSPAGE2_FORM_SAS_WWID: - if (!sas_address) - break; - rc = _scsih_srch_boot_sas_address( - sas_address, &boot_device->SasWwid); - break; - case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT: - if (!enclosure_logical_id) - break; - rc = _scsih_srch_boot_encl_slot( - enclosure_logical_id, - slot, &boot_device->EnclosureSlot); - break; - case MPI2_BIOSPAGE2_FORM_DEVICE_NAME: - if (!device_name) - break; - rc = _scsih_srch_boot_device_name( - device_name, &boot_device->DeviceName); - break; - case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED: - break; - } - - return rc; -} - -/** - * _scsih_get_sas_address - set the sas_address for given device handle - * @handle: device handle - * @sas_address: sas address - * - * Returns 0 success, non-zero when failure - */ -static int -_scsih_get_sas_address(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u64 *sas_address) -{ - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 ioc_status; - *sas_address = 0; - - if (handle <= ioc->sas_hba.num_phys) { - *sas_address = ioc->sas_hba.sas_address; - return 0; - } - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - return -ENXIO; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - *sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - return 0; - } - - /* we hit this becuase the given parent handle doesn't exist */ - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - return -ENXIO; - /* else error case */ - printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x), " - "failure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, - __FILE__, __LINE__, __func__); - return -EIO; -} - -/** - * _scsih_determine_boot_device - determine boot device. - * @ioc: per adapter object - * @device: either sas_device or raid_device object - * @is_raid: [flag] 1 = raid object, 0 = sas object - * - * Determines whether this device should be first reported device to - * to scsi-ml or sas transport, this purpose is for persistent boot device. - * There are primary, alternate, and current entries in bios page 2. The order - * priority is primary, alternate, then current. This routine saves - * the corresponding device object and is_raid flag in the ioc object. - * The saved data to be used later in _scsih_probe_boot_devices(). - */ -static void -_scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, - void *device, u8 is_raid) -{ - struct _sas_device *sas_device; - struct _raid_device *raid_device; - u64 sas_address; - u64 device_name; - u64 enclosure_logical_id; - u16 slot; - - /* only process this function when driver loads */ - if (!ioc->is_driver_loading) - return; - - /* no Bios, return immediately */ - if (!ioc->bios_pg3.BiosVersion) - return; - - if (!is_raid) { - sas_device = device; - sas_address = sas_device->sas_address; - device_name = sas_device->device_name; - enclosure_logical_id = sas_device->enclosure_logical_id; - slot = sas_device->slot; - } else { - raid_device = device; - sas_address = raid_device->wwid; - device_name = 0; - enclosure_logical_id = 0; - slot = 0; - } - - if (!ioc->req_boot_device.device) { - if (_scsih_is_boot_device(sas_address, device_name, - enclosure_logical_id, slot, - (ioc->bios_pg2.ReqBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK), - &ioc->bios_pg2.RequestedBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: req_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); - ioc->req_boot_device.device = device; - ioc->req_boot_device.is_raid = is_raid; - } - } - - if (!ioc->req_alt_boot_device.device) { - if (_scsih_is_boot_device(sas_address, device_name, - enclosure_logical_id, slot, - (ioc->bios_pg2.ReqAltBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK), - &ioc->bios_pg2.RequestedAltBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: req_alt_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); - ioc->req_alt_boot_device.device = device; - ioc->req_alt_boot_device.is_raid = is_raid; - } - } - - if (!ioc->current_boot_device.device) { - if (_scsih_is_boot_device(sas_address, device_name, - enclosure_logical_id, slot, - (ioc->bios_pg2.CurrentBootDeviceForm & - MPI2_BIOSPAGE2_FORM_MASK), - &ioc->bios_pg2.CurrentBootDevice)) { - dinitprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: current_boot_device(0x%016llx)\n", - ioc->name, __func__, - (unsigned long long)sas_address)); - ioc->current_boot_device.device = device; - ioc->current_boot_device.is_raid = is_raid; - } - } -} - -/** - * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search - * @ioc: per adapter object - * @sas_address: sas address - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for sas_device based on sas_address, then return sas_device - * object. - */ -struct _sas_device * -mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_device *sas_device; - - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->sas_address == sas_address) - return sas_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->sas_address == sas_address) - return sas_device; - - return NULL; -} - -/** - * _scsih_sas_device_find_by_handle - sas device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for sas_device based on sas_address, then return sas_device - * object. - */ -static struct _sas_device * -_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_device *sas_device; - - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->handle == handle) - return sas_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->handle == handle) - return sas_device; - - return NULL; -} - -/** - * _scsih_sas_device_remove - remove sas_device from list. - * @ioc: per adapter object - * @sas_device: the sas_device object - * Context: This function will acquire ioc->sas_device_lock. - * - * Removing object and freeing associated memory from the ioc->sas_device_list. - */ -static void -_scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - if (!sas_device) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - if (mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device->sas_address)) { - list_del(&sas_device->list); - kfree(sas_device); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -} - -/** - * _scsih_sas_device_add - insert sas_device to the list. - * @ioc: per adapter object - * @sas_device: the sas_device object - * Context: This function will acquire ioc->sas_device_lock. - * - * Adding new object to the ioc->sas_device_list. - */ -static void -_scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" - "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long)sas_device->sas_address)); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_add_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - } else if (!sas_device->starget) { - /* When asyn scanning is enabled, its not possible to remove - * devices while scanning is turned on due to an oops in - * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start() - */ - if (!ioc->is_driver_loading) - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); - } -} - -/** - * _scsih_sas_device_init_add - insert sas_device to the list. - * @ioc: per adapter object - * @sas_device: the sas_device object - * Context: This function will acquire ioc->sas_device_lock. - * - * Adding new object at driver load time to the ioc->sas_device_init_list. - */ -static void -_scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - unsigned long flags; - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" - "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long)sas_device->sas_address)); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_add_tail(&sas_device->list, &ioc->sas_device_init_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_determine_boot_device(ioc, sas_device, 0); -} - -/** - * _scsih_raid_device_find_by_id - raid device search - * @ioc: per adapter object - * @id: sas device target id - * @channel: sas device channel - * Context: Calling function should acquire ioc->raid_device_lock - * - * This searches for raid_device based on target id, then return raid_device - * object. - */ -static struct _raid_device * -_scsih_raid_device_find_by_id(struct MPT2SAS_ADAPTER *ioc, int id, int channel) -{ - struct _raid_device *raid_device, *r; - - r = NULL; - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (raid_device->id == id && raid_device->channel == channel) { - r = raid_device; - goto out; - } - } - - out: - return r; -} - -/** - * _scsih_raid_device_find_by_handle - raid device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->raid_device_lock - * - * This searches for raid_device based on handle, then return raid_device - * object. - */ -static struct _raid_device * -_scsih_raid_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _raid_device *raid_device, *r; - - r = NULL; - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (raid_device->handle != handle) - continue; - r = raid_device; - goto out; - } - - out: - return r; -} - -/** - * _scsih_raid_device_find_by_wwid - raid device search - * @ioc: per adapter object - * @handle: sas device handle (assigned by firmware) - * Context: Calling function should acquire ioc->raid_device_lock - * - * This searches for raid_device based on wwid, then return raid_device - * object. - */ -static struct _raid_device * -_scsih_raid_device_find_by_wwid(struct MPT2SAS_ADAPTER *ioc, u64 wwid) -{ - struct _raid_device *raid_device, *r; - - r = NULL; - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (raid_device->wwid != wwid) - continue; - r = raid_device; - goto out; - } - - out: - return r; -} - -/** - * _scsih_raid_device_add - add raid_device object - * @ioc: per adapter object - * @raid_device: raid_device object - * - * This is added to the raid_device_list link list. - */ -static void -_scsih_raid_device_add(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - unsigned long flags; - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle" - "(0x%04x), wwid(0x%016llx)\n", ioc->name, __func__, - raid_device->handle, (unsigned long long)raid_device->wwid)); - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - list_add_tail(&raid_device->list, &ioc->raid_device_list); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * _scsih_raid_device_remove - delete raid_device object - * @ioc: per adapter object - * @raid_device: raid_device object - * - * This is removed from the raid_device_list link list. - */ -static void -_scsih_raid_device_remove(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - list_del(&raid_device->list); - memset(raid_device, 0, sizeof(struct _raid_device)); - kfree(raid_device); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * mpt2sas_scsih_expander_find_by_handle - expander device search - * @ioc: per adapter object - * @handle: expander handle (assigned by firmware) - * Context: Calling function should acquire ioc->sas_device_lock - * - * This searches for expander device based on handle, then returns the - * sas_node object. - */ -struct _sas_node * -mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_node *sas_expander, *r; - - r = NULL; - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->handle != handle) - continue; - r = sas_expander; - goto out; - } - out: - return r; -} - -/** - * mpt2sas_scsih_expander_find_by_sas_address - expander device search - * @ioc: per adapter object - * @sas_address: sas address - * Context: Calling function should acquire ioc->sas_node_lock. - * - * This searches for expander device based on sas_address, then returns the - * sas_node object. - */ -struct _sas_node * -mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - struct _sas_node *sas_expander, *r; - - r = NULL; - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->sas_address != sas_address) - continue; - r = sas_expander; - goto out; - } - out: - return r; -} - -/** - * _scsih_expander_node_add - insert expander device to the list. - * @ioc: per adapter object - * @sas_expander: the sas_device object - * Context: This function will acquire ioc->sas_node_lock. - * - * Adding new object to the ioc->sas_expander_list. - * - * Return nothing. - */ -static void -_scsih_expander_node_add(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - list_add_tail(&sas_expander->list, &ioc->sas_expander_list); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -} - -/** - * _scsih_is_end_device - determines if device is an end device - * @device_info: bitfield providing information about the device. - * Context: none - * - * Returns 1 if end device. - */ -static int -_scsih_is_end_device(u32 device_info) -{ - if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE && - ((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) | - (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) | - (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE))) - return 1; - else - return 0; -} - -/** - * _scsih_scsi_lookup_get - returns scmd entry - * @ioc: per adapter object - * @smid: system request message index - * - * Returns the smid stored scmd pointer. - */ -static struct scsi_cmnd * -_scsih_scsi_lookup_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return ioc->scsi_lookup[smid - 1].scmd; -} - -/** - * _scsih_scsi_lookup_get_clear - returns scmd entry - * @ioc: per adapter object - * @smid: system request message index - * - * Returns the smid stored scmd pointer. - * Then will derefrence the stored scmd pointer. - */ -static inline struct scsi_cmnd * -_scsih_scsi_lookup_get_clear(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - unsigned long flags; - struct scsi_cmnd *scmd; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - scmd = ioc->scsi_lookup[smid - 1].scmd; - ioc->scsi_lookup[smid - 1].scmd = NULL; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - - return scmd; -} - -/** - * _scsih_scsi_lookup_find_by_scmd - scmd lookup - * @ioc: per adapter object - * @smid: system request message index - * @scmd: pointer to scsi command object - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will search for a scmd pointer in the scsi_lookup array, - * returning the revelent smid. A returned value of zero means invalid. - */ -static u16 -_scsih_scsi_lookup_find_by_scmd(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd - *scmd) -{ - u16 smid; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - smid = 0; - for (i = 0; i < ioc->scsiio_depth; i++) { - if (ioc->scsi_lookup[i].scmd == scmd) { - smid = ioc->scsi_lookup[i].smid; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return smid; -} - -/** - * _scsih_scsi_lookup_find_by_target - search for matching channel:id - * @ioc: per adapter object - * @id: target id - * @channel: channel - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will search for a matching channel:id in the scsi_lookup array, - * returning 1 if found. - */ -static u8 -_scsih_scsi_lookup_find_by_target(struct MPT2SAS_ADAPTER *ioc, int id, - int channel) -{ - u8 found; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - found = 0; - for (i = 0 ; i < ioc->scsiio_depth; i++) { - if (ioc->scsi_lookup[i].scmd && - (ioc->scsi_lookup[i].scmd->device->id == id && - ioc->scsi_lookup[i].scmd->device->channel == channel)) { - found = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return found; -} - -/** - * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun - * @ioc: per adapter object - * @id: target id - * @lun: lun number - * @channel: channel - * Context: This function will acquire ioc->scsi_lookup_lock. - * - * This will search for a matching channel:id:lun in the scsi_lookup array, - * returning 1 if found. - */ -static u8 -_scsih_scsi_lookup_find_by_lun(struct MPT2SAS_ADAPTER *ioc, int id, - unsigned int lun, int channel) -{ - u8 found; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - found = 0; - for (i = 0 ; i < ioc->scsiio_depth; i++) { - if (ioc->scsi_lookup[i].scmd && - (ioc->scsi_lookup[i].scmd->device->id == id && - ioc->scsi_lookup[i].scmd->device->channel == channel && - ioc->scsi_lookup[i].scmd->device->lun == lun)) { - found = 1; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return found; -} - -/** - * _scsih_get_chain_buffer_tracker - obtain chain tracker - * @ioc: per adapter object - * @smid: smid associated to an IO request - * - * Returns chain tracker(from ioc->free_chain_list) - */ -static struct chain_tracker * -_scsih_get_chain_buffer_tracker(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - struct chain_tracker *chain_req; - unsigned long flags; - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - if (list_empty(&ioc->free_chain_list)) { - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT "chain buffers not " - "available\n", ioc->name)); - return NULL; - } - chain_req = list_entry(ioc->free_chain_list.next, - struct chain_tracker, tracker_list); - list_del_init(&chain_req->tracker_list); - list_add_tail(&chain_req->tracker_list, - &ioc->scsi_lookup[smid - 1].chain_list); - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - return chain_req; -} - -/** - * _scsih_build_scatter_gather - main sg creation routine - * @ioc: per adapter object - * @scmd: scsi command - * @smid: system request message index - * Context: none. - * - * The main routine that builds scatter gather table from a given - * scsi request sent via the .queuecommand main handler. - * - * Returns 0 success, anything else error - */ -static int -_scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc, - struct scsi_cmnd *scmd, u16 smid) -{ - Mpi2SCSIIORequest_t *mpi_request; - dma_addr_t chain_dma; - struct scatterlist *sg_scmd; - void *sg_local, *chain; - u32 chain_offset; - u32 chain_length; - u32 chain_flags; - int sges_left; - u32 sges_in_segment; - u32 sgl_flags; - u32 sgl_flags_last_element; - u32 sgl_flags_end_buffer; - struct chain_tracker *chain_req; - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - - /* init scatter gather flags */ - sgl_flags = MPI2_SGE_FLAGS_SIMPLE_ELEMENT; - if (scmd->sc_data_direction == DMA_TO_DEVICE) - sgl_flags |= MPI2_SGE_FLAGS_HOST_TO_IOC; - sgl_flags_last_element = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT) - << MPI2_SGE_FLAGS_SHIFT; - sgl_flags_end_buffer = (sgl_flags | MPI2_SGE_FLAGS_LAST_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_END_OF_LIST) - << MPI2_SGE_FLAGS_SHIFT; - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - - sg_scmd = scsi_sglist(scmd); - sges_left = scsi_dma_map(scmd); - if (sges_left < 0) { - sdev_printk(KERN_ERR, scmd->device, "pci_map_sg" - " failed: request for %d bytes!\n", scsi_bufflen(scmd)); - return -ENOMEM; - } - - sg_local = &mpi_request->SGL; - sges_in_segment = ioc->max_sges_in_main_message; - if (sges_left <= sges_in_segment) - goto fill_in_last_segment; - - mpi_request->ChainOffset = (offsetof(Mpi2SCSIIORequest_t, SGL) + - (sges_in_segment * ioc->sge_size))/4; - - /* fill in main message segment when there is a chain following */ - while (sges_in_segment) { - if (sges_in_segment == 1) - ioc->base_add_sg_single(sg_local, - sgl_flags_last_element | sg_dma_len(sg_scmd), - sg_dma_address(sg_scmd)); - else - ioc->base_add_sg_single(sg_local, sgl_flags | - sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); - sg_scmd = sg_next(sg_scmd); - sg_local += ioc->sge_size; - sges_left--; - sges_in_segment--; - } - - /* initializing the chain flags and pointers */ - chain_flags = MPI2_SGE_FLAGS_CHAIN_ELEMENT << MPI2_SGE_FLAGS_SHIFT; - chain_req = _scsih_get_chain_buffer_tracker(ioc, smid); - if (!chain_req) - return -1; - chain = chain_req->chain_buffer; - chain_dma = chain_req->chain_buffer_dma; - do { - sges_in_segment = (sges_left <= - ioc->max_sges_in_chain_message) ? sges_left : - ioc->max_sges_in_chain_message; - chain_offset = (sges_left == sges_in_segment) ? - 0 : (sges_in_segment * ioc->sge_size)/4; - chain_length = sges_in_segment * ioc->sge_size; - if (chain_offset) { - chain_offset = chain_offset << - MPI2_SGE_CHAIN_OFFSET_SHIFT; - chain_length += ioc->sge_size; - } - ioc->base_add_sg_single(sg_local, chain_flags | chain_offset | - chain_length, chain_dma); - sg_local = chain; - if (!chain_offset) - goto fill_in_last_segment; - - /* fill in chain segments */ - while (sges_in_segment) { - if (sges_in_segment == 1) - ioc->base_add_sg_single(sg_local, - sgl_flags_last_element | - sg_dma_len(sg_scmd), - sg_dma_address(sg_scmd)); - else - ioc->base_add_sg_single(sg_local, sgl_flags | - sg_dma_len(sg_scmd), - sg_dma_address(sg_scmd)); - sg_scmd = sg_next(sg_scmd); - sg_local += ioc->sge_size; - sges_left--; - sges_in_segment--; - } - - chain_req = _scsih_get_chain_buffer_tracker(ioc, smid); - if (!chain_req) - return -1; - chain = chain_req->chain_buffer; - chain_dma = chain_req->chain_buffer_dma; - } while (1); - - - fill_in_last_segment: - - /* fill the last segment */ - while (sges_left) { - if (sges_left == 1) - ioc->base_add_sg_single(sg_local, sgl_flags_end_buffer | - sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); - else - ioc->base_add_sg_single(sg_local, sgl_flags | - sg_dma_len(sg_scmd), sg_dma_address(sg_scmd)); - sg_scmd = sg_next(sg_scmd); - sg_local += ioc->sge_size; - sges_left--; - } - - return 0; -} - -/** - * _scsih_adjust_queue_depth - setting device queue depth - * @sdev: scsi device struct - * @qdepth: requested queue depth - * - * - * Returns nothing - */ -static void -_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth) -{ - struct Scsi_Host *shost = sdev->host; - int max_depth; - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - unsigned long flags; - - max_depth = shost->can_queue; - - /* limit max device queue for SATA to 32 */ - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - goto not_sata; - sas_target_priv_data = sas_device_priv_data->sas_target; - if (!sas_target_priv_data) - goto not_sata; - if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) - goto not_sata; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device && sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - max_depth = MPT2SAS_SATA_QUEUE_DEPTH; - - not_sata: - - if (!sdev->tagged_supported) - max_depth = 1; - if (qdepth > max_depth) - qdepth = max_depth; - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); -} - -/** - * _scsih_change_queue_depth - setting device queue depth - * @sdev: scsi device struct - * @qdepth: requested queue depth - * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP - * (see include/scsi/scsi_host.h for definition) - * - * Returns queue depth. - */ -static int -_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) -{ - if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) - _scsih_adjust_queue_depth(sdev, qdepth); - else if (reason == SCSI_QDEPTH_QFULL) - scsi_track_queue_full(sdev, qdepth); - else - return -EOPNOTSUPP; - - if (sdev->inquiry_len > 7) - sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), " - "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n", - sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags, - sdev->ordered_tags, sdev->scsi_level, - (sdev->inquiry[7] & 2) >> 1); - - return sdev->queue_depth; -} - -/** - * _scsih_change_queue_type - changing device queue tag type - * @sdev: scsi device struct - * @tag_type: requested tag type - * - * Returns queue tag type. - */ -static int -_scsih_change_queue_type(struct scsi_device *sdev, int tag_type) -{ - if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, tag_type); - if (tag_type) - scsi_activate_tcq(sdev, sdev->queue_depth); - else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - } else - tag_type = 0; - - return tag_type; -} - -/** - * _scsih_target_alloc - target add routine - * @starget: scsi target struct - * - * Returns 0 if ok. Any other return is assumed to be an error and - * the device is ignored. - */ -static int -_scsih_target_alloc(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - struct _raid_device *raid_device; - unsigned long flags; - struct sas_rphy *rphy; - - sas_target_priv_data = kzalloc(sizeof(struct scsi_target), GFP_KERNEL); - if (!sas_target_priv_data) - return -ENOMEM; - - starget->hostdata = sas_target_priv_data; - sas_target_priv_data->starget = starget; - sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; - - /* RAID volumes */ - if (starget->channel == RAID_CHANNEL) { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, - starget->channel); - if (raid_device) { - sas_target_priv_data->handle = raid_device->handle; - sas_target_priv_data->sas_address = raid_device->wwid; - sas_target_priv_data->flags |= MPT_TARGET_FLAGS_VOLUME; - sas_target_priv_data->raid_device = raid_device; - raid_device->starget = starget; - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - return 0; - } - - /* sas/sata devices */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - rphy = dev_to_rphy(starget->dev.parent); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - rphy->identify.sas_address); - - if (sas_device) { - sas_target_priv_data->handle = sas_device->handle; - sas_target_priv_data->sas_address = sas_device->sas_address; - sas_device->starget = starget; - sas_device->id = starget->id; - sas_device->channel = starget->channel; - if (test_bit(sas_device->handle, ioc->pd_handles)) - sas_target_priv_data->flags |= - MPT_TARGET_FLAGS_RAID_COMPONENT; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - return 0; -} - -/** - * _scsih_target_destroy - target destroy routine - * @starget: scsi target struct - * - * Returns nothing. - */ -static void -_scsih_target_destroy(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - struct _raid_device *raid_device; - unsigned long flags; - struct sas_rphy *rphy; - - sas_target_priv_data = starget->hostdata; - if (!sas_target_priv_data) - return; - - if (starget->channel == RAID_CHANNEL) { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, starget->id, - starget->channel); - if (raid_device) { - raid_device->starget = NULL; - raid_device->sdev = NULL; - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - goto out; - } - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - rphy = dev_to_rphy(starget->dev.parent); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - rphy->identify.sas_address); - if (sas_device && (sas_device->starget == starget) && - (sas_device->id == starget->id) && - (sas_device->channel == starget->channel)) - sas_device->starget = NULL; - - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - out: - kfree(sas_target_priv_data); - starget->hostdata = NULL; -} - -/** - * _scsih_slave_alloc - device add routine - * @sdev: scsi device struct - * - * Returns 0 if ok. Any other return is assumed to be an error and - * the device is ignored. - */ -static int -_scsih_slave_alloc(struct scsi_device *sdev) -{ - struct Scsi_Host *shost; - struct MPT2SAS_ADAPTER *ioc; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_target *starget; - struct _raid_device *raid_device; - unsigned long flags; - - sas_device_priv_data = kzalloc(sizeof(struct scsi_device), GFP_KERNEL); - if (!sas_device_priv_data) - return -ENOMEM; - - sas_device_priv_data->lun = sdev->lun; - sas_device_priv_data->flags = MPT_DEVICE_FLAGS_INIT; - - starget = scsi_target(sdev); - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->num_luns++; - sas_device_priv_data->sas_target = sas_target_priv_data; - sdev->hostdata = sas_device_priv_data; - if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT)) - sdev->no_uld_attach = 1; - - shost = dev_to_shost(&starget->dev); - ioc = shost_priv(shost); - if (starget->channel == RAID_CHANNEL) { - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, - starget->id, starget->channel); - if (raid_device) - raid_device->sdev = sdev; /* raid is single lun */ - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - } - - return 0; -} - -/** - * _scsih_slave_destroy - device destroy routine - * @sdev: scsi device struct - * - * Returns nothing. - */ -static void -_scsih_slave_destroy(struct scsi_device *sdev) -{ - struct MPT2SAS_TARGET *sas_target_priv_data; - struct scsi_target *starget; - struct Scsi_Host *shost; - struct MPT2SAS_ADAPTER *ioc; - struct _sas_device *sas_device; - unsigned long flags; - - if (!sdev->hostdata) - return; - - starget = scsi_target(sdev); - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->num_luns--; - - shost = dev_to_shost(&starget->dev); - ioc = shost_priv(shost); - - if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_target_priv_data->sas_address); - if (sas_device && !sas_target_priv_data->num_luns) - sas_device->starget = NULL; - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } - - kfree(sdev->hostdata); - sdev->hostdata = NULL; -} - -/** - * _scsih_display_sata_capabilities - sata capabilities - * @ioc: per adapter object - * @sas_device: the sas_device object - * @sdev: scsi device struct - */ -static void -_scsih_display_sata_capabilities(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device, struct scsi_device *sdev) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - u32 ioc_status; - u16 flags; - u32 device_info; - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, sas_device->handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - flags = le16_to_cpu(sas_device_pg0.Flags); - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - - sdev_printk(KERN_INFO, sdev, - "atapi(%s), ncq(%s), asyn_notify(%s), smart(%s), fua(%s), " - "sw_preserve(%s)\n", - (device_info & MPI2_SAS_DEVICE_INFO_ATAPI_DEVICE) ? "y" : "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED) ? "y" : "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_ASYNCHRONOUS_NOTIFY) ? "y" : - "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SMART_SUPPORTED) ? "y" : "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED) ? "y" : "n", - (flags & MPI2_SAS_DEVICE0_FLAGS_SATA_SW_PRESERVE) ? "y" : "n"); -} - -/** - * _scsih_is_raid - return boolean indicating device is raid volume - * @dev the device struct object - */ -static int -_scsih_is_raid(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - - if (ioc->is_warpdrive) - return 0; - return (sdev->channel == RAID_CHANNEL) ? 1 : 0; -} - -/** - * _scsih_get_resync - get raid volume resync percent complete - * @dev the device struct object - */ -static void -_scsih_get_resync(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - static struct _raid_device *raid_device; - unsigned long flags; - Mpi2RaidVolPage0_t vol_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 volume_status_flags; - u8 percent_complete = 0; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, - sdev->channel); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (!raid_device || ioc->is_warpdrive) - goto out; - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, - sizeof(Mpi2RaidVolPage0_t))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - volume_status_flags = le32_to_cpu(vol_pg0.VolumeStatusFlags); - if (volume_status_flags & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) - percent_complete = raid_device->percent_complete; - out: - raid_set_resync(mpt2sas_raid_template, dev, percent_complete); -} - -/** - * _scsih_get_state - get raid volume level - * @dev the device struct object - */ -static void -_scsih_get_state(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(sdev->host); - static struct _raid_device *raid_device; - unsigned long flags; - Mpi2RaidVolPage0_t vol_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 volstate; - enum raid_state state = RAID_STATE_UNKNOWN; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_id(ioc, sdev->id, - sdev->channel); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (!raid_device) - goto out; - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, &vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, - sizeof(Mpi2RaidVolPage0_t))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - volstate = le32_to_cpu(vol_pg0.VolumeStatusFlags); - if (volstate & MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { - state = RAID_STATE_RESYNCING; - goto out; - } - - switch (vol_pg0.VolumeState) { - case MPI2_RAID_VOL_STATE_OPTIMAL: - case MPI2_RAID_VOL_STATE_ONLINE: - state = RAID_STATE_ACTIVE; - break; - case MPI2_RAID_VOL_STATE_DEGRADED: - state = RAID_STATE_DEGRADED; - break; - case MPI2_RAID_VOL_STATE_FAILED: - case MPI2_RAID_VOL_STATE_MISSING: - state = RAID_STATE_OFFLINE; - break; - } - out: - raid_set_state(mpt2sas_raid_template, dev, state); -} - -/** - * _scsih_set_level - set raid level - * @sdev: scsi device struct - * @raid_device: raid_device object - */ -static void -_scsih_set_level(struct scsi_device *sdev, struct _raid_device *raid_device) -{ - enum raid_level level = RAID_LEVEL_UNKNOWN; - - switch (raid_device->volume_type) { - case MPI2_RAID_VOL_TYPE_RAID0: - level = RAID_LEVEL_0; - break; - case MPI2_RAID_VOL_TYPE_RAID10: - level = RAID_LEVEL_10; - break; - case MPI2_RAID_VOL_TYPE_RAID1E: - level = RAID_LEVEL_1E; - break; - case MPI2_RAID_VOL_TYPE_RAID1: - level = RAID_LEVEL_1; - break; - } - - raid_set_level(mpt2sas_raid_template, &sdev->sdev_gendev, level); -} - -/** - * _scsih_get_volume_capabilities - volume capabilities - * @ioc: per adapter object - * @sas_device: the raid_device object - * - * Returns 0 for success, else 1 - */ -static int -_scsih_get_volume_capabilities(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - Mpi2RaidVolPage0_t *vol_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 sz; - u8 num_pds; - - if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, - &num_pds)) || !num_pds) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - return 1; - } - - raid_device->num_pds = num_pds; - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); - vol_pg0 = kzalloc(sz, GFP_KERNEL); - if (!vol_pg0) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - return 1; - } - - if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - kfree(vol_pg0); - return 1; - } - - raid_device->volume_type = vol_pg0->VolumeType; - - /* figure out what the underlying devices are by - * obtaining the device_info bits for the 1st device - */ - if (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, - vol_pg0->PhysDisk[0].PhysDiskNum))) { - if (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, - le16_to_cpu(pd_pg0.DevHandle)))) { - raid_device->device_info = - le32_to_cpu(sas_device_pg0.DeviceInfo); - } - } - - kfree(vol_pg0); - return 0; -} -/** - * _scsih_disable_ddio - Disable direct I/O for all the volumes - * @ioc: per adapter object - */ -static void -_scsih_disable_ddio(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidVolPage1_t vol_pg1; - Mpi2ConfigReply_t mpi_reply; - struct _raid_device *raid_device; - u16 handle; - u16 ioc_status; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - handle = le16_to_cpu(vol_pg1.DevHandle); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device) - raid_device->direct_io_enabled = 0; - } - return; -} - - -/** - * _scsih_get_num_volumes - Get number of volumes in the ioc - * @ioc: per adapter object - */ -static u8 -_scsih_get_num_volumes(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidVolPage1_t vol_pg1; - Mpi2ConfigReply_t mpi_reply; - u16 handle; - u8 vol_cnt = 0; - u16 ioc_status; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &vol_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - vol_cnt++; - handle = le16_to_cpu(vol_pg1.DevHandle); - } - return vol_cnt; -} - - -/** - * _scsih_init_warpdrive_properties - Set properties for warpdrive direct I/O. - * @ioc: per adapter object - * @raid_device: the raid_device object - */ -static void -_scsih_init_warpdrive_properties(struct MPT2SAS_ADAPTER *ioc, - struct _raid_device *raid_device) -{ - Mpi2RaidVolPage0_t *vol_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 sz; - u8 num_pds, count; - unsigned long stripe_sz, block_sz; - u8 stripe_exp, block_exp; - u64 dev_max_lba; - - if (!ioc->is_warpdrive) - return; - - if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "globally as drives are exposed\n", ioc->name); - return; - } - if (_scsih_get_num_volumes(ioc) > 1) { - _scsih_disable_ddio(ioc); - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "globally as number of drives > 1\n", ioc->name); - return; - } - if ((mpt2sas_config_get_number_pds(ioc, raid_device->handle, - &num_pds)) || !num_pds) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "Failure in computing number of drives\n", ioc->name); - return; - } - - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); - vol_pg0 = kzalloc(sz, GFP_KERNEL); - if (!vol_pg0) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "Memory allocation failure for RVPG0\n", ioc->name); - return; - } - - if ((mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, vol_pg0, - MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, raid_device->handle, sz))) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "Failure in retrieving RVPG0\n", ioc->name); - kfree(vol_pg0); - return; - } - - /* - * WARPDRIVE:If number of physical disks in a volume exceeds the max pds - * assumed for WARPDRIVE, disable direct I/O - */ - if (num_pds > MPT_MAX_WARPDRIVE_PDS) { - printk(MPT2SAS_WARN_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x): num_mem=%d, " - "max_mem_allowed=%d\n", ioc->name, raid_device->handle, - num_pds, MPT_MAX_WARPDRIVE_PDS); - kfree(vol_pg0); - return; - } - for (count = 0; count < num_pds; count++) { - if (mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM, - vol_pg0->PhysDisk[count].PhysDiskNum) || - pd_pg0.DevHandle == MPT2SAS_INVALID_DEVICE_HANDLE) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " - "disabled for the drive with handle(0x%04x) member" - "handle retrieval failed for member number=%d\n", - ioc->name, raid_device->handle, - vol_pg0->PhysDisk[count].PhysDiskNum); - goto out_error; - } - /* Disable direct I/O if member drive lba exceeds 4 bytes */ - dev_max_lba = le64_to_cpu(pd_pg0.DeviceMaxLBA); - if (dev_max_lba >> 32) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is " - "disabled for the drive with handle(0x%04x) member" - "handle (0x%04x) unsupported max lba 0x%016llx\n", - ioc->name, raid_device->handle, - le16_to_cpu(pd_pg0.DevHandle), - (unsigned long long)dev_max_lba); - goto out_error; - } - - raid_device->pd_handle[count] = le16_to_cpu(pd_pg0.DevHandle); - } - - /* - * Assumption for WD: Direct I/O is not supported if the volume is - * not RAID0 - */ - if (raid_device->volume_type != MPI2_RAID_VOL_TYPE_RAID0) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x): type=%d, " - "s_sz=%uK, blk_size=%u\n", ioc->name, - raid_device->handle, raid_device->volume_type, - (le32_to_cpu(vol_pg0->StripeSize) * - le16_to_cpu(vol_pg0->BlockSize)) / 1024, - le16_to_cpu(vol_pg0->BlockSize)); - goto out_error; - } - - stripe_sz = le32_to_cpu(vol_pg0->StripeSize); - stripe_exp = find_first_bit(&stripe_sz, 32); - if (stripe_exp == 32) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid stripe sz %uK\n", - ioc->name, raid_device->handle, - (le32_to_cpu(vol_pg0->StripeSize) * - le16_to_cpu(vol_pg0->BlockSize)) / 1024); - goto out_error; - } - raid_device->stripe_exponent = stripe_exp; - block_sz = le16_to_cpu(vol_pg0->BlockSize); - block_exp = find_first_bit(&block_sz, 16); - if (block_exp == 16) { - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is disabled " - "for the drive with handle(0x%04x) invalid block sz %u\n", - ioc->name, raid_device->handle, - le16_to_cpu(vol_pg0->BlockSize)); - goto out_error; - } - raid_device->block_exponent = block_exp; - raid_device->direct_io_enabled = 1; - - printk(MPT2SAS_INFO_FMT "WarpDrive : Direct IO is Enabled for the drive" - " with handle(0x%04x)\n", ioc->name, raid_device->handle); - /* - * WARPDRIVE: Though the following fields are not used for direct IO, - * stored for future purpose: - */ - raid_device->max_lba = le64_to_cpu(vol_pg0->MaxLBA); - raid_device->stripe_sz = le32_to_cpu(vol_pg0->StripeSize); - raid_device->block_sz = le16_to_cpu(vol_pg0->BlockSize); - - - kfree(vol_pg0); - return; - -out_error: - raid_device->direct_io_enabled = 0; - for (count = 0; count < num_pds; count++) - raid_device->pd_handle[count] = 0; - kfree(vol_pg0); - return; -} - -/** - * _scsih_enable_tlr - setting TLR flags - * @ioc: per adapter object - * @sdev: scsi device struct - * - * Enabling Transaction Layer Retries for tape devices when - * vpd page 0x90 is present - * - */ -static void -_scsih_enable_tlr(struct MPT2SAS_ADAPTER *ioc, struct scsi_device *sdev) -{ - /* only for TAPE */ - if (sdev->type != TYPE_TAPE) - return; - - if (!(ioc->facts.IOCCapabilities & MPI2_IOCFACTS_CAPABILITY_TLR)) - return; - - sas_enable_tlr(sdev); - sdev_printk(KERN_INFO, sdev, "TLR %s\n", - sas_is_tlr_enabled(sdev) ? "Enabled" : "Disabled"); - return; - -} - -/** - * _scsih_slave_configure - device configure routine. - * @sdev: scsi device struct - * - * Returns 0 if ok. Any other return is assumed to be an error and - * the device is ignored. - */ -static int -_scsih_slave_configure(struct scsi_device *sdev) -{ - struct Scsi_Host *shost = sdev->host; - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _sas_device *sas_device; - struct _raid_device *raid_device; - unsigned long flags; - int qdepth; - u8 ssp_target = 0; - char *ds = ""; - char *r_level = ""; - - qdepth = 1; - sas_device_priv_data = sdev->hostdata; - sas_device_priv_data->configured_lun = 1; - sas_device_priv_data->flags &= ~MPT_DEVICE_FLAGS_INIT; - sas_target_priv_data = sas_device_priv_data->sas_target; - - /* raid volume handling */ - if (sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME) { - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, - sas_target_priv_data->handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (!raid_device) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); - return 1; - } - - _scsih_get_volume_capabilities(ioc, raid_device); - - if (_scsih_get_volume_capabilities(ioc, raid_device)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, - __LINE__, __func__)); - return 1; - } - /* - * WARPDRIVE: Initialize the required data for Direct IO - */ - _scsih_init_warpdrive_properties(ioc, raid_device); - - /* RAID Queue Depth Support - * IS volume = underlying qdepth of drive type, either - * MPT2SAS_SAS_QUEUE_DEPTH or MPT2SAS_SATA_QUEUE_DEPTH - * IM/IME/R10 = 128 (MPT2SAS_RAID_QUEUE_DEPTH) - */ - if (raid_device->device_info & - MPI2_SAS_DEVICE_INFO_SSP_TARGET) { - qdepth = MPT2SAS_SAS_QUEUE_DEPTH; - ds = "SSP"; - } else { - qdepth = MPT2SAS_SATA_QUEUE_DEPTH; - if (raid_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "SATA"; - else - ds = "STP"; - } - - switch (raid_device->volume_type) { - case MPI2_RAID_VOL_TYPE_RAID0: - r_level = "RAID0"; - break; - case MPI2_RAID_VOL_TYPE_RAID1E: - qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - if (ioc->manu_pg10.OEMIdentifier && - (le32_to_cpu(ioc->manu_pg10.GenericFlags0) & - MFG10_GF0_R10_DISPLAY) && - !(raid_device->num_pds % 2)) - r_level = "RAID10"; - else - r_level = "RAID1E"; - break; - case MPI2_RAID_VOL_TYPE_RAID1: - qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - r_level = "RAID1"; - break; - case MPI2_RAID_VOL_TYPE_RAID10: - qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - r_level = "RAID10"; - break; - case MPI2_RAID_VOL_TYPE_UNKNOWN: - default: - qdepth = MPT2SAS_RAID_QUEUE_DEPTH; - r_level = "RAIDX"; - break; - } - - if (!ioc->hide_ir_msg) - sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " - "wwid(0x%016llx), pd_count(%d), type(%s)\n", - r_level, raid_device->handle, - (unsigned long long)raid_device->wwid, - raid_device->num_pds, ds); - _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); - /* raid transport support */ - if (!ioc->is_warpdrive) - _scsih_set_level(sdev, raid_device); - return 0; - } - - /* non-raid handling */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) { - if (sas_target_priv_data->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - if (mpt2sas_config_get_volume_handle(ioc, - sas_device->handle, &sas_device->volume_handle)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); - return 1; - } - if (sas_device->volume_handle && - mpt2sas_config_get_volume_wwid(ioc, - sas_device->volume_handle, - &sas_device->volume_wwid)) { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__)); - return 1; - } - } - if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) { - qdepth = MPT2SAS_SAS_QUEUE_DEPTH; - ssp_target = 1; - ds = "SSP"; - } else { - qdepth = MPT2SAS_SATA_QUEUE_DEPTH; - if (sas_device->device_info & - MPI2_SAS_DEVICE_INFO_STP_TARGET) - ds = "STP"; - else if (sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - ds = "SATA"; - } - - sdev_printk(KERN_INFO, sdev, "%s: handle(0x%04x), " - "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", - ds, sas_device->handle, - (unsigned long long)sas_device->sas_address, - sas_device->phy, - (unsigned long long)sas_device->device_name); - sdev_printk(KERN_INFO, sdev, "%s: " - "enclosure_logical_id(0x%016llx), slot(%d)\n", ds, - (unsigned long long) sas_device->enclosure_logical_id, - sas_device->slot); - - if (!ssp_target) - _scsih_display_sata_capabilities(ioc, sas_device, sdev); - } else { - dfailprintk(ioc, printk(MPT2SAS_WARN_FMT - "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, - __func__)); - return 1; - } - - _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT); - - if (ssp_target) { - sas_read_port_mode_page(sdev); - _scsih_enable_tlr(ioc, sdev); - } - return 0; -} - -/** - * _scsih_bios_param - fetch head, sector, cylinder info for a disk - * @sdev: scsi device struct - * @bdev: pointer to block device context - * @capacity: device size (in 512 byte sectors) - * @params: three element array to place output: - * params[0] number of heads (max 255) - * params[1] number of sectors (max 63) - * params[2] number of cylinders - * - * Return nothing. - */ -static int -_scsih_bios_param(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int params[]) -{ - int heads; - int sectors; - sector_t cylinders; - ulong dummy; - - heads = 64; - sectors = 32; - - dummy = heads * sectors; - cylinders = capacity; - sector_div(cylinders, dummy); - - /* - * Handle extended translation size for logical drives - * > 1Gb - */ - if ((ulong)capacity >= 0x200000) { - heads = 255; - sectors = 63; - dummy = heads * sectors; - cylinders = capacity; - sector_div(cylinders, dummy); - } - - /* return result */ - params[0] = heads; - params[1] = sectors; - params[2] = cylinders; - - return 0; -} - -/** - * _scsih_response_code - translation of device response code - * @ioc: per adapter object - * @response_code: response code returned by the device - * - * Return nothing. - */ -static void -_scsih_response_code(struct MPT2SAS_ADAPTER *ioc, u8 response_code) -{ - char *desc; - - switch (response_code) { - case MPI2_SCSITASKMGMT_RSP_TM_COMPLETE: - desc = "task management request completed"; - break; - case MPI2_SCSITASKMGMT_RSP_INVALID_FRAME: - desc = "invalid frame"; - break; - case MPI2_SCSITASKMGMT_RSP_TM_NOT_SUPPORTED: - desc = "task management request not supported"; - break; - case MPI2_SCSITASKMGMT_RSP_TM_FAILED: - desc = "task management request failed"; - break; - case MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED: - desc = "task management request succeeded"; - break; - case MPI2_SCSITASKMGMT_RSP_TM_INVALID_LUN: - desc = "invalid lun"; - break; - case 0xA: - desc = "overlapped tag attempted"; - break; - case MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC: - desc = "task queued, however not sent to target"; - break; - default: - desc = "unknown"; - break; - } - printk(MPT2SAS_WARN_FMT "response_code(0x%01x): %s\n", - ioc->name, response_code, desc); -} - -/** - * _scsih_tm_done - tm completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: none. - * - * The callback handler when using scsih_issue_tm. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - if (ioc->tm_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->tm_cmds.smid != smid) - return 1; - mpt2sas_base_flush_reply_queues(ioc); - ioc->tm_cmds.status |= MPT2_CMD_COMPLETE; - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (mpi_reply) { - memcpy(ioc->tm_cmds.reply, mpi_reply, mpi_reply->MsgLength*4); - ioc->tm_cmds.status |= MPT2_CMD_REPLY_VALID; - } - ioc->tm_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->tm_cmds.done); - return 1; -} - -/** - * mpt2sas_scsih_set_tm_flag - set per target tm_busy - * @ioc: per adapter object - * @handle: device handle - * - * During taskmangement request, we need to freeze the device queue. - */ -void -mpt2sas_scsih_set_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - u8 skip = 0; - - shost_for_each_device(sdev, ioc->shost) { - if (skip) - continue; - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->sas_target->handle == handle) { - sas_device_priv_data->sas_target->tm_busy = 1; - skip = 1; - ioc->ignore_loginfos = 1; - } - } -} - -/** - * mpt2sas_scsih_clear_tm_flag - clear per target tm_busy - * @ioc: per adapter object - * @handle: device handle - * - * During taskmangement request, we need to freeze the device queue. - */ -void -mpt2sas_scsih_clear_tm_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - u8 skip = 0; - - shost_for_each_device(sdev, ioc->shost) { - if (skip) - continue; - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->sas_target->handle == handle) { - sas_device_priv_data->sas_target->tm_busy = 0; - skip = 1; - ioc->ignore_loginfos = 0; - } - } -} - - -/** - * mpt2sas_scsih_issue_tm - main routine for sending tm requests - * @ioc: per adapter struct - * @device_handle: device handle - * @channel: the channel assigned by the OS - * @id: the id assigned by the OS - * @lun: lun number - * @type: MPI2_SCSITASKMGMT_TASKTYPE__XXX (defined in mpi2_init.h) - * @smid_task: smid assigned to the task - * @timeout: timeout in seconds - * @serial_number: the serial_number from scmd - * @m_type: TM_MUTEX_ON or TM_MUTEX_OFF - * Context: user - * - * A generic API for sending task management requests to firmware. - * - * The callback index is set inside `ioc->tm_cb_idx`. - * - * Return SUCCESS or FAILED. - */ -int -mpt2sas_scsih_issue_tm(struct MPT2SAS_ADAPTER *ioc, u16 handle, uint channel, - uint id, uint lun, u8 type, u16 smid_task, ulong timeout, - unsigned long serial_number, enum mutex_type m_type) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - Mpi2SCSITaskManagementReply_t *mpi_reply; - u16 smid = 0; - u32 ioc_state; - unsigned long timeleft; - struct scsiio_tracker *scsi_lookup = NULL; - int rc; - - if (m_type == TM_MUTEX_ON) - mutex_lock(&ioc->tm_cmds.mutex); - if (ioc->tm_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_INFO_FMT "%s: tm_cmd busy!!!\n", - __func__, ioc->name); - rc = FAILED; - goto err_out; - } - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - rc = FAILED; - goto err_out; - } - - ioc_state = mpt2sas_base_get_iocstate(ioc, 0); - if (ioc_state & MPI2_DOORBELL_USED) { - dhsprintk(ioc, printk(MPT2SAS_INFO_FMT "unexpected doorbell " - "active!\n", ioc->name)); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - goto err_out; - } - - if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { - mpt2sas_base_fault_info(ioc, ioc_state & - MPI2_DOORBELL_DATA_MASK); - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - goto err_out; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = FAILED; - goto err_out; - } - - if (type == MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK) - scsi_lookup = &ioc->scsi_lookup[smid_task - 1]; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "sending tm: handle(0x%04x)," - " task_type(0x%02x), smid(%d)\n", ioc->name, handle, type, - smid_task)); - ioc->tm_cmds.status = MPT2_CMD_PENDING; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->tm_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - memset(ioc->tm_cmds.reply, 0, sizeof(Mpi2SCSITaskManagementReply_t)); - mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - mpi_request->DevHandle = cpu_to_le16(handle); - mpi_request->TaskType = type; - mpi_request->TaskMID = cpu_to_le16(smid_task); - int_to_scsilun(lun, (struct scsi_lun *)mpi_request->LUN); - mpt2sas_scsih_set_tm_flag(ioc, handle); - init_completion(&ioc->tm_cmds.done); - mpt2sas_base_put_smid_hi_priority(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->tm_cmds.done, timeout*HZ); - if (!(ioc->tm_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SCSITaskManagementRequest_t)/4); - if (!(ioc->tm_cmds.status & MPT2_CMD_RESET)) { - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = (!rc) ? SUCCESS : FAILED; - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - mpt2sas_scsih_clear_tm_flag(ioc, handle); - goto err_out; - } - } - - if (ioc->tm_cmds.status & MPT2_CMD_REPLY_VALID) { - mpi_reply = ioc->tm_cmds.reply; - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "complete tm: " - "ioc_status(0x%04x), loginfo(0x%08x), term_count(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); - if (ioc->logging_level & MPT_DEBUG_TM) { - _scsih_response_code(ioc, mpi_reply->ResponseCode); - if (mpi_reply->IOCStatus) - _debug_dump_mf(mpi_request, - sizeof(Mpi2SCSITaskManagementRequest_t)/4); - } - } - - switch (type) { - case MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK: - rc = SUCCESS; - if (scsi_lookup->scmd == NULL) - break; - rc = FAILED; - break; - - case MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET: - if (_scsih_scsi_lookup_find_by_target(ioc, id, channel)) - rc = FAILED; - else - rc = SUCCESS; - break; - - case MPI2_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET: - case MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET: - if (_scsih_scsi_lookup_find_by_lun(ioc, id, lun, channel)) - rc = FAILED; - else - rc = SUCCESS; - break; - case MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK: - rc = SUCCESS; - break; - default: - rc = FAILED; - break; - } - - mpt2sas_scsih_clear_tm_flag(ioc, handle); - ioc->tm_cmds.status = MPT2_CMD_NOT_USED; - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); - - return rc; - - err_out: - if (m_type == TM_MUTEX_ON) - mutex_unlock(&ioc->tm_cmds.mutex); - return rc; -} - -/** - * _scsih_tm_display_info - displays info about the device - * @ioc: per adapter struct - * @scmd: pointer to scsi command object - * - * Called by task management callback handlers. - */ -static void -_scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) -{ - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *priv_target = starget->hostdata; - struct _sas_device *sas_device = NULL; - unsigned long flags; - char *device_str = NULL; - - if (!priv_target) - return; - if (ioc->hide_ir_msg) - device_str = "WarpDrive"; - else - device_str = "volume"; - - scsi_print_command(scmd); - if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - starget_printk(KERN_INFO, starget, "%s handle(0x%04x), " - "%s wwid(0x%016llx)\n", device_str, priv_target->handle, - device_str, (unsigned long long)priv_target->sas_address); - } else { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - priv_target->sas_address); - if (sas_device) { - if (priv_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - starget_printk(KERN_INFO, starget, - "volume handle(0x%04x), " - "volume wwid(0x%016llx)\n", - sas_device->volume_handle, - (unsigned long long)sas_device->volume_wwid); - } - starget_printk(KERN_INFO, starget, - "handle(0x%04x), sas_address(0x%016llx), phy(%d)\n", - sas_device->handle, - (unsigned long long)sas_device->sas_address, - sas_device->phy); - starget_printk(KERN_INFO, starget, - "enclosure_logical_id(0x%016llx), slot(%d)\n", - (unsigned long long)sas_device->enclosure_logical_id, - sas_device->slot); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } -} - -/** - * _scsih_abort - eh threads main abort routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_abort(struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - struct MPT2SAS_DEVICE *sas_device_priv_data; - u16 smid; - u16 handle; - int r; - - sdev_printk(KERN_INFO, scmd->device, "attempting task abort! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - sdev_printk(KERN_INFO, scmd->device, "device been deleted! " - "scmd(%p)\n", scmd); - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - r = SUCCESS; - goto out; - } - - /* search for the command */ - smid = _scsih_scsi_lookup_find_by_scmd(ioc, scmd); - if (!smid) { - scmd->result = DID_RESET << 16; - r = SUCCESS; - goto out; - } - - /* for hidden raid components and volumes this is not supported */ - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT || - sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_VOLUME) { - scmd->result = DID_RESET << 16; - r = FAILED; - goto out; - } - - mpt2sas_halt_firmware(ioc); - - handle = sas_device_priv_data->sas_target->handle; - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, - scmd->serial_number, TM_MUTEX_ON); - - out: - sdev_printk(KERN_INFO, scmd->device, "task abort: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - return r; -} - -/** - * _scsih_dev_reset - eh threads main device reset routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_dev_reset(struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device; - unsigned long flags; - u16 handle; - int r; - - struct scsi_target *starget = scmd->device->sdev_target; - - starget_printk(KERN_INFO, starget, "attempting device reset! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - starget_printk(KERN_INFO, starget, "device been deleted! " - "scmd(%p)\n", scmd); - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - r = SUCCESS; - goto out; - } - - /* for hidden raid components obtain the volume_handle */ - handle = 0; - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - sas_device_priv_data->sas_target->handle); - if (sas_device) - handle = sas_device->volume_handle; - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } else - handle = sas_device_priv_data->sas_target->handle; - - if (!handle) { - scmd->result = DID_RESET << 16; - r = FAILED; - goto out; - } - - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, scmd->device->lun, - MPI2_SCSITASKMGMT_TASKTYPE_LOGICAL_UNIT_RESET, 0, 30, 0, - TM_MUTEX_ON); - - out: - sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - return r; -} - -/** - * _scsih_target_reset - eh threads main target reset routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_target_reset(struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device; - unsigned long flags; - u16 handle; - int r; - struct scsi_target *starget = scmd->device->sdev_target; - - starget_printk(KERN_INFO, starget, "attempting target reset! " - "scmd(%p)\n", scmd); - _scsih_tm_display_info(ioc, scmd); - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - starget_printk(KERN_INFO, starget, "target been deleted! " - "scmd(%p)\n", scmd); - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - r = SUCCESS; - goto out; - } - - /* for hidden raid components obtain the volume_handle */ - handle = 0; - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - sas_device_priv_data->sas_target->handle); - if (sas_device) - handle = sas_device->volume_handle; - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } else - handle = sas_device_priv_data->sas_target->handle; - - if (!handle) { - scmd->result = DID_RESET << 16; - r = FAILED; - goto out; - } - - r = mpt2sas_scsih_issue_tm(ioc, handle, scmd->device->channel, - scmd->device->id, 0, MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET, 0, - 30, 0, TM_MUTEX_ON); - - out: - starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", - ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - return r; -} - -/** - * _scsih_host_reset - eh threads main host reset routine - * @scmd: pointer to scsi command object - * - * Returns SUCCESS if command aborted else FAILED - */ -static int -_scsih_host_reset(struct scsi_cmnd *scmd) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - int r, retval; - - printk(MPT2SAS_INFO_FMT "attempting host reset! scmd(%p)\n", - ioc->name, scmd); - scsi_print_command(scmd); - - retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - r = (retval < 0) ? FAILED : SUCCESS; - printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n", - ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); - - return r; -} - -/** - * _scsih_fw_event_add - insert and queue up fw_event - * @ioc: per adapter object - * @fw_event: object describing the event - * Context: This function will acquire ioc->fw_event_lock. - * - * This adds the firmware event object into link list, then queues it up to - * be processed from user context. - * - * Return nothing. - */ -static void -_scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) -{ - unsigned long flags; - - if (ioc->firmware_event_thread == NULL) - return; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - list_add_tail(&fw_event->list, &ioc->fw_event_list); - INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work); - queue_delayed_work(ioc->firmware_event_thread, - &fw_event->delayed_work, 0); - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/** - * _scsih_fw_event_free - delete fw_event - * @ioc: per adapter object - * @fw_event: object describing the event - * Context: This function will acquire ioc->fw_event_lock. - * - * This removes firmware event object from link list, frees associated memory. - * - * Return nothing. - */ -static void -_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work - *fw_event) -{ - unsigned long flags; - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - list_del(&fw_event->list); - kfree(fw_event->event_data); - kfree(fw_event); - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - - -/** - * _scsih_error_recovery_delete_devices - remove devices not responding - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - if (ioc->is_driver_loading) - return; - - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); - if (!fw_event) - return; - - fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); -} - -/** - * mpt2sas_port_enable_complete - port enable completed (fake event) - * @ioc: per adapter object - * - * Return nothing. - */ -void -mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event; - - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); - if (!fw_event) - return; - fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); -} - -/** - * _scsih_fw_event_cleanup_queue - cleanup event queue - * @ioc: per adapter object - * - * Walk the firmware event queue, either killing timers, or waiting - * for outstanding events to complete - * - * Return nothing. - */ -static void -_scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc) -{ - struct fw_event_work *fw_event, *next; - - if (list_empty(&ioc->fw_event_list) || - !ioc->firmware_event_thread || in_interrupt()) - return; - - list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { - if (cancel_delayed_work(&fw_event->delayed_work)) { - _scsih_fw_event_free(ioc, fw_event); - continue; - } - fw_event->cancel_pending_work = 1; - } -} - -/** - * _scsih_ublock_io_all_device - unblock every device - * @ioc: per adapter object - * - * change the device state from block to running - */ -static void -_scsih_ublock_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (!sas_device_priv_data->block) - continue; - sas_device_priv_data->block = 0; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_unblock(sdev); - } -} -/** - * _scsih_ublock_io_device - set the device state to SDEV_RUNNING - * @ioc: per adapter object - * @handle: device handle - * - * During device pull we need to appropiately set the sdev state. - */ -static void -_scsih_ublock_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (!sas_device_priv_data->block) - continue; - if (sas_device_priv_data->sas_target->handle == handle) { - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, - MPT2SAS_INFO_FMT "SDEV_RUNNING: " - "handle(0x%04x)\n", ioc->name, handle)); - sas_device_priv_data->block = 0; - scsi_internal_device_unblock(sdev); - } - } -} - -/** - * _scsih_block_io_all_device - set the device state to SDEV_BLOCK - * @ioc: per adapter object - * @handle: device handle - * - * During device pull we need to appropiately set the sdev state. - */ -static void -_scsih_block_io_all_device(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->block) - continue; - sas_device_priv_data->block = 1; - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_blocked, " - "handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle)); - scsi_internal_device_block(sdev); - } -} - - -/** - * _scsih_block_io_device - set the device state to SDEV_BLOCK - * @ioc: per adapter object - * @handle: device handle - * - * During device pull we need to appropiately set the sdev state. - */ -static void -_scsih_block_io_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data) - continue; - if (sas_device_priv_data->block) - continue; - if (sas_device_priv_data->sas_target->handle == handle) { - dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, - MPT2SAS_INFO_FMT "SDEV_BLOCK: " - "handle(0x%04x)\n", ioc->name, handle)); - sas_device_priv_data->block = 1; - scsi_internal_device_block(sdev); - } - } -} - -/** - * _scsih_block_io_to_children_attached_to_ex - * @ioc: per adapter object - * @sas_expander: the sas_device object - * - * This routine set sdev state to SDEV_BLOCK for all devices - * attached to this expander. This function called when expander is - * pulled. - */ -static void -_scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander) -{ - struct _sas_port *mpt2sas_port; - struct _sas_device *sas_device; - struct _sas_node *expander_sibling; - unsigned long flags; - - if (!sas_expander) - return; - - list_for_each_entry(mpt2sas_port, - &sas_expander->sas_port_list, port_list) { - if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = - mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - mpt2sas_port->remote_identify.sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - continue; - _scsih_block_io_device(ioc, sas_device->handle); - } - } - - list_for_each_entry(mpt2sas_port, - &sas_expander->sas_port_list, port_list) { - - if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) { - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - expander_sibling = - mpt2sas_scsih_expander_find_by_sas_address( - ioc, mpt2sas_port->remote_identify.sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - _scsih_block_io_to_children_attached_to_ex(ioc, - expander_sibling); - } - } -} - -/** - * _scsih_block_io_to_children_attached_directly - * @ioc: per adapter object - * @event_data: topology change event data - * - * This routine set sdev state to SDEV_BLOCK for all devices - * direct attached during device pull. - */ -static void -_scsih_block_io_to_children_attached_directly(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasTopologyChangeList_t *event_data) -{ - int i; - u16 handle; - u16 reason_code; - u8 phy_number; - - for (i = 0; i < event_data->NumEntries; i++) { - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - phy_number = event_data->StartPhyNum + i; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING) - _scsih_block_io_device(ioc, handle); - } -} - -/** - * _scsih_tm_tr_send - send task management request - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt time. - * - * This code is to initiate the device removal handshake protocol - * with controller firmware. This function will issue target reset - * using high priority request queue. It will send a sas iounit - * control request (MPI2_SAS_OP_REMOVE_DEVICE) from this completion. - * - * This is designed to send muliple task management request at the same - * time to the fifo. If the fifo is full, we will append the request, - * and process it in a future completion. - */ -static void -_scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - u16 smid; - struct _sas_device *sas_device; - struct MPT2SAS_TARGET *sas_target_priv_data = NULL; - u64 sas_address = 0; - unsigned long flags; - struct _tr_list *delayed_tr; - u32 ioc_state; - - if (ioc->remove_host) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " - "removed: handle(0x%04x)\n", __func__, ioc->name, handle)); - return; - } else if (ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " - "error recovery: handle(0x%04x)\n", __func__, ioc->name, - handle)); - return; - } - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " - "operational: handle(0x%04x)\n", __func__, ioc->name, - handle)); - return; - } - - /* if PD, then return */ - if (test_bit(handle, ioc->pd_handles)) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (sas_device && sas_device->starget && - sas_device->starget->hostdata) { - sas_target_priv_data = sas_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - sas_address = sas_device->sas_address; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_target_priv_data) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "setting delete flag: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle, - (unsigned long long)sas_address)); - _scsih_ublock_io_device(ioc, handle); - sas_target_priv_data->handle = MPT2SAS_INVALID_DEVICE_HANDLE; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_cb_idx); - if (!smid) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - if (!delayed_tr) - return; - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", - ioc->name, handle)); - return; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, - ioc->tm_tr_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - mpi_request->DevHandle = cpu_to_le16(handle); - mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - mpt2sas_base_put_smid_hi_priority(ioc, smid); -} - - - -/** - * _scsih_sas_control_complete - completion routine - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * This is the sas iounit control completion routine. - * This code is part of the code to initiate the device removal - * handshake protocol with controller firmware. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_sas_control_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, u32 reply) -{ -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - Mpi2SasIoUnitControlReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); -#endif - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "sc_complete:handle(0x%04x), (open) " - "smid(%d), ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->DevHandle), smid, - le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo))); - return 1; -} - -/** - * _scsih_tm_tr_volume_send - send target reset request for volumes - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt time. - * - * This is designed to send muliple task management request at the same - * time to the fifo. If the fifo is full, we will append the request, - * and process it in a future completion. - */ -static void -_scsih_tm_tr_volume_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SCSITaskManagementRequest_t *mpi_request; - u16 smid; - struct _tr_list *delayed_tr; - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " - "progress!\n", __func__, ioc->name)); - return; - } - - smid = mpt2sas_base_get_smid_hpr(ioc, ioc->tm_tr_volume_cb_idx); - if (!smid) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - if (!delayed_tr) - return; - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_volume_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", - ioc->name, handle)); - return; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid, - ioc->tm_tr_volume_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSITaskManagementRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SCSI_TASK_MGMT; - mpi_request->DevHandle = cpu_to_le16(handle); - mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; - mpt2sas_base_put_smid_hi_priority(ioc, smid); -} - -/** - * _scsih_tm_volume_tr_complete - target reset completion - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_volume_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, - u8 msix_index, u32 reply) -{ - u16 handle; - Mpi2SCSITaskManagementRequest_t *mpi_request_tm; - Mpi2SCSITaskManagementReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); - - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host reset in " - "progress!\n", __func__, ioc->name)); - return 1; - } - - mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); - handle = le16_to_cpu(mpi_request_tm->DevHandle); - if (handle != le16_to_cpu(mpi_reply->DevHandle)) { - dewtprintk(ioc, printk("spurious interrupt: " - "handle(0x%04x:0x%04x), smid(%d)!!!\n", handle, - le16_to_cpu(mpi_reply->DevHandle), smid)); - return 0; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", ioc->name, - handle, smid, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); - - return _scsih_check_for_pending_tm(ioc, smid); -} - -/** - * _scsih_tm_tr_complete - - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt time. - * - * This is the target reset completion routine. - * This code is part of the code to initiate the device removal - * handshake protocol with controller firmware. - * It will send a sas iounit control request (MPI2_SAS_OP_REMOVE_DEVICE) - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_tm_tr_complete(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - u16 handle; - Mpi2SCSITaskManagementRequest_t *mpi_request_tm; - Mpi2SCSITaskManagementReply_t *mpi_reply = - mpt2sas_base_get_reply_virt_addr(ioc, reply); - Mpi2SasIoUnitControlRequest_t *mpi_request; - u16 smid_sas_ctrl; - u32 ioc_state; - - if (ioc->remove_host) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host has been " - "removed\n", __func__, ioc->name)); - return 1; - } else if (ioc->pci_error_recovery) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host in pci " - "error recovery\n", __func__, ioc->name)); - return 1; - } - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - if (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: host is not " - "operational\n", __func__, ioc->name)); - return 1; - } - - mpi_request_tm = mpt2sas_base_get_msg_frame(ioc, smid); - handle = le16_to_cpu(mpi_request_tm->DevHandle); - if (handle != le16_to_cpu(mpi_reply->DevHandle)) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "spurious interrupt: " - "handle(0x%04x:0x%04x), smid(%d)!!!\n", ioc->name, handle, - le16_to_cpu(mpi_reply->DevHandle), smid)); - return 0; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "tr_complete:handle(0x%04x), (open) smid(%d), ioc_status(0x%04x), " - "loginfo(0x%08x), completed(%d)\n", ioc->name, - handle, smid, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo), - le32_to_cpu(mpi_reply->TerminationCount))); - - smid_sas_ctrl = mpt2sas_base_get_smid(ioc, ioc->tm_sas_control_cb_idx); - if (!smid_sas_ctrl) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - return 1; - } - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "sc_send:handle(0x%04x), " - "(open), smid(%d), cb(%d)\n", ioc->name, handle, smid_sas_ctrl, - ioc->tm_sas_control_cb_idx)); - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid_sas_ctrl); - memset(mpi_request, 0, sizeof(Mpi2SasIoUnitControlRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; - mpi_request->Operation = MPI2_SAS_OP_REMOVE_DEVICE; - mpi_request->DevHandle = mpi_request_tm->DevHandle; - mpt2sas_base_put_smid_default(ioc, smid_sas_ctrl); - - return _scsih_check_for_pending_tm(ioc, smid); -} - -/** - * _scsih_check_for_pending_tm - check for pending task management - * @ioc: per adapter object - * @smid: system request message index - * - * This will check delayed target reset list, and feed the - * next reqeust. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_check_for_pending_tm(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - struct _tr_list *delayed_tr; - - if (!list_empty(&ioc->delayed_tr_volume_list)) { - delayed_tr = list_entry(ioc->delayed_tr_volume_list.next, - struct _tr_list, list); - mpt2sas_base_free_smid(ioc, smid); - _scsih_tm_tr_volume_send(ioc, delayed_tr->handle); - list_del(&delayed_tr->list); - kfree(delayed_tr); - return 0; - } - - if (!list_empty(&ioc->delayed_tr_list)) { - delayed_tr = list_entry(ioc->delayed_tr_list.next, - struct _tr_list, list); - mpt2sas_base_free_smid(ioc, smid); - _scsih_tm_tr_send(ioc, delayed_tr->handle); - list_del(&delayed_tr->list); - kfree(delayed_tr); - return 0; - } - - return 1; -} - -/** - * _scsih_check_topo_delete_events - sanity check on topo events - * @ioc: per adapter object - * @event_data: the event data payload - * - * This routine added to better handle cable breaker. - * - * This handles the case where driver receives multiple expander - * add and delete events in a single shot. When there is a delete event - * the routine will void any pending add events waiting in the event queue. - * - * Return nothing. - */ -static void -_scsih_check_topo_delete_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasTopologyChangeList_t *event_data) -{ - struct fw_event_work *fw_event; - Mpi2EventDataSasTopologyChangeList_t *local_event_data; - u16 expander_handle; - struct _sas_node *sas_expander; - unsigned long flags; - int i, reason_code; - u16 handle; - - for (i = 0 ; i < event_data->NumEntries; i++) { - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - if (reason_code == MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING) - _scsih_tm_tr_send(ioc, handle); - } - - expander_handle = le16_to_cpu(event_data->ExpanderDevHandle); - if (expander_handle < ioc->sas_hba.num_phys) { - _scsih_block_io_to_children_attached_directly(ioc, event_data); - return; - } - - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING - || event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) { - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, - expander_handle); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - _scsih_block_io_to_children_attached_to_ex(ioc, sas_expander); - } else if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_RESPONDING) - _scsih_block_io_to_children_attached_directly(ioc, event_data); - - if (event_data->ExpStatus != MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING) - return; - - /* mark ignore flag for pending events */ - spin_lock_irqsave(&ioc->fw_event_lock, flags); - list_for_each_entry(fw_event, &ioc->fw_event_list, list) { - if (fw_event->event != MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST || - fw_event->ignore) - continue; - local_event_data = fw_event->event_data; - if (local_event_data->ExpStatus == - MPI2_EVENT_SAS_TOPO_ES_ADDED || - local_event_data->ExpStatus == - MPI2_EVENT_SAS_TOPO_ES_RESPONDING) { - if (le16_to_cpu(local_event_data->ExpanderDevHandle) == - expander_handle) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "setting ignoring flag\n", ioc->name)); - fw_event->ignore = 1; - } - } - } - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); -} - -/** - * _scsih_set_volume_delete_flag - setting volume delete flag - * @ioc: per adapter object - * @handle: device handle - * - * This - * Return nothing. - */ -static void -_scsih_set_volume_delete_flag(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _raid_device *raid_device; - struct MPT2SAS_TARGET *sas_target_priv_data; - unsigned long flags; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - if (raid_device && raid_device->starget && - raid_device->starget->hostdata) { - sas_target_priv_data = - raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "setting delete flag: handle(0x%04x), " - "wwid(0x%016llx)\n", ioc->name, handle, - (unsigned long long) raid_device->wwid)); - } - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * _scsih_set_volume_handle_for_tr - set handle for target reset to volume - * @handle: input handle - * @a: handle for volume a - * @b: handle for volume b - * - * IR firmware only supports two raid volumes. The purpose of this - * routine is to set the volume handle in either a or b. When the given - * input handle is non-zero, or when a and b have not been set before. - */ -static void -_scsih_set_volume_handle_for_tr(u16 handle, u16 *a, u16 *b) -{ - if (!handle || handle == *a || handle == *b) - return; - if (!*a) - *a = handle; - else if (!*b) - *b = handle; -} - -/** - * _scsih_check_ir_config_unhide_events - check for UNHIDE events - * @ioc: per adapter object - * @event_data: the event data payload - * Context: interrupt time. - * - * This routine will send target reset to volume, followed by target - * resets to the PDs. This is called when a PD has been removed, or - * volume has been deleted or removed. When the target reset is sent - * to volume, the PD target resets need to be queued to start upon - * completion of the volume target reset. - * - * Return nothing. - */ -static void -_scsih_check_ir_config_unhide_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrConfigChangeList_t *event_data) -{ - Mpi2EventIrConfigElement_t *element; - int i; - u16 handle, volume_handle, a, b; - struct _tr_list *delayed_tr; - - a = 0; - b = 0; - - if (ioc->is_warpdrive) - return; - - /* Volume Resets for Deleted or Removed */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (element->ReasonCode == - MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED || - element->ReasonCode == - MPI2_EVENT_IR_CHANGE_RC_REMOVED) { - volume_handle = le16_to_cpu(element->VolDevHandle); - _scsih_set_volume_delete_flag(ioc, volume_handle); - _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); - } - } - - /* Volume Resets for UNHIDE events */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) - continue; - if (element->ReasonCode == MPI2_EVENT_IR_CHANGE_RC_UNHIDE) { - volume_handle = le16_to_cpu(element->VolDevHandle); - _scsih_set_volume_handle_for_tr(volume_handle, &a, &b); - } - } - - if (a) - _scsih_tm_tr_volume_send(ioc, a); - if (b) - _scsih_tm_tr_volume_send(ioc, b); - - /* PD target resets */ - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - if (element->ReasonCode != MPI2_EVENT_IR_CHANGE_RC_UNHIDE) - continue; - handle = le16_to_cpu(element->PhysDiskDevHandle); - volume_handle = le16_to_cpu(element->VolDevHandle); - clear_bit(handle, ioc->pd_handles); - if (!volume_handle) - _scsih_tm_tr_send(ioc, handle); - else if (volume_handle == a || volume_handle == b) { - delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); - BUG_ON(!delayed_tr); - INIT_LIST_HEAD(&delayed_tr->list); - delayed_tr->handle = handle; - list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, - handle)); - } else - _scsih_tm_tr_send(ioc, handle); - } -} - - -/** - * _scsih_check_volume_delete_events - set delete flag for volumes - * @ioc: per adapter object - * @event_data: the event data payload - * Context: interrupt time. - * - * This will handle the case when the cable connected to entire volume is - * pulled. We will take care of setting the deleted flag so normal IO will - * not be sent. - * - * Return nothing. - */ -static void -_scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrVolume_t *event_data) -{ - u32 state; - - if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) - return; - state = le32_to_cpu(event_data->NewValue); - if (state == MPI2_RAID_VOL_STATE_MISSING || state == - MPI2_RAID_VOL_STATE_FAILED) - _scsih_set_volume_delete_flag(ioc, - le16_to_cpu(event_data->VolDevHandle)); -} - -/** - * _scsih_flush_running_cmds - completing outstanding commands. - * @ioc: per adapter object - * - * The flushing out of all pending scmd commands following host reset, - * where all IO is dropped to the floor. - * - * Return nothing. - */ -static void -_scsih_flush_running_cmds(struct MPT2SAS_ADAPTER *ioc) -{ - struct scsi_cmnd *scmd; - u16 smid; - u16 count = 0; - - for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - scmd = _scsih_scsi_lookup_get_clear(ioc, smid); - if (!scmd) - continue; - count++; - mpt2sas_base_free_smid(ioc, smid); - scsi_dma_unmap(scmd); - if (ioc->pci_error_recovery) - scmd->result = DID_NO_CONNECT << 16; - else - scmd->result = DID_RESET << 16; - scmd->scsi_done(scmd); - } - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "completing %d cmds\n", - ioc->name, count)); -} - -/** - * _scsih_setup_eedp - setup MPI request for EEDP transfer - * @scmd: pointer to scsi command object - * @mpi_request: pointer to the SCSI_IO reqest message frame - * - * Supporting protection 1 and 3. - * - * Returns nothing - */ -static void -_scsih_setup_eedp(struct scsi_cmnd *scmd, Mpi2SCSIIORequest_t *mpi_request) -{ - u16 eedp_flags; - unsigned char prot_op = scsi_get_prot_op(scmd); - unsigned char prot_type = scsi_get_prot_type(scmd); - - if (prot_type == SCSI_PROT_DIF_TYPE0 || prot_op == SCSI_PROT_NORMAL) - return; - - if (prot_op == SCSI_PROT_READ_STRIP) - eedp_flags = MPI2_SCSIIO_EEDPFLAGS_CHECK_REMOVE_OP; - else if (prot_op == SCSI_PROT_WRITE_INSERT) - eedp_flags = MPI2_SCSIIO_EEDPFLAGS_INSERT_OP; - else - return; - - switch (prot_type) { - case SCSI_PROT_DIF_TYPE1: - case SCSI_PROT_DIF_TYPE2: - - /* - * enable ref/guard checking - * auto increment ref tag - */ - eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | - MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - mpi_request->CDB.EEDP32.PrimaryReferenceTag = - cpu_to_be32(scsi_get_lba(scmd)); - break; - - case SCSI_PROT_DIF_TYPE3: - - /* - * enable guard checking - */ - eedp_flags |= MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD; - break; - } - mpi_request->EEDPBlockSize = cpu_to_le32(scmd->device->sector_size); - mpi_request->EEDPFlags = cpu_to_le16(eedp_flags); -} - -/** - * _scsih_eedp_error_handling - return sense code for EEDP errors - * @scmd: pointer to scsi command object - * @ioc_status: ioc status - * - * Returns nothing - */ -static void -_scsih_eedp_error_handling(struct scsi_cmnd *scmd, u16 ioc_status) -{ - u8 ascq; - u8 sk; - u8 host_byte; - - switch (ioc_status) { - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - ascq = 0x01; - break; - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - ascq = 0x02; - break; - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - ascq = 0x03; - break; - default: - ascq = 0x00; - break; - } - - if (scmd->sc_data_direction == DMA_TO_DEVICE) { - sk = ILLEGAL_REQUEST; - host_byte = DID_ABORT; - } else { - sk = ABORTED_COMMAND; - host_byte = DID_OK; - } - - scsi_build_sense_buffer(0, scmd->sense_buffer, sk, 0x10, ascq); - scmd->result = DRIVER_SENSE << 24 | (host_byte << 16) | - SAM_STAT_CHECK_CONDITION; -} - -/** - * _scsih_scsi_direct_io_get - returns direct io flag - * @ioc: per adapter object - * @smid: system request message index - * - * Returns the smid stored scmd pointer. - */ -static inline u8 -_scsih_scsi_direct_io_get(struct MPT2SAS_ADAPTER *ioc, u16 smid) -{ - return ioc->scsi_lookup[smid - 1].direct_io; -} - -/** - * _scsih_scsi_direct_io_set - sets direct io flag - * @ioc: per adapter object - * @smid: system request message index - * @direct_io: Zero or non-zero value to set in the direct_io flag - * - * Returns Nothing. - */ -static inline void -_scsih_scsi_direct_io_set(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 direct_io) -{ - ioc->scsi_lookup[smid - 1].direct_io = direct_io; -} - - -/** - * _scsih_setup_direct_io - setup MPI request for WARPDRIVE Direct I/O - * @ioc: per adapter object - * @scmd: pointer to scsi command object - * @raid_device: pointer to raid device data structure - * @mpi_request: pointer to the SCSI_IO reqest message frame - * @smid: system request message index - * - * Returns nothing - */ -static void -_scsih_setup_direct_io(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, - struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, - u16 smid) -{ - u32 v_lba, p_lba, stripe_off, stripe_unit, column, io_size; - u32 stripe_sz, stripe_exp; - u8 num_pds, *cdb_ptr, i; - u8 cdb0 = scmd->cmnd[0]; - u64 v_llba; - - /* - * Try Direct I/O to RAID memeber disks - */ - if (cdb0 == READ_16 || cdb0 == READ_10 || - cdb0 == WRITE_16 || cdb0 == WRITE_10) { - cdb_ptr = mpi_request->CDB.CDB32; - - if ((cdb0 < READ_16) || !(cdb_ptr[2] | cdb_ptr[3] | cdb_ptr[4] - | cdb_ptr[5])) { - io_size = scsi_bufflen(scmd) >> - raid_device->block_exponent; - i = (cdb0 < READ_16) ? 2 : 6; - /* get virtual lba */ - v_lba = be32_to_cpu(*(__be32 *)(&cdb_ptr[i])); - - if (((u64)v_lba + (u64)io_size - 1) <= - (u32)raid_device->max_lba) { - stripe_sz = raid_device->stripe_sz; - stripe_exp = raid_device->stripe_exponent; - stripe_off = v_lba & (stripe_sz - 1); - - /* Check whether IO falls within a stripe */ - if ((stripe_off + io_size) <= stripe_sz) { - num_pds = raid_device->num_pds; - p_lba = v_lba >> stripe_exp; - stripe_unit = p_lba / num_pds; - column = p_lba % num_pds; - p_lba = (stripe_unit << stripe_exp) + - stripe_off; - mpi_request->DevHandle = - cpu_to_le16(raid_device-> - pd_handle[column]); - (*(__be32 *)(&cdb_ptr[i])) = - cpu_to_be32(p_lba); - /* - * WD: To indicate this I/O is directI/O - */ - _scsih_scsi_direct_io_set(ioc, smid, 1); - } - } - } else { - io_size = scsi_bufflen(scmd) >> - raid_device->block_exponent; - /* get virtual lba */ - v_llba = be64_to_cpu(*(__be64 *)(&cdb_ptr[2])); - - if ((v_llba + (u64)io_size - 1) <= - raid_device->max_lba) { - stripe_sz = raid_device->stripe_sz; - stripe_exp = raid_device->stripe_exponent; - stripe_off = (u32) (v_llba & (stripe_sz - 1)); - - /* Check whether IO falls within a stripe */ - if ((stripe_off + io_size) <= stripe_sz) { - num_pds = raid_device->num_pds; - p_lba = (u32)(v_llba >> stripe_exp); - stripe_unit = p_lba / num_pds; - column = p_lba % num_pds; - p_lba = (stripe_unit << stripe_exp) + - stripe_off; - mpi_request->DevHandle = - cpu_to_le16(raid_device-> - pd_handle[column]); - (*(__be64 *)(&cdb_ptr[2])) = - cpu_to_be64((u64)p_lba); - /* - * WD: To indicate this I/O is directI/O - */ - _scsih_scsi_direct_io_set(ioc, smid, 1); - } - } - } - } -} - -/** - * _scsih_qcmd - main scsi request entry point - * @scmd: pointer to scsi command object - * @done: function pointer to be invoked on completion - * - * The callback index is set inside `ioc->scsi_io_cb_idx`. - * - * Returns 0 on success. If there's a failure, return either: - * SCSI_MLQUEUE_DEVICE_BUSY if the device queue is full, or - * SCSI_MLQUEUE_HOST_BUSY if the entire host queue is full - */ -static int -_scsih_qcmd_lck(struct scsi_cmnd *scmd, void (*done)(struct scsi_cmnd *)) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct _raid_device *raid_device; - Mpi2SCSIIORequest_t *mpi_request; - u32 mpi_control; - u16 smid; - - scmd->scsi_done = done; - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - if (ioc->pci_error_recovery || ioc->remove_host) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - sas_target_priv_data = sas_device_priv_data->sas_target; - /* invalid device handle */ - if (sas_target_priv_data->handle == MPT2SAS_INVALID_DEVICE_HANDLE) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - /* host recovery or link resets sent via IOCTLs */ - if (ioc->shost_recovery || ioc->ioc_link_reset_in_progress) - return SCSI_MLQUEUE_HOST_BUSY; - /* device busy with task management */ - else if (sas_device_priv_data->block || sas_target_priv_data->tm_busy) - return SCSI_MLQUEUE_DEVICE_BUSY; - /* device has been deleted */ - else if (sas_target_priv_data->deleted) { - scmd->result = DID_NO_CONNECT << 16; - scmd->scsi_done(scmd); - return 0; - } - - if (scmd->sc_data_direction == DMA_FROM_DEVICE) - mpi_control = MPI2_SCSIIO_CONTROL_READ; - else if (scmd->sc_data_direction == DMA_TO_DEVICE) - mpi_control = MPI2_SCSIIO_CONTROL_WRITE; - else - mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER; - - /* set tags */ - if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) { - if (scmd->device->tagged_supported) { - if (scmd->device->ordered_tags) - mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ; - else - mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - } else -/* MPI Revision I (UNIT = 0xA) - removed MPI2_SCSIIO_CONTROL_UNTAGGED */ -/* mpi_control |= MPI2_SCSIIO_CONTROL_UNTAGGED; - */ - mpi_control |= (0x500); - - } else - mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - /* Make sure Device is not raid volume. - * We do not expose raid functionality to upper layer for warpdrive. - */ - if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && - sas_is_tlr_enabled(scmd->device) && scmd->cmd_len != 32) - mpi_control |= MPI2_SCSIIO_CONTROL_TLR_ON; - - smid = mpt2sas_base_get_smid_scsiio(ioc, ioc->scsi_io_cb_idx, scmd); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - goto out; - } - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - memset(mpi_request, 0, sizeof(Mpi2SCSIIORequest_t)); - _scsih_setup_eedp(scmd, mpi_request); - if (scmd->cmd_len == 32) - mpi_control |= 4 << MPI2_SCSIIO_CONTROL_ADDCDBLEN_SHIFT; - mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) - mpi_request->Function = MPI2_FUNCTION_RAID_SCSI_IO_PASSTHROUGH; - else - mpi_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; - mpi_request->DevHandle = - cpu_to_le16(sas_device_priv_data->sas_target->handle); - mpi_request->DataLength = cpu_to_le32(scsi_bufflen(scmd)); - mpi_request->Control = cpu_to_le32(mpi_control); - mpi_request->IoFlags = cpu_to_le16(scmd->cmd_len); - mpi_request->MsgFlags = MPI2_SCSIIO_MSGFLAGS_SYSTEM_SENSE_ADDR; - mpi_request->SenseBufferLength = SCSI_SENSE_BUFFERSIZE; - mpi_request->SenseBufferLowAddress = - mpt2sas_base_get_sense_buffer_dma(ioc, smid); - mpi_request->SGLOffset0 = offsetof(Mpi2SCSIIORequest_t, SGL) / 4; - mpi_request->SGLFlags = cpu_to_le16(MPI2_SCSIIO_SGLFLAGS_TYPE_MPI + - MPI2_SCSIIO_SGLFLAGS_SYSTEM_ADDR); - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - int_to_scsilun(sas_device_priv_data->lun, (struct scsi_lun *) - mpi_request->LUN); - memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); - - if (!mpi_request->DataLength) { - mpt2sas_base_build_zero_len_sge(ioc, &mpi_request->SGL); - } else { - if (_scsih_build_scatter_gather(ioc, scmd, smid)) { - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - } - - raid_device = sas_target_priv_data->raid_device; - if (raid_device && raid_device->direct_io_enabled) - _scsih_setup_direct_io(ioc, scmd, raid_device, mpi_request, - smid); - - if (likely(mpi_request->Function == MPI2_FUNCTION_SCSI_IO_REQUEST)) - mpt2sas_base_put_smid_scsi_io(ioc, smid, - le16_to_cpu(mpi_request->DevHandle)); - else - mpt2sas_base_put_smid_default(ioc, smid); - return 0; - - out: - return SCSI_MLQUEUE_HOST_BUSY; -} - -static DEF_SCSI_QCMD(_scsih_qcmd) - -/** - * _scsih_normalize_sense - normalize descriptor and fixed format sense data - * @sense_buffer: sense data returned by target - * @data: normalized skey/asc/ascq - * - * Return nothing. - */ -static void -_scsih_normalize_sense(char *sense_buffer, struct sense_info *data) -{ - if ((sense_buffer[0] & 0x7F) >= 0x72) { - /* descriptor format */ - data->skey = sense_buffer[1] & 0x0F; - data->asc = sense_buffer[2]; - data->ascq = sense_buffer[3]; - } else { - /* fixed format */ - data->skey = sense_buffer[2] & 0x0F; - data->asc = sense_buffer[12]; - data->ascq = sense_buffer[13]; - } -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_scsi_ioc_info - translated non-successful SCSI_IO request - * @ioc: per adapter object - * @scmd: pointer to scsi command object - * @mpi_reply: reply mf payload returned from firmware - * - * scsi_status - SCSI Status code returned from target device - * scsi_state - state info associated with SCSI_IO determined by ioc - * ioc_status - ioc supplied status info - * - * Return nothing. - */ -static void -_scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, - Mpi2SCSIIOReply_t *mpi_reply, u16 smid) -{ - u32 response_info; - u8 *response_bytes; - u16 ioc_status = le16_to_cpu(mpi_reply->IOCStatus) & - MPI2_IOCSTATUS_MASK; - u8 scsi_state = mpi_reply->SCSIState; - u8 scsi_status = mpi_reply->SCSIStatus; - char *desc_ioc_state = NULL; - char *desc_scsi_status = NULL; - char *desc_scsi_state = ioc->tmp_string; - u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); - struct _sas_device *sas_device = NULL; - unsigned long flags; - struct scsi_target *starget = scmd->device->sdev_target; - struct MPT2SAS_TARGET *priv_target = starget->hostdata; - char *device_str = NULL; - - if (!priv_target) - return; - - if (ioc->hide_ir_msg) - device_str = "WarpDrive"; - else - device_str = "volume"; - - if (log_info == 0x31170000) - return; - - switch (ioc_status) { - case MPI2_IOCSTATUS_SUCCESS: - desc_ioc_state = "success"; - break; - case MPI2_IOCSTATUS_INVALID_FUNCTION: - desc_ioc_state = "invalid function"; - break; - case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: - desc_ioc_state = "scsi recovered error"; - break; - case MPI2_IOCSTATUS_SCSI_INVALID_DEVHANDLE: - desc_ioc_state = "scsi invalid dev handle"; - break; - case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: - desc_ioc_state = "scsi device not there"; - break; - case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: - desc_ioc_state = "scsi data overrun"; - break; - case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: - desc_ioc_state = "scsi data underrun"; - break; - case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: - desc_ioc_state = "scsi io data error"; - break; - case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: - desc_ioc_state = "scsi protocol error"; - break; - case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: - desc_ioc_state = "scsi task terminated"; - break; - case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: - desc_ioc_state = "scsi residual mismatch"; - break; - case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: - desc_ioc_state = "scsi task mgmt failed"; - break; - case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: - desc_ioc_state = "scsi ioc terminated"; - break; - case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: - desc_ioc_state = "scsi ext terminated"; - break; - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - desc_ioc_state = "eedp guard error"; - break; - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - desc_ioc_state = "eedp ref tag error"; - break; - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - desc_ioc_state = "eedp app tag error"; - break; - default: - desc_ioc_state = "unknown"; - break; - } - - switch (scsi_status) { - case MPI2_SCSI_STATUS_GOOD: - desc_scsi_status = "good"; - break; - case MPI2_SCSI_STATUS_CHECK_CONDITION: - desc_scsi_status = "check condition"; - break; - case MPI2_SCSI_STATUS_CONDITION_MET: - desc_scsi_status = "condition met"; - break; - case MPI2_SCSI_STATUS_BUSY: - desc_scsi_status = "busy"; - break; - case MPI2_SCSI_STATUS_INTERMEDIATE: - desc_scsi_status = "intermediate"; - break; - case MPI2_SCSI_STATUS_INTERMEDIATE_CONDMET: - desc_scsi_status = "intermediate condmet"; - break; - case MPI2_SCSI_STATUS_RESERVATION_CONFLICT: - desc_scsi_status = "reservation conflict"; - break; - case MPI2_SCSI_STATUS_COMMAND_TERMINATED: - desc_scsi_status = "command terminated"; - break; - case MPI2_SCSI_STATUS_TASK_SET_FULL: - desc_scsi_status = "task set full"; - break; - case MPI2_SCSI_STATUS_ACA_ACTIVE: - desc_scsi_status = "aca active"; - break; - case MPI2_SCSI_STATUS_TASK_ABORTED: - desc_scsi_status = "task aborted"; - break; - default: - desc_scsi_status = "unknown"; - break; - } - - desc_scsi_state[0] = '\0'; - if (!scsi_state) - desc_scsi_state = " "; - if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) - strcat(desc_scsi_state, "response info "); - if (scsi_state & MPI2_SCSI_STATE_TERMINATED) - strcat(desc_scsi_state, "state terminated "); - if (scsi_state & MPI2_SCSI_STATE_NO_SCSI_STATUS) - strcat(desc_scsi_state, "no status "); - if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_FAILED) - strcat(desc_scsi_state, "autosense failed "); - if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) - strcat(desc_scsi_state, "autosense valid "); - - scsi_print_command(scmd); - - if (priv_target->flags & MPT_TARGET_FLAGS_VOLUME) { - printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name, - device_str, (unsigned long long)priv_target->sas_address); - } else { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - priv_target->sas_address); - if (sas_device) { - printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " - "phy(%d)\n", ioc->name, sas_device->sas_address, - sas_device->phy); - printk(MPT2SAS_WARN_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, sas_device->enclosure_logical_id, - sas_device->slot); - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } - - printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), " - "smid(%d)\n", ioc->name, le16_to_cpu(mpi_reply->DevHandle), - desc_ioc_state, ioc_status, smid); - printk(MPT2SAS_WARN_FMT "\trequest_len(%d), underflow(%d), " - "resid(%d)\n", ioc->name, scsi_bufflen(scmd), scmd->underflow, - scsi_get_resid(scmd)); - printk(MPT2SAS_WARN_FMT "\ttag(%d), transfer_count(%d), " - "sc->result(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply->TaskTag), - le32_to_cpu(mpi_reply->TransferCount), scmd->result); - printk(MPT2SAS_WARN_FMT "\tscsi_status(%s)(0x%02x), " - "scsi_state(%s)(0x%02x)\n", ioc->name, desc_scsi_status, - scsi_status, desc_scsi_state, scsi_state); - - if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { - struct sense_info data; - _scsih_normalize_sense(scmd->sense_buffer, &data); - printk(MPT2SAS_WARN_FMT "\t[sense_key,asc,ascq]: " - "[0x%02x,0x%02x,0x%02x], count(%d)\n", ioc->name, data.skey, - data.asc, data.ascq, le32_to_cpu(mpi_reply->SenseCount)); - } - - if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { - response_info = le32_to_cpu(mpi_reply->ResponseInfo); - response_bytes = (u8 *)&response_info; - _scsih_response_code(ioc, response_bytes[0]); - } -} -#endif - -/** - * _scsih_turn_on_fault_led - illuminate Fault LED - * @ioc: per adapter object - * @handle: device handle - * Context: process - * - * Return nothing. - */ -static void -_scsih_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2SepReply_t mpi_reply; - Mpi2SepRequest_t mpi_request; - - memset(&mpi_request, 0, sizeof(Mpi2SepRequest_t)); - mpi_request.Function = MPI2_FUNCTION_SCSI_ENCLOSURE_PROCESSOR; - mpi_request.Action = MPI2_SEP_REQ_ACTION_WRITE_STATUS; - mpi_request.SlotStatus = - cpu_to_le32(MPI2_SEP_REQ_SLOTSTATUS_PREDICTED_FAULT); - mpi_request.DevHandle = cpu_to_le16(handle); - mpi_request.Flags = MPI2_SEP_REQ_FLAGS_DEVHANDLE_ADDRESS; - if ((mpt2sas_base_scsi_enclosure_processor(ioc, &mpi_reply, - &mpi_request)) != 0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - return; - } - - if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "enclosure_processor: " - "ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name, - le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo))); - return; - } -} - -/** - * _scsih_send_event_to_turn_on_fault_led - fire delayed event - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt. - * - * Return nothing. - */ -static void -_scsih_send_event_to_turn_on_fault_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct fw_event_work *fw_event; - - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); - if (!fw_event) - return; - fw_event->event = MPT2SAS_TURN_ON_FAULT_LED; - fw_event->device_handle = handle; - fw_event->ioc = ioc; - _scsih_fw_event_add(ioc, fw_event); -} - -/** - * _scsih_smart_predicted_fault - process smart errors - * @ioc: per adapter object - * @handle: device handle - * Context: interrupt. - * - * Return nothing. - */ -static void -_scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct scsi_target *starget; - struct MPT2SAS_TARGET *sas_target_priv_data; - Mpi2EventNotificationReply_t *event_reply; - Mpi2EventDataSasDeviceStatusChange_t *event_data; - struct _sas_device *sas_device; - ssize_t sz; - unsigned long flags; - - /* only handle non-raid devices */ - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - - if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) || - ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } - starget_printk(KERN_WARNING, starget, "predicted fault\n"); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) - _scsih_send_event_to_turn_on_fault_led(ioc, handle); - - /* insert into event log */ - sz = offsetof(Mpi2EventNotificationReply_t, EventData) + - sizeof(Mpi2EventDataSasDeviceStatusChange_t); - event_reply = kzalloc(sz, GFP_ATOMIC); - if (!event_reply) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; - event_reply->Event = - cpu_to_le16(MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE); - event_reply->MsgLength = sz/4; - event_reply->EventDataLength = - cpu_to_le16(sizeof(Mpi2EventDataSasDeviceStatusChange_t)/4); - event_data = (Mpi2EventDataSasDeviceStatusChange_t *) - event_reply->EventData; - event_data->ReasonCode = MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA; - event_data->ASC = 0x5D; - event_data->DevHandle = cpu_to_le16(handle); - event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); - mpt2sas_ctl_add_to_event_log(ioc, event_reply); - kfree(event_reply); -} - -/** - * _scsih_io_done - scsi request callback - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Callback handler when using _scsih_qcmd. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -{ - Mpi2SCSIIORequest_t *mpi_request; - Mpi2SCSIIOReply_t *mpi_reply; - struct scsi_cmnd *scmd; - u16 ioc_status; - u32 xfer_cnt; - u8 scsi_state; - u8 scsi_status; - u32 log_info; - struct MPT2SAS_DEVICE *sas_device_priv_data; - u32 response_code = 0; - unsigned long flags; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - scmd = _scsih_scsi_lookup_get_clear(ioc, smid); - if (scmd == NULL) - return 1; - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - - if (mpi_reply == NULL) { - scmd->result = DID_OK << 16; - goto out; - } - - sas_device_priv_data = scmd->device->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target || - sas_device_priv_data->sas_target->deleted) { - scmd->result = DID_NO_CONNECT << 16; - goto out; - } - ioc_status = le16_to_cpu(mpi_reply->IOCStatus); - /* - * WARPDRIVE: If direct_io is set then it is directIO, - * the failed direct I/O should be redirected to volume - */ - if (_scsih_scsi_direct_io_get(ioc, smid) && - ((ioc_status & MPI2_IOCSTATUS_MASK) - != MPI2_IOCSTATUS_SCSI_TASK_TERMINATED)) { - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - ioc->scsi_lookup[smid - 1].scmd = scmd; - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - _scsih_scsi_direct_io_set(ioc, smid, 0); - memcpy(mpi_request->CDB.CDB32, scmd->cmnd, scmd->cmd_len); - mpi_request->DevHandle = - cpu_to_le16(sas_device_priv_data->sas_target->handle); - mpt2sas_base_put_smid_scsi_io(ioc, smid, - sas_device_priv_data->sas_target->handle); - return 0; - } - - - /* turning off TLR */ - scsi_state = mpi_reply->SCSIState; - if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) - response_code = - le32_to_cpu(mpi_reply->ResponseInfo) & 0xFF; - if (!sas_device_priv_data->tlr_snoop_check) { - sas_device_priv_data->tlr_snoop_check++; - /* Make sure Device is not raid volume. - * We do not expose raid functionality to upper layer for warpdrive. - */ - if (!ioc->is_warpdrive && !_scsih_is_raid(&scmd->device->sdev_gendev) && - sas_is_tlr_enabled(scmd->device) && - response_code == MPI2_SCSITASKMGMT_RSP_INVALID_FRAME) { - sas_disable_tlr(scmd->device); - sdev_printk(KERN_INFO, scmd->device, "TLR disabled\n"); - } - } - - xfer_cnt = le32_to_cpu(mpi_reply->TransferCount); - scsi_set_resid(scmd, scsi_bufflen(scmd) - xfer_cnt); - if (ioc_status & MPI2_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) - log_info = le32_to_cpu(mpi_reply->IOCLogInfo); - else - log_info = 0; - ioc_status &= MPI2_IOCSTATUS_MASK; - scsi_status = mpi_reply->SCSIStatus; - - if (ioc_status == MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN && xfer_cnt == 0 && - (scsi_status == MPI2_SCSI_STATUS_BUSY || - scsi_status == MPI2_SCSI_STATUS_RESERVATION_CONFLICT || - scsi_status == MPI2_SCSI_STATUS_TASK_SET_FULL)) { - ioc_status = MPI2_IOCSTATUS_SUCCESS; - } - - if (scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID) { - struct sense_info data; - const void *sense_data = mpt2sas_base_get_sense_buffer(ioc, - smid); - u32 sz = min_t(u32, SCSI_SENSE_BUFFERSIZE, - le32_to_cpu(mpi_reply->SenseCount)); - memcpy(scmd->sense_buffer, sense_data, sz); - _scsih_normalize_sense(scmd->sense_buffer, &data); - /* failure prediction threshold exceeded */ - if (data.asc == 0x5D) - _scsih_smart_predicted_fault(ioc, - le16_to_cpu(mpi_reply->DevHandle)); - } - - switch (ioc_status) { - case MPI2_IOCSTATUS_BUSY: - case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: - scmd->result = SAM_STAT_BUSY; - break; - - case MPI2_IOCSTATUS_SCSI_DEVICE_NOT_THERE: - scmd->result = DID_NO_CONNECT << 16; - break; - - case MPI2_IOCSTATUS_SCSI_IOC_TERMINATED: - if (sas_device_priv_data->block) { - scmd->result = DID_TRANSPORT_DISRUPTED << 16; - goto out; - } - scmd->result = DID_SOFT_ERROR << 16; - break; - case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED: - case MPI2_IOCSTATUS_SCSI_EXT_TERMINATED: - scmd->result = DID_RESET << 16; - break; - - case MPI2_IOCSTATUS_SCSI_RESIDUAL_MISMATCH: - if ((xfer_cnt == 0) || (scmd->underflow > xfer_cnt)) - scmd->result = DID_SOFT_ERROR << 16; - else - scmd->result = (DID_OK << 16) | scsi_status; - break; - - case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: - scmd->result = (DID_OK << 16) | scsi_status; - - if ((scsi_state & MPI2_SCSI_STATE_AUTOSENSE_VALID)) - break; - - if (xfer_cnt < scmd->underflow) { - if (scsi_status == SAM_STAT_BUSY) - scmd->result = SAM_STAT_BUSY; - else - scmd->result = DID_SOFT_ERROR << 16; - } else if (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | - MPI2_SCSI_STATE_NO_SCSI_STATUS)) - scmd->result = DID_SOFT_ERROR << 16; - else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) - scmd->result = DID_RESET << 16; - else if (!xfer_cnt && scmd->cmnd[0] == REPORT_LUNS) { - mpi_reply->SCSIState = MPI2_SCSI_STATE_AUTOSENSE_VALID; - mpi_reply->SCSIStatus = SAM_STAT_CHECK_CONDITION; - scmd->result = (DRIVER_SENSE << 24) | - SAM_STAT_CHECK_CONDITION; - scmd->sense_buffer[0] = 0x70; - scmd->sense_buffer[2] = ILLEGAL_REQUEST; - scmd->sense_buffer[12] = 0x20; - scmd->sense_buffer[13] = 0; - } - break; - - case MPI2_IOCSTATUS_SCSI_DATA_OVERRUN: - scsi_set_resid(scmd, 0); - case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: - case MPI2_IOCSTATUS_SUCCESS: - scmd->result = (DID_OK << 16) | scsi_status; - if (response_code == - MPI2_SCSITASKMGMT_RSP_INVALID_FRAME || - (scsi_state & (MPI2_SCSI_STATE_AUTOSENSE_FAILED | - MPI2_SCSI_STATE_NO_SCSI_STATUS))) - scmd->result = DID_SOFT_ERROR << 16; - else if (scsi_state & MPI2_SCSI_STATE_TERMINATED) - scmd->result = DID_RESET << 16; - break; - - case MPI2_IOCSTATUS_EEDP_GUARD_ERROR: - case MPI2_IOCSTATUS_EEDP_REF_TAG_ERROR: - case MPI2_IOCSTATUS_EEDP_APP_TAG_ERROR: - _scsih_eedp_error_handling(scmd, ioc_status); - break; - case MPI2_IOCSTATUS_SCSI_PROTOCOL_ERROR: - case MPI2_IOCSTATUS_INVALID_FUNCTION: - case MPI2_IOCSTATUS_INVALID_SGL: - case MPI2_IOCSTATUS_INTERNAL_ERROR: - case MPI2_IOCSTATUS_INVALID_FIELD: - case MPI2_IOCSTATUS_INVALID_STATE: - case MPI2_IOCSTATUS_SCSI_IO_DATA_ERROR: - case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: - default: - scmd->result = DID_SOFT_ERROR << 16; - break; - - } - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (scmd->result && (ioc->logging_level & MPT_DEBUG_REPLY)) - _scsih_scsi_ioc_info(ioc , scmd, mpi_reply, smid); -#endif - - out: - scsi_dma_unmap(scmd); - scmd->scsi_done(scmd); - return 1; -} - -/** - * _scsih_sas_host_refresh - refreshing sas host object contents - * @ioc: per adapter object - * Context: user - * - * During port enable, fw will send topology events for every device. Its - * possible that the handles may change from the previous setting, so this - * code keeping handles updating if changed. - * - * Return nothing. - */ -static void -_scsih_sas_host_refresh(struct MPT2SAS_ADAPTER *ioc) -{ - u16 sz; - u16 ioc_status; - int i; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; - u16 attached_handle; - u8 link_rate; - - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT - "updating handles for sas_host(0x%016llx)\n", - ioc->name, (unsigned long long)ioc->sas_hba.sas_address)); - - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys - * sizeof(Mpi2SasIOUnit0PhyData_t)); - sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, - sas_iounit_pg0, sz)) != 0) - goto out; - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - goto out; - for (i = 0; i < ioc->sas_hba.num_phys ; i++) { - link_rate = sas_iounit_pg0->PhyData[i].NegotiatedLinkRate >> 4; - if (i == 0) - ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> - PhyData[0].ControllerDevHandle); - ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; - attached_handle = le16_to_cpu(sas_iounit_pg0->PhyData[i]. - AttachedDevHandle); - if (attached_handle && link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) - link_rate = MPI2_SAS_NEG_LINK_RATE_1_5; - mpt2sas_transport_update_links(ioc, ioc->sas_hba.sas_address, - attached_handle, i, link_rate); - } - out: - kfree(sas_iounit_pg0); -} - -/** - * _scsih_sas_host_add - create sas host object - * @ioc: per adapter object - * - * Creating host side data object, stored in ioc->sas_hba - * - * Return nothing. - */ -static void -_scsih_sas_host_add(struct MPT2SAS_ADAPTER *ioc) -{ - int i; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage0_t *sas_iounit_pg0 = NULL; - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2SasPhyPage0_t phy_pg0; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2SasEnclosurePage0_t enclosure_pg0; - u16 ioc_status; - u16 sz; - u16 device_missing_delay; - - mpt2sas_config_get_number_hba_phys(ioc, &ioc->sas_hba.num_phys); - if (!ioc->sas_hba.num_phys) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - /* sas_iounit page 0 */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit0PhyData_t)); - sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - if ((mpt2sas_config_get_sas_iounit_pg0(ioc, &mpi_reply, - sas_iounit_pg0, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg1) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - ioc->io_missing_delay = - le16_to_cpu(sas_iounit_pg1->IODeviceMissingDelay); - device_missing_delay = - le16_to_cpu(sas_iounit_pg1->ReportDeviceMissingDelay); - if (device_missing_delay & MPI2_SASIOUNIT1_REPORT_MISSING_UNIT_16) - ioc->device_missing_delay = (device_missing_delay & - MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16; - else - ioc->device_missing_delay = device_missing_delay & - MPI2_SASIOUNIT1_REPORT_MISSING_TIMEOUT_MASK; - - ioc->sas_hba.parent_dev = &ioc->shost->shost_gendev; - ioc->sas_hba.phy = kcalloc(ioc->sas_hba.num_phys, - sizeof(struct _sas_phy), GFP_KERNEL); - if (!ioc->sas_hba.phy) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - for (i = 0; i < ioc->sas_hba.num_phys ; i++) { - if ((mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, - i))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - - if (i == 0) - ioc->sas_hba.handle = le16_to_cpu(sas_iounit_pg0-> - PhyData[0].ControllerDevHandle); - ioc->sas_hba.phy[i].handle = ioc->sas_hba.handle; - ioc->sas_hba.phy[i].phy_id = i; - mpt2sas_transport_add_host_phy(ioc, &ioc->sas_hba.phy[i], - phy_pg0, ioc->sas_hba.parent_dev); - } - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, ioc->sas_hba.handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out; - } - ioc->sas_hba.enclosure_handle = - le16_to_cpu(sas_device_pg0.EnclosureHandle); - ioc->sas_hba.sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - printk(MPT2SAS_INFO_FMT "host_add: handle(0x%04x), " - "sas_addr(0x%016llx), phys(%d)\n", ioc->name, ioc->sas_hba.handle, - (unsigned long long) ioc->sas_hba.sas_address, - ioc->sas_hba.num_phys) ; - - if (ioc->sas_hba.enclosure_handle) { - if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, - &enclosure_pg0, - MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, - ioc->sas_hba.enclosure_handle))) { - ioc->sas_hba.enclosure_logical_id = - le64_to_cpu(enclosure_pg0.EnclosureLogicalID); - } - } - - out: - kfree(sas_iounit_pg1); - kfree(sas_iounit_pg0); -} - -/** - * _scsih_expander_add - creating expander object - * @ioc: per adapter object - * @handle: expander handle - * - * Creating expander object, stored in ioc->sas_expander_list. - * - * Return 0 for success, else error. - */ -static int -_scsih_expander_add(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _sas_node *sas_expander; - Mpi2ConfigReply_t mpi_reply; - Mpi2ExpanderPage0_t expander_pg0; - Mpi2ExpanderPage1_t expander_pg1; - Mpi2SasEnclosurePage0_t enclosure_pg0; - u32 ioc_status; - u16 parent_handle; - u64 sas_address, sas_address_parent = 0; - int i; - unsigned long flags; - struct _sas_port *mpt2sas_port = NULL; - int rc = 0; - - if (!handle) - return -1; - - if (ioc->shost_recovery || ioc->pci_error_recovery) - return -1; - - if ((mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, - MPI2_SAS_EXPAND_PGAD_FORM_HNDL, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - /* handle out of order topology events */ - parent_handle = le16_to_cpu(expander_pg0.ParentDevHandle); - if (_scsih_get_sas_address(ioc, parent_handle, &sas_address_parent) - != 0) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - if (sas_address_parent != ioc->sas_hba.sas_address) { - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address_parent); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!sas_expander) { - rc = _scsih_expander_add(ioc, parent_handle); - if (rc != 0) - return rc; - } - } - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_address = le64_to_cpu(expander_pg0.SASAddress); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (sas_expander) - return 0; - - sas_expander = kzalloc(sizeof(struct _sas_node), - GFP_KERNEL); - if (!sas_expander) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - sas_expander->handle = handle; - sas_expander->num_phys = expander_pg0.NumPhys; - sas_expander->sas_address_parent = sas_address_parent; - sas_expander->sas_address = sas_address; - - printk(MPT2SAS_INFO_FMT "expander_add: handle(0x%04x)," - " parent(0x%04x), sas_addr(0x%016llx), phys(%d)\n", ioc->name, - handle, parent_handle, (unsigned long long) - sas_expander->sas_address, sas_expander->num_phys); - - if (!sas_expander->num_phys) - goto out_fail; - sas_expander->phy = kcalloc(sas_expander->num_phys, - sizeof(struct _sas_phy), GFP_KERNEL); - if (!sas_expander->phy) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - - INIT_LIST_HEAD(&sas_expander->sas_port_list); - mpt2sas_port = mpt2sas_transport_port_add(ioc, handle, - sas_address_parent); - if (!mpt2sas_port) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - sas_expander->parent_dev = &mpt2sas_port->rphy->dev; - - for (i = 0 ; i < sas_expander->num_phys ; i++) { - if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, - &expander_pg1, i, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - sas_expander->phy[i].handle = handle; - sas_expander->phy[i].phy_id = i; - - if ((mpt2sas_transport_add_expander_phy(ioc, - &sas_expander->phy[i], expander_pg1, - sas_expander->parent_dev))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -1; - goto out_fail; - } - } - - if (sas_expander->enclosure_handle) { - if (!(mpt2sas_config_get_enclosure_pg0(ioc, &mpi_reply, - &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, - sas_expander->enclosure_handle))) { - sas_expander->enclosure_logical_id = - le64_to_cpu(enclosure_pg0.EnclosureLogicalID); - } - } - - _scsih_expander_node_add(ioc, sas_expander); - return 0; - - out_fail: - - if (mpt2sas_port) - mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_address_parent); - kfree(sas_expander); - return rc; -} - -/** - * _scsih_done - scsih callback handler. - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Callback handler when sending internal generated message frames. - * The callback index passed is `ioc->scsih_cb_idx` - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -static u8 -_scsih_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (ioc->scsih_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->scsih_cmds.smid != smid) - return 1; - ioc->scsih_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - memcpy(ioc->scsih_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - ioc->scsih_cmds.status |= MPT2_CMD_REPLY_VALID; - } - ioc->scsih_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->scsih_cmds.done); - return 1; -} - -/** - * mpt2sas_expander_remove - removing expander object - * @ioc: per adapter object - * @sas_address: expander sas_address - * - * Return nothing. - */ -void -mpt2sas_expander_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) -{ - struct _sas_node *sas_expander; - unsigned long flags; - - if (ioc->shost_recovery) - return; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address); - if (!sas_expander) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return; - } - list_del(&sas_expander->list); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - _scsih_expander_node_remove(ioc, sas_expander); -} - -/** - * _scsih_check_access_status - check access flags - * @ioc: per adapter object - * @sas_address: sas address - * @handle: sas device handle - * @access_flags: errors returned during discovery of the device - * - * Return 0 for success, else failure - */ -static u8 -_scsih_check_access_status(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 handle, u8 access_status) -{ - u8 rc = 1; - char *desc = NULL; - - switch (access_status) { - case MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS: - case MPI2_SAS_DEVICE0_ASTATUS_SATA_NEEDS_INITIALIZATION: - rc = 0; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_CAPABILITY_FAILED: - desc = "sata capability failed"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_AFFILIATION_CONFLICT: - desc = "sata affiliation conflict"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_ROUTE_NOT_ADDRESSABLE: - desc = "route not addressable"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SMP_ERROR_NOT_ADDRESSABLE: - desc = "smp error not addressable"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_DEVICE_BLOCKED: - desc = "device blocked"; - break; - case MPI2_SAS_DEVICE0_ASTATUS_SATA_INIT_FAILED: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_UNKNOWN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_AFFILIATION_CONFLICT: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_DIAG: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_IDENTIFICATION: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_CHECK_POWER: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_PIO_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_MDMA_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_UDMA_SN: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_ZONING_VIOLATION: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_NOT_ADDRESSABLE: - case MPI2_SAS_DEVICE0_ASTATUS_SIF_MAX: - desc = "sata initialization failed"; - break; - default: - desc = "unknown"; - break; - } - - if (!rc) - return 0; - - printk(MPT2SAS_ERR_FMT "discovery errors(%s): sas_address(0x%016llx), " - "handle(0x%04x)\n", ioc->name, desc, - (unsigned long long)sas_address, handle); - return rc; -} - -static void -_scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - struct _sas_device *sas_device; - u32 ioc_status; - unsigned long flags; - u64 sas_address; - struct scsi_target *starget; - struct MPT2SAS_TARGET *sas_target_priv_data; - u32 device_info; - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) - return; - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) - return; - - /* check if this is end device */ - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - if (!(_scsih_is_end_device(device_info))) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - - if (!sas_device) { - printk(MPT2SAS_ERR_FMT "device is not present " - "handle(0x%04x), no sas_device!!!\n", ioc->name, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } - - if (unlikely(sas_device->handle != handle)) { - starget = sas_device->starget; - sas_target_priv_data = starget->hostdata; - starget_printk(KERN_INFO, starget, "handle changed from(0x%04x)" - " to (0x%04x)!!!\n", sas_device->handle, handle); - sas_target_priv_data->handle = handle; - sas_device->handle = handle; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - /* check if device is present */ - if (!(le16_to_cpu(sas_device_pg0.Flags) & - MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { - printk(MPT2SAS_ERR_FMT "device is not present " - "handle(0x%04x), flags!!!\n", ioc->name, handle); - return; - } - - /* check if there were any issues with discovery */ - if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) - return; - _scsih_ublock_io_device(ioc, handle); - -} - -/** - * _scsih_add_device - creating sas device object - * @ioc: per adapter object - * @handle: sas device handle - * @phy_num: phy number end device attached to - * @is_pd: is this hidden raid component - * - * Creating end device object, stored in ioc->sas_device_list. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) -{ - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2SasEnclosurePage0_t enclosure_pg0; - struct _sas_device *sas_device; - u32 ioc_status; - __le64 sas_address; - u32 device_info; - unsigned long flags; - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - - /* check if device is present */ - if (!(le16_to_cpu(sas_device_pg0.Flags) & - MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - printk(MPT2SAS_ERR_FMT "Flags = 0x%04x\n", - ioc->name, le16_to_cpu(sas_device_pg0.Flags)); - return -1; - } - - /* check if there were any issues with discovery */ - if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) - return -1; - - /* check if this is end device */ - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - if (!(_scsih_is_end_device(device_info))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) - return 0; - - sas_device = kzalloc(sizeof(struct _sas_device), - GFP_KERNEL); - if (!sas_device) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - - sas_device->handle = handle; - if (_scsih_get_sas_address(ioc, le16_to_cpu - (sas_device_pg0.ParentDevHandle), - &sas_device->sas_address_parent) != 0) - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - sas_device->enclosure_handle = - le16_to_cpu(sas_device_pg0.EnclosureHandle); - sas_device->slot = - le16_to_cpu(sas_device_pg0.Slot); - sas_device->device_info = device_info; - sas_device->sas_address = sas_address; - sas_device->phy = sas_device_pg0.PhyNum; - - /* get enclosure_logical_id */ - if (sas_device->enclosure_handle && !(mpt2sas_config_get_enclosure_pg0( - ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, - sas_device->enclosure_handle))) - sas_device->enclosure_logical_id = - le64_to_cpu(enclosure_pg0.EnclosureLogicalID); - - /* get device name */ - sas_device->device_name = le64_to_cpu(sas_device_pg0.DeviceName); - - if (ioc->wait_for_discovery_to_complete) - _scsih_sas_device_init_add(ioc, sas_device); - else - _scsih_sas_device_add(ioc, sas_device); - - return 0; -} - -/** - * _scsih_remove_device - removing sas device object - * @ioc: per adapter object - * @sas_device_delete: the sas_device object - * - * Return nothing. - */ -static void -_scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, - struct _sas_device *sas_device) -{ - struct _sas_device sas_device_backup; - struct MPT2SAS_TARGET *sas_target_priv_data; - - if (!sas_device) - return; - - memcpy(&sas_device_backup, sas_device, sizeof(struct _sas_device)); - _scsih_sas_device_remove(ioc, sas_device); - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device_backup.handle, (unsigned long long) - sas_device_backup.sas_address)); - - if (sas_device_backup.starget && sas_device_backup.starget->hostdata) { - sas_target_priv_data = sas_device_backup.starget->hostdata; - sas_target_priv_data->deleted = 1; - _scsih_ublock_io_device(ioc, sas_device_backup.handle); - sas_target_priv_data->handle = - MPT2SAS_INVALID_DEVICE_HANDLE; - } - - _scsih_ublock_io_device(ioc, sas_device_backup.handle); - - if (!ioc->hide_drives) - mpt2sas_transport_port_remove(ioc, - sas_device_backup.sas_address, - sas_device_backup.sas_address_parent); - - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), sas_addr" - "(0x%016llx)\n", ioc->name, sas_device_backup.handle, - (unsigned long long) sas_device_backup.sas_address); - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: exit: " - "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device_backup.handle, (unsigned long long) - sas_device_backup.sas_address)); -} - -/** - * mpt2sas_device_remove - removing device object - * @ioc: per adapter object - * @sas_address: expander sas_address - * - * Return nothing. - */ -void -mpt2sas_device_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) -{ - struct _sas_device *sas_device; - unsigned long flags; - - if (ioc->shost_recovery) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_remove_device(ioc, sas_device); -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_topology_change_event_debug - debug for topology event - * @ioc: per adapter object - * @event_data: event data payload - * Context: user. - */ -static void -_scsih_sas_topology_change_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasTopologyChangeList_t *event_data) -{ - int i; - u16 handle; - u16 reason_code; - u8 phy_number; - char *status_str = NULL; - u8 link_rate, prev_link_rate; - - switch (event_data->ExpStatus) { - case MPI2_EVENT_SAS_TOPO_ES_ADDED: - status_str = "add"; - break; - case MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING: - status_str = "remove"; - break; - case MPI2_EVENT_SAS_TOPO_ES_RESPONDING: - case 0: - status_str = "responding"; - break; - case MPI2_EVENT_SAS_TOPO_ES_DELAY_NOT_RESPONDING: - status_str = "remove delay"; - break; - default: - status_str = "unknown status"; - break; - } - printk(MPT2SAS_INFO_FMT "sas topology change: (%s)\n", - ioc->name, status_str); - printk(KERN_INFO "\thandle(0x%04x), enclosure_handle(0x%04x) " - "start_phy(%02d), count(%d)\n", - le16_to_cpu(event_data->ExpanderDevHandle), - le16_to_cpu(event_data->EnclosureHandle), - event_data->StartPhyNum, event_data->NumEntries); - for (i = 0; i < event_data->NumEntries; i++) { - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - phy_number = event_data->StartPhyNum + i; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - switch (reason_code) { - case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - status_str = "target add"; - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - status_str = "target remove"; - break; - case MPI2_EVENT_SAS_TOPO_RC_DELAY_NOT_RESPONDING: - status_str = "delay target remove"; - break; - case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: - status_str = "link rate change"; - break; - case MPI2_EVENT_SAS_TOPO_RC_NO_CHANGE: - status_str = "target responding"; - break; - default: - status_str = "unknown"; - break; - } - link_rate = event_data->PHY[i].LinkRate >> 4; - prev_link_rate = event_data->PHY[i].LinkRate & 0xF; - printk(KERN_INFO "\tphy(%02d), attached_handle(0x%04x): %s:" - " link rate: new(0x%02x), old(0x%02x)\n", phy_number, - handle, status_str, link_rate, prev_link_rate); - - } -} -#endif - -/** - * _scsih_sas_topology_change_event - handle topology changes - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - */ -static void -_scsih_sas_topology_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - int i; - u16 parent_handle, handle; - u16 reason_code; - u8 phy_number, max_phys; - struct _sas_node *sas_expander; - struct _sas_device *sas_device; - u64 sas_address; - unsigned long flags; - u8 link_rate, prev_link_rate; - Mpi2EventDataSasTopologyChangeList_t *event_data = fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_topology_change_event_debug(ioc, event_data); -#endif - - if (ioc->remove_host || ioc->pci_error_recovery) - return; - - if (!ioc->sas_hba.num_phys) - _scsih_sas_host_add(ioc); - else - _scsih_sas_host_refresh(ioc); - - if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring expander " - "event\n", ioc->name)); - return; - } - - parent_handle = le16_to_cpu(event_data->ExpanderDevHandle); - - /* handle expander add */ - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_ADDED) - if (_scsih_expander_add(ioc, parent_handle) != 0) - return; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_expander = mpt2sas_scsih_expander_find_by_handle(ioc, - parent_handle); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (sas_expander) { - sas_address = sas_expander->sas_address; - max_phys = sas_expander->num_phys; - } else if (parent_handle < ioc->sas_hba.num_phys) { - sas_address = ioc->sas_hba.sas_address; - max_phys = ioc->sas_hba.num_phys; - } else - return; - - /* handle siblings events */ - for (i = 0; i < event_data->NumEntries; i++) { - if (fw_event->ignore) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "ignoring " - "expander event\n", ioc->name)); - return; - } - if (ioc->shost_recovery || ioc->remove_host || - ioc->pci_error_recovery) - return; - phy_number = event_data->StartPhyNum + i; - if (phy_number >= max_phys) - continue; - reason_code = event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_RC_MASK; - if ((event_data->PHY[i].PhyStatus & - MPI2_EVENT_SAS_TOPO_PHYSTATUS_VACANT) && (reason_code != - MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING)) - continue; - handle = le16_to_cpu(event_data->PHY[i].AttachedDevHandle); - if (!handle) - continue; - link_rate = event_data->PHY[i].LinkRate >> 4; - prev_link_rate = event_data->PHY[i].LinkRate & 0xF; - switch (reason_code) { - case MPI2_EVENT_SAS_TOPO_RC_PHY_CHANGED: - - if (ioc->shost_recovery) - break; - - if (link_rate == prev_link_rate) - break; - - mpt2sas_transport_update_links(ioc, sas_address, - handle, phy_number, link_rate); - - if (link_rate < MPI2_SAS_NEG_LINK_RATE_1_5) - break; - - _scsih_check_device(ioc, handle); - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_ADDED: - - if (ioc->shost_recovery) - break; - - mpt2sas_transport_update_links(ioc, sas_address, - handle, phy_number, link_rate); - - _scsih_add_device(ioc, handle, phy_number, 0); - break; - case MPI2_EVENT_SAS_TOPO_RC_TARG_NOT_RESPONDING: - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - handle); - if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, - flags); - break; - } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - _scsih_remove_device(ioc, sas_device); - break; - } - } - - /* handle expander removal */ - if (event_data->ExpStatus == MPI2_EVENT_SAS_TOPO_ES_NOT_RESPONDING && - sas_expander) - mpt2sas_expander_remove(ioc, sas_address); - -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_device_status_change_event_debug - debug for device event - * @event_data: event data payload - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_device_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasDeviceStatusChange_t *event_data) -{ - char *reason_str = NULL; - - switch (event_data->ReasonCode) { - case MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA: - reason_str = "smart data"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_UNSUPPORTED: - reason_str = "unsupported device discovered"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: - reason_str = "internal device reset"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_TASK_ABORT_INTERNAL: - reason_str = "internal task abort"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_ABORT_TASK_SET_INTERNAL: - reason_str = "internal task abort set"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CLEAR_TASK_SET_INTERNAL: - reason_str = "internal clear task set"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_QUERY_TASK_INTERNAL: - reason_str = "internal query task"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_SATA_INIT_FAILURE: - reason_str = "sata init failure"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET: - reason_str = "internal device reset complete"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_TASK_ABORT_INTERNAL: - reason_str = "internal task abort complete"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_ASYNC_NOTIFICATION: - reason_str = "internal async notification"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_EXPANDER_REDUCED_FUNCTIONALITY: - reason_str = "expander reduced functionality"; - break; - case MPI2_EVENT_SAS_DEV_STAT_RC_CMP_EXPANDER_REDUCED_FUNCTIONALITY: - reason_str = "expander reduced functionality complete"; - break; - default: - reason_str = "unknown reason"; - break; - } - printk(MPT2SAS_INFO_FMT "device status change: (%s)\n" - "\thandle(0x%04x), sas address(0x%016llx), tag(%d)", - ioc->name, reason_str, le16_to_cpu(event_data->DevHandle), - (unsigned long long)le64_to_cpu(event_data->SASAddress), - le16_to_cpu(event_data->TaskTag)); - if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_SMART_DATA) - printk(MPT2SAS_INFO_FMT ", ASC(0x%x), ASCQ(0x%x)\n", ioc->name, - event_data->ASC, event_data->ASCQ); - printk(KERN_INFO "\n"); -} -#endif - -/** - * _scsih_sas_device_status_change_event - handle device status change - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - struct MPT2SAS_TARGET *target_priv_data; - struct _sas_device *sas_device; - u64 sas_address; - unsigned long flags; - Mpi2EventDataSasDeviceStatusChange_t *event_data = - fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_device_status_change_event_debug(ioc, - event_data); -#endif - - /* In MPI Revision K (0xC), the internal device reset complete was - * implemented, so avoid setting tm_busy flag for older firmware. - */ - if ((ioc->facts.HeaderVersion >> 8) < 0xC) - return; - - if (event_data->ReasonCode != - MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET && - event_data->ReasonCode != - MPI2_EVENT_SAS_DEV_STAT_RC_CMP_INTERNAL_DEV_RESET) - return; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_address = le64_to_cpu(event_data->SASAddress); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (!sas_device || !sas_device->starget) - return; - - target_priv_data = sas_device->starget->hostdata; - if (!target_priv_data) - return; - - if (event_data->ReasonCode == - MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) - target_priv_data->tm_busy = 1; - else - target_priv_data->tm_busy = 0; -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_enclosure_dev_status_change_event_debug - debug for enclosure event - * @ioc: per adapter object - * @event_data: event data payload - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_enclosure_dev_status_change_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataSasEnclDevStatusChange_t *event_data) -{ - char *reason_str = NULL; - - switch (event_data->ReasonCode) { - case MPI2_EVENT_SAS_ENCL_RC_ADDED: - reason_str = "enclosure add"; - break; - case MPI2_EVENT_SAS_ENCL_RC_NOT_RESPONDING: - reason_str = "enclosure remove"; - break; - default: - reason_str = "unknown reason"; - break; - } - - printk(MPT2SAS_INFO_FMT "enclosure status change: (%s)\n" - "\thandle(0x%04x), enclosure logical id(0x%016llx)" - " number slots(%d)\n", ioc->name, reason_str, - le16_to_cpu(event_data->EnclosureHandle), - (unsigned long long)le64_to_cpu(event_data->EnclosureLogicalID), - le16_to_cpu(event_data->StartSlot)); -} -#endif - -/** - * _scsih_sas_enclosure_dev_status_change_event - handle enclosure events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_enclosure_dev_status_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - _scsih_sas_enclosure_dev_status_change_event_debug(ioc, - fw_event->event_data); -#endif -} - -/** - * _scsih_sas_broadcast_primitive_event - handle broadcast events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_broadcast_primitive_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - struct scsi_cmnd *scmd; - struct scsi_device *sdev; - u16 smid, handle; - u32 lun; - struct MPT2SAS_DEVICE *sas_device_priv_data; - u32 termination_count; - u32 query_count; - Mpi2SCSITaskManagementReply_t *mpi_reply; - Mpi2EventDataSasBroadcastPrimitive_t *event_data = fw_event->event_data; - u16 ioc_status; - unsigned long flags; - int r; - u8 max_retries = 0; - u8 task_abort_retries; - - mutex_lock(&ioc->tm_cmds.mutex); - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: enter: phy number(%d), " - "width(%d)\n", ioc->name, __func__, event_data->PhyNum, - event_data->PortWidth)); - - _scsih_block_io_all_device(ioc); - - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - mpi_reply = ioc->tm_cmds.reply; -broadcast_aen_retry: - - /* sanity checks for retrying this loop */ - if (max_retries++ == 5) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: giving up\n", - ioc->name, __func__)); - goto out; - } else if (max_retries > 1) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: %d retry\n", - ioc->name, __func__, max_retries - 1)); - - termination_count = 0; - query_count = 0; - for (smid = 1; smid <= ioc->scsiio_depth; smid++) { - if (ioc->shost_recovery) - goto out; - scmd = _scsih_scsi_lookup_get(ioc, smid); - if (!scmd) - continue; - sdev = scmd->device; - sas_device_priv_data = sdev->hostdata; - if (!sas_device_priv_data || !sas_device_priv_data->sas_target) - continue; - /* skip hidden raid components */ - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_RAID_COMPONENT) - continue; - /* skip volumes */ - if (sas_device_priv_data->sas_target->flags & - MPT_TARGET_FLAGS_VOLUME) - continue; - - handle = sas_device_priv_data->sas_target->handle; - lun = sas_device_priv_data->lun; - query_count++; - - if (ioc->shost_recovery) - goto out; - - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - r = mpt2sas_scsih_issue_tm(ioc, handle, 0, 0, lun, - MPI2_SCSITASKMGMT_TASKTYPE_QUERY_TASK, smid, 30, 0, - TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: FAILED when sending " - "QUERY_TASK: scmd(%p)\n", scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - ioc_status = le16_to_cpu(mpi_reply->IOCStatus) - & MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - sdev_printk(KERN_WARNING, sdev, "query task: FAILED " - "with IOCSTATUS(0x%04x), scmd(%p)\n", ioc_status, - scmd); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - /* see if IO is still owned by IOC and target */ - if (mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_TM_SUCCEEDED || - mpi_reply->ResponseCode == - MPI2_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC) { - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - continue; - } - task_abort_retries = 0; - tm_retry: - if (task_abort_retries++ == 60) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s: ABORT_TASK: giving up\n", ioc->name, - __func__)); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - goto broadcast_aen_retry; - } - - if (ioc->shost_recovery) - goto out_no_lock; - - r = mpt2sas_scsih_issue_tm(ioc, handle, sdev->channel, sdev->id, - sdev->lun, MPI2_SCSITASKMGMT_TASKTYPE_ABORT_TASK, smid, 30, - scmd->serial_number, TM_MUTEX_OFF); - if (r == FAILED) { - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: FAILED : " - "scmd(%p)\n", scmd); - goto tm_retry; - } - - if (task_abort_retries > 1) - sdev_printk(KERN_WARNING, sdev, - "mpt2sas_scsih_issue_tm: ABORT_TASK: RETRIES (%d):" - " scmd(%p)\n", - task_abort_retries - 1, scmd); - - termination_count += le32_to_cpu(mpi_reply->TerminationCount); - spin_lock_irqsave(&ioc->scsi_lookup_lock, flags); - } - - if (ioc->broadcast_aen_pending) { - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: loop back due to" - " pending AEN\n", ioc->name, __func__)); - ioc->broadcast_aen_pending = 0; - goto broadcast_aen_retry; - } - - out: - spin_unlock_irqrestore(&ioc->scsi_lookup_lock, flags); - out_no_lock: - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s - exit, query_count = %d termination_count = %d\n", - ioc->name, __func__, query_count, termination_count)); - - ioc->broadcast_aen_busy = 0; - if (!ioc->shost_recovery) - _scsih_ublock_io_all_device(ioc); - mutex_unlock(&ioc->tm_cmds.mutex); -} - -/** - * _scsih_sas_discovery_event - handle discovery events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_discovery_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventDataSasDiscovery_t *event_data = fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if (ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) { - printk(MPT2SAS_INFO_FMT "discovery event: (%s)", ioc->name, - (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED) ? - "start" : "stop"); - if (event_data->DiscoveryStatus) - printk("discovery_status(0x%08x)", - le32_to_cpu(event_data->DiscoveryStatus)); - printk("\n"); - } -#endif - - if (event_data->ReasonCode == MPI2_EVENT_SAS_DISC_RC_STARTED && - !ioc->sas_hba.num_phys) - _scsih_sas_host_add(ioc); -} - -/** - * _scsih_reprobe_lun - reprobing lun - * @sdev: scsi device struct - * @no_uld_attach: sdev->no_uld_attach flag setting - * - **/ -static void -_scsih_reprobe_lun(struct scsi_device *sdev, void *no_uld_attach) -{ - int rc; - - sdev->no_uld_attach = no_uld_attach ? 1 : 0; - sdev_printk(KERN_INFO, sdev, "%s raid component\n", - sdev->no_uld_attach ? "hidding" : "exposing"); - rc = scsi_device_reprobe(sdev); -} - -/** - * _scsih_reprobe_target - reprobing target - * @starget: scsi target struct - * @no_uld_attach: sdev->no_uld_attach flag setting - * - * Note: no_uld_attach flag determines whether the disk device is attached - * to block layer. A value of `1` means to not attach. - **/ -static void -_scsih_reprobe_target(struct scsi_target *starget, int no_uld_attach) -{ - struct MPT2SAS_TARGET *sas_target_priv_data; - - if (starget == NULL) - return; - sas_target_priv_data = starget->hostdata; - if (no_uld_attach) - sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; - else - sas_target_priv_data->flags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; - - starget_for_each_device(starget, no_uld_attach ? (void *)1 : NULL, - _scsih_reprobe_lun); -} -/** - * _scsih_sas_volume_add - add new volume - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_volume_add(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _raid_device *raid_device; - unsigned long flags; - u64 wwid; - u16 handle = le16_to_cpu(element->VolDevHandle); - int rc; - - mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); - if (!wwid) { - printk(MPT2SAS_ERR_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - return; - } - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_wwid(ioc, wwid); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (raid_device) - return; - - raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); - if (!raid_device) { - printk(MPT2SAS_ERR_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - return; - } - - raid_device->id = ioc->sas_id++; - raid_device->channel = RAID_CHANNEL; - raid_device->handle = handle; - raid_device->wwid = wwid; - _scsih_raid_device_add(ioc, raid_device); - if (!ioc->wait_for_discovery_to_complete) { - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - } else - _scsih_determine_boot_device(ioc, raid_device, 1); -} - -/** - * _scsih_sas_volume_delete - delete volume - * @ioc: per adapter object - * @handle: volume device handle - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_volume_delete(struct MPT2SAS_ADAPTER *ioc, u16 handle) -{ - struct _raid_device *raid_device; - unsigned long flags; - struct MPT2SAS_TARGET *sas_target_priv_data; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - if (!raid_device) - return; - if (raid_device->starget) { - sas_target_priv_data = raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - scsi_remove_target(&raid_device->starget->dev); - } - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" - "(0x%016llx)\n", ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); - _scsih_raid_device_remove(ioc, raid_device); -} - -/** - * _scsih_sas_pd_expose - expose pd component to /dev/sdX - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _sas_device *sas_device; - unsigned long flags; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - return; - - /* exposing raid component */ - sas_device->volume_handle = 0; - sas_device->volume_wwid = 0; - clear_bit(handle, ioc->pd_handles); - _scsih_reprobe_target(sas_device->starget, 0); -} - -/** - * _scsih_sas_pd_hide - hide pd component from /dev/sdX - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _sas_device *sas_device; - unsigned long flags; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - return; - - /* hiding raid component */ - mpt2sas_config_get_volume_handle(ioc, handle, - &sas_device->volume_handle); - mpt2sas_config_get_volume_wwid(ioc, sas_device->volume_handle, - &sas_device->volume_wwid); - set_bit(handle, ioc->pd_handles); - _scsih_reprobe_target(sas_device->starget, 1); - -} - -/** - * _scsih_sas_pd_delete - delete pd component - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_pd_delete(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _sas_device *sas_device; - unsigned long flags; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (!sas_device) - return; - _scsih_remove_device(ioc, sas_device); -} - -/** - * _scsih_sas_pd_add - remove pd component - * @ioc: per adapter object - * @element: IR config element data - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventIrConfigElement_t *element) -{ - struct _sas_device *sas_device; - unsigned long flags; - u16 handle = le16_to_cpu(element->PhysDiskDevHandle); - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - u32 ioc_status; - u64 sas_address; - u16 parent_handle; - - set_bit(handle, ioc->pd_handles); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) - return; - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - - _scsih_add_device(ioc, handle, 0, 1); -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_ir_config_change_event_debug - debug for IR Config Change events - * @ioc: per adapter object - * @event_data: event data payload - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_config_change_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrConfigChangeList_t *event_data) -{ - Mpi2EventIrConfigElement_t *element; - u8 element_type; - int i; - char *reason_str = NULL, *element_str = NULL; - - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - - printk(MPT2SAS_INFO_FMT "raid config change: (%s), elements(%d)\n", - ioc->name, (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? - "foreign" : "native", event_data->NumElements); - for (i = 0; i < event_data->NumElements; i++, element++) { - switch (element->ReasonCode) { - case MPI2_EVENT_IR_CHANGE_RC_ADDED: - reason_str = "add"; - break; - case MPI2_EVENT_IR_CHANGE_RC_REMOVED: - reason_str = "remove"; - break; - case MPI2_EVENT_IR_CHANGE_RC_NO_CHANGE: - reason_str = "no change"; - break; - case MPI2_EVENT_IR_CHANGE_RC_HIDE: - reason_str = "hide"; - break; - case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - reason_str = "unhide"; - break; - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: - reason_str = "volume_created"; - break; - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: - reason_str = "volume_deleted"; - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - reason_str = "pd_created"; - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - reason_str = "pd_deleted"; - break; - default: - reason_str = "unknown reason"; - break; - } - element_type = le16_to_cpu(element->ElementFlags) & - MPI2_EVENT_IR_CHANGE_EFLAGS_ELEMENT_TYPE_MASK; - switch (element_type) { - case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLUME_ELEMENT: - element_str = "volume"; - break; - case MPI2_EVENT_IR_CHANGE_EFLAGS_VOLPHYSDISK_ELEMENT: - element_str = "phys disk"; - break; - case MPI2_EVENT_IR_CHANGE_EFLAGS_HOTSPARE_ELEMENT: - element_str = "hot spare"; - break; - default: - element_str = "unknown element"; - break; - } - printk(KERN_INFO "\t(%s:%s), vol handle(0x%04x), " - "pd handle(0x%04x), pd num(0x%02x)\n", element_str, - reason_str, le16_to_cpu(element->VolDevHandle), - le16_to_cpu(element->PhysDiskDevHandle), - element->PhysDiskNum); - } -} -#endif - -/** - * _scsih_sas_ir_config_change_event - handle ir configuration change events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_config_change_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventIrConfigElement_t *element; - int i; - u8 foreign_config; - Mpi2EventDataIrConfigChangeList_t *event_data = fw_event->event_data; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - && !ioc->hide_ir_msg) - _scsih_sas_ir_config_change_event_debug(ioc, event_data); - -#endif - - if (ioc->shost_recovery) - return; - - foreign_config = (le32_to_cpu(event_data->Flags) & - MPI2_EVENT_IR_CHANGE_FLAGS_FOREIGN_CONFIG) ? 1 : 0; - - element = (Mpi2EventIrConfigElement_t *)&event_data->ConfigElement[0]; - for (i = 0; i < event_data->NumElements; i++, element++) { - - switch (element->ReasonCode) { - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_CREATED: - case MPI2_EVENT_IR_CHANGE_RC_ADDED: - if (!foreign_config) - _scsih_sas_volume_add(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_VOLUME_DELETED: - case MPI2_EVENT_IR_CHANGE_RC_REMOVED: - if (!foreign_config) - _scsih_sas_volume_delete(ioc, - le16_to_cpu(element->VolDevHandle)); - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_CREATED: - if (!ioc->is_warpdrive) - _scsih_sas_pd_hide(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_PD_DELETED: - if (!ioc->is_warpdrive) - _scsih_sas_pd_expose(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_HIDE: - if (!ioc->is_warpdrive) - _scsih_sas_pd_add(ioc, element); - break; - case MPI2_EVENT_IR_CHANGE_RC_UNHIDE: - if (!ioc->is_warpdrive) - _scsih_sas_pd_delete(ioc, element); - break; - } - } -} - -/** - * _scsih_sas_ir_volume_event - IR volume event - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_volume_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - u64 wwid; - unsigned long flags; - struct _raid_device *raid_device; - u16 handle; - u32 state; - int rc; - Mpi2EventDataIrVolume_t *event_data = fw_event->event_data; - - if (ioc->shost_recovery) - return; - - if (event_data->ReasonCode != MPI2_EVENT_IR_VOLUME_RC_STATE_CHANGED) - return; - - handle = le16_to_cpu(event_data->VolDevHandle); - state = le32_to_cpu(event_data->NewValue); - if (!ioc->hide_ir_msg) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); - - switch (state) { - case MPI2_RAID_VOL_STATE_MISSING: - case MPI2_RAID_VOL_STATE_FAILED: - _scsih_sas_volume_delete(ioc, handle); - break; - - case MPI2_RAID_VOL_STATE_ONLINE: - case MPI2_RAID_VOL_STATE_DEGRADED: - case MPI2_RAID_VOL_STATE_OPTIMAL: - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (raid_device) - break; - - mpt2sas_config_get_volume_wwid(ioc, handle, &wwid); - if (!wwid) { - printk(MPT2SAS_ERR_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - break; - } - - raid_device = kzalloc(sizeof(struct _raid_device), GFP_KERNEL); - if (!raid_device) { - printk(MPT2SAS_ERR_FMT - "failure at %s:%d/%s()!\n", ioc->name, - __FILE__, __LINE__, __func__); - break; - } - - raid_device->id = ioc->sas_id++; - raid_device->channel = RAID_CHANNEL; - raid_device->handle = handle; - raid_device->wwid = wwid; - _scsih_raid_device_add(ioc, raid_device); - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - break; - - case MPI2_RAID_VOL_STATE_INITIALIZING: - default: - break; - } -} - -/** - * _scsih_sas_ir_physical_disk_event - PD event - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - u16 handle, parent_handle; - u32 state; - struct _sas_device *sas_device; - unsigned long flags; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasDevicePage0_t sas_device_pg0; - u32 ioc_status; - Mpi2EventDataIrPhysicalDisk_t *event_data = fw_event->event_data; - u64 sas_address; - - if (ioc->shost_recovery) - return; - - if (event_data->ReasonCode != MPI2_EVENT_IR_PHYSDISK_RC_STATE_CHANGED) - return; - - handle = le16_to_cpu(event_data->PhysDiskDevHandle); - state = le32_to_cpu(event_data->NewValue); - - if (!ioc->hide_ir_msg) - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: handle(0x%04x), " - "old(0x%08x), new(0x%08x)\n", ioc->name, __func__, handle, - le32_to_cpu(event_data->PreviousValue), state)); - - switch (state) { - case MPI2_RAID_PD_STATE_ONLINE: - case MPI2_RAID_PD_STATE_DEGRADED: - case MPI2_RAID_PD_STATE_REBUILDING: - case MPI2_RAID_PD_STATE_OPTIMAL: - case MPI2_RAID_PD_STATE_HOT_SPARE: - - if (!ioc->is_warpdrive) - set_bit(handle, ioc->pd_handles); - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) - return; - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, - handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - - _scsih_add_device(ioc, handle, 0, 1); - - break; - - case MPI2_RAID_PD_STATE_OFFLINE: - case MPI2_RAID_PD_STATE_NOT_CONFIGURED: - case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: - default: - break; - } -} - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING -/** - * _scsih_sas_ir_operation_status_event_debug - debug for IR op event - * @ioc: per adapter object - * @event_data: event data payload - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_operation_status_event_debug(struct MPT2SAS_ADAPTER *ioc, - Mpi2EventDataIrOperationStatus_t *event_data) -{ - char *reason_str = NULL; - - switch (event_data->RAIDOperation) { - case MPI2_EVENT_IR_RAIDOP_RESYNC: - reason_str = "resync"; - break; - case MPI2_EVENT_IR_RAIDOP_ONLINE_CAP_EXPANSION: - reason_str = "online capacity expansion"; - break; - case MPI2_EVENT_IR_RAIDOP_CONSISTENCY_CHECK: - reason_str = "consistency check"; - break; - case MPI2_EVENT_IR_RAIDOP_BACKGROUND_INIT: - reason_str = "background init"; - break; - case MPI2_EVENT_IR_RAIDOP_MAKE_DATA_CONSISTENT: - reason_str = "make data consistent"; - break; - } - - if (!reason_str) - return; - - printk(MPT2SAS_INFO_FMT "raid operational status: (%s)" - "\thandle(0x%04x), percent complete(%d)\n", - ioc->name, reason_str, - le16_to_cpu(event_data->VolDevHandle), - event_data->PercentComplete); -} -#endif - -/** - * _scsih_sas_ir_operation_status_event - handle RAID operation events - * @ioc: per adapter object - * @fw_event: The fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_scsih_sas_ir_operation_status_event(struct MPT2SAS_ADAPTER *ioc, - struct fw_event_work *fw_event) -{ - Mpi2EventDataIrOperationStatus_t *event_data = fw_event->event_data; - static struct _raid_device *raid_device; - unsigned long flags; - u16 handle; - -#ifdef CONFIG_SCSI_MPT2SAS_LOGGING - if ((ioc->logging_level & MPT_DEBUG_EVENT_WORK_TASK) - && !ioc->hide_ir_msg) - _scsih_sas_ir_operation_status_event_debug(ioc, - event_data); -#endif - - /* code added for raid transport support */ - if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) { - - handle = le16_to_cpu(event_data->VolDevHandle); - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - raid_device = _scsih_raid_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - - if (!raid_device) - return; - - if (event_data->RAIDOperation == MPI2_EVENT_IR_RAIDOP_RESYNC) - raid_device->percent_complete = - event_data->PercentComplete; - } -} - -/** - * _scsih_prep_device_scan - initialize parameters prior to device scan - * @ioc: per adapter object - * - * Set the deleted flag prior to device scan. If the device is found during - * the scan, then we clear the deleted flag. - */ -static void -_scsih_prep_device_scan(struct MPT2SAS_ADAPTER *ioc) -{ - struct MPT2SAS_DEVICE *sas_device_priv_data; - struct scsi_device *sdev; - - shost_for_each_device(sdev, ioc->shost) { - sas_device_priv_data = sdev->hostdata; - if (sas_device_priv_data && sas_device_priv_data->sas_target) - sas_device_priv_data->sas_target->deleted = 1; - } -} - -/** - * _scsih_mark_responding_sas_device - mark a sas_devices as responding - * @ioc: per adapter object - * @sas_address: sas address - * @slot: enclosure slot id - * @handle: device handle - * - * After host reset, find out whether devices are still responding. - * Used in _scsi_remove_unresponsive_sas_devices. - * - * Return nothing. - */ -static void -_scsih_mark_responding_sas_device(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 slot, u16 handle) -{ - struct MPT2SAS_TARGET *sas_target_priv_data = NULL; - struct scsi_target *starget; - struct _sas_device *sas_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->sas_address == sas_address && - sas_device->slot == slot) { - sas_device->responding = 1; - starget = sas_device->starget; - if (starget && starget->hostdata) { - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->tm_busy = 0; - sas_target_priv_data->deleted = 0; - } else - sas_target_priv_data = NULL; - if (starget) - starget_printk(KERN_INFO, starget, - "handle(0x%04x), sas_addr(0x%016llx), " - "enclosure logical id(0x%016llx), " - "slot(%d)\n", handle, - (unsigned long long)sas_device->sas_address, - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); - if (sas_device->handle == handle) - goto out; - printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", - sas_device->handle); - sas_device->handle = handle; - if (sas_target_priv_data) - sas_target_priv_data->handle = handle; - goto out; - } - } - out: - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); -} - -/** - * _scsih_search_responding_sas_devices - - * @ioc: per adapter object - * - * After host reset, find out whether devices are still responding. - * If not remove. - * - * Return nothing. - */ -static void -_scsih_search_responding_sas_devices(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - __le64 sas_address; - u16 handle; - u32 device_info; - u16 slot; - - printk(MPT2SAS_INFO_FMT "search for end-devices: start\n", ioc->name); - - if (list_empty(&ioc->sas_device_list)) - goto out; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, - handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - handle = le16_to_cpu(sas_device_pg0.DevHandle); - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - if (!(_scsih_is_end_device(device_info))) - continue; - sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - slot = le16_to_cpu(sas_device_pg0.Slot); - _scsih_mark_responding_sas_device(ioc, sas_address, slot, - handle); - } -out: - printk(MPT2SAS_INFO_FMT "search for end-devices: complete\n", - ioc->name); -} - -/** - * _scsih_mark_responding_raid_device - mark a raid_device as responding - * @ioc: per adapter object - * @wwid: world wide identifier for raid volume - * @handle: device handle - * - * After host reset, find out whether devices are still responding. - * Used in _scsi_remove_unresponsive_raid_devices. - * - * Return nothing. - */ -static void -_scsih_mark_responding_raid_device(struct MPT2SAS_ADAPTER *ioc, u64 wwid, - u16 handle) -{ - struct MPT2SAS_TARGET *sas_target_priv_data; - struct scsi_target *starget; - struct _raid_device *raid_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->raid_device_lock, flags); - list_for_each_entry(raid_device, &ioc->raid_device_list, list) { - if (raid_device->wwid == wwid && raid_device->starget) { - starget = raid_device->starget; - if (starget && starget->hostdata) { - sas_target_priv_data = starget->hostdata; - sas_target_priv_data->deleted = 0; - } else - sas_target_priv_data = NULL; - raid_device->responding = 1; - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); - starget_printk(KERN_INFO, raid_device->starget, - "handle(0x%04x), wwid(0x%016llx)\n", handle, - (unsigned long long)raid_device->wwid); - /* - * WARPDRIVE: The handles of the PDs might have changed - * across the host reset so re-initialize the - * required data for Direct IO - */ - _scsih_init_warpdrive_properties(ioc, raid_device); - if (raid_device->handle == handle) - return; - printk(KERN_INFO "\thandle changed from(0x%04x)!!!\n", - raid_device->handle); - raid_device->handle = handle; - if (sas_target_priv_data) - sas_target_priv_data->handle = handle; - return; - } - } - - spin_unlock_irqrestore(&ioc->raid_device_lock, flags); -} - -/** - * _scsih_search_responding_raid_devices - - * @ioc: per adapter object - * - * After host reset, find out whether devices are still responding. - * If not remove. - * - * Return nothing. - */ -static void -_scsih_search_responding_raid_devices(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidVolPage1_t volume_pg1; - Mpi2RaidVolPage0_t volume_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 handle; - u8 phys_disk_num; - - if (!ioc->ir_firmware) - return; - - printk(MPT2SAS_INFO_FMT "search for raid volumes: start\n", - ioc->name); - - if (list_empty(&ioc->raid_device_list)) - goto out; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - handle = le16_to_cpu(volume_pg1.DevHandle); - - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, - &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) - continue; - - if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) - _scsih_mark_responding_raid_device(ioc, - le64_to_cpu(volume_pg1.WWID), handle); - } - - /* refresh the pd_handles */ - if (!ioc->is_warpdrive) { - phys_disk_num = 0xFF; - memset(ioc->pd_handles, 0, ioc->pd_handles_sz); - while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, - phys_disk_num))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - phys_disk_num = pd_pg0.PhysDiskNum; - handle = le16_to_cpu(pd_pg0.DevHandle); - set_bit(handle, ioc->pd_handles); - } - } -out: - printk(MPT2SAS_INFO_FMT "search for responding raid volumes: " - "complete\n", ioc->name); -} - -/** - * _scsih_mark_responding_expander - mark a expander as responding - * @ioc: per adapter object - * @sas_address: sas address - * @handle: - * - * After host reset, find out whether devices are still responding. - * Used in _scsi_remove_unresponsive_expanders. - * - * Return nothing. - */ -static void -_scsih_mark_responding_expander(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u16 handle) -{ - struct _sas_node *sas_expander; - unsigned long flags; - int i; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->sas_address != sas_address) - continue; - sas_expander->responding = 1; - if (sas_expander->handle == handle) - goto out; - printk(KERN_INFO "\texpander(0x%016llx): handle changed" - " from(0x%04x) to (0x%04x)!!!\n", - (unsigned long long)sas_expander->sas_address, - sas_expander->handle, handle); - sas_expander->handle = handle; - for (i = 0 ; i < sas_expander->num_phys ; i++) - sas_expander->phy[i].handle = handle; - goto out; - } - out: - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); -} - -/** - * _scsih_search_responding_expanders - - * @ioc: per adapter object - * - * After host reset, find out whether devices are still responding. - * If not remove. - * - * Return nothing. - */ -static void -_scsih_search_responding_expanders(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2ExpanderPage0_t expander_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u64 sas_address; - u16 handle; - - printk(MPT2SAS_INFO_FMT "search for expanders: start\n", ioc->name); - - if (list_empty(&ioc->sas_expander_list)) - goto out; - - handle = 0xFFFF; - while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, - MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - - handle = le16_to_cpu(expander_pg0.DevHandle); - sas_address = le64_to_cpu(expander_pg0.SASAddress); - printk(KERN_INFO "\texpander present: handle(0x%04x), " - "sas_addr(0x%016llx)\n", handle, - (unsigned long long)sas_address); - _scsih_mark_responding_expander(ioc, sas_address, handle); - } - - out: - printk(MPT2SAS_INFO_FMT "search for expanders: complete\n", ioc->name); -} - -/** - * _scsih_remove_unresponding_sas_devices - removing unresponding devices - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) -{ - struct _sas_device *sas_device, *sas_device_next; - struct _sas_node *sas_expander; - struct _raid_device *raid_device, *raid_device_next; - - printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n", - ioc->name); - - list_for_each_entry_safe(sas_device, sas_device_next, - &ioc->sas_device_list, list) { - if (sas_device->responding) { - sas_device->responding = 0; - continue; - } - if (sas_device->starget) - starget_printk(KERN_INFO, sas_device->starget, - "removing: handle(0x%04x), sas_addr(0x%016llx), " - "enclosure logical id(0x%016llx), slot(%d)\n", - sas_device->handle, - (unsigned long long)sas_device->sas_address, - (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); - _scsih_remove_device(ioc, sas_device); - } - - if (!ioc->ir_firmware) - goto retry_expander_search; - - list_for_each_entry_safe(raid_device, raid_device_next, - &ioc->raid_device_list, list) { - if (raid_device->responding) { - raid_device->responding = 0; - continue; - } - if (raid_device->starget) { - starget_printk(KERN_INFO, raid_device->starget, - "removing: handle(0x%04x), wwid(0x%016llx)\n", - raid_device->handle, - (unsigned long long)raid_device->wwid); - scsi_remove_target(&raid_device->starget->dev); - } - _scsih_raid_device_remove(ioc, raid_device); - } - - retry_expander_search: - sas_expander = NULL; - list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { - if (sas_expander->responding) { - sas_expander->responding = 0; - continue; - } - mpt2sas_expander_remove(ioc, sas_expander->sas_address); - goto retry_expander_search; - } - printk(MPT2SAS_INFO_FMT "removing unresponding devices: complete\n", - ioc->name); - /* unblock devices */ - _scsih_ublock_io_all_device(ioc); -} - -static void -_scsih_refresh_expander_links(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander, u16 handle) -{ - Mpi2ExpanderPage1_t expander_pg1; - Mpi2ConfigReply_t mpi_reply; - int i; - - for (i = 0 ; i < sas_expander->num_phys ; i++) { - if ((mpt2sas_config_get_expander_pg1(ioc, &mpi_reply, - &expander_pg1, i, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return; - } - - mpt2sas_transport_update_links(ioc, sas_expander->sas_address, - le16_to_cpu(expander_pg1.AttachedDevHandle), i, - expander_pg1.NegotiatedLinkRate >> 4); - } -} - -/** - * _scsih_scan_for_devices_after_reset - scan for devices after host reset - * @ioc: per adapter object - * - * Return nothing. - */ -static void -_scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2ExpanderPage0_t expander_pg0; - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2RaidVolPage1_t volume_pg1; - Mpi2RaidVolPage0_t volume_pg0; - Mpi2RaidPhysDiskPage0_t pd_pg0; - Mpi2EventIrConfigElement_t element; - Mpi2ConfigReply_t mpi_reply; - u8 phys_disk_num; - u16 ioc_status; - u16 handle, parent_handle; - u64 sas_address; - struct _sas_device *sas_device; - struct _sas_node *expander_device; - static struct _raid_device *raid_device; - - printk(MPT2SAS_INFO_FMT "scan devices: start\n", ioc->name); - - _scsih_sas_host_refresh(ioc); - - /* expanders */ - handle = 0xFFFF; - while (!(mpt2sas_config_get_expander_pg0(ioc, &mpi_reply, &expander_pg0, - MPI2_SAS_EXPAND_PGAD_FORM_GET_NEXT_HNDL, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - handle = le16_to_cpu(expander_pg0.DevHandle); - expander_device = mpt2sas_scsih_expander_find_by_sas_address( - ioc, le64_to_cpu(expander_pg0.SASAddress)); - if (expander_device) - _scsih_refresh_expander_links(ioc, expander_device, - handle); - else - _scsih_expander_add(ioc, handle); - } - - if (!ioc->ir_firmware) - goto skip_to_sas; - - /* phys disk */ - phys_disk_num = 0xFF; - while (!(mpt2sas_config_get_phys_disk_pg0(ioc, &mpi_reply, - &pd_pg0, MPI2_PHYSDISK_PGAD_FORM_GET_NEXT_PHYSDISKNUM, - phys_disk_num))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - phys_disk_num = pd_pg0.PhysDiskNum; - handle = le16_to_cpu(pd_pg0.DevHandle); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (sas_device) - continue; - if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, - handle) != 0) - continue; - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, - &sas_address)) { - mpt2sas_transport_update_links(ioc, sas_address, - handle, sas_device_pg0.PhyNum, - MPI2_SAS_NEG_LINK_RATE_1_5); - set_bit(handle, ioc->pd_handles); - _scsih_add_device(ioc, handle, 0, 1); - } - } - - /* volumes */ - handle = 0xFFFF; - while (!(mpt2sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - handle = le16_to_cpu(volume_pg1.DevHandle); - raid_device = _scsih_raid_device_find_by_wwid(ioc, - le64_to_cpu(volume_pg1.WWID)); - if (raid_device) - continue; - if (mpt2sas_config_get_raid_volume_pg0(ioc, &mpi_reply, - &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, - sizeof(Mpi2RaidVolPage0_t))) - continue; - if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || - volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { - memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); - element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; - element.VolDevHandle = volume_pg1.DevHandle; - _scsih_sas_volume_add(ioc, &element); - } - } - - skip_to_sas: - - /* sas devices */ - handle = 0xFFFF; - while (!(mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, - &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, - handle))) { - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) - break; - handle = le16_to_cpu(sas_device_pg0.DevHandle); - if (!(_scsih_is_end_device( - le32_to_cpu(sas_device_pg0.DeviceInfo)))) - continue; - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - le64_to_cpu(sas_device_pg0.SASAddress)); - if (sas_device) - continue; - parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); - if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { - mpt2sas_transport_update_links(ioc, sas_address, handle, - sas_device_pg0.PhyNum, MPI2_SAS_NEG_LINK_RATE_1_5); - _scsih_add_device(ioc, handle, 0, 0); - } - } - - printk(MPT2SAS_INFO_FMT "scan devices: complete\n", ioc->name); -} - - -/** - * mpt2sas_scsih_reset_handler - reset callback handler (for scsih) - * @ioc: per adapter object - * @reset_phase: phase - * - * The handler for doing any required cleanup or initialization. - * - * The reset phase can be MPT2_IOC_PRE_RESET, MPT2_IOC_AFTER_RESET, - * MPT2_IOC_DONE_RESET - * - * Return nothing. - */ -void -mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase) -{ - switch (reset_phase) { - case MPT2_IOC_PRE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_PRE_RESET\n", ioc->name, __func__)); - break; - case MPT2_IOC_AFTER_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_AFTER_RESET\n", ioc->name, __func__)); - if (ioc->scsih_cmds.status & MPT2_CMD_PENDING) { - ioc->scsih_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->scsih_cmds.smid); - complete(&ioc->scsih_cmds.done); - } - if (ioc->tm_cmds.status & MPT2_CMD_PENDING) { - ioc->tm_cmds.status |= MPT2_CMD_RESET; - mpt2sas_base_free_smid(ioc, ioc->tm_cmds.smid); - complete(&ioc->tm_cmds.done); - } - _scsih_fw_event_cleanup_queue(ioc); - _scsih_flush_running_cmds(ioc); - break; - case MPT2_IOC_DONE_RESET: - dtmprintk(ioc, printk(MPT2SAS_INFO_FMT "%s: " - "MPT2_IOC_DONE_RESET\n", ioc->name, __func__)); - _scsih_sas_host_refresh(ioc); - _scsih_prep_device_scan(ioc); - _scsih_search_responding_sas_devices(ioc); - _scsih_search_responding_raid_devices(ioc); - _scsih_search_responding_expanders(ioc); - if (!ioc->is_driver_loading) { - _scsih_prep_device_scan(ioc); - _scsih_search_responding_sas_devices(ioc); - _scsih_search_responding_raid_devices(ioc); - _scsih_search_responding_expanders(ioc); - _scsih_error_recovery_delete_devices(ioc); - } - break; - } -} - -/** - * _firmware_event_work - delayed task for processing firmware events - * @ioc: per adapter object - * @work: equal to the fw_event_work object - * Context: user. - * - * Return nothing. - */ -static void -_firmware_event_work(struct work_struct *work) -{ - struct fw_event_work *fw_event = container_of(work, - struct fw_event_work, delayed_work.work); - struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; - - /* the queue is being flushed so ignore this event */ - if (ioc->remove_host || fw_event->cancel_pending_work || - ioc->pci_error_recovery) { - _scsih_fw_event_free(ioc, fw_event); - return; - } - - switch (fw_event->event) { - case MPT2SAS_REMOVE_UNRESPONDING_DEVICES: - while (scsi_host_in_recovery(ioc->shost)) - ssleep(1); - _scsih_remove_unresponding_sas_devices(ioc); - _scsih_scan_for_devices_after_reset(ioc); - break; - case MPT2SAS_PORT_ENABLE_COMPLETE: - ioc->start_scan = 0; - - - - dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "port enable: complete " - "from worker thread\n", ioc->name)); - break; - case MPT2SAS_TURN_ON_FAULT_LED: - _scsih_turn_on_fault_led(ioc, fw_event->device_handle); - break; - case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_sas_topology_change_event(ioc, fw_event); - break; - case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - _scsih_sas_device_status_change_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_DISCOVERY: - _scsih_sas_discovery_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: - _scsih_sas_broadcast_primitive_event(ioc, - fw_event); - break; - case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - _scsih_sas_enclosure_dev_status_change_event(ioc, - fw_event); - break; - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - _scsih_sas_ir_config_change_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_VOLUME: - _scsih_sas_ir_volume_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_PHYSICAL_DISK: - _scsih_sas_ir_physical_disk_event(ioc, fw_event); - break; - case MPI2_EVENT_IR_OPERATION_STATUS: - _scsih_sas_ir_operation_status_event(ioc, fw_event); - break; - } - _scsih_fw_event_free(ioc, fw_event); -} - -/** - * mpt2sas_scsih_event_callback - firmware event handler (called at ISR time) - * @ioc: per adapter object - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * Context: interrupt. - * - * This function merely adds a new work task into ioc->firmware_event_thread. - * The tasks are worked from _firmware_event_work in user context. - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, - u32 reply) -{ - struct fw_event_work *fw_event; - Mpi2EventNotificationReply_t *mpi_reply; - u16 event; - u16 sz; - - /* events turned off due to host reset or driver unloading */ - if (ioc->remove_host || ioc->pci_error_recovery) - return 1; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - event = le16_to_cpu(mpi_reply->Event); - - switch (event) { - /* handle these */ - case MPI2_EVENT_SAS_BROADCAST_PRIMITIVE: - { - Mpi2EventDataSasBroadcastPrimitive_t *baen_data = - (Mpi2EventDataSasBroadcastPrimitive_t *) - mpi_reply->EventData; - - if (baen_data->Primitive != - MPI2_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT) - return 1; - - if (ioc->broadcast_aen_busy) { - ioc->broadcast_aen_pending++; - return 1; - } else - ioc->broadcast_aen_busy = 1; - break; - } - - case MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST: - _scsih_check_topo_delete_events(ioc, - (Mpi2EventDataSasTopologyChangeList_t *) - mpi_reply->EventData); - break; - case MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST: - _scsih_check_ir_config_unhide_events(ioc, - (Mpi2EventDataIrConfigChangeList_t *) - mpi_reply->EventData); - break; - case MPI2_EVENT_IR_VOLUME: - _scsih_check_volume_delete_events(ioc, - (Mpi2EventDataIrVolume_t *) - mpi_reply->EventData); - break; - case MPI2_EVENT_LOG_ENTRY_ADDED: - { - Mpi2EventDataLogEntryAdded_t *log_entry; - u32 *log_code; - - if (!ioc->is_warpdrive) - break; - - log_entry = (Mpi2EventDataLogEntryAdded_t *) - mpi_reply->EventData; - log_code = (u32 *)log_entry->LogData; - - if (le16_to_cpu(log_entry->LogEntryQualifier) - != MPT2_WARPDRIVE_LOGENTRY) - break; - - switch (le32_to_cpu(*log_code)) { - case MPT2_WARPDRIVE_LC_SSDT: - printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " - "IO Throttling has occurred in the WarpDrive " - "subsystem. Check WarpDrive documentation for " - "additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_SSDLW: - printk(MPT2SAS_WARN_FMT "WarpDrive Warning: " - "Program/Erase Cycles for the WarpDrive subsystem " - "in degraded range. Check WarpDrive documentation " - "for additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_SSDLF: - printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " - "There are no Program/Erase Cycles for the " - "WarpDrive subsystem. The storage device will be " - "in read-only mode. Check WarpDrive documentation " - "for additional details.\n", ioc->name); - break; - case MPT2_WARPDRIVE_LC_BRMF: - printk(MPT2SAS_ERR_FMT "WarpDrive Fatal Error: " - "The Backup Rail Monitor has failed on the " - "WarpDrive subsystem. Check WarpDrive " - "documentation for additional details.\n", - ioc->name); - break; - } - - break; - } - case MPI2_EVENT_SAS_DEVICE_STATUS_CHANGE: - case MPI2_EVENT_IR_OPERATION_STATUS: - case MPI2_EVENT_SAS_DISCOVERY: - case MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE: - case MPI2_EVENT_IR_PHYSICAL_DISK: - break; - - default: /* ignore the rest */ - return 1; - } - - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); - if (!fw_event) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return 1; - } - sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; - fw_event->event_data = kzalloc(sz, GFP_ATOMIC); - if (!fw_event->event_data) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - kfree(fw_event); - return 1; - } - - memcpy(fw_event->event_data, mpi_reply->EventData, - sz); - fw_event->ioc = ioc; - fw_event->VF_ID = mpi_reply->VF_ID; - fw_event->VP_ID = mpi_reply->VP_ID; - fw_event->event = event; - _scsih_fw_event_add(ioc, fw_event); - return 1; -} - -/* shost template */ -static struct scsi_host_template scsih_driver_template = { - .module = THIS_MODULE, - .name = "Fusion MPT SAS Host", - .proc_name = MPT2SAS_DRIVER_NAME, - .queuecommand = _scsih_qcmd, - .target_alloc = _scsih_target_alloc, - .slave_alloc = _scsih_slave_alloc, - .slave_configure = _scsih_slave_configure, - .target_destroy = _scsih_target_destroy, - .slave_destroy = _scsih_slave_destroy, - .scan_finished = _scsih_scan_finished, - .scan_start = _scsih_scan_start, - .change_queue_depth = _scsih_change_queue_depth, - .change_queue_type = _scsih_change_queue_type, - .eh_abort_handler = _scsih_abort, - .eh_device_reset_handler = _scsih_dev_reset, - .eh_target_reset_handler = _scsih_target_reset, - .eh_host_reset_handler = _scsih_host_reset, - .bios_param = _scsih_bios_param, - .can_queue = 1, - .this_id = -1, - .sg_tablesize = MPT2SAS_SG_DEPTH, - .max_sectors = 32767, - .cmd_per_lun = 7, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = mpt2sas_host_attrs, - .sdev_attrs = mpt2sas_dev_attrs, -}; - -/** - * _scsih_expander_node_remove - removing expander device from list. - * @ioc: per adapter object - * @sas_expander: the sas_device object - * Context: Calling function should acquire ioc->sas_node_lock. - * - * Removing object and freeing associated memory from the - * ioc->sas_expander_list. - * - * Return nothing. - */ -static void -_scsih_expander_node_remove(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_expander) -{ - struct _sas_port *mpt2sas_port, *next; - - /* remove sibling ports attached to this expander */ - list_for_each_entry_safe(mpt2sas_port, next, - &sas_expander->sas_port_list, port_list) { - if (ioc->shost_recovery) - return; - if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) - mpt2sas_device_remove(ioc, - mpt2sas_port->remote_identify.sas_address); - else if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, - mpt2sas_port->remote_identify.sas_address); - } - - mpt2sas_transport_port_remove(ioc, sas_expander->sas_address, - sas_expander->sas_address_parent); - - printk(MPT2SAS_INFO_FMT "expander_remove: handle" - "(0x%04x), sas_addr(0x%016llx)\n", ioc->name, - sas_expander->handle, (unsigned long long) - sas_expander->sas_address); - - kfree(sas_expander->phy); - kfree(sas_expander); -} - -/** - * _scsih_ir_shutdown - IR shutdown notification - * @ioc: per adapter object - * - * Sending RAID Action to alert the Integrated RAID subsystem of the IOC that - * the host system is shutting down. - * - * Return nothing. - */ -static void -_scsih_ir_shutdown(struct MPT2SAS_ADAPTER *ioc) -{ - Mpi2RaidActionRequest_t *mpi_request; - Mpi2RaidActionReply_t *mpi_reply; - u16 smid; - - /* is IR firmware build loaded ? */ - if (!ioc->ir_firmware) - return; - - /* are there any volumes ? */ - if (list_empty(&ioc->raid_device_list)) - return; - - mutex_lock(&ioc->scsih_cmds.mutex); - - if (ioc->scsih_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: scsih_cmd in use\n", - ioc->name, __func__); - goto out; - } - ioc->scsih_cmds.status = MPT2_CMD_PENDING; - - smid = mpt2sas_base_get_smid(ioc, ioc->scsih_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->scsih_cmds.smid = smid; - memset(mpi_request, 0, sizeof(Mpi2RaidActionRequest_t)); - - mpi_request->Function = MPI2_FUNCTION_RAID_ACTION; - mpi_request->Action = MPI2_RAID_ACTION_SYSTEM_SHUTDOWN_INITIATED; - - if (!ioc->hide_ir_msg) - printk(MPT2SAS_INFO_FMT "IR shutdown (sending)\n", ioc->name); - init_completion(&ioc->scsih_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - wait_for_completion_timeout(&ioc->scsih_cmds.done, 10*HZ); - - if (!(ioc->scsih_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - goto out; - } - - if (ioc->scsih_cmds.status & MPT2_CMD_REPLY_VALID) { - mpi_reply = ioc->scsih_cmds.reply; - - if (!ioc->hide_ir_msg) - printk(MPT2SAS_INFO_FMT "IR shutdown (complete): " - "ioc_status(0x%04x), loginfo(0x%08x)\n", - ioc->name, le16_to_cpu(mpi_reply->IOCStatus), - le32_to_cpu(mpi_reply->IOCLogInfo)); - } - - out: - ioc->scsih_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->scsih_cmds.mutex); -} - -/** - * _scsih_shutdown - routine call during system shutdown - * @pdev: PCI device struct - * - * Return nothing. - */ -static void -_scsih_shutdown(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct workqueue_struct *wq; - unsigned long flags; - - ioc->remove_host = 1; - _scsih_fw_event_cleanup_queue(ioc); - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - wq = ioc->firmware_event_thread; - ioc->firmware_event_thread = NULL; - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - if (wq) - destroy_workqueue(wq); - - _scsih_ir_shutdown(ioc); - mpt2sas_base_detach(ioc); -} - -/** - * _scsih_remove - detach and remove add host - * @pdev: PCI device struct - * - * Routine called when unloading the driver. - * Return nothing. - */ -static void __devexit -_scsih_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - struct _sas_port *mpt2sas_port, *next_port; - struct _raid_device *raid_device, *next; - struct MPT2SAS_TARGET *sas_target_priv_data; - struct workqueue_struct *wq; - unsigned long flags; - - ioc->remove_host = 1; - _scsih_fw_event_cleanup_queue(ioc); - - spin_lock_irqsave(&ioc->fw_event_lock, flags); - wq = ioc->firmware_event_thread; - ioc->firmware_event_thread = NULL; - spin_unlock_irqrestore(&ioc->fw_event_lock, flags); - if (wq) - destroy_workqueue(wq); - - /* release all the volumes */ - _scsih_ir_shutdown(ioc); - list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list, - list) { - if (raid_device->starget) { - sas_target_priv_data = - raid_device->starget->hostdata; - sas_target_priv_data->deleted = 1; - scsi_remove_target(&raid_device->starget->dev); - } - printk(MPT2SAS_INFO_FMT "removing handle(0x%04x), wwid" - "(0x%016llx)\n", ioc->name, raid_device->handle, - (unsigned long long) raid_device->wwid); - _scsih_raid_device_remove(ioc, raid_device); - } - - /* free ports attached to the sas_host */ - list_for_each_entry_safe(mpt2sas_port, next_port, - &ioc->sas_hba.sas_port_list, port_list) { - if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) - mpt2sas_device_remove(ioc, - mpt2sas_port->remote_identify.sas_address); - else if (mpt2sas_port->remote_identify.device_type == - SAS_EDGE_EXPANDER_DEVICE || - mpt2sas_port->remote_identify.device_type == - SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, - mpt2sas_port->remote_identify.sas_address); - } - - /* free phys attached to the sas_host */ - if (ioc->sas_hba.num_phys) { - kfree(ioc->sas_hba.phy); - ioc->sas_hba.phy = NULL; - ioc->sas_hba.num_phys = 0; - } - - sas_remove_host(shost); - mpt2sas_base_detach(ioc); - list_del(&ioc->list); - scsi_remove_host(shost); - scsi_host_put(shost); -} - -/** - * _scsih_probe_boot_devices - reports 1st device - * @ioc: per adapter object - * - * If specified in bios page 2, this routine reports the 1st - * device scsi-ml or sas transport for persistent boot device - * purposes. Please refer to function _scsih_determine_boot_device() - */ -static void -_scsih_probe_boot_devices(struct MPT2SAS_ADAPTER *ioc) -{ - u8 is_raid; - void *device; - struct _sas_device *sas_device; - struct _raid_device *raid_device; - u16 handle; - u64 sas_address_parent; - u64 sas_address; - unsigned long flags; - int rc; - - /* no Bios, return immediately */ - if (!ioc->bios_pg3.BiosVersion) - return; - - device = NULL; - is_raid = 0; - if (ioc->req_boot_device.device) { - device = ioc->req_boot_device.device; - is_raid = ioc->req_boot_device.is_raid; - } else if (ioc->req_alt_boot_device.device) { - device = ioc->req_alt_boot_device.device; - is_raid = ioc->req_alt_boot_device.is_raid; - } else if (ioc->current_boot_device.device) { - device = ioc->current_boot_device.device; - is_raid = ioc->current_boot_device.is_raid; - } - - if (!device) - return; - - if (is_raid) { - raid_device = device; - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - } else { - sas_device = device; - handle = sas_device->handle; - sas_address_parent = sas_device->sas_address_parent; - sas_address = sas_device->sas_address; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_move_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (ioc->hide_drives) - return; - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - _scsih_sas_device_remove(ioc, sas_device); - } else if (!sas_device->starget) { - if (!ioc->is_driver_loading) - mpt2sas_transport_port_remove(ioc, sas_address, - sas_address_parent); - _scsih_sas_device_remove(ioc, sas_device); - } - } -} - -/** - * _scsih_probe_raid - reporting raid volumes to scsi-ml - * @ioc: per adapter object - * - * Called during initial loading of the driver. - */ -static void -_scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc) -{ - struct _raid_device *raid_device, *raid_next; - int rc; - - list_for_each_entry_safe(raid_device, raid_next, - &ioc->raid_device_list, list) { - if (raid_device->starget) - continue; - rc = scsi_add_device(ioc->shost, RAID_CHANNEL, - raid_device->id, 0); - if (rc) - _scsih_raid_device_remove(ioc, raid_device); - } -} - -/** - * _scsih_probe_sas - reporting sas devices to sas transport - * @ioc: per adapter object - * - * Called during initial loading of the driver. - */ -static void -_scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) -{ - struct _sas_device *sas_device, *next; - unsigned long flags; - - /* SAS Device List */ - list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, - list) { - - if (ioc->hide_drives) - continue; - - if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - list_del(&sas_device->list); - kfree(sas_device); - continue; - } else if (!sas_device->starget) { - if (!ioc->is_driver_loading) - mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - list_del(&sas_device->list); - kfree(sas_device); - continue; - - } - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_move_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - } -} - -/** - * _scsih_probe_devices - probing for devices - * @ioc: per adapter object - * - * Called during initial loading of the driver. - */ -static void -_scsih_probe_devices(struct MPT2SAS_ADAPTER *ioc) -{ - u16 volume_mapping_flags; - - if (!(ioc->facts.ProtocolFlags & MPI2_IOCFACTS_PROTOCOL_SCSI_INITIATOR)) - return; /* return when IOC doesn't support initiator mode */ - - _scsih_probe_boot_devices(ioc); - - if (ioc->ir_firmware) { - volume_mapping_flags = - le16_to_cpu(ioc->ioc_pg8.IRVolumeMappingFlags) & - MPI2_IOCPAGE8_IRFLAGS_MASK_VOLUME_MAPPING_MODE; - if (volume_mapping_flags == - MPI2_IOCPAGE8_IRFLAGS_LOW_VOLUME_MAPPING) { - _scsih_probe_raid(ioc); - _scsih_probe_sas(ioc); - } else { - _scsih_probe_sas(ioc); - _scsih_probe_raid(ioc); - } - } else - _scsih_probe_sas(ioc); -} - - -/** - * _scsih_scan_start - scsi lld callback for .scan_start - * @shost: SCSI host pointer - * - * The shost has the ability to discover targets on its own instead - * of scanning the entire bus. In our implemention, we will kick off - * firmware discovery. - */ -static void -_scsih_scan_start(struct Scsi_Host *shost) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int rc; - - if (diag_buffer_enable != -1 && diag_buffer_enable != 0) - mpt2sas_enable_diag_buffer(ioc, diag_buffer_enable); - - ioc->start_scan = 1; - rc = mpt2sas_port_enable(ioc); - - if (rc != 0) - printk(MPT2SAS_INFO_FMT "port enable: FAILED\n", ioc->name); -} - -/** - * _scsih_scan_finished - scsi lld callback for .scan_finished - * @shost: SCSI host pointer - * @time: elapsed time of the scan in jiffies - * - * This function will be called periodically until it returns 1 with the - * scsi_host and the elapsed time of the scan in jiffies. In our implemention, - * we wait for firmware discovery to complete, then return 1. - */ -static int -_scsih_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - if (time >= (300 * HZ)) { - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - printk(MPT2SAS_INFO_FMT "port enable: FAILED with timeout " - "(timeout=300s)\n", ioc->name); - ioc->is_driver_loading = 0; - return 1; - } - - if (ioc->start_scan) - return 0; - - if (ioc->start_scan_failed) { - printk(MPT2SAS_INFO_FMT "port enable: FAILED with " - "(ioc_status=0x%08x)\n", ioc->name, ioc->start_scan_failed); - ioc->is_driver_loading = 0; - ioc->wait_for_discovery_to_complete = 0; - ioc->remove_host = 1; - return 1; - } - - printk(MPT2SAS_INFO_FMT "port enable: SUCCESS\n", ioc->name); - ioc->base_cmds.status = MPT2_CMD_NOT_USED; - - if (ioc->wait_for_discovery_to_complete) { - ioc->wait_for_discovery_to_complete = 0; - _scsih_probe_devices(ioc); - } - mpt2sas_base_start_watchdog(ioc); - ioc->is_driver_loading = 0; - return 1; -} - - -/** - * _scsih_probe - attach and add scsi host - * @pdev: PCI device struct - * @id: pci device id - * - * Returns 0 success, anything else error. - */ -static int -_scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct MPT2SAS_ADAPTER *ioc; - struct Scsi_Host *shost; - - shost = scsi_host_alloc(&scsih_driver_template, - sizeof(struct MPT2SAS_ADAPTER)); - if (!shost) - return -ENODEV; - - /* init local params */ - ioc = shost_priv(shost); - memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER)); - INIT_LIST_HEAD(&ioc->list); - list_add_tail(&ioc->list, &mpt2sas_ioc_list); - ioc->shost = shost; - ioc->id = mpt_ids++; - sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id); - ioc->pdev = pdev; - if (id->device == MPI2_MFGPAGE_DEVID_SSS6200) { - ioc->is_warpdrive = 1; - ioc->hide_ir_msg = 1; - } else - ioc->mfg_pg10_hide_flag = MFG_PAGE10_EXPOSE_ALL_DISKS; - ioc->scsi_io_cb_idx = scsi_io_cb_idx; - ioc->tm_cb_idx = tm_cb_idx; - ioc->ctl_cb_idx = ctl_cb_idx; - ioc->base_cb_idx = base_cb_idx; - ioc->port_enable_cb_idx = port_enable_cb_idx; - ioc->transport_cb_idx = transport_cb_idx; - ioc->scsih_cb_idx = scsih_cb_idx; - ioc->config_cb_idx = config_cb_idx; - ioc->tm_tr_cb_idx = tm_tr_cb_idx; - ioc->tm_tr_volume_cb_idx = tm_tr_volume_cb_idx; - ioc->tm_sas_control_cb_idx = tm_sas_control_cb_idx; - ioc->logging_level = logging_level; - ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; - /* misc semaphores and spin locks */ - mutex_init(&ioc->reset_in_progress_mutex); - spin_lock_init(&ioc->ioc_reset_in_progress_lock); - spin_lock_init(&ioc->scsi_lookup_lock); - spin_lock_init(&ioc->sas_device_lock); - spin_lock_init(&ioc->sas_node_lock); - spin_lock_init(&ioc->fw_event_lock); - spin_lock_init(&ioc->raid_device_lock); - - INIT_LIST_HEAD(&ioc->sas_device_list); - INIT_LIST_HEAD(&ioc->sas_device_init_list); - INIT_LIST_HEAD(&ioc->sas_expander_list); - INIT_LIST_HEAD(&ioc->fw_event_list); - INIT_LIST_HEAD(&ioc->raid_device_list); - INIT_LIST_HEAD(&ioc->sas_hba.sas_port_list); - INIT_LIST_HEAD(&ioc->delayed_tr_list); - INIT_LIST_HEAD(&ioc->delayed_tr_volume_list); - - /* init shost parameters */ - shost->max_cmd_len = 32; - shost->max_lun = max_lun; - shost->transportt = mpt2sas_transport_template; - shost->unique_id = ioc->id; - - if (max_sectors != 0xFFFF) { - if (max_sectors < 64) { - shost->max_sectors = 64; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 8192. Assigning " - "value of 64.\n", ioc->name, max_sectors); - } else if (max_sectors > 32767) { - shost->max_sectors = 32767; - printk(MPT2SAS_WARN_FMT "Invalid value %d passed " - "for max_sectors, range is 64 to 8192. Assigning " - "default value of 32767.\n", ioc->name, - max_sectors); - } else { - shost->max_sectors = max_sectors & 0xFFFE; - printk(MPT2SAS_INFO_FMT "The max_sectors value is " - "set to %d\n", ioc->name, shost->max_sectors); - } - } - - if ((scsi_add_host(shost, &pdev->dev))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - list_del(&ioc->list); - goto out_add_shost_fail; - } - - scsi_host_set_prot(shost, SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE2_PROTECTION | SHOST_DIF_TYPE3_PROTECTION); - scsi_host_set_guard(shost, SHOST_DIX_GUARD_CRC); - - /* event thread */ - snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), - "fw_event%d", ioc->id); - ioc->firmware_event_thread = create_singlethread_workqueue( - ioc->firmware_event_name); - if (!ioc->firmware_event_thread) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_thread_fail; - } - - ioc->is_driver_loading = 1; - if ((mpt2sas_base_attach(ioc))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_attach_fail; - } - - if (ioc->is_warpdrive) { - if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_EXPOSE_ALL_DISKS) - ioc->hide_drives = 0; - else if (ioc->mfg_pg10_hide_flag == MFG_PAGE10_HIDE_ALL_DISKS) - ioc->hide_drives = 1; - else { - if (_scsih_get_num_volumes(ioc)) - ioc->hide_drives = 1; - else - ioc->hide_drives = 0; - } - } else - ioc->hide_drives = 0; - scsi_scan_host(shost); - - return 0; - - out_attach_fail: - destroy_workqueue(ioc->firmware_event_thread); - out_thread_fail: - list_del(&ioc->list); - scsi_remove_host(shost); - scsi_host_put(shost); - out_add_shost_fail: - return -ENODEV; -} - -#ifdef CONFIG_PM -/** - * _scsih_suspend - power management suspend main entry point - * @pdev: PCI device struct - * @state: PM state change to (usually PCI_D3) - * - * Returns 0 success, anything else error. - */ -static int -_scsih_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - pci_power_t device_state; - - mpt2sas_base_stop_watchdog(ioc); - scsi_block_requests(shost); - device_state = pci_choose_state(pdev, state); - printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, entering " - "operating state [D%d]\n", ioc->name, pdev, - pci_name(pdev), device_state); - - mpt2sas_base_free_resources(ioc); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, device_state); - return 0; -} - -/** - * _scsih_resume - power management resume main entry point - * @pdev: PCI device struct - * - * Returns 0 success, anything else error. - */ -static int -_scsih_resume(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - pci_power_t device_state = pdev->current_state; - int r; - - printk(MPT2SAS_INFO_FMT "pdev=0x%p, slot=%s, previous " - "operating state [D%d]\n", ioc->name, pdev, - pci_name(pdev), device_state); - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - ioc->pdev = pdev; - r = mpt2sas_base_map_resources(ioc); - if (r) - return r; - - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, SOFT_RESET); - scsi_unblock_requests(shost); - mpt2sas_base_start_watchdog(ioc); - return 0; -} -#endif /* CONFIG_PM */ - -/** - * _scsih_pci_error_detected - Called when a PCI error is detected. - * @pdev: PCI device struct - * @state: PCI channel state - * - * Description: Called when a PCI error is detected. - * - * Return value: - * PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT - */ -static pci_ers_result_t -_scsih_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: detected callback, state(%d)!!\n", - ioc->name, state); - - switch (state) { - case pci_channel_io_normal: - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - /* Fatal error, prepare for slot reset */ - ioc->pci_error_recovery = 1; - scsi_block_requests(ioc->shost); - mpt2sas_base_stop_watchdog(ioc); - mpt2sas_base_free_resources(ioc); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - /* Permanent error, prepare for device removal */ - ioc->pci_error_recovery = 1; - mpt2sas_base_stop_watchdog(ioc); - _scsih_flush_running_cmds(ioc); - return PCI_ERS_RESULT_DISCONNECT; - } - return PCI_ERS_RESULT_NEED_RESET; -} - -/** - * _scsih_pci_slot_reset - Called when PCI slot has been reset. - * @pdev: PCI device struct - * - * Description: This routine is called by the pci error recovery - * code after the PCI slot has been reset, just before we - * should resume normal operations. - */ -static pci_ers_result_t -_scsih_pci_slot_reset(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - int rc; - - printk(MPT2SAS_INFO_FMT "PCI error: slot reset callback!!\n", - ioc->name); - - ioc->pci_error_recovery = 0; - ioc->pdev = pdev; - pci_restore_state(pdev); - rc = mpt2sas_base_map_resources(ioc); - if (rc) - return PCI_ERS_RESULT_DISCONNECT; - - - rc = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - - printk(MPT2SAS_WARN_FMT "hard reset: %s\n", ioc->name, - (rc == 0) ? "success" : "failed"); - - if (!rc) - return PCI_ERS_RESULT_RECOVERED; - else - return PCI_ERS_RESULT_DISCONNECT; -} - -/** - * _scsih_pci_resume() - resume normal ops after PCI reset - * @pdev: pointer to PCI device - * - * Called when the error recovery driver tells us that its - * OK to resume normal operation. Use completion to allow - * halted scsi ops to resume. - */ -static void -_scsih_pci_resume(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: resume callback!!\n", ioc->name); - - pci_cleanup_aer_uncorrect_error_status(pdev); - mpt2sas_base_start_watchdog(ioc); - scsi_unblock_requests(ioc->shost); -} - -/** - * _scsih_pci_mmio_enabled - Enable MMIO and dump debug registers - * @pdev: pointer to PCI device - */ -static pci_ers_result_t -_scsih_pci_mmio_enabled(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - - printk(MPT2SAS_INFO_FMT "PCI error: mmio enabled callback!!\n", - ioc->name); - - /* TODO - dump whatever for debugging purposes */ - - /* Request a slot reset. */ - return PCI_ERS_RESULT_NEED_RESET; -} - -static struct pci_error_handlers _scsih_err_handler = { - .error_detected = _scsih_pci_error_detected, - .mmio_enabled = _scsih_pci_mmio_enabled, - .slot_reset = _scsih_pci_slot_reset, - .resume = _scsih_pci_resume, -}; - -static struct pci_driver scsih_driver = { - .name = MPT2SAS_DRIVER_NAME, - .id_table = scsih_pci_table, - .probe = _scsih_probe, - .remove = __devexit_p(_scsih_remove), - .shutdown = _scsih_shutdown, - .err_handler = &_scsih_err_handler, -#ifdef CONFIG_PM - .suspend = _scsih_suspend, - .resume = _scsih_resume, -#endif -}; - -/* raid transport support */ -static struct raid_function_template mpt2sas_raid_functions = { - .cookie = &scsih_driver_template, - .is_raid = _scsih_is_raid, - .get_resync = _scsih_get_resync, - .get_state = _scsih_get_state, -}; - -/** - * _scsih_init - main entry point for this driver. - * - * Returns 0 success, anything else error. - */ -static int __init -_scsih_init(void) -{ - int error; - - mpt_ids = 0; - printk(KERN_INFO "%s version %s loaded\n", MPT2SAS_DRIVER_NAME, - MPT2SAS_DRIVER_VERSION); - - mpt2sas_transport_template = - sas_attach_transport(&mpt2sas_transport_functions); - if (!mpt2sas_transport_template) - return -ENODEV; - /* raid transport support */ - mpt2sas_raid_template = raid_class_attach(&mpt2sas_raid_functions); - if (!mpt2sas_raid_template) { - sas_release_transport(mpt2sas_transport_template); - return -ENODEV; - } - - mpt2sas_base_initialize_callback_handler(); - - /* queuecommand callback hander */ - scsi_io_cb_idx = mpt2sas_base_register_callback_handler(_scsih_io_done); - - /* task management callback handler */ - tm_cb_idx = mpt2sas_base_register_callback_handler(_scsih_tm_done); - - /* base internal commands callback handler */ - base_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_base_done); - port_enable_cb_idx = mpt2sas_base_register_callback_handler( - mpt2sas_port_enable_done); - - /* transport internal commands callback handler */ - transport_cb_idx = mpt2sas_base_register_callback_handler( - mpt2sas_transport_done); - - /* scsih internal commands callback handler */ - scsih_cb_idx = mpt2sas_base_register_callback_handler(_scsih_done); - - /* configuration page API internal commands callback handler */ - config_cb_idx = mpt2sas_base_register_callback_handler( - mpt2sas_config_done); - - /* ctl module callback handler */ - ctl_cb_idx = mpt2sas_base_register_callback_handler(mpt2sas_ctl_done); - - tm_tr_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_tm_tr_complete); - - tm_tr_volume_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_tm_volume_tr_complete); - - tm_sas_control_cb_idx = mpt2sas_base_register_callback_handler( - _scsih_sas_control_complete); - - mpt2sas_ctl_init(); - - error = pci_register_driver(&scsih_driver); - if (error) { - /* raid transport support */ - raid_class_release(mpt2sas_raid_template); - sas_release_transport(mpt2sas_transport_template); - } - - return error; -} - -/** - * _scsih_exit - exit point for this driver (when it is a module). - * - * Returns 0 success, anything else error. - */ -static void __exit -_scsih_exit(void) -{ - printk(KERN_INFO "mpt2sas version %s unloading\n", - MPT2SAS_DRIVER_VERSION); - - pci_unregister_driver(&scsih_driver); - - mpt2sas_ctl_exit(); - - mpt2sas_base_release_callback_handler(scsi_io_cb_idx); - mpt2sas_base_release_callback_handler(tm_cb_idx); - mpt2sas_base_release_callback_handler(base_cb_idx); - mpt2sas_base_release_callback_handler(port_enable_cb_idx); - mpt2sas_base_release_callback_handler(transport_cb_idx); - mpt2sas_base_release_callback_handler(scsih_cb_idx); - mpt2sas_base_release_callback_handler(config_cb_idx); - mpt2sas_base_release_callback_handler(ctl_cb_idx); - - mpt2sas_base_release_callback_handler(tm_tr_cb_idx); - mpt2sas_base_release_callback_handler(tm_tr_volume_cb_idx); - mpt2sas_base_release_callback_handler(tm_sas_control_cb_idx); - - /* raid transport support */ - raid_class_release(mpt2sas_raid_template); - sas_release_transport(mpt2sas_transport_template); - -} - -module_init(_scsih_init); -module_exit(_scsih_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_transport.c b/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_transport.c deleted file mode 100644 index 83104746..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ /dev/null @@ -1,2022 +0,0 @@ -/* - * SAS Transport Layer for MPT (Message Passing Technology) based controllers - * - * This code is based on drivers/scsi/mpt2sas/mpt2_transport.c - * Copyright (C) 2007-2010 LSI Corporation - * (mailto:DL-MPTFusionLinux@lsi.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "mpt2sas_base.h" -/** - * _transport_sas_node_find_by_sas_address - sas node search - * @ioc: per adapter object - * @sas_address: sas address of expander or sas host - * Context: Calling function should acquire ioc->sas_node_lock. - * - * Search for either hba phys or expander device based on handle, then returns - * the sas_node object. - */ -static struct _sas_node * -_transport_sas_node_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address) -{ - if (ioc->sas_hba.sas_address == sas_address) - return &ioc->sas_hba; - else - return mpt2sas_scsih_expander_find_by_sas_address(ioc, - sas_address); -} - -/** - * _transport_convert_phy_link_rate - - * @link_rate: link rate returned from mpt firmware - * - * Convert link_rate from mpi fusion into sas_transport form. - */ -static enum sas_linkrate -_transport_convert_phy_link_rate(u8 link_rate) -{ - enum sas_linkrate rc; - - switch (link_rate) { - case MPI2_SAS_NEG_LINK_RATE_1_5: - rc = SAS_LINK_RATE_1_5_GBPS; - break; - case MPI2_SAS_NEG_LINK_RATE_3_0: - rc = SAS_LINK_RATE_3_0_GBPS; - break; - case MPI2_SAS_NEG_LINK_RATE_6_0: - rc = SAS_LINK_RATE_6_0_GBPS; - break; - case MPI2_SAS_NEG_LINK_RATE_PHY_DISABLED: - rc = SAS_PHY_DISABLED; - break; - case MPI2_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED: - rc = SAS_LINK_RATE_FAILED; - break; - case MPI2_SAS_NEG_LINK_RATE_PORT_SELECTOR: - rc = SAS_SATA_PORT_SELECTOR; - break; - case MPI2_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS: - rc = SAS_PHY_RESET_IN_PROGRESS; - break; - default: - case MPI2_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE: - case MPI2_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE: - rc = SAS_LINK_RATE_UNKNOWN; - break; - } - return rc; -} - -/** - * _transport_set_identify - set identify for phys and end devices - * @ioc: per adapter object - * @handle: device handle - * @identify: sas identify info - * - * Populates sas identify info. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_set_identify(struct MPT2SAS_ADAPTER *ioc, u16 handle, - struct sas_identify *identify) -{ - Mpi2SasDevicePage0_t sas_device_pg0; - Mpi2ConfigReply_t mpi_reply; - u32 device_info; - u32 ioc_status; - - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, - MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - - ioc->name, __FILE__, __LINE__, __func__); - return -ENXIO; - } - - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "handle(0x%04x), ioc_status(0x%04x)" - "\nfailure at %s:%d/%s()!\n", ioc->name, handle, ioc_status, - __FILE__, __LINE__, __func__); - return -EIO; - } - - memset(identify, 0, sizeof(*identify)); - device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); - - /* sas_address */ - identify->sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - - /* device_type */ - switch (device_info & MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) { - case MPI2_SAS_DEVICE_INFO_NO_DEVICE: - identify->device_type = SAS_PHY_UNUSED; - break; - case MPI2_SAS_DEVICE_INFO_END_DEVICE: - identify->device_type = SAS_END_DEVICE; - break; - case MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER: - identify->device_type = SAS_EDGE_EXPANDER_DEVICE; - break; - case MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER: - identify->device_type = SAS_FANOUT_EXPANDER_DEVICE; - break; - } - - /* initiator_port_protocols */ - if (device_info & MPI2_SAS_DEVICE_INFO_SSP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; - if (device_info & MPI2_SAS_DEVICE_INFO_STP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_STP; - if (device_info & MPI2_SAS_DEVICE_INFO_SMP_INITIATOR) - identify->initiator_port_protocols |= SAS_PROTOCOL_SMP; - if (device_info & MPI2_SAS_DEVICE_INFO_SATA_HOST) - identify->initiator_port_protocols |= SAS_PROTOCOL_SATA; - - /* target_port_protocols */ - if (device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_SSP; - if (device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_STP; - if (device_info & MPI2_SAS_DEVICE_INFO_SMP_TARGET) - identify->target_port_protocols |= SAS_PROTOCOL_SMP; - if (device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - identify->target_port_protocols |= SAS_PROTOCOL_SATA; - - return 0; -} - -/** - * mpt2sas_transport_done - internal transport layer callback handler. - * @ioc: per adapter object - * @smid: system request message index - * @msix_index: MSIX table index supplied by the OS - * @reply: reply message frame(lower 32bit addr) - * - * Callback handler when sending internal generated transport cmds. - * The callback index passed is `ioc->transport_cb_idx` - * - * Return 1 meaning mf should be freed from _base_interrupt - * 0 means the mf is freed from this function. - */ -u8 -mpt2sas_transport_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, - u32 reply) -{ - MPI2DefaultReply_t *mpi_reply; - - mpi_reply = mpt2sas_base_get_reply_virt_addr(ioc, reply); - if (ioc->transport_cmds.status == MPT2_CMD_NOT_USED) - return 1; - if (ioc->transport_cmds.smid != smid) - return 1; - ioc->transport_cmds.status |= MPT2_CMD_COMPLETE; - if (mpi_reply) { - memcpy(ioc->transport_cmds.reply, mpi_reply, - mpi_reply->MsgLength*4); - ioc->transport_cmds.status |= MPT2_CMD_REPLY_VALID; - } - ioc->transport_cmds.status &= ~MPT2_CMD_PENDING; - complete(&ioc->transport_cmds.done); - return 1; -} - -/* report manufacture request structure */ -struct rep_manu_request{ - u8 smp_frame_type; - u8 function; - u8 reserved; - u8 request_length; -}; - -/* report manufacture reply structure */ -struct rep_manu_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x01 */ - u8 function_result; - u8 response_length; - u16 expander_change_count; - u8 reserved0[2]; - u8 sas_format; - u8 reserved2[3]; - u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN]; - u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN]; - u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN]; - u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN]; - u16 component_id; - u8 component_revision_id; - u8 reserved3; - u8 vendor_specific[8]; -}; - -/** - * _transport_expander_report_manufacture - obtain SMP report_manufacture - * @ioc: per adapter object - * @sas_address: expander sas address - * @edev: the sas_expander_device object - * - * Fills in the sas_expander_device object when SMP port is created. - * - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_expander_report_manufacture(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address, struct sas_expander_device *edev) -{ - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - struct rep_manu_reply *manufacture_reply; - struct rep_manu_request *manufacture_request; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); - - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - rc = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - - manufacture_request = data_out; - manufacture_request->smp_frame_type = 0x40; - manufacture_request->function = 1; - manufacture_request->reserved = 0; - manufacture_request->request_length = 0; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(sizeof(struct rep_manu_request)); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct rep_manu_request), data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct rep_manu_reply), data_out_dma + - sizeof(struct rep_manu_request)); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - " - "send to sas_addr(0x%016llx)\n", ioc->name, - (unsigned long long)sas_address)); - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "report_manufacture - " - "complete\n", ioc->name)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - u8 *tmp; - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "report_manufacture - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); - - if (le16_to_cpu(mpi_reply->ResponseDataLength) != - sizeof(struct rep_manu_reply)) - goto out; - - manufacture_reply = data_out + sizeof(struct rep_manu_request); - strncpy(edev->vendor_id, manufacture_reply->vendor_id, - SAS_EXPANDER_VENDOR_ID_LEN); - strncpy(edev->product_id, manufacture_reply->product_id, - SAS_EXPANDER_PRODUCT_ID_LEN); - strncpy(edev->product_rev, manufacture_reply->product_rev, - SAS_EXPANDER_PRODUCT_REV_LEN); - edev->level = manufacture_reply->sas_format & 1; - if (edev->level) { - strncpy(edev->component_vendor_id, - manufacture_reply->component_vendor_id, - SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); - tmp = (u8 *)&manufacture_reply->component_id; - edev->component_id = tmp[0] << 8 | tmp[1]; - edev->component_revision_id = - manufacture_reply->component_revision_id; - } - } else - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "report_manufacture - no reply\n", ioc->name)); - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); - - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -/** - * _transport_delete_port - helper function to removing a port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * - * Returns nothing. - */ -static void -_transport_delete_port(struct MPT2SAS_ADAPTER *ioc, - struct _sas_port *mpt2sas_port) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - enum sas_device_type device_type = - mpt2sas_port->remote_identify.device_type; - - dev_printk(KERN_INFO, &mpt2sas_port->port->dev, - "remove: sas_addr(0x%016llx)\n", - (unsigned long long) sas_address); - - ioc->logging_level |= MPT_DEBUG_TRANSPORT; - if (device_type == SAS_END_DEVICE) - mpt2sas_device_remove(ioc, sas_address); - else if (device_type == SAS_EDGE_EXPANDER_DEVICE || - device_type == SAS_FANOUT_EXPANDER_DEVICE) - mpt2sas_expander_remove(ioc, sas_address); - ioc->logging_level &= ~MPT_DEBUG_TRANSPORT; -} - -/** - * _transport_delete_phy - helper function to removing single phy from port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_delete_phy(struct MPT2SAS_ADAPTER *ioc, - struct _sas_port *mpt2sas_port, struct _sas_phy *mpt2sas_phy) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - - dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "remove: sas_addr(0x%016llx), phy(%d)\n", - (unsigned long long) sas_address, mpt2sas_phy->phy_id); - - list_del(&mpt2sas_phy->port_siblings); - mpt2sas_port->num_phys--; - sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); - mpt2sas_phy->phy_belongs_to_port = 0; -} - -/** - * _transport_add_phy - helper function to adding single phy to port - * @ioc: per adapter object - * @mpt2sas_port: mpt2sas per port object - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_add_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_port *mpt2sas_port, - struct _sas_phy *mpt2sas_phy) -{ - u64 sas_address = mpt2sas_port->remote_identify.sas_address; - - dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "add: sas_addr(0x%016llx), phy(%d)\n", (unsigned long long) - sas_address, mpt2sas_phy->phy_id); - - list_add_tail(&mpt2sas_phy->port_siblings, &mpt2sas_port->phy_list); - mpt2sas_port->num_phys++; - sas_port_add_phy(mpt2sas_port->port, mpt2sas_phy->phy); - mpt2sas_phy->phy_belongs_to_port = 1; -} - -/** - * _transport_add_phy_to_an_existing_port - adding new phy to existing port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @mpt2sas_phy: mpt2sas per phy object - * @sas_address: sas address of device/expander were phy needs to be added to - * - * Returns nothing. - */ -static void -_transport_add_phy_to_an_existing_port(struct MPT2SAS_ADAPTER *ioc, -struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy, u64 sas_address) -{ - struct _sas_port *mpt2sas_port; - struct _sas_phy *phy_srch; - - if (mpt2sas_phy->phy_belongs_to_port == 1) - return; - - list_for_each_entry(mpt2sas_port, &sas_node->sas_port_list, - port_list) { - if (mpt2sas_port->remote_identify.sas_address != - sas_address) - continue; - list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, - port_siblings) { - if (phy_srch == mpt2sas_phy) - return; - } - _transport_add_phy(ioc, mpt2sas_port, mpt2sas_phy); - return; - } - -} - -/** - * _transport_del_phy_from_an_existing_port - delete phy from existing port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @mpt2sas_phy: mpt2sas per phy object - * - * Returns nothing. - */ -static void -_transport_del_phy_from_an_existing_port(struct MPT2SAS_ADAPTER *ioc, - struct _sas_node *sas_node, struct _sas_phy *mpt2sas_phy) -{ - struct _sas_port *mpt2sas_port, *next; - struct _sas_phy *phy_srch; - - if (mpt2sas_phy->phy_belongs_to_port == 0) - return; - - list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, - port_list) { - list_for_each_entry(phy_srch, &mpt2sas_port->phy_list, - port_siblings) { - if (phy_srch != mpt2sas_phy) - continue; - if (mpt2sas_port->num_phys == 1) - _transport_delete_port(ioc, mpt2sas_port); - else - _transport_delete_phy(ioc, mpt2sas_port, - mpt2sas_phy); - return; - } - } -} - -/** - * _transport_sanity_check - sanity check when adding a new port - * @ioc: per adapter object - * @sas_node: sas node object (either expander or sas host) - * @sas_address: sas address of device being added - * - * See the explanation above from _transport_delete_duplicate_port - */ -static void -_transport_sanity_check(struct MPT2SAS_ADAPTER *ioc, struct _sas_node *sas_node, - u64 sas_address) -{ - int i; - - for (i = 0; i < sas_node->num_phys; i++) { - if (sas_node->phy[i].remote_identify.sas_address != sas_address) - continue; - if (sas_node->phy[i].phy_belongs_to_port == 1) - _transport_del_phy_from_an_existing_port(ioc, sas_node, - &sas_node->phy[i]); - } -} - -/** - * mpt2sas_transport_port_add - insert port to the list - * @ioc: per adapter object - * @handle: handle of attached device - * @sas_address: sas address of parent expander or sas host - * Context: This function will acquire ioc->sas_node_lock. - * - * Adding new port object to the sas_node->sas_port_list. - * - * Returns mpt2sas_port. - */ -struct _sas_port * -mpt2sas_transport_port_add(struct MPT2SAS_ADAPTER *ioc, u16 handle, - u64 sas_address) -{ - struct _sas_phy *mpt2sas_phy, *next; - struct _sas_port *mpt2sas_port; - unsigned long flags; - struct _sas_node *sas_node; - struct sas_rphy *rphy; - int i; - struct sas_port *port; - - mpt2sas_port = kzalloc(sizeof(struct _sas_port), - GFP_KERNEL); - if (!mpt2sas_port) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return NULL; - } - - INIT_LIST_HEAD(&mpt2sas_port->port_list); - INIT_LIST_HEAD(&mpt2sas_port->phy_list); - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (!sas_node) { - printk(MPT2SAS_ERR_FMT "%s: Could not find " - "parent sas_address(0x%016llx)!\n", ioc->name, - __func__, (unsigned long long)sas_address); - goto out_fail; - } - - if ((_transport_set_identify(ioc, handle, - &mpt2sas_port->remote_identify))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_fail; - } - - if (mpt2sas_port->remote_identify.device_type == SAS_PHY_UNUSED) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_fail; - } - - _transport_sanity_check(ioc, sas_node, - mpt2sas_port->remote_identify.sas_address); - - for (i = 0; i < sas_node->num_phys; i++) { - if (sas_node->phy[i].remote_identify.sas_address != - mpt2sas_port->remote_identify.sas_address) - continue; - list_add_tail(&sas_node->phy[i].port_siblings, - &mpt2sas_port->phy_list); - mpt2sas_port->num_phys++; - } - - if (!mpt2sas_port->num_phys) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_fail; - } - - port = sas_port_alloc_num(sas_node->parent_dev); - if ((sas_port_add(port))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - goto out_fail; - } - - list_for_each_entry(mpt2sas_phy, &mpt2sas_port->phy_list, - port_siblings) { - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &port->dev, "add: handle(0x%04x)" - ", sas_addr(0x%016llx), phy(%d)\n", handle, - (unsigned long long) - mpt2sas_port->remote_identify.sas_address, - mpt2sas_phy->phy_id); - sas_port_add_phy(port, mpt2sas_phy->phy); - mpt2sas_phy->phy_belongs_to_port = 1; - } - - mpt2sas_port->port = port; - if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) - rphy = sas_end_device_alloc(port); - else - rphy = sas_expander_alloc(port, - mpt2sas_port->remote_identify.device_type); - - rphy->identify = mpt2sas_port->remote_identify; - if ((sas_rphy_add(rphy))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - } - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), " - "sas_addr(0x%016llx)\n", handle, - (unsigned long long) - mpt2sas_port->remote_identify.sas_address); - mpt2sas_port->rphy = rphy; - spin_lock_irqsave(&ioc->sas_node_lock, flags); - list_add_tail(&mpt2sas_port->port_list, &sas_node->sas_port_list); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* fill in report manufacture */ - if (mpt2sas_port->remote_identify.device_type == - MPI2_SAS_DEVICE_INFO_EDGE_EXPANDER || - mpt2sas_port->remote_identify.device_type == - MPI2_SAS_DEVICE_INFO_FANOUT_EXPANDER) - _transport_expander_report_manufacture(ioc, - mpt2sas_port->remote_identify.sas_address, - rphy_to_expander_device(rphy)); - - return mpt2sas_port; - - out_fail: - list_for_each_entry_safe(mpt2sas_phy, next, &mpt2sas_port->phy_list, - port_siblings) - list_del(&mpt2sas_phy->port_siblings); - kfree(mpt2sas_port); - return NULL; -} - -/** - * mpt2sas_transport_port_remove - remove port from the list - * @ioc: per adapter object - * @sas_address: sas address of attached device - * @sas_address_parent: sas address of parent expander or sas host - * Context: This function will acquire ioc->sas_node_lock. - * - * Removing object and freeing associated memory from the - * ioc->sas_port_list. - * - * Return nothing. - */ -void -mpt2sas_transport_port_remove(struct MPT2SAS_ADAPTER *ioc, u64 sas_address, - u64 sas_address_parent) -{ - int i; - unsigned long flags; - struct _sas_port *mpt2sas_port, *next; - struct _sas_node *sas_node; - u8 found = 0; - struct _sas_phy *mpt2sas_phy, *next_phy; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, - sas_address_parent); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!sas_node) - return; - list_for_each_entry_safe(mpt2sas_port, next, &sas_node->sas_port_list, - port_list) { - if (mpt2sas_port->remote_identify.sas_address != sas_address) - continue; - found = 1; - list_del(&mpt2sas_port->port_list); - goto out; - } - out: - if (!found) - return; - - for (i = 0; i < sas_node->num_phys; i++) { - if (sas_node->phy[i].remote_identify.sas_address == sas_address) - memset(&sas_node->phy[i].remote_identify, 0 , - sizeof(struct sas_identify)); - } - - list_for_each_entry_safe(mpt2sas_phy, next_phy, - &mpt2sas_port->phy_list, port_siblings) { - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &mpt2sas_port->port->dev, - "remove: sas_addr(0x%016llx), phy(%d)\n", - (unsigned long long) - mpt2sas_port->remote_identify.sas_address, - mpt2sas_phy->phy_id); - mpt2sas_phy->phy_belongs_to_port = 0; - sas_port_delete_phy(mpt2sas_port->port, mpt2sas_phy->phy); - list_del(&mpt2sas_phy->port_siblings); - } - sas_port_delete(mpt2sas_port->port); - kfree(mpt2sas_port); -} - -/** - * mpt2sas_transport_add_host_phy - report sas_host phy to transport - * @ioc: per adapter object - * @mpt2sas_phy: mpt2sas per phy object - * @phy_pg0: sas phy page 0 - * @parent_dev: parent device class object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_transport_add_host_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy - *mpt2sas_phy, Mpi2SasPhyPage0_t phy_pg0, struct device *parent_dev) -{ - struct sas_phy *phy; - int phy_index = mpt2sas_phy->phy_id; - - - INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); - phy = sas_phy_alloc(parent_dev, phy_index); - if (!phy) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - if ((_transport_set_identify(ioc, mpt2sas_phy->handle, - &mpt2sas_phy->identify))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - phy->identify = mpt2sas_phy->identify; - mpt2sas_phy->attached_handle = le16_to_cpu(phy_pg0.AttachedDevHandle); - if (mpt2sas_phy->attached_handle) - _transport_set_identify(ioc, mpt2sas_phy->attached_handle, - &mpt2sas_phy->remote_identify); - phy->identify.phy_identifier = mpt2sas_phy->phy_id; - phy->negotiated_linkrate = _transport_convert_phy_link_rate( - phy_pg0.NegotiatedLinkRate & MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); - phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( - phy_pg0.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); - phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( - phy_pg0.HwLinkRate >> 4); - phy->minimum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); - phy->maximum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate >> 4); - - if ((sas_phy_add(phy))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - sas_phy_free(phy); - return -1; - } - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &phy->dev, - "add: handle(0x%04x), sas_addr(0x%016llx)\n" - "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", - mpt2sas_phy->handle, (unsigned long long) - mpt2sas_phy->identify.sas_address, - mpt2sas_phy->attached_handle, - (unsigned long long) - mpt2sas_phy->remote_identify.sas_address); - mpt2sas_phy->phy = phy; - return 0; -} - - -/** - * mpt2sas_transport_add_expander_phy - report expander phy to transport - * @ioc: per adapter object - * @mpt2sas_phy: mpt2sas per phy object - * @expander_pg1: expander page 1 - * @parent_dev: parent device class object - * - * Returns 0 for success, non-zero for failure. - */ -int -mpt2sas_transport_add_expander_phy(struct MPT2SAS_ADAPTER *ioc, struct _sas_phy - *mpt2sas_phy, Mpi2ExpanderPage1_t expander_pg1, struct device *parent_dev) -{ - struct sas_phy *phy; - int phy_index = mpt2sas_phy->phy_id; - - INIT_LIST_HEAD(&mpt2sas_phy->port_siblings); - phy = sas_phy_alloc(parent_dev, phy_index); - if (!phy) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - if ((_transport_set_identify(ioc, mpt2sas_phy->handle, - &mpt2sas_phy->identify))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -1; - } - phy->identify = mpt2sas_phy->identify; - mpt2sas_phy->attached_handle = - le16_to_cpu(expander_pg1.AttachedDevHandle); - if (mpt2sas_phy->attached_handle) - _transport_set_identify(ioc, mpt2sas_phy->attached_handle, - &mpt2sas_phy->remote_identify); - phy->identify.phy_identifier = mpt2sas_phy->phy_id; - phy->negotiated_linkrate = _transport_convert_phy_link_rate( - expander_pg1.NegotiatedLinkRate & - MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); - phy->minimum_linkrate_hw = _transport_convert_phy_link_rate( - expander_pg1.HwLinkRate & MPI2_SAS_HWRATE_MIN_RATE_MASK); - phy->maximum_linkrate_hw = _transport_convert_phy_link_rate( - expander_pg1.HwLinkRate >> 4); - phy->minimum_linkrate = _transport_convert_phy_link_rate( - expander_pg1.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); - phy->maximum_linkrate = _transport_convert_phy_link_rate( - expander_pg1.ProgrammedLinkRate >> 4); - - if ((sas_phy_add(phy))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - sas_phy_free(phy); - return -1; - } - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &phy->dev, - "add: handle(0x%04x), sas_addr(0x%016llx)\n" - "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", - mpt2sas_phy->handle, (unsigned long long) - mpt2sas_phy->identify.sas_address, - mpt2sas_phy->attached_handle, - (unsigned long long) - mpt2sas_phy->remote_identify.sas_address); - mpt2sas_phy->phy = phy; - return 0; -} - -/** - * mpt2sas_transport_update_links - refreshing phy link changes - * @ioc: per adapter object - * @sas_address: sas address of parent expander or sas host - * @handle: attached device handle - * @phy_numberv: phy number - * @link_rate: new link rate - * - * Returns nothing. - */ -void -mpt2sas_transport_update_links(struct MPT2SAS_ADAPTER *ioc, - u64 sas_address, u16 handle, u8 phy_number, u8 link_rate) -{ - unsigned long flags; - struct _sas_node *sas_node; - struct _sas_phy *mpt2sas_phy; - - if (ioc->shost_recovery || ioc->pci_error_recovery) - return; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - sas_node = _transport_sas_node_find_by_sas_address(ioc, sas_address); - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - if (!sas_node) - return; - - mpt2sas_phy = &sas_node->phy[phy_number]; - mpt2sas_phy->attached_handle = handle; - if (handle && (link_rate >= MPI2_SAS_NEG_LINK_RATE_1_5)) { - _transport_set_identify(ioc, handle, - &mpt2sas_phy->remote_identify); - _transport_add_phy_to_an_existing_port(ioc, sas_node, - mpt2sas_phy, mpt2sas_phy->remote_identify.sas_address); - } else - memset(&mpt2sas_phy->remote_identify, 0 , sizeof(struct - sas_identify)); - - if (mpt2sas_phy->phy) - mpt2sas_phy->phy->negotiated_linkrate = - _transport_convert_phy_link_rate(link_rate); - - if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) - dev_printk(KERN_INFO, &mpt2sas_phy->phy->dev, - "refresh: parent sas_addr(0x%016llx),\n" - "\tlink_rate(0x%02x), phy(%d)\n" - "\tattached_handle(0x%04x), sas_addr(0x%016llx)\n", - (unsigned long long)sas_address, - link_rate, phy_number, handle, (unsigned long long) - mpt2sas_phy->remote_identify.sas_address); -} - -static inline void * -phy_to_ioc(struct sas_phy *phy) -{ - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - return shost_priv(shost); -} - -static inline void * -rphy_to_ioc(struct sas_rphy *rphy) -{ - struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); - return shost_priv(shost); -} - - -/* report phy error log structure */ -struct phy_error_log_request{ - u8 smp_frame_type; /* 0x40 */ - u8 function; /* 0x11 */ - u8 allocated_response_length; - u8 request_length; /* 02 */ - u8 reserved_1[5]; - u8 phy_identifier; - u8 reserved_2[2]; -}; - -/* report phy error log reply structure */ -struct phy_error_log_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x11 */ - u8 function_result; - u8 response_length; - __be16 expander_change_count; - u8 reserved_1[3]; - u8 phy_identifier; - u8 reserved_2[2]; - __be32 invalid_dword; - __be32 running_disparity_error; - __be32 loss_of_dword_sync; - __be32 phy_reset_problem; -}; - -/** - * _transport_get_expander_phy_error_log - return expander counters - * @ioc: per adapter object - * @phy: The sas phy object - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_transport_get_expander_phy_error_log(struct MPT2SAS_ADAPTER *ioc, - struct sas_phy *phy) -{ - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - struct phy_error_log_request *phy_error_log_request; - struct phy_error_log_reply *phy_error_log_reply; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery || ioc->pci_error_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - sz = sizeof(struct phy_error_log_request) + - sizeof(struct phy_error_log_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - rc = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - - rc = -EINVAL; - memset(data_out, 0, sz); - phy_error_log_request = data_out; - phy_error_log_request->smp_frame_type = 0x40; - phy_error_log_request->function = 0x11; - phy_error_log_request->request_length = 2; - phy_error_log_request->allocated_response_length = 0; - phy_error_log_request->phy_identifier = phy->number; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(sizeof(struct phy_error_log_request)); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_error_log_request), data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_error_log_reply), data_out_dma + - sizeof(struct phy_error_log_request)); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " - "send to sas_addr(0x%016llx), phy(%d)\n", ioc->name, - (unsigned long long)phy->identify.sas_address, phy->number)); - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_error_log - " - "complete\n", ioc->name)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); - - if (le16_to_cpu(mpi_reply->ResponseDataLength) != - sizeof(struct phy_error_log_reply)) - goto out; - - phy_error_log_reply = data_out + - sizeof(struct phy_error_log_request); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - function_result(%d)\n", - ioc->name, phy_error_log_reply->function_result)); - - phy->invalid_dword_count = - be32_to_cpu(phy_error_log_reply->invalid_dword); - phy->running_disparity_error_count = - be32_to_cpu(phy_error_log_reply->running_disparity_error); - phy->loss_of_dword_sync_count = - be32_to_cpu(phy_error_log_reply->loss_of_dword_sync); - phy->phy_reset_problem_count = - be32_to_cpu(phy_error_log_reply->phy_reset_problem); - rc = 0; - } else - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_error_log - no reply\n", ioc->name)); - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); - - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -/** - * _transport_get_linkerrors - return phy counters for both hba and expanders - * @phy: The sas phy object - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_transport_get_linkerrors(struct sas_phy *phy) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - unsigned long flags; - Mpi2ConfigReply_t mpi_reply; - Mpi2SasPhyPage1_t phy_pg1; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_get_expander_phy_error_log(ioc, phy); - - /* get hba phy error logs */ - if ((mpt2sas_config_get_phy_pg1(ioc, &mpi_reply, &phy_pg1, - phy->number))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -ENXIO; - } - - if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) - printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status" - "(0x%04x), loginfo(0x%08x)\n", ioc->name, - phy->number, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo)); - - phy->invalid_dword_count = le32_to_cpu(phy_pg1.InvalidDwordCount); - phy->running_disparity_error_count = - le32_to_cpu(phy_pg1.RunningDisparityErrorCount); - phy->loss_of_dword_sync_count = - le32_to_cpu(phy_pg1.LossDwordSynchCount); - phy->phy_reset_problem_count = - le32_to_cpu(phy_pg1.PhyResetProblemCount); - return 0; -} - -/** - * _transport_get_enclosure_identifier - - * @phy: The sas phy object - * - * Obtain the enclosure logical id for an expander. - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) -{ - struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); - struct _sas_device *sas_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - rphy->identify.sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (!sas_device) - return -ENXIO; - - *identifier = sas_device->enclosure_logical_id; - return 0; -} - -/** - * _transport_get_bay_identifier - - * @phy: The sas phy object - * - * Returns the slot id for a device that resides inside an enclosure. - */ -static int -_transport_get_bay_identifier(struct sas_rphy *rphy) -{ - struct MPT2SAS_ADAPTER *ioc = rphy_to_ioc(rphy); - struct _sas_device *sas_device; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - rphy->identify.sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (!sas_device) - return -ENXIO; - - return sas_device->slot; -} - -/* phy control request structure */ -struct phy_control_request{ - u8 smp_frame_type; /* 0x40 */ - u8 function; /* 0x91 */ - u8 allocated_response_length; - u8 request_length; /* 0x09 */ - u16 expander_change_count; - u8 reserved_1[3]; - u8 phy_identifier; - u8 phy_operation; - u8 reserved_2[13]; - u64 attached_device_name; - u8 programmed_min_physical_link_rate; - u8 programmed_max_physical_link_rate; - u8 reserved_3[6]; -}; - -/* phy control reply structure */ -struct phy_control_reply{ - u8 smp_frame_type; /* 0x41 */ - u8 function; /* 0x11 */ - u8 function_result; - u8 response_length; -}; - -#define SMP_PHY_CONTROL_LINK_RESET (0x01) -#define SMP_PHY_CONTROL_HARD_RESET (0x02) -#define SMP_PHY_CONTROL_DISABLE (0x03) - -/** - * _transport_expander_phy_control - expander phy control - * @ioc: per adapter object - * @phy: The sas phy object - * - * Returns 0 for success, non-zero for failure. - * - */ -static int -_transport_expander_phy_control(struct MPT2SAS_ADAPTER *ioc, - struct sas_phy *phy, u8 phy_operation) -{ - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - struct phy_control_request *phy_control_request; - struct phy_control_reply *phy_control_reply; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - void *data_out = NULL; - dma_addr_t data_out_dma; - u32 sz; - u16 wait_state_count; - - if (ioc->shost_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - mutex_lock(&ioc->transport_cmds.mutex); - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - sz = sizeof(struct phy_control_request) + - sizeof(struct phy_control_reply); - data_out = pci_alloc_consistent(ioc->pdev, sz, &data_out_dma); - if (!data_out) { - printk(KERN_ERR "failure at %s:%d/%s()!\n", __FILE__, - __LINE__, __func__); - rc = -ENOMEM; - mpt2sas_base_free_smid(ioc, smid); - goto out; - } - - rc = -EINVAL; - memset(data_out, 0, sz); - phy_control_request = data_out; - phy_control_request->smp_frame_type = 0x40; - phy_control_request->function = 0x91; - phy_control_request->request_length = 9; - phy_control_request->allocated_response_length = 0; - phy_control_request->phy_identifier = phy->number; - phy_control_request->phy_operation = phy_operation; - phy_control_request->programmed_min_physical_link_rate = - phy->minimum_linkrate << 4; - phy_control_request->programmed_max_physical_link_rate = - phy->maximum_linkrate << 4; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = cpu_to_le64(phy->identify.sas_address); - mpi_request->RequestDataLength = - cpu_to_le16(sizeof(struct phy_error_log_request)); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_control_request), data_out_dma); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - ioc->base_add_sg_single(psge, sgl_flags | - sizeof(struct phy_control_reply), data_out_dma + - sizeof(struct phy_control_request)); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " - "send to sas_addr(0x%016llx), phy(%d), opcode(%d)\n", ioc->name, - (unsigned long long)phy->identify.sas_address, phy->number, - phy_operation)); - - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s: timeout\n", - ioc->name, __func__); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "phy_control - " - "complete\n", ioc->name)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - reply data transfer size(%d)\n", - ioc->name, le16_to_cpu(mpi_reply->ResponseDataLength))); - - if (le16_to_cpu(mpi_reply->ResponseDataLength) != - sizeof(struct phy_control_reply)) - goto out; - - phy_control_reply = data_out + - sizeof(struct phy_control_request); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - function_result(%d)\n", - ioc->name, phy_control_reply->function_result)); - - rc = 0; - } else - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "phy_control - no reply\n", ioc->name)); - - issue_host_reset: - if (issue_reset) - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - if (data_out) - pci_free_consistent(ioc->pdev, sz, data_out, data_out_dma); - - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -/** - * _transport_phy_reset - - * @phy: The sas phy object - * @hard_reset: - * - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_phy_reset(struct sas_phy *phy, int hard_reset) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - Mpi2SasIoUnitControlReply_t mpi_reply; - Mpi2SasIoUnitControlRequest_t mpi_request; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_expander_phy_control(ioc, phy, - (hard_reset == 1) ? SMP_PHY_CONTROL_HARD_RESET : - SMP_PHY_CONTROL_LINK_RESET); - - /* handle hba phys */ - memset(&mpi_request, 0, sizeof(Mpi2SasIoUnitControlReply_t)); - mpi_request.Function = MPI2_FUNCTION_SAS_IO_UNIT_CONTROL; - mpi_request.Operation = hard_reset ? - MPI2_SAS_OP_PHY_HARD_RESET : MPI2_SAS_OP_PHY_LINK_RESET; - mpi_request.PhyNum = phy->number; - - if ((mpt2sas_base_sas_iounit_control(ioc, &mpi_reply, &mpi_request))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return -ENXIO; - } - - if (mpi_reply.IOCStatus || mpi_reply.IOCLogInfo) - printk(MPT2SAS_INFO_FMT "phy(%d), ioc_status" - "(0x%04x), loginfo(0x%08x)\n", ioc->name, - phy->number, le16_to_cpu(mpi_reply.IOCStatus), - le32_to_cpu(mpi_reply.IOCLogInfo)); - - return 0; -} - -/** - * _transport_phy_enable - enable/disable phys - * @phy: The sas phy object - * @enable: enable phy when true - * - * Only support sas_host direct attached phys. - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_phy_enable(struct sas_phy *phy, int enable) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 sz; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) - return _transport_expander_phy_control(ioc, phy, - (enable == 1) ? SMP_PHY_CONTROL_LINK_RESET : - SMP_PHY_CONTROL_DISABLE); - - /* handle hba phys */ - - /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg1) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENOMEM; - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENXIO; - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -EIO; - goto out; - } - - if (enable) - sas_iounit_pg1->PhyData[phy->number].PhyFlags - &= ~MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; - else - sas_iounit_pg1->PhyData[phy->number].PhyFlags - |= MPI2_SASIOUNIT1_PHYFLAGS_PHY_DISABLE; - - mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, sz); - - /* link reset */ - if (enable) - _transport_phy_reset(phy, 0); - - out: - kfree(sas_iounit_pg1); - return rc; -} - -/** - * _transport_phy_speed - set phy min/max link rates - * @phy: The sas phy object - * @rates: rates defined in sas_phy_linkrates - * - * Only support sas_host direct attached phys. - * Returns 0 for success, non-zero for failure. - */ -static int -_transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) -{ - struct MPT2SAS_ADAPTER *ioc = phy_to_ioc(phy); - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; - Mpi2SasPhyPage0_t phy_pg0; - Mpi2ConfigReply_t mpi_reply; - u16 ioc_status; - u16 sz; - int i; - int rc = 0; - unsigned long flags; - - spin_lock_irqsave(&ioc->sas_node_lock, flags); - if (_transport_sas_node_find_by_sas_address(ioc, - phy->identify.sas_address) == NULL) { - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - return -EINVAL; - } - spin_unlock_irqrestore(&ioc->sas_node_lock, flags); - - if (!rates->minimum_linkrate) - rates->minimum_linkrate = phy->minimum_linkrate; - else if (rates->minimum_linkrate < phy->minimum_linkrate_hw) - rates->minimum_linkrate = phy->minimum_linkrate_hw; - - if (!rates->maximum_linkrate) - rates->maximum_linkrate = phy->maximum_linkrate; - else if (rates->maximum_linkrate > phy->maximum_linkrate_hw) - rates->maximum_linkrate = phy->maximum_linkrate_hw; - - /* handle expander phys */ - if (phy->identify.sas_address != ioc->sas_hba.sas_address) { - phy->minimum_linkrate = rates->minimum_linkrate; - phy->maximum_linkrate = rates->maximum_linkrate; - return _transport_expander_phy_control(ioc, phy, - SMP_PHY_CONTROL_LINK_RESET); - } - - /* handle hba phys */ - - /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); - sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); - if (!sas_iounit_pg1) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENOMEM; - goto out; - } - if ((mpt2sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz))) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENXIO; - goto out; - } - ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & - MPI2_IOCSTATUS_MASK; - if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -EIO; - goto out; - } - - for (i = 0; i < ioc->sas_hba.num_phys; i++) { - if (phy->number != i) { - sas_iounit_pg1->PhyData[i].MaxMinLinkRate = - (ioc->sas_hba.phy[i].phy->minimum_linkrate + - (ioc->sas_hba.phy[i].phy->maximum_linkrate << 4)); - } else { - sas_iounit_pg1->PhyData[i].MaxMinLinkRate = - (rates->minimum_linkrate + - (rates->maximum_linkrate << 4)); - } - } - - if (mpt2sas_config_set_sas_iounit_pg1(ioc, &mpi_reply, sas_iounit_pg1, - sz)) { - printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - rc = -ENXIO; - goto out; - } - - /* link reset */ - _transport_phy_reset(phy, 0); - - /* read phy page 0, then update the rates in the sas transport phy */ - if (!mpt2sas_config_get_phy_pg0(ioc, &mpi_reply, &phy_pg0, - phy->number)) { - phy->minimum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate & MPI2_SAS_PRATE_MIN_RATE_MASK); - phy->maximum_linkrate = _transport_convert_phy_link_rate( - phy_pg0.ProgrammedLinkRate >> 4); - phy->negotiated_linkrate = _transport_convert_phy_link_rate( - phy_pg0.NegotiatedLinkRate & - MPI2_SAS_NEG_LINK_RATE_MASK_PHYSICAL); - } - - out: - kfree(sas_iounit_pg1); - return rc; -} - - -/** - * _transport_smp_handler - transport portal for smp passthru - * @shost: shost object - * @rphy: sas transport rphy object - * @req: - * - * This used primarily for smp_utils. - * Example: - * smp_rep_general /sys/class/bsg/expander-5:0 - */ -static int -_transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, - struct request *req) -{ - struct MPT2SAS_ADAPTER *ioc = shost_priv(shost); - Mpi2SmpPassthroughRequest_t *mpi_request; - Mpi2SmpPassthroughReply_t *mpi_reply; - int rc; - u16 smid; - u32 ioc_state; - unsigned long timeleft; - void *psge; - u32 sgl_flags; - u8 issue_reset = 0; - dma_addr_t dma_addr_in = 0; - dma_addr_t dma_addr_out = 0; - u16 wait_state_count; - struct request *rsp = req->next_rq; - - if (!rsp) { - printk(MPT2SAS_ERR_FMT "%s: the smp response space is " - "missing\n", ioc->name, __func__); - return -EINVAL; - } - - /* do we need to support multiple segments? */ - if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) { - printk(MPT2SAS_ERR_FMT "%s: multiple segments req %u %u, " - "rsp %u %u\n", ioc->name, __func__, req->bio->bi_vcnt, - blk_rq_bytes(req), rsp->bio->bi_vcnt, blk_rq_bytes(rsp)); - return -EINVAL; - } - - if (ioc->shost_recovery) { - printk(MPT2SAS_INFO_FMT "%s: host reset in progress!\n", - __func__, ioc->name); - return -EFAULT; - } - - rc = mutex_lock_interruptible(&ioc->transport_cmds.mutex); - if (rc) - return rc; - - if (ioc->transport_cmds.status != MPT2_CMD_NOT_USED) { - printk(MPT2SAS_ERR_FMT "%s: transport_cmds in use\n", ioc->name, - __func__); - rc = -EAGAIN; - goto out; - } - ioc->transport_cmds.status = MPT2_CMD_PENDING; - - wait_state_count = 0; - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - while (ioc_state != MPI2_IOC_STATE_OPERATIONAL) { - if (wait_state_count++ == 10) { - printk(MPT2SAS_ERR_FMT - "%s: failed due to ioc not operational\n", - ioc->name, __func__); - rc = -EFAULT; - goto out; - } - ssleep(1); - ioc_state = mpt2sas_base_get_iocstate(ioc, 1); - printk(MPT2SAS_INFO_FMT "%s: waiting for " - "operational state(count=%d)\n", ioc->name, - __func__, wait_state_count); - } - if (wait_state_count) - printk(MPT2SAS_INFO_FMT "%s: ioc is operational\n", - ioc->name, __func__); - - smid = mpt2sas_base_get_smid(ioc, ioc->transport_cb_idx); - if (!smid) { - printk(MPT2SAS_ERR_FMT "%s: failed obtaining a smid\n", - ioc->name, __func__); - rc = -EAGAIN; - goto out; - } - - rc = 0; - mpi_request = mpt2sas_base_get_msg_frame(ioc, smid); - ioc->transport_cmds.smid = smid; - - memset(mpi_request, 0, sizeof(Mpi2SmpPassthroughRequest_t)); - mpi_request->Function = MPI2_FUNCTION_SMP_PASSTHROUGH; - mpi_request->PhysicalPort = 0xFF; - mpi_request->VF_ID = 0; /* TODO */ - mpi_request->VP_ID = 0; - mpi_request->SASAddress = (rphy) ? - cpu_to_le64(rphy->identify.sas_address) : - cpu_to_le64(ioc->sas_hba.sas_address); - mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4); - psge = &mpi_request->SGL; - - /* WRITE sgel first */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), - blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_out) { - mpt2sas_base_free_smid(ioc, smid); - goto unmap; - } - - ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(req) - 4), - dma_addr_out); - - /* incr sgel */ - psge += ioc->sge_size; - - /* READ sgel last */ - sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT | - MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER | - MPI2_SGE_FLAGS_END_OF_LIST); - sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT; - dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), - blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_in) { - mpt2sas_base_free_smid(ioc, smid); - goto unmap; - } - - ioc->base_add_sg_single(psge, sgl_flags | (blk_rq_bytes(rsp) + 4), - dma_addr_in); - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " - "sending smp request\n", ioc->name, __func__)); - - init_completion(&ioc->transport_cmds.done); - mpt2sas_base_put_smid_default(ioc, smid); - timeleft = wait_for_completion_timeout(&ioc->transport_cmds.done, - 10*HZ); - - if (!(ioc->transport_cmds.status & MPT2_CMD_COMPLETE)) { - printk(MPT2SAS_ERR_FMT "%s : timeout\n", - __func__, ioc->name); - _debug_dump_mf(mpi_request, - sizeof(Mpi2SmpPassthroughRequest_t)/4); - if (!(ioc->transport_cmds.status & MPT2_CMD_RESET)) - issue_reset = 1; - goto issue_host_reset; - } - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT "%s - " - "complete\n", ioc->name, __func__)); - - if (ioc->transport_cmds.status & MPT2_CMD_REPLY_VALID) { - - mpi_reply = ioc->transport_cmds.reply; - - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s - reply data transfer size(%d)\n", - ioc->name, __func__, - le16_to_cpu(mpi_reply->ResponseDataLength))); - - memcpy(req->sense, mpi_reply, sizeof(*mpi_reply)); - req->sense_len = sizeof(*mpi_reply); - req->resid_len = 0; - rsp->resid_len -= - le16_to_cpu(mpi_reply->ResponseDataLength); - } else { - dtransportprintk(ioc, printk(MPT2SAS_INFO_FMT - "%s - no reply\n", ioc->name, __func__)); - rc = -ENXIO; - } - - issue_host_reset: - if (issue_reset) { - mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP, - FORCE_BIG_HAMMER); - rc = -ETIMEDOUT; - } - - unmap: - if (dma_addr_out) - pci_unmap_single(ioc->pdev, dma_addr_out, blk_rq_bytes(req), - PCI_DMA_BIDIRECTIONAL); - if (dma_addr_in) - pci_unmap_single(ioc->pdev, dma_addr_in, blk_rq_bytes(rsp), - PCI_DMA_BIDIRECTIONAL); - - out: - ioc->transport_cmds.status = MPT2_CMD_NOT_USED; - mutex_unlock(&ioc->transport_cmds.mutex); - return rc; -} - -struct sas_function_template mpt2sas_transport_functions = { - .get_linkerrors = _transport_get_linkerrors, - .get_enclosure_identifier = _transport_get_enclosure_identifier, - .get_bay_identifier = _transport_get_bay_identifier, - .phy_reset = _transport_phy_reset, - .phy_enable = _transport_phy_enable, - .set_phy_speed = _transport_phy_speed, - .smp_handler = _transport_smp_handler, -}; - -struct scsi_transport_template *mpt2sas_transport_template; diff --git a/ANDROID_3.4.5/drivers/scsi/mvme147.c b/ANDROID_3.4.5/drivers/scsi/mvme147.c deleted file mode 100644 index c29d0dbb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvme147.c +++ /dev/null @@ -1,165 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "scsi.h" -#include -#include "wd33c93.h" -#include "mvme147.h" - -#include - - -static irqreturn_t mvme147_intr(int irq, void *data) -{ - struct Scsi_Host *instance = data; - - if (irq == MVME147_IRQ_SCSI_PORT) - wd33c93_intr(instance); - else - m147_pcc->dma_intr = 0x89; /* Ack and enable ints */ - return IRQ_HANDLED; -} - -static int dma_setup(struct scsi_cmnd *cmd, int dir_in) -{ - struct Scsi_Host *instance = cmd->device->host; - struct WD33C93_hostdata *hdata = shost_priv(instance); - unsigned char flags = 0x01; - unsigned long addr = virt_to_bus(cmd->SCp.ptr); - - /* setup dma direction */ - if (!dir_in) - flags |= 0x04; - - /* remember direction */ - hdata->dma_dir = dir_in; - - if (dir_in) { - /* invalidate any cache */ - cache_clear(addr, cmd->SCp.this_residual); - } else { - /* push any dirty cache */ - cache_push(addr, cmd->SCp.this_residual); - } - - /* start DMA */ - m147_pcc->dma_bcr = cmd->SCp.this_residual | (1 << 24); - m147_pcc->dma_dadr = addr; - m147_pcc->dma_cntrl = flags; - - /* return success */ - return 0; -} - -static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, - int status) -{ - m147_pcc->dma_cntrl = 0; -} - -int mvme147_detect(struct scsi_host_template *tpnt) -{ - static unsigned char called = 0; - struct Scsi_Host *instance; - wd33c93_regs regs; - struct WD33C93_hostdata *hdata; - - if (!MACH_IS_MVME147 || called) - return 0; - called++; - - tpnt->proc_name = "MVME147"; - tpnt->proc_info = &wd33c93_proc_info; - - instance = scsi_register(tpnt, sizeof(struct WD33C93_hostdata)); - if (!instance) - goto err_out; - - instance->base = 0xfffe4000; - instance->irq = MVME147_IRQ_SCSI_PORT; - regs.SASR = (volatile unsigned char *)0xfffe4000; - regs.SCMD = (volatile unsigned char *)0xfffe4001; - hdata = shost_priv(instance); - hdata->no_sync = 0xff; - hdata->fast = 0; - hdata->dma_mode = CTRL_DMA; - wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10); - - if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, - "MVME147 SCSI PORT", instance)) - goto err_unregister; - if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, - "MVME147 SCSI DMA", instance)) - goto err_free_irq; -#if 0 /* Disabled; causes problems booting */ - m147_pcc->scsi_interrupt = 0x10; /* Assert SCSI bus reset */ - udelay(100); - m147_pcc->scsi_interrupt = 0x00; /* Negate SCSI bus reset */ - udelay(2000); - m147_pcc->scsi_interrupt = 0x40; /* Clear bus reset interrupt */ -#endif - m147_pcc->scsi_interrupt = 0x09; /* Enable interrupt */ - - m147_pcc->dma_cntrl = 0x00; /* ensure DMA is stopped */ - m147_pcc->dma_intr = 0x89; /* Ack and enable ints */ - - return 1; - -err_free_irq: - free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); -err_unregister: - scsi_unregister(instance); -err_out: - return 0; -} - -static int mvme147_bus_reset(struct scsi_cmnd *cmd) -{ - /* FIXME perform bus-specific reset */ - - /* FIXME 2: kill this function, and let midlayer fallback to - the same result, calling wd33c93_host_reset() */ - - spin_lock_irq(cmd->device->host->host_lock); - wd33c93_host_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return SUCCESS; -} - - -static struct scsi_host_template driver_template = { - .proc_name = "MVME147", - .name = "MVME147 built-in SCSI", - .detect = mvme147_detect, - .release = mvme147_release, - .queuecommand = wd33c93_queuecommand, - .eh_abort_handler = wd33c93_abort, - .eh_bus_reset_handler = mvme147_bus_reset, - .eh_host_reset_handler = wd33c93_host_reset, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -int mvme147_release(struct Scsi_Host *instance) -{ -#ifdef MODULE - /* XXX Make sure DMA is stopped! */ - free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr); - free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr); -#endif - return 1; -} diff --git a/ANDROID_3.4.5/drivers/scsi/mvme147.h b/ANDROID_3.4.5/drivers/scsi/mvme147.h deleted file mode 100644 index bfd4566e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvme147.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MVME147_H - -/* $Id: mvme147.h,v 1.4 1997/01/19 23:07:10 davem Exp $ - * - * Header file for the MVME147 built-in SCSI controller for Linux - * - * Written and (C) 1993, Hamish Macdonald, see mvme147.c for more info - * - */ - -#include - -int mvme147_detect(struct scsi_host_template *); -int mvme147_release(struct Scsi_Host *); - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 16 -#endif - -#endif /* MVME147_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/mvme16x_scsi.c b/ANDROID_3.4.5/drivers/scsi/mvme16x_scsi.c deleted file mode 100644 index 39f554f5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvme16x_scsi.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux. - * - * Based on work by Alan Hourihane - * - * Rewritten to use 53c700.c by Kars de Jong - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "53c700.h" - -MODULE_AUTHOR("Kars de Jong "); -MODULE_DESCRIPTION("MVME16x NCR53C710 driver"); -MODULE_LICENSE("GPL"); - -static struct scsi_host_template mvme16x_scsi_driver_template = { - .name = "MVME16x NCR53c710 SCSI", - .proc_name = "MVME16x", - .this_id = 7, - .module = THIS_MODULE, -}; - -static struct platform_device *mvme16x_scsi_device; - -static __devinit int -mvme16x_probe(struct platform_device *dev) -{ - struct Scsi_Host * host = NULL; - struct NCR_700_Host_Parameters *hostdata; - - if (!MACH_IS_MVME16x) - goto out; - - if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) { - printk(KERN_INFO "mvme16x-scsi: detection disabled, " - "SCSI chip not present\n"); - goto out; - } - - hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); - if (hostdata == NULL) { - printk(KERN_ERR "mvme16x-scsi: " - "Failed to allocate host data\n"); - goto out; - } - - /* Fill in the required pieces of hostdata */ - hostdata->base = (void __iomem *)0xfff47000UL; - hostdata->clock = 50; /* XXX - depends on the CPU clock! */ - hostdata->chip710 = 1; - hostdata->dmode_extra = DMODE_FC2; - hostdata->dcntl_extra = EA_710; - hostdata->ctest7_extra = CTEST7_TT1; - - /* and register the chip */ - host = NCR_700_detect(&mvme16x_scsi_driver_template, hostdata, - &dev->dev); - if (!host) { - printk(KERN_ERR "mvme16x-scsi: No host detected; " - "board configuration problem?\n"); - goto out_free; - } - host->this_id = 7; - host->base = 0xfff47000UL; - host->irq = MVME16x_IRQ_SCSI; - if (request_irq(host->irq, NCR_700_intr, 0, "mvme16x-scsi", host)) { - printk(KERN_ERR "mvme16x-scsi: request_irq failed\n"); - goto out_put_host; - } - - /* Enable scsi chip ints */ - { - volatile unsigned long v; - - /* Enable scsi interrupts at level 4 in PCCchip2 */ - v = in_be32(0xfff4202c); - v = (v & ~0xff) | 0x10 | 4; - out_be32(0xfff4202c, v); - } - - platform_set_drvdata(dev, host); - scsi_scan_host(host); - - return 0; - - out_put_host: - scsi_host_put(host); - out_free: - kfree(hostdata); - out: - return -ENODEV; -} - -static __devexit int -mvme16x_device_remove(struct platform_device *dev) -{ - struct Scsi_Host *host = platform_get_drvdata(dev); - struct NCR_700_Host_Parameters *hostdata = shost_priv(host); - - /* Disable scsi chip ints */ - { - volatile unsigned long v; - - v = in_be32(0xfff4202c); - v &= ~0x10; - out_be32(0xfff4202c, v); - } - scsi_remove_host(host); - NCR_700_release(host); - kfree(hostdata); - free_irq(host->irq, host); - - return 0; -} - -static struct platform_driver mvme16x_scsi_driver = { - .driver = { - .name = "mvme16x-scsi", - .owner = THIS_MODULE, - }, - .probe = mvme16x_probe, - .remove = __devexit_p(mvme16x_device_remove), -}; - -static int __init mvme16x_scsi_init(void) -{ - int err; - - err = platform_driver_register(&mvme16x_scsi_driver); - if (err) - return err; - - mvme16x_scsi_device = platform_device_register_simple("mvme16x-scsi", - -1, NULL, 0); - if (IS_ERR(mvme16x_scsi_device)) { - platform_driver_unregister(&mvme16x_scsi_driver); - return PTR_ERR(mvme16x_scsi_device); - } - - return 0; -} - -static void __exit mvme16x_scsi_exit(void) -{ - platform_device_unregister(mvme16x_scsi_device); - platform_driver_unregister(&mvme16x_scsi_driver); -} - -module_init(mvme16x_scsi_init); -module_exit(mvme16x_scsi_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/Kconfig b/ANDROID_3.4.5/drivers/scsi/mvsas/Kconfig deleted file mode 100644 index 78f7e20a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -# -# Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver. -# -# Copyright 2007 Red Hat, Inc. -# Copyright 2008 Marvell. -# Copyright 2009-2011 Marvell. -# -# This file is licensed under GPLv2. -# -# This file is part of the 88SE64XX/88SE94XX driver. -# -# The 88SE64XX/88SE94XX driver is free software; you can redistribute -# it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; version 2 of the -# License. -# -# The 88SE64XX/88SE94XX driver is distributed in the hope that it will be -# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 88SE64XX/88SE94XX Driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# - -config SCSI_MVSAS - tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support" - depends on PCI - select SCSI_SAS_LIBSAS - select FW_LOADER - help - This driver supports Marvell's SAS/SATA 3Gb/s PCI-E 88SE64XX and 6Gb/s - PCI-E 88SE94XX chip based host adapters. - -config SCSI_MVSAS_DEBUG - bool "Compile in debug mode" - default y - depends on SCSI_MVSAS - help - Compiles the 88SE64XX/88SE94XX driver in debug mode. In debug mode, - the driver prints some messages to the console. -config SCSI_MVSAS_TASKLET - bool "Support for interrupt tasklet" - default n - depends on SCSI_MVSAS - help - Compiles the 88SE64xx/88SE94xx driver in interrupt tasklet mode.In this mode, - the interrupt will schedule a tasklet. diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/Makefile b/ANDROID_3.4.5/drivers/scsi/mvsas/Makefile deleted file mode 100644 index 87b231a5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# Makefile for Marvell 88SE64xx/88SE84xx SAS/SATA driver. -# -# Copyright 2007 Red Hat, Inc. -# Copyright 2008 Marvell. -# Copyright 2009-2011 Marvell. -# -# This file is licensed under GPLv2. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 of the -# License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA - -ccflags-$(CONFIG_SCSI_MVSAS_DEBUG) := -DMV_DEBUG - -obj-$(CONFIG_SCSI_MVSAS) += mvsas.o -mvsas-y += mv_init.o \ - mv_sas.o \ - mv_64xx.o \ - mv_94xx.o diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.c b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.c deleted file mode 100644 index 8ba47229..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.c +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Marvell 88SE64xx hardware specific - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - -#include "mv_sas.h" -#include "mv_64xx.h" -#include "mv_chips.h" - -static void mvs_64xx_detect_porttype(struct mvs_info *mvi, int i) -{ - void __iomem *regs = mvi->regs; - u32 reg; - struct mvs_phy *phy = &mvi->phy[i]; - - reg = mr32(MVS_GBL_PORT_TYPE); - phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); - if (reg & MODE_SAS_SATA & (1 << i)) - phy->phy_type |= PORT_TYPE_SAS; - else - phy->phy_type |= PORT_TYPE_SATA; -} - -static void __devinit mvs_64xx_enable_xmt(struct mvs_info *mvi, int phy_id) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - tmp = mr32(MVS_PCS); - if (mvi->chip->n_phy <= MVS_SOC_PORTS) - tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT); - else - tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); - mw32(MVS_PCS, tmp); -} - -static void __devinit mvs_64xx_phy_hacks(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - int i; - - mvs_phy_hacks(mvi); - - if (!(mvi->flags & MVF_FLAG_SOC)) { - for (i = 0; i < MVS_SOC_PORTS; i++) { - mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE8); - mvs_write_port_vsr_data(mvi, i, 0x2F0); - } - } else { - /* disable auto port detection */ - mw32(MVS_GBL_PORT_TYPE, 0); - for (i = 0; i < mvi->chip->n_phy; i++) { - mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE7); - mvs_write_port_vsr_data(mvi, i, 0x90000000); - mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE9); - mvs_write_port_vsr_data(mvi, i, 0x50f2); - mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE11); - mvs_write_port_vsr_data(mvi, i, 0x0e); - } - } -} - -static void mvs_64xx_stp_reset(struct mvs_info *mvi, u32 phy_id) -{ - void __iomem *regs = mvi->regs; - u32 reg, tmp; - - if (!(mvi->flags & MVF_FLAG_SOC)) { - if (phy_id < MVS_SOC_PORTS) - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, ®); - else - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, ®); - - } else - reg = mr32(MVS_PHY_CTL); - - tmp = reg; - if (phy_id < MVS_SOC_PORTS) - tmp |= (1U << phy_id) << PCTL_LINK_OFFS; - else - tmp |= (1U << (phy_id - MVS_SOC_PORTS)) << PCTL_LINK_OFFS; - - if (!(mvi->flags & MVF_FLAG_SOC)) { - if (phy_id < MVS_SOC_PORTS) { - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); - mdelay(10); - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, reg); - } else { - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); - mdelay(10); - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, reg); - } - } else { - mw32(MVS_PHY_CTL, tmp); - mdelay(10); - mw32(MVS_PHY_CTL, reg); - } -} - -static void mvs_64xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) -{ - u32 tmp; - tmp = mvs_read_port_irq_stat(mvi, phy_id); - tmp &= ~PHYEV_RDY_CH; - mvs_write_port_irq_stat(mvi, phy_id, tmp); - tmp = mvs_read_phy_ctl(mvi, phy_id); - if (hard == MVS_HARD_RESET) - tmp |= PHY_RST_HARD; - else if (hard == MVS_SOFT_RESET) - tmp |= PHY_RST; - mvs_write_phy_ctl(mvi, phy_id, tmp); - if (hard) { - do { - tmp = mvs_read_phy_ctl(mvi, phy_id); - } while (tmp & PHY_RST_HARD); - } -} - -void mvs_64xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - if (clear_all) { - tmp = mr32(MVS_INT_STAT_SRS_0); - if (tmp) { - printk(KERN_DEBUG "check SRS 0 %08X.\n", tmp); - mw32(MVS_INT_STAT_SRS_0, tmp); - } - } else { - tmp = mr32(MVS_INT_STAT_SRS_0); - if (tmp & (1 << (reg_set % 32))) { - printk(KERN_DEBUG "register set 0x%x was stopped.\n", - reg_set); - mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32)); - } - } -} - -static int __devinit mvs_64xx_chip_reset(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - int i; - - /* make sure interrupts are masked immediately (paranoia) */ - mw32(MVS_GBL_CTL, 0); - tmp = mr32(MVS_GBL_CTL); - - /* Reset Controller */ - if (!(tmp & HBA_RST)) { - if (mvi->flags & MVF_PHY_PWR_FIX) { - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); - tmp &= ~PCTL_PWR_OFF; - tmp |= PCTL_PHY_DSBL; - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); - - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); - tmp &= ~PCTL_PWR_OFF; - tmp |= PCTL_PHY_DSBL; - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); - } - } - - /* make sure interrupts are masked immediately (paranoia) */ - mw32(MVS_GBL_CTL, 0); - tmp = mr32(MVS_GBL_CTL); - - /* Reset Controller */ - if (!(tmp & HBA_RST)) { - /* global reset, incl. COMRESET/H_RESET_N (self-clearing) */ - mw32_f(MVS_GBL_CTL, HBA_RST); - } - - /* wait for reset to finish; timeout is just a guess */ - i = 1000; - while (i-- > 0) { - msleep(10); - - if (!(mr32(MVS_GBL_CTL) & HBA_RST)) - break; - } - if (mr32(MVS_GBL_CTL) & HBA_RST) { - dev_printk(KERN_ERR, mvi->dev, "HBA reset failed\n"); - return -EBUSY; - } - return 0; -} - -static void mvs_64xx_phy_disable(struct mvs_info *mvi, u32 phy_id) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - if (!(mvi->flags & MVF_FLAG_SOC)) { - u32 offs; - if (phy_id < 4) - offs = PCR_PHY_CTL; - else { - offs = PCR_PHY_CTL2; - phy_id -= 4; - } - pci_read_config_dword(mvi->pdev, offs, &tmp); - tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); - pci_write_config_dword(mvi->pdev, offs, tmp); - } else { - tmp = mr32(MVS_PHY_CTL); - tmp |= 1U << (PCTL_PHY_DSBL_OFFS + phy_id); - mw32(MVS_PHY_CTL, tmp); - } -} - -static void mvs_64xx_phy_enable(struct mvs_info *mvi, u32 phy_id) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - if (!(mvi->flags & MVF_FLAG_SOC)) { - u32 offs; - if (phy_id < 4) - offs = PCR_PHY_CTL; - else { - offs = PCR_PHY_CTL2; - phy_id -= 4; - } - pci_read_config_dword(mvi->pdev, offs, &tmp); - tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); - pci_write_config_dword(mvi->pdev, offs, tmp); - } else { - tmp = mr32(MVS_PHY_CTL); - tmp &= ~(1U << (PCTL_PHY_DSBL_OFFS + phy_id)); - mw32(MVS_PHY_CTL, tmp); - } -} - -static int __devinit mvs_64xx_init(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - int i; - u32 tmp, cctl; - - if (mvi->pdev && mvi->pdev->revision == 0) - mvi->flags |= MVF_PHY_PWR_FIX; - if (!(mvi->flags & MVF_FLAG_SOC)) { - mvs_show_pcie_usage(mvi); - tmp = mvs_64xx_chip_reset(mvi); - if (tmp) - return tmp; - } else { - tmp = mr32(MVS_PHY_CTL); - tmp &= ~PCTL_PWR_OFF; - tmp |= PCTL_PHY_DSBL; - mw32(MVS_PHY_CTL, tmp); - } - - /* Init Chip */ - /* make sure RST is set; HBA_RST /should/ have done that for us */ - cctl = mr32(MVS_CTL) & 0xFFFF; - if (cctl & CCTL_RST) - cctl &= ~CCTL_RST; - else - mw32_f(MVS_CTL, cctl | CCTL_RST); - - if (!(mvi->flags & MVF_FLAG_SOC)) { - /* write to device control _AND_ device status register */ - pci_read_config_dword(mvi->pdev, PCR_DEV_CTRL, &tmp); - tmp &= ~PRD_REQ_MASK; - tmp |= PRD_REQ_SIZE; - pci_write_config_dword(mvi->pdev, PCR_DEV_CTRL, tmp); - - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL, &tmp); - tmp &= ~PCTL_PWR_OFF; - tmp &= ~PCTL_PHY_DSBL; - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL, tmp); - - pci_read_config_dword(mvi->pdev, PCR_PHY_CTL2, &tmp); - tmp &= PCTL_PWR_OFF; - tmp &= ~PCTL_PHY_DSBL; - pci_write_config_dword(mvi->pdev, PCR_PHY_CTL2, tmp); - } else { - tmp = mr32(MVS_PHY_CTL); - tmp &= ~PCTL_PWR_OFF; - tmp |= PCTL_COM_ON; - tmp &= ~PCTL_PHY_DSBL; - tmp |= PCTL_LINK_RST; - mw32(MVS_PHY_CTL, tmp); - msleep(100); - tmp &= ~PCTL_LINK_RST; - mw32(MVS_PHY_CTL, tmp); - msleep(100); - } - - /* reset control */ - mw32(MVS_PCS, 0); /* MVS_PCS */ - /* init phys */ - mvs_64xx_phy_hacks(mvi); - - tmp = mvs_cr32(mvi, CMD_PHY_MODE_21); - tmp &= 0x0000ffff; - tmp |= 0x00fa0000; - mvs_cw32(mvi, CMD_PHY_MODE_21, tmp); - - /* enable auto port detection */ - mw32(MVS_GBL_PORT_TYPE, MODE_AUTO_DET_EN); - - mw32(MVS_CMD_LIST_LO, mvi->slot_dma); - mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); - - mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); - mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); - - mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); - mw32(MVS_TX_LO, mvi->tx_dma); - mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); - - mw32(MVS_RX_CFG, MVS_RX_RING_SZ); - mw32(MVS_RX_LO, mvi->rx_dma); - mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); - - for (i = 0; i < mvi->chip->n_phy; i++) { - /* set phy local SAS address */ - /* should set little endian SAS address to 64xx chip */ - mvs_set_sas_addr(mvi, i, PHYR_ADDR_LO, PHYR_ADDR_HI, - cpu_to_be64(mvi->phy[i].dev_sas_addr)); - - mvs_64xx_enable_xmt(mvi, i); - - mvs_64xx_phy_reset(mvi, i, MVS_HARD_RESET); - msleep(500); - mvs_64xx_detect_porttype(mvi, i); - } - if (mvi->flags & MVF_FLAG_SOC) { - /* set select registers */ - writel(0x0E008000, regs + 0x000); - writel(0x59000008, regs + 0x004); - writel(0x20, regs + 0x008); - writel(0x20, regs + 0x00c); - writel(0x20, regs + 0x010); - writel(0x20, regs + 0x014); - writel(0x20, regs + 0x018); - writel(0x20, regs + 0x01c); - } - for (i = 0; i < mvi->chip->n_phy; i++) { - /* clear phy int status */ - tmp = mvs_read_port_irq_stat(mvi, i); - tmp &= ~PHYEV_SIG_FIS; - mvs_write_port_irq_stat(mvi, i, tmp); - - /* set phy int mask */ - tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | PHYEV_UNASSOC_FIS | - PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR | - PHYEV_DEC_ERR; - mvs_write_port_irq_mask(mvi, i, tmp); - - msleep(100); - mvs_update_phyinfo(mvi, i, 1); - } - - /* little endian for open address and command table, etc. */ - cctl = mr32(MVS_CTL); - cctl |= CCTL_ENDIAN_CMD; - cctl |= CCTL_ENDIAN_DATA; - cctl &= ~CCTL_ENDIAN_OPEN; - cctl |= CCTL_ENDIAN_RSP; - mw32_f(MVS_CTL, cctl); - - /* reset CMD queue */ - tmp = mr32(MVS_PCS); - tmp |= PCS_CMD_RST; - tmp &= ~PCS_SELF_CLEAR; - mw32(MVS_PCS, tmp); - /* - * the max count is 0x1ff, while our max slot is 0x200, - * it will make count 0. - */ - tmp = 0; - if (MVS_CHIP_SLOT_SZ > 0x1ff) - mw32(MVS_INT_COAL, 0x1ff | COAL_EN); - else - mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN); - - tmp = 0x10000 | interrupt_coalescing; - mw32(MVS_INT_COAL_TMOUT, tmp); - - /* ladies and gentlemen, start your engines */ - mw32(MVS_TX_CFG, 0); - mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); - mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); - /* enable CMD/CMPL_Q/RESP mode */ - mw32(MVS_PCS, PCS_SATA_RETRY | PCS_FIS_RX_EN | - PCS_CMD_EN | PCS_CMD_STOP_ERR); - - /* enable completion queue interrupt */ - tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | - CINT_DMA_PCIE); - - mw32(MVS_INT_MASK, tmp); - - /* Enable SRS interrupt */ - mw32(MVS_INT_MASK_SRS_0, 0xFFFF); - - return 0; -} - -static int mvs_64xx_ioremap(struct mvs_info *mvi) -{ - if (!mvs_ioremap(mvi, 4, 2)) - return 0; - return -1; -} - -static void mvs_64xx_iounmap(struct mvs_info *mvi) -{ - mvs_iounmap(mvi->regs); - mvs_iounmap(mvi->regs_ex); -} - -static void mvs_64xx_interrupt_enable(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - tmp = mr32(MVS_GBL_CTL); - mw32(MVS_GBL_CTL, tmp | INT_EN); -} - -static void mvs_64xx_interrupt_disable(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - tmp = mr32(MVS_GBL_CTL); - mw32(MVS_GBL_CTL, tmp & ~INT_EN); -} - -static u32 mvs_64xx_isr_status(struct mvs_info *mvi, int irq) -{ - void __iomem *regs = mvi->regs; - u32 stat; - - if (!(mvi->flags & MVF_FLAG_SOC)) { - stat = mr32(MVS_GBL_INT_STAT); - - if (stat == 0 || stat == 0xffffffff) - return 0; - } else - stat = 1; - return stat; -} - -static irqreturn_t mvs_64xx_isr(struct mvs_info *mvi, int irq, u32 stat) -{ - void __iomem *regs = mvi->regs; - - /* clear CMD_CMPLT ASAP */ - mw32_f(MVS_INT_STAT, CINT_DONE); - - spin_lock(&mvi->lock); - mvs_int_full(mvi); - spin_unlock(&mvi->lock); - - return IRQ_HANDLED; -} - -static void mvs_64xx_command_active(struct mvs_info *mvi, u32 slot_idx) -{ - u32 tmp; - mvs_cw32(mvi, 0x40 + (slot_idx >> 3), 1 << (slot_idx % 32)); - mvs_cw32(mvi, 0x00 + (slot_idx >> 3), 1 << (slot_idx % 32)); - do { - tmp = mvs_cr32(mvi, 0x00 + (slot_idx >> 3)); - } while (tmp & 1 << (slot_idx % 32)); - do { - tmp = mvs_cr32(mvi, 0x40 + (slot_idx >> 3)); - } while (tmp & 1 << (slot_idx % 32)); -} - -static void mvs_64xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, - u32 tfs) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - if (type == PORT_TYPE_SATA) { - tmp = mr32(MVS_INT_STAT_SRS_0) | (1U << tfs); - mw32(MVS_INT_STAT_SRS_0, tmp); - } - mw32(MVS_INT_STAT, CINT_CI_STOP); - tmp = mr32(MVS_PCS) | 0xFF00; - mw32(MVS_PCS, tmp); -} - -static void mvs_64xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) -{ - void __iomem *regs = mvi->regs; - u32 tmp, offs; - - if (*tfs == MVS_ID_NOT_MAPPED) - return; - - offs = 1U << ((*tfs & 0x0f) + PCS_EN_SATA_REG_SHIFT); - if (*tfs < 16) { - tmp = mr32(MVS_PCS); - mw32(MVS_PCS, tmp & ~offs); - } else { - tmp = mr32(MVS_CTL); - mw32(MVS_CTL, tmp & ~offs); - } - - tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << *tfs); - if (tmp) - mw32(MVS_INT_STAT_SRS_0, tmp); - - *tfs = MVS_ID_NOT_MAPPED; - return; -} - -static u8 mvs_64xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) -{ - int i; - u32 tmp, offs; - void __iomem *regs = mvi->regs; - - if (*tfs != MVS_ID_NOT_MAPPED) - return 0; - - tmp = mr32(MVS_PCS); - - for (i = 0; i < mvi->chip->srs_sz; i++) { - if (i == 16) - tmp = mr32(MVS_CTL); - offs = 1U << ((i & 0x0f) + PCS_EN_SATA_REG_SHIFT); - if (!(tmp & offs)) { - *tfs = i; - - if (i < 16) - mw32(MVS_PCS, tmp | offs); - else - mw32(MVS_CTL, tmp | offs); - tmp = mr32(MVS_INT_STAT_SRS_0) & (1U << i); - if (tmp) - mw32(MVS_INT_STAT_SRS_0, tmp); - return 0; - } - } - return MVS_ID_NOT_MAPPED; -} - -void mvs_64xx_make_prd(struct scatterlist *scatter, int nr, void *prd) -{ - int i; - struct scatterlist *sg; - struct mvs_prd *buf_prd = prd; - for_each_sg(scatter, sg, nr, i) { - buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); - buf_prd->len = cpu_to_le32(sg_dma_len(sg)); - buf_prd++; - } -} - -static int mvs_64xx_oob_done(struct mvs_info *mvi, int i) -{ - u32 phy_st; - mvs_write_port_cfg_addr(mvi, i, - PHYR_PHY_STAT); - phy_st = mvs_read_port_cfg_data(mvi, i); - if (phy_st & PHY_OOB_DTCTD) - return 1; - return 0; -} - -static void mvs_64xx_fix_phy_info(struct mvs_info *mvi, int i, - struct sas_identify_frame *id) - -{ - struct mvs_phy *phy = &mvi->phy[i]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - - sas_phy->linkrate = - (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> - PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; - - phy->minimum_linkrate = - (phy->phy_status & - PHY_MIN_SPP_PHYS_LINK_RATE_MASK) >> 8; - phy->maximum_linkrate = - (phy->phy_status & - PHY_MAX_SPP_PHYS_LINK_RATE_MASK) >> 12; - - mvs_write_port_cfg_addr(mvi, i, PHYR_IDENTIFY); - phy->dev_info = mvs_read_port_cfg_data(mvi, i); - - mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_DEV_INFO); - phy->att_dev_info = mvs_read_port_cfg_data(mvi, i); - - mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_HI); - phy->att_dev_sas_addr = - (u64) mvs_read_port_cfg_data(mvi, i) << 32; - mvs_write_port_cfg_addr(mvi, i, PHYR_ATT_ADDR_LO); - phy->att_dev_sas_addr |= mvs_read_port_cfg_data(mvi, i); - phy->att_dev_sas_addr = SAS_ADDR(&phy->att_dev_sas_addr); -} - -static void mvs_64xx_phy_work_around(struct mvs_info *mvi, int i) -{ - u32 tmp; - struct mvs_phy *phy = &mvi->phy[i]; - mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE6); - tmp = mvs_read_port_vsr_data(mvi, i); - if (((phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> - PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET) == - SAS_LINK_RATE_1_5_GBPS) - tmp &= ~PHY_MODE6_LATECLK; - else - tmp |= PHY_MODE6_LATECLK; - mvs_write_port_vsr_data(mvi, i, tmp); -} - -void mvs_64xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, - struct sas_phy_linkrates *rates) -{ - u32 lrmin = 0, lrmax = 0; - u32 tmp; - - tmp = mvs_read_phy_ctl(mvi, phy_id); - lrmin = (rates->minimum_linkrate << 8); - lrmax = (rates->maximum_linkrate << 12); - - if (lrmin) { - tmp &= ~(0xf << 8); - tmp |= lrmin; - } - if (lrmax) { - tmp &= ~(0xf << 12); - tmp |= lrmax; - } - mvs_write_phy_ctl(mvi, phy_id, tmp); - mvs_64xx_phy_reset(mvi, phy_id, MVS_HARD_RESET); -} - -static void mvs_64xx_clear_active_cmds(struct mvs_info *mvi) -{ - u32 tmp; - void __iomem *regs = mvi->regs; - tmp = mr32(MVS_PCS); - mw32(MVS_PCS, tmp & 0xFFFF); - mw32(MVS_PCS, tmp); - tmp = mr32(MVS_CTL); - mw32(MVS_CTL, tmp & 0xFFFF); - mw32(MVS_CTL, tmp); -} - - -u32 mvs_64xx_spi_read_data(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs_ex; - return ior32(SPI_DATA_REG_64XX); -} - -void mvs_64xx_spi_write_data(struct mvs_info *mvi, u32 data) -{ - void __iomem *regs = mvi->regs_ex; - iow32(SPI_DATA_REG_64XX, data); -} - - -int mvs_64xx_spi_buildcmd(struct mvs_info *mvi, - u32 *dwCmd, - u8 cmd, - u8 read, - u8 length, - u32 addr - ) -{ - u32 dwTmp; - - dwTmp = ((u32)cmd << 24) | ((u32)length << 19); - if (read) - dwTmp |= 1U<<23; - - if (addr != MV_MAX_U32) { - dwTmp |= 1U<<22; - dwTmp |= (addr & 0x0003FFFF); - } - - *dwCmd = dwTmp; - return 0; -} - - -int mvs_64xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) -{ - void __iomem *regs = mvi->regs_ex; - int retry; - - for (retry = 0; retry < 1; retry++) { - iow32(SPI_CTRL_REG_64XX, SPI_CTRL_VENDOR_ENABLE); - iow32(SPI_CMD_REG_64XX, cmd); - iow32(SPI_CTRL_REG_64XX, - SPI_CTRL_VENDOR_ENABLE | SPI_CTRL_SPISTART); - } - - return 0; -} - -int mvs_64xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) -{ - void __iomem *regs = mvi->regs_ex; - u32 i, dwTmp; - - for (i = 0; i < timeout; i++) { - dwTmp = ior32(SPI_CTRL_REG_64XX); - if (!(dwTmp & SPI_CTRL_SPISTART)) - return 0; - msleep(10); - } - - return -1; -} - -void mvs_64xx_fix_dma(struct mvs_info *mvi, u32 phy_mask, - int buf_len, int from, void *prd) -{ - int i; - struct mvs_prd *buf_prd = prd; - dma_addr_t buf_dma = mvi->bulk_buffer_dma; - - buf_prd += from; - for (i = 0; i < MAX_SG_ENTRY - from; i++) { - buf_prd->addr = cpu_to_le64(buf_dma); - buf_prd->len = cpu_to_le32(buf_len); - ++buf_prd; - } -} - -static void mvs_64xx_tune_interrupt(struct mvs_info *mvi, u32 time) -{ - void __iomem *regs = mvi->regs; - u32 tmp = 0; - /* - * the max count is 0x1ff, while our max slot is 0x200, - * it will make count 0. - */ - if (time == 0) { - mw32(MVS_INT_COAL, 0); - mw32(MVS_INT_COAL_TMOUT, 0x10000); - } else { - if (MVS_CHIP_SLOT_SZ > 0x1ff) - mw32(MVS_INT_COAL, 0x1ff|COAL_EN); - else - mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN); - - tmp = 0x10000 | time; - mw32(MVS_INT_COAL_TMOUT, tmp); - } -} - -const struct mvs_dispatch mvs_64xx_dispatch = { - "mv64xx", - mvs_64xx_init, - NULL, - mvs_64xx_ioremap, - mvs_64xx_iounmap, - mvs_64xx_isr, - mvs_64xx_isr_status, - mvs_64xx_interrupt_enable, - mvs_64xx_interrupt_disable, - mvs_read_phy_ctl, - mvs_write_phy_ctl, - mvs_read_port_cfg_data, - mvs_write_port_cfg_data, - mvs_write_port_cfg_addr, - mvs_read_port_vsr_data, - mvs_write_port_vsr_data, - mvs_write_port_vsr_addr, - mvs_read_port_irq_stat, - mvs_write_port_irq_stat, - mvs_read_port_irq_mask, - mvs_write_port_irq_mask, - mvs_64xx_command_active, - mvs_64xx_clear_srs_irq, - mvs_64xx_issue_stop, - mvs_start_delivery, - mvs_rx_update, - mvs_int_full, - mvs_64xx_assign_reg_set, - mvs_64xx_free_reg_set, - mvs_get_prd_size, - mvs_get_prd_count, - mvs_64xx_make_prd, - mvs_64xx_detect_porttype, - mvs_64xx_oob_done, - mvs_64xx_fix_phy_info, - mvs_64xx_phy_work_around, - mvs_64xx_phy_set_link_rate, - mvs_hw_max_link_rate, - mvs_64xx_phy_disable, - mvs_64xx_phy_enable, - mvs_64xx_phy_reset, - mvs_64xx_stp_reset, - mvs_64xx_clear_active_cmds, - mvs_64xx_spi_read_data, - mvs_64xx_spi_write_data, - mvs_64xx_spi_buildcmd, - mvs_64xx_spi_issuecmd, - mvs_64xx_spi_waitdataready, - mvs_64xx_fix_dma, - mvs_64xx_tune_interrupt, - NULL, -}; - diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.h b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.h deleted file mode 100644 index 545889bd..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_64xx.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Marvell 88SE64xx hardware specific head file - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - -#ifndef _MVS64XX_REG_H_ -#define _MVS64XX_REG_H_ - -#include - -#define MAX_LINK_RATE SAS_LINK_RATE_3_0_GBPS - -/* enhanced mode registers (BAR4) */ -enum hw_registers { - MVS_GBL_CTL = 0x04, /* global control */ - MVS_GBL_INT_STAT = 0x08, /* global irq status */ - MVS_GBL_PI = 0x0C, /* ports implemented bitmask */ - - MVS_PHY_CTL = 0x40, /* SOC PHY Control */ - MVS_PORTS_IMP = 0x9C, /* SOC Port Implemented */ - - MVS_GBL_PORT_TYPE = 0xa0, /* port type */ - - MVS_CTL = 0x100, /* SAS/SATA port configuration */ - MVS_PCS = 0x104, /* SAS/SATA port control/status */ - MVS_CMD_LIST_LO = 0x108, /* cmd list addr */ - MVS_CMD_LIST_HI = 0x10C, - MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */ - MVS_RX_FIS_HI = 0x114, - - MVS_TX_CFG = 0x120, /* TX configuration */ - MVS_TX_LO = 0x124, /* TX (delivery) ring addr */ - MVS_TX_HI = 0x128, - - MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */ - MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */ - MVS_RX_CFG = 0x134, /* RX configuration */ - MVS_RX_LO = 0x138, /* RX (completion) ring addr */ - MVS_RX_HI = 0x13C, - MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */ - - MVS_INT_COAL = 0x148, /* Int coalescing config */ - MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */ - MVS_INT_STAT = 0x150, /* Central int status */ - MVS_INT_MASK = 0x154, /* Central int enable */ - MVS_INT_STAT_SRS_0 = 0x158, /* SATA register set status */ - MVS_INT_MASK_SRS_0 = 0x15C, - - /* ports 1-3 follow after this */ - MVS_P0_INT_STAT = 0x160, /* port0 interrupt status */ - MVS_P0_INT_MASK = 0x164, /* port0 interrupt mask */ - /* ports 5-7 follow after this */ - MVS_P4_INT_STAT = 0x200, /* Port4 interrupt status */ - MVS_P4_INT_MASK = 0x204, /* Port4 interrupt enable mask */ - - /* ports 1-3 follow after this */ - MVS_P0_SER_CTLSTAT = 0x180, /* port0 serial control/status */ - /* ports 5-7 follow after this */ - MVS_P4_SER_CTLSTAT = 0x220, /* port4 serial control/status */ - - MVS_CMD_ADDR = 0x1B8, /* Command register port (addr) */ - MVS_CMD_DATA = 0x1BC, /* Command register port (data) */ - - /* ports 1-3 follow after this */ - MVS_P0_CFG_ADDR = 0x1C0, /* port0 phy register address */ - MVS_P0_CFG_DATA = 0x1C4, /* port0 phy register data */ - /* ports 5-7 follow after this */ - MVS_P4_CFG_ADDR = 0x230, /* Port4 config address */ - MVS_P4_CFG_DATA = 0x234, /* Port4 config data */ - - /* ports 1-3 follow after this */ - MVS_P0_VSR_ADDR = 0x1E0, /* port0 VSR address */ - MVS_P0_VSR_DATA = 0x1E4, /* port0 VSR data */ - /* ports 5-7 follow after this */ - MVS_P4_VSR_ADDR = 0x250, /* port4 VSR addr */ - MVS_P4_VSR_DATA = 0x254, /* port4 VSR data */ -}; - -enum pci_cfg_registers { - PCR_PHY_CTL = 0x40, - PCR_PHY_CTL2 = 0x90, - PCR_DEV_CTRL = 0xE8, - PCR_LINK_STAT = 0xF2, -}; - -/* SAS/SATA Vendor Specific Port Registers */ -enum sas_sata_vsp_regs { - VSR_PHY_STAT = 0x00, /* Phy Status */ - VSR_PHY_MODE1 = 0x01, /* phy tx */ - VSR_PHY_MODE2 = 0x02, /* tx scc */ - VSR_PHY_MODE3 = 0x03, /* pll */ - VSR_PHY_MODE4 = 0x04, /* VCO */ - VSR_PHY_MODE5 = 0x05, /* Rx */ - VSR_PHY_MODE6 = 0x06, /* CDR */ - VSR_PHY_MODE7 = 0x07, /* Impedance */ - VSR_PHY_MODE8 = 0x08, /* Voltage */ - VSR_PHY_MODE9 = 0x09, /* Test */ - VSR_PHY_MODE10 = 0x0A, /* Power */ - VSR_PHY_MODE11 = 0x0B, /* Phy Mode */ - VSR_PHY_VS0 = 0x0C, /* Vednor Specific 0 */ - VSR_PHY_VS1 = 0x0D, /* Vednor Specific 1 */ -}; - -enum chip_register_bits { - PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0xF << 8), - PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0xF << 12), - PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16), - PHY_NEG_SPP_PHYS_LINK_RATE_MASK = - (0xF << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET), -}; - -#define MAX_SG_ENTRY 64 - -struct mvs_prd { - __le64 addr; /* 64-bit buffer address */ - __le32 reserved; - __le32 len; /* 16-bit length */ -}; - -#define SPI_CTRL_REG 0xc0 -#define SPI_CTRL_VENDOR_ENABLE (1U<<29) -#define SPI_CTRL_SPIRDY (1U<<22) -#define SPI_CTRL_SPISTART (1U<<20) - -#define SPI_CMD_REG 0xc4 -#define SPI_DATA_REG 0xc8 - -#define SPI_CTRL_REG_64XX 0x10 -#define SPI_CMD_REG_64XX 0x14 -#define SPI_DATA_REG_64XX 0x18 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.c b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.c deleted file mode 100644 index 7e423e5a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * Marvell 88SE94xx hardware specific - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - -#include "mv_sas.h" -#include "mv_94xx.h" -#include "mv_chips.h" - -static void mvs_94xx_detect_porttype(struct mvs_info *mvi, int i) -{ - u32 reg; - struct mvs_phy *phy = &mvi->phy[i]; - u32 phy_status; - - mvs_write_port_vsr_addr(mvi, i, VSR_PHY_MODE3); - reg = mvs_read_port_vsr_data(mvi, i); - phy_status = ((reg & 0x3f0000) >> 16) & 0xff; - phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); - switch (phy_status) { - case 0x10: - phy->phy_type |= PORT_TYPE_SAS; - break; - case 0x1d: - default: - phy->phy_type |= PORT_TYPE_SATA; - break; - } -} - -void set_phy_tuning(struct mvs_info *mvi, int phy_id, - struct phy_tuning phy_tuning) -{ - u32 tmp, setting_0 = 0, setting_1 = 0; - u8 i; - - /* Remap information for B0 chip: - * - * R0Ch -> R118h[15:0] (Adapted DFE F3 - F5 coefficient) - * R0Dh -> R118h[31:16] (Generation 1 Setting 0) - * R0Eh -> R11Ch[15:0] (Generation 1 Setting 1) - * R0Fh -> R11Ch[31:16] (Generation 2 Setting 0) - * R10h -> R120h[15:0] (Generation 2 Setting 1) - * R11h -> R120h[31:16] (Generation 3 Setting 0) - * R12h -> R124h[15:0] (Generation 3 Setting 1) - * R13h -> R124h[31:16] (Generation 4 Setting 0 (Reserved)) - */ - - /* A0 has a different set of registers */ - if (mvi->pdev->revision == VANIR_A0_REV) - return; - - for (i = 0; i < 3; i++) { - /* loop 3 times, set Gen 1, Gen 2, Gen 3 */ - switch (i) { - case 0: - setting_0 = GENERATION_1_SETTING; - setting_1 = GENERATION_1_2_SETTING; - break; - case 1: - setting_0 = GENERATION_1_2_SETTING; - setting_1 = GENERATION_2_3_SETTING; - break; - case 2: - setting_0 = GENERATION_2_3_SETTING; - setting_1 = GENERATION_3_4_SETTING; - break; - } - - /* Set: - * - * Transmitter Emphasis Enable - * Transmitter Emphasis Amplitude - * Transmitter Amplitude - */ - mvs_write_port_vsr_addr(mvi, phy_id, setting_0); - tmp = mvs_read_port_vsr_data(mvi, phy_id); - tmp &= ~(0xFBE << 16); - tmp |= (((phy_tuning.trans_emp_en << 11) | - (phy_tuning.trans_emp_amp << 7) | - (phy_tuning.trans_amp << 1)) << 16); - mvs_write_port_vsr_data(mvi, phy_id, tmp); - - /* Set Transmitter Amplitude Adjust */ - mvs_write_port_vsr_addr(mvi, phy_id, setting_1); - tmp = mvs_read_port_vsr_data(mvi, phy_id); - tmp &= ~(0xC000); - tmp |= (phy_tuning.trans_amp_adj << 14); - mvs_write_port_vsr_data(mvi, phy_id, tmp); - } -} - -void set_phy_ffe_tuning(struct mvs_info *mvi, int phy_id, - struct ffe_control ffe) -{ - u32 tmp; - - /* Don't run this if A0/B0 */ - if ((mvi->pdev->revision == VANIR_A0_REV) - || (mvi->pdev->revision == VANIR_B0_REV)) - return; - - /* FFE Resistor and Capacitor */ - /* R10Ch DFE Resolution Control/Squelch and FFE Setting - * - * FFE_FORCE [7] - * FFE_RES_SEL [6:4] - * FFE_CAP_SEL [3:0] - */ - mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_FFE_CONTROL); - tmp = mvs_read_port_vsr_data(mvi, phy_id); - tmp &= ~0xFF; - - /* Read from HBA_Info_Page */ - tmp |= ((0x1 << 7) | - (ffe.ffe_rss_sel << 4) | - (ffe.ffe_cap_sel << 0)); - - mvs_write_port_vsr_data(mvi, phy_id, tmp); - - /* R064h PHY Mode Register 1 - * - * DFE_DIS 18 - */ - mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL); - tmp = mvs_read_port_vsr_data(mvi, phy_id); - tmp &= ~0x40001; - /* Hard coding */ - /* No defines in HBA_Info_Page */ - tmp |= (0 << 18); - mvs_write_port_vsr_data(mvi, phy_id, tmp); - - /* R110h DFE F0-F1 Coefficient Control/DFE Update Control - * - * DFE_UPDATE_EN [11:6] - * DFE_FX_FORCE [5:0] - */ - mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_DFE_UPDATE_CRTL); - tmp = mvs_read_port_vsr_data(mvi, phy_id); - tmp &= ~0xFFF; - /* Hard coding */ - /* No defines in HBA_Info_Page */ - tmp |= ((0x3F << 6) | (0x0 << 0)); - mvs_write_port_vsr_data(mvi, phy_id, tmp); - - /* R1A0h Interface and Digital Reference Clock Control/Reserved_50h - * - * FFE_TRAIN_EN 3 - */ - mvs_write_port_vsr_addr(mvi, phy_id, VSR_REF_CLOCK_CRTL); - tmp = mvs_read_port_vsr_data(mvi, phy_id); - tmp &= ~0x8; - /* Hard coding */ - /* No defines in HBA_Info_Page */ - tmp |= (0 << 3); - mvs_write_port_vsr_data(mvi, phy_id, tmp); -} - -/*Notice: this function must be called when phy is disabled*/ -void set_phy_rate(struct mvs_info *mvi, int phy_id, u8 rate) -{ - union reg_phy_cfg phy_cfg, phy_cfg_tmp; - mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); - phy_cfg_tmp.v = mvs_read_port_vsr_data(mvi, phy_id); - phy_cfg.v = 0; - phy_cfg.u.disable_phy = phy_cfg_tmp.u.disable_phy; - phy_cfg.u.sas_support = 1; - phy_cfg.u.sata_support = 1; - phy_cfg.u.sata_host_mode = 1; - - switch (rate) { - case 0x0: - /* support 1.5 Gbps */ - phy_cfg.u.speed_support = 1; - phy_cfg.u.snw_3_support = 0; - phy_cfg.u.tx_lnk_parity = 1; - phy_cfg.u.tx_spt_phs_lnk_rate = 0x30; - break; - case 0x1: - - /* support 1.5, 3.0 Gbps */ - phy_cfg.u.speed_support = 3; - phy_cfg.u.tx_spt_phs_lnk_rate = 0x3c; - phy_cfg.u.tx_lgcl_lnk_rate = 0x08; - break; - case 0x2: - default: - /* support 1.5, 3.0, 6.0 Gbps */ - phy_cfg.u.speed_support = 7; - phy_cfg.u.snw_3_support = 1; - phy_cfg.u.tx_lnk_parity = 1; - phy_cfg.u.tx_spt_phs_lnk_rate = 0x3f; - phy_cfg.u.tx_lgcl_lnk_rate = 0x09; - break; - } - mvs_write_port_vsr_data(mvi, phy_id, phy_cfg.v); -} - -static void __devinit -mvs_94xx_config_reg_from_hba(struct mvs_info *mvi, int phy_id) -{ - u32 temp; - temp = (u32)(*(u32 *)&mvi->hba_info_param.phy_tuning[phy_id]); - if (temp == 0xFFFFFFFFL) { - mvi->hba_info_param.phy_tuning[phy_id].trans_emp_amp = 0x6; - mvi->hba_info_param.phy_tuning[phy_id].trans_amp = 0x1A; - mvi->hba_info_param.phy_tuning[phy_id].trans_amp_adj = 0x3; - } - - temp = (u8)(*(u8 *)&mvi->hba_info_param.ffe_ctl[phy_id]); - if (temp == 0xFFL) { - switch (mvi->pdev->revision) { - case VANIR_A0_REV: - case VANIR_B0_REV: - mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7; - mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0x7; - break; - case VANIR_C0_REV: - case VANIR_C1_REV: - case VANIR_C2_REV: - default: - mvi->hba_info_param.ffe_ctl[phy_id].ffe_rss_sel = 0x7; - mvi->hba_info_param.ffe_ctl[phy_id].ffe_cap_sel = 0xC; - break; - } - } - - temp = (u8)(*(u8 *)&mvi->hba_info_param.phy_rate[phy_id]); - if (temp == 0xFFL) - /*set default phy_rate = 6Gbps*/ - mvi->hba_info_param.phy_rate[phy_id] = 0x2; - - set_phy_tuning(mvi, phy_id, - mvi->hba_info_param.phy_tuning[phy_id]); - set_phy_ffe_tuning(mvi, phy_id, - mvi->hba_info_param.ffe_ctl[phy_id]); - set_phy_rate(mvi, phy_id, - mvi->hba_info_param.phy_rate[phy_id]); -} - -static void __devinit mvs_94xx_enable_xmt(struct mvs_info *mvi, int phy_id) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - tmp = mr32(MVS_PCS); - tmp |= 1 << (phy_id + PCS_EN_PORT_XMT_SHIFT2); - mw32(MVS_PCS, tmp); -} - -static void mvs_94xx_phy_reset(struct mvs_info *mvi, u32 phy_id, int hard) -{ - u32 tmp; - u32 delay = 5000; - if (hard == MVS_PHY_TUNE) { - mvs_write_port_cfg_addr(mvi, phy_id, PHYR_SATA_CTL); - tmp = mvs_read_port_cfg_data(mvi, phy_id); - mvs_write_port_cfg_data(mvi, phy_id, tmp|0x20000000); - mvs_write_port_cfg_data(mvi, phy_id, tmp|0x100000); - return; - } - tmp = mvs_read_port_irq_stat(mvi, phy_id); - tmp &= ~PHYEV_RDY_CH; - mvs_write_port_irq_stat(mvi, phy_id, tmp); - if (hard) { - tmp = mvs_read_phy_ctl(mvi, phy_id); - tmp |= PHY_RST_HARD; - mvs_write_phy_ctl(mvi, phy_id, tmp); - do { - tmp = mvs_read_phy_ctl(mvi, phy_id); - udelay(10); - delay--; - } while ((tmp & PHY_RST_HARD) && delay); - if (!delay) - mv_dprintk("phy hard reset failed.\n"); - } else { - tmp = mvs_read_phy_ctl(mvi, phy_id); - tmp |= PHY_RST; - mvs_write_phy_ctl(mvi, phy_id, tmp); - } -} - -static void mvs_94xx_phy_disable(struct mvs_info *mvi, u32 phy_id) -{ - u32 tmp; - mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); - tmp = mvs_read_port_vsr_data(mvi, phy_id); - mvs_write_port_vsr_data(mvi, phy_id, tmp | 0x00800000); -} - -static void mvs_94xx_phy_enable(struct mvs_info *mvi, u32 phy_id) -{ - u32 tmp; - u8 revision = 0; - - revision = mvi->pdev->revision; - if (revision == VANIR_A0_REV) { - mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA); - mvs_write_port_vsr_data(mvi, phy_id, 0x8300ffc1); - } - if (revision == VANIR_B0_REV) { - mvs_write_port_vsr_addr(mvi, phy_id, CMD_APP_MEM_CTL); - mvs_write_port_vsr_data(mvi, phy_id, 0x08001006); - mvs_write_port_vsr_addr(mvi, phy_id, CMD_HOST_RD_DATA); - mvs_write_port_vsr_data(mvi, phy_id, 0x0000705f); - } - - mvs_write_port_vsr_addr(mvi, phy_id, VSR_PHY_MODE2); - tmp = mvs_read_port_vsr_data(mvi, phy_id); - tmp |= bit(0); - mvs_write_port_vsr_data(mvi, phy_id, tmp & 0xfd7fffff); -} - -static int __devinit mvs_94xx_init(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - int i; - u32 tmp, cctl; - u8 revision; - - revision = mvi->pdev->revision; - mvs_show_pcie_usage(mvi); - if (mvi->flags & MVF_FLAG_SOC) { - tmp = mr32(MVS_PHY_CTL); - tmp &= ~PCTL_PWR_OFF; - tmp |= PCTL_PHY_DSBL; - mw32(MVS_PHY_CTL, tmp); - } - - /* Init Chip */ - /* make sure RST is set; HBA_RST /should/ have done that for us */ - cctl = mr32(MVS_CTL) & 0xFFFF; - if (cctl & CCTL_RST) - cctl &= ~CCTL_RST; - else - mw32_f(MVS_CTL, cctl | CCTL_RST); - - if (mvi->flags & MVF_FLAG_SOC) { - tmp = mr32(MVS_PHY_CTL); - tmp &= ~PCTL_PWR_OFF; - tmp |= PCTL_COM_ON; - tmp &= ~PCTL_PHY_DSBL; - tmp |= PCTL_LINK_RST; - mw32(MVS_PHY_CTL, tmp); - msleep(100); - tmp &= ~PCTL_LINK_RST; - mw32(MVS_PHY_CTL, tmp); - msleep(100); - } - - /* disable Multiplexing, enable phy implemented */ - mw32(MVS_PORTS_IMP, 0xFF); - - if (revision == VANIR_A0_REV) { - mw32(MVS_PA_VSR_ADDR, CMD_CMWK_OOB_DET); - mw32(MVS_PA_VSR_PORT, 0x00018080); - } - mw32(MVS_PA_VSR_ADDR, VSR_PHY_MODE2); - if (revision == VANIR_A0_REV || revision == VANIR_B0_REV) - /* set 6G/3G/1.5G, multiplexing, without SSC */ - mw32(MVS_PA_VSR_PORT, 0x0084d4fe); - else - /* set 6G/3G/1.5G, multiplexing, with and without SSC */ - mw32(MVS_PA_VSR_PORT, 0x0084fffe); - - if (revision == VANIR_B0_REV) { - mw32(MVS_PA_VSR_ADDR, CMD_APP_MEM_CTL); - mw32(MVS_PA_VSR_PORT, 0x08001006); - mw32(MVS_PA_VSR_ADDR, CMD_HOST_RD_DATA); - mw32(MVS_PA_VSR_PORT, 0x0000705f); - } - - /* reset control */ - mw32(MVS_PCS, 0); /* MVS_PCS */ - mw32(MVS_STP_REG_SET_0, 0); - mw32(MVS_STP_REG_SET_1, 0); - - /* init phys */ - mvs_phy_hacks(mvi); - - /* disable non data frame retry */ - tmp = mvs_cr32(mvi, CMD_SAS_CTL1); - if ((revision == VANIR_A0_REV) || - (revision == VANIR_B0_REV) || - (revision == VANIR_C0_REV)) { - tmp &= ~0xffff; - tmp |= 0x007f; - mvs_cw32(mvi, CMD_SAS_CTL1, tmp); - } - - /* set LED blink when IO*/ - mw32(MVS_PA_VSR_ADDR, VSR_PHY_ACT_LED); - tmp = mr32(MVS_PA_VSR_PORT); - tmp &= 0xFFFF00FF; - tmp |= 0x00003300; - mw32(MVS_PA_VSR_PORT, tmp); - - mw32(MVS_CMD_LIST_LO, mvi->slot_dma); - mw32(MVS_CMD_LIST_HI, (mvi->slot_dma >> 16) >> 16); - - mw32(MVS_RX_FIS_LO, mvi->rx_fis_dma); - mw32(MVS_RX_FIS_HI, (mvi->rx_fis_dma >> 16) >> 16); - - mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ); - mw32(MVS_TX_LO, mvi->tx_dma); - mw32(MVS_TX_HI, (mvi->tx_dma >> 16) >> 16); - - mw32(MVS_RX_CFG, MVS_RX_RING_SZ); - mw32(MVS_RX_LO, mvi->rx_dma); - mw32(MVS_RX_HI, (mvi->rx_dma >> 16) >> 16); - - for (i = 0; i < mvi->chip->n_phy; i++) { - mvs_94xx_phy_disable(mvi, i); - /* set phy local SAS address */ - mvs_set_sas_addr(mvi, i, CONFIG_ID_FRAME3, CONFIG_ID_FRAME4, - cpu_to_le64(mvi->phy[i].dev_sas_addr)); - - mvs_94xx_enable_xmt(mvi, i); - mvs_94xx_config_reg_from_hba(mvi, i); - mvs_94xx_phy_enable(mvi, i); - - mvs_94xx_phy_reset(mvi, i, PHY_RST_HARD); - msleep(500); - mvs_94xx_detect_porttype(mvi, i); - } - - if (mvi->flags & MVF_FLAG_SOC) { - /* set select registers */ - writel(0x0E008000, regs + 0x000); - writel(0x59000008, regs + 0x004); - writel(0x20, regs + 0x008); - writel(0x20, regs + 0x00c); - writel(0x20, regs + 0x010); - writel(0x20, regs + 0x014); - writel(0x20, regs + 0x018); - writel(0x20, regs + 0x01c); - } - for (i = 0; i < mvi->chip->n_phy; i++) { - /* clear phy int status */ - tmp = mvs_read_port_irq_stat(mvi, i); - tmp &= ~PHYEV_SIG_FIS; - mvs_write_port_irq_stat(mvi, i, tmp); - - /* set phy int mask */ - tmp = PHYEV_RDY_CH | PHYEV_BROAD_CH | - PHYEV_ID_DONE | PHYEV_DCDR_ERR | PHYEV_CRC_ERR ; - mvs_write_port_irq_mask(mvi, i, tmp); - - msleep(100); - mvs_update_phyinfo(mvi, i, 1); - } - - /* little endian for open address and command table, etc. */ - cctl = mr32(MVS_CTL); - cctl |= CCTL_ENDIAN_CMD; - cctl &= ~CCTL_ENDIAN_OPEN; - cctl |= CCTL_ENDIAN_RSP; - mw32_f(MVS_CTL, cctl); - - /* reset CMD queue */ - tmp = mr32(MVS_PCS); - tmp |= PCS_CMD_RST; - tmp &= ~PCS_SELF_CLEAR; - mw32(MVS_PCS, tmp); - /* - * the max count is 0x1ff, while our max slot is 0x200, - * it will make count 0. - */ - tmp = 0; - if (MVS_CHIP_SLOT_SZ > 0x1ff) - mw32(MVS_INT_COAL, 0x1ff | COAL_EN); - else - mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ | COAL_EN); - - /* default interrupt coalescing time is 128us */ - tmp = 0x10000 | interrupt_coalescing; - mw32(MVS_INT_COAL_TMOUT, tmp); - - /* ladies and gentlemen, start your engines */ - mw32(MVS_TX_CFG, 0); - mw32(MVS_TX_CFG, MVS_CHIP_SLOT_SZ | TX_EN); - mw32(MVS_RX_CFG, MVS_RX_RING_SZ | RX_EN); - /* enable CMD/CMPL_Q/RESP mode */ - mw32(MVS_PCS, PCS_SATA_RETRY_2 | PCS_FIS_RX_EN | - PCS_CMD_EN | PCS_CMD_STOP_ERR); - - /* enable completion queue interrupt */ - tmp = (CINT_PORT_MASK | CINT_DONE | CINT_MEM | CINT_SRS | CINT_CI_STOP | - CINT_DMA_PCIE | CINT_NON_SPEC_NCQ_ERROR); - tmp |= CINT_PHY_MASK; - mw32(MVS_INT_MASK, tmp); - - tmp = mvs_cr32(mvi, CMD_LINK_TIMER); - tmp |= 0xFFFF0000; - mvs_cw32(mvi, CMD_LINK_TIMER, tmp); - - /* tune STP performance */ - tmp = 0x003F003F; - mvs_cw32(mvi, CMD_PL_TIMER, tmp); - - /* This can improve expander large block size seq write performance */ - tmp = mvs_cr32(mvi, CMD_PORT_LAYER_TIMER1); - tmp |= 0xFFFF007F; - mvs_cw32(mvi, CMD_PORT_LAYER_TIMER1, tmp); - - /* change the connection open-close behavior (bit 9) - * set bit8 to 1 for performance tuning */ - tmp = mvs_cr32(mvi, CMD_SL_MODE0); - tmp |= 0x00000300; - /* set bit0 to 0 to enable retry for no_dest reject case */ - tmp &= 0xFFFFFFFE; - mvs_cw32(mvi, CMD_SL_MODE0, tmp); - - /* Enable SRS interrupt */ - mw32(MVS_INT_MASK_SRS_0, 0xFFFF); - - return 0; -} - -static int mvs_94xx_ioremap(struct mvs_info *mvi) -{ - if (!mvs_ioremap(mvi, 2, -1)) { - mvi->regs_ex = mvi->regs + 0x10200; - mvi->regs += 0x20000; - if (mvi->id == 1) - mvi->regs += 0x4000; - return 0; - } - return -1; -} - -static void mvs_94xx_iounmap(struct mvs_info *mvi) -{ - if (mvi->regs) { - mvi->regs -= 0x20000; - if (mvi->id == 1) - mvi->regs -= 0x4000; - mvs_iounmap(mvi->regs); - } -} - -static void mvs_94xx_interrupt_enable(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs_ex; - u32 tmp; - - tmp = mr32(MVS_GBL_CTL); - tmp |= (IRQ_SAS_A | IRQ_SAS_B); - mw32(MVS_GBL_INT_STAT, tmp); - writel(tmp, regs + 0x0C); - writel(tmp, regs + 0x10); - writel(tmp, regs + 0x14); - writel(tmp, regs + 0x18); - mw32(MVS_GBL_CTL, tmp); -} - -static void mvs_94xx_interrupt_disable(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs_ex; - u32 tmp; - - tmp = mr32(MVS_GBL_CTL); - - tmp &= ~(IRQ_SAS_A | IRQ_SAS_B); - mw32(MVS_GBL_INT_STAT, tmp); - writel(tmp, regs + 0x0C); - writel(tmp, regs + 0x10); - writel(tmp, regs + 0x14); - writel(tmp, regs + 0x18); - mw32(MVS_GBL_CTL, tmp); -} - -static u32 mvs_94xx_isr_status(struct mvs_info *mvi, int irq) -{ - void __iomem *regs = mvi->regs_ex; - u32 stat = 0; - if (!(mvi->flags & MVF_FLAG_SOC)) { - stat = mr32(MVS_GBL_INT_STAT); - - if (!(stat & (IRQ_SAS_A | IRQ_SAS_B))) - return 0; - } - return stat; -} - -static irqreturn_t mvs_94xx_isr(struct mvs_info *mvi, int irq, u32 stat) -{ - void __iomem *regs = mvi->regs; - - if (((stat & IRQ_SAS_A) && mvi->id == 0) || - ((stat & IRQ_SAS_B) && mvi->id == 1)) { - mw32_f(MVS_INT_STAT, CINT_DONE); - - spin_lock(&mvi->lock); - mvs_int_full(mvi); - spin_unlock(&mvi->lock); - } - return IRQ_HANDLED; -} - -static void mvs_94xx_command_active(struct mvs_info *mvi, u32 slot_idx) -{ - u32 tmp; - tmp = mvs_cr32(mvi, MVS_COMMAND_ACTIVE+(slot_idx >> 3)); - if (tmp && 1 << (slot_idx % 32)) { - mv_printk("command active %08X, slot [%x].\n", tmp, slot_idx); - mvs_cw32(mvi, MVS_COMMAND_ACTIVE + (slot_idx >> 3), - 1 << (slot_idx % 32)); - do { - tmp = mvs_cr32(mvi, - MVS_COMMAND_ACTIVE + (slot_idx >> 3)); - } while (tmp & 1 << (slot_idx % 32)); - } -} - -void mvs_94xx_clear_srs_irq(struct mvs_info *mvi, u8 reg_set, u8 clear_all) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - - if (clear_all) { - tmp = mr32(MVS_INT_STAT_SRS_0); - if (tmp) { - mv_dprintk("check SRS 0 %08X.\n", tmp); - mw32(MVS_INT_STAT_SRS_0, tmp); - } - tmp = mr32(MVS_INT_STAT_SRS_1); - if (tmp) { - mv_dprintk("check SRS 1 %08X.\n", tmp); - mw32(MVS_INT_STAT_SRS_1, tmp); - } - } else { - if (reg_set > 31) - tmp = mr32(MVS_INT_STAT_SRS_1); - else - tmp = mr32(MVS_INT_STAT_SRS_0); - - if (tmp & (1 << (reg_set % 32))) { - mv_dprintk("register set 0x%x was stopped.\n", reg_set); - if (reg_set > 31) - mw32(MVS_INT_STAT_SRS_1, 1 << (reg_set % 32)); - else - mw32(MVS_INT_STAT_SRS_0, 1 << (reg_set % 32)); - } - } -} - -static void mvs_94xx_issue_stop(struct mvs_info *mvi, enum mvs_port_type type, - u32 tfs) -{ - void __iomem *regs = mvi->regs; - u32 tmp; - mvs_94xx_clear_srs_irq(mvi, 0, 1); - - tmp = mr32(MVS_INT_STAT); - mw32(MVS_INT_STAT, tmp | CINT_CI_STOP); - tmp = mr32(MVS_PCS) | 0xFF00; - mw32(MVS_PCS, tmp); -} - -static void mvs_94xx_non_spec_ncq_error(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 err_0, err_1; - u8 i; - struct mvs_device *device; - - err_0 = mr32(MVS_NON_NCQ_ERR_0); - err_1 = mr32(MVS_NON_NCQ_ERR_1); - - mv_dprintk("non specific ncq error err_0:%x,err_1:%x.\n", - err_0, err_1); - for (i = 0; i < 32; i++) { - if (err_0 & bit(i)) { - device = mvs_find_dev_by_reg_set(mvi, i); - if (device) - mvs_release_task(mvi, device->sas_device); - } - if (err_1 & bit(i)) { - device = mvs_find_dev_by_reg_set(mvi, i+32); - if (device) - mvs_release_task(mvi, device->sas_device); - } - } - - mw32(MVS_NON_NCQ_ERR_0, err_0); - mw32(MVS_NON_NCQ_ERR_1, err_1); -} - -static void mvs_94xx_free_reg_set(struct mvs_info *mvi, u8 *tfs) -{ - void __iomem *regs = mvi->regs; - u8 reg_set = *tfs; - - if (*tfs == MVS_ID_NOT_MAPPED) - return; - - mvi->sata_reg_set &= ~bit(reg_set); - if (reg_set < 32) - w_reg_set_enable(reg_set, (u32)mvi->sata_reg_set); - else - w_reg_set_enable(reg_set, (u32)(mvi->sata_reg_set >> 32)); - - *tfs = MVS_ID_NOT_MAPPED; - - return; -} - -static u8 mvs_94xx_assign_reg_set(struct mvs_info *mvi, u8 *tfs) -{ - int i; - void __iomem *regs = mvi->regs; - - if (*tfs != MVS_ID_NOT_MAPPED) - return 0; - - i = mv_ffc64(mvi->sata_reg_set); - if (i >= 32) { - mvi->sata_reg_set |= bit(i); - w_reg_set_enable(i, (u32)(mvi->sata_reg_set >> 32)); - *tfs = i; - return 0; - } else if (i >= 0) { - mvi->sata_reg_set |= bit(i); - w_reg_set_enable(i, (u32)mvi->sata_reg_set); - *tfs = i; - return 0; - } - return MVS_ID_NOT_MAPPED; -} - -static void mvs_94xx_make_prd(struct scatterlist *scatter, int nr, void *prd) -{ - int i; - struct scatterlist *sg; - struct mvs_prd *buf_prd = prd; - struct mvs_prd_imt im_len; - *(u32 *)&im_len = 0; - for_each_sg(scatter, sg, nr, i) { - buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); - im_len.len = sg_dma_len(sg); - buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len); - buf_prd++; - } -} - -static int mvs_94xx_oob_done(struct mvs_info *mvi, int i) -{ - u32 phy_st; - phy_st = mvs_read_phy_ctl(mvi, i); - if (phy_st & PHY_READY_MASK) - return 1; - return 0; -} - -static void mvs_94xx_get_dev_identify_frame(struct mvs_info *mvi, int port_id, - struct sas_identify_frame *id) -{ - int i; - u32 id_frame[7]; - - for (i = 0; i < 7; i++) { - mvs_write_port_cfg_addr(mvi, port_id, - CONFIG_ID_FRAME0 + i * 4); - id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id)); - } - memcpy(id, id_frame, 28); -} - -static void mvs_94xx_get_att_identify_frame(struct mvs_info *mvi, int port_id, - struct sas_identify_frame *id) -{ - int i; - u32 id_frame[7]; - - for (i = 0; i < 7; i++) { - mvs_write_port_cfg_addr(mvi, port_id, - CONFIG_ATT_ID_FRAME0 + i * 4); - id_frame[i] = cpu_to_le32(mvs_read_port_cfg_data(mvi, port_id)); - mv_dprintk("94xx phy %d atta frame %d %x.\n", - port_id + mvi->id * mvi->chip->n_phy, i, id_frame[i]); - } - memcpy(id, id_frame, 28); -} - -static u32 mvs_94xx_make_dev_info(struct sas_identify_frame *id) -{ - u32 att_dev_info = 0; - - att_dev_info |= id->dev_type; - if (id->stp_iport) - att_dev_info |= PORT_DEV_STP_INIT; - if (id->smp_iport) - att_dev_info |= PORT_DEV_SMP_INIT; - if (id->ssp_iport) - att_dev_info |= PORT_DEV_SSP_INIT; - if (id->stp_tport) - att_dev_info |= PORT_DEV_STP_TRGT; - if (id->smp_tport) - att_dev_info |= PORT_DEV_SMP_TRGT; - if (id->ssp_tport) - att_dev_info |= PORT_DEV_SSP_TRGT; - - att_dev_info |= (u32)id->phy_id<<24; - return att_dev_info; -} - -static u32 mvs_94xx_make_att_info(struct sas_identify_frame *id) -{ - return mvs_94xx_make_dev_info(id); -} - -static void mvs_94xx_fix_phy_info(struct mvs_info *mvi, int i, - struct sas_identify_frame *id) -{ - struct mvs_phy *phy = &mvi->phy[i]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - mv_dprintk("get all reg link rate is 0x%x\n", phy->phy_status); - sas_phy->linkrate = - (phy->phy_status & PHY_NEG_SPP_PHYS_LINK_RATE_MASK) >> - PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET; - sas_phy->linkrate += 0x8; - mv_dprintk("get link rate is %d\n", sas_phy->linkrate); - phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; - phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS; - mvs_94xx_get_dev_identify_frame(mvi, i, id); - phy->dev_info = mvs_94xx_make_dev_info(id); - - if (phy->phy_type & PORT_TYPE_SAS) { - mvs_94xx_get_att_identify_frame(mvi, i, id); - phy->att_dev_info = mvs_94xx_make_att_info(id); - phy->att_dev_sas_addr = *(u64 *)id->sas_addr; - } else { - phy->att_dev_info = PORT_DEV_STP_TRGT | 1; - } - - /* enable spin up bit */ - mvs_write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); - mvs_write_port_cfg_data(mvi, i, 0x04); - -} - -void mvs_94xx_phy_set_link_rate(struct mvs_info *mvi, u32 phy_id, - struct sas_phy_linkrates *rates) -{ - u32 lrmax = 0; - u32 tmp; - - tmp = mvs_read_phy_ctl(mvi, phy_id); - lrmax = (rates->maximum_linkrate - SAS_LINK_RATE_1_5_GBPS) << 12; - - if (lrmax) { - tmp &= ~(0x3 << 12); - tmp |= lrmax; - } - mvs_write_phy_ctl(mvi, phy_id, tmp); - mvs_94xx_phy_reset(mvi, phy_id, PHY_RST_HARD); -} - -static void mvs_94xx_clear_active_cmds(struct mvs_info *mvi) -{ - u32 tmp; - void __iomem *regs = mvi->regs; - tmp = mr32(MVS_STP_REG_SET_0); - mw32(MVS_STP_REG_SET_0, 0); - mw32(MVS_STP_REG_SET_0, tmp); - tmp = mr32(MVS_STP_REG_SET_1); - mw32(MVS_STP_REG_SET_1, 0); - mw32(MVS_STP_REG_SET_1, tmp); -} - - -u32 mvs_94xx_spi_read_data(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs_ex - 0x10200; - return mr32(SPI_RD_DATA_REG_94XX); -} - -void mvs_94xx_spi_write_data(struct mvs_info *mvi, u32 data) -{ - void __iomem *regs = mvi->regs_ex - 0x10200; - mw32(SPI_RD_DATA_REG_94XX, data); -} - - -int mvs_94xx_spi_buildcmd(struct mvs_info *mvi, - u32 *dwCmd, - u8 cmd, - u8 read, - u8 length, - u32 addr - ) -{ - void __iomem *regs = mvi->regs_ex - 0x10200; - u32 dwTmp; - - dwTmp = ((u32)cmd << 8) | ((u32)length << 4); - if (read) - dwTmp |= SPI_CTRL_READ_94XX; - - if (addr != MV_MAX_U32) { - mw32(SPI_ADDR_REG_94XX, (addr & 0x0003FFFFL)); - dwTmp |= SPI_ADDR_VLD_94XX; - } - - *dwCmd = dwTmp; - return 0; -} - - -int mvs_94xx_spi_issuecmd(struct mvs_info *mvi, u32 cmd) -{ - void __iomem *regs = mvi->regs_ex - 0x10200; - mw32(SPI_CTRL_REG_94XX, cmd | SPI_CTRL_SpiStart_94XX); - - return 0; -} - -int mvs_94xx_spi_waitdataready(struct mvs_info *mvi, u32 timeout) -{ - void __iomem *regs = mvi->regs_ex - 0x10200; - u32 i, dwTmp; - - for (i = 0; i < timeout; i++) { - dwTmp = mr32(SPI_CTRL_REG_94XX); - if (!(dwTmp & SPI_CTRL_SpiStart_94XX)) - return 0; - msleep(10); - } - - return -1; -} - -void mvs_94xx_fix_dma(struct mvs_info *mvi, u32 phy_mask, - int buf_len, int from, void *prd) -{ - int i; - struct mvs_prd *buf_prd = prd; - dma_addr_t buf_dma; - struct mvs_prd_imt im_len; - - *(u32 *)&im_len = 0; - buf_prd += from; - -#define PRD_CHAINED_ENTRY 0x01 - if ((mvi->pdev->revision == VANIR_A0_REV) || - (mvi->pdev->revision == VANIR_B0_REV)) - buf_dma = (phy_mask <= 0x08) ? - mvi->bulk_buffer_dma : mvi->bulk_buffer_dma1; - else - return; - - for (i = from; i < MAX_SG_ENTRY; i++, ++buf_prd) { - if (i == MAX_SG_ENTRY - 1) { - buf_prd->addr = cpu_to_le64(virt_to_phys(buf_prd - 1)); - im_len.len = 2; - im_len.misc_ctl = PRD_CHAINED_ENTRY; - } else { - buf_prd->addr = cpu_to_le64(buf_dma); - im_len.len = buf_len; - } - buf_prd->im_len = cpu_to_le32(*(u32 *)&im_len); - } -} - -static void mvs_94xx_tune_interrupt(struct mvs_info *mvi, u32 time) -{ - void __iomem *regs = mvi->regs; - u32 tmp = 0; - /* - * the max count is 0x1ff, while our max slot is 0x200, - * it will make count 0. - */ - if (time == 0) { - mw32(MVS_INT_COAL, 0); - mw32(MVS_INT_COAL_TMOUT, 0x10000); - } else { - if (MVS_CHIP_SLOT_SZ > 0x1ff) - mw32(MVS_INT_COAL, 0x1ff|COAL_EN); - else - mw32(MVS_INT_COAL, MVS_CHIP_SLOT_SZ|COAL_EN); - - tmp = 0x10000 | time; - mw32(MVS_INT_COAL_TMOUT, tmp); - } - -} - -const struct mvs_dispatch mvs_94xx_dispatch = { - "mv94xx", - mvs_94xx_init, - NULL, - mvs_94xx_ioremap, - mvs_94xx_iounmap, - mvs_94xx_isr, - mvs_94xx_isr_status, - mvs_94xx_interrupt_enable, - mvs_94xx_interrupt_disable, - mvs_read_phy_ctl, - mvs_write_phy_ctl, - mvs_read_port_cfg_data, - mvs_write_port_cfg_data, - mvs_write_port_cfg_addr, - mvs_read_port_vsr_data, - mvs_write_port_vsr_data, - mvs_write_port_vsr_addr, - mvs_read_port_irq_stat, - mvs_write_port_irq_stat, - mvs_read_port_irq_mask, - mvs_write_port_irq_mask, - mvs_94xx_command_active, - mvs_94xx_clear_srs_irq, - mvs_94xx_issue_stop, - mvs_start_delivery, - mvs_rx_update, - mvs_int_full, - mvs_94xx_assign_reg_set, - mvs_94xx_free_reg_set, - mvs_get_prd_size, - mvs_get_prd_count, - mvs_94xx_make_prd, - mvs_94xx_detect_porttype, - mvs_94xx_oob_done, - mvs_94xx_fix_phy_info, - NULL, - mvs_94xx_phy_set_link_rate, - mvs_hw_max_link_rate, - mvs_94xx_phy_disable, - mvs_94xx_phy_enable, - mvs_94xx_phy_reset, - NULL, - mvs_94xx_clear_active_cmds, - mvs_94xx_spi_read_data, - mvs_94xx_spi_write_data, - mvs_94xx_spi_buildcmd, - mvs_94xx_spi_issuecmd, - mvs_94xx_spi_waitdataready, - mvs_94xx_fix_dma, - mvs_94xx_tune_interrupt, - mvs_94xx_non_spec_ncq_error, -}; - diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.h b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.h deleted file mode 100644 index 8f7eb4f2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_94xx.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Marvell 88SE94xx hardware specific head file - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - -#ifndef _MVS94XX_REG_H_ -#define _MVS94XX_REG_H_ - -#include - -#define MAX_LINK_RATE SAS_LINK_RATE_6_0_GBPS - -enum VANIR_REVISION_ID { - VANIR_A0_REV = 0xA0, - VANIR_B0_REV = 0x01, - VANIR_C0_REV = 0x02, - VANIR_C1_REV = 0x03, - VANIR_C2_REV = 0xC2, -}; - -enum hw_registers { - MVS_GBL_CTL = 0x04, /* global control */ - MVS_GBL_INT_STAT = 0x00, /* global irq status */ - MVS_GBL_PI = 0x0C, /* ports implemented bitmask */ - - MVS_PHY_CTL = 0x40, /* SOC PHY Control */ - MVS_PORTS_IMP = 0x9C, /* SOC Port Implemented */ - - MVS_GBL_PORT_TYPE = 0xa0, /* port type */ - - MVS_CTL = 0x100, /* SAS/SATA port configuration */ - MVS_PCS = 0x104, /* SAS/SATA port control/status */ - MVS_CMD_LIST_LO = 0x108, /* cmd list addr */ - MVS_CMD_LIST_HI = 0x10C, - MVS_RX_FIS_LO = 0x110, /* RX FIS list addr */ - MVS_RX_FIS_HI = 0x114, - MVS_STP_REG_SET_0 = 0x118, /* STP/SATA Register Set Enable */ - MVS_STP_REG_SET_1 = 0x11C, - MVS_TX_CFG = 0x120, /* TX configuration */ - MVS_TX_LO = 0x124, /* TX (delivery) ring addr */ - MVS_TX_HI = 0x128, - - MVS_TX_PROD_IDX = 0x12C, /* TX producer pointer */ - MVS_TX_CONS_IDX = 0x130, /* TX consumer pointer (RO) */ - MVS_RX_CFG = 0x134, /* RX configuration */ - MVS_RX_LO = 0x138, /* RX (completion) ring addr */ - MVS_RX_HI = 0x13C, - MVS_RX_CONS_IDX = 0x140, /* RX consumer pointer (RO) */ - - MVS_INT_COAL = 0x148, /* Int coalescing config */ - MVS_INT_COAL_TMOUT = 0x14C, /* Int coalescing timeout */ - MVS_INT_STAT = 0x150, /* Central int status */ - MVS_INT_MASK = 0x154, /* Central int enable */ - MVS_INT_STAT_SRS_0 = 0x158, /* SATA register set status */ - MVS_INT_MASK_SRS_0 = 0x15C, - MVS_INT_STAT_SRS_1 = 0x160, - MVS_INT_MASK_SRS_1 = 0x164, - MVS_NON_NCQ_ERR_0 = 0x168, /* SRS Non-specific NCQ Error */ - MVS_NON_NCQ_ERR_1 = 0x16C, - MVS_CMD_ADDR = 0x170, /* Command register port (addr) */ - MVS_CMD_DATA = 0x174, /* Command register port (data) */ - MVS_MEM_PARITY_ERR = 0x178, /* Memory parity error */ - - /* ports 1-3 follow after this */ - MVS_P0_INT_STAT = 0x180, /* port0 interrupt status */ - MVS_P0_INT_MASK = 0x184, /* port0 interrupt mask */ - /* ports 5-7 follow after this */ - MVS_P4_INT_STAT = 0x1A0, /* Port4 interrupt status */ - MVS_P4_INT_MASK = 0x1A4, /* Port4 interrupt enable mask */ - - /* ports 1-3 follow after this */ - MVS_P0_SER_CTLSTAT = 0x1D0, /* port0 serial control/status */ - /* ports 5-7 follow after this */ - MVS_P4_SER_CTLSTAT = 0x1E0, /* port4 serial control/status */ - - /* ports 1-3 follow after this */ - MVS_P0_CFG_ADDR = 0x200, /* port0 phy register address */ - MVS_P0_CFG_DATA = 0x204, /* port0 phy register data */ - /* ports 5-7 follow after this */ - MVS_P4_CFG_ADDR = 0x220, /* Port4 config address */ - MVS_P4_CFG_DATA = 0x224, /* Port4 config data */ - - /* phys 1-3 follow after this */ - MVS_P0_VSR_ADDR = 0x250, /* phy0 VSR address */ - MVS_P0_VSR_DATA = 0x254, /* phy0 VSR data */ - /* phys 1-3 follow after this */ - /* multiplexing */ - MVS_P4_VSR_ADDR = 0x250, /* phy4 VSR address */ - MVS_P4_VSR_DATA = 0x254, /* phy4 VSR data */ - MVS_PA_VSR_ADDR = 0x290, /* All port VSR addr */ - MVS_PA_VSR_PORT = 0x294, /* All port VSR data */ - MVS_COMMAND_ACTIVE = 0x300, -}; - -enum pci_cfg_registers { - PCR_PHY_CTL = 0x40, - PCR_PHY_CTL2 = 0x90, - PCR_DEV_CTRL = 0x78, - PCR_LINK_STAT = 0x82, -}; - -/* SAS/SATA Vendor Specific Port Registers */ -enum sas_sata_vsp_regs { - VSR_PHY_STAT = 0x00 * 4, /* Phy Interrupt Status */ - VSR_PHY_MODE1 = 0x01 * 4, /* phy Interrupt Enable */ - VSR_PHY_MODE2 = 0x02 * 4, /* Phy Configuration */ - VSR_PHY_MODE3 = 0x03 * 4, /* Phy Status */ - VSR_PHY_MODE4 = 0x04 * 4, /* Phy Counter 0 */ - VSR_PHY_MODE5 = 0x05 * 4, /* Phy Counter 1 */ - VSR_PHY_MODE6 = 0x06 * 4, /* Event Counter Control */ - VSR_PHY_MODE7 = 0x07 * 4, /* Event Counter Select */ - VSR_PHY_MODE8 = 0x08 * 4, /* Event Counter 0 */ - VSR_PHY_MODE9 = 0x09 * 4, /* Event Counter 1 */ - VSR_PHY_MODE10 = 0x0A * 4, /* Event Counter 2 */ - VSR_PHY_MODE11 = 0x0B * 4, /* Event Counter 3 */ - VSR_PHY_ACT_LED = 0x0C * 4, /* Activity LED control */ - - VSR_PHY_FFE_CONTROL = 0x10C, - VSR_PHY_DFE_UPDATE_CRTL = 0x110, - VSR_REF_CLOCK_CRTL = 0x1A0, -}; - -enum chip_register_bits { - PHY_MIN_SPP_PHYS_LINK_RATE_MASK = (0x7 << 8), - PHY_MAX_SPP_PHYS_LINK_RATE_MASK = (0x7 << 12), - PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET = (16), - PHY_NEG_SPP_PHYS_LINK_RATE_MASK = - (0x3 << PHY_NEG_SPP_PHYS_LINK_RATE_MASK_OFFSET), -}; - -enum pci_interrupt_cause { - /* MAIN_IRQ_CAUSE (R10200) Bits*/ - IRQ_COM_IN_I2O_IOP0 = (1 << 0), - IRQ_COM_IN_I2O_IOP1 = (1 << 1), - IRQ_COM_IN_I2O_IOP2 = (1 << 2), - IRQ_COM_IN_I2O_IOP3 = (1 << 3), - IRQ_COM_OUT_I2O_HOS0 = (1 << 4), - IRQ_COM_OUT_I2O_HOS1 = (1 << 5), - IRQ_COM_OUT_I2O_HOS2 = (1 << 6), - IRQ_COM_OUT_I2O_HOS3 = (1 << 7), - IRQ_PCIF_TO_CPU_DRBL0 = (1 << 8), - IRQ_PCIF_TO_CPU_DRBL1 = (1 << 9), - IRQ_PCIF_TO_CPU_DRBL2 = (1 << 10), - IRQ_PCIF_TO_CPU_DRBL3 = (1 << 11), - IRQ_PCIF_DRBL0 = (1 << 12), - IRQ_PCIF_DRBL1 = (1 << 13), - IRQ_PCIF_DRBL2 = (1 << 14), - IRQ_PCIF_DRBL3 = (1 << 15), - IRQ_XOR_A = (1 << 16), - IRQ_XOR_B = (1 << 17), - IRQ_SAS_A = (1 << 18), - IRQ_SAS_B = (1 << 19), - IRQ_CPU_CNTRL = (1 << 20), - IRQ_GPIO = (1 << 21), - IRQ_UART = (1 << 22), - IRQ_SPI = (1 << 23), - IRQ_I2C = (1 << 24), - IRQ_SGPIO = (1 << 25), - IRQ_COM_ERR = (1 << 29), - IRQ_I2O_ERR = (1 << 30), - IRQ_PCIE_ERR = (1 << 31), -}; - -union reg_phy_cfg { - u32 v; - struct { - u32 phy_reset:1; - u32 sas_support:1; - u32 sata_support:1; - u32 sata_host_mode:1; - /* - * bit 2: 6Gbps support - * bit 1: 3Gbps support - * bit 0: 1.5Gbps support - */ - u32 speed_support:3; - u32 snw_3_support:1; - u32 tx_lnk_parity:1; - /* - * bit 5: G1 (1.5Gbps) Without SSC - * bit 4: G1 (1.5Gbps) with SSC - * bit 3: G2 (3.0Gbps) Without SSC - * bit 2: G2 (3.0Gbps) with SSC - * bit 1: G3 (6.0Gbps) without SSC - * bit 0: G3 (6.0Gbps) with SSC - */ - u32 tx_spt_phs_lnk_rate:6; - /* 8h: 1.5Gbps 9h: 3Gbps Ah: 6Gbps */ - u32 tx_lgcl_lnk_rate:4; - u32 tx_ssc_type:1; - u32 sata_spin_up_spt:1; - u32 sata_spin_up_en:1; - u32 bypass_oob:1; - u32 disable_phy:1; - u32 rsvd:8; - } u; -}; - -#define MAX_SG_ENTRY 255 - -struct mvs_prd_imt { -#ifndef __BIG_ENDIAN - __le32 len:22; - u8 _r_a:2; - u8 misc_ctl:4; - u8 inter_sel:4; -#else - u32 inter_sel:4; - u32 misc_ctl:4; - u32 _r_a:2; - u32 len:22; -#endif -}; - -struct mvs_prd { - /* 64-bit buffer address */ - __le64 addr; - /* 22-bit length */ - __le32 im_len; -} __attribute__ ((packed)); - -/* - * these registers are accessed through port vendor - * specific address/data registers - */ -enum sas_sata_phy_regs { - GENERATION_1_SETTING = 0x118, - GENERATION_1_2_SETTING = 0x11C, - GENERATION_2_3_SETTING = 0x120, - GENERATION_3_4_SETTING = 0x124, -}; - -#define SPI_CTRL_REG_94XX 0xc800 -#define SPI_ADDR_REG_94XX 0xc804 -#define SPI_WR_DATA_REG_94XX 0xc808 -#define SPI_RD_DATA_REG_94XX 0xc80c -#define SPI_CTRL_READ_94XX (1U << 2) -#define SPI_ADDR_VLD_94XX (1U << 1) -#define SPI_CTRL_SpiStart_94XX (1U << 0) - -#define mv_ffc(x) ffz(x) - -static inline int -mv_ffc64(u64 v) -{ - int i; - i = mv_ffc((u32)v); - if (i >= 0) - return i; - i = mv_ffc((u32)(v>>32)); - - if (i != 0) - return 32 + i; - - return -1; -} - -#define r_reg_set_enable(i) \ - (((i) > 31) ? mr32(MVS_STP_REG_SET_1) : \ - mr32(MVS_STP_REG_SET_0)) - -#define w_reg_set_enable(i, tmp) \ - (((i) > 31) ? mw32(MVS_STP_REG_SET_1, tmp) : \ - mw32(MVS_STP_REG_SET_0, tmp)) - -extern const struct mvs_dispatch mvs_94xx_dispatch; -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_chips.h b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_chips.h deleted file mode 100644 index bcc40804..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_chips.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Marvell 88SE64xx/88SE94xx register IO interface - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - - -#ifndef _MV_CHIPS_H_ -#define _MV_CHIPS_H_ - -#define mr32(reg) readl(regs + reg) -#define mw32(reg, val) writel((val), regs + reg) -#define mw32_f(reg, val) do { \ - mw32(reg, val); \ - mr32(reg); \ - } while (0) - -#define iow32(reg, val) outl(val, (unsigned long)(regs + reg)) -#define ior32(reg) inl((unsigned long)(regs + reg)) -#define iow16(reg, val) outw((unsigned long)(val, regs + reg)) -#define ior16(reg) inw((unsigned long)(regs + reg)) -#define iow8(reg, val) outb((unsigned long)(val, regs + reg)) -#define ior8(reg) inb((unsigned long)(regs + reg)) - -static inline u32 mvs_cr32(struct mvs_info *mvi, u32 addr) -{ - void __iomem *regs = mvi->regs; - mw32(MVS_CMD_ADDR, addr); - return mr32(MVS_CMD_DATA); -} - -static inline void mvs_cw32(struct mvs_info *mvi, u32 addr, u32 val) -{ - void __iomem *regs = mvi->regs; - mw32(MVS_CMD_ADDR, addr); - mw32(MVS_CMD_DATA, val); -} - -static inline u32 mvs_read_phy_ctl(struct mvs_info *mvi, u32 port) -{ - void __iomem *regs = mvi->regs; - return (port < 4) ? mr32(MVS_P0_SER_CTLSTAT + port * 4) : - mr32(MVS_P4_SER_CTLSTAT + (port - 4) * 4); -} - -static inline void mvs_write_phy_ctl(struct mvs_info *mvi, u32 port, u32 val) -{ - void __iomem *regs = mvi->regs; - if (port < 4) - mw32(MVS_P0_SER_CTLSTAT + port * 4, val); - else - mw32(MVS_P4_SER_CTLSTAT + (port - 4) * 4, val); -} - -static inline u32 mvs_read_port(struct mvs_info *mvi, u32 off, - u32 off2, u32 port) -{ - void __iomem *regs = mvi->regs + off; - void __iomem *regs2 = mvi->regs + off2; - return (port < 4) ? readl(regs + port * 8) : - readl(regs2 + (port - 4) * 8); -} - -static inline void mvs_write_port(struct mvs_info *mvi, u32 off, u32 off2, - u32 port, u32 val) -{ - void __iomem *regs = mvi->regs + off; - void __iomem *regs2 = mvi->regs + off2; - if (port < 4) - writel(val, regs + port * 8); - else - writel(val, regs2 + (port - 4) * 8); -} - -static inline u32 mvs_read_port_cfg_data(struct mvs_info *mvi, u32 port) -{ - return mvs_read_port(mvi, MVS_P0_CFG_DATA, - MVS_P4_CFG_DATA, port); -} - -static inline void mvs_write_port_cfg_data(struct mvs_info *mvi, - u32 port, u32 val) -{ - mvs_write_port(mvi, MVS_P0_CFG_DATA, - MVS_P4_CFG_DATA, port, val); -} - -static inline void mvs_write_port_cfg_addr(struct mvs_info *mvi, - u32 port, u32 addr) -{ - mvs_write_port(mvi, MVS_P0_CFG_ADDR, - MVS_P4_CFG_ADDR, port, addr); - mdelay(10); -} - -static inline u32 mvs_read_port_vsr_data(struct mvs_info *mvi, u32 port) -{ - return mvs_read_port(mvi, MVS_P0_VSR_DATA, - MVS_P4_VSR_DATA, port); -} - -static inline void mvs_write_port_vsr_data(struct mvs_info *mvi, - u32 port, u32 val) -{ - mvs_write_port(mvi, MVS_P0_VSR_DATA, - MVS_P4_VSR_DATA, port, val); -} - -static inline void mvs_write_port_vsr_addr(struct mvs_info *mvi, - u32 port, u32 addr) -{ - mvs_write_port(mvi, MVS_P0_VSR_ADDR, - MVS_P4_VSR_ADDR, port, addr); - mdelay(10); -} - -static inline u32 mvs_read_port_irq_stat(struct mvs_info *mvi, u32 port) -{ - return mvs_read_port(mvi, MVS_P0_INT_STAT, - MVS_P4_INT_STAT, port); -} - -static inline void mvs_write_port_irq_stat(struct mvs_info *mvi, - u32 port, u32 val) -{ - mvs_write_port(mvi, MVS_P0_INT_STAT, - MVS_P4_INT_STAT, port, val); -} - -static inline u32 mvs_read_port_irq_mask(struct mvs_info *mvi, u32 port) -{ - return mvs_read_port(mvi, MVS_P0_INT_MASK, - MVS_P4_INT_MASK, port); - -} - -static inline void mvs_write_port_irq_mask(struct mvs_info *mvi, - u32 port, u32 val) -{ - mvs_write_port(mvi, MVS_P0_INT_MASK, - MVS_P4_INT_MASK, port, val); -} - -static inline void __devinit mvs_phy_hacks(struct mvs_info *mvi) -{ - u32 tmp; - - tmp = mvs_cr32(mvi, CMD_PHY_TIMER); - tmp &= ~(1 << 9); - tmp |= (1 << 10); - mvs_cw32(mvi, CMD_PHY_TIMER, tmp); - - /* enable retry 127 times */ - mvs_cw32(mvi, CMD_SAS_CTL1, 0x7f7f); - - /* extend open frame timeout to max */ - tmp = mvs_cr32(mvi, CMD_SAS_CTL0); - tmp &= ~0xffff; - tmp |= 0x3fff; - mvs_cw32(mvi, CMD_SAS_CTL0, tmp); - - mvs_cw32(mvi, CMD_WD_TIMER, 0x7a0000); - - /* not to halt for different port op during wideport link change */ - mvs_cw32(mvi, CMD_APP_ERR_CONFIG, 0xffefbf7d); -} - -static inline void mvs_int_sata(struct mvs_info *mvi) -{ - u32 tmp; - void __iomem *regs = mvi->regs; - tmp = mr32(MVS_INT_STAT_SRS_0); - if (tmp) - mw32(MVS_INT_STAT_SRS_0, tmp); - MVS_CHIP_DISP->clear_active_cmds(mvi); -} - -static inline void mvs_int_full(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - u32 tmp, stat; - int i; - - stat = mr32(MVS_INT_STAT); - mvs_int_rx(mvi, false); - - for (i = 0; i < mvi->chip->n_phy; i++) { - tmp = (stat >> i) & (CINT_PORT | CINT_PORT_STOPPED); - if (tmp) - mvs_int_port(mvi, i, tmp); - } - - if (stat & CINT_NON_SPEC_NCQ_ERROR) - MVS_CHIP_DISP->non_spec_ncq_error(mvi); - - if (stat & CINT_SRS) - mvs_int_sata(mvi); - - mw32(MVS_INT_STAT, stat); -} - -static inline void mvs_start_delivery(struct mvs_info *mvi, u32 tx) -{ - void __iomem *regs = mvi->regs; - mw32(MVS_TX_PROD_IDX, tx); -} - -static inline u32 mvs_rx_update(struct mvs_info *mvi) -{ - void __iomem *regs = mvi->regs; - return mr32(MVS_RX_CONS_IDX); -} - -static inline u32 mvs_get_prd_size(void) -{ - return sizeof(struct mvs_prd); -} - -static inline u32 mvs_get_prd_count(void) -{ - return MAX_SG_ENTRY; -} - -static inline void mvs_show_pcie_usage(struct mvs_info *mvi) -{ - u16 link_stat, link_spd; - const char *spd[] = { - "UnKnown", - "2.5", - "5.0", - }; - if (mvi->flags & MVF_FLAG_SOC || mvi->id > 0) - return; - - pci_read_config_word(mvi->pdev, PCR_LINK_STAT, &link_stat); - link_spd = (link_stat & PLS_LINK_SPD) >> PLS_LINK_SPD_OFFS; - if (link_spd >= 3) - link_spd = 0; - dev_printk(KERN_INFO, mvi->dev, - "mvsas: PCI-E x%u, Bandwidth Usage: %s Gbps\n", - (link_stat & PLS_NEG_LINK_WD) >> PLS_NEG_LINK_WD_OFFS, - spd[link_spd]); -} - -static inline u32 mvs_hw_max_link_rate(void) -{ - return MAX_LINK_RATE; -} - -#endif /* _MV_CHIPS_H_ */ - diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_defs.h b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_defs.h deleted file mode 100644 index f5451940..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_defs.h +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Marvell 88SE64xx/88SE94xx const head file - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - -#ifndef _MV_DEFS_H_ -#define _MV_DEFS_H_ - -#define PCI_DEVICE_ID_ARECA_1300 0x1300 -#define PCI_DEVICE_ID_ARECA_1320 0x1320 - -enum chip_flavors { - chip_6320, - chip_6440, - chip_6485, - chip_9480, - chip_9180, - chip_9445, - chip_9485, - chip_1300, - chip_1320 -}; - -/* driver compile-time configuration */ -enum driver_configuration { - MVS_TX_RING_SZ = 1024, /* TX ring size (12-bit) */ - MVS_RX_RING_SZ = 1024, /* RX ring size (12-bit) */ - /* software requires power-of-2 - ring size */ - MVS_SOC_SLOTS = 64, - MVS_SOC_TX_RING_SZ = MVS_SOC_SLOTS * 2, - MVS_SOC_RX_RING_SZ = MVS_SOC_SLOTS * 2, - - MVS_SLOT_BUF_SZ = 8192, /* cmd tbl + IU + status + PRD */ - MVS_SSP_CMD_SZ = 64, /* SSP command table buffer size */ - MVS_ATA_CMD_SZ = 96, /* SATA command table buffer size */ - MVS_OAF_SZ = 64, /* Open address frame buffer size */ - MVS_QUEUE_SIZE = 64, /* Support Queue depth */ - MVS_SOC_CAN_QUEUE = MVS_SOC_SLOTS - 2, -}; - -/* unchangeable hardware details */ -enum hardware_details { - MVS_MAX_PHYS = 8, /* max. possible phys */ - MVS_MAX_PORTS = 8, /* max. possible ports */ - MVS_SOC_PHYS = 4, /* soc phys */ - MVS_SOC_PORTS = 4, /* soc phys */ - MVS_MAX_DEVICES = 1024, /* max supported device */ -}; - -/* peripheral registers (BAR2) */ -enum peripheral_registers { - SPI_CTL = 0x10, /* EEPROM control */ - SPI_CMD = 0x14, /* EEPROM command */ - SPI_DATA = 0x18, /* EEPROM data */ -}; - -enum peripheral_register_bits { - TWSI_RDY = (1U << 7), /* EEPROM interface ready */ - TWSI_RD = (1U << 4), /* EEPROM read access */ - - SPI_ADDR_MASK = 0x3ffff, /* bits 17:0 */ -}; - -enum hw_register_bits { - /* MVS_GBL_CTL */ - INT_EN = (1U << 1), /* Global int enable */ - HBA_RST = (1U << 0), /* HBA reset */ - - /* MVS_GBL_INT_STAT */ - INT_XOR = (1U << 4), /* XOR engine event */ - INT_SAS_SATA = (1U << 0), /* SAS/SATA event */ - - /* MVS_GBL_PORT_TYPE */ /* shl for ports 1-3 */ - SATA_TARGET = (1U << 16), /* port0 SATA target enable */ - MODE_AUTO_DET_PORT7 = (1U << 15), /* port0 SAS/SATA autodetect */ - MODE_AUTO_DET_PORT6 = (1U << 14), - MODE_AUTO_DET_PORT5 = (1U << 13), - MODE_AUTO_DET_PORT4 = (1U << 12), - MODE_AUTO_DET_PORT3 = (1U << 11), - MODE_AUTO_DET_PORT2 = (1U << 10), - MODE_AUTO_DET_PORT1 = (1U << 9), - MODE_AUTO_DET_PORT0 = (1U << 8), - MODE_AUTO_DET_EN = MODE_AUTO_DET_PORT0 | MODE_AUTO_DET_PORT1 | - MODE_AUTO_DET_PORT2 | MODE_AUTO_DET_PORT3 | - MODE_AUTO_DET_PORT4 | MODE_AUTO_DET_PORT5 | - MODE_AUTO_DET_PORT6 | MODE_AUTO_DET_PORT7, - MODE_SAS_PORT7_MASK = (1U << 7), /* port0 SAS(1), SATA(0) mode */ - MODE_SAS_PORT6_MASK = (1U << 6), - MODE_SAS_PORT5_MASK = (1U << 5), - MODE_SAS_PORT4_MASK = (1U << 4), - MODE_SAS_PORT3_MASK = (1U << 3), - MODE_SAS_PORT2_MASK = (1U << 2), - MODE_SAS_PORT1_MASK = (1U << 1), - MODE_SAS_PORT0_MASK = (1U << 0), - MODE_SAS_SATA = MODE_SAS_PORT0_MASK | MODE_SAS_PORT1_MASK | - MODE_SAS_PORT2_MASK | MODE_SAS_PORT3_MASK | - MODE_SAS_PORT4_MASK | MODE_SAS_PORT5_MASK | - MODE_SAS_PORT6_MASK | MODE_SAS_PORT7_MASK, - - /* SAS_MODE value may be - * dictated (in hw) by values - * of SATA_TARGET & AUTO_DET - */ - - /* MVS_TX_CFG */ - TX_EN = (1U << 16), /* Enable TX */ - TX_RING_SZ_MASK = 0xfff, /* TX ring size, bits 11:0 */ - - /* MVS_RX_CFG */ - RX_EN = (1U << 16), /* Enable RX */ - RX_RING_SZ_MASK = 0xfff, /* RX ring size, bits 11:0 */ - - /* MVS_INT_COAL */ - COAL_EN = (1U << 16), /* Enable int coalescing */ - - /* MVS_INT_STAT, MVS_INT_MASK */ - CINT_I2C = (1U << 31), /* I2C event */ - CINT_SW0 = (1U << 30), /* software event 0 */ - CINT_SW1 = (1U << 29), /* software event 1 */ - CINT_PRD_BC = (1U << 28), /* PRD BC err for read cmd */ - CINT_DMA_PCIE = (1U << 27), /* DMA to PCIE timeout */ - CINT_MEM = (1U << 26), /* int mem parity err */ - CINT_I2C_SLAVE = (1U << 25), /* slave I2C event */ - CINT_NON_SPEC_NCQ_ERROR = (1U << 25), /* Non specific NCQ error */ - CINT_SRS = (1U << 3), /* SRS event */ - CINT_CI_STOP = (1U << 1), /* cmd issue stopped */ - CINT_DONE = (1U << 0), /* cmd completion */ - - /* shl for ports 1-3 */ - CINT_PORT_STOPPED = (1U << 16), /* port0 stopped */ - CINT_PORT = (1U << 8), /* port0 event */ - CINT_PORT_MASK_OFFSET = 8, - CINT_PORT_MASK = (0xFF << CINT_PORT_MASK_OFFSET), - CINT_PHY_MASK_OFFSET = 4, - CINT_PHY_MASK = (0x0F << CINT_PHY_MASK_OFFSET), - - /* TX (delivery) ring bits */ - TXQ_CMD_SHIFT = 29, - TXQ_CMD_SSP = 1, /* SSP protocol */ - TXQ_CMD_SMP = 2, /* SMP protocol */ - TXQ_CMD_STP = 3, /* STP/SATA protocol */ - TXQ_CMD_SSP_FREE_LIST = 4, /* add to SSP target free list */ - TXQ_CMD_SLOT_RESET = 7, /* reset command slot */ - TXQ_MODE_I = (1U << 28), /* mode: 0=target,1=initiator */ - TXQ_MODE_TARGET = 0, - TXQ_MODE_INITIATOR = 1, - TXQ_PRIO_HI = (1U << 27), /* priority: 0=normal, 1=high */ - TXQ_PRI_NORMAL = 0, - TXQ_PRI_HIGH = 1, - TXQ_SRS_SHIFT = 20, /* SATA register set */ - TXQ_SRS_MASK = 0x7f, - TXQ_PHY_SHIFT = 12, /* PHY bitmap */ - TXQ_PHY_MASK = 0xff, - TXQ_SLOT_MASK = 0xfff, /* slot number */ - - /* RX (completion) ring bits */ - RXQ_GOOD = (1U << 23), /* Response good */ - RXQ_SLOT_RESET = (1U << 21), /* Slot reset complete */ - RXQ_CMD_RX = (1U << 20), /* target cmd received */ - RXQ_ATTN = (1U << 19), /* attention */ - RXQ_RSP = (1U << 18), /* response frame xfer'd */ - RXQ_ERR = (1U << 17), /* err info rec xfer'd */ - RXQ_DONE = (1U << 16), /* cmd complete */ - RXQ_SLOT_MASK = 0xfff, /* slot number */ - - /* mvs_cmd_hdr bits */ - MCH_PRD_LEN_SHIFT = 16, /* 16-bit PRD table len */ - MCH_SSP_FR_TYPE_SHIFT = 13, /* SSP frame type */ - - /* SSP initiator only */ - MCH_SSP_FR_CMD = 0x0, /* COMMAND frame */ - - /* SSP initiator or target */ - MCH_SSP_FR_TASK = 0x1, /* TASK frame */ - - /* SSP target only */ - MCH_SSP_FR_XFER_RDY = 0x4, /* XFER_RDY frame */ - MCH_SSP_FR_RESP = 0x5, /* RESPONSE frame */ - MCH_SSP_FR_READ = 0x6, /* Read DATA frame(s) */ - MCH_SSP_FR_READ_RESP = 0x7, /* ditto, plus RESPONSE */ - - MCH_SSP_MODE_PASSTHRU = 1, - MCH_SSP_MODE_NORMAL = 0, - MCH_PASSTHRU = (1U << 12), /* pass-through (SSP) */ - MCH_FBURST = (1U << 11), /* first burst (SSP) */ - MCH_CHK_LEN = (1U << 10), /* chk xfer len (SSP) */ - MCH_RETRY = (1U << 9), /* tport layer retry (SSP) */ - MCH_PROTECTION = (1U << 8), /* protection info rec (SSP) */ - MCH_RESET = (1U << 7), /* Reset (STP/SATA) */ - MCH_FPDMA = (1U << 6), /* First party DMA (STP/SATA) */ - MCH_ATAPI = (1U << 5), /* ATAPI (STP/SATA) */ - MCH_BIST = (1U << 4), /* BIST activate (STP/SATA) */ - MCH_PMP_MASK = 0xf, /* PMP from cmd FIS (STP/SATA)*/ - - CCTL_RST = (1U << 5), /* port logic reset */ - - /* 0(LSB first), 1(MSB first) */ - CCTL_ENDIAN_DATA = (1U << 3), /* PRD data */ - CCTL_ENDIAN_RSP = (1U << 2), /* response frame */ - CCTL_ENDIAN_OPEN = (1U << 1), /* open address frame */ - CCTL_ENDIAN_CMD = (1U << 0), /* command table */ - - /* MVS_Px_SER_CTLSTAT (per-phy control) */ - PHY_SSP_RST = (1U << 3), /* reset SSP link layer */ - PHY_BCAST_CHG = (1U << 2), /* broadcast(change) notif */ - PHY_RST_HARD = (1U << 1), /* hard reset + phy reset */ - PHY_RST = (1U << 0), /* phy reset */ - PHY_READY_MASK = (1U << 20), - - /* MVS_Px_INT_STAT, MVS_Px_INT_MASK (per-phy events) */ - PHYEV_DEC_ERR = (1U << 24), /* Phy Decoding Error */ - PHYEV_DCDR_ERR = (1U << 23), /* STP Deocder Error */ - PHYEV_CRC_ERR = (1U << 22), /* STP CRC Error */ - PHYEV_UNASSOC_FIS = (1U << 19), /* unassociated FIS rx'd */ - PHYEV_AN = (1U << 18), /* SATA async notification */ - PHYEV_BIST_ACT = (1U << 17), /* BIST activate FIS */ - PHYEV_SIG_FIS = (1U << 16), /* signature FIS */ - PHYEV_POOF = (1U << 12), /* phy ready from 1 -> 0 */ - PHYEV_IU_BIG = (1U << 11), /* IU too long err */ - PHYEV_IU_SMALL = (1U << 10), /* IU too short err */ - PHYEV_UNK_TAG = (1U << 9), /* unknown tag */ - PHYEV_BROAD_CH = (1U << 8), /* broadcast(CHANGE) */ - PHYEV_COMWAKE = (1U << 7), /* COMWAKE rx'd */ - PHYEV_PORT_SEL = (1U << 6), /* port selector present */ - PHYEV_HARD_RST = (1U << 5), /* hard reset rx'd */ - PHYEV_ID_TMOUT = (1U << 4), /* identify timeout */ - PHYEV_ID_FAIL = (1U << 3), /* identify failed */ - PHYEV_ID_DONE = (1U << 2), /* identify done */ - PHYEV_HARD_RST_DONE = (1U << 1), /* hard reset done */ - PHYEV_RDY_CH = (1U << 0), /* phy ready changed state */ - - /* MVS_PCS */ - PCS_EN_SATA_REG_SHIFT = (16), /* Enable SATA Register Set */ - PCS_EN_PORT_XMT_SHIFT = (12), /* Enable Port Transmit */ - PCS_EN_PORT_XMT_SHIFT2 = (8), /* For 6485 */ - PCS_SATA_RETRY = (1U << 8), /* retry ctl FIS on R_ERR */ - PCS_RSP_RX_EN = (1U << 7), /* raw response rx */ - PCS_SATA_RETRY_2 = (1U << 6), /* For 9180 */ - PCS_SELF_CLEAR = (1U << 5), /* self-clearing int mode */ - PCS_FIS_RX_EN = (1U << 4), /* FIS rx enable */ - PCS_CMD_STOP_ERR = (1U << 3), /* cmd stop-on-err enable */ - PCS_CMD_RST = (1U << 1), /* reset cmd issue */ - PCS_CMD_EN = (1U << 0), /* enable cmd issue */ - - /* Port n Attached Device Info */ - PORT_DEV_SSP_TRGT = (1U << 19), - PORT_DEV_SMP_TRGT = (1U << 18), - PORT_DEV_STP_TRGT = (1U << 17), - PORT_DEV_SSP_INIT = (1U << 11), - PORT_DEV_SMP_INIT = (1U << 10), - PORT_DEV_STP_INIT = (1U << 9), - PORT_PHY_ID_MASK = (0xFFU << 24), - PORT_SSP_TRGT_MASK = (0x1U << 19), - PORT_SSP_INIT_MASK = (0x1U << 11), - PORT_DEV_TRGT_MASK = (0x7U << 17), - PORT_DEV_INIT_MASK = (0x7U << 9), - PORT_DEV_TYPE_MASK = (0x7U << 0), - - /* Port n PHY Status */ - PHY_RDY = (1U << 2), - PHY_DW_SYNC = (1U << 1), - PHY_OOB_DTCTD = (1U << 0), - - /* VSR */ - /* PHYMODE 6 (CDB) */ - PHY_MODE6_LATECLK = (1U << 29), /* Lock Clock */ - PHY_MODE6_DTL_SPEED = (1U << 27), /* Digital Loop Speed */ - PHY_MODE6_FC_ORDER = (1U << 26), /* Fibre Channel Mode Order*/ - PHY_MODE6_MUCNT_EN = (1U << 24), /* u Count Enable */ - PHY_MODE6_SEL_MUCNT_LEN = (1U << 22), /* Training Length Select */ - PHY_MODE6_SELMUPI = (1U << 20), /* Phase Multi Select (init) */ - PHY_MODE6_SELMUPF = (1U << 18), /* Phase Multi Select (final) */ - PHY_MODE6_SELMUFF = (1U << 16), /* Freq Loop Multi Sel(final) */ - PHY_MODE6_SELMUFI = (1U << 14), /* Freq Loop Multi Sel(init) */ - PHY_MODE6_FREEZE_LOOP = (1U << 12), /* Freeze Rx CDR Loop */ - PHY_MODE6_INT_RXFOFFS = (1U << 3), /* Rx CDR Freq Loop Enable */ - PHY_MODE6_FRC_RXFOFFS = (1U << 2), /* Initial Rx CDR Offset */ - PHY_MODE6_STAU_0D8 = (1U << 1), /* Rx CDR Freq Loop Saturate */ - PHY_MODE6_RXSAT_DIS = (1U << 0), /* Saturate Ctl */ -}; - -/* SAS/SATA configuration port registers, aka phy registers */ -enum sas_sata_config_port_regs { - PHYR_IDENTIFY = 0x00, /* info for IDENTIFY frame */ - PHYR_ADDR_LO = 0x04, /* my SAS address (low) */ - PHYR_ADDR_HI = 0x08, /* my SAS address (high) */ - PHYR_ATT_DEV_INFO = 0x0C, /* attached device info */ - PHYR_ATT_ADDR_LO = 0x10, /* attached dev SAS addr (low) */ - PHYR_ATT_ADDR_HI = 0x14, /* attached dev SAS addr (high) */ - PHYR_SATA_CTL = 0x18, /* SATA control */ - PHYR_PHY_STAT = 0x1C, /* PHY status */ - PHYR_SATA_SIG0 = 0x20, /*port SATA signature FIS(Byte 0-3) */ - PHYR_SATA_SIG1 = 0x24, /*port SATA signature FIS(Byte 4-7) */ - PHYR_SATA_SIG2 = 0x28, /*port SATA signature FIS(Byte 8-11) */ - PHYR_SATA_SIG3 = 0x2c, /*port SATA signature FIS(Byte 12-15) */ - PHYR_R_ERR_COUNT = 0x30, /* port R_ERR count register */ - PHYR_CRC_ERR_COUNT = 0x34, /* port CRC error count register */ - PHYR_WIDE_PORT = 0x38, /* wide port participating */ - PHYR_CURRENT0 = 0x80, /* current connection info 0 */ - PHYR_CURRENT1 = 0x84, /* current connection info 1 */ - PHYR_CURRENT2 = 0x88, /* current connection info 2 */ - CONFIG_ID_FRAME0 = 0x100, /* Port device ID frame register 0 */ - CONFIG_ID_FRAME1 = 0x104, /* Port device ID frame register 1 */ - CONFIG_ID_FRAME2 = 0x108, /* Port device ID frame register 2 */ - CONFIG_ID_FRAME3 = 0x10c, /* Port device ID frame register 3 */ - CONFIG_ID_FRAME4 = 0x110, /* Port device ID frame register 4 */ - CONFIG_ID_FRAME5 = 0x114, /* Port device ID frame register 5 */ - CONFIG_ID_FRAME6 = 0x118, /* Port device ID frame register 6 */ - CONFIG_ATT_ID_FRAME0 = 0x11c, /* attached ID frame register 0 */ - CONFIG_ATT_ID_FRAME1 = 0x120, /* attached ID frame register 1 */ - CONFIG_ATT_ID_FRAME2 = 0x124, /* attached ID frame register 2 */ - CONFIG_ATT_ID_FRAME3 = 0x128, /* attached ID frame register 3 */ - CONFIG_ATT_ID_FRAME4 = 0x12c, /* attached ID frame register 4 */ - CONFIG_ATT_ID_FRAME5 = 0x130, /* attached ID frame register 5 */ - CONFIG_ATT_ID_FRAME6 = 0x134, /* attached ID frame register 6 */ -}; - -enum sas_cmd_port_registers { - CMD_CMRST_OOB_DET = 0x100, /* COMRESET OOB detect register */ - CMD_CMWK_OOB_DET = 0x104, /* COMWAKE OOB detect register */ - CMD_CMSAS_OOB_DET = 0x108, /* COMSAS OOB detect register */ - CMD_BRST_OOB_DET = 0x10c, /* burst OOB detect register */ - CMD_OOB_SPACE = 0x110, /* OOB space control register */ - CMD_OOB_BURST = 0x114, /* OOB burst control register */ - CMD_PHY_TIMER = 0x118, /* PHY timer control register */ - CMD_PHY_CONFIG0 = 0x11c, /* PHY config register 0 */ - CMD_PHY_CONFIG1 = 0x120, /* PHY config register 1 */ - CMD_SAS_CTL0 = 0x124, /* SAS control register 0 */ - CMD_SAS_CTL1 = 0x128, /* SAS control register 1 */ - CMD_SAS_CTL2 = 0x12c, /* SAS control register 2 */ - CMD_SAS_CTL3 = 0x130, /* SAS control register 3 */ - CMD_ID_TEST = 0x134, /* ID test register */ - CMD_PL_TIMER = 0x138, /* PL timer register */ - CMD_WD_TIMER = 0x13c, /* WD timer register */ - CMD_PORT_SEL_COUNT = 0x140, /* port selector count register */ - CMD_APP_MEM_CTL = 0x144, /* Application Memory Control */ - CMD_XOR_MEM_CTL = 0x148, /* XOR Block Memory Control */ - CMD_DMA_MEM_CTL = 0x14c, /* DMA Block Memory Control */ - CMD_PORT_MEM_CTL0 = 0x150, /* Port Memory Control 0 */ - CMD_PORT_MEM_CTL1 = 0x154, /* Port Memory Control 1 */ - CMD_SATA_PORT_MEM_CTL0 = 0x158, /* SATA Port Memory Control 0 */ - CMD_SATA_PORT_MEM_CTL1 = 0x15c, /* SATA Port Memory Control 1 */ - CMD_XOR_MEM_BIST_CTL = 0x160, /* XOR Memory BIST Control */ - CMD_XOR_MEM_BIST_STAT = 0x164, /* XOR Memroy BIST Status */ - CMD_DMA_MEM_BIST_CTL = 0x168, /* DMA Memory BIST Control */ - CMD_DMA_MEM_BIST_STAT = 0x16c, /* DMA Memory BIST Status */ - CMD_PORT_MEM_BIST_CTL = 0x170, /* Port Memory BIST Control */ - CMD_PORT_MEM_BIST_STAT0 = 0x174, /* Port Memory BIST Status 0 */ - CMD_PORT_MEM_BIST_STAT1 = 0x178, /* Port Memory BIST Status 1 */ - CMD_STP_MEM_BIST_CTL = 0x17c, /* STP Memory BIST Control */ - CMD_STP_MEM_BIST_STAT0 = 0x180, /* STP Memory BIST Status 0 */ - CMD_STP_MEM_BIST_STAT1 = 0x184, /* STP Memory BIST Status 1 */ - CMD_RESET_COUNT = 0x188, /* Reset Count */ - CMD_MONTR_DATA_SEL = 0x18C, /* Monitor Data/Select */ - CMD_PLL_PHY_CONFIG = 0x190, /* PLL/PHY Configuration */ - CMD_PHY_CTL = 0x194, /* PHY Control and Status */ - CMD_PHY_TEST_COUNT0 = 0x198, /* Phy Test Count 0 */ - CMD_PHY_TEST_COUNT1 = 0x19C, /* Phy Test Count 1 */ - CMD_PHY_TEST_COUNT2 = 0x1A0, /* Phy Test Count 2 */ - CMD_APP_ERR_CONFIG = 0x1A4, /* Application Error Configuration */ - CMD_PND_FIFO_CTL0 = 0x1A8, /* Pending FIFO Control 0 */ - CMD_HOST_CTL = 0x1AC, /* Host Control Status */ - CMD_HOST_WR_DATA = 0x1B0, /* Host Write Data */ - CMD_HOST_RD_DATA = 0x1B4, /* Host Read Data */ - CMD_PHY_MODE_21 = 0x1B8, /* Phy Mode 21 */ - CMD_SL_MODE0 = 0x1BC, /* SL Mode 0 */ - CMD_SL_MODE1 = 0x1C0, /* SL Mode 1 */ - CMD_PND_FIFO_CTL1 = 0x1C4, /* Pending FIFO Control 1 */ - CMD_PORT_LAYER_TIMER1 = 0x1E0, /* Port Layer Timer 1 */ - CMD_LINK_TIMER = 0x1E4, /* Link Timer */ -}; - -enum mvs_info_flags { - MVF_PHY_PWR_FIX = (1U << 1), /* bug workaround */ - MVF_FLAG_SOC = (1U << 2), /* SoC integrated controllers */ -}; - -enum mvs_event_flags { - PHY_PLUG_EVENT = (3U), - PHY_PLUG_IN = (1U << 0), /* phy plug in */ - PHY_PLUG_OUT = (1U << 1), /* phy plug out */ - EXP_BRCT_CHG = (1U << 2), /* broadcast change */ -}; - -enum mvs_port_type { - PORT_TGT_MASK = (1U << 5), - PORT_INIT_PORT = (1U << 4), - PORT_TGT_PORT = (1U << 3), - PORT_INIT_TGT_PORT = (PORT_INIT_PORT | PORT_TGT_PORT), - PORT_TYPE_SAS = (1U << 1), - PORT_TYPE_SATA = (1U << 0), -}; - -/* Command Table Format */ -enum ct_format { - /* SSP */ - SSP_F_H = 0x00, - SSP_F_IU = 0x18, - SSP_F_MAX = 0x4D, - /* STP */ - STP_CMD_FIS = 0x00, - STP_ATAPI_CMD = 0x40, - STP_F_MAX = 0x10, - /* SMP */ - SMP_F_T = 0x00, - SMP_F_DEP = 0x01, - SMP_F_MAX = 0x101, -}; - -enum status_buffer { - SB_EIR_OFF = 0x00, /* Error Information Record */ - SB_RFB_OFF = 0x08, /* Response Frame Buffer */ - SB_RFB_MAX = 0x400, /* RFB size*/ -}; - -enum error_info_rec { - CMD_ISS_STPD = (1U << 31), /* Cmd Issue Stopped */ - CMD_PI_ERR = (1U << 30), /* Protection info error. see flags2 */ - RSP_OVER = (1U << 29), /* rsp buffer overflow */ - RETRY_LIM = (1U << 28), /* FIS/frame retry limit exceeded */ - UNK_FIS = (1U << 27), /* unknown FIS */ - DMA_TERM = (1U << 26), /* DMA terminate primitive rx'd */ - SYNC_ERR = (1U << 25), /* SYNC rx'd during frame xmit */ - TFILE_ERR = (1U << 24), /* SATA taskfile Error bit set */ - R_ERR = (1U << 23), /* SATA returned R_ERR prim */ - RD_OFS = (1U << 20), /* Read DATA frame invalid offset */ - XFER_RDY_OFS = (1U << 19), /* XFER_RDY offset error */ - UNEXP_XFER_RDY = (1U << 18), /* unexpected XFER_RDY error */ - DATA_OVER_UNDER = (1U << 16), /* data overflow/underflow */ - INTERLOCK = (1U << 15), /* interlock error */ - NAK = (1U << 14), /* NAK rx'd */ - ACK_NAK_TO = (1U << 13), /* ACK/NAK timeout */ - CXN_CLOSED = (1U << 12), /* cxn closed w/out ack/nak */ - OPEN_TO = (1U << 11), /* I_T nexus lost, open cxn timeout */ - PATH_BLOCKED = (1U << 10), /* I_T nexus lost, pathway blocked */ - NO_DEST = (1U << 9), /* I_T nexus lost, no destination */ - STP_RES_BSY = (1U << 8), /* STP resources busy */ - BREAK = (1U << 7), /* break received */ - BAD_DEST = (1U << 6), /* bad destination */ - BAD_PROTO = (1U << 5), /* protocol not supported */ - BAD_RATE = (1U << 4), /* cxn rate not supported */ - WRONG_DEST = (1U << 3), /* wrong destination error */ - CREDIT_TO = (1U << 2), /* credit timeout */ - WDOG_TO = (1U << 1), /* watchdog timeout */ - BUF_PAR = (1U << 0), /* buffer parity error */ -}; - -enum error_info_rec_2 { - SLOT_BSY_ERR = (1U << 31), /* Slot Busy Error */ - GRD_CHK_ERR = (1U << 14), /* Guard Check Error */ - APP_CHK_ERR = (1U << 13), /* Application Check error */ - REF_CHK_ERR = (1U << 12), /* Reference Check Error */ - USR_BLK_NM = (1U << 0), /* User Block Number */ -}; - -enum pci_cfg_register_bits { - PCTL_PWR_OFF = (0xFU << 24), - PCTL_COM_ON = (0xFU << 20), - PCTL_LINK_RST = (0xFU << 16), - PCTL_LINK_OFFS = (16), - PCTL_PHY_DSBL = (0xFU << 12), - PCTL_PHY_DSBL_OFFS = (12), - PRD_REQ_SIZE = (0x4000), - PRD_REQ_MASK = (0x00007000), - PLS_NEG_LINK_WD = (0x3FU << 4), - PLS_NEG_LINK_WD_OFFS = 4, - PLS_LINK_SPD = (0x0FU << 0), - PLS_LINK_SPD_OFFS = 0, -}; - -enum open_frame_protocol { - PROTOCOL_SMP = 0x0, - PROTOCOL_SSP = 0x1, - PROTOCOL_STP = 0x2, -}; - -/* define for response frame datapres field */ -enum datapres_field { - NO_DATA = 0, - RESPONSE_DATA = 1, - SENSE_DATA = 2, -}; - -/* define task management IU */ -struct mvs_tmf_task{ - u8 tmf; - u16 tag_of_task_to_be_managed; -}; -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_init.c b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_init.c deleted file mode 100644 index cc59dff3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_init.c +++ /dev/null @@ -1,869 +0,0 @@ -/* - * Marvell 88SE64xx/88SE94xx pci init - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - - -#include "mv_sas.h" - -static int lldd_max_execute_num = 1; -module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); -MODULE_PARM_DESC(collector, "\n" - "\tIf greater than one, tells the SAS Layer to run in Task Collector\n" - "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n" - "\tThe mvsas SAS LLDD supports both modes.\n" - "\tDefault: 1 (Direct Mode).\n"); - -int interrupt_coalescing = 0x80; - -static struct scsi_transport_template *mvs_stt; -struct kmem_cache *mvs_task_list_cache; -static const struct mvs_chip_info mvs_chips[] = { - [chip_6320] = { 1, 2, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, - [chip_6440] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, - [chip_6485] = { 1, 8, 0x800, 33, 32, 6, 10, &mvs_64xx_dispatch, }, - [chip_9180] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, - [chip_9480] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, - [chip_9445] = { 1, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, }, - [chip_9485] = { 2, 4, 0x800, 17, 64, 8, 11, &mvs_94xx_dispatch, }, - [chip_1300] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, }, - [chip_1320] = { 2, 4, 0x800, 17, 64, 8, 9, &mvs_94xx_dispatch, }, -}; - -struct device_attribute *mvst_host_attrs[]; - -#define SOC_SAS_NUM 2 - -static struct scsi_host_template mvs_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .queuecommand = sas_queuecommand, - .target_alloc = sas_target_alloc, - .slave_configure = sas_slave_configure, - .scan_finished = mvs_scan_finished, - .scan_start = mvs_scan_start, - .change_queue_depth = sas_change_queue_depth, - .change_queue_type = sas_change_queue_type, - .bios_param = sas_bios_param, - .can_queue = 1, - .cmd_per_lun = 1, - .this_id = -1, - .sg_tablesize = SG_ALL, - .max_sectors = SCSI_DEFAULT_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .eh_device_reset_handler = sas_eh_device_reset_handler, - .eh_bus_reset_handler = sas_eh_bus_reset_handler, - .target_destroy = sas_target_destroy, - .ioctl = sas_ioctl, - .shost_attrs = mvst_host_attrs, -}; - -static struct sas_domain_function_template mvs_transport_ops = { - .lldd_dev_found = mvs_dev_found, - .lldd_dev_gone = mvs_dev_gone, - .lldd_execute_task = mvs_queue_command, - .lldd_control_phy = mvs_phy_control, - - .lldd_abort_task = mvs_abort_task, - .lldd_abort_task_set = mvs_abort_task_set, - .lldd_clear_aca = mvs_clear_aca, - .lldd_clear_task_set = mvs_clear_task_set, - .lldd_I_T_nexus_reset = mvs_I_T_nexus_reset, - .lldd_lu_reset = mvs_lu_reset, - .lldd_query_task = mvs_query_task, - .lldd_port_formed = mvs_port_formed, - .lldd_port_deformed = mvs_port_deformed, - -}; - -static void __devinit mvs_phy_init(struct mvs_info *mvi, int phy_id) -{ - struct mvs_phy *phy = &mvi->phy[phy_id]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - - phy->mvi = mvi; - phy->port = NULL; - init_timer(&phy->timer); - sas_phy->enabled = (phy_id < mvi->chip->n_phy) ? 1 : 0; - sas_phy->class = SAS; - sas_phy->iproto = SAS_PROTOCOL_ALL; - sas_phy->tproto = 0; - sas_phy->type = PHY_TYPE_PHYSICAL; - sas_phy->role = PHY_ROLE_INITIATOR; - sas_phy->oob_mode = OOB_NOT_CONNECTED; - sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; - - sas_phy->id = phy_id; - sas_phy->sas_addr = &mvi->sas_addr[0]; - sas_phy->frame_rcvd = &phy->frame_rcvd[0]; - sas_phy->ha = (struct sas_ha_struct *)mvi->shost->hostdata; - sas_phy->lldd_phy = phy; -} - -static void mvs_free(struct mvs_info *mvi) -{ - struct mvs_wq *mwq; - int slot_nr; - - if (!mvi) - return; - - if (mvi->flags & MVF_FLAG_SOC) - slot_nr = MVS_SOC_SLOTS; - else - slot_nr = MVS_CHIP_SLOT_SZ; - - if (mvi->dma_pool) - pci_pool_destroy(mvi->dma_pool); - - if (mvi->tx) - dma_free_coherent(mvi->dev, - sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, - mvi->tx, mvi->tx_dma); - if (mvi->rx_fis) - dma_free_coherent(mvi->dev, MVS_RX_FISL_SZ, - mvi->rx_fis, mvi->rx_fis_dma); - if (mvi->rx) - dma_free_coherent(mvi->dev, - sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), - mvi->rx, mvi->rx_dma); - if (mvi->slot) - dma_free_coherent(mvi->dev, - sizeof(*mvi->slot) * slot_nr, - mvi->slot, mvi->slot_dma); - - if (mvi->bulk_buffer) - dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE, - mvi->bulk_buffer, mvi->bulk_buffer_dma); - if (mvi->bulk_buffer1) - dma_free_coherent(mvi->dev, TRASH_BUCKET_SIZE, - mvi->bulk_buffer1, mvi->bulk_buffer_dma1); - - MVS_CHIP_DISP->chip_iounmap(mvi); - if (mvi->shost) - scsi_host_put(mvi->shost); - list_for_each_entry(mwq, &mvi->wq_list, entry) - cancel_delayed_work(&mwq->work_q); - kfree(mvi->tags); - kfree(mvi); -} - -#ifdef CONFIG_SCSI_MVSAS_TASKLET -static void mvs_tasklet(unsigned long opaque) -{ - u32 stat; - u16 core_nr, i = 0; - - struct mvs_info *mvi; - struct sas_ha_struct *sha = (struct sas_ha_struct *)opaque; - - core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; - - if (unlikely(!mvi)) - BUG_ON(1); - - stat = MVS_CHIP_DISP->isr_status(mvi, mvi->pdev->irq); - if (!stat) - goto out; - - for (i = 0; i < core_nr; i++) { - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; - MVS_CHIP_DISP->isr(mvi, mvi->pdev->irq, stat); - } -out: - MVS_CHIP_DISP->interrupt_enable(mvi); - -} -#endif - -static irqreturn_t mvs_interrupt(int irq, void *opaque) -{ - u32 core_nr; - u32 stat; - struct mvs_info *mvi; - struct sas_ha_struct *sha = opaque; -#ifndef CONFIG_SCSI_MVSAS_TASKLET - u32 i; -#endif - - core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; - - if (unlikely(!mvi)) - return IRQ_NONE; -#ifdef CONFIG_SCSI_MVSAS_TASKLET - MVS_CHIP_DISP->interrupt_disable(mvi); -#endif - - stat = MVS_CHIP_DISP->isr_status(mvi, irq); - if (!stat) { - #ifdef CONFIG_SCSI_MVSAS_TASKLET - MVS_CHIP_DISP->interrupt_enable(mvi); - #endif - return IRQ_NONE; - } - -#ifdef CONFIG_SCSI_MVSAS_TASKLET - tasklet_schedule(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); -#else - for (i = 0; i < core_nr; i++) { - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; - MVS_CHIP_DISP->isr(mvi, irq, stat); - } -#endif - return IRQ_HANDLED; -} - -static int __devinit mvs_alloc(struct mvs_info *mvi, struct Scsi_Host *shost) -{ - int i = 0, slot_nr; - char pool_name[32]; - - if (mvi->flags & MVF_FLAG_SOC) - slot_nr = MVS_SOC_SLOTS; - else - slot_nr = MVS_CHIP_SLOT_SZ; - - spin_lock_init(&mvi->lock); - for (i = 0; i < mvi->chip->n_phy; i++) { - mvs_phy_init(mvi, i); - mvi->port[i].wide_port_phymap = 0; - mvi->port[i].port_attached = 0; - INIT_LIST_HEAD(&mvi->port[i].list); - } - for (i = 0; i < MVS_MAX_DEVICES; i++) { - mvi->devices[i].taskfileset = MVS_ID_NOT_MAPPED; - mvi->devices[i].dev_type = NO_DEVICE; - mvi->devices[i].device_id = i; - mvi->devices[i].dev_status = MVS_DEV_NORMAL; - init_timer(&mvi->devices[i].timer); - } - - /* - * alloc and init our DMA areas - */ - mvi->tx = dma_alloc_coherent(mvi->dev, - sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ, - &mvi->tx_dma, GFP_KERNEL); - if (!mvi->tx) - goto err_out; - memset(mvi->tx, 0, sizeof(*mvi->tx) * MVS_CHIP_SLOT_SZ); - mvi->rx_fis = dma_alloc_coherent(mvi->dev, MVS_RX_FISL_SZ, - &mvi->rx_fis_dma, GFP_KERNEL); - if (!mvi->rx_fis) - goto err_out; - memset(mvi->rx_fis, 0, MVS_RX_FISL_SZ); - - mvi->rx = dma_alloc_coherent(mvi->dev, - sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1), - &mvi->rx_dma, GFP_KERNEL); - if (!mvi->rx) - goto err_out; - memset(mvi->rx, 0, sizeof(*mvi->rx) * (MVS_RX_RING_SZ + 1)); - mvi->rx[0] = cpu_to_le32(0xfff); - mvi->rx_cons = 0xfff; - - mvi->slot = dma_alloc_coherent(mvi->dev, - sizeof(*mvi->slot) * slot_nr, - &mvi->slot_dma, GFP_KERNEL); - if (!mvi->slot) - goto err_out; - memset(mvi->slot, 0, sizeof(*mvi->slot) * slot_nr); - - mvi->bulk_buffer = dma_alloc_coherent(mvi->dev, - TRASH_BUCKET_SIZE, - &mvi->bulk_buffer_dma, GFP_KERNEL); - if (!mvi->bulk_buffer) - goto err_out; - - mvi->bulk_buffer1 = dma_alloc_coherent(mvi->dev, - TRASH_BUCKET_SIZE, - &mvi->bulk_buffer_dma1, GFP_KERNEL); - if (!mvi->bulk_buffer1) - goto err_out; - - sprintf(pool_name, "%s%d", "mvs_dma_pool", mvi->id); - mvi->dma_pool = pci_pool_create(pool_name, mvi->pdev, MVS_SLOT_BUF_SZ, 16, 0); - if (!mvi->dma_pool) { - printk(KERN_DEBUG "failed to create dma pool %s.\n", pool_name); - goto err_out; - } - mvi->tags_num = slot_nr; - - /* Initialize tags */ - mvs_tag_init(mvi); - return 0; -err_out: - return 1; -} - - -int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex) -{ - unsigned long res_start, res_len, res_flag, res_flag_ex = 0; - struct pci_dev *pdev = mvi->pdev; - if (bar_ex != -1) { - /* - * ioremap main and peripheral registers - */ - res_start = pci_resource_start(pdev, bar_ex); - res_len = pci_resource_len(pdev, bar_ex); - if (!res_start || !res_len) - goto err_out; - - res_flag_ex = pci_resource_flags(pdev, bar_ex); - if (res_flag_ex & IORESOURCE_MEM) { - if (res_flag_ex & IORESOURCE_CACHEABLE) - mvi->regs_ex = ioremap(res_start, res_len); - else - mvi->regs_ex = ioremap_nocache(res_start, - res_len); - } else - mvi->regs_ex = (void *)res_start; - if (!mvi->regs_ex) - goto err_out; - } - - res_start = pci_resource_start(pdev, bar); - res_len = pci_resource_len(pdev, bar); - if (!res_start || !res_len) - goto err_out; - - res_flag = pci_resource_flags(pdev, bar); - if (res_flag & IORESOURCE_CACHEABLE) - mvi->regs = ioremap(res_start, res_len); - else - mvi->regs = ioremap_nocache(res_start, res_len); - - if (!mvi->regs) { - if (mvi->regs_ex && (res_flag_ex & IORESOURCE_MEM)) - iounmap(mvi->regs_ex); - mvi->regs_ex = NULL; - goto err_out; - } - - return 0; -err_out: - return -1; -} - -void mvs_iounmap(void __iomem *regs) -{ - iounmap(regs); -} - -static struct mvs_info *__devinit mvs_pci_alloc(struct pci_dev *pdev, - const struct pci_device_id *ent, - struct Scsi_Host *shost, unsigned int id) -{ - struct mvs_info *mvi = NULL; - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - - mvi = kzalloc(sizeof(*mvi) + - (1L << mvs_chips[ent->driver_data].slot_width) * - sizeof(struct mvs_slot_info), GFP_KERNEL); - if (!mvi) - return NULL; - - mvi->pdev = pdev; - mvi->dev = &pdev->dev; - mvi->chip_id = ent->driver_data; - mvi->chip = &mvs_chips[mvi->chip_id]; - INIT_LIST_HEAD(&mvi->wq_list); - - ((struct mvs_prv_info *)sha->lldd_ha)->mvi[id] = mvi; - ((struct mvs_prv_info *)sha->lldd_ha)->n_phy = mvi->chip->n_phy; - - mvi->id = id; - mvi->sas = sha; - mvi->shost = shost; - - mvi->tags = kzalloc(MVS_CHIP_SLOT_SZ>>3, GFP_KERNEL); - if (!mvi->tags) - goto err_out; - - if (MVS_CHIP_DISP->chip_ioremap(mvi)) - goto err_out; - if (!mvs_alloc(mvi, shost)) - return mvi; -err_out: - mvs_free(mvi); - return NULL; -} - -static int pci_go_64(struct pci_dev *pdev) -{ - int rc; - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "64-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit DMA enable failed\n"); - return rc; - } - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - - return rc; -} - -static int __devinit mvs_prep_sas_ha_init(struct Scsi_Host *shost, - const struct mvs_chip_info *chip_info) -{ - int phy_nr, port_nr; unsigned short core_nr; - struct asd_sas_phy **arr_phy; - struct asd_sas_port **arr_port; - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - - core_nr = chip_info->n_host; - phy_nr = core_nr * chip_info->n_phy; - port_nr = phy_nr; - - memset(sha, 0x00, sizeof(struct sas_ha_struct)); - arr_phy = kcalloc(phy_nr, sizeof(void *), GFP_KERNEL); - arr_port = kcalloc(port_nr, sizeof(void *), GFP_KERNEL); - if (!arr_phy || !arr_port) - goto exit_free; - - sha->sas_phy = arr_phy; - sha->sas_port = arr_port; - sha->core.shost = shost; - - sha->lldd_ha = kzalloc(sizeof(struct mvs_prv_info), GFP_KERNEL); - if (!sha->lldd_ha) - goto exit_free; - - ((struct mvs_prv_info *)sha->lldd_ha)->n_host = core_nr; - - shost->transportt = mvs_stt; - shost->max_id = MVS_MAX_DEVICES; - shost->max_lun = ~0; - shost->max_channel = 1; - shost->max_cmd_len = 16; - - return 0; -exit_free: - kfree(arr_phy); - kfree(arr_port); - return -1; - -} - -static void __devinit mvs_post_sas_ha_init(struct Scsi_Host *shost, - const struct mvs_chip_info *chip_info) -{ - int can_queue, i = 0, j = 0; - struct mvs_info *mvi = NULL; - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - unsigned short nr_core = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; - - for (j = 0; j < nr_core; j++) { - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j]; - for (i = 0; i < chip_info->n_phy; i++) { - sha->sas_phy[j * chip_info->n_phy + i] = - &mvi->phy[i].sas_phy; - sha->sas_port[j * chip_info->n_phy + i] = - &mvi->port[i].sas_port; - } - } - - sha->sas_ha_name = DRV_NAME; - sha->dev = mvi->dev; - sha->lldd_module = THIS_MODULE; - sha->sas_addr = &mvi->sas_addr[0]; - - sha->num_phys = nr_core * chip_info->n_phy; - - sha->lldd_max_execute_num = lldd_max_execute_num; - - if (mvi->flags & MVF_FLAG_SOC) - can_queue = MVS_SOC_CAN_QUEUE; - else - can_queue = MVS_CHIP_SLOT_SZ; - - sha->lldd_queue_size = can_queue; - shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG); - shost->can_queue = can_queue; - mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE; - sha->core.shost = mvi->shost; -} - -static void mvs_init_sas_add(struct mvs_info *mvi) -{ - u8 i; - for (i = 0; i < mvi->chip->n_phy; i++) { - mvi->phy[i].dev_sas_addr = 0x5005043011ab0000ULL; - mvi->phy[i].dev_sas_addr = - cpu_to_be64((u64)(*(u64 *)&mvi->phy[i].dev_sas_addr)); - } - - memcpy(mvi->sas_addr, &mvi->phy[0].dev_sas_addr, SAS_ADDR_SIZE); -} - -static int __devinit mvs_pci_init(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - unsigned int rc, nhost = 0; - struct mvs_info *mvi; - struct mvs_prv_info *mpi; - irq_handler_t irq_handler = mvs_interrupt; - struct Scsi_Host *shost = NULL; - const struct mvs_chip_info *chip; - - dev_printk(KERN_INFO, &pdev->dev, - "mvsas: driver version %s\n", DRV_VERSION); - rc = pci_enable_device(pdev); - if (rc) - goto err_out_enable; - - pci_set_master(pdev); - - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_out_disable; - - rc = pci_go_64(pdev); - if (rc) - goto err_out_regions; - - shost = scsi_host_alloc(&mvs_sht, sizeof(void *)); - if (!shost) { - rc = -ENOMEM; - goto err_out_regions; - } - - chip = &mvs_chips[ent->driver_data]; - SHOST_TO_SAS_HA(shost) = - kcalloc(1, sizeof(struct sas_ha_struct), GFP_KERNEL); - if (!SHOST_TO_SAS_HA(shost)) { - kfree(shost); - rc = -ENOMEM; - goto err_out_regions; - } - - rc = mvs_prep_sas_ha_init(shost, chip); - if (rc) { - kfree(shost); - rc = -ENOMEM; - goto err_out_regions; - } - - pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost)); - - do { - mvi = mvs_pci_alloc(pdev, ent, shost, nhost); - if (!mvi) { - rc = -ENOMEM; - goto err_out_regions; - } - - memset(&mvi->hba_info_param, 0xFF, - sizeof(struct hba_info_page)); - - mvs_init_sas_add(mvi); - - mvi->instance = nhost; - rc = MVS_CHIP_DISP->chip_init(mvi); - if (rc) { - mvs_free(mvi); - goto err_out_regions; - } - nhost++; - } while (nhost < chip->n_host); - mpi = (struct mvs_prv_info *)(SHOST_TO_SAS_HA(shost)->lldd_ha); -#ifdef CONFIG_SCSI_MVSAS_TASKLET - tasklet_init(&(mpi->mv_tasklet), mvs_tasklet, - (unsigned long)SHOST_TO_SAS_HA(shost)); -#endif - - mvs_post_sas_ha_init(shost, chip); - - rc = scsi_add_host(shost, &pdev->dev); - if (rc) - goto err_out_shost; - - rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); - if (rc) - goto err_out_shost; - rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, - DRV_NAME, SHOST_TO_SAS_HA(shost)); - if (rc) - goto err_not_sas; - - MVS_CHIP_DISP->interrupt_enable(mvi); - - scsi_scan_host(mvi->shost); - - return 0; - -err_not_sas: - sas_unregister_ha(SHOST_TO_SAS_HA(shost)); -err_out_shost: - scsi_remove_host(mvi->shost); -err_out_regions: - pci_release_regions(pdev); -err_out_disable: - pci_disable_device(pdev); -err_out_enable: - return rc; -} - -static void __devexit mvs_pci_remove(struct pci_dev *pdev) -{ - unsigned short core_nr, i = 0; - struct sas_ha_struct *sha = pci_get_drvdata(pdev); - struct mvs_info *mvi = NULL; - - core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; - -#ifdef CONFIG_SCSI_MVSAS_TASKLET - tasklet_kill(&((struct mvs_prv_info *)sha->lldd_ha)->mv_tasklet); -#endif - - pci_set_drvdata(pdev, NULL); - sas_unregister_ha(sha); - sas_remove_host(mvi->shost); - scsi_remove_host(mvi->shost); - - MVS_CHIP_DISP->interrupt_disable(mvi); - free_irq(mvi->pdev->irq, sha); - for (i = 0; i < core_nr; i++) { - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; - mvs_free(mvi); - } - kfree(sha->sas_phy); - kfree(sha->sas_port); - kfree(sha); - pci_release_regions(pdev); - pci_disable_device(pdev); - return; -} - -static struct pci_device_id __devinitdata mvs_pci_table[] = { - { PCI_VDEVICE(MARVELL, 0x6320), chip_6320 }, - { PCI_VDEVICE(MARVELL, 0x6340), chip_6440 }, - { - .vendor = PCI_VENDOR_ID_MARVELL, - .device = 0x6440, - .subvendor = PCI_ANY_ID, - .subdevice = 0x6480, - .class = 0, - .class_mask = 0, - .driver_data = chip_6485, - }, - { PCI_VDEVICE(MARVELL, 0x6440), chip_6440 }, - { PCI_VDEVICE(MARVELL, 0x6485), chip_6485 }, - { PCI_VDEVICE(MARVELL, 0x9480), chip_9480 }, - { PCI_VDEVICE(MARVELL, 0x9180), chip_9180 }, - { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1300), chip_1300 }, - { PCI_VDEVICE(ARECA, PCI_DEVICE_ID_ARECA_1320), chip_1320 }, - { PCI_VDEVICE(ADAPTEC2, 0x0450), chip_6440 }, - { PCI_VDEVICE(TTI, 0x2710), chip_9480 }, - { PCI_VDEVICE(TTI, 0x2720), chip_9480 }, - { PCI_VDEVICE(TTI, 0x2721), chip_9480 }, - { PCI_VDEVICE(TTI, 0x2722), chip_9480 }, - { PCI_VDEVICE(TTI, 0x2740), chip_9480 }, - { PCI_VDEVICE(TTI, 0x2744), chip_9480 }, - { PCI_VDEVICE(TTI, 0x2760), chip_9480 }, - { - .vendor = 0x1b4b, - .device = 0x9480, - .subvendor = PCI_ANY_ID, - .subdevice = 0x9480, - .class = 0, - .class_mask = 0, - .driver_data = chip_9480, - }, - { - .vendor = 0x1b4b, - .device = 0x9445, - .subvendor = PCI_ANY_ID, - .subdevice = 0x9480, - .class = 0, - .class_mask = 0, - .driver_data = chip_9445, - }, - { - .vendor = 0x1b4b, - .device = 0x9485, - .subvendor = PCI_ANY_ID, - .subdevice = 0x9480, - .class = 0, - .class_mask = 0, - .driver_data = chip_9485, - }, - { PCI_VDEVICE(OCZ, 0x1021), chip_9485}, /* OCZ RevoDrive3 */ - { PCI_VDEVICE(OCZ, 0x1022), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - { PCI_VDEVICE(OCZ, 0x1040), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - { PCI_VDEVICE(OCZ, 0x1041), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - { PCI_VDEVICE(OCZ, 0x1042), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - { PCI_VDEVICE(OCZ, 0x1043), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - { PCI_VDEVICE(OCZ, 0x1044), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - { PCI_VDEVICE(OCZ, 0x1080), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - { PCI_VDEVICE(OCZ, 0x1083), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - { PCI_VDEVICE(OCZ, 0x1084), chip_9485}, /* OCZ RevoDrive3/zDriveR4 (exact model unknown) */ - - { } /* terminate list */ -}; - -static struct pci_driver mvs_pci_driver = { - .name = DRV_NAME, - .id_table = mvs_pci_table, - .probe = mvs_pci_init, - .remove = __devexit_p(mvs_pci_remove), -}; - -static ssize_t -mvs_show_driver_version(struct device *cdev, - struct device_attribute *attr, char *buffer) -{ - return snprintf(buffer, PAGE_SIZE, "%s\n", DRV_VERSION); -} - -static DEVICE_ATTR(driver_version, - S_IRUGO, - mvs_show_driver_version, - NULL); - -static ssize_t -mvs_store_interrupt_coalescing(struct device *cdev, - struct device_attribute *attr, - const char *buffer, size_t size) -{ - int val = 0; - struct mvs_info *mvi = NULL; - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - u8 i, core_nr; - if (buffer == NULL) - return size; - - if (sscanf(buffer, "%d", &val) != 1) - return -EINVAL; - - if (val >= 0x10000) { - mv_dprintk("interrupt coalescing timer %d us is" - "too long\n", val); - return strlen(buffer); - } - - interrupt_coalescing = val; - - core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[0]; - - if (unlikely(!mvi)) - return -EINVAL; - - for (i = 0; i < core_nr; i++) { - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[i]; - if (MVS_CHIP_DISP->tune_interrupt) - MVS_CHIP_DISP->tune_interrupt(mvi, - interrupt_coalescing); - } - mv_dprintk("set interrupt coalescing time to %d us\n", - interrupt_coalescing); - return strlen(buffer); -} - -static ssize_t mvs_show_interrupt_coalescing(struct device *cdev, - struct device_attribute *attr, char *buffer) -{ - return snprintf(buffer, PAGE_SIZE, "%d\n", interrupt_coalescing); -} - -static DEVICE_ATTR(interrupt_coalescing, - S_IRUGO|S_IWUSR, - mvs_show_interrupt_coalescing, - mvs_store_interrupt_coalescing); - -/* task handler */ -struct task_struct *mvs_th; -static int __init mvs_init(void) -{ - int rc; - mvs_stt = sas_domain_attach_transport(&mvs_transport_ops); - if (!mvs_stt) - return -ENOMEM; - - mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list), - 0, SLAB_HWCACHE_ALIGN, NULL); - if (!mvs_task_list_cache) { - rc = -ENOMEM; - mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__); - goto err_out; - } - - rc = pci_register_driver(&mvs_pci_driver); - - if (rc) - goto err_out; - - return 0; - -err_out: - sas_release_transport(mvs_stt); - return rc; -} - -static void __exit mvs_exit(void) -{ - pci_unregister_driver(&mvs_pci_driver); - sas_release_transport(mvs_stt); - kmem_cache_destroy(mvs_task_list_cache); -} - -struct device_attribute *mvst_host_attrs[] = { - &dev_attr_driver_version, - &dev_attr_interrupt_coalescing, - NULL, -}; - -module_init(mvs_init); -module_exit(mvs_exit); - -MODULE_AUTHOR("Jeff Garzik "); -MODULE_DESCRIPTION("Marvell 88SE6440 SAS/SATA controller driver"); -MODULE_VERSION(DRV_VERSION); -MODULE_LICENSE("GPL"); -#ifdef CONFIG_PCI -MODULE_DEVICE_TABLE(pci, mvs_pci_table); -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.c b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.c deleted file mode 100644 index fd3b2839..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.c +++ /dev/null @@ -1,2194 +0,0 @@ -/* - * Marvell 88SE64xx/88SE94xx main function - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - -#include "mv_sas.h" - -static int mvs_find_tag(struct mvs_info *mvi, struct sas_task *task, u32 *tag) -{ - if (task->lldd_task) { - struct mvs_slot_info *slot; - slot = task->lldd_task; - *tag = slot->slot_tag; - return 1; - } - return 0; -} - -void mvs_tag_clear(struct mvs_info *mvi, u32 tag) -{ - void *bitmap = mvi->tags; - clear_bit(tag, bitmap); -} - -void mvs_tag_free(struct mvs_info *mvi, u32 tag) -{ - mvs_tag_clear(mvi, tag); -} - -void mvs_tag_set(struct mvs_info *mvi, unsigned int tag) -{ - void *bitmap = mvi->tags; - set_bit(tag, bitmap); -} - -inline int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out) -{ - unsigned int index, tag; - void *bitmap = mvi->tags; - - index = find_first_zero_bit(bitmap, mvi->tags_num); - tag = index; - if (tag >= mvi->tags_num) - return -SAS_QUEUE_FULL; - mvs_tag_set(mvi, tag); - *tag_out = tag; - return 0; -} - -void mvs_tag_init(struct mvs_info *mvi) -{ - int i; - for (i = 0; i < mvi->tags_num; ++i) - mvs_tag_clear(mvi, i); -} - -struct mvs_info *mvs_find_dev_mvi(struct domain_device *dev) -{ - unsigned long i = 0, j = 0, hi = 0; - struct sas_ha_struct *sha = dev->port->ha; - struct mvs_info *mvi = NULL; - struct asd_sas_phy *phy; - - while (sha->sas_port[i]) { - if (sha->sas_port[i] == dev->port) { - phy = container_of(sha->sas_port[i]->phy_list.next, - struct asd_sas_phy, port_phy_el); - j = 0; - while (sha->sas_phy[j]) { - if (sha->sas_phy[j] == phy) - break; - j++; - } - break; - } - i++; - } - hi = j/((struct mvs_prv_info *)sha->lldd_ha)->n_phy; - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi]; - - return mvi; - -} - -int mvs_find_dev_phyno(struct domain_device *dev, int *phyno) -{ - unsigned long i = 0, j = 0, n = 0, num = 0; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; - struct mvs_info *mvi = mvi_dev->mvi_info; - struct sas_ha_struct *sha = dev->port->ha; - - while (sha->sas_port[i]) { - if (sha->sas_port[i] == dev->port) { - struct asd_sas_phy *phy; - list_for_each_entry(phy, - &sha->sas_port[i]->phy_list, port_phy_el) { - j = 0; - while (sha->sas_phy[j]) { - if (sha->sas_phy[j] == phy) - break; - j++; - } - phyno[n] = (j >= mvi->chip->n_phy) ? - (j - mvi->chip->n_phy) : j; - num++; - n++; - } - break; - } - i++; - } - return num; -} - -struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, - u8 reg_set) -{ - u32 dev_no; - for (dev_no = 0; dev_no < MVS_MAX_DEVICES; dev_no++) { - if (mvi->devices[dev_no].taskfileset == MVS_ID_NOT_MAPPED) - continue; - - if (mvi->devices[dev_no].taskfileset == reg_set) - return &mvi->devices[dev_no]; - } - return NULL; -} - -static inline void mvs_free_reg_set(struct mvs_info *mvi, - struct mvs_device *dev) -{ - if (!dev) { - mv_printk("device has been free.\n"); - return; - } - if (dev->taskfileset == MVS_ID_NOT_MAPPED) - return; - MVS_CHIP_DISP->free_reg_set(mvi, &dev->taskfileset); -} - -static inline u8 mvs_assign_reg_set(struct mvs_info *mvi, - struct mvs_device *dev) -{ - if (dev->taskfileset != MVS_ID_NOT_MAPPED) - return 0; - return MVS_CHIP_DISP->assign_reg_set(mvi, &dev->taskfileset); -} - -void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard) -{ - u32 no; - for_each_phy(phy_mask, phy_mask, no) { - if (!(phy_mask & 1)) - continue; - MVS_CHIP_DISP->phy_reset(mvi, no, hard); - } -} - -int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, - void *funcdata) -{ - int rc = 0, phy_id = sas_phy->id; - u32 tmp, i = 0, hi; - struct sas_ha_struct *sha = sas_phy->ha; - struct mvs_info *mvi = NULL; - - while (sha->sas_phy[i]) { - if (sha->sas_phy[i] == sas_phy) - break; - i++; - } - hi = i/((struct mvs_prv_info *)sha->lldd_ha)->n_phy; - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[hi]; - - switch (func) { - case PHY_FUNC_SET_LINK_RATE: - MVS_CHIP_DISP->phy_set_link_rate(mvi, phy_id, funcdata); - break; - - case PHY_FUNC_HARD_RESET: - tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_id); - if (tmp & PHY_RST_HARD) - break; - MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_HARD_RESET); - break; - - case PHY_FUNC_LINK_RESET: - MVS_CHIP_DISP->phy_enable(mvi, phy_id); - MVS_CHIP_DISP->phy_reset(mvi, phy_id, MVS_SOFT_RESET); - break; - - case PHY_FUNC_DISABLE: - MVS_CHIP_DISP->phy_disable(mvi, phy_id); - break; - case PHY_FUNC_RELEASE_SPINUP_HOLD: - default: - rc = -ENOSYS; - } - msleep(200); - return rc; -} - -void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id, - u32 off_lo, u32 off_hi, u64 sas_addr) -{ - u32 lo = (u32)sas_addr; - u32 hi = (u32)(sas_addr>>32); - - MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_lo); - MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, lo); - MVS_CHIP_DISP->write_port_cfg_addr(mvi, port_id, off_hi); - MVS_CHIP_DISP->write_port_cfg_data(mvi, port_id, hi); -} - -static void mvs_bytes_dmaed(struct mvs_info *mvi, int i) -{ - struct mvs_phy *phy = &mvi->phy[i]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - struct sas_ha_struct *sas_ha; - if (!phy->phy_attached) - return; - - if (!(phy->att_dev_info & PORT_DEV_TRGT_MASK) - && phy->phy_type & PORT_TYPE_SAS) { - return; - } - - sas_ha = mvi->sas; - sas_ha->notify_phy_event(sas_phy, PHYE_OOB_DONE); - - if (sas_phy->phy) { - struct sas_phy *sphy = sas_phy->phy; - - sphy->negotiated_linkrate = sas_phy->linkrate; - sphy->minimum_linkrate = phy->minimum_linkrate; - sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; - sphy->maximum_linkrate = phy->maximum_linkrate; - sphy->maximum_linkrate_hw = MVS_CHIP_DISP->phy_max_link_rate(); - } - - if (phy->phy_type & PORT_TYPE_SAS) { - struct sas_identify_frame *id; - - id = (struct sas_identify_frame *)phy->frame_rcvd; - id->dev_type = phy->identify.device_type; - id->initiator_bits = SAS_PROTOCOL_ALL; - id->target_bits = phy->identify.target_port_protocols; - - /* direct attached SAS device */ - if (phy->att_dev_info & PORT_SSP_TRGT_MASK) { - MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); - MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x00); - } - } else if (phy->phy_type & PORT_TYPE_SATA) { - /*Nothing*/ - } - mv_dprintk("phy %d byte dmaded.\n", i + mvi->id * mvi->chip->n_phy); - - sas_phy->frame_rcvd_size = phy->frame_rcvd_size; - - mvi->sas->notify_port_event(sas_phy, - PORTE_BYTES_DMAED); -} - -void mvs_scan_start(struct Scsi_Host *shost) -{ - int i, j; - unsigned short core_nr; - struct mvs_info *mvi; - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct mvs_prv_info *mvs_prv = sha->lldd_ha; - - core_nr = ((struct mvs_prv_info *)sha->lldd_ha)->n_host; - - for (j = 0; j < core_nr; j++) { - mvi = ((struct mvs_prv_info *)sha->lldd_ha)->mvi[j]; - for (i = 0; i < mvi->chip->n_phy; ++i) - mvs_bytes_dmaed(mvi, i); - } - mvs_prv->scan_finished = 1; -} - -int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct mvs_prv_info *mvs_prv = sha->lldd_ha; - - if (mvs_prv->scan_finished == 0) - return 0; - - sas_drain_work(sha); - return 1; -} - -static int mvs_task_prep_smp(struct mvs_info *mvi, - struct mvs_task_exec_info *tei) -{ - int elem, rc, i; - struct sas_task *task = tei->task; - struct mvs_cmd_hdr *hdr = tei->hdr; - struct domain_device *dev = task->dev; - struct asd_sas_port *sas_port = dev->port; - struct scatterlist *sg_req, *sg_resp; - u32 req_len, resp_len, tag = tei->tag; - void *buf_tmp; - u8 *buf_oaf; - dma_addr_t buf_tmp_dma; - void *buf_prd; - struct mvs_slot_info *slot = &mvi->slot_info[tag]; - u32 flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); - - /* - * DMA-map SMP request, response buffers - */ - sg_req = &task->smp_task.smp_req; - elem = dma_map_sg(mvi->dev, sg_req, 1, PCI_DMA_TODEVICE); - if (!elem) - return -ENOMEM; - req_len = sg_dma_len(sg_req); - - sg_resp = &task->smp_task.smp_resp; - elem = dma_map_sg(mvi->dev, sg_resp, 1, PCI_DMA_FROMDEVICE); - if (!elem) { - rc = -ENOMEM; - goto err_out; - } - resp_len = SB_RFB_MAX; - - /* must be in dwords */ - if ((req_len & 0x3) || (resp_len & 0x3)) { - rc = -EINVAL; - goto err_out_2; - } - - /* - * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs - */ - - /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ***** */ - buf_tmp = slot->buf; - buf_tmp_dma = slot->buf_dma; - - hdr->cmd_tbl = cpu_to_le64(sg_dma_address(sg_req)); - - /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ - buf_oaf = buf_tmp; - hdr->open_frame = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_OAF_SZ; - buf_tmp_dma += MVS_OAF_SZ; - - /* region 3: PRD table *********************************** */ - buf_prd = buf_tmp; - if (tei->n_elem) - hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); - else - hdr->prd_tbl = 0; - - i = MVS_CHIP_DISP->prd_size() * tei->n_elem; - buf_tmp += i; - buf_tmp_dma += i; - - /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ - slot->response = buf_tmp; - hdr->status_buf = cpu_to_le64(buf_tmp_dma); - if (mvi->flags & MVF_FLAG_SOC) - hdr->reserved[0] = 0; - - /* - * Fill in TX ring and command slot header - */ - slot->tx = mvi->tx_prod; - mvi->tx[mvi->tx_prod] = cpu_to_le32((TXQ_CMD_SMP << TXQ_CMD_SHIFT) | - TXQ_MODE_I | tag | - (sas_port->phy_mask << TXQ_PHY_SHIFT)); - - hdr->flags |= flags; - hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | ((req_len - 4) / 4)); - hdr->tags = cpu_to_le32(tag); - hdr->data_len = 0; - - /* generate open address frame hdr (first 12 bytes) */ - /* initiator, SMP, ftype 1h */ - buf_oaf[0] = (1 << 7) | (PROTOCOL_SMP << 4) | 0x01; - buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; - *(u16 *)(buf_oaf + 2) = 0xFFFF; /* SAS SPEC */ - memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); - - /* fill in PRD (scatter/gather) table, if any */ - MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); - - return 0; - -err_out_2: - dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); -err_out: - dma_unmap_sg(mvi->dev, &tei->task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - return rc; -} - -static u32 mvs_get_ncq_tag(struct sas_task *task, u32 *tag) -{ - struct ata_queued_cmd *qc = task->uldd_task; - - if (qc) { - if (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ) { - *tag = qc->tag; - return 1; - } - } - - return 0; -} - -static int mvs_task_prep_ata(struct mvs_info *mvi, - struct mvs_task_exec_info *tei) -{ - struct sas_task *task = tei->task; - struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = dev->lldd_dev; - struct mvs_cmd_hdr *hdr = tei->hdr; - struct asd_sas_port *sas_port = dev->port; - struct mvs_slot_info *slot; - void *buf_prd; - u32 tag = tei->tag, hdr_tag; - u32 flags, del_q; - void *buf_tmp; - u8 *buf_cmd, *buf_oaf; - dma_addr_t buf_tmp_dma; - u32 i, req_len, resp_len; - const u32 max_resp_len = SB_RFB_MAX; - - if (mvs_assign_reg_set(mvi, mvi_dev) == MVS_ID_NOT_MAPPED) { - mv_dprintk("Have not enough regiset for dev %d.\n", - mvi_dev->device_id); - return -EBUSY; - } - slot = &mvi->slot_info[tag]; - slot->tx = mvi->tx_prod; - del_q = TXQ_MODE_I | tag | - (TXQ_CMD_STP << TXQ_CMD_SHIFT) | - (sas_port->phy_mask << TXQ_PHY_SHIFT) | - (mvi_dev->taskfileset << TXQ_SRS_SHIFT); - mvi->tx[mvi->tx_prod] = cpu_to_le32(del_q); - - if (task->data_dir == DMA_FROM_DEVICE) - flags = (MVS_CHIP_DISP->prd_count() << MCH_PRD_LEN_SHIFT); - else - flags = (tei->n_elem << MCH_PRD_LEN_SHIFT); - - if (task->ata_task.use_ncq) - flags |= MCH_FPDMA; - if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) { - if (task->ata_task.fis.command != ATA_CMD_ID_ATAPI) - flags |= MCH_ATAPI; - } - - hdr->flags = cpu_to_le32(flags); - - if (task->ata_task.use_ncq && mvs_get_ncq_tag(task, &hdr_tag)) - task->ata_task.fis.sector_count |= (u8) (hdr_tag << 3); - else - hdr_tag = tag; - - hdr->tags = cpu_to_le32(hdr_tag); - - hdr->data_len = cpu_to_le32(task->total_xfer_len); - - /* - * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs - */ - - /* region 1: command table area (MVS_ATA_CMD_SZ bytes) ************** */ - buf_cmd = buf_tmp = slot->buf; - buf_tmp_dma = slot->buf_dma; - - hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_ATA_CMD_SZ; - buf_tmp_dma += MVS_ATA_CMD_SZ; - - /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ - /* used for STP. unused for SATA? */ - buf_oaf = buf_tmp; - hdr->open_frame = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_OAF_SZ; - buf_tmp_dma += MVS_OAF_SZ; - - /* region 3: PRD table ********************************************* */ - buf_prd = buf_tmp; - - if (tei->n_elem) - hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); - else - hdr->prd_tbl = 0; - i = MVS_CHIP_DISP->prd_size() * MVS_CHIP_DISP->prd_count(); - - buf_tmp += i; - buf_tmp_dma += i; - - /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ - slot->response = buf_tmp; - hdr->status_buf = cpu_to_le64(buf_tmp_dma); - if (mvi->flags & MVF_FLAG_SOC) - hdr->reserved[0] = 0; - - req_len = sizeof(struct host_to_dev_fis); - resp_len = MVS_SLOT_BUF_SZ - MVS_ATA_CMD_SZ - - sizeof(struct mvs_err_info) - i; - - /* request, response lengths */ - resp_len = min(resp_len, max_resp_len); - hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); - - if (likely(!task->ata_task.device_control_reg_update)) - task->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ - /* fill in command FIS and ATAPI CDB */ - memcpy(buf_cmd, &task->ata_task.fis, sizeof(struct host_to_dev_fis)); - if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) - memcpy(buf_cmd + STP_ATAPI_CMD, - task->ata_task.atapi_packet, 16); - - /* generate open address frame hdr (first 12 bytes) */ - /* initiator, STP, ftype 1h */ - buf_oaf[0] = (1 << 7) | (PROTOCOL_STP << 4) | 0x1; - buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; - *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1); - memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); - - /* fill in PRD (scatter/gather) table, if any */ - MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); - - if (task->data_dir == DMA_FROM_DEVICE) - MVS_CHIP_DISP->dma_fix(mvi, sas_port->phy_mask, - TRASH_BUCKET_SIZE, tei->n_elem, buf_prd); - - return 0; -} - -static int mvs_task_prep_ssp(struct mvs_info *mvi, - struct mvs_task_exec_info *tei, int is_tmf, - struct mvs_tmf_task *tmf) -{ - struct sas_task *task = tei->task; - struct mvs_cmd_hdr *hdr = tei->hdr; - struct mvs_port *port = tei->port; - struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = dev->lldd_dev; - struct asd_sas_port *sas_port = dev->port; - struct mvs_slot_info *slot; - void *buf_prd; - struct ssp_frame_hdr *ssp_hdr; - void *buf_tmp; - u8 *buf_cmd, *buf_oaf, fburst = 0; - dma_addr_t buf_tmp_dma; - u32 flags; - u32 resp_len, req_len, i, tag = tei->tag; - const u32 max_resp_len = SB_RFB_MAX; - u32 phy_mask; - - slot = &mvi->slot_info[tag]; - - phy_mask = ((port->wide_port_phymap) ? port->wide_port_phymap : - sas_port->phy_mask) & TXQ_PHY_MASK; - - slot->tx = mvi->tx_prod; - mvi->tx[mvi->tx_prod] = cpu_to_le32(TXQ_MODE_I | tag | - (TXQ_CMD_SSP << TXQ_CMD_SHIFT) | - (phy_mask << TXQ_PHY_SHIFT)); - - flags = MCH_RETRY; - if (task->ssp_task.enable_first_burst) { - flags |= MCH_FBURST; - fburst = (1 << 7); - } - if (is_tmf) - flags |= (MCH_SSP_FR_TASK << MCH_SSP_FR_TYPE_SHIFT); - else - flags |= (MCH_SSP_FR_CMD << MCH_SSP_FR_TYPE_SHIFT); - - hdr->flags = cpu_to_le32(flags | (tei->n_elem << MCH_PRD_LEN_SHIFT)); - hdr->tags = cpu_to_le32(tag); - hdr->data_len = cpu_to_le32(task->total_xfer_len); - - /* - * arrange MVS_SLOT_BUF_SZ-sized DMA buffer according to our needs - */ - - /* region 1: command table area (MVS_SSP_CMD_SZ bytes) ************** */ - buf_cmd = buf_tmp = slot->buf; - buf_tmp_dma = slot->buf_dma; - - hdr->cmd_tbl = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_SSP_CMD_SZ; - buf_tmp_dma += MVS_SSP_CMD_SZ; - - /* region 2: open address frame area (MVS_OAF_SZ bytes) ********* */ - buf_oaf = buf_tmp; - hdr->open_frame = cpu_to_le64(buf_tmp_dma); - - buf_tmp += MVS_OAF_SZ; - buf_tmp_dma += MVS_OAF_SZ; - - /* region 3: PRD table ********************************************* */ - buf_prd = buf_tmp; - if (tei->n_elem) - hdr->prd_tbl = cpu_to_le64(buf_tmp_dma); - else - hdr->prd_tbl = 0; - - i = MVS_CHIP_DISP->prd_size() * tei->n_elem; - buf_tmp += i; - buf_tmp_dma += i; - - /* region 4: status buffer (larger the PRD, smaller this buf) ****** */ - slot->response = buf_tmp; - hdr->status_buf = cpu_to_le64(buf_tmp_dma); - if (mvi->flags & MVF_FLAG_SOC) - hdr->reserved[0] = 0; - - resp_len = MVS_SLOT_BUF_SZ - MVS_SSP_CMD_SZ - MVS_OAF_SZ - - sizeof(struct mvs_err_info) - i; - resp_len = min(resp_len, max_resp_len); - - req_len = sizeof(struct ssp_frame_hdr) + 28; - - /* request, response lengths */ - hdr->lens = cpu_to_le32(((resp_len / 4) << 16) | (req_len / 4)); - - /* generate open address frame hdr (first 12 bytes) */ - /* initiator, SSP, ftype 1h */ - buf_oaf[0] = (1 << 7) | (PROTOCOL_SSP << 4) | 0x1; - buf_oaf[1] = min(sas_port->linkrate, dev->linkrate) & 0xf; - *(u16 *)(buf_oaf + 2) = cpu_to_be16(mvi_dev->device_id + 1); - memcpy(buf_oaf + 4, dev->sas_addr, SAS_ADDR_SIZE); - - /* fill in SSP frame header (Command Table.SSP frame header) */ - ssp_hdr = (struct ssp_frame_hdr *)buf_cmd; - - if (is_tmf) - ssp_hdr->frame_type = SSP_TASK; - else - ssp_hdr->frame_type = SSP_COMMAND; - - memcpy(ssp_hdr->hashed_dest_addr, dev->hashed_sas_addr, - HASHED_SAS_ADDR_SIZE); - memcpy(ssp_hdr->hashed_src_addr, - dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); - ssp_hdr->tag = cpu_to_be16(tag); - - /* fill in IU for TASK and Command Frame */ - buf_cmd += sizeof(*ssp_hdr); - memcpy(buf_cmd, &task->ssp_task.LUN, 8); - - if (ssp_hdr->frame_type != SSP_TASK) { - buf_cmd[9] = fburst | task->ssp_task.task_attr | - (task->ssp_task.task_prio << 3); - memcpy(buf_cmd + 12, &task->ssp_task.cdb, 16); - } else{ - buf_cmd[10] = tmf->tmf; - switch (tmf->tmf) { - case TMF_ABORT_TASK: - case TMF_QUERY_TASK: - buf_cmd[12] = - (tmf->tag_of_task_to_be_managed >> 8) & 0xff; - buf_cmd[13] = - tmf->tag_of_task_to_be_managed & 0xff; - break; - default: - break; - } - } - /* fill in PRD (scatter/gather) table, if any */ - MVS_CHIP_DISP->make_prd(task->scatter, tei->n_elem, buf_prd); - return 0; -} - -#define DEV_IS_GONE(mvi_dev) ((!mvi_dev || (mvi_dev->dev_type == NO_DEVICE))) -static int mvs_task_prep(struct sas_task *task, struct mvs_info *mvi, int is_tmf, - struct mvs_tmf_task *tmf, int *pass) -{ - struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = dev->lldd_dev; - struct mvs_task_exec_info tei; - struct mvs_slot_info *slot; - u32 tag = 0xdeadbeef, n_elem = 0; - int rc = 0; - - if (!dev->port) { - struct task_status_struct *tsm = &task->task_status; - - tsm->resp = SAS_TASK_UNDELIVERED; - tsm->stat = SAS_PHY_DOWN; - /* - * libsas will use dev->port, should - * not call task_done for sata - */ - if (dev->dev_type != SATA_DEV) - task->task_done(task); - return rc; - } - - if (DEV_IS_GONE(mvi_dev)) { - if (mvi_dev) - mv_dprintk("device %d not ready.\n", - mvi_dev->device_id); - else - mv_dprintk("device %016llx not ready.\n", - SAS_ADDR(dev->sas_addr)); - - rc = SAS_PHY_DOWN; - return rc; - } - tei.port = dev->port->lldd_port; - if (tei.port && !tei.port->port_attached && !tmf) { - if (sas_protocol_ata(task->task_proto)) { - struct task_status_struct *ts = &task->task_status; - mv_dprintk("SATA/STP port %d does not attach" - "device.\n", dev->port->id); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_PHY_DOWN; - - task->task_done(task); - - } else { - struct task_status_struct *ts = &task->task_status; - mv_dprintk("SAS port %d does not attach" - "device.\n", dev->port->id); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - task->task_done(task); - } - return rc; - } - - if (!sas_protocol_ata(task->task_proto)) { - if (task->num_scatter) { - n_elem = dma_map_sg(mvi->dev, - task->scatter, - task->num_scatter, - task->data_dir); - if (!n_elem) { - rc = -ENOMEM; - goto prep_out; - } - } - } else { - n_elem = task->num_scatter; - } - - rc = mvs_tag_alloc(mvi, &tag); - if (rc) - goto err_out; - - slot = &mvi->slot_info[tag]; - - task->lldd_task = NULL; - slot->n_elem = n_elem; - slot->slot_tag = tag; - - slot->buf = pci_pool_alloc(mvi->dma_pool, GFP_ATOMIC, &slot->buf_dma); - if (!slot->buf) - goto err_out_tag; - memset(slot->buf, 0, MVS_SLOT_BUF_SZ); - - tei.task = task; - tei.hdr = &mvi->slot[tag]; - tei.tag = tag; - tei.n_elem = n_elem; - switch (task->task_proto) { - case SAS_PROTOCOL_SMP: - rc = mvs_task_prep_smp(mvi, &tei); - break; - case SAS_PROTOCOL_SSP: - rc = mvs_task_prep_ssp(mvi, &tei, is_tmf, tmf); - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - rc = mvs_task_prep_ata(mvi, &tei); - break; - default: - dev_printk(KERN_ERR, mvi->dev, - "unknown sas_task proto: 0x%x\n", - task->task_proto); - rc = -EINVAL; - break; - } - - if (rc) { - mv_dprintk("rc is %x\n", rc); - goto err_out_slot_buf; - } - slot->task = task; - slot->port = tei.port; - task->lldd_task = slot; - list_add_tail(&slot->entry, &tei.port->list); - spin_lock(&task->task_state_lock); - task->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&task->task_state_lock); - - mvi_dev->running_req++; - ++(*pass); - mvi->tx_prod = (mvi->tx_prod + 1) & (MVS_CHIP_SLOT_SZ - 1); - - return rc; - -err_out_slot_buf: - pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); -err_out_tag: - mvs_tag_free(mvi, tag); -err_out: - - dev_printk(KERN_ERR, mvi->dev, "mvsas prep failed[%d]!\n", rc); - if (!sas_protocol_ata(task->task_proto)) - if (n_elem) - dma_unmap_sg(mvi->dev, task->scatter, n_elem, - task->data_dir); -prep_out: - return rc; -} - -static struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags) -{ - struct mvs_task_list *first = NULL; - - for (; *num > 0; --*num) { - struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags); - - if (!mvs_list) - break; - - INIT_LIST_HEAD(&mvs_list->list); - if (!first) - first = mvs_list; - else - list_add_tail(&mvs_list->list, &first->list); - - } - - return first; -} - -static inline void mvs_task_free_list(struct mvs_task_list *mvs_list) -{ - LIST_HEAD(list); - struct list_head *pos, *a; - struct mvs_task_list *mlist = NULL; - - __list_add(&list, mvs_list->list.prev, &mvs_list->list); - - list_for_each_safe(pos, a, &list) { - list_del_init(pos); - mlist = list_entry(pos, struct mvs_task_list, list); - kmem_cache_free(mvs_task_list_cache, mlist); - } -} - -static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, - struct completion *completion, int is_tmf, - struct mvs_tmf_task *tmf) -{ - struct domain_device *dev = task->dev; - struct mvs_info *mvi = NULL; - u32 rc = 0; - u32 pass = 0; - unsigned long flags = 0; - - mvi = ((struct mvs_device *)task->dev->lldd_dev)->mvi_info; - - spin_lock_irqsave(&mvi->lock, flags); - rc = mvs_task_prep(task, mvi, is_tmf, tmf, &pass); - if (rc) - dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); - - if (likely(pass)) - MVS_CHIP_DISP->start_delivery(mvi, (mvi->tx_prod - 1) & - (MVS_CHIP_SLOT_SZ - 1)); - spin_unlock_irqrestore(&mvi->lock, flags); - - return rc; -} - -static int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags, - struct completion *completion, int is_tmf, - struct mvs_tmf_task *tmf) -{ - struct domain_device *dev = task->dev; - struct mvs_prv_info *mpi = dev->port->ha->lldd_ha; - struct mvs_info *mvi = NULL; - struct sas_task *t = task; - struct mvs_task_list *mvs_list = NULL, *a; - LIST_HEAD(q); - int pass[2] = {0}; - u32 rc = 0; - u32 n = num; - unsigned long flags = 0; - - mvs_list = mvs_task_alloc_list(&n, gfp_flags); - if (n) { - printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__); - rc = -ENOMEM; - goto free_list; - } - - __list_add(&q, mvs_list->list.prev, &mvs_list->list); - - list_for_each_entry(a, &q, list) { - a->task = t; - t = list_entry(t->list.next, struct sas_task, list); - } - - list_for_each_entry(a, &q , list) { - - t = a->task; - mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info; - - spin_lock_irqsave(&mvi->lock, flags); - rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]); - if (rc) - dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc); - spin_unlock_irqrestore(&mvi->lock, flags); - } - - if (likely(pass[0])) - MVS_CHIP_DISP->start_delivery(mpi->mvi[0], - (mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); - - if (likely(pass[1])) - MVS_CHIP_DISP->start_delivery(mpi->mvi[1], - (mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1)); - - list_del_init(&q); - -free_list: - if (mvs_list) - mvs_task_free_list(mvs_list); - - return rc; -} - -int mvs_queue_command(struct sas_task *task, const int num, - gfp_t gfp_flags) -{ - struct mvs_device *mvi_dev = task->dev->lldd_dev; - struct sas_ha_struct *sas = mvi_dev->mvi_info->sas; - - if (sas->lldd_max_execute_num < 2) - return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL); - else - return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL); -} - -static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc) -{ - u32 slot_idx = rx_desc & RXQ_SLOT_MASK; - mvs_tag_clear(mvi, slot_idx); -} - -static void mvs_slot_task_free(struct mvs_info *mvi, struct sas_task *task, - struct mvs_slot_info *slot, u32 slot_idx) -{ - if (!slot->task) - return; - if (!sas_protocol_ata(task->task_proto)) - if (slot->n_elem) - dma_unmap_sg(mvi->dev, task->scatter, - slot->n_elem, task->data_dir); - - switch (task->task_proto) { - case SAS_PROTOCOL_SMP: - dma_unmap_sg(mvi->dev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); - dma_unmap_sg(mvi->dev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - break; - - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SSP: - default: - /* do nothing */ - break; - } - - if (slot->buf) { - pci_pool_free(mvi->dma_pool, slot->buf, slot->buf_dma); - slot->buf = NULL; - } - list_del_init(&slot->entry); - task->lldd_task = NULL; - slot->task = NULL; - slot->port = NULL; - slot->slot_tag = 0xFFFFFFFF; - mvs_slot_free(mvi, slot_idx); -} - -static void mvs_update_wideport(struct mvs_info *mvi, int phy_no) -{ - struct mvs_phy *phy = &mvi->phy[phy_no]; - struct mvs_port *port = phy->port; - int j, no; - - for_each_phy(port->wide_port_phymap, j, no) { - if (j & 1) { - MVS_CHIP_DISP->write_port_cfg_addr(mvi, no, - PHYR_WIDE_PORT); - MVS_CHIP_DISP->write_port_cfg_data(mvi, no, - port->wide_port_phymap); - } else { - MVS_CHIP_DISP->write_port_cfg_addr(mvi, no, - PHYR_WIDE_PORT); - MVS_CHIP_DISP->write_port_cfg_data(mvi, no, - 0); - } - } -} - -static u32 mvs_is_phy_ready(struct mvs_info *mvi, int i) -{ - u32 tmp; - struct mvs_phy *phy = &mvi->phy[i]; - struct mvs_port *port = phy->port; - - tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, i); - if ((tmp & PHY_READY_MASK) && !(phy->irq_status & PHYEV_POOF)) { - if (!port) - phy->phy_attached = 1; - return tmp; - } - - if (port) { - if (phy->phy_type & PORT_TYPE_SAS) { - port->wide_port_phymap &= ~(1U << i); - if (!port->wide_port_phymap) - port->port_attached = 0; - mvs_update_wideport(mvi, i); - } else if (phy->phy_type & PORT_TYPE_SATA) - port->port_attached = 0; - phy->port = NULL; - phy->phy_attached = 0; - phy->phy_type &= ~(PORT_TYPE_SAS | PORT_TYPE_SATA); - } - return 0; -} - -static void *mvs_get_d2h_reg(struct mvs_info *mvi, int i, void *buf) -{ - u32 *s = (u32 *) buf; - - if (!s) - return NULL; - - MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG3); - s[3] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); - - MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG2); - s[2] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); - - MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG1); - s[1] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); - - MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0); - s[0] = cpu_to_le32(MVS_CHIP_DISP->read_port_cfg_data(mvi, i)); - - if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01)) - s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10); - - return s; -} - -static u32 mvs_is_sig_fis_received(u32 irq_status) -{ - return irq_status & PHYEV_SIG_FIS; -} - -static void mvs_sig_remove_timer(struct mvs_phy *phy) -{ - if (phy->timer.function) - del_timer(&phy->timer); - phy->timer.function = NULL; -} - -void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st) -{ - struct mvs_phy *phy = &mvi->phy[i]; - struct sas_identify_frame *id; - - id = (struct sas_identify_frame *)phy->frame_rcvd; - - if (get_st) { - phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, i); - phy->phy_status = mvs_is_phy_ready(mvi, i); - } - - if (phy->phy_status) { - int oob_done = 0; - struct asd_sas_phy *sas_phy = &mvi->phy[i].sas_phy; - - oob_done = MVS_CHIP_DISP->oob_done(mvi, i); - - MVS_CHIP_DISP->fix_phy_info(mvi, i, id); - if (phy->phy_type & PORT_TYPE_SATA) { - phy->identify.target_port_protocols = SAS_PROTOCOL_STP; - if (mvs_is_sig_fis_received(phy->irq_status)) { - mvs_sig_remove_timer(phy); - phy->phy_attached = 1; - phy->att_dev_sas_addr = - i + mvi->id * mvi->chip->n_phy; - if (oob_done) - sas_phy->oob_mode = SATA_OOB_MODE; - phy->frame_rcvd_size = - sizeof(struct dev_to_host_fis); - mvs_get_d2h_reg(mvi, i, id); - } else { - u32 tmp; - dev_printk(KERN_DEBUG, mvi->dev, - "Phy%d : No sig fis\n", i); - tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, i); - MVS_CHIP_DISP->write_port_irq_mask(mvi, i, - tmp | PHYEV_SIG_FIS); - phy->phy_attached = 0; - phy->phy_type &= ~PORT_TYPE_SATA; - goto out_done; - } - } else if (phy->phy_type & PORT_TYPE_SAS - || phy->att_dev_info & PORT_SSP_INIT_MASK) { - phy->phy_attached = 1; - phy->identify.device_type = - phy->att_dev_info & PORT_DEV_TYPE_MASK; - - if (phy->identify.device_type == SAS_END_DEV) - phy->identify.target_port_protocols = - SAS_PROTOCOL_SSP; - else if (phy->identify.device_type != NO_DEVICE) - phy->identify.target_port_protocols = - SAS_PROTOCOL_SMP; - if (oob_done) - sas_phy->oob_mode = SAS_OOB_MODE; - phy->frame_rcvd_size = - sizeof(struct sas_identify_frame); - } - memcpy(sas_phy->attached_sas_addr, - &phy->att_dev_sas_addr, SAS_ADDR_SIZE); - - if (MVS_CHIP_DISP->phy_work_around) - MVS_CHIP_DISP->phy_work_around(mvi, i); - } - mv_dprintk("phy %d attach dev info is %x\n", - i + mvi->id * mvi->chip->n_phy, phy->att_dev_info); - mv_dprintk("phy %d attach sas addr is %llx\n", - i + mvi->id * mvi->chip->n_phy, phy->att_dev_sas_addr); -out_done: - if (get_st) - MVS_CHIP_DISP->write_port_irq_stat(mvi, i, phy->irq_status); -} - -static void mvs_port_notify_formed(struct asd_sas_phy *sas_phy, int lock) -{ - struct sas_ha_struct *sas_ha = sas_phy->ha; - struct mvs_info *mvi = NULL; int i = 0, hi; - struct mvs_phy *phy = sas_phy->lldd_phy; - struct asd_sas_port *sas_port = sas_phy->port; - struct mvs_port *port; - unsigned long flags = 0; - if (!sas_port) - return; - - while (sas_ha->sas_phy[i]) { - if (sas_ha->sas_phy[i] == sas_phy) - break; - i++; - } - hi = i/((struct mvs_prv_info *)sas_ha->lldd_ha)->n_phy; - mvi = ((struct mvs_prv_info *)sas_ha->lldd_ha)->mvi[hi]; - if (i >= mvi->chip->n_phy) - port = &mvi->port[i - mvi->chip->n_phy]; - else - port = &mvi->port[i]; - if (lock) - spin_lock_irqsave(&mvi->lock, flags); - port->port_attached = 1; - phy->port = port; - sas_port->lldd_port = port; - if (phy->phy_type & PORT_TYPE_SAS) { - port->wide_port_phymap = sas_port->phy_mask; - mv_printk("set wide port phy map %x\n", sas_port->phy_mask); - mvs_update_wideport(mvi, sas_phy->id); - - /* direct attached SAS device */ - if (phy->att_dev_info & PORT_SSP_TRGT_MASK) { - MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_PHY_STAT); - MVS_CHIP_DISP->write_port_cfg_data(mvi, i, 0x04); - } - } - if (lock) - spin_unlock_irqrestore(&mvi->lock, flags); -} - -static void mvs_port_notify_deformed(struct asd_sas_phy *sas_phy, int lock) -{ - struct domain_device *dev; - struct mvs_phy *phy = sas_phy->lldd_phy; - struct mvs_info *mvi = phy->mvi; - struct asd_sas_port *port = sas_phy->port; - int phy_no = 0; - - while (phy != &mvi->phy[phy_no]) { - phy_no++; - if (phy_no >= MVS_MAX_PHYS) - return; - } - list_for_each_entry(dev, &port->dev_list, dev_list_node) - mvs_do_release_task(phy->mvi, phy_no, dev); - -} - - -void mvs_port_formed(struct asd_sas_phy *sas_phy) -{ - mvs_port_notify_formed(sas_phy, 1); -} - -void mvs_port_deformed(struct asd_sas_phy *sas_phy) -{ - mvs_port_notify_deformed(sas_phy, 1); -} - -struct mvs_device *mvs_alloc_dev(struct mvs_info *mvi) -{ - u32 dev; - for (dev = 0; dev < MVS_MAX_DEVICES; dev++) { - if (mvi->devices[dev].dev_type == NO_DEVICE) { - mvi->devices[dev].device_id = dev; - return &mvi->devices[dev]; - } - } - - if (dev == MVS_MAX_DEVICES) - mv_printk("max support %d devices, ignore ..\n", - MVS_MAX_DEVICES); - - return NULL; -} - -void mvs_free_dev(struct mvs_device *mvi_dev) -{ - u32 id = mvi_dev->device_id; - memset(mvi_dev, 0, sizeof(*mvi_dev)); - mvi_dev->device_id = id; - mvi_dev->dev_type = NO_DEVICE; - mvi_dev->dev_status = MVS_DEV_NORMAL; - mvi_dev->taskfileset = MVS_ID_NOT_MAPPED; -} - -int mvs_dev_found_notify(struct domain_device *dev, int lock) -{ - unsigned long flags = 0; - int res = 0; - struct mvs_info *mvi = NULL; - struct domain_device *parent_dev = dev->parent; - struct mvs_device *mvi_device; - - mvi = mvs_find_dev_mvi(dev); - - if (lock) - spin_lock_irqsave(&mvi->lock, flags); - - mvi_device = mvs_alloc_dev(mvi); - if (!mvi_device) { - res = -1; - goto found_out; - } - dev->lldd_dev = mvi_device; - mvi_device->dev_status = MVS_DEV_NORMAL; - mvi_device->dev_type = dev->dev_type; - mvi_device->mvi_info = mvi; - mvi_device->sas_device = dev; - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { - int phy_id; - u8 phy_num = parent_dev->ex_dev.num_phys; - struct ex_phy *phy; - for (phy_id = 0; phy_id < phy_num; phy_id++) { - phy = &parent_dev->ex_dev.ex_phy[phy_id]; - if (SAS_ADDR(phy->attached_sas_addr) == - SAS_ADDR(dev->sas_addr)) { - mvi_device->attached_phy = phy_id; - break; - } - } - - if (phy_id == phy_num) { - mv_printk("Error: no attached dev:%016llx" - "at ex:%016llx.\n", - SAS_ADDR(dev->sas_addr), - SAS_ADDR(parent_dev->sas_addr)); - res = -1; - } - } - -found_out: - if (lock) - spin_unlock_irqrestore(&mvi->lock, flags); - return res; -} - -int mvs_dev_found(struct domain_device *dev) -{ - return mvs_dev_found_notify(dev, 1); -} - -void mvs_dev_gone_notify(struct domain_device *dev) -{ - unsigned long flags = 0; - struct mvs_device *mvi_dev = dev->lldd_dev; - struct mvs_info *mvi = mvi_dev->mvi_info; - - spin_lock_irqsave(&mvi->lock, flags); - - if (mvi_dev) { - mv_dprintk("found dev[%d:%x] is gone.\n", - mvi_dev->device_id, mvi_dev->dev_type); - mvs_release_task(mvi, dev); - mvs_free_reg_set(mvi, mvi_dev); - mvs_free_dev(mvi_dev); - } else { - mv_dprintk("found dev has gone.\n"); - } - dev->lldd_dev = NULL; - mvi_dev->sas_device = NULL; - - spin_unlock_irqrestore(&mvi->lock, flags); -} - - -void mvs_dev_gone(struct domain_device *dev) -{ - mvs_dev_gone_notify(dev); -} - -static void mvs_task_done(struct sas_task *task) -{ - if (!del_timer(&task->timer)) - return; - complete(&task->completion); -} - -static void mvs_tmf_timedout(unsigned long data) -{ - struct sas_task *task = (struct sas_task *)data; - - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - complete(&task->completion); -} - -#define MVS_TASK_TIMEOUT 20 -static int mvs_exec_internal_tmf_task(struct domain_device *dev, - void *parameter, u32 para_len, struct mvs_tmf_task *tmf) -{ - int res, retry; - struct sas_task *task = NULL; - - for (retry = 0; retry < 3; retry++) { - task = sas_alloc_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = dev; - task->task_proto = dev->tproto; - - memcpy(&task->ssp_task, parameter, para_len); - task->task_done = mvs_task_done; - - task->timer.data = (unsigned long) task; - task->timer.function = mvs_tmf_timedout; - task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ; - add_timer(&task->timer); - - res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf); - - if (res) { - del_timer(&task->timer); - mv_printk("executing internel task failed:%d\n", res); - goto ex_err; - } - - wait_for_completion(&task->completion); - res = TMF_RESP_FUNC_FAILED; - /* Even TMF timed out, return direct. */ - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - mv_printk("TMF task[%x] timeout.\n", tmf->tmf); - goto ex_err; - } - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_STAT_GOOD) { - res = TMF_RESP_FUNC_COMPLETE; - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_UNDERRUN) { - /* no error, but return the number of bytes of - * underrun */ - res = task->task_status.residual; - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_OVERRUN) { - mv_dprintk("blocked task error.\n"); - res = -EMSGSIZE; - break; - } else { - mv_dprintk(" task to dev %016llx response: 0x%x " - "status 0x%x\n", - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat); - sas_free_task(task); - task = NULL; - - } - } -ex_err: - BUG_ON(retry == 3 && task != NULL); - sas_free_task(task); - return res; -} - -static int mvs_debug_issue_ssp_tmf(struct domain_device *dev, - u8 *lun, struct mvs_tmf_task *tmf) -{ - struct sas_ssp_task ssp_task; - if (!(dev->tproto & SAS_PROTOCOL_SSP)) - return TMF_RESP_FUNC_ESUPP; - - memcpy(ssp_task.LUN, lun, 8); - - return mvs_exec_internal_tmf_task(dev, &ssp_task, - sizeof(ssp_task), tmf); -} - - -/* Standard mandates link reset for ATA (type 0) - and hard reset for SSP (type 1) , only for RECOVERY */ -static int mvs_debug_I_T_nexus_reset(struct domain_device *dev) -{ - int rc; - struct sas_phy *phy = sas_get_local_phy(dev); - int reset_type = (dev->dev_type == SATA_DEV || - (dev->tproto & SAS_PROTOCOL_STP)) ? 0 : 1; - rc = sas_phy_reset(phy, reset_type); - sas_put_local_phy(phy); - msleep(2000); - return rc; -} - -/* mandatory SAM-3 */ -int mvs_lu_reset(struct domain_device *dev, u8 *lun) -{ - unsigned long flags; - int rc = TMF_RESP_FUNC_FAILED; - struct mvs_tmf_task tmf_task; - struct mvs_device * mvi_dev = dev->lldd_dev; - struct mvs_info *mvi = mvi_dev->mvi_info; - - tmf_task.tmf = TMF_LU_RESET; - mvi_dev->dev_status = MVS_DEV_EH; - rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); - if (rc == TMF_RESP_FUNC_COMPLETE) { - spin_lock_irqsave(&mvi->lock, flags); - mvs_release_task(mvi, dev); - spin_unlock_irqrestore(&mvi->lock, flags); - } - /* If failed, fall-through I_T_Nexus reset */ - mv_printk("%s for device[%x]:rc= %d\n", __func__, - mvi_dev->device_id, rc); - return rc; -} - -int mvs_I_T_nexus_reset(struct domain_device *dev) -{ - unsigned long flags; - int rc = TMF_RESP_FUNC_FAILED; - struct mvs_device * mvi_dev = (struct mvs_device *)dev->lldd_dev; - struct mvs_info *mvi = mvi_dev->mvi_info; - - if (mvi_dev->dev_status != MVS_DEV_EH) - return TMF_RESP_FUNC_COMPLETE; - else - mvi_dev->dev_status = MVS_DEV_NORMAL; - rc = mvs_debug_I_T_nexus_reset(dev); - mv_printk("%s for device[%x]:rc= %d\n", - __func__, mvi_dev->device_id, rc); - - spin_lock_irqsave(&mvi->lock, flags); - mvs_release_task(mvi, dev); - spin_unlock_irqrestore(&mvi->lock, flags); - - return rc; -} -/* optional SAM-3 */ -int mvs_query_task(struct sas_task *task) -{ - u32 tag; - struct scsi_lun lun; - struct mvs_tmf_task tmf_task; - int rc = TMF_RESP_FUNC_FAILED; - - if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { - struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; - struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; - struct mvs_info *mvi = mvi_dev->mvi_info; - - int_to_scsilun(cmnd->device->lun, &lun); - rc = mvs_find_tag(mvi, task, &tag); - if (rc == 0) { - rc = TMF_RESP_FUNC_FAILED; - return rc; - } - - tmf_task.tmf = TMF_QUERY_TASK; - tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); - - rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task); - switch (rc) { - /* The task is still in Lun, release it then */ - case TMF_RESP_FUNC_SUCC: - /* The task is not in Lun or failed, reset the phy */ - case TMF_RESP_FUNC_FAILED: - case TMF_RESP_FUNC_COMPLETE: - break; - } - } - mv_printk("%s:rc= %d\n", __func__, rc); - return rc; -} - -/* mandatory SAM-3, still need free task/slot info */ -int mvs_abort_task(struct sas_task *task) -{ - struct scsi_lun lun; - struct mvs_tmf_task tmf_task; - struct domain_device *dev = task->dev; - struct mvs_device *mvi_dev = (struct mvs_device *)dev->lldd_dev; - struct mvs_info *mvi; - int rc = TMF_RESP_FUNC_FAILED; - unsigned long flags; - u32 tag; - - if (!mvi_dev) { - mv_printk("Device has removed\n"); - return TMF_RESP_FUNC_FAILED; - } - - mvi = mvi_dev->mvi_info; - - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - rc = TMF_RESP_FUNC_COMPLETE; - goto out; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - mvi_dev->dev_status = MVS_DEV_EH; - if (task->lldd_task && task->task_proto & SAS_PROTOCOL_SSP) { - struct scsi_cmnd * cmnd = (struct scsi_cmnd *)task->uldd_task; - - int_to_scsilun(cmnd->device->lun, &lun); - rc = mvs_find_tag(mvi, task, &tag); - if (rc == 0) { - mv_printk("No such tag in %s\n", __func__); - rc = TMF_RESP_FUNC_FAILED; - return rc; - } - - tmf_task.tmf = TMF_ABORT_TASK; - tmf_task.tag_of_task_to_be_managed = cpu_to_le16(tag); - - rc = mvs_debug_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task); - - /* if successful, clear the task and callback forwards.*/ - if (rc == TMF_RESP_FUNC_COMPLETE) { - u32 slot_no; - struct mvs_slot_info *slot; - - if (task->lldd_task) { - slot = task->lldd_task; - slot_no = (u32) (slot - mvi->slot_info); - spin_lock_irqsave(&mvi->lock, flags); - mvs_slot_complete(mvi, slot_no, 1); - spin_unlock_irqrestore(&mvi->lock, flags); - } - } - - } else if (task->task_proto & SAS_PROTOCOL_SATA || - task->task_proto & SAS_PROTOCOL_STP) { - if (SATA_DEV == dev->dev_type) { - struct mvs_slot_info *slot = task->lldd_task; - u32 slot_idx = (u32)(slot - mvi->slot_info); - mv_dprintk("mvs_abort_task() mvi=%p task=%p " - "slot=%p slot_idx=x%x\n", - mvi, task, slot, slot_idx); - mvs_tmf_timedout((unsigned long)task); - mvs_slot_task_free(mvi, task, slot, slot_idx); - rc = TMF_RESP_FUNC_COMPLETE; - goto out; - } - - } -out: - if (rc != TMF_RESP_FUNC_COMPLETE) - mv_printk("%s:rc= %d\n", __func__, rc); - return rc; -} - -int mvs_abort_task_set(struct domain_device *dev, u8 *lun) -{ - int rc = TMF_RESP_FUNC_FAILED; - struct mvs_tmf_task tmf_task; - - tmf_task.tmf = TMF_ABORT_TASK_SET; - rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); - - return rc; -} - -int mvs_clear_aca(struct domain_device *dev, u8 *lun) -{ - int rc = TMF_RESP_FUNC_FAILED; - struct mvs_tmf_task tmf_task; - - tmf_task.tmf = TMF_CLEAR_ACA; - rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); - - return rc; -} - -int mvs_clear_task_set(struct domain_device *dev, u8 *lun) -{ - int rc = TMF_RESP_FUNC_FAILED; - struct mvs_tmf_task tmf_task; - - tmf_task.tmf = TMF_CLEAR_TASK_SET; - rc = mvs_debug_issue_ssp_tmf(dev, lun, &tmf_task); - - return rc; -} - -static int mvs_sata_done(struct mvs_info *mvi, struct sas_task *task, - u32 slot_idx, int err) -{ - struct mvs_device *mvi_dev = task->dev->lldd_dev; - struct task_status_struct *tstat = &task->task_status; - struct ata_task_resp *resp = (struct ata_task_resp *)tstat->buf; - int stat = SAM_STAT_GOOD; - - - resp->frame_len = sizeof(struct dev_to_host_fis); - memcpy(&resp->ending_fis[0], - SATA_RECEIVED_D2H_FIS(mvi_dev->taskfileset), - sizeof(struct dev_to_host_fis)); - tstat->buf_valid_size = sizeof(*resp); - if (unlikely(err)) { - if (unlikely(err & CMD_ISS_STPD)) - stat = SAS_OPEN_REJECT; - else - stat = SAS_PROTO_RESPONSE; - } - - return stat; -} - -void mvs_set_sense(u8 *buffer, int len, int d_sense, - int key, int asc, int ascq) -{ - memset(buffer, 0, len); - - if (d_sense) { - /* Descriptor format */ - if (len < 4) { - mv_printk("Length %d of sense buffer too small to " - "fit sense %x:%x:%x", len, key, asc, ascq); - } - - buffer[0] = 0x72; /* Response Code */ - if (len > 1) - buffer[1] = key; /* Sense Key */ - if (len > 2) - buffer[2] = asc; /* ASC */ - if (len > 3) - buffer[3] = ascq; /* ASCQ */ - } else { - if (len < 14) { - mv_printk("Length %d of sense buffer too small to " - "fit sense %x:%x:%x", len, key, asc, ascq); - } - - buffer[0] = 0x70; /* Response Code */ - if (len > 2) - buffer[2] = key; /* Sense Key */ - if (len > 7) - buffer[7] = 0x0a; /* Additional Sense Length */ - if (len > 12) - buffer[12] = asc; /* ASC */ - if (len > 13) - buffer[13] = ascq; /* ASCQ */ - } - - return; -} - -void mvs_fill_ssp_resp_iu(struct ssp_response_iu *iu, - u8 key, u8 asc, u8 asc_q) -{ - iu->datapres = 2; - iu->response_data_len = 0; - iu->sense_data_len = 17; - iu->status = 02; - mvs_set_sense(iu->sense_data, 17, 0, - key, asc, asc_q); -} - -static int mvs_slot_err(struct mvs_info *mvi, struct sas_task *task, - u32 slot_idx) -{ - struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; - int stat; - u32 err_dw0 = le32_to_cpu(*(u32 *)slot->response); - u32 err_dw1 = le32_to_cpu(*((u32 *)slot->response + 1)); - u32 tfs = 0; - enum mvs_port_type type = PORT_TYPE_SAS; - - if (err_dw0 & CMD_ISS_STPD) - MVS_CHIP_DISP->issue_stop(mvi, type, tfs); - - MVS_CHIP_DISP->command_active(mvi, slot_idx); - - stat = SAM_STAT_CHECK_CONDITION; - switch (task->task_proto) { - case SAS_PROTOCOL_SSP: - { - stat = SAS_ABORTED_TASK; - if ((err_dw0 & NO_DEST) || err_dw1 & bit(31)) { - struct ssp_response_iu *iu = slot->response + - sizeof(struct mvs_err_info); - mvs_fill_ssp_resp_iu(iu, NOT_READY, 0x04, 01); - sas_ssp_task_response(mvi->dev, task, iu); - stat = SAM_STAT_CHECK_CONDITION; - } - if (err_dw1 & bit(31)) - mv_printk("reuse same slot, retry command.\n"); - break; - } - case SAS_PROTOCOL_SMP: - stat = SAM_STAT_CHECK_CONDITION; - break; - - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - { - task->ata_task.use_ncq = 0; - stat = SAS_PROTO_RESPONSE; - mvs_sata_done(mvi, task, slot_idx, err_dw0); - } - break; - default: - break; - } - - return stat; -} - -int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags) -{ - u32 slot_idx = rx_desc & RXQ_SLOT_MASK; - struct mvs_slot_info *slot = &mvi->slot_info[slot_idx]; - struct sas_task *task = slot->task; - struct mvs_device *mvi_dev = NULL; - struct task_status_struct *tstat; - struct domain_device *dev; - u32 aborted; - - void *to; - enum exec_status sts; - - if (unlikely(!task || !task->lldd_task || !task->dev)) - return -1; - - tstat = &task->task_status; - dev = task->dev; - mvi_dev = dev->lldd_dev; - - spin_lock(&task->task_state_lock); - task->task_state_flags &= - ~(SAS_TASK_STATE_PENDING | SAS_TASK_AT_INITIATOR); - task->task_state_flags |= SAS_TASK_STATE_DONE; - /* race condition*/ - aborted = task->task_state_flags & SAS_TASK_STATE_ABORTED; - spin_unlock(&task->task_state_lock); - - memset(tstat, 0, sizeof(*tstat)); - tstat->resp = SAS_TASK_COMPLETE; - - if (unlikely(aborted)) { - tstat->stat = SAS_ABORTED_TASK; - if (mvi_dev && mvi_dev->running_req) - mvi_dev->running_req--; - if (sas_protocol_ata(task->task_proto)) - mvs_free_reg_set(mvi, mvi_dev); - - mvs_slot_task_free(mvi, task, slot, slot_idx); - return -1; - } - - /* when no device attaching, go ahead and complete by error handling*/ - if (unlikely(!mvi_dev || flags)) { - if (!mvi_dev) - mv_dprintk("port has not device.\n"); - tstat->stat = SAS_PHY_DOWN; - goto out; - } - - /* error info record present */ - if (unlikely((rx_desc & RXQ_ERR) && (*(u64 *) slot->response))) { - mv_dprintk("port %d slot %d rx_desc %X has error info" - "%016llX.\n", slot->port->sas_port.id, slot_idx, - rx_desc, (u64)(*(u64 *)slot->response)); - tstat->stat = mvs_slot_err(mvi, task, slot_idx); - tstat->resp = SAS_TASK_COMPLETE; - goto out; - } - - switch (task->task_proto) { - case SAS_PROTOCOL_SSP: - /* hw says status == 0, datapres == 0 */ - if (rx_desc & RXQ_GOOD) { - tstat->stat = SAM_STAT_GOOD; - tstat->resp = SAS_TASK_COMPLETE; - } - /* response frame present */ - else if (rx_desc & RXQ_RSP) { - struct ssp_response_iu *iu = slot->response + - sizeof(struct mvs_err_info); - sas_ssp_task_response(mvi->dev, task, iu); - } else - tstat->stat = SAM_STAT_CHECK_CONDITION; - break; - - case SAS_PROTOCOL_SMP: { - struct scatterlist *sg_resp = &task->smp_task.smp_resp; - tstat->stat = SAM_STAT_GOOD; - to = kmap_atomic(sg_page(sg_resp)); - memcpy(to + sg_resp->offset, - slot->response + sizeof(struct mvs_err_info), - sg_dma_len(sg_resp)); - kunmap_atomic(to); - break; - } - - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: { - tstat->stat = mvs_sata_done(mvi, task, slot_idx, 0); - break; - } - - default: - tstat->stat = SAM_STAT_CHECK_CONDITION; - break; - } - if (!slot->port->port_attached) { - mv_dprintk("port %d has removed.\n", slot->port->sas_port.id); - tstat->stat = SAS_PHY_DOWN; - } - - -out: - if (mvi_dev && mvi_dev->running_req) { - mvi_dev->running_req--; - if (sas_protocol_ata(task->task_proto) && !mvi_dev->running_req) - mvs_free_reg_set(mvi, mvi_dev); - } - mvs_slot_task_free(mvi, task, slot, slot_idx); - sts = tstat->stat; - - spin_unlock(&mvi->lock); - if (task->task_done) - task->task_done(task); - - spin_lock(&mvi->lock); - - return sts; -} - -void mvs_do_release_task(struct mvs_info *mvi, - int phy_no, struct domain_device *dev) -{ - u32 slot_idx; - struct mvs_phy *phy; - struct mvs_port *port; - struct mvs_slot_info *slot, *slot2; - - phy = &mvi->phy[phy_no]; - port = phy->port; - if (!port) - return; - /* clean cmpl queue in case request is already finished */ - mvs_int_rx(mvi, false); - - - - list_for_each_entry_safe(slot, slot2, &port->list, entry) { - struct sas_task *task; - slot_idx = (u32) (slot - mvi->slot_info); - task = slot->task; - - if (dev && task->dev != dev) - continue; - - mv_printk("Release slot [%x] tag[%x], task [%p]:\n", - slot_idx, slot->slot_tag, task); - MVS_CHIP_DISP->command_active(mvi, slot_idx); - - mvs_slot_complete(mvi, slot_idx, 1); - } -} - -void mvs_release_task(struct mvs_info *mvi, - struct domain_device *dev) -{ - int i, phyno[WIDE_PORT_MAX_PHY], num; - num = mvs_find_dev_phyno(dev, phyno); - for (i = 0; i < num; i++) - mvs_do_release_task(mvi, phyno[i], dev); -} - -static void mvs_phy_disconnected(struct mvs_phy *phy) -{ - phy->phy_attached = 0; - phy->att_dev_info = 0; - phy->att_dev_sas_addr = 0; -} - -static void mvs_work_queue(struct work_struct *work) -{ - struct delayed_work *dw = container_of(work, struct delayed_work, work); - struct mvs_wq *mwq = container_of(dw, struct mvs_wq, work_q); - struct mvs_info *mvi = mwq->mvi; - unsigned long flags; - u32 phy_no = (unsigned long) mwq->data; - struct sas_ha_struct *sas_ha = mvi->sas; - struct mvs_phy *phy = &mvi->phy[phy_no]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - - spin_lock_irqsave(&mvi->lock, flags); - if (mwq->handler & PHY_PLUG_EVENT) { - - if (phy->phy_event & PHY_PLUG_OUT) { - u32 tmp; - struct sas_identify_frame *id; - id = (struct sas_identify_frame *)phy->frame_rcvd; - tmp = MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no); - phy->phy_event &= ~PHY_PLUG_OUT; - if (!(tmp & PHY_READY_MASK)) { - sas_phy_disconnected(sas_phy); - mvs_phy_disconnected(phy); - sas_ha->notify_phy_event(sas_phy, - PHYE_LOSS_OF_SIGNAL); - mv_dprintk("phy%d Removed Device\n", phy_no); - } else { - MVS_CHIP_DISP->detect_porttype(mvi, phy_no); - mvs_update_phyinfo(mvi, phy_no, 1); - mvs_bytes_dmaed(mvi, phy_no); - mvs_port_notify_formed(sas_phy, 0); - mv_dprintk("phy%d Attached Device\n", phy_no); - } - } - } else if (mwq->handler & EXP_BRCT_CHG) { - phy->phy_event &= ~EXP_BRCT_CHG; - sas_ha->notify_port_event(sas_phy, - PORTE_BROADCAST_RCVD); - mv_dprintk("phy%d Got Broadcast Change\n", phy_no); - } - list_del(&mwq->entry); - spin_unlock_irqrestore(&mvi->lock, flags); - kfree(mwq); -} - -static int mvs_handle_event(struct mvs_info *mvi, void *data, int handler) -{ - struct mvs_wq *mwq; - int ret = 0; - - mwq = kmalloc(sizeof(struct mvs_wq), GFP_ATOMIC); - if (mwq) { - mwq->mvi = mvi; - mwq->data = data; - mwq->handler = handler; - MV_INIT_DELAYED_WORK(&mwq->work_q, mvs_work_queue, mwq); - list_add_tail(&mwq->entry, &mvi->wq_list); - schedule_delayed_work(&mwq->work_q, HZ * 2); - } else - ret = -ENOMEM; - - return ret; -} - -static void mvs_sig_time_out(unsigned long tphy) -{ - struct mvs_phy *phy = (struct mvs_phy *)tphy; - struct mvs_info *mvi = phy->mvi; - u8 phy_no; - - for (phy_no = 0; phy_no < mvi->chip->n_phy; phy_no++) { - if (&mvi->phy[phy_no] == phy) { - mv_dprintk("Get signature time out, reset phy %d\n", - phy_no+mvi->id*mvi->chip->n_phy); - MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_HARD_RESET); - } - } -} - -void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events) -{ - u32 tmp; - struct mvs_phy *phy = &mvi->phy[phy_no]; - - phy->irq_status = MVS_CHIP_DISP->read_port_irq_stat(mvi, phy_no); - MVS_CHIP_DISP->write_port_irq_stat(mvi, phy_no, phy->irq_status); - mv_dprintk("phy %d ctrl sts=0x%08X.\n", phy_no+mvi->id*mvi->chip->n_phy, - MVS_CHIP_DISP->read_phy_ctl(mvi, phy_no)); - mv_dprintk("phy %d irq sts = 0x%08X\n", phy_no+mvi->id*mvi->chip->n_phy, - phy->irq_status); - - /* - * events is port event now , - * we need check the interrupt status which belongs to per port. - */ - - if (phy->irq_status & PHYEV_DCDR_ERR) { - mv_dprintk("phy %d STP decoding error.\n", - phy_no + mvi->id*mvi->chip->n_phy); - } - - if (phy->irq_status & PHYEV_POOF) { - mdelay(500); - if (!(phy->phy_event & PHY_PLUG_OUT)) { - int dev_sata = phy->phy_type & PORT_TYPE_SATA; - int ready; - mvs_do_release_task(mvi, phy_no, NULL); - phy->phy_event |= PHY_PLUG_OUT; - MVS_CHIP_DISP->clear_srs_irq(mvi, 0, 1); - mvs_handle_event(mvi, - (void *)(unsigned long)phy_no, - PHY_PLUG_EVENT); - ready = mvs_is_phy_ready(mvi, phy_no); - if (ready || dev_sata) { - if (MVS_CHIP_DISP->stp_reset) - MVS_CHIP_DISP->stp_reset(mvi, - phy_no); - else - MVS_CHIP_DISP->phy_reset(mvi, - phy_no, MVS_SOFT_RESET); - return; - } - } - } - - if (phy->irq_status & PHYEV_COMWAKE) { - tmp = MVS_CHIP_DISP->read_port_irq_mask(mvi, phy_no); - MVS_CHIP_DISP->write_port_irq_mask(mvi, phy_no, - tmp | PHYEV_SIG_FIS); - if (phy->timer.function == NULL) { - phy->timer.data = (unsigned long)phy; - phy->timer.function = mvs_sig_time_out; - phy->timer.expires = jiffies + 5*HZ; - add_timer(&phy->timer); - } - } - if (phy->irq_status & (PHYEV_SIG_FIS | PHYEV_ID_DONE)) { - phy->phy_status = mvs_is_phy_ready(mvi, phy_no); - mv_dprintk("notify plug in on phy[%d]\n", phy_no); - if (phy->phy_status) { - mdelay(10); - MVS_CHIP_DISP->detect_porttype(mvi, phy_no); - if (phy->phy_type & PORT_TYPE_SATA) { - tmp = MVS_CHIP_DISP->read_port_irq_mask( - mvi, phy_no); - tmp &= ~PHYEV_SIG_FIS; - MVS_CHIP_DISP->write_port_irq_mask(mvi, - phy_no, tmp); - } - mvs_update_phyinfo(mvi, phy_no, 0); - if (phy->phy_type & PORT_TYPE_SAS) { - MVS_CHIP_DISP->phy_reset(mvi, phy_no, MVS_PHY_TUNE); - mdelay(10); - } - - mvs_bytes_dmaed(mvi, phy_no); - /* whether driver is going to handle hot plug */ - if (phy->phy_event & PHY_PLUG_OUT) { - mvs_port_notify_formed(&phy->sas_phy, 0); - phy->phy_event &= ~PHY_PLUG_OUT; - } - } else { - mv_dprintk("plugin interrupt but phy%d is gone\n", - phy_no + mvi->id*mvi->chip->n_phy); - } - } else if (phy->irq_status & PHYEV_BROAD_CH) { - mv_dprintk("phy %d broadcast change.\n", - phy_no + mvi->id*mvi->chip->n_phy); - mvs_handle_event(mvi, (void *)(unsigned long)phy_no, - EXP_BRCT_CHG); - } -} - -int mvs_int_rx(struct mvs_info *mvi, bool self_clear) -{ - u32 rx_prod_idx, rx_desc; - bool attn = false; - - /* the first dword in the RX ring is special: it contains - * a mirror of the hardware's RX producer index, so that - * we don't have to stall the CPU reading that register. - * The actual RX ring is offset by one dword, due to this. - */ - rx_prod_idx = mvi->rx_cons; - mvi->rx_cons = le32_to_cpu(mvi->rx[0]); - if (mvi->rx_cons == 0xfff) /* h/w hasn't touched RX ring yet */ - return 0; - - /* The CMPL_Q may come late, read from register and try again - * note: if coalescing is enabled, - * it will need to read from register every time for sure - */ - if (unlikely(mvi->rx_cons == rx_prod_idx)) - mvi->rx_cons = MVS_CHIP_DISP->rx_update(mvi) & RX_RING_SZ_MASK; - - if (mvi->rx_cons == rx_prod_idx) - return 0; - - while (mvi->rx_cons != rx_prod_idx) { - /* increment our internal RX consumer pointer */ - rx_prod_idx = (rx_prod_idx + 1) & (MVS_RX_RING_SZ - 1); - rx_desc = le32_to_cpu(mvi->rx[rx_prod_idx + 1]); - - if (likely(rx_desc & RXQ_DONE)) - mvs_slot_complete(mvi, rx_desc, 0); - if (rx_desc & RXQ_ATTN) { - attn = true; - } else if (rx_desc & RXQ_ERR) { - if (!(rx_desc & RXQ_DONE)) - mvs_slot_complete(mvi, rx_desc, 0); - } else if (rx_desc & RXQ_SLOT_RESET) { - mvs_slot_free(mvi, rx_desc); - } - } - - if (attn && self_clear) - MVS_CHIP_DISP->int_full(mvi); - return 0; -} - diff --git a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.h b/ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.h deleted file mode 100644 index c04a4f5b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvsas/mv_sas.h +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Marvell 88SE64xx/88SE94xx main function head file - * - * Copyright 2007 Red Hat, Inc. - * Copyright 2008 Marvell. - * Copyright 2009-2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - -#ifndef _MV_SAS_H_ -#define _MV_SAS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mv_defs.h" - -#define DRV_NAME "mvsas" -#define DRV_VERSION "0.8.16" -#define MVS_ID_NOT_MAPPED 0x7f -#define WIDE_PORT_MAX_PHY 4 -#define mv_printk(fmt, arg ...) \ - printk(KERN_DEBUG"%s %d:" fmt, __FILE__, __LINE__, ## arg) -#ifdef MV_DEBUG -#define mv_dprintk(format, arg...) \ - printk(KERN_DEBUG"%s %d:" format, __FILE__, __LINE__, ## arg) -#else -#define mv_dprintk(format, arg...) -#endif -#define MV_MAX_U32 0xffffffff - -extern int interrupt_coalescing; -extern struct mvs_tgt_initiator mvs_tgt; -extern struct mvs_info *tgt_mvi; -extern const struct mvs_dispatch mvs_64xx_dispatch; -extern const struct mvs_dispatch mvs_94xx_dispatch; -extern struct kmem_cache *mvs_task_list_cache; - -#define DEV_IS_EXPANDER(type) \ - ((type == EDGE_DEV) || (type == FANOUT_DEV)) - -#define bit(n) ((u32)1 << n) - -#define for_each_phy(__lseq_mask, __mc, __lseq) \ - for ((__mc) = (__lseq_mask), (__lseq) = 0; \ - (__mc) != 0 ; \ - (++__lseq), (__mc) >>= 1) - -#define MV_INIT_DELAYED_WORK(w, f, d) INIT_DELAYED_WORK(w, f) -#define UNASSOC_D2H_FIS(id) \ - ((void *) mvi->rx_fis + 0x100 * id) -#define SATA_RECEIVED_FIS_LIST(reg_set) \ - ((void *) mvi->rx_fis + mvi->chip->fis_offs + 0x100 * reg_set) -#define SATA_RECEIVED_SDB_FIS(reg_set) \ - (SATA_RECEIVED_FIS_LIST(reg_set) + 0x58) -#define SATA_RECEIVED_D2H_FIS(reg_set) \ - (SATA_RECEIVED_FIS_LIST(reg_set) + 0x40) -#define SATA_RECEIVED_PIO_FIS(reg_set) \ - (SATA_RECEIVED_FIS_LIST(reg_set) + 0x20) -#define SATA_RECEIVED_DMA_FIS(reg_set) \ - (SATA_RECEIVED_FIS_LIST(reg_set) + 0x00) - -enum dev_status { - MVS_DEV_NORMAL = 0x0, - MVS_DEV_EH = 0x1, -}; - -enum dev_reset { - MVS_SOFT_RESET = 0, - MVS_HARD_RESET = 1, - MVS_PHY_TUNE = 2, -}; - -struct mvs_info; - -struct mvs_dispatch { - char *name; - int (*chip_init)(struct mvs_info *mvi); - int (*spi_init)(struct mvs_info *mvi); - int (*chip_ioremap)(struct mvs_info *mvi); - void (*chip_iounmap)(struct mvs_info *mvi); - irqreturn_t (*isr)(struct mvs_info *mvi, int irq, u32 stat); - u32 (*isr_status)(struct mvs_info *mvi, int irq); - void (*interrupt_enable)(struct mvs_info *mvi); - void (*interrupt_disable)(struct mvs_info *mvi); - - u32 (*read_phy_ctl)(struct mvs_info *mvi, u32 port); - void (*write_phy_ctl)(struct mvs_info *mvi, u32 port, u32 val); - - u32 (*read_port_cfg_data)(struct mvs_info *mvi, u32 port); - void (*write_port_cfg_data)(struct mvs_info *mvi, u32 port, u32 val); - void (*write_port_cfg_addr)(struct mvs_info *mvi, u32 port, u32 addr); - - u32 (*read_port_vsr_data)(struct mvs_info *mvi, u32 port); - void (*write_port_vsr_data)(struct mvs_info *mvi, u32 port, u32 val); - void (*write_port_vsr_addr)(struct mvs_info *mvi, u32 port, u32 addr); - - u32 (*read_port_irq_stat)(struct mvs_info *mvi, u32 port); - void (*write_port_irq_stat)(struct mvs_info *mvi, u32 port, u32 val); - - u32 (*read_port_irq_mask)(struct mvs_info *mvi, u32 port); - void (*write_port_irq_mask)(struct mvs_info *mvi, u32 port, u32 val); - - void (*command_active)(struct mvs_info *mvi, u32 slot_idx); - void (*clear_srs_irq)(struct mvs_info *mvi, u8 reg_set, u8 clear_all); - void (*issue_stop)(struct mvs_info *mvi, enum mvs_port_type type, - u32 tfs); - void (*start_delivery)(struct mvs_info *mvi, u32 tx); - u32 (*rx_update)(struct mvs_info *mvi); - void (*int_full)(struct mvs_info *mvi); - u8 (*assign_reg_set)(struct mvs_info *mvi, u8 *tfs); - void (*free_reg_set)(struct mvs_info *mvi, u8 *tfs); - u32 (*prd_size)(void); - u32 (*prd_count)(void); - void (*make_prd)(struct scatterlist *scatter, int nr, void *prd); - void (*detect_porttype)(struct mvs_info *mvi, int i); - int (*oob_done)(struct mvs_info *mvi, int i); - void (*fix_phy_info)(struct mvs_info *mvi, int i, - struct sas_identify_frame *id); - void (*phy_work_around)(struct mvs_info *mvi, int i); - void (*phy_set_link_rate)(struct mvs_info *mvi, u32 phy_id, - struct sas_phy_linkrates *rates); - u32 (*phy_max_link_rate)(void); - void (*phy_disable)(struct mvs_info *mvi, u32 phy_id); - void (*phy_enable)(struct mvs_info *mvi, u32 phy_id); - void (*phy_reset)(struct mvs_info *mvi, u32 phy_id, int hard); - void (*stp_reset)(struct mvs_info *mvi, u32 phy_id); - void (*clear_active_cmds)(struct mvs_info *mvi); - u32 (*spi_read_data)(struct mvs_info *mvi); - void (*spi_write_data)(struct mvs_info *mvi, u32 data); - int (*spi_buildcmd)(struct mvs_info *mvi, - u32 *dwCmd, - u8 cmd, - u8 read, - u8 length, - u32 addr - ); - int (*spi_issuecmd)(struct mvs_info *mvi, u32 cmd); - int (*spi_waitdataready)(struct mvs_info *mvi, u32 timeout); - void (*dma_fix)(struct mvs_info *mvi, u32 phy_mask, - int buf_len, int from, void *prd); - void (*tune_interrupt)(struct mvs_info *mvi, u32 time); - void (*non_spec_ncq_error)(struct mvs_info *mvi); - -}; - -struct mvs_chip_info { - u32 n_host; - u32 n_phy; - u32 fis_offs; - u32 fis_count; - u32 srs_sz; - u32 sg_width; - u32 slot_width; - const struct mvs_dispatch *dispatch; -}; -#define MVS_MAX_SG (1U << mvi->chip->sg_width) -#define MVS_CHIP_SLOT_SZ (1U << mvi->chip->slot_width) -#define MVS_RX_FISL_SZ \ - (mvi->chip->fis_offs + (mvi->chip->fis_count * 0x100)) -#define MVS_CHIP_DISP (mvi->chip->dispatch) - -struct mvs_err_info { - __le32 flags; - __le32 flags2; -}; - -struct mvs_cmd_hdr { - __le32 flags; /* PRD tbl len; SAS, SATA ctl */ - __le32 lens; /* cmd, max resp frame len */ - __le32 tags; /* targ port xfer tag; tag */ - __le32 data_len; /* data xfer len */ - __le64 cmd_tbl; /* command table address */ - __le64 open_frame; /* open addr frame address */ - __le64 status_buf; /* status buffer address */ - __le64 prd_tbl; /* PRD tbl address */ - __le32 reserved[4]; -}; - -struct mvs_port { - struct asd_sas_port sas_port; - u8 port_attached; - u8 wide_port_phymap; - struct list_head list; -}; - -struct mvs_phy { - struct mvs_info *mvi; - struct mvs_port *port; - struct asd_sas_phy sas_phy; - struct sas_identify identify; - struct scsi_device *sdev; - struct timer_list timer; - u64 dev_sas_addr; - u64 att_dev_sas_addr; - u32 att_dev_info; - u32 dev_info; - u32 phy_type; - u32 phy_status; - u32 irq_status; - u32 frame_rcvd_size; - u8 frame_rcvd[32]; - u8 phy_attached; - u8 phy_mode; - u8 reserved[2]; - u32 phy_event; - enum sas_linkrate minimum_linkrate; - enum sas_linkrate maximum_linkrate; -}; - -struct mvs_device { - struct list_head dev_entry; - enum sas_dev_type dev_type; - struct mvs_info *mvi_info; - struct domain_device *sas_device; - struct timer_list timer; - u32 attached_phy; - u32 device_id; - u32 running_req; - u8 taskfileset; - u8 dev_status; - u16 reserved; -}; - -/* Generate PHY tunning parameters */ -struct phy_tuning { - /* 1 bit, transmitter emphasis enable */ - u8 trans_emp_en:1; - /* 4 bits, transmitter emphasis amplitude */ - u8 trans_emp_amp:4; - /* 3 bits, reserved space */ - u8 Reserved_2bit_1:3; - /* 5 bits, transmitter amplitude */ - u8 trans_amp:5; - /* 2 bits, transmitter amplitude adjust */ - u8 trans_amp_adj:2; - /* 1 bit, reserved space */ - u8 resv_2bit_2:1; - /* 2 bytes, reserved space */ - u8 reserved[2]; -}; - -struct ffe_control { - /* 4 bits, FFE Capacitor Select (value range 0~F) */ - u8 ffe_cap_sel:4; - /* 3 bits, FFE Resistor Select (value range 0~7) */ - u8 ffe_rss_sel:3; - /* 1 bit reserve*/ - u8 reserved:1; -}; - -/* - * HBA_Info_Page is saved in Flash/NVRAM, total 256 bytes. - * The data area is valid only Signature="MRVL". - * If any member fills with 0xFF, the member is invalid. - */ -struct hba_info_page { - /* Dword 0 */ - /* 4 bytes, structure signature,should be "MRVL" at first initial */ - u8 signature[4]; - - /* Dword 1-13 */ - u32 reserved1[13]; - - /* Dword 14-29 */ - /* 64 bytes, SAS address for each port */ - u64 sas_addr[8]; - - /* Dword 30-31 */ - /* 8 bytes for vanir 8 port PHY FFE seeting - * BIT 0~3 : FFE Capacitor select(value range 0~F) - * BIT 4~6 : FFE Resistor select(value range 0~7) - * BIT 7: reserve. - */ - - struct ffe_control ffe_ctl[8]; - /* Dword 32 -43 */ - u32 reserved2[12]; - - /* Dword 44-45 */ - /* 8 bytes, 0: 1.5G, 1: 3.0G, should be 0x01 at first initial */ - u8 phy_rate[8]; - - /* Dword 46-53 */ - /* 32 bytes, PHY tuning parameters for each PHY*/ - struct phy_tuning phy_tuning[8]; - - /* Dword 54-63 */ - u32 reserved3[10]; -}; /* total 256 bytes */ - -struct mvs_slot_info { - struct list_head entry; - union { - struct sas_task *task; - void *tdata; - }; - u32 n_elem; - u32 tx; - u32 slot_tag; - - /* DMA buffer for storing cmd tbl, open addr frame, status buffer, - * and PRD table - */ - void *buf; - dma_addr_t buf_dma; - void *response; - struct mvs_port *port; - struct mvs_device *device; - void *open_frame; -}; - -struct mvs_info { - unsigned long flags; - - /* host-wide lock */ - spinlock_t lock; - - /* our device */ - struct pci_dev *pdev; - struct device *dev; - - /* enhanced mode registers */ - void __iomem *regs; - - /* peripheral or soc registers */ - void __iomem *regs_ex; - u8 sas_addr[SAS_ADDR_SIZE]; - - /* SCSI/SAS glue */ - struct sas_ha_struct *sas; - struct Scsi_Host *shost; - - /* TX (delivery) DMA ring */ - __le32 *tx; - dma_addr_t tx_dma; - - /* cached next-producer idx */ - u32 tx_prod; - - /* RX (completion) DMA ring */ - __le32 *rx; - dma_addr_t rx_dma; - - /* RX consumer idx */ - u32 rx_cons; - - /* RX'd FIS area */ - __le32 *rx_fis; - dma_addr_t rx_fis_dma; - - /* DMA command header slots */ - struct mvs_cmd_hdr *slot; - dma_addr_t slot_dma; - - u32 chip_id; - const struct mvs_chip_info *chip; - - int tags_num; - unsigned long *tags; - /* further per-slot information */ - struct mvs_phy phy[MVS_MAX_PHYS]; - struct mvs_port port[MVS_MAX_PHYS]; - u32 id; - u64 sata_reg_set; - struct list_head *hba_list; - struct list_head soc_entry; - struct list_head wq_list; - unsigned long instance; - u16 flashid; - u32 flashsize; - u32 flashsectSize; - - void *addon; - struct hba_info_page hba_info_param; - struct mvs_device devices[MVS_MAX_DEVICES]; - void *bulk_buffer; - dma_addr_t bulk_buffer_dma; - void *bulk_buffer1; - dma_addr_t bulk_buffer_dma1; -#define TRASH_BUCKET_SIZE 0x20000 - void *dma_pool; - struct mvs_slot_info slot_info[0]; -}; - -struct mvs_prv_info{ - u8 n_host; - u8 n_phy; - u8 scan_finished; - u8 reserve; - struct mvs_info *mvi[2]; - struct tasklet_struct mv_tasklet; -}; - -struct mvs_wq { - struct delayed_work work_q; - struct mvs_info *mvi; - void *data; - int handler; - struct list_head entry; -}; - -struct mvs_task_exec_info { - struct sas_task *task; - struct mvs_cmd_hdr *hdr; - struct mvs_port *port; - u32 tag; - int n_elem; -}; - -struct mvs_task_list { - struct sas_task *task; - struct list_head list; -}; - - -/******************** function prototype *********************/ -void mvs_get_sas_addr(void *buf, u32 buflen); -void mvs_tag_clear(struct mvs_info *mvi, u32 tag); -void mvs_tag_free(struct mvs_info *mvi, u32 tag); -void mvs_tag_set(struct mvs_info *mvi, unsigned int tag); -int mvs_tag_alloc(struct mvs_info *mvi, u32 *tag_out); -void mvs_tag_init(struct mvs_info *mvi); -void mvs_iounmap(void __iomem *regs); -int mvs_ioremap(struct mvs_info *mvi, int bar, int bar_ex); -void mvs_phys_reset(struct mvs_info *mvi, u32 phy_mask, int hard); -int mvs_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, - void *funcdata); -void __devinit mvs_set_sas_addr(struct mvs_info *mvi, int port_id, - u32 off_lo, u32 off_hi, u64 sas_addr); -void mvs_scan_start(struct Scsi_Host *shost); -int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time); -int mvs_queue_command(struct sas_task *task, const int num, - gfp_t gfp_flags); -int mvs_abort_task(struct sas_task *task); -int mvs_abort_task_set(struct domain_device *dev, u8 *lun); -int mvs_clear_aca(struct domain_device *dev, u8 *lun); -int mvs_clear_task_set(struct domain_device *dev, u8 * lun); -void mvs_port_formed(struct asd_sas_phy *sas_phy); -void mvs_port_deformed(struct asd_sas_phy *sas_phy); -int mvs_dev_found(struct domain_device *dev); -void mvs_dev_gone(struct domain_device *dev); -int mvs_lu_reset(struct domain_device *dev, u8 *lun); -int mvs_slot_complete(struct mvs_info *mvi, u32 rx_desc, u32 flags); -int mvs_I_T_nexus_reset(struct domain_device *dev); -int mvs_query_task(struct sas_task *task); -void mvs_release_task(struct mvs_info *mvi, - struct domain_device *dev); -void mvs_do_release_task(struct mvs_info *mvi, int phy_no, - struct domain_device *dev); -void mvs_int_port(struct mvs_info *mvi, int phy_no, u32 events); -void mvs_update_phyinfo(struct mvs_info *mvi, int i, int get_st); -int mvs_int_rx(struct mvs_info *mvi, bool self_clear); -struct mvs_device *mvs_find_dev_by_reg_set(struct mvs_info *mvi, u8 reg_set); -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/mvumi.c b/ANDROID_3.4.5/drivers/scsi/mvumi.c deleted file mode 100644 index 88cf1db2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvumi.c +++ /dev/null @@ -1,2018 +0,0 @@ -/* - * Marvell UMI driver - * - * Copyright 2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mvumi.h" - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("jyli@marvell.com"); -MODULE_DESCRIPTION("Marvell UMI Driver"); - -static DEFINE_PCI_DEVICE_TABLE(mvumi_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_2, PCI_DEVICE_ID_MARVELL_MV9143) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, mvumi_pci_table); - -static void tag_init(struct mvumi_tag *st, unsigned short size) -{ - unsigned short i; - BUG_ON(size != st->size); - st->top = size; - for (i = 0; i < size; i++) - st->stack[i] = size - 1 - i; -} - -static unsigned short tag_get_one(struct mvumi_hba *mhba, struct mvumi_tag *st) -{ - BUG_ON(st->top <= 0); - return st->stack[--st->top]; -} - -static void tag_release_one(struct mvumi_hba *mhba, struct mvumi_tag *st, - unsigned short tag) -{ - BUG_ON(st->top >= st->size); - st->stack[st->top++] = tag; -} - -static bool tag_is_empty(struct mvumi_tag *st) -{ - if (st->top == 0) - return 1; - else - return 0; -} - -static void mvumi_unmap_pci_addr(struct pci_dev *dev, void **addr_array) -{ - int i; - - for (i = 0; i < MAX_BASE_ADDRESS; i++) - if ((pci_resource_flags(dev, i) & IORESOURCE_MEM) && - addr_array[i]) - pci_iounmap(dev, addr_array[i]); -} - -static int mvumi_map_pci_addr(struct pci_dev *dev, void **addr_array) -{ - int i; - - for (i = 0; i < MAX_BASE_ADDRESS; i++) { - if (pci_resource_flags(dev, i) & IORESOURCE_MEM) { - addr_array[i] = pci_iomap(dev, i, 0); - if (!addr_array[i]) { - dev_err(&dev->dev, "failed to map Bar[%d]\n", - i); - mvumi_unmap_pci_addr(dev, addr_array); - return -ENOMEM; - } - } else - addr_array[i] = NULL; - - dev_dbg(&dev->dev, "Bar %d : %p.\n", i, addr_array[i]); - } - - return 0; -} - -static struct mvumi_res *mvumi_alloc_mem_resource(struct mvumi_hba *mhba, - enum resource_type type, unsigned int size) -{ - struct mvumi_res *res = kzalloc(sizeof(*res), GFP_KERNEL); - - if (!res) { - dev_err(&mhba->pdev->dev, - "Failed to allocate memory for resouce manager.\n"); - return NULL; - } - - switch (type) { - case RESOURCE_CACHED_MEMORY: - res->virt_addr = kzalloc(size, GFP_KERNEL); - if (!res->virt_addr) { - dev_err(&mhba->pdev->dev, - "unable to allocate memory,size = %d.\n", size); - kfree(res); - return NULL; - } - break; - - case RESOURCE_UNCACHED_MEMORY: - size = round_up(size, 8); - res->virt_addr = pci_alloc_consistent(mhba->pdev, size, - &res->bus_addr); - if (!res->virt_addr) { - dev_err(&mhba->pdev->dev, - "unable to allocate consistent mem," - "size = %d.\n", size); - kfree(res); - return NULL; - } - memset(res->virt_addr, 0, size); - break; - - default: - dev_err(&mhba->pdev->dev, "unknown resource type %d.\n", type); - kfree(res); - return NULL; - } - - res->type = type; - res->size = size; - INIT_LIST_HEAD(&res->entry); - list_add_tail(&res->entry, &mhba->res_list); - - return res; -} - -static void mvumi_release_mem_resource(struct mvumi_hba *mhba) -{ - struct mvumi_res *res, *tmp; - - list_for_each_entry_safe(res, tmp, &mhba->res_list, entry) { - switch (res->type) { - case RESOURCE_UNCACHED_MEMORY: - pci_free_consistent(mhba->pdev, res->size, - res->virt_addr, res->bus_addr); - break; - case RESOURCE_CACHED_MEMORY: - kfree(res->virt_addr); - break; - default: - dev_err(&mhba->pdev->dev, - "unknown resource type %d\n", res->type); - break; - } - list_del(&res->entry); - kfree(res); - } - mhba->fw_flag &= ~MVUMI_FW_ALLOC; -} - -/** - * mvumi_make_sgl - Prepares SGL - * @mhba: Adapter soft state - * @scmd: SCSI command from the mid-layer - * @sgl_p: SGL to be filled in - * @sg_count return the number of SG elements - * - * If successful, this function returns 0. otherwise, it returns -1. - */ -static int mvumi_make_sgl(struct mvumi_hba *mhba, struct scsi_cmnd *scmd, - void *sgl_p, unsigned char *sg_count) -{ - struct scatterlist *sg; - struct mvumi_sgl *m_sg = (struct mvumi_sgl *) sgl_p; - unsigned int i; - unsigned int sgnum = scsi_sg_count(scmd); - dma_addr_t busaddr; - - if (sgnum) { - sg = scsi_sglist(scmd); - *sg_count = pci_map_sg(mhba->pdev, sg, sgnum, - (int) scmd->sc_data_direction); - if (*sg_count > mhba->max_sge) { - dev_err(&mhba->pdev->dev, "sg count[0x%x] is bigger " - "than max sg[0x%x].\n", - *sg_count, mhba->max_sge); - return -1; - } - for (i = 0; i < *sg_count; i++) { - busaddr = sg_dma_address(&sg[i]); - m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr)); - m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr)); - m_sg->flags = 0; - m_sg->size = cpu_to_le32(sg_dma_len(&sg[i])); - if ((i + 1) == *sg_count) - m_sg->flags |= SGD_EOT; - - m_sg++; - } - } else { - scmd->SCp.dma_handle = scsi_bufflen(scmd) ? - pci_map_single(mhba->pdev, scsi_sglist(scmd), - scsi_bufflen(scmd), - (int) scmd->sc_data_direction) - : 0; - busaddr = scmd->SCp.dma_handle; - m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(busaddr)); - m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(busaddr)); - m_sg->flags = SGD_EOT; - m_sg->size = cpu_to_le32(scsi_bufflen(scmd)); - *sg_count = 1; - } - - return 0; -} - -static int mvumi_internal_cmd_sgl(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, - unsigned int size) -{ - struct mvumi_sgl *m_sg; - void *virt_addr; - dma_addr_t phy_addr; - - if (size == 0) - return 0; - - virt_addr = pci_alloc_consistent(mhba->pdev, size, &phy_addr); - if (!virt_addr) - return -1; - - memset(virt_addr, 0, size); - - m_sg = (struct mvumi_sgl *) &cmd->frame->payload[0]; - cmd->frame->sg_counts = 1; - cmd->data_buf = virt_addr; - - m_sg->baseaddr_l = cpu_to_le32(lower_32_bits(phy_addr)); - m_sg->baseaddr_h = cpu_to_le32(upper_32_bits(phy_addr)); - m_sg->flags = SGD_EOT; - m_sg->size = cpu_to_le32(size); - - return 0; -} - -static struct mvumi_cmd *mvumi_create_internal_cmd(struct mvumi_hba *mhba, - unsigned int buf_size) -{ - struct mvumi_cmd *cmd; - - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) { - dev_err(&mhba->pdev->dev, "failed to create a internal cmd\n"); - return NULL; - } - INIT_LIST_HEAD(&cmd->queue_pointer); - - cmd->frame = kzalloc(mhba->ib_max_size, GFP_KERNEL); - if (!cmd->frame) { - dev_err(&mhba->pdev->dev, "failed to allocate memory for FW" - " frame,size = %d.\n", mhba->ib_max_size); - kfree(cmd); - return NULL; - } - - if (buf_size) { - if (mvumi_internal_cmd_sgl(mhba, cmd, buf_size)) { - dev_err(&mhba->pdev->dev, "failed to allocate memory" - " for internal frame\n"); - kfree(cmd->frame); - kfree(cmd); - return NULL; - } - } else - cmd->frame->sg_counts = 0; - - return cmd; -} - -static void mvumi_delete_internal_cmd(struct mvumi_hba *mhba, - struct mvumi_cmd *cmd) -{ - struct mvumi_sgl *m_sg; - unsigned int size; - dma_addr_t phy_addr; - - if (cmd && cmd->frame) { - if (cmd->frame->sg_counts) { - m_sg = (struct mvumi_sgl *) &cmd->frame->payload[0]; - size = m_sg->size; - - phy_addr = (dma_addr_t) m_sg->baseaddr_l | - (dma_addr_t) ((m_sg->baseaddr_h << 16) << 16); - - pci_free_consistent(mhba->pdev, size, cmd->data_buf, - phy_addr); - } - kfree(cmd->frame); - kfree(cmd); - } -} - -/** - * mvumi_get_cmd - Get a command from the free pool - * @mhba: Adapter soft state - * - * Returns a free command from the pool - */ -static struct mvumi_cmd *mvumi_get_cmd(struct mvumi_hba *mhba) -{ - struct mvumi_cmd *cmd = NULL; - - if (likely(!list_empty(&mhba->cmd_pool))) { - cmd = list_entry((&mhba->cmd_pool)->next, - struct mvumi_cmd, queue_pointer); - list_del_init(&cmd->queue_pointer); - } else - dev_warn(&mhba->pdev->dev, "command pool is empty!\n"); - - return cmd; -} - -/** - * mvumi_return_cmd - Return a cmd to free command pool - * @mhba: Adapter soft state - * @cmd: Command packet to be returned to free command pool - */ -static inline void mvumi_return_cmd(struct mvumi_hba *mhba, - struct mvumi_cmd *cmd) -{ - cmd->scmd = NULL; - list_add_tail(&cmd->queue_pointer, &mhba->cmd_pool); -} - -/** - * mvumi_free_cmds - Free all the cmds in the free cmd pool - * @mhba: Adapter soft state - */ -static void mvumi_free_cmds(struct mvumi_hba *mhba) -{ - struct mvumi_cmd *cmd; - - while (!list_empty(&mhba->cmd_pool)) { - cmd = list_first_entry(&mhba->cmd_pool, struct mvumi_cmd, - queue_pointer); - list_del(&cmd->queue_pointer); - kfree(cmd->frame); - kfree(cmd); - } -} - -/** - * mvumi_alloc_cmds - Allocates the command packets - * @mhba: Adapter soft state - * - */ -static int mvumi_alloc_cmds(struct mvumi_hba *mhba) -{ - int i; - struct mvumi_cmd *cmd; - - for (i = 0; i < mhba->max_io; i++) { - cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); - if (!cmd) - goto err_exit; - - INIT_LIST_HEAD(&cmd->queue_pointer); - list_add_tail(&cmd->queue_pointer, &mhba->cmd_pool); - cmd->frame = kzalloc(mhba->ib_max_size, GFP_KERNEL); - if (!cmd->frame) - goto err_exit; - } - return 0; - -err_exit: - dev_err(&mhba->pdev->dev, - "failed to allocate memory for cmd[0x%x].\n", i); - while (!list_empty(&mhba->cmd_pool)) { - cmd = list_first_entry(&mhba->cmd_pool, struct mvumi_cmd, - queue_pointer); - list_del(&cmd->queue_pointer); - kfree(cmd->frame); - kfree(cmd); - } - return -ENOMEM; -} - -static int mvumi_get_ib_list_entry(struct mvumi_hba *mhba, void **ib_entry) -{ - unsigned int ib_rp_reg, cur_ib_entry; - - if (atomic_read(&mhba->fw_outstanding) >= mhba->max_io) { - dev_warn(&mhba->pdev->dev, "firmware io overflow.\n"); - return -1; - } - ib_rp_reg = ioread32(mhba->mmio + CLA_INB_READ_POINTER); - - if (unlikely(((ib_rp_reg & CL_SLOT_NUM_MASK) == - (mhba->ib_cur_slot & CL_SLOT_NUM_MASK)) && - ((ib_rp_reg & CL_POINTER_TOGGLE) != - (mhba->ib_cur_slot & CL_POINTER_TOGGLE)))) { - dev_warn(&mhba->pdev->dev, "no free slot to use.\n"); - return -1; - } - - cur_ib_entry = mhba->ib_cur_slot & CL_SLOT_NUM_MASK; - cur_ib_entry++; - if (cur_ib_entry >= mhba->list_num_io) { - cur_ib_entry -= mhba->list_num_io; - mhba->ib_cur_slot ^= CL_POINTER_TOGGLE; - } - mhba->ib_cur_slot &= ~CL_SLOT_NUM_MASK; - mhba->ib_cur_slot |= (cur_ib_entry & CL_SLOT_NUM_MASK); - *ib_entry = mhba->ib_list + cur_ib_entry * mhba->ib_max_size; - atomic_inc(&mhba->fw_outstanding); - - return 0; -} - -static void mvumi_send_ib_list_entry(struct mvumi_hba *mhba) -{ - iowrite32(0xfff, mhba->ib_shadow); - iowrite32(mhba->ib_cur_slot, mhba->mmio + CLA_INB_WRITE_POINTER); -} - -static char mvumi_check_ob_frame(struct mvumi_hba *mhba, - unsigned int cur_obf, struct mvumi_rsp_frame *p_outb_frame) -{ - unsigned short tag, request_id; - - udelay(1); - p_outb_frame = mhba->ob_list + cur_obf * mhba->ob_max_size; - request_id = p_outb_frame->request_id; - tag = p_outb_frame->tag; - if (tag > mhba->tag_pool.size) { - dev_err(&mhba->pdev->dev, "ob frame data error\n"); - return -1; - } - if (mhba->tag_cmd[tag] == NULL) { - dev_err(&mhba->pdev->dev, "tag[0x%x] with NO command\n", tag); - return -1; - } else if (mhba->tag_cmd[tag]->request_id != request_id && - mhba->request_id_enabled) { - dev_err(&mhba->pdev->dev, "request ID from FW:0x%x," - "cmd request ID:0x%x\n", request_id, - mhba->tag_cmd[tag]->request_id); - return -1; - } - - return 0; -} - -static void mvumi_receive_ob_list_entry(struct mvumi_hba *mhba) -{ - unsigned int ob_write_reg, ob_write_shadow_reg; - unsigned int cur_obf, assign_obf_end, i; - struct mvumi_ob_data *ob_data; - struct mvumi_rsp_frame *p_outb_frame; - - do { - ob_write_reg = ioread32(mhba->mmio + CLA_OUTB_COPY_POINTER); - ob_write_shadow_reg = ioread32(mhba->ob_shadow); - } while ((ob_write_reg & CL_SLOT_NUM_MASK) != ob_write_shadow_reg); - - cur_obf = mhba->ob_cur_slot & CL_SLOT_NUM_MASK; - assign_obf_end = ob_write_reg & CL_SLOT_NUM_MASK; - - if ((ob_write_reg & CL_POINTER_TOGGLE) != - (mhba->ob_cur_slot & CL_POINTER_TOGGLE)) { - assign_obf_end += mhba->list_num_io; - } - - for (i = (assign_obf_end - cur_obf); i != 0; i--) { - cur_obf++; - if (cur_obf >= mhba->list_num_io) { - cur_obf -= mhba->list_num_io; - mhba->ob_cur_slot ^= CL_POINTER_TOGGLE; - } - - p_outb_frame = mhba->ob_list + cur_obf * mhba->ob_max_size; - - /* Copy pointer may point to entry in outbound list - * before entry has valid data - */ - if (unlikely(p_outb_frame->tag > mhba->tag_pool.size || - mhba->tag_cmd[p_outb_frame->tag] == NULL || - p_outb_frame->request_id != - mhba->tag_cmd[p_outb_frame->tag]->request_id)) - if (mvumi_check_ob_frame(mhba, cur_obf, p_outb_frame)) - continue; - - if (!list_empty(&mhba->ob_data_list)) { - ob_data = (struct mvumi_ob_data *) - list_first_entry(&mhba->ob_data_list, - struct mvumi_ob_data, list); - list_del_init(&ob_data->list); - } else { - ob_data = NULL; - if (cur_obf == 0) { - cur_obf = mhba->list_num_io - 1; - mhba->ob_cur_slot ^= CL_POINTER_TOGGLE; - } else - cur_obf -= 1; - break; - } - - memcpy(ob_data->data, p_outb_frame, mhba->ob_max_size); - p_outb_frame->tag = 0xff; - - list_add_tail(&ob_data->list, &mhba->free_ob_list); - } - mhba->ob_cur_slot &= ~CL_SLOT_NUM_MASK; - mhba->ob_cur_slot |= (cur_obf & CL_SLOT_NUM_MASK); - iowrite32(mhba->ob_cur_slot, mhba->mmio + CLA_OUTB_READ_POINTER); -} - -static void mvumi_reset(void *regs) -{ - iowrite32(0, regs + CPU_ENPOINTA_MASK_REG); - if (ioread32(regs + CPU_ARM_TO_PCIEA_MSG1) != HANDSHAKE_DONESTATE) - return; - - iowrite32(DRBL_SOFT_RESET, regs + CPU_PCIEA_TO_ARM_DRBL_REG); -} - -static unsigned char mvumi_start(struct mvumi_hba *mhba); - -static int mvumi_wait_for_outstanding(struct mvumi_hba *mhba) -{ - mhba->fw_state = FW_STATE_ABORT; - mvumi_reset(mhba->mmio); - - if (mvumi_start(mhba)) - return FAILED; - else - return SUCCESS; -} - -static int mvumi_host_reset(struct scsi_cmnd *scmd) -{ - struct mvumi_hba *mhba; - - mhba = (struct mvumi_hba *) scmd->device->host->hostdata; - - scmd_printk(KERN_NOTICE, scmd, "RESET -%ld cmd=%x retries=%x\n", - scmd->serial_number, scmd->cmnd[0], scmd->retries); - - return mvumi_wait_for_outstanding(mhba); -} - -static int mvumi_issue_blocked_cmd(struct mvumi_hba *mhba, - struct mvumi_cmd *cmd) -{ - unsigned long flags; - - cmd->cmd_status = REQ_STATUS_PENDING; - - if (atomic_read(&cmd->sync_cmd)) { - dev_err(&mhba->pdev->dev, - "last blocked cmd not finished, sync_cmd = %d\n", - atomic_read(&cmd->sync_cmd)); - BUG_ON(1); - return -1; - } - atomic_inc(&cmd->sync_cmd); - spin_lock_irqsave(mhba->shost->host_lock, flags); - mhba->instancet->fire_cmd(mhba, cmd); - spin_unlock_irqrestore(mhba->shost->host_lock, flags); - - wait_event_timeout(mhba->int_cmd_wait_q, - (cmd->cmd_status != REQ_STATUS_PENDING), - MVUMI_INTERNAL_CMD_WAIT_TIME * HZ); - - /* command timeout */ - if (atomic_read(&cmd->sync_cmd)) { - spin_lock_irqsave(mhba->shost->host_lock, flags); - atomic_dec(&cmd->sync_cmd); - if (mhba->tag_cmd[cmd->frame->tag]) { - mhba->tag_cmd[cmd->frame->tag] = 0; - dev_warn(&mhba->pdev->dev, "TIMEOUT:release tag [%d]\n", - cmd->frame->tag); - tag_release_one(mhba, &mhba->tag_pool, cmd->frame->tag); - } - if (!list_empty(&cmd->queue_pointer)) { - dev_warn(&mhba->pdev->dev, - "TIMEOUT:A internal command doesn't send!\n"); - list_del_init(&cmd->queue_pointer); - } else - atomic_dec(&mhba->fw_outstanding); - - spin_unlock_irqrestore(mhba->shost->host_lock, flags); - } - return 0; -} - -static void mvumi_release_fw(struct mvumi_hba *mhba) -{ - mvumi_free_cmds(mhba); - mvumi_release_mem_resource(mhba); - mvumi_unmap_pci_addr(mhba->pdev, mhba->base_addr); - kfree(mhba->handshake_page); - pci_release_regions(mhba->pdev); -} - -static unsigned char mvumi_flush_cache(struct mvumi_hba *mhba) -{ - struct mvumi_cmd *cmd; - struct mvumi_msg_frame *frame; - unsigned char device_id, retry = 0; - unsigned char bitcount = sizeof(unsigned char) * 8; - - for (device_id = 0; device_id < mhba->max_target_id; device_id++) { - if (!(mhba->target_map[device_id / bitcount] & - (1 << (device_id % bitcount)))) - continue; -get_cmd: cmd = mvumi_create_internal_cmd(mhba, 0); - if (!cmd) { - if (retry++ >= 5) { - dev_err(&mhba->pdev->dev, "failed to get memory" - " for internal flush cache cmd for " - "device %d", device_id); - retry = 0; - continue; - } else - goto get_cmd; - } - cmd->scmd = NULL; - cmd->cmd_status = REQ_STATUS_PENDING; - atomic_set(&cmd->sync_cmd, 0); - frame = cmd->frame; - frame->req_function = CL_FUN_SCSI_CMD; - frame->device_id = device_id; - frame->cmd_flag = CMD_FLAG_NON_DATA; - frame->data_transfer_length = 0; - frame->cdb_length = MAX_COMMAND_SIZE; - memset(frame->cdb, 0, MAX_COMMAND_SIZE); - frame->cdb[0] = SCSI_CMD_MARVELL_SPECIFIC; - frame->cdb[2] = CDB_CORE_SHUTDOWN; - - mvumi_issue_blocked_cmd(mhba, cmd); - if (cmd->cmd_status != SAM_STAT_GOOD) { - dev_err(&mhba->pdev->dev, - "device %d flush cache failed, status=0x%x.\n", - device_id, cmd->cmd_status); - } - - mvumi_delete_internal_cmd(mhba, cmd); - } - return 0; -} - -static unsigned char -mvumi_calculate_checksum(struct mvumi_hs_header *p_header, - unsigned short len) -{ - unsigned char *ptr; - unsigned char ret = 0, i; - - ptr = (unsigned char *) p_header->frame_content; - for (i = 0; i < len; i++) { - ret ^= *ptr; - ptr++; - } - - return ret; -} - -void mvumi_hs_build_page(struct mvumi_hba *mhba, - struct mvumi_hs_header *hs_header) -{ - struct mvumi_hs_page2 *hs_page2; - struct mvumi_hs_page4 *hs_page4; - struct mvumi_hs_page3 *hs_page3; - struct timeval time; - unsigned int local_time; - - switch (hs_header->page_code) { - case HS_PAGE_HOST_INFO: - hs_page2 = (struct mvumi_hs_page2 *) hs_header; - hs_header->frame_length = sizeof(*hs_page2) - 4; - memset(hs_header->frame_content, 0, hs_header->frame_length); - hs_page2->host_type = 3; /* 3 mean linux*/ - hs_page2->host_ver.ver_major = VER_MAJOR; - hs_page2->host_ver.ver_minor = VER_MINOR; - hs_page2->host_ver.ver_oem = VER_OEM; - hs_page2->host_ver.ver_build = VER_BUILD; - hs_page2->system_io_bus = 0; - hs_page2->slot_number = 0; - hs_page2->intr_level = 0; - hs_page2->intr_vector = 0; - do_gettimeofday(&time); - local_time = (unsigned int) (time.tv_sec - - (sys_tz.tz_minuteswest * 60)); - hs_page2->seconds_since1970 = local_time; - hs_header->checksum = mvumi_calculate_checksum(hs_header, - hs_header->frame_length); - break; - - case HS_PAGE_FIRM_CTL: - hs_page3 = (struct mvumi_hs_page3 *) hs_header; - hs_header->frame_length = sizeof(*hs_page3) - 4; - memset(hs_header->frame_content, 0, hs_header->frame_length); - hs_header->checksum = mvumi_calculate_checksum(hs_header, - hs_header->frame_length); - break; - - case HS_PAGE_CL_INFO: - hs_page4 = (struct mvumi_hs_page4 *) hs_header; - hs_header->frame_length = sizeof(*hs_page4) - 4; - memset(hs_header->frame_content, 0, hs_header->frame_length); - hs_page4->ib_baseaddr_l = lower_32_bits(mhba->ib_list_phys); - hs_page4->ib_baseaddr_h = upper_32_bits(mhba->ib_list_phys); - - hs_page4->ob_baseaddr_l = lower_32_bits(mhba->ob_list_phys); - hs_page4->ob_baseaddr_h = upper_32_bits(mhba->ob_list_phys); - hs_page4->ib_entry_size = mhba->ib_max_size_setting; - hs_page4->ob_entry_size = mhba->ob_max_size_setting; - hs_page4->ob_depth = mhba->list_num_io; - hs_page4->ib_depth = mhba->list_num_io; - hs_header->checksum = mvumi_calculate_checksum(hs_header, - hs_header->frame_length); - break; - - default: - dev_err(&mhba->pdev->dev, "cannot build page, code[0x%x]\n", - hs_header->page_code); - break; - } -} - -/** - * mvumi_init_data - Initialize requested date for FW - * @mhba: Adapter soft state - */ -static int mvumi_init_data(struct mvumi_hba *mhba) -{ - struct mvumi_ob_data *ob_pool; - struct mvumi_res *res_mgnt; - unsigned int tmp_size, offset, i; - void *virmem, *v; - dma_addr_t p; - - if (mhba->fw_flag & MVUMI_FW_ALLOC) - return 0; - - tmp_size = mhba->ib_max_size * mhba->max_io; - tmp_size += 128 + mhba->ob_max_size * mhba->max_io; - tmp_size += 8 + sizeof(u32) + 16; - - res_mgnt = mvumi_alloc_mem_resource(mhba, - RESOURCE_UNCACHED_MEMORY, tmp_size); - if (!res_mgnt) { - dev_err(&mhba->pdev->dev, - "failed to allocate memory for inbound list\n"); - goto fail_alloc_dma_buf; - } - - p = res_mgnt->bus_addr; - v = res_mgnt->virt_addr; - /* ib_list */ - offset = round_up(p, 128) - p; - p += offset; - v += offset; - mhba->ib_list = v; - mhba->ib_list_phys = p; - v += mhba->ib_max_size * mhba->max_io; - p += mhba->ib_max_size * mhba->max_io; - /* ib shadow */ - offset = round_up(p, 8) - p; - p += offset; - v += offset; - mhba->ib_shadow = v; - mhba->ib_shadow_phys = p; - p += sizeof(u32); - v += sizeof(u32); - /* ob shadow */ - offset = round_up(p, 8) - p; - p += offset; - v += offset; - mhba->ob_shadow = v; - mhba->ob_shadow_phys = p; - p += 8; - v += 8; - - /* ob list */ - offset = round_up(p, 128) - p; - p += offset; - v += offset; - - mhba->ob_list = v; - mhba->ob_list_phys = p; - - /* ob data pool */ - tmp_size = mhba->max_io * (mhba->ob_max_size + sizeof(*ob_pool)); - tmp_size = round_up(tmp_size, 8); - - res_mgnt = mvumi_alloc_mem_resource(mhba, - RESOURCE_CACHED_MEMORY, tmp_size); - if (!res_mgnt) { - dev_err(&mhba->pdev->dev, - "failed to allocate memory for outbound data buffer\n"); - goto fail_alloc_dma_buf; - } - virmem = res_mgnt->virt_addr; - - for (i = mhba->max_io; i != 0; i--) { - ob_pool = (struct mvumi_ob_data *) virmem; - list_add_tail(&ob_pool->list, &mhba->ob_data_list); - virmem += mhba->ob_max_size + sizeof(*ob_pool); - } - - tmp_size = sizeof(unsigned short) * mhba->max_io + - sizeof(struct mvumi_cmd *) * mhba->max_io; - tmp_size += round_up(mhba->max_target_id, sizeof(unsigned char) * 8) / - (sizeof(unsigned char) * 8); - - res_mgnt = mvumi_alloc_mem_resource(mhba, - RESOURCE_CACHED_MEMORY, tmp_size); - if (!res_mgnt) { - dev_err(&mhba->pdev->dev, - "failed to allocate memory for tag and target map\n"); - goto fail_alloc_dma_buf; - } - - virmem = res_mgnt->virt_addr; - mhba->tag_pool.stack = virmem; - mhba->tag_pool.size = mhba->max_io; - tag_init(&mhba->tag_pool, mhba->max_io); - virmem += sizeof(unsigned short) * mhba->max_io; - - mhba->tag_cmd = virmem; - virmem += sizeof(struct mvumi_cmd *) * mhba->max_io; - - mhba->target_map = virmem; - - mhba->fw_flag |= MVUMI_FW_ALLOC; - return 0; - -fail_alloc_dma_buf: - mvumi_release_mem_resource(mhba); - return -1; -} - -static int mvumi_hs_process_page(struct mvumi_hba *mhba, - struct mvumi_hs_header *hs_header) -{ - struct mvumi_hs_page1 *hs_page1; - unsigned char page_checksum; - - page_checksum = mvumi_calculate_checksum(hs_header, - hs_header->frame_length); - if (page_checksum != hs_header->checksum) { - dev_err(&mhba->pdev->dev, "checksum error\n"); - return -1; - } - - switch (hs_header->page_code) { - case HS_PAGE_FIRM_CAP: - hs_page1 = (struct mvumi_hs_page1 *) hs_header; - - mhba->max_io = hs_page1->max_io_support; - mhba->list_num_io = hs_page1->cl_inout_list_depth; - mhba->max_transfer_size = hs_page1->max_transfer_size; - mhba->max_target_id = hs_page1->max_devices_support; - mhba->hba_capability = hs_page1->capability; - mhba->ib_max_size_setting = hs_page1->cl_in_max_entry_size; - mhba->ib_max_size = (1 << hs_page1->cl_in_max_entry_size) << 2; - - mhba->ob_max_size_setting = hs_page1->cl_out_max_entry_size; - mhba->ob_max_size = (1 << hs_page1->cl_out_max_entry_size) << 2; - - dev_dbg(&mhba->pdev->dev, "FW version:%d\n", - hs_page1->fw_ver.ver_build); - - break; - default: - dev_err(&mhba->pdev->dev, "handshake: page code error\n"); - return -1; - } - return 0; -} - -/** - * mvumi_handshake - Move the FW to READY state - * @mhba: Adapter soft state - * - * During the initialization, FW passes can potentially be in any one of - * several possible states. If the FW in operational, waiting-for-handshake - * states, driver must take steps to bring it to ready state. Otherwise, it - * has to wait for the ready state. - */ -static int mvumi_handshake(struct mvumi_hba *mhba) -{ - unsigned int hs_state, tmp, hs_fun; - struct mvumi_hs_header *hs_header; - void *regs = mhba->mmio; - - if (mhba->fw_state == FW_STATE_STARTING) - hs_state = HS_S_START; - else { - tmp = ioread32(regs + CPU_ARM_TO_PCIEA_MSG0); - hs_state = HS_GET_STATE(tmp); - dev_dbg(&mhba->pdev->dev, "handshake state[0x%x].\n", hs_state); - if (HS_GET_STATUS(tmp) != HS_STATUS_OK) { - mhba->fw_state = FW_STATE_STARTING; - return -1; - } - } - - hs_fun = 0; - switch (hs_state) { - case HS_S_START: - mhba->fw_state = FW_STATE_HANDSHAKING; - HS_SET_STATUS(hs_fun, HS_STATUS_OK); - HS_SET_STATE(hs_fun, HS_S_RESET); - iowrite32(HANDSHAKE_SIGNATURE, regs + CPU_PCIEA_TO_ARM_MSG1); - iowrite32(hs_fun, regs + CPU_PCIEA_TO_ARM_MSG0); - iowrite32(DRBL_HANDSHAKE, regs + CPU_PCIEA_TO_ARM_DRBL_REG); - break; - - case HS_S_RESET: - iowrite32(lower_32_bits(mhba->handshake_page_phys), - regs + CPU_PCIEA_TO_ARM_MSG1); - iowrite32(upper_32_bits(mhba->handshake_page_phys), - regs + CPU_ARM_TO_PCIEA_MSG1); - HS_SET_STATUS(hs_fun, HS_STATUS_OK); - HS_SET_STATE(hs_fun, HS_S_PAGE_ADDR); - iowrite32(hs_fun, regs + CPU_PCIEA_TO_ARM_MSG0); - iowrite32(DRBL_HANDSHAKE, regs + CPU_PCIEA_TO_ARM_DRBL_REG); - - break; - - case HS_S_PAGE_ADDR: - case HS_S_QUERY_PAGE: - case HS_S_SEND_PAGE: - hs_header = (struct mvumi_hs_header *) mhba->handshake_page; - if (hs_header->page_code == HS_PAGE_FIRM_CAP) { - mhba->hba_total_pages = - ((struct mvumi_hs_page1 *) hs_header)->total_pages; - - if (mhba->hba_total_pages == 0) - mhba->hba_total_pages = HS_PAGE_TOTAL-1; - } - - if (hs_state == HS_S_QUERY_PAGE) { - if (mvumi_hs_process_page(mhba, hs_header)) { - HS_SET_STATE(hs_fun, HS_S_ABORT); - return -1; - } - if (mvumi_init_data(mhba)) { - HS_SET_STATE(hs_fun, HS_S_ABORT); - return -1; - } - } else if (hs_state == HS_S_PAGE_ADDR) { - hs_header->page_code = 0; - mhba->hba_total_pages = HS_PAGE_TOTAL-1; - } - - if ((hs_header->page_code + 1) <= mhba->hba_total_pages) { - hs_header->page_code++; - if (hs_header->page_code != HS_PAGE_FIRM_CAP) { - mvumi_hs_build_page(mhba, hs_header); - HS_SET_STATE(hs_fun, HS_S_SEND_PAGE); - } else - HS_SET_STATE(hs_fun, HS_S_QUERY_PAGE); - } else - HS_SET_STATE(hs_fun, HS_S_END); - - HS_SET_STATUS(hs_fun, HS_STATUS_OK); - iowrite32(hs_fun, regs + CPU_PCIEA_TO_ARM_MSG0); - iowrite32(DRBL_HANDSHAKE, regs + CPU_PCIEA_TO_ARM_DRBL_REG); - break; - - case HS_S_END: - /* Set communication list ISR */ - tmp = ioread32(regs + CPU_ENPOINTA_MASK_REG); - tmp |= INT_MAP_COMAOUT | INT_MAP_COMAERR; - iowrite32(tmp, regs + CPU_ENPOINTA_MASK_REG); - iowrite32(mhba->list_num_io, mhba->ib_shadow); - /* Set InBound List Avaliable count shadow */ - iowrite32(lower_32_bits(mhba->ib_shadow_phys), - regs + CLA_INB_AVAL_COUNT_BASEL); - iowrite32(upper_32_bits(mhba->ib_shadow_phys), - regs + CLA_INB_AVAL_COUNT_BASEH); - - /* Set OutBound List Avaliable count shadow */ - iowrite32((mhba->list_num_io-1) | CL_POINTER_TOGGLE, - mhba->ob_shadow); - iowrite32(lower_32_bits(mhba->ob_shadow_phys), regs + 0x5B0); - iowrite32(upper_32_bits(mhba->ob_shadow_phys), regs + 0x5B4); - - mhba->ib_cur_slot = (mhba->list_num_io - 1) | CL_POINTER_TOGGLE; - mhba->ob_cur_slot = (mhba->list_num_io - 1) | CL_POINTER_TOGGLE; - mhba->fw_state = FW_STATE_STARTED; - - break; - default: - dev_err(&mhba->pdev->dev, "unknown handshake state [0x%x].\n", - hs_state); - return -1; - } - return 0; -} - -static unsigned char mvumi_handshake_event(struct mvumi_hba *mhba) -{ - unsigned int isr_status; - unsigned long before; - - before = jiffies; - mvumi_handshake(mhba); - do { - isr_status = mhba->instancet->read_fw_status_reg(mhba->mmio); - - if (mhba->fw_state == FW_STATE_STARTED) - return 0; - if (time_after(jiffies, before + FW_MAX_DELAY * HZ)) { - dev_err(&mhba->pdev->dev, - "no handshake response at state 0x%x.\n", - mhba->fw_state); - dev_err(&mhba->pdev->dev, - "isr : global=0x%x,status=0x%x.\n", - mhba->global_isr, isr_status); - return -1; - } - rmb(); - usleep_range(1000, 2000); - } while (!(isr_status & DRBL_HANDSHAKE_ISR)); - - return 0; -} - -static unsigned char mvumi_check_handshake(struct mvumi_hba *mhba) -{ - void *regs = mhba->mmio; - unsigned int tmp; - unsigned long before; - - before = jiffies; - tmp = ioread32(regs + CPU_ARM_TO_PCIEA_MSG1); - while ((tmp != HANDSHAKE_READYSTATE) && (tmp != HANDSHAKE_DONESTATE)) { - if (tmp != HANDSHAKE_READYSTATE) - iowrite32(DRBL_MU_RESET, - regs + CPU_PCIEA_TO_ARM_DRBL_REG); - if (time_after(jiffies, before + FW_MAX_DELAY * HZ)) { - dev_err(&mhba->pdev->dev, - "invalid signature [0x%x].\n", tmp); - return -1; - } - usleep_range(1000, 2000); - rmb(); - tmp = ioread32(regs + CPU_ARM_TO_PCIEA_MSG1); - } - - mhba->fw_state = FW_STATE_STARTING; - dev_dbg(&mhba->pdev->dev, "start firmware handshake...\n"); - do { - if (mvumi_handshake_event(mhba)) { - dev_err(&mhba->pdev->dev, - "handshake failed at state 0x%x.\n", - mhba->fw_state); - return -1; - } - } while (mhba->fw_state != FW_STATE_STARTED); - - dev_dbg(&mhba->pdev->dev, "firmware handshake done\n"); - - return 0; -} - -static unsigned char mvumi_start(struct mvumi_hba *mhba) -{ - void *regs = mhba->mmio; - unsigned int tmp; - /* clear Door bell */ - tmp = ioread32(regs + CPU_ARM_TO_PCIEA_DRBL_REG); - iowrite32(tmp, regs + CPU_ARM_TO_PCIEA_DRBL_REG); - - iowrite32(0x3FFFFFFF, regs + CPU_ARM_TO_PCIEA_MASK_REG); - tmp = ioread32(regs + CPU_ENPOINTA_MASK_REG) | INT_MAP_DL_CPU2PCIEA; - iowrite32(tmp, regs + CPU_ENPOINTA_MASK_REG); - if (mvumi_check_handshake(mhba)) - return -1; - - return 0; -} - -/** - * mvumi_complete_cmd - Completes a command - * @mhba: Adapter soft state - * @cmd: Command to be completed - */ -static void mvumi_complete_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd, - struct mvumi_rsp_frame *ob_frame) -{ - struct scsi_cmnd *scmd = cmd->scmd; - - cmd->scmd->SCp.ptr = NULL; - scmd->result = ob_frame->req_status; - - switch (ob_frame->req_status) { - case SAM_STAT_GOOD: - scmd->result |= DID_OK << 16; - break; - case SAM_STAT_BUSY: - scmd->result |= DID_BUS_BUSY << 16; - break; - case SAM_STAT_CHECK_CONDITION: - scmd->result |= (DID_OK << 16); - if (ob_frame->rsp_flag & CL_RSP_FLAG_SENSEDATA) { - memcpy(cmd->scmd->sense_buffer, ob_frame->payload, - sizeof(struct mvumi_sense_data)); - scmd->result |= (DRIVER_SENSE << 24); - } - break; - default: - scmd->result |= (DRIVER_INVALID << 24) | (DID_ABORT << 16); - break; - } - - if (scsi_bufflen(scmd)) { - if (scsi_sg_count(scmd)) { - pci_unmap_sg(mhba->pdev, - scsi_sglist(scmd), - scsi_sg_count(scmd), - (int) scmd->sc_data_direction); - } else { - pci_unmap_single(mhba->pdev, - scmd->SCp.dma_handle, - scsi_bufflen(scmd), - (int) scmd->sc_data_direction); - - scmd->SCp.dma_handle = 0; - } - } - cmd->scmd->scsi_done(scmd); - mvumi_return_cmd(mhba, cmd); -} -static void mvumi_complete_internal_cmd(struct mvumi_hba *mhba, - struct mvumi_cmd *cmd, - struct mvumi_rsp_frame *ob_frame) -{ - if (atomic_read(&cmd->sync_cmd)) { - cmd->cmd_status = ob_frame->req_status; - - if ((ob_frame->req_status == SAM_STAT_CHECK_CONDITION) && - (ob_frame->rsp_flag & CL_RSP_FLAG_SENSEDATA) && - cmd->data_buf) { - memcpy(cmd->data_buf, ob_frame->payload, - sizeof(struct mvumi_sense_data)); - } - atomic_dec(&cmd->sync_cmd); - wake_up(&mhba->int_cmd_wait_q); - } -} - -static void mvumi_show_event(struct mvumi_hba *mhba, - struct mvumi_driver_event *ptr) -{ - unsigned int i; - - dev_warn(&mhba->pdev->dev, - "Event[0x%x] id[0x%x] severity[0x%x] device id[0x%x]\n", - ptr->sequence_no, ptr->event_id, ptr->severity, ptr->device_id); - if (ptr->param_count) { - printk(KERN_WARNING "Event param(len 0x%x): ", - ptr->param_count); - for (i = 0; i < ptr->param_count; i++) - printk(KERN_WARNING "0x%x ", ptr->params[i]); - - printk(KERN_WARNING "\n"); - } - - if (ptr->sense_data_length) { - printk(KERN_WARNING "Event sense data(len 0x%x): ", - ptr->sense_data_length); - for (i = 0; i < ptr->sense_data_length; i++) - printk(KERN_WARNING "0x%x ", ptr->sense_data[i]); - printk(KERN_WARNING "\n"); - } -} - -static void mvumi_notification(struct mvumi_hba *mhba, u8 msg, void *buffer) -{ - if (msg == APICDB1_EVENT_GETEVENT) { - int i, count; - struct mvumi_driver_event *param = NULL; - struct mvumi_event_req *er = buffer; - count = er->count; - if (count > MAX_EVENTS_RETURNED) { - dev_err(&mhba->pdev->dev, "event count[0x%x] is bigger" - " than max event count[0x%x].\n", - count, MAX_EVENTS_RETURNED); - return; - } - for (i = 0; i < count; i++) { - param = &er->events[i]; - mvumi_show_event(mhba, param); - } - } -} - -static int mvumi_get_event(struct mvumi_hba *mhba, unsigned char msg) -{ - struct mvumi_cmd *cmd; - struct mvumi_msg_frame *frame; - - cmd = mvumi_create_internal_cmd(mhba, 512); - if (!cmd) - return -1; - cmd->scmd = NULL; - cmd->cmd_status = REQ_STATUS_PENDING; - atomic_set(&cmd->sync_cmd, 0); - frame = cmd->frame; - frame->device_id = 0; - frame->cmd_flag = CMD_FLAG_DATA_IN; - frame->req_function = CL_FUN_SCSI_CMD; - frame->cdb_length = MAX_COMMAND_SIZE; - frame->data_transfer_length = sizeof(struct mvumi_event_req); - memset(frame->cdb, 0, MAX_COMMAND_SIZE); - frame->cdb[0] = APICDB0_EVENT; - frame->cdb[1] = msg; - mvumi_issue_blocked_cmd(mhba, cmd); - - if (cmd->cmd_status != SAM_STAT_GOOD) - dev_err(&mhba->pdev->dev, "get event failed, status=0x%x.\n", - cmd->cmd_status); - else - mvumi_notification(mhba, cmd->frame->cdb[1], cmd->data_buf); - - mvumi_delete_internal_cmd(mhba, cmd); - return 0; -} - -static void mvumi_scan_events(struct work_struct *work) -{ - struct mvumi_events_wq *mu_ev = - container_of(work, struct mvumi_events_wq, work_q); - - mvumi_get_event(mu_ev->mhba, mu_ev->event); - kfree(mu_ev); -} - -static void mvumi_launch_events(struct mvumi_hba *mhba, u8 msg) -{ - struct mvumi_events_wq *mu_ev; - - mu_ev = kzalloc(sizeof(*mu_ev), GFP_ATOMIC); - if (mu_ev) { - INIT_WORK(&mu_ev->work_q, mvumi_scan_events); - mu_ev->mhba = mhba; - mu_ev->event = msg; - mu_ev->param = NULL; - schedule_work(&mu_ev->work_q); - } -} - -static void mvumi_handle_clob(struct mvumi_hba *mhba) -{ - struct mvumi_rsp_frame *ob_frame; - struct mvumi_cmd *cmd; - struct mvumi_ob_data *pool; - - while (!list_empty(&mhba->free_ob_list)) { - pool = list_first_entry(&mhba->free_ob_list, - struct mvumi_ob_data, list); - list_del_init(&pool->list); - list_add_tail(&pool->list, &mhba->ob_data_list); - - ob_frame = (struct mvumi_rsp_frame *) &pool->data[0]; - cmd = mhba->tag_cmd[ob_frame->tag]; - - atomic_dec(&mhba->fw_outstanding); - mhba->tag_cmd[ob_frame->tag] = 0; - tag_release_one(mhba, &mhba->tag_pool, ob_frame->tag); - if (cmd->scmd) - mvumi_complete_cmd(mhba, cmd, ob_frame); - else - mvumi_complete_internal_cmd(mhba, cmd, ob_frame); - } - mhba->instancet->fire_cmd(mhba, NULL); -} - -static irqreturn_t mvumi_isr_handler(int irq, void *devp) -{ - struct mvumi_hba *mhba = (struct mvumi_hba *) devp; - unsigned long flags; - - spin_lock_irqsave(mhba->shost->host_lock, flags); - if (unlikely(mhba->instancet->clear_intr(mhba) || !mhba->global_isr)) { - spin_unlock_irqrestore(mhba->shost->host_lock, flags); - return IRQ_NONE; - } - - if (mhba->global_isr & INT_MAP_DL_CPU2PCIEA) { - if (mhba->isr_status & DRBL_HANDSHAKE_ISR) { - dev_warn(&mhba->pdev->dev, "enter handshake again!\n"); - mvumi_handshake(mhba); - } - if (mhba->isr_status & DRBL_EVENT_NOTIFY) - mvumi_launch_events(mhba, APICDB1_EVENT_GETEVENT); - } - - if (mhba->global_isr & INT_MAP_COMAOUT) - mvumi_receive_ob_list_entry(mhba); - - mhba->global_isr = 0; - mhba->isr_status = 0; - if (mhba->fw_state == FW_STATE_STARTED) - mvumi_handle_clob(mhba); - spin_unlock_irqrestore(mhba->shost->host_lock, flags); - return IRQ_HANDLED; -} - -static enum mvumi_qc_result mvumi_send_command(struct mvumi_hba *mhba, - struct mvumi_cmd *cmd) -{ - void *ib_entry; - struct mvumi_msg_frame *ib_frame; - unsigned int frame_len; - - ib_frame = cmd->frame; - if (unlikely(mhba->fw_state != FW_STATE_STARTED)) { - dev_dbg(&mhba->pdev->dev, "firmware not ready.\n"); - return MV_QUEUE_COMMAND_RESULT_NO_RESOURCE; - } - if (tag_is_empty(&mhba->tag_pool)) { - dev_dbg(&mhba->pdev->dev, "no free tag.\n"); - return MV_QUEUE_COMMAND_RESULT_NO_RESOURCE; - } - if (mvumi_get_ib_list_entry(mhba, &ib_entry)) - return MV_QUEUE_COMMAND_RESULT_NO_RESOURCE; - - cmd->frame->tag = tag_get_one(mhba, &mhba->tag_pool); - cmd->frame->request_id = mhba->io_seq++; - cmd->request_id = cmd->frame->request_id; - mhba->tag_cmd[cmd->frame->tag] = cmd; - frame_len = sizeof(*ib_frame) - 4 + - ib_frame->sg_counts * sizeof(struct mvumi_sgl); - memcpy(ib_entry, ib_frame, frame_len); - return MV_QUEUE_COMMAND_RESULT_SENT; -} - -static void mvumi_fire_cmd(struct mvumi_hba *mhba, struct mvumi_cmd *cmd) -{ - unsigned short num_of_cl_sent = 0; - enum mvumi_qc_result result; - - if (cmd) - list_add_tail(&cmd->queue_pointer, &mhba->waiting_req_list); - - while (!list_empty(&mhba->waiting_req_list)) { - cmd = list_first_entry(&mhba->waiting_req_list, - struct mvumi_cmd, queue_pointer); - list_del_init(&cmd->queue_pointer); - result = mvumi_send_command(mhba, cmd); - switch (result) { - case MV_QUEUE_COMMAND_RESULT_SENT: - num_of_cl_sent++; - break; - case MV_QUEUE_COMMAND_RESULT_NO_RESOURCE: - list_add(&cmd->queue_pointer, &mhba->waiting_req_list); - if (num_of_cl_sent > 0) - mvumi_send_ib_list_entry(mhba); - - return; - } - } - if (num_of_cl_sent > 0) - mvumi_send_ib_list_entry(mhba); -} - -/** - * mvumi_enable_intr - Enables interrupts - * @regs: FW register set - */ -static void mvumi_enable_intr(void *regs) -{ - unsigned int mask; - - iowrite32(0x3FFFFFFF, regs + CPU_ARM_TO_PCIEA_MASK_REG); - mask = ioread32(regs + CPU_ENPOINTA_MASK_REG); - mask |= INT_MAP_DL_CPU2PCIEA | INT_MAP_COMAOUT | INT_MAP_COMAERR; - iowrite32(mask, regs + CPU_ENPOINTA_MASK_REG); -} - -/** - * mvumi_disable_intr -Disables interrupt - * @regs: FW register set - */ -static void mvumi_disable_intr(void *regs) -{ - unsigned int mask; - - iowrite32(0, regs + CPU_ARM_TO_PCIEA_MASK_REG); - mask = ioread32(regs + CPU_ENPOINTA_MASK_REG); - mask &= ~(INT_MAP_DL_CPU2PCIEA | INT_MAP_COMAOUT | INT_MAP_COMAERR); - iowrite32(mask, regs + CPU_ENPOINTA_MASK_REG); -} - -static int mvumi_clear_intr(void *extend) -{ - struct mvumi_hba *mhba = (struct mvumi_hba *) extend; - unsigned int status, isr_status = 0, tmp = 0; - void *regs = mhba->mmio; - - status = ioread32(regs + CPU_MAIN_INT_CAUSE_REG); - if (!(status & INT_MAP_MU) || status == 0xFFFFFFFF) - return 1; - if (unlikely(status & INT_MAP_COMAERR)) { - tmp = ioread32(regs + CLA_ISR_CAUSE); - if (tmp & (CLIC_IN_ERR_IRQ | CLIC_OUT_ERR_IRQ)) - iowrite32(tmp & (CLIC_IN_ERR_IRQ | CLIC_OUT_ERR_IRQ), - regs + CLA_ISR_CAUSE); - status ^= INT_MAP_COMAERR; - /* inbound or outbound parity error, command will timeout */ - } - if (status & INT_MAP_COMAOUT) { - tmp = ioread32(regs + CLA_ISR_CAUSE); - if (tmp & CLIC_OUT_IRQ) - iowrite32(tmp & CLIC_OUT_IRQ, regs + CLA_ISR_CAUSE); - } - if (status & INT_MAP_DL_CPU2PCIEA) { - isr_status = ioread32(regs + CPU_ARM_TO_PCIEA_DRBL_REG); - if (isr_status) - iowrite32(isr_status, regs + CPU_ARM_TO_PCIEA_DRBL_REG); - } - - mhba->global_isr = status; - mhba->isr_status = isr_status; - - return 0; -} - -/** - * mvumi_read_fw_status_reg - returns the current FW status value - * @regs: FW register set - */ -static unsigned int mvumi_read_fw_status_reg(void *regs) -{ - unsigned int status; - - status = ioread32(regs + CPU_ARM_TO_PCIEA_DRBL_REG); - if (status) - iowrite32(status, regs + CPU_ARM_TO_PCIEA_DRBL_REG); - return status; -} - -static struct mvumi_instance_template mvumi_instance_template = { - .fire_cmd = mvumi_fire_cmd, - .enable_intr = mvumi_enable_intr, - .disable_intr = mvumi_disable_intr, - .clear_intr = mvumi_clear_intr, - .read_fw_status_reg = mvumi_read_fw_status_reg, -}; - -static int mvumi_slave_configure(struct scsi_device *sdev) -{ - struct mvumi_hba *mhba; - unsigned char bitcount = sizeof(unsigned char) * 8; - - mhba = (struct mvumi_hba *) sdev->host->hostdata; - if (sdev->id >= mhba->max_target_id) - return -EINVAL; - - mhba->target_map[sdev->id / bitcount] |= (1 << (sdev->id % bitcount)); - return 0; -} - -/** - * mvumi_build_frame - Prepares a direct cdb (DCDB) command - * @mhba: Adapter soft state - * @scmd: SCSI command - * @cmd: Command to be prepared in - * - * This function prepares CDB commands. These are typcially pass-through - * commands to the devices. - */ -static unsigned char mvumi_build_frame(struct mvumi_hba *mhba, - struct scsi_cmnd *scmd, struct mvumi_cmd *cmd) -{ - struct mvumi_msg_frame *pframe; - - cmd->scmd = scmd; - cmd->cmd_status = REQ_STATUS_PENDING; - pframe = cmd->frame; - pframe->device_id = ((unsigned short) scmd->device->id) | - (((unsigned short) scmd->device->lun) << 8); - pframe->cmd_flag = 0; - - switch (scmd->sc_data_direction) { - case DMA_NONE: - pframe->cmd_flag |= CMD_FLAG_NON_DATA; - break; - case DMA_FROM_DEVICE: - pframe->cmd_flag |= CMD_FLAG_DATA_IN; - break; - case DMA_TO_DEVICE: - pframe->cmd_flag |= CMD_FLAG_DATA_OUT; - break; - case DMA_BIDIRECTIONAL: - default: - dev_warn(&mhba->pdev->dev, "unexpected data direction[%d] " - "cmd[0x%x]\n", scmd->sc_data_direction, scmd->cmnd[0]); - goto error; - } - - pframe->cdb_length = scmd->cmd_len; - memcpy(pframe->cdb, scmd->cmnd, pframe->cdb_length); - pframe->req_function = CL_FUN_SCSI_CMD; - if (scsi_bufflen(scmd)) { - if (mvumi_make_sgl(mhba, scmd, &pframe->payload[0], - &pframe->sg_counts)) - goto error; - - pframe->data_transfer_length = scsi_bufflen(scmd); - } else { - pframe->sg_counts = 0; - pframe->data_transfer_length = 0; - } - return 0; - -error: - scmd->result = (DID_OK << 16) | (DRIVER_SENSE << 24) | - SAM_STAT_CHECK_CONDITION; - scsi_build_sense_buffer(0, scmd->sense_buffer, ILLEGAL_REQUEST, 0x24, - 0); - return -1; -} - -/** - * mvumi_queue_command - Queue entry point - * @scmd: SCSI command to be queued - * @done: Callback entry point - */ -static int mvumi_queue_command(struct Scsi_Host *shost, - struct scsi_cmnd *scmd) -{ - struct mvumi_cmd *cmd; - struct mvumi_hba *mhba; - unsigned long irq_flags; - - spin_lock_irqsave(shost->host_lock, irq_flags); - scsi_cmd_get_serial(shost, scmd); - - mhba = (struct mvumi_hba *) shost->hostdata; - scmd->result = 0; - cmd = mvumi_get_cmd(mhba); - if (unlikely(!cmd)) { - spin_unlock_irqrestore(shost->host_lock, irq_flags); - return SCSI_MLQUEUE_HOST_BUSY; - } - - if (unlikely(mvumi_build_frame(mhba, scmd, cmd))) - goto out_return_cmd; - - cmd->scmd = scmd; - scmd->SCp.ptr = (char *) cmd; - mhba->instancet->fire_cmd(mhba, cmd); - spin_unlock_irqrestore(shost->host_lock, irq_flags); - return 0; - -out_return_cmd: - mvumi_return_cmd(mhba, cmd); - scmd->scsi_done(scmd); - spin_unlock_irqrestore(shost->host_lock, irq_flags); - return 0; -} - -static enum blk_eh_timer_return mvumi_timed_out(struct scsi_cmnd *scmd) -{ - struct mvumi_cmd *cmd = (struct mvumi_cmd *) scmd->SCp.ptr; - struct Scsi_Host *host = scmd->device->host; - struct mvumi_hba *mhba = shost_priv(host); - unsigned long flags; - - spin_lock_irqsave(mhba->shost->host_lock, flags); - - if (mhba->tag_cmd[cmd->frame->tag]) { - mhba->tag_cmd[cmd->frame->tag] = 0; - tag_release_one(mhba, &mhba->tag_pool, cmd->frame->tag); - } - if (!list_empty(&cmd->queue_pointer)) - list_del_init(&cmd->queue_pointer); - else - atomic_dec(&mhba->fw_outstanding); - - scmd->result = (DRIVER_INVALID << 24) | (DID_ABORT << 16); - scmd->SCp.ptr = NULL; - if (scsi_bufflen(scmd)) { - if (scsi_sg_count(scmd)) { - pci_unmap_sg(mhba->pdev, - scsi_sglist(scmd), - scsi_sg_count(scmd), - (int)scmd->sc_data_direction); - } else { - pci_unmap_single(mhba->pdev, - scmd->SCp.dma_handle, - scsi_bufflen(scmd), - (int)scmd->sc_data_direction); - - scmd->SCp.dma_handle = 0; - } - } - mvumi_return_cmd(mhba, cmd); - spin_unlock_irqrestore(mhba->shost->host_lock, flags); - - return BLK_EH_NOT_HANDLED; -} - -static int -mvumi_bios_param(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - int heads, sectors; - sector_t cylinders; - unsigned long tmp; - - heads = 64; - sectors = 32; - tmp = heads * sectors; - cylinders = capacity; - sector_div(cylinders, tmp); - - if (capacity >= 0x200000) { - heads = 255; - sectors = 63; - tmp = heads * sectors; - cylinders = capacity; - sector_div(cylinders, tmp); - } - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return 0; -} - -static struct scsi_host_template mvumi_template = { - - .module = THIS_MODULE, - .name = "Marvell Storage Controller", - .slave_configure = mvumi_slave_configure, - .queuecommand = mvumi_queue_command, - .eh_host_reset_handler = mvumi_host_reset, - .bios_param = mvumi_bios_param, - .this_id = -1, -}; - -static struct scsi_transport_template mvumi_transport_template = { - .eh_timed_out = mvumi_timed_out, -}; - -/** - * mvumi_init_fw - Initializes the FW - * @mhba: Adapter soft state - * - * This is the main function for initializing firmware. - */ -static int mvumi_init_fw(struct mvumi_hba *mhba) -{ - int ret = 0; - - if (pci_request_regions(mhba->pdev, MV_DRIVER_NAME)) { - dev_err(&mhba->pdev->dev, "IO memory region busy!\n"); - return -EBUSY; - } - ret = mvumi_map_pci_addr(mhba->pdev, mhba->base_addr); - if (ret) - goto fail_ioremap; - - mhba->mmio = mhba->base_addr[0]; - - switch (mhba->pdev->device) { - case PCI_DEVICE_ID_MARVELL_MV9143: - mhba->instancet = &mvumi_instance_template; - mhba->io_seq = 0; - mhba->max_sge = MVUMI_MAX_SG_ENTRY; - mhba->request_id_enabled = 1; - break; - default: - dev_err(&mhba->pdev->dev, "device 0x%x not supported!\n", - mhba->pdev->device); - mhba->instancet = NULL; - ret = -EINVAL; - goto fail_alloc_mem; - } - dev_dbg(&mhba->pdev->dev, "device id : %04X is found.\n", - mhba->pdev->device); - - mhba->handshake_page = kzalloc(HSP_MAX_SIZE, GFP_KERNEL); - if (!mhba->handshake_page) { - dev_err(&mhba->pdev->dev, - "failed to allocate memory for handshake\n"); - ret = -ENOMEM; - goto fail_alloc_mem; - } - mhba->handshake_page_phys = virt_to_phys(mhba->handshake_page); - - if (mvumi_start(mhba)) { - ret = -EINVAL; - goto fail_ready_state; - } - ret = mvumi_alloc_cmds(mhba); - if (ret) - goto fail_ready_state; - - return 0; - -fail_ready_state: - mvumi_release_mem_resource(mhba); - kfree(mhba->handshake_page); -fail_alloc_mem: - mvumi_unmap_pci_addr(mhba->pdev, mhba->base_addr); -fail_ioremap: - pci_release_regions(mhba->pdev); - - return ret; -} - -/** - * mvumi_io_attach - Attaches this driver to SCSI mid-layer - * @mhba: Adapter soft state - */ -static int mvumi_io_attach(struct mvumi_hba *mhba) -{ - struct Scsi_Host *host = mhba->shost; - int ret; - unsigned int max_sg = (mhba->ib_max_size + 4 - - sizeof(struct mvumi_msg_frame)) / sizeof(struct mvumi_sgl); - - host->irq = mhba->pdev->irq; - host->unique_id = mhba->unique_id; - host->can_queue = (mhba->max_io - 1) ? (mhba->max_io - 1) : 1; - host->sg_tablesize = mhba->max_sge > max_sg ? max_sg : mhba->max_sge; - host->max_sectors = mhba->max_transfer_size / 512; - host->cmd_per_lun = (mhba->max_io - 1) ? (mhba->max_io - 1) : 1; - host->max_id = mhba->max_target_id; - host->max_cmd_len = MAX_COMMAND_SIZE; - host->transportt = &mvumi_transport_template; - - ret = scsi_add_host(host, &mhba->pdev->dev); - if (ret) { - dev_err(&mhba->pdev->dev, "scsi_add_host failed\n"); - return ret; - } - mhba->fw_flag |= MVUMI_FW_ATTACH; - scsi_scan_host(host); - - return 0; -} - -/** - * mvumi_probe_one - PCI hotplug entry point - * @pdev: PCI device structure - * @id: PCI ids of supported hotplugged adapter - */ -static int __devinit mvumi_probe_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct Scsi_Host *host; - struct mvumi_hba *mhba; - int ret; - - dev_dbg(&pdev->dev, " %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", - pdev->vendor, pdev->device, pdev->subsystem_vendor, - pdev->subsystem_device); - - ret = pci_enable_device(pdev); - if (ret) - return ret; - - pci_set_master(pdev); - - if (IS_DMA64) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (ret) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - goto fail_set_dma_mask; - } - } else { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - goto fail_set_dma_mask; - } - - host = scsi_host_alloc(&mvumi_template, sizeof(*mhba)); - if (!host) { - dev_err(&pdev->dev, "scsi_host_alloc failed\n"); - ret = -ENOMEM; - goto fail_alloc_instance; - } - mhba = shost_priv(host); - - INIT_LIST_HEAD(&mhba->cmd_pool); - INIT_LIST_HEAD(&mhba->ob_data_list); - INIT_LIST_HEAD(&mhba->free_ob_list); - INIT_LIST_HEAD(&mhba->res_list); - INIT_LIST_HEAD(&mhba->waiting_req_list); - atomic_set(&mhba->fw_outstanding, 0); - init_waitqueue_head(&mhba->int_cmd_wait_q); - - mhba->pdev = pdev; - mhba->shost = host; - mhba->unique_id = pdev->bus->number << 8 | pdev->devfn; - - ret = mvumi_init_fw(mhba); - if (ret) - goto fail_init_fw; - - ret = request_irq(mhba->pdev->irq, mvumi_isr_handler, IRQF_SHARED, - "mvumi", mhba); - if (ret) { - dev_err(&pdev->dev, "failed to register IRQ\n"); - goto fail_init_irq; - } - mhba->instancet->enable_intr(mhba->mmio); - pci_set_drvdata(pdev, mhba); - - ret = mvumi_io_attach(mhba); - if (ret) - goto fail_io_attach; - dev_dbg(&pdev->dev, "probe mvumi driver successfully.\n"); - - return 0; - -fail_io_attach: - pci_set_drvdata(pdev, NULL); - mhba->instancet->disable_intr(mhba->mmio); - free_irq(mhba->pdev->irq, mhba); -fail_init_irq: - mvumi_release_fw(mhba); -fail_init_fw: - scsi_host_put(host); - -fail_alloc_instance: -fail_set_dma_mask: - pci_disable_device(pdev); - - return ret; -} - -static void mvumi_detach_one(struct pci_dev *pdev) -{ - struct Scsi_Host *host; - struct mvumi_hba *mhba; - - mhba = pci_get_drvdata(pdev); - host = mhba->shost; - scsi_remove_host(mhba->shost); - mvumi_flush_cache(mhba); - - mhba->instancet->disable_intr(mhba->mmio); - free_irq(mhba->pdev->irq, mhba); - mvumi_release_fw(mhba); - scsi_host_put(host); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); - dev_dbg(&pdev->dev, "driver is removed!\n"); -} - -/** - * mvumi_shutdown - Shutdown entry point - * @device: Generic device structure - */ -static void mvumi_shutdown(struct pci_dev *pdev) -{ - struct mvumi_hba *mhba = pci_get_drvdata(pdev); - - mvumi_flush_cache(mhba); -} - -static int mvumi_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct mvumi_hba *mhba = NULL; - - mhba = pci_get_drvdata(pdev); - mvumi_flush_cache(mhba); - - pci_set_drvdata(pdev, mhba); - mhba->instancet->disable_intr(mhba->mmio); - free_irq(mhba->pdev->irq, mhba); - mvumi_unmap_pci_addr(pdev, mhba->base_addr); - pci_release_regions(pdev); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -static int mvumi_resume(struct pci_dev *pdev) -{ - int ret; - struct mvumi_hba *mhba = NULL; - - mhba = pci_get_drvdata(pdev); - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - ret = pci_enable_device(pdev); - if (ret) { - dev_err(&pdev->dev, "enable device failed\n"); - return ret; - } - pci_set_master(pdev); - if (IS_DMA64) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); - if (ret) { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - goto fail; - } - } else { - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (ret) - goto fail; - } - ret = pci_request_regions(mhba->pdev, MV_DRIVER_NAME); - if (ret) - goto fail; - ret = mvumi_map_pci_addr(mhba->pdev, mhba->base_addr); - if (ret) - goto release_regions; - - mhba->mmio = mhba->base_addr[0]; - mvumi_reset(mhba->mmio); - - if (mvumi_start(mhba)) { - ret = -EINVAL; - goto unmap_pci_addr; - } - - ret = request_irq(mhba->pdev->irq, mvumi_isr_handler, IRQF_SHARED, - "mvumi", mhba); - if (ret) { - dev_err(&pdev->dev, "failed to register IRQ\n"); - goto unmap_pci_addr; - } - mhba->instancet->enable_intr(mhba->mmio); - - return 0; - -unmap_pci_addr: - mvumi_unmap_pci_addr(pdev, mhba->base_addr); -release_regions: - pci_release_regions(pdev); -fail: - pci_disable_device(pdev); - - return ret; -} - -static struct pci_driver mvumi_pci_driver = { - - .name = MV_DRIVER_NAME, - .id_table = mvumi_pci_table, - .probe = mvumi_probe_one, - .remove = __devexit_p(mvumi_detach_one), - .shutdown = mvumi_shutdown, -#ifdef CONFIG_PM - .suspend = mvumi_suspend, - .resume = mvumi_resume, -#endif -}; - -/** - * mvumi_init - Driver load entry point - */ -static int __init mvumi_init(void) -{ - return pci_register_driver(&mvumi_pci_driver); -} - -/** - * mvumi_exit - Driver unload entry point - */ -static void __exit mvumi_exit(void) -{ - - pci_unregister_driver(&mvumi_pci_driver); -} - -module_init(mvumi_init); -module_exit(mvumi_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/mvumi.h b/ANDROID_3.4.5/drivers/scsi/mvumi.h deleted file mode 100644 index 10b92375..00000000 --- a/ANDROID_3.4.5/drivers/scsi/mvumi.h +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Marvell UMI head file - * - * Copyright 2011 Marvell. - * - * This file is licensed under GPLv2. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - * USA - */ - -#ifndef MVUMI_H -#define MVUMI_H - -#define MAX_BASE_ADDRESS 6 - -#define VER_MAJOR 1 -#define VER_MINOR 1 -#define VER_OEM 0 -#define VER_BUILD 1500 - -#define MV_DRIVER_NAME "mvumi" -#define PCI_VENDOR_ID_MARVELL_2 0x1b4b -#define PCI_DEVICE_ID_MARVELL_MV9143 0x9143 - -#define MVUMI_INTERNAL_CMD_WAIT_TIME 45 - -#define IS_DMA64 (sizeof(dma_addr_t) == 8) - -enum mvumi_qc_result { - MV_QUEUE_COMMAND_RESULT_SENT = 0, - MV_QUEUE_COMMAND_RESULT_NO_RESOURCE, -}; - -enum { - /*******************************************/ - - /* ARM Mbus Registers Map */ - - /*******************************************/ - CPU_MAIN_INT_CAUSE_REG = 0x20200, - CPU_MAIN_IRQ_MASK_REG = 0x20204, - CPU_MAIN_FIQ_MASK_REG = 0x20208, - CPU_ENPOINTA_MASK_REG = 0x2020C, - CPU_ENPOINTB_MASK_REG = 0x20210, - - INT_MAP_COMAERR = 1 << 6, - INT_MAP_COMAIN = 1 << 7, - INT_MAP_COMAOUT = 1 << 8, - INT_MAP_COMBERR = 1 << 9, - INT_MAP_COMBIN = 1 << 10, - INT_MAP_COMBOUT = 1 << 11, - - INT_MAP_COMAINT = (INT_MAP_COMAOUT | INT_MAP_COMAERR), - INT_MAP_COMBINT = (INT_MAP_COMBOUT | INT_MAP_COMBIN | INT_MAP_COMBERR), - - INT_MAP_DL_PCIEA2CPU = 1 << 0, - INT_MAP_DL_CPU2PCIEA = 1 << 1, - - /***************************************/ - - /* ARM Doorbell Registers Map */ - - /***************************************/ - CPU_PCIEA_TO_ARM_DRBL_REG = 0x20400, - CPU_PCIEA_TO_ARM_MASK_REG = 0x20404, - CPU_ARM_TO_PCIEA_DRBL_REG = 0x20408, - CPU_ARM_TO_PCIEA_MASK_REG = 0x2040C, - - DRBL_HANDSHAKE = 1 << 0, - DRBL_SOFT_RESET = 1 << 1, - DRBL_BUS_CHANGE = 1 << 2, - DRBL_EVENT_NOTIFY = 1 << 3, - DRBL_MU_RESET = 1 << 4, - DRBL_HANDSHAKE_ISR = DRBL_HANDSHAKE, - - CPU_PCIEA_TO_ARM_MSG0 = 0x20430, - CPU_PCIEA_TO_ARM_MSG1 = 0x20434, - CPU_ARM_TO_PCIEA_MSG0 = 0x20438, - CPU_ARM_TO_PCIEA_MSG1 = 0x2043C, - - /*******************************************/ - - /* ARM Communication List Registers Map */ - - /*******************************************/ - CLA_INB_LIST_BASEL = 0x500, - CLA_INB_LIST_BASEH = 0x504, - CLA_INB_AVAL_COUNT_BASEL = 0x508, - CLA_INB_AVAL_COUNT_BASEH = 0x50C, - CLA_INB_DESTI_LIST_BASEL = 0x510, - CLA_INB_DESTI_LIST_BASEH = 0x514, - CLA_INB_WRITE_POINTER = 0x518, - CLA_INB_READ_POINTER = 0x51C, - - CLA_OUTB_LIST_BASEL = 0x530, - CLA_OUTB_LIST_BASEH = 0x534, - CLA_OUTB_SOURCE_LIST_BASEL = 0x538, - CLA_OUTB_SOURCE_LIST_BASEH = 0x53C, - CLA_OUTB_COPY_POINTER = 0x544, - CLA_OUTB_READ_POINTER = 0x548, - - CLA_ISR_CAUSE = 0x560, - CLA_ISR_MASK = 0x564, - - INT_MAP_MU = (INT_MAP_DL_CPU2PCIEA | INT_MAP_COMAINT), - - CL_POINTER_TOGGLE = 1 << 12, - - CLIC_IN_IRQ = 1 << 0, - CLIC_OUT_IRQ = 1 << 1, - CLIC_IN_ERR_IRQ = 1 << 8, - CLIC_OUT_ERR_IRQ = 1 << 12, - - CL_SLOT_NUM_MASK = 0xFFF, - - /* - * Command flag is the flag for the CDB command itself - */ - /* 1-non data; 0-data command */ - CMD_FLAG_NON_DATA = 1 << 0, - CMD_FLAG_DMA = 1 << 1, - CMD_FLAG_PIO = 1 << 2, - /* 1-host read data */ - CMD_FLAG_DATA_IN = 1 << 3, - /* 1-host write data */ - CMD_FLAG_DATA_OUT = 1 << 4, - - SCSI_CMD_MARVELL_SPECIFIC = 0xE1, - CDB_CORE_SHUTDOWN = 0xB, -}; - -#define APICDB0_EVENT 0xF4 -#define APICDB1_EVENT_GETEVENT 0 -#define MAX_EVENTS_RETURNED 6 - -struct mvumi_driver_event { - u32 time_stamp; - u32 sequence_no; - u32 event_id; - u8 severity; - u8 param_count; - u16 device_id; - u32 params[4]; - u8 sense_data_length; - u8 Reserved1; - u8 sense_data[30]; -}; - -struct mvumi_event_req { - unsigned char count; - unsigned char reserved[3]; - struct mvumi_driver_event events[MAX_EVENTS_RETURNED]; -}; - -struct mvumi_events_wq { - struct work_struct work_q; - struct mvumi_hba *mhba; - unsigned int event; - void *param; -}; - -#define MVUMI_MAX_SG_ENTRY 32 -#define SGD_EOT (1L << 27) - -struct mvumi_sgl { - u32 baseaddr_l; - u32 baseaddr_h; - u32 flags; - u32 size; -}; - -struct mvumi_res { - struct list_head entry; - dma_addr_t bus_addr; - void *virt_addr; - unsigned int size; - unsigned short type; /* enum Resource_Type */ -}; - -/* Resource type */ -enum resource_type { - RESOURCE_CACHED_MEMORY = 0, - RESOURCE_UNCACHED_MEMORY -}; - -struct mvumi_sense_data { - u8 error_eode:7; - u8 valid:1; - u8 segment_number; - u8 sense_key:4; - u8 reserved:1; - u8 incorrect_length:1; - u8 end_of_media:1; - u8 file_mark:1; - u8 information[4]; - u8 additional_sense_length; - u8 command_specific_information[4]; - u8 additional_sense_code; - u8 additional_sense_code_qualifier; - u8 field_replaceable_unit_code; - u8 sense_key_specific[3]; -}; - -/* Request initiator must set the status to REQ_STATUS_PENDING. */ -#define REQ_STATUS_PENDING 0x80 - -struct mvumi_cmd { - struct list_head queue_pointer; - struct mvumi_msg_frame *frame; - struct scsi_cmnd *scmd; - atomic_t sync_cmd; - void *data_buf; - unsigned short request_id; - unsigned char cmd_status; -}; - -/* - * the function type of the in bound frame - */ -#define CL_FUN_SCSI_CMD 0x1 - -struct mvumi_msg_frame { - u16 device_id; - u16 tag; - u8 cmd_flag; - u8 req_function; - u8 cdb_length; - u8 sg_counts; - u32 data_transfer_length; - u16 request_id; - u16 reserved1; - u8 cdb[MAX_COMMAND_SIZE]; - u32 payload[1]; -}; - -/* - * the respond flag for data_payload of the out bound frame - */ -#define CL_RSP_FLAG_NODATA 0x0 -#define CL_RSP_FLAG_SENSEDATA 0x1 - -struct mvumi_rsp_frame { - u16 device_id; - u16 tag; - u8 req_status; - u8 rsp_flag; /* Indicates the type of Data_Payload.*/ - u16 request_id; - u32 payload[1]; -}; - -struct mvumi_ob_data { - struct list_head list; - unsigned char data[0]; -}; - -struct version_info { - u32 ver_major; - u32 ver_minor; - u32 ver_oem; - u32 ver_build; -}; - -#define FW_MAX_DELAY 30 -#define MVUMI_FW_BUSY (1U << 0) -#define MVUMI_FW_ATTACH (1U << 1) -#define MVUMI_FW_ALLOC (1U << 2) - -/* - * State is the state of the MU - */ -#define FW_STATE_IDLE 0 -#define FW_STATE_STARTING 1 -#define FW_STATE_HANDSHAKING 2 -#define FW_STATE_STARTED 3 -#define FW_STATE_ABORT 4 - -#define HANDSHAKE_SIGNATURE 0x5A5A5A5AL -#define HANDSHAKE_READYSTATE 0x55AA5AA5L -#define HANDSHAKE_DONESTATE 0x55AAA55AL - -/* HandShake Status definition */ -#define HS_STATUS_OK 1 -#define HS_STATUS_ERR 2 -#define HS_STATUS_INVALID 3 - -/* HandShake State/Cmd definition */ -#define HS_S_START 1 -#define HS_S_RESET 2 -#define HS_S_PAGE_ADDR 3 -#define HS_S_QUERY_PAGE 4 -#define HS_S_SEND_PAGE 5 -#define HS_S_END 6 -#define HS_S_ABORT 7 -#define HS_PAGE_VERIFY_SIZE 128 - -#define HS_GET_STATE(a) (a & 0xFFFF) -#define HS_GET_STATUS(a) ((a & 0xFFFF0000) >> 16) -#define HS_SET_STATE(a, b) (a |= (b & 0xFFFF)) -#define HS_SET_STATUS(a, b) (a |= ((b & 0xFFFF) << 16)) - -/* handshake frame */ -struct mvumi_hs_frame { - u16 size; - /* host information */ - u8 host_type; - u8 reserved_1[1]; - struct version_info host_ver; /* bios or driver version */ - - /* controller information */ - u32 system_io_bus; - u32 slot_number; - u32 intr_level; - u32 intr_vector; - - /* communication list configuration */ - u32 ib_baseaddr_l; - u32 ib_baseaddr_h; - u32 ob_baseaddr_l; - u32 ob_baseaddr_h; - - u8 ib_entry_size; - u8 ob_entry_size; - u8 ob_depth; - u8 ib_depth; - - /* system time */ - u64 seconds_since1970; -}; - -struct mvumi_hs_header { - u8 page_code; - u8 checksum; - u16 frame_length; - u32 frame_content[1]; -}; - -/* - * the page code type of the handshake header - */ -#define HS_PAGE_FIRM_CAP 0x1 -#define HS_PAGE_HOST_INFO 0x2 -#define HS_PAGE_FIRM_CTL 0x3 -#define HS_PAGE_CL_INFO 0x4 -#define HS_PAGE_TOTAL 0x5 - -#define HSP_SIZE(i) sizeof(struct mvumi_hs_page##i) - -#define HSP_MAX_SIZE ({ \ - int size, m1, m2; \ - m1 = max(HSP_SIZE(1), HSP_SIZE(3)); \ - m2 = max(HSP_SIZE(2), HSP_SIZE(4)); \ - size = max(m1, m2); \ - size; \ -}) - -/* The format of the page code for Firmware capability */ -struct mvumi_hs_page1 { - u8 pagecode; - u8 checksum; - u16 frame_length; - - u16 number_of_ports; - u16 max_devices_support; - u16 max_io_support; - u16 umi_ver; - u32 max_transfer_size; - struct version_info fw_ver; - u8 cl_in_max_entry_size; - u8 cl_out_max_entry_size; - u8 cl_inout_list_depth; - u8 total_pages; - u16 capability; - u16 reserved1; -}; - -/* The format of the page code for Host information */ -struct mvumi_hs_page2 { - u8 pagecode; - u8 checksum; - u16 frame_length; - - u8 host_type; - u8 reserved[3]; - struct version_info host_ver; - u32 system_io_bus; - u32 slot_number; - u32 intr_level; - u32 intr_vector; - u64 seconds_since1970; -}; - -/* The format of the page code for firmware control */ -struct mvumi_hs_page3 { - u8 pagecode; - u8 checksum; - u16 frame_length; - u16 control; - u8 reserved[2]; - u32 host_bufferaddr_l; - u32 host_bufferaddr_h; - u32 host_eventaddr_l; - u32 host_eventaddr_h; -}; - -struct mvumi_hs_page4 { - u8 pagecode; - u8 checksum; - u16 frame_length; - u32 ib_baseaddr_l; - u32 ib_baseaddr_h; - u32 ob_baseaddr_l; - u32 ob_baseaddr_h; - u8 ib_entry_size; - u8 ob_entry_size; - u8 ob_depth; - u8 ib_depth; -}; - -struct mvumi_tag { - unsigned short *stack; - unsigned short top; - unsigned short size; -}; - -struct mvumi_hba { - void *base_addr[MAX_BASE_ADDRESS]; - void *mmio; - struct list_head cmd_pool; - struct Scsi_Host *shost; - wait_queue_head_t int_cmd_wait_q; - struct pci_dev *pdev; - unsigned int unique_id; - atomic_t fw_outstanding; - struct mvumi_instance_template *instancet; - - void *ib_list; - dma_addr_t ib_list_phys; - - void *ob_list; - dma_addr_t ob_list_phys; - - void *ib_shadow; - dma_addr_t ib_shadow_phys; - - void *ob_shadow; - dma_addr_t ob_shadow_phys; - - void *handshake_page; - dma_addr_t handshake_page_phys; - - unsigned int global_isr; - unsigned int isr_status; - - unsigned short max_sge; - unsigned short max_target_id; - unsigned char *target_map; - unsigned int max_io; - unsigned int list_num_io; - unsigned int ib_max_size; - unsigned int ob_max_size; - unsigned int ib_max_size_setting; - unsigned int ob_max_size_setting; - unsigned int max_transfer_size; - unsigned char hba_total_pages; - unsigned char fw_flag; - unsigned char request_id_enabled; - unsigned short hba_capability; - unsigned short io_seq; - - unsigned int ib_cur_slot; - unsigned int ob_cur_slot; - unsigned int fw_state; - - struct list_head ob_data_list; - struct list_head free_ob_list; - struct list_head res_list; - struct list_head waiting_req_list; - - struct mvumi_tag tag_pool; - struct mvumi_cmd **tag_cmd; -}; - -struct mvumi_instance_template { - void (*fire_cmd)(struct mvumi_hba *, struct mvumi_cmd *); - void (*enable_intr)(void *) ; - void (*disable_intr)(void *); - int (*clear_intr)(void *); - unsigned int (*read_fw_status_reg)(void *); -}; - -extern struct timezone sys_tz; -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/ncr53c8xx.c b/ANDROID_3.4.5/drivers/scsi/ncr53c8xx.c deleted file mode 100644 index 5982a587..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ncr53c8xx.c +++ /dev/null @@ -1,8629 +0,0 @@ -/****************************************************************************** -** Device driver for the PCI-SCSI NCR538XX controller family. -** -** Copyright (C) 1994 Wolfgang Stanglmeier -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -** -** This driver has been ported to Linux from the FreeBSD NCR53C8XX driver -** and is currently maintained by -** -** Gerard Roudier -** -** Being given that this driver originates from the FreeBSD version, and -** in order to keep synergy on both, any suggested enhancements and corrections -** received on Linux are automatically a potential candidate for the FreeBSD -** version. -** -** The original driver has been written for 386bsd and FreeBSD by -** Wolfgang Stanglmeier -** Stefan Esser -** -** And has been ported to NetBSD by -** Charles M. Hannum -** -**----------------------------------------------------------------------------- -** -** Brief history -** -** December 10 1995 by Gerard Roudier: -** Initial port to Linux. -** -** June 23 1996 by Gerard Roudier: -** Support for 64 bits architectures (Alpha). -** -** November 30 1996 by Gerard Roudier: -** Support for Fast-20 scsi. -** Support for large DMA fifo and 128 dwords bursting. -** -** February 27 1997 by Gerard Roudier: -** Support for Fast-40 scsi. -** Support for on-Board RAM. -** -** May 3 1997 by Gerard Roudier: -** Full support for scsi scripts instructions pre-fetching. -** -** May 19 1997 by Richard Waltham : -** Support for NvRAM detection and reading. -** -** August 18 1997 by Cort : -** Support for Power/PC (Big Endian). -** -** June 20 1998 by Gerard Roudier -** Support for up to 64 tags per lun. -** O(1) everywhere (C and SCRIPTS) for normal cases. -** Low PCI traffic for command handling when on-chip RAM is present. -** Aggressive SCSI SCRIPTS optimizations. -** -** 2005 by Matthew Wilcox and James Bottomley -** PCI-ectomy. This driver now supports only the 720 chip (see the -** NCR_Q720 and zalon drivers for the bus probe logic). -** -******************************************************************************* -*/ - -/* -** Supported SCSI-II features: -** Synchronous negotiation -** Wide negotiation (depends on the NCR Chip) -** Enable disconnection -** Tagged command queuing -** Parity checking -** Etc... -** -** Supported NCR/SYMBIOS chips: -** 53C720 (Wide, Fast SCSI-2, intfly problems) -*/ - -/* Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.3g" - -#define SCSI_NCR_DEBUG_FLAGS (0) - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "ncr53c8xx.h" - -#define NAME53C8XX "ncr53c8xx" - -/*========================================================== -** -** Debugging tags -** -**========================================================== -*/ - -#define DEBUG_ALLOC (0x0001) -#define DEBUG_PHASE (0x0002) -#define DEBUG_QUEUE (0x0008) -#define DEBUG_RESULT (0x0010) -#define DEBUG_POINTER (0x0020) -#define DEBUG_SCRIPT (0x0040) -#define DEBUG_TINY (0x0080) -#define DEBUG_TIMING (0x0100) -#define DEBUG_NEGO (0x0200) -#define DEBUG_TAGS (0x0400) -#define DEBUG_SCATTER (0x0800) -#define DEBUG_IC (0x1000) - -/* -** Enable/Disable debug messages. -** Can be changed at runtime too. -*/ - -#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT -static int ncr_debug = SCSI_NCR_DEBUG_FLAGS; - #define DEBUG_FLAGS ncr_debug -#else - #define DEBUG_FLAGS SCSI_NCR_DEBUG_FLAGS -#endif - -static inline struct list_head *ncr_list_pop(struct list_head *head) -{ - if (!list_empty(head)) { - struct list_head *elem = head->next; - - list_del(elem); - return elem; - } - - return NULL; -} - -/*========================================================== -** -** Simple power of two buddy-like allocator. -** -** This simple code is not intended to be fast, but to -** provide power of 2 aligned memory allocations. -** Since the SCRIPTS processor only supplies 8 bit -** arithmetic, this allocator allows simple and fast -** address calculations from the SCRIPTS code. -** In addition, cache line alignment is guaranteed for -** power of 2 cache line size. -** Enhanced in linux-2.3.44 to provide a memory pool -** per pcidev to support dynamic dma mapping. (I would -** have preferred a real bus abstraction, btw). -** -**========================================================== -*/ - -#define MEMO_SHIFT 4 /* 16 bytes minimum memory chunk */ -#if PAGE_SIZE >= 8192 -#define MEMO_PAGE_ORDER 0 /* 1 PAGE maximum */ -#else -#define MEMO_PAGE_ORDER 1 /* 2 PAGES maximum */ -#endif -#define MEMO_FREE_UNUSED /* Free unused pages immediately */ -#define MEMO_WARN 1 -#define MEMO_GFP_FLAGS GFP_ATOMIC -#define MEMO_CLUSTER_SHIFT (PAGE_SHIFT+MEMO_PAGE_ORDER) -#define MEMO_CLUSTER_SIZE (1UL << MEMO_CLUSTER_SHIFT) -#define MEMO_CLUSTER_MASK (MEMO_CLUSTER_SIZE-1) - -typedef u_long m_addr_t; /* Enough bits to bit-hack addresses */ -typedef struct device *m_bush_t; /* Something that addresses DMAable */ - -typedef struct m_link { /* Link between free memory chunks */ - struct m_link *next; -} m_link_s; - -typedef struct m_vtob { /* Virtual to Bus address translation */ - struct m_vtob *next; - m_addr_t vaddr; - m_addr_t baddr; -} m_vtob_s; -#define VTOB_HASH_SHIFT 5 -#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) -#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) -#define VTOB_HASH_CODE(m) \ - ((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK) - -typedef struct m_pool { /* Memory pool of a given kind */ - m_bush_t bush; - m_addr_t (*getp)(struct m_pool *); - void (*freep)(struct m_pool *, m_addr_t); - int nump; - m_vtob_s *(vtob[VTOB_HASH_SIZE]); - struct m_pool *next; - struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1]; -} m_pool_s; - -static void *___m_alloc(m_pool_s *mp, int size) -{ - int i = 0; - int s = (1 << MEMO_SHIFT); - int j; - m_addr_t a; - m_link_s *h = mp->h; - - if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) - return NULL; - - while (size > s) { - s <<= 1; - ++i; - } - - j = i; - while (!h[j].next) { - if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { - h[j].next = (m_link_s *)mp->getp(mp); - if (h[j].next) - h[j].next->next = NULL; - break; - } - ++j; - s <<= 1; - } - a = (m_addr_t) h[j].next; - if (a) { - h[j].next = h[j].next->next; - while (j > i) { - j -= 1; - s >>= 1; - h[j].next = (m_link_s *) (a+s); - h[j].next->next = NULL; - } - } -#ifdef DEBUG - printk("___m_alloc(%d) = %p\n", size, (void *) a); -#endif - return (void *) a; -} - -static void ___m_free(m_pool_s *mp, void *ptr, int size) -{ - int i = 0; - int s = (1 << MEMO_SHIFT); - m_link_s *q; - m_addr_t a, b; - m_link_s *h = mp->h; - -#ifdef DEBUG - printk("___m_free(%p, %d)\n", ptr, size); -#endif - - if (size > (PAGE_SIZE << MEMO_PAGE_ORDER)) - return; - - while (size > s) { - s <<= 1; - ++i; - } - - a = (m_addr_t) ptr; - - while (1) { -#ifdef MEMO_FREE_UNUSED - if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) { - mp->freep(mp, a); - break; - } -#endif - b = a ^ s; - q = &h[i]; - while (q->next && q->next != (m_link_s *) b) { - q = q->next; - } - if (!q->next) { - ((m_link_s *) a)->next = h[i].next; - h[i].next = (m_link_s *) a; - break; - } - q->next = q->next->next; - a = a & b; - s <<= 1; - ++i; - } -} - -static DEFINE_SPINLOCK(ncr53c8xx_lock); - -static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags) -{ - void *p; - - p = ___m_alloc(mp, size); - - if (DEBUG_FLAGS & DEBUG_ALLOC) - printk ("new %-10s[%4d] @%p.\n", name, size, p); - - if (p) - memset(p, 0, size); - else if (uflags & MEMO_WARN) - printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size); - - return p; -} - -#define __m_calloc(mp, s, n) __m_calloc2(mp, s, n, MEMO_WARN) - -static void __m_free(m_pool_s *mp, void *ptr, int size, char *name) -{ - if (DEBUG_FLAGS & DEBUG_ALLOC) - printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr); - - ___m_free(mp, ptr, size); - -} - -/* - * With pci bus iommu support, we use a default pool of unmapped memory - * for memory we donnot need to DMA from/to and one pool per pcidev for - * memory accessed by the PCI chip. `mp0' is the default not DMAable pool. - */ - -static m_addr_t ___mp0_getp(m_pool_s *mp) -{ - m_addr_t m = __get_free_pages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER); - if (m) - ++mp->nump; - return m; -} - -static void ___mp0_freep(m_pool_s *mp, m_addr_t m) -{ - free_pages(m, MEMO_PAGE_ORDER); - --mp->nump; -} - -static m_pool_s mp0 = {NULL, ___mp0_getp, ___mp0_freep}; - -/* - * DMAable pools. - */ - -/* - * With pci bus iommu support, we maintain one pool per pcidev and a - * hashed reverse table for virtual to bus physical address translations. - */ -static m_addr_t ___dma_getp(m_pool_s *mp) -{ - m_addr_t vp; - m_vtob_s *vbp; - - vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB"); - if (vbp) { - dma_addr_t daddr; - vp = (m_addr_t) dma_alloc_coherent(mp->bush, - PAGE_SIZE<vaddr = vp; - vbp->baddr = daddr; - vbp->next = mp->vtob[hc]; - mp->vtob[hc] = vbp; - ++mp->nump; - return vp; - } - } - if (vbp) - __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); - return 0; -} - -static void ___dma_freep(m_pool_s *mp, m_addr_t m) -{ - m_vtob_s **vbpp, *vbp; - int hc = VTOB_HASH_CODE(m); - - vbpp = &mp->vtob[hc]; - while (*vbpp && (*vbpp)->vaddr != m) - vbpp = &(*vbpp)->next; - if (*vbpp) { - vbp = *vbpp; - *vbpp = (*vbpp)->next; - dma_free_coherent(mp->bush, PAGE_SIZE<vaddr, (dma_addr_t)vbp->baddr); - __m_free(&mp0, vbp, sizeof(*vbp), "VTOB"); - --mp->nump; - } -} - -static inline m_pool_s *___get_dma_pool(m_bush_t bush) -{ - m_pool_s *mp; - for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next); - return mp; -} - -static m_pool_s *___cre_dma_pool(m_bush_t bush) -{ - m_pool_s *mp; - mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL"); - if (mp) { - memset(mp, 0, sizeof(*mp)); - mp->bush = bush; - mp->getp = ___dma_getp; - mp->freep = ___dma_freep; - mp->next = mp0.next; - mp0.next = mp; - } - return mp; -} - -static void ___del_dma_pool(m_pool_s *p) -{ - struct m_pool **pp = &mp0.next; - - while (*pp && *pp != p) - pp = &(*pp)->next; - if (*pp) { - *pp = (*pp)->next; - __m_free(&mp0, p, sizeof(*p), "MPOOL"); - } -} - -static void *__m_calloc_dma(m_bush_t bush, int size, char *name) -{ - u_long flags; - struct m_pool *mp; - void *m = NULL; - - spin_lock_irqsave(&ncr53c8xx_lock, flags); - mp = ___get_dma_pool(bush); - if (!mp) - mp = ___cre_dma_pool(bush); - if (mp) - m = __m_calloc(mp, size, name); - if (mp && !mp->nump) - ___del_dma_pool(mp); - spin_unlock_irqrestore(&ncr53c8xx_lock, flags); - - return m; -} - -static void __m_free_dma(m_bush_t bush, void *m, int size, char *name) -{ - u_long flags; - struct m_pool *mp; - - spin_lock_irqsave(&ncr53c8xx_lock, flags); - mp = ___get_dma_pool(bush); - if (mp) - __m_free(mp, m, size, name); - if (mp && !mp->nump) - ___del_dma_pool(mp); - spin_unlock_irqrestore(&ncr53c8xx_lock, flags); -} - -static m_addr_t __vtobus(m_bush_t bush, void *m) -{ - u_long flags; - m_pool_s *mp; - int hc = VTOB_HASH_CODE(m); - m_vtob_s *vp = NULL; - m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK; - - spin_lock_irqsave(&ncr53c8xx_lock, flags); - mp = ___get_dma_pool(bush); - if (mp) { - vp = mp->vtob[hc]; - while (vp && (m_addr_t) vp->vaddr != a) - vp = vp->next; - } - spin_unlock_irqrestore(&ncr53c8xx_lock, flags); - return vp ? vp->baddr + (((m_addr_t) m) - a) : 0; -} - -#define _m_calloc_dma(np, s, n) __m_calloc_dma(np->dev, s, n) -#define _m_free_dma(np, p, s, n) __m_free_dma(np->dev, p, s, n) -#define m_calloc_dma(s, n) _m_calloc_dma(np, s, n) -#define m_free_dma(p, s, n) _m_free_dma(np, p, s, n) -#define _vtobus(np, p) __vtobus(np->dev, p) -#define vtobus(p) _vtobus(np, p) - -/* - * Deal with DMA mapping/unmapping. - */ - -/* To keep track of the dma mapping (sg/single) that has been set */ -#define __data_mapped SCp.phase -#define __data_mapping SCp.have_data_in - -static void __unmap_scsi_data(struct device *dev, struct scsi_cmnd *cmd) -{ - switch(cmd->__data_mapped) { - case 2: - scsi_dma_unmap(cmd); - break; - } - cmd->__data_mapped = 0; -} - -static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd) -{ - int use_sg; - - use_sg = scsi_dma_map(cmd); - if (!use_sg) - return 0; - - cmd->__data_mapped = 2; - cmd->__data_mapping = use_sg; - - return use_sg; -} - -#define unmap_scsi_data(np, cmd) __unmap_scsi_data(np->dev, cmd) -#define map_scsi_sg_data(np, cmd) __map_scsi_sg_data(np->dev, cmd) - -/*========================================================== -** -** Driver setup. -** -** This structure is initialized from linux config -** options. It can be overridden at boot-up by the boot -** command line. -** -**========================================================== -*/ -static struct ncr_driver_setup - driver_setup = SCSI_NCR_DRIVER_SETUP; - -#ifndef MODULE -#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT -static struct ncr_driver_setup - driver_safe_setup __initdata = SCSI_NCR_DRIVER_SAFE_SETUP; -#endif -#endif /* !MODULE */ - -#define initverbose (driver_setup.verbose) -#define bootverbose (np->verbose) - - -/*=================================================================== -** -** Driver setup from the boot command line -** -**=================================================================== -*/ - -#ifdef MODULE -#define ARG_SEP ' ' -#else -#define ARG_SEP ',' -#endif - -#define OPT_TAGS 1 -#define OPT_MASTER_PARITY 2 -#define OPT_SCSI_PARITY 3 -#define OPT_DISCONNECTION 4 -#define OPT_SPECIAL_FEATURES 5 -#define OPT_UNUSED_1 6 -#define OPT_FORCE_SYNC_NEGO 7 -#define OPT_REVERSE_PROBE 8 -#define OPT_DEFAULT_SYNC 9 -#define OPT_VERBOSE 10 -#define OPT_DEBUG 11 -#define OPT_BURST_MAX 12 -#define OPT_LED_PIN 13 -#define OPT_MAX_WIDE 14 -#define OPT_SETTLE_DELAY 15 -#define OPT_DIFF_SUPPORT 16 -#define OPT_IRQM 17 -#define OPT_PCI_FIX_UP 18 -#define OPT_BUS_CHECK 19 -#define OPT_OPTIMIZE 20 -#define OPT_RECOVERY 21 -#define OPT_SAFE_SETUP 22 -#define OPT_USE_NVRAM 23 -#define OPT_EXCLUDE 24 -#define OPT_HOST_ID 25 - -#ifdef SCSI_NCR_IARB_SUPPORT -#define OPT_IARB 26 -#endif - -#ifdef MODULE -#define ARG_SEP ' ' -#else -#define ARG_SEP ',' -#endif - -#ifndef MODULE -static char setup_token[] __initdata = - "tags:" "mpar:" - "spar:" "disc:" - "specf:" "ultra:" - "fsn:" "revprob:" - "sync:" "verb:" - "debug:" "burst:" - "led:" "wide:" - "settle:" "diff:" - "irqm:" "pcifix:" - "buschk:" "optim:" - "recovery:" - "safe:" "nvram:" - "excl:" "hostid:" -#ifdef SCSI_NCR_IARB_SUPPORT - "iarb:" -#endif - ; /* DONNOT REMOVE THIS ';' */ - -static int __init get_setup_token(char *p) -{ - char *cur = setup_token; - char *pc; - int i = 0; - - while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { - ++pc; - ++i; - if (!strncmp(p, cur, pc - cur)) - return i; - cur = pc; - } - return 0; -} - -static int __init sym53c8xx__setup(char *str) -{ -#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT - char *cur = str; - char *pc, *pv; - int i, val, c; - int xi = 0; - - while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { - char *pe; - - val = 0; - pv = pc; - c = *++pv; - - if (c == 'n') - val = 0; - else if (c == 'y') - val = 1; - else - val = (int) simple_strtoul(pv, &pe, 0); - - switch (get_setup_token(cur)) { - case OPT_TAGS: - driver_setup.default_tags = val; - if (pe && *pe == '/') { - i = 0; - while (*pe && *pe != ARG_SEP && - i < sizeof(driver_setup.tag_ctrl)-1) { - driver_setup.tag_ctrl[i++] = *pe++; - } - driver_setup.tag_ctrl[i] = '\0'; - } - break; - case OPT_MASTER_PARITY: - driver_setup.master_parity = val; - break; - case OPT_SCSI_PARITY: - driver_setup.scsi_parity = val; - break; - case OPT_DISCONNECTION: - driver_setup.disconnection = val; - break; - case OPT_SPECIAL_FEATURES: - driver_setup.special_features = val; - break; - case OPT_FORCE_SYNC_NEGO: - driver_setup.force_sync_nego = val; - break; - case OPT_REVERSE_PROBE: - driver_setup.reverse_probe = val; - break; - case OPT_DEFAULT_SYNC: - driver_setup.default_sync = val; - break; - case OPT_VERBOSE: - driver_setup.verbose = val; - break; - case OPT_DEBUG: - driver_setup.debug = val; - break; - case OPT_BURST_MAX: - driver_setup.burst_max = val; - break; - case OPT_LED_PIN: - driver_setup.led_pin = val; - break; - case OPT_MAX_WIDE: - driver_setup.max_wide = val? 1:0; - break; - case OPT_SETTLE_DELAY: - driver_setup.settle_delay = val; - break; - case OPT_DIFF_SUPPORT: - driver_setup.diff_support = val; - break; - case OPT_IRQM: - driver_setup.irqm = val; - break; - case OPT_PCI_FIX_UP: - driver_setup.pci_fix_up = val; - break; - case OPT_BUS_CHECK: - driver_setup.bus_check = val; - break; - case OPT_OPTIMIZE: - driver_setup.optimize = val; - break; - case OPT_RECOVERY: - driver_setup.recovery = val; - break; - case OPT_USE_NVRAM: - driver_setup.use_nvram = val; - break; - case OPT_SAFE_SETUP: - memcpy(&driver_setup, &driver_safe_setup, - sizeof(driver_setup)); - break; - case OPT_EXCLUDE: - if (xi < SCSI_NCR_MAX_EXCLUDES) - driver_setup.excludes[xi++] = val; - break; - case OPT_HOST_ID: - driver_setup.host_id = val; - break; -#ifdef SCSI_NCR_IARB_SUPPORT - case OPT_IARB: - driver_setup.iarb = val; - break; -#endif - default: - printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); - break; - } - - if ((cur = strchr(cur, ARG_SEP)) != NULL) - ++cur; - } -#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ - return 1; -} -#endif /* !MODULE */ - -/*=================================================================== -** -** Get device queue depth from boot command line. -** -**=================================================================== -*/ -#define DEF_DEPTH (driver_setup.default_tags) -#define ALL_TARGETS -2 -#define NO_TARGET -1 -#define ALL_LUNS -2 -#define NO_LUN -1 - -static int device_queue_depth(int unit, int target, int lun) -{ - int c, h, t, u, v; - char *p = driver_setup.tag_ctrl; - char *ep; - - h = -1; - t = NO_TARGET; - u = NO_LUN; - while ((c = *p++) != 0) { - v = simple_strtoul(p, &ep, 0); - switch(c) { - case '/': - ++h; - t = ALL_TARGETS; - u = ALL_LUNS; - break; - case 't': - if (t != target) - t = (target == v) ? v : NO_TARGET; - u = ALL_LUNS; - break; - case 'u': - if (u != lun) - u = (lun == v) ? v : NO_LUN; - break; - case 'q': - if (h == unit && - (t == ALL_TARGETS || t == target) && - (u == ALL_LUNS || u == lun)) - return v; - break; - case '-': - t = ALL_TARGETS; - u = ALL_LUNS; - break; - default: - break; - } - p = ep; - } - return DEF_DEPTH; -} - - -/*========================================================== -** -** The CCB done queue uses an array of CCB virtual -** addresses. Empty entries are flagged using the bogus -** virtual address 0xffffffff. -** -** Since PCI ensures that only aligned DWORDs are accessed -** atomically, 64 bit little-endian architecture requires -** to test the high order DWORD of the entry to determine -** if it is empty or valid. -** -** BTW, I will make things differently as soon as I will -** have a better idea, but this is simple and should work. -** -**========================================================== -*/ - -#define SCSI_NCR_CCB_DONE_SUPPORT -#ifdef SCSI_NCR_CCB_DONE_SUPPORT - -#define MAX_DONE 24 -#define CCB_DONE_EMPTY 0xffffffffUL - -/* All 32 bit architectures */ -#if BITS_PER_LONG == 32 -#define CCB_DONE_VALID(cp) (((u_long) cp) != CCB_DONE_EMPTY) - -/* All > 32 bit (64 bit) architectures regardless endian-ness */ -#else -#define CCB_DONE_VALID(cp) \ - ((((u_long) cp) & 0xffffffff00000000ul) && \ - (((u_long) cp) & 0xfffffffful) != CCB_DONE_EMPTY) -#endif - -#endif /* SCSI_NCR_CCB_DONE_SUPPORT */ - -/*========================================================== -** -** Configuration and Debugging -** -**========================================================== -*/ - -/* -** SCSI address of this device. -** The boot routines should have set it. -** If not, use this. -*/ - -#ifndef SCSI_NCR_MYADDR -#define SCSI_NCR_MYADDR (7) -#endif - -/* -** The maximum number of tags per logic unit. -** Used only for disk devices that support tags. -*/ - -#ifndef SCSI_NCR_MAX_TAGS -#define SCSI_NCR_MAX_TAGS (8) -#endif - -/* -** TAGS are actually limited to 64 tags/lun. -** We need to deal with power of 2, for alignment constraints. -*/ -#if SCSI_NCR_MAX_TAGS > 64 -#define MAX_TAGS (64) -#else -#define MAX_TAGS SCSI_NCR_MAX_TAGS -#endif - -#define NO_TAG (255) - -/* -** Choose appropriate type for tag bitmap. -*/ -#if MAX_TAGS > 32 -typedef u64 tagmap_t; -#else -typedef u32 tagmap_t; -#endif - -/* -** Number of targets supported by the driver. -** n permits target numbers 0..n-1. -** Default is 16, meaning targets #0..#15. -** #7 .. is myself. -*/ - -#ifdef SCSI_NCR_MAX_TARGET -#define MAX_TARGET (SCSI_NCR_MAX_TARGET) -#else -#define MAX_TARGET (16) -#endif - -/* -** Number of logic units supported by the driver. -** n enables logic unit numbers 0..n-1. -** The common SCSI devices require only -** one lun, so take 1 as the default. -*/ - -#ifdef SCSI_NCR_MAX_LUN -#define MAX_LUN SCSI_NCR_MAX_LUN -#else -#define MAX_LUN (1) -#endif - -/* -** Asynchronous pre-scaler (ns). Shall be 40 -*/ - -#ifndef SCSI_NCR_MIN_ASYNC -#define SCSI_NCR_MIN_ASYNC (40) -#endif - -/* -** The maximum number of jobs scheduled for starting. -** There should be one slot per target, and one slot -** for each tag of each target in use. -** The calculation below is actually quite silly ... -*/ - -#ifdef SCSI_NCR_CAN_QUEUE -#define MAX_START (SCSI_NCR_CAN_QUEUE + 4) -#else -#define MAX_START (MAX_TARGET + 7 * MAX_TAGS) -#endif - -/* -** We limit the max number of pending IO to 250. -** since we donnot want to allocate more than 1 -** PAGE for 'scripth'. -*/ -#if MAX_START > 250 -#undef MAX_START -#define MAX_START 250 -#endif - -/* -** The maximum number of segments a transfer is split into. -** We support up to 127 segments for both read and write. -** The data scripts are broken into 2 sub-scripts. -** 80 (MAX_SCATTERL) segments are moved from a sub-script -** in on-chip RAM. This makes data transfers shorter than -** 80k (assuming 1k fs) as fast as possible. -*/ - -#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER) - -#if (MAX_SCATTER > 80) -#define MAX_SCATTERL 80 -#define MAX_SCATTERH (MAX_SCATTER - MAX_SCATTERL) -#else -#define MAX_SCATTERL (MAX_SCATTER-1) -#define MAX_SCATTERH 1 -#endif - -/* -** other -*/ - -#define NCR_SNOOP_TIMEOUT (1000000) - -/* -** Other definitions -*/ - -#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f)) - -#define initverbose (driver_setup.verbose) -#define bootverbose (np->verbose) - -/*========================================================== -** -** Command control block states. -** -**========================================================== -*/ - -#define HS_IDLE (0) -#define HS_BUSY (1) -#define HS_NEGOTIATE (2) /* sync/wide data transfer*/ -#define HS_DISCONNECT (3) /* Disconnected by target */ - -#define HS_DONEMASK (0x80) -#define HS_COMPLETE (4|HS_DONEMASK) -#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */ -#define HS_RESET (6|HS_DONEMASK) /* SCSI reset */ -#define HS_ABORTED (7|HS_DONEMASK) /* Transfer aborted */ -#define HS_TIMEOUT (8|HS_DONEMASK) /* Software timeout */ -#define HS_FAIL (9|HS_DONEMASK) /* SCSI or PCI bus errors */ -#define HS_UNEXPECTED (10|HS_DONEMASK)/* Unexpected disconnect */ - -/* -** Invalid host status values used by the SCRIPTS processor -** when the nexus is not fully identified. -** Shall never appear in a CCB. -*/ - -#define HS_INVALMASK (0x40) -#define HS_SELECTING (0|HS_INVALMASK) -#define HS_IN_RESELECT (1|HS_INVALMASK) -#define HS_STARTING (2|HS_INVALMASK) - -/* -** Flags set by the SCRIPT processor for commands -** that have been skipped. -*/ -#define HS_SKIPMASK (0x20) - -/*========================================================== -** -** Software Interrupt Codes -** -**========================================================== -*/ - -#define SIR_BAD_STATUS (1) -#define SIR_XXXXXXXXXX (2) -#define SIR_NEGO_SYNC (3) -#define SIR_NEGO_WIDE (4) -#define SIR_NEGO_FAILED (5) -#define SIR_NEGO_PROTO (6) -#define SIR_REJECT_RECEIVED (7) -#define SIR_REJECT_SENT (8) -#define SIR_IGN_RESIDUE (9) -#define SIR_MISSING_SAVE (10) -#define SIR_RESEL_NO_MSG_IN (11) -#define SIR_RESEL_NO_IDENTIFY (12) -#define SIR_RESEL_BAD_LUN (13) -#define SIR_RESEL_BAD_TARGET (14) -#define SIR_RESEL_BAD_I_T_L (15) -#define SIR_RESEL_BAD_I_T_L_Q (16) -#define SIR_DONE_OVERFLOW (17) -#define SIR_INTFLY (18) -#define SIR_MAX (18) - -/*========================================================== -** -** Extended error codes. -** xerr_status field of struct ccb. -** -**========================================================== -*/ - -#define XE_OK (0) -#define XE_EXTRA_DATA (1) /* unexpected data phase */ -#define XE_BAD_PHASE (2) /* illegal phase (4/5) */ - -/*========================================================== -** -** Negotiation status. -** nego_status field of struct ccb. -** -**========================================================== -*/ - -#define NS_NOCHANGE (0) -#define NS_SYNC (1) -#define NS_WIDE (2) -#define NS_PPR (4) - -/*========================================================== -** -** Misc. -** -**========================================================== -*/ - -#define CCB_MAGIC (0xf2691ad2) - -/*========================================================== -** -** Declaration of structs. -** -**========================================================== -*/ - -static struct scsi_transport_template *ncr53c8xx_transport_template = NULL; - -struct tcb; -struct lcb; -struct ccb; -struct ncb; -struct script; - -struct link { - ncrcmd l_cmd; - ncrcmd l_paddr; -}; - -struct usrcmd { - u_long target; - u_long lun; - u_long data; - u_long cmd; -}; - -#define UC_SETSYNC 10 -#define UC_SETTAGS 11 -#define UC_SETDEBUG 12 -#define UC_SETORDER 13 -#define UC_SETWIDE 14 -#define UC_SETFLAG 15 -#define UC_SETVERBOSE 17 - -#define UF_TRACE (0x01) -#define UF_NODISC (0x02) -#define UF_NOSCAN (0x04) - -/*======================================================================== -** -** Declaration of structs: target control block -** -**======================================================================== -*/ -struct tcb { - /*---------------------------------------------------------------- - ** During reselection the ncr jumps to this point with SFBR - ** set to the encoded target number with bit 7 set. - ** if it's not this target, jump to the next. - ** - ** JUMP IF (SFBR != #target#), @(next tcb) - **---------------------------------------------------------------- - */ - struct link jump_tcb; - - /*---------------------------------------------------------------- - ** Load the actual values for the sxfer and the scntl3 - ** register (sync/wide mode). - ** - ** SCR_COPY (1), @(sval field of this tcb), @(sxfer register) - ** SCR_COPY (1), @(wval field of this tcb), @(scntl3 register) - **---------------------------------------------------------------- - */ - ncrcmd getscr[6]; - - /*---------------------------------------------------------------- - ** Get the IDENTIFY message and load the LUN to SFBR. - ** - ** CALL, - **---------------------------------------------------------------- - */ - struct link call_lun; - - /*---------------------------------------------------------------- - ** Now look for the right lun. - ** - ** For i = 0 to 3 - ** SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(first lcb mod. i) - ** - ** Recent chips will prefetch the 4 JUMPS using only 1 burst. - ** It is kind of hashcoding. - **---------------------------------------------------------------- - */ - struct link jump_lcb[4]; /* JUMPs for reselection */ - struct lcb * lp[MAX_LUN]; /* The lcb's of this tcb */ - - /*---------------------------------------------------------------- - ** Pointer to the ccb used for negotiation. - ** Prevent from starting a negotiation for all queued commands - ** when tagged command queuing is enabled. - **---------------------------------------------------------------- - */ - struct ccb * nego_cp; - - /*---------------------------------------------------------------- - ** statistical data - **---------------------------------------------------------------- - */ - u_long transfers; - u_long bytes; - - /*---------------------------------------------------------------- - ** negotiation of wide and synch transfer and device quirks. - **---------------------------------------------------------------- - */ -#ifdef SCSI_NCR_BIG_ENDIAN -/*0*/ u16 period; -/*2*/ u_char sval; -/*3*/ u_char minsync; -/*0*/ u_char wval; -/*1*/ u_char widedone; -/*2*/ u_char quirks; -/*3*/ u_char maxoffs; -#else -/*0*/ u_char minsync; -/*1*/ u_char sval; -/*2*/ u16 period; -/*0*/ u_char maxoffs; -/*1*/ u_char quirks; -/*2*/ u_char widedone; -/*3*/ u_char wval; -#endif - - /* User settable limits and options. */ - u_char usrsync; - u_char usrwide; - u_char usrtags; - u_char usrflag; - struct scsi_target *starget; -}; - -/*======================================================================== -** -** Declaration of structs: lun control block -** -**======================================================================== -*/ -struct lcb { - /*---------------------------------------------------------------- - ** During reselection the ncr jumps to this point - ** with SFBR set to the "Identify" message. - ** if it's not this lun, jump to the next. - ** - ** JUMP IF (SFBR != #lun#), @(next lcb of this target) - ** - ** It is this lun. Load TEMP with the nexus jumps table - ** address and jump to RESEL_TAG (or RESEL_NOTAG). - ** - ** SCR_COPY (4), p_jump_ccb, TEMP, - ** SCR_JUMP, - **---------------------------------------------------------------- - */ - struct link jump_lcb; - ncrcmd load_jump_ccb[3]; - struct link jump_tag; - ncrcmd p_jump_ccb; /* Jump table bus address */ - - /*---------------------------------------------------------------- - ** Jump table used by the script processor to directly jump - ** to the CCB corresponding to the reselected nexus. - ** Address is allocated on 256 bytes boundary in order to - ** allow 8 bit calculation of the tag jump entry for up to - ** 64 possible tags. - **---------------------------------------------------------------- - */ - u32 jump_ccb_0; /* Default table if no tags */ - u32 *jump_ccb; /* Virtual address */ - - /*---------------------------------------------------------------- - ** CCB queue management. - **---------------------------------------------------------------- - */ - struct list_head free_ccbq; /* Queue of available CCBs */ - struct list_head busy_ccbq; /* Queue of busy CCBs */ - struct list_head wait_ccbq; /* Queue of waiting for IO CCBs */ - struct list_head skip_ccbq; /* Queue of skipped CCBs */ - u_char actccbs; /* Number of allocated CCBs */ - u_char busyccbs; /* CCBs busy for this lun */ - u_char queuedccbs; /* CCBs queued to the controller*/ - u_char queuedepth; /* Queue depth for this lun */ - u_char scdev_depth; /* SCSI device queue depth */ - u_char maxnxs; /* Max possible nexuses */ - - /*---------------------------------------------------------------- - ** Control of tagged command queuing. - ** Tags allocation is performed using a circular buffer. - ** This avoids using a loop for tag allocation. - **---------------------------------------------------------------- - */ - u_char ia_tag; /* Allocation index */ - u_char if_tag; /* Freeing index */ - u_char cb_tags[MAX_TAGS]; /* Circular tags buffer */ - u_char usetags; /* Command queuing is active */ - u_char maxtags; /* Max nr of tags asked by user */ - u_char numtags; /* Current number of tags */ - - /*---------------------------------------------------------------- - ** QUEUE FULL control and ORDERED tag control. - **---------------------------------------------------------------- - */ - /*---------------------------------------------------------------- - ** QUEUE FULL and ORDERED tag control. - **---------------------------------------------------------------- - */ - u16 num_good; /* Nr of GOOD since QUEUE FULL */ - tagmap_t tags_umap; /* Used tags bitmap */ - tagmap_t tags_smap; /* Tags in use at 'tag_stime' */ - u_long tags_stime; /* Last time we set smap=umap */ - struct ccb * held_ccb; /* CCB held for QUEUE FULL */ -}; - -/*======================================================================== -** -** Declaration of structs: the launch script. -** -**======================================================================== -** -** It is part of the CCB and is called by the scripts processor to -** start or restart the data structure (nexus). -** This 6 DWORDs mini script makes use of prefetching. -** -**------------------------------------------------------------------------ -*/ -struct launch { - /*---------------------------------------------------------------- - ** SCR_COPY(4), @(p_phys), @(dsa register) - ** SCR_JUMP, @(scheduler_point) - **---------------------------------------------------------------- - */ - ncrcmd setup_dsa[3]; /* Copy 'phys' address to dsa */ - struct link schedule; /* Jump to scheduler point */ - ncrcmd p_phys; /* 'phys' header bus address */ -}; - -/*======================================================================== -** -** Declaration of structs: global HEADER. -** -**======================================================================== -** -** This substructure is copied from the ccb to a global address after -** selection (or reselection) and copied back before disconnect. -** -** These fields are accessible to the script processor. -** -**------------------------------------------------------------------------ -*/ - -struct head { - /*---------------------------------------------------------------- - ** Saved data pointer. - ** Points to the position in the script responsible for the - ** actual transfer transfer of data. - ** It's written after reception of a SAVE_DATA_POINTER message. - ** The goalpointer points after the last transfer command. - **---------------------------------------------------------------- - */ - u32 savep; - u32 lastp; - u32 goalp; - - /*---------------------------------------------------------------- - ** Alternate data pointer. - ** They are copied back to savep/lastp/goalp by the SCRIPTS - ** when the direction is unknown and the device claims data out. - **---------------------------------------------------------------- - */ - u32 wlastp; - u32 wgoalp; - - /*---------------------------------------------------------------- - ** The virtual address of the ccb containing this header. - **---------------------------------------------------------------- - */ - struct ccb * cp; - - /*---------------------------------------------------------------- - ** Status fields. - **---------------------------------------------------------------- - */ - u_char scr_st[4]; /* script status */ - u_char status[4]; /* host status. must be the */ - /* last DWORD of the header. */ -}; - -/* -** The status bytes are used by the host and the script processor. -** -** The byte corresponding to the host_status must be stored in the -** last DWORD of the CCB header since it is used for command -** completion (ncr_wakeup()). Doing so, we are sure that the header -** has been entirely copied back to the CCB when the host_status is -** seen complete by the CPU. -** -** The last four bytes (status[4]) are copied to the scratchb register -** (declared as scr0..scr3 in ncr_reg.h) just after the select/reselect, -** and copied back just after disconnecting. -** Inside the script the XX_REG are used. -** -** The first four bytes (scr_st[4]) are used inside the script by -** "COPY" commands. -** Because source and destination must have the same alignment -** in a DWORD, the fields HAVE to be at the chosen offsets. -** xerr_st 0 (0x34) scratcha -** sync_st 1 (0x05) sxfer -** wide_st 3 (0x03) scntl3 -*/ - -/* -** Last four bytes (script) -*/ -#define QU_REG scr0 -#define HS_REG scr1 -#define HS_PRT nc_scr1 -#define SS_REG scr2 -#define SS_PRT nc_scr2 -#define PS_REG scr3 - -/* -** Last four bytes (host) -*/ -#ifdef SCSI_NCR_BIG_ENDIAN -#define actualquirks phys.header.status[3] -#define host_status phys.header.status[2] -#define scsi_status phys.header.status[1] -#define parity_status phys.header.status[0] -#else -#define actualquirks phys.header.status[0] -#define host_status phys.header.status[1] -#define scsi_status phys.header.status[2] -#define parity_status phys.header.status[3] -#endif - -/* -** First four bytes (script) -*/ -#define xerr_st header.scr_st[0] -#define sync_st header.scr_st[1] -#define nego_st header.scr_st[2] -#define wide_st header.scr_st[3] - -/* -** First four bytes (host) -*/ -#define xerr_status phys.xerr_st -#define nego_status phys.nego_st - -#if 0 -#define sync_status phys.sync_st -#define wide_status phys.wide_st -#endif - -/*========================================================== -** -** Declaration of structs: Data structure block -** -**========================================================== -** -** During execution of a ccb by the script processor, -** the DSA (data structure address) register points -** to this substructure of the ccb. -** This substructure contains the header with -** the script-processor-changeable data and -** data blocks for the indirect move commands. -** -**---------------------------------------------------------- -*/ - -struct dsb { - - /* - ** Header. - */ - - struct head header; - - /* - ** Table data for Script - */ - - struct scr_tblsel select; - struct scr_tblmove smsg ; - struct scr_tblmove cmd ; - struct scr_tblmove sense ; - struct scr_tblmove data[MAX_SCATTER]; -}; - - -/*======================================================================== -** -** Declaration of structs: Command control block. -** -**======================================================================== -*/ -struct ccb { - /*---------------------------------------------------------------- - ** This is the data structure which is pointed by the DSA - ** register when it is executed by the script processor. - ** It must be the first entry because it contains the header - ** as first entry that must be cache line aligned. - **---------------------------------------------------------------- - */ - struct dsb phys; - - /*---------------------------------------------------------------- - ** Mini-script used at CCB execution start-up. - ** Load the DSA with the data structure address (phys) and - ** jump to SELECT. Jump to CANCEL if CCB is to be canceled. - **---------------------------------------------------------------- - */ - struct launch start; - - /*---------------------------------------------------------------- - ** Mini-script used at CCB relection to restart the nexus. - ** Load the DSA with the data structure address (phys) and - ** jump to RESEL_DSA. Jump to ABORT if CCB is to be aborted. - **---------------------------------------------------------------- - */ - struct launch restart; - - /*---------------------------------------------------------------- - ** If a data transfer phase is terminated too early - ** (after reception of a message (i.e. DISCONNECT)), - ** we have to prepare a mini script to transfer - ** the rest of the data. - **---------------------------------------------------------------- - */ - ncrcmd patch[8]; - - /*---------------------------------------------------------------- - ** The general SCSI driver provides a - ** pointer to a control block. - **---------------------------------------------------------------- - */ - struct scsi_cmnd *cmd; /* SCSI command */ - u_char cdb_buf[16]; /* Copy of CDB */ - u_char sense_buf[64]; - int data_len; /* Total data length */ - - /*---------------------------------------------------------------- - ** Message areas. - ** We prepare a message to be sent after selection. - ** We may use a second one if the command is rescheduled - ** due to GETCC or QFULL. - ** Contents are IDENTIFY and SIMPLE_TAG. - ** While negotiating sync or wide transfer, - ** a SDTR or WDTR message is appended. - **---------------------------------------------------------------- - */ - u_char scsi_smsg [8]; - u_char scsi_smsg2[8]; - - /*---------------------------------------------------------------- - ** Other fields. - **---------------------------------------------------------------- - */ - u_long p_ccb; /* BUS address of this CCB */ - u_char sensecmd[6]; /* Sense command */ - u_char tag; /* Tag for this transfer */ - /* 255 means no tag */ - u_char target; - u_char lun; - u_char queued; - u_char auto_sense; - struct ccb * link_ccb; /* Host adapter CCB chain */ - struct list_head link_ccbq; /* Link to unit CCB queue */ - u32 startp; /* Initial data pointer */ - u_long magic; /* Free / busy CCB flag */ -}; - -#define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl)) - - -/*======================================================================== -** -** Declaration of structs: NCR device descriptor -** -**======================================================================== -*/ -struct ncb { - /*---------------------------------------------------------------- - ** The global header. - ** It is accessible to both the host and the script processor. - ** Must be cache line size aligned (32 for x86) in order to - ** allow cache line bursting when it is copied to/from CCB. - **---------------------------------------------------------------- - */ - struct head header; - - /*---------------------------------------------------------------- - ** CCBs management queues. - **---------------------------------------------------------------- - */ - struct scsi_cmnd *waiting_list; /* Commands waiting for a CCB */ - /* when lcb is not allocated. */ - struct scsi_cmnd *done_list; /* Commands waiting for done() */ - /* callback to be invoked. */ - spinlock_t smp_lock; /* Lock for SMP threading */ - - /*---------------------------------------------------------------- - ** Chip and controller indentification. - **---------------------------------------------------------------- - */ - int unit; /* Unit number */ - char inst_name[16]; /* ncb instance name */ - - /*---------------------------------------------------------------- - ** Initial value of some IO register bits. - ** These values are assumed to have been set by BIOS, and may - ** be used for probing adapter implementation differences. - **---------------------------------------------------------------- - */ - u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest0, sv_ctest3, - sv_ctest4, sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4; - - /*---------------------------------------------------------------- - ** Actual initial value of IO register bits used by the - ** driver. They are loaded at initialisation according to - ** features that are to be enabled. - **---------------------------------------------------------------- - */ - u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest0, rv_ctest3, - rv_ctest4, rv_ctest5, rv_stest2; - - /*---------------------------------------------------------------- - ** Targets management. - ** During reselection the ncr jumps to jump_tcb. - ** The SFBR register is loaded with the encoded target id. - ** For i = 0 to 3 - ** SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(next tcb mod. i) - ** - ** Recent chips will prefetch the 4 JUMPS using only 1 burst. - ** It is kind of hashcoding. - **---------------------------------------------------------------- - */ - struct link jump_tcb[4]; /* JUMPs for reselection */ - struct tcb target[MAX_TARGET]; /* Target data */ - - /*---------------------------------------------------------------- - ** Virtual and physical bus addresses of the chip. - **---------------------------------------------------------------- - */ - void __iomem *vaddr; /* Virtual and bus address of */ - unsigned long paddr; /* chip's IO registers. */ - unsigned long paddr2; /* On-chip RAM bus address. */ - volatile /* Pointer to volatile for */ - struct ncr_reg __iomem *reg; /* memory mapped IO. */ - - /*---------------------------------------------------------------- - ** SCRIPTS virtual and physical bus addresses. - ** 'script' is loaded in the on-chip RAM if present. - ** 'scripth' stays in main memory. - **---------------------------------------------------------------- - */ - struct script *script0; /* Copies of script and scripth */ - struct scripth *scripth0; /* relocated for this ncb. */ - struct scripth *scripth; /* Actual scripth virt. address */ - u_long p_script; /* Actual script and scripth */ - u_long p_scripth; /* bus addresses. */ - - /*---------------------------------------------------------------- - ** General controller parameters and configuration. - **---------------------------------------------------------------- - */ - struct device *dev; - u_char revision_id; /* PCI device revision id */ - u32 irq; /* IRQ level */ - u32 features; /* Chip features map */ - u_char myaddr; /* SCSI id of the adapter */ - u_char maxburst; /* log base 2 of dwords burst */ - u_char maxwide; /* Maximum transfer width */ - u_char minsync; /* Minimum sync period factor */ - u_char maxsync; /* Maximum sync period factor */ - u_char maxoffs; /* Max scsi offset */ - u_char multiplier; /* Clock multiplier (1,2,4) */ - u_char clock_divn; /* Number of clock divisors */ - u_long clock_khz; /* SCSI clock frequency in KHz */ - - /*---------------------------------------------------------------- - ** Start queue management. - ** It is filled up by the host processor and accessed by the - ** SCRIPTS processor in order to start SCSI commands. - **---------------------------------------------------------------- - */ - u16 squeueput; /* Next free slot of the queue */ - u16 actccbs; /* Number of allocated CCBs */ - u16 queuedccbs; /* Number of CCBs in start queue*/ - u16 queuedepth; /* Start queue depth */ - - /*---------------------------------------------------------------- - ** Timeout handler. - **---------------------------------------------------------------- - */ - struct timer_list timer; /* Timer handler link header */ - u_long lasttime; - u_long settle_time; /* Resetting the SCSI BUS */ - - /*---------------------------------------------------------------- - ** Debugging and profiling. - **---------------------------------------------------------------- - */ - struct ncr_reg regdump; /* Register dump */ - u_long regtime; /* Time it has been done */ - - /*---------------------------------------------------------------- - ** Miscellaneous buffers accessed by the scripts-processor. - ** They shall be DWORD aligned, because they may be read or - ** written with a SCR_COPY script command. - **---------------------------------------------------------------- - */ - u_char msgout[8]; /* Buffer for MESSAGE OUT */ - u_char msgin [8]; /* Buffer for MESSAGE IN */ - u32 lastmsg; /* Last SCSI message sent */ - u_char scratch; /* Scratch for SCSI receive */ - - /*---------------------------------------------------------------- - ** Miscellaneous configuration and status parameters. - **---------------------------------------------------------------- - */ - u_char disc; /* Diconnection allowed */ - u_char scsi_mode; /* Current SCSI BUS mode */ - u_char order; /* Tag order to use */ - u_char verbose; /* Verbosity for this controller*/ - int ncr_cache; /* Used for cache test at init. */ - u_long p_ncb; /* BUS address of this NCB */ - - /*---------------------------------------------------------------- - ** Command completion handling. - **---------------------------------------------------------------- - */ -#ifdef SCSI_NCR_CCB_DONE_SUPPORT - struct ccb *(ccb_done[MAX_DONE]); - int ccb_done_ic; -#endif - /*---------------------------------------------------------------- - ** Fields that should be removed or changed. - **---------------------------------------------------------------- - */ - struct ccb *ccb; /* Global CCB */ - struct usrcmd user; /* Command from user */ - volatile u_char release_stage; /* Synchronisation stage on release */ -}; - -#define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) -#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl)) - -/*========================================================== -** -** -** Script for NCR-Processor. -** -** Use ncr_script_fill() to create the variable parts. -** Use ncr_script_copy_and_bind() to make a copy and -** bind to physical addresses. -** -** -**========================================================== -** -** We have to know the offsets of all labels before -** we reach them (for forward jumps). -** Therefore we declare a struct here. -** If you make changes inside the script, -** DONT FORGET TO CHANGE THE LENGTHS HERE! -** -**---------------------------------------------------------- -*/ - -/* -** For HP Zalon/53c720 systems, the Zalon interface -** between CPU and 53c720 does prefetches, which causes -** problems with self modifying scripts. The problem -** is overcome by calling a dummy subroutine after each -** modification, to force a refetch of the script on -** return from the subroutine. -*/ - -#ifdef CONFIG_NCR53C8XX_PREFETCH -#define PREFETCH_FLUSH_CNT 2 -#define PREFETCH_FLUSH SCR_CALL, PADDRH (wait_dma), -#else -#define PREFETCH_FLUSH_CNT 0 -#define PREFETCH_FLUSH -#endif - -/* -** Script fragments which are loaded into the on-chip RAM -** of 825A, 875 and 895 chips. -*/ -struct script { - ncrcmd start [ 5]; - ncrcmd startpos [ 1]; - ncrcmd select [ 6]; - ncrcmd select2 [ 9 + PREFETCH_FLUSH_CNT]; - ncrcmd loadpos [ 4]; - ncrcmd send_ident [ 9]; - ncrcmd prepare [ 6]; - ncrcmd prepare2 [ 7]; - ncrcmd command [ 6]; - ncrcmd dispatch [ 32]; - ncrcmd clrack [ 4]; - ncrcmd no_data [ 17]; - ncrcmd status [ 8]; - ncrcmd msg_in [ 2]; - ncrcmd msg_in2 [ 16]; - ncrcmd msg_bad [ 4]; - ncrcmd setmsg [ 7]; - ncrcmd cleanup [ 6]; - ncrcmd complete [ 9]; - ncrcmd cleanup_ok [ 8 + PREFETCH_FLUSH_CNT]; - ncrcmd cleanup0 [ 1]; -#ifndef SCSI_NCR_CCB_DONE_SUPPORT - ncrcmd signal [ 12]; -#else - ncrcmd signal [ 9]; - ncrcmd done_pos [ 1]; - ncrcmd done_plug [ 2]; - ncrcmd done_end [ 7]; -#endif - ncrcmd save_dp [ 7]; - ncrcmd restore_dp [ 5]; - ncrcmd disconnect [ 10]; - ncrcmd msg_out [ 9]; - ncrcmd msg_out_done [ 7]; - ncrcmd idle [ 2]; - ncrcmd reselect [ 8]; - ncrcmd reselected [ 8]; - ncrcmd resel_dsa [ 6 + PREFETCH_FLUSH_CNT]; - ncrcmd loadpos1 [ 4]; - ncrcmd resel_lun [ 6]; - ncrcmd resel_tag [ 6]; - ncrcmd jump_to_nexus [ 4 + PREFETCH_FLUSH_CNT]; - ncrcmd nexus_indirect [ 4]; - ncrcmd resel_notag [ 4]; - ncrcmd data_in [MAX_SCATTERL * 4]; - ncrcmd data_in2 [ 4]; - ncrcmd data_out [MAX_SCATTERL * 4]; - ncrcmd data_out2 [ 4]; -}; - -/* -** Script fragments which stay in main memory for all chips. -*/ -struct scripth { - ncrcmd tryloop [MAX_START*2]; - ncrcmd tryloop2 [ 2]; -#ifdef SCSI_NCR_CCB_DONE_SUPPORT - ncrcmd done_queue [MAX_DONE*5]; - ncrcmd done_queue2 [ 2]; -#endif - ncrcmd select_no_atn [ 8]; - ncrcmd cancel [ 4]; - ncrcmd skip [ 9 + PREFETCH_FLUSH_CNT]; - ncrcmd skip2 [ 19]; - ncrcmd par_err_data_in [ 6]; - ncrcmd par_err_other [ 4]; - ncrcmd msg_reject [ 8]; - ncrcmd msg_ign_residue [ 24]; - ncrcmd msg_extended [ 10]; - ncrcmd msg_ext_2 [ 10]; - ncrcmd msg_wdtr [ 14]; - ncrcmd send_wdtr [ 7]; - ncrcmd msg_ext_3 [ 10]; - ncrcmd msg_sdtr [ 14]; - ncrcmd send_sdtr [ 7]; - ncrcmd nego_bad_phase [ 4]; - ncrcmd msg_out_abort [ 10]; - ncrcmd hdata_in [MAX_SCATTERH * 4]; - ncrcmd hdata_in2 [ 2]; - ncrcmd hdata_out [MAX_SCATTERH * 4]; - ncrcmd hdata_out2 [ 2]; - ncrcmd reset [ 4]; - ncrcmd aborttag [ 4]; - ncrcmd abort [ 2]; - ncrcmd abort_resel [ 20]; - ncrcmd resend_ident [ 4]; - ncrcmd clratn_go_on [ 3]; - ncrcmd nxtdsp_go_on [ 1]; - ncrcmd sdata_in [ 8]; - ncrcmd data_io [ 18]; - ncrcmd bad_identify [ 12]; - ncrcmd bad_i_t_l [ 4]; - ncrcmd bad_i_t_l_q [ 4]; - ncrcmd bad_target [ 8]; - ncrcmd bad_status [ 8]; - ncrcmd start_ram [ 4 + PREFETCH_FLUSH_CNT]; - ncrcmd start_ram0 [ 4]; - ncrcmd sto_restart [ 5]; - ncrcmd wait_dma [ 2]; - ncrcmd snooptest [ 9]; - ncrcmd snoopend [ 2]; -}; - -/*========================================================== -** -** -** Function headers. -** -** -**========================================================== -*/ - -static void ncr_alloc_ccb (struct ncb *np, u_char tn, u_char ln); -static void ncr_complete (struct ncb *np, struct ccb *cp); -static void ncr_exception (struct ncb *np); -static void ncr_free_ccb (struct ncb *np, struct ccb *cp); -static void ncr_init_ccb (struct ncb *np, struct ccb *cp); -static void ncr_init_tcb (struct ncb *np, u_char tn); -static struct lcb * ncr_alloc_lcb (struct ncb *np, u_char tn, u_char ln); -static struct lcb * ncr_setup_lcb (struct ncb *np, struct scsi_device *sdev); -static void ncr_getclock (struct ncb *np, int mult); -static void ncr_selectclock (struct ncb *np, u_char scntl3); -static struct ccb *ncr_get_ccb (struct ncb *np, struct scsi_cmnd *cmd); -static void ncr_chip_reset (struct ncb *np, int delay); -static void ncr_init (struct ncb *np, int reset, char * msg, u_long code); -static int ncr_int_sbmc (struct ncb *np); -static int ncr_int_par (struct ncb *np); -static void ncr_int_ma (struct ncb *np); -static void ncr_int_sir (struct ncb *np); -static void ncr_int_sto (struct ncb *np); -static void ncr_negotiate (struct ncb* np, struct tcb* tp); -static int ncr_prepare_nego(struct ncb *np, struct ccb *cp, u_char *msgptr); - -static void ncr_script_copy_and_bind - (struct ncb *np, ncrcmd *src, ncrcmd *dst, int len); -static void ncr_script_fill (struct script * scr, struct scripth * scripth); -static int ncr_scatter (struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd); -static void ncr_getsync (struct ncb *np, u_char sfac, u_char *fakp, u_char *scntl3p); -static void ncr_setsync (struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer); -static void ncr_setup_tags (struct ncb *np, struct scsi_device *sdev); -static void ncr_setwide (struct ncb *np, struct ccb *cp, u_char wide, u_char ack); -static int ncr_snooptest (struct ncb *np); -static void ncr_timeout (struct ncb *np); -static void ncr_wakeup (struct ncb *np, u_long code); -static void ncr_wakeup_done (struct ncb *np); -static void ncr_start_next_ccb (struct ncb *np, struct lcb * lp, int maxn); -static void ncr_put_start_queue(struct ncb *np, struct ccb *cp); - -static void insert_into_waiting_list(struct ncb *np, struct scsi_cmnd *cmd); -static struct scsi_cmnd *retrieve_from_waiting_list(int to_remove, struct ncb *np, struct scsi_cmnd *cmd); -static void process_waiting_list(struct ncb *np, int sts); - -#define remove_from_waiting_list(np, cmd) \ - retrieve_from_waiting_list(1, (np), (cmd)) -#define requeue_waiting_list(np) process_waiting_list((np), DID_OK) -#define reset_waiting_list(np) process_waiting_list((np), DID_RESET) - -static inline char *ncr_name (struct ncb *np) -{ - return np->inst_name; -} - - -/*========================================================== -** -** -** Scripts for NCR-Processor. -** -** Use ncr_script_bind for binding to physical addresses. -** -** -**========================================================== -** -** NADDR generates a reference to a field of the controller data. -** PADDR generates a reference to another part of the script. -** RADDR generates a reference to a script processor register. -** FADDR generates a reference to a script processor register -** with offset. -** -**---------------------------------------------------------- -*/ - -#define RELOC_SOFTC 0x40000000 -#define RELOC_LABEL 0x50000000 -#define RELOC_REGISTER 0x60000000 -#if 0 -#define RELOC_KVAR 0x70000000 -#endif -#define RELOC_LABELH 0x80000000 -#define RELOC_MASK 0xf0000000 - -#define NADDR(label) (RELOC_SOFTC | offsetof(struct ncb, label)) -#define PADDR(label) (RELOC_LABEL | offsetof(struct script, label)) -#define PADDRH(label) (RELOC_LABELH | offsetof(struct scripth, label)) -#define RADDR(label) (RELOC_REGISTER | REG(label)) -#define FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs))) -#if 0 -#define KVAR(which) (RELOC_KVAR | (which)) -#endif - -#if 0 -#define SCRIPT_KVAR_JIFFIES (0) -#define SCRIPT_KVAR_FIRST SCRIPT_KVAR_JIFFIES -#define SCRIPT_KVAR_LAST SCRIPT_KVAR_JIFFIES -/* - * Kernel variables referenced in the scripts. - * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY. - */ -static void *script_kvars[] __initdata = - { (void *)&jiffies }; -#endif - -static struct script script0 __initdata = { -/*--------------------------< START >-----------------------*/ { - /* - ** This NOP will be patched with LED ON - ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) - */ - SCR_NO_OP, - 0, - /* - ** Clear SIGP. - */ - SCR_FROM_REG (ctest2), - 0, - /* - ** Then jump to a certain point in tryloop. - ** Due to the lack of indirect addressing the code - ** is self modifying here. - */ - SCR_JUMP, -}/*-------------------------< STARTPOS >--------------------*/,{ - PADDRH(tryloop), - -}/*-------------------------< SELECT >----------------------*/,{ - /* - ** DSA contains the address of a scheduled - ** data structure. - ** - ** SCRATCHA contains the address of the script, - ** which starts the next entry. - ** - ** Set Initiator mode. - ** - ** (Target mode is left as an exercise for the reader) - */ - - SCR_CLR (SCR_TRG), - 0, - SCR_LOAD_REG (HS_REG, HS_SELECTING), - 0, - - /* - ** And try to select this target. - */ - SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select), - PADDR (reselect), - -}/*-------------------------< SELECT2 >----------------------*/,{ - /* - ** Now there are 4 possibilities: - ** - ** (1) The ncr loses arbitration. - ** This is ok, because it will try again, - ** when the bus becomes idle. - ** (But beware of the timeout function!) - ** - ** (2) The ncr is reselected. - ** Then the script processor takes the jump - ** to the RESELECT label. - ** - ** (3) The ncr wins arbitration. - ** Then it will execute SCRIPTS instruction until - ** the next instruction that checks SCSI phase. - ** Then will stop and wait for selection to be - ** complete or selection time-out to occur. - ** As a result the SCRIPTS instructions until - ** LOADPOS + 2 should be executed in parallel with - ** the SCSI core performing selection. - */ - - /* - ** The MESSAGE_REJECT problem seems to be due to a selection - ** timing problem. - ** Wait immediately for the selection to complete. - ** (2.5x behaves so) - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), - 0, - - /* - ** Next time use the next slot. - */ - SCR_COPY (4), - RADDR (temp), - PADDR (startpos), - /* - ** The ncr doesn't have an indirect load - ** or store command. So we have to - ** copy part of the control block to a - ** fixed place, where we can access it. - ** - ** We patch the address part of a - ** COPY command with the DSA-register. - */ - SCR_COPY_F (4), - RADDR (dsa), - PADDR (loadpos), - /* - ** Flush script prefetch if required - */ - PREFETCH_FLUSH - /* - ** then we do the actual copy. - */ - SCR_COPY (sizeof (struct head)), - /* - ** continued after the next label ... - */ -}/*-------------------------< LOADPOS >---------------------*/,{ - 0, - NADDR (header), - /* - ** Wait for the next phase or the selection - ** to complete or time-out. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDR (prepare), - -}/*-------------------------< SEND_IDENT >----------------------*/,{ - /* - ** Selection complete. - ** Send the IDENTIFY and SIMPLE_TAG messages - ** (and the EXTENDED_SDTR message) - */ - SCR_MOVE_TBL ^ SCR_MSG_OUT, - offsetof (struct dsb, smsg), - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), - PADDRH (resend_ident), - SCR_LOAD_REG (scratcha, 0x80), - 0, - SCR_COPY (1), - RADDR (scratcha), - NADDR (lastmsg), -}/*-------------------------< PREPARE >----------------------*/,{ - /* - ** load the savep (saved pointer) into - ** the TEMP register (actual pointer) - */ - SCR_COPY (4), - NADDR (header.savep), - RADDR (temp), - /* - ** Initialize the status registers - */ - SCR_COPY (4), - NADDR (header.status), - RADDR (scr0), -}/*-------------------------< PREPARE2 >---------------------*/,{ - /* - ** Initialize the msgout buffer with a NOOP message. - */ - SCR_LOAD_REG (scratcha, NOP), - 0, - SCR_COPY (1), - RADDR (scratcha), - NADDR (msgout), -#if 0 - SCR_COPY (1), - RADDR (scratcha), - NADDR (msgin), -#endif - /* - ** Anticipate the COMMAND phase. - ** This is the normal case for initial selection. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)), - PADDR (dispatch), - -}/*-------------------------< COMMAND >--------------------*/,{ - /* - ** ... and send the command - */ - SCR_MOVE_TBL ^ SCR_COMMAND, - offsetof (struct dsb, cmd), - /* - ** If status is still HS_NEGOTIATE, negotiation failed. - ** We check this here, since we want to do that - ** only once. - */ - SCR_FROM_REG (HS_REG), - 0, - SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), - SIR_NEGO_FAILED, - -}/*-----------------------< DISPATCH >----------------------*/,{ - /* - ** MSG_IN is the only phase that shall be - ** entered at least once for each (re)selection. - ** So we test it first. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR (msg_in), - - SCR_RETURN ^ IFTRUE (IF (SCR_DATA_OUT)), - 0, - /* - ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 4. - ** Possible data corruption during Memory Write and Invalidate. - ** This work-around resets the addressing logic prior to the - ** start of the first MOVE of a DATA IN phase. - ** (See Documentation/scsi/ncr53c8xx.txt for more information) - */ - SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)), - 20, - SCR_COPY (4), - RADDR (scratcha), - RADDR (scratcha), - SCR_RETURN, - 0, - SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), - PADDR (status), - SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), - PADDR (command), - SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), - PADDR (msg_out), - /* - ** Discard one illegal phase byte, if required. - */ - SCR_LOAD_REG (scratcha, XE_BAD_PHASE), - 0, - SCR_COPY (1), - RADDR (scratcha), - NADDR (xerr_st), - SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)), - 8, - SCR_MOVE_ABS (1) ^ SCR_ILG_OUT, - NADDR (scratch), - SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)), - 8, - SCR_MOVE_ABS (1) ^ SCR_ILG_IN, - NADDR (scratch), - SCR_JUMP, - PADDR (dispatch), - -}/*-------------------------< CLRACK >----------------------*/,{ - /* - ** Terminate possible pending message phase. - */ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP, - PADDR (dispatch), - -}/*-------------------------< NO_DATA >--------------------*/,{ - /* - ** The target wants to tranfer too much data - ** or in the wrong direction. - ** Remember that in extended error. - */ - SCR_LOAD_REG (scratcha, XE_EXTRA_DATA), - 0, - SCR_COPY (1), - RADDR (scratcha), - NADDR (xerr_st), - /* - ** Discard one data byte, if required. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), - 8, - SCR_MOVE_ABS (1) ^ SCR_DATA_OUT, - NADDR (scratch), - SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)), - 8, - SCR_MOVE_ABS (1) ^ SCR_DATA_IN, - NADDR (scratch), - /* - ** .. and repeat as required. - */ - SCR_CALL, - PADDR (dispatch), - SCR_JUMP, - PADDR (no_data), - -}/*-------------------------< STATUS >--------------------*/,{ - /* - ** get the status - */ - SCR_MOVE_ABS (1) ^ SCR_STATUS, - NADDR (scratch), - /* - ** save status to scsi_status. - ** mark as complete. - */ - SCR_TO_REG (SS_REG), - 0, - SCR_LOAD_REG (HS_REG, HS_COMPLETE), - 0, - SCR_JUMP, - PADDR (dispatch), -}/*-------------------------< MSG_IN >--------------------*/,{ - /* - ** Get the first byte of the message - ** and save it to SCRATCHA. - ** - ** The script processor doesn't negate the - ** ACK signal after this transfer. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[0]), -}/*-------------------------< MSG_IN2 >--------------------*/,{ - /* - ** Handle this message. - */ - SCR_JUMP ^ IFTRUE (DATA (COMMAND_COMPLETE)), - PADDR (complete), - SCR_JUMP ^ IFTRUE (DATA (DISCONNECT)), - PADDR (disconnect), - SCR_JUMP ^ IFTRUE (DATA (SAVE_POINTERS)), - PADDR (save_dp), - SCR_JUMP ^ IFTRUE (DATA (RESTORE_POINTERS)), - PADDR (restore_dp), - SCR_JUMP ^ IFTRUE (DATA (EXTENDED_MESSAGE)), - PADDRH (msg_extended), - SCR_JUMP ^ IFTRUE (DATA (NOP)), - PADDR (clrack), - SCR_JUMP ^ IFTRUE (DATA (MESSAGE_REJECT)), - PADDRH (msg_reject), - SCR_JUMP ^ IFTRUE (DATA (IGNORE_WIDE_RESIDUE)), - PADDRH (msg_ign_residue), - /* - ** Rest of the messages left as - ** an exercise ... - ** - ** Unimplemented messages: - ** fall through to MSG_BAD. - */ -}/*-------------------------< MSG_BAD >------------------*/,{ - /* - ** unimplemented message - reject it. - */ - SCR_INT, - SIR_REJECT_SENT, - SCR_LOAD_REG (scratcha, MESSAGE_REJECT), - 0, -}/*-------------------------< SETMSG >----------------------*/,{ - SCR_COPY (1), - RADDR (scratcha), - NADDR (msgout), - SCR_SET (SCR_ATN), - 0, - SCR_JUMP, - PADDR (clrack), -}/*-------------------------< CLEANUP >-------------------*/,{ - /* - ** dsa: Pointer to ccb - ** or xxxxxxFF (no ccb) - ** - ** HS_REG: Host-Status (<>0!) - */ - SCR_FROM_REG (dsa), - 0, - SCR_JUMP ^ IFTRUE (DATA (0xff)), - PADDR (start), - /* - ** dsa is valid. - ** complete the cleanup. - */ - SCR_JUMP, - PADDR (cleanup_ok), - -}/*-------------------------< COMPLETE >-----------------*/,{ - /* - ** Complete message. - ** - ** Copy TEMP register to LASTP in header. - */ - SCR_COPY (4), - RADDR (temp), - NADDR (header.lastp), - /* - ** When we terminate the cycle by clearing ACK, - ** the target may disconnect immediately. - ** - ** We don't want to be told of an - ** "unexpected disconnect", - ** so we disable this feature. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - /* - ** Terminate cycle ... - */ - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - /* - ** ... and wait for the disconnect. - */ - SCR_WAIT_DISC, - 0, -}/*-------------------------< CLEANUP_OK >----------------*/,{ - /* - ** Save host status to header. - */ - SCR_COPY (4), - RADDR (scr0), - NADDR (header.status), - /* - ** and copy back the header to the ccb. - */ - SCR_COPY_F (4), - RADDR (dsa), - PADDR (cleanup0), - /* - ** Flush script prefetch if required - */ - PREFETCH_FLUSH - SCR_COPY (sizeof (struct head)), - NADDR (header), -}/*-------------------------< CLEANUP0 >--------------------*/,{ - 0, -}/*-------------------------< SIGNAL >----------------------*/,{ - /* - ** if job not completed ... - */ - SCR_FROM_REG (HS_REG), - 0, - /* - ** ... start the next command. - */ - SCR_JUMP ^ IFTRUE (MASK (0, (HS_DONEMASK|HS_SKIPMASK))), - PADDR(start), - /* - ** If command resulted in not GOOD status, - ** call the C code if needed. - */ - SCR_FROM_REG (SS_REG), - 0, - SCR_CALL ^ IFFALSE (DATA (S_GOOD)), - PADDRH (bad_status), - -#ifndef SCSI_NCR_CCB_DONE_SUPPORT - - /* - ** ... signal completion to the host - */ - SCR_INT, - SIR_INTFLY, - /* - ** Auf zu neuen Schandtaten! - */ - SCR_JUMP, - PADDR(start), - -#else /* defined SCSI_NCR_CCB_DONE_SUPPORT */ - - /* - ** ... signal completion to the host - */ - SCR_JUMP, -}/*------------------------< DONE_POS >---------------------*/,{ - PADDRH (done_queue), -}/*------------------------< DONE_PLUG >--------------------*/,{ - SCR_INT, - SIR_DONE_OVERFLOW, -}/*------------------------< DONE_END >---------------------*/,{ - SCR_INT, - SIR_INTFLY, - SCR_COPY (4), - RADDR (temp), - PADDR (done_pos), - SCR_JUMP, - PADDR (start), - -#endif /* SCSI_NCR_CCB_DONE_SUPPORT */ - -}/*-------------------------< SAVE_DP >------------------*/,{ - /* - ** SAVE_DP message: - ** Copy TEMP register to SAVEP in header. - */ - SCR_COPY (4), - RADDR (temp), - NADDR (header.savep), - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP, - PADDR (dispatch), -}/*-------------------------< RESTORE_DP >---------------*/,{ - /* - ** RESTORE_DP message: - ** Copy SAVEP in header to TEMP register. - */ - SCR_COPY (4), - NADDR (header.savep), - RADDR (temp), - SCR_JUMP, - PADDR (clrack), - -}/*-------------------------< DISCONNECT >---------------*/,{ - /* - ** DISCONNECTing ... - ** - ** disable the "unexpected disconnect" feature, - ** and remove the ACK signal. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - /* - ** Wait for the disconnect. - */ - SCR_WAIT_DISC, - 0, - /* - ** Status is: DISCONNECTED. - */ - SCR_LOAD_REG (HS_REG, HS_DISCONNECT), - 0, - SCR_JUMP, - PADDR (cleanup_ok), - -}/*-------------------------< MSG_OUT >-------------------*/,{ - /* - ** The target requests a message. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, - NADDR (msgout), - SCR_COPY (1), - NADDR (msgout), - NADDR (lastmsg), - /* - ** If it was no ABORT message ... - */ - SCR_JUMP ^ IFTRUE (DATA (ABORT_TASK_SET)), - PADDRH (msg_out_abort), - /* - ** ... wait for the next phase - ** if it's a message out, send it again, ... - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), - PADDR (msg_out), -}/*-------------------------< MSG_OUT_DONE >--------------*/,{ - /* - ** ... else clear the message ... - */ - SCR_LOAD_REG (scratcha, NOP), - 0, - SCR_COPY (4), - RADDR (scratcha), - NADDR (msgout), - /* - ** ... and process the next phase - */ - SCR_JUMP, - PADDR (dispatch), -}/*-------------------------< IDLE >------------------------*/,{ - /* - ** Nothing to do? - ** Wait for reselect. - ** This NOP will be patched with LED OFF - ** SCR_REG_REG (gpreg, SCR_OR, 0x01) - */ - SCR_NO_OP, - 0, -}/*-------------------------< RESELECT >--------------------*/,{ - /* - ** make the DSA invalid. - */ - SCR_LOAD_REG (dsa, 0xff), - 0, - SCR_CLR (SCR_TRG), - 0, - SCR_LOAD_REG (HS_REG, HS_IN_RESELECT), - 0, - /* - ** Sleep waiting for a reselection. - ** If SIGP is set, special treatment. - ** - ** Zu allem bereit .. - */ - SCR_WAIT_RESEL, - PADDR(start), -}/*-------------------------< RESELECTED >------------------*/,{ - /* - ** This NOP will be patched with LED ON - ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) - */ - SCR_NO_OP, - 0, - /* - ** ... zu nichts zu gebrauchen ? - ** - ** load the target id into the SFBR - ** and jump to the control block. - ** - ** Look at the declarations of - ** - struct ncb - ** - struct tcb - ** - struct lcb - ** - struct ccb - ** to understand what's going on. - */ - SCR_REG_SFBR (ssid, SCR_AND, 0x8F), - 0, - SCR_TO_REG (sdid), - 0, - SCR_JUMP, - NADDR (jump_tcb), - -}/*-------------------------< RESEL_DSA >-------------------*/,{ - /* - ** Ack the IDENTIFY or TAG previously received. - */ - SCR_CLR (SCR_ACK), - 0, - /* - ** The ncr doesn't have an indirect load - ** or store command. So we have to - ** copy part of the control block to a - ** fixed place, where we can access it. - ** - ** We patch the address part of a - ** COPY command with the DSA-register. - */ - SCR_COPY_F (4), - RADDR (dsa), - PADDR (loadpos1), - /* - ** Flush script prefetch if required - */ - PREFETCH_FLUSH - /* - ** then we do the actual copy. - */ - SCR_COPY (sizeof (struct head)), - /* - ** continued after the next label ... - */ - -}/*-------------------------< LOADPOS1 >-------------------*/,{ - 0, - NADDR (header), - /* - ** The DSA contains the data structure address. - */ - SCR_JUMP, - PADDR (prepare), - -}/*-------------------------< RESEL_LUN >-------------------*/,{ - /* - ** come back to this point - ** to get an IDENTIFY message - ** Wait for a msg_in phase. - */ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), - SIR_RESEL_NO_MSG_IN, - /* - ** message phase. - ** Read the data directly from the BUS DATA lines. - ** This helps to support very old SCSI devices that - ** may reselect without sending an IDENTIFY. - */ - SCR_FROM_REG (sbdl), - 0, - /* - ** It should be an Identify message. - */ - SCR_RETURN, - 0, -}/*-------------------------< RESEL_TAG >-------------------*/,{ - /* - ** Read IDENTIFY + SIMPLE + TAG using a single MOVE. - ** Aggressive optimization, is'nt it? - ** No need to test the SIMPLE TAG message, since the - ** driver only supports conformant devices for tags. ;-) - */ - SCR_MOVE_ABS (3) ^ SCR_MSG_IN, - NADDR (msgin), - /* - ** Read the TAG from the SIDL. - ** Still an aggressive optimization. ;-) - ** Compute the CCB indirect jump address which - ** is (#TAG*2 & 0xfc) due to tag numbering using - ** 1,3,5..MAXTAGS*2+1 actual values. - */ - SCR_REG_SFBR (sidl, SCR_SHL, 0), - 0, - SCR_SFBR_REG (temp, SCR_AND, 0xfc), - 0, -}/*-------------------------< JUMP_TO_NEXUS >-------------------*/,{ - SCR_COPY_F (4), - RADDR (temp), - PADDR (nexus_indirect), - /* - ** Flush script prefetch if required - */ - PREFETCH_FLUSH - SCR_COPY (4), -}/*-------------------------< NEXUS_INDIRECT >-------------------*/,{ - 0, - RADDR (temp), - SCR_RETURN, - 0, -}/*-------------------------< RESEL_NOTAG >-------------------*/,{ - /* - ** No tag expected. - ** Read an throw away the IDENTIFY. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_JUMP, - PADDR (jump_to_nexus), -}/*-------------------------< DATA_IN >--------------------*/,{ -/* -** Because the size depends on the -** #define MAX_SCATTERL parameter, -** it is filled in at runtime. -** -** ##===========< i=0; i========= -** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), -** || PADDR (dispatch), -** || SCR_MOVE_TBL ^ SCR_DATA_IN, -** || offsetof (struct dsb, data[ i]), -** ##========================================== -** -**--------------------------------------------------------- -*/ -0 -}/*-------------------------< DATA_IN2 >-------------------*/,{ - SCR_CALL, - PADDR (dispatch), - SCR_JUMP, - PADDR (no_data), -}/*-------------------------< DATA_OUT >--------------------*/,{ -/* -** Because the size depends on the -** #define MAX_SCATTERL parameter, -** it is filled in at runtime. -** -** ##===========< i=0; i========= -** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), -** || PADDR (dispatch), -** || SCR_MOVE_TBL ^ SCR_DATA_OUT, -** || offsetof (struct dsb, data[ i]), -** ##========================================== -** -**--------------------------------------------------------- -*/ -0 -}/*-------------------------< DATA_OUT2 >-------------------*/,{ - SCR_CALL, - PADDR (dispatch), - SCR_JUMP, - PADDR (no_data), -}/*--------------------------------------------------------*/ -}; - -static struct scripth scripth0 __initdata = { -/*-------------------------< TRYLOOP >---------------------*/{ -/* -** Start the next entry. -** Called addresses point to the launch script in the CCB. -** They are patched by the main processor. -** -** Because the size depends on the -** #define MAX_START parameter, it is filled -** in at runtime. -** -**----------------------------------------------------------- -** -** ##===========< I=0; i=========== -** || SCR_CALL, -** || PADDR (idle), -** ##========================================== -** -**----------------------------------------------------------- -*/ -0 -}/*------------------------< TRYLOOP2 >---------------------*/,{ - SCR_JUMP, - PADDRH(tryloop), - -#ifdef SCSI_NCR_CCB_DONE_SUPPORT - -}/*------------------------< DONE_QUEUE >-------------------*/,{ -/* -** Copy the CCB address to the next done entry. -** Because the size depends on the -** #define MAX_DONE parameter, it is filled -** in at runtime. -** -**----------------------------------------------------------- -** -** ##===========< I=0; i=========== -** || SCR_COPY (sizeof(struct ccb *), -** || NADDR (header.cp), -** || NADDR (ccb_done[i]), -** || SCR_CALL, -** || PADDR (done_end), -** ##========================================== -** -**----------------------------------------------------------- -*/ -0 -}/*------------------------< DONE_QUEUE2 >------------------*/,{ - SCR_JUMP, - PADDRH (done_queue), - -#endif /* SCSI_NCR_CCB_DONE_SUPPORT */ -}/*------------------------< SELECT_NO_ATN >-----------------*/,{ - /* - ** Set Initiator mode. - ** And try to select this target without ATN. - */ - - SCR_CLR (SCR_TRG), - 0, - SCR_LOAD_REG (HS_REG, HS_SELECTING), - 0, - SCR_SEL_TBL ^ offsetof (struct dsb, select), - PADDR (reselect), - SCR_JUMP, - PADDR (select2), - -}/*-------------------------< CANCEL >------------------------*/,{ - - SCR_LOAD_REG (scratcha, HS_ABORTED), - 0, - SCR_JUMPR, - 8, -}/*-------------------------< SKIP >------------------------*/,{ - SCR_LOAD_REG (scratcha, 0), - 0, - /* - ** This entry has been canceled. - ** Next time use the next slot. - */ - SCR_COPY (4), - RADDR (temp), - PADDR (startpos), - /* - ** The ncr doesn't have an indirect load - ** or store command. So we have to - ** copy part of the control block to a - ** fixed place, where we can access it. - ** - ** We patch the address part of a - ** COPY command with the DSA-register. - */ - SCR_COPY_F (4), - RADDR (dsa), - PADDRH (skip2), - /* - ** Flush script prefetch if required - */ - PREFETCH_FLUSH - /* - ** then we do the actual copy. - */ - SCR_COPY (sizeof (struct head)), - /* - ** continued after the next label ... - */ -}/*-------------------------< SKIP2 >---------------------*/,{ - 0, - NADDR (header), - /* - ** Initialize the status registers - */ - SCR_COPY (4), - NADDR (header.status), - RADDR (scr0), - /* - ** Force host status. - */ - SCR_FROM_REG (scratcha), - 0, - SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)), - 16, - SCR_REG_REG (HS_REG, SCR_OR, HS_SKIPMASK), - 0, - SCR_JUMPR, - 8, - SCR_TO_REG (HS_REG), - 0, - SCR_LOAD_REG (SS_REG, S_GOOD), - 0, - SCR_JUMP, - PADDR (cleanup_ok), - -},/*-------------------------< PAR_ERR_DATA_IN >---------------*/{ - /* - ** Ignore all data in byte, until next phase - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), - PADDRH (par_err_other), - SCR_MOVE_ABS (1) ^ SCR_DATA_IN, - NADDR (scratch), - SCR_JUMPR, - -24, -},/*-------------------------< PAR_ERR_OTHER >------------------*/{ - /* - ** count it. - */ - SCR_REG_REG (PS_REG, SCR_ADD, 0x01), - 0, - /* - ** jump to dispatcher. - */ - SCR_JUMP, - PADDR (dispatch), -}/*-------------------------< MSG_REJECT >---------------*/,{ - /* - ** If a negotiation was in progress, - ** negotiation failed. - ** Otherwise, let the C code print - ** some message. - */ - SCR_FROM_REG (HS_REG), - 0, - SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)), - SIR_REJECT_RECEIVED, - SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), - SIR_NEGO_FAILED, - SCR_JUMP, - PADDR (clrack), - -}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{ - /* - ** Terminate cycle - */ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR (dispatch), - /* - ** get residue size. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[1]), - /* - ** Size is 0 .. ignore message. - */ - SCR_JUMP ^ IFTRUE (DATA (0)), - PADDR (clrack), - /* - ** Size is not 1 .. have to interrupt. - */ - SCR_JUMPR ^ IFFALSE (DATA (1)), - 40, - /* - ** Check for residue byte in swide register - */ - SCR_FROM_REG (scntl2), - 0, - SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), - 16, - /* - ** There IS data in the swide register. - ** Discard it. - */ - SCR_REG_REG (scntl2, SCR_OR, WSR), - 0, - SCR_JUMP, - PADDR (clrack), - /* - ** Load again the size to the sfbr register. - */ - SCR_FROM_REG (scratcha), - 0, - SCR_INT, - SIR_IGN_RESIDUE, - SCR_JUMP, - PADDR (clrack), - -}/*-------------------------< MSG_EXTENDED >-------------*/,{ - /* - ** Terminate cycle - */ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR (dispatch), - /* - ** get length. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[1]), - /* - */ - SCR_JUMP ^ IFTRUE (DATA (3)), - PADDRH (msg_ext_3), - SCR_JUMP ^ IFFALSE (DATA (2)), - PADDR (msg_bad), -}/*-------------------------< MSG_EXT_2 >----------------*/,{ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR (dispatch), - /* - ** get extended message code. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[2]), - SCR_JUMP ^ IFTRUE (DATA (EXTENDED_WDTR)), - PADDRH (msg_wdtr), - /* - ** unknown extended message - */ - SCR_JUMP, - PADDR (msg_bad) -}/*-------------------------< MSG_WDTR >-----------------*/,{ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR (dispatch), - /* - ** get data bus width - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[3]), - /* - ** let the host do the real work. - */ - SCR_INT, - SIR_NEGO_WIDE, - /* - ** let the target fetch our answer. - */ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDRH (nego_bad_phase), - -}/*-------------------------< SEND_WDTR >----------------*/,{ - /* - ** Send the EXTENDED_WDTR - */ - SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, - NADDR (msgout), - SCR_COPY (1), - NADDR (msgout), - NADDR (lastmsg), - SCR_JUMP, - PADDR (msg_out_done), - -}/*-------------------------< MSG_EXT_3 >----------------*/,{ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR (dispatch), - /* - ** get extended message code. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin[2]), - SCR_JUMP ^ IFTRUE (DATA (EXTENDED_SDTR)), - PADDRH (msg_sdtr), - /* - ** unknown extended message - */ - SCR_JUMP, - PADDR (msg_bad) - -}/*-------------------------< MSG_SDTR >-----------------*/,{ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR (dispatch), - /* - ** get period and offset - */ - SCR_MOVE_ABS (2) ^ SCR_MSG_IN, - NADDR (msgin[3]), - /* - ** let the host do the real work. - */ - SCR_INT, - SIR_NEGO_SYNC, - /* - ** let the target fetch our answer. - */ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDRH (nego_bad_phase), - -}/*-------------------------< SEND_SDTR >-------------*/,{ - /* - ** Send the EXTENDED_SDTR - */ - SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, - NADDR (msgout), - SCR_COPY (1), - NADDR (msgout), - NADDR (lastmsg), - SCR_JUMP, - PADDR (msg_out_done), - -}/*-------------------------< NEGO_BAD_PHASE >------------*/,{ - SCR_INT, - SIR_NEGO_PROTO, - SCR_JUMP, - PADDR (dispatch), - -}/*-------------------------< MSG_OUT_ABORT >-------------*/,{ - /* - ** After ABORT message, - ** - ** expect an immediate disconnect, ... - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - SCR_WAIT_DISC, - 0, - /* - ** ... and set the status to "ABORTED" - */ - SCR_LOAD_REG (HS_REG, HS_ABORTED), - 0, - SCR_JUMP, - PADDR (cleanup), - -}/*-------------------------< HDATA_IN >-------------------*/,{ -/* -** Because the size depends on the -** #define MAX_SCATTERH parameter, -** it is filled in at runtime. -** -** ##==< i=MAX_SCATTERL; i== -** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), -** || PADDR (dispatch), -** || SCR_MOVE_TBL ^ SCR_DATA_IN, -** || offsetof (struct dsb, data[ i]), -** ##=================================================== -** -**--------------------------------------------------------- -*/ -0 -}/*-------------------------< HDATA_IN2 >------------------*/,{ - SCR_JUMP, - PADDR (data_in), - -}/*-------------------------< HDATA_OUT >-------------------*/,{ -/* -** Because the size depends on the -** #define MAX_SCATTERH parameter, -** it is filled in at runtime. -** -** ##==< i=MAX_SCATTERL; i== -** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), -** || PADDR (dispatch), -** || SCR_MOVE_TBL ^ SCR_DATA_OUT, -** || offsetof (struct dsb, data[ i]), -** ##=================================================== -** -**--------------------------------------------------------- -*/ -0 -}/*-------------------------< HDATA_OUT2 >------------------*/,{ - SCR_JUMP, - PADDR (data_out), - -}/*-------------------------< RESET >----------------------*/,{ - /* - ** Send a TARGET_RESET message if bad IDENTIFY - ** received on reselection. - */ - SCR_LOAD_REG (scratcha, ABORT_TASK), - 0, - SCR_JUMP, - PADDRH (abort_resel), -}/*-------------------------< ABORTTAG >-------------------*/,{ - /* - ** Abort a wrong tag received on reselection. - */ - SCR_LOAD_REG (scratcha, ABORT_TASK), - 0, - SCR_JUMP, - PADDRH (abort_resel), -}/*-------------------------< ABORT >----------------------*/,{ - /* - ** Abort a reselection when no active CCB. - */ - SCR_LOAD_REG (scratcha, ABORT_TASK_SET), - 0, -}/*-------------------------< ABORT_RESEL >----------------*/,{ - SCR_COPY (1), - RADDR (scratcha), - NADDR (msgout), - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - /* - ** and send it. - ** we expect an immediate disconnect - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, - NADDR (msgout), - SCR_COPY (1), - NADDR (msgout), - NADDR (lastmsg), - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - SCR_WAIT_DISC, - 0, - SCR_JUMP, - PADDR (start), -}/*-------------------------< RESEND_IDENT >-------------------*/,{ - /* - ** The target stays in MSG OUT phase after having acked - ** Identify [+ Tag [+ Extended message ]]. Targets shall - ** behave this way on parity error. - ** We must send it again all the messages. - */ - SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */ - 0, /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */ - SCR_JUMP, - PADDR (send_ident), -}/*-------------------------< CLRATN_GO_ON >-------------------*/,{ - SCR_CLR (SCR_ATN), - 0, - SCR_JUMP, -}/*-------------------------< NXTDSP_GO_ON >-------------------*/,{ - 0, -}/*-------------------------< SDATA_IN >-------------------*/,{ - SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), - PADDR (dispatch), - SCR_MOVE_TBL ^ SCR_DATA_IN, - offsetof (struct dsb, sense), - SCR_CALL, - PADDR (dispatch), - SCR_JUMP, - PADDR (no_data), -}/*-------------------------< DATA_IO >--------------------*/,{ - /* - ** We jump here if the data direction was unknown at the - ** time we had to queue the command to the scripts processor. - ** Pointers had been set as follow in this situation: - ** savep --> DATA_IO - ** lastp --> start pointer when DATA_IN - ** goalp --> goal pointer when DATA_IN - ** wlastp --> start pointer when DATA_OUT - ** wgoalp --> goal pointer when DATA_OUT - ** This script sets savep/lastp/goalp according to the - ** direction chosen by the target. - */ - SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_OUT)), - 32, - /* - ** Direction is DATA IN. - ** Warning: we jump here, even when phase is DATA OUT. - */ - SCR_COPY (4), - NADDR (header.lastp), - NADDR (header.savep), - - /* - ** Jump to the SCRIPTS according to actual direction. - */ - SCR_COPY (4), - NADDR (header.savep), - RADDR (temp), - SCR_RETURN, - 0, - /* - ** Direction is DATA OUT. - */ - SCR_COPY (4), - NADDR (header.wlastp), - NADDR (header.lastp), - SCR_COPY (4), - NADDR (header.wgoalp), - NADDR (header.goalp), - SCR_JUMPR, - -64, -}/*-------------------------< BAD_IDENTIFY >---------------*/,{ - /* - ** If message phase but not an IDENTIFY, - ** get some help from the C code. - ** Old SCSI device may behave so. - */ - SCR_JUMPR ^ IFTRUE (MASK (0x80, 0x80)), - 16, - SCR_INT, - SIR_RESEL_NO_IDENTIFY, - SCR_JUMP, - PADDRH (reset), - /* - ** Message is an IDENTIFY, but lun is unknown. - ** Read the message, since we got it directly - ** from the SCSI BUS data lines. - ** Signal problem to C code for logging the event. - ** Send an ABORT_TASK_SET to clear all pending tasks. - */ - SCR_INT, - SIR_RESEL_BAD_LUN, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_JUMP, - PADDRH (abort), -}/*-------------------------< BAD_I_T_L >------------------*/,{ - /* - ** We donnot have a task for that I_T_L. - ** Signal problem to C code for logging the event. - ** Send an ABORT_TASK_SET message. - */ - SCR_INT, - SIR_RESEL_BAD_I_T_L, - SCR_JUMP, - PADDRH (abort), -}/*-------------------------< BAD_I_T_L_Q >----------------*/,{ - /* - ** We donnot have a task that matches the tag. - ** Signal problem to C code for logging the event. - ** Send an ABORT_TASK message. - */ - SCR_INT, - SIR_RESEL_BAD_I_T_L_Q, - SCR_JUMP, - PADDRH (aborttag), -}/*-------------------------< BAD_TARGET >-----------------*/,{ - /* - ** We donnot know the target that reselected us. - ** Grab the first message if any (IDENTIFY). - ** Signal problem to C code for logging the event. - ** TARGET_RESET message. - */ - SCR_INT, - SIR_RESEL_BAD_TARGET, - SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), - 8, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_JUMP, - PADDRH (reset), -}/*-------------------------< BAD_STATUS >-----------------*/,{ - /* - ** If command resulted in either QUEUE FULL, - ** CHECK CONDITION or COMMAND TERMINATED, - ** call the C code. - */ - SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)), - SIR_BAD_STATUS, - SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)), - SIR_BAD_STATUS, - SCR_INT ^ IFTRUE (DATA (S_TERMINATED)), - SIR_BAD_STATUS, - SCR_RETURN, - 0, -}/*-------------------------< START_RAM >-------------------*/,{ - /* - ** Load the script into on-chip RAM, - ** and jump to start point. - */ - SCR_COPY_F (4), - RADDR (scratcha), - PADDRH (start_ram0), - /* - ** Flush script prefetch if required - */ - PREFETCH_FLUSH - SCR_COPY (sizeof (struct script)), -}/*-------------------------< START_RAM0 >--------------------*/,{ - 0, - PADDR (start), - SCR_JUMP, - PADDR (start), -}/*-------------------------< STO_RESTART >-------------------*/,{ - /* - ** - ** Repair start queue (e.g. next time use the next slot) - ** and jump to start point. - */ - SCR_COPY (4), - RADDR (temp), - PADDR (startpos), - SCR_JUMP, - PADDR (start), -}/*-------------------------< WAIT_DMA >-------------------*/,{ - /* - ** For HP Zalon/53c720 systems, the Zalon interface - ** between CPU and 53c720 does prefetches, which causes - ** problems with self modifying scripts. The problem - ** is overcome by calling a dummy subroutine after each - ** modification, to force a refetch of the script on - ** return from the subroutine. - */ - SCR_RETURN, - 0, -}/*-------------------------< SNOOPTEST >-------------------*/,{ - /* - ** Read the variable. - */ - SCR_COPY (4), - NADDR(ncr_cache), - RADDR (scratcha), - /* - ** Write the variable. - */ - SCR_COPY (4), - RADDR (temp), - NADDR(ncr_cache), - /* - ** Read back the variable. - */ - SCR_COPY (4), - NADDR(ncr_cache), - RADDR (temp), -}/*-------------------------< SNOOPEND >-------------------*/,{ - /* - ** And stop. - */ - SCR_INT, - 99, -}/*--------------------------------------------------------*/ -}; - -/*========================================================== -** -** -** Fill in #define dependent parts of the script -** -** -**========================================================== -*/ - -void __init ncr_script_fill (struct script * scr, struct scripth * scrh) -{ - int i; - ncrcmd *p; - - p = scrh->tryloop; - for (i=0; itryloop + sizeof (scrh->tryloop)); - -#ifdef SCSI_NCR_CCB_DONE_SUPPORT - - p = scrh->done_queue; - for (i = 0; idone_queue+sizeof(scrh->done_queue)); - -#endif /* SCSI_NCR_CCB_DONE_SUPPORT */ - - p = scrh->hdata_in; - for (i=0; ihdata_in + sizeof (scrh->hdata_in)); - - p = scr->data_in; - for (i=MAX_SCATTERH; idata_in + sizeof (scr->data_in)); - - p = scrh->hdata_out; - for (i=0; ihdata_out + sizeof (scrh->hdata_out)); - - p = scr->data_out; - for (i=MAX_SCATTERH; idata_out + sizeof (scr->data_out)); -} - -/*========================================================== -** -** -** Copy and rebind a script. -** -** -**========================================================== -*/ - -static void __init -ncr_script_copy_and_bind (struct ncb *np, ncrcmd *src, ncrcmd *dst, int len) -{ - ncrcmd opcode, new, old, tmp1, tmp2; - ncrcmd *start, *end; - int relocs; - int opchanged = 0; - - start = src; - end = src + len/4; - - while (src < end) { - - opcode = *src++; - *dst++ = cpu_to_scr(opcode); - - /* - ** If we forget to change the length - ** in struct script, a field will be - ** padded with 0. This is an illegal - ** command. - */ - - if (opcode == 0) { - printk (KERN_ERR "%s: ERROR0 IN SCRIPT at %d.\n", - ncr_name(np), (int) (src-start-1)); - mdelay(1000); - } - - if (DEBUG_FLAGS & DEBUG_SCRIPT) - printk (KERN_DEBUG "%p: <%x>\n", - (src-1), (unsigned)opcode); - - /* - ** We don't have to decode ALL commands - */ - switch (opcode >> 28) { - - case 0xc: - /* - ** COPY has TWO arguments. - */ - relocs = 2; - tmp1 = src[0]; -#ifdef RELOC_KVAR - if ((tmp1 & RELOC_MASK) == RELOC_KVAR) - tmp1 = 0; -#endif - tmp2 = src[1]; -#ifdef RELOC_KVAR - if ((tmp2 & RELOC_MASK) == RELOC_KVAR) - tmp2 = 0; -#endif - if ((tmp1 ^ tmp2) & 3) { - printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n", - ncr_name(np), (int) (src-start-1)); - mdelay(1000); - } - /* - ** If PREFETCH feature not enabled, remove - ** the NO FLUSH bit if present. - */ - if ((opcode & SCR_NO_FLUSH) && !(np->features & FE_PFEN)) { - dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH); - ++opchanged; - } - break; - - case 0x0: - /* - ** MOVE (absolute address) - */ - relocs = 1; - break; - - case 0x8: - /* - ** JUMP / CALL - ** don't relocate if relative :-) - */ - if (opcode & 0x00800000) - relocs = 0; - else - relocs = 1; - break; - - case 0x4: - case 0x5: - case 0x6: - case 0x7: - relocs = 1; - break; - - default: - relocs = 0; - break; - } - - if (relocs) { - while (relocs--) { - old = *src++; - - switch (old & RELOC_MASK) { - case RELOC_REGISTER: - new = (old & ~RELOC_MASK) + np->paddr; - break; - case RELOC_LABEL: - new = (old & ~RELOC_MASK) + np->p_script; - break; - case RELOC_LABELH: - new = (old & ~RELOC_MASK) + np->p_scripth; - break; - case RELOC_SOFTC: - new = (old & ~RELOC_MASK) + np->p_ncb; - break; -#ifdef RELOC_KVAR - case RELOC_KVAR: - if (((old & ~RELOC_MASK) < - SCRIPT_KVAR_FIRST) || - ((old & ~RELOC_MASK) > - SCRIPT_KVAR_LAST)) - panic("ncr KVAR out of range"); - new = vtophys(script_kvars[old & - ~RELOC_MASK]); - break; -#endif - case 0: - /* Don't relocate a 0 address. */ - if (old == 0) { - new = old; - break; - } - /* fall through */ - default: - panic("ncr_script_copy_and_bind: weird relocation %x\n", old); - break; - } - - *dst++ = cpu_to_scr(new); - } - } else - *dst++ = cpu_to_scr(*src++); - - } -} - -/* -** Linux host data structure -*/ - -struct host_data { - struct ncb *ncb; -}; - -#define PRINT_ADDR(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg) - -static void ncr_print_msg(struct ccb *cp, char *label, u_char *msg) -{ - PRINT_ADDR(cp->cmd, "%s: ", label); - - spi_print_msg(msg); - printk("\n"); -} - -/*========================================================== -** -** NCR chip clock divisor table. -** Divisors are multiplied by 10,000,000 in order to make -** calculations more simple. -** -**========================================================== -*/ - -#define _5M 5000000 -static u_long div_10M[] = - {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; - - -/*=============================================================== -** -** Prepare io register values used by ncr_init() according -** to selected and supported features. -** -** NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 -** transfers. 32,64,128 are only supported by 875 and 895 chips. -** We use log base 2 (burst length) as internal code, with -** value 0 meaning "burst disabled". -** -**=============================================================== -*/ - -/* - * Burst length from burst code. - */ -#define burst_length(bc) (!(bc))? 0 : 1 << (bc) - -/* - * Burst code from io register bits. Burst enable is ctest0 for c720 - */ -#define burst_code(dmode, ctest0) \ - (ctest0) & 0x80 ? 0 : (((dmode) & 0xc0) >> 6) + 1 - -/* - * Set initial io register bits from burst code. - */ -static inline void ncr_init_burst(struct ncb *np, u_char bc) -{ - u_char *be = &np->rv_ctest0; - *be &= ~0x80; - np->rv_dmode &= ~(0x3 << 6); - np->rv_ctest5 &= ~0x4; - - if (!bc) { - *be |= 0x80; - } else { - --bc; - np->rv_dmode |= ((bc & 0x3) << 6); - np->rv_ctest5 |= (bc & 0x4); - } -} - -static void __init ncr_prepare_setting(struct ncb *np) -{ - u_char burst_max; - u_long period; - int i; - - /* - ** Save assumed BIOS setting - */ - - np->sv_scntl0 = INB(nc_scntl0) & 0x0a; - np->sv_scntl3 = INB(nc_scntl3) & 0x07; - np->sv_dmode = INB(nc_dmode) & 0xce; - np->sv_dcntl = INB(nc_dcntl) & 0xa8; - np->sv_ctest0 = INB(nc_ctest0) & 0x84; - np->sv_ctest3 = INB(nc_ctest3) & 0x01; - np->sv_ctest4 = INB(nc_ctest4) & 0x80; - np->sv_ctest5 = INB(nc_ctest5) & 0x24; - np->sv_gpcntl = INB(nc_gpcntl); - np->sv_stest2 = INB(nc_stest2) & 0x20; - np->sv_stest4 = INB(nc_stest4); - - /* - ** Wide ? - */ - - np->maxwide = (np->features & FE_WIDE)? 1 : 0; - - /* - * Guess the frequency of the chip's clock. - */ - if (np->features & FE_ULTRA) - np->clock_khz = 80000; - else - np->clock_khz = 40000; - - /* - * Get the clock multiplier factor. - */ - if (np->features & FE_QUAD) - np->multiplier = 4; - else if (np->features & FE_DBLR) - np->multiplier = 2; - else - np->multiplier = 1; - - /* - * Measure SCSI clock frequency for chips - * it may vary from assumed one. - */ - if (np->features & FE_VARCLK) - ncr_getclock(np, np->multiplier); - - /* - * Divisor to be used for async (timer pre-scaler). - */ - i = np->clock_divn - 1; - while (--i >= 0) { - if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) { - ++i; - break; - } - } - np->rv_scntl3 = i+1; - - /* - * Minimum synchronous period factor supported by the chip. - * Btw, 'period' is in tenths of nanoseconds. - */ - - period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; - if (period <= 250) np->minsync = 10; - else if (period <= 303) np->minsync = 11; - else if (period <= 500) np->minsync = 12; - else np->minsync = (period + 40 - 1) / 40; - - /* - * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). - */ - - if (np->minsync < 25 && !(np->features & FE_ULTRA)) - np->minsync = 25; - - /* - * Maximum synchronous period factor supported by the chip. - */ - - period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz); - np->maxsync = period > 2540 ? 254 : period / 10; - - /* - ** Prepare initial value of other IO registers - */ -#if defined SCSI_NCR_TRUST_BIOS_SETTING - np->rv_scntl0 = np->sv_scntl0; - np->rv_dmode = np->sv_dmode; - np->rv_dcntl = np->sv_dcntl; - np->rv_ctest0 = np->sv_ctest0; - np->rv_ctest3 = np->sv_ctest3; - np->rv_ctest4 = np->sv_ctest4; - np->rv_ctest5 = np->sv_ctest5; - burst_max = burst_code(np->sv_dmode, np->sv_ctest0); -#else - - /* - ** Select burst length (dwords) - */ - burst_max = driver_setup.burst_max; - if (burst_max == 255) - burst_max = burst_code(np->sv_dmode, np->sv_ctest0); - if (burst_max > 7) - burst_max = 7; - if (burst_max > np->maxburst) - burst_max = np->maxburst; - - /* - ** Select all supported special features - */ - if (np->features & FE_ERL) - np->rv_dmode |= ERL; /* Enable Read Line */ - if (np->features & FE_BOF) - np->rv_dmode |= BOF; /* Burst Opcode Fetch */ - if (np->features & FE_ERMP) - np->rv_dmode |= ERMP; /* Enable Read Multiple */ - if (np->features & FE_PFEN) - np->rv_dcntl |= PFEN; /* Prefetch Enable */ - if (np->features & FE_CLSE) - np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ - if (np->features & FE_WRIE) - np->rv_ctest3 |= WRIE; /* Write and Invalidate */ - if (np->features & FE_DFS) - np->rv_ctest5 |= DFS; /* Dma Fifo Size */ - if (np->features & FE_MUX) - np->rv_ctest4 |= MUX; /* Host bus multiplex mode */ - if (np->features & FE_EA) - np->rv_dcntl |= EA; /* Enable ACK */ - if (np->features & FE_EHP) - np->rv_ctest0 |= EHP; /* Even host parity */ - - /* - ** Select some other - */ - if (driver_setup.master_parity) - np->rv_ctest4 |= MPEE; /* Master parity checking */ - if (driver_setup.scsi_parity) - np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */ - - /* - ** Get SCSI addr of host adapter (set by bios?). - */ - if (np->myaddr == 255) { - np->myaddr = INB(nc_scid) & 0x07; - if (!np->myaddr) - np->myaddr = SCSI_NCR_MYADDR; - } - -#endif /* SCSI_NCR_TRUST_BIOS_SETTING */ - - /* - * Prepare initial io register bits for burst length - */ - ncr_init_burst(np, burst_max); - - /* - ** Set SCSI BUS mode. - ** - ** - ULTRA2 chips (895/895A/896) report the current - ** BUS mode through the STEST4 IO register. - ** - For previous generation chips (825/825A/875), - ** user has to tell us how to check against HVD, - ** since a 100% safe algorithm is not possible. - */ - np->scsi_mode = SMODE_SE; - if (np->features & FE_DIFF) { - switch(driver_setup.diff_support) { - case 4: /* Trust previous settings if present, then GPIO3 */ - if (np->sv_scntl3) { - if (np->sv_stest2 & 0x20) - np->scsi_mode = SMODE_HVD; - break; - } - case 3: /* SYMBIOS controllers report HVD through GPIO3 */ - if (INB(nc_gpreg) & 0x08) - break; - case 2: /* Set HVD unconditionally */ - np->scsi_mode = SMODE_HVD; - case 1: /* Trust previous settings for HVD */ - if (np->sv_stest2 & 0x20) - np->scsi_mode = SMODE_HVD; - break; - default:/* Don't care about HVD */ - break; - } - } - if (np->scsi_mode == SMODE_HVD) - np->rv_stest2 |= 0x20; - - /* - ** Set LED support from SCRIPTS. - ** Ignore this feature for boards known to use a - ** specific GPIO wiring and for the 895A or 896 - ** that drive the LED directly. - ** Also probe initial setting of GPIO0 as output. - */ - if ((driver_setup.led_pin) && - !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01)) - np->features |= FE_LED0; - - /* - ** Set irq mode. - */ - switch(driver_setup.irqm & 3) { - case 2: - np->rv_dcntl |= IRQM; - break; - case 1: - np->rv_dcntl |= (np->sv_dcntl & IRQM); - break; - default: - break; - } - - /* - ** Configure targets according to driver setup. - ** Allow to override sync, wide and NOSCAN from - ** boot command line. - */ - for (i = 0 ; i < MAX_TARGET ; i++) { - struct tcb *tp = &np->target[i]; - - tp->usrsync = driver_setup.default_sync; - tp->usrwide = driver_setup.max_wide; - tp->usrtags = MAX_TAGS; - tp->period = 0xffff; - if (!driver_setup.disconnection) - np->target[i].usrflag = UF_NODISC; - } - - /* - ** Announce all that stuff to user. - */ - - printk(KERN_INFO "%s: ID %d, Fast-%d%s%s\n", ncr_name(np), - np->myaddr, - np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10), - (np->rv_scntl0 & 0xa) ? ", Parity Checking" : ", NO Parity", - (np->rv_stest2 & 0x20) ? ", Differential" : ""); - - if (bootverbose > 1) { - printk (KERN_INFO "%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " - "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", - ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, - np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); - - printk (KERN_INFO "%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " - "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", - ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, - np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); - } - - if (bootverbose && np->paddr2) - printk (KERN_INFO "%s: on-chip RAM at 0x%lx\n", - ncr_name(np), np->paddr2); -} - -/*========================================================== -** -** -** Done SCSI commands list management. -** -** We donnot enter the scsi_done() callback immediately -** after a command has been seen as completed but we -** insert it into a list which is flushed outside any kind -** of driver critical section. -** This allows to do minimal stuff under interrupt and -** inside critical sections and to also avoid locking up -** on recursive calls to driver entry points under SMP. -** In fact, the only kernel point which is entered by the -** driver with a driver lock set is kmalloc(GFP_ATOMIC) -** that shall not reenter the driver under any circumstances, -** AFAIK. -** -**========================================================== -*/ -static inline void ncr_queue_done_cmd(struct ncb *np, struct scsi_cmnd *cmd) -{ - unmap_scsi_data(np, cmd); - cmd->host_scribble = (char *) np->done_list; - np->done_list = cmd; -} - -static inline void ncr_flush_done_cmds(struct scsi_cmnd *lcmd) -{ - struct scsi_cmnd *cmd; - - while (lcmd) { - cmd = lcmd; - lcmd = (struct scsi_cmnd *) cmd->host_scribble; - cmd->scsi_done(cmd); - } -} - -/*========================================================== -** -** -** Prepare the next negotiation message if needed. -** -** Fill in the part of message buffer that contains the -** negotiation and the nego_status field of the CCB. -** Returns the size of the message in bytes. -** -** -**========================================================== -*/ - - -static int ncr_prepare_nego(struct ncb *np, struct ccb *cp, u_char *msgptr) -{ - struct tcb *tp = &np->target[cp->target]; - int msglen = 0; - int nego = 0; - struct scsi_target *starget = tp->starget; - - /* negotiate wide transfers ? */ - if (!tp->widedone) { - if (spi_support_wide(starget)) { - nego = NS_WIDE; - } else - tp->widedone=1; - } - - /* negotiate synchronous transfers? */ - if (!nego && !tp->period) { - if (spi_support_sync(starget)) { - nego = NS_SYNC; - } else { - tp->period =0xffff; - dev_info(&starget->dev, "target did not report SYNC.\n"); - } - } - - switch (nego) { - case NS_SYNC: - msglen += spi_populate_sync_msg(msgptr + msglen, - tp->maxoffs ? tp->minsync : 0, tp->maxoffs); - break; - case NS_WIDE: - msglen += spi_populate_width_msg(msgptr + msglen, tp->usrwide); - break; - } - - cp->nego_status = nego; - - if (nego) { - tp->nego_cp = cp; - if (DEBUG_FLAGS & DEBUG_NEGO) { - ncr_print_msg(cp, nego == NS_WIDE ? - "wide msgout":"sync_msgout", msgptr); - } - } - - return msglen; -} - - - -/*========================================================== -** -** -** Start execution of a SCSI command. -** This is called from the generic SCSI driver. -** -** -**========================================================== -*/ -static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct tcb *tp = &np->target[sdev->id]; - struct lcb *lp = tp->lp[sdev->lun]; - struct ccb *cp; - - int segments; - u_char idmsg, *msgptr; - u32 msglen; - int direction; - u32 lastp, goalp; - - /*--------------------------------------------- - ** - ** Some shortcuts ... - ** - **--------------------------------------------- - */ - if ((sdev->id == np->myaddr ) || - (sdev->id >= MAX_TARGET) || - (sdev->lun >= MAX_LUN )) { - return(DID_BAD_TARGET); - } - - /*--------------------------------------------- - ** - ** Complete the 1st TEST UNIT READY command - ** with error condition if the device is - ** flagged NOSCAN, in order to speed up - ** the boot. - ** - **--------------------------------------------- - */ - if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) && - (tp->usrflag & UF_NOSCAN)) { - tp->usrflag &= ~UF_NOSCAN; - return DID_BAD_TARGET; - } - - if (DEBUG_FLAGS & DEBUG_TINY) { - PRINT_ADDR(cmd, "CMD=%x ", cmd->cmnd[0]); - } - - /*--------------------------------------------------- - ** - ** Assign a ccb / bind cmd. - ** If resetting, shorten settle_time if necessary - ** in order to avoid spurious timeouts. - ** If resetting or no free ccb, - ** insert cmd into the waiting list. - ** - **---------------------------------------------------- - */ - if (np->settle_time && cmd->request->timeout >= HZ) { - u_long tlimit = jiffies + cmd->request->timeout - HZ; - if (time_after(np->settle_time, tlimit)) - np->settle_time = tlimit; - } - - if (np->settle_time || !(cp=ncr_get_ccb (np, cmd))) { - insert_into_waiting_list(np, cmd); - return(DID_OK); - } - cp->cmd = cmd; - - /*---------------------------------------------------- - ** - ** Build the identify / tag / sdtr message - ** - **---------------------------------------------------- - */ - - idmsg = IDENTIFY(0, sdev->lun); - - if (cp ->tag != NO_TAG || - (cp != np->ccb && np->disc && !(tp->usrflag & UF_NODISC))) - idmsg |= 0x40; - - msgptr = cp->scsi_smsg; - msglen = 0; - msgptr[msglen++] = idmsg; - - if (cp->tag != NO_TAG) { - char order = np->order; - - /* - ** Force ordered tag if necessary to avoid timeouts - ** and to preserve interactivity. - */ - if (lp && time_after(jiffies, lp->tags_stime)) { - if (lp->tags_smap) { - order = ORDERED_QUEUE_TAG; - if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ - PRINT_ADDR(cmd, - "ordered tag forced.\n"); - } - } - lp->tags_stime = jiffies + 3*HZ; - lp->tags_smap = lp->tags_umap; - } - - if (order == 0) { - /* - ** Ordered write ops, unordered read ops. - */ - switch (cmd->cmnd[0]) { - case 0x08: /* READ_SMALL (6) */ - case 0x28: /* READ_BIG (10) */ - case 0xa8: /* READ_HUGE (12) */ - order = SIMPLE_QUEUE_TAG; - break; - default: - order = ORDERED_QUEUE_TAG; - } - } - msgptr[msglen++] = order; - /* - ** Actual tags are numbered 1,3,5,..2*MAXTAGS+1, - ** since we may have to deal with devices that have - ** problems with #TAG 0 or too great #TAG numbers. - */ - msgptr[msglen++] = (cp->tag << 1) + 1; - } - - /*---------------------------------------------------- - ** - ** Build the data descriptors - ** - **---------------------------------------------------- - */ - - direction = cmd->sc_data_direction; - if (direction != DMA_NONE) { - segments = ncr_scatter(np, cp, cp->cmd); - if (segments < 0) { - ncr_free_ccb(np, cp); - return(DID_ERROR); - } - } - else { - cp->data_len = 0; - segments = 0; - } - - /*--------------------------------------------------- - ** - ** negotiation required? - ** - ** (nego_status is filled by ncr_prepare_nego()) - ** - **--------------------------------------------------- - */ - - cp->nego_status = 0; - - if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) { - msglen += ncr_prepare_nego (np, cp, msgptr + msglen); - } - - /*---------------------------------------------------- - ** - ** Determine xfer direction. - ** - **---------------------------------------------------- - */ - if (!cp->data_len) - direction = DMA_NONE; - - /* - ** If data direction is BIDIRECTIONAL, speculate FROM_DEVICE - ** but prepare alternate pointers for TO_DEVICE in case - ** of our speculation will be just wrong. - ** SCRIPTS will swap values if needed. - */ - switch(direction) { - case DMA_BIDIRECTIONAL: - case DMA_TO_DEVICE: - goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8; - if (segments <= MAX_SCATTERL) - lastp = goalp - 8 - (segments * 16); - else { - lastp = NCB_SCRIPTH_PHYS (np, hdata_out2); - lastp -= (segments - MAX_SCATTERL) * 16; - } - if (direction != DMA_BIDIRECTIONAL) - break; - cp->phys.header.wgoalp = cpu_to_scr(goalp); - cp->phys.header.wlastp = cpu_to_scr(lastp); - /* fall through */ - case DMA_FROM_DEVICE: - goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8; - if (segments <= MAX_SCATTERL) - lastp = goalp - 8 - (segments * 16); - else { - lastp = NCB_SCRIPTH_PHYS (np, hdata_in2); - lastp -= (segments - MAX_SCATTERL) * 16; - } - break; - default: - case DMA_NONE: - lastp = goalp = NCB_SCRIPT_PHYS (np, no_data); - break; - } - - /* - ** Set all pointers values needed by SCRIPTS. - ** If direction is unknown, start at data_io. - */ - cp->phys.header.lastp = cpu_to_scr(lastp); - cp->phys.header.goalp = cpu_to_scr(goalp); - - if (direction == DMA_BIDIRECTIONAL) - cp->phys.header.savep = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io)); - else - cp->phys.header.savep= cpu_to_scr(lastp); - - /* - ** Save the initial data pointer in order to be able - ** to redo the command. - */ - cp->startp = cp->phys.header.savep; - - /*---------------------------------------------------- - ** - ** fill in ccb - ** - **---------------------------------------------------- - ** - ** - ** physical -> virtual backlink - ** Generic SCSI command - */ - - /* - ** Startqueue - */ - cp->start.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); - cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_dsa)); - /* - ** select - */ - cp->phys.select.sel_id = sdev_id(sdev); - cp->phys.select.sel_scntl3 = tp->wval; - cp->phys.select.sel_sxfer = tp->sval; - /* - ** message - */ - cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg)); - cp->phys.smsg.size = cpu_to_scr(msglen); - - /* - ** command - */ - memcpy(cp->cdb_buf, cmd->cmnd, min_t(int, cmd->cmd_len, sizeof(cp->cdb_buf))); - cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, cdb_buf[0])); - cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); - - /* - ** status - */ - cp->actualquirks = 0; - cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; - cp->scsi_status = S_ILLEGAL; - cp->parity_status = 0; - - cp->xerr_status = XE_OK; -#if 0 - cp->sync_status = tp->sval; - cp->wide_status = tp->wval; -#endif - - /*---------------------------------------------------- - ** - ** Critical region: start this job. - ** - **---------------------------------------------------- - */ - - /* activate this job. */ - cp->magic = CCB_MAGIC; - - /* - ** insert next CCBs into start queue. - ** 2 max at a time is enough to flush the CCB wait queue. - */ - cp->auto_sense = 0; - if (lp) - ncr_start_next_ccb(np, lp, 2); - else - ncr_put_start_queue(np, cp); - - /* Command is successfully queued. */ - - return DID_OK; -} - - -/*========================================================== -** -** -** Insert a CCB into the start queue and wake up the -** SCRIPTS processor. -** -** -**========================================================== -*/ - -static void ncr_start_next_ccb(struct ncb *np, struct lcb *lp, int maxn) -{ - struct list_head *qp; - struct ccb *cp; - - if (lp->held_ccb) - return; - - while (maxn-- && lp->queuedccbs < lp->queuedepth) { - qp = ncr_list_pop(&lp->wait_ccbq); - if (!qp) - break; - ++lp->queuedccbs; - cp = list_entry(qp, struct ccb, link_ccbq); - list_add_tail(qp, &lp->busy_ccbq); - lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag] = - cpu_to_scr(CCB_PHYS (cp, restart)); - ncr_put_start_queue(np, cp); - } -} - -static void ncr_put_start_queue(struct ncb *np, struct ccb *cp) -{ - u16 qidx; - - /* - ** insert into start queue. - */ - if (!np->squeueput) np->squeueput = 1; - qidx = np->squeueput + 2; - if (qidx >= MAX_START + MAX_START) qidx = 1; - - np->scripth->tryloop [qidx] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); - MEMORY_BARRIER(); - np->scripth->tryloop [np->squeueput] = cpu_to_scr(CCB_PHYS (cp, start)); - - np->squeueput = qidx; - ++np->queuedccbs; - cp->queued = 1; - - if (DEBUG_FLAGS & DEBUG_QUEUE) - printk ("%s: queuepos=%d.\n", ncr_name (np), np->squeueput); - - /* - ** Script processor may be waiting for reselect. - ** Wake it up. - */ - MEMORY_BARRIER(); - OUTB (nc_istat, SIGP); -} - - -static int ncr_reset_scsi_bus(struct ncb *np, int enab_int, int settle_delay) -{ - u32 term; - int retv = 0; - - np->settle_time = jiffies + settle_delay * HZ; - - if (bootverbose > 1) - printk("%s: resetting, " - "command processing suspended for %d seconds\n", - ncr_name(np), settle_delay); - - ncr_chip_reset(np, 100); - udelay(2000); /* The 895 needs time for the bus mode to settle */ - if (enab_int) - OUTW (nc_sien, RST); - /* - ** Enable Tolerant, reset IRQD if present and - ** properly set IRQ mode, prior to resetting the bus. - */ - OUTB (nc_stest3, TE); - OUTB (nc_scntl1, CRST); - udelay(200); - - if (!driver_setup.bus_check) - goto out; - /* - ** Check for no terminators or SCSI bus shorts to ground. - ** Read SCSI data bus, data parity bits and control signals. - ** We are expecting RESET to be TRUE and other signals to be - ** FALSE. - */ - - term = INB(nc_sstat0); - term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */ - term |= ((INB(nc_sstat2) & 0x01) << 26) | /* sdp1 */ - ((INW(nc_sbdl) & 0xff) << 9) | /* d7-0 */ - ((INW(nc_sbdl) & 0xff00) << 10) | /* d15-8 */ - INB(nc_sbcl); /* req ack bsy sel atn msg cd io */ - - if (!(np->features & FE_WIDE)) - term &= 0x3ffff; - - if (term != (2<<7)) { - printk("%s: suspicious SCSI data while resetting the BUS.\n", - ncr_name(np)); - printk("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " - "0x%lx, expecting 0x%lx\n", - ncr_name(np), - (np->features & FE_WIDE) ? "dp1,d15-8," : "", - (u_long)term, (u_long)(2<<7)); - if (driver_setup.bus_check == 1) - retv = 1; - } -out: - OUTB (nc_scntl1, 0); - return retv; -} - -/* - * Start reset process. - * If reset in progress do nothing. - * The interrupt handler will reinitialize the chip. - * The timeout handler will wait for settle_time before - * clearing it and so resuming command processing. - */ -static void ncr_start_reset(struct ncb *np) -{ - if (!np->settle_time) { - ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay); - } -} - -/*========================================================== -** -** -** Reset the SCSI BUS. -** This is called from the generic SCSI driver. -** -** -**========================================================== -*/ -static int ncr_reset_bus (struct ncb *np, struct scsi_cmnd *cmd, int sync_reset) -{ -/* struct scsi_device *device = cmd->device; */ - struct ccb *cp; - int found; - -/* - * Return immediately if reset is in progress. - */ - if (np->settle_time) { - return FAILED; - } -/* - * Start the reset process. - * The script processor is then assumed to be stopped. - * Commands will now be queued in the waiting list until a settle - * delay of 2 seconds will be completed. - */ - ncr_start_reset(np); -/* - * First, look in the wakeup list - */ - for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) { - /* - ** look for the ccb of this command. - */ - if (cp->host_status == HS_IDLE) continue; - if (cp->cmd == cmd) { - found = 1; - break; - } - } -/* - * Then, look in the waiting list - */ - if (!found && retrieve_from_waiting_list(0, np, cmd)) - found = 1; -/* - * Wake-up all awaiting commands with DID_RESET. - */ - reset_waiting_list(np); -/* - * Wake-up all pending commands with HS_RESET -> DID_RESET. - */ - ncr_wakeup(np, HS_RESET); -/* - * If the involved command was not in a driver queue, and the - * scsi driver told us reset is synchronous, and the command is not - * currently in the waiting list, complete it with DID_RESET status, - * in order to keep it alive. - */ - if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) { - cmd->result = ScsiResult(DID_RESET, 0); - ncr_queue_done_cmd(np, cmd); - } - - return SUCCESS; -} - -#if 0 /* unused and broken.. */ -/*========================================================== -** -** -** Abort an SCSI command. -** This is called from the generic SCSI driver. -** -** -**========================================================== -*/ -static int ncr_abort_command (struct ncb *np, struct scsi_cmnd *cmd) -{ -/* struct scsi_device *device = cmd->device; */ - struct ccb *cp; - int found; - int retv; - -/* - * First, look for the scsi command in the waiting list - */ - if (remove_from_waiting_list(np, cmd)) { - cmd->result = ScsiResult(DID_ABORT, 0); - ncr_queue_done_cmd(np, cmd); - return SCSI_ABORT_SUCCESS; - } - -/* - * Then, look in the wakeup list - */ - for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) { - /* - ** look for the ccb of this command. - */ - if (cp->host_status == HS_IDLE) continue; - if (cp->cmd == cmd) { - found = 1; - break; - } - } - - if (!found) { - return SCSI_ABORT_NOT_RUNNING; - } - - if (np->settle_time) { - return SCSI_ABORT_SNOOZE; - } - - /* - ** If the CCB is active, patch schedule jumps for the - ** script to abort the command. - */ - - switch(cp->host_status) { - case HS_BUSY: - case HS_NEGOTIATE: - printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp); - cp->start.schedule.l_paddr = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel)); - retv = SCSI_ABORT_PENDING; - break; - case HS_DISCONNECT: - cp->restart.schedule.l_paddr = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort)); - retv = SCSI_ABORT_PENDING; - break; - default: - retv = SCSI_ABORT_NOT_RUNNING; - break; - - } - - /* - ** If there are no requests, the script - ** processor will sleep on SEL_WAIT_RESEL. - ** Let's wake it up, since it may have to work. - */ - OUTB (nc_istat, SIGP); - - return retv; -} -#endif - -static void ncr_detach(struct ncb *np) -{ - struct ccb *cp; - struct tcb *tp; - struct lcb *lp; - int target, lun; - int i; - char inst_name[16]; - - /* Local copy so we don't access np after freeing it! */ - strlcpy(inst_name, ncr_name(np), sizeof(inst_name)); - - printk("%s: releasing host resources\n", ncr_name(np)); - -/* -** Stop the ncr_timeout process -** Set release_stage to 1 and wait that ncr_timeout() set it to 2. -*/ - -#ifdef DEBUG_NCR53C8XX - printk("%s: stopping the timer\n", ncr_name(np)); -#endif - np->release_stage = 1; - for (i = 50 ; i && np->release_stage != 2 ; i--) - mdelay(100); - if (np->release_stage != 2) - printk("%s: the timer seems to be already stopped\n", ncr_name(np)); - else np->release_stage = 2; - -/* -** Disable chip interrupts -*/ - -#ifdef DEBUG_NCR53C8XX - printk("%s: disabling chip interrupts\n", ncr_name(np)); -#endif - OUTW (nc_sien , 0); - OUTB (nc_dien , 0); - - /* - ** Reset NCR chip - ** Restore bios setting for automatic clock detection. - */ - - printk("%s: resetting chip\n", ncr_name(np)); - ncr_chip_reset(np, 100); - - OUTB(nc_dmode, np->sv_dmode); - OUTB(nc_dcntl, np->sv_dcntl); - OUTB(nc_ctest0, np->sv_ctest0); - OUTB(nc_ctest3, np->sv_ctest3); - OUTB(nc_ctest4, np->sv_ctest4); - OUTB(nc_ctest5, np->sv_ctest5); - OUTB(nc_gpcntl, np->sv_gpcntl); - OUTB(nc_stest2, np->sv_stest2); - - ncr_selectclock(np, np->sv_scntl3); - - /* - ** Free allocated ccb(s) - */ - - while ((cp=np->ccb->link_ccb) != NULL) { - np->ccb->link_ccb = cp->link_ccb; - if (cp->host_status) { - printk("%s: shall free an active ccb (host_status=%d)\n", - ncr_name(np), cp->host_status); - } -#ifdef DEBUG_NCR53C8XX - printk("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp); -#endif - m_free_dma(cp, sizeof(*cp), "CCB"); - } - - /* Free allocated tp(s) */ - - for (target = 0; target < MAX_TARGET ; target++) { - tp=&np->target[target]; - for (lun = 0 ; lun < MAX_LUN ; lun++) { - lp = tp->lp[lun]; - if (lp) { -#ifdef DEBUG_NCR53C8XX - printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp); -#endif - if (lp->jump_ccb != &lp->jump_ccb_0) - m_free_dma(lp->jump_ccb,256,"JUMP_CCB"); - m_free_dma(lp, sizeof(*lp), "LCB"); - } - } - } - - if (np->scripth0) - m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH"); - if (np->script0) - m_free_dma(np->script0, sizeof(struct script), "SCRIPT"); - if (np->ccb) - m_free_dma(np->ccb, sizeof(struct ccb), "CCB"); - m_free_dma(np, sizeof(struct ncb), "NCB"); - - printk("%s: host resources successfully released\n", inst_name); -} - -/*========================================================== -** -** -** Complete execution of a SCSI command. -** Signal completion to the generic SCSI driver. -** -** -**========================================================== -*/ - -void ncr_complete (struct ncb *np, struct ccb *cp) -{ - struct scsi_cmnd *cmd; - struct tcb *tp; - struct lcb *lp; - - /* - ** Sanity check - */ - - if (!cp || cp->magic != CCB_MAGIC || !cp->cmd) - return; - - /* - ** Print minimal debug information. - */ - - if (DEBUG_FLAGS & DEBUG_TINY) - printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp, - cp->host_status,cp->scsi_status); - - /* - ** Get command, target and lun pointers. - */ - - cmd = cp->cmd; - cp->cmd = NULL; - tp = &np->target[cmd->device->id]; - lp = tp->lp[cmd->device->lun]; - - /* - ** We donnot queue more than 1 ccb per target - ** with negotiation at any time. If this ccb was - ** used for negotiation, clear this info in the tcb. - */ - - if (cp == tp->nego_cp) - tp->nego_cp = NULL; - - /* - ** If auto-sense performed, change scsi status. - */ - if (cp->auto_sense) { - cp->scsi_status = cp->auto_sense; - } - - /* - ** If we were recovering from queue full or performing - ** auto-sense, requeue skipped CCBs to the wait queue. - */ - - if (lp && lp->held_ccb) { - if (cp == lp->held_ccb) { - list_splice_init(&lp->skip_ccbq, &lp->wait_ccbq); - lp->held_ccb = NULL; - } - } - - /* - ** Check for parity errors. - */ - - if (cp->parity_status > 1) { - PRINT_ADDR(cmd, "%d parity error(s).\n",cp->parity_status); - } - - /* - ** Check for extended errors. - */ - - if (cp->xerr_status != XE_OK) { - switch (cp->xerr_status) { - case XE_EXTRA_DATA: - PRINT_ADDR(cmd, "extraneous data discarded.\n"); - break; - case XE_BAD_PHASE: - PRINT_ADDR(cmd, "invalid scsi phase (4/5).\n"); - break; - default: - PRINT_ADDR(cmd, "extended error %d.\n", - cp->xerr_status); - break; - } - if (cp->host_status==HS_COMPLETE) - cp->host_status = HS_FAIL; - } - - /* - ** Print out any error for debugging purpose. - */ - if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { - if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) { - PRINT_ADDR(cmd, "ERROR: cmd=%x host_status=%x " - "scsi_status=%x\n", cmd->cmnd[0], - cp->host_status, cp->scsi_status); - } - } - - /* - ** Check the status. - */ - if ( (cp->host_status == HS_COMPLETE) - && (cp->scsi_status == S_GOOD || - cp->scsi_status == S_COND_MET)) { - /* - * All went well (GOOD status). - * CONDITION MET status is returned on - * `Pre-Fetch' or `Search data' success. - */ - cmd->result = ScsiResult(DID_OK, cp->scsi_status); - - /* - ** @RESID@ - ** Could dig out the correct value for resid, - ** but it would be quite complicated. - */ - /* if (cp->phys.header.lastp != cp->phys.header.goalp) */ - - /* - ** Allocate the lcb if not yet. - */ - if (!lp) - ncr_alloc_lcb (np, cmd->device->id, cmd->device->lun); - - tp->bytes += cp->data_len; - tp->transfers ++; - - /* - ** If tags was reduced due to queue full, - ** increase tags if 1000 good status received. - */ - if (lp && lp->usetags && lp->numtags < lp->maxtags) { - ++lp->num_good; - if (lp->num_good >= 1000) { - lp->num_good = 0; - ++lp->numtags; - ncr_setup_tags (np, cmd->device); - } - } - } else if ((cp->host_status == HS_COMPLETE) - && (cp->scsi_status == S_CHECK_COND)) { - /* - ** Check condition code - */ - cmd->result = ScsiResult(DID_OK, S_CHECK_COND); - - /* - ** Copy back sense data to caller's buffer. - */ - memcpy(cmd->sense_buffer, cp->sense_buf, - min_t(size_t, SCSI_SENSE_BUFFERSIZE, - sizeof(cp->sense_buf))); - - if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { - u_char *p = cmd->sense_buffer; - int i; - PRINT_ADDR(cmd, "sense data:"); - for (i=0; i<14; i++) printk (" %x", *p++); - printk (".\n"); - } - } else if ((cp->host_status == HS_COMPLETE) - && (cp->scsi_status == S_CONFLICT)) { - /* - ** Reservation Conflict condition code - */ - cmd->result = ScsiResult(DID_OK, S_CONFLICT); - - } else if ((cp->host_status == HS_COMPLETE) - && (cp->scsi_status == S_BUSY || - cp->scsi_status == S_QUEUE_FULL)) { - - /* - ** Target is busy. - */ - cmd->result = ScsiResult(DID_OK, cp->scsi_status); - - } else if ((cp->host_status == HS_SEL_TIMEOUT) - || (cp->host_status == HS_TIMEOUT)) { - - /* - ** No response - */ - cmd->result = ScsiResult(DID_TIME_OUT, cp->scsi_status); - - } else if (cp->host_status == HS_RESET) { - - /* - ** SCSI bus reset - */ - cmd->result = ScsiResult(DID_RESET, cp->scsi_status); - - } else if (cp->host_status == HS_ABORTED) { - - /* - ** Transfer aborted - */ - cmd->result = ScsiResult(DID_ABORT, cp->scsi_status); - - } else { - - /* - ** Other protocol messes - */ - PRINT_ADDR(cmd, "COMMAND FAILED (%x %x) @%p.\n", - cp->host_status, cp->scsi_status, cp); - - cmd->result = ScsiResult(DID_ERROR, cp->scsi_status); - } - - /* - ** trace output - */ - - if (tp->usrflag & UF_TRACE) { - u_char * p; - int i; - PRINT_ADDR(cmd, " CMD:"); - p = (u_char*) &cmd->cmnd[0]; - for (i=0; icmd_len; i++) printk (" %x", *p++); - - if (cp->host_status==HS_COMPLETE) { - switch (cp->scsi_status) { - case S_GOOD: - printk (" GOOD"); - break; - case S_CHECK_COND: - printk (" SENSE:"); - p = (u_char*) &cmd->sense_buffer; - for (i=0; i<14; i++) - printk (" %x", *p++); - break; - default: - printk (" STAT: %x\n", cp->scsi_status); - break; - } - } else printk (" HOSTERROR: %x", cp->host_status); - printk ("\n"); - } - - /* - ** Free this ccb - */ - ncr_free_ccb (np, cp); - - /* - ** requeue awaiting scsi commands for this lun. - */ - if (lp && lp->queuedccbs < lp->queuedepth && - !list_empty(&lp->wait_ccbq)) - ncr_start_next_ccb(np, lp, 2); - - /* - ** requeue awaiting scsi commands for this controller. - */ - if (np->waiting_list) - requeue_waiting_list(np); - - /* - ** signal completion to generic driver. - */ - ncr_queue_done_cmd(np, cmd); -} - -/*========================================================== -** -** -** Signal all (or one) control block done. -** -** -**========================================================== -*/ - -/* -** This CCB has been skipped by the NCR. -** Queue it in the corresponding unit queue. -*/ -static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp) -{ - struct tcb *tp = &np->target[cp->target]; - struct lcb *lp = tp->lp[cp->lun]; - - if (lp && cp != np->ccb) { - cp->host_status &= ~HS_SKIPMASK; - cp->start.schedule.l_paddr = - cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); - list_move_tail(&cp->link_ccbq, &lp->skip_ccbq); - if (cp->queued) { - --lp->queuedccbs; - } - } - if (cp->queued) { - --np->queuedccbs; - cp->queued = 0; - } -} - -/* -** The NCR has completed CCBs. -** Look at the DONE QUEUE if enabled, otherwise scan all CCBs -*/ -void ncr_wakeup_done (struct ncb *np) -{ - struct ccb *cp; -#ifdef SCSI_NCR_CCB_DONE_SUPPORT - int i, j; - - i = np->ccb_done_ic; - while (1) { - j = i+1; - if (j >= MAX_DONE) - j = 0; - - cp = np->ccb_done[j]; - if (!CCB_DONE_VALID(cp)) - break; - - np->ccb_done[j] = (struct ccb *)CCB_DONE_EMPTY; - np->scripth->done_queue[5*j + 4] = - cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug)); - MEMORY_BARRIER(); - np->scripth->done_queue[5*i + 4] = - cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end)); - - if (cp->host_status & HS_DONEMASK) - ncr_complete (np, cp); - else if (cp->host_status & HS_SKIPMASK) - ncr_ccb_skipped (np, cp); - - i = j; - } - np->ccb_done_ic = i; -#else - cp = np->ccb; - while (cp) { - if (cp->host_status & HS_DONEMASK) - ncr_complete (np, cp); - else if (cp->host_status & HS_SKIPMASK) - ncr_ccb_skipped (np, cp); - cp = cp->link_ccb; - } -#endif -} - -/* -** Complete all active CCBs. -*/ -void ncr_wakeup (struct ncb *np, u_long code) -{ - struct ccb *cp = np->ccb; - - while (cp) { - if (cp->host_status != HS_IDLE) { - cp->host_status = code; - ncr_complete (np, cp); - } - cp = cp->link_ccb; - } -} - -/* -** Reset ncr chip. -*/ - -/* Some initialisation must be done immediately following reset, for 53c720, - * at least. EA (dcntl bit 5) isn't set here as it is set once only in - * the _detect function. - */ -static void ncr_chip_reset(struct ncb *np, int delay) -{ - OUTB (nc_istat, SRST); - udelay(delay); - OUTB (nc_istat, 0 ); - - if (np->features & FE_EHP) - OUTB (nc_ctest0, EHP); - if (np->features & FE_MUX) - OUTB (nc_ctest4, MUX); -} - - -/*========================================================== -** -** -** Start NCR chip. -** -** -**========================================================== -*/ - -void ncr_init (struct ncb *np, int reset, char * msg, u_long code) -{ - int i; - - /* - ** Reset chip if asked, otherwise just clear fifos. - */ - - if (reset) { - OUTB (nc_istat, SRST); - udelay(100); - } - else { - OUTB (nc_stest3, TE|CSF); - OUTONB (nc_ctest3, CLF); - } - - /* - ** Message. - */ - - if (msg) printk (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg); - - /* - ** Clear Start Queue - */ - np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */ - for (i = 1; i < MAX_START + MAX_START; i += 2) - np->scripth0->tryloop[i] = - cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); - - /* - ** Start at first entry. - */ - np->squeueput = 0; - np->script0->startpos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tryloop)); - -#ifdef SCSI_NCR_CCB_DONE_SUPPORT - /* - ** Clear Done Queue - */ - for (i = 0; i < MAX_DONE; i++) { - np->ccb_done[i] = (struct ccb *)CCB_DONE_EMPTY; - np->scripth0->done_queue[5*i + 4] = - cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end)); - } -#endif - - /* - ** Start at first entry. - */ - np->script0->done_pos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np,done_queue)); - np->ccb_done_ic = MAX_DONE-1; - np->scripth0->done_queue[5*(MAX_DONE-1) + 4] = - cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug)); - - /* - ** Wakeup all pending jobs. - */ - ncr_wakeup (np, code); - - /* - ** Init chip. - */ - - /* - ** Remove reset; big delay because the 895 needs time for the - ** bus mode to settle - */ - ncr_chip_reset(np, 2000); - - OUTB (nc_scntl0, np->rv_scntl0 | 0xc0); - /* full arb., ena parity, par->ATN */ - OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ - - ncr_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ - - OUTB (nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ - OUTW (nc_respid, 1ul<myaddr); /* Id to respond to */ - OUTB (nc_istat , SIGP ); /* Signal Process */ - OUTB (nc_dmode , np->rv_dmode); /* Burst length, dma mode */ - OUTB (nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ - - OUTB (nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ - OUTB (nc_ctest0, np->rv_ctest0); /* 720: CDIS and EHP */ - OUTB (nc_ctest3, np->rv_ctest3); /* Write and invalidate */ - OUTB (nc_ctest4, np->rv_ctest4); /* Master parity checking */ - - OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */ - OUTB (nc_stest3, TE); /* TolerANT enable */ - OUTB (nc_stime0, 0x0c ); /* HTH disabled STO 0.25 sec */ - - /* - ** Disable disconnects. - */ - - np->disc = 0; - - /* - ** Enable GPIO0 pin for writing if LED support. - */ - - if (np->features & FE_LED0) { - OUTOFFB (nc_gpcntl, 0x01); - } - - /* - ** enable ints - */ - - OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); - OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID); - - /* - ** Fill in target structure. - ** Reinitialize usrsync. - ** Reinitialize usrwide. - ** Prepare sync negotiation according to actual SCSI bus mode. - */ - - for (i=0;itarget[i]; - - tp->sval = 0; - tp->wval = np->rv_scntl3; - - if (tp->usrsync != 255) { - if (tp->usrsync <= np->maxsync) { - if (tp->usrsync < np->minsync) { - tp->usrsync = np->minsync; - } - } - else - tp->usrsync = 255; - } - - if (tp->usrwide > np->maxwide) - tp->usrwide = np->maxwide; - - } - - /* - ** Start script processor. - */ - if (np->paddr2) { - if (bootverbose) - printk ("%s: Downloading SCSI SCRIPTS.\n", - ncr_name(np)); - OUTL (nc_scratcha, vtobus(np->script0)); - OUTL_DSP (NCB_SCRIPTH_PHYS (np, start_ram)); - } - else - OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); -} - -/*========================================================== -** -** Prepare the negotiation values for wide and -** synchronous transfers. -** -**========================================================== -*/ - -static void ncr_negotiate (struct ncb* np, struct tcb* tp) -{ - /* - ** minsync unit is 4ns ! - */ - - u_long minsync = tp->usrsync; - - /* - ** SCSI bus mode limit - */ - - if (np->scsi_mode && np->scsi_mode == SMODE_SE) { - if (minsync < 12) minsync = 12; - } - - /* - ** our limit .. - */ - - if (minsync < np->minsync) - minsync = np->minsync; - - /* - ** divider limit - */ - - if (minsync > np->maxsync) - minsync = 255; - - if (tp->maxoffs > np->maxoffs) - tp->maxoffs = np->maxoffs; - - tp->minsync = minsync; - tp->maxoffs = (minsync<255 ? tp->maxoffs : 0); - - /* - ** period=0: has to negotiate sync transfer - */ - - tp->period=0; - - /* - ** widedone=0: has to negotiate wide transfer - */ - tp->widedone=0; -} - -/*========================================================== -** -** Get clock factor and sync divisor for a given -** synchronous factor period. -** Returns the clock factor (in sxfer) and scntl3 -** synchronous divisor field. -** -**========================================================== -*/ - -static void ncr_getsync(struct ncb *np, u_char sfac, u_char *fakp, u_char *scntl3p) -{ - u_long clk = np->clock_khz; /* SCSI clock frequency in kHz */ - int div = np->clock_divn; /* Number of divisors supported */ - u_long fak; /* Sync factor in sxfer */ - u_long per; /* Period in tenths of ns */ - u_long kpc; /* (per * clk) */ - - /* - ** Compute the synchronous period in tenths of nano-seconds - */ - if (sfac <= 10) per = 250; - else if (sfac == 11) per = 303; - else if (sfac == 12) per = 500; - else per = 40 * sfac; - - /* - ** Look for the greatest clock divisor that allows an - ** input speed faster than the period. - */ - kpc = per * clk; - while (--div > 0) - if (kpc >= (div_10M[div] << 2)) break; - - /* - ** Calculate the lowest clock factor that allows an output - ** speed not faster than the period. - */ - fak = (kpc - 1) / div_10M[div] + 1; - -#if 0 /* This optimization does not seem very useful */ - - per = (fak * div_10M[div]) / clk; - - /* - ** Why not to try the immediate lower divisor and to choose - ** the one that allows the fastest output speed ? - ** We don't want input speed too much greater than output speed. - */ - if (div >= 1 && fak < 8) { - u_long fak2, per2; - fak2 = (kpc - 1) / div_10M[div-1] + 1; - per2 = (fak2 * div_10M[div-1]) / clk; - if (per2 < per && fak2 <= 8) { - fak = fak2; - per = per2; - --div; - } - } -#endif - - if (fak < 4) fak = 4; /* Should never happen, too bad ... */ - - /* - ** Compute and return sync parameters for the ncr - */ - *fakp = fak - 4; - *scntl3p = ((div+1) << 4) + (sfac < 25 ? 0x80 : 0); -} - - -/*========================================================== -** -** Set actual values, sync status and patch all ccbs of -** a target according to new sync/wide agreement. -** -**========================================================== -*/ - -static void ncr_set_sync_wide_status (struct ncb *np, u_char target) -{ - struct ccb *cp; - struct tcb *tp = &np->target[target]; - - /* - ** set actual value and sync_status - */ - OUTB (nc_sxfer, tp->sval); - np->sync_st = tp->sval; - OUTB (nc_scntl3, tp->wval); - np->wide_st = tp->wval; - - /* - ** patch ALL ccbs of this target. - */ - for (cp = np->ccb; cp; cp = cp->link_ccb) { - if (!cp->cmd) continue; - if (scmd_id(cp->cmd) != target) continue; -#if 0 - cp->sync_status = tp->sval; - cp->wide_status = tp->wval; -#endif - cp->phys.select.sel_scntl3 = tp->wval; - cp->phys.select.sel_sxfer = tp->sval; - } -} - -/*========================================================== -** -** Switch sync mode for current job and it's target -** -**========================================================== -*/ - -static void ncr_setsync (struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer) -{ - struct scsi_cmnd *cmd = cp->cmd; - struct tcb *tp; - u_char target = INB (nc_sdid) & 0x0f; - u_char idiv; - - BUG_ON(target != (scmd_id(cmd) & 0xf)); - - tp = &np->target[target]; - - if (!scntl3 || !(sxfer & 0x1f)) - scntl3 = np->rv_scntl3; - scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | (np->rv_scntl3 & 0x07); - - /* - ** Deduce the value of controller sync period from scntl3. - ** period is in tenths of nano-seconds. - */ - - idiv = ((scntl3 >> 4) & 0x7); - if ((sxfer & 0x1f) && idiv) - tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz; - else - tp->period = 0xffff; - - /* Stop there if sync parameters are unchanged */ - if (tp->sval == sxfer && tp->wval == scntl3) - return; - tp->sval = sxfer; - tp->wval = scntl3; - - if (sxfer & 0x01f) { - /* Disable extended Sreq/Sack filtering */ - if (tp->period <= 2000) - OUTOFFB(nc_stest2, EXT); - } - - spi_display_xfer_agreement(tp->starget); - - /* - ** set actual value and sync_status - ** patch ALL ccbs of this target. - */ - ncr_set_sync_wide_status(np, target); -} - -/*========================================================== -** -** Switch wide mode for current job and it's target -** SCSI specs say: a SCSI device that accepts a WDTR -** message shall reset the synchronous agreement to -** asynchronous mode. -** -**========================================================== -*/ - -static void ncr_setwide (struct ncb *np, struct ccb *cp, u_char wide, u_char ack) -{ - struct scsi_cmnd *cmd = cp->cmd; - u16 target = INB (nc_sdid) & 0x0f; - struct tcb *tp; - u_char scntl3; - u_char sxfer; - - BUG_ON(target != (scmd_id(cmd) & 0xf)); - - tp = &np->target[target]; - tp->widedone = wide+1; - scntl3 = (tp->wval & (~EWS)) | (wide ? EWS : 0); - - sxfer = ack ? 0 : tp->sval; - - /* - ** Stop there if sync/wide parameters are unchanged - */ - if (tp->sval == sxfer && tp->wval == scntl3) return; - tp->sval = sxfer; - tp->wval = scntl3; - - /* - ** Bells and whistles ;-) - */ - if (bootverbose >= 2) { - dev_info(&cmd->device->sdev_target->dev, "WIDE SCSI %sabled.\n", - (scntl3 & EWS) ? "en" : "dis"); - } - - /* - ** set actual value and sync_status - ** patch ALL ccbs of this target. - */ - ncr_set_sync_wide_status(np, target); -} - -/*========================================================== -** -** Switch tagged mode for a target. -** -**========================================================== -*/ - -static void ncr_setup_tags (struct ncb *np, struct scsi_device *sdev) -{ - unsigned char tn = sdev->id, ln = sdev->lun; - struct tcb *tp = &np->target[tn]; - struct lcb *lp = tp->lp[ln]; - u_char reqtags, maxdepth; - - /* - ** Just in case ... - */ - if ((!tp) || (!lp) || !sdev) - return; - - /* - ** If SCSI device queue depth is not yet set, leave here. - */ - if (!lp->scdev_depth) - return; - - /* - ** Donnot allow more tags than the SCSI driver can queue - ** for this device. - ** Donnot allow more tags than we can handle. - */ - maxdepth = lp->scdev_depth; - if (maxdepth > lp->maxnxs) maxdepth = lp->maxnxs; - if (lp->maxtags > maxdepth) lp->maxtags = maxdepth; - if (lp->numtags > maxdepth) lp->numtags = maxdepth; - - /* - ** only devices conformant to ANSI Version >= 2 - ** only devices capable of tagged commands - ** only if enabled by user .. - */ - if (sdev->tagged_supported && lp->numtags > 1) { - reqtags = lp->numtags; - } else { - reqtags = 1; - } - - /* - ** Update max number of tags - */ - lp->numtags = reqtags; - if (lp->numtags > lp->maxtags) - lp->maxtags = lp->numtags; - - /* - ** If we want to switch tag mode, we must wait - ** for no CCB to be active. - */ - if (reqtags > 1 && lp->usetags) { /* Stay in tagged mode */ - if (lp->queuedepth == reqtags) /* Already announced */ - return; - lp->queuedepth = reqtags; - } - else if (reqtags <= 1 && !lp->usetags) { /* Stay in untagged mode */ - lp->queuedepth = reqtags; - return; - } - else { /* Want to switch tag mode */ - if (lp->busyccbs) /* If not yet safe, return */ - return; - lp->queuedepth = reqtags; - lp->usetags = reqtags > 1 ? 1 : 0; - } - - /* - ** Patch the lun mini-script, according to tag mode. - */ - lp->jump_tag.l_paddr = lp->usetags? - cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) : - cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag)); - - /* - ** Announce change to user. - */ - if (bootverbose) { - if (lp->usetags) { - dev_info(&sdev->sdev_gendev, - "tagged command queue depth set to %d\n", - reqtags); - } else { - dev_info(&sdev->sdev_gendev, - "tagged command queueing disabled\n"); - } - } -} - -/*========================================================== -** -** -** ncr timeout handler. -** -** -**========================================================== -** -** Misused to keep the driver running when -** interrupts are not configured correctly. -** -**---------------------------------------------------------- -*/ - -static void ncr_timeout (struct ncb *np) -{ - u_long thistime = jiffies; - - /* - ** If release process in progress, let's go - ** Set the release stage from 1 to 2 to synchronize - ** with the release process. - */ - - if (np->release_stage) { - if (np->release_stage == 1) np->release_stage = 2; - return; - } - - np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL; - add_timer(&np->timer); - - /* - ** If we are resetting the ncr, wait for settle_time before - ** clearing it. Then command processing will be resumed. - */ - if (np->settle_time) { - if (np->settle_time <= thistime) { - if (bootverbose > 1) - printk("%s: command processing resumed\n", ncr_name(np)); - np->settle_time = 0; - np->disc = 1; - requeue_waiting_list(np); - } - return; - } - - /* - ** Since the generic scsi driver only allows us 0.5 second - ** to perform abort of a command, we must look at ccbs about - ** every 0.25 second. - */ - if (np->lasttime + 4*HZ < thistime) { - /* - ** block ncr interrupts - */ - np->lasttime = thistime; - } - -#ifdef SCSI_NCR_BROKEN_INTR - if (INB(nc_istat) & (INTF|SIP|DIP)) { - - /* - ** Process pending interrupts. - */ - if (DEBUG_FLAGS & DEBUG_TINY) printk ("{"); - ncr_exception (np); - if (DEBUG_FLAGS & DEBUG_TINY) printk ("}"); - } -#endif /* SCSI_NCR_BROKEN_INTR */ -} - -/*========================================================== -** -** log message for real hard errors -** -** "ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc)." -** " reg: r0 r1 r2 r3 r4 r5 r6 ..... rf." -** -** exception register: -** ds: dstat -** si: sist -** -** SCSI bus lines: -** so: control lines as driver by NCR. -** si: control lines as seen by NCR. -** sd: scsi data lines as seen by NCR. -** -** wide/fastmode: -** sxfer: (see the manual) -** scntl3: (see the manual) -** -** current script command: -** dsp: script address (relative to start of script). -** dbc: first word of script command. -** -** First 16 register of the chip: -** r0..rf -** -**========================================================== -*/ - -static void ncr_log_hard_error(struct ncb *np, u16 sist, u_char dstat) -{ - u32 dsp; - int script_ofs; - int script_size; - char *script_name; - u_char *script_base; - int i; - - dsp = INL (nc_dsp); - - if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) { - script_ofs = dsp - np->p_script; - script_size = sizeof(struct script); - script_base = (u_char *) np->script0; - script_name = "script"; - } - else if (np->p_scripth < dsp && - dsp <= np->p_scripth + sizeof(struct scripth)) { - script_ofs = dsp - np->p_scripth; - script_size = sizeof(struct scripth); - script_base = (u_char *) np->scripth0; - script_name = "scripth"; - } else { - script_ofs = dsp; - script_size = 0; - script_base = NULL; - script_name = "mem"; - } - - printk ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n", - ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist, - (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl), - (unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs, - (unsigned)INL (nc_dbc)); - - if (((script_ofs & 3) == 0) && - (unsigned)script_ofs < script_size) { - printk ("%s: script cmd = %08x\n", ncr_name(np), - scr_to_cpu((int) *(ncrcmd *)(script_base + script_ofs))); - } - - printk ("%s: regdump:", ncr_name(np)); - for (i=0; i<16;i++) - printk (" %02x", (unsigned)INB_OFF(i)); - printk (".\n"); -} - -/*============================================================ -** -** ncr chip exception handler. -** -**============================================================ -** -** In normal cases, interrupt conditions occur one at a -** time. The ncr is able to stack in some extra registers -** other interrupts that will occur after the first one. -** But, several interrupts may occur at the same time. -** -** We probably should only try to deal with the normal -** case, but it seems that multiple interrupts occur in -** some cases that are not abnormal at all. -** -** The most frequent interrupt condition is Phase Mismatch. -** We should want to service this interrupt quickly. -** A SCSI parity error may be delivered at the same time. -** The SIR interrupt is not very frequent in this driver, -** since the INTFLY is likely used for command completion -** signaling. -** The Selection Timeout interrupt may be triggered with -** IID and/or UDC. -** The SBMC interrupt (SCSI Bus Mode Change) may probably -** occur at any time. -** -** This handler try to deal as cleverly as possible with all -** the above. -** -**============================================================ -*/ - -void ncr_exception (struct ncb *np) -{ - u_char istat, dstat; - u16 sist; - int i; - - /* - ** interrupt on the fly ? - ** Since the global header may be copied back to a CCB - ** using a posted PCI memory write, the last operation on - ** the istat register is a READ in order to flush posted - ** PCI write commands. - */ - istat = INB (nc_istat); - if (istat & INTF) { - OUTB (nc_istat, (istat & SIGP) | INTF); - istat = INB (nc_istat); - if (DEBUG_FLAGS & DEBUG_TINY) printk ("F "); - ncr_wakeup_done (np); - } - - if (!(istat & (SIP|DIP))) - return; - - if (istat & CABRT) - OUTB (nc_istat, CABRT); - - /* - ** Steinbach's Guideline for Systems Programming: - ** Never test for an error condition you don't know how to handle. - */ - - sist = (istat & SIP) ? INW (nc_sist) : 0; - dstat = (istat & DIP) ? INB (nc_dstat) : 0; - - if (DEBUG_FLAGS & DEBUG_TINY) - printk ("<%d|%x:%x|%x:%x>", - (int)INB(nc_scr0), - dstat,sist, - (unsigned)INL(nc_dsp), - (unsigned)INL(nc_dbc)); - - /*======================================================== - ** First, interrupts we want to service cleanly. - ** - ** Phase mismatch is the most frequent interrupt, and - ** so we have to service it as quickly and as cleanly - ** as possible. - ** Programmed interrupts are rarely used in this driver, - ** but we must handle them cleanly anyway. - ** We try to deal with PAR and SBMC combined with - ** some other interrupt(s). - **========================================================= - */ - - if (!(sist & (STO|GEN|HTH|SGE|UDC|RST)) && - !(dstat & (MDPE|BF|ABRT|IID))) { - if ((sist & SBMC) && ncr_int_sbmc (np)) - return; - if ((sist & PAR) && ncr_int_par (np)) - return; - if (sist & MA) { - ncr_int_ma (np); - return; - } - if (dstat & SIR) { - ncr_int_sir (np); - return; - } - /* - ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 2. - */ - if (!(sist & (SBMC|PAR)) && !(dstat & SSI)) { - printk( "%s: unknown interrupt(s) ignored, " - "ISTAT=%x DSTAT=%x SIST=%x\n", - ncr_name(np), istat, dstat, sist); - return; - } - OUTONB_STD (); - return; - } - - /*======================================================== - ** Now, interrupts that need some fixing up. - ** Order and multiple interrupts is so less important. - ** - ** If SRST has been asserted, we just reset the chip. - ** - ** Selection is intirely handled by the chip. If the - ** chip says STO, we trust it. Seems some other - ** interrupts may occur at the same time (UDC, IID), so - ** we ignore them. In any case we do enough fix-up - ** in the service routine. - ** We just exclude some fatal dma errors. - **========================================================= - */ - - if (sist & RST) { - ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET); - return; - } - - if ((sist & STO) && - !(dstat & (MDPE|BF|ABRT))) { - /* - ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 1. - */ - OUTONB (nc_ctest3, CLF); - - ncr_int_sto (np); - return; - } - - /*========================================================= - ** Now, interrupts we are not able to recover cleanly. - ** (At least for the moment). - ** - ** Do the register dump. - ** Log message for real hard errors. - ** Clear all fifos. - ** For MDPE, BF, ABORT, IID, SGE and HTH we reset the - ** BUS and the chip. - ** We are more soft for UDC. - **========================================================= - */ - - if (time_after(jiffies, np->regtime)) { - np->regtime = jiffies + 10*HZ; - for (i = 0; iregdump); i++) - ((char*)&np->regdump)[i] = INB_OFF(i); - np->regdump.nc_dstat = dstat; - np->regdump.nc_sist = sist; - } - - ncr_log_hard_error(np, sist, dstat); - - printk ("%s: have to clear fifos.\n", ncr_name (np)); - OUTB (nc_stest3, TE|CSF); - OUTONB (nc_ctest3, CLF); - - if ((sist & (SGE)) || - (dstat & (MDPE|BF|ABRT|IID))) { - ncr_start_reset(np); - return; - } - - if (sist & HTH) { - printk ("%s: handshake timeout\n", ncr_name(np)); - ncr_start_reset(np); - return; - } - - if (sist & UDC) { - printk ("%s: unexpected disconnect\n", ncr_name(np)); - OUTB (HS_PRT, HS_UNEXPECTED); - OUTL_DSP (NCB_SCRIPT_PHYS (np, cleanup)); - return; - } - - /*========================================================= - ** We just miss the cause of the interrupt. :( - ** Print a message. The timeout will do the real work. - **========================================================= - */ - printk ("%s: unknown interrupt\n", ncr_name(np)); -} - -/*========================================================== -** -** ncr chip exception handler for selection timeout -** -**========================================================== -** -** There seems to be a bug in the 53c810. -** Although a STO-Interrupt is pending, -** it continues executing script commands. -** But it will fail and interrupt (IID) on -** the next instruction where it's looking -** for a valid phase. -** -**---------------------------------------------------------- -*/ - -void ncr_int_sto (struct ncb *np) -{ - u_long dsa; - struct ccb *cp; - if (DEBUG_FLAGS & DEBUG_TINY) printk ("T"); - - /* - ** look for ccb and set the status. - */ - - dsa = INL (nc_dsa); - cp = np->ccb; - while (cp && (CCB_PHYS (cp, phys) != dsa)) - cp = cp->link_ccb; - - if (cp) { - cp-> host_status = HS_SEL_TIMEOUT; - ncr_complete (np, cp); - } - - /* - ** repair start queue and jump to start point. - */ - - OUTL_DSP (NCB_SCRIPTH_PHYS (np, sto_restart)); - return; -} - -/*========================================================== -** -** ncr chip exception handler for SCSI bus mode change -** -**========================================================== -** -** spi2-r12 11.2.3 says a transceiver mode change must -** generate a reset event and a device that detects a reset -** event shall initiate a hard reset. It says also that a -** device that detects a mode change shall set data transfer -** mode to eight bit asynchronous, etc... -** So, just resetting should be enough. -** -** -**---------------------------------------------------------- -*/ - -static int ncr_int_sbmc (struct ncb *np) -{ - u_char scsi_mode = INB (nc_stest4) & SMODE; - - if (scsi_mode != np->scsi_mode) { - printk("%s: SCSI bus mode change from %x to %x.\n", - ncr_name(np), np->scsi_mode, scsi_mode); - - np->scsi_mode = scsi_mode; - - - /* - ** Suspend command processing for 1 second and - ** reinitialize all except the chip. - */ - np->settle_time = jiffies + HZ; - ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET); - return 1; - } - return 0; -} - -/*========================================================== -** -** ncr chip exception handler for SCSI parity error. -** -**========================================================== -** -** -**---------------------------------------------------------- -*/ - -static int ncr_int_par (struct ncb *np) -{ - u_char hsts = INB (HS_PRT); - u32 dbc = INL (nc_dbc); - u_char sstat1 = INB (nc_sstat1); - int phase = -1; - int msg = -1; - u32 jmp; - - printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SSTAT1=%x\n", - ncr_name(np), hsts, dbc, sstat1); - - /* - * Ignore the interrupt if the NCR is not connected - * to the SCSI bus, since the right work should have - * been done on unexpected disconnection handling. - */ - if (!(INB (nc_scntl1) & ISCON)) - return 0; - - /* - * If the nexus is not clearly identified, reset the bus. - * We will try to do better later. - */ - if (hsts & HS_INVALMASK) - goto reset_all; - - /* - * If the SCSI parity error occurs in MSG IN phase, prepare a - * MSG PARITY message. Otherwise, prepare a INITIATOR DETECTED - * ERROR message and let the device decide to retry the command - * or to terminate with check condition. If we were in MSG IN - * phase waiting for the response of a negotiation, we will - * get SIR_NEGO_FAILED at dispatch. - */ - if (!(dbc & 0xc0000000)) - phase = (dbc >> 24) & 7; - if (phase == 7) - msg = MSG_PARITY_ERROR; - else - msg = INITIATOR_ERROR; - - - /* - * If the NCR stopped on a MOVE ^ DATA_IN, we jump to a - * script that will ignore all data in bytes until phase - * change, since we are not sure the chip will wait the phase - * change prior to delivering the interrupt. - */ - if (phase == 1) - jmp = NCB_SCRIPTH_PHYS (np, par_err_data_in); - else - jmp = NCB_SCRIPTH_PHYS (np, par_err_other); - - OUTONB (nc_ctest3, CLF ); /* clear dma fifo */ - OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ - - np->msgout[0] = msg; - OUTL_DSP (jmp); - return 1; - -reset_all: - ncr_start_reset(np); - return 1; -} - -/*========================================================== -** -** -** ncr chip exception handler for phase errors. -** -** -**========================================================== -** -** We have to construct a new transfer descriptor, -** to transfer the rest of the current block. -** -**---------------------------------------------------------- -*/ - -static void ncr_int_ma (struct ncb *np) -{ - u32 dbc; - u32 rest; - u32 dsp; - u32 dsa; - u32 nxtdsp; - u32 newtmp; - u32 *vdsp; - u32 oadr, olen; - u32 *tblp; - ncrcmd *newcmd; - u_char cmd, sbcl; - struct ccb *cp; - - dsp = INL (nc_dsp); - dbc = INL (nc_dbc); - sbcl = INB (nc_sbcl); - - cmd = dbc >> 24; - rest = dbc & 0xffffff; - - /* - ** Take into account dma fifo and various buffers and latches, - ** only if the interrupted phase is an OUTPUT phase. - */ - - if ((cmd & 1) == 0) { - u_char ctest5, ss0, ss2; - u16 delta; - - ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0; - if (ctest5 & DFS) - delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff; - else - delta=(INB (nc_dfifo) - rest) & 0x7f; - - /* - ** The data in the dma fifo has not been transferred to - ** the target -> add the amount to the rest - ** and clear the data. - ** Check the sstat2 register in case of wide transfer. - */ - - rest += delta; - ss0 = INB (nc_sstat0); - if (ss0 & OLF) rest++; - if (ss0 & ORF) rest++; - if (INB(nc_scntl3) & EWS) { - ss2 = INB (nc_sstat2); - if (ss2 & OLF1) rest++; - if (ss2 & ORF1) rest++; - } - - if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) - printk ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7, - (unsigned) rest, (unsigned) delta, ss0); - - } else { - if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) - printk ("P%x%x RL=%d ", cmd&7, sbcl&7, rest); - } - - /* - ** Clear fifos. - */ - OUTONB (nc_ctest3, CLF ); /* clear dma fifo */ - OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ - - /* - ** locate matching cp. - ** if the interrupted phase is DATA IN or DATA OUT, - ** trust the global header. - */ - dsa = INL (nc_dsa); - if (!(cmd & 6)) { - cp = np->header.cp; - if (CCB_PHYS(cp, phys) != dsa) - cp = NULL; - } else { - cp = np->ccb; - while (cp && (CCB_PHYS (cp, phys) != dsa)) - cp = cp->link_ccb; - } - - /* - ** try to find the interrupted script command, - ** and the address at which to continue. - */ - vdsp = NULL; - nxtdsp = 0; - if (dsp > np->p_script && - dsp <= np->p_script + sizeof(struct script)) { - vdsp = (u32 *)((char*)np->script0 + (dsp-np->p_script-8)); - nxtdsp = dsp; - } - else if (dsp > np->p_scripth && - dsp <= np->p_scripth + sizeof(struct scripth)) { - vdsp = (u32 *)((char*)np->scripth0 + (dsp-np->p_scripth-8)); - nxtdsp = dsp; - } - else if (cp) { - if (dsp == CCB_PHYS (cp, patch[2])) { - vdsp = &cp->patch[0]; - nxtdsp = scr_to_cpu(vdsp[3]); - } - else if (dsp == CCB_PHYS (cp, patch[6])) { - vdsp = &cp->patch[4]; - nxtdsp = scr_to_cpu(vdsp[3]); - } - } - - /* - ** log the information - */ - - if (DEBUG_FLAGS & DEBUG_PHASE) { - printk ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", - cp, np->header.cp, - (unsigned)dsp, - (unsigned)nxtdsp, vdsp, cmd); - } - - /* - ** cp=0 means that the DSA does not point to a valid control - ** block. This should not happen since we donnot use multi-byte - ** move while we are being reselected ot after command complete. - ** We are not able to recover from such a phase error. - */ - if (!cp) { - printk ("%s: SCSI phase error fixup: " - "CCB already dequeued (0x%08lx)\n", - ncr_name (np), (u_long) np->header.cp); - goto reset_all; - } - - /* - ** get old startaddress and old length. - */ - - oadr = scr_to_cpu(vdsp[1]); - - if (cmd & 0x10) { /* Table indirect */ - tblp = (u32 *) ((char*) &cp->phys + oadr); - olen = scr_to_cpu(tblp[0]); - oadr = scr_to_cpu(tblp[1]); - } else { - tblp = (u32 *) 0; - olen = scr_to_cpu(vdsp[0]) & 0xffffff; - } - - if (DEBUG_FLAGS & DEBUG_PHASE) { - printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", - (unsigned) (scr_to_cpu(vdsp[0]) >> 24), - tblp, - (unsigned) olen, - (unsigned) oadr); - } - - /* - ** check cmd against assumed interrupted script command. - */ - - if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) { - PRINT_ADDR(cp->cmd, "internal error: cmd=%02x != %02x=(vdsp[0] " - ">> 24)\n", cmd, scr_to_cpu(vdsp[0]) >> 24); - - goto reset_all; - } - - /* - ** cp != np->header.cp means that the header of the CCB - ** currently being processed has not yet been copied to - ** the global header area. That may happen if the device did - ** not accept all our messages after having been selected. - */ - if (cp != np->header.cp) { - printk ("%s: SCSI phase error fixup: " - "CCB address mismatch (0x%08lx != 0x%08lx)\n", - ncr_name (np), (u_long) cp, (u_long) np->header.cp); - } - - /* - ** if old phase not dataphase, leave here. - */ - - if (cmd & 0x06) { - PRINT_ADDR(cp->cmd, "phase change %x-%x %d@%08x resid=%d.\n", - cmd&7, sbcl&7, (unsigned)olen, - (unsigned)oadr, (unsigned)rest); - goto unexpected_phase; - } - - /* - ** choose the correct patch area. - ** if savep points to one, choose the other. - */ - - newcmd = cp->patch; - newtmp = CCB_PHYS (cp, patch); - if (newtmp == scr_to_cpu(cp->phys.header.savep)) { - newcmd = &cp->patch[4]; - newtmp = CCB_PHYS (cp, patch[4]); - } - - /* - ** fillin the commands - */ - - newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest); - newcmd[1] = cpu_to_scr(oadr + olen - rest); - newcmd[2] = cpu_to_scr(SCR_JUMP); - newcmd[3] = cpu_to_scr(nxtdsp); - - if (DEBUG_FLAGS & DEBUG_PHASE) { - PRINT_ADDR(cp->cmd, "newcmd[%d] %x %x %x %x.\n", - (int) (newcmd - cp->patch), - (unsigned)scr_to_cpu(newcmd[0]), - (unsigned)scr_to_cpu(newcmd[1]), - (unsigned)scr_to_cpu(newcmd[2]), - (unsigned)scr_to_cpu(newcmd[3])); - } - /* - ** fake the return address (to the patch). - ** and restart script processor at dispatcher. - */ - OUTL (nc_temp, newtmp); - OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch)); - return; - - /* - ** Unexpected phase changes that occurs when the current phase - ** is not a DATA IN or DATA OUT phase are due to error conditions. - ** Such event may only happen when the SCRIPTS is using a - ** multibyte SCSI MOVE. - ** - ** Phase change Some possible cause - ** - ** COMMAND --> MSG IN SCSI parity error detected by target. - ** COMMAND --> STATUS Bad command or refused by target. - ** MSG OUT --> MSG IN Message rejected by target. - ** MSG OUT --> COMMAND Bogus target that discards extended - ** negotiation messages. - ** - ** The code below does not care of the new phase and so - ** trusts the target. Why to annoy it ? - ** If the interrupted phase is COMMAND phase, we restart at - ** dispatcher. - ** If a target does not get all the messages after selection, - ** the code assumes blindly that the target discards extended - ** messages and clears the negotiation status. - ** If the target does not want all our response to negotiation, - ** we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids - ** bloat for such a should_not_happen situation). - ** In all other situation, we reset the BUS. - ** Are these assumptions reasonable ? (Wait and see ...) - */ -unexpected_phase: - dsp -= 8; - nxtdsp = 0; - - switch (cmd & 7) { - case 2: /* COMMAND phase */ - nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); - break; -#if 0 - case 3: /* STATUS phase */ - nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); - break; -#endif - case 6: /* MSG OUT phase */ - np->scripth->nxtdsp_go_on[0] = cpu_to_scr(dsp + 8); - if (dsp == NCB_SCRIPT_PHYS (np, send_ident)) { - cp->host_status = HS_BUSY; - nxtdsp = NCB_SCRIPTH_PHYS (np, clratn_go_on); - } - else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) || - dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) { - nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase); - } - break; -#if 0 - case 7: /* MSG IN phase */ - nxtdsp = NCB_SCRIPT_PHYS (np, clrack); - break; -#endif - } - - if (nxtdsp) { - OUTL_DSP (nxtdsp); - return; - } - -reset_all: - ncr_start_reset(np); -} - - -static void ncr_sir_to_redo(struct ncb *np, int num, struct ccb *cp) -{ - struct scsi_cmnd *cmd = cp->cmd; - struct tcb *tp = &np->target[cmd->device->id]; - struct lcb *lp = tp->lp[cmd->device->lun]; - struct list_head *qp; - struct ccb * cp2; - int disc_cnt = 0; - int busy_cnt = 0; - u32 startp; - u_char s_status = INB (SS_PRT); - - /* - ** Let the SCRIPTS processor skip all not yet started CCBs, - ** and count disconnected CCBs. Since the busy queue is in - ** the same order as the chip start queue, disconnected CCBs - ** are before cp and busy ones after. - */ - if (lp) { - qp = lp->busy_ccbq.prev; - while (qp != &lp->busy_ccbq) { - cp2 = list_entry(qp, struct ccb, link_ccbq); - qp = qp->prev; - ++busy_cnt; - if (cp2 == cp) - break; - cp2->start.schedule.l_paddr = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, skip)); - } - lp->held_ccb = cp; /* Requeue when this one completes */ - disc_cnt = lp->queuedccbs - busy_cnt; - } - - switch(s_status) { - default: /* Just for safety, should never happen */ - case S_QUEUE_FULL: - /* - ** Decrease number of tags to the number of - ** disconnected commands. - */ - if (!lp) - goto out; - if (bootverbose >= 1) { - PRINT_ADDR(cmd, "QUEUE FULL! %d busy, %d disconnected " - "CCBs\n", busy_cnt, disc_cnt); - } - if (disc_cnt < lp->numtags) { - lp->numtags = disc_cnt > 2 ? disc_cnt : 2; - lp->num_good = 0; - ncr_setup_tags (np, cmd->device); - } - /* - ** Requeue the command to the start queue. - ** If any disconnected commands, - ** Clear SIGP. - ** Jump to reselect. - */ - cp->phys.header.savep = cp->startp; - cp->host_status = HS_BUSY; - cp->scsi_status = S_ILLEGAL; - - ncr_put_start_queue(np, cp); - if (disc_cnt) - INB (nc_ctest2); /* Clear SIGP */ - OUTL_DSP (NCB_SCRIPT_PHYS (np, reselect)); - return; - case S_TERMINATED: - case S_CHECK_COND: - /* - ** If we were requesting sense, give up. - */ - if (cp->auto_sense) - goto out; - - /* - ** Device returned CHECK CONDITION status. - ** Prepare all needed data strutures for getting - ** sense data. - ** - ** identify message - */ - cp->scsi_smsg2[0] = IDENTIFY(0, cmd->device->lun); - cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg2)); - cp->phys.smsg.size = cpu_to_scr(1); - - /* - ** sense command - */ - cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, sensecmd)); - cp->phys.cmd.size = cpu_to_scr(6); - - /* - ** patch requested size into sense command - */ - cp->sensecmd[0] = 0x03; - cp->sensecmd[1] = cmd->device->lun << 5; - cp->sensecmd[4] = sizeof(cp->sense_buf); - - /* - ** sense data - */ - memset(cp->sense_buf, 0, sizeof(cp->sense_buf)); - cp->phys.sense.addr = cpu_to_scr(CCB_PHYS(cp,sense_buf[0])); - cp->phys.sense.size = cpu_to_scr(sizeof(cp->sense_buf)); - - /* - ** requeue the command. - */ - startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in)); - - cp->phys.header.savep = startp; - cp->phys.header.goalp = startp + 24; - cp->phys.header.lastp = startp; - cp->phys.header.wgoalp = startp + 24; - cp->phys.header.wlastp = startp; - - cp->host_status = HS_BUSY; - cp->scsi_status = S_ILLEGAL; - cp->auto_sense = s_status; - - cp->start.schedule.l_paddr = - cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); - - /* - ** Select without ATN for quirky devices. - */ - if (cmd->device->select_no_atn) - cp->start.schedule.l_paddr = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn)); - - ncr_put_start_queue(np, cp); - - OUTL_DSP (NCB_SCRIPT_PHYS (np, start)); - return; - } - -out: - OUTONB_STD (); - return; -} - - -/*========================================================== -** -** -** ncr chip exception handler for programmed interrupts. -** -** -**========================================================== -*/ - -void ncr_int_sir (struct ncb *np) -{ - u_char scntl3; - u_char chg, ofs, per, fak, wide; - u_char num = INB (nc_dsps); - struct ccb *cp=NULL; - u_long dsa = INL (nc_dsa); - u_char target = INB (nc_sdid) & 0x0f; - struct tcb *tp = &np->target[target]; - struct scsi_target *starget = tp->starget; - - if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num); - - switch (num) { - case SIR_INTFLY: - /* - ** This is used for HP Zalon/53c720 where INTFLY - ** operation is currently broken. - */ - ncr_wakeup_done(np); -#ifdef SCSI_NCR_CCB_DONE_SUPPORT - OUTL(nc_dsp, NCB_SCRIPT_PHYS (np, done_end) + 8); -#else - OUTL(nc_dsp, NCB_SCRIPT_PHYS (np, start)); -#endif - return; - case SIR_RESEL_NO_MSG_IN: - case SIR_RESEL_NO_IDENTIFY: - /* - ** If devices reselecting without sending an IDENTIFY - ** message still exist, this should help. - ** We just assume lun=0, 1 CCB, no tag. - */ - if (tp->lp[0]) { - OUTL_DSP (scr_to_cpu(tp->lp[0]->jump_ccb[0])); - return; - } - case SIR_RESEL_BAD_TARGET: /* Will send a TARGET RESET message */ - case SIR_RESEL_BAD_LUN: /* Will send a TARGET RESET message */ - case SIR_RESEL_BAD_I_T_L_Q: /* Will send an ABORT TAG message */ - case SIR_RESEL_BAD_I_T_L: /* Will send an ABORT message */ - printk ("%s:%d: SIR %d, " - "incorrect nexus identification on reselection\n", - ncr_name (np), target, num); - goto out; - case SIR_DONE_OVERFLOW: - printk ("%s:%d: SIR %d, " - "CCB done queue overflow\n", - ncr_name (np), target, num); - goto out; - case SIR_BAD_STATUS: - cp = np->header.cp; - if (!cp || CCB_PHYS (cp, phys) != dsa) - goto out; - ncr_sir_to_redo(np, num, cp); - return; - default: - /* - ** lookup the ccb - */ - cp = np->ccb; - while (cp && (CCB_PHYS (cp, phys) != dsa)) - cp = cp->link_ccb; - - BUG_ON(!cp); - BUG_ON(cp != np->header.cp); - - if (!cp || cp != np->header.cp) - goto out; - } - - switch (num) { -/*----------------------------------------------------------------------------- -** -** Was Sie schon immer ueber transfermode negotiation wissen wollten ... -** ("Everything you've always wanted to know about transfer mode -** negotiation") -** -** We try to negotiate sync and wide transfer only after -** a successful inquire command. We look at byte 7 of the -** inquire data to determine the capabilities of the target. -** -** When we try to negotiate, we append the negotiation message -** to the identify and (maybe) simple tag message. -** The host status field is set to HS_NEGOTIATE to mark this -** situation. -** -** If the target doesn't answer this message immediately -** (as required by the standard), the SIR_NEGO_FAIL interrupt -** will be raised eventually. -** The handler removes the HS_NEGOTIATE status, and sets the -** negotiated value to the default (async / nowide). -** -** If we receive a matching answer immediately, we check it -** for validity, and set the values. -** -** If we receive a Reject message immediately, we assume the -** negotiation has failed, and fall back to standard values. -** -** If we receive a negotiation message while not in HS_NEGOTIATE -** state, it's a target initiated negotiation. We prepare a -** (hopefully) valid answer, set our parameters, and send back -** this answer to the target. -** -** If the target doesn't fetch the answer (no message out phase), -** we assume the negotiation has failed, and fall back to default -** settings. -** -** When we set the values, we adjust them in all ccbs belonging -** to this target, in the controller's register, and in the "phys" -** field of the controller's struct ncb. -** -** Possible cases: hs sir msg_in value send goto -** We try to negotiate: -** -> target doesn't msgin NEG FAIL noop defa. - dispatch -** -> target rejected our msg NEG FAIL reject defa. - dispatch -** -> target answered (ok) NEG SYNC sdtr set - clrack -** -> target answered (!ok) NEG SYNC sdtr defa. REJ--->msg_bad -** -> target answered (ok) NEG WIDE wdtr set - clrack -** -> target answered (!ok) NEG WIDE wdtr defa. REJ--->msg_bad -** -> any other msgin NEG FAIL noop defa. - dispatch -** -** Target tries to negotiate: -** -> incoming message --- SYNC sdtr set SDTR - -** -> incoming message --- WIDE wdtr set WDTR - -** We sent our answer: -** -> target doesn't msgout --- PROTO ? defa. - dispatch -** -**----------------------------------------------------------------------------- -*/ - - case SIR_NEGO_FAILED: - /*------------------------------------------------------- - ** - ** Negotiation failed. - ** Target doesn't send an answer message, - ** or target rejected our message. - ** - ** Remove negotiation request. - ** - **------------------------------------------------------- - */ - OUTB (HS_PRT, HS_BUSY); - - /* fall through */ - - case SIR_NEGO_PROTO: - /*------------------------------------------------------- - ** - ** Negotiation failed. - ** Target doesn't fetch the answer message. - ** - **------------------------------------------------------- - */ - - if (DEBUG_FLAGS & DEBUG_NEGO) { - PRINT_ADDR(cp->cmd, "negotiation failed sir=%x " - "status=%x.\n", num, cp->nego_status); - } - - /* - ** any error in negotiation: - ** fall back to default mode. - */ - switch (cp->nego_status) { - - case NS_SYNC: - spi_period(starget) = 0; - spi_offset(starget) = 0; - ncr_setsync (np, cp, 0, 0xe0); - break; - - case NS_WIDE: - spi_width(starget) = 0; - ncr_setwide (np, cp, 0, 0); - break; - - } - np->msgin [0] = NOP; - np->msgout[0] = NOP; - cp->nego_status = 0; - break; - - case SIR_NEGO_SYNC: - if (DEBUG_FLAGS & DEBUG_NEGO) { - ncr_print_msg(cp, "sync msgin", np->msgin); - } - - chg = 0; - per = np->msgin[3]; - ofs = np->msgin[4]; - if (ofs==0) per=255; - - /* - ** if target sends SDTR message, - ** it CAN transfer synch. - */ - - if (ofs && starget) - spi_support_sync(starget) = 1; - - /* - ** check values against driver limits. - */ - - if (per < np->minsync) - {chg = 1; per = np->minsync;} - if (per < tp->minsync) - {chg = 1; per = tp->minsync;} - if (ofs > tp->maxoffs) - {chg = 1; ofs = tp->maxoffs;} - - /* - ** Check against controller limits. - */ - fak = 7; - scntl3 = 0; - if (ofs != 0) { - ncr_getsync(np, per, &fak, &scntl3); - if (fak > 7) { - chg = 1; - ofs = 0; - } - } - if (ofs == 0) { - fak = 7; - per = 0; - scntl3 = 0; - tp->minsync = 0; - } - - if (DEBUG_FLAGS & DEBUG_NEGO) { - PRINT_ADDR(cp->cmd, "sync: per=%d scntl3=0x%x ofs=%d " - "fak=%d chg=%d.\n", per, scntl3, ofs, fak, chg); - } - - if (INB (HS_PRT) == HS_NEGOTIATE) { - OUTB (HS_PRT, HS_BUSY); - switch (cp->nego_status) { - - case NS_SYNC: - /* This was an answer message */ - if (chg) { - /* Answer wasn't acceptable. */ - spi_period(starget) = 0; - spi_offset(starget) = 0; - ncr_setsync(np, cp, 0, 0xe0); - OUTL_DSP(NCB_SCRIPT_PHYS (np, msg_bad)); - } else { - /* Answer is ok. */ - spi_period(starget) = per; - spi_offset(starget) = ofs; - ncr_setsync(np, cp, scntl3, (fak<<5)|ofs); - OUTL_DSP(NCB_SCRIPT_PHYS (np, clrack)); - } - return; - - case NS_WIDE: - spi_width(starget) = 0; - ncr_setwide(np, cp, 0, 0); - break; - } - } - - /* - ** It was a request. Set value and - ** prepare an answer message - */ - - spi_period(starget) = per; - spi_offset(starget) = ofs; - ncr_setsync(np, cp, scntl3, (fak<<5)|ofs); - - spi_populate_sync_msg(np->msgout, per, ofs); - cp->nego_status = NS_SYNC; - - if (DEBUG_FLAGS & DEBUG_NEGO) { - ncr_print_msg(cp, "sync msgout", np->msgout); - } - - if (!ofs) { - OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad)); - return; - } - np->msgin [0] = NOP; - - break; - - case SIR_NEGO_WIDE: - /* - ** Wide request message received. - */ - if (DEBUG_FLAGS & DEBUG_NEGO) { - ncr_print_msg(cp, "wide msgin", np->msgin); - } - - /* - ** get requested values. - */ - - chg = 0; - wide = np->msgin[3]; - - /* - ** if target sends WDTR message, - ** it CAN transfer wide. - */ - - if (wide && starget) - spi_support_wide(starget) = 1; - - /* - ** check values against driver limits. - */ - - if (wide > tp->usrwide) - {chg = 1; wide = tp->usrwide;} - - if (DEBUG_FLAGS & DEBUG_NEGO) { - PRINT_ADDR(cp->cmd, "wide: wide=%d chg=%d.\n", wide, - chg); - } - - if (INB (HS_PRT) == HS_NEGOTIATE) { - OUTB (HS_PRT, HS_BUSY); - switch (cp->nego_status) { - - case NS_WIDE: - /* - ** This was an answer message - */ - if (chg) { - /* Answer wasn't acceptable. */ - spi_width(starget) = 0; - ncr_setwide(np, cp, 0, 1); - OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad)); - } else { - /* Answer is ok. */ - spi_width(starget) = wide; - ncr_setwide(np, cp, wide, 1); - OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack)); - } - return; - - case NS_SYNC: - spi_period(starget) = 0; - spi_offset(starget) = 0; - ncr_setsync(np, cp, 0, 0xe0); - break; - } - } - - /* - ** It was a request, set value and - ** prepare an answer message - */ - - spi_width(starget) = wide; - ncr_setwide(np, cp, wide, 1); - spi_populate_width_msg(np->msgout, wide); - - np->msgin [0] = NOP; - - cp->nego_status = NS_WIDE; - - if (DEBUG_FLAGS & DEBUG_NEGO) { - ncr_print_msg(cp, "wide msgout", np->msgin); - } - break; - -/*-------------------------------------------------------------------- -** -** Processing of special messages -** -**-------------------------------------------------------------------- -*/ - - case SIR_REJECT_RECEIVED: - /*----------------------------------------------- - ** - ** We received a MESSAGE_REJECT. - ** - **----------------------------------------------- - */ - - PRINT_ADDR(cp->cmd, "MESSAGE_REJECT received (%x:%x).\n", - (unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]); - break; - - case SIR_REJECT_SENT: - /*----------------------------------------------- - ** - ** We received an unknown message - ** - **----------------------------------------------- - */ - - ncr_print_msg(cp, "MESSAGE_REJECT sent for", np->msgin); - break; - -/*-------------------------------------------------------------------- -** -** Processing of special messages -** -**-------------------------------------------------------------------- -*/ - - case SIR_IGN_RESIDUE: - /*----------------------------------------------- - ** - ** We received an IGNORE RESIDUE message, - ** which couldn't be handled by the script. - ** - **----------------------------------------------- - */ - - PRINT_ADDR(cp->cmd, "IGNORE_WIDE_RESIDUE received, but not yet " - "implemented.\n"); - break; -#if 0 - case SIR_MISSING_SAVE: - /*----------------------------------------------- - ** - ** We received an DISCONNECT message, - ** but the datapointer wasn't saved before. - ** - **----------------------------------------------- - */ - - PRINT_ADDR(cp->cmd, "DISCONNECT received, but datapointer " - "not saved: data=%x save=%x goal=%x.\n", - (unsigned) INL (nc_temp), - (unsigned) scr_to_cpu(np->header.savep), - (unsigned) scr_to_cpu(np->header.goalp)); - break; -#endif - } - -out: - OUTONB_STD (); -} - -/*========================================================== -** -** -** Acquire a control block -** -** -**========================================================== -*/ - -static struct ccb *ncr_get_ccb(struct ncb *np, struct scsi_cmnd *cmd) -{ - u_char tn = cmd->device->id; - u_char ln = cmd->device->lun; - struct tcb *tp = &np->target[tn]; - struct lcb *lp = tp->lp[ln]; - u_char tag = NO_TAG; - struct ccb *cp = NULL; - - /* - ** Lun structure available ? - */ - if (lp) { - struct list_head *qp; - /* - ** Keep from using more tags than we can handle. - */ - if (lp->usetags && lp->busyccbs >= lp->maxnxs) - return NULL; - - /* - ** Allocate a new CCB if needed. - */ - if (list_empty(&lp->free_ccbq)) - ncr_alloc_ccb(np, tn, ln); - - /* - ** Look for free CCB - */ - qp = ncr_list_pop(&lp->free_ccbq); - if (qp) { - cp = list_entry(qp, struct ccb, link_ccbq); - if (cp->magic) { - PRINT_ADDR(cmd, "ccb free list corrupted " - "(@%p)\n", cp); - cp = NULL; - } else { - list_add_tail(qp, &lp->wait_ccbq); - ++lp->busyccbs; - } - } - - /* - ** If a CCB is available, - ** Get a tag for this nexus if required. - */ - if (cp) { - if (lp->usetags) - tag = lp->cb_tags[lp->ia_tag]; - } - else if (lp->actccbs > 0) - return NULL; - } - - /* - ** if nothing available, take the default. - */ - if (!cp) - cp = np->ccb; - - /* - ** Wait until available. - */ -#if 0 - while (cp->magic) { - if (flags & SCSI_NOSLEEP) break; - if (tsleep ((caddr_t)cp, PRIBIO|PCATCH, "ncr", 0)) - break; - } -#endif - - if (cp->magic) - return NULL; - - cp->magic = 1; - - /* - ** Move to next available tag if tag used. - */ - if (lp) { - if (tag != NO_TAG) { - ++lp->ia_tag; - if (lp->ia_tag == MAX_TAGS) - lp->ia_tag = 0; - lp->tags_umap |= (((tagmap_t) 1) << tag); - } - } - - /* - ** Remember all informations needed to free this CCB. - */ - cp->tag = tag; - cp->target = tn; - cp->lun = ln; - - if (DEBUG_FLAGS & DEBUG_TAGS) { - PRINT_ADDR(cmd, "ccb @%p using tag %d.\n", cp, tag); - } - - return cp; -} - -/*========================================================== -** -** -** Release one control block -** -** -**========================================================== -*/ - -static void ncr_free_ccb (struct ncb *np, struct ccb *cp) -{ - struct tcb *tp = &np->target[cp->target]; - struct lcb *lp = tp->lp[cp->lun]; - - if (DEBUG_FLAGS & DEBUG_TAGS) { - PRINT_ADDR(cp->cmd, "ccb @%p freeing tag %d.\n", cp, cp->tag); - } - - /* - ** If lun control block available, - ** decrement active commands and increment credit, - ** free the tag if any and remove the JUMP for reselect. - */ - if (lp) { - if (cp->tag != NO_TAG) { - lp->cb_tags[lp->if_tag++] = cp->tag; - if (lp->if_tag == MAX_TAGS) - lp->if_tag = 0; - lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag); - lp->tags_smap &= lp->tags_umap; - lp->jump_ccb[cp->tag] = - cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l_q)); - } else { - lp->jump_ccb[0] = - cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l)); - } - } - - /* - ** Make this CCB available. - */ - - if (lp) { - if (cp != np->ccb) - list_move(&cp->link_ccbq, &lp->free_ccbq); - --lp->busyccbs; - if (cp->queued) { - --lp->queuedccbs; - } - } - cp -> host_status = HS_IDLE; - cp -> magic = 0; - if (cp->queued) { - --np->queuedccbs; - cp->queued = 0; - } - -#if 0 - if (cp == np->ccb) - wakeup ((caddr_t) cp); -#endif -} - - -#define ncr_reg_bus_addr(r) (np->paddr + offsetof (struct ncr_reg, r)) - -/*------------------------------------------------------------------------ -** Initialize the fixed part of a CCB structure. -**------------------------------------------------------------------------ -**------------------------------------------------------------------------ -*/ -static void ncr_init_ccb(struct ncb *np, struct ccb *cp) -{ - ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4); - - /* - ** Remember virtual and bus address of this ccb. - */ - cp->p_ccb = vtobus(cp); - cp->phys.header.cp = cp; - - /* - ** This allows list_del to work for the default ccb. - */ - INIT_LIST_HEAD(&cp->link_ccbq); - - /* - ** Initialyze the start and restart launch script. - ** - ** COPY(4) @(...p_phys), @(dsa) - ** JUMP @(sched_point) - */ - cp->start.setup_dsa[0] = cpu_to_scr(copy_4); - cp->start.setup_dsa[1] = cpu_to_scr(CCB_PHYS(cp, start.p_phys)); - cp->start.setup_dsa[2] = cpu_to_scr(ncr_reg_bus_addr(nc_dsa)); - cp->start.schedule.l_cmd = cpu_to_scr(SCR_JUMP); - cp->start.p_phys = cpu_to_scr(CCB_PHYS(cp, phys)); - - memcpy(&cp->restart, &cp->start, sizeof(cp->restart)); - - cp->start.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); - cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort)); -} - - -/*------------------------------------------------------------------------ -** Allocate a CCB and initialize its fixed part. -**------------------------------------------------------------------------ -**------------------------------------------------------------------------ -*/ -static void ncr_alloc_ccb(struct ncb *np, u_char tn, u_char ln) -{ - struct tcb *tp = &np->target[tn]; - struct lcb *lp = tp->lp[ln]; - struct ccb *cp = NULL; - - /* - ** Allocate memory for this CCB. - */ - cp = m_calloc_dma(sizeof(struct ccb), "CCB"); - if (!cp) - return; - - /* - ** Count it and initialyze it. - */ - lp->actccbs++; - np->actccbs++; - memset(cp, 0, sizeof (*cp)); - ncr_init_ccb(np, cp); - - /* - ** Chain into wakeup list and free ccb queue and take it - ** into account for tagged commands. - */ - cp->link_ccb = np->ccb->link_ccb; - np->ccb->link_ccb = cp; - - list_add(&cp->link_ccbq, &lp->free_ccbq); -} - -/*========================================================== -** -** -** Allocation of resources for Targets/Luns/Tags. -** -** -**========================================================== -*/ - - -/*------------------------------------------------------------------------ -** Target control block initialisation. -**------------------------------------------------------------------------ -** This data structure is fully initialized after a SCSI command -** has been successfully completed for this target. -** It contains a SCRIPT that is called on target reselection. -**------------------------------------------------------------------------ -*/ -static void ncr_init_tcb (struct ncb *np, u_char tn) -{ - struct tcb *tp = &np->target[tn]; - ncrcmd copy_1 = np->features & FE_PFEN ? SCR_COPY(1) : SCR_COPY_F(1); - int th = tn & 3; - int i; - - /* - ** Jump to next tcb if SFBR does not match this target. - ** JUMP IF (SFBR != #target#), @(next tcb) - */ - tp->jump_tcb.l_cmd = - cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (0x80 + tn)))); - tp->jump_tcb.l_paddr = np->jump_tcb[th].l_paddr; - - /* - ** Load the synchronous transfer register. - ** COPY @(tp->sval), @(sxfer) - */ - tp->getscr[0] = cpu_to_scr(copy_1); - tp->getscr[1] = cpu_to_scr(vtobus (&tp->sval)); -#ifdef SCSI_NCR_BIG_ENDIAN - tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer) ^ 3); -#else - tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer)); -#endif - - /* - ** Load the timing register. - ** COPY @(tp->wval), @(scntl3) - */ - tp->getscr[3] = cpu_to_scr(copy_1); - tp->getscr[4] = cpu_to_scr(vtobus (&tp->wval)); -#ifdef SCSI_NCR_BIG_ENDIAN - tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3) ^ 3); -#else - tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3)); -#endif - - /* - ** Get the IDENTIFY message and the lun. - ** CALL @script(resel_lun) - */ - tp->call_lun.l_cmd = cpu_to_scr(SCR_CALL); - tp->call_lun.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun)); - - /* - ** Look for the lun control block of this nexus. - ** For i = 0 to 3 - ** JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb) - */ - for (i = 0 ; i < 4 ; i++) { - tp->jump_lcb[i].l_cmd = - cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3)))); - tp->jump_lcb[i].l_paddr = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_identify)); - } - - /* - ** Link this target control block to the JUMP chain. - */ - np->jump_tcb[th].l_paddr = cpu_to_scr(vtobus (&tp->jump_tcb)); - - /* - ** These assert's should be moved at driver initialisations. - */ -#ifdef SCSI_NCR_BIG_ENDIAN - BUG_ON(((offsetof(struct ncr_reg, nc_sxfer) ^ - offsetof(struct tcb , sval )) &3) != 3); - BUG_ON(((offsetof(struct ncr_reg, nc_scntl3) ^ - offsetof(struct tcb , wval )) &3) != 3); -#else - BUG_ON(((offsetof(struct ncr_reg, nc_sxfer) ^ - offsetof(struct tcb , sval )) &3) != 0); - BUG_ON(((offsetof(struct ncr_reg, nc_scntl3) ^ - offsetof(struct tcb , wval )) &3) != 0); -#endif -} - - -/*------------------------------------------------------------------------ -** Lun control block allocation and initialization. -**------------------------------------------------------------------------ -** This data structure is allocated and initialized after a SCSI -** command has been successfully completed for this target/lun. -**------------------------------------------------------------------------ -*/ -static struct lcb *ncr_alloc_lcb (struct ncb *np, u_char tn, u_char ln) -{ - struct tcb *tp = &np->target[tn]; - struct lcb *lp = tp->lp[ln]; - ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4); - int lh = ln & 3; - - /* - ** Already done, return. - */ - if (lp) - return lp; - - /* - ** Allocate the lcb. - */ - lp = m_calloc_dma(sizeof(struct lcb), "LCB"); - if (!lp) - goto fail; - memset(lp, 0, sizeof(*lp)); - tp->lp[ln] = lp; - - /* - ** Initialize the target control block if not yet. - */ - if (!tp->jump_tcb.l_cmd) - ncr_init_tcb(np, tn); - - /* - ** Initialize the CCB queue headers. - */ - INIT_LIST_HEAD(&lp->free_ccbq); - INIT_LIST_HEAD(&lp->busy_ccbq); - INIT_LIST_HEAD(&lp->wait_ccbq); - INIT_LIST_HEAD(&lp->skip_ccbq); - - /* - ** Set max CCBs to 1 and use the default 1 entry - ** jump table by default. - */ - lp->maxnxs = 1; - lp->jump_ccb = &lp->jump_ccb_0; - lp->p_jump_ccb = cpu_to_scr(vtobus(lp->jump_ccb)); - - /* - ** Initilialyze the reselect script: - ** - ** Jump to next lcb if SFBR does not match this lun. - ** Load TEMP with the CCB direct jump table bus address. - ** Get the SIMPLE TAG message and the tag. - ** - ** JUMP IF (SFBR != #lun#), @(next lcb) - ** COPY @(lp->p_jump_ccb), @(temp) - ** JUMP @script(resel_notag) - */ - lp->jump_lcb.l_cmd = - cpu_to_scr((SCR_JUMP ^ IFFALSE (MASK (0x80+ln, 0xff)))); - lp->jump_lcb.l_paddr = tp->jump_lcb[lh].l_paddr; - - lp->load_jump_ccb[0] = cpu_to_scr(copy_4); - lp->load_jump_ccb[1] = cpu_to_scr(vtobus (&lp->p_jump_ccb)); - lp->load_jump_ccb[2] = cpu_to_scr(ncr_reg_bus_addr(nc_temp)); - - lp->jump_tag.l_cmd = cpu_to_scr(SCR_JUMP); - lp->jump_tag.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_notag)); - - /* - ** Link this lun control block to the JUMP chain. - */ - tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtobus (&lp->jump_lcb)); - - /* - ** Initialize command queuing control. - */ - lp->busyccbs = 1; - lp->queuedccbs = 1; - lp->queuedepth = 1; -fail: - return lp; -} - - -/*------------------------------------------------------------------------ -** Lun control block setup on INQUIRY data received. -**------------------------------------------------------------------------ -** We only support WIDE, SYNC for targets and CMDQ for logical units. -** This setup is done on each INQUIRY since we are expecting user -** will play with CHANGE DEFINITION commands. :-) -**------------------------------------------------------------------------ -*/ -static struct lcb *ncr_setup_lcb (struct ncb *np, struct scsi_device *sdev) -{ - unsigned char tn = sdev->id, ln = sdev->lun; - struct tcb *tp = &np->target[tn]; - struct lcb *lp = tp->lp[ln]; - - /* If no lcb, try to allocate it. */ - if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln))) - goto fail; - - /* - ** If unit supports tagged commands, allocate the - ** CCB JUMP table if not yet. - */ - if (sdev->tagged_supported && lp->jump_ccb == &lp->jump_ccb_0) { - int i; - lp->jump_ccb = m_calloc_dma(256, "JUMP_CCB"); - if (!lp->jump_ccb) { - lp->jump_ccb = &lp->jump_ccb_0; - goto fail; - } - lp->p_jump_ccb = cpu_to_scr(vtobus(lp->jump_ccb)); - for (i = 0 ; i < 64 ; i++) - lp->jump_ccb[i] = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q)); - for (i = 0 ; i < MAX_TAGS ; i++) - lp->cb_tags[i] = i; - lp->maxnxs = MAX_TAGS; - lp->tags_stime = jiffies + 3*HZ; - ncr_setup_tags (np, sdev); - } - - -fail: - return lp; -} - -/*========================================================== -** -** -** Build Scatter Gather Block -** -** -**========================================================== -** -** The transfer area may be scattered among -** several non adjacent physical pages. -** -** We may use MAX_SCATTER blocks. -** -**---------------------------------------------------------- -*/ - -/* -** We try to reduce the number of interrupts caused -** by unexpected phase changes due to disconnects. -** A typical harddisk may disconnect before ANY block. -** If we wanted to avoid unexpected phase changes at all -** we had to use a break point every 512 bytes. -** Of course the number of scatter/gather blocks is -** limited. -** Under Linux, the scatter/gatter blocks are provided by -** the generic driver. We just have to copy addresses and -** sizes to the data segment array. -*/ - -static int ncr_scatter(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd) -{ - int segment = 0; - int use_sg = scsi_sg_count(cmd); - - cp->data_len = 0; - - use_sg = map_scsi_sg_data(np, cmd); - if (use_sg > 0) { - struct scatterlist *sg; - struct scr_tblmove *data; - - if (use_sg > MAX_SCATTER) { - unmap_scsi_data(np, cmd); - return -1; - } - - data = &cp->phys.data[MAX_SCATTER - use_sg]; - - scsi_for_each_sg(cmd, sg, use_sg, segment) { - dma_addr_t baddr = sg_dma_address(sg); - unsigned int len = sg_dma_len(sg); - - ncr_build_sge(np, &data[segment], baddr, len); - cp->data_len += len; - } - } else - segment = -2; - - return segment; -} - -/*========================================================== -** -** -** Test the bus snoop logic :-( -** -** Has to be called with interrupts disabled. -** -** -**========================================================== -*/ - -static int __init ncr_regtest (struct ncb* np) -{ - register volatile u32 data; - /* - ** ncr registers may NOT be cached. - ** write 0xffffffff to a read only register area, - ** and try to read it back. - */ - data = 0xffffffff; - OUTL_OFF(offsetof(struct ncr_reg, nc_dstat), data); - data = INL_OFF(offsetof(struct ncr_reg, nc_dstat)); -#if 1 - if (data == 0xffffffff) { -#else - if ((data & 0xe2f0fffd) != 0x02000080) { -#endif - printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", - (unsigned) data); - return (0x10); - } - return (0); -} - -static int __init ncr_snooptest (struct ncb* np) -{ - u32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; - int i, err=0; - if (np->reg) { - err |= ncr_regtest (np); - if (err) - return (err); - } - - /* init */ - pc = NCB_SCRIPTH_PHYS (np, snooptest); - host_wr = 1; - ncr_wr = 2; - /* - ** Set memory and register. - */ - np->ncr_cache = cpu_to_scr(host_wr); - OUTL (nc_temp, ncr_wr); - /* - ** Start script (exchange values) - */ - OUTL_DSP (pc); - /* - ** Wait 'til done (with timeout) - */ - for (i=0; incr_cache); - ncr_rd = INL (nc_scratcha); - ncr_bk = INL (nc_temp); - /* - ** Reset ncr chip - */ - ncr_chip_reset(np, 100); - /* - ** check for timeout - */ - if (i>=NCR_SNOOP_TIMEOUT) { - printk ("CACHE TEST FAILED: timeout.\n"); - return (0x20); - } - /* - ** Check termination position. - */ - if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) { - printk ("CACHE TEST FAILED: script execution failed.\n"); - printk ("start=%08lx, pc=%08lx, end=%08lx\n", - (u_long) NCB_SCRIPTH_PHYS (np, snooptest), (u_long) pc, - (u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8); - return (0x40); - } - /* - ** Show results. - */ - if (host_wr != ncr_rd) { - printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n", - (int) host_wr, (int) ncr_rd); - err |= 1; - } - if (host_rd != ncr_wr) { - printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n", - (int) ncr_wr, (int) host_rd); - err |= 2; - } - if (ncr_bk != ncr_wr) { - printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n", - (int) ncr_wr, (int) ncr_bk); - err |= 4; - } - return (err); -} - -/*========================================================== -** -** Determine the ncr's clock frequency. -** This is essential for the negotiation -** of the synchronous transfer rate. -** -**========================================================== -** -** Note: we have to return the correct value. -** THERE IS NO SAFE DEFAULT VALUE. -** -** Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. -** 53C860 and 53C875 rev. 1 support fast20 transfers but -** do not have a clock doubler and so are provided with a -** 80 MHz clock. All other fast20 boards incorporate a doubler -** and so should be delivered with a 40 MHz clock. -** The future fast40 chips (895/895) use a 40 Mhz base clock -** and provide a clock quadrupler (160 Mhz). The code below -** tries to deal as cleverly as possible with all this stuff. -** -**---------------------------------------------------------- -*/ - -/* - * Select NCR SCSI clock frequency - */ -static void ncr_selectclock(struct ncb *np, u_char scntl3) -{ - if (np->multiplier < 2) { - OUTB(nc_scntl3, scntl3); - return; - } - - if (bootverbose >= 2) - printk ("%s: enabling clock multiplier\n", ncr_name(np)); - - OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ - if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */ - int i = 20; - while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) - udelay(20); - if (!i) - printk("%s: the chip cannot lock the frequency\n", ncr_name(np)); - } else /* Wait 20 micro-seconds for doubler */ - udelay(20); - OUTB(nc_stest3, HSC); /* Halt the scsi clock */ - OUTB(nc_scntl3, scntl3); - OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ - OUTB(nc_stest3, 0x00); /* Restart scsi clock */ -} - - -/* - * calculate NCR SCSI clock frequency (in KHz) - */ -static unsigned __init ncrgetfreq (struct ncb *np, int gen) -{ - unsigned ms = 0; - char count = 0; - - /* - * Measure GEN timer delay in order - * to calculate SCSI clock frequency - * - * This code will never execute too - * many loop iterations (if DELAY is - * reasonably correct). It could get - * too low a delay (too high a freq.) - * if the CPU is slow executing the - * loop for some reason (an NMI, for - * example). For this reason we will - * if multiple measurements are to be - * performed trust the higher delay - * (lower frequency returned). - */ - OUTB (nc_stest1, 0); /* make sure clock doubler is OFF */ - OUTW (nc_sien , 0); /* mask all scsi interrupts */ - (void) INW (nc_sist); /* clear pending scsi interrupt */ - OUTB (nc_dien , 0); /* mask all dma interrupts */ - (void) INW (nc_sist); /* another one, just to be sure :) */ - OUTB (nc_scntl3, 4); /* set pre-scaler to divide by 3 */ - OUTB (nc_stime1, 0); /* disable general purpose timer */ - OUTB (nc_stime1, gen); /* set to nominal delay of 1<= 2) - printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms); - /* - * adjust for prescaler, and convert into KHz - */ - return ms ? ((1 << gen) * 4340) / ms : 0; -} - -/* - * Get/probe NCR SCSI clock frequency - */ -static void __init ncr_getclock (struct ncb *np, int mult) -{ - unsigned char scntl3 = INB(nc_scntl3); - unsigned char stest1 = INB(nc_stest1); - unsigned f1; - - np->multiplier = 1; - f1 = 40000; - - /* - ** True with 875 or 895 with clock multiplier selected - */ - if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { - if (bootverbose >= 2) - printk ("%s: clock multiplier found\n", ncr_name(np)); - np->multiplier = mult; - } - - /* - ** If multiplier not found or scntl3 not 7,5,3, - ** reset chip and get frequency from general purpose timer. - ** Otherwise trust scntl3 BIOS setting. - */ - if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { - unsigned f2; - - ncr_chip_reset(np, 5); - - (void) ncrgetfreq (np, 11); /* throw away first result */ - f1 = ncrgetfreq (np, 11); - f2 = ncrgetfreq (np, 11); - - if(bootverbose) - printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2); - - if (f1 > f2) f1 = f2; /* trust lower result */ - - if (f1 < 45000) f1 = 40000; - else if (f1 < 55000) f1 = 50000; - else f1 = 80000; - - if (f1 < 80000 && mult > 1) { - if (bootverbose >= 2) - printk ("%s: clock multiplier assumed\n", ncr_name(np)); - np->multiplier = mult; - } - } else { - if ((scntl3 & 7) == 3) f1 = 40000; - else if ((scntl3 & 7) == 5) f1 = 80000; - else f1 = 160000; - - f1 /= np->multiplier; - } - - /* - ** Compute controller synchronous parameters. - */ - f1 *= np->multiplier; - np->clock_khz = f1; -} - -/*===================== LINUX ENTRY POINTS SECTION ==========================*/ - -static int ncr53c8xx_slave_alloc(struct scsi_device *device) -{ - struct Scsi_Host *host = device->host; - struct ncb *np = ((struct host_data *) host->hostdata)->ncb; - struct tcb *tp = &np->target[device->id]; - tp->starget = device->sdev_target; - - return 0; -} - -static int ncr53c8xx_slave_configure(struct scsi_device *device) -{ - struct Scsi_Host *host = device->host; - struct ncb *np = ((struct host_data *) host->hostdata)->ncb; - struct tcb *tp = &np->target[device->id]; - struct lcb *lp = tp->lp[device->lun]; - int numtags, depth_to_use; - - ncr_setup_lcb(np, device); - - /* - ** Select queue depth from driver setup. - ** Donnot use more than configured by user. - ** Use at least 2. - ** Donnot use more than our maximum. - */ - numtags = device_queue_depth(np->unit, device->id, device->lun); - if (numtags > tp->usrtags) - numtags = tp->usrtags; - if (!device->tagged_supported) - numtags = 1; - depth_to_use = numtags; - if (depth_to_use < 2) - depth_to_use = 2; - if (depth_to_use > MAX_TAGS) - depth_to_use = MAX_TAGS; - - scsi_adjust_queue_depth(device, - (device->tagged_supported ? - MSG_SIMPLE_TAG : 0), - depth_to_use); - - /* - ** Since the queue depth is not tunable under Linux, - ** we need to know this value in order not to - ** announce stupid things to user. - ** - ** XXX(hch): As of Linux 2.6 it certainly _is_ tunable.. - ** In fact we just tuned it, or did I miss - ** something important? :) - */ - if (lp) { - lp->numtags = lp->maxtags = numtags; - lp->scdev_depth = depth_to_use; - } - ncr_setup_tags (np, device); - -#ifdef DEBUG_NCR53C8XX - printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", - np->unit, device->id, device->lun, depth_to_use); -#endif - - if (spi_support_sync(device->sdev_target) && - !spi_initial_dv(device->sdev_target)) - spi_dv_device(device); - return 0; -} - -static int ncr53c8xx_queue_command_lck (struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb; - unsigned long flags; - int sts; - -#ifdef DEBUG_NCR53C8XX -printk("ncr53c8xx_queue_command\n"); -#endif - - cmd->scsi_done = done; - cmd->host_scribble = NULL; - cmd->__data_mapped = 0; - cmd->__data_mapping = 0; - - spin_lock_irqsave(&np->smp_lock, flags); - - if ((sts = ncr_queue_command(np, cmd)) != DID_OK) { - cmd->result = ScsiResult(sts, 0); -#ifdef DEBUG_NCR53C8XX -printk("ncr53c8xx : command not queued - result=%d\n", sts); -#endif - } -#ifdef DEBUG_NCR53C8XX - else -printk("ncr53c8xx : command successfully queued\n"); -#endif - - spin_unlock_irqrestore(&np->smp_lock, flags); - - if (sts != DID_OK) { - unmap_scsi_data(np, cmd); - done(cmd); - sts = 0; - } - - return sts; -} - -static DEF_SCSI_QCMD(ncr53c8xx_queue_command) - -irqreturn_t ncr53c8xx_intr(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *shost = (struct Scsi_Host *)dev_id; - struct host_data *host_data = (struct host_data *)shost->hostdata; - struct ncb *np = host_data->ncb; - struct scsi_cmnd *done_list; - -#ifdef DEBUG_NCR53C8XX - printk("ncr53c8xx : interrupt received\n"); -#endif - - if (DEBUG_FLAGS & DEBUG_TINY) printk ("["); - - spin_lock_irqsave(&np->smp_lock, flags); - ncr_exception(np); - done_list = np->done_list; - np->done_list = NULL; - spin_unlock_irqrestore(&np->smp_lock, flags); - - if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n"); - - if (done_list) - ncr_flush_done_cmds(done_list); - return IRQ_HANDLED; -} - -static void ncr53c8xx_timeout(unsigned long npref) -{ - struct ncb *np = (struct ncb *) npref; - unsigned long flags; - struct scsi_cmnd *done_list; - - spin_lock_irqsave(&np->smp_lock, flags); - ncr_timeout(np); - done_list = np->done_list; - np->done_list = NULL; - spin_unlock_irqrestore(&np->smp_lock, flags); - - if (done_list) - ncr_flush_done_cmds(done_list); -} - -static int ncr53c8xx_bus_reset(struct scsi_cmnd *cmd) -{ - struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb; - int sts; - unsigned long flags; - struct scsi_cmnd *done_list; - - /* - * If the mid-level driver told us reset is synchronous, it seems - * that we must call the done() callback for the involved command, - * even if this command was not queued to the low-level driver, - * before returning SUCCESS. - */ - - spin_lock_irqsave(&np->smp_lock, flags); - sts = ncr_reset_bus(np, cmd, 1); - - done_list = np->done_list; - np->done_list = NULL; - spin_unlock_irqrestore(&np->smp_lock, flags); - - ncr_flush_done_cmds(done_list); - - return sts; -} - -#if 0 /* unused and broken */ -static int ncr53c8xx_abort(struct scsi_cmnd *cmd) -{ - struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb; - int sts; - unsigned long flags; - struct scsi_cmnd *done_list; - - printk("ncr53c8xx_abort\n"); - - NCR_LOCK_NCB(np, flags); - - sts = ncr_abort_command(np, cmd); -out: - done_list = np->done_list; - np->done_list = NULL; - NCR_UNLOCK_NCB(np, flags); - - ncr_flush_done_cmds(done_list); - - return sts; -} -#endif - - -/* -** Scsi command waiting list management. -** -** It may happen that we cannot insert a scsi command into the start queue, -** in the following circumstances. -** Too few preallocated ccb(s), -** maxtags < cmd_per_lun of the Linux host control block, -** etc... -** Such scsi commands are inserted into a waiting list. -** When a scsi command complete, we try to requeue the commands of the -** waiting list. -*/ - -#define next_wcmd host_scribble - -static void insert_into_waiting_list(struct ncb *np, struct scsi_cmnd *cmd) -{ - struct scsi_cmnd *wcmd; - -#ifdef DEBUG_WAITING_LIST - printk("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd); -#endif - cmd->next_wcmd = NULL; - if (!(wcmd = np->waiting_list)) np->waiting_list = cmd; - else { - while (wcmd->next_wcmd) - wcmd = (struct scsi_cmnd *) wcmd->next_wcmd; - wcmd->next_wcmd = (char *) cmd; - } -} - -static struct scsi_cmnd *retrieve_from_waiting_list(int to_remove, struct ncb *np, struct scsi_cmnd *cmd) -{ - struct scsi_cmnd **pcmd = &np->waiting_list; - - while (*pcmd) { - if (cmd == *pcmd) { - if (to_remove) { - *pcmd = (struct scsi_cmnd *) cmd->next_wcmd; - cmd->next_wcmd = NULL; - } -#ifdef DEBUG_WAITING_LIST - printk("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd); -#endif - return cmd; - } - pcmd = (struct scsi_cmnd **) &(*pcmd)->next_wcmd; - } - return NULL; -} - -static void process_waiting_list(struct ncb *np, int sts) -{ - struct scsi_cmnd *waiting_list, *wcmd; - - waiting_list = np->waiting_list; - np->waiting_list = NULL; - -#ifdef DEBUG_WAITING_LIST - if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); -#endif - while ((wcmd = waiting_list) != NULL) { - waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd; - wcmd->next_wcmd = NULL; - if (sts == DID_OK) { -#ifdef DEBUG_WAITING_LIST - printk("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd); -#endif - sts = ncr_queue_command(np, wcmd); - } - if (sts != DID_OK) { -#ifdef DEBUG_WAITING_LIST - printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts); -#endif - wcmd->result = ScsiResult(sts, 0); - ncr_queue_done_cmd(np, wcmd); - } - } -} - -#undef next_wcmd - -static ssize_t show_ncr53c8xx_revision(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *host = class_to_shost(dev); - struct host_data *host_data = (struct host_data *)host->hostdata; - - return snprintf(buf, 20, "0x%x\n", host_data->ncb->revision_id); -} - -static struct device_attribute ncr53c8xx_revision_attr = { - .attr = { .name = "revision", .mode = S_IRUGO, }, - .show = show_ncr53c8xx_revision, -}; - -static struct device_attribute *ncr53c8xx_host_attrs[] = { - &ncr53c8xx_revision_attr, - NULL -}; - -/*========================================================== -** -** Boot command line. -** -**========================================================== -*/ -#ifdef MODULE -char *ncr53c8xx; /* command line passed by insmod */ -module_param(ncr53c8xx, charp, 0); -#endif - -#ifndef MODULE -static int __init ncr53c8xx_setup(char *str) -{ - return sym53c8xx__setup(str); -} - -__setup("ncr53c8xx=", ncr53c8xx_setup); -#endif - - -/* - * Host attach and initialisations. - * - * Allocate host data and ncb structure. - * Request IO region and remap MMIO region. - * Do chip initialization. - * If all is OK, install interrupt handling and - * start the timer daemon. - */ -struct Scsi_Host * __init ncr_attach(struct scsi_host_template *tpnt, - int unit, struct ncr_device *device) -{ - struct host_data *host_data; - struct ncb *np = NULL; - struct Scsi_Host *instance = NULL; - u_long flags = 0; - int i; - - if (!tpnt->name) - tpnt->name = SCSI_NCR_DRIVER_NAME; - if (!tpnt->shost_attrs) - tpnt->shost_attrs = ncr53c8xx_host_attrs; - - tpnt->queuecommand = ncr53c8xx_queue_command; - tpnt->slave_configure = ncr53c8xx_slave_configure; - tpnt->slave_alloc = ncr53c8xx_slave_alloc; - tpnt->eh_bus_reset_handler = ncr53c8xx_bus_reset; - tpnt->can_queue = SCSI_NCR_CAN_QUEUE; - tpnt->this_id = 7; - tpnt->sg_tablesize = SCSI_NCR_SG_TABLESIZE; - tpnt->cmd_per_lun = SCSI_NCR_CMD_PER_LUN; - tpnt->use_clustering = ENABLE_CLUSTERING; - - if (device->differential) - driver_setup.diff_support = device->differential; - - printk(KERN_INFO "ncr53c720-%d: rev 0x%x irq %d\n", - unit, device->chip.revision_id, device->slot.irq); - - instance = scsi_host_alloc(tpnt, sizeof(*host_data)); - if (!instance) - goto attach_error; - host_data = (struct host_data *) instance->hostdata; - - np = __m_calloc_dma(device->dev, sizeof(struct ncb), "NCB"); - if (!np) - goto attach_error; - spin_lock_init(&np->smp_lock); - np->dev = device->dev; - np->p_ncb = vtobus(np); - host_data->ncb = np; - - np->ccb = m_calloc_dma(sizeof(struct ccb), "CCB"); - if (!np->ccb) - goto attach_error; - - /* Store input information in the host data structure. */ - np->unit = unit; - np->verbose = driver_setup.verbose; - sprintf(np->inst_name, "ncr53c720-%d", np->unit); - np->revision_id = device->chip.revision_id; - np->features = device->chip.features; - np->clock_divn = device->chip.nr_divisor; - np->maxoffs = device->chip.offset_max; - np->maxburst = device->chip.burst_max; - np->myaddr = device->host_id; - - /* Allocate SCRIPTS areas. */ - np->script0 = m_calloc_dma(sizeof(struct script), "SCRIPT"); - if (!np->script0) - goto attach_error; - np->scripth0 = m_calloc_dma(sizeof(struct scripth), "SCRIPTH"); - if (!np->scripth0) - goto attach_error; - - init_timer(&np->timer); - np->timer.data = (unsigned long) np; - np->timer.function = ncr53c8xx_timeout; - - /* Try to map the controller chip to virtual and physical memory. */ - - np->paddr = device->slot.base; - np->paddr2 = (np->features & FE_RAM) ? device->slot.base_2 : 0; - - if (device->slot.base_v) - np->vaddr = device->slot.base_v; - else - np->vaddr = ioremap(device->slot.base_c, 128); - - if (!np->vaddr) { - printk(KERN_ERR - "%s: can't map memory mapped IO region\n",ncr_name(np)); - goto attach_error; - } else { - if (bootverbose > 1) - printk(KERN_INFO - "%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr); - } - - /* Make the controller's registers available. Now the INB INW INL - * OUTB OUTW OUTL macros can be used safely. - */ - - np->reg = (struct ncr_reg __iomem *)np->vaddr; - - /* Do chip dependent initialization. */ - ncr_prepare_setting(np); - - if (np->paddr2 && sizeof(struct script) > 4096) { - np->paddr2 = 0; - printk(KERN_WARNING "%s: script too large, NOT using on chip RAM.\n", - ncr_name(np)); - } - - instance->max_channel = 0; - instance->this_id = np->myaddr; - instance->max_id = np->maxwide ? 16 : 8; - instance->max_lun = SCSI_NCR_MAX_LUN; - instance->base = (unsigned long) np->reg; - instance->irq = device->slot.irq; - instance->unique_id = device->slot.base; - instance->dma_channel = 0; - instance->cmd_per_lun = MAX_TAGS; - instance->can_queue = (MAX_START-4); - /* This can happen if you forget to call ncr53c8xx_init from - * your module_init */ - BUG_ON(!ncr53c8xx_transport_template); - instance->transportt = ncr53c8xx_transport_template; - - /* Patch script to physical addresses */ - ncr_script_fill(&script0, &scripth0); - - np->scripth = np->scripth0; - np->p_scripth = vtobus(np->scripth); - np->p_script = (np->paddr2) ? np->paddr2 : vtobus(np->script0); - - ncr_script_copy_and_bind(np, (ncrcmd *) &script0, - (ncrcmd *) np->script0, sizeof(struct script)); - ncr_script_copy_and_bind(np, (ncrcmd *) &scripth0, - (ncrcmd *) np->scripth0, sizeof(struct scripth)); - np->ccb->p_ccb = vtobus (np->ccb); - - /* Patch the script for LED support. */ - - if (np->features & FE_LED0) { - np->script0->idle[0] = - cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR, 0x01)); - np->script0->reselected[0] = - cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); - np->script0->start[0] = - cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); - } - - /* - * Look for the target control block of this nexus. - * For i = 0 to 3 - * JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb) - */ - for (i = 0 ; i < 4 ; i++) { - np->jump_tcb[i].l_cmd = - cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3)))); - np->jump_tcb[i].l_paddr = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_target)); - } - - ncr_chip_reset(np, 100); - - /* Now check the cache handling of the chipset. */ - - if (ncr_snooptest(np)) { - printk(KERN_ERR "CACHE INCORRECTLY CONFIGURED.\n"); - goto attach_error; - } - - /* Install the interrupt handler. */ - np->irq = device->slot.irq; - - /* Initialize the fixed part of the default ccb. */ - ncr_init_ccb(np, np->ccb); - - /* - * After SCSI devices have been opened, we cannot reset the bus - * safely, so we do it here. Interrupt handler does the real work. - * Process the reset exception if interrupts are not enabled yet. - * Then enable disconnects. - */ - spin_lock_irqsave(&np->smp_lock, flags); - if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) { - printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np)); - - spin_unlock_irqrestore(&np->smp_lock, flags); - goto attach_error; - } - ncr_exception(np); - - np->disc = 1; - - /* - * The middle-level SCSI driver does not wait for devices to settle. - * Wait synchronously if more than 2 seconds. - */ - if (driver_setup.settle_delay > 2) { - printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...\n", - ncr_name(np), driver_setup.settle_delay); - mdelay(1000 * driver_setup.settle_delay); - } - - /* start the timeout daemon */ - np->lasttime=0; - ncr_timeout (np); - - /* use SIMPLE TAG messages by default */ -#ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG - np->order = SIMPLE_QUEUE_TAG; -#endif - - spin_unlock_irqrestore(&np->smp_lock, flags); - - return instance; - - attach_error: - if (!instance) - return NULL; - printk(KERN_INFO "%s: detaching...\n", ncr_name(np)); - if (!np) - goto unregister; - if (np->scripth0) - m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH"); - if (np->script0) - m_free_dma(np->script0, sizeof(struct script), "SCRIPT"); - if (np->ccb) - m_free_dma(np->ccb, sizeof(struct ccb), "CCB"); - m_free_dma(np, sizeof(struct ncb), "NCB"); - host_data->ncb = NULL; - - unregister: - scsi_host_put(instance); - - return NULL; -} - - -void ncr53c8xx_release(struct Scsi_Host *host) -{ - struct host_data *host_data = shost_priv(host); -#ifdef DEBUG_NCR53C8XX - printk("ncr53c8xx: release\n"); -#endif - if (host_data->ncb) - ncr_detach(host_data->ncb); - scsi_host_put(host); -} - -static void ncr53c8xx_set_period(struct scsi_target *starget, int period) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ncb *np = ((struct host_data *)shost->hostdata)->ncb; - struct tcb *tp = &np->target[starget->id]; - - if (period > np->maxsync) - period = np->maxsync; - else if (period < np->minsync) - period = np->minsync; - - tp->usrsync = period; - - ncr_negotiate(np, tp); -} - -static void ncr53c8xx_set_offset(struct scsi_target *starget, int offset) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ncb *np = ((struct host_data *)shost->hostdata)->ncb; - struct tcb *tp = &np->target[starget->id]; - - if (offset > np->maxoffs) - offset = np->maxoffs; - else if (offset < 0) - offset = 0; - - tp->maxoffs = offset; - - ncr_negotiate(np, tp); -} - -static void ncr53c8xx_set_width(struct scsi_target *starget, int width) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct ncb *np = ((struct host_data *)shost->hostdata)->ncb; - struct tcb *tp = &np->target[starget->id]; - - if (width > np->maxwide) - width = np->maxwide; - else if (width < 0) - width = 0; - - tp->usrwide = width; - - ncr_negotiate(np, tp); -} - -static void ncr53c8xx_get_signalling(struct Scsi_Host *shost) -{ - struct ncb *np = ((struct host_data *)shost->hostdata)->ncb; - enum spi_signal_type type; - - switch (np->scsi_mode) { - case SMODE_SE: - type = SPI_SIGNAL_SE; - break; - case SMODE_HVD: - type = SPI_SIGNAL_HVD; - break; - default: - type = SPI_SIGNAL_UNKNOWN; - break; - } - spi_signalling(shost) = type; -} - -static struct spi_function_template ncr53c8xx_transport_functions = { - .set_period = ncr53c8xx_set_period, - .show_period = 1, - .set_offset = ncr53c8xx_set_offset, - .show_offset = 1, - .set_width = ncr53c8xx_set_width, - .show_width = 1, - .get_signalling = ncr53c8xx_get_signalling, -}; - -int __init ncr53c8xx_init(void) -{ - ncr53c8xx_transport_template = spi_attach_transport(&ncr53c8xx_transport_functions); - if (!ncr53c8xx_transport_template) - return -ENODEV; - return 0; -} - -void ncr53c8xx_exit(void) -{ - spi_release_transport(ncr53c8xx_transport_template); -} diff --git a/ANDROID_3.4.5/drivers/scsi/ncr53c8xx.h b/ANDROID_3.4.5/drivers/scsi/ncr53c8xx.h deleted file mode 100644 index 0e008dac..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ncr53c8xx.h +++ /dev/null @@ -1,1329 +0,0 @@ -/****************************************************************************** -** Device driver for the PCI-SCSI NCR538XX controller family. -** -** Copyright (C) 1994 Wolfgang Stanglmeier -** Copyright (C) 1998-2001 Gerard Roudier -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -** -** This driver has been ported to Linux from the FreeBSD NCR53C8XX driver -** and is currently maintained by -** -** Gerard Roudier -** -** Being given that this driver originates from the FreeBSD version, and -** in order to keep synergy on both, any suggested enhancements and corrections -** received on Linux are automatically a potential candidate for the FreeBSD -** version. -** -** The original driver has been written for 386bsd and FreeBSD by -** Wolfgang Stanglmeier -** Stefan Esser -** -** And has been ported to NetBSD by -** Charles M. Hannum -** -** NVRAM detection and reading. -** Copyright (C) 1997 Richard Waltham -** -** Added support for MIPS big endian systems. -** Carsten Langgaard, carstenl@mips.com -** Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. -** -** Added support for HP PARISC big endian systems. -** Copyright (C) 2000 MIPS Technologies, Inc. All rights reserved. -** -******************************************************************************* -*/ - -#ifndef NCR53C8XX_H -#define NCR53C8XX_H - -#include - - -/* -** If you want a driver as small as possible, donnot define the -** following options. -*/ -#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT -#define SCSI_NCR_DEBUG_INFO_SUPPORT - -/* -** To disable integrity checking, do not define the -** following option. -*/ -#ifdef CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK -# define SCSI_NCR_ENABLE_INTEGRITY_CHECK -#endif - -/* --------------------------------------------------------------------- -** Take into account kernel configured parameters. -** Most of these options can be overridden at startup by a command line. -** --------------------------------------------------------------------- -*/ - -/* - * For Ultra2 and Ultra3 SCSI support option, use special features. - * - * Value (default) means: - * bit 0 : all features enabled, except: - * bit 1 : PCI Write And Invalidate. - * bit 2 : Data Phase Mismatch handling from SCRIPTS. - * - * Use boot options ncr53c8xx=specf:1 if you want all chip features to be - * enabled by the driver. - */ -#define SCSI_NCR_SETUP_SPECIAL_FEATURES (3) - -#define SCSI_NCR_MAX_SYNC (80) - -/* - * Allow tags from 2 to 256, default 8 - */ -#ifdef CONFIG_SCSI_NCR53C8XX_MAX_TAGS -#if CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2 -#define SCSI_NCR_MAX_TAGS (2) -#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 256 -#define SCSI_NCR_MAX_TAGS (256) -#else -#define SCSI_NCR_MAX_TAGS CONFIG_SCSI_NCR53C8XX_MAX_TAGS -#endif -#else -#define SCSI_NCR_MAX_TAGS (8) -#endif - -/* - * Allow tagged command queuing support if configured with default number - * of tags set to max (see above). - */ -#ifdef CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS -#define SCSI_NCR_SETUP_DEFAULT_TAGS CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS -#elif defined CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE -#define SCSI_NCR_SETUP_DEFAULT_TAGS SCSI_NCR_MAX_TAGS -#else -#define SCSI_NCR_SETUP_DEFAULT_TAGS (0) -#endif - -/* - * Immediate arbitration - */ -#if defined(CONFIG_SCSI_NCR53C8XX_IARB) -#define SCSI_NCR_IARB_SUPPORT -#endif - -/* - * Sync transfer frequency at startup. - * Allow from 5Mhz to 80Mhz default 20 Mhz. - */ -#ifndef CONFIG_SCSI_NCR53C8XX_SYNC -#define CONFIG_SCSI_NCR53C8XX_SYNC (20) -#elif CONFIG_SCSI_NCR53C8XX_SYNC > SCSI_NCR_MAX_SYNC -#undef CONFIG_SCSI_NCR53C8XX_SYNC -#define CONFIG_SCSI_NCR53C8XX_SYNC SCSI_NCR_MAX_SYNC -#endif - -#if CONFIG_SCSI_NCR53C8XX_SYNC == 0 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (255) -#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 5 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (50) -#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 20 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (250/(CONFIG_SCSI_NCR53C8XX_SYNC)) -#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 33 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (11) -#elif CONFIG_SCSI_NCR53C8XX_SYNC <= 40 -#define SCSI_NCR_SETUP_DEFAULT_SYNC (10) -#else -#define SCSI_NCR_SETUP_DEFAULT_SYNC (9) -#endif - -/* - * Disallow disconnections at boot-up - */ -#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT -#define SCSI_NCR_SETUP_DISCONNECTION (0) -#else -#define SCSI_NCR_SETUP_DISCONNECTION (1) -#endif - -/* - * Force synchronous negotiation for all targets - */ -#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO -#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO (1) -#else -#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO (0) -#endif - -/* - * Disable master parity checking (flawed hardwares need that) - */ -#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK -#define SCSI_NCR_SETUP_MASTER_PARITY (0) -#else -#define SCSI_NCR_SETUP_MASTER_PARITY (1) -#endif - -/* - * Disable scsi parity checking (flawed devices may need that) - */ -#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK -#define SCSI_NCR_SETUP_SCSI_PARITY (0) -#else -#define SCSI_NCR_SETUP_SCSI_PARITY (1) -#endif - -/* - * Settle time after reset at boot-up - */ -#define SCSI_NCR_SETUP_SETTLE_TIME (2) - -/* -** Bridge quirks work-around option defaulted to 1. -*/ -#ifndef SCSI_NCR_PCIQ_WORK_AROUND_OPT -#define SCSI_NCR_PCIQ_WORK_AROUND_OPT 1 -#endif - -/* -** Work-around common bridge misbehaviour. -** -** - Do not flush posted writes in the opposite -** direction on read. -** - May reorder DMA writes to memory. -** -** This option should not affect performances -** significantly, so it is the default. -*/ -#if SCSI_NCR_PCIQ_WORK_AROUND_OPT == 1 -#define SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM -#define SCSI_NCR_PCIQ_MAY_REORDER_WRITES -#define SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS - -/* -** Same as option 1, but also deal with -** misconfigured interrupts. -** -** - Edge triggered instead of level sensitive. -** - No interrupt line connected. -** - IRQ number misconfigured. -** -** If no interrupt is delivered, the driver will -** catch the interrupt conditions 10 times per -** second. No need to say that this option is -** not recommended. -*/ -#elif SCSI_NCR_PCIQ_WORK_AROUND_OPT == 2 -#define SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM -#define SCSI_NCR_PCIQ_MAY_REORDER_WRITES -#define SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS -#define SCSI_NCR_PCIQ_BROKEN_INTR - -/* -** Some bridge designers decided to flush -** everything prior to deliver the interrupt. -** This option tries to deal with such a -** behaviour. -*/ -#elif SCSI_NCR_PCIQ_WORK_AROUND_OPT == 3 -#define SCSI_NCR_PCIQ_SYNC_ON_INTR -#endif - -/* -** Other parameters not configurable with "make config" -** Avoid to change these constants, unless you know what you are doing. -*/ - -#define SCSI_NCR_ALWAYS_SIMPLE_TAG -#define SCSI_NCR_MAX_SCATTER (127) -#define SCSI_NCR_MAX_TARGET (16) - -/* -** Compute some desirable value for CAN_QUEUE -** and CMD_PER_LUN. -** The driver will use lower values if these -** ones appear to be too large. -*/ -#define SCSI_NCR_CAN_QUEUE (8*SCSI_NCR_MAX_TAGS + 2*SCSI_NCR_MAX_TARGET) -#define SCSI_NCR_CMD_PER_LUN (SCSI_NCR_MAX_TAGS) - -#define SCSI_NCR_SG_TABLESIZE (SCSI_NCR_MAX_SCATTER) -#define SCSI_NCR_TIMER_INTERVAL (HZ) - -#if 1 /* defined CONFIG_SCSI_MULTI_LUN */ -#define SCSI_NCR_MAX_LUN (16) -#else -#define SCSI_NCR_MAX_LUN (1) -#endif - -/* - * IO functions definition for big/little endian CPU support. - * For now, the NCR is only supported in little endian addressing mode, - */ - -#ifdef __BIG_ENDIAN - -#define inw_l2b inw -#define inl_l2b inl -#define outw_b2l outw -#define outl_b2l outl - -#define readb_raw readb -#define writeb_raw writeb - -#if defined(SCSI_NCR_BIG_ENDIAN) -#define readw_l2b __raw_readw -#define readl_l2b __raw_readl -#define writew_b2l __raw_writew -#define writel_b2l __raw_writel -#define readw_raw __raw_readw -#define readl_raw __raw_readl -#define writew_raw __raw_writew -#define writel_raw __raw_writel -#else /* Other big-endian */ -#define readw_l2b readw -#define readl_l2b readl -#define writew_b2l writew -#define writel_b2l writel -#define readw_raw readw -#define readl_raw readl -#define writew_raw writew -#define writel_raw writel -#endif - -#else /* little endian */ - -#define inw_raw inw -#define inl_raw inl -#define outw_raw outw -#define outl_raw outl - -#define readb_raw readb -#define readw_raw readw -#define readl_raw readl -#define writeb_raw writeb -#define writew_raw writew -#define writel_raw writel - -#endif - -#if !defined(__hppa__) && !defined(__mips__) -#ifdef SCSI_NCR_BIG_ENDIAN -#error "The NCR in BIG ENDIAN addressing mode is not (yet) supported" -#endif -#endif - -#define MEMORY_BARRIER() mb() - - -/* - * If the NCR uses big endian addressing mode over the - * PCI, actual io register addresses for byte and word - * accesses must be changed according to lane routing. - * Btw, ncr_offb() and ncr_offw() macros only apply to - * constants and so donnot generate bloated code. - */ - -#if defined(SCSI_NCR_BIG_ENDIAN) - -#define ncr_offb(o) (((o)&~3)+((~((o)&3))&3)) -#define ncr_offw(o) (((o)&~3)+((~((o)&3))&2)) - -#else - -#define ncr_offb(o) (o) -#define ncr_offw(o) (o) - -#endif - -/* - * If the CPU and the NCR use same endian-ness addressing, - * no byte reordering is needed for script patching. - * Macro cpu_to_scr() is to be used for script patching. - * Macro scr_to_cpu() is to be used for getting a DWORD - * from the script. - */ - -#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) - -#define cpu_to_scr(dw) cpu_to_le32(dw) -#define scr_to_cpu(dw) le32_to_cpu(dw) - -#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) - -#define cpu_to_scr(dw) cpu_to_be32(dw) -#define scr_to_cpu(dw) be32_to_cpu(dw) - -#else - -#define cpu_to_scr(dw) (dw) -#define scr_to_cpu(dw) (dw) - -#endif - -/* - * Access to the controller chip. - * - * If the CPU and the NCR use same endian-ness addressing, - * no byte reordering is needed for accessing chip io - * registers. Functions suffixed by '_raw' are assumed - * to access the chip over the PCI without doing byte - * reordering. Functions suffixed by '_l2b' are - * assumed to perform little-endian to big-endian byte - * reordering, those suffixed by '_b2l' blah, blah, - * blah, ... - */ - -/* - * MEMORY mapped IO input / output - */ - -#define INB_OFF(o) readb_raw((char __iomem *)np->reg + ncr_offb(o)) -#define OUTB_OFF(o, val) writeb_raw((val), (char __iomem *)np->reg + ncr_offb(o)) - -#if defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) readw_l2b((char __iomem *)np->reg + ncr_offw(o)) -#define INL_OFF(o) readl_l2b((char __iomem *)np->reg + (o)) - -#define OUTW_OFF(o, val) writew_b2l((val), (char __iomem *)np->reg + ncr_offw(o)) -#define OUTL_OFF(o, val) writel_b2l((val), (char __iomem *)np->reg + (o)) - -#elif defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN) - -#define INW_OFF(o) readw_b2l((char __iomem *)np->reg + ncr_offw(o)) -#define INL_OFF(o) readl_b2l((char __iomem *)np->reg + (o)) - -#define OUTW_OFF(o, val) writew_l2b((val), (char __iomem *)np->reg + ncr_offw(o)) -#define OUTL_OFF(o, val) writel_l2b((val), (char __iomem *)np->reg + (o)) - -#else - -#ifdef CONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS -/* Only 8 or 32 bit transfers allowed */ -#define INW_OFF(o) (readb((char __iomem *)np->reg + ncr_offw(o)) << 8 | readb((char __iomem *)np->reg + ncr_offw(o) + 1)) -#else -#define INW_OFF(o) readw_raw((char __iomem *)np->reg + ncr_offw(o)) -#endif -#define INL_OFF(o) readl_raw((char __iomem *)np->reg + (o)) - -#ifdef CONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS -/* Only 8 or 32 bit transfers allowed */ -#define OUTW_OFF(o, val) do { writeb((char)((val) >> 8), (char __iomem *)np->reg + ncr_offw(o)); writeb((char)(val), (char __iomem *)np->reg + ncr_offw(o) + 1); } while (0) -#else -#define OUTW_OFF(o, val) writew_raw((val), (char __iomem *)np->reg + ncr_offw(o)) -#endif -#define OUTL_OFF(o, val) writel_raw((val), (char __iomem *)np->reg + (o)) - -#endif - -#define INB(r) INB_OFF (offsetof(struct ncr_reg,r)) -#define INW(r) INW_OFF (offsetof(struct ncr_reg,r)) -#define INL(r) INL_OFF (offsetof(struct ncr_reg,r)) - -#define OUTB(r, val) OUTB_OFF (offsetof(struct ncr_reg,r), (val)) -#define OUTW(r, val) OUTW_OFF (offsetof(struct ncr_reg,r), (val)) -#define OUTL(r, val) OUTL_OFF (offsetof(struct ncr_reg,r), (val)) - -/* - * Set bit field ON, OFF - */ - -#define OUTONB(r, m) OUTB(r, INB(r) | (m)) -#define OUTOFFB(r, m) OUTB(r, INB(r) & ~(m)) -#define OUTONW(r, m) OUTW(r, INW(r) | (m)) -#define OUTOFFW(r, m) OUTW(r, INW(r) & ~(m)) -#define OUTONL(r, m) OUTL(r, INL(r) | (m)) -#define OUTOFFL(r, m) OUTL(r, INL(r) & ~(m)) - -/* - * We normally want the chip to have a consistent view - * of driver internal data structures when we restart it. - * Thus these macros. - */ -#define OUTL_DSP(v) \ - do { \ - MEMORY_BARRIER(); \ - OUTL (nc_dsp, (v)); \ - } while (0) - -#define OUTONB_STD() \ - do { \ - MEMORY_BARRIER(); \ - OUTONB (nc_dcntl, (STD|NOCOM)); \ - } while (0) - - -/* -** NCR53C8XX devices features table. -*/ -struct ncr_chip { - unsigned short revision_id; - unsigned char burst_max; /* log-base-2 of max burst */ - unsigned char offset_max; - unsigned char nr_divisor; - unsigned int features; -#define FE_LED0 (1<<0) -#define FE_WIDE (1<<1) /* Wide data transfers */ -#define FE_ULTRA (1<<2) /* Ultra speed 20Mtrans/sec */ -#define FE_DBLR (1<<4) /* Clock doubler present */ -#define FE_QUAD (1<<5) /* Clock quadrupler present */ -#define FE_ERL (1<<6) /* Enable read line */ -#define FE_CLSE (1<<7) /* Cache line size enable */ -#define FE_WRIE (1<<8) /* Write & Invalidate enable */ -#define FE_ERMP (1<<9) /* Enable read multiple */ -#define FE_BOF (1<<10) /* Burst opcode fetch */ -#define FE_DFS (1<<11) /* DMA fifo size */ -#define FE_PFEN (1<<12) /* Prefetch enable */ -#define FE_LDSTR (1<<13) /* Load/Store supported */ -#define FE_RAM (1<<14) /* On chip RAM present */ -#define FE_VARCLK (1<<15) /* SCSI clock may vary */ -#define FE_RAM8K (1<<16) /* On chip RAM sized 8Kb */ -#define FE_64BIT (1<<17) /* Have a 64-bit PCI interface */ -#define FE_IO256 (1<<18) /* Requires full 256 bytes in PCI space */ -#define FE_NOPM (1<<19) /* Scripts handles phase mismatch */ -#define FE_LEDC (1<<20) /* Hardware control of LED */ -#define FE_DIFF (1<<21) /* Support Differential SCSI */ -#define FE_66MHZ (1<<23) /* 66MHz PCI Support */ -#define FE_DAC (1<<24) /* Support DAC cycles (64 bit addressing) */ -#define FE_ISTAT1 (1<<25) /* Have ISTAT1, MBOX0, MBOX1 registers */ -#define FE_DAC_IN_USE (1<<26) /* Platform does DAC cycles */ -#define FE_EHP (1<<27) /* 720: Even host parity */ -#define FE_MUX (1<<28) /* 720: Multiplexed bus */ -#define FE_EA (1<<29) /* 720: Enable Ack */ - -#define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) -#define FE_SCSI_SET (FE_WIDE|FE_ULTRA|FE_DBLR|FE_QUAD|F_CLK80) -#define FE_SPECIAL_SET (FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM) -}; - - -/* -** Driver setup structure. -** -** This structure is initialized from linux config options. -** It can be overridden at boot-up by the boot command line. -*/ -#define SCSI_NCR_MAX_EXCLUDES 8 -struct ncr_driver_setup { - u8 master_parity; - u8 scsi_parity; - u8 disconnection; - u8 special_features; - u8 force_sync_nego; - u8 reverse_probe; - u8 pci_fix_up; - u8 use_nvram; - u8 verbose; - u8 default_tags; - u16 default_sync; - u16 debug; - u8 burst_max; - u8 led_pin; - u8 max_wide; - u8 settle_delay; - u8 diff_support; - u8 irqm; - u8 bus_check; - u8 optimize; - u8 recovery; - u8 host_id; - u16 iarb; - u32 excludes[SCSI_NCR_MAX_EXCLUDES]; - char tag_ctrl[100]; -}; - -/* -** Initial setup. -** Can be overridden at startup by a command line. -*/ -#define SCSI_NCR_DRIVER_SETUP \ -{ \ - SCSI_NCR_SETUP_MASTER_PARITY, \ - SCSI_NCR_SETUP_SCSI_PARITY, \ - SCSI_NCR_SETUP_DISCONNECTION, \ - SCSI_NCR_SETUP_SPECIAL_FEATURES, \ - SCSI_NCR_SETUP_FORCE_SYNC_NEGO, \ - 0, \ - 0, \ - 1, \ - 0, \ - SCSI_NCR_SETUP_DEFAULT_TAGS, \ - SCSI_NCR_SETUP_DEFAULT_SYNC, \ - 0x00, \ - 7, \ - 0, \ - 1, \ - SCSI_NCR_SETUP_SETTLE_TIME, \ - 0, \ - 0, \ - 1, \ - 0, \ - 0, \ - 255, \ - 0x00 \ -} - -/* -** Boot fail safe setup. -** Override initial setup from boot command line: -** ncr53c8xx=safe:y -*/ -#define SCSI_NCR_DRIVER_SAFE_SETUP \ -{ \ - 0, \ - 1, \ - 0, \ - 0, \ - 0, \ - 0, \ - 0, \ - 1, \ - 2, \ - 0, \ - 255, \ - 0x00, \ - 255, \ - 0, \ - 0, \ - 10, \ - 1, \ - 1, \ - 1, \ - 0, \ - 0, \ - 255 \ -} - -/**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/ - -/*----------------------------------------------------------------- -** -** The ncr 53c810 register structure. -** -**----------------------------------------------------------------- -*/ - -struct ncr_reg { -/*00*/ u8 nc_scntl0; /* full arb., ena parity, par->ATN */ - -/*01*/ u8 nc_scntl1; /* no reset */ - #define ISCON 0x10 /* connected to scsi */ - #define CRST 0x08 /* force reset */ - #define IARB 0x02 /* immediate arbitration */ - -/*02*/ u8 nc_scntl2; /* no disconnect expected */ - #define SDU 0x80 /* cmd: disconnect will raise error */ - #define CHM 0x40 /* sta: chained mode */ - #define WSS 0x08 /* sta: wide scsi send [W]*/ - #define WSR 0x01 /* sta: wide scsi received [W]*/ - -/*03*/ u8 nc_scntl3; /* cnf system clock dependent */ - #define EWS 0x08 /* cmd: enable wide scsi [W]*/ - #define ULTRA 0x80 /* cmd: ULTRA enable */ - /* bits 0-2, 7 rsvd for C1010 */ - -/*04*/ u8 nc_scid; /* cnf host adapter scsi address */ - #define RRE 0x40 /* r/w:e enable response to resel. */ - #define SRE 0x20 /* r/w:e enable response to select */ - -/*05*/ u8 nc_sxfer; /* ### Sync speed and count */ - /* bits 6-7 rsvd for C1010 */ - -/*06*/ u8 nc_sdid; /* ### Destination-ID */ - -/*07*/ u8 nc_gpreg; /* ??? IO-Pins */ - -/*08*/ u8 nc_sfbr; /* ### First byte in phase */ - -/*09*/ u8 nc_socl; - #define CREQ 0x80 /* r/w: SCSI-REQ */ - #define CACK 0x40 /* r/w: SCSI-ACK */ - #define CBSY 0x20 /* r/w: SCSI-BSY */ - #define CSEL 0x10 /* r/w: SCSI-SEL */ - #define CATN 0x08 /* r/w: SCSI-ATN */ - #define CMSG 0x04 /* r/w: SCSI-MSG */ - #define CC_D 0x02 /* r/w: SCSI-C_D */ - #define CI_O 0x01 /* r/w: SCSI-I_O */ - -/*0a*/ u8 nc_ssid; - -/*0b*/ u8 nc_sbcl; - -/*0c*/ u8 nc_dstat; - #define DFE 0x80 /* sta: dma fifo empty */ - #define MDPE 0x40 /* int: master data parity error */ - #define BF 0x20 /* int: script: bus fault */ - #define ABRT 0x10 /* int: script: command aborted */ - #define SSI 0x08 /* int: script: single step */ - #define SIR 0x04 /* int: script: interrupt instruct. */ - #define IID 0x01 /* int: script: illegal instruct. */ - -/*0d*/ u8 nc_sstat0; - #define ILF 0x80 /* sta: data in SIDL register lsb */ - #define ORF 0x40 /* sta: data in SODR register lsb */ - #define OLF 0x20 /* sta: data in SODL register lsb */ - #define AIP 0x10 /* sta: arbitration in progress */ - #define LOA 0x08 /* sta: arbitration lost */ - #define WOA 0x04 /* sta: arbitration won */ - #define IRST 0x02 /* sta: scsi reset signal */ - #define SDP 0x01 /* sta: scsi parity signal */ - -/*0e*/ u8 nc_sstat1; - #define FF3210 0xf0 /* sta: bytes in the scsi fifo */ - -/*0f*/ u8 nc_sstat2; - #define ILF1 0x80 /* sta: data in SIDL register msb[W]*/ - #define ORF1 0x40 /* sta: data in SODR register msb[W]*/ - #define OLF1 0x20 /* sta: data in SODL register msb[W]*/ - #define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */ - #define LDSC 0x02 /* sta: disconnect & reconnect */ - -/*10*/ u8 nc_dsa; /* --> Base page */ -/*11*/ u8 nc_dsa1; -/*12*/ u8 nc_dsa2; -/*13*/ u8 nc_dsa3; - -/*14*/ u8 nc_istat; /* --> Main Command and status */ - #define CABRT 0x80 /* cmd: abort current operation */ - #define SRST 0x40 /* mod: reset chip */ - #define SIGP 0x20 /* r/w: message from host to ncr */ - #define SEM 0x10 /* r/w: message between host + ncr */ - #define CON 0x08 /* sta: connected to scsi */ - #define INTF 0x04 /* sta: int on the fly (reset by wr)*/ - #define SIP 0x02 /* sta: scsi-interrupt */ - #define DIP 0x01 /* sta: host/script interrupt */ - -/*15*/ u8 nc_istat1; /* 896 and later cores only */ - #define FLSH 0x04 /* sta: chip is flushing */ - #define SRUN 0x02 /* sta: scripts are running */ - #define SIRQD 0x01 /* r/w: disable INT pin */ - -/*16*/ u8 nc_mbox0; /* 896 and later cores only */ -/*17*/ u8 nc_mbox1; /* 896 and later cores only */ - -/*18*/ u8 nc_ctest0; - #define EHP 0x04 /* 720 even host parity */ -/*19*/ u8 nc_ctest1; - -/*1a*/ u8 nc_ctest2; - #define CSIGP 0x40 - /* bits 0-2,7 rsvd for C1010 */ - -/*1b*/ u8 nc_ctest3; - #define FLF 0x08 /* cmd: flush dma fifo */ - #define CLF 0x04 /* cmd: clear dma fifo */ - #define FM 0x02 /* mod: fetch pin mode */ - #define WRIE 0x01 /* mod: write and invalidate enable */ - /* bits 4-7 rsvd for C1010 */ - -/*1c*/ u32 nc_temp; /* ### Temporary stack */ - -/*20*/ u8 nc_dfifo; -/*21*/ u8 nc_ctest4; - #define MUX 0x80 /* 720 host bus multiplex mode */ - #define BDIS 0x80 /* mod: burst disable */ - #define MPEE 0x08 /* mod: master parity error enable */ - -/*22*/ u8 nc_ctest5; - #define DFS 0x20 /* mod: dma fifo size */ - /* bits 0-1, 3-7 rsvd for C1010 */ -/*23*/ u8 nc_ctest6; - -/*24*/ u32 nc_dbc; /* ### Byte count and command */ -/*28*/ u32 nc_dnad; /* ### Next command register */ -/*2c*/ u32 nc_dsp; /* --> Script Pointer */ -/*30*/ u32 nc_dsps; /* --> Script pointer save/opcode#2 */ - -/*34*/ u8 nc_scratcha; /* Temporary register a */ -/*35*/ u8 nc_scratcha1; -/*36*/ u8 nc_scratcha2; -/*37*/ u8 nc_scratcha3; - -/*38*/ u8 nc_dmode; - #define BL_2 0x80 /* mod: burst length shift value +2 */ - #define BL_1 0x40 /* mod: burst length shift value +1 */ - #define ERL 0x08 /* mod: enable read line */ - #define ERMP 0x04 /* mod: enable read multiple */ - #define BOF 0x02 /* mod: burst op code fetch */ - -/*39*/ u8 nc_dien; -/*3a*/ u8 nc_sbr; - -/*3b*/ u8 nc_dcntl; /* --> Script execution control */ - #define CLSE 0x80 /* mod: cache line size enable */ - #define PFF 0x40 /* cmd: pre-fetch flush */ - #define PFEN 0x20 /* mod: pre-fetch enable */ - #define EA 0x20 /* mod: 720 enable-ack */ - #define SSM 0x10 /* mod: single step mode */ - #define IRQM 0x08 /* mod: irq mode (1 = totem pole !) */ - #define STD 0x04 /* cmd: start dma mode */ - #define IRQD 0x02 /* mod: irq disable */ - #define NOCOM 0x01 /* cmd: protect sfbr while reselect */ - /* bits 0-1 rsvd for C1010 */ - -/*3c*/ u32 nc_adder; - -/*40*/ u16 nc_sien; /* -->: interrupt enable */ -/*42*/ u16 nc_sist; /* <--: interrupt status */ - #define SBMC 0x1000/* sta: SCSI Bus Mode Change (895/6 only) */ - #define STO 0x0400/* sta: timeout (select) */ - #define GEN 0x0200/* sta: timeout (general) */ - #define HTH 0x0100/* sta: timeout (handshake) */ - #define MA 0x80 /* sta: phase mismatch */ - #define CMP 0x40 /* sta: arbitration complete */ - #define SEL 0x20 /* sta: selected by another device */ - #define RSL 0x10 /* sta: reselected by another device*/ - #define SGE 0x08 /* sta: gross error (over/underflow)*/ - #define UDC 0x04 /* sta: unexpected disconnect */ - #define RST 0x02 /* sta: scsi bus reset detected */ - #define PAR 0x01 /* sta: scsi parity error */ - -/*44*/ u8 nc_slpar; -/*45*/ u8 nc_swide; -/*46*/ u8 nc_macntl; -/*47*/ u8 nc_gpcntl; -/*48*/ u8 nc_stime0; /* cmd: timeout for select&handshake*/ -/*49*/ u8 nc_stime1; /* cmd: timeout user defined */ -/*4a*/ u16 nc_respid; /* sta: Reselect-IDs */ - -/*4c*/ u8 nc_stest0; - -/*4d*/ u8 nc_stest1; - #define SCLK 0x80 /* Use the PCI clock as SCSI clock */ - #define DBLEN 0x08 /* clock doubler running */ - #define DBLSEL 0x04 /* clock doubler selected */ - - -/*4e*/ u8 nc_stest2; - #define ROF 0x40 /* reset scsi offset (after gross error!) */ - #define DIF 0x20 /* 720 SCSI differential mode */ - #define EXT 0x02 /* extended filtering */ - -/*4f*/ u8 nc_stest3; - #define TE 0x80 /* c: tolerAnt enable */ - #define HSC 0x20 /* c: Halt SCSI Clock */ - #define CSF 0x02 /* c: clear scsi fifo */ - -/*50*/ u16 nc_sidl; /* Lowlevel: latched from scsi data */ -/*52*/ u8 nc_stest4; - #define SMODE 0xc0 /* SCSI bus mode (895/6 only) */ - #define SMODE_HVD 0x40 /* High Voltage Differential */ - #define SMODE_SE 0x80 /* Single Ended */ - #define SMODE_LVD 0xc0 /* Low Voltage Differential */ - #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */ - /* bits 0-5 rsvd for C1010 */ - -/*53*/ u8 nc_53_; -/*54*/ u16 nc_sodl; /* Lowlevel: data out to scsi data */ -/*56*/ u8 nc_ccntl0; /* Chip Control 0 (896) */ - #define ENPMJ 0x80 /* Enable Phase Mismatch Jump */ - #define PMJCTL 0x40 /* Phase Mismatch Jump Control */ - #define ENNDJ 0x20 /* Enable Non Data PM Jump */ - #define DISFC 0x10 /* Disable Auto FIFO Clear */ - #define DILS 0x02 /* Disable Internal Load/Store */ - #define DPR 0x01 /* Disable Pipe Req */ - -/*57*/ u8 nc_ccntl1; /* Chip Control 1 (896) */ - #define ZMOD 0x80 /* High Impedance Mode */ - #define DIC 0x10 /* Disable Internal Cycles */ - #define DDAC 0x08 /* Disable Dual Address Cycle */ - #define XTIMOD 0x04 /* 64-bit Table Ind. Indexing Mode */ - #define EXTIBMV 0x02 /* Enable 64-bit Table Ind. BMOV */ - #define EXDBMV 0x01 /* Enable 64-bit Direct BMOV */ - -/*58*/ u16 nc_sbdl; /* Lowlevel: data from scsi data */ -/*5a*/ u16 nc_5a_; - -/*5c*/ u8 nc_scr0; /* Working register B */ -/*5d*/ u8 nc_scr1; /* */ -/*5e*/ u8 nc_scr2; /* */ -/*5f*/ u8 nc_scr3; /* */ - -/*60*/ u8 nc_scrx[64]; /* Working register C-R */ -/*a0*/ u32 nc_mmrs; /* Memory Move Read Selector */ -/*a4*/ u32 nc_mmws; /* Memory Move Write Selector */ -/*a8*/ u32 nc_sfs; /* Script Fetch Selector */ -/*ac*/ u32 nc_drs; /* DSA Relative Selector */ -/*b0*/ u32 nc_sbms; /* Static Block Move Selector */ -/*b4*/ u32 nc_dbms; /* Dynamic Block Move Selector */ -/*b8*/ u32 nc_dnad64; /* DMA Next Address 64 */ -/*bc*/ u16 nc_scntl4; /* C1010 only */ - #define U3EN 0x80 /* Enable Ultra 3 */ - #define AIPEN 0x40 /* Allow check upper byte lanes */ - #define XCLKH_DT 0x08 /* Extra clock of data hold on DT - transfer edge */ - #define XCLKH_ST 0x04 /* Extra clock of data hold on ST - transfer edge */ - -/*be*/ u8 nc_aipcntl0; /* Epat Control 1 C1010 only */ -/*bf*/ u8 nc_aipcntl1; /* AIP Control C1010_66 Only */ - -/*c0*/ u32 nc_pmjad1; /* Phase Mismatch Jump Address 1 */ -/*c4*/ u32 nc_pmjad2; /* Phase Mismatch Jump Address 2 */ -/*c8*/ u8 nc_rbc; /* Remaining Byte Count */ -/*c9*/ u8 nc_rbc1; /* */ -/*ca*/ u8 nc_rbc2; /* */ -/*cb*/ u8 nc_rbc3; /* */ - -/*cc*/ u8 nc_ua; /* Updated Address */ -/*cd*/ u8 nc_ua1; /* */ -/*ce*/ u8 nc_ua2; /* */ -/*cf*/ u8 nc_ua3; /* */ -/*d0*/ u32 nc_esa; /* Entry Storage Address */ -/*d4*/ u8 nc_ia; /* Instruction Address */ -/*d5*/ u8 nc_ia1; -/*d6*/ u8 nc_ia2; -/*d7*/ u8 nc_ia3; -/*d8*/ u32 nc_sbc; /* SCSI Byte Count (3 bytes only) */ -/*dc*/ u32 nc_csbc; /* Cumulative SCSI Byte Count */ - - /* Following for C1010 only */ -/*e0*/ u16 nc_crcpad; /* CRC Value */ -/*e2*/ u8 nc_crccntl0; /* CRC control register */ - #define SNDCRC 0x10 /* Send CRC Request */ -/*e3*/ u8 nc_crccntl1; /* CRC control register */ -/*e4*/ u32 nc_crcdata; /* CRC data register */ -/*e8*/ u32 nc_e8_; /* rsvd */ -/*ec*/ u32 nc_ec_; /* rsvd */ -/*f0*/ u16 nc_dfbc; /* DMA FIFO byte count */ - -}; - -/*----------------------------------------------------------- -** -** Utility macros for the script. -** -**----------------------------------------------------------- -*/ - -#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r)) -#define REG(r) REGJ (nc_, r) - -typedef u32 ncrcmd; - -/*----------------------------------------------------------- -** -** SCSI phases -** -** DT phases illegal for ncr driver. -** -**----------------------------------------------------------- -*/ - -#define SCR_DATA_OUT 0x00000000 -#define SCR_DATA_IN 0x01000000 -#define SCR_COMMAND 0x02000000 -#define SCR_STATUS 0x03000000 -#define SCR_DT_DATA_OUT 0x04000000 -#define SCR_DT_DATA_IN 0x05000000 -#define SCR_MSG_OUT 0x06000000 -#define SCR_MSG_IN 0x07000000 - -#define SCR_ILG_OUT 0x04000000 -#define SCR_ILG_IN 0x05000000 - -/*----------------------------------------------------------- -** -** Data transfer via SCSI. -** -**----------------------------------------------------------- -** -** MOVE_ABS (LEN) -** <> -** -** MOVE_IND (LEN) -** <> -** -** MOVE_TBL -** <> -** -**----------------------------------------------------------- -*/ - -#define OPC_MOVE 0x08000000 - -#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l)) -#define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l)) -#define SCR_MOVE_TBL (0x10000000 | OPC_MOVE) - -#define SCR_CHMOV_ABS(l) ((0x00000000) | (l)) -#define SCR_CHMOV_IND(l) ((0x20000000) | (l)) -#define SCR_CHMOV_TBL (0x10000000) - -struct scr_tblmove { - u32 size; - u32 addr; -}; - -/*----------------------------------------------------------- -** -** Selection -** -**----------------------------------------------------------- -** -** SEL_ABS | SCR_ID (0..15) [ | REL_JMP] -** <> -** -** SEL_TBL | << dnad_offset>> [ | REL_JMP] -** <> -** -**----------------------------------------------------------- -*/ - -#define SCR_SEL_ABS 0x40000000 -#define SCR_SEL_ABS_ATN 0x41000000 -#define SCR_SEL_TBL 0x42000000 -#define SCR_SEL_TBL_ATN 0x43000000 - - -#ifdef SCSI_NCR_BIG_ENDIAN -struct scr_tblsel { - u8 sel_scntl3; - u8 sel_id; - u8 sel_sxfer; - u8 sel_scntl4; -}; -#else -struct scr_tblsel { - u8 sel_scntl4; - u8 sel_sxfer; - u8 sel_id; - u8 sel_scntl3; -}; -#endif - -#define SCR_JMP_REL 0x04000000 -#define SCR_ID(id) (((u32)(id)) << 16) - -/*----------------------------------------------------------- -** -** Waiting for Disconnect or Reselect -** -**----------------------------------------------------------- -** -** WAIT_DISC -** dummy: <> -** -** WAIT_RESEL -** <> -** -**----------------------------------------------------------- -*/ - -#define SCR_WAIT_DISC 0x48000000 -#define SCR_WAIT_RESEL 0x50000000 - -/*----------------------------------------------------------- -** -** Bit Set / Reset -** -**----------------------------------------------------------- -** -** SET (flags {|.. }) -** -** CLR (flags {|.. }) -** -**----------------------------------------------------------- -*/ - -#define SCR_SET(f) (0x58000000 | (f)) -#define SCR_CLR(f) (0x60000000 | (f)) - -#define SCR_CARRY 0x00000400 -#define SCR_TRG 0x00000200 -#define SCR_ACK 0x00000040 -#define SCR_ATN 0x00000008 - - - - -/*----------------------------------------------------------- -** -** Memory to memory move -** -**----------------------------------------------------------- -** -** COPY (bytecount) -** << source_address >> -** << destination_address >> -** -** SCR_COPY sets the NO FLUSH option by default. -** SCR_COPY_F does not set this option. -** -** For chips which do not support this option, -** ncr_copy_and_bind() will remove this bit. -**----------------------------------------------------------- -*/ - -#define SCR_NO_FLUSH 0x01000000 - -#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n)) -#define SCR_COPY_F(n) (0xc0000000 | (n)) - -/*----------------------------------------------------------- -** -** Register move and binary operations -** -**----------------------------------------------------------- -** -** SFBR_REG (reg, op, data) reg = SFBR op data -** << 0 >> -** -** REG_SFBR (reg, op, data) SFBR = reg op data -** << 0 >> -** -** REG_REG (reg, op, data) reg = reg op data -** << 0 >> -** -**----------------------------------------------------------- -** On 810A, 860, 825A, 875, 895 and 896 chips the content -** of SFBR register can be used as data (SCR_SFBR_DATA). -** The 896 has additional IO registers starting at -** offset 0x80. Bit 7 of register offset is stored in -** bit 7 of the SCRIPTS instruction first DWORD. -**----------------------------------------------------------- -*/ - -#define SCR_REG_OFS(ofs) ((((ofs) & 0x7f) << 16ul) + ((ofs) & 0x80)) - -#define SCR_SFBR_REG(reg,op,data) \ - (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) - -#define SCR_REG_SFBR(reg,op,data) \ - (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) - -#define SCR_REG_REG(reg,op,data) \ - (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) - - -#define SCR_LOAD 0x00000000 -#define SCR_SHL 0x01000000 -#define SCR_OR 0x02000000 -#define SCR_XOR 0x03000000 -#define SCR_AND 0x04000000 -#define SCR_SHR 0x05000000 -#define SCR_ADD 0x06000000 -#define SCR_ADDC 0x07000000 - -#define SCR_SFBR_DATA (0x00800000>>8ul) /* Use SFBR as data */ - -/*----------------------------------------------------------- -** -** FROM_REG (reg) SFBR = reg -** << 0 >> -** -** TO_REG (reg) reg = SFBR -** << 0 >> -** -** LOAD_REG (reg, data) reg = -** << 0 >> -** -** LOAD_SFBR(data) SFBR = -** << 0 >> -** -**----------------------------------------------------------- -*/ - -#define SCR_FROM_REG(reg) \ - SCR_REG_SFBR(reg,SCR_OR,0) - -#define SCR_TO_REG(reg) \ - SCR_SFBR_REG(reg,SCR_OR,0) - -#define SCR_LOAD_REG(reg,data) \ - SCR_REG_REG(reg,SCR_LOAD,data) - -#define SCR_LOAD_SFBR(data) \ - (SCR_REG_SFBR (gpreg, SCR_LOAD, data)) - -/*----------------------------------------------------------- -** -** LOAD from memory to register. -** STORE from register to memory. -** -** Only supported by 810A, 860, 825A, 875, 895 and 896. -** -**----------------------------------------------------------- -** -** LOAD_ABS (LEN) -** <> -** -** LOAD_REL (LEN) (DSA relative) -** <> -** -**----------------------------------------------------------- -*/ - -#define SCR_REG_OFS2(ofs) (((ofs) & 0xff) << 16ul) -#define SCR_NO_FLUSH2 0x02000000 -#define SCR_DSA_REL2 0x10000000 - -#define SCR_LOAD_R(reg, how, n) \ - (0xe1000000 | how | (SCR_REG_OFS2(REG(reg))) | (n)) - -#define SCR_STORE_R(reg, how, n) \ - (0xe0000000 | how | (SCR_REG_OFS2(REG(reg))) | (n)) - -#define SCR_LOAD_ABS(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2, n) -#define SCR_LOAD_REL(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n) -#define SCR_LOAD_ABS_F(reg, n) SCR_LOAD_R(reg, 0, n) -#define SCR_LOAD_REL_F(reg, n) SCR_LOAD_R(reg, SCR_DSA_REL2, n) - -#define SCR_STORE_ABS(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2, n) -#define SCR_STORE_REL(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n) -#define SCR_STORE_ABS_F(reg, n) SCR_STORE_R(reg, 0, n) -#define SCR_STORE_REL_F(reg, n) SCR_STORE_R(reg, SCR_DSA_REL2, n) - - -/*----------------------------------------------------------- -** -** Waiting for Disconnect or Reselect -** -**----------------------------------------------------------- -** -** JUMP [ | IFTRUE/IFFALSE ( ... ) ] -** <
> -** -** JUMPR [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** CALL [ | IFTRUE/IFFALSE ( ... ) ] -** <
> -** -** CALLR [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** RETURN [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** INT [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** INT_FLY [ | IFTRUE/IFFALSE ( ... ) ] -** <> -** -** Conditions: -** WHEN (phase) -** IF (phase) -** CARRYSET -** DATA (data, mask) -** -**----------------------------------------------------------- -*/ - -#define SCR_NO_OP 0x80000000 -#define SCR_JUMP 0x80080000 -#define SCR_JUMP64 0x80480000 -#define SCR_JUMPR 0x80880000 -#define SCR_CALL 0x88080000 -#define SCR_CALLR 0x88880000 -#define SCR_RETURN 0x90080000 -#define SCR_INT 0x98080000 -#define SCR_INT_FLY 0x98180000 - -#define IFFALSE(arg) (0x00080000 | (arg)) -#define IFTRUE(arg) (0x00000000 | (arg)) - -#define WHEN(phase) (0x00030000 | (phase)) -#define IF(phase) (0x00020000 | (phase)) - -#define DATA(D) (0x00040000 | ((D) & 0xff)) -#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff)) - -#define CARRYSET (0x00200000) - -/*----------------------------------------------------------- -** -** SCSI constants. -** -**----------------------------------------------------------- -*/ - -/* -** Status -*/ - -#define S_GOOD (0x00) -#define S_CHECK_COND (0x02) -#define S_COND_MET (0x04) -#define S_BUSY (0x08) -#define S_INT (0x10) -#define S_INT_COND_MET (0x14) -#define S_CONFLICT (0x18) -#define S_TERMINATED (0x20) -#define S_QUEUE_FULL (0x28) -#define S_ILLEGAL (0xff) -#define S_SENSE (0x80) - -/* - * End of ncrreg from FreeBSD - */ - -/* - Build a scatter/gather entry. - see sym53c8xx_2/sym_hipd.h for more detailed sym_build_sge() - implementation ;) - */ - -#define ncr_build_sge(np, data, badd, len) \ -do { \ - (data)->addr = cpu_to_scr(badd); \ - (data)->size = cpu_to_scr(len); \ -} while (0) - -/*========================================================== -** -** Structures used by the detection routine to transmit -** device configuration to the attach function. -** -**========================================================== -*/ -struct ncr_slot { - u_long base; - u_long base_2; - u_long base_c; - u_long base_2_c; - void __iomem *base_v; - void __iomem *base_2_v; - int irq; -/* port and reg fields to use INB, OUTB macros */ - volatile struct ncr_reg __iomem *reg; -}; - -/*========================================================== -** -** Structure used by detection routine to save data on -** each detected board for attach. -** -**========================================================== -*/ -struct ncr_device { - struct device *dev; - struct ncr_slot slot; - struct ncr_chip chip; - u_char host_id; - u8 differential; -}; - -extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device); -extern void ncr53c8xx_release(struct Scsi_Host *host); -irqreturn_t ncr53c8xx_intr(int irq, void *dev_id); -extern int ncr53c8xx_init(void); -extern void ncr53c8xx_exit(void); - -#endif /* NCR53C8XX_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/nsp32.c b/ANDROID_3.4.5/drivers/scsi/nsp32.c deleted file mode 100644 index 62b61689..00000000 --- a/ANDROID_3.4.5/drivers/scsi/nsp32.c +++ /dev/null @@ -1,3461 +0,0 @@ -/* - * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver - * Copyright (C) 2001, 2002, 2003 - * YOKOTA Hiroshi - * GOTO Masanori , - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * - * Revision History: - * 1.0: Initial Release. - * 1.1: Add /proc SDTR status. - * Remove obsolete error handler nsp32_reset. - * Some clean up. - * 1.2: PowerPC (big endian) support. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -#include "nsp32.h" - - -/*********************************************************************** - * Module parameters - */ -static int trans_mode = 0; /* default: BIOS */ -module_param (trans_mode, int, 0); -MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra20M"); -#define ASYNC_MODE 1 -#define ULTRA20M_MODE 2 - -static bool auto_param = 0; /* default: ON */ -module_param (auto_param, bool, 0); -MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)"); - -static bool disc_priv = 1; /* default: OFF */ -module_param (disc_priv, bool, 0); -MODULE_PARM_DESC(disc_priv, "disconnection privilege mode (0: ON 1: OFF(default))"); - -MODULE_AUTHOR("YOKOTA Hiroshi , GOTO Masanori "); -MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE CardBus/PCI SCSI host bus adapter module"); -MODULE_LICENSE("GPL"); - -static const char *nsp32_release_version = "1.2"; - - -/**************************************************************************** - * Supported hardware - */ -static struct pci_device_id nsp32_pci_table[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_IODATA, - .device = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = MODEL_IODATA, - }, - { - .vendor = PCI_VENDOR_ID_WORKBIT, - .device = PCI_DEVICE_ID_NINJASCSI_32BI_KME, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = MODEL_KME, - }, - { - .vendor = PCI_VENDOR_ID_WORKBIT, - .device = PCI_DEVICE_ID_NINJASCSI_32BI_WBT, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = MODEL_WORKBIT, - }, - { - .vendor = PCI_VENDOR_ID_WORKBIT, - .device = PCI_DEVICE_ID_WORKBIT_STANDARD, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = MODEL_PCI_WORKBIT, - }, - { - .vendor = PCI_VENDOR_ID_WORKBIT, - .device = PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = MODEL_LOGITEC, - }, - { - .vendor = PCI_VENDOR_ID_WORKBIT, - .device = PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = MODEL_PCI_LOGITEC, - }, - { - .vendor = PCI_VENDOR_ID_WORKBIT, - .device = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = MODEL_PCI_MELCO, - }, - { - .vendor = PCI_VENDOR_ID_WORKBIT, - .device = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = MODEL_PCI_MELCO, - }, - {0,0,}, -}; -MODULE_DEVICE_TABLE(pci, nsp32_pci_table); - -static nsp32_hw_data nsp32_data_base; /* probe <-> detect glue */ - - -/* - * Period/AckWidth speed conversion table - * - * Note: This period/ackwidth speed table must be in descending order. - */ -static nsp32_sync_table nsp32_sync_table_40M[] = { - /* {PNo, AW, SP, EP, SREQ smpl} Speed(MB/s) Period AckWidth */ - {0x1, 0, 0x0c, 0x0c, SMPL_40M}, /* 20.0 : 50ns, 25ns */ - {0x2, 0, 0x0d, 0x18, SMPL_40M}, /* 13.3 : 75ns, 25ns */ - {0x3, 1, 0x19, 0x19, SMPL_40M}, /* 10.0 : 100ns, 50ns */ - {0x4, 1, 0x1a, 0x1f, SMPL_20M}, /* 8.0 : 125ns, 50ns */ - {0x5, 2, 0x20, 0x25, SMPL_20M}, /* 6.7 : 150ns, 75ns */ - {0x6, 2, 0x26, 0x31, SMPL_20M}, /* 5.7 : 175ns, 75ns */ - {0x7, 3, 0x32, 0x32, SMPL_20M}, /* 5.0 : 200ns, 100ns */ - {0x8, 3, 0x33, 0x38, SMPL_10M}, /* 4.4 : 225ns, 100ns */ - {0x9, 3, 0x39, 0x3e, SMPL_10M}, /* 4.0 : 250ns, 100ns */ -}; - -static nsp32_sync_table nsp32_sync_table_20M[] = { - {0x1, 0, 0x19, 0x19, SMPL_40M}, /* 10.0 : 100ns, 50ns */ - {0x2, 0, 0x1a, 0x25, SMPL_20M}, /* 6.7 : 150ns, 50ns */ - {0x3, 1, 0x26, 0x32, SMPL_20M}, /* 5.0 : 200ns, 100ns */ - {0x4, 1, 0x33, 0x3e, SMPL_10M}, /* 4.0 : 250ns, 100ns */ - {0x5, 2, 0x3f, 0x4b, SMPL_10M}, /* 3.3 : 300ns, 150ns */ - {0x6, 2, 0x4c, 0x57, SMPL_10M}, /* 2.8 : 350ns, 150ns */ - {0x7, 3, 0x58, 0x64, SMPL_10M}, /* 2.5 : 400ns, 200ns */ - {0x8, 3, 0x65, 0x70, SMPL_10M}, /* 2.2 : 450ns, 200ns */ - {0x9, 3, 0x71, 0x7d, SMPL_10M}, /* 2.0 : 500ns, 200ns */ -}; - -static nsp32_sync_table nsp32_sync_table_pci[] = { - {0x1, 0, 0x0c, 0x0f, SMPL_40M}, /* 16.6 : 60ns, 30ns */ - {0x2, 0, 0x10, 0x16, SMPL_40M}, /* 11.1 : 90ns, 30ns */ - {0x3, 1, 0x17, 0x1e, SMPL_20M}, /* 8.3 : 120ns, 60ns */ - {0x4, 1, 0x1f, 0x25, SMPL_20M}, /* 6.7 : 150ns, 60ns */ - {0x5, 2, 0x26, 0x2d, SMPL_20M}, /* 5.6 : 180ns, 90ns */ - {0x6, 2, 0x2e, 0x34, SMPL_10M}, /* 4.8 : 210ns, 90ns */ - {0x7, 3, 0x35, 0x3c, SMPL_10M}, /* 4.2 : 240ns, 120ns */ - {0x8, 3, 0x3d, 0x43, SMPL_10M}, /* 3.7 : 270ns, 120ns */ - {0x9, 3, 0x44, 0x4b, SMPL_10M}, /* 3.3 : 300ns, 120ns */ -}; - -/* - * function declaration - */ -/* module entry point */ -static int __devinit nsp32_probe (struct pci_dev *, const struct pci_device_id *); -static void __devexit nsp32_remove(struct pci_dev *); -static int __init init_nsp32 (void); -static void __exit exit_nsp32 (void); - -/* struct struct scsi_host_template */ -static int nsp32_proc_info (struct Scsi_Host *, char *, char **, off_t, int, int); - -static int nsp32_detect (struct pci_dev *pdev); -static int nsp32_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static const char *nsp32_info (struct Scsi_Host *); -static int nsp32_release (struct Scsi_Host *); - -/* SCSI error handler */ -static int nsp32_eh_abort (struct scsi_cmnd *); -static int nsp32_eh_bus_reset (struct scsi_cmnd *); -static int nsp32_eh_host_reset(struct scsi_cmnd *); - -/* generate SCSI message */ -static void nsp32_build_identify(struct scsi_cmnd *); -static void nsp32_build_nop (struct scsi_cmnd *); -static void nsp32_build_reject (struct scsi_cmnd *); -static void nsp32_build_sdtr (struct scsi_cmnd *, unsigned char, unsigned char); - -/* SCSI message handler */ -static int nsp32_busfree_occur(struct scsi_cmnd *, unsigned short); -static void nsp32_msgout_occur (struct scsi_cmnd *); -static void nsp32_msgin_occur (struct scsi_cmnd *, unsigned long, unsigned short); - -static int nsp32_setup_sg_table (struct scsi_cmnd *); -static int nsp32_selection_autopara(struct scsi_cmnd *); -static int nsp32_selection_autoscsi(struct scsi_cmnd *); -static void nsp32_scsi_done (struct scsi_cmnd *); -static int nsp32_arbitration (struct scsi_cmnd *, unsigned int); -static int nsp32_reselection (struct scsi_cmnd *, unsigned char); -static void nsp32_adjust_busfree (struct scsi_cmnd *, unsigned int); -static void nsp32_restart_autoscsi (struct scsi_cmnd *, unsigned short); - -/* SCSI SDTR */ -static void nsp32_analyze_sdtr (struct scsi_cmnd *); -static int nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *, unsigned char); -static void nsp32_set_async (nsp32_hw_data *, nsp32_target *); -static void nsp32_set_max_sync (nsp32_hw_data *, nsp32_target *, unsigned char *, unsigned char *); -static void nsp32_set_sync_entry (nsp32_hw_data *, nsp32_target *, int, unsigned char); - -/* SCSI bus status handler */ -static void nsp32_wait_req (nsp32_hw_data *, int); -static void nsp32_wait_sack (nsp32_hw_data *, int); -static void nsp32_sack_assert (nsp32_hw_data *); -static void nsp32_sack_negate (nsp32_hw_data *); -static void nsp32_do_bus_reset(nsp32_hw_data *); - -/* hardware interrupt handler */ -static irqreturn_t do_nsp32_isr(int, void *); - -/* initialize hardware */ -static int nsp32hw_init(nsp32_hw_data *); - -/* EEPROM handler */ -static int nsp32_getprom_param (nsp32_hw_data *); -static int nsp32_getprom_at24 (nsp32_hw_data *); -static int nsp32_getprom_c16 (nsp32_hw_data *); -static void nsp32_prom_start (nsp32_hw_data *); -static void nsp32_prom_stop (nsp32_hw_data *); -static int nsp32_prom_read (nsp32_hw_data *, int); -static int nsp32_prom_read_bit (nsp32_hw_data *); -static void nsp32_prom_write_bit(nsp32_hw_data *, int); -static void nsp32_prom_set (nsp32_hw_data *, int, int); -static int nsp32_prom_get (nsp32_hw_data *, int); - -/* debug/warning/info message */ -static void nsp32_message (const char *, int, char *, char *, ...); -#ifdef NSP32_DEBUG -static void nsp32_dmessage(const char *, int, int, char *, ...); -#endif - -/* - * max_sectors is currently limited up to 128. - */ -static struct scsi_host_template nsp32_template = { - .proc_name = "nsp32", - .name = "Workbit NinjaSCSI-32Bi/UDE", - .proc_info = nsp32_proc_info, - .info = nsp32_info, - .queuecommand = nsp32_queuecommand, - .can_queue = 1, - .sg_tablesize = NSP32_SG_SIZE, - .max_sectors = 128, - .cmd_per_lun = 1, - .this_id = NSP32_HOST_SCSIID, - .use_clustering = DISABLE_CLUSTERING, - .eh_abort_handler = nsp32_eh_abort, - .eh_bus_reset_handler = nsp32_eh_bus_reset, - .eh_host_reset_handler = nsp32_eh_host_reset, -/* .highmem_io = 1, */ -}; - -#include "nsp32_io.h" - -/*********************************************************************** - * debug, error print - */ -#ifndef NSP32_DEBUG -# define NSP32_DEBUG_MASK 0x000000 -# define nsp32_msg(type, args...) nsp32_message ("", 0, (type), args) -# define nsp32_dbg(mask, args...) /* */ -#else -# define NSP32_DEBUG_MASK 0xffffff -# define nsp32_msg(type, args...) \ - nsp32_message (__func__, __LINE__, (type), args) -# define nsp32_dbg(mask, args...) \ - nsp32_dmessage(__func__, __LINE__, (mask), args) -#endif - -#define NSP32_DEBUG_QUEUECOMMAND BIT(0) -#define NSP32_DEBUG_REGISTER BIT(1) -#define NSP32_DEBUG_AUTOSCSI BIT(2) -#define NSP32_DEBUG_INTR BIT(3) -#define NSP32_DEBUG_SGLIST BIT(4) -#define NSP32_DEBUG_BUSFREE BIT(5) -#define NSP32_DEBUG_CDB_CONTENTS BIT(6) -#define NSP32_DEBUG_RESELECTION BIT(7) -#define NSP32_DEBUG_MSGINOCCUR BIT(8) -#define NSP32_DEBUG_EEPROM BIT(9) -#define NSP32_DEBUG_MSGOUTOCCUR BIT(10) -#define NSP32_DEBUG_BUSRESET BIT(11) -#define NSP32_DEBUG_RESTART BIT(12) -#define NSP32_DEBUG_SYNC BIT(13) -#define NSP32_DEBUG_WAIT BIT(14) -#define NSP32_DEBUG_TARGETFLAG BIT(15) -#define NSP32_DEBUG_PROC BIT(16) -#define NSP32_DEBUG_INIT BIT(17) -#define NSP32_SPECIAL_PRINT_REGISTER BIT(20) - -#define NSP32_DEBUG_BUF_LEN 100 - -static void nsp32_message(const char *func, int line, char *type, char *fmt, ...) -{ - va_list args; - char buf[NSP32_DEBUG_BUF_LEN]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - -#ifndef NSP32_DEBUG - printk("%snsp32: %s\n", type, buf); -#else - printk("%snsp32: %s (%d): %s\n", type, func, line, buf); -#endif -} - -#ifdef NSP32_DEBUG -static void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...) -{ - va_list args; - char buf[NSP32_DEBUG_BUF_LEN]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - - if (mask & NSP32_DEBUG_MASK) { - printk("nsp32-debug: 0x%x %s (%d): %s\n", mask, func, line, buf); - } -} -#endif - -#ifdef NSP32_DEBUG -# include "nsp32_debug.c" -#else -# define show_command(arg) /* */ -# define show_busphase(arg) /* */ -# define show_autophase(arg) /* */ -#endif - -/* - * IDENTIFY Message - */ -static void nsp32_build_identify(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - int pos = data->msgout_len; - int mode = FALSE; - - /* XXX: Auto DiscPriv detection is progressing... */ - if (disc_priv == 0) { - /* mode = TRUE; */ - } - - data->msgoutbuf[pos] = IDENTIFY(mode, SCpnt->device->lun); pos++; - - data->msgout_len = pos; -} - -/* - * SDTR Message Routine - */ -static void nsp32_build_sdtr(struct scsi_cmnd *SCpnt, - unsigned char period, - unsigned char offset) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - int pos = data->msgout_len; - - data->msgoutbuf[pos] = EXTENDED_MESSAGE; pos++; - data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++; - data->msgoutbuf[pos] = EXTENDED_SDTR; pos++; - data->msgoutbuf[pos] = period; pos++; - data->msgoutbuf[pos] = offset; pos++; - - data->msgout_len = pos; -} - -/* - * No Operation Message - */ -static void nsp32_build_nop(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - int pos = data->msgout_len; - - if (pos != 0) { - nsp32_msg(KERN_WARNING, - "Some messages are already contained!"); - return; - } - - data->msgoutbuf[pos] = NOP; pos++; - data->msgout_len = pos; -} - -/* - * Reject Message - */ -static void nsp32_build_reject(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - int pos = data->msgout_len; - - data->msgoutbuf[pos] = MESSAGE_REJECT; pos++; - data->msgout_len = pos; -} - -/* - * timer - */ -#if 0 -static void nsp32_start_timer(struct scsi_cmnd *SCpnt, int time) -{ - unsigned int base = SCpnt->host->io_port; - - nsp32_dbg(NSP32_DEBUG_INTR, "timer=%d", time); - - if (time & (~TIMER_CNT_MASK)) { - nsp32_dbg(NSP32_DEBUG_INTR, "timer set overflow"); - } - - nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK); -} -#endif - - -/* - * set SCSI command and other parameter to asic, and start selection phase - */ -static int nsp32_selection_autopara(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = SCpnt->device->host->io_port; - unsigned int host_id = SCpnt->device->host->this_id; - unsigned char target = scmd_id(SCpnt); - nsp32_autoparam *param = data->autoparam; - unsigned char phase; - int i, ret; - unsigned int msgout; - u16_le s; - - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in"); - - /* - * check bus free - */ - phase = nsp32_read1(base, SCSI_BUS_MONITOR); - if (phase != BUSMON_BUS_FREE) { - nsp32_msg(KERN_WARNING, "bus busy"); - show_busphase(phase & BUSMON_PHASE_MASK); - SCpnt->result = DID_BUS_BUSY << 16; - return FALSE; - } - - /* - * message out - * - * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout. - * over 3 messages needs another routine. - */ - if (data->msgout_len == 0) { - nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!"); - SCpnt->result = DID_ERROR << 16; - return FALSE; - } else if (data->msgout_len > 0 && data->msgout_len <= 3) { - msgout = 0; - for (i = 0; i < data->msgout_len; i++) { - /* - * the sending order of the message is: - * MCNT 3: MSG#0 -> MSG#1 -> MSG#2 - * MCNT 2: MSG#1 -> MSG#2 - * MCNT 1: MSG#2 - */ - msgout >>= 8; - msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24); - } - msgout |= MV_VALID; /* MV valid */ - msgout |= (unsigned int)data->msgout_len; /* len */ - } else { - /* data->msgout_len > 3 */ - msgout = 0; - } - - // nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n", nsp32_read2(base, SEL_TIME_OUT)); - // nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); - - /* - * setup asic parameter - */ - memset(param, 0, sizeof(nsp32_autoparam)); - - /* cdb */ - for (i = 0; i < SCpnt->cmd_len; i++) { - param->cdb[4 * i] = SCpnt->cmnd[i]; - } - - /* outgoing messages */ - param->msgout = cpu_to_le32(msgout); - - /* syncreg, ackwidth, target id, SREQ sampling rate */ - param->syncreg = data->cur_target->syncreg; - param->ackwidth = data->cur_target->ackwidth; - param->target_id = BIT(host_id) | BIT(target); - param->sample_reg = data->cur_target->sample_reg; - - // nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "sample rate=0x%x\n", data->cur_target->sample_reg); - - /* command control */ - param->command_control = cpu_to_le16(CLEAR_CDB_FIFO_POINTER | - AUTOSCSI_START | - AUTO_MSGIN_00_OR_04 | - AUTO_MSGIN_02 | - AUTO_ATN ); - - - /* transfer control */ - s = 0; - switch (data->trans_method) { - case NSP32_TRANSFER_BUSMASTER: - s |= BM_START; - break; - case NSP32_TRANSFER_MMIO: - s |= CB_MMIO_MODE; - break; - case NSP32_TRANSFER_PIO: - s |= CB_IO_MODE; - break; - default: - nsp32_msg(KERN_ERR, "unknown trans_method"); - break; - } - /* - * OR-ed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits. - * For bus master transfer, it's taken off. - */ - s |= (TRANSFER_GO | ALL_COUNTER_CLR); - param->transfer_control = cpu_to_le16(s); - - /* sg table addr */ - param->sgt_pointer = cpu_to_le32(data->cur_lunt->sglun_paddr); - - /* - * transfer parameter to ASIC - */ - nsp32_write4(base, SGT_ADR, data->auto_paddr); - nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER | - AUTO_PARAMETER ); - - /* - * Check arbitration - */ - ret = nsp32_arbitration(SCpnt, base); - - return ret; -} - - -/* - * Selection with AUTO SCSI (without AUTO PARAMETER) - */ -static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = SCpnt->device->host->io_port; - unsigned int host_id = SCpnt->device->host->this_id; - unsigned char target = scmd_id(SCpnt); - unsigned char phase; - int status; - unsigned short command = 0; - unsigned int msgout = 0; - unsigned short execph; - int i; - - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in"); - - /* - * IRQ disable - */ - nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); - - /* - * check bus line - */ - phase = nsp32_read1(base, SCSI_BUS_MONITOR); - if(((phase & BUSMON_BSY) == 1) || (phase & BUSMON_SEL) == 1) { - nsp32_msg(KERN_WARNING, "bus busy"); - SCpnt->result = DID_BUS_BUSY << 16; - status = 1; - goto out; - } - - /* - * clear execph - */ - execph = nsp32_read2(base, SCSI_EXECUTE_PHASE); - - /* - * clear FIFO counter to set CDBs - */ - nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER); - - /* - * set CDB0 - CDB15 - */ - for (i = 0; i < SCpnt->cmd_len; i++) { - nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]); - } - nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[0]); - - /* - * set SCSIOUT LATCH(initiator)/TARGET(target) (OR-ed) ID - */ - nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID, BIT(host_id) | BIT(target)); - - /* - * set SCSI MSGOUT REG - * - * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout. - * over 3 messages needs another routine. - */ - if (data->msgout_len == 0) { - nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!"); - SCpnt->result = DID_ERROR << 16; - status = 1; - goto out; - } else if (data->msgout_len > 0 && data->msgout_len <= 3) { - msgout = 0; - for (i = 0; i < data->msgout_len; i++) { - /* - * the sending order of the message is: - * MCNT 3: MSG#0 -> MSG#1 -> MSG#2 - * MCNT 2: MSG#1 -> MSG#2 - * MCNT 1: MSG#2 - */ - msgout >>= 8; - msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24); - } - msgout |= MV_VALID; /* MV valid */ - msgout |= (unsigned int)data->msgout_len; /* len */ - nsp32_write4(base, SCSI_MSG_OUT, msgout); - } else { - /* data->msgout_len > 3 */ - nsp32_write4(base, SCSI_MSG_OUT, 0); - } - - /* - * set selection timeout(= 250ms) - */ - nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); - - /* - * set SREQ hazard killer sampling rate - * - * TODO: sample_rate (BASE+0F) is 0 when internal clock = 40MHz. - * check other internal clock! - */ - nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg); - - /* - * clear Arbit - */ - nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); - - /* - * set SYNCREG - * Don't set BM_START_ADR before setting this register. - */ - nsp32_write1(base, SYNC_REG, data->cur_target->syncreg); - - /* - * set ACKWIDTH - */ - nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth); - - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, - "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x", - nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH), - nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID)); - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgout_len=%d, msgout=0x%x", - data->msgout_len, msgout); - - /* - * set SGT ADDR (physical address) - */ - nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr); - - /* - * set TRANSFER CONTROL REG - */ - command = 0; - command |= (TRANSFER_GO | ALL_COUNTER_CLR); - if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { - if (scsi_bufflen(SCpnt) > 0) { - command |= BM_START; - } - } else if (data->trans_method & NSP32_TRANSFER_MMIO) { - command |= CB_MMIO_MODE; - } else if (data->trans_method & NSP32_TRANSFER_PIO) { - command |= CB_IO_MODE; - } - nsp32_write2(base, TRANSFER_CONTROL, command); - - /* - * start AUTO SCSI, kick off arbitration - */ - command = (CLEAR_CDB_FIFO_POINTER | - AUTOSCSI_START | - AUTO_MSGIN_00_OR_04 | - AUTO_MSGIN_02 | - AUTO_ATN ); - nsp32_write2(base, COMMAND_CONTROL, command); - - /* - * Check arbitration - */ - status = nsp32_arbitration(SCpnt, base); - - out: - /* - * IRQ enable - */ - nsp32_write2(base, IRQ_CONTROL, 0); - - return status; -} - - -/* - * Arbitration Status Check - * - * Note: Arbitration counter is waited during ARBIT_GO is not lifting. - * Using udelay(1) consumes CPU time and system time, but - * arbitration delay time is defined minimal 2.4us in SCSI - * specification, thus udelay works as coarse grained wait timer. - */ -static int nsp32_arbitration(struct scsi_cmnd *SCpnt, unsigned int base) -{ - unsigned char arbit; - int status = TRUE; - int time = 0; - - do { - arbit = nsp32_read1(base, ARBIT_STATUS); - time++; - } while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && - (time <= ARBIT_TIMEOUT_TIME)); - - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, - "arbit: 0x%x, delay time: %d", arbit, time); - - if (arbit & ARBIT_WIN) { - /* Arbitration succeeded */ - SCpnt->result = DID_OK << 16; - nsp32_index_write1(base, EXT_PORT, LED_ON); /* PCI LED on */ - } else if (arbit & ARBIT_FAIL) { - /* Arbitration failed */ - SCpnt->result = DID_BUS_BUSY << 16; - status = FALSE; - } else { - /* - * unknown error or ARBIT_GO timeout, - * something lock up! guess no connection. - */ - nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit timeout"); - SCpnt->result = DID_NO_CONNECT << 16; - status = FALSE; - } - - /* - * clear Arbit - */ - nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR); - - return status; -} - - -/* - * reselection - * - * Note: This reselection routine is called from msgin_occur, - * reselection target id&lun must be already set. - * SCSI-2 says IDENTIFY implies RESTORE_POINTER operation. - */ -static int nsp32_reselection(struct scsi_cmnd *SCpnt, unsigned char newlun) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int host_id = SCpnt->device->host->this_id; - unsigned int base = SCpnt->device->host->io_port; - unsigned char tmpid, newid; - - nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter"); - - /* - * calculate reselected SCSI ID - */ - tmpid = nsp32_read1(base, RESELECT_ID); - tmpid &= (~BIT(host_id)); - newid = 0; - while (tmpid) { - if (tmpid & 1) { - break; - } - tmpid >>= 1; - newid++; - } - - /* - * If reselected New ID:LUN is not existed - * or current nexus is not existed, unexpected - * reselection is occurred. Send reject message. - */ - if (newid >= ARRAY_SIZE(data->lunt) || newlun >= ARRAY_SIZE(data->lunt[0])) { - nsp32_msg(KERN_WARNING, "unknown id/lun"); - return FALSE; - } else if(data->lunt[newid][newlun].SCpnt == NULL) { - nsp32_msg(KERN_WARNING, "no SCSI command is processing"); - return FALSE; - } - - data->cur_id = newid; - data->cur_lun = newlun; - data->cur_target = &(data->target[newid]); - data->cur_lunt = &(data->lunt[newid][newlun]); - - /* reset SACK/SavedACK counter (or ALL clear?) */ - nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); - - return TRUE; -} - - -/* - * nsp32_setup_sg_table - build scatter gather list for transfer data - * with bus master. - * - * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time. - */ -static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - struct scatterlist *sg; - nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt; - int num, i; - u32_le l; - - if (sgt == NULL) { - nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null"); - return FALSE; - } - - num = scsi_dma_map(SCpnt); - if (!num) - return TRUE; - else if (num < 0) - return FALSE; - else { - scsi_for_each_sg(SCpnt, sg, num, i) { - /* - * Build nsp32_sglist, substitute sg dma addresses. - */ - sgt[i].addr = cpu_to_le32(sg_dma_address(sg)); - sgt[i].len = cpu_to_le32(sg_dma_len(sg)); - - if (le32_to_cpu(sgt[i].len) > 0x10000) { - nsp32_msg(KERN_ERR, - "can't transfer over 64KB at a time, size=0x%lx", le32_to_cpu(sgt[i].len)); - return FALSE; - } - nsp32_dbg(NSP32_DEBUG_SGLIST, - "num 0x%x : addr 0x%lx len 0x%lx", - i, - le32_to_cpu(sgt[i].addr), - le32_to_cpu(sgt[i].len )); - } - - /* set end mark */ - l = le32_to_cpu(sgt[num-1].len); - sgt[num-1].len = cpu_to_le32(l | SGTEND); - } - - return TRUE; -} - -static int nsp32_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - nsp32_target *target; - nsp32_lunt *cur_lunt; - int ret; - - nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, - "enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x " - "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x", - SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0], SCpnt->cmd_len, - scsi_sg_count(SCpnt), scsi_sglist(SCpnt), scsi_bufflen(SCpnt)); - - if (data->CurrentSC != NULL) { - nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request"); - data->CurrentSC = NULL; - SCpnt->result = DID_NO_CONNECT << 16; - done(SCpnt); - return 0; - } - - /* check target ID is not same as this initiator ID */ - if (scmd_id(SCpnt) == SCpnt->device->host->this_id) { - nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "terget==host???"); - SCpnt->result = DID_BAD_TARGET << 16; - done(SCpnt); - return 0; - } - - /* check target LUN is allowable value */ - if (SCpnt->device->lun >= MAX_LUN) { - nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "no more lun"); - SCpnt->result = DID_BAD_TARGET << 16; - done(SCpnt); - return 0; - } - - show_command(SCpnt); - - SCpnt->scsi_done = done; - data->CurrentSC = SCpnt; - SCpnt->SCp.Status = CHECK_CONDITION; - SCpnt->SCp.Message = 0; - scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); - - SCpnt->SCp.ptr = (char *)scsi_sglist(SCpnt); - SCpnt->SCp.this_residual = scsi_bufflen(SCpnt); - SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; - - /* initialize data */ - data->msgout_len = 0; - data->msgin_len = 0; - cur_lunt = &(data->lunt[SCpnt->device->id][SCpnt->device->lun]); - cur_lunt->SCpnt = SCpnt; - cur_lunt->save_datp = 0; - cur_lunt->msgin03 = FALSE; - data->cur_lunt = cur_lunt; - data->cur_id = SCpnt->device->id; - data->cur_lun = SCpnt->device->lun; - - ret = nsp32_setup_sg_table(SCpnt); - if (ret == FALSE) { - nsp32_msg(KERN_ERR, "SGT fail"); - SCpnt->result = DID_ERROR << 16; - nsp32_scsi_done(SCpnt); - return 0; - } - - /* Build IDENTIFY */ - nsp32_build_identify(SCpnt); - - /* - * If target is the first time to transfer after the reset - * (target don't have SDTR_DONE and SDTR_INITIATOR), sync - * message SDTR is needed to do synchronous transfer. - */ - target = &data->target[scmd_id(SCpnt)]; - data->cur_target = target; - - if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) { - unsigned char period, offset; - - if (trans_mode != ASYNC_MODE) { - nsp32_set_max_sync(data, target, &period, &offset); - nsp32_build_sdtr(SCpnt, period, offset); - target->sync_flag |= SDTR_INITIATOR; - } else { - nsp32_set_async(data, target); - target->sync_flag |= SDTR_DONE; - } - - nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, - "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n", - target->limit_entry, period, offset); - } else if (target->sync_flag & SDTR_INITIATOR) { - /* - * It was negotiating SDTR with target, sending from the - * initiator, but there are no chance to remove this flag. - * Set async because we don't get proper negotiation. - */ - nsp32_set_async(data, target); - target->sync_flag &= ~SDTR_INITIATOR; - target->sync_flag |= SDTR_DONE; - - nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, - "SDTR_INITIATOR: fall back to async"); - } else if (target->sync_flag & SDTR_TARGET) { - /* - * It was negotiating SDTR with target, sending from target, - * but there are no chance to remove this flag. Set async - * because we don't get proper negotiation. - */ - nsp32_set_async(data, target); - target->sync_flag &= ~SDTR_TARGET; - target->sync_flag |= SDTR_DONE; - - nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, - "Unknown SDTR from target is reached, fall back to async."); - } - - nsp32_dbg(NSP32_DEBUG_TARGETFLAG, - "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x", - SCpnt->device->id, target->sync_flag, target->syncreg, - target->ackwidth); - - /* Selection */ - if (auto_param == 0) { - ret = nsp32_selection_autopara(SCpnt); - } else { - ret = nsp32_selection_autoscsi(SCpnt); - } - - if (ret != TRUE) { - nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "selection fail"); - nsp32_scsi_done(SCpnt); - } - - return 0; -} - -static DEF_SCSI_QCMD(nsp32_queuecommand) - -/* initialize asic */ -static int nsp32hw_init(nsp32_hw_data *data) -{ - unsigned int base = data->BaseAddress; - unsigned short irq_stat; - unsigned long lc_reg; - unsigned char power; - - lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE); - if ((lc_reg & 0xff00) == 0) { - lc_reg |= (0x20 << 8); - nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff); - } - - nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); - nsp32_write2(base, TRANSFER_CONTROL, 0); - nsp32_write4(base, BM_CNT, 0); - nsp32_write2(base, SCSI_EXECUTE_PHASE, 0); - - do { - irq_stat = nsp32_read2(base, IRQ_STATUS); - nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat); - } while (irq_stat & IRQSTATUS_ANY_IRQ); - - /* - * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is - * designated by specification. - */ - if ((data->trans_method & NSP32_TRANSFER_PIO) || - (data->trans_method & NSP32_TRANSFER_MMIO)) { - nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x40); - nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x40); - } else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { - nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT, 0x10); - nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60); - } else { - nsp32_dbg(NSP32_DEBUG_INIT, "unknown transfer mode"); - } - - nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x", - nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT), - nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT)); - - nsp32_index_write1(base, CLOCK_DIV, data->clock); - nsp32_index_write1(base, BM_CYCLE, MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD); - nsp32_write1(base, PARITY_CONTROL, 0); /* parity check is disable */ - - /* - * initialize MISC_WRRD register - * - * Note: Designated parameters is obeyed as following: - * MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set. - * MISC_MASTER_TERMINATION_SELECT: It must be set. - * MISC_BMREQ_NEGATE_TIMING_SEL: It should be set. - * MISC_AUTOSEL_TIMING_SEL: It should be set. - * MISC_BMSTOP_CHANGE2_NONDATA_PHASE: It should be set. - * MISC_DELAYED_BMSTART: It's selected for safety. - * - * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then - * we have to set TRANSFERCONTROL_BM_START as 0 and set - * appropriate value before restarting bus master transfer. - */ - nsp32_index_write2(base, MISC_WR, - (SCSI_DIRECTION_DETECTOR_SELECT | - DELAYED_BMSTART | - MASTER_TERMINATION_SELECT | - BMREQ_NEGATE_TIMING_SEL | - AUTOSEL_TIMING_SEL | - BMSTOP_CHANGE2_NONDATA_PHASE)); - - nsp32_index_write1(base, TERM_PWR_CONTROL, 0); - power = nsp32_index_read1(base, TERM_PWR_CONTROL); - if (!(power & SENSE)) { - nsp32_msg(KERN_INFO, "term power on"); - nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR); - } - - nsp32_write2(base, TIMER_SET, TIMER_STOP); - nsp32_write2(base, TIMER_SET, TIMER_STOP); /* Required 2 times */ - - nsp32_write1(base, SYNC_REG, 0); - nsp32_write1(base, ACK_WIDTH, 0); - nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME); - - /* - * enable to select designated IRQ (except for - * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR) - */ - nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ | - IRQSELECT_SCSIRESET_IRQ | - IRQSELECT_FIFO_SHLD_IRQ | - IRQSELECT_RESELECT_IRQ | - IRQSELECT_PHASE_CHANGE_IRQ | - IRQSELECT_AUTO_SCSI_SEQ_IRQ | - // IRQSELECT_BMCNTERR_IRQ | - IRQSELECT_TARGET_ABORT_IRQ | - IRQSELECT_MASTER_ABORT_IRQ ); - nsp32_write2(base, IRQ_CONTROL, 0); - - /* PCI LED off */ - nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF); - nsp32_index_write1(base, EXT_PORT, LED_OFF); - - return TRUE; -} - - -/* interrupt routine */ -static irqreturn_t do_nsp32_isr(int irq, void *dev_id) -{ - nsp32_hw_data *data = dev_id; - unsigned int base = data->BaseAddress; - struct scsi_cmnd *SCpnt = data->CurrentSC; - unsigned short auto_stat, irq_stat, trans_stat; - unsigned char busmon, busphase; - unsigned long flags; - int ret; - int handled = 0; - struct Scsi_Host *host = data->Host; - - spin_lock_irqsave(host->host_lock, flags); - - /* - * IRQ check, then enable IRQ mask - */ - irq_stat = nsp32_read2(base, IRQ_STATUS); - nsp32_dbg(NSP32_DEBUG_INTR, - "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat); - /* is this interrupt comes from Ninja asic? */ - if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) { - nsp32_dbg(NSP32_DEBUG_INTR, "shared interrupt: irq other 0x%x", irq_stat); - goto out2; - } - handled = 1; - nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); - - busmon = nsp32_read1(base, SCSI_BUS_MONITOR); - busphase = busmon & BUSMON_PHASE_MASK; - - trans_stat = nsp32_read2(base, TRANSFER_STATUS); - if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) { - nsp32_msg(KERN_INFO, "card disconnect"); - if (data->CurrentSC != NULL) { - nsp32_msg(KERN_INFO, "clean up current SCSI command"); - SCpnt->result = DID_BAD_TARGET << 16; - nsp32_scsi_done(SCpnt); - } - goto out; - } - - /* Timer IRQ */ - if (irq_stat & IRQSTATUS_TIMER_IRQ) { - nsp32_dbg(NSP32_DEBUG_INTR, "timer stop"); - nsp32_write2(base, TIMER_SET, TIMER_STOP); - goto out; - } - - /* SCSI reset */ - if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) { - nsp32_msg(KERN_INFO, "detected someone do bus reset"); - nsp32_do_bus_reset(data); - if (SCpnt != NULL) { - SCpnt->result = DID_RESET << 16; - nsp32_scsi_done(SCpnt); - } - goto out; - } - - if (SCpnt == NULL) { - nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened"); - nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); - goto out; - } - - /* - * AutoSCSI Interrupt. - * Note: This interrupt is occurred when AutoSCSI is finished. Then - * check SCSIEXECUTEPHASE, and do appropriate action. Each phases are - * recorded when AutoSCSI sequencer has been processed. - */ - if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) { - /* getting SCSI executed phase */ - auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE); - nsp32_write2(base, SCSI_EXECUTE_PHASE, 0); - - /* Selection Timeout, go busfree phase. */ - if (auto_stat & SELECTION_TIMEOUT) { - nsp32_dbg(NSP32_DEBUG_INTR, - "selection timeout occurred"); - - SCpnt->result = DID_TIME_OUT << 16; - nsp32_scsi_done(SCpnt); - goto out; - } - - if (auto_stat & MSGOUT_PHASE) { - /* - * MsgOut phase was processed. - * If MSG_IN_OCCUER is not set, then MsgOut phase is - * completed. Thus, msgout_len must reset. Otherwise, - * nothing to do here. If MSG_OUT_OCCUER is occurred, - * then we will encounter the condition and check. - */ - if (!(auto_stat & MSG_IN_OCCUER) && - (data->msgout_len <= 3)) { - /* - * !MSG_IN_OCCUER && msgout_len <=3 - * ---> AutoSCSI with MSGOUTreg is processed. - */ - data->msgout_len = 0; - }; - - nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed"); - } - - if ((auto_stat & DATA_IN_PHASE) && - (scsi_get_resid(SCpnt) > 0) && - ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) { - printk( "auto+fifo\n"); - //nsp32_pio_read(SCpnt); - } - - if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) { - /* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */ - nsp32_dbg(NSP32_DEBUG_INTR, - "Data in/out phase processed"); - - /* read BMCNT, SGT pointer addr */ - nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx", - nsp32_read4(base, BM_CNT)); - nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx", - nsp32_read4(base, SGT_ADR)); - nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx", - nsp32_read4(base, SACK_CNT)); - nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", - nsp32_read4(base, SAVED_SACK_CNT)); - - scsi_set_resid(SCpnt, 0); /* all data transferred! */ - } - - /* - * MsgIn Occur - */ - if (auto_stat & MSG_IN_OCCUER) { - nsp32_msgin_occur(SCpnt, irq_stat, auto_stat); - } - - /* - * MsgOut Occur - */ - if (auto_stat & MSG_OUT_OCCUER) { - nsp32_msgout_occur(SCpnt); - } - - /* - * Bus Free Occur - */ - if (auto_stat & BUS_FREE_OCCUER) { - ret = nsp32_busfree_occur(SCpnt, auto_stat); - if (ret == TRUE) { - goto out; - } - } - - if (auto_stat & STATUS_PHASE) { - /* - * Read CSB and substitute CSB for SCpnt->result - * to save status phase stutas byte. - * scsi error handler checks host_byte (DID_*: - * low level driver to indicate status), then checks - * status_byte (SCSI status byte). - */ - SCpnt->result = (int)nsp32_read1(base, SCSI_CSB_IN); - } - - if (auto_stat & ILLEGAL_PHASE) { - /* Illegal phase is detected. SACK is not back. */ - nsp32_msg(KERN_WARNING, - "AUTO SCSI ILLEGAL PHASE OCCUR!!!!"); - - /* TODO: currently we don't have any action... bus reset? */ - - /* - * To send back SACK, assert, wait, and negate. - */ - nsp32_sack_assert(data); - nsp32_wait_req(data, NEGATE); - nsp32_sack_negate(data); - - } - - if (auto_stat & COMMAND_PHASE) { - /* nothing to do */ - nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed"); - } - - if (auto_stat & AUTOSCSI_BUSY) { - /* AutoSCSI is running */ - } - - show_autophase(auto_stat); - } - - /* FIFO_SHLD_IRQ */ - if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) { - nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ"); - - switch(busphase) { - case BUSPHASE_DATA_OUT: - nsp32_dbg(NSP32_DEBUG_INTR, "fifo/write"); - - //nsp32_pio_write(SCpnt); - - break; - - case BUSPHASE_DATA_IN: - nsp32_dbg(NSP32_DEBUG_INTR, "fifo/read"); - - //nsp32_pio_read(SCpnt); - - break; - - case BUSPHASE_STATUS: - nsp32_dbg(NSP32_DEBUG_INTR, "fifo/status"); - - SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); - - break; - default: - nsp32_dbg(NSP32_DEBUG_INTR, "fifo/other phase"); - nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); - show_busphase(busphase); - break; - } - - goto out; - } - - /* Phase Change IRQ */ - if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) { - nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ"); - - switch(busphase) { - case BUSPHASE_MESSAGE_IN: - nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in"); - nsp32_msgin_occur(SCpnt, irq_stat, 0); - break; - default: - nsp32_msg(KERN_WARNING, "phase chg/other phase?"); - nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n", - irq_stat, trans_stat); - show_busphase(busphase); - break; - } - goto out; - } - - /* PCI_IRQ */ - if (irq_stat & IRQSTATUS_PCI_IRQ) { - nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occurred"); - /* Do nothing */ - } - - /* BMCNTERR_IRQ */ - if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) { - nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! "); - /* - * TODO: To be implemented improving bus master - * transfer reliability when BMCNTERR is occurred in - * AutoSCSI phase described in specification. - */ - } - -#if 0 - nsp32_dbg(NSP32_DEBUG_INTR, - "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat); - show_busphase(busphase); -#endif - - out: - /* disable IRQ mask */ - nsp32_write2(base, IRQ_CONTROL, 0); - - out2: - spin_unlock_irqrestore(host->host_lock, flags); - - nsp32_dbg(NSP32_DEBUG_INTR, "exit"); - - return IRQ_RETVAL(handled); -} - -#undef SPRINTF -#define SPRINTF(args...) \ - do { \ - if(length > (pos - buffer)) { \ - pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \ - nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\ - } \ - } while(0) - -static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, char **start, - off_t offset, int length, int inout) -{ - char *pos = buffer; - int thislength; - unsigned long flags; - nsp32_hw_data *data; - int hostno; - unsigned int base; - unsigned char mode_reg; - int id, speed; - long model; - - /* Write is not supported, just return. */ - if (inout == TRUE) { - return -EINVAL; - } - - hostno = host->host_no; - data = (nsp32_hw_data *)host->hostdata; - base = host->io_port; - - SPRINTF("NinjaSCSI-32 status\n\n"); - SPRINTF("Driver version: %s, $Revision: 1.33 $\n", nsp32_release_version); - SPRINTF("SCSI host No.: %d\n", hostno); - SPRINTF("IRQ: %d\n", host->irq); - SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); - SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); - SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); - SPRINTF("Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff); - - mode_reg = nsp32_index_read1(base, CHIP_MODE); - model = data->pci_devid->driver_data; - -#ifdef CONFIG_PM - SPRINTF("Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no"); -#endif - SPRINTF("OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]); - - spin_lock_irqsave(&(data->Lock), flags); - SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); - spin_unlock_irqrestore(&(data->Lock), flags); - - - SPRINTF("SDTR status\n"); - for (id = 0; id < ARRAY_SIZE(data->target); id++) { - - SPRINTF("id %d: ", id); - - if (id == host->this_id) { - SPRINTF("----- NinjaSCSI-32 host adapter\n"); - continue; - } - - if (data->target[id].sync_flag == SDTR_DONE) { - if (data->target[id].period == 0 && - data->target[id].offset == ASYNC_OFFSET ) { - SPRINTF("async"); - } else { - SPRINTF(" sync"); - } - } else { - SPRINTF(" none"); - } - - if (data->target[id].period != 0) { - - speed = 1000000 / (data->target[id].period * 4); - - SPRINTF(" transfer %d.%dMB/s, offset %d", - speed / 1000, - speed % 1000, - data->target[id].offset - ); - } - SPRINTF("\n"); - } - - - thislength = pos - (buffer + offset); - - if(thislength < 0) { - *start = NULL; - return 0; - } - - - thislength = min(thislength, length); - *start = buffer + offset; - - return thislength; -} -#undef SPRINTF - - - -/* - * Reset parameters and call scsi_done for data->cur_lunt. - * Be careful setting SCpnt->result = DID_* before calling this function. - */ -static void nsp32_scsi_done(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = SCpnt->device->host->io_port; - - scsi_dma_unmap(SCpnt); - - /* - * clear TRANSFERCONTROL_BM_START - */ - nsp32_write2(base, TRANSFER_CONTROL, 0); - nsp32_write4(base, BM_CNT, 0); - - /* - * call scsi_done - */ - (*SCpnt->scsi_done)(SCpnt); - - /* - * reset parameters - */ - data->cur_lunt->SCpnt = NULL; - data->cur_lunt = NULL; - data->cur_target = NULL; - data->CurrentSC = NULL; -} - - -/* - * Bus Free Occur - * - * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase - * with ACK reply when below condition is matched: - * MsgIn 00: Command Complete. - * MsgIn 02: Save Data Pointer. - * MsgIn 04: Diconnect. - * In other case, unexpected BUSFREE is detected. - */ -static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = SCpnt->device->host->io_port; - - nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph); - show_autophase(execph); - - nsp32_write4(base, BM_CNT, 0); - nsp32_write2(base, TRANSFER_CONTROL, 0); - - /* - * MsgIn 02: Save Data Pointer - * - * VALID: - * Save Data Pointer is received. Adjust pointer. - * - * NO-VALID: - * SCSI-3 says if Save Data Pointer is not received, then we restart - * processing and we can't adjust any SCSI data pointer in next data - * phase. - */ - if (execph & MSGIN_02_VALID) { - nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid"); - - /* - * Check sack_cnt/saved_sack_cnt, then adjust sg table if - * needed. - */ - if (!(execph & MSGIN_00_VALID) && - ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) { - unsigned int sacklen, s_sacklen; - - /* - * Read SACK count and SAVEDSACK count, then compare. - */ - sacklen = nsp32_read4(base, SACK_CNT ); - s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); - - /* - * If SAVEDSACKCNT == 0, it means SavedDataPointer is - * come after data transferring. - */ - if (s_sacklen > 0) { - /* - * Comparing between sack and savedsack to - * check the condition of AutoMsgIn03. - * - * If they are same, set msgin03 == TRUE, - * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at - * reselection. On the other hand, if they - * aren't same, set msgin03 == FALSE, and - * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at - * reselection. - */ - if (sacklen != s_sacklen) { - data->cur_lunt->msgin03 = FALSE; - } else { - data->cur_lunt->msgin03 = TRUE; - } - - nsp32_adjust_busfree(SCpnt, s_sacklen); - } - } - - /* This value has not substitude with valid value yet... */ - //data->cur_lunt->save_datp = data->cur_datp; - } else { - /* - * no processing. - */ - } - - if (execph & MSGIN_03_VALID) { - /* MsgIn03 was valid to be processed. No need processing. */ - } - - /* - * target SDTR check - */ - if (data->cur_target->sync_flag & SDTR_INITIATOR) { - /* - * SDTR negotiation pulled by the initiator has not - * finished yet. Fall back to ASYNC mode. - */ - nsp32_set_async(data, data->cur_target); - data->cur_target->sync_flag &= ~SDTR_INITIATOR; - data->cur_target->sync_flag |= SDTR_DONE; - } else if (data->cur_target->sync_flag & SDTR_TARGET) { - /* - * SDTR negotiation pulled by the target has been - * negotiating. - */ - if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) { - /* - * If valid message is received, then - * negotiation is succeeded. - */ - } else { - /* - * On the contrary, if unexpected bus free is - * occurred, then negotiation is failed. Fall - * back to ASYNC mode. - */ - nsp32_set_async(data, data->cur_target); - } - data->cur_target->sync_flag &= ~SDTR_TARGET; - data->cur_target->sync_flag |= SDTR_DONE; - } - - /* - * It is always ensured by SCSI standard that initiator - * switches into Bus Free Phase after - * receiving message 00 (Command Complete), 04 (Disconnect). - * It's the reason that processing here is valid. - */ - if (execph & MSGIN_00_VALID) { - /* MsgIn 00: Command Complete */ - nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete"); - - SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); - SCpnt->SCp.Message = 0; - nsp32_dbg(NSP32_DEBUG_BUSFREE, - "normal end stat=0x%x resid=0x%x\n", - SCpnt->SCp.Status, scsi_get_resid(SCpnt)); - SCpnt->result = (DID_OK << 16) | - (SCpnt->SCp.Message << 8) | - (SCpnt->SCp.Status << 0); - nsp32_scsi_done(SCpnt); - /* All operation is done */ - return TRUE; - } else if (execph & MSGIN_04_VALID) { - /* MsgIn 04: Disconnect */ - SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN); - SCpnt->SCp.Message = 4; - - nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect"); - return TRUE; - } else { - /* Unexpected bus free */ - nsp32_msg(KERN_WARNING, "unexpected bus free occurred"); - - /* DID_ERROR? */ - //SCpnt->result = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0); - SCpnt->result = DID_ERROR << 16; - nsp32_scsi_done(SCpnt); - return TRUE; - } - return FALSE; -} - - -/* - * nsp32_adjust_busfree - adjusting SG table - * - * Note: This driver adjust the SG table using SCSI ACK - * counter instead of BMCNT counter! - */ -static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - int old_entry = data->cur_entry; - int new_entry; - int sg_num = data->cur_lunt->sg_num; - nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt; - unsigned int restlen, sentlen; - u32_le len, addr; - - nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", scsi_get_resid(SCpnt)); - - /* adjust saved SACK count with 4 byte start address boundary */ - s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3; - - /* - * calculate new_entry from sack count and each sgt[].len - * calculate the byte which is intent to send - */ - sentlen = 0; - for (new_entry = old_entry; new_entry < sg_num; new_entry++) { - sentlen += (le32_to_cpu(sgt[new_entry].len) & ~SGTEND); - if (sentlen > s_sacklen) { - break; - } - } - - /* all sgt is processed */ - if (new_entry == sg_num) { - goto last; - } - - if (sentlen == s_sacklen) { - /* XXX: confirm it's ok or not */ - /* In this case, it's ok because we are at - the head element of the sg. restlen is correctly calculated. */ - } - - /* calculate the rest length for transferring */ - restlen = sentlen - s_sacklen; - - /* update adjusting current SG table entry */ - len = le32_to_cpu(sgt[new_entry].len); - addr = le32_to_cpu(sgt[new_entry].addr); - addr += (len - restlen); - sgt[new_entry].addr = cpu_to_le32(addr); - sgt[new_entry].len = cpu_to_le32(restlen); - - /* set cur_entry with new_entry */ - data->cur_entry = new_entry; - - return; - - last: - if (scsi_get_resid(SCpnt) < sentlen) { - nsp32_msg(KERN_ERR, "resid underflow"); - } - - scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) - sentlen); - nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", scsi_get_resid(SCpnt)); - - /* update hostdata and lun */ - - return; -} - - -/* - * It's called MsgOut phase occur. - * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in - * message out phase. It, however, has more than 3 messages, - * HBA creates the interrupt and we have to process by hand. - */ -static void nsp32_msgout_occur(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = SCpnt->device->host->io_port; - //unsigned short command; - long new_sgtp; - int i; - - nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, - "enter: msgout_len: 0x%x", data->msgout_len); - - /* - * If MsgOut phase is occurred without having any - * message, then No_Operation is sent (SCSI-2). - */ - if (data->msgout_len == 0) { - nsp32_build_nop(SCpnt); - } - - /* - * Set SGTP ADDR current entry for restarting AUTOSCSI, - * because SGTP is incremented next point. - * There is few statement in the specification... - */ - new_sgtp = data->cur_lunt->sglun_paddr + - (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable)); - - /* - * send messages - */ - for (i = 0; i < data->msgout_len; i++) { - nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, - "%d : 0x%x", i, data->msgoutbuf[i]); - - /* - * Check REQ is asserted. - */ - nsp32_wait_req(data, ASSERT); - - if (i == (data->msgout_len - 1)) { - /* - * If the last message, set the AutoSCSI restart - * before send back the ack message. AutoSCSI - * restart automatically negate ATN signal. - */ - //command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02); - //nsp32_restart_autoscsi(SCpnt, command); - nsp32_write2(base, COMMAND_CONTROL, - (CLEAR_CDB_FIFO_POINTER | - AUTO_COMMAND_PHASE | - AUTOSCSI_RESTART | - AUTO_MSGIN_00_OR_04 | - AUTO_MSGIN_02 )); - } - /* - * Write data with SACK, then wait sack is - * automatically negated. - */ - nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]); - nsp32_wait_sack(data, NEGATE); - - nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n", - nsp32_read1(base, SCSI_BUS_MONITOR)); - }; - - data->msgout_len = 0; - - nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit"); -} - -/* - * Restart AutoSCSI - * - * Note: Restarting AutoSCSI needs set: - * SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL - */ -static void nsp32_restart_autoscsi(struct scsi_cmnd *SCpnt, unsigned short command) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = data->BaseAddress; - unsigned short transfer = 0; - - nsp32_dbg(NSP32_DEBUG_RESTART, "enter"); - - if (data->cur_target == NULL || data->cur_lunt == NULL) { - nsp32_msg(KERN_ERR, "Target or Lun is invalid"); - } - - /* - * set SYNC_REG - * Don't set BM_START_ADR before setting this register. - */ - nsp32_write1(base, SYNC_REG, data->cur_target->syncreg); - - /* - * set ACKWIDTH - */ - nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth); - - /* - * set SREQ hazard killer sampling rate - */ - nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg); - - /* - * set SGT ADDR (physical address) - */ - nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr); - - /* - * set TRANSFER CONTROL REG - */ - transfer = 0; - transfer |= (TRANSFER_GO | ALL_COUNTER_CLR); - if (data->trans_method & NSP32_TRANSFER_BUSMASTER) { - if (scsi_bufflen(SCpnt) > 0) { - transfer |= BM_START; - } - } else if (data->trans_method & NSP32_TRANSFER_MMIO) { - transfer |= CB_MMIO_MODE; - } else if (data->trans_method & NSP32_TRANSFER_PIO) { - transfer |= CB_IO_MODE; - } - nsp32_write2(base, TRANSFER_CONTROL, transfer); - - /* - * restart AutoSCSI - * - * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ? - */ - command |= (CLEAR_CDB_FIFO_POINTER | - AUTO_COMMAND_PHASE | - AUTOSCSI_RESTART ); - nsp32_write2(base, COMMAND_CONTROL, command); - - nsp32_dbg(NSP32_DEBUG_RESTART, "exit"); -} - - -/* - * cannot run automatically message in occur - */ -static void nsp32_msgin_occur(struct scsi_cmnd *SCpnt, - unsigned long irq_status, - unsigned short execph) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = SCpnt->device->host->io_port; - unsigned char msg; - unsigned char msgtype; - unsigned char newlun; - unsigned short command = 0; - int msgclear = TRUE; - long new_sgtp; - int ret; - - /* - * read first message - * Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure - * of Message-In have to be processed before sending back SCSI ACK. - */ - msg = nsp32_read1(base, SCSI_DATA_IN); - data->msginbuf[(unsigned char)data->msgin_len] = msg; - msgtype = data->msginbuf[0]; - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, - "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x", - data->msgin_len, msg, msgtype); - - /* - * TODO: We need checking whether bus phase is message in? - */ - - /* - * assert SCSI ACK - */ - nsp32_sack_assert(data); - - /* - * processing IDENTIFY - */ - if (msgtype & 0x80) { - if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) { - /* Invalid (non reselect) phase */ - goto reject; - } - - newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */ - ret = nsp32_reselection(SCpnt, newlun); - if (ret == TRUE) { - goto restart; - } else { - goto reject; - } - } - - /* - * processing messages except for IDENTIFY - * - * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO. - */ - switch (msgtype) { - /* - * 1-byte message - */ - case COMMAND_COMPLETE: - case DISCONNECT: - /* - * These messages should not be occurred. - * They should be processed on AutoSCSI sequencer. - */ - nsp32_msg(KERN_WARNING, - "unexpected message of AutoSCSI MsgIn: 0x%x", msg); - break; - - case RESTORE_POINTERS: - /* - * AutoMsgIn03 is disabled, and HBA gets this message. - */ - - if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) { - unsigned int s_sacklen; - - s_sacklen = nsp32_read4(base, SAVED_SACK_CNT); - if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) { - nsp32_adjust_busfree(SCpnt, s_sacklen); - } else { - /* No need to rewrite SGT */ - } - } - data->cur_lunt->msgin03 = FALSE; - - /* Update with the new value */ - - /* reset SACK/SavedACK counter (or ALL clear?) */ - nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); - - /* - * set new sg pointer - */ - new_sgtp = data->cur_lunt->sglun_paddr + - (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable)); - nsp32_write4(base, SGT_ADR, new_sgtp); - - break; - - case SAVE_POINTERS: - /* - * These messages should not be occurred. - * They should be processed on AutoSCSI sequencer. - */ - nsp32_msg (KERN_WARNING, - "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS"); - - break; - - case MESSAGE_REJECT: - /* If previous message_out is sending SDTR, and get - message_reject from target, SDTR negotiation is failed */ - if (data->cur_target->sync_flag & - (SDTR_INITIATOR | SDTR_TARGET)) { - /* - * Current target is negotiating SDTR, but it's - * failed. Fall back to async transfer mode, and set - * SDTR_DONE. - */ - nsp32_set_async(data, data->cur_target); - data->cur_target->sync_flag &= ~SDTR_INITIATOR; - data->cur_target->sync_flag |= SDTR_DONE; - - } - break; - - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* queue tag is not supported currently */ - nsp32_msg (KERN_WARNING, - "unsupported message: 0x%x", msgtype); - break; - - case INITIATE_RECOVERY: - /* staring ECA (Extended Contingent Allegiance) state. */ - /* This message is declined in SPI2 or later. */ - - goto reject; - - /* - * 2-byte message - */ - case SIMPLE_QUEUE_TAG: - case 0x23: - /* - * 0x23: Ignore_Wide_Residue is not declared in scsi.h. - * No support is needed. - */ - if (data->msgin_len >= 1) { - goto reject; - } - - /* current position is 1-byte of 2 byte */ - msgclear = FALSE; - - break; - - /* - * extended message - */ - case EXTENDED_MESSAGE: - if (data->msgin_len < 1) { - /* - * Current position does not reach 2-byte - * (2-byte is extended message length). - */ - msgclear = FALSE; - break; - } - - if ((data->msginbuf[1] + 1) > data->msgin_len) { - /* - * Current extended message has msginbuf[1] + 2 - * (msgin_len starts counting from 0, so buf[1] + 1). - * If current message position is not finished, - * continue receiving message. - */ - msgclear = FALSE; - break; - } - - /* - * Reach here means regular length of each type of - * extended messages. - */ - switch (data->msginbuf[2]) { - case EXTENDED_MODIFY_DATA_POINTER: - /* TODO */ - goto reject; /* not implemented yet */ - break; - - case EXTENDED_SDTR: - /* - * Exchange this message between initiator and target. - */ - if (data->msgin_len != EXTENDED_SDTR_LEN + 1) { - /* - * received inappropriate message. - */ - goto reject; - break; - } - - nsp32_analyze_sdtr(SCpnt); - - break; - - case EXTENDED_EXTENDED_IDENTIFY: - /* SCSI-I only, not supported. */ - goto reject; /* not implemented yet */ - - break; - - case EXTENDED_WDTR: - goto reject; /* not implemented yet */ - - break; - - default: - goto reject; - } - break; - - default: - goto reject; - } - - restart: - if (msgclear == TRUE) { - data->msgin_len = 0; - - /* - * If restarting AutoSCSI, but there are some message to out - * (msgout_len > 0), set AutoATN, and set SCSIMSGOUT as 0 - * (MV_VALID = 0). When commandcontrol is written with - * AutoSCSI restart, at the same time MsgOutOccur should be - * happened (however, such situation is really possible...?). - */ - if (data->msgout_len > 0) { - nsp32_write4(base, SCSI_MSG_OUT, 0); - command |= AUTO_ATN; - } - - /* - * restart AutoSCSI - * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed. - */ - command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02); - - /* - * If current msgin03 is TRUE, then flag on. - */ - if (data->cur_lunt->msgin03 == TRUE) { - command |= AUTO_MSGIN_03; - } - data->cur_lunt->msgin03 = FALSE; - } else { - data->msgin_len++; - } - - /* - * restart AutoSCSI - */ - nsp32_restart_autoscsi(SCpnt, command); - - /* - * wait SCSI REQ negate for REQ-ACK handshake - */ - nsp32_wait_req(data, NEGATE); - - /* - * negate SCSI ACK - */ - nsp32_sack_negate(data); - - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit"); - - return; - - reject: - nsp32_msg(KERN_WARNING, - "invalid or unsupported MessageIn, rejected. " - "current msg: 0x%x (len: 0x%x), processing msg: 0x%x", - msg, data->msgin_len, msgtype); - nsp32_build_reject(SCpnt); - data->msgin_len = 0; - - goto restart; -} - -/* - * - */ -static void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - nsp32_target *target = data->cur_target; - nsp32_sync_table *synct; - unsigned char get_period = data->msginbuf[3]; - unsigned char get_offset = data->msginbuf[4]; - int entry; - int syncnum; - - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter"); - - synct = data->synct; - syncnum = data->syncnum; - - /* - * If this inititor sent the SDTR message, then target responds SDTR, - * initiator SYNCREG, ACKWIDTH from SDTR parameter. - * Messages are not appropriate, then send back reject message. - * If initiator did not send the SDTR, but target sends SDTR, - * initiator calculator the appropriate parameter and send back SDTR. - */ - if (target->sync_flag & SDTR_INITIATOR) { - /* - * Initiator sent SDTR, the target responds and - * send back negotiation SDTR. - */ - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR"); - - target->sync_flag &= ~SDTR_INITIATOR; - target->sync_flag |= SDTR_DONE; - - /* - * offset: - */ - if (get_offset > SYNC_OFFSET) { - /* - * Negotiation is failed, the target send back - * unexpected offset value. - */ - goto reject; - } - - if (get_offset == ASYNC_OFFSET) { - /* - * Negotiation is succeeded, the target want - * to fall back into asynchronous transfer mode. - */ - goto async; - } - - /* - * period: - * Check whether sync period is too short. If too short, - * fall back to async mode. If it's ok, then investigate - * the received sync period. If sync period is acceptable - * between sync table start_period and end_period, then - * set this I_T nexus as sent offset and period. - * If it's not acceptable, send back reject and fall back - * to async mode. - */ - if (get_period < data->synct[0].period_num) { - /* - * Negotiation is failed, the target send back - * unexpected period value. - */ - goto reject; - } - - entry = nsp32_search_period_entry(data, target, get_period); - - if (entry < 0) { - /* - * Target want to use long period which is not - * acceptable NinjaSCSI-32Bi/UDE. - */ - goto reject; - } - - /* - * Set new sync table and offset in this I_T nexus. - */ - nsp32_set_sync_entry(data, target, entry, get_offset); - } else { - /* Target send SDTR to initiator. */ - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR"); - - target->sync_flag |= SDTR_INITIATOR; - - /* offset: */ - if (get_offset > SYNC_OFFSET) { - /* send back as SYNC_OFFSET */ - get_offset = SYNC_OFFSET; - } - - /* period: */ - if (get_period < data->synct[0].period_num) { - get_period = data->synct[0].period_num; - } - - entry = nsp32_search_period_entry(data, target, get_period); - - if (get_offset == ASYNC_OFFSET || entry < 0) { - nsp32_set_async(data, target); - nsp32_build_sdtr(SCpnt, 0, ASYNC_OFFSET); - } else { - nsp32_set_sync_entry(data, target, entry, get_offset); - nsp32_build_sdtr(SCpnt, get_period, get_offset); - } - } - - target->period = get_period; - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit"); - return; - - reject: - /* - * If the current message is unacceptable, send back to the target - * with reject message. - */ - nsp32_build_reject(SCpnt); - - async: - nsp32_set_async(data, target); /* set as ASYNC transfer mode */ - - target->period = 0; - nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async"); - return; -} - - -/* - * Search config entry number matched in sync_table from given - * target and speed period value. If failed to search, return negative value. - */ -static int nsp32_search_period_entry(nsp32_hw_data *data, - nsp32_target *target, - unsigned char period) -{ - int i; - - if (target->limit_entry >= data->syncnum) { - nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!"); - target->limit_entry = 0; - } - - for (i = target->limit_entry; i < data->syncnum; i++) { - if (period >= data->synct[i].start_period && - period <= data->synct[i].end_period) { - break; - } - } - - /* - * Check given period value is over the sync_table value. - * If so, return max value. - */ - if (i == data->syncnum) { - i = -1; - } - - return i; -} - - -/* - * target <-> initiator use ASYNC transfer - */ -static void nsp32_set_async(nsp32_hw_data *data, nsp32_target *target) -{ - unsigned char period = data->synct[target->limit_entry].period_num; - - target->offset = ASYNC_OFFSET; - target->period = 0; - target->syncreg = TO_SYNCREG(period, ASYNC_OFFSET); - target->ackwidth = 0; - target->sample_reg = 0; - - nsp32_dbg(NSP32_DEBUG_SYNC, "set async"); -} - - -/* - * target <-> initiator use maximum SYNC transfer - */ -static void nsp32_set_max_sync(nsp32_hw_data *data, - nsp32_target *target, - unsigned char *period, - unsigned char *offset) -{ - unsigned char period_num, ackwidth; - - period_num = data->synct[target->limit_entry].period_num; - *period = data->synct[target->limit_entry].start_period; - ackwidth = data->synct[target->limit_entry].ackwidth; - *offset = SYNC_OFFSET; - - target->syncreg = TO_SYNCREG(period_num, *offset); - target->ackwidth = ackwidth; - target->offset = *offset; - target->sample_reg = 0; /* disable SREQ sampling */ -} - - -/* - * target <-> initiator use entry number speed - */ -static void nsp32_set_sync_entry(nsp32_hw_data *data, - nsp32_target *target, - int entry, - unsigned char offset) -{ - unsigned char period, ackwidth, sample_rate; - - period = data->synct[entry].period_num; - ackwidth = data->synct[entry].ackwidth; - offset = offset; - sample_rate = data->synct[entry].sample_rate; - - target->syncreg = TO_SYNCREG(period, offset); - target->ackwidth = ackwidth; - target->offset = offset; - target->sample_reg = sample_rate | SAMPLING_ENABLE; - - nsp32_dbg(NSP32_DEBUG_SYNC, "set sync"); -} - - -/* - * It waits until SCSI REQ becomes assertion or negation state. - * - * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then - * connected target responds SCSI REQ negation. We have to wait - * SCSI REQ becomes negation in order to negate SCSI ACK signal for - * REQ-ACK handshake. - */ -static void nsp32_wait_req(nsp32_hw_data *data, int state) -{ - unsigned int base = data->BaseAddress; - int wait_time = 0; - unsigned char bus, req_bit; - - if (!((state == ASSERT) || (state == NEGATE))) { - nsp32_msg(KERN_ERR, "unknown state designation"); - } - /* REQ is BIT(5) */ - req_bit = (state == ASSERT ? BUSMON_REQ : 0); - - do { - bus = nsp32_read1(base, SCSI_BUS_MONITOR); - if ((bus & BUSMON_REQ) == req_bit) { - nsp32_dbg(NSP32_DEBUG_WAIT, - "wait_time: %d", wait_time); - return; - } - udelay(1); - wait_time++; - } while (wait_time < REQSACK_TIMEOUT_TIME); - - nsp32_msg(KERN_WARNING, "wait REQ timeout, req_bit: 0x%x", req_bit); -} - -/* - * It waits until SCSI SACK becomes assertion or negation state. - */ -static void nsp32_wait_sack(nsp32_hw_data *data, int state) -{ - unsigned int base = data->BaseAddress; - int wait_time = 0; - unsigned char bus, ack_bit; - - if (!((state == ASSERT) || (state == NEGATE))) { - nsp32_msg(KERN_ERR, "unknown state designation"); - } - /* ACK is BIT(4) */ - ack_bit = (state == ASSERT ? BUSMON_ACK : 0); - - do { - bus = nsp32_read1(base, SCSI_BUS_MONITOR); - if ((bus & BUSMON_ACK) == ack_bit) { - nsp32_dbg(NSP32_DEBUG_WAIT, - "wait_time: %d", wait_time); - return; - } - udelay(1); - wait_time++; - } while (wait_time < REQSACK_TIMEOUT_TIME); - - nsp32_msg(KERN_WARNING, "wait SACK timeout, ack_bit: 0x%x", ack_bit); -} - -/* - * assert SCSI ACK - * - * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1. - */ -static void nsp32_sack_assert(nsp32_hw_data *data) -{ - unsigned int base = data->BaseAddress; - unsigned char busctrl; - - busctrl = nsp32_read1(base, SCSI_BUS_CONTROL); - busctrl |= (BUSCTL_ACK | AUTODIRECTION | ACKENB); - nsp32_write1(base, SCSI_BUS_CONTROL, busctrl); -} - -/* - * negate SCSI ACK - */ -static void nsp32_sack_negate(nsp32_hw_data *data) -{ - unsigned int base = data->BaseAddress; - unsigned char busctrl; - - busctrl = nsp32_read1(base, SCSI_BUS_CONTROL); - busctrl &= ~BUSCTL_ACK; - nsp32_write1(base, SCSI_BUS_CONTROL, busctrl); -} - - - -/* - * Note: n_io_port is defined as 0x7f because I/O register port is - * assigned as: - * 0x800-0x8ff: memory mapped I/O port - * 0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly) - * 0xc00-0xfff: CardBus status registers - */ -static int nsp32_detect(struct pci_dev *pdev) -{ - struct Scsi_Host *host; /* registered host structure */ - struct resource *res; - nsp32_hw_data *data; - int ret; - int i, j; - - nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); - - /* - * register this HBA as SCSI device - */ - host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data)); - if (host == NULL) { - nsp32_msg (KERN_ERR, "failed to scsi register"); - goto err; - } - - /* - * set nsp32_hw_data - */ - data = (nsp32_hw_data *)host->hostdata; - - memcpy(data, &nsp32_data_base, sizeof(nsp32_hw_data)); - - host->irq = data->IrqNumber; - host->io_port = data->BaseAddress; - host->unique_id = data->BaseAddress; - host->n_io_port = data->NumAddress; - host->base = (unsigned long)data->MmioAddress; - - data->Host = host; - spin_lock_init(&(data->Lock)); - - data->cur_lunt = NULL; - data->cur_target = NULL; - - /* - * Bus master transfer mode is supported currently. - */ - data->trans_method = NSP32_TRANSFER_BUSMASTER; - - /* - * Set clock div, CLOCK_4 (HBA has own external clock, and - * dividing * 100ns/4). - * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet. - */ - data->clock = CLOCK_4; - - /* - * Select appropriate nsp32_sync_table and set I_CLOCKDIV. - */ - switch (data->clock) { - case CLOCK_4: - /* If data->clock is CLOCK_4, then select 40M sync table. */ - data->synct = nsp32_sync_table_40M; - data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M); - break; - case CLOCK_2: - /* If data->clock is CLOCK_2, then select 20M sync table. */ - data->synct = nsp32_sync_table_20M; - data->syncnum = ARRAY_SIZE(nsp32_sync_table_20M); - break; - case PCICLK: - /* If data->clock is PCICLK, then select pci sync table. */ - data->synct = nsp32_sync_table_pci; - data->syncnum = ARRAY_SIZE(nsp32_sync_table_pci); - break; - default: - nsp32_msg(KERN_WARNING, - "Invalid clock div is selected, set CLOCK_4."); - /* Use default value CLOCK_4 */ - data->clock = CLOCK_4; - data->synct = nsp32_sync_table_40M; - data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M); - } - - /* - * setup nsp32_lunt - */ - - /* - * setup DMA - */ - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { - nsp32_msg (KERN_ERR, "failed to set PCI DMA mask"); - goto scsi_unregister; - } - - /* - * allocate autoparam DMA resource. - */ - data->autoparam = pci_alloc_consistent(pdev, sizeof(nsp32_autoparam), &(data->auto_paddr)); - if (data->autoparam == NULL) { - nsp32_msg(KERN_ERR, "failed to allocate DMA memory"); - goto scsi_unregister; - } - - /* - * allocate scatter-gather DMA resource. - */ - data->sg_list = pci_alloc_consistent(pdev, NSP32_SG_TABLE_SIZE, - &(data->sg_paddr)); - if (data->sg_list == NULL) { - nsp32_msg(KERN_ERR, "failed to allocate DMA memory"); - goto free_autoparam; - } - - for (i = 0; i < ARRAY_SIZE(data->lunt); i++) { - for (j = 0; j < ARRAY_SIZE(data->lunt[0]); j++) { - int offset = i * ARRAY_SIZE(data->lunt[0]) + j; - nsp32_lunt tmp = { - .SCpnt = NULL, - .save_datp = 0, - .msgin03 = FALSE, - .sg_num = 0, - .cur_entry = 0, - .sglun = &(data->sg_list[offset]), - .sglun_paddr = data->sg_paddr + (offset * sizeof(nsp32_sglun)), - }; - - data->lunt[i][j] = tmp; - } - } - - /* - * setup target - */ - for (i = 0; i < ARRAY_SIZE(data->target); i++) { - nsp32_target *target = &(data->target[i]); - - target->limit_entry = 0; - target->sync_flag = 0; - nsp32_set_async(data, target); - } - - /* - * EEPROM check - */ - ret = nsp32_getprom_param(data); - if (ret == FALSE) { - data->resettime = 3; /* default 3 */ - } - - /* - * setup HBA - */ - nsp32hw_init(data); - - snprintf(data->info_str, sizeof(data->info_str), - "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x", - host->irq, host->io_port, host->n_io_port); - - /* - * SCSI bus reset - * - * Note: It's important to reset SCSI bus in initialization phase. - * NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when - * system is coming up, so SCSI devices connected to HBA is set as - * un-asynchronous mode. It brings the merit that this HBA is - * ready to start synchronous transfer without any preparation, - * but we are difficult to control transfer speed. In addition, - * it prevents device transfer speed from effecting EEPROM start-up - * SDTR. NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as - * Auto Mode, then FAST-10M is selected when SCSI devices are - * connected same or more than 4 devices. It should be avoided - * depending on this specification. Thus, resetting the SCSI bus - * restores all connected SCSI devices to asynchronous mode, then - * this driver set SDTR safely later, and we can control all SCSI - * device transfer mode. - */ - nsp32_do_bus_reset(data); - - ret = request_irq(host->irq, do_nsp32_isr, IRQF_SHARED, "nsp32", data); - if (ret < 0) { - nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 " - "SCSI PCI controller. Interrupt: %d", host->irq); - goto free_sg_list; - } - - /* - * PCI IO register - */ - res = request_region(host->io_port, host->n_io_port, "nsp32"); - if (res == NULL) { - nsp32_msg(KERN_ERR, - "I/O region 0x%lx+0x%lx is already used", - data->BaseAddress, data->NumAddress); - goto free_irq; - } - - ret = scsi_add_host(host, &pdev->dev); - if (ret) { - nsp32_msg(KERN_ERR, "failed to add scsi host"); - goto free_region; - } - scsi_scan_host(host); - pci_set_drvdata(pdev, host); - return 0; - - free_region: - release_region(host->io_port, host->n_io_port); - - free_irq: - free_irq(host->irq, data); - - free_sg_list: - pci_free_consistent(pdev, NSP32_SG_TABLE_SIZE, - data->sg_list, data->sg_paddr); - - free_autoparam: - pci_free_consistent(pdev, sizeof(nsp32_autoparam), - data->autoparam, data->auto_paddr); - - scsi_unregister: - scsi_host_put(host); - - err: - return 1; -} - -static int nsp32_release(struct Scsi_Host *host) -{ - nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; - - if (data->autoparam) { - pci_free_consistent(data->Pci, sizeof(nsp32_autoparam), - data->autoparam, data->auto_paddr); - } - - if (data->sg_list) { - pci_free_consistent(data->Pci, NSP32_SG_TABLE_SIZE, - data->sg_list, data->sg_paddr); - } - - if (host->irq) { - free_irq(host->irq, data); - } - - if (host->io_port && host->n_io_port) { - release_region(host->io_port, host->n_io_port); - } - - if (data->MmioAddress) { - iounmap(data->MmioAddress); - } - - return 0; -} - -static const char *nsp32_info(struct Scsi_Host *shpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata; - - return data->info_str; -} - - -/**************************************************************************** - * error handler - */ -static int nsp32_eh_abort(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = SCpnt->device->host->io_port; - - nsp32_msg(KERN_WARNING, "abort"); - - if (data->cur_lunt->SCpnt == NULL) { - nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort failed"); - return FAILED; - } - - if (data->cur_target->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) { - /* reset SDTR negotiation */ - data->cur_target->sync_flag = 0; - nsp32_set_async(data, data->cur_target); - } - - nsp32_write2(base, TRANSFER_CONTROL, 0); - nsp32_write2(base, BM_CNT, 0); - - SCpnt->result = DID_ABORT << 16; - nsp32_scsi_done(SCpnt); - - nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort success"); - return SUCCESS; -} - -static int nsp32_eh_bus_reset(struct scsi_cmnd *SCpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata; - unsigned int base = SCpnt->device->host->io_port; - - spin_lock_irq(SCpnt->device->host->host_lock); - - nsp32_msg(KERN_INFO, "Bus Reset"); - nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt); - - nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); - nsp32_do_bus_reset(data); - nsp32_write2(base, IRQ_CONTROL, 0); - - spin_unlock_irq(SCpnt->device->host->host_lock); - return SUCCESS; /* SCSI bus reset is succeeded at any time. */ -} - -static void nsp32_do_bus_reset(nsp32_hw_data *data) -{ - unsigned int base = data->BaseAddress; - unsigned short intrdat; - int i; - - nsp32_dbg(NSP32_DEBUG_BUSRESET, "in"); - - /* - * stop all transfer - * clear TRANSFERCONTROL_BM_START - * clear counter - */ - nsp32_write2(base, TRANSFER_CONTROL, 0); - nsp32_write4(base, BM_CNT, 0); - nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK); - - /* - * fall back to asynchronous transfer mode - * initialize SDTR negotiation flag - */ - for (i = 0; i < ARRAY_SIZE(data->target); i++) { - nsp32_target *target = &data->target[i]; - - target->sync_flag = 0; - nsp32_set_async(data, target); - } - - /* - * reset SCSI bus - */ - nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST); - udelay(RESET_HOLD_TIME); - nsp32_write1(base, SCSI_BUS_CONTROL, 0); - for(i = 0; i < 5; i++) { - intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */ - nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat); - } - - data->CurrentSC = NULL; -} - -static int nsp32_eh_host_reset(struct scsi_cmnd *SCpnt) -{ - struct Scsi_Host *host = SCpnt->device->host; - unsigned int base = SCpnt->device->host->io_port; - nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; - - nsp32_msg(KERN_INFO, "Host Reset"); - nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt); - - spin_lock_irq(SCpnt->device->host->host_lock); - - nsp32hw_init(data); - nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK); - nsp32_do_bus_reset(data); - nsp32_write2(base, IRQ_CONTROL, 0); - - spin_unlock_irq(SCpnt->device->host->host_lock); - return SUCCESS; /* Host reset is succeeded at any time. */ -} - - -/************************************************************************** - * EEPROM handler - */ - -/* - * getting EEPROM parameter - */ -static int nsp32_getprom_param(nsp32_hw_data *data) -{ - int vendor = data->pci_devid->vendor; - int device = data->pci_devid->device; - int ret, val, i; - - /* - * EEPROM checking. - */ - ret = nsp32_prom_read(data, 0x7e); - if (ret != 0x55) { - nsp32_msg(KERN_INFO, "No EEPROM detected: 0x%x", ret); - return FALSE; - } - ret = nsp32_prom_read(data, 0x7f); - if (ret != 0xaa) { - nsp32_msg(KERN_INFO, "Invalid number: 0x%x", ret); - return FALSE; - } - - /* - * check EEPROM type - */ - if (vendor == PCI_VENDOR_ID_WORKBIT && - device == PCI_DEVICE_ID_WORKBIT_STANDARD) { - ret = nsp32_getprom_c16(data); - } else if (vendor == PCI_VENDOR_ID_WORKBIT && - device == PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC) { - ret = nsp32_getprom_at24(data); - } else if (vendor == PCI_VENDOR_ID_WORKBIT && - device == PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO ) { - ret = nsp32_getprom_at24(data); - } else { - nsp32_msg(KERN_WARNING, "Unknown EEPROM"); - ret = FALSE; - } - - /* for debug : SPROM data full checking */ - for (i = 0; i <= 0x1f; i++) { - val = nsp32_prom_read(data, i); - nsp32_dbg(NSP32_DEBUG_EEPROM, - "rom address 0x%x : 0x%x", i, val); - } - - return ret; -} - - -/* - * AT24C01A (Logitec: LHA-600S), AT24C02 (Melco Buffalo: IFC-USLP) data map: - * - * ROMADDR - * 0x00 - 0x06 : Device Synchronous Transfer Period (SCSI ID 0 - 6) - * Value 0x0: ASYNC, 0x0c: Ultra-20M, 0x19: Fast-10M - * 0x07 : HBA Synchronous Transfer Period - * Value 0: AutoSync, 1: Manual Setting - * 0x08 - 0x0f : Not Used? (0x0) - * 0x10 : Bus Termination - * Value 0: Auto[ON], 1: ON, 2: OFF - * 0x11 : Not Used? (0) - * 0x12 : Bus Reset Delay Time (0x03) - * 0x13 : Bootable CD Support - * Value 0: Disable, 1: Enable - * 0x14 : Device Scan - * Bit 7 6 5 4 3 2 1 0 - * | <-----------------> - * | SCSI ID: Value 0: Skip, 1: YES - * |-> Value 0: ALL scan, Value 1: Manual - * 0x15 - 0x1b : Not Used? (0) - * 0x1c : Constant? (0x01) (clock div?) - * 0x1d - 0x7c : Not Used (0xff) - * 0x7d : Not Used? (0xff) - * 0x7e : Constant (0x55), Validity signature - * 0x7f : Constant (0xaa), Validity signature - */ -static int nsp32_getprom_at24(nsp32_hw_data *data) -{ - int ret, i; - int auto_sync; - nsp32_target *target; - int entry; - - /* - * Reset time which is designated by EEPROM. - * - * TODO: Not used yet. - */ - data->resettime = nsp32_prom_read(data, 0x12); - - /* - * HBA Synchronous Transfer Period - * - * Note: auto_sync = 0: auto, 1: manual. Ninja SCSI HBA spec says - * that if auto_sync is 0 (auto), and connected SCSI devices are - * same or lower than 3, then transfer speed is set as ULTRA-20M. - * On the contrary if connected SCSI devices are same or higher - * than 4, then transfer speed is set as FAST-10M. - * - * I break this rule. The number of connected SCSI devices are - * only ignored. If auto_sync is 0 (auto), then transfer speed is - * forced as ULTRA-20M. - */ - ret = nsp32_prom_read(data, 0x07); - switch (ret) { - case 0: - auto_sync = TRUE; - break; - case 1: - auto_sync = FALSE; - break; - default: - nsp32_msg(KERN_WARNING, - "Unsupported Auto Sync mode. Fall back to manual mode."); - auto_sync = TRUE; - } - - if (trans_mode == ULTRA20M_MODE) { - auto_sync = TRUE; - } - - /* - * each device Synchronous Transfer Period - */ - for (i = 0; i < NSP32_HOST_SCSIID; i++) { - target = &data->target[i]; - if (auto_sync == TRUE) { - target->limit_entry = 0; /* set as ULTRA20M */ - } else { - ret = nsp32_prom_read(data, i); - entry = nsp32_search_period_entry(data, target, ret); - if (entry < 0) { - /* search failed... set maximum speed */ - entry = 0; - } - target->limit_entry = entry; - } - } - - return TRUE; -} - - -/* - * C16 110 (I-O Data: SC-NBD) data map: - * - * ROMADDR - * 0x00 - 0x06 : Device Synchronous Transfer Period (SCSI ID 0 - 6) - * Value 0x0: 20MB/S, 0x1: 10MB/S, 0x2: 5MB/S, 0x3: ASYNC - * 0x07 : 0 (HBA Synchronous Transfer Period: Auto Sync) - * 0x08 - 0x0f : Not Used? (0x0) - * 0x10 : Transfer Mode - * Value 0: PIO, 1: Busmater - * 0x11 : Bus Reset Delay Time (0x00-0x20) - * 0x12 : Bus Termination - * Value 0: Disable, 1: Enable - * 0x13 - 0x19 : Disconnection - * Value 0: Disable, 1: Enable - * 0x1a - 0x7c : Not Used? (0) - * 0x7d : Not Used? (0xf8) - * 0x7e : Constant (0x55), Validity signature - * 0x7f : Constant (0xaa), Validity signature - */ -static int nsp32_getprom_c16(nsp32_hw_data *data) -{ - int ret, i; - nsp32_target *target; - int entry, val; - - /* - * Reset time which is designated by EEPROM. - * - * TODO: Not used yet. - */ - data->resettime = nsp32_prom_read(data, 0x11); - - /* - * each device Synchronous Transfer Period - */ - for (i = 0; i < NSP32_HOST_SCSIID; i++) { - target = &data->target[i]; - ret = nsp32_prom_read(data, i); - switch (ret) { - case 0: /* 20MB/s */ - val = 0x0c; - break; - case 1: /* 10MB/s */ - val = 0x19; - break; - case 2: /* 5MB/s */ - val = 0x32; - break; - case 3: /* ASYNC */ - val = 0x00; - break; - default: /* default 20MB/s */ - val = 0x0c; - break; - } - entry = nsp32_search_period_entry(data, target, val); - if (entry < 0 || trans_mode == ULTRA20M_MODE) { - /* search failed... set maximum speed */ - entry = 0; - } - target->limit_entry = entry; - } - - return TRUE; -} - - -/* - * Atmel AT24C01A (drived in 5V) serial EEPROM routines - */ -static int nsp32_prom_read(nsp32_hw_data *data, int romaddr) -{ - int i, val; - - /* start condition */ - nsp32_prom_start(data); - - /* device address */ - nsp32_prom_write_bit(data, 1); /* 1 */ - nsp32_prom_write_bit(data, 0); /* 0 */ - nsp32_prom_write_bit(data, 1); /* 1 */ - nsp32_prom_write_bit(data, 0); /* 0 */ - nsp32_prom_write_bit(data, 0); /* A2: 0 (GND) */ - nsp32_prom_write_bit(data, 0); /* A1: 0 (GND) */ - nsp32_prom_write_bit(data, 0); /* A0: 0 (GND) */ - - /* R/W: W for dummy write */ - nsp32_prom_write_bit(data, 0); - - /* ack */ - nsp32_prom_write_bit(data, 0); - - /* word address */ - for (i = 7; i >= 0; i--) { - nsp32_prom_write_bit(data, ((romaddr >> i) & 1)); - } - - /* ack */ - nsp32_prom_write_bit(data, 0); - - /* start condition */ - nsp32_prom_start(data); - - /* device address */ - nsp32_prom_write_bit(data, 1); /* 1 */ - nsp32_prom_write_bit(data, 0); /* 0 */ - nsp32_prom_write_bit(data, 1); /* 1 */ - nsp32_prom_write_bit(data, 0); /* 0 */ - nsp32_prom_write_bit(data, 0); /* A2: 0 (GND) */ - nsp32_prom_write_bit(data, 0); /* A1: 0 (GND) */ - nsp32_prom_write_bit(data, 0); /* A0: 0 (GND) */ - - /* R/W: R */ - nsp32_prom_write_bit(data, 1); - - /* ack */ - nsp32_prom_write_bit(data, 0); - - /* data... */ - val = 0; - for (i = 7; i >= 0; i--) { - val += (nsp32_prom_read_bit(data) << i); - } - - /* no ack */ - nsp32_prom_write_bit(data, 1); - - /* stop condition */ - nsp32_prom_stop(data); - - return val; -} - -static void nsp32_prom_set(nsp32_hw_data *data, int bit, int val) -{ - int base = data->BaseAddress; - int tmp; - - tmp = nsp32_index_read1(base, SERIAL_ROM_CTL); - - if (val == 0) { - tmp &= ~bit; - } else { - tmp |= bit; - } - - nsp32_index_write1(base, SERIAL_ROM_CTL, tmp); - - udelay(10); -} - -static int nsp32_prom_get(nsp32_hw_data *data, int bit) -{ - int base = data->BaseAddress; - int tmp, ret; - - if (bit != SDA) { - nsp32_msg(KERN_ERR, "return value is not appropriate"); - return 0; - } - - - tmp = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit; - - if (tmp == 0) { - ret = 0; - } else { - ret = 1; - } - - udelay(10); - - return ret; -} - -static void nsp32_prom_start (nsp32_hw_data *data) -{ - /* start condition */ - nsp32_prom_set(data, SCL, 1); - nsp32_prom_set(data, SDA, 1); - nsp32_prom_set(data, ENA, 1); /* output mode */ - nsp32_prom_set(data, SDA, 0); /* keeping SCL=1 and transiting - * SDA 1->0 is start condition */ - nsp32_prom_set(data, SCL, 0); -} - -static void nsp32_prom_stop (nsp32_hw_data *data) -{ - /* stop condition */ - nsp32_prom_set(data, SCL, 1); - nsp32_prom_set(data, SDA, 0); - nsp32_prom_set(data, ENA, 1); /* output mode */ - nsp32_prom_set(data, SDA, 1); - nsp32_prom_set(data, SCL, 0); -} - -static void nsp32_prom_write_bit(nsp32_hw_data *data, int val) -{ - /* write */ - nsp32_prom_set(data, SDA, val); - nsp32_prom_set(data, SCL, 1 ); - nsp32_prom_set(data, SCL, 0 ); -} - -static int nsp32_prom_read_bit(nsp32_hw_data *data) -{ - int val; - - /* read */ - nsp32_prom_set(data, ENA, 0); /* input mode */ - nsp32_prom_set(data, SCL, 1); - - val = nsp32_prom_get(data, SDA); - - nsp32_prom_set(data, SCL, 0); - nsp32_prom_set(data, ENA, 1); /* output mode */ - - return val; -} - - -/************************************************************************** - * Power Management - */ -#ifdef CONFIG_PM - -/* Device suspended */ -static int nsp32_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - - nsp32_msg(KERN_INFO, "pci-suspend: pdev=0x%p, state=%ld, slot=%s, host=0x%p", pdev, state, pci_name(pdev), host); - - pci_save_state (pdev); - pci_disable_device (pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -/* Device woken up */ -static int nsp32_resume(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata; - unsigned short reg; - - nsp32_msg(KERN_INFO, "pci-resume: pdev=0x%p, slot=%s, host=0x%p", pdev, pci_name(pdev), host); - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake (pdev, PCI_D0, 0); - pci_restore_state (pdev); - - reg = nsp32_read2(data->BaseAddress, INDEX_REG); - - nsp32_msg(KERN_INFO, "io=0x%x reg=0x%x", data->BaseAddress, reg); - - if (reg == 0xffff) { - nsp32_msg(KERN_INFO, "missing device. abort resume."); - return 0; - } - - nsp32hw_init (data); - nsp32_do_bus_reset(data); - - nsp32_msg(KERN_INFO, "resume success"); - - return 0; -} - -#endif - -/************************************************************************ - * PCI/Cardbus probe/remove routine - */ -static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int ret; - nsp32_hw_data *data = &nsp32_data_base; - - nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); - - ret = pci_enable_device(pdev); - if (ret) { - nsp32_msg(KERN_ERR, "failed to enable pci device"); - return ret; - } - - data->Pci = pdev; - data->pci_devid = id; - data->IrqNumber = pdev->irq; - data->BaseAddress = pci_resource_start(pdev, 0); - data->NumAddress = pci_resource_len (pdev, 0); - data->MmioAddress = pci_ioremap_bar(pdev, 1); - data->MmioLength = pci_resource_len (pdev, 1); - - pci_set_master(pdev); - - ret = nsp32_detect(pdev); - - nsp32_msg(KERN_INFO, "irq: %i mmio: %p+0x%lx slot: %s model: %s", - pdev->irq, - data->MmioAddress, data->MmioLength, - pci_name(pdev), - nsp32_model[id->driver_data]); - - nsp32_dbg(NSP32_DEBUG_REGISTER, "exit %d", ret); - - return ret; -} - -static void __devexit nsp32_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - - nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); - - scsi_remove_host(host); - - nsp32_release(host); - - scsi_host_put(host); -} - -static struct pci_driver nsp32_driver = { - .name = "nsp32", - .id_table = nsp32_pci_table, - .probe = nsp32_probe, - .remove = __devexit_p(nsp32_remove), -#ifdef CONFIG_PM - .suspend = nsp32_suspend, - .resume = nsp32_resume, -#endif -}; - -/********************************************************************* - * Moule entry point - */ -static int __init init_nsp32(void) { - nsp32_msg(KERN_INFO, "loading..."); - return pci_register_driver(&nsp32_driver); -} - -static void __exit exit_nsp32(void) { - nsp32_msg(KERN_INFO, "unloading..."); - pci_unregister_driver(&nsp32_driver); -} - -module_init(init_nsp32); -module_exit(exit_nsp32); - -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/nsp32.h b/ANDROID_3.4.5/drivers/scsi/nsp32.h deleted file mode 100644 index c0221829..00000000 --- a/ANDROID_3.4.5/drivers/scsi/nsp32.h +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver - * Basic data header - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. -*/ - -#ifndef _NSP32_H -#define _NSP32_H - -//#define NSP32_DEBUG 9 - -/* - * VENDOR/DEVICE ID - */ -#define PCI_VENDOR_ID_IODATA 0x10fc -#define PCI_VENDOR_ID_WORKBIT 0x1145 - -#define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II 0x0005 -#define PCI_DEVICE_ID_NINJASCSI_32BI_KME 0xf007 -#define PCI_DEVICE_ID_NINJASCSI_32BI_WBT 0x8007 -#define PCI_DEVICE_ID_WORKBIT_STANDARD 0xf010 -#define PCI_DEVICE_ID_WORKBIT_DUALEDGE 0xf011 -#define PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC 0xf012 -#define PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC 0xf013 -#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO 0xf015 -#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II 0x8009 - -/* - * MODEL - */ -enum { - MODEL_IODATA = 0, - MODEL_KME = 1, - MODEL_WORKBIT = 2, - MODEL_LOGITEC = 3, - MODEL_PCI_WORKBIT = 4, - MODEL_PCI_LOGITEC = 5, - MODEL_PCI_MELCO = 6, -}; - -static char * nsp32_model[] = { - "I-O DATA CBSC-II CardBus card", - "KME SCSI CardBus card", - "Workbit duo SCSI CardBus card", - "Logitec CardBus card with external ROM", - "Workbit / I-O DATA PCI card", - "Logitec PCI card with external ROM", - "Melco CardBus/PCI card with external ROM", -}; - - -/* - * SCSI Generic Definitions - */ -#define EXTENDED_SDTR_LEN 0x03 - -/* Little Endian */ -typedef u32 u32_le; -typedef u16 u16_le; - -/* - * BASIC Definitions - */ -#ifndef TRUE -# define TRUE 1 -#endif -#ifndef FALSE -# define FALSE 0 -#endif -#define ASSERT 1 -#define NEGATE 0 - - -/*******************/ -/* normal register */ -/*******************/ -/* - * Don't access below register with Double Word: - * +00, +04, +08, +0c, +64, +80, +84, +88, +90, +c4, +c8, +cc, +d0. - */ -#define IRQ_CONTROL 0x00 /* BASE+00, W, W */ -#define IRQ_STATUS 0x00 /* BASE+00, W, R */ -# define IRQSTATUS_LATCHED_MSG BIT(0) -# define IRQSTATUS_LATCHED_IO BIT(1) -# define IRQSTATUS_LATCHED_CD BIT(2) -# define IRQSTATUS_LATCHED_BUS_FREE BIT(3) -# define IRQSTATUS_RESELECT_OCCUER BIT(4) -# define IRQSTATUS_PHASE_CHANGE_IRQ BIT(5) -# define IRQSTATUS_SCSIRESET_IRQ BIT(6) -# define IRQSTATUS_TIMER_IRQ BIT(7) -# define IRQSTATUS_FIFO_SHLD_IRQ BIT(8) -# define IRQSTATUS_PCI_IRQ BIT(9) -# define IRQSTATUS_BMCNTERR_IRQ BIT(10) -# define IRQSTATUS_AUTOSCSI_IRQ BIT(11) -# define PCI_IRQ_MASK BIT(12) -# define TIMER_IRQ_MASK BIT(13) -# define FIFO_IRQ_MASK BIT(14) -# define SCSI_IRQ_MASK BIT(15) -# define IRQ_CONTROL_ALL_IRQ_MASK (PCI_IRQ_MASK | \ - TIMER_IRQ_MASK | \ - FIFO_IRQ_MASK | \ - SCSI_IRQ_MASK ) -# define IRQSTATUS_ANY_IRQ (IRQSTATUS_RESELECT_OCCUER | \ - IRQSTATUS_PHASE_CHANGE_IRQ | \ - IRQSTATUS_SCSIRESET_IRQ | \ - IRQSTATUS_TIMER_IRQ | \ - IRQSTATUS_FIFO_SHLD_IRQ | \ - IRQSTATUS_PCI_IRQ | \ - IRQSTATUS_BMCNTERR_IRQ | \ - IRQSTATUS_AUTOSCSI_IRQ ) - -#define TRANSFER_CONTROL 0x02 /* BASE+02, W, W */ -#define TRANSFER_STATUS 0x02 /* BASE+02, W, R */ -# define CB_MMIO_MODE BIT(0) -# define CB_IO_MODE BIT(1) -# define BM_TEST BIT(2) -# define BM_TEST_DIR BIT(3) -# define DUAL_EDGE_ENABLE BIT(4) -# define NO_TRANSFER_TO_HOST BIT(5) -# define TRANSFER_GO BIT(7) -# define BLIEND_MODE BIT(8) -# define BM_START BIT(9) -# define ADVANCED_BM_WRITE BIT(10) -# define BM_SINGLE_MODE BIT(11) -# define FIFO_TRUE_FULL BIT(12) -# define FIFO_TRUE_EMPTY BIT(13) -# define ALL_COUNTER_CLR BIT(14) -# define FIFOTEST BIT(15) - -#define INDEX_REG 0x04 /* BASE+04, Byte(R/W), Word(R) */ - -#define TIMER_SET 0x06 /* BASE+06, W, R/W */ -# define TIMER_CNT_MASK (0xff) -# define TIMER_STOP BIT(8) - -#define DATA_REG_LOW 0x08 /* BASE+08, LowW, R/W */ -#define DATA_REG_HI 0x0a /* BASE+0a, Hi-W, R/W */ - -#define FIFO_REST_CNT 0x0c /* BASE+0c, W, R/W */ -# define FIFO_REST_MASK 0x1ff -# define FIFO_EMPTY_SHLD_FLAG BIT(14) -# define FIFO_FULL_SHLD_FLAG BIT(15) - -#define SREQ_SMPL_RATE 0x0f /* BASE+0f, B, R/W */ -# define SREQSMPLRATE_RATE0 BIT(0) -# define SREQSMPLRATE_RATE1 BIT(1) -# define SAMPLING_ENABLE BIT(2) -# define SMPL_40M (0) /* 40MHz: 0-100ns/period */ -# define SMPL_20M (SREQSMPLRATE_RATE0) /* 20MHz: 100-200ns/period */ -# define SMPL_10M (SREQSMPLRATE_RATE1) /* 10Mhz: 200- ns/period */ - -#define SCSI_BUS_CONTROL 0x10 /* BASE+10, B, R/W */ -# define BUSCTL_SEL BIT(0) -# define BUSCTL_RST BIT(1) -# define BUSCTL_DATAOUT_ENB BIT(2) -# define BUSCTL_ATN BIT(3) -# define BUSCTL_ACK BIT(4) -# define BUSCTL_BSY BIT(5) -# define AUTODIRECTION BIT(6) -# define ACKENB BIT(7) - -#define CLR_COUNTER 0x12 /* BASE+12, B, W */ -# define ACK_COUNTER_CLR BIT(0) -# define SREQ_COUNTER_CLR BIT(1) -# define FIFO_HOST_POINTER_CLR BIT(2) -# define FIFO_REST_COUNT_CLR BIT(3) -# define BM_COUNTER_CLR BIT(4) -# define SAVED_ACK_CLR BIT(5) -# define CLRCOUNTER_ALLMASK (ACK_COUNTER_CLR | \ - SREQ_COUNTER_CLR | \ - FIFO_HOST_POINTER_CLR | \ - FIFO_REST_COUNT_CLR | \ - BM_COUNTER_CLR | \ - SAVED_ACK_CLR ) - -#define SCSI_BUS_MONITOR 0x12 /* BASE+12, B, R */ -# define BUSMON_MSG BIT(0) -# define BUSMON_IO BIT(1) -# define BUSMON_CD BIT(2) -# define BUSMON_BSY BIT(3) -# define BUSMON_ACK BIT(4) -# define BUSMON_REQ BIT(5) -# define BUSMON_SEL BIT(6) -# define BUSMON_ATN BIT(7) - -#define COMMAND_DATA 0x14 /* BASE+14, B, R/W */ - -#define PARITY_CONTROL 0x16 /* BASE+16, B, W */ -# define PARITY_CHECK_ENABLE BIT(0) -# define PARITY_ERROR_CLEAR BIT(1) -#define PARITY_STATUS 0x16 /* BASE+16, B, R */ -//# define PARITY_CHECK_ENABLE BIT(0) -# define PARITY_ERROR_NORMAL BIT(1) -# define PARITY_ERROR_LSB BIT(1) -# define PARITY_ERROR_MSB BIT(2) - -#define RESELECT_ID 0x18 /* BASE+18, B, R */ - -#define COMMAND_CONTROL 0x18 /* BASE+18, W, W */ -# define CLEAR_CDB_FIFO_POINTER BIT(0) -# define AUTO_COMMAND_PHASE BIT(1) -# define AUTOSCSI_START BIT(2) -# define AUTOSCSI_RESTART BIT(3) -# define AUTO_PARAMETER BIT(4) -# define AUTO_ATN BIT(5) -# define AUTO_MSGIN_00_OR_04 BIT(6) -# define AUTO_MSGIN_02 BIT(7) -# define AUTO_MSGIN_03 BIT(8) - -#define SET_ARBIT 0x1a /* BASE+1a, B, W */ -# define ARBIT_GO BIT(0) -# define ARBIT_CLEAR BIT(1) - -#define ARBIT_STATUS 0x1a /* BASE+1a, B, R */ -//# define ARBIT_GO BIT(0) -# define ARBIT_WIN BIT(1) -# define ARBIT_FAIL BIT(2) -# define AUTO_PARAMETER_VALID BIT(3) -# define SGT_VALID BIT(4) - -#define SYNC_REG 0x1c /* BASE+1c, B, R/W */ - -#define ACK_WIDTH 0x1d /* BASE+1d, B, R/W */ - -#define SCSI_DATA_WITH_ACK 0x20 /* BASE+20, B, R/W */ -#define SCSI_OUT_LATCH_TARGET_ID 0x22 /* BASE+22, B, W */ -#define SCSI_DATA_IN 0x22 /* BASE+22, B, R */ - -#define SCAM_CONTROL 0x24 /* BASE+24, B, W */ -#define SCAM_STATUS 0x24 /* BASE+24, B, R */ -# define SCAM_MSG BIT(0) -# define SCAM_IO BIT(1) -# define SCAM_CD BIT(2) -# define SCAM_BSY BIT(3) -# define SCAM_SEL BIT(4) -# define SCAM_XFEROK BIT(5) - -#define SCAM_DATA 0x26 /* BASE+26, B, R/W */ -# define SD0 BIT(0) -# define SD1 BIT(1) -# define SD2 BIT(2) -# define SD3 BIT(3) -# define SD4 BIT(4) -# define SD5 BIT(5) -# define SD6 BIT(6) -# define SD7 BIT(7) - -#define SACK_CNT 0x28 /* BASE+28, DW, R/W */ -#define SREQ_CNT 0x2c /* BASE+2c, DW, R/W */ - -#define FIFO_DATA_LOW 0x30 /* BASE+30, B/W/DW, R/W */ -#define FIFO_DATA_HIGH 0x32 /* BASE+32, B/W, R/W */ -#define BM_START_ADR 0x34 /* BASE+34, DW, R/W */ - -#define BM_CNT 0x38 /* BASE+38, DW, R/W */ -# define BM_COUNT_MASK 0x0001ffffUL -# define SGTEND BIT(31) /* Last SGT marker */ - -#define SGT_ADR 0x3c /* BASE+3c, DW, R/W */ -#define WAIT_REG 0x40 /* Bi only */ - -#define SCSI_EXECUTE_PHASE 0x40 /* BASE+40, W, R */ -# define COMMAND_PHASE BIT(0) -# define DATA_IN_PHASE BIT(1) -# define DATA_OUT_PHASE BIT(2) -# define MSGOUT_PHASE BIT(3) -# define STATUS_PHASE BIT(4) -# define ILLEGAL_PHASE BIT(5) -# define BUS_FREE_OCCUER BIT(6) -# define MSG_IN_OCCUER BIT(7) -# define MSG_OUT_OCCUER BIT(8) -# define SELECTION_TIMEOUT BIT(9) -# define MSGIN_00_VALID BIT(10) -# define MSGIN_02_VALID BIT(11) -# define MSGIN_03_VALID BIT(12) -# define MSGIN_04_VALID BIT(13) -# define AUTOSCSI_BUSY BIT(15) - -#define SCSI_CSB_IN 0x42 /* BASE+42, B, R */ - -#define SCSI_MSG_OUT 0x44 /* BASE+44, DW, R/W */ -# define MSGOUT_COUNT_MASK (BIT(0)|BIT(1)) -# define MV_VALID BIT(7) - -#define SEL_TIME_OUT 0x48 /* BASE+48, W, R/W */ -#define SAVED_SACK_CNT 0x4c /* BASE+4c, DW, R */ - -#define HTOSDATADELAY 0x50 /* BASE+50, B, R/W */ -#define STOHDATADELAY 0x54 /* BASE+54, B, R/W */ -#define ACKSUMCHECKRD 0x58 /* BASE+58, W, R */ -#define REQSUMCHECKRD 0x5c /* BASE+5c, W, R */ - - -/********************/ -/* indexed register */ -/********************/ - -#define CLOCK_DIV 0x00 /* BASE+08, IDX+00, B, R/W */ -# define CLOCK_2 BIT(0) /* MCLK/2 */ -# define CLOCK_4 BIT(1) /* MCLK/4 */ -# define PCICLK BIT(7) /* PCICLK (33MHz) */ - -#define TERM_PWR_CONTROL 0x01 /* BASE+08, IDX+01, B, R/W */ -# define BPWR BIT(0) -# define SENSE BIT(1) /* Read Only */ - -#define EXT_PORT_DDR 0x02 /* BASE+08, IDX+02, B, R/W */ -#define EXT_PORT 0x03 /* BASE+08, IDX+03, B, R/W */ -# define LED_ON (0) -# define LED_OFF BIT(0) - -#define IRQ_SELECT 0x04 /* BASE+08, IDX+04, W, R/W */ -# define IRQSELECT_RESELECT_IRQ BIT(0) -# define IRQSELECT_PHASE_CHANGE_IRQ BIT(1) -# define IRQSELECT_SCSIRESET_IRQ BIT(2) -# define IRQSELECT_TIMER_IRQ BIT(3) -# define IRQSELECT_FIFO_SHLD_IRQ BIT(4) -# define IRQSELECT_TARGET_ABORT_IRQ BIT(5) -# define IRQSELECT_MASTER_ABORT_IRQ BIT(6) -# define IRQSELECT_SERR_IRQ BIT(7) -# define IRQSELECT_PERR_IRQ BIT(8) -# define IRQSELECT_BMCNTERR_IRQ BIT(9) -# define IRQSELECT_AUTO_SCSI_SEQ_IRQ BIT(10) - -#define OLD_SCSI_PHASE 0x05 /* BASE+08, IDX+05, B, R */ -# define OLD_MSG BIT(0) -# define OLD_IO BIT(1) -# define OLD_CD BIT(2) -# define OLD_BUSY BIT(3) - -#define FIFO_FULL_SHLD_COUNT 0x06 /* BASE+08, IDX+06, B, R/W */ -#define FIFO_EMPTY_SHLD_COUNT 0x07 /* BASE+08, IDX+07, B, R/W */ - -#define EXP_ROM_CONTROL 0x08 /* BASE+08, IDX+08, B, R/W */ /* external ROM control */ -# define ROM_WRITE_ENB BIT(0) -# define IO_ACCESS_ENB BIT(1) -# define ROM_ADR_CLEAR BIT(2) - -#define EXP_ROM_ADR 0x09 /* BASE+08, IDX+09, W, R/W */ - -#define EXP_ROM_DATA 0x0a /* BASE+08, IDX+0a, B, R/W */ - -#define CHIP_MODE 0x0b /* BASE+08, IDX+0b, B, R */ /* NinjaSCSI-32Bi only */ -# define OEM0 BIT(1) /* OEM select */ /* 00=I-O DATA, 01=KME, 10=Workbit, 11=Ext ROM */ -# define OEM1 BIT(2) /* OEM select */ -# define OPTB BIT(3) /* KME mode select */ -# define OPTC BIT(4) /* KME mode select */ -# define OPTD BIT(5) /* KME mode select */ -# define OPTE BIT(6) /* KME mode select */ -# define OPTF BIT(7) /* Power management */ - -#define MISC_WR 0x0c /* BASE+08, IDX+0c, W, R/W */ -#define MISC_RD 0x0c -# define SCSI_DIRECTION_DETECTOR_SELECT BIT(0) -# define SCSI2_HOST_DIRECTION_VALID BIT(1) /* Read only */ -# define HOST2_SCSI_DIRECTION_VALID BIT(2) /* Read only */ -# define DELAYED_BMSTART BIT(3) -# define MASTER_TERMINATION_SELECT BIT(4) -# define BMREQ_NEGATE_TIMING_SEL BIT(5) -# define AUTOSEL_TIMING_SEL BIT(6) -# define MISC_MABORT_MASK BIT(7) -# define BMSTOP_CHANGE2_NONDATA_PHASE BIT(8) - -#define BM_CYCLE 0x0d /* BASE+08, IDX+0d, B, R/W */ -# define BM_CYCLE0 BIT(0) -# define BM_CYCLE1 BIT(1) -# define BM_FRAME_ASSERT_TIMING BIT(2) -# define BM_IRDY_ASSERT_TIMING BIT(3) -# define BM_SINGLE_BUS_MASTER BIT(4) -# define MEMRD_CMD0 BIT(5) -# define SGT_AUTO_PARA_MEMED_CMD BIT(6) -# define MEMRD_CMD1 BIT(7) - - -#define SREQ_EDGH 0x0e /* BASE+08, IDX+0e, B, W */ -# define SREQ_EDGH_SELECT BIT(0) - -#define UP_CNT 0x0f /* BASE+08, IDX+0f, B, W */ -# define REQCNT_UP BIT(0) -# define ACKCNT_UP BIT(1) -# define BMADR_UP BIT(4) -# define BMCNT_UP BIT(5) -# define SGT_CNT_UP BIT(7) - -#define CFG_CMD_STR 0x10 /* BASE+08, IDX+10, W, R */ -#define CFG_LATE_CACHE 0x11 /* BASE+08, IDX+11, W, R/W */ -#define CFG_BASE_ADR_1 0x12 /* BASE+08, IDX+12, W, R */ -#define CFG_BASE_ADR_2 0x13 /* BASE+08, IDX+13, W, R */ -#define CFG_INLINE 0x14 /* BASE+08, IDX+14, W, R */ - -#define SERIAL_ROM_CTL 0x15 /* BASE+08, IDX+15, B, R */ -# define SCL BIT(0) -# define ENA BIT(1) -# define SDA BIT(2) - -#define FIFO_HST_POINTER 0x16 /* BASE+08, IDX+16, B, R/W */ -#define SREQ_DELAY 0x17 /* BASE+08, IDX+17, B, R/W */ -#define SACK_DELAY 0x18 /* BASE+08, IDX+18, B, R/W */ -#define SREQ_NOISE_CANCEL 0x19 /* BASE+08, IDX+19, B, R/W */ -#define SDP_NOISE_CANCEL 0x1a /* BASE+08, IDX+1a, B, R/W */ -#define DELAY_TEST 0x1b /* BASE+08, IDX+1b, B, R/W */ -#define SD0_NOISE_CANCEL 0x20 /* BASE+08, IDX+20, B, R/W */ -#define SD1_NOISE_CANCEL 0x21 /* BASE+08, IDX+21, B, R/W */ -#define SD2_NOISE_CANCEL 0x22 /* BASE+08, IDX+22, B, R/W */ -#define SD3_NOISE_CANCEL 0x23 /* BASE+08, IDX+23, B, R/W */ -#define SD4_NOISE_CANCEL 0x24 /* BASE+08, IDX+24, B, R/W */ -#define SD5_NOISE_CANCEL 0x25 /* BASE+08, IDX+25, B, R/W */ -#define SD6_NOISE_CANCEL 0x26 /* BASE+08, IDX+26, B, R/W */ -#define SD7_NOISE_CANCEL 0x27 /* BASE+08, IDX+27, B, R/W */ - - -/* - * Useful Bus Monitor status combinations. - */ -#define BUSMON_BUS_FREE 0 -#define BUSMON_COMMAND ( BUSMON_BSY | BUSMON_CD | BUSMON_REQ ) -#define BUSMON_MESSAGE_IN ( BUSMON_BSY | BUSMON_MSG | BUSMON_IO | BUSMON_CD | BUSMON_REQ ) -#define BUSMON_MESSAGE_OUT ( BUSMON_BSY | BUSMON_MSG | BUSMON_CD | BUSMON_REQ ) -#define BUSMON_DATA_IN ( BUSMON_BSY | BUSMON_IO | BUSMON_REQ ) -#define BUSMON_DATA_OUT ( BUSMON_BSY | BUSMON_REQ ) -#define BUSMON_STATUS ( BUSMON_BSY | BUSMON_IO | BUSMON_CD | BUSMON_REQ ) -#define BUSMON_RESELECT ( BUSMON_IO | BUSMON_SEL) -#define BUSMON_PHASE_MASK ( BUSMON_MSG | BUSMON_IO | BUSMON_CD | BUSMON_SEL) - -#define BUSPHASE_COMMAND ( BUSMON_COMMAND & BUSMON_PHASE_MASK ) -#define BUSPHASE_MESSAGE_IN ( BUSMON_MESSAGE_IN & BUSMON_PHASE_MASK ) -#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK ) -#define BUSPHASE_DATA_IN ( BUSMON_DATA_IN & BUSMON_PHASE_MASK ) -#define BUSPHASE_DATA_OUT ( BUSMON_DATA_OUT & BUSMON_PHASE_MASK ) -#define BUSPHASE_STATUS ( BUSMON_STATUS & BUSMON_PHASE_MASK ) -#define BUSPHASE_SELECT ( BUSMON_SEL | BUSMON_IO ) - - -/************************************************************************ - * structure for DMA/Scatter Gather list - */ -#define NSP32_SG_SIZE SG_ALL - -typedef struct _nsp32_sgtable { - /* values must be little endian */ - u32_le addr; /* transfer address */ - u32_le len; /* transfer length. BIT(31) is for SGT_END mark */ -} __attribute__ ((packed)) nsp32_sgtable; - -typedef struct _nsp32_sglun { - nsp32_sgtable sgt[NSP32_SG_SIZE+1]; /* SG table */ -} __attribute__ ((packed)) nsp32_sglun; -#define NSP32_SG_TABLE_SIZE (sizeof(nsp32_sgtable) * NSP32_SG_SIZE * MAX_TARGET * MAX_LUN) - -/* Auto parameter mode memory map. */ -/* All values must be little endian. */ -typedef struct _nsp32_autoparam { - u8 cdb[4 * 0x10]; /* SCSI Command */ - u32_le msgout; /* outgoing messages */ - u8 syncreg; /* sync register value */ - u8 ackwidth; /* ack width register value */ - u8 target_id; /* target/host device id */ - u8 sample_reg; /* hazard killer sampling rate */ - u16_le command_control; /* command control register */ - u16_le transfer_control; /* transfer control register */ - u32_le sgt_pointer; /* SG table physical address for DMA */ - u32_le dummy[2]; -} __attribute__ ((packed)) nsp32_autoparam; /* must be packed struct */ - -/* - * host data structure - */ -/* message in/out buffer */ -#define MSGOUTBUF_MAX 20 -#define MSGINBUF_MAX 20 - -/* flag for trans_method */ -#define NSP32_TRANSFER_BUSMASTER BIT(0) -#define NSP32_TRANSFER_MMIO BIT(1) /* Not supported yet */ -#define NSP32_TRANSFER_PIO BIT(2) /* Not supported yet */ - - -/* - * structure for connected LUN dynamic data - * - * Note: Currently tagged queuing is disabled, each nsp32_lunt holds - * one SCSI command and one state. - */ -#define DISCPRIV_OK BIT(0) /* DISCPRIV Enable mode */ -#define MSGIN03 BIT(1) /* Auto Msg In 03 Flag */ - -typedef struct _nsp32_lunt { - struct scsi_cmnd *SCpnt; /* Current Handling struct scsi_cmnd */ - unsigned long save_datp; /* Save Data Pointer - saved position from initial address */ - int msgin03; /* auto msg in 03 flag */ - unsigned int sg_num; /* Total number of SG entries */ - int cur_entry; /* Current SG entry number */ - nsp32_sglun *sglun; /* sg table per lun */ - dma_addr_t sglun_paddr; /* sglun physical address */ -} nsp32_lunt; - - -/* - * SCSI TARGET/LUN definition - */ -#define NSP32_HOST_SCSIID 7 /* SCSI initiator is every time defined as 7 */ -#define MAX_TARGET 8 -#define MAX_LUN 8 /* XXX: In SPI3, max number of LUN is 64. */ - - -typedef struct _nsp32_sync_table { - unsigned char period_num; /* period number */ - unsigned char ackwidth; /* ack width designated by period */ - unsigned char start_period; /* search range - start period */ - unsigned char end_period; /* search range - end period */ - unsigned char sample_rate; /* hazard killer parameter */ -} nsp32_sync_table; - - -/* - * structure for target device static data - */ -/* flag for nsp32_target.sync_flag */ -#define SDTR_INITIATOR BIT(0) /* sending SDTR from initiator */ -#define SDTR_TARGET BIT(1) /* sending SDTR from target */ -#define SDTR_DONE BIT(2) /* exchanging SDTR has been processed */ - -/* syncronous period value for nsp32_target.config_max */ -#define FAST5M 0x32 -#define FAST10M 0x19 -#define ULTRA20M 0x0c - -/* flag for nsp32_target.{sync_offset}, period */ -#define ASYNC_OFFSET 0 /* asynchronous transfer */ -#define SYNC_OFFSET 0xf /* synchronous transfer max offset */ - -/* syncreg: - bit:07 06 05 04 03 02 01 00 - ---PERIOD-- ---OFFSET-- */ -#define TO_SYNCREG(period, offset) (((period) & 0x0f) << 4 | ((offset) & 0x0f)) - -typedef struct _nsp32_target { - unsigned char syncreg; /* value for SYNCREG */ - unsigned char ackwidth; /* value for ACKWIDTH */ - unsigned char period; /* sync period (0-255) */ - unsigned char offset; /* sync offset (0-15) */ - int sync_flag; /* SDTR_*, 0 */ - int limit_entry; /* max speed limit entry designated - by EEPROM configuration */ - unsigned char sample_reg; /* SREQ hazard killer register */ -} nsp32_target; - -typedef struct _nsp32_hw_data { - int IrqNumber; - int BaseAddress; - int NumAddress; - void __iomem *MmioAddress; -#define NSP32_MMIO_OFFSET 0x0800 - unsigned long MmioLength; - - struct scsi_cmnd *CurrentSC; - - struct pci_dev *Pci; - const struct pci_device_id *pci_devid; - struct Scsi_Host *Host; - spinlock_t Lock; - - char info_str[100]; - - /* allocated memory region */ - nsp32_sglun *sg_list; /* sglist virtuxal address */ - dma_addr_t sg_paddr; /* physical address of hw_sg_table */ - nsp32_autoparam *autoparam; /* auto parameter transfer region */ - dma_addr_t auto_paddr; /* physical address of autoparam */ - int cur_entry; /* current sgt entry */ - - /* target/LUN */ - nsp32_lunt *cur_lunt; /* Current connected LUN table */ - nsp32_lunt lunt[MAX_TARGET][MAX_LUN]; /* All LUN table */ - - nsp32_target *cur_target; /* Current connected SCSI ID */ - nsp32_target target[MAX_TARGET]; /* SCSI ID */ - int cur_id; /* Current connected target ID */ - int cur_lun; /* Current connected target LUN */ - - /* behavior setting parameters */ - int trans_method; /* transfer method flag */ - int resettime; /* Reset time */ - int clock; /* clock dividing flag */ - nsp32_sync_table *synct; /* sync_table determined by clock */ - int syncnum; /* the max number of synct element */ - - /* message buffer */ - unsigned char msgoutbuf[MSGOUTBUF_MAX]; /* msgout buffer */ - char msgout_len; /* msgoutbuf length */ - unsigned char msginbuf [MSGINBUF_MAX]; /* megin buffer */ - char msgin_len; /* msginbuf length */ - -} nsp32_hw_data; - -/* - * TIME definition - */ -#define RESET_HOLD_TIME 10000 /* reset time in us (SCSI-2 says the - minimum is 25us) */ -#define SEL_TIMEOUT_TIME 10000 /* 250ms defined in SCSI specification - (25.6us/1unit) */ -#define ARBIT_TIMEOUT_TIME 100 /* 100us */ -#define REQSACK_TIMEOUT_TIME 10000 /* max wait time for REQ/SACK assertion - or negation, 10000us == 10ms */ - -#endif /* _NSP32_H */ -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/nsp32_debug.c b/ANDROID_3.4.5/drivers/scsi/nsp32_debug.c deleted file mode 100644 index 58806f43..00000000 --- a/ANDROID_3.4.5/drivers/scsi/nsp32_debug.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver - * Debug routine - * - * This software may be used and distributed according to the terms of - * the GNU General Public License. - */ - -/* - * Show the command data of a command - */ -static const char unknown[] = "UNKNOWN"; - -static const char * group_0_commands[] = { -/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", -/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reassign Blocks", -/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, -/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", -/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", -/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", -/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, -}; - - -static const char *group_1_commands[] = { -/* 20-22 */ unknown, unknown, unknown, -/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", -/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, -/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", -/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", -/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", -/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", -/* 3d-3f */ "Update Block", "Read Long", "Write Long", -}; - - -static const char *group_2_commands[] = { -/* 40-41 */ "Change Definition", "Write Same", -/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", -/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown, -/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", -/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, -/* 5c-5f */ unknown, unknown, unknown, -}; - -#define group(opcode) (((opcode) >> 5) & 7) - -#define RESERVED_GROUP 0 -#define VENDOR_GROUP 1 -#define NOTEXT_GROUP 2 - -static const char **commands[] = { - group_0_commands, group_1_commands, group_2_commands, - (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, - (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, - (const char **) VENDOR_GROUP -}; - -static const char reserved[] = "RESERVED"; -static const char vendor[] = "VENDOR SPECIFIC"; - -static void print_opcodek(unsigned char opcode) -{ - const char **table = commands[ group(opcode) ]; - - switch ((unsigned long) table) { - case RESERVED_GROUP: - printk("%s[%02x] ", reserved, opcode); - break; - case NOTEXT_GROUP: - printk("%s(notext)[%02x] ", unknown, opcode); - break; - case VENDOR_GROUP: - printk("%s[%02x] ", vendor, opcode); - break; - default: - if (table[opcode & 0x1f] != unknown) - printk("%s[%02x] ", table[opcode & 0x1f], opcode); - else - printk("%s[%02x] ", unknown, opcode); - break; - } -} - -static void print_commandk (unsigned char *command) -{ - int i,s; -// printk(KERN_DEBUG); - print_opcodek(command[0]); - /*printk(KERN_DEBUG "%s ", __func__);*/ - if ((command[0] >> 5) == 6 || - (command[0] >> 5) == 7 ) { - s = 12; /* vender specific */ - } else { - s = COMMAND_SIZE(command[0]); - } - - for ( i = 1; i < s; ++i) { - printk("%02x ", command[i]); - } - - switch (s) { - case 6: - printk("LBA=%d len=%d", - (((unsigned int)command[1] & 0x0f) << 16) | - ( (unsigned int)command[2] << 8) | - ( (unsigned int)command[3] ), - (unsigned int)command[4] - ); - break; - case 10: - printk("LBA=%d len=%d", - ((unsigned int)command[2] << 24) | - ((unsigned int)command[3] << 16) | - ((unsigned int)command[4] << 8) | - ((unsigned int)command[5] ), - ((unsigned int)command[7] << 8) | - ((unsigned int)command[8] ) - ); - break; - case 12: - printk("LBA=%d len=%d", - ((unsigned int)command[2] << 24) | - ((unsigned int)command[3] << 16) | - ((unsigned int)command[4] << 8) | - ((unsigned int)command[5] ), - ((unsigned int)command[6] << 24) | - ((unsigned int)command[7] << 16) | - ((unsigned int)command[8] << 8) | - ((unsigned int)command[9] ) - ); - break; - default: - break; - } - printk("\n"); -} - -static void show_command(Scsi_Cmnd *SCpnt) -{ - print_commandk(SCpnt->cmnd); -} - -static void show_busphase(unsigned char stat) -{ - switch(stat) { - case BUSPHASE_COMMAND: - printk( "BUSPHASE_COMMAND\n"); - break; - case BUSPHASE_MESSAGE_IN: - printk( "BUSPHASE_MESSAGE_IN\n"); - break; - case BUSPHASE_MESSAGE_OUT: - printk( "BUSPHASE_MESSAGE_OUT\n"); - break; - case BUSPHASE_DATA_IN: - printk( "BUSPHASE_DATA_IN\n"); - break; - case BUSPHASE_DATA_OUT: - printk( "BUSPHASE_DATA_OUT\n"); - break; - case BUSPHASE_STATUS: - printk( "BUSPHASE_STATUS\n"); - break; - case BUSPHASE_SELECT: - printk( "BUSPHASE_SELECT\n"); - break; - default: - printk( "BUSPHASE_other: 0x%x\n", stat); - break; - } -} - -static void show_autophase(unsigned short i) -{ - printk("auto: 0x%x,", i); - - if(i & COMMAND_PHASE) { - printk(" cmd"); - } - if(i & DATA_IN_PHASE) { - printk(" din"); - } - if(i & DATA_OUT_PHASE) { - printk(" dout"); - } - if(i & MSGOUT_PHASE) { - printk(" mout"); - } - if(i & STATUS_PHASE) { - printk(" stat"); - } - if(i & ILLEGAL_PHASE) { - printk(" ill"); - } - if(i & BUS_FREE_OCCUER) { - printk(" bfree-o"); - } - if(i & MSG_IN_OCCUER) { - printk(" min-o"); - } - if(i & MSG_OUT_OCCUER) { - printk(" mout-o"); - } - if(i & SELECTION_TIMEOUT) { - printk(" sel"); - } - if(i & MSGIN_00_VALID) { - printk(" m0"); - } - if(i & MSGIN_02_VALID) { - printk(" m2"); - } - if(i & MSGIN_03_VALID) { - printk(" m3"); - } - if(i & MSGIN_04_VALID) { - printk(" m4"); - } - if(i & AUTOSCSI_BUSY) { - printk(" busy"); - } - - printk("\n"); -} - -static void nsp32_print_register(int base) -{ - if (!(NSP32_DEBUG_MASK & NSP32_SPECIAL_PRINT_REGISTER)) - return; - - printk("Phase=0x%x, ", nsp32_read1(base, SCSI_BUS_MONITOR)); - printk("OldPhase=0x%x, ", nsp32_index_read1(base, OLD_SCSI_PHASE)); - printk("syncreg=0x%x, ", nsp32_read1(base, SYNC_REG)); - printk("ackwidth=0x%x, ", nsp32_read1(base, ACK_WIDTH)); - printk("sgtpaddr=0x%lx, ", nsp32_read4(base, SGT_ADR)); - printk("scsioutlatch=0x%x, ", nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID)); - printk("msgout=0x%lx, ", nsp32_read4(base, SCSI_MSG_OUT)); - printk("miscrd=0x%x, ", nsp32_index_read2(base, MISC_WR)); - printk("seltimeout=0x%x, ", nsp32_read2(base, SEL_TIME_OUT)); - printk("sreqrate=0x%x, ", nsp32_read1(base, SREQ_SMPL_RATE)); - printk("transStatus=0x%x, ", nsp32_read2(base, TRANSFER_STATUS)); - printk("reselectid=0x%x, ", nsp32_read2(base, COMMAND_CONTROL)); - printk("arbit=0x%x, ", nsp32_read1(base, ARBIT_STATUS)); - printk("BmStart=0x%lx, ", nsp32_read4(base, BM_START_ADR)); - printk("BmCount=0x%lx, ", nsp32_read4(base, BM_CNT)); - printk("SackCnt=0x%lx, ", nsp32_read4(base, SACK_CNT)); - printk("SReqCnt=0x%lx, ", nsp32_read4(base, SREQ_CNT)); - printk("SavedSackCnt=0x%lx, ", nsp32_read4(base, SAVED_SACK_CNT)); - printk("ScsiBusControl=0x%x, ", nsp32_read1(base, SCSI_BUS_CONTROL)); - printk("FifoRestCnt=0x%x, ", nsp32_read2(base, FIFO_REST_CNT)); - printk("CdbIn=0x%x, ", nsp32_read1(base, SCSI_CSB_IN)); - printk("\n"); - - if (0) { - printk("execph=0x%x, ", nsp32_read2(base, SCSI_EXECUTE_PHASE)); - printk("IrqStatus=0x%x, ", nsp32_read2(base, IRQ_STATUS)); - printk("\n"); - } -} - -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/nsp32_io.h b/ANDROID_3.4.5/drivers/scsi/nsp32_io.h deleted file mode 100644 index e3f3c27b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/nsp32_io.h +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver - * I/O routine - * - * This software may be used and distributed according to the terms of - * the GNU General Public License. - */ - -#ifndef _NSP32_IO_H -#define _NSP32_IO_H - -static inline void nsp32_write1(unsigned int base, - unsigned int index, - unsigned char val) -{ - outb(val, (base + index)); -} - -static inline unsigned char nsp32_read1(unsigned int base, - unsigned int index) -{ - return inb(base + index); -} - -static inline void nsp32_write2(unsigned int base, - unsigned int index, - unsigned short val) -{ - outw(val, (base + index)); -} - -static inline unsigned short nsp32_read2(unsigned int base, - unsigned int index) -{ - return inw(base + index); -} - -static inline void nsp32_write4(unsigned int base, - unsigned int index, - unsigned long val) -{ - outl(val, (base + index)); -} - -static inline unsigned long nsp32_read4(unsigned int base, - unsigned int index) -{ - return inl(base + index); -} - -/*==============================================*/ - -static inline void nsp32_mmio_write1(unsigned long base, - unsigned int index, - unsigned char val) -{ - volatile unsigned char *ptr; - - ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index); - - writeb(val, ptr); -} - -static inline unsigned char nsp32_mmio_read1(unsigned long base, - unsigned int index) -{ - volatile unsigned char *ptr; - - ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index); - - return readb(ptr); -} - -static inline void nsp32_mmio_write2(unsigned long base, - unsigned int index, - unsigned short val) -{ - volatile unsigned short *ptr; - - ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index); - - writew(cpu_to_le16(val), ptr); -} - -static inline unsigned short nsp32_mmio_read2(unsigned long base, - unsigned int index) -{ - volatile unsigned short *ptr; - - ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index); - - return le16_to_cpu(readw(ptr)); -} - -static inline void nsp32_mmio_write4(unsigned long base, - unsigned int index, - unsigned long val) -{ - volatile unsigned long *ptr; - - ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index); - - writel(cpu_to_le32(val), ptr); -} - -static inline unsigned long nsp32_mmio_read4(unsigned long base, - unsigned int index) -{ - volatile unsigned long *ptr; - - ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index); - - return le32_to_cpu(readl(ptr)); -} - -/*==============================================*/ - -static inline unsigned char nsp32_index_read1(unsigned int base, - unsigned int reg) -{ - outb(reg, base + INDEX_REG); - return inb(base + DATA_REG_LOW); -} - -static inline void nsp32_index_write1(unsigned int base, - unsigned int reg, - unsigned char val) -{ - outb(reg, base + INDEX_REG ); - outb(val, base + DATA_REG_LOW); -} - -static inline unsigned short nsp32_index_read2(unsigned int base, - unsigned int reg) -{ - outb(reg, base + INDEX_REG); - return inw(base + DATA_REG_LOW); -} - -static inline void nsp32_index_write2(unsigned int base, - unsigned int reg, - unsigned short val) -{ - outb(reg, base + INDEX_REG ); - outw(val, base + DATA_REG_LOW); -} - -static inline unsigned long nsp32_index_read4(unsigned int base, - unsigned int reg) -{ - unsigned long h,l; - - outb(reg, base + INDEX_REG); - l = inw(base + DATA_REG_LOW); - h = inw(base + DATA_REG_HI ); - - return ((h << 16) | l); -} - -static inline void nsp32_index_write4(unsigned int base, - unsigned int reg, - unsigned long val) -{ - unsigned long h,l; - - h = (val & 0xffff0000) >> 16; - l = (val & 0x0000ffff) >> 0; - - outb(reg, base + INDEX_REG ); - outw(l, base + DATA_REG_LOW); - outw(h, base + DATA_REG_HI ); -} - -/*==============================================*/ - -static inline unsigned char nsp32_mmio_index_read1(unsigned long base, - unsigned int reg) -{ - volatile unsigned short *index_ptr, *data_ptr; - - index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG); - data_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW); - - writeb(reg, index_ptr); - return readb(data_ptr); -} - -static inline void nsp32_mmio_index_write1(unsigned long base, - unsigned int reg, - unsigned char val) -{ - volatile unsigned short *index_ptr, *data_ptr; - - index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG); - data_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW); - - writeb(reg, index_ptr); - writeb(val, data_ptr ); -} - -static inline unsigned short nsp32_mmio_index_read2(unsigned long base, - unsigned int reg) -{ - volatile unsigned short *index_ptr, *data_ptr; - - index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG); - data_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW); - - writeb(reg, index_ptr); - return le16_to_cpu(readw(data_ptr)); -} - -static inline void nsp32_mmio_index_write2(unsigned long base, - unsigned int reg, - unsigned short val) -{ - volatile unsigned short *index_ptr, *data_ptr; - - index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG); - data_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW); - - writeb(reg, index_ptr); - writew(cpu_to_le16(val), data_ptr ); -} - -/*==============================================*/ - -static inline void nsp32_multi_read4(unsigned int base, - unsigned int reg, - void *buf, - unsigned long count) -{ - insl(base + reg, buf, count); -} - -static inline void nsp32_fifo_read(unsigned int base, - void *buf, - unsigned long count) -{ - nsp32_multi_read4(base, FIFO_DATA_LOW, buf, count); -} - -static inline void nsp32_multi_write4(unsigned int base, - unsigned int reg, - void *buf, - unsigned long count) -{ - outsl(base + reg, buf, count); -} - -static inline void nsp32_fifo_write(unsigned int base, - void *buf, - unsigned long count) -{ - nsp32_multi_write4(base, FIFO_DATA_LOW, buf, count); -} - -#endif /* _NSP32_IO_H */ -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/osd/Kbuild b/ANDROID_3.4.5/drivers/scsi/osd/Kbuild deleted file mode 100644 index 5fd73d77..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osd/Kbuild +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kbuild for the OSD modules -# -# Copyright (C) 2008 Panasas Inc. All rights reserved. -# -# Authors: -# Boaz Harrosh -# Benny Halevy -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 -# - -# libosd.ko - osd-initiator library -libosd-y := osd_initiator.o -obj-$(CONFIG_SCSI_OSD_INITIATOR) += libosd.o - -# osd.ko - SCSI ULD and char-device -osd-y := osd_uld.o -obj-$(CONFIG_SCSI_OSD_ULD) += osd.o diff --git a/ANDROID_3.4.5/drivers/scsi/osd/Kconfig b/ANDROID_3.4.5/drivers/scsi/osd/Kconfig deleted file mode 100644 index a0703514..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osd/Kconfig +++ /dev/null @@ -1,49 +0,0 @@ -# -# Kernel configuration file for the OSD scsi protocol -# -# Copyright (C) 2008 Panasas Inc. All rights reserved. -# -# Authors: -# Boaz Harrosh -# Benny Halevy -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public version 2 License as -# published by the Free Software Foundation -# -config SCSI_OSD_INITIATOR - tristate "OSD-Initiator library" - depends on SCSI - help - Enable the OSD-Initiator library (libosd.ko). - NOTE: You must also select CRYPTO_SHA1 + CRYPTO_HMAC and their - dependencies - -config SCSI_OSD_ULD - tristate "OSD Upper Level driver" - depends on SCSI_OSD_INITIATOR - help - Build a SCSI upper layer driver that exports /dev/osdX devices - to user-mode for testing and controlling OSD devices. It is also - needed by exofs, for mounting an OSD based file system. - -config SCSI_OSD_DPRINT_SENSE - int "(0-2) When sense is returned, DEBUG print all sense descriptors" - default 1 - depends on SCSI_OSD_INITIATOR - help - When a CHECK_CONDITION status is returned from a target, and a - sense-buffer is retrieved, turning this on will dump a full - sense-decoding message. Setting to 2 will also print recoverable - errors that might be regularly returned for some filesystem - operations. - -config SCSI_OSD_DEBUG - bool "Compile All OSD modules with lots of DEBUG prints" - default n - depends on SCSI_OSD_INITIATOR - help - OSD Code is populated with lots of OSD_DEBUG(..) printouts to - dmesg. Enable this if you found a bug and you want to help us - track the problem (see also MAINTAINERS). Setting this will also - force SCSI_OSD_DPRINT_SENSE=2. diff --git a/ANDROID_3.4.5/drivers/scsi/osd/osd_debug.h b/ANDROID_3.4.5/drivers/scsi/osd/osd_debug.h deleted file mode 100644 index 579e491f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osd/osd_debug.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * osd_debug.h - Some kprintf macros - * - * Copyright (C) 2008 Panasas Inc. All rights reserved. - * - * Authors: - * Boaz Harrosh - * Benny Halevy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * - */ -#ifndef __OSD_DEBUG_H__ -#define __OSD_DEBUG_H__ - -#define OSD_ERR(fmt, a...) printk(KERN_ERR "osd: " fmt, ##a) -#define OSD_INFO(fmt, a...) printk(KERN_NOTICE "osd: " fmt, ##a) - -#ifdef CONFIG_SCSI_OSD_DEBUG -#define OSD_DEBUG(fmt, a...) \ - printk(KERN_NOTICE "osd @%s:%d: " fmt, __func__, __LINE__, ##a) -#else -#define OSD_DEBUG(fmt, a...) do {} while (0) -#endif - -/* u64 has problems with printk this will cast it to unsigned long long */ -#define _LLU(x) (unsigned long long)(x) - -#endif /* ndef __OSD_DEBUG_H__ */ diff --git a/ANDROID_3.4.5/drivers/scsi/osd/osd_initiator.c b/ANDROID_3.4.5/drivers/scsi/osd/osd_initiator.c deleted file mode 100644 index c06b8e5a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osd/osd_initiator.c +++ /dev/null @@ -1,2067 +0,0 @@ -/* - * osd_initiator - Main body of the osd initiator library. - * - * Note: The file does not contain the advanced security functionality which - * is only needed by the security_manager's initiators. - * - * Copyright (C) 2008 Panasas Inc. All rights reserved. - * - * Authors: - * Boaz Harrosh - * Benny Halevy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Panasas company nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include - -#include -#include -#include -#include - -#include - -#include "osd_debug.h" - -#ifndef __unused -# define __unused __attribute__((unused)) -#endif - -enum { OSD_REQ_RETRIES = 1 }; - -MODULE_AUTHOR("Boaz Harrosh "); -MODULE_DESCRIPTION("open-osd initiator library libosd.ko"); -MODULE_LICENSE("GPL"); - -static inline void build_test(void) -{ - /* structures were not packed */ - BUILD_BUG_ON(sizeof(struct osd_capability) != OSD_CAP_LEN); - BUILD_BUG_ON(sizeof(struct osdv2_cdb) != OSD_TOTAL_CDB_LEN); - BUILD_BUG_ON(sizeof(struct osdv1_cdb) != OSDv1_TOTAL_CDB_LEN); -} - -static const char *_osd_ver_desc(struct osd_request *or) -{ - return osd_req_is_ver1(or) ? "OSD1" : "OSD2"; -} - -#define ATTR_DEF_RI(id, len) ATTR_DEF(OSD_APAGE_ROOT_INFORMATION, id, len) - -static int _osd_get_print_system_info(struct osd_dev *od, - void *caps, struct osd_dev_info *odi) -{ - struct osd_request *or; - struct osd_attr get_attrs[] = { - ATTR_DEF_RI(OSD_ATTR_RI_VENDOR_IDENTIFICATION, 8), - ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_IDENTIFICATION, 16), - ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_MODEL, 32), - ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_REVISION_LEVEL, 4), - ATTR_DEF_RI(OSD_ATTR_RI_PRODUCT_SERIAL_NUMBER, 64 /*variable*/), - ATTR_DEF_RI(OSD_ATTR_RI_OSD_NAME, 64 /*variable*/), - ATTR_DEF_RI(OSD_ATTR_RI_TOTAL_CAPACITY, 8), - ATTR_DEF_RI(OSD_ATTR_RI_USED_CAPACITY, 8), - ATTR_DEF_RI(OSD_ATTR_RI_NUMBER_OF_PARTITIONS, 8), - ATTR_DEF_RI(OSD_ATTR_RI_CLOCK, 6), - /* IBM-OSD-SIM Has a bug with this one put it last */ - ATTR_DEF_RI(OSD_ATTR_RI_OSD_SYSTEM_ID, 20), - }; - void *iter = NULL, *pFirst; - int nelem = ARRAY_SIZE(get_attrs), a = 0; - int ret; - - or = osd_start_request(od, GFP_KERNEL); - if (!or) - return -ENOMEM; - - /* get attrs */ - osd_req_get_attributes(or, &osd_root_object); - osd_req_add_get_attr_list(or, get_attrs, ARRAY_SIZE(get_attrs)); - - ret = osd_finalize_request(or, 0, caps, NULL); - if (ret) - goto out; - - ret = osd_execute_request(or); - if (ret) { - OSD_ERR("Failed to detect %s => %d\n", _osd_ver_desc(or), ret); - goto out; - } - - osd_req_decode_get_attr_list(or, get_attrs, &nelem, &iter); - - OSD_INFO("Detected %s device\n", - _osd_ver_desc(or)); - - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("VENDOR_IDENTIFICATION [%s]\n", - (char *)pFirst); - - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("PRODUCT_IDENTIFICATION [%s]\n", - (char *)pFirst); - - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("PRODUCT_MODEL [%s]\n", - (char *)pFirst); - - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("PRODUCT_REVISION_LEVEL [%u]\n", - pFirst ? get_unaligned_be32(pFirst) : ~0U); - - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("PRODUCT_SERIAL_NUMBER [%s]\n", - (char *)pFirst); - - odi->osdname_len = get_attrs[a].len; - /* Avoid NULL for memcmp optimization 0-length is good enough */ - odi->osdname = kzalloc(odi->osdname_len + 1, GFP_KERNEL); - if (odi->osdname_len) - memcpy(odi->osdname, get_attrs[a].val_ptr, odi->osdname_len); - OSD_INFO("OSD_NAME [%s]\n", odi->osdname); - a++; - - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("TOTAL_CAPACITY [0x%llx]\n", - pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); - - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("USED_CAPACITY [0x%llx]\n", - pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); - - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("NUMBER_OF_PARTITIONS [%llu]\n", - pFirst ? _LLU(get_unaligned_be64(pFirst)) : ~0ULL); - - if (a >= nelem) - goto out; - - /* FIXME: Where are the time utilities */ - pFirst = get_attrs[a++].val_ptr; - OSD_INFO("CLOCK [0x%02x%02x%02x%02x%02x%02x]\n", - ((char *)pFirst)[0], ((char *)pFirst)[1], - ((char *)pFirst)[2], ((char *)pFirst)[3], - ((char *)pFirst)[4], ((char *)pFirst)[5]); - - if (a < nelem) { /* IBM-OSD-SIM bug, Might not have it */ - unsigned len = get_attrs[a].len; - char sid_dump[32*4 + 2]; /* 2nibbles+space+ASCII */ - - hex_dump_to_buffer(get_attrs[a].val_ptr, len, 32, 1, - sid_dump, sizeof(sid_dump), true); - OSD_INFO("OSD_SYSTEM_ID(%d)\n" - " [%s]\n", len, sid_dump); - - if (unlikely(len > sizeof(odi->systemid))) { - OSD_ERR("OSD Target error: OSD_SYSTEM_ID too long(%d). " - "device idetification might not work\n", len); - len = sizeof(odi->systemid); - } - odi->systemid_len = len; - memcpy(odi->systemid, get_attrs[a].val_ptr, len); - a++; - } -out: - osd_end_request(or); - return ret; -} - -int osd_auto_detect_ver(struct osd_dev *od, - void *caps, struct osd_dev_info *odi) -{ - int ret; - - /* Auto-detect the osd version */ - ret = _osd_get_print_system_info(od, caps, odi); - if (ret) { - osd_dev_set_ver(od, OSD_VER1); - OSD_DEBUG("converting to OSD1\n"); - ret = _osd_get_print_system_info(od, caps, odi); - } - - return ret; -} -EXPORT_SYMBOL(osd_auto_detect_ver); - -static unsigned _osd_req_cdb_len(struct osd_request *or) -{ - return osd_req_is_ver1(or) ? OSDv1_TOTAL_CDB_LEN : OSD_TOTAL_CDB_LEN; -} - -static unsigned _osd_req_alist_elem_size(struct osd_request *or, unsigned len) -{ - return osd_req_is_ver1(or) ? - osdv1_attr_list_elem_size(len) : - osdv2_attr_list_elem_size(len); -} - -static void _osd_req_alist_elem_encode(struct osd_request *or, - void *attr_last, const struct osd_attr *oa) -{ - if (osd_req_is_ver1(or)) { - struct osdv1_attributes_list_element *attr = attr_last; - - attr->attr_page = cpu_to_be32(oa->attr_page); - attr->attr_id = cpu_to_be32(oa->attr_id); - attr->attr_bytes = cpu_to_be16(oa->len); - memcpy(attr->attr_val, oa->val_ptr, oa->len); - } else { - struct osdv2_attributes_list_element *attr = attr_last; - - attr->attr_page = cpu_to_be32(oa->attr_page); - attr->attr_id = cpu_to_be32(oa->attr_id); - attr->attr_bytes = cpu_to_be16(oa->len); - memcpy(attr->attr_val, oa->val_ptr, oa->len); - } -} - -static int _osd_req_alist_elem_decode(struct osd_request *or, - void *cur_p, struct osd_attr *oa, unsigned max_bytes) -{ - unsigned inc; - if (osd_req_is_ver1(or)) { - struct osdv1_attributes_list_element *attr = cur_p; - - if (max_bytes < sizeof(*attr)) - return -1; - - oa->len = be16_to_cpu(attr->attr_bytes); - inc = _osd_req_alist_elem_size(or, oa->len); - if (inc > max_bytes) - return -1; - - oa->attr_page = be32_to_cpu(attr->attr_page); - oa->attr_id = be32_to_cpu(attr->attr_id); - - /* OSD1: On empty attributes we return a pointer to 2 bytes - * of zeros. This keeps similar behaviour with OSD2. - * (See below) - */ - oa->val_ptr = likely(oa->len) ? attr->attr_val : - (u8 *)&attr->attr_bytes; - } else { - struct osdv2_attributes_list_element *attr = cur_p; - - if (max_bytes < sizeof(*attr)) - return -1; - - oa->len = be16_to_cpu(attr->attr_bytes); - inc = _osd_req_alist_elem_size(or, oa->len); - if (inc > max_bytes) - return -1; - - oa->attr_page = be32_to_cpu(attr->attr_page); - oa->attr_id = be32_to_cpu(attr->attr_id); - - /* OSD2: For convenience, on empty attributes, we return 8 bytes - * of zeros here. This keeps the same behaviour with OSD2r04, - * and is nice with null terminating ASCII fields. - * oa->val_ptr == NULL marks the end-of-list, or error. - */ - oa->val_ptr = likely(oa->len) ? attr->attr_val : attr->reserved; - } - return inc; -} - -static unsigned _osd_req_alist_size(struct osd_request *or, void *list_head) -{ - return osd_req_is_ver1(or) ? - osdv1_list_size(list_head) : - osdv2_list_size(list_head); -} - -static unsigned _osd_req_sizeof_alist_header(struct osd_request *or) -{ - return osd_req_is_ver1(or) ? - sizeof(struct osdv1_attributes_list_header) : - sizeof(struct osdv2_attributes_list_header); -} - -static void _osd_req_set_alist_type(struct osd_request *or, - void *list, int list_type) -{ - if (osd_req_is_ver1(or)) { - struct osdv1_attributes_list_header *attr_list = list; - - memset(attr_list, 0, sizeof(*attr_list)); - attr_list->type = list_type; - } else { - struct osdv2_attributes_list_header *attr_list = list; - - memset(attr_list, 0, sizeof(*attr_list)); - attr_list->type = list_type; - } -} - -static bool _osd_req_is_alist_type(struct osd_request *or, - void *list, int list_type) -{ - if (!list) - return false; - - if (osd_req_is_ver1(or)) { - struct osdv1_attributes_list_header *attr_list = list; - - return attr_list->type == list_type; - } else { - struct osdv2_attributes_list_header *attr_list = list; - - return attr_list->type == list_type; - } -} - -/* This is for List-objects not Attributes-Lists */ -static void _osd_req_encode_olist(struct osd_request *or, - struct osd_obj_id_list *list) -{ - struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); - - if (osd_req_is_ver1(or)) { - cdbh->v1.list_identifier = list->list_identifier; - cdbh->v1.start_address = list->continuation_id; - } else { - cdbh->v2.list_identifier = list->list_identifier; - cdbh->v2.start_address = list->continuation_id; - } -} - -static osd_cdb_offset osd_req_encode_offset(struct osd_request *or, - u64 offset, unsigned *padding) -{ - return __osd_encode_offset(offset, padding, - osd_req_is_ver1(or) ? - OSDv1_OFFSET_MIN_SHIFT : OSD_OFFSET_MIN_SHIFT, - OSD_OFFSET_MAX_SHIFT); -} - -static struct osd_security_parameters * -_osd_req_sec_params(struct osd_request *or) -{ - struct osd_cdb *ocdb = &or->cdb; - - if (osd_req_is_ver1(or)) - return (struct osd_security_parameters *)&ocdb->v1.sec_params; - else - return (struct osd_security_parameters *)&ocdb->v2.sec_params; -} - -void osd_dev_init(struct osd_dev *osdd, struct scsi_device *scsi_device) -{ - memset(osdd, 0, sizeof(*osdd)); - osdd->scsi_device = scsi_device; - osdd->def_timeout = BLK_DEFAULT_SG_TIMEOUT; -#ifdef OSD_VER1_SUPPORT - osdd->version = OSD_VER2; -#endif - /* TODO: Allocate pools for osd_request attributes ... */ -} -EXPORT_SYMBOL(osd_dev_init); - -void osd_dev_fini(struct osd_dev *osdd) -{ - /* TODO: De-allocate pools */ - - osdd->scsi_device = NULL; -} -EXPORT_SYMBOL(osd_dev_fini); - -static struct osd_request *_osd_request_alloc(gfp_t gfp) -{ - struct osd_request *or; - - /* TODO: Use mempool with one saved request */ - or = kzalloc(sizeof(*or), gfp); - return or; -} - -static void _osd_request_free(struct osd_request *or) -{ - kfree(or); -} - -struct osd_request *osd_start_request(struct osd_dev *dev, gfp_t gfp) -{ - struct osd_request *or; - - or = _osd_request_alloc(gfp); - if (!or) - return NULL; - - or->osd_dev = dev; - or->alloc_flags = gfp; - or->timeout = dev->def_timeout; - or->retries = OSD_REQ_RETRIES; - - return or; -} -EXPORT_SYMBOL(osd_start_request); - -static void _osd_free_seg(struct osd_request *or __unused, - struct _osd_req_data_segment *seg) -{ - if (!seg->buff || !seg->alloc_size) - return; - - kfree(seg->buff); - seg->buff = NULL; - seg->alloc_size = 0; -} - -static void _put_request(struct request *rq) -{ - /* - * If osd_finalize_request() was called but the request was not - * executed through the block layer, then we must release BIOs. - * TODO: Keep error code in or->async_error. Need to audit all - * code paths. - */ - if (unlikely(rq->bio)) - blk_end_request(rq, -ENOMEM, blk_rq_bytes(rq)); - else - blk_put_request(rq); -} - -void osd_end_request(struct osd_request *or) -{ - struct request *rq = or->request; - - if (rq) { - if (rq->next_rq) { - _put_request(rq->next_rq); - rq->next_rq = NULL; - } - - _put_request(rq); - } - - _osd_free_seg(or, &or->get_attr); - _osd_free_seg(or, &or->enc_get_attr); - _osd_free_seg(or, &or->set_attr); - _osd_free_seg(or, &or->cdb_cont); - - _osd_request_free(or); -} -EXPORT_SYMBOL(osd_end_request); - -static void _set_error_resid(struct osd_request *or, struct request *req, - int error) -{ - or->async_error = error; - or->req_errors = req->errors ? : error; - or->sense_len = req->sense_len; - if (or->out.req) - or->out.residual = or->out.req->resid_len; - if (or->in.req) - or->in.residual = or->in.req->resid_len; -} - -int osd_execute_request(struct osd_request *or) -{ - int error = blk_execute_rq(or->request->q, NULL, or->request, 0); - - _set_error_resid(or, or->request, error); - return error; -} -EXPORT_SYMBOL(osd_execute_request); - -static void osd_request_async_done(struct request *req, int error) -{ - struct osd_request *or = req->end_io_data; - - _set_error_resid(or, req, error); - if (req->next_rq) { - __blk_put_request(req->q, req->next_rq); - req->next_rq = NULL; - } - - __blk_put_request(req->q, req); - or->request = NULL; - or->in.req = NULL; - or->out.req = NULL; - - if (or->async_done) - or->async_done(or, or->async_private); - else - osd_end_request(or); -} - -int osd_execute_request_async(struct osd_request *or, - osd_req_done_fn *done, void *private) -{ - or->request->end_io_data = or; - or->async_private = private; - or->async_done = done; - - blk_execute_rq_nowait(or->request->q, NULL, or->request, 0, - osd_request_async_done); - return 0; -} -EXPORT_SYMBOL(osd_execute_request_async); - -u8 sg_out_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT]; -u8 sg_in_pad_buffer[1 << OSDv1_OFFSET_MIN_SHIFT]; - -static int _osd_realloc_seg(struct osd_request *or, - struct _osd_req_data_segment *seg, unsigned max_bytes) -{ - void *buff; - - if (seg->alloc_size >= max_bytes) - return 0; - - buff = krealloc(seg->buff, max_bytes, or->alloc_flags); - if (!buff) { - OSD_ERR("Failed to Realloc %d-bytes was-%d\n", max_bytes, - seg->alloc_size); - return -ENOMEM; - } - - memset(buff + seg->alloc_size, 0, max_bytes - seg->alloc_size); - seg->buff = buff; - seg->alloc_size = max_bytes; - return 0; -} - -static int _alloc_cdb_cont(struct osd_request *or, unsigned total_bytes) -{ - OSD_DEBUG("total_bytes=%d\n", total_bytes); - return _osd_realloc_seg(or, &or->cdb_cont, total_bytes); -} - -static int _alloc_set_attr_list(struct osd_request *or, - const struct osd_attr *oa, unsigned nelem, unsigned add_bytes) -{ - unsigned total_bytes = add_bytes; - - for (; nelem; --nelem, ++oa) - total_bytes += _osd_req_alist_elem_size(or, oa->len); - - OSD_DEBUG("total_bytes=%d\n", total_bytes); - return _osd_realloc_seg(or, &or->set_attr, total_bytes); -} - -static int _alloc_get_attr_desc(struct osd_request *or, unsigned max_bytes) -{ - OSD_DEBUG("total_bytes=%d\n", max_bytes); - return _osd_realloc_seg(or, &or->enc_get_attr, max_bytes); -} - -static int _alloc_get_attr_list(struct osd_request *or) -{ - OSD_DEBUG("total_bytes=%d\n", or->get_attr.total_bytes); - return _osd_realloc_seg(or, &or->get_attr, or->get_attr.total_bytes); -} - -/* - * Common to all OSD commands - */ - -static void _osdv1_req_encode_common(struct osd_request *or, - __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) -{ - struct osdv1_cdb *ocdb = &or->cdb.v1; - - /* - * For speed, the commands - * OSD_ACT_PERFORM_SCSI_COMMAND , V1 0x8F7E, V2 0x8F7C - * OSD_ACT_SCSI_TASK_MANAGEMENT , V1 0x8F7F, V2 0x8F7D - * are not supported here. Should pass zero and set after the call - */ - act &= cpu_to_be16(~0x0080); /* V1 action code */ - - OSD_DEBUG("OSDv1 execute opcode 0x%x\n", be16_to_cpu(act)); - - ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD; - ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH; - ocdb->h.varlen_cdb.service_action = act; - - ocdb->h.partition = cpu_to_be64(obj->partition); - ocdb->h.object = cpu_to_be64(obj->id); - ocdb->h.v1.length = cpu_to_be64(len); - ocdb->h.v1.start_address = cpu_to_be64(offset); -} - -static void _osdv2_req_encode_common(struct osd_request *or, - __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) -{ - struct osdv2_cdb *ocdb = &or->cdb.v2; - - OSD_DEBUG("OSDv2 execute opcode 0x%x\n", be16_to_cpu(act)); - - ocdb->h.varlen_cdb.opcode = VARIABLE_LENGTH_CMD; - ocdb->h.varlen_cdb.additional_cdb_length = OSD_ADDITIONAL_CDB_LENGTH; - ocdb->h.varlen_cdb.service_action = act; - - ocdb->h.partition = cpu_to_be64(obj->partition); - ocdb->h.object = cpu_to_be64(obj->id); - ocdb->h.v2.length = cpu_to_be64(len); - ocdb->h.v2.start_address = cpu_to_be64(offset); -} - -static void _osd_req_encode_common(struct osd_request *or, - __be16 act, const struct osd_obj_id *obj, u64 offset, u64 len) -{ - if (osd_req_is_ver1(or)) - _osdv1_req_encode_common(or, act, obj, offset, len); - else - _osdv2_req_encode_common(or, act, obj, offset, len); -} - -/* - * Device commands - */ -/*TODO: void osd_req_set_master_seed_xchg(struct osd_request *, ...); */ -/*TODO: void osd_req_set_master_key(struct osd_request *, ...); */ - -void osd_req_format(struct osd_request *or, u64 tot_capacity) -{ - _osd_req_encode_common(or, OSD_ACT_FORMAT_OSD, &osd_root_object, 0, - tot_capacity); -} -EXPORT_SYMBOL(osd_req_format); - -int osd_req_list_dev_partitions(struct osd_request *or, - osd_id initial_id, struct osd_obj_id_list *list, unsigned nelem) -{ - return osd_req_list_partition_objects(or, 0, initial_id, list, nelem); -} -EXPORT_SYMBOL(osd_req_list_dev_partitions); - -static void _osd_req_encode_flush(struct osd_request *or, - enum osd_options_flush_scope_values op) -{ - struct osd_cdb_head *ocdb = osd_cdb_head(&or->cdb); - - ocdb->command_specific_options = op; -} - -void osd_req_flush_obsd(struct osd_request *or, - enum osd_options_flush_scope_values op) -{ - _osd_req_encode_common(or, OSD_ACT_FLUSH_OSD, &osd_root_object, 0, 0); - _osd_req_encode_flush(or, op); -} -EXPORT_SYMBOL(osd_req_flush_obsd); - -/*TODO: void osd_req_perform_scsi_command(struct osd_request *, - const u8 *cdb, ...); */ -/*TODO: void osd_req_task_management(struct osd_request *, ...); */ - -/* - * Partition commands - */ -static void _osd_req_encode_partition(struct osd_request *or, - __be16 act, osd_id partition) -{ - struct osd_obj_id par = { - .partition = partition, - .id = 0, - }; - - _osd_req_encode_common(or, act, &par, 0, 0); -} - -void osd_req_create_partition(struct osd_request *or, osd_id partition) -{ - _osd_req_encode_partition(or, OSD_ACT_CREATE_PARTITION, partition); -} -EXPORT_SYMBOL(osd_req_create_partition); - -void osd_req_remove_partition(struct osd_request *or, osd_id partition) -{ - _osd_req_encode_partition(or, OSD_ACT_REMOVE_PARTITION, partition); -} -EXPORT_SYMBOL(osd_req_remove_partition); - -/*TODO: void osd_req_set_partition_key(struct osd_request *, - osd_id partition, u8 new_key_id[OSD_CRYPTO_KEYID_SIZE], - u8 seed[OSD_CRYPTO_SEED_SIZE]); */ - -static int _osd_req_list_objects(struct osd_request *or, - __be16 action, const struct osd_obj_id *obj, osd_id initial_id, - struct osd_obj_id_list *list, unsigned nelem) -{ - struct request_queue *q = osd_request_queue(or->osd_dev); - u64 len = nelem * sizeof(osd_id) + sizeof(*list); - struct bio *bio; - - _osd_req_encode_common(or, action, obj, (u64)initial_id, len); - - if (list->list_identifier) - _osd_req_encode_olist(or, list); - - WARN_ON(or->in.bio); - bio = bio_map_kern(q, list, len, or->alloc_flags); - if (IS_ERR(bio)) { - OSD_ERR("!!! Failed to allocate list_objects BIO\n"); - return PTR_ERR(bio); - } - - bio->bi_rw &= ~REQ_WRITE; - or->in.bio = bio; - or->in.total_bytes = bio->bi_size; - return 0; -} - -int osd_req_list_partition_collections(struct osd_request *or, - osd_id partition, osd_id initial_id, struct osd_obj_id_list *list, - unsigned nelem) -{ - struct osd_obj_id par = { - .partition = partition, - .id = 0, - }; - - return osd_req_list_collection_objects(or, &par, initial_id, list, - nelem); -} -EXPORT_SYMBOL(osd_req_list_partition_collections); - -int osd_req_list_partition_objects(struct osd_request *or, - osd_id partition, osd_id initial_id, struct osd_obj_id_list *list, - unsigned nelem) -{ - struct osd_obj_id par = { - .partition = partition, - .id = 0, - }; - - return _osd_req_list_objects(or, OSD_ACT_LIST, &par, initial_id, list, - nelem); -} -EXPORT_SYMBOL(osd_req_list_partition_objects); - -void osd_req_flush_partition(struct osd_request *or, - osd_id partition, enum osd_options_flush_scope_values op) -{ - _osd_req_encode_partition(or, OSD_ACT_FLUSH_PARTITION, partition); - _osd_req_encode_flush(or, op); -} -EXPORT_SYMBOL(osd_req_flush_partition); - -/* - * Collection commands - */ -/*TODO: void osd_req_create_collection(struct osd_request *, - const struct osd_obj_id *); */ -/*TODO: void osd_req_remove_collection(struct osd_request *, - const struct osd_obj_id *); */ - -int osd_req_list_collection_objects(struct osd_request *or, - const struct osd_obj_id *obj, osd_id initial_id, - struct osd_obj_id_list *list, unsigned nelem) -{ - return _osd_req_list_objects(or, OSD_ACT_LIST_COLLECTION, obj, - initial_id, list, nelem); -} -EXPORT_SYMBOL(osd_req_list_collection_objects); - -/*TODO: void query(struct osd_request *, ...); V2 */ - -void osd_req_flush_collection(struct osd_request *or, - const struct osd_obj_id *obj, enum osd_options_flush_scope_values op) -{ - _osd_req_encode_common(or, OSD_ACT_FLUSH_PARTITION, obj, 0, 0); - _osd_req_encode_flush(or, op); -} -EXPORT_SYMBOL(osd_req_flush_collection); - -/*TODO: void get_member_attrs(struct osd_request *, ...); V2 */ -/*TODO: void set_member_attrs(struct osd_request *, ...); V2 */ - -/* - * Object commands - */ -void osd_req_create_object(struct osd_request *or, struct osd_obj_id *obj) -{ - _osd_req_encode_common(or, OSD_ACT_CREATE, obj, 0, 0); -} -EXPORT_SYMBOL(osd_req_create_object); - -void osd_req_remove_object(struct osd_request *or, struct osd_obj_id *obj) -{ - _osd_req_encode_common(or, OSD_ACT_REMOVE, obj, 0, 0); -} -EXPORT_SYMBOL(osd_req_remove_object); - - -/*TODO: void osd_req_create_multi(struct osd_request *or, - struct osd_obj_id *first, struct osd_obj_id_list *list, unsigned nelem); -*/ - -void osd_req_write(struct osd_request *or, - const struct osd_obj_id *obj, u64 offset, - struct bio *bio, u64 len) -{ - _osd_req_encode_common(or, OSD_ACT_WRITE, obj, offset, len); - WARN_ON(or->out.bio || or->out.total_bytes); - WARN_ON(0 == (bio->bi_rw & REQ_WRITE)); - or->out.bio = bio; - or->out.total_bytes = len; -} -EXPORT_SYMBOL(osd_req_write); - -int osd_req_write_kern(struct osd_request *or, - const struct osd_obj_id *obj, u64 offset, void* buff, u64 len) -{ - struct request_queue *req_q = osd_request_queue(or->osd_dev); - struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL); - - if (IS_ERR(bio)) - return PTR_ERR(bio); - - bio->bi_rw |= REQ_WRITE; /* FIXME: bio_set_dir() */ - osd_req_write(or, obj, offset, bio, len); - return 0; -} -EXPORT_SYMBOL(osd_req_write_kern); - -/*TODO: void osd_req_append(struct osd_request *, - const struct osd_obj_id *, struct bio *data_out); */ -/*TODO: void osd_req_create_write(struct osd_request *, - const struct osd_obj_id *, struct bio *data_out, u64 offset); */ -/*TODO: void osd_req_clear(struct osd_request *, - const struct osd_obj_id *, u64 offset, u64 len); */ -/*TODO: void osd_req_punch(struct osd_request *, - const struct osd_obj_id *, u64 offset, u64 len); V2 */ - -void osd_req_flush_object(struct osd_request *or, - const struct osd_obj_id *obj, enum osd_options_flush_scope_values op, - /*V2*/ u64 offset, /*V2*/ u64 len) -{ - if (unlikely(osd_req_is_ver1(or) && (offset || len))) { - OSD_DEBUG("OSD Ver1 flush on specific range ignored\n"); - offset = 0; - len = 0; - } - - _osd_req_encode_common(or, OSD_ACT_FLUSH, obj, offset, len); - _osd_req_encode_flush(or, op); -} -EXPORT_SYMBOL(osd_req_flush_object); - -void osd_req_read(struct osd_request *or, - const struct osd_obj_id *obj, u64 offset, - struct bio *bio, u64 len) -{ - _osd_req_encode_common(or, OSD_ACT_READ, obj, offset, len); - WARN_ON(or->in.bio || or->in.total_bytes); - WARN_ON(bio->bi_rw & REQ_WRITE); - or->in.bio = bio; - or->in.total_bytes = len; -} -EXPORT_SYMBOL(osd_req_read); - -int osd_req_read_kern(struct osd_request *or, - const struct osd_obj_id *obj, u64 offset, void* buff, u64 len) -{ - struct request_queue *req_q = osd_request_queue(or->osd_dev); - struct bio *bio = bio_map_kern(req_q, buff, len, GFP_KERNEL); - - if (IS_ERR(bio)) - return PTR_ERR(bio); - - osd_req_read(or, obj, offset, bio, len); - return 0; -} -EXPORT_SYMBOL(osd_req_read_kern); - -static int _add_sg_continuation_descriptor(struct osd_request *or, - const struct osd_sg_entry *sglist, unsigned numentries, u64 *len) -{ - struct osd_sg_continuation_descriptor *oscd; - u32 oscd_size; - unsigned i; - int ret; - - oscd_size = sizeof(*oscd) + numentries * sizeof(oscd->entries[0]); - - if (!or->cdb_cont.total_bytes) { - /* First time, jump over the header, we will write to: - * cdb_cont.buff + cdb_cont.total_bytes - */ - or->cdb_cont.total_bytes = - sizeof(struct osd_continuation_segment_header); - } - - ret = _alloc_cdb_cont(or, or->cdb_cont.total_bytes + oscd_size); - if (unlikely(ret)) - return ret; - - oscd = or->cdb_cont.buff + or->cdb_cont.total_bytes; - oscd->hdr.type = cpu_to_be16(SCATTER_GATHER_LIST); - oscd->hdr.pad_length = 0; - oscd->hdr.length = cpu_to_be32(oscd_size - sizeof(*oscd)); - - *len = 0; - /* copy the sg entries and convert to network byte order */ - for (i = 0; i < numentries; i++) { - oscd->entries[i].offset = cpu_to_be64(sglist[i].offset); - oscd->entries[i].len = cpu_to_be64(sglist[i].len); - *len += sglist[i].len; - } - - or->cdb_cont.total_bytes += oscd_size; - OSD_DEBUG("total_bytes=%d oscd_size=%d numentries=%d\n", - or->cdb_cont.total_bytes, oscd_size, numentries); - return 0; -} - -static int _osd_req_finalize_cdb_cont(struct osd_request *or, const u8 *cap_key) -{ - struct request_queue *req_q = osd_request_queue(or->osd_dev); - struct bio *bio; - struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); - struct osd_continuation_segment_header *cont_seg_hdr; - - if (!or->cdb_cont.total_bytes) - return 0; - - cont_seg_hdr = or->cdb_cont.buff; - cont_seg_hdr->format = CDB_CONTINUATION_FORMAT_V2; - cont_seg_hdr->service_action = cdbh->varlen_cdb.service_action; - - /* create a bio for continuation segment */ - bio = bio_map_kern(req_q, or->cdb_cont.buff, or->cdb_cont.total_bytes, - GFP_KERNEL); - if (IS_ERR(bio)) - return PTR_ERR(bio); - - bio->bi_rw |= REQ_WRITE; - - /* integrity check the continuation before the bio is linked - * with the other data segments since the continuation - * integrity is separate from the other data segments. - */ - osd_sec_sign_data(cont_seg_hdr->integrity_check, bio, cap_key); - - cdbh->v2.cdb_continuation_length = cpu_to_be32(or->cdb_cont.total_bytes); - - /* we can't use _req_append_segment, because we need to link in the - * continuation bio to the head of the bio list - the - * continuation segment (if it exists) is always the first segment in - * the out data buffer. - */ - bio->bi_next = or->out.bio; - or->out.bio = bio; - or->out.total_bytes += or->cdb_cont.total_bytes; - - return 0; -} - -/* osd_req_write_sg: Takes a @bio that points to the data out buffer and an - * @sglist that has the scatter gather entries. Scatter-gather enables a write - * of multiple none-contiguous areas of an object, in a single call. The extents - * may overlap and/or be in any order. The only constrain is that: - * total_bytes(sglist) >= total_bytes(bio) - */ -int osd_req_write_sg(struct osd_request *or, - const struct osd_obj_id *obj, struct bio *bio, - const struct osd_sg_entry *sglist, unsigned numentries) -{ - u64 len; - int ret = _add_sg_continuation_descriptor(or, sglist, numentries, &len); - - if (ret) - return ret; - osd_req_write(or, obj, 0, bio, len); - - return 0; -} -EXPORT_SYMBOL(osd_req_write_sg); - -/* osd_req_read_sg: Read multiple extents of an object into @bio - * See osd_req_write_sg - */ -int osd_req_read_sg(struct osd_request *or, - const struct osd_obj_id *obj, struct bio *bio, - const struct osd_sg_entry *sglist, unsigned numentries) -{ - u64 len; - u64 off; - int ret; - - if (numentries > 1) { - off = 0; - ret = _add_sg_continuation_descriptor(or, sglist, numentries, - &len); - if (ret) - return ret; - } else { - /* Optimize the case of single segment, read_sg is a - * bidi operation. - */ - len = sglist->len; - off = sglist->offset; - } - osd_req_read(or, obj, off, bio, len); - - return 0; -} -EXPORT_SYMBOL(osd_req_read_sg); - -/* SG-list write/read Kern API - * - * osd_req_{write,read}_sg_kern takes an array of @buff pointers and an array - * of sg_entries. @numentries indicates how many pointers and sg_entries there - * are. By requiring an array of buff pointers. This allows a caller to do a - * single write/read and scatter into multiple buffers. - * NOTE: Each buffer + len should not cross a page boundary. - */ -static struct bio *_create_sg_bios(struct osd_request *or, - void **buff, const struct osd_sg_entry *sglist, unsigned numentries) -{ - struct request_queue *q = osd_request_queue(or->osd_dev); - struct bio *bio; - unsigned i; - - bio = bio_kmalloc(GFP_KERNEL, numentries); - if (unlikely(!bio)) { - OSD_DEBUG("Faild to allocate BIO size=%u\n", numentries); - return ERR_PTR(-ENOMEM); - } - - for (i = 0; i < numentries; i++) { - unsigned offset = offset_in_page(buff[i]); - struct page *page = virt_to_page(buff[i]); - unsigned len = sglist[i].len; - unsigned added_len; - - BUG_ON(offset + len > PAGE_SIZE); - added_len = bio_add_pc_page(q, bio, page, len, offset); - if (unlikely(len != added_len)) { - OSD_DEBUG("bio_add_pc_page len(%d) != added_len(%d)\n", - len, added_len); - bio_put(bio); - return ERR_PTR(-ENOMEM); - } - } - - return bio; -} - -int osd_req_write_sg_kern(struct osd_request *or, - const struct osd_obj_id *obj, void **buff, - const struct osd_sg_entry *sglist, unsigned numentries) -{ - struct bio *bio = _create_sg_bios(or, buff, sglist, numentries); - if (IS_ERR(bio)) - return PTR_ERR(bio); - - bio->bi_rw |= REQ_WRITE; - osd_req_write_sg(or, obj, bio, sglist, numentries); - - return 0; -} -EXPORT_SYMBOL(osd_req_write_sg_kern); - -int osd_req_read_sg_kern(struct osd_request *or, - const struct osd_obj_id *obj, void **buff, - const struct osd_sg_entry *sglist, unsigned numentries) -{ - struct bio *bio = _create_sg_bios(or, buff, sglist, numentries); - if (IS_ERR(bio)) - return PTR_ERR(bio); - - osd_req_read_sg(or, obj, bio, sglist, numentries); - - return 0; -} -EXPORT_SYMBOL(osd_req_read_sg_kern); - - - -void osd_req_get_attributes(struct osd_request *or, - const struct osd_obj_id *obj) -{ - _osd_req_encode_common(or, OSD_ACT_GET_ATTRIBUTES, obj, 0, 0); -} -EXPORT_SYMBOL(osd_req_get_attributes); - -void osd_req_set_attributes(struct osd_request *or, - const struct osd_obj_id *obj) -{ - _osd_req_encode_common(or, OSD_ACT_SET_ATTRIBUTES, obj, 0, 0); -} -EXPORT_SYMBOL(osd_req_set_attributes); - -/* - * Attributes List-mode - */ - -int osd_req_add_set_attr_list(struct osd_request *or, - const struct osd_attr *oa, unsigned nelem) -{ - unsigned total_bytes = or->set_attr.total_bytes; - void *attr_last; - int ret; - - if (or->attributes_mode && - or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) { - WARN_ON(1); - return -EINVAL; - } - or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS; - - if (!total_bytes) { /* first-time: allocate and put list header */ - total_bytes = _osd_req_sizeof_alist_header(or); - ret = _alloc_set_attr_list(or, oa, nelem, total_bytes); - if (ret) - return ret; - _osd_req_set_alist_type(or, or->set_attr.buff, - OSD_ATTR_LIST_SET_RETRIEVE); - } - attr_last = or->set_attr.buff + total_bytes; - - for (; nelem; --nelem) { - unsigned elem_size = _osd_req_alist_elem_size(or, oa->len); - - total_bytes += elem_size; - if (unlikely(or->set_attr.alloc_size < total_bytes)) { - or->set_attr.total_bytes = total_bytes - elem_size; - ret = _alloc_set_attr_list(or, oa, nelem, total_bytes); - if (ret) - return ret; - attr_last = - or->set_attr.buff + or->set_attr.total_bytes; - } - - _osd_req_alist_elem_encode(or, attr_last, oa); - - attr_last += elem_size; - ++oa; - } - - or->set_attr.total_bytes = total_bytes; - return 0; -} -EXPORT_SYMBOL(osd_req_add_set_attr_list); - -static int _req_append_segment(struct osd_request *or, - unsigned padding, struct _osd_req_data_segment *seg, - struct _osd_req_data_segment *last_seg, struct _osd_io_info *io) -{ - void *pad_buff; - int ret; - - if (padding) { - /* check if we can just add it to last buffer */ - if (last_seg && - (padding <= last_seg->alloc_size - last_seg->total_bytes)) - pad_buff = last_seg->buff + last_seg->total_bytes; - else - pad_buff = io->pad_buff; - - ret = blk_rq_map_kern(io->req->q, io->req, pad_buff, padding, - or->alloc_flags); - if (ret) - return ret; - io->total_bytes += padding; - } - - ret = blk_rq_map_kern(io->req->q, io->req, seg->buff, seg->total_bytes, - or->alloc_flags); - if (ret) - return ret; - - io->total_bytes += seg->total_bytes; - OSD_DEBUG("padding=%d buff=%p total_bytes=%d\n", padding, seg->buff, - seg->total_bytes); - return 0; -} - -static int _osd_req_finalize_set_attr_list(struct osd_request *or) -{ - struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); - unsigned padding; - int ret; - - if (!or->set_attr.total_bytes) { - cdbh->attrs_list.set_attr_offset = OSD_OFFSET_UNUSED; - return 0; - } - - cdbh->attrs_list.set_attr_bytes = cpu_to_be32(or->set_attr.total_bytes); - cdbh->attrs_list.set_attr_offset = - osd_req_encode_offset(or, or->out.total_bytes, &padding); - - ret = _req_append_segment(or, padding, &or->set_attr, - or->out.last_seg, &or->out); - if (ret) - return ret; - - or->out.last_seg = &or->set_attr; - return 0; -} - -int osd_req_add_get_attr_list(struct osd_request *or, - const struct osd_attr *oa, unsigned nelem) -{ - unsigned total_bytes = or->enc_get_attr.total_bytes; - void *attr_last; - int ret; - - if (or->attributes_mode && - or->attributes_mode != OSD_CDB_GET_SET_ATTR_LISTS) { - WARN_ON(1); - return -EINVAL; - } - or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS; - - /* first time calc data-in list header size */ - if (!or->get_attr.total_bytes) - or->get_attr.total_bytes = _osd_req_sizeof_alist_header(or); - - /* calc data-out info */ - if (!total_bytes) { /* first-time: allocate and put list header */ - unsigned max_bytes; - - total_bytes = _osd_req_sizeof_alist_header(or); - max_bytes = total_bytes + - nelem * sizeof(struct osd_attributes_list_attrid); - ret = _alloc_get_attr_desc(or, max_bytes); - if (ret) - return ret; - - _osd_req_set_alist_type(or, or->enc_get_attr.buff, - OSD_ATTR_LIST_GET); - } - attr_last = or->enc_get_attr.buff + total_bytes; - - for (; nelem; --nelem) { - struct osd_attributes_list_attrid *attrid; - const unsigned cur_size = sizeof(*attrid); - - total_bytes += cur_size; - if (unlikely(or->enc_get_attr.alloc_size < total_bytes)) { - or->enc_get_attr.total_bytes = total_bytes - cur_size; - ret = _alloc_get_attr_desc(or, - total_bytes + nelem * sizeof(*attrid)); - if (ret) - return ret; - attr_last = or->enc_get_attr.buff + - or->enc_get_attr.total_bytes; - } - - attrid = attr_last; - attrid->attr_page = cpu_to_be32(oa->attr_page); - attrid->attr_id = cpu_to_be32(oa->attr_id); - - attr_last += cur_size; - - /* calc data-in size */ - or->get_attr.total_bytes += - _osd_req_alist_elem_size(or, oa->len); - ++oa; - } - - or->enc_get_attr.total_bytes = total_bytes; - - OSD_DEBUG( - "get_attr.total_bytes=%u(%u) enc_get_attr.total_bytes=%u(%Zu)\n", - or->get_attr.total_bytes, - or->get_attr.total_bytes - _osd_req_sizeof_alist_header(or), - or->enc_get_attr.total_bytes, - (or->enc_get_attr.total_bytes - _osd_req_sizeof_alist_header(or)) - / sizeof(struct osd_attributes_list_attrid)); - - return 0; -} -EXPORT_SYMBOL(osd_req_add_get_attr_list); - -static int _osd_req_finalize_get_attr_list(struct osd_request *or) -{ - struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); - unsigned out_padding; - unsigned in_padding; - int ret; - - if (!or->enc_get_attr.total_bytes) { - cdbh->attrs_list.get_attr_desc_offset = OSD_OFFSET_UNUSED; - cdbh->attrs_list.get_attr_offset = OSD_OFFSET_UNUSED; - return 0; - } - - ret = _alloc_get_attr_list(or); - if (ret) - return ret; - - /* The out-going buffer info update */ - OSD_DEBUG("out-going\n"); - cdbh->attrs_list.get_attr_desc_bytes = - cpu_to_be32(or->enc_get_attr.total_bytes); - - cdbh->attrs_list.get_attr_desc_offset = - osd_req_encode_offset(or, or->out.total_bytes, &out_padding); - - ret = _req_append_segment(or, out_padding, &or->enc_get_attr, - or->out.last_seg, &or->out); - if (ret) - return ret; - or->out.last_seg = &or->enc_get_attr; - - /* The incoming buffer info update */ - OSD_DEBUG("in-coming\n"); - cdbh->attrs_list.get_attr_alloc_length = - cpu_to_be32(or->get_attr.total_bytes); - - cdbh->attrs_list.get_attr_offset = - osd_req_encode_offset(or, or->in.total_bytes, &in_padding); - - ret = _req_append_segment(or, in_padding, &or->get_attr, NULL, - &or->in); - if (ret) - return ret; - or->in.last_seg = &or->get_attr; - - return 0; -} - -int osd_req_decode_get_attr_list(struct osd_request *or, - struct osd_attr *oa, int *nelem, void **iterator) -{ - unsigned cur_bytes, returned_bytes; - int n; - const unsigned sizeof_attr_list = _osd_req_sizeof_alist_header(or); - void *cur_p; - - if (!_osd_req_is_alist_type(or, or->get_attr.buff, - OSD_ATTR_LIST_SET_RETRIEVE)) { - oa->attr_page = 0; - oa->attr_id = 0; - oa->val_ptr = NULL; - oa->len = 0; - *iterator = NULL; - return 0; - } - - if (*iterator) { - BUG_ON((*iterator < or->get_attr.buff) || - (or->get_attr.buff + or->get_attr.alloc_size < *iterator)); - cur_p = *iterator; - cur_bytes = (*iterator - or->get_attr.buff) - sizeof_attr_list; - returned_bytes = or->get_attr.total_bytes; - } else { /* first time decode the list header */ - cur_bytes = sizeof_attr_list; - returned_bytes = _osd_req_alist_size(or, or->get_attr.buff) + - sizeof_attr_list; - - cur_p = or->get_attr.buff + sizeof_attr_list; - - if (returned_bytes > or->get_attr.alloc_size) { - OSD_DEBUG("target report: space was not big enough! " - "Allocate=%u Needed=%u\n", - or->get_attr.alloc_size, - returned_bytes + sizeof_attr_list); - - returned_bytes = - or->get_attr.alloc_size - sizeof_attr_list; - } - or->get_attr.total_bytes = returned_bytes; - } - - for (n = 0; (n < *nelem) && (cur_bytes < returned_bytes); ++n) { - int inc = _osd_req_alist_elem_decode(or, cur_p, oa, - returned_bytes - cur_bytes); - - if (inc < 0) { - OSD_ERR("BAD FOOD from target. list not valid!" - "c=%d r=%d n=%d\n", - cur_bytes, returned_bytes, n); - oa->val_ptr = NULL; - cur_bytes = returned_bytes; /* break the caller loop */ - break; - } - - cur_bytes += inc; - cur_p += inc; - ++oa; - } - - *iterator = (returned_bytes - cur_bytes) ? cur_p : NULL; - *nelem = n; - return returned_bytes - cur_bytes; -} -EXPORT_SYMBOL(osd_req_decode_get_attr_list); - -/* - * Attributes Page-mode - */ - -int osd_req_add_get_attr_page(struct osd_request *or, - u32 page_id, void *attar_page, unsigned max_page_len, - const struct osd_attr *set_one_attr) -{ - struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); - - if (or->attributes_mode && - or->attributes_mode != OSD_CDB_GET_ATTR_PAGE_SET_ONE) { - WARN_ON(1); - return -EINVAL; - } - or->attributes_mode = OSD_CDB_GET_ATTR_PAGE_SET_ONE; - - or->get_attr.buff = attar_page; - or->get_attr.total_bytes = max_page_len; - - cdbh->attrs_page.get_attr_page = cpu_to_be32(page_id); - cdbh->attrs_page.get_attr_alloc_length = cpu_to_be32(max_page_len); - - if (!set_one_attr || !set_one_attr->attr_page) - return 0; /* The set is optional */ - - or->set_attr.buff = set_one_attr->val_ptr; - or->set_attr.total_bytes = set_one_attr->len; - - cdbh->attrs_page.set_attr_page = cpu_to_be32(set_one_attr->attr_page); - cdbh->attrs_page.set_attr_id = cpu_to_be32(set_one_attr->attr_id); - cdbh->attrs_page.set_attr_length = cpu_to_be32(set_one_attr->len); - return 0; -} -EXPORT_SYMBOL(osd_req_add_get_attr_page); - -static int _osd_req_finalize_attr_page(struct osd_request *or) -{ - struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); - unsigned in_padding, out_padding; - int ret; - - /* returned page */ - cdbh->attrs_page.get_attr_offset = - osd_req_encode_offset(or, or->in.total_bytes, &in_padding); - - ret = _req_append_segment(or, in_padding, &or->get_attr, NULL, - &or->in); - if (ret) - return ret; - - if (or->set_attr.total_bytes == 0) - return 0; - - /* set one value */ - cdbh->attrs_page.set_attr_offset = - osd_req_encode_offset(or, or->out.total_bytes, &out_padding); - - ret = _req_append_segment(or, out_padding, &or->set_attr, NULL, - &or->out); - return ret; -} - -static inline void osd_sec_parms_set_out_offset(bool is_v1, - struct osd_security_parameters *sec_parms, osd_cdb_offset offset) -{ - if (is_v1) - sec_parms->v1.data_out_integrity_check_offset = offset; - else - sec_parms->v2.data_out_integrity_check_offset = offset; -} - -static inline void osd_sec_parms_set_in_offset(bool is_v1, - struct osd_security_parameters *sec_parms, osd_cdb_offset offset) -{ - if (is_v1) - sec_parms->v1.data_in_integrity_check_offset = offset; - else - sec_parms->v2.data_in_integrity_check_offset = offset; -} - -static int _osd_req_finalize_data_integrity(struct osd_request *or, - bool has_in, bool has_out, struct bio *out_data_bio, u64 out_data_bytes, - const u8 *cap_key) -{ - struct osd_security_parameters *sec_parms = _osd_req_sec_params(or); - int ret; - - if (!osd_is_sec_alldata(sec_parms)) - return 0; - - if (has_out) { - struct _osd_req_data_segment seg = { - .buff = &or->out_data_integ, - .total_bytes = sizeof(or->out_data_integ), - }; - unsigned pad; - - or->out_data_integ.data_bytes = cpu_to_be64(out_data_bytes); - or->out_data_integ.set_attributes_bytes = cpu_to_be64( - or->set_attr.total_bytes); - or->out_data_integ.get_attributes_bytes = cpu_to_be64( - or->enc_get_attr.total_bytes); - - osd_sec_parms_set_out_offset(osd_req_is_ver1(or), sec_parms, - osd_req_encode_offset(or, or->out.total_bytes, &pad)); - - ret = _req_append_segment(or, pad, &seg, or->out.last_seg, - &or->out); - if (ret) - return ret; - or->out.last_seg = NULL; - - /* they are now all chained to request sign them all together */ - osd_sec_sign_data(&or->out_data_integ, out_data_bio, - cap_key); - } - - if (has_in) { - struct _osd_req_data_segment seg = { - .buff = &or->in_data_integ, - .total_bytes = sizeof(or->in_data_integ), - }; - unsigned pad; - - osd_sec_parms_set_in_offset(osd_req_is_ver1(or), sec_parms, - osd_req_encode_offset(or, or->in.total_bytes, &pad)); - - ret = _req_append_segment(or, pad, &seg, or->in.last_seg, - &or->in); - if (ret) - return ret; - - or->in.last_seg = NULL; - } - - return 0; -} - -/* - * osd_finalize_request and helpers - */ -static struct request *_make_request(struct request_queue *q, bool has_write, - struct _osd_io_info *oii, gfp_t flags) -{ - if (oii->bio) - return blk_make_request(q, oii->bio, flags); - else { - struct request *req; - - req = blk_get_request(q, has_write ? WRITE : READ, flags); - if (unlikely(!req)) - return ERR_PTR(-ENOMEM); - - return req; - } -} - -static int _init_blk_request(struct osd_request *or, - bool has_in, bool has_out) -{ - gfp_t flags = or->alloc_flags; - struct scsi_device *scsi_device = or->osd_dev->scsi_device; - struct request_queue *q = scsi_device->request_queue; - struct request *req; - int ret; - - req = _make_request(q, has_out, has_out ? &or->out : &or->in, flags); - if (IS_ERR(req)) { - ret = PTR_ERR(req); - goto out; - } - - or->request = req; - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_QUIET; - - req->timeout = or->timeout; - req->retries = or->retries; - req->sense = or->sense; - req->sense_len = 0; - - if (has_out) { - or->out.req = req; - if (has_in) { - /* allocate bidi request */ - req = _make_request(q, false, &or->in, flags); - if (IS_ERR(req)) { - OSD_DEBUG("blk_get_request for bidi failed\n"); - ret = PTR_ERR(req); - goto out; - } - req->cmd_type = REQ_TYPE_BLOCK_PC; - or->in.req = or->request->next_rq = req; - } - } else if (has_in) - or->in.req = req; - - ret = 0; -out: - OSD_DEBUG("or=%p has_in=%d has_out=%d => %d, %p\n", - or, has_in, has_out, ret, or->request); - return ret; -} - -int osd_finalize_request(struct osd_request *or, - u8 options, const void *cap, const u8 *cap_key) -{ - struct osd_cdb_head *cdbh = osd_cdb_head(&or->cdb); - bool has_in, has_out; - /* Save for data_integrity without the cdb_continuation */ - struct bio *out_data_bio = or->out.bio; - u64 out_data_bytes = or->out.total_bytes; - int ret; - - if (options & OSD_REQ_FUA) - cdbh->options |= OSD_CDB_FUA; - - if (options & OSD_REQ_DPO) - cdbh->options |= OSD_CDB_DPO; - - if (options & OSD_REQ_BYPASS_TIMESTAMPS) - cdbh->timestamp_control = OSD_CDB_BYPASS_TIMESTAMPS; - - osd_set_caps(&or->cdb, cap); - - has_in = or->in.bio || or->get_attr.total_bytes; - has_out = or->out.bio || or->cdb_cont.total_bytes || - or->set_attr.total_bytes || or->enc_get_attr.total_bytes; - - ret = _osd_req_finalize_cdb_cont(or, cap_key); - if (ret) { - OSD_DEBUG("_osd_req_finalize_cdb_cont failed\n"); - return ret; - } - ret = _init_blk_request(or, has_in, has_out); - if (ret) { - OSD_DEBUG("_init_blk_request failed\n"); - return ret; - } - - or->out.pad_buff = sg_out_pad_buffer; - or->in.pad_buff = sg_in_pad_buffer; - - if (!or->attributes_mode) - or->attributes_mode = OSD_CDB_GET_SET_ATTR_LISTS; - cdbh->command_specific_options |= or->attributes_mode; - if (or->attributes_mode == OSD_CDB_GET_ATTR_PAGE_SET_ONE) { - ret = _osd_req_finalize_attr_page(or); - if (ret) { - OSD_DEBUG("_osd_req_finalize_attr_page failed\n"); - return ret; - } - } else { - /* TODO: I think that for the GET_ATTR command these 2 should - * be reversed to keep them in execution order (for embeded - * targets with low memory footprint) - */ - ret = _osd_req_finalize_set_attr_list(or); - if (ret) { - OSD_DEBUG("_osd_req_finalize_set_attr_list failed\n"); - return ret; - } - - ret = _osd_req_finalize_get_attr_list(or); - if (ret) { - OSD_DEBUG("_osd_req_finalize_get_attr_list failed\n"); - return ret; - } - } - - ret = _osd_req_finalize_data_integrity(or, has_in, has_out, - out_data_bio, out_data_bytes, - cap_key); - if (ret) - return ret; - - osd_sec_sign_cdb(&or->cdb, cap_key); - - or->request->cmd = or->cdb.buff; - or->request->cmd_len = _osd_req_cdb_len(or); - - return 0; -} -EXPORT_SYMBOL(osd_finalize_request); - -static bool _is_osd_security_code(int code) -{ - return (code == osd_security_audit_value_frozen) || - (code == osd_security_working_key_frozen) || - (code == osd_nonce_not_unique) || - (code == osd_nonce_timestamp_out_of_range) || - (code == osd_invalid_dataout_buffer_integrity_check_value); -} - -#define OSD_SENSE_PRINT1(fmt, a...) \ - do { \ - if (__cur_sense_need_output) \ - OSD_ERR(fmt, ##a); \ - } while (0) - -#define OSD_SENSE_PRINT2(fmt, a...) OSD_SENSE_PRINT1(" " fmt, ##a) - -int osd_req_decode_sense_full(struct osd_request *or, - struct osd_sense_info *osi, bool silent, - struct osd_obj_id *bad_obj_list __unused, int max_obj __unused, - struct osd_attr *bad_attr_list, int max_attr) -{ - int sense_len, original_sense_len; - struct osd_sense_info local_osi; - struct scsi_sense_descriptor_based *ssdb; - void *cur_descriptor; -#if (CONFIG_SCSI_OSD_DPRINT_SENSE == 0) - const bool __cur_sense_need_output = false; -#else - bool __cur_sense_need_output = !silent; -#endif - int ret; - - if (likely(!or->req_errors)) - return 0; - - osi = osi ? : &local_osi; - memset(osi, 0, sizeof(*osi)); - - ssdb = (typeof(ssdb))or->sense; - sense_len = or->sense_len; - if ((sense_len < (int)sizeof(*ssdb) || !ssdb->sense_key)) { - OSD_ERR("Block-layer returned error(0x%x) but " - "sense_len(%u) || key(%d) is empty\n", - or->req_errors, sense_len, ssdb->sense_key); - goto analyze; - } - - if ((ssdb->response_code != 0x72) && (ssdb->response_code != 0x73)) { - OSD_ERR("Unrecognized scsi sense: rcode=%x length=%d\n", - ssdb->response_code, sense_len); - goto analyze; - } - - osi->key = ssdb->sense_key; - osi->additional_code = be16_to_cpu(ssdb->additional_sense_code); - original_sense_len = ssdb->additional_sense_length + 8; - -#if (CONFIG_SCSI_OSD_DPRINT_SENSE == 1) - if (__cur_sense_need_output) - __cur_sense_need_output = (osi->key > scsi_sk_recovered_error); -#endif - OSD_SENSE_PRINT1("Main Sense information key=0x%x length(%d, %d) " - "additional_code=0x%x async_error=%d errors=0x%x\n", - osi->key, original_sense_len, sense_len, - osi->additional_code, or->async_error, - or->req_errors); - - if (original_sense_len < sense_len) - sense_len = original_sense_len; - - cur_descriptor = ssdb->ssd; - sense_len -= sizeof(*ssdb); - while (sense_len > 0) { - struct scsi_sense_descriptor *ssd = cur_descriptor; - int cur_len = ssd->additional_length + 2; - - sense_len -= cur_len; - - if (sense_len < 0) - break; /* sense was truncated */ - - switch (ssd->descriptor_type) { - case scsi_sense_information: - case scsi_sense_command_specific_information: - { - struct scsi_sense_command_specific_data_descriptor - *sscd = cur_descriptor; - - osi->command_info = - get_unaligned_be64(&sscd->information) ; - OSD_SENSE_PRINT2( - "command_specific_information 0x%llx \n", - _LLU(osi->command_info)); - break; - } - case scsi_sense_key_specific: - { - struct scsi_sense_key_specific_data_descriptor - *ssks = cur_descriptor; - - osi->sense_info = get_unaligned_be16(&ssks->value); - OSD_SENSE_PRINT2( - "sense_key_specific_information %u" - "sksv_cd_bpv_bp (0x%x)\n", - osi->sense_info, ssks->sksv_cd_bpv_bp); - break; - } - case osd_sense_object_identification: - { /*FIXME: Keep first not last, Store in array*/ - struct osd_sense_identification_data_descriptor - *osidd = cur_descriptor; - - osi->not_initiated_command_functions = - le32_to_cpu(osidd->not_initiated_functions); - osi->completed_command_functions = - le32_to_cpu(osidd->completed_functions); - osi->obj.partition = be64_to_cpu(osidd->partition_id); - osi->obj.id = be64_to_cpu(osidd->object_id); - OSD_SENSE_PRINT2( - "object_identification pid=0x%llx oid=0x%llx\n", - _LLU(osi->obj.partition), _LLU(osi->obj.id)); - OSD_SENSE_PRINT2( - "not_initiated_bits(%x) " - "completed_command_bits(%x)\n", - osi->not_initiated_command_functions, - osi->completed_command_functions); - break; - } - case osd_sense_response_integrity_check: - { - struct osd_sense_response_integrity_check_descriptor - *osricd = cur_descriptor; - const unsigned len = - sizeof(osricd->integrity_check_value); - char key_dump[len*4 + 2]; /* 2nibbles+space+ASCII */ - - hex_dump_to_buffer(osricd->integrity_check_value, len, - 32, 1, key_dump, sizeof(key_dump), true); - OSD_SENSE_PRINT2("response_integrity [%s]\n", key_dump); - } - case osd_sense_attribute_identification: - { - struct osd_sense_attributes_data_descriptor - *osadd = cur_descriptor; - unsigned len = min(cur_len, sense_len); - struct osd_sense_attr *pattr = osadd->sense_attrs; - - while (len >= sizeof(*pattr)) { - u32 attr_page = be32_to_cpu(pattr->attr_page); - u32 attr_id = be32_to_cpu(pattr->attr_id); - - if (!osi->attr.attr_page) { - osi->attr.attr_page = attr_page; - osi->attr.attr_id = attr_id; - } - - if (bad_attr_list && max_attr) { - bad_attr_list->attr_page = attr_page; - bad_attr_list->attr_id = attr_id; - bad_attr_list++; - max_attr--; - } - - len -= sizeof(*pattr); - OSD_SENSE_PRINT2( - "osd_sense_attribute_identification" - "attr_page=0x%x attr_id=0x%x\n", - attr_page, attr_id); - } - } - /*These are not legal for OSD*/ - case scsi_sense_field_replaceable_unit: - OSD_SENSE_PRINT2("scsi_sense_field_replaceable_unit\n"); - break; - case scsi_sense_stream_commands: - OSD_SENSE_PRINT2("scsi_sense_stream_commands\n"); - break; - case scsi_sense_block_commands: - OSD_SENSE_PRINT2("scsi_sense_block_commands\n"); - break; - case scsi_sense_ata_return: - OSD_SENSE_PRINT2("scsi_sense_ata_return\n"); - break; - default: - if (ssd->descriptor_type <= scsi_sense_Reserved_last) - OSD_SENSE_PRINT2( - "scsi_sense Reserved descriptor (0x%x)", - ssd->descriptor_type); - else - OSD_SENSE_PRINT2( - "scsi_sense Vendor descriptor (0x%x)", - ssd->descriptor_type); - } - - cur_descriptor += cur_len; - } - -analyze: - if (!osi->key) { - /* scsi sense is Empty, the request was never issued to target - * linux return code might tell us what happened. - */ - if (or->async_error == -ENOMEM) - osi->osd_err_pri = OSD_ERR_PRI_RESOURCE; - else - osi->osd_err_pri = OSD_ERR_PRI_UNREACHABLE; - ret = or->async_error; - } else if (osi->key <= scsi_sk_recovered_error) { - osi->osd_err_pri = 0; - ret = 0; - } else if (osi->additional_code == scsi_invalid_field_in_cdb) { - if (osi->cdb_field_offset == OSD_CFO_STARTING_BYTE) { - osi->osd_err_pri = OSD_ERR_PRI_CLEAR_PAGES; - ret = -EFAULT; /* caller should recover from this */ - } else if (osi->cdb_field_offset == OSD_CFO_OBJECT_ID) { - osi->osd_err_pri = OSD_ERR_PRI_NOT_FOUND; - ret = -ENOENT; - } else if (osi->cdb_field_offset == OSD_CFO_PERMISSIONS) { - osi->osd_err_pri = OSD_ERR_PRI_NO_ACCESS; - ret = -EACCES; - } else { - osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED; - ret = -EINVAL; - } - } else if (osi->additional_code == osd_quota_error) { - osi->osd_err_pri = OSD_ERR_PRI_NO_SPACE; - ret = -ENOSPC; - } else if (_is_osd_security_code(osi->additional_code)) { - osi->osd_err_pri = OSD_ERR_PRI_BAD_CRED; - ret = -EINVAL; - } else { - osi->osd_err_pri = OSD_ERR_PRI_EIO; - ret = -EIO; - } - - if (!or->out.residual) - or->out.residual = or->out.total_bytes; - if (!or->in.residual) - or->in.residual = or->in.total_bytes; - - return ret; -} -EXPORT_SYMBOL(osd_req_decode_sense_full); - -/* - * Implementation of osd_sec.h API - * TODO: Move to a separate osd_sec.c file at a later stage. - */ - -enum { OSD_SEC_CAP_V1_ALL_CAPS = - OSD_SEC_CAP_APPEND | OSD_SEC_CAP_OBJ_MGMT | OSD_SEC_CAP_REMOVE | - OSD_SEC_CAP_CREATE | OSD_SEC_CAP_SET_ATTR | OSD_SEC_CAP_GET_ATTR | - OSD_SEC_CAP_WRITE | OSD_SEC_CAP_READ | OSD_SEC_CAP_POL_SEC | - OSD_SEC_CAP_GLOBAL | OSD_SEC_CAP_DEV_MGMT -}; - -enum { OSD_SEC_CAP_V2_ALL_CAPS = - OSD_SEC_CAP_V1_ALL_CAPS | OSD_SEC_CAP_QUERY | OSD_SEC_CAP_M_OBJECT -}; - -void osd_sec_init_nosec_doall_caps(void *caps, - const struct osd_obj_id *obj, bool is_collection, const bool is_v1) -{ - struct osd_capability *cap = caps; - u8 type; - u8 descriptor_type; - - if (likely(obj->id)) { - if (unlikely(is_collection)) { - type = OSD_SEC_OBJ_COLLECTION; - descriptor_type = is_v1 ? OSD_SEC_OBJ_DESC_OBJ : - OSD_SEC_OBJ_DESC_COL; - } else { - type = OSD_SEC_OBJ_USER; - descriptor_type = OSD_SEC_OBJ_DESC_OBJ; - } - WARN_ON(!obj->partition); - } else { - type = obj->partition ? OSD_SEC_OBJ_PARTITION : - OSD_SEC_OBJ_ROOT; - descriptor_type = OSD_SEC_OBJ_DESC_PAR; - } - - memset(cap, 0, sizeof(*cap)); - - cap->h.format = OSD_SEC_CAP_FORMAT_VER1; - cap->h.integrity_algorithm__key_version = 0; /* MAKE_BYTE(0, 0); */ - cap->h.security_method = OSD_SEC_NOSEC; -/* cap->expiration_time; - cap->AUDIT[30-10]; - cap->discriminator[42-30]; - cap->object_created_time; */ - cap->h.object_type = type; - osd_sec_set_caps(&cap->h, OSD_SEC_CAP_V1_ALL_CAPS); - cap->h.object_descriptor_type = descriptor_type; - cap->od.obj_desc.policy_access_tag = 0; - cap->od.obj_desc.allowed_partition_id = cpu_to_be64(obj->partition); - cap->od.obj_desc.allowed_object_id = cpu_to_be64(obj->id); -} -EXPORT_SYMBOL(osd_sec_init_nosec_doall_caps); - -/* FIXME: Extract version from caps pointer. - * Also Pete's target only supports caps from OSDv1 for now - */ -void osd_set_caps(struct osd_cdb *cdb, const void *caps) -{ - bool is_ver1 = true; - /* NOTE: They start at same address */ - memcpy(&cdb->v1.caps, caps, is_ver1 ? OSDv1_CAP_LEN : OSD_CAP_LEN); -} - -bool osd_is_sec_alldata(struct osd_security_parameters *sec_parms __unused) -{ - return false; -} - -void osd_sec_sign_cdb(struct osd_cdb *ocdb __unused, const u8 *cap_key __unused) -{ -} - -void osd_sec_sign_data(void *data_integ __unused, - struct bio *bio __unused, const u8 *cap_key __unused) -{ -} - -/* - * Declared in osd_protocol.h - * 4.12.5 Data-In and Data-Out buffer offsets - * byte offset = mantissa * (2^(exponent+8)) - * Returns the smallest allowed encoded offset that contains given @offset - * The actual encoded offset returned is @offset + *@padding. - */ -osd_cdb_offset __osd_encode_offset( - u64 offset, unsigned *padding, int min_shift, int max_shift) -{ - u64 try_offset = -1, mod, align; - osd_cdb_offset be32_offset; - int shift; - - *padding = 0; - if (!offset) - return 0; - - for (shift = min_shift; shift < max_shift; ++shift) { - try_offset = offset >> shift; - if (try_offset < (1 << OSD_OFFSET_MAX_BITS)) - break; - } - - BUG_ON(shift == max_shift); - - align = 1 << shift; - mod = offset & (align - 1); - if (mod) { - *padding = align - mod; - try_offset += 1; - } - - try_offset |= ((shift - 8) & 0xf) << 28; - be32_offset = cpu_to_be32((u32)try_offset); - - OSD_DEBUG("offset=%llu mantissa=%llu exp=%d encoded=%x pad=%d\n", - _LLU(offset), _LLU(try_offset & 0x0FFFFFFF), shift, - be32_offset, *padding); - return be32_offset; -} diff --git a/ANDROID_3.4.5/drivers/scsi/osd/osd_uld.c b/ANDROID_3.4.5/drivers/scsi/osd/osd_uld.c deleted file mode 100644 index d4ed9eb5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osd/osd_uld.c +++ /dev/null @@ -1,571 +0,0 @@ -/* - * osd_uld.c - OSD Upper Layer Driver - * - * A Linux driver module that registers as a SCSI ULD and probes - * for OSD type SCSI devices. - * It's main function is to export osd devices to in-kernel users like - * osdfs and pNFS-objects-LD. It also provides one ioctl for running - * in Kernel tests. - * - * Copyright (C) 2008 Panasas Inc. All rights reserved. - * - * Authors: - * Boaz Harrosh - * Benny Halevy - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Panasas company nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#include "osd_debug.h" - -#ifndef TYPE_OSD -# define TYPE_OSD 0x11 -#endif - -#ifndef SCSI_OSD_MAJOR -# define SCSI_OSD_MAJOR 260 -#endif -#define SCSI_OSD_MAX_MINOR MINORMASK - -static const char osd_name[] = "osd"; -static const char *osd_version_string = "open-osd 0.2.1"; - -MODULE_AUTHOR("Boaz Harrosh "); -MODULE_DESCRIPTION("open-osd Upper-Layer-Driver osd.ko"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(SCSI_OSD_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_OSD); - -struct osd_uld_device { - int minor; - struct device class_dev; - struct cdev cdev; - struct osd_dev od; - struct osd_dev_info odi; - struct gendisk *disk; -}; - -struct osd_dev_handle { - struct osd_dev od; - struct file *file; - struct osd_uld_device *oud; -} ; - -static DEFINE_IDA(osd_minor_ida); - -static struct class osd_uld_class = { - .owner = THIS_MODULE, - .name = "scsi_osd", -}; - -/* - * Char Device operations - */ - -static int osd_uld_open(struct inode *inode, struct file *file) -{ - struct osd_uld_device *oud = container_of(inode->i_cdev, - struct osd_uld_device, cdev); - - get_device(&oud->class_dev); - /* cache osd_uld_device on file handle */ - file->private_data = oud; - OSD_DEBUG("osd_uld_open %p\n", oud); - return 0; -} - -static int osd_uld_release(struct inode *inode, struct file *file) -{ - struct osd_uld_device *oud = file->private_data; - - OSD_DEBUG("osd_uld_release %p\n", file->private_data); - file->private_data = NULL; - put_device(&oud->class_dev); - return 0; -} - -/* FIXME: Only one vector for now */ -unsigned g_test_ioctl; -do_test_fn *g_do_test; - -int osduld_register_test(unsigned ioctl, do_test_fn *do_test) -{ - if (g_test_ioctl) - return -EINVAL; - - g_test_ioctl = ioctl; - g_do_test = do_test; - return 0; -} -EXPORT_SYMBOL(osduld_register_test); - -void osduld_unregister_test(unsigned ioctl) -{ - if (ioctl == g_test_ioctl) { - g_test_ioctl = 0; - g_do_test = NULL; - } -} -EXPORT_SYMBOL(osduld_unregister_test); - -static do_test_fn *_find_ioctl(unsigned cmd) -{ - if (g_test_ioctl == cmd) - return g_do_test; - else - return NULL; -} - -static long osd_uld_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct osd_uld_device *oud = file->private_data; - int ret; - do_test_fn *do_test; - - do_test = _find_ioctl(cmd); - if (do_test) - ret = do_test(&oud->od, cmd, arg); - else { - OSD_ERR("Unknown ioctl %d: osd_uld_device=%p\n", cmd, oud); - ret = -ENOIOCTLCMD; - } - return ret; -} - -static const struct file_operations osd_fops = { - .owner = THIS_MODULE, - .open = osd_uld_open, - .release = osd_uld_release, - .unlocked_ioctl = osd_uld_ioctl, - .llseek = noop_llseek, -}; - -struct osd_dev *osduld_path_lookup(const char *name) -{ - struct osd_uld_device *oud; - struct osd_dev_handle *odh; - struct file *file; - int error; - - if (!name || !*name) { - OSD_ERR("Mount with !path || !*path\n"); - return ERR_PTR(-EINVAL); - } - - odh = kzalloc(sizeof(*odh), GFP_KERNEL); - if (unlikely(!odh)) - return ERR_PTR(-ENOMEM); - - file = filp_open(name, O_RDWR, 0); - if (IS_ERR(file)) { - error = PTR_ERR(file); - goto free_od; - } - - if (file->f_op != &osd_fops){ - error = -EINVAL; - goto close_file; - } - - oud = file->private_data; - - odh->od = oud->od; - odh->file = file; - odh->oud = oud; - - return &odh->od; - -close_file: - fput(file); -free_od: - kfree(odh); - return ERR_PTR(error); -} -EXPORT_SYMBOL(osduld_path_lookup); - -static inline bool _the_same_or_null(const u8 *a1, unsigned a1_len, - const u8 *a2, unsigned a2_len) -{ - if (!a2_len) /* User string is Empty means don't care */ - return true; - - if (a1_len != a2_len) - return false; - - return 0 == memcmp(a1, a2, a1_len); -} - -struct find_oud_t { - const struct osd_dev_info *odi; - struct device *dev; - struct osd_uld_device *oud; -} ; - -int _mach_odi(struct device *dev, void *find_data) -{ - struct osd_uld_device *oud = container_of(dev, struct osd_uld_device, - class_dev); - struct find_oud_t *fot = find_data; - const struct osd_dev_info *odi = fot->odi; - - if (_the_same_or_null(oud->odi.systemid, oud->odi.systemid_len, - odi->systemid, odi->systemid_len) && - _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len, - odi->osdname, odi->osdname_len)) { - OSD_DEBUG("found device sysid_len=%d osdname=%d\n", - odi->systemid_len, odi->osdname_len); - fot->oud = oud; - return 1; - } else { - return 0; - } -} - -/* osduld_info_lookup - Loop through all devices, return the requested osd_dev. - * - * if @odi->systemid_len and/or @odi->osdname_len are zero, they act as a don't - * care. .e.g if they're both zero /dev/osd0 is returned. - */ -struct osd_dev *osduld_info_lookup(const struct osd_dev_info *odi) -{ - struct find_oud_t find = {.odi = odi}; - - find.dev = class_find_device(&osd_uld_class, NULL, &find, _mach_odi); - if (likely(find.dev)) { - struct osd_dev_handle *odh = kzalloc(sizeof(*odh), GFP_KERNEL); - - if (unlikely(!odh)) { - put_device(find.dev); - return ERR_PTR(-ENOMEM); - } - - odh->od = find.oud->od; - odh->oud = find.oud; - - return &odh->od; - } - - return ERR_PTR(-ENODEV); -} -EXPORT_SYMBOL(osduld_info_lookup); - -void osduld_put_device(struct osd_dev *od) -{ - if (od && !IS_ERR(od)) { - struct osd_dev_handle *odh = - container_of(od, struct osd_dev_handle, od); - struct osd_uld_device *oud = odh->oud; - - BUG_ON(od->scsi_device != oud->od.scsi_device); - - /* If scsi has released the device (logout), and exofs has last - * reference on oud it will be freed by above osd_uld_release - * within fput below. But this will oops in cdev_release which - * is called after the fops->release. A get_/put_ pair makes - * sure we have a cdev for the duration of fput - */ - if (odh->file) { - get_device(&oud->class_dev); - fput(odh->file); - } - put_device(&oud->class_dev); - kfree(odh); - } -} -EXPORT_SYMBOL(osduld_put_device); - -const struct osd_dev_info *osduld_device_info(struct osd_dev *od) -{ - struct osd_dev_handle *odh = - container_of(od, struct osd_dev_handle, od); - return &odh->oud->odi; -} -EXPORT_SYMBOL(osduld_device_info); - -bool osduld_device_same(struct osd_dev *od, const struct osd_dev_info *odi) -{ - struct osd_dev_handle *odh = - container_of(od, struct osd_dev_handle, od); - struct osd_uld_device *oud = odh->oud; - - return (oud->odi.systemid_len == odi->systemid_len) && - _the_same_or_null(oud->odi.systemid, oud->odi.systemid_len, - odi->systemid, odi->systemid_len) && - (oud->odi.osdname_len == odi->osdname_len) && - _the_same_or_null(oud->odi.osdname, oud->odi.osdname_len, - odi->osdname, odi->osdname_len); -} -EXPORT_SYMBOL(osduld_device_same); - -/* - * Scsi Device operations - */ - -static int __detect_osd(struct osd_uld_device *oud) -{ - struct scsi_device *scsi_device = oud->od.scsi_device; - char caps[OSD_CAP_LEN]; - int error; - - /* sending a test_unit_ready as first command seems to be needed - * by some targets - */ - OSD_DEBUG("start scsi_test_unit_ready %p %p %p\n", - oud, scsi_device, scsi_device->request_queue); - error = scsi_test_unit_ready(scsi_device, 10*HZ, 5, NULL); - if (error) - OSD_ERR("warning: scsi_test_unit_ready failed\n"); - - osd_sec_init_nosec_doall_caps(caps, &osd_root_object, false, true); - if (osd_auto_detect_ver(&oud->od, caps, &oud->odi)) - return -ENODEV; - - return 0; -} - -static void __remove(struct device *dev) -{ - struct osd_uld_device *oud = container_of(dev, struct osd_uld_device, - class_dev); - struct scsi_device *scsi_device = oud->od.scsi_device; - - kfree(oud->odi.osdname); - - if (oud->cdev.owner) - cdev_del(&oud->cdev); - - osd_dev_fini(&oud->od); - scsi_device_put(scsi_device); - - OSD_INFO("osd_remove %s\n", - oud->disk ? oud->disk->disk_name : NULL); - - if (oud->disk) - put_disk(oud->disk); - ida_remove(&osd_minor_ida, oud->minor); - - kfree(oud); -} - -static int osd_probe(struct device *dev) -{ - struct scsi_device *scsi_device = to_scsi_device(dev); - struct gendisk *disk; - struct osd_uld_device *oud; - int minor; - int error; - - if (scsi_device->type != TYPE_OSD) - return -ENODEV; - - do { - if (!ida_pre_get(&osd_minor_ida, GFP_KERNEL)) - return -ENODEV; - - error = ida_get_new(&osd_minor_ida, &minor); - } while (error == -EAGAIN); - - if (error) - return error; - if (minor >= SCSI_OSD_MAX_MINOR) { - error = -EBUSY; - goto err_retract_minor; - } - - error = -ENOMEM; - oud = kzalloc(sizeof(*oud), GFP_KERNEL); - if (NULL == oud) - goto err_retract_minor; - - dev_set_drvdata(dev, oud); - oud->minor = minor; - - /* allocate a disk and set it up */ - /* FIXME: do we need this since sg has already done that */ - disk = alloc_disk(1); - if (!disk) { - OSD_ERR("alloc_disk failed\n"); - goto err_free_osd; - } - disk->major = SCSI_OSD_MAJOR; - disk->first_minor = oud->minor; - sprintf(disk->disk_name, "osd%d", oud->minor); - oud->disk = disk; - - /* hold one more reference to the scsi_device that will get released - * in __release, in case a logout is happening while fs is mounted - */ - scsi_device_get(scsi_device); - osd_dev_init(&oud->od, scsi_device); - - /* Detect the OSD Version */ - error = __detect_osd(oud); - if (error) { - OSD_ERR("osd detection failed, non-compatible OSD device\n"); - goto err_put_disk; - } - - /* init the char-device for communication with user-mode */ - cdev_init(&oud->cdev, &osd_fops); - oud->cdev.owner = THIS_MODULE; - error = cdev_add(&oud->cdev, - MKDEV(SCSI_OSD_MAJOR, oud->minor), 1); - if (error) { - OSD_ERR("cdev_add failed\n"); - goto err_put_disk; - } - - /* class device member */ - oud->class_dev.devt = oud->cdev.dev; - oud->class_dev.class = &osd_uld_class; - oud->class_dev.parent = dev; - oud->class_dev.release = __remove; - error = dev_set_name(&oud->class_dev, disk->disk_name); - if (error) { - OSD_ERR("dev_set_name failed => %d\n", error); - goto err_put_cdev; - } - - error = device_register(&oud->class_dev); - if (error) { - OSD_ERR("device_register failed => %d\n", error); - goto err_put_cdev; - } - - get_device(&oud->class_dev); - - OSD_INFO("osd_probe %s\n", disk->disk_name); - return 0; - -err_put_cdev: - cdev_del(&oud->cdev); -err_put_disk: - scsi_device_put(scsi_device); - put_disk(disk); -err_free_osd: - dev_set_drvdata(dev, NULL); - kfree(oud); -err_retract_minor: - ida_remove(&osd_minor_ida, minor); - return error; -} - -static int osd_remove(struct device *dev) -{ - struct scsi_device *scsi_device = to_scsi_device(dev); - struct osd_uld_device *oud = dev_get_drvdata(dev); - - if (!oud || (oud->od.scsi_device != scsi_device)) { - OSD_ERR("Half cooked osd-device %p,%p || %p!=%p", - dev, oud, oud ? oud->od.scsi_device : NULL, - scsi_device); - } - - device_unregister(&oud->class_dev); - - put_device(&oud->class_dev); - return 0; -} - -/* - * Global driver and scsi registration - */ - -static struct scsi_driver osd_driver = { - .owner = THIS_MODULE, - .gendrv = { - .name = osd_name, - .probe = osd_probe, - .remove = osd_remove, - } -}; - -static int __init osd_uld_init(void) -{ - int err; - - err = class_register(&osd_uld_class); - if (err) { - OSD_ERR("Unable to register sysfs class => %d\n", err); - return err; - } - - err = register_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), - SCSI_OSD_MAX_MINOR, osd_name); - if (err) { - OSD_ERR("Unable to register major %d for osd ULD => %d\n", - SCSI_OSD_MAJOR, err); - goto err_out; - } - - err = scsi_register_driver(&osd_driver.gendrv); - if (err) { - OSD_ERR("scsi_register_driver failed => %d\n", err); - goto err_out_chrdev; - } - - OSD_INFO("LOADED %s\n", osd_version_string); - return 0; - -err_out_chrdev: - unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR); -err_out: - class_unregister(&osd_uld_class); - return err; -} - -static void __exit osd_uld_exit(void) -{ - scsi_unregister_driver(&osd_driver.gendrv); - unregister_chrdev_region(MKDEV(SCSI_OSD_MAJOR, 0), SCSI_OSD_MAX_MINOR); - class_unregister(&osd_uld_class); - OSD_INFO("UNLOADED %s\n", osd_version_string); -} - -module_init(osd_uld_init); -module_exit(osd_uld_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/osst.c b/ANDROID_3.4.5/drivers/scsi/osst.c deleted file mode 100644 index 21883a2d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osst.c +++ /dev/null @@ -1,6095 +0,0 @@ -/* - SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying - file Documentation/scsi/st.txt for more information. - - History: - - OnStream SCSI Tape support (osst) cloned from st.c by - Willem Riede (osst@riede.org) Feb 2000 - Fixes ... Kurt Garloff Mar 2000 - - Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. - Contribution and ideas from several people including (in alphabetical - order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, - Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. - - Copyright 1992 - 2002 Kai Makisara / 2000 - 2006 Willem Riede - email osst@riede.org - - $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $ - - Microscopic alterations - Rik Ling, 2000/12/21 - Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara - Some small formal changes - aeb, 950809 -*/ - -static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $"; -static const char * osst_version = "0.99.4"; - -/* The "failure to reconnect" firmware bug */ -#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ -#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/ -#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7) - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* The driver prints some debugging information on the console if DEBUG - is defined and non-zero. */ -#define DEBUG 0 - -/* The message level for the debug messages is currently set to KERN_NOTICE - so that people can easily see the messages. Later when the debugging messages - in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ -#define OSST_DEB_MSG KERN_NOTICE - -#include -#include -#include -#include -#include -#include -#include - -#define ST_KILOBYTE 1024 - -#include "st.h" -#include "osst.h" -#include "osst_options.h" -#include "osst_detect.h" - -static DEFINE_MUTEX(osst_int_mutex); -static int max_dev = 0; -static int write_threshold_kbs = 0; -static int max_sg_segs = 0; - -#ifdef MODULE -MODULE_AUTHOR("Willem Riede"); -MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); - -module_param(max_dev, int, 0444); -MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)"); - -module_param(write_threshold_kbs, int, 0644); -MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)"); - -module_param(max_sg_segs, int, 0644); -MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)"); -#else -static struct osst_dev_parm { - char *name; - int *val; -} parms[] __initdata = { - { "max_dev", &max_dev }, - { "write_threshold_kbs", &write_threshold_kbs }, - { "max_sg_segs", &max_sg_segs } -}; -#endif - -/* Some default definitions have been moved to osst_options.h */ -#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE) -#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE) - -/* The buffer size should fit into the 24 bits for length in the - 6-byte SCSI read and write commands. */ -#if OSST_BUFFER_SIZE >= (2 << 24 - 1) -#error "Buffer size should not exceed (2 << 24 - 1) bytes!" -#endif - -#if DEBUG -static int debugging = 1; -/* uncomment define below to test error recovery */ -// #define OSST_INJECT_ERRORS 1 -#endif - -/* Do not retry! The drive firmware already retries when appropriate, - and when it tries to tell us something, we had better listen... */ -#define MAX_RETRIES 0 - -#define NO_TAPE NOT_READY - -#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1) -#define OSST_WAIT_WRITE_COMPLETE (HZ / 12) -#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2) - -#define OSST_TIMEOUT (200 * HZ) -#define OSST_LONG_TIMEOUT (1800 * HZ) - -#define TAPE_NR(x) (iminor(x) & ~(-1 << ST_MODE_SHIFT)) -#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) -#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0) -#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1)) - -/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower - 24 bits) */ -#define SET_DENS_AND_BLK 0x10001 - -static int osst_buffer_size = OSST_BUFFER_SIZE; -static int osst_write_threshold = OSST_WRITE_THRESHOLD; -static int osst_max_sg_segs = OSST_MAX_SG; -static int osst_max_dev = OSST_MAX_TAPES; -static int osst_nr_dev; - -static struct osst_tape **os_scsi_tapes = NULL; -static DEFINE_RWLOCK(os_scsi_tapes_lock); - -static int modes_defined = 0; - -static struct osst_buffer *new_tape_buffer(int, int, int); -static int enlarge_buffer(struct osst_buffer *, int); -static void normalize_buffer(struct osst_buffer *); -static int append_to_buffer(const char __user *, struct osst_buffer *, int); -static int from_buffer(struct osst_buffer *, char __user *, int); -static int osst_zero_buffer_tail(struct osst_buffer *); -static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *); -static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *); - -static int osst_probe(struct device *); -static int osst_remove(struct device *); - -static struct scsi_driver osst_template = { - .owner = THIS_MODULE, - .gendrv = { - .name = "osst", - .probe = osst_probe, - .remove = osst_remove, - } -}; - -static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt, - unsigned int cmd_in, unsigned long arg); - -static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip); - -static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt); - -static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt); - -static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending); - -static inline char *tape_name(struct osst_tape *tape) -{ - return tape->drive->disk_name; -} - -/* Routines that handle the interaction with mid-layer SCSI routines */ - - -/* Normalize Sense */ -static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s) -{ - const u8 *ucp; - const u8 *sense = SRpnt->sense; - - s->have_sense = scsi_normalize_sense(SRpnt->sense, - SCSI_SENSE_BUFFERSIZE, &s->sense_hdr); - s->flags = 0; - - if (s->have_sense) { - s->deferred = 0; - s->remainder_valid = - scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64); - switch (sense[0] & 0x7f) { - case 0x71: - s->deferred = 1; - case 0x70: - s->fixed_format = 1; - s->flags = sense[2] & 0xe0; - break; - case 0x73: - s->deferred = 1; - case 0x72: - s->fixed_format = 0; - ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4); - s->flags = ucp ? (ucp[3] & 0xe0) : 0; - break; - } - } -} - -/* Convert the result to success code */ -static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) -{ - char *name = tape_name(STp); - int result = SRpnt->result; - u8 * sense = SRpnt->sense, scode; -#if DEBUG - const char *stp; -#endif - struct st_cmdstatus *cmdstatp; - - if (!result) - return 0; - - cmdstatp = &STp->buffer->cmdstat; - osst_analyze_sense(SRpnt, cmdstatp); - - if (cmdstatp->have_sense) - scode = STp->buffer->cmdstat.sense_hdr.sense_key; - else - scode = 0; -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n", - name, result, - SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2], - SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]); - if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n", - name, scode, sense[12], sense[13]); - if (cmdstatp->have_sense) - __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE); - } - else -#endif - if (cmdstatp->have_sense && ( - scode != NO_SENSE && - scode != RECOVERED_ERROR && -/* scode != UNIT_ATTENTION && */ - scode != BLANK_CHECK && - scode != VOLUME_OVERFLOW && - SRpnt->cmd[0] != MODE_SENSE && - SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ - if (cmdstatp->have_sense) { - printk(KERN_WARNING "%s:W: Command with sense data:\n", name); - __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE); - } - else { - static int notyetprinted = 1; - - printk(KERN_WARNING - "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n", - name, result, driver_byte(result), - host_byte(result)); - if (notyetprinted) { - notyetprinted = 0; - printk(KERN_INFO - "%s:I: This warning may be caused by your scsi controller,\n", name); - printk(KERN_INFO - "%s:I: it has been reported with some Buslogic cards.\n", name); - } - } - } - STp->pos_unknown |= STp->device->was_reset; - - if (cmdstatp->have_sense && scode == RECOVERED_ERROR) { - STp->recover_count++; - STp->recover_erreg++; -#if DEBUG - if (debugging) { - if (SRpnt->cmd[0] == READ_6) - stp = "read"; - else if (SRpnt->cmd[0] == WRITE_6) - stp = "write"; - else - stp = "ioctl"; - printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp, - STp->recover_count); - } -#endif - if ((sense[2] & 0xe0) == 0) - return 0; - } - return (-EIO); -} - - -/* Wakeup from interrupt */ -static void osst_end_async(struct request *req, int update) -{ - struct osst_request *SRpnt = req->end_io_data; - struct osst_tape *STp = SRpnt->stp; - struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - - STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; -#if DEBUG - STp->write_pending = 0; -#endif - if (SRpnt->waiting) - complete(SRpnt->waiting); - - if (SRpnt->bio) { - kfree(mdata->pages); - blk_rq_unmap_user(SRpnt->bio); - } - - __blk_put_request(req->q, req); -} - -/* osst_request memory management */ -static struct osst_request *osst_allocate_request(void) -{ - return kzalloc(sizeof(struct osst_request), GFP_KERNEL); -} - -static void osst_release_request(struct osst_request *streq) -{ - kfree(streq); -} - -static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, - int cmd_len, int data_direction, void *buffer, unsigned bufflen, - int use_sg, int timeout, int retries) -{ - struct request *req; - struct page **pages = NULL; - struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - - int err = 0; - int write = (data_direction == DMA_TO_DEVICE); - - req = blk_get_request(SRpnt->stp->device->request_queue, write, GFP_KERNEL); - if (!req) - return DRIVER_ERROR << 24; - - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_QUIET; - - SRpnt->bio = NULL; - - if (use_sg) { - struct scatterlist *sg, *sgl = (struct scatterlist *)buffer; - int i; - - pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL); - if (!pages) - goto free_req; - - for_each_sg(sgl, sg, use_sg, i) - pages[i] = sg_page(sg); - - mdata->null_mapped = 1; - - mdata->page_order = get_order(sgl[0].length); - mdata->nr_entries = - DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order); - mdata->offset = 0; - - err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL); - if (err) { - kfree(pages); - goto free_req; - } - SRpnt->bio = req->bio; - mdata->pages = pages; - - } else if (bufflen) { - err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL); - if (err) - goto free_req; - } - - req->cmd_len = cmd_len; - memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ - memcpy(req->cmd, cmd, req->cmd_len); - req->sense = SRpnt->sense; - req->sense_len = 0; - req->timeout = timeout; - req->retries = retries; - req->end_io_data = SRpnt; - - blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async); - return 0; -free_req: - blk_put_request(req); - return DRIVER_ERROR << 24; -} - -/* Do the scsi command. Waits until command performed if do_wait is true. - Otherwise osst_write_behind_check() is used to check that the command - has finished. */ -static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp, - unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait) -{ - unsigned char *bp; - unsigned short use_sg; -#ifdef OSST_INJECT_ERRORS - static int inject = 0; - static int repeat = 0; -#endif - struct completion *waiting; - - /* if async, make sure there's no command outstanding */ - if (!do_wait && ((STp->buffer)->last_SRpnt)) { - printk(KERN_ERR "%s: Async command already active.\n", - tape_name(STp)); - if (signal_pending(current)) - (STp->buffer)->syscall_result = (-EINTR); - else - (STp->buffer)->syscall_result = (-EBUSY); - return NULL; - } - - if (SRpnt == NULL) { - SRpnt = osst_allocate_request(); - if (SRpnt == NULL) { - printk(KERN_ERR "%s: Can't allocate SCSI request.\n", - tape_name(STp)); - if (signal_pending(current)) - (STp->buffer)->syscall_result = (-EINTR); - else - (STp->buffer)->syscall_result = (-EBUSY); - return NULL; - } - SRpnt->stp = STp; - } - - /* If async IO, set last_SRpnt. This ptr tells write_behind_check - which IO is outstanding. It's nulled out when the IO completes. */ - if (!do_wait) - (STp->buffer)->last_SRpnt = SRpnt; - - waiting = &STp->wait; - init_completion(waiting); - SRpnt->waiting = waiting; - - use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0; - if (use_sg) { - bp = (char *)&(STp->buffer->sg[0]); - if (STp->buffer->sg_segs < use_sg) - use_sg = STp->buffer->sg_segs; - } - else - bp = (STp->buffer)->b_data; - - memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); - STp->buffer->cmdstat.have_sense = 0; - STp->buffer->syscall_result = 0; - - if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, - use_sg, timeout, retries)) - /* could not allocate the buffer or request was too large */ - (STp->buffer)->syscall_result = (-EBUSY); - else if (do_wait) { - wait_for_completion(waiting); - SRpnt->waiting = NULL; - STp->buffer->syscall_result = osst_chk_result(STp, SRpnt); -#ifdef OSST_INJECT_ERRORS - if (STp->buffer->syscall_result == 0 && - cmd[0] == READ_6 && - cmd[4] && - ( (++ inject % 83) == 29 || - (STp->first_frame_position == 240 - /* or STp->read_error_frame to fail again on the block calculated above */ && - ++repeat < 3))) { - printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp)); - STp->buffer->last_result_fatal = 1; - } -#endif - } - return SRpnt; -} - - -/* Handle the write-behind checking (downs the semaphore) */ -static void osst_write_behind_check(struct osst_tape *STp) -{ - struct osst_buffer * STbuffer; - - STbuffer = STp->buffer; - -#if DEBUG - if (STp->write_pending) - STp->nbr_waits++; - else - STp->nbr_finished++; -#endif - wait_for_completion(&(STp->wait)); - STp->buffer->last_SRpnt->waiting = NULL; - - STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt); - - if (STp->buffer->syscall_result) - STp->buffer->syscall_result = - osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1); - else - STp->first_frame_position++; - - osst_release_request(STp->buffer->last_SRpnt); - - if (STbuffer->writing < STbuffer->buffer_bytes) - printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n"); - - STbuffer->last_SRpnt = NULL; - STbuffer->buffer_bytes -= STbuffer->writing; - STbuffer->writing = 0; - - return; -} - - - -/* Onstream specific Routines */ -/* - * Initialize the OnStream AUX - */ -static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number, - int logical_blk_num, int blk_sz, int blk_cnt) -{ - os_aux_t *aux = STp->buffer->aux; - os_partition_t *par = &aux->partition; - os_dat_t *dat = &aux->dat; - - if (STp->raw) return; - - memset(aux, 0, sizeof(*aux)); - aux->format_id = htonl(0); - memcpy(aux->application_sig, "LIN4", 4); - aux->hdwr = htonl(0); - aux->frame_type = frame_type; - - switch (frame_type) { - case OS_FRAME_TYPE_HEADER: - aux->update_frame_cntr = htonl(STp->update_frame_cntr); - par->partition_num = OS_CONFIG_PARTITION; - par->par_desc_ver = OS_PARTITION_VERSION; - par->wrt_pass_cntr = htons(0xffff); - /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */ - par->first_frame_ppos = htonl(0); - par->last_frame_ppos = htonl(0xbb7); - aux->frame_seq_num = htonl(0); - aux->logical_blk_num_high = htonl(0); - aux->logical_blk_num = htonl(0); - aux->next_mark_ppos = htonl(STp->first_mark_ppos); - break; - case OS_FRAME_TYPE_DATA: - case OS_FRAME_TYPE_MARKER: - dat->dat_sz = 8; - dat->reserved1 = 0; - dat->entry_cnt = 1; - dat->reserved3 = 0; - dat->dat_list[0].blk_sz = htonl(blk_sz); - dat->dat_list[0].blk_cnt = htons(blk_cnt); - dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER? - OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA; - dat->dat_list[0].reserved = 0; - case OS_FRAME_TYPE_EOD: - aux->update_frame_cntr = htonl(0); - par->partition_num = OS_DATA_PARTITION; - par->par_desc_ver = OS_PARTITION_VERSION; - par->wrt_pass_cntr = htons(STp->wrt_pass_cntr); - par->first_frame_ppos = htonl(STp->first_data_ppos); - par->last_frame_ppos = htonl(STp->capacity); - aux->frame_seq_num = htonl(frame_seq_number); - aux->logical_blk_num_high = htonl(0); - aux->logical_blk_num = htonl(logical_blk_num); - break; - default: ; /* probably FILL */ - } - aux->filemark_cnt = htonl(STp->filemark_cnt); - aux->phys_fm = htonl(0xffffffff); - aux->last_mark_ppos = htonl(STp->last_mark_ppos); - aux->last_mark_lbn = htonl(STp->last_mark_lbn); -} - -/* - * Verify that we have the correct tape frame - */ -static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet) -{ - char * name = tape_name(STp); - os_aux_t * aux = STp->buffer->aux; - os_partition_t * par = &(aux->partition); - struct st_partstat * STps = &(STp->ps[STp->partition]); - int blk_cnt, blk_sz, i; - - if (STp->raw) { - if (STp->buffer->syscall_result) { - for (i=0; i < STp->buffer->sg_segs; i++) - memset(page_address(sg_page(&STp->buffer->sg[i])), - 0, STp->buffer->sg[i].length); - strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); - } else - STp->buffer->buffer_bytes = OS_FRAME_SIZE; - return 1; - } - if (STp->buffer->syscall_result) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name); -#endif - return 0; - } - if (ntohl(aux->format_id) != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id)); -#endif - goto err_out; - } - if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 && - (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name); -#endif - goto err_out; - } - if (par->partition_num != OS_DATA_PARTITION) { - if (!STp->linux_media || STp->linux_media_version != 2) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n", - name, par->partition_num); -#endif - goto err_out; - } - } - if (par->par_desc_ver != OS_PARTITION_VERSION) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver); -#endif - goto err_out; - } - if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", - name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr); -#endif - goto err_out; - } - if (aux->frame_type != OS_FRAME_TYPE_DATA && - aux->frame_type != OS_FRAME_TYPE_EOD && - aux->frame_type != OS_FRAME_TYPE_MARKER) { - if (!quiet) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type); -#endif - } - goto err_out; - } - if (aux->frame_type == OS_FRAME_TYPE_EOD && - STp->first_frame_position < STp->eod_frame_ppos) { - printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name, - STp->first_frame_position); - goto err_out; - } - if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { - if (!quiet) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", - name, ntohl(aux->frame_seq_num), frame_seq_number); -#endif - } - goto err_out; - } - if (aux->frame_type == OS_FRAME_TYPE_MARKER) { - STps->eof = ST_FM_HIT; - - i = ntohl(aux->filemark_cnt); - if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt || - STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name, - STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected", - i, STp->first_frame_position - 1); -#endif - STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1); - if (i >= STp->filemark_cnt) - STp->filemark_cnt = i+1; - } - } - if (aux->frame_type == OS_FRAME_TYPE_EOD) { - STps->eof = ST_EOD_1; - STp->frame_in_buffer = 1; - } - if (aux->frame_type == OS_FRAME_TYPE_DATA) { - blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt); - blk_sz = ntohl(aux->dat.dat_list[0].blk_sz); - STp->buffer->buffer_bytes = blk_cnt * blk_sz; - STp->buffer->read_pointer = 0; - STp->frame_in_buffer = 1; - - /* See what block size was used to write file */ - if (STp->block_size != blk_sz && blk_sz > 0) { - printk(KERN_INFO - "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n", - name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k', - STp->block_size<1024?STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); - STp->block_size = blk_sz; - STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz; - } - STps->eof = ST_NOEOF; - } - STp->frame_seq_number = ntohl(aux->frame_seq_num); - STp->logical_blk_num = ntohl(aux->logical_blk_num); - return 1; - -err_out: - if (STp->read_error_frame == 0) - STp->read_error_frame = STp->first_frame_position - 1; - return 0; -} - -/* - * Wait for the unit to become Ready - */ -static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned timeout, int initial_delay) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name); -#endif - - if (initial_delay > 0) - msleep(jiffies_to_msecs(initial_delay)); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - - while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 && - (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) || - ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 && - SRpnt->sense[13] == 0 ) )) { -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - msleep(100); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - } - *aSRpnt = SRpnt; -#if DEBUG - debugging = dbg; -#endif - if ( STp->buffer->syscall_result && - osst_write_error_recovery(STp, aSRpnt, 0) ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, - STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - return (-EIO); - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name); -#endif - return 0; -} - -/* - * Wait for a tape to be inserted in the unit - */ -static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name); -#endif - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - - while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && - SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) { -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - msleep(100); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - } - *aSRpnt = SRpnt; -#if DEBUG - debugging = dbg; -#endif - if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 && - SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name); - printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, - STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - return 0; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name); -#endif - return 1; -} - -static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame) -{ - int retval; - - osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */ - retval = osst_set_frame_position(STp, aSRpnt, frame, 0); - if (retval) return (retval); - osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE); - return (osst_get_frame_position(STp, aSRpnt)); -} - -/* - * Wait for write(s) to complete - */ -static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int result = 0; - int delay = OSST_WAIT_WRITE_COMPLETE; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name); -#endif - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) return (-EBUSY); - if (STp->buffer->syscall_result) { - if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) { - if (SRpnt->sense[13] == 8) { - delay = OSST_WAIT_LONG_WRITE_COMPLETE; - } - } else - result = osst_write_error_recovery(STp, aSRpnt, 0); - } - result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay); - STp->ps[STp->partition].rw = OS_WRITING_COMPLETE; - - return (result); -} - -#define OSST_POLL_PER_SEC 10 -static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to) -{ - unsigned long startwait = jiffies; - char * name = tape_name(STp); -#if DEBUG - char notyetprinted = 1; -#endif - if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING) - printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name); - - while (time_before (jiffies, startwait + to*HZ)) - { - int result; - result = osst_get_frame_position(STp, aSRpnt); - if (result == -EIO) - if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0) - return 0; /* successful recovery leaves drive ready for frame */ - if (result < 0) break; - if (STp->first_frame_position == curr && - ((minlast < 0 && - (signed)STp->last_frame_position > (signed)curr + minlast) || - (minlast >= 0 && STp->cur_frames > minlast) - ) && result >= 0) - { -#if DEBUG - if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC)) - printk (OSST_DEB_MSG - "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, - result, (jiffies-startwait)/HZ, - (((jiffies-startwait)%HZ)*10)/HZ); -#endif - return 0; - } -#if DEBUG - if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted) - { - printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, result); - notyetprinted--; - } -#endif - msleep(1000 / OSST_POLL_PER_SEC); - } -#if DEBUG - printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n", - name, curr, curr+minlast, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames, - (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ); -#endif - return -EBUSY; -} - -static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing) -{ - struct osst_request * SRpnt; - unsigned char cmd[MAX_COMMAND_SIZE]; - unsigned long startwait = jiffies; - int retval = 1; - char * name = tape_name(STp); - - if (writing) { - char mybuf[24]; - char * olddata = STp->buffer->b_data; - int oldsize = STp->buffer->buffer_size; - - /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */ - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, - MAX_RETRIES, 1); - - while (retval && time_before (jiffies, startwait + 5*60*HZ)) { - - if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) { - - /* some failure - not just not-ready */ - retval = osst_write_error_recovery(STp, aSRpnt, 0); - break; - } - schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC); - - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_POSITION; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout, - MAX_RETRIES, 1); - - retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 ); - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - } - if (retval) - printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name); - } else - /* TODO - figure out which error conditions can be handled */ - if (STp->buffer->syscall_result) - printk(KERN_WARNING - "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name, - (*aSRpnt)->sense[ 2] & 0x0f, - (*aSRpnt)->sense[12], - (*aSRpnt)->sense[13]); - - return retval; -} - -/* - * Read the next OnStream tape frame at the current location - */ -static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int retval = 0; -#if DEBUG - os_aux_t * aux = STp->buffer->aux; - char * name = tape_name(STp); -#endif - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout)) - retval = osst_recover_wait_frame(STp, aSRpnt, 0); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_6; - cmd[1] = 1; - cmd[4] = 1; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) - return (-EBUSY); - - if ((STp->buffer)->syscall_result) { - retval = 1; - if (STp->read_error_frame == 0) { - STp->read_error_frame = STp->first_frame_position; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame); -#endif - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", - name, - SRpnt->sense[0], SRpnt->sense[1], - SRpnt->sense[2], SRpnt->sense[3], - SRpnt->sense[4], SRpnt->sense[5], - SRpnt->sense[6], SRpnt->sense[7]); -#endif - } - else - STp->first_frame_position++; -#if DEBUG - if (debugging) { - char sig[8]; int i; - for (i=0;i<4;i++) - sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i]; - sig[4] = '\0'; - printk(OSST_DEB_MSG - "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig, - ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr), - aux->frame_type==1?"EOD":aux->frame_type==2?"MARK": - aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", - ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), - ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) ); - if (aux->frame_type==2) - printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name, - ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn)); - printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval); - } -#endif - return (retval); -} - -static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - struct osst_request * SRpnt ; - unsigned char cmd[MAX_COMMAND_SIZE]; - int retval = 0; - char * name = tape_name(STp); - - if (STps->rw != ST_READING) { /* Initialize read operation */ - if (STps->rw == ST_WRITING || STp->dirty) { - STp->write_type = OS_WRITE_DATA; - osst_flush_write_buffer(STp, aSRpnt); - osst_flush_drive_buffer(STp, aSRpnt); - } - STps->rw = ST_READING; - STp->frame_in_buffer = 0; - - /* - * Issue a read 0 command to get the OnStream drive - * read frames into its buffer. - */ - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_6; - cmd[1] = 1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if ((retval = STp->buffer->syscall_result)) - printk(KERN_WARNING "%s:W: Error starting read ahead\n", name); - } - - return retval; -} - -static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, - int frame_seq_number, int quiet) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - char * name = tape_name(STp); - int cnt = 0, - bad = 0, - past = 0, - x, - position; - - /* - * If we want just any frame (-1) and there is a frame in the buffer, return it - */ - if (frame_seq_number == -1 && STp->frame_in_buffer) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number); -#endif - return (STps->eof); - } - /* - * Search and wait for the next logical tape frame - */ - while (1) { - if (cnt++ > 400) { - printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n", - name, frame_seq_number); - if (STp->read_error_frame) { - osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n", - name, STp->read_error_frame); -#endif - STp->read_error_frame = 0; - STp->abort_count++; - } - return (-EIO); - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n", - name, frame_seq_number, cnt); -#endif - if ( osst_initiate_read(STp, aSRpnt) - || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) { - if (STp->raw) - return (-EIO); - position = osst_get_frame_position(STp, aSRpnt); - if (position >= 0xbae && position < 0xbb8) - position = 0xbb8; - else if (position > STp->eod_frame_ppos || ++bad == 10) { - position = STp->read_error_frame - 1; - bad = 0; - } - else { - position += 29; - cnt += 19; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n", - name, position); -#endif - osst_set_frame_position(STp, aSRpnt, position, 0); - continue; - } - if (osst_verify_frame(STp, frame_seq_number, quiet)) - break; - if (osst_verify_frame(STp, -1, quiet)) { - x = ntohl(STp->buffer->aux->frame_seq_num); - if (STp->fast_open) { - printk(KERN_WARNING - "%s:W: Found logical frame %d instead of %d after fast open\n", - name, x, frame_seq_number); - STp->header_ok = 0; - STp->read_error_frame = 0; - return (-EIO); - } - if (x > frame_seq_number) { - if (++past > 3) { - /* positioning backwards did not bring us to the desired frame */ - position = STp->read_error_frame - 1; - } - else { - position = osst_get_frame_position(STp, aSRpnt) - + frame_seq_number - x - 1; - - if (STp->first_frame_position >= 3000 && position < 3000) - position -= 10; - } -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Found logical frame %d while looking for %d: back up %d\n", - name, x, frame_seq_number, - STp->first_frame_position - position); -#endif - osst_set_frame_position(STp, aSRpnt, position, 0); - cnt += 10; - } - else - past = 0; - } - if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name); -#endif - osst_set_frame_position(STp, aSRpnt, 0xbb8, 0); - cnt--; - } - STp->frame_in_buffer = 0; - } - if (cnt > 1) { - STp->recover_count++; - STp->recover_erreg++; - printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n", - name, STp->read_error_frame); - } - STp->read_count++; - -#if DEBUG - if (debugging || STps->eof) - printk(OSST_DEB_MSG - "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n", - name, frame_seq_number, STp->frame_seq_number, STps->eof); -#endif - STp->fast_open = 0; - STp->read_error_frame = 0; - return (STps->eof); -} - -static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - char * name = tape_name(STp); - int retries = 0; - int frame_seq_estimate, ppos_estimate, move; - - if (logical_blk_num < 0) logical_blk_num = 0; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n", - name, logical_blk_num, STp->logical_blk_num, - STp->block_size<1024?STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); -#endif - /* Do we know where we are? */ - if (STps->drv_block >= 0) { - move = logical_blk_num - STp->logical_blk_num; - if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; - move /= (OS_DATA_SIZE / STp->block_size); - frame_seq_estimate = STp->frame_seq_number + move; - } else - frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE; - - if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10; - else ppos_estimate = frame_seq_estimate + 20; - while (++retries < 10) { - if (ppos_estimate > STp->eod_frame_ppos-2) { - frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate; - ppos_estimate = STp->eod_frame_ppos - 2; - } - if (frame_seq_estimate < 0) { - frame_seq_estimate = 0; - ppos_estimate = 10; - } - osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0); - if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) { - /* we've located the estimated frame, now does it have our block? */ - if (logical_blk_num < STp->logical_blk_num || - logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) { - if (STps->eof == ST_FM_HIT) - move = logical_blk_num < STp->logical_blk_num? -2 : 1; - else { - move = logical_blk_num - STp->logical_blk_num; - if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; - move /= (OS_DATA_SIZE / STp->block_size); - } - if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n", - name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, - STp->logical_blk_num, logical_blk_num, move); -#endif - frame_seq_estimate += move; - ppos_estimate += move; - continue; - } else { - STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size; - STp->buffer->buffer_bytes -= STp->buffer->read_pointer; - STp->logical_blk_num = logical_blk_num; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n", - name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, - STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, - STp->block_size); -#endif - STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); - if (STps->eof == ST_FM_HIT) { - STps->drv_file++; - STps->drv_block = 0; - } else { - STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? - STp->logical_blk_num - - (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): - -1; - } - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; - return 0; - } - } - if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0) - goto error; - /* we are not yet at the estimated frame, adjust our estimate of its physical position */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", - name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, - STp->logical_blk_num, logical_blk_num); -#endif - if (frame_seq_estimate != STp->frame_seq_number) - ppos_estimate += frame_seq_estimate - STp->frame_seq_number; - else - break; - } -error: - printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n", - name, logical_blk_num, STp->logical_blk_num, retries); - return (-EIO); -} - -/* The values below are based on the OnStream frame payload size of 32K == 2**15, - * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block - * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions - * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1. - */ -#define OSST_FRAME_SHIFT 6 -#define OSST_SECTOR_SHIFT 9 -#define OSST_SECTOR_MASK 0x03F - -static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int sector; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG - "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n", - name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, - STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, - STp->ps[STp->partition].rw == ST_WRITING?'w':'r', - STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes: - STp->buffer->read_pointer, STp->ps[STp->partition].eof); -#endif - /* do we know where we are inside a file? */ - if (STp->ps[STp->partition].drv_block >= 0) { - sector = (STp->frame_in_buffer ? STp->first_frame_position-1 : - STp->first_frame_position) << OSST_FRAME_SHIFT; - if (STp->ps[STp->partition].rw == ST_WRITING) - sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK; - else - sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK; - } else { - sector = osst_get_frame_position(STp, aSRpnt); - if (sector > 0) - sector <<= OSST_FRAME_SHIFT; - } - return sector; -} - -static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - int frame = sector >> OSST_FRAME_SHIFT, - offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, - r; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n", - name, sector, frame, offset); -#endif - if (frame < 0 || frame >= STp->capacity) return (-ENXIO); - - if (frame <= STp->first_data_ppos) { - STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0; - return (osst_set_frame_position(STp, aSRpnt, frame, 0)); - } - r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0); - if (r < 0) return r; - - r = osst_get_logical_frame(STp, aSRpnt, -1, 1); - if (r < 0) return r; - - if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO); - - if (offset) { - STp->logical_blk_num += offset / STp->block_size; - STp->buffer->read_pointer = offset; - STp->buffer->buffer_bytes -= offset; - } else { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; - } - STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); - if (STps->eof == ST_FM_HIT) { - STps->drv_file++; - STps->drv_block = 0; - } else { - STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? - STp->logical_blk_num - - (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): - -1; - } - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n", - name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, - STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof); -#endif - return 0; -} - -/* - * Read back the drive's internal buffer contents, as a part - * of the write error recovery mechanism for old OnStream - * firmware revisions. - * Precondition for this function to work: all frames in the - * drive's buffer must be of one type (DATA, MARK or EOD)! - */ -static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int frame, unsigned int skip, int pending) -{ - struct osst_request * SRpnt = * aSRpnt; - unsigned char * buffer, * p; - unsigned char cmd[MAX_COMMAND_SIZE]; - int flag, new_frame, i; - int nframes = STp->cur_frames; - int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num) - - (nframes + pending - 1); - int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num) - - (nframes + pending - 1) * blks_per_frame; - char * name = tape_name(STp); - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; -#endif - - if ((buffer = vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL) - return (-EIO); - - printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n", - name, nframes, pending?" and one that was pending":""); - - osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE])); -#if DEBUG - if (pending && debugging) - printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n", - name, frame_seq_number + nframes, - logical_blk_num + nframes * blks_per_frame, - p[0], p[1], p[2], p[3]); -#endif - for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = 0x3C; /* Buffer Read */ - cmd[1] = 6; /* Retrieve Faulty Block */ - cmd[7] = 32768 >> 8; - cmd[8] = 32768 & 0xff; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - - if ((STp->buffer)->syscall_result || !SRpnt) { - printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name); - vfree(buffer); - *aSRpnt = SRpnt; - return (-EIO); - } - osst_copy_from_buffer(STp->buffer, p); -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n", - name, frame_seq_number + i, p[0], p[1], p[2], p[3]); -#endif - } - *aSRpnt = SRpnt; - osst_get_frame_position(STp, aSRpnt); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames); -#endif - /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */ - /* In the header we don't actually re-write the frames that fail, just the ones after them */ - - for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) { - - if (flag) { - if (STp->write_type == OS_WRITE_HEADER) { - i += skip; - p += skip * OS_DATA_SIZE; - } - else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990) - new_frame = 3000-i; - else - new_frame += skip; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n", - name, new_frame+i, frame_seq_number+i); -#endif - osst_set_frame_position(STp, aSRpnt, new_frame + i, 0); - osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE); - osst_get_frame_position(STp, aSRpnt); - SRpnt = * aSRpnt; - - if (new_frame > frame + 1000) { - printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name); - vfree(buffer); - return (-EIO); - } - if ( i >= nframes + pending ) break; - flag = 0; - } - osst_copy_to_buffer(STp->buffer, p); - /* - * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type! - */ - osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i, - logical_blk_num + i*blks_per_frame, - ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame); - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG - "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n", - name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame, - p[0], p[1], p[2], p[3]); -#endif - SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - - if (STp->buffer->syscall_result) - flag = 1; - else { - p += OS_DATA_SIZE; i++; - - /* if we just sent the last frame, wait till all successfully written */ - if ( i == nframes + pending ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name); -#endif - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - cmd[1] = 1; - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - flag = STp->buffer->syscall_result; - while ( !flag && time_before(jiffies, startwait + 60*HZ) ) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, - MAX_RETRIES, 1); - - if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 && - (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) { - /* in the process of becoming ready */ - msleep(100); - continue; - } - if (STp->buffer->syscall_result) - flag = 1; - break; - } -#if DEBUG - debugging = dbg; - printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); -#endif - } - } - *aSRpnt = SRpnt; - if (flag) { - if ((SRpnt->sense[ 2] & 0x0f) == 13 && - SRpnt->sense[12] == 0 && - SRpnt->sense[13] == 2) { - printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name); - vfree(buffer); - return (-EIO); /* hit end of tape = fail */ - } - i = ((SRpnt->sense[3] << 24) | - (SRpnt->sense[4] << 16) | - (SRpnt->sense[5] << 8) | - SRpnt->sense[6] ) - new_frame; - p = &buffer[i * OS_DATA_SIZE]; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i); -#endif - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n", - name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames); -#endif - } - } - if (flag) { - /* error recovery did not successfully complete */ - printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name, - STp->write_type == OS_WRITE_HEADER?"header":"body"); - } - if (!pending) - osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */ - vfree(buffer); - return 0; -} - -static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int frame, unsigned int skip, int pending) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - char * name = tape_name(STp); - int expected = 0; - int attempts = 1000 / skip; - int flag = 1; - unsigned long startwait = jiffies; -#if DEBUG - int dbg = debugging; -#endif - - while (attempts && time_before(jiffies, startwait + 60*HZ)) { - if (flag) { -#if DEBUG - debugging = dbg; -#endif - if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990) - frame = 3000-skip; - expected = frame+skip+STp->cur_frames+pending; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n", - name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending); -#endif - osst_set_frame_position(STp, aSRpnt, frame + skip, 1); - flag = 0; - attempts--; - schedule_timeout_interruptible(msecs_to_jiffies(100)); - } - if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n", - name, STp->first_frame_position, - STp->last_frame_position, STp->cur_frames); -#endif - frame = STp->last_frame_position; - flag = 1; - continue; - } - if (pending && STp->cur_frames < 50) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n", - name, STp->frame_seq_number-1, STp->first_frame_position); -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - - if (STp->buffer->syscall_result) { /* additional write error */ - if ((SRpnt->sense[ 2] & 0x0f) == 13 && - SRpnt->sense[12] == 0 && - SRpnt->sense[13] == 2) { - printk(KERN_ERR - "%s:E: Volume overflow in write error recovery\n", - name); - break; /* hit end of tape = fail */ - } - flag = 1; - } - else - pending = 0; - - continue; - } - if (STp->cur_frames == 0) { -#if DEBUG - debugging = dbg; - printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); -#endif - if (STp->first_frame_position != expected) { - printk(KERN_ERR "%s:A: Actual position %d - expected %d\n", - name, STp->first_frame_position, expected); - return (-EIO); - } - return 0; - } -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); - printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); - debugging = 0; - } -#endif - schedule_timeout_interruptible(msecs_to_jiffies(100)); - } - printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name); -#if DEBUG - debugging = dbg; -#endif - return (-EIO); -} - -/* - * Error recovery algorithm for the OnStream tape. - */ - -static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending) -{ - struct osst_request * SRpnt = * aSRpnt; - struct st_partstat * STps = & STp->ps[STp->partition]; - char * name = tape_name(STp); - int retval = 0; - int rw_state; - unsigned int frame, skip; - - rw_state = STps->rw; - - if ((SRpnt->sense[ 2] & 0x0f) != 3 - || SRpnt->sense[12] != 12 - || SRpnt->sense[13] != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name, - SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]); -#endif - return (-EIO); - } - frame = (SRpnt->sense[3] << 24) | - (SRpnt->sense[4] << 16) | - (SRpnt->sense[5] << 8) | - SRpnt->sense[6]; - skip = SRpnt->sense[9]; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip); -#endif - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n", - name, STp->first_frame_position, STp->last_frame_position); -#endif - switch (STp->write_type) { - case OS_WRITE_DATA: - case OS_WRITE_EOD: - case OS_WRITE_NEW_MARK: - printk(KERN_WARNING - "%s:I: Relocating %d buffered logical frames from position %u to %u\n", - name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip); - if (STp->os_fw_rev >= 10600) - retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); - else - retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); - printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name, - retval?"E" :"I", - retval?"" :"Don't worry, ", - retval?" not ":" "); - break; - case OS_WRITE_LAST_MARK: - printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name); - osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); - retval = -EIO; - break; - case OS_WRITE_HEADER: - printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name); - retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending); - break; - default: - printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name); - osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); - } - osst_get_frame_position(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", - name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position); - printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num); -#endif - if (retval == 0) { - STp->recover_count++; - STp->recover_erreg++; - } else - STp->abort_count++; - - STps->rw = rw_state; - return retval; -} - -static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - char * name = tape_name(STp); - int cnt; - int last_mark_ppos = -1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name); -#endif - return -EIO; - } - if (STp->linux_media_version >= 4) { - /* - * direct lookup in header filemark list - */ - cnt = ntohl(STp->buffer->aux->filemark_cnt); - if (STp->header_ok && - STp->header_cache != NULL && - (cnt - mt_count) >= 0 && - (cnt - mt_count) < OS_FM_TAB_MAX && - (cnt - mt_count) < STp->filemark_cnt && - STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos) - - last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]); -#if DEBUG - if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX) - printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, - STp->header_cache == NULL?"lack of header cache":"count out of range"); - else - printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", - name, cnt, - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == - STp->buffer->aux->last_mark_ppos))?"match":"error", - mt_count, last_mark_ppos); -#endif - if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) { - osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, last_mark_ppos); - return (-EIO); - } - goto found; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name); -#endif - } - cnt = 0; - while (cnt != mt_count) { - last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos); - if (last_mark_ppos == -1) - return (-EIO); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); - cnt++; - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, last_mark_ppos); - return (-EIO); - } - } -found: - if (mt_op == MTBSFM) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * ADRL 1.1 compatible "slow" space filemarks fwd version - * - * Just scans for the filemark sequentially. - */ -static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - int cnt = 0; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); -#endif - return (-EIO); - } - while (1) { - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) - cnt++; - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); -#endif - if (STp->first_frame_position > STp->eod_frame_ppos+1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n", - name, STp->eod_frame_ppos, STp->first_frame_position-1); -#endif - STp->eod_frame_ppos = STp->first_frame_position-1; - } - return (-EIO); - } - if (cnt == mt_count) - break; - STp->frame_in_buffer = 0; - } - if (mt_op == MTFSF) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * Fast linux specific version of OnStream FSF - */ -static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt, - int mt_op, int mt_count) -{ - char * name = tape_name(STp); - int cnt = 0, - next_mark_ppos = -1; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count); -#endif - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); -#endif - return (-EIO); - } - - if (STp->linux_media_version >= 4) { - /* - * direct lookup in header filemark list - */ - cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1; - if (STp->header_ok && - STp->header_cache != NULL && - (cnt + mt_count) < OS_FM_TAB_MAX && - (cnt + mt_count) < STp->filemark_cnt && - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos))) - - next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]); -#if DEBUG - if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX) - printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, - STp->header_cache == NULL?"lack of header cache":"count out of range"); - else - printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", - name, cnt, - ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || - (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == - STp->buffer->aux->last_mark_ppos))?"match":"error", - mt_count, next_mark_ppos); -#endif - if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); - } else { - osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, next_mark_ppos); - return (-EIO); - } - if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) { - printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n", - name, cnt+mt_count, next_mark_ppos, - ntohl(STp->buffer->aux->filemark_cnt)); - return (-EIO); - } - } - } else { - /* - * Find nearest (usually previous) marker, then jump from marker to marker - */ - while (1) { - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) - break; - if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); -#endif - return (-EIO); - } - if (ntohl(STp->buffer->aux->filemark_cnt) == 0) { - if (STp->first_mark_ppos == -1) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); - } - osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n", - name, STp->first_mark_ppos); - return (-EIO); - } - } else { - if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0) - return (-EIO); - mt_count++; - } - } - cnt++; - while (cnt != mt_count) { - next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos); - if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); -#endif - return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt); - } -#if DEBUG - else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); - cnt++; - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", - name); -#endif - return (-EIO); - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { - printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", - name, next_mark_ppos); - return (-EIO); - } - } - } - if (mt_op == MTFSF) { - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->buffer_bytes = 0; - STp->buffer->read_pointer = 0; - STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); - } - return 0; -} - -/* - * In debug mode, we want to see as many errors as possible - * to test the error recovery mechanism. - */ -#if DEBUG -static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = * aSRpnt; - char * name = tape_name(STp); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH; - - (STp->buffer)->b_data[0] = cmd[4] - 1; - (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ - (STp->buffer)->b_data[2] = 0; /* Reserved */ - (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7); - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries; - - if (debugging) - printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries); - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result) - printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries); -} -#endif - - -static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int result; - int this_mark_ppos = STp->first_frame_position; - int this_mark_lbn = STp->logical_blk_num; -#if DEBUG - char * name = tape_name(STp); -#endif - - if (STp->raw) return 0; - - STp->write_type = OS_WRITE_NEW_MARK; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", - name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn); -#endif - STp->dirty = 1; - result = osst_flush_write_buffer(STp, aSRpnt); - result |= osst_flush_drive_buffer(STp, aSRpnt); - STp->last_mark_ppos = this_mark_ppos; - STp->last_mark_lbn = this_mark_lbn; - if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX) - STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos); - if (STp->filemark_cnt++ == 0) - STp->first_mark_ppos = this_mark_ppos; - return result; -} - -static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int result; -#if DEBUG - char * name = tape_name(STp); -#endif - - if (STp->raw) return 0; - - STp->write_type = OS_WRITE_EOD; - STp->eod_frame_ppos = STp->first_frame_position; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name, - STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num); -#endif - STp->dirty = 1; - - result = osst_flush_write_buffer(STp, aSRpnt); - result |= osst_flush_drive_buffer(STp, aSRpnt); - STp->eod_frame_lfa = --(STp->frame_seq_number); - return result; -} - -static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count) -{ - char * name = tape_name(STp); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where); -#endif - osst_wait_ready(STp, aSRpnt, 60 * 5, 0); - osst_set_frame_position(STp, aSRpnt, where, 0); - STp->write_type = OS_WRITE_FILLER; - while (count--) { - memcpy(STp->buffer->b_data, "Filler", 6); - STp->buffer->buffer_bytes = 6; - STp->dirty = 1; - if (osst_flush_write_buffer(STp, aSRpnt)) { - printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name); - return (-EIO); - } - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name); -#endif - return osst_flush_drive_buffer(STp, aSRpnt); -} - -static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count) -{ - char * name = tape_name(STp); - int result; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where); -#endif - osst_wait_ready(STp, aSRpnt, 60 * 5, 0); - osst_set_frame_position(STp, aSRpnt, where, 0); - STp->write_type = OS_WRITE_HEADER; - while (count--) { - osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache); - STp->buffer->buffer_bytes = sizeof(os_header_t); - STp->dirty = 1; - if (osst_flush_write_buffer(STp, aSRpnt)) { - printk(KERN_INFO "%s:I: Couldn't write header frame\n", name); - return (-EIO); - } - } - result = osst_flush_drive_buffer(STp, aSRpnt); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done"); -#endif - return result; -} - -static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod) -{ - os_header_t * header; - int result; - char * name = tape_name(STp); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name); -#endif - if (STp->raw) return 0; - - if (STp->header_cache == NULL) { - if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { - printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); - return (-ENOMEM); - } - memset(STp->header_cache, 0, sizeof(os_header_t)); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name); -#endif - } - if (STp->header_ok) STp->update_frame_cntr++; - else STp->update_frame_cntr = 0; - - header = STp->header_cache; - strcpy(header->ident_str, "ADR_SEQ"); - header->major_rev = 1; - header->minor_rev = 4; - header->ext_trk_tb_off = htons(17192); - header->pt_par_num = 1; - header->partition[0].partition_num = OS_DATA_PARTITION; - header->partition[0].par_desc_ver = OS_PARTITION_VERSION; - header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr); - header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos); - header->partition[0].last_frame_ppos = htonl(STp->capacity); - header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos); - header->cfg_col_width = htonl(20); - header->dat_col_width = htonl(1500); - header->qfa_col_width = htonl(0); - header->ext_track_tb.nr_stream_part = 1; - header->ext_track_tb.et_ent_sz = 32; - header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0; - header->ext_track_tb.dat_ext_trk_ey.fmt = 1; - header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736); - header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0; - header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa); - header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos); - header->dat_fm_tab.fm_part_num = 0; - header->dat_fm_tab.fm_tab_ent_sz = 4; - header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cntfilemark_cnt:OS_FM_TAB_MAX); - - result = __osst_write_header(STp, aSRpnt, 0xbae, 5); - if (STp->update_frame_cntr == 0) - osst_write_filler(STp, aSRpnt, 0xbb3, 5); - result &= __osst_write_header(STp, aSRpnt, 5, 5); - - if (locate_eod) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos); -#endif - osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0); - } - if (result) - printk(KERN_ERR "%s:E: Write header failed\n", name); - else { - memcpy(STp->application_sig, "LIN4", 4); - STp->linux_media = 1; - STp->linux_media_version = 4; - STp->header_ok = 1; - } - return result; -} - -static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - if (STp->header_cache != NULL) - memset(STp->header_cache, 0, sizeof(os_header_t)); - - STp->logical_blk_num = STp->frame_seq_number = 0; - STp->frame_in_buffer = 0; - STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A; - STp->filemark_cnt = 0; - STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; - return osst_write_header(STp, aSRpnt, 1); -} - -static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos) -{ - char * name = tape_name(STp); - os_header_t * header; - os_aux_t * aux; - char id_string[8]; - int linux_media_version, - update_frame_cntr; - - if (STp->raw) - return 1; - - if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) { - if (osst_set_frame_position(STp, aSRpnt, ppos, 0)) - printk(KERN_WARNING "%s:W: Couldn't position tape\n", name); - osst_wait_ready(STp, aSRpnt, 60 * 15, 0); - if (osst_initiate_read (STp, aSRpnt)) { - printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name); - return 0; - } - } - if (osst_read_frame(STp, aSRpnt, 180)) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name); -#endif - return 0; - } - header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */ - aux = STp->buffer->aux; - if (aux->frame_type != OS_FRAME_TYPE_HEADER) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos); -#endif - return 0; - } - if (ntohl(aux->frame_seq_num) != 0 || - ntohl(aux->logical_blk_num) != 0 || - aux->partition.partition_num != OS_CONFIG_PARTITION || - ntohl(aux->partition.first_frame_ppos) != 0 || - ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name, - ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), - aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos), - ntohl(aux->partition.last_frame_ppos)); -#endif - return 0; - } - if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 && - strncmp(header->ident_str, "ADR-SEQ", 7) != 0) { - strlcpy(id_string, header->ident_str, 8); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string); -#endif - return 0; - } - update_frame_cntr = ntohl(aux->update_frame_cntr); - if (update_frame_cntr < STp->update_frame_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n", - name, ppos, update_frame_cntr, STp->update_frame_cntr); -#endif - return 0; - } - if (header->major_rev != 1 || header->minor_rev != 4 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n", - name, (header->major_rev != 1 || header->minor_rev < 2 || - header->minor_rev > 4 )? "Invalid" : "Warning:", - header->major_rev, header->minor_rev); -#endif - if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4) - return 0; - } -#if DEBUG - if (header->pt_par_num != 1) - printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n", - name, header->pt_par_num); -#endif - memcpy(id_string, aux->application_sig, 4); - id_string[4] = 0; - if (memcmp(id_string, "LIN", 3) == 0) { - STp->linux_media = 1; - linux_media_version = id_string[3] - '0'; - if (linux_media_version != 4) - printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n", - name, linux_media_version); - } else { - printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string); - return 0; - } - if (linux_media_version < STp->linux_media_version) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n", - name, ppos, linux_media_version); -#endif - return 0; - } - if (linux_media_version > STp->linux_media_version) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n", - name, ppos, linux_media_version); -#endif - memcpy(STp->application_sig, id_string, 5); - STp->linux_media_version = linux_media_version; - STp->update_frame_cntr = -1; - } - if (update_frame_cntr > STp->update_frame_cntr) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n", - name, ppos, update_frame_cntr); -#endif - if (STp->header_cache == NULL) { - if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { - printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); - return 0; - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name); -#endif - } - osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache); - header = STp->header_cache; /* further accesses from cached (full) copy */ - - STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr); - STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos); - STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos); - STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb); - STp->filemark_cnt = ntohl(aux->filemark_cnt); - STp->first_mark_ppos = ntohl(aux->next_mark_ppos); - STp->last_mark_ppos = ntohl(aux->last_mark_ppos); - STp->last_mark_lbn = ntohl(aux->last_mark_lbn); - STp->update_frame_cntr = update_frame_cntr; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n", - name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt); - printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name, - STp->first_data_ppos, - ntohl(header->partition[0].last_frame_ppos), - ntohl(header->partition[0].eod_frame_ppos)); - printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n", - name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos); -#endif - if (header->minor_rev < 4 && STp->linux_media_version == 4) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name); -#endif - memcpy((void *)header->dat_fm_tab.fm_tab_ent, - (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent)); - memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list)); - } - if (header->minor_rev == 4 && - (header->ext_trk_tb_off != htons(17192) || - header->partition[0].partition_num != OS_DATA_PARTITION || - header->partition[0].par_desc_ver != OS_PARTITION_VERSION || - header->partition[0].last_frame_ppos != htonl(STp->capacity) || - header->cfg_col_width != htonl(20) || - header->dat_col_width != htonl(1500) || - header->qfa_col_width != htonl(0) || - header->ext_track_tb.nr_stream_part != 1 || - header->ext_track_tb.et_ent_sz != 32 || - header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION || - header->ext_track_tb.dat_ext_trk_ey.fmt != 1 || - header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) || - header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 || - header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) || - header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION || - header->dat_fm_tab.fm_tab_ent_sz != 4 || - header->dat_fm_tab.fm_tab_ent_cnt != - htons(STp->filemark_cntfilemark_cnt:OS_FM_TAB_MAX))) - printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name); - - } - - return 1; -} - -static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int position, ppos; - int first, last; - int valid = 0; - char * name = tape_name(STp); - - position = osst_get_frame_position(STp, aSRpnt); - - if (STp->raw) { - STp->header_ok = STp->linux_media = 1; - STp->linux_media_version = 0; - return 1; - } - STp->header_ok = STp->linux_media = STp->linux_media_version = 0; - STp->wrt_pass_cntr = STp->update_frame_cntr = -1; - STp->eod_frame_ppos = STp->first_data_ppos = -1; - STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reading header\n", name); -#endif - - /* optimization for speed - if we are positioned at ppos 10, read second group first */ - /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */ - - first = position==10?0xbae: 5; - last = position==10?0xbb3:10; - - for (ppos = first; ppos < last; ppos++) - if (__osst_analyze_headers(STp, aSRpnt, ppos)) - valid = 1; - - first = position==10? 5:0xbae; - last = position==10?10:0xbb3; - - for (ppos = first; ppos < last; ppos++) - if (__osst_analyze_headers(STp, aSRpnt, ppos)) - valid = 1; - - if (!valid) { - printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name); - STp->eod_frame_ppos = STp->first_data_ppos = 0; - osst_set_frame_position(STp, aSRpnt, 10, 0); - return 0; - } - if (position <= STp->first_data_ppos) { - position = STp->first_data_ppos; - STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0; - } - osst_set_frame_position(STp, aSRpnt, position, 0); - STp->header_ok = 1; - - return 1; -} - -static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt) -{ - int frame_position = STp->first_frame_position; - int frame_seq_numbr = STp->frame_seq_number; - int logical_blk_num = STp->logical_blk_num; - int halfway_frame = STp->frame_in_buffer; - int read_pointer = STp->buffer->read_pointer; - int prev_mark_ppos = -1; - int actual_mark_ppos, i, n; -#if DEBUG - char * name = tape_name(STp); - - printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name); -#endif - osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); - if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name); -#endif - return (-EIO); - } - if (STp->linux_media_version >= 4) { - for (i=0; ifilemark_cnt; i++) - if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position) - prev_mark_ppos = n; - } else - prev_mark_ppos = frame_position - 1; /* usually - we don't really know */ - actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ? - frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos); - if (frame_position != STp->first_frame_position || - frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) || - prev_mark_ppos != actual_mark_ppos ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name, - STp->first_frame_position, frame_position, - STp->frame_seq_number + (halfway_frame?0:1), - frame_seq_numbr, actual_mark_ppos, prev_mark_ppos); -#endif - return (-EIO); - } - if (halfway_frame) { - /* prepare buffer for append and rewrite on top of original */ - osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); - STp->buffer->buffer_bytes = read_pointer; - STp->ps[STp->partition].rw = ST_WRITING; - STp->dirty = 1; - } - STp->frame_in_buffer = halfway_frame; - STp->frame_seq_number = frame_seq_numbr; - STp->logical_blk_num = logical_blk_num; - return 0; -} - -/* Acc. to OnStream, the vers. numbering is the following: - * X.XX for released versions (X=digit), - * XXXY for unreleased versions (Y=letter) - * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06 - * This fn makes monoton numbers out of this scheme ... - */ -static unsigned int osst_parse_firmware_rev (const char * str) -{ - if (str[1] == '.') { - return (str[0]-'0')*10000 - +(str[2]-'0')*1000 - +(str[3]-'0')*100; - } else { - return (str[0]-'0')*10000 - +(str[1]-'0')*1000 - +(str[2]-'0')*100 - 100 - +(str[3]-'@'); - } -} - -/* - * Configure the OnStream SCII tape drive for default operation - */ -static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - char * name = tape_name(STp); - struct osst_request * SRpnt = * aSRpnt; - osst_mode_parameter_header_t * header; - osst_block_size_page_t * bs; - osst_capabilities_page_t * cp; - osst_tape_paramtr_page_t * prm; - int drive_buffer_size; - - if (STp->ready != ST_READY) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Not Ready\n", name); -#endif - return (-EIO); - } - - if (STp->os_fw_rev < 10600) { - printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev); - printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name); - } - - /* - * Configure 32.5KB (data+aux) frame size. - * Get the current frame size from the block size mode page - */ - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = BLOCK_SIZE_PAGE; - cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - if (SRpnt == NULL) { -#if DEBUG - printk(OSST_DEB_MSG "osst :D: Busy\n"); -#endif - return (-EBUSY); - } - *aSRpnt = SRpnt; - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl); - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No"); - printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No"); -#endif - - /* - * Configure default auto columns mode, 32.5KB transfer mode - */ - bs->one = 1; - bs->play32 = 0; - bs->play32_5 = 1; - bs->record32 = 0; - bs->record32_5 = 1; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name); - return (-EIO); - } - -#if DEBUG - printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name); - /* - * In debug mode, we want to see as many errors as possible - * to test the error recovery mechanism. - */ - osst_set_retries(STp, aSRpnt, 0); - SRpnt = * aSRpnt; -#endif - - /* - * Set vendor name to 'LIN4' for "Linux support version 4". - */ - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; - - header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1; - header->medium_type = 0; /* Medium Type - ignoring */ - header->dsp = 0; /* Reserved */ - header->bdl = 0; /* Block Descriptor Length */ - - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7); - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4'; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name, - (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2)); - return (-EIO); - } - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = CAPABILITIES_PAGE; - cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get capabilities page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data + - sizeof(osst_mode_parameter_header_t) + header->bdl); - - drive_buffer_size = ntohs(cp->buffer_size) / 2; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = TAPE_PARAMTR_PAGE; - cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { - printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name); - return (-EIO); - } - - header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; - prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data + - sizeof(osst_mode_parameter_header_t) + header->bdl); - - STp->density = prm->density; - STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n", - name, STp->density, STp->capacity / 32, drive_buffer_size); -#endif - - return 0; - -} - - -/* Step over EOF if it has been inadvertently crossed (ioctl not used because - it messes up the block number). */ -static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward) -{ - int result; - char * name = tape_name(STp); - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n", - name, forward ? "forward" : "backward"); -#endif - - if (forward) { - /* assumes that the filemark is already read by the drive, so this is low cost */ - result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1); - } - else - /* assumes this is only called if we just read the filemark! */ - result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1); - - if (result < 0) - printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n", - name, forward ? "forward" : "backward"); - - return result; -} - - -/* Get the tape position. */ - -static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - unsigned char scmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int result = 0; - char * name = tape_name(STp); - - /* KG: We want to be able to use it for checking Write Buffer availability - * and thus don't want to risk to overwrite anything. Exchange buffers ... */ - char mybuf[24]; - char * olddata = STp->buffer->b_data; - int oldsize = STp->buffer->buffer_size; - - if (STp->ready != ST_READY) return (-EIO); - - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = READ_POSITION; - - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); - if (!SRpnt) { - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - return (-EBUSY); - } - *aSRpnt = SRpnt; - - if (STp->buffer->syscall_result) - result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */ - - if (result == -EINVAL) - printk(KERN_ERR "%s:E: Can't read tape position.\n", name); - else { - if (result == -EIO) { /* re-read position - this needs to preserve media errors */ - unsigned char mysense[16]; - memcpy (mysense, SRpnt->sense, 16); - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = READ_POSITION; - STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; - SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE, - STp->timeout, MAX_RETRIES, 1); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n", - name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:", - SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]); -#endif - if (!STp->buffer->syscall_result) - memcpy (SRpnt->sense, mysense, 16); - else - printk(KERN_WARNING "%s:W: Double error in get position\n", name); - } - STp->first_frame_position = ((STp->buffer)->b_data[4] << 24) - + ((STp->buffer)->b_data[5] << 16) - + ((STp->buffer)->b_data[6] << 8) - + (STp->buffer)->b_data[7]; - STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24) - + ((STp->buffer)->b_data[ 9] << 16) - + ((STp->buffer)->b_data[10] << 8) - + (STp->buffer)->b_data[11]; - STp->cur_frames = (STp->buffer)->b_data[15]; -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name, - STp->first_frame_position, STp->last_frame_position, - ((STp->buffer)->b_data[0]&0x80)?" (BOP)": - ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"", - STp->cur_frames); - } -#endif - if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name, - STp->first_frame_position, STp->last_frame_position, STp->cur_frames); -#endif - STp->first_frame_position = STp->last_frame_position; - } - } - STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; - - return (result == 0 ? STp->first_frame_position : result); -} - - -/* Set the tape block */ -static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip) -{ - unsigned char scmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - struct st_partstat * STps; - int result = 0; - int pp = (ppos == 3000 && !skip)? 0 : ppos; - char * name = tape_name(STp); - - if (STp->ready != ST_READY) return (-EIO); - - STps = &(STp->ps[STp->partition]); - - if (ppos < 0 || ppos > STp->capacity) { - printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos); - pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1); - result = (-EINVAL); - } - - do { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp); -#endif - memset (scmd, 0, MAX_COMMAND_SIZE); - scmd[0] = SEEK_10; - scmd[1] = 1; - scmd[3] = (pp >> 24); - scmd[4] = (pp >> 16); - scmd[5] = (pp >> 8); - scmd[6] = pp; - if (skip) - scmd[9] = 0x80; - - SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout, - MAX_RETRIES, 1); - if (!SRpnt) - return (-EBUSY); - *aSRpnt = SRpnt; - - if ((STp->buffer)->syscall_result != 0) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n", - name, STp->first_frame_position, pp); -#endif - result = (-EIO); - } - if (pp != ppos) - osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE); - } while ((pp != ppos) && (pp = ppos)); - STp->first_frame_position = STp->last_frame_position = ppos; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->rw = ST_IDLE; - STp->frame_in_buffer = 0; - return result; -} - -static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT) -{ - struct st_partstat * STps = &(STp->ps[STp->partition]); - int result = 0; - - if (STp->write_type != OS_WRITE_NEW_MARK) { - /* true unless the user wrote the filemark for us */ - result = osst_flush_drive_buffer(STp, aSRpnt); - if (result < 0) goto out; - result = osst_write_filemark(STp, aSRpnt); - if (result < 0) goto out; - - if (STps->drv_file >= 0) - STps->drv_file++ ; - STps->drv_block = 0; - } - result = osst_write_eod(STp, aSRpnt); - osst_write_header(STp, aSRpnt, leave_at_EOT); - - STps->eof = ST_FM; -out: - return result; -} - -/* osst versions of st functions - augmented and stripped to suit OnStream only */ - -/* Flush the write buffer (never need to write if variable blocksize). */ -static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt) -{ - int offset, transfer, blks = 0; - int result = 0; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = *aSRpnt; - struct st_partstat * STps; - char * name = tape_name(STp); - - if ((STp->buffer)->writing) { - if (SRpnt == (STp->buffer)->last_SRpnt) -#if DEBUG - { printk(OSST_DEB_MSG - "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name); -#endif - *aSRpnt = SRpnt = NULL; -#if DEBUG - } else if (SRpnt) - printk(OSST_DEB_MSG - "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name); -#endif - osst_write_behind_check(STp); - if ((STp->buffer)->syscall_result) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n", - name, (STp->buffer)->midlevel_result); -#endif - if ((STp->buffer)->midlevel_result == INT_MAX) - return (-ENOSPC); - return (-EIO); - } - } - - result = 0; - if (STp->dirty == 1) { - - STp->write_count++; - STps = &(STp->ps[STp->partition]); - STps->rw = ST_WRITING; - offset = STp->buffer->buffer_bytes; - blks = (offset + STp->block_size - 1) / STp->block_size; - transfer = OS_FRAME_SIZE; - - if (offset < OS_DATA_SIZE) - osst_zero_buffer_tail(STp->buffer); - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120)) - result = osst_recover_wait_frame(STp, aSRpnt, 1); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; - - switch (STp->write_type) { - case OS_WRITE_DATA: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", - name, blks, STp->frame_seq_number, - STp->logical_blk_num - blks, STp->logical_blk_num - 1); -#endif - osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, - STp->logical_blk_num - blks, STp->block_size, blks); - break; - case OS_WRITE_EOD: - osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++, - STp->logical_blk_num, 0, 0); - break; - case OS_WRITE_NEW_MARK: - osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++, - STp->logical_blk_num++, 0, blks=1); - break; - case OS_WRITE_HEADER: - osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0); - break; - default: /* probably FILLER */ - osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0); - } -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n", - name, offset, transfer, blks); -#endif - - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE, - STp->timeout, MAX_RETRIES, 1); - *aSRpnt = SRpnt; - if (!SRpnt) - return (-EBUSY); - - if ((STp->buffer)->syscall_result != 0) { -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n", - name, SRpnt->sense[0], SRpnt->sense[2], - SRpnt->sense[12], SRpnt->sense[13]); -#endif - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */ - (SRpnt->sense[2] & 0x0f) == NO_SENSE) { - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - result = (-ENOSPC); - } - else { - if (osst_write_error_recovery(STp, aSRpnt, 1)) { - printk(KERN_ERR "%s:E: Error on flush write.\n", name); - result = (-EIO); - } - } - STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */ - } - else { - STp->first_frame_position++; - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - } - } -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result); -#endif - return result; -} - - -/* Flush the tape buffer. The tape will be positioned correctly unless - seek_next is true. */ -static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next) -{ - struct st_partstat * STps; - int backspace = 0, result = 0; -#if DEBUG - char * name = tape_name(STp); -#endif - - /* - * If there was a bus reset, block further access - * to this device. - */ - if( STp->pos_unknown) - return (-EIO); - - if (STp->ready != ST_READY) - return 0; - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */ - STp->write_type = OS_WRITE_DATA; - return osst_flush_write_buffer(STp, aSRpnt); - } - if (STp->block_size == 0) - return 0; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name); -#endif - - if (!STp->can_bsr) { - backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size - - ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ; - (STp->buffer)->buffer_bytes = 0; - (STp->buffer)->read_pointer = 0; - STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */ - } - - if (!seek_next) { - if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */ - if (!result) - STps->eof = ST_NOEOF; - else { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - } - } - if (!result && backspace > 0) /* TODO -- design and run a test case for this */ - result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace); - } - else if (STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_NOEOF; - } - - return result; -} - -static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt; - int blks; -#if DEBUG - char * name = tape_name(STp); -#endif - - if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name); -#endif - if (osst_flush_drive_buffer(STp, aSRpnt) < 0) { - return (-EIO); - } - /* error recovery may have bumped us past the header partition */ - if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name); -#endif - osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8); - } - } - - if (STp->poll) - if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120)) - if (osst_recover_wait_frame(STp, aSRpnt, 1)) - return (-EIO); - -// osst_build_stats(STp, &SRpnt); - - STp->ps[STp->partition].rw = ST_WRITING; - STp->write_type = OS_WRITE_DATA; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - cmd[4] = 1; /* one frame at a time... */ - blks = STp->buffer->buffer_bytes / STp->block_size; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks, - STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1); -#endif - osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, - STp->logical_blk_num - blks, STp->block_size, blks); - -#if DEBUG - if (!synchronous) - STp->write_pending = 1; -#endif - SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout, - MAX_RETRIES, synchronous); - if (!SRpnt) - return (-EBUSY); - *aSRpnt = SRpnt; - - if (synchronous) { - if (STp->buffer->syscall_result != 0) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Error on write:\n", name); -#endif - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x40)) { - if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW) - return (-ENOSPC); - } - else { - if (osst_write_error_recovery(STp, aSRpnt, 1)) - return (-EIO); - } - } - else - STp->first_frame_position++; - } - - STp->write_count++; - - return 0; -} - -/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */ -static int do_door_lock(struct osst_tape * STp, int do_lock) -{ - int retval, cmd; - - cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl"); -#endif - retval = scsi_ioctl(STp->device, cmd, NULL); - if (!retval) { - STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED; - } - else { - STp->door_locked = ST_LOCK_FAILS; - } - return retval; -} - -/* Set the internal state after reset */ -static void reset_state(struct osst_tape *STp) -{ - int i; - struct st_partstat *STps; - - STp->pos_unknown = 0; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = -1; - STps->drv_file = -1; - } -} - - -/* Entry points to osst */ - -/* Write command */ -static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos) -{ - ssize_t total, retval = 0; - ssize_t i, do_count, blks, transfer; - int write_threshold; - int doing_write = 0; - const char __user * b_point; - struct osst_request * SRpnt = NULL; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_tape * STp = filp->private_data; - char * name = tape_name(STp); - - - if (mutex_lock_interruptible(&STp->lock)) - return (-ERESTARTSYS); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - retval = (-ENXIO); - goto out; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - retval = (-ENOMEDIUM); - else - retval = (-EIO); - goto out; - } - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } - if (count == 0) - goto out; - - /* - * If there was a bus reset, block further access - * to this device. - */ - if (STp->pos_unknown) { - retval = (-EIO); - goto out; - } - -#if DEBUG - if (!STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - - if (STp->write_prot) { - retval = (-EACCES); - goto out; - } - - /* Write must be integral number of blocks */ - if (STp->block_size != 0 && (count % STp->block_size) != 0) { - printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n", - name, count, STp->block_size<1024? - STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); - retval = (-EINVAL); - goto out; - } - - if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) { - printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n", - name, STp->first_frame_position); - retval = (-ENOSPC); - goto out; - } - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) - STp->door_locked = ST_LOCKED_AUTO; - - STps = &(STp->ps[STp->partition]); - - if (STps->rw == ST_READING) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name, - STps->drv_file, STps->drv_block); -#endif - retval = osst_flush_buffer(STp, &SRpnt, 0); - if (retval) - goto out; - STps->rw = ST_IDLE; - } - if (STps->rw != ST_WRITING) { - /* Are we totally rewriting this tape? */ - if (!STp->header_ok || - (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) || - (STps->drv_file == 0 && STps->drv_block == 0)) { - STp->wrt_pass_cntr++; -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n", - name, STp->wrt_pass_cntr); -#endif - osst_reset_header(STp, &SRpnt); - STps->drv_file = STps->drv_block = 0; - } - /* Do we know where we'll be writing on the tape? */ - else { - if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) || - STps->drv_file < 0 || STps->drv_block < 0) { - if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */ - STps->drv_file = STp->filemark_cnt; - STps->drv_block = 0; - } - else { - /* We have no idea where the tape is positioned - give up */ -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: Cannot write at indeterminate position.\n", name); -#endif - retval = (-EIO); - goto out; - } - } - if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) { - STp->filemark_cnt = STps->drv_file; - STp->last_mark_ppos = - ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]); - printk(KERN_WARNING - "%s:W: Overwriting file %d with old write pass counter %d\n", - name, STps->drv_file, STp->wrt_pass_cntr); - printk(KERN_WARNING - "%s:W: may lead to stale data being accepted on reading back!\n", - name); -#if DEBUG - printk(OSST_DEB_MSG - "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n", - name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn); -#endif - } - } - STp->fast_open = 0; - } - if (!STp->header_ok) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name); -#endif - retval = (-EIO); - goto out; - } - - if ((STp->buffer)->writing) { -if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__); - osst_write_behind_check(STp); - if ((STp->buffer)->syscall_result) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name, - (STp->buffer)->midlevel_result); -#endif - if ((STp->buffer)->midlevel_result == INT_MAX) - STps->eof = ST_EOM_OK; - else - STps->eof = ST_EOM_ERROR; - } - } - if (STps->eof == ST_EOM_OK) { - retval = (-ENOSPC); - goto out; - } - else if (STps->eof == ST_EOM_ERROR) { - retval = (-EIO); - goto out; - } - - /* Check the buffer readability in cases where copy_user might catch - the problems after some tape movement. */ - if ((copy_from_user(&i, buf, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0)) { - retval = (-EFAULT); - goto out; - } - - if (!STm->do_buffer_writes) { - write_threshold = 1; - } - else - write_threshold = (STp->buffer)->buffer_blocks * STp->block_size; - if (!STm->do_async_writes) - write_threshold--; - - total = count; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n", - name, (int) count, STps->drv_file, STps->drv_block, - STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position); -#endif - b_point = buf; - while ((STp->buffer)->buffer_bytes + count > write_threshold) - { - doing_write = 1; - do_count = (STp->buffer)->buffer_blocks * STp->block_size - - (STp->buffer)->buffer_bytes; - if (do_count > count) - do_count = count; - - i = append_to_buffer(b_point, STp->buffer, do_count); - if (i) { - retval = i; - goto out; - } - - blks = do_count / STp->block_size; - STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */ - - i = osst_write_frame(STp, &SRpnt, 1); - - if (i == (-ENOSPC)) { - transfer = STp->buffer->writing; /* FIXME -- check this logic */ - if (transfer <= do_count) { - *ppos += do_count - transfer; - count -= do_count - transfer; - if (STps->drv_block >= 0) { - STps->drv_block += (do_count - transfer) / STp->block_size; - } - STps->eof = ST_EOM_OK; - retval = (-ENOSPC); /* EOM within current request */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n", - name, (int) transfer); -#endif - } - else { - STps->eof = ST_EOM_ERROR; - STps->drv_block = (-1); /* Too cautious? */ - retval = (-EIO); /* EOM for old data */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name); -#endif - } - } - else - retval = i; - - if (retval < 0) { - if (SRpnt != NULL) { - osst_release_request(SRpnt); - SRpnt = NULL; - } - STp->buffer->buffer_bytes = 0; - STp->dirty = 0; - if (count < total) - retval = total - count; - goto out; - } - - *ppos += do_count; - b_point += do_count; - count -= do_count; - if (STps->drv_block >= 0) { - STps->drv_block += blks; - } - STp->buffer->buffer_bytes = 0; - STp->dirty = 0; - } /* end while write threshold exceeded */ - - if (count != 0) { - STp->dirty = 1; - i = append_to_buffer(b_point, STp->buffer, count); - if (i) { - retval = i; - goto out; - } - blks = count / STp->block_size; - STp->logical_blk_num += blks; - if (STps->drv_block >= 0) { - STps->drv_block += blks; - } - *ppos += count; - count = 0; - } - - if (doing_write && (STp->buffer)->syscall_result != 0) { - retval = (STp->buffer)->syscall_result; - goto out; - } - - if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) { - /* Schedule an asynchronous write */ - (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / - STp->block_size) * STp->block_size; - STp->dirty = !((STp->buffer)->writing == - (STp->buffer)->buffer_bytes); - - i = osst_write_frame(STp, &SRpnt, 0); - if (i < 0) { - retval = (-EIO); - goto out; - } - SRpnt = NULL; /* Prevent releasing this request! */ - } - STps->at_sm &= (total == 0); - if (total > 0) - STps->eof = ST_NOEOF; - - retval = total; - -out: - if (SRpnt != NULL) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - return retval; -} - - -/* Read command */ -static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos) -{ - ssize_t total, retval = 0; - ssize_t i, transfer; - int special; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp = filp->private_data; - char * name = tape_name(STp); - - - if (mutex_lock_interruptible(&STp->lock)) - return (-ERESTARTSYS); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - retval = (-ENXIO); - goto out; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - retval = (-ENOMEDIUM); - else - retval = (-EIO); - goto out; - } - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } -#if DEBUG - if (!STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - /* Must have initialized medium */ - if (!STp->header_ok) { - retval = (-EIO); - goto out; - } - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) - STp->door_locked = ST_LOCKED_AUTO; - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING) { - retval = osst_flush_buffer(STp, &SRpnt, 0); - if (retval) - goto out; - STps->rw = ST_IDLE; - /* FIXME -- this may leave the tape without EOD and up2date headers */ - } - - if ((count % STp->block_size) != 0) { - printk(KERN_WARNING - "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count, - STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); - } - -#if DEBUG - if (debugging && STps->eof != ST_NOEOF) - printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name, - STps->eof, (STp->buffer)->buffer_bytes); -#endif - if ((STp->buffer)->buffer_bytes == 0 && - STps->eof >= ST_EOD_1) { - if (STps->eof < ST_EOD) { - STps->eof += 1; - retval = 0; - goto out; - } - retval = (-EIO); /* EOM or Blank Check */ - goto out; - } - - /* Check the buffer writability before any tape movement. Don't alter - buffer data. */ - if (copy_from_user(&i, buf, 1) != 0 || - copy_to_user (buf, &i, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0 || - copy_to_user (buf + count - 1, &i, 1) != 0) { - retval = (-EFAULT); - goto out; - } - - /* Loop until enough data in buffer or a special condition found */ - for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) { - - /* Get new data if the buffer is empty */ - if ((STp->buffer)->buffer_bytes == 0) { - if (STps->eof == ST_FM_HIT) - break; - special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0); - if (special < 0) { /* No need to continue read */ - STp->frame_in_buffer = 0; - retval = special; - goto out; - } - } - - /* Move the data from driver buffer to user buffer */ - if ((STp->buffer)->buffer_bytes > 0) { -#if DEBUG - if (debugging && STps->eof != ST_NOEOF) - printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name, - STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total)); -#endif - /* force multiple of block size, note block_size may have been adjusted */ - transfer = (((STp->buffer)->buffer_bytes < count - total ? - (STp->buffer)->buffer_bytes : count - total)/ - STp->block_size) * STp->block_size; - - if (transfer == 0) { - printk(KERN_WARNING - "%s:W: Nothing can be transferred, requested %Zd, tape block size (%d%c).\n", - name, count, STp->block_size < 1024? - STp->block_size:STp->block_size/1024, - STp->block_size<1024?'b':'k'); - break; - } - i = from_buffer(STp->buffer, buf, transfer); - if (i) { - retval = i; - goto out; - } - STp->logical_blk_num += transfer / STp->block_size; - STps->drv_block += transfer / STp->block_size; - *ppos += transfer; - buf += transfer; - total += transfer; - } - - if ((STp->buffer)->buffer_bytes == 0) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n", - name, STp->frame_seq_number); -#endif - STp->frame_in_buffer = 0; - STp->frame_seq_number++; /* frame to look for next time */ - } - } /* for (total = 0, special = 0; total < count && !special; ) */ - - /* Change the eof state if no data from tape or buffer */ - if (total == 0) { - if (STps->eof == ST_FM_HIT) { - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM; - STps->drv_block = 0; - if (STps->drv_file >= 0) - STps->drv_file++; - } - else if (STps->eof == ST_EOD_1) { - STps->eof = ST_EOD_2; - if (STps->drv_block > 0 && STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - } - else if (STps->eof == ST_EOD_2) - STps->eof = ST_EOD; - } - else if (STps->eof == ST_FM) - STps->eof = ST_NOEOF; - - retval = total; - -out: - if (SRpnt != NULL) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - return retval; -} - - -/* Set the driver options */ -static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name) -{ - printk(KERN_INFO -"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", - name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, - STm->do_read_ahead); - printk(KERN_INFO -"%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", - name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); - printk(KERN_INFO -"%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", - name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, - STp->scsi2_logical); - printk(KERN_INFO -"%s:I: sysv: %d\n", name, STm->sysv); -#if DEBUG - printk(KERN_INFO - "%s:D: debugging: %d\n", - name, debugging); -#endif -} - - -static int osst_set_options(struct osst_tape *STp, long options) -{ - int value; - long code; - struct st_modedef * STm; - char * name = tape_name(STp); - - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - memcpy(STm, &(STp->modes[0]), sizeof(*STm)); - modes_defined = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n", - name, STp->current_mode); -#endif - } - - code = options & MT_ST_OPTIONS; - if (code == MT_ST_BOOLEANS) { - STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; - STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; - STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; - STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; - STp->two_fm = (options & MT_ST_TWO_FM) != 0; - STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; - STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; - STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; - STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; - if ((STp->device)->scsi_level >= SCSI_2) - STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; - STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; - STm->sysv = (options & MT_ST_SYSV) != 0; -#if DEBUG - debugging = (options & MT_ST_DEBUGGING) != 0; -#endif - osst_log_options(STp, STm, name); - } - else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { - value = (code == MT_ST_SETBOOLEANS); - if ((options & MT_ST_BUFFER_WRITES) != 0) - STm->do_buffer_writes = value; - if ((options & MT_ST_ASYNC_WRITES) != 0) - STm->do_async_writes = value; - if ((options & MT_ST_DEF_WRITES) != 0) - STm->defaults_for_writes = value; - if ((options & MT_ST_READ_AHEAD) != 0) - STm->do_read_ahead = value; - if ((options & MT_ST_TWO_FM) != 0) - STp->two_fm = value; - if ((options & MT_ST_FAST_MTEOM) != 0) - STp->fast_mteom = value; - if ((options & MT_ST_AUTO_LOCK) != 0) - STp->do_auto_lock = value; - if ((options & MT_ST_CAN_BSR) != 0) - STp->can_bsr = value; - if ((options & MT_ST_NO_BLKLIMS) != 0) - STp->omit_blklims = value; - if ((STp->device)->scsi_level >= SCSI_2 && - (options & MT_ST_CAN_PARTITIONS) != 0) - STp->can_partitions = value; - if ((options & MT_ST_SCSI2LOGICAL) != 0) - STp->scsi2_logical = value; - if ((options & MT_ST_SYSV) != 0) - STm->sysv = value; -#if DEBUG - if ((options & MT_ST_DEBUGGING) != 0) - debugging = value; -#endif - osst_log_options(STp, STm, name); - } - else if (code == MT_ST_WRITE_THRESHOLD) { - value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; - if (value < 1 || value > osst_buffer_size) { - printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n", - name, value); - return (-EIO); - } - STp->write_threshold = value; - printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n", - name, value); - } - else if (code == MT_ST_DEF_BLKSIZE) { - value = (options & ~MT_ST_OPTIONS); - if (value == ~MT_ST_OPTIONS) { - STm->default_blksize = (-1); - printk(KERN_INFO "%s:I: Default block size disabled.\n", name); - } - else { - if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) { - printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n", - name, value); - return (-EINVAL); - } - STm->default_blksize = value; - printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n", - name, STm->default_blksize); - } - } - else if (code == MT_ST_TIMEOUTS) { - value = (options & ~MT_ST_OPTIONS); - if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { - STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; - printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name, - (value & ~MT_ST_SET_LONG_TIMEOUT)); - } - else { - STp->timeout = value * HZ; - printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value); - } - } - else if (code == MT_ST_DEF_OPTIONS) { - code = (options & ~MT_ST_CLEAR_DEFAULT); - value = (options & MT_ST_CLEAR_DEFAULT); - if (code == MT_ST_DEF_DENSITY) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_density = (-1); - printk(KERN_INFO "%s:I: Density default disabled.\n", name); - } - else { - STm->default_density = value & 0xff; - printk(KERN_INFO "%s:I: Density default set to %x\n", - name, STm->default_density); - } - } - else if (code == MT_ST_DEF_DRVBUFFER) { - if (value == MT_ST_CLEAR_DEFAULT) { - STp->default_drvbuffer = 0xff; - printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name); - } - else { - STp->default_drvbuffer = value & 7; - printk(KERN_INFO "%s:I: Drive buffer default set to %x\n", - name, STp->default_drvbuffer); - } - } - else if (code == MT_ST_DEF_COMPRESSION) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_compression = ST_DONT_TOUCH; - printk(KERN_INFO "%s:I: Compression default disabled.\n", name); - } - else { - STm->default_compression = (value & 1 ? ST_YES : ST_NO); - printk(KERN_INFO "%s:I: Compression default set to %x\n", - name, (value & 1)); - } - } - } - else - return (-EIO); - - return 0; -} - - -/* Internal ioctl function */ -static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt, - unsigned int cmd_in, unsigned long arg) -{ - int timeout; - long ltmp; - int i, ioctl_result; - int chg_eof = 1; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = * aSRpnt; - struct st_partstat * STps; - int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num; - int datalen = 0, direction = DMA_NONE; - char * name = tape_name(STp); - - if (STp->ready != ST_READY && cmd_in != MTLOAD) { - if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); - else - return (-EIO); - } - timeout = STp->long_timeout; - STps = &(STp->ps[STp->partition]); - fileno = STps->drv_file; - blkno = STps->drv_block; - at_sm = STps->at_sm; - frame_seq_numbr = STp->frame_seq_number; - logical_blk_num = STp->logical_blk_num; - - memset(cmd, 0, MAX_COMMAND_SIZE); - switch (cmd_in) { - case MTFSFM: - chg_eof = 0; /* Changed from the FSF after this */ - case MTFSF: - if (STp->raw) - return (-EIO); - if (STp->linux_media) - ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg); - else - ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg); - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm &= (arg == 0); - goto os_bypass; - - case MTBSF: - chg_eof = 0; /* Changed from the FSF after this */ - case MTBSFM: - if (STp->raw) - return (-EIO); - ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg); - if (fileno >= 0) - fileno -= arg; - blkno = (-1); /* We can't know the block number */ - at_sm &= (arg == 0); - goto os_bypass; - - case MTFSR: - case MTBSR: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n", - name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num); -#endif - if (cmd_in == MTFSR) { - logical_blk_num += arg; - if (blkno >= 0) blkno += arg; - } - else { - logical_blk_num -= arg; - if (blkno >= 0) blkno -= arg; - } - ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num); - fileno = STps->drv_file; - blkno = STps->drv_block; - at_sm &= (arg == 0); - goto os_bypass; - - case MTFSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTBSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; -#if DEBUG - if (debugging) { - if (cmd[2] & 0x80) - ltmp = 0xff000000; - ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n", - name, (-ltmp)); - } -#endif - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTWEOF: - if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) { - STp->write_type = OS_WRITE_DATA; - ioctl_result = osst_flush_write_buffer(STp, &SRpnt); - } else - ioctl_result = 0; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg); -#endif - for (i=0; i= 0) fileno += arg; - if (blkno >= 0) blkno = 0; - goto os_bypass; - - case MTWSM: - if (STp->write_prot) - return (-EACCES); - if (!STp->raw) - return 0; - cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */ - if (cmd_in == MTWSM) - cmd[1] = 2; - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; - timeout = STp->timeout; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); -#endif - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm = (cmd_in == MTWSM); - break; - case MTOFFL: - case MTLOAD: - case MTUNLOAD: - case MTRETEN: - cmd[0] = START_STOP; - cmd[1] = 1; /* Don't wait for completion */ - if (cmd_in == MTLOAD) { - if (STp->ready == ST_NO_TAPE) - cmd[4] = 4; /* open tray */ - else - cmd[4] = 1; /* load */ - } - if (cmd_in == MTRETEN) - cmd[4] = 3; /* retension then mount */ - if (cmd_in == MTOFFL) - cmd[4] = 4; /* rewind then eject */ - timeout = STp->timeout; -#if DEBUG - if (debugging) { - switch (cmd_in) { - case MTUNLOAD: - printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name); - break; - case MTLOAD: - printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name); - break; - case MTRETEN: - printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name); - break; - case MTOFFL: - printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name); - break; - } - } -#endif - fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; - break; - case MTNOP: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name); -#endif - return 0; /* Should do something ? */ - break; - case MTEOM: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name); -#endif - if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) || - (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) { - ioctl_result = -EIO; - goto os_bypass; - } - if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name); -#endif - ioctl_result = -EIO; - goto os_bypass; - } - ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0); - fileno = STp->filemark_cnt; - blkno = at_sm = 0; - goto os_bypass; - - case MTERASE: - if (STp->write_prot) - return (-EACCES); - ioctl_result = osst_reset_header(STp, &SRpnt); - i = osst_write_eod(STp, &SRpnt); - if (i < ioctl_result) ioctl_result = i; - i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos); - if (i < ioctl_result) ioctl_result = i; - fileno = blkno = at_sm = 0 ; - goto os_bypass; - - case MTREW: - cmd[0] = REZERO_UNIT; /* rewind */ - cmd[1] = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]); -#endif - fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; - break; - - case MTSETBLK: /* Set block length */ - if ((STps->drv_block == 0 ) && - !STp->dirty && - ((STp->buffer)->buffer_bytes == 0) && - ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) && - ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) && - !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) { - /* - * Only allowed to change the block size if you opened the - * device at the beginning of a file before writing anything. - * Note, that when reading, changing block_size is futile, - * as the size used when writing overrides it. - */ - STp->block_size = (arg & MT_ST_BLKSIZE_MASK); - printk(KERN_INFO "%s:I: Block size set to %d bytes.\n", - name, STp->block_size); - return 0; - } - case MTSETDENSITY: /* Set tape density */ - case MTSETDRVBUFFER: /* Set drive buffering */ - case SET_DENS_AND_BLK: /* Set density and block size */ - chg_eof = 0; - if (STp->dirty || (STp->buffer)->buffer_bytes != 0) - return (-EIO); /* Not allowed if data in buffer */ - if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && - (arg & MT_ST_BLKSIZE_MASK) != 0 && - (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) { - printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n", - name, (int)(arg & MT_ST_BLKSIZE_MASK), - (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now"); - return (-EINVAL); - } - return 0; /* FIXME silently ignore if block size didn't change */ - - default: - return (-ENOSYS); - } - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1); - - ioctl_result = (STp->buffer)->syscall_result; - - if (!SRpnt) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name); -#endif - return ioctl_result; - } - - if (!ioctl_result) { /* SCSI command successful */ - STp->frame_seq_number = frame_seq_numbr; - STp->logical_blk_num = logical_blk_num; - } - -os_bypass: -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result); -#endif - - if (!ioctl_result) { /* success */ - - if (cmd_in == MTFSFM) { - fileno--; - blkno--; - } - if (cmd_in == MTBSFM) { - fileno++; - blkno++; - } - STps->drv_block = blkno; - STps->drv_file = fileno; - STps->at_sm = at_sm; - - if (cmd_in == MTEOM) - STps->eof = ST_EOD; - else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) { - ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1); - STps->drv_block++; - STp->logical_blk_num++; - STp->frame_seq_number++; - STp->frame_in_buffer = 0; - STp->buffer->read_pointer = 0; - } - else if (cmd_in == MTFSF) - STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM; - else if (chg_eof) - STps->eof = ST_NOEOF; - - if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) - STp->rew_at_close = 0; - else if (cmd_in == MTLOAD) { - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */ - } - STp->partition = 0; - } - - if (cmd_in == MTREW) { - ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); - if (ioctl_result > 0) - ioctl_result = 0; - } - - } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) { - if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0) - STps->drv_file = STps->drv_block = -1; - else - STps->drv_file = STps->drv_block = 0; - STps->eof = ST_NOEOF; - } else if (cmd_in == MTFSF || cmd_in == MTFSFM) { - if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) - STps->drv_file = STps->drv_block = -1; - else { - STps->drv_file = STp->filemark_cnt; - STps->drv_block = 0; - } - STps->eof = ST_EOD; - } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) { - STps->drv_file = STps->drv_block = (-1); - STps->eof = ST_NOEOF; - STp->header_ok = 0; - } else if (cmd_in == MTERASE) { - STp->header_ok = 0; - } else if (SRpnt) { /* SCSI command was not completely successful. */ - if (SRpnt->sense[2] & 0x40) { - STps->eof = ST_EOM_OK; - STps->drv_block = 0; - } - if (chg_eof) - STps->eof = ST_NOEOF; - - if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK) - STps->eof = ST_EOD; - - if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60)) - ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE); - } - *aSRpnt = SRpnt; - - return ioctl_result; -} - - -/* Open the device */ -static int __os_scsi_tape_open(struct inode * inode, struct file * filp) -{ - unsigned short flags; - int i, b_size, new_session = 0, retval = 0; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp; - struct st_modedef * STm; - struct st_partstat * STps; - char * name; - int dev = TAPE_NR(inode); - int mode = TAPE_MODE(inode); - - /* - * We really want to do nonseekable_open(inode, filp); here, but some - * versions of tar incorrectly call lseek on tapes and bail out if that - * fails. So we disallow pread() and pwrite(), but permit lseeks. - */ - filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); - - write_lock(&os_scsi_tapes_lock); - if (dev >= osst_max_dev || os_scsi_tapes == NULL || - (STp = os_scsi_tapes[dev]) == NULL || !STp->device) { - write_unlock(&os_scsi_tapes_lock); - return (-ENXIO); - } - - name = tape_name(STp); - - if (STp->in_use) { - write_unlock(&os_scsi_tapes_lock); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name); -#endif - return (-EBUSY); - } - if (scsi_device_get(STp->device)) { - write_unlock(&os_scsi_tapes_lock); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name); -#endif - return (-ENXIO); - } - filp->private_data = STp; - STp->in_use = 1; - write_unlock(&os_scsi_tapes_lock); - STp->rew_at_close = TAPE_REWIND(inode); - - if( !scsi_block_when_processing_errors(STp->device) ) { - return -ENXIO; - } - - if (mode != STp->current_mode) { -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n", - name, STp->current_mode, mode); -#endif - new_session = 1; - STp->current_mode = mode; - } - STm = &(STp->modes[STp->current_mode]); - - flags = filp->f_flags; - STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); - - STp->raw = TAPE_IS_RAW(inode); - if (STp->raw) - STp->header_ok = 0; - - /* Allocate data segments for this device's tape buffer */ - if (!enlarge_buffer(STp->buffer, STp->restr_dma)) { - printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name); - retval = (-EOVERFLOW); - goto err_out; - } - if (STp->buffer->buffer_size >= OS_FRAME_SIZE) { - for (i = 0, b_size = 0; - (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE); - b_size += STp->buffer->sg[i++].length); - STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name, - STp->buffer->b_data, page_address(STp->buffer->sg[0].page)); - printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name, - STp->buffer->aux, i, page_address(STp->buffer->sg[i].page)); -#endif - } else { - STp->buffer->aux = NULL; /* this had better never happen! */ - printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE); - retval = (-EIO); - goto err_out; - } - STp->buffer->writing = 0; - STp->buffer->syscall_result = 0; - STp->dirty = 0; - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - } - STp->ready = ST_READY; -#if DEBUG - STp->nbr_waits = STp->nbr_finished = 0; -#endif - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); - if (!SRpnt) { - retval = (STp->buffer)->syscall_result; /* FIXME - valid? */ - goto err_out; - } - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == NOT_READY && - SRpnt->sense[12] == 4 ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]); -#endif - if (filp->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto err_out; - } - if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */ - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = START_STOP; - cmd[1] = 1; - cmd[4] = 1; - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - } - osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0); - } - if ((SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name); -#endif - STp->header_ok = 0; - - for (i=0; i < 10; i++) { - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - if ((SRpnt->sense[0] & 0x70) != 0x70 || - (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION) - break; - } - - STp->pos_unknown = 0; - STp->partition = STp->new_partition = 0; - if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = 0; - STps->drv_file = 0 ; - } - new_session = 1; - STp->recover_count = 0; - STp->abort_count = 0; - } - /* - * if we have valid headers from before, and the drive/tape seem untouched, - * open without reconfiguring and re-reading the headers - */ - if (!STp->buffer->syscall_result && STp->header_ok && - !SRpnt->result && SRpnt->sense[0] == 0) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[1] = 8; - cmd[2] = VENDOR_IDENT_PAGE; - cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); - - if (STp->buffer->syscall_result || - STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' || - STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) { -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name, - STp->buffer->b_data[MODE_HEADER_LENGTH + 2], - STp->buffer->b_data[MODE_HEADER_LENGTH + 3], - STp->buffer->b_data[MODE_HEADER_LENGTH + 4], - STp->buffer->b_data[MODE_HEADER_LENGTH + 5]); -#endif - STp->header_ok = 0; - } - i = STp->first_frame_position; - if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) { - if (STp->door_locked == ST_UNLOCKED) { - if (do_door_lock(STp, 1)) - printk(KERN_INFO "%s:I: Can't lock drive door\n", name); - else - STp->door_locked = ST_LOCKED_AUTO; - } - if (!STp->frame_in_buffer) { - STp->block_size = (STm->default_blksize > 0) ? - STm->default_blksize : OS_DATA_SIZE; - STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; - } - STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; - STp->fast_open = 1; - osst_release_request(SRpnt); - return 0; - } -#if DEBUG - if (i != STp->first_frame_position) - printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n", - name, i, STp->first_frame_position); -#endif - STp->header_ok = 0; - } - STp->fast_open = 0; - - if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */ - (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) { - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = 0x10; - cmd[4] = 4 + MODE_HEADER_LENGTH; - - (STp->buffer)->b_data[0] = cmd[4] - 1; - (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ - (STp->buffer)->b_data[2] = 0; /* Reserved */ - (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2; - (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3; - -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name); -#endif - SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); - - STp->header_ok = 0; - - for (i=0; i < 10; i++) { - - memset (cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - - SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->timeout, MAX_RETRIES, 1); - if ((SRpnt->sense[0] & 0x70) != 0x70 || - (SRpnt->sense[2] & 0x0f) == NOT_READY) - break; - - if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { - int j; - - STp->pos_unknown = 0; - STp->partition = STp->new_partition = 0; - if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ - for (j = 0; j < ST_NBR_PARTITIONS; j++) { - STps = &(STp->ps[j]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = 0; - STps->drv_file = 0 ; - } - new_session = 1; - } - } - } - - if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */ - printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name); - - if ((STp->buffer)->syscall_result != 0) { - if ((STp->device)->scsi_level >= SCSI_2 && - (SRpnt->sense[0] & 0x70) == 0x70 && - (SRpnt->sense[2] & 0x0f) == NOT_READY && - SRpnt->sense[12] == 0x3a) { /* Check ASC */ - STp->ready = ST_NO_TAPE; - } else - STp->ready = ST_NOT_READY; - osst_release_request(SRpnt); - SRpnt = NULL; - STp->density = 0; /* Clear the erroneous "residue" */ - STp->write_prot = 0; - STp->block_size = 0; - STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); - STp->partition = STp->new_partition = 0; - STp->door_locked = ST_UNLOCKED; - return 0; - } - - osst_configure_onstream(STp, &SRpnt); - - STp->block_size = STp->raw ? OS_FRAME_SIZE : ( - (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); - STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size; - STp->buffer->buffer_bytes = - STp->buffer->read_pointer = - STp->frame_in_buffer = 0; - -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n", - name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size, - (STp->buffer)->buffer_blocks); -#endif - - if (STp->drv_write_prot) { - STp->write_prot = 1; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Write protected\n", name); -#endif - if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { - retval = (-EROFS); - goto err_out; - } - } - - if (new_session) { /* Change the drive parameters for the new mode */ -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: New Session\n", name); -#endif - STp->density_changed = STp->blksize_changed = 0; - STp->compression_changed = 0; - } - - /* - * properly position the tape and check the ADR headers - */ - if (STp->door_locked == ST_UNLOCKED) { - if (do_door_lock(STp, 1)) - printk(KERN_INFO "%s:I: Can't lock drive door\n", name); - else - STp->door_locked = ST_LOCKED_AUTO; - } - - osst_analyze_headers(STp, &SRpnt); - - osst_release_request(SRpnt); - SRpnt = NULL; - - return 0; - -err_out: - if (SRpnt != NULL) - osst_release_request(SRpnt); - normalize_buffer(STp->buffer); - STp->header_ok = 0; - STp->in_use = 0; - scsi_device_put(STp->device); - - return retval; -} - -/* BKL pushdown: spaghetti avoidance wrapper */ -static int os_scsi_tape_open(struct inode * inode, struct file * filp) -{ - int ret; - - mutex_lock(&osst_int_mutex); - ret = __os_scsi_tape_open(inode, filp); - mutex_unlock(&osst_int_mutex); - return ret; -} - - - -/* Flush the tape buffer before close */ -static int os_scsi_tape_flush(struct file * filp, fl_owner_t id) -{ - int result = 0, result2; - struct osst_tape * STp = filp->private_data; - struct st_modedef * STm = &(STp->modes[STp->current_mode]); - struct st_partstat * STps = &(STp->ps[STp->partition]); - struct osst_request * SRpnt = NULL; - char * name = tape_name(STp); - - if (file_count(filp) > 1) - return 0; - - if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) { - STp->write_type = OS_WRITE_DATA; - result = osst_flush_write_buffer(STp, &SRpnt); - if (result != 0 && result != (-ENOSPC)) - goto out; - } - if ( STps->rw >= ST_WRITING && !STp->pos_unknown) { - -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n", - name, (long)(filp->f_pos)); - printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n", - name, STp->nbr_waits, STp->nbr_finished); - } -#endif - result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close)); -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n", - name, 1+STp->two_fm); -#endif - } - else if (!STp->rew_at_close) { - STps = &(STp->ps[STp->partition]); - if (!STm->sysv || STps->rw != ST_READING) { - if (STp->can_bsr) - result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */ - else if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, &SRpnt, 0); - if (result) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - else - STps->eof = ST_NOEOF; - } - } - else if ((STps->eof == ST_NOEOF && - !(result = cross_eof(STp, &SRpnt, 1))) || - STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - } - -out: - if (STp->rew_at_close) { - result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); - STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0; - if (result == 0 && result2 < 0) - result = result2; - } - if (SRpnt) osst_release_request(SRpnt); - - if (STp->abort_count || STp->recover_count) { - printk(KERN_INFO "%s:I:", name); - if (STp->abort_count) - printk(" %d unrecovered errors", STp->abort_count); - if (STp->recover_count) - printk(" %d recovered errors", STp->recover_count); - if (STp->write_count) - printk(" in %d frames written", STp->write_count); - if (STp->read_count) - printk(" in %d frames read", STp->read_count); - printk("\n"); - STp->recover_count = 0; - STp->abort_count = 0; - } - STp->write_count = 0; - STp->read_count = 0; - - return result; -} - - -/* Close the device and release it */ -static int os_scsi_tape_close(struct inode * inode, struct file * filp) -{ - int result = 0; - struct osst_tape * STp = filp->private_data; - - if (STp->door_locked == ST_LOCKED_AUTO) - do_door_lock(STp, 0); - - if (STp->raw) - STp->header_ok = 0; - - normalize_buffer(STp->buffer); - write_lock(&os_scsi_tapes_lock); - STp->in_use = 0; - write_unlock(&os_scsi_tapes_lock); - - scsi_device_put(STp->device); - - return result; -} - - -/* The ioctl command */ -static long osst_ioctl(struct file * file, - unsigned int cmd_in, unsigned long arg) -{ - int i, cmd_nr, cmd_type, blk, retval = 0; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_request * SRpnt = NULL; - struct osst_tape * STp = file->private_data; - char * name = tape_name(STp); - void __user * p = (void __user *)arg; - - mutex_lock(&osst_int_mutex); - if (mutex_lock_interruptible(&STp->lock)) { - mutex_unlock(&osst_int_mutex); - return -ERESTARTSYS; - } - -#if DEBUG - if (debugging && !STp->in_use) { - printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } -#endif - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if( !scsi_block_when_processing_errors(STp->device) ) { - retval = (-ENXIO); - goto out; - } - - cmd_type = _IOC_TYPE(cmd_in); - cmd_nr = _IOC_NR(cmd_in); -#if DEBUG - printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name, - cmd_type, cmd_nr, STp->raw?"raw":"normal"); -#endif - if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { - struct mtop mtc; - int auto_weof = 0; - - if (_IOC_SIZE(cmd_in) != sizeof(mtc)) { - retval = (-EINVAL); - goto out; - } - - i = copy_from_user((char *) &mtc, p, sizeof(struct mtop)); - if (i) { - retval = (-EFAULT); - goto out; - } - - if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { - printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name); - retval = (-EPERM); - goto out; - } - - if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) { - retval = (-ENXIO); - goto out; - } - - if (!STp->pos_unknown) { - - if (STps->eof == ST_FM_HIT) { - if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) { - mtc.mt_count -= 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { - mtc.mt_count += 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - } - - if (mtc.mt_op == MTSEEK) { - /* Old position must be restored if partition will be changed */ - i = !STp->can_partitions || (STp->new_partition != STp->partition); - } - else { - i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || - mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || - mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || - mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || - mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM || - mtc.mt_op == MTCOMPRESSION; - } - i = osst_flush_buffer(STp, &SRpnt, i); - if (i < 0) { - retval = i; - goto out; - } - } - else { - /* - * If there was a bus reset, block further access - * to this device. If the user wants to rewind the tape, - * then reset the flag and allow access again. - */ - if(mtc.mt_op != MTREW && - mtc.mt_op != MTOFFL && - mtc.mt_op != MTRETEN && - mtc.mt_op != MTERASE && - mtc.mt_op != MTSEEK && - mtc.mt_op != MTEOM) { - retval = (-EIO); - goto out; - } - reset_state(STp); - /* remove this when the midlevel properly clears was_reset */ - STp->device->was_reset = 0; - } - - if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK && - mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && - mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER && - mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART && - mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) { - - /* - * The user tells us to move to another position on the tape. - * If we were appending to the tape content, that would leave - * the tape without proper end, in that case write EOD and - * update the header to reflect its position. - */ -#if DEBUG - printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name, - STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle", - STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number, - STp->logical_blk_num, STps->drv_file, STps->drv_block ); -#endif - if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) { - auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) && - !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL)); - i = osst_write_trailer(STp, &SRpnt, - !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL)); -#if DEBUG - printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", - name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos, - STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block ); -#endif - if (i < 0) { - retval = i; - goto out; - } - } - STps->rw = ST_IDLE; - } - - if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) - do_door_lock(STp, 0); /* Ignore result! */ - - if (mtc.mt_op == MTSETDRVBUFFER && - (mtc.mt_count & MT_ST_OPTIONS) != 0) { - retval = osst_set_options(STp, mtc.mt_count); - goto out; - } - - if (mtc.mt_op == MTSETPART) { - if (mtc.mt_count >= STp->nbr_partitions) - retval = -EINVAL; - else { - STp->new_partition = mtc.mt_count; - retval = 0; - } - goto out; - } - - if (mtc.mt_op == MTMKPART) { - if (!STp->can_partitions) { - retval = (-EINVAL); - goto out; - } - if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*|| - (i = partition_tape(inode, mtc.mt_count)) < 0*/) { - retval = i; - goto out; - } - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].at_sm = 0; - STp->ps[i].last_block_valid = 0; - } - STp->partition = STp->new_partition = 0; - STp->nbr_partitions = 1; /* Bad guess ?-) */ - STps->drv_block = STps->drv_file = 0; - retval = 0; - goto out; - } - - if (mtc.mt_op == MTSEEK) { - if (STp->raw) - i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0); - else - i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); - if (!STp->can_partitions) - STp->ps[0].rw = ST_IDLE; - retval = i; - goto out; - } - - if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) { - retval = do_door_lock(STp, (mtc.mt_op == MTLOCK)); - goto out; - } - - if (auto_weof) - cross_eof(STp, &SRpnt, 0); - - if (mtc.mt_op == MTCOMPRESSION) - retval = -EINVAL; /* OnStream drives don't have compression hardware */ - else - /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS - * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */ - retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count); - goto out; - } - - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } - - if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) { - retval = i; - goto out; - } - - if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { - struct mtget mt_status; - - if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { - retval = (-EINVAL); - goto out; - } - - mt_status.mt_type = MT_ISONSTREAM_SC; - mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT; - mt_status.mt_dsreg = - ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | - ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); - mt_status.mt_blkno = STps->drv_block; - mt_status.mt_fileno = STps->drv_file; - if (STp->block_size != 0) { - if (STps->rw == ST_WRITING) - mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size; - else if (STps->rw == ST_READING) - mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes + - STp->block_size - 1) / STp->block_size; - } - - mt_status.mt_gstat = 0; - if (STp->drv_write_prot) - mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff); - if (mt_status.mt_blkno == 0) { - if (mt_status.mt_fileno == 0) - mt_status.mt_gstat |= GMT_BOT(0xffffffff); - else - mt_status.mt_gstat |= GMT_EOF(0xffffffff); - } - mt_status.mt_resid = STp->partition; - if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) - mt_status.mt_gstat |= GMT_EOT(0xffffffff); - else if (STps->eof >= ST_EOM_OK) - mt_status.mt_gstat |= GMT_EOD(0xffffffff); - if (STp->density == 1) - mt_status.mt_gstat |= GMT_D_800(0xffffffff); - else if (STp->density == 2) - mt_status.mt_gstat |= GMT_D_1600(0xffffffff); - else if (STp->density == 3) - mt_status.mt_gstat |= GMT_D_6250(0xffffffff); - if (STp->ready == ST_READY) - mt_status.mt_gstat |= GMT_ONLINE(0xffffffff); - if (STp->ready == ST_NO_TAPE) - mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff); - if (STps->at_sm) - mt_status.mt_gstat |= GMT_SM(0xffffffff); - if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || - STp->drv_buffer != 0) - mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); - - i = copy_to_user(p, &mt_status, sizeof(struct mtget)); - if (i) { - retval = (-EFAULT); - goto out; - } - - STp->recover_erreg = 0; /* Clear after read */ - retval = 0; - goto out; - } /* End of MTIOCGET */ - - if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { - struct mtpos mt_pos; - - if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) { - retval = (-EINVAL); - goto out; - } - if (STp->raw) - blk = osst_get_frame_position(STp, &SRpnt); - else - blk = osst_get_sector(STp, &SRpnt); - if (blk < 0) { - retval = blk; - goto out; - } - mt_pos.mt_blkno = blk; - i = copy_to_user(p, &mt_pos, sizeof(struct mtpos)); - if (i) - retval = -EFAULT; - goto out; - } - if (SRpnt) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - - retval = scsi_ioctl(STp->device, cmd_in, p); - mutex_unlock(&osst_int_mutex); - return retval; - -out: - if (SRpnt) osst_release_request(SRpnt); - - mutex_unlock(&STp->lock); - mutex_unlock(&osst_int_mutex); - - return retval; -} - -#ifdef CONFIG_COMPAT -static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg) -{ - struct osst_tape *STp = file->private_data; - struct scsi_device *sdev = STp->device; - int ret = -ENOIOCTLCMD; - if (sdev->host->hostt->compat_ioctl) { - - ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); - - } - return ret; -} -#endif - - - -/* Memory handling routines */ - -/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */ -static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg ) -{ - int i; - gfp_t priority; - struct osst_buffer *tb; - - if (from_initialization) - priority = GFP_ATOMIC; - else - priority = GFP_KERNEL; - - i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = kzalloc(i, priority); - if (!tb) { - printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n"); - return NULL; - } - - tb->sg_segs = tb->orig_sg_segs = 0; - tb->use_sg = max_sg; - tb->in_use = 1; - tb->dma = need_dma; - tb->buffer_size = 0; -#if DEBUG - if (debugging) - printk(OSST_DEB_MSG - "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n", - i, max_sg, need_dma); -#endif - return tb; -} - -/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */ -static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) -{ - int segs, nbr, max_segs, b_size, order, got; - gfp_t priority; - - if (STbuffer->buffer_size >= OS_FRAME_SIZE) - return 1; - - if (STbuffer->sg_segs) { - printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n"); - normalize_buffer(STbuffer); - } - /* See how many segments we can use -- need at least two */ - nbr = max_segs = STbuffer->use_sg; - if (nbr <= 2) - return 0; - - priority = GFP_KERNEL /* | __GFP_NOWARN */; - if (need_dma) - priority |= GFP_DMA; - - /* Try to allocate the first segment up to OS_DATA_SIZE and the others - big enough to reach the goal (code assumes no segments in place) */ - for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) { - struct page *page = alloc_pages(priority, order); - - STbuffer->sg[0].offset = 0; - if (page != NULL) { - sg_set_page(&STbuffer->sg[0], page, b_size, 0); - STbuffer->b_data = page_address(page); - break; - } - } - if (sg_page(&STbuffer->sg[0]) == NULL) { - printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n"); - return 0; - } - /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */ - for (segs=STbuffer->sg_segs=1, got=b_size; - segs < max_segs && got < OS_FRAME_SIZE; ) { - struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); - STbuffer->sg[segs].offset = 0; - if (page == NULL) { - printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", - OS_FRAME_SIZE); -#if DEBUG - STbuffer->buffer_size = got; -#endif - normalize_buffer(STbuffer); - return 0; - } - sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0); - got += STbuffer->sg[segs].length; - STbuffer->buffer_size = got; - STbuffer->sg_segs = ++segs; - } -#if DEBUG - if (debugging) { - printk(OSST_DEB_MSG - "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n", - got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data); - printk(OSST_DEB_MSG - "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n", - STbuffer->sg[0].length, page_address(STbuffer->sg[0].page), - STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page)); - } -#endif - - return 1; -} - - -/* Release the segments */ -static void normalize_buffer(struct osst_buffer *STbuffer) -{ - int i, order, b_size; - - for (i=0; i < STbuffer->sg_segs; i++) { - - for (b_size = PAGE_SIZE, order = 0; - b_size < STbuffer->sg[i].length; - b_size *= 2, order++); - - __free_pages(sg_page(&STbuffer->sg[i]), order); - STbuffer->buffer_size -= STbuffer->sg[i].length; - } -#if DEBUG - if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) - printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n", - STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); -#endif - STbuffer->sg_segs = STbuffer->orig_sg_segs = 0; -} - - -/* Move data from the user buffer to the tape buffer. Returns zero (success) or - negative error code. */ -static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count) -{ - int i, cnt, res, offset; - - for (i=0, offset=st_bp->buffer_bytes; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n"); - return (-EIO); - } - for ( ; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count; - res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n", - do_count); - return (-EIO); - } - return 0; -} - - -/* Move data from the tape buffer to the user buffer. Returns zero (success) or - negative error code. */ -static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count) -{ - int i, cnt, res, offset; - - for (i=0, offset=st_bp->read_pointer; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n"); - return (-EIO); - } - for ( ; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count; - res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes -= cnt; - st_bp->read_pointer += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count); - return (-EIO); - } - return 0; -} - -/* Sets the tail of the buffer after fill point to zero. - Returns zero (success) or negative error code. */ -static int osst_zero_buffer_tail(struct osst_buffer *st_bp) -{ - int i, offset, do_count, cnt; - - for (i = 0, offset = st_bp->buffer_bytes; - i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) - offset -= st_bp->sg[i].length; - if (i == st_bp->sg_segs) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n"); - return (-EIO); - } - for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes; - i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length - offset < do_count ? - st_bp->sg[i].length - offset : do_count ; - memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt); - do_count -= cnt; - offset = 0; - } - if (do_count) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count); - return (-EIO); - } - return 0; -} - -/* Copy a osst 32K chunk of memory into the buffer. - Returns zero (success) or negative error code. */ -static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr) -{ - int i, cnt, do_count = OS_DATA_SIZE; - - for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length < do_count ? - st_bp->sg[i].length : do_count ; - memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt); - do_count -= cnt; - ptr += cnt; - } - if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n", - do_count, i); - return (-EIO); - } - return 0; -} - -/* Copy a osst 32K chunk of memory from the buffer. - Returns zero (success) or negative error code. */ -static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr) -{ - int i, cnt, do_count = OS_DATA_SIZE; - - for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { - cnt = st_bp->sg[i].length < do_count ? - st_bp->sg[i].length : do_count ; - memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt); - do_count -= cnt; - ptr += cnt; - } - if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ - printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n", - do_count, i); - return (-EIO); - } - return 0; -} - - -/* Module housekeeping */ - -static void validate_options (void) -{ - if (max_dev > 0) - osst_max_dev = max_dev; - if (write_threshold_kbs > 0) - osst_write_threshold = write_threshold_kbs * ST_KILOBYTE; - if (osst_write_threshold > osst_buffer_size) - osst_write_threshold = osst_buffer_size; - if (max_sg_segs >= OSST_FIRST_SG) - osst_max_sg_segs = max_sg_segs; -#if DEBUG - printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n", - osst_max_dev, osst_write_threshold, osst_max_sg_segs); -#endif -} - -#ifndef MODULE -/* Set the boot options. Syntax: osst=xxx,yyy,... - where xxx is write threshold in 1024 byte blocks, - and yyy is number of s/g segments to use. */ -static int __init osst_setup (char *str) -{ - int i, ints[5]; - char *stp; - - stp = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) - *parms[i].val = ints[i + 1]; - } else { - while (stp != NULL) { - for (i = 0; i < ARRAY_SIZE(parms); i++) { - int len = strlen(parms[i].name); - if (!strncmp(stp, parms[i].name, len) && - (*(stp + len) == ':' || *(stp + len) == '=')) { - *parms[i].val = - simple_strtoul(stp + len + 1, NULL, 0); - break; - } - } - if (i >= ARRAY_SIZE(parms)) - printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n", - stp); - stp = strchr(stp, ','); - if (stp) - stp++; - } - } - - return 1; -} - -__setup("osst=", osst_setup); - -#endif - -static const struct file_operations osst_fops = { - .owner = THIS_MODULE, - .read = osst_read, - .write = osst_write, - .unlocked_ioctl = osst_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = osst_compat_ioctl, -#endif - .open = os_scsi_tape_open, - .flush = os_scsi_tape_flush, - .release = os_scsi_tape_close, - .llseek = noop_llseek, -}; - -static int osst_supports(struct scsi_device * SDp) -{ - struct osst_support_data { - char *vendor; - char *model; - char *rev; - char *driver_hint; /* Name of the correct driver, NULL if unknown */ - }; - -static struct osst_support_data support_list[] = { - /* {"XXX", "Yy-", "", NULL}, example */ - SIGS_FROM_OSST, - {NULL, }}; - - struct osst_support_data *rp; - - /* We are willing to drive OnStream SC-x0 as well as the - * * IDE, ParPort, FireWire, USB variants, if accessible by - * * emulation layer (ide-scsi, usb-storage, ...) */ - - for (rp=&(support_list[0]); rp->vendor != NULL; rp++) - if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) && - !strncmp(rp->model, SDp->model, strlen(rp->model)) && - !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) - return 1; - return 0; -} - -/* - * sysfs support for osst driver parameter information - */ - -static ssize_t osst_version_show(struct device_driver *ddd, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", osst_version); -} - -static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL); - -static int osst_create_sysfs_files(struct device_driver *sysfs) -{ - return driver_create_file(sysfs, &driver_attr_version); -} - -static void osst_remove_sysfs_files(struct device_driver *sysfs) -{ - driver_remove_file(sysfs, &driver_attr_version); -} - -/* - * sysfs support for accessing ADR header information - */ - -static ssize_t osst_adr_rev_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev); - return l; -} - -DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL); - -static ssize_t osst_linux_media_version_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version); - return l; -} - -DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL); - -static ssize_t osst_capacity_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity); - return l; -} - -DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL); - -static ssize_t osst_first_data_ppos_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos); - return l; -} - -DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL); - -static ssize_t osst_eod_frame_ppos_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos); - return l; -} - -DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL); - -static ssize_t osst_filemark_cnt_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); - ssize_t l = 0; - - if (STp && STp->header_ok && STp->linux_media) - l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt); - return l; -} - -DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); - -static struct class *osst_sysfs_class; - -static int osst_sysfs_init(void) -{ - osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); - if (IS_ERR(osst_sysfs_class)) { - printk(KERN_ERR "osst :W: Unable to register sysfs class\n"); - return PTR_ERR(osst_sysfs_class); - } - - return 0; -} - -static void osst_sysfs_destroy(dev_t dev) -{ - device_destroy(osst_sysfs_class, dev); -} - -static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) -{ - struct device *osst_member; - int err; - - osst_member = device_create(osst_sysfs_class, device, dev, STp, - "%s", name); - if (IS_ERR(osst_member)) { - printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); - return PTR_ERR(osst_member); - } - - err = device_create_file(osst_member, &dev_attr_ADR_rev); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_media_version); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_capacity); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_BOT_frame); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_EOD_frame); - if (err) - goto err_out; - err = device_create_file(osst_member, &dev_attr_file_count); - if (err) - goto err_out; - - return 0; - -err_out: - osst_sysfs_destroy(dev); - return err; -} - -static void osst_sysfs_cleanup(void) -{ - class_destroy(osst_sysfs_class); -} - -/* - * osst startup / cleanup code - */ - -static int osst_probe(struct device *dev) -{ - struct scsi_device * SDp = to_scsi_device(dev); - struct osst_tape * tpnt; - struct st_modedef * STm; - struct st_partstat * STps; - struct osst_buffer * buffer; - struct gendisk * drive; - int i, dev_num, err = -ENODEV; - - if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) - return -ENODEV; - - drive = alloc_disk(1); - if (!drive) { - printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n"); - return -ENODEV; - } - - /* if this is the first attach, build the infrastructure */ - write_lock(&os_scsi_tapes_lock); - if (os_scsi_tapes == NULL) { - os_scsi_tapes = kmalloc(osst_max_dev * sizeof(struct osst_tape *), GFP_ATOMIC); - if (os_scsi_tapes == NULL) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n"); - goto out_put_disk; - } - for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL; - } - - if (osst_nr_dev >= osst_max_dev) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev); - goto out_put_disk; - } - - /* find a free minor number */ - for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++) - ; - if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)"); - dev_num = i; - - /* allocate a struct osst_tape for this device */ - tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC); - if (!tpnt) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n"); - goto out_put_disk; - } - - /* allocate a buffer for this device */ - i = SDp->host->sg_tablesize; - if (osst_max_sg_segs < i) - i = osst_max_sg_segs; - buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i); - if (buffer == NULL) { - write_unlock(&os_scsi_tapes_lock); - printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n"); - kfree(tpnt); - goto out_put_disk; - } - os_scsi_tapes[dev_num] = tpnt; - tpnt->buffer = buffer; - tpnt->device = SDp; - drive->private_data = &tpnt->driver; - sprintf(drive->disk_name, "osst%d", dev_num); - tpnt->driver = &osst_template; - tpnt->drive = drive; - tpnt->in_use = 0; - tpnt->capacity = 0xfffff; - tpnt->dirty = 0; - tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ - tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; - tpnt->density = 0; - tpnt->do_auto_lock = OSST_AUTO_LOCK; - tpnt->can_bsr = OSST_IN_FILE_POS; - tpnt->can_partitions = 0; - tpnt->two_fm = OSST_TWO_FM; - tpnt->fast_mteom = OSST_FAST_MTEOM; - tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */ - tpnt->write_threshold = osst_write_threshold; - tpnt->default_drvbuffer = 0xff; /* No forced buffering */ - tpnt->partition = 0; - tpnt->new_partition = 0; - tpnt->nbr_partitions = 0; - tpnt->min_block = 512; - tpnt->max_block = OS_DATA_SIZE; - tpnt->timeout = OSST_TIMEOUT; - tpnt->long_timeout = OSST_LONG_TIMEOUT; - - /* Recognize OnStream tapes */ - /* We don't need to test for OnStream, as this has been done in detect () */ - tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev); - tpnt->omit_blklims = 1; - - tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || - (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp); - tpnt->frame_in_buffer = 0; - tpnt->header_ok = 0; - tpnt->linux_media = 0; - tpnt->header_cache = NULL; - - for (i=0; i < ST_NBR_MODES; i++) { - STm = &(tpnt->modes[i]); - STm->defined = 0; - STm->sysv = OSST_SYSV; - STm->defaults_for_writes = 0; - STm->do_async_writes = OSST_ASYNC_WRITES; - STm->do_buffer_writes = OSST_BUFFER_WRITES; - STm->do_read_ahead = OSST_READ_AHEAD; - STm->default_compression = ST_DONT_TOUCH; - STm->default_blksize = 512; - STm->default_density = (-1); /* No forced density */ - } - - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(tpnt->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = (-1); - STps->drv_file = (-1); - } - - tpnt->current_mode = 0; - tpnt->modes[0].defined = 1; - tpnt->modes[2].defined = 1; - tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0; - - mutex_init(&tpnt->lock); - osst_nr_dev++; - write_unlock(&os_scsi_tapes_lock); - - { - char name[8]; - - /* Rewind entry */ - err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); - if (err) - goto out_free_buffer; - - /* No-rewind entry */ - snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); - err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); - if (err) - goto out_free_sysfs1; - } - - sdev_printk(KERN_INFO, SDp, - "osst :I: Attached OnStream %.5s tape as %s\n", - SDp->model, tape_name(tpnt)); - - return 0; - -out_free_sysfs1: - osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num)); -out_free_buffer: - kfree(buffer); -out_put_disk: - put_disk(drive); - return err; -}; - -static int osst_remove(struct device *dev) -{ - struct scsi_device * SDp = to_scsi_device(dev); - struct osst_tape * tpnt; - int i; - - if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0)) - return 0; - - write_lock(&os_scsi_tapes_lock); - for(i=0; i < osst_max_dev; i++) { - if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) { - osst_sysfs_destroy(MKDEV(OSST_MAJOR, i)); - osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128)); - tpnt->device = NULL; - put_disk(tpnt->drive); - os_scsi_tapes[i] = NULL; - osst_nr_dev--; - write_unlock(&os_scsi_tapes_lock); - vfree(tpnt->header_cache); - if (tpnt->buffer) { - normalize_buffer(tpnt->buffer); - kfree(tpnt->buffer); - } - kfree(tpnt); - return 0; - } - } - write_unlock(&os_scsi_tapes_lock); - return 0; -} - -static int __init init_osst(void) -{ - int err; - - printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); - - validate_options(); - - err = osst_sysfs_init(); - if (err) - return err; - - err = register_chrdev(OSST_MAJOR, "osst", &osst_fops); - if (err < 0) { - printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); - goto err_out; - } - - err = scsi_register_driver(&osst_template.gendrv); - if (err) - goto err_out_chrdev; - - err = osst_create_sysfs_files(&osst_template.gendrv); - if (err) - goto err_out_scsidrv; - - return 0; - -err_out_scsidrv: - scsi_unregister_driver(&osst_template.gendrv); -err_out_chrdev: - unregister_chrdev(OSST_MAJOR, "osst"); -err_out: - osst_sysfs_cleanup(); - return err; -} - -static void __exit exit_osst (void) -{ - int i; - struct osst_tape * STp; - - osst_remove_sysfs_files(&osst_template.gendrv); - scsi_unregister_driver(&osst_template.gendrv); - unregister_chrdev(OSST_MAJOR, "osst"); - osst_sysfs_cleanup(); - - if (os_scsi_tapes) { - for (i=0; i < osst_max_dev; ++i) { - if (!(STp = os_scsi_tapes[i])) continue; - /* This is defensive, supposed to happen during detach */ - vfree(STp->header_cache); - if (STp->buffer) { - normalize_buffer(STp->buffer); - kfree(STp->buffer); - } - put_disk(STp->drive); - kfree(STp); - } - kfree(os_scsi_tapes); - } - printk(KERN_INFO "osst :I: Unloaded.\n"); -} - -module_init(init_osst); -module_exit(exit_osst); diff --git a/ANDROID_3.4.5/drivers/scsi/osst.h b/ANDROID_3.4.5/drivers/scsi/osst.h deleted file mode 100644 index b4fea98b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osst.h +++ /dev/null @@ -1,650 +0,0 @@ -/* - * $Header: /cvsroot/osst/Driver/osst.h,v 1.16 2005/01/01 21:13:35 wriede Exp $ - */ - -#include -#include -#include - -/* FIXME - rename and use the following two types or delete them! - * and the types really should go to st.h anyway... - * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C) - */ -typedef struct { - unsigned device_type :5; /* Peripheral Device Type */ - unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ - unsigned reserved1_6t0 :7; /* Reserved */ - unsigned rmb :1; /* Removable Medium Bit */ - unsigned ansi_version :3; /* ANSI Version */ - unsigned ecma_version :3; /* ECMA Version */ - unsigned iso_version :2; /* ISO Version */ - unsigned response_format :4; /* Response Data Format */ - unsigned reserved3_45 :2; /* Reserved */ - unsigned reserved3_6 :1; /* TrmIOP - Reserved */ - unsigned reserved3_7 :1; /* AENC - Reserved */ - u8 additional_length; /* Additional Length (total_length-4) */ - u8 rsv5, rsv6, rsv7; /* Reserved */ - u8 vendor_id[8]; /* Vendor Identification */ - u8 product_id[16]; /* Product Identification */ - u8 revision_level[4]; /* Revision Level */ - u8 vendor_specific[20]; /* Vendor Specific - Optional */ - u8 reserved56t95[40]; /* Reserved - Optional */ - /* Additional information may be returned */ -} idetape_inquiry_result_t; - -/* - * READ POSITION packet command - Data Format (From Table 6-57) - */ -typedef struct { - unsigned reserved0_10 :2; /* Reserved */ - unsigned bpu :1; /* Block Position Unknown */ - unsigned reserved0_543 :3; /* Reserved */ - unsigned eop :1; /* End Of Partition */ - unsigned bop :1; /* Beginning Of Partition */ - u8 partition; /* Partition Number */ - u8 reserved2, reserved3; /* Reserved */ - u32 first_block; /* First Block Location */ - u32 last_block; /* Last Block Location (Optional) */ - u8 reserved12; /* Reserved */ - u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */ - u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */ -} idetape_read_position_result_t; - -/* - * Follows structures which are related to the SELECT SENSE / MODE SENSE - * packet commands. - */ -#define COMPRESSION_PAGE 0x0f -#define COMPRESSION_PAGE_LENGTH 16 - -#define CAPABILITIES_PAGE 0x2a -#define CAPABILITIES_PAGE_LENGTH 20 - -#define TAPE_PARAMTR_PAGE 0x2b -#define TAPE_PARAMTR_PAGE_LENGTH 16 - -#define NUMBER_RETRIES_PAGE 0x2f -#define NUMBER_RETRIES_PAGE_LENGTH 4 - -#define BLOCK_SIZE_PAGE 0x30 -#define BLOCK_SIZE_PAGE_LENGTH 4 - -#define BUFFER_FILLING_PAGE 0x33 -#define BUFFER_FILLING_PAGE_LENGTH 4 - -#define VENDOR_IDENT_PAGE 0x36 -#define VENDOR_IDENT_PAGE_LENGTH 8 - -#define LOCATE_STATUS_PAGE 0x37 -#define LOCATE_STATUS_PAGE_LENGTH 0 - -#define MODE_HEADER_LENGTH 4 - - -/* - * REQUEST SENSE packet command result - Data Format. - */ -typedef struct { - unsigned error_code :7; /* Current of deferred errors */ - unsigned valid :1; /* The information field conforms to QIC-157C */ - u8 reserved1 :8; /* Segment Number - Reserved */ - unsigned sense_key :4; /* Sense Key */ - unsigned reserved2_4 :1; /* Reserved */ - unsigned ili :1; /* Incorrect Length Indicator */ - unsigned eom :1; /* End Of Medium */ - unsigned filemark :1; /* Filemark */ - u32 information __attribute__ ((packed)); - u8 asl; /* Additional sense length (n-7) */ - u32 command_specific; /* Additional command specific information */ - u8 asc; /* Additional Sense Code */ - u8 ascq; /* Additional Sense Code Qualifier */ - u8 replaceable_unit_code; /* Field Replaceable Unit Code */ - unsigned sk_specific1 :7; /* Sense Key Specific */ - unsigned sksv :1; /* Sense Key Specific information is valid */ - u8 sk_specific2; /* Sense Key Specific */ - u8 sk_specific3; /* Sense Key Specific */ - u8 pad[2]; /* Padding to 20 bytes */ -} idetape_request_sense_result_t; - -/* - * Mode Parameter Header for the MODE SENSE packet command - */ -typedef struct { - u8 mode_data_length; /* Length of the following data transfer */ - u8 medium_type; /* Medium Type */ - u8 dsp; /* Device Specific Parameter */ - u8 bdl; /* Block Descriptor Length */ -} osst_mode_parameter_header_t; - -/* - * Mode Parameter Block Descriptor the MODE SENSE packet command - * - * Support for block descriptors is optional. - */ -typedef struct { - u8 density_code; /* Medium density code */ - u8 blocks[3]; /* Number of blocks */ - u8 reserved4; /* Reserved */ - u8 length[3]; /* Block Length */ -} osst_parameter_block_descriptor_t; - -/* - * The Data Compression Page, as returned by the MODE SENSE packet command. - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved0 :1; /* Reserved */ - unsigned page_code :6; /* Page Code - Should be 0xf */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page Code - Should be 0xf */ - unsigned reserved0 :1; /* Reserved */ - unsigned ps :1; -#else -#error "Please fix " -#endif - u8 page_length; /* Page Length - Should be 14 */ -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned dce :1; /* Data Compression Enable */ - unsigned dcc :1; /* Data Compression Capable */ - unsigned reserved2 :6; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved2 :6; /* Reserved */ - unsigned dcc :1; /* Data Compression Capable */ - unsigned dce :1; /* Data Compression Enable */ -#else -#error "Please fix " -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned dde :1; /* Data Decompression Enable */ - unsigned red :2; /* Report Exception on Decompression */ - unsigned reserved3 :5; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved3 :5; /* Reserved */ - unsigned red :2; /* Report Exception on Decompression */ - unsigned dde :1; /* Data Decompression Enable */ -#else -#error "Please fix " -#endif - u32 ca; /* Compression Algorithm */ - u32 da; /* Decompression Algorithm */ - u8 reserved[4]; /* Reserved */ -} osst_data_compression_page_t; - -/* - * The Medium Partition Page, as returned by the MODE SENSE packet command. - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; /* Reserved */ - unsigned page_code :6; /* Page Code - Should be 0x11 */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page Code - Should be 0x11 */ - unsigned reserved1_6 :1; /* Reserved */ - unsigned ps :1; -#else -#error "Please fix " -#endif - u8 page_length; /* Page Length - Should be 6 */ - u8 map; /* Maximum Additional Partitions - Should be 0 */ - u8 apd; /* Additional Partitions Defined - Should be 0 */ -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned fdp :1; /* Fixed Data Partitions */ - unsigned sdp :1; /* Should be 0 */ - unsigned idp :1; /* Should be 0 */ - unsigned psum :2; /* Should be 0 */ - unsigned reserved4_012 :3; /* Reserved */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved4_012 :3; /* Reserved */ - unsigned psum :2; /* Should be 0 */ - unsigned idp :1; /* Should be 0 */ - unsigned sdp :1; /* Should be 0 */ - unsigned fdp :1; /* Fixed Data Partitions */ -#else -#error "Please fix " -#endif - u8 mfr; /* Medium Format Recognition */ - u8 reserved[2]; /* Reserved */ -} osst_medium_partition_page_t; - -/* - * Capabilities and Mechanical Status Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved1_67 :2; - unsigned page_code :6; /* Page code - Should be 0x2a */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x2a */ - unsigned reserved1_67 :2; -#else -#error "Please fix " -#endif - u8 page_length; /* Page Length - Should be 0x12 */ - u8 reserved2, reserved3; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved4_67 :2; - unsigned sprev :1; /* Supports SPACE in the reverse direction */ - unsigned reserved4_1234 :4; - unsigned ro :1; /* Read Only Mode */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned ro :1; /* Read Only Mode */ - unsigned reserved4_1234 :4; - unsigned sprev :1; /* Supports SPACE in the reverse direction */ - unsigned reserved4_67 :2; -#else -#error "Please fix " -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned reserved5_67 :2; - unsigned qfa :1; /* Supports the QFA two partition formats */ - unsigned reserved5_4 :1; - unsigned efmt :1; /* Supports ERASE command initiated formatting */ - unsigned reserved5_012 :3; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved5_012 :3; - unsigned efmt :1; /* Supports ERASE command initiated formatting */ - unsigned reserved5_4 :1; - unsigned qfa :1; /* Supports the QFA two partition formats */ - unsigned reserved5_67 :2; -#else -#error "Please fix " -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned cmprs :1; /* Supports data compression */ - unsigned ecc :1; /* Supports error correction */ - unsigned reserved6_45 :2; /* Reserved */ - unsigned eject :1; /* The device can eject the volume */ - unsigned prevent :1; /* The device defaults in the prevent state after power up */ - unsigned locked :1; /* The volume is locked */ - unsigned lock :1; /* Supports locking the volume */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned lock :1; /* Supports locking the volume */ - unsigned locked :1; /* The volume is locked */ - unsigned prevent :1; /* The device defaults in the prevent state after power up */ - unsigned eject :1; /* The device can eject the volume */ - unsigned reserved6_45 :2; /* Reserved */ - unsigned ecc :1; /* Supports error correction */ - unsigned cmprs :1; /* Supports data compression */ -#else -#error "Please fix " -#endif -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ - /* transfers for slow buffer memory ??? */ - /* Also 32768 block size in some cases */ - unsigned reserved7_3_6 :4; - unsigned blk1024 :1; /* Supports 1024 bytes block size */ - unsigned blk512 :1; /* Supports 512 bytes block size */ - unsigned reserved7_0 :1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned reserved7_0 :1; - unsigned blk512 :1; /* Supports 512 bytes block size */ - unsigned blk1024 :1; /* Supports 1024 bytes block size */ - unsigned reserved7_3_6 :4; - unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ - /* transfers for slow buffer memory ??? */ - /* Also 32768 block size in some cases */ -#else -#error "Please fix " -#endif - __be16 max_speed; /* Maximum speed supported in KBps */ - u8 reserved10, reserved11; - __be16 ctl; /* Continuous Transfer Limit in blocks */ - __be16 speed; /* Current Speed, in KBps */ - __be16 buffer_size; /* Buffer Size, in 512 bytes */ - u8 reserved18, reserved19; -} osst_capabilities_page_t; - -/* - * Block Size Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; - unsigned page_code :6; /* Page code - Should be 0x30 */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x30 */ - unsigned reserved1_6 :1; - unsigned ps :1; -#else -#error "Please fix " -#endif - u8 page_length; /* Page Length - Should be 2 */ - u8 reserved2; -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned one :1; - unsigned reserved2_6 :1; - unsigned record32_5 :1; - unsigned record32 :1; - unsigned reserved2_23 :2; - unsigned play32_5 :1; - unsigned play32 :1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned play32 :1; - unsigned play32_5 :1; - unsigned reserved2_23 :2; - unsigned record32 :1; - unsigned record32_5 :1; - unsigned reserved2_6 :1; - unsigned one :1; -#else -#error "Please fix " -#endif -} osst_block_size_page_t; - -/* - * Tape Parameters Page - */ -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned ps :1; - unsigned reserved1_6 :1; - unsigned page_code :6; /* Page code - Should be 0x2b */ -#elif defined(__LITTLE_ENDIAN_BITFIELD) - unsigned page_code :6; /* Page code - Should be 0x2b */ - unsigned reserved1_6 :1; - unsigned ps :1; -#else -#error "Please fix " -#endif - u8 reserved2; - u8 density; - u8 reserved3,reserved4; - __be16 segtrk; - __be16 trks; - u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; -} osst_tape_paramtr_page_t; - -/* OnStream definitions */ - -#define OS_CONFIG_PARTITION (0xff) -#define OS_DATA_PARTITION (0) -#define OS_PARTITION_VERSION (1) - -/* - * partition - */ -typedef struct os_partition_s { - __u8 partition_num; - __u8 par_desc_ver; - __be16 wrt_pass_cntr; - __be32 first_frame_ppos; - __be32 last_frame_ppos; - __be32 eod_frame_ppos; -} os_partition_t; - -/* - * DAT entry - */ -typedef struct os_dat_entry_s { - __be32 blk_sz; - __be16 blk_cnt; - __u8 flags; - __u8 reserved; -} os_dat_entry_t; - -/* - * DAT - */ -#define OS_DAT_FLAGS_DATA (0xc) -#define OS_DAT_FLAGS_MARK (0x1) - -typedef struct os_dat_s { - __u8 dat_sz; - __u8 reserved1; - __u8 entry_cnt; - __u8 reserved3; - os_dat_entry_t dat_list[16]; -} os_dat_t; - -/* - * Frame types - */ -#define OS_FRAME_TYPE_FILL (0) -#define OS_FRAME_TYPE_EOD (1 << 0) -#define OS_FRAME_TYPE_MARKER (1 << 1) -#define OS_FRAME_TYPE_HEADER (1 << 3) -#define OS_FRAME_TYPE_DATA (1 << 7) - -/* - * AUX - */ -typedef struct os_aux_s { - __be32 format_id; /* hardware compatibility AUX is based on */ - char application_sig[4]; /* driver used to write this media */ - __be32 hdwr; /* reserved */ - __be32 update_frame_cntr; /* for configuration frame */ - __u8 frame_type; - __u8 frame_type_reserved; - __u8 reserved_18_19[2]; - os_partition_t partition; - __u8 reserved_36_43[8]; - __be32 frame_seq_num; - __be32 logical_blk_num_high; - __be32 logical_blk_num; - os_dat_t dat; - __u8 reserved188_191[4]; - __be32 filemark_cnt; - __be32 phys_fm; - __be32 last_mark_ppos; - __u8 reserved204_223[20]; - - /* - * __u8 app_specific[32]; - * - * Linux specific fields: - */ - __be32 next_mark_ppos; /* when known, points to next marker */ - __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ - __u8 linux_specific[24]; - - __u8 reserved_256_511[256]; -} os_aux_t; - -#define OS_FM_TAB_MAX 1024 - -typedef struct os_fm_tab_s { - __u8 fm_part_num; - __u8 reserved_1; - __u8 fm_tab_ent_sz; - __u8 reserved_3; - __be16 fm_tab_ent_cnt; - __u8 reserved6_15[10]; - __be32 fm_tab_ent[OS_FM_TAB_MAX]; -} os_fm_tab_t; - -typedef struct os_ext_trk_ey_s { - __u8 et_part_num; - __u8 fmt; - __be16 fm_tab_off; - __u8 reserved4_7[4]; - __be32 last_hlb_hi; - __be32 last_hlb; - __be32 last_pp; - __u8 reserved20_31[12]; -} os_ext_trk_ey_t; - -typedef struct os_ext_trk_tb_s { - __u8 nr_stream_part; - __u8 reserved_1; - __u8 et_ent_sz; - __u8 reserved3_15[13]; - os_ext_trk_ey_t dat_ext_trk_ey; - os_ext_trk_ey_t qfa_ext_trk_ey; -} os_ext_trk_tb_t; - -typedef struct os_header_s { - char ident_str[8]; - __u8 major_rev; - __u8 minor_rev; - __be16 ext_trk_tb_off; - __u8 reserved12_15[4]; - __u8 pt_par_num; - __u8 pt_reserved1_3[3]; - os_partition_t partition[16]; - __be32 cfg_col_width; - __be32 dat_col_width; - __be32 qfa_col_width; - __u8 cartridge[16]; - __u8 reserved304_511[208]; - __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ - os_ext_trk_tb_t ext_track_tb; - __u8 reserved17272_17735[464]; - os_fm_tab_t dat_fm_tab; - os_fm_tab_t qfa_fm_tab; - __u8 reserved25960_32767[6808]; -} os_header_t; - - -/* - * OnStream ADRL frame - */ -#define OS_FRAME_SIZE (32 * 1024 + 512) -#define OS_DATA_SIZE (32 * 1024) -#define OS_AUX_SIZE (512) -//#define OSST_MAX_SG 2 - -/* The OnStream tape buffer descriptor. */ -struct osst_buffer { - unsigned char in_use; - unsigned char dma; /* DMA-able buffer */ - int buffer_size; - int buffer_blocks; - int buffer_bytes; - int read_pointer; - int writing; - int midlevel_result; - int syscall_result; - struct osst_request *last_SRpnt; - struct st_cmdstatus cmdstat; - struct rq_map_data map_data; - unsigned char *b_data; - os_aux_t *aux; /* onstream AUX structure at end of each block */ - unsigned short use_sg; /* zero or number of s/g segments for this adapter */ - unsigned short sg_segs; /* number of segments in s/g list */ - unsigned short orig_sg_segs; /* number of segments allocated at first try */ - struct scatterlist sg[1]; /* MUST BE last item */ -} ; - -/* The OnStream tape drive descriptor */ -struct osst_tape { - struct scsi_driver *driver; - unsigned capacity; - struct scsi_device *device; - struct mutex lock; /* for serialization */ - struct completion wait; /* for SCSI commands */ - struct osst_buffer * buffer; - - /* Drive characteristics */ - unsigned char omit_blklims; - unsigned char do_auto_lock; - unsigned char can_bsr; - unsigned char can_partitions; - unsigned char two_fm; - unsigned char fast_mteom; - unsigned char restr_dma; - unsigned char scsi2_logical; - unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ - unsigned char pos_unknown; /* after reset position unknown */ - int write_threshold; - int timeout; /* timeout for normal commands */ - int long_timeout; /* timeout for commands known to take long time*/ - - /* Mode characteristics */ - struct st_modedef modes[ST_NBR_MODES]; - int current_mode; - - /* Status variables */ - int partition; - int new_partition; - int nbr_partitions; /* zero until partition support enabled */ - struct st_partstat ps[ST_NBR_PARTITIONS]; - unsigned char dirty; - unsigned char ready; - unsigned char write_prot; - unsigned char drv_write_prot; - unsigned char in_use; - unsigned char blksize_changed; - unsigned char density_changed; - unsigned char compression_changed; - unsigned char drv_buffer; - unsigned char density; - unsigned char door_locked; - unsigned char rew_at_close; - unsigned char inited; - int block_size; - int min_block; - int max_block; - int recover_count; /* from tape opening */ - int abort_count; - int write_count; - int read_count; - int recover_erreg; /* from last status call */ - /* - * OnStream specific data - */ - int os_fw_rev; /* the firmware revision * 10000 */ - unsigned char raw; /* flag OnStream raw access (32.5KB block size) */ - unsigned char poll; /* flag that this drive needs polling (IDE|firmware) */ - unsigned char frame_in_buffer; /* flag that the frame as per frame_seq_number - * has been read into STp->buffer and is valid */ - int frame_seq_number; /* logical frame number */ - int logical_blk_num; /* logical block number */ - unsigned first_frame_position; /* physical frame to be transferred to/from host */ - unsigned last_frame_position; /* physical frame to be transferd to/from tape */ - int cur_frames; /* current number of frames in internal buffer */ - int max_frames; /* max number of frames in internal buffer */ - char application_sig[5]; /* application signature */ - unsigned char fast_open; /* flag that reminds us we didn't check headers at open */ - unsigned short wrt_pass_cntr; /* write pass counter */ - int update_frame_cntr; /* update frame counter */ - int onstream_write_error; /* write error recovery active */ - int header_ok; /* header frame verified ok */ - int linux_media; /* reading linux-specifc media */ - int linux_media_version; - os_header_t * header_cache; /* cache is kept for filemark positions */ - int filemark_cnt; - int first_mark_ppos; - int last_mark_ppos; - int last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ - int first_data_ppos; - int eod_frame_ppos; - int eod_frame_lfa; - int write_type; /* used in write error recovery */ - int read_error_frame; /* used in read error recovery */ - unsigned long cmd_start_time; - unsigned long max_cmd_time; - -#if DEBUG - unsigned char write_pending; - int nbr_finished; - int nbr_waits; - unsigned char last_cmnd[6]; - unsigned char last_sense[16]; -#endif - struct gendisk *drive; -} ; - -/* scsi tape command */ -struct osst_request { - unsigned char cmd[MAX_COMMAND_SIZE]; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - int result; - struct osst_tape *stp; - struct completion *waiting; - struct bio *bio; -}; - -/* Values of write_type */ -#define OS_WRITE_DATA 0 -#define OS_WRITE_EOD 1 -#define OS_WRITE_NEW_MARK 2 -#define OS_WRITE_LAST_MARK 3 -#define OS_WRITE_HEADER 4 -#define OS_WRITE_FILLER 5 - -/* Additional rw state */ -#define OS_WRITING_COMPLETE 3 diff --git a/ANDROID_3.4.5/drivers/scsi/osst_detect.h b/ANDROID_3.4.5/drivers/scsi/osst_detect.h deleted file mode 100644 index 21717d0e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osst_detect.h +++ /dev/null @@ -1,6 +0,0 @@ -#define SIGS_FROM_OSST \ - {"OnStream", "SC-", "", "osst"}, \ - {"OnStream", "DI-", "", "osst"}, \ - {"OnStream", "DP-", "", "osst"}, \ - {"OnStream", "FW-", "", "osst"}, \ - {"OnStream", "USB", "", "osst"} diff --git a/ANDROID_3.4.5/drivers/scsi/osst_options.h b/ANDROID_3.4.5/drivers/scsi/osst_options.h deleted file mode 100644 index ff1e6109..00000000 --- a/ANDROID_3.4.5/drivers/scsi/osst_options.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - The compile-time configurable defaults for the Linux SCSI tape driver. - - Copyright 1995 Kai Makisara. - - Last modified: Wed Sep 2 21:24:07 1998 by root@home - - Changed (and renamed) for OnStream SCSI drives garloff@suse.de - 2000-06-21 - - $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $ -*/ - -#ifndef _OSST_OPTIONS_H -#define _OSST_OPTIONS_H - -/* The minimum limit for the number of SCSI tape devices is determined by - OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by - OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */ -#define OSST_MAX_TAPES 4 - -/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the - record been read by the user program even if the tape has moved further - because of buffered reads. Should be set to zero to support also drives - that can't space backwards over records. NOTE: The tape will be - spaced backwards over an "accidentally" crossed filemark in any case. */ -#define OSST_IN_FILE_POS 1 - -/* The tape driver buffer size in kilobytes. */ -/* Don't change, as this is the HW blocksize */ -#define OSST_BUFFER_BLOCKS 32 - -/* The number of kilobytes of data in the buffer that triggers an - asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES - below. */ -#define OSST_WRITE_THRESHOLD_BLOCKS 32 - -/* OSST_EOM_RESERVE defines the number of frames are kept in reserve for - * * write error recovery when writing near end of medium. ENOSPC is returned - * * when write() is called and the tape write position is within this number - * * of blocks from the tape capacity. */ -#define OSST_EOM_RESERVE 300 - -/* The maximum number of tape buffers the driver allocates. The number - is also constrained by the number of drives detected. Determines the - maximum number of concurrently active tape drives. */ -#define OSST_MAX_BUFFERS OSST_MAX_TAPES - -/* Maximum number of scatter/gather segments */ -/* Fit one buffer in pages and add one for the AUX header */ -#define OSST_MAX_SG (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1) - -/* The number of scatter/gather segments to allocate at first try (must be - smaller or equal to the maximum). */ -#define OSST_FIRST_SG ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) - -/* The size of the first scatter/gather segments (determines the maximum block - size for SCSI adapters not supporting scatter/gather). The default is set - to try to allocate the buffer as one chunk. */ -#define OSST_FIRST_ORDER (15-PAGE_SHIFT) - - -/* The following lines define defaults for properties that can be set - separately for each drive using the MTSTOPTIONS ioctl. */ - -/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a - file being written. Some drives can't handle two filemarks at the - end of data. */ -#define OSST_TWO_FM 0 - -/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are - buffered until the driver buffer is full or asynchronous write is - triggered. */ -#define OSST_BUFFER_WRITES 1 - -/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started - without waiting for it to finish. May cause problems in multiple - tape backups. */ -#define OSST_ASYNC_WRITES 1 - -/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block - mode. */ -#define OSST_READ_AHEAD 1 - -/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first - read or write command after the device is opened. The door is opened - when the device is closed. */ -#define OSST_AUTO_LOCK 0 - -/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the - direct SCSI command. The file number status is lost but this method - is fast with some drives. Otherwise MTEOM is done by spacing over - files and the file number status is retained. */ -#define OSST_FAST_MTEOM 0 - -/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for - MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL - is zero. */ -#define OSST_SCSI2LOGICAL 0 - -/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics. - The default is BSD semantics. */ -#define OSST_SYSV 0 - - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/pas16.c b/ANDROID_3.4.5/drivers/scsi/pas16.c deleted file mode 100644 index 2f72c980..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pas16.c +++ /dev/null @@ -1,637 +0,0 @@ -#define AUTOSENSE -#define PSEUDO_DMA -#define FOO -#define UNSAFE /* Not unsafe for PAS16 -- use it */ -#define PDEBUG 0 - -/* - * This driver adapted from Drew Eckhardt's Trantor T128 driver - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 - * - * ( Based on T128 - DISTRIBUTION RELEASE 3. ) - * - * Modified to work with the Pro Audio Spectrum/Studio 16 - * by John Weidman. - * - * - * For more information, please consult - * - * Media Vision - * (510) 770-8600 - * (800) 348-7116 - * - * and - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * Options : - * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. - * - * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512 - * bytes at a time. Since interrupts are disabled by default during - * these transfers, we might need this to give reasonable interrupt - * service time if the transfer size gets too large. - * - * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance - * increase compared to polled I/O. - * - * PARITY - enable parity checking. Not supported. - * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * - * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. This - * parameter comes from the NCR5380 code. It is NOT unsafe with - * the PAS16 and you should use it. If you don't you will have - * a problem with dropped characters during high speed - * communications during SCSI transfers. If you really don't - * want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or - * twiddle with the transfer size in the high level code. - * - * USLEEP - enable support for devices that don't disconnect. Untested. - * - * The card is detected and initialized in one of several ways : - * 1. Autoprobe (default) - There are many different models of - * the Pro Audio Spectrum/Studio 16, and I only have one of - * them, so this may require a little tweaking. An interrupt - * is triggered to autoprobe for the interrupt line. Note: - * with the newer model boards, the interrupt is set via - * software after reset using the default_irq for the - * current board number. - * - * 2. With command line overrides - pas16=port,irq may be - * used on the LILO command line to override the defaults. - * - * 3. With the PAS16_OVERRIDE compile time define. This is - * specified as an array of address, irq tuples. Ie, for - * one board at the default 0x388 address, IRQ10, I could say - * -DPAS16_OVERRIDE={{0x388, 10}} - * NOTE: Untested. - * - * 4. When included as a module, with arguments passed on the command line: - * pas16_irq=xx the interrupt - * pas16_addr=xx the port - * e.g. "modprobe pas16 pas16_addr=0x388 pas16_irq=5" - * - * Note that if the override methods are used, place holders must - * be specified for other boards in the system. - * - * - * Configuration notes : - * The current driver does not support interrupt sharing with the - * sound portion of the card. If you use the same irq for the - * scsi port and sound you will have problems. Either use - * a different irq for the scsi port or don't use interrupts - * for the scsi port. - * - * If you have problems with your card not being recognized, use - * the LILO command line override. Try to get it recognized without - * interrupts. Ie, for a board at the default 0x388 base port, - * boot: linux pas16=0x388,255 - * - * SCSI_IRQ_NONE (255) should be specified for no interrupt, - * IRQ_AUTO (254) to autoprobe for an IRQ line if overridden - * on the command line. - * - * (IRQ_AUTO == 254, SCSI_IRQ_NONE == 255 in NCR5380.h) - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include "pas16.h" -#define AUTOPROBE_IRQ -#include "NCR5380.h" - - -static int pas_maxi = 0; -static int pas_wmaxi = 0; -static unsigned short pas16_addr = 0; -static int pas16_irq = 0; - - -static const int scsi_irq_translate[] = - { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; - -/* The default_irqs array contains values used to set the irq into the - * board via software (as must be done on newer model boards without - * irq jumpers on the board). The first value in the array will be - * assigned to logical board 0, the next to board 1, etc. - */ -static int default_irqs[] __initdata = - { PAS16_DEFAULT_BOARD_1_IRQ, - PAS16_DEFAULT_BOARD_2_IRQ, - PAS16_DEFAULT_BOARD_3_IRQ, - PAS16_DEFAULT_BOARD_4_IRQ - }; - -static struct override { - unsigned short io_port; - int irq; -} overrides -#ifdef PAS16_OVERRIDE - [] __initdata = PAS16_OVERRIDE; -#else - [4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO}, - {0,IRQ_AUTO}}; -#endif - -#define NO_OVERRIDES ARRAY_SIZE(overrides) - -static struct base { - unsigned short io_port; - int noauto; -} bases[] __initdata = - { {PAS16_DEFAULT_BASE_1, 0}, - {PAS16_DEFAULT_BASE_2, 0}, - {PAS16_DEFAULT_BASE_3, 0}, - {PAS16_DEFAULT_BASE_4, 0} - }; - -#define NO_BASES ARRAY_SIZE(bases) - -static const unsigned short pas16_offset[ 8 ] = - { - 0x1c00, /* OUTPUT_DATA_REG */ - 0x1c01, /* INITIATOR_COMMAND_REG */ - 0x1c02, /* MODE_REG */ - 0x1c03, /* TARGET_COMMAND_REG */ - 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */ - 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */ - 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?) - * START_DMA_TARGET_RECEIVE_REG wo - */ - 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro, - * START_DMA_INITIATOR_RECEIVE_REG wo - */ - }; -/*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at */ -/* 1 = blue - 2 = green - 3 = cyan - 4 = red - 5 = magenta - 6 = yellow - 7 = white -*/ -#if 1 -#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);} -#else -#define rtrc(i) {} -#endif - - -/* - * Function : enable_board( int board_num, unsigned short port ) - * - * Purpose : set address in new model board - * - * Inputs : board_num - logical board number 0-3, port - base address - * - */ - -static void __init - enable_board( int board_num, unsigned short port ) -{ - outb( 0xbc + board_num, MASTER_ADDRESS_PTR ); - outb( port >> 2, MASTER_ADDRESS_PTR ); -} - - - -/* - * Function : init_board( unsigned short port, int irq ) - * - * Purpose : Set the board up to handle the SCSI interface - * - * Inputs : port - base address of the board, - * irq - irq to assign to the SCSI port - * force_irq - set it even if it conflicts with sound driver - * - */ - -static void __init - init_board( unsigned short io_port, int irq, int force_irq ) -{ - unsigned int tmp; - unsigned int pas_irq_code; - - /* Initialize the SCSI part of the board */ - - outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */ - outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */ - outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ - - NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - - /* Set the SCSI interrupt pointer without mucking up the sound - * interrupt pointer in the same byte. - */ - pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0; - tmp = inb( io_port + IO_CONFIG_3 ); - - if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0 - && !force_irq ) - { - printk( "pas16: WARNING: Can't use same irq as sound " - "driver -- interrupts disabled\n" ); - /* Set up the drive parameters, disable 5380 interrupts */ - outb( 0x4d, io_port + SYS_CONFIG_4 ); - } - else - { - tmp = ( tmp & 0x0f ) | ( pas_irq_code << 4 ); - outb( tmp, io_port + IO_CONFIG_3 ); - - /* Set up the drive parameters and enable 5380 interrupts */ - outb( 0x6d, io_port + SYS_CONFIG_4 ); - } -} - - -/* - * Function : pas16_hw_detect( unsigned short board_num ) - * - * Purpose : determine if a pas16 board is present - * - * Inputs : board_num - logical board number ( 0 - 3 ) - * - * Returns : 0 if board not found, 1 if found. - */ - -static int __init - pas16_hw_detect( unsigned short board_num ) -{ - unsigned char board_rev, tmp; - unsigned short io_port = bases[ board_num ].io_port; - - /* See if we can find a PAS16 board at the address associated - * with this logical board number. - */ - - /* First, attempt to take a newer model board out of reset and - * give it a base address. This shouldn't affect older boards. - */ - enable_board( board_num, io_port ); - - /* Now see if it looks like a PAS16 board */ - board_rev = inb( io_port + PCB_CONFIG ); - - if( board_rev == 0xff ) - return 0; - - tmp = board_rev ^ 0xe0; - - outb( tmp, io_port + PCB_CONFIG ); - tmp = inb( io_port + PCB_CONFIG ); - outb( board_rev, io_port + PCB_CONFIG ); - - if( board_rev != tmp ) /* Not a PAS-16 */ - return 0; - - if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) - return 0; /* return if no SCSI interface found */ - - /* Mediavision has some new model boards that return ID bits - * that indicate a SCSI interface, but they're not (LMS). We'll - * put in an additional test to try to weed them out. - */ - - outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */ - NCR5380_write( MODE_REG, 0x20 ); /* Is it really SCSI? */ - if( NCR5380_read( MODE_REG ) != 0x20 ) /* Write to a reg. */ - return 0; /* and try to read */ - NCR5380_write( MODE_REG, 0x00 ); /* it back. */ - if( NCR5380_read( MODE_REG ) != 0x00 ) - return 0; - - return 1; -} - - -/* - * Function : pas16_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. - * - */ - -void __init pas16_setup(char *str, int *ints) -{ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("pas16_setup : usage pas16=io_port,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].io_port = (unsigned short) ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].io_port == (unsigned short) ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; - } -} - -/* - * Function : int pas16_detect(struct scsi_host_template * tpnt) - * - * Purpose : detects and initializes PAS16 controllers - * that were autoprobed, overridden on the LILO command line, - * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * - */ - -int __init pas16_detect(struct scsi_host_template * tpnt) -{ - static int current_override = 0; - static unsigned short current_base = 0; - struct Scsi_Host *instance; - unsigned short io_port; - int count; - - tpnt->proc_name = "pas16"; - tpnt->proc_info = &pas16_proc_info; - - if (pas16_addr != 0) { - overrides[0].io_port = pas16_addr; - /* - * This is how we avoid seeing more than - * one host adapter at the same I/O port. - * Cribbed shamelessly from pas16_setup(). - */ - for (count = 0; count < NO_BASES; ++count) - if (bases[count].io_port == pas16_addr) { - bases[count].noauto = 1; - break; - } - } - if (pas16_irq != 0) - overrides[0].irq = pas16_irq; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - io_port = 0; - - if (overrides[current_override].io_port) - { - io_port = overrides[current_override].io_port; - enable_board( current_override, io_port ); - init_board( io_port, overrides[current_override].irq, 1 ); - } - else - for (; !io_port && (current_base < NO_BASES); ++current_base) { -#if (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port); -#endif - if ( !bases[current_base].noauto && - pas16_hw_detect( current_base ) ){ - io_port = bases[current_base].io_port; - init_board( io_port, default_irqs[ current_base ], 0 ); -#if (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : detected board.\n"); -#endif - } - } - - -#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT) - printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port); -#endif - - if (!io_port) - break; - - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->io_port = io_port; - - NCR5380_init(instance, 0); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS); - - if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, pas16_intr, IRQF_DISABLED, - "pas16", instance)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = SCSI_IRQ_NONE; - } - - if (instance->irq == SCSI_IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - /* Disable 5380 interrupts, leave drive params the same */ - outb( 0x4d, io_port + SYS_CONFIG_4 ); - outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 ); - } - -#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk("scsi%d : at 0x%04x", instance->host_no, (int) - instance->io_port); - if (instance->irq == SCSI_IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; -} - -/* - * Function : int pas16_biosparam(Disk *disk, struct block_device *dev, int *ip) - * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for - * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * - */ - -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. - */ - -int pas16_biosparam(struct scsi_device *sdev, struct block_device *dev, - sector_t capacity, int * ip) -{ - int size = capacity; - ip[0] = 64; - ip[1] = 32; - ip[2] = size >> 11; /* I think I have it as /(32*64) */ - if( ip[2] > 1024 ) { /* yes, >, not >= */ - ip[0]=255; - ip[1]=63; - ip[2]=size/(63*255); - if( ip[2] > 1023 ) /* yes >1023... */ - ip[2] = 1023; - } - - return 0; -} - -/* - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. - */ - -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, - int len) { - register unsigned char *d = dst; - register unsigned short reg = (unsigned short) (instance->io_port + - P_DATA_REG_OFFSET); - register int i = len; - int ii = 0; - - while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) ) - ++ii; - - insb( reg, d, i ); - - if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { - outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); - printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", - instance->host_no); - return -1; - } - if (ii > pas_maxi) - pas_maxi = ii; - return 0; -} - -/* - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) - * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. - */ - -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, - int len) { - register unsigned char *s = src; - register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET); - register int i = len; - int ii = 0; - - while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) ) - ++ii; - - outsb( reg, s, i ); - - if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) { - outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET); - printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", - instance->host_no); - return -1; - } - if (ii > pas_maxi) - pas_wmaxi = ii; - return 0; -} - -#include "NCR5380.c" - -static int pas16_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, shost); - NCR5380_exit(shost); - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -static struct scsi_host_template driver_template = { - .name = "Pro Audio Spectrum-16 SCSI", - .detect = pas16_detect, - .release = pas16_release, - .queuecommand = pas16_queue_command, - .eh_abort_handler = pas16_abort, - .eh_bus_reset_handler = pas16_bus_reset, - .bios_param = pas16_biosparam, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" - -#ifdef MODULE -module_param(pas16_addr, ushort, 0); -module_param(pas16_irq, int, 0); -#endif -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/pas16.h b/ANDROID_3.4.5/drivers/scsi/pas16.h deleted file mode 100644 index a04281ca..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pas16.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * This driver adapted from Drew Eckhardt's Trantor T128 driver - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 - * - * ( Based on T128 - DISTRIBUTION RELEASE 3. ) - * - * Modified to work with the Pro Audio Spectrum/Studio 16 - * by John Weidman. - * - * - * For more information, please consult - * - * Media Vision - * (510) 770-8600 - * (800) 348-7116 - * - * and - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - - -#ifndef PAS16_H -#define PAS16_H - -#define PAS16_PUBLIC_RELEASE 3 - -#define PDEBUG_INIT 0x1 -#define PDEBUG_TRANSFER 0x2 - -#define PAS16_DEFAULT_BASE_1 0x388 -#define PAS16_DEFAULT_BASE_2 0x384 -#define PAS16_DEFAULT_BASE_3 0x38c -#define PAS16_DEFAULT_BASE_4 0x288 - -#define PAS16_DEFAULT_BOARD_1_IRQ 10 -#define PAS16_DEFAULT_BOARD_2_IRQ 12 -#define PAS16_DEFAULT_BOARD_3_IRQ 14 -#define PAS16_DEFAULT_BOARD_4_IRQ 15 - - -/* - * The Pro Audio Spectrum boards are I/O mapped. They use a Zilog 5380 - * SCSI controller, which is the equivalent of NCR's 5380. "Pseudo-DMA" - * architecture is used, where a PAL drives the DMA signals on the 5380 - * allowing fast, blind transfers with proper handshaking. - */ - - -/* The Time-out Counter register is used to safe-guard against a stuck - * bus (in the case of RDY driven handshake) or a stuck byte (if 16-Bit - * DMA conversion is used). The counter uses a 28.224MHz clock - * divided by 14 as its clock source. In the case of a stuck byte in - * the holding register, an interrupt is generated (and mixed with the - * one with the drive) using the CD-ROM interrupt pointer. - */ - -#define P_TIMEOUT_COUNTER_REG 0x4000 -#define P_TC_DISABLE 0x80 /* Set to 0 to enable timeout int. */ - /* Bits D6-D0 contain timeout count */ - - -#define P_TIMEOUT_STATUS_REG_OFFSET 0x4001 -#define P_TS_TIM 0x80 /* check timeout status */ - /* Bits D6-D4 N/U */ -#define P_TS_ARM_DRQ_INT 0x08 /* Arm DRQ Int. When set high, - * the next rising edge will - * cause a CD-ROM interrupt. - * When set low, the interrupt - * will be cleared. There is - * no status available for - * this interrupt. - */ -#define P_TS_ENABLE_TO_ERR_INTERRUPT /* Enable timeout error int. */ -#define P_TS_ENABLE_WAIT /* Enable Wait */ - -#define P_TS_CT 0x01 /* clear timeout. Note: writing - * to this register clears the - * timeout error int. or status - */ - - -/* - * The data register reads/writes to/from the 5380 in pseudo-DMA mode - */ - -#define P_DATA_REG_OFFSET 0x5c00 /* rw */ - -#define P_STATUS_REG_OFFSET 0x5c01 /* ro */ -#define P_ST_RDY 0x80 /* 5380 DDRQ Status */ - -#define P_IRQ_STATUS 0x5c03 -#define P_IS_IRQ 0x80 /* DIRQ status */ - -#define PCB_CONFIG 0x803 -#define MASTER_ADDRESS_PTR 0x9a01 /* Fixed position - no relo */ -#define SYS_CONFIG_4 0x8003 -#define WAIT_STATE 0xbc00 -#define OPERATION_MODE_1 0xec03 -#define IO_CONFIG_3 0xf002 - - -#ifndef ASM -static int pas16_abort(Scsi_Cmnd *); -static int pas16_biosparam(struct scsi_device *, struct block_device *, - sector_t, int*); -static int pas16_detect(struct scsi_host_template *); -static int pas16_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static int pas16_bus_reset(Scsi_Cmnd *); - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 32 -#endif - -#ifndef HOSTS_C - -#define NCR5380_implementation_fields \ - volatile unsigned short io_port - -#define NCR5380_local_declare() \ - volatile unsigned short io_port - -#define NCR5380_setup(instance) \ - io_port = (instance)->io_port - -#define PAS16_io_port(reg) ( io_port + pas16_offset[(reg)] ) - -#if !(PDEBUG & PDEBUG_TRANSFER) -#define NCR5380_read(reg) ( inb(PAS16_io_port(reg)) ) -#define NCR5380_write(reg, value) ( outb((value),PAS16_io_port(reg)) ) -#else -#define NCR5380_read(reg) \ - (((unsigned char) printk("scsi%d : read register %d at io_port %04x\n"\ - , instance->hostno, (reg), PAS16_io_port(reg))), inb( PAS16_io_port(reg)) ) - -#define NCR5380_write(reg, value) \ - (printk("scsi%d : write %02x to register %d at io_port %04x\n", \ - instance->hostno, (value), (reg), PAS16_io_port(reg)), \ - outb( (value),PAS16_io_port(reg) ) ) - -#endif - - -#define NCR5380_intr pas16_intr -#define do_NCR5380_intr do_pas16_intr -#define NCR5380_queue_command pas16_queue_command -#define NCR5380_abort pas16_abort -#define NCR5380_bus_reset pas16_bus_reset -#define NCR5380_proc_info pas16_proc_info - -/* 15 14 12 10 7 5 3 - 1101 0100 1010 1000 */ - -#define PAS16_IRQS 0xd4a8 - -#endif /* else def HOSTS_C */ -#endif /* ndef ASM */ -#endif /* PAS16_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/Kconfig b/ANDROID_3.4.5/drivers/scsi/pcmcia/Kconfig deleted file mode 100644 index ecc855c5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/Kconfig +++ /dev/null @@ -1,83 +0,0 @@ -# -# PCMCIA SCSI adapter configuration -# - -menuconfig SCSI_LOWLEVEL_PCMCIA - bool "PCMCIA SCSI adapter support" - depends on SCSI!=n && PCMCIA!=n - -# drivers have problems when build in, so require modules -if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m - -config PCMCIA_AHA152X - tristate "Adaptec AHA152X PCMCIA support" - select SCSI_SPI_ATTRS - help - Say Y here if you intend to attach this type of PCMCIA SCSI host - adapter to your computer. - - To compile this driver as a module, choose M here: the - module will be called aha152x_cs. - -config PCMCIA_FDOMAIN - tristate "Future Domain PCMCIA support" - help - Say Y here if you intend to attach this type of PCMCIA SCSI host - adapter to your computer. - - To compile this driver as a module, choose M here: the - module will be called fdomain_cs. - -config PCMCIA_NINJA_SCSI - tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support" - depends on !64BIT - help - If you intend to attach this type of PCMCIA SCSI host adapter to - your computer, say Y here and read - . - - Supported cards: - - NinjaSCSI-3: (version string: "WBT","NinjaSCSI-3","R1.0") - IO-DATA PCSC-FP - ALPHA DATA AD-PCS201 - CyQ've SFC-201 - LOGITECH LPM-SCSI2E - Pioneer PCR-PR24's card - I-O DATA CDPS-PX24's card (PCSC-F) - Panasonic KXL-RW10AN CD-RW's card - etc. - - NinjaSCSI-32Bit (in 16bit mode): - [Workbit (version string: "WORKBIT","UltraNinja-16","1")] - Jazz SCP050 - [I-O DATA (OEM) (version string: "IO DATA","CBSC16 ","1")] - I-O DATA CBSC-II - [Kyusyu Matsushita Kotobuki (OEM) - (version string: "KME ","SCSI-CARD-001","1")] - KME KXL-820AN's card - HP M820e CDRW's card - etc. - - To compile this driver as a module, choose M here: the - module will be called nsp_cs. - -config PCMCIA_QLOGIC - tristate "Qlogic PCMCIA support" - help - Say Y here if you intend to attach this type of PCMCIA SCSI host - adapter to your computer. - - To compile this driver as a module, choose M here: the - module will be called qlogic_cs. - -config PCMCIA_SYM53C500 - tristate "Symbios 53c500 PCMCIA support" - help - Say Y here if you have a New Media Bus Toaster or other PCMCIA - SCSI adapter based on the Symbios 53c500 controller. - - To compile this driver as a module, choose M here: the - module will be called sym53c500_cs. - -endif # SCSI_LOWLEVEL_PCMCIA diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/Makefile b/ANDROID_3.4.5/drivers/scsi/pcmcia/Makefile deleted file mode 100644 index 683bf148..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/Makefile +++ /dev/null @@ -1,13 +0,0 @@ - -ccflags-y := -Idrivers/scsi - -# 16-bit client drivers -obj-$(CONFIG_PCMCIA_QLOGIC) += qlogic_cs.o -obj-$(CONFIG_PCMCIA_FDOMAIN) += fdomain_cs.o -obj-$(CONFIG_PCMCIA_AHA152X) += aha152x_cs.o -obj-$(CONFIG_PCMCIA_NINJA_SCSI) += nsp_cs.o -obj-$(CONFIG_PCMCIA_SYM53C500) += sym53c500_cs.o - -aha152x_cs-objs := aha152x_stub.o aha152x_core.o -fdomain_cs-objs := fdomain_stub.o fdomain_core.o -qlogic_cs-objs := qlogic_stub.o diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_core.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_core.c deleted file mode 100644 index dba37165..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_core.c +++ /dev/null @@ -1,3 +0,0 @@ -#define PCMCIA 1 -#define AHA152X_STAT 1 -#include "aha152x.c" diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_stub.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_stub.c deleted file mode 100644 index 7d1609fa..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/aha152x_stub.c +++ /dev/null @@ -1,235 +0,0 @@ -/*====================================================================== - - A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards. - - This driver supports the Adaptec AHA-1460, the New Media Bus - Toaster, and the New Media Toast & Jam. - - aha152x_cs.c 1.54 2000/06/12 21:27:25 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include "aha152x.h" - -#include -#include - - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* SCSI bus setup options */ -static int host_id = 7; -static int reconnect = 1; -static int parity = 1; -static int synchronous = 1; -static int reset_delay = 100; -static int ext_trans = 0; - -module_param(host_id, int, 0); -module_param(reconnect, int, 0); -module_param(parity, int, 0); -module_param(synchronous, int, 0); -module_param(reset_delay, int, 0); -module_param(ext_trans, int, 0); - -MODULE_LICENSE("Dual MPL/GPL"); - -/*====================================================================*/ - -typedef struct scsi_info_t { - struct pcmcia_device *p_dev; - struct Scsi_Host *host; -} scsi_info_t; - -static void aha152x_release_cs(struct pcmcia_device *link); -static void aha152x_detach(struct pcmcia_device *p_dev); -static int aha152x_config_cs(struct pcmcia_device *link); - -static int aha152x_probe(struct pcmcia_device *link) -{ - scsi_info_t *info; - - dev_dbg(&link->dev, "aha152x_attach()\n"); - - /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) return -ENOMEM; - info->p_dev = link; - link->priv = info; - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - link->config_regs = PRESENT_OPTION; - - return aha152x_config_cs(link); -} /* aha152x_attach */ - -/*====================================================================*/ - -static void aha152x_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "aha152x_detach\n"); - - aha152x_release_cs(link); - - /* Unlink device structure, free bits */ - kfree(link->priv); -} /* aha152x_detach */ - -/*====================================================================*/ - -static int aha152x_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->io_lines = 10; - - /* For New Media T&J, look for a SCSI window */ - if ((p_dev->resource[0]->end < 0x20) && - (p_dev->resource[1]->end >= 0x20)) - p_dev->resource[0]->start = p_dev->resource[1]->start; - - if (p_dev->resource[0]->start >= 0xffff) - return -EINVAL; - - p_dev->resource[1]->start = p_dev->resource[1]->end = 0; - p_dev->resource[0]->end = 0x20; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - return pcmcia_request_io(p_dev); -} - -static int aha152x_config_cs(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - struct aha152x_setup s; - int ret; - struct Scsi_Host *host; - - dev_dbg(&link->dev, "aha152x_config\n"); - - ret = pcmcia_loop_config(link, aha152x_config_check, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* Set configuration options for the aha152x driver */ - memset(&s, 0, sizeof(s)); - s.conf = "PCMCIA setup"; - s.io_port = link->resource[0]->start; - s.irq = link->irq; - s.scsiid = host_id; - s.reconnect = reconnect; - s.parity = parity; - s.synchronous = synchronous; - s.delay = reset_delay; - if (ext_trans) - s.ext_trans = ext_trans; - - host = aha152x_probe_one(&s); - if (host == NULL) { - printk(KERN_INFO "aha152x_cs: no SCSI devices found\n"); - goto failed; - } - - info->host = host; - - return 0; - -failed: - aha152x_release_cs(link); - return -ENODEV; -} - -static void aha152x_release_cs(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - - aha152x_release(info->host); - pcmcia_disable_device(link); -} - -static int aha152x_resume(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - - aha152x_host_reset_host(info->host); - - return 0; -} - -static const struct pcmcia_device_id aha152x_ids[] = { - PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e), - PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e), - PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20), - PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Multimedia Sound/SCSI", 0x085a850b, 0x80a6535c), - PCMCIA_DEVICE_PROD_ID12("NOTEWORTHY", "NWCOMB02 SCSI/AUDIO COMBO CARD", 0xad89c6e8, 0x5f9a615b), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, aha152x_ids); - -static struct pcmcia_driver aha152x_cs_driver = { - .owner = THIS_MODULE, - .name = "aha152x_cs", - .probe = aha152x_probe, - .remove = aha152x_detach, - .id_table = aha152x_ids, - .resume = aha152x_resume, -}; - -static int __init init_aha152x_cs(void) -{ - return pcmcia_register_driver(&aha152x_cs_driver); -} - -static void __exit exit_aha152x_cs(void) -{ - pcmcia_unregister_driver(&aha152x_cs_driver); -} - -module_init(init_aha152x_cs); -module_exit(exit_aha152x_cs); diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_core.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_core.c deleted file mode 100644 index a4891379..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_core.c +++ /dev/null @@ -1,2 +0,0 @@ -#define PCMCIA 1 -#include "fdomain.c" diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_stub.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_stub.c deleted file mode 100644 index 714b248f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/fdomain_stub.c +++ /dev/null @@ -1,209 +0,0 @@ -/*====================================================================== - - A driver for Future Domain-compatible PCMCIA SCSI cards - - fdomain_cs.c 1.47 2001/10/13 00:08:52 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in - which case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include "fdomain.h" - -#include -#include - -/*====================================================================*/ - -/* Module parameters */ - -MODULE_AUTHOR("David Hinds "); -MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver"); -MODULE_LICENSE("Dual MPL/GPL"); - -/*====================================================================*/ - -typedef struct scsi_info_t { - struct pcmcia_device *p_dev; - struct Scsi_Host *host; -} scsi_info_t; - - -static void fdomain_release(struct pcmcia_device *link); -static void fdomain_detach(struct pcmcia_device *p_dev); -static int fdomain_config(struct pcmcia_device *link); - -static int fdomain_probe(struct pcmcia_device *link) -{ - scsi_info_t *info; - - dev_dbg(&link->dev, "fdomain_attach()\n"); - - /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->p_dev = link; - link->priv = info; - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - link->config_regs = PRESENT_OPTION; - - return fdomain_config(link); -} /* fdomain_attach */ - -/*====================================================================*/ - -static void fdomain_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "fdomain_detach\n"); - - fdomain_release(link); - - kfree(link->priv); -} /* fdomain_detach */ - -/*====================================================================*/ - -static int fdomain_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->io_lines = 10; - p_dev->resource[0]->end = 0x10; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - return pcmcia_request_io(p_dev); -} - - -static int fdomain_config(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - int ret; - char str[22]; - struct Scsi_Host *host; - - dev_dbg(&link->dev, "fdomain_config\n"); - - ret = pcmcia_loop_config(link, fdomain_config_check, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* A bad hack... */ - release_region(link->resource[0]->start, resource_size(link->resource[0])); - - /* Set configuration options for the fdomain driver */ - sprintf(str, "%d,%d", (unsigned int) link->resource[0]->start, link->irq); - fdomain_setup(str); - - host = __fdomain_16x0_detect(&fdomain_driver_template); - if (!host) { - printk(KERN_INFO "fdomain_cs: no SCSI devices found\n"); - goto failed; - } - - if (scsi_add_host(host, NULL)) - goto failed; - scsi_scan_host(host); - - info->host = host; - - return 0; - -failed: - fdomain_release(link); - return -ENODEV; -} /* fdomain_config */ - -/*====================================================================*/ - -static void fdomain_release(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - - dev_dbg(&link->dev, "fdomain_release\n"); - - scsi_remove_host(info->host); - pcmcia_disable_device(link); - scsi_unregister(info->host); -} - -/*====================================================================*/ - -static int fdomain_resume(struct pcmcia_device *link) -{ - fdomain_16x0_bus_reset(NULL); - - return 0; -} - -static const struct pcmcia_device_id fdomain_ids[] = { - PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20), - PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e), - PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, fdomain_ids); - -static struct pcmcia_driver fdomain_cs_driver = { - .owner = THIS_MODULE, - .name = "fdomain_cs", - .probe = fdomain_probe, - .remove = fdomain_detach, - .id_table = fdomain_ids, - .resume = fdomain_resume, -}; - -static int __init init_fdomain_cs(void) -{ - return pcmcia_register_driver(&fdomain_cs_driver); -} - -static void __exit exit_fdomain_cs(void) -{ - pcmcia_unregister_driver(&fdomain_cs_driver); -} - -module_init(init_fdomain_cs); -module_exit(exit_fdomain_cs); diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.c deleted file mode 100644 index b61a753e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.c +++ /dev/null @@ -1,1791 +0,0 @@ -/*====================================================================== - - NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver - By: YOKOTA Hiroshi - - Ver.2.8 Support 32bit MMIO mode - Support Synchronous Data Transfer Request (SDTR) mode - Ver.2.0 Support 32bit PIO mode - Ver.1.1.2 Fix for scatter list buffer exceeds - Ver.1.1 Support scatter list - Ver.0.1 Initial version - - This software may be used and distributed according to the terms of - the GNU General Public License. - -======================================================================*/ - -/*********************************************************************** - This driver is for these PCcards. - - I-O DATA PCSC-F (Workbit NinjaSCSI-3) - "WBT", "NinjaSCSI-3", "R1.0" - I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode) - "IO DATA", "CBSC16 ", "1" - -***********************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include <../drivers/scsi/scsi.h> -#include - -#include -#include - -#include -#include -#include - -#include "nsp_cs.h" - -MODULE_AUTHOR("YOKOTA Hiroshi "); -MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module"); -MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); -#ifdef MODULE_LICENSE -MODULE_LICENSE("GPL"); -#endif - -#include "nsp_io.h" - -/*====================================================================*/ -/* Parameters that can be set with 'insmod' */ - -static int nsp_burst_mode = BURST_MEM32; -module_param(nsp_burst_mode, int, 0); -MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))"); - -/* Release IO ports after configuration? */ -static bool free_ports = 0; -module_param(free_ports, bool, 0); -MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))"); - -static struct scsi_host_template nsp_driver_template = { - .proc_name = "nsp_cs", - .proc_info = nsp_proc_info, - .name = "WorkBit NinjaSCSI-3/32Bi(16bit)", - .info = nsp_info, - .queuecommand = nsp_queuecommand, -/* .eh_abort_handler = nsp_eh_abort,*/ - .eh_bus_reset_handler = nsp_eh_bus_reset, - .eh_host_reset_handler = nsp_eh_host_reset, - .can_queue = 1, - .this_id = NSP_INITIATOR_ID, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; - -static nsp_hw_data nsp_data_base; /* attach <-> detect glue */ - - - -/* - * debug, error print - */ -#ifndef NSP_DEBUG -# define NSP_DEBUG_MASK 0x000000 -# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args) -# define nsp_dbg(mask, args...) /* */ -#else -# define NSP_DEBUG_MASK 0xffffff -# define nsp_msg(type, args...) \ - nsp_cs_message (__func__, __LINE__, (type), args) -# define nsp_dbg(mask, args...) \ - nsp_cs_dmessage(__func__, __LINE__, (mask), args) -#endif - -#define NSP_DEBUG_QUEUECOMMAND BIT(0) -#define NSP_DEBUG_REGISTER BIT(1) -#define NSP_DEBUG_AUTOSCSI BIT(2) -#define NSP_DEBUG_INTR BIT(3) -#define NSP_DEBUG_SGLIST BIT(4) -#define NSP_DEBUG_BUSFREE BIT(5) -#define NSP_DEBUG_CDB_CONTENTS BIT(6) -#define NSP_DEBUG_RESELECTION BIT(7) -#define NSP_DEBUG_MSGINOCCUR BIT(8) -#define NSP_DEBUG_EEPROM BIT(9) -#define NSP_DEBUG_MSGOUTOCCUR BIT(10) -#define NSP_DEBUG_BUSRESET BIT(11) -#define NSP_DEBUG_RESTART BIT(12) -#define NSP_DEBUG_SYNC BIT(13) -#define NSP_DEBUG_WAIT BIT(14) -#define NSP_DEBUG_TARGETFLAG BIT(15) -#define NSP_DEBUG_PROC BIT(16) -#define NSP_DEBUG_INIT BIT(17) -#define NSP_DEBUG_DATA_IO BIT(18) -#define NSP_SPECIAL_PRINT_REGISTER BIT(20) - -#define NSP_DEBUG_BUF_LEN 150 - -static inline void nsp_inc_resid(struct scsi_cmnd *SCpnt, int residInc) -{ - scsi_set_resid(SCpnt, scsi_get_resid(SCpnt) + residInc); -} - -static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...) -{ - va_list args; - char buf[NSP_DEBUG_BUF_LEN]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - -#ifndef NSP_DEBUG - printk("%snsp_cs: %s\n", type, buf); -#else - printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf); -#endif -} - -#ifdef NSP_DEBUG -static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...) -{ - va_list args; - char buf[NSP_DEBUG_BUF_LEN]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - - if (mask & NSP_DEBUG_MASK) { - printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf); - } -} -#endif - -/***********************************************************/ - -/*==================================================== - * Clenaup parameters and call done() functions. - * You must be set SCpnt->result before call this function. - */ -static void nsp_scsi_done(struct scsi_cmnd *SCpnt) -{ - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - - data->CurrentSC = NULL; - - SCpnt->scsi_done(SCpnt); -} - -static int nsp_queuecommand_lck(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ -#ifdef NSP_DEBUG - /*unsigned int host_id = SCpnt->device->host->this_id;*/ - /*unsigned int base = SCpnt->device->host->io_port;*/ - unsigned char target = scmd_id(SCpnt); -#endif - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - - nsp_dbg(NSP_DEBUG_QUEUECOMMAND, - "SCpnt=0x%p target=%d lun=%d sglist=0x%p bufflen=%d sg_count=%d", - SCpnt, target, SCpnt->device->lun, scsi_sglist(SCpnt), - scsi_bufflen(SCpnt), scsi_sg_count(SCpnt)); - //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC); - - SCpnt->scsi_done = done; - - if (data->CurrentSC != NULL) { - nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen"); - SCpnt->result = DID_BAD_TARGET << 16; - nsp_scsi_done(SCpnt); - return 0; - } - -#if 0 - /* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility. - This makes kernel crash when suspending... */ - if (data->ScsiInfo->stop != 0) { - nsp_msg(KERN_INFO, "suspending device. reject command."); - SCpnt->result = DID_BAD_TARGET << 16; - nsp_scsi_done(SCpnt); - return SCSI_MLQUEUE_HOST_BUSY; - } -#endif - - show_command(SCpnt); - - data->CurrentSC = SCpnt; - - SCpnt->SCp.Status = CHECK_CONDITION; - SCpnt->SCp.Message = 0; - SCpnt->SCp.have_data_in = IO_UNKNOWN; - SCpnt->SCp.sent_command = 0; - SCpnt->SCp.phase = PH_UNDETERMINED; - scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); - - /* setup scratch area - SCp.ptr : buffer pointer - SCp.this_residual : buffer length - SCp.buffer : next buffer - SCp.buffers_residual : left buffers in list - SCp.phase : current state of the command */ - if (scsi_bufflen(SCpnt)) { - SCpnt->SCp.buffer = scsi_sglist(SCpnt); - SCpnt->SCp.ptr = BUFFER_ADDR; - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1; - } else { - SCpnt->SCp.ptr = NULL; - SCpnt->SCp.this_residual = 0; - SCpnt->SCp.buffer = NULL; - SCpnt->SCp.buffers_residual = 0; - } - - if (nsphw_start_selection(SCpnt) == FALSE) { - nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail"); - SCpnt->result = DID_BUS_BUSY << 16; - nsp_scsi_done(SCpnt); - return 0; - } - - - //nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out"); -#ifdef NSP_DEBUG - data->CmdId++; -#endif - return 0; -} - -static DEF_SCSI_QCMD(nsp_queuecommand) - -/* - * setup PIO FIFO transfer mode and enable/disable to data out - */ -static void nsp_setup_fifo(nsp_hw_data *data, int enabled) -{ - unsigned int base = data->BaseAddress; - unsigned char transfer_mode_reg; - - //nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled); - - if (enabled != FALSE) { - transfer_mode_reg = TRANSFER_GO | BRAIND; - } else { - transfer_mode_reg = 0; - } - - transfer_mode_reg |= data->TransferMode; - - nsp_index_write(base, TRANSFERMODE, transfer_mode_reg); -} - -static void nsphw_init_sync(nsp_hw_data *data) -{ - sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET, - .SyncPeriod = 0, - .SyncOffset = 0 - }; - int i; - - /* setup sync data */ - for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) { - data->Sync[i] = tmp_sync; - } -} - -/* - * Initialize Ninja hardware - */ -static int nsphw_init(nsp_hw_data *data) -{ - unsigned int base = data->BaseAddress; - - nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base); - - data->ScsiClockDiv = CLOCK_40M | FAST_20; - data->CurrentSC = NULL; - data->FifoCount = 0; - data->TransferMode = MODE_IO8; - - nsphw_init_sync(data); - - /* block all interrupts */ - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); - - /* setup SCSI interface */ - nsp_write(base, IFSELECT, IF_IFSEL); - - nsp_index_write(base, SCSIIRQMODE, 0); - - nsp_index_write(base, TRANSFERMODE, MODE_IO8); - nsp_index_write(base, CLOCKDIV, data->ScsiClockDiv); - - nsp_index_write(base, PARITYCTRL, 0); - nsp_index_write(base, POINTERCLR, POINTER_CLEAR | - ACK_COUNTER_CLEAR | - REQ_COUNTER_CLEAR | - HOST_COUNTER_CLEAR); - - /* setup fifo asic */ - nsp_write(base, IFSELECT, IF_REGSEL); - nsp_index_write(base, TERMPWRCTRL, 0); - if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) { - nsp_msg(KERN_INFO, "terminator power on"); - nsp_index_write(base, TERMPWRCTRL, POWER_ON); - } - - nsp_index_write(base, TIMERCOUNT, 0); - nsp_index_write(base, TIMERCOUNT, 0); /* requires 2 times!! */ - - nsp_index_write(base, SYNCREG, 0); - nsp_index_write(base, ACKWIDTH, 0); - - /* enable interrupts and ack them */ - nsp_index_write(base, SCSIIRQMODE, SCSI_PHASE_CHANGE_EI | - RESELECT_EI | - SCSI_RESET_IRQ_EI ); - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); - - nsp_setup_fifo(data, FALSE); - - return TRUE; -} - -/* - * Start selection phase - */ -static int nsphw_start_selection(struct scsi_cmnd *SCpnt) -{ - unsigned int host_id = SCpnt->device->host->this_id; - unsigned int base = SCpnt->device->host->io_port; - unsigned char target = scmd_id(SCpnt); - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - int time_out; - unsigned char phase, arbit; - - //nsp_dbg(NSP_DEBUG_RESELECTION, "in"); - - phase = nsp_index_read(base, SCSIBUSMON); - if(phase != BUSMON_BUS_FREE) { - //nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy"); - return FALSE; - } - - /* start arbitration */ - //nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit"); - SCpnt->SCp.phase = PH_ARBSTART; - nsp_index_write(base, SETARBIT, ARBIT_GO); - - time_out = 1000; - do { - /* XXX: what a stupid chip! */ - arbit = nsp_index_read(base, ARBITSTATUS); - //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count); - udelay(1); /* hold 1.2us */ - } while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 && - (time_out-- != 0)); - - if (!(arbit & ARBIT_WIN)) { - //nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail"); - nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); - return FALSE; - } - - /* assert select line */ - //nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line"); - SCpnt->SCp.phase = PH_SELSTART; - udelay(3); /* wait 2.4us */ - nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target)); - nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_ATN); - udelay(2); /* wait >1.2us */ - nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN); - nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR); - /*udelay(1);*/ /* wait >90ns */ - nsp_index_write(base, SCSIBUSCTRL, SCSI_SEL | SCSI_DATAOUT_ENB | SCSI_ATN); - - /* check selection timeout */ - nsp_start_timer(SCpnt, 1000/51); - data->SelectionTimeOut = 1; - - return TRUE; -} - -struct nsp_sync_table { - unsigned int min_period; - unsigned int max_period; - unsigned int chip_period; - unsigned int ack_width; -}; - -static struct nsp_sync_table nsp_sync_table_40M[] = { - {0x0c, 0x0c, 0x1, 0}, /* 20MB 50ns*/ - {0x19, 0x19, 0x3, 1}, /* 10MB 100ns*/ - {0x1a, 0x25, 0x5, 2}, /* 7.5MB 150ns*/ - {0x26, 0x32, 0x7, 3}, /* 5MB 200ns*/ - { 0, 0, 0, 0}, -}; - -static struct nsp_sync_table nsp_sync_table_20M[] = { - {0x19, 0x19, 0x1, 0}, /* 10MB 100ns*/ - {0x1a, 0x25, 0x2, 0}, /* 7.5MB 150ns*/ - {0x26, 0x32, 0x3, 1}, /* 5MB 200ns*/ - { 0, 0, 0, 0}, -}; - -/* - * setup synchronous data transfer mode - */ -static int nsp_analyze_sdtr(struct scsi_cmnd *SCpnt) -{ - unsigned char target = scmd_id(SCpnt); -// unsigned char lun = SCpnt->device->lun; - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - sync_data *sync = &(data->Sync[target]); - struct nsp_sync_table *sync_table; - unsigned int period, offset; - int i; - - - nsp_dbg(NSP_DEBUG_SYNC, "in"); - - period = sync->SyncPeriod; - offset = sync->SyncOffset; - - nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset); - - if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) { - sync_table = nsp_sync_table_20M; - } else { - sync_table = nsp_sync_table_40M; - } - - for ( i = 0; sync_table->max_period != 0; i++, sync_table++) { - if ( period >= sync_table->min_period && - period <= sync_table->max_period ) { - break; - } - } - - if (period != 0 && sync_table->max_period == 0) { - /* - * No proper period/offset found - */ - nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset"); - - sync->SyncPeriod = 0; - sync->SyncOffset = 0; - sync->SyncRegister = 0; - sync->AckWidth = 0; - - return FALSE; - } - - sync->SyncRegister = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) | - (offset & SYNCREG_OFFSET_MASK); - sync->AckWidth = sync_table->ack_width; - - nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth); - - return TRUE; -} - - -/* - * start ninja hardware timer - */ -static void nsp_start_timer(struct scsi_cmnd *SCpnt, int time) -{ - unsigned int base = SCpnt->device->host->io_port; - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - - //nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time); - data->TimerCount = time; - nsp_index_write(base, TIMERCOUNT, time); -} - -/* - * wait for bus phase change - */ -static int nsp_negate_signal(struct scsi_cmnd *SCpnt, unsigned char mask, - char *str) -{ - unsigned int base = SCpnt->device->host->io_port; - unsigned char reg; - int time_out; - - //nsp_dbg(NSP_DEBUG_INTR, "in"); - - time_out = 100; - - do { - reg = nsp_index_read(base, SCSIBUSMON); - if (reg == 0xff) { - break; - } - } while ((--time_out != 0) && (reg & mask) != 0); - - if (time_out == 0) { - nsp_msg(KERN_DEBUG, " %s signal off timeut", str); - } - - return 0; -} - -/* - * expect Ninja Irq - */ -static int nsp_expect_signal(struct scsi_cmnd *SCpnt, - unsigned char current_phase, - unsigned char mask) -{ - unsigned int base = SCpnt->device->host->io_port; - int time_out; - unsigned char phase, i_src; - - //nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask); - - time_out = 100; - do { - phase = nsp_index_read(base, SCSIBUSMON); - if (phase == 0xff) { - //nsp_dbg(NSP_DEBUG_INTR, "ret -1"); - return -1; - } - i_src = nsp_read(base, IRQSTATUS); - if (i_src & IRQSTATUS_SCSI) { - //nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal"); - return 0; - } - if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) { - //nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase); - return 1; - } - } while(time_out-- != 0); - - //nsp_dbg(NSP_DEBUG_INTR, "timeout"); - return -1; -} - -/* - * transfer SCSI message - */ -static int nsp_xfer(struct scsi_cmnd *SCpnt, int phase) -{ - unsigned int base = SCpnt->device->host->io_port; - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - char *buf = data->MsgBuffer; - int len = min(MSGBUF_SIZE, data->MsgLen); - int ptr; - int ret; - - //nsp_dbg(NSP_DEBUG_DATA_IO, "in"); - for (ptr = 0; len > 0; len--, ptr++) { - - ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ); - if (ret <= 0) { - nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit"); - return 0; - } - - /* if last byte, negate ATN */ - if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) { - nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB); - } - - /* read & write message */ - if (phase & BUSMON_IO) { - nsp_dbg(NSP_DEBUG_DATA_IO, "read msg"); - buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK); - } else { - nsp_dbg(NSP_DEBUG_DATA_IO, "write msg"); - nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]); - } - nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer"); - - } - return len; -} - -/* - * get extra SCSI data from fifo - */ -static int nsp_dataphase_bypass(struct scsi_cmnd *SCpnt) -{ - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - unsigned int count; - - //nsp_dbg(NSP_DEBUG_DATA_IO, "in"); - - if (SCpnt->SCp.have_data_in != IO_IN) { - return 0; - } - - count = nsp_fifo_count(SCpnt); - if (data->FifoCount == count) { - //nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk"); - return 0; - } - - /* - * XXX: NSP_QUIRK - * data phase skip only occures in case of SCSI_LOW_READ - */ - nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk"); - SCpnt->SCp.phase = PH_DATA; - nsp_pio_read(SCpnt); - nsp_setup_fifo(data, FALSE); - - return 0; -} - -/* - * accept reselection - */ -static int nsp_reselected(struct scsi_cmnd *SCpnt) -{ - unsigned int base = SCpnt->device->host->io_port; - unsigned int host_id = SCpnt->device->host->this_id; - //nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - unsigned char bus_reg; - unsigned char id_reg, tmp; - int target; - - nsp_dbg(NSP_DEBUG_RESELECTION, "in"); - - id_reg = nsp_index_read(base, RESELECTID); - tmp = id_reg & (~BIT(host_id)); - target = 0; - while(tmp != 0) { - if (tmp & BIT(0)) { - break; - } - tmp >>= 1; - target++; - } - - if (scmd_id(SCpnt) != target) { - nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target); - } - - nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect"); - - nsp_nexus(SCpnt); - bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN); - nsp_index_write(base, SCSIBUSCTRL, bus_reg); - nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB); - - return TRUE; -} - -/* - * count how many data transferd - */ -static int nsp_fifo_count(struct scsi_cmnd *SCpnt) -{ - unsigned int base = SCpnt->device->host->io_port; - unsigned int count; - unsigned int l, m, h, dummy; - - nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER); - - l = nsp_index_read(base, TRANSFERCOUNT); - m = nsp_index_read(base, TRANSFERCOUNT); - h = nsp_index_read(base, TRANSFERCOUNT); - dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */ - - count = (h << 16) | (m << 8) | (l << 0); - - //nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count); - - return count; -} - -/* fifo size */ -#define RFIFO_CRIT 64 -#define WFIFO_CRIT 64 - -/* - * read data in DATA IN phase - */ -static void nsp_pio_read(struct scsi_cmnd *SCpnt) -{ - unsigned int base = SCpnt->device->host->io_port; - unsigned long mmio_base = SCpnt->device->host->base; - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - long time_out; - int ocount, res; - unsigned char stat, fifo_stat; - - ocount = data->FifoCount; - - nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d", - SCpnt, scsi_get_resid(SCpnt), ocount, SCpnt->SCp.ptr, - SCpnt->SCp.this_residual, SCpnt->SCp.buffer, - SCpnt->SCp.buffers_residual); - - time_out = 1000; - - while ((time_out-- != 0) && - (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) { - - stat = nsp_index_read(base, SCSIBUSMON); - stat &= BUSMON_PHASE_MASK; - - - res = nsp_fifo_count(SCpnt) - ocount; - //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res); - if (res == 0) { /* if some data available ? */ - if (stat == BUSPHASE_DATA_IN) { /* phase changed? */ - //nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual); - continue; - } else { - nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat); - break; - } - } - - fifo_stat = nsp_read(base, FIFOSTATUS); - if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 && - stat == BUSPHASE_DATA_IN) { - continue; - } - - res = min(res, SCpnt->SCp.this_residual); - - switch (data->TransferMode) { - case MODE_IO32: - res &= ~(BIT(1)|BIT(0)); /* align 4 */ - nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2); - break; - case MODE_IO8: - nsp_fifo8_read (base, SCpnt->SCp.ptr, res ); - break; - - case MODE_MEM32: - res &= ~(BIT(1)|BIT(0)); /* align 4 */ - nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2); - break; - - default: - nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode"); - return; - } - - nsp_inc_resid(SCpnt, -res); - SCpnt->SCp.ptr += res; - SCpnt->SCp.this_residual -= res; - ocount += res; - //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount); - - /* go to next scatter list if available */ - if (SCpnt->SCp.this_residual == 0 && - SCpnt->SCp.buffers_residual != 0 ) { - //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out); - SCpnt->SCp.buffers_residual--; - SCpnt->SCp.buffer++; - SCpnt->SCp.ptr = BUFFER_ADDR; - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - time_out = 1000; - - //nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset); - } - } - - data->FifoCount = ocount; - - if (time_out < 0) { - nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d", - scsi_get_resid(SCpnt), SCpnt->SCp.this_residual, - SCpnt->SCp.buffers_residual); - } - nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount); - nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, - scsi_get_resid(SCpnt)); -} - -/* - * write data in DATA OUT phase - */ -static void nsp_pio_write(struct scsi_cmnd *SCpnt) -{ - unsigned int base = SCpnt->device->host->io_port; - unsigned long mmio_base = SCpnt->device->host->base; - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - int time_out; - int ocount, res; - unsigned char stat; - - ocount = data->FifoCount; - - nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x", - data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, - SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, - scsi_get_resid(SCpnt)); - - time_out = 1000; - - while ((time_out-- != 0) && - (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) { - stat = nsp_index_read(base, SCSIBUSMON); - stat &= BUSMON_PHASE_MASK; - - if (stat != BUSPHASE_DATA_OUT) { - res = ocount - nsp_fifo_count(SCpnt); - - nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res); - /* Put back pointer */ - nsp_inc_resid(SCpnt, res); - SCpnt->SCp.ptr -= res; - SCpnt->SCp.this_residual += res; - ocount -= res; - - break; - } - - res = ocount - nsp_fifo_count(SCpnt); - if (res > 0) { /* write all data? */ - nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res); - continue; - } - - res = min(SCpnt->SCp.this_residual, WFIFO_CRIT); - - //nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res); - switch (data->TransferMode) { - case MODE_IO32: - res &= ~(BIT(1)|BIT(0)); /* align 4 */ - nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2); - break; - case MODE_IO8: - nsp_fifo8_write (base, SCpnt->SCp.ptr, res ); - break; - - case MODE_MEM32: - res &= ~(BIT(1)|BIT(0)); /* align 4 */ - nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2); - break; - - default: - nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode"); - break; - } - - nsp_inc_resid(SCpnt, -res); - SCpnt->SCp.ptr += res; - SCpnt->SCp.this_residual -= res; - ocount += res; - - /* go to next scatter list if available */ - if (SCpnt->SCp.this_residual == 0 && - SCpnt->SCp.buffers_residual != 0 ) { - //nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next"); - SCpnt->SCp.buffers_residual--; - SCpnt->SCp.buffer++; - SCpnt->SCp.ptr = BUFFER_ADDR; - SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; - time_out = 1000; - } - } - - data->FifoCount = ocount; - - if (time_out < 0) { - nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", - scsi_get_resid(SCpnt)); - } - nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount); - nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, - scsi_get_resid(SCpnt)); -} -#undef RFIFO_CRIT -#undef WFIFO_CRIT - -/* - * setup synchronous/asynchronous data transfer mode - */ -static int nsp_nexus(struct scsi_cmnd *SCpnt) -{ - unsigned int base = SCpnt->device->host->io_port; - unsigned char target = scmd_id(SCpnt); -// unsigned char lun = SCpnt->device->lun; - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - sync_data *sync = &(data->Sync[target]); - - //nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt); - - /* setup synch transfer registers */ - nsp_index_write(base, SYNCREG, sync->SyncRegister); - nsp_index_write(base, ACKWIDTH, sync->AckWidth); - - if (scsi_get_resid(SCpnt) % 4 != 0 || - scsi_get_resid(SCpnt) <= PAGE_SIZE ) { - data->TransferMode = MODE_IO8; - } else if (nsp_burst_mode == BURST_MEM32) { - data->TransferMode = MODE_MEM32; - } else if (nsp_burst_mode == BURST_IO32) { - data->TransferMode = MODE_IO32; - } else { - data->TransferMode = MODE_IO8; - } - - /* setup pdma fifo */ - nsp_setup_fifo(data, TRUE); - - /* clear ack counter */ - data->FifoCount = 0; - nsp_index_write(base, POINTERCLR, POINTER_CLEAR | - ACK_COUNTER_CLEAR | - REQ_COUNTER_CLEAR | - HOST_COUNTER_CLEAR); - - return 0; -} - -#include "nsp_message.c" -/* - * interrupt handler - */ -static irqreturn_t nspintr(int irq, void *dev_id) -{ - unsigned int base; - unsigned char irq_status, irq_phase, phase; - struct scsi_cmnd *tmpSC; - unsigned char target, lun; - unsigned int *sync_neg; - int i, tmp; - nsp_hw_data *data; - - - //nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id); - //nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host); - - if ( dev_id != NULL && - ((scsi_info_t *)dev_id)->host != NULL ) { - scsi_info_t *info = (scsi_info_t *)dev_id; - - data = (nsp_hw_data *)info->host->hostdata; - } else { - nsp_dbg(NSP_DEBUG_INTR, "host data wrong"); - return IRQ_NONE; - } - - //nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id); - - base = data->BaseAddress; - //nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base); - - /* - * interrupt check - */ - nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE); - irq_status = nsp_read(base, IRQSTATUS); - //nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status); - if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) { - nsp_write(base, IRQCONTROL, 0); - //nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq"); - return IRQ_NONE; - } - - /* XXX: IMPORTANT - * Do not read an irq_phase register if no scsi phase interrupt. - * Unless, you should lose a scsi phase interrupt. - */ - phase = nsp_index_read(base, SCSIBUSMON); - if((irq_status & IRQSTATUS_SCSI) != 0) { - irq_phase = nsp_index_read(base, IRQPHASESENCE); - } else { - irq_phase = 0; - } - - //nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase); - - /* - * timer interrupt handler (scsi vs timer interrupts) - */ - //nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount); - if (data->TimerCount != 0) { - //nsp_dbg(NSP_DEBUG_INTR, "stop timer"); - nsp_index_write(base, TIMERCOUNT, 0); - nsp_index_write(base, TIMERCOUNT, 0); - data->TimerCount = 0; - } - - if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER && - data->SelectionTimeOut == 0) { - //nsp_dbg(NSP_DEBUG_INTR, "timer start"); - nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR); - return IRQ_HANDLED; - } - - nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR); - - if ((irq_status & IRQSTATUS_SCSI) && - (irq_phase & SCSI_RESET_IRQ)) { - nsp_msg(KERN_ERR, "bus reset (power off?)"); - - nsphw_init(data); - nsp_bus_reset(data); - - if(data->CurrentSC != NULL) { - tmpSC = data->CurrentSC; - tmpSC->result = (DID_RESET << 16) | - ((tmpSC->SCp.Message & 0xff) << 8) | - ((tmpSC->SCp.Status & 0xff) << 0); - nsp_scsi_done(tmpSC); - } - return IRQ_HANDLED; - } - - if (data->CurrentSC == NULL) { - nsp_msg(KERN_ERR, "CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen. reset everything", irq_status, phase, irq_phase); - nsphw_init(data); - nsp_bus_reset(data); - return IRQ_HANDLED; - } - - tmpSC = data->CurrentSC; - target = tmpSC->device->id; - lun = tmpSC->device->lun; - sync_neg = &(data->Sync[target].SyncNegotiation); - - /* - * parse hardware SCSI irq reasons register - */ - if (irq_status & IRQSTATUS_SCSI) { - if (irq_phase & RESELECT_IRQ) { - nsp_dbg(NSP_DEBUG_INTR, "reselect"); - nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR); - if (nsp_reselected(tmpSC) != FALSE) { - return IRQ_HANDLED; - } - } - - if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) { - return IRQ_HANDLED; - } - } - - //show_phase(tmpSC); - - switch(tmpSC->SCp.phase) { - case PH_SELSTART: - // *sync_neg = SYNC_NOT_YET; - if ((phase & BUSMON_BSY) == 0) { - //nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut); - if (data->SelectionTimeOut >= NSP_SELTIMEOUT) { - nsp_dbg(NSP_DEBUG_INTR, "selection time out"); - data->SelectionTimeOut = 0; - nsp_index_write(base, SCSIBUSCTRL, 0); - - tmpSC->result = DID_TIME_OUT << 16; - nsp_scsi_done(tmpSC); - - return IRQ_HANDLED; - } - data->SelectionTimeOut += 1; - nsp_start_timer(tmpSC, 1000/51); - return IRQ_HANDLED; - } - - /* attention assert */ - //nsp_dbg(NSP_DEBUG_INTR, "attention assert"); - data->SelectionTimeOut = 0; - tmpSC->SCp.phase = PH_SELECTED; - nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN); - udelay(1); - nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB); - return IRQ_HANDLED; - - break; - - case PH_RESELECT: - //nsp_dbg(NSP_DEBUG_INTR, "phase reselect"); - // *sync_neg = SYNC_NOT_YET; - if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) { - - tmpSC->result = DID_ABORT << 16; - nsp_scsi_done(tmpSC); - return IRQ_HANDLED; - } - /* fall thru */ - default: - if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) { - return IRQ_HANDLED; - } - break; - } - - /* - * SCSI sequencer - */ - //nsp_dbg(NSP_DEBUG_INTR, "start scsi seq"); - - /* normal disconnect */ - if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) && - (irq_phase & LATCHED_BUS_FREE) != 0 ) { - nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase); - - //*sync_neg = SYNC_NOT_YET; - - if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) { /* all command complete and return status */ - tmpSC->result = (DID_OK << 16) | - ((tmpSC->SCp.Message & 0xff) << 8) | - ((tmpSC->SCp.Status & 0xff) << 0); - nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result); - nsp_scsi_done(tmpSC); - - return IRQ_HANDLED; - } - - return IRQ_HANDLED; - } - - - /* check unexpected bus free state */ - if (phase == 0) { - nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase); - - *sync_neg = SYNC_NG; - tmpSC->result = DID_ERROR << 16; - nsp_scsi_done(tmpSC); - return IRQ_HANDLED; - } - - switch (phase & BUSMON_PHASE_MASK) { - case BUSPHASE_COMMAND: - nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND"); - if ((phase & BUSMON_REQ) == 0) { - nsp_dbg(NSP_DEBUG_INTR, "REQ == 0"); - return IRQ_HANDLED; - } - - tmpSC->SCp.phase = PH_COMMAND; - - nsp_nexus(tmpSC); - - /* write scsi command */ - nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len); - nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER); - for (i = 0; i < tmpSC->cmd_len; i++) { - nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]); - } - nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO); - break; - - case BUSPHASE_DATA_OUT: - nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT"); - - tmpSC->SCp.phase = PH_DATA; - tmpSC->SCp.have_data_in = IO_OUT; - - nsp_pio_write(tmpSC); - - break; - - case BUSPHASE_DATA_IN: - nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN"); - - tmpSC->SCp.phase = PH_DATA; - tmpSC->SCp.have_data_in = IO_IN; - - nsp_pio_read(tmpSC); - - break; - - case BUSPHASE_STATUS: - nsp_dataphase_bypass(tmpSC); - nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS"); - - tmpSC->SCp.phase = PH_STATUS; - - tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK); - nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status); - - break; - - case BUSPHASE_MESSAGE_OUT: - nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT"); - if ((phase & BUSMON_REQ) == 0) { - goto timer_out; - } - - tmpSC->SCp.phase = PH_MSG_OUT; - - //*sync_neg = SYNC_NOT_YET; - - data->MsgLen = i = 0; - data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++; - - if (*sync_neg == SYNC_NOT_YET) { - data->Sync[target].SyncPeriod = 0; - data->Sync[target].SyncOffset = 0; - - /**/ - data->MsgBuffer[i] = MSG_EXTENDED; i++; - data->MsgBuffer[i] = 3; i++; - data->MsgBuffer[i] = MSG_EXT_SDTR; i++; - data->MsgBuffer[i] = 0x0c; i++; - data->MsgBuffer[i] = 15; i++; - /**/ - } - data->MsgLen = i; - - nsp_analyze_sdtr(tmpSC); - show_message(data); - nsp_message_out(tmpSC); - break; - - case BUSPHASE_MESSAGE_IN: - nsp_dataphase_bypass(tmpSC); - nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN"); - if ((phase & BUSMON_REQ) == 0) { - goto timer_out; - } - - tmpSC->SCp.phase = PH_MSG_IN; - nsp_message_in(tmpSC); - - /**/ - if (*sync_neg == SYNC_NOT_YET) { - //nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun); - - if (data->MsgLen >= 5 && - data->MsgBuffer[0] == MSG_EXTENDED && - data->MsgBuffer[1] == 3 && - data->MsgBuffer[2] == MSG_EXT_SDTR ) { - data->Sync[target].SyncPeriod = data->MsgBuffer[3]; - data->Sync[target].SyncOffset = data->MsgBuffer[4]; - //nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]); - *sync_neg = SYNC_OK; - } else { - data->Sync[target].SyncPeriod = 0; - data->Sync[target].SyncOffset = 0; - *sync_neg = SYNC_NG; - } - nsp_analyze_sdtr(tmpSC); - } - /**/ - - /* search last messeage byte */ - tmp = -1; - for (i = 0; i < data->MsgLen; i++) { - tmp = data->MsgBuffer[i]; - if (data->MsgBuffer[i] == MSG_EXTENDED) { - i += (1 + data->MsgBuffer[i+1]); - } - } - tmpSC->SCp.Message = tmp; - - nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen); - show_message(data); - - break; - - case BUSPHASE_SELECT: - default: - nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other"); - - break; - } - - //nsp_dbg(NSP_DEBUG_INTR, "out"); - return IRQ_HANDLED; - -timer_out: - nsp_start_timer(tmpSC, 1000/102); - return IRQ_HANDLED; -} - -#ifdef NSP_DEBUG -#include "nsp_debug.c" -#endif /* NSP_DEBUG */ - -/*----------------------------------------------------------------*/ -/* look for ninja3 card and init if found */ -/*----------------------------------------------------------------*/ -static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht) -{ - struct Scsi_Host *host; /* registered host structure */ - nsp_hw_data *data_b = &nsp_data_base, *data; - - nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id); - host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data)); - if (host == NULL) { - nsp_dbg(NSP_DEBUG_INIT, "host failed"); - return NULL; - } - - memcpy(host->hostdata, data_b, sizeof(nsp_hw_data)); - data = (nsp_hw_data *)host->hostdata; - data->ScsiInfo->host = host; -#ifdef NSP_DEBUG - data->CmdId = 0; -#endif - - nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber); - - host->unique_id = data->BaseAddress; - host->io_port = data->BaseAddress; - host->n_io_port = data->NumAddress; - host->irq = data->IrqNumber; - host->base = data->MmioAddress; - - spin_lock_init(&(data->Lock)); - - snprintf(data->nspinfo, - sizeof(data->nspinfo), - "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d", - host->io_port, host->io_port + host->n_io_port - 1, - host->base, - host->irq); - sht->name = data->nspinfo; - - nsp_dbg(NSP_DEBUG_INIT, "end"); - - - return host; /* detect done. */ -} - -/*----------------------------------------------------------------*/ -/* return info string */ -/*----------------------------------------------------------------*/ -static const char *nsp_info(struct Scsi_Host *shpnt) -{ - nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata; - - return data->nspinfo; -} - -#undef SPRINTF -#define SPRINTF(args...) \ - do { \ - if(length > (pos - buffer)) { \ - pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \ - nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length, length - (pos - buffer));\ - } \ - } while(0) - -static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start, - off_t offset, int length, int inout) -{ - int id; - char *pos = buffer; - int thislength; - int speed; - unsigned long flags; - nsp_hw_data *data; - int hostno; - - if (inout) { - return -EINVAL; - } - - hostno = host->host_no; - data = (nsp_hw_data *)host->hostdata; - - - SPRINTF("NinjaSCSI status\n\n"); - SPRINTF("Driver version: $Revision: 1.23 $\n"); - SPRINTF("SCSI host No.: %d\n", hostno); - SPRINTF("IRQ: %d\n", host->irq); - SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); - SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1); - SPRINTF("sg_tablesize: %d\n", host->sg_tablesize); - - SPRINTF("burst transfer mode: "); - switch (nsp_burst_mode) { - case BURST_IO8: - SPRINTF("io8"); - break; - case BURST_IO32: - SPRINTF("io32"); - break; - case BURST_MEM32: - SPRINTF("mem32"); - break; - default: - SPRINTF("???"); - break; - } - SPRINTF("\n"); - - - spin_lock_irqsave(&(data->Lock), flags); - SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC); - spin_unlock_irqrestore(&(data->Lock), flags); - - SPRINTF("SDTR status\n"); - for(id = 0; id < ARRAY_SIZE(data->Sync); id++) { - - SPRINTF("id %d: ", id); - - if (id == host->this_id) { - SPRINTF("----- NinjaSCSI-3 host adapter\n"); - continue; - } - - switch(data->Sync[id].SyncNegotiation) { - case SYNC_OK: - SPRINTF(" sync"); - break; - case SYNC_NG: - SPRINTF("async"); - break; - case SYNC_NOT_YET: - SPRINTF(" none"); - break; - default: - SPRINTF("?????"); - break; - } - - if (data->Sync[id].SyncPeriod != 0) { - speed = 1000000 / (data->Sync[id].SyncPeriod * 4); - - SPRINTF(" transfer %d.%dMB/s, offset %d", - speed / 1000, - speed % 1000, - data->Sync[id].SyncOffset - ); - } - SPRINTF("\n"); - } - - thislength = pos - (buffer + offset); - - if(thislength < 0) { - *start = NULL; - return 0; - } - - - thislength = min(thislength, length); - *start = buffer + offset; - - return thislength; -} -#undef SPRINTF - -/*---------------------------------------------------------------*/ -/* error handler */ -/*---------------------------------------------------------------*/ - -/* -static int nsp_eh_abort(struct scsi_cmnd *SCpnt) -{ - nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); - - return nsp_eh_bus_reset(SCpnt); -}*/ - -static int nsp_bus_reset(nsp_hw_data *data) -{ - unsigned int base = data->BaseAddress; - int i; - - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK); - - nsp_index_write(base, SCSIBUSCTRL, SCSI_RST); - mdelay(100); /* 100ms */ - nsp_index_write(base, SCSIBUSCTRL, 0); - for(i = 0; i < 5; i++) { - nsp_index_read(base, IRQPHASESENCE); /* dummy read */ - } - - nsphw_init_sync(data); - - nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR); - - return SUCCESS; -} - -static int nsp_eh_bus_reset(struct scsi_cmnd *SCpnt) -{ - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - - nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt); - - return nsp_bus_reset(data); -} - -static int nsp_eh_host_reset(struct scsi_cmnd *SCpnt) -{ - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - - nsp_dbg(NSP_DEBUG_BUSRESET, "in"); - - nsphw_init(data); - - return SUCCESS; -} - - -/********************************************************************** - PCMCIA functions -**********************************************************************/ - -static int nsp_cs_probe(struct pcmcia_device *link) -{ - scsi_info_t *info; - nsp_hw_data *data = &nsp_data_base; - int ret; - - nsp_dbg(NSP_DEBUG_INIT, "in"); - - /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (info == NULL) { return -ENOMEM; } - info->p_dev = link; - link->priv = info; - data->ScsiInfo = info; - - nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info); - - ret = nsp_cs_config(link); - - nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); - return ret; -} /* nsp_cs_attach */ - - -static void nsp_cs_detach(struct pcmcia_device *link) -{ - nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link); - - ((scsi_info_t *)link->priv)->stop = 1; - nsp_cs_release(link); - - kfree(link->priv); - link->priv = NULL; -} /* nsp_cs_detach */ - - -static int nsp_cs_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - nsp_hw_data *data = priv_data; - - if (p_dev->config_index == 0) - return -ENODEV; - - /* This reserves IO space but doesn't actually enable it */ - if (pcmcia_request_io(p_dev) != 0) - goto next_entry; - - if (resource_size(p_dev->resource[2])) { - p_dev->resource[2]->flags |= (WIN_DATA_WIDTH_16 | - WIN_MEMORY_TYPE_CM | - WIN_ENABLE); - if (p_dev->resource[2]->end < 0x1000) - p_dev->resource[2]->end = 0x1000; - if (pcmcia_request_window(p_dev, p_dev->resource[2], 0) != 0) - goto next_entry; - if (pcmcia_map_mem_page(p_dev, p_dev->resource[2], - p_dev->card_addr) != 0) - goto next_entry; - - data->MmioAddress = (unsigned long) - ioremap_nocache(p_dev->resource[2]->start, - resource_size(p_dev->resource[2])); - data->MmioLength = resource_size(p_dev->resource[2]); - } - /* If we got this far, we're cool! */ - return 0; - -next_entry: - nsp_dbg(NSP_DEBUG_INIT, "next"); - pcmcia_disable_device(p_dev); - return -ENODEV; -} - -static int nsp_cs_config(struct pcmcia_device *link) -{ - int ret; - scsi_info_t *info = link->priv; - struct Scsi_Host *host; - nsp_hw_data *data = &nsp_data_base; - - nsp_dbg(NSP_DEBUG_INIT, "in"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_CHECK_VCC | - CONF_AUTO_SET_VPP | CONF_AUTO_AUDIO | CONF_AUTO_SET_IOMEM | - CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, nsp_cs_config_check, data); - if (ret) - goto cs_failed; - - if (pcmcia_request_irq(link, nspintr)) - goto cs_failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto cs_failed; - - if (free_ports) { - if (link->resource[0]) { - release_region(link->resource[0]->start, - resource_size(link->resource[0])); - } - if (link->resource[1]) { - release_region(link->resource[1]->start, - resource_size(link->resource[1])); - } - } - - /* Set port and IRQ */ - data->BaseAddress = link->resource[0]->start; - data->NumAddress = resource_size(link->resource[0]); - data->IrqNumber = link->irq; - - nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d", - data->BaseAddress, data->NumAddress, data->IrqNumber); - - if(nsphw_init(data) == FALSE) { - goto cs_failed; - } - - host = nsp_detect(&nsp_driver_template); - - if (host == NULL) { - nsp_dbg(NSP_DEBUG_INIT, "detect failed"); - goto cs_failed; - } - - - ret = scsi_add_host (host, NULL); - if (ret) - goto cs_failed; - - scsi_scan_host(host); - - info->host = host; - - return 0; - - cs_failed: - nsp_dbg(NSP_DEBUG_INIT, "config fail"); - nsp_cs_release(link); - - return -ENODEV; -} /* nsp_cs_config */ - - -static void nsp_cs_release(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - nsp_hw_data *data = NULL; - - if (info->host == NULL) { - nsp_msg(KERN_DEBUG, "unexpected card release call."); - } else { - data = (nsp_hw_data *)info->host->hostdata; - } - - nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link); - - /* Unlink the device chain */ - if (info->host != NULL) { - scsi_remove_host(info->host); - } - - if (resource_size(link->resource[2])) { - if (data != NULL) { - iounmap((void *)(data->MmioAddress)); - } - } - pcmcia_disable_device(link); - - if (info->host != NULL) { - scsi_host_put(info->host); - } -} /* nsp_cs_release */ - -static int nsp_cs_suspend(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - nsp_hw_data *data; - - nsp_dbg(NSP_DEBUG_INIT, "event: suspend"); - - if (info->host != NULL) { - nsp_msg(KERN_INFO, "clear SDTR status"); - - data = (nsp_hw_data *)info->host->hostdata; - - nsphw_init_sync(data); - } - - info->stop = 1; - - return 0; -} - -static int nsp_cs_resume(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - nsp_hw_data *data; - - nsp_dbg(NSP_DEBUG_INIT, "event: resume"); - - info->stop = 0; - - if (info->host != NULL) { - nsp_msg(KERN_INFO, "reset host and bus"); - - data = (nsp_hw_data *)info->host->hostdata; - - nsphw_init (data); - nsp_bus_reset(data); - } - - return 0; -} - -/*======================================================================* - * module entry point - *====================================================================*/ -static const struct pcmcia_device_id nsp_cs_ids[] = { - PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a), - PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a), - PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a), - PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a), - PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a), - PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e), - PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a), - PCMCIA_DEVICE_NULL -}; -MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids); - -static struct pcmcia_driver nsp_driver = { - .owner = THIS_MODULE, - .name = "nsp_cs", - .probe = nsp_cs_probe, - .remove = nsp_cs_detach, - .id_table = nsp_cs_ids, - .suspend = nsp_cs_suspend, - .resume = nsp_cs_resume, -}; - -static int __init nsp_cs_init(void) -{ - return pcmcia_register_driver(&nsp_driver); -} - -static void __exit nsp_cs_exit(void) -{ - pcmcia_unregister_driver(&nsp_driver); -} - - -module_init(nsp_cs_init) -module_exit(nsp_cs_exit) - -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.h b/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.h deleted file mode 100644 index 7fc9a9d0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_cs.h +++ /dev/null @@ -1,397 +0,0 @@ -/*=======================================================/ - Header file for nsp_cs.c - By: YOKOTA Hiroshi - - Ver.1.0 : Cut unused lines. - Ver 0.1 : Initial version. - - This software may be used and distributed according to the terms of - the GNU General Public License. - -=========================================================*/ - -#ifndef __nsp_cs__ -#define __nsp_cs__ - -/* for debugging */ -//#define NSP_DEBUG 9 - -/* -#define static -#define inline -*/ - -/************************************ - * Some useful macros... - */ - -/* SCSI initiator must be ID 7 */ -#define NSP_INITIATOR_ID 7 - -#define NSP_SELTIMEOUT 200 - -/*************************************************************************** - * register definitions - ***************************************************************************/ -/*======================================================================== - * base register - ========================================================================*/ -#define IRQCONTROL 0x00 /* R */ -# define IRQCONTROL_RESELECT_CLEAR BIT(0) -# define IRQCONTROL_PHASE_CHANGE_CLEAR BIT(1) -# define IRQCONTROL_TIMER_CLEAR BIT(2) -# define IRQCONTROL_FIFO_CLEAR BIT(3) -# define IRQCONTROL_ALLMASK 0xff -# define IRQCONTROL_ALLCLEAR (IRQCONTROL_RESELECT_CLEAR | \ - IRQCONTROL_PHASE_CHANGE_CLEAR | \ - IRQCONTROL_TIMER_CLEAR | \ - IRQCONTROL_FIFO_CLEAR ) -# define IRQCONTROL_IRQDISABLE 0xf0 - -#define IRQSTATUS 0x00 /* W */ -# define IRQSTATUS_SCSI BIT(0) -# define IRQSTATUS_TIMER BIT(2) -# define IRQSTATUS_FIFO BIT(3) -# define IRQSTATUS_MASK 0x0f - -#define IFSELECT 0x01 /* W */ -# define IF_IFSEL BIT(0) -# define IF_REGSEL BIT(2) - -#define FIFOSTATUS 0x01 /* R */ -# define FIFOSTATUS_CHIP_REVISION_MASK 0x0f -# define FIFOSTATUS_CHIP_ID_MASK 0x70 -# define FIFOSTATUS_FULL_EMPTY BIT(7) - -#define INDEXREG 0x02 /* R/W */ -#define DATAREG 0x03 /* R/W */ -#define FIFODATA 0x04 /* R/W */ -#define FIFODATA1 0x05 /* R/W */ -#define FIFODATA2 0x06 /* R/W */ -#define FIFODATA3 0x07 /* R/W */ - -/*==================================================================== - * indexed register - ====================================================================*/ -#define EXTBUSCTRL 0x10 /* R/W,deleted */ - -#define CLOCKDIV 0x11 /* R/W */ -# define CLOCK_40M 0x02 -# define CLOCK_20M 0x01 -# define FAST_20 BIT(2) - -#define TERMPWRCTRL 0x13 /* R/W */ -# define POWER_ON BIT(0) - -#define SCSIIRQMODE 0x15 /* R/W */ -# define SCSI_PHASE_CHANGE_EI BIT(0) -# define RESELECT_EI BIT(4) -# define FIFO_IRQ_EI BIT(5) -# define SCSI_RESET_IRQ_EI BIT(6) - -#define IRQPHASESENCE 0x16 /* R */ -# define LATCHED_MSG BIT(0) -# define LATCHED_IO BIT(1) -# define LATCHED_CD BIT(2) -# define LATCHED_BUS_FREE BIT(3) -# define PHASE_CHANGE_IRQ BIT(4) -# define RESELECT_IRQ BIT(5) -# define FIFO_IRQ BIT(6) -# define SCSI_RESET_IRQ BIT(7) - -#define TIMERCOUNT 0x17 /* R/W */ - -#define SCSIBUSCTRL 0x18 /* R/W */ -# define SCSI_SEL BIT(0) -# define SCSI_RST BIT(1) -# define SCSI_DATAOUT_ENB BIT(2) -# define SCSI_ATN BIT(3) -# define SCSI_ACK BIT(4) -# define SCSI_BSY BIT(5) -# define AUTODIRECTION BIT(6) -# define ACKENB BIT(7) - -#define SCSIBUSMON 0x19 /* R */ - -#define SETARBIT 0x1A /* W */ -# define ARBIT_GO BIT(0) -# define ARBIT_FLAG_CLEAR BIT(1) - -#define ARBITSTATUS 0x1A /* R */ -/*# define ARBIT_GO BIT(0)*/ -# define ARBIT_WIN BIT(1) -# define ARBIT_FAIL BIT(2) -# define RESELECT_FLAG BIT(3) - -#define PARITYCTRL 0x1B /* W */ -#define PARITYSTATUS 0x1B /* R */ - -#define COMMANDCTRL 0x1C /* W */ -# define CLEAR_COMMAND_POINTER BIT(0) -# define AUTO_COMMAND_GO BIT(1) - -#define RESELECTID 0x1C /* R */ -#define COMMANDDATA 0x1D /* R/W */ - -#define POINTERCLR 0x1E /* W */ -# define POINTER_CLEAR BIT(0) -# define ACK_COUNTER_CLEAR BIT(1) -# define REQ_COUNTER_CLEAR BIT(2) -# define HOST_COUNTER_CLEAR BIT(3) -# define READ_SOURCE (BIT(4) | BIT(5)) -# define ACK_COUNTER (0) -# define REQ_COUNTER (BIT(4)) -# define HOST_COUNTER (BIT(5)) - -#define TRANSFERCOUNT 0x1E /* R */ - -#define TRANSFERMODE 0x20 /* R/W */ -# define MODE_MEM8 BIT(0) -# define MODE_MEM32 BIT(1) -# define MODE_ADR24 BIT(2) -# define MODE_ADR32 BIT(3) -# define MODE_IO8 BIT(4) -# define MODE_IO32 BIT(5) -# define TRANSFER_GO BIT(6) -# define BRAIND BIT(7) - -#define SYNCREG 0x21 /* R/W */ -# define SYNCREG_OFFSET_MASK 0x0f -# define SYNCREG_PERIOD_MASK 0xf0 -# define SYNCREG_PERIOD_SHIFT 4 - -#define SCSIDATALATCH 0x22 /* W */ -#define SCSIDATAIN 0x22 /* R */ -#define SCSIDATAWITHACK 0x23 /* R/W */ -#define SCAMCONTROL 0x24 /* W */ -#define SCAMSTATUS 0x24 /* R */ -#define SCAMDATA 0x25 /* R/W */ - -#define OTHERCONTROL 0x26 /* R/W */ -# define TPL_ROM_WRITE_EN BIT(0) -# define TPWR_OUT BIT(1) -# define TPWR_SENSE BIT(2) -# define RA8_CONTROL BIT(3) - -#define ACKWIDTH 0x27 /* R/W */ -#define CLRTESTPNT 0x28 /* W */ -#define ACKCNTLD 0x29 /* W */ -#define REQCNTLD 0x2A /* W */ -#define HSTCNTLD 0x2B /* W */ -#define CHECKSUM 0x2C /* R/W */ - -/************************************************************************ - * Input status bit definitions. - ************************************************************************/ -#define S_MESSAGE BIT(0) /* Message line from SCSI bus */ -#define S_IO BIT(1) /* Input/Output line from SCSI bus */ -#define S_CD BIT(2) /* Command/Data line from SCSI bus */ -#define S_BUSY BIT(3) /* Busy line from SCSI bus */ -#define S_ACK BIT(4) /* Acknowledge line from SCSI bus */ -#define S_REQUEST BIT(5) /* Request line from SCSI bus */ -#define S_SELECT BIT(6) /* */ -#define S_ATN BIT(7) /* */ - -/*********************************************************************** - * Useful Bus Monitor status combinations. - ***********************************************************************/ -#define BUSMON_SEL S_SELECT -#define BUSMON_BSY S_BUSY -#define BUSMON_REQ S_REQUEST -#define BUSMON_IO S_IO -#define BUSMON_ACK S_ACK -#define BUSMON_BUS_FREE 0 -#define BUSMON_COMMAND ( S_BUSY | S_CD | S_REQUEST ) -#define BUSMON_MESSAGE_IN ( S_BUSY | S_CD | S_IO | S_MESSAGE | S_REQUEST ) -#define BUSMON_MESSAGE_OUT ( S_BUSY | S_CD | S_MESSAGE | S_REQUEST ) -#define BUSMON_DATA_IN ( S_BUSY | S_IO | S_REQUEST ) -#define BUSMON_DATA_OUT ( S_BUSY | S_REQUEST ) -#define BUSMON_STATUS ( S_BUSY | S_CD | S_IO | S_REQUEST ) -#define BUSMON_SELECT ( S_IO | S_SELECT ) -#define BUSMON_RESELECT ( S_IO | S_SELECT ) -#define BUSMON_PHASE_MASK ( S_CD | S_IO | S_MESSAGE | S_SELECT ) - -#define BUSPHASE_SELECT ( BUSMON_SELECT & BUSMON_PHASE_MASK ) -#define BUSPHASE_COMMAND ( BUSMON_COMMAND & BUSMON_PHASE_MASK ) -#define BUSPHASE_MESSAGE_IN ( BUSMON_MESSAGE_IN & BUSMON_PHASE_MASK ) -#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK ) -#define BUSPHASE_DATA_IN ( BUSMON_DATA_IN & BUSMON_PHASE_MASK ) -#define BUSPHASE_DATA_OUT ( BUSMON_DATA_OUT & BUSMON_PHASE_MASK ) -#define BUSPHASE_STATUS ( BUSMON_STATUS & BUSMON_PHASE_MASK ) - -/*====================================================================*/ - -typedef struct scsi_info_t { - struct pcmcia_device *p_dev; - struct Scsi_Host *host; - int stop; -} scsi_info_t; - - -/* synchronous transfer negotiation data */ -typedef struct _sync_data { - unsigned int SyncNegotiation; -#define SYNC_NOT_YET 0 -#define SYNC_OK 1 -#define SYNC_NG 2 - - unsigned int SyncPeriod; - unsigned int SyncOffset; - unsigned char SyncRegister; - unsigned char AckWidth; -} sync_data; - -typedef struct _nsp_hw_data { - unsigned int BaseAddress; - unsigned int NumAddress; - unsigned int IrqNumber; - - unsigned long MmioAddress; -#define NSP_MMIO_OFFSET 0x0800 - unsigned long MmioLength; - - unsigned char ScsiClockDiv; - - unsigned char TransferMode; - - int TimerCount; - int SelectionTimeOut; - struct scsi_cmnd *CurrentSC; - //int CurrnetTarget; - - int FifoCount; - -#define MSGBUF_SIZE 20 - unsigned char MsgBuffer[MSGBUF_SIZE]; - int MsgLen; - -#define N_TARGET 8 - sync_data Sync[N_TARGET]; - - char nspinfo[110]; /* description */ - spinlock_t Lock; - - scsi_info_t *ScsiInfo; /* attach <-> detect glue */ - - -#ifdef NSP_DEBUG - int CmdId; /* Accepted command serial number. - Used for debugging. */ -#endif -} nsp_hw_data; - -/**************************************************************************** - * - */ - -/* Card service functions */ -static void nsp_cs_detach (struct pcmcia_device *p_dev); -static void nsp_cs_release(struct pcmcia_device *link); -static int nsp_cs_config (struct pcmcia_device *link); - -/* Linux SCSI subsystem specific functions */ -static struct Scsi_Host *nsp_detect (struct scsi_host_template *sht); -static const char *nsp_info (struct Scsi_Host *shpnt); -static int nsp_proc_info ( - struct Scsi_Host *host, - char *buffer, - char **start, - off_t offset, - int length, - int inout); -static int nsp_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *SCpnt); - -/* Error handler */ -/*static int nsp_eh_abort (struct scsi_cmnd *SCpnt);*/ -/*static int nsp_eh_device_reset(struct scsi_cmnd *SCpnt);*/ -static int nsp_eh_bus_reset (struct scsi_cmnd *SCpnt); -static int nsp_eh_host_reset (struct scsi_cmnd *SCpnt); -static int nsp_bus_reset (nsp_hw_data *data); - -/* */ -static int nsphw_init (nsp_hw_data *data); -static int nsphw_start_selection(struct scsi_cmnd *SCpnt); -static void nsp_start_timer (struct scsi_cmnd *SCpnt, int time); -static int nsp_fifo_count (struct scsi_cmnd *SCpnt); -static void nsp_pio_read (struct scsi_cmnd *SCpnt); -static void nsp_pio_write (struct scsi_cmnd *SCpnt); -static int nsp_nexus (struct scsi_cmnd *SCpnt); -static void nsp_scsi_done (struct scsi_cmnd *SCpnt); -static int nsp_analyze_sdtr (struct scsi_cmnd *SCpnt); -static int nsp_negate_signal (struct scsi_cmnd *SCpnt, - unsigned char mask, char *str); -static int nsp_expect_signal (struct scsi_cmnd *SCpnt, - unsigned char current_phase, - unsigned char mask); -static int nsp_xfer (struct scsi_cmnd *SCpnt, int phase); -static int nsp_dataphase_bypass (struct scsi_cmnd *SCpnt); -static int nsp_reselected (struct scsi_cmnd *SCpnt); -static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht); - -/* Interrupt handler */ -//static irqreturn_t nspintr(int irq, void *dev_id); - -/* Module entry point*/ -static int __init nsp_cs_init(void); -static void __exit nsp_cs_exit(void); - -/* Debug */ -#ifdef NSP_DEBUG -static void show_command (struct scsi_cmnd *SCpnt); -static void show_phase (struct scsi_cmnd *SCpnt); -static void show_busphase(unsigned char stat); -static void show_message (nsp_hw_data *data); -#else -# define show_command(ptr) /* */ -# define show_phase(SCpnt) /* */ -# define show_busphase(stat) /* */ -# define show_message(data) /* */ -#endif - -/* - * SCSI phase - */ -enum _scsi_phase { - PH_UNDETERMINED , - PH_ARBSTART , - PH_SELSTART , - PH_SELECTED , - PH_COMMAND , - PH_DATA , - PH_STATUS , - PH_MSG_IN , - PH_MSG_OUT , - PH_DISCONNECT , - PH_RESELECT , - PH_ABORT , - PH_RESET -}; - -enum _data_in_out { - IO_UNKNOWN, - IO_IN, - IO_OUT -}; - -enum _burst_mode { - BURST_IO8 = 0, - BURST_IO32 = 1, - BURST_MEM32 = 2, -}; - -/************************************************************************** - * SCSI messaage - */ -#define MSG_COMMAND_COMPLETE 0x00 -#define MSG_EXTENDED 0x01 -#define MSG_ABORT 0x06 -#define MSG_NO_OPERATION 0x08 -#define MSG_BUS_DEVICE_RESET 0x0c - -#define MSG_EXT_SDTR 0x01 - -/* scatter-gather table */ -# define BUFFER_ADDR ((char *)((sg_virt(SCpnt->SCp.buffer)))) - -#endif /*__nsp_cs__*/ -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_debug.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_debug.c deleted file mode 100644 index 6aa7d269..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_debug.c +++ /dev/null @@ -1,215 +0,0 @@ -/*======================================================================== - Debug routines for nsp_cs - By: YOKOTA Hiroshi - - This software may be used and distributed according to the terms of - the GNU General Public License. -=========================================================================*/ - -/* $Id: nsp_debug.c,v 1.3 2003/07/26 14:21:09 elca Exp $ */ - -/* - * Show the command data of a command - */ -static const char unknown[] = "UNKNOWN"; - -static const char * group_0_commands[] = { -/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", -/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reassign Blocks", -/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, -/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", -/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", -/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", -/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", -/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, -}; - - -static const char *group_1_commands[] = { -/* 20-22 */ unknown, unknown, unknown, -/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", -/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, -/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", -/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", -/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data", -/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer", -/* 3d-3f */ "Update Block", "Read Long", "Write Long", -}; - - -static const char *group_2_commands[] = { -/* 40-41 */ "Change Definition", "Write Same", -/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", -/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown, -/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", -/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, -/* 5c-5f */ unknown, unknown, unknown, -}; - -#define group(opcode) (((opcode) >> 5) & 7) - -#define RESERVED_GROUP 0 -#define VENDOR_GROUP 1 -#define NOTEXT_GROUP 2 - -static const char **commands[] = { - group_0_commands, group_1_commands, group_2_commands, - (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, - (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, - (const char **) VENDOR_GROUP -}; - -static const char reserved[] = "RESERVED"; -static const char vendor[] = "VENDOR SPECIFIC"; - -static void print_opcodek(unsigned char opcode) -{ - const char **table = commands[ group(opcode) ]; - - switch ((unsigned long) table) { - case RESERVED_GROUP: - printk("%s[%02x] ", reserved, opcode); - break; - case NOTEXT_GROUP: - printk("%s(notext)[%02x] ", unknown, opcode); - break; - case VENDOR_GROUP: - printk("%s[%02x] ", vendor, opcode); - break; - default: - if (table[opcode & 0x1f] != unknown) - printk("%s[%02x] ", table[opcode & 0x1f], opcode); - else - printk("%s[%02x] ", unknown, opcode); - break; - } -} - -static void print_commandk (unsigned char *command) -{ - int i, s; - printk(KERN_DEBUG); - print_opcodek(command[0]); - /*printk(KERN_DEBUG "%s ", __func__);*/ - if ((command[0] >> 5) == 6 || - (command[0] >> 5) == 7 ) { - s = 12; /* vender specific */ - } else { - s = COMMAND_SIZE(command[0]); - } - for ( i = 1; i < s; ++i) { - printk("%02x ", command[i]); - } - - switch (s) { - case 6: - printk("LBA=%d len=%d", - (((unsigned int)command[1] & 0x0f) << 16) | - ( (unsigned int)command[2] << 8) | - ( (unsigned int)command[3] ), - (unsigned int)command[4] - ); - break; - case 10: - printk("LBA=%d len=%d", - ((unsigned int)command[2] << 24) | - ((unsigned int)command[3] << 16) | - ((unsigned int)command[4] << 8) | - ((unsigned int)command[5] ), - ((unsigned int)command[7] << 8) | - ((unsigned int)command[8] ) - ); - break; - case 12: - printk("LBA=%d len=%d", - ((unsigned int)command[2] << 24) | - ((unsigned int)command[3] << 16) | - ((unsigned int)command[4] << 8) | - ((unsigned int)command[5] ), - ((unsigned int)command[6] << 24) | - ((unsigned int)command[7] << 16) | - ((unsigned int)command[8] << 8) | - ((unsigned int)command[9] ) - ); - break; - default: - break; - } - printk("\n"); -} - -static void show_command(struct scsi_cmnd *SCpnt) -{ - print_commandk(SCpnt->cmnd); -} - -static void show_phase(struct scsi_cmnd *SCpnt) -{ - int i = SCpnt->SCp.phase; - - char *ph[] = { - "PH_UNDETERMINED", - "PH_ARBSTART", - "PH_SELSTART", - "PH_SELECTED", - "PH_COMMAND", - "PH_DATA", - "PH_STATUS", - "PH_MSG_IN", - "PH_MSG_OUT", - "PH_DISCONNECT", - "PH_RESELECT" - }; - - if ( i < PH_UNDETERMINED || i > PH_RESELECT ) { - printk(KERN_DEBUG "scsi phase: unknown(%d)\n", i); - return; - } - - printk(KERN_DEBUG "scsi phase: %s\n", ph[i]); - - return; -} - -static void show_busphase(unsigned char stat) -{ - switch(stat) { - case BUSPHASE_COMMAND: - printk(KERN_DEBUG "BUSPHASE_COMMAND\n"); - break; - case BUSPHASE_MESSAGE_IN: - printk(KERN_DEBUG "BUSPHASE_MESSAGE_IN\n"); - break; - case BUSPHASE_MESSAGE_OUT: - printk(KERN_DEBUG "BUSPHASE_MESSAGE_OUT\n"); - break; - case BUSPHASE_DATA_IN: - printk(KERN_DEBUG "BUSPHASE_DATA_IN\n"); - break; - case BUSPHASE_DATA_OUT: - printk(KERN_DEBUG "BUSPHASE_DATA_OUT\n"); - break; - case BUSPHASE_STATUS: - printk(KERN_DEBUG "BUSPHASE_STATUS\n"); - break; - case BUSPHASE_SELECT: - printk(KERN_DEBUG "BUSPHASE_SELECT\n"); - break; - default: - printk(KERN_DEBUG "BUSPHASE_other\n"); - break; - } -} - -static void show_message(nsp_hw_data *data) -{ - int i; - - printk(KERN_DEBUG "msg:"); - for(i=0; i < data->MsgLen; i++) { - printk(" %02x", data->MsgBuffer[i]); - } - printk("\n"); -} - -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_io.h b/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_io.h deleted file mode 100644 index 3b8746f8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_io.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - NinjaSCSI I/O funtions - By: YOKOTA Hiroshi - - This software may be used and distributed according to the terms of - the GNU General Public License. - - */ - -/* $Id: nsp_io.h,v 1.3 2003/08/04 21:15:26 elca Exp $ */ - -#ifndef __NSP_IO_H__ -#define __NSP_IO_H__ - -static inline void nsp_write(unsigned int base, - unsigned int index, - unsigned char val); -static inline unsigned char nsp_read(unsigned int base, - unsigned int index); -static inline void nsp_index_write(unsigned int BaseAddr, - unsigned int Register, - unsigned char Value); -static inline unsigned char nsp_index_read(unsigned int BaseAddr, - unsigned int Register); - -/******************************************************************* - * Basic IO - */ - -static inline void nsp_write(unsigned int base, - unsigned int index, - unsigned char val) -{ - outb(val, (base + index)); -} - -static inline unsigned char nsp_read(unsigned int base, - unsigned int index) -{ - return inb(base + index); -} - - -/********************************************************************** - * Indexed IO - */ -static inline unsigned char nsp_index_read(unsigned int BaseAddr, - unsigned int Register) -{ - outb(Register, BaseAddr + INDEXREG); - return inb(BaseAddr + DATAREG); -} - -static inline void nsp_index_write(unsigned int BaseAddr, - unsigned int Register, - unsigned char Value) -{ - outb(Register, BaseAddr + INDEXREG); - outb(Value, BaseAddr + DATAREG); -} - -/********************************************************************* - * fifo func - */ - -/* read 8 bit FIFO */ -static inline void nsp_multi_read_1(unsigned int BaseAddr, - unsigned int Register, - void *buf, - unsigned long count) -{ - insb(BaseAddr + Register, buf, count); -} - -static inline void nsp_fifo8_read(unsigned int base, - void *buf, - unsigned long count) -{ - /*nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx", buf, count);*/ - nsp_multi_read_1(base, FIFODATA, buf, count); -} - -/*--------------------------------------------------------------*/ - -/* read 16 bit FIFO */ -static inline void nsp_multi_read_2(unsigned int BaseAddr, - unsigned int Register, - void *buf, - unsigned long count) -{ - insw(BaseAddr + Register, buf, count); -} - -static inline void nsp_fifo16_read(unsigned int base, - void *buf, - unsigned long count) -{ - //nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*2", buf, count); - nsp_multi_read_2(base, FIFODATA, buf, count); -} - -/*--------------------------------------------------------------*/ - -/* read 32bit FIFO */ -static inline void nsp_multi_read_4(unsigned int BaseAddr, - unsigned int Register, - void *buf, - unsigned long count) -{ - insl(BaseAddr + Register, buf, count); -} - -static inline void nsp_fifo32_read(unsigned int base, - void *buf, - unsigned long count) -{ - //nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count); - nsp_multi_read_4(base, FIFODATA, buf, count); -} - -/*----------------------------------------------------------*/ - -/* write 8bit FIFO */ -static inline void nsp_multi_write_1(unsigned int BaseAddr, - unsigned int Register, - void *buf, - unsigned long count) -{ - outsb(BaseAddr + Register, buf, count); -} - -static inline void nsp_fifo8_write(unsigned int base, - void *buf, - unsigned long count) -{ - nsp_multi_write_1(base, FIFODATA, buf, count); -} - -/*---------------------------------------------------------*/ - -/* write 16bit FIFO */ -static inline void nsp_multi_write_2(unsigned int BaseAddr, - unsigned int Register, - void *buf, - unsigned long count) -{ - outsw(BaseAddr + Register, buf, count); -} - -static inline void nsp_fifo16_write(unsigned int base, - void *buf, - unsigned long count) -{ - nsp_multi_write_2(base, FIFODATA, buf, count); -} - -/*---------------------------------------------------------*/ - -/* write 32bit FIFO */ -static inline void nsp_multi_write_4(unsigned int BaseAddr, - unsigned int Register, - void *buf, - unsigned long count) -{ - outsl(BaseAddr + Register, buf, count); -} - -static inline void nsp_fifo32_write(unsigned int base, - void *buf, - unsigned long count) -{ - nsp_multi_write_4(base, FIFODATA, buf, count); -} - - -/*====================================================================*/ - -static inline void nsp_mmio_write(unsigned long base, - unsigned int index, - unsigned char val) -{ - unsigned char *ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + index); - - writeb(val, ptr); -} - -static inline unsigned char nsp_mmio_read(unsigned long base, - unsigned int index) -{ - unsigned char *ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + index); - - return readb(ptr); -} - -/*-----------*/ - -static inline unsigned char nsp_mmio_index_read(unsigned long base, - unsigned int reg) -{ - unsigned char *index_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + INDEXREG); - unsigned char *data_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + DATAREG); - - writeb((unsigned char)reg, index_ptr); - return readb(data_ptr); -} - -static inline void nsp_mmio_index_write(unsigned long base, - unsigned int reg, - unsigned char val) -{ - unsigned char *index_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + INDEXREG); - unsigned char *data_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + DATAREG); - - writeb((unsigned char)reg, index_ptr); - writeb(val, data_ptr); -} - -/* read 32bit FIFO */ -static inline void nsp_mmio_multi_read_4(unsigned long base, - unsigned int Register, - void *buf, - unsigned long count) -{ - unsigned long *ptr = (unsigned long *)(base + Register); - unsigned long *tmp = (unsigned long *)buf; - int i; - - //nsp_dbg(NSP_DEBUG_DATA_IO, "base 0x%0lx ptr 0x%p",base,ptr); - - for (i = 0; i < count; i++) { - *tmp = readl(ptr); - //nsp_dbg(NSP_DEBUG_DATA_IO, "<%d,%p,%p,%lx>", i, ptr, tmp, *tmp); - tmp++; - } -} - -static inline void nsp_mmio_fifo32_read(unsigned int base, - void *buf, - unsigned long count) -{ - //nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count); - nsp_mmio_multi_read_4(base, FIFODATA, buf, count); -} - -static inline void nsp_mmio_multi_write_4(unsigned long base, - unsigned int Register, - void *buf, - unsigned long count) -{ - unsigned long *ptr = (unsigned long *)(base + Register); - unsigned long *tmp = (unsigned long *)buf; - int i; - - //nsp_dbg(NSP_DEBUG_DATA_IO, "base 0x%0lx ptr 0x%p",base,ptr); - - for (i = 0; i < count; i++) { - writel(*tmp, ptr); - //nsp_dbg(NSP_DEBUG_DATA_IO, "<%d,%p,%p,%lx>", i, ptr, tmp, *tmp); - tmp++; - } -} - -static inline void nsp_mmio_fifo32_write(unsigned int base, - void *buf, - unsigned long count) -{ - //nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count); - nsp_mmio_multi_write_4(base, FIFODATA, buf, count); -} - - - -#endif -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_message.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_message.c deleted file mode 100644 index ef593b70..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/nsp_message.c +++ /dev/null @@ -1,78 +0,0 @@ -/*========================================================================== - NinjaSCSI-3 message handler - By: YOKOTA Hiroshi - - This software may be used and distributed according to the terms of - the GNU General Public License. - */ - -/* $Id: nsp_message.c,v 1.6 2003/07/26 14:21:09 elca Exp $ */ - -static void nsp_message_in(struct scsi_cmnd *SCpnt) -{ - unsigned int base = SCpnt->device->host->io_port; - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - unsigned char data_reg, control_reg; - int ret, len; - - /* - * XXX: NSP QUIRK - * NSP invoke interrupts only in the case of scsi phase changes, - * therefore we should poll the scsi phase here to catch - * the next "msg in" if exists (no scsi phase changes). - */ - ret = 16; - len = 0; - - nsp_dbg(NSP_DEBUG_MSGINOCCUR, "msgin loop"); - do { - /* read data */ - data_reg = nsp_index_read(base, SCSIDATAIN); - - /* assert ACK */ - control_reg = nsp_index_read(base, SCSIBUSCTRL); - control_reg |= SCSI_ACK; - nsp_index_write(base, SCSIBUSCTRL, control_reg); - nsp_negate_signal(SCpnt, BUSMON_REQ, "msgin"); - - data->MsgBuffer[len] = data_reg; len++; - - /* deassert ACK */ - control_reg = nsp_index_read(base, SCSIBUSCTRL); - control_reg &= ~SCSI_ACK; - nsp_index_write(base, SCSIBUSCTRL, control_reg); - - /* catch a next signal */ - ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_IN, BUSMON_REQ); - } while (ret > 0 && MSGBUF_SIZE > len); - - data->MsgLen = len; - -} - -static void nsp_message_out(struct scsi_cmnd *SCpnt) -{ - nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata; - int ret = 1; - int len = data->MsgLen; - - /* - * XXX: NSP QUIRK - * NSP invoke interrupts only in the case of scsi phase changes, - * therefore we should poll the scsi phase here to catch - * the next "msg out" if exists (no scsi phase changes). - */ - - nsp_dbg(NSP_DEBUG_MSGOUTOCCUR, "msgout loop"); - do { - if (nsp_xfer(SCpnt, BUSPHASE_MESSAGE_OUT)) { - nsp_msg(KERN_DEBUG, "msgout: xfer short"); - } - - /* catch a next signal */ - ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_OUT, BUSMON_REQ); - } while (ret > 0 && len-- > 0); - -} - -/* end */ diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/qlogic_stub.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/qlogic_stub.c deleted file mode 100644 index bcaf89fe..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/qlogic_stub.c +++ /dev/null @@ -1,318 +0,0 @@ -/*====================================================================== - - A driver for the Qlogic SCSI card - - qlogic_cs.c 1.79 2000/06/12 21:27:26 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - . Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include "../qlogicfas408.h" - -#include -#include -#include - -/* Set the following to 2 to use normal interrupt (active high/totempole- - * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open - * drain - */ -#define INT_TYPE 0 - -static char qlogic_name[] = "qlogic_cs"; - -static struct scsi_host_template qlogicfas_driver_template = { - .module = THIS_MODULE, - .name = qlogic_name, - .proc_name = qlogic_name, - .info = qlogicfas408_info, - .queuecommand = qlogicfas408_queuecommand, - .eh_abort_handler = qlogicfas408_abort, - .eh_bus_reset_handler = qlogicfas408_bus_reset, - .bios_param = qlogicfas408_biosparam, - .can_queue = 1, - .this_id = -1, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; - -/*====================================================================*/ - -typedef struct scsi_info_t { - struct pcmcia_device *p_dev; - struct Scsi_Host *host; - unsigned short manf_id; -} scsi_info_t; - -static void qlogic_release(struct pcmcia_device *link); -static void qlogic_detach(struct pcmcia_device *p_dev); -static int qlogic_config(struct pcmcia_device * link); - -static struct Scsi_Host *qlogic_detect(struct scsi_host_template *host, - struct pcmcia_device *link, int qbase, int qlirq) -{ - int qltyp; /* type of chip */ - int qinitid; - struct Scsi_Host *shost; /* registered host structure */ - struct qlogicfas408_priv *priv; - - qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE); - qinitid = host->this_id; - if (qinitid < 0) - qinitid = 7; /* if no ID, use 7 */ - - qlogicfas408_setup(qbase, qinitid, INT_TYPE); - - host->name = qlogic_name; - shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv)); - if (!shost) - goto err; - shost->io_port = qbase; - shost->n_io_port = 16; - shost->dma_channel = -1; - if (qlirq != -1) - shost->irq = qlirq; - - priv = get_priv_by_host(shost); - priv->qlirq = qlirq; - priv->qbase = qbase; - priv->qinitid = qinitid; - priv->shost = shost; - priv->int_type = INT_TYPE; - - if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost)) - goto free_scsi_host; - - sprintf(priv->qinfo, - "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", - qltyp, qbase, qlirq, QL_TURBO_PDMA); - - if (scsi_add_host(shost, NULL)) - goto free_interrupt; - - scsi_scan_host(shost); - - return shost; - -free_interrupt: - free_irq(qlirq, shost); - -free_scsi_host: - scsi_host_put(shost); - -err: - return NULL; -} -static int qlogic_probe(struct pcmcia_device *link) -{ - scsi_info_t *info; - - dev_dbg(&link->dev, "qlogic_attach()\n"); - - /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - info->p_dev = link; - link->priv = info; - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - link->config_regs = PRESENT_OPTION; - - return qlogic_config(link); -} /* qlogic_attach */ - -/*====================================================================*/ - -static void qlogic_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "qlogic_detach\n"); - - qlogic_release(link); - kfree(link->priv); - -} /* qlogic_detach */ - -/*====================================================================*/ - -static int qlogic_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->io_lines = 10; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if (p_dev->resource[0]->start == 0) - return -ENODEV; - - return pcmcia_request_io(p_dev); -} - -static int qlogic_config(struct pcmcia_device * link) -{ - scsi_info_t *info = link->priv; - int ret; - struct Scsi_Host *host; - - dev_dbg(&link->dev, "qlogic_config\n"); - - ret = pcmcia_loop_config(link, qlogic_config_check, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) { - /* set ATAcmd */ - outb(0xb4, link->resource[0]->start + 0xd); - outb(0x24, link->resource[0]->start + 0x9); - outb(0x04, link->resource[0]->start + 0xd); - } - - /* The KXL-810AN has a bigger IO port window */ - if (resource_size(link->resource[0]) == 32) - host = qlogic_detect(&qlogicfas_driver_template, link, - link->resource[0]->start + 16, link->irq); - else - host = qlogic_detect(&qlogicfas_driver_template, link, - link->resource[0]->start, link->irq); - - if (!host) { - printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name); - goto failed; - } - - info->host = host; - - return 0; - -failed: - pcmcia_disable_device(link); - return -ENODEV; -} /* qlogic_config */ - -/*====================================================================*/ - -static void qlogic_release(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - - dev_dbg(&link->dev, "qlogic_release\n"); - - scsi_remove_host(info->host); - - free_irq(link->irq, info->host); - pcmcia_disable_device(link); - - scsi_host_put(info->host); -} - -/*====================================================================*/ - -static int qlogic_resume(struct pcmcia_device *link) -{ - scsi_info_t *info = link->priv; - - pcmcia_enable_device(link); - if ((info->manf_id == MANFID_MACNICA) || - (info->manf_id == MANFID_PIONEER) || - (info->manf_id == 0x0098)) { - outb(0x80, link->resource[0]->start + 0xd); - outb(0x24, link->resource[0]->start + 0x9); - outb(0x04, link->resource[0]->start + 0xd); - } - /* Ugggglllyyyy!!! */ - qlogicfas408_bus_reset(NULL); - - return 0; -} - -static const struct pcmcia_device_id qlogic_ids[] = { - PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6), - PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751), - PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d), - PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79), - PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a), - PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7), - PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54), - PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec), - PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735), - PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8), - PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f), - PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1), - PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe), - PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0), - /* these conflict with other cards! */ - /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */ - /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */ - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, qlogic_ids); - -static struct pcmcia_driver qlogic_cs_driver = { - .owner = THIS_MODULE, - .name = "qlogic_cs", - .probe = qlogic_probe, - .remove = qlogic_detach, - .id_table = qlogic_ids, - .resume = qlogic_resume, -}; - -static int __init init_qlogic_cs(void) -{ - return pcmcia_register_driver(&qlogic_cs_driver); -} - -static void __exit exit_qlogic_cs(void) -{ - pcmcia_unregister_driver(&qlogic_cs_driver); -} - -MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); -MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers"); -MODULE_LICENSE("GPL"); -module_init(init_qlogic_cs); -module_exit(exit_qlogic_cs); diff --git a/ANDROID_3.4.5/drivers/scsi/pcmcia/sym53c500_cs.c b/ANDROID_3.4.5/drivers/scsi/pcmcia/sym53c500_cs.c deleted file mode 100644 index f5b52731..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pcmcia/sym53c500_cs.c +++ /dev/null @@ -1,898 +0,0 @@ -/* -* sym53c500_cs.c Bob Tracy (rct@frus.com) -* -* A rewrite of the pcmcia-cs add-on driver for newer (circa 1997) -* New Media Bus Toaster PCMCIA SCSI cards using the Symbios Logic -* 53c500 controller: intended for use with 2.6 and later kernels. -* The pcmcia-cs add-on version of this driver is not supported -* beyond 2.4. It consisted of three files with history/copyright -* information as follows: -* -* SYM53C500.h -* Bob Tracy (rct@frus.com) -* Original by Tom Corner (tcorner@via.at). -* Adapted from NCR53c406a.h which is Copyrighted (C) 1994 -* Normunds Saumanis (normunds@rx.tech.swh.lv) -* -* SYM53C500.c -* Bob Tracy (rct@frus.com) -* Original driver by Tom Corner (tcorner@via.at) was adapted -* from NCR53c406a.c which is Copyrighted (C) 1994, 1995, 1996 -* Normunds Saumanis (normunds@fi.ibm.com) -* -* sym53c500.c -* Bob Tracy (rct@frus.com) -* Original by Tom Corner (tcorner@via.at) was adapted from a -* driver for the Qlogic SCSI card written by -* David Hinds (dhinds@allegro.stanford.edu). -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2, or (at your option) any -* later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -*/ - -#define SYM53C500_DEBUG 0 -#define VERBOSE_SYM53C500_DEBUG 0 - -/* -* Set this to 0 if you encounter kernel lockups while transferring -* data in PIO mode. Note this can be changed via "sysfs". -*/ -#define USE_FAST_PIO 1 - -/* =============== End of user configurable parameters ============== */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - - -/* ================================================================== */ - -#define SYNC_MODE 0 /* Synchronous transfer mode */ - -/* Default configuration */ -#define C1_IMG 0x07 /* ID=7 */ -#define C2_IMG 0x48 /* FE SCSI2 */ -#define C3_IMG 0x20 /* CDB */ -#define C4_IMG 0x04 /* ANE */ -#define C5_IMG 0xa4 /* ? changed from b6= AA PI SIE POL */ -#define C7_IMG 0x80 /* added for SYM53C500 t. corner */ - -/* Hardware Registers: offsets from io_port (base) */ - -/* Control Register Set 0 */ -#define TC_LSB 0x00 /* transfer counter lsb */ -#define TC_MSB 0x01 /* transfer counter msb */ -#define SCSI_FIFO 0x02 /* scsi fifo register */ -#define CMD_REG 0x03 /* command register */ -#define STAT_REG 0x04 /* status register */ -#define DEST_ID 0x04 /* selection/reselection bus id */ -#define INT_REG 0x05 /* interrupt status register */ -#define SRTIMOUT 0x05 /* select/reselect timeout reg */ -#define SEQ_REG 0x06 /* sequence step register */ -#define SYNCPRD 0x06 /* synchronous transfer period */ -#define FIFO_FLAGS 0x07 /* indicates # of bytes in fifo */ -#define SYNCOFF 0x07 /* synchronous offset register */ -#define CONFIG1 0x08 /* configuration register */ -#define CLKCONV 0x09 /* clock conversion register */ -/* #define TESTREG 0x0A */ /* test mode register */ -#define CONFIG2 0x0B /* configuration 2 register */ -#define CONFIG3 0x0C /* configuration 3 register */ -#define CONFIG4 0x0D /* configuration 4 register */ -#define TC_HIGH 0x0E /* transfer counter high */ -/* #define FIFO_BOTTOM 0x0F */ /* reserve FIFO byte register */ - -/* Control Register Set 1 */ -/* #define JUMPER_SENSE 0x00 */ /* jumper sense port reg (r/w) */ -/* #define SRAM_PTR 0x01 */ /* SRAM address pointer reg (r/w) */ -/* #define SRAM_DATA 0x02 */ /* SRAM data register (r/w) */ -#define PIO_FIFO 0x04 /* PIO FIFO registers (r/w) */ -/* #define PIO_FIFO1 0x05 */ /* */ -/* #define PIO_FIFO2 0x06 */ /* */ -/* #define PIO_FIFO3 0x07 */ /* */ -#define PIO_STATUS 0x08 /* PIO status (r/w) */ -/* #define ATA_CMD 0x09 */ /* ATA command/status reg (r/w) */ -/* #define ATA_ERR 0x0A */ /* ATA features/error reg (r/w) */ -#define PIO_FLAG 0x0B /* PIO flag interrupt enable (r/w) */ -#define CONFIG5 0x09 /* configuration 5 register */ -/* #define SIGNATURE 0x0E */ /* signature register (r) */ -/* #define CONFIG6 0x0F */ /* configuration 6 register (r) */ -#define CONFIG7 0x0d - -/* select register set 0 */ -#define REG0(x) (outb(C4_IMG, (x) + CONFIG4)) -/* select register set 1 */ -#define REG1(x) outb(C7_IMG, (x) + CONFIG7); outb(C5_IMG, (x) + CONFIG5) - -#if SYM53C500_DEBUG -#define DEB(x) x -#else -#define DEB(x) -#endif - -#if VERBOSE_SYM53C500_DEBUG -#define VDEB(x) x -#else -#define VDEB(x) -#endif - -#define LOAD_DMA_COUNT(x, count) \ - outb(count & 0xff, (x) + TC_LSB); \ - outb((count >> 8) & 0xff, (x) + TC_MSB); \ - outb((count >> 16) & 0xff, (x) + TC_HIGH); - -/* Chip commands */ -#define DMA_OP 0x80 - -#define SCSI_NOP 0x00 -#define FLUSH_FIFO 0x01 -#define CHIP_RESET 0x02 -#define SCSI_RESET 0x03 -#define RESELECT 0x40 -#define SELECT_NO_ATN 0x41 -#define SELECT_ATN 0x42 -#define SELECT_ATN_STOP 0x43 -#define ENABLE_SEL 0x44 -#define DISABLE_SEL 0x45 -#define SELECT_ATN3 0x46 -#define RESELECT3 0x47 -#define TRANSFER_INFO 0x10 -#define INIT_CMD_COMPLETE 0x11 -#define MSG_ACCEPT 0x12 -#define TRANSFER_PAD 0x18 -#define SET_ATN 0x1a -#define RESET_ATN 0x1b -#define SEND_MSG 0x20 -#define SEND_STATUS 0x21 -#define SEND_DATA 0x22 -#define DISCONN_SEQ 0x23 -#define TERMINATE_SEQ 0x24 -#define TARG_CMD_COMPLETE 0x25 -#define DISCONN 0x27 -#define RECV_MSG 0x28 -#define RECV_CMD 0x29 -#define RECV_DATA 0x2a -#define RECV_CMD_SEQ 0x2b -#define TARGET_ABORT_DMA 0x04 - -/* ================================================================== */ - -struct scsi_info_t { - struct pcmcia_device *p_dev; - struct Scsi_Host *host; - unsigned short manf_id; -}; - -/* -* Repository for per-instance host data. -*/ -struct sym53c500_data { - struct scsi_cmnd *current_SC; - int fast_pio; -}; - -enum Phase { - idle, - data_out, - data_in, - command_ph, - status_ph, - message_out, - message_in -}; - -/* ================================================================== */ - -static void -chip_init(int io_port) -{ - REG1(io_port); - outb(0x01, io_port + PIO_STATUS); - outb(0x00, io_port + PIO_FLAG); - - outb(C4_IMG, io_port + CONFIG4); /* REG0(io_port); */ - outb(C3_IMG, io_port + CONFIG3); - outb(C2_IMG, io_port + CONFIG2); - outb(C1_IMG, io_port + CONFIG1); - - outb(0x05, io_port + CLKCONV); /* clock conversion factor */ - outb(0x9C, io_port + SRTIMOUT); /* Selection timeout */ - outb(0x05, io_port + SYNCPRD); /* Synchronous transfer period */ - outb(SYNC_MODE, io_port + SYNCOFF); /* synchronous mode */ -} - -static void -SYM53C500_int_host_reset(int io_port) -{ - outb(C4_IMG, io_port + CONFIG4); /* REG0(io_port); */ - outb(CHIP_RESET, io_port + CMD_REG); - outb(SCSI_NOP, io_port + CMD_REG); /* required after reset */ - outb(SCSI_RESET, io_port + CMD_REG); - chip_init(io_port); -} - -static __inline__ int -SYM53C500_pio_read(int fast_pio, int base, unsigned char *request, unsigned int reqlen) -{ - int i; - int len; /* current scsi fifo size */ - - REG1(base); - while (reqlen) { - i = inb(base + PIO_STATUS); - /* VDEB(printk("pio_status=%x\n", i)); */ - if (i & 0x80) - return 0; - - switch (i & 0x1e) { - default: - case 0x10: /* fifo empty */ - len = 0; - break; - case 0x0: - len = 1; - break; - case 0x8: /* fifo 1/3 full */ - len = 42; - break; - case 0xc: /* fifo 2/3 full */ - len = 84; - break; - case 0xe: /* fifo full */ - len = 128; - break; - } - - if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */ - return 0; - } - - if (len) { - if (len > reqlen) - len = reqlen; - - if (fast_pio && len > 3) { - insl(base + PIO_FIFO, request, len >> 2); - request += len & 0xfc; - reqlen -= len & 0xfc; - } else { - while (len--) { - *request++ = inb(base + PIO_FIFO); - reqlen--; - } - } - } - } - return 0; -} - -static __inline__ int -SYM53C500_pio_write(int fast_pio, int base, unsigned char *request, unsigned int reqlen) -{ - int i = 0; - int len; /* current scsi fifo size */ - - REG1(base); - while (reqlen && !(i & 0x40)) { - i = inb(base + PIO_STATUS); - /* VDEB(printk("pio_status=%x\n", i)); */ - if (i & 0x80) /* error */ - return 0; - - switch (i & 0x1e) { - case 0x10: - len = 128; - break; - case 0x0: - len = 84; - break; - case 0x8: - len = 42; - break; - case 0xc: - len = 1; - break; - default: - case 0xe: - len = 0; - break; - } - - if (len) { - if (len > reqlen) - len = reqlen; - - if (fast_pio && len > 3) { - outsl(base + PIO_FIFO, request, len >> 2); - request += len & 0xfc; - reqlen -= len & 0xfc; - } else { - while (len--) { - outb(*request++, base + PIO_FIFO); - reqlen--; - } - } - } - } - return 0; -} - -static irqreturn_t -SYM53C500_intr(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - DEB(unsigned char fifo_size;) - DEB(unsigned char seq_reg;) - unsigned char status, int_reg; - unsigned char pio_status; - int port_base = dev->io_port; - struct sym53c500_data *data = - (struct sym53c500_data *)dev->hostdata; - struct scsi_cmnd *curSC = data->current_SC; - int fast_pio = data->fast_pio; - - spin_lock_irqsave(dev->host_lock, flags); - - VDEB(printk("SYM53C500_intr called\n")); - - REG1(port_base); - pio_status = inb(port_base + PIO_STATUS); - REG0(port_base); - status = inb(port_base + STAT_REG); - DEB(seq_reg = inb(port_base + SEQ_REG)); - int_reg = inb(port_base + INT_REG); - DEB(fifo_size = inb(port_base + FIFO_FLAGS) & 0x1f); - -#if SYM53C500_DEBUG - printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", - status, seq_reg, int_reg, fifo_size); - printk(", pio=%02x\n", pio_status); -#endif /* SYM53C500_DEBUG */ - - if (int_reg & 0x80) { /* SCSI reset intr */ - DEB(printk("SYM53C500: reset intr received\n")); - curSC->result = DID_RESET << 16; - goto idle_out; - } - - if (pio_status & 0x80) { - printk("SYM53C500: Warning: PIO error!\n"); - curSC->result = DID_ERROR << 16; - goto idle_out; - } - - if (status & 0x20) { /* Parity error */ - printk("SYM53C500: Warning: parity error!\n"); - curSC->result = DID_PARITY << 16; - goto idle_out; - } - - if (status & 0x40) { /* Gross error */ - printk("SYM53C500: Warning: gross error!\n"); - curSC->result = DID_ERROR << 16; - goto idle_out; - } - - if (int_reg & 0x20) { /* Disconnect */ - DEB(printk("SYM53C500: disconnect intr received\n")); - if (curSC->SCp.phase != message_in) { /* Unexpected disconnect */ - curSC->result = DID_NO_CONNECT << 16; - } else { /* Command complete, return status and message */ - curSC->result = (curSC->SCp.Status & 0xff) - | ((curSC->SCp.Message & 0xff) << 8) | (DID_OK << 16); - } - goto idle_out; - } - - switch (status & 0x07) { /* scsi phase */ - case 0x00: /* DATA-OUT */ - if (int_reg & 0x10) { /* Target requesting info transfer */ - struct scatterlist *sg; - int i; - - curSC->SCp.phase = data_out; - VDEB(printk("SYM53C500: Data-Out phase\n")); - outb(FLUSH_FIFO, port_base + CMD_REG); - LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */ - outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG); - - scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) { - SYM53C500_pio_write(fast_pio, port_base, - sg_virt(sg), sg->length); - } - REG0(port_base); - } - break; - - case 0x01: /* DATA-IN */ - if (int_reg & 0x10) { /* Target requesting info transfer */ - struct scatterlist *sg; - int i; - - curSC->SCp.phase = data_in; - VDEB(printk("SYM53C500: Data-In phase\n")); - outb(FLUSH_FIFO, port_base + CMD_REG); - LOAD_DMA_COUNT(port_base, scsi_bufflen(curSC)); /* Max transfer size */ - outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG); - - scsi_for_each_sg(curSC, sg, scsi_sg_count(curSC), i) { - SYM53C500_pio_read(fast_pio, port_base, - sg_virt(sg), sg->length); - } - REG0(port_base); - } - break; - - case 0x02: /* COMMAND */ - curSC->SCp.phase = command_ph; - printk("SYM53C500: Warning: Unknown interrupt occurred in command phase!\n"); - break; - - case 0x03: /* STATUS */ - curSC->SCp.phase = status_ph; - VDEB(printk("SYM53C500: Status phase\n")); - outb(FLUSH_FIFO, port_base + CMD_REG); - outb(INIT_CMD_COMPLETE, port_base + CMD_REG); - break; - - case 0x04: /* Reserved */ - case 0x05: /* Reserved */ - printk("SYM53C500: WARNING: Reserved phase!!!\n"); - break; - - case 0x06: /* MESSAGE-OUT */ - DEB(printk("SYM53C500: Message-Out phase\n")); - curSC->SCp.phase = message_out; - outb(SET_ATN, port_base + CMD_REG); /* Reject the message */ - outb(MSG_ACCEPT, port_base + CMD_REG); - break; - - case 0x07: /* MESSAGE-IN */ - VDEB(printk("SYM53C500: Message-In phase\n")); - curSC->SCp.phase = message_in; - - curSC->SCp.Status = inb(port_base + SCSI_FIFO); - curSC->SCp.Message = inb(port_base + SCSI_FIFO); - - VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f)); - DEB(printk("Status = %02x Message = %02x\n", curSC->SCp.Status, curSC->SCp.Message)); - - if (curSC->SCp.Message == SAVE_POINTERS || curSC->SCp.Message == DISCONNECT) { - outb(SET_ATN, port_base + CMD_REG); /* Reject message */ - DEB(printk("Discarding SAVE_POINTERS message\n")); - } - outb(MSG_ACCEPT, port_base + CMD_REG); - break; - } -out: - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; - -idle_out: - curSC->SCp.phase = idle; - curSC->scsi_done(curSC); - goto out; -} - -static void -SYM53C500_release(struct pcmcia_device *link) -{ - struct scsi_info_t *info = link->priv; - struct Scsi_Host *shost = info->host; - - dev_dbg(&link->dev, "SYM53C500_release\n"); - - /* - * Do this before releasing/freeing resources. - */ - scsi_remove_host(shost); - - /* - * Interrupts getting hosed on card removal. Try - * the following code, mostly from qlogicfas.c. - */ - if (shost->irq) - free_irq(shost->irq, shost); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - - pcmcia_disable_device(link); - - scsi_host_put(shost); -} /* SYM53C500_release */ - -static const char* -SYM53C500_info(struct Scsi_Host *SChost) -{ - static char info_msg[256]; - struct sym53c500_data *data = - (struct sym53c500_data *)SChost->hostdata; - - DEB(printk("SYM53C500_info called\n")); - (void)snprintf(info_msg, sizeof(info_msg), - "SYM53C500 at 0x%lx, IRQ %d, %s PIO mode.", - SChost->io_port, SChost->irq, data->fast_pio ? "fast" : "slow"); - return (info_msg); -} - -static int -SYM53C500_queue_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) -{ - int i; - int port_base = SCpnt->device->host->io_port; - struct sym53c500_data *data = - (struct sym53c500_data *)SCpnt->device->host->hostdata; - - VDEB(printk("SYM53C500_queue called\n")); - - DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", - SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id, - SCpnt->device->lun, scsi_bufflen(SCpnt))); - - VDEB(for (i = 0; i < SCpnt->cmd_len; i++) - printk("cmd[%d]=%02x ", i, SCpnt->cmnd[i])); - VDEB(printk("\n")); - - data->current_SC = SCpnt; - data->current_SC->scsi_done = done; - data->current_SC->SCp.phase = command_ph; - data->current_SC->SCp.Status = 0; - data->current_SC->SCp.Message = 0; - - /* We are locked here already by the mid layer */ - REG0(port_base); - outb(scmd_id(SCpnt), port_base + DEST_ID); /* set destination */ - outb(FLUSH_FIFO, port_base + CMD_REG); /* reset the fifos */ - - for (i = 0; i < SCpnt->cmd_len; i++) { - outb(SCpnt->cmnd[i], port_base + SCSI_FIFO); - } - outb(SELECT_NO_ATN, port_base + CMD_REG); - - return 0; -} - -static DEF_SCSI_QCMD(SYM53C500_queue) - -static int -SYM53C500_host_reset(struct scsi_cmnd *SCpnt) -{ - int port_base = SCpnt->device->host->io_port; - - DEB(printk("SYM53C500_host_reset called\n")); - spin_lock_irq(SCpnt->device->host->host_lock); - SYM53C500_int_host_reset(port_base); - spin_unlock_irq(SCpnt->device->host->host_lock); - - return SUCCESS; -} - -static int -SYM53C500_biosparm(struct scsi_device *disk, - struct block_device *dev, - sector_t capacity, int *info_array) -{ - int size; - - DEB(printk("SYM53C500_biosparm called\n")); - - size = capacity; - info_array[0] = 64; /* heads */ - info_array[1] = 32; /* sectors */ - info_array[2] = size >> 11; /* cylinders */ - if (info_array[2] > 1024) { /* big disk */ - info_array[0] = 255; - info_array[1] = 63; - info_array[2] = size / (255 * 63); - } - return 0; -} - -static ssize_t -SYM53C500_show_pio(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *SHp = class_to_shost(dev); - struct sym53c500_data *data = - (struct sym53c500_data *)SHp->hostdata; - - return snprintf(buf, 4, "%d\n", data->fast_pio); -} - -static ssize_t -SYM53C500_store_pio(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int pio; - struct Scsi_Host *SHp = class_to_shost(dev); - struct sym53c500_data *data = - (struct sym53c500_data *)SHp->hostdata; - - pio = simple_strtoul(buf, NULL, 0); - if (pio == 0 || pio == 1) { - data->fast_pio = pio; - return count; - } - else - return -EINVAL; -} - -/* -* SCSI HBA device attributes we want to -* make available via sysfs. -*/ -static struct device_attribute SYM53C500_pio_attr = { - .attr = { - .name = "fast_pio", - .mode = (S_IRUGO | S_IWUSR), - }, - .show = SYM53C500_show_pio, - .store = SYM53C500_store_pio, -}; - -static struct device_attribute *SYM53C500_shost_attrs[] = { - &SYM53C500_pio_attr, - NULL, -}; - -/* -* scsi_host_template initializer -*/ -static struct scsi_host_template sym53c500_driver_template = { - .module = THIS_MODULE, - .name = "SYM53C500", - .info = SYM53C500_info, - .queuecommand = SYM53C500_queue, - .eh_host_reset_handler = SYM53C500_host_reset, - .bios_param = SYM53C500_biosparm, - .proc_name = "SYM53C500", - .can_queue = 1, - .this_id = 7, - .sg_tablesize = 32, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = SYM53C500_shost_attrs -}; - -static int SYM53C500_config_check(struct pcmcia_device *p_dev, void *priv_data) -{ - p_dev->io_lines = 10; - p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH; - p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO; - - if (p_dev->resource[0]->start == 0) - return -ENODEV; - - return pcmcia_request_io(p_dev); -} - -static int -SYM53C500_config(struct pcmcia_device *link) -{ - struct scsi_info_t *info = link->priv; - int ret; - int irq_level, port_base; - struct Scsi_Host *host; - struct scsi_host_template *tpnt = &sym53c500_driver_template; - struct sym53c500_data *data; - - dev_dbg(&link->dev, "SYM53C500_config\n"); - - info->manf_id = link->manf_id; - - ret = pcmcia_loop_config(link, SYM53C500_config_check, NULL); - if (ret) - goto failed; - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - /* - * That's the trouble with copying liberally from another driver. - * Some things probably aren't relevant, and I suspect this entire - * section dealing with manufacturer IDs can be scrapped. --rct - */ - if ((info->manf_id == MANFID_MACNICA) || - (info->manf_id == MANFID_PIONEER) || - (info->manf_id == 0x0098)) { - /* set ATAcmd */ - outb(0xb4, link->resource[0]->start + 0xd); - outb(0x24, link->resource[0]->start + 0x9); - outb(0x04, link->resource[0]->start + 0xd); - } - - /* - * irq_level == 0 implies tpnt->can_queue == 0, which - * is not supported in 2.6. Thus, only irq_level > 0 - * will be allowed. - * - * Possible port_base values are as follows: - * - * 0x130, 0x230, 0x280, 0x290, - * 0x320, 0x330, 0x340, 0x350 - */ - port_base = link->resource[0]->start; - irq_level = link->irq; - - DEB(printk("SYM53C500: port_base=0x%x, irq=%d, fast_pio=%d\n", - port_base, irq_level, USE_FAST_PIO);) - - chip_init(port_base); - - host = scsi_host_alloc(tpnt, sizeof(struct sym53c500_data)); - if (!host) { - printk("SYM53C500: Unable to register host, giving up.\n"); - goto err_release; - } - - data = (struct sym53c500_data *)host->hostdata; - - if (irq_level > 0) { - if (request_irq(irq_level, SYM53C500_intr, IRQF_SHARED, "SYM53C500", host)) { - printk("SYM53C500: unable to allocate IRQ %d\n", irq_level); - goto err_free_scsi; - } - DEB(printk("SYM53C500: allocated IRQ %d\n", irq_level)); - } else if (irq_level == 0) { - DEB(printk("SYM53C500: No interrupts detected\n")); - goto err_free_scsi; - } else { - DEB(printk("SYM53C500: Shouldn't get here!\n")); - goto err_free_scsi; - } - - host->unique_id = port_base; - host->irq = irq_level; - host->io_port = port_base; - host->n_io_port = 0x10; - host->dma_channel = -1; - - /* - * Note fast_pio is set to USE_FAST_PIO by - * default, but can be changed via "sysfs". - */ - data->fast_pio = USE_FAST_PIO; - - info->host = host; - - if (scsi_add_host(host, NULL)) - goto err_free_irq; - - scsi_scan_host(host); - - return 0; - -err_free_irq: - free_irq(irq_level, host); -err_free_scsi: - scsi_host_put(host); -err_release: - release_region(port_base, 0x10); - printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n"); - return -ENODEV; - -failed: - SYM53C500_release(link); - return -ENODEV; -} /* SYM53C500_config */ - -static int sym53c500_resume(struct pcmcia_device *link) -{ - struct scsi_info_t *info = link->priv; - - /* See earlier comment about manufacturer IDs. */ - if ((info->manf_id == MANFID_MACNICA) || - (info->manf_id == MANFID_PIONEER) || - (info->manf_id == 0x0098)) { - outb(0x80, link->resource[0]->start + 0xd); - outb(0x24, link->resource[0]->start + 0x9); - outb(0x04, link->resource[0]->start + 0xd); - } - /* - * If things don't work after a "resume", - * this is a good place to start looking. - */ - SYM53C500_int_host_reset(link->resource[0]->start); - - return 0; -} - -static void -SYM53C500_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "SYM53C500_detach\n"); - - SYM53C500_release(link); - - kfree(link->priv); - link->priv = NULL; -} /* SYM53C500_detach */ - -static int -SYM53C500_probe(struct pcmcia_device *link) -{ - struct scsi_info_t *info; - - dev_dbg(&link->dev, "SYM53C500_attach()\n"); - - /* Create new SCSI device */ - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return -ENOMEM; - info->p_dev = link; - link->priv = info; - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - return SYM53C500_config(link); -} /* SYM53C500_attach */ - -MODULE_AUTHOR("Bob Tracy "); -MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver"); -MODULE_LICENSE("GPL"); - -static const struct pcmcia_device_id sym53c500_ids[] = { - PCMCIA_DEVICE_PROD_ID12("BASICS by New Media Corporation", "SCSI Sym53C500", 0x23c78a9d, 0x0099e7f7), - PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "SCSI Bus Toaster Sym53C500", 0x085a850b, 0x45432eb8), - PCMCIA_DEVICE_PROD_ID2("SCSI9000", 0x21648f44), - PCMCIA_DEVICE_NULL, -}; -MODULE_DEVICE_TABLE(pcmcia, sym53c500_ids); - -static struct pcmcia_driver sym53c500_cs_driver = { - .owner = THIS_MODULE, - .name = "sym53c500_cs", - .probe = SYM53C500_probe, - .remove = SYM53C500_detach, - .id_table = sym53c500_ids, - .resume = sym53c500_resume, -}; - -static int __init -init_sym53c500_cs(void) -{ - return pcmcia_register_driver(&sym53c500_cs_driver); -} - -static void __exit -exit_sym53c500_cs(void) -{ - pcmcia_unregister_driver(&sym53c500_cs_driver); -} - -module_init(init_sym53c500_cs); -module_exit(exit_sym53c500_cs); diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/Makefile b/ANDROID_3.4.5/drivers/scsi/pm8001/Makefile deleted file mode 100644 index 52f04296..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# Kernel configuration file for the PM8001 SAS/SATA 8x6G based HBA driver -# -# Copyright (C) 2008-2009 USI Co., Ltd. - - -obj-$(CONFIG_SCSI_PM8001) += pm8001.o -pm8001-y += pm8001_init.o \ - pm8001_sas.o \ - pm8001_ctl.o \ - pm8001_hwi.o - diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_chips.h b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_chips.h deleted file mode 100644 index 9241c782..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_chips.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ - -#ifndef _PM8001_CHIPS_H_ -#define _PM8001_CHIPS_H_ - -static inline u32 pm8001_read_32(void *virt_addr) -{ - return *((u32 *)virt_addr); -} - -static inline void pm8001_write_32(void *addr, u32 offset, __le32 val) -{ - *((__le32 *)(addr + offset)) = val; -} - -static inline u32 pm8001_cr32(struct pm8001_hba_info *pm8001_ha, u32 bar, - u32 offset) -{ - return readl(pm8001_ha->io_mem[bar].memvirtaddr + offset); -} - -static inline void pm8001_cw32(struct pm8001_hba_info *pm8001_ha, u32 bar, - u32 addr, u32 val) -{ - writel(val, pm8001_ha->io_mem[bar].memvirtaddr + addr); -} -static inline u32 pm8001_mr32(void __iomem *addr, u32 offset) -{ - return readl(addr + offset); -} -static inline void pm8001_mw32(void __iomem *addr, u32 offset, u32 val) -{ - writel(val, addr + offset); -} -static inline u32 get_pci_bar_index(u32 pcibar) -{ - switch (pcibar) { - case 0x18: - case 0x1C: - return 1; - case 0x20: - return 2; - case 0x24: - return 3; - default: - return 0; - } -} - -#endif /* _PM8001_CHIPS_H_ */ - diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.c b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.c deleted file mode 100644 index 45bc197b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ -#include -#include -#include "pm8001_sas.h" -#include "pm8001_ctl.h" - -/* scsi host attributes */ - -/** - * pm8001_ctl_mpi_interface_rev_show - MPI interface revision number - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - - return snprintf(buf, PAGE_SIZE, "%d\n", - pm8001_ha->main_cfg_tbl.interface_rev); -} -static -DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL); - -/** - * pm8001_ctl_fw_version_show - firmware version - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_fw_version_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - - return snprintf(buf, PAGE_SIZE, "%02x.%02x.%02x.%02x\n", - (u8)(pm8001_ha->main_cfg_tbl.firmware_rev >> 24), - (u8)(pm8001_ha->main_cfg_tbl.firmware_rev >> 16), - (u8)(pm8001_ha->main_cfg_tbl.firmware_rev >> 8), - (u8)(pm8001_ha->main_cfg_tbl.firmware_rev)); -} -static DEVICE_ATTR(fw_version, S_IRUGO, pm8001_ctl_fw_version_show, NULL); -/** - * pm8001_ctl_max_out_io_show - max outstanding io supported - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_max_out_io_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - - return snprintf(buf, PAGE_SIZE, "%d\n", - pm8001_ha->main_cfg_tbl.max_out_io); -} -static DEVICE_ATTR(max_out_io, S_IRUGO, pm8001_ctl_max_out_io_show, NULL); -/** - * pm8001_ctl_max_devices_show - max devices support - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_max_devices_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - - return snprintf(buf, PAGE_SIZE, "%04d\n", - (u16)(pm8001_ha->main_cfg_tbl.max_sgl >> 16)); -} -static DEVICE_ATTR(max_devices, S_IRUGO, pm8001_ctl_max_devices_show, NULL); -/** - * pm8001_ctl_max_sg_list_show - max sg list supported iff not 0.0 for no - * hardware limitation - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_max_sg_list_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - - return snprintf(buf, PAGE_SIZE, "%04d\n", - pm8001_ha->main_cfg_tbl.max_sgl & 0x0000FFFF); -} -static DEVICE_ATTR(max_sg_list, S_IRUGO, pm8001_ctl_max_sg_list_show, NULL); - -#define SAS_1_0 0x1 -#define SAS_1_1 0x2 -#define SAS_2_0 0x4 - -static ssize_t -show_sas_spec_support_status(unsigned int mode, char *buf) -{ - ssize_t len = 0; - - if (mode & SAS_1_1) - len = sprintf(buf, "%s", "SAS1.1"); - if (mode & SAS_2_0) - len += sprintf(buf + len, "%s%s", len ? ", " : "", "SAS2.0"); - len += sprintf(buf + len, "\n"); - - return len; -} - -/** - * pm8001_ctl_sas_spec_support_show - sas spec supported - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_sas_spec_support_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - unsigned int mode; - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - mode = (pm8001_ha->main_cfg_tbl.ctrl_cap_flag & 0xfe000000)>>25; - return show_sas_spec_support_status(mode, buf); -} -static DEVICE_ATTR(sas_spec_support, S_IRUGO, - pm8001_ctl_sas_spec_support_show, NULL); - -/** - * pm8001_ctl_sas_address_show - sas address - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * This is the controller sas address - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_host_sas_address_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - return snprintf(buf, PAGE_SIZE, "0x%016llx\n", - be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr)); -} -static DEVICE_ATTR(host_sas_address, S_IRUGO, - pm8001_ctl_host_sas_address_show, NULL); - -/** - * pm8001_ctl_logging_level_show - logging level - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read/write' shost attribute. - */ -static ssize_t pm8001_ctl_logging_level_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - - return snprintf(buf, PAGE_SIZE, "%08xh\n", pm8001_ha->logging_level); -} -static ssize_t pm8001_ctl_logging_level_store(struct device *cdev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - int val = 0; - - if (sscanf(buf, "%x", &val) != 1) - return -EINVAL; - - pm8001_ha->logging_level = val; - return strlen(buf); -} - -static DEVICE_ATTR(logging_level, S_IRUGO | S_IWUSR, - pm8001_ctl_logging_level_show, pm8001_ctl_logging_level_store); -/** - * pm8001_ctl_aap_log_show - aap1 event log - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_aap_log_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - int i; -#define AAP1_MEMMAP(r, c) \ - (*(u32 *)((u8*)pm8001_ha->memoryMap.region[AAP1].virt_ptr + (r) * 32 \ - + (c))) - - char *str = buf; - int max = 2; - for (i = 0; i < max; i++) { - str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" - "0x%08x 0x%08x\n", - AAP1_MEMMAP(i, 0), - AAP1_MEMMAP(i, 4), - AAP1_MEMMAP(i, 8), - AAP1_MEMMAP(i, 12), - AAP1_MEMMAP(i, 16), - AAP1_MEMMAP(i, 20), - AAP1_MEMMAP(i, 24), - AAP1_MEMMAP(i, 28)); - } - - return str - buf; -} -static DEVICE_ATTR(aap_log, S_IRUGO, pm8001_ctl_aap_log_show, NULL); -/** - * pm8001_ctl_aap_log_show - IOP event log - * @cdev: pointer to embedded class device - * @buf: the buffer returned - * - * A sysfs 'read-only' shost attribute. - */ -static ssize_t pm8001_ctl_iop_log_show(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; -#define IOP_MEMMAP(r, c) \ - (*(u32 *)((u8*)pm8001_ha->memoryMap.region[IOP].virt_ptr + (r) * 32 \ - + (c))) - int i; - char *str = buf; - int max = 2; - for (i = 0; i < max; i++) { - str += sprintf(str, "0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x" - "0x%08x 0x%08x\n", - IOP_MEMMAP(i, 0), - IOP_MEMMAP(i, 4), - IOP_MEMMAP(i, 8), - IOP_MEMMAP(i, 12), - IOP_MEMMAP(i, 16), - IOP_MEMMAP(i, 20), - IOP_MEMMAP(i, 24), - IOP_MEMMAP(i, 28)); - } - - return str - buf; -} -static DEVICE_ATTR(iop_log, S_IRUGO, pm8001_ctl_iop_log_show, NULL); - -#define FLASH_CMD_NONE 0x00 -#define FLASH_CMD_UPDATE 0x01 -#define FLASH_CMD_SET_NVMD 0x02 - -struct flash_command { - u8 command[8]; - int code; -}; - -static struct flash_command flash_command_table[] = -{ - {"set_nvmd", FLASH_CMD_SET_NVMD}, - {"update", FLASH_CMD_UPDATE}, - {"", FLASH_CMD_NONE} /* Last entry should be NULL. */ -}; - -struct error_fw { - char *reason; - int err_code; -}; - -static struct error_fw flash_error_table[] = -{ - {"Failed to open fw image file", FAIL_OPEN_BIOS_FILE}, - {"image header mismatch", FLASH_UPDATE_HDR_ERR}, - {"image offset mismatch", FLASH_UPDATE_OFFSET_ERR}, - {"image CRC Error", FLASH_UPDATE_CRC_ERR}, - {"image length Error.", FLASH_UPDATE_LENGTH_ERR}, - {"Failed to program flash chip", FLASH_UPDATE_HW_ERR}, - {"Flash chip not supported.", FLASH_UPDATE_DNLD_NOT_SUPPORTED}, - {"Flash update disabled.", FLASH_UPDATE_DISABLED}, - {"Flash in progress", FLASH_IN_PROGRESS}, - {"Image file size Error", FAIL_FILE_SIZE}, - {"Input parameter error", FAIL_PARAMETERS}, - {"Out of memory", FAIL_OUT_MEMORY}, - {"OK", 0} /* Last entry err_code = 0. */ -}; - -static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha) -{ - struct pm8001_ioctl_payload *payload; - DECLARE_COMPLETION_ONSTACK(completion); - u8 *ioctlbuffer = NULL; - u32 length = 0; - u32 ret = 0; - - length = 1024 * 5 + sizeof(*payload) - 1; - ioctlbuffer = kzalloc(length, GFP_KERNEL); - if (!ioctlbuffer) - return -ENOMEM; - if ((pm8001_ha->fw_image->size <= 0) || - (pm8001_ha->fw_image->size > 4096)) { - ret = FAIL_FILE_SIZE; - goto out; - } - payload = (struct pm8001_ioctl_payload *)ioctlbuffer; - memcpy((u8 *)payload->func_specific, (u8 *)pm8001_ha->fw_image->data, - pm8001_ha->fw_image->size); - payload->length = pm8001_ha->fw_image->size; - payload->id = 0; - pm8001_ha->nvmd_completion = &completion; - ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload); - wait_for_completion(&completion); -out: - kfree(ioctlbuffer); - return ret; -} - -static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha) -{ - struct pm8001_ioctl_payload *payload; - DECLARE_COMPLETION_ONSTACK(completion); - u8 *ioctlbuffer = NULL; - u32 length = 0; - struct fw_control_info *fwControl; - u32 loopNumber, loopcount = 0; - u32 sizeRead = 0; - u32 partitionSize, partitionSizeTmp; - u32 ret = 0; - u32 partitionNumber = 0; - struct pm8001_fw_image_header *image_hdr; - - length = 1024 * 16 + sizeof(*payload) - 1; - ioctlbuffer = kzalloc(length, GFP_KERNEL); - image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data; - if (!ioctlbuffer) - return -ENOMEM; - if (pm8001_ha->fw_image->size < 28) { - ret = FAIL_FILE_SIZE; - goto out; - } - - while (sizeRead < pm8001_ha->fw_image->size) { - partitionSizeTmp = - *(u32 *)((u8 *)&image_hdr->image_length + sizeRead); - partitionSize = be32_to_cpu(partitionSizeTmp); - loopcount = (partitionSize + HEADER_LEN)/IOCTL_BUF_SIZE; - if (loopcount % IOCTL_BUF_SIZE) - loopcount++; - if (loopcount == 0) - loopcount++; - for (loopNumber = 0; loopNumber < loopcount; loopNumber++) { - payload = (struct pm8001_ioctl_payload *)ioctlbuffer; - payload->length = 1024*16; - payload->id = 0; - fwControl = - (struct fw_control_info *)payload->func_specific; - fwControl->len = IOCTL_BUF_SIZE; /* IN */ - fwControl->size = partitionSize + HEADER_LEN;/* IN */ - fwControl->retcode = 0;/* OUT */ - fwControl->offset = loopNumber * IOCTL_BUF_SIZE;/*OUT */ - - /* for the last chunk of data in case file size is not even with - 4k, load only the rest*/ - if (((loopcount-loopNumber) == 1) && - ((partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE)) { - fwControl->len = - (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE; - memcpy((u8 *)fwControl->buffer, - (u8 *)pm8001_ha->fw_image->data + sizeRead, - (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE); - sizeRead += - (partitionSize + HEADER_LEN) % IOCTL_BUF_SIZE; - } else { - memcpy((u8 *)fwControl->buffer, - (u8 *)pm8001_ha->fw_image->data + sizeRead, - IOCTL_BUF_SIZE); - sizeRead += IOCTL_BUF_SIZE; - } - - pm8001_ha->nvmd_completion = &completion; - ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload); - wait_for_completion(&completion); - if (ret || (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS)) { - ret = fwControl->retcode; - kfree(ioctlbuffer); - ioctlbuffer = NULL; - break; - } - } - if (ret) - break; - partitionNumber++; -} -out: - kfree(ioctlbuffer); - return ret; -} -static ssize_t pm8001_store_update_fw(struct device *cdev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - char *cmd_ptr, *filename_ptr; - int res, i; - int flash_command = FLASH_CMD_NONE; - int err = 0; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - cmd_ptr = kzalloc(count*2, GFP_KERNEL); - - if (!cmd_ptr) { - err = FAIL_OUT_MEMORY; - goto out; - } - - filename_ptr = cmd_ptr + count; - res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); - if (res != 2) { - err = FAIL_PARAMETERS; - goto out1; - } - - for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { - if (!memcmp(flash_command_table[i].command, - cmd_ptr, strlen(cmd_ptr))) { - flash_command = flash_command_table[i].code; - break; - } - } - if (flash_command == FLASH_CMD_NONE) { - err = FAIL_PARAMETERS; - goto out1; - } - - if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) { - err = FLASH_IN_PROGRESS; - goto out1; - } - err = request_firmware(&pm8001_ha->fw_image, - filename_ptr, - pm8001_ha->dev); - - if (err) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Failed to load firmware image file %s," - " error %d\n", filename_ptr, err)); - err = FAIL_OPEN_BIOS_FILE; - goto out1; - } - - switch (flash_command) { - case FLASH_CMD_UPDATE: - pm8001_ha->fw_status = FLASH_IN_PROGRESS; - err = pm8001_update_flash(pm8001_ha); - break; - case FLASH_CMD_SET_NVMD: - pm8001_ha->fw_status = FLASH_IN_PROGRESS; - err = pm8001_set_nvmd(pm8001_ha); - break; - default: - pm8001_ha->fw_status = FAIL_PARAMETERS; - err = FAIL_PARAMETERS; - break; - } - release_firmware(pm8001_ha->fw_image); -out1: - kfree(cmd_ptr); -out: - pm8001_ha->fw_status = err; - - if (!err) - return count; - else - return -err; -} - -static ssize_t pm8001_show_update_fw(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - int i; - struct Scsi_Host *shost = class_to_shost(cdev); - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - - for (i = 0; flash_error_table[i].err_code != 0; i++) { - if (flash_error_table[i].err_code == pm8001_ha->fw_status) - break; - } - if (pm8001_ha->fw_status != FLASH_IN_PROGRESS) - pm8001_ha->fw_status = FLASH_OK; - - return snprintf(buf, PAGE_SIZE, "status=%x %s\n", - flash_error_table[i].err_code, - flash_error_table[i].reason); -} - -static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUGO, - pm8001_show_update_fw, pm8001_store_update_fw); -struct device_attribute *pm8001_host_attrs[] = { - &dev_attr_interface_rev, - &dev_attr_fw_version, - &dev_attr_update_fw, - &dev_attr_aap_log, - &dev_attr_iop_log, - &dev_attr_max_out_io, - &dev_attr_max_devices, - &dev_attr_max_sg_list, - &dev_attr_sas_spec_support, - &dev_attr_logging_level, - &dev_attr_host_sas_address, - NULL, -}; - diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.h b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.h deleted file mode 100644 index 63ad4aa0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_ctl.h +++ /dev/null @@ -1,57 +0,0 @@ - /* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ - -#ifndef PM8001_CTL_H_INCLUDED -#define PM8001_CTL_H_INCLUDED - -#define IOCTL_BUF_SIZE 4096 -#define HEADER_LEN 28 -#define SIZE_OFFSET 16 - - -#define FLASH_OK 0x000000 -#define FAIL_OPEN_BIOS_FILE 0x000100 -#define FAIL_FILE_SIZE 0x000a00 -#define FAIL_PARAMETERS 0x000b00 -#define FAIL_OUT_MEMORY 0x000c00 -#define FLASH_IN_PROGRESS 0x001000 - -#endif /* PM8001_CTL_H_INCLUDED */ - diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_defs.h b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_defs.h deleted file mode 100644 index 944afada..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_defs.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ - -#ifndef _PM8001_DEFS_H_ -#define _PM8001_DEFS_H_ - -enum chip_flavors { - chip_8001, -}; -#define USI_MAX_MEMCNT 9 -#define PM8001_MAX_DMA_SG SG_ALL -enum phy_speed { - PHY_SPEED_15 = 0x01, - PHY_SPEED_30 = 0x02, - PHY_SPEED_60 = 0x04, -}; - -enum data_direction { - DATA_DIR_NONE = 0x0, /* NO TRANSFER */ - DATA_DIR_IN = 0x01, /* INBOUND */ - DATA_DIR_OUT = 0x02, /* OUTBOUND */ - DATA_DIR_BYRECIPIENT = 0x04, /* UNSPECIFIED */ -}; - -enum port_type { - PORT_TYPE_SAS = (1L << 1), - PORT_TYPE_SATA = (1L << 0), -}; - -/* driver compile-time configuration */ -#define PM8001_MAX_CCB 512 /* max ccbs supported */ -#define PM8001_MAX_INB_NUM 1 -#define PM8001_MAX_OUTB_NUM 1 -#define PM8001_CAN_QUEUE 128 /* SCSI Queue depth */ - -/* unchangeable hardware details */ -#define PM8001_MAX_PHYS 8 /* max. possible phys */ -#define PM8001_MAX_PORTS 8 /* max. possible ports */ -#define PM8001_MAX_DEVICES 1024 /* max supported device */ - -enum memory_region_num { - AAP1 = 0x0, /* application acceleration processor */ - IOP, /* IO processor */ - CI, /* consumer index */ - PI, /* producer index */ - IB, /* inbound queue */ - OB, /* outbound queue */ - NVMD, /* NVM device */ - DEV_MEM, /* memory for devices */ - CCB_MEM, /* memory for command control block */ -}; -#define PM8001_EVENT_LOG_SIZE (128 * 1024) - -/*error code*/ -enum mpi_err { - MPI_IO_STATUS_SUCCESS = 0x0, - MPI_IO_STATUS_BUSY = 0x01, - MPI_IO_STATUS_FAIL = 0x02, -}; - -/** - * Phy Control constants - */ -enum phy_control_type { - PHY_LINK_RESET = 0x01, - PHY_HARD_RESET = 0x02, - PHY_NOTIFY_ENABLE_SPINUP = 0x10, -}; - -enum pm8001_hba_info_flags { - PM8001F_INIT_TIME = (1U << 0), - PM8001F_RUN_TIME = (1U << 1), -}; - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.c b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.c deleted file mode 100644 index 9d82ee5c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.c +++ /dev/null @@ -1,4712 +0,0 @@ -/* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ - #include - #include "pm8001_sas.h" - #include "pm8001_hwi.h" - #include "pm8001_chips.h" - #include "pm8001_ctl.h" - -/** - * read_main_config_table - read the configure table and save it. - * @pm8001_ha: our hba card information - */ -static void __devinit read_main_config_table(struct pm8001_hba_info *pm8001_ha) -{ - void __iomem *address = pm8001_ha->main_cfg_tbl_addr; - pm8001_ha->main_cfg_tbl.signature = pm8001_mr32(address, 0x00); - pm8001_ha->main_cfg_tbl.interface_rev = pm8001_mr32(address, 0x04); - pm8001_ha->main_cfg_tbl.firmware_rev = pm8001_mr32(address, 0x08); - pm8001_ha->main_cfg_tbl.max_out_io = pm8001_mr32(address, 0x0C); - pm8001_ha->main_cfg_tbl.max_sgl = pm8001_mr32(address, 0x10); - pm8001_ha->main_cfg_tbl.ctrl_cap_flag = pm8001_mr32(address, 0x14); - pm8001_ha->main_cfg_tbl.gst_offset = pm8001_mr32(address, 0x18); - pm8001_ha->main_cfg_tbl.inbound_queue_offset = - pm8001_mr32(address, MAIN_IBQ_OFFSET); - pm8001_ha->main_cfg_tbl.outbound_queue_offset = - pm8001_mr32(address, MAIN_OBQ_OFFSET); - pm8001_ha->main_cfg_tbl.hda_mode_flag = - pm8001_mr32(address, MAIN_HDA_FLAGS_OFFSET); - - /* read analog Setting offset from the configuration table */ - pm8001_ha->main_cfg_tbl.anolog_setup_table_offset = - pm8001_mr32(address, MAIN_ANALOG_SETUP_OFFSET); - - /* read Error Dump Offset and Length */ - pm8001_ha->main_cfg_tbl.fatal_err_dump_offset0 = - pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_OFFSET); - pm8001_ha->main_cfg_tbl.fatal_err_dump_length0 = - pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP0_LENGTH); - pm8001_ha->main_cfg_tbl.fatal_err_dump_offset1 = - pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_OFFSET); - pm8001_ha->main_cfg_tbl.fatal_err_dump_length1 = - pm8001_mr32(address, MAIN_FATAL_ERROR_RDUMP1_LENGTH); -} - -/** - * read_general_status_table - read the general status table and save it. - * @pm8001_ha: our hba card information - */ -static void __devinit -read_general_status_table(struct pm8001_hba_info *pm8001_ha) -{ - void __iomem *address = pm8001_ha->general_stat_tbl_addr; - pm8001_ha->gs_tbl.gst_len_mpistate = pm8001_mr32(address, 0x00); - pm8001_ha->gs_tbl.iq_freeze_state0 = pm8001_mr32(address, 0x04); - pm8001_ha->gs_tbl.iq_freeze_state1 = pm8001_mr32(address, 0x08); - pm8001_ha->gs_tbl.msgu_tcnt = pm8001_mr32(address, 0x0C); - pm8001_ha->gs_tbl.iop_tcnt = pm8001_mr32(address, 0x10); - pm8001_ha->gs_tbl.reserved = pm8001_mr32(address, 0x14); - pm8001_ha->gs_tbl.phy_state[0] = pm8001_mr32(address, 0x18); - pm8001_ha->gs_tbl.phy_state[1] = pm8001_mr32(address, 0x1C); - pm8001_ha->gs_tbl.phy_state[2] = pm8001_mr32(address, 0x20); - pm8001_ha->gs_tbl.phy_state[3] = pm8001_mr32(address, 0x24); - pm8001_ha->gs_tbl.phy_state[4] = pm8001_mr32(address, 0x28); - pm8001_ha->gs_tbl.phy_state[5] = pm8001_mr32(address, 0x2C); - pm8001_ha->gs_tbl.phy_state[6] = pm8001_mr32(address, 0x30); - pm8001_ha->gs_tbl.phy_state[7] = pm8001_mr32(address, 0x34); - pm8001_ha->gs_tbl.reserved1 = pm8001_mr32(address, 0x38); - pm8001_ha->gs_tbl.reserved2 = pm8001_mr32(address, 0x3C); - pm8001_ha->gs_tbl.reserved3 = pm8001_mr32(address, 0x40); - pm8001_ha->gs_tbl.recover_err_info[0] = pm8001_mr32(address, 0x44); - pm8001_ha->gs_tbl.recover_err_info[1] = pm8001_mr32(address, 0x48); - pm8001_ha->gs_tbl.recover_err_info[2] = pm8001_mr32(address, 0x4C); - pm8001_ha->gs_tbl.recover_err_info[3] = pm8001_mr32(address, 0x50); - pm8001_ha->gs_tbl.recover_err_info[4] = pm8001_mr32(address, 0x54); - pm8001_ha->gs_tbl.recover_err_info[5] = pm8001_mr32(address, 0x58); - pm8001_ha->gs_tbl.recover_err_info[6] = pm8001_mr32(address, 0x5C); - pm8001_ha->gs_tbl.recover_err_info[7] = pm8001_mr32(address, 0x60); -} - -/** - * read_inbnd_queue_table - read the inbound queue table and save it. - * @pm8001_ha: our hba card information - */ -static void __devinit -read_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha) -{ - int inbQ_num = 1; - int i; - void __iomem *address = pm8001_ha->inbnd_q_tbl_addr; - for (i = 0; i < inbQ_num; i++) { - u32 offset = i * 0x20; - pm8001_ha->inbnd_q_tbl[i].pi_pci_bar = - get_pci_bar_index(pm8001_mr32(address, (offset + 0x14))); - pm8001_ha->inbnd_q_tbl[i].pi_offset = - pm8001_mr32(address, (offset + 0x18)); - } -} - -/** - * read_outbnd_queue_table - read the outbound queue table and save it. - * @pm8001_ha: our hba card information - */ -static void __devinit -read_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha) -{ - int outbQ_num = 1; - int i; - void __iomem *address = pm8001_ha->outbnd_q_tbl_addr; - for (i = 0; i < outbQ_num; i++) { - u32 offset = i * 0x24; - pm8001_ha->outbnd_q_tbl[i].ci_pci_bar = - get_pci_bar_index(pm8001_mr32(address, (offset + 0x14))); - pm8001_ha->outbnd_q_tbl[i].ci_offset = - pm8001_mr32(address, (offset + 0x18)); - } -} - -/** - * init_default_table_values - init the default table. - * @pm8001_ha: our hba card information - */ -static void __devinit -init_default_table_values(struct pm8001_hba_info *pm8001_ha) -{ - int qn = 1; - int i; - u32 offsetib, offsetob; - void __iomem *addressib = pm8001_ha->inbnd_q_tbl_addr; - void __iomem *addressob = pm8001_ha->outbnd_q_tbl_addr; - - pm8001_ha->main_cfg_tbl.inbound_q_nppd_hppd = 0; - pm8001_ha->main_cfg_tbl.outbound_hw_event_pid0_3 = 0; - pm8001_ha->main_cfg_tbl.outbound_hw_event_pid4_7 = 0; - pm8001_ha->main_cfg_tbl.outbound_ncq_event_pid0_3 = 0; - pm8001_ha->main_cfg_tbl.outbound_ncq_event_pid4_7 = 0; - pm8001_ha->main_cfg_tbl.outbound_tgt_ITNexus_event_pid0_3 = 0; - pm8001_ha->main_cfg_tbl.outbound_tgt_ITNexus_event_pid4_7 = 0; - pm8001_ha->main_cfg_tbl.outbound_tgt_ssp_event_pid0_3 = 0; - pm8001_ha->main_cfg_tbl.outbound_tgt_ssp_event_pid4_7 = 0; - pm8001_ha->main_cfg_tbl.outbound_tgt_smp_event_pid0_3 = 0; - pm8001_ha->main_cfg_tbl.outbound_tgt_smp_event_pid4_7 = 0; - - pm8001_ha->main_cfg_tbl.upper_event_log_addr = - pm8001_ha->memoryMap.region[AAP1].phys_addr_hi; - pm8001_ha->main_cfg_tbl.lower_event_log_addr = - pm8001_ha->memoryMap.region[AAP1].phys_addr_lo; - pm8001_ha->main_cfg_tbl.event_log_size = PM8001_EVENT_LOG_SIZE; - pm8001_ha->main_cfg_tbl.event_log_option = 0x01; - pm8001_ha->main_cfg_tbl.upper_iop_event_log_addr = - pm8001_ha->memoryMap.region[IOP].phys_addr_hi; - pm8001_ha->main_cfg_tbl.lower_iop_event_log_addr = - pm8001_ha->memoryMap.region[IOP].phys_addr_lo; - pm8001_ha->main_cfg_tbl.iop_event_log_size = PM8001_EVENT_LOG_SIZE; - pm8001_ha->main_cfg_tbl.iop_event_log_option = 0x01; - pm8001_ha->main_cfg_tbl.fatal_err_interrupt = 0x01; - for (i = 0; i < qn; i++) { - pm8001_ha->inbnd_q_tbl[i].element_pri_size_cnt = - 0x00000100 | (0x00000040 << 16) | (0x00<<30); - pm8001_ha->inbnd_q_tbl[i].upper_base_addr = - pm8001_ha->memoryMap.region[IB].phys_addr_hi; - pm8001_ha->inbnd_q_tbl[i].lower_base_addr = - pm8001_ha->memoryMap.region[IB].phys_addr_lo; - pm8001_ha->inbnd_q_tbl[i].base_virt = - (u8 *)pm8001_ha->memoryMap.region[IB].virt_ptr; - pm8001_ha->inbnd_q_tbl[i].total_length = - pm8001_ha->memoryMap.region[IB].total_len; - pm8001_ha->inbnd_q_tbl[i].ci_upper_base_addr = - pm8001_ha->memoryMap.region[CI].phys_addr_hi; - pm8001_ha->inbnd_q_tbl[i].ci_lower_base_addr = - pm8001_ha->memoryMap.region[CI].phys_addr_lo; - pm8001_ha->inbnd_q_tbl[i].ci_virt = - pm8001_ha->memoryMap.region[CI].virt_ptr; - offsetib = i * 0x20; - pm8001_ha->inbnd_q_tbl[i].pi_pci_bar = - get_pci_bar_index(pm8001_mr32(addressib, - (offsetib + 0x14))); - pm8001_ha->inbnd_q_tbl[i].pi_offset = - pm8001_mr32(addressib, (offsetib + 0x18)); - pm8001_ha->inbnd_q_tbl[i].producer_idx = 0; - pm8001_ha->inbnd_q_tbl[i].consumer_index = 0; - } - for (i = 0; i < qn; i++) { - pm8001_ha->outbnd_q_tbl[i].element_size_cnt = - 256 | (64 << 16) | (1<<30); - pm8001_ha->outbnd_q_tbl[i].upper_base_addr = - pm8001_ha->memoryMap.region[OB].phys_addr_hi; - pm8001_ha->outbnd_q_tbl[i].lower_base_addr = - pm8001_ha->memoryMap.region[OB].phys_addr_lo; - pm8001_ha->outbnd_q_tbl[i].base_virt = - (u8 *)pm8001_ha->memoryMap.region[OB].virt_ptr; - pm8001_ha->outbnd_q_tbl[i].total_length = - pm8001_ha->memoryMap.region[OB].total_len; - pm8001_ha->outbnd_q_tbl[i].pi_upper_base_addr = - pm8001_ha->memoryMap.region[PI].phys_addr_hi; - pm8001_ha->outbnd_q_tbl[i].pi_lower_base_addr = - pm8001_ha->memoryMap.region[PI].phys_addr_lo; - pm8001_ha->outbnd_q_tbl[i].interrup_vec_cnt_delay = - 0 | (10 << 16) | (0 << 24); - pm8001_ha->outbnd_q_tbl[i].pi_virt = - pm8001_ha->memoryMap.region[PI].virt_ptr; - offsetob = i * 0x24; - pm8001_ha->outbnd_q_tbl[i].ci_pci_bar = - get_pci_bar_index(pm8001_mr32(addressob, - offsetob + 0x14)); - pm8001_ha->outbnd_q_tbl[i].ci_offset = - pm8001_mr32(addressob, (offsetob + 0x18)); - pm8001_ha->outbnd_q_tbl[i].consumer_idx = 0; - pm8001_ha->outbnd_q_tbl[i].producer_index = 0; - } -} - -/** - * update_main_config_table - update the main default table to the HBA. - * @pm8001_ha: our hba card information - */ -static void __devinit -update_main_config_table(struct pm8001_hba_info *pm8001_ha) -{ - void __iomem *address = pm8001_ha->main_cfg_tbl_addr; - pm8001_mw32(address, 0x24, - pm8001_ha->main_cfg_tbl.inbound_q_nppd_hppd); - pm8001_mw32(address, 0x28, - pm8001_ha->main_cfg_tbl.outbound_hw_event_pid0_3); - pm8001_mw32(address, 0x2C, - pm8001_ha->main_cfg_tbl.outbound_hw_event_pid4_7); - pm8001_mw32(address, 0x30, - pm8001_ha->main_cfg_tbl.outbound_ncq_event_pid0_3); - pm8001_mw32(address, 0x34, - pm8001_ha->main_cfg_tbl.outbound_ncq_event_pid4_7); - pm8001_mw32(address, 0x38, - pm8001_ha->main_cfg_tbl.outbound_tgt_ITNexus_event_pid0_3); - pm8001_mw32(address, 0x3C, - pm8001_ha->main_cfg_tbl.outbound_tgt_ITNexus_event_pid4_7); - pm8001_mw32(address, 0x40, - pm8001_ha->main_cfg_tbl.outbound_tgt_ssp_event_pid0_3); - pm8001_mw32(address, 0x44, - pm8001_ha->main_cfg_tbl.outbound_tgt_ssp_event_pid4_7); - pm8001_mw32(address, 0x48, - pm8001_ha->main_cfg_tbl.outbound_tgt_smp_event_pid0_3); - pm8001_mw32(address, 0x4C, - pm8001_ha->main_cfg_tbl.outbound_tgt_smp_event_pid4_7); - pm8001_mw32(address, 0x50, - pm8001_ha->main_cfg_tbl.upper_event_log_addr); - pm8001_mw32(address, 0x54, - pm8001_ha->main_cfg_tbl.lower_event_log_addr); - pm8001_mw32(address, 0x58, pm8001_ha->main_cfg_tbl.event_log_size); - pm8001_mw32(address, 0x5C, pm8001_ha->main_cfg_tbl.event_log_option); - pm8001_mw32(address, 0x60, - pm8001_ha->main_cfg_tbl.upper_iop_event_log_addr); - pm8001_mw32(address, 0x64, - pm8001_ha->main_cfg_tbl.lower_iop_event_log_addr); - pm8001_mw32(address, 0x68, pm8001_ha->main_cfg_tbl.iop_event_log_size); - pm8001_mw32(address, 0x6C, - pm8001_ha->main_cfg_tbl.iop_event_log_option); - pm8001_mw32(address, 0x70, - pm8001_ha->main_cfg_tbl.fatal_err_interrupt); -} - -/** - * update_inbnd_queue_table - update the inbound queue table to the HBA. - * @pm8001_ha: our hba card information - */ -static void __devinit -update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number) -{ - void __iomem *address = pm8001_ha->inbnd_q_tbl_addr; - u16 offset = number * 0x20; - pm8001_mw32(address, offset + 0x00, - pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt); - pm8001_mw32(address, offset + 0x04, - pm8001_ha->inbnd_q_tbl[number].upper_base_addr); - pm8001_mw32(address, offset + 0x08, - pm8001_ha->inbnd_q_tbl[number].lower_base_addr); - pm8001_mw32(address, offset + 0x0C, - pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr); - pm8001_mw32(address, offset + 0x10, - pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr); -} - -/** - * update_outbnd_queue_table - update the outbound queue table to the HBA. - * @pm8001_ha: our hba card information - */ -static void __devinit -update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, int number) -{ - void __iomem *address = pm8001_ha->outbnd_q_tbl_addr; - u16 offset = number * 0x24; - pm8001_mw32(address, offset + 0x00, - pm8001_ha->outbnd_q_tbl[number].element_size_cnt); - pm8001_mw32(address, offset + 0x04, - pm8001_ha->outbnd_q_tbl[number].upper_base_addr); - pm8001_mw32(address, offset + 0x08, - pm8001_ha->outbnd_q_tbl[number].lower_base_addr); - pm8001_mw32(address, offset + 0x0C, - pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr); - pm8001_mw32(address, offset + 0x10, - pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr); - pm8001_mw32(address, offset + 0x1C, - pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay); -} - -/** - * pm8001_bar4_shift - function is called to shift BAR base address - * @pm8001_ha : our hba card infomation - * @shiftValue : shifting value in memory bar. - */ -int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue) -{ - u32 regVal; - unsigned long start; - - /* program the inbound AXI translation Lower Address */ - pm8001_cw32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW, shiftValue); - - /* confirm the setting is written */ - start = jiffies + HZ; /* 1 sec */ - do { - regVal = pm8001_cr32(pm8001_ha, 1, SPC_IBW_AXI_TRANSLATION_LOW); - } while ((regVal != shiftValue) && time_before(jiffies, start)); - - if (regVal != shiftValue) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:SPC_IBW_AXI_TRANSLATION_LOW" - " = 0x%x\n", regVal)); - return -1; - } - return 0; -} - -/** - * mpi_set_phys_g3_with_ssc - * @pm8001_ha: our hba card information - * @SSCbit: set SSCbit to 0 to disable all phys ssc; 1 to enable all phys ssc. - */ -static void __devinit -mpi_set_phys_g3_with_ssc(struct pm8001_hba_info *pm8001_ha, u32 SSCbit) -{ - u32 value, offset, i; - unsigned long flags; - -#define SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR 0x00030000 -#define SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR 0x00040000 -#define SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET 0x1074 -#define SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET 0x1074 -#define PHY_G3_WITHOUT_SSC_BIT_SHIFT 12 -#define PHY_G3_WITH_SSC_BIT_SHIFT 13 -#define SNW3_PHY_CAPABILITIES_PARITY 31 - - /* - * Using shifted destination address 0x3_0000:0x1074 + 0x4000*N (N=0:3) - * Using shifted destination address 0x4_0000:0x1074 + 0x4000*(N-4) (N=4:7) - */ - spin_lock_irqsave(&pm8001_ha->lock, flags); - if (-1 == pm8001_bar4_shift(pm8001_ha, - SAS2_SETTINGS_LOCAL_PHY_0_3_SHIFT_ADDR)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return; - } - - for (i = 0; i < 4; i++) { - offset = SAS2_SETTINGS_LOCAL_PHY_0_3_OFFSET + 0x4000 * i; - pm8001_cw32(pm8001_ha, 2, offset, 0x80001501); - } - /* shift membase 3 for SAS2_SETTINGS_LOCAL_PHY 4 - 7 */ - if (-1 == pm8001_bar4_shift(pm8001_ha, - SAS2_SETTINGS_LOCAL_PHY_4_7_SHIFT_ADDR)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return; - } - for (i = 4; i < 8; i++) { - offset = SAS2_SETTINGS_LOCAL_PHY_4_7_OFFSET + 0x4000 * (i-4); - pm8001_cw32(pm8001_ha, 2, offset, 0x80001501); - } - /************************************************************* - Change the SSC upspreading value to 0x0 so that upspreading is disabled. - Device MABC SMOD0 Controls - Address: (via MEMBASE-III): - Using shifted destination address 0x0_0000: with Offset 0xD8 - - 31:28 R/W Reserved Do not change - 27:24 R/W SAS_SMOD_SPRDUP 0000 - 23:20 R/W SAS_SMOD_SPRDDN 0000 - 19:0 R/W Reserved Do not change - Upon power-up this register will read as 0x8990c016, - and I would like you to change the SAS_SMOD_SPRDUP bits to 0b0000 - so that the written value will be 0x8090c016. - This will ensure only down-spreading SSC is enabled on the SPC. - *************************************************************/ - value = pm8001_cr32(pm8001_ha, 2, 0xd8); - pm8001_cw32(pm8001_ha, 2, 0xd8, 0x8000C016); - - /*set the shifted destination address to 0x0 to avoid error operation */ - pm8001_bar4_shift(pm8001_ha, 0x0); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return; -} - -/** - * mpi_set_open_retry_interval_reg - * @pm8001_ha: our hba card information - * @interval - interval time for each OPEN_REJECT (RETRY). The units are in 1us. - */ -static void __devinit -mpi_set_open_retry_interval_reg(struct pm8001_hba_info *pm8001_ha, - u32 interval) -{ - u32 offset; - u32 value; - u32 i; - unsigned long flags; - -#define OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR 0x00030000 -#define OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR 0x00040000 -#define OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET 0x30B4 -#define OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET 0x30B4 -#define OPEN_RETRY_INTERVAL_REG_MASK 0x0000FFFF - - value = interval & OPEN_RETRY_INTERVAL_REG_MASK; - spin_lock_irqsave(&pm8001_ha->lock, flags); - /* shift bar and set the OPEN_REJECT(RETRY) interval time of PHY 0 -3.*/ - if (-1 == pm8001_bar4_shift(pm8001_ha, - OPEN_RETRY_INTERVAL_PHY_0_3_SHIFT_ADDR)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return; - } - for (i = 0; i < 4; i++) { - offset = OPEN_RETRY_INTERVAL_PHY_0_3_OFFSET + 0x4000 * i; - pm8001_cw32(pm8001_ha, 2, offset, value); - } - - if (-1 == pm8001_bar4_shift(pm8001_ha, - OPEN_RETRY_INTERVAL_PHY_4_7_SHIFT_ADDR)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return; - } - for (i = 4; i < 8; i++) { - offset = OPEN_RETRY_INTERVAL_PHY_4_7_OFFSET + 0x4000 * (i-4); - pm8001_cw32(pm8001_ha, 2, offset, value); - } - /*set the shifted destination address to 0x0 to avoid error operation */ - pm8001_bar4_shift(pm8001_ha, 0x0); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return; -} - -/** - * mpi_init_check - check firmware initialization status. - * @pm8001_ha: our hba card information - */ -static int mpi_init_check(struct pm8001_hba_info *pm8001_ha) -{ - u32 max_wait_count; - u32 value; - u32 gst_len_mpistate; - /* Write bit0=1 to Inbound DoorBell Register to tell the SPC FW the - table is updated */ - pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_UPDATE); - /* wait until Inbound DoorBell Clear Register toggled */ - max_wait_count = 1 * 1000 * 1000;/* 1 sec */ - do { - udelay(1); - value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET); - value &= SPC_MSGU_CFG_TABLE_UPDATE; - } while ((value != 0) && (--max_wait_count)); - - if (!max_wait_count) - return -1; - /* check the MPI-State for initialization */ - gst_len_mpistate = - pm8001_mr32(pm8001_ha->general_stat_tbl_addr, - GST_GSTLEN_MPIS_OFFSET); - if (GST_MPI_STATE_INIT != (gst_len_mpistate & GST_MPI_STATE_MASK)) - return -1; - /* check MPI Initialization error */ - gst_len_mpistate = gst_len_mpistate >> 16; - if (0x0000 != gst_len_mpistate) - return -1; - return 0; -} - -/** - * check_fw_ready - The LLDD check if the FW is ready, if not, return error. - * @pm8001_ha: our hba card information - */ -static int check_fw_ready(struct pm8001_hba_info *pm8001_ha) -{ - u32 value, value1; - u32 max_wait_count; - /* check error state */ - value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); - value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2); - /* check AAP error */ - if (SCRATCH_PAD1_ERR == (value & SCRATCH_PAD_STATE_MASK)) { - /* error state */ - value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0); - return -1; - } - - /* check IOP error */ - if (SCRATCH_PAD2_ERR == (value1 & SCRATCH_PAD_STATE_MASK)) { - /* error state */ - value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3); - return -1; - } - - /* bit 4-31 of scratch pad1 should be zeros if it is not - in error state*/ - if (value & SCRATCH_PAD1_STATE_MASK) { - /* error case */ - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0); - return -1; - } - - /* bit 2, 4-31 of scratch pad2 should be zeros if it is not - in error state */ - if (value1 & SCRATCH_PAD2_STATE_MASK) { - /* error case */ - return -1; - } - - max_wait_count = 1 * 1000 * 1000;/* 1 sec timeout */ - - /* wait until scratch pad 1 and 2 registers in ready state */ - do { - udelay(1); - value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1) - & SCRATCH_PAD1_RDY; - value1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) - & SCRATCH_PAD2_RDY; - if ((--max_wait_count) == 0) - return -1; - } while ((value != SCRATCH_PAD1_RDY) || (value1 != SCRATCH_PAD2_RDY)); - return 0; -} - -static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) -{ - void __iomem *base_addr; - u32 value; - u32 offset; - u32 pcibar; - u32 pcilogic; - - value = pm8001_cr32(pm8001_ha, 0, 0x44); - offset = value & 0x03FFFFFF; - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Scratchpad 0 Offset: %x\n", offset)); - pcilogic = (value & 0xFC000000) >> 26; - pcibar = get_pci_bar_index(pcilogic); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Scratchpad 0 PCI BAR: %d\n", pcibar)); - pm8001_ha->main_cfg_tbl_addr = base_addr = - pm8001_ha->io_mem[pcibar].memvirtaddr + offset; - pm8001_ha->general_stat_tbl_addr = - base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x18); - pm8001_ha->inbnd_q_tbl_addr = - base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x1C); - pm8001_ha->outbnd_q_tbl_addr = - base_addr + pm8001_cr32(pm8001_ha, pcibar, offset + 0x20); -} - -/** - * pm8001_chip_init - the main init function that initialize whole PM8001 chip. - * @pm8001_ha: our hba card information - */ -static int __devinit pm8001_chip_init(struct pm8001_hba_info *pm8001_ha) -{ - /* check the firmware status */ - if (-1 == check_fw_ready(pm8001_ha)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Firmware is not ready!\n")); - return -EBUSY; - } - - /* Initialize pci space address eg: mpi offset */ - init_pci_device_addresses(pm8001_ha); - init_default_table_values(pm8001_ha); - read_main_config_table(pm8001_ha); - read_general_status_table(pm8001_ha); - read_inbnd_queue_table(pm8001_ha); - read_outbnd_queue_table(pm8001_ha); - /* update main config table ,inbound table and outbound table */ - update_main_config_table(pm8001_ha); - update_inbnd_queue_table(pm8001_ha, 0); - update_outbnd_queue_table(pm8001_ha, 0); - mpi_set_phys_g3_with_ssc(pm8001_ha, 0); - /* 7->130ms, 34->500ms, 119->1.5s */ - mpi_set_open_retry_interval_reg(pm8001_ha, 119); - /* notify firmware update finished and check initialization status */ - if (0 == mpi_init_check(pm8001_ha)) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MPI initialize successful!\n")); - } else - return -EBUSY; - /*This register is a 16-bit timer with a resolution of 1us. This is the - timer used for interrupt delay/coalescing in the PCIe Application Layer. - Zero is not a valid value. A value of 1 in the register will cause the - interrupts to be normal. A value greater than 1 will cause coalescing - delays.*/ - pm8001_cw32(pm8001_ha, 1, 0x0033c0, 0x1); - pm8001_cw32(pm8001_ha, 1, 0x0033c4, 0x0); - return 0; -} - -static int mpi_uninit_check(struct pm8001_hba_info *pm8001_ha) -{ - u32 max_wait_count; - u32 value; - u32 gst_len_mpistate; - init_pci_device_addresses(pm8001_ha); - /* Write bit1=1 to Inbound DoorBell Register to tell the SPC FW the - table is stop */ - pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPC_MSGU_CFG_TABLE_RESET); - - /* wait until Inbound DoorBell Clear Register toggled */ - max_wait_count = 1 * 1000 * 1000;/* 1 sec */ - do { - udelay(1); - value = pm8001_cr32(pm8001_ha, 0, MSGU_IBDB_SET); - value &= SPC_MSGU_CFG_TABLE_RESET; - } while ((value != 0) && (--max_wait_count)); - - if (!max_wait_count) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:IBDB value/=0x%x\n", value)); - return -1; - } - - /* check the MPI-State for termination in progress */ - /* wait until Inbound DoorBell Clear Register toggled */ - max_wait_count = 1 * 1000 * 1000; /* 1 sec */ - do { - udelay(1); - gst_len_mpistate = - pm8001_mr32(pm8001_ha->general_stat_tbl_addr, - GST_GSTLEN_MPIS_OFFSET); - if (GST_MPI_STATE_UNINIT == - (gst_len_mpistate & GST_MPI_STATE_MASK)) - break; - } while (--max_wait_count); - if (!max_wait_count) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk(" TIME OUT MPI State = 0x%x\n", - gst_len_mpistate & GST_MPI_STATE_MASK)); - return -1; - } - return 0; -} - -/** - * soft_reset_ready_check - Function to check FW is ready for soft reset. - * @pm8001_ha: our hba card information - */ -static u32 soft_reset_ready_check(struct pm8001_hba_info *pm8001_ha) -{ - u32 regVal, regVal1, regVal2; - if (mpi_uninit_check(pm8001_ha) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("MPI state is not ready\n")); - return -1; - } - /* read the scratch pad 2 register bit 2 */ - regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) - & SCRATCH_PAD2_FWRDY_RST; - if (regVal == SCRATCH_PAD2_FWRDY_RST) { - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Firmware is ready for reset .\n")); - } else { - unsigned long flags; - /* Trigger NMI twice via RB6 */ - spin_lock_irqsave(&pm8001_ha->lock, flags); - if (-1 == pm8001_bar4_shift(pm8001_ha, RB6_ACCESS_REG)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - RB6_ACCESS_REG)); - return -1; - } - pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET, - RB6_MAGIC_NUMBER_RST); - pm8001_cw32(pm8001_ha, 2, SPC_RB6_OFFSET, RB6_MAGIC_NUMBER_RST); - /* wait for 100 ms */ - mdelay(100); - regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2) & - SCRATCH_PAD2_FWRDY_RST; - if (regVal != SCRATCH_PAD2_FWRDY_RST) { - regVal1 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); - regVal2 = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:MSGU_SCRATCH_PAD1" - "=0x%x, MSGU_SCRATCH_PAD2=0x%x\n", - regVal1, regVal2)); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD0 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD3 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_3))); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return -1; - } - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - } - return 0; -} - -/** - * pm8001_chip_soft_rst - soft reset the PM8001 chip, so that the clear all - * the FW register status to the originated status. - * @pm8001_ha: our hba card information - * @signature: signature in host scratch pad0 register. - */ -static int -pm8001_chip_soft_rst(struct pm8001_hba_info *pm8001_ha, u32 signature) -{ - u32 regVal, toggleVal; - u32 max_wait_count; - u32 regVal1, regVal2, regVal3; - unsigned long flags; - - /* step1: Check FW is ready for soft reset */ - if (soft_reset_ready_check(pm8001_ha) != 0) { - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("FW is not ready\n")); - return -1; - } - - /* step 2: clear NMI status register on AAP1 and IOP, write the same - value to clear */ - /* map 0x60000 to BAR4(0x20), BAR2(win) */ - spin_lock_irqsave(&pm8001_ha->lock, flags); - if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_AAP1_ADDR_BASE)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - MBIC_AAP1_ADDR_BASE)); - return -1; - } - regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MBIC - NMI Enable VPE0 (IOP)= 0x%x\n", regVal)); - pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_IOP, 0x0); - /* map 0x70000 to BAR4(0x20), BAR2(win) */ - if (-1 == pm8001_bar4_shift(pm8001_ha, MBIC_IOP_ADDR_BASE)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - MBIC_IOP_ADDR_BASE)); - return -1; - } - regVal = pm8001_cr32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("MBIC - NMI Enable VPE0 (AAP1)= 0x%x\n", regVal)); - pm8001_cw32(pm8001_ha, 2, MBIC_NMI_ENABLE_VPE0_AAP1, 0x0); - - regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCIE -Event Interrupt Enable = 0x%x\n", regVal)); - pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT_ENABLE, 0x0); - - regVal = pm8001_cr32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCIE - Event Interrupt = 0x%x\n", regVal)); - pm8001_cw32(pm8001_ha, 1, PCIE_EVENT_INTERRUPT, regVal); - - regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCIE -Error Interrupt Enable = 0x%x\n", regVal)); - pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT_ENABLE, 0x0); - - regVal = pm8001_cr32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCIE - Error Interrupt = 0x%x\n", regVal)); - pm8001_cw32(pm8001_ha, 1, PCIE_ERROR_INTERRUPT, regVal); - - /* read the scratch pad 1 register bit 2 */ - regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1) - & SCRATCH_PAD1_RST; - toggleVal = regVal ^ SCRATCH_PAD1_RST; - - /* set signature in host scratch pad0 register to tell SPC that the - host performs the soft reset */ - pm8001_cw32(pm8001_ha, 0, MSGU_HOST_SCRATCH_PAD_0, signature); - - /* read required registers for confirmming */ - /* map 0x0700000 to BAR4(0x20), BAR2(win) */ - if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - GSM_ADDR_BASE)); - return -1; - } - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x0(0x00007b88)-GSM Configuration and" - " Reset = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET))); - - /* step 3: host read GSM Configuration and Reset register */ - regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET); - /* Put those bits to low */ - /* GSM XCBI offset = 0x70 0000 - 0x00 Bit 13 COM_SLV_SW_RSTB 1 - 0x00 Bit 12 QSSP_SW_RSTB 1 - 0x00 Bit 11 RAAE_SW_RSTB 1 - 0x00 Bit 9 RB_1_SW_RSTB 1 - 0x00 Bit 8 SM_SW_RSTB 1 - */ - regVal &= ~(0x00003b00); - /* host write GSM Configuration and Reset register */ - pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x0 (0x00007b88 ==> 0x00004088) - GSM " - "Configuration and Reset is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET))); - - /* step 4: */ - /* disable GSM - Read Address Parity Check */ - regVal1 = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700038 - Read Address Parity Check " - "Enable = 0x%x\n", regVal1)); - pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, 0x0); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700038 - Read Address Parity Check Enable" - "is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK))); - - /* disable GSM - Write Address Parity Check */ - regVal2 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700040 - Write Address Parity Check" - " Enable = 0x%x\n", regVal2)); - pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, 0x0); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700040 - Write Address Parity Check " - "Enable is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK))); - - /* disable GSM - Write Data Parity Check */ - regVal3 = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x300048 - Write Data Parity Check" - " Enable = 0x%x\n", regVal3)); - pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, 0x0); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x300048 - Write Data Parity Check Enable" - "is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK))); - - /* step 5: delay 10 usec */ - udelay(10); - /* step 5-b: set GPIO-0 output control to tristate anyway */ - if (-1 == pm8001_bar4_shift(pm8001_ha, GPIO_ADDR_BASE)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - GPIO_ADDR_BASE)); - return -1; - } - regVal = pm8001_cr32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GPIO Output Control Register:" - " = 0x%x\n", regVal)); - /* set GPIO-0 output control to tri-state */ - regVal &= 0xFFFFFFFC; - pm8001_cw32(pm8001_ha, 2, GPIO_GPIO_0_0UTPUT_CTL_OFFSET, regVal); - - /* Step 6: Reset the IOP and AAP1 */ - /* map 0x00000 to BAR4(0x20), BAR2(win) */ - if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SPC Shift Bar4 to 0x%x failed\n", - SPC_TOP_LEVEL_ADDR_BASE)); - return -1; - } - regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Top Register before resetting IOP/AAP1" - ":= 0x%x\n", regVal)); - regVal &= ~(SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS); - pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal); - - /* step 7: Reset the BDMA/OSSP */ - regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Top Register before resetting BDMA/OSSP" - ": = 0x%x\n", regVal)); - regVal &= ~(SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP); - pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal); - - /* step 8: delay 10 usec */ - udelay(10); - - /* step 9: bring the BDMA and OSSP out of reset */ - regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("Top Register before bringing up BDMA/OSSP" - ":= 0x%x\n", regVal)); - regVal |= (SPC_REG_RESET_BDMA_CORE | SPC_REG_RESET_OSSP); - pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal); - - /* step 10: delay 10 usec */ - udelay(10); - - /* step 11: reads and sets the GSM Configuration and Reset Register */ - /* map 0x0700000 to BAR4(0x20), BAR2(win) */ - if (-1 == pm8001_bar4_shift(pm8001_ha, GSM_ADDR_BASE)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SPC Shift Bar4 to 0x%x failed\n", - GSM_ADDR_BASE)); - return -1; - } - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x0 (0x00007b88)-GSM Configuration and " - "Reset = 0x%x\n", pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET))); - regVal = pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET); - /* Put those bits to high */ - /* GSM XCBI offset = 0x70 0000 - 0x00 Bit 13 COM_SLV_SW_RSTB 1 - 0x00 Bit 12 QSSP_SW_RSTB 1 - 0x00 Bit 11 RAAE_SW_RSTB 1 - 0x00 Bit 9 RB_1_SW_RSTB 1 - 0x00 Bit 8 SM_SW_RSTB 1 - */ - regVal |= (GSM_CONFIG_RESET_VALUE); - pm8001_cw32(pm8001_ha, 2, GSM_CONFIG_RESET, regVal); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM (0x00004088 ==> 0x00007b88) - GSM" - " Configuration and Reset is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_CONFIG_RESET))); - - /* step 12: Restore GSM - Read Address Parity Check */ - regVal = pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK); - /* just for debugging */ - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700038 - Read Address Parity Check Enable" - " = 0x%x\n", regVal)); - pm8001_cw32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK, regVal1); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700038 - Read Address Parity" - " Check Enable is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_READ_ADDR_PARITY_CHECK))); - /* Restore GSM - Write Address Parity Check */ - regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK); - pm8001_cw32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK, regVal2); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700040 - Write Address Parity Check" - " Enable is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_WRITE_ADDR_PARITY_CHECK))); - /* Restore GSM - Write Data Parity Check */ - regVal = pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK); - pm8001_cw32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK, regVal3); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("GSM 0x700048 - Write Data Parity Check Enable" - "is set to = 0x%x\n", - pm8001_cr32(pm8001_ha, 2, GSM_WRITE_DATA_PARITY_CHECK))); - - /* step 13: bring the IOP and AAP1 out of reset */ - /* map 0x00000 to BAR4(0x20), BAR2(win) */ - if (-1 == pm8001_bar4_shift(pm8001_ha, SPC_TOP_LEVEL_ADDR_BASE)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Shift Bar4 to 0x%x failed\n", - SPC_TOP_LEVEL_ADDR_BASE)); - return -1; - } - regVal = pm8001_cr32(pm8001_ha, 2, SPC_REG_RESET); - regVal |= (SPC_REG_RESET_PCS_IOP_SS | SPC_REG_RESET_PCS_AAP1_SS); - pm8001_cw32(pm8001_ha, 2, SPC_REG_RESET, regVal); - - /* step 14: delay 10 usec - Normal Mode */ - udelay(10); - /* check Soft Reset Normal mode or Soft Reset HDA mode */ - if (signature == SPC_SOFT_RESET_SIGNATURE) { - /* step 15 (Normal Mode): wait until scratch pad1 register - bit 2 toggled */ - max_wait_count = 2 * 1000 * 1000;/* 2 sec */ - do { - udelay(1); - regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1) & - SCRATCH_PAD1_RST; - } while ((regVal != toggleVal) && (--max_wait_count)); - - if (!max_wait_count) { - regVal = pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_1); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT : ToggleVal 0x%x," - "MSGU_SCRATCH_PAD1 = 0x%x\n", - toggleVal, regVal)); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD0 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_0))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD2 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_2))); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD3 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_3))); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return -1; - } - - /* step 16 (Normal) - Clear ODMR and ODCR */ - pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL); - pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL); - - /* step 17 (Normal Mode): wait for the FW and IOP to get - ready - 1 sec timeout */ - /* Wait for the SPC Configuration Table to be ready */ - if (check_fw_ready(pm8001_ha) == -1) { - regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_1); - /* return error if MPI Configuration Table not ready */ - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("FW not ready SCRATCH_PAD1" - " = 0x%x\n", regVal)); - regVal = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_2); - /* return error if MPI Configuration Table not ready */ - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("FW not ready SCRATCH_PAD2" - " = 0x%x\n", regVal)); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD0 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_0))); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SCRATCH_PAD3 value = 0x%x\n", - pm8001_cr32(pm8001_ha, 0, - MSGU_SCRATCH_PAD_3))); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return -1; - } - } - pm8001_bar4_shift(pm8001_ha, 0); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("SPC soft reset Complete\n")); - return 0; -} - -static void pm8001_hw_chip_rst(struct pm8001_hba_info *pm8001_ha) -{ - u32 i; - u32 regVal; - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("chip reset start\n")); - - /* do SPC chip reset. */ - regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET); - regVal &= ~(SPC_REG_RESET_DEVICE); - pm8001_cw32(pm8001_ha, 1, SPC_REG_RESET, regVal); - - /* delay 10 usec */ - udelay(10); - - /* bring chip reset out of reset */ - regVal = pm8001_cr32(pm8001_ha, 1, SPC_REG_RESET); - regVal |= SPC_REG_RESET_DEVICE; - pm8001_cw32(pm8001_ha, 1, SPC_REG_RESET, regVal); - - /* delay 10 usec */ - udelay(10); - - /* wait for 20 msec until the firmware gets reloaded */ - i = 20; - do { - mdelay(1); - } while ((--i) != 0); - - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("chip reset finished\n")); -} - -/** - * pm8001_chip_iounmap - which maped when initialized. - * @pm8001_ha: our hba card information - */ -static void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha) -{ - s8 bar, logical = 0; - for (bar = 0; bar < 6; bar++) { - /* - ** logical BARs for SPC: - ** bar 0 and 1 - logical BAR0 - ** bar 2 and 3 - logical BAR1 - ** bar4 - logical BAR2 - ** bar5 - logical BAR3 - ** Skip the appropriate assignments: - */ - if ((bar == 1) || (bar == 3)) - continue; - if (pm8001_ha->io_mem[logical].memvirtaddr) { - iounmap(pm8001_ha->io_mem[logical].memvirtaddr); - logical++; - } - } -} - -/** - * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt - * @pm8001_ha: our hba card information - */ -static void -pm8001_chip_intx_interrupt_enable(struct pm8001_hba_info *pm8001_ha) -{ - pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_CLEAR_ALL); - pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, ODCR_CLEAR_ALL); -} - - /** - * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt - * @pm8001_ha: our hba card information - */ -static void -pm8001_chip_intx_interrupt_disable(struct pm8001_hba_info *pm8001_ha) -{ - pm8001_cw32(pm8001_ha, 0, MSGU_ODMR, ODMR_MASK_ALL); -} - -/** - * pm8001_chip_msix_interrupt_enable - enable PM8001 chip interrupt - * @pm8001_ha: our hba card information - */ -static void -pm8001_chip_msix_interrupt_enable(struct pm8001_hba_info *pm8001_ha, - u32 int_vec_idx) -{ - u32 msi_index; - u32 value; - msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE; - msi_index += MSIX_TABLE_BASE; - pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_ENABLE); - value = (1 << int_vec_idx); - pm8001_cw32(pm8001_ha, 0, MSGU_ODCR, value); - -} - -/** - * pm8001_chip_msix_interrupt_disable - disable PM8001 chip interrupt - * @pm8001_ha: our hba card information - */ -static void -pm8001_chip_msix_interrupt_disable(struct pm8001_hba_info *pm8001_ha, - u32 int_vec_idx) -{ - u32 msi_index; - msi_index = int_vec_idx * MSIX_TABLE_ELEMENT_SIZE; - msi_index += MSIX_TABLE_BASE; - pm8001_cw32(pm8001_ha, 0, msi_index, MSIX_INTERRUPT_DISABLE); -} - -/** - * pm8001_chip_interrupt_enable - enable PM8001 chip interrupt - * @pm8001_ha: our hba card information - */ -static void -pm8001_chip_interrupt_enable(struct pm8001_hba_info *pm8001_ha) -{ -#ifdef PM8001_USE_MSIX - pm8001_chip_msix_interrupt_enable(pm8001_ha, 0); - return; -#endif - pm8001_chip_intx_interrupt_enable(pm8001_ha); - -} - -/** - * pm8001_chip_intx_interrupt_disable- disable PM8001 chip interrupt - * @pm8001_ha: our hba card information - */ -static void -pm8001_chip_interrupt_disable(struct pm8001_hba_info *pm8001_ha) -{ -#ifdef PM8001_USE_MSIX - pm8001_chip_msix_interrupt_disable(pm8001_ha, 0); - return; -#endif - pm8001_chip_intx_interrupt_disable(pm8001_ha); - -} - -/** - * mpi_msg_free_get- get the free message buffer for transfer inbound queue. - * @circularQ: the inbound queue we want to transfer to HBA. - * @messageSize: the message size of this transfer, normally it is 64 bytes - * @messagePtr: the pointer to message. - */ -static int mpi_msg_free_get(struct inbound_queue_table *circularQ, - u16 messageSize, void **messagePtr) -{ - u32 offset, consumer_index; - struct mpi_msg_hdr *msgHeader; - u8 bcCount = 1; /* only support single buffer */ - - /* Checks is the requested message size can be allocated in this queue*/ - if (messageSize > 64) { - *messagePtr = NULL; - return -1; - } - - /* Stores the new consumer index */ - consumer_index = pm8001_read_32(circularQ->ci_virt); - circularQ->consumer_index = cpu_to_le32(consumer_index); - if (((circularQ->producer_idx + bcCount) % 256) == - le32_to_cpu(circularQ->consumer_index)) { - *messagePtr = NULL; - return -1; - } - /* get memory IOMB buffer address */ - offset = circularQ->producer_idx * 64; - /* increment to next bcCount element */ - circularQ->producer_idx = (circularQ->producer_idx + bcCount) % 256; - /* Adds that distance to the base of the region virtual address plus - the message header size*/ - msgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt + offset); - *messagePtr = ((void *)msgHeader) + sizeof(struct mpi_msg_hdr); - return 0; -} - -/** - * mpi_build_cmd- build the message queue for transfer, update the PI to FW - * to tell the fw to get this message from IOMB. - * @pm8001_ha: our hba card information - * @circularQ: the inbound queue we want to transfer to HBA. - * @opCode: the operation code represents commands which LLDD and fw recognized. - * @payload: the command payload of each operation command. - */ -static int mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, - struct inbound_queue_table *circularQ, - u32 opCode, void *payload) -{ - u32 Header = 0, hpriority = 0, bc = 1, category = 0x02; - u32 responseQueue = 0; - void *pMessage; - - if (mpi_msg_free_get(circularQ, 64, &pMessage) < 0) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("No free mpi buffer\n")); - return -1; - } - BUG_ON(!payload); - /*Copy to the payload*/ - memcpy(pMessage, payload, (64 - sizeof(struct mpi_msg_hdr))); - - /*Build the header*/ - Header = ((1 << 31) | (hpriority << 30) | ((bc & 0x1f) << 24) - | ((responseQueue & 0x3F) << 16) - | ((category & 0xF) << 12) | (opCode & 0xFFF)); - - pm8001_write_32((pMessage - 4), 0, cpu_to_le32(Header)); - /*Update the PI to the firmware*/ - pm8001_cw32(pm8001_ha, circularQ->pi_pci_bar, - circularQ->pi_offset, circularQ->producer_idx); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("after PI= %d CI= %d\n", circularQ->producer_idx, - circularQ->consumer_index)); - return 0; -} - -static u32 mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg, - struct outbound_queue_table *circularQ, u8 bc) -{ - u32 producer_index; - struct mpi_msg_hdr *msgHeader; - struct mpi_msg_hdr *pOutBoundMsgHeader; - - msgHeader = (struct mpi_msg_hdr *)(pMsg - sizeof(struct mpi_msg_hdr)); - pOutBoundMsgHeader = (struct mpi_msg_hdr *)(circularQ->base_virt + - circularQ->consumer_idx * 64); - if (pOutBoundMsgHeader != msgHeader) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("consumer_idx = %d msgHeader = %p\n", - circularQ->consumer_idx, msgHeader)); - - /* Update the producer index from SPC */ - producer_index = pm8001_read_32(circularQ->pi_virt); - circularQ->producer_index = cpu_to_le32(producer_index); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("consumer_idx = %d producer_index = %d" - "msgHeader = %p\n", circularQ->consumer_idx, - circularQ->producer_index, msgHeader)); - return 0; - } - /* free the circular queue buffer elements associated with the message*/ - circularQ->consumer_idx = (circularQ->consumer_idx + bc) % 256; - /* update the CI of outbound queue */ - pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar, circularQ->ci_offset, - circularQ->consumer_idx); - /* Update the producer index from SPC*/ - producer_index = pm8001_read_32(circularQ->pi_virt); - circularQ->producer_index = cpu_to_le32(producer_index); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(" CI=%d PI=%d\n", circularQ->consumer_idx, - circularQ->producer_index)); - return 0; -} - -/** - * mpi_msg_consume- get the MPI message from outbound queue message table. - * @pm8001_ha: our hba card information - * @circularQ: the outbound queue table. - * @messagePtr1: the message contents of this outbound message. - * @pBC: the message size. - */ -static u32 mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, - struct outbound_queue_table *circularQ, - void **messagePtr1, u8 *pBC) -{ - struct mpi_msg_hdr *msgHeader; - __le32 msgHeader_tmp; - u32 header_tmp; - do { - /* If there are not-yet-delivered messages ... */ - if (le32_to_cpu(circularQ->producer_index) - != circularQ->consumer_idx) { - /*Get the pointer to the circular queue buffer element*/ - msgHeader = (struct mpi_msg_hdr *) - (circularQ->base_virt + - circularQ->consumer_idx * 64); - /* read header */ - header_tmp = pm8001_read_32(msgHeader); - msgHeader_tmp = cpu_to_le32(header_tmp); - if (0 != (le32_to_cpu(msgHeader_tmp) & 0x80000000)) { - if (OPC_OUB_SKIP_ENTRY != - (le32_to_cpu(msgHeader_tmp) & 0xfff)) { - *messagePtr1 = - ((u8 *)msgHeader) + - sizeof(struct mpi_msg_hdr); - *pBC = (u8)((le32_to_cpu(msgHeader_tmp) - >> 24) & 0x1f); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(": CI=%d PI=%d " - "msgHeader=%x\n", - circularQ->consumer_idx, - circularQ->producer_index, - msgHeader_tmp)); - return MPI_IO_STATUS_SUCCESS; - } else { - circularQ->consumer_idx = - (circularQ->consumer_idx + - ((le32_to_cpu(msgHeader_tmp) - >> 24) & 0x1f)) % 256; - msgHeader_tmp = 0; - pm8001_write_32(msgHeader, 0, 0); - /* update the CI of outbound queue */ - pm8001_cw32(pm8001_ha, - circularQ->ci_pci_bar, - circularQ->ci_offset, - circularQ->consumer_idx); - } - } else { - circularQ->consumer_idx = - (circularQ->consumer_idx + - ((le32_to_cpu(msgHeader_tmp) >> 24) & - 0x1f)) % 256; - msgHeader_tmp = 0; - pm8001_write_32(msgHeader, 0, 0); - /* update the CI of outbound queue */ - pm8001_cw32(pm8001_ha, circularQ->ci_pci_bar, - circularQ->ci_offset, - circularQ->consumer_idx); - return MPI_IO_STATUS_FAIL; - } - } else { - u32 producer_index; - void *pi_virt = circularQ->pi_virt; - /* Update the producer index from SPC */ - producer_index = pm8001_read_32(pi_virt); - circularQ->producer_index = cpu_to_le32(producer_index); - } - } while (le32_to_cpu(circularQ->producer_index) != - circularQ->consumer_idx); - /* while we don't have any more not-yet-delivered message */ - /* report empty */ - return MPI_IO_STATUS_BUSY; -} - -static void pm8001_work_fn(struct work_struct *work) -{ - struct pm8001_work *pw = container_of(work, struct pm8001_work, work); - struct pm8001_device *pm8001_dev; - struct domain_device *dev; - - /* - * So far, all users of this stash an associated structure here. - * If we get here, and this pointer is null, then the action - * was cancelled. This nullification happens when the device - * goes away. - */ - pm8001_dev = pw->data; /* Most stash device structure */ - if ((pm8001_dev == NULL) - || ((pw->handler != IO_XFER_ERROR_BREAK) - && (pm8001_dev->dev_type == NO_DEVICE))) { - kfree(pw); - return; - } - - switch (pw->handler) { - case IO_XFER_ERROR_BREAK: - { /* This one stashes the sas_task instead */ - struct sas_task *t = (struct sas_task *)pm8001_dev; - u32 tag; - struct pm8001_ccb_info *ccb; - struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha; - unsigned long flags, flags1; - struct task_status_struct *ts; - int i; - - if (pm8001_query_task(t) == TMF_RESP_FUNC_SUCC) - break; /* Task still on lu */ - spin_lock_irqsave(&pm8001_ha->lock, flags); - - spin_lock_irqsave(&t->task_state_lock, flags1); - if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) { - spin_unlock_irqrestore(&t->task_state_lock, flags1); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - break; /* Task got completed by another */ - } - spin_unlock_irqrestore(&t->task_state_lock, flags1); - - /* Search for a possible ccb that matches the task */ - for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) { - ccb = &pm8001_ha->ccb_info[i]; - tag = ccb->ccb_tag; - if ((tag != 0xFFFFFFFF) && (ccb->task == t)) - break; - } - if (!ccb) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - break; /* Task got freed by another */ - } - ts = &t->task_status; - ts->resp = SAS_TASK_COMPLETE; - /* Force the midlayer to retry */ - ts->stat = SAS_QUEUE_FULL; - pm8001_dev = ccb->device; - if (pm8001_dev) - pm8001_dev->running_req--; - spin_lock_irqsave(&t->task_state_lock, flags1); - t->task_state_flags &= ~SAS_TASK_STATE_PENDING; - t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - t->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&t->task_state_lock, flags1); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p" - " done with event 0x%x resp 0x%x stat 0x%x but" - " aborted by upper layer!\n", - t, pw->handler, ts->resp, ts->stat)); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - } else { - spin_unlock_irqrestore(&t->task_state_lock, flags1); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/* in order to force CPU ordering */ - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - t->task_done(t); - } - } break; - case IO_XFER_OPEN_RETRY_TIMEOUT: - { /* This one stashes the sas_task instead */ - struct sas_task *t = (struct sas_task *)pm8001_dev; - u32 tag; - struct pm8001_ccb_info *ccb; - struct pm8001_hba_info *pm8001_ha = pw->pm8001_ha; - unsigned long flags, flags1; - int i, ret = 0; - - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); - - ret = pm8001_query_task(t); - - PM8001_IO_DBG(pm8001_ha, - switch (ret) { - case TMF_RESP_FUNC_SUCC: - pm8001_printk("...Task on lu\n"); - break; - - case TMF_RESP_FUNC_COMPLETE: - pm8001_printk("...Task NOT on lu\n"); - break; - - default: - pm8001_printk("...query task failed!!!\n"); - break; - }); - - spin_lock_irqsave(&pm8001_ha->lock, flags); - - spin_lock_irqsave(&t->task_state_lock, flags1); - - if (unlikely((t->task_state_flags & SAS_TASK_STATE_DONE))) { - spin_unlock_irqrestore(&t->task_state_lock, flags1); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */ - (void)pm8001_abort_task(t); - break; /* Task got completed by another */ - } - - spin_unlock_irqrestore(&t->task_state_lock, flags1); - - /* Search for a possible ccb that matches the task */ - for (i = 0; ccb = NULL, i < PM8001_MAX_CCB; i++) { - ccb = &pm8001_ha->ccb_info[i]; - tag = ccb->ccb_tag; - if ((tag != 0xFFFFFFFF) && (ccb->task == t)) - break; - } - if (!ccb) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - if (ret == TMF_RESP_FUNC_SUCC) /* task on lu */ - (void)pm8001_abort_task(t); - break; /* Task got freed by another */ - } - - pm8001_dev = ccb->device; - dev = pm8001_dev->sas_device; - - switch (ret) { - case TMF_RESP_FUNC_SUCC: /* task on lu */ - ccb->open_retry = 1; /* Snub completion */ - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - ret = pm8001_abort_task(t); - ccb->open_retry = 0; - switch (ret) { - case TMF_RESP_FUNC_SUCC: - case TMF_RESP_FUNC_COMPLETE: - break; - default: /* device misbehavior */ - ret = TMF_RESP_FUNC_FAILED; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("...Reset phy\n")); - pm8001_I_T_nexus_reset(dev); - break; - } - break; - - case TMF_RESP_FUNC_COMPLETE: /* task not on lu */ - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - /* Do we need to abort the task locally? */ - break; - - default: /* device misbehavior */ - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - ret = TMF_RESP_FUNC_FAILED; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("...Reset phy\n")); - pm8001_I_T_nexus_reset(dev); - } - - if (ret == TMF_RESP_FUNC_FAILED) - t = NULL; - pm8001_open_reject_retry(pm8001_ha, t, pm8001_dev); - PM8001_IO_DBG(pm8001_ha, pm8001_printk("...Complete\n")); - } break; - case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - dev = pm8001_dev->sas_device; - pm8001_I_T_nexus_reset(dev); - break; - case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: - dev = pm8001_dev->sas_device; - pm8001_I_T_nexus_reset(dev); - break; - case IO_DS_IN_ERROR: - dev = pm8001_dev->sas_device; - pm8001_I_T_nexus_reset(dev); - break; - case IO_DS_NON_OPERATIONAL: - dev = pm8001_dev->sas_device; - pm8001_I_T_nexus_reset(dev); - break; - } - kfree(pw); -} - -static int pm8001_handle_event(struct pm8001_hba_info *pm8001_ha, void *data, - int handler) -{ - struct pm8001_work *pw; - int ret = 0; - - pw = kmalloc(sizeof(struct pm8001_work), GFP_ATOMIC); - if (pw) { - pw->pm8001_ha = pm8001_ha; - pw->data = data; - pw->handler = handler; - INIT_WORK(&pw->work, pm8001_work_fn); - queue_work(pm8001_wq, &pw->work); - } else - ret = -ENOMEM; - - return ret; -} - -/** - * mpi_ssp_completion- process the event that FW response to the SSP request. - * @pm8001_ha: our hba card information - * @piomb: the message contents of this outbound message. - * - * When FW has completed a ssp request for example a IO request, after it has - * filled the SG data with the data, it will trigger this event represent - * that he has finished the job,please check the coresponding buffer. - * So we will tell the caller who maybe waiting the result to tell upper layer - * that the task has been finished. - */ -static void -mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) -{ - struct sas_task *t; - struct pm8001_ccb_info *ccb; - unsigned long flags; - u32 status; - u32 param; - u32 tag; - struct ssp_completion_resp *psspPayload; - struct task_status_struct *ts; - struct ssp_response_iu *iu; - struct pm8001_device *pm8001_dev; - psspPayload = (struct ssp_completion_resp *)(piomb + 4); - status = le32_to_cpu(psspPayload->status); - tag = le32_to_cpu(psspPayload->tag); - ccb = &pm8001_ha->ccb_info[tag]; - if ((status == IO_ABORTED) && ccb->open_retry) { - /* Being completed by another */ - ccb->open_retry = 0; - return; - } - pm8001_dev = ccb->device; - param = le32_to_cpu(psspPayload->param); - - t = ccb->task; - - if (status && status != IO_UNDERFLOW) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sas IO status 0x%x\n", status)); - if (unlikely(!t || !t->lldd_task || !t->dev)) - return; - ts = &t->task_status; - switch (status) { - case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS" - ",param = %d\n", param)); - if (param == 0) { - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_STAT_GOOD; - } else { - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_PROTO_RESPONSE; - ts->residual = param; - iu = &psspPayload->ssp_resp_iu; - sas_ssp_task_response(pm8001_ha->dev, t, iu); - } - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB Tag\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_ABORTED_TASK; - break; - case IO_UNDERFLOW: - /* SSP Completion with error */ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW" - ",param = %d\n", param)); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_UNDERRUN; - ts->residual = param; - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_NO_DEVICE\n")); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - break; - case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - /* Force the midlayer to retry */ - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_EPROTO; - break; - case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - break; - case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - if (!t->uldd_task) - pm8001_handle_event(pm8001_ha, - pm8001_dev, - IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); - break; - case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_BAD_DEST; - break; - case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_CONN_RATE; - break; - case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_WRONG_DEST; - break; - case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_NAK_R_ERR; - break; - case IO_XFER_ERROR_DMA: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_DMA\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - break; - case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - break; - case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - break; - case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - if (!t->uldd_task) - pm8001_handle_event(pm8001_ha, - pm8001_dev, - IO_DS_NON_OPERATIONAL); - break; - case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_RECOVERY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - break; - case IO_TM_TAG_NOT_FOUND: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_TM_TAG_NOT_FOUND\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - break; - case IO_SSP_EXT_IU_ZERO_LEN_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_SSP_EXT_IU_ZERO_LEN_ERROR\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - break; - case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - default: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); - /* not allowed case. Therefore, return failed status */ - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - break; - } - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("scsi_status = %x \n ", - psspPayload->ssp_resp_iu.status)); - spin_lock_irqsave(&t->task_state_lock, flags); - t->task_state_flags &= ~SAS_TASK_STATE_PENDING; - t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - t->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with" - " io_status 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - } else { - spin_unlock_irqrestore(&t->task_state_lock, flags); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/* in order to force CPU ordering */ - t->task_done(t); - } -} - -/*See the comments for mpi_ssp_completion */ -static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) -{ - struct sas_task *t; - unsigned long flags; - struct task_status_struct *ts; - struct pm8001_ccb_info *ccb; - struct pm8001_device *pm8001_dev; - struct ssp_event_resp *psspPayload = - (struct ssp_event_resp *)(piomb + 4); - u32 event = le32_to_cpu(psspPayload->event); - u32 tag = le32_to_cpu(psspPayload->tag); - u32 port_id = le32_to_cpu(psspPayload->port_id); - u32 dev_id = le32_to_cpu(psspPayload->device_id); - - ccb = &pm8001_ha->ccb_info[tag]; - t = ccb->task; - pm8001_dev = ccb->device; - if (event) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sas IO status 0x%x\n", event)); - if (unlikely(!t || !t->lldd_task || !t->dev)) - return; - ts = &t->task_status; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("port_id = %x,device_id = %x\n", - port_id, dev_id)); - switch (event) { - case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n");) - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - ts->residual = 0; - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); - pm8001_handle_event(pm8001_ha, t, IO_XFER_ERROR_BREAK); - return; - case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT" - "_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_EPROTO; - break; - case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - break; - case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - if (!t->uldd_task) - pm8001_handle_event(pm8001_ha, - pm8001_dev, - IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); - break; - case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_BAD_DEST; - break; - case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_CONN_RATE; - break; - case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_WRONG_DEST; - break; - case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_NAK_R_ERR; - break; - case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); - pm8001_handle_event(pm8001_ha, t, IO_XFER_OPEN_RETRY_TIMEOUT); - return; - case IO_XFER_ERROR_UNEXPECTED_PHASE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - break; - case IO_XFER_ERROR_XFER_RDY_OVERRUN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_OVERRUN\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - break; - case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - break; - case IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - break; - case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - break; - case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - break; - case IO_XFER_CMD_FRAME_ISSUED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(" IO_XFER_CMD_FRAME_ISSUED\n")); - return; - default: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", event)); - /* not allowed case. Therefore, return failed status */ - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - break; - } - spin_lock_irqsave(&t->task_state_lock, flags); - t->task_state_flags &= ~SAS_TASK_STATE_PENDING; - t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - t->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with" - " event 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - t, event, ts->resp, ts->stat)); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - } else { - spin_unlock_irqrestore(&t->task_state_lock, flags); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/* in order to force CPU ordering */ - t->task_done(t); - } -} - -/*See the comments for mpi_ssp_completion */ -static void -mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct sas_task *t; - struct pm8001_ccb_info *ccb; - u32 param; - u32 status; - u32 tag; - struct sata_completion_resp *psataPayload; - struct task_status_struct *ts; - struct ata_task_resp *resp ; - u32 *sata_resp; - struct pm8001_device *pm8001_dev; - unsigned long flags; - - psataPayload = (struct sata_completion_resp *)(piomb + 4); - status = le32_to_cpu(psataPayload->status); - tag = le32_to_cpu(psataPayload->tag); - - ccb = &pm8001_ha->ccb_info[tag]; - param = le32_to_cpu(psataPayload->param); - t = ccb->task; - ts = &t->task_status; - pm8001_dev = ccb->device; - if (status) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sata IO status 0x%x\n", status)); - if (unlikely(!t || !t->lldd_task || !t->dev)) - return; - - switch (status) { - case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); - if (param == 0) { - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_STAT_GOOD; - } else { - u8 len; - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_PROTO_RESPONSE; - ts->residual = param; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("SAS_PROTO_RESPONSE len = %d\n", - param)); - sata_resp = &psataPayload->sata_resp[0]; - resp = (struct ata_task_resp *)ts->buf; - if (t->ata_task.dma_xfer == 0 && - t->data_dir == PCI_DMA_FROMDEVICE) { - len = sizeof(struct pio_setup_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("PIO read len = %d\n", len)); - } else if (t->ata_task.use_ncq) { - len = sizeof(struct set_dev_bits_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("FPDMA len = %d\n", len)); - } else { - len = sizeof(struct dev_to_host_fis); - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("other len = %d\n", len)); - } - if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { - resp->frame_len = len; - memcpy(&resp->ending_fis[0], sata_resp, len); - ts->buf_valid_size = sizeof(*resp); - } else - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("response to large\n")); - } - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB Tag\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_ABORTED_TASK; - if (pm8001_dev) - pm8001_dev->running_req--; - break; - /* following cases are to do cases */ - case IO_UNDERFLOW: - /* SATA Completion with error */ - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_UNDERFLOW param = %d\n", param)); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_UNDERRUN; - ts->residual = param; - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_NO_DEVICE\n")); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - break; - case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_INTERRUPTED; - break; - case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT" - "_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_EPROTO; - break; - case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - break; - case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; - break; - case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - if (!t->uldd_task) { - pm8001_handle_event(pm8001_ha, - pm8001_dev, - IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_QUEUE_FULL; - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/*in order to force CPU ordering*/ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - return; - } - break; - case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_BAD_DEST; - if (!t->uldd_task) { - pm8001_handle_event(pm8001_ha, - pm8001_dev, - IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_QUEUE_FULL; - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/*ditto*/ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - return; - } - break; - case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_CONN_RATE; - break; - case IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_STP_RESOURCES" - "_BUSY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - if (!t->uldd_task) { - pm8001_handle_event(pm8001_ha, - pm8001_dev, - IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_QUEUE_FULL; - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/* ditto*/ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - return; - } - break; - case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_WRONG_DEST; - break; - case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_NAK_R_ERR; - break; - case IO_XFER_ERROR_ACK_NAK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_ACK_NAK_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_NAK_R_ERR; - break; - case IO_XFER_ERROR_DMA: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_DMA\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_ABORTED_TASK; - break; - case IO_XFER_ERROR_SATA_LINK_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_SATA_LINK_TIMEOUT\n")); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_DEV_NO_RESPONSE; - break; - case IO_XFER_ERROR_REJECTED_NCQ_MODE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_REJECTED_NCQ_MODE\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_UNDERRUN; - break; - case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - break; - case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - if (!t->uldd_task) { - pm8001_handle_event(pm8001_ha, pm8001_dev, - IO_DS_NON_OPERATIONAL); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_QUEUE_FULL; - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/*ditto*/ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - return; - } - break; - case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(" IO_DS_IN_RECOVERY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - break; - case IO_DS_IN_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_ERROR\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - if (!t->uldd_task) { - pm8001_handle_event(pm8001_ha, pm8001_dev, - IO_DS_IN_ERROR); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_QUEUE_FULL; - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/*ditto*/ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - return; - } - break; - case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - default: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); - /* not allowed case. Therefore, return failed status */ - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - break; - } - spin_lock_irqsave(&t->task_state_lock, flags); - t->task_state_flags &= ~SAS_TASK_STATE_PENDING; - t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - t->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task 0x%p done with io_status 0x%x" - " resp 0x%x stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - } else if (t->uldd_task) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/* ditto */ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - } else if (!t->uldd_task) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/*ditto*/ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - } -} - -/*See the comments for mpi_ssp_completion */ -static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) -{ - struct sas_task *t; - struct task_status_struct *ts; - struct pm8001_ccb_info *ccb; - struct pm8001_device *pm8001_dev; - struct sata_event_resp *psataPayload = - (struct sata_event_resp *)(piomb + 4); - u32 event = le32_to_cpu(psataPayload->event); - u32 tag = le32_to_cpu(psataPayload->tag); - u32 port_id = le32_to_cpu(psataPayload->port_id); - u32 dev_id = le32_to_cpu(psataPayload->device_id); - unsigned long flags; - - ccb = &pm8001_ha->ccb_info[tag]; - t = ccb->task; - pm8001_dev = ccb->device; - if (event) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("sata IO status 0x%x\n", event)); - if (unlikely(!t || !t->lldd_task || !t->dev)) - return; - ts = &t->task_status; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("port_id = %x,device_id = %x\n", - port_id, dev_id)); - switch (event) { - case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - ts->residual = 0; - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_INTERRUPTED; - break; - case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT" - "_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_EPROTO; - break; - case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - break; - case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; - break; - case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_DEV_NO_RESPONSE; - if (!t->uldd_task) { - pm8001_handle_event(pm8001_ha, - pm8001_dev, - IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_QUEUE_FULL; - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/*ditto*/ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - return; - } - break; - case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_BAD_DEST; - break; - case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_CONN_RATE; - break; - case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_WRONG_DEST; - break; - case IO_XFER_ERROR_NAK_RECEIVED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_NAK_RECEIVED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_NAK_R_ERR; - break; - case IO_XFER_ERROR_PEER_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PEER_ABORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_NAK_R_ERR; - break; - case IO_XFER_ERROR_REJECTED_NCQ_MODE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_REJECTED_NCQ_MODE\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_UNDERRUN; - break; - case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - case IO_XFER_ERROR_UNEXPECTED_PHASE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_UNEXPECTED_PHASE\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - case IO_XFER_ERROR_XFER_RDY_OVERRUN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_OVERRUN\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - case IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - case IO_XFER_ERROR_OFFSET_MISMATCH: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_OFFSET_MISMATCH\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - case IO_XFER_ERROR_XFER_ZERO_DATA_LEN: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_XFER_ZERO_DATA_LEN\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - case IO_XFER_CMD_FRAME_ISSUED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_CMD_FRAME_ISSUED\n")); - break; - case IO_XFER_PIO_SETUP_ERROR: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_PIO_SETUP_ERROR\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - default: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", event)); - /* not allowed case. Therefore, return failed status */ - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_TO; - break; - } - spin_lock_irqsave(&t->task_state_lock, flags); - t->task_state_flags &= ~SAS_TASK_STATE_PENDING; - t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - t->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task 0x%p done with io_status 0x%x" - " resp 0x%x stat 0x%x but aborted by upper layer!\n", - t, event, ts->resp, ts->stat)); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - } else if (t->uldd_task) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/* ditto */ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - } else if (!t->uldd_task) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/*ditto*/ - spin_unlock_irq(&pm8001_ha->lock); - t->task_done(t); - spin_lock_irq(&pm8001_ha->lock); - } -} - -/*See the comments for mpi_ssp_completion */ -static void -mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - u32 param; - struct sas_task *t; - struct pm8001_ccb_info *ccb; - unsigned long flags; - u32 status; - u32 tag; - struct smp_completion_resp *psmpPayload; - struct task_status_struct *ts; - struct pm8001_device *pm8001_dev; - - psmpPayload = (struct smp_completion_resp *)(piomb + 4); - status = le32_to_cpu(psmpPayload->status); - tag = le32_to_cpu(psmpPayload->tag); - - ccb = &pm8001_ha->ccb_info[tag]; - param = le32_to_cpu(psmpPayload->param); - t = ccb->task; - ts = &t->task_status; - pm8001_dev = ccb->device; - if (status) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("smp IO status 0x%x\n", status)); - if (unlikely(!t || !t->lldd_task || !t->dev)) - return; - - switch (status) { - case IO_SUCCESS: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_STAT_GOOD; - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_ABORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ABORTED IOMB\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_ABORTED_TASK; - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_OVERFLOW: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_UNDERFLOW\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DATA_OVERRUN; - ts->residual = 0; - if (pm8001_dev) - pm8001_dev->running_req--; - break; - case IO_NO_DEVICE: - PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_NO_DEVICE\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_PHY_DOWN; - break; - case IO_ERROR_HW_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ERROR_HW_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_STAT_BUSY; - break; - case IO_XFER_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_STAT_BUSY; - break; - case IO_XFER_ERROR_PHY_NOT_READY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_PHY_NOT_READY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_STAT_BUSY; - break; - case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - break; - case IO_OPEN_CNX_ERROR_ZONE_VIOLATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_ZONE_VIOLATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - break; - case IO_OPEN_CNX_ERROR_BREAK: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BREAK\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_CONT0; - break; - case IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_UNKNOWN; - pm8001_handle_event(pm8001_ha, - pm8001_dev, - IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS); - break; - case IO_OPEN_CNX_ERROR_BAD_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_BAD_DESTINATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_BAD_DEST; - break; - case IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_CONNECTION_RATE_" - "NOT_SUPPORTED\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_CONN_RATE; - break; - case IO_OPEN_CNX_ERROR_WRONG_DESTINATION: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_WRONG_DESTINATION\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_WRONG_DEST; - break; - case IO_XFER_ERROR_RX_FRAME: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_ERROR_RX_FRAME\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - break; - case IO_XFER_OPEN_RETRY_TIMEOUT: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_XFER_OPEN_RETRY_TIMEOUT\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_ERROR_INTERNAL_SMP_RESOURCE: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_ERROR_INTERNAL_SMP_RESOURCE\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_QUEUE_FULL; - break; - case IO_PORT_IN_RESET: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_PORT_IN_RESET\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_DS_NON_OPERATIONAL: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_NON_OPERATIONAL\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - break; - case IO_DS_IN_RECOVERY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_DS_IN_RECOVERY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - case IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - break; - default: - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("Unknown status 0x%x\n", status)); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAS_DEV_NO_RESPONSE; - /* not allowed case. Therefore, return failed status */ - break; - } - spin_lock_irqsave(&t->task_state_lock, flags); - t->task_state_flags &= ~SAS_TASK_STATE_PENDING; - t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - t->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((t->task_state_flags & SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&t->task_state_lock, flags); - PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("task 0x%p done with" - " io_status 0x%x resp 0x%x " - "stat 0x%x but aborted by upper layer!\n", - t, status, ts->resp, ts->stat)); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - } else { - spin_unlock_irqrestore(&t->task_state_lock, flags); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb();/* in order to force CPU ordering */ - t->task_done(t); - } -} - -static void -mpi_set_dev_state_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct set_dev_state_resp *pPayload = - (struct set_dev_state_resp *)(piomb + 4); - u32 tag = le32_to_cpu(pPayload->tag); - struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag]; - struct pm8001_device *pm8001_dev = ccb->device; - u32 status = le32_to_cpu(pPayload->status); - u32 device_id = le32_to_cpu(pPayload->device_id); - u8 pds = le32_to_cpu(pPayload->pds_nds) | PDS_BITS; - u8 nds = le32_to_cpu(pPayload->pds_nds) | NDS_BITS; - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Set device id = 0x%x state " - "from 0x%x to 0x%x status = 0x%x!\n", - device_id, pds, nds, status)); - complete(pm8001_dev->setds_completion); - ccb->task = NULL; - ccb->ccb_tag = 0xFFFFFFFF; - pm8001_ccb_free(pm8001_ha, tag); -} - -static void -mpi_set_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct get_nvm_data_resp *pPayload = - (struct get_nvm_data_resp *)(piomb + 4); - u32 tag = le32_to_cpu(pPayload->tag); - struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag]; - u32 dlen_status = le32_to_cpu(pPayload->dlen_status); - complete(pm8001_ha->nvmd_completion); - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Set nvm data complete!\n")); - if ((dlen_status & NVMD_STAT) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Set nvm data error!\n")); - return; - } - ccb->task = NULL; - ccb->ccb_tag = 0xFFFFFFFF; - pm8001_ccb_free(pm8001_ha, tag); -} - -static void -mpi_get_nvmd_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct fw_control_ex *fw_control_context; - struct get_nvm_data_resp *pPayload = - (struct get_nvm_data_resp *)(piomb + 4); - u32 tag = le32_to_cpu(pPayload->tag); - struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag]; - u32 dlen_status = le32_to_cpu(pPayload->dlen_status); - u32 ir_tds_bn_dps_das_nvm = - le32_to_cpu(pPayload->ir_tda_bn_dps_das_nvm); - void *virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr; - fw_control_context = ccb->fw_control_context; - - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Get nvm data complete!\n")); - if ((dlen_status & NVMD_STAT) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Get nvm data error!\n")); - complete(pm8001_ha->nvmd_completion); - return; - } - - if (ir_tds_bn_dps_das_nvm & IPMode) { - /* indirect mode - IR bit set */ - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Get NVMD success, IR=1\n")); - if ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == TWI_DEVICE) { - if (ir_tds_bn_dps_das_nvm == 0x80a80200) { - memcpy(pm8001_ha->sas_addr, - ((u8 *)virt_addr + 4), - SAS_ADDR_SIZE); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Get SAS address" - " from VPD successfully!\n")); - } - } else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == C_SEEPROM) - || ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == VPD_FLASH) || - ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == EXPAN_ROM)) { - ; - } else if (((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == AAP1_RDUMP) - || ((ir_tds_bn_dps_das_nvm & NVMD_TYPE) == IOP_RDUMP)) { - ; - } else { - /* Should not be happened*/ - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("(IR=1)Wrong Device type 0x%x\n", - ir_tds_bn_dps_das_nvm)); - } - } else /* direct mode */{ - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Get NVMD success, IR=0, dataLen=%d\n", - (dlen_status & NVMD_LEN) >> 24)); - } - memcpy(fw_control_context->usrAddr, - pm8001_ha->memoryMap.region[NVMD].virt_ptr, - fw_control_context->len); - complete(pm8001_ha->nvmd_completion); - ccb->task = NULL; - ccb->ccb_tag = 0xFFFFFFFF; - pm8001_ccb_free(pm8001_ha, tag); -} - -static int mpi_local_phy_ctl(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct local_phy_ctl_resp *pPayload = - (struct local_phy_ctl_resp *)(piomb + 4); - u32 status = le32_to_cpu(pPayload->status); - u32 phy_id = le32_to_cpu(pPayload->phyop_phyid) & ID_BITS; - u32 phy_op = le32_to_cpu(pPayload->phyop_phyid) & OP_BITS; - if (status != 0) { - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("%x phy execute %x phy op failed!\n", - phy_id, phy_op)); - } else - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("%x phy execute %x phy op success!\n", - phy_id, phy_op)); - return 0; -} - -/** - * pm8001_bytes_dmaed - one of the interface function communication with libsas - * @pm8001_ha: our hba card information - * @i: which phy that received the event. - * - * when HBA driver received the identify done event or initiate FIS received - * event(for SATA), it will invoke this function to notify the sas layer that - * the sas toplogy has formed, please discover the the whole sas domain, - * while receive a broadcast(change) primitive just tell the sas - * layer to discover the changed domain rather than the whole domain. - */ -static void pm8001_bytes_dmaed(struct pm8001_hba_info *pm8001_ha, int i) -{ - struct pm8001_phy *phy = &pm8001_ha->phy[i]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - struct sas_ha_struct *sas_ha; - if (!phy->phy_attached) - return; - - sas_ha = pm8001_ha->sas; - if (sas_phy->phy) { - struct sas_phy *sphy = sas_phy->phy; - sphy->negotiated_linkrate = sas_phy->linkrate; - sphy->minimum_linkrate = phy->minimum_linkrate; - sphy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; - sphy->maximum_linkrate = phy->maximum_linkrate; - sphy->maximum_linkrate_hw = phy->maximum_linkrate; - } - - if (phy->phy_type & PORT_TYPE_SAS) { - struct sas_identify_frame *id; - id = (struct sas_identify_frame *)phy->frame_rcvd; - id->dev_type = phy->identify.device_type; - id->initiator_bits = SAS_PROTOCOL_ALL; - id->target_bits = phy->identify.target_port_protocols; - } else if (phy->phy_type & PORT_TYPE_SATA) { - /*Nothing*/ - } - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("phy %d byte dmaded.\n", i)); - - sas_phy->frame_rcvd_size = phy->frame_rcvd_size; - pm8001_ha->sas->notify_port_event(sas_phy, PORTE_BYTES_DMAED); -} - -/* Get the link rate speed */ -static void get_lrate_mode(struct pm8001_phy *phy, u8 link_rate) -{ - struct sas_phy *sas_phy = phy->sas_phy.phy; - - switch (link_rate) { - case PHY_SPEED_60: - phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS; - phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; - break; - case PHY_SPEED_30: - phy->sas_phy.linkrate = SAS_LINK_RATE_3_0_GBPS; - phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; - break; - case PHY_SPEED_15: - phy->sas_phy.linkrate = SAS_LINK_RATE_1_5_GBPS; - phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; - break; - } - sas_phy->negotiated_linkrate = phy->sas_phy.linkrate; - sas_phy->maximum_linkrate_hw = SAS_LINK_RATE_6_0_GBPS; - sas_phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; - sas_phy->maximum_linkrate = SAS_LINK_RATE_6_0_GBPS; - sas_phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; -} - -/** - * asd_get_attached_sas_addr -- extract/generate attached SAS address - * @phy: pointer to asd_phy - * @sas_addr: pointer to buffer where the SAS address is to be written - * - * This function extracts the SAS address from an IDENTIFY frame - * received. If OOB is SATA, then a SAS address is generated from the - * HA tables. - * - * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame - * buffer. - */ -static void pm8001_get_attached_sas_addr(struct pm8001_phy *phy, - u8 *sas_addr) -{ - if (phy->sas_phy.frame_rcvd[0] == 0x34 - && phy->sas_phy.oob_mode == SATA_OOB_MODE) { - struct pm8001_hba_info *pm8001_ha = phy->sas_phy.ha->lldd_ha; - /* FIS device-to-host */ - u64 addr = be64_to_cpu(*(__be64 *)pm8001_ha->sas_addr); - addr += phy->sas_phy.id; - *(__be64 *)sas_addr = cpu_to_be64(addr); - } else { - struct sas_identify_frame *idframe = - (void *) phy->sas_phy.frame_rcvd; - memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE); - } -} - -/** - * pm8001_hw_event_ack_req- For PM8001,some events need to acknowage to FW. - * @pm8001_ha: our hba card information - * @Qnum: the outbound queue message number. - * @SEA: source of event to ack - * @port_id: port id. - * @phyId: phy id. - * @param0: parameter 0. - * @param1: parameter 1. - */ -static void pm8001_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha, - u32 Qnum, u32 SEA, u32 port_id, u32 phyId, u32 param0, u32 param1) -{ - struct hw_event_ack_req payload; - u32 opc = OPC_INB_SAS_HW_EVENT_ACK; - - struct inbound_queue_table *circularQ; - - memset((u8 *)&payload, 0, sizeof(payload)); - circularQ = &pm8001_ha->inbnd_q_tbl[Qnum]; - payload.tag = cpu_to_le32(1); - payload.sea_phyid_portid = cpu_to_le32(((SEA & 0xFFFF) << 8) | - ((phyId & 0x0F) << 4) | (port_id & 0x0F)); - payload.param0 = cpu_to_le32(param0); - payload.param1 = cpu_to_le32(param1); - mpi_build_cmd(pm8001_ha, circularQ, opc, &payload); -} - -static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, - u32 phyId, u32 phy_op); - -/** - * hw_event_sas_phy_up -FW tells me a SAS phy up event. - * @pm8001_ha: our hba card information - * @piomb: IO message buffer - */ -static void -hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct hw_event_resp *pPayload = - (struct hw_event_resp *)(piomb + 4); - u32 lr_evt_status_phyid_portid = - le32_to_cpu(pPayload->lr_evt_status_phyid_portid); - u8 link_rate = - (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28); - u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F); - u8 phy_id = - (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); - u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate); - u8 portstate = (u8)(npip_portstate & 0x0000000F); - struct pm8001_port *port = &pm8001_ha->port[port_id]; - struct sas_ha_struct *sas_ha = pm8001_ha->sas; - struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; - unsigned long flags; - u8 deviceType = pPayload->sas_identify.dev_type; - port->port_state = portstate; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SAS_PHY_UP port id = %d, phy id = %d\n", - port_id, phy_id)); - - switch (deviceType) { - case SAS_PHY_UNUSED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("device type no device.\n")); - break; - case SAS_END_DEVICE: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("end device.\n")); - pm8001_chip_phy_ctl_req(pm8001_ha, phy_id, - PHY_NOTIFY_ENABLE_SPINUP); - port->port_attached = 1; - get_lrate_mode(phy, link_rate); - break; - case SAS_EDGE_EXPANDER_DEVICE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("expander device.\n")); - port->port_attached = 1; - get_lrate_mode(phy, link_rate); - break; - case SAS_FANOUT_EXPANDER_DEVICE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("fanout expander device.\n")); - port->port_attached = 1; - get_lrate_mode(phy, link_rate); - break; - default: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("unknown device type(%x)\n", deviceType)); - break; - } - phy->phy_type |= PORT_TYPE_SAS; - phy->identify.device_type = deviceType; - phy->phy_attached = 1; - if (phy->identify.device_type == SAS_END_DEVICE) - phy->identify.target_port_protocols = SAS_PROTOCOL_SSP; - else if (phy->identify.device_type != SAS_PHY_UNUSED) - phy->identify.target_port_protocols = SAS_PROTOCOL_SMP; - phy->sas_phy.oob_mode = SAS_OOB_MODE; - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); - spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); - memcpy(phy->frame_rcvd, &pPayload->sas_identify, - sizeof(struct sas_identify_frame)-4); - phy->frame_rcvd_size = sizeof(struct sas_identify_frame) - 4; - pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); - spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); - if (pm8001_ha->flags == PM8001F_RUN_TIME) - mdelay(200);/*delay a moment to wait disk to spinup*/ - pm8001_bytes_dmaed(pm8001_ha, phy_id); -} - -/** - * hw_event_sata_phy_up -FW tells me a SATA phy up event. - * @pm8001_ha: our hba card information - * @piomb: IO message buffer - */ -static void -hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct hw_event_resp *pPayload = - (struct hw_event_resp *)(piomb + 4); - u32 lr_evt_status_phyid_portid = - le32_to_cpu(pPayload->lr_evt_status_phyid_portid); - u8 link_rate = - (u8)((lr_evt_status_phyid_portid & 0xF0000000) >> 28); - u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F); - u8 phy_id = - (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); - u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate); - u8 portstate = (u8)(npip_portstate & 0x0000000F); - struct pm8001_port *port = &pm8001_ha->port[port_id]; - struct sas_ha_struct *sas_ha = pm8001_ha->sas; - struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; - unsigned long flags; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SATA_PHY_UP port id = %d," - " phy id = %d\n", port_id, phy_id)); - port->port_state = portstate; - port->port_attached = 1; - get_lrate_mode(phy, link_rate); - phy->phy_type |= PORT_TYPE_SATA; - phy->phy_attached = 1; - phy->sas_phy.oob_mode = SATA_OOB_MODE; - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); - spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); - memcpy(phy->frame_rcvd, ((u8 *)&pPayload->sata_fis - 4), - sizeof(struct dev_to_host_fis)); - phy->frame_rcvd_size = sizeof(struct dev_to_host_fis); - phy->identify.target_port_protocols = SAS_PROTOCOL_SATA; - phy->identify.device_type = SATA_DEV; - pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); - spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); - pm8001_bytes_dmaed(pm8001_ha, phy_id); -} - -/** - * hw_event_phy_down -we should notify the libsas the phy is down. - * @pm8001_ha: our hba card information - * @piomb: IO message buffer - */ -static void -hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct hw_event_resp *pPayload = - (struct hw_event_resp *)(piomb + 4); - u32 lr_evt_status_phyid_portid = - le32_to_cpu(pPayload->lr_evt_status_phyid_portid); - u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F); - u8 phy_id = - (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); - u32 npip_portstate = le32_to_cpu(pPayload->npip_portstate); - u8 portstate = (u8)(npip_portstate & 0x0000000F); - struct pm8001_port *port = &pm8001_ha->port[port_id]; - struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; - port->port_state = portstate; - phy->phy_type = 0; - phy->identify.device_type = 0; - phy->phy_attached = 0; - memset(&phy->dev_sas_addr, 0, SAS_ADDR_SIZE); - switch (portstate) { - case PORT_VALID: - break; - case PORT_INVALID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" PortInvalid portID %d\n", port_id)); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Last phy Down and port invalid\n")); - port->port_attached = 0; - pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, - port_id, phy_id, 0, 0); - break; - case PORT_IN_RESET: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Port In Reset portID %d\n", port_id)); - break; - case PORT_NOT_ESTABLISHED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n")); - port->port_attached = 0; - break; - case PORT_LOSTCOMM: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and PORT_LOSTCOMM\n")); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" Last phy Down and port invalid\n")); - port->port_attached = 0; - pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, - port_id, phy_id, 0, 0); - break; - default: - port->port_attached = 0; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and(default) = %x\n", - portstate)); - break; - - } -} - -/** - * mpi_reg_resp -process register device ID response. - * @pm8001_ha: our hba card information - * @piomb: IO message buffer - * - * when sas layer find a device it will notify LLDD, then the driver register - * the domain device to FW, this event is the return device ID which the FW - * has assigned, from now,inter-communication with FW is no longer using the - * SAS address, use device ID which FW assigned. - */ -static int mpi_reg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - u32 status; - u32 device_id; - u32 htag; - struct pm8001_ccb_info *ccb; - struct pm8001_device *pm8001_dev; - struct dev_reg_resp *registerRespPayload = - (struct dev_reg_resp *)(piomb + 4); - - htag = le32_to_cpu(registerRespPayload->tag); - ccb = &pm8001_ha->ccb_info[htag]; - pm8001_dev = ccb->device; - status = le32_to_cpu(registerRespPayload->status); - device_id = le32_to_cpu(registerRespPayload->device_id); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" register device is status = %d\n", status)); - switch (status) { - case DEVREG_SUCCESS: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("DEVREG_SUCCESS\n")); - pm8001_dev->device_id = device_id; - break; - case DEVREG_FAILURE_OUT_OF_RESOURCE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_OUT_OF_RESOURCE\n")); - break; - case DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED\n")); - break; - case DEVREG_FAILURE_INVALID_PHY_ID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_INVALID_PHY_ID\n")); - break; - case DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED\n")); - break; - case DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE\n")); - break; - case DEVREG_FAILURE_PORT_NOT_VALID_STATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_PORT_NOT_VALID_STATE\n")); - break; - case DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID\n")); - break; - default: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("DEVREG_FAILURE_DEVICE_TYPE_NOT_UNSORPORTED\n")); - break; - } - complete(pm8001_dev->dcompletion); - ccb->task = NULL; - ccb->ccb_tag = 0xFFFFFFFF; - pm8001_ccb_free(pm8001_ha, htag); - return 0; -} - -static int mpi_dereg_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - u32 status; - u32 device_id; - struct dev_reg_resp *registerRespPayload = - (struct dev_reg_resp *)(piomb + 4); - - status = le32_to_cpu(registerRespPayload->status); - device_id = le32_to_cpu(registerRespPayload->device_id); - if (status != 0) - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" deregister device failed ,status = %x" - ", device_id = %x\n", status, device_id)); - return 0; -} - -static int -mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - u32 status; - struct fw_control_ex fw_control_context; - struct fw_flash_Update_resp *ppayload = - (struct fw_flash_Update_resp *)(piomb + 4); - u32 tag = ppayload->tag; - struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[tag]; - status = le32_to_cpu(ppayload->status); - memcpy(&fw_control_context, - ccb->fw_control_context, - sizeof(fw_control_context)); - switch (status) { - case FLASH_UPDATE_COMPLETE_PENDING_REBOOT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_COMPLETE_PENDING_REBOOT\n")); - break; - case FLASH_UPDATE_IN_PROGRESS: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_IN_PROGRESS\n")); - break; - case FLASH_UPDATE_HDR_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_HDR_ERR\n")); - break; - case FLASH_UPDATE_OFFSET_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_OFFSET_ERR\n")); - break; - case FLASH_UPDATE_CRC_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_CRC_ERR\n")); - break; - case FLASH_UPDATE_LENGTH_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_LENGTH_ERR\n")); - break; - case FLASH_UPDATE_HW_ERR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_HW_ERR\n")); - break; - case FLASH_UPDATE_DNLD_NOT_SUPPORTED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_DNLD_NOT_SUPPORTED\n")); - break; - case FLASH_UPDATE_DISABLED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(": FLASH_UPDATE_DISABLED\n")); - break; - default: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("No matched status = %d\n", status)); - break; - } - ccb->fw_control_context->fw_control->retcode = status; - pci_free_consistent(pm8001_ha->pdev, - fw_control_context.len, - fw_control_context.virtAddr, - fw_control_context.phys_addr); - complete(pm8001_ha->nvmd_completion); - ccb->task = NULL; - ccb->ccb_tag = 0xFFFFFFFF; - pm8001_ccb_free(pm8001_ha, tag); - return 0; -} - -static int -mpi_general_event(struct pm8001_hba_info *pm8001_ha , void *piomb) -{ - u32 status; - int i; - struct general_event_resp *pPayload = - (struct general_event_resp *)(piomb + 4); - status = le32_to_cpu(pPayload->status); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" status = 0x%x\n", status)); - for (i = 0; i < GENERAL_EVENT_PAYLOAD; i++) - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("inb_IOMB_payload[0x%x] 0x%x,\n", i, - pPayload->inb_IOMB_payload[i])); - return 0; -} - -static int -mpi_task_abort_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - struct sas_task *t; - struct pm8001_ccb_info *ccb; - unsigned long flags; - u32 status ; - u32 tag, scp; - struct task_status_struct *ts; - - struct task_abort_resp *pPayload = - (struct task_abort_resp *)(piomb + 4); - - status = le32_to_cpu(pPayload->status); - tag = le32_to_cpu(pPayload->tag); - scp = le32_to_cpu(pPayload->scp); - ccb = &pm8001_ha->ccb_info[tag]; - t = ccb->task; - PM8001_IO_DBG(pm8001_ha, - pm8001_printk(" status = 0x%x\n", status)); - if (t == NULL) - return -1; - ts = &t->task_status; - if (status != 0) - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("task abort failed status 0x%x ," - "tag = 0x%x, scp= 0x%x\n", status, tag, scp)); - switch (status) { - case IO_SUCCESS: - PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS\n")); - ts->resp = SAS_TASK_COMPLETE; - ts->stat = SAM_STAT_GOOD; - break; - case IO_NOT_VALID: - PM8001_EH_DBG(pm8001_ha, pm8001_printk("IO_NOT_VALID\n")); - ts->resp = TMF_RESP_FUNC_FAILED; - break; - } - spin_lock_irqsave(&t->task_state_lock, flags); - t->task_state_flags &= ~SAS_TASK_STATE_PENDING; - t->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - t->task_state_flags |= SAS_TASK_STATE_DONE; - spin_unlock_irqrestore(&t->task_state_lock, flags); - pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); - mb(); - t->task_done(t); - return 0; -} - -/** - * mpi_hw_event -The hw event has come. - * @pm8001_ha: our hba card information - * @piomb: IO message buffer - */ -static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) -{ - unsigned long flags; - struct hw_event_resp *pPayload = - (struct hw_event_resp *)(piomb + 4); - u32 lr_evt_status_phyid_portid = - le32_to_cpu(pPayload->lr_evt_status_phyid_portid); - u8 port_id = (u8)(lr_evt_status_phyid_portid & 0x0000000F); - u8 phy_id = - (u8)((lr_evt_status_phyid_portid & 0x000000F0) >> 4); - u16 eventType = - (u16)((lr_evt_status_phyid_portid & 0x00FFFF00) >> 8); - u8 status = - (u8)((lr_evt_status_phyid_portid & 0x0F000000) >> 24); - struct sas_ha_struct *sas_ha = pm8001_ha->sas; - struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; - struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("outbound queue HW event & event type : ")); - switch (eventType) { - case HW_EVENT_PHY_START_STATUS: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_START_STATUS" - " status = %x\n", status)); - if (status == 0) { - phy->phy_state = 1; - if (pm8001_ha->flags == PM8001F_RUN_TIME) - complete(phy->enable_completion); - } - break; - case HW_EVENT_SAS_PHY_UP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_START_STATUS\n")); - hw_event_sas_phy_up(pm8001_ha, piomb); - break; - case HW_EVENT_SATA_PHY_UP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SATA_PHY_UP\n")); - hw_event_sata_phy_up(pm8001_ha, piomb); - break; - case HW_EVENT_PHY_STOP_STATUS: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_STOP_STATUS " - "status = %x\n", status)); - if (status == 0) - phy->phy_state = 0; - break; - case HW_EVENT_SATA_SPINUP_HOLD: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_SATA_SPINUP_HOLD\n")); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); - break; - case HW_EVENT_PHY_DOWN: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_DOWN\n")); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL); - phy->phy_attached = 0; - phy->phy_state = 0; - hw_event_phy_down(pm8001_ha, piomb); - break; - case HW_EVENT_PORT_INVALID: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_INVALID\n")); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - /* the broadcast change primitive received, tell the LIBSAS this event - to revalidate the sas domain*/ - case HW_EVENT_BROADCAST_CHANGE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_CHANGE\n")); - pm8001_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_BROADCAST_CHANGE, - port_id, phy_id, 1, 0); - spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); - sas_phy->sas_prim = HW_EVENT_BROADCAST_CHANGE; - spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); - sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); - break; - case HW_EVENT_PHY_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PHY_ERROR\n")); - sas_phy_disconnected(&phy->sas_phy); - phy->phy_attached = 0; - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR); - break; - case HW_EVENT_BROADCAST_EXP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_EXP\n")); - spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); - sas_phy->sas_prim = HW_EVENT_BROADCAST_EXP; - spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); - sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); - break; - case HW_EVENT_LINK_ERR_INVALID_DWORD: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_INVALID_DWORD\n")); - pm8001_hw_event_ack_req(pm8001_ha, 0, - HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - case HW_EVENT_LINK_ERR_DISPARITY_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_DISPARITY_ERROR\n")); - pm8001_hw_event_ack_req(pm8001_ha, 0, - HW_EVENT_LINK_ERR_DISPARITY_ERROR, - port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - case HW_EVENT_LINK_ERR_CODE_VIOLATION: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_CODE_VIOLATION\n")); - pm8001_hw_event_ack_req(pm8001_ha, 0, - HW_EVENT_LINK_ERR_CODE_VIOLATION, - port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH\n")); - pm8001_hw_event_ack_req(pm8001_ha, 0, - HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH, - port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - case HW_EVENT_MALFUNCTION: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_MALFUNCTION\n")); - break; - case HW_EVENT_BROADCAST_SES: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_BROADCAST_SES\n")); - spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); - sas_phy->sas_prim = HW_EVENT_BROADCAST_SES; - spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); - sas_ha->notify_port_event(sas_phy, PORTE_BROADCAST_RCVD); - break; - case HW_EVENT_INBOUND_CRC_ERROR: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_INBOUND_CRC_ERROR\n")); - pm8001_hw_event_ack_req(pm8001_ha, 0, - HW_EVENT_INBOUND_CRC_ERROR, - port_id, phy_id, 0, 0); - break; - case HW_EVENT_HARD_RESET_RECEIVED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_HARD_RESET_RECEIVED\n")); - sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); - break; - case HW_EVENT_ID_FRAME_TIMEOUT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_ID_FRAME_TIMEOUT\n")); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - case HW_EVENT_LINK_ERR_PHY_RESET_FAILED: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_LINK_ERR_PHY_RESET_FAILED\n")); - pm8001_hw_event_ack_req(pm8001_ha, 0, - HW_EVENT_LINK_ERR_PHY_RESET_FAILED, - port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - case HW_EVENT_PORT_RESET_TIMER_TMO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RESET_TIMER_TMO\n")); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - case HW_EVENT_PORT_RECOVERY_TIMER_TMO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RECOVERY_TIMER_TMO\n")); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); - break; - case HW_EVENT_PORT_RECOVER: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RECOVER\n")); - break; - case HW_EVENT_PORT_RESET_COMPLETE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("HW_EVENT_PORT_RESET_COMPLETE\n")); - break; - case EVENT_BROADCAST_ASYNCH_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("EVENT_BROADCAST_ASYNCH_EVENT\n")); - break; - default: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Unknown event type = %x\n", eventType)); - break; - } - return 0; -} - -/** - * process_one_iomb - process one outbound Queue memory block - * @pm8001_ha: our hba card information - * @piomb: IO message buffer - */ -static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) -{ - u32 pHeader = (u32)*(u32 *)piomb; - u8 opc = (u8)(pHeader & 0xFFF); - - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("process_one_iomb:")); - - switch (opc) { - case OPC_OUB_ECHO: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk("OPC_OUB_ECHO\n")); - break; - case OPC_OUB_HW_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_HW_EVENT\n")); - mpi_hw_event(pm8001_ha, piomb); - break; - case OPC_OUB_SSP_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_COMP\n")); - mpi_ssp_completion(pm8001_ha, piomb); - break; - case OPC_OUB_SMP_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SMP_COMP\n")); - mpi_smp_completion(pm8001_ha, piomb); - break; - case OPC_OUB_LOCAL_PHY_CNTRL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_LOCAL_PHY_CNTRL\n")); - mpi_local_phy_ctl(pm8001_ha, piomb); - break; - case OPC_OUB_DEV_REGIST: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEV_REGIST\n")); - mpi_reg_resp(pm8001_ha, piomb); - break; - case OPC_OUB_DEREG_DEV: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("unregister the device\n")); - mpi_dereg_resp(pm8001_ha, piomb); - break; - case OPC_OUB_GET_DEV_HANDLE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_DEV_HANDLE\n")); - break; - case OPC_OUB_SATA_COMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_COMP\n")); - mpi_sata_completion(pm8001_ha, piomb); - break; - case OPC_OUB_SATA_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_EVENT\n")); - mpi_sata_event(pm8001_ha, piomb); - break; - case OPC_OUB_SSP_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_EVENT\n")); - mpi_ssp_event(pm8001_ha, piomb); - break; - case OPC_OUB_DEV_HANDLE_ARRIV: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEV_HANDLE_ARRIV\n")); - /*This is for target*/ - break; - case OPC_OUB_SSP_RECV_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_RECV_EVENT\n")); - /*This is for target*/ - break; - case OPC_OUB_DEV_INFO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEV_INFO\n")); - break; - case OPC_OUB_FW_FLASH_UPDATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_FW_FLASH_UPDATE\n")); - mpi_fw_flash_update_resp(pm8001_ha, piomb); - break; - case OPC_OUB_GPIO_RESPONSE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GPIO_RESPONSE\n")); - break; - case OPC_OUB_GPIO_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GPIO_EVENT\n")); - break; - case OPC_OUB_GENERAL_EVENT: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GENERAL_EVENT\n")); - mpi_general_event(pm8001_ha, piomb); - break; - case OPC_OUB_SSP_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SSP_ABORT_RSP\n")); - mpi_task_abort_resp(pm8001_ha, piomb); - break; - case OPC_OUB_SATA_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SATA_ABORT_RSP\n")); - mpi_task_abort_resp(pm8001_ha, piomb); - break; - case OPC_OUB_SAS_DIAG_MODE_START_END: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_DIAG_MODE_START_END\n")); - break; - case OPC_OUB_SAS_DIAG_EXECUTE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_DIAG_EXECUTE\n")); - break; - case OPC_OUB_GET_TIME_STAMP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_TIME_STAMP\n")); - break; - case OPC_OUB_SAS_HW_EVENT_ACK: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_HW_EVENT_ACK\n")); - break; - case OPC_OUB_PORT_CONTROL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_PORT_CONTROL\n")); - break; - case OPC_OUB_SMP_ABORT_RSP: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SMP_ABORT_RSP\n")); - mpi_task_abort_resp(pm8001_ha, piomb); - break; - case OPC_OUB_GET_NVMD_DATA: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_NVMD_DATA\n")); - mpi_get_nvmd_resp(pm8001_ha, piomb); - break; - case OPC_OUB_SET_NVMD_DATA: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_NVMD_DATA\n")); - mpi_set_nvmd_resp(pm8001_ha, piomb); - break; - case OPC_OUB_DEVICE_HANDLE_REMOVAL: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_DEVICE_HANDLE_REMOVAL\n")); - break; - case OPC_OUB_SET_DEVICE_STATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_DEVICE_STATE\n")); - mpi_set_dev_state_resp(pm8001_ha, piomb); - break; - case OPC_OUB_GET_DEVICE_STATE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_GET_DEVICE_STATE\n")); - break; - case OPC_OUB_SET_DEV_INFO: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SET_DEV_INFO\n")); - break; - case OPC_OUB_SAS_RE_INITIALIZE: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("OPC_OUB_SAS_RE_INITIALIZE\n")); - break; - default: - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Unknown outbound Queue IOMB OPC = %x\n", - opc)); - break; - } -} - -static int process_oq(struct pm8001_hba_info *pm8001_ha) -{ - struct outbound_queue_table *circularQ; - void *pMsg1 = NULL; - u8 uninitialized_var(bc); - u32 ret = MPI_IO_STATUS_FAIL; - unsigned long flags; - - spin_lock_irqsave(&pm8001_ha->lock, flags); - circularQ = &pm8001_ha->outbnd_q_tbl[0]; - do { - ret = mpi_msg_consume(pm8001_ha, circularQ, &pMsg1, &bc); - if (MPI_IO_STATUS_SUCCESS == ret) { - /* process the outbound message */ - process_one_iomb(pm8001_ha, (void *)(pMsg1 - 4)); - /* free the message from the outbound circular buffer */ - mpi_msg_free_set(pm8001_ha, pMsg1, circularQ, bc); - } - if (MPI_IO_STATUS_BUSY == ret) { - /* Update the producer index from SPC */ - circularQ->producer_index = - cpu_to_le32(pm8001_read_32(circularQ->pi_virt)); - if (le32_to_cpu(circularQ->producer_index) == - circularQ->consumer_idx) - /* OQ is empty */ - break; - } - } while (1); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return ret; -} - -/* PCI_DMA_... to our direction translation. */ -static const u8 data_dir_flags[] = { - [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT,/* UNSPECIFIED */ - [PCI_DMA_TODEVICE] = DATA_DIR_OUT,/* OUTBOUND */ - [PCI_DMA_FROMDEVICE] = DATA_DIR_IN,/* INBOUND */ - [PCI_DMA_NONE] = DATA_DIR_NONE,/* NO TRANSFER */ -}; -static void -pm8001_chip_make_sg(struct scatterlist *scatter, int nr, void *prd) -{ - int i; - struct scatterlist *sg; - struct pm8001_prd *buf_prd = prd; - - for_each_sg(scatter, sg, nr, i) { - buf_prd->addr = cpu_to_le64(sg_dma_address(sg)); - buf_prd->im_len.len = cpu_to_le32(sg_dma_len(sg)); - buf_prd->im_len.e = 0; - buf_prd++; - } -} - -static void build_smp_cmd(u32 deviceID, __le32 hTag, struct smp_req *psmp_cmd) -{ - psmp_cmd->tag = hTag; - psmp_cmd->device_id = cpu_to_le32(deviceID); - psmp_cmd->len_ip_ir = cpu_to_le32(1|(1 << 1)); -} - -/** - * pm8001_chip_smp_req - send a SMP task to FW - * @pm8001_ha: our hba card information. - * @ccb: the ccb information this request used. - */ -static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb) -{ - int elem, rc; - struct sas_task *task = ccb->task; - struct domain_device *dev = task->dev; - struct pm8001_device *pm8001_dev = dev->lldd_dev; - struct scatterlist *sg_req, *sg_resp; - u32 req_len, resp_len; - struct smp_req smp_cmd; - u32 opc; - struct inbound_queue_table *circularQ; - - memset(&smp_cmd, 0, sizeof(smp_cmd)); - /* - * DMA-map SMP request, response buffers - */ - sg_req = &task->smp_task.smp_req; - elem = dma_map_sg(pm8001_ha->dev, sg_req, 1, PCI_DMA_TODEVICE); - if (!elem) - return -ENOMEM; - req_len = sg_dma_len(sg_req); - - sg_resp = &task->smp_task.smp_resp; - elem = dma_map_sg(pm8001_ha->dev, sg_resp, 1, PCI_DMA_FROMDEVICE); - if (!elem) { - rc = -ENOMEM; - goto err_out; - } - resp_len = sg_dma_len(sg_resp); - /* must be in dwords */ - if ((req_len & 0x3) || (resp_len & 0x3)) { - rc = -EINVAL; - goto err_out_2; - } - - opc = OPC_INB_SMP_REQUEST; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - smp_cmd.tag = cpu_to_le32(ccb->ccb_tag); - smp_cmd.long_smp_req.long_req_addr = - cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req)); - smp_cmd.long_smp_req.long_req_size = - cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4); - smp_cmd.long_smp_req.long_resp_addr = - cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp)); - smp_cmd.long_smp_req.long_resp_size = - cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4); - build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd); - mpi_build_cmd(pm8001_ha, circularQ, opc, (u32 *)&smp_cmd); - return 0; - -err_out_2: - dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); -err_out: - dma_unmap_sg(pm8001_ha->dev, &ccb->task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - return rc; -} - -/** - * pm8001_chip_ssp_io_req - send a SSP task to FW - * @pm8001_ha: our hba card information. - * @ccb: the ccb information this request used. - */ -static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb) -{ - struct sas_task *task = ccb->task; - struct domain_device *dev = task->dev; - struct pm8001_device *pm8001_dev = dev->lldd_dev; - struct ssp_ini_io_start_req ssp_cmd; - u32 tag = ccb->ccb_tag; - int ret; - u64 phys_addr; - struct inbound_queue_table *circularQ; - u32 opc = OPC_INB_SSPINIIOSTART; - memset(&ssp_cmd, 0, sizeof(ssp_cmd)); - memcpy(ssp_cmd.ssp_iu.lun, task->ssp_task.LUN, 8); - ssp_cmd.dir_m_tlr = - cpu_to_le32(data_dir_flags[task->data_dir] << 8 | 0x0);/*0 for - SAS 1.1 compatible TLR*/ - ssp_cmd.data_len = cpu_to_le32(task->total_xfer_len); - ssp_cmd.device_id = cpu_to_le32(pm8001_dev->device_id); - ssp_cmd.tag = cpu_to_le32(tag); - if (task->ssp_task.enable_first_burst) - ssp_cmd.ssp_iu.efb_prio_attr |= 0x80; - ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_prio << 3); - ssp_cmd.ssp_iu.efb_prio_attr |= (task->ssp_task.task_attr & 7); - memcpy(ssp_cmd.ssp_iu.cdb, task->ssp_task.cdb, 16); - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - - /* fill in PRD (scatter/gather) table, if any */ - if (task->num_scatter > 1) { - pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd); - phys_addr = ccb->ccb_dma_handle + - offsetof(struct pm8001_ccb_info, buf_prd[0]); - ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(phys_addr)); - ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(phys_addr)); - ssp_cmd.esgl = cpu_to_le32(1<<31); - } else if (task->num_scatter == 1) { - u64 dma_addr = sg_dma_address(task->scatter); - ssp_cmd.addr_low = cpu_to_le32(lower_32_bits(dma_addr)); - ssp_cmd.addr_high = cpu_to_le32(upper_32_bits(dma_addr)); - ssp_cmd.len = cpu_to_le32(task->total_xfer_len); - ssp_cmd.esgl = 0; - } else if (task->num_scatter == 0) { - ssp_cmd.addr_low = 0; - ssp_cmd.addr_high = 0; - ssp_cmd.len = cpu_to_le32(task->total_xfer_len); - ssp_cmd.esgl = 0; - } - ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd); - return ret; -} - -static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb) -{ - struct sas_task *task = ccb->task; - struct domain_device *dev = task->dev; - struct pm8001_device *pm8001_ha_dev = dev->lldd_dev; - u32 tag = ccb->ccb_tag; - int ret; - struct sata_start_req sata_cmd; - u32 hdr_tag, ncg_tag = 0; - u64 phys_addr; - u32 ATAP = 0x0; - u32 dir; - struct inbound_queue_table *circularQ; - u32 opc = OPC_INB_SATA_HOST_OPSTART; - memset(&sata_cmd, 0, sizeof(sata_cmd)); - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - if (task->data_dir == PCI_DMA_NONE) { - ATAP = 0x04; /* no data*/ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("no data\n")); - } else if (likely(!task->ata_task.device_control_reg_update)) { - if (task->ata_task.dma_xfer) { - ATAP = 0x06; /* DMA */ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("DMA\n")); - } else { - ATAP = 0x05; /* PIO*/ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("PIO\n")); - } - if (task->ata_task.use_ncq && - dev->sata_dev.command_set != ATAPI_COMMAND_SET) { - ATAP = 0x07; /* FPDMA */ - PM8001_IO_DBG(pm8001_ha, pm8001_printk("FPDMA\n")); - } - } - if (task->ata_task.use_ncq && pm8001_get_ncq_tag(task, &hdr_tag)) - ncg_tag = hdr_tag; - dir = data_dir_flags[task->data_dir] << 8; - sata_cmd.tag = cpu_to_le32(tag); - sata_cmd.device_id = cpu_to_le32(pm8001_ha_dev->device_id); - sata_cmd.data_len = cpu_to_le32(task->total_xfer_len); - sata_cmd.ncqtag_atap_dir_m = - cpu_to_le32(((ncg_tag & 0xff)<<16)|((ATAP & 0x3f) << 10) | dir); - sata_cmd.sata_fis = task->ata_task.fis; - if (likely(!task->ata_task.device_control_reg_update)) - sata_cmd.sata_fis.flags |= 0x80;/* C=1: update ATA cmd reg */ - sata_cmd.sata_fis.flags &= 0xF0;/* PM_PORT field shall be 0 */ - /* fill in PRD (scatter/gather) table, if any */ - if (task->num_scatter > 1) { - pm8001_chip_make_sg(task->scatter, ccb->n_elem, ccb->buf_prd); - phys_addr = ccb->ccb_dma_handle + - offsetof(struct pm8001_ccb_info, buf_prd[0]); - sata_cmd.addr_low = lower_32_bits(phys_addr); - sata_cmd.addr_high = upper_32_bits(phys_addr); - sata_cmd.esgl = cpu_to_le32(1 << 31); - } else if (task->num_scatter == 1) { - u64 dma_addr = sg_dma_address(task->scatter); - sata_cmd.addr_low = lower_32_bits(dma_addr); - sata_cmd.addr_high = upper_32_bits(dma_addr); - sata_cmd.len = cpu_to_le32(task->total_xfer_len); - sata_cmd.esgl = 0; - } else if (task->num_scatter == 0) { - sata_cmd.addr_low = 0; - sata_cmd.addr_high = 0; - sata_cmd.len = cpu_to_le32(task->total_xfer_len); - sata_cmd.esgl = 0; - } - ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd); - return ret; -} - -/** - * pm8001_chip_phy_start_req - start phy via PHY_START COMMAND - * @pm8001_ha: our hba card information. - * @num: the inbound queue number - * @phy_id: the phy id which we wanted to start up. - */ -static int -pm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) -{ - struct phy_start_req payload; - struct inbound_queue_table *circularQ; - int ret; - u32 tag = 0x01; - u32 opcode = OPC_INB_PHYSTART; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - memset(&payload, 0, sizeof(payload)); - payload.tag = cpu_to_le32(tag); - /* - ** [0:7] PHY Identifier - ** [8:11] link rate 1.5G, 3G, 6G - ** [12:13] link mode 01b SAS mode; 10b SATA mode; 11b both - ** [14] 0b disable spin up hold; 1b enable spin up hold - */ - payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | - LINKMODE_AUTO | LINKRATE_15 | - LINKRATE_30 | LINKRATE_60 | phy_id); - payload.sas_identify.dev_type = SAS_END_DEV; - payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL; - memcpy(payload.sas_identify.sas_addr, - pm8001_ha->sas_addr, SAS_ADDR_SIZE); - payload.sas_identify.phy_id = phy_id; - ret = mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload); - return ret; -} - -/** - * pm8001_chip_phy_stop_req - start phy via PHY_STOP COMMAND - * @pm8001_ha: our hba card information. - * @num: the inbound queue number - * @phy_id: the phy id which we wanted to start up. - */ -static int pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha, - u8 phy_id) -{ - struct phy_stop_req payload; - struct inbound_queue_table *circularQ; - int ret; - u32 tag = 0x01; - u32 opcode = OPC_INB_PHYSTOP; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - memset(&payload, 0, sizeof(payload)); - payload.tag = cpu_to_le32(tag); - payload.phy_id = cpu_to_le32(phy_id); - ret = mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload); - return ret; -} - -/** - * see comments on mpi_reg_resp. - */ -static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, u32 flag) -{ - struct reg_dev_req payload; - u32 opc; - u32 stp_sspsmp_sata = 0x4; - struct inbound_queue_table *circularQ; - u32 linkrate, phy_id; - int rc, tag = 0xdeadbeef; - struct pm8001_ccb_info *ccb; - u8 retryFlag = 0x1; - u16 firstBurstSize = 0; - u16 ITNT = 2000; - struct domain_device *dev = pm8001_dev->sas_device; - struct domain_device *parent_dev = dev->parent; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - - memset(&payload, 0, sizeof(payload)); - rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) - return rc; - ccb = &pm8001_ha->ccb_info[tag]; - ccb->device = pm8001_dev; - ccb->ccb_tag = tag; - payload.tag = cpu_to_le32(tag); - if (flag == 1) - stp_sspsmp_sata = 0x02; /*direct attached sata */ - else { - if (pm8001_dev->dev_type == SATA_DEV) - stp_sspsmp_sata = 0x00; /* stp*/ - else if (pm8001_dev->dev_type == SAS_END_DEV || - pm8001_dev->dev_type == EDGE_DEV || - pm8001_dev->dev_type == FANOUT_DEV) - stp_sspsmp_sata = 0x01; /*ssp or smp*/ - } - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) - phy_id = parent_dev->ex_dev.ex_phy->phy_id; - else - phy_id = pm8001_dev->attached_phy; - opc = OPC_INB_REG_DEV; - linkrate = (pm8001_dev->sas_device->linkrate < dev->port->linkrate) ? - pm8001_dev->sas_device->linkrate : dev->port->linkrate; - payload.phyid_portid = - cpu_to_le32(((pm8001_dev->sas_device->port->id) & 0x0F) | - ((phy_id & 0x0F) << 4)); - payload.dtype_dlr_retry = cpu_to_le32((retryFlag & 0x01) | - ((linkrate & 0x0F) * 0x1000000) | - ((stp_sspsmp_sata & 0x03) * 0x10000000)); - payload.firstburstsize_ITNexustimeout = - cpu_to_le32(ITNT | (firstBurstSize * 0x10000)); - memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr, - SAS_ADDR_SIZE); - rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload); - return rc; -} - -/** - * see comments on mpi_reg_resp. - */ -static int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha, - u32 device_id) -{ - struct dereg_dev_req payload; - u32 opc = OPC_INB_DEREG_DEV_HANDLE; - int ret; - struct inbound_queue_table *circularQ; - - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - memset(&payload, 0, sizeof(payload)); - payload.tag = cpu_to_le32(1); - payload.device_id = cpu_to_le32(device_id); - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("unregister device device_id = %d\n", device_id)); - ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload); - return ret; -} - -/** - * pm8001_chip_phy_ctl_req - support the local phy operation - * @pm8001_ha: our hba card information. - * @num: the inbound queue number - * @phy_id: the phy id which we wanted to operate - * @phy_op: - */ -static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, - u32 phyId, u32 phy_op) -{ - struct local_phy_ctl_req payload; - struct inbound_queue_table *circularQ; - int ret; - u32 opc = OPC_INB_LOCAL_PHY_CONTROL; - memset(&payload, 0, sizeof(payload)); - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - payload.tag = cpu_to_le32(1); - payload.phyop_phyid = - cpu_to_le32(((phy_op & 0xff) << 8) | (phyId & 0x0F)); - ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload); - return ret; -} - -static u32 pm8001_chip_is_our_interupt(struct pm8001_hba_info *pm8001_ha) -{ - u32 value; -#ifdef PM8001_USE_MSIX - return 1; -#endif - value = pm8001_cr32(pm8001_ha, 0, MSGU_ODR); - if (value) - return 1; - return 0; - -} - -/** - * pm8001_chip_isr - PM8001 isr handler. - * @pm8001_ha: our hba card information. - * @irq: irq number. - * @stat: stat. - */ -static irqreturn_t -pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha) -{ - pm8001_chip_interrupt_disable(pm8001_ha); - process_oq(pm8001_ha); - pm8001_chip_interrupt_enable(pm8001_ha); - return IRQ_HANDLED; -} - -static int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc, - u32 dev_id, u8 flag, u32 task_tag, u32 cmd_tag) -{ - struct task_abort_req task_abort; - struct inbound_queue_table *circularQ; - int ret; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - memset(&task_abort, 0, sizeof(task_abort)); - if (ABORT_SINGLE == (flag & ABORT_MASK)) { - task_abort.abort_all = 0; - task_abort.device_id = cpu_to_le32(dev_id); - task_abort.tag_to_abort = cpu_to_le32(task_tag); - task_abort.tag = cpu_to_le32(cmd_tag); - } else if (ABORT_ALL == (flag & ABORT_MASK)) { - task_abort.abort_all = cpu_to_le32(1); - task_abort.device_id = cpu_to_le32(dev_id); - task_abort.tag = cpu_to_le32(cmd_tag); - } - ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort); - return ret; -} - -/** - * pm8001_chip_abort_task - SAS abort task when error or exception happened. - * @task: the task we wanted to aborted. - * @flag: the abort flag. - */ -static int pm8001_chip_abort_task(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, u8 flag, u32 task_tag, u32 cmd_tag) -{ - u32 opc, device_id; - int rc = TMF_RESP_FUNC_FAILED; - PM8001_EH_DBG(pm8001_ha, pm8001_printk("cmd_tag = %x, abort task tag" - " = %x", cmd_tag, task_tag)); - if (pm8001_dev->dev_type == SAS_END_DEV) - opc = OPC_INB_SSP_ABORT; - else if (pm8001_dev->dev_type == SATA_DEV) - opc = OPC_INB_SATA_ABORT; - else - opc = OPC_INB_SMP_ABORT;/* SMP */ - device_id = pm8001_dev->device_id; - rc = send_task_abort(pm8001_ha, opc, device_id, flag, - task_tag, cmd_tag); - if (rc != TMF_RESP_FUNC_COMPLETE) - PM8001_EH_DBG(pm8001_ha, pm8001_printk("rc= %d\n", rc)); - return rc; -} - -/** - * pm8001_chip_ssp_tm_req - built the task management command. - * @pm8001_ha: our hba card information. - * @ccb: the ccb information. - * @tmf: task management function. - */ -static int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf) -{ - struct sas_task *task = ccb->task; - struct domain_device *dev = task->dev; - struct pm8001_device *pm8001_dev = dev->lldd_dev; - u32 opc = OPC_INB_SSPINITMSTART; - struct inbound_queue_table *circularQ; - struct ssp_ini_tm_start_req sspTMCmd; - int ret; - - memset(&sspTMCmd, 0, sizeof(sspTMCmd)); - sspTMCmd.device_id = cpu_to_le32(pm8001_dev->device_id); - sspTMCmd.relate_tag = cpu_to_le32(tmf->tag_of_task_to_be_managed); - sspTMCmd.tmf = cpu_to_le32(tmf->tmf); - memcpy(sspTMCmd.lun, task->ssp_task.LUN, 8); - sspTMCmd.tag = cpu_to_le32(ccb->ccb_tag); - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd); - return ret; -} - -static int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, - void *payload) -{ - u32 opc = OPC_INB_GET_NVMD_DATA; - u32 nvmd_type; - int rc; - u32 tag; - struct pm8001_ccb_info *ccb; - struct inbound_queue_table *circularQ; - struct get_nvm_data_req nvmd_req; - struct fw_control_ex *fw_control_context; - struct pm8001_ioctl_payload *ioctl_payload = payload; - - nvmd_type = ioctl_payload->minor_function; - fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); - if (!fw_control_context) - return -ENOMEM; - fw_control_context->usrAddr = (u8 *)&ioctl_payload->func_specific[0]; - fw_control_context->len = ioctl_payload->length; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - memset(&nvmd_req, 0, sizeof(nvmd_req)); - rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) { - kfree(fw_control_context); - return rc; - } - ccb = &pm8001_ha->ccb_info[tag]; - ccb->ccb_tag = tag; - ccb->fw_control_context = fw_control_context; - nvmd_req.tag = cpu_to_le32(tag); - - switch (nvmd_type) { - case TWI_DEVICE: { - u32 twi_addr, twi_page_size; - twi_addr = 0xa8; - twi_page_size = 2; - - nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 | - twi_page_size << 8 | TWI_DEVICE); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); - nvmd_req.resp_addr_hi = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); - nvmd_req.resp_addr_lo = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); - break; - } - case C_SEEPROM: { - nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); - nvmd_req.resp_addr_hi = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); - nvmd_req.resp_addr_lo = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); - break; - } - case VPD_FLASH: { - nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); - nvmd_req.resp_addr_hi = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); - nvmd_req.resp_addr_lo = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); - break; - } - case EXPAN_ROM: { - nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); - nvmd_req.resp_addr_hi = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); - nvmd_req.resp_addr_lo = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); - break; - } - default: - break; - } - rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req); - return rc; -} - -static int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, - void *payload) -{ - u32 opc = OPC_INB_SET_NVMD_DATA; - u32 nvmd_type; - int rc; - u32 tag; - struct pm8001_ccb_info *ccb; - struct inbound_queue_table *circularQ; - struct set_nvm_data_req nvmd_req; - struct fw_control_ex *fw_control_context; - struct pm8001_ioctl_payload *ioctl_payload = payload; - - nvmd_type = ioctl_payload->minor_function; - fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); - if (!fw_control_context) - return -ENOMEM; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - memcpy(pm8001_ha->memoryMap.region[NVMD].virt_ptr, - ioctl_payload->func_specific, - ioctl_payload->length); - memset(&nvmd_req, 0, sizeof(nvmd_req)); - rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) { - kfree(fw_control_context); - return rc; - } - ccb = &pm8001_ha->ccb_info[tag]; - ccb->fw_control_context = fw_control_context; - ccb->ccb_tag = tag; - nvmd_req.tag = cpu_to_le32(tag); - switch (nvmd_type) { - case TWI_DEVICE: { - u32 twi_addr, twi_page_size; - twi_addr = 0xa8; - twi_page_size = 2; - nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98); - nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | twi_addr << 16 | - twi_page_size << 8 | TWI_DEVICE); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); - nvmd_req.resp_addr_hi = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); - nvmd_req.resp_addr_lo = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); - break; - } - case C_SEEPROM: - nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | C_SEEPROM); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); - nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98); - nvmd_req.resp_addr_hi = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); - nvmd_req.resp_addr_lo = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); - break; - case VPD_FLASH: - nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | VPD_FLASH); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); - nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98); - nvmd_req.resp_addr_hi = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); - nvmd_req.resp_addr_lo = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); - break; - case EXPAN_ROM: - nvmd_req.len_ir_vpdd = cpu_to_le32(IPMode | EXPAN_ROM); - nvmd_req.resp_len = cpu_to_le32(ioctl_payload->length); - nvmd_req.reserved[0] = cpu_to_le32(0xFEDCBA98); - nvmd_req.resp_addr_hi = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_hi); - nvmd_req.resp_addr_lo = - cpu_to_le32(pm8001_ha->memoryMap.region[NVMD].phys_addr_lo); - break; - default: - break; - } - rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req); - return rc; -} - -/** - * pm8001_chip_fw_flash_update_build - support the firmware update operation - * @pm8001_ha: our hba card information. - * @fw_flash_updata_info: firmware flash update param - */ -static int -pm8001_chip_fw_flash_update_build(struct pm8001_hba_info *pm8001_ha, - void *fw_flash_updata_info, u32 tag) -{ - struct fw_flash_Update_req payload; - struct fw_flash_updata_info *info; - struct inbound_queue_table *circularQ; - int ret; - u32 opc = OPC_INB_FW_FLASH_UPDATE; - - memset(&payload, 0, sizeof(struct fw_flash_Update_req)); - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - info = fw_flash_updata_info; - payload.tag = cpu_to_le32(tag); - payload.cur_image_len = cpu_to_le32(info->cur_image_len); - payload.cur_image_offset = cpu_to_le32(info->cur_image_offset); - payload.total_image_len = cpu_to_le32(info->total_image_len); - payload.len = info->sgl.im_len.len ; - payload.sgl_addr_lo = - cpu_to_le32(lower_32_bits(le64_to_cpu(info->sgl.addr))); - payload.sgl_addr_hi = - cpu_to_le32(upper_32_bits(le64_to_cpu(info->sgl.addr))); - ret = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload); - return ret; -} - -static int -pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, - void *payload) -{ - struct fw_flash_updata_info flash_update_info; - struct fw_control_info *fw_control; - struct fw_control_ex *fw_control_context; - int rc; - u32 tag; - struct pm8001_ccb_info *ccb; - void *buffer = NULL; - dma_addr_t phys_addr; - u32 phys_addr_hi; - u32 phys_addr_lo; - struct pm8001_ioctl_payload *ioctl_payload = payload; - - fw_control_context = kzalloc(sizeof(struct fw_control_ex), GFP_KERNEL); - if (!fw_control_context) - return -ENOMEM; - fw_control = (struct fw_control_info *)&ioctl_payload->func_specific[0]; - if (fw_control->len != 0) { - if (pm8001_mem_alloc(pm8001_ha->pdev, - (void **)&buffer, - &phys_addr, - &phys_addr_hi, - &phys_addr_lo, - fw_control->len, 0) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Mem alloc failure\n")); - kfree(fw_control_context); - return -ENOMEM; - } - } - memcpy(buffer, fw_control->buffer, fw_control->len); - flash_update_info.sgl.addr = cpu_to_le64(phys_addr); - flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len); - flash_update_info.sgl.im_len.e = 0; - flash_update_info.cur_image_offset = fw_control->offset; - flash_update_info.cur_image_len = fw_control->len; - flash_update_info.total_image_len = fw_control->size; - fw_control_context->fw_control = fw_control; - fw_control_context->virtAddr = buffer; - fw_control_context->len = fw_control->len; - rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) { - kfree(fw_control_context); - return rc; - } - ccb = &pm8001_ha->ccb_info[tag]; - ccb->fw_control_context = fw_control_context; - ccb->ccb_tag = tag; - rc = pm8001_chip_fw_flash_update_build(pm8001_ha, &flash_update_info, - tag); - return rc; -} - -static int -pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, u32 state) -{ - struct set_dev_state_req payload; - struct inbound_queue_table *circularQ; - struct pm8001_ccb_info *ccb; - int rc; - u32 tag; - u32 opc = OPC_INB_SET_DEVICE_STATE; - memset(&payload, 0, sizeof(payload)); - rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) - return -1; - ccb = &pm8001_ha->ccb_info[tag]; - ccb->ccb_tag = tag; - ccb->device = pm8001_dev; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - payload.tag = cpu_to_le32(tag); - payload.device_id = cpu_to_le32(pm8001_dev->device_id); - payload.nds = cpu_to_le32(state); - rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload); - return rc; - -} - -static int -pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha) -{ - struct sas_re_initialization_req payload; - struct inbound_queue_table *circularQ; - struct pm8001_ccb_info *ccb; - int rc; - u32 tag; - u32 opc = OPC_INB_SAS_RE_INITIALIZE; - memset(&payload, 0, sizeof(payload)); - rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) - return -1; - ccb = &pm8001_ha->ccb_info[tag]; - ccb->ccb_tag = tag; - circularQ = &pm8001_ha->inbnd_q_tbl[0]; - payload.tag = cpu_to_le32(tag); - payload.SSAHOLT = cpu_to_le32(0xd << 25); - payload.sata_hol_tmo = cpu_to_le32(80); - payload.open_reject_cmdretries_data_retries = cpu_to_le32(0xff00ff); - rc = mpi_build_cmd(pm8001_ha, circularQ, opc, &payload); - return rc; - -} - -const struct pm8001_dispatch pm8001_8001_dispatch = { - .name = "pmc8001", - .chip_init = pm8001_chip_init, - .chip_soft_rst = pm8001_chip_soft_rst, - .chip_rst = pm8001_hw_chip_rst, - .chip_iounmap = pm8001_chip_iounmap, - .isr = pm8001_chip_isr, - .is_our_interupt = pm8001_chip_is_our_interupt, - .isr_process_oq = process_oq, - .interrupt_enable = pm8001_chip_interrupt_enable, - .interrupt_disable = pm8001_chip_interrupt_disable, - .make_prd = pm8001_chip_make_sg, - .smp_req = pm8001_chip_smp_req, - .ssp_io_req = pm8001_chip_ssp_io_req, - .sata_req = pm8001_chip_sata_req, - .phy_start_req = pm8001_chip_phy_start_req, - .phy_stop_req = pm8001_chip_phy_stop_req, - .reg_dev_req = pm8001_chip_reg_dev_req, - .dereg_dev_req = pm8001_chip_dereg_dev_req, - .phy_ctl_req = pm8001_chip_phy_ctl_req, - .task_abort = pm8001_chip_abort_task, - .ssp_tm_req = pm8001_chip_ssp_tm_req, - .get_nvmd_req = pm8001_chip_get_nvmd_req, - .set_nvmd_req = pm8001_chip_set_nvmd_req, - .fw_flash_update_req = pm8001_chip_fw_flash_update_req, - .set_dev_state_req = pm8001_chip_set_dev_state_req, - .sas_re_init_req = pm8001_chip_sas_re_initialization, -}; - diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.h b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.h deleted file mode 100644 index 1a4611eb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_hwi.h +++ /dev/null @@ -1,1029 +0,0 @@ -/* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ -#ifndef _PMC8001_REG_H_ -#define _PMC8001_REG_H_ - -#include -#include - - -/* for Request Opcode of IOMB */ -#define OPC_INB_ECHO 1 /* 0x000 */ -#define OPC_INB_PHYSTART 4 /* 0x004 */ -#define OPC_INB_PHYSTOP 5 /* 0x005 */ -#define OPC_INB_SSPINIIOSTART 6 /* 0x006 */ -#define OPC_INB_SSPINITMSTART 7 /* 0x007 */ -#define OPC_INB_SSPINIEXTIOSTART 8 /* 0x008 */ -#define OPC_INB_DEV_HANDLE_ACCEPT 9 /* 0x009 */ -#define OPC_INB_SSPTGTIOSTART 10 /* 0x00A */ -#define OPC_INB_SSPTGTRSPSTART 11 /* 0x00B */ -#define OPC_INB_SSPINIEDCIOSTART 12 /* 0x00C */ -#define OPC_INB_SSPINIEXTEDCIOSTART 13 /* 0x00D */ -#define OPC_INB_SSPTGTEDCIOSTART 14 /* 0x00E */ -#define OPC_INB_SSP_ABORT 15 /* 0x00F */ -#define OPC_INB_DEREG_DEV_HANDLE 16 /* 0x010 */ -#define OPC_INB_GET_DEV_HANDLE 17 /* 0x011 */ -#define OPC_INB_SMP_REQUEST 18 /* 0x012 */ -/* SMP_RESPONSE is removed */ -#define OPC_INB_SMP_RESPONSE 19 /* 0x013 */ -#define OPC_INB_SMP_ABORT 20 /* 0x014 */ -#define OPC_INB_REG_DEV 22 /* 0x016 */ -#define OPC_INB_SATA_HOST_OPSTART 23 /* 0x017 */ -#define OPC_INB_SATA_ABORT 24 /* 0x018 */ -#define OPC_INB_LOCAL_PHY_CONTROL 25 /* 0x019 */ -#define OPC_INB_GET_DEV_INFO 26 /* 0x01A */ -#define OPC_INB_FW_FLASH_UPDATE 32 /* 0x020 */ -#define OPC_INB_GPIO 34 /* 0x022 */ -#define OPC_INB_SAS_DIAG_MODE_START_END 35 /* 0x023 */ -#define OPC_INB_SAS_DIAG_EXECUTE 36 /* 0x024 */ -#define OPC_INB_SAS_HW_EVENT_ACK 37 /* 0x025 */ -#define OPC_INB_GET_TIME_STAMP 38 /* 0x026 */ -#define OPC_INB_PORT_CONTROL 39 /* 0x027 */ -#define OPC_INB_GET_NVMD_DATA 40 /* 0x028 */ -#define OPC_INB_SET_NVMD_DATA 41 /* 0x029 */ -#define OPC_INB_SET_DEVICE_STATE 42 /* 0x02A */ -#define OPC_INB_GET_DEVICE_STATE 43 /* 0x02B */ -#define OPC_INB_SET_DEV_INFO 44 /* 0x02C */ -#define OPC_INB_SAS_RE_INITIALIZE 45 /* 0x02D */ - -/* for Response Opcode of IOMB */ -#define OPC_OUB_ECHO 1 /* 0x001 */ -#define OPC_OUB_HW_EVENT 4 /* 0x004 */ -#define OPC_OUB_SSP_COMP 5 /* 0x005 */ -#define OPC_OUB_SMP_COMP 6 /* 0x006 */ -#define OPC_OUB_LOCAL_PHY_CNTRL 7 /* 0x007 */ -#define OPC_OUB_DEV_REGIST 10 /* 0x00A */ -#define OPC_OUB_DEREG_DEV 11 /* 0x00B */ -#define OPC_OUB_GET_DEV_HANDLE 12 /* 0x00C */ -#define OPC_OUB_SATA_COMP 13 /* 0x00D */ -#define OPC_OUB_SATA_EVENT 14 /* 0x00E */ -#define OPC_OUB_SSP_EVENT 15 /* 0x00F */ -#define OPC_OUB_DEV_HANDLE_ARRIV 16 /* 0x010 */ -/* SMP_RECEIVED Notification is removed */ -#define OPC_OUB_SMP_RECV_EVENT 17 /* 0x011 */ -#define OPC_OUB_SSP_RECV_EVENT 18 /* 0x012 */ -#define OPC_OUB_DEV_INFO 19 /* 0x013 */ -#define OPC_OUB_FW_FLASH_UPDATE 20 /* 0x014 */ -#define OPC_OUB_GPIO_RESPONSE 22 /* 0x016 */ -#define OPC_OUB_GPIO_EVENT 23 /* 0x017 */ -#define OPC_OUB_GENERAL_EVENT 24 /* 0x018 */ -#define OPC_OUB_SSP_ABORT_RSP 26 /* 0x01A */ -#define OPC_OUB_SATA_ABORT_RSP 27 /* 0x01B */ -#define OPC_OUB_SAS_DIAG_MODE_START_END 28 /* 0x01C */ -#define OPC_OUB_SAS_DIAG_EXECUTE 29 /* 0x01D */ -#define OPC_OUB_GET_TIME_STAMP 30 /* 0x01E */ -#define OPC_OUB_SAS_HW_EVENT_ACK 31 /* 0x01F */ -#define OPC_OUB_PORT_CONTROL 32 /* 0x020 */ -#define OPC_OUB_SKIP_ENTRY 33 /* 0x021 */ -#define OPC_OUB_SMP_ABORT_RSP 34 /* 0x022 */ -#define OPC_OUB_GET_NVMD_DATA 35 /* 0x023 */ -#define OPC_OUB_SET_NVMD_DATA 36 /* 0x024 */ -#define OPC_OUB_DEVICE_HANDLE_REMOVAL 37 /* 0x025 */ -#define OPC_OUB_SET_DEVICE_STATE 38 /* 0x026 */ -#define OPC_OUB_GET_DEVICE_STATE 39 /* 0x027 */ -#define OPC_OUB_SET_DEV_INFO 40 /* 0x028 */ -#define OPC_OUB_SAS_RE_INITIALIZE 41 /* 0x029 */ - -/* for phy start*/ -#define SPINHOLD_DISABLE (0x00 << 14) -#define SPINHOLD_ENABLE (0x01 << 14) -#define LINKMODE_SAS (0x01 << 12) -#define LINKMODE_DSATA (0x02 << 12) -#define LINKMODE_AUTO (0x03 << 12) -#define LINKRATE_15 (0x01 << 8) -#define LINKRATE_30 (0x02 << 8) -#define LINKRATE_60 (0x04 << 8) - -struct mpi_msg_hdr{ - __le32 header; /* Bits [11:0] - Message operation code */ - /* Bits [15:12] - Message Category */ - /* Bits [21:16] - Outboundqueue ID for the - operation completion message */ - /* Bits [23:22] - Reserved */ - /* Bits [28:24] - Buffer Count, indicates how - many buffer are allocated for the massage */ - /* Bits [30:29] - Reserved */ - /* Bits [31] - Message Valid bit */ -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of PHY Start Command - * use to describe enable the phy (64 bytes) - */ -struct phy_start_req { - __le32 tag; - __le32 ase_sh_lm_slr_phyid; - struct sas_identify_frame sas_identify; - u32 reserved[5]; -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of PHY Start Command - * use to disable the phy (64 bytes) - */ -struct phy_stop_req { - __le32 tag; - __le32 phy_id; - u32 reserved[13]; -} __attribute__((packed, aligned(4))); - - -/* set device bits fis - device to host */ -struct set_dev_bits_fis { - u8 fis_type; /* 0xA1*/ - u8 n_i_pmport; - /* b7 : n Bit. Notification bit. If set device needs attention. */ - /* b6 : i Bit. Interrupt Bit */ - /* b5-b4: reserved2 */ - /* b3-b0: PM Port */ - u8 status; - u8 error; - u32 _r_a; -} __attribute__ ((packed)); -/* PIO setup FIS - device to host */ -struct pio_setup_fis { - u8 fis_type; /* 0x5f */ - u8 i_d_pmPort; - /* b7 : reserved */ - /* b6 : i bit. Interrupt bit */ - /* b5 : d bit. data transfer direction. set to 1 for device to host - xfer */ - /* b4 : reserved */ - /* b3-b0: PM Port */ - u8 status; - u8 error; - u8 lbal; - u8 lbam; - u8 lbah; - u8 device; - u8 lbal_exp; - u8 lbam_exp; - u8 lbah_exp; - u8 _r_a; - u8 sector_count; - u8 sector_count_exp; - u8 _r_b; - u8 e_status; - u8 _r_c[2]; - u8 transfer_count; -} __attribute__ ((packed)); - -/* - * brief the data structure of SATA Completion Response - * use to describe the sata task response (64 bytes) - */ -struct sata_completion_resp { - __le32 tag; - __le32 status; - __le32 param; - u32 sata_resp[12]; -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of SAS HW Event Notification - * use to alert the host about the hardware event(64 bytes) - */ -struct hw_event_resp { - __le32 lr_evt_status_phyid_portid; - __le32 evt_param; - __le32 npip_portstate; - struct sas_identify_frame sas_identify; - struct dev_to_host_fis sata_fis; -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of REGISTER DEVICE Command - * use to describe MPI REGISTER DEVICE Command (64 bytes) - */ - -struct reg_dev_req { - __le32 tag; - __le32 phyid_portid; - __le32 dtype_dlr_retry; - __le32 firstburstsize_ITNexustimeout; - u8 sas_addr[SAS_ADDR_SIZE]; - __le32 upper_device_id; - u32 reserved[8]; -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of DEREGISTER DEVICE Command - * use to request spc to remove all internal resources associated - * with the device id (64 bytes) - */ - -struct dereg_dev_req { - __le32 tag; - __le32 device_id; - u32 reserved[13]; -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of DEVICE_REGISTRATION Response - * use to notify the completion of the device registration (64 bytes) - */ - -struct dev_reg_resp { - __le32 tag; - __le32 status; - __le32 device_id; - u32 reserved[12]; -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of Local PHY Control Command - * use to issue PHY CONTROL to local phy (64 bytes) - */ -struct local_phy_ctl_req { - __le32 tag; - __le32 phyop_phyid; - u32 reserved1[13]; -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of Local Phy Control Response - * use to describe MPI Local Phy Control Response (64 bytes) - */ -struct local_phy_ctl_resp { - __le32 tag; - __le32 phyop_phyid; - __le32 status; - u32 reserved[12]; -} __attribute__((packed, aligned(4))); - - -#define OP_BITS 0x0000FF00 -#define ID_BITS 0x0000000F - -/* - * brief the data structure of PORT Control Command - * use to control port properties (64 bytes) - */ - -struct port_ctl_req { - __le32 tag; - __le32 portop_portid; - __le32 param0; - __le32 param1; - u32 reserved1[11]; -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of HW Event Ack Command - * use to acknowledge receive HW event (64 bytes) - */ - -struct hw_event_ack_req { - __le32 tag; - __le32 sea_phyid_portid; - __le32 param0; - __le32 param1; - u32 reserved1[11]; -} __attribute__((packed, aligned(4))); - - -/* - * brief the data structure of SSP Completion Response - * use to indicate a SSP Completion (n bytes) - */ -struct ssp_completion_resp { - __le32 tag; - __le32 status; - __le32 param; - __le32 ssptag_rescv_rescpad; - struct ssp_response_iu ssp_resp_iu; - __le32 residual_count; -} __attribute__((packed, aligned(4))); - - -#define SSP_RESCV_BIT 0x00010000 - -/* - * brief the data structure of SATA EVNET esponse - * use to indicate a SATA Completion (64 bytes) - */ - -struct sata_event_resp { - __le32 tag; - __le32 event; - __le32 port_id; - __le32 device_id; - u32 reserved[11]; -} __attribute__((packed, aligned(4))); - -/* - * brief the data structure of SSP EVNET esponse - * use to indicate a SSP Completion (64 bytes) - */ - -struct ssp_event_resp { - __le32 tag; - __le32 event; - __le32 port_id; - __le32 device_id; - u32 reserved[11]; -} __attribute__((packed, aligned(4))); - -/** - * brief the data structure of General Event Notification Response - * use to describe MPI General Event Notification Response (64 bytes) - */ -struct general_event_resp { - __le32 status; - __le32 inb_IOMB_payload[14]; -} __attribute__((packed, aligned(4))); - - -#define GENERAL_EVENT_PAYLOAD 14 -#define OPCODE_BITS 0x00000fff - -/* - * brief the data structure of SMP Request Command - * use to describe MPI SMP REQUEST Command (64 bytes) - */ -struct smp_req { - __le32 tag; - __le32 device_id; - __le32 len_ip_ir; - /* Bits [0] - Indirect response */ - /* Bits [1] - Indirect Payload */ - /* Bits [15:2] - Reserved */ - /* Bits [23:16] - direct payload Len */ - /* Bits [31:24] - Reserved */ - u8 smp_req16[16]; - union { - u8 smp_req[32]; - struct { - __le64 long_req_addr;/* sg dma address, LE */ - __le32 long_req_size;/* LE */ - u32 _r_a; - __le64 long_resp_addr;/* sg dma address, LE */ - __le32 long_resp_size;/* LE */ - u32 _r_b; - } long_smp_req;/* sequencer extension */ - }; -} __attribute__((packed, aligned(4))); -/* - * brief the data structure of SMP Completion Response - * use to describe MPI SMP Completion Response (64 bytes) - */ -struct smp_completion_resp { - __le32 tag; - __le32 status; - __le32 param; - __le32 _r_a[12]; -} __attribute__((packed, aligned(4))); - -/* - *brief the data structure of SSP SMP SATA Abort Command - * use to describe MPI SSP SMP & SATA Abort Command (64 bytes) - */ -struct task_abort_req { - __le32 tag; - __le32 device_id; - __le32 tag_to_abort; - __le32 abort_all; - u32 reserved[11]; -} __attribute__((packed, aligned(4))); - -/* These flags used for SSP SMP & SATA Abort */ -#define ABORT_MASK 0x3 -#define ABORT_SINGLE 0x0 -#define ABORT_ALL 0x1 - -/** - * brief the data structure of SSP SATA SMP Abort Response - * use to describe SSP SMP & SATA Abort Response ( 64 bytes) - */ -struct task_abort_resp { - __le32 tag; - __le32 status; - __le32 scp; - u32 reserved[12]; -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of SAS Diagnostic Start/End Command - * use to describe MPI SAS Diagnostic Start/End Command (64 bytes) - */ -struct sas_diag_start_end_req { - __le32 tag; - __le32 operation_phyid; - u32 reserved[13]; -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of SAS Diagnostic Execute Command - * use to describe MPI SAS Diagnostic Execute Command (64 bytes) - */ -struct sas_diag_execute_req{ - __le32 tag; - __le32 cmdtype_cmddesc_phyid; - __le32 pat1_pat2; - __le32 threshold; - __le32 codepat_errmsk; - __le32 pmon; - __le32 pERF1CTL; - u32 reserved[8]; -} __attribute__((packed, aligned(4))); - - -#define SAS_DIAG_PARAM_BYTES 24 - -/* - * brief the data structure of Set Device State Command - * use to describe MPI Set Device State Command (64 bytes) - */ -struct set_dev_state_req { - __le32 tag; - __le32 device_id; - __le32 nds; - u32 reserved[12]; -} __attribute__((packed, aligned(4))); - -/* - * brief the data structure of sas_re_initialization - */ -struct sas_re_initialization_req { - - __le32 tag; - __le32 SSAHOLT;/* bit29-set max port; - ** bit28-set open reject cmd retries. - ** bit27-set open reject data retries. - ** bit26-set open reject option, remap:1 or not:0. - ** bit25-set sata head of line time out. - */ - __le32 reserved_maxPorts; - __le32 open_reject_cmdretries_data_retries;/* cmd retries: 31-bit16; - * data retries: bit15-bit0. - */ - __le32 sata_hol_tmo; - u32 reserved1[10]; -} __attribute__((packed, aligned(4))); - -/* - * brief the data structure of SATA Start Command - * use to describe MPI SATA IO Start Command (64 bytes) - */ - -struct sata_start_req { - __le32 tag; - __le32 device_id; - __le32 data_len; - __le32 ncqtag_atap_dir_m; - struct host_to_dev_fis sata_fis; - u32 reserved1; - u32 reserved2; - u32 addr_low; - u32 addr_high; - __le32 len; - __le32 esgl; -} __attribute__((packed, aligned(4))); - -/** - * brief the data structure of SSP INI TM Start Command - * use to describe MPI SSP INI TM Start Command (64 bytes) - */ -struct ssp_ini_tm_start_req { - __le32 tag; - __le32 device_id; - __le32 relate_tag; - __le32 tmf; - u8 lun[8]; - __le32 ds_ads_m; - u32 reserved[8]; -} __attribute__((packed, aligned(4))); - - -struct ssp_info_unit { - u8 lun[8];/* SCSI Logical Unit Number */ - u8 reserved1;/* reserved */ - u8 efb_prio_attr; - /* B7 : enabledFirstBurst */ - /* B6-3 : taskPriority */ - /* B2-0 : taskAttribute */ - u8 reserved2; /* reserved */ - u8 additional_cdb_len; - /* B7-2 : additional_cdb_len */ - /* B1-0 : reserved */ - u8 cdb[16];/* The SCSI CDB up to 16 bytes length */ -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of SSP INI IO Start Command - * use to describe MPI SSP INI IO Start Command (64 bytes) - */ -struct ssp_ini_io_start_req { - __le32 tag; - __le32 device_id; - __le32 data_len; - __le32 dir_m_tlr; - struct ssp_info_unit ssp_iu; - __le32 addr_low; - __le32 addr_high; - __le32 len; - __le32 esgl; -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of Firmware download - * use to describe MPI FW DOWNLOAD Command (64 bytes) - */ -struct fw_flash_Update_req { - __le32 tag; - __le32 cur_image_offset; - __le32 cur_image_len; - __le32 total_image_len; - u32 reserved0[7]; - __le32 sgl_addr_lo; - __le32 sgl_addr_hi; - __le32 len; - __le32 ext_reserved; -} __attribute__((packed, aligned(4))); - - -#define FWFLASH_IOMB_RESERVED_LEN 0x07 -/** - * brief the data structure of FW_FLASH_UPDATE Response - * use to describe MPI FW_FLASH_UPDATE Response (64 bytes) - * - */ -struct fw_flash_Update_resp { - dma_addr_t tag; - __le32 status; - u32 reserved[13]; -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of Get NVM Data Command - * use to get data from NVM in HBA(64 bytes) - */ -struct get_nvm_data_req { - __le32 tag; - __le32 len_ir_vpdd; - __le32 vpd_offset; - u32 reserved[8]; - __le32 resp_addr_lo; - __le32 resp_addr_hi; - __le32 resp_len; - u32 reserved1; -} __attribute__((packed, aligned(4))); - - -struct set_nvm_data_req { - __le32 tag; - __le32 len_ir_vpdd; - __le32 vpd_offset; - __le32 reserved[8]; - __le32 resp_addr_lo; - __le32 resp_addr_hi; - __le32 resp_len; - u32 reserved1; -} __attribute__((packed, aligned(4))); - - -#define TWI_DEVICE 0x0 -#define C_SEEPROM 0x1 -#define VPD_FLASH 0x4 -#define AAP1_RDUMP 0x5 -#define IOP_RDUMP 0x6 -#define EXPAN_ROM 0x7 - -#define IPMode 0x80000000 -#define NVMD_TYPE 0x0000000F -#define NVMD_STAT 0x0000FFFF -#define NVMD_LEN 0xFF000000 -/** - * brief the data structure of Get NVMD Data Response - * use to describe MPI Get NVMD Data Response (64 bytes) - */ -struct get_nvm_data_resp { - __le32 tag; - __le32 ir_tda_bn_dps_das_nvm; - __le32 dlen_status; - __le32 nvm_data[12]; -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of SAS Diagnostic Start/End Response - * use to describe MPI SAS Diagnostic Start/End Response (64 bytes) - * - */ -struct sas_diag_start_end_resp { - __le32 tag; - __le32 status; - u32 reserved[13]; -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of SAS Diagnostic Execute Response - * use to describe MPI SAS Diagnostic Execute Response (64 bytes) - * - */ -struct sas_diag_execute_resp { - __le32 tag; - __le32 cmdtype_cmddesc_phyid; - __le32 Status; - __le32 ReportData; - u32 reserved[11]; -} __attribute__((packed, aligned(4))); - - -/** - * brief the data structure of Set Device State Response - * use to describe MPI Set Device State Response (64 bytes) - * - */ -struct set_dev_state_resp { - __le32 tag; - __le32 status; - __le32 device_id; - __le32 pds_nds; - u32 reserved[11]; -} __attribute__((packed, aligned(4))); - - -#define NDS_BITS 0x0F -#define PDS_BITS 0xF0 - -/* - * HW Events type - */ - -#define HW_EVENT_RESET_START 0x01 -#define HW_EVENT_CHIP_RESET_COMPLETE 0x02 -#define HW_EVENT_PHY_STOP_STATUS 0x03 -#define HW_EVENT_SAS_PHY_UP 0x04 -#define HW_EVENT_SATA_PHY_UP 0x05 -#define HW_EVENT_SATA_SPINUP_HOLD 0x06 -#define HW_EVENT_PHY_DOWN 0x07 -#define HW_EVENT_PORT_INVALID 0x08 -#define HW_EVENT_BROADCAST_CHANGE 0x09 -#define HW_EVENT_PHY_ERROR 0x0A -#define HW_EVENT_BROADCAST_SES 0x0B -#define HW_EVENT_INBOUND_CRC_ERROR 0x0C -#define HW_EVENT_HARD_RESET_RECEIVED 0x0D -#define HW_EVENT_MALFUNCTION 0x0E -#define HW_EVENT_ID_FRAME_TIMEOUT 0x0F -#define HW_EVENT_BROADCAST_EXP 0x10 -#define HW_EVENT_PHY_START_STATUS 0x11 -#define HW_EVENT_LINK_ERR_INVALID_DWORD 0x12 -#define HW_EVENT_LINK_ERR_DISPARITY_ERROR 0x13 -#define HW_EVENT_LINK_ERR_CODE_VIOLATION 0x14 -#define HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH 0x15 -#define HW_EVENT_LINK_ERR_PHY_RESET_FAILED 0x16 -#define HW_EVENT_PORT_RECOVERY_TIMER_TMO 0x17 -#define HW_EVENT_PORT_RECOVER 0x18 -#define HW_EVENT_PORT_RESET_TIMER_TMO 0x19 -#define HW_EVENT_PORT_RESET_COMPLETE 0x20 -#define EVENT_BROADCAST_ASYNCH_EVENT 0x21 - -/* port state */ -#define PORT_NOT_ESTABLISHED 0x00 -#define PORT_VALID 0x01 -#define PORT_LOSTCOMM 0x02 -#define PORT_IN_RESET 0x04 -#define PORT_INVALID 0x08 - -/* - * SSP/SMP/SATA IO Completion Status values - */ - -#define IO_SUCCESS 0x00 -#define IO_ABORTED 0x01 -#define IO_OVERFLOW 0x02 -#define IO_UNDERFLOW 0x03 -#define IO_FAILED 0x04 -#define IO_ABORT_RESET 0x05 -#define IO_NOT_VALID 0x06 -#define IO_NO_DEVICE 0x07 -#define IO_ILLEGAL_PARAMETER 0x08 -#define IO_LINK_FAILURE 0x09 -#define IO_PROG_ERROR 0x0A -#define IO_EDC_IN_ERROR 0x0B -#define IO_EDC_OUT_ERROR 0x0C -#define IO_ERROR_HW_TIMEOUT 0x0D -#define IO_XFER_ERROR_BREAK 0x0E -#define IO_XFER_ERROR_PHY_NOT_READY 0x0F -#define IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED 0x10 -#define IO_OPEN_CNX_ERROR_ZONE_VIOLATION 0x11 -#define IO_OPEN_CNX_ERROR_BREAK 0x12 -#define IO_OPEN_CNX_ERROR_IT_NEXUS_LOSS 0x13 -#define IO_OPEN_CNX_ERROR_BAD_DESTINATION 0x14 -#define IO_OPEN_CNX_ERROR_CONNECTION_RATE_NOT_SUPPORTED 0x15 -#define IO_OPEN_CNX_ERROR_STP_RESOURCES_BUSY 0x16 -#define IO_OPEN_CNX_ERROR_WRONG_DESTINATION 0x17 -#define IO_OPEN_CNX_ERROR_UNKNOWN_ERROR 0x18 -#define IO_XFER_ERROR_NAK_RECEIVED 0x19 -#define IO_XFER_ERROR_ACK_NAK_TIMEOUT 0x1A -#define IO_XFER_ERROR_PEER_ABORTED 0x1B -#define IO_XFER_ERROR_RX_FRAME 0x1C -#define IO_XFER_ERROR_DMA 0x1D -#define IO_XFER_ERROR_CREDIT_TIMEOUT 0x1E -#define IO_XFER_ERROR_SATA_LINK_TIMEOUT 0x1F -#define IO_XFER_ERROR_SATA 0x20 -#define IO_XFER_ERROR_ABORTED_DUE_TO_SRST 0x22 -#define IO_XFER_ERROR_REJECTED_NCQ_MODE 0x21 -#define IO_XFER_ERROR_ABORTED_NCQ_MODE 0x23 -#define IO_XFER_OPEN_RETRY_TIMEOUT 0x24 -#define IO_XFER_SMP_RESP_CONNECTION_ERROR 0x25 -#define IO_XFER_ERROR_UNEXPECTED_PHASE 0x26 -#define IO_XFER_ERROR_XFER_RDY_OVERRUN 0x27 -#define IO_XFER_ERROR_XFER_RDY_NOT_EXPECTED 0x28 - -#define IO_XFER_ERROR_CMD_ISSUE_ACK_NAK_TIMEOUT 0x30 -#define IO_XFER_ERROR_CMD_ISSUE_BREAK_BEFORE_ACK_NAK 0x31 -#define IO_XFER_ERROR_CMD_ISSUE_PHY_DOWN_BEFORE_ACK_NAK 0x32 - -#define IO_XFER_ERROR_OFFSET_MISMATCH 0x34 -#define IO_XFER_ERROR_XFER_ZERO_DATA_LEN 0x35 -#define IO_XFER_CMD_FRAME_ISSUED 0x36 -#define IO_ERROR_INTERNAL_SMP_RESOURCE 0x37 -#define IO_PORT_IN_RESET 0x38 -#define IO_DS_NON_OPERATIONAL 0x39 -#define IO_DS_IN_RECOVERY 0x3A -#define IO_TM_TAG_NOT_FOUND 0x3B -#define IO_XFER_PIO_SETUP_ERROR 0x3C -#define IO_SSP_EXT_IU_ZERO_LEN_ERROR 0x3D -#define IO_DS_IN_ERROR 0x3E -#define IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY 0x3F -#define IO_ABORT_IN_PROGRESS 0x40 -#define IO_ABORT_DELAYED 0x41 -#define IO_INVALID_LENGTH 0x42 - -/* WARNING: This error code must always be the last number. - * If you add error code, modify this code also - * It is used as an index - */ -#define IO_ERROR_UNKNOWN_GENERIC 0x43 - -/* MSGU CONFIGURATION TABLE*/ - -#define SPC_MSGU_CFG_TABLE_UPDATE 0x01/* Inbound doorbell bit0 */ -#define SPC_MSGU_CFG_TABLE_RESET 0x02/* Inbound doorbell bit1 */ -#define SPC_MSGU_CFG_TABLE_FREEZE 0x04/* Inbound doorbell bit2 */ -#define SPC_MSGU_CFG_TABLE_UNFREEZE 0x08/* Inbound doorbell bit4 */ -#define MSGU_IBDB_SET 0x04 -#define MSGU_HOST_INT_STATUS 0x08 -#define MSGU_HOST_INT_MASK 0x0C -#define MSGU_IOPIB_INT_STATUS 0x18 -#define MSGU_IOPIB_INT_MASK 0x1C -#define MSGU_IBDB_CLEAR 0x20/* RevB - Host not use */ -#define MSGU_MSGU_CONTROL 0x24 -#define MSGU_ODR 0x3C/* RevB */ -#define MSGU_ODCR 0x40/* RevB */ -#define MSGU_SCRATCH_PAD_0 0x44 -#define MSGU_SCRATCH_PAD_1 0x48 -#define MSGU_SCRATCH_PAD_2 0x4C -#define MSGU_SCRATCH_PAD_3 0x50 -#define MSGU_HOST_SCRATCH_PAD_0 0x54 -#define MSGU_HOST_SCRATCH_PAD_1 0x58 -#define MSGU_HOST_SCRATCH_PAD_2 0x5C -#define MSGU_HOST_SCRATCH_PAD_3 0x60 -#define MSGU_HOST_SCRATCH_PAD_4 0x64 -#define MSGU_HOST_SCRATCH_PAD_5 0x68 -#define MSGU_HOST_SCRATCH_PAD_6 0x6C -#define MSGU_HOST_SCRATCH_PAD_7 0x70 -#define MSGU_ODMR 0x74/* RevB */ - -/* bit definition for ODMR register */ -#define ODMR_MASK_ALL 0xFFFFFFFF/* mask all - interrupt vector */ -#define ODMR_CLEAR_ALL 0/* clear all - interrupt vector */ -/* bit definition for ODCR register */ -#define ODCR_CLEAR_ALL 0xFFFFFFFF /* mask all - interrupt vector*/ -/* MSIX Interupts */ -#define MSIX_TABLE_OFFSET 0x2000 -#define MSIX_TABLE_ELEMENT_SIZE 0x10 -#define MSIX_INTERRUPT_CONTROL_OFFSET 0xC -#define MSIX_TABLE_BASE (MSIX_TABLE_OFFSET + MSIX_INTERRUPT_CONTROL_OFFSET) -#define MSIX_INTERRUPT_DISABLE 0x1 -#define MSIX_INTERRUPT_ENABLE 0x0 - - -/* state definition for Scratch Pad1 register */ -#define SCRATCH_PAD1_POR 0x00 /* power on reset state */ -#define SCRATCH_PAD1_SFR 0x01 /* soft reset state */ -#define SCRATCH_PAD1_ERR 0x02 /* error state */ -#define SCRATCH_PAD1_RDY 0x03 /* ready state */ -#define SCRATCH_PAD1_RST 0x04 /* soft reset toggle flag */ -#define SCRATCH_PAD1_AAP1RDY_RST 0x08 /* AAP1 ready for soft reset */ -#define SCRATCH_PAD1_STATE_MASK 0xFFFFFFF0 /* ScratchPad1 - Mask, bit1-0 State, bit2 Soft Reset, bit3 FW RDY for Soft Reset */ -#define SCRATCH_PAD1_RESERVED 0x000003F8 /* Scratch Pad1 - Reserved bit 3 to 9 */ - - /* state definition for Scratch Pad2 register */ -#define SCRATCH_PAD2_POR 0x00 /* power on state */ -#define SCRATCH_PAD2_SFR 0x01 /* soft reset state */ -#define SCRATCH_PAD2_ERR 0x02 /* error state */ -#define SCRATCH_PAD2_RDY 0x03 /* ready state */ -#define SCRATCH_PAD2_FWRDY_RST 0x04 /* FW ready for soft reset flag*/ -#define SCRATCH_PAD2_IOPRDY_RST 0x08 /* IOP ready for soft reset */ -#define SCRATCH_PAD2_STATE_MASK 0xFFFFFFF4 /* ScratchPad 2 - Mask, bit1-0 State */ -#define SCRATCH_PAD2_RESERVED 0x000003FC /* Scratch Pad1 - Reserved bit 2 to 9 */ - -#define SCRATCH_PAD_ERROR_MASK 0xFFFFFC00 /* Error mask bits */ -#define SCRATCH_PAD_STATE_MASK 0x00000003 /* State Mask bits */ - -/* main configuration offset - byte offset */ -#define MAIN_SIGNATURE_OFFSET 0x00/* DWORD 0x00 */ -#define MAIN_INTERFACE_REVISION 0x04/* DWORD 0x01 */ -#define MAIN_FW_REVISION 0x08/* DWORD 0x02 */ -#define MAIN_MAX_OUTSTANDING_IO_OFFSET 0x0C/* DWORD 0x03 */ -#define MAIN_MAX_SGL_OFFSET 0x10/* DWORD 0x04 */ -#define MAIN_CNTRL_CAP_OFFSET 0x14/* DWORD 0x05 */ -#define MAIN_GST_OFFSET 0x18/* DWORD 0x06 */ -#define MAIN_IBQ_OFFSET 0x1C/* DWORD 0x07 */ -#define MAIN_OBQ_OFFSET 0x20/* DWORD 0x08 */ -#define MAIN_IQNPPD_HPPD_OFFSET 0x24/* DWORD 0x09 */ -#define MAIN_OB_HW_EVENT_PID03_OFFSET 0x28/* DWORD 0x0A */ -#define MAIN_OB_HW_EVENT_PID47_OFFSET 0x2C/* DWORD 0x0B */ -#define MAIN_OB_NCQ_EVENT_PID03_OFFSET 0x30/* DWORD 0x0C */ -#define MAIN_OB_NCQ_EVENT_PID47_OFFSET 0x34/* DWORD 0x0D */ -#define MAIN_TITNX_EVENT_PID03_OFFSET 0x38/* DWORD 0x0E */ -#define MAIN_TITNX_EVENT_PID47_OFFSET 0x3C/* DWORD 0x0F */ -#define MAIN_OB_SSP_EVENT_PID03_OFFSET 0x40/* DWORD 0x10 */ -#define MAIN_OB_SSP_EVENT_PID47_OFFSET 0x44/* DWORD 0x11 */ -#define MAIN_OB_SMP_EVENT_PID03_OFFSET 0x48/* DWORD 0x12 */ -#define MAIN_OB_SMP_EVENT_PID47_OFFSET 0x4C/* DWORD 0x13 */ -#define MAIN_EVENT_LOG_ADDR_HI 0x50/* DWORD 0x14 */ -#define MAIN_EVENT_LOG_ADDR_LO 0x54/* DWORD 0x15 */ -#define MAIN_EVENT_LOG_BUFF_SIZE 0x58/* DWORD 0x16 */ -#define MAIN_EVENT_LOG_OPTION 0x5C/* DWORD 0x17 */ -#define MAIN_IOP_EVENT_LOG_ADDR_HI 0x60/* DWORD 0x18 */ -#define MAIN_IOP_EVENT_LOG_ADDR_LO 0x64/* DWORD 0x19 */ -#define MAIN_IOP_EVENT_LOG_BUFF_SIZE 0x68/* DWORD 0x1A */ -#define MAIN_IOP_EVENT_LOG_OPTION 0x6C/* DWORD 0x1B */ -#define MAIN_FATAL_ERROR_INTERRUPT 0x70/* DWORD 0x1C */ -#define MAIN_FATAL_ERROR_RDUMP0_OFFSET 0x74/* DWORD 0x1D */ -#define MAIN_FATAL_ERROR_RDUMP0_LENGTH 0x78/* DWORD 0x1E */ -#define MAIN_FATAL_ERROR_RDUMP1_OFFSET 0x7C/* DWORD 0x1F */ -#define MAIN_FATAL_ERROR_RDUMP1_LENGTH 0x80/* DWORD 0x20 */ -#define MAIN_HDA_FLAGS_OFFSET 0x84/* DWORD 0x21 */ -#define MAIN_ANALOG_SETUP_OFFSET 0x88/* DWORD 0x22 */ - -/* Gereral Status Table offset - byte offset */ -#define GST_GSTLEN_MPIS_OFFSET 0x00 -#define GST_IQ_FREEZE_STATE0_OFFSET 0x04 -#define GST_IQ_FREEZE_STATE1_OFFSET 0x08 -#define GST_MSGUTCNT_OFFSET 0x0C -#define GST_IOPTCNT_OFFSET 0x10 -#define GST_PHYSTATE_OFFSET 0x18 -#define GST_PHYSTATE0_OFFSET 0x18 -#define GST_PHYSTATE1_OFFSET 0x1C -#define GST_PHYSTATE2_OFFSET 0x20 -#define GST_PHYSTATE3_OFFSET 0x24 -#define GST_PHYSTATE4_OFFSET 0x28 -#define GST_PHYSTATE5_OFFSET 0x2C -#define GST_PHYSTATE6_OFFSET 0x30 -#define GST_PHYSTATE7_OFFSET 0x34 -#define GST_RERRINFO_OFFSET 0x44 - -/* General Status Table - MPI state */ -#define GST_MPI_STATE_UNINIT 0x00 -#define GST_MPI_STATE_INIT 0x01 -#define GST_MPI_STATE_TERMINATION 0x02 -#define GST_MPI_STATE_ERROR 0x03 -#define GST_MPI_STATE_MASK 0x07 - -#define MBIC_NMI_ENABLE_VPE0_IOP 0x000418 -#define MBIC_NMI_ENABLE_VPE0_AAP1 0x000418 -/* PCIE registers - BAR2(0x18), BAR1(win) 0x010000 */ -#define PCIE_EVENT_INTERRUPT_ENABLE 0x003040 -#define PCIE_EVENT_INTERRUPT 0x003044 -#define PCIE_ERROR_INTERRUPT_ENABLE 0x003048 -#define PCIE_ERROR_INTERRUPT 0x00304C -/* signature definition for host scratch pad0 register */ -#define SPC_SOFT_RESET_SIGNATURE 0x252acbcd -/* Signature for Soft Reset */ - -/* SPC Reset register - BAR4(0x20), BAR2(win) (need dynamic mapping) */ -#define SPC_REG_RESET 0x000000/* reset register */ - -/* bit difination for SPC_RESET register */ -#define SPC_REG_RESET_OSSP 0x00000001 -#define SPC_REG_RESET_RAAE 0x00000002 -#define SPC_REG_RESET_PCS_SPBC 0x00000004 -#define SPC_REG_RESET_PCS_IOP_SS 0x00000008 -#define SPC_REG_RESET_PCS_AAP1_SS 0x00000010 -#define SPC_REG_RESET_PCS_AAP2_SS 0x00000020 -#define SPC_REG_RESET_PCS_LM 0x00000040 -#define SPC_REG_RESET_PCS 0x00000080 -#define SPC_REG_RESET_GSM 0x00000100 -#define SPC_REG_RESET_DDR2 0x00010000 -#define SPC_REG_RESET_BDMA_CORE 0x00020000 -#define SPC_REG_RESET_BDMA_SXCBI 0x00040000 -#define SPC_REG_RESET_PCIE_AL_SXCBI 0x00080000 -#define SPC_REG_RESET_PCIE_PWR 0x00100000 -#define SPC_REG_RESET_PCIE_SFT 0x00200000 -#define SPC_REG_RESET_PCS_SXCBI 0x00400000 -#define SPC_REG_RESET_LMS_SXCBI 0x00800000 -#define SPC_REG_RESET_PMIC_SXCBI 0x01000000 -#define SPC_REG_RESET_PMIC_CORE 0x02000000 -#define SPC_REG_RESET_PCIE_PC_SXCBI 0x04000000 -#define SPC_REG_RESET_DEVICE 0x80000000 - -/* registers for BAR Shifting - BAR2(0x18), BAR1(win) */ -#define SPC_IBW_AXI_TRANSLATION_LOW 0x003258 - -#define MBIC_AAP1_ADDR_BASE 0x060000 -#define MBIC_IOP_ADDR_BASE 0x070000 -#define GSM_ADDR_BASE 0x0700000 -/* Dynamic map through Bar4 - 0x00700000 */ -#define GSM_CONFIG_RESET 0x00000000 -#define RAM_ECC_DB_ERR 0x00000018 -#define GSM_READ_ADDR_PARITY_INDIC 0x00000058 -#define GSM_WRITE_ADDR_PARITY_INDIC 0x00000060 -#define GSM_WRITE_DATA_PARITY_INDIC 0x00000068 -#define GSM_READ_ADDR_PARITY_CHECK 0x00000038 -#define GSM_WRITE_ADDR_PARITY_CHECK 0x00000040 -#define GSM_WRITE_DATA_PARITY_CHECK 0x00000048 - -#define RB6_ACCESS_REG 0x6A0000 -#define HDAC_EXEC_CMD 0x0002 -#define HDA_C_PA 0xcb -#define HDA_SEQ_ID_BITS 0x00ff0000 -#define HDA_GSM_OFFSET_BITS 0x00FFFFFF -#define MBIC_AAP1_ADDR_BASE 0x060000 -#define MBIC_IOP_ADDR_BASE 0x070000 -#define GSM_ADDR_BASE 0x0700000 -#define SPC_TOP_LEVEL_ADDR_BASE 0x000000 -#define GSM_CONFIG_RESET_VALUE 0x00003b00 -#define GPIO_ADDR_BASE 0x00090000 -#define GPIO_GPIO_0_0UTPUT_CTL_OFFSET 0x0000010c - -/* RB6 offset */ -#define SPC_RB6_OFFSET 0x80C0 -/* Magic number of soft reset for RB6 */ -#define RB6_MAGIC_NUMBER_RST 0x1234 - -/* Device Register status */ -#define DEVREG_SUCCESS 0x00 -#define DEVREG_FAILURE_OUT_OF_RESOURCE 0x01 -#define DEVREG_FAILURE_DEVICE_ALREADY_REGISTERED 0x02 -#define DEVREG_FAILURE_INVALID_PHY_ID 0x03 -#define DEVREG_FAILURE_PHY_ID_ALREADY_REGISTERED 0x04 -#define DEVREG_FAILURE_PORT_ID_OUT_OF_RANGE 0x05 -#define DEVREG_FAILURE_PORT_NOT_VALID_STATE 0x06 -#define DEVREG_FAILURE_DEVICE_TYPE_NOT_VALID 0x07 - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_init.c b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_init.c deleted file mode 100644 index 36efaa7c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_init.c +++ /dev/null @@ -1,908 +0,0 @@ -/* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ - -#include -#include "pm8001_sas.h" -#include "pm8001_chips.h" - -static struct scsi_transport_template *pm8001_stt; - -static const struct pm8001_chip_info pm8001_chips[] = { - [chip_8001] = { 8, &pm8001_8001_dispatch,}, -}; -static int pm8001_id; - -LIST_HEAD(hba_list); - -struct workqueue_struct *pm8001_wq; - -/** - * The main structure which LLDD must register for scsi core. - */ -static struct scsi_host_template pm8001_sht = { - .module = THIS_MODULE, - .name = DRV_NAME, - .queuecommand = sas_queuecommand, - .target_alloc = sas_target_alloc, - .slave_configure = sas_slave_configure, - .scan_finished = pm8001_scan_finished, - .scan_start = pm8001_scan_start, - .change_queue_depth = sas_change_queue_depth, - .change_queue_type = sas_change_queue_type, - .bios_param = sas_bios_param, - .can_queue = 1, - .cmd_per_lun = 1, - .this_id = -1, - .sg_tablesize = SG_ALL, - .max_sectors = SCSI_DEFAULT_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .eh_device_reset_handler = sas_eh_device_reset_handler, - .eh_bus_reset_handler = sas_eh_bus_reset_handler, - .target_destroy = sas_target_destroy, - .ioctl = sas_ioctl, - .shost_attrs = pm8001_host_attrs, -}; - -/** - * Sas layer call this function to execute specific task. - */ -static struct sas_domain_function_template pm8001_transport_ops = { - .lldd_dev_found = pm8001_dev_found, - .lldd_dev_gone = pm8001_dev_gone, - - .lldd_execute_task = pm8001_queue_command, - .lldd_control_phy = pm8001_phy_control, - - .lldd_abort_task = pm8001_abort_task, - .lldd_abort_task_set = pm8001_abort_task_set, - .lldd_clear_aca = pm8001_clear_aca, - .lldd_clear_task_set = pm8001_clear_task_set, - .lldd_I_T_nexus_reset = pm8001_I_T_nexus_reset, - .lldd_lu_reset = pm8001_lu_reset, - .lldd_query_task = pm8001_query_task, -}; - -/** - *pm8001_phy_init - initiate our adapter phys - *@pm8001_ha: our hba structure. - *@phy_id: phy id. - */ -static void __devinit pm8001_phy_init(struct pm8001_hba_info *pm8001_ha, - int phy_id) -{ - struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; - struct asd_sas_phy *sas_phy = &phy->sas_phy; - phy->phy_state = 0; - phy->pm8001_ha = pm8001_ha; - sas_phy->enabled = (phy_id < pm8001_ha->chip->n_phy) ? 1 : 0; - sas_phy->class = SAS; - sas_phy->iproto = SAS_PROTOCOL_ALL; - sas_phy->tproto = 0; - sas_phy->type = PHY_TYPE_PHYSICAL; - sas_phy->role = PHY_ROLE_INITIATOR; - sas_phy->oob_mode = OOB_NOT_CONNECTED; - sas_phy->linkrate = SAS_LINK_RATE_UNKNOWN; - sas_phy->id = phy_id; - sas_phy->sas_addr = &pm8001_ha->sas_addr[0]; - sas_phy->frame_rcvd = &phy->frame_rcvd[0]; - sas_phy->ha = (struct sas_ha_struct *)pm8001_ha->shost->hostdata; - sas_phy->lldd_phy = phy; -} - -/** - *pm8001_free - free hba - *@pm8001_ha: our hba structure. - * - */ -static void pm8001_free(struct pm8001_hba_info *pm8001_ha) -{ - int i; - - if (!pm8001_ha) - return; - - for (i = 0; i < USI_MAX_MEMCNT; i++) { - if (pm8001_ha->memoryMap.region[i].virt_ptr != NULL) { - pci_free_consistent(pm8001_ha->pdev, - pm8001_ha->memoryMap.region[i].element_size, - pm8001_ha->memoryMap.region[i].virt_ptr, - pm8001_ha->memoryMap.region[i].phys_addr); - } - } - PM8001_CHIP_DISP->chip_iounmap(pm8001_ha); - if (pm8001_ha->shost) - scsi_host_put(pm8001_ha->shost); - flush_workqueue(pm8001_wq); - kfree(pm8001_ha->tags); - kfree(pm8001_ha); -} - -#ifdef PM8001_USE_TASKLET -static void pm8001_tasklet(unsigned long opaque) -{ - struct pm8001_hba_info *pm8001_ha; - pm8001_ha = (struct pm8001_hba_info *)opaque; - if (unlikely(!pm8001_ha)) - BUG_ON(1); - PM8001_CHIP_DISP->isr(pm8001_ha); -} -#endif - - - /** - * pm8001_interrupt - when HBA originate a interrupt,we should invoke this - * dispatcher to handle each case. - * @irq: irq number. - * @opaque: the passed general host adapter struct - */ -static irqreturn_t pm8001_interrupt(int irq, void *opaque) -{ - struct pm8001_hba_info *pm8001_ha; - irqreturn_t ret = IRQ_HANDLED; - struct sas_ha_struct *sha = opaque; - pm8001_ha = sha->lldd_ha; - if (unlikely(!pm8001_ha)) - return IRQ_NONE; - if (!PM8001_CHIP_DISP->is_our_interupt(pm8001_ha)) - return IRQ_NONE; -#ifdef PM8001_USE_TASKLET - tasklet_schedule(&pm8001_ha->tasklet); -#else - ret = PM8001_CHIP_DISP->isr(pm8001_ha); -#endif - return ret; -} - -/** - * pm8001_alloc - initiate our hba structure and 6 DMAs area. - * @pm8001_ha:our hba structure. - * - */ -static int __devinit pm8001_alloc(struct pm8001_hba_info *pm8001_ha) -{ - int i; - spin_lock_init(&pm8001_ha->lock); - for (i = 0; i < pm8001_ha->chip->n_phy; i++) { - pm8001_phy_init(pm8001_ha, i); - pm8001_ha->port[i].wide_port_phymap = 0; - pm8001_ha->port[i].port_attached = 0; - pm8001_ha->port[i].port_state = 0; - INIT_LIST_HEAD(&pm8001_ha->port[i].list); - } - - pm8001_ha->tags = kzalloc(PM8001_MAX_CCB, GFP_KERNEL); - if (!pm8001_ha->tags) - goto err_out; - /* MPI Memory region 1 for AAP Event Log for fw */ - pm8001_ha->memoryMap.region[AAP1].num_elements = 1; - pm8001_ha->memoryMap.region[AAP1].element_size = PM8001_EVENT_LOG_SIZE; - pm8001_ha->memoryMap.region[AAP1].total_len = PM8001_EVENT_LOG_SIZE; - pm8001_ha->memoryMap.region[AAP1].alignment = 32; - - /* MPI Memory region 2 for IOP Event Log for fw */ - pm8001_ha->memoryMap.region[IOP].num_elements = 1; - pm8001_ha->memoryMap.region[IOP].element_size = PM8001_EVENT_LOG_SIZE; - pm8001_ha->memoryMap.region[IOP].total_len = PM8001_EVENT_LOG_SIZE; - pm8001_ha->memoryMap.region[IOP].alignment = 32; - - /* MPI Memory region 3 for consumer Index of inbound queues */ - pm8001_ha->memoryMap.region[CI].num_elements = 1; - pm8001_ha->memoryMap.region[CI].element_size = 4; - pm8001_ha->memoryMap.region[CI].total_len = 4; - pm8001_ha->memoryMap.region[CI].alignment = 4; - - /* MPI Memory region 4 for producer Index of outbound queues */ - pm8001_ha->memoryMap.region[PI].num_elements = 1; - pm8001_ha->memoryMap.region[PI].element_size = 4; - pm8001_ha->memoryMap.region[PI].total_len = 4; - pm8001_ha->memoryMap.region[PI].alignment = 4; - - /* MPI Memory region 5 inbound queues */ - pm8001_ha->memoryMap.region[IB].num_elements = 256; - pm8001_ha->memoryMap.region[IB].element_size = 64; - pm8001_ha->memoryMap.region[IB].total_len = 256 * 64; - pm8001_ha->memoryMap.region[IB].alignment = 64; - - /* MPI Memory region 6 inbound queues */ - pm8001_ha->memoryMap.region[OB].num_elements = 256; - pm8001_ha->memoryMap.region[OB].element_size = 64; - pm8001_ha->memoryMap.region[OB].total_len = 256 * 64; - pm8001_ha->memoryMap.region[OB].alignment = 64; - - /* Memory region write DMA*/ - pm8001_ha->memoryMap.region[NVMD].num_elements = 1; - pm8001_ha->memoryMap.region[NVMD].element_size = 4096; - pm8001_ha->memoryMap.region[NVMD].total_len = 4096; - /* Memory region for devices*/ - pm8001_ha->memoryMap.region[DEV_MEM].num_elements = 1; - pm8001_ha->memoryMap.region[DEV_MEM].element_size = PM8001_MAX_DEVICES * - sizeof(struct pm8001_device); - pm8001_ha->memoryMap.region[DEV_MEM].total_len = PM8001_MAX_DEVICES * - sizeof(struct pm8001_device); - - /* Memory region for ccb_info*/ - pm8001_ha->memoryMap.region[CCB_MEM].num_elements = 1; - pm8001_ha->memoryMap.region[CCB_MEM].element_size = PM8001_MAX_CCB * - sizeof(struct pm8001_ccb_info); - pm8001_ha->memoryMap.region[CCB_MEM].total_len = PM8001_MAX_CCB * - sizeof(struct pm8001_ccb_info); - - for (i = 0; i < USI_MAX_MEMCNT; i++) { - if (pm8001_mem_alloc(pm8001_ha->pdev, - &pm8001_ha->memoryMap.region[i].virt_ptr, - &pm8001_ha->memoryMap.region[i].phys_addr, - &pm8001_ha->memoryMap.region[i].phys_addr_hi, - &pm8001_ha->memoryMap.region[i].phys_addr_lo, - pm8001_ha->memoryMap.region[i].total_len, - pm8001_ha->memoryMap.region[i].alignment) != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Mem%d alloc failed\n", - i)); - goto err_out; - } - } - - pm8001_ha->devices = pm8001_ha->memoryMap.region[DEV_MEM].virt_ptr; - for (i = 0; i < PM8001_MAX_DEVICES; i++) { - pm8001_ha->devices[i].dev_type = NO_DEVICE; - pm8001_ha->devices[i].id = i; - pm8001_ha->devices[i].device_id = PM8001_MAX_DEVICES; - pm8001_ha->devices[i].running_req = 0; - } - pm8001_ha->ccb_info = pm8001_ha->memoryMap.region[CCB_MEM].virt_ptr; - for (i = 0; i < PM8001_MAX_CCB; i++) { - pm8001_ha->ccb_info[i].ccb_dma_handle = - pm8001_ha->memoryMap.region[CCB_MEM].phys_addr + - i * sizeof(struct pm8001_ccb_info); - pm8001_ha->ccb_info[i].task = NULL; - pm8001_ha->ccb_info[i].ccb_tag = 0xffffffff; - pm8001_ha->ccb_info[i].device = NULL; - ++pm8001_ha->tags_num; - } - pm8001_ha->flags = PM8001F_INIT_TIME; - /* Initialize tags */ - pm8001_tag_init(pm8001_ha); - return 0; -err_out: - return 1; -} - -/** - * pm8001_ioremap - remap the pci high physical address to kernal virtual - * address so that we can access them. - * @pm8001_ha:our hba structure. - */ -static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha) -{ - u32 bar; - u32 logicalBar = 0; - struct pci_dev *pdev; - - pdev = pm8001_ha->pdev; - /* map pci mem (PMC pci base 0-3)*/ - for (bar = 0; bar < 6; bar++) { - /* - ** logical BARs for SPC: - ** bar 0 and 1 - logical BAR0 - ** bar 2 and 3 - logical BAR1 - ** bar4 - logical BAR2 - ** bar5 - logical BAR3 - ** Skip the appropriate assignments: - */ - if ((bar == 1) || (bar == 3)) - continue; - if (pci_resource_flags(pdev, bar) & IORESOURCE_MEM) { - pm8001_ha->io_mem[logicalBar].membase = - pci_resource_start(pdev, bar); - pm8001_ha->io_mem[logicalBar].membase &= - (u32)PCI_BASE_ADDRESS_MEM_MASK; - pm8001_ha->io_mem[logicalBar].memsize = - pci_resource_len(pdev, bar); - pm8001_ha->io_mem[logicalBar].memvirtaddr = - ioremap(pm8001_ha->io_mem[logicalBar].membase, - pm8001_ha->io_mem[logicalBar].memsize); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("PCI: bar %d, logicalBar %d " - "virt_addr=%lx,len=%d\n", bar, logicalBar, - (unsigned long) - pm8001_ha->io_mem[logicalBar].memvirtaddr, - pm8001_ha->io_mem[logicalBar].memsize)); - } else { - pm8001_ha->io_mem[logicalBar].membase = 0; - pm8001_ha->io_mem[logicalBar].memsize = 0; - pm8001_ha->io_mem[logicalBar].memvirtaddr = 0; - } - logicalBar++; - } - return 0; -} - -/** - * pm8001_pci_alloc - initialize our ha card structure - * @pdev: pci device. - * @ent: ent - * @shost: scsi host struct which has been initialized before. - */ -static struct pm8001_hba_info *__devinit -pm8001_pci_alloc(struct pci_dev *pdev, u32 chip_id, struct Scsi_Host *shost) -{ - struct pm8001_hba_info *pm8001_ha; - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - - - pm8001_ha = sha->lldd_ha; - if (!pm8001_ha) - return NULL; - - pm8001_ha->pdev = pdev; - pm8001_ha->dev = &pdev->dev; - pm8001_ha->chip_id = chip_id; - pm8001_ha->chip = &pm8001_chips[pm8001_ha->chip_id]; - pm8001_ha->irq = pdev->irq; - pm8001_ha->sas = sha; - pm8001_ha->shost = shost; - pm8001_ha->id = pm8001_id++; - pm8001_ha->logging_level = 0x01; - sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id); -#ifdef PM8001_USE_TASKLET - tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet, - (unsigned long)pm8001_ha); -#endif - pm8001_ioremap(pm8001_ha); - if (!pm8001_alloc(pm8001_ha)) - return pm8001_ha; - pm8001_free(pm8001_ha); - return NULL; -} - -/** - * pci_go_44 - pm8001 specified, its DMA is 44 bit rather than 64 bit - * @pdev: pci device. - */ -static int pci_go_44(struct pci_dev *pdev) -{ - int rc; - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(44))) { - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(44)); - if (rc) { - rc = pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "44-bit DMA enable failed\n"); - return rc; - } - } - } else { - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit DMA enable failed\n"); - return rc; - } - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (rc) { - dev_printk(KERN_ERR, &pdev->dev, - "32-bit consistent DMA enable failed\n"); - return rc; - } - } - return rc; -} - -/** - * pm8001_prep_sas_ha_init - allocate memory in general hba struct && init them. - * @shost: scsi host which has been allocated outside. - * @chip_info: our ha struct. - */ -static int __devinit pm8001_prep_sas_ha_init(struct Scsi_Host * shost, - const struct pm8001_chip_info *chip_info) -{ - int phy_nr, port_nr; - struct asd_sas_phy **arr_phy; - struct asd_sas_port **arr_port; - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - - phy_nr = chip_info->n_phy; - port_nr = phy_nr; - memset(sha, 0x00, sizeof(*sha)); - arr_phy = kcalloc(phy_nr, sizeof(void *), GFP_KERNEL); - if (!arr_phy) - goto exit; - arr_port = kcalloc(port_nr, sizeof(void *), GFP_KERNEL); - if (!arr_port) - goto exit_free2; - - sha->sas_phy = arr_phy; - sha->sas_port = arr_port; - sha->lldd_ha = kzalloc(sizeof(struct pm8001_hba_info), GFP_KERNEL); - if (!sha->lldd_ha) - goto exit_free1; - - shost->transportt = pm8001_stt; - shost->max_id = PM8001_MAX_DEVICES; - shost->max_lun = 8; - shost->max_channel = 0; - shost->unique_id = pm8001_id; - shost->max_cmd_len = 16; - shost->can_queue = PM8001_CAN_QUEUE; - shost->cmd_per_lun = 32; - return 0; -exit_free1: - kfree(arr_port); -exit_free2: - kfree(arr_phy); -exit: - return -1; -} - -/** - * pm8001_post_sas_ha_init - initialize general hba struct defined in libsas - * @shost: scsi host which has been allocated outside - * @chip_info: our ha struct. - */ -static void __devinit pm8001_post_sas_ha_init(struct Scsi_Host *shost, - const struct pm8001_chip_info *chip_info) -{ - int i = 0; - struct pm8001_hba_info *pm8001_ha; - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - - pm8001_ha = sha->lldd_ha; - for (i = 0; i < chip_info->n_phy; i++) { - sha->sas_phy[i] = &pm8001_ha->phy[i].sas_phy; - sha->sas_port[i] = &pm8001_ha->port[i].sas_port; - } - sha->sas_ha_name = DRV_NAME; - sha->dev = pm8001_ha->dev; - - sha->lldd_module = THIS_MODULE; - sha->sas_addr = &pm8001_ha->sas_addr[0]; - sha->num_phys = chip_info->n_phy; - sha->lldd_max_execute_num = 1; - sha->lldd_queue_size = PM8001_CAN_QUEUE; - sha->core.shost = shost; -} - -/** - * pm8001_init_sas_add - initialize sas address - * @chip_info: our ha struct. - * - * Currently we just set the fixed SAS address to our HBA,for manufacture, - * it should read from the EEPROM - */ -static void pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) -{ - u8 i; -#ifdef PM8001_READ_VPD - DECLARE_COMPLETION_ONSTACK(completion); - struct pm8001_ioctl_payload payload; - pm8001_ha->nvmd_completion = &completion; - payload.minor_function = 0; - payload.length = 128; - payload.func_specific = kzalloc(128, GFP_KERNEL); - PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); - wait_for_completion(&completion); - for (i = 0; i < pm8001_ha->chip->n_phy; i++) { - memcpy(&pm8001_ha->phy[i].dev_sas_addr, pm8001_ha->sas_addr, - SAS_ADDR_SIZE); - PM8001_INIT_DBG(pm8001_ha, - pm8001_printk("phy %d sas_addr = %016llx \n", i, - pm8001_ha->phy[i].dev_sas_addr)); - } -#else - for (i = 0; i < pm8001_ha->chip->n_phy; i++) { - pm8001_ha->phy[i].dev_sas_addr = 0x50010c600047f9d0ULL; - pm8001_ha->phy[i].dev_sas_addr = - cpu_to_be64((u64) - (*(u64 *)&pm8001_ha->phy[i].dev_sas_addr)); - } - memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr, - SAS_ADDR_SIZE); -#endif -} - -#ifdef PM8001_USE_MSIX -/** - * pm8001_setup_msix - enable MSI-X interrupt - * @chip_info: our ha struct. - * @irq_handler: irq_handler - */ -static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha, - irq_handler_t irq_handler) -{ - u32 i = 0, j = 0; - u32 number_of_intr = 1; - int flag = 0; - u32 max_entry; - int rc; - max_entry = sizeof(pm8001_ha->msix_entries) / - sizeof(pm8001_ha->msix_entries[0]); - flag |= IRQF_DISABLED; - for (i = 0; i < max_entry ; i++) - pm8001_ha->msix_entries[i].entry = i; - rc = pci_enable_msix(pm8001_ha->pdev, pm8001_ha->msix_entries, - number_of_intr); - pm8001_ha->number_of_intr = number_of_intr; - if (!rc) { - for (i = 0; i < number_of_intr; i++) { - if (request_irq(pm8001_ha->msix_entries[i].vector, - irq_handler, flag, DRV_NAME, - SHOST_TO_SAS_HA(pm8001_ha->shost))) { - for (j = 0; j < i; j++) - free_irq( - pm8001_ha->msix_entries[j].vector, - SHOST_TO_SAS_HA(pm8001_ha->shost)); - pci_disable_msix(pm8001_ha->pdev); - break; - } - } - } - return rc; -} -#endif - -/** - * pm8001_request_irq - register interrupt - * @chip_info: our ha struct. - */ -static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) -{ - struct pci_dev *pdev; - irq_handler_t irq_handler = pm8001_interrupt; - int rc; - - pdev = pm8001_ha->pdev; - -#ifdef PM8001_USE_MSIX - if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) - return pm8001_setup_msix(pm8001_ha, irq_handler); - else - goto intx; -#endif - -intx: - /* initialize the INT-X interrupt */ - rc = request_irq(pdev->irq, irq_handler, IRQF_SHARED, DRV_NAME, - SHOST_TO_SAS_HA(pm8001_ha->shost)); - return rc; -} - -/** - * pm8001_pci_probe - probe supported device - * @pdev: pci device which kernel has been prepared for. - * @ent: pci device id - * - * This function is the main initialization function, when register a new - * pci driver it is invoked, all struct an hardware initilization should be done - * here, also, register interrupt - */ -static int __devinit pm8001_pci_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - unsigned int rc; - u32 pci_reg; - struct pm8001_hba_info *pm8001_ha; - struct Scsi_Host *shost = NULL; - const struct pm8001_chip_info *chip; - - dev_printk(KERN_INFO, &pdev->dev, - "pm8001: driver version %s\n", DRV_VERSION); - rc = pci_enable_device(pdev); - if (rc) - goto err_out_enable; - pci_set_master(pdev); - /* - * Enable pci slot busmaster by setting pci command register. - * This is required by FW for Cyclone card. - */ - - pci_read_config_dword(pdev, PCI_COMMAND, &pci_reg); - pci_reg |= 0x157; - pci_write_config_dword(pdev, PCI_COMMAND, pci_reg); - rc = pci_request_regions(pdev, DRV_NAME); - if (rc) - goto err_out_disable; - rc = pci_go_44(pdev); - if (rc) - goto err_out_regions; - - shost = scsi_host_alloc(&pm8001_sht, sizeof(void *)); - if (!shost) { - rc = -ENOMEM; - goto err_out_regions; - } - chip = &pm8001_chips[ent->driver_data]; - SHOST_TO_SAS_HA(shost) = - kzalloc(sizeof(struct sas_ha_struct), GFP_KERNEL); - if (!SHOST_TO_SAS_HA(shost)) { - rc = -ENOMEM; - goto err_out_free_host; - } - - rc = pm8001_prep_sas_ha_init(shost, chip); - if (rc) { - rc = -ENOMEM; - goto err_out_free; - } - pci_set_drvdata(pdev, SHOST_TO_SAS_HA(shost)); - pm8001_ha = pm8001_pci_alloc(pdev, chip_8001, shost); - if (!pm8001_ha) { - rc = -ENOMEM; - goto err_out_free; - } - list_add_tail(&pm8001_ha->list, &hba_list); - PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd); - rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); - if (rc) - goto err_out_ha_free; - - rc = scsi_add_host(shost, &pdev->dev); - if (rc) - goto err_out_ha_free; - rc = pm8001_request_irq(pm8001_ha); - if (rc) - goto err_out_shost; - - PM8001_CHIP_DISP->interrupt_enable(pm8001_ha); - pm8001_init_sas_add(pm8001_ha); - pm8001_post_sas_ha_init(shost, chip); - rc = sas_register_ha(SHOST_TO_SAS_HA(shost)); - if (rc) - goto err_out_shost; - scsi_scan_host(pm8001_ha->shost); - return 0; - -err_out_shost: - scsi_remove_host(pm8001_ha->shost); -err_out_ha_free: - pm8001_free(pm8001_ha); -err_out_free: - kfree(SHOST_TO_SAS_HA(shost)); -err_out_free_host: - kfree(shost); -err_out_regions: - pci_release_regions(pdev); -err_out_disable: - pci_disable_device(pdev); -err_out_enable: - return rc; -} - -static void __devexit pm8001_pci_remove(struct pci_dev *pdev) -{ - struct sas_ha_struct *sha = pci_get_drvdata(pdev); - struct pm8001_hba_info *pm8001_ha; - int i; - pm8001_ha = sha->lldd_ha; - pci_set_drvdata(pdev, NULL); - sas_unregister_ha(sha); - sas_remove_host(pm8001_ha->shost); - list_del(&pm8001_ha->list); - scsi_remove_host(pm8001_ha->shost); - PM8001_CHIP_DISP->interrupt_disable(pm8001_ha); - PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd); - -#ifdef PM8001_USE_MSIX - for (i = 0; i < pm8001_ha->number_of_intr; i++) - synchronize_irq(pm8001_ha->msix_entries[i].vector); - for (i = 0; i < pm8001_ha->number_of_intr; i++) - free_irq(pm8001_ha->msix_entries[i].vector, sha); - pci_disable_msix(pdev); -#else - free_irq(pm8001_ha->irq, sha); -#endif -#ifdef PM8001_USE_TASKLET - tasklet_kill(&pm8001_ha->tasklet); -#endif - pm8001_free(pm8001_ha); - kfree(sha->sas_phy); - kfree(sha->sas_port); - kfree(sha); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -/** - * pm8001_pci_suspend - power management suspend main entry point - * @pdev: PCI device struct - * @state: PM state change to (usually PCI_D3) - * - * Returns 0 success, anything else error. - */ -static int pm8001_pci_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct sas_ha_struct *sha = pci_get_drvdata(pdev); - struct pm8001_hba_info *pm8001_ha; - int i , pos; - u32 device_state; - pm8001_ha = sha->lldd_ha; - flush_workqueue(pm8001_wq); - scsi_block_requests(pm8001_ha->shost); - pos = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pos == 0) { - printk(KERN_ERR " PCI PM not supported\n"); - return -ENODEV; - } - PM8001_CHIP_DISP->interrupt_disable(pm8001_ha); - PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd); -#ifdef PM8001_USE_MSIX - for (i = 0; i < pm8001_ha->number_of_intr; i++) - synchronize_irq(pm8001_ha->msix_entries[i].vector); - for (i = 0; i < pm8001_ha->number_of_intr; i++) - free_irq(pm8001_ha->msix_entries[i].vector, sha); - pci_disable_msix(pdev); -#else - free_irq(pm8001_ha->irq, sha); -#endif -#ifdef PM8001_USE_TASKLET - tasklet_kill(&pm8001_ha->tasklet); -#endif - device_state = pci_choose_state(pdev, state); - pm8001_printk("pdev=0x%p, slot=%s, entering " - "operating state [D%d]\n", pdev, - pm8001_ha->name, device_state); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, device_state); - return 0; -} - -/** - * pm8001_pci_resume - power management resume main entry point - * @pdev: PCI device struct - * - * Returns 0 success, anything else error. - */ -static int pm8001_pci_resume(struct pci_dev *pdev) -{ - struct sas_ha_struct *sha = pci_get_drvdata(pdev); - struct pm8001_hba_info *pm8001_ha; - int rc; - u32 device_state; - pm8001_ha = sha->lldd_ha; - device_state = pdev->current_state; - - pm8001_printk("pdev=0x%p, slot=%s, resuming from previous " - "operating state [D%d]\n", pdev, pm8001_ha->name, device_state); - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - rc = pci_enable_device(pdev); - if (rc) { - pm8001_printk("slot=%s Enable device failed during resume\n", - pm8001_ha->name); - goto err_out_enable; - } - - pci_set_master(pdev); - rc = pci_go_44(pdev); - if (rc) - goto err_out_disable; - - PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha, 0x252acbcd); - rc = PM8001_CHIP_DISP->chip_init(pm8001_ha); - if (rc) - goto err_out_disable; - PM8001_CHIP_DISP->interrupt_disable(pm8001_ha); - rc = pm8001_request_irq(pm8001_ha); - if (rc) - goto err_out_disable; - #ifdef PM8001_USE_TASKLET - tasklet_init(&pm8001_ha->tasklet, pm8001_tasklet, - (unsigned long)pm8001_ha); - #endif - PM8001_CHIP_DISP->interrupt_enable(pm8001_ha); - scsi_unblock_requests(pm8001_ha->shost); - return 0; - -err_out_disable: - scsi_remove_host(pm8001_ha->shost); - pci_disable_device(pdev); -err_out_enable: - return rc; -} - -static struct pci_device_id __devinitdata pm8001_pci_table[] = { - { - PCI_VDEVICE(PMC_Sierra, 0x8001), chip_8001 - }, - { - PCI_DEVICE(0x117c, 0x0042), - .driver_data = chip_8001 - }, - {} /* terminate list */ -}; - -static struct pci_driver pm8001_pci_driver = { - .name = DRV_NAME, - .id_table = pm8001_pci_table, - .probe = pm8001_pci_probe, - .remove = __devexit_p(pm8001_pci_remove), - .suspend = pm8001_pci_suspend, - .resume = pm8001_pci_resume, -}; - -/** - * pm8001_init - initialize scsi transport template - */ -static int __init pm8001_init(void) -{ - int rc = -ENOMEM; - - pm8001_wq = alloc_workqueue("pm8001", 0, 0); - if (!pm8001_wq) - goto err; - - pm8001_id = 0; - pm8001_stt = sas_domain_attach_transport(&pm8001_transport_ops); - if (!pm8001_stt) - goto err_wq; - rc = pci_register_driver(&pm8001_pci_driver); - if (rc) - goto err_tp; - return 0; - -err_tp: - sas_release_transport(pm8001_stt); -err_wq: - destroy_workqueue(pm8001_wq); -err: - return rc; -} - -static void __exit pm8001_exit(void) -{ - pci_unregister_driver(&pm8001_pci_driver); - sas_release_transport(pm8001_stt); - destroy_workqueue(pm8001_wq); -} - -module_init(pm8001_init); -module_exit(pm8001_exit); - -MODULE_AUTHOR("Jack Wang "); -MODULE_DESCRIPTION("PMC-Sierra PM8001 SAS/SATA controller driver"); -MODULE_VERSION(DRV_VERSION); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(pci, pm8001_pci_table); - diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.c b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.c deleted file mode 100644 index 3b11edd4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ - -#include -#include "pm8001_sas.h" - -/** - * pm8001_find_tag - from sas task to find out tag that belongs to this task - * @task: the task sent to the LLDD - * @tag: the found tag associated with the task - */ -static int pm8001_find_tag(struct sas_task *task, u32 *tag) -{ - if (task->lldd_task) { - struct pm8001_ccb_info *ccb; - ccb = task->lldd_task; - *tag = ccb->ccb_tag; - return 1; - } - return 0; -} - -/** - * pm8001_tag_clear - clear the tags bitmap - * @pm8001_ha: our hba struct - * @tag: the found tag associated with the task - */ -static void pm8001_tag_clear(struct pm8001_hba_info *pm8001_ha, u32 tag) -{ - void *bitmap = pm8001_ha->tags; - clear_bit(tag, bitmap); -} - -static void pm8001_tag_free(struct pm8001_hba_info *pm8001_ha, u32 tag) -{ - pm8001_tag_clear(pm8001_ha, tag); -} - -static void pm8001_tag_set(struct pm8001_hba_info *pm8001_ha, u32 tag) -{ - void *bitmap = pm8001_ha->tags; - set_bit(tag, bitmap); -} - -/** - * pm8001_tag_alloc - allocate a empty tag for task used. - * @pm8001_ha: our hba struct - * @tag_out: the found empty tag . - */ -inline int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out) -{ - unsigned int index, tag; - void *bitmap = pm8001_ha->tags; - - index = find_first_zero_bit(bitmap, pm8001_ha->tags_num); - tag = index; - if (tag >= pm8001_ha->tags_num) - return -SAS_QUEUE_FULL; - pm8001_tag_set(pm8001_ha, tag); - *tag_out = tag; - return 0; -} - -void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha) -{ - int i; - for (i = 0; i < pm8001_ha->tags_num; ++i) - pm8001_tag_clear(pm8001_ha, i); -} - - /** - * pm8001_mem_alloc - allocate memory for pm8001. - * @pdev: pci device. - * @virt_addr: the allocated virtual address - * @pphys_addr_hi: the physical address high byte address. - * @pphys_addr_lo: the physical address low byte address. - * @mem_size: memory size. - */ -int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr, - dma_addr_t *pphys_addr, u32 *pphys_addr_hi, - u32 *pphys_addr_lo, u32 mem_size, u32 align) -{ - caddr_t mem_virt_alloc; - dma_addr_t mem_dma_handle; - u64 phys_align; - u64 align_offset = 0; - if (align) - align_offset = (dma_addr_t)align - 1; - mem_virt_alloc = - pci_alloc_consistent(pdev, mem_size + align, &mem_dma_handle); - if (!mem_virt_alloc) { - pm8001_printk("memory allocation error\n"); - return -1; - } - memset((void *)mem_virt_alloc, 0, mem_size+align); - *pphys_addr = mem_dma_handle; - phys_align = (*pphys_addr + align_offset) & ~align_offset; - *virt_addr = (void *)mem_virt_alloc + phys_align - *pphys_addr; - *pphys_addr_hi = upper_32_bits(phys_align); - *pphys_addr_lo = lower_32_bits(phys_align); - return 0; -} -/** - * pm8001_find_ha_by_dev - from domain device which come from sas layer to - * find out our hba struct. - * @dev: the domain device which from sas layer. - */ -static -struct pm8001_hba_info *pm8001_find_ha_by_dev(struct domain_device *dev) -{ - struct sas_ha_struct *sha = dev->port->ha; - struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - return pm8001_ha; -} - -/** - * pm8001_phy_control - this function should be registered to - * sas_domain_function_template to provide libsas used, note: this is just - * control the HBA phy rather than other expander phy if you want control - * other phy, you should use SMP command. - * @sas_phy: which phy in HBA phys. - * @func: the operation. - * @funcdata: always NULL. - */ -int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, - void *funcdata) -{ - int rc = 0, phy_id = sas_phy->id; - struct pm8001_hba_info *pm8001_ha = NULL; - struct sas_phy_linkrates *rates; - DECLARE_COMPLETION_ONSTACK(completion); - unsigned long flags; - pm8001_ha = sas_phy->ha->lldd_ha; - pm8001_ha->phy[phy_id].enable_completion = &completion; - switch (func) { - case PHY_FUNC_SET_LINK_RATE: - rates = funcdata; - if (rates->minimum_linkrate) { - pm8001_ha->phy[phy_id].minimum_linkrate = - rates->minimum_linkrate; - } - if (rates->maximum_linkrate) { - pm8001_ha->phy[phy_id].maximum_linkrate = - rates->maximum_linkrate; - } - if (pm8001_ha->phy[phy_id].phy_state == 0) { - PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id); - wait_for_completion(&completion); - } - PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, - PHY_LINK_RESET); - break; - case PHY_FUNC_HARD_RESET: - if (pm8001_ha->phy[phy_id].phy_state == 0) { - PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id); - wait_for_completion(&completion); - } - PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, - PHY_HARD_RESET); - break; - case PHY_FUNC_LINK_RESET: - if (pm8001_ha->phy[phy_id].phy_state == 0) { - PM8001_CHIP_DISP->phy_start_req(pm8001_ha, phy_id); - wait_for_completion(&completion); - } - PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, - PHY_LINK_RESET); - break; - case PHY_FUNC_RELEASE_SPINUP_HOLD: - PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, - PHY_LINK_RESET); - break; - case PHY_FUNC_DISABLE: - PM8001_CHIP_DISP->phy_stop_req(pm8001_ha, phy_id); - break; - case PHY_FUNC_GET_EVENTS: - spin_lock_irqsave(&pm8001_ha->lock, flags); - if (-1 == pm8001_bar4_shift(pm8001_ha, - (phy_id < 4) ? 0x30000 : 0x40000)) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return -EINVAL; - } - { - struct sas_phy *phy = sas_phy->phy; - uint32_t *qp = (uint32_t *)(((char *) - pm8001_ha->io_mem[2].memvirtaddr) - + 0x1034 + (0x4000 * (phy_id & 3))); - - phy->invalid_dword_count = qp[0]; - phy->running_disparity_error_count = qp[1]; - phy->loss_of_dword_sync_count = qp[3]; - phy->phy_reset_problem_count = qp[4]; - } - pm8001_bar4_shift(pm8001_ha, 0); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return 0; - default: - rc = -EOPNOTSUPP; - } - msleep(300); - return rc; -} - -/** - * pm8001_scan_start - we should enable all HBA phys by sending the phy_start - * command to HBA. - * @shost: the scsi host data. - */ -void pm8001_scan_start(struct Scsi_Host *shost) -{ - int i; - struct pm8001_hba_info *pm8001_ha; - struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - pm8001_ha = sha->lldd_ha; - PM8001_CHIP_DISP->sas_re_init_req(pm8001_ha); - for (i = 0; i < pm8001_ha->chip->n_phy; ++i) - PM8001_CHIP_DISP->phy_start_req(pm8001_ha, i); -} - -int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); - - /* give the phy enabling interrupt event time to come in (1s - * is empirically about all it takes) */ - if (time < HZ) - return 0; - /* Wait for discovery to finish */ - sas_drain_work(ha); - return 1; -} - -/** - * pm8001_task_prep_smp - the dispatcher function, prepare data for smp task - * @pm8001_ha: our hba card information - * @ccb: the ccb which attached to smp task - */ -static int pm8001_task_prep_smp(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb) -{ - return PM8001_CHIP_DISP->smp_req(pm8001_ha, ccb); -} - -u32 pm8001_get_ncq_tag(struct sas_task *task, u32 *tag) -{ - struct ata_queued_cmd *qc = task->uldd_task; - if (qc) { - if (qc->tf.command == ATA_CMD_FPDMA_WRITE || - qc->tf.command == ATA_CMD_FPDMA_READ) { - *tag = qc->tag; - return 1; - } - } - return 0; -} - -/** - * pm8001_task_prep_ata - the dispatcher function, prepare data for sata task - * @pm8001_ha: our hba card information - * @ccb: the ccb which attached to sata task - */ -static int pm8001_task_prep_ata(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb) -{ - return PM8001_CHIP_DISP->sata_req(pm8001_ha, ccb); -} - -/** - * pm8001_task_prep_ssp_tm - the dispatcher function, prepare task management data - * @pm8001_ha: our hba card information - * @ccb: the ccb which attached to TM - * @tmf: the task management IU - */ -static int pm8001_task_prep_ssp_tm(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf) -{ - return PM8001_CHIP_DISP->ssp_tm_req(pm8001_ha, ccb, tmf); -} - -/** - * pm8001_task_prep_ssp - the dispatcher function,prepare ssp data for ssp task - * @pm8001_ha: our hba card information - * @ccb: the ccb which attached to ssp task - */ -static int pm8001_task_prep_ssp(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb) -{ - return PM8001_CHIP_DISP->ssp_io_req(pm8001_ha, ccb); -} - - /* Find the local port id that's attached to this device */ -static int sas_find_local_port_id(struct domain_device *dev) -{ - struct domain_device *pdev = dev->parent; - - /* Directly attached device */ - if (!pdev) - return dev->port->id; - while (pdev) { - struct domain_device *pdev_p = pdev->parent; - if (!pdev_p) - return pdev->port->id; - pdev = pdev->parent; - } - return 0; -} - -/** - * pm8001_task_exec - queue the task(ssp, smp && ata) to the hardware. - * @task: the task to be execute. - * @num: if can_queue great than 1, the task can be queued up. for SMP task, - * we always execute one one time. - * @gfp_flags: gfp_flags. - * @is_tmf: if it is task management task. - * @tmf: the task management IU - */ -#define DEV_IS_GONE(pm8001_dev) \ - ((!pm8001_dev || (pm8001_dev->dev_type == NO_DEVICE))) -static int pm8001_task_exec(struct sas_task *task, const int num, - gfp_t gfp_flags, int is_tmf, struct pm8001_tmf_task *tmf) -{ - struct domain_device *dev = task->dev; - struct pm8001_hba_info *pm8001_ha; - struct pm8001_device *pm8001_dev; - struct pm8001_port *port = NULL; - struct sas_task *t = task; - struct pm8001_ccb_info *ccb; - u32 tag = 0xdeadbeef, rc, n_elem = 0; - u32 n = num; - unsigned long flags = 0; - - if (!dev->port) { - struct task_status_struct *tsm = &t->task_status; - tsm->resp = SAS_TASK_UNDELIVERED; - tsm->stat = SAS_PHY_DOWN; - if (dev->dev_type != SATA_DEV) - t->task_done(t); - return 0; - } - pm8001_ha = pm8001_find_ha_by_dev(task->dev); - PM8001_IO_DBG(pm8001_ha, pm8001_printk("pm8001_task_exec device \n ")); - spin_lock_irqsave(&pm8001_ha->lock, flags); - do { - dev = t->dev; - pm8001_dev = dev->lldd_dev; - port = &pm8001_ha->port[sas_find_local_port_id(dev)]; - if (DEV_IS_GONE(pm8001_dev) || !port->port_attached) { - if (sas_protocol_ata(t->task_proto)) { - struct task_status_struct *ts = &t->task_status; - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - t->task_done(t); - spin_lock_irqsave(&pm8001_ha->lock, flags); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); - continue; - } else { - struct task_status_struct *ts = &t->task_status; - ts->resp = SAS_TASK_UNDELIVERED; - ts->stat = SAS_PHY_DOWN; - t->task_done(t); - if (n > 1) - t = list_entry(t->list.next, - struct sas_task, list); - continue; - } - } - rc = pm8001_tag_alloc(pm8001_ha, &tag); - if (rc) - goto err_out; - ccb = &pm8001_ha->ccb_info[tag]; - - if (!sas_protocol_ata(t->task_proto)) { - if (t->num_scatter) { - n_elem = dma_map_sg(pm8001_ha->dev, - t->scatter, - t->num_scatter, - t->data_dir); - if (!n_elem) { - rc = -ENOMEM; - goto err_out_tag; - } - } - } else { - n_elem = t->num_scatter; - } - - t->lldd_task = ccb; - ccb->n_elem = n_elem; - ccb->ccb_tag = tag; - ccb->task = t; - switch (t->task_proto) { - case SAS_PROTOCOL_SMP: - rc = pm8001_task_prep_smp(pm8001_ha, ccb); - break; - case SAS_PROTOCOL_SSP: - if (is_tmf) - rc = pm8001_task_prep_ssp_tm(pm8001_ha, - ccb, tmf); - else - rc = pm8001_task_prep_ssp(pm8001_ha, ccb); - break; - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP: - rc = pm8001_task_prep_ata(pm8001_ha, ccb); - break; - default: - dev_printk(KERN_ERR, pm8001_ha->dev, - "unknown sas_task proto: 0x%x\n", - t->task_proto); - rc = -EINVAL; - break; - } - - if (rc) { - PM8001_IO_DBG(pm8001_ha, - pm8001_printk("rc is %x\n", rc)); - goto err_out_tag; - } - /* TODO: select normal or high priority */ - spin_lock(&t->task_state_lock); - t->task_state_flags |= SAS_TASK_AT_INITIATOR; - spin_unlock(&t->task_state_lock); - pm8001_dev->running_req++; - if (n > 1) - t = list_entry(t->list.next, struct sas_task, list); - } while (--n); - rc = 0; - goto out_done; - -err_out_tag: - pm8001_tag_free(pm8001_ha, tag); -err_out: - dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc); - if (!sas_protocol_ata(t->task_proto)) - if (n_elem) - dma_unmap_sg(pm8001_ha->dev, t->scatter, n_elem, - t->data_dir); -out_done: - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return rc; -} - -/** - * pm8001_queue_command - register for upper layer used, all IO commands sent - * to HBA are from this interface. - * @task: the task to be execute. - * @num: if can_queue great than 1, the task can be queued up. for SMP task, - * we always execute one one time - * @gfp_flags: gfp_flags - */ -int pm8001_queue_command(struct sas_task *task, const int num, - gfp_t gfp_flags) -{ - return pm8001_task_exec(task, num, gfp_flags, 0, NULL); -} - -void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx) -{ - pm8001_tag_clear(pm8001_ha, ccb_idx); -} - -/** - * pm8001_ccb_task_free - free the sg for ssp and smp command, free the ccb. - * @pm8001_ha: our hba card information - * @ccb: the ccb which attached to ssp task - * @task: the task to be free. - * @ccb_idx: ccb index. - */ -void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha, - struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx) -{ - if (!ccb->task) - return; - if (!sas_protocol_ata(task->task_proto)) - if (ccb->n_elem) - dma_unmap_sg(pm8001_ha->dev, task->scatter, - task->num_scatter, task->data_dir); - - switch (task->task_proto) { - case SAS_PROTOCOL_SMP: - dma_unmap_sg(pm8001_ha->dev, &task->smp_task.smp_resp, 1, - PCI_DMA_FROMDEVICE); - dma_unmap_sg(pm8001_ha->dev, &task->smp_task.smp_req, 1, - PCI_DMA_TODEVICE); - break; - - case SAS_PROTOCOL_SATA: - case SAS_PROTOCOL_STP: - case SAS_PROTOCOL_SSP: - default: - /* do nothing */ - break; - } - task->lldd_task = NULL; - ccb->task = NULL; - ccb->ccb_tag = 0xFFFFFFFF; - ccb->open_retry = 0; - pm8001_ccb_free(pm8001_ha, ccb_idx); -} - - /** - * pm8001_alloc_dev - find a empty pm8001_device - * @pm8001_ha: our hba card information - */ -struct pm8001_device *pm8001_alloc_dev(struct pm8001_hba_info *pm8001_ha) -{ - u32 dev; - for (dev = 0; dev < PM8001_MAX_DEVICES; dev++) { - if (pm8001_ha->devices[dev].dev_type == NO_DEVICE) { - pm8001_ha->devices[dev].id = dev; - return &pm8001_ha->devices[dev]; - } - } - if (dev == PM8001_MAX_DEVICES) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("max support %d devices, ignore ..\n", - PM8001_MAX_DEVICES)); - } - return NULL; -} - -static void pm8001_free_dev(struct pm8001_device *pm8001_dev) -{ - u32 id = pm8001_dev->id; - memset(pm8001_dev, 0, sizeof(*pm8001_dev)); - pm8001_dev->id = id; - pm8001_dev->dev_type = NO_DEVICE; - pm8001_dev->device_id = PM8001_MAX_DEVICES; - pm8001_dev->sas_device = NULL; -} - -/** - * pm8001_dev_found_notify - libsas notify a device is found. - * @dev: the device structure which sas layer used. - * - * when libsas find a sas domain device, it should tell the LLDD that - * device is found, and then LLDD register this device to HBA firmware - * by the command "OPC_INB_REG_DEV", after that the HBA will assign a - * device ID(according to device's sas address) and returned it to LLDD. From - * now on, we communicate with HBA FW with the device ID which HBA assigned - * rather than sas address. it is the necessary step for our HBA but it is - * the optional for other HBA driver. - */ -static int pm8001_dev_found_notify(struct domain_device *dev) -{ - unsigned long flags = 0; - int res = 0; - struct pm8001_hba_info *pm8001_ha = NULL; - struct domain_device *parent_dev = dev->parent; - struct pm8001_device *pm8001_device; - DECLARE_COMPLETION_ONSTACK(completion); - u32 flag = 0; - pm8001_ha = pm8001_find_ha_by_dev(dev); - spin_lock_irqsave(&pm8001_ha->lock, flags); - - pm8001_device = pm8001_alloc_dev(pm8001_ha); - if (!pm8001_device) { - res = -1; - goto found_out; - } - pm8001_device->sas_device = dev; - dev->lldd_dev = pm8001_device; - pm8001_device->dev_type = dev->dev_type; - pm8001_device->dcompletion = &completion; - if (parent_dev && DEV_IS_EXPANDER(parent_dev->dev_type)) { - int phy_id; - struct ex_phy *phy; - for (phy_id = 0; phy_id < parent_dev->ex_dev.num_phys; - phy_id++) { - phy = &parent_dev->ex_dev.ex_phy[phy_id]; - if (SAS_ADDR(phy->attached_sas_addr) - == SAS_ADDR(dev->sas_addr)) { - pm8001_device->attached_phy = phy_id; - break; - } - } - if (phy_id == parent_dev->ex_dev.num_phys) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Error: no attached dev:%016llx" - " at ex:%016llx.\n", SAS_ADDR(dev->sas_addr), - SAS_ADDR(parent_dev->sas_addr))); - res = -1; - } - } else { - if (dev->dev_type == SATA_DEV) { - pm8001_device->attached_phy = - dev->rphy->identify.phy_identifier; - flag = 1; /* directly sata*/ - } - } /*register this device to HBA*/ - PM8001_DISC_DBG(pm8001_ha, pm8001_printk("Found device\n")); - PM8001_CHIP_DISP->reg_dev_req(pm8001_ha, pm8001_device, flag); - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - wait_for_completion(&completion); - if (dev->dev_type == SAS_END_DEV) - msleep(50); - pm8001_ha->flags = PM8001F_RUN_TIME; - return 0; -found_out: - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - return res; -} - -int pm8001_dev_found(struct domain_device *dev) -{ - return pm8001_dev_found_notify(dev); -} - -static void pm8001_task_done(struct sas_task *task) -{ - if (!del_timer(&task->timer)) - return; - complete(&task->completion); -} - -static void pm8001_tmf_timedout(unsigned long data) -{ - struct sas_task *task = (struct sas_task *)data; - - task->task_state_flags |= SAS_TASK_STATE_ABORTED; - complete(&task->completion); -} - -#define PM8001_TASK_TIMEOUT 20 -/** - * pm8001_exec_internal_tmf_task - execute some task management commands. - * @dev: the wanted device. - * @tmf: which task management wanted to be take. - * @para_len: para_len. - * @parameter: ssp task parameter. - * - * when errors or exception happened, we may want to do something, for example - * abort the issued task which result in this execption, it is done by calling - * this function, note it is also with the task execute interface. - */ -static int pm8001_exec_internal_tmf_task(struct domain_device *dev, - void *parameter, u32 para_len, struct pm8001_tmf_task *tmf) -{ - int res, retry; - struct sas_task *task = NULL; - struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); - - for (retry = 0; retry < 3; retry++) { - task = sas_alloc_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = dev; - task->task_proto = dev->tproto; - memcpy(&task->ssp_task, parameter, para_len); - task->task_done = pm8001_task_done; - task->timer.data = (unsigned long)task; - task->timer.function = pm8001_tmf_timedout; - task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ; - add_timer(&task->timer); - - res = pm8001_task_exec(task, 1, GFP_KERNEL, 1, tmf); - - if (res) { - del_timer(&task->timer); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Executing internal task " - "failed\n")); - goto ex_err; - } - wait_for_completion(&task->completion); - res = -TMF_RESP_FUNC_FAILED; - /* Even TMF timed out, return direct. */ - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TMF task[%x]timeout.\n", - tmf->tmf)); - goto ex_err; - } - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_STAT_GOOD) { - res = TMF_RESP_FUNC_COMPLETE; - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_UNDERRUN) { - /* no error, but return the number of bytes of - * underrun */ - res = task->task_status.residual; - break; - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAS_DATA_OVERRUN) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Blocked task error.\n")); - res = -EMSGSIZE; - break; - } else { - PM8001_EH_DBG(pm8001_ha, - pm8001_printk(" Task to dev %016llx response:" - "0x%x status 0x%x\n", - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat)); - sas_free_task(task); - task = NULL; - } - } -ex_err: - BUG_ON(retry == 3 && task != NULL); - sas_free_task(task); - return res; -} - -static int -pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, struct domain_device *dev, u32 flag, - u32 task_tag) -{ - int res, retry; - u32 ccb_tag; - struct pm8001_ccb_info *ccb; - struct sas_task *task = NULL; - - for (retry = 0; retry < 3; retry++) { - task = sas_alloc_task(GFP_KERNEL); - if (!task) - return -ENOMEM; - - task->dev = dev; - task->task_proto = dev->tproto; - task->task_done = pm8001_task_done; - task->timer.data = (unsigned long)task; - task->timer.function = pm8001_tmf_timedout; - task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ; - add_timer(&task->timer); - - res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); - if (res) - return res; - ccb = &pm8001_ha->ccb_info[ccb_tag]; - ccb->device = pm8001_dev; - ccb->ccb_tag = ccb_tag; - ccb->task = task; - - res = PM8001_CHIP_DISP->task_abort(pm8001_ha, - pm8001_dev, flag, task_tag, ccb_tag); - - if (res) { - del_timer(&task->timer); - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("Executing internal task " - "failed\n")); - goto ex_err; - } - wait_for_completion(&task->completion); - res = TMF_RESP_FUNC_FAILED; - /* Even TMF timed out, return direct. */ - if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TMF task timeout.\n")); - goto ex_err; - } - } - - if (task->task_status.resp == SAS_TASK_COMPLETE && - task->task_status.stat == SAM_STAT_GOOD) { - res = TMF_RESP_FUNC_COMPLETE; - break; - - } else { - PM8001_EH_DBG(pm8001_ha, - pm8001_printk(" Task to dev %016llx response: " - "0x%x status 0x%x\n", - SAS_ADDR(dev->sas_addr), - task->task_status.resp, - task->task_status.stat)); - sas_free_task(task); - task = NULL; - } - } -ex_err: - BUG_ON(retry == 3 && task != NULL); - sas_free_task(task); - return res; -} - -/** - * pm8001_dev_gone_notify - see the comments for "pm8001_dev_found_notify" - * @dev: the device structure which sas layer used. - */ -static void pm8001_dev_gone_notify(struct domain_device *dev) -{ - unsigned long flags = 0; - u32 tag; - struct pm8001_hba_info *pm8001_ha; - struct pm8001_device *pm8001_dev = dev->lldd_dev; - - pm8001_ha = pm8001_find_ha_by_dev(dev); - spin_lock_irqsave(&pm8001_ha->lock, flags); - pm8001_tag_alloc(pm8001_ha, &tag); - if (pm8001_dev) { - u32 device_id = pm8001_dev->device_id; - - PM8001_DISC_DBG(pm8001_ha, - pm8001_printk("found dev[%d:%x] is gone.\n", - pm8001_dev->device_id, pm8001_dev->dev_type)); - if (pm8001_dev->running_req) { - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , - dev, 1, 0); - spin_lock_irqsave(&pm8001_ha->lock, flags); - } - PM8001_CHIP_DISP->dereg_dev_req(pm8001_ha, device_id); - pm8001_free_dev(pm8001_dev); - } else { - PM8001_DISC_DBG(pm8001_ha, - pm8001_printk("Found dev has gone.\n")); - } - dev->lldd_dev = NULL; - spin_unlock_irqrestore(&pm8001_ha->lock, flags); -} - -void pm8001_dev_gone(struct domain_device *dev) -{ - pm8001_dev_gone_notify(dev); -} - -static int pm8001_issue_ssp_tmf(struct domain_device *dev, - u8 *lun, struct pm8001_tmf_task *tmf) -{ - struct sas_ssp_task ssp_task; - if (!(dev->tproto & SAS_PROTOCOL_SSP)) - return TMF_RESP_FUNC_ESUPP; - - strncpy((u8 *)&ssp_task.LUN, lun, 8); - return pm8001_exec_internal_tmf_task(dev, &ssp_task, sizeof(ssp_task), - tmf); -} - -/* retry commands by ha, by task and/or by device */ -void pm8001_open_reject_retry( - struct pm8001_hba_info *pm8001_ha, - struct sas_task *task_to_close, - struct pm8001_device *device_to_close) -{ - int i; - unsigned long flags; - - if (pm8001_ha == NULL) - return; - - spin_lock_irqsave(&pm8001_ha->lock, flags); - - for (i = 0; i < PM8001_MAX_CCB; i++) { - struct sas_task *task; - struct task_status_struct *ts; - struct pm8001_device *pm8001_dev; - unsigned long flags1; - u32 tag; - struct pm8001_ccb_info *ccb = &pm8001_ha->ccb_info[i]; - - pm8001_dev = ccb->device; - if (!pm8001_dev || (pm8001_dev->dev_type == NO_DEVICE)) - continue; - if (!device_to_close) { - uintptr_t d = (uintptr_t)pm8001_dev - - (uintptr_t)&pm8001_ha->devices; - if (((d % sizeof(*pm8001_dev)) != 0) - || ((d / sizeof(*pm8001_dev)) >= PM8001_MAX_DEVICES)) - continue; - } else if (pm8001_dev != device_to_close) - continue; - tag = ccb->ccb_tag; - if (!tag || (tag == 0xFFFFFFFF)) - continue; - task = ccb->task; - if (!task || !task->task_done) - continue; - if (task_to_close && (task != task_to_close)) - continue; - ts = &task->task_status; - ts->resp = SAS_TASK_COMPLETE; - /* Force the midlayer to retry */ - ts->stat = SAS_OPEN_REJECT; - ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; - if (pm8001_dev) - pm8001_dev->running_req--; - spin_lock_irqsave(&task->task_state_lock, flags1); - task->task_state_flags &= ~SAS_TASK_STATE_PENDING; - task->task_state_flags &= ~SAS_TASK_AT_INITIATOR; - task->task_state_flags |= SAS_TASK_STATE_DONE; - if (unlikely((task->task_state_flags - & SAS_TASK_STATE_ABORTED))) { - spin_unlock_irqrestore(&task->task_state_lock, - flags1); - pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); - } else { - spin_unlock_irqrestore(&task->task_state_lock, - flags1); - pm8001_ccb_task_free(pm8001_ha, task, ccb, tag); - mb();/* in order to force CPU ordering */ - spin_unlock_irqrestore(&pm8001_ha->lock, flags); - task->task_done(task); - spin_lock_irqsave(&pm8001_ha->lock, flags); - } - } - - spin_unlock_irqrestore(&pm8001_ha->lock, flags); -} - -/** - * Standard mandates link reset for ATA (type 0) and hard reset for - * SSP (type 1) , only for RECOVERY - */ -int pm8001_I_T_nexus_reset(struct domain_device *dev) -{ - int rc = TMF_RESP_FUNC_FAILED; - struct pm8001_device *pm8001_dev; - struct pm8001_hba_info *pm8001_ha; - struct sas_phy *phy; - if (!dev || !dev->lldd_dev) - return -1; - - pm8001_dev = dev->lldd_dev; - pm8001_ha = pm8001_find_ha_by_dev(dev); - phy = sas_get_local_phy(dev); - - if (dev_is_sata(dev)) { - DECLARE_COMPLETION_ONSTACK(completion_setstate); - if (scsi_is_sas_phy_local(phy)) { - rc = 0; - goto out; - } - rc = sas_phy_reset(phy, 1); - msleep(2000); - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , - dev, 1, 0); - pm8001_dev->setds_completion = &completion_setstate; - rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, - pm8001_dev, 0x01); - wait_for_completion(&completion_setstate); - } else { - rc = sas_phy_reset(phy, 1); - msleep(2000); - } - PM8001_EH_DBG(pm8001_ha, pm8001_printk(" for device[%x]:rc=%d\n", - pm8001_dev->device_id, rc)); - out: - sas_put_local_phy(phy); - return rc; -} - -/* mandatory SAM-3, the task reset the specified LUN*/ -int pm8001_lu_reset(struct domain_device *dev, u8 *lun) -{ - int rc = TMF_RESP_FUNC_FAILED; - struct pm8001_tmf_task tmf_task; - struct pm8001_device *pm8001_dev = dev->lldd_dev; - struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); - if (dev_is_sata(dev)) { - struct sas_phy *phy = sas_get_local_phy(dev); - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , - dev, 1, 0); - rc = sas_phy_reset(phy, 1); - sas_put_local_phy(phy); - rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, - pm8001_dev, 0x01); - msleep(2000); - } else { - tmf_task.tmf = TMF_LU_RESET; - rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); - } - /* If failed, fall-through I_T_Nexus reset */ - PM8001_EH_DBG(pm8001_ha, pm8001_printk("for device[%x]:rc=%d\n", - pm8001_dev->device_id, rc)); - return rc; -} - -/* optional SAM-3 */ -int pm8001_query_task(struct sas_task *task) -{ - u32 tag = 0xdeadbeef; - int i = 0; - struct scsi_lun lun; - struct pm8001_tmf_task tmf_task; - int rc = TMF_RESP_FUNC_FAILED; - if (unlikely(!task || !task->lldd_task || !task->dev)) - return rc; - - if (task->task_proto & SAS_PROTOCOL_SSP) { - struct scsi_cmnd *cmnd = task->uldd_task; - struct domain_device *dev = task->dev; - struct pm8001_hba_info *pm8001_ha = - pm8001_find_ha_by_dev(dev); - - int_to_scsilun(cmnd->device->lun, &lun); - rc = pm8001_find_tag(task, &tag); - if (rc == 0) { - rc = TMF_RESP_FUNC_FAILED; - return rc; - } - PM8001_EH_DBG(pm8001_ha, pm8001_printk("Query:[")); - for (i = 0; i < 16; i++) - printk(KERN_INFO "%02x ", cmnd->cmnd[i]); - printk(KERN_INFO "]\n"); - tmf_task.tmf = TMF_QUERY_TASK; - tmf_task.tag_of_task_to_be_managed = tag; - - rc = pm8001_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task); - switch (rc) { - /* The task is still in Lun, release it then */ - case TMF_RESP_FUNC_SUCC: - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("The task is still in Lun\n")); - break; - /* The task is not in Lun or failed, reset the phy */ - case TMF_RESP_FUNC_FAILED: - case TMF_RESP_FUNC_COMPLETE: - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("The task is not in Lun or failed," - " reset the phy\n")); - break; - } - } - pm8001_printk(":rc= %d\n", rc); - return rc; -} - -/* mandatory SAM-3, still need free task/ccb info, abord the specified task */ -int pm8001_abort_task(struct sas_task *task) -{ - unsigned long flags; - u32 tag = 0xdeadbeef; - u32 device_id; - struct domain_device *dev ; - struct pm8001_hba_info *pm8001_ha = NULL; - struct pm8001_ccb_info *ccb; - struct scsi_lun lun; - struct pm8001_device *pm8001_dev; - struct pm8001_tmf_task tmf_task; - int rc = TMF_RESP_FUNC_FAILED; - if (unlikely(!task || !task->lldd_task || !task->dev)) - return rc; - spin_lock_irqsave(&task->task_state_lock, flags); - if (task->task_state_flags & SAS_TASK_STATE_DONE) { - spin_unlock_irqrestore(&task->task_state_lock, flags); - rc = TMF_RESP_FUNC_COMPLETE; - goto out; - } - spin_unlock_irqrestore(&task->task_state_lock, flags); - if (task->task_proto & SAS_PROTOCOL_SSP) { - struct scsi_cmnd *cmnd = task->uldd_task; - dev = task->dev; - ccb = task->lldd_task; - pm8001_dev = dev->lldd_dev; - pm8001_ha = pm8001_find_ha_by_dev(dev); - int_to_scsilun(cmnd->device->lun, &lun); - rc = pm8001_find_tag(task, &tag); - if (rc == 0) { - printk(KERN_INFO "No such tag in %s\n", __func__); - rc = TMF_RESP_FUNC_FAILED; - return rc; - } - device_id = pm8001_dev->device_id; - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("abort io to deviceid= %d\n", device_id)); - tmf_task.tmf = TMF_ABORT_TASK; - tmf_task.tag_of_task_to_be_managed = tag; - rc = pm8001_issue_ssp_tmf(dev, lun.scsi_lun, &tmf_task); - pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - pm8001_dev->sas_device, 0, tag); - } else if (task->task_proto & SAS_PROTOCOL_SATA || - task->task_proto & SAS_PROTOCOL_STP) { - dev = task->dev; - pm8001_dev = dev->lldd_dev; - pm8001_ha = pm8001_find_ha_by_dev(dev); - rc = pm8001_find_tag(task, &tag); - if (rc == 0) { - printk(KERN_INFO "No such tag in %s\n", __func__); - rc = TMF_RESP_FUNC_FAILED; - return rc; - } - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - pm8001_dev->sas_device, 0, tag); - } else if (task->task_proto & SAS_PROTOCOL_SMP) { - /* SMP */ - dev = task->dev; - pm8001_dev = dev->lldd_dev; - pm8001_ha = pm8001_find_ha_by_dev(dev); - rc = pm8001_find_tag(task, &tag); - if (rc == 0) { - printk(KERN_INFO "No such tag in %s\n", __func__); - rc = TMF_RESP_FUNC_FAILED; - return rc; - } - rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev, - pm8001_dev->sas_device, 0, tag); - - } -out: - if (rc != TMF_RESP_FUNC_COMPLETE) - pm8001_printk("rc= %d\n", rc); - return rc; -} - -int pm8001_abort_task_set(struct domain_device *dev, u8 *lun) -{ - int rc = TMF_RESP_FUNC_FAILED; - struct pm8001_tmf_task tmf_task; - - tmf_task.tmf = TMF_ABORT_TASK_SET; - rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); - return rc; -} - -int pm8001_clear_aca(struct domain_device *dev, u8 *lun) -{ - int rc = TMF_RESP_FUNC_FAILED; - struct pm8001_tmf_task tmf_task; - - tmf_task.tmf = TMF_CLEAR_ACA; - rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); - - return rc; -} - -int pm8001_clear_task_set(struct domain_device *dev, u8 *lun) -{ - int rc = TMF_RESP_FUNC_FAILED; - struct pm8001_tmf_task tmf_task; - struct pm8001_device *pm8001_dev = dev->lldd_dev; - struct pm8001_hba_info *pm8001_ha = pm8001_find_ha_by_dev(dev); - - PM8001_EH_DBG(pm8001_ha, - pm8001_printk("I_T_L_Q clear task set[%x]\n", - pm8001_dev->device_id)); - tmf_task.tmf = TMF_CLEAR_TASK_SET; - rc = pm8001_issue_ssp_tmf(dev, lun, &tmf_task); - return rc; -} - diff --git a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.h b/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.h deleted file mode 100644 index 11008205..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pm8001/pm8001_sas.h +++ /dev/null @@ -1,502 +0,0 @@ -/* - * PMC-Sierra SPC 8001 SAS/SATA based host adapters driver - * - * Copyright (c) 2008-2009 USI Co., Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - * - */ - -#ifndef _PM8001_SAS_H_ -#define _PM8001_SAS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "pm8001_defs.h" - -#define DRV_NAME "pm8001" -#define DRV_VERSION "0.1.36" -#define PM8001_FAIL_LOGGING 0x01 /* Error message logging */ -#define PM8001_INIT_LOGGING 0x02 /* driver init logging */ -#define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */ -#define PM8001_IO_LOGGING 0x08 /* I/O path logging */ -#define PM8001_EH_LOGGING 0x10 /* libsas EH function logging*/ -#define PM8001_IOCTL_LOGGING 0x20 /* IOCTL message logging */ -#define PM8001_MSG_LOGGING 0x40 /* misc message logging */ -#define pm8001_printk(format, arg...) printk(KERN_INFO "%s %d:" format,\ - __func__, __LINE__, ## arg) -#define PM8001_CHECK_LOGGING(HBA, LEVEL, CMD) \ -do { \ - if (unlikely(HBA->logging_level & LEVEL)) \ - do { \ - CMD; \ - } while (0); \ -} while (0); - -#define PM8001_EH_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_EH_LOGGING, CMD) - -#define PM8001_INIT_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_INIT_LOGGING, CMD) - -#define PM8001_DISC_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_DISC_LOGGING, CMD) - -#define PM8001_IO_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_IO_LOGGING, CMD) - -#define PM8001_FAIL_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_FAIL_LOGGING, CMD) - -#define PM8001_IOCTL_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_IOCTL_LOGGING, CMD) - -#define PM8001_MSG_DBG(HBA, CMD) \ - PM8001_CHECK_LOGGING(HBA, PM8001_MSG_LOGGING, CMD) - - -#define PM8001_USE_TASKLET -#define PM8001_USE_MSIX -#define PM8001_READ_VPD - - -#define DEV_IS_EXPANDER(type) ((type == EDGE_DEV) || (type == FANOUT_DEV)) - -#define PM8001_NAME_LENGTH 32/* generic length of strings */ -extern struct list_head hba_list; -extern const struct pm8001_dispatch pm8001_8001_dispatch; - -struct pm8001_hba_info; -struct pm8001_ccb_info; -struct pm8001_device; -/* define task management IU */ -struct pm8001_tmf_task { - u8 tmf; - u32 tag_of_task_to_be_managed; -}; -struct pm8001_ioctl_payload { - u32 signature; - u16 major_function; - u16 minor_function; - u16 length; - u16 status; - u16 offset; - u16 id; - u8 *func_specific; -}; - -struct pm8001_dispatch { - char *name; - int (*chip_init)(struct pm8001_hba_info *pm8001_ha); - int (*chip_soft_rst)(struct pm8001_hba_info *pm8001_ha, u32 signature); - void (*chip_rst)(struct pm8001_hba_info *pm8001_ha); - int (*chip_ioremap)(struct pm8001_hba_info *pm8001_ha); - void (*chip_iounmap)(struct pm8001_hba_info *pm8001_ha); - irqreturn_t (*isr)(struct pm8001_hba_info *pm8001_ha); - u32 (*is_our_interupt)(struct pm8001_hba_info *pm8001_ha); - int (*isr_process_oq)(struct pm8001_hba_info *pm8001_ha); - void (*interrupt_enable)(struct pm8001_hba_info *pm8001_ha); - void (*interrupt_disable)(struct pm8001_hba_info *pm8001_ha); - void (*make_prd)(struct scatterlist *scatter, int nr, void *prd); - int (*smp_req)(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb); - int (*ssp_io_req)(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb); - int (*sata_req)(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb); - int (*phy_start_req)(struct pm8001_hba_info *pm8001_ha, u8 phy_id); - int (*phy_stop_req)(struct pm8001_hba_info *pm8001_ha, u8 phy_id); - int (*reg_dev_req)(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, u32 flag); - int (*dereg_dev_req)(struct pm8001_hba_info *pm8001_ha, u32 device_id); - int (*phy_ctl_req)(struct pm8001_hba_info *pm8001_ha, - u32 phy_id, u32 phy_op); - int (*task_abort)(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, u8 flag, u32 task_tag, - u32 cmd_tag); - int (*ssp_tm_req)(struct pm8001_hba_info *pm8001_ha, - struct pm8001_ccb_info *ccb, struct pm8001_tmf_task *tmf); - int (*get_nvmd_req)(struct pm8001_hba_info *pm8001_ha, void *payload); - int (*set_nvmd_req)(struct pm8001_hba_info *pm8001_ha, void *payload); - int (*fw_flash_update_req)(struct pm8001_hba_info *pm8001_ha, - void *payload); - int (*set_dev_state_req)(struct pm8001_hba_info *pm8001_ha, - struct pm8001_device *pm8001_dev, u32 state); - int (*sas_diag_start_end_req)(struct pm8001_hba_info *pm8001_ha, - u32 state); - int (*sas_diag_execute_req)(struct pm8001_hba_info *pm8001_ha, - u32 state); - int (*sas_re_init_req)(struct pm8001_hba_info *pm8001_ha); -}; - -struct pm8001_chip_info { - u32 n_phy; - const struct pm8001_dispatch *dispatch; -}; -#define PM8001_CHIP_DISP (pm8001_ha->chip->dispatch) - -struct pm8001_port { - struct asd_sas_port sas_port; - u8 port_attached; - u8 wide_port_phymap; - u8 port_state; - struct list_head list; -}; - -struct pm8001_phy { - struct pm8001_hba_info *pm8001_ha; - struct pm8001_port *port; - struct asd_sas_phy sas_phy; - struct sas_identify identify; - struct scsi_device *sdev; - u64 dev_sas_addr; - u32 phy_type; - struct completion *enable_completion; - u32 frame_rcvd_size; - u8 frame_rcvd[32]; - u8 phy_attached; - u8 phy_state; - enum sas_linkrate minimum_linkrate; - enum sas_linkrate maximum_linkrate; -}; - -struct pm8001_device { - enum sas_dev_type dev_type; - struct domain_device *sas_device; - u32 attached_phy; - u32 id; - struct completion *dcompletion; - struct completion *setds_completion; - u32 device_id; - u32 running_req; -}; - -struct pm8001_prd_imt { - __le32 len; - __le32 e; -}; - -struct pm8001_prd { - __le64 addr; /* 64-bit buffer address */ - struct pm8001_prd_imt im_len; /* 64-bit length */ -} __attribute__ ((packed)); -/* - * CCB(Command Control Block) - */ -struct pm8001_ccb_info { - struct list_head entry; - struct sas_task *task; - u32 n_elem; - u32 ccb_tag; - dma_addr_t ccb_dma_handle; - struct pm8001_device *device; - struct pm8001_prd buf_prd[PM8001_MAX_DMA_SG]; - struct fw_control_ex *fw_control_context; - u8 open_retry; -}; - -struct mpi_mem { - void *virt_ptr; - dma_addr_t phys_addr; - u32 phys_addr_hi; - u32 phys_addr_lo; - u32 total_len; - u32 num_elements; - u32 element_size; - u32 alignment; -}; - -struct mpi_mem_req { - /* The number of element in the mpiMemory array */ - u32 count; - /* The array of structures that define memroy regions*/ - struct mpi_mem region[USI_MAX_MEMCNT]; -}; - -struct main_cfg_table { - u32 signature; - u32 interface_rev; - u32 firmware_rev; - u32 max_out_io; - u32 max_sgl; - u32 ctrl_cap_flag; - u32 gst_offset; - u32 inbound_queue_offset; - u32 outbound_queue_offset; - u32 inbound_q_nppd_hppd; - u32 outbound_hw_event_pid0_3; - u32 outbound_hw_event_pid4_7; - u32 outbound_ncq_event_pid0_3; - u32 outbound_ncq_event_pid4_7; - u32 outbound_tgt_ITNexus_event_pid0_3; - u32 outbound_tgt_ITNexus_event_pid4_7; - u32 outbound_tgt_ssp_event_pid0_3; - u32 outbound_tgt_ssp_event_pid4_7; - u32 outbound_tgt_smp_event_pid0_3; - u32 outbound_tgt_smp_event_pid4_7; - u32 upper_event_log_addr; - u32 lower_event_log_addr; - u32 event_log_size; - u32 event_log_option; - u32 upper_iop_event_log_addr; - u32 lower_iop_event_log_addr; - u32 iop_event_log_size; - u32 iop_event_log_option; - u32 fatal_err_interrupt; - u32 fatal_err_dump_offset0; - u32 fatal_err_dump_length0; - u32 fatal_err_dump_offset1; - u32 fatal_err_dump_length1; - u32 hda_mode_flag; - u32 anolog_setup_table_offset; -}; -struct general_status_table { - u32 gst_len_mpistate; - u32 iq_freeze_state0; - u32 iq_freeze_state1; - u32 msgu_tcnt; - u32 iop_tcnt; - u32 reserved; - u32 phy_state[8]; - u32 reserved1; - u32 reserved2; - u32 reserved3; - u32 recover_err_info[8]; -}; -struct inbound_queue_table { - u32 element_pri_size_cnt; - u32 upper_base_addr; - u32 lower_base_addr; - u32 ci_upper_base_addr; - u32 ci_lower_base_addr; - u32 pi_pci_bar; - u32 pi_offset; - u32 total_length; - void *base_virt; - void *ci_virt; - u32 reserved; - __le32 consumer_index; - u32 producer_idx; -}; -struct outbound_queue_table { - u32 element_size_cnt; - u32 upper_base_addr; - u32 lower_base_addr; - void *base_virt; - u32 pi_upper_base_addr; - u32 pi_lower_base_addr; - u32 ci_pci_bar; - u32 ci_offset; - u32 total_length; - void *pi_virt; - u32 interrup_vec_cnt_delay; - u32 dinterrup_to_pci_offset; - __le32 producer_index; - u32 consumer_idx; -}; -struct pm8001_hba_memspace { - void __iomem *memvirtaddr; - u64 membase; - u32 memsize; -}; -struct pm8001_hba_info { - char name[PM8001_NAME_LENGTH]; - struct list_head list; - unsigned long flags; - spinlock_t lock;/* host-wide lock */ - struct pci_dev *pdev;/* our device */ - struct device *dev; - struct pm8001_hba_memspace io_mem[6]; - struct mpi_mem_req memoryMap; - void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/ - void __iomem *main_cfg_tbl_addr;/*Main Config Table Addr*/ - void __iomem *general_stat_tbl_addr;/*General Status Table Addr*/ - void __iomem *inbnd_q_tbl_addr;/*Inbound Queue Config Table Addr*/ - void __iomem *outbnd_q_tbl_addr;/*Outbound Queue Config Table Addr*/ - struct main_cfg_table main_cfg_tbl; - struct general_status_table gs_tbl; - struct inbound_queue_table inbnd_q_tbl[PM8001_MAX_INB_NUM]; - struct outbound_queue_table outbnd_q_tbl[PM8001_MAX_OUTB_NUM]; - u8 sas_addr[SAS_ADDR_SIZE]; - struct sas_ha_struct *sas;/* SCSI/SAS glue */ - struct Scsi_Host *shost; - u32 chip_id; - const struct pm8001_chip_info *chip; - struct completion *nvmd_completion; - int tags_num; - unsigned long *tags; - struct pm8001_phy phy[PM8001_MAX_PHYS]; - struct pm8001_port port[PM8001_MAX_PHYS]; - u32 id; - u32 irq; - struct pm8001_device *devices; - struct pm8001_ccb_info *ccb_info; -#ifdef PM8001_USE_MSIX - struct msix_entry msix_entries[16];/*for msi-x interrupt*/ - int number_of_intr;/*will be used in remove()*/ -#endif -#ifdef PM8001_USE_TASKLET - struct tasklet_struct tasklet; -#endif - u32 logging_level; - u32 fw_status; - const struct firmware *fw_image; -}; - -struct pm8001_work { - struct work_struct work; - struct pm8001_hba_info *pm8001_ha; - void *data; - int handler; -}; - -struct pm8001_fw_image_header { - u8 vender_id[8]; - u8 product_id; - u8 hardware_rev; - u8 dest_partition; - u8 reserved; - u8 fw_rev[4]; - __be32 image_length; - __be32 image_crc; - __be32 startup_entry; -} __attribute__((packed, aligned(4))); - - -/** - * FW Flash Update status values - */ -#define FLASH_UPDATE_COMPLETE_PENDING_REBOOT 0x00 -#define FLASH_UPDATE_IN_PROGRESS 0x01 -#define FLASH_UPDATE_HDR_ERR 0x02 -#define FLASH_UPDATE_OFFSET_ERR 0x03 -#define FLASH_UPDATE_CRC_ERR 0x04 -#define FLASH_UPDATE_LENGTH_ERR 0x05 -#define FLASH_UPDATE_HW_ERR 0x06 -#define FLASH_UPDATE_DNLD_NOT_SUPPORTED 0x10 -#define FLASH_UPDATE_DISABLED 0x11 - -/** - * brief param structure for firmware flash update. - */ -struct fw_flash_updata_info { - u32 cur_image_offset; - u32 cur_image_len; - u32 total_image_len; - struct pm8001_prd sgl; -}; - -struct fw_control_info { - u32 retcode;/*ret code (status)*/ - u32 phase;/*ret code phase*/ - u32 phaseCmplt;/*percent complete for the current - update phase */ - u32 version;/*Hex encoded firmware version number*/ - u32 offset;/*Used for downloading firmware */ - u32 len; /*len of buffer*/ - u32 size;/* Used in OS VPD and Trace get size - operations.*/ - u32 reserved;/* padding required for 64 bit - alignment */ - u8 buffer[1];/* Start of buffer */ -}; -struct fw_control_ex { - struct fw_control_info *fw_control; - void *buffer;/* keep buffer pointer to be - freed when the response comes*/ - void *virtAddr;/* keep virtual address of the data */ - void *usrAddr;/* keep virtual address of the - user data */ - dma_addr_t phys_addr; - u32 len; /* len of buffer */ - void *payload; /* pointer to IOCTL Payload */ - u8 inProgress;/*if 1 - the IOCTL request is in - progress */ - void *param1; - void *param2; - void *param3; -}; - -/* pm8001 workqueue */ -extern struct workqueue_struct *pm8001_wq; - -/******************** function prototype *********************/ -int pm8001_tag_alloc(struct pm8001_hba_info *pm8001_ha, u32 *tag_out); -void pm8001_tag_init(struct pm8001_hba_info *pm8001_ha); -u32 pm8001_get_ncq_tag(struct sas_task *task, u32 *tag); -void pm8001_ccb_free(struct pm8001_hba_info *pm8001_ha, u32 ccb_idx); -void pm8001_ccb_task_free(struct pm8001_hba_info *pm8001_ha, - struct sas_task *task, struct pm8001_ccb_info *ccb, u32 ccb_idx); -int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, - void *funcdata); -void pm8001_scan_start(struct Scsi_Host *shost); -int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time); -int pm8001_queue_command(struct sas_task *task, const int num, - gfp_t gfp_flags); -int pm8001_abort_task(struct sas_task *task); -int pm8001_abort_task_set(struct domain_device *dev, u8 *lun); -int pm8001_clear_aca(struct domain_device *dev, u8 *lun); -int pm8001_clear_task_set(struct domain_device *dev, u8 *lun); -int pm8001_dev_found(struct domain_device *dev); -void pm8001_dev_gone(struct domain_device *dev); -int pm8001_lu_reset(struct domain_device *dev, u8 *lun); -int pm8001_I_T_nexus_reset(struct domain_device *dev); -int pm8001_query_task(struct sas_task *task); -void pm8001_open_reject_retry( - struct pm8001_hba_info *pm8001_ha, - struct sas_task *task_to_close, - struct pm8001_device *device_to_close); -int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr, - dma_addr_t *pphys_addr, u32 *pphys_addr_hi, u32 *pphys_addr_lo, - u32 mem_size, u32 align); - -int pm8001_bar4_shift(struct pm8001_hba_info *pm8001_ha, u32 shiftValue); - -/* ctl shared API */ -extern struct device_attribute *pm8001_host_attrs[]; - -#endif - diff --git a/ANDROID_3.4.5/drivers/scsi/pmcraid.c b/ANDROID_3.4.5/drivers/scsi/pmcraid.c deleted file mode 100644 index ea8a0b47..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pmcraid.c +++ /dev/null @@ -1,6158 +0,0 @@ -/* - * pmcraid.c -- driver for PMC Sierra MaxRAID controller adapters - * - * Written By: Anil Ravindranath - * PMC-Sierra Inc - * - * Copyright (C) 2008, 2009 PMC Sierra Inc - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, - * USA - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pmcraid.h" - -/* - * Module configuration parameters - */ -static unsigned int pmcraid_debug_log; -static unsigned int pmcraid_disable_aen; -static unsigned int pmcraid_log_level = IOASC_LOG_LEVEL_MUST; -static unsigned int pmcraid_enable_msix; - -/* - * Data structures to support multiple adapters by the LLD. - * pmcraid_adapter_count - count of configured adapters - */ -static atomic_t pmcraid_adapter_count = ATOMIC_INIT(0); - -/* - * Supporting user-level control interface through IOCTL commands. - * pmcraid_major - major number to use - * pmcraid_minor - minor number(s) to use - */ -static unsigned int pmcraid_major; -static struct class *pmcraid_class; -DECLARE_BITMAP(pmcraid_minor, PMCRAID_MAX_ADAPTERS); - -/* - * Module parameters - */ -MODULE_AUTHOR("Anil Ravindranath"); -MODULE_DESCRIPTION("PMC Sierra MaxRAID Controller Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(PMCRAID_DRIVER_VERSION); - -module_param_named(log_level, pmcraid_log_level, uint, (S_IRUGO | S_IWUSR)); -MODULE_PARM_DESC(log_level, - "Enables firmware error code logging, default :1 high-severity" - " errors, 2: all errors including high-severity errors," - " 0: disables logging"); - -module_param_named(debug, pmcraid_debug_log, uint, (S_IRUGO | S_IWUSR)); -MODULE_PARM_DESC(debug, - "Enable driver verbose message logging. Set 1 to enable." - "(default: 0)"); - -module_param_named(disable_aen, pmcraid_disable_aen, uint, (S_IRUGO | S_IWUSR)); -MODULE_PARM_DESC(disable_aen, - "Disable driver aen notifications to apps. Set 1 to disable." - "(default: 0)"); - -/* chip specific constants for PMC MaxRAID controllers (same for - * 0x5220 and 0x8010 - */ -static struct pmcraid_chip_details pmcraid_chip_cfg[] = { - { - .ioastatus = 0x0, - .ioarrin = 0x00040, - .mailbox = 0x7FC30, - .global_intr_mask = 0x00034, - .ioa_host_intr = 0x0009C, - .ioa_host_intr_clr = 0x000A0, - .ioa_host_msix_intr = 0x7FC40, - .ioa_host_mask = 0x7FC28, - .ioa_host_mask_clr = 0x7FC28, - .host_ioa_intr = 0x00020, - .host_ioa_intr_clr = 0x00020, - .transop_timeout = 300 - } -}; - -/* - * PCI device ids supported by pmcraid driver - */ -static struct pci_device_id pmcraid_pci_table[] __devinitdata = { - { PCI_DEVICE(PCI_VENDOR_ID_PMC, PCI_DEVICE_ID_PMC_MAXRAID), - 0, 0, (kernel_ulong_t)&pmcraid_chip_cfg[0] - }, - {} -}; - -MODULE_DEVICE_TABLE(pci, pmcraid_pci_table); - - - -/** - * pmcraid_slave_alloc - Prepare for commands to a device - * @scsi_dev: scsi device struct - * - * This function is called by mid-layer prior to sending any command to the new - * device. Stores resource entry details of the device in scsi_device struct. - * Queuecommand uses the resource handle and other details to fill up IOARCB - * while sending commands to the device. - * - * Return value: - * 0 on success / -ENXIO if device does not exist - */ -static int pmcraid_slave_alloc(struct scsi_device *scsi_dev) -{ - struct pmcraid_resource_entry *temp, *res = NULL; - struct pmcraid_instance *pinstance; - u8 target, bus, lun; - unsigned long lock_flags; - int rc = -ENXIO; - u16 fw_version; - - pinstance = shost_priv(scsi_dev->host); - - fw_version = be16_to_cpu(pinstance->inq_data->fw_version); - - /* Driver exposes VSET and GSCSI resources only; all other device types - * are not exposed. Resource list is synchronized using resource lock - * so any traversal or modifications to the list should be done inside - * this lock - */ - spin_lock_irqsave(&pinstance->resource_lock, lock_flags); - list_for_each_entry(temp, &pinstance->used_res_q, queue) { - - /* do not expose VSETs with order-ids > MAX_VSET_TARGETS */ - if (RES_IS_VSET(temp->cfg_entry)) { - if (fw_version <= PMCRAID_FW_VERSION_1) - target = temp->cfg_entry.unique_flags1; - else - target = temp->cfg_entry.array_id & 0xFF; - - if (target > PMCRAID_MAX_VSET_TARGETS) - continue; - bus = PMCRAID_VSET_BUS_ID; - lun = 0; - } else if (RES_IS_GSCSI(temp->cfg_entry)) { - target = RES_TARGET(temp->cfg_entry.resource_address); - bus = PMCRAID_PHYS_BUS_ID; - lun = RES_LUN(temp->cfg_entry.resource_address); - } else { - continue; - } - - if (bus == scsi_dev->channel && - target == scsi_dev->id && - lun == scsi_dev->lun) { - res = temp; - break; - } - } - - if (res) { - res->scsi_dev = scsi_dev; - scsi_dev->hostdata = res; - res->change_detected = 0; - atomic_set(&res->read_failures, 0); - atomic_set(&res->write_failures, 0); - rc = 0; - } - spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); - return rc; -} - -/** - * pmcraid_slave_configure - Configures a SCSI device - * @scsi_dev: scsi device struct - * - * This function is executed by SCSI mid layer just after a device is first - * scanned (i.e. it has responded to an INQUIRY). For VSET resources, the - * timeout value (default 30s) will be over-written to a higher value (60s) - * and max_sectors value will be over-written to 512. It also sets queue depth - * to host->cmd_per_lun value - * - * Return value: - * 0 on success - */ -static int pmcraid_slave_configure(struct scsi_device *scsi_dev) -{ - struct pmcraid_resource_entry *res = scsi_dev->hostdata; - - if (!res) - return 0; - - /* LLD exposes VSETs and Enclosure devices only */ - if (RES_IS_GSCSI(res->cfg_entry) && - scsi_dev->type != TYPE_ENCLOSURE) - return -ENXIO; - - pmcraid_info("configuring %x:%x:%x:%x\n", - scsi_dev->host->unique_id, - scsi_dev->channel, - scsi_dev->id, - scsi_dev->lun); - - if (RES_IS_GSCSI(res->cfg_entry)) { - scsi_dev->allow_restart = 1; - } else if (RES_IS_VSET(res->cfg_entry)) { - scsi_dev->allow_restart = 1; - blk_queue_rq_timeout(scsi_dev->request_queue, - PMCRAID_VSET_IO_TIMEOUT); - blk_queue_max_hw_sectors(scsi_dev->request_queue, - PMCRAID_VSET_MAX_SECTORS); - } - - if (scsi_dev->tagged_supported && - (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) { - scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); - scsi_adjust_queue_depth(scsi_dev, MSG_SIMPLE_TAG, - scsi_dev->host->cmd_per_lun); - } else { - scsi_adjust_queue_depth(scsi_dev, 0, - scsi_dev->host->cmd_per_lun); - } - - return 0; -} - -/** - * pmcraid_slave_destroy - Unconfigure a SCSI device before removing it - * - * @scsi_dev: scsi device struct - * - * This is called by mid-layer before removing a device. Pointer assignments - * done in pmcraid_slave_alloc will be reset to NULL here. - * - * Return value - * none - */ -static void pmcraid_slave_destroy(struct scsi_device *scsi_dev) -{ - struct pmcraid_resource_entry *res; - - res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; - - if (res) - res->scsi_dev = NULL; - - scsi_dev->hostdata = NULL; -} - -/** - * pmcraid_change_queue_depth - Change the device's queue depth - * @scsi_dev: scsi device struct - * @depth: depth to set - * @reason: calling context - * - * Return value - * actual depth set - */ -static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth, - int reason) -{ - if (reason != SCSI_QDEPTH_DEFAULT) - return -EOPNOTSUPP; - - if (depth > PMCRAID_MAX_CMD_PER_LUN) - depth = PMCRAID_MAX_CMD_PER_LUN; - - scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev), depth); - - return scsi_dev->queue_depth; -} - -/** - * pmcraid_change_queue_type - Change the device's queue type - * @scsi_dev: scsi device struct - * @tag: type of tags to use - * - * Return value: - * actual queue type set - */ -static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag) -{ - struct pmcraid_resource_entry *res; - - res = (struct pmcraid_resource_entry *)scsi_dev->hostdata; - - if ((res) && scsi_dev->tagged_supported && - (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) { - scsi_set_tag_type(scsi_dev, tag); - - if (tag) - scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); - else - scsi_deactivate_tcq(scsi_dev, scsi_dev->queue_depth); - } else - tag = 0; - - return tag; -} - - -/** - * pmcraid_init_cmdblk - initializes a command block - * - * @cmd: pointer to struct pmcraid_cmd to be initialized - * @index: if >=0 first time initialization; otherwise reinitialization - * - * Return Value - * None - */ -void pmcraid_init_cmdblk(struct pmcraid_cmd *cmd, int index) -{ - struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); - dma_addr_t dma_addr = cmd->ioa_cb_bus_addr; - - if (index >= 0) { - /* first time initialization (called from probe) */ - u32 ioasa_offset = - offsetof(struct pmcraid_control_block, ioasa); - - cmd->index = index; - ioarcb->response_handle = cpu_to_le32(index << 2); - ioarcb->ioarcb_bus_addr = cpu_to_le64(dma_addr); - ioarcb->ioasa_bus_addr = cpu_to_le64(dma_addr + ioasa_offset); - ioarcb->ioasa_len = cpu_to_le16(sizeof(struct pmcraid_ioasa)); - } else { - /* re-initialization of various lengths, called once command is - * processed by IOA - */ - memset(&cmd->ioa_cb->ioarcb.cdb, 0, PMCRAID_MAX_CDB_LEN); - ioarcb->hrrq_id = 0; - ioarcb->request_flags0 = 0; - ioarcb->request_flags1 = 0; - ioarcb->cmd_timeout = 0; - ioarcb->ioarcb_bus_addr &= (~0x1FULL); - ioarcb->ioadl_bus_addr = 0; - ioarcb->ioadl_length = 0; - ioarcb->data_transfer_length = 0; - ioarcb->add_cmd_param_length = 0; - ioarcb->add_cmd_param_offset = 0; - cmd->ioa_cb->ioasa.ioasc = 0; - cmd->ioa_cb->ioasa.residual_data_length = 0; - cmd->time_left = 0; - } - - cmd->cmd_done = NULL; - cmd->scsi_cmd = NULL; - cmd->release = 0; - cmd->completion_req = 0; - cmd->sense_buffer = 0; - cmd->sense_buffer_dma = 0; - cmd->dma_handle = 0; - init_timer(&cmd->timer); -} - -/** - * pmcraid_reinit_cmdblk - reinitialize a command block - * - * @cmd: pointer to struct pmcraid_cmd to be reinitialized - * - * Return Value - * None - */ -static void pmcraid_reinit_cmdblk(struct pmcraid_cmd *cmd) -{ - pmcraid_init_cmdblk(cmd, -1); -} - -/** - * pmcraid_get_free_cmd - get a free cmd block from command block pool - * @pinstance: adapter instance structure - * - * Return Value: - * returns pointer to cmd block or NULL if no blocks are available - */ -static struct pmcraid_cmd *pmcraid_get_free_cmd( - struct pmcraid_instance *pinstance -) -{ - struct pmcraid_cmd *cmd = NULL; - unsigned long lock_flags; - - /* free cmd block list is protected by free_pool_lock */ - spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); - - if (!list_empty(&pinstance->free_cmd_pool)) { - cmd = list_entry(pinstance->free_cmd_pool.next, - struct pmcraid_cmd, free_list); - list_del(&cmd->free_list); - } - spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); - - /* Initialize the command block before giving it the caller */ - if (cmd != NULL) - pmcraid_reinit_cmdblk(cmd); - return cmd; -} - -/** - * pmcraid_return_cmd - return a completed command block back into free pool - * @cmd: pointer to the command block - * - * Return Value: - * nothing - */ -void pmcraid_return_cmd(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - unsigned long lock_flags; - - spin_lock_irqsave(&pinstance->free_pool_lock, lock_flags); - list_add_tail(&cmd->free_list, &pinstance->free_cmd_pool); - spin_unlock_irqrestore(&pinstance->free_pool_lock, lock_flags); -} - -/** - * pmcraid_read_interrupts - reads IOA interrupts - * - * @pinstance: pointer to adapter instance structure - * - * Return value - * interrupts read from IOA - */ -static u32 pmcraid_read_interrupts(struct pmcraid_instance *pinstance) -{ - return (pinstance->interrupt_mode) ? - ioread32(pinstance->int_regs.ioa_host_msix_interrupt_reg) : - ioread32(pinstance->int_regs.ioa_host_interrupt_reg); -} - -/** - * pmcraid_disable_interrupts - Masks and clears all specified interrupts - * - * @pinstance: pointer to per adapter instance structure - * @intrs: interrupts to disable - * - * Return Value - * None - */ -static void pmcraid_disable_interrupts( - struct pmcraid_instance *pinstance, - u32 intrs -) -{ - u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); - u32 nmask = gmask | GLOBAL_INTERRUPT_MASK; - - iowrite32(intrs, pinstance->int_regs.ioa_host_interrupt_clr_reg); - iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); - ioread32(pinstance->int_regs.global_interrupt_mask_reg); - - if (!pinstance->interrupt_mode) { - iowrite32(intrs, - pinstance->int_regs.ioa_host_interrupt_mask_reg); - ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); - } -} - -/** - * pmcraid_enable_interrupts - Enables specified interrupts - * - * @pinstance: pointer to per adapter instance structure - * @intr: interrupts to enable - * - * Return Value - * None - */ -static void pmcraid_enable_interrupts( - struct pmcraid_instance *pinstance, - u32 intrs -) -{ - u32 gmask = ioread32(pinstance->int_regs.global_interrupt_mask_reg); - u32 nmask = gmask & (~GLOBAL_INTERRUPT_MASK); - - iowrite32(nmask, pinstance->int_regs.global_interrupt_mask_reg); - - if (!pinstance->interrupt_mode) { - iowrite32(~intrs, - pinstance->int_regs.ioa_host_interrupt_mask_reg); - ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); - } - - pmcraid_info("enabled interrupts global mask = %x intr_mask = %x\n", - ioread32(pinstance->int_regs.global_interrupt_mask_reg), - ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg)); -} - -/** - * pmcraid_clr_trans_op - clear trans to op interrupt - * - * @pinstance: pointer to per adapter instance structure - * - * Return Value - * None - */ -static void pmcraid_clr_trans_op( - struct pmcraid_instance *pinstance -) -{ - unsigned long lock_flags; - - if (!pinstance->interrupt_mode) { - iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, - pinstance->int_regs.ioa_host_interrupt_mask_reg); - ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); - iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, - pinstance->int_regs.ioa_host_interrupt_clr_reg); - ioread32(pinstance->int_regs.ioa_host_interrupt_clr_reg); - } - - if (pinstance->reset_cmd != NULL) { - del_timer(&pinstance->reset_cmd->timer); - spin_lock_irqsave( - pinstance->host->host_lock, lock_flags); - pinstance->reset_cmd->cmd_done(pinstance->reset_cmd); - spin_unlock_irqrestore( - pinstance->host->host_lock, lock_flags); - } -} - -/** - * pmcraid_reset_type - Determine the required reset type - * @pinstance: pointer to adapter instance structure - * - * IOA requires hard reset if any of the following conditions is true. - * 1. If HRRQ valid interrupt is not masked - * 2. IOA reset alert doorbell is set - * 3. If there are any error interrupts - */ -static void pmcraid_reset_type(struct pmcraid_instance *pinstance) -{ - u32 mask; - u32 intrs; - u32 alerts; - - mask = ioread32(pinstance->int_regs.ioa_host_interrupt_mask_reg); - intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); - alerts = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); - - if ((mask & INTRS_HRRQ_VALID) == 0 || - (alerts & DOORBELL_IOA_RESET_ALERT) || - (intrs & PMCRAID_ERROR_INTERRUPTS)) { - pmcraid_info("IOA requires hard reset\n"); - pinstance->ioa_hard_reset = 1; - } - - /* If unit check is active, trigger the dump */ - if (intrs & INTRS_IOA_UNIT_CHECK) - pinstance->ioa_unit_check = 1; -} - -/** - * pmcraid_bist_done - completion function for PCI BIST - * @cmd: pointer to reset command - * Return Value - * none - */ - -static void pmcraid_ioa_reset(struct pmcraid_cmd *); - -static void pmcraid_bist_done(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - unsigned long lock_flags; - int rc; - u16 pci_reg; - - rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); - - /* If PCI config space can't be accessed wait for another two secs */ - if ((rc != PCIBIOS_SUCCESSFUL || (!(pci_reg & PCI_COMMAND_MEMORY))) && - cmd->time_left > 0) { - pmcraid_info("BIST not complete, waiting another 2 secs\n"); - cmd->timer.expires = jiffies + cmd->time_left; - cmd->time_left = 0; - cmd->timer.data = (unsigned long)cmd; - cmd->timer.function = - (void (*)(unsigned long))pmcraid_bist_done; - add_timer(&cmd->timer); - } else { - cmd->time_left = 0; - pmcraid_info("BIST is complete, proceeding with reset\n"); - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - pmcraid_ioa_reset(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - } -} - -/** - * pmcraid_start_bist - starts BIST - * @cmd: pointer to reset cmd - * Return Value - * none - */ -static void pmcraid_start_bist(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - u32 doorbells, intrs; - - /* proceed with bist and wait for 2 seconds */ - iowrite32(DOORBELL_IOA_START_BIST, - pinstance->int_regs.host_ioa_interrupt_reg); - doorbells = ioread32(pinstance->int_regs.host_ioa_interrupt_reg); - intrs = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); - pmcraid_info("doorbells after start bist: %x intrs: %x\n", - doorbells, intrs); - - cmd->time_left = msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); - cmd->timer.data = (unsigned long)cmd; - cmd->timer.expires = jiffies + msecs_to_jiffies(PMCRAID_BIST_TIMEOUT); - cmd->timer.function = (void (*)(unsigned long))pmcraid_bist_done; - add_timer(&cmd->timer); -} - -/** - * pmcraid_reset_alert_done - completion routine for reset_alert - * @cmd: pointer to command block used in reset sequence - * Return value - * None - */ -static void pmcraid_reset_alert_done(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - u32 status = ioread32(pinstance->ioa_status); - unsigned long lock_flags; - - /* if the critical operation in progress bit is set or the wait times - * out, invoke reset engine to proceed with hard reset. If there is - * some more time to wait, restart the timer - */ - if (((status & INTRS_CRITICAL_OP_IN_PROGRESS) == 0) || - cmd->time_left <= 0) { - pmcraid_info("critical op is reset proceeding with reset\n"); - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - pmcraid_ioa_reset(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - } else { - pmcraid_info("critical op is not yet reset waiting again\n"); - /* restart timer if some more time is available to wait */ - cmd->time_left -= PMCRAID_CHECK_FOR_RESET_TIMEOUT; - cmd->timer.data = (unsigned long)cmd; - cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; - cmd->timer.function = - (void (*)(unsigned long))pmcraid_reset_alert_done; - add_timer(&cmd->timer); - } -} - -/** - * pmcraid_reset_alert - alerts IOA for a possible reset - * @cmd : command block to be used for reset sequence. - * - * Return Value - * returns 0 if pci config-space is accessible and RESET_DOORBELL is - * successfully written to IOA. Returns non-zero in case pci_config_space - * is not accessible - */ -static void pmcraid_notify_ioastate(struct pmcraid_instance *, u32); -static void pmcraid_reset_alert(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - u32 doorbells; - int rc; - u16 pci_reg; - - /* If we are able to access IOA PCI config space, alert IOA that we are - * going to reset it soon. This enables IOA to preserv persistent error - * data if any. In case memory space is not accessible, proceed with - * BIST or slot_reset - */ - rc = pci_read_config_word(pinstance->pdev, PCI_COMMAND, &pci_reg); - if ((rc == PCIBIOS_SUCCESSFUL) && (pci_reg & PCI_COMMAND_MEMORY)) { - - /* wait for IOA permission i.e until CRITICAL_OPERATION bit is - * reset IOA doesn't generate any interrupts when CRITICAL - * OPERATION bit is reset. A timer is started to wait for this - * bit to be reset. - */ - cmd->time_left = PMCRAID_RESET_TIMEOUT; - cmd->timer.data = (unsigned long)cmd; - cmd->timer.expires = jiffies + PMCRAID_CHECK_FOR_RESET_TIMEOUT; - cmd->timer.function = - (void (*)(unsigned long))pmcraid_reset_alert_done; - add_timer(&cmd->timer); - - iowrite32(DOORBELL_IOA_RESET_ALERT, - pinstance->int_regs.host_ioa_interrupt_reg); - doorbells = - ioread32(pinstance->int_regs.host_ioa_interrupt_reg); - pmcraid_info("doorbells after reset alert: %x\n", doorbells); - } else { - pmcraid_info("PCI config is not accessible starting BIST\n"); - pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; - pmcraid_start_bist(cmd); - } -} - -/** - * pmcraid_timeout_handler - Timeout handler for internally generated ops - * - * @cmd : pointer to command structure, that got timedout - * - * This function blocks host requests and initiates an adapter reset. - * - * Return value: - * None - */ -static void pmcraid_timeout_handler(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - unsigned long lock_flags; - - dev_info(&pinstance->pdev->dev, - "Adapter being reset due to cmd(CDB[0] = %x) timeout\n", - cmd->ioa_cb->ioarcb.cdb[0]); - - /* Command timeouts result in hard reset sequence. The command that got - * timed out may be the one used as part of reset sequence. In this - * case restart reset sequence using the same command block even if - * reset is in progress. Otherwise fail this command and get a free - * command block to restart the reset sequence. - */ - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - if (!pinstance->ioa_reset_in_progress) { - pinstance->ioa_reset_attempts = 0; - cmd = pmcraid_get_free_cmd(pinstance); - - /* If we are out of command blocks, just return here itself. - * Some other command's timeout handler can do the reset job - */ - if (cmd == NULL) { - spin_unlock_irqrestore(pinstance->host->host_lock, - lock_flags); - pmcraid_err("no free cmnd block for timeout handler\n"); - return; - } - - pinstance->reset_cmd = cmd; - pinstance->ioa_reset_in_progress = 1; - } else { - pmcraid_info("reset is already in progress\n"); - - if (pinstance->reset_cmd != cmd) { - /* This command should have been given to IOA, this - * command will be completed by fail_outstanding_cmds - * anyway - */ - pmcraid_err("cmd is pending but reset in progress\n"); - } - - /* If this command was being used as part of the reset - * sequence, set cmd_done pointer to pmcraid_ioa_reset. This - * causes fail_outstanding_commands not to return the command - * block back to free pool - */ - if (cmd == pinstance->reset_cmd) - cmd->cmd_done = pmcraid_ioa_reset; - } - - /* Notify apps of important IOA bringup/bringdown sequences */ - if (pinstance->scn.ioa_state != PMC_DEVICE_EVENT_RESET_START && - pinstance->scn.ioa_state != PMC_DEVICE_EVENT_SHUTDOWN_START) - pmcraid_notify_ioastate(pinstance, - PMC_DEVICE_EVENT_RESET_START); - - pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; - scsi_block_requests(pinstance->host); - pmcraid_reset_alert(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); -} - -/** - * pmcraid_internal_done - completion routine for internally generated cmds - * - * @cmd: command that got response from IOA - * - * Return Value: - * none - */ -static void pmcraid_internal_done(struct pmcraid_cmd *cmd) -{ - pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", - cmd->ioa_cb->ioarcb.cdb[0], - le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); - - /* Some of the internal commands are sent with callers blocking for the - * response. Same will be indicated as part of cmd->completion_req - * field. Response path needs to wake up any waiters waiting for cmd - * completion if this flag is set. - */ - if (cmd->completion_req) { - cmd->completion_req = 0; - complete(&cmd->wait_for_completion); - } - - /* most of the internal commands are completed by caller itself, so - * no need to return the command block back to free pool until we are - * required to do so (e.g once done with initialization). - */ - if (cmd->release) { - cmd->release = 0; - pmcraid_return_cmd(cmd); - } -} - -/** - * pmcraid_reinit_cfgtable_done - done function for cfg table reinitialization - * - * @cmd: command that got response from IOA - * - * This routine is called after driver re-reads configuration table due to a - * lost CCN. It returns the command block back to free pool and schedules - * worker thread to add/delete devices into the system. - * - * Return Value: - * none - */ -static void pmcraid_reinit_cfgtable_done(struct pmcraid_cmd *cmd) -{ - pmcraid_info("response internal cmd CDB[0] = %x ioasc = %x\n", - cmd->ioa_cb->ioarcb.cdb[0], - le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); - - if (cmd->release) { - cmd->release = 0; - pmcraid_return_cmd(cmd); - } - pmcraid_info("scheduling worker for config table reinitialization\n"); - schedule_work(&cmd->drv_inst->worker_q); -} - -/** - * pmcraid_erp_done - Process completion of SCSI error response from device - * @cmd: pmcraid_command - * - * This function copies the sense buffer into the scsi_cmd struct and completes - * scsi_cmd by calling scsi_done function. - * - * Return value: - * none - */ -static void pmcraid_erp_done(struct pmcraid_cmd *cmd) -{ - struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; - struct pmcraid_instance *pinstance = cmd->drv_inst; - u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); - - if (PMCRAID_IOASC_SENSE_KEY(ioasc) > 0) { - scsi_cmd->result |= (DID_ERROR << 16); - scmd_printk(KERN_INFO, scsi_cmd, - "command CDB[0] = %x failed with IOASC: 0x%08X\n", - cmd->ioa_cb->ioarcb.cdb[0], ioasc); - } - - /* if we had allocated sense buffers for request sense, copy the sense - * release the buffers - */ - if (cmd->sense_buffer != NULL) { - memcpy(scsi_cmd->sense_buffer, - cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE); - pci_free_consistent(pinstance->pdev, - SCSI_SENSE_BUFFERSIZE, - cmd->sense_buffer, cmd->sense_buffer_dma); - cmd->sense_buffer = NULL; - cmd->sense_buffer_dma = 0; - } - - scsi_dma_unmap(scsi_cmd); - pmcraid_return_cmd(cmd); - scsi_cmd->scsi_done(scsi_cmd); -} - -/** - * pmcraid_fire_command - sends an IOA command to adapter - * - * This function adds the given block into pending command list - * and returns without waiting - * - * @cmd : command to be sent to the device - * - * Return Value - * None - */ -static void _pmcraid_fire_command(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - unsigned long lock_flags; - - /* Add this command block to pending cmd pool. We do this prior to - * writting IOARCB to ioarrin because IOA might complete the command - * by the time we are about to add it to the list. Response handler - * (isr/tasklet) looks for cmd block in the pending pending list. - */ - spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); - list_add_tail(&cmd->free_list, &pinstance->pending_cmd_pool); - spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); - atomic_inc(&pinstance->outstanding_cmds); - - /* driver writes lower 32-bit value of IOARCB address only */ - mb(); - iowrite32(le32_to_cpu(cmd->ioa_cb->ioarcb.ioarcb_bus_addr), - pinstance->ioarrin); -} - -/** - * pmcraid_send_cmd - fires a command to IOA - * - * This function also sets up timeout function, and command completion - * function - * - * @cmd: pointer to the command block to be fired to IOA - * @cmd_done: command completion function, called once IOA responds - * @timeout: timeout to wait for this command completion - * @timeout_func: timeout handler - * - * Return value - * none - */ -static void pmcraid_send_cmd( - struct pmcraid_cmd *cmd, - void (*cmd_done) (struct pmcraid_cmd *), - unsigned long timeout, - void (*timeout_func) (struct pmcraid_cmd *) -) -{ - /* initialize done function */ - cmd->cmd_done = cmd_done; - - if (timeout_func) { - /* setup timeout handler */ - cmd->timer.data = (unsigned long)cmd; - cmd->timer.expires = jiffies + timeout; - cmd->timer.function = (void (*)(unsigned long))timeout_func; - add_timer(&cmd->timer); - } - - /* fire the command to IOA */ - _pmcraid_fire_command(cmd); -} - -/** - * pmcraid_ioa_shutdown_done - completion function for IOA shutdown command - * @cmd: pointer to the command block used for sending IOA shutdown command - * - * Return value - * None - */ -static void pmcraid_ioa_shutdown_done(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - unsigned long lock_flags; - - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - pmcraid_ioa_reset(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); -} - -/** - * pmcraid_ioa_shutdown - sends SHUTDOWN command to ioa - * - * @cmd: pointer to the command block used as part of reset sequence - * - * Return Value - * None - */ -static void pmcraid_ioa_shutdown(struct pmcraid_cmd *cmd) -{ - pmcraid_info("response for Cancel CCN CDB[0] = %x ioasc = %x\n", - cmd->ioa_cb->ioarcb.cdb[0], - le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); - - /* Note that commands sent during reset require next command to be sent - * to IOA. Hence reinit the done function as well as timeout function - */ - pmcraid_reinit_cmdblk(cmd); - cmd->ioa_cb->ioarcb.request_type = REQ_TYPE_IOACMD; - cmd->ioa_cb->ioarcb.resource_handle = - cpu_to_le32(PMCRAID_IOA_RES_HANDLE); - cmd->ioa_cb->ioarcb.cdb[0] = PMCRAID_IOA_SHUTDOWN; - cmd->ioa_cb->ioarcb.cdb[1] = PMCRAID_SHUTDOWN_NORMAL; - - /* fire shutdown command to hardware. */ - pmcraid_info("firing normal shutdown command (%d) to IOA\n", - le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle)); - - pmcraid_notify_ioastate(cmd->drv_inst, PMC_DEVICE_EVENT_SHUTDOWN_START); - - pmcraid_send_cmd(cmd, pmcraid_ioa_shutdown_done, - PMCRAID_SHUTDOWN_TIMEOUT, - pmcraid_timeout_handler); -} - -/** - * pmcraid_get_fwversion_done - completion function for get_fwversion - * - * @cmd: pointer to command block used to send INQUIRY command - * - * Return Value - * none - */ -static void pmcraid_querycfg(struct pmcraid_cmd *); - -static void pmcraid_get_fwversion_done(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); - unsigned long lock_flags; - - /* configuration table entry size depends on firmware version. If fw - * version is not known, it is not possible to interpret IOA config - * table - */ - if (ioasc) { - pmcraid_err("IOA Inquiry failed with %x\n", ioasc); - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; - pmcraid_reset_alert(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - } else { - pmcraid_querycfg(cmd); - } -} - -/** - * pmcraid_get_fwversion - reads firmware version information - * - * @cmd: pointer to command block used to send INQUIRY command - * - * Return Value - * none - */ -static void pmcraid_get_fwversion(struct pmcraid_cmd *cmd) -{ - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; - struct pmcraid_instance *pinstance = cmd->drv_inst; - u16 data_size = sizeof(struct pmcraid_inquiry_data); - - pmcraid_reinit_cmdblk(cmd); - ioarcb->request_type = REQ_TYPE_SCSI; - ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); - ioarcb->cdb[0] = INQUIRY; - ioarcb->cdb[1] = 1; - ioarcb->cdb[2] = 0xD0; - ioarcb->cdb[3] = (data_size >> 8) & 0xFF; - ioarcb->cdb[4] = data_size & 0xFF; - - /* Since entire inquiry data it can be part of IOARCB itself - */ - ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + - offsetof(struct pmcraid_ioarcb, - add_data.u.ioadl[0])); - ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); - ioarcb->ioarcb_bus_addr &= ~(0x1FULL); - - ioarcb->request_flags0 |= NO_LINK_DESCS; - ioarcb->data_transfer_length = cpu_to_le32(data_size); - ioadl = &(ioarcb->add_data.u.ioadl[0]); - ioadl->flags = IOADL_FLAGS_LAST_DESC; - ioadl->address = cpu_to_le64(pinstance->inq_data_baddr); - ioadl->data_len = cpu_to_le32(data_size); - - pmcraid_send_cmd(cmd, pmcraid_get_fwversion_done, - PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); -} - -/** - * pmcraid_identify_hrrq - registers host rrq buffers with IOA - * @cmd: pointer to command block to be used for identify hrrq - * - * Return Value - * none - */ -static void pmcraid_identify_hrrq(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - int index = cmd->hrrq_index; - __be64 hrrq_addr = cpu_to_be64(pinstance->hrrq_start_bus_addr[index]); - u32 hrrq_size = cpu_to_be32(sizeof(u32) * PMCRAID_MAX_CMD); - void (*done_function)(struct pmcraid_cmd *); - - pmcraid_reinit_cmdblk(cmd); - cmd->hrrq_index = index + 1; - - if (cmd->hrrq_index < pinstance->num_hrrq) { - done_function = pmcraid_identify_hrrq; - } else { - cmd->hrrq_index = 0; - done_function = pmcraid_get_fwversion; - } - - /* Initialize ioarcb */ - ioarcb->request_type = REQ_TYPE_IOACMD; - ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); - - /* initialize the hrrq number where IOA will respond to this command */ - ioarcb->hrrq_id = index; - ioarcb->cdb[0] = PMCRAID_IDENTIFY_HRRQ; - ioarcb->cdb[1] = index; - - /* IOA expects 64-bit pci address to be written in B.E format - * (i.e cdb[2]=MSByte..cdb[9]=LSB. - */ - pmcraid_info("HRRQ_IDENTIFY with hrrq:ioarcb:index => %llx:%llx:%x\n", - hrrq_addr, ioarcb->ioarcb_bus_addr, index); - - memcpy(&(ioarcb->cdb[2]), &hrrq_addr, sizeof(hrrq_addr)); - memcpy(&(ioarcb->cdb[10]), &hrrq_size, sizeof(hrrq_size)); - - /* Subsequent commands require HRRQ identification to be successful. - * Note that this gets called even during reset from SCSI mid-layer - * or tasklet - */ - pmcraid_send_cmd(cmd, done_function, - PMCRAID_INTERNAL_TIMEOUT, - pmcraid_timeout_handler); -} - -static void pmcraid_process_ccn(struct pmcraid_cmd *cmd); -static void pmcraid_process_ldn(struct pmcraid_cmd *cmd); - -/** - * pmcraid_send_hcam_cmd - send an initialized command block(HCAM) to IOA - * - * @cmd: initialized command block pointer - * - * Return Value - * none - */ -static void pmcraid_send_hcam_cmd(struct pmcraid_cmd *cmd) -{ - if (cmd->ioa_cb->ioarcb.cdb[1] == PMCRAID_HCAM_CODE_CONFIG_CHANGE) - atomic_set(&(cmd->drv_inst->ccn.ignore), 0); - else - atomic_set(&(cmd->drv_inst->ldn.ignore), 0); - - pmcraid_send_cmd(cmd, cmd->cmd_done, 0, NULL); -} - -/** - * pmcraid_init_hcam - send an initialized command block(HCAM) to IOA - * - * @pinstance: pointer to adapter instance structure - * @type: HCAM type - * - * Return Value - * pointer to initialized pmcraid_cmd structure or NULL - */ -static struct pmcraid_cmd *pmcraid_init_hcam -( - struct pmcraid_instance *pinstance, - u8 type -) -{ - struct pmcraid_cmd *cmd; - struct pmcraid_ioarcb *ioarcb; - struct pmcraid_ioadl_desc *ioadl; - struct pmcraid_hostrcb *hcam; - void (*cmd_done) (struct pmcraid_cmd *); - dma_addr_t dma; - int rcb_size; - - cmd = pmcraid_get_free_cmd(pinstance); - - if (!cmd) { - pmcraid_err("no free command blocks for hcam\n"); - return cmd; - } - - if (type == PMCRAID_HCAM_CODE_CONFIG_CHANGE) { - rcb_size = sizeof(struct pmcraid_hcam_ccn_ext); - cmd_done = pmcraid_process_ccn; - dma = pinstance->ccn.baddr + PMCRAID_AEN_HDR_SIZE; - hcam = &pinstance->ccn; - } else { - rcb_size = sizeof(struct pmcraid_hcam_ldn); - cmd_done = pmcraid_process_ldn; - dma = pinstance->ldn.baddr + PMCRAID_AEN_HDR_SIZE; - hcam = &pinstance->ldn; - } - - /* initialize command pointer used for HCAM registration */ - hcam->cmd = cmd; - - ioarcb = &cmd->ioa_cb->ioarcb; - ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + - offsetof(struct pmcraid_ioarcb, - add_data.u.ioadl[0])); - ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); - ioadl = ioarcb->add_data.u.ioadl; - - /* Initialize ioarcb */ - ioarcb->request_type = REQ_TYPE_HCAM; - ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); - ioarcb->cdb[0] = PMCRAID_HOST_CONTROLLED_ASYNC; - ioarcb->cdb[1] = type; - ioarcb->cdb[7] = (rcb_size >> 8) & 0xFF; - ioarcb->cdb[8] = (rcb_size) & 0xFF; - - ioarcb->data_transfer_length = cpu_to_le32(rcb_size); - - ioadl[0].flags |= IOADL_FLAGS_READ_LAST; - ioadl[0].data_len = cpu_to_le32(rcb_size); - ioadl[0].address = cpu_to_le32(dma); - - cmd->cmd_done = cmd_done; - return cmd; -} - -/** - * pmcraid_send_hcam - Send an HCAM to IOA - * @pinstance: ioa config struct - * @type: HCAM type - * - * This function will send a Host Controlled Async command to IOA. - * - * Return value: - * none - */ -static void pmcraid_send_hcam(struct pmcraid_instance *pinstance, u8 type) -{ - struct pmcraid_cmd *cmd = pmcraid_init_hcam(pinstance, type); - pmcraid_send_hcam_cmd(cmd); -} - - -/** - * pmcraid_prepare_cancel_cmd - prepares a command block to abort another - * - * @cmd: pointer to cmd that is used as cancelling command - * @cmd_to_cancel: pointer to the command that needs to be cancelled - */ -static void pmcraid_prepare_cancel_cmd( - struct pmcraid_cmd *cmd, - struct pmcraid_cmd *cmd_to_cancel -) -{ - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - __be64 ioarcb_addr = cmd_to_cancel->ioa_cb->ioarcb.ioarcb_bus_addr; - - /* Get the resource handle to where the command to be aborted has been - * sent. - */ - ioarcb->resource_handle = cmd_to_cancel->ioa_cb->ioarcb.resource_handle; - ioarcb->request_type = REQ_TYPE_IOACMD; - memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); - ioarcb->cdb[0] = PMCRAID_ABORT_CMD; - - /* IOARCB address of the command to be cancelled is given in - * cdb[2]..cdb[9] is Big-Endian format. Note that length bits in - * IOARCB address are not masked. - */ - ioarcb_addr = cpu_to_be64(ioarcb_addr); - memcpy(&(ioarcb->cdb[2]), &ioarcb_addr, sizeof(ioarcb_addr)); -} - -/** - * pmcraid_cancel_hcam - sends ABORT task to abort a given HCAM - * - * @cmd: command to be used as cancelling command - * @type: HCAM type - * @cmd_done: op done function for the cancelling command - */ -static void pmcraid_cancel_hcam( - struct pmcraid_cmd *cmd, - u8 type, - void (*cmd_done) (struct pmcraid_cmd *) -) -{ - struct pmcraid_instance *pinstance; - struct pmcraid_hostrcb *hcam; - - pinstance = cmd->drv_inst; - hcam = (type == PMCRAID_HCAM_CODE_LOG_DATA) ? - &pinstance->ldn : &pinstance->ccn; - - /* prepare for cancelling previous hcam command. If the HCAM is - * currently not pending with IOA, we would have hcam->cmd as non-null - */ - if (hcam->cmd == NULL) - return; - - pmcraid_prepare_cancel_cmd(cmd, hcam->cmd); - - /* writing to IOARRIN must be protected by host_lock, as mid-layer - * schedule queuecommand while we are doing this - */ - pmcraid_send_cmd(cmd, cmd_done, - PMCRAID_INTERNAL_TIMEOUT, - pmcraid_timeout_handler); -} - -/** - * pmcraid_cancel_ccn - cancel CCN HCAM already registered with IOA - * - * @cmd: command block to be used for cancelling the HCAM - */ -static void pmcraid_cancel_ccn(struct pmcraid_cmd *cmd) -{ - pmcraid_info("response for Cancel LDN CDB[0] = %x ioasc = %x\n", - cmd->ioa_cb->ioarcb.cdb[0], - le32_to_cpu(cmd->ioa_cb->ioasa.ioasc)); - - pmcraid_reinit_cmdblk(cmd); - - pmcraid_cancel_hcam(cmd, - PMCRAID_HCAM_CODE_CONFIG_CHANGE, - pmcraid_ioa_shutdown); -} - -/** - * pmcraid_cancel_ldn - cancel LDN HCAM already registered with IOA - * - * @cmd: command block to be used for cancelling the HCAM - */ -static void pmcraid_cancel_ldn(struct pmcraid_cmd *cmd) -{ - pmcraid_cancel_hcam(cmd, - PMCRAID_HCAM_CODE_LOG_DATA, - pmcraid_cancel_ccn); -} - -/** - * pmcraid_expose_resource - check if the resource can be exposed to OS - * - * @fw_version: firmware version code - * @cfgte: pointer to configuration table entry of the resource - * - * Return value: - * true if resource can be added to midlayer, false(0) otherwise - */ -static int pmcraid_expose_resource(u16 fw_version, - struct pmcraid_config_table_entry *cfgte) -{ - int retval = 0; - - if (cfgte->resource_type == RES_TYPE_VSET) { - if (fw_version <= PMCRAID_FW_VERSION_1) - retval = ((cfgte->unique_flags1 & 0x80) == 0); - else - retval = ((cfgte->unique_flags0 & 0x80) == 0 && - (cfgte->unique_flags1 & 0x80) == 0); - - } else if (cfgte->resource_type == RES_TYPE_GSCSI) - retval = (RES_BUS(cfgte->resource_address) != - PMCRAID_VIRTUAL_ENCL_BUS_ID); - return retval; -} - -/* attributes supported by pmcraid_event_family */ -enum { - PMCRAID_AEN_ATTR_UNSPEC, - PMCRAID_AEN_ATTR_EVENT, - __PMCRAID_AEN_ATTR_MAX, -}; -#define PMCRAID_AEN_ATTR_MAX (__PMCRAID_AEN_ATTR_MAX - 1) - -/* commands supported by pmcraid_event_family */ -enum { - PMCRAID_AEN_CMD_UNSPEC, - PMCRAID_AEN_CMD_EVENT, - __PMCRAID_AEN_CMD_MAX, -}; -#define PMCRAID_AEN_CMD_MAX (__PMCRAID_AEN_CMD_MAX - 1) - -static struct genl_family pmcraid_event_family = { - .id = GENL_ID_GENERATE, - .name = "pmcraid", - .version = 1, - .maxattr = PMCRAID_AEN_ATTR_MAX -}; - -/** - * pmcraid_netlink_init - registers pmcraid_event_family - * - * Return value: - * 0 if the pmcraid_event_family is successfully registered - * with netlink generic, non-zero otherwise - */ -static int pmcraid_netlink_init(void) -{ - int result; - - result = genl_register_family(&pmcraid_event_family); - - if (result) - return result; - - pmcraid_info("registered NETLINK GENERIC group: %d\n", - pmcraid_event_family.id); - - return result; -} - -/** - * pmcraid_netlink_release - unregisters pmcraid_event_family - * - * Return value: - * none - */ -static void pmcraid_netlink_release(void) -{ - genl_unregister_family(&pmcraid_event_family); -} - -/** - * pmcraid_notify_aen - sends event msg to user space application - * @pinstance: pointer to adapter instance structure - * @type: HCAM type - * - * Return value: - * 0 if success, error value in case of any failure. - */ -static int pmcraid_notify_aen( - struct pmcraid_instance *pinstance, - struct pmcraid_aen_msg *aen_msg, - u32 data_size -) -{ - struct sk_buff *skb; - void *msg_header; - u32 total_size, nla_genl_hdr_total_size; - int result; - - aen_msg->hostno = (pinstance->host->unique_id << 16 | - MINOR(pinstance->cdev.dev)); - aen_msg->length = data_size; - - data_size += sizeof(*aen_msg); - - total_size = nla_total_size(data_size); - /* Add GENL_HDR to total_size */ - nla_genl_hdr_total_size = - (total_size + (GENL_HDRLEN + - ((struct genl_family *)&pmcraid_event_family)->hdrsize) - + NLMSG_HDRLEN); - skb = genlmsg_new(nla_genl_hdr_total_size, GFP_ATOMIC); - - - if (!skb) { - pmcraid_err("Failed to allocate aen data SKB of size: %x\n", - total_size); - return -ENOMEM; - } - - /* add the genetlink message header */ - msg_header = genlmsg_put(skb, 0, 0, - &pmcraid_event_family, 0, - PMCRAID_AEN_CMD_EVENT); - if (!msg_header) { - pmcraid_err("failed to copy command details\n"); - nlmsg_free(skb); - return -ENOMEM; - } - - result = nla_put(skb, PMCRAID_AEN_ATTR_EVENT, data_size, aen_msg); - - if (result) { - pmcraid_err("failed to copy AEN attribute data\n"); - nlmsg_free(skb); - return -EINVAL; - } - - /* send genetlink multicast message to notify appplications */ - result = genlmsg_end(skb, msg_header); - - if (result < 0) { - pmcraid_err("genlmsg_end failed\n"); - nlmsg_free(skb); - return result; - } - - result = - genlmsg_multicast(skb, 0, pmcraid_event_family.id, GFP_ATOMIC); - - /* If there are no listeners, genlmsg_multicast may return non-zero - * value. - */ - if (result) - pmcraid_info("error (%x) sending aen event message\n", result); - return result; -} - -/** - * pmcraid_notify_ccn - notifies about CCN event msg to user space - * @pinstance: pointer adapter instance structure - * - * Return value: - * 0 if success, error value in case of any failure - */ -static int pmcraid_notify_ccn(struct pmcraid_instance *pinstance) -{ - return pmcraid_notify_aen(pinstance, - pinstance->ccn.msg, - pinstance->ccn.hcam->data_len + - sizeof(struct pmcraid_hcam_hdr)); -} - -/** - * pmcraid_notify_ldn - notifies about CCN event msg to user space - * @pinstance: pointer adapter instance structure - * - * Return value: - * 0 if success, error value in case of any failure - */ -static int pmcraid_notify_ldn(struct pmcraid_instance *pinstance) -{ - return pmcraid_notify_aen(pinstance, - pinstance->ldn.msg, - pinstance->ldn.hcam->data_len + - sizeof(struct pmcraid_hcam_hdr)); -} - -/** - * pmcraid_notify_ioastate - sends IOA state event msg to user space - * @pinstance: pointer adapter instance structure - * @evt: controller state event to be sent - * - * Return value: - * 0 if success, error value in case of any failure - */ -static void pmcraid_notify_ioastate(struct pmcraid_instance *pinstance, u32 evt) -{ - pinstance->scn.ioa_state = evt; - pmcraid_notify_aen(pinstance, - &pinstance->scn.msg, - sizeof(u32)); -} - -/** - * pmcraid_handle_config_change - Handle a config change from the adapter - * @pinstance: pointer to per adapter instance structure - * - * Return value: - * none - */ - -static void pmcraid_handle_config_change(struct pmcraid_instance *pinstance) -{ - struct pmcraid_config_table_entry *cfg_entry; - struct pmcraid_hcam_ccn *ccn_hcam; - struct pmcraid_cmd *cmd; - struct pmcraid_cmd *cfgcmd; - struct pmcraid_resource_entry *res = NULL; - unsigned long lock_flags; - unsigned long host_lock_flags; - u32 new_entry = 1; - u32 hidden_entry = 0; - u16 fw_version; - int rc; - - ccn_hcam = (struct pmcraid_hcam_ccn *)pinstance->ccn.hcam; - cfg_entry = &ccn_hcam->cfg_entry; - fw_version = be16_to_cpu(pinstance->inq_data->fw_version); - - pmcraid_info("CCN(%x): %x timestamp: %llx type: %x lost: %x flags: %x \ - res: %x:%x:%x:%x\n", - pinstance->ccn.hcam->ilid, - pinstance->ccn.hcam->op_code, - ((pinstance->ccn.hcam->timestamp1) | - ((pinstance->ccn.hcam->timestamp2 & 0xffffffffLL) << 32)), - pinstance->ccn.hcam->notification_type, - pinstance->ccn.hcam->notification_lost, - pinstance->ccn.hcam->flags, - pinstance->host->unique_id, - RES_IS_VSET(*cfg_entry) ? PMCRAID_VSET_BUS_ID : - (RES_IS_GSCSI(*cfg_entry) ? PMCRAID_PHYS_BUS_ID : - RES_BUS(cfg_entry->resource_address)), - RES_IS_VSET(*cfg_entry) ? - (fw_version <= PMCRAID_FW_VERSION_1 ? - cfg_entry->unique_flags1 : - cfg_entry->array_id & 0xFF) : - RES_TARGET(cfg_entry->resource_address), - RES_LUN(cfg_entry->resource_address)); - - - /* If this HCAM indicates a lost notification, read the config table */ - if (pinstance->ccn.hcam->notification_lost) { - cfgcmd = pmcraid_get_free_cmd(pinstance); - if (cfgcmd) { - pmcraid_info("lost CCN, reading config table\b"); - pinstance->reinit_cfg_table = 1; - pmcraid_querycfg(cfgcmd); - } else { - pmcraid_err("lost CCN, no free cmd for querycfg\n"); - } - goto out_notify_apps; - } - - /* If this resource is not going to be added to mid-layer, just notify - * applications and return. If this notification is about hiding a VSET - * resource, check if it was exposed already. - */ - if (pinstance->ccn.hcam->notification_type == - NOTIFICATION_TYPE_ENTRY_CHANGED && - cfg_entry->resource_type == RES_TYPE_VSET) { - - if (fw_version <= PMCRAID_FW_VERSION_1) - hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; - else - hidden_entry = (cfg_entry->unique_flags1 & 0x80) != 0; - - } else if (!pmcraid_expose_resource(fw_version, cfg_entry)) { - goto out_notify_apps; - } - - spin_lock_irqsave(&pinstance->resource_lock, lock_flags); - list_for_each_entry(res, &pinstance->used_res_q, queue) { - rc = memcmp(&res->cfg_entry.resource_address, - &cfg_entry->resource_address, - sizeof(cfg_entry->resource_address)); - if (!rc) { - new_entry = 0; - break; - } - } - - if (new_entry) { - - if (hidden_entry) { - spin_unlock_irqrestore(&pinstance->resource_lock, - lock_flags); - goto out_notify_apps; - } - - /* If there are more number of resources than what driver can - * manage, do not notify the applications about the CCN. Just - * ignore this notifications and re-register the same HCAM - */ - if (list_empty(&pinstance->free_res_q)) { - spin_unlock_irqrestore(&pinstance->resource_lock, - lock_flags); - pmcraid_err("too many resources attached\n"); - spin_lock_irqsave(pinstance->host->host_lock, - host_lock_flags); - pmcraid_send_hcam(pinstance, - PMCRAID_HCAM_CODE_CONFIG_CHANGE); - spin_unlock_irqrestore(pinstance->host->host_lock, - host_lock_flags); - return; - } - - res = list_entry(pinstance->free_res_q.next, - struct pmcraid_resource_entry, queue); - - list_del(&res->queue); - res->scsi_dev = NULL; - res->reset_progress = 0; - list_add_tail(&res->queue, &pinstance->used_res_q); - } - - memcpy(&res->cfg_entry, cfg_entry, pinstance->config_table_entry_size); - - if (pinstance->ccn.hcam->notification_type == - NOTIFICATION_TYPE_ENTRY_DELETED || hidden_entry) { - if (res->scsi_dev) { - if (fw_version <= PMCRAID_FW_VERSION_1) - res->cfg_entry.unique_flags1 &= 0x7F; - else - res->cfg_entry.array_id &= 0xFF; - res->change_detected = RES_CHANGE_DEL; - res->cfg_entry.resource_handle = - PMCRAID_INVALID_RES_HANDLE; - schedule_work(&pinstance->worker_q); - } else { - /* This may be one of the non-exposed resources */ - list_move_tail(&res->queue, &pinstance->free_res_q); - } - } else if (!res->scsi_dev) { - res->change_detected = RES_CHANGE_ADD; - schedule_work(&pinstance->worker_q); - } - spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); - -out_notify_apps: - - /* Notify configuration changes to registered applications.*/ - if (!pmcraid_disable_aen) - pmcraid_notify_ccn(pinstance); - - cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); - if (cmd) - pmcraid_send_hcam_cmd(cmd); -} - -/** - * pmcraid_get_error_info - return error string for an ioasc - * @ioasc: ioasc code - * Return Value - * none - */ -static struct pmcraid_ioasc_error *pmcraid_get_error_info(u32 ioasc) -{ - int i; - for (i = 0; i < ARRAY_SIZE(pmcraid_ioasc_error_table); i++) { - if (pmcraid_ioasc_error_table[i].ioasc_code == ioasc) - return &pmcraid_ioasc_error_table[i]; - } - return NULL; -} - -/** - * pmcraid_ioasc_logger - log IOASC information based user-settings - * @ioasc: ioasc code - * @cmd: pointer to command that resulted in 'ioasc' - */ -void pmcraid_ioasc_logger(u32 ioasc, struct pmcraid_cmd *cmd) -{ - struct pmcraid_ioasc_error *error_info = pmcraid_get_error_info(ioasc); - - if (error_info == NULL || - cmd->drv_inst->current_log_level < error_info->log_level) - return; - - /* log the error string */ - pmcraid_err("cmd [%x] for resource %x failed with %x(%s)\n", - cmd->ioa_cb->ioarcb.cdb[0], - cmd->ioa_cb->ioarcb.resource_handle, - le32_to_cpu(ioasc), error_info->error_string); -} - -/** - * pmcraid_handle_error_log - Handle a config change (error log) from the IOA - * - * @pinstance: pointer to per adapter instance structure - * - * Return value: - * none - */ -static void pmcraid_handle_error_log(struct pmcraid_instance *pinstance) -{ - struct pmcraid_hcam_ldn *hcam_ldn; - u32 ioasc; - - hcam_ldn = (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; - - pmcraid_info - ("LDN(%x): %x type: %x lost: %x flags: %x overlay id: %x\n", - pinstance->ldn.hcam->ilid, - pinstance->ldn.hcam->op_code, - pinstance->ldn.hcam->notification_type, - pinstance->ldn.hcam->notification_lost, - pinstance->ldn.hcam->flags, - pinstance->ldn.hcam->overlay_id); - - /* log only the errors, no need to log informational log entries */ - if (pinstance->ldn.hcam->notification_type != - NOTIFICATION_TYPE_ERROR_LOG) - return; - - if (pinstance->ldn.hcam->notification_lost == - HOSTRCB_NOTIFICATIONS_LOST) - dev_info(&pinstance->pdev->dev, "Error notifications lost\n"); - - ioasc = le32_to_cpu(hcam_ldn->error_log.fd_ioasc); - - if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || - ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER) { - dev_info(&pinstance->pdev->dev, - "UnitAttention due to IOA Bus Reset\n"); - scsi_report_bus_reset( - pinstance->host, - RES_BUS(hcam_ldn->error_log.fd_ra)); - } - - return; -} - -/** - * pmcraid_process_ccn - Op done function for a CCN. - * @cmd: pointer to command struct - * - * This function is the op done function for a configuration - * change notification - * - * Return value: - * none - */ -static void pmcraid_process_ccn(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); - unsigned long lock_flags; - - pinstance->ccn.cmd = NULL; - pmcraid_return_cmd(cmd); - - /* If driver initiated IOA reset happened while this hcam was pending - * with IOA, or IOA bringdown sequence is in progress, no need to - * re-register the hcam - */ - if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || - atomic_read(&pinstance->ccn.ignore) == 1) { - return; - } else if (ioasc) { - dev_info(&pinstance->pdev->dev, - "Host RCB (CCN) failed with IOASC: 0x%08X\n", ioasc); - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - } else { - pmcraid_handle_config_change(pinstance); - } -} - -/** - * pmcraid_process_ldn - op done function for an LDN - * @cmd: pointer to command block - * - * Return value - * none - */ -static void pmcraid_initiate_reset(struct pmcraid_instance *); -static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd); - -static void pmcraid_process_ldn(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - struct pmcraid_hcam_ldn *ldn_hcam = - (struct pmcraid_hcam_ldn *)pinstance->ldn.hcam; - u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); - u32 fd_ioasc = le32_to_cpu(ldn_hcam->error_log.fd_ioasc); - unsigned long lock_flags; - - /* return the command block back to freepool */ - pinstance->ldn.cmd = NULL; - pmcraid_return_cmd(cmd); - - /* If driver initiated IOA reset happened while this hcam was pending - * with IOA, no need to re-register the hcam as reset engine will do it - * once reset sequence is complete - */ - if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || - atomic_read(&pinstance->ccn.ignore) == 1) { - return; - } else if (!ioasc) { - pmcraid_handle_error_log(pinstance); - if (fd_ioasc == PMCRAID_IOASC_NR_IOA_RESET_REQUIRED) { - spin_lock_irqsave(pinstance->host->host_lock, - lock_flags); - pmcraid_initiate_reset(pinstance); - spin_unlock_irqrestore(pinstance->host->host_lock, - lock_flags); - return; - } - if (fd_ioasc == PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC) { - pinstance->timestamp_error = 1; - pmcraid_set_timestamp(cmd); - } - } else { - dev_info(&pinstance->pdev->dev, - "Host RCB(LDN) failed with IOASC: 0x%08X\n", ioasc); - } - /* send netlink message for HCAM notification if enabled */ - if (!pmcraid_disable_aen) - pmcraid_notify_ldn(pinstance); - - cmd = pmcraid_init_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); - if (cmd) - pmcraid_send_hcam_cmd(cmd); -} - -/** - * pmcraid_register_hcams - register HCAMs for CCN and LDN - * - * @pinstance: pointer per adapter instance structure - * - * Return Value - * none - */ -static void pmcraid_register_hcams(struct pmcraid_instance *pinstance) -{ - pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_CONFIG_CHANGE); - pmcraid_send_hcam(pinstance, PMCRAID_HCAM_CODE_LOG_DATA); -} - -/** - * pmcraid_unregister_hcams - cancel HCAMs registered already - * @cmd: pointer to command used as part of reset sequence - */ -static void pmcraid_unregister_hcams(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - - /* During IOA bringdown, HCAM gets fired and tasklet proceeds with - * handling hcam response though it is not necessary. In order to - * prevent this, set 'ignore', so that bring-down sequence doesn't - * re-send any more hcams - */ - atomic_set(&pinstance->ccn.ignore, 1); - atomic_set(&pinstance->ldn.ignore, 1); - - /* If adapter reset was forced as part of runtime reset sequence, - * start the reset sequence. Reset will be triggered even in case - * IOA unit_check. - */ - if ((pinstance->force_ioa_reset && !pinstance->ioa_bringdown) || - pinstance->ioa_unit_check) { - pinstance->force_ioa_reset = 0; - pinstance->ioa_unit_check = 0; - pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; - pmcraid_reset_alert(cmd); - return; - } - - /* Driver tries to cancel HCAMs by sending ABORT TASK for each HCAM - * one after the other. So CCN cancellation will be triggered by - * pmcraid_cancel_ldn itself. - */ - pmcraid_cancel_ldn(cmd); -} - -/** - * pmcraid_reset_enable_ioa - re-enable IOA after a hard reset - * @pinstance: pointer to adapter instance structure - * Return Value - * 1 if TRANSITION_TO_OPERATIONAL is active, otherwise 0 - */ -static void pmcraid_reinit_buffers(struct pmcraid_instance *); - -static int pmcraid_reset_enable_ioa(struct pmcraid_instance *pinstance) -{ - u32 intrs; - - pmcraid_reinit_buffers(pinstance); - intrs = pmcraid_read_interrupts(pinstance); - - pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); - - if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { - if (!pinstance->interrupt_mode) { - iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, - pinstance->int_regs. - ioa_host_interrupt_mask_reg); - iowrite32(INTRS_TRANSITION_TO_OPERATIONAL, - pinstance->int_regs.ioa_host_interrupt_clr_reg); - } - return 1; - } else { - return 0; - } -} - -/** - * pmcraid_soft_reset - performs a soft reset and makes IOA become ready - * @cmd : pointer to reset command block - * - * Return Value - * none - */ -static void pmcraid_soft_reset(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - u32 int_reg; - u32 doorbell; - - /* There will be an interrupt when Transition to Operational bit is - * set so tasklet would execute next reset task. The timeout handler - * would re-initiate a reset - */ - cmd->cmd_done = pmcraid_ioa_reset; - cmd->timer.data = (unsigned long)cmd; - cmd->timer.expires = jiffies + - msecs_to_jiffies(PMCRAID_TRANSOP_TIMEOUT); - cmd->timer.function = (void (*)(unsigned long))pmcraid_timeout_handler; - - if (!timer_pending(&cmd->timer)) - add_timer(&cmd->timer); - - /* Enable destructive diagnostics on IOA if it is not yet in - * operational state - */ - doorbell = DOORBELL_RUNTIME_RESET | - DOORBELL_ENABLE_DESTRUCTIVE_DIAGS; - - /* Since we do RESET_ALERT and Start BIST we have to again write - * MSIX Doorbell to indicate the interrupt mode - */ - if (pinstance->interrupt_mode) { - iowrite32(DOORBELL_INTR_MODE_MSIX, - pinstance->int_regs.host_ioa_interrupt_reg); - ioread32(pinstance->int_regs.host_ioa_interrupt_reg); - } - - iowrite32(doorbell, pinstance->int_regs.host_ioa_interrupt_reg); - ioread32(pinstance->int_regs.host_ioa_interrupt_reg), - int_reg = ioread32(pinstance->int_regs.ioa_host_interrupt_reg); - - pmcraid_info("Waiting for IOA to become operational %x:%x\n", - ioread32(pinstance->int_regs.host_ioa_interrupt_reg), - int_reg); -} - -/** - * pmcraid_get_dump - retrieves IOA dump in case of Unit Check interrupt - * - * @pinstance: pointer to adapter instance structure - * - * Return Value - * none - */ -static void pmcraid_get_dump(struct pmcraid_instance *pinstance) -{ - pmcraid_info("%s is not yet implemented\n", __func__); -} - -/** - * pmcraid_fail_outstanding_cmds - Fails all outstanding ops. - * @pinstance: pointer to adapter instance structure - * - * This function fails all outstanding ops. If they are submitted to IOA - * already, it sends cancel all messages if IOA is still accepting IOARCBs, - * otherwise just completes the commands and returns the cmd blocks to free - * pool. - * - * Return value: - * none - */ -static void pmcraid_fail_outstanding_cmds(struct pmcraid_instance *pinstance) -{ - struct pmcraid_cmd *cmd, *temp; - unsigned long lock_flags; - - /* pending command list is protected by pending_pool_lock. Its - * traversal must be done as within this lock - */ - spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); - list_for_each_entry_safe(cmd, temp, &pinstance->pending_cmd_pool, - free_list) { - list_del(&cmd->free_list); - spin_unlock_irqrestore(&pinstance->pending_pool_lock, - lock_flags); - cmd->ioa_cb->ioasa.ioasc = - cpu_to_le32(PMCRAID_IOASC_IOA_WAS_RESET); - cmd->ioa_cb->ioasa.ilid = - cpu_to_be32(PMCRAID_DRIVER_ILID); - - /* In case the command timer is still running */ - del_timer(&cmd->timer); - - /* If this is an IO command, complete it by invoking scsi_done - * function. If this is one of the internal commands other - * than pmcraid_ioa_reset and HCAM commands invoke cmd_done to - * complete it - */ - if (cmd->scsi_cmd) { - - struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; - __le32 resp = cmd->ioa_cb->ioarcb.response_handle; - - scsi_cmd->result |= DID_ERROR << 16; - - scsi_dma_unmap(scsi_cmd); - pmcraid_return_cmd(cmd); - - pmcraid_info("failing(%d) CDB[0] = %x result: %x\n", - le32_to_cpu(resp) >> 2, - cmd->ioa_cb->ioarcb.cdb[0], - scsi_cmd->result); - scsi_cmd->scsi_done(scsi_cmd); - } else if (cmd->cmd_done == pmcraid_internal_done || - cmd->cmd_done == pmcraid_erp_done) { - cmd->cmd_done(cmd); - } else if (cmd->cmd_done != pmcraid_ioa_reset && - cmd->cmd_done != pmcraid_ioa_shutdown_done) { - pmcraid_return_cmd(cmd); - } - - atomic_dec(&pinstance->outstanding_cmds); - spin_lock_irqsave(&pinstance->pending_pool_lock, lock_flags); - } - - spin_unlock_irqrestore(&pinstance->pending_pool_lock, lock_flags); -} - -/** - * pmcraid_ioa_reset - Implementation of IOA reset logic - * - * @cmd: pointer to the cmd block to be used for entire reset process - * - * This function executes most of the steps required for IOA reset. This gets - * called by user threads (modprobe/insmod/rmmod) timer, tasklet and midlayer's - * 'eh_' thread. Access to variables used for controlling the reset sequence is - * synchronized using host lock. Various functions called during reset process - * would make use of a single command block, pointer to which is also stored in - * adapter instance structure. - * - * Return Value - * None - */ -static void pmcraid_ioa_reset(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - u8 reset_complete = 0; - - pinstance->ioa_reset_in_progress = 1; - - if (pinstance->reset_cmd != cmd) { - pmcraid_err("reset is called with different command block\n"); - pinstance->reset_cmd = cmd; - } - - pmcraid_info("reset_engine: state = %d, command = %p\n", - pinstance->ioa_state, cmd); - - switch (pinstance->ioa_state) { - - case IOA_STATE_DEAD: - /* If IOA is offline, whatever may be the reset reason, just - * return. callers might be waiting on the reset wait_q, wake - * up them - */ - pmcraid_err("IOA is offline no reset is possible\n"); - reset_complete = 1; - break; - - case IOA_STATE_IN_BRINGDOWN: - /* we enter here, once ioa shutdown command is processed by IOA - * Alert IOA for a possible reset. If reset alert fails, IOA - * goes through hard-reset - */ - pmcraid_disable_interrupts(pinstance, ~0); - pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; - pmcraid_reset_alert(cmd); - break; - - case IOA_STATE_UNKNOWN: - /* We may be called during probe or resume. Some pre-processing - * is required for prior to reset - */ - scsi_block_requests(pinstance->host); - - /* If asked to reset while IOA was processing responses or - * there are any error responses then IOA may require - * hard-reset. - */ - if (pinstance->ioa_hard_reset == 0) { - if (ioread32(pinstance->ioa_status) & - INTRS_TRANSITION_TO_OPERATIONAL) { - pmcraid_info("sticky bit set, bring-up\n"); - pinstance->ioa_state = IOA_STATE_IN_BRINGUP; - pmcraid_reinit_cmdblk(cmd); - pmcraid_identify_hrrq(cmd); - } else { - pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; - pmcraid_soft_reset(cmd); - } - } else { - /* Alert IOA of a possible reset and wait for critical - * operation in progress bit to reset - */ - pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; - pmcraid_reset_alert(cmd); - } - break; - - case IOA_STATE_IN_RESET_ALERT: - /* If critical operation in progress bit is reset or wait gets - * timed out, reset proceeds with starting BIST on the IOA. - * pmcraid_ioa_hard_reset keeps a count of reset attempts. If - * they are 3 or more, reset engine marks IOA dead and returns - */ - pinstance->ioa_state = IOA_STATE_IN_HARD_RESET; - pmcraid_start_bist(cmd); - break; - - case IOA_STATE_IN_HARD_RESET: - pinstance->ioa_reset_attempts++; - - /* retry reset if we haven't reached maximum allowed limit */ - if (pinstance->ioa_reset_attempts > PMCRAID_RESET_ATTEMPTS) { - pinstance->ioa_reset_attempts = 0; - pmcraid_err("IOA didn't respond marking it as dead\n"); - pinstance->ioa_state = IOA_STATE_DEAD; - - if (pinstance->ioa_bringdown) - pmcraid_notify_ioastate(pinstance, - PMC_DEVICE_EVENT_SHUTDOWN_FAILED); - else - pmcraid_notify_ioastate(pinstance, - PMC_DEVICE_EVENT_RESET_FAILED); - reset_complete = 1; - break; - } - - /* Once either bist or pci reset is done, restore PCI config - * space. If this fails, proceed with hard reset again - */ - pci_restore_state(pinstance->pdev); - - /* fail all pending commands */ - pmcraid_fail_outstanding_cmds(pinstance); - - /* check if unit check is active, if so extract dump */ - if (pinstance->ioa_unit_check) { - pmcraid_info("unit check is active\n"); - pinstance->ioa_unit_check = 0; - pmcraid_get_dump(pinstance); - pinstance->ioa_reset_attempts--; - pinstance->ioa_state = IOA_STATE_IN_RESET_ALERT; - pmcraid_reset_alert(cmd); - break; - } - - /* if the reset reason is to bring-down the ioa, we might be - * done with the reset restore pci_config_space and complete - * the reset - */ - if (pinstance->ioa_bringdown) { - pmcraid_info("bringing down the adapter\n"); - pinstance->ioa_shutdown_type = SHUTDOWN_NONE; - pinstance->ioa_bringdown = 0; - pinstance->ioa_state = IOA_STATE_UNKNOWN; - pmcraid_notify_ioastate(pinstance, - PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS); - reset_complete = 1; - } else { - /* bring-up IOA, so proceed with soft reset - * Reinitialize hrrq_buffers and their indices also - * enable interrupts after a pci_restore_state - */ - if (pmcraid_reset_enable_ioa(pinstance)) { - pinstance->ioa_state = IOA_STATE_IN_BRINGUP; - pmcraid_info("bringing up the adapter\n"); - pmcraid_reinit_cmdblk(cmd); - pmcraid_identify_hrrq(cmd); - } else { - pinstance->ioa_state = IOA_STATE_IN_SOFT_RESET; - pmcraid_soft_reset(cmd); - } - } - break; - - case IOA_STATE_IN_SOFT_RESET: - /* TRANSITION TO OPERATIONAL is on so start initialization - * sequence - */ - pmcraid_info("In softreset proceeding with bring-up\n"); - pinstance->ioa_state = IOA_STATE_IN_BRINGUP; - - /* Initialization commands start with HRRQ identification. From - * now on tasklet completes most of the commands as IOA is up - * and intrs are enabled - */ - pmcraid_identify_hrrq(cmd); - break; - - case IOA_STATE_IN_BRINGUP: - /* we are done with bringing up of IOA, change the ioa_state to - * operational and wake up any waiters - */ - pinstance->ioa_state = IOA_STATE_OPERATIONAL; - reset_complete = 1; - break; - - case IOA_STATE_OPERATIONAL: - default: - /* When IOA is operational and a reset is requested, check for - * the reset reason. If reset is to bring down IOA, unregister - * HCAMs and initiate shutdown; if adapter reset is forced then - * restart reset sequence again - */ - if (pinstance->ioa_shutdown_type == SHUTDOWN_NONE && - pinstance->force_ioa_reset == 0) { - pmcraid_notify_ioastate(pinstance, - PMC_DEVICE_EVENT_RESET_SUCCESS); - reset_complete = 1; - } else { - if (pinstance->ioa_shutdown_type != SHUTDOWN_NONE) - pinstance->ioa_state = IOA_STATE_IN_BRINGDOWN; - pmcraid_reinit_cmdblk(cmd); - pmcraid_unregister_hcams(cmd); - } - break; - } - - /* reset will be completed if ioa_state is either DEAD or UNKNOWN or - * OPERATIONAL. Reset all control variables used during reset, wake up - * any waiting threads and let the SCSI mid-layer send commands. Note - * that host_lock must be held before invoking scsi_report_bus_reset. - */ - if (reset_complete) { - pinstance->ioa_reset_in_progress = 0; - pinstance->ioa_reset_attempts = 0; - pinstance->reset_cmd = NULL; - pinstance->ioa_shutdown_type = SHUTDOWN_NONE; - pinstance->ioa_bringdown = 0; - pmcraid_return_cmd(cmd); - - /* If target state is to bring up the adapter, proceed with - * hcam registration and resource exposure to mid-layer. - */ - if (pinstance->ioa_state == IOA_STATE_OPERATIONAL) - pmcraid_register_hcams(pinstance); - - wake_up_all(&pinstance->reset_wait_q); - } - - return; -} - -/** - * pmcraid_initiate_reset - initiates reset sequence. This is called from - * ISR/tasklet during error interrupts including IOA unit check. If reset - * is already in progress, it just returns, otherwise initiates IOA reset - * to bring IOA up to operational state. - * - * @pinstance: pointer to adapter instance structure - * - * Return value - * none - */ -static void pmcraid_initiate_reset(struct pmcraid_instance *pinstance) -{ - struct pmcraid_cmd *cmd; - - /* If the reset is already in progress, just return, otherwise start - * reset sequence and return - */ - if (!pinstance->ioa_reset_in_progress) { - scsi_block_requests(pinstance->host); - cmd = pmcraid_get_free_cmd(pinstance); - - if (cmd == NULL) { - pmcraid_err("no cmnd blocks for initiate_reset\n"); - return; - } - - pinstance->ioa_shutdown_type = SHUTDOWN_NONE; - pinstance->reset_cmd = cmd; - pinstance->force_ioa_reset = 1; - pmcraid_notify_ioastate(pinstance, - PMC_DEVICE_EVENT_RESET_START); - pmcraid_ioa_reset(cmd); - } -} - -/** - * pmcraid_reset_reload - utility routine for doing IOA reset either to bringup - * or bringdown IOA - * @pinstance: pointer adapter instance structure - * @shutdown_type: shutdown type to be used NONE, NORMAL or ABRREV - * @target_state: expected target state after reset - * - * Note: This command initiates reset and waits for its completion. Hence this - * should not be called from isr/timer/tasklet functions (timeout handlers, - * error response handlers and interrupt handlers). - * - * Return Value - * 1 in case ioa_state is not target_state, 0 otherwise. - */ -static int pmcraid_reset_reload( - struct pmcraid_instance *pinstance, - u8 shutdown_type, - u8 target_state -) -{ - struct pmcraid_cmd *reset_cmd = NULL; - unsigned long lock_flags; - int reset = 1; - - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - - if (pinstance->ioa_reset_in_progress) { - pmcraid_info("reset_reload: reset is already in progress\n"); - - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - - wait_event(pinstance->reset_wait_q, - !pinstance->ioa_reset_in_progress); - - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - - if (pinstance->ioa_state == IOA_STATE_DEAD) { - spin_unlock_irqrestore(pinstance->host->host_lock, - lock_flags); - pmcraid_info("reset_reload: IOA is dead\n"); - return reset; - } else if (pinstance->ioa_state == target_state) { - reset = 0; - } - } - - if (reset) { - pmcraid_info("reset_reload: proceeding with reset\n"); - scsi_block_requests(pinstance->host); - reset_cmd = pmcraid_get_free_cmd(pinstance); - - if (reset_cmd == NULL) { - pmcraid_err("no free cmnd for reset_reload\n"); - spin_unlock_irqrestore(pinstance->host->host_lock, - lock_flags); - return reset; - } - - if (shutdown_type == SHUTDOWN_NORMAL) - pinstance->ioa_bringdown = 1; - - pinstance->ioa_shutdown_type = shutdown_type; - pinstance->reset_cmd = reset_cmd; - pinstance->force_ioa_reset = reset; - pmcraid_info("reset_reload: initiating reset\n"); - pmcraid_ioa_reset(reset_cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - pmcraid_info("reset_reload: waiting for reset to complete\n"); - wait_event(pinstance->reset_wait_q, - !pinstance->ioa_reset_in_progress); - - pmcraid_info("reset_reload: reset is complete !!\n"); - scsi_unblock_requests(pinstance->host); - if (pinstance->ioa_state == target_state) - reset = 0; - } - - return reset; -} - -/** - * pmcraid_reset_bringdown - wrapper over pmcraid_reset_reload to bringdown IOA - * - * @pinstance: pointer to adapter instance structure - * - * Return Value - * whatever is returned from pmcraid_reset_reload - */ -static int pmcraid_reset_bringdown(struct pmcraid_instance *pinstance) -{ - return pmcraid_reset_reload(pinstance, - SHUTDOWN_NORMAL, - IOA_STATE_UNKNOWN); -} - -/** - * pmcraid_reset_bringup - wrapper over pmcraid_reset_reload to bring up IOA - * - * @pinstance: pointer to adapter instance structure - * - * Return Value - * whatever is returned from pmcraid_reset_reload - */ -static int pmcraid_reset_bringup(struct pmcraid_instance *pinstance) -{ - pmcraid_notify_ioastate(pinstance, PMC_DEVICE_EVENT_RESET_START); - - return pmcraid_reset_reload(pinstance, - SHUTDOWN_NONE, - IOA_STATE_OPERATIONAL); -} - -/** - * pmcraid_request_sense - Send request sense to a device - * @cmd: pmcraid command struct - * - * This function sends a request sense to a device as a result of a check - * condition. This method re-uses the same command block that failed earlier. - */ -static void pmcraid_request_sense(struct pmcraid_cmd *cmd) -{ - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; - - /* allocate DMAable memory for sense buffers */ - cmd->sense_buffer = pci_alloc_consistent(cmd->drv_inst->pdev, - SCSI_SENSE_BUFFERSIZE, - &cmd->sense_buffer_dma); - - if (cmd->sense_buffer == NULL) { - pmcraid_err - ("couldn't allocate sense buffer for request sense\n"); - pmcraid_erp_done(cmd); - return; - } - - /* re-use the command block */ - memset(&cmd->ioa_cb->ioasa, 0, sizeof(struct pmcraid_ioasa)); - memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); - ioarcb->request_flags0 = (SYNC_COMPLETE | - NO_LINK_DESCS | - INHIBIT_UL_CHECK); - ioarcb->request_type = REQ_TYPE_SCSI; - ioarcb->cdb[0] = REQUEST_SENSE; - ioarcb->cdb[4] = SCSI_SENSE_BUFFERSIZE; - - ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + - offsetof(struct pmcraid_ioarcb, - add_data.u.ioadl[0])); - ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); - - ioarcb->data_transfer_length = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); - - ioadl->address = cpu_to_le64(cmd->sense_buffer_dma); - ioadl->data_len = cpu_to_le32(SCSI_SENSE_BUFFERSIZE); - ioadl->flags = IOADL_FLAGS_LAST_DESC; - - /* request sense might be called as part of error response processing - * which runs in tasklets context. It is possible that mid-layer might - * schedule queuecommand during this time, hence, writting to IOARRIN - * must be protect by host_lock - */ - pmcraid_send_cmd(cmd, pmcraid_erp_done, - PMCRAID_REQUEST_SENSE_TIMEOUT, - pmcraid_timeout_handler); -} - -/** - * pmcraid_cancel_all - cancel all outstanding IOARCBs as part of error recovery - * @cmd: command that failed - * @sense: true if request_sense is required after cancel all - * - * This function sends a cancel all to a device to clear the queue. - */ -static void pmcraid_cancel_all(struct pmcraid_cmd *cmd, u32 sense) -{ - struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; - void (*cmd_done) (struct pmcraid_cmd *) = sense ? pmcraid_erp_done - : pmcraid_request_sense; - - memset(ioarcb->cdb, 0, PMCRAID_MAX_CDB_LEN); - ioarcb->request_flags0 = SYNC_OVERRIDE; - ioarcb->request_type = REQ_TYPE_IOACMD; - ioarcb->cdb[0] = PMCRAID_CANCEL_ALL_REQUESTS; - - if (RES_IS_GSCSI(res->cfg_entry)) - ioarcb->cdb[1] = PMCRAID_SYNC_COMPLETE_AFTER_CANCEL; - - ioarcb->ioadl_bus_addr = 0; - ioarcb->ioadl_length = 0; - ioarcb->data_transfer_length = 0; - ioarcb->ioarcb_bus_addr &= (~0x1FULL); - - /* writing to IOARRIN must be protected by host_lock, as mid-layer - * schedule queuecommand while we are doing this - */ - pmcraid_send_cmd(cmd, cmd_done, - PMCRAID_REQUEST_SENSE_TIMEOUT, - pmcraid_timeout_handler); -} - -/** - * pmcraid_frame_auto_sense: frame fixed format sense information - * - * @cmd: pointer to failing command block - * - * Return value - * none - */ -static void pmcraid_frame_auto_sense(struct pmcraid_cmd *cmd) -{ - u8 *sense_buf = cmd->scsi_cmd->sense_buffer; - struct pmcraid_resource_entry *res = cmd->scsi_cmd->device->hostdata; - struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; - u32 ioasc = le32_to_cpu(ioasa->ioasc); - u32 failing_lba = 0; - - memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE); - cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION; - - if (RES_IS_VSET(res->cfg_entry) && - ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC && - ioasa->u.vset.failing_lba_hi != 0) { - - sense_buf[0] = 0x72; - sense_buf[1] = PMCRAID_IOASC_SENSE_KEY(ioasc); - sense_buf[2] = PMCRAID_IOASC_SENSE_CODE(ioasc); - sense_buf[3] = PMCRAID_IOASC_SENSE_QUAL(ioasc); - - sense_buf[7] = 12; - sense_buf[8] = 0; - sense_buf[9] = 0x0A; - sense_buf[10] = 0x80; - - failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_hi); - - sense_buf[12] = (failing_lba & 0xff000000) >> 24; - sense_buf[13] = (failing_lba & 0x00ff0000) >> 16; - sense_buf[14] = (failing_lba & 0x0000ff00) >> 8; - sense_buf[15] = failing_lba & 0x000000ff; - - failing_lba = le32_to_cpu(ioasa->u.vset.failing_lba_lo); - - sense_buf[16] = (failing_lba & 0xff000000) >> 24; - sense_buf[17] = (failing_lba & 0x00ff0000) >> 16; - sense_buf[18] = (failing_lba & 0x0000ff00) >> 8; - sense_buf[19] = failing_lba & 0x000000ff; - } else { - sense_buf[0] = 0x70; - sense_buf[2] = PMCRAID_IOASC_SENSE_KEY(ioasc); - sense_buf[12] = PMCRAID_IOASC_SENSE_CODE(ioasc); - sense_buf[13] = PMCRAID_IOASC_SENSE_QUAL(ioasc); - - if (ioasc == PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC) { - if (RES_IS_VSET(res->cfg_entry)) - failing_lba = - le32_to_cpu(ioasa->u. - vset.failing_lba_lo); - sense_buf[0] |= 0x80; - sense_buf[3] = (failing_lba >> 24) & 0xff; - sense_buf[4] = (failing_lba >> 16) & 0xff; - sense_buf[5] = (failing_lba >> 8) & 0xff; - sense_buf[6] = failing_lba & 0xff; - } - - sense_buf[7] = 6; /* additional length */ - } -} - -/** - * pmcraid_error_handler - Error response handlers for a SCSI op - * @cmd: pointer to pmcraid_cmd that has failed - * - * This function determines whether or not to initiate ERP on the affected - * device. This is called from a tasklet, which doesn't hold any locks. - * - * Return value: - * 0 it caller can complete the request, otherwise 1 where in error - * handler itself completes the request and returns the command block - * back to free-pool - */ -static int pmcraid_error_handler(struct pmcraid_cmd *cmd) -{ - struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; - struct pmcraid_resource_entry *res = scsi_cmd->device->hostdata; - struct pmcraid_instance *pinstance = cmd->drv_inst; - struct pmcraid_ioasa *ioasa = &cmd->ioa_cb->ioasa; - u32 ioasc = le32_to_cpu(ioasa->ioasc); - u32 masked_ioasc = ioasc & PMCRAID_IOASC_SENSE_MASK; - u32 sense_copied = 0; - - if (!res) { - pmcraid_info("resource pointer is NULL\n"); - return 0; - } - - /* If this was a SCSI read/write command keep count of errors */ - if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_READ_CMD) - atomic_inc(&res->read_failures); - else if (SCSI_CMD_TYPE(scsi_cmd->cmnd[0]) == SCSI_WRITE_CMD) - atomic_inc(&res->write_failures); - - if (!RES_IS_GSCSI(res->cfg_entry) && - masked_ioasc != PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR) { - pmcraid_frame_auto_sense(cmd); - } - - /* Log IOASC/IOASA information based on user settings */ - pmcraid_ioasc_logger(ioasc, cmd); - - switch (masked_ioasc) { - - case PMCRAID_IOASC_AC_TERMINATED_BY_HOST: - scsi_cmd->result |= (DID_ABORT << 16); - break; - - case PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE: - case PMCRAID_IOASC_HW_CANNOT_COMMUNICATE: - scsi_cmd->result |= (DID_NO_CONNECT << 16); - break; - - case PMCRAID_IOASC_NR_SYNC_REQUIRED: - res->sync_reqd = 1; - scsi_cmd->result |= (DID_IMM_RETRY << 16); - break; - - case PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC: - scsi_cmd->result |= (DID_PASSTHROUGH << 16); - break; - - case PMCRAID_IOASC_UA_BUS_WAS_RESET: - case PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER: - if (!res->reset_progress) - scsi_report_bus_reset(pinstance->host, - scsi_cmd->device->channel); - scsi_cmd->result |= (DID_ERROR << 16); - break; - - case PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR: - scsi_cmd->result |= PMCRAID_IOASC_SENSE_STATUS(ioasc); - res->sync_reqd = 1; - - /* if check_condition is not active return with error otherwise - * get/frame the sense buffer - */ - if (PMCRAID_IOASC_SENSE_STATUS(ioasc) != - SAM_STAT_CHECK_CONDITION && - PMCRAID_IOASC_SENSE_STATUS(ioasc) != SAM_STAT_ACA_ACTIVE) - return 0; - - /* If we have auto sense data as part of IOASA pass it to - * mid-layer - */ - if (ioasa->auto_sense_length != 0) { - short sense_len = ioasa->auto_sense_length; - int data_size = min_t(u16, le16_to_cpu(sense_len), - SCSI_SENSE_BUFFERSIZE); - - memcpy(scsi_cmd->sense_buffer, - ioasa->sense_data, - data_size); - sense_copied = 1; - } - - if (RES_IS_GSCSI(res->cfg_entry)) - pmcraid_cancel_all(cmd, sense_copied); - else if (sense_copied) - pmcraid_erp_done(cmd); - else - pmcraid_request_sense(cmd); - - return 1; - - case PMCRAID_IOASC_NR_INIT_CMD_REQUIRED: - break; - - default: - if (PMCRAID_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR) - scsi_cmd->result |= (DID_ERROR << 16); - break; - } - return 0; -} - -/** - * pmcraid_reset_device - device reset handler functions - * - * @scsi_cmd: scsi command struct - * @modifier: reset modifier indicating the reset sequence to be performed - * - * This function issues a device reset to the affected device. - * A LUN reset will be sent to the device first. If that does - * not work, a target reset will be sent. - * - * Return value: - * SUCCESS / FAILED - */ -static int pmcraid_reset_device( - struct scsi_cmnd *scsi_cmd, - unsigned long timeout, - u8 modifier -) -{ - struct pmcraid_cmd *cmd; - struct pmcraid_instance *pinstance; - struct pmcraid_resource_entry *res; - struct pmcraid_ioarcb *ioarcb; - unsigned long lock_flags; - u32 ioasc; - - pinstance = - (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; - res = scsi_cmd->device->hostdata; - - if (!res) { - sdev_printk(KERN_ERR, scsi_cmd->device, - "reset_device: NULL resource pointer\n"); - return FAILED; - } - - /* If adapter is currently going through reset/reload, return failed. - * This will force the mid-layer to call _eh_bus/host reset, which - * will then go to sleep and wait for the reset to complete - */ - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - if (pinstance->ioa_reset_in_progress || - pinstance->ioa_state == IOA_STATE_DEAD) { - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - return FAILED; - } - - res->reset_progress = 1; - pmcraid_info("Resetting %s resource with addr %x\n", - ((modifier & RESET_DEVICE_LUN) ? "LUN" : - ((modifier & RESET_DEVICE_TARGET) ? "TARGET" : "BUS")), - le32_to_cpu(res->cfg_entry.resource_address)); - - /* get a free cmd block */ - cmd = pmcraid_get_free_cmd(pinstance); - - if (cmd == NULL) { - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - pmcraid_err("%s: no cmd blocks are available\n", __func__); - return FAILED; - } - - ioarcb = &cmd->ioa_cb->ioarcb; - ioarcb->resource_handle = res->cfg_entry.resource_handle; - ioarcb->request_type = REQ_TYPE_IOACMD; - ioarcb->cdb[0] = PMCRAID_RESET_DEVICE; - - /* Initialize reset modifier bits */ - if (modifier) - modifier = ENABLE_RESET_MODIFIER | modifier; - - ioarcb->cdb[1] = modifier; - - init_completion(&cmd->wait_for_completion); - cmd->completion_req = 1; - - pmcraid_info("cmd(CDB[0] = %x) for %x with index = %d\n", - cmd->ioa_cb->ioarcb.cdb[0], - le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle), - le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2); - - pmcraid_send_cmd(cmd, - pmcraid_internal_done, - timeout, - pmcraid_timeout_handler); - - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - - /* RESET_DEVICE command completes after all pending IOARCBs are - * completed. Once this command is completed, pmcraind_internal_done - * will wake up the 'completion' queue. - */ - wait_for_completion(&cmd->wait_for_completion); - - /* complete the command here itself and return the command block - * to free list - */ - pmcraid_return_cmd(cmd); - res->reset_progress = 0; - ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); - - /* set the return value based on the returned ioasc */ - return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; -} - -/** - * _pmcraid_io_done - helper for pmcraid_io_done function - * - * @cmd: pointer to pmcraid command struct - * @reslen: residual data length to be set in the ioasa - * @ioasc: ioasc either returned by IOA or set by driver itself. - * - * This function is invoked by pmcraid_io_done to complete mid-layer - * scsi ops. - * - * Return value: - * 0 if caller is required to return it to free_pool. Returns 1 if - * caller need not worry about freeing command block as error handler - * will take care of that. - */ - -static int _pmcraid_io_done(struct pmcraid_cmd *cmd, int reslen, int ioasc) -{ - struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; - int rc = 0; - - scsi_set_resid(scsi_cmd, reslen); - - pmcraid_info("response(%d) CDB[0] = %x ioasc:result: %x:%x\n", - le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, - cmd->ioa_cb->ioarcb.cdb[0], - ioasc, scsi_cmd->result); - - if (PMCRAID_IOASC_SENSE_KEY(ioasc) != 0) - rc = pmcraid_error_handler(cmd); - - if (rc == 0) { - scsi_dma_unmap(scsi_cmd); - scsi_cmd->scsi_done(scsi_cmd); - } - - return rc; -} - -/** - * pmcraid_io_done - SCSI completion function - * - * @cmd: pointer to pmcraid command struct - * - * This function is invoked by tasklet/mid-layer error handler to completing - * the SCSI ops sent from mid-layer. - * - * Return value - * none - */ - -static void pmcraid_io_done(struct pmcraid_cmd *cmd) -{ - u32 ioasc = le32_to_cpu(cmd->ioa_cb->ioasa.ioasc); - u32 reslen = le32_to_cpu(cmd->ioa_cb->ioasa.residual_data_length); - - if (_pmcraid_io_done(cmd, reslen, ioasc) == 0) - pmcraid_return_cmd(cmd); -} - -/** - * pmcraid_abort_cmd - Aborts a single IOARCB already submitted to IOA - * - * @cmd: command block of the command to be aborted - * - * Return Value: - * returns pointer to command structure used as cancelling cmd - */ -static struct pmcraid_cmd *pmcraid_abort_cmd(struct pmcraid_cmd *cmd) -{ - struct pmcraid_cmd *cancel_cmd; - struct pmcraid_instance *pinstance; - struct pmcraid_resource_entry *res; - - pinstance = (struct pmcraid_instance *)cmd->drv_inst; - res = cmd->scsi_cmd->device->hostdata; - - cancel_cmd = pmcraid_get_free_cmd(pinstance); - - if (cancel_cmd == NULL) { - pmcraid_err("%s: no cmd blocks are available\n", __func__); - return NULL; - } - - pmcraid_prepare_cancel_cmd(cancel_cmd, cmd); - - pmcraid_info("aborting command CDB[0]= %x with index = %d\n", - cmd->ioa_cb->ioarcb.cdb[0], - cmd->ioa_cb->ioarcb.response_handle >> 2); - - init_completion(&cancel_cmd->wait_for_completion); - cancel_cmd->completion_req = 1; - - pmcraid_info("command (%d) CDB[0] = %x for %x\n", - le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.response_handle) >> 2, - cancel_cmd->ioa_cb->ioarcb.cdb[0], - le32_to_cpu(cancel_cmd->ioa_cb->ioarcb.resource_handle)); - - pmcraid_send_cmd(cancel_cmd, - pmcraid_internal_done, - PMCRAID_INTERNAL_TIMEOUT, - pmcraid_timeout_handler); - return cancel_cmd; -} - -/** - * pmcraid_abort_complete - Waits for ABORT TASK completion - * - * @cancel_cmd: command block use as cancelling command - * - * Return Value: - * returns SUCCESS if ABORT TASK has good completion - * otherwise FAILED - */ -static int pmcraid_abort_complete(struct pmcraid_cmd *cancel_cmd) -{ - struct pmcraid_resource_entry *res; - u32 ioasc; - - wait_for_completion(&cancel_cmd->wait_for_completion); - res = cancel_cmd->res; - cancel_cmd->res = NULL; - ioasc = le32_to_cpu(cancel_cmd->ioa_cb->ioasa.ioasc); - - /* If the abort task is not timed out we will get a Good completion - * as sense_key, otherwise we may get one the following responses - * due to subsequent bus reset or device reset. In case IOASC is - * NR_SYNC_REQUIRED, set sync_reqd flag for the corresponding resource - */ - if (ioasc == PMCRAID_IOASC_UA_BUS_WAS_RESET || - ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) { - if (ioasc == PMCRAID_IOASC_NR_SYNC_REQUIRED) - res->sync_reqd = 1; - ioasc = 0; - } - - /* complete the command here itself */ - pmcraid_return_cmd(cancel_cmd); - return PMCRAID_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS; -} - -/** - * pmcraid_eh_abort_handler - entry point for aborting a single task on errors - * - * @scsi_cmd: scsi command struct given by mid-layer. When this is called - * mid-layer ensures that no other commands are queued. This - * never gets called under interrupt, but a separate eh thread. - * - * Return value: - * SUCCESS / FAILED - */ -static int pmcraid_eh_abort_handler(struct scsi_cmnd *scsi_cmd) -{ - struct pmcraid_instance *pinstance; - struct pmcraid_cmd *cmd; - struct pmcraid_resource_entry *res; - unsigned long host_lock_flags; - unsigned long pending_lock_flags; - struct pmcraid_cmd *cancel_cmd = NULL; - int cmd_found = 0; - int rc = FAILED; - - pinstance = - (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; - - scmd_printk(KERN_INFO, scsi_cmd, - "I/O command timed out, aborting it.\n"); - - res = scsi_cmd->device->hostdata; - - if (res == NULL) - return rc; - - /* If we are currently going through reset/reload, return failed. - * This will force the mid-layer to eventually call - * pmcraid_eh_host_reset which will then go to sleep and wait for the - * reset to complete - */ - spin_lock_irqsave(pinstance->host->host_lock, host_lock_flags); - - if (pinstance->ioa_reset_in_progress || - pinstance->ioa_state == IOA_STATE_DEAD) { - spin_unlock_irqrestore(pinstance->host->host_lock, - host_lock_flags); - return rc; - } - - /* loop over pending cmd list to find cmd corresponding to this - * scsi_cmd. Note that this command might not have been completed - * already. locking: all pending commands are protected with - * pending_pool_lock. - */ - spin_lock_irqsave(&pinstance->pending_pool_lock, pending_lock_flags); - list_for_each_entry(cmd, &pinstance->pending_cmd_pool, free_list) { - - if (cmd->scsi_cmd == scsi_cmd) { - cmd_found = 1; - break; - } - } - - spin_unlock_irqrestore(&pinstance->pending_pool_lock, - pending_lock_flags); - - /* If the command to be aborted was given to IOA and still pending with - * it, send ABORT_TASK to abort this and wait for its completion - */ - if (cmd_found) - cancel_cmd = pmcraid_abort_cmd(cmd); - - spin_unlock_irqrestore(pinstance->host->host_lock, - host_lock_flags); - - if (cancel_cmd) { - cancel_cmd->res = cmd->scsi_cmd->device->hostdata; - rc = pmcraid_abort_complete(cancel_cmd); - } - - return cmd_found ? rc : SUCCESS; -} - -/** - * pmcraid_eh_xxxx_reset_handler - bus/target/device reset handler callbacks - * - * @scmd: pointer to scsi_cmd that was sent to the resource to be reset. - * - * All these routines invokve pmcraid_reset_device with appropriate parameters. - * Since these are called from mid-layer EH thread, no other IO will be queued - * to the resource being reset. However, control path (IOCTL) may be active so - * it is necessary to synchronize IOARRIN writes which pmcraid_reset_device - * takes care by locking/unlocking host_lock. - * - * Return value - * SUCCESS or FAILED - */ -static int pmcraid_eh_device_reset_handler(struct scsi_cmnd *scmd) -{ - scmd_printk(KERN_INFO, scmd, - "resetting device due to an I/O command timeout.\n"); - return pmcraid_reset_device(scmd, - PMCRAID_INTERNAL_TIMEOUT, - RESET_DEVICE_LUN); -} - -static int pmcraid_eh_bus_reset_handler(struct scsi_cmnd *scmd) -{ - scmd_printk(KERN_INFO, scmd, - "Doing bus reset due to an I/O command timeout.\n"); - return pmcraid_reset_device(scmd, - PMCRAID_RESET_BUS_TIMEOUT, - RESET_DEVICE_BUS); -} - -static int pmcraid_eh_target_reset_handler(struct scsi_cmnd *scmd) -{ - scmd_printk(KERN_INFO, scmd, - "Doing target reset due to an I/O command timeout.\n"); - return pmcraid_reset_device(scmd, - PMCRAID_INTERNAL_TIMEOUT, - RESET_DEVICE_TARGET); -} - -/** - * pmcraid_eh_host_reset_handler - adapter reset handler callback - * - * @scmd: pointer to scsi_cmd that was sent to a resource of adapter - * - * Initiates adapter reset to bring it up to operational state - * - * Return value - * SUCCESS or FAILED - */ -static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd) -{ - unsigned long interval = 10000; /* 10 seconds interval */ - int waits = jiffies_to_msecs(PMCRAID_RESET_HOST_TIMEOUT) / interval; - struct pmcraid_instance *pinstance = - (struct pmcraid_instance *)(scmd->device->host->hostdata); - - - /* wait for an additional 150 seconds just in case firmware could come - * up and if it could complete all the pending commands excluding the - * two HCAM (CCN and LDN). - */ - while (waits--) { - if (atomic_read(&pinstance->outstanding_cmds) <= - PMCRAID_MAX_HCAM_CMD) - return SUCCESS; - msleep(interval); - } - - dev_err(&pinstance->pdev->dev, - "Adapter being reset due to an I/O command timeout.\n"); - return pmcraid_reset_bringup(pinstance) == 0 ? SUCCESS : FAILED; -} - -/** - * pmcraid_task_attributes - Translate SPI Q-Tags to task attributes - * @scsi_cmd: scsi command struct - * - * Return value - * number of tags or 0 if the task is not tagged - */ -static u8 pmcraid_task_attributes(struct scsi_cmnd *scsi_cmd) -{ - char tag[2]; - u8 rc = 0; - - if (scsi_populate_tag_msg(scsi_cmd, tag)) { - switch (tag[0]) { - case MSG_SIMPLE_TAG: - rc = TASK_TAG_SIMPLE; - break; - case MSG_HEAD_TAG: - rc = TASK_TAG_QUEUE_HEAD; - break; - case MSG_ORDERED_TAG: - rc = TASK_TAG_ORDERED; - break; - }; - } - - return rc; -} - - -/** - * pmcraid_init_ioadls - initializes IOADL related fields in IOARCB - * @cmd: pmcraid command struct - * @sgcount: count of scatter-gather elements - * - * Return value - * returns pointer pmcraid_ioadl_desc, initialized to point to internal - * or external IOADLs - */ -struct pmcraid_ioadl_desc * -pmcraid_init_ioadls(struct pmcraid_cmd *cmd, int sgcount) -{ - struct pmcraid_ioadl_desc *ioadl; - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - int ioadl_count = 0; - - if (ioarcb->add_cmd_param_length) - ioadl_count = DIV_ROUND_UP(ioarcb->add_cmd_param_length, 16); - ioarcb->ioadl_length = - sizeof(struct pmcraid_ioadl_desc) * sgcount; - - if ((sgcount + ioadl_count) > (ARRAY_SIZE(ioarcb->add_data.u.ioadl))) { - /* external ioadls start at offset 0x80 from control_block - * structure, re-using 24 out of 27 ioadls part of IOARCB. - * It is necessary to indicate to firmware that driver is - * using ioadls to be treated as external to IOARCB. - */ - ioarcb->ioarcb_bus_addr &= ~(0x1FULL); - ioarcb->ioadl_bus_addr = - cpu_to_le64((cmd->ioa_cb_bus_addr) + - offsetof(struct pmcraid_ioarcb, - add_data.u.ioadl[3])); - ioadl = &ioarcb->add_data.u.ioadl[3]; - } else { - ioarcb->ioadl_bus_addr = - cpu_to_le64((cmd->ioa_cb_bus_addr) + - offsetof(struct pmcraid_ioarcb, - add_data.u.ioadl[ioadl_count])); - - ioadl = &ioarcb->add_data.u.ioadl[ioadl_count]; - ioarcb->ioarcb_bus_addr |= - DIV_ROUND_CLOSEST(sgcount + ioadl_count, 8); - } - - return ioadl; -} - -/** - * pmcraid_build_ioadl - Build a scatter/gather list and map the buffer - * @pinstance: pointer to adapter instance structure - * @cmd: pmcraid command struct - * - * This function is invoked by queuecommand entry point while sending a command - * to firmware. This builds ioadl descriptors and sets up ioarcb fields. - * - * Return value: - * 0 on success or -1 on failure - */ -static int pmcraid_build_ioadl( - struct pmcraid_instance *pinstance, - struct pmcraid_cmd *cmd -) -{ - int i, nseg; - struct scatterlist *sglist; - - struct scsi_cmnd *scsi_cmd = cmd->scsi_cmd; - struct pmcraid_ioarcb *ioarcb = &(cmd->ioa_cb->ioarcb); - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; - - u32 length = scsi_bufflen(scsi_cmd); - - if (!length) - return 0; - - nseg = scsi_dma_map(scsi_cmd); - - if (nseg < 0) { - scmd_printk(KERN_ERR, scsi_cmd, "scsi_map_dma failed!\n"); - return -1; - } else if (nseg > PMCRAID_MAX_IOADLS) { - scsi_dma_unmap(scsi_cmd); - scmd_printk(KERN_ERR, scsi_cmd, - "sg count is (%d) more than allowed!\n", nseg); - return -1; - } - - /* Initialize IOARCB data transfer length fields */ - if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) - ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; - - ioarcb->request_flags0 |= NO_LINK_DESCS; - ioarcb->data_transfer_length = cpu_to_le32(length); - ioadl = pmcraid_init_ioadls(cmd, nseg); - - /* Initialize IOADL descriptor addresses */ - scsi_for_each_sg(scsi_cmd, sglist, nseg, i) { - ioadl[i].data_len = cpu_to_le32(sg_dma_len(sglist)); - ioadl[i].address = cpu_to_le64(sg_dma_address(sglist)); - ioadl[i].flags = 0; - } - /* setup last descriptor */ - ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; - - return 0; -} - -/** - * pmcraid_free_sglist - Frees an allocated SG buffer list - * @sglist: scatter/gather list pointer - * - * Free a DMA'able memory previously allocated with pmcraid_alloc_sglist - * - * Return value: - * none - */ -static void pmcraid_free_sglist(struct pmcraid_sglist *sglist) -{ - int i; - - for (i = 0; i < sglist->num_sg; i++) - __free_pages(sg_page(&(sglist->scatterlist[i])), - sglist->order); - - kfree(sglist); -} - -/** - * pmcraid_alloc_sglist - Allocates memory for a SG list - * @buflen: buffer length - * - * Allocates a DMA'able buffer in chunks and assembles a scatter/gather - * list. - * - * Return value - * pointer to sglist / NULL on failure - */ -static struct pmcraid_sglist *pmcraid_alloc_sglist(int buflen) -{ - struct pmcraid_sglist *sglist; - struct scatterlist *scatterlist; - struct page *page; - int num_elem, i, j; - int sg_size; - int order; - int bsize_elem; - - sg_size = buflen / (PMCRAID_MAX_IOADLS - 1); - order = (sg_size > 0) ? get_order(sg_size) : 0; - bsize_elem = PAGE_SIZE * (1 << order); - - /* Determine the actual number of sg entries needed */ - if (buflen % bsize_elem) - num_elem = (buflen / bsize_elem) + 1; - else - num_elem = buflen / bsize_elem; - - /* Allocate a scatter/gather list for the DMA */ - sglist = kzalloc(sizeof(struct pmcraid_sglist) + - (sizeof(struct scatterlist) * (num_elem - 1)), - GFP_KERNEL); - - if (sglist == NULL) - return NULL; - - scatterlist = sglist->scatterlist; - sg_init_table(scatterlist, num_elem); - sglist->order = order; - sglist->num_sg = num_elem; - sg_size = buflen; - - for (i = 0; i < num_elem; i++) { - page = alloc_pages(GFP_KERNEL|GFP_DMA|__GFP_ZERO, order); - if (!page) { - for (j = i - 1; j >= 0; j--) - __free_pages(sg_page(&scatterlist[j]), order); - kfree(sglist); - return NULL; - } - - sg_set_page(&scatterlist[i], page, - sg_size < bsize_elem ? sg_size : bsize_elem, 0); - sg_size -= bsize_elem; - } - - return sglist; -} - -/** - * pmcraid_copy_sglist - Copy user buffer to kernel buffer's SG list - * @sglist: scatter/gather list pointer - * @buffer: buffer pointer - * @len: buffer length - * @direction: data transfer direction - * - * Copy a user buffer into a buffer allocated by pmcraid_alloc_sglist - * - * Return value: - * 0 on success / other on failure - */ -static int pmcraid_copy_sglist( - struct pmcraid_sglist *sglist, - unsigned long buffer, - u32 len, - int direction -) -{ - struct scatterlist *scatterlist; - void *kaddr; - int bsize_elem; - int i; - int rc = 0; - - /* Determine the actual number of bytes per element */ - bsize_elem = PAGE_SIZE * (1 << sglist->order); - - scatterlist = sglist->scatterlist; - - for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); - - kaddr = kmap(page); - if (direction == DMA_TO_DEVICE) - rc = __copy_from_user(kaddr, - (void *)buffer, - bsize_elem); - else - rc = __copy_to_user((void *)buffer, kaddr, bsize_elem); - - kunmap(page); - - if (rc) { - pmcraid_err("failed to copy user data into sg list\n"); - return -EFAULT; - } - - scatterlist[i].length = bsize_elem; - } - - if (len % bsize_elem) { - struct page *page = sg_page(&scatterlist[i]); - - kaddr = kmap(page); - - if (direction == DMA_TO_DEVICE) - rc = __copy_from_user(kaddr, - (void *)buffer, - len % bsize_elem); - else - rc = __copy_to_user((void *)buffer, - kaddr, - len % bsize_elem); - - kunmap(page); - - scatterlist[i].length = len % bsize_elem; - } - - if (rc) { - pmcraid_err("failed to copy user data into sg list\n"); - rc = -EFAULT; - } - - return rc; -} - -/** - * pmcraid_queuecommand - Queue a mid-layer request - * @scsi_cmd: scsi command struct - * @done: done function - * - * This function queues a request generated by the mid-layer. Midlayer calls - * this routine within host->lock. Some of the functions called by queuecommand - * would use cmd block queue locks (free_pool_lock and pending_pool_lock) - * - * Return value: - * 0 on success - * SCSI_MLQUEUE_DEVICE_BUSY if device is busy - * SCSI_MLQUEUE_HOST_BUSY if host is busy - */ -static int pmcraid_queuecommand_lck( - struct scsi_cmnd *scsi_cmd, - void (*done) (struct scsi_cmnd *) -) -{ - struct pmcraid_instance *pinstance; - struct pmcraid_resource_entry *res; - struct pmcraid_ioarcb *ioarcb; - struct pmcraid_cmd *cmd; - u32 fw_version; - int rc = 0; - - pinstance = - (struct pmcraid_instance *)scsi_cmd->device->host->hostdata; - fw_version = be16_to_cpu(pinstance->inq_data->fw_version); - scsi_cmd->scsi_done = done; - res = scsi_cmd->device->hostdata; - scsi_cmd->result = (DID_OK << 16); - - /* if adapter is marked as dead, set result to DID_NO_CONNECT complete - * the command - */ - if (pinstance->ioa_state == IOA_STATE_DEAD) { - pmcraid_info("IOA is dead, but queuecommand is scheduled\n"); - scsi_cmd->result = (DID_NO_CONNECT << 16); - scsi_cmd->scsi_done(scsi_cmd); - return 0; - } - - /* If IOA reset is in progress, can't queue the commands */ - if (pinstance->ioa_reset_in_progress) - return SCSI_MLQUEUE_HOST_BUSY; - - /* Firmware doesn't support SYNCHRONIZE_CACHE command (0x35), complete - * the command here itself with success return - */ - if (scsi_cmd->cmnd[0] == SYNCHRONIZE_CACHE) { - pmcraid_info("SYNC_CACHE(0x35), completing in driver itself\n"); - scsi_cmd->scsi_done(scsi_cmd); - return 0; - } - - /* initialize the command and IOARCB to be sent to IOA */ - cmd = pmcraid_get_free_cmd(pinstance); - - if (cmd == NULL) { - pmcraid_err("free command block is not available\n"); - return SCSI_MLQUEUE_HOST_BUSY; - } - - cmd->scsi_cmd = scsi_cmd; - ioarcb = &(cmd->ioa_cb->ioarcb); - memcpy(ioarcb->cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len); - ioarcb->resource_handle = res->cfg_entry.resource_handle; - ioarcb->request_type = REQ_TYPE_SCSI; - - /* set hrrq number where the IOA should respond to. Note that all cmds - * generated internally uses hrrq_id 0, exception to this is the cmd - * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses - * hrrq_id assigned here in queuecommand - */ - ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % - pinstance->num_hrrq; - cmd->cmd_done = pmcraid_io_done; - - if (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry)) { - if (scsi_cmd->underflow == 0) - ioarcb->request_flags0 |= INHIBIT_UL_CHECK; - - if (res->sync_reqd) { - ioarcb->request_flags0 |= SYNC_COMPLETE; - res->sync_reqd = 0; - } - - ioarcb->request_flags0 |= NO_LINK_DESCS; - ioarcb->request_flags1 |= pmcraid_task_attributes(scsi_cmd); - - if (RES_IS_GSCSI(res->cfg_entry)) - ioarcb->request_flags1 |= DELAY_AFTER_RESET; - } - - rc = pmcraid_build_ioadl(pinstance, cmd); - - pmcraid_info("command (%d) CDB[0] = %x for %x:%x:%x:%x\n", - le32_to_cpu(ioarcb->response_handle) >> 2, - scsi_cmd->cmnd[0], pinstance->host->unique_id, - RES_IS_VSET(res->cfg_entry) ? PMCRAID_VSET_BUS_ID : - PMCRAID_PHYS_BUS_ID, - RES_IS_VSET(res->cfg_entry) ? - (fw_version <= PMCRAID_FW_VERSION_1 ? - res->cfg_entry.unique_flags1 : - res->cfg_entry.array_id & 0xFF) : - RES_TARGET(res->cfg_entry.resource_address), - RES_LUN(res->cfg_entry.resource_address)); - - if (likely(rc == 0)) { - _pmcraid_fire_command(cmd); - } else { - pmcraid_err("queuecommand could not build ioadl\n"); - pmcraid_return_cmd(cmd); - rc = SCSI_MLQUEUE_HOST_BUSY; - } - - return rc; -} - -static DEF_SCSI_QCMD(pmcraid_queuecommand) - -/** - * pmcraid_open -char node "open" entry, allowed only users with admin access - */ -static int pmcraid_chr_open(struct inode *inode, struct file *filep) -{ - struct pmcraid_instance *pinstance; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - /* Populate adapter instance * pointer for use by ioctl */ - pinstance = container_of(inode->i_cdev, struct pmcraid_instance, cdev); - filep->private_data = pinstance; - - return 0; -} - -/** - * pmcraid_release - char node "release" entry point - */ -static int pmcraid_chr_release(struct inode *inode, struct file *filep) -{ - struct pmcraid_instance *pinstance = filep->private_data; - - filep->private_data = NULL; - fasync_helper(-1, filep, 0, &pinstance->aen_queue); - - return 0; -} - -/** - * pmcraid_fasync - Async notifier registration from applications - * - * This function adds the calling process to a driver global queue. When an - * event occurs, SIGIO will be sent to all processes in this queue. - */ -static int pmcraid_chr_fasync(int fd, struct file *filep, int mode) -{ - struct pmcraid_instance *pinstance; - int rc; - - pinstance = filep->private_data; - mutex_lock(&pinstance->aen_queue_lock); - rc = fasync_helper(fd, filep, mode, &pinstance->aen_queue); - mutex_unlock(&pinstance->aen_queue_lock); - - return rc; -} - - -/** - * pmcraid_build_passthrough_ioadls - builds SG elements for passthrough - * commands sent over IOCTL interface - * - * @cmd : pointer to struct pmcraid_cmd - * @buflen : length of the request buffer - * @direction : data transfer direction - * - * Return value - * 0 on success, non-zero error code on failure - */ -static int pmcraid_build_passthrough_ioadls( - struct pmcraid_cmd *cmd, - int buflen, - int direction -) -{ - struct pmcraid_sglist *sglist = NULL; - struct scatterlist *sg = NULL; - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - struct pmcraid_ioadl_desc *ioadl; - int i; - - sglist = pmcraid_alloc_sglist(buflen); - - if (!sglist) { - pmcraid_err("can't allocate memory for passthrough SGls\n"); - return -ENOMEM; - } - - sglist->num_dma_sg = pci_map_sg(cmd->drv_inst->pdev, - sglist->scatterlist, - sglist->num_sg, direction); - - if (!sglist->num_dma_sg || sglist->num_dma_sg > PMCRAID_MAX_IOADLS) { - dev_err(&cmd->drv_inst->pdev->dev, - "Failed to map passthrough buffer!\n"); - pmcraid_free_sglist(sglist); - return -EIO; - } - - cmd->sglist = sglist; - ioarcb->request_flags0 |= NO_LINK_DESCS; - - ioadl = pmcraid_init_ioadls(cmd, sglist->num_dma_sg); - - /* Initialize IOADL descriptor addresses */ - for_each_sg(sglist->scatterlist, sg, sglist->num_dma_sg, i) { - ioadl[i].data_len = cpu_to_le32(sg_dma_len(sg)); - ioadl[i].address = cpu_to_le64(sg_dma_address(sg)); - ioadl[i].flags = 0; - } - - /* setup the last descriptor */ - ioadl[i - 1].flags = IOADL_FLAGS_LAST_DESC; - - return 0; -} - - -/** - * pmcraid_release_passthrough_ioadls - release passthrough ioadls - * - * @cmd: pointer to struct pmcraid_cmd for which ioadls were allocated - * @buflen: size of the request buffer - * @direction: data transfer direction - * - * Return value - * 0 on success, non-zero error code on failure - */ -static void pmcraid_release_passthrough_ioadls( - struct pmcraid_cmd *cmd, - int buflen, - int direction -) -{ - struct pmcraid_sglist *sglist = cmd->sglist; - - if (buflen > 0) { - pci_unmap_sg(cmd->drv_inst->pdev, - sglist->scatterlist, - sglist->num_sg, - direction); - pmcraid_free_sglist(sglist); - cmd->sglist = NULL; - } -} - -/** - * pmcraid_ioctl_passthrough - handling passthrough IOCTL commands - * - * @pinstance: pointer to adapter instance structure - * @cmd: ioctl code - * @arg: pointer to pmcraid_passthrough_buffer user buffer - * - * Return value - * 0 on success, non-zero error code on failure - */ -static long pmcraid_ioctl_passthrough( - struct pmcraid_instance *pinstance, - unsigned int ioctl_cmd, - unsigned int buflen, - unsigned long arg -) -{ - struct pmcraid_passthrough_ioctl_buffer *buffer; - struct pmcraid_ioarcb *ioarcb; - struct pmcraid_cmd *cmd; - struct pmcraid_cmd *cancel_cmd; - unsigned long request_buffer; - unsigned long request_offset; - unsigned long lock_flags; - void *ioasa; - u32 ioasc; - int request_size; - int buffer_size; - u8 access, direction; - int rc = 0; - - /* If IOA reset is in progress, wait 10 secs for reset to complete */ - if (pinstance->ioa_reset_in_progress) { - rc = wait_event_interruptible_timeout( - pinstance->reset_wait_q, - !pinstance->ioa_reset_in_progress, - msecs_to_jiffies(10000)); - - if (!rc) - return -ETIMEDOUT; - else if (rc < 0) - return -ERESTARTSYS; - } - - /* If adapter is not in operational state, return error */ - if (pinstance->ioa_state != IOA_STATE_OPERATIONAL) { - pmcraid_err("IOA is not operational\n"); - return -ENOTTY; - } - - buffer_size = sizeof(struct pmcraid_passthrough_ioctl_buffer); - buffer = kmalloc(buffer_size, GFP_KERNEL); - - if (!buffer) { - pmcraid_err("no memory for passthrough buffer\n"); - return -ENOMEM; - } - - request_offset = - offsetof(struct pmcraid_passthrough_ioctl_buffer, request_buffer); - - request_buffer = arg + request_offset; - - rc = __copy_from_user(buffer, - (struct pmcraid_passthrough_ioctl_buffer *) arg, - sizeof(struct pmcraid_passthrough_ioctl_buffer)); - - ioasa = - (void *)(arg + - offsetof(struct pmcraid_passthrough_ioctl_buffer, ioasa)); - - if (rc) { - pmcraid_err("ioctl: can't copy passthrough buffer\n"); - rc = -EFAULT; - goto out_free_buffer; - } - - request_size = buffer->ioarcb.data_transfer_length; - - if (buffer->ioarcb.request_flags0 & TRANSFER_DIR_WRITE) { - access = VERIFY_READ; - direction = DMA_TO_DEVICE; - } else { - access = VERIFY_WRITE; - direction = DMA_FROM_DEVICE; - } - - if (request_size > 0) { - rc = access_ok(access, arg, request_offset + request_size); - - if (!rc) { - rc = -EFAULT; - goto out_free_buffer; - } - } else if (request_size < 0) { - rc = -EINVAL; - goto out_free_buffer; - } - - /* check if we have any additional command parameters */ - if (buffer->ioarcb.add_cmd_param_length > PMCRAID_ADD_CMD_PARAM_LEN) { - rc = -EINVAL; - goto out_free_buffer; - } - - cmd = pmcraid_get_free_cmd(pinstance); - - if (!cmd) { - pmcraid_err("free command block is not available\n"); - rc = -ENOMEM; - goto out_free_buffer; - } - - cmd->scsi_cmd = NULL; - ioarcb = &(cmd->ioa_cb->ioarcb); - - /* Copy the user-provided IOARCB stuff field by field */ - ioarcb->resource_handle = buffer->ioarcb.resource_handle; - ioarcb->data_transfer_length = buffer->ioarcb.data_transfer_length; - ioarcb->cmd_timeout = buffer->ioarcb.cmd_timeout; - ioarcb->request_type = buffer->ioarcb.request_type; - ioarcb->request_flags0 = buffer->ioarcb.request_flags0; - ioarcb->request_flags1 = buffer->ioarcb.request_flags1; - memcpy(ioarcb->cdb, buffer->ioarcb.cdb, PMCRAID_MAX_CDB_LEN); - - if (buffer->ioarcb.add_cmd_param_length) { - ioarcb->add_cmd_param_length = - buffer->ioarcb.add_cmd_param_length; - ioarcb->add_cmd_param_offset = - buffer->ioarcb.add_cmd_param_offset; - memcpy(ioarcb->add_data.u.add_cmd_params, - buffer->ioarcb.add_data.u.add_cmd_params, - buffer->ioarcb.add_cmd_param_length); - } - - /* set hrrq number where the IOA should respond to. Note that all cmds - * generated internally uses hrrq_id 0, exception to this is the cmd - * block of scsi_cmd which is re-used (e.g. cancel/abort), which uses - * hrrq_id assigned here in queuecommand - */ - ioarcb->hrrq_id = atomic_add_return(1, &(pinstance->last_message_id)) % - pinstance->num_hrrq; - - if (request_size) { - rc = pmcraid_build_passthrough_ioadls(cmd, - request_size, - direction); - if (rc) { - pmcraid_err("couldn't build passthrough ioadls\n"); - goto out_free_buffer; - } - } else if (request_size < 0) { - rc = -EINVAL; - goto out_free_buffer; - } - - /* If data is being written into the device, copy the data from user - * buffers - */ - if (direction == DMA_TO_DEVICE && request_size > 0) { - rc = pmcraid_copy_sglist(cmd->sglist, - request_buffer, - request_size, - direction); - if (rc) { - pmcraid_err("failed to copy user buffer\n"); - goto out_free_sglist; - } - } - - /* passthrough ioctl is a blocking command so, put the user to sleep - * until timeout. Note that a timeout value of 0 means, do timeout. - */ - cmd->cmd_done = pmcraid_internal_done; - init_completion(&cmd->wait_for_completion); - cmd->completion_req = 1; - - pmcraid_info("command(%d) (CDB[0] = %x) for %x\n", - le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle) >> 2, - cmd->ioa_cb->ioarcb.cdb[0], - le32_to_cpu(cmd->ioa_cb->ioarcb.resource_handle)); - - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - _pmcraid_fire_command(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - - /* NOTE ! Remove the below line once abort_task is implemented - * in firmware. This line disables ioctl command timeout handling logic - * similar to IO command timeout handling, making ioctl commands to wait - * until the command completion regardless of timeout value specified in - * ioarcb - */ - buffer->ioarcb.cmd_timeout = 0; - - /* If command timeout is specified put caller to wait till that time, - * otherwise it would be blocking wait. If command gets timed out, it - * will be aborted. - */ - if (buffer->ioarcb.cmd_timeout == 0) { - wait_for_completion(&cmd->wait_for_completion); - } else if (!wait_for_completion_timeout( - &cmd->wait_for_completion, - msecs_to_jiffies(buffer->ioarcb.cmd_timeout * 1000))) { - - pmcraid_info("aborting cmd %d (CDB[0] = %x) due to timeout\n", - le32_to_cpu(cmd->ioa_cb->ioarcb.response_handle >> 2), - cmd->ioa_cb->ioarcb.cdb[0]); - - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - cancel_cmd = pmcraid_abort_cmd(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - - if (cancel_cmd) { - wait_for_completion(&cancel_cmd->wait_for_completion); - ioasc = cancel_cmd->ioa_cb->ioasa.ioasc; - pmcraid_return_cmd(cancel_cmd); - - /* if abort task couldn't find the command i.e it got - * completed prior to aborting, return good completion. - * if command got aborted successfully or there was IOA - * reset due to abort task itself getting timedout then - * return -ETIMEDOUT - */ - if (ioasc == PMCRAID_IOASC_IOA_WAS_RESET || - PMCRAID_IOASC_SENSE_KEY(ioasc) == 0x00) { - if (ioasc != PMCRAID_IOASC_GC_IOARCB_NOTFOUND) - rc = -ETIMEDOUT; - goto out_handle_response; - } - } - - /* no command block for abort task or abort task failed to abort - * the IOARCB, then wait for 150 more seconds and initiate reset - * sequence after timeout - */ - if (!wait_for_completion_timeout( - &cmd->wait_for_completion, - msecs_to_jiffies(150 * 1000))) { - pmcraid_reset_bringup(cmd->drv_inst); - rc = -ETIMEDOUT; - } - } - -out_handle_response: - /* copy entire IOASA buffer and return IOCTL success. - * If copying IOASA to user-buffer fails, return - * EFAULT - */ - if (copy_to_user(ioasa, &cmd->ioa_cb->ioasa, - sizeof(struct pmcraid_ioasa))) { - pmcraid_err("failed to copy ioasa buffer to user\n"); - rc = -EFAULT; - } - - /* If the data transfer was from device, copy the data onto user - * buffers - */ - else if (direction == DMA_FROM_DEVICE && request_size > 0) { - rc = pmcraid_copy_sglist(cmd->sglist, - request_buffer, - request_size, - direction); - if (rc) { - pmcraid_err("failed to copy user buffer\n"); - rc = -EFAULT; - } - } - -out_free_sglist: - pmcraid_release_passthrough_ioadls(cmd, request_size, direction); - pmcraid_return_cmd(cmd); - -out_free_buffer: - kfree(buffer); - - return rc; -} - - - - -/** - * pmcraid_ioctl_driver - ioctl handler for commands handled by driver itself - * - * @pinstance: pointer to adapter instance structure - * @cmd: ioctl command passed in - * @buflen: length of user_buffer - * @user_buffer: user buffer pointer - * - * Return Value - * 0 in case of success, otherwise appropriate error code - */ -static long pmcraid_ioctl_driver( - struct pmcraid_instance *pinstance, - unsigned int cmd, - unsigned int buflen, - void __user *user_buffer -) -{ - int rc = -ENOSYS; - - if (!access_ok(VERIFY_READ, user_buffer, _IOC_SIZE(cmd))) { - pmcraid_err("ioctl_driver: access fault in request buffer\n"); - return -EFAULT; - } - - switch (cmd) { - case PMCRAID_IOCTL_RESET_ADAPTER: - pmcraid_reset_bringup(pinstance); - rc = 0; - break; - - default: - break; - } - - return rc; -} - -/** - * pmcraid_check_ioctl_buffer - check for proper access to user buffer - * - * @cmd: ioctl command - * @arg: user buffer - * @hdr: pointer to kernel memory for pmcraid_ioctl_header - * - * Return Value - * negetive error code if there are access issues, otherwise zero. - * Upon success, returns ioctl header copied out of user buffer. - */ - -static int pmcraid_check_ioctl_buffer( - int cmd, - void __user *arg, - struct pmcraid_ioctl_header *hdr -) -{ - int rc = 0; - int access = VERIFY_READ; - - if (copy_from_user(hdr, arg, sizeof(struct pmcraid_ioctl_header))) { - pmcraid_err("couldn't copy ioctl header from user buffer\n"); - return -EFAULT; - } - - /* check for valid driver signature */ - rc = memcmp(hdr->signature, - PMCRAID_IOCTL_SIGNATURE, - sizeof(hdr->signature)); - if (rc) { - pmcraid_err("signature verification failed\n"); - return -EINVAL; - } - - /* check for appropriate buffer access */ - if ((_IOC_DIR(cmd) & _IOC_READ) == _IOC_READ) - access = VERIFY_WRITE; - - rc = access_ok(access, - (arg + sizeof(struct pmcraid_ioctl_header)), - hdr->buffer_length); - if (!rc) { - pmcraid_err("access failed for user buffer of size %d\n", - hdr->buffer_length); - return -EFAULT; - } - - return 0; -} - -/** - * pmcraid_ioctl - char node ioctl entry point - */ -static long pmcraid_chr_ioctl( - struct file *filep, - unsigned int cmd, - unsigned long arg -) -{ - struct pmcraid_instance *pinstance = NULL; - struct pmcraid_ioctl_header *hdr = NULL; - int retval = -ENOTTY; - - hdr = kmalloc(sizeof(struct pmcraid_ioctl_header), GFP_KERNEL); - - if (!hdr) { - pmcraid_err("failed to allocate memory for ioctl header\n"); - return -ENOMEM; - } - - retval = pmcraid_check_ioctl_buffer(cmd, (void *)arg, hdr); - - if (retval) { - pmcraid_info("chr_ioctl: header check failed\n"); - kfree(hdr); - return retval; - } - - pinstance = filep->private_data; - - if (!pinstance) { - pmcraid_info("adapter instance is not found\n"); - kfree(hdr); - return -ENOTTY; - } - - switch (_IOC_TYPE(cmd)) { - - case PMCRAID_PASSTHROUGH_IOCTL: - /* If ioctl code is to download microcode, we need to block - * mid-layer requests. - */ - if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) - scsi_block_requests(pinstance->host); - - retval = pmcraid_ioctl_passthrough(pinstance, - cmd, - hdr->buffer_length, - arg); - - if (cmd == PMCRAID_IOCTL_DOWNLOAD_MICROCODE) - scsi_unblock_requests(pinstance->host); - break; - - case PMCRAID_DRIVER_IOCTL: - arg += sizeof(struct pmcraid_ioctl_header); - retval = pmcraid_ioctl_driver(pinstance, - cmd, - hdr->buffer_length, - (void __user *)arg); - break; - - default: - retval = -ENOTTY; - break; - } - - kfree(hdr); - - return retval; -} - -/** - * File operations structure for management interface - */ -static const struct file_operations pmcraid_fops = { - .owner = THIS_MODULE, - .open = pmcraid_chr_open, - .release = pmcraid_chr_release, - .fasync = pmcraid_chr_fasync, - .unlocked_ioctl = pmcraid_chr_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = pmcraid_chr_ioctl, -#endif - .llseek = noop_llseek, -}; - - - - -/** - * pmcraid_show_log_level - Display adapter's error logging level - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - */ -static ssize_t pmcraid_show_log_level( - struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct pmcraid_instance *pinstance = - (struct pmcraid_instance *)shost->hostdata; - return snprintf(buf, PAGE_SIZE, "%d\n", pinstance->current_log_level); -} - -/** - * pmcraid_store_log_level - Change the adapter's error logging level - * @dev: class device struct - * @buf: buffer - * @count: not used - * - * Return value: - * number of bytes printed to buffer - */ -static ssize_t pmcraid_store_log_level( - struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count -) -{ - struct Scsi_Host *shost; - struct pmcraid_instance *pinstance; - unsigned long val; - - if (strict_strtoul(buf, 10, &val)) - return -EINVAL; - /* log-level should be from 0 to 2 */ - if (val > 2) - return -EINVAL; - - shost = class_to_shost(dev); - pinstance = (struct pmcraid_instance *)shost->hostdata; - pinstance->current_log_level = val; - - return strlen(buf); -} - -static struct device_attribute pmcraid_log_level_attr = { - .attr = { - .name = "log_level", - .mode = S_IRUGO | S_IWUSR, - }, - .show = pmcraid_show_log_level, - .store = pmcraid_store_log_level, -}; - -/** - * pmcraid_show_drv_version - Display driver version - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - */ -static ssize_t pmcraid_show_drv_version( - struct device *dev, - struct device_attribute *attr, - char *buf -) -{ - return snprintf(buf, PAGE_SIZE, "version: %s\n", - PMCRAID_DRIVER_VERSION); -} - -static struct device_attribute pmcraid_driver_version_attr = { - .attr = { - .name = "drv_version", - .mode = S_IRUGO, - }, - .show = pmcraid_show_drv_version, -}; - -/** - * pmcraid_show_io_adapter_id - Display driver assigned adapter id - * @dev: class device struct - * @buf: buffer - * - * Return value: - * number of bytes printed to buffer - */ -static ssize_t pmcraid_show_adapter_id( - struct device *dev, - struct device_attribute *attr, - char *buf -) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct pmcraid_instance *pinstance = - (struct pmcraid_instance *)shost->hostdata; - u32 adapter_id = (pinstance->pdev->bus->number << 8) | - pinstance->pdev->devfn; - u32 aen_group = pmcraid_event_family.id; - - return snprintf(buf, PAGE_SIZE, - "adapter id: %d\nminor: %d\naen group: %d\n", - adapter_id, MINOR(pinstance->cdev.dev), aen_group); -} - -static struct device_attribute pmcraid_adapter_id_attr = { - .attr = { - .name = "adapter_id", - .mode = S_IRUGO | S_IWUSR, - }, - .show = pmcraid_show_adapter_id, -}; - -static struct device_attribute *pmcraid_host_attrs[] = { - &pmcraid_log_level_attr, - &pmcraid_driver_version_attr, - &pmcraid_adapter_id_attr, - NULL, -}; - - -/* host template structure for pmcraid driver */ -static struct scsi_host_template pmcraid_host_template = { - .module = THIS_MODULE, - .name = PMCRAID_DRIVER_NAME, - .queuecommand = pmcraid_queuecommand, - .eh_abort_handler = pmcraid_eh_abort_handler, - .eh_bus_reset_handler = pmcraid_eh_bus_reset_handler, - .eh_target_reset_handler = pmcraid_eh_target_reset_handler, - .eh_device_reset_handler = pmcraid_eh_device_reset_handler, - .eh_host_reset_handler = pmcraid_eh_host_reset_handler, - - .slave_alloc = pmcraid_slave_alloc, - .slave_configure = pmcraid_slave_configure, - .slave_destroy = pmcraid_slave_destroy, - .change_queue_depth = pmcraid_change_queue_depth, - .change_queue_type = pmcraid_change_queue_type, - .can_queue = PMCRAID_MAX_IO_CMD, - .this_id = -1, - .sg_tablesize = PMCRAID_MAX_IOADLS, - .max_sectors = PMCRAID_IOA_MAX_SECTORS, - .cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN, - .use_clustering = ENABLE_CLUSTERING, - .shost_attrs = pmcraid_host_attrs, - .proc_name = PMCRAID_DRIVER_NAME -}; - -/* - * pmcraid_isr_msix - implements MSI-X interrupt handling routine - * @irq: interrupt vector number - * @dev_id: pointer hrrq_vector - * - * Return Value - * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored - */ - -static irqreturn_t pmcraid_isr_msix(int irq, void *dev_id) -{ - struct pmcraid_isr_param *hrrq_vector; - struct pmcraid_instance *pinstance; - unsigned long lock_flags; - u32 intrs_val; - int hrrq_id; - - hrrq_vector = (struct pmcraid_isr_param *)dev_id; - hrrq_id = hrrq_vector->hrrq_id; - pinstance = hrrq_vector->drv_inst; - - if (!hrrq_id) { - /* Read the interrupt */ - intrs_val = pmcraid_read_interrupts(pinstance); - if (intrs_val && - ((ioread32(pinstance->int_regs.host_ioa_interrupt_reg) - & DOORBELL_INTR_MSIX_CLR) == 0)) { - /* Any error interrupts including unit_check, - * initiate IOA reset.In case of unit check indicate - * to reset_sequence that IOA unit checked and prepare - * for a dump during reset sequence - */ - if (intrs_val & PMCRAID_ERROR_INTERRUPTS) { - if (intrs_val & INTRS_IOA_UNIT_CHECK) - pinstance->ioa_unit_check = 1; - - pmcraid_err("ISR: error interrupts: %x \ - initiating reset\n", intrs_val); - spin_lock_irqsave(pinstance->host->host_lock, - lock_flags); - pmcraid_initiate_reset(pinstance); - spin_unlock_irqrestore( - pinstance->host->host_lock, - lock_flags); - } - /* If interrupt was as part of the ioa initialization, - * clear it. Delete the timer and wakeup the - * reset engine to proceed with reset sequence - */ - if (intrs_val & INTRS_TRANSITION_TO_OPERATIONAL) - pmcraid_clr_trans_op(pinstance); - - /* Clear the interrupt register by writing - * to host to ioa doorbell. Once done - * FW will clear the interrupt. - */ - iowrite32(DOORBELL_INTR_MSIX_CLR, - pinstance->int_regs.host_ioa_interrupt_reg); - ioread32(pinstance->int_regs.host_ioa_interrupt_reg); - - - } - } - - tasklet_schedule(&(pinstance->isr_tasklet[hrrq_id])); - - return IRQ_HANDLED; -} - -/** - * pmcraid_isr - implements legacy interrupt handling routine - * - * @irq: interrupt vector number - * @dev_id: pointer hrrq_vector - * - * Return Value - * IRQ_HANDLED if interrupt is handled or IRQ_NONE if ignored - */ -static irqreturn_t pmcraid_isr(int irq, void *dev_id) -{ - struct pmcraid_isr_param *hrrq_vector; - struct pmcraid_instance *pinstance; - u32 intrs; - unsigned long lock_flags; - int hrrq_id = 0; - - /* In case of legacy interrupt mode where interrupts are shared across - * isrs, it may be possible that the current interrupt is not from IOA - */ - if (!dev_id) { - printk(KERN_INFO "%s(): NULL host pointer\n", __func__); - return IRQ_NONE; - } - hrrq_vector = (struct pmcraid_isr_param *)dev_id; - pinstance = hrrq_vector->drv_inst; - - intrs = pmcraid_read_interrupts(pinstance); - - if (unlikely((intrs & PMCRAID_PCI_INTERRUPTS) == 0)) - return IRQ_NONE; - - /* Any error interrupts including unit_check, initiate IOA reset. - * In case of unit check indicate to reset_sequence that IOA unit - * checked and prepare for a dump during reset sequence - */ - if (intrs & PMCRAID_ERROR_INTERRUPTS) { - - if (intrs & INTRS_IOA_UNIT_CHECK) - pinstance->ioa_unit_check = 1; - - iowrite32(intrs, - pinstance->int_regs.ioa_host_interrupt_clr_reg); - pmcraid_err("ISR: error interrupts: %x initiating reset\n", - intrs); - intrs = ioread32( - pinstance->int_regs.ioa_host_interrupt_clr_reg); - spin_lock_irqsave(pinstance->host->host_lock, lock_flags); - pmcraid_initiate_reset(pinstance); - spin_unlock_irqrestore(pinstance->host->host_lock, lock_flags); - } else { - /* If interrupt was as part of the ioa initialization, - * clear. Delete the timer and wakeup the - * reset engine to proceed with reset sequence - */ - if (intrs & INTRS_TRANSITION_TO_OPERATIONAL) { - pmcraid_clr_trans_op(pinstance); - } else { - iowrite32(intrs, - pinstance->int_regs.ioa_host_interrupt_clr_reg); - ioread32( - pinstance->int_regs.ioa_host_interrupt_clr_reg); - - tasklet_schedule( - &(pinstance->isr_tasklet[hrrq_id])); - } - } - - return IRQ_HANDLED; -} - - -/** - * pmcraid_worker_function - worker thread function - * - * @workp: pointer to struct work queue - * - * Return Value - * None - */ - -static void pmcraid_worker_function(struct work_struct *workp) -{ - struct pmcraid_instance *pinstance; - struct pmcraid_resource_entry *res; - struct pmcraid_resource_entry *temp; - struct scsi_device *sdev; - unsigned long lock_flags; - unsigned long host_lock_flags; - u16 fw_version; - u8 bus, target, lun; - - pinstance = container_of(workp, struct pmcraid_instance, worker_q); - /* add resources only after host is added into system */ - if (!atomic_read(&pinstance->expose_resources)) - return; - - fw_version = be16_to_cpu(pinstance->inq_data->fw_version); - - spin_lock_irqsave(&pinstance->resource_lock, lock_flags); - list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) { - - if (res->change_detected == RES_CHANGE_DEL && res->scsi_dev) { - sdev = res->scsi_dev; - - /* host_lock must be held before calling - * scsi_device_get - */ - spin_lock_irqsave(pinstance->host->host_lock, - host_lock_flags); - if (!scsi_device_get(sdev)) { - spin_unlock_irqrestore( - pinstance->host->host_lock, - host_lock_flags); - pmcraid_info("deleting %x from midlayer\n", - res->cfg_entry.resource_address); - list_move_tail(&res->queue, - &pinstance->free_res_q); - spin_unlock_irqrestore( - &pinstance->resource_lock, - lock_flags); - scsi_remove_device(sdev); - scsi_device_put(sdev); - spin_lock_irqsave(&pinstance->resource_lock, - lock_flags); - res->change_detected = 0; - } else { - spin_unlock_irqrestore( - pinstance->host->host_lock, - host_lock_flags); - } - } - } - - list_for_each_entry(res, &pinstance->used_res_q, queue) { - - if (res->change_detected == RES_CHANGE_ADD) { - - if (!pmcraid_expose_resource(fw_version, - &res->cfg_entry)) - continue; - - if (RES_IS_VSET(res->cfg_entry)) { - bus = PMCRAID_VSET_BUS_ID; - if (fw_version <= PMCRAID_FW_VERSION_1) - target = res->cfg_entry.unique_flags1; - else - target = res->cfg_entry.array_id & 0xFF; - lun = PMCRAID_VSET_LUN_ID; - } else { - bus = PMCRAID_PHYS_BUS_ID; - target = - RES_TARGET( - res->cfg_entry.resource_address); - lun = RES_LUN(res->cfg_entry.resource_address); - } - - res->change_detected = 0; - spin_unlock_irqrestore(&pinstance->resource_lock, - lock_flags); - scsi_add_device(pinstance->host, bus, target, lun); - spin_lock_irqsave(&pinstance->resource_lock, - lock_flags); - } - } - - spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); -} - -/** - * pmcraid_tasklet_function - Tasklet function - * - * @instance: pointer to msix param structure - * - * Return Value - * None - */ -static void pmcraid_tasklet_function(unsigned long instance) -{ - struct pmcraid_isr_param *hrrq_vector; - struct pmcraid_instance *pinstance; - unsigned long hrrq_lock_flags; - unsigned long pending_lock_flags; - unsigned long host_lock_flags; - spinlock_t *lockp; /* hrrq buffer lock */ - int id; - __le32 resp; - - hrrq_vector = (struct pmcraid_isr_param *)instance; - pinstance = hrrq_vector->drv_inst; - id = hrrq_vector->hrrq_id; - lockp = &(pinstance->hrrq_lock[id]); - - /* loop through each of the commands responded by IOA. Each HRRQ buf is - * protected by its own lock. Traversals must be done within this lock - * as there may be multiple tasklets running on multiple CPUs. Note - * that the lock is held just for picking up the response handle and - * manipulating hrrq_curr/toggle_bit values. - */ - spin_lock_irqsave(lockp, hrrq_lock_flags); - - resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); - - while ((resp & HRRQ_TOGGLE_BIT) == - pinstance->host_toggle_bit[id]) { - - int cmd_index = resp >> 2; - struct pmcraid_cmd *cmd = NULL; - - if (pinstance->hrrq_curr[id] < pinstance->hrrq_end[id]) { - pinstance->hrrq_curr[id]++; - } else { - pinstance->hrrq_curr[id] = pinstance->hrrq_start[id]; - pinstance->host_toggle_bit[id] ^= 1u; - } - - if (cmd_index >= PMCRAID_MAX_CMD) { - /* In case of invalid response handle, log message */ - pmcraid_err("Invalid response handle %d\n", cmd_index); - resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); - continue; - } - - cmd = pinstance->cmd_list[cmd_index]; - spin_unlock_irqrestore(lockp, hrrq_lock_flags); - - spin_lock_irqsave(&pinstance->pending_pool_lock, - pending_lock_flags); - list_del(&cmd->free_list); - spin_unlock_irqrestore(&pinstance->pending_pool_lock, - pending_lock_flags); - del_timer(&cmd->timer); - atomic_dec(&pinstance->outstanding_cmds); - - if (cmd->cmd_done == pmcraid_ioa_reset) { - spin_lock_irqsave(pinstance->host->host_lock, - host_lock_flags); - cmd->cmd_done(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, - host_lock_flags); - } else if (cmd->cmd_done != NULL) { - cmd->cmd_done(cmd); - } - /* loop over until we are done with all responses */ - spin_lock_irqsave(lockp, hrrq_lock_flags); - resp = le32_to_cpu(*(pinstance->hrrq_curr[id])); - } - - spin_unlock_irqrestore(lockp, hrrq_lock_flags); -} - -/** - * pmcraid_unregister_interrupt_handler - de-register interrupts handlers - * @pinstance: pointer to adapter instance structure - * - * This routine un-registers registered interrupt handler and - * also frees irqs/vectors. - * - * Retun Value - * None - */ -static -void pmcraid_unregister_interrupt_handler(struct pmcraid_instance *pinstance) -{ - int i; - - for (i = 0; i < pinstance->num_hrrq; i++) - free_irq(pinstance->hrrq_vector[i].vector, - &(pinstance->hrrq_vector[i])); - - if (pinstance->interrupt_mode) { - pci_disable_msix(pinstance->pdev); - pinstance->interrupt_mode = 0; - } -} - -/** - * pmcraid_register_interrupt_handler - registers interrupt handler - * @pinstance: pointer to per-adapter instance structure - * - * Return Value - * 0 on success, non-zero error code otherwise. - */ -static int -pmcraid_register_interrupt_handler(struct pmcraid_instance *pinstance) -{ - int rc; - struct pci_dev *pdev = pinstance->pdev; - - if ((pmcraid_enable_msix) && - (pci_find_capability(pdev, PCI_CAP_ID_MSIX))) { - int num_hrrq = PMCRAID_NUM_MSIX_VECTORS; - struct msix_entry entries[PMCRAID_NUM_MSIX_VECTORS]; - int i; - for (i = 0; i < PMCRAID_NUM_MSIX_VECTORS; i++) - entries[i].entry = i; - - rc = pci_enable_msix(pdev, entries, num_hrrq); - if (rc < 0) - goto pmcraid_isr_legacy; - - /* Check how many MSIX vectors are allocated and register - * msi-x handlers for each of them giving appropriate buffer - */ - if (rc > 0) { - num_hrrq = rc; - if (pci_enable_msix(pdev, entries, num_hrrq)) - goto pmcraid_isr_legacy; - } - - for (i = 0; i < num_hrrq; i++) { - pinstance->hrrq_vector[i].hrrq_id = i; - pinstance->hrrq_vector[i].drv_inst = pinstance; - pinstance->hrrq_vector[i].vector = entries[i].vector; - rc = request_irq(pinstance->hrrq_vector[i].vector, - pmcraid_isr_msix, 0, - PMCRAID_DRIVER_NAME, - &(pinstance->hrrq_vector[i])); - - if (rc) { - int j; - for (j = 0; j < i; j++) - free_irq(entries[j].vector, - &(pinstance->hrrq_vector[j])); - pci_disable_msix(pdev); - goto pmcraid_isr_legacy; - } - } - - pinstance->num_hrrq = num_hrrq; - pinstance->interrupt_mode = 1; - iowrite32(DOORBELL_INTR_MODE_MSIX, - pinstance->int_regs.host_ioa_interrupt_reg); - ioread32(pinstance->int_regs.host_ioa_interrupt_reg); - goto pmcraid_isr_out; - } - -pmcraid_isr_legacy: - /* If MSI-X registration failed fallback to legacy mode, where - * only one hrrq entry will be used - */ - pinstance->hrrq_vector[0].hrrq_id = 0; - pinstance->hrrq_vector[0].drv_inst = pinstance; - pinstance->hrrq_vector[0].vector = pdev->irq; - pinstance->num_hrrq = 1; - rc = 0; - - rc = request_irq(pdev->irq, pmcraid_isr, IRQF_SHARED, - PMCRAID_DRIVER_NAME, &pinstance->hrrq_vector[0]); -pmcraid_isr_out: - return rc; -} - -/** - * pmcraid_release_cmd_blocks - release buufers allocated for command blocks - * @pinstance: per adapter instance structure pointer - * @max_index: number of buffer blocks to release - * - * Return Value - * None - */ -static void -pmcraid_release_cmd_blocks(struct pmcraid_instance *pinstance, int max_index) -{ - int i; - for (i = 0; i < max_index; i++) { - kmem_cache_free(pinstance->cmd_cachep, pinstance->cmd_list[i]); - pinstance->cmd_list[i] = NULL; - } - kmem_cache_destroy(pinstance->cmd_cachep); - pinstance->cmd_cachep = NULL; -} - -/** - * pmcraid_release_control_blocks - releases buffers alloced for control blocks - * @pinstance: pointer to per adapter instance structure - * @max_index: number of buffers (from 0 onwards) to release - * - * This function assumes that the command blocks for which control blocks are - * linked are not released. - * - * Return Value - * None - */ -static void -pmcraid_release_control_blocks( - struct pmcraid_instance *pinstance, - int max_index -) -{ - int i; - - if (pinstance->control_pool == NULL) - return; - - for (i = 0; i < max_index; i++) { - pci_pool_free(pinstance->control_pool, - pinstance->cmd_list[i]->ioa_cb, - pinstance->cmd_list[i]->ioa_cb_bus_addr); - pinstance->cmd_list[i]->ioa_cb = NULL; - pinstance->cmd_list[i]->ioa_cb_bus_addr = 0; - } - pci_pool_destroy(pinstance->control_pool); - pinstance->control_pool = NULL; -} - -/** - * pmcraid_allocate_cmd_blocks - allocate memory for cmd block structures - * @pinstance - pointer to per adapter instance structure - * - * Allocates memory for command blocks using kernel slab allocator. - * - * Return Value - * 0 in case of success; -ENOMEM in case of failure - */ -static int __devinit -pmcraid_allocate_cmd_blocks(struct pmcraid_instance *pinstance) -{ - int i; - - sprintf(pinstance->cmd_pool_name, "pmcraid_cmd_pool_%d", - pinstance->host->unique_id); - - - pinstance->cmd_cachep = kmem_cache_create( - pinstance->cmd_pool_name, - sizeof(struct pmcraid_cmd), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!pinstance->cmd_cachep) - return -ENOMEM; - - for (i = 0; i < PMCRAID_MAX_CMD; i++) { - pinstance->cmd_list[i] = - kmem_cache_alloc(pinstance->cmd_cachep, GFP_KERNEL); - if (!pinstance->cmd_list[i]) { - pmcraid_release_cmd_blocks(pinstance, i); - return -ENOMEM; - } - } - return 0; -} - -/** - * pmcraid_allocate_control_blocks - allocates memory control blocks - * @pinstance : pointer to per adapter instance structure - * - * This function allocates PCI memory for DMAable buffers like IOARCB, IOADLs - * and IOASAs. This is called after command blocks are already allocated. - * - * Return Value - * 0 in case it can allocate all control blocks, otherwise -ENOMEM - */ -static int __devinit -pmcraid_allocate_control_blocks(struct pmcraid_instance *pinstance) -{ - int i; - - sprintf(pinstance->ctl_pool_name, "pmcraid_control_pool_%d", - pinstance->host->unique_id); - - pinstance->control_pool = - pci_pool_create(pinstance->ctl_pool_name, - pinstance->pdev, - sizeof(struct pmcraid_control_block), - PMCRAID_IOARCB_ALIGNMENT, 0); - - if (!pinstance->control_pool) - return -ENOMEM; - - for (i = 0; i < PMCRAID_MAX_CMD; i++) { - pinstance->cmd_list[i]->ioa_cb = - pci_pool_alloc( - pinstance->control_pool, - GFP_KERNEL, - &(pinstance->cmd_list[i]->ioa_cb_bus_addr)); - - if (!pinstance->cmd_list[i]->ioa_cb) { - pmcraid_release_control_blocks(pinstance, i); - return -ENOMEM; - } - memset(pinstance->cmd_list[i]->ioa_cb, 0, - sizeof(struct pmcraid_control_block)); - } - return 0; -} - -/** - * pmcraid_release_host_rrqs - release memory allocated for hrrq buffer(s) - * @pinstance: pointer to per adapter instance structure - * @maxindex: size of hrrq buffer pointer array - * - * Return Value - * None - */ -static void -pmcraid_release_host_rrqs(struct pmcraid_instance *pinstance, int maxindex) -{ - int i; - for (i = 0; i < maxindex; i++) { - - pci_free_consistent(pinstance->pdev, - HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD, - pinstance->hrrq_start[i], - pinstance->hrrq_start_bus_addr[i]); - - /* reset pointers and toggle bit to zeros */ - pinstance->hrrq_start[i] = NULL; - pinstance->hrrq_start_bus_addr[i] = 0; - pinstance->host_toggle_bit[i] = 0; - } -} - -/** - * pmcraid_allocate_host_rrqs - Allocate and initialize host RRQ buffers - * @pinstance: pointer to per adapter instance structure - * - * Return value - * 0 hrrq buffers are allocated, -ENOMEM otherwise. - */ -static int __devinit -pmcraid_allocate_host_rrqs(struct pmcraid_instance *pinstance) -{ - int i, buffer_size; - - buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; - - for (i = 0; i < pinstance->num_hrrq; i++) { - pinstance->hrrq_start[i] = - pci_alloc_consistent( - pinstance->pdev, - buffer_size, - &(pinstance->hrrq_start_bus_addr[i])); - - if (pinstance->hrrq_start[i] == 0) { - pmcraid_err("pci_alloc failed for hrrq vector : %d\n", - i); - pmcraid_release_host_rrqs(pinstance, i); - return -ENOMEM; - } - - memset(pinstance->hrrq_start[i], 0, buffer_size); - pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; - pinstance->hrrq_end[i] = - pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; - pinstance->host_toggle_bit[i] = 1; - spin_lock_init(&pinstance->hrrq_lock[i]); - } - return 0; -} - -/** - * pmcraid_release_hcams - release HCAM buffers - * - * @pinstance: pointer to per adapter instance structure - * - * Return value - * none - */ -static void pmcraid_release_hcams(struct pmcraid_instance *pinstance) -{ - if (pinstance->ccn.msg != NULL) { - pci_free_consistent(pinstance->pdev, - PMCRAID_AEN_HDR_SIZE + - sizeof(struct pmcraid_hcam_ccn_ext), - pinstance->ccn.msg, - pinstance->ccn.baddr); - - pinstance->ccn.msg = NULL; - pinstance->ccn.hcam = NULL; - pinstance->ccn.baddr = 0; - } - - if (pinstance->ldn.msg != NULL) { - pci_free_consistent(pinstance->pdev, - PMCRAID_AEN_HDR_SIZE + - sizeof(struct pmcraid_hcam_ldn), - pinstance->ldn.msg, - pinstance->ldn.baddr); - - pinstance->ldn.msg = NULL; - pinstance->ldn.hcam = NULL; - pinstance->ldn.baddr = 0; - } -} - -/** - * pmcraid_allocate_hcams - allocates HCAM buffers - * @pinstance : pointer to per adapter instance structure - * - * Return Value: - * 0 in case of successful allocation, non-zero otherwise - */ -static int pmcraid_allocate_hcams(struct pmcraid_instance *pinstance) -{ - pinstance->ccn.msg = pci_alloc_consistent( - pinstance->pdev, - PMCRAID_AEN_HDR_SIZE + - sizeof(struct pmcraid_hcam_ccn_ext), - &(pinstance->ccn.baddr)); - - pinstance->ldn.msg = pci_alloc_consistent( - pinstance->pdev, - PMCRAID_AEN_HDR_SIZE + - sizeof(struct pmcraid_hcam_ldn), - &(pinstance->ldn.baddr)); - - if (pinstance->ldn.msg == NULL || pinstance->ccn.msg == NULL) { - pmcraid_release_hcams(pinstance); - } else { - pinstance->ccn.hcam = - (void *)pinstance->ccn.msg + PMCRAID_AEN_HDR_SIZE; - pinstance->ldn.hcam = - (void *)pinstance->ldn.msg + PMCRAID_AEN_HDR_SIZE; - - atomic_set(&pinstance->ccn.ignore, 0); - atomic_set(&pinstance->ldn.ignore, 0); - } - - return (pinstance->ldn.msg == NULL) ? -ENOMEM : 0; -} - -/** - * pmcraid_release_config_buffers - release config.table buffers - * @pinstance: pointer to per adapter instance structure - * - * Return Value - * none - */ -static void pmcraid_release_config_buffers(struct pmcraid_instance *pinstance) -{ - if (pinstance->cfg_table != NULL && - pinstance->cfg_table_bus_addr != 0) { - pci_free_consistent(pinstance->pdev, - sizeof(struct pmcraid_config_table), - pinstance->cfg_table, - pinstance->cfg_table_bus_addr); - pinstance->cfg_table = NULL; - pinstance->cfg_table_bus_addr = 0; - } - - if (pinstance->res_entries != NULL) { - int i; - - for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) - list_del(&pinstance->res_entries[i].queue); - kfree(pinstance->res_entries); - pinstance->res_entries = NULL; - } - - pmcraid_release_hcams(pinstance); -} - -/** - * pmcraid_allocate_config_buffers - allocates DMAable memory for config table - * @pinstance : pointer to per adapter instance structure - * - * Return Value - * 0 for successful allocation, -ENOMEM for any failure - */ -static int __devinit -pmcraid_allocate_config_buffers(struct pmcraid_instance *pinstance) -{ - int i; - - pinstance->res_entries = - kzalloc(sizeof(struct pmcraid_resource_entry) * - PMCRAID_MAX_RESOURCES, GFP_KERNEL); - - if (NULL == pinstance->res_entries) { - pmcraid_err("failed to allocate memory for resource table\n"); - return -ENOMEM; - } - - for (i = 0; i < PMCRAID_MAX_RESOURCES; i++) - list_add_tail(&pinstance->res_entries[i].queue, - &pinstance->free_res_q); - - pinstance->cfg_table = - pci_alloc_consistent(pinstance->pdev, - sizeof(struct pmcraid_config_table), - &pinstance->cfg_table_bus_addr); - - if (NULL == pinstance->cfg_table) { - pmcraid_err("couldn't alloc DMA memory for config table\n"); - pmcraid_release_config_buffers(pinstance); - return -ENOMEM; - } - - if (pmcraid_allocate_hcams(pinstance)) { - pmcraid_err("could not alloc DMA memory for HCAMS\n"); - pmcraid_release_config_buffers(pinstance); - return -ENOMEM; - } - - return 0; -} - -/** - * pmcraid_init_tasklets - registers tasklets for response handling - * - * @pinstance: pointer adapter instance structure - * - * Return value - * none - */ -static void pmcraid_init_tasklets(struct pmcraid_instance *pinstance) -{ - int i; - for (i = 0; i < pinstance->num_hrrq; i++) - tasklet_init(&pinstance->isr_tasklet[i], - pmcraid_tasklet_function, - (unsigned long)&pinstance->hrrq_vector[i]); -} - -/** - * pmcraid_kill_tasklets - destroys tasklets registered for response handling - * - * @pinstance: pointer to adapter instance structure - * - * Return value - * none - */ -static void pmcraid_kill_tasklets(struct pmcraid_instance *pinstance) -{ - int i; - for (i = 0; i < pinstance->num_hrrq; i++) - tasklet_kill(&pinstance->isr_tasklet[i]); -} - -/** - * pmcraid_release_buffers - release per-adapter buffers allocated - * - * @pinstance: pointer to adapter soft state - * - * Return Value - * none - */ -static void pmcraid_release_buffers(struct pmcraid_instance *pinstance) -{ - pmcraid_release_config_buffers(pinstance); - pmcraid_release_control_blocks(pinstance, PMCRAID_MAX_CMD); - pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); - pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); - - if (pinstance->inq_data != NULL) { - pci_free_consistent(pinstance->pdev, - sizeof(struct pmcraid_inquiry_data), - pinstance->inq_data, - pinstance->inq_data_baddr); - - pinstance->inq_data = NULL; - pinstance->inq_data_baddr = 0; - } - - if (pinstance->timestamp_data != NULL) { - pci_free_consistent(pinstance->pdev, - sizeof(struct pmcraid_timestamp_data), - pinstance->timestamp_data, - pinstance->timestamp_data_baddr); - - pinstance->timestamp_data = NULL; - pinstance->timestamp_data_baddr = 0; - } -} - -/** - * pmcraid_init_buffers - allocates memory and initializes various structures - * @pinstance: pointer to per adapter instance structure - * - * This routine pre-allocates memory based on the type of block as below: - * cmdblocks(PMCRAID_MAX_CMD): kernel memory using kernel's slab_allocator, - * IOARCBs(PMCRAID_MAX_CMD) : DMAable memory, using pci pool allocator - * config-table entries : DMAable memory using pci_alloc_consistent - * HostRRQs : DMAable memory, using pci_alloc_consistent - * - * Return Value - * 0 in case all of the blocks are allocated, -ENOMEM otherwise. - */ -static int __devinit pmcraid_init_buffers(struct pmcraid_instance *pinstance) -{ - int i; - - if (pmcraid_allocate_host_rrqs(pinstance)) { - pmcraid_err("couldn't allocate memory for %d host rrqs\n", - pinstance->num_hrrq); - return -ENOMEM; - } - - if (pmcraid_allocate_config_buffers(pinstance)) { - pmcraid_err("couldn't allocate memory for config buffers\n"); - pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); - return -ENOMEM; - } - - if (pmcraid_allocate_cmd_blocks(pinstance)) { - pmcraid_err("couldn't allocate memory for cmd blocks\n"); - pmcraid_release_config_buffers(pinstance); - pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); - return -ENOMEM; - } - - if (pmcraid_allocate_control_blocks(pinstance)) { - pmcraid_err("couldn't allocate memory control blocks\n"); - pmcraid_release_config_buffers(pinstance); - pmcraid_release_cmd_blocks(pinstance, PMCRAID_MAX_CMD); - pmcraid_release_host_rrqs(pinstance, pinstance->num_hrrq); - return -ENOMEM; - } - - /* allocate DMAable memory for page D0 INQUIRY buffer */ - pinstance->inq_data = pci_alloc_consistent( - pinstance->pdev, - sizeof(struct pmcraid_inquiry_data), - &pinstance->inq_data_baddr); - - if (pinstance->inq_data == NULL) { - pmcraid_err("couldn't allocate DMA memory for INQUIRY\n"); - pmcraid_release_buffers(pinstance); - return -ENOMEM; - } - - /* allocate DMAable memory for set timestamp data buffer */ - pinstance->timestamp_data = pci_alloc_consistent( - pinstance->pdev, - sizeof(struct pmcraid_timestamp_data), - &pinstance->timestamp_data_baddr); - - if (pinstance->timestamp_data == NULL) { - pmcraid_err("couldn't allocate DMA memory for \ - set time_stamp \n"); - pmcraid_release_buffers(pinstance); - return -ENOMEM; - } - - - /* Initialize all the command blocks and add them to free pool. No - * need to lock (free_pool_lock) as this is done in initialization - * itself - */ - for (i = 0; i < PMCRAID_MAX_CMD; i++) { - struct pmcraid_cmd *cmdp = pinstance->cmd_list[i]; - pmcraid_init_cmdblk(cmdp, i); - cmdp->drv_inst = pinstance; - list_add_tail(&cmdp->free_list, &pinstance->free_cmd_pool); - } - - return 0; -} - -/** - * pmcraid_reinit_buffers - resets various buffer pointers - * @pinstance: pointer to adapter instance - * Return value - * none - */ -static void pmcraid_reinit_buffers(struct pmcraid_instance *pinstance) -{ - int i; - int buffer_size = HRRQ_ENTRY_SIZE * PMCRAID_MAX_CMD; - - for (i = 0; i < pinstance->num_hrrq; i++) { - memset(pinstance->hrrq_start[i], 0, buffer_size); - pinstance->hrrq_curr[i] = pinstance->hrrq_start[i]; - pinstance->hrrq_end[i] = - pinstance->hrrq_start[i] + PMCRAID_MAX_CMD - 1; - pinstance->host_toggle_bit[i] = 1; - } -} - -/** - * pmcraid_init_instance - initialize per instance data structure - * @pdev: pointer to pci device structure - * @host: pointer to Scsi_Host structure - * @mapped_pci_addr: memory mapped IOA configuration registers - * - * Return Value - * 0 on success, non-zero in case of any failure - */ -static int __devinit pmcraid_init_instance( - struct pci_dev *pdev, - struct Scsi_Host *host, - void __iomem *mapped_pci_addr -) -{ - struct pmcraid_instance *pinstance = - (struct pmcraid_instance *)host->hostdata; - - pinstance->host = host; - pinstance->pdev = pdev; - - /* Initialize register addresses */ - pinstance->mapped_dma_addr = mapped_pci_addr; - - /* Initialize chip-specific details */ - { - struct pmcraid_chip_details *chip_cfg = pinstance->chip_cfg; - struct pmcraid_interrupts *pint_regs = &pinstance->int_regs; - - pinstance->ioarrin = mapped_pci_addr + chip_cfg->ioarrin; - - pint_regs->ioa_host_interrupt_reg = - mapped_pci_addr + chip_cfg->ioa_host_intr; - pint_regs->ioa_host_interrupt_clr_reg = - mapped_pci_addr + chip_cfg->ioa_host_intr_clr; - pint_regs->ioa_host_msix_interrupt_reg = - mapped_pci_addr + chip_cfg->ioa_host_msix_intr; - pint_regs->host_ioa_interrupt_reg = - mapped_pci_addr + chip_cfg->host_ioa_intr; - pint_regs->host_ioa_interrupt_clr_reg = - mapped_pci_addr + chip_cfg->host_ioa_intr_clr; - - /* Current version of firmware exposes interrupt mask set - * and mask clr registers through memory mapped bar0. - */ - pinstance->mailbox = mapped_pci_addr + chip_cfg->mailbox; - pinstance->ioa_status = mapped_pci_addr + chip_cfg->ioastatus; - pint_regs->ioa_host_interrupt_mask_reg = - mapped_pci_addr + chip_cfg->ioa_host_mask; - pint_regs->ioa_host_interrupt_mask_clr_reg = - mapped_pci_addr + chip_cfg->ioa_host_mask_clr; - pint_regs->global_interrupt_mask_reg = - mapped_pci_addr + chip_cfg->global_intr_mask; - }; - - pinstance->ioa_reset_attempts = 0; - init_waitqueue_head(&pinstance->reset_wait_q); - - atomic_set(&pinstance->outstanding_cmds, 0); - atomic_set(&pinstance->last_message_id, 0); - atomic_set(&pinstance->expose_resources, 0); - - INIT_LIST_HEAD(&pinstance->free_res_q); - INIT_LIST_HEAD(&pinstance->used_res_q); - INIT_LIST_HEAD(&pinstance->free_cmd_pool); - INIT_LIST_HEAD(&pinstance->pending_cmd_pool); - - spin_lock_init(&pinstance->free_pool_lock); - spin_lock_init(&pinstance->pending_pool_lock); - spin_lock_init(&pinstance->resource_lock); - mutex_init(&pinstance->aen_queue_lock); - - /* Work-queue (Shared) for deferred processing error handling */ - INIT_WORK(&pinstance->worker_q, pmcraid_worker_function); - - /* Initialize the default log_level */ - pinstance->current_log_level = pmcraid_log_level; - - /* Setup variables required for reset engine */ - pinstance->ioa_state = IOA_STATE_UNKNOWN; - pinstance->reset_cmd = NULL; - return 0; -} - -/** - * pmcraid_shutdown - shutdown adapter controller. - * @pdev: pci device struct - * - * Issues an adapter shutdown to the card waits for its completion - * - * Return value - * none - */ -static void pmcraid_shutdown(struct pci_dev *pdev) -{ - struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); - pmcraid_reset_bringdown(pinstance); -} - - -/** - * pmcraid_get_minor - returns unused minor number from minor number bitmap - */ -static unsigned short pmcraid_get_minor(void) -{ - int minor; - - minor = find_first_zero_bit(pmcraid_minor, sizeof(pmcraid_minor)); - __set_bit(minor, pmcraid_minor); - return minor; -} - -/** - * pmcraid_release_minor - releases given minor back to minor number bitmap - */ -static void pmcraid_release_minor(unsigned short minor) -{ - __clear_bit(minor, pmcraid_minor); -} - -/** - * pmcraid_setup_chrdev - allocates a minor number and registers a char device - * - * @pinstance: pointer to adapter instance for which to register device - * - * Return value - * 0 in case of success, otherwise non-zero - */ -static int pmcraid_setup_chrdev(struct pmcraid_instance *pinstance) -{ - int minor; - int error; - - minor = pmcraid_get_minor(); - cdev_init(&pinstance->cdev, &pmcraid_fops); - pinstance->cdev.owner = THIS_MODULE; - - error = cdev_add(&pinstance->cdev, MKDEV(pmcraid_major, minor), 1); - - if (error) - pmcraid_release_minor(minor); - else - device_create(pmcraid_class, NULL, MKDEV(pmcraid_major, minor), - NULL, "%s%u", PMCRAID_DEVFILE, minor); - return error; -} - -/** - * pmcraid_release_chrdev - unregisters per-adapter management interface - * - * @pinstance: pointer to adapter instance structure - * - * Return value - * none - */ -static void pmcraid_release_chrdev(struct pmcraid_instance *pinstance) -{ - pmcraid_release_minor(MINOR(pinstance->cdev.dev)); - device_destroy(pmcraid_class, - MKDEV(pmcraid_major, MINOR(pinstance->cdev.dev))); - cdev_del(&pinstance->cdev); -} - -/** - * pmcraid_remove - IOA hot plug remove entry point - * @pdev: pci device struct - * - * Return value - * none - */ -static void __devexit pmcraid_remove(struct pci_dev *pdev) -{ - struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); - - /* remove the management interface (/dev file) for this device */ - pmcraid_release_chrdev(pinstance); - - /* remove host template from scsi midlayer */ - scsi_remove_host(pinstance->host); - - /* block requests from mid-layer */ - scsi_block_requests(pinstance->host); - - /* initiate shutdown adapter */ - pmcraid_shutdown(pdev); - - pmcraid_disable_interrupts(pinstance, ~0); - flush_work_sync(&pinstance->worker_q); - - pmcraid_kill_tasklets(pinstance); - pmcraid_unregister_interrupt_handler(pinstance); - pmcraid_release_buffers(pinstance); - iounmap(pinstance->mapped_dma_addr); - pci_release_regions(pdev); - scsi_host_put(pinstance->host); - pci_disable_device(pdev); - - return; -} - -#ifdef CONFIG_PM -/** - * pmcraid_suspend - driver suspend entry point for power management - * @pdev: PCI device structure - * @state: PCI power state to suspend routine - * - * Return Value - 0 always - */ -static int pmcraid_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); - - pmcraid_shutdown(pdev); - pmcraid_disable_interrupts(pinstance, ~0); - pmcraid_kill_tasklets(pinstance); - pci_set_drvdata(pinstance->pdev, pinstance); - pmcraid_unregister_interrupt_handler(pinstance); - pci_save_state(pdev); - pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -/** - * pmcraid_resume - driver resume entry point PCI power management - * @pdev: PCI device structure - * - * Return Value - 0 in case of success. Error code in case of any failure - */ -static int pmcraid_resume(struct pci_dev *pdev) -{ - struct pmcraid_instance *pinstance = pci_get_drvdata(pdev); - struct Scsi_Host *host = pinstance->host; - int rc; - - pci_set_power_state(pdev, PCI_D0); - pci_enable_wake(pdev, PCI_D0, 0); - pci_restore_state(pdev); - - rc = pci_enable_device(pdev); - - if (rc) { - dev_err(&pdev->dev, "resume: Enable device failed\n"); - return rc; - } - - pci_set_master(pdev); - - if ((sizeof(dma_addr_t) == 4) || - pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - - if (rc == 0) - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - - if (rc != 0) { - dev_err(&pdev->dev, "resume: Failed to set PCI DMA mask\n"); - goto disable_device; - } - - pmcraid_disable_interrupts(pinstance, ~0); - atomic_set(&pinstance->outstanding_cmds, 0); - rc = pmcraid_register_interrupt_handler(pinstance); - - if (rc) { - dev_err(&pdev->dev, - "resume: couldn't register interrupt handlers\n"); - rc = -ENODEV; - goto release_host; - } - - pmcraid_init_tasklets(pinstance); - pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); - - /* Start with hard reset sequence which brings up IOA to operational - * state as well as completes the reset sequence. - */ - pinstance->ioa_hard_reset = 1; - - /* Start IOA firmware initialization and bring card to Operational - * state. - */ - if (pmcraid_reset_bringup(pinstance)) { - dev_err(&pdev->dev, "couldn't initialize IOA\n"); - rc = -ENODEV; - goto release_tasklets; - } - - return 0; - -release_tasklets: - pmcraid_disable_interrupts(pinstance, ~0); - pmcraid_kill_tasklets(pinstance); - pmcraid_unregister_interrupt_handler(pinstance); - -release_host: - scsi_host_put(host); - -disable_device: - pci_disable_device(pdev); - - return rc; -} - -#else - -#define pmcraid_suspend NULL -#define pmcraid_resume NULL - -#endif /* CONFIG_PM */ - -/** - * pmcraid_complete_ioa_reset - Called by either timer or tasklet during - * completion of the ioa reset - * @cmd: pointer to reset command block - */ -static void pmcraid_complete_ioa_reset(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - unsigned long flags; - - spin_lock_irqsave(pinstance->host->host_lock, flags); - pmcraid_ioa_reset(cmd); - spin_unlock_irqrestore(pinstance->host->host_lock, flags); - scsi_unblock_requests(pinstance->host); - schedule_work(&pinstance->worker_q); -} - -/** - * pmcraid_set_supported_devs - sends SET SUPPORTED DEVICES to IOAFP - * - * @cmd: pointer to pmcraid_cmd structure - * - * Return Value - * 0 for success or non-zero for failure cases - */ -static void pmcraid_set_supported_devs(struct pmcraid_cmd *cmd) -{ - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - void (*cmd_done) (struct pmcraid_cmd *) = pmcraid_complete_ioa_reset; - - pmcraid_reinit_cmdblk(cmd); - - ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); - ioarcb->request_type = REQ_TYPE_IOACMD; - ioarcb->cdb[0] = PMCRAID_SET_SUPPORTED_DEVICES; - ioarcb->cdb[1] = ALL_DEVICES_SUPPORTED; - - /* If this was called as part of resource table reinitialization due to - * lost CCN, it is enough to return the command block back to free pool - * as part of set_supported_devs completion function. - */ - if (cmd->drv_inst->reinit_cfg_table) { - cmd->drv_inst->reinit_cfg_table = 0; - cmd->release = 1; - cmd_done = pmcraid_reinit_cfgtable_done; - } - - /* we will be done with the reset sequence after set supported devices, - * setup the done function to return the command block back to free - * pool - */ - pmcraid_send_cmd(cmd, - cmd_done, - PMCRAID_SET_SUP_DEV_TIMEOUT, - pmcraid_timeout_handler); - return; -} - -/** - * pmcraid_set_timestamp - set the timestamp to IOAFP - * - * @cmd: pointer to pmcraid_cmd structure - * - * Return Value - * 0 for success or non-zero for failure cases - */ -static void pmcraid_set_timestamp(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - __be32 time_stamp_len = cpu_to_be32(PMCRAID_TIMESTAMP_LEN); - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; - - struct timeval tv; - __le64 timestamp; - - do_gettimeofday(&tv); - timestamp = tv.tv_sec * 1000; - - pinstance->timestamp_data->timestamp[0] = (__u8)(timestamp); - pinstance->timestamp_data->timestamp[1] = (__u8)((timestamp) >> 8); - pinstance->timestamp_data->timestamp[2] = (__u8)((timestamp) >> 16); - pinstance->timestamp_data->timestamp[3] = (__u8)((timestamp) >> 24); - pinstance->timestamp_data->timestamp[4] = (__u8)((timestamp) >> 32); - pinstance->timestamp_data->timestamp[5] = (__u8)((timestamp) >> 40); - - pmcraid_reinit_cmdblk(cmd); - ioarcb->request_type = REQ_TYPE_SCSI; - ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); - ioarcb->cdb[0] = PMCRAID_SCSI_SET_TIMESTAMP; - ioarcb->cdb[1] = PMCRAID_SCSI_SERVICE_ACTION; - memcpy(&(ioarcb->cdb[6]), &time_stamp_len, sizeof(time_stamp_len)); - - ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + - offsetof(struct pmcraid_ioarcb, - add_data.u.ioadl[0])); - ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); - ioarcb->ioarcb_bus_addr &= ~(0x1FULL); - - ioarcb->request_flags0 |= NO_LINK_DESCS; - ioarcb->request_flags0 |= TRANSFER_DIR_WRITE; - ioarcb->data_transfer_length = - cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); - ioadl = &(ioarcb->add_data.u.ioadl[0]); - ioadl->flags = IOADL_FLAGS_LAST_DESC; - ioadl->address = cpu_to_le64(pinstance->timestamp_data_baddr); - ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_timestamp_data)); - - if (!pinstance->timestamp_error) { - pinstance->timestamp_error = 0; - pmcraid_send_cmd(cmd, pmcraid_set_supported_devs, - PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); - } else { - pmcraid_send_cmd(cmd, pmcraid_return_cmd, - PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); - return; - } -} - - -/** - * pmcraid_init_res_table - Initialize the resource table - * @cmd: pointer to pmcraid command struct - * - * This function looks through the existing resource table, comparing - * it with the config table. This function will take care of old/new - * devices and schedule adding/removing them from the mid-layer - * as appropriate. - * - * Return value - * None - */ -static void pmcraid_init_res_table(struct pmcraid_cmd *cmd) -{ - struct pmcraid_instance *pinstance = cmd->drv_inst; - struct pmcraid_resource_entry *res, *temp; - struct pmcraid_config_table_entry *cfgte; - unsigned long lock_flags; - int found, rc, i; - u16 fw_version; - LIST_HEAD(old_res); - - if (pinstance->cfg_table->flags & MICROCODE_UPDATE_REQUIRED) - pmcraid_err("IOA requires microcode download\n"); - - fw_version = be16_to_cpu(pinstance->inq_data->fw_version); - - /* resource list is protected by pinstance->resource_lock. - * init_res_table can be called from probe (user-thread) or runtime - * reset (timer/tasklet) - */ - spin_lock_irqsave(&pinstance->resource_lock, lock_flags); - - list_for_each_entry_safe(res, temp, &pinstance->used_res_q, queue) - list_move_tail(&res->queue, &old_res); - - for (i = 0; i < pinstance->cfg_table->num_entries; i++) { - if (be16_to_cpu(pinstance->inq_data->fw_version) <= - PMCRAID_FW_VERSION_1) - cfgte = &pinstance->cfg_table->entries[i]; - else - cfgte = (struct pmcraid_config_table_entry *) - &pinstance->cfg_table->entries_ext[i]; - - if (!pmcraid_expose_resource(fw_version, cfgte)) - continue; - - found = 0; - - /* If this entry was already detected and initialized */ - list_for_each_entry_safe(res, temp, &old_res, queue) { - - rc = memcmp(&res->cfg_entry.resource_address, - &cfgte->resource_address, - sizeof(cfgte->resource_address)); - if (!rc) { - list_move_tail(&res->queue, - &pinstance->used_res_q); - found = 1; - break; - } - } - - /* If this is new entry, initialize it and add it the queue */ - if (!found) { - - if (list_empty(&pinstance->free_res_q)) { - pmcraid_err("Too many devices attached\n"); - break; - } - - found = 1; - res = list_entry(pinstance->free_res_q.next, - struct pmcraid_resource_entry, queue); - - res->scsi_dev = NULL; - res->change_detected = RES_CHANGE_ADD; - res->reset_progress = 0; - list_move_tail(&res->queue, &pinstance->used_res_q); - } - - /* copy new configuration table entry details into driver - * maintained resource entry - */ - if (found) { - memcpy(&res->cfg_entry, cfgte, - pinstance->config_table_entry_size); - pmcraid_info("New res type:%x, vset:%x, addr:%x:\n", - res->cfg_entry.resource_type, - (fw_version <= PMCRAID_FW_VERSION_1 ? - res->cfg_entry.unique_flags1 : - res->cfg_entry.array_id & 0xFF), - le32_to_cpu(res->cfg_entry.resource_address)); - } - } - - /* Detect any deleted entries, mark them for deletion from mid-layer */ - list_for_each_entry_safe(res, temp, &old_res, queue) { - - if (res->scsi_dev) { - res->change_detected = RES_CHANGE_DEL; - res->cfg_entry.resource_handle = - PMCRAID_INVALID_RES_HANDLE; - list_move_tail(&res->queue, &pinstance->used_res_q); - } else { - list_move_tail(&res->queue, &pinstance->free_res_q); - } - } - - /* release the resource list lock */ - spin_unlock_irqrestore(&pinstance->resource_lock, lock_flags); - pmcraid_set_timestamp(cmd); -} - -/** - * pmcraid_querycfg - Send a Query IOA Config to the adapter. - * @cmd: pointer pmcraid_cmd struct - * - * This function sends a Query IOA Configuration command to the adapter to - * retrieve the IOA configuration table. - * - * Return value: - * none - */ -static void pmcraid_querycfg(struct pmcraid_cmd *cmd) -{ - struct pmcraid_ioarcb *ioarcb = &cmd->ioa_cb->ioarcb; - struct pmcraid_ioadl_desc *ioadl = ioarcb->add_data.u.ioadl; - struct pmcraid_instance *pinstance = cmd->drv_inst; - int cfg_table_size = cpu_to_be32(sizeof(struct pmcraid_config_table)); - - if (be16_to_cpu(pinstance->inq_data->fw_version) <= - PMCRAID_FW_VERSION_1) - pinstance->config_table_entry_size = - sizeof(struct pmcraid_config_table_entry); - else - pinstance->config_table_entry_size = - sizeof(struct pmcraid_config_table_entry_ext); - - ioarcb->request_type = REQ_TYPE_IOACMD; - ioarcb->resource_handle = cpu_to_le32(PMCRAID_IOA_RES_HANDLE); - - ioarcb->cdb[0] = PMCRAID_QUERY_IOA_CONFIG; - - /* firmware requires 4-byte length field, specified in B.E format */ - memcpy(&(ioarcb->cdb[10]), &cfg_table_size, sizeof(cfg_table_size)); - - /* Since entire config table can be described by single IOADL, it can - * be part of IOARCB itself - */ - ioarcb->ioadl_bus_addr = cpu_to_le64((cmd->ioa_cb_bus_addr) + - offsetof(struct pmcraid_ioarcb, - add_data.u.ioadl[0])); - ioarcb->ioadl_length = cpu_to_le32(sizeof(struct pmcraid_ioadl_desc)); - ioarcb->ioarcb_bus_addr &= ~(0x1FULL); - - ioarcb->request_flags0 |= NO_LINK_DESCS; - ioarcb->data_transfer_length = - cpu_to_le32(sizeof(struct pmcraid_config_table)); - - ioadl = &(ioarcb->add_data.u.ioadl[0]); - ioadl->flags = IOADL_FLAGS_LAST_DESC; - ioadl->address = cpu_to_le64(pinstance->cfg_table_bus_addr); - ioadl->data_len = cpu_to_le32(sizeof(struct pmcraid_config_table)); - - pmcraid_send_cmd(cmd, pmcraid_init_res_table, - PMCRAID_INTERNAL_TIMEOUT, pmcraid_timeout_handler); -} - - -/** - * pmcraid_probe - PCI probe entry pointer for PMC MaxRAID controller driver - * @pdev: pointer to pci device structure - * @dev_id: pointer to device ids structure - * - * Return Value - * returns 0 if the device is claimed and successfully configured. - * returns non-zero error code in case of any failure - */ -static int __devinit pmcraid_probe( - struct pci_dev *pdev, - const struct pci_device_id *dev_id -) -{ - struct pmcraid_instance *pinstance; - struct Scsi_Host *host; - void __iomem *mapped_pci_addr; - int rc = PCIBIOS_SUCCESSFUL; - - if (atomic_read(&pmcraid_adapter_count) >= PMCRAID_MAX_ADAPTERS) { - pmcraid_err - ("maximum number(%d) of supported adapters reached\n", - atomic_read(&pmcraid_adapter_count)); - return -ENOMEM; - } - - atomic_inc(&pmcraid_adapter_count); - rc = pci_enable_device(pdev); - - if (rc) { - dev_err(&pdev->dev, "Cannot enable adapter\n"); - atomic_dec(&pmcraid_adapter_count); - return rc; - } - - dev_info(&pdev->dev, - "Found new IOA(%x:%x), Total IOA count: %d\n", - pdev->vendor, pdev->device, - atomic_read(&pmcraid_adapter_count)); - - rc = pci_request_regions(pdev, PMCRAID_DRIVER_NAME); - - if (rc < 0) { - dev_err(&pdev->dev, - "Couldn't register memory range of registers\n"); - goto out_disable_device; - } - - mapped_pci_addr = pci_iomap(pdev, 0, 0); - - if (!mapped_pci_addr) { - dev_err(&pdev->dev, "Couldn't map PCI registers memory\n"); - rc = -ENOMEM; - goto out_release_regions; - } - - pci_set_master(pdev); - - /* Firmware requires the system bus address of IOARCB to be within - * 32-bit addressable range though it has 64-bit IOARRIN register. - * However, firmware supports 64-bit streaming DMA buffers, whereas - * coherent buffers are to be 32-bit. Since pci_alloc_consistent always - * returns memory within 4GB (if not, change this logic), coherent - * buffers are within firmware acceptable address ranges. - */ - if ((sizeof(dma_addr_t) == 4) || - pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) - rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - - /* firmware expects 32-bit DMA addresses for IOARRIN register; set 32 - * bit mask for pci_alloc_consistent to return addresses within 4GB - */ - if (rc == 0) - rc = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - - if (rc != 0) { - dev_err(&pdev->dev, "Failed to set PCI DMA mask\n"); - goto cleanup_nomem; - } - - host = scsi_host_alloc(&pmcraid_host_template, - sizeof(struct pmcraid_instance)); - - if (!host) { - dev_err(&pdev->dev, "scsi_host_alloc failed!\n"); - rc = -ENOMEM; - goto cleanup_nomem; - } - - host->max_id = PMCRAID_MAX_NUM_TARGETS_PER_BUS; - host->max_lun = PMCRAID_MAX_NUM_LUNS_PER_TARGET; - host->unique_id = host->host_no; - host->max_channel = PMCRAID_MAX_BUS_TO_SCAN; - host->max_cmd_len = PMCRAID_MAX_CDB_LEN; - - /* zero out entire instance structure */ - pinstance = (struct pmcraid_instance *)host->hostdata; - memset(pinstance, 0, sizeof(*pinstance)); - - pinstance->chip_cfg = - (struct pmcraid_chip_details *)(dev_id->driver_data); - - rc = pmcraid_init_instance(pdev, host, mapped_pci_addr); - - if (rc < 0) { - dev_err(&pdev->dev, "failed to initialize adapter instance\n"); - goto out_scsi_host_put; - } - - pci_set_drvdata(pdev, pinstance); - - /* Save PCI config-space for use following the reset */ - rc = pci_save_state(pinstance->pdev); - - if (rc != 0) { - dev_err(&pdev->dev, "Failed to save PCI config space\n"); - goto out_scsi_host_put; - } - - pmcraid_disable_interrupts(pinstance, ~0); - - rc = pmcraid_register_interrupt_handler(pinstance); - - if (rc) { - dev_err(&pdev->dev, "couldn't register interrupt handler\n"); - goto out_scsi_host_put; - } - - pmcraid_init_tasklets(pinstance); - - /* allocate verious buffers used by LLD.*/ - rc = pmcraid_init_buffers(pinstance); - - if (rc) { - pmcraid_err("couldn't allocate memory blocks\n"); - goto out_unregister_isr; - } - - /* check the reset type required */ - pmcraid_reset_type(pinstance); - - pmcraid_enable_interrupts(pinstance, PMCRAID_PCI_INTERRUPTS); - - /* Start IOA firmware initialization and bring card to Operational - * state. - */ - pmcraid_info("starting IOA initialization sequence\n"); - if (pmcraid_reset_bringup(pinstance)) { - dev_err(&pdev->dev, "couldn't initialize IOA\n"); - rc = 1; - goto out_release_bufs; - } - - /* Add adapter instance into mid-layer list */ - rc = scsi_add_host(pinstance->host, &pdev->dev); - if (rc != 0) { - pmcraid_err("couldn't add host into mid-layer: %d\n", rc); - goto out_release_bufs; - } - - scsi_scan_host(pinstance->host); - - rc = pmcraid_setup_chrdev(pinstance); - - if (rc != 0) { - pmcraid_err("couldn't create mgmt interface, error: %x\n", - rc); - goto out_remove_host; - } - - /* Schedule worker thread to handle CCN and take care of adding and - * removing devices to OS - */ - atomic_set(&pinstance->expose_resources, 1); - schedule_work(&pinstance->worker_q); - return rc; - -out_remove_host: - scsi_remove_host(host); - -out_release_bufs: - pmcraid_release_buffers(pinstance); - -out_unregister_isr: - pmcraid_kill_tasklets(pinstance); - pmcraid_unregister_interrupt_handler(pinstance); - -out_scsi_host_put: - scsi_host_put(host); - -cleanup_nomem: - iounmap(mapped_pci_addr); - -out_release_regions: - pci_release_regions(pdev); - -out_disable_device: - atomic_dec(&pmcraid_adapter_count); - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); - return -ENODEV; -} - -/* - * PCI driver structure of pcmraid driver - */ -static struct pci_driver pmcraid_driver = { - .name = PMCRAID_DRIVER_NAME, - .id_table = pmcraid_pci_table, - .probe = pmcraid_probe, - .remove = pmcraid_remove, - .suspend = pmcraid_suspend, - .resume = pmcraid_resume, - .shutdown = pmcraid_shutdown -}; - -/** - * pmcraid_init - module load entry point - */ -static int __init pmcraid_init(void) -{ - dev_t dev; - int error; - - pmcraid_info("%s Device Driver version: %s\n", - PMCRAID_DRIVER_NAME, PMCRAID_DRIVER_VERSION); - - error = alloc_chrdev_region(&dev, 0, - PMCRAID_MAX_ADAPTERS, - PMCRAID_DEVFILE); - - if (error) { - pmcraid_err("failed to get a major number for adapters\n"); - goto out_init; - } - - pmcraid_major = MAJOR(dev); - pmcraid_class = class_create(THIS_MODULE, PMCRAID_DEVFILE); - - if (IS_ERR(pmcraid_class)) { - error = PTR_ERR(pmcraid_class); - pmcraid_err("failed to register with with sysfs, error = %x\n", - error); - goto out_unreg_chrdev; - } - - error = pmcraid_netlink_init(); - - if (error) - goto out_unreg_chrdev; - - error = pci_register_driver(&pmcraid_driver); - - if (error == 0) - goto out_init; - - pmcraid_err("failed to register pmcraid driver, error = %x\n", - error); - class_destroy(pmcraid_class); - pmcraid_netlink_release(); - -out_unreg_chrdev: - unregister_chrdev_region(MKDEV(pmcraid_major, 0), PMCRAID_MAX_ADAPTERS); - -out_init: - return error; -} - -/** - * pmcraid_exit - module unload entry point - */ -static void __exit pmcraid_exit(void) -{ - pmcraid_netlink_release(); - unregister_chrdev_region(MKDEV(pmcraid_major, 0), - PMCRAID_MAX_ADAPTERS); - pci_unregister_driver(&pmcraid_driver); - class_destroy(pmcraid_class); -} - -module_init(pmcraid_init); -module_exit(pmcraid_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/pmcraid.h b/ANDROID_3.4.5/drivers/scsi/pmcraid.h deleted file mode 100644 index e1d150f3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/pmcraid.h +++ /dev/null @@ -1,1095 +0,0 @@ -/* - * pmcraid.h -- PMC Sierra MaxRAID controller driver header file - * - * Written By: Anil Ravindranath - * PMC-Sierra Inc - * - * Copyright (C) 2008, 2009 PMC Sierra Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _PMCRAID_H -#define _PMCRAID_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* - * Driver name : string representing the driver name - * Device file : /dev file to be used for management interfaces - * Driver version: version string in major_version.minor_version.patch format - * Driver date : date information in "Mon dd yyyy" format - */ -#define PMCRAID_DRIVER_NAME "PMC MaxRAID" -#define PMCRAID_DEVFILE "pmcsas" -#define PMCRAID_DRIVER_VERSION "1.0.3" - -#define PMCRAID_FW_VERSION_1 0x002 - -/* Maximum number of adapters supported by current version of the driver */ -#define PMCRAID_MAX_ADAPTERS 1024 - -/* Bit definitions as per firmware, bit position [0][1][2].....[31] */ -#define PMC_BIT8(n) (1 << (7-n)) -#define PMC_BIT16(n) (1 << (15-n)) -#define PMC_BIT32(n) (1 << (31-n)) - -/* PMC PCI vendor ID and device ID values */ -#define PCI_VENDOR_ID_PMC 0x11F8 -#define PCI_DEVICE_ID_PMC_MAXRAID 0x5220 - -/* - * MAX_CMD : maximum commands that can be outstanding with IOA - * MAX_IO_CMD : command blocks available for IO commands - * MAX_HCAM_CMD : command blocks avaibale for HCAMS - * MAX_INTERNAL_CMD : command blocks avaible for internal commands like reset - */ -#define PMCRAID_MAX_CMD 1024 -#define PMCRAID_MAX_IO_CMD 1020 -#define PMCRAID_MAX_HCAM_CMD 2 -#define PMCRAID_MAX_INTERNAL_CMD 2 - -/* MAX_IOADLS : max number of scatter-gather lists supported by IOA - * IOADLS_INTERNAL : number of ioadls included as part of IOARCB. - * IOADLS_EXTERNAL : number of ioadls allocated external to IOARCB - */ -#define PMCRAID_IOADLS_INTERNAL 27 -#define PMCRAID_IOADLS_EXTERNAL 37 -#define PMCRAID_MAX_IOADLS PMCRAID_IOADLS_INTERNAL - -/* HRRQ_ENTRY_SIZE : size of hrrq buffer - * IOARCB_ALIGNMENT : alignment required for IOARCB - * IOADL_ALIGNMENT : alignment requirement for IOADLs - * MSIX_VECTORS : number of MSIX vectors supported - */ -#define HRRQ_ENTRY_SIZE sizeof(__le32) -#define PMCRAID_IOARCB_ALIGNMENT 32 -#define PMCRAID_IOADL_ALIGNMENT 16 -#define PMCRAID_IOASA_ALIGNMENT 4 -#define PMCRAID_NUM_MSIX_VECTORS 16 - -/* various other limits */ -#define PMCRAID_VENDOR_ID_LEN 8 -#define PMCRAID_PRODUCT_ID_LEN 16 -#define PMCRAID_SERIAL_NUM_LEN 8 -#define PMCRAID_LUN_LEN 8 -#define PMCRAID_MAX_CDB_LEN 16 -#define PMCRAID_DEVICE_ID_LEN 8 -#define PMCRAID_SENSE_DATA_LEN 256 -#define PMCRAID_ADD_CMD_PARAM_LEN 48 - -#define PMCRAID_MAX_BUS_TO_SCAN 1 -#define PMCRAID_MAX_NUM_TARGETS_PER_BUS 256 -#define PMCRAID_MAX_NUM_LUNS_PER_TARGET 8 - -/* IOA bus/target/lun number of IOA resources */ -#define PMCRAID_IOA_BUS_ID 0xfe -#define PMCRAID_IOA_TARGET_ID 0xff -#define PMCRAID_IOA_LUN_ID 0xff -#define PMCRAID_VSET_BUS_ID 0x1 -#define PMCRAID_VSET_LUN_ID 0x0 -#define PMCRAID_PHYS_BUS_ID 0x0 -#define PMCRAID_VIRTUAL_ENCL_BUS_ID 0x8 -#define PMCRAID_MAX_VSET_TARGETS 0x7F -#define PMCRAID_MAX_VSET_LUNS_PER_TARGET 8 - -#define PMCRAID_IOA_MAX_SECTORS 32767 -#define PMCRAID_VSET_MAX_SECTORS 512 -#define PMCRAID_MAX_CMD_PER_LUN 254 - -/* Number of configuration table entries (resources), includes 1 FP, - * 1 Enclosure device - */ -#define PMCRAID_MAX_RESOURCES 256 - -/* Adapter Commands used by driver */ -#define PMCRAID_QUERY_RESOURCE_STATE 0xC2 -#define PMCRAID_RESET_DEVICE 0xC3 -/* options to select reset target */ -#define ENABLE_RESET_MODIFIER 0x80 -#define RESET_DEVICE_LUN 0x40 -#define RESET_DEVICE_TARGET 0x20 -#define RESET_DEVICE_BUS 0x10 - -#define PMCRAID_IDENTIFY_HRRQ 0xC4 -#define PMCRAID_QUERY_IOA_CONFIG 0xC5 -#define PMCRAID_QUERY_CMD_STATUS 0xCB -#define PMCRAID_ABORT_CMD 0xC7 - -/* CANCEL ALL command, provides option for setting SYNC_COMPLETE - * on the target resources for which commands got cancelled - */ -#define PMCRAID_CANCEL_ALL_REQUESTS 0xCE -#define PMCRAID_SYNC_COMPLETE_AFTER_CANCEL PMC_BIT8(0) - -/* HCAM command and types of HCAM supported by IOA */ -#define PMCRAID_HOST_CONTROLLED_ASYNC 0xCF -#define PMCRAID_HCAM_CODE_CONFIG_CHANGE 0x01 -#define PMCRAID_HCAM_CODE_LOG_DATA 0x02 - -/* IOA shutdown command and various shutdown types */ -#define PMCRAID_IOA_SHUTDOWN 0xF7 -#define PMCRAID_SHUTDOWN_NORMAL 0x00 -#define PMCRAID_SHUTDOWN_PREPARE_FOR_NORMAL 0x40 -#define PMCRAID_SHUTDOWN_NONE 0x100 -#define PMCRAID_SHUTDOWN_ABBREV 0x80 - -/* SET SUPPORTED DEVICES command and the option to select all the - * devices to be supported - */ -#define PMCRAID_SET_SUPPORTED_DEVICES 0xFB -#define ALL_DEVICES_SUPPORTED PMC_BIT8(0) - -/* This option is used with SCSI WRITE_BUFFER command */ -#define PMCRAID_WR_BUF_DOWNLOAD_AND_SAVE 0x05 - -/* IOASC Codes used by driver */ -#define PMCRAID_IOASC_SENSE_MASK 0xFFFFFF00 -#define PMCRAID_IOASC_SENSE_KEY(ioasc) ((ioasc) >> 24) -#define PMCRAID_IOASC_SENSE_CODE(ioasc) (((ioasc) & 0x00ff0000) >> 16) -#define PMCRAID_IOASC_SENSE_QUAL(ioasc) (((ioasc) & 0x0000ff00) >> 8) -#define PMCRAID_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff) - -#define PMCRAID_IOASC_GOOD_COMPLETION 0x00000000 -#define PMCRAID_IOASC_GC_IOARCB_NOTFOUND 0x005A0000 -#define PMCRAID_IOASC_NR_INIT_CMD_REQUIRED 0x02040200 -#define PMCRAID_IOASC_NR_IOA_RESET_REQUIRED 0x02048000 -#define PMCRAID_IOASC_NR_SYNC_REQUIRED 0x023F0000 -#define PMCRAID_IOASC_ME_READ_ERROR_NO_REALLOC 0x03110C00 -#define PMCRAID_IOASC_HW_CANNOT_COMMUNICATE 0x04050000 -#define PMCRAID_IOASC_HW_DEVICE_TIMEOUT 0x04080100 -#define PMCRAID_IOASC_HW_DEVICE_BUS_STATUS_ERROR 0x04448500 -#define PMCRAID_IOASC_HW_IOA_RESET_REQUIRED 0x04448600 -#define PMCRAID_IOASC_IR_INVALID_RESOURCE_HANDLE 0x05250000 -#define PMCRAID_IOASC_AC_TERMINATED_BY_HOST 0x0B5A0000 -#define PMCRAID_IOASC_UA_BUS_WAS_RESET 0x06290000 -#define PMCRAID_IOASC_TIME_STAMP_OUT_OF_SYNC 0x06908B00 -#define PMCRAID_IOASC_UA_BUS_WAS_RESET_BY_OTHER 0x06298000 - -/* Driver defined IOASCs */ -#define PMCRAID_IOASC_IOA_WAS_RESET 0x10000001 -#define PMCRAID_IOASC_PCI_ACCESS_ERROR 0x10000002 - -/* Various timeout values (in milliseconds) used. If any of these are chip - * specific, move them to pmcraid_chip_details structure. - */ -#define PMCRAID_PCI_DEASSERT_TIMEOUT 2000 -#define PMCRAID_BIST_TIMEOUT 2000 -#define PMCRAID_AENWAIT_TIMEOUT 5000 -#define PMCRAID_TRANSOP_TIMEOUT 60000 - -#define PMCRAID_RESET_TIMEOUT (2 * HZ) -#define PMCRAID_CHECK_FOR_RESET_TIMEOUT ((HZ / 10)) -#define PMCRAID_VSET_IO_TIMEOUT (60 * HZ) -#define PMCRAID_INTERNAL_TIMEOUT (60 * HZ) -#define PMCRAID_SHUTDOWN_TIMEOUT (150 * HZ) -#define PMCRAID_RESET_BUS_TIMEOUT (60 * HZ) -#define PMCRAID_RESET_HOST_TIMEOUT (150 * HZ) -#define PMCRAID_REQUEST_SENSE_TIMEOUT (30 * HZ) -#define PMCRAID_SET_SUP_DEV_TIMEOUT (2 * 60 * HZ) - -/* structure to represent a scatter-gather element (IOADL descriptor) */ -struct pmcraid_ioadl_desc { - __le64 address; - __le32 data_len; - __u8 reserved[3]; - __u8 flags; -} __attribute__((packed, aligned(PMCRAID_IOADL_ALIGNMENT))); - -/* pmcraid_ioadl_desc.flags values */ -#define IOADL_FLAGS_CHAINED PMC_BIT8(0) -#define IOADL_FLAGS_LAST_DESC PMC_BIT8(1) -#define IOADL_FLAGS_READ_LAST PMC_BIT8(1) -#define IOADL_FLAGS_WRITE_LAST PMC_BIT8(1) - - -/* additional IOARCB data which can be CDB or additional request parameters - * or list of IOADLs. Firmware supports max of 512 bytes for IOARCB, hence then - * number of IOADLs are limted to 27. In case they are more than 27, they will - * be used in chained form - */ -struct pmcraid_ioarcb_add_data { - union { - struct pmcraid_ioadl_desc ioadl[PMCRAID_IOADLS_INTERNAL]; - __u8 add_cmd_params[PMCRAID_ADD_CMD_PARAM_LEN]; - } u; -}; - -/* - * IOA Request Control Block - */ -struct pmcraid_ioarcb { - __le64 ioarcb_bus_addr; - __le32 resource_handle; - __le32 response_handle; - __le64 ioadl_bus_addr; - __le32 ioadl_length; - __le32 data_transfer_length; - __le64 ioasa_bus_addr; - __le16 ioasa_len; - __le16 cmd_timeout; - __le16 add_cmd_param_offset; - __le16 add_cmd_param_length; - __le32 reserved1[2]; - __le32 reserved2; - __u8 request_type; - __u8 request_flags0; - __u8 request_flags1; - __u8 hrrq_id; - __u8 cdb[PMCRAID_MAX_CDB_LEN]; - struct pmcraid_ioarcb_add_data add_data; -} __attribute__((packed, aligned(PMCRAID_IOARCB_ALIGNMENT))); - -/* well known resource handle values */ -#define PMCRAID_IOA_RES_HANDLE 0xffffffff -#define PMCRAID_INVALID_RES_HANDLE 0 - -/* pmcraid_ioarcb.request_type values */ -#define REQ_TYPE_SCSI 0x00 -#define REQ_TYPE_IOACMD 0x01 -#define REQ_TYPE_HCAM 0x02 - -/* pmcraid_ioarcb.flags0 values */ -#define TRANSFER_DIR_WRITE PMC_BIT8(0) -#define INHIBIT_UL_CHECK PMC_BIT8(2) -#define SYNC_OVERRIDE PMC_BIT8(3) -#define SYNC_COMPLETE PMC_BIT8(4) -#define NO_LINK_DESCS PMC_BIT8(5) - -/* pmcraid_ioarcb.flags1 values */ -#define DELAY_AFTER_RESET PMC_BIT8(0) -#define TASK_TAG_SIMPLE 0x10 -#define TASK_TAG_ORDERED 0x20 -#define TASK_TAG_QUEUE_HEAD 0x30 - -/* toggle bit offset in response handle */ -#define HRRQ_TOGGLE_BIT 0x01 -#define HRRQ_RESPONSE_BIT 0x02 - -/* IOA Status Area */ -struct pmcraid_ioasa_vset { - __le32 failing_lba_hi; - __le32 failing_lba_lo; - __le32 reserved; -} __attribute__((packed, aligned(4))); - -struct pmcraid_ioasa { - __le32 ioasc; - __le16 returned_status_length; - __le16 available_status_length; - __le32 residual_data_length; - __le32 ilid; - __le32 fd_ioasc; - __le32 fd_res_address; - __le32 fd_res_handle; - __le32 reserved; - - /* resource specific sense information */ - union { - struct pmcraid_ioasa_vset vset; - } u; - - /* IOA autosense data */ - __le16 auto_sense_length; - __le16 error_data_length; - __u8 sense_data[PMCRAID_SENSE_DATA_LEN]; -} __attribute__((packed, aligned(4))); - -#define PMCRAID_DRIVER_ILID 0xffffffff - -/* Config Table Entry per Resource */ -struct pmcraid_config_table_entry { - __u8 resource_type; - __u8 bus_protocol; - __le16 array_id; - __u8 common_flags0; - __u8 common_flags1; - __u8 unique_flags0; - __u8 unique_flags1; /*also used as vset target_id */ - __le32 resource_handle; - __le32 resource_address; - __u8 device_id[PMCRAID_DEVICE_ID_LEN]; - __u8 lun[PMCRAID_LUN_LEN]; -} __attribute__((packed, aligned(4))); - -/* extended configuration table sizes are also of 32 bytes in size */ -struct pmcraid_config_table_entry_ext { - struct pmcraid_config_table_entry cfgte; -}; - -/* resource types (config_table_entry.resource_type values) */ -#define RES_TYPE_AF_DASD 0x00 -#define RES_TYPE_GSCSI 0x01 -#define RES_TYPE_VSET 0x02 -#define RES_TYPE_IOA_FP 0xFF - -#define RES_IS_IOA(res) ((res).resource_type == RES_TYPE_IOA_FP) -#define RES_IS_GSCSI(res) ((res).resource_type == RES_TYPE_GSCSI) -#define RES_IS_VSET(res) ((res).resource_type == RES_TYPE_VSET) -#define RES_IS_AFDASD(res) ((res).resource_type == RES_TYPE_AF_DASD) - -/* bus_protocol values used by driver */ -#define RES_TYPE_VENCLOSURE 0x8 - -/* config_table_entry.common_flags0 */ -#define MULTIPATH_RESOURCE PMC_BIT32(0) - -/* unique_flags1 */ -#define IMPORT_MODE_MANUAL PMC_BIT8(0) - -/* well known resource handle values */ -#define RES_HANDLE_IOA 0xFFFFFFFF -#define RES_HANDLE_NONE 0x00000000 - -/* well known resource address values */ -#define RES_ADDRESS_IOAFP 0xFEFFFFFF -#define RES_ADDRESS_INVALID 0xFFFFFFFF - -/* BUS/TARGET/LUN values from resource_addrr */ -#define RES_BUS(res_addr) (le32_to_cpu(res_addr) & 0xFF) -#define RES_TARGET(res_addr) ((le32_to_cpu(res_addr) >> 16) & 0xFF) -#define RES_LUN(res_addr) 0x0 - -/* configuration table structure */ -struct pmcraid_config_table { - __le16 num_entries; - __u8 table_format; - __u8 reserved1; - __u8 flags; - __u8 reserved2[11]; - union { - struct pmcraid_config_table_entry - entries[PMCRAID_MAX_RESOURCES]; - struct pmcraid_config_table_entry_ext - entries_ext[PMCRAID_MAX_RESOURCES]; - }; -} __attribute__((packed, aligned(4))); - -/* config_table.flags value */ -#define MICROCODE_UPDATE_REQUIRED PMC_BIT32(0) - -/* - * HCAM format - */ -#define PMCRAID_HOSTRCB_LDNSIZE 4056 - -/* Error log notification format */ -struct pmcraid_hostrcb_error { - __le32 fd_ioasc; - __le32 fd_ra; - __le32 fd_rh; - __le32 prc; - union { - __u8 data[PMCRAID_HOSTRCB_LDNSIZE]; - } u; -} __attribute__ ((packed, aligned(4))); - -struct pmcraid_hcam_hdr { - __u8 op_code; - __u8 notification_type; - __u8 notification_lost; - __u8 flags; - __u8 overlay_id; - __u8 reserved1[3]; - __le32 ilid; - __le32 timestamp1; - __le32 timestamp2; - __le32 data_len; -} __attribute__((packed, aligned(4))); - -#define PMCRAID_AEN_GROUP 0x3 - -struct pmcraid_hcam_ccn { - struct pmcraid_hcam_hdr header; - struct pmcraid_config_table_entry cfg_entry; - struct pmcraid_config_table_entry cfg_entry_old; -} __attribute__((packed, aligned(4))); - -#define PMCRAID_CCN_EXT_SIZE 3944 -struct pmcraid_hcam_ccn_ext { - struct pmcraid_hcam_hdr header; - struct pmcraid_config_table_entry_ext cfg_entry; - struct pmcraid_config_table_entry_ext cfg_entry_old; - __u8 reserved[PMCRAID_CCN_EXT_SIZE]; -} __attribute__((packed, aligned(4))); - -struct pmcraid_hcam_ldn { - struct pmcraid_hcam_hdr header; - struct pmcraid_hostrcb_error error_log; -} __attribute__((packed, aligned(4))); - -/* pmcraid_hcam.op_code values */ -#define HOSTRCB_TYPE_CCN 0xE1 -#define HOSTRCB_TYPE_LDN 0xE2 - -/* pmcraid_hcam.notification_type values */ -#define NOTIFICATION_TYPE_ENTRY_CHANGED 0x0 -#define NOTIFICATION_TYPE_ENTRY_NEW 0x1 -#define NOTIFICATION_TYPE_ENTRY_DELETED 0x2 -#define NOTIFICATION_TYPE_STATE_CHANGE 0x3 -#define NOTIFICATION_TYPE_ENTRY_STATECHANGED 0x4 -#define NOTIFICATION_TYPE_ERROR_LOG 0x10 -#define NOTIFICATION_TYPE_INFORMATION_LOG 0x11 - -#define HOSTRCB_NOTIFICATIONS_LOST PMC_BIT8(0) - -/* pmcraid_hcam.flags values */ -#define HOSTRCB_INTERNAL_OP_ERROR PMC_BIT8(0) -#define HOSTRCB_ERROR_RESPONSE_SENT PMC_BIT8(1) - -/* pmcraid_hcam.overlay_id values */ -#define HOSTRCB_OVERLAY_ID_08 0x08 -#define HOSTRCB_OVERLAY_ID_09 0x09 -#define HOSTRCB_OVERLAY_ID_11 0x11 -#define HOSTRCB_OVERLAY_ID_12 0x12 -#define HOSTRCB_OVERLAY_ID_13 0x13 -#define HOSTRCB_OVERLAY_ID_14 0x14 -#define HOSTRCB_OVERLAY_ID_16 0x16 -#define HOSTRCB_OVERLAY_ID_17 0x17 -#define HOSTRCB_OVERLAY_ID_20 0x20 -#define HOSTRCB_OVERLAY_ID_FF 0xFF - -/* Implementation specific card details */ -struct pmcraid_chip_details { - /* hardware register offsets */ - unsigned long ioastatus; - unsigned long ioarrin; - unsigned long mailbox; - unsigned long global_intr_mask; - unsigned long ioa_host_intr; - unsigned long ioa_host_msix_intr; - unsigned long ioa_host_intr_clr; - unsigned long ioa_host_mask; - unsigned long ioa_host_mask_clr; - unsigned long host_ioa_intr; - unsigned long host_ioa_intr_clr; - - /* timeout used during transitional to operational state */ - unsigned long transop_timeout; -}; - -/* IOA to HOST doorbells (interrupts) */ -#define INTRS_TRANSITION_TO_OPERATIONAL PMC_BIT32(0) -#define INTRS_IOARCB_TRANSFER_FAILED PMC_BIT32(3) -#define INTRS_IOA_UNIT_CHECK PMC_BIT32(4) -#define INTRS_NO_HRRQ_FOR_CMD_RESPONSE PMC_BIT32(5) -#define INTRS_CRITICAL_OP_IN_PROGRESS PMC_BIT32(6) -#define INTRS_IO_DEBUG_ACK PMC_BIT32(7) -#define INTRS_IOARRIN_LOST PMC_BIT32(27) -#define INTRS_SYSTEM_BUS_MMIO_ERROR PMC_BIT32(28) -#define INTRS_IOA_PROCESSOR_ERROR PMC_BIT32(29) -#define INTRS_HRRQ_VALID PMC_BIT32(30) -#define INTRS_OPERATIONAL_STATUS PMC_BIT32(0) -#define INTRS_ALLOW_MSIX_VECTOR0 PMC_BIT32(31) - -/* Host to IOA Doorbells */ -#define DOORBELL_RUNTIME_RESET PMC_BIT32(1) -#define DOORBELL_IOA_RESET_ALERT PMC_BIT32(7) -#define DOORBELL_IOA_DEBUG_ALERT PMC_BIT32(9) -#define DOORBELL_ENABLE_DESTRUCTIVE_DIAGS PMC_BIT32(8) -#define DOORBELL_IOA_START_BIST PMC_BIT32(23) -#define DOORBELL_INTR_MODE_MSIX PMC_BIT32(25) -#define DOORBELL_INTR_MSIX_CLR PMC_BIT32(26) -#define DOORBELL_RESET_IOA PMC_BIT32(31) - -/* Global interrupt mask register value */ -#define GLOBAL_INTERRUPT_MASK 0x5ULL - -#define PMCRAID_ERROR_INTERRUPTS (INTRS_IOARCB_TRANSFER_FAILED | \ - INTRS_IOA_UNIT_CHECK | \ - INTRS_NO_HRRQ_FOR_CMD_RESPONSE | \ - INTRS_IOARRIN_LOST | \ - INTRS_SYSTEM_BUS_MMIO_ERROR | \ - INTRS_IOA_PROCESSOR_ERROR) - -#define PMCRAID_PCI_INTERRUPTS (PMCRAID_ERROR_INTERRUPTS | \ - INTRS_HRRQ_VALID | \ - INTRS_TRANSITION_TO_OPERATIONAL |\ - INTRS_ALLOW_MSIX_VECTOR0) - -/* control_block, associated with each of the commands contains IOARCB, IOADLs - * memory for IOASA. Additional 3 * 16 bytes are allocated in order to support - * additional request parameters (of max size 48) any command. - */ -struct pmcraid_control_block { - struct pmcraid_ioarcb ioarcb; - struct pmcraid_ioadl_desc ioadl[PMCRAID_IOADLS_EXTERNAL + 3]; - struct pmcraid_ioasa ioasa; -} __attribute__ ((packed, aligned(PMCRAID_IOARCB_ALIGNMENT))); - -/* pmcraid_sglist - Scatter-gather list allocated for passthrough ioctls - */ -struct pmcraid_sglist { - u32 order; - u32 num_sg; - u32 num_dma_sg; - u32 buffer_len; - struct scatterlist scatterlist[1]; -}; - -/* page D0 inquiry data of focal point resource */ -struct pmcraid_inquiry_data { - __u8 ph_dev_type; - __u8 page_code; - __u8 reserved1; - __u8 add_page_len; - __u8 length; - __u8 reserved2; - __le16 fw_version; - __u8 reserved3[16]; -}; - -#define PMCRAID_TIMESTAMP_LEN 12 -#define PMCRAID_REQ_TM_STR_LEN 6 -#define PMCRAID_SCSI_SET_TIMESTAMP 0xA4 -#define PMCRAID_SCSI_SERVICE_ACTION 0x0F - -struct pmcraid_timestamp_data { - __u8 reserved1[4]; - __u8 timestamp[PMCRAID_REQ_TM_STR_LEN]; /* current time value */ - __u8 reserved2[2]; -}; - -/* pmcraid_cmd - LLD representation of SCSI command */ -struct pmcraid_cmd { - - /* Ptr and bus address of DMA.able control block for this command */ - struct pmcraid_control_block *ioa_cb; - dma_addr_t ioa_cb_bus_addr; - dma_addr_t dma_handle; - - /* pointer to mid layer structure of SCSI commands */ - struct scsi_cmnd *scsi_cmd; - - struct list_head free_list; - struct completion wait_for_completion; - struct timer_list timer; /* needed for internal commands */ - u32 timeout; /* current timeout value */ - u32 index; /* index into the command list */ - u8 completion_req; /* for handling internal commands */ - u8 release; /* for handling completions */ - - void (*cmd_done) (struct pmcraid_cmd *); - struct pmcraid_instance *drv_inst; - - struct pmcraid_sglist *sglist; /* used for passthrough IOCTLs */ - - /* scratch used */ - union { - /* during reset sequence */ - unsigned long time_left; - struct pmcraid_resource_entry *res; - int hrrq_index; - - /* used during IO command error handling. Sense buffer - * for REQUEST SENSE command if firmware is not sending - * auto sense data - */ - struct { - u8 *sense_buffer; - dma_addr_t sense_buffer_dma; - }; - }; -}; - -/* - * Interrupt registers of IOA - */ -struct pmcraid_interrupts { - void __iomem *ioa_host_interrupt_reg; - void __iomem *ioa_host_msix_interrupt_reg; - void __iomem *ioa_host_interrupt_clr_reg; - void __iomem *ioa_host_interrupt_mask_reg; - void __iomem *ioa_host_interrupt_mask_clr_reg; - void __iomem *global_interrupt_mask_reg; - void __iomem *host_ioa_interrupt_reg; - void __iomem *host_ioa_interrupt_clr_reg; -}; - -/* ISR parameters LLD allocates (one for each MSI-X if enabled) vectors */ -struct pmcraid_isr_param { - struct pmcraid_instance *drv_inst; - u16 vector; /* allocated msi-x vector */ - u8 hrrq_id; /* hrrq entry index */ -}; - - -/* AEN message header sent as part of event data to applications */ -struct pmcraid_aen_msg { - u32 hostno; - u32 length; - u8 reserved[8]; - u8 data[0]; -}; - -/* Controller state event message type */ -struct pmcraid_state_msg { - struct pmcraid_aen_msg msg; - u32 ioa_state; -}; - -#define PMC_DEVICE_EVENT_RESET_START 0x11000000 -#define PMC_DEVICE_EVENT_RESET_SUCCESS 0x11000001 -#define PMC_DEVICE_EVENT_RESET_FAILED 0x11000002 -#define PMC_DEVICE_EVENT_SHUTDOWN_START 0x11000003 -#define PMC_DEVICE_EVENT_SHUTDOWN_SUCCESS 0x11000004 -#define PMC_DEVICE_EVENT_SHUTDOWN_FAILED 0x11000005 - -struct pmcraid_hostrcb { - struct pmcraid_instance *drv_inst; - struct pmcraid_aen_msg *msg; - struct pmcraid_hcam_hdr *hcam; /* pointer to hcam buffer */ - struct pmcraid_cmd *cmd; /* pointer to command block used */ - dma_addr_t baddr; /* system address of hcam buffer */ - atomic_t ignore; /* process HCAM response ? */ -}; - -#define PMCRAID_AEN_HDR_SIZE sizeof(struct pmcraid_aen_msg) - - - -/* - * Per adapter structure maintained by LLD - */ -struct pmcraid_instance { - /* Array of allowed-to-be-exposed resources, initialized from - * Configutation Table, later updated with CCNs - */ - struct pmcraid_resource_entry *res_entries; - - struct list_head free_res_q; /* res_entries lists for easy lookup */ - struct list_head used_res_q; /* List of to be exposed resources */ - spinlock_t resource_lock; /* spinlock to protect resource list */ - - void __iomem *mapped_dma_addr; - void __iomem *ioa_status; /* Iomapped IOA status register */ - void __iomem *mailbox; /* Iomapped mailbox register */ - void __iomem *ioarrin; /* IOmapped IOARR IN register */ - - struct pmcraid_interrupts int_regs; - struct pmcraid_chip_details *chip_cfg; - - /* HostRCBs needed for HCAM */ - struct pmcraid_hostrcb ldn; - struct pmcraid_hostrcb ccn; - struct pmcraid_state_msg scn; /* controller state change msg */ - - - /* Bus address of start of HRRQ */ - dma_addr_t hrrq_start_bus_addr[PMCRAID_NUM_MSIX_VECTORS]; - - /* Pointer to 1st entry of HRRQ */ - __be32 *hrrq_start[PMCRAID_NUM_MSIX_VECTORS]; - - /* Pointer to last entry of HRRQ */ - __be32 *hrrq_end[PMCRAID_NUM_MSIX_VECTORS]; - - /* Pointer to current pointer of hrrq */ - __be32 *hrrq_curr[PMCRAID_NUM_MSIX_VECTORS]; - - /* Lock for HRRQ access */ - spinlock_t hrrq_lock[PMCRAID_NUM_MSIX_VECTORS]; - - struct pmcraid_inquiry_data *inq_data; - dma_addr_t inq_data_baddr; - - struct pmcraid_timestamp_data *timestamp_data; - dma_addr_t timestamp_data_baddr; - - /* size of configuration table entry, varies based on the firmware */ - u32 config_table_entry_size; - - /* Expected toggle bit at host */ - u8 host_toggle_bit[PMCRAID_NUM_MSIX_VECTORS]; - - - /* Wait Q for threads to wait for Reset IOA completion */ - wait_queue_head_t reset_wait_q; - struct pmcraid_cmd *reset_cmd; - - /* structures for supporting SIGIO based AEN. */ - struct fasync_struct *aen_queue; - struct mutex aen_queue_lock; /* lock for aen subscribers list */ - struct cdev cdev; - - struct Scsi_Host *host; /* mid layer interface structure handle */ - struct pci_dev *pdev; /* PCI device structure handle */ - - /* No of Reset IOA retries . IOA marked dead if threshold exceeds */ - u8 ioa_reset_attempts; -#define PMCRAID_RESET_ATTEMPTS 3 - - u8 current_log_level; /* default level for logging IOASC errors */ - - u8 num_hrrq; /* Number of interrupt vectors allocated */ - u8 interrupt_mode; /* current interrupt mode legacy or msix */ - dev_t dev; /* Major-Minor numbers for Char device */ - - /* Used as ISR handler argument */ - struct pmcraid_isr_param hrrq_vector[PMCRAID_NUM_MSIX_VECTORS]; - - /* Message id as filled in last fired IOARCB, used to identify HRRQ */ - atomic_t last_message_id; - - /* configuration table */ - struct pmcraid_config_table *cfg_table; - dma_addr_t cfg_table_bus_addr; - - /* structures related to command blocks */ - struct kmem_cache *cmd_cachep; /* cache for cmd blocks */ - struct pci_pool *control_pool; /* pool for control blocks */ - char cmd_pool_name[64]; /* name of cmd cache */ - char ctl_pool_name[64]; /* name of control cache */ - - struct pmcraid_cmd *cmd_list[PMCRAID_MAX_CMD]; - - struct list_head free_cmd_pool; - struct list_head pending_cmd_pool; - spinlock_t free_pool_lock; /* free pool lock */ - spinlock_t pending_pool_lock; /* pending pool lock */ - - /* Tasklet to handle deferred processing */ - struct tasklet_struct isr_tasklet[PMCRAID_NUM_MSIX_VECTORS]; - - /* Work-queue (Shared) for deferred reset processing */ - struct work_struct worker_q; - - /* No of IO commands pending with FW */ - atomic_t outstanding_cmds; - - /* should add/delete resources to mid-layer now ?*/ - atomic_t expose_resources; - - - - u32 ioa_state:4; /* For IOA Reset sequence FSM */ -#define IOA_STATE_OPERATIONAL 0x0 -#define IOA_STATE_UNKNOWN 0x1 -#define IOA_STATE_DEAD 0x2 -#define IOA_STATE_IN_SOFT_RESET 0x3 -#define IOA_STATE_IN_HARD_RESET 0x4 -#define IOA_STATE_IN_RESET_ALERT 0x5 -#define IOA_STATE_IN_BRINGDOWN 0x6 -#define IOA_STATE_IN_BRINGUP 0x7 - - u32 ioa_reset_in_progress:1; /* true if IOA reset is in progress */ - u32 ioa_hard_reset:1; /* TRUE if Hard Reset is needed */ - u32 ioa_unit_check:1; /* Indicates Unit Check condition */ - u32 ioa_bringdown:1; /* whether IOA needs to be brought down */ - u32 force_ioa_reset:1; /* force adapter reset ? */ - u32 reinit_cfg_table:1; /* reinit config table due to lost CCN */ - u32 ioa_shutdown_type:2;/* shutdown type used during reset */ -#define SHUTDOWN_NONE 0x0 -#define SHUTDOWN_NORMAL 0x1 -#define SHUTDOWN_ABBREV 0x2 - u32 timestamp_error:1; /* indicate set timestamp for out of sync */ - -}; - -/* LLD maintained resource entry structure */ -struct pmcraid_resource_entry { - struct list_head queue; /* link to "to be exposed" resources */ - union { - struct pmcraid_config_table_entry cfg_entry; - struct pmcraid_config_table_entry_ext cfg_entry_ext; - }; - struct scsi_device *scsi_dev; /* Link scsi_device structure */ - atomic_t read_failures; /* count of failed READ commands */ - atomic_t write_failures; /* count of failed WRITE commands */ - - /* To indicate add/delete/modify during CCN */ - u8 change_detected; -#define RES_CHANGE_ADD 0x1 /* add this to mid-layer */ -#define RES_CHANGE_DEL 0x2 /* remove this from mid-layer */ - - u8 reset_progress; /* Device is resetting */ - - /* - * When IOA asks for sync (i.e. IOASC = Not Ready, Sync Required), this - * flag will be set, mid layer will be asked to retry. In the next - * attempt, this flag will be checked in queuecommand() to set - * SYNC_COMPLETE flag in IOARCB (flag_0). - */ - u8 sync_reqd; - - /* target indicates the mapped target_id assigned to this resource if - * this is VSET resource. For non-VSET resources this will be un-used - * or zero - */ - u8 target; -}; - -/* Data structures used in IOASC error code logging */ -struct pmcraid_ioasc_error { - u32 ioasc_code; /* IOASC code */ - u8 log_level; /* default log level assignment. */ - char *error_string; -}; - -/* Initial log_level assignments for various IOASCs */ -#define IOASC_LOG_LEVEL_NONE 0x0 /* no logging */ -#define IOASC_LOG_LEVEL_MUST 0x1 /* must log: all high-severity errors */ -#define IOASC_LOG_LEVEL_HARD 0x2 /* optional – low severity errors */ - -/* Error information maintained by LLD. LLD initializes the pmcraid_error_table - * statically. - */ -static struct pmcraid_ioasc_error pmcraid_ioasc_error_table[] = { - {0x01180600, IOASC_LOG_LEVEL_HARD, - "Recovered Error, soft media error, sector reassignment suggested"}, - {0x015D0000, IOASC_LOG_LEVEL_HARD, - "Recovered Error, failure prediction threshold exceeded"}, - {0x015D9200, IOASC_LOG_LEVEL_HARD, - "Recovered Error, soft Cache Card Battery error threshold"}, - {0x015D9200, IOASC_LOG_LEVEL_HARD, - "Recovered Error, soft Cache Card Battery error threshold"}, - {0x02048000, IOASC_LOG_LEVEL_HARD, - "Not Ready, IOA Reset Required"}, - {0x02408500, IOASC_LOG_LEVEL_HARD, - "Not Ready, IOA microcode download required"}, - {0x03110B00, IOASC_LOG_LEVEL_HARD, - "Medium Error, data unreadable, reassignment suggested"}, - {0x03110C00, IOASC_LOG_LEVEL_MUST, - "Medium Error, data unreadable do not reassign"}, - {0x03310000, IOASC_LOG_LEVEL_HARD, - "Medium Error, media corrupted"}, - {0x04050000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, IOA can't communicate with device"}, - {0x04080000, IOASC_LOG_LEVEL_MUST, - "Hardware Error, device bus error"}, - {0x04088000, IOASC_LOG_LEVEL_MUST, - "Hardware Error, device bus is not functioning"}, - {0x04118000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, IOA reserved area data check"}, - {0x04118100, IOASC_LOG_LEVEL_HARD, - "Hardware Error, IOA reserved area invalid data pattern"}, - {0x04118200, IOASC_LOG_LEVEL_HARD, - "Hardware Error, IOA reserved area LRC error"}, - {0x04320000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, reassignment space exhausted"}, - {0x04330000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, data transfer underlength error"}, - {0x04330000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, data transfer overlength error"}, - {0x04418000, IOASC_LOG_LEVEL_MUST, - "Hardware Error, PCI bus error"}, - {0x04440000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, device error"}, - {0x04448200, IOASC_LOG_LEVEL_MUST, - "Hardware Error, IOA error"}, - {0x04448300, IOASC_LOG_LEVEL_HARD, - "Hardware Error, undefined device response"}, - {0x04448400, IOASC_LOG_LEVEL_HARD, - "Hardware Error, IOA microcode error"}, - {0x04448600, IOASC_LOG_LEVEL_HARD, - "Hardware Error, IOA reset required"}, - {0x04449200, IOASC_LOG_LEVEL_HARD, - "Hardware Error, hard Cache Fearuee Card Battery error"}, - {0x0444A000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, failed device altered"}, - {0x0444A200, IOASC_LOG_LEVEL_HARD, - "Hardware Error, data check after reassignment"}, - {0x0444A300, IOASC_LOG_LEVEL_HARD, - "Hardware Error, LRC error after reassignment"}, - {0x044A0000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, device bus error (msg/cmd phase)"}, - {0x04670400, IOASC_LOG_LEVEL_HARD, - "Hardware Error, new device can't be used"}, - {0x04678000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, invalid multiadapter configuration"}, - {0x04678100, IOASC_LOG_LEVEL_HARD, - "Hardware Error, incorrect connection between enclosures"}, - {0x04678200, IOASC_LOG_LEVEL_HARD, - "Hardware Error, connections exceed IOA design limits"}, - {0x04678300, IOASC_LOG_LEVEL_HARD, - "Hardware Error, incorrect multipath connection"}, - {0x04679000, IOASC_LOG_LEVEL_HARD, - "Hardware Error, command to LUN failed"}, - {0x064C8000, IOASC_LOG_LEVEL_HARD, - "Unit Attention, cache exists for missing/failed device"}, - {0x06670100, IOASC_LOG_LEVEL_HARD, - "Unit Attention, incompatible exposed mode device"}, - {0x06670600, IOASC_LOG_LEVEL_HARD, - "Unit Attention, attachment of logical unit failed"}, - {0x06678000, IOASC_LOG_LEVEL_HARD, - "Unit Attention, cables exceed connective design limit"}, - {0x06678300, IOASC_LOG_LEVEL_HARD, - "Unit Attention, incomplete multipath connection between" \ - "IOA and enclosure"}, - {0x06678400, IOASC_LOG_LEVEL_HARD, - "Unit Attention, incomplete multipath connection between" \ - "device and enclosure"}, - {0x06678500, IOASC_LOG_LEVEL_HARD, - "Unit Attention, incomplete multipath connection between" \ - "IOA and remote IOA"}, - {0x06678600, IOASC_LOG_LEVEL_HARD, - "Unit Attention, missing remote IOA"}, - {0x06679100, IOASC_LOG_LEVEL_HARD, - "Unit Attention, enclosure doesn't support required multipath" \ - "function"}, - {0x06698200, IOASC_LOG_LEVEL_HARD, - "Unit Attention, corrupt array parity detected on device"}, - {0x066B0200, IOASC_LOG_LEVEL_HARD, - "Unit Attention, array exposed"}, - {0x066B8200, IOASC_LOG_LEVEL_HARD, - "Unit Attention, exposed array is still protected"}, - {0x066B9200, IOASC_LOG_LEVEL_HARD, - "Unit Attention, Multipath redundancy level got worse"}, - {0x07270000, IOASC_LOG_LEVEL_HARD, - "Data Protect, device is read/write protected by IOA"}, - {0x07278000, IOASC_LOG_LEVEL_HARD, - "Data Protect, IOA doesn't support device attribute"}, - {0x07278100, IOASC_LOG_LEVEL_HARD, - "Data Protect, NVRAM mirroring prohibited"}, - {0x07278400, IOASC_LOG_LEVEL_HARD, - "Data Protect, array is short 2 or more devices"}, - {0x07278600, IOASC_LOG_LEVEL_HARD, - "Data Protect, exposed array is short a required device"}, - {0x07278700, IOASC_LOG_LEVEL_HARD, - "Data Protect, array members not at required addresses"}, - {0x07278800, IOASC_LOG_LEVEL_HARD, - "Data Protect, exposed mode device resource address conflict"}, - {0x07278900, IOASC_LOG_LEVEL_HARD, - "Data Protect, incorrect resource address of exposed mode device"}, - {0x07278A00, IOASC_LOG_LEVEL_HARD, - "Data Protect, Array is missing a device and parity is out of sync"}, - {0x07278B00, IOASC_LOG_LEVEL_HARD, - "Data Protect, maximum number of arrays already exist"}, - {0x07278C00, IOASC_LOG_LEVEL_HARD, - "Data Protect, cannot locate cache data for device"}, - {0x07278D00, IOASC_LOG_LEVEL_HARD, - "Data Protect, cache data exits for a changed device"}, - {0x07279100, IOASC_LOG_LEVEL_HARD, - "Data Protect, detection of a device requiring format"}, - {0x07279200, IOASC_LOG_LEVEL_HARD, - "Data Protect, IOA exceeds maximum number of devices"}, - {0x07279600, IOASC_LOG_LEVEL_HARD, - "Data Protect, missing array, volume set is not functional"}, - {0x07279700, IOASC_LOG_LEVEL_HARD, - "Data Protect, single device for a volume set"}, - {0x07279800, IOASC_LOG_LEVEL_HARD, - "Data Protect, missing multiple devices for a volume set"}, - {0x07279900, IOASC_LOG_LEVEL_HARD, - "Data Protect, maximum number of volument sets already exists"}, - {0x07279A00, IOASC_LOG_LEVEL_HARD, - "Data Protect, other volume set problem"}, -}; - -/* macros to help in debugging */ -#define pmcraid_err(...) \ - printk(KERN_ERR "MaxRAID: "__VA_ARGS__) - -#define pmcraid_info(...) \ - if (pmcraid_debug_log) \ - printk(KERN_INFO "MaxRAID: "__VA_ARGS__) - -/* check if given command is a SCSI READ or SCSI WRITE command */ -#define SCSI_READ_CMD 0x1 /* any of SCSI READ commands */ -#define SCSI_WRITE_CMD 0x2 /* any of SCSI WRITE commands */ -#define SCSI_CMD_TYPE(opcode) \ -({ u8 op = opcode; u8 __type = 0;\ - if (op == READ_6 || op == READ_10 || op == READ_12 || op == READ_16)\ - __type = SCSI_READ_CMD;\ - else if (op == WRITE_6 || op == WRITE_10 || op == WRITE_12 || \ - op == WRITE_16)\ - __type = SCSI_WRITE_CMD;\ - __type;\ -}) - -#define IS_SCSI_READ_WRITE(opcode) \ -({ u8 __type = SCSI_CMD_TYPE(opcode); \ - (__type == SCSI_READ_CMD || __type == SCSI_WRITE_CMD) ? 1 : 0;\ -}) - - -/* - * pmcraid_ioctl_header - definition of header structure that precedes all the - * buffers given as ioctl arguments. - * - * .signature : always ASCII string, "PMCRAID" - * .reserved : not used - * .buffer_length : length of the buffer following the header - */ -struct pmcraid_ioctl_header { - u8 signature[8]; - u32 reserved; - u32 buffer_length; -}; - -#define PMCRAID_IOCTL_SIGNATURE "PMCRAID" - -/* - * pmcraid_passthrough_ioctl_buffer - structure given as argument to - * passthrough(or firmware handled) IOCTL commands. Note that ioarcb requires - * 32-byte alignment so, it is necessary to pack this structure to avoid any - * holes between ioctl_header and passthrough buffer - * - * .ioactl_header : ioctl header - * .ioarcb : filled-up ioarcb buffer, driver always reads this buffer - * .ioasa : buffer for ioasa, driver fills this with IOASA from firmware - * .request_buffer: The I/O buffer (flat), driver reads/writes to this based on - * the transfer directions passed in ioarcb.flags0. Contents - * of this buffer are valid only when ioarcb.data_transfer_len - * is not zero. - */ -struct pmcraid_passthrough_ioctl_buffer { - struct pmcraid_ioctl_header ioctl_header; - struct pmcraid_ioarcb ioarcb; - struct pmcraid_ioasa ioasa; - u8 request_buffer[1]; -} __attribute__ ((packed)); - -/* - * keys to differentiate between driver handled IOCTLs and passthrough - * IOCTLs passed to IOA. driver determines the ioctl type using macro - * _IOC_TYPE - */ -#define PMCRAID_DRIVER_IOCTL 'D' -#define PMCRAID_PASSTHROUGH_IOCTL 'F' - -#define DRV_IOCTL(n, size) \ - _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_DRIVER_IOCTL, (n), (size)) - -#define FMW_IOCTL(n, size) \ - _IOC(_IOC_READ|_IOC_WRITE, PMCRAID_PASSTHROUGH_IOCTL, (n), (size)) - -/* - * _ARGSIZE: macro that gives size of the argument type passed to an IOCTL cmd. - * This is to facilitate applications avoiding un-necessary memory allocations. - * For example, most of driver handled ioctls do not require ioarcb, ioasa. - */ -#define _ARGSIZE(arg) (sizeof(struct pmcraid_ioctl_header) + sizeof(arg)) - -/* Driver handled IOCTL command definitions */ - -#define PMCRAID_IOCTL_RESET_ADAPTER \ - DRV_IOCTL(5, sizeof(struct pmcraid_ioctl_header)) - -/* passthrough/firmware handled commands */ -#define PMCRAID_IOCTL_PASSTHROUGH_COMMAND \ - FMW_IOCTL(1, sizeof(struct pmcraid_passthrough_ioctl_buffer)) - -#define PMCRAID_IOCTL_DOWNLOAD_MICROCODE \ - FMW_IOCTL(2, sizeof(struct pmcraid_passthrough_ioctl_buffer)) - - -#endif /* _PMCRAID_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/ppa.c b/ANDROID_3.4.5/drivers/scsi/ppa.c deleted file mode 100644 index d164c963..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ppa.c +++ /dev/null @@ -1,1148 +0,0 @@ -/* ppa.c -- low level driver for the IOMEGA PPA3 - * parallel port SCSI host adapter. - * - * (The PPA3 is the embedded controller in the ZIP drive.) - * - * (c) 1995,1996 Grant R. Guenther, grant@torque.net, - * under the terms of the GNU General Public License. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - - -static void ppa_reset_pulse(unsigned int base); - -typedef struct { - struct pardevice *dev; /* Parport device entry */ - int base; /* Actual port address */ - int mode; /* Transfer mode */ - struct scsi_cmnd *cur_cmd; /* Current queued command */ - struct delayed_work ppa_tq; /* Polling interrupt stuff */ - unsigned long jstart; /* Jiffies at start */ - unsigned long recon_tmo; /* How many usecs to wait for reconnection (6th bit) */ - unsigned int failed:1; /* Failure flag */ - unsigned wanted:1; /* Parport sharing busy flag */ - wait_queue_head_t *waiting; - struct Scsi_Host *host; - struct list_head list; -} ppa_struct; - -#include "ppa.h" - -static inline ppa_struct *ppa_dev(struct Scsi_Host *host) -{ - return *(ppa_struct **)&host->hostdata; -} - -static DEFINE_SPINLOCK(arbitration_lock); - -static void got_it(ppa_struct *dev) -{ - dev->base = dev->dev->port->base; - if (dev->cur_cmd) - dev->cur_cmd->SCp.phase = 1; - else - wake_up(dev->waiting); -} - -static void ppa_wakeup(void *ref) -{ - ppa_struct *dev = (ppa_struct *) ref; - unsigned long flags; - - spin_lock_irqsave(&arbitration_lock, flags); - if (dev->wanted) { - parport_claim(dev->dev); - got_it(dev); - dev->wanted = 0; - } - spin_unlock_irqrestore(&arbitration_lock, flags); - return; -} - -static int ppa_pb_claim(ppa_struct *dev) -{ - unsigned long flags; - int res = 1; - spin_lock_irqsave(&arbitration_lock, flags); - if (parport_claim(dev->dev) == 0) { - got_it(dev); - res = 0; - } - dev->wanted = res; - spin_unlock_irqrestore(&arbitration_lock, flags); - return res; -} - -static void ppa_pb_dismiss(ppa_struct *dev) -{ - unsigned long flags; - int wanted; - spin_lock_irqsave(&arbitration_lock, flags); - wanted = dev->wanted; - dev->wanted = 0; - spin_unlock_irqrestore(&arbitration_lock, flags); - if (!wanted) - parport_release(dev->dev); -} - -static inline void ppa_pb_release(ppa_struct *dev) -{ - parport_release(dev->dev); -} - -/* - * Start of Chipset kludges - */ - -/* This is to give the ppa driver a way to modify the timings (and other - * parameters) by writing to the /proc/scsi/ppa/0 file. - * Very simple method really... (To simple, no error checking :( ) - * Reason: Kernel hackers HATE having to unload and reload modules for - * testing... - * Also gives a method to use a script to obtain optimum timings (TODO) - */ - -static inline int ppa_proc_write(ppa_struct *dev, char *buffer, int length) -{ - unsigned long x; - - if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) { - x = simple_strtoul(buffer + 5, NULL, 0); - dev->mode = x; - return length; - } - if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) { - x = simple_strtoul(buffer + 10, NULL, 0); - dev->recon_tmo = x; - printk(KERN_INFO "ppa: recon_tmo set to %ld\n", x); - return length; - } - printk(KERN_WARNING "ppa /proc: invalid variable\n"); - return -EINVAL; -} - -static int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout) -{ - int len = 0; - ppa_struct *dev = ppa_dev(host); - - if (inout) - return ppa_proc_write(dev, buffer, length); - - len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION); - len += - sprintf(buffer + len, "Parport : %s\n", - dev->dev->port->name); - len += - sprintf(buffer + len, "Mode : %s\n", - PPA_MODE_STRING[dev->mode]); -#if PPA_DEBUG > 0 - len += - sprintf(buffer + len, "recon_tmo : %lu\n", dev->recon_tmo); -#endif - - /* Request for beyond end of buffer */ - if (offset > length) - return 0; - - *start = buffer + offset; - len -= offset; - if (len > length) - len = length; - return len; -} - -static int device_check(ppa_struct *dev); - -#if PPA_DEBUG > 0 -#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\ - y, __func__, __LINE__); ppa_fail_func(x,y); -static inline void ppa_fail_func(ppa_struct *dev, int error_code) -#else -static inline void ppa_fail(ppa_struct *dev, int error_code) -#endif -{ - /* If we fail a device then we trash status / message bytes */ - if (dev->cur_cmd) { - dev->cur_cmd->result = error_code << 16; - dev->failed = 1; - } -} - -/* - * Wait for the high bit to be set. - * - * In principle, this could be tied to an interrupt, but the adapter - * doesn't appear to be designed to support interrupts. We spin on - * the 0x80 ready bit. - */ -static unsigned char ppa_wait(ppa_struct *dev) -{ - int k; - unsigned short ppb = dev->base; - unsigned char r; - - k = PPA_SPIN_TMO; - /* Wait for bit 6 and 7 - PJC */ - for (r = r_str(ppb); ((r & 0xc0) != 0xc0) && (k); k--) { - udelay(1); - r = r_str(ppb); - } - - /* - * return some status information. - * Semantics: 0xc0 = ZIP wants more data - * 0xd0 = ZIP wants to send more data - * 0xe0 = ZIP is expecting SCSI command data - * 0xf0 = end of transfer, ZIP is sending status - */ - if (k) - return (r & 0xf0); - - /* Counter expired - Time out occurred */ - ppa_fail(dev, DID_TIME_OUT); - printk(KERN_WARNING "ppa timeout in ppa_wait\n"); - return 0; /* command timed out */ -} - -/* - * Clear EPP Timeout Bit - */ -static inline void epp_reset(unsigned short ppb) -{ - int i; - - i = r_str(ppb); - w_str(ppb, i); - w_str(ppb, i & 0xfe); -} - -/* - * Wait for empty ECP fifo (if we are in ECP fifo mode only) - */ -static inline void ecp_sync(ppa_struct *dev) -{ - int i, ppb_hi = dev->dev->port->base_hi; - - if (ppb_hi == 0) - return; - - if ((r_ecr(ppb_hi) & 0xe0) == 0x60) { /* mode 011 == ECP fifo mode */ - for (i = 0; i < 100; i++) { - if (r_ecr(ppb_hi) & 0x01) - return; - udelay(5); - } - printk(KERN_WARNING "ppa: ECP sync failed as data still present in FIFO.\n"); - } -} - -static int ppa_byte_out(unsigned short base, const char *buffer, int len) -{ - int i; - - for (i = len; i; i--) { - w_dtr(base, *buffer++); - w_ctr(base, 0xe); - w_ctr(base, 0xc); - } - return 1; /* All went well - we hope! */ -} - -static int ppa_byte_in(unsigned short base, char *buffer, int len) -{ - int i; - - for (i = len; i; i--) { - *buffer++ = r_dtr(base); - w_ctr(base, 0x27); - w_ctr(base, 0x25); - } - return 1; /* All went well - we hope! */ -} - -static int ppa_nibble_in(unsigned short base, char *buffer, int len) -{ - for (; len; len--) { - unsigned char h; - - w_ctr(base, 0x4); - h = r_str(base) & 0xf0; - w_ctr(base, 0x6); - *buffer++ = h | ((r_str(base) & 0xf0) >> 4); - } - return 1; /* All went well - we hope! */ -} - -static int ppa_out(ppa_struct *dev, char *buffer, int len) -{ - int r; - unsigned short ppb = dev->base; - - r = ppa_wait(dev); - - if ((r & 0x50) != 0x40) { - ppa_fail(dev, DID_ERROR); - return 0; - } - switch (dev->mode) { - case PPA_NIBBLE: - case PPA_PS2: - /* 8 bit output, with a loop */ - r = ppa_byte_out(ppb, buffer, len); - break; - - case PPA_EPP_32: - case PPA_EPP_16: - case PPA_EPP_8: - epp_reset(ppb); - w_ctr(ppb, 0x4); -#ifdef CONFIG_SCSI_IZIP_EPP16 - if (!(((long) buffer | len) & 0x01)) - outsw(ppb + 4, buffer, len >> 1); -#else - if (!(((long) buffer | len) & 0x03)) - outsl(ppb + 4, buffer, len >> 2); -#endif - else - outsb(ppb + 4, buffer, len); - w_ctr(ppb, 0xc); - r = !(r_str(ppb) & 0x01); - w_ctr(ppb, 0xc); - ecp_sync(dev); - break; - - default: - printk(KERN_ERR "PPA: bug in ppa_out()\n"); - r = 0; - } - return r; -} - -static int ppa_in(ppa_struct *dev, char *buffer, int len) -{ - int r; - unsigned short ppb = dev->base; - - r = ppa_wait(dev); - - if ((r & 0x50) != 0x50) { - ppa_fail(dev, DID_ERROR); - return 0; - } - switch (dev->mode) { - case PPA_NIBBLE: - /* 4 bit input, with a loop */ - r = ppa_nibble_in(ppb, buffer, len); - w_ctr(ppb, 0xc); - break; - - case PPA_PS2: - /* 8 bit input, with a loop */ - w_ctr(ppb, 0x25); - r = ppa_byte_in(ppb, buffer, len); - w_ctr(ppb, 0x4); - w_ctr(ppb, 0xc); - break; - - case PPA_EPP_32: - case PPA_EPP_16: - case PPA_EPP_8: - epp_reset(ppb); - w_ctr(ppb, 0x24); -#ifdef CONFIG_SCSI_IZIP_EPP16 - if (!(((long) buffer | len) & 0x01)) - insw(ppb + 4, buffer, len >> 1); -#else - if (!(((long) buffer | len) & 0x03)) - insl(ppb + 4, buffer, len >> 2); -#endif - else - insb(ppb + 4, buffer, len); - w_ctr(ppb, 0x2c); - r = !(r_str(ppb) & 0x01); - w_ctr(ppb, 0x2c); - ecp_sync(dev); - break; - - default: - printk(KERN_ERR "PPA: bug in ppa_ins()\n"); - r = 0; - break; - } - return r; -} - -/* end of ppa_io.h */ -static inline void ppa_d_pulse(unsigned short ppb, unsigned char b) -{ - w_dtr(ppb, b); - w_ctr(ppb, 0xc); - w_ctr(ppb, 0xe); - w_ctr(ppb, 0xc); - w_ctr(ppb, 0x4); - w_ctr(ppb, 0xc); -} - -static void ppa_disconnect(ppa_struct *dev) -{ - unsigned short ppb = dev->base; - - ppa_d_pulse(ppb, 0); - ppa_d_pulse(ppb, 0x3c); - ppa_d_pulse(ppb, 0x20); - ppa_d_pulse(ppb, 0xf); -} - -static inline void ppa_c_pulse(unsigned short ppb, unsigned char b) -{ - w_dtr(ppb, b); - w_ctr(ppb, 0x4); - w_ctr(ppb, 0x6); - w_ctr(ppb, 0x4); - w_ctr(ppb, 0xc); -} - -static inline void ppa_connect(ppa_struct *dev, int flag) -{ - unsigned short ppb = dev->base; - - ppa_c_pulse(ppb, 0); - ppa_c_pulse(ppb, 0x3c); - ppa_c_pulse(ppb, 0x20); - if ((flag == CONNECT_EPP_MAYBE) && IN_EPP_MODE(dev->mode)) - ppa_c_pulse(ppb, 0xcf); - else - ppa_c_pulse(ppb, 0x8f); -} - -static int ppa_select(ppa_struct *dev, int target) -{ - int k; - unsigned short ppb = dev->base; - - /* - * Bit 6 (0x40) is the device selected bit. - * First we must wait till the current device goes off line... - */ - k = PPA_SELECT_TMO; - do { - k--; - udelay(1); - } while ((r_str(ppb) & 0x40) && (k)); - if (!k) - return 0; - - w_dtr(ppb, (1 << target)); - w_ctr(ppb, 0xe); - w_ctr(ppb, 0xc); - w_dtr(ppb, 0x80); /* This is NOT the initator */ - w_ctr(ppb, 0x8); - - k = PPA_SELECT_TMO; - do { - k--; - udelay(1); - } - while (!(r_str(ppb) & 0x40) && (k)); - if (!k) - return 0; - - return 1; -} - -/* - * This is based on a trace of what the Iomega DOS 'guest' driver does. - * I've tried several different kinds of parallel ports with guest and - * coded this to react in the same ways that it does. - * - * The return value from this function is just a hint about where the - * handshaking failed. - * - */ -static int ppa_init(ppa_struct *dev) -{ - int retv; - unsigned short ppb = dev->base; - - ppa_disconnect(dev); - ppa_connect(dev, CONNECT_NORMAL); - - retv = 2; /* Failed */ - - w_ctr(ppb, 0xe); - if ((r_str(ppb) & 0x08) == 0x08) - retv--; - - w_ctr(ppb, 0xc); - if ((r_str(ppb) & 0x08) == 0x00) - retv--; - - if (!retv) - ppa_reset_pulse(ppb); - udelay(1000); /* Allow devices to settle down */ - ppa_disconnect(dev); - udelay(1000); /* Another delay to allow devices to settle */ - - if (retv) - return -EIO; - - return device_check(dev); -} - -static inline int ppa_send_command(struct scsi_cmnd *cmd) -{ - ppa_struct *dev = ppa_dev(cmd->device->host); - int k; - - w_ctr(dev->base, 0x0c); - - for (k = 0; k < cmd->cmd_len; k++) - if (!ppa_out(dev, &cmd->cmnd[k], 1)) - return 0; - return 1; -} - -/* - * The bulk flag enables some optimisations in the data transfer loops, - * it should be true for any command that transfers data in integral - * numbers of sectors. - * - * The driver appears to remain stable if we speed up the parallel port - * i/o in this function, but not elsewhere. - */ -static int ppa_completion(struct scsi_cmnd *cmd) -{ - /* Return codes: - * -1 Error - * 0 Told to schedule - * 1 Finished data transfer - */ - ppa_struct *dev = ppa_dev(cmd->device->host); - unsigned short ppb = dev->base; - unsigned long start_jiffies = jiffies; - - unsigned char r, v; - int fast, bulk, status; - - v = cmd->cmnd[0]; - bulk = ((v == READ_6) || - (v == READ_10) || (v == WRITE_6) || (v == WRITE_10)); - - /* - * We only get here if the drive is ready to comunicate, - * hence no need for a full ppa_wait. - */ - r = (r_str(ppb) & 0xf0); - - while (r != (unsigned char) 0xf0) { - /* - * If we have been running for more than a full timer tick - * then take a rest. - */ - if (time_after(jiffies, start_jiffies + 1)) - return 0; - - if ((cmd->SCp.this_residual <= 0)) { - ppa_fail(dev, DID_ERROR); - return -1; /* ERROR_RETURN */ - } - - /* On some hardware we have SCSI disconnected (6th bit low) - * for about 100usecs. It is too expensive to wait a - * tick on every loop so we busy wait for no more than - * 500usecs to give the drive a chance first. We do not - * change things for "normal" hardware since generally - * the 6th bit is always high. - * This makes the CPU load higher on some hardware - * but otherwise we can not get more than 50K/secs - * on this problem hardware. - */ - if ((r & 0xc0) != 0xc0) { - /* Wait for reconnection should be no more than - * jiffy/2 = 5ms = 5000 loops - */ - unsigned long k = dev->recon_tmo; - for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0; - k--) - udelay(1); - - if (!k) - return 0; - } - - /* determine if we should use burst I/O */ - fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE)) - ? PPA_BURST_SIZE : 1; - - if (r == (unsigned char) 0xc0) - status = ppa_out(dev, cmd->SCp.ptr, fast); - else - status = ppa_in(dev, cmd->SCp.ptr, fast); - - cmd->SCp.ptr += fast; - cmd->SCp.this_residual -= fast; - - if (!status) { - ppa_fail(dev, DID_BUS_BUSY); - return -1; /* ERROR_RETURN */ - } - if (cmd->SCp.buffer && !cmd->SCp.this_residual) { - /* if scatter/gather, advance to the next segment */ - if (cmd->SCp.buffers_residual--) { - cmd->SCp.buffer++; - cmd->SCp.this_residual = - cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - } - } - /* Now check to see if the drive is ready to comunicate */ - r = (r_str(ppb) & 0xf0); - /* If not, drop back down to the scheduler and wait a timer tick */ - if (!(r & 0x80)) - return 0; - } - return 1; /* FINISH_RETURN */ -} - -/* - * Since the PPA itself doesn't generate interrupts, we use - * the scheduler's task queue to generate a stream of call-backs and - * complete the request when the drive is ready. - */ -static void ppa_interrupt(struct work_struct *work) -{ - ppa_struct *dev = container_of(work, ppa_struct, ppa_tq.work); - struct scsi_cmnd *cmd = dev->cur_cmd; - - if (!cmd) { - printk(KERN_ERR "PPA: bug in ppa_interrupt\n"); - return; - } - if (ppa_engine(dev, cmd)) { - schedule_delayed_work(&dev->ppa_tq, 1); - return; - } - /* Command must of completed hence it is safe to let go... */ -#if PPA_DEBUG > 0 - switch ((cmd->result >> 16) & 0xff) { - case DID_OK: - break; - case DID_NO_CONNECT: - printk(KERN_DEBUG "ppa: no device at SCSI ID %i\n", cmd->device->target); - break; - case DID_BUS_BUSY: - printk(KERN_DEBUG "ppa: BUS BUSY - EPP timeout detected\n"); - break; - case DID_TIME_OUT: - printk(KERN_DEBUG "ppa: unknown timeout\n"); - break; - case DID_ABORT: - printk(KERN_DEBUG "ppa: told to abort\n"); - break; - case DID_PARITY: - printk(KERN_DEBUG "ppa: parity error (???)\n"); - break; - case DID_ERROR: - printk(KERN_DEBUG "ppa: internal driver error\n"); - break; - case DID_RESET: - printk(KERN_DEBUG "ppa: told to reset device\n"); - break; - case DID_BAD_INTR: - printk(KERN_WARNING "ppa: bad interrupt (???)\n"); - break; - default: - printk(KERN_WARNING "ppa: bad return code (%02x)\n", - (cmd->result >> 16) & 0xff); - } -#endif - - if (cmd->SCp.phase > 1) - ppa_disconnect(dev); - - ppa_pb_dismiss(dev); - - dev->cur_cmd = NULL; - - cmd->scsi_done(cmd); -} - -static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd) -{ - unsigned short ppb = dev->base; - unsigned char l = 0, h = 0; - int retv; - - /* First check for any errors that may of occurred - * Here we check for internal errors - */ - if (dev->failed) - return 0; - - switch (cmd->SCp.phase) { - case 0: /* Phase 0 - Waiting for parport */ - if (time_after(jiffies, dev->jstart + HZ)) { - /* - * We waited more than a second - * for parport to call us - */ - ppa_fail(dev, DID_BUS_BUSY); - return 0; - } - return 1; /* wait until ppa_wakeup claims parport */ - case 1: /* Phase 1 - Connected */ - { /* Perform a sanity check for cable unplugged */ - int retv = 2; /* Failed */ - - ppa_connect(dev, CONNECT_EPP_MAYBE); - - w_ctr(ppb, 0xe); - if ((r_str(ppb) & 0x08) == 0x08) - retv--; - - w_ctr(ppb, 0xc); - if ((r_str(ppb) & 0x08) == 0x00) - retv--; - - if (retv) { - if (time_after(jiffies, dev->jstart + (1 * HZ))) { - printk(KERN_ERR "ppa: Parallel port cable is unplugged.\n"); - ppa_fail(dev, DID_BUS_BUSY); - return 0; - } else { - ppa_disconnect(dev); - return 1; /* Try again in a jiffy */ - } - } - cmd->SCp.phase++; - } - - case 2: /* Phase 2 - We are now talking to the scsi bus */ - if (!ppa_select(dev, scmd_id(cmd))) { - ppa_fail(dev, DID_NO_CONNECT); - return 0; - } - cmd->SCp.phase++; - - case 3: /* Phase 3 - Ready to accept a command */ - w_ctr(ppb, 0x0c); - if (!(r_str(ppb) & 0x80)) - return 1; - - if (!ppa_send_command(cmd)) - return 0; - cmd->SCp.phase++; - - case 4: /* Phase 4 - Setup scatter/gather buffers */ - if (scsi_bufflen(cmd)) { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.this_residual = 0; - cmd->SCp.ptr = NULL; - } - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; - cmd->SCp.phase++; - - case 5: /* Phase 5 - Data transfer stage */ - w_ctr(ppb, 0x0c); - if (!(r_str(ppb) & 0x80)) - return 1; - - retv = ppa_completion(cmd); - if (retv == -1) - return 0; - if (retv == 0) - return 1; - cmd->SCp.phase++; - - case 6: /* Phase 6 - Read status/message */ - cmd->result = DID_OK << 16; - /* Check for data overrun */ - if (ppa_wait(dev) != (unsigned char) 0xf0) { - ppa_fail(dev, DID_ERROR); - return 0; - } - if (ppa_in(dev, &l, 1)) { /* read status byte */ - /* Check for optional message byte */ - if (ppa_wait(dev) == (unsigned char) 0xf0) - ppa_in(dev, &h, 1); - cmd->result = - (DID_OK << 16) + (h << 8) + (l & STATUS_MASK); - } - return 0; /* Finished */ - break; - - default: - printk(KERN_ERR "ppa: Invalid scsi phase\n"); - } - return 0; -} - -static int ppa_queuecommand_lck(struct scsi_cmnd *cmd, - void (*done) (struct scsi_cmnd *)) -{ - ppa_struct *dev = ppa_dev(cmd->device->host); - - if (dev->cur_cmd) { - printk(KERN_ERR "PPA: bug in ppa_queuecommand\n"); - return 0; - } - dev->failed = 0; - dev->jstart = jiffies; - dev->cur_cmd = cmd; - cmd->scsi_done = done; - cmd->result = DID_ERROR << 16; /* default return code */ - cmd->SCp.phase = 0; /* bus free */ - - schedule_delayed_work(&dev->ppa_tq, 0); - - ppa_pb_claim(dev); - - return 0; -} - -static DEF_SCSI_QCMD(ppa_queuecommand) - -/* - * Apparently the disk->capacity attribute is off by 1 sector - * for all disk drives. We add the one here, but it should really - * be done in sd.c. Even if it gets fixed there, this will still - * work. - */ -static int ppa_biosparam(struct scsi_device *sdev, struct block_device *dev, - sector_t capacity, int ip[]) -{ - ip[0] = 0x40; - ip[1] = 0x20; - ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]); - if (ip[2] > 1024) { - ip[0] = 0xff; - ip[1] = 0x3f; - ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]); - if (ip[2] > 1023) - ip[2] = 1023; - } - return 0; -} - -static int ppa_abort(struct scsi_cmnd *cmd) -{ - ppa_struct *dev = ppa_dev(cmd->device->host); - /* - * There is no method for aborting commands since Iomega - * have tied the SCSI_MESSAGE line high in the interface - */ - - switch (cmd->SCp.phase) { - case 0: /* Do not have access to parport */ - case 1: /* Have not connected to interface */ - dev->cur_cmd = NULL; /* Forget the problem */ - return SUCCESS; - break; - default: /* SCSI command sent, can not abort */ - return FAILED; - break; - } -} - -static void ppa_reset_pulse(unsigned int base) -{ - w_dtr(base, 0x40); - w_ctr(base, 0x8); - udelay(30); - w_ctr(base, 0xc); -} - -static int ppa_reset(struct scsi_cmnd *cmd) -{ - ppa_struct *dev = ppa_dev(cmd->device->host); - - if (cmd->SCp.phase) - ppa_disconnect(dev); - dev->cur_cmd = NULL; /* Forget the problem */ - - ppa_connect(dev, CONNECT_NORMAL); - ppa_reset_pulse(dev->base); - mdelay(1); /* device settle delay */ - ppa_disconnect(dev); - mdelay(1); /* device settle delay */ - return SUCCESS; -} - -static int device_check(ppa_struct *dev) -{ - /* This routine looks for a device and then attempts to use EPP - to send a command. If all goes as planned then EPP is available. */ - - static u8 cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - int loop, old_mode, status, k, ppb = dev->base; - unsigned char l; - - old_mode = dev->mode; - for (loop = 0; loop < 8; loop++) { - /* Attempt to use EPP for Test Unit Ready */ - if ((ppb & 0x0007) == 0x0000) - dev->mode = PPA_EPP_32; - -second_pass: - ppa_connect(dev, CONNECT_EPP_MAYBE); - /* Select SCSI device */ - if (!ppa_select(dev, loop)) { - ppa_disconnect(dev); - continue; - } - printk(KERN_INFO "ppa: Found device at ID %i, Attempting to use %s\n", - loop, PPA_MODE_STRING[dev->mode]); - - /* Send SCSI command */ - status = 1; - w_ctr(ppb, 0x0c); - for (l = 0; (l < 6) && (status); l++) - status = ppa_out(dev, cmd, 1); - - if (!status) { - ppa_disconnect(dev); - ppa_connect(dev, CONNECT_EPP_MAYBE); - w_dtr(ppb, 0x40); - w_ctr(ppb, 0x08); - udelay(30); - w_ctr(ppb, 0x0c); - udelay(1000); - ppa_disconnect(dev); - udelay(1000); - if (dev->mode == PPA_EPP_32) { - dev->mode = old_mode; - goto second_pass; - } - return -EIO; - } - w_ctr(ppb, 0x0c); - k = 1000000; /* 1 Second */ - do { - l = r_str(ppb); - k--; - udelay(1); - } while (!(l & 0x80) && (k)); - - l &= 0xf0; - - if (l != 0xf0) { - ppa_disconnect(dev); - ppa_connect(dev, CONNECT_EPP_MAYBE); - ppa_reset_pulse(ppb); - udelay(1000); - ppa_disconnect(dev); - udelay(1000); - if (dev->mode == PPA_EPP_32) { - dev->mode = old_mode; - goto second_pass; - } - return -EIO; - } - ppa_disconnect(dev); - printk(KERN_INFO "ppa: Communication established with ID %i using %s\n", - loop, PPA_MODE_STRING[dev->mode]); - ppa_connect(dev, CONNECT_EPP_MAYBE); - ppa_reset_pulse(ppb); - udelay(1000); - ppa_disconnect(dev); - udelay(1000); - return 0; - } - return -ENODEV; -} - -static int ppa_adjust_queue(struct scsi_device *device) -{ - blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH); - return 0; -} - -static struct scsi_host_template ppa_template = { - .module = THIS_MODULE, - .proc_name = "ppa", - .proc_info = ppa_proc_info, - .name = "Iomega VPI0 (ppa) interface", - .queuecommand = ppa_queuecommand, - .eh_abort_handler = ppa_abort, - .eh_bus_reset_handler = ppa_reset, - .eh_host_reset_handler = ppa_reset, - .bios_param = ppa_biosparam, - .this_id = -1, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, - .can_queue = 1, - .slave_alloc = ppa_adjust_queue, -}; - -/*************************************************************************** - * Parallel port probing routines * - ***************************************************************************/ - -static LIST_HEAD(ppa_hosts); - -static int __ppa_attach(struct parport *pb) -{ - struct Scsi_Host *host; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(waiting); - DEFINE_WAIT(wait); - ppa_struct *dev; - int ports; - int modes, ppb, ppb_hi; - int err = -ENOMEM; - - dev = kzalloc(sizeof(ppa_struct), GFP_KERNEL); - if (!dev) - return -ENOMEM; - dev->base = -1; - dev->mode = PPA_AUTODETECT; - dev->recon_tmo = PPA_RECON_TMO; - init_waitqueue_head(&waiting); - dev->dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup, - NULL, 0, dev); - - if (!dev->dev) - goto out; - - /* Claim the bus so it remembers what we do to the control - * registers. [ CTR and ECP ] - */ - err = -EBUSY; - dev->waiting = &waiting; - prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE); - if (ppa_pb_claim(dev)) - schedule_timeout(3 * HZ); - if (dev->wanted) { - printk(KERN_ERR "ppa%d: failed to claim parport because " - "a pardevice is owning the port for too long " - "time!\n", pb->number); - ppa_pb_dismiss(dev); - dev->waiting = NULL; - finish_wait(&waiting, &wait); - goto out1; - } - dev->waiting = NULL; - finish_wait(&waiting, &wait); - ppb = dev->base = dev->dev->port->base; - ppb_hi = dev->dev->port->base_hi; - w_ctr(ppb, 0x0c); - modes = dev->dev->port->modes; - - /* Mode detection works up the chain of speed - * This avoids a nasty if-then-else-if-... tree - */ - dev->mode = PPA_NIBBLE; - - if (modes & PARPORT_MODE_TRISTATE) - dev->mode = PPA_PS2; - - if (modes & PARPORT_MODE_ECP) { - w_ecr(ppb_hi, 0x20); - dev->mode = PPA_PS2; - } - if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP)) - w_ecr(ppb_hi, 0x80); - - /* Done configuration */ - - err = ppa_init(dev); - ppa_pb_release(dev); - - if (err) - goto out1; - - /* now the glue ... */ - if (dev->mode == PPA_NIBBLE || dev->mode == PPA_PS2) - ports = 3; - else - ports = 8; - - INIT_DELAYED_WORK(&dev->ppa_tq, ppa_interrupt); - - err = -ENOMEM; - host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *)); - if (!host) - goto out1; - host->io_port = pb->base; - host->n_io_port = ports; - host->dma_channel = -1; - host->unique_id = pb->number; - *(ppa_struct **)&host->hostdata = dev; - dev->host = host; - list_add_tail(&dev->list, &ppa_hosts); - err = scsi_add_host(host, NULL); - if (err) - goto out2; - scsi_scan_host(host); - return 0; -out2: - list_del_init(&dev->list); - scsi_host_put(host); -out1: - parport_unregister_device(dev->dev); -out: - kfree(dev); - return err; -} - -static void ppa_attach(struct parport *pb) -{ - __ppa_attach(pb); -} - -static void ppa_detach(struct parport *pb) -{ - ppa_struct *dev; - list_for_each_entry(dev, &ppa_hosts, list) { - if (dev->dev->port == pb) { - list_del_init(&dev->list); - scsi_remove_host(dev->host); - scsi_host_put(dev->host); - parport_unregister_device(dev->dev); - kfree(dev); - break; - } - } -} - -static struct parport_driver ppa_driver = { - .name = "ppa", - .attach = ppa_attach, - .detach = ppa_detach, -}; - -static int __init ppa_driver_init(void) -{ - printk(KERN_INFO "ppa: Version %s\n", PPA_VERSION); - return parport_register_driver(&ppa_driver); -} - -static void __exit ppa_driver_exit(void) -{ - parport_unregister_driver(&ppa_driver); -} - -module_init(ppa_driver_init); -module_exit(ppa_driver_exit); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/ppa.h b/ANDROID_3.4.5/drivers/scsi/ppa.h deleted file mode 100644 index ba802142..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ppa.h +++ /dev/null @@ -1,150 +0,0 @@ -/* Driver for the PPA3 parallel port SCSI HBA embedded in - * the Iomega ZIP drive - * - * (c) 1996 Grant R. Guenther grant@torque.net - * David Campbell - * - * All comments to David. - */ - -#ifndef _PPA_H -#define _PPA_H - -#define PPA_VERSION "2.07 (for Linux 2.4.x)" - -/* - * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu) - * to support EPP and scatter-gather. [0.26-athena] - * - * additional hacks by David Campbell - * in response to this driver "mis-behaving" on his machine. - * Fixed EPP to handle "software" changing of EPP port data direction. - * Chased down EPP timeouts - * Made this driver "kernel version friendly" [0.28-athena] - * - * [ Stuff removed ] - * - * Corrected ppa.h for 2.1.x kernels (>=2.1.85) - * Modified "Nat Semi Kludge" for extended chipsets - * [1.41] - * - * Fixed id_probe for EPP 1.9 chipsets (misdetected as EPP 1.7) - * [1.42] - * - * Development solely for 2.1.x kernels from now on! - * [2.00] - * - * Hack and slash at the init code (EPP device check routine) - * Added INSANE option. - * [2.01] - * - * Patch applied to sync against the 2.1.x kernel code - * Included qboot_zip.sh - * [2.02] - * - * Cleaned up the mess left by someone else trying to fix the - * asm section to keep egcc happy. The asm section no longer - * exists, the nibble code is *almost* as fast as the asm code - * providing it is compiled with egcc. - * - * Other clean ups include the follow changes: - * CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16 - * added CONFIG_SCSI_IZIP_SLOW_CTR option - * [2.03] - * - * Use ppa_wait() to check for ready AND connected status bits - * Add ppa_wait() calls to ppa_completion() - * by Peter Cherriman and - * Tim Waugh - * [2.04] - * - * Fix kernel panic on scsi timeout, 2000-08-18 [2.05] - * - * Avoid io_request_lock problems. - * John Cavan [2.06] - * - * Busy wait for connected status bit in ppa_completion() - * in order to cope with some hardware that has this bit low - * for short periods of time. - * Add udelay() to ppa_select() - * by Peter Cherriman and - * Oleg Makarenko - * [2.07] - */ -/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -/* batteries not included :-) */ - -/* - * modes in which the driver can operate - */ -#define PPA_AUTODETECT 0 /* Autodetect mode */ -#define PPA_NIBBLE 1 /* work in standard 4 bit mode */ -#define PPA_PS2 2 /* PS/2 byte mode */ -#define PPA_EPP_8 3 /* EPP mode, 8 bit */ -#define PPA_EPP_16 4 /* EPP mode, 16 bit */ -#define PPA_EPP_32 5 /* EPP mode, 32 bit */ -#define PPA_UNKNOWN 6 /* Just in case... */ - -static char *PPA_MODE_STRING[] = -{ - "Autodetect", - "SPP", - "PS/2", - "EPP 8 bit", - "EPP 16 bit", -#ifdef CONFIG_SCSI_IZIP_EPP16 - "EPP 16 bit", -#else - "EPP 32 bit", -#endif - "Unknown"}; - -/* other options */ -#define PPA_BURST_SIZE 512 /* data burst size */ -#define PPA_SELECT_TMO 5000 /* how long to wait for target ? */ -#define PPA_SPIN_TMO 50000 /* ppa_wait loop limiter */ -#define PPA_RECON_TMO 500 /* scsi reconnection loop limiter */ -#define PPA_DEBUG 0 /* debugging option */ -#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32) - -/* args to ppa_connect */ -#define CONNECT_EPP_MAYBE 1 -#define CONNECT_NORMAL 0 - -#define r_dtr(x) (unsigned char)inb((x)) -#define r_str(x) (unsigned char)inb((x)+1) -#define r_ctr(x) (unsigned char)inb((x)+2) -#define r_epp(x) (unsigned char)inb((x)+4) -#define r_fifo(x) (unsigned char)inb((x)) /* x must be base_hi */ - /* On PCI is base+0x400 != base_hi */ -#define r_ecr(x) (unsigned char)inb((x)+0x2) /* x must be base_hi */ - -#define w_dtr(x,y) outb(y, (x)) -#define w_str(x,y) outb(y, (x)+1) -#define w_epp(x,y) outb(y, (x)+4) -#define w_fifo(x,y) outb(y, (x)) /* x must be base_hi */ -#define w_ecr(x,y) outb(y, (x)+0x2)/* x must be base_hi */ - -#ifdef CONFIG_SCSI_IZIP_SLOW_CTR -#define w_ctr(x,y) outb_p(y, (x)+2) -#else -#define w_ctr(x,y) outb(y, (x)+2) -#endif - -static int ppa_engine(ppa_struct *, struct scsi_cmnd *); - -#endif /* _PPA_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/ps3rom.c b/ANDROID_3.4.5/drivers/scsi/ps3rom.c deleted file mode 100644 index 959f1005..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ps3rom.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * PS3 BD/DVD/CD-ROM Storage Driver - * - * Copyright (C) 2007 Sony Computer Entertainment Inc. - * Copyright 2007 Sony Corp. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published - * by the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - - -#define DEVICE_NAME "ps3rom" - -#define BOUNCE_SIZE (64*1024) - -#define PS3ROM_MAX_SECTORS (BOUNCE_SIZE >> 9) - - -struct ps3rom_private { - struct ps3_storage_device *dev; - struct scsi_cmnd *curr_cmd; -}; - - -#define LV1_STORAGE_SEND_ATAPI_COMMAND (1) - -struct lv1_atapi_cmnd_block { - u8 pkt[32]; /* packet command block */ - u32 pktlen; /* should be 12 for ATAPI 8020 */ - u32 blocks; - u32 block_size; - u32 proto; /* transfer mode */ - u32 in_out; /* transfer direction */ - u64 buffer; /* parameter except command block */ - u32 arglen; /* length above */ -}; - -enum lv1_atapi_proto { - NON_DATA_PROTO = 0, - PIO_DATA_IN_PROTO = 1, - PIO_DATA_OUT_PROTO = 2, - DMA_PROTO = 3 -}; - -enum lv1_atapi_in_out { - DIR_WRITE = 0, /* memory -> device */ - DIR_READ = 1 /* device -> memory */ -}; - - -static int ps3rom_slave_configure(struct scsi_device *scsi_dev) -{ - struct ps3rom_private *priv = shost_priv(scsi_dev->host); - struct ps3_storage_device *dev = priv->dev; - - dev_dbg(&dev->sbd.core, "%s:%u: id %u, lun %u, channel %u\n", __func__, - __LINE__, scsi_dev->id, scsi_dev->lun, scsi_dev->channel); - - /* - * ATAPI SFF8020 devices use MODE_SENSE_10, - * so we can prohibit MODE_SENSE_6 - */ - scsi_dev->use_10_for_ms = 1; - - /* we don't support {READ,WRITE}_6 */ - scsi_dev->use_10_for_rw = 1; - - return 0; -} - -static int ps3rom_atapi_request(struct ps3_storage_device *dev, - struct scsi_cmnd *cmd) -{ - struct lv1_atapi_cmnd_block atapi_cmnd; - unsigned char opcode = cmd->cmnd[0]; - int res; - u64 lpar; - - dev_dbg(&dev->sbd.core, "%s:%u: send ATAPI command 0x%02x\n", __func__, - __LINE__, opcode); - - memset(&atapi_cmnd, 0, sizeof(struct lv1_atapi_cmnd_block)); - memcpy(&atapi_cmnd.pkt, cmd->cmnd, 12); - atapi_cmnd.pktlen = 12; - atapi_cmnd.block_size = 1; /* transfer size is block_size * blocks */ - atapi_cmnd.blocks = atapi_cmnd.arglen = scsi_bufflen(cmd); - atapi_cmnd.buffer = dev->bounce_lpar; - - switch (cmd->sc_data_direction) { - case DMA_FROM_DEVICE: - if (scsi_bufflen(cmd) >= CD_FRAMESIZE) - atapi_cmnd.proto = DMA_PROTO; - else - atapi_cmnd.proto = PIO_DATA_IN_PROTO; - atapi_cmnd.in_out = DIR_READ; - break; - - case DMA_TO_DEVICE: - if (scsi_bufflen(cmd) >= CD_FRAMESIZE) - atapi_cmnd.proto = DMA_PROTO; - else - atapi_cmnd.proto = PIO_DATA_OUT_PROTO; - atapi_cmnd.in_out = DIR_WRITE; - scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size); - break; - - default: - atapi_cmnd.proto = NON_DATA_PROTO; - break; - } - - lpar = ps3_mm_phys_to_lpar(__pa(&atapi_cmnd)); - res = lv1_storage_send_device_command(dev->sbd.dev_id, - LV1_STORAGE_SEND_ATAPI_COMMAND, - lpar, sizeof(atapi_cmnd), - atapi_cmnd.buffer, - atapi_cmnd.arglen, &dev->tag); - if (res == LV1_DENIED_BY_POLICY) { - dev_dbg(&dev->sbd.core, - "%s:%u: ATAPI command 0x%02x denied by policy\n", - __func__, __LINE__, opcode); - return DID_ERROR << 16; - } - - if (res) { - dev_err(&dev->sbd.core, - "%s:%u: ATAPI command 0x%02x failed %d\n", __func__, - __LINE__, opcode, res); - return DID_ERROR << 16; - } - - return 0; -} - -static inline unsigned int srb10_lba(const struct scsi_cmnd *cmd) -{ - return cmd->cmnd[2] << 24 | cmd->cmnd[3] << 16 | cmd->cmnd[4] << 8 | - cmd->cmnd[5]; -} - -static inline unsigned int srb10_len(const struct scsi_cmnd *cmd) -{ - return cmd->cmnd[7] << 8 | cmd->cmnd[8]; -} - -static int ps3rom_read_request(struct ps3_storage_device *dev, - struct scsi_cmnd *cmd, u32 start_sector, - u32 sectors) -{ - int res; - - dev_dbg(&dev->sbd.core, "%s:%u: read %u sectors starting at %u\n", - __func__, __LINE__, sectors, start_sector); - - res = lv1_storage_read(dev->sbd.dev_id, - dev->regions[dev->region_idx].id, start_sector, - sectors, 0, dev->bounce_lpar, &dev->tag); - if (res) { - dev_err(&dev->sbd.core, "%s:%u: read failed %d\n", __func__, - __LINE__, res); - return DID_ERROR << 16; - } - - return 0; -} - -static int ps3rom_write_request(struct ps3_storage_device *dev, - struct scsi_cmnd *cmd, u32 start_sector, - u32 sectors) -{ - int res; - - dev_dbg(&dev->sbd.core, "%s:%u: write %u sectors starting at %u\n", - __func__, __LINE__, sectors, start_sector); - - scsi_sg_copy_to_buffer(cmd, dev->bounce_buf, dev->bounce_size); - - res = lv1_storage_write(dev->sbd.dev_id, - dev->regions[dev->region_idx].id, start_sector, - sectors, 0, dev->bounce_lpar, &dev->tag); - if (res) { - dev_err(&dev->sbd.core, "%s:%u: write failed %d\n", __func__, - __LINE__, res); - return DID_ERROR << 16; - } - - return 0; -} - -static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - struct ps3rom_private *priv = shost_priv(cmd->device->host); - struct ps3_storage_device *dev = priv->dev; - unsigned char opcode; - int res; - -#ifdef DEBUG - scsi_print_command(cmd); -#endif - - priv->curr_cmd = cmd; - cmd->scsi_done = done; - - opcode = cmd->cmnd[0]; - /* - * While we can submit READ/WRITE SCSI commands as ATAPI commands, - * it's recommended for various reasons (performance, error handling, - * ...) to use lv1_storage_{read,write}() instead - */ - switch (opcode) { - case READ_10: - res = ps3rom_read_request(dev, cmd, srb10_lba(cmd), - srb10_len(cmd)); - break; - - case WRITE_10: - res = ps3rom_write_request(dev, cmd, srb10_lba(cmd), - srb10_len(cmd)); - break; - - default: - res = ps3rom_atapi_request(dev, cmd); - break; - } - - if (res) { - memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - cmd->result = res; - cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = ILLEGAL_REQUEST; - priv->curr_cmd = NULL; - cmd->scsi_done(cmd); - } - - return 0; -} - -static DEF_SCSI_QCMD(ps3rom_queuecommand) - -static int decode_lv1_status(u64 status, unsigned char *sense_key, - unsigned char *asc, unsigned char *ascq) -{ - if (((status >> 24) & 0xff) != SAM_STAT_CHECK_CONDITION) - return -1; - - *sense_key = (status >> 16) & 0xff; - *asc = (status >> 8) & 0xff; - *ascq = status & 0xff; - return 0; -} - -static irqreturn_t ps3rom_interrupt(int irq, void *data) -{ - struct ps3_storage_device *dev = data; - struct Scsi_Host *host; - struct ps3rom_private *priv; - struct scsi_cmnd *cmd; - int res; - u64 tag, status; - unsigned char sense_key, asc, ascq; - - res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status); - /* - * status = -1 may mean that ATAPI transport completed OK, but - * ATAPI command itself resulted CHECK CONDITION - * so, upper layer should issue REQUEST_SENSE to check the sense data - */ - - if (tag != dev->tag) - dev_err(&dev->sbd.core, - "%s:%u: tag mismatch, got %llx, expected %llx\n", - __func__, __LINE__, tag, dev->tag); - - if (res) { - dev_err(&dev->sbd.core, "%s:%u: res=%d status=0x%llx\n", - __func__, __LINE__, res, status); - return IRQ_HANDLED; - } - - host = ps3_system_bus_get_drvdata(&dev->sbd); - priv = shost_priv(host); - cmd = priv->curr_cmd; - - if (!status) { - /* OK, completed */ - if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - int len; - - len = scsi_sg_copy_from_buffer(cmd, - dev->bounce_buf, - dev->bounce_size); - - scsi_set_resid(cmd, scsi_bufflen(cmd) - len); - } - cmd->result = DID_OK << 16; - goto done; - } - - if (cmd->cmnd[0] == REQUEST_SENSE) { - /* SCSI spec says request sense should never get error */ - dev_err(&dev->sbd.core, "%s:%u: end error without autosense\n", - __func__, __LINE__); - cmd->result = DID_ERROR << 16 | SAM_STAT_CHECK_CONDITION; - goto done; - } - - if (decode_lv1_status(status, &sense_key, &asc, &ascq)) { - cmd->result = DID_ERROR << 16; - goto done; - } - - scsi_build_sense_buffer(0, cmd->sense_buffer, sense_key, asc, ascq); - cmd->result = SAM_STAT_CHECK_CONDITION; - -done: - priv->curr_cmd = NULL; - cmd->scsi_done(cmd); - return IRQ_HANDLED; -} - -static struct scsi_host_template ps3rom_host_template = { - .name = DEVICE_NAME, - .slave_configure = ps3rom_slave_configure, - .queuecommand = ps3rom_queuecommand, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .emulated = 1, /* only sg driver uses this */ - .max_sectors = PS3ROM_MAX_SECTORS, - .use_clustering = ENABLE_CLUSTERING, - .module = THIS_MODULE, -}; - - -static int __devinit ps3rom_probe(struct ps3_system_bus_device *_dev) -{ - struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); - int error; - struct Scsi_Host *host; - struct ps3rom_private *priv; - - if (dev->blk_size != CD_FRAMESIZE) { - dev_err(&dev->sbd.core, - "%s:%u: cannot handle block size %llu\n", __func__, - __LINE__, dev->blk_size); - return -EINVAL; - } - - dev->bounce_size = BOUNCE_SIZE; - dev->bounce_buf = kmalloc(BOUNCE_SIZE, GFP_DMA); - if (!dev->bounce_buf) - return -ENOMEM; - - error = ps3stor_setup(dev, ps3rom_interrupt); - if (error) - goto fail_free_bounce; - - host = scsi_host_alloc(&ps3rom_host_template, - sizeof(struct ps3rom_private)); - if (!host) { - dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed\n", - __func__, __LINE__); - goto fail_teardown; - } - - priv = shost_priv(host); - ps3_system_bus_set_drvdata(&dev->sbd, host); - priv->dev = dev; - - /* One device/LUN per SCSI bus */ - host->max_id = 1; - host->max_lun = 1; - - error = scsi_add_host(host, &dev->sbd.core); - if (error) { - dev_err(&dev->sbd.core, "%s:%u: scsi_host_alloc failed %d\n", - __func__, __LINE__, error); - error = -ENODEV; - goto fail_host_put; - } - - scsi_scan_host(host); - return 0; - -fail_host_put: - scsi_host_put(host); - ps3_system_bus_set_drvdata(&dev->sbd, NULL); -fail_teardown: - ps3stor_teardown(dev); -fail_free_bounce: - kfree(dev->bounce_buf); - return error; -} - -static int ps3rom_remove(struct ps3_system_bus_device *_dev) -{ - struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); - struct Scsi_Host *host = ps3_system_bus_get_drvdata(&dev->sbd); - - scsi_remove_host(host); - ps3stor_teardown(dev); - scsi_host_put(host); - ps3_system_bus_set_drvdata(&dev->sbd, NULL); - kfree(dev->bounce_buf); - return 0; -} - -static struct ps3_system_bus_driver ps3rom = { - .match_id = PS3_MATCH_ID_STOR_ROM, - .core.name = DEVICE_NAME, - .core.owner = THIS_MODULE, - .probe = ps3rom_probe, - .remove = ps3rom_remove -}; - - -static int __init ps3rom_init(void) -{ - return ps3_system_bus_driver_register(&ps3rom); -} - -static void __exit ps3rom_exit(void) -{ - ps3_system_bus_driver_unregister(&ps3rom); -} - -module_init(ps3rom_init); -module_exit(ps3rom_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("PS3 BD/DVD/CD-ROM Storage Driver"); -MODULE_AUTHOR("Sony Corporation"); -MODULE_ALIAS(PS3_MODULE_ALIAS_STOR_ROM); diff --git a/ANDROID_3.4.5/drivers/scsi/qla1280.c b/ANDROID_3.4.5/drivers/scsi/qla1280.c deleted file mode 100644 index 6c6486f6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla1280.c +++ /dev/null @@ -1,4505 +0,0 @@ -/****************************************************************************** -* QLOGIC LINUX SOFTWARE -* -* QLogic QLA1280 (Ultra2) and QLA12160 (Ultra3) SCSI driver -* Copyright (C) 2000 Qlogic Corporation (www.qlogic.com) -* Copyright (C) 2001-2004 Jes Sorensen, Wild Open Source Inc. -* Copyright (C) 2003-2004 Christoph Hellwig -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2, or (at your option) any -* later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -******************************************************************************/ -#define QLA1280_VERSION "3.27.1" -/***************************************************************************** - Revision History: - Rev 3.27.1, February 8, 2010, Michael Reed - - Retain firmware image for error recovery. - Rev 3.27, February 10, 2009, Michael Reed - - General code cleanup. - - Improve error recovery. - Rev 3.26, January 16, 2006 Jes Sorensen - - Ditch all < 2.6 support - Rev 3.25.1, February 10, 2005 Christoph Hellwig - - use pci_map_single to map non-S/G requests - - remove qla1280_proc_info - Rev 3.25, September 28, 2004, Christoph Hellwig - - add support for ISP1020/1040 - - don't include "scsi.h" anymore for 2.6.x - Rev 3.24.4 June 7, 2004 Christoph Hellwig - - restructure firmware loading, cleanup initialization code - - prepare support for ISP1020/1040 chips - Rev 3.24.3 January 19, 2004, Jes Sorensen - - Handle PCI DMA mask settings correctly - - Correct order of error handling in probe_one, free_irq should not - be called if request_irq failed - Rev 3.24.2 January 19, 2004, James Bottomley & Andrew Vasquez - - Big endian fixes (James) - - Remove bogus IOCB content on zero data transfer commands (Andrew) - Rev 3.24.1 January 5, 2004, Jes Sorensen - - Initialize completion queue to avoid OOPS on probe - - Handle interrupts during mailbox testing - Rev 3.24 November 17, 2003, Christoph Hellwig - - use struct list_head for completion queue - - avoid old Scsi_FOO typedefs - - cleanup 2.4 compat glue a bit - - use headers on 2.6 instead of "scsi.h" - - make initialization for memory mapped vs port I/O more similar - - remove broken pci config space manipulation - - kill more cruft - - this is an almost perfect 2.6 scsi driver now! ;) - Rev 3.23.39 December 17, 2003, Jes Sorensen - - Delete completion queue from srb if mailbox command failed to - to avoid qla1280_done completeting qla1280_error_action's - obsolete context - - Reduce arguments for qla1280_done - Rev 3.23.38 October 18, 2003, Christoph Hellwig - - Convert to new-style hotplugable driver for 2.6 - - Fix missing scsi_unregister/scsi_host_put on HBA removal - - Kill some more cruft - Rev 3.23.37 October 1, 2003, Jes Sorensen - - Make MMIO depend on CONFIG_X86_VISWS instead of yet another - random CONFIG option - - Clean up locking in probe path - Rev 3.23.36 October 1, 2003, Christoph Hellwig - - queuecommand only ever receives new commands - clear flags - - Reintegrate lost fixes from Linux 2.5 - Rev 3.23.35 August 14, 2003, Jes Sorensen - - Build against 2.6 - Rev 3.23.34 July 23, 2003, Jes Sorensen - - Remove pointless TRUE/FALSE macros - - Clean up vchan handling - Rev 3.23.33 July 3, 2003, Jes Sorensen - - Don't define register access macros before define determining MMIO. - This just happened to work out on ia64 but not elsewhere. - - Don't try and read from the card while it is in reset as - it won't respond and causes an MCA - Rev 3.23.32 June 23, 2003, Jes Sorensen - - Basic support for boot time arguments - Rev 3.23.31 June 8, 2003, Jes Sorensen - - Reduce boot time messages - Rev 3.23.30 June 6, 2003, Jes Sorensen - - Do not enable sync/wide/ppr before it has been determined - that the target device actually supports it - - Enable DMA arbitration for multi channel controllers - Rev 3.23.29 June 3, 2003, Jes Sorensen - - Port to 2.5.69 - Rev 3.23.28 June 3, 2003, Jes Sorensen - - Eliminate duplicate marker commands on bus resets - - Handle outstanding commands appropriately on bus/device resets - Rev 3.23.27 May 28, 2003, Jes Sorensen - - Remove bogus input queue code, let the Linux SCSI layer do the work - - Clean up NVRAM handling, only read it once from the card - - Add a number of missing default nvram parameters - Rev 3.23.26 Beta May 28, 2003, Jes Sorensen - - Use completion queue for mailbox commands instead of busy wait - Rev 3.23.25 Beta May 27, 2003, James Bottomley - - Migrate to use new error handling code - Rev 3.23.24 Beta May 21, 2003, James Bottomley - - Big endian support - - Cleanup data direction code - Rev 3.23.23 Beta May 12, 2003, Jes Sorensen - - Switch to using MMIO instead of PIO - Rev 3.23.22 Beta April 15, 2003, Jes Sorensen - - Fix PCI parity problem with 12160 during reset. - Rev 3.23.21 Beta April 14, 2003, Jes Sorensen - - Use pci_map_page()/pci_unmap_page() instead of map_single version. - Rev 3.23.20 Beta April 9, 2003, Jes Sorensen - - Remove < 2.4.x support - - Introduce HOST_LOCK to make the spin lock changes portable. - - Remove a bunch of idiotic and unnecessary typedef's - - Kill all leftovers of target-mode support which never worked anyway - Rev 3.23.19 Beta April 11, 2002, Linus Torvalds - - Do qla1280_pci_config() before calling request_irq() and - request_region() - - Use pci_dma_hi32() to handle upper word of DMA addresses instead - of large shifts - - Hand correct arguments to free_irq() in case of failure - Rev 3.23.18 Beta April 11, 2002, Jes Sorensen - - Run source through Lindent and clean up the output - Rev 3.23.17 Beta April 11, 2002, Jes Sorensen - - Update SCSI firmware to qla1280 v8.15.00 and qla12160 v10.04.32 - Rev 3.23.16 Beta March 19, 2002, Jes Sorensen - - Rely on mailbox commands generating interrupts - do not - run qla1280_isr() from ql1280_mailbox_command() - - Remove device_reg_t - - Integrate ql12160_set_target_parameters() with 1280 version - - Make qla1280_setup() non static - - Do not call qla1280_check_for_dead_scsi_bus() on every I/O request - sent to the card - this command pauses the firmware!!! - Rev 3.23.15 Beta March 19, 2002, Jes Sorensen - - Clean up qla1280.h - remove obsolete QL_DEBUG_LEVEL_x definitions - - Remove a pile of pointless and confusing (srb_t **) and - (scsi_lu_t *) typecasts - - Explicit mark that we do not use the new error handling (for now) - - Remove scsi_qla_host_t and use 'struct' instead - - Remove in_abort, watchdog_enabled, dpc, dpc_sched, bios_enabled, - pci_64bit_slot flags which weren't used for anything anyway - - Grab host->host_lock while calling qla1280_isr() from abort() - - Use spin_lock()/spin_unlock() in qla1280_intr_handler() - we - do not need to save/restore flags in the interrupt handler - - Enable interrupts early (before any mailbox access) in preparation - for cleaning up the mailbox handling - Rev 3.23.14 Beta March 14, 2002, Jes Sorensen - - Further cleanups. Remove all trace of QL_DEBUG_LEVEL_x and replace - it with proper use of dprintk(). - - Make qla1280_print_scsi_cmd() and qla1280_dump_buffer() both take - a debug level argument to determine if data is to be printed - - Add KERN_* info to printk() - Rev 3.23.13 Beta March 14, 2002, Jes Sorensen - - Significant cosmetic cleanups - - Change debug code to use dprintk() and remove #if mess - Rev 3.23.12 Beta March 13, 2002, Jes Sorensen - - More cosmetic cleanups, fix places treating return as function - - use cpu_relax() in qla1280_debounce_register() - Rev 3.23.11 Beta March 13, 2002, Jes Sorensen - - Make it compile under 2.5.5 - Rev 3.23.10 Beta October 1, 2001, Jes Sorensen - - Do no typecast short * to long * in QL1280BoardTbl, this - broke miserably on big endian boxes - Rev 3.23.9 Beta September 30, 2001, Jes Sorensen - - Remove pre 2.2 hack for checking for reentrance in interrupt handler - - Make data types used to receive from SCSI_{BUS,TCN,LUN}_32 - unsigned int to match the types from struct scsi_cmnd - Rev 3.23.8 Beta September 29, 2001, Jes Sorensen - - Remove bogus timer_t typedef from qla1280.h - - Remove obsolete pre 2.2 PCI setup code, use proper #define's - for PCI_ values, call pci_set_master() - - Fix memleak of qla1280_buffer on module unload - - Only compile module parsing code #ifdef MODULE - should be - changed to use individual MODULE_PARM's later - - Remove dummy_buffer that was never modified nor printed - - ENTER()/LEAVE() are noops unless QL_DEBUG_LEVEL_3, hence remove - #ifdef QL_DEBUG_LEVEL_3/#endif around ENTER()/LEAVE() calls - - Remove \r from print statements, this is Linux, not DOS - - Remove obsolete QLA1280_{SCSILU,INTR,RING}_{LOCK,UNLOCK} - dummy macros - - Remove C++ compile hack in header file as Linux driver are not - supposed to be compiled as C++ - - Kill MS_64BITS macro as it makes the code more readable - - Remove unnecessary flags.in_interrupts bit - Rev 3.23.7 Beta August 20, 2001, Jes Sorensen - - Dont' check for set flags on q->q_flag one by one in qla1280_next() - - Check whether the interrupt was generated by the QLA1280 before - doing any processing - - qla1280_status_entry(): Only zero out part of sense_buffer that - is not being copied into - - Remove more superflouous typecasts - - qla1280_32bit_start_scsi() replace home-brew memcpy() with memcpy() - Rev 3.23.6 Beta August 20, 2001, Tony Luck, Intel - - Don't walk the entire list in qla1280_putq_t() just to directly - grab the pointer to the last element afterwards - Rev 3.23.5 Beta August 9, 2001, Jes Sorensen - - Don't use IRQF_DISABLED, it's use is deprecated for this kinda driver - Rev 3.23.4 Beta August 8, 2001, Jes Sorensen - - Set dev->max_sectors to 1024 - Rev 3.23.3 Beta August 6, 2001, Jes Sorensen - - Provide compat macros for pci_enable_device(), pci_find_subsys() - and scsi_set_pci_device() - - Call scsi_set_pci_device() for all devices - - Reduce size of kernel version dependent device probe code - - Move duplicate probe/init code to separate function - - Handle error if qla1280_mem_alloc() fails - - Kill OFFSET() macro and use Linux's PCI definitions instead - - Kill private structure defining PCI config space (struct config_reg) - - Only allocate I/O port region if not in MMIO mode - - Remove duplicate (unused) sanity check of sife of srb_t - Rev 3.23.2 Beta August 6, 2001, Jes Sorensen - - Change home-brew memset() implementations to use memset() - - Remove all references to COMTRACE() - accessing a PC's COM2 serial - port directly is not legal under Linux. - Rev 3.23.1 Beta April 24, 2001, Jes Sorensen - - Remove pre 2.2 kernel support - - clean up 64 bit DMA setting to use 2.4 API (provide backwards compat) - - Fix MMIO access to use readl/writel instead of directly - dereferencing pointers - - Nuke MSDOS debugging code - - Change true/false data types to int from uint8_t - - Use int for counters instead of uint8_t etc. - - Clean up size & byte order conversion macro usage - Rev 3.23 Beta January 11, 2001 BN Qlogic - - Added check of device_id when handling non - QLA12160s during detect(). - Rev 3.22 Beta January 5, 2001 BN Qlogic - - Changed queue_task() to schedule_task() - for kernels 2.4.0 and higher. - Note: 2.4.0-testxx kernels released prior to - the actual 2.4.0 kernel release on January 2001 - will get compile/link errors with schedule_task(). - Please update your kernel to released 2.4.0 level, - or comment lines in this file flagged with 3.22 - to resolve compile/link error of schedule_task(). - - Added -DCONFIG_SMP in addition to -D__SMP__ - in Makefile for 2.4.0 builds of driver as module. - Rev 3.21 Beta January 4, 2001 BN Qlogic - - Changed criteria of 64/32 Bit mode of HBA - operation according to BITS_PER_LONG rather - than HBA's NVRAM setting of >4Gig memory bit; - so that the HBA auto-configures without the need - to setup each system individually. - Rev 3.20 Beta December 5, 2000 BN Qlogic - - Added priority handling to IA-64 onboard SCSI - ISP12160 chip for kernels greater than 2.3.18. - - Added irqrestore for qla1280_intr_handler. - - Enabled /proc/scsi/qla1280 interface. - - Clear /proc/scsi/qla1280 counters in detect(). - Rev 3.19 Beta October 13, 2000 BN Qlogic - - Declare driver_template for new kernel - (2.4.0 and greater) scsi initialization scheme. - - Update /proc/scsi entry for 2.3.18 kernels and - above as qla1280 - Rev 3.18 Beta October 10, 2000 BN Qlogic - - Changed scan order of adapters to map - the QLA12160 followed by the QLA1280. - Rev 3.17 Beta September 18, 2000 BN Qlogic - - Removed warnings for 32 bit 2.4.x compiles - - Corrected declared size for request and response - DMA addresses that are kept in each ha - Rev. 3.16 Beta August 25, 2000 BN Qlogic - - Corrected 64 bit addressing issue on IA-64 - where the upper 32 bits were not properly - passed to the RISC engine. - Rev. 3.15 Beta August 22, 2000 BN Qlogic - - Modified qla1280_setup_chip to properly load - ISP firmware for greater that 4 Gig memory on IA-64 - Rev. 3.14 Beta August 16, 2000 BN Qlogic - - Added setting of dma_mask to full 64 bit - if flags.enable_64bit_addressing is set in NVRAM - Rev. 3.13 Beta August 16, 2000 BN Qlogic - - Use new PCI DMA mapping APIs for 2.4.x kernel - Rev. 3.12 July 18, 2000 Redhat & BN Qlogic - - Added check of pci_enable_device to detect() for 2.3.x - - Use pci_resource_start() instead of - pdev->resource[0].start in detect() for 2.3.x - - Updated driver version - Rev. 3.11 July 14, 2000 BN Qlogic - - Updated SCSI Firmware to following versions: - qla1x80: 8.13.08 - qla1x160: 10.04.08 - - Updated driver version to 3.11 - Rev. 3.10 June 23, 2000 BN Qlogic - - Added filtering of AMI SubSys Vendor ID devices - Rev. 3.9 - - DEBUG_QLA1280 undefined and new version BN Qlogic - Rev. 3.08b May 9, 2000 MD Dell - - Added logic to check against AMI subsystem vendor ID - Rev. 3.08 May 4, 2000 DG Qlogic - - Added logic to check for PCI subsystem ID. - Rev. 3.07 Apr 24, 2000 DG & BN Qlogic - - Updated SCSI Firmware to following versions: - qla12160: 10.01.19 - qla1280: 8.09.00 - Rev. 3.06 Apr 12, 2000 DG & BN Qlogic - - Internal revision; not released - Rev. 3.05 Mar 28, 2000 DG & BN Qlogic - - Edit correction for virt_to_bus and PROC. - Rev. 3.04 Mar 28, 2000 DG & BN Qlogic - - Merge changes from ia64 port. - Rev. 3.03 Mar 28, 2000 BN Qlogic - - Increase version to reflect new code drop with compile fix - of issue with inclusion of linux/spinlock for 2.3 kernels - Rev. 3.02 Mar 15, 2000 BN Qlogic - - Merge qla1280_proc_info from 2.10 code base - Rev. 3.01 Feb 10, 2000 BN Qlogic - - Corrected code to compile on a 2.2.x kernel. - Rev. 3.00 Jan 17, 2000 DG Qlogic - - Added 64-bit support. - Rev. 2.07 Nov 9, 1999 DG Qlogic - - Added new routine to set target parameters for ISP12160. - Rev. 2.06 Sept 10, 1999 DG Qlogic - - Added support for ISP12160 Ultra 3 chip. - Rev. 2.03 August 3, 1999 Fred Lewis, Intel DuPont - - Modified code to remove errors generated when compiling with - Cygnus IA64 Compiler. - - Changed conversion of pointers to unsigned longs instead of integers. - - Changed type of I/O port variables from uint32_t to unsigned long. - - Modified OFFSET macro to work with 64-bit as well as 32-bit. - - Changed sprintf and printk format specifiers for pointers to %p. - - Changed some int to long type casts where needed in sprintf & printk. - - Added l modifiers to sprintf and printk format specifiers for longs. - - Removed unused local variables. - Rev. 1.20 June 8, 1999 DG, Qlogic - Changes to support RedHat release 6.0 (kernel 2.2.5). - - Added SCSI exclusive access lock (io_request_lock) when accessing - the adapter. - - Added changes for the new LINUX interface template. Some new error - handling routines have been added to the template, but for now we - will use the old ones. - - Initial Beta Release. -*****************************************************************************/ - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) -#include -#endif - - -/* - * Compile time Options: - * 0 - Disable and 1 - Enable - */ -#define DEBUG_QLA1280_INTR 0 -#define DEBUG_PRINT_NVRAM 0 -#define DEBUG_QLA1280 0 - -/* - * The SGI VISWS is broken and doesn't support MMIO ;-( - */ -#ifdef CONFIG_X86_VISWS -#define MEMORY_MAPPED_IO 0 -#else -#define MEMORY_MAPPED_IO 1 -#endif - -#include "qla1280.h" - -#ifndef BITS_PER_LONG -#error "BITS_PER_LONG not defined!" -#endif -#if (BITS_PER_LONG == 64) || defined CONFIG_HIGHMEM -#define QLA_64BIT_PTR 1 -#endif - -#ifdef QLA_64BIT_PTR -#define pci_dma_hi32(a) ((a >> 16) >> 16) -#else -#define pci_dma_hi32(a) 0 -#endif -#define pci_dma_lo32(a) (a & 0xffffffff) - -#define NVRAM_DELAY() udelay(500) /* 2 microseconds */ - -#if defined(__ia64__) && !defined(ia64_platform_is) -#define ia64_platform_is(foo) (!strcmp(x, platform_name)) -#endif - - -#define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020) -#define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \ - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240) -#define IS_ISP1x160(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160 || \ - ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160) - - -static int qla1280_probe_one(struct pci_dev *, const struct pci_device_id *); -static void qla1280_remove_one(struct pci_dev *); - -/* - * QLogic Driver Support Function Prototypes. - */ -static void qla1280_done(struct scsi_qla_host *); -static int qla1280_get_token(char *); -static int qla1280_setup(char *s) __init; - -/* - * QLogic ISP1280 Hardware Support Function Prototypes. - */ -static int qla1280_load_firmware(struct scsi_qla_host *); -static int qla1280_init_rings(struct scsi_qla_host *); -static int qla1280_nvram_config(struct scsi_qla_host *); -static int qla1280_mailbox_command(struct scsi_qla_host *, - uint8_t, uint16_t *); -static int qla1280_bus_reset(struct scsi_qla_host *, int); -static int qla1280_device_reset(struct scsi_qla_host *, int, int); -static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int); -static int qla1280_abort_isp(struct scsi_qla_host *); -#ifdef QLA_64BIT_PTR -static int qla1280_64bit_start_scsi(struct scsi_qla_host *, struct srb *); -#else -static int qla1280_32bit_start_scsi(struct scsi_qla_host *, struct srb *); -#endif -static void qla1280_nv_write(struct scsi_qla_host *, uint16_t); -static void qla1280_poll(struct scsi_qla_host *); -static void qla1280_reset_adapter(struct scsi_qla_host *); -static void qla1280_marker(struct scsi_qla_host *, int, int, int, u8); -static void qla1280_isp_cmd(struct scsi_qla_host *); -static void qla1280_isr(struct scsi_qla_host *, struct list_head *); -static void qla1280_rst_aen(struct scsi_qla_host *); -static void qla1280_status_entry(struct scsi_qla_host *, struct response *, - struct list_head *); -static void qla1280_error_entry(struct scsi_qla_host *, struct response *, - struct list_head *); -static uint16_t qla1280_get_nvram_word(struct scsi_qla_host *, uint32_t); -static uint16_t qla1280_nvram_request(struct scsi_qla_host *, uint32_t); -static uint16_t qla1280_debounce_register(volatile uint16_t __iomem *); -static request_t *qla1280_req_pkt(struct scsi_qla_host *); -static int qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *, - unsigned int); -static void qla1280_get_target_parameters(struct scsi_qla_host *, - struct scsi_device *); -static int qla1280_set_target_parameters(struct scsi_qla_host *, int, int); - - -static struct qla_driver_setup driver_setup; - -/* - * convert scsi data direction to request_t control flags - */ -static inline uint16_t -qla1280_data_direction(struct scsi_cmnd *cmnd) -{ - switch(cmnd->sc_data_direction) { - case DMA_FROM_DEVICE: - return BIT_5; - case DMA_TO_DEVICE: - return BIT_6; - case DMA_BIDIRECTIONAL: - return BIT_5 | BIT_6; - /* - * We could BUG() on default here if one of the four cases aren't - * met, but then again if we receive something like that from the - * SCSI layer we have more serious problems. This shuts up GCC. - */ - case DMA_NONE: - default: - return 0; - } -} - -#if DEBUG_QLA1280 -static void __qla1280_print_scsi_cmd(struct scsi_cmnd * cmd); -static void __qla1280_dump_buffer(char *, int); -#endif - - -/* - * insmod needs to find the variable and make it point to something - */ -#ifdef MODULE -static char *qla1280; - -/* insmod qla1280 options=verbose" */ -module_param(qla1280, charp, 0); -#else -__setup("qla1280=", qla1280_setup); -#endif - - -/* - * We use the scsi_pointer structure that's included with each scsi_command - * to overlay our struct srb over it. qla1280_init() checks that a srb is not - * bigger than a scsi_pointer. - */ - -#define CMD_SP(Cmnd) &Cmnd->SCp -#define CMD_CDBLEN(Cmnd) Cmnd->cmd_len -#define CMD_CDBP(Cmnd) Cmnd->cmnd -#define CMD_SNSP(Cmnd) Cmnd->sense_buffer -#define CMD_SNSLEN(Cmnd) SCSI_SENSE_BUFFERSIZE -#define CMD_RESULT(Cmnd) Cmnd->result -#define CMD_HANDLE(Cmnd) Cmnd->host_scribble -#define CMD_REQUEST(Cmnd) Cmnd->request->cmd - -#define CMD_HOST(Cmnd) Cmnd->device->host -#define SCSI_BUS_32(Cmnd) Cmnd->device->channel -#define SCSI_TCN_32(Cmnd) Cmnd->device->id -#define SCSI_LUN_32(Cmnd) Cmnd->device->lun - - -/*****************************************/ -/* ISP Boards supported by this driver */ -/*****************************************/ - -struct qla_boards { - char *name; /* Board ID String */ - int numPorts; /* Number of SCSI ports */ - int fw_index; /* index into qla1280_fw_tbl for firmware */ -}; - -/* NOTE: the last argument in each entry is used to index ql1280_board_tbl */ -static struct pci_device_id qla1280_pci_tbl[] = { - {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP12160, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1080, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1240, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1280, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - {PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP10160, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - {0,} -}; -MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl); - -DEFINE_MUTEX(qla1280_firmware_mutex); - -struct qla_fw { - char *fwname; - const struct firmware *fw; -}; - -#define QL_NUM_FW_IMAGES 3 - -struct qla_fw qla1280_fw_tbl[QL_NUM_FW_IMAGES] = { - {"qlogic/1040.bin", NULL}, /* image 0 */ - {"qlogic/1280.bin", NULL}, /* image 1 */ - {"qlogic/12160.bin", NULL}, /* image 2 */ -}; - -/* NOTE: Order of boards in this table must match order in qla1280_pci_tbl */ -static struct qla_boards ql1280_board_tbl[] = { - {.name = "QLA12160", .numPorts = 2, .fw_index = 2}, - {.name = "QLA1040" , .numPorts = 1, .fw_index = 0}, - {.name = "QLA1080" , .numPorts = 1, .fw_index = 1}, - {.name = "QLA1240" , .numPorts = 2, .fw_index = 1}, - {.name = "QLA1280" , .numPorts = 2, .fw_index = 1}, - {.name = "QLA10160", .numPorts = 1, .fw_index = 2}, - {.name = " ", .numPorts = 0, .fw_index = -1}, -}; - -static int qla1280_verbose = 1; - -#if DEBUG_QLA1280 -static int ql_debug_level = 1; -#define dprintk(level, format, a...) \ - do { if (ql_debug_level >= level) printk(KERN_ERR format, ##a); } while(0) -#define qla1280_dump_buffer(level, buf, size) \ - if (ql_debug_level >= level) __qla1280_dump_buffer(buf, size) -#define qla1280_print_scsi_cmd(level, cmd) \ - if (ql_debug_level >= level) __qla1280_print_scsi_cmd(cmd) -#else -#define ql_debug_level 0 -#define dprintk(level, format, a...) do{}while(0) -#define qla1280_dump_buffer(a, b, c) do{}while(0) -#define qla1280_print_scsi_cmd(a, b) do{}while(0) -#endif - -#define ENTER(x) dprintk(3, "qla1280 : Entering %s()\n", x); -#define LEAVE(x) dprintk(3, "qla1280 : Leaving %s()\n", x); -#define ENTER_INTR(x) dprintk(4, "qla1280 : Entering %s()\n", x); -#define LEAVE_INTR(x) dprintk(4, "qla1280 : Leaving %s()\n", x); - - -static int qla1280_read_nvram(struct scsi_qla_host *ha) -{ - uint16_t *wptr; - uint8_t chksum; - int cnt, i; - struct nvram *nv; - - ENTER("qla1280_read_nvram"); - - if (driver_setup.no_nvram) - return 1; - - printk(KERN_INFO "scsi(%ld): Reading NVRAM\n", ha->host_no); - - wptr = (uint16_t *)&ha->nvram; - nv = &ha->nvram; - chksum = 0; - for (cnt = 0; cnt < 3; cnt++) { - *wptr = qla1280_get_nvram_word(ha, cnt); - chksum += *wptr & 0xff; - chksum += (*wptr >> 8) & 0xff; - wptr++; - } - - if (nv->id0 != 'I' || nv->id1 != 'S' || - nv->id2 != 'P' || nv->id3 != ' ' || nv->version < 1) { - dprintk(2, "Invalid nvram ID or version!\n"); - chksum = 1; - } else { - for (; cnt < sizeof(struct nvram); cnt++) { - *wptr = qla1280_get_nvram_word(ha, cnt); - chksum += *wptr & 0xff; - chksum += (*wptr >> 8) & 0xff; - wptr++; - } - } - - dprintk(3, "qla1280_read_nvram: NVRAM Magic ID= %c %c %c %02x" - " version %i\n", nv->id0, nv->id1, nv->id2, nv->id3, - nv->version); - - - if (chksum) { - if (!driver_setup.no_nvram) - printk(KERN_WARNING "scsi(%ld): Unable to identify or " - "validate NVRAM checksum, using default " - "settings\n", ha->host_no); - ha->nvram_valid = 0; - } else - ha->nvram_valid = 1; - - /* The firmware interface is, um, interesting, in that the - * actual firmware image on the chip is little endian, thus, - * the process of taking that image to the CPU would end up - * little endian. However, the firmware interface requires it - * to be read a word (two bytes) at a time. - * - * The net result of this would be that the word (and - * doubleword) quantites in the firmware would be correct, but - * the bytes would be pairwise reversed. Since most of the - * firmware quantites are, in fact, bytes, we do an extra - * le16_to_cpu() in the firmware read routine. - * - * The upshot of all this is that the bytes in the firmware - * are in the correct places, but the 16 and 32 bit quantites - * are still in little endian format. We fix that up below by - * doing extra reverses on them */ - nv->isp_parameter = cpu_to_le16(nv->isp_parameter); - nv->firmware_feature.w = cpu_to_le16(nv->firmware_feature.w); - for(i = 0; i < MAX_BUSES; i++) { - nv->bus[i].selection_timeout = cpu_to_le16(nv->bus[i].selection_timeout); - nv->bus[i].max_queue_depth = cpu_to_le16(nv->bus[i].max_queue_depth); - } - dprintk(1, "qla1280_read_nvram: Completed Reading NVRAM\n"); - LEAVE("qla1280_read_nvram"); - - return chksum; -} - -/************************************************************************** - * qla1280_info - * Return a string describing the driver. - **************************************************************************/ -static const char * -qla1280_info(struct Scsi_Host *host) -{ - static char qla1280_scsi_name_buffer[125]; - char *bp; - struct scsi_qla_host *ha; - struct qla_boards *bdp; - - bp = &qla1280_scsi_name_buffer[0]; - ha = (struct scsi_qla_host *)host->hostdata; - bdp = &ql1280_board_tbl[ha->devnum]; - memset(bp, 0, sizeof(qla1280_scsi_name_buffer)); - - sprintf (bp, - "QLogic %s PCI to SCSI Host Adapter\n" - " Firmware version: %2d.%02d.%02d, Driver version %s", - &bdp->name[0], ha->fwver1, ha->fwver2, ha->fwver3, - QLA1280_VERSION); - return bp; -} - -/************************************************************************** - * qla1280_queuecommand - * Queue a command to the controller. - * - * Note: - * The mid-level driver tries to ensures that queuecommand never gets invoked - * concurrently with itself or the interrupt handler (although the - * interrupt handler may call this routine as part of request-completion - * handling). Unfortunely, it sometimes calls the scheduler in interrupt - * context which is a big NO! NO!. - **************************************************************************/ -static int -qla1280_queuecommand_lck(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *)) -{ - struct Scsi_Host *host = cmd->device->host; - struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; - struct srb *sp = (struct srb *)CMD_SP(cmd); - int status; - - cmd->scsi_done = fn; - sp->cmd = cmd; - sp->flags = 0; - sp->wait = NULL; - CMD_HANDLE(cmd) = (unsigned char *)NULL; - - qla1280_print_scsi_cmd(5, cmd); - -#ifdef QLA_64BIT_PTR - /* - * Using 64 bit commands if the PCI bridge doesn't support it is a - * bit wasteful, however this should really only happen if one's - * PCI controller is completely broken, like the BCM1250. For - * sane hardware this is not an issue. - */ - status = qla1280_64bit_start_scsi(ha, sp); -#else - status = qla1280_32bit_start_scsi(ha, sp); -#endif - return status; -} - -static DEF_SCSI_QCMD(qla1280_queuecommand) - -enum action { - ABORT_COMMAND, - DEVICE_RESET, - BUS_RESET, - ADAPTER_RESET, -}; - - -static void qla1280_mailbox_timeout(unsigned long __data) -{ - struct scsi_qla_host *ha = (struct scsi_qla_host *)__data; - struct device_reg __iomem *reg; - reg = ha->iobase; - - ha->mailbox_out[0] = RD_REG_WORD(®->mailbox0); - printk(KERN_ERR "scsi(%ld): mailbox timed out, mailbox0 %04x, " - "ictrl %04x, istatus %04x\n", ha->host_no, ha->mailbox_out[0], - RD_REG_WORD(®->ictrl), RD_REG_WORD(®->istatus)); - complete(ha->mailbox_wait); -} - -static int -_qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp, - struct completion *wait) -{ - int status = FAILED; - struct scsi_cmnd *cmd = sp->cmd; - - spin_unlock_irq(ha->host->host_lock); - wait_for_completion_timeout(wait, 4*HZ); - spin_lock_irq(ha->host->host_lock); - sp->wait = NULL; - if(CMD_HANDLE(cmd) == COMPLETED_HANDLE) { - status = SUCCESS; - (*cmd->scsi_done)(cmd); - } - return status; -} - -static int -qla1280_wait_for_single_command(struct scsi_qla_host *ha, struct srb *sp) -{ - DECLARE_COMPLETION_ONSTACK(wait); - - sp->wait = &wait; - return _qla1280_wait_for_single_command(ha, sp, &wait); -} - -static int -qla1280_wait_for_pending_commands(struct scsi_qla_host *ha, int bus, int target) -{ - int cnt; - int status; - struct srb *sp; - struct scsi_cmnd *cmd; - - status = SUCCESS; - - /* - * Wait for all commands with the designated bus/target - * to be completed by the firmware - */ - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = ha->outstanding_cmds[cnt]; - if (sp) { - cmd = sp->cmd; - - if (bus >= 0 && SCSI_BUS_32(cmd) != bus) - continue; - if (target >= 0 && SCSI_TCN_32(cmd) != target) - continue; - - status = qla1280_wait_for_single_command(ha, sp); - if (status == FAILED) - break; - } - } - return status; -} - -/************************************************************************** - * qla1280_error_action - * The function will attempt to perform a specified error action and - * wait for the results (or time out). - * - * Input: - * cmd = Linux SCSI command packet of the command that cause the - * bus reset. - * action = error action to take (see action_t) - * - * Returns: - * SUCCESS or FAILED - * - **************************************************************************/ -static int -qla1280_error_action(struct scsi_cmnd *cmd, enum action action) -{ - struct scsi_qla_host *ha; - int bus, target, lun; - struct srb *sp; - int i, found; - int result=FAILED; - int wait_for_bus=-1; - int wait_for_target = -1; - DECLARE_COMPLETION_ONSTACK(wait); - - ENTER("qla1280_error_action"); - - ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata); - sp = (struct srb *)CMD_SP(cmd); - bus = SCSI_BUS_32(cmd); - target = SCSI_TCN_32(cmd); - lun = SCSI_LUN_32(cmd); - - dprintk(4, "error_action %i, istatus 0x%04x\n", action, - RD_REG_WORD(&ha->iobase->istatus)); - - dprintk(4, "host_cmd 0x%04x, ictrl 0x%04x, jiffies %li\n", - RD_REG_WORD(&ha->iobase->host_cmd), - RD_REG_WORD(&ha->iobase->ictrl), jiffies); - - if (qla1280_verbose) - printk(KERN_INFO "scsi(%li): Resetting Cmnd=0x%p, " - "Handle=0x%p, action=0x%x\n", - ha->host_no, cmd, CMD_HANDLE(cmd), action); - - /* - * Check to see if we have the command in the outstanding_cmds[] - * array. If not then it must have completed before this error - * action was initiated. If the error_action isn't ABORT_COMMAND - * then the driver must proceed with the requested action. - */ - found = -1; - for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) { - if (sp == ha->outstanding_cmds[i]) { - found = i; - sp->wait = &wait; /* we'll wait for it to complete */ - break; - } - } - - if (found < 0) { /* driver doesn't have command */ - result = SUCCESS; - if (qla1280_verbose) { - printk(KERN_INFO - "scsi(%ld:%d:%d:%d): specified command has " - "already completed.\n", ha->host_no, bus, - target, lun); - } - } - - switch (action) { - - case ABORT_COMMAND: - dprintk(1, "qla1280: RISC aborting command\n"); - /* - * The abort might fail due to race when the host_lock - * is released to issue the abort. As such, we - * don't bother to check the return status. - */ - if (found >= 0) - qla1280_abort_command(ha, sp, found); - break; - - case DEVICE_RESET: - if (qla1280_verbose) - printk(KERN_INFO - "scsi(%ld:%d:%d:%d): Queueing device reset " - "command.\n", ha->host_no, bus, target, lun); - if (qla1280_device_reset(ha, bus, target) == 0) { - /* issued device reset, set wait conditions */ - wait_for_bus = bus; - wait_for_target = target; - } - break; - - case BUS_RESET: - if (qla1280_verbose) - printk(KERN_INFO "qla1280(%ld:%d): Issued bus " - "reset.\n", ha->host_no, bus); - if (qla1280_bus_reset(ha, bus) == 0) { - /* issued bus reset, set wait conditions */ - wait_for_bus = bus; - } - break; - - case ADAPTER_RESET: - default: - if (qla1280_verbose) { - printk(KERN_INFO - "scsi(%ld): Issued ADAPTER RESET\n", - ha->host_no); - printk(KERN_INFO "scsi(%ld): I/O processing will " - "continue automatically\n", ha->host_no); - } - ha->flags.reset_active = 1; - - if (qla1280_abort_isp(ha) != 0) { /* it's dead */ - result = FAILED; - } - - ha->flags.reset_active = 0; - } - - /* - * At this point, the host_lock has been released and retaken - * by the issuance of the mailbox command. - * Wait for the command passed in by the mid-layer if it - * was found by the driver. It might have been returned - * between eh recovery steps, hence the check of the "found" - * variable. - */ - - if (found >= 0) - result = _qla1280_wait_for_single_command(ha, sp, &wait); - - if (action == ABORT_COMMAND && result != SUCCESS) { - printk(KERN_WARNING - "scsi(%li:%i:%i:%i): " - "Unable to abort command!\n", - ha->host_no, bus, target, lun); - } - - /* - * If the command passed in by the mid-layer has been - * returned by the board, then wait for any additional - * commands which are supposed to complete based upon - * the error action. - * - * All commands are unconditionally returned during a - * call to qla1280_abort_isp(), ADAPTER_RESET. No need - * to wait for them. - */ - if (result == SUCCESS && wait_for_bus >= 0) { - result = qla1280_wait_for_pending_commands(ha, - wait_for_bus, wait_for_target); - } - - dprintk(1, "RESET returning %d\n", result); - - LEAVE("qla1280_error_action"); - return result; -} - -/************************************************************************** - * qla1280_abort - * Abort the specified SCSI command(s). - **************************************************************************/ -static int -qla1280_eh_abort(struct scsi_cmnd * cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = qla1280_error_action(cmd, ABORT_COMMAND); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - -/************************************************************************** - * qla1280_device_reset - * Reset the specified SCSI device - **************************************************************************/ -static int -qla1280_eh_device_reset(struct scsi_cmnd *cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = qla1280_error_action(cmd, DEVICE_RESET); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - -/************************************************************************** - * qla1280_bus_reset - * Reset the specified bus. - **************************************************************************/ -static int -qla1280_eh_bus_reset(struct scsi_cmnd *cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = qla1280_error_action(cmd, BUS_RESET); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - -/************************************************************************** - * qla1280_adapter_reset - * Reset the specified adapter (both channels) - **************************************************************************/ -static int -qla1280_eh_adapter_reset(struct scsi_cmnd *cmd) -{ - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = qla1280_error_action(cmd, ADAPTER_RESET); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; -} - -static int -qla1280_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int geom[]) -{ - int heads, sectors, cylinders; - - heads = 64; - sectors = 32; - cylinders = (unsigned long)capacity / (heads * sectors); - if (cylinders > 1024) { - heads = 255; - sectors = 63; - cylinders = (unsigned long)capacity / (heads * sectors); - /* if (cylinders > 1023) - cylinders = 1023; */ - } - - geom[0] = heads; - geom[1] = sectors; - geom[2] = cylinders; - - return 0; -} - - -/* disable risc and host interrupts */ -static inline void -qla1280_disable_intrs(struct scsi_qla_host *ha) -{ - WRT_REG_WORD(&ha->iobase->ictrl, 0); - RD_REG_WORD(&ha->iobase->ictrl); /* PCI Posted Write flush */ -} - -/* enable risc and host interrupts */ -static inline void -qla1280_enable_intrs(struct scsi_qla_host *ha) -{ - WRT_REG_WORD(&ha->iobase->ictrl, (ISP_EN_INT | ISP_EN_RISC)); - RD_REG_WORD(&ha->iobase->ictrl); /* PCI Posted Write flush */ -} - -/************************************************************************** - * qla1280_intr_handler - * Handles the H/W interrupt - **************************************************************************/ -static irqreturn_t -qla1280_intr_handler(int irq, void *dev_id) -{ - struct scsi_qla_host *ha; - struct device_reg __iomem *reg; - u16 data; - int handled = 0; - - ENTER_INTR ("qla1280_intr_handler"); - ha = (struct scsi_qla_host *)dev_id; - - spin_lock(ha->host->host_lock); - - ha->isr_count++; - reg = ha->iobase; - - qla1280_disable_intrs(ha); - - data = qla1280_debounce_register(®->istatus); - /* Check for pending interrupts. */ - if (data & RISC_INT) { - qla1280_isr(ha, &ha->done_q); - handled = 1; - } - if (!list_empty(&ha->done_q)) - qla1280_done(ha); - - spin_unlock(ha->host->host_lock); - - qla1280_enable_intrs(ha); - - LEAVE_INTR("qla1280_intr_handler"); - return IRQ_RETVAL(handled); -} - - -static int -qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) -{ - uint8_t mr; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - struct nvram *nv; - int status, lun; - - nv = &ha->nvram; - - mr = BIT_3 | BIT_2 | BIT_1 | BIT_0; - - /* Set Target Parameters. */ - mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); - mb[2] = nv->bus[bus].target[target].parameter.renegotiate_on_error << 8; - mb[2] |= nv->bus[bus].target[target].parameter.stop_queue_on_check << 9; - mb[2] |= nv->bus[bus].target[target].parameter.auto_request_sense << 10; - mb[2] |= nv->bus[bus].target[target].parameter.tag_queuing << 11; - mb[2] |= nv->bus[bus].target[target].parameter.enable_sync << 12; - mb[2] |= nv->bus[bus].target[target].parameter.enable_wide << 13; - mb[2] |= nv->bus[bus].target[target].parameter.parity_checking << 14; - mb[2] |= nv->bus[bus].target[target].parameter.disconnect_allowed << 15; - - if (IS_ISP1x160(ha)) { - mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8); - mb[6] = (nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) | - nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; - mr |= BIT_6; - } else { - mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8); - } - mb[3] |= nv->bus[bus].target[target].sync_period; - - status = qla1280_mailbox_command(ha, mr, mb); - - /* Set Device Queue Parameters. */ - for (lun = 0; lun < MAX_LUNS; lun++) { - mb[0] = MBC_SET_DEVICE_QUEUE; - mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); - mb[1] |= lun; - mb[2] = nv->bus[bus].max_queue_depth; - mb[3] = nv->bus[bus].target[target].execution_throttle; - status |= qla1280_mailbox_command(ha, 0x0f, mb); - } - - if (status) - printk(KERN_WARNING "scsi(%ld:%i:%i): " - "qla1280_set_target_parameters() failed\n", - ha->host_no, bus, target); - return status; -} - - -/************************************************************************** - * qla1280_slave_configure - * - * Description: - * Determines the queue depth for a given device. There are two ways - * a queue depth can be obtained for a tagged queueing device. One - * way is the default queue depth which is determined by whether - * If it is defined, then it is used - * as the default queue depth. Otherwise, we use either 4 or 8 as the - * default queue depth (dependent on the number of hardware SCBs). - **************************************************************************/ -static int -qla1280_slave_configure(struct scsi_device *device) -{ - struct scsi_qla_host *ha; - int default_depth = 3; - int bus = device->channel; - int target = device->id; - int status = 0; - struct nvram *nv; - unsigned long flags; - - ha = (struct scsi_qla_host *)device->host->hostdata; - nv = &ha->nvram; - - if (qla1280_check_for_dead_scsi_bus(ha, bus)) - return 1; - - if (device->tagged_supported && - (ha->bus_settings[bus].qtag_enables & (BIT_0 << target))) { - scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, - ha->bus_settings[bus].hiwat); - } else { - scsi_adjust_queue_depth(device, 0, default_depth); - } - - nv->bus[bus].target[target].parameter.enable_sync = device->sdtr; - nv->bus[bus].target[target].parameter.enable_wide = device->wdtr; - nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = device->ppr; - - if (driver_setup.no_sync || - (driver_setup.sync_mask && - (~driver_setup.sync_mask & (1 << target)))) - nv->bus[bus].target[target].parameter.enable_sync = 0; - if (driver_setup.no_wide || - (driver_setup.wide_mask && - (~driver_setup.wide_mask & (1 << target)))) - nv->bus[bus].target[target].parameter.enable_wide = 0; - if (IS_ISP1x160(ha)) { - if (driver_setup.no_ppr || - (driver_setup.ppr_mask && - (~driver_setup.ppr_mask & (1 << target)))) - nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0; - } - - spin_lock_irqsave(ha->host->host_lock, flags); - if (nv->bus[bus].target[target].parameter.enable_sync) - status = qla1280_set_target_parameters(ha, bus, target); - qla1280_get_target_parameters(ha, device); - spin_unlock_irqrestore(ha->host->host_lock, flags); - return status; -} - - -/* - * qla1280_done - * Process completed commands. - * - * Input: - * ha = adapter block pointer. - */ -static void -qla1280_done(struct scsi_qla_host *ha) -{ - struct srb *sp; - struct list_head *done_q; - int bus, target, lun; - struct scsi_cmnd *cmd; - - ENTER("qla1280_done"); - - done_q = &ha->done_q; - - while (!list_empty(done_q)) { - sp = list_entry(done_q->next, struct srb, list); - - list_del(&sp->list); - - cmd = sp->cmd; - bus = SCSI_BUS_32(cmd); - target = SCSI_TCN_32(cmd); - lun = SCSI_LUN_32(cmd); - - switch ((CMD_RESULT(cmd) >> 16)) { - case DID_RESET: - /* Issue marker command. */ - if (!ha->flags.abort_isp_active) - qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); - break; - case DID_ABORT: - sp->flags &= ~SRB_ABORT_PENDING; - sp->flags |= SRB_ABORTED; - break; - default: - break; - } - - /* Release memory used for this I/O */ - scsi_dma_unmap(cmd); - - /* Call the mid-level driver interrupt handler */ - ha->actthreads--; - - if (sp->wait == NULL) - (*(cmd)->scsi_done)(cmd); - else - complete(sp->wait); - } - LEAVE("qla1280_done"); -} - -/* - * Translates a ISP error to a Linux SCSI error - */ -static int -qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) -{ - int host_status = DID_ERROR; - uint16_t comp_status = le16_to_cpu(sts->comp_status); - uint16_t state_flags = le16_to_cpu(sts->state_flags); - uint32_t residual_length = le32_to_cpu(sts->residual_length); - uint16_t scsi_status = le16_to_cpu(sts->scsi_status); -#if DEBUG_QLA1280_INTR - static char *reason[] = { - "DID_OK", - "DID_NO_CONNECT", - "DID_BUS_BUSY", - "DID_TIME_OUT", - "DID_BAD_TARGET", - "DID_ABORT", - "DID_PARITY", - "DID_ERROR", - "DID_RESET", - "DID_BAD_INTR" - }; -#endif /* DEBUG_QLA1280_INTR */ - - ENTER("qla1280_return_status"); - -#if DEBUG_QLA1280_INTR - /* - dprintk(1, "qla1280_return_status: compl status = 0x%04x\n", - comp_status); - */ -#endif - - switch (comp_status) { - case CS_COMPLETE: - host_status = DID_OK; - break; - - case CS_INCOMPLETE: - if (!(state_flags & SF_GOT_BUS)) - host_status = DID_NO_CONNECT; - else if (!(state_flags & SF_GOT_TARGET)) - host_status = DID_BAD_TARGET; - else if (!(state_flags & SF_SENT_CDB)) - host_status = DID_ERROR; - else if (!(state_flags & SF_TRANSFERRED_DATA)) - host_status = DID_ERROR; - else if (!(state_flags & SF_GOT_STATUS)) - host_status = DID_ERROR; - else if (!(state_flags & SF_GOT_SENSE)) - host_status = DID_ERROR; - break; - - case CS_RESET: - host_status = DID_RESET; - break; - - case CS_ABORTED: - host_status = DID_ABORT; - break; - - case CS_TIMEOUT: - host_status = DID_TIME_OUT; - break; - - case CS_DATA_OVERRUN: - dprintk(2, "Data overrun 0x%x\n", residual_length); - dprintk(2, "qla1280_return_status: response packet data\n"); - qla1280_dump_buffer(2, (char *)sts, RESPONSE_ENTRY_SIZE); - host_status = DID_ERROR; - break; - - case CS_DATA_UNDERRUN: - if ((scsi_bufflen(cp) - residual_length) < - cp->underflow) { - printk(KERN_WARNING - "scsi: Underflow detected - retrying " - "command.\n"); - host_status = DID_ERROR; - } else { - scsi_set_resid(cp, residual_length); - host_status = DID_OK; - } - break; - - default: - host_status = DID_ERROR; - break; - } - -#if DEBUG_QLA1280_INTR - dprintk(1, "qla1280 ISP status: host status (%s) scsi status %x\n", - reason[host_status], scsi_status); -#endif - - LEAVE("qla1280_return_status"); - - return (scsi_status & 0xff) | (host_status << 16); -} - -/****************************************************************************/ -/* QLogic ISP1280 Hardware Support Functions. */ -/****************************************************************************/ - -/* - * qla1280_initialize_adapter - * Initialize board. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success - */ -static int __devinit -qla1280_initialize_adapter(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg; - int status; - int bus; - unsigned long flags; - - ENTER("qla1280_initialize_adapter"); - - /* Clear adapter flags. */ - ha->flags.online = 0; - ha->flags.disable_host_adapter = 0; - ha->flags.reset_active = 0; - ha->flags.abort_isp_active = 0; - -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) - if (ia64_platform_is("sn2")) { - printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA " - "dual channel lockup workaround\n", ha->host_no); - ha->flags.use_pci_vchannel = 1; - driver_setup.no_nvram = 1; - } -#endif - - /* TODO: implement support for the 1040 nvram format */ - if (IS_ISP1040(ha)) - driver_setup.no_nvram = 1; - - dprintk(1, "Configure PCI space for adapter...\n"); - - reg = ha->iobase; - - /* Insure mailbox registers are free. */ - WRT_REG_WORD(®->semaphore, 0); - WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); - WRT_REG_WORD(®->host_cmd, HC_CLR_HOST_INT); - RD_REG_WORD(®->host_cmd); - - if (qla1280_read_nvram(ha)) { - dprintk(2, "qla1280_initialize_adapter: failed to read " - "NVRAM\n"); - } - - /* - * It's necessary to grab the spin here as qla1280_mailbox_command - * needs to be able to drop the lock unconditionally to wait - * for completion. - */ - spin_lock_irqsave(ha->host->host_lock, flags); - - status = qla1280_load_firmware(ha); - if (status) { - printk(KERN_ERR "scsi(%li): initialize: pci probe failed!\n", - ha->host_no); - goto out; - } - - /* Setup adapter based on NVRAM parameters. */ - dprintk(1, "scsi(%ld): Configure NVRAM parameters\n", ha->host_no); - qla1280_nvram_config(ha); - - if (ha->flags.disable_host_adapter) { - status = 1; - goto out; - } - - status = qla1280_init_rings(ha); - if (status) - goto out; - - /* Issue SCSI reset, if we can't reset twice then bus is dead */ - for (bus = 0; bus < ha->ports; bus++) { - if (!ha->bus_settings[bus].disable_scsi_reset && - qla1280_bus_reset(ha, bus) && - qla1280_bus_reset(ha, bus)) - ha->bus_settings[bus].scsi_bus_dead = 1; - } - - ha->flags.online = 1; - out: - spin_unlock_irqrestore(ha->host->host_lock, flags); - - if (status) - dprintk(2, "qla1280_initialize_adapter: **** FAILED ****\n"); - - LEAVE("qla1280_initialize_adapter"); - return status; -} - -/* - * qla1280_request_firmware - * Acquire firmware for chip. Retain in memory - * for error recovery. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * Pointer to firmware image or an error code - * cast to pointer via ERR_PTR(). - */ -static const struct firmware * -qla1280_request_firmware(struct scsi_qla_host *ha) -{ - const struct firmware *fw; - int err; - int index; - char *fwname; - - spin_unlock_irq(ha->host->host_lock); - mutex_lock(&qla1280_firmware_mutex); - - index = ql1280_board_tbl[ha->devnum].fw_index; - fw = qla1280_fw_tbl[index].fw; - if (fw) - goto out; - - fwname = qla1280_fw_tbl[index].fwname; - err = request_firmware(&fw, fwname, &ha->pdev->dev); - - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fwname, err); - fw = ERR_PTR(err); - goto unlock; - } - if ((fw->size % 2) || (fw->size < 6)) { - printk(KERN_ERR "Invalid firmware length %zu in image \"%s\"\n", - fw->size, fwname); - release_firmware(fw); - fw = ERR_PTR(-EINVAL); - goto unlock; - } - - qla1280_fw_tbl[index].fw = fw; - - out: - ha->fwver1 = fw->data[0]; - ha->fwver2 = fw->data[1]; - ha->fwver3 = fw->data[2]; - unlock: - mutex_unlock(&qla1280_firmware_mutex); - spin_lock_irq(ha->host->host_lock); - return fw; -} - -/* - * Chip diagnostics - * Test chip for proper operation. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success. - */ -static int -qla1280_chip_diag(struct scsi_qla_host *ha) -{ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - struct device_reg __iomem *reg = ha->iobase; - int status = 0; - int cnt; - uint16_t data; - dprintk(3, "qla1280_chip_diag: testing device at 0x%p \n", ®->id_l); - - dprintk(1, "scsi(%ld): Verifying chip\n", ha->host_no); - - /* Soft reset chip and wait for it to finish. */ - WRT_REG_WORD(®->ictrl, ISP_RESET); - - /* - * We can't do a traditional PCI write flush here by reading - * back the register. The card will not respond once the reset - * is in action and we end up with a machine check exception - * instead. Nothing to do but wait and hope for the best. - * A portable pci_write_flush(pdev) call would be very useful here. - */ - udelay(20); - data = qla1280_debounce_register(®->ictrl); - /* - * Yet another QLogic gem ;-( - */ - for (cnt = 1000000; cnt && data & ISP_RESET; cnt--) { - udelay(5); - data = RD_REG_WORD(®->ictrl); - } - - if (!cnt) - goto fail; - - /* Reset register cleared by chip reset. */ - dprintk(3, "qla1280_chip_diag: reset register cleared by chip reset\n"); - - WRT_REG_WORD(®->cfg_1, 0); - - /* Reset RISC and disable BIOS which - allows RISC to execute out of RAM. */ - WRT_REG_WORD(®->host_cmd, HC_RESET_RISC | - HC_RELEASE_RISC | HC_DISABLE_BIOS); - - RD_REG_WORD(®->id_l); /* Flush PCI write */ - data = qla1280_debounce_register(®->mailbox0); - - /* - * I *LOVE* this code! - */ - for (cnt = 1000000; cnt && data == MBS_BUSY; cnt--) { - udelay(5); - data = RD_REG_WORD(®->mailbox0); - } - - if (!cnt) - goto fail; - - /* Check product ID of chip */ - dprintk(3, "qla1280_chip_diag: Checking product ID of chip\n"); - - if (RD_REG_WORD(®->mailbox1) != PROD_ID_1 || - (RD_REG_WORD(®->mailbox2) != PROD_ID_2 && - RD_REG_WORD(®->mailbox2) != PROD_ID_2a) || - RD_REG_WORD(®->mailbox3) != PROD_ID_3 || - RD_REG_WORD(®->mailbox4) != PROD_ID_4) { - printk(KERN_INFO "qla1280: Wrong product ID = " - "0x%x,0x%x,0x%x,0x%x\n", - RD_REG_WORD(®->mailbox1), - RD_REG_WORD(®->mailbox2), - RD_REG_WORD(®->mailbox3), - RD_REG_WORD(®->mailbox4)); - goto fail; - } - - /* - * Enable ints early!!! - */ - qla1280_enable_intrs(ha); - - dprintk(1, "qla1280_chip_diag: Checking mailboxes of chip\n"); - /* Wrap Incoming Mailboxes Test. */ - mb[0] = MBC_MAILBOX_REGISTER_TEST; - mb[1] = 0xAAAA; - mb[2] = 0x5555; - mb[3] = 0xAA55; - mb[4] = 0x55AA; - mb[5] = 0xA5A5; - mb[6] = 0x5A5A; - mb[7] = 0x2525; - - status = qla1280_mailbox_command(ha, 0xff, mb); - if (status) - goto fail; - - if (mb[1] != 0xAAAA || mb[2] != 0x5555 || mb[3] != 0xAA55 || - mb[4] != 0x55AA || mb[5] != 0xA5A5 || mb[6] != 0x5A5A || - mb[7] != 0x2525) { - printk(KERN_INFO "qla1280: Failed mbox check\n"); - goto fail; - } - - dprintk(3, "qla1280_chip_diag: exiting normally\n"); - return 0; - fail: - dprintk(2, "qla1280_chip_diag: **** FAILED ****\n"); - return status; -} - -static int -qla1280_load_firmware_pio(struct scsi_qla_host *ha) -{ - /* enter with host_lock acquired */ - - const struct firmware *fw; - const __le16 *fw_data; - uint16_t risc_address, risc_code_size; - uint16_t mb[MAILBOX_REGISTER_COUNT], i; - int err = 0; - - fw = qla1280_request_firmware(ha); - if (IS_ERR(fw)) - return PTR_ERR(fw); - - fw_data = (const __le16 *)&fw->data[0]; - ha->fwstart = __le16_to_cpu(fw_data[2]); - - /* Load RISC code. */ - risc_address = ha->fwstart; - fw_data = (const __le16 *)&fw->data[6]; - risc_code_size = (fw->size - 6) / 2; - - for (i = 0; i < risc_code_size; i++) { - mb[0] = MBC_WRITE_RAM_WORD; - mb[1] = risc_address + i; - mb[2] = __le16_to_cpu(fw_data[i]); - - err = qla1280_mailbox_command(ha, BIT_0 | BIT_1 | BIT_2, mb); - if (err) { - printk(KERN_ERR "scsi(%li): Failed to load firmware\n", - ha->host_no); - break; - } - } - - return err; -} - -#define DUMP_IT_BACK 0 /* for debug of RISC loading */ -static int -qla1280_load_firmware_dma(struct scsi_qla_host *ha) -{ - /* enter with host_lock acquired */ - const struct firmware *fw; - const __le16 *fw_data; - uint16_t risc_address, risc_code_size; - uint16_t mb[MAILBOX_REGISTER_COUNT], cnt; - int err = 0, num, i; -#if DUMP_IT_BACK - uint8_t *sp, *tbuf; - dma_addr_t p_tbuf; - - tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf); - if (!tbuf) - return -ENOMEM; -#endif - - fw = qla1280_request_firmware(ha); - if (IS_ERR(fw)) - return PTR_ERR(fw); - - fw_data = (const __le16 *)&fw->data[0]; - ha->fwstart = __le16_to_cpu(fw_data[2]); - - /* Load RISC code. */ - risc_address = ha->fwstart; - fw_data = (const __le16 *)&fw->data[6]; - risc_code_size = (fw->size - 6) / 2; - - dprintk(1, "%s: DMA RISC code (%i) words\n", - __func__, risc_code_size); - - num = 0; - while (risc_code_size > 0) { - int warn __attribute__((unused)) = 0; - - cnt = 2000 >> 1; - - if (cnt > risc_code_size) - cnt = risc_code_size; - - dprintk(2, "qla1280_setup_chip: loading risc @ =(0x%p)," - "%d,%d(0x%x)\n", - fw_data, cnt, num, risc_address); - for(i = 0; i < cnt; i++) - ((__le16 *)ha->request_ring)[i] = fw_data[i]; - - mb[0] = MBC_LOAD_RAM; - mb[1] = risc_address; - mb[4] = cnt; - mb[3] = ha->request_dma & 0xffff; - mb[2] = (ha->request_dma >> 16) & 0xffff; - mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; - mb[6] = pci_dma_hi32(ha->request_dma) >> 16; - dprintk(2, "%s: op=%d 0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n", - __func__, mb[0], - (void *)(long)ha->request_dma, - mb[6], mb[7], mb[2], mb[3]); - err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | - BIT_1 | BIT_0, mb); - if (err) { - printk(KERN_ERR "scsi(%li): Failed to load partial " - "segment of f\n", ha->host_no); - goto out; - } - -#if DUMP_IT_BACK - mb[0] = MBC_DUMP_RAM; - mb[1] = risc_address; - mb[4] = cnt; - mb[3] = p_tbuf & 0xffff; - mb[2] = (p_tbuf >> 16) & 0xffff; - mb[7] = pci_dma_hi32(p_tbuf) & 0xffff; - mb[6] = pci_dma_hi32(p_tbuf) >> 16; - - err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | - BIT_1 | BIT_0, mb); - if (err) { - printk(KERN_ERR - "Failed to dump partial segment of f/w\n"); - goto out; - } - sp = (uint8_t *)ha->request_ring; - for (i = 0; i < (cnt << 1); i++) { - if (tbuf[i] != sp[i] && warn++ < 10) { - printk(KERN_ERR "%s: FW compare error @ " - "byte(0x%x) loop#=%x\n", - __func__, i, num); - printk(KERN_ERR "%s: FWbyte=%x " - "FWfromChip=%x\n", - __func__, sp[i], tbuf[i]); - /*break; */ - } - } -#endif - risc_address += cnt; - risc_code_size = risc_code_size - cnt; - fw_data = fw_data + cnt; - num++; - } - - out: -#if DUMP_IT_BACK - pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf); -#endif - return err; -} - -static int -qla1280_start_firmware(struct scsi_qla_host *ha) -{ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - int err; - - dprintk(1, "%s: Verifying checksum of loaded RISC code.\n", - __func__); - - /* Verify checksum of loaded RISC code. */ - mb[0] = MBC_VERIFY_CHECKSUM; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = ha->fwstart; - err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); - if (err) { - printk(KERN_ERR "scsi(%li): RISC checksum failed.\n", ha->host_no); - return err; - } - - /* Start firmware execution. */ - dprintk(1, "%s: start firmware running.\n", __func__); - mb[0] = MBC_EXECUTE_FIRMWARE; - mb[1] = ha->fwstart; - err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - if (err) { - printk(KERN_ERR "scsi(%li): Failed to start firmware\n", - ha->host_no); - } - - return err; -} - -static int -qla1280_load_firmware(struct scsi_qla_host *ha) -{ - /* enter with host_lock taken */ - int err; - - err = qla1280_chip_diag(ha); - if (err) - goto out; - if (IS_ISP1040(ha)) - err = qla1280_load_firmware_pio(ha); - else - err = qla1280_load_firmware_dma(ha); - if (err) - goto out; - err = qla1280_start_firmware(ha); - out: - return err; -} - -/* - * Initialize rings - * - * Input: - * ha = adapter block pointer. - * ha->request_ring = request ring virtual address - * ha->response_ring = response ring virtual address - * ha->request_dma = request ring physical address - * ha->response_dma = response ring physical address - * - * Returns: - * 0 = success. - */ -static int -qla1280_init_rings(struct scsi_qla_host *ha) -{ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - int status = 0; - - ENTER("qla1280_init_rings"); - - /* Clear outstanding commands array. */ - memset(ha->outstanding_cmds, 0, - sizeof(struct srb *) * MAX_OUTSTANDING_COMMANDS); - - /* Initialize request queue. */ - ha->request_ring_ptr = ha->request_ring; - ha->req_ring_index = 0; - ha->req_q_cnt = REQUEST_ENTRY_CNT; - /* mb[0] = MBC_INIT_REQUEST_QUEUE; */ - mb[0] = MBC_INIT_REQUEST_QUEUE_A64; - mb[1] = REQUEST_ENTRY_CNT; - mb[3] = ha->request_dma & 0xffff; - mb[2] = (ha->request_dma >> 16) & 0xffff; - mb[4] = 0; - mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; - mb[6] = pci_dma_hi32(ha->request_dma) >> 16; - if (!(status = qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_4 | - BIT_3 | BIT_2 | BIT_1 | BIT_0, - &mb[0]))) { - /* Initialize response queue. */ - ha->response_ring_ptr = ha->response_ring; - ha->rsp_ring_index = 0; - /* mb[0] = MBC_INIT_RESPONSE_QUEUE; */ - mb[0] = MBC_INIT_RESPONSE_QUEUE_A64; - mb[1] = RESPONSE_ENTRY_CNT; - mb[3] = ha->response_dma & 0xffff; - mb[2] = (ha->response_dma >> 16) & 0xffff; - mb[5] = 0; - mb[7] = pci_dma_hi32(ha->response_dma) & 0xffff; - mb[6] = pci_dma_hi32(ha->response_dma) >> 16; - status = qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_5 | - BIT_3 | BIT_2 | BIT_1 | BIT_0, - &mb[0]); - } - - if (status) - dprintk(2, "qla1280_init_rings: **** FAILED ****\n"); - - LEAVE("qla1280_init_rings"); - return status; -} - -static void -qla1280_print_settings(struct nvram *nv) -{ - dprintk(1, "qla1280 : initiator scsi id bus[0]=%d\n", - nv->bus[0].config_1.initiator_id); - dprintk(1, "qla1280 : initiator scsi id bus[1]=%d\n", - nv->bus[1].config_1.initiator_id); - - dprintk(1, "qla1280 : bus reset delay[0]=%d\n", - nv->bus[0].bus_reset_delay); - dprintk(1, "qla1280 : bus reset delay[1]=%d\n", - nv->bus[1].bus_reset_delay); - - dprintk(1, "qla1280 : retry count[0]=%d\n", nv->bus[0].retry_count); - dprintk(1, "qla1280 : retry delay[0]=%d\n", nv->bus[0].retry_delay); - dprintk(1, "qla1280 : retry count[1]=%d\n", nv->bus[1].retry_count); - dprintk(1, "qla1280 : retry delay[1]=%d\n", nv->bus[1].retry_delay); - - dprintk(1, "qla1280 : async data setup time[0]=%d\n", - nv->bus[0].config_2.async_data_setup_time); - dprintk(1, "qla1280 : async data setup time[1]=%d\n", - nv->bus[1].config_2.async_data_setup_time); - - dprintk(1, "qla1280 : req/ack active negation[0]=%d\n", - nv->bus[0].config_2.req_ack_active_negation); - dprintk(1, "qla1280 : req/ack active negation[1]=%d\n", - nv->bus[1].config_2.req_ack_active_negation); - - dprintk(1, "qla1280 : data line active negation[0]=%d\n", - nv->bus[0].config_2.data_line_active_negation); - dprintk(1, "qla1280 : data line active negation[1]=%d\n", - nv->bus[1].config_2.data_line_active_negation); - - dprintk(1, "qla1280 : disable loading risc code=%d\n", - nv->cntr_flags_1.disable_loading_risc_code); - - dprintk(1, "qla1280 : enable 64bit addressing=%d\n", - nv->cntr_flags_1.enable_64bit_addressing); - - dprintk(1, "qla1280 : selection timeout limit[0]=%d\n", - nv->bus[0].selection_timeout); - dprintk(1, "qla1280 : selection timeout limit[1]=%d\n", - nv->bus[1].selection_timeout); - - dprintk(1, "qla1280 : max queue depth[0]=%d\n", - nv->bus[0].max_queue_depth); - dprintk(1, "qla1280 : max queue depth[1]=%d\n", - nv->bus[1].max_queue_depth); -} - -static void -qla1280_set_target_defaults(struct scsi_qla_host *ha, int bus, int target) -{ - struct nvram *nv = &ha->nvram; - - nv->bus[bus].target[target].parameter.renegotiate_on_error = 1; - nv->bus[bus].target[target].parameter.auto_request_sense = 1; - nv->bus[bus].target[target].parameter.tag_queuing = 1; - nv->bus[bus].target[target].parameter.enable_sync = 1; -#if 1 /* Some SCSI Processors do not seem to like this */ - nv->bus[bus].target[target].parameter.enable_wide = 1; -#endif - nv->bus[bus].target[target].execution_throttle = - nv->bus[bus].max_queue_depth - 1; - nv->bus[bus].target[target].parameter.parity_checking = 1; - nv->bus[bus].target[target].parameter.disconnect_allowed = 1; - - if (IS_ISP1x160(ha)) { - nv->bus[bus].target[target].flags.flags1x160.device_enable = 1; - nv->bus[bus].target[target].flags.flags1x160.sync_offset = 0x0e; - nv->bus[bus].target[target].sync_period = 9; - nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1; - nv->bus[bus].target[target].ppr_1x160.flags.ppr_options = 2; - nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width = 1; - } else { - nv->bus[bus].target[target].flags.flags1x80.device_enable = 1; - nv->bus[bus].target[target].flags.flags1x80.sync_offset = 12; - nv->bus[bus].target[target].sync_period = 10; - } -} - -static void -qla1280_set_defaults(struct scsi_qla_host *ha) -{ - struct nvram *nv = &ha->nvram; - int bus, target; - - dprintk(1, "Using defaults for NVRAM: \n"); - memset(nv, 0, sizeof(struct nvram)); - - /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ - nv->firmware_feature.f.enable_fast_posting = 1; - nv->firmware_feature.f.disable_synchronous_backoff = 1; - nv->termination.scsi_bus_0_control = 3; - nv->termination.scsi_bus_1_control = 3; - nv->termination.auto_term_support = 1; - - /* - * Set default FIFO magic - What appropriate values would be here - * is unknown. This is what I have found testing with 12160s. - * - * Now, I would love the magic decoder ring for this one, the - * header file provided by QLogic seems to be bogus or incomplete - * at best. - */ - nv->isp_config.burst_enable = 1; - if (IS_ISP1040(ha)) - nv->isp_config.fifo_threshold |= 3; - else - nv->isp_config.fifo_threshold |= 4; - - if (IS_ISP1x160(ha)) - nv->isp_parameter = 0x01; /* fast memory enable */ - - for (bus = 0; bus < MAX_BUSES; bus++) { - nv->bus[bus].config_1.initiator_id = 7; - nv->bus[bus].config_2.req_ack_active_negation = 1; - nv->bus[bus].config_2.data_line_active_negation = 1; - nv->bus[bus].selection_timeout = 250; - nv->bus[bus].max_queue_depth = 32; - - if (IS_ISP1040(ha)) { - nv->bus[bus].bus_reset_delay = 3; - nv->bus[bus].config_2.async_data_setup_time = 6; - nv->bus[bus].retry_delay = 1; - } else { - nv->bus[bus].bus_reset_delay = 5; - nv->bus[bus].config_2.async_data_setup_time = 8; - } - - for (target = 0; target < MAX_TARGETS; target++) - qla1280_set_target_defaults(ha, bus, target); - } -} - -static int -qla1280_config_target(struct scsi_qla_host *ha, int bus, int target) -{ - struct nvram *nv = &ha->nvram; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - int status, lun; - uint16_t flag; - - /* Set Target Parameters. */ - mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); - - /* - * Do not enable sync and ppr for the initial INQUIRY run. We - * enable this later if we determine the target actually - * supports it. - */ - mb[2] = (TP_RENEGOTIATE | TP_AUTO_REQUEST_SENSE | TP_TAGGED_QUEUE - | TP_WIDE | TP_PARITY | TP_DISCONNECT); - - if (IS_ISP1x160(ha)) - mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; - else - mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; - mb[3] |= nv->bus[bus].target[target].sync_period; - status = qla1280_mailbox_command(ha, 0x0f, mb); - - /* Save Tag queuing enable flag. */ - flag = (BIT_0 << target); - if (nv->bus[bus].target[target].parameter.tag_queuing) - ha->bus_settings[bus].qtag_enables |= flag; - - /* Save Device enable flag. */ - if (IS_ISP1x160(ha)) { - if (nv->bus[bus].target[target].flags.flags1x160.device_enable) - ha->bus_settings[bus].device_enables |= flag; - ha->bus_settings[bus].lun_disables |= 0; - } else { - if (nv->bus[bus].target[target].flags.flags1x80.device_enable) - ha->bus_settings[bus].device_enables |= flag; - /* Save LUN disable flag. */ - if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) - ha->bus_settings[bus].lun_disables |= flag; - } - - /* Set Device Queue Parameters. */ - for (lun = 0; lun < MAX_LUNS; lun++) { - mb[0] = MBC_SET_DEVICE_QUEUE; - mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); - mb[1] |= lun; - mb[2] = nv->bus[bus].max_queue_depth; - mb[3] = nv->bus[bus].target[target].execution_throttle; - status |= qla1280_mailbox_command(ha, 0x0f, mb); - } - - return status; -} - -static int -qla1280_config_bus(struct scsi_qla_host *ha, int bus) -{ - struct nvram *nv = &ha->nvram; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - int target, status; - - /* SCSI Reset Disable. */ - ha->bus_settings[bus].disable_scsi_reset = - nv->bus[bus].config_1.scsi_reset_disable; - - /* Initiator ID. */ - ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id; - mb[0] = MBC_SET_INITIATOR_ID; - mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 : - ha->bus_settings[bus].id; - status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - - /* Reset Delay. */ - ha->bus_settings[bus].bus_reset_delay = - nv->bus[bus].bus_reset_delay; - - /* Command queue depth per device. */ - ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1; - - /* Set target parameters. */ - for (target = 0; target < MAX_TARGETS; target++) - status |= qla1280_config_target(ha, bus, target); - - return status; -} - -static int -qla1280_nvram_config(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg = ha->iobase; - struct nvram *nv = &ha->nvram; - int bus, target, status = 0; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - - ENTER("qla1280_nvram_config"); - - if (ha->nvram_valid) { - /* Always force AUTO sense for LINUX SCSI */ - for (bus = 0; bus < MAX_BUSES; bus++) - for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter. - auto_request_sense = 1; - } - } else { - qla1280_set_defaults(ha); - } - - qla1280_print_settings(nv); - - /* Disable RISC load of firmware. */ - ha->flags.disable_risc_code_load = - nv->cntr_flags_1.disable_loading_risc_code; - - if (IS_ISP1040(ha)) { - uint16_t hwrev, cfg1, cdma_conf, ddma_conf; - - hwrev = RD_REG_WORD(®->cfg_0) & ISP_CFG0_HWMSK; - - cfg1 = RD_REG_WORD(®->cfg_1) & ~(BIT_4 | BIT_5 | BIT_6); - cdma_conf = RD_REG_WORD(®->cdma_cfg); - ddma_conf = RD_REG_WORD(®->ddma_cfg); - - /* Busted fifo, says mjacob. */ - if (hwrev != ISP_CFG0_1040A) - cfg1 |= nv->isp_config.fifo_threshold << 4; - - cfg1 |= nv->isp_config.burst_enable << 2; - WRT_REG_WORD(®->cfg_1, cfg1); - - WRT_REG_WORD(®->cdma_cfg, cdma_conf | CDMA_CONF_BENAB); - WRT_REG_WORD(®->ddma_cfg, cdma_conf | DDMA_CONF_BENAB); - } else { - uint16_t cfg1, term; - - /* Set ISP hardware DMA burst */ - cfg1 = nv->isp_config.fifo_threshold << 4; - cfg1 |= nv->isp_config.burst_enable << 2; - /* Enable DMA arbitration on dual channel controllers */ - if (ha->ports > 1) - cfg1 |= BIT_13; - WRT_REG_WORD(®->cfg_1, cfg1); - - /* Set SCSI termination. */ - WRT_REG_WORD(®->gpio_enable, - BIT_7 | BIT_3 | BIT_2 | BIT_1 | BIT_0); - term = nv->termination.scsi_bus_1_control; - term |= nv->termination.scsi_bus_0_control << 2; - term |= nv->termination.auto_term_support << 7; - RD_REG_WORD(®->id_l); /* Flush PCI write */ - WRT_REG_WORD(®->gpio_data, term); - } - RD_REG_WORD(®->id_l); /* Flush PCI write */ - - /* ISP parameter word. */ - mb[0] = MBC_SET_SYSTEM_PARAMETER; - mb[1] = nv->isp_parameter; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - - if (IS_ISP1x40(ha)) { - /* clock rate - for qla1240 and older, only */ - mb[0] = MBC_SET_CLOCK_RATE; - mb[1] = 40; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); - } - - /* Firmware feature word. */ - mb[0] = MBC_SET_FIRMWARE_FEATURES; - mb[1] = nv->firmware_feature.f.enable_fast_posting; - mb[1] |= nv->firmware_feature.f.report_lvd_bus_transition << 1; - mb[1] |= nv->firmware_feature.f.disable_synchronous_backoff << 5; -#if defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_SGI_SN2) - if (ia64_platform_is("sn2")) { - printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA " - "workaround\n", ha->host_no); - mb[1] |= nv->firmware_feature.f.unused_9 << 9; /* XXX */ - } -#endif - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); - - /* Retry count and delay. */ - mb[0] = MBC_SET_RETRY_COUNT; - mb[1] = nv->bus[0].retry_count; - mb[2] = nv->bus[0].retry_delay; - mb[6] = nv->bus[1].retry_count; - mb[7] = nv->bus[1].retry_delay; - status |= qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_2 | - BIT_1 | BIT_0, &mb[0]); - - /* ASYNC data setup time. */ - mb[0] = MBC_SET_ASYNC_DATA_SETUP; - mb[1] = nv->bus[0].config_2.async_data_setup_time; - mb[2] = nv->bus[1].config_2.async_data_setup_time; - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); - - /* Active negation states. */ - mb[0] = MBC_SET_ACTIVE_NEGATION; - mb[1] = 0; - if (nv->bus[0].config_2.req_ack_active_negation) - mb[1] |= BIT_5; - if (nv->bus[0].config_2.data_line_active_negation) - mb[1] |= BIT_4; - mb[2] = 0; - if (nv->bus[1].config_2.req_ack_active_negation) - mb[2] |= BIT_5; - if (nv->bus[1].config_2.data_line_active_negation) - mb[2] |= BIT_4; - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); - - mb[0] = MBC_SET_DATA_OVERRUN_RECOVERY; - mb[1] = 2; /* Reset SCSI bus and return all outstanding IO */ - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); - - /* thingy */ - mb[0] = MBC_SET_PCI_CONTROL; - mb[1] = BIT_1; /* Data DMA Channel Burst Enable */ - mb[2] = BIT_1; /* Command DMA Channel Burst Enable */ - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); - - mb[0] = MBC_SET_TAG_AGE_LIMIT; - mb[1] = 8; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); - - /* Selection timeout. */ - mb[0] = MBC_SET_SELECTION_TIMEOUT; - mb[1] = nv->bus[0].selection_timeout; - mb[2] = nv->bus[1].selection_timeout; - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); - - for (bus = 0; bus < ha->ports; bus++) - status |= qla1280_config_bus(ha, bus); - - if (status) - dprintk(2, "qla1280_nvram_config: **** FAILED ****\n"); - - LEAVE("qla1280_nvram_config"); - return status; -} - -/* - * Get NVRAM data word - * Calculates word position in NVRAM and calls request routine to - * get the word from NVRAM. - * - * Input: - * ha = adapter block pointer. - * address = NVRAM word address. - * - * Returns: - * data word. - */ -static uint16_t -qla1280_get_nvram_word(struct scsi_qla_host *ha, uint32_t address) -{ - uint32_t nv_cmd; - uint16_t data; - - nv_cmd = address << 16; - nv_cmd |= NV_READ_OP; - - data = le16_to_cpu(qla1280_nvram_request(ha, nv_cmd)); - - dprintk(8, "qla1280_get_nvram_word: exiting normally NVRAM data = " - "0x%x", data); - - return data; -} - -/* - * NVRAM request - * Sends read command to NVRAM and gets data from NVRAM. - * - * Input: - * ha = adapter block pointer. - * nv_cmd = Bit 26 = start bit - * Bit 25, 24 = opcode - * Bit 23-16 = address - * Bit 15-0 = write data - * - * Returns: - * data word. - */ -static uint16_t -qla1280_nvram_request(struct scsi_qla_host *ha, uint32_t nv_cmd) -{ - struct device_reg __iomem *reg = ha->iobase; - int cnt; - uint16_t data = 0; - uint16_t reg_data; - - /* Send command to NVRAM. */ - - nv_cmd <<= 5; - for (cnt = 0; cnt < 11; cnt++) { - if (nv_cmd & BIT_31) - qla1280_nv_write(ha, NV_DATA_OUT); - else - qla1280_nv_write(ha, 0); - nv_cmd <<= 1; - } - - /* Read data from NVRAM. */ - - for (cnt = 0; cnt < 16; cnt++) { - WRT_REG_WORD(®->nvram, (NV_SELECT | NV_CLOCK)); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - NVRAM_DELAY(); - data <<= 1; - reg_data = RD_REG_WORD(®->nvram); - if (reg_data & NV_DATA_IN) - data |= BIT_0; - WRT_REG_WORD(®->nvram, NV_SELECT); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - NVRAM_DELAY(); - } - - /* Deselect chip. */ - - WRT_REG_WORD(®->nvram, NV_DESELECT); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - NVRAM_DELAY(); - - return data; -} - -static void -qla1280_nv_write(struct scsi_qla_host *ha, uint16_t data) -{ - struct device_reg __iomem *reg = ha->iobase; - - WRT_REG_WORD(®->nvram, data | NV_SELECT); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - NVRAM_DELAY(); - WRT_REG_WORD(®->nvram, data | NV_SELECT | NV_CLOCK); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - NVRAM_DELAY(); - WRT_REG_WORD(®->nvram, data | NV_SELECT); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - NVRAM_DELAY(); -} - -/* - * Mailbox Command - * Issue mailbox command and waits for completion. - * - * Input: - * ha = adapter block pointer. - * mr = mailbox registers to load. - * mb = data pointer for mailbox registers. - * - * Output: - * mb[MAILBOX_REGISTER_COUNT] = returned mailbox data. - * - * Returns: - * 0 = success - */ -static int -qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb) -{ - struct device_reg __iomem *reg = ha->iobase; - int status = 0; - int cnt; - uint16_t *optr, *iptr; - uint16_t __iomem *mptr; - uint16_t data; - DECLARE_COMPLETION_ONSTACK(wait); - struct timer_list timer; - - ENTER("qla1280_mailbox_command"); - - if (ha->mailbox_wait) { - printk(KERN_ERR "Warning mailbox wait already in use!\n"); - } - ha->mailbox_wait = &wait; - - /* - * We really should start out by verifying that the mailbox is - * available before starting sending the command data - */ - /* Load mailbox registers. */ - mptr = (uint16_t __iomem *) ®->mailbox0; - iptr = mb; - for (cnt = 0; cnt < MAILBOX_REGISTER_COUNT; cnt++) { - if (mr & BIT_0) { - WRT_REG_WORD(mptr, (*iptr)); - } - - mr >>= 1; - mptr++; - iptr++; - } - - /* Issue set host interrupt command. */ - - /* set up a timer just in case we're really jammed */ - init_timer(&timer); - timer.expires = jiffies + 20*HZ; - timer.data = (unsigned long)ha; - timer.function = qla1280_mailbox_timeout; - add_timer(&timer); - - spin_unlock_irq(ha->host->host_lock); - WRT_REG_WORD(®->host_cmd, HC_SET_HOST_INT); - data = qla1280_debounce_register(®->istatus); - - wait_for_completion(&wait); - del_timer_sync(&timer); - - spin_lock_irq(ha->host->host_lock); - - ha->mailbox_wait = NULL; - - /* Check for mailbox command timeout. */ - if (ha->mailbox_out[0] != MBS_CMD_CMP) { - printk(KERN_WARNING "qla1280_mailbox_command: Command failed, " - "mailbox0 = 0x%04x, mailbox_out0 = 0x%04x, istatus = " - "0x%04x\n", - mb[0], ha->mailbox_out[0], RD_REG_WORD(®->istatus)); - printk(KERN_WARNING "m0 %04x, m1 %04x, m2 %04x, m3 %04x\n", - RD_REG_WORD(®->mailbox0), RD_REG_WORD(®->mailbox1), - RD_REG_WORD(®->mailbox2), RD_REG_WORD(®->mailbox3)); - printk(KERN_WARNING "m4 %04x, m5 %04x, m6 %04x, m7 %04x\n", - RD_REG_WORD(®->mailbox4), RD_REG_WORD(®->mailbox5), - RD_REG_WORD(®->mailbox6), RD_REG_WORD(®->mailbox7)); - status = 1; - } - - /* Load return mailbox registers. */ - optr = mb; - iptr = (uint16_t *) &ha->mailbox_out[0]; - mr = MAILBOX_REGISTER_COUNT; - memcpy(optr, iptr, MAILBOX_REGISTER_COUNT * sizeof(uint16_t)); - - if (ha->flags.reset_marker) - qla1280_rst_aen(ha); - - if (status) - dprintk(2, "qla1280_mailbox_command: **** FAILED, mailbox0 = " - "0x%x ****\n", mb[0]); - - LEAVE("qla1280_mailbox_command"); - return status; -} - -/* - * qla1280_poll - * Polls ISP for interrupts. - * - * Input: - * ha = adapter block pointer. - */ -static void -qla1280_poll(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg = ha->iobase; - uint16_t data; - LIST_HEAD(done_q); - - /* ENTER("qla1280_poll"); */ - - /* Check for pending interrupts. */ - data = RD_REG_WORD(®->istatus); - if (data & RISC_INT) - qla1280_isr(ha, &done_q); - - if (!ha->mailbox_wait) { - if (ha->flags.reset_marker) - qla1280_rst_aen(ha); - } - - if (!list_empty(&done_q)) - qla1280_done(ha); - - /* LEAVE("qla1280_poll"); */ -} - -/* - * qla1280_bus_reset - * Issue SCSI bus reset. - * - * Input: - * ha = adapter block pointer. - * bus = SCSI bus number. - * - * Returns: - * 0 = success - */ -static int -qla1280_bus_reset(struct scsi_qla_host *ha, int bus) -{ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t reset_delay; - int status; - - dprintk(3, "qla1280_bus_reset: entered\n"); - - if (qla1280_verbose) - printk(KERN_INFO "scsi(%li:%i): Resetting SCSI BUS\n", - ha->host_no, bus); - - reset_delay = ha->bus_settings[bus].bus_reset_delay; - mb[0] = MBC_BUS_RESET; - mb[1] = reset_delay; - mb[2] = (uint16_t) bus; - status = qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); - - if (status) { - if (ha->bus_settings[bus].failed_reset_count > 2) - ha->bus_settings[bus].scsi_bus_dead = 1; - ha->bus_settings[bus].failed_reset_count++; - } else { - spin_unlock_irq(ha->host->host_lock); - ssleep(reset_delay); - spin_lock_irq(ha->host->host_lock); - - ha->bus_settings[bus].scsi_bus_dead = 0; - ha->bus_settings[bus].failed_reset_count = 0; - ha->bus_settings[bus].reset_marker = 0; - /* Issue marker command. */ - qla1280_marker(ha, bus, 0, 0, MK_SYNC_ALL); - } - - /* - * We should probably call qla1280_set_target_parameters() - * here as well for all devices on the bus. - */ - - if (status) - dprintk(2, "qla1280_bus_reset: **** FAILED ****\n"); - else - dprintk(3, "qla1280_bus_reset: exiting normally\n"); - - return status; -} - -/* - * qla1280_device_reset - * Issue bus device reset message to the target. - * - * Input: - * ha = adapter block pointer. - * bus = SCSI BUS number. - * target = SCSI ID. - * - * Returns: - * 0 = success - */ -static int -qla1280_device_reset(struct scsi_qla_host *ha, int bus, int target) -{ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - int status; - - ENTER("qla1280_device_reset"); - - mb[0] = MBC_ABORT_TARGET; - mb[1] = (bus ? (target | BIT_7) : target) << 8; - mb[2] = 1; - status = qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); - - /* Issue marker command. */ - qla1280_marker(ha, bus, target, 0, MK_SYNC_ID); - - if (status) - dprintk(2, "qla1280_device_reset: **** FAILED ****\n"); - - LEAVE("qla1280_device_reset"); - return status; -} - -/* - * qla1280_abort_command - * Abort command aborts a specified IOCB. - * - * Input: - * ha = adapter block pointer. - * sp = SB structure pointer. - * - * Returns: - * 0 = success - */ -static int -qla1280_abort_command(struct scsi_qla_host *ha, struct srb * sp, int handle) -{ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - unsigned int bus, target, lun; - int status; - - ENTER("qla1280_abort_command"); - - bus = SCSI_BUS_32(sp->cmd); - target = SCSI_TCN_32(sp->cmd); - lun = SCSI_LUN_32(sp->cmd); - - sp->flags |= SRB_ABORT_PENDING; - - mb[0] = MBC_ABORT_COMMAND; - mb[1] = (bus ? target | BIT_7 : target) << 8 | lun; - mb[2] = handle >> 16; - mb[3] = handle & 0xffff; - status = qla1280_mailbox_command(ha, 0x0f, &mb[0]); - - if (status) { - dprintk(2, "qla1280_abort_command: **** FAILED ****\n"); - sp->flags &= ~SRB_ABORT_PENDING; - } - - - LEAVE("qla1280_abort_command"); - return status; -} - -/* - * qla1280_reset_adapter - * Reset adapter. - * - * Input: - * ha = adapter block pointer. - */ -static void -qla1280_reset_adapter(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg = ha->iobase; - - ENTER("qla1280_reset_adapter"); - - /* Disable ISP chip */ - ha->flags.online = 0; - WRT_REG_WORD(®->ictrl, ISP_RESET); - WRT_REG_WORD(®->host_cmd, - HC_RESET_RISC | HC_RELEASE_RISC | HC_DISABLE_BIOS); - RD_REG_WORD(®->id_l); /* Flush PCI write */ - - LEAVE("qla1280_reset_adapter"); -} - -/* - * Issue marker command. - * Function issues marker IOCB. - * - * Input: - * ha = adapter block pointer. - * bus = SCSI BUS number - * id = SCSI ID - * lun = SCSI LUN - * type = marker modifier - */ -static void -qla1280_marker(struct scsi_qla_host *ha, int bus, int id, int lun, u8 type) -{ - struct mrk_entry *pkt; - - ENTER("qla1280_marker"); - - /* Get request packet. */ - if ((pkt = (struct mrk_entry *) qla1280_req_pkt(ha))) { - pkt->entry_type = MARKER_TYPE; - pkt->lun = (uint8_t) lun; - pkt->target = (uint8_t) (bus ? (id | BIT_7) : id); - pkt->modifier = type; - pkt->entry_status = 0; - - /* Issue command to ISP */ - qla1280_isp_cmd(ha); - } - - LEAVE("qla1280_marker"); -} - - -/* - * qla1280_64bit_start_scsi - * The start SCSI is responsible for building request packets on - * request ring and modifying ISP input pointer. - * - * Input: - * ha = adapter block pointer. - * sp = SB structure pointer. - * - * Returns: - * 0 = success, was able to issue command. - */ -#ifdef QLA_64BIT_PTR -static int -qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) -{ - struct device_reg __iomem *reg = ha->iobase; - struct scsi_cmnd *cmd = sp->cmd; - cmd_a64_entry_t *pkt; - __le32 *dword_ptr; - dma_addr_t dma_handle; - int status = 0; - int cnt; - int req_cnt; - int seg_cnt; - u8 dir; - - ENTER("qla1280_64bit_start_scsi:"); - - /* Calculate number of entries and segments required. */ - req_cnt = 1; - seg_cnt = scsi_dma_map(cmd); - if (seg_cnt > 0) { - if (seg_cnt > 2) { - req_cnt += (seg_cnt - 2) / 5; - if ((seg_cnt - 2) % 5) - req_cnt++; - } - } else if (seg_cnt < 0) { - status = 1; - goto out; - } - - if ((req_cnt + 2) >= ha->req_q_cnt) { - /* Calculate number of free request entries. */ - cnt = RD_REG_WORD(®->mailbox4); - if (ha->req_ring_index < cnt) - ha->req_q_cnt = cnt - ha->req_ring_index; - else - ha->req_q_cnt = - REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); - } - - dprintk(3, "Number of free entries=(%d) seg_cnt=0x%x\n", - ha->req_q_cnt, seg_cnt); - - /* If room for request in request ring. */ - if ((req_cnt + 2) >= ha->req_q_cnt) { - status = SCSI_MLQUEUE_HOST_BUSY; - dprintk(2, "qla1280_start_scsi: in-ptr=0x%x req_q_cnt=" - "0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt, - req_cnt); - goto out; - } - - /* Check for room in outstanding command list. */ - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS && - ha->outstanding_cmds[cnt] != NULL; cnt++); - - if (cnt >= MAX_OUTSTANDING_COMMANDS) { - status = SCSI_MLQUEUE_HOST_BUSY; - dprintk(2, "qla1280_start_scsi: NO ROOM IN " - "OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt); - goto out; - } - - ha->outstanding_cmds[cnt] = sp; - ha->req_q_cnt -= req_cnt; - CMD_HANDLE(sp->cmd) = (unsigned char *)(unsigned long)(cnt + 1); - - dprintk(2, "start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp, - cmd->cmnd[0], (long)CMD_HANDLE(sp->cmd)); - dprintk(2, " bus %i, target %i, lun %i\n", - SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); - qla1280_dump_buffer(2, cmd->cmnd, MAX_COMMAND_SIZE); - - /* - * Build command packet. - */ - pkt = (cmd_a64_entry_t *) ha->request_ring_ptr; - - pkt->entry_type = COMMAND_A64_TYPE; - pkt->entry_count = (uint8_t) req_cnt; - pkt->sys_define = (uint8_t) ha->req_ring_index; - pkt->entry_status = 0; - pkt->handle = cpu_to_le32(cnt); - - /* Zero out remaining portion of packet. */ - memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); - - /* Set ISP command timeout. */ - pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ); - - /* Set device target ID and LUN */ - pkt->lun = SCSI_LUN_32(cmd); - pkt->target = SCSI_BUS_32(cmd) ? - (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd); - - /* Enable simple tag queuing if device supports it. */ - if (cmd->device->simple_tags) - pkt->control_flags |= cpu_to_le16(BIT_3); - - /* Load SCSI command packet. */ - pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd)); - memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd)); - /* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */ - - /* Set transfer direction. */ - dir = qla1280_data_direction(cmd); - pkt->control_flags |= cpu_to_le16(dir); - - /* Set total data segment count. */ - pkt->dseg_count = cpu_to_le16(seg_cnt); - - /* - * Load data segments. - */ - if (seg_cnt) { /* If data transfer. */ - struct scatterlist *sg, *s; - int remseg = seg_cnt; - - sg = scsi_sglist(cmd); - - /* Setup packet address segment pointer. */ - dword_ptr = (u32 *)&pkt->dseg_0_address; - - /* Load command entry data segments. */ - for_each_sg(sg, s, seg_cnt, cnt) { - if (cnt == 2) - break; - - dma_handle = sg_dma_address(s); -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) - if (ha->flags.use_pci_vchannel) - sn_pci_set_vchan(ha->pdev, - (unsigned long *)&dma_handle, - SCSI_BUS_32(cmd)); -#endif - *dword_ptr++ = - cpu_to_le32(pci_dma_lo32(dma_handle)); - *dword_ptr++ = - cpu_to_le32(pci_dma_hi32(dma_handle)); - *dword_ptr++ = cpu_to_le32(sg_dma_len(s)); - dprintk(3, "S/G Segment phys_addr=%x %x, len=0x%x\n", - cpu_to_le32(pci_dma_hi32(dma_handle)), - cpu_to_le32(pci_dma_lo32(dma_handle)), - cpu_to_le32(sg_dma_len(sg_next(s)))); - remseg--; - } - dprintk(5, "qla1280_64bit_start_scsi: Scatter/gather " - "command packet data - b %i, t %i, l %i \n", - SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), - SCSI_LUN_32(cmd)); - qla1280_dump_buffer(5, (char *)pkt, - REQUEST_ENTRY_SIZE); - - /* - * Build continuation packets. - */ - dprintk(3, "S/G Building Continuation...seg_cnt=0x%x " - "remains\n", seg_cnt); - - while (remseg > 0) { - /* Update sg start */ - sg = s; - /* Adjust ring index. */ - ha->req_ring_index++; - if (ha->req_ring_index == REQUEST_ENTRY_CNT) { - ha->req_ring_index = 0; - ha->request_ring_ptr = - ha->request_ring; - } else - ha->request_ring_ptr++; - - pkt = (cmd_a64_entry_t *)ha->request_ring_ptr; - - /* Zero out packet. */ - memset(pkt, 0, REQUEST_ENTRY_SIZE); - - /* Load packet defaults. */ - ((struct cont_a64_entry *) pkt)->entry_type = - CONTINUE_A64_TYPE; - ((struct cont_a64_entry *) pkt)->entry_count = 1; - ((struct cont_a64_entry *) pkt)->sys_define = - (uint8_t)ha->req_ring_index; - /* Setup packet address segment pointer. */ - dword_ptr = - (u32 *)&((struct cont_a64_entry *) pkt)->dseg_0_address; - - /* Load continuation entry data segments. */ - for_each_sg(sg, s, remseg, cnt) { - if (cnt == 5) - break; - dma_handle = sg_dma_address(s); -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) - if (ha->flags.use_pci_vchannel) - sn_pci_set_vchan(ha->pdev, - (unsigned long *)&dma_handle, - SCSI_BUS_32(cmd)); -#endif - *dword_ptr++ = - cpu_to_le32(pci_dma_lo32(dma_handle)); - *dword_ptr++ = - cpu_to_le32(pci_dma_hi32(dma_handle)); - *dword_ptr++ = - cpu_to_le32(sg_dma_len(s)); - dprintk(3, "S/G Segment Cont. phys_addr=%x %x, len=0x%x\n", - cpu_to_le32(pci_dma_hi32(dma_handle)), - cpu_to_le32(pci_dma_lo32(dma_handle)), - cpu_to_le32(sg_dma_len(s))); - } - remseg -= cnt; - dprintk(5, "qla1280_64bit_start_scsi: " - "continuation packet data - b %i, t " - "%i, l %i \n", SCSI_BUS_32(cmd), - SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); - qla1280_dump_buffer(5, (char *)pkt, - REQUEST_ENTRY_SIZE); - } - } else { /* No data transfer */ - dprintk(5, "qla1280_64bit_start_scsi: No data, command " - "packet data - b %i, t %i, l %i \n", - SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); - qla1280_dump_buffer(5, (char *)pkt, REQUEST_ENTRY_SIZE); - } - /* Adjust ring index. */ - ha->req_ring_index++; - if (ha->req_ring_index == REQUEST_ENTRY_CNT) { - ha->req_ring_index = 0; - ha->request_ring_ptr = ha->request_ring; - } else - ha->request_ring_ptr++; - - /* Set chip new ring index. */ - dprintk(2, - "qla1280_64bit_start_scsi: Wakeup RISC for pending command\n"); - sp->flags |= SRB_SENT; - ha->actthreads++; - WRT_REG_WORD(®->mailbox4, ha->req_ring_index); - /* Enforce mmio write ordering; see comment in qla1280_isp_cmd(). */ - mmiowb(); - - out: - if (status) - dprintk(2, "qla1280_64bit_start_scsi: **** FAILED ****\n"); - else - dprintk(3, "qla1280_64bit_start_scsi: exiting normally\n"); - - return status; -} -#else /* !QLA_64BIT_PTR */ - -/* - * qla1280_32bit_start_scsi - * The start SCSI is responsible for building request packets on - * request ring and modifying ISP input pointer. - * - * The Qlogic firmware interface allows every queue slot to have a SCSI - * command and up to 4 scatter/gather (SG) entries. If we need more - * than 4 SG entries, then continuation entries are used that can - * hold another 7 entries each. The start routine determines if there - * is eought empty slots then build the combination of requests to - * fulfill the OS request. - * - * Input: - * ha = adapter block pointer. - * sp = SCSI Request Block structure pointer. - * - * Returns: - * 0 = success, was able to issue command. - */ -static int -qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) -{ - struct device_reg __iomem *reg = ha->iobase; - struct scsi_cmnd *cmd = sp->cmd; - struct cmd_entry *pkt; - __le32 *dword_ptr; - int status = 0; - int cnt; - int req_cnt; - int seg_cnt; - u8 dir; - - ENTER("qla1280_32bit_start_scsi"); - - dprintk(1, "32bit_start: cmd=%p sp=%p CDB=%x\n", cmd, sp, - cmd->cmnd[0]); - - /* Calculate number of entries and segments required. */ - req_cnt = 1; - seg_cnt = scsi_dma_map(cmd); - if (seg_cnt) { - /* - * if greater than four sg entries then we need to allocate - * continuation entries - */ - if (seg_cnt > 4) { - req_cnt += (seg_cnt - 4) / 7; - if ((seg_cnt - 4) % 7) - req_cnt++; - } - dprintk(3, "S/G Transfer cmd=%p seg_cnt=0x%x, req_cnt=%x\n", - cmd, seg_cnt, req_cnt); - } else if (seg_cnt < 0) { - status = 1; - goto out; - } - - if ((req_cnt + 2) >= ha->req_q_cnt) { - /* Calculate number of free request entries. */ - cnt = RD_REG_WORD(®->mailbox4); - if (ha->req_ring_index < cnt) - ha->req_q_cnt = cnt - ha->req_ring_index; - else - ha->req_q_cnt = - REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); - } - - dprintk(3, "Number of free entries=(%d) seg_cnt=0x%x\n", - ha->req_q_cnt, seg_cnt); - /* If room for request in request ring. */ - if ((req_cnt + 2) >= ha->req_q_cnt) { - status = SCSI_MLQUEUE_HOST_BUSY; - dprintk(2, "qla1280_32bit_start_scsi: in-ptr=0x%x, " - "req_q_cnt=0x%x, req_cnt=0x%x", ha->req_ring_index, - ha->req_q_cnt, req_cnt); - goto out; - } - - /* Check for empty slot in outstanding command list. */ - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS && - (ha->outstanding_cmds[cnt] != 0); cnt++) ; - - if (cnt >= MAX_OUTSTANDING_COMMANDS) { - status = SCSI_MLQUEUE_HOST_BUSY; - dprintk(2, "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING " - "ARRAY, req_q_cnt=0x%x\n", ha->req_q_cnt); - goto out; - } - - CMD_HANDLE(sp->cmd) = (unsigned char *) (unsigned long)(cnt + 1); - ha->outstanding_cmds[cnt] = sp; - ha->req_q_cnt -= req_cnt; - - /* - * Build command packet. - */ - pkt = (struct cmd_entry *) ha->request_ring_ptr; - - pkt->entry_type = COMMAND_TYPE; - pkt->entry_count = (uint8_t) req_cnt; - pkt->sys_define = (uint8_t) ha->req_ring_index; - pkt->entry_status = 0; - pkt->handle = cpu_to_le32(cnt); - - /* Zero out remaining portion of packet. */ - memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); - - /* Set ISP command timeout. */ - pkt->timeout = cpu_to_le16(cmd->request->timeout/HZ); - - /* Set device target ID and LUN */ - pkt->lun = SCSI_LUN_32(cmd); - pkt->target = SCSI_BUS_32(cmd) ? - (SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd); - - /* Enable simple tag queuing if device supports it. */ - if (cmd->device->simple_tags) - pkt->control_flags |= cpu_to_le16(BIT_3); - - /* Load SCSI command packet. */ - pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd)); - memcpy(pkt->scsi_cdb, CMD_CDBP(cmd), CMD_CDBLEN(cmd)); - - /*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */ - /* Set transfer direction. */ - dir = qla1280_data_direction(cmd); - pkt->control_flags |= cpu_to_le16(dir); - - /* Set total data segment count. */ - pkt->dseg_count = cpu_to_le16(seg_cnt); - - /* - * Load data segments. - */ - if (seg_cnt) { - struct scatterlist *sg, *s; - int remseg = seg_cnt; - - sg = scsi_sglist(cmd); - - /* Setup packet address segment pointer. */ - dword_ptr = &pkt->dseg_0_address; - - dprintk(3, "Building S/G data segments..\n"); - qla1280_dump_buffer(1, (char *)sg, 4 * 16); - - /* Load command entry data segments. */ - for_each_sg(sg, s, seg_cnt, cnt) { - if (cnt == 4) - break; - *dword_ptr++ = - cpu_to_le32(pci_dma_lo32(sg_dma_address(s))); - *dword_ptr++ = cpu_to_le32(sg_dma_len(s)); - dprintk(3, "S/G Segment phys_addr=0x%lx, len=0x%x\n", - (pci_dma_lo32(sg_dma_address(s))), - (sg_dma_len(s))); - remseg--; - } - /* - * Build continuation packets. - */ - dprintk(3, "S/G Building Continuation" - "...seg_cnt=0x%x remains\n", seg_cnt); - while (remseg > 0) { - /* Continue from end point */ - sg = s; - /* Adjust ring index. */ - ha->req_ring_index++; - if (ha->req_ring_index == REQUEST_ENTRY_CNT) { - ha->req_ring_index = 0; - ha->request_ring_ptr = - ha->request_ring; - } else - ha->request_ring_ptr++; - - pkt = (struct cmd_entry *)ha->request_ring_ptr; - - /* Zero out packet. */ - memset(pkt, 0, REQUEST_ENTRY_SIZE); - - /* Load packet defaults. */ - ((struct cont_entry *) pkt)-> - entry_type = CONTINUE_TYPE; - ((struct cont_entry *) pkt)->entry_count = 1; - - ((struct cont_entry *) pkt)->sys_define = - (uint8_t) ha->req_ring_index; - - /* Setup packet address segment pointer. */ - dword_ptr = - &((struct cont_entry *) pkt)->dseg_0_address; - - /* Load continuation entry data segments. */ - for_each_sg(sg, s, remseg, cnt) { - if (cnt == 7) - break; - *dword_ptr++ = - cpu_to_le32(pci_dma_lo32(sg_dma_address(s))); - *dword_ptr++ = - cpu_to_le32(sg_dma_len(s)); - dprintk(1, - "S/G Segment Cont. phys_addr=0x%x, " - "len=0x%x\n", - cpu_to_le32(pci_dma_lo32(sg_dma_address(s))), - cpu_to_le32(sg_dma_len(s))); - } - remseg -= cnt; - dprintk(5, "qla1280_32bit_start_scsi: " - "continuation packet data - " - "scsi(%i:%i:%i)\n", SCSI_BUS_32(cmd), - SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); - qla1280_dump_buffer(5, (char *)pkt, - REQUEST_ENTRY_SIZE); - } - } else { /* No data transfer at all */ - dprintk(5, "qla1280_32bit_start_scsi: No data, command " - "packet data - \n"); - qla1280_dump_buffer(5, (char *)pkt, REQUEST_ENTRY_SIZE); - } - dprintk(5, "qla1280_32bit_start_scsi: First IOCB block:\n"); - qla1280_dump_buffer(5, (char *)ha->request_ring_ptr, - REQUEST_ENTRY_SIZE); - - /* Adjust ring index. */ - ha->req_ring_index++; - if (ha->req_ring_index == REQUEST_ENTRY_CNT) { - ha->req_ring_index = 0; - ha->request_ring_ptr = ha->request_ring; - } else - ha->request_ring_ptr++; - - /* Set chip new ring index. */ - dprintk(2, "qla1280_32bit_start_scsi: Wakeup RISC " - "for pending command\n"); - sp->flags |= SRB_SENT; - ha->actthreads++; - WRT_REG_WORD(®->mailbox4, ha->req_ring_index); - /* Enforce mmio write ordering; see comment in qla1280_isp_cmd(). */ - mmiowb(); - -out: - if (status) - dprintk(2, "qla1280_32bit_start_scsi: **** FAILED ****\n"); - - LEAVE("qla1280_32bit_start_scsi"); - - return status; -} -#endif - -/* - * qla1280_req_pkt - * Function is responsible for locking ring and - * getting a zeroed out request packet. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = failed to get slot. - */ -static request_t * -qla1280_req_pkt(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg = ha->iobase; - request_t *pkt = NULL; - int cnt; - uint32_t timer; - - ENTER("qla1280_req_pkt"); - - /* - * This can be called from interrupt context, damn it!!! - */ - /* Wait for 30 seconds for slot. */ - for (timer = 15000000; timer; timer--) { - if (ha->req_q_cnt > 0) { - /* Calculate number of free request entries. */ - cnt = RD_REG_WORD(®->mailbox4); - if (ha->req_ring_index < cnt) - ha->req_q_cnt = cnt - ha->req_ring_index; - else - ha->req_q_cnt = - REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); - } - - /* Found empty request ring slot? */ - if (ha->req_q_cnt > 0) { - ha->req_q_cnt--; - pkt = ha->request_ring_ptr; - - /* Zero out packet. */ - memset(pkt, 0, REQUEST_ENTRY_SIZE); - - /* - * How can this be right when we have a ring - * size of 512??? - */ - /* Set system defined field. */ - pkt->sys_define = (uint8_t) ha->req_ring_index; - - /* Set entry count. */ - pkt->entry_count = 1; - - break; - } - - udelay(2); /* 10 */ - - /* Check for pending interrupts. */ - qla1280_poll(ha); - } - - if (!pkt) - dprintk(2, "qla1280_req_pkt: **** FAILED ****\n"); - else - dprintk(3, "qla1280_req_pkt: exiting normally\n"); - - return pkt; -} - -/* - * qla1280_isp_cmd - * Function is responsible for modifying ISP input pointer. - * Releases ring lock. - * - * Input: - * ha = adapter block pointer. - */ -static void -qla1280_isp_cmd(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg = ha->iobase; - - ENTER("qla1280_isp_cmd"); - - dprintk(5, "qla1280_isp_cmd: IOCB data:\n"); - qla1280_dump_buffer(5, (char *)ha->request_ring_ptr, - REQUEST_ENTRY_SIZE); - - /* Adjust ring index. */ - ha->req_ring_index++; - if (ha->req_ring_index == REQUEST_ENTRY_CNT) { - ha->req_ring_index = 0; - ha->request_ring_ptr = ha->request_ring; - } else - ha->request_ring_ptr++; - - /* - * Update request index to mailbox4 (Request Queue In). - * The mmiowb() ensures that this write is ordered with writes by other - * CPUs. Without the mmiowb(), it is possible for the following: - * CPUA posts write of index 5 to mailbox4 - * CPUA releases host lock - * CPUB acquires host lock - * CPUB posts write of index 6 to mailbox4 - * On PCI bus, order reverses and write of 6 posts, then index 5, - * causing chip to issue full queue of stale commands - * The mmiowb() prevents future writes from crossing the barrier. - * See Documentation/DocBook/deviceiobook.tmpl for more information. - */ - WRT_REG_WORD(®->mailbox4, ha->req_ring_index); - mmiowb(); - - LEAVE("qla1280_isp_cmd"); -} - -/****************************************************************************/ -/* Interrupt Service Routine. */ -/****************************************************************************/ - -/**************************************************************************** - * qla1280_isr - * Calls I/O done on command completion. - * - * Input: - * ha = adapter block pointer. - * done_q = done queue. - ****************************************************************************/ -static void -qla1280_isr(struct scsi_qla_host *ha, struct list_head *done_q) -{ - struct device_reg __iomem *reg = ha->iobase; - struct response *pkt; - struct srb *sp = NULL; - uint16_t mailbox[MAILBOX_REGISTER_COUNT]; - uint16_t *wptr; - uint32_t index; - u16 istatus; - - ENTER("qla1280_isr"); - - istatus = RD_REG_WORD(®->istatus); - if (!(istatus & (RISC_INT | PCI_INT))) - return; - - /* Save mailbox register 5 */ - mailbox[5] = RD_REG_WORD(®->mailbox5); - - /* Check for mailbox interrupt. */ - - mailbox[0] = RD_REG_WORD_dmasync(®->semaphore); - - if (mailbox[0] & BIT_0) { - /* Get mailbox data. */ - /* dprintk(1, "qla1280_isr: In Get mailbox data \n"); */ - - wptr = &mailbox[0]; - *wptr++ = RD_REG_WORD(®->mailbox0); - *wptr++ = RD_REG_WORD(®->mailbox1); - *wptr = RD_REG_WORD(®->mailbox2); - if (mailbox[0] != MBA_SCSI_COMPLETION) { - wptr++; - *wptr++ = RD_REG_WORD(®->mailbox3); - *wptr++ = RD_REG_WORD(®->mailbox4); - wptr++; - *wptr++ = RD_REG_WORD(®->mailbox6); - *wptr = RD_REG_WORD(®->mailbox7); - } - - /* Release mailbox registers. */ - - WRT_REG_WORD(®->semaphore, 0); - WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); - - dprintk(5, "qla1280_isr: mailbox interrupt mailbox[0] = 0x%x", - mailbox[0]); - - /* Handle asynchronous event */ - switch (mailbox[0]) { - case MBA_SCSI_COMPLETION: /* Response completion */ - dprintk(5, "qla1280_isr: mailbox SCSI response " - "completion\n"); - - if (ha->flags.online) { - /* Get outstanding command index. */ - index = mailbox[2] << 16 | mailbox[1]; - - /* Validate handle. */ - if (index < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[index]; - else - sp = NULL; - - if (sp) { - /* Free outstanding command slot. */ - ha->outstanding_cmds[index] = NULL; - - /* Save ISP completion status */ - CMD_RESULT(sp->cmd) = 0; - CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; - - /* Place block on done queue */ - list_add_tail(&sp->list, done_q); - } else { - /* - * If we get here we have a real problem! - */ - printk(KERN_WARNING - "qla1280: ISP invalid handle\n"); - } - } - break; - - case MBA_BUS_RESET: /* SCSI Bus Reset */ - ha->flags.reset_marker = 1; - index = mailbox[6] & BIT_0; - ha->bus_settings[index].reset_marker = 1; - - printk(KERN_DEBUG "qla1280_isr(): index %i " - "asynchronous BUS_RESET\n", index); - break; - - case MBA_SYSTEM_ERR: /* System Error */ - printk(KERN_WARNING - "qla1280: ISP System Error - mbx1=%xh, mbx2=" - "%xh, mbx3=%xh\n", mailbox[1], mailbox[2], - mailbox[3]); - break; - - case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ - printk(KERN_WARNING - "qla1280: ISP Request Transfer Error\n"); - break; - - case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ - printk(KERN_WARNING - "qla1280: ISP Response Transfer Error\n"); - break; - - case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ - dprintk(2, "qla1280_isr: asynchronous WAKEUP_THRES\n"); - break; - - case MBA_TIMEOUT_RESET: /* Execution Timeout Reset */ - dprintk(2, - "qla1280_isr: asynchronous TIMEOUT_RESET\n"); - break; - - case MBA_DEVICE_RESET: /* Bus Device Reset */ - printk(KERN_INFO "qla1280_isr(): asynchronous " - "BUS_DEVICE_RESET\n"); - - ha->flags.reset_marker = 1; - index = mailbox[6] & BIT_0; - ha->bus_settings[index].reset_marker = 1; - break; - - case MBA_BUS_MODE_CHANGE: - dprintk(2, - "qla1280_isr: asynchronous BUS_MODE_CHANGE\n"); - break; - - default: - /* dprintk(1, "qla1280_isr: default case of switch MB \n"); */ - if (mailbox[0] < MBA_ASYNC_EVENT) { - wptr = &mailbox[0]; - memcpy((uint16_t *) ha->mailbox_out, wptr, - MAILBOX_REGISTER_COUNT * - sizeof(uint16_t)); - - if(ha->mailbox_wait != NULL) - complete(ha->mailbox_wait); - } - break; - } - } else { - WRT_REG_WORD(®->host_cmd, HC_CLR_RISC_INT); - } - - /* - * We will receive interrupts during mailbox testing prior to - * the card being marked online, hence the double check. - */ - if (!(ha->flags.online && !ha->mailbox_wait)) { - dprintk(2, "qla1280_isr: Response pointer Error\n"); - goto out; - } - - if (mailbox[5] >= RESPONSE_ENTRY_CNT) - goto out; - - while (ha->rsp_ring_index != mailbox[5]) { - pkt = ha->response_ring_ptr; - - dprintk(5, "qla1280_isr: ha->rsp_ring_index = 0x%x, mailbox[5]" - " = 0x%x\n", ha->rsp_ring_index, mailbox[5]); - dprintk(5,"qla1280_isr: response packet data\n"); - qla1280_dump_buffer(5, (char *)pkt, RESPONSE_ENTRY_SIZE); - - if (pkt->entry_type == STATUS_TYPE) { - if ((le16_to_cpu(pkt->scsi_status) & 0xff) - || pkt->comp_status || pkt->entry_status) { - dprintk(2, "qla1280_isr: ha->rsp_ring_index = " - "0x%x mailbox[5] = 0x%x, comp_status " - "= 0x%x, scsi_status = 0x%x\n", - ha->rsp_ring_index, mailbox[5], - le16_to_cpu(pkt->comp_status), - le16_to_cpu(pkt->scsi_status)); - } - } else { - dprintk(2, "qla1280_isr: ha->rsp_ring_index = " - "0x%x, mailbox[5] = 0x%x\n", - ha->rsp_ring_index, mailbox[5]); - dprintk(2, "qla1280_isr: response packet data\n"); - qla1280_dump_buffer(2, (char *)pkt, - RESPONSE_ENTRY_SIZE); - } - - if (pkt->entry_type == STATUS_TYPE || pkt->entry_status) { - dprintk(2, "status: Cmd %p, handle %i\n", - ha->outstanding_cmds[pkt->handle]->cmd, - pkt->handle); - if (pkt->entry_type == STATUS_TYPE) - qla1280_status_entry(ha, pkt, done_q); - else - qla1280_error_entry(ha, pkt, done_q); - /* Adjust ring index. */ - ha->rsp_ring_index++; - if (ha->rsp_ring_index == RESPONSE_ENTRY_CNT) { - ha->rsp_ring_index = 0; - ha->response_ring_ptr = ha->response_ring; - } else - ha->response_ring_ptr++; - WRT_REG_WORD(®->mailbox5, ha->rsp_ring_index); - } - } - - out: - LEAVE("qla1280_isr"); -} - -/* - * qla1280_rst_aen - * Processes asynchronous reset. - * - * Input: - * ha = adapter block pointer. - */ -static void -qla1280_rst_aen(struct scsi_qla_host *ha) -{ - uint8_t bus; - - ENTER("qla1280_rst_aen"); - - if (ha->flags.online && !ha->flags.reset_active && - !ha->flags.abort_isp_active) { - ha->flags.reset_active = 1; - while (ha->flags.reset_marker) { - /* Issue marker command. */ - ha->flags.reset_marker = 0; - for (bus = 0; bus < ha->ports && - !ha->flags.reset_marker; bus++) { - if (ha->bus_settings[bus].reset_marker) { - ha->bus_settings[bus].reset_marker = 0; - qla1280_marker(ha, bus, 0, 0, - MK_SYNC_ALL); - } - } - } - } - - LEAVE("qla1280_rst_aen"); -} - - -/* - * qla1280_status_entry - * Processes received ISP status entry. - * - * Input: - * ha = adapter block pointer. - * pkt = entry pointer. - * done_q = done queue. - */ -static void -qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt, - struct list_head *done_q) -{ - unsigned int bus, target, lun; - int sense_sz; - struct srb *sp; - struct scsi_cmnd *cmd; - uint32_t handle = le32_to_cpu(pkt->handle); - uint16_t scsi_status = le16_to_cpu(pkt->scsi_status); - uint16_t comp_status = le16_to_cpu(pkt->comp_status); - - ENTER("qla1280_status_entry"); - - /* Validate handle. */ - if (handle < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[handle]; - else - sp = NULL; - - if (!sp) { - printk(KERN_WARNING "qla1280: Status Entry invalid handle\n"); - goto out; - } - - /* Free outstanding command slot. */ - ha->outstanding_cmds[handle] = NULL; - - cmd = sp->cmd; - - /* Generate LU queue on cntrl, target, LUN */ - bus = SCSI_BUS_32(cmd); - target = SCSI_TCN_32(cmd); - lun = SCSI_LUN_32(cmd); - - if (comp_status || scsi_status) { - dprintk(3, "scsi: comp_status = 0x%x, scsi_status = " - "0x%x, handle = 0x%x\n", comp_status, - scsi_status, handle); - } - - /* Target busy or queue full */ - if ((scsi_status & 0xFF) == SAM_STAT_TASK_SET_FULL || - (scsi_status & 0xFF) == SAM_STAT_BUSY) { - CMD_RESULT(cmd) = scsi_status & 0xff; - } else { - - /* Save ISP completion status */ - CMD_RESULT(cmd) = qla1280_return_status(pkt, cmd); - - if (scsi_status & SAM_STAT_CHECK_CONDITION) { - if (comp_status != CS_ARS_FAILED) { - uint16_t req_sense_length = - le16_to_cpu(pkt->req_sense_length); - if (req_sense_length < CMD_SNSLEN(cmd)) - sense_sz = req_sense_length; - else - /* - * scsi_cmnd->sense_buffer is - * 64 bytes, why only copy 63? - * This looks wrong! /Jes - */ - sense_sz = CMD_SNSLEN(cmd) - 1; - - memcpy(cmd->sense_buffer, - &pkt->req_sense_data, sense_sz); - } else - sense_sz = 0; - memset(cmd->sense_buffer + sense_sz, 0, - SCSI_SENSE_BUFFERSIZE - sense_sz); - - dprintk(2, "qla1280_status_entry: Check " - "condition Sense data, b %i, t %i, " - "l %i\n", bus, target, lun); - if (sense_sz) - qla1280_dump_buffer(2, - (char *)cmd->sense_buffer, - sense_sz); - } - } - - CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; - - /* Place command on done queue. */ - list_add_tail(&sp->list, done_q); - out: - LEAVE("qla1280_status_entry"); -} - -/* - * qla1280_error_entry - * Processes error entry. - * - * Input: - * ha = adapter block pointer. - * pkt = entry pointer. - * done_q = done queue. - */ -static void -qla1280_error_entry(struct scsi_qla_host *ha, struct response *pkt, - struct list_head *done_q) -{ - struct srb *sp; - uint32_t handle = le32_to_cpu(pkt->handle); - - ENTER("qla1280_error_entry"); - - if (pkt->entry_status & BIT_3) - dprintk(2, "qla1280_error_entry: BAD PAYLOAD flag error\n"); - else if (pkt->entry_status & BIT_2) - dprintk(2, "qla1280_error_entry: BAD HEADER flag error\n"); - else if (pkt->entry_status & BIT_1) - dprintk(2, "qla1280_error_entry: FULL flag error\n"); - else - dprintk(2, "qla1280_error_entry: UNKNOWN flag error\n"); - - /* Validate handle. */ - if (handle < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[handle]; - else - sp = NULL; - - if (sp) { - /* Free outstanding command slot. */ - ha->outstanding_cmds[handle] = NULL; - - /* Bad payload or header */ - if (pkt->entry_status & (BIT_3 + BIT_2)) { - /* Bad payload or header, set error status. */ - /* CMD_RESULT(sp->cmd) = CS_BAD_PAYLOAD; */ - CMD_RESULT(sp->cmd) = DID_ERROR << 16; - } else if (pkt->entry_status & BIT_1) { /* FULL flag */ - CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16; - } else { - /* Set error status. */ - CMD_RESULT(sp->cmd) = DID_ERROR << 16; - } - - CMD_HANDLE(sp->cmd) = COMPLETED_HANDLE; - - /* Place command on done queue. */ - list_add_tail(&sp->list, done_q); - } -#ifdef QLA_64BIT_PTR - else if (pkt->entry_type == COMMAND_A64_TYPE) { - printk(KERN_WARNING "!qla1280: Error Entry invalid handle"); - } -#endif - - LEAVE("qla1280_error_entry"); -} - -/* - * qla1280_abort_isp - * Resets ISP and aborts all outstanding commands. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success - */ -static int -qla1280_abort_isp(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg = ha->iobase; - struct srb *sp; - int status = 0; - int cnt; - int bus; - - ENTER("qla1280_abort_isp"); - - if (ha->flags.abort_isp_active || !ha->flags.online) - goto out; - - ha->flags.abort_isp_active = 1; - - /* Disable ISP interrupts. */ - qla1280_disable_intrs(ha); - WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); - RD_REG_WORD(®->id_l); - - printk(KERN_INFO "scsi(%li): dequeuing outstanding commands\n", - ha->host_no); - /* Dequeue all commands in outstanding command list. */ - for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - struct scsi_cmnd *cmd; - sp = ha->outstanding_cmds[cnt]; - if (sp) { - cmd = sp->cmd; - CMD_RESULT(cmd) = DID_RESET << 16; - CMD_HANDLE(cmd) = COMPLETED_HANDLE; - ha->outstanding_cmds[cnt] = NULL; - list_add_tail(&sp->list, &ha->done_q); - } - } - - qla1280_done(ha); - - status = qla1280_load_firmware(ha); - if (status) - goto out; - - /* Setup adapter based on NVRAM parameters. */ - qla1280_nvram_config (ha); - - status = qla1280_init_rings(ha); - if (status) - goto out; - - /* Issue SCSI reset. */ - for (bus = 0; bus < ha->ports; bus++) - qla1280_bus_reset(ha, bus); - - ha->flags.abort_isp_active = 0; - out: - if (status) { - printk(KERN_WARNING - "qla1280: ISP error recovery failed, board disabled"); - qla1280_reset_adapter(ha); - dprintk(2, "qla1280_abort_isp: **** FAILED ****\n"); - } - - LEAVE("qla1280_abort_isp"); - return status; -} - - -/* - * qla1280_debounce_register - * Debounce register. - * - * Input: - * port = register address. - * - * Returns: - * register value. - */ -static u16 -qla1280_debounce_register(volatile u16 __iomem * addr) -{ - volatile u16 ret; - volatile u16 ret2; - - ret = RD_REG_WORD(addr); - ret2 = RD_REG_WORD(addr); - - if (ret == ret2) - return ret; - - do { - cpu_relax(); - ret = RD_REG_WORD(addr); - ret2 = RD_REG_WORD(addr); - } while (ret != ret2); - - return ret; -} - - -/************************************************************************ - * qla1280_check_for_dead_scsi_bus * - * * - * This routine checks for a dead SCSI bus * - ************************************************************************/ -#define SET_SXP_BANK 0x0100 -#define SCSI_PHASE_INVALID 0x87FF -static int -qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *ha, unsigned int bus) -{ - uint16_t config_reg, scsi_control; - struct device_reg __iomem *reg = ha->iobase; - - if (ha->bus_settings[bus].scsi_bus_dead) { - WRT_REG_WORD(®->host_cmd, HC_PAUSE_RISC); - config_reg = RD_REG_WORD(®->cfg_1); - WRT_REG_WORD(®->cfg_1, SET_SXP_BANK); - scsi_control = RD_REG_WORD(®->scsiControlPins); - WRT_REG_WORD(®->cfg_1, config_reg); - WRT_REG_WORD(®->host_cmd, HC_RELEASE_RISC); - - if (scsi_control == SCSI_PHASE_INVALID) { - ha->bus_settings[bus].scsi_bus_dead = 1; - return 1; /* bus is dead */ - } else { - ha->bus_settings[bus].scsi_bus_dead = 0; - ha->bus_settings[bus].failed_reset_count = 0; - } - } - return 0; /* bus is not dead */ -} - -static void -qla1280_get_target_parameters(struct scsi_qla_host *ha, - struct scsi_device *device) -{ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - int bus, target, lun; - - bus = device->channel; - target = device->id; - lun = device->lun; - - - mb[0] = MBC_GET_TARGET_PARAMETERS; - mb[1] = (uint16_t) (bus ? target | BIT_7 : target); - mb[1] <<= 8; - qla1280_mailbox_command(ha, BIT_6 | BIT_3 | BIT_2 | BIT_1 | BIT_0, - &mb[0]); - - printk(KERN_INFO "scsi(%li:%d:%d:%d):", ha->host_no, bus, target, lun); - - if (mb[3] != 0) { - printk(" Sync: period %d, offset %d", - (mb[3] & 0xff), (mb[3] >> 8)); - if (mb[2] & BIT_13) - printk(", Wide"); - if ((mb[2] & BIT_5) && ((mb[6] >> 8) & 0xff) >= 2) - printk(", DT"); - } else - printk(" Async"); - - if (device->simple_tags) - printk(", Tagged queuing: depth %d", device->queue_depth); - printk("\n"); -} - - -#if DEBUG_QLA1280 -static void -__qla1280_dump_buffer(char *b, int size) -{ - int cnt; - u8 c; - - printk(KERN_DEBUG " 0 1 2 3 4 5 6 7 8 9 Ah " - "Bh Ch Dh Eh Fh\n"); - printk(KERN_DEBUG "---------------------------------------------" - "------------------\n"); - - for (cnt = 0; cnt < size;) { - c = *b++; - - printk("0x%02x", c); - cnt++; - if (!(cnt % 16)) - printk("\n"); - else - printk(" "); - } - if (cnt % 16) - printk("\n"); -} - -/************************************************************************** - * ql1280_print_scsi_cmd - * - **************************************************************************/ -static void -__qla1280_print_scsi_cmd(struct scsi_cmnd *cmd) -{ - struct scsi_qla_host *ha; - struct Scsi_Host *host = CMD_HOST(cmd); - struct srb *sp; - /* struct scatterlist *sg; */ - - int i; - ha = (struct scsi_qla_host *)host->hostdata; - - sp = (struct srb *)CMD_SP(cmd); - printk("SCSI Command @= 0x%p, Handle=0x%p\n", cmd, CMD_HANDLE(cmd)); - printk(" chan=%d, target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", - SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd), - CMD_CDBLEN(cmd)); - printk(" CDB = "); - for (i = 0; i < cmd->cmd_len; i++) { - printk("0x%02x ", cmd->cmnd[i]); - } - printk(" seg_cnt =%d\n", scsi_sg_count(cmd)); - printk(" request buffer=0x%p, request buffer len=0x%x\n", - scsi_sglist(cmd), scsi_bufflen(cmd)); - /* if (cmd->use_sg) - { - sg = (struct scatterlist *) cmd->request_buffer; - printk(" SG buffer: \n"); - qla1280_dump_buffer(1, (char *)sg, (cmd->use_sg*sizeof(struct scatterlist))); - } */ - printk(" tag=%d, transfersize=0x%x \n", - cmd->tag, cmd->transfersize); - printk(" SP=0x%p\n", CMD_SP(cmd)); - printk(" underflow size = 0x%x, direction=0x%x\n", - cmd->underflow, cmd->sc_data_direction); -} - -/************************************************************************** - * ql1280_dump_device - * - **************************************************************************/ -static void -ql1280_dump_device(struct scsi_qla_host *ha) -{ - - struct scsi_cmnd *cp; - struct srb *sp; - int i; - - printk(KERN_DEBUG "Outstanding Commands on controller:\n"); - - for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) { - if ((sp = ha->outstanding_cmds[i]) == NULL) - continue; - if ((cp = sp->cmd) == NULL) - continue; - qla1280_print_scsi_cmd(1, cp); - } -} -#endif - - -enum tokens { - TOKEN_NVRAM, - TOKEN_SYNC, - TOKEN_WIDE, - TOKEN_PPR, - TOKEN_VERBOSE, - TOKEN_DEBUG, -}; - -struct setup_tokens { - char *token; - int val; -}; - -static struct setup_tokens setup_token[] __initdata = -{ - { "nvram", TOKEN_NVRAM }, - { "sync", TOKEN_SYNC }, - { "wide", TOKEN_WIDE }, - { "ppr", TOKEN_PPR }, - { "verbose", TOKEN_VERBOSE }, - { "debug", TOKEN_DEBUG }, -}; - - -/************************************************************************** - * qla1280_setup - * - * Handle boot parameters. This really needs to be changed so one - * can specify per adapter parameters. - **************************************************************************/ -static int __init -qla1280_setup(char *s) -{ - char *cp, *ptr; - unsigned long val; - int toke; - - cp = s; - - while (cp && (ptr = strchr(cp, ':'))) { - ptr++; - if (!strcmp(ptr, "yes")) { - val = 0x10000; - ptr += 3; - } else if (!strcmp(ptr, "no")) { - val = 0; - ptr += 2; - } else - val = simple_strtoul(ptr, &ptr, 0); - - switch ((toke = qla1280_get_token(cp))) { - case TOKEN_NVRAM: - if (!val) - driver_setup.no_nvram = 1; - break; - case TOKEN_SYNC: - if (!val) - driver_setup.no_sync = 1; - else if (val != 0x10000) - driver_setup.sync_mask = val; - break; - case TOKEN_WIDE: - if (!val) - driver_setup.no_wide = 1; - else if (val != 0x10000) - driver_setup.wide_mask = val; - break; - case TOKEN_PPR: - if (!val) - driver_setup.no_ppr = 1; - else if (val != 0x10000) - driver_setup.ppr_mask = val; - break; - case TOKEN_VERBOSE: - qla1280_verbose = val; - break; - default: - printk(KERN_INFO "qla1280: unknown boot option %s\n", - cp); - } - - cp = strchr(ptr, ';'); - if (cp) - cp++; - else { - break; - } - } - return 1; -} - - -static int __init -qla1280_get_token(char *str) -{ - char *sep; - long ret = -1; - int i; - - sep = strchr(str, ':'); - - if (sep) { - for (i = 0; i < ARRAY_SIZE(setup_token); i++) { - if (!strncmp(setup_token[i].token, str, (sep - str))) { - ret = setup_token[i].val; - break; - } - } - } - - return ret; -} - - -static struct scsi_host_template qla1280_driver_template = { - .module = THIS_MODULE, - .proc_name = "qla1280", - .name = "Qlogic ISP 1280/12160", - .info = qla1280_info, - .slave_configure = qla1280_slave_configure, - .queuecommand = qla1280_queuecommand, - .eh_abort_handler = qla1280_eh_abort, - .eh_device_reset_handler= qla1280_eh_device_reset, - .eh_bus_reset_handler = qla1280_eh_bus_reset, - .eh_host_reset_handler = qla1280_eh_adapter_reset, - .bios_param = qla1280_biosparam, - .can_queue = 0xfffff, - .this_id = -1, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - - -static int __devinit -qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int devnum = id->driver_data; - struct qla_boards *bdp = &ql1280_board_tbl[devnum]; - struct Scsi_Host *host; - struct scsi_qla_host *ha; - int error = -ENODEV; - - /* Bypass all AMI SUBSYS VENDOR IDs */ - if (pdev->subsystem_vendor == PCI_VENDOR_ID_AMI) { - printk(KERN_INFO - "qla1280: Skipping AMI SubSys Vendor ID Chip\n"); - goto error; - } - - printk(KERN_INFO "qla1280: %s found on PCI bus %i, dev %i\n", - bdp->name, pdev->bus->number, PCI_SLOT(pdev->devfn)); - - if (pci_enable_device(pdev)) { - printk(KERN_WARNING - "qla1280: Failed to enabled pci device, aborting.\n"); - goto error; - } - - pci_set_master(pdev); - - error = -ENOMEM; - host = scsi_host_alloc(&qla1280_driver_template, sizeof(*ha)); - if (!host) { - printk(KERN_WARNING - "qla1280: Failed to register host, aborting.\n"); - goto error_disable_device; - } - - ha = (struct scsi_qla_host *)host->hostdata; - memset(ha, 0, sizeof(struct scsi_qla_host)); - - ha->pdev = pdev; - ha->devnum = devnum; /* specifies microcode load address */ - -#ifdef QLA_64BIT_PTR - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "scsi(%li): Unable to set a " - "suitable DMA mask - aborting\n", ha->host_no); - error = -ENODEV; - goto error_put_host; - } - } else - dprintk(2, "scsi(%li): 64 Bit PCI Addressing Enabled\n", - ha->host_no); -#else - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32))) { - printk(KERN_WARNING "scsi(%li): Unable to set a " - "suitable DMA mask - aborting\n", ha->host_no); - error = -ENODEV; - goto error_put_host; - } -#endif - - ha->request_ring = pci_alloc_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)), - &ha->request_dma); - if (!ha->request_ring) { - printk(KERN_INFO "qla1280: Failed to get request memory\n"); - goto error_put_host; - } - - ha->response_ring = pci_alloc_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)), - &ha->response_dma); - if (!ha->response_ring) { - printk(KERN_INFO "qla1280: Failed to get response memory\n"); - goto error_free_request_ring; - } - - ha->ports = bdp->numPorts; - - ha->host = host; - ha->host_no = host->host_no; - - host->irq = pdev->irq; - host->max_channel = bdp->numPorts - 1; - host->max_lun = MAX_LUNS - 1; - host->max_id = MAX_TARGETS; - host->max_sectors = 1024; - host->unique_id = host->host_no; - - error = -ENODEV; - -#if MEMORY_MAPPED_IO - ha->mmpbase = pci_ioremap_bar(ha->pdev, 1); - if (!ha->mmpbase) { - printk(KERN_INFO "qla1280: Unable to map I/O memory\n"); - goto error_free_response_ring; - } - - host->base = (unsigned long)ha->mmpbase; - ha->iobase = (struct device_reg __iomem *)ha->mmpbase; -#else - host->io_port = pci_resource_start(ha->pdev, 0); - if (!request_region(host->io_port, 0xff, "qla1280")) { - printk(KERN_INFO "qla1280: Failed to reserve i/o region " - "0x%04lx-0x%04lx - already in use\n", - host->io_port, host->io_port + 0xff); - goto error_free_response_ring; - } - - ha->iobase = (struct device_reg *)host->io_port; -#endif - - INIT_LIST_HEAD(&ha->done_q); - - /* Disable ISP interrupts. */ - qla1280_disable_intrs(ha); - - if (request_irq(pdev->irq, qla1280_intr_handler, IRQF_SHARED, - "qla1280", ha)) { - printk("qla1280 : Failed to reserve interrupt %d already " - "in use\n", pdev->irq); - goto error_release_region; - } - - /* load the F/W, read paramaters, and init the H/W */ - if (qla1280_initialize_adapter(ha)) { - printk(KERN_INFO "qla1x160: Failed to initialize adapter\n"); - goto error_free_irq; - } - - /* set our host ID (need to do something about our two IDs) */ - host->this_id = ha->bus_settings[0].id; - - pci_set_drvdata(pdev, host); - - error = scsi_add_host(host, &pdev->dev); - if (error) - goto error_disable_adapter; - scsi_scan_host(host); - - return 0; - - error_disable_adapter: - qla1280_disable_intrs(ha); - error_free_irq: - free_irq(pdev->irq, ha); - error_release_region: -#if MEMORY_MAPPED_IO - iounmap(ha->mmpbase); -#else - release_region(host->io_port, 0xff); -#endif - error_free_response_ring: - pci_free_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)), - ha->response_ring, ha->response_dma); - error_free_request_ring: - pci_free_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)), - ha->request_ring, ha->request_dma); - error_put_host: - scsi_host_put(host); - error_disable_device: - pci_disable_device(pdev); - error: - return error; -} - - -static void __devexit -qla1280_remove_one(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata; - - scsi_remove_host(host); - - qla1280_disable_intrs(ha); - - free_irq(pdev->irq, ha); - -#if MEMORY_MAPPED_IO - iounmap(ha->mmpbase); -#else - release_region(host->io_port, 0xff); -#endif - - pci_free_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), - ha->request_ring, ha->request_dma); - pci_free_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), - ha->response_ring, ha->response_dma); - - pci_disable_device(pdev); - - scsi_host_put(host); -} - -static struct pci_driver qla1280_pci_driver = { - .name = "qla1280", - .id_table = qla1280_pci_tbl, - .probe = qla1280_probe_one, - .remove = __devexit_p(qla1280_remove_one), -}; - -static int __init -qla1280_init(void) -{ - if (sizeof(struct srb) > sizeof(struct scsi_pointer)) { - printk(KERN_WARNING - "qla1280: struct srb too big, aborting\n"); - return -EINVAL; - } - -#ifdef MODULE - /* - * If we are called as a module, the qla1280 pointer may not be null - * and it would point to our bootup string, just like on the lilo - * command line. IF not NULL, then process this config string with - * qla1280_setup - * - * Boot time Options - * To add options at boot time add a line to your lilo.conf file like: - * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}" - * which will result in the first four devices on the first two - * controllers being set to a tagged queue depth of 32. - */ - if (qla1280) - qla1280_setup(qla1280); -#endif - - return pci_register_driver(&qla1280_pci_driver); -} - -static void __exit -qla1280_exit(void) -{ - int i; - - pci_unregister_driver(&qla1280_pci_driver); - /* release any allocated firmware images */ - for (i = 0; i < QL_NUM_FW_IMAGES; i++) { - if (qla1280_fw_tbl[i].fw) { - release_firmware(qla1280_fw_tbl[i].fw); - qla1280_fw_tbl[i].fw = NULL; - } - } -} - -module_init(qla1280_init); -module_exit(qla1280_exit); - - -MODULE_AUTHOR("Qlogic & Jes Sorensen"); -MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE("qlogic/1040.bin"); -MODULE_FIRMWARE("qlogic/1280.bin"); -MODULE_FIRMWARE("qlogic/12160.bin"); -MODULE_VERSION(QLA1280_VERSION); - -/* - * Overrides for Emacs so that we almost follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla1280.h b/ANDROID_3.4.5/drivers/scsi/qla1280.h deleted file mode 100644 index 834884b9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla1280.h +++ /dev/null @@ -1,1081 +0,0 @@ -/****************************************************************************** -* QLOGIC LINUX SOFTWARE -* -* QLogic ISP1280 (Ultra2) /12160 (Ultra3) SCSI driver -* Copyright (C) 2000 Qlogic Corporation -* (www.qlogic.com) -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2, or (at your option) any -* later version. -* -* This program is distributed in the hope that it will be useful, but -* WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -* General Public License for more details. -* -******************************************************************************/ - -#ifndef _QLA1280_H -#define _QLA1280_H - -/* - * Data bit definitions. - */ -#define BIT_0 0x1 -#define BIT_1 0x2 -#define BIT_2 0x4 -#define BIT_3 0x8 -#define BIT_4 0x10 -#define BIT_5 0x20 -#define BIT_6 0x40 -#define BIT_7 0x80 -#define BIT_8 0x100 -#define BIT_9 0x200 -#define BIT_10 0x400 -#define BIT_11 0x800 -#define BIT_12 0x1000 -#define BIT_13 0x2000 -#define BIT_14 0x4000 -#define BIT_15 0x8000 -#define BIT_16 0x10000 -#define BIT_17 0x20000 -#define BIT_18 0x40000 -#define BIT_19 0x80000 -#define BIT_20 0x100000 -#define BIT_21 0x200000 -#define BIT_22 0x400000 -#define BIT_23 0x800000 -#define BIT_24 0x1000000 -#define BIT_25 0x2000000 -#define BIT_26 0x4000000 -#define BIT_27 0x8000000 -#define BIT_28 0x10000000 -#define BIT_29 0x20000000 -#define BIT_30 0x40000000 -#define BIT_31 0x80000000 - -#if MEMORY_MAPPED_IO -#define RD_REG_WORD(addr) readw_relaxed(addr) -#define RD_REG_WORD_dmasync(addr) readw(addr) -#define WRT_REG_WORD(addr, data) writew(data, addr) -#else /* MEMORY_MAPPED_IO */ -#define RD_REG_WORD(addr) inw((unsigned long)addr) -#define RD_REG_WORD_dmasync(addr) RD_REG_WORD(addr) -#define WRT_REG_WORD(addr, data) outw(data, (unsigned long)addr) -#endif /* MEMORY_MAPPED_IO */ - -/* - * Host adapter default definitions. - */ -#define MAX_BUSES 2 /* 2 */ -#define MAX_B_BITS 1 - -#define MAX_TARGETS 16 /* 16 */ -#define MAX_T_BITS 4 /* 4 */ - -#define MAX_LUNS 8 /* 32 */ -#define MAX_L_BITS 3 /* 5 */ - -/* - * Watchdog time quantum - */ -#define QLA1280_WDG_TIME_QUANTUM 5 /* In seconds */ - -/* Command retry count (0-65535) */ -#define COMMAND_RETRY_COUNT 255 - -/* Maximum outstanding commands in ISP queues */ -#define MAX_OUTSTANDING_COMMANDS 512 -#define COMPLETED_HANDLE ((unsigned char *) \ - (MAX_OUTSTANDING_COMMANDS + 2)) - -/* ISP request and response entry counts (37-65535) */ -#define REQUEST_ENTRY_CNT 255 /* Number of request entries. */ -#define RESPONSE_ENTRY_CNT 63 /* Number of response entries. */ - -/* - * SCSI Request Block structure (sp) that is placed - * on cmd->SCp location of every I/O - */ -struct srb { - struct list_head list; /* (8/16) LU queue */ - struct scsi_cmnd *cmd; /* (4/8) SCSI command block */ - /* NOTE: the sp->cmd will be NULL when this completion is - * called, so you should know the scsi_cmnd when using this */ - struct completion *wait; - dma_addr_t saved_dma_handle; /* for unmap of single transfers */ - uint8_t flags; /* (1) Status flags. */ - uint8_t dir; /* direction of transfer */ -}; - -/* - * SRB flag definitions - */ -#define SRB_TIMEOUT (1 << 0) /* Command timed out */ -#define SRB_SENT (1 << 1) /* Command sent to ISP */ -#define SRB_ABORT_PENDING (1 << 2) /* Command abort sent to device */ -#define SRB_ABORTED (1 << 3) /* Command aborted command already */ - -/* - * ISP I/O Register Set structure definitions. - */ -struct device_reg { - uint16_t id_l; /* ID low */ - uint16_t id_h; /* ID high */ - uint16_t cfg_0; /* Configuration 0 */ -#define ISP_CFG0_HWMSK 0x000f /* Hardware revision mask */ -#define ISP_CFG0_1020 BIT_0 /* ISP1020 */ -#define ISP_CFG0_1020A BIT_1 /* ISP1020A */ -#define ISP_CFG0_1040 BIT_2 /* ISP1040 */ -#define ISP_CFG0_1040A BIT_3 /* ISP1040A */ -#define ISP_CFG0_1040B BIT_4 /* ISP1040B */ -#define ISP_CFG0_1040C BIT_5 /* ISP1040C */ - uint16_t cfg_1; /* Configuration 1 */ -#define ISP_CFG1_F128 BIT_6 /* 128-byte FIFO threshold */ -#define ISP_CFG1_F64 BIT_4|BIT_5 /* 128-byte FIFO threshold */ -#define ISP_CFG1_F32 BIT_5 /* 128-byte FIFO threshold */ -#define ISP_CFG1_F16 BIT_4 /* 128-byte FIFO threshold */ -#define ISP_CFG1_BENAB BIT_2 /* Global Bus burst enable */ -#define ISP_CFG1_SXP BIT_0 /* SXP register select */ - uint16_t ictrl; /* Interface control */ -#define ISP_RESET BIT_0 /* ISP soft reset */ -#define ISP_EN_INT BIT_1 /* ISP enable interrupts. */ -#define ISP_EN_RISC BIT_2 /* ISP enable RISC interrupts. */ -#define ISP_FLASH_ENABLE BIT_8 /* Flash BIOS Read/Write enable */ -#define ISP_FLASH_UPPER BIT_9 /* Flash upper bank select */ - uint16_t istatus; /* Interface status */ -#define PCI_64BIT_SLOT BIT_14 /* PCI 64-bit slot indicator. */ -#define RISC_INT BIT_2 /* RISC interrupt */ -#define PCI_INT BIT_1 /* PCI interrupt */ - uint16_t semaphore; /* Semaphore */ - uint16_t nvram; /* NVRAM register. */ -#define NV_DESELECT 0 -#define NV_CLOCK BIT_0 -#define NV_SELECT BIT_1 -#define NV_DATA_OUT BIT_2 -#define NV_DATA_IN BIT_3 - uint16_t flash_data; /* Flash BIOS data */ - uint16_t flash_address; /* Flash BIOS address */ - - uint16_t unused_1[0x06]; - - /* cdma_* and ddma_* are 1040 only */ - uint16_t cdma_cfg; -#define CDMA_CONF_SENAB BIT_3 /* SXP to DMA Data enable */ -#define CDMA_CONF_RIRQ BIT_2 /* RISC interrupt enable */ -#define CDMA_CONF_BENAB BIT_1 /* Bus burst enable */ -#define CDMA_CONF_DIR BIT_0 /* DMA direction (0=fifo->host 1=host->fifo) */ - uint16_t cdma_ctrl; - uint16_t cdma_status; - uint16_t cdma_fifo_status; - uint16_t cdma_count; - uint16_t cdma_reserved; - uint16_t cdma_address_count_0; - uint16_t cdma_address_count_1; - uint16_t cdma_address_count_2; - uint16_t cdma_address_count_3; - - uint16_t unused_2[0x06]; - - uint16_t ddma_cfg; -#define DDMA_CONF_SENAB BIT_3 /* SXP to DMA Data enable */ -#define DDMA_CONF_RIRQ BIT_2 /* RISC interrupt enable */ -#define DDMA_CONF_BENAB BIT_1 /* Bus burst enable */ -#define DDMA_CONF_DIR BIT_0 /* DMA direction (0=fifo->host 1=host->fifo) */ - uint16_t ddma_ctrl; - uint16_t ddma_status; - uint16_t ddma_fifo_status; - uint16_t ddma_xfer_count_low; - uint16_t ddma_xfer_count_high; - uint16_t ddma_addr_count_0; - uint16_t ddma_addr_count_1; - uint16_t ddma_addr_count_2; - uint16_t ddma_addr_count_3; - - uint16_t unused_3[0x0e]; - - uint16_t mailbox0; /* Mailbox 0 */ - uint16_t mailbox1; /* Mailbox 1 */ - uint16_t mailbox2; /* Mailbox 2 */ - uint16_t mailbox3; /* Mailbox 3 */ - uint16_t mailbox4; /* Mailbox 4 */ - uint16_t mailbox5; /* Mailbox 5 */ - uint16_t mailbox6; /* Mailbox 6 */ - uint16_t mailbox7; /* Mailbox 7 */ - - uint16_t unused_4[0x20];/* 0x80-0xbf Gap */ - - uint16_t host_cmd; /* Host command and control */ -#define HOST_INT BIT_7 /* host interrupt bit */ -#define BIOS_ENABLE BIT_0 - - uint16_t unused_5[0x5]; /* 0xc2-0xcb Gap */ - - uint16_t gpio_data; - uint16_t gpio_enable; - - uint16_t unused_6[0x11]; /* d0-f0 */ - uint16_t scsiControlPins; /* f2 */ -}; - -#define MAILBOX_REGISTER_COUNT 8 - -/* - * ISP product identification definitions in mailboxes after reset. - */ -#define PROD_ID_1 0x4953 -#define PROD_ID_2 0x0000 -#define PROD_ID_2a 0x5020 -#define PROD_ID_3 0x2020 -#define PROD_ID_4 0x1 - -/* - * ISP host command and control register command definitions - */ -#define HC_RESET_RISC 0x1000 /* Reset RISC */ -#define HC_PAUSE_RISC 0x2000 /* Pause RISC */ -#define HC_RELEASE_RISC 0x3000 /* Release RISC from reset. */ -#define HC_SET_HOST_INT 0x5000 /* Set host interrupt */ -#define HC_CLR_HOST_INT 0x6000 /* Clear HOST interrupt */ -#define HC_CLR_RISC_INT 0x7000 /* Clear RISC interrupt */ -#define HC_DISABLE_BIOS 0x9000 /* Disable BIOS. */ - -/* - * ISP mailbox Self-Test status codes - */ -#define MBS_FRM_ALIVE 0 /* Firmware Alive. */ -#define MBS_CHKSUM_ERR 1 /* Checksum Error. */ -#define MBS_SHADOW_LD_ERR 2 /* Shadow Load Error. */ -#define MBS_BUSY 4 /* Busy. */ - -/* - * ISP mailbox command complete status codes - */ -#define MBS_CMD_CMP 0x4000 /* Command Complete. */ -#define MBS_INV_CMD 0x4001 /* Invalid Command. */ -#define MBS_HOST_INF_ERR 0x4002 /* Host Interface Error. */ -#define MBS_TEST_FAILED 0x4003 /* Test Failed. */ -#define MBS_CMD_ERR 0x4005 /* Command Error. */ -#define MBS_CMD_PARAM_ERR 0x4006 /* Command Parameter Error. */ - -/* - * ISP mailbox asynchronous event status codes - */ -#define MBA_ASYNC_EVENT 0x8000 /* Asynchronous event. */ -#define MBA_BUS_RESET 0x8001 /* SCSI Bus Reset. */ -#define MBA_SYSTEM_ERR 0x8002 /* System Error. */ -#define MBA_REQ_TRANSFER_ERR 0x8003 /* Request Transfer Error. */ -#define MBA_RSP_TRANSFER_ERR 0x8004 /* Response Transfer Error. */ -#define MBA_WAKEUP_THRES 0x8005 /* Request Queue Wake-up. */ -#define MBA_TIMEOUT_RESET 0x8006 /* Execution Timeout Reset. */ -#define MBA_DEVICE_RESET 0x8007 /* Bus Device Reset. */ -#define MBA_BUS_MODE_CHANGE 0x800E /* SCSI bus mode transition. */ -#define MBA_SCSI_COMPLETION 0x8020 /* Completion response. */ - -/* - * ISP mailbox commands - */ -#define MBC_NOP 0 /* No Operation */ -#define MBC_LOAD_RAM 1 /* Load RAM */ -#define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware */ -#define MBC_DUMP_RAM 3 /* Dump RAM contents */ -#define MBC_WRITE_RAM_WORD 4 /* Write ram word */ -#define MBC_READ_RAM_WORD 5 /* Read ram word */ -#define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ -#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum */ -#define MBC_ABOUT_FIRMWARE 8 /* Get firmware revision */ -#define MBC_INIT_REQUEST_QUEUE 0x10 /* Initialize request queue */ -#define MBC_INIT_RESPONSE_QUEUE 0x11 /* Initialize response queue */ -#define MBC_EXECUTE_IOCB 0x12 /* Execute IOCB command */ -#define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command */ -#define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN) */ -#define MBC_ABORT_TARGET 0x17 /* Abort target (ID) */ -#define MBC_BUS_RESET 0x18 /* SCSI bus reset */ -#define MBC_GET_RETRY_COUNT 0x22 /* Get retry count and delay */ -#define MBC_GET_TARGET_PARAMETERS 0x28 /* Get target parameters */ -#define MBC_SET_INITIATOR_ID 0x30 /* Set initiator SCSI ID */ -#define MBC_SET_SELECTION_TIMEOUT 0x31 /* Set selection timeout */ -#define MBC_SET_RETRY_COUNT 0x32 /* Set retry count and delay */ -#define MBC_SET_TAG_AGE_LIMIT 0x33 /* Set tag age limit */ -#define MBC_SET_CLOCK_RATE 0x34 /* Set clock rate */ -#define MBC_SET_ACTIVE_NEGATION 0x35 /* Set active negation state */ -#define MBC_SET_ASYNC_DATA_SETUP 0x36 /* Set async data setup time */ -#define MBC_SET_PCI_CONTROL 0x37 /* Set BUS control parameters */ -#define MBC_SET_TARGET_PARAMETERS 0x38 /* Set target parameters */ -#define MBC_SET_DEVICE_QUEUE 0x39 /* Set device queue parameters */ -#define MBC_SET_RESET_DELAY_PARAMETERS 0x3A /* Set reset delay parameters */ -#define MBC_SET_SYSTEM_PARAMETER 0x45 /* Set system parameter word */ -#define MBC_SET_FIRMWARE_FEATURES 0x4A /* Set firmware feature word */ -#define MBC_INIT_REQUEST_QUEUE_A64 0x52 /* Initialize request queue A64 */ -#define MBC_INIT_RESPONSE_QUEUE_A64 0x53 /* Initialize response q A64 */ -#define MBC_ENABLE_TARGET_MODE 0x55 /* Enable target mode */ -#define MBC_SET_DATA_OVERRUN_RECOVERY 0x5A /* Set data overrun recovery mode */ - -/* - * ISP Get/Set Target Parameters mailbox command control flags. - */ -#define TP_PPR BIT_5 /* PPR */ -#define TP_RENEGOTIATE BIT_8 /* Renegotiate on error. */ -#define TP_STOP_QUEUE BIT_9 /* Stop que on check condition */ -#define TP_AUTO_REQUEST_SENSE BIT_10 /* Automatic request sense. */ -#define TP_TAGGED_QUEUE BIT_11 /* Tagged queuing. */ -#define TP_SYNC BIT_12 /* Synchronous data transfers. */ -#define TP_WIDE BIT_13 /* Wide data transfers. */ -#define TP_PARITY BIT_14 /* Parity checking. */ -#define TP_DISCONNECT BIT_15 /* Disconnect privilege. */ - -/* - * NVRAM Command values. - */ -#define NV_START_BIT BIT_2 -#define NV_WRITE_OP (BIT_26 | BIT_24) -#define NV_READ_OP (BIT_26 | BIT_25) -#define NV_ERASE_OP (BIT_26 | BIT_25 | BIT_24) -#define NV_MASK_OP (BIT_26 | BIT_25 | BIT_24) -#define NV_DELAY_COUNT 10 - -/* - * QLogic ISP1280/ISP12160 NVRAM structure definition. - */ -struct nvram { - uint8_t id0; /* 0 */ - uint8_t id1; /* 1 */ - uint8_t id2; /* 2 */ - uint8_t id3; /* 3 */ - uint8_t version; /* 4 */ - - struct { - uint8_t bios_configuration_mode:2; - uint8_t bios_disable:1; - uint8_t selectable_scsi_boot_enable:1; - uint8_t cd_rom_boot_enable:1; - uint8_t disable_loading_risc_code:1; - uint8_t enable_64bit_addressing:1; - uint8_t unused_7:1; - } cntr_flags_1; /* 5 */ - - struct { - uint8_t boot_lun_number:5; - uint8_t scsi_bus_number:1; - uint8_t unused_6:1; - uint8_t unused_7:1; - } cntr_flags_2l; /* 7 */ - - struct { - uint8_t boot_target_number:4; - uint8_t unused_12:1; - uint8_t unused_13:1; - uint8_t unused_14:1; - uint8_t unused_15:1; - } cntr_flags_2h; /* 8 */ - - uint16_t unused_8; /* 8, 9 */ - uint16_t unused_10; /* 10, 11 */ - uint16_t unused_12; /* 12, 13 */ - uint16_t unused_14; /* 14, 15 */ - - struct { - uint8_t reserved:2; - uint8_t burst_enable:1; - uint8_t reserved_1:1; - uint8_t fifo_threshold:4; - } isp_config; /* 16 */ - - /* Termination - * 0 = Disable, 1 = high only, 3 = Auto term - */ - struct { - uint8_t scsi_bus_1_control:2; - uint8_t scsi_bus_0_control:2; - uint8_t unused_0:1; - uint8_t unused_1:1; - uint8_t unused_2:1; - uint8_t auto_term_support:1; - } termination; /* 17 */ - - uint16_t isp_parameter; /* 18, 19 */ - - union { - uint16_t w; - struct { - uint16_t enable_fast_posting:1; - uint16_t report_lvd_bus_transition:1; - uint16_t unused_2:1; - uint16_t unused_3:1; - uint16_t disable_iosbs_with_bus_reset_status:1; - uint16_t disable_synchronous_backoff:1; - uint16_t unused_6:1; - uint16_t synchronous_backoff_reporting:1; - uint16_t disable_reselection_fairness:1; - uint16_t unused_9:1; - uint16_t unused_10:1; - uint16_t unused_11:1; - uint16_t unused_12:1; - uint16_t unused_13:1; - uint16_t unused_14:1; - uint16_t unused_15:1; - } f; - } firmware_feature; /* 20, 21 */ - - uint16_t unused_22; /* 22, 23 */ - - struct { - struct { - uint8_t initiator_id:4; - uint8_t scsi_reset_disable:1; - uint8_t scsi_bus_size:1; - uint8_t scsi_bus_type:1; - uint8_t unused_7:1; - } config_1; /* 24 */ - - uint8_t bus_reset_delay; /* 25 */ - uint8_t retry_count; /* 26 */ - uint8_t retry_delay; /* 27 */ - - struct { - uint8_t async_data_setup_time:4; - uint8_t req_ack_active_negation:1; - uint8_t data_line_active_negation:1; - uint8_t unused_6:1; - uint8_t unused_7:1; - } config_2; /* 28 */ - - uint8_t unused_29; /* 29 */ - - uint16_t selection_timeout; /* 30, 31 */ - uint16_t max_queue_depth; /* 32, 33 */ - - uint16_t unused_34; /* 34, 35 */ - uint16_t unused_36; /* 36, 37 */ - uint16_t unused_38; /* 38, 39 */ - - struct { - struct { - uint8_t renegotiate_on_error:1; - uint8_t stop_queue_on_check:1; - uint8_t auto_request_sense:1; - uint8_t tag_queuing:1; - uint8_t enable_sync:1; - uint8_t enable_wide:1; - uint8_t parity_checking:1; - uint8_t disconnect_allowed:1; - } parameter; /* 40 */ - - uint8_t execution_throttle; /* 41 */ - uint8_t sync_period; /* 42 */ - - union { /* 43 */ - uint8_t flags_43; - struct { - uint8_t sync_offset:4; - uint8_t device_enable:1; - uint8_t lun_disable:1; - uint8_t unused_6:1; - uint8_t unused_7:1; - } flags1x80; - struct { - uint8_t sync_offset:5; - uint8_t device_enable:1; - uint8_t unused_6:1; - uint8_t unused_7:1; - } flags1x160; - } flags; - union { /* PPR flags for the 1x160 controllers */ - uint8_t unused_44; - struct { - uint8_t ppr_options:4; - uint8_t ppr_bus_width:2; - uint8_t unused_8:1; - uint8_t enable_ppr:1; - } flags; /* 44 */ - } ppr_1x160; - uint8_t unused_45; /* 45 */ - } target[MAX_TARGETS]; - } bus[MAX_BUSES]; - - uint16_t unused_248; /* 248, 249 */ - - uint16_t subsystem_id[2]; /* 250, 251, 252, 253 */ - - union { /* 254 */ - uint8_t unused_254; - uint8_t system_id_pointer; - } sysid_1x160; - - uint8_t chksum; /* 255 */ -}; - -/* - * ISP queue - command entry structure definition. - */ -#define MAX_CMDSZ 12 /* SCSI maximum CDB size. */ -struct cmd_entry { - uint8_t entry_type; /* Entry type. */ -#define COMMAND_TYPE 1 /* Command entry */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - __le32 handle; /* System handle. */ - uint8_t lun; /* SCSI LUN */ - uint8_t target; /* SCSI ID */ - __le16 cdb_len; /* SCSI command length. */ - __le16 control_flags; /* Control flags. */ - __le16 reserved; - __le16 timeout; /* Command timeout. */ - __le16 dseg_count; /* Data segment count. */ - uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ - __le32 dseg_0_address; /* Data segment 0 address. */ - __le32 dseg_0_length; /* Data segment 0 length. */ - __le32 dseg_1_address; /* Data segment 1 address. */ - __le32 dseg_1_length; /* Data segment 1 length. */ - __le32 dseg_2_address; /* Data segment 2 address. */ - __le32 dseg_2_length; /* Data segment 2 length. */ - __le32 dseg_3_address; /* Data segment 3 address. */ - __le32 dseg_3_length; /* Data segment 3 length. */ -}; - -/* - * ISP queue - continuation entry structure definition. - */ -struct cont_entry { - uint8_t entry_type; /* Entry type. */ -#define CONTINUE_TYPE 2 /* Continuation entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - __le32 reserved; /* Reserved */ - __le32 dseg_0_address; /* Data segment 0 address. */ - __le32 dseg_0_length; /* Data segment 0 length. */ - __le32 dseg_1_address; /* Data segment 1 address. */ - __le32 dseg_1_length; /* Data segment 1 length. */ - __le32 dseg_2_address; /* Data segment 2 address. */ - __le32 dseg_2_length; /* Data segment 2 length. */ - __le32 dseg_3_address; /* Data segment 3 address. */ - __le32 dseg_3_length; /* Data segment 3 length. */ - __le32 dseg_4_address; /* Data segment 4 address. */ - __le32 dseg_4_length; /* Data segment 4 length. */ - __le32 dseg_5_address; /* Data segment 5 address. */ - __le32 dseg_5_length; /* Data segment 5 length. */ - __le32 dseg_6_address; /* Data segment 6 address. */ - __le32 dseg_6_length; /* Data segment 6 length. */ -}; - -/* - * ISP queue - status entry structure definition. - */ -struct response { - uint8_t entry_type; /* Entry type. */ -#define STATUS_TYPE 3 /* Status entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ -#define RF_CONT BIT_0 /* Continuation. */ -#define RF_FULL BIT_1 /* Full */ -#define RF_BAD_HEADER BIT_2 /* Bad header. */ -#define RF_BAD_PAYLOAD BIT_3 /* Bad payload. */ - __le32 handle; /* System handle. */ - __le16 scsi_status; /* SCSI status. */ - __le16 comp_status; /* Completion status. */ - __le16 state_flags; /* State flags. */ -#define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */ -#define SF_GOT_SENSE BIT_13 /* Got Sense */ -#define SF_GOT_STATUS BIT_12 /* Got Status */ -#define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */ -#define SF_SENT_CDB BIT_10 /* Send CDB */ -#define SF_GOT_TARGET BIT_9 /* */ -#define SF_GOT_BUS BIT_8 /* */ - __le16 status_flags; /* Status flags. */ - __le16 time; /* Time. */ - __le16 req_sense_length;/* Request sense data length. */ - __le32 residual_length; /* Residual transfer length. */ - __le16 reserved[4]; - uint8_t req_sense_data[32]; /* Request sense data. */ -}; - -/* - * ISP queue - marker entry structure definition. - */ -struct mrk_entry { - uint8_t entry_type; /* Entry type. */ -#define MARKER_TYPE 4 /* Marker entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - __le32 reserved; - uint8_t lun; /* SCSI LUN */ - uint8_t target; /* SCSI ID */ - uint8_t modifier; /* Modifier (7-0). */ -#define MK_SYNC_ID_LUN 0 /* Synchronize ID/LUN */ -#define MK_SYNC_ID 1 /* Synchronize ID */ -#define MK_SYNC_ALL 2 /* Synchronize all ID/LUN */ - uint8_t reserved_1[53]; -}; - -/* - * ISP queue - extended command entry structure definition. - * - * Unused by the driver! - */ -struct ecmd_entry { - uint8_t entry_type; /* Entry type. */ -#define EXTENDED_CMD_TYPE 5 /* Extended command entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System handle. */ - uint8_t lun; /* SCSI LUN */ - uint8_t target; /* SCSI ID */ - __le16 cdb_len; /* SCSI command length. */ - __le16 control_flags; /* Control flags. */ - __le16 reserved; - __le16 timeout; /* Command timeout. */ - __le16 dseg_count; /* Data segment count. */ - uint8_t scsi_cdb[88]; /* SCSI command words. */ -}; - -/* - * ISP queue - 64-Bit addressing, command entry structure definition. - */ -typedef struct { - uint8_t entry_type; /* Entry type. */ -#define COMMAND_A64_TYPE 9 /* Command A64 entry */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - __le32 handle; /* System handle. */ - uint8_t lun; /* SCSI LUN */ - uint8_t target; /* SCSI ID */ - __le16 cdb_len; /* SCSI command length. */ - __le16 control_flags; /* Control flags. */ - __le16 reserved; - __le16 timeout; /* Command timeout. */ - __le16 dseg_count; /* Data segment count. */ - uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ - __le32 reserved_1[2]; /* unused */ - __le32 dseg_0_address[2]; /* Data segment 0 address. */ - __le32 dseg_0_length; /* Data segment 0 length. */ - __le32 dseg_1_address[2]; /* Data segment 1 address. */ - __le32 dseg_1_length; /* Data segment 1 length. */ -} cmd_a64_entry_t, request_t; - -/* - * ISP queue - 64-Bit addressing, continuation entry structure definition. - */ -struct cont_a64_entry { - uint8_t entry_type; /* Entry type. */ -#define CONTINUE_A64_TYPE 0xA /* Continuation A64 entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - __le32 dseg_0_address[2]; /* Data segment 0 address. */ - __le32 dseg_0_length; /* Data segment 0 length. */ - __le32 dseg_1_address[2]; /* Data segment 1 address. */ - __le32 dseg_1_length; /* Data segment 1 length. */ - __le32 dseg_2_address[2]; /* Data segment 2 address. */ - __le32 dseg_2_length; /* Data segment 2 length. */ - __le32 dseg_3_address[2]; /* Data segment 3 address. */ - __le32 dseg_3_length; /* Data segment 3 length. */ - __le32 dseg_4_address[2]; /* Data segment 4 address. */ - __le32 dseg_4_length; /* Data segment 4 length. */ -}; - -/* - * ISP queue - enable LUN entry structure definition. - */ -struct elun_entry { - uint8_t entry_type; /* Entry type. */ -#define ENABLE_LUN_TYPE 0xB /* Enable LUN entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status not used. */ - __le32 reserved_2; - __le16 lun; /* Bit 15 is bus number. */ - __le16 reserved_4; - __le32 option_flags; - uint8_t status; - uint8_t reserved_5; - uint8_t command_count; /* Number of ATIOs allocated. */ - uint8_t immed_notify_count; /* Number of Immediate Notify */ - /* entries allocated. */ - uint8_t group_6_length; /* SCSI CDB length for group 6 */ - /* commands (2-26). */ - uint8_t group_7_length; /* SCSI CDB length for group 7 */ - /* commands (2-26). */ - __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - __le16 reserved_6[20]; -}; - -/* - * ISP queue - modify LUN entry structure definition. - * - * Unused by the driver! - */ -struct modify_lun_entry { - uint8_t entry_type; /* Entry type. */ -#define MODIFY_LUN_TYPE 0xC /* Modify LUN entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status. */ - __le32 reserved_2; - uint8_t lun; /* SCSI LUN */ - uint8_t reserved_3; - uint8_t operators; - uint8_t reserved_4; - __le32 option_flags; - uint8_t status; - uint8_t reserved_5; - uint8_t command_count; /* Number of ATIOs allocated. */ - uint8_t immed_notify_count; /* Number of Immediate Notify */ - /* entries allocated. */ - __le16 reserved_6; - __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - __le16 reserved_7[20]; -}; - -/* - * ISP queue - immediate notify entry structure definition. - */ -struct notify_entry { - uint8_t entry_type; /* Entry type. */ -#define IMMED_NOTIFY_TYPE 0xD /* Immediate notify entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status. */ - __le32 reserved_2; - uint8_t lun; - uint8_t initiator_id; - uint8_t reserved_3; - uint8_t target_id; - __le32 option_flags; - uint8_t status; - uint8_t reserved_4; - uint8_t tag_value; /* Received queue tag message value */ - uint8_t tag_type; /* Received queue tag message type */ - /* entries allocated. */ - __le16 seq_id; - uint8_t scsi_msg[8]; /* SCSI message not handled by ISP */ - __le16 reserved_5[8]; - uint8_t sense_data[18]; -}; - -/* - * ISP queue - notify acknowledge entry structure definition. - */ -struct nack_entry { - uint8_t entry_type; /* Entry type. */ -#define NOTIFY_ACK_TYPE 0xE /* Notify acknowledge entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status. */ - __le32 reserved_2; - uint8_t lun; - uint8_t initiator_id; - uint8_t reserved_3; - uint8_t target_id; - __le32 option_flags; - uint8_t status; - uint8_t event; - __le16 seq_id; - __le16 reserved_4[22]; -}; - -/* - * ISP queue - Accept Target I/O (ATIO) entry structure definition. - */ -struct atio_entry { - uint8_t entry_type; /* Entry type. */ -#define ACCEPT_TGT_IO_TYPE 6 /* Accept target I/O entry. */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status. */ - __le32 reserved_2; - uint8_t lun; - uint8_t initiator_id; - uint8_t cdb_len; - uint8_t target_id; - __le32 option_flags; - uint8_t status; - uint8_t scsi_status; - uint8_t tag_value; /* Received queue tag message value */ - uint8_t tag_type; /* Received queue tag message type */ - uint8_t cdb[26]; - uint8_t sense_data[18]; -}; - -/* - * ISP queue - Continue Target I/O (CTIO) entry structure definition. - */ -struct ctio_entry { - uint8_t entry_type; /* Entry type. */ -#define CONTINUE_TGT_IO_TYPE 7 /* CTIO entry */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status. */ - __le32 reserved_2; - uint8_t lun; /* SCSI LUN */ - uint8_t initiator_id; - uint8_t reserved_3; - uint8_t target_id; - __le32 option_flags; - uint8_t status; - uint8_t scsi_status; - uint8_t tag_value; /* Received queue tag message value */ - uint8_t tag_type; /* Received queue tag message type */ - __le32 transfer_length; - __le32 residual; - __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - __le16 dseg_count; /* Data segment count. */ - __le32 dseg_0_address; /* Data segment 0 address. */ - __le32 dseg_0_length; /* Data segment 0 length. */ - __le32 dseg_1_address; /* Data segment 1 address. */ - __le32 dseg_1_length; /* Data segment 1 length. */ - __le32 dseg_2_address; /* Data segment 2 address. */ - __le32 dseg_2_length; /* Data segment 2 length. */ - __le32 dseg_3_address; /* Data segment 3 address. */ - __le32 dseg_3_length; /* Data segment 3 length. */ -}; - -/* - * ISP queue - CTIO returned entry structure definition. - */ -struct ctio_ret_entry { - uint8_t entry_type; /* Entry type. */ -#define CTIO_RET_TYPE 7 /* CTIO return entry */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status. */ - __le32 reserved_2; - uint8_t lun; /* SCSI LUN */ - uint8_t initiator_id; - uint8_t reserved_3; - uint8_t target_id; - __le32 option_flags; - uint8_t status; - uint8_t scsi_status; - uint8_t tag_value; /* Received queue tag message value */ - uint8_t tag_type; /* Received queue tag message type */ - __le32 transfer_length; - __le32 residual; - __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - __le16 dseg_count; /* Data segment count. */ - __le32 dseg_0_address; /* Data segment 0 address. */ - __le32 dseg_0_length; /* Data segment 0 length. */ - __le32 dseg_1_address; /* Data segment 1 address. */ - __le16 dseg_1_length; /* Data segment 1 length. */ - uint8_t sense_data[18]; -}; - -/* - * ISP queue - CTIO A64 entry structure definition. - */ -struct ctio_a64_entry { - uint8_t entry_type; /* Entry type. */ -#define CTIO_A64_TYPE 0xF /* CTIO A64 entry */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status. */ - __le32 reserved_2; - uint8_t lun; /* SCSI LUN */ - uint8_t initiator_id; - uint8_t reserved_3; - uint8_t target_id; - __le32 option_flags; - uint8_t status; - uint8_t scsi_status; - uint8_t tag_value; /* Received queue tag message value */ - uint8_t tag_type; /* Received queue tag message type */ - __le32 transfer_length; - __le32 residual; - __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - __le16 dseg_count; /* Data segment count. */ - __le32 reserved_4[2]; - __le32 dseg_0_address[2];/* Data segment 0 address. */ - __le32 dseg_0_length; /* Data segment 0 length. */ - __le32 dseg_1_address[2];/* Data segment 1 address. */ - __le32 dseg_1_length; /* Data segment 1 length. */ -}; - -/* - * ISP queue - CTIO returned entry structure definition. - */ -struct ctio_a64_ret_entry { - uint8_t entry_type; /* Entry type. */ -#define CTIO_A64_RET_TYPE 0xF /* CTIO A64 returned entry */ - uint8_t entry_count; /* Entry count. */ - uint8_t reserved_1; - uint8_t entry_status; /* Entry Status. */ - __le32 reserved_2; - uint8_t lun; /* SCSI LUN */ - uint8_t initiator_id; - uint8_t reserved_3; - uint8_t target_id; - __le32 option_flags; - uint8_t status; - uint8_t scsi_status; - uint8_t tag_value; /* Received queue tag message value */ - uint8_t tag_type; /* Received queue tag message type */ - __le32 transfer_length; - __le32 residual; - __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - __le16 dseg_count; /* Data segment count. */ - __le16 reserved_4[7]; - uint8_t sense_data[18]; -}; - -/* - * ISP request and response queue entry sizes - */ -#define RESPONSE_ENTRY_SIZE (sizeof(struct response)) -#define REQUEST_ENTRY_SIZE (sizeof(request_t)) - -/* - * ISP status entry - completion status definitions. - */ -#define CS_COMPLETE 0x0 /* No errors */ -#define CS_INCOMPLETE 0x1 /* Incomplete transfer of cmd. */ -#define CS_DMA 0x2 /* A DMA direction error. */ -#define CS_TRANSPORT 0x3 /* Transport error. */ -#define CS_RESET 0x4 /* SCSI bus reset occurred */ -#define CS_ABORTED 0x5 /* System aborted command. */ -#define CS_TIMEOUT 0x6 /* Timeout error. */ -#define CS_DATA_OVERRUN 0x7 /* Data overrun. */ -#define CS_COMMAND_OVERRUN 0x8 /* Command Overrun. */ -#define CS_STATUS_OVERRUN 0x9 /* Status Overrun. */ -#define CS_BAD_MSG 0xA /* Bad msg after status phase. */ -#define CS_NO_MSG_OUT 0xB /* No msg out after selection. */ -#define CS_EXTENDED_ID 0xC /* Extended ID failed. */ -#define CS_IDE_MSG 0xD /* Target rejected IDE msg. */ -#define CS_ABORT_MSG 0xE /* Target rejected abort msg. */ -#define CS_REJECT_MSG 0xF /* Target rejected reject msg. */ -#define CS_NOP_MSG 0x10 /* Target rejected NOP msg. */ -#define CS_PARITY_MSG 0x11 /* Target rejected parity msg. */ -#define CS_DEV_RESET_MSG 0x12 /* Target rejected dev rst msg. */ -#define CS_ID_MSG 0x13 /* Target rejected ID msg. */ -#define CS_FREE 0x14 /* Unexpected bus free. */ -#define CS_DATA_UNDERRUN 0x15 /* Data Underrun. */ -#define CS_TRANACTION_1 0x18 /* Transaction error 1 */ -#define CS_TRANACTION_2 0x19 /* Transaction error 2 */ -#define CS_TRANACTION_3 0x1a /* Transaction error 3 */ -#define CS_INV_ENTRY_TYPE 0x1b /* Invalid entry type */ -#define CS_DEV_QUEUE_FULL 0x1c /* Device queue full */ -#define CS_PHASED_SKIPPED 0x1d /* SCSI phase skipped */ -#define CS_ARS_FAILED 0x1e /* ARS failed */ -#define CS_LVD_BUS_ERROR 0x21 /* LVD bus error */ -#define CS_BAD_PAYLOAD 0x80 /* Driver defined */ -#define CS_UNKNOWN 0x81 /* Driver defined */ -#define CS_RETRY 0x82 /* Driver defined */ - -/* - * ISP target entries - Option flags bit definitions. - */ -#define OF_ENABLE_TAG BIT_1 /* Tagged queue action enable */ -#define OF_DATA_IN BIT_6 /* Data in to initiator */ - /* (data from target to initiator) */ -#define OF_DATA_OUT BIT_7 /* Data out from initiator */ - /* (data from initiator to target) */ -#define OF_NO_DATA (BIT_7 | BIT_6) -#define OF_DISC_DISABLED BIT_15 /* Disconnects disabled */ -#define OF_DISABLE_SDP BIT_24 /* Disable sending save data ptr */ -#define OF_SEND_RDP BIT_26 /* Send restore data pointers msg */ -#define OF_FORCE_DISC BIT_30 /* Disconnects mandatory */ -#define OF_SSTS BIT_31 /* Send SCSI status */ - - -/* - * BUS parameters/settings structure - UNUSED - */ -struct bus_param { - uint8_t id; /* Host adapter SCSI id */ - uint8_t bus_reset_delay; /* SCSI bus reset delay. */ - uint8_t failed_reset_count; /* number of time reset failed */ - uint8_t unused; - uint16_t device_enables; /* Device enable bits. */ - uint16_t lun_disables; /* LUN disable bits. */ - uint16_t qtag_enables; /* Tag queue enables. */ - uint16_t hiwat; /* High water mark per device. */ - uint8_t reset_marker:1; - uint8_t disable_scsi_reset:1; - uint8_t scsi_bus_dead:1; /* SCSI Bus is Dead, when 5 back to back resets failed */ -}; - - -struct qla_driver_setup { - uint32_t no_sync:1; - uint32_t no_wide:1; - uint32_t no_ppr:1; - uint32_t no_nvram:1; - uint16_t sync_mask; - uint16_t wide_mask; - uint16_t ppr_mask; -}; - - -/* - * Linux Host Adapter structure - */ -struct scsi_qla_host { - /* Linux adapter configuration data */ - struct Scsi_Host *host; /* pointer to host data */ - struct scsi_qla_host *next; - struct device_reg __iomem *iobase; /* Base Memory-mapped I/O address */ - - unsigned char __iomem *mmpbase; /* memory mapped address */ - unsigned long host_no; - struct pci_dev *pdev; - uint8_t devnum; - uint8_t revision; - uint8_t ports; - - unsigned long actthreads; - unsigned long isr_count; /* Interrupt count */ - unsigned long spurious_int; - - /* Outstandings ISP commands. */ - struct srb *outstanding_cmds[MAX_OUTSTANDING_COMMANDS]; - - /* BUS configuration data */ - struct bus_param bus_settings[MAX_BUSES]; - - /* Received ISP mailbox data. */ - volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; - - dma_addr_t request_dma; /* Physical Address */ - request_t *request_ring; /* Base virtual address */ - request_t *request_ring_ptr; /* Current address. */ - uint16_t req_ring_index; /* Current index. */ - uint16_t req_q_cnt; /* Number of available entries. */ - - dma_addr_t response_dma; /* Physical address. */ - struct response *response_ring; /* Base virtual address */ - struct response *response_ring_ptr; /* Current address. */ - uint16_t rsp_ring_index; /* Current index. */ - - struct list_head done_q; /* Done queue */ - - struct completion *mailbox_wait; - - volatile struct { - uint32_t online:1; /* 0 */ - uint32_t reset_marker:1; /* 1 */ - uint32_t disable_host_adapter:1; /* 2 */ - uint32_t reset_active:1; /* 3 */ - uint32_t abort_isp_active:1; /* 4 */ - uint32_t disable_risc_code_load:1; /* 5 */ -#ifdef __ia64__ - uint32_t use_pci_vchannel:1; -#endif - } flags; - - struct nvram nvram; - int nvram_valid; - - /* Firmware Info */ - unsigned short fwstart; /* start address for F/W */ - unsigned char fwver1; /* F/W version first char */ - unsigned char fwver2; /* F/W version second char */ - unsigned char fwver3; /* F/W version third char */ -}; - -#endif /* _QLA1280_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/Kconfig b/ANDROID_3.4.5/drivers/scsi/qla2xxx/Kconfig deleted file mode 100644 index 6208d562..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config SCSI_QLA_FC - tristate "QLogic QLA2XXX Fibre Channel Support" - depends on PCI && SCSI - select SCSI_FC_ATTRS - select FW_LOADER - ---help--- - This qla2xxx driver supports all QLogic Fibre Channel - PCI and PCIe host adapters. - - By default, firmware for the ISP parts will be loaded - via the Firmware Loader interface. - - ISP Firmware Filename - ---------- ----------------- - 21xx ql2100_fw.bin - 22xx ql2200_fw.bin - 2300, 2312, 6312 ql2300_fw.bin - 2322, 6322 ql2322_fw.bin - 24xx, 54xx ql2400_fw.bin - 25xx ql2500_fw.bin - - Upon request, the driver caches the firmware image until - the driver is unloaded. - - Firmware images can be retrieved from: - - ftp://ftp.qlogic.com/outgoing/linux/firmware/ diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/Makefile b/ANDROID_3.4.5/drivers/scsi/qla2xxx/Makefile deleted file mode 100644 index 5df782f4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \ - qla_dbg.o qla_sup.o qla_attr.o qla_mid.o qla_dfs.o qla_bsg.o \ - qla_nx.o - -obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx.o diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_attr.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_attr.c deleted file mode 100644 index 5926f5a8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_attr.c +++ /dev/null @@ -1,1971 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -#include -#include -#include -#include - -static int qla24xx_vport_disable(struct fc_vport *, bool); - -/* SYSFS attributes --------------------------------------------------------- */ - -static ssize_t -qla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - int rval = 0; - - if (ha->fw_dump_reading == 0) - return 0; - - if (IS_QLA82XX(ha)) { - if (off < ha->md_template_size) { - rval = memory_read_from_buffer(buf, count, - &off, ha->md_tmplt_hdr, ha->md_template_size); - return rval; - } - off -= ha->md_template_size; - rval = memory_read_from_buffer(buf, count, - &off, ha->md_dump, ha->md_dump_size); - return rval; - } else - return memory_read_from_buffer(buf, count, &off, ha->fw_dump, - ha->fw_dump_len); -} - -static ssize_t -qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - int reading; - - if (off != 0) - return (0); - - reading = simple_strtol(buf, NULL, 10); - switch (reading) { - case 0: - if (!ha->fw_dump_reading) - break; - - ql_log(ql_log_info, vha, 0x705d, - "Firmware dump cleared on (%ld).\n", vha->host_no); - - if (IS_QLA82XX(vha->hw)) { - qla82xx_md_free(vha); - qla82xx_md_prep(vha); - } - ha->fw_dump_reading = 0; - ha->fw_dumped = 0; - break; - case 1: - if (ha->fw_dumped && !ha->fw_dump_reading) { - ha->fw_dump_reading = 1; - - ql_log(ql_log_info, vha, 0x705e, - "Raw firmware dump ready for read on (%ld).\n", - vha->host_no); - } - break; - case 2: - qla2x00_alloc_fw_dump(vha); - break; - case 3: - if (IS_QLA82XX(ha)) { - qla82xx_idc_lock(ha); - qla82xx_set_reset_owner(vha); - qla82xx_idc_unlock(ha); - } else - qla2x00_system_error(vha); - break; - case 4: - if (IS_QLA82XX(ha)) { - if (ha->md_tmplt_hdr) - ql_dbg(ql_dbg_user, vha, 0x705b, - "MiniDump supported with this firmware.\n"); - else - ql_dbg(ql_dbg_user, vha, 0x709d, - "MiniDump not supported with this firmware.\n"); - } - break; - case 5: - if (IS_QLA82XX(ha)) - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - } - return count; -} - -static struct bin_attribute sysfs_fw_dump_attr = { - .attr = { - .name = "fw_dump", - .mode = S_IRUSR | S_IWUSR, - }, - .size = 0, - .read = qla2x00_sysfs_read_fw_dump, - .write = qla2x00_sysfs_write_fw_dump, -}; - -static ssize_t -qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - - if (!capable(CAP_SYS_ADMIN)) - return 0; - - if (IS_NOCACHE_VPD_TYPE(ha)) - ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, - ha->nvram_size); - return memory_read_from_buffer(buf, count, &off, ha->nvram, - ha->nvram_size); -} - -static ssize_t -qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - uint16_t cnt; - - if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size || - !ha->isp_ops->write_nvram) - return -EINVAL; - - /* Checksum NVRAM. */ - if (IS_FWI2_CAPABLE(ha)) { - uint32_t *iter; - uint32_t chksum; - - iter = (uint32_t *)buf; - chksum = 0; - for (cnt = 0; cnt < ((count >> 2) - 1); cnt++) - chksum += le32_to_cpu(*iter++); - chksum = ~chksum + 1; - *iter = cpu_to_le32(chksum); - } else { - uint8_t *iter; - uint8_t chksum; - - iter = (uint8_t *)buf; - chksum = 0; - for (cnt = 0; cnt < count - 1; cnt++) - chksum += *iter++; - chksum = ~chksum + 1; - *iter = chksum; - } - - if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x705f, - "HBA not online, failing NVRAM update.\n"); - return -EAGAIN; - } - - /* Write NVRAM. */ - ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->nvram_base, count); - ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base, - count); - - ql_dbg(ql_dbg_user, vha, 0x7060, - "Setting ISP_ABORT_NEEDED\n"); - /* NVRAM settings take effect immediately. */ - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - qla2x00_wait_for_chip_reset(vha); - - return count; -} - -static struct bin_attribute sysfs_nvram_attr = { - .attr = { - .name = "nvram", - .mode = S_IRUSR | S_IWUSR, - }, - .size = 512, - .read = qla2x00_sysfs_read_nvram, - .write = qla2x00_sysfs_write_nvram, -}; - -static ssize_t -qla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - - if (ha->optrom_state != QLA_SREADING) - return 0; - - return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer, - ha->optrom_region_size); -} - -static ssize_t -qla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - - if (ha->optrom_state != QLA_SWRITING) - return -EINVAL; - if (off > ha->optrom_region_size) - return -ERANGE; - if (off + count > ha->optrom_region_size) - count = ha->optrom_region_size - off; - - memcpy(&ha->optrom_buffer[off], buf, count); - - return count; -} - -static struct bin_attribute sysfs_optrom_attr = { - .attr = { - .name = "optrom", - .mode = S_IRUSR | S_IWUSR, - }, - .size = 0, - .read = qla2x00_sysfs_read_optrom, - .write = qla2x00_sysfs_write_optrom, -}; - -static ssize_t -qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - - uint32_t start = 0; - uint32_t size = ha->optrom_size; - int val, valid; - - if (off) - return -EINVAL; - - if (unlikely(pci_channel_offline(ha->pdev))) - return -EAGAIN; - - if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1) - return -EINVAL; - if (start > ha->optrom_size) - return -EINVAL; - - switch (val) { - case 0: - if (ha->optrom_state != QLA_SREADING && - ha->optrom_state != QLA_SWRITING) - return -EINVAL; - - ha->optrom_state = QLA_SWAITING; - - ql_dbg(ql_dbg_user, vha, 0x7061, - "Freeing flash region allocation -- 0x%x bytes.\n", - ha->optrom_region_size); - - vfree(ha->optrom_buffer); - ha->optrom_buffer = NULL; - break; - case 1: - if (ha->optrom_state != QLA_SWAITING) - return -EINVAL; - - ha->optrom_region_start = start; - ha->optrom_region_size = start + size > ha->optrom_size ? - ha->optrom_size - start : size; - - ha->optrom_state = QLA_SREADING; - ha->optrom_buffer = vmalloc(ha->optrom_region_size); - if (ha->optrom_buffer == NULL) { - ql_log(ql_log_warn, vha, 0x7062, - "Unable to allocate memory for optrom retrieval " - "(%x).\n", ha->optrom_region_size); - - ha->optrom_state = QLA_SWAITING; - return -ENOMEM; - } - - if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7063, - "HBA not online, failing NVRAM update.\n"); - return -EAGAIN; - } - - ql_dbg(ql_dbg_user, vha, 0x7064, - "Reading flash region -- 0x%x/0x%x.\n", - ha->optrom_region_start, ha->optrom_region_size); - - memset(ha->optrom_buffer, 0, ha->optrom_region_size); - ha->isp_ops->read_optrom(vha, ha->optrom_buffer, - ha->optrom_region_start, ha->optrom_region_size); - break; - case 2: - if (ha->optrom_state != QLA_SWAITING) - return -EINVAL; - - /* - * We need to be more restrictive on which FLASH regions are - * allowed to be updated via user-space. Regions accessible - * via this method include: - * - * ISP21xx/ISP22xx/ISP23xx type boards: - * - * 0x000000 -> 0x020000 -- Boot code. - * - * ISP2322/ISP24xx type boards: - * - * 0x000000 -> 0x07ffff -- Boot code. - * 0x080000 -> 0x0fffff -- Firmware. - * - * ISP25xx type boards: - * - * 0x000000 -> 0x07ffff -- Boot code. - * 0x080000 -> 0x0fffff -- Firmware. - * 0x120000 -> 0x12ffff -- VPD and HBA parameters. - */ - valid = 0; - if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0) - valid = 1; - else if (start == (ha->flt_region_boot * 4) || - start == (ha->flt_region_fw * 4)) - valid = 1; - else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) - || IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) - valid = 1; - if (!valid) { - ql_log(ql_log_warn, vha, 0x7065, - "Invalid start region 0x%x/0x%x.\n", start, size); - return -EINVAL; - } - - ha->optrom_region_start = start; - ha->optrom_region_size = start + size > ha->optrom_size ? - ha->optrom_size - start : size; - - ha->optrom_state = QLA_SWRITING; - ha->optrom_buffer = vmalloc(ha->optrom_region_size); - if (ha->optrom_buffer == NULL) { - ql_log(ql_log_warn, vha, 0x7066, - "Unable to allocate memory for optrom update " - "(%x)\n", ha->optrom_region_size); - - ha->optrom_state = QLA_SWAITING; - return -ENOMEM; - } - - ql_dbg(ql_dbg_user, vha, 0x7067, - "Staging flash region write -- 0x%x/0x%x.\n", - ha->optrom_region_start, ha->optrom_region_size); - - memset(ha->optrom_buffer, 0, ha->optrom_region_size); - break; - case 3: - if (ha->optrom_state != QLA_SWRITING) - return -EINVAL; - - if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7068, - "HBA not online, failing flash update.\n"); - return -EAGAIN; - } - - ql_dbg(ql_dbg_user, vha, 0x7069, - "Writing flash region -- 0x%x/0x%x.\n", - ha->optrom_region_start, ha->optrom_region_size); - - ha->isp_ops->write_optrom(vha, ha->optrom_buffer, - ha->optrom_region_start, ha->optrom_region_size); - break; - default: - return -EINVAL; - } - return count; -} - -static struct bin_attribute sysfs_optrom_ctl_attr = { - .attr = { - .name = "optrom_ctl", - .mode = S_IWUSR, - }, - .size = 0, - .write = qla2x00_sysfs_write_optrom_ctl, -}; - -static ssize_t -qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - - if (unlikely(pci_channel_offline(ha->pdev))) - return -EAGAIN; - - if (!capable(CAP_SYS_ADMIN)) - return -EINVAL; - - if (IS_NOCACHE_VPD_TYPE(ha)) - ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2, - ha->vpd_size); - return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size); -} - -static ssize_t -qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - uint8_t *tmp_data; - - if (unlikely(pci_channel_offline(ha->pdev))) - return 0; - - if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size || - !ha->isp_ops->write_nvram) - return 0; - - if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x706a, - "HBA not online, failing VPD update.\n"); - return -EAGAIN; - } - - /* Write NVRAM. */ - ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->vpd_base, count); - ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, ha->vpd_base, count); - - /* Update flash version information for 4Gb & above. */ - if (!IS_FWI2_CAPABLE(ha)) - return -EINVAL; - - tmp_data = vmalloc(256); - if (!tmp_data) { - ql_log(ql_log_warn, vha, 0x706b, - "Unable to allocate memory for VPD information update.\n"); - return -ENOMEM; - } - ha->isp_ops->get_flash_version(vha, tmp_data); - vfree(tmp_data); - - return count; -} - -static struct bin_attribute sysfs_vpd_attr = { - .attr = { - .name = "vpd", - .mode = S_IRUSR | S_IWUSR, - }, - .size = 0, - .read = qla2x00_sysfs_read_vpd, - .write = qla2x00_sysfs_write_vpd, -}; - -static ssize_t -qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - uint16_t iter, addr, offset; - int rval; - - if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2) - return 0; - - if (ha->sfp_data) - goto do_read; - - ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->sfp_data_dma); - if (!ha->sfp_data) { - ql_log(ql_log_warn, vha, 0x706c, - "Unable to allocate memory for SFP read-data.\n"); - return 0; - } - -do_read: - memset(ha->sfp_data, 0, SFP_BLOCK_SIZE); - addr = 0xa0; - for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE; - iter++, offset += SFP_BLOCK_SIZE) { - if (iter == 4) { - /* Skip to next device address. */ - addr = 0xa2; - offset = 0; - } - - rval = qla2x00_read_sfp(vha, ha->sfp_data_dma, ha->sfp_data, - addr, offset, SFP_BLOCK_SIZE, 0); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x706d, - "Unable to read SFP data (%x/%x/%x).\n", rval, - addr, offset); - - return -EIO; - } - memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE); - buf += SFP_BLOCK_SIZE; - } - - return count; -} - -static struct bin_attribute sysfs_sfp_attr = { - .attr = { - .name = "sfp", - .mode = S_IRUSR | S_IWUSR, - }, - .size = SFP_DEV_SIZE * 2, - .read = qla2x00_sysfs_read_sfp, -}; - -static ssize_t -qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - int type; - - if (off != 0) - return -EINVAL; - - type = simple_strtol(buf, NULL, 10); - switch (type) { - case 0x2025c: - ql_log(ql_log_info, vha, 0x706e, - "Issuing ISP reset.\n"); - - scsi_block_requests(vha->host); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - if (IS_QLA82XX(ha)) { - qla82xx_idc_lock(ha); - qla82xx_set_reset_owner(vha); - qla82xx_idc_unlock(ha); - } - qla2xxx_wake_dpc(vha); - qla2x00_wait_for_chip_reset(vha); - scsi_unblock_requests(vha->host); - break; - case 0x2025d: - if (!IS_QLA81XX(ha)) - return -EPERM; - - ql_log(ql_log_info, vha, 0x706f, - "Issuing MPI reset.\n"); - - /* Make sure FC side is not in reset */ - qla2x00_wait_for_hba_online(vha); - - /* Issue MPI reset */ - scsi_block_requests(vha->host); - if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS) - ql_log(ql_log_warn, vha, 0x7070, - "MPI reset failed.\n"); - scsi_unblock_requests(vha->host); - break; - case 0x2025e: - if (!IS_QLA82XX(ha) || vha != base_vha) { - ql_log(ql_log_info, vha, 0x7071, - "FCoE ctx reset no supported.\n"); - return -EPERM; - } - - ql_log(ql_log_info, vha, 0x7072, - "Issuing FCoE ctx reset.\n"); - set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - qla2x00_wait_for_fcoe_ctx_reset(vha); - break; - } - return count; -} - -static struct bin_attribute sysfs_reset_attr = { - .attr = { - .name = "reset", - .mode = S_IWUSR, - }, - .size = 0, - .write = qla2x00_sysfs_write_reset, -}; - -static ssize_t -qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - int rval; - uint16_t actual_size; - - if (!capable(CAP_SYS_ADMIN) || off != 0 || count > XGMAC_DATA_SIZE) - return 0; - - if (ha->xgmac_data) - goto do_read; - - ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE, - &ha->xgmac_data_dma, GFP_KERNEL); - if (!ha->xgmac_data) { - ql_log(ql_log_warn, vha, 0x7076, - "Unable to allocate memory for XGMAC read-data.\n"); - return 0; - } - -do_read: - actual_size = 0; - memset(ha->xgmac_data, 0, XGMAC_DATA_SIZE); - - rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma, - XGMAC_DATA_SIZE, &actual_size); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7077, - "Unable to read XGMAC data (%x).\n", rval); - count = 0; - } - - count = actual_size > count ? count: actual_size; - memcpy(buf, ha->xgmac_data, count); - - return count; -} - -static struct bin_attribute sysfs_xgmac_stats_attr = { - .attr = { - .name = "xgmac_stats", - .mode = S_IRUSR, - }, - .size = 0, - .read = qla2x00_sysfs_read_xgmac_stats, -}; - -static ssize_t -qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj, - struct device, kobj))); - struct qla_hw_data *ha = vha->hw; - int rval; - uint16_t actual_size; - - if (!capable(CAP_SYS_ADMIN) || off != 0 || count > DCBX_TLV_DATA_SIZE) - return 0; - - if (ha->dcbx_tlv) - goto do_read; - - ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, - &ha->dcbx_tlv_dma, GFP_KERNEL); - if (!ha->dcbx_tlv) { - ql_log(ql_log_warn, vha, 0x7078, - "Unable to allocate memory for DCBX TLV read-data.\n"); - return -ENOMEM; - } - -do_read: - actual_size = 0; - memset(ha->dcbx_tlv, 0, DCBX_TLV_DATA_SIZE); - - rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma, - DCBX_TLV_DATA_SIZE); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7079, - "Unable to read DCBX TLV (%x).\n", rval); - return -EIO; - } - - memcpy(buf, ha->dcbx_tlv, count); - - return count; -} - -static struct bin_attribute sysfs_dcbx_tlv_attr = { - .attr = { - .name = "dcbx_tlv", - .mode = S_IRUSR, - }, - .size = 0, - .read = qla2x00_sysfs_read_dcbx_tlv, -}; - -static struct sysfs_entry { - char *name; - struct bin_attribute *attr; - int is4GBp_only; -} bin_file_entries[] = { - { "fw_dump", &sysfs_fw_dump_attr, }, - { "nvram", &sysfs_nvram_attr, }, - { "optrom", &sysfs_optrom_attr, }, - { "optrom_ctl", &sysfs_optrom_ctl_attr, }, - { "vpd", &sysfs_vpd_attr, 1 }, - { "sfp", &sysfs_sfp_attr, 1 }, - { "reset", &sysfs_reset_attr, }, - { "xgmac_stats", &sysfs_xgmac_stats_attr, 3 }, - { "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 }, - { NULL }, -}; - -void -qla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha) -{ - struct Scsi_Host *host = vha->host; - struct sysfs_entry *iter; - int ret; - - for (iter = bin_file_entries; iter->name; iter++) { - if (iter->is4GBp_only && !IS_FWI2_CAPABLE(vha->hw)) - continue; - if (iter->is4GBp_only == 2 && !IS_QLA25XX(vha->hw)) - continue; - if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw))) - continue; - - ret = sysfs_create_bin_file(&host->shost_gendev.kobj, - iter->attr); - if (ret) - ql_log(ql_log_warn, vha, 0x00f3, - "Unable to create sysfs %s binary attribute (%d).\n", - iter->name, ret); - else - ql_dbg(ql_dbg_init, vha, 0x00f4, - "Successfully created sysfs %s binary attribure.\n", - iter->name); - } -} - -void -qla2x00_free_sysfs_attr(scsi_qla_host_t *vha) -{ - struct Scsi_Host *host = vha->host; - struct sysfs_entry *iter; - struct qla_hw_data *ha = vha->hw; - - for (iter = bin_file_entries; iter->name; iter++) { - if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha)) - continue; - if (iter->is4GBp_only == 2 && !IS_QLA25XX(ha)) - continue; - if (iter->is4GBp_only == 3 && !(IS_CNA_CAPABLE(vha->hw))) - continue; - - sysfs_remove_bin_file(&host->shost_gendev.kobj, - iter->attr); - } - - if (ha->beacon_blink_led == 1) - ha->isp_ops->beacon_off(vha); -} - -/* Scsi_Host attributes. */ - -static ssize_t -qla2x00_drvr_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str); -} - -static ssize_t -qla2x00_fw_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - char fw_str[128]; - - return snprintf(buf, PAGE_SIZE, "%s\n", - ha->isp_ops->fw_version_str(vha, fw_str)); -} - -static ssize_t -qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - uint32_t sn; - - if (IS_FWI2_CAPABLE(ha)) { - qla2xxx_get_vpd_field(vha, "SN", buf, PAGE_SIZE); - return snprintf(buf, PAGE_SIZE, "%s\n", buf); - } - - sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; - return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000, - sn % 100000); -} - -static ssize_t -qla2x00_isp_name_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - return snprintf(buf, PAGE_SIZE, "ISP%04X\n", vha->hw->pdev->device); -} - -static ssize_t -qla2x00_isp_id_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n", - ha->product_id[0], ha->product_id[1], ha->product_id[2], - ha->product_id[3]); -} - -static ssize_t -qla2x00_model_name_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - return snprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_number); -} - -static ssize_t -qla2x00_model_desc_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - return snprintf(buf, PAGE_SIZE, "%s\n", - vha->hw->model_desc ? vha->hw->model_desc : ""); -} - -static ssize_t -qla2x00_pci_info_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - char pci_info[30]; - - return snprintf(buf, PAGE_SIZE, "%s\n", - vha->hw->isp_ops->pci_info_str(vha, pci_info)); -} - -static ssize_t -qla2x00_link_state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - int len = 0; - - if (atomic_read(&vha->loop_state) == LOOP_DOWN || - atomic_read(&vha->loop_state) == LOOP_DEAD || - vha->device_flags & DFLG_NO_CABLE) - len = snprintf(buf, PAGE_SIZE, "Link Down\n"); - else if (atomic_read(&vha->loop_state) != LOOP_READY || - qla2x00_reset_active(vha)) - len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n"); - else { - len = snprintf(buf, PAGE_SIZE, "Link Up - "); - - switch (ha->current_topology) { - case ISP_CFG_NL: - len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n"); - break; - case ISP_CFG_FL: - len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n"); - break; - case ISP_CFG_N: - len += snprintf(buf + len, PAGE_SIZE-len, - "N_Port to N_Port\n"); - break; - case ISP_CFG_F: - len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n"); - break; - default: - len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n"); - break; - } - } - return len; -} - -static ssize_t -qla2x00_zio_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - int len = 0; - - switch (vha->hw->zio_mode) { - case QLA_ZIO_MODE_6: - len += snprintf(buf + len, PAGE_SIZE-len, "Mode 6\n"); - break; - case QLA_ZIO_DISABLED: - len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n"); - break; - } - return len; -} - -static ssize_t -qla2x00_zio_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - int val = 0; - uint16_t zio_mode; - - if (!IS_ZIO_SUPPORTED(ha)) - return -ENOTSUPP; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - if (val) - zio_mode = QLA_ZIO_MODE_6; - else - zio_mode = QLA_ZIO_DISABLED; - - /* Update per-hba values and queue a reset. */ - if (zio_mode != QLA_ZIO_DISABLED || ha->zio_mode != QLA_ZIO_DISABLED) { - ha->zio_mode = zio_mode; - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - } - return strlen(buf); -} - -static ssize_t -qla2x00_zio_timer_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - - return snprintf(buf, PAGE_SIZE, "%d us\n", vha->hw->zio_timer * 100); -} - -static ssize_t -qla2x00_zio_timer_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - int val = 0; - uint16_t zio_timer; - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - if (val > 25500 || val < 100) - return -ERANGE; - - zio_timer = (uint16_t)(val / 100); - vha->hw->zio_timer = zio_timer; - - return strlen(buf); -} - -static ssize_t -qla2x00_beacon_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - int len = 0; - - if (vha->hw->beacon_blink_led) - len += snprintf(buf + len, PAGE_SIZE-len, "Enabled\n"); - else - len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n"); - return len; -} - -static ssize_t -qla2x00_beacon_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - int val = 0; - int rval; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return -EPERM; - - if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { - ql_log(ql_log_warn, vha, 0x707a, - "Abort ISP active -- ignoring beacon request.\n"); - return -EBUSY; - } - - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - - if (val) - rval = ha->isp_ops->beacon_on(vha); - else - rval = ha->isp_ops->beacon_off(vha); - - if (rval != QLA_SUCCESS) - count = 0; - - return count; -} - -static ssize_t -qla2x00_optrom_bios_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1], - ha->bios_revision[0]); -} - -static ssize_t -qla2x00_optrom_efi_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1], - ha->efi_revision[0]); -} - -static ssize_t -qla2x00_optrom_fcode_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1], - ha->fcode_revision[0]); -} - -static ssize_t -qla2x00_optrom_fw_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n", - ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2], - ha->fw_revision[3]); -} - -static ssize_t -qla2x00_optrom_gold_fw_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) - return snprintf(buf, PAGE_SIZE, "\n"); - - return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n", - ha->gold_fw_version[0], ha->gold_fw_version[1], - ha->gold_fw_version[2], ha->gold_fw_version[3]); -} - -static ssize_t -qla2x00_total_isp_aborts_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - return snprintf(buf, PAGE_SIZE, "%d\n", - ha->qla_stats.total_isp_aborts); -} - -static ssize_t -qla24xx_84xx_fw_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int rval = QLA_SUCCESS; - uint16_t status[2] = {0, 0}; - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA84XX(ha)) - return snprintf(buf, PAGE_SIZE, "\n"); - - if (ha->cs84xx->op_fw_version == 0) - rval = qla84xx_verify_chip(vha, status); - - if ((rval == QLA_SUCCESS) && (status[0] == 0)) - return snprintf(buf, PAGE_SIZE, "%u\n", - (uint32_t)ha->cs84xx->op_fw_version); - - return snprintf(buf, PAGE_SIZE, "\n"); -} - -static ssize_t -qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) - return snprintf(buf, PAGE_SIZE, "\n"); - - return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n", - ha->mpi_version[0], ha->mpi_version[1], ha->mpi_version[2], - ha->mpi_capabilities); -} - -static ssize_t -qla2x00_phy_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) - return snprintf(buf, PAGE_SIZE, "\n"); - - return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n", - ha->phy_version[0], ha->phy_version[1], ha->phy_version[2]); -} - -static ssize_t -qla2x00_flash_block_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - struct qla_hw_data *ha = vha->hw; - - return snprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size); -} - -static ssize_t -qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - - if (!IS_CNA_CAPABLE(vha->hw)) - return snprintf(buf, PAGE_SIZE, "\n"); - - return snprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id); -} - -static ssize_t -qla2x00_vn_port_mac_address_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - - if (!IS_CNA_CAPABLE(vha->hw)) - return snprintf(buf, PAGE_SIZE, "\n"); - - return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", - vha->fcoe_vn_port_mac[5], vha->fcoe_vn_port_mac[4], - vha->fcoe_vn_port_mac[3], vha->fcoe_vn_port_mac[2], - vha->fcoe_vn_port_mac[1], vha->fcoe_vn_port_mac[0]); -} - -static ssize_t -qla2x00_fabric_param_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - - return snprintf(buf, PAGE_SIZE, "%d\n", vha->hw->switch_cap); -} - -static ssize_t -qla2x00_thermal_temp_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - int rval = QLA_FUNCTION_FAILED; - uint16_t temp, frac; - - if (!vha->hw->flags.thermal_supported) - return snprintf(buf, PAGE_SIZE, "\n"); - - temp = frac = 0; - if (qla2x00_reset_active(vha)) - ql_log(ql_log_warn, vha, 0x707b, - "ISP reset active.\n"); - else if (!vha->hw->flags.eeh_busy) - rval = qla2x00_get_thermal_temp(vha, &temp, &frac); - if (rval != QLA_SUCCESS) - return snprintf(buf, PAGE_SIZE, "\n"); - - return snprintf(buf, PAGE_SIZE, "%d.%02d\n", temp, frac); -} - -static ssize_t -qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - int rval = QLA_FUNCTION_FAILED; - uint16_t state[5]; - - if (qla2x00_reset_active(vha)) - ql_log(ql_log_warn, vha, 0x707c, - "ISP reset active.\n"); - else if (!vha->hw->flags.eeh_busy) - rval = qla2x00_get_firmware_state(vha, state); - if (rval != QLA_SUCCESS) - memset(state, -1, sizeof(state)); - - return snprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0], - state[1], state[2], state[3], state[4]); -} - -static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); -static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); -static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); -static DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL); -static DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL); -static DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL); -static DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL); -static DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL); -static DEVICE_ATTR(link_state, S_IRUGO, qla2x00_link_state_show, NULL); -static DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show, qla2x00_zio_store); -static DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show, - qla2x00_zio_timer_store); -static DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show, - qla2x00_beacon_store); -static DEVICE_ATTR(optrom_bios_version, S_IRUGO, - qla2x00_optrom_bios_version_show, NULL); -static DEVICE_ATTR(optrom_efi_version, S_IRUGO, - qla2x00_optrom_efi_version_show, NULL); -static DEVICE_ATTR(optrom_fcode_version, S_IRUGO, - qla2x00_optrom_fcode_version_show, NULL); -static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show, - NULL); -static DEVICE_ATTR(optrom_gold_fw_version, S_IRUGO, - qla2x00_optrom_gold_fw_version_show, NULL); -static DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show, - NULL); -static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show, - NULL); -static DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL); -static DEVICE_ATTR(phy_version, S_IRUGO, qla2x00_phy_version_show, NULL); -static DEVICE_ATTR(flash_block_size, S_IRUGO, qla2x00_flash_block_size_show, - NULL); -static DEVICE_ATTR(vlan_id, S_IRUGO, qla2x00_vlan_id_show, NULL); -static DEVICE_ATTR(vn_port_mac_address, S_IRUGO, - qla2x00_vn_port_mac_address_show, NULL); -static DEVICE_ATTR(fabric_param, S_IRUGO, qla2x00_fabric_param_show, NULL); -static DEVICE_ATTR(fw_state, S_IRUGO, qla2x00_fw_state_show, NULL); -static DEVICE_ATTR(thermal_temp, S_IRUGO, qla2x00_thermal_temp_show, NULL); - -struct device_attribute *qla2x00_host_attrs[] = { - &dev_attr_driver_version, - &dev_attr_fw_version, - &dev_attr_serial_num, - &dev_attr_isp_name, - &dev_attr_isp_id, - &dev_attr_model_name, - &dev_attr_model_desc, - &dev_attr_pci_info, - &dev_attr_link_state, - &dev_attr_zio, - &dev_attr_zio_timer, - &dev_attr_beacon, - &dev_attr_optrom_bios_version, - &dev_attr_optrom_efi_version, - &dev_attr_optrom_fcode_version, - &dev_attr_optrom_fw_version, - &dev_attr_84xx_fw_version, - &dev_attr_total_isp_aborts, - &dev_attr_mpi_version, - &dev_attr_phy_version, - &dev_attr_flash_block_size, - &dev_attr_vlan_id, - &dev_attr_vn_port_mac_address, - &dev_attr_fabric_param, - &dev_attr_fw_state, - &dev_attr_optrom_gold_fw_version, - &dev_attr_thermal_temp, - NULL, -}; - -/* Host attributes. */ - -static void -qla2x00_get_host_port_id(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - - fc_host_port_id(shost) = vha->d_id.b.domain << 16 | - vha->d_id.b.area << 8 | vha->d_id.b.al_pa; -} - -static void -qla2x00_get_host_speed(struct Scsi_Host *shost) -{ - struct qla_hw_data *ha = ((struct scsi_qla_host *) - (shost_priv(shost)))->hw; - u32 speed = FC_PORTSPEED_UNKNOWN; - - switch (ha->link_data_rate) { - case PORT_SPEED_1GB: - speed = FC_PORTSPEED_1GBIT; - break; - case PORT_SPEED_2GB: - speed = FC_PORTSPEED_2GBIT; - break; - case PORT_SPEED_4GB: - speed = FC_PORTSPEED_4GBIT; - break; - case PORT_SPEED_8GB: - speed = FC_PORTSPEED_8GBIT; - break; - case PORT_SPEED_10GB: - speed = FC_PORTSPEED_10GBIT; - break; - case PORT_SPEED_16GB: - speed = FC_PORTSPEED_16GBIT; - break; - } - fc_host_speed(shost) = speed; -} - -static void -qla2x00_get_host_port_type(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - uint32_t port_type = FC_PORTTYPE_UNKNOWN; - - if (vha->vp_idx) { - fc_host_port_type(shost) = FC_PORTTYPE_NPIV; - return; - } - switch (vha->hw->current_topology) { - case ISP_CFG_NL: - port_type = FC_PORTTYPE_LPORT; - break; - case ISP_CFG_FL: - port_type = FC_PORTTYPE_NLPORT; - break; - case ISP_CFG_N: - port_type = FC_PORTTYPE_PTP; - break; - case ISP_CFG_F: - port_type = FC_PORTTYPE_NPORT; - break; - } - fc_host_port_type(shost) = port_type; -} - -static void -qla2x00_get_starget_node_name(struct scsi_target *starget) -{ - struct Scsi_Host *host = dev_to_shost(starget->dev.parent); - scsi_qla_host_t *vha = shost_priv(host); - fc_port_t *fcport; - u64 node_name = 0; - - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (fcport->rport && - starget->id == fcport->rport->scsi_target_id) { - node_name = wwn_to_u64(fcport->node_name); - break; - } - } - - fc_starget_node_name(starget) = node_name; -} - -static void -qla2x00_get_starget_port_name(struct scsi_target *starget) -{ - struct Scsi_Host *host = dev_to_shost(starget->dev.parent); - scsi_qla_host_t *vha = shost_priv(host); - fc_port_t *fcport; - u64 port_name = 0; - - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (fcport->rport && - starget->id == fcport->rport->scsi_target_id) { - port_name = wwn_to_u64(fcport->port_name); - break; - } - } - - fc_starget_port_name(starget) = port_name; -} - -static void -qla2x00_get_starget_port_id(struct scsi_target *starget) -{ - struct Scsi_Host *host = dev_to_shost(starget->dev.parent); - scsi_qla_host_t *vha = shost_priv(host); - fc_port_t *fcport; - uint32_t port_id = ~0U; - - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (fcport->rport && - starget->id == fcport->rport->scsi_target_id) { - port_id = fcport->d_id.b.domain << 16 | - fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa; - break; - } - } - - fc_starget_port_id(starget) = port_id; -} - -static void -qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout) -{ - if (timeout) - rport->dev_loss_tmo = timeout; - else - rport->dev_loss_tmo = 1; -} - -static void -qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport) -{ - struct Scsi_Host *host = rport_to_shost(rport); - fc_port_t *fcport = *(fc_port_t **)rport->dd_data; - unsigned long flags; - - if (!fcport) - return; - - /* Now that the rport has been deleted, set the fcport state to - FCS_DEVICE_DEAD */ - qla2x00_set_fcport_state(fcport, FCS_DEVICE_DEAD); - - /* - * Transport has effectively 'deleted' the rport, clear - * all local references. - */ - spin_lock_irqsave(host->host_lock, flags); - fcport->rport = fcport->drport = NULL; - *((fc_port_t **)rport->dd_data) = NULL; - spin_unlock_irqrestore(host->host_lock, flags); - - if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags)) - return; - - if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) { - qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16); - return; - } -} - -static void -qla2x00_terminate_rport_io(struct fc_rport *rport) -{ - fc_port_t *fcport = *(fc_port_t **)rport->dd_data; - - if (!fcport) - return; - - if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags)) - return; - - if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) { - qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16); - return; - } - /* - * At this point all fcport's software-states are cleared. Perform any - * final cleanup of firmware resources (PCBs and XCBs). - */ - if (fcport->loop_id != FC_NO_LOOP_ID && - !test_bit(UNLOADING, &fcport->vha->dpc_flags)) { - if (IS_FWI2_CAPABLE(fcport->vha->hw)) - fcport->vha->hw->isp_ops->fabric_logout(fcport->vha, - fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - else - qla2x00_port_logout(fcport->vha, fcport); - } -} - -static int -qla2x00_issue_lip(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - - qla2x00_loop_reset(vha); - return 0; -} - -static struct fc_host_statistics * -qla2x00_get_fc_host_stats(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - int rval; - struct link_statistics *stats; - dma_addr_t stats_dma; - struct fc_host_statistics *pfc_host_stat; - - pfc_host_stat = &ha->fc_host_stat; - memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics)); - - if (test_bit(UNLOADING, &vha->dpc_flags)) - goto done; - - if (unlikely(pci_channel_offline(ha->pdev))) - goto done; - - stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma); - if (stats == NULL) { - ql_log(ql_log_warn, vha, 0x707d, - "Failed to allocate memory for stats.\n"); - goto done; - } - memset(stats, 0, DMA_POOL_SIZE); - - rval = QLA_FUNCTION_FAILED; - if (IS_FWI2_CAPABLE(ha)) { - rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma); - } else if (atomic_read(&base_vha->loop_state) == LOOP_READY && - !qla2x00_reset_active(vha) && !ha->dpc_active) { - /* Must be in a 'READY' state for statistics retrieval. */ - rval = qla2x00_get_link_status(base_vha, base_vha->loop_id, - stats, stats_dma); - } - - if (rval != QLA_SUCCESS) - goto done_free; - - pfc_host_stat->link_failure_count = stats->link_fail_cnt; - pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt; - pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt; - pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt; - pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt; - pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt; - if (IS_FWI2_CAPABLE(ha)) { - pfc_host_stat->lip_count = stats->lip_cnt; - pfc_host_stat->tx_frames = stats->tx_frames; - pfc_host_stat->rx_frames = stats->rx_frames; - pfc_host_stat->dumped_frames = stats->dumped_frames; - pfc_host_stat->nos_count = stats->nos_rcvd; - } - pfc_host_stat->fcp_input_megabytes = ha->qla_stats.input_bytes >> 20; - pfc_host_stat->fcp_output_megabytes = ha->qla_stats.output_bytes >> 20; - -done_free: - dma_pool_free(ha->s_dma_pool, stats, stats_dma); -done: - return pfc_host_stat; -} - -static void -qla2x00_get_host_symbolic_name(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - - qla2x00_get_sym_node_name(vha, fc_host_symbolic_name(shost)); -} - -static void -qla2x00_set_host_system_hostname(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - - set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); -} - -static void -qla2x00_get_host_fabric_name(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - uint8_t node_name[WWN_SIZE] = { 0xFF, 0xFF, 0xFF, 0xFF, \ - 0xFF, 0xFF, 0xFF, 0xFF}; - u64 fabric_name = wwn_to_u64(node_name); - - if (vha->device_flags & SWITCH_FOUND) - fabric_name = wwn_to_u64(vha->fabric_node_name); - - fc_host_fabric_name(shost) = fabric_name; -} - -static void -qla2x00_get_host_port_state(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - struct scsi_qla_host *base_vha = pci_get_drvdata(vha->hw->pdev); - - if (!base_vha->flags.online) { - fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE; - return; - } - - switch (atomic_read(&base_vha->loop_state)) { - case LOOP_UPDATE: - fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS; - break; - case LOOP_DOWN: - if (test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags)) - fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS; - else - fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; - break; - case LOOP_DEAD: - fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN; - break; - case LOOP_READY: - fc_host_port_state(shost) = FC_PORTSTATE_ONLINE; - break; - default: - fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN; - break; - } -} - -static int -qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) -{ - int ret = 0; - uint8_t qos = 0; - scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost); - scsi_qla_host_t *vha = NULL; - struct qla_hw_data *ha = base_vha->hw; - uint16_t options = 0; - int cnt; - struct req_que *req = ha->req_q_map[0]; - - ret = qla24xx_vport_create_req_sanity_check(fc_vport); - if (ret) { - ql_log(ql_log_warn, vha, 0x707e, - "Vport sanity check failed, status %x\n", ret); - return (ret); - } - - vha = qla24xx_create_vhost(fc_vport); - if (vha == NULL) { - ql_log(ql_log_warn, vha, 0x707f, "Vport create host failed.\n"); - return FC_VPORT_FAILED; - } - if (disable) { - atomic_set(&vha->vp_state, VP_OFFLINE); - fc_vport_set_state(fc_vport, FC_VPORT_DISABLED); - } else - atomic_set(&vha->vp_state, VP_FAILED); - - /* ready to create vport */ - ql_log(ql_log_info, vha, 0x7080, - "VP entry id %d assigned.\n", vha->vp_idx); - - /* initialized vport states */ - atomic_set(&vha->loop_state, LOOP_DOWN); - vha->vp_err_state= VP_ERR_PORTDWN; - vha->vp_prev_err_state= VP_ERR_UNKWN; - /* Check if physical ha port is Up */ - if (atomic_read(&base_vha->loop_state) == LOOP_DOWN || - atomic_read(&base_vha->loop_state) == LOOP_DEAD) { - /* Don't retry or attempt login of this virtual port */ - ql_dbg(ql_dbg_user, vha, 0x7081, - "Vport loop state is not UP.\n"); - atomic_set(&vha->loop_state, LOOP_DEAD); - if (!disable) - fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN); - } - - if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { - if (ha->fw_attributes & BIT_4) { - int prot = 0; - vha->flags.difdix_supported = 1; - ql_dbg(ql_dbg_user, vha, 0x7082, - "Registered for DIF/DIX type 1 and 3 protection.\n"); - if (ql2xenabledif == 1) - prot = SHOST_DIX_TYPE0_PROTECTION; - scsi_host_set_prot(vha->host, - prot | SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE2_PROTECTION - | SHOST_DIF_TYPE3_PROTECTION - | SHOST_DIX_TYPE1_PROTECTION - | SHOST_DIX_TYPE2_PROTECTION - | SHOST_DIX_TYPE3_PROTECTION); - scsi_host_set_guard(vha->host, SHOST_DIX_GUARD_CRC); - } else - vha->flags.difdix_supported = 0; - } - - if (scsi_add_host_with_dma(vha->host, &fc_vport->dev, - &ha->pdev->dev)) { - ql_dbg(ql_dbg_user, vha, 0x7083, - "scsi_add_host failure for VP[%d].\n", vha->vp_idx); - goto vport_create_failed_2; - } - - /* initialize attributes */ - fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count; - fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name); - fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name); - fc_host_supported_classes(vha->host) = - fc_host_supported_classes(base_vha->host); - fc_host_supported_speeds(vha->host) = - fc_host_supported_speeds(base_vha->host); - - qla24xx_vport_disable(fc_vport, disable); - - if (ha->flags.cpu_affinity_enabled) { - req = ha->req_q_map[1]; - ql_dbg(ql_dbg_multiq, vha, 0xc000, - "Request queue %p attached with " - "VP[%d], cpu affinity =%d\n", - req, vha->vp_idx, ha->flags.cpu_affinity_enabled); - goto vport_queue; - } else if (ql2xmaxqueues == 1 || !ha->npiv_info) - goto vport_queue; - /* Create a request queue in QoS mode for the vport */ - for (cnt = 0; cnt < ha->nvram_npiv_size; cnt++) { - if (memcmp(ha->npiv_info[cnt].port_name, vha->port_name, 8) == 0 - && memcmp(ha->npiv_info[cnt].node_name, vha->node_name, - 8) == 0) { - qos = ha->npiv_info[cnt].q_qos; - break; - } - } - - if (qos) { - ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0, - qos); - if (!ret) - ql_log(ql_log_warn, vha, 0x7084, - "Can't create request queue for VP[%d]\n", - vha->vp_idx); - else { - ql_dbg(ql_dbg_multiq, vha, 0xc001, - "Request Que:%d Q0s: %d) created for VP[%d]\n", - ret, qos, vha->vp_idx); - ql_dbg(ql_dbg_user, vha, 0x7085, - "Request Que:%d Q0s: %d) created for VP[%d]\n", - ret, qos, vha->vp_idx); - req = ha->req_q_map[ret]; - } - } - -vport_queue: - vha->req = req; - return 0; - -vport_create_failed_2: - qla24xx_disable_vp(vha); - qla24xx_deallocate_vp_id(vha); - scsi_host_put(vha->host); - return FC_VPORT_FAILED; -} - -static int -qla24xx_vport_delete(struct fc_vport *fc_vport) -{ - scsi_qla_host_t *vha = fc_vport->dd_data; - struct qla_hw_data *ha = vha->hw; - uint16_t id = vha->vp_idx; - - while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) || - test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) - msleep(1000); - - qla24xx_disable_vp(vha); - - vha->flags.delete_progress = 1; - - fc_remove_host(vha->host); - - scsi_remove_host(vha->host); - - /* Allow timer to run to drain queued items, when removing vp */ - qla24xx_deallocate_vp_id(vha); - - if (vha->timer_active) { - qla2x00_vp_stop_timer(vha); - ql_dbg(ql_dbg_user, vha, 0x7086, - "Timer for the VP[%d] has stopped\n", vha->vp_idx); - } - - /* No pending activities shall be there on the vha now */ - if (ql2xextended_error_logging & ql_dbg_user) - msleep(random32()%10); /* Just to see if something falls on - * the net we have placed below */ - - BUG_ON(atomic_read(&vha->vref_count)); - - qla2x00_free_fcports(vha); - - mutex_lock(&ha->vport_lock); - ha->cur_vport_count--; - clear_bit(vha->vp_idx, ha->vp_idx_map); - mutex_unlock(&ha->vport_lock); - - if (vha->req->id && !ha->flags.cpu_affinity_enabled) { - if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) - ql_log(ql_log_warn, vha, 0x7087, - "Queue delete failed.\n"); - } - - ql_log(ql_log_info, vha, 0x7088, "VP[%d] deleted.\n", id); - scsi_host_put(vha->host); - return 0; -} - -static int -qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable) -{ - scsi_qla_host_t *vha = fc_vport->dd_data; - - if (disable) - qla24xx_disable_vp(vha); - else - qla24xx_enable_vp(vha); - - return 0; -} - -struct fc_function_template qla2xxx_transport_functions = { - - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - .show_host_supported_speeds = 1, - - .get_host_port_id = qla2x00_get_host_port_id, - .show_host_port_id = 1, - .get_host_speed = qla2x00_get_host_speed, - .show_host_speed = 1, - .get_host_port_type = qla2x00_get_host_port_type, - .show_host_port_type = 1, - .get_host_symbolic_name = qla2x00_get_host_symbolic_name, - .show_host_symbolic_name = 1, - .set_host_system_hostname = qla2x00_set_host_system_hostname, - .show_host_system_hostname = 1, - .get_host_fabric_name = qla2x00_get_host_fabric_name, - .show_host_fabric_name = 1, - .get_host_port_state = qla2x00_get_host_port_state, - .show_host_port_state = 1, - - .dd_fcrport_size = sizeof(struct fc_port *), - .show_rport_supported_classes = 1, - - .get_starget_node_name = qla2x00_get_starget_node_name, - .show_starget_node_name = 1, - .get_starget_port_name = qla2x00_get_starget_port_name, - .show_starget_port_name = 1, - .get_starget_port_id = qla2x00_get_starget_port_id, - .show_starget_port_id = 1, - - .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - - .issue_fc_host_lip = qla2x00_issue_lip, - .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, - .terminate_rport_io = qla2x00_terminate_rport_io, - .get_fc_host_stats = qla2x00_get_fc_host_stats, - - .vport_create = qla24xx_vport_create, - .vport_disable = qla24xx_vport_disable, - .vport_delete = qla24xx_vport_delete, - .bsg_request = qla24xx_bsg_request, - .bsg_timeout = qla24xx_bsg_timeout, -}; - -struct fc_function_template qla2xxx_transport_vport_functions = { - - .show_host_node_name = 1, - .show_host_port_name = 1, - .show_host_supported_classes = 1, - - .get_host_port_id = qla2x00_get_host_port_id, - .show_host_port_id = 1, - .get_host_speed = qla2x00_get_host_speed, - .show_host_speed = 1, - .get_host_port_type = qla2x00_get_host_port_type, - .show_host_port_type = 1, - .get_host_symbolic_name = qla2x00_get_host_symbolic_name, - .show_host_symbolic_name = 1, - .set_host_system_hostname = qla2x00_set_host_system_hostname, - .show_host_system_hostname = 1, - .get_host_fabric_name = qla2x00_get_host_fabric_name, - .show_host_fabric_name = 1, - .get_host_port_state = qla2x00_get_host_port_state, - .show_host_port_state = 1, - - .dd_fcrport_size = sizeof(struct fc_port *), - .show_rport_supported_classes = 1, - - .get_starget_node_name = qla2x00_get_starget_node_name, - .show_starget_node_name = 1, - .get_starget_port_name = qla2x00_get_starget_port_name, - .show_starget_port_name = 1, - .get_starget_port_id = qla2x00_get_starget_port_id, - .show_starget_port_id = 1, - - .set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo, - .show_rport_dev_loss_tmo = 1, - - .issue_fc_host_lip = qla2x00_issue_lip, - .dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk, - .terminate_rport_io = qla2x00_terminate_rport_io, - .get_fc_host_stats = qla2x00_get_fc_host_stats, - .bsg_request = qla24xx_bsg_request, - .bsg_timeout = qla24xx_bsg_timeout, -}; - -void -qla2x00_init_host_attr(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - u32 speed = FC_PORTSPEED_UNKNOWN; - - fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count; - fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name); - fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name); - fc_host_supported_classes(vha->host) = FC_COS_CLASS3; - fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports; - fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count; - - if (IS_CNA_CAPABLE(ha)) - speed = FC_PORTSPEED_10GBIT; - else if (IS_QLA25XX(ha)) - speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT | - FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; - else if (IS_QLA24XX_TYPE(ha)) - speed = FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT | - FC_PORTSPEED_1GBIT; - else if (IS_QLA23XX(ha)) - speed = FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT; - else - speed = FC_PORTSPEED_1GBIT; - fc_host_supported_speeds(vha->host) = speed; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.c deleted file mode 100644 index bc3cc6d9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.c +++ /dev/null @@ -1,1716 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -#include -#include -#include - -/* BSG support for ELS/CT pass through */ -void -qla2x00_bsg_job_done(void *data, void *ptr, int res) -{ - srb_t *sp = (srb_t *)ptr; - struct scsi_qla_host *vha = (scsi_qla_host_t *)data; - struct fc_bsg_job *bsg_job = sp->u.bsg_job; - - bsg_job->reply->result = res; - bsg_job->job_done(bsg_job); - sp->free(vha, sp); -} - -void -qla2x00_bsg_sp_free(void *data, void *ptr) -{ - srb_t *sp = (srb_t *)ptr; - struct scsi_qla_host *vha = (scsi_qla_host_t *)data; - struct fc_bsg_job *bsg_job = sp->u.bsg_job; - struct qla_hw_data *ha = vha->hw; - - dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - - dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - - if (sp->type == SRB_CT_CMD || - sp->type == SRB_ELS_CMD_HST) - kfree(sp->fcport); - mempool_free(sp, vha->hw->srb_mempool); -} - -int -qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *vha, - struct qla_fcp_prio_cfg *pri_cfg, uint8_t flag) -{ - int i, ret, num_valid; - uint8_t *bcode; - struct qla_fcp_prio_entry *pri_entry; - uint32_t *bcode_val_ptr, bcode_val; - - ret = 1; - num_valid = 0; - bcode = (uint8_t *)pri_cfg; - bcode_val_ptr = (uint32_t *)pri_cfg; - bcode_val = (uint32_t)(*bcode_val_ptr); - - if (bcode_val == 0xFFFFFFFF) { - /* No FCP Priority config data in flash */ - ql_dbg(ql_dbg_user, vha, 0x7051, - "No FCP Priority config data.\n"); - return 0; - } - - if (bcode[0] != 'H' || bcode[1] != 'Q' || bcode[2] != 'O' || - bcode[3] != 'S') { - /* Invalid FCP priority data header*/ - ql_dbg(ql_dbg_user, vha, 0x7052, - "Invalid FCP Priority data header. bcode=0x%x.\n", - bcode_val); - return 0; - } - if (flag != 1) - return ret; - - pri_entry = &pri_cfg->entry[0]; - for (i = 0; i < pri_cfg->num_entries; i++) { - if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID) - num_valid++; - pri_entry++; - } - - if (num_valid == 0) { - /* No valid FCP priority data entries */ - ql_dbg(ql_dbg_user, vha, 0x7053, - "No valid FCP Priority data entries.\n"); - ret = 0; - } else { - /* FCP priority data is valid */ - ql_dbg(ql_dbg_user, vha, 0x7054, - "Valid FCP priority data. num entries = %d.\n", - num_valid); - } - - return ret; -} - -static int -qla24xx_proc_fcp_prio_cfg_cmd(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int ret = 0; - uint32_t len; - uint32_t oper; - - if (!(IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || IS_QLA82XX(ha))) { - ret = -EINVAL; - goto exit_fcp_prio_cfg; - } - - /* Get the sub command */ - oper = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; - - /* Only set config is allowed if config memory is not allocated */ - if (!ha->fcp_prio_cfg && (oper != QLFC_FCP_PRIO_SET_CONFIG)) { - ret = -EINVAL; - goto exit_fcp_prio_cfg; - } - switch (oper) { - case QLFC_FCP_PRIO_DISABLE: - if (ha->flags.fcp_prio_enabled) { - ha->flags.fcp_prio_enabled = 0; - ha->fcp_prio_cfg->attributes &= - ~FCP_PRIO_ATTR_ENABLE; - qla24xx_update_all_fcp_prio(vha); - bsg_job->reply->result = DID_OK; - } else { - ret = -EINVAL; - bsg_job->reply->result = (DID_ERROR << 16); - goto exit_fcp_prio_cfg; - } - break; - - case QLFC_FCP_PRIO_ENABLE: - if (!ha->flags.fcp_prio_enabled) { - if (ha->fcp_prio_cfg) { - ha->flags.fcp_prio_enabled = 1; - ha->fcp_prio_cfg->attributes |= - FCP_PRIO_ATTR_ENABLE; - qla24xx_update_all_fcp_prio(vha); - bsg_job->reply->result = DID_OK; - } else { - ret = -EINVAL; - bsg_job->reply->result = (DID_ERROR << 16); - goto exit_fcp_prio_cfg; - } - } - break; - - case QLFC_FCP_PRIO_GET_CONFIG: - len = bsg_job->reply_payload.payload_len; - if (!len || len > FCP_PRIO_CFG_SIZE) { - ret = -EINVAL; - bsg_job->reply->result = (DID_ERROR << 16); - goto exit_fcp_prio_cfg; - } - - bsg_job->reply->result = DID_OK; - bsg_job->reply->reply_payload_rcv_len = - sg_copy_from_buffer( - bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, ha->fcp_prio_cfg, - len); - - break; - - case QLFC_FCP_PRIO_SET_CONFIG: - len = bsg_job->request_payload.payload_len; - if (!len || len > FCP_PRIO_CFG_SIZE) { - bsg_job->reply->result = (DID_ERROR << 16); - ret = -EINVAL; - goto exit_fcp_prio_cfg; - } - - if (!ha->fcp_prio_cfg) { - ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE); - if (!ha->fcp_prio_cfg) { - ql_log(ql_log_warn, vha, 0x7050, - "Unable to allocate memory for fcp prio " - "config data (%x).\n", FCP_PRIO_CFG_SIZE); - bsg_job->reply->result = (DID_ERROR << 16); - ret = -ENOMEM; - goto exit_fcp_prio_cfg; - } - } - - memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE); - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, ha->fcp_prio_cfg, - FCP_PRIO_CFG_SIZE); - - /* validate fcp priority data */ - - if (!qla24xx_fcp_prio_cfg_valid(vha, - (struct qla_fcp_prio_cfg *) ha->fcp_prio_cfg, 1)) { - bsg_job->reply->result = (DID_ERROR << 16); - ret = -EINVAL; - /* If buffer was invalidatic int - * fcp_prio_cfg is of no use - */ - vfree(ha->fcp_prio_cfg); - ha->fcp_prio_cfg = NULL; - goto exit_fcp_prio_cfg; - } - - ha->flags.fcp_prio_enabled = 0; - if (ha->fcp_prio_cfg->attributes & FCP_PRIO_ATTR_ENABLE) - ha->flags.fcp_prio_enabled = 1; - qla24xx_update_all_fcp_prio(vha); - bsg_job->reply->result = DID_OK; - break; - default: - ret = -EINVAL; - break; - } -exit_fcp_prio_cfg: - bsg_job->job_done(bsg_job); - return ret; -} - -static int -qla2x00_process_els(struct fc_bsg_job *bsg_job) -{ - struct fc_rport *rport; - fc_port_t *fcport = NULL; - struct Scsi_Host *host; - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - srb_t *sp; - const char *type; - int req_sg_cnt, rsp_sg_cnt; - int rval = (DRIVER_ERROR << 16); - uint16_t nextlid = 0; - - if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { - rport = bsg_job->rport; - fcport = *(fc_port_t **) rport->dd_data; - host = rport_to_shost(rport); - vha = shost_priv(host); - ha = vha->hw; - type = "FC_BSG_RPT_ELS"; - } else { - host = bsg_job->shost; - vha = shost_priv(host); - ha = vha->hw; - type = "FC_BSG_HST_ELS_NOLOGIN"; - } - - /* pass through is supported only for ISP 4Gb or higher */ - if (!IS_FWI2_CAPABLE(ha)) { - ql_dbg(ql_dbg_user, vha, 0x7001, - "ELS passthru not supported for ISP23xx based adapters.\n"); - rval = -EPERM; - goto done; - } - - /* Multiple SG's are not supported for ELS requests */ - if (bsg_job->request_payload.sg_cnt > 1 || - bsg_job->reply_payload.sg_cnt > 1) { - ql_dbg(ql_dbg_user, vha, 0x7002, - "Multiple SG's are not suppored for ELS requests, " - "request_sg_cnt=%x reply_sg_cnt=%x.\n", - bsg_job->request_payload.sg_cnt, - bsg_job->reply_payload.sg_cnt); - rval = -EPERM; - goto done; - } - - /* ELS request for rport */ - if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { - /* make sure the rport is logged in, - * if not perform fabric login - */ - if (qla2x00_fabric_login(vha, fcport, &nextlid)) { - ql_dbg(ql_dbg_user, vha, 0x7003, - "Failed to login port %06X for ELS passthru.\n", - fcport->d_id.b24); - rval = -EIO; - goto done; - } - } else { - /* Allocate a dummy fcport structure, since functions - * preparing the IOCB and mailbox command retrieves port - * specific information from fcport structure. For Host based - * ELS commands there will be no fcport structure allocated - */ - fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); - if (!fcport) { - rval = -ENOMEM; - goto done; - } - - /* Initialize all required fields of fcport */ - fcport->vha = vha; - fcport->vp_idx = vha->vp_idx; - fcport->d_id.b.al_pa = - bsg_job->request->rqst_data.h_els.port_id[0]; - fcport->d_id.b.area = - bsg_job->request->rqst_data.h_els.port_id[1]; - fcport->d_id.b.domain = - bsg_job->request->rqst_data.h_els.port_id[2]; - fcport->loop_id = - (fcport->d_id.b.al_pa == 0xFD) ? - NPH_FABRIC_CONTROLLER : NPH_F_PORT; - } - - if (!vha->flags.online) { - ql_log(ql_log_warn, vha, 0x7005, "Host not online.\n"); - rval = -EIO; - goto done; - } - - req_sg_cnt = - dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - if (!req_sg_cnt) { - rval = -ENOMEM; - goto done_free_fcport; - } - - rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - if (!rsp_sg_cnt) { - rval = -ENOMEM; - goto done_free_fcport; - } - - if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || - (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { - ql_log(ql_log_warn, vha, 0x7008, - "dma mapping resulted in different sg counts, " - "request_sg_cnt: %x dma_request_sg_cnt:%x reply_sg_cnt:%x " - "dma_reply_sg_cnt:%x.\n", bsg_job->request_payload.sg_cnt, - req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt); - rval = -EAGAIN; - goto done_unmap_sg; - } - - /* Alloc SRB structure */ - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); - if (!sp) { - rval = -ENOMEM; - goto done_unmap_sg; - } - - sp->type = - (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? - SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST); - sp->name = - (bsg_job->request->msgcode == FC_BSG_RPT_ELS ? - "bsg_els_rpt" : "bsg_els_hst"); - sp->u.bsg_job = bsg_job; - sp->free = qla2x00_bsg_sp_free; - sp->done = qla2x00_bsg_job_done; - - ql_dbg(ql_dbg_user, vha, 0x700a, - "bsg rqst type: %s els type: %x - loop-id=%x " - "portid=%-2x%02x%02x.\n", type, - bsg_job->request->rqst_data.h_els.command_code, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); - - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x700e, - "qla2x00_start_sp failed = %d\n", rval); - mempool_free(sp, ha->srb_mempool); - rval = -EIO; - goto done_unmap_sg; - } - return rval; - -done_unmap_sg: - dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - goto done_free_fcport; - -done_free_fcport: - if (bsg_job->request->msgcode == FC_BSG_HST_ELS_NOLOGIN) - kfree(fcport); -done: - return rval; -} - -inline uint16_t -qla24xx_calc_ct_iocbs(uint16_t dsds) -{ - uint16_t iocbs; - - iocbs = 1; - if (dsds > 2) { - iocbs += (dsds - 2) / 5; - if ((dsds - 2) % 5) - iocbs++; - } - return iocbs; -} - -static int -qla2x00_process_ct(struct fc_bsg_job *bsg_job) -{ - srb_t *sp; - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int rval = (DRIVER_ERROR << 16); - int req_sg_cnt, rsp_sg_cnt; - uint16_t loop_id; - struct fc_port *fcport; - char *type = "FC_BSG_HST_CT"; - - req_sg_cnt = - dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - if (!req_sg_cnt) { - ql_log(ql_log_warn, vha, 0x700f, - "dma_map_sg return %d for request\n", req_sg_cnt); - rval = -ENOMEM; - goto done; - } - - rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - if (!rsp_sg_cnt) { - ql_log(ql_log_warn, vha, 0x7010, - "dma_map_sg return %d for reply\n", rsp_sg_cnt); - rval = -ENOMEM; - goto done; - } - - if ((req_sg_cnt != bsg_job->request_payload.sg_cnt) || - (rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { - ql_log(ql_log_warn, vha, 0x7011, - "request_sg_cnt: %x dma_request_sg_cnt: %x reply_sg_cnt:%x " - "dma_reply_sg_cnt: %x\n", bsg_job->request_payload.sg_cnt, - req_sg_cnt, bsg_job->reply_payload.sg_cnt, rsp_sg_cnt); - rval = -EAGAIN; - goto done_unmap_sg; - } - - if (!vha->flags.online) { - ql_log(ql_log_warn, vha, 0x7012, - "Host is not online.\n"); - rval = -EIO; - goto done_unmap_sg; - } - - loop_id = - (bsg_job->request->rqst_data.h_ct.preamble_word1 & 0xFF000000) - >> 24; - switch (loop_id) { - case 0xFC: - loop_id = cpu_to_le16(NPH_SNS); - break; - case 0xFA: - loop_id = vha->mgmt_svr_loop_id; - break; - default: - ql_dbg(ql_dbg_user, vha, 0x7013, - "Unknown loop id: %x.\n", loop_id); - rval = -EINVAL; - goto done_unmap_sg; - } - - /* Allocate a dummy fcport structure, since functions preparing the - * IOCB and mailbox command retrieves port specific information - * from fcport structure. For Host based ELS commands there will be - * no fcport structure allocated - */ - fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); - if (!fcport) { - ql_log(ql_log_warn, vha, 0x7014, - "Failed to allocate fcport.\n"); - rval = -ENOMEM; - goto done_unmap_sg; - } - - /* Initialize all required fields of fcport */ - fcport->vha = vha; - fcport->vp_idx = vha->vp_idx; - fcport->d_id.b.al_pa = bsg_job->request->rqst_data.h_ct.port_id[0]; - fcport->d_id.b.area = bsg_job->request->rqst_data.h_ct.port_id[1]; - fcport->d_id.b.domain = bsg_job->request->rqst_data.h_ct.port_id[2]; - fcport->loop_id = loop_id; - - /* Alloc SRB structure */ - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); - if (!sp) { - ql_log(ql_log_warn, vha, 0x7015, - "qla2x00_get_sp failed.\n"); - rval = -ENOMEM; - goto done_free_fcport; - } - - sp->type = SRB_CT_CMD; - sp->name = "bsg_ct"; - sp->iocbs = qla24xx_calc_ct_iocbs(req_sg_cnt + rsp_sg_cnt); - sp->u.bsg_job = bsg_job; - sp->free = qla2x00_bsg_sp_free; - sp->done = qla2x00_bsg_job_done; - - ql_dbg(ql_dbg_user, vha, 0x7016, - "bsg rqst type: %s else type: %x - " - "loop-id=%x portid=%02x%02x%02x.\n", type, - (bsg_job->request->rqst_data.h_ct.preamble_word2 >> 16), - fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7017, - "qla2x00_start_sp failed=%d.\n", rval); - mempool_free(sp, ha->srb_mempool); - rval = -EIO; - goto done_free_fcport; - } - return rval; - -done_free_fcport: - kfree(fcport); -done_unmap_sg: - dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -done: - return rval; -} - -/* Set the port configuration to enable the - * internal loopback on ISP81XX - */ -static inline int -qla81xx_set_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, - uint16_t *new_config) -{ - int ret = 0; - int rval = 0; - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) - goto done_set_internal; - - new_config[0] = config[0] | (ENABLE_INTERNAL_LOOPBACK << 1); - memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; - - ha->notify_dcbx_comp = 1; - ret = qla81xx_set_port_config(vha, new_config); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7021, - "set port config failed.\n"); - ha->notify_dcbx_comp = 0; - rval = -EINVAL; - goto done_set_internal; - } - - /* Wait for DCBX complete event */ - if (!wait_for_completion_timeout(&ha->dcbx_comp, (20 * HZ))) { - ql_dbg(ql_dbg_user, vha, 0x7022, - "State change notification not received.\n"); - } else - ql_dbg(ql_dbg_user, vha, 0x7023, - "State change received.\n"); - - ha->notify_dcbx_comp = 0; - -done_set_internal: - return rval; -} - -/* Set the port configuration to disable the - * internal loopback on ISP81XX - */ -static inline int -qla81xx_reset_internal_loopback(scsi_qla_host_t *vha, uint16_t *config, - int wait) -{ - int ret = 0; - int rval = 0; - uint16_t new_config[4]; - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) - goto done_reset_internal; - - memset(new_config, 0 , sizeof(new_config)); - if ((config[0] & INTERNAL_LOOPBACK_MASK) >> 1 == - ENABLE_INTERNAL_LOOPBACK) { - new_config[0] = config[0] & ~INTERNAL_LOOPBACK_MASK; - memcpy(&new_config[1], &config[1], sizeof(uint16_t) * 3) ; - - ha->notify_dcbx_comp = wait; - ret = qla81xx_set_port_config(vha, new_config); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7025, - "Set port config failed.\n"); - ha->notify_dcbx_comp = 0; - rval = -EINVAL; - goto done_reset_internal; - } - - /* Wait for DCBX complete event */ - if (wait && !wait_for_completion_timeout(&ha->dcbx_comp, - (20 * HZ))) { - ql_dbg(ql_dbg_user, vha, 0x7026, - "State change notification not received.\n"); - ha->notify_dcbx_comp = 0; - rval = -EINVAL; - goto done_reset_internal; - } else - ql_dbg(ql_dbg_user, vha, 0x7027, - "State change received.\n"); - - ha->notify_dcbx_comp = 0; - } -done_reset_internal: - return rval; -} - -static int -qla2x00_process_loopback(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int rval; - uint8_t command_sent; - char *type; - struct msg_echo_lb elreq; - uint16_t response[MAILBOX_REGISTER_COUNT]; - uint16_t config[4], new_config[4]; - uint8_t *fw_sts_ptr; - uint8_t *req_data = NULL; - dma_addr_t req_data_dma; - uint32_t req_data_len; - uint8_t *rsp_data = NULL; - dma_addr_t rsp_data_dma; - uint32_t rsp_data_len; - - if (!vha->flags.online) { - ql_log(ql_log_warn, vha, 0x7019, "Host is not online.\n"); - return -EIO; - } - - elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev, - bsg_job->request_payload.sg_list, bsg_job->request_payload.sg_cnt, - DMA_TO_DEVICE); - - if (!elreq.req_sg_cnt) { - ql_log(ql_log_warn, vha, 0x701a, - "dma_map_sg returned %d for request.\n", elreq.req_sg_cnt); - return -ENOMEM; - } - - elreq.rsp_sg_cnt = dma_map_sg(&ha->pdev->dev, - bsg_job->reply_payload.sg_list, bsg_job->reply_payload.sg_cnt, - DMA_FROM_DEVICE); - - if (!elreq.rsp_sg_cnt) { - ql_log(ql_log_warn, vha, 0x701b, - "dma_map_sg returned %d for reply.\n", elreq.rsp_sg_cnt); - rval = -ENOMEM; - goto done_unmap_req_sg; - } - - if ((elreq.req_sg_cnt != bsg_job->request_payload.sg_cnt) || - (elreq.rsp_sg_cnt != bsg_job->reply_payload.sg_cnt)) { - ql_log(ql_log_warn, vha, 0x701c, - "dma mapping resulted in different sg counts, " - "request_sg_cnt: %x dma_request_sg_cnt: %x " - "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n", - bsg_job->request_payload.sg_cnt, elreq.req_sg_cnt, - bsg_job->reply_payload.sg_cnt, elreq.rsp_sg_cnt); - rval = -EAGAIN; - goto done_unmap_sg; - } - req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; - req_data = dma_alloc_coherent(&ha->pdev->dev, req_data_len, - &req_data_dma, GFP_KERNEL); - if (!req_data) { - ql_log(ql_log_warn, vha, 0x701d, - "dma alloc failed for req_data.\n"); - rval = -ENOMEM; - goto done_unmap_sg; - } - - rsp_data = dma_alloc_coherent(&ha->pdev->dev, rsp_data_len, - &rsp_data_dma, GFP_KERNEL); - if (!rsp_data) { - ql_log(ql_log_warn, vha, 0x7004, - "dma alloc failed for rsp_data.\n"); - rval = -ENOMEM; - goto done_free_dma_req; - } - - /* Copy the request buffer in req_data now */ - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, req_data, req_data_len); - - elreq.send_dma = req_data_dma; - elreq.rcv_dma = rsp_data_dma; - elreq.transfer_size = req_data_len; - - elreq.options = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; - - if ((ha->current_topology == ISP_CFG_F || - (atomic_read(&vha->loop_state) == LOOP_DOWN) || - ((IS_QLA81XX(ha) || IS_QLA83XX(ha)) && - le32_to_cpu(*(uint32_t *)req_data) == ELS_OPCODE_BYTE - && req_data_len == MAX_ELS_FRAME_PAYLOAD)) && - elreq.options == EXTERNAL_LOOPBACK) { - type = "FC_BSG_HST_VENDOR_ECHO_DIAG"; - ql_dbg(ql_dbg_user, vha, 0x701e, - "BSG request type: %s.\n", type); - command_sent = INT_DEF_LB_ECHO_CMD; - rval = qla2x00_echo_test(vha, &elreq, response); - } else { - if (IS_QLA81XX(ha) || IS_QLA8031(ha)) { - memset(config, 0, sizeof(config)); - memset(new_config, 0, sizeof(new_config)); - if (qla81xx_get_port_config(vha, config)) { - ql_log(ql_log_warn, vha, 0x701f, - "Get port config failed.\n"); - bsg_job->reply->result = (DID_ERROR << 16); - rval = -EPERM; - goto done_free_dma_req; - } - - if (elreq.options != EXTERNAL_LOOPBACK) { - ql_dbg(ql_dbg_user, vha, 0x7020, - "Internal: current port config = %x\n", - config[0]); - if (qla81xx_set_internal_loopback(vha, config, - new_config)) { - ql_log(ql_log_warn, vha, 0x7024, - "Internal loopback failed.\n"); - bsg_job->reply->result = - (DID_ERROR << 16); - rval = -EPERM; - goto done_free_dma_req; - } - } else { - /* For external loopback to work - * ensure internal loopback is disabled - */ - if (qla81xx_reset_internal_loopback(vha, - config, 1)) { - bsg_job->reply->result = - (DID_ERROR << 16); - rval = -EPERM; - goto done_free_dma_req; - } - } - - type = "FC_BSG_HST_VENDOR_LOOPBACK"; - ql_dbg(ql_dbg_user, vha, 0x7028, - "BSG request type: %s.\n", type); - - command_sent = INT_DEF_LB_LOOPBACK_CMD; - rval = qla2x00_loopback_test(vha, &elreq, response); - - if (new_config[0]) { - /* Revert back to original port config - * Also clear internal loopback - */ - qla81xx_reset_internal_loopback(vha, - new_config, 0); - } - - if (response[0] == MBS_COMMAND_ERROR && - response[1] == MBS_LB_RESET) { - ql_log(ql_log_warn, vha, 0x7029, - "MBX command error, Aborting ISP.\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - qla2x00_wait_for_chip_reset(vha); - /* Also reset the MPI */ - if (qla81xx_restart_mpi_firmware(vha) != - QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x702a, - "MPI reset failed.\n"); - } - - bsg_job->reply->result = (DID_ERROR << 16); - rval = -EIO; - goto done_free_dma_req; - } - } else { - type = "FC_BSG_HST_VENDOR_LOOPBACK"; - ql_dbg(ql_dbg_user, vha, 0x702b, - "BSG request type: %s.\n", type); - command_sent = INT_DEF_LB_LOOPBACK_CMD; - rval = qla2x00_loopback_test(vha, &elreq, response); - } - } - - if (rval) { - ql_log(ql_log_warn, vha, 0x702c, - "Vendor request %s failed.\n", type); - - fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + - sizeof(struct fc_bsg_reply); - - memcpy(fw_sts_ptr, response, sizeof(response)); - fw_sts_ptr += sizeof(response); - *fw_sts_ptr = command_sent; - rval = 0; - bsg_job->reply->result = (DID_ERROR << 16); - } else { - ql_dbg(ql_dbg_user, vha, 0x702d, - "Vendor request %s completed.\n", type); - - bsg_job->reply_len = sizeof(struct fc_bsg_reply) + - sizeof(response) + sizeof(uint8_t); - bsg_job->reply->reply_payload_rcv_len = - bsg_job->reply_payload.payload_len; - fw_sts_ptr = ((uint8_t *)bsg_job->req->sense) + - sizeof(struct fc_bsg_reply); - memcpy(fw_sts_ptr, response, sizeof(response)); - fw_sts_ptr += sizeof(response); - *fw_sts_ptr = command_sent; - bsg_job->reply->result = DID_OK; - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, rsp_data, - rsp_data_len); - } - bsg_job->job_done(bsg_job); - - dma_free_coherent(&ha->pdev->dev, rsp_data_len, - rsp_data, rsp_data_dma); -done_free_dma_req: - dma_free_coherent(&ha->pdev->dev, req_data_len, - req_data, req_data_dma); -done_unmap_sg: - dma_unmap_sg(&ha->pdev->dev, - bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); -done_unmap_req_sg: - dma_unmap_sg(&ha->pdev->dev, - bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - return rval; -} - -static int -qla84xx_reset(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int rval = 0; - uint32_t flag; - - if (!IS_QLA84XX(ha)) { - ql_dbg(ql_dbg_user, vha, 0x702f, "Not 84xx, exiting.\n"); - return -EINVAL; - } - - flag = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; - - rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW); - - if (rval) { - ql_log(ql_log_warn, vha, 0x7030, - "Vendor request 84xx reset failed.\n"); - rval = 0; - bsg_job->reply->result = (DID_ERROR << 16); - - } else { - ql_dbg(ql_dbg_user, vha, 0x7031, - "Vendor request 84xx reset completed.\n"); - bsg_job->reply->result = DID_OK; - } - - bsg_job->job_done(bsg_job); - return rval; -} - -static int -qla84xx_updatefw(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - struct verify_chip_entry_84xx *mn = NULL; - dma_addr_t mn_dma, fw_dma; - void *fw_buf = NULL; - int rval = 0; - uint32_t sg_cnt; - uint32_t data_len; - uint16_t options; - uint32_t flag; - uint32_t fw_ver; - - if (!IS_QLA84XX(ha)) { - ql_dbg(ql_dbg_user, vha, 0x7032, - "Not 84xx, exiting.\n"); - return -EINVAL; - } - - sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - if (!sg_cnt) { - ql_log(ql_log_warn, vha, 0x7033, - "dma_map_sg returned %d for request.\n", sg_cnt); - return -ENOMEM; - } - - if (sg_cnt != bsg_job->request_payload.sg_cnt) { - ql_log(ql_log_warn, vha, 0x7034, - "DMA mapping resulted in different sg counts, " - "request_sg_cnt: %x dma_request_sg_cnt: %x.\n", - bsg_job->request_payload.sg_cnt, sg_cnt); - rval = -EAGAIN; - goto done_unmap_sg; - } - - data_len = bsg_job->request_payload.payload_len; - fw_buf = dma_alloc_coherent(&ha->pdev->dev, data_len, - &fw_dma, GFP_KERNEL); - if (!fw_buf) { - ql_log(ql_log_warn, vha, 0x7035, - "DMA alloc failed for fw_buf.\n"); - rval = -ENOMEM; - goto done_unmap_sg; - } - - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, fw_buf, data_len); - - mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); - if (!mn) { - ql_log(ql_log_warn, vha, 0x7036, - "DMA alloc failed for fw buffer.\n"); - rval = -ENOMEM; - goto done_free_fw_buf; - } - - flag = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; - fw_ver = le32_to_cpu(*((uint32_t *)((uint32_t *)fw_buf + 2))); - - memset(mn, 0, sizeof(struct access_chip_84xx)); - mn->entry_type = VERIFY_CHIP_IOCB_TYPE; - mn->entry_count = 1; - - options = VCO_FORCE_UPDATE | VCO_END_OF_DATA; - if (flag == A84_ISSUE_UPDATE_DIAGFW_CMD) - options |= VCO_DIAG_FW; - - mn->options = cpu_to_le16(options); - mn->fw_ver = cpu_to_le32(fw_ver); - mn->fw_size = cpu_to_le32(data_len); - mn->fw_seq_size = cpu_to_le32(data_len); - mn->dseg_address[0] = cpu_to_le32(LSD(fw_dma)); - mn->dseg_address[1] = cpu_to_le32(MSD(fw_dma)); - mn->dseg_length = cpu_to_le32(data_len); - mn->data_seg_cnt = cpu_to_le16(1); - - rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120); - - if (rval) { - ql_log(ql_log_warn, vha, 0x7037, - "Vendor request 84xx updatefw failed.\n"); - - rval = 0; - bsg_job->reply->result = (DID_ERROR << 16); - } else { - ql_dbg(ql_dbg_user, vha, 0x7038, - "Vendor request 84xx updatefw completed.\n"); - - bsg_job->reply_len = sizeof(struct fc_bsg_reply); - bsg_job->reply->result = DID_OK; - } - - bsg_job->job_done(bsg_job); - dma_pool_free(ha->s_dma_pool, mn, mn_dma); - -done_free_fw_buf: - dma_free_coherent(&ha->pdev->dev, data_len, fw_buf, fw_dma); - -done_unmap_sg: - dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - - return rval; -} - -static int -qla84xx_mgmt_cmd(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - struct access_chip_84xx *mn = NULL; - dma_addr_t mn_dma, mgmt_dma; - void *mgmt_b = NULL; - int rval = 0; - struct qla_bsg_a84_mgmt *ql84_mgmt; - uint32_t sg_cnt; - uint32_t data_len = 0; - uint32_t dma_direction = DMA_NONE; - - if (!IS_QLA84XX(ha)) { - ql_log(ql_log_warn, vha, 0x703a, - "Not 84xx, exiting.\n"); - return -EINVAL; - } - - ql84_mgmt = (struct qla_bsg_a84_mgmt *)((char *)bsg_job->request + - sizeof(struct fc_bsg_request)); - if (!ql84_mgmt) { - ql_log(ql_log_warn, vha, 0x703b, - "MGMT header not provided, exiting.\n"); - return -EINVAL; - } - - mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); - if (!mn) { - ql_log(ql_log_warn, vha, 0x703c, - "DMA alloc failed for fw buffer.\n"); - return -ENOMEM; - } - - memset(mn, 0, sizeof(struct access_chip_84xx)); - mn->entry_type = ACCESS_CHIP_IOCB_TYPE; - mn->entry_count = 1; - - switch (ql84_mgmt->mgmt.cmd) { - case QLA84_MGMT_READ_MEM: - case QLA84_MGMT_GET_INFO: - sg_cnt = dma_map_sg(&ha->pdev->dev, - bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - if (!sg_cnt) { - ql_log(ql_log_warn, vha, 0x703d, - "dma_map_sg returned %d for reply.\n", sg_cnt); - rval = -ENOMEM; - goto exit_mgmt; - } - - dma_direction = DMA_FROM_DEVICE; - - if (sg_cnt != bsg_job->reply_payload.sg_cnt) { - ql_log(ql_log_warn, vha, 0x703e, - "DMA mapping resulted in different sg counts, " - "reply_sg_cnt: %x dma_reply_sg_cnt: %x.\n", - bsg_job->reply_payload.sg_cnt, sg_cnt); - rval = -EAGAIN; - goto done_unmap_sg; - } - - data_len = bsg_job->reply_payload.payload_len; - - mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len, - &mgmt_dma, GFP_KERNEL); - if (!mgmt_b) { - ql_log(ql_log_warn, vha, 0x703f, - "DMA alloc failed for mgmt_b.\n"); - rval = -ENOMEM; - goto done_unmap_sg; - } - - if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) { - mn->options = cpu_to_le16(ACO_DUMP_MEMORY); - mn->parameter1 = - cpu_to_le32( - ql84_mgmt->mgmt.mgmtp.u.mem.start_addr); - - } else if (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO) { - mn->options = cpu_to_le16(ACO_REQUEST_INFO); - mn->parameter1 = - cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.info.type); - - mn->parameter2 = - cpu_to_le32( - ql84_mgmt->mgmt.mgmtp.u.info.context); - } - break; - - case QLA84_MGMT_WRITE_MEM: - sg_cnt = dma_map_sg(&ha->pdev->dev, - bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - - if (!sg_cnt) { - ql_log(ql_log_warn, vha, 0x7040, - "dma_map_sg returned %d.\n", sg_cnt); - rval = -ENOMEM; - goto exit_mgmt; - } - - dma_direction = DMA_TO_DEVICE; - - if (sg_cnt != bsg_job->request_payload.sg_cnt) { - ql_log(ql_log_warn, vha, 0x7041, - "DMA mapping resulted in different sg counts, " - "request_sg_cnt: %x dma_request_sg_cnt: %x.\n", - bsg_job->request_payload.sg_cnt, sg_cnt); - rval = -EAGAIN; - goto done_unmap_sg; - } - - data_len = bsg_job->request_payload.payload_len; - mgmt_b = dma_alloc_coherent(&ha->pdev->dev, data_len, - &mgmt_dma, GFP_KERNEL); - if (!mgmt_b) { - ql_log(ql_log_warn, vha, 0x7042, - "DMA alloc failed for mgmt_b.\n"); - rval = -ENOMEM; - goto done_unmap_sg; - } - - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, mgmt_b, data_len); - - mn->options = cpu_to_le16(ACO_LOAD_MEMORY); - mn->parameter1 = - cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.mem.start_addr); - break; - - case QLA84_MGMT_CHNG_CONFIG: - mn->options = cpu_to_le16(ACO_CHANGE_CONFIG_PARAM); - mn->parameter1 = - cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.id); - - mn->parameter2 = - cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param0); - - mn->parameter3 = - cpu_to_le32(ql84_mgmt->mgmt.mgmtp.u.config.param1); - break; - - default: - rval = -EIO; - goto exit_mgmt; - } - - if (ql84_mgmt->mgmt.cmd != QLA84_MGMT_CHNG_CONFIG) { - mn->total_byte_cnt = cpu_to_le32(ql84_mgmt->mgmt.len); - mn->dseg_count = cpu_to_le16(1); - mn->dseg_address[0] = cpu_to_le32(LSD(mgmt_dma)); - mn->dseg_address[1] = cpu_to_le32(MSD(mgmt_dma)); - mn->dseg_length = cpu_to_le32(ql84_mgmt->mgmt.len); - } - - rval = qla2x00_issue_iocb(vha, mn, mn_dma, 0); - - if (rval) { - ql_log(ql_log_warn, vha, 0x7043, - "Vendor request 84xx mgmt failed.\n"); - - rval = 0; - bsg_job->reply->result = (DID_ERROR << 16); - - } else { - ql_dbg(ql_dbg_user, vha, 0x7044, - "Vendor request 84xx mgmt completed.\n"); - - bsg_job->reply_len = sizeof(struct fc_bsg_reply); - bsg_job->reply->result = DID_OK; - - if ((ql84_mgmt->mgmt.cmd == QLA84_MGMT_READ_MEM) || - (ql84_mgmt->mgmt.cmd == QLA84_MGMT_GET_INFO)) { - bsg_job->reply->reply_payload_rcv_len = - bsg_job->reply_payload.payload_len; - - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, mgmt_b, - data_len); - } - } - - bsg_job->job_done(bsg_job); - -done_unmap_sg: - if (mgmt_b) - dma_free_coherent(&ha->pdev->dev, data_len, mgmt_b, mgmt_dma); - - if (dma_direction == DMA_TO_DEVICE) - dma_unmap_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE); - else if (dma_direction == DMA_FROM_DEVICE) - dma_unmap_sg(&ha->pdev->dev, bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, DMA_FROM_DEVICE); - -exit_mgmt: - dma_pool_free(ha->s_dma_pool, mn, mn_dma); - - return rval; -} - -static int -qla24xx_iidma(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - int rval = 0; - struct qla_port_param *port_param = NULL; - fc_port_t *fcport = NULL; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint8_t *rsp_ptr = NULL; - - if (!IS_IIDMA_CAPABLE(vha->hw)) { - ql_log(ql_log_info, vha, 0x7046, "iiDMA not supported.\n"); - return -EINVAL; - } - - port_param = (struct qla_port_param *)((char *)bsg_job->request + - sizeof(struct fc_bsg_request)); - if (!port_param) { - ql_log(ql_log_warn, vha, 0x7047, - "port_param header not provided.\n"); - return -EINVAL; - } - - if (port_param->fc_scsi_addr.dest_type != EXT_DEF_TYPE_WWPN) { - ql_log(ql_log_warn, vha, 0x7048, - "Invalid destination type.\n"); - return -EINVAL; - } - - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (fcport->port_type != FCT_TARGET) - continue; - - if (memcmp(port_param->fc_scsi_addr.dest_addr.wwpn, - fcport->port_name, sizeof(fcport->port_name))) - continue; - break; - } - - if (!fcport) { - ql_log(ql_log_warn, vha, 0x7049, - "Failed to find port.\n"); - return -EINVAL; - } - - if (atomic_read(&fcport->state) != FCS_ONLINE) { - ql_log(ql_log_warn, vha, 0x704a, - "Port is not online.\n"); - return -EINVAL; - } - - if (fcport->flags & FCF_LOGIN_NEEDED) { - ql_log(ql_log_warn, vha, 0x704b, - "Remote port not logged in flags = 0x%x.\n", fcport->flags); - return -EINVAL; - } - - if (port_param->mode) - rval = qla2x00_set_idma_speed(vha, fcport->loop_id, - port_param->speed, mb); - else - rval = qla2x00_get_idma_speed(vha, fcport->loop_id, - &port_param->speed, mb); - - if (rval) { - ql_log(ql_log_warn, vha, 0x704c, - "iIDMA cmd failed for %02x%02x%02x%02x%02x%02x%02x%02x -- " - "%04x %x %04x %04x.\n", fcport->port_name[0], - fcport->port_name[1], fcport->port_name[2], - fcport->port_name[3], fcport->port_name[4], - fcport->port_name[5], fcport->port_name[6], - fcport->port_name[7], rval, fcport->fp_speed, mb[0], mb[1]); - rval = 0; - bsg_job->reply->result = (DID_ERROR << 16); - - } else { - if (!port_param->mode) { - bsg_job->reply_len = sizeof(struct fc_bsg_reply) + - sizeof(struct qla_port_param); - - rsp_ptr = ((uint8_t *)bsg_job->reply) + - sizeof(struct fc_bsg_reply); - - memcpy(rsp_ptr, port_param, - sizeof(struct qla_port_param)); - } - - bsg_job->reply->result = DID_OK; - } - - bsg_job->job_done(bsg_job); - return rval; -} - -static int -qla2x00_optrom_setup(struct fc_bsg_job *bsg_job, scsi_qla_host_t *vha, - uint8_t is_update) -{ - uint32_t start = 0; - int valid = 0; - struct qla_hw_data *ha = vha->hw; - - if (unlikely(pci_channel_offline(ha->pdev))) - return -EINVAL; - - start = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; - if (start > ha->optrom_size) { - ql_log(ql_log_warn, vha, 0x7055, - "start %d > optrom_size %d.\n", start, ha->optrom_size); - return -EINVAL; - } - - if (ha->optrom_state != QLA_SWAITING) { - ql_log(ql_log_info, vha, 0x7056, - "optrom_state %d.\n", ha->optrom_state); - return -EBUSY; - } - - ha->optrom_region_start = start; - ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update); - if (is_update) { - if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0) - valid = 1; - else if (start == (ha->flt_region_boot * 4) || - start == (ha->flt_region_fw * 4)) - valid = 1; - else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || - IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) - valid = 1; - if (!valid) { - ql_log(ql_log_warn, vha, 0x7058, - "Invalid start region 0x%x/0x%x.\n", start, - bsg_job->request_payload.payload_len); - return -EINVAL; - } - - ha->optrom_region_size = start + - bsg_job->request_payload.payload_len > ha->optrom_size ? - ha->optrom_size - start : - bsg_job->request_payload.payload_len; - ha->optrom_state = QLA_SWRITING; - } else { - ha->optrom_region_size = start + - bsg_job->reply_payload.payload_len > ha->optrom_size ? - ha->optrom_size - start : - bsg_job->reply_payload.payload_len; - ha->optrom_state = QLA_SREADING; - } - - ha->optrom_buffer = vmalloc(ha->optrom_region_size); - if (!ha->optrom_buffer) { - ql_log(ql_log_warn, vha, 0x7059, - "Read: Unable to allocate memory for optrom retrieval " - "(%x)\n", ha->optrom_region_size); - - ha->optrom_state = QLA_SWAITING; - return -ENOMEM; - } - - memset(ha->optrom_buffer, 0, ha->optrom_region_size); - return 0; -} - -static int -qla2x00_read_optrom(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int rval = 0; - - if (ha->flags.isp82xx_reset_hdlr_active) - return -EBUSY; - - rval = qla2x00_optrom_setup(bsg_job, vha, 0); - if (rval) - return rval; - - ha->isp_ops->read_optrom(vha, ha->optrom_buffer, - ha->optrom_region_start, ha->optrom_region_size); - - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, ha->optrom_buffer, - ha->optrom_region_size); - - bsg_job->reply->reply_payload_rcv_len = ha->optrom_region_size; - bsg_job->reply->result = DID_OK; - vfree(ha->optrom_buffer); - ha->optrom_buffer = NULL; - ha->optrom_state = QLA_SWAITING; - bsg_job->job_done(bsg_job); - return rval; -} - -static int -qla2x00_update_optrom(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int rval = 0; - - rval = qla2x00_optrom_setup(bsg_job, vha, 1); - if (rval) - return rval; - - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, ha->optrom_buffer, - ha->optrom_region_size); - - ha->isp_ops->write_optrom(vha, ha->optrom_buffer, - ha->optrom_region_start, ha->optrom_region_size); - - bsg_job->reply->result = DID_OK; - vfree(ha->optrom_buffer); - ha->optrom_buffer = NULL; - ha->optrom_state = QLA_SWAITING; - bsg_job->job_done(bsg_job); - return rval; -} - -static int -qla2x00_update_fru_versions(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int rval = 0; - uint8_t bsg[DMA_POOL_SIZE]; - struct qla_image_version_list *list = (void *)bsg; - struct qla_image_version *image; - uint32_t count; - dma_addr_t sfp_dma; - void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); - if (!sfp) { - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = - EXT_STATUS_NO_MEMORY; - goto done; - } - - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, list, sizeof(bsg)); - - image = list->version; - count = list->count; - while (count--) { - memcpy(sfp, &image->field_info, sizeof(image->field_info)); - rval = qla2x00_write_sfp(vha, sfp_dma, sfp, - image->field_address.device, image->field_address.offset, - sizeof(image->field_info), image->field_address.option); - if (rval) { - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = - EXT_STATUS_MAILBOX; - goto dealloc; - } - image++; - } - - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = 0; - -dealloc: - dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); - -done: - bsg_job->reply_len = sizeof(struct fc_bsg_reply); - bsg_job->reply->result = DID_OK << 16; - bsg_job->job_done(bsg_job); - - return 0; -} - -static int -qla2x00_read_fru_status(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int rval = 0; - uint8_t bsg[DMA_POOL_SIZE]; - struct qla_status_reg *sr = (void *)bsg; - dma_addr_t sfp_dma; - uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); - if (!sfp) { - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = - EXT_STATUS_NO_MEMORY; - goto done; - } - - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, sr, sizeof(*sr)); - - rval = qla2x00_read_sfp(vha, sfp_dma, sfp, - sr->field_address.device, sr->field_address.offset, - sizeof(sr->status_reg), sr->field_address.option); - sr->status_reg = *sfp; - - if (rval) { - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = - EXT_STATUS_MAILBOX; - goto dealloc; - } - - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, sr, sizeof(*sr)); - - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = 0; - -dealloc: - dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); - -done: - bsg_job->reply_len = sizeof(struct fc_bsg_reply); - bsg_job->reply->reply_payload_rcv_len = sizeof(*sr); - bsg_job->reply->result = DID_OK << 16; - bsg_job->job_done(bsg_job); - - return 0; -} - -static int -qla2x00_write_fru_status(struct fc_bsg_job *bsg_job) -{ - struct Scsi_Host *host = bsg_job->shost; - scsi_qla_host_t *vha = shost_priv(host); - struct qla_hw_data *ha = vha->hw; - int rval = 0; - uint8_t bsg[DMA_POOL_SIZE]; - struct qla_status_reg *sr = (void *)bsg; - dma_addr_t sfp_dma; - uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma); - if (!sfp) { - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = - EXT_STATUS_NO_MEMORY; - goto done; - } - - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, sr, sizeof(*sr)); - - *sfp = sr->status_reg; - rval = qla2x00_write_sfp(vha, sfp_dma, sfp, - sr->field_address.device, sr->field_address.offset, - sizeof(sr->status_reg), sr->field_address.option); - - if (rval) { - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = - EXT_STATUS_MAILBOX; - goto dealloc; - } - - bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = 0; - -dealloc: - dma_pool_free(ha->s_dma_pool, sfp, sfp_dma); - -done: - bsg_job->reply_len = sizeof(struct fc_bsg_reply); - bsg_job->reply->result = DID_OK << 16; - bsg_job->job_done(bsg_job); - - return 0; -} - -static int -qla2x00_process_vendor_specific(struct fc_bsg_job *bsg_job) -{ - switch (bsg_job->request->rqst_data.h_vendor.vendor_cmd[0]) { - case QL_VND_LOOPBACK: - return qla2x00_process_loopback(bsg_job); - - case QL_VND_A84_RESET: - return qla84xx_reset(bsg_job); - - case QL_VND_A84_UPDATE_FW: - return qla84xx_updatefw(bsg_job); - - case QL_VND_A84_MGMT_CMD: - return qla84xx_mgmt_cmd(bsg_job); - - case QL_VND_IIDMA: - return qla24xx_iidma(bsg_job); - - case QL_VND_FCP_PRIO_CFG_CMD: - return qla24xx_proc_fcp_prio_cfg_cmd(bsg_job); - - case QL_VND_READ_FLASH: - return qla2x00_read_optrom(bsg_job); - - case QL_VND_UPDATE_FLASH: - return qla2x00_update_optrom(bsg_job); - - case QL_VND_SET_FRU_VERSION: - return qla2x00_update_fru_versions(bsg_job); - - case QL_VND_READ_FRU_STATUS: - return qla2x00_read_fru_status(bsg_job); - - case QL_VND_WRITE_FRU_STATUS: - return qla2x00_write_fru_status(bsg_job); - - default: - bsg_job->reply->result = (DID_ERROR << 16); - bsg_job->job_done(bsg_job); - return -ENOSYS; - } -} - -int -qla24xx_bsg_request(struct fc_bsg_job *bsg_job) -{ - int ret = -EINVAL; - struct fc_rport *rport; - fc_port_t *fcport = NULL; - struct Scsi_Host *host; - scsi_qla_host_t *vha; - - /* In case no data transferred. */ - bsg_job->reply->reply_payload_rcv_len = 0; - - if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { - rport = bsg_job->rport; - fcport = *(fc_port_t **) rport->dd_data; - host = rport_to_shost(rport); - vha = shost_priv(host); - } else { - host = bsg_job->shost; - vha = shost_priv(host); - } - - if (qla2x00_reset_active(vha)) { - ql_dbg(ql_dbg_user, vha, 0x709f, - "BSG: ISP abort active/needed -- cmd=%d.\n", - bsg_job->request->msgcode); - bsg_job->reply->result = (DID_ERROR << 16); - bsg_job->job_done(bsg_job); - return -EBUSY; - } - - ql_dbg(ql_dbg_user, vha, 0x7000, - "Entered %s msgcode=0x%x.\n", __func__, bsg_job->request->msgcode); - - switch (bsg_job->request->msgcode) { - case FC_BSG_RPT_ELS: - case FC_BSG_HST_ELS_NOLOGIN: - ret = qla2x00_process_els(bsg_job); - break; - case FC_BSG_HST_CT: - ret = qla2x00_process_ct(bsg_job); - break; - case FC_BSG_HST_VENDOR: - ret = qla2x00_process_vendor_specific(bsg_job); - break; - case FC_BSG_HST_ADD_RPORT: - case FC_BSG_HST_DEL_RPORT: - case FC_BSG_RPT_CT: - default: - ql_log(ql_log_warn, vha, 0x705a, "Unsupported BSG request.\n"); - bsg_job->reply->result = ret; - break; - } - return ret; -} - -int -qla24xx_bsg_timeout(struct fc_bsg_job *bsg_job) -{ - scsi_qla_host_t *vha = shost_priv(bsg_job->shost); - struct qla_hw_data *ha = vha->hw; - srb_t *sp; - int cnt, que; - unsigned long flags; - struct req_que *req; - - /* find the bsg job from the active list of commands */ - spin_lock_irqsave(&ha->hardware_lock, flags); - for (que = 0; que < ha->max_req_queues; que++) { - req = ha->req_q_map[que]; - if (!req) - continue; - - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (sp) { - if (((sp->type == SRB_CT_CMD) || - (sp->type == SRB_ELS_CMD_HST)) - && (sp->u.bsg_job == bsg_job)) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (ha->isp_ops->abort_command(sp)) { - ql_log(ql_log_warn, vha, 0x7089, - "mbx abort_command " - "failed.\n"); - bsg_job->req->errors = - bsg_job->reply->result = -EIO; - } else { - ql_dbg(ql_dbg_user, vha, 0x708a, - "mbx abort_command " - "success.\n"); - bsg_job->req->errors = - bsg_job->reply->result = 0; - } - spin_lock_irqsave(&ha->hardware_lock, flags); - goto done; - } - } - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - ql_log(ql_log_info, vha, 0x708b, "SRB not found to abort.\n"); - bsg_job->req->errors = bsg_job->reply->result = -ENXIO; - return 0; - -done: - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (bsg_job->request->msgcode == FC_BSG_HST_CT) - kfree(sp->fcport); - mempool_free(sp, ha->srb_mempool); - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.h deleted file mode 100644 index 70caa63a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_bsg.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#ifndef __QLA_BSG_H -#define __QLA_BSG_H - -/* BSG Vendor specific commands */ -#define QL_VND_LOOPBACK 0x01 -#define QL_VND_A84_RESET 0x02 -#define QL_VND_A84_UPDATE_FW 0x03 -#define QL_VND_A84_MGMT_CMD 0x04 -#define QL_VND_IIDMA 0x05 -#define QL_VND_FCP_PRIO_CFG_CMD 0x06 -#define QL_VND_READ_FLASH 0x07 -#define QL_VND_UPDATE_FLASH 0x08 -#define QL_VND_SET_FRU_VERSION 0x0B -#define QL_VND_READ_FRU_STATUS 0x0C -#define QL_VND_WRITE_FRU_STATUS 0x0D - -/* BSG Vendor specific subcode returns */ -#define EXT_STATUS_OK 0 -#define EXT_STATUS_ERR 1 -#define EXT_STATUS_INVALID_PARAM 6 -#define EXT_STATUS_MAILBOX 11 -#define EXT_STATUS_NO_MEMORY 17 - -/* BSG definations for interpreting CommandSent field */ -#define INT_DEF_LB_LOOPBACK_CMD 0 -#define INT_DEF_LB_ECHO_CMD 1 - -/* Loopback related definations */ -#define EXTERNAL_LOOPBACK 0xF2 -#define ENABLE_INTERNAL_LOOPBACK 0x02 -#define INTERNAL_LOOPBACK_MASK 0x000E -#define MAX_ELS_FRAME_PAYLOAD 252 -#define ELS_OPCODE_BYTE 0x10 - -/* BSG Vendor specific definations */ -#define A84_ISSUE_WRITE_TYPE_CMD 0 -#define A84_ISSUE_READ_TYPE_CMD 1 -#define A84_CLEANUP_CMD 2 -#define A84_ISSUE_RESET_OP_FW 3 -#define A84_ISSUE_RESET_DIAG_FW 4 -#define A84_ISSUE_UPDATE_OPFW_CMD 5 -#define A84_ISSUE_UPDATE_DIAGFW_CMD 6 - -struct qla84_mgmt_param { - union { - struct { - uint32_t start_addr; - } mem; /* for QLA84_MGMT_READ/WRITE_MEM */ - struct { - uint32_t id; -#define QLA84_MGMT_CONFIG_ID_UIF 1 -#define QLA84_MGMT_CONFIG_ID_FCOE_COS 2 -#define QLA84_MGMT_CONFIG_ID_PAUSE 3 -#define QLA84_MGMT_CONFIG_ID_TIMEOUTS 4 - - uint32_t param0; - uint32_t param1; - } config; /* for QLA84_MGMT_CHNG_CONFIG */ - - struct { - uint32_t type; -#define QLA84_MGMT_INFO_CONFIG_LOG_DATA 1 /* Get Config Log Data */ -#define QLA84_MGMT_INFO_LOG_DATA 2 /* Get Log Data */ -#define QLA84_MGMT_INFO_PORT_STAT 3 /* Get Port Statistics */ -#define QLA84_MGMT_INFO_LIF_STAT 4 /* Get LIF Statistics */ -#define QLA84_MGMT_INFO_ASIC_STAT 5 /* Get ASIC Statistics */ -#define QLA84_MGMT_INFO_CONFIG_PARAMS 6 /* Get Config Parameters */ -#define QLA84_MGMT_INFO_PANIC_LOG 7 /* Get Panic Log */ - - uint32_t context; -/* -* context definitions for QLA84_MGMT_INFO_CONFIG_LOG_DATA -*/ -#define IC_LOG_DATA_LOG_ID_DEBUG_LOG 0 -#define IC_LOG_DATA_LOG_ID_LEARN_LOG 1 -#define IC_LOG_DATA_LOG_ID_FC_ACL_INGRESS_LOG 2 -#define IC_LOG_DATA_LOG_ID_FC_ACL_EGRESS_LOG 3 -#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_INGRESS_LOG 4 -#define IC_LOG_DATA_LOG_ID_ETHERNET_ACL_EGRESS_LOG 5 -#define IC_LOG_DATA_LOG_ID_MESSAGE_TRANSMIT_LOG 6 -#define IC_LOG_DATA_LOG_ID_MESSAGE_RECEIVE_LOG 7 -#define IC_LOG_DATA_LOG_ID_LINK_EVENT_LOG 8 -#define IC_LOG_DATA_LOG_ID_DCX_LOG 9 - -/* -* context definitions for QLA84_MGMT_INFO_PORT_STAT -*/ -#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT0 0 -#define IC_PORT_STATISTICS_PORT_NUMBER_ETHERNET_PORT1 1 -#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT0 2 -#define IC_PORT_STATISTICS_PORT_NUMBER_NSL_PORT1 3 -#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT0 4 -#define IC_PORT_STATISTICS_PORT_NUMBER_FC_PORT1 5 - - -/* -* context definitions for QLA84_MGMT_INFO_LIF_STAT -*/ -#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT0 0 -#define IC_LIF_STATISTICS_LIF_NUMBER_ETHERNET_PORT1 1 -#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT0 2 -#define IC_LIF_STATISTICS_LIF_NUMBER_FC_PORT1 3 -#define IC_LIF_STATISTICS_LIF_NUMBER_CPU 6 - - } info; /* for QLA84_MGMT_GET_INFO */ - } u; -}; - -struct qla84_msg_mgmt { - uint16_t cmd; -#define QLA84_MGMT_READ_MEM 0x00 -#define QLA84_MGMT_WRITE_MEM 0x01 -#define QLA84_MGMT_CHNG_CONFIG 0x02 -#define QLA84_MGMT_GET_INFO 0x03 - uint16_t rsrvd; - struct qla84_mgmt_param mgmtp;/* parameters for cmd */ - uint32_t len; /* bytes in payload following this struct */ - uint8_t payload[0]; /* payload for cmd */ -}; - -struct qla_bsg_a84_mgmt { - struct qla84_msg_mgmt mgmt; -} __attribute__ ((packed)); - -struct qla_scsi_addr { - uint16_t bus; - uint16_t target; -} __attribute__ ((packed)); - -struct qla_ext_dest_addr { - union { - uint8_t wwnn[8]; - uint8_t wwpn[8]; - uint8_t id[4]; - struct qla_scsi_addr scsi_addr; - } dest_addr; - uint16_t dest_type; -#define EXT_DEF_TYPE_WWPN 2 - uint16_t lun; - uint16_t padding[2]; -} __attribute__ ((packed)); - -struct qla_port_param { - struct qla_ext_dest_addr fc_scsi_addr; - uint16_t mode; - uint16_t speed; -} __attribute__ ((packed)); - - -/* FRU VPD */ - -#define MAX_FRU_SIZE 36 - -struct qla_field_address { - uint16_t offset; - uint16_t device; - uint16_t option; -} __packed; - -struct qla_field_info { - uint8_t version[MAX_FRU_SIZE]; -} __packed; - -struct qla_image_version { - struct qla_field_address field_address; - struct qla_field_info field_info; -} __packed; - -struct qla_image_version_list { - uint32_t count; - struct qla_image_version version[0]; -} __packed; - -struct qla_status_reg { - struct qla_field_address field_address; - uint8_t status_reg; - uint8_t reserved[7]; -} __packed; - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.c deleted file mode 100644 index 62324a1d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.c +++ /dev/null @@ -1,2495 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ - -/* - * Table for showing the current message id in use for particular level - * Change this table for addition of log/debug messages. - * ---------------------------------------------------------------------- - * | Level | Last Value Used | Holes | - * ---------------------------------------------------------------------- - * | Module Init and Probe | 0x0120 | 0x4b,0xba,0xfa | - * | Mailbox commands | 0x113e | 0x112c-0x112e | - * | | | 0x113a | - * | Device Discovery | 0x2086 | 0x2020-0x2022 | - * | Queue Command and IO tracing | 0x3030 | 0x3006,0x3008 | - * | | | 0x302d-0x302e | - * | DPC Thread | 0x401c | | - * | Async Events | 0x505d | 0x502b-0x502f | - * | | | 0x5047,0x5052 | - * | Timer Routines | 0x6011 | 0x600e-0x600f | - * | User Space Interactions | 0x709f | 0x7018,0x702e, | - * | | | 0x7039,0x7045, | - * | | | 0x7073-0x7075, | - * | | | 0x708c | - * | Task Management | 0x803c | 0x8025-0x8026 | - * | | | 0x800b,0x8039 | - * | AER/EEH | 0x900f | | - * | Virtual Port | 0xa007 | | - * | ISP82XX Specific | 0xb054 | 0xb053 | - * | MultiQ | 0xc00c | | - * | Misc | 0xd010 | | - * ---------------------------------------------------------------------- - */ - -#include "qla_def.h" - -#include - -static uint32_t ql_dbg_offset = 0x800; - -static inline void -qla2xxx_prep_dump(struct qla_hw_data *ha, struct qla2xxx_fw_dump *fw_dump) -{ - fw_dump->fw_major_version = htonl(ha->fw_major_version); - fw_dump->fw_minor_version = htonl(ha->fw_minor_version); - fw_dump->fw_subminor_version = htonl(ha->fw_subminor_version); - fw_dump->fw_attributes = htonl(ha->fw_attributes); - - fw_dump->vendor = htonl(ha->pdev->vendor); - fw_dump->device = htonl(ha->pdev->device); - fw_dump->subsystem_vendor = htonl(ha->pdev->subsystem_vendor); - fw_dump->subsystem_device = htonl(ha->pdev->subsystem_device); -} - -static inline void * -qla2xxx_copy_queues(struct qla_hw_data *ha, void *ptr) -{ - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; - /* Request queue. */ - memcpy(ptr, req->ring, req->length * - sizeof(request_t)); - - /* Response queue. */ - ptr += req->length * sizeof(request_t); - memcpy(ptr, rsp->ring, rsp->length * - sizeof(response_t)); - - return ptr + (rsp->length * sizeof(response_t)); -} - -static int -qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, - uint32_t ram_dwords, void **nxt) -{ - int rval; - uint32_t cnt, stat, timer, dwords, idx; - uint16_t mb0; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - dma_addr_t dump_dma = ha->gid_list_dma; - uint32_t *dump = (uint32_t *)ha->gid_list; - - rval = QLA_SUCCESS; - mb0 = 0; - - WRT_REG_WORD(®->mailbox0, MBC_DUMP_RISC_RAM_EXTENDED); - clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - - dwords = qla2x00_gid_list_size(ha) / 4; - for (cnt = 0; cnt < ram_dwords && rval == QLA_SUCCESS; - cnt += dwords, addr += dwords) { - if (cnt + dwords > ram_dwords) - dwords = ram_dwords - cnt; - - WRT_REG_WORD(®->mailbox1, LSW(addr)); - WRT_REG_WORD(®->mailbox8, MSW(addr)); - - WRT_REG_WORD(®->mailbox2, MSW(dump_dma)); - WRT_REG_WORD(®->mailbox3, LSW(dump_dma)); - WRT_REG_WORD(®->mailbox6, MSW(MSD(dump_dma))); - WRT_REG_WORD(®->mailbox7, LSW(MSD(dump_dma))); - - WRT_REG_WORD(®->mailbox4, MSW(dwords)); - WRT_REG_WORD(®->mailbox5, LSW(dwords)); - WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT); - - for (timer = 6000000; timer; timer--) { - /* Check for pending interrupts. */ - stat = RD_REG_DWORD(®->host_status); - if (stat & HSRX_RISC_INT) { - stat &= 0xff; - - if (stat == 0x1 || stat == 0x2 || - stat == 0x10 || stat == 0x11) { - set_bit(MBX_INTERRUPT, - &ha->mbx_cmd_flags); - - mb0 = RD_REG_WORD(®->mailbox0); - - WRT_REG_DWORD(®->hccr, - HCCRX_CLR_RISC_INT); - RD_REG_DWORD(®->hccr); - break; - } - - /* Clear this intr; it wasn't a mailbox intr */ - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - RD_REG_DWORD(®->hccr); - } - udelay(5); - } - - if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { - rval = mb0 & MBS_MASK; - for (idx = 0; idx < dwords; idx++) - ram[cnt + idx] = swab32(dump[idx]); - } else { - rval = QLA_FUNCTION_FAILED; - } - } - - *nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL; - return rval; -} - -static int -qla24xx_dump_memory(struct qla_hw_data *ha, uint32_t *code_ram, - uint32_t cram_size, void **nxt) -{ - int rval; - - /* Code RAM. */ - rval = qla24xx_dump_ram(ha, 0x20000, code_ram, cram_size / 4, nxt); - if (rval != QLA_SUCCESS) - return rval; - - /* External Memory. */ - return qla24xx_dump_ram(ha, 0x100000, *nxt, - ha->fw_memory_size - 0x100000 + 1, nxt); -} - -static uint32_t * -qla24xx_read_window(struct device_reg_24xx __iomem *reg, uint32_t iobase, - uint32_t count, uint32_t *buf) -{ - uint32_t __iomem *dmp_reg; - - WRT_REG_DWORD(®->iobase_addr, iobase); - dmp_reg = ®->iobase_window; - while (count--) - *buf++ = htonl(RD_REG_DWORD(dmp_reg++)); - - return buf; -} - -static inline int -qla24xx_pause_risc(struct device_reg_24xx __iomem *reg) -{ - int rval = QLA_SUCCESS; - uint32_t cnt; - - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - for (cnt = 30000; - ((RD_REG_DWORD(®->host_status) & HSRX_RISC_PAUSED) == 0) && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - - return rval; -} - -static int -qla24xx_soft_reset(struct qla_hw_data *ha) -{ - int rval = QLA_SUCCESS; - uint32_t cnt; - uint16_t mb0, wd; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Reset RISC. */ - WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_DWORD(®->ctrl_status) & CSRX_DMA_ACTIVE) == 0) - break; - - udelay(10); - } - - WRT_REG_DWORD(®->ctrl_status, - CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); - pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); - - udelay(100); - /* Wait for firmware to complete NVRAM accesses. */ - mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); - for (cnt = 10000 ; cnt && mb0; cnt--) { - udelay(5); - mb0 = (uint32_t) RD_REG_WORD(®->mailbox0); - barrier(); - } - - /* Wait for soft-reset to complete. */ - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_DWORD(®->ctrl_status) & - CSRX_ISP_SOFT_RESET) == 0) - break; - - udelay(10); - } - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - - for (cnt = 30000; RD_REG_WORD(®->mailbox0) != 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - - return rval; -} - -static int -qla2xxx_dump_ram(struct qla_hw_data *ha, uint32_t addr, uint16_t *ram, - uint32_t ram_words, void **nxt) -{ - int rval; - uint32_t cnt, stat, timer, words, idx; - uint16_t mb0; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - dma_addr_t dump_dma = ha->gid_list_dma; - uint16_t *dump = (uint16_t *)ha->gid_list; - - rval = QLA_SUCCESS; - mb0 = 0; - - WRT_MAILBOX_REG(ha, reg, 0, MBC_DUMP_RISC_RAM_EXTENDED); - clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - - words = qla2x00_gid_list_size(ha) / 2; - for (cnt = 0; cnt < ram_words && rval == QLA_SUCCESS; - cnt += words, addr += words) { - if (cnt + words > ram_words) - words = ram_words - cnt; - - WRT_MAILBOX_REG(ha, reg, 1, LSW(addr)); - WRT_MAILBOX_REG(ha, reg, 8, MSW(addr)); - - WRT_MAILBOX_REG(ha, reg, 2, MSW(dump_dma)); - WRT_MAILBOX_REG(ha, reg, 3, LSW(dump_dma)); - WRT_MAILBOX_REG(ha, reg, 6, MSW(MSD(dump_dma))); - WRT_MAILBOX_REG(ha, reg, 7, LSW(MSD(dump_dma))); - - WRT_MAILBOX_REG(ha, reg, 4, words); - WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); - - for (timer = 6000000; timer; timer--) { - /* Check for pending interrupts. */ - stat = RD_REG_DWORD(®->u.isp2300.host_status); - if (stat & HSR_RISC_INT) { - stat &= 0xff; - - if (stat == 0x1 || stat == 0x2) { - set_bit(MBX_INTERRUPT, - &ha->mbx_cmd_flags); - - mb0 = RD_MAILBOX_REG(ha, reg, 0); - - /* Release mailbox registers. */ - WRT_REG_WORD(®->semaphore, 0); - WRT_REG_WORD(®->hccr, - HCCR_CLR_RISC_INT); - RD_REG_WORD(®->hccr); - break; - } else if (stat == 0x10 || stat == 0x11) { - set_bit(MBX_INTERRUPT, - &ha->mbx_cmd_flags); - - mb0 = RD_MAILBOX_REG(ha, reg, 0); - - WRT_REG_WORD(®->hccr, - HCCR_CLR_RISC_INT); - RD_REG_WORD(®->hccr); - break; - } - - /* clear this intr; it wasn't a mailbox intr */ - WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); - RD_REG_WORD(®->hccr); - } - udelay(5); - } - - if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { - rval = mb0 & MBS_MASK; - for (idx = 0; idx < words; idx++) - ram[cnt + idx] = swab16(dump[idx]); - } else { - rval = QLA_FUNCTION_FAILED; - } - } - - *nxt = rval == QLA_SUCCESS ? &ram[cnt]: NULL; - return rval; -} - -static inline void -qla2xxx_read_window(struct device_reg_2xxx __iomem *reg, uint32_t count, - uint16_t *buf) -{ - uint16_t __iomem *dmp_reg = ®->u.isp2300.fb_cmd; - - while (count--) - *buf++ = htons(RD_REG_WORD(dmp_reg++)); -} - -static inline void * -qla24xx_copy_eft(struct qla_hw_data *ha, void *ptr) -{ - if (!ha->eft) - return ptr; - - memcpy(ptr, ha->eft, ntohl(ha->fw_dump->eft_size)); - return ptr + ntohl(ha->fw_dump->eft_size); -} - -static inline void * -qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) -{ - uint32_t cnt; - uint32_t *iter_reg; - struct qla2xxx_fce_chain *fcec = ptr; - - if (!ha->fce) - return ptr; - - *last_chain = &fcec->type; - fcec->type = __constant_htonl(DUMP_CHAIN_FCE); - fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) + - fce_calc_size(ha->fce_bufs)); - fcec->size = htonl(fce_calc_size(ha->fce_bufs)); - fcec->addr_l = htonl(LSD(ha->fce_dma)); - fcec->addr_h = htonl(MSD(ha->fce_dma)); - - iter_reg = fcec->eregs; - for (cnt = 0; cnt < 8; cnt++) - *iter_reg++ = htonl(ha->fce_mb[cnt]); - - memcpy(iter_reg, ha->fce, ntohl(fcec->size)); - - return (char *)iter_reg + ntohl(fcec->size); -} - -static inline void * -qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) -{ - struct qla2xxx_mqueue_chain *q; - struct qla2xxx_mqueue_header *qh; - struct req_que *req; - struct rsp_que *rsp; - int que; - - if (!ha->mqenable) - return ptr; - - /* Request queues */ - for (que = 1; que < ha->max_req_queues; que++) { - req = ha->req_q_map[que]; - if (!req) - break; - - /* Add chain. */ - q = ptr; - *last_chain = &q->type; - q->type = __constant_htonl(DUMP_CHAIN_QUEUE); - q->chain_size = htonl( - sizeof(struct qla2xxx_mqueue_chain) + - sizeof(struct qla2xxx_mqueue_header) + - (req->length * sizeof(request_t))); - ptr += sizeof(struct qla2xxx_mqueue_chain); - - /* Add header. */ - qh = ptr; - qh->queue = __constant_htonl(TYPE_REQUEST_QUEUE); - qh->number = htonl(que); - qh->size = htonl(req->length * sizeof(request_t)); - ptr += sizeof(struct qla2xxx_mqueue_header); - - /* Add data. */ - memcpy(ptr, req->ring, req->length * sizeof(request_t)); - ptr += req->length * sizeof(request_t); - } - - /* Response queues */ - for (que = 1; que < ha->max_rsp_queues; que++) { - rsp = ha->rsp_q_map[que]; - if (!rsp) - break; - - /* Add chain. */ - q = ptr; - *last_chain = &q->type; - q->type = __constant_htonl(DUMP_CHAIN_QUEUE); - q->chain_size = htonl( - sizeof(struct qla2xxx_mqueue_chain) + - sizeof(struct qla2xxx_mqueue_header) + - (rsp->length * sizeof(response_t))); - ptr += sizeof(struct qla2xxx_mqueue_chain); - - /* Add header. */ - qh = ptr; - qh->queue = __constant_htonl(TYPE_RESPONSE_QUEUE); - qh->number = htonl(que); - qh->size = htonl(rsp->length * sizeof(response_t)); - ptr += sizeof(struct qla2xxx_mqueue_header); - - /* Add data. */ - memcpy(ptr, rsp->ring, rsp->length * sizeof(response_t)); - ptr += rsp->length * sizeof(response_t); - } - - return ptr; -} - -static inline void * -qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) -{ - uint32_t cnt, que_idx; - uint8_t que_cnt; - struct qla2xxx_mq_chain *mq = ptr; - struct device_reg_25xxmq __iomem *reg; - - if (!ha->mqenable || IS_QLA83XX(ha)) - return ptr; - - mq = ptr; - *last_chain = &mq->type; - mq->type = __constant_htonl(DUMP_CHAIN_MQ); - mq->chain_size = __constant_htonl(sizeof(struct qla2xxx_mq_chain)); - - que_cnt = ha->max_req_queues > ha->max_rsp_queues ? - ha->max_req_queues : ha->max_rsp_queues; - mq->count = htonl(que_cnt); - for (cnt = 0; cnt < que_cnt; cnt++) { - reg = (struct device_reg_25xxmq *) ((void *) - ha->mqiobase + cnt * QLA_QUE_PAGE); - que_idx = cnt * 4; - mq->qregs[que_idx] = htonl(RD_REG_DWORD(®->req_q_in)); - mq->qregs[que_idx+1] = htonl(RD_REG_DWORD(®->req_q_out)); - mq->qregs[que_idx+2] = htonl(RD_REG_DWORD(®->rsp_q_in)); - mq->qregs[que_idx+3] = htonl(RD_REG_DWORD(®->rsp_q_out)); - } - - return ptr + sizeof(struct qla2xxx_mq_chain); -} - -void -qla2xxx_dump_post_process(scsi_qla_host_t *vha, int rval) -{ - struct qla_hw_data *ha = vha->hw; - - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0xd000, - "Failed to dump firmware (%x).\n", rval); - ha->fw_dumped = 0; - } else { - ql_log(ql_log_info, vha, 0xd001, - "Firmware dump saved to temp buffer (%ld/%p).\n", - vha->host_no, ha->fw_dump); - ha->fw_dumped = 1; - qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP); - } -} - -/** - * qla2300_fw_dump() - Dumps binary data from the 2300 firmware. - * @ha: HA context - * @hardware_locked: Called with the hardware_lock - */ -void -qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked) -{ - int rval; - uint32_t cnt; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - uint16_t __iomem *dmp_reg; - unsigned long flags; - struct qla2300_fw_dump *fw; - void *nxt; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - flags = 0; - - if (!hardware_locked) - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!ha->fw_dump) { - ql_log(ql_log_warn, vha, 0xd002, - "No buffer available for dump.\n"); - goto qla2300_fw_dump_failed; - } - - if (ha->fw_dumped) { - ql_log(ql_log_warn, vha, 0xd003, - "Firmware has been previously dumped (%p) " - "-- ignoring request.\n", - ha->fw_dump); - goto qla2300_fw_dump_failed; - } - fw = &ha->fw_dump->isp.isp23; - qla2xxx_prep_dump(ha, ha->fw_dump); - - rval = QLA_SUCCESS; - fw->hccr = htons(RD_REG_WORD(®->hccr)); - - /* Pause RISC. */ - WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); - if (IS_QLA2300(ha)) { - for (cnt = 30000; - (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - } else { - RD_REG_WORD(®->hccr); /* PCI Posting. */ - udelay(10); - } - - if (rval == QLA_SUCCESS) { - dmp_reg = ®->flash_address; - for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) - fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - - dmp_reg = ®->u.isp2300.req_q_in; - for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++) - fw->risc_host_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - - dmp_reg = ®->u.isp2300.mailbox0; - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - - WRT_REG_WORD(®->ctrl_status, 0x40); - qla2xxx_read_window(reg, 32, fw->resp_dma_reg); - - WRT_REG_WORD(®->ctrl_status, 0x50); - qla2xxx_read_window(reg, 48, fw->dma_reg); - - WRT_REG_WORD(®->ctrl_status, 0x00); - dmp_reg = ®->risc_hw; - for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) - fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - - WRT_REG_WORD(®->pcr, 0x2000); - qla2xxx_read_window(reg, 16, fw->risc_gp0_reg); - - WRT_REG_WORD(®->pcr, 0x2200); - qla2xxx_read_window(reg, 16, fw->risc_gp1_reg); - - WRT_REG_WORD(®->pcr, 0x2400); - qla2xxx_read_window(reg, 16, fw->risc_gp2_reg); - - WRT_REG_WORD(®->pcr, 0x2600); - qla2xxx_read_window(reg, 16, fw->risc_gp3_reg); - - WRT_REG_WORD(®->pcr, 0x2800); - qla2xxx_read_window(reg, 16, fw->risc_gp4_reg); - - WRT_REG_WORD(®->pcr, 0x2A00); - qla2xxx_read_window(reg, 16, fw->risc_gp5_reg); - - WRT_REG_WORD(®->pcr, 0x2C00); - qla2xxx_read_window(reg, 16, fw->risc_gp6_reg); - - WRT_REG_WORD(®->pcr, 0x2E00); - qla2xxx_read_window(reg, 16, fw->risc_gp7_reg); - - WRT_REG_WORD(®->ctrl_status, 0x10); - qla2xxx_read_window(reg, 64, fw->frame_buf_hdw_reg); - - WRT_REG_WORD(®->ctrl_status, 0x20); - qla2xxx_read_window(reg, 64, fw->fpm_b0_reg); - - WRT_REG_WORD(®->ctrl_status, 0x30); - qla2xxx_read_window(reg, 64, fw->fpm_b1_reg); - - /* Reset RISC. */ - WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_WORD(®->ctrl_status) & - CSR_ISP_SOFT_RESET) == 0) - break; - - udelay(10); - } - } - - if (!IS_QLA2300(ha)) { - for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - } - - /* Get RISC SRAM. */ - if (rval == QLA_SUCCESS) - rval = qla2xxx_dump_ram(ha, 0x800, fw->risc_ram, - sizeof(fw->risc_ram) / 2, &nxt); - - /* Get stack SRAM. */ - if (rval == QLA_SUCCESS) - rval = qla2xxx_dump_ram(ha, 0x10000, fw->stack_ram, - sizeof(fw->stack_ram) / 2, &nxt); - - /* Get data SRAM. */ - if (rval == QLA_SUCCESS) - rval = qla2xxx_dump_ram(ha, 0x11000, fw->data_ram, - ha->fw_memory_size - 0x11000 + 1, &nxt); - - if (rval == QLA_SUCCESS) - qla2xxx_copy_queues(ha, nxt); - - qla2xxx_dump_post_process(base_vha, rval); - -qla2300_fw_dump_failed: - if (!hardware_locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -/** - * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware. - * @ha: HA context - * @hardware_locked: Called with the hardware_lock - */ -void -qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked) -{ - int rval; - uint32_t cnt, timer; - uint16_t risc_address; - uint16_t mb0, mb2; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - uint16_t __iomem *dmp_reg; - unsigned long flags; - struct qla2100_fw_dump *fw; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - risc_address = 0; - mb0 = mb2 = 0; - flags = 0; - - if (!hardware_locked) - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!ha->fw_dump) { - ql_log(ql_log_warn, vha, 0xd004, - "No buffer available for dump.\n"); - goto qla2100_fw_dump_failed; - } - - if (ha->fw_dumped) { - ql_log(ql_log_warn, vha, 0xd005, - "Firmware has been previously dumped (%p) " - "-- ignoring request.\n", - ha->fw_dump); - goto qla2100_fw_dump_failed; - } - fw = &ha->fw_dump->isp.isp21; - qla2xxx_prep_dump(ha, ha->fw_dump); - - rval = QLA_SUCCESS; - fw->hccr = htons(RD_REG_WORD(®->hccr)); - - /* Pause RISC. */ - WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); - for (cnt = 30000; (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - if (rval == QLA_SUCCESS) { - dmp_reg = ®->flash_address; - for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) - fw->pbiu_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - - dmp_reg = ®->u.isp2100.mailbox0; - for (cnt = 0; cnt < ha->mbx_count; cnt++) { - if (cnt == 8) - dmp_reg = ®->u_end.isp2200.mailbox8; - - fw->mailbox_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - } - - dmp_reg = ®->u.isp2100.unused_2[0]; - for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) - fw->dma_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - - WRT_REG_WORD(®->ctrl_status, 0x00); - dmp_reg = ®->risc_hw; - for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) - fw->risc_hdw_reg[cnt] = htons(RD_REG_WORD(dmp_reg++)); - - WRT_REG_WORD(®->pcr, 0x2000); - qla2xxx_read_window(reg, 16, fw->risc_gp0_reg); - - WRT_REG_WORD(®->pcr, 0x2100); - qla2xxx_read_window(reg, 16, fw->risc_gp1_reg); - - WRT_REG_WORD(®->pcr, 0x2200); - qla2xxx_read_window(reg, 16, fw->risc_gp2_reg); - - WRT_REG_WORD(®->pcr, 0x2300); - qla2xxx_read_window(reg, 16, fw->risc_gp3_reg); - - WRT_REG_WORD(®->pcr, 0x2400); - qla2xxx_read_window(reg, 16, fw->risc_gp4_reg); - - WRT_REG_WORD(®->pcr, 0x2500); - qla2xxx_read_window(reg, 16, fw->risc_gp5_reg); - - WRT_REG_WORD(®->pcr, 0x2600); - qla2xxx_read_window(reg, 16, fw->risc_gp6_reg); - - WRT_REG_WORD(®->pcr, 0x2700); - qla2xxx_read_window(reg, 16, fw->risc_gp7_reg); - - WRT_REG_WORD(®->ctrl_status, 0x10); - qla2xxx_read_window(reg, 16, fw->frame_buf_hdw_reg); - - WRT_REG_WORD(®->ctrl_status, 0x20); - qla2xxx_read_window(reg, 64, fw->fpm_b0_reg); - - WRT_REG_WORD(®->ctrl_status, 0x30); - qla2xxx_read_window(reg, 64, fw->fpm_b1_reg); - - /* Reset the ISP. */ - WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); - } - - for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - - /* Pause RISC. */ - if (rval == QLA_SUCCESS && (IS_QLA2200(ha) || (IS_QLA2100(ha) && - (RD_REG_WORD(®->mctr) & (BIT_1 | BIT_0)) != 0))) { - - WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); - for (cnt = 30000; - (RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(100); - else - rval = QLA_FUNCTION_TIMEOUT; - } - if (rval == QLA_SUCCESS) { - /* Set memory configuration and timing. */ - if (IS_QLA2100(ha)) - WRT_REG_WORD(®->mctr, 0xf1); - else - WRT_REG_WORD(®->mctr, 0xf2); - RD_REG_WORD(®->mctr); /* PCI Posting. */ - - /* Release RISC. */ - WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); - } - } - - if (rval == QLA_SUCCESS) { - /* Get RISC SRAM. */ - risc_address = 0x1000; - WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD); - clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - } - for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS; - cnt++, risc_address++) { - WRT_MAILBOX_REG(ha, reg, 1, risc_address); - WRT_REG_WORD(®->hccr, HCCR_SET_HOST_INT); - - for (timer = 6000000; timer != 0; timer--) { - /* Check for pending interrupts. */ - if (RD_REG_WORD(®->istatus) & ISR_RISC_INT) { - if (RD_REG_WORD(®->semaphore) & BIT_0) { - set_bit(MBX_INTERRUPT, - &ha->mbx_cmd_flags); - - mb0 = RD_MAILBOX_REG(ha, reg, 0); - mb2 = RD_MAILBOX_REG(ha, reg, 2); - - WRT_REG_WORD(®->semaphore, 0); - WRT_REG_WORD(®->hccr, - HCCR_CLR_RISC_INT); - RD_REG_WORD(®->hccr); - break; - } - WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); - RD_REG_WORD(®->hccr); - } - udelay(5); - } - - if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) { - rval = mb0 & MBS_MASK; - fw->risc_ram[cnt] = htons(mb2); - } else { - rval = QLA_FUNCTION_FAILED; - } - } - - if (rval == QLA_SUCCESS) - qla2xxx_copy_queues(ha, &fw->risc_ram[cnt]); - - qla2xxx_dump_post_process(base_vha, rval); - -qla2100_fw_dump_failed: - if (!hardware_locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void -qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) -{ - int rval; - uint32_t cnt; - uint32_t risc_address; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - uint32_t __iomem *dmp_reg; - uint32_t *iter_reg; - uint16_t __iomem *mbx_reg; - unsigned long flags; - struct qla24xx_fw_dump *fw; - uint32_t ext_mem_cnt; - void *nxt; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - if (IS_QLA82XX(ha)) - return; - - risc_address = ext_mem_cnt = 0; - flags = 0; - - if (!hardware_locked) - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!ha->fw_dump) { - ql_log(ql_log_warn, vha, 0xd006, - "No buffer available for dump.\n"); - goto qla24xx_fw_dump_failed; - } - - if (ha->fw_dumped) { - ql_log(ql_log_warn, vha, 0xd007, - "Firmware has been previously dumped (%p) " - "-- ignoring request.\n", - ha->fw_dump); - goto qla24xx_fw_dump_failed; - } - fw = &ha->fw_dump->isp.isp24; - qla2xxx_prep_dump(ha, ha->fw_dump); - - fw->host_status = htonl(RD_REG_DWORD(®->host_status)); - - /* Pause RISC. */ - rval = qla24xx_pause_risc(reg); - if (rval != QLA_SUCCESS) - goto qla24xx_fw_dump_failed_0; - - /* Host interface registers. */ - dmp_reg = ®->flash_addr; - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Disable interrupts. */ - WRT_REG_DWORD(®->ictrl, 0); - RD_REG_DWORD(®->ictrl); - - /* Shadow registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_select, 0xB0000000); - fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0100000); - fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0200000); - fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0300000); - fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0400000); - fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0500000); - fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0600000); - fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - /* Mailbox registers. */ - mbx_reg = ®->mailbox0; - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); - - /* Transfer sequence registers. */ - iter_reg = fw->xseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg); - qla24xx_read_window(reg, 0xBF70, 16, iter_reg); - - qla24xx_read_window(reg, 0xBFE0, 16, fw->xseq_0_reg); - qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg); - - /* Receive sequence registers. */ - iter_reg = fw->rseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg); - qla24xx_read_window(reg, 0xFF70, 16, iter_reg); - - qla24xx_read_window(reg, 0xFFD0, 16, fw->rseq_0_reg); - qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg); - qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg); - - /* Command DMA registers. */ - qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg); - - /* Queues. */ - iter_reg = fw->req0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->resp0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->req1_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Transmit DMA registers. */ - iter_reg = fw->xmt0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg); - qla24xx_read_window(reg, 0x7610, 16, iter_reg); - - iter_reg = fw->xmt1_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg); - qla24xx_read_window(reg, 0x7630, 16, iter_reg); - - iter_reg = fw->xmt2_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg); - qla24xx_read_window(reg, 0x7650, 16, iter_reg); - - iter_reg = fw->xmt3_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg); - qla24xx_read_window(reg, 0x7670, 16, iter_reg); - - iter_reg = fw->xmt4_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg); - qla24xx_read_window(reg, 0x7690, 16, iter_reg); - - qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg); - - /* Receive DMA registers. */ - iter_reg = fw->rcvt0_data_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg); - qla24xx_read_window(reg, 0x7710, 16, iter_reg); - - iter_reg = fw->rcvt1_data_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg); - qla24xx_read_window(reg, 0x7730, 16, iter_reg); - - /* RISC registers. */ - iter_reg = fw->risc_gp_reg; - iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg); - qla24xx_read_window(reg, 0x0F70, 16, iter_reg); - - /* Local memory controller registers. */ - iter_reg = fw->lmc_reg; - iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg); - qla24xx_read_window(reg, 0x3060, 16, iter_reg); - - /* Fibre Protocol Module registers. */ - iter_reg = fw->fpm_hdw_reg; - iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg); - qla24xx_read_window(reg, 0x40B0, 16, iter_reg); - - /* Frame Buffer registers. */ - iter_reg = fw->fb_hdw_reg; - iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg); - qla24xx_read_window(reg, 0x61B0, 16, iter_reg); - - rval = qla24xx_soft_reset(ha); - if (rval != QLA_SUCCESS) - goto qla24xx_fw_dump_failed_0; - - rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram), - &nxt); - if (rval != QLA_SUCCESS) - goto qla24xx_fw_dump_failed_0; - - nxt = qla2xxx_copy_queues(ha, nxt); - - qla24xx_copy_eft(ha, nxt); - -qla24xx_fw_dump_failed_0: - qla2xxx_dump_post_process(base_vha, rval); - -qla24xx_fw_dump_failed: - if (!hardware_locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void -qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) -{ - int rval; - uint32_t cnt; - uint32_t risc_address; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - uint32_t __iomem *dmp_reg; - uint32_t *iter_reg; - uint16_t __iomem *mbx_reg; - unsigned long flags; - struct qla25xx_fw_dump *fw; - uint32_t ext_mem_cnt; - void *nxt, *nxt_chain; - uint32_t *last_chain = NULL; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - risc_address = ext_mem_cnt = 0; - flags = 0; - - if (!hardware_locked) - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!ha->fw_dump) { - ql_log(ql_log_warn, vha, 0xd008, - "No buffer available for dump.\n"); - goto qla25xx_fw_dump_failed; - } - - if (ha->fw_dumped) { - ql_log(ql_log_warn, vha, 0xd009, - "Firmware has been previously dumped (%p) " - "-- ignoring request.\n", - ha->fw_dump); - goto qla25xx_fw_dump_failed; - } - fw = &ha->fw_dump->isp.isp25; - qla2xxx_prep_dump(ha, ha->fw_dump); - ha->fw_dump->version = __constant_htonl(2); - - fw->host_status = htonl(RD_REG_DWORD(®->host_status)); - - /* Pause RISC. */ - rval = qla24xx_pause_risc(reg); - if (rval != QLA_SUCCESS) - goto qla25xx_fw_dump_failed_0; - - /* Host/Risc registers. */ - iter_reg = fw->host_risc_reg; - iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg); - qla24xx_read_window(reg, 0x7010, 16, iter_reg); - - /* PCIe registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x7C00); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_window, 0x01); - dmp_reg = ®->iobase_c4; - fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++)); - fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++)); - fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg)); - fw->pcie_regs[3] = htonl(RD_REG_DWORD(®->iobase_window)); - - WRT_REG_DWORD(®->iobase_window, 0x00); - RD_REG_DWORD(®->iobase_window); - - /* Host interface registers. */ - dmp_reg = ®->flash_addr; - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Disable interrupts. */ - WRT_REG_DWORD(®->ictrl, 0); - RD_REG_DWORD(®->ictrl); - - /* Shadow registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_select, 0xB0000000); - fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0100000); - fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0200000); - fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0300000); - fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0400000); - fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0500000); - fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0600000); - fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0700000); - fw->shadow_reg[7] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0800000); - fw->shadow_reg[8] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0900000); - fw->shadow_reg[9] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0A00000); - fw->shadow_reg[10] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - /* RISC I/O register. */ - WRT_REG_DWORD(®->iobase_addr, 0x0010); - fw->risc_io_reg = htonl(RD_REG_DWORD(®->iobase_window)); - - /* Mailbox registers. */ - mbx_reg = ®->mailbox0; - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); - - /* Transfer sequence registers. */ - iter_reg = fw->xseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg); - qla24xx_read_window(reg, 0xBF70, 16, iter_reg); - - iter_reg = fw->xseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg); - qla24xx_read_window(reg, 0xBFE0, 16, iter_reg); - - qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg); - - /* Receive sequence registers. */ - iter_reg = fw->rseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg); - qla24xx_read_window(reg, 0xFF70, 16, iter_reg); - - iter_reg = fw->rseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg); - qla24xx_read_window(reg, 0xFFD0, 16, iter_reg); - - qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg); - qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg); - - /* Auxiliary sequence registers. */ - iter_reg = fw->aseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg); - qla24xx_read_window(reg, 0xB070, 16, iter_reg); - - iter_reg = fw->aseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg); - qla24xx_read_window(reg, 0xB0D0, 16, iter_reg); - - qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg); - qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg); - - /* Command DMA registers. */ - qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg); - - /* Queues. */ - iter_reg = fw->req0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->resp0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->req1_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Transmit DMA registers. */ - iter_reg = fw->xmt0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg); - qla24xx_read_window(reg, 0x7610, 16, iter_reg); - - iter_reg = fw->xmt1_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg); - qla24xx_read_window(reg, 0x7630, 16, iter_reg); - - iter_reg = fw->xmt2_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg); - qla24xx_read_window(reg, 0x7650, 16, iter_reg); - - iter_reg = fw->xmt3_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg); - qla24xx_read_window(reg, 0x7670, 16, iter_reg); - - iter_reg = fw->xmt4_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg); - qla24xx_read_window(reg, 0x7690, 16, iter_reg); - - qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg); - - /* Receive DMA registers. */ - iter_reg = fw->rcvt0_data_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg); - qla24xx_read_window(reg, 0x7710, 16, iter_reg); - - iter_reg = fw->rcvt1_data_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg); - qla24xx_read_window(reg, 0x7730, 16, iter_reg); - - /* RISC registers. */ - iter_reg = fw->risc_gp_reg; - iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg); - qla24xx_read_window(reg, 0x0F70, 16, iter_reg); - - /* Local memory controller registers. */ - iter_reg = fw->lmc_reg; - iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg); - qla24xx_read_window(reg, 0x3070, 16, iter_reg); - - /* Fibre Protocol Module registers. */ - iter_reg = fw->fpm_hdw_reg; - iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg); - qla24xx_read_window(reg, 0x40B0, 16, iter_reg); - - /* Frame Buffer registers. */ - iter_reg = fw->fb_hdw_reg; - iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg); - qla24xx_read_window(reg, 0x6F00, 16, iter_reg); - - /* Multi queue registers */ - nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset, - &last_chain); - - rval = qla24xx_soft_reset(ha); - if (rval != QLA_SUCCESS) - goto qla25xx_fw_dump_failed_0; - - rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram), - &nxt); - if (rval != QLA_SUCCESS) - goto qla25xx_fw_dump_failed_0; - - nxt = qla2xxx_copy_queues(ha, nxt); - - nxt = qla24xx_copy_eft(ha, nxt); - - /* Chain entries -- started with MQ. */ - nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); - nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); - if (last_chain) { - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); - } - - /* Adjust valid length. */ - ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump); - -qla25xx_fw_dump_failed_0: - qla2xxx_dump_post_process(base_vha, rval); - -qla25xx_fw_dump_failed: - if (!hardware_locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void -qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) -{ - int rval; - uint32_t cnt; - uint32_t risc_address; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - uint32_t __iomem *dmp_reg; - uint32_t *iter_reg; - uint16_t __iomem *mbx_reg; - unsigned long flags; - struct qla81xx_fw_dump *fw; - uint32_t ext_mem_cnt; - void *nxt, *nxt_chain; - uint32_t *last_chain = NULL; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - risc_address = ext_mem_cnt = 0; - flags = 0; - - if (!hardware_locked) - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!ha->fw_dump) { - ql_log(ql_log_warn, vha, 0xd00a, - "No buffer available for dump.\n"); - goto qla81xx_fw_dump_failed; - } - - if (ha->fw_dumped) { - ql_log(ql_log_warn, vha, 0xd00b, - "Firmware has been previously dumped (%p) " - "-- ignoring request.\n", - ha->fw_dump); - goto qla81xx_fw_dump_failed; - } - fw = &ha->fw_dump->isp.isp81; - qla2xxx_prep_dump(ha, ha->fw_dump); - - fw->host_status = htonl(RD_REG_DWORD(®->host_status)); - - /* Pause RISC. */ - rval = qla24xx_pause_risc(reg); - if (rval != QLA_SUCCESS) - goto qla81xx_fw_dump_failed_0; - - /* Host/Risc registers. */ - iter_reg = fw->host_risc_reg; - iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg); - qla24xx_read_window(reg, 0x7010, 16, iter_reg); - - /* PCIe registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x7C00); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_window, 0x01); - dmp_reg = ®->iobase_c4; - fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++)); - fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++)); - fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg)); - fw->pcie_regs[3] = htonl(RD_REG_DWORD(®->iobase_window)); - - WRT_REG_DWORD(®->iobase_window, 0x00); - RD_REG_DWORD(®->iobase_window); - - /* Host interface registers. */ - dmp_reg = ®->flash_addr; - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Disable interrupts. */ - WRT_REG_DWORD(®->ictrl, 0); - RD_REG_DWORD(®->ictrl); - - /* Shadow registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_select, 0xB0000000); - fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0100000); - fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0200000); - fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0300000); - fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0400000); - fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0500000); - fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0600000); - fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0700000); - fw->shadow_reg[7] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0800000); - fw->shadow_reg[8] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0900000); - fw->shadow_reg[9] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0A00000); - fw->shadow_reg[10] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - /* RISC I/O register. */ - WRT_REG_DWORD(®->iobase_addr, 0x0010); - fw->risc_io_reg = htonl(RD_REG_DWORD(®->iobase_window)); - - /* Mailbox registers. */ - mbx_reg = ®->mailbox0; - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); - - /* Transfer sequence registers. */ - iter_reg = fw->xseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg); - qla24xx_read_window(reg, 0xBF70, 16, iter_reg); - - iter_reg = fw->xseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg); - qla24xx_read_window(reg, 0xBFE0, 16, iter_reg); - - qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg); - - /* Receive sequence registers. */ - iter_reg = fw->rseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg); - qla24xx_read_window(reg, 0xFF70, 16, iter_reg); - - iter_reg = fw->rseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg); - qla24xx_read_window(reg, 0xFFD0, 16, iter_reg); - - qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg); - qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg); - - /* Auxiliary sequence registers. */ - iter_reg = fw->aseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg); - qla24xx_read_window(reg, 0xB070, 16, iter_reg); - - iter_reg = fw->aseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg); - qla24xx_read_window(reg, 0xB0D0, 16, iter_reg); - - qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg); - qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg); - - /* Command DMA registers. */ - qla24xx_read_window(reg, 0x7100, 16, fw->cmd_dma_reg); - - /* Queues. */ - iter_reg = fw->req0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->resp0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->req1_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Transmit DMA registers. */ - iter_reg = fw->xmt0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg); - qla24xx_read_window(reg, 0x7610, 16, iter_reg); - - iter_reg = fw->xmt1_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg); - qla24xx_read_window(reg, 0x7630, 16, iter_reg); - - iter_reg = fw->xmt2_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg); - qla24xx_read_window(reg, 0x7650, 16, iter_reg); - - iter_reg = fw->xmt3_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg); - qla24xx_read_window(reg, 0x7670, 16, iter_reg); - - iter_reg = fw->xmt4_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg); - qla24xx_read_window(reg, 0x7690, 16, iter_reg); - - qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg); - - /* Receive DMA registers. */ - iter_reg = fw->rcvt0_data_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg); - qla24xx_read_window(reg, 0x7710, 16, iter_reg); - - iter_reg = fw->rcvt1_data_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg); - qla24xx_read_window(reg, 0x7730, 16, iter_reg); - - /* RISC registers. */ - iter_reg = fw->risc_gp_reg; - iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg); - qla24xx_read_window(reg, 0x0F70, 16, iter_reg); - - /* Local memory controller registers. */ - iter_reg = fw->lmc_reg; - iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg); - qla24xx_read_window(reg, 0x3070, 16, iter_reg); - - /* Fibre Protocol Module registers. */ - iter_reg = fw->fpm_hdw_reg; - iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40B0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40C0, 16, iter_reg); - qla24xx_read_window(reg, 0x40D0, 16, iter_reg); - - /* Frame Buffer registers. */ - iter_reg = fw->fb_hdw_reg; - iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x61C0, 16, iter_reg); - qla24xx_read_window(reg, 0x6F00, 16, iter_reg); - - /* Multi queue registers */ - nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset, - &last_chain); - - rval = qla24xx_soft_reset(ha); - if (rval != QLA_SUCCESS) - goto qla81xx_fw_dump_failed_0; - - rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram), - &nxt); - if (rval != QLA_SUCCESS) - goto qla81xx_fw_dump_failed_0; - - nxt = qla2xxx_copy_queues(ha, nxt); - - nxt = qla24xx_copy_eft(ha, nxt); - - /* Chain entries -- started with MQ. */ - nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); - nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); - if (last_chain) { - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); - } - - /* Adjust valid length. */ - ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump); - -qla81xx_fw_dump_failed_0: - qla2xxx_dump_post_process(base_vha, rval); - -qla81xx_fw_dump_failed: - if (!hardware_locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void -qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) -{ - int rval; - uint32_t cnt, reg_data; - uint32_t risc_address; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - uint32_t __iomem *dmp_reg; - uint32_t *iter_reg; - uint16_t __iomem *mbx_reg; - unsigned long flags; - struct qla83xx_fw_dump *fw; - uint32_t ext_mem_cnt; - void *nxt, *nxt_chain; - uint32_t *last_chain = NULL; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - risc_address = ext_mem_cnt = 0; - flags = 0; - - if (!hardware_locked) - spin_lock_irqsave(&ha->hardware_lock, flags); - - if (!ha->fw_dump) { - ql_log(ql_log_warn, vha, 0xd00c, - "No buffer available for dump!!!\n"); - goto qla83xx_fw_dump_failed; - } - - if (ha->fw_dumped) { - ql_log(ql_log_warn, vha, 0xd00d, - "Firmware has been previously dumped (%p) -- ignoring " - "request...\n", ha->fw_dump); - goto qla83xx_fw_dump_failed; - } - fw = &ha->fw_dump->isp.isp83; - qla2xxx_prep_dump(ha, ha->fw_dump); - - fw->host_status = htonl(RD_REG_DWORD(®->host_status)); - - /* Pause RISC. */ - rval = qla24xx_pause_risc(reg); - if (rval != QLA_SUCCESS) - goto qla83xx_fw_dump_failed_0; - - WRT_REG_DWORD(®->iobase_addr, 0x6000); - dmp_reg = ®->iobase_window; - reg_data = RD_REG_DWORD(dmp_reg); - WRT_REG_DWORD(dmp_reg, 0); - - dmp_reg = ®->unused_4_1[0]; - reg_data = RD_REG_DWORD(dmp_reg); - WRT_REG_DWORD(dmp_reg, 0); - - WRT_REG_DWORD(®->iobase_addr, 0x6010); - dmp_reg = ®->unused_4_1[2]; - reg_data = RD_REG_DWORD(dmp_reg); - WRT_REG_DWORD(dmp_reg, 0); - - /* select PCR and disable ecc checking and correction */ - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_select, 0x60000000); /* write to F0h = PCR */ - - /* Host/Risc registers. */ - iter_reg = fw->host_risc_reg; - iter_reg = qla24xx_read_window(reg, 0x7000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x7010, 16, iter_reg); - qla24xx_read_window(reg, 0x7040, 16, iter_reg); - - /* PCIe registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x7C00); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_window, 0x01); - dmp_reg = ®->iobase_c4; - fw->pcie_regs[0] = htonl(RD_REG_DWORD(dmp_reg++)); - fw->pcie_regs[1] = htonl(RD_REG_DWORD(dmp_reg++)); - fw->pcie_regs[2] = htonl(RD_REG_DWORD(dmp_reg)); - fw->pcie_regs[3] = htonl(RD_REG_DWORD(®->iobase_window)); - - WRT_REG_DWORD(®->iobase_window, 0x00); - RD_REG_DWORD(®->iobase_window); - - /* Host interface registers. */ - dmp_reg = ®->flash_addr; - for (cnt = 0; cnt < sizeof(fw->host_reg) / 4; cnt++) - fw->host_reg[cnt] = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Disable interrupts. */ - WRT_REG_DWORD(®->ictrl, 0); - RD_REG_DWORD(®->ictrl); - - /* Shadow registers. */ - WRT_REG_DWORD(®->iobase_addr, 0x0F70); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_select, 0xB0000000); - fw->shadow_reg[0] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0100000); - fw->shadow_reg[1] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0200000); - fw->shadow_reg[2] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0300000); - fw->shadow_reg[3] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0400000); - fw->shadow_reg[4] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0500000); - fw->shadow_reg[5] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0600000); - fw->shadow_reg[6] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0700000); - fw->shadow_reg[7] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0800000); - fw->shadow_reg[8] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0900000); - fw->shadow_reg[9] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - WRT_REG_DWORD(®->iobase_select, 0xB0A00000); - fw->shadow_reg[10] = htonl(RD_REG_DWORD(®->iobase_sdata)); - - /* RISC I/O register. */ - WRT_REG_DWORD(®->iobase_addr, 0x0010); - fw->risc_io_reg = htonl(RD_REG_DWORD(®->iobase_window)); - - /* Mailbox registers. */ - mbx_reg = ®->mailbox0; - for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) - fw->mailbox_reg[cnt] = htons(RD_REG_WORD(mbx_reg++)); - - /* Transfer sequence registers. */ - iter_reg = fw->xseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xBE00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBE10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBE20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBE30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBE40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBE50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBE60, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBE70, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBF60, 16, iter_reg); - qla24xx_read_window(reg, 0xBF70, 16, iter_reg); - - iter_reg = fw->xseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xBFC0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xBFD0, 16, iter_reg); - qla24xx_read_window(reg, 0xBFE0, 16, iter_reg); - - qla24xx_read_window(reg, 0xBFF0, 16, fw->xseq_1_reg); - - qla24xx_read_window(reg, 0xBEF0, 16, fw->xseq_2_reg); - - /* Receive sequence registers. */ - iter_reg = fw->rseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xFE00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFE10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFE20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFE30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFE40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFE50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFE60, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFE70, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xFF60, 16, iter_reg); - qla24xx_read_window(reg, 0xFF70, 16, iter_reg); - - iter_reg = fw->rseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xFFC0, 16, iter_reg); - qla24xx_read_window(reg, 0xFFD0, 16, iter_reg); - - qla24xx_read_window(reg, 0xFFE0, 16, fw->rseq_1_reg); - qla24xx_read_window(reg, 0xFFF0, 16, fw->rseq_2_reg); - qla24xx_read_window(reg, 0xFEF0, 16, fw->rseq_3_reg); - - /* Auxiliary sequence registers. */ - iter_reg = fw->aseq_gp_reg; - iter_reg = qla24xx_read_window(reg, 0xB000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB060, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB070, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB100, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB110, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB120, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB130, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB140, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB150, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0xB160, 16, iter_reg); - qla24xx_read_window(reg, 0xB170, 16, iter_reg); - - iter_reg = fw->aseq_0_reg; - iter_reg = qla24xx_read_window(reg, 0xB0C0, 16, iter_reg); - qla24xx_read_window(reg, 0xB0D0, 16, iter_reg); - - qla24xx_read_window(reg, 0xB0E0, 16, fw->aseq_1_reg); - qla24xx_read_window(reg, 0xB0F0, 16, fw->aseq_2_reg); - qla24xx_read_window(reg, 0xB1F0, 16, fw->aseq_3_reg); - - /* Command DMA registers. */ - iter_reg = fw->cmd_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7100, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x7120, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x7130, 16, iter_reg); - qla24xx_read_window(reg, 0x71F0, 16, iter_reg); - - /* Queues. */ - iter_reg = fw->req0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7200, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->resp0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7300, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - iter_reg = fw->req1_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7400, 8, iter_reg); - dmp_reg = ®->iobase_q; - for (cnt = 0; cnt < 7; cnt++) - *iter_reg++ = htonl(RD_REG_DWORD(dmp_reg++)); - - /* Transmit DMA registers. */ - iter_reg = fw->xmt0_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7600, 16, iter_reg); - qla24xx_read_window(reg, 0x7610, 16, iter_reg); - - iter_reg = fw->xmt1_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7620, 16, iter_reg); - qla24xx_read_window(reg, 0x7630, 16, iter_reg); - - iter_reg = fw->xmt2_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7640, 16, iter_reg); - qla24xx_read_window(reg, 0x7650, 16, iter_reg); - - iter_reg = fw->xmt3_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7660, 16, iter_reg); - qla24xx_read_window(reg, 0x7670, 16, iter_reg); - - iter_reg = fw->xmt4_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7680, 16, iter_reg); - qla24xx_read_window(reg, 0x7690, 16, iter_reg); - - qla24xx_read_window(reg, 0x76A0, 16, fw->xmt_data_dma_reg); - - /* Receive DMA registers. */ - iter_reg = fw->rcvt0_data_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7700, 16, iter_reg); - qla24xx_read_window(reg, 0x7710, 16, iter_reg); - - iter_reg = fw->rcvt1_data_dma_reg; - iter_reg = qla24xx_read_window(reg, 0x7720, 16, iter_reg); - qla24xx_read_window(reg, 0x7730, 16, iter_reg); - - /* RISC registers. */ - iter_reg = fw->risc_gp_reg; - iter_reg = qla24xx_read_window(reg, 0x0F00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x0F60, 16, iter_reg); - qla24xx_read_window(reg, 0x0F70, 16, iter_reg); - - /* Local memory controller registers. */ - iter_reg = fw->lmc_reg; - iter_reg = qla24xx_read_window(reg, 0x3000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x3060, 16, iter_reg); - qla24xx_read_window(reg, 0x3070, 16, iter_reg); - - /* Fibre Protocol Module registers. */ - iter_reg = fw->fpm_hdw_reg; - iter_reg = qla24xx_read_window(reg, 0x4000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4050, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4060, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4070, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4080, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x4090, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40A0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40B0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40C0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40D0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x40E0, 16, iter_reg); - qla24xx_read_window(reg, 0x40F0, 16, iter_reg); - - /* RQ0 Array registers. */ - iter_reg = fw->rq0_array_reg; - iter_reg = qla24xx_read_window(reg, 0x5C00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C60, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C70, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C80, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5C90, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5CA0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5CB0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5CC0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5CD0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5CE0, 16, iter_reg); - qla24xx_read_window(reg, 0x5CF0, 16, iter_reg); - - /* RQ1 Array registers. */ - iter_reg = fw->rq1_array_reg; - iter_reg = qla24xx_read_window(reg, 0x5D00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D60, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D70, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D80, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5D90, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5DA0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5DB0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5DC0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5DD0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5DE0, 16, iter_reg); - qla24xx_read_window(reg, 0x5DF0, 16, iter_reg); - - /* RP0 Array registers. */ - iter_reg = fw->rp0_array_reg; - iter_reg = qla24xx_read_window(reg, 0x5E00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E60, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E70, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E80, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5E90, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5EA0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5EB0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5EC0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5ED0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5EE0, 16, iter_reg); - qla24xx_read_window(reg, 0x5EF0, 16, iter_reg); - - /* RP1 Array registers. */ - iter_reg = fw->rp1_array_reg; - iter_reg = qla24xx_read_window(reg, 0x5F00, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F10, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F20, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F30, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F40, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F50, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F60, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F70, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F80, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5F90, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5FA0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5FB0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5FC0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5FD0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x5FE0, 16, iter_reg); - qla24xx_read_window(reg, 0x5FF0, 16, iter_reg); - - iter_reg = fw->at0_array_reg; - iter_reg = qla24xx_read_window(reg, 0x7080, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x7090, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x70A0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x70B0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x70C0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x70D0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x70E0, 16, iter_reg); - qla24xx_read_window(reg, 0x70F0, 16, iter_reg); - - /* I/O Queue Control registers. */ - qla24xx_read_window(reg, 0x7800, 16, fw->queue_control_reg); - - /* Frame Buffer registers. */ - iter_reg = fw->fb_hdw_reg; - iter_reg = qla24xx_read_window(reg, 0x6000, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6010, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6020, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6030, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6040, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6060, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6070, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6100, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6130, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6150, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6170, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6190, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x61B0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x61C0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6530, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6540, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6550, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6560, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6570, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6580, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x6590, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x65A0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x65B0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x65C0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x65D0, 16, iter_reg); - iter_reg = qla24xx_read_window(reg, 0x65E0, 16, iter_reg); - qla24xx_read_window(reg, 0x6F00, 16, iter_reg); - - /* Multi queue registers */ - nxt_chain = qla25xx_copy_mq(ha, (void *)ha->fw_dump + ha->chain_offset, - &last_chain); - - rval = qla24xx_soft_reset(ha); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0xd00e, - "SOFT RESET FAILED, forcing continuation of dump!!!\n"); - rval = QLA_SUCCESS; - - ql_log(ql_log_warn, vha, 0xd00f, "try a bigger hammer!!!\n"); - - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); - RD_REG_DWORD(®->hccr); - - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); - - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); - RD_REG_DWORD(®->hccr); - - for (cnt = 30000; cnt && (RD_REG_WORD(®->mailbox0)); cnt--) - udelay(5); - - if (!cnt) { - nxt = fw->code_ram; - nxt += sizeof(fw->code_ram), - nxt += (ha->fw_memory_size - 0x100000 + 1); - goto copy_queue; - } else - ql_log(ql_log_warn, vha, 0xd010, - "bigger hammer success?\n"); - } - - rval = qla24xx_dump_memory(ha, fw->code_ram, sizeof(fw->code_ram), - &nxt); - if (rval != QLA_SUCCESS) - goto qla83xx_fw_dump_failed_0; - -copy_queue: - nxt = qla2xxx_copy_queues(ha, nxt); - - nxt = qla24xx_copy_eft(ha, nxt); - - /* Chain entries -- started with MQ. */ - nxt_chain = qla25xx_copy_fce(ha, nxt_chain, &last_chain); - nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); - if (last_chain) { - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); - } - - /* Adjust valid length. */ - ha->fw_dump_len = (nxt_chain - (void *)ha->fw_dump); - -qla83xx_fw_dump_failed_0: - qla2xxx_dump_post_process(base_vha, rval); - -qla83xx_fw_dump_failed: - if (!hardware_locked) - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -/****************************************************************************/ -/* Driver Debug Functions. */ -/****************************************************************************/ - -static inline int -ql_mask_match(uint32_t level) -{ - if (ql2xextended_error_logging == 1) - ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK; - return (level & ql2xextended_error_logging) == level; -} - -/* - * This function is for formatting and logging debug information. - * It is to be used when vha is available. It formats the message - * and logs it to the messages file. - * parameters: - * level: The level of the debug messages to be printed. - * If ql2xextended_error_logging value is correctly set, - * this message will appear in the messages file. - * vha: Pointer to the scsi_qla_host_t. - * id: This is a unique identifier for the level. It identifies the - * part of the code from where the message originated. - * msg: The message to be displayed. - */ -void -ql_dbg(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...) -{ - va_list va; - struct va_format vaf; - - if (!ql_mask_match(level)) - return; - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - if (vha != NULL) { - const struct pci_dev *pdev = vha->hw->pdev; - /* : Message */ - pr_warn("%s [%s]-%04x:%ld: %pV", - QL_MSGHDR, dev_name(&(pdev->dev)), id + ql_dbg_offset, - vha->host_no, &vaf); - } else { - pr_warn("%s [%s]-%04x: : %pV", - QL_MSGHDR, "0000:00:00.0", id + ql_dbg_offset, &vaf); - } - - va_end(va); - -} - -/* - * This function is for formatting and logging debug information. - * It is to be used when vha is not available and pci is availble, - * i.e., before host allocation. It formats the message and logs it - * to the messages file. - * parameters: - * level: The level of the debug messages to be printed. - * If ql2xextended_error_logging value is correctly set, - * this message will appear in the messages file. - * pdev: Pointer to the struct pci_dev. - * id: This is a unique id for the level. It identifies the part - * of the code from where the message originated. - * msg: The message to be displayed. - */ -void -ql_dbg_pci(uint32_t level, struct pci_dev *pdev, int32_t id, - const char *fmt, ...) -{ - va_list va; - struct va_format vaf; - - if (pdev == NULL) - return; - if (!ql_mask_match(level)) - return; - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - /* : Message */ - pr_warn("%s [%s]-%04x: : %pV", - QL_MSGHDR, dev_name(&(pdev->dev)), id + ql_dbg_offset, &vaf); - - va_end(va); -} - -/* - * This function is for formatting and logging log messages. - * It is to be used when vha is available. It formats the message - * and logs it to the messages file. All the messages will be logged - * irrespective of value of ql2xextended_error_logging. - * parameters: - * level: The level of the log messages to be printed in the - * messages file. - * vha: Pointer to the scsi_qla_host_t - * id: This is a unique id for the level. It identifies the - * part of the code from where the message originated. - * msg: The message to be displayed. - */ -void -ql_log(uint32_t level, scsi_qla_host_t *vha, int32_t id, const char *fmt, ...) -{ - va_list va; - struct va_format vaf; - char pbuf[128]; - - if (level > ql_errlev) - return; - - if (vha != NULL) { - const struct pci_dev *pdev = vha->hw->pdev; - /* : Message */ - snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x:%ld: ", - QL_MSGHDR, dev_name(&(pdev->dev)), id, vha->host_no); - } else { - snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x: : ", - QL_MSGHDR, "0000:00:00.0", id); - } - pbuf[sizeof(pbuf) - 1] = 0; - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - switch (level) { - case ql_log_fatal: /* FATAL LOG */ - pr_crit("%s%pV", pbuf, &vaf); - break; - case ql_log_warn: - pr_err("%s%pV", pbuf, &vaf); - break; - case ql_log_info: - pr_warn("%s%pV", pbuf, &vaf); - break; - default: - pr_info("%s%pV", pbuf, &vaf); - break; - } - - va_end(va); -} - -/* - * This function is for formatting and logging log messages. - * It is to be used when vha is not available and pci is availble, - * i.e., before host allocation. It formats the message and logs - * it to the messages file. All the messages are logged irrespective - * of the value of ql2xextended_error_logging. - * parameters: - * level: The level of the log messages to be printed in the - * messages file. - * pdev: Pointer to the struct pci_dev. - * id: This is a unique id for the level. It identifies the - * part of the code from where the message originated. - * msg: The message to be displayed. - */ -void -ql_log_pci(uint32_t level, struct pci_dev *pdev, int32_t id, - const char *fmt, ...) -{ - va_list va; - struct va_format vaf; - char pbuf[128]; - - if (pdev == NULL) - return; - if (level > ql_errlev) - return; - - /* : Message */ - snprintf(pbuf, sizeof(pbuf), "%s [%s]-%04x: : ", - QL_MSGHDR, dev_name(&(pdev->dev)), id); - pbuf[sizeof(pbuf) - 1] = 0; - - va_start(va, fmt); - - vaf.fmt = fmt; - vaf.va = &va; - - switch (level) { - case ql_log_fatal: /* FATAL LOG */ - pr_crit("%s%pV", pbuf, &vaf); - break; - case ql_log_warn: - pr_err("%s%pV", pbuf, &vaf); - break; - case ql_log_info: - pr_warn("%s%pV", pbuf, &vaf); - break; - default: - pr_info("%s%pV", pbuf, &vaf); - break; - } - - va_end(va); -} - -void -ql_dump_regs(uint32_t level, scsi_qla_host_t *vha, int32_t id) -{ - int i; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; - struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82; - uint16_t __iomem *mbx_reg; - - if (!ql_mask_match(level)) - return; - - if (IS_QLA82XX(ha)) - mbx_reg = ®82->mailbox_in[0]; - else if (IS_FWI2_CAPABLE(ha)) - mbx_reg = ®24->mailbox0; - else - mbx_reg = MAILBOX_REG(ha, reg, 0); - - ql_dbg(level, vha, id, "Mailbox registers:\n"); - for (i = 0; i < 6; i++) - ql_dbg(level, vha, id, - "mbox[%d] 0x%04x\n", i, RD_REG_WORD(mbx_reg++)); -} - - -void -ql_dump_buffer(uint32_t level, scsi_qla_host_t *vha, int32_t id, - uint8_t *b, uint32_t size) -{ - uint32_t cnt; - uint8_t c; - - if (!ql_mask_match(level)) - return; - - ql_dbg(level, vha, id, " 0 1 2 3 4 5 6 7 8 " - "9 Ah Bh Ch Dh Eh Fh\n"); - ql_dbg(level, vha, id, "----------------------------------" - "----------------------------\n"); - - ql_dbg(level, vha, id, " "); - for (cnt = 0; cnt < size;) { - c = *b++; - printk("%02x", (uint32_t) c); - cnt++; - if (!(cnt % 16)) - printk("\n"); - else - printk(" "); - } - if (cnt % 16) - ql_dbg(level, vha, id, "\n"); -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.h deleted file mode 100644 index 2157bdf1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dbg.h +++ /dev/null @@ -1,341 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ - -#include "qla_def.h" - -/* - * Firmware Dump structure definition - */ - -struct qla2300_fw_dump { - uint16_t hccr; - uint16_t pbiu_reg[8]; - uint16_t risc_host_reg[8]; - uint16_t mailbox_reg[32]; - uint16_t resp_dma_reg[32]; - uint16_t dma_reg[48]; - uint16_t risc_hdw_reg[16]; - uint16_t risc_gp0_reg[16]; - uint16_t risc_gp1_reg[16]; - uint16_t risc_gp2_reg[16]; - uint16_t risc_gp3_reg[16]; - uint16_t risc_gp4_reg[16]; - uint16_t risc_gp5_reg[16]; - uint16_t risc_gp6_reg[16]; - uint16_t risc_gp7_reg[16]; - uint16_t frame_buf_hdw_reg[64]; - uint16_t fpm_b0_reg[64]; - uint16_t fpm_b1_reg[64]; - uint16_t risc_ram[0xf800]; - uint16_t stack_ram[0x1000]; - uint16_t data_ram[1]; -}; - -struct qla2100_fw_dump { - uint16_t hccr; - uint16_t pbiu_reg[8]; - uint16_t mailbox_reg[32]; - uint16_t dma_reg[48]; - uint16_t risc_hdw_reg[16]; - uint16_t risc_gp0_reg[16]; - uint16_t risc_gp1_reg[16]; - uint16_t risc_gp2_reg[16]; - uint16_t risc_gp3_reg[16]; - uint16_t risc_gp4_reg[16]; - uint16_t risc_gp5_reg[16]; - uint16_t risc_gp6_reg[16]; - uint16_t risc_gp7_reg[16]; - uint16_t frame_buf_hdw_reg[16]; - uint16_t fpm_b0_reg[64]; - uint16_t fpm_b1_reg[64]; - uint16_t risc_ram[0xf000]; -}; - -struct qla24xx_fw_dump { - uint32_t host_status; - uint32_t host_reg[32]; - uint32_t shadow_reg[7]; - uint16_t mailbox_reg[32]; - uint32_t xseq_gp_reg[128]; - uint32_t xseq_0_reg[16]; - uint32_t xseq_1_reg[16]; - uint32_t rseq_gp_reg[128]; - uint32_t rseq_0_reg[16]; - uint32_t rseq_1_reg[16]; - uint32_t rseq_2_reg[16]; - uint32_t cmd_dma_reg[16]; - uint32_t req0_dma_reg[15]; - uint32_t resp0_dma_reg[15]; - uint32_t req1_dma_reg[15]; - uint32_t xmt0_dma_reg[32]; - uint32_t xmt1_dma_reg[32]; - uint32_t xmt2_dma_reg[32]; - uint32_t xmt3_dma_reg[32]; - uint32_t xmt4_dma_reg[32]; - uint32_t xmt_data_dma_reg[16]; - uint32_t rcvt0_data_dma_reg[32]; - uint32_t rcvt1_data_dma_reg[32]; - uint32_t risc_gp_reg[128]; - uint32_t lmc_reg[112]; - uint32_t fpm_hdw_reg[192]; - uint32_t fb_hdw_reg[176]; - uint32_t code_ram[0x2000]; - uint32_t ext_mem[1]; -}; - -struct qla25xx_fw_dump { - uint32_t host_status; - uint32_t host_risc_reg[32]; - uint32_t pcie_regs[4]; - uint32_t host_reg[32]; - uint32_t shadow_reg[11]; - uint32_t risc_io_reg; - uint16_t mailbox_reg[32]; - uint32_t xseq_gp_reg[128]; - uint32_t xseq_0_reg[48]; - uint32_t xseq_1_reg[16]; - uint32_t rseq_gp_reg[128]; - uint32_t rseq_0_reg[32]; - uint32_t rseq_1_reg[16]; - uint32_t rseq_2_reg[16]; - uint32_t aseq_gp_reg[128]; - uint32_t aseq_0_reg[32]; - uint32_t aseq_1_reg[16]; - uint32_t aseq_2_reg[16]; - uint32_t cmd_dma_reg[16]; - uint32_t req0_dma_reg[15]; - uint32_t resp0_dma_reg[15]; - uint32_t req1_dma_reg[15]; - uint32_t xmt0_dma_reg[32]; - uint32_t xmt1_dma_reg[32]; - uint32_t xmt2_dma_reg[32]; - uint32_t xmt3_dma_reg[32]; - uint32_t xmt4_dma_reg[32]; - uint32_t xmt_data_dma_reg[16]; - uint32_t rcvt0_data_dma_reg[32]; - uint32_t rcvt1_data_dma_reg[32]; - uint32_t risc_gp_reg[128]; - uint32_t lmc_reg[128]; - uint32_t fpm_hdw_reg[192]; - uint32_t fb_hdw_reg[192]; - uint32_t code_ram[0x2000]; - uint32_t ext_mem[1]; -}; - -struct qla81xx_fw_dump { - uint32_t host_status; - uint32_t host_risc_reg[32]; - uint32_t pcie_regs[4]; - uint32_t host_reg[32]; - uint32_t shadow_reg[11]; - uint32_t risc_io_reg; - uint16_t mailbox_reg[32]; - uint32_t xseq_gp_reg[128]; - uint32_t xseq_0_reg[48]; - uint32_t xseq_1_reg[16]; - uint32_t rseq_gp_reg[128]; - uint32_t rseq_0_reg[32]; - uint32_t rseq_1_reg[16]; - uint32_t rseq_2_reg[16]; - uint32_t aseq_gp_reg[128]; - uint32_t aseq_0_reg[32]; - uint32_t aseq_1_reg[16]; - uint32_t aseq_2_reg[16]; - uint32_t cmd_dma_reg[16]; - uint32_t req0_dma_reg[15]; - uint32_t resp0_dma_reg[15]; - uint32_t req1_dma_reg[15]; - uint32_t xmt0_dma_reg[32]; - uint32_t xmt1_dma_reg[32]; - uint32_t xmt2_dma_reg[32]; - uint32_t xmt3_dma_reg[32]; - uint32_t xmt4_dma_reg[32]; - uint32_t xmt_data_dma_reg[16]; - uint32_t rcvt0_data_dma_reg[32]; - uint32_t rcvt1_data_dma_reg[32]; - uint32_t risc_gp_reg[128]; - uint32_t lmc_reg[128]; - uint32_t fpm_hdw_reg[224]; - uint32_t fb_hdw_reg[208]; - uint32_t code_ram[0x2000]; - uint32_t ext_mem[1]; -}; - -struct qla83xx_fw_dump { - uint32_t host_status; - uint32_t host_risc_reg[48]; - uint32_t pcie_regs[4]; - uint32_t host_reg[32]; - uint32_t shadow_reg[11]; - uint32_t risc_io_reg; - uint16_t mailbox_reg[32]; - uint32_t xseq_gp_reg[256]; - uint32_t xseq_0_reg[48]; - uint32_t xseq_1_reg[16]; - uint32_t xseq_2_reg[16]; - uint32_t rseq_gp_reg[256]; - uint32_t rseq_0_reg[32]; - uint32_t rseq_1_reg[16]; - uint32_t rseq_2_reg[16]; - uint32_t rseq_3_reg[16]; - uint32_t aseq_gp_reg[256]; - uint32_t aseq_0_reg[32]; - uint32_t aseq_1_reg[16]; - uint32_t aseq_2_reg[16]; - uint32_t aseq_3_reg[16]; - uint32_t cmd_dma_reg[64]; - uint32_t req0_dma_reg[15]; - uint32_t resp0_dma_reg[15]; - uint32_t req1_dma_reg[15]; - uint32_t xmt0_dma_reg[32]; - uint32_t xmt1_dma_reg[32]; - uint32_t xmt2_dma_reg[32]; - uint32_t xmt3_dma_reg[32]; - uint32_t xmt4_dma_reg[32]; - uint32_t xmt_data_dma_reg[16]; - uint32_t rcvt0_data_dma_reg[32]; - uint32_t rcvt1_data_dma_reg[32]; - uint32_t risc_gp_reg[128]; - uint32_t lmc_reg[128]; - uint32_t fpm_hdw_reg[256]; - uint32_t rq0_array_reg[256]; - uint32_t rq1_array_reg[256]; - uint32_t rp0_array_reg[256]; - uint32_t rp1_array_reg[256]; - uint32_t queue_control_reg[16]; - uint32_t fb_hdw_reg[432]; - uint32_t at0_array_reg[128]; - uint32_t code_ram[0x2400]; - uint32_t ext_mem[1]; -}; - -#define EFT_NUM_BUFFERS 4 -#define EFT_BYTES_PER_BUFFER 0x4000 -#define EFT_SIZE ((EFT_BYTES_PER_BUFFER) * (EFT_NUM_BUFFERS)) - -#define FCE_NUM_BUFFERS 64 -#define FCE_BYTES_PER_BUFFER 0x400 -#define FCE_SIZE ((FCE_BYTES_PER_BUFFER) * (FCE_NUM_BUFFERS)) -#define fce_calc_size(b) ((FCE_BYTES_PER_BUFFER) * (b)) - -struct qla2xxx_fce_chain { - uint32_t type; - uint32_t chain_size; - - uint32_t size; - uint32_t addr_l; - uint32_t addr_h; - uint32_t eregs[8]; -}; - -struct qla2xxx_mq_chain { - uint32_t type; - uint32_t chain_size; - - uint32_t count; - uint32_t qregs[4 * QLA_MQ_SIZE]; -}; - -struct qla2xxx_mqueue_header { - uint32_t queue; -#define TYPE_REQUEST_QUEUE 0x1 -#define TYPE_RESPONSE_QUEUE 0x2 - uint32_t number; - uint32_t size; -}; - -struct qla2xxx_mqueue_chain { - uint32_t type; - uint32_t chain_size; -}; - -#define DUMP_CHAIN_VARIANT 0x80000000 -#define DUMP_CHAIN_FCE 0x7FFFFAF0 -#define DUMP_CHAIN_MQ 0x7FFFFAF1 -#define DUMP_CHAIN_QUEUE 0x7FFFFAF2 -#define DUMP_CHAIN_LAST 0x80000000 - -struct qla2xxx_fw_dump { - uint8_t signature[4]; - uint32_t version; - - uint32_t fw_major_version; - uint32_t fw_minor_version; - uint32_t fw_subminor_version; - uint32_t fw_attributes; - - uint32_t vendor; - uint32_t device; - uint32_t subsystem_vendor; - uint32_t subsystem_device; - - uint32_t fixed_size; - uint32_t mem_size; - uint32_t req_q_size; - uint32_t rsp_q_size; - - uint32_t eft_size; - uint32_t eft_addr_l; - uint32_t eft_addr_h; - - uint32_t header_size; - - union { - struct qla2100_fw_dump isp21; - struct qla2300_fw_dump isp23; - struct qla24xx_fw_dump isp24; - struct qla25xx_fw_dump isp25; - struct qla81xx_fw_dump isp81; - struct qla83xx_fw_dump isp83; - } isp; -}; - -#define QL_MSGHDR "qla2xxx" -#define QL_DBG_DEFAULT1_MASK 0x1e400000 - -#define ql_log_fatal 0 /* display fatal errors */ -#define ql_log_warn 1 /* display critical errors */ -#define ql_log_info 2 /* display all recovered errors */ -#define ql_log_all 3 /* This value is only used by ql_errlev. - * No messages will use this value. - * This should be always highest value - * as compared to other log levels. - */ - -extern int ql_errlev; - -void __attribute__((format (printf, 4, 5))) -ql_dbg(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...); -void __attribute__((format (printf, 4, 5))) -ql_dbg_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); - -void __attribute__((format (printf, 4, 5))) -ql_log(uint32_t, scsi_qla_host_t *vha, int32_t, const char *fmt, ...); -void __attribute__((format (printf, 4, 5))) -ql_log_pci(uint32_t, struct pci_dev *pdev, int32_t, const char *fmt, ...); - -/* Debug Levels */ -/* The 0x40000000 is the max value any debug level can have - * as ql2xextended_error_logging is of type signed int - */ -#define ql_dbg_init 0x40000000 /* Init Debug */ -#define ql_dbg_mbx 0x20000000 /* MBX Debug */ -#define ql_dbg_disc 0x10000000 /* Device Discovery Debug */ -#define ql_dbg_io 0x08000000 /* IO Tracing Debug */ -#define ql_dbg_dpc 0x04000000 /* DPC Thead Debug */ -#define ql_dbg_async 0x02000000 /* Async events Debug */ -#define ql_dbg_timer 0x01000000 /* Timer Debug */ -#define ql_dbg_user 0x00800000 /* User Space Interations Debug */ -#define ql_dbg_taskm 0x00400000 /* Task Management Debug */ -#define ql_dbg_aer 0x00200000 /* AER/EEH Debug */ -#define ql_dbg_multiq 0x00100000 /* MultiQ Debug */ -#define ql_dbg_p3p 0x00080000 /* P3P specific Debug */ -#define ql_dbg_vport 0x00040000 /* Virtual Port Debug */ -#define ql_dbg_buffer 0x00020000 /* For dumping the buffer/regs */ -#define ql_dbg_misc 0x00010000 /* For dumping everything that is not - * not covered by upper categories - */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_def.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_def.h deleted file mode 100644 index a2443031..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_def.h +++ /dev/null @@ -1,3068 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#ifndef __QLA_DEF_H -#define __QLA_DEF_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "qla_bsg.h" -#include "qla_nx.h" -#define QLA2XXX_DRIVER_NAME "qla2xxx" -#define QLA2XXX_APIDEV "ql2xapidev" - -/* - * We have MAILBOX_REGISTER_COUNT sized arrays in a few places, - * but that's fine as we don't look at the last 24 ones for - * ISP2100 HBAs. - */ -#define MAILBOX_REGISTER_COUNT_2100 8 -#define MAILBOX_REGISTER_COUNT_2200 24 -#define MAILBOX_REGISTER_COUNT 32 - -#define QLA2200A_RISC_ROM_VER 4 -#define FPM_2300 6 -#define FPM_2310 7 - -#include "qla_settings.h" - -/* - * Data bit definitions - */ -#define BIT_0 0x1 -#define BIT_1 0x2 -#define BIT_2 0x4 -#define BIT_3 0x8 -#define BIT_4 0x10 -#define BIT_5 0x20 -#define BIT_6 0x40 -#define BIT_7 0x80 -#define BIT_8 0x100 -#define BIT_9 0x200 -#define BIT_10 0x400 -#define BIT_11 0x800 -#define BIT_12 0x1000 -#define BIT_13 0x2000 -#define BIT_14 0x4000 -#define BIT_15 0x8000 -#define BIT_16 0x10000 -#define BIT_17 0x20000 -#define BIT_18 0x40000 -#define BIT_19 0x80000 -#define BIT_20 0x100000 -#define BIT_21 0x200000 -#define BIT_22 0x400000 -#define BIT_23 0x800000 -#define BIT_24 0x1000000 -#define BIT_25 0x2000000 -#define BIT_26 0x4000000 -#define BIT_27 0x8000000 -#define BIT_28 0x10000000 -#define BIT_29 0x20000000 -#define BIT_30 0x40000000 -#define BIT_31 0x80000000 - -#define LSB(x) ((uint8_t)(x)) -#define MSB(x) ((uint8_t)((uint16_t)(x) >> 8)) - -#define LSW(x) ((uint16_t)(x)) -#define MSW(x) ((uint16_t)((uint32_t)(x) >> 16)) - -#define LSD(x) ((uint32_t)((uint64_t)(x))) -#define MSD(x) ((uint32_t)((((uint64_t)(x)) >> 16) >> 16)) - -#define MAKE_HANDLE(x, y) ((uint32_t)((((uint32_t)(x)) << 16) | (uint32_t)(y))) - -/* - * I/O register -*/ - -#define RD_REG_BYTE(addr) readb(addr) -#define RD_REG_WORD(addr) readw(addr) -#define RD_REG_DWORD(addr) readl(addr) -#define RD_REG_BYTE_RELAXED(addr) readb_relaxed(addr) -#define RD_REG_WORD_RELAXED(addr) readw_relaxed(addr) -#define RD_REG_DWORD_RELAXED(addr) readl_relaxed(addr) -#define WRT_REG_BYTE(addr, data) writeb(data,addr) -#define WRT_REG_WORD(addr, data) writew(data,addr) -#define WRT_REG_DWORD(addr, data) writel(data,addr) - -/* - * The ISP2312 v2 chip cannot access the FLASH/GPIO registers via MMIO in an - * 133Mhz slot. - */ -#define RD_REG_WORD_PIO(addr) (inw((unsigned long)addr)) -#define WRT_REG_WORD_PIO(addr, data) (outw(data,(unsigned long)addr)) - -/* - * Fibre Channel device definitions. - */ -#define WWN_SIZE 8 /* Size of WWPN, WWN & WWNN */ -#define MAX_FIBRE_DEVICES_2100 512 -#define MAX_FIBRE_DEVICES_2400 2048 -#define MAX_FIBRE_DEVICES_LOOP 128 -#define MAX_FIBRE_DEVICES_MAX MAX_FIBRE_DEVICES_2400 -#define MAX_FIBRE_LUNS 0xFFFF -#define MAX_HOST_COUNT 16 - -/* - * Host adapter default definitions. - */ -#define MAX_BUSES 1 /* We only have one bus today */ -#define MIN_LUNS 8 -#define MAX_LUNS MAX_FIBRE_LUNS -#define MAX_CMDS_PER_LUN 255 - -/* - * Fibre Channel device definitions. - */ -#define SNS_LAST_LOOP_ID_2100 0xfe -#define SNS_LAST_LOOP_ID_2300 0x7ff - -#define LAST_LOCAL_LOOP_ID 0x7d -#define SNS_FL_PORT 0x7e -#define FABRIC_CONTROLLER 0x7f -#define SIMPLE_NAME_SERVER 0x80 -#define SNS_FIRST_LOOP_ID 0x81 -#define MANAGEMENT_SERVER 0xfe -#define BROADCAST 0xff - -/* - * There is no correspondence between an N-PORT id and an AL_PA. Therefore the - * valid range of an N-PORT id is 0 through 0x7ef. - */ -#define NPH_LAST_HANDLE 0x7ef -#define NPH_MGMT_SERVER 0x7fa /* FFFFFA */ -#define NPH_SNS 0x7fc /* FFFFFC */ -#define NPH_FABRIC_CONTROLLER 0x7fd /* FFFFFD */ -#define NPH_F_PORT 0x7fe /* FFFFFE */ -#define NPH_IP_BROADCAST 0x7ff /* FFFFFF */ - -#define MAX_CMDSZ 16 /* SCSI maximum CDB size. */ -#include "qla_fw.h" - -/* - * Timeout timer counts in seconds - */ -#define PORT_RETRY_TIME 1 -#define LOOP_DOWN_TIMEOUT 60 -#define LOOP_DOWN_TIME 255 /* 240 */ -#define LOOP_DOWN_RESET (LOOP_DOWN_TIME - 30) - -/* Maximum outstanding commands in ISP queues (1-65535) */ -#define MAX_OUTSTANDING_COMMANDS 1024 - -/* ISP request and response entry counts (37-65535) */ -#define REQUEST_ENTRY_CNT_2100 128 /* Number of request entries. */ -#define REQUEST_ENTRY_CNT_2200 2048 /* Number of request entries. */ -#define REQUEST_ENTRY_CNT_24XX 2048 /* Number of request entries. */ -#define RESPONSE_ENTRY_CNT_2100 64 /* Number of response entries.*/ -#define RESPONSE_ENTRY_CNT_2300 512 /* Number of response entries.*/ -#define RESPONSE_ENTRY_CNT_MQ 128 /* Number of response entries.*/ - -struct req_que; - -/* - * (sd.h is not exported, hence local inclusion) - * Data Integrity Field tuple. - */ -struct sd_dif_tuple { - __be16 guard_tag; /* Checksum */ - __be16 app_tag; /* Opaque storage */ - __be32 ref_tag; /* Target LBA or indirect LBA */ -}; - -/* - * SCSI Request Block - */ -struct srb_cmd { - struct scsi_cmnd *cmd; /* Linux SCSI command pkt */ - uint32_t request_sense_length; - uint8_t *request_sense_ptr; - void *ctx; -}; - -/* - * SRB flag definitions - */ -#define SRB_DMA_VALID BIT_0 /* Command sent to ISP */ -#define SRB_FCP_CMND_DMA_VALID BIT_12 /* DIF: DSD List valid */ -#define SRB_CRC_CTX_DMA_VALID BIT_2 /* DIF: context DMA valid */ -#define SRB_CRC_PROT_DMA_VALID BIT_4 /* DIF: prot DMA valid */ -#define SRB_CRC_CTX_DSD_VALID BIT_5 /* DIF: dsd_list valid */ - -/* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */ -#define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID) - -/* - * SRB extensions. - */ -struct srb_iocb { - union { - struct { - uint16_t flags; -#define SRB_LOGIN_RETRIED BIT_0 -#define SRB_LOGIN_COND_PLOGI BIT_1 -#define SRB_LOGIN_SKIP_PRLI BIT_2 - uint16_t data[2]; - } logio; - struct { - /* - * Values for flags field below are as - * defined in tsk_mgmt_entry struct - * for control_flags field in qla_fw.h. - */ - uint32_t flags; - uint32_t lun; - uint32_t data; - } tmf; - } u; - - struct timer_list timer; - void (*timeout)(void *); -}; - -/* Values for srb_ctx type */ -#define SRB_LOGIN_CMD 1 -#define SRB_LOGOUT_CMD 2 -#define SRB_ELS_CMD_RPT 3 -#define SRB_ELS_CMD_HST 4 -#define SRB_CT_CMD 5 -#define SRB_ADISC_CMD 6 -#define SRB_TM_CMD 7 -#define SRB_SCSI_CMD 8 - -typedef struct srb { - atomic_t ref_count; - struct fc_port *fcport; - uint32_t handle; - uint16_t flags; - uint16_t type; - char *name; - int iocbs; - union { - struct srb_iocb iocb_cmd; - struct fc_bsg_job *bsg_job; - struct srb_cmd scmd; - } u; - void (*done)(void *, void *, int); - void (*free)(void *, void *); -} srb_t; - -#define GET_CMD_SP(sp) (sp->u.scmd.cmd) -#define SET_CMD_SP(sp, cmd) (sp->u.scmd.cmd = cmd) -#define GET_CMD_CTX_SP(sp) (sp->u.scmd.ctx) - -#define GET_CMD_SENSE_LEN(sp) \ - (sp->u.scmd.request_sense_length) -#define SET_CMD_SENSE_LEN(sp, len) \ - (sp->u.scmd.request_sense_length = len) -#define GET_CMD_SENSE_PTR(sp) \ - (sp->u.scmd.request_sense_ptr) -#define SET_CMD_SENSE_PTR(sp, ptr) \ - (sp->u.scmd.request_sense_ptr = ptr) - -struct msg_echo_lb { - dma_addr_t send_dma; - dma_addr_t rcv_dma; - uint16_t req_sg_cnt; - uint16_t rsp_sg_cnt; - uint16_t options; - uint32_t transfer_size; -}; - -/* - * ISP I/O Register Set structure definitions. - */ -struct device_reg_2xxx { - uint16_t flash_address; /* Flash BIOS address */ - uint16_t flash_data; /* Flash BIOS data */ - uint16_t unused_1[1]; /* Gap */ - uint16_t ctrl_status; /* Control/Status */ -#define CSR_FLASH_64K_BANK BIT_3 /* Flash upper 64K bank select */ -#define CSR_FLASH_ENABLE BIT_1 /* Flash BIOS Read/Write enable */ -#define CSR_ISP_SOFT_RESET BIT_0 /* ISP soft reset */ - - uint16_t ictrl; /* Interrupt control */ -#define ICR_EN_INT BIT_15 /* ISP enable interrupts. */ -#define ICR_EN_RISC BIT_3 /* ISP enable RISC interrupts. */ - - uint16_t istatus; /* Interrupt status */ -#define ISR_RISC_INT BIT_3 /* RISC interrupt */ - - uint16_t semaphore; /* Semaphore */ - uint16_t nvram; /* NVRAM register. */ -#define NVR_DESELECT 0 -#define NVR_BUSY BIT_15 -#define NVR_WRT_ENABLE BIT_14 /* Write enable */ -#define NVR_PR_ENABLE BIT_13 /* Protection register enable */ -#define NVR_DATA_IN BIT_3 -#define NVR_DATA_OUT BIT_2 -#define NVR_SELECT BIT_1 -#define NVR_CLOCK BIT_0 - -#define NVR_WAIT_CNT 20000 - - union { - struct { - uint16_t mailbox0; - uint16_t mailbox1; - uint16_t mailbox2; - uint16_t mailbox3; - uint16_t mailbox4; - uint16_t mailbox5; - uint16_t mailbox6; - uint16_t mailbox7; - uint16_t unused_2[59]; /* Gap */ - } __attribute__((packed)) isp2100; - struct { - /* Request Queue */ - uint16_t req_q_in; /* In-Pointer */ - uint16_t req_q_out; /* Out-Pointer */ - /* Response Queue */ - uint16_t rsp_q_in; /* In-Pointer */ - uint16_t rsp_q_out; /* Out-Pointer */ - - /* RISC to Host Status */ - uint32_t host_status; -#define HSR_RISC_INT BIT_15 /* RISC interrupt */ -#define HSR_RISC_PAUSED BIT_8 /* RISC Paused */ - - /* Host to Host Semaphore */ - uint16_t host_semaphore; - uint16_t unused_3[17]; /* Gap */ - uint16_t mailbox0; - uint16_t mailbox1; - uint16_t mailbox2; - uint16_t mailbox3; - uint16_t mailbox4; - uint16_t mailbox5; - uint16_t mailbox6; - uint16_t mailbox7; - uint16_t mailbox8; - uint16_t mailbox9; - uint16_t mailbox10; - uint16_t mailbox11; - uint16_t mailbox12; - uint16_t mailbox13; - uint16_t mailbox14; - uint16_t mailbox15; - uint16_t mailbox16; - uint16_t mailbox17; - uint16_t mailbox18; - uint16_t mailbox19; - uint16_t mailbox20; - uint16_t mailbox21; - uint16_t mailbox22; - uint16_t mailbox23; - uint16_t mailbox24; - uint16_t mailbox25; - uint16_t mailbox26; - uint16_t mailbox27; - uint16_t mailbox28; - uint16_t mailbox29; - uint16_t mailbox30; - uint16_t mailbox31; - uint16_t fb_cmd; - uint16_t unused_4[10]; /* Gap */ - } __attribute__((packed)) isp2300; - } u; - - uint16_t fpm_diag_config; - uint16_t unused_5[0x4]; /* Gap */ - uint16_t risc_hw; - uint16_t unused_5_1; /* Gap */ - uint16_t pcr; /* Processor Control Register. */ - uint16_t unused_6[0x5]; /* Gap */ - uint16_t mctr; /* Memory Configuration and Timing. */ - uint16_t unused_7[0x3]; /* Gap */ - uint16_t fb_cmd_2100; /* Unused on 23XX */ - uint16_t unused_8[0x3]; /* Gap */ - uint16_t hccr; /* Host command & control register. */ -#define HCCR_HOST_INT BIT_7 /* Host interrupt bit */ -#define HCCR_RISC_PAUSE BIT_5 /* Pause mode bit */ - /* HCCR commands */ -#define HCCR_RESET_RISC 0x1000 /* Reset RISC */ -#define HCCR_PAUSE_RISC 0x2000 /* Pause RISC */ -#define HCCR_RELEASE_RISC 0x3000 /* Release RISC from reset. */ -#define HCCR_SET_HOST_INT 0x5000 /* Set host interrupt */ -#define HCCR_CLR_HOST_INT 0x6000 /* Clear HOST interrupt */ -#define HCCR_CLR_RISC_INT 0x7000 /* Clear RISC interrupt */ -#define HCCR_DISABLE_PARITY_PAUSE 0x4001 /* Disable parity error RISC pause. */ -#define HCCR_ENABLE_PARITY 0xA000 /* Enable PARITY interrupt */ - - uint16_t unused_9[5]; /* Gap */ - uint16_t gpiod; /* GPIO Data register. */ - uint16_t gpioe; /* GPIO Enable register. */ -#define GPIO_LED_MASK 0x00C0 -#define GPIO_LED_GREEN_OFF_AMBER_OFF 0x0000 -#define GPIO_LED_GREEN_ON_AMBER_OFF 0x0040 -#define GPIO_LED_GREEN_OFF_AMBER_ON 0x0080 -#define GPIO_LED_GREEN_ON_AMBER_ON 0x00C0 -#define GPIO_LED_ALL_OFF 0x0000 -#define GPIO_LED_RED_ON_OTHER_OFF 0x0001 /* isp2322 */ -#define GPIO_LED_RGA_ON 0x00C1 /* isp2322: red green amber */ - - union { - struct { - uint16_t unused_10[8]; /* Gap */ - uint16_t mailbox8; - uint16_t mailbox9; - uint16_t mailbox10; - uint16_t mailbox11; - uint16_t mailbox12; - uint16_t mailbox13; - uint16_t mailbox14; - uint16_t mailbox15; - uint16_t mailbox16; - uint16_t mailbox17; - uint16_t mailbox18; - uint16_t mailbox19; - uint16_t mailbox20; - uint16_t mailbox21; - uint16_t mailbox22; - uint16_t mailbox23; /* Also probe reg. */ - } __attribute__((packed)) isp2200; - } u_end; -}; - -struct device_reg_25xxmq { - uint32_t req_q_in; - uint32_t req_q_out; - uint32_t rsp_q_in; - uint32_t rsp_q_out; -}; - -typedef union { - struct device_reg_2xxx isp; - struct device_reg_24xx isp24; - struct device_reg_25xxmq isp25mq; - struct device_reg_82xx isp82; -} device_reg_t; - -#define ISP_REQ_Q_IN(ha, reg) \ - (IS_QLA2100(ha) || IS_QLA2200(ha) ? \ - &(reg)->u.isp2100.mailbox4 : \ - &(reg)->u.isp2300.req_q_in) -#define ISP_REQ_Q_OUT(ha, reg) \ - (IS_QLA2100(ha) || IS_QLA2200(ha) ? \ - &(reg)->u.isp2100.mailbox4 : \ - &(reg)->u.isp2300.req_q_out) -#define ISP_RSP_Q_IN(ha, reg) \ - (IS_QLA2100(ha) || IS_QLA2200(ha) ? \ - &(reg)->u.isp2100.mailbox5 : \ - &(reg)->u.isp2300.rsp_q_in) -#define ISP_RSP_Q_OUT(ha, reg) \ - (IS_QLA2100(ha) || IS_QLA2200(ha) ? \ - &(reg)->u.isp2100.mailbox5 : \ - &(reg)->u.isp2300.rsp_q_out) - -#define MAILBOX_REG(ha, reg, num) \ - (IS_QLA2100(ha) || IS_QLA2200(ha) ? \ - (num < 8 ? \ - &(reg)->u.isp2100.mailbox0 + (num) : \ - &(reg)->u_end.isp2200.mailbox8 + (num) - 8) : \ - &(reg)->u.isp2300.mailbox0 + (num)) -#define RD_MAILBOX_REG(ha, reg, num) \ - RD_REG_WORD(MAILBOX_REG(ha, reg, num)) -#define WRT_MAILBOX_REG(ha, reg, num, data) \ - WRT_REG_WORD(MAILBOX_REG(ha, reg, num), data) - -#define FB_CMD_REG(ha, reg) \ - (IS_QLA2100(ha) || IS_QLA2200(ha) ? \ - &(reg)->fb_cmd_2100 : \ - &(reg)->u.isp2300.fb_cmd) -#define RD_FB_CMD_REG(ha, reg) \ - RD_REG_WORD(FB_CMD_REG(ha, reg)) -#define WRT_FB_CMD_REG(ha, reg, data) \ - WRT_REG_WORD(FB_CMD_REG(ha, reg), data) - -typedef struct { - uint32_t out_mb; /* outbound from driver */ - uint32_t in_mb; /* Incoming from RISC */ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - long buf_size; - void *bufp; - uint32_t tov; - uint8_t flags; -#define MBX_DMA_IN BIT_0 -#define MBX_DMA_OUT BIT_1 -#define IOCTL_CMD BIT_2 -} mbx_cmd_t; - -#define MBX_TOV_SECONDS 30 - -/* - * ISP product identification definitions in mailboxes after reset. - */ -#define PROD_ID_1 0x4953 -#define PROD_ID_2 0x0000 -#define PROD_ID_2a 0x5020 -#define PROD_ID_3 0x2020 - -/* - * ISP mailbox Self-Test status codes - */ -#define MBS_FRM_ALIVE 0 /* Firmware Alive. */ -#define MBS_CHKSUM_ERR 1 /* Checksum Error. */ -#define MBS_BUSY 4 /* Busy. */ - -/* - * ISP mailbox command complete status codes - */ -#define MBS_COMMAND_COMPLETE 0x4000 -#define MBS_INVALID_COMMAND 0x4001 -#define MBS_HOST_INTERFACE_ERROR 0x4002 -#define MBS_TEST_FAILED 0x4003 -#define MBS_COMMAND_ERROR 0x4005 -#define MBS_COMMAND_PARAMETER_ERROR 0x4006 -#define MBS_PORT_ID_USED 0x4007 -#define MBS_LOOP_ID_USED 0x4008 -#define MBS_ALL_IDS_IN_USE 0x4009 -#define MBS_NOT_LOGGED_IN 0x400A -#define MBS_LINK_DOWN_ERROR 0x400B -#define MBS_DIAG_ECHO_TEST_ERROR 0x400C - -/* - * ISP mailbox asynchronous event status codes - */ -#define MBA_ASYNC_EVENT 0x8000 /* Asynchronous event. */ -#define MBA_RESET 0x8001 /* Reset Detected. */ -#define MBA_SYSTEM_ERR 0x8002 /* System Error. */ -#define MBA_REQ_TRANSFER_ERR 0x8003 /* Request Transfer Error. */ -#define MBA_RSP_TRANSFER_ERR 0x8004 /* Response Transfer Error. */ -#define MBA_WAKEUP_THRES 0x8005 /* Request Queue Wake-up. */ -#define MBA_LIP_OCCURRED 0x8010 /* Loop Initialization Procedure */ - /* occurred. */ -#define MBA_LOOP_UP 0x8011 /* FC Loop UP. */ -#define MBA_LOOP_DOWN 0x8012 /* FC Loop Down. */ -#define MBA_LIP_RESET 0x8013 /* LIP reset occurred. */ -#define MBA_PORT_UPDATE 0x8014 /* Port Database update. */ -#define MBA_RSCN_UPDATE 0x8015 /* Register State Chg Notification. */ -#define MBA_LIP_F8 0x8016 /* Received a LIP F8. */ -#define MBA_LOOP_INIT_ERR 0x8017 /* Loop Initialization Error. */ -#define MBA_FABRIC_AUTH_REQ 0x801b /* Fabric Authentication Required. */ -#define MBA_SCSI_COMPLETION 0x8020 /* SCSI Command Complete. */ -#define MBA_CTIO_COMPLETION 0x8021 /* CTIO Complete. */ -#define MBA_IP_COMPLETION 0x8022 /* IP Transmit Command Complete. */ -#define MBA_IP_RECEIVE 0x8023 /* IP Received. */ -#define MBA_IP_BROADCAST 0x8024 /* IP Broadcast Received. */ -#define MBA_IP_LOW_WATER_MARK 0x8025 /* IP Low Water Mark reached. */ -#define MBA_IP_RCV_BUFFER_EMPTY 0x8026 /* IP receive buffer queue empty. */ -#define MBA_IP_HDR_DATA_SPLIT 0x8027 /* IP header/data splitting feature */ - /* used. */ -#define MBA_TRACE_NOTIFICATION 0x8028 /* Trace/Diagnostic notification. */ -#define MBA_POINT_TO_POINT 0x8030 /* Point to point mode. */ -#define MBA_CMPLT_1_16BIT 0x8031 /* Completion 1 16bit IOSB. */ -#define MBA_CMPLT_2_16BIT 0x8032 /* Completion 2 16bit IOSB. */ -#define MBA_CMPLT_3_16BIT 0x8033 /* Completion 3 16bit IOSB. */ -#define MBA_CMPLT_4_16BIT 0x8034 /* Completion 4 16bit IOSB. */ -#define MBA_CMPLT_5_16BIT 0x8035 /* Completion 5 16bit IOSB. */ -#define MBA_CHG_IN_CONNECTION 0x8036 /* Change in connection mode. */ -#define MBA_RIO_RESPONSE 0x8040 /* RIO response queue update. */ -#define MBA_ZIO_RESPONSE 0x8040 /* ZIO response queue update. */ -#define MBA_CMPLT_2_32BIT 0x8042 /* Completion 2 32bit IOSB. */ -#define MBA_BYPASS_NOTIFICATION 0x8043 /* Auto bypass notification. */ -#define MBA_DISCARD_RND_FRAME 0x8048 /* discard RND frame due to error. */ -#define MBA_REJECTED_FCP_CMD 0x8049 /* rejected FCP_CMD. */ - -/* ISP mailbox loopback echo diagnostic error code */ -#define MBS_LB_RESET 0x17 -/* - * Firmware options 1, 2, 3. - */ -#define FO1_AE_ON_LIPF8 BIT_0 -#define FO1_AE_ALL_LIP_RESET BIT_1 -#define FO1_CTIO_RETRY BIT_3 -#define FO1_DISABLE_LIP_F7_SW BIT_4 -#define FO1_DISABLE_100MS_LOS_WAIT BIT_5 -#define FO1_DISABLE_GPIO6_7 BIT_6 /* LED bits */ -#define FO1_AE_ON_LOOP_INIT_ERR BIT_7 -#define FO1_SET_EMPHASIS_SWING BIT_8 -#define FO1_AE_AUTO_BYPASS BIT_9 -#define FO1_ENABLE_PURE_IOCB BIT_10 -#define FO1_AE_PLOGI_RJT BIT_11 -#define FO1_ENABLE_ABORT_SEQUENCE BIT_12 -#define FO1_AE_QUEUE_FULL BIT_13 - -#define FO2_ENABLE_ATIO_TYPE_3 BIT_0 -#define FO2_REV_LOOPBACK BIT_1 - -#define FO3_ENABLE_EMERG_IOCB BIT_0 -#define FO3_AE_RND_ERROR BIT_1 - -/* 24XX additional firmware options */ -#define ADD_FO_COUNT 3 -#define ADD_FO1_DISABLE_GPIO_LED_CTRL BIT_6 /* LED bits */ -#define ADD_FO1_ENABLE_PUREX_IOCB BIT_10 - -#define ADD_FO2_ENABLE_SEL_CLS2 BIT_5 - -#define ADD_FO3_NO_ABT_ON_LINK_DOWN BIT_14 - -/* - * ISP mailbox commands - */ -#define MBC_LOAD_RAM 1 /* Load RAM. */ -#define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */ -#define MBC_WRITE_RAM_WORD 4 /* Write RAM word. */ -#define MBC_READ_RAM_WORD 5 /* Read RAM word. */ -#define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ -#define MBC_VERIFY_CHECKSUM 7 /* Verify checksum. */ -#define MBC_GET_FIRMWARE_VERSION 8 /* Get firmware revision. */ -#define MBC_LOAD_RISC_RAM 9 /* Load RAM command. */ -#define MBC_DUMP_RISC_RAM 0xa /* Dump RAM command. */ -#define MBC_LOAD_RISC_RAM_EXTENDED 0xb /* Load RAM extended. */ -#define MBC_DUMP_RISC_RAM_EXTENDED 0xc /* Dump RAM extended. */ -#define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */ -#define MBC_READ_RAM_EXTENDED 0xf /* Read RAM extended. */ -#define MBC_IOCB_COMMAND 0x12 /* Execute IOCB command. */ -#define MBC_STOP_FIRMWARE 0x14 /* Stop firmware. */ -#define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */ -#define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */ -#define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */ -#define MBC_RESET 0x18 /* Reset. */ -#define MBC_GET_ADAPTER_LOOP_ID 0x20 /* Get loop id of ISP2200. */ -#define MBC_GET_RETRY_COUNT 0x22 /* Get f/w retry cnt/delay. */ -#define MBC_DISABLE_VI 0x24 /* Disable VI operation. */ -#define MBC_ENABLE_VI 0x25 /* Enable VI operation. */ -#define MBC_GET_FIRMWARE_OPTION 0x28 /* Get Firmware Options. */ -#define MBC_SET_FIRMWARE_OPTION 0x38 /* Set Firmware Options. */ -#define MBC_LOOP_PORT_BYPASS 0x40 /* Loop Port Bypass. */ -#define MBC_LOOP_PORT_ENABLE 0x41 /* Loop Port Enable. */ -#define MBC_GET_RESOURCE_COUNTS 0x42 /* Get Resource Counts. */ -#define MBC_NON_PARTICIPATE 0x43 /* Non-Participating Mode. */ -#define MBC_DIAGNOSTIC_ECHO 0x44 /* Diagnostic echo. */ -#define MBC_DIAGNOSTIC_LOOP_BACK 0x45 /* Diagnostic loop back. */ -#define MBC_ONLINE_SELF_TEST 0x46 /* Online self-test. */ -#define MBC_ENHANCED_GET_PORT_DATABASE 0x47 /* Get port database + login */ -#define MBC_CONFIGURE_VF 0x4b /* Configure VFs */ -#define MBC_RESET_LINK_STATUS 0x52 /* Reset Link Error Status */ -#define MBC_IOCB_COMMAND_A64 0x54 /* Execute IOCB command (64) */ -#define MBC_PORT_LOGOUT 0x56 /* Port Logout request */ -#define MBC_SEND_RNID_ELS 0x57 /* Send RNID ELS request */ -#define MBC_SET_RNID_PARAMS 0x59 /* Set RNID parameters */ -#define MBC_GET_RNID_PARAMS 0x5a /* Data Rate */ -#define MBC_DATA_RATE 0x5d /* Get RNID parameters */ -#define MBC_INITIALIZE_FIRMWARE 0x60 /* Initialize firmware */ -#define MBC_INITIATE_LIP 0x62 /* Initiate Loop */ - /* Initialization Procedure */ -#define MBC_GET_FC_AL_POSITION_MAP 0x63 /* Get FC_AL Position Map. */ -#define MBC_GET_PORT_DATABASE 0x64 /* Get Port Database. */ -#define MBC_CLEAR_ACA 0x65 /* Clear ACA. */ -#define MBC_TARGET_RESET 0x66 /* Target Reset. */ -#define MBC_CLEAR_TASK_SET 0x67 /* Clear Task Set. */ -#define MBC_ABORT_TASK_SET 0x68 /* Abort Task Set. */ -#define MBC_GET_FIRMWARE_STATE 0x69 /* Get firmware state. */ -#define MBC_GET_PORT_NAME 0x6a /* Get port name. */ -#define MBC_GET_LINK_STATUS 0x6b /* Get port link status. */ -#define MBC_LIP_RESET 0x6c /* LIP reset. */ -#define MBC_SEND_SNS_COMMAND 0x6e /* Send Simple Name Server */ - /* commandd. */ -#define MBC_LOGIN_FABRIC_PORT 0x6f /* Login fabric port. */ -#define MBC_SEND_CHANGE_REQUEST 0x70 /* Send Change Request. */ -#define MBC_LOGOUT_FABRIC_PORT 0x71 /* Logout fabric port. */ -#define MBC_LIP_FULL_LOGIN 0x72 /* Full login LIP. */ -#define MBC_LOGIN_LOOP_PORT 0x74 /* Login Loop Port. */ -#define MBC_PORT_NODE_NAME_LIST 0x75 /* Get port/node name list. */ -#define MBC_INITIALIZE_RECEIVE_QUEUE 0x77 /* Initialize receive queue */ -#define MBC_UNLOAD_IP 0x79 /* Shutdown IP */ -#define MBC_GET_ID_LIST 0x7C /* Get Port ID list. */ -#define MBC_SEND_LFA_COMMAND 0x7D /* Send Loop Fabric Address */ -#define MBC_LUN_RESET 0x7E /* Send LUN reset */ - -/* - * ISP24xx mailbox commands - */ -#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */ -#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */ -#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */ -#define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */ -#define MBC_TRACE_CONTROL 0x27 /* Trace control command. */ -#define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */ -#define MBC_WRITE_SFP 0x30 /* Write SFP Data. */ -#define MBC_READ_SFP 0x31 /* Read SFP Data. */ -#define MBC_SET_TIMEOUT_PARAMS 0x32 /* Set FW timeouts. */ -#define MBC_MID_INITIALIZE_FIRMWARE 0x48 /* MID Initialize firmware. */ -#define MBC_MID_GET_VP_DATABASE 0x49 /* MID Get VP Database. */ -#define MBC_MID_GET_VP_ENTRY 0x4a /* MID Get VP Entry. */ -#define MBC_HOST_MEMORY_COPY 0x53 /* Host Memory Copy. */ -#define MBC_SEND_RNFT_ELS 0x5e /* Send RNFT ELS request */ -#define MBC_GET_LINK_PRIV_STATS 0x6d /* Get link & private data. */ -#define MBC_SET_VENDOR_ID 0x76 /* Set Vendor ID. */ -#define MBC_SET_PORT_CONFIG 0x122 /* Set port configuration */ -#define MBC_GET_PORT_CONFIG 0x123 /* Get port configuration */ - -/* - * ISP81xx mailbox commands - */ -#define MBC_WRITE_MPI_REGISTER 0x01 /* Write MPI Register. */ - -/* Firmware return data sizes */ -#define FCAL_MAP_SIZE 128 - -/* Mailbox bit definitions for out_mb and in_mb */ -#define MBX_31 BIT_31 -#define MBX_30 BIT_30 -#define MBX_29 BIT_29 -#define MBX_28 BIT_28 -#define MBX_27 BIT_27 -#define MBX_26 BIT_26 -#define MBX_25 BIT_25 -#define MBX_24 BIT_24 -#define MBX_23 BIT_23 -#define MBX_22 BIT_22 -#define MBX_21 BIT_21 -#define MBX_20 BIT_20 -#define MBX_19 BIT_19 -#define MBX_18 BIT_18 -#define MBX_17 BIT_17 -#define MBX_16 BIT_16 -#define MBX_15 BIT_15 -#define MBX_14 BIT_14 -#define MBX_13 BIT_13 -#define MBX_12 BIT_12 -#define MBX_11 BIT_11 -#define MBX_10 BIT_10 -#define MBX_9 BIT_9 -#define MBX_8 BIT_8 -#define MBX_7 BIT_7 -#define MBX_6 BIT_6 -#define MBX_5 BIT_5 -#define MBX_4 BIT_4 -#define MBX_3 BIT_3 -#define MBX_2 BIT_2 -#define MBX_1 BIT_1 -#define MBX_0 BIT_0 - -/* - * Firmware state codes from get firmware state mailbox command - */ -#define FSTATE_CONFIG_WAIT 0 -#define FSTATE_WAIT_AL_PA 1 -#define FSTATE_WAIT_LOGIN 2 -#define FSTATE_READY 3 -#define FSTATE_LOSS_OF_SYNC 4 -#define FSTATE_ERROR 5 -#define FSTATE_REINIT 6 -#define FSTATE_NON_PART 7 - -#define FSTATE_CONFIG_CORRECT 0 -#define FSTATE_P2P_RCV_LIP 1 -#define FSTATE_P2P_CHOOSE_LOOP 2 -#define FSTATE_P2P_RCV_UNIDEN_LIP 3 -#define FSTATE_FATAL_ERROR 4 -#define FSTATE_LOOP_BACK_CONN 5 - -/* - * Port Database structure definition - * Little endian except where noted. - */ -#define PORT_DATABASE_SIZE 128 /* bytes */ -typedef struct { - uint8_t options; - uint8_t control; - uint8_t master_state; - uint8_t slave_state; - uint8_t reserved[2]; - uint8_t hard_address; - uint8_t reserved_1; - uint8_t port_id[4]; - uint8_t node_name[WWN_SIZE]; - uint8_t port_name[WWN_SIZE]; - uint16_t execution_throttle; - uint16_t execution_count; - uint8_t reset_count; - uint8_t reserved_2; - uint16_t resource_allocation; - uint16_t current_allocation; - uint16_t queue_head; - uint16_t queue_tail; - uint16_t transmit_execution_list_next; - uint16_t transmit_execution_list_previous; - uint16_t common_features; - uint16_t total_concurrent_sequences; - uint16_t RO_by_information_category; - uint8_t recipient; - uint8_t initiator; - uint16_t receive_data_size; - uint16_t concurrent_sequences; - uint16_t open_sequences_per_exchange; - uint16_t lun_abort_flags; - uint16_t lun_stop_flags; - uint16_t stop_queue_head; - uint16_t stop_queue_tail; - uint16_t port_retry_timer; - uint16_t next_sequence_id; - uint16_t frame_count; - uint16_t PRLI_payload_length; - uint8_t prli_svc_param_word_0[2]; /* Big endian */ - /* Bits 15-0 of word 0 */ - uint8_t prli_svc_param_word_3[2]; /* Big endian */ - /* Bits 15-0 of word 3 */ - uint16_t loop_id; - uint16_t extended_lun_info_list_pointer; - uint16_t extended_lun_stop_list_pointer; -} port_database_t; - -/* - * Port database slave/master states - */ -#define PD_STATE_DISCOVERY 0 -#define PD_STATE_WAIT_DISCOVERY_ACK 1 -#define PD_STATE_PORT_LOGIN 2 -#define PD_STATE_WAIT_PORT_LOGIN_ACK 3 -#define PD_STATE_PROCESS_LOGIN 4 -#define PD_STATE_WAIT_PROCESS_LOGIN_ACK 5 -#define PD_STATE_PORT_LOGGED_IN 6 -#define PD_STATE_PORT_UNAVAILABLE 7 -#define PD_STATE_PROCESS_LOGOUT 8 -#define PD_STATE_WAIT_PROCESS_LOGOUT_ACK 9 -#define PD_STATE_PORT_LOGOUT 10 -#define PD_STATE_WAIT_PORT_LOGOUT_ACK 11 - - -#define QLA_ZIO_MODE_6 (BIT_2 | BIT_1) -#define QLA_ZIO_DISABLED 0 -#define QLA_ZIO_DEFAULT_TIMER 2 - -/* - * ISP Initialization Control Block. - * Little endian except where noted. - */ -#define ICB_VERSION 1 -typedef struct { - uint8_t version; - uint8_t reserved_1; - - /* - * LSB BIT 0 = Enable Hard Loop Id - * LSB BIT 1 = Enable Fairness - * LSB BIT 2 = Enable Full-Duplex - * LSB BIT 3 = Enable Fast Posting - * LSB BIT 4 = Enable Target Mode - * LSB BIT 5 = Disable Initiator Mode - * LSB BIT 6 = Enable ADISC - * LSB BIT 7 = Enable Target Inquiry Data - * - * MSB BIT 0 = Enable PDBC Notify - * MSB BIT 1 = Non Participating LIP - * MSB BIT 2 = Descending Loop ID Search - * MSB BIT 3 = Acquire Loop ID in LIPA - * MSB BIT 4 = Stop PortQ on Full Status - * MSB BIT 5 = Full Login after LIP - * MSB BIT 6 = Node Name Option - * MSB BIT 7 = Ext IFWCB enable bit - */ - uint8_t firmware_options[2]; - - uint16_t frame_payload_size; - uint16_t max_iocb_allocation; - uint16_t execution_throttle; - uint8_t retry_count; - uint8_t retry_delay; /* unused */ - uint8_t port_name[WWN_SIZE]; /* Big endian. */ - uint16_t hard_address; - uint8_t inquiry_data; - uint8_t login_timeout; - uint8_t node_name[WWN_SIZE]; /* Big endian. */ - - uint16_t request_q_outpointer; - uint16_t response_q_inpointer; - uint16_t request_q_length; - uint16_t response_q_length; - uint32_t request_q_address[2]; - uint32_t response_q_address[2]; - - uint16_t lun_enables; - uint8_t command_resource_count; - uint8_t immediate_notify_resource_count; - uint16_t timeout; - uint8_t reserved_2[2]; - - /* - * LSB BIT 0 = Timer Operation mode bit 0 - * LSB BIT 1 = Timer Operation mode bit 1 - * LSB BIT 2 = Timer Operation mode bit 2 - * LSB BIT 3 = Timer Operation mode bit 3 - * LSB BIT 4 = Init Config Mode bit 0 - * LSB BIT 5 = Init Config Mode bit 1 - * LSB BIT 6 = Init Config Mode bit 2 - * LSB BIT 7 = Enable Non part on LIHA failure - * - * MSB BIT 0 = Enable class 2 - * MSB BIT 1 = Enable ACK0 - * MSB BIT 2 = - * MSB BIT 3 = - * MSB BIT 4 = FC Tape Enable - * MSB BIT 5 = Enable FC Confirm - * MSB BIT 6 = Enable command queuing in target mode - * MSB BIT 7 = No Logo On Link Down - */ - uint8_t add_firmware_options[2]; - - uint8_t response_accumulation_timer; - uint8_t interrupt_delay_timer; - - /* - * LSB BIT 0 = Enable Read xfr_rdy - * LSB BIT 1 = Soft ID only - * LSB BIT 2 = - * LSB BIT 3 = - * LSB BIT 4 = FCP RSP Payload [0] - * LSB BIT 5 = FCP RSP Payload [1] / Sbus enable - 2200 - * LSB BIT 6 = Enable Out-of-Order frame handling - * LSB BIT 7 = Disable Automatic PLOGI on Local Loop - * - * MSB BIT 0 = Sbus enable - 2300 - * MSB BIT 1 = - * MSB BIT 2 = - * MSB BIT 3 = - * MSB BIT 4 = LED mode - * MSB BIT 5 = enable 50 ohm termination - * MSB BIT 6 = Data Rate (2300 only) - * MSB BIT 7 = Data Rate (2300 only) - */ - uint8_t special_options[2]; - - uint8_t reserved_3[26]; -} init_cb_t; - -/* - * Get Link Status mailbox command return buffer. - */ -#define GLSO_SEND_RPS BIT_0 -#define GLSO_USE_DID BIT_3 - -struct link_statistics { - uint32_t link_fail_cnt; - uint32_t loss_sync_cnt; - uint32_t loss_sig_cnt; - uint32_t prim_seq_err_cnt; - uint32_t inval_xmit_word_cnt; - uint32_t inval_crc_cnt; - uint32_t lip_cnt; - uint32_t unused1[0x1a]; - uint32_t tx_frames; - uint32_t rx_frames; - uint32_t dumped_frames; - uint32_t unused2[2]; - uint32_t nos_rcvd; -}; - -/* - * NVRAM Command values. - */ -#define NV_START_BIT BIT_2 -#define NV_WRITE_OP (BIT_26+BIT_24) -#define NV_READ_OP (BIT_26+BIT_25) -#define NV_ERASE_OP (BIT_26+BIT_25+BIT_24) -#define NV_MASK_OP (BIT_26+BIT_25+BIT_24) -#define NV_DELAY_COUNT 10 - -/* - * QLogic ISP2100, ISP2200 and ISP2300 NVRAM structure definition. - */ -typedef struct { - /* - * NVRAM header - */ - uint8_t id[4]; - uint8_t nvram_version; - uint8_t reserved_0; - - /* - * NVRAM RISC parameter block - */ - uint8_t parameter_block_version; - uint8_t reserved_1; - - /* - * LSB BIT 0 = Enable Hard Loop Id - * LSB BIT 1 = Enable Fairness - * LSB BIT 2 = Enable Full-Duplex - * LSB BIT 3 = Enable Fast Posting - * LSB BIT 4 = Enable Target Mode - * LSB BIT 5 = Disable Initiator Mode - * LSB BIT 6 = Enable ADISC - * LSB BIT 7 = Enable Target Inquiry Data - * - * MSB BIT 0 = Enable PDBC Notify - * MSB BIT 1 = Non Participating LIP - * MSB BIT 2 = Descending Loop ID Search - * MSB BIT 3 = Acquire Loop ID in LIPA - * MSB BIT 4 = Stop PortQ on Full Status - * MSB BIT 5 = Full Login after LIP - * MSB BIT 6 = Node Name Option - * MSB BIT 7 = Ext IFWCB enable bit - */ - uint8_t firmware_options[2]; - - uint16_t frame_payload_size; - uint16_t max_iocb_allocation; - uint16_t execution_throttle; - uint8_t retry_count; - uint8_t retry_delay; /* unused */ - uint8_t port_name[WWN_SIZE]; /* Big endian. */ - uint16_t hard_address; - uint8_t inquiry_data; - uint8_t login_timeout; - uint8_t node_name[WWN_SIZE]; /* Big endian. */ - - /* - * LSB BIT 0 = Timer Operation mode bit 0 - * LSB BIT 1 = Timer Operation mode bit 1 - * LSB BIT 2 = Timer Operation mode bit 2 - * LSB BIT 3 = Timer Operation mode bit 3 - * LSB BIT 4 = Init Config Mode bit 0 - * LSB BIT 5 = Init Config Mode bit 1 - * LSB BIT 6 = Init Config Mode bit 2 - * LSB BIT 7 = Enable Non part on LIHA failure - * - * MSB BIT 0 = Enable class 2 - * MSB BIT 1 = Enable ACK0 - * MSB BIT 2 = - * MSB BIT 3 = - * MSB BIT 4 = FC Tape Enable - * MSB BIT 5 = Enable FC Confirm - * MSB BIT 6 = Enable command queuing in target mode - * MSB BIT 7 = No Logo On Link Down - */ - uint8_t add_firmware_options[2]; - - uint8_t response_accumulation_timer; - uint8_t interrupt_delay_timer; - - /* - * LSB BIT 0 = Enable Read xfr_rdy - * LSB BIT 1 = Soft ID only - * LSB BIT 2 = - * LSB BIT 3 = - * LSB BIT 4 = FCP RSP Payload [0] - * LSB BIT 5 = FCP RSP Payload [1] / Sbus enable - 2200 - * LSB BIT 6 = Enable Out-of-Order frame handling - * LSB BIT 7 = Disable Automatic PLOGI on Local Loop - * - * MSB BIT 0 = Sbus enable - 2300 - * MSB BIT 1 = - * MSB BIT 2 = - * MSB BIT 3 = - * MSB BIT 4 = LED mode - * MSB BIT 5 = enable 50 ohm termination - * MSB BIT 6 = Data Rate (2300 only) - * MSB BIT 7 = Data Rate (2300 only) - */ - uint8_t special_options[2]; - - /* Reserved for expanded RISC parameter block */ - uint8_t reserved_2[22]; - - /* - * LSB BIT 0 = Tx Sensitivity 1G bit 0 - * LSB BIT 1 = Tx Sensitivity 1G bit 1 - * LSB BIT 2 = Tx Sensitivity 1G bit 2 - * LSB BIT 3 = Tx Sensitivity 1G bit 3 - * LSB BIT 4 = Rx Sensitivity 1G bit 0 - * LSB BIT 5 = Rx Sensitivity 1G bit 1 - * LSB BIT 6 = Rx Sensitivity 1G bit 2 - * LSB BIT 7 = Rx Sensitivity 1G bit 3 - * - * MSB BIT 0 = Tx Sensitivity 2G bit 0 - * MSB BIT 1 = Tx Sensitivity 2G bit 1 - * MSB BIT 2 = Tx Sensitivity 2G bit 2 - * MSB BIT 3 = Tx Sensitivity 2G bit 3 - * MSB BIT 4 = Rx Sensitivity 2G bit 0 - * MSB BIT 5 = Rx Sensitivity 2G bit 1 - * MSB BIT 6 = Rx Sensitivity 2G bit 2 - * MSB BIT 7 = Rx Sensitivity 2G bit 3 - * - * LSB BIT 0 = Output Swing 1G bit 0 - * LSB BIT 1 = Output Swing 1G bit 1 - * LSB BIT 2 = Output Swing 1G bit 2 - * LSB BIT 3 = Output Emphasis 1G bit 0 - * LSB BIT 4 = Output Emphasis 1G bit 1 - * LSB BIT 5 = Output Swing 2G bit 0 - * LSB BIT 6 = Output Swing 2G bit 1 - * LSB BIT 7 = Output Swing 2G bit 2 - * - * MSB BIT 0 = Output Emphasis 2G bit 0 - * MSB BIT 1 = Output Emphasis 2G bit 1 - * MSB BIT 2 = Output Enable - * MSB BIT 3 = - * MSB BIT 4 = - * MSB BIT 5 = - * MSB BIT 6 = - * MSB BIT 7 = - */ - uint8_t seriallink_options[4]; - - /* - * NVRAM host parameter block - * - * LSB BIT 0 = Enable spinup delay - * LSB BIT 1 = Disable BIOS - * LSB BIT 2 = Enable Memory Map BIOS - * LSB BIT 3 = Enable Selectable Boot - * LSB BIT 4 = Disable RISC code load - * LSB BIT 5 = Set cache line size 1 - * LSB BIT 6 = PCI Parity Disable - * LSB BIT 7 = Enable extended logging - * - * MSB BIT 0 = Enable 64bit addressing - * MSB BIT 1 = Enable lip reset - * MSB BIT 2 = Enable lip full login - * MSB BIT 3 = Enable target reset - * MSB BIT 4 = Enable database storage - * MSB BIT 5 = Enable cache flush read - * MSB BIT 6 = Enable database load - * MSB BIT 7 = Enable alternate WWN - */ - uint8_t host_p[2]; - - uint8_t boot_node_name[WWN_SIZE]; - uint8_t boot_lun_number; - uint8_t reset_delay; - uint8_t port_down_retry_count; - uint8_t boot_id_number; - uint16_t max_luns_per_target; - uint8_t fcode_boot_port_name[WWN_SIZE]; - uint8_t alternate_port_name[WWN_SIZE]; - uint8_t alternate_node_name[WWN_SIZE]; - - /* - * BIT 0 = Selective Login - * BIT 1 = Alt-Boot Enable - * BIT 2 = - * BIT 3 = Boot Order List - * BIT 4 = - * BIT 5 = Selective LUN - * BIT 6 = - * BIT 7 = unused - */ - uint8_t efi_parameters; - - uint8_t link_down_timeout; - - uint8_t adapter_id[16]; - - uint8_t alt1_boot_node_name[WWN_SIZE]; - uint16_t alt1_boot_lun_number; - uint8_t alt2_boot_node_name[WWN_SIZE]; - uint16_t alt2_boot_lun_number; - uint8_t alt3_boot_node_name[WWN_SIZE]; - uint16_t alt3_boot_lun_number; - uint8_t alt4_boot_node_name[WWN_SIZE]; - uint16_t alt4_boot_lun_number; - uint8_t alt5_boot_node_name[WWN_SIZE]; - uint16_t alt5_boot_lun_number; - uint8_t alt6_boot_node_name[WWN_SIZE]; - uint16_t alt6_boot_lun_number; - uint8_t alt7_boot_node_name[WWN_SIZE]; - uint16_t alt7_boot_lun_number; - - uint8_t reserved_3[2]; - - /* Offset 200-215 : Model Number */ - uint8_t model_number[16]; - - /* OEM related items */ - uint8_t oem_specific[16]; - - /* - * NVRAM Adapter Features offset 232-239 - * - * LSB BIT 0 = External GBIC - * LSB BIT 1 = Risc RAM parity - * LSB BIT 2 = Buffer Plus Module - * LSB BIT 3 = Multi Chip Adapter - * LSB BIT 4 = Internal connector - * LSB BIT 5 = - * LSB BIT 6 = - * LSB BIT 7 = - * - * MSB BIT 0 = - * MSB BIT 1 = - * MSB BIT 2 = - * MSB BIT 3 = - * MSB BIT 4 = - * MSB BIT 5 = - * MSB BIT 6 = - * MSB BIT 7 = - */ - uint8_t adapter_features[2]; - - uint8_t reserved_4[16]; - - /* Subsystem vendor ID for ISP2200 */ - uint16_t subsystem_vendor_id_2200; - - /* Subsystem device ID for ISP2200 */ - uint16_t subsystem_device_id_2200; - - uint8_t reserved_5; - uint8_t checksum; -} nvram_t; - -/* - * ISP queue - response queue entry definition. - */ -typedef struct { - uint8_t data[60]; - uint32_t signature; -#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */ -} response_t; - -typedef union { - uint16_t extended; - struct { - uint8_t reserved; - uint8_t standard; - } id; -} target_id_t; - -#define SET_TARGET_ID(ha, to, from) \ -do { \ - if (HAS_EXTENDED_IDS(ha)) \ - to.extended = cpu_to_le16(from); \ - else \ - to.id.standard = (uint8_t)from; \ -} while (0) - -/* - * ISP queue - command entry structure definition. - */ -#define COMMAND_TYPE 0x11 /* Command entry */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System handle. */ - target_id_t target; /* SCSI ID */ - uint16_t lun; /* SCSI LUN */ - uint16_t control_flags; /* Control flags. */ -#define CF_WRITE BIT_6 -#define CF_READ BIT_5 -#define CF_SIMPLE_TAG BIT_3 -#define CF_ORDERED_TAG BIT_2 -#define CF_HEAD_TAG BIT_1 - uint16_t reserved_1; - uint16_t timeout; /* Command timeout. */ - uint16_t dseg_count; /* Data segment count. */ - uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ - uint32_t byte_count; /* Total byte count. */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ -} cmd_entry_t; - -/* - * ISP queue - 64-Bit addressing, command entry structure definition. - */ -#define COMMAND_A64_TYPE 0x19 /* Command A64 entry */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System handle. */ - target_id_t target; /* SCSI ID */ - uint16_t lun; /* SCSI LUN */ - uint16_t control_flags; /* Control flags. */ - uint16_t reserved_1; - uint16_t timeout; /* Command timeout. */ - uint16_t dseg_count; /* Data segment count. */ - uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ - uint32_t byte_count; /* Total byte count. */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ -} cmd_a64_entry_t, request_t; - -/* - * ISP queue - continuation entry structure definition. - */ -#define CONTINUE_TYPE 0x02 /* Continuation entry. */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t reserved; - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ - uint32_t dseg_4_address; /* Data segment 4 address. */ - uint32_t dseg_4_length; /* Data segment 4 length. */ - uint32_t dseg_5_address; /* Data segment 5 address. */ - uint32_t dseg_5_length; /* Data segment 5 length. */ - uint32_t dseg_6_address; /* Data segment 6 address. */ - uint32_t dseg_6_length; /* Data segment 6 length. */ -} cont_entry_t; - -/* - * ISP queue - 64-Bit addressing, continuation entry structure definition. - */ -#define CONTINUE_A64_TYPE 0x0A /* Continuation A64 entry. */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address [2]; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address[2]; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ - uint32_t dseg_4_address[2]; /* Data segment 4 address. */ - uint32_t dseg_4_length; /* Data segment 4 length. */ -} cont_a64_entry_t; - -#define PO_MODE_DIF_INSERT 0 -#define PO_MODE_DIF_REMOVE BIT_0 -#define PO_MODE_DIF_PASS BIT_1 -#define PO_MODE_DIF_REPLACE (BIT_0 + BIT_1) -#define PO_ENABLE_DIF_BUNDLING BIT_8 -#define PO_ENABLE_INCR_GUARD_SEED BIT_3 -#define PO_DISABLE_INCR_REF_TAG BIT_5 -#define PO_DISABLE_GUARD_CHECK BIT_4 -/* - * ISP queue - 64-Bit addressing, continuation crc entry structure definition. - */ -struct crc_context { - uint32_t handle; /* System handle. */ - uint32_t ref_tag; - uint16_t app_tag; - uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/ - uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/ - uint16_t guard_seed; /* Initial Guard Seed */ - uint16_t prot_opts; /* Requested Data Protection Mode */ - uint16_t blk_size; /* Data size in bytes */ - uint16_t runt_blk_guard; /* Guard value for runt block (tape - * only) */ - uint32_t byte_count; /* Total byte count/ total data - * transfer count */ - union { - struct { - uint32_t reserved_1; - uint16_t reserved_2; - uint16_t reserved_3; - uint32_t reserved_4; - uint32_t data_address[2]; - uint32_t data_length; - uint32_t reserved_5[2]; - uint32_t reserved_6; - } nobundling; - struct { - uint32_t dif_byte_count; /* Total DIF byte - * count */ - uint16_t reserved_1; - uint16_t dseg_count; /* Data segment count */ - uint32_t reserved_2; - uint32_t data_address[2]; - uint32_t data_length; - uint32_t dif_address[2]; - uint32_t dif_length; /* Data segment 0 - * length */ - } bundling; - } u; - - struct fcp_cmnd fcp_cmnd; - dma_addr_t crc_ctx_dma; - /* List of DMA context transfers */ - struct list_head dsd_list; - - /* This structure should not exceed 512 bytes */ -}; - -#define CRC_CONTEXT_LEN_FW (offsetof(struct crc_context, fcp_cmnd.lun)) -#define CRC_CONTEXT_FCPCMND_OFF (offsetof(struct crc_context, fcp_cmnd.lun)) - -/* - * ISP queue - status entry structure definition. - */ -#define STATUS_TYPE 0x03 /* Status entry. */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System handle. */ - uint16_t scsi_status; /* SCSI status. */ - uint16_t comp_status; /* Completion status. */ - uint16_t state_flags; /* State flags. */ - uint16_t status_flags; /* Status flags. */ - uint16_t rsp_info_len; /* Response Info Length. */ - uint16_t req_sense_length; /* Request sense data length. */ - uint32_t residual_length; /* Residual transfer length. */ - uint8_t rsp_info[8]; /* FCP response information. */ - uint8_t req_sense_data[32]; /* Request sense data. */ -} sts_entry_t; - -/* - * Status entry entry status - */ -#define RF_RQ_DMA_ERROR BIT_6 /* Request Queue DMA error. */ -#define RF_INV_E_ORDER BIT_5 /* Invalid entry order. */ -#define RF_INV_E_COUNT BIT_4 /* Invalid entry count. */ -#define RF_INV_E_PARAM BIT_3 /* Invalid entry parameter. */ -#define RF_INV_E_TYPE BIT_2 /* Invalid entry type. */ -#define RF_BUSY BIT_1 /* Busy */ -#define RF_MASK (RF_RQ_DMA_ERROR | RF_INV_E_ORDER | RF_INV_E_COUNT | \ - RF_INV_E_PARAM | RF_INV_E_TYPE | RF_BUSY) -#define RF_MASK_24XX (RF_INV_E_ORDER | RF_INV_E_COUNT | RF_INV_E_PARAM | \ - RF_INV_E_TYPE) - -/* - * Status entry SCSI status bit definitions. - */ -#define SS_MASK 0xfff /* Reserved bits BIT_12-BIT_15*/ -#define SS_RESIDUAL_UNDER BIT_11 -#define SS_RESIDUAL_OVER BIT_10 -#define SS_SENSE_LEN_VALID BIT_9 -#define SS_RESPONSE_INFO_LEN_VALID BIT_8 - -#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3) -#define SS_BUSY_CONDITION BIT_3 -#define SS_CONDITION_MET BIT_2 -#define SS_CHECK_CONDITION BIT_1 - -/* - * Status entry completion status - */ -#define CS_COMPLETE 0x0 /* No errors */ -#define CS_INCOMPLETE 0x1 /* Incomplete transfer of cmd. */ -#define CS_DMA 0x2 /* A DMA direction error. */ -#define CS_TRANSPORT 0x3 /* Transport error. */ -#define CS_RESET 0x4 /* SCSI bus reset occurred */ -#define CS_ABORTED 0x5 /* System aborted command. */ -#define CS_TIMEOUT 0x6 /* Timeout error. */ -#define CS_DATA_OVERRUN 0x7 /* Data overrun. */ -#define CS_DIF_ERROR 0xC /* DIF error detected */ - -#define CS_DATA_UNDERRUN 0x15 /* Data Underrun. */ -#define CS_QUEUE_FULL 0x1C /* Queue Full. */ -#define CS_PORT_UNAVAILABLE 0x28 /* Port unavailable */ - /* (selection timeout) */ -#define CS_PORT_LOGGED_OUT 0x29 /* Port Logged Out */ -#define CS_PORT_CONFIG_CHG 0x2A /* Port Configuration Changed */ -#define CS_PORT_BUSY 0x2B /* Port Busy */ -#define CS_COMPLETE_CHKCOND 0x30 /* Error? */ -#define CS_BAD_PAYLOAD 0x80 /* Driver defined */ -#define CS_UNKNOWN 0x81 /* Driver defined */ -#define CS_RETRY 0x82 /* Driver defined */ -#define CS_LOOP_DOWN_ABORT 0x83 /* Driver defined */ - -/* - * Status entry status flags - */ -#define SF_ABTS_TERMINATED BIT_10 -#define SF_LOGOUT_SENT BIT_13 - -/* - * ISP queue - status continuation entry structure definition. - */ -#define STATUS_CONT_TYPE 0x10 /* Status continuation entry. */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - uint8_t data[60]; /* data */ -} sts_cont_entry_t; - -/* - * ISP queue - RIO Type 1 status entry (32 bit I/O entry handles) - * structure definition. - */ -#define STATUS_TYPE_21 0x21 /* Status entry. */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; /* Handle count. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle[15]; /* System handles. */ -} sts21_entry_t; - -/* - * ISP queue - RIO Type 2 status entry (16 bit I/O entry handles) - * structure definition. - */ -#define STATUS_TYPE_22 0x22 /* Status entry. */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; /* Handle count. */ - uint8_t entry_status; /* Entry Status. */ - uint16_t handle[30]; /* System handles. */ -} sts22_entry_t; - -/* - * ISP queue - marker entry structure definition. - */ -#define MARKER_TYPE 0x04 /* Marker entry. */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; /* Handle count. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t sys_define_2; /* System defined. */ - target_id_t target; /* SCSI ID */ - uint8_t modifier; /* Modifier (7-0). */ -#define MK_SYNC_ID_LUN 0 /* Synchronize ID/LUN */ -#define MK_SYNC_ID 1 /* Synchronize ID */ -#define MK_SYNC_ALL 2 /* Synchronize all ID/LUN */ -#define MK_SYNC_LIP 3 /* Synchronize all ID/LUN, */ - /* clear port changed, */ - /* use sequence number. */ - uint8_t reserved_1; - uint16_t sequence_number; /* Sequence number of event */ - uint16_t lun; /* SCSI LUN */ - uint8_t reserved_2[48]; -} mrk_entry_t; - -/* - * ISP queue - Management Server entry structure definition. - */ -#define MS_IOCB_TYPE 0x29 /* Management Server IOCB entry */ -typedef struct { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; /* Handle count. */ - uint8_t entry_status; /* Entry Status. */ - uint32_t handle1; /* System handle. */ - target_id_t loop_id; - uint16_t status; - uint16_t control_flags; /* Control flags. */ - uint16_t reserved2; - uint16_t timeout; - uint16_t cmd_dsd_count; - uint16_t total_dsd_count; - uint8_t type; - uint8_t r_ctl; - uint16_t rx_id; - uint16_t reserved3; - uint32_t handle2; - uint32_t rsp_bytecount; - uint32_t req_bytecount; - uint32_t dseg_req_address[2]; /* Data segment 0 address. */ - uint32_t dseg_req_length; /* Data segment 0 length. */ - uint32_t dseg_rsp_address[2]; /* Data segment 1 address. */ - uint32_t dseg_rsp_length; /* Data segment 1 length. */ -} ms_iocb_entry_t; - - -/* - * ISP queue - Mailbox Command entry structure definition. - */ -#define MBX_IOCB_TYPE 0x39 -struct mbx_entry { - uint8_t entry_type; - uint8_t entry_count; - uint8_t sys_define1; - /* Use sys_define1 for source type */ -#define SOURCE_SCSI 0x00 -#define SOURCE_IP 0x01 -#define SOURCE_VI 0x02 -#define SOURCE_SCTP 0x03 -#define SOURCE_MP 0x04 -#define SOURCE_MPIOCTL 0x05 -#define SOURCE_ASYNC_IOCB 0x07 - - uint8_t entry_status; - - uint32_t handle; - target_id_t loop_id; - - uint16_t status; - uint16_t state_flags; - uint16_t status_flags; - - uint32_t sys_define2[2]; - - uint16_t mb0; - uint16_t mb1; - uint16_t mb2; - uint16_t mb3; - uint16_t mb6; - uint16_t mb7; - uint16_t mb9; - uint16_t mb10; - uint32_t reserved_2[2]; - uint8_t node_name[WWN_SIZE]; - uint8_t port_name[WWN_SIZE]; -}; - -/* - * ISP request and response queue entry sizes - */ -#define RESPONSE_ENTRY_SIZE (sizeof(response_t)) -#define REQUEST_ENTRY_SIZE (sizeof(request_t)) - - -/* - * 24 bit port ID type definition. - */ -typedef union { - uint32_t b24 : 24; - - struct { -#ifdef __BIG_ENDIAN - uint8_t domain; - uint8_t area; - uint8_t al_pa; -#elif defined(__LITTLE_ENDIAN) - uint8_t al_pa; - uint8_t area; - uint8_t domain; -#else -#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined!" -#endif - uint8_t rsvd_1; - } b; -} port_id_t; -#define INVALID_PORT_ID 0xFFFFFF - -/* - * Switch info gathering structure. - */ -typedef struct { - port_id_t d_id; - uint8_t node_name[WWN_SIZE]; - uint8_t port_name[WWN_SIZE]; - uint8_t fabric_port_name[WWN_SIZE]; - uint16_t fp_speed; - uint8_t fc4_type; -} sw_info_t; - -/* FCP-4 types */ -#define FC4_TYPE_FCP_SCSI 0x08 -#define FC4_TYPE_OTHER 0x0 -#define FC4_TYPE_UNKNOWN 0xff - -/* - * Fibre channel port type. - */ - typedef enum { - FCT_UNKNOWN, - FCT_RSCN, - FCT_SWITCH, - FCT_BROADCAST, - FCT_INITIATOR, - FCT_TARGET -} fc_port_type_t; - -/* - * Fibre channel port structure. - */ -typedef struct fc_port { - struct list_head list; - struct scsi_qla_host *vha; - - uint8_t node_name[WWN_SIZE]; - uint8_t port_name[WWN_SIZE]; - port_id_t d_id; - uint16_t loop_id; - uint16_t old_loop_id; - - uint8_t fcp_prio; - - uint8_t fabric_port_name[WWN_SIZE]; - uint16_t fp_speed; - - fc_port_type_t port_type; - - atomic_t state; - uint32_t flags; - - int login_retry; - - struct fc_rport *rport, *drport; - u32 supported_classes; - - uint16_t vp_idx; - uint8_t fc4_type; - uint8_t scan_state; -} fc_port_t; - -/* - * Fibre channel port/lun states. - */ -#define FCS_UNCONFIGURED 1 -#define FCS_DEVICE_DEAD 2 -#define FCS_DEVICE_LOST 3 -#define FCS_ONLINE 4 - -static const char * const port_state_str[] = { - "Unknown", - "UNCONFIGURED", - "DEAD", - "LOST", - "ONLINE" -}; - -/* - * FC port flags. - */ -#define FCF_FABRIC_DEVICE BIT_0 -#define FCF_LOGIN_NEEDED BIT_1 -#define FCF_FCP2_DEVICE BIT_2 -#define FCF_ASYNC_SENT BIT_3 - -/* No loop ID flag. */ -#define FC_NO_LOOP_ID 0x1000 - -/* - * FC-CT interface - * - * NOTE: All structures are big-endian in form. - */ - -#define CT_REJECT_RESPONSE 0x8001 -#define CT_ACCEPT_RESPONSE 0x8002 -#define CT_REASON_INVALID_COMMAND_CODE 0x01 -#define CT_REASON_CANNOT_PERFORM 0x09 -#define CT_REASON_COMMAND_UNSUPPORTED 0x0b -#define CT_EXPL_ALREADY_REGISTERED 0x10 - -#define NS_N_PORT_TYPE 0x01 -#define NS_NL_PORT_TYPE 0x02 -#define NS_NX_PORT_TYPE 0x7F - -#define GA_NXT_CMD 0x100 -#define GA_NXT_REQ_SIZE (16 + 4) -#define GA_NXT_RSP_SIZE (16 + 620) - -#define GID_PT_CMD 0x1A1 -#define GID_PT_REQ_SIZE (16 + 4) - -#define GPN_ID_CMD 0x112 -#define GPN_ID_REQ_SIZE (16 + 4) -#define GPN_ID_RSP_SIZE (16 + 8) - -#define GNN_ID_CMD 0x113 -#define GNN_ID_REQ_SIZE (16 + 4) -#define GNN_ID_RSP_SIZE (16 + 8) - -#define GFT_ID_CMD 0x117 -#define GFT_ID_REQ_SIZE (16 + 4) -#define GFT_ID_RSP_SIZE (16 + 32) - -#define RFT_ID_CMD 0x217 -#define RFT_ID_REQ_SIZE (16 + 4 + 32) -#define RFT_ID_RSP_SIZE 16 - -#define RFF_ID_CMD 0x21F -#define RFF_ID_REQ_SIZE (16 + 4 + 2 + 1 + 1) -#define RFF_ID_RSP_SIZE 16 - -#define RNN_ID_CMD 0x213 -#define RNN_ID_REQ_SIZE (16 + 4 + 8) -#define RNN_ID_RSP_SIZE 16 - -#define RSNN_NN_CMD 0x239 -#define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255) -#define RSNN_NN_RSP_SIZE 16 - -#define GFPN_ID_CMD 0x11C -#define GFPN_ID_REQ_SIZE (16 + 4) -#define GFPN_ID_RSP_SIZE (16 + 8) - -#define GPSC_CMD 0x127 -#define GPSC_REQ_SIZE (16 + 8) -#define GPSC_RSP_SIZE (16 + 2 + 2) - -#define GFF_ID_CMD 0x011F -#define GFF_ID_REQ_SIZE (16 + 4) -#define GFF_ID_RSP_SIZE (16 + 128) - -/* - * HBA attribute types. - */ -#define FDMI_HBA_ATTR_COUNT 9 -#define FDMI_HBA_NODE_NAME 1 -#define FDMI_HBA_MANUFACTURER 2 -#define FDMI_HBA_SERIAL_NUMBER 3 -#define FDMI_HBA_MODEL 4 -#define FDMI_HBA_MODEL_DESCRIPTION 5 -#define FDMI_HBA_HARDWARE_VERSION 6 -#define FDMI_HBA_DRIVER_VERSION 7 -#define FDMI_HBA_OPTION_ROM_VERSION 8 -#define FDMI_HBA_FIRMWARE_VERSION 9 -#define FDMI_HBA_OS_NAME_AND_VERSION 0xa -#define FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH 0xb - -struct ct_fdmi_hba_attr { - uint16_t type; - uint16_t len; - union { - uint8_t node_name[WWN_SIZE]; - uint8_t manufacturer[32]; - uint8_t serial_num[8]; - uint8_t model[16]; - uint8_t model_desc[80]; - uint8_t hw_version[16]; - uint8_t driver_version[32]; - uint8_t orom_version[16]; - uint8_t fw_version[16]; - uint8_t os_version[128]; - uint8_t max_ct_len[4]; - } a; -}; - -struct ct_fdmi_hba_attributes { - uint32_t count; - struct ct_fdmi_hba_attr entry[FDMI_HBA_ATTR_COUNT]; -}; - -/* - * Port attribute types. - */ -#define FDMI_PORT_ATTR_COUNT 6 -#define FDMI_PORT_FC4_TYPES 1 -#define FDMI_PORT_SUPPORT_SPEED 2 -#define FDMI_PORT_CURRENT_SPEED 3 -#define FDMI_PORT_MAX_FRAME_SIZE 4 -#define FDMI_PORT_OS_DEVICE_NAME 5 -#define FDMI_PORT_HOST_NAME 6 - -#define FDMI_PORT_SPEED_1GB 0x1 -#define FDMI_PORT_SPEED_2GB 0x2 -#define FDMI_PORT_SPEED_10GB 0x4 -#define FDMI_PORT_SPEED_4GB 0x8 -#define FDMI_PORT_SPEED_8GB 0x10 -#define FDMI_PORT_SPEED_16GB 0x20 -#define FDMI_PORT_SPEED_UNKNOWN 0x8000 - -struct ct_fdmi_port_attr { - uint16_t type; - uint16_t len; - union { - uint8_t fc4_types[32]; - uint32_t sup_speed; - uint32_t cur_speed; - uint32_t max_frame_size; - uint8_t os_dev_name[32]; - uint8_t host_name[32]; - } a; -}; - -/* - * Port Attribute Block. - */ -struct ct_fdmi_port_attributes { - uint32_t count; - struct ct_fdmi_port_attr entry[FDMI_PORT_ATTR_COUNT]; -}; - -/* FDMI definitions. */ -#define GRHL_CMD 0x100 -#define GHAT_CMD 0x101 -#define GRPL_CMD 0x102 -#define GPAT_CMD 0x110 - -#define RHBA_CMD 0x200 -#define RHBA_RSP_SIZE 16 - -#define RHAT_CMD 0x201 -#define RPRT_CMD 0x210 - -#define RPA_CMD 0x211 -#define RPA_RSP_SIZE 16 - -#define DHBA_CMD 0x300 -#define DHBA_REQ_SIZE (16 + 8) -#define DHBA_RSP_SIZE 16 - -#define DHAT_CMD 0x301 -#define DPRT_CMD 0x310 -#define DPA_CMD 0x311 - -/* CT command header -- request/response common fields */ -struct ct_cmd_hdr { - uint8_t revision; - uint8_t in_id[3]; - uint8_t gs_type; - uint8_t gs_subtype; - uint8_t options; - uint8_t reserved; -}; - -/* CT command request */ -struct ct_sns_req { - struct ct_cmd_hdr header; - uint16_t command; - uint16_t max_rsp_size; - uint8_t fragment_id; - uint8_t reserved[3]; - - union { - /* GA_NXT, GPN_ID, GNN_ID, GFT_ID, GFPN_ID */ - struct { - uint8_t reserved; - uint8_t port_id[3]; - } port_id; - - struct { - uint8_t port_type; - uint8_t domain; - uint8_t area; - uint8_t reserved; - } gid_pt; - - struct { - uint8_t reserved; - uint8_t port_id[3]; - uint8_t fc4_types[32]; - } rft_id; - - struct { - uint8_t reserved; - uint8_t port_id[3]; - uint16_t reserved2; - uint8_t fc4_feature; - uint8_t fc4_type; - } rff_id; - - struct { - uint8_t reserved; - uint8_t port_id[3]; - uint8_t node_name[8]; - } rnn_id; - - struct { - uint8_t node_name[8]; - uint8_t name_len; - uint8_t sym_node_name[255]; - } rsnn_nn; - - struct { - uint8_t hba_indentifier[8]; - } ghat; - - struct { - uint8_t hba_identifier[8]; - uint32_t entry_count; - uint8_t port_name[8]; - struct ct_fdmi_hba_attributes attrs; - } rhba; - - struct { - uint8_t hba_identifier[8]; - struct ct_fdmi_hba_attributes attrs; - } rhat; - - struct { - uint8_t port_name[8]; - struct ct_fdmi_port_attributes attrs; - } rpa; - - struct { - uint8_t port_name[8]; - } dhba; - - struct { - uint8_t port_name[8]; - } dhat; - - struct { - uint8_t port_name[8]; - } dprt; - - struct { - uint8_t port_name[8]; - } dpa; - - struct { - uint8_t port_name[8]; - } gpsc; - - struct { - uint8_t reserved; - uint8_t port_name[3]; - } gff_id; - } req; -}; - -/* CT command response header */ -struct ct_rsp_hdr { - struct ct_cmd_hdr header; - uint16_t response; - uint16_t residual; - uint8_t fragment_id; - uint8_t reason_code; - uint8_t explanation_code; - uint8_t vendor_unique; -}; - -struct ct_sns_gid_pt_data { - uint8_t control_byte; - uint8_t port_id[3]; -}; - -struct ct_sns_rsp { - struct ct_rsp_hdr header; - - union { - struct { - uint8_t port_type; - uint8_t port_id[3]; - uint8_t port_name[8]; - uint8_t sym_port_name_len; - uint8_t sym_port_name[255]; - uint8_t node_name[8]; - uint8_t sym_node_name_len; - uint8_t sym_node_name[255]; - uint8_t init_proc_assoc[8]; - uint8_t node_ip_addr[16]; - uint8_t class_of_service[4]; - uint8_t fc4_types[32]; - uint8_t ip_address[16]; - uint8_t fabric_port_name[8]; - uint8_t reserved; - uint8_t hard_address[3]; - } ga_nxt; - - struct { - /* Assume the largest number of targets for the union */ - struct ct_sns_gid_pt_data - entries[MAX_FIBRE_DEVICES_MAX]; - } gid_pt; - - struct { - uint8_t port_name[8]; - } gpn_id; - - struct { - uint8_t node_name[8]; - } gnn_id; - - struct { - uint8_t fc4_types[32]; - } gft_id; - - struct { - uint32_t entry_count; - uint8_t port_name[8]; - struct ct_fdmi_hba_attributes attrs; - } ghat; - - struct { - uint8_t port_name[8]; - } gfpn_id; - - struct { - uint16_t speeds; - uint16_t speed; - } gpsc; - -#define GFF_FCP_SCSI_OFFSET 7 - struct { - uint8_t fc4_features[128]; - } gff_id; - } rsp; -}; - -struct ct_sns_pkt { - union { - struct ct_sns_req req; - struct ct_sns_rsp rsp; - } p; -}; - -/* - * SNS command structures -- for 2200 compatibility. - */ -#define RFT_ID_SNS_SCMD_LEN 22 -#define RFT_ID_SNS_CMD_SIZE 60 -#define RFT_ID_SNS_DATA_SIZE 16 - -#define RNN_ID_SNS_SCMD_LEN 10 -#define RNN_ID_SNS_CMD_SIZE 36 -#define RNN_ID_SNS_DATA_SIZE 16 - -#define GA_NXT_SNS_SCMD_LEN 6 -#define GA_NXT_SNS_CMD_SIZE 28 -#define GA_NXT_SNS_DATA_SIZE (620 + 16) - -#define GID_PT_SNS_SCMD_LEN 6 -#define GID_PT_SNS_CMD_SIZE 28 -/* - * Assume MAX_FIBRE_DEVICES_2100 as these defines are only used with older - * adapters. - */ -#define GID_PT_SNS_DATA_SIZE (MAX_FIBRE_DEVICES_2100 * 4 + 16) - -#define GPN_ID_SNS_SCMD_LEN 6 -#define GPN_ID_SNS_CMD_SIZE 28 -#define GPN_ID_SNS_DATA_SIZE (8 + 16) - -#define GNN_ID_SNS_SCMD_LEN 6 -#define GNN_ID_SNS_CMD_SIZE 28 -#define GNN_ID_SNS_DATA_SIZE (8 + 16) - -struct sns_cmd_pkt { - union { - struct { - uint16_t buffer_length; - uint16_t reserved_1; - uint32_t buffer_address[2]; - uint16_t subcommand_length; - uint16_t reserved_2; - uint16_t subcommand; - uint16_t size; - uint32_t reserved_3; - uint8_t param[36]; - } cmd; - - uint8_t rft_data[RFT_ID_SNS_DATA_SIZE]; - uint8_t rnn_data[RNN_ID_SNS_DATA_SIZE]; - uint8_t gan_data[GA_NXT_SNS_DATA_SIZE]; - uint8_t gid_data[GID_PT_SNS_DATA_SIZE]; - uint8_t gpn_data[GPN_ID_SNS_DATA_SIZE]; - uint8_t gnn_data[GNN_ID_SNS_DATA_SIZE]; - } p; -}; - -struct fw_blob { - char *name; - uint32_t segs[4]; - const struct firmware *fw; -}; - -/* Return data from MBC_GET_ID_LIST call. */ -struct gid_list_info { - uint8_t al_pa; - uint8_t area; - uint8_t domain; - uint8_t loop_id_2100; /* ISP2100/ISP2200 -- 4 bytes. */ - uint16_t loop_id; /* ISP23XX -- 6 bytes. */ - uint16_t reserved_1; /* ISP24XX -- 8 bytes. */ -}; - -/* NPIV */ -typedef struct vport_info { - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; - int vp_id; - uint16_t loop_id; - unsigned long host_no; - uint8_t port_id[3]; - int loop_state; -} vport_info_t; - -typedef struct vport_params { - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; - uint32_t options; -#define VP_OPTS_RETRY_ENABLE BIT_0 -#define VP_OPTS_VP_DISABLE BIT_1 -} vport_params_t; - -/* NPIV - return codes of VP create and modify */ -#define VP_RET_CODE_OK 0 -#define VP_RET_CODE_FATAL 1 -#define VP_RET_CODE_WRONG_ID 2 -#define VP_RET_CODE_WWPN 3 -#define VP_RET_CODE_RESOURCES 4 -#define VP_RET_CODE_NO_MEM 5 -#define VP_RET_CODE_NOT_FOUND 6 - -struct qla_hw_data; -struct rsp_que; -/* - * ISP operations - */ -struct isp_operations { - - int (*pci_config) (struct scsi_qla_host *); - void (*reset_chip) (struct scsi_qla_host *); - int (*chip_diag) (struct scsi_qla_host *); - void (*config_rings) (struct scsi_qla_host *); - void (*reset_adapter) (struct scsi_qla_host *); - int (*nvram_config) (struct scsi_qla_host *); - void (*update_fw_options) (struct scsi_qla_host *); - int (*load_risc) (struct scsi_qla_host *, uint32_t *); - - char * (*pci_info_str) (struct scsi_qla_host *, char *); - char * (*fw_version_str) (struct scsi_qla_host *, char *); - - irq_handler_t intr_handler; - void (*enable_intrs) (struct qla_hw_data *); - void (*disable_intrs) (struct qla_hw_data *); - - int (*abort_command) (srb_t *); - int (*target_reset) (struct fc_port *, unsigned int, int); - int (*lun_reset) (struct fc_port *, unsigned int, int); - int (*fabric_login) (struct scsi_qla_host *, uint16_t, uint8_t, - uint8_t, uint8_t, uint16_t *, uint8_t); - int (*fabric_logout) (struct scsi_qla_host *, uint16_t, uint8_t, - uint8_t, uint8_t); - - uint16_t (*calc_req_entries) (uint16_t); - void (*build_iocbs) (srb_t *, cmd_entry_t *, uint16_t); - void * (*prep_ms_iocb) (struct scsi_qla_host *, uint32_t, uint32_t); - void * (*prep_ms_fdmi_iocb) (struct scsi_qla_host *, uint32_t, - uint32_t); - - uint8_t * (*read_nvram) (struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); - int (*write_nvram) (struct scsi_qla_host *, uint8_t *, uint32_t, - uint32_t); - - void (*fw_dump) (struct scsi_qla_host *, int); - - int (*beacon_on) (struct scsi_qla_host *); - int (*beacon_off) (struct scsi_qla_host *); - void (*beacon_blink) (struct scsi_qla_host *); - - uint8_t * (*read_optrom) (struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); - int (*write_optrom) (struct scsi_qla_host *, uint8_t *, uint32_t, - uint32_t); - - int (*get_flash_version) (struct scsi_qla_host *, void *); - int (*start_scsi) (srb_t *); - int (*abort_isp) (struct scsi_qla_host *); - int (*iospace_config)(struct qla_hw_data*); -}; - -/* MSI-X Support *************************************************************/ - -#define QLA_MSIX_CHIP_REV_24XX 3 -#define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7) -#define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1) - -#define QLA_MSIX_DEFAULT 0x00 -#define QLA_MSIX_RSP_Q 0x01 - -#define QLA_MIDX_DEFAULT 0 -#define QLA_MIDX_RSP_Q 1 -#define QLA_PCI_MSIX_CONTROL 0xa2 -#define QLA_83XX_PCI_MSIX_CONTROL 0x92 - -struct scsi_qla_host; - -struct qla_msix_entry { - int have_irq; - uint32_t vector; - uint16_t entry; - struct rsp_que *rsp; -}; - -#define WATCH_INTERVAL 1 /* number of seconds */ - -/* Work events. */ -enum qla_work_type { - QLA_EVT_AEN, - QLA_EVT_IDC_ACK, - QLA_EVT_ASYNC_LOGIN, - QLA_EVT_ASYNC_LOGIN_DONE, - QLA_EVT_ASYNC_LOGOUT, - QLA_EVT_ASYNC_LOGOUT_DONE, - QLA_EVT_ASYNC_ADISC, - QLA_EVT_ASYNC_ADISC_DONE, - QLA_EVT_UEVENT, -}; - - -struct qla_work_evt { - struct list_head list; - enum qla_work_type type; - u32 flags; -#define QLA_EVT_FLAG_FREE 0x1 - - union { - struct { - enum fc_host_event_code code; - u32 data; - } aen; - struct { -#define QLA_IDC_ACK_REGS 7 - uint16_t mb[QLA_IDC_ACK_REGS]; - } idc_ack; - struct { - struct fc_port *fcport; -#define QLA_LOGIO_LOGIN_RETRIED BIT_0 - u16 data[2]; - } logio; - struct { - u32 code; -#define QLA_UEVENT_CODE_FW_DUMP 0 - } uevent; - } u; -}; - -struct qla_chip_state_84xx { - struct list_head list; - struct kref kref; - - void *bus; - spinlock_t access_lock; - struct mutex fw_update_mutex; - uint32_t fw_update; - uint32_t op_fw_version; - uint32_t op_fw_size; - uint32_t op_fw_seq_size; - uint32_t diag_fw_version; - uint32_t gold_fw_version; -}; - -struct qla_statistics { - uint32_t total_isp_aborts; - uint64_t input_bytes; - uint64_t output_bytes; -}; - -/* Multi queue support */ -#define MBC_INITIALIZE_MULTIQ 0x1f -#define QLA_QUE_PAGE 0X1000 -#define QLA_MQ_SIZE 32 -#define QLA_MAX_QUEUES 256 -#define ISP_QUE_REG(ha, id) \ - ((ha->mqenable || IS_QLA83XX(ha)) ? \ - ((void *)(ha->mqiobase) +\ - (QLA_QUE_PAGE * id)) :\ - ((void *)(ha->iobase))) -#define QLA_REQ_QUE_ID(tag) \ - ((tag < QLA_MAX_QUEUES && tag > 0) ? tag : 0) -#define QLA_DEFAULT_QUE_QOS 5 -#define QLA_PRECONFIG_VPORTS 32 -#define QLA_MAX_VPORTS_QLA24XX 128 -#define QLA_MAX_VPORTS_QLA25XX 256 -/* Response queue data structure */ -struct rsp_que { - dma_addr_t dma; - response_t *ring; - response_t *ring_ptr; - uint32_t __iomem *rsp_q_in; /* FWI2-capable only. */ - uint32_t __iomem *rsp_q_out; - uint16_t ring_index; - uint16_t out_ptr; - uint16_t length; - uint16_t options; - uint16_t rid; - uint16_t id; - uint16_t vp_idx; - struct qla_hw_data *hw; - struct qla_msix_entry *msix; - struct req_que *req; - srb_t *status_srb; /* status continuation entry */ - struct work_struct q_work; -}; - -/* Request queue data structure */ -struct req_que { - dma_addr_t dma; - request_t *ring; - request_t *ring_ptr; - uint32_t __iomem *req_q_in; /* FWI2-capable only. */ - uint32_t __iomem *req_q_out; - uint16_t ring_index; - uint16_t in_ptr; - uint16_t cnt; - uint16_t length; - uint16_t options; - uint16_t rid; - uint16_t id; - uint16_t qos; - uint16_t vp_idx; - struct rsp_que *rsp; - srb_t *outstanding_cmds[MAX_OUTSTANDING_COMMANDS]; - uint32_t current_outstanding_cmd; - int max_q_depth; -}; - -/* Place holder for FW buffer parameters */ -struct qlfc_fw { - void *fw_buf; - dma_addr_t fw_dma; - uint32_t len; -}; - -/* - * Qlogic host adapter specific data structure. -*/ -struct qla_hw_data { - struct pci_dev *pdev; - /* SRB cache. */ -#define SRB_MIN_REQ 128 - mempool_t *srb_mempool; - - volatile struct { - uint32_t mbox_int :1; - uint32_t mbox_busy :1; - uint32_t disable_risc_code_load :1; - uint32_t enable_64bit_addressing :1; - uint32_t enable_lip_reset :1; - uint32_t enable_target_reset :1; - uint32_t enable_lip_full_login :1; - uint32_t enable_led_scheme :1; - - uint32_t msi_enabled :1; - uint32_t msix_enabled :1; - uint32_t disable_serdes :1; - uint32_t gpsc_supported :1; - uint32_t npiv_supported :1; - uint32_t pci_channel_io_perm_failure :1; - uint32_t fce_enabled :1; - uint32_t fac_supported :1; - - uint32_t chip_reset_done :1; - uint32_t port0 :1; - uint32_t running_gold_fw :1; - uint32_t eeh_busy :1; - uint32_t cpu_affinity_enabled :1; - uint32_t disable_msix_handshake :1; - uint32_t fcp_prio_enabled :1; - uint32_t isp82xx_fw_hung:1; - - uint32_t quiesce_owner:1; - uint32_t thermal_supported:1; - uint32_t isp82xx_reset_hdlr_active:1; - uint32_t isp82xx_reset_owner:1; - /* 28 bits */ - } flags; - - /* This spinlock is used to protect "io transactions", you must - * acquire it before doing any IO to the card, eg with RD_REG*() and - * WRT_REG*() for the duration of your entire commandtransaction. - * - * This spinlock is of lower priority than the io request lock. - */ - - spinlock_t hardware_lock ____cacheline_aligned; - int bars; - int mem_only; - device_reg_t __iomem *iobase; /* Base I/O address */ - resource_size_t pio_address; - -#define MIN_IOBASE_LEN 0x100 -/* Multi queue data structs */ - device_reg_t __iomem *mqiobase; - device_reg_t __iomem *msixbase; - uint16_t msix_count; - uint8_t mqenable; - struct req_que **req_q_map; - struct rsp_que **rsp_q_map; - unsigned long req_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)]; - unsigned long rsp_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)]; - uint8_t max_req_queues; - uint8_t max_rsp_queues; - struct qla_npiv_entry *npiv_info; - uint16_t nvram_npiv_size; - - uint16_t switch_cap; -#define FLOGI_SEQ_DEL BIT_8 -#define FLOGI_MID_SUPPORT BIT_10 -#define FLOGI_VSAN_SUPPORT BIT_12 -#define FLOGI_SP_SUPPORT BIT_13 - - uint8_t port_no; /* Physical port of adapter */ - - /* Timeout timers. */ - uint8_t loop_down_abort_time; /* port down timer */ - atomic_t loop_down_timer; /* loop down timer */ - uint8_t link_down_timeout; /* link down timeout */ - uint16_t max_loop_id; - uint16_t max_fibre_devices; /* Maximum number of targets */ - - uint16_t fb_rev; - uint16_t min_external_loopid; /* First external loop Id */ - -#define PORT_SPEED_UNKNOWN 0xFFFF -#define PORT_SPEED_1GB 0x00 -#define PORT_SPEED_2GB 0x01 -#define PORT_SPEED_4GB 0x03 -#define PORT_SPEED_8GB 0x04 -#define PORT_SPEED_16GB 0x05 -#define PORT_SPEED_10GB 0x13 - uint16_t link_data_rate; /* F/W operating speed */ - - uint8_t current_topology; - uint8_t prev_topology; -#define ISP_CFG_NL 1 -#define ISP_CFG_N 2 -#define ISP_CFG_FL 4 -#define ISP_CFG_F 8 - - uint8_t operating_mode; /* F/W operating mode */ -#define LOOP 0 -#define P2P 1 -#define LOOP_P2P 2 -#define P2P_LOOP 3 - uint8_t interrupts_on; - uint32_t isp_abort_cnt; - -#define PCI_DEVICE_ID_QLOGIC_ISP2532 0x2532 -#define PCI_DEVICE_ID_QLOGIC_ISP8432 0x8432 -#define PCI_DEVICE_ID_QLOGIC_ISP8001 0x8001 -#define PCI_DEVICE_ID_QLOGIC_ISP8031 0x8031 -#define PCI_DEVICE_ID_QLOGIC_ISP2031 0x2031 - uint32_t device_type; -#define DT_ISP2100 BIT_0 -#define DT_ISP2200 BIT_1 -#define DT_ISP2300 BIT_2 -#define DT_ISP2312 BIT_3 -#define DT_ISP2322 BIT_4 -#define DT_ISP6312 BIT_5 -#define DT_ISP6322 BIT_6 -#define DT_ISP2422 BIT_7 -#define DT_ISP2432 BIT_8 -#define DT_ISP5422 BIT_9 -#define DT_ISP5432 BIT_10 -#define DT_ISP2532 BIT_11 -#define DT_ISP8432 BIT_12 -#define DT_ISP8001 BIT_13 -#define DT_ISP8021 BIT_14 -#define DT_ISP2031 BIT_15 -#define DT_ISP8031 BIT_16 -#define DT_ISP_LAST (DT_ISP8031 << 1) - -#define DT_T10_PI BIT_25 -#define DT_IIDMA BIT_26 -#define DT_FWI2 BIT_27 -#define DT_ZIO_SUPPORTED BIT_28 -#define DT_OEM_001 BIT_29 -#define DT_ISP2200A BIT_30 -#define DT_EXTENDED_IDS BIT_31 -#define DT_MASK(ha) ((ha)->device_type & (DT_ISP_LAST - 1)) -#define IS_QLA2100(ha) (DT_MASK(ha) & DT_ISP2100) -#define IS_QLA2200(ha) (DT_MASK(ha) & DT_ISP2200) -#define IS_QLA2300(ha) (DT_MASK(ha) & DT_ISP2300) -#define IS_QLA2312(ha) (DT_MASK(ha) & DT_ISP2312) -#define IS_QLA2322(ha) (DT_MASK(ha) & DT_ISP2322) -#define IS_QLA6312(ha) (DT_MASK(ha) & DT_ISP6312) -#define IS_QLA6322(ha) (DT_MASK(ha) & DT_ISP6322) -#define IS_QLA2422(ha) (DT_MASK(ha) & DT_ISP2422) -#define IS_QLA2432(ha) (DT_MASK(ha) & DT_ISP2432) -#define IS_QLA5422(ha) (DT_MASK(ha) & DT_ISP5422) -#define IS_QLA5432(ha) (DT_MASK(ha) & DT_ISP5432) -#define IS_QLA2532(ha) (DT_MASK(ha) & DT_ISP2532) -#define IS_QLA8432(ha) (DT_MASK(ha) & DT_ISP8432) -#define IS_QLA8001(ha) (DT_MASK(ha) & DT_ISP8001) -#define IS_QLA81XX(ha) (IS_QLA8001(ha)) -#define IS_QLA82XX(ha) (DT_MASK(ha) & DT_ISP8021) -#define IS_QLA2031(ha) (DT_MASK(ha) & DT_ISP2031) -#define IS_QLA8031(ha) (DT_MASK(ha) & DT_ISP8031) - -#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \ - IS_QLA6312(ha) || IS_QLA6322(ha)) -#define IS_QLA24XX(ha) (IS_QLA2422(ha) || IS_QLA2432(ha)) -#define IS_QLA54XX(ha) (IS_QLA5422(ha) || IS_QLA5432(ha)) -#define IS_QLA25XX(ha) (IS_QLA2532(ha)) -#define IS_QLA83XX(ha) (IS_QLA2031(ha) || IS_QLA8031(ha)) -#define IS_QLA84XX(ha) (IS_QLA8432(ha)) -#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \ - IS_QLA84XX(ha)) -#define IS_CNA_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha) || \ - IS_QLA8031(ha)) -#define IS_QLA2XXX_MIDTYPE(ha) (IS_QLA24XX(ha) || IS_QLA84XX(ha) || \ - IS_QLA25XX(ha) || IS_QLA81XX(ha) || \ - IS_QLA82XX(ha) || IS_QLA83XX(ha)) -#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha)) -#define IS_NOPOLLING_TYPE(ha) ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || \ - IS_QLA83XX(ha)) && (ha)->flags.msix_enabled) -#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha)) -#define IS_NOCACHE_VPD_TYPE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha)) -#define IS_ALOGIO_CAPABLE(ha) (IS_QLA23XX(ha) || IS_FWI2_CAPABLE(ha)) - -#define IS_T10_PI_CAPABLE(ha) ((ha)->device_type & DT_T10_PI) -#define IS_IIDMA_CAPABLE(ha) ((ha)->device_type & DT_IIDMA) -#define IS_FWI2_CAPABLE(ha) ((ha)->device_type & DT_FWI2) -#define IS_ZIO_SUPPORTED(ha) ((ha)->device_type & DT_ZIO_SUPPORTED) -#define IS_OEM_001(ha) ((ha)->device_type & DT_OEM_001) -#define HAS_EXTENDED_IDS(ha) ((ha)->device_type & DT_EXTENDED_IDS) -#define IS_CT6_SUPPORTED(ha) ((ha)->device_type & DT_CT6_SUPPORTED) -#define IS_MQUE_CAPABLE(ha) ((ha)->mqenable || IS_QLA83XX(ha)) - - /* HBA serial number */ - uint8_t serial0; - uint8_t serial1; - uint8_t serial2; - - /* NVRAM configuration data */ -#define MAX_NVRAM_SIZE 4096 -#define VPD_OFFSET MAX_NVRAM_SIZE / 2 - uint16_t nvram_size; - uint16_t nvram_base; - void *nvram; - uint16_t vpd_size; - uint16_t vpd_base; - void *vpd; - - uint16_t loop_reset_delay; - uint8_t retry_count; - uint8_t login_timeout; - uint16_t r_a_tov; - int port_down_retry_count; - uint8_t mbx_count; - - uint32_t login_retry_count; - /* SNS command interfaces. */ - ms_iocb_entry_t *ms_iocb; - dma_addr_t ms_iocb_dma; - struct ct_sns_pkt *ct_sns; - dma_addr_t ct_sns_dma; - /* SNS command interfaces for 2200. */ - struct sns_cmd_pkt *sns_cmd; - dma_addr_t sns_cmd_dma; - -#define SFP_DEV_SIZE 256 -#define SFP_BLOCK_SIZE 64 - void *sfp_data; - dma_addr_t sfp_data_dma; - -#define XGMAC_DATA_SIZE 4096 - void *xgmac_data; - dma_addr_t xgmac_data_dma; - -#define DCBX_TLV_DATA_SIZE 4096 - void *dcbx_tlv; - dma_addr_t dcbx_tlv_dma; - - struct task_struct *dpc_thread; - uint8_t dpc_active; /* DPC routine is active */ - - dma_addr_t gid_list_dma; - struct gid_list_info *gid_list; - int gid_list_info_size; - - /* Small DMA pool allocations -- maximum 256 bytes in length. */ -#define DMA_POOL_SIZE 256 - struct dma_pool *s_dma_pool; - - dma_addr_t init_cb_dma; - init_cb_t *init_cb; - int init_cb_size; - dma_addr_t ex_init_cb_dma; - struct ex_init_cb_81xx *ex_init_cb; - - void *async_pd; - dma_addr_t async_pd_dma; - - void *swl; - - /* These are used by mailbox operations. */ - volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT]; - - mbx_cmd_t *mcp; - unsigned long mbx_cmd_flags; -#define MBX_INTERRUPT 1 -#define MBX_INTR_WAIT 2 -#define MBX_UPDATE_FLASH_ACTIVE 3 - - struct mutex vport_lock; /* Virtual port synchronization */ - spinlock_t vport_slock; /* order is hardware_lock, then vport_slock */ - struct completion mbx_cmd_comp; /* Serialize mbx access */ - struct completion mbx_intr_comp; /* Used for completion notification */ - struct completion dcbx_comp; /* For set port config notification */ - int notify_dcbx_comp; - - /* Basic firmware related information. */ - uint16_t fw_major_version; - uint16_t fw_minor_version; - uint16_t fw_subminor_version; - uint16_t fw_attributes; - uint16_t fw_attributes_h; - uint16_t fw_attributes_ext[2]; - uint32_t fw_memory_size; - uint32_t fw_transfer_size; - uint32_t fw_srisc_address; -#define RISC_START_ADDRESS_2100 0x1000 -#define RISC_START_ADDRESS_2300 0x800 -#define RISC_START_ADDRESS_2400 0x100000 - uint16_t fw_xcb_count; - - uint16_t fw_options[16]; /* slots: 1,2,3,10,11 */ - uint8_t fw_seriallink_options[4]; - uint16_t fw_seriallink_options24[4]; - - uint8_t mpi_version[3]; - uint32_t mpi_capabilities; - uint8_t phy_version[3]; - - /* Firmware dump information. */ - struct qla2xxx_fw_dump *fw_dump; - uint32_t fw_dump_len; - int fw_dumped; - int fw_dump_reading; - dma_addr_t eft_dma; - void *eft; - - uint32_t chain_offset; - struct dentry *dfs_dir; - struct dentry *dfs_fce; - dma_addr_t fce_dma; - void *fce; - uint32_t fce_bufs; - uint16_t fce_mb[8]; - uint64_t fce_wr, fce_rd; - struct mutex fce_mutex; - - uint32_t pci_attr; - uint16_t chip_revision; - - uint16_t product_id[4]; - - uint8_t model_number[16+1]; -#define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" - char model_desc[80]; - uint8_t adapter_id[16+1]; - - /* Option ROM information. */ - char *optrom_buffer; - uint32_t optrom_size; - int optrom_state; -#define QLA_SWAITING 0 -#define QLA_SREADING 1 -#define QLA_SWRITING 2 - uint32_t optrom_region_start; - uint32_t optrom_region_size; - -/* PCI expansion ROM image information. */ -#define ROM_CODE_TYPE_BIOS 0 -#define ROM_CODE_TYPE_FCODE 1 -#define ROM_CODE_TYPE_EFI 3 - uint8_t bios_revision[2]; - uint8_t efi_revision[2]; - uint8_t fcode_revision[16]; - uint32_t fw_revision[4]; - - uint32_t gold_fw_version[4]; - - /* Offsets for flash/nvram access (set to ~0 if not used). */ - uint32_t flash_conf_off; - uint32_t flash_data_off; - uint32_t nvram_conf_off; - uint32_t nvram_data_off; - - uint32_t fdt_wrt_disable; - uint32_t fdt_erase_cmd; - uint32_t fdt_block_size; - uint32_t fdt_unprotect_sec_cmd; - uint32_t fdt_protect_sec_cmd; - - uint32_t flt_region_flt; - uint32_t flt_region_fdt; - uint32_t flt_region_boot; - uint32_t flt_region_fw; - uint32_t flt_region_vpd_nvram; - uint32_t flt_region_vpd; - uint32_t flt_region_nvram; - uint32_t flt_region_npiv_conf; - uint32_t flt_region_gold_fw; - uint32_t flt_region_fcp_prio; - uint32_t flt_region_bootload; - - /* Needed for BEACON */ - uint16_t beacon_blink_led; - uint8_t beacon_color_state; -#define QLA_LED_GRN_ON 0x01 -#define QLA_LED_YLW_ON 0x02 -#define QLA_LED_ABR_ON 0x04 -#define QLA_LED_ALL_ON 0x07 /* yellow, green, amber. */ - /* ISP2322: red, green, amber. */ - uint16_t zio_mode; - uint16_t zio_timer; - struct fc_host_statistics fc_host_stat; - - struct qla_msix_entry *msix_entries; - - struct list_head vp_list; /* list of VP */ - unsigned long vp_idx_map[(MAX_MULTI_ID_FABRIC / 8) / - sizeof(unsigned long)]; - uint16_t num_vhosts; /* number of vports created */ - uint16_t num_vsans; /* number of vsan created */ - uint16_t max_npiv_vports; /* 63 or 125 per topoloty */ - int cur_vport_count; - - struct qla_chip_state_84xx *cs84xx; - struct qla_statistics qla_stats; - struct isp_operations *isp_ops; - struct workqueue_struct *wq; - struct qlfc_fw fw_buf; - - /* FCP_CMND priority support */ - struct qla_fcp_prio_cfg *fcp_prio_cfg; - - struct dma_pool *dl_dma_pool; -#define DSD_LIST_DMA_POOL_SIZE 512 - - struct dma_pool *fcp_cmnd_dma_pool; - mempool_t *ctx_mempool; -#define FCP_CMND_DMA_POOL_SIZE 512 - - unsigned long nx_pcibase; /* Base I/O address */ - uint8_t *nxdb_rd_ptr; /* Doorbell read pointer */ - unsigned long nxdb_wr_ptr; /* Door bell write pointer */ - - uint32_t crb_win; - uint32_t curr_window; - uint32_t ddr_mn_window; - unsigned long mn_win_crb; - unsigned long ms_win_crb; - int qdr_sn_window; - uint32_t nx_dev_init_timeout; - uint32_t nx_reset_timeout; - rwlock_t hw_lock; - uint16_t portnum; /* port number */ - int link_width; - struct fw_blob *hablob; - struct qla82xx_legacy_intr_set nx_legacy_intr; - - uint16_t gbl_dsd_inuse; - uint16_t gbl_dsd_avail; - struct list_head gbl_dsd_list; -#define NUM_DSD_CHAIN 4096 - - uint8_t fw_type; - __le32 file_prd_off; /* File firmware product offset */ - - uint32_t md_template_size; - void *md_tmplt_hdr; - dma_addr_t md_tmplt_hdr_dma; - void *md_dump; - uint32_t md_dump_size; -}; - -/* - * Qlogic scsi host structure - */ -typedef struct scsi_qla_host { - struct list_head list; - struct list_head vp_fcports; /* list of fcports */ - struct list_head work_list; - spinlock_t work_lock; - - /* Commonly used flags and state information. */ - struct Scsi_Host *host; - unsigned long host_no; - uint8_t host_str[16]; - - volatile struct { - uint32_t init_done :1; - uint32_t online :1; - uint32_t reset_active :1; - - uint32_t management_server_logged_in :1; - uint32_t process_response_queue :1; - uint32_t difdix_supported:1; - uint32_t delete_progress:1; - } flags; - - atomic_t loop_state; -#define LOOP_TIMEOUT 1 -#define LOOP_DOWN 2 -#define LOOP_UP 3 -#define LOOP_UPDATE 4 -#define LOOP_READY 5 -#define LOOP_DEAD 6 - - unsigned long dpc_flags; -#define RESET_MARKER_NEEDED 0 /* Send marker to ISP. */ -#define RESET_ACTIVE 1 -#define ISP_ABORT_NEEDED 2 /* Initiate ISP abort. */ -#define ABORT_ISP_ACTIVE 3 /* ISP abort in progress. */ -#define LOOP_RESYNC_NEEDED 4 /* Device Resync needed. */ -#define LOOP_RESYNC_ACTIVE 5 -#define LOCAL_LOOP_UPDATE 6 /* Perform a local loop update. */ -#define RSCN_UPDATE 7 /* Perform an RSCN update. */ -#define RELOGIN_NEEDED 8 -#define REGISTER_FC4_NEEDED 9 /* SNS FC4 registration required. */ -#define ISP_ABORT_RETRY 10 /* ISP aborted. */ -#define BEACON_BLINK_NEEDED 11 -#define REGISTER_FDMI_NEEDED 12 -#define FCPORT_UPDATE_NEEDED 13 -#define VP_DPC_NEEDED 14 /* wake up for VP dpc handling */ -#define UNLOADING 15 -#define NPIV_CONFIG_NEEDED 16 -#define ISP_UNRECOVERABLE 17 -#define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */ -#define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */ -#define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */ - - uint32_t device_flags; -#define SWITCH_FOUND BIT_0 -#define DFLG_NO_CABLE BIT_1 -#define DFLG_DEV_FAILED BIT_5 - - /* ISP configuration data. */ - uint16_t loop_id; /* Host adapter loop id */ - - port_id_t d_id; /* Host adapter port id */ - uint8_t marker_needed; - uint16_t mgmt_svr_loop_id; - - - - /* Timeout timers. */ - uint8_t loop_down_abort_time; /* port down timer */ - atomic_t loop_down_timer; /* loop down timer */ - uint8_t link_down_timeout; /* link down timeout */ - - uint32_t timer_active; - struct timer_list timer; - - uint8_t node_name[WWN_SIZE]; - uint8_t port_name[WWN_SIZE]; - uint8_t fabric_node_name[WWN_SIZE]; - - uint16_t fcoe_vlan_id; - uint16_t fcoe_fcf_idx; - uint8_t fcoe_vn_port_mac[6]; - - uint32_t vp_abort_cnt; - - struct fc_vport *fc_vport; /* holds fc_vport * for each vport */ - uint16_t vp_idx; /* vport ID */ - - unsigned long vp_flags; -#define VP_IDX_ACQUIRED 0 /* bit no 0 */ -#define VP_CREATE_NEEDED 1 -#define VP_BIND_NEEDED 2 -#define VP_DELETE_NEEDED 3 -#define VP_SCR_NEEDED 4 /* State Change Request registration */ - atomic_t vp_state; -#define VP_OFFLINE 0 -#define VP_ACTIVE 1 -#define VP_FAILED 2 -// #define VP_DISABLE 3 - uint16_t vp_err_state; - uint16_t vp_prev_err_state; -#define VP_ERR_UNKWN 0 -#define VP_ERR_PORTDWN 1 -#define VP_ERR_FAB_UNSUPPORTED 2 -#define VP_ERR_FAB_NORESOURCES 3 -#define VP_ERR_FAB_LOGOUT 4 -#define VP_ERR_ADAP_NORESOURCES 5 - struct qla_hw_data *hw; - struct req_que *req; - int fw_heartbeat_counter; - int seconds_since_last_heartbeat; - - atomic_t vref_count; -} scsi_qla_host_t; - -/* - * Macros to help code, maintain, etc. - */ -#define LOOP_TRANSITION(ha) \ - (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \ - test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \ - atomic_read(&ha->loop_state) == LOOP_DOWN) - -#define QLA_VHA_MARK_BUSY(__vha, __bail) do { \ - atomic_inc(&__vha->vref_count); \ - mb(); \ - if (__vha->flags.delete_progress) { \ - atomic_dec(&__vha->vref_count); \ - __bail = 1; \ - } else { \ - __bail = 0; \ - } \ -} while (0) - -#define QLA_VHA_MARK_NOT_BUSY(__vha) do { \ - atomic_dec(&__vha->vref_count); \ -} while (0) - -/* - * qla2x00 local function return status codes - */ -#define MBS_MASK 0x3fff - -#define QLA_SUCCESS (MBS_COMMAND_COMPLETE & MBS_MASK) -#define QLA_INVALID_COMMAND (MBS_INVALID_COMMAND & MBS_MASK) -#define QLA_INTERFACE_ERROR (MBS_HOST_INTERFACE_ERROR & MBS_MASK) -#define QLA_TEST_FAILED (MBS_TEST_FAILED & MBS_MASK) -#define QLA_COMMAND_ERROR (MBS_COMMAND_ERROR & MBS_MASK) -#define QLA_PARAMETER_ERROR (MBS_COMMAND_PARAMETER_ERROR & MBS_MASK) -#define QLA_PORT_ID_USED (MBS_PORT_ID_USED & MBS_MASK) -#define QLA_LOOP_ID_USED (MBS_LOOP_ID_USED & MBS_MASK) -#define QLA_ALL_IDS_IN_USE (MBS_ALL_IDS_IN_USE & MBS_MASK) -#define QLA_NOT_LOGGED_IN (MBS_NOT_LOGGED_IN & MBS_MASK) - -#define QLA_FUNCTION_TIMEOUT 0x100 -#define QLA_FUNCTION_PARAMETER_ERROR 0x101 -#define QLA_FUNCTION_FAILED 0x102 -#define QLA_MEMORY_ALLOC_FAILED 0x103 -#define QLA_LOCK_TIMEOUT 0x104 -#define QLA_ABORTED 0x105 -#define QLA_SUSPENDED 0x106 -#define QLA_BUSY 0x107 -#define QLA_ALREADY_REGISTERED 0x109 - -#define NVRAM_DELAY() udelay(10) - -#define INVALID_HANDLE (MAX_OUTSTANDING_COMMANDS+1) - -/* - * Flash support definitions - */ -#define OPTROM_SIZE_2300 0x20000 -#define OPTROM_SIZE_2322 0x100000 -#define OPTROM_SIZE_24XX 0x100000 -#define OPTROM_SIZE_25XX 0x200000 -#define OPTROM_SIZE_81XX 0x400000 -#define OPTROM_SIZE_82XX 0x800000 -#define OPTROM_SIZE_83XX 0x1000000 - -#define OPTROM_BURST_SIZE 0x1000 -#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) - -#define QLA_DSDS_PER_IOCB 37 - -#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) - -#define QLA_SG_ALL 1024 - -enum nexus_wait_type { - WAIT_HOST = 0, - WAIT_TARGET, - WAIT_LUN, -}; - -#include "qla_gbl.h" -#include "qla_dbg.h" -#include "qla_inline.h" -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_devtbl.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_devtbl.h deleted file mode 100644 index d6ea69df..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_devtbl.h +++ /dev/null @@ -1,99 +0,0 @@ -#define QLA_MODEL_NAMES 0x5C - -/* - * Adapter model names and descriptions. - */ -static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = { - "QLA2340", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x100 */ - "QLA2342", "133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x101 */ - "QLA2344", "133MHz PCI-X to 2Gb FC, Quad Channel", /* 0x102 */ - "QCP2342", "cPCI to 2Gb FC, Dual Channel", /* 0x103 */ - "QSB2340", "SBUS to 2Gb FC, Single Channel", /* 0x104 */ - "QSB2342", "SBUS to 2Gb FC, Dual Channel", /* 0x105 */ - "QLA2310", "Sun 66MHz PCI-X to 2Gb FC, Single Channel", /* 0x106 */ - "QLA2332", "Sun 66MHz PCI-X to 2Gb FC, Single Channel", /* 0x107 */ - "QCP2332", "Sun cPCI to 2Gb FC, Dual Channel", /* 0x108 */ - "QCP2340", "cPCI to 2Gb FC, Single Channel", /* 0x109 */ - "QLA2342", "Sun 133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x10a */ - "QCP2342", "Sun - cPCI to 2Gb FC, Dual Channel", /* 0x10b */ - "QLA2350", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x10c */ - "QLA2352", "133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x10d */ - "QLA2352", "Sun 133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x10e */ - " ", " ", /* 0x10f */ - " ", " ", /* 0x110 */ - " ", " ", /* 0x111 */ - " ", " ", /* 0x112 */ - " ", " ", /* 0x113 */ - " ", " ", /* 0x114 */ - "QLA2360", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x115 */ - "QLA2362", "133MHz PCI-X to 2Gb FC, Dual Channel", /* 0x116 */ - "QLE2360", "PCI-Express to 2Gb FC, Single Channel", /* 0x117 */ - "QLE2362", "PCI-Express to 2Gb FC, Dual Channel", /* 0x118 */ - "QLA200", "133MHz PCI-X to 2Gb FC Optical", /* 0x119 */ - " ", " ", /* 0x11a */ - " ", " ", /* 0x11b */ - "QLA200P", "133MHz PCI-X to 2Gb FC SFP", /* 0x11c */ - " ", " ", /* 0x11d */ - " ", " ", /* 0x11e */ - " ", " ", /* 0x11f */ - " ", " ", /* 0x120 */ - " ", " ", /* 0x121 */ - " ", " ", /* 0x122 */ - " ", " ", /* 0x123 */ - " ", " ", /* 0x124 */ - " ", " ", /* 0x125 */ - " ", " ", /* 0x126 */ - " ", " ", /* 0x127 */ - " ", " ", /* 0x128 */ - " ", " ", /* 0x129 */ - " ", " ", /* 0x12a */ - " ", " ", /* 0x12b */ - " ", " ", /* 0x12c */ - " ", " ", /* 0x12d */ - " ", " ", /* 0x12e */ - "QLA210", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x12f */ - "EMC 250", "133MHz PCI-X to 2Gb FC, Single Channel", /* 0x130 */ - "HP A7538A", "HP 1p2g PCI-X to 2Gb FC, Single Channel", /* 0x131 */ - "QLA210", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x132 */ - "QLA2460", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x133 */ - "QLA2462", "PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x134 */ - "QMC2462", "IBM eServer BC 4Gb FC Expansion Card", /* 0x135 */ - "QMC2462S", "IBM eServer BC 4Gb FC Expansion Card SFF", /* 0x136 */ - "QLE2460", "PCI-Express to 4Gb FC, Single Channel", /* 0x137 */ - "QLE2462", "PCI-Express to 4Gb FC, Dual Channel", /* 0x138 */ - "QME2462", "Dell BS PCI-Express to 4Gb FC, Dual Channel", /* 0x139 */ - " ", " ", /* 0x13a */ - " ", " ", /* 0x13b */ - " ", " ", /* 0x13c */ - "QEM2462", "Sun Server I/O Module 4Gb FC, Dual Channel", /* 0x13d */ - "QLE210", "PCI-Express to 2Gb FC, Single Channel", /* 0x13e */ - "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x13f */ - "QLA2460", "Sun PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x140 */ - "QLA2462", "Sun PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x141 */ - "QLE2460", "Sun PCI-Express to 2Gb FC, Single Channel", /* 0x142 */ - "QLE2462", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x143 */ - "QEM2462", "Server I/O Module 4Gb FC, Dual Channel", /* 0x144 */ - "QLE2440", "PCI-Express to 4Gb FC, Single Channel", /* 0x145 */ - "QLE2464", "PCI-Express to 4Gb FC, Quad Channel", /* 0x146 */ - "QLA2440", "PCI-X 2.0 to 4Gb FC, Single Channel", /* 0x147 */ - "HP AE369A", "PCI-X 2.0 to 4Gb FC, Dual Channel", /* 0x148 */ - "QLA2340", "Sun 133MHz PCI-X to 2Gb FC, Single Channel", /* 0x149 */ - " ", " ", /* 0x14a */ - " ", " ", /* 0x14b */ - "QMC2432M", "IBM eServer BC 4Gb FC Expansion Card CFFE", /* 0x14c */ - "QMC2422M", "IBM eServer BC 4Gb FC Expansion Card CFFX", /* 0x14d */ - "QLE220", "Sun PCI-Express to 4Gb FC, Single Channel", /* 0x14e */ - " ", " ", /* 0x14f */ - " ", " ", /* 0x150 */ - " ", " ", /* 0x151 */ - "QME2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x152 */ - "QMH2462", "PCI-Express to 4Gb FC, Dual Channel Mezz HBA", /* 0x153 */ - " ", " ", /* 0x154 */ - "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x155 */ - "QLE220", "PCI-Express to 4Gb FC, Single Channel", /* 0x156 */ - " ", " ", /* 0x157 */ - " ", " ", /* 0x158 */ - " ", " ", /* 0x159 */ - " ", " ", /* 0x15a */ - "QME2472", "Dell BS PCI-Express to 4Gb FC, Dual Channel", /* 0x15b */ -}; diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dfs.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dfs.c deleted file mode 100644 index 499c74e3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_dfs.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -#include -#include - -static struct dentry *qla2x00_dfs_root; -static atomic_t qla2x00_dfs_root_count; - -static int -qla2x00_dfs_fce_show(struct seq_file *s, void *unused) -{ - scsi_qla_host_t *vha = s->private; - uint32_t cnt; - uint32_t *fce; - uint64_t fce_start; - struct qla_hw_data *ha = vha->hw; - - mutex_lock(&ha->fce_mutex); - - seq_printf(s, "FCE Trace Buffer\n"); - seq_printf(s, "In Pointer = %llx\n\n", (unsigned long long)ha->fce_wr); - seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma); - seq_printf(s, "FCE Enable Registers\n"); - seq_printf(s, "%08x %08x %08x %08x %08x %08x\n", - ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4], - ha->fce_mb[5], ha->fce_mb[6]); - - fce = (uint32_t *) ha->fce; - fce_start = (unsigned long long) ha->fce_dma; - for (cnt = 0; cnt < fce_calc_size(ha->fce_bufs) / 4; cnt++) { - if (cnt % 8 == 0) - seq_printf(s, "\n%llx: ", - (unsigned long long)((cnt * 4) + fce_start)); - else - seq_printf(s, " "); - seq_printf(s, "%08x", *fce++); - } - - seq_printf(s, "\nEnd\n"); - - mutex_unlock(&ha->fce_mutex); - - return 0; -} - -static int -qla2x00_dfs_fce_open(struct inode *inode, struct file *file) -{ - scsi_qla_host_t *vha = inode->i_private; - struct qla_hw_data *ha = vha->hw; - int rval; - - if (!ha->flags.fce_enabled) - goto out; - - mutex_lock(&ha->fce_mutex); - - /* Pause tracing to flush FCE buffers. */ - rval = qla2x00_disable_fce_trace(vha, &ha->fce_wr, &ha->fce_rd); - if (rval) - ql_dbg(ql_dbg_user, vha, 0x705c, - "DebugFS: Unable to disable FCE (%d).\n", rval); - - ha->flags.fce_enabled = 0; - - mutex_unlock(&ha->fce_mutex); -out: - return single_open(file, qla2x00_dfs_fce_show, vha); -} - -static int -qla2x00_dfs_fce_release(struct inode *inode, struct file *file) -{ - scsi_qla_host_t *vha = inode->i_private; - struct qla_hw_data *ha = vha->hw; - int rval; - - if (ha->flags.fce_enabled) - goto out; - - mutex_lock(&ha->fce_mutex); - - /* Re-enable FCE tracing. */ - ha->flags.fce_enabled = 1; - memset(ha->fce, 0, fce_calc_size(ha->fce_bufs)); - rval = qla2x00_enable_fce_trace(vha, ha->fce_dma, ha->fce_bufs, - ha->fce_mb, &ha->fce_bufs); - if (rval) { - ql_dbg(ql_dbg_user, vha, 0x700d, - "DebugFS: Unable to reinitialize FCE (%d).\n", rval); - ha->flags.fce_enabled = 0; - } - - mutex_unlock(&ha->fce_mutex); -out: - return single_release(inode, file); -} - -static const struct file_operations dfs_fce_ops = { - .open = qla2x00_dfs_fce_open, - .read = seq_read, - .llseek = seq_lseek, - .release = qla2x00_dfs_fce_release, -}; - -int -qla2x00_dfs_setup(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha)) - goto out; - if (!ha->fce) - goto out; - - if (qla2x00_dfs_root) - goto create_dir; - - atomic_set(&qla2x00_dfs_root_count, 0); - qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL); - if (!qla2x00_dfs_root) { - ql_log(ql_log_warn, vha, 0x00f7, - "Unable to create debugfs root directory.\n"); - goto out; - } - -create_dir: - if (ha->dfs_dir) - goto create_nodes; - - mutex_init(&ha->fce_mutex); - ha->dfs_dir = debugfs_create_dir(vha->host_str, qla2x00_dfs_root); - if (!ha->dfs_dir) { - ql_log(ql_log_warn, vha, 0x00f8, - "Unable to create debugfs ha directory.\n"); - goto out; - } - - atomic_inc(&qla2x00_dfs_root_count); - -create_nodes: - ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha, - &dfs_fce_ops); - if (!ha->dfs_fce) { - ql_log(ql_log_warn, vha, 0x00f9, - "Unable to create debugfs fce node.\n"); - goto out; - } -out: - return 0; -} - -int -qla2x00_dfs_remove(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - if (ha->dfs_fce) { - debugfs_remove(ha->dfs_fce); - ha->dfs_fce = NULL; - } - - if (ha->dfs_dir) { - debugfs_remove(ha->dfs_dir); - ha->dfs_dir = NULL; - atomic_dec(&qla2x00_dfs_root_count); - } - - if (atomic_read(&qla2x00_dfs_root_count) == 0 && - qla2x00_dfs_root) { - debugfs_remove(qla2x00_dfs_root); - qla2x00_dfs_root = NULL; - } - - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_fw.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_fw.h deleted file mode 100644 index 6d7d7758..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_fw.h +++ /dev/null @@ -1,1891 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#ifndef __QLA_FW_H -#define __QLA_FW_H - -#define MBS_CHECKSUM_ERROR 0x4010 -#define MBS_INVALID_PRODUCT_KEY 0x4020 - -/* - * Firmware Options. - */ -#define FO1_ENABLE_PUREX BIT_10 -#define FO1_DISABLE_LED_CTRL BIT_6 -#define FO1_ENABLE_8016 BIT_0 -#define FO2_ENABLE_SEL_CLASS2 BIT_5 -#define FO3_NO_ABTS_ON_LINKDOWN BIT_14 -#define FO3_HOLD_STS_IOCB BIT_12 - -/* - * Port Database structure definition for ISP 24xx. - */ -#define PDO_FORCE_ADISC BIT_1 -#define PDO_FORCE_PLOGI BIT_0 - - -#define PORT_DATABASE_24XX_SIZE 64 -struct port_database_24xx { - uint16_t flags; -#define PDF_TASK_RETRY_ID BIT_14 -#define PDF_FC_TAPE BIT_7 -#define PDF_ACK0_CAPABLE BIT_6 -#define PDF_FCP2_CONF BIT_5 -#define PDF_CLASS_2 BIT_4 -#define PDF_HARD_ADDR BIT_1 - - uint8_t current_login_state; - uint8_t last_login_state; -#define PDS_PLOGI_PENDING 0x03 -#define PDS_PLOGI_COMPLETE 0x04 -#define PDS_PRLI_PENDING 0x05 -#define PDS_PRLI_COMPLETE 0x06 -#define PDS_PORT_UNAVAILABLE 0x07 -#define PDS_PRLO_PENDING 0x09 -#define PDS_LOGO_PENDING 0x11 -#define PDS_PRLI2_PENDING 0x12 - - uint8_t hard_address[3]; - uint8_t reserved_1; - - uint8_t port_id[3]; - uint8_t sequence_id; - - uint16_t port_timer; - - uint16_t nport_handle; /* N_PORT handle. */ - - uint16_t receive_data_size; - uint16_t reserved_2; - - uint8_t prli_svc_param_word_0[2]; /* Big endian */ - /* Bits 15-0 of word 0 */ - uint8_t prli_svc_param_word_3[2]; /* Big endian */ - /* Bits 15-0 of word 3 */ - - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; - - uint8_t reserved_3[24]; -}; - -struct vp_database_24xx { - uint16_t vp_status; - uint8_t options; - uint8_t id; - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; - uint16_t port_id_low; - uint16_t port_id_high; -}; - -struct nvram_24xx { - /* NVRAM header. */ - uint8_t id[4]; - uint16_t nvram_version; - uint16_t reserved_0; - - /* Firmware Initialization Control Block. */ - uint16_t version; - uint16_t reserved_1; - uint16_t frame_payload_size; - uint16_t execution_throttle; - uint16_t exchange_count; - uint16_t hard_address; - - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; - - uint16_t login_retry_count; - uint16_t link_down_on_nos; - uint16_t interrupt_delay_timer; - uint16_t login_timeout; - - uint32_t firmware_options_1; - uint32_t firmware_options_2; - uint32_t firmware_options_3; - - /* Offset 56. */ - - /* - * BIT 0 = Control Enable - * BIT 1-15 = - * - * BIT 0-7 = Reserved - * BIT 8-10 = Output Swing 1G - * BIT 11-13 = Output Emphasis 1G - * BIT 14-15 = Reserved - * - * BIT 0-7 = Reserved - * BIT 8-10 = Output Swing 2G - * BIT 11-13 = Output Emphasis 2G - * BIT 14-15 = Reserved - * - * BIT 0-7 = Reserved - * BIT 8-10 = Output Swing 4G - * BIT 11-13 = Output Emphasis 4G - * BIT 14-15 = Reserved - */ - uint16_t seriallink_options[4]; - - uint16_t reserved_2[16]; - - /* Offset 96. */ - uint16_t reserved_3[16]; - - /* PCIe table entries. */ - uint16_t reserved_4[16]; - - /* Offset 160. */ - uint16_t reserved_5[16]; - - /* Offset 192. */ - uint16_t reserved_6[16]; - - /* Offset 224. */ - uint16_t reserved_7[16]; - - /* - * BIT 0 = Enable spinup delay - * BIT 1 = Disable BIOS - * BIT 2 = Enable Memory Map BIOS - * BIT 3 = Enable Selectable Boot - * BIT 4 = Disable RISC code load - * BIT 5 = Disable Serdes - * BIT 6 = - * BIT 7 = - * - * BIT 8 = - * BIT 9 = - * BIT 10 = Enable lip full login - * BIT 11 = Enable target reset - * BIT 12 = - * BIT 13 = - * BIT 14 = - * BIT 15 = Enable alternate WWN - * - * BIT 16-31 = - */ - uint32_t host_p; - - uint8_t alternate_port_name[WWN_SIZE]; - uint8_t alternate_node_name[WWN_SIZE]; - - uint8_t boot_port_name[WWN_SIZE]; - uint16_t boot_lun_number; - uint16_t reserved_8; - - uint8_t alt1_boot_port_name[WWN_SIZE]; - uint16_t alt1_boot_lun_number; - uint16_t reserved_9; - - uint8_t alt2_boot_port_name[WWN_SIZE]; - uint16_t alt2_boot_lun_number; - uint16_t reserved_10; - - uint8_t alt3_boot_port_name[WWN_SIZE]; - uint16_t alt3_boot_lun_number; - uint16_t reserved_11; - - /* - * BIT 0 = Selective Login - * BIT 1 = Alt-Boot Enable - * BIT 2 = Reserved - * BIT 3 = Boot Order List - * BIT 4 = Reserved - * BIT 5 = Selective LUN - * BIT 6 = Reserved - * BIT 7-31 = - */ - uint32_t efi_parameters; - - uint8_t reset_delay; - uint8_t reserved_12; - uint16_t reserved_13; - - uint16_t boot_id_number; - uint16_t reserved_14; - - uint16_t max_luns_per_target; - uint16_t reserved_15; - - uint16_t port_down_retry_count; - uint16_t link_down_timeout; - - /* FCode parameters. */ - uint16_t fcode_parameter; - - uint16_t reserved_16[3]; - - /* Offset 352. */ - uint8_t prev_drv_ver_major; - uint8_t prev_drv_ver_submajob; - uint8_t prev_drv_ver_minor; - uint8_t prev_drv_ver_subminor; - - uint16_t prev_bios_ver_major; - uint16_t prev_bios_ver_minor; - - uint16_t prev_efi_ver_major; - uint16_t prev_efi_ver_minor; - - uint16_t prev_fw_ver_major; - uint8_t prev_fw_ver_minor; - uint8_t prev_fw_ver_subminor; - - uint16_t reserved_17[8]; - - /* Offset 384. */ - uint16_t reserved_18[16]; - - /* Offset 416. */ - uint16_t reserved_19[16]; - - /* Offset 448. */ - uint16_t reserved_20[16]; - - /* Offset 480. */ - uint8_t model_name[16]; - - uint16_t reserved_21[2]; - - /* Offset 500. */ - /* HW Parameter Block. */ - uint16_t pcie_table_sig; - uint16_t pcie_table_offset; - - uint16_t subsystem_vendor_id; - uint16_t subsystem_device_id; - - uint32_t checksum; -}; - -/* - * ISP Initialization Control Block. - * Little endian except where noted. - */ -#define ICB_VERSION 1 -struct init_cb_24xx { - uint16_t version; - uint16_t reserved_1; - - uint16_t frame_payload_size; - uint16_t execution_throttle; - uint16_t exchange_count; - - uint16_t hard_address; - - uint8_t port_name[WWN_SIZE]; /* Big endian. */ - uint8_t node_name[WWN_SIZE]; /* Big endian. */ - - uint16_t response_q_inpointer; - uint16_t request_q_outpointer; - - uint16_t login_retry_count; - - uint16_t prio_request_q_outpointer; - - uint16_t response_q_length; - uint16_t request_q_length; - - uint16_t link_down_on_nos; /* Milliseconds. */ - - uint16_t prio_request_q_length; - - uint32_t request_q_address[2]; - uint32_t response_q_address[2]; - uint32_t prio_request_q_address[2]; - - uint16_t msix; - uint8_t reserved_2[6]; - - uint16_t atio_q_inpointer; - uint16_t atio_q_length; - uint32_t atio_q_address[2]; - - uint16_t interrupt_delay_timer; /* 100us increments. */ - uint16_t login_timeout; - - /* - * BIT 0 = Enable Hard Loop Id - * BIT 1 = Enable Fairness - * BIT 2 = Enable Full-Duplex - * BIT 3 = Reserved - * BIT 4 = Enable Target Mode - * BIT 5 = Disable Initiator Mode - * BIT 6 = Reserved - * BIT 7 = Reserved - * - * BIT 8 = Reserved - * BIT 9 = Non Participating LIP - * BIT 10 = Descending Loop ID Search - * BIT 11 = Acquire Loop ID in LIPA - * BIT 12 = Reserved - * BIT 13 = Full Login after LIP - * BIT 14 = Node Name Option - * BIT 15-31 = Reserved - */ - uint32_t firmware_options_1; - - /* - * BIT 0 = Operation Mode bit 0 - * BIT 1 = Operation Mode bit 1 - * BIT 2 = Operation Mode bit 2 - * BIT 3 = Operation Mode bit 3 - * BIT 4 = Connection Options bit 0 - * BIT 5 = Connection Options bit 1 - * BIT 6 = Connection Options bit 2 - * BIT 7 = Enable Non part on LIHA failure - * - * BIT 8 = Enable Class 2 - * BIT 9 = Enable ACK0 - * BIT 10 = Reserved - * BIT 11 = Enable FC-SP Security - * BIT 12 = FC Tape Enable - * BIT 13 = Reserved - * BIT 14 = Enable Target PRLI Control - * BIT 15-31 = Reserved - */ - uint32_t firmware_options_2; - - /* - * BIT 0 = Reserved - * BIT 1 = Soft ID only - * BIT 2 = Reserved - * BIT 3 = Reserved - * BIT 4 = FCP RSP Payload bit 0 - * BIT 5 = FCP RSP Payload bit 1 - * BIT 6 = Enable Receive Out-of-Order data frame handling - * BIT 7 = Disable Automatic PLOGI on Local Loop - * - * BIT 8 = Reserved - * BIT 9 = Enable Out-of-Order FCP_XFER_RDY relative offset handling - * BIT 10 = Reserved - * BIT 11 = Reserved - * BIT 12 = Reserved - * BIT 13 = Data Rate bit 0 - * BIT 14 = Data Rate bit 1 - * BIT 15 = Data Rate bit 2 - * BIT 16 = Enable 75 ohm Termination Select - * BIT 17-31 = Reserved - */ - uint32_t firmware_options_3; - uint16_t qos; - uint16_t rid; - uint8_t reserved_3[20]; -}; - -/* - * ISP queue - command entry structure definition. - */ -#define COMMAND_TYPE_6 0x48 /* Command Type 6 entry */ -struct cmd_type_6 { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t nport_handle; /* N_PORT handle. */ - uint16_t timeout; /* Command timeout. */ - - uint16_t dseg_count; /* Data segment count. */ - - uint16_t fcp_rsp_dsd_len; /* FCP_RSP DSD length. */ - - struct scsi_lun lun; /* FCP LUN (BE). */ - - uint16_t control_flags; /* Control flags. */ -#define CF_DIF_SEG_DESCR_ENABLE BIT_3 -#define CF_DATA_SEG_DESCR_ENABLE BIT_2 -#define CF_READ_DATA BIT_1 -#define CF_WRITE_DATA BIT_0 - - uint16_t fcp_cmnd_dseg_len; /* Data segment length. */ - uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */ - - uint32_t fcp_rsp_dseg_address[2]; /* Data segment address. */ - - uint32_t byte_count; /* Total byte count. */ - - uint8_t port_id[3]; /* PortID of destination port. */ - uint8_t vp_index; - - uint32_t fcp_data_dseg_address[2]; /* Data segment address. */ - uint32_t fcp_data_dseg_len; /* Data segment length. */ -}; - -#define COMMAND_TYPE_7 0x18 /* Command Type 7 entry */ -struct cmd_type_7 { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t nport_handle; /* N_PORT handle. */ - uint16_t timeout; /* Command timeout. */ -#define FW_MAX_TIMEOUT 0x1999 - - uint16_t dseg_count; /* Data segment count. */ - uint16_t reserved_1; - - struct scsi_lun lun; /* FCP LUN (BE). */ - - uint16_t task_mgmt_flags; /* Task management flags. */ -#define TMF_CLEAR_ACA BIT_14 -#define TMF_TARGET_RESET BIT_13 -#define TMF_LUN_RESET BIT_12 -#define TMF_CLEAR_TASK_SET BIT_10 -#define TMF_ABORT_TASK_SET BIT_9 -#define TMF_DSD_LIST_ENABLE BIT_2 -#define TMF_READ_DATA BIT_1 -#define TMF_WRITE_DATA BIT_0 - - uint8_t task; -#define TSK_SIMPLE 0 -#define TSK_HEAD_OF_QUEUE 1 -#define TSK_ORDERED 2 -#define TSK_ACA 4 -#define TSK_UNTAGGED 5 - - uint8_t crn; - - uint8_t fcp_cdb[MAX_CMDSZ]; /* SCSI command words. */ - uint32_t byte_count; /* Total byte count. */ - - uint8_t port_id[3]; /* PortID of destination port. */ - uint8_t vp_index; - - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_len; /* Data segment 0 length. */ -}; - -#define COMMAND_TYPE_CRC_2 0x6A /* Command Type CRC_2 (Type 6) - * (T10-DIF) */ -struct cmd_type_crc_2 { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t nport_handle; /* N_PORT handle. */ - uint16_t timeout; /* Command timeout. */ - - uint16_t dseg_count; /* Data segment count. */ - - uint16_t fcp_rsp_dseg_len; /* FCP_RSP DSD length. */ - - struct scsi_lun lun; /* FCP LUN (BE). */ - - uint16_t control_flags; /* Control flags. */ - - uint16_t fcp_cmnd_dseg_len; /* Data segment length. */ - uint32_t fcp_cmnd_dseg_address[2]; /* Data segment address. */ - - uint32_t fcp_rsp_dseg_address[2]; /* Data segment address. */ - - uint32_t byte_count; /* Total byte count. */ - - uint8_t port_id[3]; /* PortID of destination port. */ - uint8_t vp_index; - - uint32_t crc_context_address[2]; /* Data segment address. */ - uint16_t crc_context_len; /* Data segment length. */ - uint16_t reserved_1; /* MUST be set to 0. */ -}; - - -/* - * ISP queue - status entry structure definition. - */ -#define STATUS_TYPE 0x03 /* Status entry. */ -struct sts_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t comp_status; /* Completion status. */ - uint16_t ox_id; /* OX_ID used by the firmware. */ - - uint32_t residual_len; /* FW calc residual transfer length. */ - - uint16_t reserved_1; - uint16_t state_flags; /* State flags. */ -#define SF_TRANSFERRED_DATA BIT_11 -#define SF_FCP_RSP_DMA BIT_0 - - uint16_t reserved_2; - uint16_t scsi_status; /* SCSI status. */ -#define SS_CONFIRMATION_REQ BIT_12 - - uint32_t rsp_residual_count; /* FCP RSP residual count. */ - - uint32_t sense_len; /* FCP SENSE length. */ - uint32_t rsp_data_len; /* FCP response data length. */ - uint8_t data[28]; /* FCP response/sense information. */ - /* - * If DIF Error is set in comp_status, these additional fields are - * defined: - * - * !!! NOTE: Firmware sends expected/actual DIF data in big endian - * format; but all of the "data" field gets swab32-d in the beginning - * of qla2x00_status_entry(). - * - * &data[10] : uint8_t report_runt_bg[2]; - computed guard - * &data[12] : uint8_t actual_dif[8]; - DIF Data received - * &data[20] : uint8_t expected_dif[8]; - DIF Data computed - */ -}; - - -/* - * Status entry completion status - */ -#define CS_DATA_REASSEMBLY_ERROR 0x11 /* Data Reassembly Error.. */ -#define CS_ABTS_BY_TARGET 0x13 /* Target send ABTS to abort IOCB. */ -#define CS_FW_RESOURCE 0x2C /* Firmware Resource Unavailable. */ -#define CS_TASK_MGMT_OVERRUN 0x30 /* Task management overrun (8+). */ -#define CS_ABORT_BY_TARGET 0x47 /* Abort By Target. */ - -/* - * ISP queue - marker entry structure definition. - */ -#define MARKER_TYPE 0x04 /* Marker entry. */ -struct mrk_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; /* Handle count. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t nport_handle; /* N_PORT handle. */ - - uint8_t modifier; /* Modifier (7-0). */ -#define MK_SYNC_ID_LUN 0 /* Synchronize ID/LUN */ -#define MK_SYNC_ID 1 /* Synchronize ID */ -#define MK_SYNC_ALL 2 /* Synchronize all ID/LUN */ - uint8_t reserved_1; - - uint8_t reserved_2; - uint8_t vp_index; - - uint16_t reserved_3; - - uint8_t lun[8]; /* FCP LUN (BE). */ - uint8_t reserved_4[40]; -}; - -/* - * ISP queue - CT Pass-Through entry structure definition. - */ -#define CT_IOCB_TYPE 0x29 /* CT Pass-Through IOCB entry */ -struct ct_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System Defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t comp_status; /* Completion status. */ - - uint16_t nport_handle; /* N_PORT handle. */ - - uint16_t cmd_dsd_count; - - uint8_t vp_index; - uint8_t reserved_1; - - uint16_t timeout; /* Command timeout. */ - uint16_t reserved_2; - - uint16_t rsp_dsd_count; - - uint8_t reserved_3[10]; - - uint32_t rsp_byte_count; - uint32_t cmd_byte_count; - - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_len; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_len; /* Data segment 1 length. */ -}; - -/* - * ISP queue - ELS Pass-Through entry structure definition. - */ -#define ELS_IOCB_TYPE 0x53 /* ELS Pass-Through IOCB entry */ -struct els_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System Defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t reserved_1; - - uint16_t nport_handle; /* N_PORT handle. */ - - uint16_t tx_dsd_count; - - uint8_t vp_index; - uint8_t sof_type; -#define EST_SOFI3 (1 << 4) -#define EST_SOFI2 (3 << 4) - - uint32_t rx_xchg_address; /* Receive exchange address. */ - uint16_t rx_dsd_count; - - uint8_t opcode; - uint8_t reserved_2; - - uint8_t port_id[3]; - uint8_t reserved_3; - - uint16_t reserved_4; - - uint16_t control_flags; /* Control flags. */ -#define ECF_PAYLOAD_DESCR_MASK (BIT_15|BIT_14|BIT_13) -#define EPD_ELS_COMMAND (0 << 13) -#define EPD_ELS_ACC (1 << 13) -#define EPD_ELS_RJT (2 << 13) -#define EPD_RX_XCHG (3 << 13) -#define ECF_CLR_PASSTHRU_PEND BIT_12 -#define ECF_INCL_FRAME_HDR BIT_11 - - uint32_t rx_byte_count; - uint32_t tx_byte_count; - - uint32_t tx_address[2]; /* Data segment 0 address. */ - uint32_t tx_len; /* Data segment 0 length. */ - uint32_t rx_address[2]; /* Data segment 1 address. */ - uint32_t rx_len; /* Data segment 1 length. */ -}; - -struct els_sts_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System Defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t comp_status; - - uint16_t nport_handle; /* N_PORT handle. */ - - uint16_t reserved_1; - - uint8_t vp_index; - uint8_t sof_type; - - uint32_t rx_xchg_address; /* Receive exchange address. */ - uint16_t reserved_2; - - uint8_t opcode; - uint8_t reserved_3; - - uint8_t port_id[3]; - uint8_t reserved_4; - - uint16_t reserved_5; - - uint16_t control_flags; /* Control flags. */ - uint32_t total_byte_count; - uint32_t error_subcode_1; - uint32_t error_subcode_2; -}; -/* - * ISP queue - Mailbox Command entry structure definition. - */ -#define MBX_IOCB_TYPE 0x39 -struct mbx_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; /* Handle count. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t mbx[28]; -}; - - -#define LOGINOUT_PORT_IOCB_TYPE 0x52 /* Login/Logout Port entry. */ -struct logio_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t comp_status; /* Completion status. */ -#define CS_LOGIO_ERROR 0x31 /* Login/Logout IOCB error. */ - - uint16_t nport_handle; /* N_PORT handle. */ - - uint16_t control_flags; /* Control flags. */ - /* Modifiers. */ -#define LCF_INCLUDE_SNS BIT_10 /* Include SNS (FFFFFC) during LOGO. */ -#define LCF_FCP2_OVERRIDE BIT_9 /* Set/Reset word 3 of PRLI. */ -#define LCF_CLASS_2 BIT_8 /* Enable class 2 during PLOGI. */ -#define LCF_FREE_NPORT BIT_7 /* Release NPORT handle after LOGO. */ -#define LCF_EXPL_LOGO BIT_6 /* Perform an explicit LOGO. */ -#define LCF_SKIP_PRLI BIT_5 /* Skip PRLI after PLOGI. */ -#define LCF_IMPL_LOGO_ALL BIT_5 /* Implicit LOGO to all ports. */ -#define LCF_COND_PLOGI BIT_4 /* PLOGI only if not logged-in. */ -#define LCF_IMPL_LOGO BIT_4 /* Perform an implicit LOGO. */ -#define LCF_IMPL_PRLO BIT_4 /* Perform an implicit PRLO. */ - /* Commands. */ -#define LCF_COMMAND_PLOGI 0x00 /* PLOGI. */ -#define LCF_COMMAND_PRLI 0x01 /* PRLI. */ -#define LCF_COMMAND_PDISC 0x02 /* PDISC. */ -#define LCF_COMMAND_ADISC 0x03 /* ADISC. */ -#define LCF_COMMAND_LOGO 0x08 /* LOGO. */ -#define LCF_COMMAND_PRLO 0x09 /* PRLO. */ -#define LCF_COMMAND_TPRLO 0x0A /* TPRLO. */ - - uint8_t vp_index; - uint8_t reserved_1; - - uint8_t port_id[3]; /* PortID of destination port. */ - - uint8_t rsp_size; /* Response size in 32bit words. */ - - uint32_t io_parameter[11]; /* General I/O parameters. */ -#define LSC_SCODE_NOLINK 0x01 -#define LSC_SCODE_NOIOCB 0x02 -#define LSC_SCODE_NOXCB 0x03 -#define LSC_SCODE_CMD_FAILED 0x04 -#define LSC_SCODE_NOFABRIC 0x05 -#define LSC_SCODE_FW_NOT_READY 0x07 -#define LSC_SCODE_NOT_LOGGED_IN 0x09 -#define LSC_SCODE_NOPCB 0x0A - -#define LSC_SCODE_ELS_REJECT 0x18 -#define LSC_SCODE_CMD_PARAM_ERR 0x19 -#define LSC_SCODE_PORTID_USED 0x1A -#define LSC_SCODE_NPORT_USED 0x1B -#define LSC_SCODE_NONPORT 0x1C -#define LSC_SCODE_LOGGED_IN 0x1D -#define LSC_SCODE_NOFLOGI_ACC 0x1F -}; - -#define TSK_MGMT_IOCB_TYPE 0x14 -struct tsk_mgmt_entry { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; /* Handle count. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t nport_handle; /* N_PORT handle. */ - - uint16_t reserved_1; - - uint16_t delay; /* Activity delay in seconds. */ - - uint16_t timeout; /* Command timeout. */ - - struct scsi_lun lun; /* FCP LUN (BE). */ - - uint32_t control_flags; /* Control Flags. */ -#define TCF_NOTMCMD_TO_TARGET BIT_31 -#define TCF_LUN_RESET BIT_4 -#define TCF_ABORT_TASK_SET BIT_3 -#define TCF_CLEAR_TASK_SET BIT_2 -#define TCF_TARGET_RESET BIT_1 -#define TCF_CLEAR_ACA BIT_0 - - uint8_t reserved_2[20]; - - uint8_t port_id[3]; /* PortID of destination port. */ - uint8_t vp_index; - - uint8_t reserved_3[12]; -}; - -#define ABORT_IOCB_TYPE 0x33 -struct abort_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; /* Handle count. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t nport_handle; /* N_PORT handle. */ - /* or Completion status. */ - - uint16_t options; /* Options. */ -#define AOF_NO_ABTS BIT_0 /* Do not send any ABTS. */ - - uint32_t handle_to_abort; /* System handle to abort. */ - - uint16_t req_que_no; - uint8_t reserved_1[30]; - - uint8_t port_id[3]; /* PortID of destination port. */ - uint8_t vp_index; - - uint8_t reserved_2[12]; -}; - -/* - * ISP I/O Register Set structure definitions. - */ -struct device_reg_24xx { - uint32_t flash_addr; /* Flash/NVRAM BIOS address. */ -#define FARX_DATA_FLAG BIT_31 -#define FARX_ACCESS_FLASH_CONF 0x7FFD0000 -#define FARX_ACCESS_FLASH_DATA 0x7FF00000 -#define FARX_ACCESS_NVRAM_CONF 0x7FFF0000 -#define FARX_ACCESS_NVRAM_DATA 0x7FFE0000 - -#define FA_NVRAM_FUNC0_ADDR 0x80 -#define FA_NVRAM_FUNC1_ADDR 0x180 - -#define FA_NVRAM_VPD_SIZE 0x200 -#define FA_NVRAM_VPD0_ADDR 0x00 -#define FA_NVRAM_VPD1_ADDR 0x100 - -#define FA_BOOT_CODE_ADDR 0x00000 - /* - * RISC code begins at offset 512KB - * within flash. Consisting of two - * contiguous RISC code segments. - */ -#define FA_RISC_CODE_ADDR 0x20000 -#define FA_RISC_CODE_SEGMENTS 2 - -#define FA_FLASH_DESCR_ADDR_24 0x11000 -#define FA_FLASH_LAYOUT_ADDR_24 0x11400 -#define FA_NPIV_CONF0_ADDR_24 0x16000 -#define FA_NPIV_CONF1_ADDR_24 0x17000 - -#define FA_FW_AREA_ADDR 0x40000 -#define FA_VPD_NVRAM_ADDR 0x48000 -#define FA_FEATURE_ADDR 0x4C000 -#define FA_FLASH_DESCR_ADDR 0x50000 -#define FA_FLASH_LAYOUT_ADDR 0x50400 -#define FA_HW_EVENT0_ADDR 0x54000 -#define FA_HW_EVENT1_ADDR 0x54400 -#define FA_HW_EVENT_SIZE 0x200 -#define FA_HW_EVENT_ENTRY_SIZE 4 -#define FA_NPIV_CONF0_ADDR 0x5C000 -#define FA_NPIV_CONF1_ADDR 0x5D000 -#define FA_FCP_PRIO0_ADDR 0x10000 -#define FA_FCP_PRIO1_ADDR 0x12000 - -/* - * Flash Error Log Event Codes. - */ -#define HW_EVENT_RESET_ERR 0xF00B -#define HW_EVENT_ISP_ERR 0xF020 -#define HW_EVENT_PARITY_ERR 0xF022 -#define HW_EVENT_NVRAM_CHKSUM_ERR 0xF023 -#define HW_EVENT_FLASH_FW_ERR 0xF024 - - uint32_t flash_data; /* Flash/NVRAM BIOS data. */ - - uint32_t ctrl_status; /* Control/Status. */ -#define CSRX_FLASH_ACCESS_ERROR BIT_18 /* Flash/NVRAM Access Error. */ -#define CSRX_DMA_ACTIVE BIT_17 /* DMA Active status. */ -#define CSRX_DMA_SHUTDOWN BIT_16 /* DMA Shutdown control status. */ -#define CSRX_FUNCTION BIT_15 /* Function number. */ - /* PCI-X Bus Mode. */ -#define CSRX_PCIX_BUS_MODE_MASK (BIT_11|BIT_10|BIT_9|BIT_8) -#define PBM_PCI_33MHZ (0 << 8) -#define PBM_PCIX_M1_66MHZ (1 << 8) -#define PBM_PCIX_M1_100MHZ (2 << 8) -#define PBM_PCIX_M1_133MHZ (3 << 8) -#define PBM_PCIX_M2_66MHZ (5 << 8) -#define PBM_PCIX_M2_100MHZ (6 << 8) -#define PBM_PCIX_M2_133MHZ (7 << 8) -#define PBM_PCI_66MHZ (8 << 8) - /* Max Write Burst byte count. */ -#define CSRX_MAX_WRT_BURST_MASK (BIT_5|BIT_4) -#define MWB_512_BYTES (0 << 4) -#define MWB_1024_BYTES (1 << 4) -#define MWB_2048_BYTES (2 << 4) -#define MWB_4096_BYTES (3 << 4) - -#define CSRX_64BIT_SLOT BIT_2 /* PCI 64-Bit Bus Slot. */ -#define CSRX_FLASH_ENABLE BIT_1 /* Flash BIOS Read/Write enable. */ -#define CSRX_ISP_SOFT_RESET BIT_0 /* ISP soft reset. */ - - uint32_t ictrl; /* Interrupt control. */ -#define ICRX_EN_RISC_INT BIT_3 /* Enable RISC interrupts on PCI. */ - - uint32_t istatus; /* Interrupt status. */ -#define ISRX_RISC_INT BIT_3 /* RISC interrupt. */ - - uint32_t unused_1[2]; /* Gap. */ - - /* Request Queue. */ - uint32_t req_q_in; /* In-Pointer. */ - uint32_t req_q_out; /* Out-Pointer. */ - /* Response Queue. */ - uint32_t rsp_q_in; /* In-Pointer. */ - uint32_t rsp_q_out; /* Out-Pointer. */ - /* Priority Request Queue. */ - uint32_t preq_q_in; /* In-Pointer. */ - uint32_t preq_q_out; /* Out-Pointer. */ - - uint32_t unused_2[2]; /* Gap. */ - - /* ATIO Queue. */ - uint32_t atio_q_in; /* In-Pointer. */ - uint32_t atio_q_out; /* Out-Pointer. */ - - uint32_t host_status; -#define HSRX_RISC_INT BIT_15 /* RISC to Host interrupt. */ -#define HSRX_RISC_PAUSED BIT_8 /* RISC Paused. */ - - uint32_t hccr; /* Host command & control register. */ - /* HCCR statuses. */ -#define HCCRX_HOST_INT BIT_6 /* Host to RISC interrupt bit. */ -#define HCCRX_RISC_RESET BIT_5 /* RISC Reset mode bit. */ - /* HCCR commands. */ - /* NOOP. */ -#define HCCRX_NOOP 0x00000000 - /* Set RISC Reset. */ -#define HCCRX_SET_RISC_RESET 0x10000000 - /* Clear RISC Reset. */ -#define HCCRX_CLR_RISC_RESET 0x20000000 - /* Set RISC Pause. */ -#define HCCRX_SET_RISC_PAUSE 0x30000000 - /* Releases RISC Pause. */ -#define HCCRX_REL_RISC_PAUSE 0x40000000 - /* Set HOST to RISC interrupt. */ -#define HCCRX_SET_HOST_INT 0x50000000 - /* Clear HOST to RISC interrupt. */ -#define HCCRX_CLR_HOST_INT 0x60000000 - /* Clear RISC to PCI interrupt. */ -#define HCCRX_CLR_RISC_INT 0xA0000000 - - uint32_t gpiod; /* GPIO Data register. */ - - /* LED update mask. */ -#define GPDX_LED_UPDATE_MASK (BIT_20|BIT_19|BIT_18) - /* Data update mask. */ -#define GPDX_DATA_UPDATE_MASK (BIT_17|BIT_16) - /* Data update mask. */ -#define GPDX_DATA_UPDATE_2_MASK (BIT_28|BIT_27|BIT_26|BIT_17|BIT_16) - /* LED control mask. */ -#define GPDX_LED_COLOR_MASK (BIT_4|BIT_3|BIT_2) - /* LED bit values. Color names as - * referenced in fw spec. - */ -#define GPDX_LED_YELLOW_ON BIT_2 -#define GPDX_LED_GREEN_ON BIT_3 -#define GPDX_LED_AMBER_ON BIT_4 - /* Data in/out. */ -#define GPDX_DATA_INOUT (BIT_1|BIT_0) - - uint32_t gpioe; /* GPIO Enable register. */ - /* Enable update mask. */ -#define GPEX_ENABLE_UPDATE_MASK (BIT_17|BIT_16) - /* Enable update mask. */ -#define GPEX_ENABLE_UPDATE_2_MASK (BIT_28|BIT_27|BIT_26|BIT_17|BIT_16) - /* Enable. */ -#define GPEX_ENABLE (BIT_1|BIT_0) - - uint32_t iobase_addr; /* I/O Bus Base Address register. */ - - uint32_t unused_3[10]; /* Gap. */ - - uint16_t mailbox0; - uint16_t mailbox1; - uint16_t mailbox2; - uint16_t mailbox3; - uint16_t mailbox4; - uint16_t mailbox5; - uint16_t mailbox6; - uint16_t mailbox7; - uint16_t mailbox8; - uint16_t mailbox9; - uint16_t mailbox10; - uint16_t mailbox11; - uint16_t mailbox12; - uint16_t mailbox13; - uint16_t mailbox14; - uint16_t mailbox15; - uint16_t mailbox16; - uint16_t mailbox17; - uint16_t mailbox18; - uint16_t mailbox19; - uint16_t mailbox20; - uint16_t mailbox21; - uint16_t mailbox22; - uint16_t mailbox23; - uint16_t mailbox24; - uint16_t mailbox25; - uint16_t mailbox26; - uint16_t mailbox27; - uint16_t mailbox28; - uint16_t mailbox29; - uint16_t mailbox30; - uint16_t mailbox31; - - uint32_t iobase_window; - uint32_t iobase_c4; - uint32_t iobase_c8; - uint32_t unused_4_1[6]; /* Gap. */ - uint32_t iobase_q; - uint32_t unused_5[2]; /* Gap. */ - uint32_t iobase_select; - uint32_t unused_6[2]; /* Gap. */ - uint32_t iobase_sdata; -}; - -/* Trace Control *************************************************************/ - -#define TC_AEN_DISABLE 0 - -#define TC_EFT_ENABLE 4 -#define TC_EFT_DISABLE 5 - -#define TC_FCE_ENABLE 8 -#define TC_FCE_OPTIONS 0 -#define TC_FCE_DEFAULT_RX_SIZE 2112 -#define TC_FCE_DEFAULT_TX_SIZE 2112 -#define TC_FCE_DISABLE 9 -#define TC_FCE_DISABLE_TRACE BIT_0 - -/* MID Support ***************************************************************/ - -#define MIN_MULTI_ID_FABRIC 64 /* Must be power-of-2. */ -#define MAX_MULTI_ID_FABRIC 256 /* ... */ - -#define for_each_mapped_vp_idx(_ha, _idx) \ - for (_idx = find_next_bit((_ha)->vp_idx_map, \ - (_ha)->max_npiv_vports + 1, 1); \ - _idx <= (_ha)->max_npiv_vports; \ - _idx = find_next_bit((_ha)->vp_idx_map, \ - (_ha)->max_npiv_vports + 1, _idx + 1)) \ - -struct mid_conf_entry_24xx { - uint16_t reserved_1; - - /* - * BIT 0 = Enable Hard Loop Id - * BIT 1 = Acquire Loop ID in LIPA - * BIT 2 = ID not Acquired - * BIT 3 = Enable VP - * BIT 4 = Enable Initiator Mode - * BIT 5 = Disable Target Mode - * BIT 6-7 = Reserved - */ - uint8_t options; - - uint8_t hard_address; - - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; -}; - -struct mid_init_cb_24xx { - struct init_cb_24xx init_cb; - - uint16_t count; - uint16_t options; - - struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC]; -}; - - -struct mid_db_entry_24xx { - uint16_t status; -#define MDBS_NON_PARTIC BIT_3 -#define MDBS_ID_ACQUIRED BIT_1 -#define MDBS_ENABLED BIT_0 - - uint8_t options; - uint8_t hard_address; - - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; - - uint8_t port_id[3]; - uint8_t reserved_1; -}; - -/* - * Virtual Port Control IOCB - */ -#define VP_CTRL_IOCB_TYPE 0x30 /* Vitual Port Control entry. */ -struct vp_ctrl_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t vp_idx_failed; - - uint16_t comp_status; /* Completion status. */ -#define CS_VCE_IOCB_ERROR 0x01 /* Error processing IOCB */ -#define CS_VCE_ACQ_ID_ERROR 0x02 /* Error while acquireing ID. */ -#define CS_VCE_BUSY 0x05 /* Firmware not ready to accept cmd. */ - - uint16_t command; -#define VCE_COMMAND_ENABLE_VPS 0x00 /* Enable VPs. */ -#define VCE_COMMAND_DISABLE_VPS 0x08 /* Disable VPs. */ -#define VCE_COMMAND_DISABLE_VPS_REINIT 0x09 /* Disable VPs and reinit link. */ -#define VCE_COMMAND_DISABLE_VPS_LOGO 0x0a /* Disable VPs and LOGO ports. */ -#define VCE_COMMAND_DISABLE_VPS_LOGO_ALL 0x0b /* Disable VPs and LOGO ports. */ - - uint16_t vp_count; - - uint8_t vp_idx_map[16]; - uint16_t flags; - uint16_t id; - uint16_t reserved_4; - uint16_t hopct; - uint8_t reserved_5[24]; -}; - -/* - * Modify Virtual Port Configuration IOCB - */ -#define VP_CONFIG_IOCB_TYPE 0x31 /* Vitual Port Config entry. */ -struct vp_config_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t handle_count; - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t flags; -#define CS_VF_BIND_VPORTS_TO_VF BIT_0 -#define CS_VF_SET_QOS_OF_VPORTS BIT_1 -#define CS_VF_SET_HOPS_OF_VPORTS BIT_2 - - uint16_t comp_status; /* Completion status. */ -#define CS_VCT_STS_ERROR 0x01 /* Specified VPs were not disabled. */ -#define CS_VCT_CNT_ERROR 0x02 /* Invalid VP count. */ -#define CS_VCT_ERROR 0x03 /* Unknown error. */ -#define CS_VCT_IDX_ERROR 0x02 /* Invalid VP index. */ -#define CS_VCT_BUSY 0x05 /* Firmware not ready to accept cmd. */ - - uint8_t command; -#define VCT_COMMAND_MOD_VPS 0x00 /* Modify VP configurations. */ -#define VCT_COMMAND_MOD_ENABLE_VPS 0x01 /* Modify configuration & enable VPs. */ - - uint8_t vp_count; - - uint8_t vp_index1; - uint8_t vp_index2; - - uint8_t options_idx1; - uint8_t hard_address_idx1; - uint16_t reserved_vp1; - uint8_t port_name_idx1[WWN_SIZE]; - uint8_t node_name_idx1[WWN_SIZE]; - - uint8_t options_idx2; - uint8_t hard_address_idx2; - uint16_t reserved_vp2; - uint8_t port_name_idx2[WWN_SIZE]; - uint8_t node_name_idx2[WWN_SIZE]; - uint16_t id; - uint16_t reserved_4; - uint16_t hopct; - uint8_t reserved_5[2]; -}; - -#define VP_RPT_ID_IOCB_TYPE 0x32 /* Report ID Acquisition entry. */ -struct vp_rpt_id_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - - uint16_t vp_count; /* Format 0 -- | VP setup | VP acq |. */ - /* Format 1 -- | VP count |. */ - uint16_t vp_idx; /* Format 0 -- Reserved. */ - /* Format 1 -- VP status and index. */ - - uint8_t port_id[3]; - uint8_t format; - - uint8_t vp_idx_map[16]; - - uint8_t reserved_4[32]; -}; - -#define VF_EVFP_IOCB_TYPE 0x26 /* Exchange Virtual Fabric Parameters entry. */ -struct vf_evfp_entry_24xx { - uint8_t entry_type; /* Entry type. */ - uint8_t entry_count; /* Entry count. */ - uint8_t sys_define; /* System defined. */ - uint8_t entry_status; /* Entry Status. */ - - uint32_t handle; /* System handle. */ - uint16_t comp_status; /* Completion status. */ - uint16_t timeout; /* timeout */ - uint16_t adim_tagging_mode; - - uint16_t vfport_id; - uint32_t exch_addr; - - uint16_t nport_handle; /* N_PORT handle. */ - uint16_t control_flags; - uint32_t io_parameter_0; - uint32_t io_parameter_1; - uint32_t tx_address[2]; /* Data segment 0 address. */ - uint32_t tx_len; /* Data segment 0 length. */ - uint32_t rx_address[2]; /* Data segment 1 address. */ - uint32_t rx_len; /* Data segment 1 length. */ -}; - -/* END MID Support ***********************************************************/ - -/* Flash Description Table ***************************************************/ - -struct qla_fdt_layout { - uint8_t sig[4]; - uint16_t version; - uint16_t len; - uint16_t checksum; - uint8_t unused1[2]; - uint8_t model[16]; - uint16_t man_id; - uint16_t id; - uint8_t flags; - uint8_t erase_cmd; - uint8_t alt_erase_cmd; - uint8_t wrt_enable_cmd; - uint8_t wrt_enable_bits; - uint8_t wrt_sts_reg_cmd; - uint8_t unprotect_sec_cmd; - uint8_t read_man_id_cmd; - uint32_t block_size; - uint32_t alt_block_size; - uint32_t flash_size; - uint32_t wrt_enable_data; - uint8_t read_id_addr_len; - uint8_t wrt_disable_bits; - uint8_t read_dev_id_len; - uint8_t chip_erase_cmd; - uint16_t read_timeout; - uint8_t protect_sec_cmd; - uint8_t unused2[65]; -}; - -/* Flash Layout Table ********************************************************/ - -struct qla_flt_location { - uint8_t sig[4]; - uint16_t start_lo; - uint16_t start_hi; - uint8_t version; - uint8_t unused[5]; - uint16_t checksum; -}; - -struct qla_flt_header { - uint16_t version; - uint16_t length; - uint16_t checksum; - uint16_t unused; -}; - -#define FLT_REG_FW 0x01 -#define FLT_REG_BOOT_CODE 0x07 -#define FLT_REG_VPD_0 0x14 -#define FLT_REG_NVRAM_0 0x15 -#define FLT_REG_VPD_1 0x16 -#define FLT_REG_NVRAM_1 0x17 -#define FLT_REG_FDT 0x1a -#define FLT_REG_FLT 0x1c -#define FLT_REG_HW_EVENT_0 0x1d -#define FLT_REG_HW_EVENT_1 0x1f -#define FLT_REG_NPIV_CONF_0 0x29 -#define FLT_REG_NPIV_CONF_1 0x2a -#define FLT_REG_GOLD_FW 0x2f -#define FLT_REG_FCP_PRIO_0 0x87 -#define FLT_REG_FCP_PRIO_1 0x88 -#define FLT_REG_FCOE_FW 0xA4 -#define FLT_REG_FCOE_VPD_0 0xA9 -#define FLT_REG_FCOE_NVRAM_0 0xAA -#define FLT_REG_FCOE_VPD_1 0xAB -#define FLT_REG_FCOE_NVRAM_1 0xAC - -struct qla_flt_region { - uint32_t code; - uint32_t size; - uint32_t start; - uint32_t end; -}; - -/* Flash NPIV Configuration Table ********************************************/ - -struct qla_npiv_header { - uint8_t sig[2]; - uint16_t version; - uint16_t entries; - uint16_t unused[4]; - uint16_t checksum; -}; - -struct qla_npiv_entry { - uint16_t flags; - uint16_t vf_id; - uint8_t q_qos; - uint8_t f_qos; - uint16_t unused1; - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; -}; - -/* 84XX Support **************************************************************/ - -#define MBA_ISP84XX_ALERT 0x800f /* Alert Notification. */ -#define A84_PANIC_RECOVERY 0x1 -#define A84_OP_LOGIN_COMPLETE 0x2 -#define A84_DIAG_LOGIN_COMPLETE 0x3 -#define A84_GOLD_LOGIN_COMPLETE 0x4 - -#define MBC_ISP84XX_RESET 0x3a /* Reset. */ - -#define FSTATE_REMOTE_FC_DOWN BIT_0 -#define FSTATE_NSL_LINK_DOWN BIT_1 -#define FSTATE_IS_DIAG_FW BIT_2 -#define FSTATE_LOGGED_IN BIT_3 -#define FSTATE_WAITING_FOR_VERIFY BIT_4 - -#define VERIFY_CHIP_IOCB_TYPE 0x1B -struct verify_chip_entry_84xx { - uint8_t entry_type; - uint8_t entry_count; - uint8_t sys_defined; - uint8_t entry_status; - - uint32_t handle; - - uint16_t options; -#define VCO_DONT_UPDATE_FW BIT_0 -#define VCO_FORCE_UPDATE BIT_1 -#define VCO_DONT_RESET_UPDATE BIT_2 -#define VCO_DIAG_FW BIT_3 -#define VCO_END_OF_DATA BIT_14 -#define VCO_ENABLE_DSD BIT_15 - - uint16_t reserved_1; - - uint16_t data_seg_cnt; - uint16_t reserved_2[3]; - - uint32_t fw_ver; - uint32_t exchange_address; - - uint32_t reserved_3[3]; - uint32_t fw_size; - uint32_t fw_seq_size; - uint32_t relative_offset; - - uint32_t dseg_address[2]; - uint32_t dseg_length; -}; - -struct verify_chip_rsp_84xx { - uint8_t entry_type; - uint8_t entry_count; - uint8_t sys_defined; - uint8_t entry_status; - - uint32_t handle; - - uint16_t comp_status; -#define CS_VCS_CHIP_FAILURE 0x3 -#define CS_VCS_BAD_EXCHANGE 0x8 -#define CS_VCS_SEQ_COMPLETEi 0x40 - - uint16_t failure_code; -#define VFC_CHECKSUM_ERROR 0x1 -#define VFC_INVALID_LEN 0x2 -#define VFC_ALREADY_IN_PROGRESS 0x8 - - uint16_t reserved_1[4]; - - uint32_t fw_ver; - uint32_t exchange_address; - - uint32_t reserved_2[6]; -}; - -#define ACCESS_CHIP_IOCB_TYPE 0x2B -struct access_chip_84xx { - uint8_t entry_type; - uint8_t entry_count; - uint8_t sys_defined; - uint8_t entry_status; - - uint32_t handle; - - uint16_t options; -#define ACO_DUMP_MEMORY 0x0 -#define ACO_LOAD_MEMORY 0x1 -#define ACO_CHANGE_CONFIG_PARAM 0x2 -#define ACO_REQUEST_INFO 0x3 - - uint16_t reserved1; - - uint16_t dseg_count; - uint16_t reserved2[3]; - - uint32_t parameter1; - uint32_t parameter2; - uint32_t parameter3; - - uint32_t reserved3[3]; - uint32_t total_byte_cnt; - uint32_t reserved4; - - uint32_t dseg_address[2]; - uint32_t dseg_length; -}; - -struct access_chip_rsp_84xx { - uint8_t entry_type; - uint8_t entry_count; - uint8_t sys_defined; - uint8_t entry_status; - - uint32_t handle; - - uint16_t comp_status; - uint16_t failure_code; - uint32_t residual_count; - - uint32_t reserved[12]; -}; - -/* 81XX Support **************************************************************/ - -#define MBA_DCBX_START 0x8016 -#define MBA_DCBX_COMPLETE 0x8030 -#define MBA_FCF_CONF_ERR 0x8031 -#define MBA_DCBX_PARAM_UPDATE 0x8032 -#define MBA_IDC_COMPLETE 0x8100 -#define MBA_IDC_NOTIFY 0x8101 -#define MBA_IDC_TIME_EXT 0x8102 - -#define MBC_IDC_ACK 0x101 -#define MBC_RESTART_MPI_FW 0x3d -#define MBC_FLASH_ACCESS_CTRL 0x3e /* Control flash access. */ -#define MBC_GET_XGMAC_STATS 0x7a -#define MBC_GET_DCBX_PARAMS 0x51 - -/* - * ISP83xx mailbox commands - */ -#define MBC_WRITE_REMOTE_REG 0x0001 /* Write remote register */ - -/* Flash access control option field bit definitions */ -#define FAC_OPT_FORCE_SEMAPHORE BIT_15 -#define FAC_OPT_REQUESTOR_ID BIT_14 -#define FAC_OPT_CMD_SUBCODE 0xff - -/* Flash access control command subcodes */ -#define FAC_OPT_CMD_WRITE_PROTECT 0x00 -#define FAC_OPT_CMD_WRITE_ENABLE 0x01 -#define FAC_OPT_CMD_ERASE_SECTOR 0x02 -#define FAC_OPT_CMD_LOCK_SEMAPHORE 0x03 -#define FAC_OPT_CMD_UNLOCK_SEMAPHORE 0x04 -#define FAC_OPT_CMD_GET_SECTOR_SIZE 0x05 - -struct nvram_81xx { - /* NVRAM header. */ - uint8_t id[4]; - uint16_t nvram_version; - uint16_t reserved_0; - - /* Firmware Initialization Control Block. */ - uint16_t version; - uint16_t reserved_1; - uint16_t frame_payload_size; - uint16_t execution_throttle; - uint16_t exchange_count; - uint16_t reserved_2; - - uint8_t port_name[WWN_SIZE]; - uint8_t node_name[WWN_SIZE]; - - uint16_t login_retry_count; - uint16_t reserved_3; - uint16_t interrupt_delay_timer; - uint16_t login_timeout; - - uint32_t firmware_options_1; - uint32_t firmware_options_2; - uint32_t firmware_options_3; - - uint16_t reserved_4[4]; - - /* Offset 64. */ - uint8_t enode_mac[6]; - uint16_t reserved_5[5]; - - /* Offset 80. */ - uint16_t reserved_6[24]; - - /* Offset 128. */ - uint16_t ex_version; - uint8_t prio_fcf_matching_flags; - uint8_t reserved_6_1[3]; - uint16_t pri_fcf_vlan_id; - uint8_t pri_fcf_fabric_name[8]; - uint16_t reserved_6_2[7]; - uint8_t spma_mac_addr[6]; - uint16_t reserved_6_3[14]; - - /* Offset 192. */ - uint16_t reserved_7[32]; - - /* - * BIT 0 = Enable spinup delay - * BIT 1 = Disable BIOS - * BIT 2 = Enable Memory Map BIOS - * BIT 3 = Enable Selectable Boot - * BIT 4 = Disable RISC code load - * BIT 5 = Disable Serdes - * BIT 6 = Opt boot mode - * BIT 7 = Interrupt enable - * - * BIT 8 = EV Control enable - * BIT 9 = Enable lip reset - * BIT 10 = Enable lip full login - * BIT 11 = Enable target reset - * BIT 12 = Stop firmware - * BIT 13 = Enable nodename option - * BIT 14 = Default WWPN valid - * BIT 15 = Enable alternate WWN - * - * BIT 16 = CLP LUN string - * BIT 17 = CLP Target string - * BIT 18 = CLP BIOS enable string - * BIT 19 = CLP Serdes string - * BIT 20 = CLP WWPN string - * BIT 21 = CLP WWNN string - * BIT 22 = - * BIT 23 = - * BIT 24 = Keep WWPN - * BIT 25 = Temp WWPN - * BIT 26-31 = - */ - uint32_t host_p; - - uint8_t alternate_port_name[WWN_SIZE]; - uint8_t alternate_node_name[WWN_SIZE]; - - uint8_t boot_port_name[WWN_SIZE]; - uint16_t boot_lun_number; - uint16_t reserved_8; - - uint8_t alt1_boot_port_name[WWN_SIZE]; - uint16_t alt1_boot_lun_number; - uint16_t reserved_9; - - uint8_t alt2_boot_port_name[WWN_SIZE]; - uint16_t alt2_boot_lun_number; - uint16_t reserved_10; - - uint8_t alt3_boot_port_name[WWN_SIZE]; - uint16_t alt3_boot_lun_number; - uint16_t reserved_11; - - /* - * BIT 0 = Selective Login - * BIT 1 = Alt-Boot Enable - * BIT 2 = Reserved - * BIT 3 = Boot Order List - * BIT 4 = Reserved - * BIT 5 = Selective LUN - * BIT 6 = Reserved - * BIT 7-31 = - */ - uint32_t efi_parameters; - - uint8_t reset_delay; - uint8_t reserved_12; - uint16_t reserved_13; - - uint16_t boot_id_number; - uint16_t reserved_14; - - uint16_t max_luns_per_target; - uint16_t reserved_15; - - uint16_t port_down_retry_count; - uint16_t link_down_timeout; - - /* FCode parameters. */ - uint16_t fcode_parameter; - - uint16_t reserved_16[3]; - - /* Offset 352. */ - uint8_t reserved_17[4]; - uint16_t reserved_18[5]; - uint8_t reserved_19[2]; - uint16_t reserved_20[8]; - - /* Offset 384. */ - uint8_t reserved_21[16]; - uint16_t reserved_22[3]; - - /* - * BIT 0 = Extended BB credits for LR - * BIT 1 = Virtual Fabric Enable - * BIT 2 = Enhanced Features Unused - * BIT 3-7 = Enhanced Features Reserved - */ - /* Enhanced Features */ - uint8_t enhanced_features; - - uint8_t reserved_23; - uint16_t reserved_24[4]; - - /* Offset 416. */ - uint16_t reserved_25[32]; - - /* Offset 480. */ - uint8_t model_name[16]; - - /* Offset 496. */ - uint16_t feature_mask_l; - uint16_t feature_mask_h; - uint16_t reserved_26[2]; - - uint16_t subsystem_vendor_id; - uint16_t subsystem_device_id; - - uint32_t checksum; -}; - -/* - * ISP Initialization Control Block. - * Little endian except where noted. - */ -#define ICB_VERSION 1 -struct init_cb_81xx { - uint16_t version; - uint16_t reserved_1; - - uint16_t frame_payload_size; - uint16_t execution_throttle; - uint16_t exchange_count; - - uint16_t reserved_2; - - uint8_t port_name[WWN_SIZE]; /* Big endian. */ - uint8_t node_name[WWN_SIZE]; /* Big endian. */ - - uint16_t response_q_inpointer; - uint16_t request_q_outpointer; - - uint16_t login_retry_count; - - uint16_t prio_request_q_outpointer; - - uint16_t response_q_length; - uint16_t request_q_length; - - uint16_t reserved_3; - - uint16_t prio_request_q_length; - - uint32_t request_q_address[2]; - uint32_t response_q_address[2]; - uint32_t prio_request_q_address[2]; - - uint8_t reserved_4[8]; - - uint16_t atio_q_inpointer; - uint16_t atio_q_length; - uint32_t atio_q_address[2]; - - uint16_t interrupt_delay_timer; /* 100us increments. */ - uint16_t login_timeout; - - /* - * BIT 0-3 = Reserved - * BIT 4 = Enable Target Mode - * BIT 5 = Disable Initiator Mode - * BIT 6 = Reserved - * BIT 7 = Reserved - * - * BIT 8-13 = Reserved - * BIT 14 = Node Name Option - * BIT 15-31 = Reserved - */ - uint32_t firmware_options_1; - - /* - * BIT 0 = Operation Mode bit 0 - * BIT 1 = Operation Mode bit 1 - * BIT 2 = Operation Mode bit 2 - * BIT 3 = Operation Mode bit 3 - * BIT 4-7 = Reserved - * - * BIT 8 = Enable Class 2 - * BIT 9 = Enable ACK0 - * BIT 10 = Reserved - * BIT 11 = Enable FC-SP Security - * BIT 12 = FC Tape Enable - * BIT 13 = Reserved - * BIT 14 = Enable Target PRLI Control - * BIT 15-31 = Reserved - */ - uint32_t firmware_options_2; - - /* - * BIT 0-3 = Reserved - * BIT 4 = FCP RSP Payload bit 0 - * BIT 5 = FCP RSP Payload bit 1 - * BIT 6 = Enable Receive Out-of-Order data frame handling - * BIT 7 = Reserved - * - * BIT 8 = Reserved - * BIT 9 = Enable Out-of-Order FCP_XFER_RDY relative offset handling - * BIT 10-16 = Reserved - * BIT 17 = Enable multiple FCFs - * BIT 18-20 = MAC addressing mode - * BIT 21-25 = Ethernet data rate - * BIT 26 = Enable ethernet header rx IOCB for ATIO q - * BIT 27 = Enable ethernet header rx IOCB for response q - * BIT 28 = SPMA selection bit 0 - * BIT 28 = SPMA selection bit 1 - * BIT 30-31 = Reserved - */ - uint32_t firmware_options_3; - - uint8_t reserved_5[8]; - - uint8_t enode_mac[6]; - - uint8_t reserved_6[10]; -}; - -struct mid_init_cb_81xx { - struct init_cb_81xx init_cb; - - uint16_t count; - uint16_t options; - - struct mid_conf_entry_24xx entries[MAX_MULTI_ID_FABRIC]; -}; - -struct ex_init_cb_81xx { - uint16_t ex_version; - uint8_t prio_fcf_matching_flags; - uint8_t reserved_1[3]; - uint16_t pri_fcf_vlan_id; - uint8_t pri_fcf_fabric_name[8]; - uint16_t reserved_2[7]; - uint8_t spma_mac_addr[6]; - uint16_t reserved_3[14]; -}; - -#define FARX_ACCESS_FLASH_CONF_81XX 0x7FFD0000 -#define FARX_ACCESS_FLASH_DATA_81XX 0x7F800000 - -/* FCP priority config defines *************************************/ -/* operations */ -#define QLFC_FCP_PRIO_DISABLE 0x0 -#define QLFC_FCP_PRIO_ENABLE 0x1 -#define QLFC_FCP_PRIO_GET_CONFIG 0x2 -#define QLFC_FCP_PRIO_SET_CONFIG 0x3 - -struct qla_fcp_prio_entry { - uint16_t flags; /* Describes parameter(s) in FCP */ - /* priority entry that are valid */ -#define FCP_PRIO_ENTRY_VALID 0x1 -#define FCP_PRIO_ENTRY_TAG_VALID 0x2 -#define FCP_PRIO_ENTRY_SPID_VALID 0x4 -#define FCP_PRIO_ENTRY_DPID_VALID 0x8 -#define FCP_PRIO_ENTRY_LUNB_VALID 0x10 -#define FCP_PRIO_ENTRY_LUNE_VALID 0x20 -#define FCP_PRIO_ENTRY_SWWN_VALID 0x40 -#define FCP_PRIO_ENTRY_DWWN_VALID 0x80 - uint8_t tag; /* Priority value */ - uint8_t reserved; /* Reserved for future use */ - uint32_t src_pid; /* Src port id. high order byte */ - /* unused; -1 (wild card) */ - uint32_t dst_pid; /* Src port id. high order byte */ - /* unused; -1 (wild card) */ - uint16_t lun_beg; /* 1st lun num of lun range. */ - /* -1 (wild card) */ - uint16_t lun_end; /* 2nd lun num of lun range. */ - /* -1 (wild card) */ - uint8_t src_wwpn[8]; /* Source WWPN: -1 (wild card) */ - uint8_t dst_wwpn[8]; /* Destination WWPN: -1 (wild card) */ -}; - -struct qla_fcp_prio_cfg { - uint8_t signature[4]; /* "HQOS" signature of config data */ - uint16_t version; /* 1: Initial version */ - uint16_t length; /* config data size in num bytes */ - uint16_t checksum; /* config data bytes checksum */ - uint16_t num_entries; /* Number of entries */ - uint16_t size_of_entry; /* Size of each entry in num bytes */ - uint8_t attributes; /* enable/disable, persistence */ -#define FCP_PRIO_ATTR_DISABLE 0x0 -#define FCP_PRIO_ATTR_ENABLE 0x1 -#define FCP_PRIO_ATTR_PERSIST 0x2 - uint8_t reserved; /* Reserved for future use */ -#define FCP_PRIO_CFG_HDR_SIZE 0x10 - struct qla_fcp_prio_entry entry[1]; /* fcp priority entries */ -#define FCP_PRIO_CFG_ENTRY_SIZE 0x20 -}; - -#define FCP_PRIO_CFG_SIZE (32*1024) /* fcp prio data per port*/ - -/* 25XX Support ****************************************************/ -#define FA_FCP_PRIO0_ADDR_25 0x3C000 -#define FA_FCP_PRIO1_ADDR_25 0x3E000 - -/* 81XX Flash locations -- occupies second 2MB region. */ -#define FA_BOOT_CODE_ADDR_81 0x80000 -#define FA_RISC_CODE_ADDR_81 0xA0000 -#define FA_FW_AREA_ADDR_81 0xC0000 -#define FA_VPD_NVRAM_ADDR_81 0xD0000 -#define FA_VPD0_ADDR_81 0xD0000 -#define FA_VPD1_ADDR_81 0xD0400 -#define FA_NVRAM0_ADDR_81 0xD0080 -#define FA_NVRAM1_ADDR_81 0xD0180 -#define FA_FEATURE_ADDR_81 0xD4000 -#define FA_FLASH_DESCR_ADDR_81 0xD8000 -#define FA_FLASH_LAYOUT_ADDR_81 0xD8400 -#define FA_HW_EVENT0_ADDR_81 0xDC000 -#define FA_HW_EVENT1_ADDR_81 0xDC400 -#define FA_NPIV_CONF0_ADDR_81 0xD1000 -#define FA_NPIV_CONF1_ADDR_81 0xD2000 - -/* 83XX Flash locations -- occupies second 8MB region. */ -#define FA_FLASH_LAYOUT_ADDR_83 0xFC400 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gbl.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gbl.h deleted file mode 100644 index 9f065804..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gbl.h +++ /dev/null @@ -1,611 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#ifndef __QLA_GBL_H -#define __QLA_GBL_H - -#include - -/* - * Global Function Prototypes in qla_init.c source file. - */ -extern int qla2x00_initialize_adapter(scsi_qla_host_t *); - -extern int qla2100_pci_config(struct scsi_qla_host *); -extern int qla2300_pci_config(struct scsi_qla_host *); -extern int qla24xx_pci_config(scsi_qla_host_t *); -extern int qla25xx_pci_config(scsi_qla_host_t *); -extern void qla2x00_reset_chip(struct scsi_qla_host *); -extern void qla24xx_reset_chip(struct scsi_qla_host *); -extern int qla2x00_chip_diag(struct scsi_qla_host *); -extern int qla24xx_chip_diag(struct scsi_qla_host *); -extern void qla2x00_config_rings(struct scsi_qla_host *); -extern void qla24xx_config_rings(struct scsi_qla_host *); -extern void qla2x00_reset_adapter(struct scsi_qla_host *); -extern void qla24xx_reset_adapter(struct scsi_qla_host *); -extern int qla2x00_nvram_config(struct scsi_qla_host *); -extern int qla24xx_nvram_config(struct scsi_qla_host *); -extern int qla81xx_nvram_config(struct scsi_qla_host *); -extern void qla2x00_update_fw_options(struct scsi_qla_host *); -extern void qla24xx_update_fw_options(scsi_qla_host_t *); -extern void qla81xx_update_fw_options(scsi_qla_host_t *); -extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *); -extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *); -extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *); - -extern int qla2x00_perform_loop_resync(scsi_qla_host_t *); -extern int qla2x00_loop_resync(scsi_qla_host_t *); - -extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *); - -extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); -extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); - -extern void qla2x00_update_fcports(scsi_qla_host_t *); - -extern int qla2x00_abort_isp(scsi_qla_host_t *); -extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *); -extern void qla82xx_quiescent_state_cleanup(scsi_qla_host_t *); - -extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); - -extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); -extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); - -extern int qla2x00_get_thermal_temp(scsi_qla_host_t *, uint16_t *, uint16_t *); - -extern void qla84xx_put_chip(struct scsi_qla_host *); - -extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *, - uint16_t *); -extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *); -extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *, - uint16_t *); -extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t); -extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, - uint16_t *); -extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, - uint16_t *); -extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, - uint16_t *); -extern void *qla2x00_alloc_iocbs(struct scsi_qla_host *, srb_t *); -extern int qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *, fc_port_t *); - -extern fc_port_t * -qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t ); -/* - * Global Data in qla_os.c source file. - */ -extern char qla2x00_version_str[]; - -extern int ql2xlogintimeout; -extern int qlport_down_retry; -extern int ql2xplogiabsentdevice; -extern int ql2xloginretrycount; -extern int ql2xfdmienable; -extern int ql2xallocfwdump; -extern int ql2xextended_error_logging; -extern int ql2xiidmaenable; -extern int ql2xmaxqueues; -extern int ql2xmultique_tag; -extern int ql2xfwloadbin; -extern int ql2xetsenable; -extern int ql2xshiftctondsd; -extern int ql2xdbwr; -extern int ql2xasynctmfenable; -extern int ql2xgffidenable; -extern int ql2xenabledif; -extern int ql2xenablehba_err_chk; -extern int ql2xtargetreset; -extern int ql2xdontresethba; -extern unsigned int ql2xmaxlun; -extern int ql2xmdcapmask; -extern int ql2xmdenable; - -extern int qla2x00_loop_reset(scsi_qla_host_t *); -extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); -extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum - fc_host_event_code, u32); -extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *); -extern int qla2x00_post_async_login_work(struct scsi_qla_host *, fc_port_t *, - uint16_t *); -extern int qla2x00_post_async_login_done_work(struct scsi_qla_host *, - fc_port_t *, uint16_t *); -extern int qla2x00_post_async_logout_work(struct scsi_qla_host *, fc_port_t *, - uint16_t *); -extern int qla2x00_post_async_logout_done_work(struct scsi_qla_host *, - fc_port_t *, uint16_t *); -extern int qla2x00_post_async_adisc_work(struct scsi_qla_host *, fc_port_t *, - uint16_t *); -extern int qla2x00_post_async_adisc_done_work(struct scsi_qla_host *, - fc_port_t *, uint16_t *); -extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32); - -extern int qla81xx_restart_mpi_firmware(scsi_qla_host_t *); - -extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *, - struct qla_hw_data *); -extern void qla2x00_free_host(struct scsi_qla_host *); -extern void qla2x00_relogin(struct scsi_qla_host *); -extern void qla2x00_do_work(struct scsi_qla_host *); -extern void qla2x00_free_fcports(struct scsi_qla_host *); - -/* - * Global Functions in qla_mid.c source file. - */ -extern struct scsi_host_template qla2xxx_driver_template; -extern struct scsi_transport_template *qla2xxx_transport_vport_template; -extern void qla2x00_timer(scsi_qla_host_t *); -extern void qla2x00_start_timer(scsi_qla_host_t *, void *, unsigned long); -extern void qla24xx_deallocate_vp_id(scsi_qla_host_t *); -extern int qla24xx_disable_vp (scsi_qla_host_t *); -extern int qla24xx_enable_vp (scsi_qla_host_t *); -extern int qla24xx_control_vp(scsi_qla_host_t *, int ); -extern int qla24xx_modify_vp_config(scsi_qla_host_t *); -extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t); -extern void qla2x00_vp_stop_timer(scsi_qla_host_t *); -extern int qla24xx_configure_vhba (scsi_qla_host_t *); -extern void qla24xx_report_id_acquisition(scsi_qla_host_t *, - struct vp_rpt_id_entry_24xx *); -extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *); -extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *); -extern scsi_qla_host_t * qla24xx_create_vhost(struct fc_vport *); - -extern void qla2x00_sp_free_dma(void *, void *); -extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *); - -extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int, int); -extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *, int); - -extern struct fw_blob *qla2x00_request_firmware(scsi_qla_host_t *); - -extern int qla2x00_wait_for_hba_online(scsi_qla_host_t *); -extern int qla2x00_wait_for_chip_reset(scsi_qla_host_t *); -extern int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *); - -extern void qla2xxx_wake_dpc(struct scsi_qla_host *); -extern void qla2x00_alert_all_vps(struct rsp_que *, uint16_t *); -extern void qla2x00_async_event(scsi_qla_host_t *, struct rsp_que *, - uint16_t *); -extern int qla2x00_vp_abort_isp(scsi_qla_host_t *); - -/* - * Global Function Prototypes in qla_iocb.c source file. - */ -extern uint16_t qla2x00_calc_iocbs_32(uint16_t); -extern uint16_t qla2x00_calc_iocbs_64(uint16_t); -extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); -extern void qla2x00_build_scsi_iocbs_64(srb_t *, cmd_entry_t *, uint16_t); -extern int qla2x00_start_scsi(srb_t *sp); -extern int qla24xx_start_scsi(srb_t *sp); -int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, - uint16_t, uint16_t, uint8_t); -extern int qla2x00_start_sp(srb_t *); -extern uint16_t qla24xx_calc_iocbs(scsi_qla_host_t *, uint16_t); -extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t); -extern int qla24xx_dif_start_scsi(srb_t *); - - -/* - * Global Function Prototypes in qla_mbx.c source file. - */ -extern int -qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); - -extern int -qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t); - -extern int -qla2x00_execute_fw(scsi_qla_host_t *, uint32_t); - -extern int -qla2x00_get_fw_version(scsi_qla_host_t *); - -extern int -qla2x00_get_fw_options(scsi_qla_host_t *, uint16_t *); - -extern int -qla2x00_set_fw_options(scsi_qla_host_t *, uint16_t *); - -extern int -qla2x00_mbx_reg_test(scsi_qla_host_t *); - -extern int -qla2x00_verify_checksum(scsi_qla_host_t *, uint32_t); - -extern int -qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t); - -extern int -qla2x00_abort_command(srb_t *); - -extern int -qla2x00_abort_target(struct fc_port *, unsigned int, int); - -extern int -qla2x00_lun_reset(struct fc_port *, unsigned int, int); - -extern int -qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, - uint8_t *, uint16_t *, uint16_t *); - -extern int -qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *); - -extern int -qla2x00_init_firmware(scsi_qla_host_t *, uint16_t); - -extern int -qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t); - -extern int -qla2x00_get_firmware_state(scsi_qla_host_t *, uint16_t *); - -extern int -qla2x00_get_port_name(scsi_qla_host_t *, uint16_t, uint8_t *, uint8_t); - -extern int -qla2x00_lip_reset(scsi_qla_host_t *); - -extern int -qla2x00_send_sns(scsi_qla_host_t *, dma_addr_t, uint16_t, size_t); - -extern int -qla2x00_login_fabric(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t, - uint16_t *, uint8_t); -extern int -qla24xx_login_fabric(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t, - uint16_t *, uint8_t); - -extern int -qla2x00_login_local_device(scsi_qla_host_t *, fc_port_t *, uint16_t *, - uint8_t); - -extern int -qla2x00_fabric_logout(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t); - -extern int -qla24xx_fabric_logout(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t); - -extern int -qla2x00_full_login_lip(scsi_qla_host_t *ha); - -extern int -qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *); - -extern int -qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, - uint16_t *, uint16_t *, uint16_t *, uint16_t *); - -extern int -qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map); - -extern int -qla2x00_get_link_status(scsi_qla_host_t *, uint16_t, struct link_statistics *, - dma_addr_t); - -extern int -qla24xx_get_isp_stats(scsi_qla_host_t *, struct link_statistics *, - dma_addr_t); - -extern int qla24xx_abort_command(srb_t *); -extern int -qla24xx_abort_target(struct fc_port *, unsigned int, int); -extern int -qla24xx_lun_reset(struct fc_port *, unsigned int, int); -extern int -qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *, unsigned int, - unsigned int, enum nexus_wait_type); -extern int -qla2x00_system_error(scsi_qla_host_t *); - -extern int -qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); - -extern int -qla2x00_stop_firmware(scsi_qla_host_t *); - -extern int -qla2x00_enable_eft_trace(scsi_qla_host_t *, dma_addr_t, uint16_t); -extern int -qla2x00_disable_eft_trace(scsi_qla_host_t *); - -extern int -qla2x00_enable_fce_trace(scsi_qla_host_t *, dma_addr_t, uint16_t , uint16_t *, - uint32_t *); - -extern int -qla2x00_disable_fce_trace(scsi_qla_host_t *, uint64_t *, uint64_t *); - -extern int -qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *, - uint16_t, uint16_t, uint16_t, uint16_t); - -extern int -qla2x00_write_sfp(scsi_qla_host_t *, dma_addr_t, uint8_t *, - uint16_t, uint16_t, uint16_t, uint16_t); - -extern int -qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *); - -extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *); - -extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *); - -extern int -qla81xx_fac_get_sector_size(scsi_qla_host_t *, uint32_t *); - -extern int -qla81xx_fac_do_write_enable(scsi_qla_host_t *, int); - -extern int -qla81xx_fac_erase_sector(scsi_qla_host_t *, uint32_t, uint32_t); - -extern int -qla2x00_get_xgmac_stats(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t *); - -extern int -qla2x00_get_dcbx_params(scsi_qla_host_t *, dma_addr_t, uint16_t); - -extern int -qla2x00_read_ram_word(scsi_qla_host_t *, uint32_t, uint32_t *); - -extern int -qla2x00_write_ram_word(scsi_qla_host_t *, uint32_t, uint32_t); - -extern int -qla81xx_write_mpi_register(scsi_qla_host_t *, uint16_t *); -extern int qla2x00_get_data_rate(scsi_qla_host_t *); -extern int qla24xx_set_fcp_prio(scsi_qla_host_t *, uint16_t, uint16_t, - uint16_t *); -extern int -qla81xx_get_port_config(scsi_qla_host_t *, uint16_t *); - -extern int -qla81xx_set_port_config(scsi_qla_host_t *, uint16_t *); - -extern int -qla2x00_port_logout(scsi_qla_host_t *, struct fc_port *); - -/* - * Global Function Prototypes in qla_isr.c source file. - */ -extern irqreturn_t qla2100_intr_handler(int, void *); -extern irqreturn_t qla2300_intr_handler(int, void *); -extern irqreturn_t qla24xx_intr_handler(int, void *); -extern void qla2x00_process_response_queue(struct rsp_que *); -extern void -qla24xx_process_response_queue(struct scsi_qla_host *, struct rsp_que *); -extern int qla2x00_request_irqs(struct qla_hw_data *, struct rsp_que *); -extern void qla2x00_free_irqs(scsi_qla_host_t *); - -extern int qla2x00_get_data_rate(scsi_qla_host_t *); -/* - * Global Function Prototypes in qla_sup.c source file. - */ -extern void qla2x00_release_nvram_protection(scsi_qla_host_t *); -extern uint32_t *qla24xx_read_flash_data(scsi_qla_host_t *, uint32_t *, - uint32_t, uint32_t); -extern uint8_t *qla2x00_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern uint8_t *qla24xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern int qla2x00_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern int qla24xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern uint8_t *qla25xx_read_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); -extern int qla25xx_write_nvram_data(scsi_qla_host_t *, uint8_t *, uint32_t, - uint32_t); - -extern int qla2x00_beacon_on(struct scsi_qla_host *); -extern int qla2x00_beacon_off(struct scsi_qla_host *); -extern void qla2x00_beacon_blink(struct scsi_qla_host *); -extern int qla24xx_beacon_on(struct scsi_qla_host *); -extern int qla24xx_beacon_off(struct scsi_qla_host *); -extern void qla24xx_beacon_blink(struct scsi_qla_host *); -extern void qla83xx_beacon_blink(struct scsi_qla_host *); -extern int qla82xx_beacon_on(struct scsi_qla_host *); -extern int qla82xx_beacon_off(struct scsi_qla_host *); -extern int qla83xx_write_remote_reg(struct scsi_qla_host *, uint32_t, uint32_t); - -extern uint8_t *qla2x00_read_optrom_data(struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); -extern int qla2x00_write_optrom_data(struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); -extern uint8_t *qla24xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); -extern int qla24xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); -extern uint8_t *qla25xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); - -extern int qla2x00_get_flash_version(scsi_qla_host_t *, void *); -extern int qla24xx_get_flash_version(scsi_qla_host_t *, void *); - -extern int qla2xxx_get_flash_info(scsi_qla_host_t *); -extern int qla2xxx_get_vpd_field(scsi_qla_host_t *, char *, char *, size_t); - -extern void qla2xxx_flash_npiv_conf(scsi_qla_host_t *); -extern int qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *); - -/* - * Global Function Prototypes in qla_dbg.c source file. - */ -extern void qla2100_fw_dump(scsi_qla_host_t *, int); -extern void qla2300_fw_dump(scsi_qla_host_t *, int); -extern void qla24xx_fw_dump(scsi_qla_host_t *, int); -extern void qla25xx_fw_dump(scsi_qla_host_t *, int); -extern void qla81xx_fw_dump(scsi_qla_host_t *, int); -extern void qla2x00_dump_regs(scsi_qla_host_t *); -extern void qla2x00_dump_buffer(uint8_t *, uint32_t); -extern void qla2x00_dump_buffer_zipped(uint8_t *, uint32_t); -extern void ql_dump_regs(uint32_t, scsi_qla_host_t *, int32_t); -extern void ql_dump_buffer(uint32_t, scsi_qla_host_t *, int32_t, - uint8_t *, uint32_t); -extern void qla2xxx_dump_post_process(scsi_qla_host_t *, int); - -/* - * Global Function Prototypes in qla_gs.c source file. - */ -extern void *qla2x00_prep_ms_iocb(scsi_qla_host_t *, uint32_t, uint32_t); -extern void *qla24xx_prep_ms_iocb(scsi_qla_host_t *, uint32_t, uint32_t); -extern int qla2x00_ga_nxt(scsi_qla_host_t *, fc_port_t *); -extern int qla2x00_gid_pt(scsi_qla_host_t *, sw_info_t *); -extern int qla2x00_gpn_id(scsi_qla_host_t *, sw_info_t *); -extern int qla2x00_gnn_id(scsi_qla_host_t *, sw_info_t *); -extern void qla2x00_gff_id(scsi_qla_host_t *, sw_info_t *); -extern int qla2x00_rft_id(scsi_qla_host_t *); -extern int qla2x00_rff_id(scsi_qla_host_t *); -extern int qla2x00_rnn_id(scsi_qla_host_t *); -extern int qla2x00_rsnn_nn(scsi_qla_host_t *); -extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); -extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); -extern int qla2x00_fdmi_register(scsi_qla_host_t *); -extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *); -extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *); -extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *); - -/* - * Global Function Prototypes in qla_attr.c source file. - */ -struct device_attribute; -extern struct device_attribute *qla2x00_host_attrs[]; -struct fc_function_template; -extern struct fc_function_template qla2xxx_transport_functions; -extern struct fc_function_template qla2xxx_transport_vport_functions; -extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); -extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); -extern void qla2x00_init_host_attr(scsi_qla_host_t *); -extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); -extern void qla2x00_free_sysfs_attr(scsi_qla_host_t *); -extern int qla2x00_loopback_test(scsi_qla_host_t *, struct msg_echo_lb *, uint16_t *); -extern int qla2x00_echo_test(scsi_qla_host_t *, - struct msg_echo_lb *, uint16_t *); -extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *); -extern int qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *, - struct qla_fcp_prio_cfg *, uint8_t); - -/* - * Global Function Prototypes in qla_dfs.c source file. - */ -extern int qla2x00_dfs_setup(scsi_qla_host_t *); -extern int qla2x00_dfs_remove(scsi_qla_host_t *); - -/* Globa function prototypes for multi-q */ -extern int qla25xx_request_irq(struct rsp_que *); -extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *); -extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *); -extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, - uint16_t, int, uint8_t); -extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t, - uint16_t, int); -extern void qla2x00_init_response_q_entries(struct rsp_que *); -extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *); -extern int qla25xx_delete_queues(struct scsi_qla_host *); -extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t); -extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t); -extern void qla24xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t); -extern void qla25xx_wrt_req_reg(struct qla_hw_data *, uint16_t, uint16_t); -extern void qla25xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); -extern void qla24xx_wrt_rsp_reg(struct qla_hw_data *, uint16_t, uint16_t); - -/* qla82xx related functions */ - -/* PCI related functions */ -extern int qla82xx_pci_config(struct scsi_qla_host *); -extern int qla82xx_pci_mem_read_2M(struct qla_hw_data *, u64, void *, int); -extern char *qla82xx_pci_info_str(struct scsi_qla_host *, char *); -extern int qla82xx_pci_region_offset(struct pci_dev *, int); -extern int qla82xx_iospace_config(struct qla_hw_data *); - -/* Initialization related functions */ -extern void qla82xx_reset_chip(struct scsi_qla_host *); -extern void qla82xx_config_rings(struct scsi_qla_host *); -extern void qla82xx_watchdog(scsi_qla_host_t *); -extern int qla82xx_start_firmware(scsi_qla_host_t *); - -/* Firmware and flash related functions */ -extern int qla82xx_load_risc(scsi_qla_host_t *, uint32_t *); -extern uint8_t *qla82xx_read_optrom_data(struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); -extern int qla82xx_write_optrom_data(struct scsi_qla_host *, uint8_t *, - uint32_t, uint32_t); - -/* Mailbox related functions */ -extern int qla82xx_abort_isp(scsi_qla_host_t *); -extern int qla82xx_restart_isp(scsi_qla_host_t *); - -/* IOCB related functions */ -extern int qla82xx_start_scsi(srb_t *); -extern void qla2x00_sp_free(void *, void *); -extern void qla2x00_sp_timeout(unsigned long); -extern void qla2x00_bsg_job_done(void *, void *, int); -extern void qla2x00_bsg_sp_free(void *, void *); - -/* Interrupt related */ -extern irqreturn_t qla82xx_intr_handler(int, void *); -extern irqreturn_t qla82xx_msi_handler(int, void *); -extern irqreturn_t qla82xx_msix_default(int, void *); -extern irqreturn_t qla82xx_msix_rsp_q(int, void *); -extern void qla82xx_enable_intrs(struct qla_hw_data *); -extern void qla82xx_disable_intrs(struct qla_hw_data *); -extern void qla82xx_poll(int, void *); -extern void qla82xx_init_flags(struct qla_hw_data *); - -/* ISP 8021 hardware related */ -extern void qla82xx_set_drv_active(scsi_qla_host_t *); -extern void qla82xx_crb_win_unlock(struct qla_hw_data *); -extern int qla82xx_wr_32(struct qla_hw_data *, ulong, u32); -extern int qla82xx_rd_32(struct qla_hw_data *, ulong); -extern int qla82xx_rdmem(struct qla_hw_data *, u64, void *, int); -extern int qla82xx_wrmem(struct qla_hw_data *, u64, void *, int); - -/* ISP 8021 IDC */ -extern void qla82xx_clear_drv_active(struct qla_hw_data *); -extern uint32_t qla82xx_wait_for_state_change(scsi_qla_host_t *, uint32_t); -extern int qla82xx_idc_lock(struct qla_hw_data *); -extern void qla82xx_idc_unlock(struct qla_hw_data *); -extern int qla82xx_device_state_handler(scsi_qla_host_t *); -extern void qla82xx_clear_qsnt_ready(scsi_qla_host_t *); - -extern void qla2x00_set_model_info(scsi_qla_host_t *, uint8_t *, - size_t, char *); -extern int qla82xx_mbx_intr_enable(scsi_qla_host_t *); -extern int qla82xx_mbx_intr_disable(scsi_qla_host_t *); -extern void qla82xx_start_iocbs(scsi_qla_host_t *); -extern int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *); -extern int qla82xx_check_md_needed(scsi_qla_host_t *); -extern void qla82xx_chip_reset_cleanup(scsi_qla_host_t *); -extern int qla81xx_set_led_config(scsi_qla_host_t *, uint16_t *); -extern int qla81xx_get_led_config(scsi_qla_host_t *, uint16_t *); -extern int qla82xx_mbx_beacon_ctl(scsi_qla_host_t *, int); -extern char *qdev_state(uint32_t); -extern void qla82xx_clear_pending_mbx(scsi_qla_host_t *); - -/* BSG related functions */ -extern int qla24xx_bsg_request(struct fc_bsg_job *); -extern int qla24xx_bsg_timeout(struct fc_bsg_job *); -extern int qla84xx_reset_chip(scsi_qla_host_t *, uint16_t); -extern int qla2x00_issue_iocb_timeout(scsi_qla_host_t *, void *, - dma_addr_t, size_t, uint32_t); -extern int qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, - uint16_t *, uint16_t *); - -/* 83xx related functions */ -extern void qla83xx_fw_dump(scsi_qla_host_t *, int); - -/* Minidump related functions */ -extern int qla82xx_md_get_template_size(scsi_qla_host_t *); -extern int qla82xx_md_get_template(scsi_qla_host_t *); -extern int qla82xx_md_alloc(scsi_qla_host_t *); -extern void qla82xx_md_free(scsi_qla_host_t *); -extern int qla82xx_md_collect(scsi_qla_host_t *); -extern void qla82xx_md_prep(scsi_qla_host_t *); -extern void qla82xx_set_reset_owner(scsi_qla_host_t *); - -#endif /* _QLA_GBL_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gs.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gs.c deleted file mode 100644 index 3128f804..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_gs.c +++ /dev/null @@ -1,2025 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -static int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *); -static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *); -static int qla2x00_sns_gpn_id(scsi_qla_host_t *, sw_info_t *); -static int qla2x00_sns_gnn_id(scsi_qla_host_t *, sw_info_t *); -static int qla2x00_sns_rft_id(scsi_qla_host_t *); -static int qla2x00_sns_rnn_id(scsi_qla_host_t *); - -/** - * qla2x00_prep_ms_iocb() - Prepare common MS/CT IOCB fields for SNS CT query. - * @ha: HA context - * @req_size: request size in bytes - * @rsp_size: response size in bytes - * - * Returns a pointer to the @ha's ms_iocb. - */ -void * -qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size) -{ - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - - ms_pkt = ha->ms_iocb; - memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); - - ms_pkt->entry_type = MS_IOCB_TYPE; - ms_pkt->entry_count = 1; - SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER); - ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); - ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); - ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); - ms_pkt->req_bytecount = cpu_to_le32(req_size); - - ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ms_pkt->dseg_req_length = ms_pkt->req_bytecount; - - ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; - - return (ms_pkt); -} - -/** - * qla24xx_prep_ms_iocb() - Prepare common CT IOCB fields for SNS CT query. - * @ha: HA context - * @req_size: request size in bytes - * @rsp_size: response size in bytes - * - * Returns a pointer to the @ha's ms_iocb. - */ -void * -qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size) -{ - struct qla_hw_data *ha = vha->hw; - struct ct_entry_24xx *ct_pkt; - - ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; - memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); - - ct_pkt->entry_type = CT_IOCB_TYPE; - ct_pkt->entry_count = 1; - ct_pkt->nport_handle = __constant_cpu_to_le16(NPH_SNS); - ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); - ct_pkt->cmd_byte_count = cpu_to_le32(req_size); - - ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; - - ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; - ct_pkt->vp_index = vha->vp_idx; - - return (ct_pkt); -} - -/** - * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. - * @ct_req: CT request buffer - * @cmd: GS command - * @rsp_size: response size in bytes - * - * Returns a pointer to the intitialized @ct_req. - */ -static inline struct ct_sns_req * -qla2x00_prep_ct_req(struct ct_sns_req *ct_req, uint16_t cmd, uint16_t rsp_size) -{ - memset(ct_req, 0, sizeof(struct ct_sns_pkt)); - - ct_req->header.revision = 0x01; - ct_req->header.gs_type = 0xFC; - ct_req->header.gs_subtype = 0x02; - ct_req->command = cpu_to_be16(cmd); - ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); - - return (ct_req); -} - -static int -qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, - struct ct_sns_rsp *ct_rsp, const char *routine) -{ - int rval; - uint16_t comp_status; - struct qla_hw_data *ha = vha->hw; - - rval = QLA_FUNCTION_FAILED; - if (ms_pkt->entry_status != 0) { - ql_dbg(ql_dbg_disc, vha, 0x2031, - "%s failed, error status (%x) on port_id: %02x%02x%02x.\n", - routine, ms_pkt->entry_status, vha->d_id.b.domain, - vha->d_id.b.area, vha->d_id.b.al_pa); - } else { - if (IS_FWI2_CAPABLE(ha)) - comp_status = le16_to_cpu( - ((struct ct_entry_24xx *)ms_pkt)->comp_status); - else - comp_status = le16_to_cpu(ms_pkt->status); - switch (comp_status) { - case CS_COMPLETE: - case CS_DATA_UNDERRUN: - case CS_DATA_OVERRUN: /* Overrun? */ - if (ct_rsp->header.response != - __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { - ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2077, - "%s failed rejected request on port_id: " - "%02x%02x%02x.\n", routine, - vha->d_id.b.domain, vha->d_id.b.area, - vha->d_id.b.al_pa); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, - 0x2078, (uint8_t *)&ct_rsp->header, - sizeof(struct ct_rsp_hdr)); - rval = QLA_INVALID_COMMAND; - } else - rval = QLA_SUCCESS; - break; - default: - ql_dbg(ql_dbg_disc, vha, 0x2033, - "%s failed, completion status (%x) on port_id: " - "%02x%02x%02x.\n", routine, comp_status, - vha->d_id.b.domain, vha->d_id.b.area, - vha->d_id.b.al_pa); - break; - } - } - return rval; -} - -/** - * qla2x00_ga_nxt() - SNS scan for fabric devices via GA_NXT command. - * @ha: HA context - * @fcport: fcport entry to updated - * - * Returns 0 on success. - */ -int -qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - int rval; - - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - struct qla_hw_data *ha = vha->hw; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return qla2x00_sns_ga_nxt(vha, fcport); - - /* Issue GA_NXT */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GA_NXT_REQ_SIZE, - GA_NXT_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD, - GA_NXT_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain; - ct_req->req.port_id.port_id[1] = fcport->d_id.b.area; - ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa; - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2062, - "GA_NXT issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GA_NXT") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - } else { - /* Populate fc_port_t entry. */ - fcport->d_id.b.domain = ct_rsp->rsp.ga_nxt.port_id[0]; - fcport->d_id.b.area = ct_rsp->rsp.ga_nxt.port_id[1]; - fcport->d_id.b.al_pa = ct_rsp->rsp.ga_nxt.port_id[2]; - - memcpy(fcport->node_name, ct_rsp->rsp.ga_nxt.node_name, - WWN_SIZE); - memcpy(fcport->port_name, ct_rsp->rsp.ga_nxt.port_name, - WWN_SIZE); - - if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE && - ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE) - fcport->d_id.b.domain = 0xf0; - - ql_dbg(ql_dbg_disc, vha, 0x2063, - "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x " - "pn %02x%02x%02x%02x%02x%02x%02x%02x " - "port_id=%02x%02x%02x.\n", - fcport->node_name[0], fcport->node_name[1], - fcport->node_name[2], fcport->node_name[3], - fcport->node_name[4], fcport->node_name[5], - fcport->node_name[6], fcport->node_name[7], - fcport->port_name[0], fcport->port_name[1], - fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7], - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - } - - return (rval); -} - -static inline int -qla2x00_gid_pt_rsp_size(scsi_qla_host_t *vha) -{ - return vha->hw->max_fibre_devices * 4 + 16; -} - -/** - * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command. - * @ha: HA context - * @list: switch info entries to populate - * - * NOTE: Non-Nx_Ports are not requested. - * - * Returns 0 on success. - */ -int -qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval; - uint16_t i; - - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - struct ct_sns_gid_pt_data *gid_data; - struct qla_hw_data *ha = vha->hw; - uint16_t gid_pt_rsp_size; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return qla2x00_sns_gid_pt(vha, list); - - gid_data = NULL; - gid_pt_rsp_size = qla2x00_gid_pt_rsp_size(vha); - /* Issue GID_PT */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GID_PT_REQ_SIZE, - gid_pt_rsp_size); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD, - gid_pt_rsp_size); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_type */ - ct_req->req.gid_pt.port_type = NS_NX_PORT_TYPE; - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2055, - "GID_PT issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GID_PT") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - } else { - /* Set port IDs in switch info list. */ - for (i = 0; i < ha->max_fibre_devices; i++) { - gid_data = &ct_rsp->rsp.gid_pt.entries[i]; - list[i].d_id.b.domain = gid_data->port_id[0]; - list[i].d_id.b.area = gid_data->port_id[1]; - list[i].d_id.b.al_pa = gid_data->port_id[2]; - memset(list[i].fabric_port_name, 0, WWN_SIZE); - list[i].fp_speed = PORT_SPEED_UNKNOWN; - - /* Last one exit. */ - if (gid_data->control_byte & BIT_7) { - list[i].d_id.b.rsvd_1 = gid_data->control_byte; - break; - } - } - - /* - * If we've used all available slots, then the switch is - * reporting back more devices than we can handle with this - * single call. Return a failed status, and let GA_NXT handle - * the overload. - */ - if (i == ha->max_fibre_devices) - rval = QLA_FUNCTION_FAILED; - } - - return (rval); -} - -/** - * qla2x00_gpn_id() - SNS Get Port Name (GPN_ID) query. - * @ha: HA context - * @list: switch info entries to populate - * - * Returns 0 on success. - */ -int -qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval = QLA_SUCCESS; - uint16_t i; - - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - struct qla_hw_data *ha = vha->hw; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return qla2x00_sns_gpn_id(vha, list); - - for (i = 0; i < ha->max_fibre_devices; i++) { - /* Issue GPN_ID */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GPN_ID_REQ_SIZE, - GPN_ID_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GPN_ID_CMD, - GPN_ID_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; - ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; - ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2056, - "GPN_ID issue IOCB failed (%d).\n", rval); - break; - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, - "GPN_ID") != QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - break; - } else { - /* Save portname */ - memcpy(list[i].port_name, - ct_rsp->rsp.gpn_id.port_name, WWN_SIZE); - } - - /* Last device exit. */ - if (list[i].d_id.b.rsvd_1 != 0) - break; - } - - return (rval); -} - -/** - * qla2x00_gnn_id() - SNS Get Node Name (GNN_ID) query. - * @ha: HA context - * @list: switch info entries to populate - * - * Returns 0 on success. - */ -int -qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval = QLA_SUCCESS; - uint16_t i; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return qla2x00_sns_gnn_id(vha, list); - - for (i = 0; i < ha->max_fibre_devices; i++) { - /* Issue GNN_ID */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GNN_ID_REQ_SIZE, - GNN_ID_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GNN_ID_CMD, - GNN_ID_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; - ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; - ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2057, - "GNN_ID issue IOCB failed (%d).\n", rval); - break; - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, - "GNN_ID") != QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - break; - } else { - /* Save nodename */ - memcpy(list[i].node_name, - ct_rsp->rsp.gnn_id.node_name, WWN_SIZE); - - ql_dbg(ql_dbg_disc, vha, 0x2058, - "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02X%02x " - "pn %02x%02x%02x%02x%02x%02x%02X%02x " - "portid=%02x%02x%02x.\n", - list[i].node_name[0], list[i].node_name[1], - list[i].node_name[2], list[i].node_name[3], - list[i].node_name[4], list[i].node_name[5], - list[i].node_name[6], list[i].node_name[7], - list[i].port_name[0], list[i].port_name[1], - list[i].port_name[2], list[i].port_name[3], - list[i].port_name[4], list[i].port_name[5], - list[i].port_name[6], list[i].port_name[7], - list[i].d_id.b.domain, list[i].d_id.b.area, - list[i].d_id.b.al_pa); - } - - /* Last device exit. */ - if (list[i].d_id.b.rsvd_1 != 0) - break; - } - - return (rval); -} - -/** - * qla2x00_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla2x00_rft_id(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return qla2x00_sns_rft_id(vha); - - /* Issue RFT_ID */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, RFT_ID_REQ_SIZE, - RFT_ID_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD, - RFT_ID_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_id, FC-4 types */ - ct_req->req.rft_id.port_id[0] = vha->d_id.b.domain; - ct_req->req.rft_id.port_id[1] = vha->d_id.b.area; - ct_req->req.rft_id.port_id[2] = vha->d_id.b.al_pa; - - ct_req->req.rft_id.fc4_types[2] = 0x01; /* FCP-3 */ - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2043, - "RFT_ID issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RFT_ID") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2044, - "RFT_ID exiting normally.\n"); - } - - return (rval); -} - -/** - * qla2x00_rff_id() - SNS Register FC-4 Features (RFF_ID) supported by the HBA. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla2x00_rff_id(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - ql_dbg(ql_dbg_disc, vha, 0x2046, - "RFF_ID call not supported on ISP2100/ISP2200.\n"); - return (QLA_SUCCESS); - } - - /* Issue RFF_ID */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, RFF_ID_REQ_SIZE, - RFF_ID_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD, - RFF_ID_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */ - ct_req->req.rff_id.port_id[0] = vha->d_id.b.domain; - ct_req->req.rff_id.port_id[1] = vha->d_id.b.area; - ct_req->req.rff_id.port_id[2] = vha->d_id.b.al_pa; - - ct_req->req.rff_id.fc4_feature = BIT_1; - ct_req->req.rff_id.fc4_type = 0x08; /* SCSI - FCP */ - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2047, - "RFF_ID issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RFF_ID") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2048, - "RFF_ID exiting normally.\n"); - } - - return (rval); -} - -/** - * qla2x00_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla2x00_rnn_id(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return qla2x00_sns_rnn_id(vha); - - /* Issue RNN_ID */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, RNN_ID_REQ_SIZE, - RNN_ID_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD, - RNN_ID_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_id, node_name */ - ct_req->req.rnn_id.port_id[0] = vha->d_id.b.domain; - ct_req->req.rnn_id.port_id[1] = vha->d_id.b.area; - ct_req->req.rnn_id.port_id[2] = vha->d_id.b.al_pa; - - memcpy(ct_req->req.rnn_id.node_name, vha->node_name, WWN_SIZE); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x204d, - "RNN_ID issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RNN_ID") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x204e, - "RNN_ID exiting normally.\n"); - } - - return (rval); -} - -void -qla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn) -{ - struct qla_hw_data *ha = vha->hw; - sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number, - ha->fw_major_version, ha->fw_minor_version, - ha->fw_subminor_version, qla2x00_version_str); -} - -/** - * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla2x00_rsnn_nn(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - ql_dbg(ql_dbg_disc, vha, 0x2050, - "RSNN_ID call unsupported on ISP2100/ISP2200.\n"); - return (QLA_SUCCESS); - } - - /* Issue RSNN_NN */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, 0, RSNN_NN_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD, - RSNN_NN_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- node_name, symbolic node_name, size */ - memcpy(ct_req->req.rsnn_nn.node_name, vha->node_name, WWN_SIZE); - - /* Prepare the Symbolic Node Name */ - qla2x00_get_sym_node_name(vha, ct_req->req.rsnn_nn.sym_node_name); - - /* Calculate SNN length */ - ct_req->req.rsnn_nn.name_len = - (uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name); - - /* Update MS IOCB request */ - ms_pkt->req_bytecount = - cpu_to_le32(24 + 1 + ct_req->req.rsnn_nn.name_len); - ms_pkt->dseg_req_length = ms_pkt->req_bytecount; - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2051, - "RSNN_NN issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RSNN_NN") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2052, - "RSNN_NN exiting normally.\n"); - } - - return (rval); -} - -/** - * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query. - * @ha: HA context - * @cmd: GS command - * @scmd_len: Subcommand length - * @data_size: response size in bytes - * - * Returns a pointer to the @ha's sns_cmd. - */ -static inline struct sns_cmd_pkt * -qla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len, - uint16_t data_size) -{ - uint16_t wc; - struct sns_cmd_pkt *sns_cmd; - struct qla_hw_data *ha = vha->hw; - - sns_cmd = ha->sns_cmd; - memset(sns_cmd, 0, sizeof(struct sns_cmd_pkt)); - wc = data_size / 2; /* Size in 16bit words. */ - sns_cmd->p.cmd.buffer_length = cpu_to_le16(wc); - sns_cmd->p.cmd.buffer_address[0] = cpu_to_le32(LSD(ha->sns_cmd_dma)); - sns_cmd->p.cmd.buffer_address[1] = cpu_to_le32(MSD(ha->sns_cmd_dma)); - sns_cmd->p.cmd.subcommand_length = cpu_to_le16(scmd_len); - sns_cmd->p.cmd.subcommand = cpu_to_le16(cmd); - wc = (data_size - 16) / 4; /* Size in 32bit words. */ - sns_cmd->p.cmd.size = cpu_to_le16(wc); - - return (sns_cmd); -} - -/** - * qla2x00_sns_ga_nxt() - SNS scan for fabric devices via GA_NXT command. - * @ha: HA context - * @fcport: fcport entry to updated - * - * This command uses the old Exectute SNS Command mailbox routine. - * - * Returns 0 on success. - */ -static int -qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - int rval = QLA_SUCCESS; - struct qla_hw_data *ha = vha->hw; - struct sns_cmd_pkt *sns_cmd; - - /* Issue GA_NXT. */ - /* Prepare SNS command request. */ - sns_cmd = qla2x00_prep_sns_cmd(vha, GA_NXT_CMD, GA_NXT_SNS_SCMD_LEN, - GA_NXT_SNS_DATA_SIZE); - - /* Prepare SNS command arguments -- port_id. */ - sns_cmd->p.cmd.param[0] = fcport->d_id.b.al_pa; - sns_cmd->p.cmd.param[1] = fcport->d_id.b.area; - sns_cmd->p.cmd.param[2] = fcport->d_id.b.domain; - - /* Execute SNS command. */ - rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, GA_NXT_SNS_CMD_SIZE / 2, - sizeof(struct sns_cmd_pkt)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x205f, - "GA_NXT Send SNS failed (%d).\n", rval); - } else if (sns_cmd->p.gan_data[8] != 0x80 || - sns_cmd->p.gan_data[9] != 0x02) { - ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2084, - "GA_NXT failed, rejected request ga_nxt_rsp:\n"); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2074, - sns_cmd->p.gan_data, 16); - rval = QLA_FUNCTION_FAILED; - } else { - /* Populate fc_port_t entry. */ - fcport->d_id.b.domain = sns_cmd->p.gan_data[17]; - fcport->d_id.b.area = sns_cmd->p.gan_data[18]; - fcport->d_id.b.al_pa = sns_cmd->p.gan_data[19]; - - memcpy(fcport->node_name, &sns_cmd->p.gan_data[284], WWN_SIZE); - memcpy(fcport->port_name, &sns_cmd->p.gan_data[20], WWN_SIZE); - - if (sns_cmd->p.gan_data[16] != NS_N_PORT_TYPE && - sns_cmd->p.gan_data[16] != NS_NL_PORT_TYPE) - fcport->d_id.b.domain = 0xf0; - - ql_dbg(ql_dbg_disc, vha, 0x2061, - "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x " - "pn %02x%02x%02x%02x%02x%02x%02x%02x " - "port_id=%02x%02x%02x.\n", - fcport->node_name[0], fcport->node_name[1], - fcport->node_name[2], fcport->node_name[3], - fcport->node_name[4], fcport->node_name[5], - fcport->node_name[6], fcport->node_name[7], - fcport->port_name[0], fcport->port_name[1], - fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7], - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - } - - return (rval); -} - -/** - * qla2x00_sns_gid_pt() - SNS scan for fabric devices via GID_PT command. - * @ha: HA context - * @list: switch info entries to populate - * - * This command uses the old Exectute SNS Command mailbox routine. - * - * NOTE: Non-Nx_Ports are not requested. - * - * Returns 0 on success. - */ -static int -qla2x00_sns_gid_pt(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - uint16_t i; - uint8_t *entry; - struct sns_cmd_pkt *sns_cmd; - uint16_t gid_pt_sns_data_size; - - gid_pt_sns_data_size = qla2x00_gid_pt_rsp_size(vha); - - /* Issue GID_PT. */ - /* Prepare SNS command request. */ - sns_cmd = qla2x00_prep_sns_cmd(vha, GID_PT_CMD, GID_PT_SNS_SCMD_LEN, - gid_pt_sns_data_size); - - /* Prepare SNS command arguments -- port_type. */ - sns_cmd->p.cmd.param[0] = NS_NX_PORT_TYPE; - - /* Execute SNS command. */ - rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, GID_PT_SNS_CMD_SIZE / 2, - sizeof(struct sns_cmd_pkt)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x206d, - "GID_PT Send SNS failed (%d).\n", rval); - } else if (sns_cmd->p.gid_data[8] != 0x80 || - sns_cmd->p.gid_data[9] != 0x02) { - ql_dbg(ql_dbg_disc, vha, 0x202f, - "GID_PT failed, rejected request, gid_rsp:\n"); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2081, - sns_cmd->p.gid_data, 16); - rval = QLA_FUNCTION_FAILED; - } else { - /* Set port IDs in switch info list. */ - for (i = 0; i < ha->max_fibre_devices; i++) { - entry = &sns_cmd->p.gid_data[(i * 4) + 16]; - list[i].d_id.b.domain = entry[1]; - list[i].d_id.b.area = entry[2]; - list[i].d_id.b.al_pa = entry[3]; - - /* Last one exit. */ - if (entry[0] & BIT_7) { - list[i].d_id.b.rsvd_1 = entry[0]; - break; - } - } - - /* - * If we've used all available slots, then the switch is - * reporting back more devices that we can handle with this - * single call. Return a failed status, and let GA_NXT handle - * the overload. - */ - if (i == ha->max_fibre_devices) - rval = QLA_FUNCTION_FAILED; - } - - return (rval); -} - -/** - * qla2x00_sns_gpn_id() - SNS Get Port Name (GPN_ID) query. - * @ha: HA context - * @list: switch info entries to populate - * - * This command uses the old Exectute SNS Command mailbox routine. - * - * Returns 0 on success. - */ -static int -qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval = QLA_SUCCESS; - struct qla_hw_data *ha = vha->hw; - uint16_t i; - struct sns_cmd_pkt *sns_cmd; - - for (i = 0; i < ha->max_fibre_devices; i++) { - /* Issue GPN_ID */ - /* Prepare SNS command request. */ - sns_cmd = qla2x00_prep_sns_cmd(vha, GPN_ID_CMD, - GPN_ID_SNS_SCMD_LEN, GPN_ID_SNS_DATA_SIZE); - - /* Prepare SNS command arguments -- port_id. */ - sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa; - sns_cmd->p.cmd.param[1] = list[i].d_id.b.area; - sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain; - - /* Execute SNS command. */ - rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, - GPN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2032, - "GPN_ID Send SNS failed (%d).\n", rval); - } else if (sns_cmd->p.gpn_data[8] != 0x80 || - sns_cmd->p.gpn_data[9] != 0x02) { - ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207e, - "GPN_ID failed, rejected request, gpn_rsp:\n"); - ql_dump_buffer(ql_dbg_disc, vha, 0x207f, - sns_cmd->p.gpn_data, 16); - rval = QLA_FUNCTION_FAILED; - } else { - /* Save portname */ - memcpy(list[i].port_name, &sns_cmd->p.gpn_data[16], - WWN_SIZE); - } - - /* Last device exit. */ - if (list[i].d_id.b.rsvd_1 != 0) - break; - } - - return (rval); -} - -/** - * qla2x00_sns_gnn_id() - SNS Get Node Name (GNN_ID) query. - * @ha: HA context - * @list: switch info entries to populate - * - * This command uses the old Exectute SNS Command mailbox routine. - * - * Returns 0 on success. - */ -static int -qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval = QLA_SUCCESS; - struct qla_hw_data *ha = vha->hw; - uint16_t i; - struct sns_cmd_pkt *sns_cmd; - - for (i = 0; i < ha->max_fibre_devices; i++) { - /* Issue GNN_ID */ - /* Prepare SNS command request. */ - sns_cmd = qla2x00_prep_sns_cmd(vha, GNN_ID_CMD, - GNN_ID_SNS_SCMD_LEN, GNN_ID_SNS_DATA_SIZE); - - /* Prepare SNS command arguments -- port_id. */ - sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa; - sns_cmd->p.cmd.param[1] = list[i].d_id.b.area; - sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain; - - /* Execute SNS command. */ - rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, - GNN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x203f, - "GNN_ID Send SNS failed (%d).\n", rval); - } else if (sns_cmd->p.gnn_data[8] != 0x80 || - sns_cmd->p.gnn_data[9] != 0x02) { - ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2082, - "GNN_ID failed, rejected request, gnn_rsp:\n"); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207a, - sns_cmd->p.gnn_data, 16); - rval = QLA_FUNCTION_FAILED; - } else { - /* Save nodename */ - memcpy(list[i].node_name, &sns_cmd->p.gnn_data[16], - WWN_SIZE); - - ql_dbg(ql_dbg_disc, vha, 0x206e, - "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x " - "pn %02x%02x%02x%02x%02x%02x%02x%02x " - "port_id=%02x%02x%02x.\n", - list[i].node_name[0], list[i].node_name[1], - list[i].node_name[2], list[i].node_name[3], - list[i].node_name[4], list[i].node_name[5], - list[i].node_name[6], list[i].node_name[7], - list[i].port_name[0], list[i].port_name[1], - list[i].port_name[2], list[i].port_name[3], - list[i].port_name[4], list[i].port_name[5], - list[i].port_name[6], list[i].port_name[7], - list[i].d_id.b.domain, list[i].d_id.b.area, - list[i].d_id.b.al_pa); - } - - /* Last device exit. */ - if (list[i].d_id.b.rsvd_1 != 0) - break; - } - - return (rval); -} - -/** - * qla2x00_snd_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. - * @ha: HA context - * - * This command uses the old Exectute SNS Command mailbox routine. - * - * Returns 0 on success. - */ -static int -qla2x00_sns_rft_id(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - struct sns_cmd_pkt *sns_cmd; - - /* Issue RFT_ID. */ - /* Prepare SNS command request. */ - sns_cmd = qla2x00_prep_sns_cmd(vha, RFT_ID_CMD, RFT_ID_SNS_SCMD_LEN, - RFT_ID_SNS_DATA_SIZE); - - /* Prepare SNS command arguments -- port_id, FC-4 types */ - sns_cmd->p.cmd.param[0] = vha->d_id.b.al_pa; - sns_cmd->p.cmd.param[1] = vha->d_id.b.area; - sns_cmd->p.cmd.param[2] = vha->d_id.b.domain; - - sns_cmd->p.cmd.param[5] = 0x01; /* FCP-3 */ - - /* Execute SNS command. */ - rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, RFT_ID_SNS_CMD_SIZE / 2, - sizeof(struct sns_cmd_pkt)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2060, - "RFT_ID Send SNS failed (%d).\n", rval); - } else if (sns_cmd->p.rft_data[8] != 0x80 || - sns_cmd->p.rft_data[9] != 0x02) { - ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2083, - "RFT_ID failed, rejected request rft_rsp:\n"); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2080, - sns_cmd->p.rft_data, 16); - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2073, - "RFT_ID exiting normally.\n"); - } - - return (rval); -} - -/** - * qla2x00_sns_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. - * HBA. - * @ha: HA context - * - * This command uses the old Exectute SNS Command mailbox routine. - * - * Returns 0 on success. - */ -static int -qla2x00_sns_rnn_id(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - struct sns_cmd_pkt *sns_cmd; - - /* Issue RNN_ID. */ - /* Prepare SNS command request. */ - sns_cmd = qla2x00_prep_sns_cmd(vha, RNN_ID_CMD, RNN_ID_SNS_SCMD_LEN, - RNN_ID_SNS_DATA_SIZE); - - /* Prepare SNS command arguments -- port_id, nodename. */ - sns_cmd->p.cmd.param[0] = vha->d_id.b.al_pa; - sns_cmd->p.cmd.param[1] = vha->d_id.b.area; - sns_cmd->p.cmd.param[2] = vha->d_id.b.domain; - - sns_cmd->p.cmd.param[4] = vha->node_name[7]; - sns_cmd->p.cmd.param[5] = vha->node_name[6]; - sns_cmd->p.cmd.param[6] = vha->node_name[5]; - sns_cmd->p.cmd.param[7] = vha->node_name[4]; - sns_cmd->p.cmd.param[8] = vha->node_name[3]; - sns_cmd->p.cmd.param[9] = vha->node_name[2]; - sns_cmd->p.cmd.param[10] = vha->node_name[1]; - sns_cmd->p.cmd.param[11] = vha->node_name[0]; - - /* Execute SNS command. */ - rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, RNN_ID_SNS_CMD_SIZE / 2, - sizeof(struct sns_cmd_pkt)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x204a, - "RNN_ID Send SNS failed (%d).\n", rval); - } else if (sns_cmd->p.rnn_data[8] != 0x80 || - sns_cmd->p.rnn_data[9] != 0x02) { - ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207b, - "RNN_ID failed, rejected request, rnn_rsp:\n"); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207c, - sns_cmd->p.rnn_data, 16); - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x204c, - "RNN_ID exiting normally.\n"); - } - - return (rval); -} - -/** - * qla2x00_mgmt_svr_login() - Login to fabric Management Service. - * @ha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_mgmt_svr_login(scsi_qla_host_t *vha) -{ - int ret, rval; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - struct qla_hw_data *ha = vha->hw; - ret = QLA_SUCCESS; - if (vha->flags.management_server_logged_in) - return ret; - - rval = ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, - 0xfa, mb, BIT_1|BIT_0); - if (rval != QLA_SUCCESS || mb[0] != MBS_COMMAND_COMPLETE) { - if (rval == QLA_MEMORY_ALLOC_FAILED) - ql_dbg(ql_dbg_disc, vha, 0x2085, - "Failed management_server login: loopid=%x " - "rval=%d\n", vha->mgmt_svr_loop_id, rval); - else - ql_dbg(ql_dbg_disc, vha, 0x2024, - "Failed management_server login: loopid=%x " - "mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x.\n", - vha->mgmt_svr_loop_id, mb[0], mb[1], mb[2], mb[6], - mb[7]); - ret = QLA_FUNCTION_FAILED; - } else - vha->flags.management_server_logged_in = 1; - - return ret; -} - -/** - * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. - * @ha: HA context - * @req_size: request size in bytes - * @rsp_size: response size in bytes - * - * Returns a pointer to the @ha's ms_iocb. - */ -void * -qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, - uint32_t rsp_size) -{ - ms_iocb_entry_t *ms_pkt; - struct qla_hw_data *ha = vha->hw; - ms_pkt = ha->ms_iocb; - memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); - - ms_pkt->entry_type = MS_IOCB_TYPE; - ms_pkt->entry_count = 1; - SET_TARGET_ID(ha, ms_pkt->loop_id, vha->mgmt_svr_loop_id); - ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); - ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); - ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); - ms_pkt->req_bytecount = cpu_to_le32(req_size); - - ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ms_pkt->dseg_req_length = ms_pkt->req_bytecount; - - ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; - - return ms_pkt; -} - -/** - * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. - * @ha: HA context - * @req_size: request size in bytes - * @rsp_size: response size in bytes - * - * Returns a pointer to the @ha's ms_iocb. - */ -void * -qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, - uint32_t rsp_size) -{ - struct ct_entry_24xx *ct_pkt; - struct qla_hw_data *ha = vha->hw; - - ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; - memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); - - ct_pkt->entry_type = CT_IOCB_TYPE; - ct_pkt->entry_count = 1; - ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id); - ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); - ct_pkt->cmd_byte_count = cpu_to_le32(req_size); - - ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; - - ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; - ct_pkt->vp_index = vha->vp_idx; - - return ct_pkt; -} - -static inline ms_iocb_entry_t * -qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size) -{ - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt = ha->ms_iocb; - struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; - - if (IS_FWI2_CAPABLE(ha)) { - ct_pkt->cmd_byte_count = cpu_to_le32(req_size); - ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; - } else { - ms_pkt->req_bytecount = cpu_to_le32(req_size); - ms_pkt->dseg_req_length = ms_pkt->req_bytecount; - } - - return ms_pkt; -} - -/** - * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. - * @ct_req: CT request buffer - * @cmd: GS command - * @rsp_size: response size in bytes - * - * Returns a pointer to the intitialized @ct_req. - */ -static inline struct ct_sns_req * -qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd, - uint16_t rsp_size) -{ - memset(ct_req, 0, sizeof(struct ct_sns_pkt)); - - ct_req->header.revision = 0x01; - ct_req->header.gs_type = 0xFA; - ct_req->header.gs_subtype = 0x10; - ct_req->command = cpu_to_be16(cmd); - ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); - - return ct_req; -} - -/** - * qla2x00_fdmi_rhba() - - * @ha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_fdmi_rhba(scsi_qla_host_t *vha) -{ - int rval, alen; - uint32_t size, sn; - - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - uint8_t *entries; - struct ct_fdmi_hba_attr *eiter; - struct qla_hw_data *ha = vha->hw; - - /* Issue RHBA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RHBA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD, - RHBA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rhba.hba_identifier, vha->port_name, WWN_SIZE); - ct_req->req.rhba.entry_count = __constant_cpu_to_be32(1); - memcpy(ct_req->req.rhba.port_name, vha->port_name, WWN_SIZE); - size = 2 * WWN_SIZE + 4 + 4; - - /* Attributes */ - ct_req->req.rhba.attrs.count = - __constant_cpu_to_be32(FDMI_HBA_ATTR_COUNT); - entries = ct_req->req.rhba.hba_identifier; - - /* Nodename. */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_NODE_NAME); - eiter->len = __constant_cpu_to_be16(4 + WWN_SIZE); - memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE); - size += 4 + WWN_SIZE; - - ql_dbg(ql_dbg_disc, vha, 0x2025, - "NodeName = %02x%02x%02x%02x%02x%02x%02x%02x.\n", - eiter->a.node_name[0], eiter->a.node_name[1], - eiter->a.node_name[2], eiter->a.node_name[3], - eiter->a.node_name[4], eiter->a.node_name[5], - eiter->a.node_name[6], eiter->a.node_name[7]); - - /* Manufacturer. */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_MANUFACTURER); - strcpy(eiter->a.manufacturer, "QLogic Corporation"); - alen = strlen(eiter->a.manufacturer); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2026, - "Manufacturer = %s.\n", eiter->a.manufacturer); - - /* Serial number. */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); - sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; - sprintf(eiter->a.serial_num, "%c%05d", 'A' + sn / 100000, sn % 100000); - alen = strlen(eiter->a.serial_num); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2027, - "Serial no. = %s.\n", eiter->a.serial_num); - - /* Model name. */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL); - strcpy(eiter->a.model, ha->model_number); - alen = strlen(eiter->a.model); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2028, - "Model Name = %s.\n", eiter->a.model); - - /* Model description. */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); - if (ha->model_desc) - strncpy(eiter->a.model_desc, ha->model_desc, 80); - alen = strlen(eiter->a.model_desc); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x2029, - "Model Desc = %s.\n", eiter->a.model_desc); - - /* Hardware version. */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); - strcpy(eiter->a.hw_version, ha->adapter_id); - alen = strlen(eiter->a.hw_version); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202a, - "Hardware ver = %s.\n", eiter->a.hw_version); - - /* Driver version. */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_DRIVER_VERSION); - strcpy(eiter->a.driver_version, qla2x00_version_str); - alen = strlen(eiter->a.driver_version); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202b, - "Driver ver = %s.\n", eiter->a.driver_version); - - /* Option ROM version. */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); - strcpy(eiter->a.orom_version, "0.00"); - alen = strlen(eiter->a.orom_version); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha , 0x202c, - "Optrom vers = %s.\n", eiter->a.orom_version); - - /* Firmware version */ - eiter = (struct ct_fdmi_hba_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); - ha->isp_ops->fw_version_str(vha, eiter->a.fw_version); - alen = strlen(eiter->a.fw_version); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x202d, - "Firmware vers = %s.\n", eiter->a.fw_version); - - /* Update MS request size. */ - qla2x00_update_ms_fdmi_iocb(vha, size + 16); - - ql_dbg(ql_dbg_disc, vha, 0x202e, - "RHBA identifier = " - "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", - ct_req->req.rhba.hba_identifier[0], - ct_req->req.rhba.hba_identifier[1], - ct_req->req.rhba.hba_identifier[2], - ct_req->req.rhba.hba_identifier[3], - ct_req->req.rhba.hba_identifier[4], - ct_req->req.rhba.hba_identifier[5], - ct_req->req.rhba.hba_identifier[6], - ct_req->req.rhba.hba_identifier[7], size); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076, - entries, size); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2030, - "RHBA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && - ct_rsp->header.explanation_code == - CT_EXPL_ALREADY_REGISTERED) { - ql_dbg(ql_dbg_disc, vha, 0x2034, - "HBA already registered.\n"); - rval = QLA_ALREADY_REGISTERED; - } - } else { - ql_dbg(ql_dbg_disc, vha, 0x2035, - "RHBA exiting normally.\n"); - } - - return rval; -} - -/** - * qla2x00_fdmi_dhba() - - * @ha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_fdmi_dhba(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - /* Issue RPA */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, DHBA_REQ_SIZE, - DHBA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD, - DHBA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- portname. */ - memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE); - - ql_dbg(ql_dbg_disc, vha, 0x2036, - "DHBA portname = %02x%02x%02x%02x%02x%02x%02x%02x.\n", - ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1], - ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3], - ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5], - ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2037, - "DHBA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "DHBA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2038, - "DHBA exiting normally.\n"); - } - - return rval; -} - -/** - * qla2x00_fdmi_rpa() - - * @ha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_fdmi_rpa(scsi_qla_host_t *vha) -{ - int rval, alen; - uint32_t size, max_frame_size; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - uint8_t *entries; - struct ct_fdmi_port_attr *eiter; - struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; - - /* Issue RPA */ - /* Prepare common MS IOCB */ - /* Request size adjusted after CT preparation */ - ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RPA_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD, - RPA_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare FDMI command arguments -- attribute block, attributes. */ - memcpy(ct_req->req.rpa.port_name, vha->port_name, WWN_SIZE); - size = WWN_SIZE + 4; - - /* Attributes */ - ct_req->req.rpa.attrs.count = - __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT - 1); - entries = ct_req->req.rpa.port_name; - - /* FC4 types. */ - eiter = (struct ct_fdmi_port_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_PORT_FC4_TYPES); - eiter->len = __constant_cpu_to_be16(4 + 32); - eiter->a.fc4_types[2] = 0x01; - size += 4 + 32; - - ql_dbg(ql_dbg_disc, vha, 0x2039, - "FC4_TYPES=%02x %02x.\n", - eiter->a.fc4_types[2], - eiter->a.fc4_types[1]); - - /* Supported speed. */ - eiter = (struct ct_fdmi_port_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); - eiter->len = __constant_cpu_to_be16(4 + 4); - if (IS_CNA_CAPABLE(ha)) - eiter->a.sup_speed = __constant_cpu_to_be32( - FDMI_PORT_SPEED_10GB); - else if (IS_QLA25XX(ha)) - eiter->a.sup_speed = __constant_cpu_to_be32( - FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB); - else if (IS_QLA24XX_TYPE(ha)) - eiter->a.sup_speed = __constant_cpu_to_be32( - FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB| - FDMI_PORT_SPEED_4GB); - else if (IS_QLA23XX(ha)) - eiter->a.sup_speed =__constant_cpu_to_be32( - FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB); - else - eiter->a.sup_speed = __constant_cpu_to_be32( - FDMI_PORT_SPEED_1GB); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203a, - "Supported_Speed=%x.\n", eiter->a.sup_speed); - - /* Current speed. */ - eiter = (struct ct_fdmi_port_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED); - eiter->len = __constant_cpu_to_be16(4 + 4); - switch (ha->link_data_rate) { - case PORT_SPEED_1GB: - eiter->a.cur_speed = - __constant_cpu_to_be32(FDMI_PORT_SPEED_1GB); - break; - case PORT_SPEED_2GB: - eiter->a.cur_speed = - __constant_cpu_to_be32(FDMI_PORT_SPEED_2GB); - break; - case PORT_SPEED_4GB: - eiter->a.cur_speed = - __constant_cpu_to_be32(FDMI_PORT_SPEED_4GB); - break; - case PORT_SPEED_8GB: - eiter->a.cur_speed = - __constant_cpu_to_be32(FDMI_PORT_SPEED_8GB); - break; - case PORT_SPEED_10GB: - eiter->a.cur_speed = - __constant_cpu_to_be32(FDMI_PORT_SPEED_10GB); - break; - case PORT_SPEED_16GB: - eiter->a.cur_speed = - __constant_cpu_to_be32(FDMI_PORT_SPEED_16GB); - break; - default: - eiter->a.cur_speed = - __constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN); - break; - } - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203b, - "Current_Speed=%x.\n", eiter->a.cur_speed); - - /* Max frame size. */ - eiter = (struct ct_fdmi_port_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); - eiter->len = __constant_cpu_to_be16(4 + 4); - max_frame_size = IS_FWI2_CAPABLE(ha) ? - le16_to_cpu(icb24->frame_payload_size): - le16_to_cpu(ha->init_cb->frame_payload_size); - eiter->a.max_frame_size = cpu_to_be32(max_frame_size); - size += 4 + 4; - - ql_dbg(ql_dbg_disc, vha, 0x203c, - "Max_Frame_Size=%x.\n", eiter->a.max_frame_size); - - /* OS device name. */ - eiter = (struct ct_fdmi_port_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); - strcpy(eiter->a.os_dev_name, QLA2XXX_DRIVER_NAME); - alen = strlen(eiter->a.os_dev_name); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x204b, - "OS_Device_Name=%s.\n", eiter->a.os_dev_name); - - /* Hostname. */ - if (strlen(fc_host_system_hostname(vha->host))) { - ct_req->req.rpa.attrs.count = - __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT); - eiter = (struct ct_fdmi_port_attr *) (entries + size); - eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME); - snprintf(eiter->a.host_name, sizeof(eiter->a.host_name), - "%s", fc_host_system_hostname(vha->host)); - alen = strlen(eiter->a.host_name); - alen += (alen & 3) ? (4 - (alen & 3)) : 4; - eiter->len = cpu_to_be16(4 + alen); - size += 4 + alen; - - ql_dbg(ql_dbg_disc, vha, 0x203d, - "HostName=%s.\n", eiter->a.host_name); - } - - /* Update MS request size. */ - qla2x00_update_ms_fdmi_iocb(vha, size + 16); - - ql_dbg(ql_dbg_disc, vha, 0x203e, - "RPA portname= %02x%02x%02x%02x%02X%02x%02x%02x size=%d.\n", - ct_req->req.rpa.port_name[0], ct_req->req.rpa.port_name[1], - ct_req->req.rpa.port_name[2], ct_req->req.rpa.port_name[3], - ct_req->req.rpa.port_name[4], ct_req->req.rpa.port_name[5], - ct_req->req.rpa.port_name[6], ct_req->req.rpa.port_name[7], - size); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079, - entries, size); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2040, - "RPA issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA") != - QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_disc, vha, 0x2041, - "RPA exiting nornally.\n"); - } - - return rval; -} - -/** - * qla2x00_fdmi_register() - - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla2x00_fdmi_register(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return QLA_FUNCTION_FAILED; - - rval = qla2x00_mgmt_svr_login(vha); - if (rval) - return rval; - - rval = qla2x00_fdmi_rhba(vha); - if (rval) { - if (rval != QLA_ALREADY_REGISTERED) - return rval; - - rval = qla2x00_fdmi_dhba(vha); - if (rval) - return rval; - - rval = qla2x00_fdmi_rhba(vha); - if (rval) - return rval; - } - rval = qla2x00_fdmi_rpa(vha); - - return rval; -} - -/** - * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query. - * @ha: HA context - * @list: switch info entries to populate - * - * Returns 0 on success. - */ -int -qla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval = QLA_SUCCESS; - uint16_t i; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - if (!IS_IIDMA_CAPABLE(ha)) - return QLA_FUNCTION_FAILED; - - for (i = 0; i < ha->max_fibre_devices; i++) { - /* Issue GFPN_ID */ - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GFPN_ID_REQ_SIZE, - GFPN_ID_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD, - GFPN_ID_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; - ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; - ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2023, - "GFPN_ID issue IOCB failed (%d).\n", rval); - break; - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, - "GFPN_ID") != QLA_SUCCESS) { - rval = QLA_FUNCTION_FAILED; - break; - } else { - /* Save fabric portname */ - memcpy(list[i].fabric_port_name, - ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE); - } - - /* Last device exit. */ - if (list[i].d_id.b.rsvd_1 != 0) - break; - } - - return (rval); -} - -static inline void * -qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *vha, uint32_t req_size, - uint32_t rsp_size) -{ - struct ct_entry_24xx *ct_pkt; - struct qla_hw_data *ha = vha->hw; - ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; - memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); - - ct_pkt->entry_type = CT_IOCB_TYPE; - ct_pkt->entry_count = 1; - ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id); - ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); - ct_pkt->cmd_byte_count = cpu_to_le32(req_size); - - ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; - - ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); - ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); - ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; - ct_pkt->vp_index = vha->vp_idx; - - return ct_pkt; -} - - -static inline struct ct_sns_req * -qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd, - uint16_t rsp_size) -{ - memset(ct_req, 0, sizeof(struct ct_sns_pkt)); - - ct_req->header.revision = 0x01; - ct_req->header.gs_type = 0xFA; - ct_req->header.gs_subtype = 0x01; - ct_req->command = cpu_to_be16(cmd); - ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); - - return ct_req; -} - -/** - * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query. - * @ha: HA context - * @list: switch info entries to populate - * - * Returns 0 on success. - */ -int -qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval; - uint16_t i; - struct qla_hw_data *ha = vha->hw; - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - - if (!IS_IIDMA_CAPABLE(ha)) - return QLA_FUNCTION_FAILED; - if (!ha->flags.gpsc_supported) - return QLA_FUNCTION_FAILED; - - rval = qla2x00_mgmt_svr_login(vha); - if (rval) - return rval; - - for (i = 0; i < ha->max_fibre_devices; i++) { - /* Issue GFPN_ID */ - /* Prepare common MS IOCB */ - ms_pkt = qla24xx_prep_ms_fm_iocb(vha, GPSC_REQ_SIZE, - GPSC_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req, - GPSC_CMD, GPSC_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_name */ - memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name, - WWN_SIZE); - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2059, - "GPSC issue IOCB failed (%d).\n", rval); - } else if ((rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, - "GPSC")) != QLA_SUCCESS) { - /* FM command unsupported? */ - if (rval == QLA_INVALID_COMMAND && - (ct_rsp->header.reason_code == - CT_REASON_INVALID_COMMAND_CODE || - ct_rsp->header.reason_code == - CT_REASON_COMMAND_UNSUPPORTED)) { - ql_dbg(ql_dbg_disc, vha, 0x205a, - "GPSC command unsupported, disabling " - "query.\n"); - ha->flags.gpsc_supported = 0; - rval = QLA_FUNCTION_FAILED; - break; - } - rval = QLA_FUNCTION_FAILED; - } else { - /* Save port-speed */ - switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) { - case BIT_15: - list[i].fp_speed = PORT_SPEED_1GB; - break; - case BIT_14: - list[i].fp_speed = PORT_SPEED_2GB; - break; - case BIT_13: - list[i].fp_speed = PORT_SPEED_4GB; - break; - case BIT_12: - list[i].fp_speed = PORT_SPEED_10GB; - break; - case BIT_11: - list[i].fp_speed = PORT_SPEED_8GB; - break; - } - - ql_dbg(ql_dbg_disc, vha, 0x205b, - "GPSC ext entry - fpn " - "%02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x " - "speed=%04x.\n", - list[i].fabric_port_name[0], - list[i].fabric_port_name[1], - list[i].fabric_port_name[2], - list[i].fabric_port_name[3], - list[i].fabric_port_name[4], - list[i].fabric_port_name[5], - list[i].fabric_port_name[6], - list[i].fabric_port_name[7], - be16_to_cpu(ct_rsp->rsp.gpsc.speeds), - be16_to_cpu(ct_rsp->rsp.gpsc.speed)); - } - - /* Last device exit. */ - if (list[i].d_id.b.rsvd_1 != 0) - break; - } - - return (rval); -} - -/** - * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query. - * - * @ha: HA context - * @list: switch info entries to populate - * - */ -void -qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) -{ - int rval; - uint16_t i; - - ms_iocb_entry_t *ms_pkt; - struct ct_sns_req *ct_req; - struct ct_sns_rsp *ct_rsp; - struct qla_hw_data *ha = vha->hw; - uint8_t fcp_scsi_features = 0; - - for (i = 0; i < ha->max_fibre_devices; i++) { - /* Set default FC4 Type as UNKNOWN so the default is to - * Process this port */ - list[i].fc4_type = FC4_TYPE_UNKNOWN; - - /* Do not attempt GFF_ID if we are not FWI_2 capable */ - if (!IS_FWI2_CAPABLE(ha)) - continue; - - /* Prepare common MS IOCB */ - ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GFF_ID_REQ_SIZE, - GFF_ID_RSP_SIZE); - - /* Prepare CT request */ - ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFF_ID_CMD, - GFF_ID_RSP_SIZE); - ct_rsp = &ha->ct_sns->p.rsp; - - /* Prepare CT arguments -- port_id */ - ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain; - ct_req->req.port_id.port_id[1] = list[i].d_id.b.area; - ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa; - - /* Execute MS IOCB */ - rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, - sizeof(ms_iocb_entry_t)); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x205c, - "GFF_ID issue IOCB failed (%d).\n", rval); - } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, - "GFF_ID") != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x205d, - "GFF_ID IOCB status had a failure status code.\n"); - } else { - fcp_scsi_features = - ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; - fcp_scsi_features &= 0x0f; - - if (fcp_scsi_features) - list[i].fc4_type = FC4_TYPE_FCP_SCSI; - else - list[i].fc4_type = FC4_TYPE_OTHER; - } - - /* Last device exit. */ - if (list[i].d_id.b.rsvd_1 != 0) - break; - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_init.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_init.c deleted file mode 100644 index b9465643..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_init.c +++ /dev/null @@ -1,5558 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" -#include "qla_gbl.h" - -#include -#include -#include - -#include "qla_devtbl.h" - -#ifdef CONFIG_SPARC -#include -#endif - -/* -* QLogic ISP2x00 Hardware Support Function Prototypes. -*/ -static int qla2x00_isp_firmware(scsi_qla_host_t *); -static int qla2x00_setup_chip(scsi_qla_host_t *); -static int qla2x00_init_rings(scsi_qla_host_t *); -static int qla2x00_fw_ready(scsi_qla_host_t *); -static int qla2x00_configure_hba(scsi_qla_host_t *); -static int qla2x00_configure_loop(scsi_qla_host_t *); -static int qla2x00_configure_local_loop(scsi_qla_host_t *); -static int qla2x00_configure_fabric(scsi_qla_host_t *); -static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *); -static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *, - uint16_t *); - -static int qla2x00_restart_isp(scsi_qla_host_t *); - -static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *); -static int qla84xx_init_chip(scsi_qla_host_t *); -static int qla25xx_init_queues(struct qla_hw_data *); - -/* SRB Extensions ---------------------------------------------------------- */ - -void -qla2x00_sp_timeout(unsigned long __data) -{ - srb_t *sp = (srb_t *)__data; - struct srb_iocb *iocb; - fc_port_t *fcport = sp->fcport; - struct qla_hw_data *ha = fcport->vha->hw; - struct req_que *req; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - req = ha->req_q_map[0]; - req->outstanding_cmds[sp->handle] = NULL; - iocb = &sp->u.iocb_cmd; - iocb->timeout(sp); - sp->free(fcport->vha, sp); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void -qla2x00_sp_free(void *data, void *ptr) -{ - srb_t *sp = (srb_t *)ptr; - struct srb_iocb *iocb = &sp->u.iocb_cmd; - struct scsi_qla_host *vha = (scsi_qla_host_t *)data; - - del_timer(&iocb->timer); - mempool_free(sp, vha->hw->srb_mempool); - - QLA_VHA_MARK_NOT_BUSY(vha); -} - -/* Asynchronous Login/Logout Routines -------------------------------------- */ - -static inline unsigned long -qla2x00_get_async_timeout(struct scsi_qla_host *vha) -{ - unsigned long tmo; - struct qla_hw_data *ha = vha->hw; - - /* Firmware should use switch negotiated r_a_tov for timeout. */ - tmo = ha->r_a_tov / 10 * 2; - if (!IS_FWI2_CAPABLE(ha)) { - /* - * Except for earlier ISPs where the timeout is seeded from the - * initialization control block. - */ - tmo = ha->login_timeout; - } - return tmo; -} - -static void -qla2x00_async_iocb_timeout(void *data) -{ - srb_t *sp = (srb_t *)data; - fc_port_t *fcport = sp->fcport; - - ql_dbg(ql_dbg_disc, fcport->vha, 0x2071, - "Async-%s timeout - hdl=%x portid=%02x%02x%02x.\n", - sp->name, sp->handle, fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - - fcport->flags &= ~FCF_ASYNC_SENT; - if (sp->type == SRB_LOGIN_CMD) { - struct srb_iocb *lio = &sp->u.iocb_cmd; - qla2x00_post_async_logout_work(fcport->vha, fcport, NULL); - /* Retry as needed. */ - lio->u.logio.data[0] = MBS_COMMAND_ERROR; - lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? - QLA_LOGIO_LOGIN_RETRIED : 0; - qla2x00_post_async_login_done_work(fcport->vha, fcport, - lio->u.logio.data); - } -} - -static void -qla2x00_async_login_sp_done(void *data, void *ptr, int res) -{ - srb_t *sp = (srb_t *)ptr; - struct srb_iocb *lio = &sp->u.iocb_cmd; - struct scsi_qla_host *vha = (scsi_qla_host_t *)data; - - if (!test_bit(UNLOADING, &vha->dpc_flags)) - qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport, - lio->u.logio.data); - sp->free(sp->fcport->vha, sp); -} - -int -qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, - uint16_t *data) -{ - srb_t *sp; - struct srb_iocb *lio; - int rval; - - rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); - if (!sp) - goto done; - - sp->type = SRB_LOGIN_CMD; - sp->name = "login"; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - lio = &sp->u.iocb_cmd; - lio->timeout = qla2x00_async_iocb_timeout; - sp->done = qla2x00_async_login_sp_done; - lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI; - if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - lio->u.logio.flags |= SRB_LOGIN_RETRIED; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - - ql_dbg(ql_dbg_disc, vha, 0x2072, - "Async-login - hdl=%x, loopid=%x portid=%02x%02x%02x " - "retries=%d.\n", sp->handle, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, - fcport->login_retry); - return rval; - -done_free_sp: - sp->free(fcport->vha, sp); -done: - return rval; -} - -static void -qla2x00_async_logout_sp_done(void *data, void *ptr, int res) -{ - srb_t *sp = (srb_t *)ptr; - struct srb_iocb *lio = &sp->u.iocb_cmd; - struct scsi_qla_host *vha = (scsi_qla_host_t *)data; - - if (!test_bit(UNLOADING, &vha->dpc_flags)) - qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport, - lio->u.logio.data); - sp->free(sp->fcport->vha, sp); -} - -int -qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) -{ - srb_t *sp; - struct srb_iocb *lio; - int rval; - - rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); - if (!sp) - goto done; - - sp->type = SRB_LOGOUT_CMD; - sp->name = "logout"; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - lio = &sp->u.iocb_cmd; - lio->timeout = qla2x00_async_iocb_timeout; - sp->done = qla2x00_async_logout_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - - ql_dbg(ql_dbg_disc, vha, 0x2070, - "Async-logout - hdl=%x loop-id=%x portid=%02x%02x%02x.\n", - sp->handle, fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - return rval; - -done_free_sp: - sp->free(fcport->vha, sp); -done: - return rval; -} - -static void -qla2x00_async_adisc_sp_done(void *data, void *ptr, int res) -{ - srb_t *sp = (srb_t *)ptr; - struct srb_iocb *lio = &sp->u.iocb_cmd; - struct scsi_qla_host *vha = (scsi_qla_host_t *)data; - - if (!test_bit(UNLOADING, &vha->dpc_flags)) - qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport, - lio->u.logio.data); - sp->free(sp->fcport->vha, sp); -} - -int -qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, - uint16_t *data) -{ - srb_t *sp; - struct srb_iocb *lio; - int rval; - - rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); - if (!sp) - goto done; - - sp->type = SRB_ADISC_CMD; - sp->name = "adisc"; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - lio = &sp->u.iocb_cmd; - lio->timeout = qla2x00_async_iocb_timeout; - sp->done = qla2x00_async_adisc_sp_done; - if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - lio->u.logio.flags |= SRB_LOGIN_RETRIED; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - - ql_dbg(ql_dbg_disc, vha, 0x206f, - "Async-adisc - hdl=%x loopid=%x portid=%02x%02x%02x.\n", - sp->handle, fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - return rval; - -done_free_sp: - sp->free(fcport->vha, sp); -done: - return rval; -} - -static void -qla2x00_async_tm_cmd_done(void *data, void *ptr, int res) -{ - srb_t *sp = (srb_t *)ptr; - struct srb_iocb *iocb = &sp->u.iocb_cmd; - struct scsi_qla_host *vha = (scsi_qla_host_t *)data; - uint32_t flags; - uint16_t lun; - int rval; - - if (!test_bit(UNLOADING, &vha->dpc_flags)) { - flags = iocb->u.tmf.flags; - lun = (uint16_t)iocb->u.tmf.lun; - - /* Issue Marker IOCB */ - rval = qla2x00_marker(vha, vha->hw->req_q_map[0], - vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun, - flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID); - - if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) { - ql_dbg(ql_dbg_taskm, vha, 0x8030, - "TM IOCB failed (%x).\n", rval); - } - } - sp->free(sp->fcport->vha, sp); -} - -int -qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t tm_flags, uint32_t lun, - uint32_t tag) -{ - struct scsi_qla_host *vha = fcport->vha; - srb_t *sp; - struct srb_iocb *tcf; - int rval; - - rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); - if (!sp) - goto done; - - sp->type = SRB_TM_CMD; - sp->name = "tmf"; - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - tcf = &sp->u.iocb_cmd; - tcf->u.tmf.flags = tm_flags; - tcf->u.tmf.lun = lun; - tcf->u.tmf.data = tag; - tcf->timeout = qla2x00_async_iocb_timeout; - sp->done = qla2x00_async_tm_cmd_done; - - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - - ql_dbg(ql_dbg_taskm, vha, 0x802f, - "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n", - sp->handle, fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - return rval; - -done_free_sp: - sp->free(fcport->vha, sp); -done: - return rval; -} - -void -qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport, - uint16_t *data) -{ - int rval; - - switch (data[0]) { - case MBS_COMMAND_COMPLETE: - /* - * Driver must validate login state - If PRLI not complete, - * force a relogin attempt via implicit LOGO, PLOGI, and PRLI - * requests. - */ - rval = qla2x00_get_port_database(vha, fcport, 0); - if (rval == QLA_NOT_LOGGED_IN) { - fcport->flags &= ~FCF_ASYNC_SENT; - fcport->flags |= FCF_LOGIN_NEEDED; - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - break; - } - - if (rval != QLA_SUCCESS) { - qla2x00_post_async_logout_work(vha, fcport, NULL); - qla2x00_post_async_login_work(vha, fcport, NULL); - break; - } - if (fcport->flags & FCF_FCP2_DEVICE) { - qla2x00_post_async_adisc_work(vha, fcport, data); - break; - } - qla2x00_update_fcport(vha, fcport); - break; - case MBS_COMMAND_ERROR: - fcport->flags &= ~FCF_ASYNC_SENT; - if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - else - qla2x00_mark_device_lost(vha, fcport, 1, 0); - break; - case MBS_PORT_ID_USED: - fcport->loop_id = data[1]; - qla2x00_post_async_logout_work(vha, fcport, NULL); - qla2x00_post_async_login_work(vha, fcport, NULL); - break; - case MBS_LOOP_ID_USED: - fcport->loop_id++; - rval = qla2x00_find_new_loop_id(vha, fcport); - if (rval != QLA_SUCCESS) { - fcport->flags &= ~FCF_ASYNC_SENT; - qla2x00_mark_device_lost(vha, fcport, 1, 0); - break; - } - qla2x00_post_async_login_work(vha, fcport, NULL); - break; - } - return; -} - -void -qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, - uint16_t *data) -{ - qla2x00_mark_device_lost(vha, fcport, 1, 0); - return; -} - -void -qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, - uint16_t *data) -{ - if (data[0] == MBS_COMMAND_COMPLETE) { - qla2x00_update_fcport(vha, fcport); - - return; - } - - /* Retry login. */ - fcport->flags &= ~FCF_ASYNC_SENT; - if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - else - qla2x00_mark_device_lost(vha, fcport, 1, 0); - - return; -} - -/****************************************************************************/ -/* QLogic ISP2x00 Hardware Support Functions. */ -/****************************************************************************/ - -/* -* qla2x00_initialize_adapter -* Initialize board. -* -* Input: -* ha = adapter block pointer. -* -* Returns: -* 0 = success -*/ -int -qla2x00_initialize_adapter(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - /* Clear adapter flags. */ - vha->flags.online = 0; - ha->flags.chip_reset_done = 0; - vha->flags.reset_active = 0; - ha->flags.pci_channel_io_perm_failure = 0; - ha->flags.eeh_busy = 0; - ha->flags.thermal_supported = 1; - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - atomic_set(&vha->loop_state, LOOP_DOWN); - vha->device_flags = DFLG_NO_CABLE; - vha->dpc_flags = 0; - vha->flags.management_server_logged_in = 0; - vha->marker_needed = 0; - ha->isp_abort_cnt = 0; - ha->beacon_blink_led = 0; - - set_bit(0, ha->req_qid_map); - set_bit(0, ha->rsp_qid_map); - - ql_dbg(ql_dbg_init, vha, 0x0040, - "Configuring PCI space...\n"); - rval = ha->isp_ops->pci_config(vha); - if (rval) { - ql_log(ql_log_warn, vha, 0x0044, - "Unable to configure PCI space.\n"); - return (rval); - } - - ha->isp_ops->reset_chip(vha); - - rval = qla2xxx_get_flash_info(vha); - if (rval) { - ql_log(ql_log_fatal, vha, 0x004f, - "Unable to validate FLASH data.\n"); - return (rval); - } - - ha->isp_ops->get_flash_version(vha, req->ring); - ql_dbg(ql_dbg_init, vha, 0x0061, - "Configure NVRAM parameters...\n"); - - ha->isp_ops->nvram_config(vha); - - if (ha->flags.disable_serdes) { - /* Mask HBA via NVRAM settings? */ - ql_log(ql_log_info, vha, 0x0077, - "Masking HBA WWPN " - "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n", - vha->port_name[0], vha->port_name[1], - vha->port_name[2], vha->port_name[3], - vha->port_name[4], vha->port_name[5], - vha->port_name[6], vha->port_name[7]); - return QLA_FUNCTION_FAILED; - } - - ql_dbg(ql_dbg_init, vha, 0x0078, - "Verifying loaded RISC code...\n"); - - if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) { - rval = ha->isp_ops->chip_diag(vha); - if (rval) - return (rval); - rval = qla2x00_setup_chip(vha); - if (rval) - return (rval); - } - - if (IS_QLA84XX(ha)) { - ha->cs84xx = qla84xx_get_chip(vha); - if (!ha->cs84xx) { - ql_log(ql_log_warn, vha, 0x00d0, - "Unable to configure ISP84XX.\n"); - return QLA_FUNCTION_FAILED; - } - } - rval = qla2x00_init_rings(vha); - ha->flags.chip_reset_done = 1; - - if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) { - /* Issue verify 84xx FW IOCB to complete 84xx initialization */ - rval = qla84xx_init_chip(vha); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x00d4, - "Unable to initialize ISP84XX.\n"); - qla84xx_put_chip(vha); - } - } - - if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) - qla24xx_read_fcp_prio_cfg(vha); - - return (rval); -} - -/** - * qla2100_pci_config() - Setup ISP21xx PCI configuration registers. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla2100_pci_config(scsi_qla_host_t *vha) -{ - uint16_t w; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - pci_set_master(ha->pdev); - pci_try_set_mwi(ha->pdev); - - pci_read_config_word(ha->pdev, PCI_COMMAND, &w); - w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); - pci_write_config_word(ha->pdev, PCI_COMMAND, w); - - pci_disable_rom(ha->pdev); - - /* Get PCI bus information. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->pci_attr = RD_REG_WORD(®->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_SUCCESS; -} - -/** - * qla2300_pci_config() - Setup ISP23xx PCI configuration registers. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla2300_pci_config(scsi_qla_host_t *vha) -{ - uint16_t w; - unsigned long flags = 0; - uint32_t cnt; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - pci_set_master(ha->pdev); - pci_try_set_mwi(ha->pdev); - - pci_read_config_word(ha->pdev, PCI_COMMAND, &w); - w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); - - if (IS_QLA2322(ha) || IS_QLA6322(ha)) - w &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(ha->pdev, PCI_COMMAND, w); - - /* - * If this is a 2300 card and not 2312, reset the - * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately, - * the 2310 also reports itself as a 2300 so we need to get the - * fb revision level -- a 6 indicates it really is a 2300 and - * not a 2310. - */ - if (IS_QLA2300(ha)) { - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Pause RISC. */ - WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) != 0) - break; - - udelay(10); - } - - /* Select FPM registers. */ - WRT_REG_WORD(®->ctrl_status, 0x20); - RD_REG_WORD(®->ctrl_status); - - /* Get the fb rev level */ - ha->fb_rev = RD_FB_CMD_REG(ha, reg); - - if (ha->fb_rev == FPM_2300) - pci_clear_mwi(ha->pdev); - - /* Deselect FPM registers. */ - WRT_REG_WORD(®->ctrl_status, 0x0); - RD_REG_WORD(®->ctrl_status); - - /* Release RISC module. */ - WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) == 0) - break; - - udelay(10); - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - - pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); - - pci_disable_rom(ha->pdev); - - /* Get PCI bus information. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->pci_attr = RD_REG_WORD(®->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_SUCCESS; -} - -/** - * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla24xx_pci_config(scsi_qla_host_t *vha) -{ - uint16_t w; - unsigned long flags = 0; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - pci_set_master(ha->pdev); - pci_try_set_mwi(ha->pdev); - - pci_read_config_word(ha->pdev, PCI_COMMAND, &w); - w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); - w &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(ha->pdev, PCI_COMMAND, w); - - pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80); - - /* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */ - if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX)) - pcix_set_mmrbc(ha->pdev, 2048); - - /* PCIe -- adjust Maximum Read Request Size (2048). */ - if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP)) - pcie_set_readrq(ha->pdev, 2048); - - pci_disable_rom(ha->pdev); - - ha->chip_revision = ha->pdev->revision; - - /* Get PCI bus information. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->pci_attr = RD_REG_DWORD(®->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_SUCCESS; -} - -/** - * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla25xx_pci_config(scsi_qla_host_t *vha) -{ - uint16_t w; - struct qla_hw_data *ha = vha->hw; - - pci_set_master(ha->pdev); - pci_try_set_mwi(ha->pdev); - - pci_read_config_word(ha->pdev, PCI_COMMAND, &w); - w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR); - w &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(ha->pdev, PCI_COMMAND, w); - - /* PCIe -- adjust Maximum Read Request Size (2048). */ - if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP)) - pcie_set_readrq(ha->pdev, 2048); - - pci_disable_rom(ha->pdev); - - ha->chip_revision = ha->pdev->revision; - - return QLA_SUCCESS; -} - -/** - * qla2x00_isp_firmware() - Choose firmware image. - * @ha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_isp_firmware(scsi_qla_host_t *vha) -{ - int rval; - uint16_t loop_id, topo, sw_cap; - uint8_t domain, area, al_pa; - struct qla_hw_data *ha = vha->hw; - - /* Assume loading risc code */ - rval = QLA_FUNCTION_FAILED; - - if (ha->flags.disable_risc_code_load) { - ql_log(ql_log_info, vha, 0x0079, "RISC CODE NOT loaded.\n"); - - /* Verify checksum of loaded RISC code. */ - rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address); - if (rval == QLA_SUCCESS) { - /* And, verify we are not in ROM code. */ - rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa, - &area, &domain, &topo, &sw_cap); - } - } - - if (rval) - ql_dbg(ql_dbg_init, vha, 0x007a, - "**** Load RISC code ****.\n"); - - return (rval); -} - -/** - * qla2x00_reset_chip() - Reset ISP chip. - * @ha: HA context - * - * Returns 0 on success. - */ -void -qla2x00_reset_chip(scsi_qla_host_t *vha) -{ - unsigned long flags = 0; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - uint32_t cnt; - uint16_t cmd; - - if (unlikely(pci_channel_offline(ha->pdev))) - return; - - ha->isp_ops->disable_intrs(ha); - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Turn off master enable */ - cmd = 0; - pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd); - cmd &= ~PCI_COMMAND_MASTER; - pci_write_config_word(ha->pdev, PCI_COMMAND, cmd); - - if (!IS_QLA2100(ha)) { - /* Pause RISC. */ - WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); - if (IS_QLA2200(ha) || IS_QLA2300(ha)) { - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_WORD(®->hccr) & - HCCR_RISC_PAUSE) != 0) - break; - udelay(100); - } - } else { - RD_REG_WORD(®->hccr); /* PCI Posting. */ - udelay(10); - } - - /* Select FPM registers. */ - WRT_REG_WORD(®->ctrl_status, 0x20); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - - /* FPM Soft Reset. */ - WRT_REG_WORD(®->fpm_diag_config, 0x100); - RD_REG_WORD(®->fpm_diag_config); /* PCI Posting. */ - - /* Toggle Fpm Reset. */ - if (!IS_QLA2200(ha)) { - WRT_REG_WORD(®->fpm_diag_config, 0x0); - RD_REG_WORD(®->fpm_diag_config); /* PCI Posting. */ - } - - /* Select frame buffer registers. */ - WRT_REG_WORD(®->ctrl_status, 0x10); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - - /* Reset frame buffer FIFOs. */ - if (IS_QLA2200(ha)) { - WRT_FB_CMD_REG(ha, reg, 0xa000); - RD_FB_CMD_REG(ha, reg); /* PCI Posting. */ - } else { - WRT_FB_CMD_REG(ha, reg, 0x00fc); - - /* Read back fb_cmd until zero or 3 seconds max */ - for (cnt = 0; cnt < 3000; cnt++) { - if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0) - break; - udelay(100); - } - } - - /* Select RISC module registers. */ - WRT_REG_WORD(®->ctrl_status, 0); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - - /* Reset RISC processor. */ - WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); - RD_REG_WORD(®->hccr); /* PCI Posting. */ - - /* Release RISC processor. */ - WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); - RD_REG_WORD(®->hccr); /* PCI Posting. */ - } - - WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); - WRT_REG_WORD(®->hccr, HCCR_CLR_HOST_INT); - - /* Reset ISP chip. */ - WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); - - /* Wait for RISC to recover from reset. */ - if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { - /* - * It is necessary to for a delay here since the card doesn't - * respond to PCI reads during a reset. On some architectures - * this will result in an MCA. - */ - udelay(20); - for (cnt = 30000; cnt; cnt--) { - if ((RD_REG_WORD(®->ctrl_status) & - CSR_ISP_SOFT_RESET) == 0) - break; - udelay(100); - } - } else - udelay(10); - - /* Reset RISC processor. */ - WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); - - WRT_REG_WORD(®->semaphore, 0); - - /* Release RISC processor. */ - WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); - RD_REG_WORD(®->hccr); /* PCI Posting. */ - - if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { - for (cnt = 0; cnt < 30000; cnt++) { - if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY) - break; - - udelay(100); - } - } else - udelay(100); - - /* Turn on master enable */ - cmd |= PCI_COMMAND_MASTER; - pci_write_config_word(ha->pdev, PCI_COMMAND, cmd); - - /* Disable RISC pause on FPM parity error. */ - if (!IS_QLA2100(ha)) { - WRT_REG_WORD(®->hccr, HCCR_DISABLE_PARITY_PAUSE); - RD_REG_WORD(®->hccr); /* PCI Posting. */ - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -/** - * qla81xx_reset_mpi() - Reset's MPI FW via Write MPI Register MBC. - * - * Returns 0 on success. - */ -int -qla81xx_reset_mpi(scsi_qla_host_t *vha) -{ - uint16_t mb[4] = {0x1010, 0, 1, 0}; - - if (!IS_QLA81XX(vha->hw)) - return QLA_SUCCESS; - - return qla81xx_write_mpi_register(vha, mb); -} - -/** - * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC. - * @ha: HA context - * - * Returns 0 on success. - */ -static inline void -qla24xx_reset_risc(scsi_qla_host_t *vha) -{ - unsigned long flags = 0; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - uint32_t cnt, d2; - uint16_t wd; - static int abts_cnt; /* ISP abort retry counts */ - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Reset RISC. */ - WRT_REG_DWORD(®->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_DWORD(®->ctrl_status) & CSRX_DMA_ACTIVE) == 0) - break; - - udelay(10); - } - - WRT_REG_DWORD(®->ctrl_status, - CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES); - pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); - - udelay(100); - /* Wait for firmware to complete NVRAM accesses. */ - d2 = (uint32_t) RD_REG_WORD(®->mailbox0); - for (cnt = 10000 ; cnt && d2; cnt--) { - udelay(5); - d2 = (uint32_t) RD_REG_WORD(®->mailbox0); - barrier(); - } - - /* Wait for soft-reset to complete. */ - d2 = RD_REG_DWORD(®->ctrl_status); - for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) { - udelay(5); - d2 = RD_REG_DWORD(®->ctrl_status); - barrier(); - } - - /* If required, do an MPI FW reset now */ - if (test_and_clear_bit(MPI_RESET_NEEDED, &vha->dpc_flags)) { - if (qla81xx_reset_mpi(vha) != QLA_SUCCESS) { - if (++abts_cnt < 5) { - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - set_bit(MPI_RESET_NEEDED, &vha->dpc_flags); - } else { - /* - * We exhausted the ISP abort retries. We have to - * set the board offline. - */ - abts_cnt = 0; - vha->flags.online = 0; - } - } - } - - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); - RD_REG_DWORD(®->hccr); - - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); - - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); - RD_REG_DWORD(®->hccr); - - d2 = (uint32_t) RD_REG_WORD(®->mailbox0); - for (cnt = 6000000 ; cnt && d2; cnt--) { - udelay(5); - d2 = (uint32_t) RD_REG_WORD(®->mailbox0); - barrier(); - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (IS_NOPOLLING_TYPE(ha)) - ha->isp_ops->enable_intrs(ha); -} - -/** - * qla24xx_reset_chip() - Reset ISP24xx chip. - * @ha: HA context - * - * Returns 0 on success. - */ -void -qla24xx_reset_chip(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - if (pci_channel_offline(ha->pdev) && - ha->flags.pci_channel_io_perm_failure) { - return; - } - - ha->isp_ops->disable_intrs(ha); - - /* Perform RISC reset. */ - qla24xx_reset_risc(vha); -} - -/** - * qla2x00_chip_diag() - Test chip for proper operation. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla2x00_chip_diag(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - unsigned long flags = 0; - uint16_t data; - uint32_t cnt; - uint16_t mb[5]; - struct req_que *req = ha->req_q_map[0]; - - /* Assume a failed state */ - rval = QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_init, vha, 0x007b, - "Testing device at %lx.\n", (u_long)®->flash_address); - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Reset ISP chip. */ - WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); - - /* - * We need to have a delay here since the card will not respond while - * in reset causing an MCA on some architectures. - */ - udelay(20); - data = qla2x00_debounce_register(®->ctrl_status); - for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) { - udelay(5); - data = RD_REG_WORD(®->ctrl_status); - barrier(); - } - - if (!cnt) - goto chip_diag_failed; - - ql_dbg(ql_dbg_init, vha, 0x007c, - "Reset register cleared by chip reset.\n"); - - /* Reset RISC processor. */ - WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); - WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); - - /* Workaround for QLA2312 PCI parity error */ - if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { - data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0)); - for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) { - udelay(5); - data = RD_MAILBOX_REG(ha, reg, 0); - barrier(); - } - } else - udelay(10); - - if (!cnt) - goto chip_diag_failed; - - /* Check product ID of chip */ - ql_dbg(ql_dbg_init, vha, 0x007d, "Checking product Id of chip.\n"); - - mb[1] = RD_MAILBOX_REG(ha, reg, 1); - mb[2] = RD_MAILBOX_REG(ha, reg, 2); - mb[3] = RD_MAILBOX_REG(ha, reg, 3); - mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4)); - if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) || - mb[3] != PROD_ID_3) { - ql_log(ql_log_warn, vha, 0x0062, - "Wrong product ID = 0x%x,0x%x,0x%x.\n", - mb[1], mb[2], mb[3]); - - goto chip_diag_failed; - } - ha->product_id[0] = mb[1]; - ha->product_id[1] = mb[2]; - ha->product_id[2] = mb[3]; - ha->product_id[3] = mb[4]; - - /* Adjust fw RISC transfer size */ - if (req->length > 1024) - ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024; - else - ha->fw_transfer_size = REQUEST_ENTRY_SIZE * - req->length; - - if (IS_QLA2200(ha) && - RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) { - /* Limit firmware transfer size with a 2200A */ - ql_dbg(ql_dbg_init, vha, 0x007e, "Found QLA2200A Chip.\n"); - - ha->device_type |= DT_ISP2200A; - ha->fw_transfer_size = 128; - } - - /* Wrap Incoming Mailboxes Test. */ - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - ql_dbg(ql_dbg_init, vha, 0x007f, "Checking mailboxes.\n"); - rval = qla2x00_mbx_reg_test(vha); - if (rval) - ql_log(ql_log_warn, vha, 0x0080, - "Failed mailbox send register test.\n"); - else - /* Flag a successful rval */ - rval = QLA_SUCCESS; - spin_lock_irqsave(&ha->hardware_lock, flags); - -chip_diag_failed: - if (rval) - ql_log(ql_log_info, vha, 0x0081, - "Chip diagnostics **** FAILED ****.\n"); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return (rval); -} - -/** - * qla24xx_chip_diag() - Test ISP24xx for proper operation. - * @ha: HA context - * - * Returns 0 on success. - */ -int -qla24xx_chip_diag(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - if (IS_QLA82XX(ha)) - return QLA_SUCCESS; - - ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length; - - rval = qla2x00_mbx_reg_test(vha); - if (rval) { - ql_log(ql_log_warn, vha, 0x0082, - "Failed mailbox send register test.\n"); - } else { - /* Flag a successful rval */ - rval = QLA_SUCCESS; - } - - return rval; -} - -void -qla2x00_alloc_fw_dump(scsi_qla_host_t *vha) -{ - int rval; - uint32_t dump_size, fixed_size, mem_size, req_q_size, rsp_q_size, - eft_size, fce_size, mq_size; - dma_addr_t tc_dma; - void *tc; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; - - if (ha->fw_dump) { - ql_dbg(ql_dbg_init, vha, 0x00bd, - "Firmware dump already allocated.\n"); - return; - } - - ha->fw_dumped = 0; - fixed_size = mem_size = eft_size = fce_size = mq_size = 0; - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - fixed_size = sizeof(struct qla2100_fw_dump); - } else if (IS_QLA23XX(ha)) { - fixed_size = offsetof(struct qla2300_fw_dump, data_ram); - mem_size = (ha->fw_memory_size - 0x11000 + 1) * - sizeof(uint16_t); - } else if (IS_FWI2_CAPABLE(ha)) { - if (IS_QLA83XX(ha)) - fixed_size = offsetof(struct qla83xx_fw_dump, ext_mem); - else if (IS_QLA81XX(ha)) - fixed_size = offsetof(struct qla81xx_fw_dump, ext_mem); - else if (IS_QLA25XX(ha)) - fixed_size = offsetof(struct qla25xx_fw_dump, ext_mem); - else - fixed_size = offsetof(struct qla24xx_fw_dump, ext_mem); - mem_size = (ha->fw_memory_size - 0x100000 + 1) * - sizeof(uint32_t); - if (ha->mqenable) { - if (!IS_QLA83XX(ha)) - mq_size = sizeof(struct qla2xxx_mq_chain); - /* - * Allocate maximum buffer size for all queues. - * Resizing must be done at end-of-dump processing. - */ - mq_size += ha->max_req_queues * - (req->length * sizeof(request_t)); - mq_size += ha->max_rsp_queues * - (rsp->length * sizeof(response_t)); - } - /* Allocate memory for Fibre Channel Event Buffer. */ - if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha)) - goto try_eft; - - tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, - GFP_KERNEL); - if (!tc) { - ql_log(ql_log_warn, vha, 0x00be, - "Unable to allocate (%d KB) for FCE.\n", - FCE_SIZE / 1024); - goto try_eft; - } - - memset(tc, 0, FCE_SIZE); - rval = qla2x00_enable_fce_trace(vha, tc_dma, FCE_NUM_BUFFERS, - ha->fce_mb, &ha->fce_bufs); - if (rval) { - ql_log(ql_log_warn, vha, 0x00bf, - "Unable to initialize FCE (%d).\n", rval); - dma_free_coherent(&ha->pdev->dev, FCE_SIZE, tc, - tc_dma); - ha->flags.fce_enabled = 0; - goto try_eft; - } - ql_dbg(ql_dbg_init, vha, 0x00c0, - "Allocate (%d KB) for FCE...\n", FCE_SIZE / 1024); - - fce_size = sizeof(struct qla2xxx_fce_chain) + FCE_SIZE; - ha->flags.fce_enabled = 1; - ha->fce_dma = tc_dma; - ha->fce = tc; -try_eft: - /* Allocate memory for Extended Trace Buffer. */ - tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, - GFP_KERNEL); - if (!tc) { - ql_log(ql_log_warn, vha, 0x00c1, - "Unable to allocate (%d KB) for EFT.\n", - EFT_SIZE / 1024); - goto cont_alloc; - } - - memset(tc, 0, EFT_SIZE); - rval = qla2x00_enable_eft_trace(vha, tc_dma, EFT_NUM_BUFFERS); - if (rval) { - ql_log(ql_log_warn, vha, 0x00c2, - "Unable to initialize EFT (%d).\n", rval); - dma_free_coherent(&ha->pdev->dev, EFT_SIZE, tc, - tc_dma); - goto cont_alloc; - } - ql_dbg(ql_dbg_init, vha, 0x00c3, - "Allocated (%d KB) EFT ...\n", EFT_SIZE / 1024); - - eft_size = EFT_SIZE; - ha->eft_dma = tc_dma; - ha->eft = tc; - } -cont_alloc: - req_q_size = req->length * sizeof(request_t); - rsp_q_size = rsp->length * sizeof(response_t); - - dump_size = offsetof(struct qla2xxx_fw_dump, isp); - dump_size += fixed_size + mem_size + req_q_size + rsp_q_size + eft_size; - ha->chain_offset = dump_size; - dump_size += mq_size + fce_size; - - ha->fw_dump = vmalloc(dump_size); - if (!ha->fw_dump) { - ql_log(ql_log_warn, vha, 0x00c4, - "Unable to allocate (%d KB) for firmware dump.\n", - dump_size / 1024); - - if (ha->fce) { - dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, - ha->fce_dma); - ha->fce = NULL; - ha->fce_dma = 0; - } - - if (ha->eft) { - dma_free_coherent(&ha->pdev->dev, eft_size, ha->eft, - ha->eft_dma); - ha->eft = NULL; - ha->eft_dma = 0; - } - return; - } - ql_dbg(ql_dbg_init, vha, 0x00c5, - "Allocated (%d KB) for firmware dump.\n", dump_size / 1024); - - ha->fw_dump_len = dump_size; - ha->fw_dump->signature[0] = 'Q'; - ha->fw_dump->signature[1] = 'L'; - ha->fw_dump->signature[2] = 'G'; - ha->fw_dump->signature[3] = 'C'; - ha->fw_dump->version = __constant_htonl(1); - - ha->fw_dump->fixed_size = htonl(fixed_size); - ha->fw_dump->mem_size = htonl(mem_size); - ha->fw_dump->req_q_size = htonl(req_q_size); - ha->fw_dump->rsp_q_size = htonl(rsp_q_size); - - ha->fw_dump->eft_size = htonl(eft_size); - ha->fw_dump->eft_addr_l = htonl(LSD(ha->eft_dma)); - ha->fw_dump->eft_addr_h = htonl(MSD(ha->eft_dma)); - - ha->fw_dump->header_size = - htonl(offsetof(struct qla2xxx_fw_dump, isp)); -} - -static int -qla81xx_mpi_sync(scsi_qla_host_t *vha) -{ -#define MPS_MASK 0xe0 - int rval; - uint16_t dc; - uint32_t dw; - - if (!IS_QLA81XX(vha->hw)) - return QLA_SUCCESS; - - rval = qla2x00_write_ram_word(vha, 0x7c00, 1); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x0105, - "Unable to acquire semaphore.\n"); - goto done; - } - - pci_read_config_word(vha->hw->pdev, 0x54, &dc); - rval = qla2x00_read_ram_word(vha, 0x7a15, &dw); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x0067, "Unable to read sync.\n"); - goto done_release; - } - - dc &= MPS_MASK; - if (dc == (dw & MPS_MASK)) - goto done_release; - - dw &= ~MPS_MASK; - dw |= dc; - rval = qla2x00_write_ram_word(vha, 0x7a15, dw); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x0114, "Unable to gain sync.\n"); - } - -done_release: - rval = qla2x00_write_ram_word(vha, 0x7c00, 0); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x006d, - "Unable to release semaphore.\n"); - } - -done: - return rval; -} - -/** - * qla2x00_setup_chip() - Load and start RISC firmware. - * @ha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_setup_chip(scsi_qla_host_t *vha) -{ - int rval; - uint32_t srisc_address = 0; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - unsigned long flags; - uint16_t fw_major_version; - - if (IS_QLA82XX(ha)) { - rval = ha->isp_ops->load_risc(vha, &srisc_address); - if (rval == QLA_SUCCESS) { - qla2x00_stop_firmware(vha); - goto enable_82xx_npiv; - } else - goto failed; - } - - if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { - /* Disable SRAM, Instruction RAM and GP RAM parity. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_WORD(®->hccr, (HCCR_ENABLE_PARITY + 0x0)); - RD_REG_WORD(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - - qla81xx_mpi_sync(vha); - - /* Load firmware sequences */ - rval = ha->isp_ops->load_risc(vha, &srisc_address); - if (rval == QLA_SUCCESS) { - ql_dbg(ql_dbg_init, vha, 0x00c9, - "Verifying Checksum of loaded RISC code.\n"); - - rval = qla2x00_verify_checksum(vha, srisc_address); - if (rval == QLA_SUCCESS) { - /* Start firmware execution. */ - ql_dbg(ql_dbg_init, vha, 0x00ca, - "Starting firmware.\n"); - - rval = qla2x00_execute_fw(vha, srisc_address); - /* Retrieve firmware information. */ - if (rval == QLA_SUCCESS) { -enable_82xx_npiv: - fw_major_version = ha->fw_major_version; - if (IS_QLA82XX(ha)) - qla82xx_check_md_needed(vha); - else - rval = qla2x00_get_fw_version(vha); - if (rval != QLA_SUCCESS) - goto failed; - ha->flags.npiv_supported = 0; - if (IS_QLA2XXX_MIDTYPE(ha) && - (ha->fw_attributes & BIT_2)) { - ha->flags.npiv_supported = 1; - if ((!ha->max_npiv_vports) || - ((ha->max_npiv_vports + 1) % - MIN_MULTI_ID_FABRIC)) - ha->max_npiv_vports = - MIN_MULTI_ID_FABRIC - 1; - } - qla2x00_get_resource_cnts(vha, NULL, - &ha->fw_xcb_count, NULL, NULL, - &ha->max_npiv_vports, NULL); - - if (!fw_major_version && ql2xallocfwdump - && !IS_QLA82XX(ha)) - qla2x00_alloc_fw_dump(vha); - } - } else { - ql_log(ql_log_fatal, vha, 0x00cd, - "ISP Firmware failed checksum.\n"); - goto failed; - } - } - - if (!IS_FWI2_CAPABLE(ha) && !IS_QLA2100(ha) && !IS_QLA2200(ha)) { - /* Enable proper parity. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - if (IS_QLA2300(ha)) - /* SRAM parity */ - WRT_REG_WORD(®->hccr, HCCR_ENABLE_PARITY + 0x1); - else - /* SRAM, Instruction RAM and GP RAM parity */ - WRT_REG_WORD(®->hccr, HCCR_ENABLE_PARITY + 0x7); - RD_REG_WORD(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - - if (IS_QLA83XX(ha)) - goto skip_fac_check; - - if (rval == QLA_SUCCESS && IS_FAC_REQUIRED(ha)) { - uint32_t size; - - rval = qla81xx_fac_get_sector_size(vha, &size); - if (rval == QLA_SUCCESS) { - ha->flags.fac_supported = 1; - ha->fdt_block_size = size << 2; - } else { - ql_log(ql_log_warn, vha, 0x00ce, - "Unsupported FAC firmware (%d.%02d.%02d).\n", - ha->fw_major_version, ha->fw_minor_version, - ha->fw_subminor_version); -skip_fac_check: - if (IS_QLA83XX(ha)) { - ha->flags.fac_supported = 0; - rval = QLA_SUCCESS; - } - } - } -failed: - if (rval) { - ql_log(ql_log_fatal, vha, 0x00cf, - "Setup chip ****FAILED****.\n"); - } - - return (rval); -} - -/** - * qla2x00_init_response_q_entries() - Initializes response queue entries. - * @ha: HA context - * - * Beginning of request ring has initialization control block already built - * by nvram config routine. - * - * Returns 0 on success. - */ -void -qla2x00_init_response_q_entries(struct rsp_que *rsp) -{ - uint16_t cnt; - response_t *pkt; - - rsp->ring_ptr = rsp->ring; - rsp->ring_index = 0; - rsp->status_srb = NULL; - pkt = rsp->ring_ptr; - for (cnt = 0; cnt < rsp->length; cnt++) { - pkt->signature = RESPONSE_PROCESSED; - pkt++; - } -} - -/** - * qla2x00_update_fw_options() - Read and process firmware options. - * @ha: HA context - * - * Returns 0 on success. - */ -void -qla2x00_update_fw_options(scsi_qla_host_t *vha) -{ - uint16_t swing, emphasis, tx_sens, rx_sens; - struct qla_hw_data *ha = vha->hw; - - memset(ha->fw_options, 0, sizeof(ha->fw_options)); - qla2x00_get_fw_options(vha, ha->fw_options); - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - return; - - /* Serial Link options. */ - ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0115, - "Serial link options.\n"); - ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0109, - (uint8_t *)&ha->fw_seriallink_options, - sizeof(ha->fw_seriallink_options)); - - ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; - if (ha->fw_seriallink_options[3] & BIT_2) { - ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING; - - /* 1G settings */ - swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0); - emphasis = (ha->fw_seriallink_options[2] & - (BIT_4 | BIT_3)) >> 3; - tx_sens = ha->fw_seriallink_options[0] & - (BIT_3 | BIT_2 | BIT_1 | BIT_0); - rx_sens = (ha->fw_seriallink_options[0] & - (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4; - ha->fw_options[10] = (emphasis << 14) | (swing << 8); - if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) { - if (rx_sens == 0x0) - rx_sens = 0x3; - ha->fw_options[10] |= (tx_sens << 4) | rx_sens; - } else if (IS_QLA2322(ha) || IS_QLA6322(ha)) - ha->fw_options[10] |= BIT_5 | - ((rx_sens & (BIT_1 | BIT_0)) << 2) | - (tx_sens & (BIT_1 | BIT_0)); - - /* 2G settings */ - swing = (ha->fw_seriallink_options[2] & - (BIT_7 | BIT_6 | BIT_5)) >> 5; - emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0); - tx_sens = ha->fw_seriallink_options[1] & - (BIT_3 | BIT_2 | BIT_1 | BIT_0); - rx_sens = (ha->fw_seriallink_options[1] & - (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4; - ha->fw_options[11] = (emphasis << 14) | (swing << 8); - if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) { - if (rx_sens == 0x0) - rx_sens = 0x3; - ha->fw_options[11] |= (tx_sens << 4) | rx_sens; - } else if (IS_QLA2322(ha) || IS_QLA6322(ha)) - ha->fw_options[11] |= BIT_5 | - ((rx_sens & (BIT_1 | BIT_0)) << 2) | - (tx_sens & (BIT_1 | BIT_0)); - } - - /* FCP2 options. */ - /* Return command IOCBs without waiting for an ABTS to complete. */ - ha->fw_options[3] |= BIT_13; - - /* LED scheme. */ - if (ha->flags.enable_led_scheme) - ha->fw_options[2] |= BIT_12; - - /* Detect ISP6312. */ - if (IS_QLA6312(ha)) - ha->fw_options[2] |= BIT_13; - - /* Update firmware options. */ - qla2x00_set_fw_options(vha, ha->fw_options); -} - -void -qla24xx_update_fw_options(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - - if (IS_QLA82XX(ha)) - return; - - /* Update Serial Link options. */ - if ((le16_to_cpu(ha->fw_seriallink_options24[0]) & BIT_0) == 0) - return; - - rval = qla2x00_set_serdes_params(vha, - le16_to_cpu(ha->fw_seriallink_options24[1]), - le16_to_cpu(ha->fw_seriallink_options24[2]), - le16_to_cpu(ha->fw_seriallink_options24[3])); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x0104, - "Unable to update Serial Link options (%x).\n", rval); - } -} - -void -qla2x00_config_rings(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; - - /* Setup ring parameters in initialization control block. */ - ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0); - ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0); - ha->init_cb->request_q_length = cpu_to_le16(req->length); - ha->init_cb->response_q_length = cpu_to_le16(rsp->length); - ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); - ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(req->dma)); - ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); - ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); - - WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0); - WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0); - WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0); - WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0); - RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg)); /* PCI Posting. */ -} - -void -qla24xx_config_rings(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, 0); - struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; - struct qla_msix_entry *msix; - struct init_cb_24xx *icb; - uint16_t rid = 0; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; - - /* Setup ring parameters in initialization control block. */ - icb = (struct init_cb_24xx *)ha->init_cb; - icb->request_q_outpointer = __constant_cpu_to_le16(0); - icb->response_q_inpointer = __constant_cpu_to_le16(0); - icb->request_q_length = cpu_to_le16(req->length); - icb->response_q_length = cpu_to_le16(rsp->length); - icb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); - icb->request_q_address[1] = cpu_to_le32(MSD(req->dma)); - icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); - icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); - - if (ha->mqenable || IS_QLA83XX(ha)) { - icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS); - icb->rid = __constant_cpu_to_le16(rid); - if (ha->flags.msix_enabled) { - msix = &ha->msix_entries[1]; - ql_dbg(ql_dbg_init, vha, 0x00fd, - "Registering vector 0x%x for base que.\n", - msix->entry); - icb->msix = cpu_to_le16(msix->entry); - } - /* Use alternate PCI bus number */ - if (MSB(rid)) - icb->firmware_options_2 |= - __constant_cpu_to_le32(BIT_19); - /* Use alternate PCI devfn */ - if (LSB(rid)) - icb->firmware_options_2 |= - __constant_cpu_to_le32(BIT_18); - - /* Use Disable MSIX Handshake mode for capable adapters */ - if ((ha->fw_attributes & BIT_6) && (IS_MSIX_NACK_CAPABLE(ha)) && - (ha->flags.msix_enabled)) { - icb->firmware_options_2 &= - __constant_cpu_to_le32(~BIT_22); - ha->flags.disable_msix_handshake = 1; - ql_dbg(ql_dbg_init, vha, 0x00fe, - "MSIX Handshake Disable Mode turned on.\n"); - } else { - icb->firmware_options_2 |= - __constant_cpu_to_le32(BIT_22); - } - icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23); - - WRT_REG_DWORD(®->isp25mq.req_q_in, 0); - WRT_REG_DWORD(®->isp25mq.req_q_out, 0); - WRT_REG_DWORD(®->isp25mq.rsp_q_in, 0); - WRT_REG_DWORD(®->isp25mq.rsp_q_out, 0); - } else { - WRT_REG_DWORD(®->isp24.req_q_in, 0); - WRT_REG_DWORD(®->isp24.req_q_out, 0); - WRT_REG_DWORD(®->isp24.rsp_q_in, 0); - WRT_REG_DWORD(®->isp24.rsp_q_out, 0); - } - /* PCI posting */ - RD_REG_DWORD(&ioreg->hccr); -} - -/** - * qla2x00_init_rings() - Initializes firmware. - * @ha: HA context - * - * Beginning of request ring has initialization control block already built - * by nvram config routine. - * - * Returns 0 on success. - */ -static int -qla2x00_init_rings(scsi_qla_host_t *vha) -{ - int rval; - unsigned long flags = 0; - int cnt, que; - struct qla_hw_data *ha = vha->hw; - struct req_que *req; - struct rsp_que *rsp; - struct mid_init_cb_24xx *mid_init_cb = - (struct mid_init_cb_24xx *) ha->init_cb; - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Clear outstanding commands array. */ - for (que = 0; que < ha->max_req_queues; que++) { - req = ha->req_q_map[que]; - if (!req) - continue; - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) - req->outstanding_cmds[cnt] = NULL; - - req->current_outstanding_cmd = 1; - - /* Initialize firmware. */ - req->ring_ptr = req->ring; - req->ring_index = 0; - req->cnt = req->length; - } - - for (que = 0; que < ha->max_rsp_queues; que++) { - rsp = ha->rsp_q_map[que]; - if (!rsp) - continue; - /* Initialize response queue entries */ - qla2x00_init_response_q_entries(rsp); - } - - spin_lock(&ha->vport_slock); - - spin_unlock(&ha->vport_slock); - - ha->isp_ops->config_rings(vha); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* Update any ISP specific firmware options before initialization. */ - ha->isp_ops->update_fw_options(vha); - - ql_dbg(ql_dbg_init, vha, 0x00d1, "Issue init firmware.\n"); - - if (ha->flags.npiv_supported) { - if (ha->operating_mode == LOOP) - ha->max_npiv_vports = MIN_MULTI_ID_FABRIC - 1; - mid_init_cb->count = cpu_to_le16(ha->max_npiv_vports); - } - - if (IS_FWI2_CAPABLE(ha)) { - mid_init_cb->options = __constant_cpu_to_le16(BIT_1); - mid_init_cb->init_cb.execution_throttle = - cpu_to_le16(ha->fw_xcb_count); - } - - rval = qla2x00_init_firmware(vha, ha->init_cb_size); - if (rval) { - ql_log(ql_log_fatal, vha, 0x00d2, - "Init Firmware **** FAILED ****.\n"); - } else { - ql_dbg(ql_dbg_init, vha, 0x00d3, - "Init Firmware -- success.\n"); - } - - return (rval); -} - -/** - * qla2x00_fw_ready() - Waits for firmware ready. - * @ha: HA context - * - * Returns 0 on success. - */ -static int -qla2x00_fw_ready(scsi_qla_host_t *vha) -{ - int rval; - unsigned long wtime, mtime, cs84xx_time; - uint16_t min_wait; /* Minimum wait time if loop is down */ - uint16_t wait_time; /* Wait time if loop is coming ready */ - uint16_t state[5]; - struct qla_hw_data *ha = vha->hw; - - rval = QLA_SUCCESS; - - /* 20 seconds for loop down. */ - min_wait = 20; - - /* - * Firmware should take at most one RATOV to login, plus 5 seconds for - * our own processing. - */ - if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) { - wait_time = min_wait; - } - - /* Min wait time if loop down */ - mtime = jiffies + (min_wait * HZ); - - /* wait time before firmware ready */ - wtime = jiffies + (wait_time * HZ); - - /* Wait for ISP to finish LIP */ - if (!vha->flags.init_done) - ql_log(ql_log_info, vha, 0x801e, - "Waiting for LIP to complete.\n"); - - do { - rval = qla2x00_get_firmware_state(vha, state); - if (rval == QLA_SUCCESS) { - if (state[0] < FSTATE_LOSS_OF_SYNC) { - vha->device_flags &= ~DFLG_NO_CABLE; - } - if (IS_QLA84XX(ha) && state[0] != FSTATE_READY) { - ql_dbg(ql_dbg_taskm, vha, 0x801f, - "fw_state=%x 84xx=%x.\n", state[0], - state[2]); - if ((state[2] & FSTATE_LOGGED_IN) && - (state[2] & FSTATE_WAITING_FOR_VERIFY)) { - ql_dbg(ql_dbg_taskm, vha, 0x8028, - "Sending verify iocb.\n"); - - cs84xx_time = jiffies; - rval = qla84xx_init_chip(vha); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, - vha, 0x8007, - "Init chip failed.\n"); - break; - } - - /* Add time taken to initialize. */ - cs84xx_time = jiffies - cs84xx_time; - wtime += cs84xx_time; - mtime += cs84xx_time; - ql_dbg(ql_dbg_taskm, vha, 0x8008, - "Increasing wait time by %ld. " - "New time %ld.\n", cs84xx_time, - wtime); - } - } else if (state[0] == FSTATE_READY) { - ql_dbg(ql_dbg_taskm, vha, 0x8037, - "F/W Ready - OK.\n"); - - qla2x00_get_retry_cnt(vha, &ha->retry_count, - &ha->login_timeout, &ha->r_a_tov); - - rval = QLA_SUCCESS; - break; - } - - rval = QLA_FUNCTION_FAILED; - - if (atomic_read(&vha->loop_down_timer) && - state[0] != FSTATE_READY) { - /* Loop down. Timeout on min_wait for states - * other than Wait for Login. - */ - if (time_after_eq(jiffies, mtime)) { - ql_log(ql_log_info, vha, 0x8038, - "Cable is unplugged...\n"); - - vha->device_flags |= DFLG_NO_CABLE; - break; - } - } - } else { - /* Mailbox cmd failed. Timeout on min_wait. */ - if (time_after_eq(jiffies, mtime) || - ha->flags.isp82xx_fw_hung) - break; - } - - if (time_after_eq(jiffies, wtime)) - break; - - /* Delay for a while */ - msleep(500); - } while (1); - - ql_dbg(ql_dbg_taskm, vha, 0x803a, - "fw_state=%x (%x, %x, %x, %x) " "curr time=%lx.\n", state[0], - state[1], state[2], state[3], state[4], jiffies); - - if (rval && !(vha->device_flags & DFLG_NO_CABLE)) { - ql_log(ql_log_warn, vha, 0x803b, - "Firmware ready **** FAILED ****.\n"); - } - - return (rval); -} - -/* -* qla2x00_configure_hba -* Setup adapter context. -* -* Input: -* ha = adapter state pointer. -* -* Returns: -* 0 = success -* -* Context: -* Kernel context. -*/ -static int -qla2x00_configure_hba(scsi_qla_host_t *vha) -{ - int rval; - uint16_t loop_id; - uint16_t topo; - uint16_t sw_cap; - uint8_t al_pa; - uint8_t area; - uint8_t domain; - char connect_type[22]; - struct qla_hw_data *ha = vha->hw; - - /* Get host addresses. */ - rval = qla2x00_get_adapter_id(vha, - &loop_id, &al_pa, &area, &domain, &topo, &sw_cap); - if (rval != QLA_SUCCESS) { - if (LOOP_TRANSITION(vha) || atomic_read(&ha->loop_down_timer) || - IS_CNA_CAPABLE(ha) || - (rval == QLA_COMMAND_ERROR && loop_id == 0x7)) { - ql_dbg(ql_dbg_disc, vha, 0x2008, - "Loop is in a transition state.\n"); - } else { - ql_log(ql_log_warn, vha, 0x2009, - "Unable to get host loop ID.\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - } - return (rval); - } - - if (topo == 4) { - ql_log(ql_log_info, vha, 0x200a, - "Cannot get topology - retrying.\n"); - return (QLA_FUNCTION_FAILED); - } - - vha->loop_id = loop_id; - - /* initialize */ - ha->min_external_loopid = SNS_FIRST_LOOP_ID; - ha->operating_mode = LOOP; - ha->switch_cap = 0; - - switch (topo) { - case 0: - ql_dbg(ql_dbg_disc, vha, 0x200b, "HBA in NL topology.\n"); - ha->current_topology = ISP_CFG_NL; - strcpy(connect_type, "(Loop)"); - break; - - case 1: - ql_dbg(ql_dbg_disc, vha, 0x200c, "HBA in FL topology.\n"); - ha->switch_cap = sw_cap; - ha->current_topology = ISP_CFG_FL; - strcpy(connect_type, "(FL_Port)"); - break; - - case 2: - ql_dbg(ql_dbg_disc, vha, 0x200d, "HBA in N P2P topology.\n"); - ha->operating_mode = P2P; - ha->current_topology = ISP_CFG_N; - strcpy(connect_type, "(N_Port-to-N_Port)"); - break; - - case 3: - ql_dbg(ql_dbg_disc, vha, 0x200e, "HBA in F P2P topology.\n"); - ha->switch_cap = sw_cap; - ha->operating_mode = P2P; - ha->current_topology = ISP_CFG_F; - strcpy(connect_type, "(F_Port)"); - break; - - default: - ql_dbg(ql_dbg_disc, vha, 0x200f, - "HBA in unknown topology %x, using NL.\n", topo); - ha->current_topology = ISP_CFG_NL; - strcpy(connect_type, "(Loop)"); - break; - } - - /* Save Host port and loop ID. */ - /* byte order - Big Endian */ - vha->d_id.b.domain = domain; - vha->d_id.b.area = area; - vha->d_id.b.al_pa = al_pa; - - if (!vha->flags.init_done) - ql_log(ql_log_info, vha, 0x2010, - "Topology - %s, Host Loop address 0x%x.\n", - connect_type, vha->loop_id); - - if (rval) { - ql_log(ql_log_warn, vha, 0x2011, - "%s FAILED\n", __func__); - } else { - ql_dbg(ql_dbg_disc, vha, 0x2012, - "%s success\n", __func__); - } - - return(rval); -} - -inline void -qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len, - char *def) -{ - char *st, *en; - uint16_t index; - struct qla_hw_data *ha = vha->hw; - int use_tbl = !IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && - !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha); - - if (memcmp(model, BINZERO, len) != 0) { - strncpy(ha->model_number, model, len); - st = en = ha->model_number; - en += len - 1; - while (en > st) { - if (*en != 0x20 && *en != 0x00) - break; - *en-- = '\0'; - } - - index = (ha->pdev->subsystem_device & 0xff); - if (use_tbl && - ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && - index < QLA_MODEL_NAMES) - strncpy(ha->model_desc, - qla2x00_model_name[index * 2 + 1], - sizeof(ha->model_desc) - 1); - } else { - index = (ha->pdev->subsystem_device & 0xff); - if (use_tbl && - ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC && - index < QLA_MODEL_NAMES) { - strcpy(ha->model_number, - qla2x00_model_name[index * 2]); - strncpy(ha->model_desc, - qla2x00_model_name[index * 2 + 1], - sizeof(ha->model_desc) - 1); - } else { - strcpy(ha->model_number, def); - } - } - if (IS_FWI2_CAPABLE(ha)) - qla2xxx_get_vpd_field(vha, "\x82", ha->model_desc, - sizeof(ha->model_desc)); -} - -/* On sparc systems, obtain port and node WWN from firmware - * properties. - */ -static void qla2xxx_nvram_wwn_from_ofw(scsi_qla_host_t *vha, nvram_t *nv) -{ -#ifdef CONFIG_SPARC - struct qla_hw_data *ha = vha->hw; - struct pci_dev *pdev = ha->pdev; - struct device_node *dp = pci_device_to_OF_node(pdev); - const u8 *val; - int len; - - val = of_get_property(dp, "port-wwn", &len); - if (val && len >= WWN_SIZE) - memcpy(nv->port_name, val, WWN_SIZE); - - val = of_get_property(dp, "node-wwn", &len); - if (val && len >= WWN_SIZE) - memcpy(nv->node_name, val, WWN_SIZE); -#endif -} - -/* -* NVRAM configuration for ISP 2xxx -* -* Input: -* ha = adapter block pointer. -* -* Output: -* initialization control block in response_ring -* host adapters parameters in host adapter block -* -* Returns: -* 0 = success. -*/ -int -qla2x00_nvram_config(scsi_qla_host_t *vha) -{ - int rval; - uint8_t chksum = 0; - uint16_t cnt; - uint8_t *dptr1, *dptr2; - struct qla_hw_data *ha = vha->hw; - init_cb_t *icb = ha->init_cb; - nvram_t *nv = ha->nvram; - uint8_t *ptr = ha->nvram; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - rval = QLA_SUCCESS; - - /* Determine NVRAM starting address. */ - ha->nvram_size = sizeof(nvram_t); - ha->nvram_base = 0; - if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) - if ((RD_REG_WORD(®->ctrl_status) >> 14) == 1) - ha->nvram_base = 0x80; - - /* Get NVRAM data and calculate checksum. */ - ha->isp_ops->read_nvram(vha, ptr, ha->nvram_base, ha->nvram_size); - for (cnt = 0, chksum = 0; cnt < ha->nvram_size; cnt++) - chksum += *ptr++; - - ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010f, - "Contents of NVRAM.\n"); - ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0110, - (uint8_t *)nv, ha->nvram_size); - - /* Bad NVRAM data, set defaults parameters. */ - if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || - nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) { - /* Reset NVRAM data. */ - ql_log(ql_log_warn, vha, 0x0064, - "Inconisistent NVRAM " - "detected: checksum=0x%x id=%c version=0x%x.\n", - chksum, nv->id[0], nv->nvram_version); - ql_log(ql_log_warn, vha, 0x0065, - "Falling back to " - "functioning (yet invalid -- WWPN) defaults.\n"); - - /* - * Set default initialization control block. - */ - memset(nv, 0, ha->nvram_size); - nv->parameter_block_version = ICB_VERSION; - - if (IS_QLA23XX(ha)) { - nv->firmware_options[0] = BIT_2 | BIT_1; - nv->firmware_options[1] = BIT_7 | BIT_5; - nv->add_firmware_options[0] = BIT_5; - nv->add_firmware_options[1] = BIT_5 | BIT_4; - nv->frame_payload_size = __constant_cpu_to_le16(2048); - nv->special_options[1] = BIT_7; - } else if (IS_QLA2200(ha)) { - nv->firmware_options[0] = BIT_2 | BIT_1; - nv->firmware_options[1] = BIT_7 | BIT_5; - nv->add_firmware_options[0] = BIT_5; - nv->add_firmware_options[1] = BIT_5 | BIT_4; - nv->frame_payload_size = __constant_cpu_to_le16(1024); - } else if (IS_QLA2100(ha)) { - nv->firmware_options[0] = BIT_3 | BIT_1; - nv->firmware_options[1] = BIT_5; - nv->frame_payload_size = __constant_cpu_to_le16(1024); - } - - nv->max_iocb_allocation = __constant_cpu_to_le16(256); - nv->execution_throttle = __constant_cpu_to_le16(16); - nv->retry_count = 8; - nv->retry_delay = 1; - - nv->port_name[0] = 33; - nv->port_name[3] = 224; - nv->port_name[4] = 139; - - qla2xxx_nvram_wwn_from_ofw(vha, nv); - - nv->login_timeout = 4; - - /* - * Set default host adapter parameters - */ - nv->host_p[1] = BIT_2; - nv->reset_delay = 5; - nv->port_down_retry_count = 8; - nv->max_luns_per_target = __constant_cpu_to_le16(8); - nv->link_down_timeout = 60; - - rval = 1; - } - -#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) - /* - * The SN2 does not provide BIOS emulation which means you can't change - * potentially bogus BIOS settings. Force the use of default settings - * for link rate and frame size. Hope that the rest of the settings - * are valid. - */ - if (ia64_platform_is("sn2")) { - nv->frame_payload_size = __constant_cpu_to_le16(2048); - if (IS_QLA23XX(ha)) - nv->special_options[1] = BIT_7; - } -#endif - - /* Reset Initialization control block */ - memset(icb, 0, ha->init_cb_size); - - /* - * Setup driver NVRAM options. - */ - nv->firmware_options[0] |= (BIT_6 | BIT_1); - nv->firmware_options[0] &= ~(BIT_5 | BIT_4); - nv->firmware_options[1] |= (BIT_5 | BIT_0); - nv->firmware_options[1] &= ~BIT_4; - - if (IS_QLA23XX(ha)) { - nv->firmware_options[0] |= BIT_2; - nv->firmware_options[0] &= ~BIT_3; - nv->firmware_options[0] &= ~BIT_6; - nv->add_firmware_options[1] |= BIT_5 | BIT_4; - - if (IS_QLA2300(ha)) { - if (ha->fb_rev == FPM_2310) { - strcpy(ha->model_number, "QLA2310"); - } else { - strcpy(ha->model_number, "QLA2300"); - } - } else { - qla2x00_set_model_info(vha, nv->model_number, - sizeof(nv->model_number), "QLA23xx"); - } - } else if (IS_QLA2200(ha)) { - nv->firmware_options[0] |= BIT_2; - /* - * 'Point-to-point preferred, else loop' is not a safe - * connection mode setting. - */ - if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) == - (BIT_5 | BIT_4)) { - /* Force 'loop preferred, else point-to-point'. */ - nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4); - nv->add_firmware_options[0] |= BIT_5; - } - strcpy(ha->model_number, "QLA22xx"); - } else /*if (IS_QLA2100(ha))*/ { - strcpy(ha->model_number, "QLA2100"); - } - - /* - * Copy over NVRAM RISC parameter block to initialization control block. - */ - dptr1 = (uint8_t *)icb; - dptr2 = (uint8_t *)&nv->parameter_block_version; - cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version; - while (cnt--) - *dptr1++ = *dptr2++; - - /* Copy 2nd half. */ - dptr1 = (uint8_t *)icb->add_firmware_options; - cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options; - while (cnt--) - *dptr1++ = *dptr2++; - - /* Use alternate WWN? */ - if (nv->host_p[1] & BIT_7) { - memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); - memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE); - } - - /* Prepare nodename */ - if ((icb->firmware_options[1] & BIT_6) == 0) { - /* - * Firmware will apply the following mask if the nodename was - * not provided. - */ - memcpy(icb->node_name, icb->port_name, WWN_SIZE); - icb->node_name[0] &= 0xF0; - } - - /* - * Set host adapter parameters. - */ - - /* - * BIT_7 in the host-parameters section allows for modification to - * internal driver logging. - */ - if (nv->host_p[0] & BIT_7) - ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK; - ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0); - /* Always load RISC code on non ISP2[12]00 chips. */ - if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) - ha->flags.disable_risc_code_load = 0; - ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0); - ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0); - ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0); - ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0; - ha->flags.disable_serdes = 0; - - ha->operating_mode = - (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; - - memcpy(ha->fw_seriallink_options, nv->seriallink_options, - sizeof(ha->fw_seriallink_options)); - - /* save HBA serial number */ - ha->serial0 = icb->port_name[5]; - ha->serial1 = icb->port_name[6]; - ha->serial2 = icb->port_name[7]; - memcpy(vha->node_name, icb->node_name, WWN_SIZE); - memcpy(vha->port_name, icb->port_name, WWN_SIZE); - - icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); - - ha->retry_count = nv->retry_count; - - /* Set minimum login_timeout to 4 seconds. */ - if (nv->login_timeout != ql2xlogintimeout) - nv->login_timeout = ql2xlogintimeout; - if (nv->login_timeout < 4) - nv->login_timeout = 4; - ha->login_timeout = nv->login_timeout; - icb->login_timeout = nv->login_timeout; - - /* Set minimum RATOV to 100 tenths of a second. */ - ha->r_a_tov = 100; - - ha->loop_reset_delay = nv->reset_delay; - - /* Link Down Timeout = 0: - * - * When Port Down timer expires we will start returning - * I/O's to OS with "DID_NO_CONNECT". - * - * Link Down Timeout != 0: - * - * The driver waits for the link to come up after link down - * before returning I/Os to OS with "DID_NO_CONNECT". - */ - if (nv->link_down_timeout == 0) { - ha->loop_down_abort_time = - (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT); - } else { - ha->link_down_timeout = nv->link_down_timeout; - ha->loop_down_abort_time = - (LOOP_DOWN_TIME - ha->link_down_timeout); - } - - /* - * Need enough time to try and get the port back. - */ - ha->port_down_retry_count = nv->port_down_retry_count; - if (qlport_down_retry) - ha->port_down_retry_count = qlport_down_retry; - /* Set login_retry_count */ - ha->login_retry_count = nv->retry_count; - if (ha->port_down_retry_count == nv->port_down_retry_count && - ha->port_down_retry_count > 3) - ha->login_retry_count = ha->port_down_retry_count; - else if (ha->port_down_retry_count > (int)ha->login_retry_count) - ha->login_retry_count = ha->port_down_retry_count; - if (ql2xloginretrycount) - ha->login_retry_count = ql2xloginretrycount; - - icb->lun_enables = __constant_cpu_to_le16(0); - icb->command_resource_count = 0; - icb->immediate_notify_resource_count = 0; - icb->timeout = __constant_cpu_to_le16(0); - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - /* Enable RIO */ - icb->firmware_options[0] &= ~BIT_3; - icb->add_firmware_options[0] &= - ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); - icb->add_firmware_options[0] |= BIT_2; - icb->response_accumulation_timer = 3; - icb->interrupt_delay_timer = 5; - - vha->flags.process_response_queue = 1; - } else { - /* Enable ZIO. */ - if (!vha->flags.init_done) { - ha->zio_mode = icb->add_firmware_options[0] & - (BIT_3 | BIT_2 | BIT_1 | BIT_0); - ha->zio_timer = icb->interrupt_delay_timer ? - icb->interrupt_delay_timer: 2; - } - icb->add_firmware_options[0] &= - ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); - vha->flags.process_response_queue = 0; - if (ha->zio_mode != QLA_ZIO_DISABLED) { - ha->zio_mode = QLA_ZIO_MODE_6; - - ql_log(ql_log_info, vha, 0x0068, - "ZIO mode %d enabled; timer delay (%d us).\n", - ha->zio_mode, ha->zio_timer * 100); - - icb->add_firmware_options[0] |= (uint8_t)ha->zio_mode; - icb->interrupt_delay_timer = (uint8_t)ha->zio_timer; - vha->flags.process_response_queue = 1; - } - } - - if (rval) { - ql_log(ql_log_warn, vha, 0x0069, - "NVRAM configuration failed.\n"); - } - return (rval); -} - -static void -qla2x00_rport_del(void *data) -{ - fc_port_t *fcport = data; - struct fc_rport *rport; - unsigned long flags; - - spin_lock_irqsave(fcport->vha->host->host_lock, flags); - rport = fcport->drport ? fcport->drport: fcport->rport; - fcport->drport = NULL; - spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); - if (rport) - fc_remote_port_delete(rport); -} - -/** - * qla2x00_alloc_fcport() - Allocate a generic fcport. - * @ha: HA context - * @flags: allocation flags - * - * Returns a pointer to the allocated fcport, or NULL, if none available. - */ -fc_port_t * -qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) -{ - fc_port_t *fcport; - - fcport = kzalloc(sizeof(fc_port_t), flags); - if (!fcport) - return NULL; - - /* Setup fcport template structure. */ - fcport->vha = vha; - fcport->vp_idx = vha->vp_idx; - fcport->port_type = FCT_UNKNOWN; - fcport->loop_id = FC_NO_LOOP_ID; - qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED); - fcport->supported_classes = FC_COS_UNSPECIFIED; - - return fcport; -} - -/* - * qla2x00_configure_loop - * Updates Fibre Channel Device Database with what is actually on loop. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success. - * 1 = error. - * 2 = database was full and device was not configured. - */ -static int -qla2x00_configure_loop(scsi_qla_host_t *vha) -{ - int rval; - unsigned long flags, save_flags; - struct qla_hw_data *ha = vha->hw; - rval = QLA_SUCCESS; - - /* Get Initiator ID */ - if (test_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags)) { - rval = qla2x00_configure_hba(vha); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x2013, - "Unable to configure HBA.\n"); - return (rval); - } - } - - save_flags = flags = vha->dpc_flags; - ql_dbg(ql_dbg_disc, vha, 0x2014, - "Configure loop -- dpc flags = 0x%lx.\n", flags); - - /* - * If we have both an RSCN and PORT UPDATE pending then handle them - * both at the same time. - */ - clear_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - clear_bit(RSCN_UPDATE, &vha->dpc_flags); - - qla2x00_get_data_rate(vha); - - /* Determine what we need to do */ - if (ha->current_topology == ISP_CFG_FL && - (test_bit(LOCAL_LOOP_UPDATE, &flags))) { - - set_bit(RSCN_UPDATE, &flags); - - } else if (ha->current_topology == ISP_CFG_F && - (test_bit(LOCAL_LOOP_UPDATE, &flags))) { - - set_bit(RSCN_UPDATE, &flags); - clear_bit(LOCAL_LOOP_UPDATE, &flags); - - } else if (ha->current_topology == ISP_CFG_N) { - clear_bit(RSCN_UPDATE, &flags); - - } else if (!vha->flags.online || - (test_bit(ABORT_ISP_ACTIVE, &flags))) { - - set_bit(RSCN_UPDATE, &flags); - set_bit(LOCAL_LOOP_UPDATE, &flags); - } - - if (test_bit(LOCAL_LOOP_UPDATE, &flags)) { - if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { - ql_dbg(ql_dbg_disc, vha, 0x2015, - "Loop resync needed, failing.\n"); - rval = QLA_FUNCTION_FAILED; - } else - rval = qla2x00_configure_local_loop(vha); - } - - if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) { - if (LOOP_TRANSITION(vha)) { - ql_dbg(ql_dbg_disc, vha, 0x201e, - "Needs RSCN update and loop transition.\n"); - rval = QLA_FUNCTION_FAILED; - } - else - rval = qla2x00_configure_fabric(vha); - } - - if (rval == QLA_SUCCESS) { - if (atomic_read(&vha->loop_down_timer) || - test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { - rval = QLA_FUNCTION_FAILED; - } else { - atomic_set(&vha->loop_state, LOOP_READY); - ql_dbg(ql_dbg_disc, vha, 0x2069, - "LOOP READY.\n"); - } - } - - if (rval) { - ql_dbg(ql_dbg_disc, vha, 0x206a, - "%s *** FAILED ***.\n", __func__); - } else { - ql_dbg(ql_dbg_disc, vha, 0x206b, - "%s: exiting normally.\n", __func__); - } - - /* Restore state if a resync event occurred during processing */ - if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { - if (test_bit(LOCAL_LOOP_UPDATE, &save_flags)) - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - if (test_bit(RSCN_UPDATE, &save_flags)) { - set_bit(RSCN_UPDATE, &vha->dpc_flags); - } - } - - return (rval); -} - - - -/* - * qla2x00_configure_local_loop - * Updates Fibre Channel Device Database with local loop devices. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success. - */ -static int -qla2x00_configure_local_loop(scsi_qla_host_t *vha) -{ - int rval, rval2; - int found_devs; - int found; - fc_port_t *fcport, *new_fcport; - - uint16_t index; - uint16_t entries; - char *id_iter; - uint16_t loop_id; - uint8_t domain, area, al_pa; - struct qla_hw_data *ha = vha->hw; - - found_devs = 0; - new_fcport = NULL; - entries = MAX_FIBRE_DEVICES_LOOP; - - ql_dbg(ql_dbg_disc, vha, 0x2016, - "Getting FCAL position map.\n"); - if (ql2xextended_error_logging & ql_dbg_disc) - qla2x00_get_fcal_position_map(vha, NULL); - - /* Get list of logged in devices. */ - memset(ha->gid_list, 0, qla2x00_gid_list_size(ha)); - rval = qla2x00_get_id_list(vha, ha->gid_list, ha->gid_list_dma, - &entries); - if (rval != QLA_SUCCESS) - goto cleanup_allocation; - - ql_dbg(ql_dbg_disc, vha, 0x2017, - "Entries in ID list (%d).\n", entries); - ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2075, - (uint8_t *)ha->gid_list, - entries * sizeof(struct gid_list_info)); - - /* Allocate temporary fcport for any new fcports discovered. */ - new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); - if (new_fcport == NULL) { - ql_log(ql_log_warn, vha, 0x2018, - "Memory allocation failed for fcport.\n"); - rval = QLA_MEMORY_ALLOC_FAILED; - goto cleanup_allocation; - } - new_fcport->flags &= ~FCF_FABRIC_DEVICE; - - /* - * Mark local devices that were present with FCF_DEVICE_LOST for now. - */ - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (atomic_read(&fcport->state) == FCS_ONLINE && - fcport->port_type != FCT_BROADCAST && - (fcport->flags & FCF_FABRIC_DEVICE) == 0) { - - ql_dbg(ql_dbg_disc, vha, 0x2019, - "Marking port lost loop_id=0x%04x.\n", - fcport->loop_id); - - qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); - } - } - - /* Add devices to port list. */ - id_iter = (char *)ha->gid_list; - for (index = 0; index < entries; index++) { - domain = ((struct gid_list_info *)id_iter)->domain; - area = ((struct gid_list_info *)id_iter)->area; - al_pa = ((struct gid_list_info *)id_iter)->al_pa; - if (IS_QLA2100(ha) || IS_QLA2200(ha)) - loop_id = (uint16_t) - ((struct gid_list_info *)id_iter)->loop_id_2100; - else - loop_id = le16_to_cpu( - ((struct gid_list_info *)id_iter)->loop_id); - id_iter += ha->gid_list_info_size; - - /* Bypass reserved domain fields. */ - if ((domain & 0xf0) == 0xf0) - continue; - - /* Bypass if not same domain and area of adapter. */ - if (area && domain && - (area != vha->d_id.b.area || domain != vha->d_id.b.domain)) - continue; - - /* Bypass invalid local loop ID. */ - if (loop_id > LAST_LOCAL_LOOP_ID) - continue; - - /* Fill in member data. */ - new_fcport->d_id.b.domain = domain; - new_fcport->d_id.b.area = area; - new_fcport->d_id.b.al_pa = al_pa; - new_fcport->loop_id = loop_id; - new_fcport->vp_idx = vha->vp_idx; - rval2 = qla2x00_get_port_database(vha, new_fcport, 0); - if (rval2 != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x201a, - "Failed to retrieve fcport information " - "-- get_port_database=%x, loop_id=0x%04x.\n", - rval2, new_fcport->loop_id); - ql_dbg(ql_dbg_disc, vha, 0x201b, - "Scheduling resync.\n"); - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - continue; - } - - /* Check for matching device in port list. */ - found = 0; - fcport = NULL; - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (memcmp(new_fcport->port_name, fcport->port_name, - WWN_SIZE)) - continue; - - fcport->flags &= ~FCF_FABRIC_DEVICE; - fcport->loop_id = new_fcport->loop_id; - fcport->port_type = new_fcport->port_type; - fcport->d_id.b24 = new_fcport->d_id.b24; - memcpy(fcport->node_name, new_fcport->node_name, - WWN_SIZE); - - found++; - break; - } - - if (!found) { - /* New device, add to fcports list. */ - if (vha->vp_idx) { - new_fcport->vha = vha; - new_fcport->vp_idx = vha->vp_idx; - } - list_add_tail(&new_fcport->list, &vha->vp_fcports); - - /* Allocate a new replacement fcport. */ - fcport = new_fcport; - new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); - if (new_fcport == NULL) { - ql_log(ql_log_warn, vha, 0x201c, - "Failed to allocate memory for fcport.\n"); - rval = QLA_MEMORY_ALLOC_FAILED; - goto cleanup_allocation; - } - new_fcport->flags &= ~FCF_FABRIC_DEVICE; - } - - /* Base iIDMA settings on HBA port speed. */ - fcport->fp_speed = ha->link_data_rate; - - qla2x00_update_fcport(vha, fcport); - - found_devs++; - } - -cleanup_allocation: - kfree(new_fcport); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x201d, - "Configure local loop error exit: rval=%x.\n", rval); - } - - return (rval); -} - -static void -qla2x00_iidma_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) -{ -#define LS_UNKNOWN 2 - static char *link_speeds[] = { "1", "2", "?", "4", "8", "10" }; - char *link_speed; - int rval; - uint16_t mb[4]; - struct qla_hw_data *ha = vha->hw; - - if (!IS_IIDMA_CAPABLE(ha)) - return; - - if (atomic_read(&fcport->state) != FCS_ONLINE) - return; - - if (fcport->fp_speed == PORT_SPEED_UNKNOWN || - fcport->fp_speed > ha->link_data_rate) - return; - - rval = qla2x00_set_idma_speed(vha, fcport->loop_id, fcport->fp_speed, - mb); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x2004, - "Unable to adjust iIDMA " - "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x " - "%04x.\n", fcport->port_name[0], fcport->port_name[1], - fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7], rval, - fcport->fp_speed, mb[0], mb[1]); - } else { - link_speed = link_speeds[LS_UNKNOWN]; - if (fcport->fp_speed < 5) - link_speed = link_speeds[fcport->fp_speed]; - else if (fcport->fp_speed == 0x13) - link_speed = link_speeds[5]; - ql_dbg(ql_dbg_disc, vha, 0x2005, - "iIDMA adjusted to %s GB/s " - "on %02x%02x%02x%02x%02x%02x%02x%02x.\n", link_speed, - fcport->port_name[0], fcport->port_name[1], - fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7]); - } -} - -static void -qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - struct fc_rport_identifiers rport_ids; - struct fc_rport *rport; - unsigned long flags; - - qla2x00_rport_del(fcport); - - rport_ids.node_name = wwn_to_u64(fcport->node_name); - rport_ids.port_name = wwn_to_u64(fcport->port_name); - rport_ids.port_id = fcport->d_id.b.domain << 16 | - fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa; - rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; - fcport->rport = rport = fc_remote_port_add(vha->host, 0, &rport_ids); - if (!rport) { - ql_log(ql_log_warn, vha, 0x2006, - "Unable to allocate fc remote port.\n"); - return; - } - spin_lock_irqsave(fcport->vha->host->host_lock, flags); - *((fc_port_t **)rport->dd_data) = fcport; - spin_unlock_irqrestore(fcport->vha->host->host_lock, flags); - - rport->supported_classes = fcport->supported_classes; - - rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; - if (fcport->port_type == FCT_INITIATOR) - rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; - if (fcport->port_type == FCT_TARGET) - rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; - fc_remote_port_rolechg(rport, rport_ids.roles); -} - -/* - * qla2x00_update_fcport - * Updates device on list. - * - * Input: - * ha = adapter block pointer. - * fcport = port structure pointer. - * - * Return: - * 0 - Success - * BIT_0 - error - * - * Context: - * Kernel context. - */ -void -qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - fcport->vha = vha; - fcport->login_retry = 0; - fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); - - qla2x00_iidma_fcport(vha, fcport); - qla24xx_update_fcport_fcp_prio(vha, fcport); - qla2x00_reg_remote_port(vha, fcport); - qla2x00_set_fcport_state(fcport, FCS_ONLINE); -} - -/* - * qla2x00_configure_fabric - * Setup SNS devices with loop ID's. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success. - * BIT_0 = error - */ -static int -qla2x00_configure_fabric(scsi_qla_host_t *vha) -{ - int rval; - fc_port_t *fcport, *fcptemp; - uint16_t next_loopid; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t loop_id; - LIST_HEAD(new_fcports); - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - /* If FL port exists, then SNS is present */ - if (IS_FWI2_CAPABLE(ha)) - loop_id = NPH_F_PORT; - else - loop_id = SNS_FL_PORT; - rval = qla2x00_get_port_name(vha, loop_id, vha->fabric_node_name, 1); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_disc, vha, 0x201f, - "MBX_GET_PORT_NAME failed, No FL Port.\n"); - - vha->device_flags &= ~SWITCH_FOUND; - return (QLA_SUCCESS); - } - vha->device_flags |= SWITCH_FOUND; - - do { - /* FDMI support. */ - if (ql2xfdmienable && - test_and_clear_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags)) - qla2x00_fdmi_register(vha); - - /* Ensure we are logged into the SNS. */ - if (IS_FWI2_CAPABLE(ha)) - loop_id = NPH_SNS; - else - loop_id = SIMPLE_NAME_SERVER; - rval = ha->isp_ops->fabric_login(vha, loop_id, 0xff, 0xff, - 0xfc, mb, BIT_1|BIT_0); - if (rval != QLA_SUCCESS) { - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - return rval; - } - if (mb[0] != MBS_COMMAND_COMPLETE) { - ql_dbg(ql_dbg_disc, vha, 0x2042, - "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x " - "mb[6]=%x mb[7]=%x.\n", loop_id, mb[0], mb[1], - mb[2], mb[6], mb[7]); - return (QLA_SUCCESS); - } - - if (test_and_clear_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags)) { - if (qla2x00_rft_id(vha)) { - /* EMPTY */ - ql_dbg(ql_dbg_disc, vha, 0x2045, - "Register FC-4 TYPE failed.\n"); - } - if (qla2x00_rff_id(vha)) { - /* EMPTY */ - ql_dbg(ql_dbg_disc, vha, 0x2049, - "Register FC-4 Features failed.\n"); - } - if (qla2x00_rnn_id(vha)) { - /* EMPTY */ - ql_dbg(ql_dbg_disc, vha, 0x204f, - "Register Node Name failed.\n"); - } else if (qla2x00_rsnn_nn(vha)) { - /* EMPTY */ - ql_dbg(ql_dbg_disc, vha, 0x2053, - "Register Symobilic Node Name failed.\n"); - } - } - -#define QLA_FCPORT_SCAN 1 -#define QLA_FCPORT_FOUND 2 - - list_for_each_entry(fcport, &vha->vp_fcports, list) { - fcport->scan_state = QLA_FCPORT_SCAN; - } - - rval = qla2x00_find_all_fabric_devs(vha, &new_fcports); - if (rval != QLA_SUCCESS) - break; - - /* - * Logout all previous fabric devices marked lost, except - * FCP2 devices. - */ - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) - break; - - if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) - continue; - - if (fcport->scan_state == QLA_FCPORT_SCAN && - atomic_read(&fcport->state) == FCS_ONLINE) { - qla2x00_mark_device_lost(vha, fcport, - ql2xplogiabsentdevice, 0); - if (fcport->loop_id != FC_NO_LOOP_ID && - (fcport->flags & FCF_FCP2_DEVICE) == 0 && - fcport->port_type != FCT_INITIATOR && - fcport->port_type != FCT_BROADCAST) { - ha->isp_ops->fabric_logout(vha, - fcport->loop_id, - fcport->d_id.b.domain, - fcport->d_id.b.area, - fcport->d_id.b.al_pa); - fcport->loop_id = FC_NO_LOOP_ID; - } - } - } - - /* Starting free loop ID. */ - next_loopid = ha->min_external_loopid; - - /* - * Scan through our port list and login entries that need to be - * logged in. - */ - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (atomic_read(&vha->loop_down_timer) || - test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) - break; - - if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 || - (fcport->flags & FCF_LOGIN_NEEDED) == 0) - continue; - - if (fcport->loop_id == FC_NO_LOOP_ID) { - fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id( - base_vha, fcport); - if (rval != QLA_SUCCESS) { - /* Ran out of IDs to use */ - break; - } - } - /* Login and update database */ - qla2x00_fabric_dev_login(vha, fcport, &next_loopid); - } - - /* Exit if out of loop IDs. */ - if (rval != QLA_SUCCESS) { - break; - } - - /* - * Login and add the new devices to our port list. - */ - list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) { - if (atomic_read(&vha->loop_down_timer) || - test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) - break; - - /* Find a new loop ID to use. */ - fcport->loop_id = next_loopid; - rval = qla2x00_find_new_loop_id(base_vha, fcport); - if (rval != QLA_SUCCESS) { - /* Ran out of IDs to use */ - break; - } - - /* Login and update database */ - qla2x00_fabric_dev_login(vha, fcport, &next_loopid); - - if (vha->vp_idx) { - fcport->vha = vha; - fcport->vp_idx = vha->vp_idx; - } - list_move_tail(&fcport->list, &vha->vp_fcports); - } - } while (0); - - /* Free all new device structures not processed. */ - list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) { - list_del(&fcport->list); - kfree(fcport); - } - - if (rval) { - ql_dbg(ql_dbg_disc, vha, 0x2068, - "Configure fabric error exit rval=%d.\n", rval); - } - - return (rval); -} - -/* - * qla2x00_find_all_fabric_devs - * - * Input: - * ha = adapter block pointer. - * dev = database device entry pointer. - * - * Returns: - * 0 = success. - * - * Context: - * Kernel context. - */ -static int -qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha, - struct list_head *new_fcports) -{ - int rval; - uint16_t loop_id; - fc_port_t *fcport, *new_fcport, *fcptemp; - int found; - - sw_info_t *swl; - int swl_idx; - int first_dev, last_dev; - port_id_t wrap = {}, nxt_d_id; - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *vp, *base_vha = pci_get_drvdata(ha->pdev); - struct scsi_qla_host *tvp; - - rval = QLA_SUCCESS; - - /* Try GID_PT to get device list, else GAN. */ - if (!ha->swl) - ha->swl = kcalloc(ha->max_fibre_devices, sizeof(sw_info_t), - GFP_KERNEL); - swl = ha->swl; - if (!swl) { - /*EMPTY*/ - ql_dbg(ql_dbg_disc, vha, 0x2054, - "GID_PT allocations failed, fallback on GA_NXT.\n"); - } else { - memset(swl, 0, ha->max_fibre_devices * sizeof(sw_info_t)); - if (qla2x00_gid_pt(vha, swl) != QLA_SUCCESS) { - swl = NULL; - } else if (qla2x00_gpn_id(vha, swl) != QLA_SUCCESS) { - swl = NULL; - } else if (qla2x00_gnn_id(vha, swl) != QLA_SUCCESS) { - swl = NULL; - } else if (ql2xiidmaenable && - qla2x00_gfpn_id(vha, swl) == QLA_SUCCESS) { - qla2x00_gpsc(vha, swl); - } - - /* If other queries succeeded probe for FC-4 type */ - if (swl) - qla2x00_gff_id(vha, swl); - } - swl_idx = 0; - - /* Allocate temporary fcport for any new fcports discovered. */ - new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); - if (new_fcport == NULL) { - ql_log(ql_log_warn, vha, 0x205e, - "Failed to allocate memory for fcport.\n"); - return (QLA_MEMORY_ALLOC_FAILED); - } - new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); - /* Set start port ID scan at adapter ID. */ - first_dev = 1; - last_dev = 0; - - /* Starting free loop ID. */ - loop_id = ha->min_external_loopid; - for (; loop_id <= ha->max_loop_id; loop_id++) { - if (qla2x00_is_reserved_id(vha, loop_id)) - continue; - - if (ha->current_topology == ISP_CFG_FL && - (atomic_read(&vha->loop_down_timer) || - LOOP_TRANSITION(vha))) { - atomic_set(&vha->loop_down_timer, 0); - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - break; - } - - if (swl != NULL) { - if (last_dev) { - wrap.b24 = new_fcport->d_id.b24; - } else { - new_fcport->d_id.b24 = swl[swl_idx].d_id.b24; - memcpy(new_fcport->node_name, - swl[swl_idx].node_name, WWN_SIZE); - memcpy(new_fcport->port_name, - swl[swl_idx].port_name, WWN_SIZE); - memcpy(new_fcport->fabric_port_name, - swl[swl_idx].fabric_port_name, WWN_SIZE); - new_fcport->fp_speed = swl[swl_idx].fp_speed; - new_fcport->fc4_type = swl[swl_idx].fc4_type; - - if (swl[swl_idx].d_id.b.rsvd_1 != 0) { - last_dev = 1; - } - swl_idx++; - } - } else { - /* Send GA_NXT to the switch */ - rval = qla2x00_ga_nxt(vha, new_fcport); - if (rval != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x2064, - "SNS scan failed -- assuming " - "zero-entry result.\n"); - list_for_each_entry_safe(fcport, fcptemp, - new_fcports, list) { - list_del(&fcport->list); - kfree(fcport); - } - rval = QLA_SUCCESS; - break; - } - } - - /* If wrap on switch device list, exit. */ - if (first_dev) { - wrap.b24 = new_fcport->d_id.b24; - first_dev = 0; - } else if (new_fcport->d_id.b24 == wrap.b24) { - ql_dbg(ql_dbg_disc, vha, 0x2065, - "Device wrap (%02x%02x%02x).\n", - new_fcport->d_id.b.domain, - new_fcport->d_id.b.area, - new_fcport->d_id.b.al_pa); - break; - } - - /* Bypass if same physical adapter. */ - if (new_fcport->d_id.b24 == base_vha->d_id.b24) - continue; - - /* Bypass virtual ports of the same host. */ - found = 0; - if (ha->num_vhosts) { - unsigned long flags; - - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { - if (new_fcport->d_id.b24 == vp->d_id.b24) { - found = 1; - break; - } - } - spin_unlock_irqrestore(&ha->vport_slock, flags); - - if (found) - continue; - } - - /* Bypass if same domain and area of adapter. */ - if (((new_fcport->d_id.b24 & 0xffff00) == - (vha->d_id.b24 & 0xffff00)) && ha->current_topology == - ISP_CFG_FL) - continue; - - /* Bypass reserved domain fields. */ - if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0) - continue; - - /* Bypass ports whose FCP-4 type is not FCP_SCSI */ - if (ql2xgffidenable && - (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI && - new_fcport->fc4_type != FC4_TYPE_UNKNOWN)) - continue; - - /* Locate matching device in database. */ - found = 0; - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (memcmp(new_fcport->port_name, fcport->port_name, - WWN_SIZE)) - continue; - - fcport->scan_state = QLA_FCPORT_FOUND; - - found++; - - /* Update port state. */ - memcpy(fcport->fabric_port_name, - new_fcport->fabric_port_name, WWN_SIZE); - fcport->fp_speed = new_fcport->fp_speed; - - /* - * If address the same and state FCS_ONLINE, nothing - * changed. - */ - if (fcport->d_id.b24 == new_fcport->d_id.b24 && - atomic_read(&fcport->state) == FCS_ONLINE) { - break; - } - - /* - * If device was not a fabric device before. - */ - if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) { - fcport->d_id.b24 = new_fcport->d_id.b24; - fcport->loop_id = FC_NO_LOOP_ID; - fcport->flags |= (FCF_FABRIC_DEVICE | - FCF_LOGIN_NEEDED); - break; - } - - /* - * Port ID changed or device was marked to be updated; - * Log it out if still logged in and mark it for - * relogin later. - */ - fcport->d_id.b24 = new_fcport->d_id.b24; - fcport->flags |= FCF_LOGIN_NEEDED; - if (fcport->loop_id != FC_NO_LOOP_ID && - (fcport->flags & FCF_FCP2_DEVICE) == 0 && - (fcport->flags & FCF_ASYNC_SENT) == 0 && - fcport->port_type != FCT_INITIATOR && - fcport->port_type != FCT_BROADCAST) { - ha->isp_ops->fabric_logout(vha, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - fcport->loop_id = FC_NO_LOOP_ID; - } - - break; - } - - if (found) - continue; - /* If device was not in our fcports list, then add it. */ - list_add_tail(&new_fcport->list, new_fcports); - - /* Allocate a new replacement fcport. */ - nxt_d_id.b24 = new_fcport->d_id.b24; - new_fcport = qla2x00_alloc_fcport(vha, GFP_KERNEL); - if (new_fcport == NULL) { - ql_log(ql_log_warn, vha, 0x2066, - "Memory allocation failed for fcport.\n"); - return (QLA_MEMORY_ALLOC_FAILED); - } - new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED); - new_fcport->d_id.b24 = nxt_d_id.b24; - } - - kfree(new_fcport); - - return (rval); -} - -/* - * qla2x00_find_new_loop_id - * Scan through our port list and find a new usable loop ID. - * - * Input: - * ha: adapter state pointer. - * dev: port structure pointer. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) -{ - int rval; - int found; - fc_port_t *fcport; - uint16_t first_loop_id; - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *vp; - struct scsi_qla_host *tvp; - unsigned long flags = 0; - - rval = QLA_SUCCESS; - - /* Save starting loop ID. */ - first_loop_id = dev->loop_id; - - for (;;) { - /* Skip loop ID if already used by adapter. */ - if (dev->loop_id == vha->loop_id) - dev->loop_id++; - - /* Skip reserved loop IDs. */ - while (qla2x00_is_reserved_id(vha, dev->loop_id)) - dev->loop_id++; - - /* Reset loop ID if passed the end. */ - if (dev->loop_id > ha->max_loop_id) { - /* first loop ID. */ - dev->loop_id = ha->min_external_loopid; - } - - /* Check for loop ID being already in use. */ - found = 0; - fcport = NULL; - - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry_safe(vp, tvp, &ha->vp_list, list) { - list_for_each_entry(fcport, &vp->vp_fcports, list) { - if (fcport->loop_id == dev->loop_id && - fcport != dev) { - /* ID possibly in use */ - found++; - break; - } - } - if (found) - break; - } - spin_unlock_irqrestore(&ha->vport_slock, flags); - - /* If not in use then it is free to use. */ - if (!found) { - ql_dbg(ql_dbg_disc, dev->vha, 0x2086, - "Assigning new loopid=%x, portid=%x.\n", - dev->loop_id, dev->d_id.b24); - break; - } - - /* ID in use. Try next value. */ - dev->loop_id++; - - /* If wrap around. No free ID to use. */ - if (dev->loop_id == first_loop_id) { - dev->loop_id = FC_NO_LOOP_ID; - rval = QLA_FUNCTION_FAILED; - break; - } - } - - return (rval); -} - -/* - * qla2x00_fabric_dev_login - * Login fabric target device and update FC port database. - * - * Input: - * ha: adapter state pointer. - * fcport: port structure list pointer. - * next_loopid: contains value of a new loop ID that can be used - * by the next login attempt. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -static int -qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport, - uint16_t *next_loopid) -{ - int rval; - int retry; - uint8_t opts; - struct qla_hw_data *ha = vha->hw; - - rval = QLA_SUCCESS; - retry = 0; - - if (IS_ALOGIO_CAPABLE(ha)) { - if (fcport->flags & FCF_ASYNC_SENT) - return rval; - fcport->flags |= FCF_ASYNC_SENT; - rval = qla2x00_post_async_login_work(vha, fcport, NULL); - if (!rval) - return rval; - } - - fcport->flags &= ~FCF_ASYNC_SENT; - rval = qla2x00_fabric_login(vha, fcport, next_loopid); - if (rval == QLA_SUCCESS) { - /* Send an ADISC to FCP2 devices.*/ - opts = 0; - if (fcport->flags & FCF_FCP2_DEVICE) - opts |= BIT_1; - rval = qla2x00_get_port_database(vha, fcport, opts); - if (rval != QLA_SUCCESS) { - ha->isp_ops->fabric_logout(vha, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - qla2x00_mark_device_lost(vha, fcport, 1, 0); - } else { - qla2x00_update_fcport(vha, fcport); - } - } else { - /* Retry Login. */ - qla2x00_mark_device_lost(vha, fcport, 1, 0); - } - - return (rval); -} - -/* - * qla2x00_fabric_login - * Issue fabric login command. - * - * Input: - * ha = adapter block pointer. - * device = pointer to FC device type structure. - * - * Returns: - * 0 - Login successfully - * 1 - Login failed - * 2 - Initiator device - * 3 - Fatal error - */ -int -qla2x00_fabric_login(scsi_qla_host_t *vha, fc_port_t *fcport, - uint16_t *next_loopid) -{ - int rval; - int retry; - uint16_t tmp_loopid; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - struct qla_hw_data *ha = vha->hw; - - retry = 0; - tmp_loopid = 0; - - for (;;) { - ql_dbg(ql_dbg_disc, vha, 0x2000, - "Trying Fabric Login w/loop id 0x%04x for port " - "%02x%02x%02x.\n", - fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - - /* Login fcport on switch. */ - rval = ha->isp_ops->fabric_login(vha, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, mb, BIT_0); - if (rval != QLA_SUCCESS) { - return rval; - } - if (mb[0] == MBS_PORT_ID_USED) { - /* - * Device has another loop ID. The firmware team - * recommends the driver perform an implicit login with - * the specified ID again. The ID we just used is save - * here so we return with an ID that can be tried by - * the next login. - */ - retry++; - tmp_loopid = fcport->loop_id; - fcport->loop_id = mb[1]; - - ql_dbg(ql_dbg_disc, vha, 0x2001, - "Fabric Login: port in use - next loop " - "id=0x%04x, port id= %02x%02x%02x.\n", - fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - - } else if (mb[0] == MBS_COMMAND_COMPLETE) { - /* - * Login succeeded. - */ - if (retry) { - /* A retry occurred before. */ - *next_loopid = tmp_loopid; - } else { - /* - * No retry occurred before. Just increment the - * ID value for next login. - */ - *next_loopid = (fcport->loop_id + 1); - } - - if (mb[1] & BIT_0) { - fcport->port_type = FCT_INITIATOR; - } else { - fcport->port_type = FCT_TARGET; - if (mb[1] & BIT_1) { - fcport->flags |= FCF_FCP2_DEVICE; - } - } - - if (mb[10] & BIT_0) - fcport->supported_classes |= FC_COS_CLASS2; - if (mb[10] & BIT_1) - fcport->supported_classes |= FC_COS_CLASS3; - - rval = QLA_SUCCESS; - break; - } else if (mb[0] == MBS_LOOP_ID_USED) { - /* - * Loop ID already used, try next loop ID. - */ - fcport->loop_id++; - rval = qla2x00_find_new_loop_id(vha, fcport); - if (rval != QLA_SUCCESS) { - /* Ran out of loop IDs to use */ - break; - } - } else if (mb[0] == MBS_COMMAND_ERROR) { - /* - * Firmware possibly timed out during login. If NO - * retries are left to do then the device is declared - * dead. - */ - *next_loopid = fcport->loop_id; - ha->isp_ops->fabric_logout(vha, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - qla2x00_mark_device_lost(vha, fcport, 1, 0); - - rval = 1; - break; - } else { - /* - * unrecoverable / not handled error - */ - ql_dbg(ql_dbg_disc, vha, 0x2002, - "Failed=%x port_id=%02x%02x%02x loop_id=%x " - "jiffies=%lx.\n", mb[0], fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, - fcport->loop_id, jiffies); - - *next_loopid = fcport->loop_id; - ha->isp_ops->fabric_logout(vha, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - fcport->loop_id = FC_NO_LOOP_ID; - fcport->login_retry = 0; - - rval = 3; - break; - } - } - - return (rval); -} - -/* - * qla2x00_local_device_login - * Issue local device login command. - * - * Input: - * ha = adapter block pointer. - * loop_id = loop id of device to login to. - * - * Returns (Where's the #define!!!!): - * 0 - Login successfully - * 1 - Login failed - * 3 - Fatal error - */ -int -qla2x00_local_device_login(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - int rval; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - - memset(mb, 0, sizeof(mb)); - rval = qla2x00_login_local_device(vha, fcport, mb, BIT_0); - if (rval == QLA_SUCCESS) { - /* Interrogate mailbox registers for any errors */ - if (mb[0] == MBS_COMMAND_ERROR) - rval = 1; - else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR) - /* device not in PCB table */ - rval = 3; - } - - return (rval); -} - -/* - * qla2x00_loop_resync - * Resync with fibre channel devices. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success - */ -int -qla2x00_loop_resync(scsi_qla_host_t *vha) -{ - int rval = QLA_SUCCESS; - uint32_t wait_time; - struct req_que *req; - struct rsp_que *rsp; - - if (vha->hw->flags.cpu_affinity_enabled) - req = vha->hw->req_q_map[0]; - else - req = vha->req; - rsp = req->rsp; - - clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); - if (vha->flags.online) { - if (!(rval = qla2x00_fw_ready(vha))) { - /* Wait at most MAX_TARGET RSCNs for a stable link. */ - wait_time = 256; - do { - /* Issue a marker after FW becomes ready. */ - qla2x00_marker(vha, req, rsp, 0, 0, - MK_SYNC_ALL); - vha->marker_needed = 0; - - /* Remap devices on Loop. */ - clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - - qla2x00_configure_loop(vha); - wait_time--; - } while (!atomic_read(&vha->loop_down_timer) && - !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) - && wait_time && (test_bit(LOOP_RESYNC_NEEDED, - &vha->dpc_flags))); - } - } - - if (test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) - return (QLA_FUNCTION_FAILED); - - if (rval) - ql_dbg(ql_dbg_disc, vha, 0x206c, - "%s *** FAILED ***.\n", __func__); - - return (rval); -} - -/* -* qla2x00_perform_loop_resync -* Description: This function will set the appropriate flags and call -* qla2x00_loop_resync. If successful loop will be resynced -* Arguments : scsi_qla_host_t pointer -* returm : Success or Failure -*/ - -int qla2x00_perform_loop_resync(scsi_qla_host_t *ha) -{ - int32_t rval = 0; - - if (!test_and_set_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags)) { - /*Configure the flags so that resync happens properly*/ - atomic_set(&ha->loop_down_timer, 0); - if (!(ha->device_flags & DFLG_NO_CABLE)) { - atomic_set(&ha->loop_state, LOOP_UP); - set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags); - set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags); - set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags); - - rval = qla2x00_loop_resync(ha); - } else - atomic_set(&ha->loop_state, LOOP_DEAD); - - clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags); - } - - return rval; -} - -void -qla2x00_update_fcports(scsi_qla_host_t *base_vha) -{ - fc_port_t *fcport; - struct scsi_qla_host *vha; - struct qla_hw_data *ha = base_vha->hw; - unsigned long flags; - - spin_lock_irqsave(&ha->vport_slock, flags); - /* Go with deferred removal of rport references. */ - list_for_each_entry(vha, &base_vha->hw->vp_list, list) { - atomic_inc(&vha->vref_count); - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (fcport->drport && - atomic_read(&fcport->state) != FCS_UNCONFIGURED) { - spin_unlock_irqrestore(&ha->vport_slock, flags); - - qla2x00_rport_del(fcport); - - spin_lock_irqsave(&ha->vport_slock, flags); - } - } - atomic_dec(&vha->vref_count); - } - spin_unlock_irqrestore(&ha->vport_slock, flags); -} - -/* -* qla82xx_quiescent_state_cleanup -* Description: This function will block the new I/Os -* Its not aborting any I/Os as context -* is not destroyed during quiescence -* Arguments: scsi_qla_host_t -* return : void -*/ -void -qla82xx_quiescent_state_cleanup(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *vp; - - ql_dbg(ql_dbg_p3p, vha, 0xb002, - "Performing ISP error recovery - ha=%p.\n", ha); - - atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME); - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - qla2x00_mark_all_devices_lost(vha, 0); - list_for_each_entry(vp, &ha->vp_list, list) - qla2x00_mark_all_devices_lost(vha, 0); - } else { - if (!atomic_read(&vha->loop_down_timer)) - atomic_set(&vha->loop_down_timer, - LOOP_DOWN_TIME); - } - /* Wait for pending cmds to complete */ - qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST); -} - -void -qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *vp; - unsigned long flags; - fc_port_t *fcport; - - /* For ISP82XX, driver waits for completion of the commands. - * online flag should be set. - */ - if (!IS_QLA82XX(ha)) - vha->flags.online = 0; - ha->flags.chip_reset_done = 0; - clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - ha->qla_stats.total_isp_aborts++; - - ql_log(ql_log_info, vha, 0x00af, - "Performing ISP error recovery - ha=%p.\n", ha); - - /* For ISP82XX, reset_chip is just disabling interrupts. - * Driver waits for the completion of the commands. - * the interrupts need to be enabled. - */ - if (!IS_QLA82XX(ha)) - ha->isp_ops->reset_chip(vha); - - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - qla2x00_mark_all_devices_lost(vha, 0); - - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vp, &ha->vp_list, list) { - atomic_inc(&vp->vref_count); - spin_unlock_irqrestore(&ha->vport_slock, flags); - - qla2x00_mark_all_devices_lost(vp, 0); - - spin_lock_irqsave(&ha->vport_slock, flags); - atomic_dec(&vp->vref_count); - } - spin_unlock_irqrestore(&ha->vport_slock, flags); - } else { - if (!atomic_read(&vha->loop_down_timer)) - atomic_set(&vha->loop_down_timer, - LOOP_DOWN_TIME); - } - - /* Clear all async request states across all VPs. */ - list_for_each_entry(fcport, &vha->vp_fcports, list) - fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vp, &ha->vp_list, list) { - atomic_inc(&vp->vref_count); - spin_unlock_irqrestore(&ha->vport_slock, flags); - - list_for_each_entry(fcport, &vp->vp_fcports, list) - fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); - - spin_lock_irqsave(&ha->vport_slock, flags); - atomic_dec(&vp->vref_count); - } - spin_unlock_irqrestore(&ha->vport_slock, flags); - - if (!ha->flags.eeh_busy) { - /* Make sure for ISP 82XX IO DMA is complete */ - if (IS_QLA82XX(ha)) { - qla82xx_chip_reset_cleanup(vha); - ql_log(ql_log_info, vha, 0x00b4, - "Done chip reset cleanup.\n"); - - /* Done waiting for pending commands. - * Reset the online flag. - */ - vha->flags.online = 0; - } - - /* Requeue all commands in outstanding command list. */ - qla2x00_abort_all_cmds(vha, DID_RESET << 16); - } -} - -/* -* qla2x00_abort_isp -* Resets ISP and aborts all outstanding commands. -* -* Input: -* ha = adapter block pointer. -* -* Returns: -* 0 = success -*/ -int -qla2x00_abort_isp(scsi_qla_host_t *vha) -{ - int rval; - uint8_t status = 0; - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *vp; - struct req_que *req = ha->req_q_map[0]; - unsigned long flags; - - if (vha->flags.online) { - qla2x00_abort_isp_cleanup(vha); - - if (unlikely(pci_channel_offline(ha->pdev) && - ha->flags.pci_channel_io_perm_failure)) { - clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); - status = 0; - return status; - } - - ha->isp_ops->get_flash_version(vha, req->ring); - - ha->isp_ops->nvram_config(vha); - - if (!qla2x00_restart_isp(vha)) { - clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - - if (!atomic_read(&vha->loop_down_timer)) { - /* - * Issue marker command only when we are going - * to start the I/O . - */ - vha->marker_needed = 1; - } - - vha->flags.online = 1; - - ha->isp_ops->enable_intrs(ha); - - ha->isp_abort_cnt = 0; - clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); - - if (IS_QLA81XX(ha) || IS_QLA8031(ha)) - qla2x00_get_fw_version(vha); - if (ha->fce) { - ha->flags.fce_enabled = 1; - memset(ha->fce, 0, - fce_calc_size(ha->fce_bufs)); - rval = qla2x00_enable_fce_trace(vha, - ha->fce_dma, ha->fce_bufs, ha->fce_mb, - &ha->fce_bufs); - if (rval) { - ql_log(ql_log_warn, vha, 0x8033, - "Unable to reinitialize FCE " - "(%d).\n", rval); - ha->flags.fce_enabled = 0; - } - } - - if (ha->eft) { - memset(ha->eft, 0, EFT_SIZE); - rval = qla2x00_enable_eft_trace(vha, - ha->eft_dma, EFT_NUM_BUFFERS); - if (rval) { - ql_log(ql_log_warn, vha, 0x8034, - "Unable to reinitialize EFT " - "(%d).\n", rval); - } - } - } else { /* failed the ISP abort */ - vha->flags.online = 1; - if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - if (ha->isp_abort_cnt == 0) { - ql_log(ql_log_fatal, vha, 0x8035, - "ISP error recover failed - " - "board disabled.\n"); - /* - * The next call disables the board - * completely. - */ - ha->isp_ops->reset_adapter(vha); - vha->flags.online = 0; - clear_bit(ISP_ABORT_RETRY, - &vha->dpc_flags); - status = 0; - } else { /* schedule another ISP abort */ - ha->isp_abort_cnt--; - ql_dbg(ql_dbg_taskm, vha, 0x8020, - "ISP abort - retry remaining %d.\n", - ha->isp_abort_cnt); - status = 1; - } - } else { - ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT; - ql_dbg(ql_dbg_taskm, vha, 0x8021, - "ISP error recovery - retrying (%d) " - "more times.\n", ha->isp_abort_cnt); - set_bit(ISP_ABORT_RETRY, &vha->dpc_flags); - status = 1; - } - } - - } - - if (!status) { - ql_dbg(ql_dbg_taskm, vha, 0x8022, "%s succeeded.\n", __func__); - - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vp, &ha->vp_list, list) { - if (vp->vp_idx) { - atomic_inc(&vp->vref_count); - spin_unlock_irqrestore(&ha->vport_slock, flags); - - qla2x00_vp_abort_isp(vp); - - spin_lock_irqsave(&ha->vport_slock, flags); - atomic_dec(&vp->vref_count); - } - } - spin_unlock_irqrestore(&ha->vport_slock, flags); - - } else { - ql_log(ql_log_warn, vha, 0x8023, "%s **** FAILED ****.\n", - __func__); - } - - return(status); -} - -/* -* qla2x00_restart_isp -* restarts the ISP after a reset -* -* Input: -* ha = adapter block pointer. -* -* Returns: -* 0 = success -*/ -static int -qla2x00_restart_isp(scsi_qla_host_t *vha) -{ - int status = 0; - uint32_t wait_time; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; - - /* If firmware needs to be loaded */ - if (qla2x00_isp_firmware(vha)) { - vha->flags.online = 0; - status = ha->isp_ops->chip_diag(vha); - if (!status) - status = qla2x00_setup_chip(vha); - } - - if (!status && !(status = qla2x00_init_rings(vha))) { - clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - ha->flags.chip_reset_done = 1; - /* Initialize the queues in use */ - qla25xx_init_queues(ha); - - status = qla2x00_fw_ready(vha); - if (!status) { - ql_dbg(ql_dbg_taskm, vha, 0x8031, - "Start configure loop status = %d.\n", status); - - /* Issue a marker after FW becomes ready. */ - qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); - - vha->flags.online = 1; - /* Wait at most MAX_TARGET RSCNs for a stable link. */ - wait_time = 256; - do { - clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - qla2x00_configure_loop(vha); - wait_time--; - } while (!atomic_read(&vha->loop_down_timer) && - !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) - && wait_time && (test_bit(LOOP_RESYNC_NEEDED, - &vha->dpc_flags))); - } - - /* if no cable then assume it's good */ - if ((vha->device_flags & DFLG_NO_CABLE)) - status = 0; - - ql_dbg(ql_dbg_taskm, vha, 0x8032, - "Configure loop done, status = 0x%x.\n", status); - } - return (status); -} - -static int -qla25xx_init_queues(struct qla_hw_data *ha) -{ - struct rsp_que *rsp = NULL; - struct req_que *req = NULL; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - int ret = -1; - int i; - - for (i = 1; i < ha->max_rsp_queues; i++) { - rsp = ha->rsp_q_map[i]; - if (rsp) { - rsp->options &= ~BIT_0; - ret = qla25xx_init_rsp_que(base_vha, rsp); - if (ret != QLA_SUCCESS) - ql_dbg(ql_dbg_init, base_vha, 0x00ff, - "%s Rsp que: %d init failed.\n", - __func__, rsp->id); - else - ql_dbg(ql_dbg_init, base_vha, 0x0100, - "%s Rsp que: %d inited.\n", - __func__, rsp->id); - } - } - for (i = 1; i < ha->max_req_queues; i++) { - req = ha->req_q_map[i]; - if (req) { - /* Clear outstanding commands array. */ - req->options &= ~BIT_0; - ret = qla25xx_init_req_que(base_vha, req); - if (ret != QLA_SUCCESS) - ql_dbg(ql_dbg_init, base_vha, 0x0101, - "%s Req que: %d init failed.\n", - __func__, req->id); - else - ql_dbg(ql_dbg_init, base_vha, 0x0102, - "%s Req que: %d inited.\n", - __func__, req->id); - } - } - return ret; -} - -/* -* qla2x00_reset_adapter -* Reset adapter. -* -* Input: -* ha = adapter block pointer. -*/ -void -qla2x00_reset_adapter(scsi_qla_host_t *vha) -{ - unsigned long flags = 0; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - vha->flags.online = 0; - ha->isp_ops->disable_intrs(ha); - - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); - RD_REG_WORD(®->hccr); /* PCI Posting. */ - WRT_REG_WORD(®->hccr, HCCR_RELEASE_RISC); - RD_REG_WORD(®->hccr); /* PCI Posting. */ - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void -qla24xx_reset_adapter(scsi_qla_host_t *vha) -{ - unsigned long flags = 0; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - if (IS_QLA82XX(ha)) - return; - - vha->flags.online = 0; - ha->isp_ops->disable_intrs(ha); - - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_RESET); - RD_REG_DWORD(®->hccr); - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (IS_NOPOLLING_TYPE(ha)) - ha->isp_ops->enable_intrs(ha); -} - -/* On sparc systems, obtain port and node WWN from firmware - * properties. - */ -static void qla24xx_nvram_wwn_from_ofw(scsi_qla_host_t *vha, - struct nvram_24xx *nv) -{ -#ifdef CONFIG_SPARC - struct qla_hw_data *ha = vha->hw; - struct pci_dev *pdev = ha->pdev; - struct device_node *dp = pci_device_to_OF_node(pdev); - const u8 *val; - int len; - - val = of_get_property(dp, "port-wwn", &len); - if (val && len >= WWN_SIZE) - memcpy(nv->port_name, val, WWN_SIZE); - - val = of_get_property(dp, "node-wwn", &len); - if (val && len >= WWN_SIZE) - memcpy(nv->node_name, val, WWN_SIZE); -#endif -} - -int -qla24xx_nvram_config(scsi_qla_host_t *vha) -{ - int rval; - struct init_cb_24xx *icb; - struct nvram_24xx *nv; - uint32_t *dptr; - uint8_t *dptr1, *dptr2; - uint32_t chksum; - uint16_t cnt; - struct qla_hw_data *ha = vha->hw; - - rval = QLA_SUCCESS; - icb = (struct init_cb_24xx *)ha->init_cb; - nv = ha->nvram; - - /* Determine NVRAM starting address. */ - if (ha->flags.port0) { - ha->nvram_base = FA_NVRAM_FUNC0_ADDR; - ha->vpd_base = FA_NVRAM_VPD0_ADDR; - } else { - ha->nvram_base = FA_NVRAM_FUNC1_ADDR; - ha->vpd_base = FA_NVRAM_VPD1_ADDR; - } - ha->nvram_size = sizeof(struct nvram_24xx); - ha->vpd_size = FA_NVRAM_VPD_SIZE; - if (IS_QLA82XX(ha)) - ha->vpd_size = FA_VPD_SIZE_82XX; - - /* Get VPD data into cache */ - ha->vpd = ha->nvram + VPD_OFFSET; - ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, - ha->nvram_base - FA_NVRAM_FUNC0_ADDR, FA_NVRAM_VPD_SIZE * 4); - - /* Get NVRAM data into cache and calculate checksum. */ - dptr = (uint32_t *)nv; - ha->isp_ops->read_nvram(vha, (uint8_t *)dptr, ha->nvram_base, - ha->nvram_size); - for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) - chksum += le32_to_cpu(*dptr++); - - ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x006a, - "Contents of NVRAM\n"); - ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010d, - (uint8_t *)nv, ha->nvram_size); - - /* Bad NVRAM data, set defaults parameters. */ - if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' - || nv->id[3] != ' ' || - nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { - /* Reset NVRAM data. */ - ql_log(ql_log_warn, vha, 0x006b, - "Inconisistent NVRAM detected: checksum=0x%x id=%c " - "version=0x%x.\n", chksum, nv->id[0], nv->nvram_version); - ql_log(ql_log_warn, vha, 0x006c, - "Falling back to functioning (yet invalid -- WWPN) " - "defaults.\n"); - - /* - * Set default initialization control block. - */ - memset(nv, 0, ha->nvram_size); - nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); - nv->version = __constant_cpu_to_le16(ICB_VERSION); - nv->frame_payload_size = __constant_cpu_to_le16(2048); - nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); - nv->exchange_count = __constant_cpu_to_le16(0); - nv->hard_address = __constant_cpu_to_le16(124); - nv->port_name[0] = 0x21; - nv->port_name[1] = 0x00 + ha->port_no; - nv->port_name[2] = 0x00; - nv->port_name[3] = 0xe0; - nv->port_name[4] = 0x8b; - nv->port_name[5] = 0x1c; - nv->port_name[6] = 0x55; - nv->port_name[7] = 0x86; - nv->node_name[0] = 0x20; - nv->node_name[1] = 0x00; - nv->node_name[2] = 0x00; - nv->node_name[3] = 0xe0; - nv->node_name[4] = 0x8b; - nv->node_name[5] = 0x1c; - nv->node_name[6] = 0x55; - nv->node_name[7] = 0x86; - qla24xx_nvram_wwn_from_ofw(vha, nv); - nv->login_retry_count = __constant_cpu_to_le16(8); - nv->interrupt_delay_timer = __constant_cpu_to_le16(0); - nv->login_timeout = __constant_cpu_to_le16(0); - nv->firmware_options_1 = - __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); - nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); - nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); - nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); - nv->efi_parameters = __constant_cpu_to_le32(0); - nv->reset_delay = 5; - nv->max_luns_per_target = __constant_cpu_to_le16(128); - nv->port_down_retry_count = __constant_cpu_to_le16(30); - nv->link_down_timeout = __constant_cpu_to_le16(30); - - rval = 1; - } - - /* Reset Initialization control block */ - memset(icb, 0, ha->init_cb_size); - - /* Copy 1st segment. */ - dptr1 = (uint8_t *)icb; - dptr2 = (uint8_t *)&nv->version; - cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version; - while (cnt--) - *dptr1++ = *dptr2++; - - icb->login_retry_count = nv->login_retry_count; - icb->link_down_on_nos = nv->link_down_on_nos; - - /* Copy 2nd segment. */ - dptr1 = (uint8_t *)&icb->interrupt_delay_timer; - dptr2 = (uint8_t *)&nv->interrupt_delay_timer; - cnt = (uint8_t *)&icb->reserved_3 - - (uint8_t *)&icb->interrupt_delay_timer; - while (cnt--) - *dptr1++ = *dptr2++; - - /* - * Setup driver NVRAM options. - */ - qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name), - "QLA2462"); - - /* Use alternate WWN? */ - if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { - memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); - memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE); - } - - /* Prepare nodename */ - if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) { - /* - * Firmware will apply the following mask if the nodename was - * not provided. - */ - memcpy(icb->node_name, icb->port_name, WWN_SIZE); - icb->node_name[0] &= 0xF0; - } - - /* Set host adapter parameters. */ - ha->flags.disable_risc_code_load = 0; - ha->flags.enable_lip_reset = 0; - ha->flags.enable_lip_full_login = - le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0; - ha->flags.enable_target_reset = - le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0; - ha->flags.enable_led_scheme = 0; - ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; - - ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & - (BIT_6 | BIT_5 | BIT_4)) >> 4; - - memcpy(ha->fw_seriallink_options24, nv->seriallink_options, - sizeof(ha->fw_seriallink_options24)); - - /* save HBA serial number */ - ha->serial0 = icb->port_name[5]; - ha->serial1 = icb->port_name[6]; - ha->serial2 = icb->port_name[7]; - memcpy(vha->node_name, icb->node_name, WWN_SIZE); - memcpy(vha->port_name, icb->port_name, WWN_SIZE); - - icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); - - ha->retry_count = le16_to_cpu(nv->login_retry_count); - - /* Set minimum login_timeout to 4 seconds. */ - if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout) - nv->login_timeout = cpu_to_le16(ql2xlogintimeout); - if (le16_to_cpu(nv->login_timeout) < 4) - nv->login_timeout = __constant_cpu_to_le16(4); - ha->login_timeout = le16_to_cpu(nv->login_timeout); - icb->login_timeout = nv->login_timeout; - - /* Set minimum RATOV to 100 tenths of a second. */ - ha->r_a_tov = 100; - - ha->loop_reset_delay = nv->reset_delay; - - /* Link Down Timeout = 0: - * - * When Port Down timer expires we will start returning - * I/O's to OS with "DID_NO_CONNECT". - * - * Link Down Timeout != 0: - * - * The driver waits for the link to come up after link down - * before returning I/Os to OS with "DID_NO_CONNECT". - */ - if (le16_to_cpu(nv->link_down_timeout) == 0) { - ha->loop_down_abort_time = - (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT); - } else { - ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout); - ha->loop_down_abort_time = - (LOOP_DOWN_TIME - ha->link_down_timeout); - } - - /* Need enough time to try and get the port back. */ - ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count); - if (qlport_down_retry) - ha->port_down_retry_count = qlport_down_retry; - - /* Set login_retry_count */ - ha->login_retry_count = le16_to_cpu(nv->login_retry_count); - if (ha->port_down_retry_count == - le16_to_cpu(nv->port_down_retry_count) && - ha->port_down_retry_count > 3) - ha->login_retry_count = ha->port_down_retry_count; - else if (ha->port_down_retry_count > (int)ha->login_retry_count) - ha->login_retry_count = ha->port_down_retry_count; - if (ql2xloginretrycount) - ha->login_retry_count = ql2xloginretrycount; - - /* Enable ZIO. */ - if (!vha->flags.init_done) { - ha->zio_mode = le32_to_cpu(icb->firmware_options_2) & - (BIT_3 | BIT_2 | BIT_1 | BIT_0); - ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ? - le16_to_cpu(icb->interrupt_delay_timer): 2; - } - icb->firmware_options_2 &= __constant_cpu_to_le32( - ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); - vha->flags.process_response_queue = 0; - if (ha->zio_mode != QLA_ZIO_DISABLED) { - ha->zio_mode = QLA_ZIO_MODE_6; - - ql_log(ql_log_info, vha, 0x006f, - "ZIO mode %d enabled; timer delay (%d us).\n", - ha->zio_mode, ha->zio_timer * 100); - - icb->firmware_options_2 |= cpu_to_le32( - (uint32_t)ha->zio_mode); - icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer); - vha->flags.process_response_queue = 1; - } - - if (rval) { - ql_log(ql_log_warn, vha, 0x0070, - "NVRAM configuration failed.\n"); - } - return (rval); -} - -static int -qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr, - uint32_t faddr) -{ - int rval = QLA_SUCCESS; - int segments, fragment; - uint32_t *dcode, dlen; - uint32_t risc_addr; - uint32_t risc_size; - uint32_t i; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - ql_dbg(ql_dbg_init, vha, 0x008b, - "FW: Loading firmware from flash (%x).\n", faddr); - - rval = QLA_SUCCESS; - - segments = FA_RISC_CODE_SEGMENTS; - dcode = (uint32_t *)req->ring; - *srisc_addr = 0; - - /* Validate firmware image by checking version. */ - qla24xx_read_flash_data(vha, dcode, faddr + 4, 4); - for (i = 0; i < 4; i++) - dcode[i] = be32_to_cpu(dcode[i]); - if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && - dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || - (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && - dcode[3] == 0)) { - ql_log(ql_log_fatal, vha, 0x008c, - "Unable to verify the integrity of flash firmware " - "image.\n"); - ql_log(ql_log_fatal, vha, 0x008d, - "Firmware data: %08x %08x %08x %08x.\n", - dcode[0], dcode[1], dcode[2], dcode[3]); - - return QLA_FUNCTION_FAILED; - } - - while (segments && rval == QLA_SUCCESS) { - /* Read segment's load information. */ - qla24xx_read_flash_data(vha, dcode, faddr, 4); - - risc_addr = be32_to_cpu(dcode[2]); - *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr; - risc_size = be32_to_cpu(dcode[3]); - - fragment = 0; - while (risc_size > 0 && rval == QLA_SUCCESS) { - dlen = (uint32_t)(ha->fw_transfer_size >> 2); - if (dlen > risc_size) - dlen = risc_size; - - ql_dbg(ql_dbg_init, vha, 0x008e, - "Loading risc segment@ risc addr %x " - "number of dwords 0x%x offset 0x%x.\n", - risc_addr, dlen, faddr); - - qla24xx_read_flash_data(vha, dcode, faddr, dlen); - for (i = 0; i < dlen; i++) - dcode[i] = swab32(dcode[i]); - - rval = qla2x00_load_ram(vha, req->dma, risc_addr, - dlen); - if (rval) { - ql_log(ql_log_fatal, vha, 0x008f, - "Failed to load segment %d of firmware.\n", - fragment); - break; - } - - faddr += dlen; - risc_addr += dlen; - risc_size -= dlen; - fragment++; - } - - /* Next segment. */ - segments--; - } - - return rval; -} - -#define QLA_FW_URL "ftp://ftp.qlogic.com/outgoing/linux/firmware/" - -int -qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) -{ - int rval; - int i, fragment; - uint16_t *wcode, *fwcode; - uint32_t risc_addr, risc_size, fwclen, wlen, *seg; - struct fw_blob *blob; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - /* Load firmware blob. */ - blob = qla2x00_request_firmware(vha); - if (!blob) { - ql_log(ql_log_info, vha, 0x0083, - "Fimware image unavailable.\n"); - ql_log(ql_log_info, vha, 0x0084, - "Firmware images can be retrieved from: "QLA_FW_URL ".\n"); - return QLA_FUNCTION_FAILED; - } - - rval = QLA_SUCCESS; - - wcode = (uint16_t *)req->ring; - *srisc_addr = 0; - fwcode = (uint16_t *)blob->fw->data; - fwclen = 0; - - /* Validate firmware image by checking version. */ - if (blob->fw->size < 8 * sizeof(uint16_t)) { - ql_log(ql_log_fatal, vha, 0x0085, - "Unable to verify integrity of firmware image (%Zd).\n", - blob->fw->size); - goto fail_fw_integrity; - } - for (i = 0; i < 4; i++) - wcode[i] = be16_to_cpu(fwcode[i + 4]); - if ((wcode[0] == 0xffff && wcode[1] == 0xffff && wcode[2] == 0xffff && - wcode[3] == 0xffff) || (wcode[0] == 0 && wcode[1] == 0 && - wcode[2] == 0 && wcode[3] == 0)) { - ql_log(ql_log_fatal, vha, 0x0086, - "Unable to verify integrity of firmware image.\n"); - ql_log(ql_log_fatal, vha, 0x0087, - "Firmware data: %04x %04x %04x %04x.\n", - wcode[0], wcode[1], wcode[2], wcode[3]); - goto fail_fw_integrity; - } - - seg = blob->segs; - while (*seg && rval == QLA_SUCCESS) { - risc_addr = *seg; - *srisc_addr = *srisc_addr == 0 ? *seg : *srisc_addr; - risc_size = be16_to_cpu(fwcode[3]); - - /* Validate firmware image size. */ - fwclen += risc_size * sizeof(uint16_t); - if (blob->fw->size < fwclen) { - ql_log(ql_log_fatal, vha, 0x0088, - "Unable to verify integrity of firmware image " - "(%Zd).\n", blob->fw->size); - goto fail_fw_integrity; - } - - fragment = 0; - while (risc_size > 0 && rval == QLA_SUCCESS) { - wlen = (uint16_t)(ha->fw_transfer_size >> 1); - if (wlen > risc_size) - wlen = risc_size; - ql_dbg(ql_dbg_init, vha, 0x0089, - "Loading risc segment@ risc addr %x number of " - "words 0x%x.\n", risc_addr, wlen); - - for (i = 0; i < wlen; i++) - wcode[i] = swab16(fwcode[i]); - - rval = qla2x00_load_ram(vha, req->dma, risc_addr, - wlen); - if (rval) { - ql_log(ql_log_fatal, vha, 0x008a, - "Failed to load segment %d of firmware.\n", - fragment); - break; - } - - fwcode += wlen; - risc_addr += wlen; - risc_size -= wlen; - fragment++; - } - - /* Next segment. */ - seg++; - } - return rval; - -fail_fw_integrity: - return QLA_FUNCTION_FAILED; -} - -static int -qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr) -{ - int rval; - int segments, fragment; - uint32_t *dcode, dlen; - uint32_t risc_addr; - uint32_t risc_size; - uint32_t i; - struct fw_blob *blob; - uint32_t *fwcode, fwclen; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - /* Load firmware blob. */ - blob = qla2x00_request_firmware(vha); - if (!blob) { - ql_log(ql_log_warn, vha, 0x0090, - "Fimware image unavailable.\n"); - ql_log(ql_log_warn, vha, 0x0091, - "Firmware images can be retrieved from: " - QLA_FW_URL ".\n"); - - return QLA_FUNCTION_FAILED; - } - - ql_dbg(ql_dbg_init, vha, 0x0092, - "FW: Loading via request-firmware.\n"); - - rval = QLA_SUCCESS; - - segments = FA_RISC_CODE_SEGMENTS; - dcode = (uint32_t *)req->ring; - *srisc_addr = 0; - fwcode = (uint32_t *)blob->fw->data; - fwclen = 0; - - /* Validate firmware image by checking version. */ - if (blob->fw->size < 8 * sizeof(uint32_t)) { - ql_log(ql_log_fatal, vha, 0x0093, - "Unable to verify integrity of firmware image (%Zd).\n", - blob->fw->size); - goto fail_fw_integrity; - } - for (i = 0; i < 4; i++) - dcode[i] = be32_to_cpu(fwcode[i + 4]); - if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && - dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || - (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && - dcode[3] == 0)) { - ql_log(ql_log_fatal, vha, 0x0094, - "Unable to verify integrity of firmware image (%Zd).\n", - blob->fw->size); - ql_log(ql_log_fatal, vha, 0x0095, - "Firmware data: %08x %08x %08x %08x.\n", - dcode[0], dcode[1], dcode[2], dcode[3]); - goto fail_fw_integrity; - } - - while (segments && rval == QLA_SUCCESS) { - risc_addr = be32_to_cpu(fwcode[2]); - *srisc_addr = *srisc_addr == 0 ? risc_addr : *srisc_addr; - risc_size = be32_to_cpu(fwcode[3]); - - /* Validate firmware image size. */ - fwclen += risc_size * sizeof(uint32_t); - if (blob->fw->size < fwclen) { - ql_log(ql_log_fatal, vha, 0x0096, - "Unable to verify integrity of firmware image " - "(%Zd).\n", blob->fw->size); - - goto fail_fw_integrity; - } - - fragment = 0; - while (risc_size > 0 && rval == QLA_SUCCESS) { - dlen = (uint32_t)(ha->fw_transfer_size >> 2); - if (dlen > risc_size) - dlen = risc_size; - - ql_dbg(ql_dbg_init, vha, 0x0097, - "Loading risc segment@ risc addr %x " - "number of dwords 0x%x.\n", risc_addr, dlen); - - for (i = 0; i < dlen; i++) - dcode[i] = swab32(fwcode[i]); - - rval = qla2x00_load_ram(vha, req->dma, risc_addr, - dlen); - if (rval) { - ql_log(ql_log_fatal, vha, 0x0098, - "Failed to load segment %d of firmware.\n", - fragment); - break; - } - - fwcode += dlen; - risc_addr += dlen; - risc_size -= dlen; - fragment++; - } - - /* Next segment. */ - segments--; - } - return rval; - -fail_fw_integrity: - return QLA_FUNCTION_FAILED; -} - -int -qla24xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) -{ - int rval; - - if (ql2xfwloadbin == 1) - return qla81xx_load_risc(vha, srisc_addr); - - /* - * FW Load priority: - * 1) Firmware via request-firmware interface (.bin file). - * 2) Firmware residing in flash. - */ - rval = qla24xx_load_risc_blob(vha, srisc_addr); - if (rval == QLA_SUCCESS) - return rval; - - return qla24xx_load_risc_flash(vha, srisc_addr, - vha->hw->flt_region_fw); -} - -int -qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - - if (ql2xfwloadbin == 2) - goto try_blob_fw; - - /* - * FW Load priority: - * 1) Firmware residing in flash. - * 2) Firmware via request-firmware interface (.bin file). - * 3) Golden-Firmware residing in flash -- limited operation. - */ - rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_fw); - if (rval == QLA_SUCCESS) - return rval; - -try_blob_fw: - rval = qla24xx_load_risc_blob(vha, srisc_addr); - if (rval == QLA_SUCCESS || !ha->flt_region_gold_fw) - return rval; - - ql_log(ql_log_info, vha, 0x0099, - "Attempting to fallback to golden firmware.\n"); - rval = qla24xx_load_risc_flash(vha, srisc_addr, ha->flt_region_gold_fw); - if (rval != QLA_SUCCESS) - return rval; - - ql_log(ql_log_info, vha, 0x009a, "Update operational firmware.\n"); - ha->flags.running_gold_fw = 1; - return rval; -} - -void -qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha) -{ - int ret, retries; - struct qla_hw_data *ha = vha->hw; - - if (ha->flags.pci_channel_io_perm_failure) - return; - if (!IS_FWI2_CAPABLE(ha)) - return; - if (!ha->fw_major_version) - return; - - ret = qla2x00_stop_firmware(vha); - for (retries = 5; ret != QLA_SUCCESS && ret != QLA_FUNCTION_TIMEOUT && - ret != QLA_INVALID_COMMAND && retries ; retries--) { - ha->isp_ops->reset_chip(vha); - if (ha->isp_ops->chip_diag(vha) != QLA_SUCCESS) - continue; - if (qla2x00_setup_chip(vha) != QLA_SUCCESS) - continue; - ql_log(ql_log_info, vha, 0x8015, - "Attempting retry of stop-firmware command.\n"); - ret = qla2x00_stop_firmware(vha); - } -} - -int -qla24xx_configure_vhba(scsi_qla_host_t *vha) -{ - int rval = QLA_SUCCESS; - int rval2; - uint16_t mb[MAILBOX_REGISTER_COUNT]; - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - struct req_que *req; - struct rsp_que *rsp; - - if (!vha->vp_idx) - return -EINVAL; - - rval = qla2x00_fw_ready(base_vha); - if (ha->flags.cpu_affinity_enabled) - req = ha->req_q_map[0]; - else - req = vha->req; - rsp = req->rsp; - - if (rval == QLA_SUCCESS) { - clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); - } - - vha->flags.management_server_logged_in = 0; - - /* Login to SNS first */ - rval2 = ha->isp_ops->fabric_login(vha, NPH_SNS, 0xff, 0xff, 0xfc, mb, - BIT_1); - if (rval2 != QLA_SUCCESS || mb[0] != MBS_COMMAND_COMPLETE) { - if (rval2 == QLA_MEMORY_ALLOC_FAILED) - ql_dbg(ql_dbg_init, vha, 0x0120, - "Failed SNS login: loop_id=%x, rval2=%d\n", - NPH_SNS, rval2); - else - ql_dbg(ql_dbg_init, vha, 0x0103, - "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x " - "mb[2]=%x mb[6]=%x mb[7]=%x.\n", - NPH_SNS, mb[0], mb[1], mb[2], mb[6], mb[7]); - return (QLA_FUNCTION_FAILED); - } - - atomic_set(&vha->loop_down_timer, 0); - atomic_set(&vha->loop_state, LOOP_UP); - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - rval = qla2x00_loop_resync(base_vha); - - return rval; -} - -/* 84XX Support **************************************************************/ - -static LIST_HEAD(qla_cs84xx_list); -static DEFINE_MUTEX(qla_cs84xx_mutex); - -static struct qla_chip_state_84xx * -qla84xx_get_chip(struct scsi_qla_host *vha) -{ - struct qla_chip_state_84xx *cs84xx; - struct qla_hw_data *ha = vha->hw; - - mutex_lock(&qla_cs84xx_mutex); - - /* Find any shared 84xx chip. */ - list_for_each_entry(cs84xx, &qla_cs84xx_list, list) { - if (cs84xx->bus == ha->pdev->bus) { - kref_get(&cs84xx->kref); - goto done; - } - } - - cs84xx = kzalloc(sizeof(*cs84xx), GFP_KERNEL); - if (!cs84xx) - goto done; - - kref_init(&cs84xx->kref); - spin_lock_init(&cs84xx->access_lock); - mutex_init(&cs84xx->fw_update_mutex); - cs84xx->bus = ha->pdev->bus; - - list_add_tail(&cs84xx->list, &qla_cs84xx_list); -done: - mutex_unlock(&qla_cs84xx_mutex); - return cs84xx; -} - -static void -__qla84xx_chip_release(struct kref *kref) -{ - struct qla_chip_state_84xx *cs84xx = - container_of(kref, struct qla_chip_state_84xx, kref); - - mutex_lock(&qla_cs84xx_mutex); - list_del(&cs84xx->list); - mutex_unlock(&qla_cs84xx_mutex); - kfree(cs84xx); -} - -void -qla84xx_put_chip(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - if (ha->cs84xx) - kref_put(&ha->cs84xx->kref, __qla84xx_chip_release); -} - -static int -qla84xx_init_chip(scsi_qla_host_t *vha) -{ - int rval; - uint16_t status[2]; - struct qla_hw_data *ha = vha->hw; - - mutex_lock(&ha->cs84xx->fw_update_mutex); - - rval = qla84xx_verify_chip(vha, status); - - mutex_unlock(&ha->cs84xx->fw_update_mutex); - - return rval != QLA_SUCCESS || status[0] ? QLA_FUNCTION_FAILED: - QLA_SUCCESS; -} - -/* 81XX Support **************************************************************/ - -int -qla81xx_nvram_config(scsi_qla_host_t *vha) -{ - int rval; - struct init_cb_81xx *icb; - struct nvram_81xx *nv; - uint32_t *dptr; - uint8_t *dptr1, *dptr2; - uint32_t chksum; - uint16_t cnt; - struct qla_hw_data *ha = vha->hw; - - rval = QLA_SUCCESS; - icb = (struct init_cb_81xx *)ha->init_cb; - nv = ha->nvram; - - /* Determine NVRAM starting address. */ - ha->nvram_size = sizeof(struct nvram_81xx); - ha->vpd_size = FA_NVRAM_VPD_SIZE; - - /* Get VPD data into cache */ - ha->vpd = ha->nvram + VPD_OFFSET; - ha->isp_ops->read_optrom(vha, ha->vpd, ha->flt_region_vpd << 2, - ha->vpd_size); - - /* Get NVRAM data into cache and calculate checksum. */ - ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, - ha->nvram_size); - dptr = (uint32_t *)nv; - for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++) - chksum += le32_to_cpu(*dptr++); - - ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111, - "Contents of NVRAM:\n"); - ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112, - (uint8_t *)nv, ha->nvram_size); - - /* Bad NVRAM data, set defaults parameters. */ - if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' - || nv->id[3] != ' ' || - nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { - /* Reset NVRAM data. */ - ql_log(ql_log_info, vha, 0x0073, - "Inconisistent NVRAM detected: checksum=0x%x id=%c " - "version=0x%x.\n", chksum, nv->id[0], - le16_to_cpu(nv->nvram_version)); - ql_log(ql_log_info, vha, 0x0074, - "Falling back to functioning (yet invalid -- WWPN) " - "defaults.\n"); - - /* - * Set default initialization control block. - */ - memset(nv, 0, ha->nvram_size); - nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); - nv->version = __constant_cpu_to_le16(ICB_VERSION); - nv->frame_payload_size = __constant_cpu_to_le16(2048); - nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); - nv->exchange_count = __constant_cpu_to_le16(0); - nv->port_name[0] = 0x21; - nv->port_name[1] = 0x00 + ha->port_no; - nv->port_name[2] = 0x00; - nv->port_name[3] = 0xe0; - nv->port_name[4] = 0x8b; - nv->port_name[5] = 0x1c; - nv->port_name[6] = 0x55; - nv->port_name[7] = 0x86; - nv->node_name[0] = 0x20; - nv->node_name[1] = 0x00; - nv->node_name[2] = 0x00; - nv->node_name[3] = 0xe0; - nv->node_name[4] = 0x8b; - nv->node_name[5] = 0x1c; - nv->node_name[6] = 0x55; - nv->node_name[7] = 0x86; - nv->login_retry_count = __constant_cpu_to_le16(8); - nv->interrupt_delay_timer = __constant_cpu_to_le16(0); - nv->login_timeout = __constant_cpu_to_le16(0); - nv->firmware_options_1 = - __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); - nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); - nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); - nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); - nv->efi_parameters = __constant_cpu_to_le32(0); - nv->reset_delay = 5; - nv->max_luns_per_target = __constant_cpu_to_le16(128); - nv->port_down_retry_count = __constant_cpu_to_le16(30); - nv->link_down_timeout = __constant_cpu_to_le16(180); - nv->enode_mac[0] = 0x00; - nv->enode_mac[1] = 0xC0; - nv->enode_mac[2] = 0xDD; - nv->enode_mac[3] = 0x04; - nv->enode_mac[4] = 0x05; - nv->enode_mac[5] = 0x06 + ha->port_no; - - rval = 1; - } - - /* Reset Initialization control block */ - memset(icb, 0, ha->init_cb_size); - - /* Copy 1st segment. */ - dptr1 = (uint8_t *)icb; - dptr2 = (uint8_t *)&nv->version; - cnt = (uint8_t *)&icb->response_q_inpointer - (uint8_t *)&icb->version; - while (cnt--) - *dptr1++ = *dptr2++; - - icb->login_retry_count = nv->login_retry_count; - - /* Copy 2nd segment. */ - dptr1 = (uint8_t *)&icb->interrupt_delay_timer; - dptr2 = (uint8_t *)&nv->interrupt_delay_timer; - cnt = (uint8_t *)&icb->reserved_5 - - (uint8_t *)&icb->interrupt_delay_timer; - while (cnt--) - *dptr1++ = *dptr2++; - - memcpy(icb->enode_mac, nv->enode_mac, sizeof(icb->enode_mac)); - /* Some boards (with valid NVRAMs) still have NULL enode_mac!! */ - if (!memcmp(icb->enode_mac, "\0\0\0\0\0\0", sizeof(icb->enode_mac))) { - icb->enode_mac[0] = 0x00; - icb->enode_mac[1] = 0xC0; - icb->enode_mac[2] = 0xDD; - icb->enode_mac[3] = 0x04; - icb->enode_mac[4] = 0x05; - icb->enode_mac[5] = 0x06 + ha->port_no; - } - - /* Use extended-initialization control block. */ - memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb)); - - /* - * Setup driver NVRAM options. - */ - qla2x00_set_model_info(vha, nv->model_name, sizeof(nv->model_name), - "QLE8XXX"); - - /* Use alternate WWN? */ - if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { - memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); - memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE); - } - - /* Prepare nodename */ - if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) { - /* - * Firmware will apply the following mask if the nodename was - * not provided. - */ - memcpy(icb->node_name, icb->port_name, WWN_SIZE); - icb->node_name[0] &= 0xF0; - } - - /* Set host adapter parameters. */ - ha->flags.disable_risc_code_load = 0; - ha->flags.enable_lip_reset = 0; - ha->flags.enable_lip_full_login = - le32_to_cpu(nv->host_p) & BIT_10 ? 1: 0; - ha->flags.enable_target_reset = - le32_to_cpu(nv->host_p) & BIT_11 ? 1: 0; - ha->flags.enable_led_scheme = 0; - ha->flags.disable_serdes = le32_to_cpu(nv->host_p) & BIT_5 ? 1: 0; - - ha->operating_mode = (le32_to_cpu(icb->firmware_options_2) & - (BIT_6 | BIT_5 | BIT_4)) >> 4; - - /* save HBA serial number */ - ha->serial0 = icb->port_name[5]; - ha->serial1 = icb->port_name[6]; - ha->serial2 = icb->port_name[7]; - memcpy(vha->node_name, icb->node_name, WWN_SIZE); - memcpy(vha->port_name, icb->port_name, WWN_SIZE); - - icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); - - ha->retry_count = le16_to_cpu(nv->login_retry_count); - - /* Set minimum login_timeout to 4 seconds. */ - if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout) - nv->login_timeout = cpu_to_le16(ql2xlogintimeout); - if (le16_to_cpu(nv->login_timeout) < 4) - nv->login_timeout = __constant_cpu_to_le16(4); - ha->login_timeout = le16_to_cpu(nv->login_timeout); - icb->login_timeout = nv->login_timeout; - - /* Set minimum RATOV to 100 tenths of a second. */ - ha->r_a_tov = 100; - - ha->loop_reset_delay = nv->reset_delay; - - /* Link Down Timeout = 0: - * - * When Port Down timer expires we will start returning - * I/O's to OS with "DID_NO_CONNECT". - * - * Link Down Timeout != 0: - * - * The driver waits for the link to come up after link down - * before returning I/Os to OS with "DID_NO_CONNECT". - */ - if (le16_to_cpu(nv->link_down_timeout) == 0) { - ha->loop_down_abort_time = - (LOOP_DOWN_TIME - LOOP_DOWN_TIMEOUT); - } else { - ha->link_down_timeout = le16_to_cpu(nv->link_down_timeout); - ha->loop_down_abort_time = - (LOOP_DOWN_TIME - ha->link_down_timeout); - } - - /* Need enough time to try and get the port back. */ - ha->port_down_retry_count = le16_to_cpu(nv->port_down_retry_count); - if (qlport_down_retry) - ha->port_down_retry_count = qlport_down_retry; - - /* Set login_retry_count */ - ha->login_retry_count = le16_to_cpu(nv->login_retry_count); - if (ha->port_down_retry_count == - le16_to_cpu(nv->port_down_retry_count) && - ha->port_down_retry_count > 3) - ha->login_retry_count = ha->port_down_retry_count; - else if (ha->port_down_retry_count > (int)ha->login_retry_count) - ha->login_retry_count = ha->port_down_retry_count; - if (ql2xloginretrycount) - ha->login_retry_count = ql2xloginretrycount; - - /* if not running MSI-X we need handshaking on interrupts */ - if (!vha->hw->flags.msix_enabled && IS_QLA83XX(ha)) - icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22); - - /* Enable ZIO. */ - if (!vha->flags.init_done) { - ha->zio_mode = le32_to_cpu(icb->firmware_options_2) & - (BIT_3 | BIT_2 | BIT_1 | BIT_0); - ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ? - le16_to_cpu(icb->interrupt_delay_timer): 2; - } - icb->firmware_options_2 &= __constant_cpu_to_le32( - ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); - vha->flags.process_response_queue = 0; - if (ha->zio_mode != QLA_ZIO_DISABLED) { - ha->zio_mode = QLA_ZIO_MODE_6; - - ql_log(ql_log_info, vha, 0x0075, - "ZIO mode %d enabled; timer delay (%d us).\n", - ha->zio_mode, - ha->zio_timer * 100); - - icb->firmware_options_2 |= cpu_to_le32( - (uint32_t)ha->zio_mode); - icb->interrupt_delay_timer = cpu_to_le16(ha->zio_timer); - vha->flags.process_response_queue = 1; - } - - if (rval) { - ql_log(ql_log_warn, vha, 0x0076, - "NVRAM configuration failed.\n"); - } - return (rval); -} - -int -qla82xx_restart_isp(scsi_qla_host_t *vha) -{ - int status, rval; - uint32_t wait_time; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; - struct scsi_qla_host *vp; - unsigned long flags; - - status = qla2x00_init_rings(vha); - if (!status) { - clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - ha->flags.chip_reset_done = 1; - - status = qla2x00_fw_ready(vha); - if (!status) { - ql_log(ql_log_info, vha, 0x803c, - "Start configure loop, status =%d.\n", status); - - /* Issue a marker after FW becomes ready. */ - qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); - - vha->flags.online = 1; - /* Wait at most MAX_TARGET RSCNs for a stable link. */ - wait_time = 256; - do { - clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - qla2x00_configure_loop(vha); - wait_time--; - } while (!atomic_read(&vha->loop_down_timer) && - !(test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) && - wait_time && - (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags))); - } - - /* if no cable then assume it's good */ - if ((vha->device_flags & DFLG_NO_CABLE)) - status = 0; - - ql_log(ql_log_info, vha, 0x8000, - "Configure loop done, status = 0x%x.\n", status); - } - - if (!status) { - clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - - if (!atomic_read(&vha->loop_down_timer)) { - /* - * Issue marker command only when we are going - * to start the I/O . - */ - vha->marker_needed = 1; - } - - vha->flags.online = 1; - - ha->isp_ops->enable_intrs(ha); - - ha->isp_abort_cnt = 0; - clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); - - /* Update the firmware version */ - status = qla82xx_check_md_needed(vha); - - if (ha->fce) { - ha->flags.fce_enabled = 1; - memset(ha->fce, 0, - fce_calc_size(ha->fce_bufs)); - rval = qla2x00_enable_fce_trace(vha, - ha->fce_dma, ha->fce_bufs, ha->fce_mb, - &ha->fce_bufs); - if (rval) { - ql_log(ql_log_warn, vha, 0x8001, - "Unable to reinitialize FCE (%d).\n", - rval); - ha->flags.fce_enabled = 0; - } - } - - if (ha->eft) { - memset(ha->eft, 0, EFT_SIZE); - rval = qla2x00_enable_eft_trace(vha, - ha->eft_dma, EFT_NUM_BUFFERS); - if (rval) { - ql_log(ql_log_warn, vha, 0x8010, - "Unable to reinitialize EFT (%d).\n", - rval); - } - } - } - - if (!status) { - ql_dbg(ql_dbg_taskm, vha, 0x8011, - "qla82xx_restart_isp succeeded.\n"); - - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vp, &ha->vp_list, list) { - if (vp->vp_idx) { - atomic_inc(&vp->vref_count); - spin_unlock_irqrestore(&ha->vport_slock, flags); - - qla2x00_vp_abort_isp(vp); - - spin_lock_irqsave(&ha->vport_slock, flags); - atomic_dec(&vp->vref_count); - } - } - spin_unlock_irqrestore(&ha->vport_slock, flags); - - } else { - ql_log(ql_log_warn, vha, 0x8016, - "qla82xx_restart_isp **** FAILED ****.\n"); - } - - return status; -} - -void -qla81xx_update_fw_options(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - if (!ql2xetsenable) - return; - - /* Enable ETS Burst. */ - memset(ha->fw_options, 0, sizeof(ha->fw_options)); - ha->fw_options[2] |= BIT_9; - qla2x00_set_fw_options(vha, ha->fw_options); -} - -/* - * qla24xx_get_fcp_prio - * Gets the fcp cmd priority value for the logged in port. - * Looks for a match of the port descriptors within - * each of the fcp prio config entries. If a match is found, - * the tag (priority) value is returned. - * - * Input: - * vha = scsi host structure pointer. - * fcport = port structure pointer. - * - * Return: - * non-zero (if found) - * -1 (if not found) - * - * Context: - * Kernel context - */ -static int -qla24xx_get_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - int i, entries; - uint8_t pid_match, wwn_match; - int priority; - uint32_t pid1, pid2; - uint64_t wwn1, wwn2; - struct qla_fcp_prio_entry *pri_entry; - struct qla_hw_data *ha = vha->hw; - - if (!ha->fcp_prio_cfg || !ha->flags.fcp_prio_enabled) - return -1; - - priority = -1; - entries = ha->fcp_prio_cfg->num_entries; - pri_entry = &ha->fcp_prio_cfg->entry[0]; - - for (i = 0; i < entries; i++) { - pid_match = wwn_match = 0; - - if (!(pri_entry->flags & FCP_PRIO_ENTRY_VALID)) { - pri_entry++; - continue; - } - - /* check source pid for a match */ - if (pri_entry->flags & FCP_PRIO_ENTRY_SPID_VALID) { - pid1 = pri_entry->src_pid & INVALID_PORT_ID; - pid2 = vha->d_id.b24 & INVALID_PORT_ID; - if (pid1 == INVALID_PORT_ID) - pid_match++; - else if (pid1 == pid2) - pid_match++; - } - - /* check destination pid for a match */ - if (pri_entry->flags & FCP_PRIO_ENTRY_DPID_VALID) { - pid1 = pri_entry->dst_pid & INVALID_PORT_ID; - pid2 = fcport->d_id.b24 & INVALID_PORT_ID; - if (pid1 == INVALID_PORT_ID) - pid_match++; - else if (pid1 == pid2) - pid_match++; - } - - /* check source WWN for a match */ - if (pri_entry->flags & FCP_PRIO_ENTRY_SWWN_VALID) { - wwn1 = wwn_to_u64(vha->port_name); - wwn2 = wwn_to_u64(pri_entry->src_wwpn); - if (wwn2 == (uint64_t)-1) - wwn_match++; - else if (wwn1 == wwn2) - wwn_match++; - } - - /* check destination WWN for a match */ - if (pri_entry->flags & FCP_PRIO_ENTRY_DWWN_VALID) { - wwn1 = wwn_to_u64(fcport->port_name); - wwn2 = wwn_to_u64(pri_entry->dst_wwpn); - if (wwn2 == (uint64_t)-1) - wwn_match++; - else if (wwn1 == wwn2) - wwn_match++; - } - - if (pid_match == 2 || wwn_match == 2) { - /* Found a matching entry */ - if (pri_entry->flags & FCP_PRIO_ENTRY_TAG_VALID) - priority = pri_entry->tag; - break; - } - - pri_entry++; - } - - return priority; -} - -/* - * qla24xx_update_fcport_fcp_prio - * Activates fcp priority for the logged in fc port - * - * Input: - * vha = scsi host structure pointer. - * fcp = port structure pointer. - * - * Return: - * QLA_SUCCESS or QLA_FUNCTION_FAILED - * - * Context: - * Kernel context. - */ -int -qla24xx_update_fcport_fcp_prio(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - int ret; - int priority; - uint16_t mb[5]; - - if (fcport->port_type != FCT_TARGET || - fcport->loop_id == FC_NO_LOOP_ID) - return QLA_FUNCTION_FAILED; - - priority = qla24xx_get_fcp_prio(vha, fcport); - if (priority < 0) - return QLA_FUNCTION_FAILED; - - if (IS_QLA82XX(vha->hw)) { - fcport->fcp_prio = priority & 0xf; - return QLA_SUCCESS; - } - - ret = qla24xx_set_fcp_prio(vha, fcport->loop_id, priority, mb); - if (ret == QLA_SUCCESS) { - if (fcport->fcp_prio != priority) - ql_dbg(ql_dbg_user, vha, 0x709e, - "Updated FCP_CMND priority - value=%d loop_id=%d " - "port_id=%02x%02x%02x.\n", priority, - fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - fcport->fcp_prio = priority & 0xf; - } else - ql_dbg(ql_dbg_user, vha, 0x704f, - "Unable to update FCP_CMND priority - ret=0x%x for " - "loop_id=%d port_id=%02x%02x%02x.\n", ret, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - return ret; -} - -/* - * qla24xx_update_all_fcp_prio - * Activates fcp priority for all the logged in ports - * - * Input: - * ha = adapter block pointer. - * - * Return: - * QLA_SUCCESS or QLA_FUNCTION_FAILED - * - * Context: - * Kernel context. - */ -int -qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha) -{ - int ret; - fc_port_t *fcport; - - ret = QLA_FUNCTION_FAILED; - /* We need to set priority for all logged in ports */ - list_for_each_entry(fcport, &vha->vp_fcports, list) - ret = qla24xx_update_fcport_fcp_prio(vha, fcport); - - return ret; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_inline.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_inline.h deleted file mode 100644 index 6e457643..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_inline.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ - -/* - * qla2x00_debounce_register - * Debounce register. - * - * Input: - * port = register address. - * - * Returns: - * register value. - */ -static __inline__ uint16_t -qla2x00_debounce_register(volatile uint16_t __iomem *addr) -{ - volatile uint16_t first; - volatile uint16_t second; - - do { - first = RD_REG_WORD(addr); - barrier(); - cpu_relax(); - second = RD_REG_WORD(addr); - } while (first != second); - - return (first); -} - -static inline void -qla2x00_poll(struct rsp_que *rsp) -{ - unsigned long flags; - struct qla_hw_data *ha = rsp->hw; - local_irq_save(flags); - if (IS_QLA82XX(ha)) - qla82xx_poll(0, rsp); - else - ha->isp_ops->intr_handler(0, rsp); - local_irq_restore(flags); -} - -static inline uint8_t * -host_to_fcp_swap(uint8_t *fcp, uint32_t bsize) -{ - uint32_t *ifcp = (uint32_t *) fcp; - uint32_t *ofcp = (uint32_t *) fcp; - uint32_t iter = bsize >> 2; - - for (; iter ; iter--) - *ofcp++ = swab32(*ifcp++); - - return fcp; -} - -static inline int -qla2x00_is_reserved_id(scsi_qla_host_t *vha, uint16_t loop_id) -{ - struct qla_hw_data *ha = vha->hw; - if (IS_FWI2_CAPABLE(ha)) - return (loop_id > NPH_LAST_HANDLE); - - return ((loop_id > ha->max_loop_id && loop_id < SNS_FIRST_LOOP_ID) || - loop_id == MANAGEMENT_SERVER || loop_id == BROADCAST); -} - -static inline void -qla2x00_clean_dsd_pool(struct qla_hw_data *ha, srb_t *sp) -{ - struct dsd_dma *dsd_ptr, *tdsd_ptr; - struct crc_context *ctx; - - ctx = (struct crc_context *)GET_CMD_CTX_SP(sp); - - /* clean up allocated prev pool */ - list_for_each_entry_safe(dsd_ptr, tdsd_ptr, - &ctx->dsd_list, list) { - dma_pool_free(ha->dl_dma_pool, dsd_ptr->dsd_addr, - dsd_ptr->dsd_list_dma); - list_del(&dsd_ptr->list); - kfree(dsd_ptr); - } - INIT_LIST_HEAD(&ctx->dsd_list); -} - -static inline void -qla2x00_set_fcport_state(fc_port_t *fcport, int state) -{ - int old_state; - - old_state = atomic_read(&fcport->state); - atomic_set(&fcport->state, state); - - /* Don't print state transitions during initial allocation of fcport */ - if (old_state && old_state != state) { - ql_dbg(ql_dbg_disc, fcport->vha, 0x207d, - "FCPort state transitioned from %s to %s - " - "portid=%02x%02x%02x.\n", - port_state_str[old_state], port_state_str[state], - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa); - } -} - -static inline int -qla2x00_hba_err_chk_enabled(srb_t *sp) -{ - /* - * Uncomment when corresponding SCSI changes are done. - * - if (!sp->cmd->prot_chk) - return 0; - * - */ - switch (scsi_get_prot_op(GET_CMD_SP(sp))) { - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_WRITE_INSERT: - if (ql2xenablehba_err_chk >= 1) - return 1; - break; - case SCSI_PROT_READ_PASS: - case SCSI_PROT_WRITE_PASS: - if (ql2xenablehba_err_chk >= 2) - return 1; - break; - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_WRITE_STRIP: - return 1; - } - return 0; -} - -static inline int -qla2x00_reset_active(scsi_qla_host_t *vha) -{ - scsi_qla_host_t *base_vha = pci_get_drvdata(vha->hw->pdev); - - /* Test appropriate base-vha and vha flags. */ - return test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || - test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); -} - -static inline srb_t * -qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag) -{ - srb_t *sp = NULL; - struct qla_hw_data *ha = vha->hw; - uint8_t bail; - - QLA_VHA_MARK_BUSY(vha, bail); - if (unlikely(bail)) - return NULL; - - sp = mempool_alloc(ha->srb_mempool, flag); - if (!sp) - goto done; - - memset(sp, 0, sizeof(*sp)); - sp->fcport = fcport; - sp->iocbs = 1; -done: - if (!sp) - QLA_VHA_MARK_NOT_BUSY(vha); - return sp; -} - -static inline void -qla2x00_init_timer(srb_t *sp, unsigned long tmo) -{ - init_timer(&sp->u.iocb_cmd.timer); - sp->u.iocb_cmd.timer.expires = jiffies + tmo * HZ; - sp->u.iocb_cmd.timer.data = (unsigned long)sp; - sp->u.iocb_cmd.timer.function = qla2x00_sp_timeout; - add_timer(&sp->u.iocb_cmd.timer); - sp->free = qla2x00_sp_free; -} - -static inline int -qla2x00_gid_list_size(struct qla_hw_data *ha) -{ - return sizeof(struct gid_list_info) * ha->max_fibre_devices; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_iocb.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_iocb.c deleted file mode 100644 index eac95092..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_iocb.c +++ /dev/null @@ -1,2647 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -#include -#include - -#include - -static void qla25xx_set_que(srb_t *, struct rsp_que **); -/** - * qla2x00_get_cmd_direction() - Determine control_flag data direction. - * @cmd: SCSI command - * - * Returns the proper CF_* direction based on CDB. - */ -static inline uint16_t -qla2x00_get_cmd_direction(srb_t *sp) -{ - uint16_t cflags; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - - cflags = 0; - - /* Set transfer direction */ - if (cmd->sc_data_direction == DMA_TO_DEVICE) { - cflags = CF_WRITE; - sp->fcport->vha->hw->qla_stats.output_bytes += - scsi_bufflen(cmd); - } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - cflags = CF_READ; - sp->fcport->vha->hw->qla_stats.input_bytes += - scsi_bufflen(cmd); - } - return (cflags); -} - -/** - * qla2x00_calc_iocbs_32() - Determine number of Command Type 2 and - * Continuation Type 0 IOCBs to allocate. - * - * @dsds: number of data segment decriptors needed - * - * Returns the number of IOCB entries needed to store @dsds. - */ -uint16_t -qla2x00_calc_iocbs_32(uint16_t dsds) -{ - uint16_t iocbs; - - iocbs = 1; - if (dsds > 3) { - iocbs += (dsds - 3) / 7; - if ((dsds - 3) % 7) - iocbs++; - } - return (iocbs); -} - -/** - * qla2x00_calc_iocbs_64() - Determine number of Command Type 3 and - * Continuation Type 1 IOCBs to allocate. - * - * @dsds: number of data segment decriptors needed - * - * Returns the number of IOCB entries needed to store @dsds. - */ -uint16_t -qla2x00_calc_iocbs_64(uint16_t dsds) -{ - uint16_t iocbs; - - iocbs = 1; - if (dsds > 2) { - iocbs += (dsds - 2) / 5; - if ((dsds - 2) % 5) - iocbs++; - } - return (iocbs); -} - -/** - * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB. - * @ha: HA context - * - * Returns a pointer to the Continuation Type 0 IOCB packet. - */ -static inline cont_entry_t * -qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) -{ - cont_entry_t *cont_pkt; - struct req_que *req = vha->req; - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else { - req->ring_ptr++; - } - - cont_pkt = (cont_entry_t *)req->ring_ptr; - - /* Load packet defaults. */ - *((uint32_t *)(&cont_pkt->entry_type)) = - __constant_cpu_to_le32(CONTINUE_TYPE); - - return (cont_pkt); -} - -/** - * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB. - * @ha: HA context - * - * Returns a pointer to the continuation type 1 IOCB packet. - */ -static inline cont_a64_entry_t * -qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) -{ - cont_a64_entry_t *cont_pkt; - - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else { - req->ring_ptr++; - } - - cont_pkt = (cont_a64_entry_t *)req->ring_ptr; - - /* Load packet defaults. */ - *((uint32_t *)(&cont_pkt->entry_type)) = - __constant_cpu_to_le32(CONTINUE_A64_TYPE); - - return (cont_pkt); -} - -static inline int -qla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts) -{ - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - uint8_t guard = scsi_host_get_guard(cmd->device->host); - - /* We only support T10 DIF right now */ - if (guard != SHOST_DIX_GUARD_CRC) { - ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3007, - "Unsupported guard: %d for cmd=%p.\n", guard, cmd); - return 0; - } - - /* We always use DIFF Bundling for best performance */ - *fw_prot_opts = 0; - - /* Translate SCSI opcode to a protection opcode */ - switch (scsi_get_prot_op(cmd)) { - case SCSI_PROT_READ_STRIP: - *fw_prot_opts |= PO_MODE_DIF_REMOVE; - break; - case SCSI_PROT_WRITE_INSERT: - *fw_prot_opts |= PO_MODE_DIF_INSERT; - break; - case SCSI_PROT_READ_INSERT: - *fw_prot_opts |= PO_MODE_DIF_INSERT; - break; - case SCSI_PROT_WRITE_STRIP: - *fw_prot_opts |= PO_MODE_DIF_REMOVE; - break; - case SCSI_PROT_READ_PASS: - *fw_prot_opts |= PO_MODE_DIF_PASS; - break; - case SCSI_PROT_WRITE_PASS: - *fw_prot_opts |= PO_MODE_DIF_PASS; - break; - default: /* Normal Request */ - *fw_prot_opts |= PO_MODE_DIF_PASS; - break; - } - - return scsi_prot_sg_count(cmd); -} - -/* - * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit - * capable IOCB types. - * - * @sp: SRB command to process - * @cmd_pkt: Command type 2 IOCB - * @tot_dsds: Total number of segments to transfer - */ -void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, - uint16_t tot_dsds) -{ - uint16_t avail_dsds; - uint32_t *cur_dsd; - scsi_qla_host_t *vha; - struct scsi_cmnd *cmd; - struct scatterlist *sg; - int i; - - cmd = GET_CMD_SP(sp); - - /* Update entry type to indicate Command Type 2 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE); - - /* No data transfer */ - if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); - return; - } - - vha = sp->fcport->vha; - cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); - - /* Three DSDs are available in the Command Type 2 IOCB */ - avail_dsds = 3; - cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; - - /* Load data segments */ - scsi_for_each_sg(cmd, sg, tot_dsds, i) { - cont_entry_t *cont_pkt; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - /* - * Seven DSDs are available in the Continuation - * Type 0 IOCB. - */ - cont_pkt = qla2x00_prep_cont_type0_iocb(vha); - cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address; - avail_dsds = 7; - } - - *cur_dsd++ = cpu_to_le32(sg_dma_address(sg)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - avail_dsds--; - } -} - -/** - * qla2x00_build_scsi_iocbs_64() - Build IOCB command utilizing 64bit - * capable IOCB types. - * - * @sp: SRB command to process - * @cmd_pkt: Command type 3 IOCB - * @tot_dsds: Total number of segments to transfer - */ -void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, - uint16_t tot_dsds) -{ - uint16_t avail_dsds; - uint32_t *cur_dsd; - scsi_qla_host_t *vha; - struct scsi_cmnd *cmd; - struct scatterlist *sg; - int i; - - cmd = GET_CMD_SP(sp); - - /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_A64_TYPE); - - /* No data transfer */ - if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); - return; - } - - vha = sp->fcport->vha; - cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(sp)); - - /* Two DSDs are available in the Command Type 3 IOCB */ - avail_dsds = 2; - cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; - - /* Load data segments */ - scsi_for_each_sg(cmd, sg, tot_dsds, i) { - dma_addr_t sle_dma; - cont_a64_entry_t *cont_pkt; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - /* - * Five DSDs are available in the Continuation - * Type 1 IOCB. - */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); - cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; - avail_dsds = 5; - } - - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - avail_dsds--; - } -} - -/** - * qla2x00_start_scsi() - Send a SCSI command to the ISP - * @sp: command to send to the ISP - * - * Returns non-zero if a failure occurred, else zero. - */ -int -qla2x00_start_scsi(srb_t *sp) -{ - int ret, nseg; - unsigned long flags; - scsi_qla_host_t *vha; - struct scsi_cmnd *cmd; - uint32_t *clr_ptr; - uint32_t index; - uint32_t handle; - cmd_entry_t *cmd_pkt; - uint16_t cnt; - uint16_t req_cnt; - uint16_t tot_dsds; - struct device_reg_2xxx __iomem *reg; - struct qla_hw_data *ha; - struct req_que *req; - struct rsp_que *rsp; - char tag[2]; - - /* Setup device pointers. */ - ret = 0; - vha = sp->fcport->vha; - ha = vha->hw; - reg = &ha->iobase->isp; - cmd = GET_CMD_SP(sp); - req = ha->req_q_map[0]; - rsp = ha->rsp_q_map[0]; - /* So we know we haven't pci_map'ed anything yet */ - tot_dsds = 0; - - /* Send marker if required */ - if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != - QLA_SUCCESS) { - return (QLA_FUNCTION_FAILED); - } - vha->marker_needed = 0; - } - - /* Acquire ring specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { - handle++; - if (handle == MAX_OUTSTANDING_COMMANDS) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == MAX_OUTSTANDING_COMMANDS) - goto queuing_error; - - /* Map the sg table so we have an accurate count of sg entries needed */ - if (scsi_sg_count(cmd)) { - nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), - scsi_sg_count(cmd), cmd->sc_data_direction); - if (unlikely(!nseg)) - goto queuing_error; - } else - nseg = 0; - - tot_dsds = nseg; - - /* Calculate the number of request entries needed. */ - req_cnt = ha->isp_ops->calc_req_entries(tot_dsds); - if (req->cnt < (req_cnt + 2)) { - cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg)); - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - if (req->cnt < (req_cnt + 2)) - goto queuing_error; - - /* Build command packet */ - req->current_outstanding_cmd = handle; - req->outstanding_cmds[handle] = sp; - sp->handle = handle; - cmd->host_scribble = (unsigned char *)(unsigned long)handle; - req->cnt -= req_cnt; - - cmd_pkt = (cmd_entry_t *)req->ring_ptr; - cmd_pkt->handle = handle; - /* Zero out remaining portion of packet. */ - clr_ptr = (uint32_t *)cmd_pkt + 2; - memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); - cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); - - /* Set target ID and LUN number*/ - SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id); - cmd_pkt->lun = cpu_to_le16(cmd->device->lun); - - /* Update tagged queuing modifier */ - if (scsi_populate_tag_msg(cmd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_HEAD_TAG); - break; - case ORDERED_QUEUE_TAG: - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_ORDERED_TAG); - break; - default: - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_SIMPLE_TAG); - break; - } - } - - /* Load SCSI command packet. */ - memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len); - cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); - - /* Build IOCB segments */ - ha->isp_ops->build_iocbs(sp, cmd_pkt, tot_dsds); - - /* Set total data segment count. */ - cmd_pkt->entry_count = (uint8_t)req_cnt; - wmb(); - - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else - req->ring_ptr++; - - sp->flags |= SRB_DMA_VALID; - - /* Set chip new ring index. */ - WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), req->ring_index); - RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg)); /* PCI Posting. */ - - /* Manage unprocessed RIO/ZIO commands in response queue. */ - if (vha->flags.process_response_queue && - rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla2x00_process_response_queue(rsp); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return (QLA_SUCCESS); - -queuing_error: - if (tot_dsds) - scsi_dma_unmap(cmd); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return (QLA_FUNCTION_FAILED); -} - -/** - * qla2x00_start_iocbs() - Execute the IOCB command - */ -static void -qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) -{ - struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); - - if (IS_QLA82XX(ha)) { - qla82xx_start_iocbs(vha); - } else { - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else - req->ring_ptr++; - - /* Set chip new ring index. */ - if (ha->mqenable || IS_QLA83XX(ha)) { - WRT_REG_DWORD(req->req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); - } else if (IS_FWI2_CAPABLE(ha)) { - WRT_REG_DWORD(®->isp24.req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(®->isp24.req_q_in); - } else { - WRT_REG_WORD(ISP_REQ_Q_IN(ha, ®->isp), - req->ring_index); - RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, ®->isp)); - } - } -} - -/** - * qla2x00_marker() - Send a marker IOCB to the firmware. - * @ha: HA context - * @loop_id: loop ID - * @lun: LUN - * @type: marker modifier - * - * Can be called from both normal and interrupt context. - * - * Returns non-zero if a failure occurred, else zero. - */ -static int -__qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, - struct rsp_que *rsp, uint16_t loop_id, - uint16_t lun, uint8_t type) -{ - mrk_entry_t *mrk; - struct mrk_entry_24xx *mrk24; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - mrk24 = NULL; - req = ha->req_q_map[0]; - mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, 0); - if (mrk == NULL) { - ql_log(ql_log_warn, base_vha, 0x3026, - "Failed to allocate Marker IOCB.\n"); - - return (QLA_FUNCTION_FAILED); - } - - mrk->entry_type = MARKER_TYPE; - mrk->modifier = type; - if (type != MK_SYNC_ALL) { - if (IS_FWI2_CAPABLE(ha)) { - mrk24 = (struct mrk_entry_24xx *) mrk; - mrk24->nport_handle = cpu_to_le16(loop_id); - mrk24->lun[1] = LSB(lun); - mrk24->lun[2] = MSB(lun); - host_to_fcp_swap(mrk24->lun, sizeof(mrk24->lun)); - mrk24->vp_index = vha->vp_idx; - mrk24->handle = MAKE_HANDLE(req->id, mrk24->handle); - } else { - SET_TARGET_ID(ha, mrk->target, loop_id); - mrk->lun = cpu_to_le16(lun); - } - } - wmb(); - - qla2x00_start_iocbs(vha, req); - - return (QLA_SUCCESS); -} - -int -qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, - struct rsp_que *rsp, uint16_t loop_id, uint16_t lun, - uint8_t type) -{ - int ret; - unsigned long flags = 0; - - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - ret = __qla2x00_marker(vha, req, rsp, loop_id, lun, type); - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); - - return (ret); -} - -/** - * qla24xx_calc_iocbs() - Determine number of Command Type 3 and - * Continuation Type 1 IOCBs to allocate. - * - * @dsds: number of data segment decriptors needed - * - * Returns the number of IOCB entries needed to store @dsds. - */ -inline uint16_t -qla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds) -{ - uint16_t iocbs; - - iocbs = 1; - if (dsds > 1) { - iocbs += (dsds - 1) / 5; - if ((dsds - 1) % 5) - iocbs++; - } - return iocbs; -} - -static inline int -qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, - uint16_t tot_dsds) -{ - uint32_t *cur_dsd = NULL; - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct scsi_cmnd *cmd; - struct scatterlist *cur_seg; - uint32_t *dsd_seg; - void *next_dsd; - uint8_t avail_dsds; - uint8_t first_iocb = 1; - uint32_t dsd_list_len; - struct dsd_dma *dsd_ptr; - struct ct6_dsd *ctx; - - cmd = GET_CMD_SP(sp); - - /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE_6); - - /* No data transfer */ - if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); - return 0; - } - - vha = sp->fcport->vha; - ha = vha->hw; - - /* Set transfer direction */ - if (cmd->sc_data_direction == DMA_TO_DEVICE) { - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_WRITE_DATA); - ha->qla_stats.output_bytes += scsi_bufflen(cmd); - } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_READ_DATA); - ha->qla_stats.input_bytes += scsi_bufflen(cmd); - } - - cur_seg = scsi_sglist(cmd); - ctx = GET_CMD_CTX_SP(sp); - - while (tot_dsds) { - avail_dsds = (tot_dsds > QLA_DSDS_PER_IOCB) ? - QLA_DSDS_PER_IOCB : tot_dsds; - tot_dsds -= avail_dsds; - dsd_list_len = (avail_dsds + 1) * QLA_DSD_SIZE; - - dsd_ptr = list_first_entry(&ha->gbl_dsd_list, - struct dsd_dma, list); - next_dsd = dsd_ptr->dsd_addr; - list_del(&dsd_ptr->list); - ha->gbl_dsd_avail--; - list_add_tail(&dsd_ptr->list, &ctx->dsd_list); - ctx->dsd_use_cnt++; - ha->gbl_dsd_inuse++; - - if (first_iocb) { - first_iocb = 0; - dsd_seg = (uint32_t *)&cmd_pkt->fcp_data_dseg_address; - *dsd_seg++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *dsd_seg++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - cmd_pkt->fcp_data_dseg_len = cpu_to_le32(dsd_list_len); - } else { - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(dsd_list_len); - } - cur_dsd = (uint32_t *)next_dsd; - while (avail_dsds) { - dma_addr_t sle_dma; - - sle_dma = sg_dma_address(cur_seg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg)); - cur_seg = sg_next(cur_seg); - avail_dsds--; - } - } - - /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; - cmd_pkt->control_flags |= CF_DATA_SEG_DESCR_ENABLE; - return 0; -} - -/* - * qla24xx_calc_dsd_lists() - Determine number of DSD list required - * for Command Type 6. - * - * @dsds: number of data segment decriptors needed - * - * Returns the number of dsd list needed to store @dsds. - */ -inline uint16_t -qla24xx_calc_dsd_lists(uint16_t dsds) -{ - uint16_t dsd_lists = 0; - - dsd_lists = (dsds/QLA_DSDS_PER_IOCB); - if (dsds % QLA_DSDS_PER_IOCB) - dsd_lists++; - return dsd_lists; -} - - -/** - * qla24xx_build_scsi_iocbs() - Build IOCB command utilizing Command Type 7 - * IOCB types. - * - * @sp: SRB command to process - * @cmd_pkt: Command type 3 IOCB - * @tot_dsds: Total number of segments to transfer - */ -inline void -qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, - uint16_t tot_dsds) -{ - uint16_t avail_dsds; - uint32_t *cur_dsd; - scsi_qla_host_t *vha; - struct scsi_cmnd *cmd; - struct scatterlist *sg; - int i; - struct req_que *req; - - cmd = GET_CMD_SP(sp); - - /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE_7); - - /* No data transfer */ - if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); - return; - } - - vha = sp->fcport->vha; - req = vha->req; - - /* Set transfer direction */ - if (cmd->sc_data_direction == DMA_TO_DEVICE) { - cmd_pkt->task_mgmt_flags = - __constant_cpu_to_le16(TMF_WRITE_DATA); - sp->fcport->vha->hw->qla_stats.output_bytes += - scsi_bufflen(cmd); - } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - cmd_pkt->task_mgmt_flags = - __constant_cpu_to_le16(TMF_READ_DATA); - sp->fcport->vha->hw->qla_stats.input_bytes += - scsi_bufflen(cmd); - } - - /* One DSD is available in the Command Type 3 IOCB */ - avail_dsds = 1; - cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address; - - /* Load data segments */ - - scsi_for_each_sg(cmd, sg, tot_dsds, i) { - dma_addr_t sle_dma; - cont_a64_entry_t *cont_pkt; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - /* - * Five DSDs are available in the Continuation - * Type 1 IOCB. - */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); - cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; - avail_dsds = 5; - } - - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - avail_dsds--; - } -} - -struct fw_dif_context { - uint32_t ref_tag; - uint16_t app_tag; - uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/ - uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/ -}; - -/* - * qla24xx_set_t10dif_tags_from_cmd - Extract Ref and App tags from SCSI command - * - */ -static inline void -qla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt, - unsigned int protcnt) -{ - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - - switch (scsi_get_prot_type(cmd)) { - case SCSI_PROT_DIF_TYPE0: - /* - * No check for ql2xenablehba_err_chk, as it would be an - * I/O error if hba tag generation is not done. - */ - pkt->ref_tag = cpu_to_le32((uint32_t) - (0xffffffff & scsi_get_lba(cmd))); - - if (!qla2x00_hba_err_chk_enabled(sp)) - break; - - pkt->ref_tag_mask[0] = 0xff; - pkt->ref_tag_mask[1] = 0xff; - pkt->ref_tag_mask[2] = 0xff; - pkt->ref_tag_mask[3] = 0xff; - break; - - /* - * For TYPE 2 protection: 16 bit GUARD + 32 bit REF tag has to - * match LBA in CDB + N - */ - case SCSI_PROT_DIF_TYPE2: - pkt->app_tag = __constant_cpu_to_le16(0); - pkt->app_tag_mask[0] = 0x0; - pkt->app_tag_mask[1] = 0x0; - - pkt->ref_tag = cpu_to_le32((uint32_t) - (0xffffffff & scsi_get_lba(cmd))); - - if (!qla2x00_hba_err_chk_enabled(sp)) - break; - - /* enable ALL bytes of the ref tag */ - pkt->ref_tag_mask[0] = 0xff; - pkt->ref_tag_mask[1] = 0xff; - pkt->ref_tag_mask[2] = 0xff; - pkt->ref_tag_mask[3] = 0xff; - break; - - /* For Type 3 protection: 16 bit GUARD only */ - case SCSI_PROT_DIF_TYPE3: - pkt->ref_tag_mask[0] = pkt->ref_tag_mask[1] = - pkt->ref_tag_mask[2] = pkt->ref_tag_mask[3] = - 0x00; - break; - - /* - * For TYpe 1 protection: 16 bit GUARD tag, 32 bit REF tag, and - * 16 bit app tag. - */ - case SCSI_PROT_DIF_TYPE1: - pkt->ref_tag = cpu_to_le32((uint32_t) - (0xffffffff & scsi_get_lba(cmd))); - pkt->app_tag = __constant_cpu_to_le16(0); - pkt->app_tag_mask[0] = 0x0; - pkt->app_tag_mask[1] = 0x0; - - if (!qla2x00_hba_err_chk_enabled(sp)) - break; - - /* enable ALL bytes of the ref tag */ - pkt->ref_tag_mask[0] = 0xff; - pkt->ref_tag_mask[1] = 0xff; - pkt->ref_tag_mask[2] = 0xff; - pkt->ref_tag_mask[3] = 0xff; - break; - } - - ql_dbg(ql_dbg_io, vha, 0x3009, - "Setting protection Tags: (BIG) ref tag = 0x%x, app tag = 0x%x, " - "prot SG count %d, cmd lba 0x%x, prot_type=%u cmd=%p.\n", - pkt->ref_tag, pkt->app_tag, protcnt, (int)scsi_get_lba(cmd), - scsi_get_prot_type(cmd), cmd); -} - -struct qla2_sgx { - dma_addr_t dma_addr; /* OUT */ - uint32_t dma_len; /* OUT */ - - uint32_t tot_bytes; /* IN */ - struct scatterlist *cur_sg; /* IN */ - - /* for book keeping, bzero on initial invocation */ - uint32_t bytes_consumed; - uint32_t num_bytes; - uint32_t tot_partial; - - /* for debugging */ - uint32_t num_sg; - srb_t *sp; -}; - -static int -qla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx, - uint32_t *partial) -{ - struct scatterlist *sg; - uint32_t cumulative_partial, sg_len; - dma_addr_t sg_dma_addr; - - if (sgx->num_bytes == sgx->tot_bytes) - return 0; - - sg = sgx->cur_sg; - cumulative_partial = sgx->tot_partial; - - sg_dma_addr = sg_dma_address(sg); - sg_len = sg_dma_len(sg); - - sgx->dma_addr = sg_dma_addr + sgx->bytes_consumed; - - if ((cumulative_partial + (sg_len - sgx->bytes_consumed)) >= blk_sz) { - sgx->dma_len = (blk_sz - cumulative_partial); - sgx->tot_partial = 0; - sgx->num_bytes += blk_sz; - *partial = 0; - } else { - sgx->dma_len = sg_len - sgx->bytes_consumed; - sgx->tot_partial += sgx->dma_len; - *partial = 1; - } - - sgx->bytes_consumed += sgx->dma_len; - - if (sg_len == sgx->bytes_consumed) { - sg = sg_next(sg); - sgx->num_sg++; - sgx->cur_sg = sg; - sgx->bytes_consumed = 0; - } - - return 1; -} - -static int -qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp, - uint32_t *dsd, uint16_t tot_dsds) -{ - void *next_dsd; - uint8_t avail_dsds = 0; - uint32_t dsd_list_len; - struct dsd_dma *dsd_ptr; - struct scatterlist *sg_prot; - uint32_t *cur_dsd = dsd; - uint16_t used_dsds = tot_dsds; - - uint32_t prot_int; - uint32_t partial; - struct qla2_sgx sgx; - dma_addr_t sle_dma; - uint32_t sle_dma_len, tot_prot_dma_len = 0; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - - prot_int = cmd->device->sector_size; - - memset(&sgx, 0, sizeof(struct qla2_sgx)); - sgx.tot_bytes = scsi_bufflen(cmd); - sgx.cur_sg = scsi_sglist(cmd); - sgx.sp = sp; - - sg_prot = scsi_prot_sglist(cmd); - - while (qla24xx_get_one_block_sg(prot_int, &sgx, &partial)) { - - sle_dma = sgx.dma_addr; - sle_dma_len = sgx.dma_len; -alloc_and_fill: - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? - QLA_DSDS_PER_IOCB : used_dsds; - dsd_list_len = (avail_dsds + 1) * 12; - used_dsds -= avail_dsds; - - /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); - if (!dsd_ptr) - return 1; - - /* allocate new list */ - dsd_ptr->dsd_addr = next_dsd = - dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, - &dsd_ptr->dsd_list_dma); - - if (!next_dsd) { - /* - * Need to cleanup only this dsd_ptr, rest - * will be done by sp_free_dma() - */ - kfree(dsd_ptr); - return 1; - } - - list_add_tail(&dsd_ptr->list, - &((struct crc_context *)sp->u.scmd.ctx)->dsd_list); - - sp->flags |= SRB_CRC_CTX_DSD_VALID; - - /* add new list to cmd iocb or last list */ - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; - cur_dsd = (uint32_t *)next_dsd; - } - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sle_dma_len); - avail_dsds--; - - if (partial == 0) { - /* Got a full protection interval */ - sle_dma = sg_dma_address(sg_prot) + tot_prot_dma_len; - sle_dma_len = 8; - - tot_prot_dma_len += sle_dma_len; - if (tot_prot_dma_len == sg_dma_len(sg_prot)) { - tot_prot_dma_len = 0; - sg_prot = sg_next(sg_prot); - } - - partial = 1; /* So as to not re-enter this block */ - goto alloc_and_fill; - } - } - /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; - return 0; -} - -static int -qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, - uint16_t tot_dsds) -{ - void *next_dsd; - uint8_t avail_dsds = 0; - uint32_t dsd_list_len; - struct dsd_dma *dsd_ptr; - struct scatterlist *sg; - uint32_t *cur_dsd = dsd; - int i; - uint16_t used_dsds = tot_dsds; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - - uint8_t *cp; - - scsi_for_each_sg(cmd, sg, tot_dsds, i) { - dma_addr_t sle_dma; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? - QLA_DSDS_PER_IOCB : used_dsds; - dsd_list_len = (avail_dsds + 1) * 12; - used_dsds -= avail_dsds; - - /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); - if (!dsd_ptr) - return 1; - - /* allocate new list */ - dsd_ptr->dsd_addr = next_dsd = - dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, - &dsd_ptr->dsd_list_dma); - - if (!next_dsd) { - /* - * Need to cleanup only this dsd_ptr, rest - * will be done by sp_free_dma() - */ - kfree(dsd_ptr); - return 1; - } - - list_add_tail(&dsd_ptr->list, - &((struct crc_context *)sp->u.scmd.ctx)->dsd_list); - - sp->flags |= SRB_CRC_CTX_DSD_VALID; - - /* add new list to cmd iocb or last list */ - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; - cur_dsd = (uint32_t *)next_dsd; - } - sle_dma = sg_dma_address(sg); - ql_dbg(ql_dbg_io, vha, 0x300a, - "sg entry %d - addr=0x%x 0x%x, " "len=%d for cmd=%p.\n", - i, LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg), cmd); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - avail_dsds--; - - if (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_PASS) { - cp = page_address(sg_page(sg)) + sg->offset; - ql_dbg(ql_dbg_io, vha, 0x300b, - "User data buffer=%p for cmd=%p.\n", cp, cmd); - } - } - /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; - return 0; -} - -static int -qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, - uint32_t *dsd, - uint16_t tot_dsds) -{ - void *next_dsd; - uint8_t avail_dsds = 0; - uint32_t dsd_list_len; - struct dsd_dma *dsd_ptr; - struct scatterlist *sg; - int i; - struct scsi_cmnd *cmd; - uint32_t *cur_dsd = dsd; - uint16_t used_dsds = tot_dsds; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - uint8_t *cp; - - cmd = GET_CMD_SP(sp); - scsi_for_each_prot_sg(cmd, sg, tot_dsds, i) { - dma_addr_t sle_dma; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? - QLA_DSDS_PER_IOCB : used_dsds; - dsd_list_len = (avail_dsds + 1) * 12; - used_dsds -= avail_dsds; - - /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); - if (!dsd_ptr) - return 1; - - /* allocate new list */ - dsd_ptr->dsd_addr = next_dsd = - dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, - &dsd_ptr->dsd_list_dma); - - if (!next_dsd) { - /* - * Need to cleanup only this dsd_ptr, rest - * will be done by sp_free_dma() - */ - kfree(dsd_ptr); - return 1; - } - - list_add_tail(&dsd_ptr->list, - &((struct crc_context *)sp->u.scmd.ctx)->dsd_list); - - sp->flags |= SRB_CRC_CTX_DSD_VALID; - - /* add new list to cmd iocb or last list */ - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; - cur_dsd = (uint32_t *)next_dsd; - } - sle_dma = sg_dma_address(sg); - if (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_PASS) { - ql_dbg(ql_dbg_io, vha, 0x3027, - "%s(): %p, sg_entry %d - " - "addr=0x%x0x%x, len=%d.\n", - __func__, cur_dsd, i, - LSD(sle_dma), MSD(sle_dma), sg_dma_len(sg)); - } - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - - if (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_PASS) { - cp = page_address(sg_page(sg)) + sg->offset; - ql_dbg(ql_dbg_io, vha, 0x3028, - "%s(): Protection Data buffer = %p.\n", __func__, - cp); - } - avail_dsds--; - } - /* Null termination */ - *cur_dsd++ = 0; - *cur_dsd++ = 0; - *cur_dsd++ = 0; - return 0; -} - -/** - * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command - * Type 6 IOCB types. - * - * @sp: SRB command to process - * @cmd_pkt: Command type 3 IOCB - * @tot_dsds: Total number of segments to transfer - */ -static inline int -qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, - uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts) -{ - uint32_t *cur_dsd, *fcp_dl; - scsi_qla_host_t *vha; - struct scsi_cmnd *cmd; - struct scatterlist *cur_seg; - int sgc; - uint32_t total_bytes = 0; - uint32_t data_bytes; - uint32_t dif_bytes; - uint8_t bundling = 1; - uint16_t blk_size; - uint8_t *clr_ptr; - struct crc_context *crc_ctx_pkt = NULL; - struct qla_hw_data *ha; - uint8_t additional_fcpcdb_len; - uint16_t fcp_cmnd_len; - struct fcp_cmnd *fcp_cmnd; - dma_addr_t crc_ctx_dma; - char tag[2]; - - cmd = GET_CMD_SP(sp); - - sgc = 0; - /* Update entry type to indicate Command Type CRC_2 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE_CRC_2); - - vha = sp->fcport->vha; - ha = vha->hw; - - /* No data transfer */ - data_bytes = scsi_bufflen(cmd); - if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); - return QLA_SUCCESS; - } - - cmd_pkt->vp_index = sp->fcport->vp_idx; - - /* Set transfer direction */ - if (cmd->sc_data_direction == DMA_TO_DEVICE) { - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_WRITE_DATA); - } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_READ_DATA); - } - - if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || - (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP) || - (scsi_get_prot_op(cmd) == SCSI_PROT_READ_STRIP) || - (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_INSERT)) - bundling = 0; - - /* Allocate CRC context from global pool */ - crc_ctx_pkt = sp->u.scmd.ctx = - dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, &crc_ctx_dma); - - if (!crc_ctx_pkt) - goto crc_queuing_error; - - /* Zero out CTX area. */ - clr_ptr = (uint8_t *)crc_ctx_pkt; - memset(clr_ptr, 0, sizeof(*crc_ctx_pkt)); - - crc_ctx_pkt->crc_ctx_dma = crc_ctx_dma; - - sp->flags |= SRB_CRC_CTX_DMA_VALID; - - /* Set handle */ - crc_ctx_pkt->handle = cmd_pkt->handle; - - INIT_LIST_HEAD(&crc_ctx_pkt->dsd_list); - - qla24xx_set_t10dif_tags(sp, (struct fw_dif_context *) - &crc_ctx_pkt->ref_tag, tot_prot_dsds); - - cmd_pkt->crc_context_address[0] = cpu_to_le32(LSD(crc_ctx_dma)); - cmd_pkt->crc_context_address[1] = cpu_to_le32(MSD(crc_ctx_dma)); - cmd_pkt->crc_context_len = CRC_CONTEXT_LEN_FW; - - /* Determine SCSI command length -- align to 4 byte boundary */ - if (cmd->cmd_len > 16) { - additional_fcpcdb_len = cmd->cmd_len - 16; - if ((cmd->cmd_len % 4) != 0) { - /* SCSI cmd > 16 bytes must be multiple of 4 */ - goto crc_queuing_error; - } - fcp_cmnd_len = 12 + cmd->cmd_len + 4; - } else { - additional_fcpcdb_len = 0; - fcp_cmnd_len = 12 + 16 + 4; - } - - fcp_cmnd = &crc_ctx_pkt->fcp_cmnd; - - fcp_cmnd->additional_cdb_len = additional_fcpcdb_len; - if (cmd->sc_data_direction == DMA_TO_DEVICE) - fcp_cmnd->additional_cdb_len |= 1; - else if (cmd->sc_data_direction == DMA_FROM_DEVICE) - fcp_cmnd->additional_cdb_len |= 2; - - int_to_scsilun(cmd->device->lun, &fcp_cmnd->lun); - memcpy(fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); - cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(fcp_cmnd_len); - cmd_pkt->fcp_cmnd_dseg_address[0] = cpu_to_le32( - LSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF)); - cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32( - MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF)); - fcp_cmnd->task_management = 0; - - /* - * Update tagged queuing modifier if using command tag queuing - */ - if (scsi_populate_tag_msg(cmd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - fcp_cmnd->task_attribute = TSK_HEAD_OF_QUEUE; - break; - case ORDERED_QUEUE_TAG: - fcp_cmnd->task_attribute = TSK_ORDERED; - break; - default: - fcp_cmnd->task_attribute = 0; - break; - } - } else { - fcp_cmnd->task_attribute = 0; - } - - cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */ - - /* Compute dif len and adjust data len to incude protection */ - dif_bytes = 0; - blk_size = cmd->device->sector_size; - dif_bytes = (data_bytes / blk_size) * 8; - - switch (scsi_get_prot_op(GET_CMD_SP(sp))) { - case SCSI_PROT_READ_INSERT: - case SCSI_PROT_WRITE_STRIP: - total_bytes = data_bytes; - data_bytes += dif_bytes; - break; - - case SCSI_PROT_READ_STRIP: - case SCSI_PROT_WRITE_INSERT: - case SCSI_PROT_READ_PASS: - case SCSI_PROT_WRITE_PASS: - total_bytes = data_bytes + dif_bytes; - break; - default: - BUG(); - } - - if (!qla2x00_hba_err_chk_enabled(sp)) - fw_prot_opts |= 0x10; /* Disable Guard tag checking */ - - if (!bundling) { - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.nobundling.data_address; - } else { - /* - * Configure Bundling if we need to fetch interlaving - * protection PCI accesses - */ - fw_prot_opts |= PO_ENABLE_DIF_BUNDLING; - crc_ctx_pkt->u.bundling.dif_byte_count = cpu_to_le32(dif_bytes); - crc_ctx_pkt->u.bundling.dseg_count = cpu_to_le16(tot_dsds - - tot_prot_dsds); - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.data_address; - } - - /* Finish the common fields of CRC pkt */ - crc_ctx_pkt->blk_size = cpu_to_le16(blk_size); - crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts); - crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes); - crc_ctx_pkt->guard_seed = __constant_cpu_to_le16(0); - /* Fibre channel byte count */ - cmd_pkt->byte_count = cpu_to_le32(total_bytes); - fcp_dl = (uint32_t *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 + - additional_fcpcdb_len); - *fcp_dl = htonl(total_bytes); - - if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); - return QLA_SUCCESS; - } - /* Walks data segments */ - - cmd_pkt->control_flags |= - __constant_cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); - - if (!bundling && tot_prot_dsds) { - if (qla24xx_walk_and_build_sglist_no_difb(ha, sp, - cur_dsd, tot_dsds)) - goto crc_queuing_error; - } else if (qla24xx_walk_and_build_sglist(ha, sp, cur_dsd, - (tot_dsds - tot_prot_dsds))) - goto crc_queuing_error; - - if (bundling && tot_prot_dsds) { - /* Walks dif segments */ - cur_seg = scsi_prot_sglist(cmd); - cmd_pkt->control_flags |= - __constant_cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE); - cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; - if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd, - tot_prot_dsds)) - goto crc_queuing_error; - } - return QLA_SUCCESS; - -crc_queuing_error: - /* Cleanup will be performed by the caller */ - - return QLA_FUNCTION_FAILED; -} - -/** - * qla24xx_start_scsi() - Send a SCSI command to the ISP - * @sp: command to send to the ISP - * - * Returns non-zero if a failure occurred, else zero. - */ -int -qla24xx_start_scsi(srb_t *sp) -{ - int ret, nseg; - unsigned long flags; - uint32_t *clr_ptr; - uint32_t index; - uint32_t handle; - struct cmd_type_7 *cmd_pkt; - uint16_t cnt; - uint16_t req_cnt; - uint16_t tot_dsds; - struct req_que *req = NULL; - struct rsp_que *rsp = NULL; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - struct scsi_qla_host *vha = sp->fcport->vha; - struct qla_hw_data *ha = vha->hw; - char tag[2]; - - /* Setup device pointers. */ - ret = 0; - - qla25xx_set_que(sp, &rsp); - req = vha->req; - - /* So we know we haven't pci_map'ed anything yet */ - tot_dsds = 0; - - /* Send marker if required */ - if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != - QLA_SUCCESS) - return QLA_FUNCTION_FAILED; - vha->marker_needed = 0; - } - - /* Acquire ring specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { - handle++; - if (handle == MAX_OUTSTANDING_COMMANDS) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == MAX_OUTSTANDING_COMMANDS) { - goto queuing_error; - } - - /* Map the sg table so we have an accurate count of sg entries needed */ - if (scsi_sg_count(cmd)) { - nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), - scsi_sg_count(cmd), cmd->sc_data_direction); - if (unlikely(!nseg)) - goto queuing_error; - } else - nseg = 0; - - tot_dsds = nseg; - req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); - if (req->cnt < (req_cnt + 2)) { - cnt = RD_REG_DWORD_RELAXED(req->req_q_out); - - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - if (req->cnt < (req_cnt + 2)) - goto queuing_error; - - /* Build command packet. */ - req->current_outstanding_cmd = handle; - req->outstanding_cmds[handle] = sp; - sp->handle = handle; - cmd->host_scribble = (unsigned char *)(unsigned long)handle; - req->cnt -= req_cnt; - - cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); - - /* Zero out remaining portion of packet. */ - /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ - clr_ptr = (uint32_t *)cmd_pkt + 2; - memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); - cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); - - /* Set NPORT-ID and LUN number*/ - cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); - cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; - cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; - cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - cmd_pkt->vp_index = sp->fcport->vp_idx; - - int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); - host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); - - /* Update tagged queuing modifier -- default is TSK_SIMPLE (0). */ - if (scsi_populate_tag_msg(cmd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - cmd_pkt->task = TSK_HEAD_OF_QUEUE; - break; - case ORDERED_QUEUE_TAG: - cmd_pkt->task = TSK_ORDERED; - break; - } - } - - /* Load SCSI command packet. */ - memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); - host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); - - cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); - - /* Build IOCB segments */ - qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds); - - /* Set total data segment count. */ - cmd_pkt->entry_count = (uint8_t)req_cnt; - /* Specify response queue number where completion should happen */ - cmd_pkt->entry_status = (uint8_t) rsp->id; - wmb(); - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else - req->ring_ptr++; - - sp->flags |= SRB_DMA_VALID; - - /* Set chip new ring index. */ - WRT_REG_DWORD(req->req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); - - /* Manage unprocessed RIO/ZIO commands in response queue. */ - if (vha->flags.process_response_queue && - rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(vha, rsp); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return QLA_SUCCESS; - -queuing_error: - if (tot_dsds) - scsi_dma_unmap(cmd); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_FUNCTION_FAILED; -} - - -/** - * qla24xx_dif_start_scsi() - Send a SCSI command to the ISP - * @sp: command to send to the ISP - * - * Returns non-zero if a failure occurred, else zero. - */ -int -qla24xx_dif_start_scsi(srb_t *sp) -{ - int nseg; - unsigned long flags; - uint32_t *clr_ptr; - uint32_t index; - uint32_t handle; - uint16_t cnt; - uint16_t req_cnt = 0; - uint16_t tot_dsds; - uint16_t tot_prot_dsds; - uint16_t fw_prot_opts = 0; - struct req_que *req = NULL; - struct rsp_que *rsp = NULL; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - struct scsi_qla_host *vha = sp->fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct cmd_type_crc_2 *cmd_pkt; - uint32_t status = 0; - -#define QDSS_GOT_Q_SPACE BIT_0 - - /* Only process protection or >16 cdb in this routine */ - if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { - if (cmd->cmd_len <= 16) - return qla24xx_start_scsi(sp); - } - - /* Setup device pointers. */ - - qla25xx_set_que(sp, &rsp); - req = vha->req; - - /* So we know we haven't pci_map'ed anything yet */ - tot_dsds = 0; - - /* Send marker if required */ - if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != - QLA_SUCCESS) - return QLA_FUNCTION_FAILED; - vha->marker_needed = 0; - } - - /* Acquire ring specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { - handle++; - if (handle == MAX_OUTSTANDING_COMMANDS) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - - if (index == MAX_OUTSTANDING_COMMANDS) - goto queuing_error; - - /* Compute number of required data segments */ - /* Map the sg table so we have an accurate count of sg entries needed */ - if (scsi_sg_count(cmd)) { - nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), - scsi_sg_count(cmd), cmd->sc_data_direction); - if (unlikely(!nseg)) - goto queuing_error; - else - sp->flags |= SRB_DMA_VALID; - - if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || - (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { - struct qla2_sgx sgx; - uint32_t partial; - - memset(&sgx, 0, sizeof(struct qla2_sgx)); - sgx.tot_bytes = scsi_bufflen(cmd); - sgx.cur_sg = scsi_sglist(cmd); - sgx.sp = sp; - - nseg = 0; - while (qla24xx_get_one_block_sg( - cmd->device->sector_size, &sgx, &partial)) - nseg++; - } - } else - nseg = 0; - - /* number of required data segments */ - tot_dsds = nseg; - - /* Compute number of required protection segments */ - if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) { - nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), - scsi_prot_sg_count(cmd), cmd->sc_data_direction); - if (unlikely(!nseg)) - goto queuing_error; - else - sp->flags |= SRB_CRC_PROT_DMA_VALID; - - if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || - (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { - nseg = scsi_bufflen(cmd) / cmd->device->sector_size; - } - } else { - nseg = 0; - } - - req_cnt = 1; - /* Total Data and protection sg segment(s) */ - tot_prot_dsds = nseg; - tot_dsds += nseg; - if (req->cnt < (req_cnt + 2)) { - cnt = RD_REG_DWORD_RELAXED(req->req_q_out); - - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - - if (req->cnt < (req_cnt + 2)) - goto queuing_error; - - status |= QDSS_GOT_Q_SPACE; - - /* Build header part of command packet (excluding the OPCODE). */ - req->current_outstanding_cmd = handle; - req->outstanding_cmds[handle] = sp; - sp->handle = handle; - cmd->host_scribble = (unsigned char *)(unsigned long)handle; - req->cnt -= req_cnt; - - /* Fill-in common area */ - cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); - - clr_ptr = (uint32_t *)cmd_pkt + 2; - memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); - - /* Set NPORT-ID and LUN number*/ - cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); - cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; - cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; - cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - - int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); - host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); - - /* Total Data and protection segment(s) */ - cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); - - /* Build IOCB segments and adjust for data protection segments */ - if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *) - req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) != - QLA_SUCCESS) - goto queuing_error; - - cmd_pkt->entry_count = (uint8_t)req_cnt; - /* Specify response queue number where completion should happen */ - cmd_pkt->entry_status = (uint8_t) rsp->id; - cmd_pkt->timeout = __constant_cpu_to_le16(0); - wmb(); - - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else - req->ring_ptr++; - - /* Set chip new ring index. */ - WRT_REG_DWORD(req->req_q_in, req->ring_index); - RD_REG_DWORD_RELAXED(&ha->iobase->isp24.hccr); - - /* Manage unprocessed RIO/ZIO commands in response queue. */ - if (vha->flags.process_response_queue && - rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(vha, rsp); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_SUCCESS; - -queuing_error: - if (status & QDSS_GOT_Q_SPACE) { - req->outstanding_cmds[handle] = NULL; - req->cnt += req_cnt; - } - /* Cleanup will be performed by the caller (queuecommand) */ - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return QLA_FUNCTION_FAILED; -} - - -static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp) -{ - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - struct qla_hw_data *ha = sp->fcport->vha->hw; - int affinity = cmd->request->cpu; - - if (ha->flags.cpu_affinity_enabled && affinity >= 0 && - affinity < ha->max_rsp_queues - 1) - *rsp = ha->rsp_q_map[affinity + 1]; - else - *rsp = ha->rsp_q_map[0]; -} - -/* Generic Control-SRB manipulation functions. */ -void * -qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp) -{ - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); - uint32_t index, handle; - request_t *pkt; - uint16_t cnt, req_cnt; - - pkt = NULL; - req_cnt = 1; - handle = 0; - - if (!sp) - goto skip_cmd_array; - - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { - handle++; - if (handle == MAX_OUTSTANDING_COMMANDS) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == MAX_OUTSTANDING_COMMANDS) { - ql_log(ql_log_warn, vha, 0x700b, - "No room on oustanding cmd array.\n"); - goto queuing_error; - } - - /* Prep command array. */ - req->current_outstanding_cmd = handle; - req->outstanding_cmds[handle] = sp; - sp->handle = handle; - - /* Adjust entry-counts as needed. */ - if (sp->type != SRB_SCSI_CMD) - req_cnt = sp->iocbs; - -skip_cmd_array: - /* Check for room on request queue. */ - if (req->cnt < req_cnt) { - if (ha->mqenable || IS_QLA83XX(ha)) - cnt = RD_REG_DWORD(®->isp25mq.req_q_out); - else if (IS_QLA82XX(ha)) - cnt = RD_REG_DWORD(®->isp82.req_q_out); - else if (IS_FWI2_CAPABLE(ha)) - cnt = RD_REG_DWORD(®->isp24.req_q_out); - else - cnt = qla2x00_debounce_register( - ISP_REQ_Q_OUT(ha, ®->isp)); - - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - if (req->cnt < req_cnt) - goto queuing_error; - - /* Prep packet */ - req->cnt -= req_cnt; - pkt = req->ring_ptr; - memset(pkt, 0, REQUEST_ENTRY_SIZE); - pkt->entry_count = req_cnt; - pkt->handle = handle; - -queuing_error: - return pkt; -} - -static void -qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) -{ - struct srb_iocb *lio = &sp->u.iocb_cmd; - - logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; - logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); - if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI) - logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); - if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI) - logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); - logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); - logio->port_id[0] = sp->fcport->d_id.b.al_pa; - logio->port_id[1] = sp->fcport->d_id.b.area; - logio->port_id[2] = sp->fcport->d_id.b.domain; - logio->vp_index = sp->fcport->vp_idx; -} - -static void -qla2x00_login_iocb(srb_t *sp, struct mbx_entry *mbx) -{ - struct qla_hw_data *ha = sp->fcport->vha->hw; - struct srb_iocb *lio = &sp->u.iocb_cmd; - uint16_t opts; - - mbx->entry_type = MBX_IOCB_TYPE; - SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); - mbx->mb0 = cpu_to_le16(MBC_LOGIN_FABRIC_PORT); - opts = lio->u.logio.flags & SRB_LOGIN_COND_PLOGI ? BIT_0 : 0; - opts |= lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI ? BIT_1 : 0; - if (HAS_EXTENDED_IDS(ha)) { - mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); - mbx->mb10 = cpu_to_le16(opts); - } else { - mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | opts); - } - mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); - mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | - sp->fcport->d_id.b.al_pa); - mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); -} - -static void -qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) -{ - logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; - logio->control_flags = - cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); - logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); - logio->port_id[0] = sp->fcport->d_id.b.al_pa; - logio->port_id[1] = sp->fcport->d_id.b.area; - logio->port_id[2] = sp->fcport->d_id.b.domain; - logio->vp_index = sp->fcport->vp_idx; -} - -static void -qla2x00_logout_iocb(srb_t *sp, struct mbx_entry *mbx) -{ - struct qla_hw_data *ha = sp->fcport->vha->hw; - - mbx->entry_type = MBX_IOCB_TYPE; - SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); - mbx->mb0 = cpu_to_le16(MBC_LOGOUT_FABRIC_PORT); - mbx->mb1 = HAS_EXTENDED_IDS(ha) ? - cpu_to_le16(sp->fcport->loop_id): - cpu_to_le16(sp->fcport->loop_id << 8); - mbx->mb2 = cpu_to_le16(sp->fcport->d_id.b.domain); - mbx->mb3 = cpu_to_le16(sp->fcport->d_id.b.area << 8 | - sp->fcport->d_id.b.al_pa); - mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); - /* Implicit: mbx->mbx10 = 0. */ -} - -static void -qla24xx_adisc_iocb(srb_t *sp, struct logio_entry_24xx *logio) -{ - logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; - logio->control_flags = cpu_to_le16(LCF_COMMAND_ADISC); - logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); - logio->vp_index = sp->fcport->vp_idx; -} - -static void -qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx) -{ - struct qla_hw_data *ha = sp->fcport->vha->hw; - - mbx->entry_type = MBX_IOCB_TYPE; - SET_TARGET_ID(ha, mbx->loop_id, sp->fcport->loop_id); - mbx->mb0 = cpu_to_le16(MBC_GET_PORT_DATABASE); - if (HAS_EXTENDED_IDS(ha)) { - mbx->mb1 = cpu_to_le16(sp->fcport->loop_id); - mbx->mb10 = cpu_to_le16(BIT_0); - } else { - mbx->mb1 = cpu_to_le16((sp->fcport->loop_id << 8) | BIT_0); - } - mbx->mb2 = cpu_to_le16(MSW(ha->async_pd_dma)); - mbx->mb3 = cpu_to_le16(LSW(ha->async_pd_dma)); - mbx->mb6 = cpu_to_le16(MSW(MSD(ha->async_pd_dma))); - mbx->mb7 = cpu_to_le16(LSW(MSD(ha->async_pd_dma))); - mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx); -} - -static void -qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk) -{ - uint32_t flags; - unsigned int lun; - struct fc_port *fcport = sp->fcport; - scsi_qla_host_t *vha = fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct srb_iocb *iocb = &sp->u.iocb_cmd; - struct req_que *req = vha->req; - - flags = iocb->u.tmf.flags; - lun = iocb->u.tmf.lun; - - tsk->entry_type = TSK_MGMT_IOCB_TYPE; - tsk->entry_count = 1; - tsk->handle = MAKE_HANDLE(req->id, tsk->handle); - tsk->nport_handle = cpu_to_le16(fcport->loop_id); - tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - tsk->control_flags = cpu_to_le32(flags); - tsk->port_id[0] = fcport->d_id.b.al_pa; - tsk->port_id[1] = fcport->d_id.b.area; - tsk->port_id[2] = fcport->d_id.b.domain; - tsk->vp_index = fcport->vp_idx; - - if (flags == TCF_LUN_RESET) { - int_to_scsilun(lun, &tsk->lun); - host_to_fcp_swap((uint8_t *)&tsk->lun, - sizeof(tsk->lun)); - } -} - -static void -qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) -{ - struct fc_bsg_job *bsg_job = sp->u.bsg_job; - - els_iocb->entry_type = ELS_IOCB_TYPE; - els_iocb->entry_count = 1; - els_iocb->sys_define = 0; - els_iocb->entry_status = 0; - els_iocb->handle = sp->handle; - els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); - els_iocb->tx_dsd_count = __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); - els_iocb->vp_index = sp->fcport->vp_idx; - els_iocb->sof_type = EST_SOFI3; - els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); - - els_iocb->opcode = - sp->type == SRB_ELS_CMD_RPT ? - bsg_job->request->rqst_data.r_els.els_code : - bsg_job->request->rqst_data.h_els.command_code; - els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; - els_iocb->port_id[1] = sp->fcport->d_id.b.area; - els_iocb->port_id[2] = sp->fcport->d_id.b.domain; - els_iocb->control_flags = 0; - els_iocb->rx_byte_count = - cpu_to_le32(bsg_job->reply_payload.payload_len); - els_iocb->tx_byte_count = - cpu_to_le32(bsg_job->request_payload.payload_len); - - els_iocb->tx_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - els_iocb->tx_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - els_iocb->tx_len = cpu_to_le32(sg_dma_len - (bsg_job->request_payload.sg_list)); - - els_iocb->rx_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->reply_payload.sg_list))); - els_iocb->rx_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->reply_payload.sg_list))); - els_iocb->rx_len = cpu_to_le32(sg_dma_len - (bsg_job->reply_payload.sg_list)); -} - -static void -qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) -{ - uint16_t avail_dsds; - uint32_t *cur_dsd; - struct scatterlist *sg; - int index; - uint16_t tot_dsds; - scsi_qla_host_t *vha = sp->fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct fc_bsg_job *bsg_job = sp->u.bsg_job; - int loop_iterartion = 0; - int cont_iocb_prsnt = 0; - int entry_count = 1; - - memset(ct_iocb, 0, sizeof(ms_iocb_entry_t)); - ct_iocb->entry_type = CT_IOCB_TYPE; - ct_iocb->entry_status = 0; - ct_iocb->handle1 = sp->handle; - SET_TARGET_ID(ha, ct_iocb->loop_id, sp->fcport->loop_id); - ct_iocb->status = __constant_cpu_to_le16(0); - ct_iocb->control_flags = __constant_cpu_to_le16(0); - ct_iocb->timeout = 0; - ct_iocb->cmd_dsd_count = - __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); - ct_iocb->total_dsd_count = - __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt + 1); - ct_iocb->req_bytecount = - cpu_to_le32(bsg_job->request_payload.payload_len); - ct_iocb->rsp_bytecount = - cpu_to_le32(bsg_job->reply_payload.payload_len); - - ct_iocb->dseg_req_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - ct_iocb->dseg_req_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - ct_iocb->dseg_req_length = ct_iocb->req_bytecount; - - ct_iocb->dseg_rsp_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->reply_payload.sg_list))); - ct_iocb->dseg_rsp_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->reply_payload.sg_list))); - ct_iocb->dseg_rsp_length = ct_iocb->rsp_bytecount; - - avail_dsds = 1; - cur_dsd = (uint32_t *)ct_iocb->dseg_rsp_address; - index = 0; - tot_dsds = bsg_job->reply_payload.sg_cnt; - - for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { - dma_addr_t sle_dma; - cont_a64_entry_t *cont_pkt; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - /* - * Five DSDs are available in the Cont. - * Type 1 IOCB. - */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha, - vha->hw->req_q_map[0]); - cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; - avail_dsds = 5; - cont_iocb_prsnt = 1; - entry_count++; - } - - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - loop_iterartion++; - avail_dsds--; - } - ct_iocb->entry_count = entry_count; -} - -static void -qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) -{ - uint16_t avail_dsds; - uint32_t *cur_dsd; - struct scatterlist *sg; - int index; - uint16_t tot_dsds; - scsi_qla_host_t *vha = sp->fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct fc_bsg_job *bsg_job = sp->u.bsg_job; - int loop_iterartion = 0; - int cont_iocb_prsnt = 0; - int entry_count = 1; - - ct_iocb->entry_type = CT_IOCB_TYPE; - ct_iocb->entry_status = 0; - ct_iocb->sys_define = 0; - ct_iocb->handle = sp->handle; - - ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); - ct_iocb->vp_index = sp->fcport->vp_idx; - ct_iocb->comp_status = __constant_cpu_to_le16(0); - - ct_iocb->cmd_dsd_count = - __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); - ct_iocb->timeout = 0; - ct_iocb->rsp_dsd_count = - __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); - ct_iocb->rsp_byte_count = - cpu_to_le32(bsg_job->reply_payload.payload_len); - ct_iocb->cmd_byte_count = - cpu_to_le32(bsg_job->request_payload.payload_len); - ct_iocb->dseg_0_address[0] = cpu_to_le32(LSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - ct_iocb->dseg_0_address[1] = cpu_to_le32(MSD(sg_dma_address - (bsg_job->request_payload.sg_list))); - ct_iocb->dseg_0_len = cpu_to_le32(sg_dma_len - (bsg_job->request_payload.sg_list)); - - avail_dsds = 1; - cur_dsd = (uint32_t *)ct_iocb->dseg_1_address; - index = 0; - tot_dsds = bsg_job->reply_payload.sg_cnt; - - for_each_sg(bsg_job->reply_payload.sg_list, sg, tot_dsds, index) { - dma_addr_t sle_dma; - cont_a64_entry_t *cont_pkt; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - /* - * Five DSDs are available in the Cont. - * Type 1 IOCB. - */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha, - ha->req_q_map[0]); - cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; - avail_dsds = 5; - cont_iocb_prsnt = 1; - entry_count++; - } - - sle_dma = sg_dma_address(sg); - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); - loop_iterartion++; - avail_dsds--; - } - ct_iocb->entry_count = entry_count; -} - -/* - * qla82xx_start_scsi() - Send a SCSI command to the ISP - * @sp: command to send to the ISP - * - * Returns non-zero if a failure occurred, else zero. - */ -int -qla82xx_start_scsi(srb_t *sp) -{ - int ret, nseg; - unsigned long flags; - struct scsi_cmnd *cmd; - uint32_t *clr_ptr; - uint32_t index; - uint32_t handle; - uint16_t cnt; - uint16_t req_cnt; - uint16_t tot_dsds; - struct device_reg_82xx __iomem *reg; - uint32_t dbval; - uint32_t *fcp_dl; - uint8_t additional_cdb_len; - struct ct6_dsd *ctx; - struct scsi_qla_host *vha = sp->fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = NULL; - struct rsp_que *rsp = NULL; - char tag[2]; - - /* Setup device pointers. */ - ret = 0; - reg = &ha->iobase->isp82; - cmd = GET_CMD_SP(sp); - req = vha->req; - rsp = ha->rsp_q_map[0]; - - /* So we know we haven't pci_map'ed anything yet */ - tot_dsds = 0; - - dbval = 0x04 | (ha->portnum << 5); - - /* Send marker if required */ - if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, - rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x300c, - "qla2x00_marker failed for cmd=%p.\n", cmd); - return QLA_FUNCTION_FAILED; - } - vha->marker_needed = 0; - } - - /* Acquire ring specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Check for room in outstanding command list. */ - handle = req->current_outstanding_cmd; - for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) { - handle++; - if (handle == MAX_OUTSTANDING_COMMANDS) - handle = 1; - if (!req->outstanding_cmds[handle]) - break; - } - if (index == MAX_OUTSTANDING_COMMANDS) - goto queuing_error; - - /* Map the sg table so we have an accurate count of sg entries needed */ - if (scsi_sg_count(cmd)) { - nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), - scsi_sg_count(cmd), cmd->sc_data_direction); - if (unlikely(!nseg)) - goto queuing_error; - } else - nseg = 0; - - tot_dsds = nseg; - - if (tot_dsds > ql2xshiftctondsd) { - struct cmd_type_6 *cmd_pkt; - uint16_t more_dsd_lists = 0; - struct dsd_dma *dsd_ptr; - uint16_t i; - - more_dsd_lists = qla24xx_calc_dsd_lists(tot_dsds); - if ((more_dsd_lists + ha->gbl_dsd_inuse) >= NUM_DSD_CHAIN) { - ql_dbg(ql_dbg_io, vha, 0x300d, - "Num of DSD list %d is than %d for cmd=%p.\n", - more_dsd_lists + ha->gbl_dsd_inuse, NUM_DSD_CHAIN, - cmd); - goto queuing_error; - } - - if (more_dsd_lists <= ha->gbl_dsd_avail) - goto sufficient_dsds; - else - more_dsd_lists -= ha->gbl_dsd_avail; - - for (i = 0; i < more_dsd_lists; i++) { - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); - if (!dsd_ptr) { - ql_log(ql_log_fatal, vha, 0x300e, - "Failed to allocate memory for dsd_dma " - "for cmd=%p.\n", cmd); - goto queuing_error; - } - - dsd_ptr->dsd_addr = dma_pool_alloc(ha->dl_dma_pool, - GFP_ATOMIC, &dsd_ptr->dsd_list_dma); - if (!dsd_ptr->dsd_addr) { - kfree(dsd_ptr); - ql_log(ql_log_fatal, vha, 0x300f, - "Failed to allocate memory for dsd_addr " - "for cmd=%p.\n", cmd); - goto queuing_error; - } - list_add_tail(&dsd_ptr->list, &ha->gbl_dsd_list); - ha->gbl_dsd_avail++; - } - -sufficient_dsds: - req_cnt = 1; - - if (req->cnt < (req_cnt + 2)) { - cnt = (uint16_t)RD_REG_DWORD_RELAXED( - ®->req_q_out[0]); - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - - if (req->cnt < (req_cnt + 2)) - goto queuing_error; - - ctx = sp->u.scmd.ctx = - mempool_alloc(ha->ctx_mempool, GFP_ATOMIC); - if (!ctx) { - ql_log(ql_log_fatal, vha, 0x3010, - "Failed to allocate ctx for cmd=%p.\n", cmd); - goto queuing_error; - } - - memset(ctx, 0, sizeof(struct ct6_dsd)); - ctx->fcp_cmnd = dma_pool_alloc(ha->fcp_cmnd_dma_pool, - GFP_ATOMIC, &ctx->fcp_cmnd_dma); - if (!ctx->fcp_cmnd) { - ql_log(ql_log_fatal, vha, 0x3011, - "Failed to allocate fcp_cmnd for cmd=%p.\n", cmd); - goto queuing_error_fcp_cmnd; - } - - /* Initialize the DSD list and dma handle */ - INIT_LIST_HEAD(&ctx->dsd_list); - ctx->dsd_use_cnt = 0; - - if (cmd->cmd_len > 16) { - additional_cdb_len = cmd->cmd_len - 16; - if ((cmd->cmd_len % 4) != 0) { - /* SCSI command bigger than 16 bytes must be - * multiple of 4 - */ - ql_log(ql_log_warn, vha, 0x3012, - "scsi cmd len %d not multiple of 4 " - "for cmd=%p.\n", cmd->cmd_len, cmd); - goto queuing_error_fcp_cmnd; - } - ctx->fcp_cmnd_len = 12 + cmd->cmd_len + 4; - } else { - additional_cdb_len = 0; - ctx->fcp_cmnd_len = 12 + 16 + 4; - } - - cmd_pkt = (struct cmd_type_6 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); - - /* Zero out remaining portion of packet. */ - /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ - clr_ptr = (uint32_t *)cmd_pkt + 2; - memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); - cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); - - /* Set NPORT-ID and LUN number*/ - cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); - cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; - cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; - cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - cmd_pkt->vp_index = sp->fcport->vp_idx; - - /* Build IOCB segments */ - if (qla24xx_build_scsi_type_6_iocbs(sp, cmd_pkt, tot_dsds)) - goto queuing_error_fcp_cmnd; - - int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); - host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); - - /* build FCP_CMND IU */ - memset(ctx->fcp_cmnd, 0, sizeof(struct fcp_cmnd)); - int_to_scsilun(cmd->device->lun, &ctx->fcp_cmnd->lun); - ctx->fcp_cmnd->additional_cdb_len = additional_cdb_len; - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - ctx->fcp_cmnd->additional_cdb_len |= 1; - else if (cmd->sc_data_direction == DMA_FROM_DEVICE) - ctx->fcp_cmnd->additional_cdb_len |= 2; - - /* - * Update tagged queuing modifier -- default is TSK_SIMPLE (0). - */ - if (scsi_populate_tag_msg(cmd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - ctx->fcp_cmnd->task_attribute = - TSK_HEAD_OF_QUEUE; - break; - case ORDERED_QUEUE_TAG: - ctx->fcp_cmnd->task_attribute = - TSK_ORDERED; - break; - } - } - - /* Populate the FCP_PRIO. */ - if (ha->flags.fcp_prio_enabled) - ctx->fcp_cmnd->task_attribute |= - sp->fcport->fcp_prio << 3; - - memcpy(ctx->fcp_cmnd->cdb, cmd->cmnd, cmd->cmd_len); - - fcp_dl = (uint32_t *)(ctx->fcp_cmnd->cdb + 16 + - additional_cdb_len); - *fcp_dl = htonl((uint32_t)scsi_bufflen(cmd)); - - cmd_pkt->fcp_cmnd_dseg_len = cpu_to_le16(ctx->fcp_cmnd_len); - cmd_pkt->fcp_cmnd_dseg_address[0] = - cpu_to_le32(LSD(ctx->fcp_cmnd_dma)); - cmd_pkt->fcp_cmnd_dseg_address[1] = - cpu_to_le32(MSD(ctx->fcp_cmnd_dma)); - - sp->flags |= SRB_FCP_CMND_DMA_VALID; - cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); - /* Set total data segment count. */ - cmd_pkt->entry_count = (uint8_t)req_cnt; - /* Specify response queue number where - * completion should happen - */ - cmd_pkt->entry_status = (uint8_t) rsp->id; - } else { - struct cmd_type_7 *cmd_pkt; - req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); - if (req->cnt < (req_cnt + 2)) { - cnt = (uint16_t)RD_REG_DWORD_RELAXED( - ®->req_q_out[0]); - if (req->ring_index < cnt) - req->cnt = cnt - req->ring_index; - else - req->cnt = req->length - - (req->ring_index - cnt); - } - if (req->cnt < (req_cnt + 2)) - goto queuing_error; - - cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; - cmd_pkt->handle = MAKE_HANDLE(req->id, handle); - - /* Zero out remaining portion of packet. */ - /* tagged queuing modifier -- default is TSK_SIMPLE (0).*/ - clr_ptr = (uint32_t *)cmd_pkt + 2; - memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); - cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); - - /* Set NPORT-ID and LUN number*/ - cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); - cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; - cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; - cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - cmd_pkt->vp_index = sp->fcport->vp_idx; - - int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); - host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, - sizeof(cmd_pkt->lun)); - - /* - * Update tagged queuing modifier -- default is TSK_SIMPLE (0). - */ - if (scsi_populate_tag_msg(cmd, tag)) { - switch (tag[0]) { - case HEAD_OF_QUEUE_TAG: - cmd_pkt->task = TSK_HEAD_OF_QUEUE; - break; - case ORDERED_QUEUE_TAG: - cmd_pkt->task = TSK_ORDERED; - break; - } - } - - /* Populate the FCP_PRIO. */ - if (ha->flags.fcp_prio_enabled) - cmd_pkt->task |= sp->fcport->fcp_prio << 3; - - /* Load SCSI command packet. */ - memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); - host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); - - cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); - - /* Build IOCB segments */ - qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds); - - /* Set total data segment count. */ - cmd_pkt->entry_count = (uint8_t)req_cnt; - /* Specify response queue number where - * completion should happen. - */ - cmd_pkt->entry_status = (uint8_t) rsp->id; - - } - /* Build command packet. */ - req->current_outstanding_cmd = handle; - req->outstanding_cmds[handle] = sp; - sp->handle = handle; - cmd->host_scribble = (unsigned char *)(unsigned long)handle; - req->cnt -= req_cnt; - wmb(); - - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else - req->ring_ptr++; - - sp->flags |= SRB_DMA_VALID; - - /* Set chip new ring index. */ - /* write, read and verify logic */ - dbval = dbval | (req->id << 8) | (req->ring_index << 16); - if (ql2xdbwr) - qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); - else { - WRT_REG_DWORD( - (unsigned long __iomem *)ha->nxdb_wr_ptr, - dbval); - wmb(); - while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { - WRT_REG_DWORD( - (unsigned long __iomem *)ha->nxdb_wr_ptr, - dbval); - wmb(); - } - } - - /* Manage unprocessed RIO/ZIO commands in response queue. */ - if (vha->flags.process_response_queue && - rsp->ring_ptr->signature != RESPONSE_PROCESSED) - qla24xx_process_response_queue(vha, rsp); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return QLA_SUCCESS; - -queuing_error_fcp_cmnd: - dma_pool_free(ha->fcp_cmnd_dma_pool, ctx->fcp_cmnd, ctx->fcp_cmnd_dma); -queuing_error: - if (tot_dsds) - scsi_dma_unmap(cmd); - - if (sp->u.scmd.ctx) { - mempool_free(sp->u.scmd.ctx, ha->ctx_mempool); - sp->u.scmd.ctx = NULL; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_FUNCTION_FAILED; -} - -int -qla2x00_start_sp(srb_t *sp) -{ - int rval; - struct qla_hw_data *ha = sp->fcport->vha->hw; - void *pkt; - unsigned long flags; - - rval = QLA_FUNCTION_FAILED; - spin_lock_irqsave(&ha->hardware_lock, flags); - pkt = qla2x00_alloc_iocbs(sp->fcport->vha, sp); - if (!pkt) { - ql_log(ql_log_warn, sp->fcport->vha, 0x700c, - "qla2x00_alloc_iocbs failed.\n"); - goto done; - } - - rval = QLA_SUCCESS; - switch (sp->type) { - case SRB_LOGIN_CMD: - IS_FWI2_CAPABLE(ha) ? - qla24xx_login_iocb(sp, pkt) : - qla2x00_login_iocb(sp, pkt); - break; - case SRB_LOGOUT_CMD: - IS_FWI2_CAPABLE(ha) ? - qla24xx_logout_iocb(sp, pkt) : - qla2x00_logout_iocb(sp, pkt); - break; - case SRB_ELS_CMD_RPT: - case SRB_ELS_CMD_HST: - qla24xx_els_iocb(sp, pkt); - break; - case SRB_CT_CMD: - IS_FWI2_CAPABLE(ha) ? - qla24xx_ct_iocb(sp, pkt) : - qla2x00_ct_iocb(sp, pkt); - break; - case SRB_ADISC_CMD: - IS_FWI2_CAPABLE(ha) ? - qla24xx_adisc_iocb(sp, pkt) : - qla2x00_adisc_iocb(sp, pkt); - break; - case SRB_TM_CMD: - qla24xx_tm_iocb(sp, pkt); - break; - default: - break; - } - - wmb(); - qla2x00_start_iocbs(sp->fcport->vha, ha->req_q_map[0]); -done: - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return rval; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_isr.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_isr.c deleted file mode 100644 index ce422880..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_isr.c +++ /dev/null @@ -1,2597 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -#include -#include -#include -#include -#include - -static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t); -static void qla2x00_process_completed_request(struct scsi_qla_host *, - struct req_que *, uint32_t); -static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *); -static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *); -static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, - sts_entry_t *); - -/** - * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. - * @irq: - * @dev_id: SCSI driver HA context - * - * Called by system whenever the host adapter generates an interrupt. - * - * Returns handled flag. - */ -irqreturn_t -qla2100_intr_handler(int irq, void *dev_id) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct device_reg_2xxx __iomem *reg; - int status; - unsigned long iter; - uint16_t hccr; - uint16_t mb[4]; - struct rsp_que *rsp; - unsigned long flags; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - ql_log(ql_log_info, NULL, 0x505d, - "%s: NULL response queue pointer.\n", __func__); - return (IRQ_NONE); - } - - ha = rsp->hw; - reg = &ha->iobase->isp; - status = 0; - - spin_lock_irqsave(&ha->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - for (iter = 50; iter--; ) { - hccr = RD_REG_WORD(®->hccr); - if (hccr & HCCR_RISC_PAUSE) { - if (pci_channel_offline(ha->pdev)) - break; - - /* - * Issue a "HARD" reset in order for the RISC interrupt - * bit to be cleared. Schedule a big hammer to get - * out of the RISC PAUSED state. - */ - WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); - RD_REG_WORD(®->hccr); - - ha->isp_ops->fw_dump(vha, 1); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - } else if ((RD_REG_WORD(®->istatus) & ISR_RISC_INT) == 0) - break; - - if (RD_REG_WORD(®->semaphore) & BIT_0) { - WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); - RD_REG_WORD(®->hccr); - - /* Get mailbox data. */ - mb[0] = RD_MAILBOX_REG(ha, reg, 0); - if (mb[0] > 0x3fff && mb[0] < 0x8000) { - qla2x00_mbx_completion(vha, mb[0]); - status |= MBX_INTERRUPT; - } else if (mb[0] > 0x7fff && mb[0] < 0xc000) { - mb[1] = RD_MAILBOX_REG(ha, reg, 1); - mb[2] = RD_MAILBOX_REG(ha, reg, 2); - mb[3] = RD_MAILBOX_REG(ha, reg, 3); - qla2x00_async_event(vha, rsp, mb); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_async, vha, 0x5025, - "Unrecognized interrupt type (%d).\n", - mb[0]); - } - /* Release mailbox registers. */ - WRT_REG_WORD(®->semaphore, 0); - RD_REG_WORD(®->semaphore); - } else { - qla2x00_process_response_queue(rsp); - - WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); - RD_REG_WORD(®->hccr); - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && - (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - complete(&ha->mbx_intr_comp); - } - - return (IRQ_HANDLED); -} - -/** - * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. - * @irq: - * @dev_id: SCSI driver HA context - * - * Called by system whenever the host adapter generates an interrupt. - * - * Returns handled flag. - */ -irqreturn_t -qla2300_intr_handler(int irq, void *dev_id) -{ - scsi_qla_host_t *vha; - struct device_reg_2xxx __iomem *reg; - int status; - unsigned long iter; - uint32_t stat; - uint16_t hccr; - uint16_t mb[4]; - struct rsp_que *rsp; - struct qla_hw_data *ha; - unsigned long flags; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - ql_log(ql_log_info, NULL, 0x5058, - "%s: NULL response queue pointer.\n", __func__); - return (IRQ_NONE); - } - - ha = rsp->hw; - reg = &ha->iobase->isp; - status = 0; - - spin_lock_irqsave(&ha->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - for (iter = 50; iter--; ) { - stat = RD_REG_DWORD(®->u.isp2300.host_status); - if (stat & HSR_RISC_PAUSED) { - if (unlikely(pci_channel_offline(ha->pdev))) - break; - - hccr = RD_REG_WORD(®->hccr); - if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8)) - ql_log(ql_log_warn, vha, 0x5026, - "Parity error -- HCCR=%x, Dumping " - "firmware.\n", hccr); - else - ql_log(ql_log_warn, vha, 0x5027, - "RISC paused -- HCCR=%x, Dumping " - "firmware.\n", hccr); - - /* - * Issue a "HARD" reset in order for the RISC - * interrupt bit to be cleared. Schedule a big - * hammer to get out of the RISC PAUSED state. - */ - WRT_REG_WORD(®->hccr, HCCR_RESET_RISC); - RD_REG_WORD(®->hccr); - - ha->isp_ops->fw_dump(vha, 1); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - } else if ((stat & HSR_RISC_INT) == 0) - break; - - switch (stat & 0xff) { - case 0x1: - case 0x2: - case 0x10: - case 0x11: - qla2x00_mbx_completion(vha, MSW(stat)); - status |= MBX_INTERRUPT; - - /* Release mailbox registers. */ - WRT_REG_WORD(®->semaphore, 0); - break; - case 0x12: - mb[0] = MSW(stat); - mb[1] = RD_MAILBOX_REG(ha, reg, 1); - mb[2] = RD_MAILBOX_REG(ha, reg, 2); - mb[3] = RD_MAILBOX_REG(ha, reg, 3); - qla2x00_async_event(vha, rsp, mb); - break; - case 0x13: - qla2x00_process_response_queue(rsp); - break; - case 0x15: - mb[0] = MBA_CMPLT_1_16BIT; - mb[1] = MSW(stat); - qla2x00_async_event(vha, rsp, mb); - break; - case 0x16: - mb[0] = MBA_SCSI_COMPLETION; - mb[1] = MSW(stat); - mb[2] = RD_MAILBOX_REG(ha, reg, 2); - qla2x00_async_event(vha, rsp, mb); - break; - default: - ql_dbg(ql_dbg_async, vha, 0x5028, - "Unrecognized interrupt type (%d).\n", stat & 0xff); - break; - } - WRT_REG_WORD(®->hccr, HCCR_CLR_RISC_INT); - RD_REG_WORD_RELAXED(®->hccr); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && - (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - complete(&ha->mbx_intr_comp); - } - - return (IRQ_HANDLED); -} - -/** - * qla2x00_mbx_completion() - Process mailbox command completions. - * @ha: SCSI driver HA context - * @mb0: Mailbox0 register - */ -static void -qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) -{ - uint16_t cnt; - uint32_t mboxes; - uint16_t __iomem *wptr; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; - if (!ha->mcp) - ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERRROR.\n"); - else - mboxes = ha->mcp->in_mb; - - /* Load return mailbox registers. */ - ha->flags.mbox_int = 1; - ha->mailbox_out[0] = mb0; - mboxes >>= 1; - wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1); - - for (cnt = 1; cnt < ha->mbx_count; cnt++) { - if (IS_QLA2200(ha) && cnt == 8) - wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8); - if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0)) - ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr); - else if (mboxes & BIT_0) - ha->mailbox_out[cnt] = RD_REG_WORD(wptr); - - wptr++; - mboxes >>= 1; - } -} - -static void -qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr) -{ - static char *event[] = - { "Complete", "Request Notification", "Time Extension" }; - int rval; - struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24; - uint16_t __iomem *wptr; - uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS]; - - /* Seed data -- mailbox1 -> mailbox7. */ - wptr = (uint16_t __iomem *)®24->mailbox1; - for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++) - mb[cnt] = RD_REG_WORD(wptr); - - ql_dbg(ql_dbg_async, vha, 0x5021, - "Inter-Driver Communication %s -- " - "%04x %04x %04x %04x %04x %04x %04x.\n", - event[aen & 0xff], mb[0], mb[1], mb[2], mb[3], - mb[4], mb[5], mb[6]); - - /* Acknowledgement needed? [Notify && non-zero timeout]. */ - timeout = (descr >> 8) & 0xf; - if (aen != MBA_IDC_NOTIFY || !timeout) - return; - - ql_dbg(ql_dbg_async, vha, 0x5022, - "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n", - vha->host_no, event[aen & 0xff], timeout); - - rval = qla2x00_post_idc_ack_work(vha, mb); - if (rval != QLA_SUCCESS) - ql_log(ql_log_warn, vha, 0x5023, - "IDC failed to post ACK.\n"); -} - -/** - * qla2x00_async_event() - Process aynchronous events. - * @ha: SCSI driver HA context - * @mb: Mailbox registers (0 - 3) - */ -void -qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) -{ -#define LS_UNKNOWN 2 - static char *link_speeds[] = { "1", "2", "?", "4", "8", "16", "10" }; - char *link_speed; - uint16_t handle_cnt; - uint16_t cnt, mbx; - uint32_t handles[5]; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; - struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82; - uint32_t rscn_entry, host_pid; - unsigned long flags; - - /* Setup to process RIO completion. */ - handle_cnt = 0; - if (IS_CNA_CAPABLE(ha)) - goto skip_rio; - switch (mb[0]) { - case MBA_SCSI_COMPLETION: - handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1])); - handle_cnt = 1; - break; - case MBA_CMPLT_1_16BIT: - handles[0] = mb[1]; - handle_cnt = 1; - mb[0] = MBA_SCSI_COMPLETION; - break; - case MBA_CMPLT_2_16BIT: - handles[0] = mb[1]; - handles[1] = mb[2]; - handle_cnt = 2; - mb[0] = MBA_SCSI_COMPLETION; - break; - case MBA_CMPLT_3_16BIT: - handles[0] = mb[1]; - handles[1] = mb[2]; - handles[2] = mb[3]; - handle_cnt = 3; - mb[0] = MBA_SCSI_COMPLETION; - break; - case MBA_CMPLT_4_16BIT: - handles[0] = mb[1]; - handles[1] = mb[2]; - handles[2] = mb[3]; - handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6); - handle_cnt = 4; - mb[0] = MBA_SCSI_COMPLETION; - break; - case MBA_CMPLT_5_16BIT: - handles[0] = mb[1]; - handles[1] = mb[2]; - handles[2] = mb[3]; - handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6); - handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7); - handle_cnt = 5; - mb[0] = MBA_SCSI_COMPLETION; - break; - case MBA_CMPLT_2_32BIT: - handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1])); - handles[1] = le32_to_cpu( - ((uint32_t)(RD_MAILBOX_REG(ha, reg, 7) << 16)) | - RD_MAILBOX_REG(ha, reg, 6)); - handle_cnt = 2; - mb[0] = MBA_SCSI_COMPLETION; - break; - default: - break; - } -skip_rio: - switch (mb[0]) { - case MBA_SCSI_COMPLETION: /* Fast Post */ - if (!vha->flags.online) - break; - - for (cnt = 0; cnt < handle_cnt; cnt++) - qla2x00_process_completed_request(vha, rsp->req, - handles[cnt]); - break; - - case MBA_RESET: /* Reset */ - ql_dbg(ql_dbg_async, vha, 0x5002, - "Asynchronous RESET.\n"); - - set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - break; - - case MBA_SYSTEM_ERR: /* System Error */ - mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha)) ? - RD_REG_WORD(®24->mailbox7) : 0; - ql_log(ql_log_warn, vha, 0x5003, - "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh " - "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx); - - ha->isp_ops->fw_dump(vha, 1); - - if (IS_FWI2_CAPABLE(ha)) { - if (mb[1] == 0 && mb[2] == 0) { - ql_log(ql_log_fatal, vha, 0x5004, - "Unrecoverable Hardware Error: adapter " - "marked OFFLINE!\n"); - vha->flags.online = 0; - vha->device_flags |= DFLG_DEV_FAILED; - } else { - /* Check to see if MPI timeout occurred */ - if ((mbx & MBX_3) && (ha->flags.port0)) - set_bit(MPI_RESET_NEEDED, - &vha->dpc_flags); - - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - } - } else if (mb[1] == 0) { - ql_log(ql_log_fatal, vha, 0x5005, - "Unrecoverable Hardware Error: adapter marked " - "OFFLINE!\n"); - vha->flags.online = 0; - vha->device_flags |= DFLG_DEV_FAILED; - } else - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - - case MBA_REQ_TRANSFER_ERR: /* Request Transfer Error */ - ql_log(ql_log_warn, vha, 0x5006, - "ISP Request Transfer Error (%x).\n", mb[1]); - - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - - case MBA_RSP_TRANSFER_ERR: /* Response Transfer Error */ - ql_log(ql_log_warn, vha, 0x5007, - "ISP Response Transfer Error.\n"); - - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - - case MBA_WAKEUP_THRES: /* Request Queue Wake-up */ - ql_dbg(ql_dbg_async, vha, 0x5008, - "Asynchronous WAKEUP_THRES.\n"); - break; - - case MBA_LIP_OCCURRED: /* Loop Initialization Procedure */ - ql_dbg(ql_dbg_async, vha, 0x5009, - "LIP occurred (%x).\n", mb[1]); - - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - qla2x00_mark_all_devices_lost(vha, 1); - } - - if (vha->vp_idx) { - atomic_set(&vha->vp_state, VP_FAILED); - fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); - } - - set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); - set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); - - vha->flags.management_server_logged_in = 0; - qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]); - break; - - case MBA_LOOP_UP: /* Loop Up Event */ - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - link_speed = link_speeds[0]; - ha->link_data_rate = PORT_SPEED_1GB; - } else { - link_speed = link_speeds[LS_UNKNOWN]; - if (mb[1] < 6) - link_speed = link_speeds[mb[1]]; - else if (mb[1] == 0x13) - link_speed = link_speeds[6]; - ha->link_data_rate = mb[1]; - } - - ql_dbg(ql_dbg_async, vha, 0x500a, - "LOOP UP detected (%s Gbps).\n", link_speed); - - vha->flags.management_server_logged_in = 0; - qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate); - break; - - case MBA_LOOP_DOWN: /* Loop Down Event */ - mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha)) - ? RD_REG_WORD(®24->mailbox4) : 0; - mbx = IS_QLA82XX(ha) ? RD_REG_WORD(®82->mailbox_out[4]) : mbx; - ql_dbg(ql_dbg_async, vha, 0x500b, - "LOOP DOWN detected (%x %x %x %x).\n", - mb[1], mb[2], mb[3], mbx); - - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - vha->device_flags |= DFLG_NO_CABLE; - qla2x00_mark_all_devices_lost(vha, 1); - } - - if (vha->vp_idx) { - atomic_set(&vha->vp_state, VP_FAILED); - fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); - } - - vha->flags.management_server_logged_in = 0; - ha->link_data_rate = PORT_SPEED_UNKNOWN; - qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0); - break; - - case MBA_LIP_RESET: /* LIP reset occurred */ - ql_dbg(ql_dbg_async, vha, 0x500c, - "LIP reset occurred (%x).\n", mb[1]); - - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - qla2x00_mark_all_devices_lost(vha, 1); - } - - if (vha->vp_idx) { - atomic_set(&vha->vp_state, VP_FAILED); - fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); - } - - set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - - ha->operating_mode = LOOP; - vha->flags.management_server_logged_in = 0; - qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]); - break; - - /* case MBA_DCBX_COMPLETE: */ - case MBA_POINT_TO_POINT: /* Point-to-Point */ - if (IS_QLA2100(ha)) - break; - - if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA8031(ha)) { - ql_dbg(ql_dbg_async, vha, 0x500d, - "DCBX Completed -- %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - if (ha->notify_dcbx_comp) - complete(&ha->dcbx_comp); - - } else - ql_dbg(ql_dbg_async, vha, 0x500e, - "Asynchronous P2P MODE received.\n"); - - /* - * Until there's a transition from loop down to loop up, treat - * this as loop down only. - */ - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - if (!atomic_read(&vha->loop_down_timer)) - atomic_set(&vha->loop_down_timer, - LOOP_DOWN_TIME); - qla2x00_mark_all_devices_lost(vha, 1); - } - - if (vha->vp_idx) { - atomic_set(&vha->vp_state, VP_FAILED); - fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); - } - - if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))) - set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - - set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); - set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); - - ha->flags.gpsc_supported = 1; - vha->flags.management_server_logged_in = 0; - break; - - case MBA_CHG_IN_CONNECTION: /* Change in connection mode */ - if (IS_QLA2100(ha)) - break; - - ql_dbg(ql_dbg_async, vha, 0x500f, - "Configuration change detected: value=%x.\n", mb[1]); - - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - if (!atomic_read(&vha->loop_down_timer)) - atomic_set(&vha->loop_down_timer, - LOOP_DOWN_TIME); - qla2x00_mark_all_devices_lost(vha, 1); - } - - if (vha->vp_idx) { - atomic_set(&vha->vp_state, VP_FAILED); - fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); - } - - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - break; - - case MBA_PORT_UPDATE: /* Port database update */ - /* - * Handle only global and vn-port update events - * - * Relevant inputs: - * mb[1] = N_Port handle of changed port - * OR 0xffff for global event - * mb[2] = New login state - * 7 = Port logged out - * mb[3] = LSB is vp_idx, 0xff = all vps - * - * Skip processing if: - * Event is global, vp_idx is NOT all vps, - * vp_idx does not match - * Event is not global, vp_idx does not match - */ - if (IS_QLA2XXX_MIDTYPE(ha) && - ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) || - (mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff)) - break; - - /* Global event -- port logout or port unavailable. */ - if (mb[1] == 0xffff && mb[2] == 0x7) { - ql_dbg(ql_dbg_async, vha, 0x5010, - "Port unavailable %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - atomic_set(&vha->loop_down_timer, - LOOP_DOWN_TIME); - vha->device_flags |= DFLG_NO_CABLE; - qla2x00_mark_all_devices_lost(vha, 1); - } - - if (vha->vp_idx) { - atomic_set(&vha->vp_state, VP_FAILED); - fc_vport_set_state(vha->fc_vport, - FC_VPORT_FAILED); - qla2x00_mark_all_devices_lost(vha, 1); - } - - vha->flags.management_server_logged_in = 0; - ha->link_data_rate = PORT_SPEED_UNKNOWN; - break; - } - - /* - * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET - * event etc. earlier indicating loop is down) then process - * it. Otherwise ignore it and Wait for RSCN to come in. - */ - atomic_set(&vha->loop_down_timer, 0); - if (atomic_read(&vha->loop_state) != LOOP_DOWN && - atomic_read(&vha->loop_state) != LOOP_DEAD) { - ql_dbg(ql_dbg_async, vha, 0x5011, - "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n", - mb[1], mb[2], mb[3]); - break; - } - - ql_dbg(ql_dbg_async, vha, 0x5012, - "Port database changed %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - - /* - * Mark all devices as missing so we will login again. - */ - atomic_set(&vha->loop_state, LOOP_UP); - - qla2x00_mark_all_devices_lost(vha, 1); - - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - break; - - case MBA_RSCN_UPDATE: /* State Change Registration */ - /* Check if the Vport has issued a SCR */ - if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags)) - break; - /* Only handle SCNs for our Vport index. */ - if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff)) - break; - - ql_dbg(ql_dbg_async, vha, 0x5013, - "RSCN database changed -- %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - - rscn_entry = ((mb[1] & 0xff) << 16) | mb[2]; - host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8) - | vha->d_id.b.al_pa; - if (rscn_entry == host_pid) { - ql_dbg(ql_dbg_async, vha, 0x5014, - "Ignoring RSCN update to local host " - "port ID (%06x).\n", host_pid); - break; - } - - /* Ignore reserved bits from RSCN-payload. */ - rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2]; - - atomic_set(&vha->loop_down_timer, 0); - vha->flags.management_server_logged_in = 0; - - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - set_bit(RSCN_UPDATE, &vha->dpc_flags); - qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry); - break; - - /* case MBA_RIO_RESPONSE: */ - case MBA_ZIO_RESPONSE: - ql_dbg(ql_dbg_async, vha, 0x5015, - "[R|Z]IO update completion.\n"); - - if (IS_FWI2_CAPABLE(ha)) - qla24xx_process_response_queue(vha, rsp); - else - qla2x00_process_response_queue(rsp); - break; - - case MBA_DISCARD_RND_FRAME: - ql_dbg(ql_dbg_async, vha, 0x5016, - "Discard RND Frame -- %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - break; - - case MBA_TRACE_NOTIFICATION: - ql_dbg(ql_dbg_async, vha, 0x5017, - "Trace Notification -- %04x %04x.\n", mb[1], mb[2]); - break; - - case MBA_ISP84XX_ALERT: - ql_dbg(ql_dbg_async, vha, 0x5018, - "ISP84XX Alert Notification -- %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - - spin_lock_irqsave(&ha->cs84xx->access_lock, flags); - switch (mb[1]) { - case A84_PANIC_RECOVERY: - ql_log(ql_log_info, vha, 0x5019, - "Alert 84XX: panic recovery %04x %04x.\n", - mb[2], mb[3]); - break; - case A84_OP_LOGIN_COMPLETE: - ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2]; - ql_log(ql_log_info, vha, 0x501a, - "Alert 84XX: firmware version %x.\n", - ha->cs84xx->op_fw_version); - break; - case A84_DIAG_LOGIN_COMPLETE: - ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2]; - ql_log(ql_log_info, vha, 0x501b, - "Alert 84XX: diagnostic firmware version %x.\n", - ha->cs84xx->diag_fw_version); - break; - case A84_GOLD_LOGIN_COMPLETE: - ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2]; - ha->cs84xx->fw_update = 1; - ql_log(ql_log_info, vha, 0x501c, - "Alert 84XX: gold firmware version %x.\n", - ha->cs84xx->gold_fw_version); - break; - default: - ql_log(ql_log_warn, vha, 0x501d, - "Alert 84xx: Invalid Alert %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - } - spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags); - break; - case MBA_DCBX_START: - ql_dbg(ql_dbg_async, vha, 0x501e, - "DCBX Started -- %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - break; - case MBA_DCBX_PARAM_UPDATE: - ql_dbg(ql_dbg_async, vha, 0x501f, - "DCBX Parameters Updated -- %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - break; - case MBA_FCF_CONF_ERR: - ql_dbg(ql_dbg_async, vha, 0x5020, - "FCF Configuration Error -- %04x %04x %04x.\n", - mb[1], mb[2], mb[3]); - break; - case MBA_IDC_COMPLETE: - case MBA_IDC_NOTIFY: - case MBA_IDC_TIME_EXT: - qla81xx_idc_event(vha, mb[0], mb[1]); - break; - default: - ql_dbg(ql_dbg_async, vha, 0x5057, - "Unknown AEN:%04x %04x %04x %04x\n", - mb[0], mb[1], mb[2], mb[3]); - } - - if (!vha->vp_idx && ha->num_vhosts) - qla2x00_alert_all_vps(rsp, mb); -} - -/** - * qla2x00_process_completed_request() - Process a Fast Post response. - * @ha: SCSI driver HA context - * @index: SRB index - */ -static void -qla2x00_process_completed_request(struct scsi_qla_host *vha, - struct req_que *req, uint32_t index) -{ - srb_t *sp; - struct qla_hw_data *ha = vha->hw; - - /* Validate handle. */ - if (index >= MAX_OUTSTANDING_COMMANDS) { - ql_log(ql_log_warn, vha, 0x3014, - "Invalid SCSI command index (%x).\n", index); - - if (IS_QLA82XX(ha)) - set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); - else - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - return; - } - - sp = req->outstanding_cmds[index]; - if (sp) { - /* Free outstanding command slot. */ - req->outstanding_cmds[index] = NULL; - - /* Save ISP completion status */ - sp->done(ha, sp, DID_OK << 16); - } else { - ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n"); - - if (IS_QLA82XX(ha)) - set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); - else - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - } -} - -static srb_t * -qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func, - struct req_que *req, void *iocb) -{ - struct qla_hw_data *ha = vha->hw; - sts_entry_t *pkt = iocb; - srb_t *sp = NULL; - uint16_t index; - - index = LSW(pkt->handle); - if (index >= MAX_OUTSTANDING_COMMANDS) { - ql_log(ql_log_warn, vha, 0x5031, - "Invalid command index (%x).\n", index); - if (IS_QLA82XX(ha)) - set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); - else - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - goto done; - } - sp = req->outstanding_cmds[index]; - if (!sp) { - ql_log(ql_log_warn, vha, 0x5032, - "Invalid completion handle (%x) -- timed-out.\n", index); - return sp; - } - if (sp->handle != index) { - ql_log(ql_log_warn, vha, 0x5033, - "SRB handle (%x) mismatch %x.\n", sp->handle, index); - return NULL; - } - - req->outstanding_cmds[index] = NULL; - -done: - return sp; -} - -static void -qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, - struct mbx_entry *mbx) -{ - const char func[] = "MBX-IOCB"; - const char *type; - fc_port_t *fcport; - srb_t *sp; - struct srb_iocb *lio; - uint16_t *data; - uint16_t status; - - sp = qla2x00_get_sp_from_handle(vha, func, req, mbx); - if (!sp) - return; - - lio = &sp->u.iocb_cmd; - type = sp->name; - fcport = sp->fcport; - data = lio->u.logio.data; - - data[0] = MBS_COMMAND_ERROR; - data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? - QLA_LOGIO_LOGIN_RETRIED : 0; - if (mbx->entry_status) { - ql_dbg(ql_dbg_async, vha, 0x5043, - "Async-%s error entry - hdl=%x portid=%02x%02x%02x " - "entry-status=%x status=%x state-flag=%x " - "status-flags=%x.\n", type, sp->handle, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, mbx->entry_status, - le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags), - le16_to_cpu(mbx->status_flags)); - - ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029, - (uint8_t *)mbx, sizeof(*mbx)); - - goto logio_done; - } - - status = le16_to_cpu(mbx->status); - if (status == 0x30 && sp->type == SRB_LOGIN_CMD && - le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) - status = 0; - if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) { - ql_dbg(ql_dbg_async, vha, 0x5045, - "Async-%s complete - hdl=%x portid=%02x%02x%02x mbx1=%x.\n", - type, sp->handle, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, - le16_to_cpu(mbx->mb1)); - - data[0] = MBS_COMMAND_COMPLETE; - if (sp->type == SRB_LOGIN_CMD) { - fcport->port_type = FCT_TARGET; - if (le16_to_cpu(mbx->mb1) & BIT_0) - fcport->port_type = FCT_INITIATOR; - else if (le16_to_cpu(mbx->mb1) & BIT_1) - fcport->flags |= FCF_FCP2_DEVICE; - } - goto logio_done; - } - - data[0] = le16_to_cpu(mbx->mb0); - switch (data[0]) { - case MBS_PORT_ID_USED: - data[1] = le16_to_cpu(mbx->mb1); - break; - case MBS_LOOP_ID_USED: - break; - default: - data[0] = MBS_COMMAND_ERROR; - break; - } - - ql_log(ql_log_warn, vha, 0x5046, - "Async-%s failed - hdl=%x portid=%02x%02x%02x status=%x " - "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", type, sp->handle, - fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, - status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1), - le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6), - le16_to_cpu(mbx->mb7)); - -logio_done: - sp->done(vha, sp, 0); -} - -static void -qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req, - sts_entry_t *pkt, int iocb_type) -{ - const char func[] = "CT_IOCB"; - const char *type; - srb_t *sp; - struct fc_bsg_job *bsg_job; - uint16_t comp_status; - int res; - - sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); - if (!sp) - return; - - bsg_job = sp->u.bsg_job; - - type = "ct pass-through"; - - comp_status = le16_to_cpu(pkt->comp_status); - - /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT - * fc payload to the caller - */ - bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; - bsg_job->reply_len = sizeof(struct fc_bsg_reply); - - if (comp_status != CS_COMPLETE) { - if (comp_status == CS_DATA_UNDERRUN) { - res = DID_OK << 16; - bsg_job->reply->reply_payload_rcv_len = - le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len); - - ql_log(ql_log_warn, vha, 0x5048, - "CT pass-through-%s error " - "comp_status-status=0x%x total_byte = 0x%x.\n", - type, comp_status, - bsg_job->reply->reply_payload_rcv_len); - } else { - ql_log(ql_log_warn, vha, 0x5049, - "CT pass-through-%s error " - "comp_status-status=0x%x.\n", type, comp_status); - res = DID_ERROR << 16; - bsg_job->reply->reply_payload_rcv_len = 0; - } - ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035, - (uint8_t *)pkt, sizeof(*pkt)); - } else { - res = DID_OK << 16; - bsg_job->reply->reply_payload_rcv_len = - bsg_job->reply_payload.payload_len; - bsg_job->reply_len = 0; - } - - sp->done(vha, sp, res); -} - -static void -qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, - struct sts_entry_24xx *pkt, int iocb_type) -{ - const char func[] = "ELS_CT_IOCB"; - const char *type; - srb_t *sp; - struct fc_bsg_job *bsg_job; - uint16_t comp_status; - uint32_t fw_status[3]; - uint8_t* fw_sts_ptr; - int res; - - sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); - if (!sp) - return; - bsg_job = sp->u.bsg_job; - - type = NULL; - switch (sp->type) { - case SRB_ELS_CMD_RPT: - case SRB_ELS_CMD_HST: - type = "els"; - break; - case SRB_CT_CMD: - type = "ct pass-through"; - break; - default: - ql_dbg(ql_dbg_user, vha, 0x503e, - "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type); - return; - } - - comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status); - fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1); - fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2); - - /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT - * fc payload to the caller - */ - bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK; - bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status); - - if (comp_status != CS_COMPLETE) { - if (comp_status == CS_DATA_UNDERRUN) { - res = DID_OK << 16; - bsg_job->reply->reply_payload_rcv_len = - le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->total_byte_count); - - ql_dbg(ql_dbg_user, vha, 0x503f, - "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x " - "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n", - type, sp->handle, comp_status, fw_status[1], fw_status[2], - le16_to_cpu(((struct els_sts_entry_24xx *) - pkt)->total_byte_count)); - fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); - memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); - } - else { - ql_dbg(ql_dbg_user, vha, 0x5040, - "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x " - "error subcode 1=0x%x error subcode 2=0x%x.\n", - type, sp->handle, comp_status, - le16_to_cpu(((struct els_sts_entry_24xx *) - pkt)->error_subcode_1), - le16_to_cpu(((struct els_sts_entry_24xx *) - pkt)->error_subcode_2)); - res = DID_ERROR << 16; - bsg_job->reply->reply_payload_rcv_len = 0; - fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply); - memcpy( fw_sts_ptr, fw_status, sizeof(fw_status)); - } - ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056, - (uint8_t *)pkt, sizeof(*pkt)); - } - else { - res = DID_OK << 16; - bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; - bsg_job->reply_len = 0; - } - - sp->done(vha, sp, res); -} - -static void -qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, - struct logio_entry_24xx *logio) -{ - const char func[] = "LOGIO-IOCB"; - const char *type; - fc_port_t *fcport; - srb_t *sp; - struct srb_iocb *lio; - uint16_t *data; - uint32_t iop[2]; - - sp = qla2x00_get_sp_from_handle(vha, func, req, logio); - if (!sp) - return; - - lio = &sp->u.iocb_cmd; - type = sp->name; - fcport = sp->fcport; - data = lio->u.logio.data; - - data[0] = MBS_COMMAND_ERROR; - data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? - QLA_LOGIO_LOGIN_RETRIED : 0; - if (logio->entry_status) { - ql_log(ql_log_warn, fcport->vha, 0x5034, - "Async-%s error entry - hdl=%x" - "portid=%02x%02x%02x entry-status=%x.\n", - type, sp->handle, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, - logio->entry_status); - ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d, - (uint8_t *)logio, sizeof(*logio)); - - goto logio_done; - } - - if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) { - ql_dbg(ql_dbg_async, fcport->vha, 0x5036, - "Async-%s complete - hdl=%x portid=%02x%02x%02x " - "iop0=%x.\n", type, sp->handle, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, - le32_to_cpu(logio->io_parameter[0])); - - data[0] = MBS_COMMAND_COMPLETE; - if (sp->type != SRB_LOGIN_CMD) - goto logio_done; - - iop[0] = le32_to_cpu(logio->io_parameter[0]); - if (iop[0] & BIT_4) { - fcport->port_type = FCT_TARGET; - if (iop[0] & BIT_8) - fcport->flags |= FCF_FCP2_DEVICE; - } else if (iop[0] & BIT_5) - fcport->port_type = FCT_INITIATOR; - - if (logio->io_parameter[7] || logio->io_parameter[8]) - fcport->supported_classes |= FC_COS_CLASS2; - if (logio->io_parameter[9] || logio->io_parameter[10]) - fcport->supported_classes |= FC_COS_CLASS3; - - goto logio_done; - } - - iop[0] = le32_to_cpu(logio->io_parameter[0]); - iop[1] = le32_to_cpu(logio->io_parameter[1]); - switch (iop[0]) { - case LSC_SCODE_PORTID_USED: - data[0] = MBS_PORT_ID_USED; - data[1] = LSW(iop[1]); - break; - case LSC_SCODE_NPORT_USED: - data[0] = MBS_LOOP_ID_USED; - break; - default: - data[0] = MBS_COMMAND_ERROR; - break; - } - - ql_dbg(ql_dbg_async, fcport->vha, 0x5037, - "Async-%s failed - hdl=%x portid=%02x%02x%02x comp=%x " - "iop0=%x iop1=%x.\n", type, sp->handle, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, - le16_to_cpu(logio->comp_status), - le32_to_cpu(logio->io_parameter[0]), - le32_to_cpu(logio->io_parameter[1])); - -logio_done: - sp->done(vha, sp, 0); -} - -static void -qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, - struct tsk_mgmt_entry *tsk) -{ - const char func[] = "TMF-IOCB"; - const char *type; - fc_port_t *fcport; - srb_t *sp; - struct srb_iocb *iocb; - struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; - int error = 1; - - sp = qla2x00_get_sp_from_handle(vha, func, req, tsk); - if (!sp) - return; - - iocb = &sp->u.iocb_cmd; - type = sp->name; - fcport = sp->fcport; - - if (sts->entry_status) { - ql_log(ql_log_warn, fcport->vha, 0x5038, - "Async-%s error - hdl=%x entry-status(%x).\n", - type, sp->handle, sts->entry_status); - } else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { - ql_log(ql_log_warn, fcport->vha, 0x5039, - "Async-%s error - hdl=%x completion status(%x).\n", - type, sp->handle, sts->comp_status); - } else if (!(le16_to_cpu(sts->scsi_status) & - SS_RESPONSE_INFO_LEN_VALID)) { - ql_log(ql_log_warn, fcport->vha, 0x503a, - "Async-%s error - hdl=%x no response info(%x).\n", - type, sp->handle, sts->scsi_status); - } else if (le32_to_cpu(sts->rsp_data_len) < 4) { - ql_log(ql_log_warn, fcport->vha, 0x503b, - "Async-%s error - hdl=%x not enough response(%d).\n", - type, sp->handle, sts->rsp_data_len); - } else if (sts->data[3]) { - ql_log(ql_log_warn, fcport->vha, 0x503c, - "Async-%s error - hdl=%x response(%x).\n", - type, sp->handle, sts->data[3]); - } else { - error = 0; - } - - if (error) { - iocb->u.tmf.data = error; - ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055, - (uint8_t *)sts, sizeof(*sts)); - } - - sp->done(vha, sp, 0); -} - -/** - * qla2x00_process_response_queue() - Process response queue entries. - * @ha: SCSI driver HA context - */ -void -qla2x00_process_response_queue(struct rsp_que *rsp) -{ - struct scsi_qla_host *vha; - struct qla_hw_data *ha = rsp->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - sts_entry_t *pkt; - uint16_t handle_cnt; - uint16_t cnt; - - vha = pci_get_drvdata(ha->pdev); - - if (!vha->flags.online) - return; - - while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) { - pkt = (sts_entry_t *)rsp->ring_ptr; - - rsp->ring_index++; - if (rsp->ring_index == rsp->length) { - rsp->ring_index = 0; - rsp->ring_ptr = rsp->ring; - } else { - rsp->ring_ptr++; - } - - if (pkt->entry_status != 0) { - qla2x00_error_entry(vha, rsp, pkt); - ((response_t *)pkt)->signature = RESPONSE_PROCESSED; - wmb(); - continue; - } - - switch (pkt->entry_type) { - case STATUS_TYPE: - qla2x00_status_entry(vha, rsp, pkt); - break; - case STATUS_TYPE_21: - handle_cnt = ((sts21_entry_t *)pkt)->handle_count; - for (cnt = 0; cnt < handle_cnt; cnt++) { - qla2x00_process_completed_request(vha, rsp->req, - ((sts21_entry_t *)pkt)->handle[cnt]); - } - break; - case STATUS_TYPE_22: - handle_cnt = ((sts22_entry_t *)pkt)->handle_count; - for (cnt = 0; cnt < handle_cnt; cnt++) { - qla2x00_process_completed_request(vha, rsp->req, - ((sts22_entry_t *)pkt)->handle[cnt]); - } - break; - case STATUS_CONT_TYPE: - qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); - break; - case MBX_IOCB_TYPE: - qla2x00_mbx_iocb_entry(vha, rsp->req, - (struct mbx_entry *)pkt); - break; - case CT_IOCB_TYPE: - qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); - break; - default: - /* Type Not Supported. */ - ql_log(ql_log_warn, vha, 0x504a, - "Received unknown response pkt type %x " - "entry status=%x.\n", - pkt->entry_type, pkt->entry_status); - break; - } - ((response_t *)pkt)->signature = RESPONSE_PROCESSED; - wmb(); - } - - /* Adjust ring index */ - WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index); -} - -static inline void -qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len, - uint32_t sense_len, struct rsp_que *rsp, int res) -{ - struct scsi_qla_host *vha = sp->fcport->vha; - struct scsi_cmnd *cp = GET_CMD_SP(sp); - uint32_t track_sense_len; - - if (sense_len >= SCSI_SENSE_BUFFERSIZE) - sense_len = SCSI_SENSE_BUFFERSIZE; - - SET_CMD_SENSE_LEN(sp, sense_len); - SET_CMD_SENSE_PTR(sp, cp->sense_buffer); - track_sense_len = sense_len; - - if (sense_len > par_sense_len) - sense_len = par_sense_len; - - memcpy(cp->sense_buffer, sense_data, sense_len); - - SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len); - track_sense_len -= sense_len; - SET_CMD_SENSE_LEN(sp, track_sense_len); - - if (track_sense_len != 0) { - rsp->status_srb = sp; - cp->result = res; - } - - if (sense_len) { - ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c, - "Check condition Sense data, nexus%ld:%d:%d cmd=%p.\n", - sp->fcport->vha->host_no, cp->device->id, cp->device->lun, - cp); - ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b, - cp->sense_buffer, sense_len); - } -} - -struct scsi_dif_tuple { - __be16 guard; /* Checksum */ - __be16 app_tag; /* APPL identifer */ - __be32 ref_tag; /* Target LBA or indirect LBA */ -}; - -/* - * Checks the guard or meta-data for the type of error - * detected by the HBA. In case of errors, we set the - * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST - * to indicate to the kernel that the HBA detected error. - */ -static inline int -qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24) -{ - struct scsi_qla_host *vha = sp->fcport->vha; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - uint8_t *ap = &sts24->data[12]; - uint8_t *ep = &sts24->data[20]; - uint32_t e_ref_tag, a_ref_tag; - uint16_t e_app_tag, a_app_tag; - uint16_t e_guard, a_guard; - - /* - * swab32 of the "data" field in the beginning of qla2x00_status_entry() - * would make guard field appear at offset 2 - */ - a_guard = le16_to_cpu(*(uint16_t *)(ap + 2)); - a_app_tag = le16_to_cpu(*(uint16_t *)(ap + 0)); - a_ref_tag = le32_to_cpu(*(uint32_t *)(ap + 4)); - e_guard = le16_to_cpu(*(uint16_t *)(ep + 2)); - e_app_tag = le16_to_cpu(*(uint16_t *)(ep + 0)); - e_ref_tag = le32_to_cpu(*(uint32_t *)(ep + 4)); - - ql_dbg(ql_dbg_io, vha, 0x3023, - "iocb(s) %p Returned STATUS.\n", sts24); - - ql_dbg(ql_dbg_io, vha, 0x3024, - "DIF ERROR in cmd 0x%x lba 0x%llx act ref" - " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app" - " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n", - cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag, - a_app_tag, e_app_tag, a_guard, e_guard); - - /* - * Ignore sector if: - * For type 3: ref & app tag is all 'f's - * For type 0,1,2: app tag is all 'f's - */ - if ((a_app_tag == 0xffff) && - ((scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3) || - (a_ref_tag == 0xffffffff))) { - uint32_t blocks_done, resid; - sector_t lba_s = scsi_get_lba(cmd); - - /* 2TB boundary case covered automatically with this */ - blocks_done = e_ref_tag - (uint32_t)lba_s + 1; - - resid = scsi_bufflen(cmd) - (blocks_done * - cmd->device->sector_size); - - scsi_set_resid(cmd, resid); - cmd->result = DID_OK << 16; - - /* Update protection tag */ - if (scsi_prot_sg_count(cmd)) { - uint32_t i, j = 0, k = 0, num_ent; - struct scatterlist *sg; - struct sd_dif_tuple *spt; - - /* Patch the corresponding protection tags */ - scsi_for_each_prot_sg(cmd, sg, - scsi_prot_sg_count(cmd), i) { - num_ent = sg_dma_len(sg) / 8; - if (k + num_ent < blocks_done) { - k += num_ent; - continue; - } - j = blocks_done - k - 1; - k = blocks_done; - break; - } - - if (k != blocks_done) { - ql_log(ql_log_warn, vha, 0x302f, - "unexpected tag values tag:lba=%x:%llx)\n", - e_ref_tag, (unsigned long long)lba_s); - return 1; - } - - spt = page_address(sg_page(sg)) + sg->offset; - spt += j; - - spt->app_tag = 0xffff; - if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3) - spt->ref_tag = 0xffffffff; - } - - return 0; - } - - /* check guard */ - if (e_guard != a_guard) { - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x1); - set_driver_byte(cmd, DRIVER_SENSE); - set_host_byte(cmd, DID_ABORT); - cmd->result |= SAM_STAT_CHECK_CONDITION << 1; - return 1; - } - - /* check ref tag */ - if (e_ref_tag != a_ref_tag) { - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x3); - set_driver_byte(cmd, DRIVER_SENSE); - set_host_byte(cmd, DID_ABORT); - cmd->result |= SAM_STAT_CHECK_CONDITION << 1; - return 1; - } - - /* check appl tag */ - if (e_app_tag != a_app_tag) { - scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST, - 0x10, 0x2); - set_driver_byte(cmd, DRIVER_SENSE); - set_host_byte(cmd, DID_ABORT); - cmd->result |= SAM_STAT_CHECK_CONDITION << 1; - return 1; - } - - return 1; -} - -/** - * qla2x00_status_entry() - Process a Status IOCB entry. - * @ha: SCSI driver HA context - * @pkt: Entry pointer - */ -static void -qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) -{ - srb_t *sp; - fc_port_t *fcport; - struct scsi_cmnd *cp; - sts_entry_t *sts; - struct sts_entry_24xx *sts24; - uint16_t comp_status; - uint16_t scsi_status; - uint16_t ox_id; - uint8_t lscsi_status; - int32_t resid; - uint32_t sense_len, par_sense_len, rsp_info_len, resid_len, - fw_resid_len; - uint8_t *rsp_info, *sense_data; - struct qla_hw_data *ha = vha->hw; - uint32_t handle; - uint16_t que; - struct req_que *req; - int logit = 1; - int res = 0; - - sts = (sts_entry_t *) pkt; - sts24 = (struct sts_entry_24xx *) pkt; - if (IS_FWI2_CAPABLE(ha)) { - comp_status = le16_to_cpu(sts24->comp_status); - scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK; - } else { - comp_status = le16_to_cpu(sts->comp_status); - scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK; - } - handle = (uint32_t) LSW(sts->handle); - que = MSW(sts->handle); - req = ha->req_q_map[que]; - - /* Fast path completion. */ - if (comp_status == CS_COMPLETE && scsi_status == 0) { - qla2x00_process_completed_request(vha, req, handle); - - return; - } - - /* Validate handle. */ - if (handle < MAX_OUTSTANDING_COMMANDS) { - sp = req->outstanding_cmds[handle]; - req->outstanding_cmds[handle] = NULL; - } else - sp = NULL; - - if (sp == NULL) { - ql_dbg(ql_dbg_io, vha, 0x3017, - "Invalid status handle (0x%x).\n", sts->handle); - - if (IS_QLA82XX(ha)) - set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); - else - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - return; - } - cp = GET_CMD_SP(sp); - if (cp == NULL) { - ql_dbg(ql_dbg_io, vha, 0x3018, - "Command already returned (0x%x/%p).\n", - sts->handle, sp); - - return; - } - - lscsi_status = scsi_status & STATUS_MASK; - - fcport = sp->fcport; - - ox_id = 0; - sense_len = par_sense_len = rsp_info_len = resid_len = - fw_resid_len = 0; - if (IS_FWI2_CAPABLE(ha)) { - if (scsi_status & SS_SENSE_LEN_VALID) - sense_len = le32_to_cpu(sts24->sense_len); - if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) - rsp_info_len = le32_to_cpu(sts24->rsp_data_len); - if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) - resid_len = le32_to_cpu(sts24->rsp_residual_count); - if (comp_status == CS_DATA_UNDERRUN) - fw_resid_len = le32_to_cpu(sts24->residual_len); - rsp_info = sts24->data; - sense_data = sts24->data; - host_to_fcp_swap(sts24->data, sizeof(sts24->data)); - ox_id = le16_to_cpu(sts24->ox_id); - par_sense_len = sizeof(sts24->data); - } else { - if (scsi_status & SS_SENSE_LEN_VALID) - sense_len = le16_to_cpu(sts->req_sense_length); - if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) - rsp_info_len = le16_to_cpu(sts->rsp_info_len); - resid_len = le32_to_cpu(sts->residual_length); - rsp_info = sts->rsp_info; - sense_data = sts->req_sense_data; - par_sense_len = sizeof(sts->req_sense_data); - } - - /* Check for any FCP transport errors. */ - if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) { - /* Sense data lies beyond any FCP RESPONSE data. */ - if (IS_FWI2_CAPABLE(ha)) { - sense_data += rsp_info_len; - par_sense_len -= rsp_info_len; - } - if (rsp_info_len > 3 && rsp_info[3]) { - ql_dbg(ql_dbg_io, fcport->vha, 0x3019, - "FCP I/O protocol failure (0x%x/0x%x).\n", - rsp_info_len, rsp_info[3]); - - res = DID_BUS_BUSY << 16; - goto out; - } - } - - /* Check for overrun. */ - if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE && - scsi_status & SS_RESIDUAL_OVER) - comp_status = CS_DATA_OVERRUN; - - /* - * Based on Host and scsi status generate status code for Linux - */ - switch (comp_status) { - case CS_COMPLETE: - case CS_QUEUE_FULL: - if (scsi_status == 0) { - res = DID_OK << 16; - break; - } - if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) { - resid = resid_len; - scsi_set_resid(cp, resid); - - if (!lscsi_status && - ((unsigned)(scsi_bufflen(cp) - resid) < - cp->underflow)) { - ql_dbg(ql_dbg_io, fcport->vha, 0x301a, - "Mid-layer underflow " - "detected (0x%x of 0x%x bytes).\n", - resid, scsi_bufflen(cp)); - - res = DID_ERROR << 16; - break; - } - } - res = DID_OK << 16 | lscsi_status; - - if (lscsi_status == SAM_STAT_TASK_SET_FULL) { - ql_dbg(ql_dbg_io, fcport->vha, 0x301b, - "QUEUE FULL detected.\n"); - break; - } - logit = 0; - if (lscsi_status != SS_CHECK_CONDITION) - break; - - memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - if (!(scsi_status & SS_SENSE_LEN_VALID)) - break; - - qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len, - rsp, res); - break; - - case CS_DATA_UNDERRUN: - /* Use F/W calculated residual length. */ - resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len; - scsi_set_resid(cp, resid); - if (scsi_status & SS_RESIDUAL_UNDER) { - if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) { - ql_dbg(ql_dbg_io, fcport->vha, 0x301d, - "Dropped frame(s) detected " - "(0x%x of 0x%x bytes).\n", - resid, scsi_bufflen(cp)); - - res = DID_ERROR << 16 | lscsi_status; - goto check_scsi_status; - } - - if (!lscsi_status && - ((unsigned)(scsi_bufflen(cp) - resid) < - cp->underflow)) { - ql_dbg(ql_dbg_io, fcport->vha, 0x301e, - "Mid-layer underflow " - "detected (0x%x of 0x%x bytes).\n", - resid, scsi_bufflen(cp)); - - res = DID_ERROR << 16; - break; - } - } else if (lscsi_status != SAM_STAT_TASK_SET_FULL && - lscsi_status != SAM_STAT_BUSY) { - /* - * scsi status of task set and busy are considered to be - * task not completed. - */ - - ql_dbg(ql_dbg_io, fcport->vha, 0x301f, - "Dropped frame(s) detected (0x%x " - "of 0x%x bytes).\n", resid, - scsi_bufflen(cp)); - - res = DID_ERROR << 16 | lscsi_status; - goto check_scsi_status; - } else { - ql_dbg(ql_dbg_io, fcport->vha, 0x3030, - "scsi_status: 0x%x, lscsi_status: 0x%x\n", - scsi_status, lscsi_status); - } - - res = DID_OK << 16 | lscsi_status; - logit = 0; - -check_scsi_status: - /* - * Check to see if SCSI Status is non zero. If so report SCSI - * Status. - */ - if (lscsi_status != 0) { - if (lscsi_status == SAM_STAT_TASK_SET_FULL) { - ql_dbg(ql_dbg_io, fcport->vha, 0x3020, - "QUEUE FULL detected.\n"); - logit = 1; - break; - } - if (lscsi_status != SS_CHECK_CONDITION) - break; - - memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - if (!(scsi_status & SS_SENSE_LEN_VALID)) - break; - - qla2x00_handle_sense(sp, sense_data, par_sense_len, - sense_len, rsp, res); - } - break; - - case CS_PORT_LOGGED_OUT: - case CS_PORT_CONFIG_CHG: - case CS_PORT_BUSY: - case CS_INCOMPLETE: - case CS_PORT_UNAVAILABLE: - case CS_TIMEOUT: - case CS_RESET: - - /* - * We are going to have the fc class block the rport - * while we try to recover so instruct the mid layer - * to requeue until the class decides how to handle this. - */ - res = DID_TRANSPORT_DISRUPTED << 16; - - if (comp_status == CS_TIMEOUT) { - if (IS_FWI2_CAPABLE(ha)) - break; - else if ((le16_to_cpu(sts->status_flags) & - SF_LOGOUT_SENT) == 0) - break; - } - - ql_dbg(ql_dbg_io, fcport->vha, 0x3021, - "Port down status: port-state=0x%x.\n", - atomic_read(&fcport->state)); - - if (atomic_read(&fcport->state) == FCS_ONLINE) - qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1); - break; - - case CS_ABORTED: - res = DID_RESET << 16; - break; - - case CS_DIF_ERROR: - logit = qla2x00_handle_dif_error(sp, sts24); - break; - default: - res = DID_ERROR << 16; - break; - } - -out: - if (logit) - ql_dbg(ql_dbg_io, fcport->vha, 0x3022, - "FCP command status: 0x%x-0x%x (0x%x) " - "nexus=%ld:%d:%d portid=%02x%02x%02x oxid=0x%x " - "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x " - "rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n", - comp_status, scsi_status, res, vha->host_no, - cp->device->id, cp->device->lun, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id, - cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3], - cp->cmnd[4], cp->cmnd[5], cp->cmnd[6], cp->cmnd[7], - cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp), rsp_info_len, - resid_len, fw_resid_len); - - if (rsp->status_srb == NULL) - sp->done(ha, sp, res); -} - -/** - * qla2x00_status_cont_entry() - Process a Status Continuations entry. - * @ha: SCSI driver HA context - * @pkt: Entry pointer - * - * Extended sense data. - */ -static void -qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) -{ - uint8_t sense_sz = 0; - struct qla_hw_data *ha = rsp->hw; - struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev); - srb_t *sp = rsp->status_srb; - struct scsi_cmnd *cp; - uint32_t sense_len; - uint8_t *sense_ptr; - - if (!sp || !GET_CMD_SENSE_LEN(sp)) - return; - - sense_len = GET_CMD_SENSE_LEN(sp); - sense_ptr = GET_CMD_SENSE_PTR(sp); - - cp = GET_CMD_SP(sp); - if (cp == NULL) { - ql_log(ql_log_warn, vha, 0x3025, - "cmd is NULL: already returned to OS (sp=%p).\n", sp); - - rsp->status_srb = NULL; - return; - } - - if (sense_len > sizeof(pkt->data)) - sense_sz = sizeof(pkt->data); - else - sense_sz = sense_len; - - /* Move sense data. */ - if (IS_FWI2_CAPABLE(ha)) - host_to_fcp_swap(pkt->data, sizeof(pkt->data)); - memcpy(sense_ptr, pkt->data, sense_sz); - ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c, - sense_ptr, sense_sz); - - sense_len -= sense_sz; - sense_ptr += sense_sz; - - SET_CMD_SENSE_PTR(sp, sense_ptr); - SET_CMD_SENSE_LEN(sp, sense_len); - - /* Place command on done queue. */ - if (sense_len == 0) { - rsp->status_srb = NULL; - sp->done(ha, sp, cp->result); - } -} - -/** - * qla2x00_error_entry() - Process an error entry. - * @ha: SCSI driver HA context - * @pkt: Entry pointer - */ -static void -qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) -{ - srb_t *sp; - struct qla_hw_data *ha = vha->hw; - const char func[] = "ERROR-IOCB"; - uint16_t que = MSW(pkt->handle); - struct req_que *req = NULL; - int res = DID_ERROR << 16; - - ql_dbg(ql_dbg_async, vha, 0x502a, - "type of error status in response: 0x%x\n", pkt->entry_status); - - if (que >= ha->max_req_queues || !ha->req_q_map[que]) - goto fatal; - - req = ha->req_q_map[que]; - - if (pkt->entry_status & RF_BUSY) - res = DID_BUS_BUSY << 16; - - sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); - if (sp) { - sp->done(ha, sp, res); - return; - } -fatal: - ql_log(ql_log_warn, vha, 0x5030, - "Error entry - invalid handle/queue.\n"); - - if (IS_QLA82XX(ha)) - set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); - else - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); -} - -/** - * qla24xx_mbx_completion() - Process mailbox command completions. - * @ha: SCSI driver HA context - * @mb0: Mailbox0 register - */ -static void -qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) -{ - uint16_t cnt; - uint32_t mboxes; - uint16_t __iomem *wptr; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Read all mbox registers? */ - mboxes = (1 << ha->mbx_count) - 1; - if (!ha->mcp) - ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERRROR.\n"); - else - mboxes = ha->mcp->in_mb; - - /* Load return mailbox registers. */ - ha->flags.mbox_int = 1; - ha->mailbox_out[0] = mb0; - mboxes >>= 1; - wptr = (uint16_t __iomem *)®->mailbox1; - - for (cnt = 1; cnt < ha->mbx_count; cnt++) { - if (mboxes & BIT_0) - ha->mailbox_out[cnt] = RD_REG_WORD(wptr); - - mboxes >>= 1; - wptr++; - } -} - -/** - * qla24xx_process_response_queue() - Process response queue entries. - * @ha: SCSI driver HA context - */ -void qla24xx_process_response_queue(struct scsi_qla_host *vha, - struct rsp_que *rsp) -{ - struct sts_entry_24xx *pkt; - struct qla_hw_data *ha = vha->hw; - - if (!vha->flags.online) - return; - - while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) { - pkt = (struct sts_entry_24xx *)rsp->ring_ptr; - - rsp->ring_index++; - if (rsp->ring_index == rsp->length) { - rsp->ring_index = 0; - rsp->ring_ptr = rsp->ring; - } else { - rsp->ring_ptr++; - } - - if (pkt->entry_status != 0) { - qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt); - ((response_t *)pkt)->signature = RESPONSE_PROCESSED; - wmb(); - continue; - } - - switch (pkt->entry_type) { - case STATUS_TYPE: - qla2x00_status_entry(vha, rsp, pkt); - break; - case STATUS_CONT_TYPE: - qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt); - break; - case VP_RPT_ID_IOCB_TYPE: - qla24xx_report_id_acquisition(vha, - (struct vp_rpt_id_entry_24xx *)pkt); - break; - case LOGINOUT_PORT_IOCB_TYPE: - qla24xx_logio_entry(vha, rsp->req, - (struct logio_entry_24xx *)pkt); - break; - case TSK_MGMT_IOCB_TYPE: - qla24xx_tm_iocb_entry(vha, rsp->req, - (struct tsk_mgmt_entry *)pkt); - break; - case CT_IOCB_TYPE: - qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE); - break; - case ELS_IOCB_TYPE: - qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE); - break; - case MARKER_TYPE: - /* Do nothing in this case, this check is to prevent it - * from falling into default case - */ - break; - default: - /* Type Not Supported. */ - ql_dbg(ql_dbg_async, vha, 0x5042, - "Received unknown response pkt type %x " - "entry status=%x.\n", - pkt->entry_type, pkt->entry_status); - break; - } - ((response_t *)pkt)->signature = RESPONSE_PROCESSED; - wmb(); - } - - /* Adjust ring index */ - if (IS_QLA82XX(ha)) { - struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; - WRT_REG_DWORD(®->rsp_q_out[0], rsp->ring_index); - } else - WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index); -} - -static void -qla2xxx_check_risc_status(scsi_qla_host_t *vha) -{ - int rval; - uint32_t cnt; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha)) - return; - - rval = QLA_SUCCESS; - WRT_REG_DWORD(®->iobase_addr, 0x7C00); - RD_REG_DWORD(®->iobase_addr); - WRT_REG_DWORD(®->iobase_window, 0x0001); - for (cnt = 10000; (RD_REG_DWORD(®->iobase_window) & BIT_0) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) { - WRT_REG_DWORD(®->iobase_window, 0x0001); - udelay(10); - } else - rval = QLA_FUNCTION_TIMEOUT; - } - if (rval == QLA_SUCCESS) - goto next_test; - - WRT_REG_DWORD(®->iobase_window, 0x0003); - for (cnt = 100; (RD_REG_DWORD(®->iobase_window) & BIT_0) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) { - WRT_REG_DWORD(®->iobase_window, 0x0003); - udelay(10); - } else - rval = QLA_FUNCTION_TIMEOUT; - } - if (rval != QLA_SUCCESS) - goto done; - -next_test: - if (RD_REG_DWORD(®->iobase_c8) & BIT_3) - ql_log(ql_log_info, vha, 0x504c, - "Additional code -- 0x55AA.\n"); - -done: - WRT_REG_DWORD(®->iobase_window, 0x0000); - RD_REG_DWORD(®->iobase_window); -} - -/** - * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx. - * @irq: - * @dev_id: SCSI driver HA context - * - * Called by system whenever the host adapter generates an interrupt. - * - * Returns handled flag. - */ -irqreturn_t -qla24xx_intr_handler(int irq, void *dev_id) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct device_reg_24xx __iomem *reg; - int status; - unsigned long iter; - uint32_t stat; - uint32_t hccr; - uint16_t mb[4]; - struct rsp_que *rsp; - unsigned long flags; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - ql_log(ql_log_info, NULL, 0x5059, - "%s: NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - - ha = rsp->hw; - reg = &ha->iobase->isp24; - status = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - return IRQ_HANDLED; - - spin_lock_irqsave(&ha->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - for (iter = 50; iter--; ) { - stat = RD_REG_DWORD(®->host_status); - if (stat & HSRX_RISC_PAUSED) { - if (unlikely(pci_channel_offline(ha->pdev))) - break; - - hccr = RD_REG_DWORD(®->hccr); - - ql_log(ql_log_warn, vha, 0x504b, - "RISC paused -- HCCR=%x, Dumping firmware.\n", - hccr); - - qla2xxx_check_risc_status(vha); - - ha->isp_ops->fw_dump(vha, 1); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - } else if ((stat & HSRX_RISC_INT) == 0) - break; - - switch (stat & 0xff) { - case 0x1: - case 0x2: - case 0x10: - case 0x11: - qla24xx_mbx_completion(vha, MSW(stat)); - status |= MBX_INTERRUPT; - - break; - case 0x12: - mb[0] = MSW(stat); - mb[1] = RD_REG_WORD(®->mailbox1); - mb[2] = RD_REG_WORD(®->mailbox2); - mb[3] = RD_REG_WORD(®->mailbox3); - qla2x00_async_event(vha, rsp, mb); - break; - case 0x13: - case 0x14: - qla24xx_process_response_queue(vha, rsp); - break; - default: - ql_dbg(ql_dbg_async, vha, 0x504f, - "Unrecognized interrupt type (%d).\n", stat * 0xff); - break; - } - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - RD_REG_DWORD_RELAXED(®->hccr); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && - (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - complete(&ha->mbx_intr_comp); - } - - return IRQ_HANDLED; -} - -static irqreturn_t -qla24xx_msix_rsp_q(int irq, void *dev_id) -{ - struct qla_hw_data *ha; - struct rsp_que *rsp; - struct device_reg_24xx __iomem *reg; - struct scsi_qla_host *vha; - unsigned long flags; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - ql_log(ql_log_info, NULL, 0x505a, - "%s: NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - ha = rsp->hw; - reg = &ha->iobase->isp24; - - spin_lock_irqsave(&ha->hardware_lock, flags); - - vha = pci_get_drvdata(ha->pdev); - qla24xx_process_response_queue(vha, rsp); - if (!ha->flags.disable_msix_handshake) { - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - RD_REG_DWORD_RELAXED(®->hccr); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return IRQ_HANDLED; -} - -static irqreturn_t -qla25xx_msix_rsp_q(int irq, void *dev_id) -{ - struct qla_hw_data *ha; - struct rsp_que *rsp; - struct device_reg_24xx __iomem *reg; - unsigned long flags; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - ql_log(ql_log_info, NULL, 0x505b, - "%s: NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - ha = rsp->hw; - - /* Clear the interrupt, if enabled, for this response queue */ - if (!ha->flags.disable_msix_handshake) { - reg = &ha->iobase->isp24; - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - RD_REG_DWORD_RELAXED(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work); - - return IRQ_HANDLED; -} - -static irqreturn_t -qla24xx_msix_default(int irq, void *dev_id) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct rsp_que *rsp; - struct device_reg_24xx __iomem *reg; - int status; - uint32_t stat; - uint32_t hccr; - uint16_t mb[4]; - unsigned long flags; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - ql_log(ql_log_info, NULL, 0x505c, - "%s: NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - ha = rsp->hw; - reg = &ha->iobase->isp24; - status = 0; - - spin_lock_irqsave(&ha->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - do { - stat = RD_REG_DWORD(®->host_status); - if (stat & HSRX_RISC_PAUSED) { - if (unlikely(pci_channel_offline(ha->pdev))) - break; - - hccr = RD_REG_DWORD(®->hccr); - - ql_log(ql_log_info, vha, 0x5050, - "RISC paused -- HCCR=%x, Dumping firmware.\n", - hccr); - - qla2xxx_check_risc_status(vha); - - ha->isp_ops->fw_dump(vha, 1); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - break; - } else if ((stat & HSRX_RISC_INT) == 0) - break; - - switch (stat & 0xff) { - case 0x1: - case 0x2: - case 0x10: - case 0x11: - qla24xx_mbx_completion(vha, MSW(stat)); - status |= MBX_INTERRUPT; - - break; - case 0x12: - mb[0] = MSW(stat); - mb[1] = RD_REG_WORD(®->mailbox1); - mb[2] = RD_REG_WORD(®->mailbox2); - mb[3] = RD_REG_WORD(®->mailbox3); - qla2x00_async_event(vha, rsp, mb); - break; - case 0x13: - case 0x14: - qla24xx_process_response_queue(vha, rsp); - break; - default: - ql_dbg(ql_dbg_async, vha, 0x5051, - "Unrecognized interrupt type (%d).\n", stat & 0xff); - break; - } - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - } while (0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && - (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - complete(&ha->mbx_intr_comp); - } - return IRQ_HANDLED; -} - -/* Interrupt handling helpers. */ - -struct qla_init_msix_entry { - const char *name; - irq_handler_t handler; -}; - -static struct qla_init_msix_entry msix_entries[3] = { - { "qla2xxx (default)", qla24xx_msix_default }, - { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, - { "qla2xxx (multiq)", qla25xx_msix_rsp_q }, -}; - -static struct qla_init_msix_entry qla82xx_msix_entries[2] = { - { "qla2xxx (default)", qla82xx_msix_default }, - { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q }, -}; - -static void -qla24xx_disable_msix(struct qla_hw_data *ha) -{ - int i; - struct qla_msix_entry *qentry; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - for (i = 0; i < ha->msix_count; i++) { - qentry = &ha->msix_entries[i]; - if (qentry->have_irq) - free_irq(qentry->vector, qentry->rsp); - } - pci_disable_msix(ha->pdev); - kfree(ha->msix_entries); - ha->msix_entries = NULL; - ha->flags.msix_enabled = 0; - ql_dbg(ql_dbg_init, vha, 0x0042, - "Disabled the MSI.\n"); -} - -static int -qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) -{ -#define MIN_MSIX_COUNT 2 - int i, ret; - struct msix_entry *entries; - struct qla_msix_entry *qentry; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count, - GFP_KERNEL); - if (!entries) { - ql_log(ql_log_warn, vha, 0x00bc, - "Failed to allocate memory for msix_entry.\n"); - return -ENOMEM; - } - - for (i = 0; i < ha->msix_count; i++) - entries[i].entry = i; - - ret = pci_enable_msix(ha->pdev, entries, ha->msix_count); - if (ret) { - if (ret < MIN_MSIX_COUNT) - goto msix_failed; - - ql_log(ql_log_warn, vha, 0x00c6, - "MSI-X: Failed to enable support " - "-- %d/%d\n Retry with %d vectors.\n", - ha->msix_count, ret, ret); - ha->msix_count = ret; - ret = pci_enable_msix(ha->pdev, entries, ha->msix_count); - if (ret) { -msix_failed: - ql_log(ql_log_fatal, vha, 0x00c7, - "MSI-X: Failed to enable support, " - "giving up -- %d/%d.\n", - ha->msix_count, ret); - goto msix_out; - } - ha->max_rsp_queues = ha->msix_count - 1; - } - ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) * - ha->msix_count, GFP_KERNEL); - if (!ha->msix_entries) { - ql_log(ql_log_fatal, vha, 0x00c8, - "Failed to allocate memory for ha->msix_entries.\n"); - ret = -ENOMEM; - goto msix_out; - } - ha->flags.msix_enabled = 1; - - for (i = 0; i < ha->msix_count; i++) { - qentry = &ha->msix_entries[i]; - qentry->vector = entries[i].vector; - qentry->entry = entries[i].entry; - qentry->have_irq = 0; - qentry->rsp = NULL; - } - - /* Enable MSI-X vectors for the base queue */ - for (i = 0; i < 2; i++) { - qentry = &ha->msix_entries[i]; - if (IS_QLA82XX(ha)) { - ret = request_irq(qentry->vector, - qla82xx_msix_entries[i].handler, - 0, qla82xx_msix_entries[i].name, rsp); - } else { - ret = request_irq(qentry->vector, - msix_entries[i].handler, - 0, msix_entries[i].name, rsp); - } - if (ret) { - ql_log(ql_log_fatal, vha, 0x00cb, - "MSI-X: unable to register handler -- %x/%d.\n", - qentry->vector, ret); - qla24xx_disable_msix(ha); - ha->mqenable = 0; - goto msix_out; - } - qentry->have_irq = 1; - qentry->rsp = rsp; - rsp->msix = qentry; - } - - /* Enable MSI-X vector for response queue update for queue 0 */ - if (IS_QLA83XX(ha)) { - if (ha->msixbase && ha->mqiobase && - (ha->max_rsp_queues > 1 || ha->max_req_queues > 1)) - ha->mqenable = 1; - } else - if (ha->mqiobase - && (ha->max_rsp_queues > 1 || ha->max_req_queues > 1)) - ha->mqenable = 1; - ql_dbg(ql_dbg_multiq, vha, 0xc005, - "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n", - ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues); - ql_dbg(ql_dbg_init, vha, 0x0055, - "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n", - ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues); - -msix_out: - kfree(entries); - return ret; -} - -int -qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp) -{ - int ret; - device_reg_t __iomem *reg = ha->iobase; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - /* If possible, enable MSI-X. */ - if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && - !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha)) - goto skip_msi; - - if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP && - (ha->pdev->subsystem_device == 0x7040 || - ha->pdev->subsystem_device == 0x7041 || - ha->pdev->subsystem_device == 0x1705)) { - ql_log(ql_log_warn, vha, 0x0034, - "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n", - ha->pdev->subsystem_vendor, - ha->pdev->subsystem_device); - goto skip_msi; - } - - if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) { - ql_log(ql_log_warn, vha, 0x0035, - "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n", - ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX); - goto skip_msix; - } - - ret = qla24xx_enable_msix(ha, rsp); - if (!ret) { - ql_dbg(ql_dbg_init, vha, 0x0036, - "MSI-X: Enabled (0x%X, 0x%X).\n", - ha->chip_revision, ha->fw_attributes); - goto clear_risc_ints; - } - ql_log(ql_log_info, vha, 0x0037, - "MSI-X Falling back-to MSI mode -%d.\n", ret); -skip_msix: - - if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) && - !IS_QLA8001(ha)) - goto skip_msi; - - ret = pci_enable_msi(ha->pdev); - if (!ret) { - ql_dbg(ql_dbg_init, vha, 0x0038, - "MSI: Enabled.\n"); - ha->flags.msi_enabled = 1; - } else - ql_log(ql_log_warn, vha, 0x0039, - "MSI-X; Falling back-to INTa mode -- %d.\n", ret); -skip_msi: - - ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, - ha->flags.msi_enabled ? 0 : IRQF_SHARED, - QLA2XXX_DRIVER_NAME, rsp); - if (ret) { - ql_log(ql_log_warn, vha, 0x003a, - "Failed to reserve interrupt %d already in use.\n", - ha->pdev->irq); - goto fail; - } - -clear_risc_ints: - - /* - * FIXME: Noted that 8014s were being dropped during NK testing. - * Timing deltas during MSI-X/INTa transitions? - */ - if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA83XX(ha)) - goto fail; - spin_lock_irq(&ha->hardware_lock); - if (IS_FWI2_CAPABLE(ha)) { - WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_HOST_INT); - WRT_REG_DWORD(®->isp24.hccr, HCCRX_CLR_RISC_INT); - } else { - WRT_REG_WORD(®->isp.semaphore, 0); - WRT_REG_WORD(®->isp.hccr, HCCR_CLR_RISC_INT); - WRT_REG_WORD(®->isp.hccr, HCCR_CLR_HOST_INT); - } - spin_unlock_irq(&ha->hardware_lock); - -fail: - return ret; -} - -void -qla2x00_free_irqs(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct rsp_que *rsp = ha->rsp_q_map[0]; - - if (ha->flags.msix_enabled) - qla24xx_disable_msix(ha); - else if (ha->flags.msi_enabled) { - free_irq(ha->pdev->irq, rsp); - pci_disable_msi(ha->pdev); - } else - free_irq(ha->pdev->irq, rsp); -} - - -int qla25xx_request_irq(struct rsp_que *rsp) -{ - struct qla_hw_data *ha = rsp->hw; - struct qla_init_msix_entry *intr = &msix_entries[2]; - struct qla_msix_entry *msix = rsp->msix; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - int ret; - - ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp); - if (ret) { - ql_log(ql_log_fatal, vha, 0x00e6, - "MSI-X: Unable to register handler -- %x/%d.\n", - msix->vector, ret); - return ret; - } - msix->have_irq = 1; - msix->rsp = rsp; - return ret; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mbx.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mbx.c deleted file mode 100644 index b4a23394..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mbx.c +++ /dev/null @@ -1,4571 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -#include -#include - - -/* - * qla2x00_mailbox_command - * Issue mailbox command and waits for completion. - * - * Input: - * ha = adapter block pointer. - * mcp = driver internal mbx struct pointer. - * - * Output: - * mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data. - * - * Returns: - * 0 : QLA_SUCCESS = cmd performed success - * 1 : QLA_FUNCTION_FAILED (error encountered) - * 6 : QLA_FUNCTION_TIMEOUT (timeout condition encountered) - * - * Context: - * Kernel context. - */ -static int -qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) -{ - int rval; - unsigned long flags = 0; - device_reg_t __iomem *reg; - uint8_t abort_active; - uint8_t io_lock_on; - uint16_t command = 0; - uint16_t *iptr; - uint16_t __iomem *optr; - uint32_t cnt; - uint32_t mboxes; - unsigned long wait_time; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - ql_dbg(ql_dbg_mbx, vha, 0x1000, "Entered %s.\n", __func__); - - if (ha->pdev->error_state > pci_channel_io_frozen) { - ql_log(ql_log_warn, vha, 0x1001, - "error_state is greater than pci_channel_io_frozen, " - "exiting.\n"); - return QLA_FUNCTION_TIMEOUT; - } - - if (vha->device_flags & DFLG_DEV_FAILED) { - ql_log(ql_log_warn, vha, 0x1002, - "Device in failed state, exiting.\n"); - return QLA_FUNCTION_TIMEOUT; - } - - reg = ha->iobase; - io_lock_on = base_vha->flags.init_done; - - rval = QLA_SUCCESS; - abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - - - if (ha->flags.pci_channel_io_perm_failure) { - ql_log(ql_log_warn, vha, 0x1003, - "Perm failure on EEH timeout MBX, exiting.\n"); - return QLA_FUNCTION_TIMEOUT; - } - - if (ha->flags.isp82xx_fw_hung) { - /* Setting Link-Down error */ - mcp->mb[0] = MBS_LINK_DOWN_ERROR; - ql_log(ql_log_warn, vha, 0x1004, - "FW hung = %d.\n", ha->flags.isp82xx_fw_hung); - return QLA_FUNCTION_TIMEOUT; - } - - /* - * Wait for active mailbox commands to finish by waiting at most tov - * seconds. This is to serialize actual issuing of mailbox cmds during - * non ISP abort time. - */ - if (!wait_for_completion_timeout(&ha->mbx_cmd_comp, mcp->tov * HZ)) { - /* Timeout occurred. Return error. */ - ql_log(ql_log_warn, vha, 0x1005, - "Cmd access timeout, cmd=0x%x, Exiting.\n", - mcp->mb[0]); - return QLA_FUNCTION_TIMEOUT; - } - - ha->flags.mbox_busy = 1; - /* Save mailbox command for debug */ - ha->mcp = mcp; - - ql_dbg(ql_dbg_mbx, vha, 0x1006, - "Prepare to issue mbox cmd=0x%x.\n", mcp->mb[0]); - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Load mailbox registers. */ - if (IS_QLA82XX(ha)) - optr = (uint16_t __iomem *)®->isp82.mailbox_in[0]; - else if (IS_FWI2_CAPABLE(ha) && !IS_QLA82XX(ha)) - optr = (uint16_t __iomem *)®->isp24.mailbox0; - else - optr = (uint16_t __iomem *)MAILBOX_REG(ha, ®->isp, 0); - - iptr = mcp->mb; - command = mcp->mb[0]; - mboxes = mcp->out_mb; - - for (cnt = 0; cnt < ha->mbx_count; cnt++) { - if (IS_QLA2200(ha) && cnt == 8) - optr = - (uint16_t __iomem *)MAILBOX_REG(ha, ®->isp, 8); - if (mboxes & BIT_0) - WRT_REG_WORD(optr, *iptr); - - mboxes >>= 1; - optr++; - iptr++; - } - - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1111, - "Loaded MBX registers (displayed in bytes) =.\n"); - ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1112, - (uint8_t *)mcp->mb, 16); - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1113, - ".\n"); - ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1114, - ((uint8_t *)mcp->mb + 0x10), 16); - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1115, - ".\n"); - ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1116, - ((uint8_t *)mcp->mb + 0x20), 8); - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1117, - "I/O Address = %p.\n", optr); - ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x100e); - - /* Issue set host interrupt command to send cmd out. */ - ha->flags.mbox_int = 0; - clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - - /* Unlock mbx registers and wait for interrupt */ - ql_dbg(ql_dbg_mbx, vha, 0x100f, - "Going to unlock irq & waiting for interrupts. " - "jiffies=%lx.\n", jiffies); - - /* Wait for mbx cmd completion until timeout */ - - if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) { - set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); - - if (IS_QLA82XX(ha)) { - if (RD_REG_DWORD(®->isp82.hint) & - HINT_MBX_INT_PENDING) { - spin_unlock_irqrestore(&ha->hardware_lock, - flags); - ha->flags.mbox_busy = 0; - ql_dbg(ql_dbg_mbx, vha, 0x1010, - "Pending mailbox timeout, exiting.\n"); - rval = QLA_FUNCTION_TIMEOUT; - goto premature_exit; - } - WRT_REG_DWORD(®->isp82.hint, HINT_MBX_INT_PENDING); - } else if (IS_FWI2_CAPABLE(ha)) - WRT_REG_DWORD(®->isp24.hccr, HCCRX_SET_HOST_INT); - else - WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ); - - clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); - - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1011, - "Cmd=%x Polling Mode.\n", command); - - if (IS_QLA82XX(ha)) { - if (RD_REG_DWORD(®->isp82.hint) & - HINT_MBX_INT_PENDING) { - spin_unlock_irqrestore(&ha->hardware_lock, - flags); - ha->flags.mbox_busy = 0; - ql_dbg(ql_dbg_mbx, vha, 0x1012, - "Pending mailbox timeout, exiting.\n"); - rval = QLA_FUNCTION_TIMEOUT; - goto premature_exit; - } - WRT_REG_DWORD(®->isp82.hint, HINT_MBX_INT_PENDING); - } else if (IS_FWI2_CAPABLE(ha)) - WRT_REG_DWORD(®->isp24.hccr, HCCRX_SET_HOST_INT); - else - WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */ - while (!ha->flags.mbox_int) { - if (time_after(jiffies, wait_time)) - break; - - /* Check for pending interrupts. */ - qla2x00_poll(ha->rsp_q_map[0]); - - if (!ha->flags.mbox_int && - !(IS_QLA2200(ha) && - command == MBC_LOAD_RISC_RAM_EXTENDED)) - msleep(10); - } /* while */ - ql_dbg(ql_dbg_mbx, vha, 0x1013, - "Waited %d sec.\n", - (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ)); - } - - /* Check whether we timed out */ - if (ha->flags.mbox_int) { - uint16_t *iptr2; - - ql_dbg(ql_dbg_mbx, vha, 0x1014, - "Cmd=%x completed.\n", command); - - /* Got interrupt. Clear the flag. */ - ha->flags.mbox_int = 0; - clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - - if (ha->flags.isp82xx_fw_hung) { - ha->flags.mbox_busy = 0; - /* Setting Link-Down error */ - mcp->mb[0] = MBS_LINK_DOWN_ERROR; - ha->mcp = NULL; - rval = QLA_FUNCTION_FAILED; - ql_log(ql_log_warn, vha, 0x1015, - "FW hung = %d.\n", ha->flags.isp82xx_fw_hung); - goto premature_exit; - } - - if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE) - rval = QLA_FUNCTION_FAILED; - - /* Load return mailbox registers. */ - iptr2 = mcp->mb; - iptr = (uint16_t *)&ha->mailbox_out[0]; - mboxes = mcp->in_mb; - for (cnt = 0; cnt < ha->mbx_count; cnt++) { - if (mboxes & BIT_0) - *iptr2 = *iptr; - - mboxes >>= 1; - iptr2++; - iptr++; - } - } else { - - uint16_t mb0; - uint32_t ictrl; - - if (IS_FWI2_CAPABLE(ha)) { - mb0 = RD_REG_WORD(®->isp24.mailbox0); - ictrl = RD_REG_DWORD(®->isp24.ictrl); - } else { - mb0 = RD_MAILBOX_REG(ha, ®->isp, 0); - ictrl = RD_REG_WORD(®->isp.ictrl); - } - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1119, - "MBX Command timeout for cmd %x.\n", command); - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111a, - "iocontrol=%x jiffies=%lx.\n", ictrl, jiffies); - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111b, - "mb[0] = 0x%x.\n", mb0); - ql_dump_regs(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1019); - - /* - * Attempt to capture a firmware dump for further analysis - * of the current firmware state - */ - ha->isp_ops->fw_dump(vha, 0); - - rval = QLA_FUNCTION_TIMEOUT; - } - - ha->flags.mbox_busy = 0; - - /* Clean up */ - ha->mcp = NULL; - - if ((abort_active || !io_lock_on) && !IS_NOPOLLING_TYPE(ha)) { - ql_dbg(ql_dbg_mbx, vha, 0x101a, - "Checking for additional resp interrupt.\n"); - - /* polling mode for non isp_abort commands. */ - qla2x00_poll(ha->rsp_q_map[0]); - } - - if (rval == QLA_FUNCTION_TIMEOUT && - mcp->mb[0] != MBC_GEN_SYSTEM_ERROR) { - if (!io_lock_on || (mcp->flags & IOCTL_CMD) || - ha->flags.eeh_busy) { - /* not in dpc. schedule it for dpc to take over. */ - ql_dbg(ql_dbg_mbx, vha, 0x101b, - "Timeout, schedule isp_abort_needed.\n"); - - if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && - !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && - !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - if (IS_QLA82XX(ha)) { - ql_dbg(ql_dbg_mbx, vha, 0x112a, - "disabling pause transmit on port " - "0 & 1.\n"); - qla82xx_wr_32(ha, - QLA82XX_CRB_NIU + 0x98, - CRB_NIU_XG_PAUSE_CTL_P0| - CRB_NIU_XG_PAUSE_CTL_P1); - } - ql_log(ql_log_info, base_vha, 0x101c, - "Mailbox cmd timeout occured, cmd=0x%x, " - "mb[0]=0x%x, eeh_busy=0x%x. Scheduling ISP " - "abort.\n", command, mcp->mb[0], - ha->flags.eeh_busy); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } - } else if (!abort_active) { - /* call abort directly since we are in the DPC thread */ - ql_dbg(ql_dbg_mbx, vha, 0x101d, - "Timeout, calling abort_isp.\n"); - - if (!test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) && - !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && - !test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - if (IS_QLA82XX(ha)) { - ql_dbg(ql_dbg_mbx, vha, 0x112b, - "disabling pause transmit on port " - "0 & 1.\n"); - qla82xx_wr_32(ha, - QLA82XX_CRB_NIU + 0x98, - CRB_NIU_XG_PAUSE_CTL_P0| - CRB_NIU_XG_PAUSE_CTL_P1); - } - ql_log(ql_log_info, base_vha, 0x101e, - "Mailbox cmd timeout occured, cmd=0x%x, " - "mb[0]=0x%x. Scheduling ISP abort ", - command, mcp->mb[0]); - set_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); - clear_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - /* Allow next mbx cmd to come in. */ - complete(&ha->mbx_cmd_comp); - if (ha->isp_ops->abort_isp(vha)) { - /* Failed. retry later. */ - set_bit(ISP_ABORT_NEEDED, - &vha->dpc_flags); - } - clear_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); - ql_dbg(ql_dbg_mbx, vha, 0x101f, - "Finished abort_isp.\n"); - goto mbx_done; - } - } - } - -premature_exit: - /* Allow next mbx cmd to come in. */ - complete(&ha->mbx_cmd_comp); - -mbx_done: - if (rval) { - ql_dbg(ql_dbg_mbx, base_vha, 0x1020, - "**** Failed mbx[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x, cmd=%x ****.\n", - mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3], command); - } else { - ql_dbg(ql_dbg_mbx, base_vha, 0x1021, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr, - uint32_t risc_code_size) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1022, "Entered %s.\n", __func__); - - if (MSW(risc_addr) || IS_FWI2_CAPABLE(ha)) { - mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED; - mcp->mb[8] = MSW(risc_addr); - mcp->out_mb = MBX_8|MBX_0; - } else { - mcp->mb[0] = MBC_LOAD_RISC_RAM; - mcp->out_mb = MBX_0; - } - mcp->mb[1] = LSW(risc_addr); - mcp->mb[2] = MSW(req_dma); - mcp->mb[3] = LSW(req_dma); - mcp->mb[6] = MSW(MSD(req_dma)); - mcp->mb[7] = LSW(MSD(req_dma)); - mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1; - if (IS_FWI2_CAPABLE(ha)) { - mcp->mb[4] = MSW(risc_code_size); - mcp->mb[5] = LSW(risc_code_size); - mcp->out_mb |= MBX_5|MBX_4; - } else { - mcp->mb[4] = LSW(risc_code_size); - mcp->out_mb |= MBX_4; - } - - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1023, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1024, "Done %s.\n", __func__); - } - - return rval; -} - -#define EXTENDED_BB_CREDITS BIT_0 -/* - * qla2x00_execute_fw - * Start adapter firmware. - * - * Input: - * ha = adapter block pointer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1025, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_EXECUTE_FIRMWARE; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_0; - if (IS_FWI2_CAPABLE(ha)) { - mcp->mb[1] = MSW(risc_addr); - mcp->mb[2] = LSW(risc_addr); - mcp->mb[3] = 0; - if (IS_QLA81XX(ha) || IS_QLA83XX(ha)) { - struct nvram_81xx *nv = ha->nvram; - mcp->mb[4] = (nv->enhanced_features & - EXTENDED_BB_CREDITS); - } else - mcp->mb[4] = 0; - mcp->out_mb |= MBX_4|MBX_3|MBX_2|MBX_1; - mcp->in_mb |= MBX_1; - } else { - mcp->mb[1] = LSW(risc_addr); - mcp->out_mb |= MBX_1; - if (IS_QLA2322(ha) || IS_QLA6322(ha)) { - mcp->mb[2] = 0; - mcp->out_mb |= MBX_2; - } - } - - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1026, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - if (IS_FWI2_CAPABLE(ha)) { - ql_dbg(ql_dbg_mbx, vha, 0x1027, - "Done exchanges=%x.\n", mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1028, "Done %s.\n", __func__); - } - } - - return rval; -} - -/* - * qla2x00_get_fw_version - * Get firmware version. - * - * Input: - * ha: adapter state pointer. - * major: pointer for major number. - * minor: pointer for minor number. - * subminor: pointer for subminor number. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_fw_version(scsi_qla_host_t *vha) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x1029, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_FIRMWARE_VERSION; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - if (IS_QLA81XX(vha->hw) || IS_QLA8031(ha)) - mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8; - if (IS_QLA83XX(vha->hw)) - mcp->in_mb |= MBX_17|MBX_16|MBX_15; - mcp->flags = 0; - mcp->tov = MBX_TOV_SECONDS; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) - goto failed; - - /* Return mailbox data. */ - ha->fw_major_version = mcp->mb[1]; - ha->fw_minor_version = mcp->mb[2]; - ha->fw_subminor_version = mcp->mb[3]; - ha->fw_attributes = mcp->mb[6]; - if (IS_QLA2100(vha->hw) || IS_QLA2200(vha->hw)) - ha->fw_memory_size = 0x1FFFF; /* Defaults to 128KB. */ - else - ha->fw_memory_size = (mcp->mb[5] << 16) | mcp->mb[4]; - if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw)) { - ha->mpi_version[0] = mcp->mb[10] & 0xff; - ha->mpi_version[1] = mcp->mb[11] >> 8; - ha->mpi_version[2] = mcp->mb[11] & 0xff; - ha->mpi_capabilities = (mcp->mb[12] << 16) | mcp->mb[13]; - ha->phy_version[0] = mcp->mb[8] & 0xff; - ha->phy_version[1] = mcp->mb[9] >> 8; - ha->phy_version[2] = mcp->mb[9] & 0xff; - } - if (IS_QLA83XX(ha)) { - if (mcp->mb[6] & BIT_15) { - ha->fw_attributes_h = mcp->mb[15]; - ha->fw_attributes_ext[0] = mcp->mb[16]; - ha->fw_attributes_ext[1] = mcp->mb[17]; - ql_dbg(ql_dbg_mbx, vha, 0x1139, - "%s: FW_attributes Upper: 0x%x, Lower: 0x%x.\n", - __func__, mcp->mb[15], mcp->mb[6]); - } else - ql_dbg(ql_dbg_mbx, vha, 0x112f, - "%s: FwAttributes [Upper] invalid, MB6:%04x\n", - __func__, mcp->mb[6]); - } - -failed: - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x102a, "Failed=%x.\n", rval); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x102b, "Done %s.\n", __func__); - } - return rval; -} - -/* - * qla2x00_get_fw_options - * Set firmware options. - * - * Input: - * ha = adapter block pointer. - * fwopt = pointer for firmware options. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x102c, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_FIRMWARE_OPTION; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x102d, "Failed=%x.\n", rval); - } else { - fwopts[0] = mcp->mb[0]; - fwopts[1] = mcp->mb[1]; - fwopts[2] = mcp->mb[2]; - fwopts[3] = mcp->mb[3]; - - ql_dbg(ql_dbg_mbx, vha, 0x102e, "Done %s.\n", __func__); - } - - return rval; -} - - -/* - * qla2x00_set_fw_options - * Set firmware options. - * - * Input: - * ha = adapter block pointer. - * fwopt = pointer for firmware options. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_set_fw_options(scsi_qla_host_t *vha, uint16_t *fwopts) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x102f, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_SET_FIRMWARE_OPTION; - mcp->mb[1] = fwopts[1]; - mcp->mb[2] = fwopts[2]; - mcp->mb[3] = fwopts[3]; - mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - if (IS_FWI2_CAPABLE(vha->hw)) { - mcp->in_mb |= MBX_1; - } else { - mcp->mb[10] = fwopts[10]; - mcp->mb[11] = fwopts[11]; - mcp->mb[12] = 0; /* Undocumented, but used */ - mcp->out_mb |= MBX_12|MBX_11|MBX_10; - } - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - fwopts[0] = mcp->mb[0]; - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1030, - "Failed=%x (%x/%x).\n", rval, mcp->mb[0], mcp->mb[1]); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1031, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_mbx_reg_test - * Mailbox register wrap test. - * - * Input: - * ha = adapter block pointer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_mbx_reg_test(scsi_qla_host_t *vha) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1032, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST; - mcp->mb[1] = 0xAAAA; - mcp->mb[2] = 0x5555; - mcp->mb[3] = 0xAA55; - mcp->mb[4] = 0x55AA; - mcp->mb[5] = 0xA5A5; - mcp->mb[6] = 0x5A5A; - mcp->mb[7] = 0x2525; - mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval == QLA_SUCCESS) { - if (mcp->mb[1] != 0xAAAA || mcp->mb[2] != 0x5555 || - mcp->mb[3] != 0xAA55 || mcp->mb[4] != 0x55AA) - rval = QLA_FUNCTION_FAILED; - if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A || - mcp->mb[7] != 0x2525) - rval = QLA_FUNCTION_FAILED; - } - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1033, "Failed=%x.\n", rval); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1034, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_verify_checksum - * Verify firmware checksum. - * - * Input: - * ha = adapter block pointer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_verify_checksum(scsi_qla_host_t *vha, uint32_t risc_addr) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1035, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_VERIFY_CHECKSUM; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_0; - if (IS_FWI2_CAPABLE(vha->hw)) { - mcp->mb[1] = MSW(risc_addr); - mcp->mb[2] = LSW(risc_addr); - mcp->out_mb |= MBX_2|MBX_1; - mcp->in_mb |= MBX_2|MBX_1; - } else { - mcp->mb[1] = LSW(risc_addr); - mcp->out_mb |= MBX_1; - mcp->in_mb |= MBX_1; - } - - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1036, - "Failed=%x chm sum=%x.\n", rval, IS_FWI2_CAPABLE(vha->hw) ? - (mcp->mb[2] << 16) | mcp->mb[1] : mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1037, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_issue_iocb - * Issue IOCB using mailbox command - * - * Input: - * ha = adapter state pointer. - * buffer = buffer pointer. - * phys_addr = physical address of buffer. - * size = size of buffer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_issue_iocb_timeout(scsi_qla_host_t *vha, void *buffer, - dma_addr_t phys_addr, size_t size, uint32_t tov) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1038, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_IOCB_COMMAND_A64; - mcp->mb[1] = 0; - mcp->mb[2] = MSW(phys_addr); - mcp->mb[3] = LSW(phys_addr); - mcp->mb[6] = MSW(MSD(phys_addr)); - mcp->mb[7] = LSW(MSD(phys_addr)); - mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_2|MBX_0; - mcp->tov = tov; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1039, "Failed=%x.\n", rval); - } else { - sts_entry_t *sts_entry = (sts_entry_t *) buffer; - - /* Mask reserved bits. */ - sts_entry->entry_status &= - IS_FWI2_CAPABLE(vha->hw) ? RF_MASK_24XX : RF_MASK; - ql_dbg(ql_dbg_mbx, vha, 0x103a, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_issue_iocb(scsi_qla_host_t *vha, void *buffer, dma_addr_t phys_addr, - size_t size) -{ - return qla2x00_issue_iocb_timeout(vha, buffer, phys_addr, size, - MBX_TOV_SECONDS); -} - -/* - * qla2x00_abort_command - * Abort command aborts a specified IOCB. - * - * Input: - * ha = adapter block pointer. - * sp = SB structure pointer. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_abort_command(srb_t *sp) -{ - unsigned long flags = 0; - int rval; - uint32_t handle = 0; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - fc_port_t *fcport = sp->fcport; - scsi_qla_host_t *vha = fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = vha->req; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - - ql_dbg(ql_dbg_mbx, vha, 0x103b, "Entered %s.\n", __func__); - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { - if (req->outstanding_cmds[handle] == sp) - break; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (handle == MAX_OUTSTANDING_COMMANDS) { - /* command not found */ - return QLA_FUNCTION_FAILED; - } - - mcp->mb[0] = MBC_ABORT_COMMAND; - if (HAS_EXTENDED_IDS(ha)) - mcp->mb[1] = fcport->loop_id; - else - mcp->mb[1] = fcport->loop_id << 8; - mcp->mb[2] = (uint16_t)handle; - mcp->mb[3] = (uint16_t)(handle >> 16); - mcp->mb[6] = (uint16_t)cmd->device->lun; - mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x103c, "Failed=%x.\n", rval); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x103d, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_abort_target(struct fc_port *fcport, unsigned int l, int tag) -{ - int rval, rval2; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - scsi_qla_host_t *vha; - struct req_que *req; - struct rsp_que *rsp; - - l = l; - vha = fcport->vha; - - ql_dbg(ql_dbg_mbx, vha, 0x103e, "Entered %s.\n", __func__); - - req = vha->hw->req_q_map[0]; - rsp = req->rsp; - mcp->mb[0] = MBC_ABORT_TARGET; - mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0; - if (HAS_EXTENDED_IDS(vha->hw)) { - mcp->mb[1] = fcport->loop_id; - mcp->mb[10] = 0; - mcp->out_mb |= MBX_10; - } else { - mcp->mb[1] = fcport->loop_id << 8; - } - mcp->mb[2] = vha->hw->loop_reset_delay; - mcp->mb[9] = vha->vp_idx; - - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x103f, "Failed=%x.\n", rval); - } - - /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, 0, - MK_SYNC_ID); - if (rval2 != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1040, - "Failed to issue marker IOCB (%x).\n", rval2); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1041, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_lun_reset(struct fc_port *fcport, unsigned int l, int tag) -{ - int rval, rval2; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - scsi_qla_host_t *vha; - struct req_que *req; - struct rsp_que *rsp; - - vha = fcport->vha; - - ql_dbg(ql_dbg_mbx, vha, 0x1042, "Entered %s.\n", __func__); - - req = vha->hw->req_q_map[0]; - rsp = req->rsp; - mcp->mb[0] = MBC_LUN_RESET; - mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; - if (HAS_EXTENDED_IDS(vha->hw)) - mcp->mb[1] = fcport->loop_id; - else - mcp->mb[1] = fcport->loop_id << 8; - mcp->mb[2] = l; - mcp->mb[3] = 0; - mcp->mb[9] = vha->vp_idx; - - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1043, "Failed=%x.\n", rval); - } - - /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l, - MK_SYNC_ID_LUN); - if (rval2 != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1044, - "Failed to issue marker IOCB (%x).\n", rval2); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1045, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_get_adapter_id - * Get adapter ID and topology. - * - * Input: - * ha = adapter block pointer. - * id = pointer for loop ID. - * al_pa = pointer for AL_PA. - * area = pointer for area. - * domain = pointer for domain. - * top = pointer for topology. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, - uint8_t *area, uint8_t *domain, uint16_t *top, uint16_t *sw_cap) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1046, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID; - mcp->mb[9] = vha->vp_idx; - mcp->out_mb = MBX_9|MBX_0; - mcp->in_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - if (IS_CNA_CAPABLE(vha->hw)) - mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (mcp->mb[0] == MBS_COMMAND_ERROR) - rval = QLA_COMMAND_ERROR; - else if (mcp->mb[0] == MBS_INVALID_COMMAND) - rval = QLA_INVALID_COMMAND; - - /* Return data. */ - *id = mcp->mb[1]; - *al_pa = LSB(mcp->mb[2]); - *area = MSB(mcp->mb[2]); - *domain = LSB(mcp->mb[3]); - *top = mcp->mb[6]; - *sw_cap = mcp->mb[7]; - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1047, "Failed=%x.\n", rval); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1048, "Done %s.\n", __func__); - - if (IS_CNA_CAPABLE(vha->hw)) { - vha->fcoe_vlan_id = mcp->mb[9] & 0xfff; - vha->fcoe_fcf_idx = mcp->mb[10]; - vha->fcoe_vn_port_mac[5] = mcp->mb[11] >> 8; - vha->fcoe_vn_port_mac[4] = mcp->mb[11] & 0xff; - vha->fcoe_vn_port_mac[3] = mcp->mb[12] >> 8; - vha->fcoe_vn_port_mac[2] = mcp->mb[12] & 0xff; - vha->fcoe_vn_port_mac[1] = mcp->mb[13] >> 8; - vha->fcoe_vn_port_mac[0] = mcp->mb[13] & 0xff; - } - } - - return rval; -} - -/* - * qla2x00_get_retry_cnt - * Get current firmware login retry count and delay. - * - * Input: - * ha = adapter block pointer. - * retry_cnt = pointer to login retry count. - * tov = pointer to login timeout value. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_retry_cnt(scsi_qla_host_t *vha, uint8_t *retry_cnt, uint8_t *tov, - uint16_t *r_a_tov) -{ - int rval; - uint16_t ratov; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1049, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_RETRY_COUNT; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x104a, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - /* Convert returned data and check our values. */ - *r_a_tov = mcp->mb[3] / 2; - ratov = (mcp->mb[3]/2) / 10; /* mb[3] value is in 100ms */ - if (mcp->mb[1] * ratov > (*retry_cnt) * (*tov)) { - /* Update to the larger values */ - *retry_cnt = (uint8_t)mcp->mb[1]; - *tov = ratov; - } - - ql_dbg(ql_dbg_mbx, vha, 0x104b, - "Done %s mb3=%d ratov=%d.\n", __func__, mcp->mb[3], ratov); - } - - return rval; -} - -/* - * qla2x00_init_firmware - * Initialize adapter firmware. - * - * Input: - * ha = adapter block pointer. - * dptr = Initialization control block pointer. - * size = size of initialization control block. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x104c, "Entered %s.\n", __func__); - - if (IS_QLA82XX(ha) && ql2xdbwr) - qla82xx_wr_32(ha, ha->nxdb_wr_ptr, - (0x04 | (ha->portnum << 5) | (0 << 8) | (0 << 16))); - - if (ha->flags.npiv_supported) - mcp->mb[0] = MBC_MID_INITIALIZE_FIRMWARE; - else - mcp->mb[0] = MBC_INITIALIZE_FIRMWARE; - - mcp->mb[1] = 0; - mcp->mb[2] = MSW(ha->init_cb_dma); - mcp->mb[3] = LSW(ha->init_cb_dma); - mcp->mb[6] = MSW(MSD(ha->init_cb_dma)); - mcp->mb[7] = LSW(MSD(ha->init_cb_dma)); - mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - if ((IS_QLA81XX(ha) || IS_QLA83XX(ha)) && ha->ex_init_cb->ex_version) { - mcp->mb[1] = BIT_0; - mcp->mb[10] = MSW(ha->ex_init_cb_dma); - mcp->mb[11] = LSW(ha->ex_init_cb_dma); - mcp->mb[12] = MSW(MSD(ha->ex_init_cb_dma)); - mcp->mb[13] = LSW(MSD(ha->ex_init_cb_dma)); - mcp->mb[14] = sizeof(*ha->ex_init_cb); - mcp->out_mb |= MBX_14|MBX_13|MBX_12|MBX_11|MBX_10; - } - /* 1 and 2 should normally be captured. */ - mcp->in_mb = MBX_2|MBX_1|MBX_0; - if (IS_QLA83XX(ha)) - /* mb3 is additional info about the installed SFP. */ - mcp->in_mb |= MBX_3; - mcp->buf_size = size; - mcp->flags = MBX_DMA_OUT; - mcp->tov = MBX_TOV_SECONDS; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x104d, - "Failed=%x mb[0]=%x, mb[1]=%x, mb[2]=%x, mb[3]=%x,.\n", - rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x104e, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_get_port_database - * Issue normal/enhanced get port database mailbox command - * and copy device name as necessary. - * - * Input: - * ha = adapter state pointer. - * dev = structure pointer. - * opt = enhanced cmd option byte. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - port_database_t *pd; - struct port_database_24xx *pd24; - dma_addr_t pd_dma; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x104f, "Entered %s.\n", __func__); - - pd24 = NULL; - pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pd_dma); - if (pd == NULL) { - ql_log(ql_log_warn, vha, 0x1050, - "Failed to allocate port database structure.\n"); - return QLA_MEMORY_ALLOC_FAILED; - } - memset(pd, 0, max(PORT_DATABASE_SIZE, PORT_DATABASE_24XX_SIZE)); - - mcp->mb[0] = MBC_GET_PORT_DATABASE; - if (opt != 0 && !IS_FWI2_CAPABLE(ha)) - mcp->mb[0] = MBC_ENHANCED_GET_PORT_DATABASE; - mcp->mb[2] = MSW(pd_dma); - mcp->mb[3] = LSW(pd_dma); - mcp->mb[6] = MSW(MSD(pd_dma)); - mcp->mb[7] = LSW(MSD(pd_dma)); - mcp->mb[9] = vha->vp_idx; - mcp->out_mb = MBX_9|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; - mcp->in_mb = MBX_0; - if (IS_FWI2_CAPABLE(ha)) { - mcp->mb[1] = fcport->loop_id; - mcp->mb[10] = opt; - mcp->out_mb |= MBX_10|MBX_1; - mcp->in_mb |= MBX_1; - } else if (HAS_EXTENDED_IDS(ha)) { - mcp->mb[1] = fcport->loop_id; - mcp->mb[10] = opt; - mcp->out_mb |= MBX_10|MBX_1; - } else { - mcp->mb[1] = fcport->loop_id << 8 | opt; - mcp->out_mb |= MBX_1; - } - mcp->buf_size = IS_FWI2_CAPABLE(ha) ? - PORT_DATABASE_24XX_SIZE : PORT_DATABASE_SIZE; - mcp->flags = MBX_DMA_IN; - mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2); - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) - goto gpd_error_out; - - if (IS_FWI2_CAPABLE(ha)) { - uint64_t zero = 0; - pd24 = (struct port_database_24xx *) pd; - - /* Check for logged in state. */ - if (pd24->current_login_state != PDS_PRLI_COMPLETE && - pd24->last_login_state != PDS_PRLI_COMPLETE) { - ql_dbg(ql_dbg_mbx, vha, 0x1051, - "Unable to verify login-state (%x/%x) for " - "loop_id %x.\n", pd24->current_login_state, - pd24->last_login_state, fcport->loop_id); - rval = QLA_FUNCTION_FAILED; - goto gpd_error_out; - } - - if (fcport->loop_id == FC_NO_LOOP_ID || - (memcmp(fcport->port_name, (uint8_t *)&zero, 8) && - memcmp(fcport->port_name, pd24->port_name, 8))) { - /* We lost the device mid way. */ - rval = QLA_NOT_LOGGED_IN; - goto gpd_error_out; - } - - /* Names are little-endian. */ - memcpy(fcport->node_name, pd24->node_name, WWN_SIZE); - memcpy(fcport->port_name, pd24->port_name, WWN_SIZE); - - /* Get port_id of device. */ - fcport->d_id.b.domain = pd24->port_id[0]; - fcport->d_id.b.area = pd24->port_id[1]; - fcport->d_id.b.al_pa = pd24->port_id[2]; - fcport->d_id.b.rsvd_1 = 0; - - /* If not target must be initiator or unknown type. */ - if ((pd24->prli_svc_param_word_3[0] & BIT_4) == 0) - fcport->port_type = FCT_INITIATOR; - else - fcport->port_type = FCT_TARGET; - } else { - uint64_t zero = 0; - - /* Check for logged in state. */ - if (pd->master_state != PD_STATE_PORT_LOGGED_IN && - pd->slave_state != PD_STATE_PORT_LOGGED_IN) { - ql_dbg(ql_dbg_mbx, vha, 0x100a, - "Unable to verify login-state (%x/%x) - " - "portid=%02x%02x%02x.\n", pd->master_state, - pd->slave_state, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - rval = QLA_FUNCTION_FAILED; - goto gpd_error_out; - } - - if (fcport->loop_id == FC_NO_LOOP_ID || - (memcmp(fcport->port_name, (uint8_t *)&zero, 8) && - memcmp(fcport->port_name, pd->port_name, 8))) { - /* We lost the device mid way. */ - rval = QLA_NOT_LOGGED_IN; - goto gpd_error_out; - } - - /* Names are little-endian. */ - memcpy(fcport->node_name, pd->node_name, WWN_SIZE); - memcpy(fcport->port_name, pd->port_name, WWN_SIZE); - - /* Get port_id of device. */ - fcport->d_id.b.domain = pd->port_id[0]; - fcport->d_id.b.area = pd->port_id[3]; - fcport->d_id.b.al_pa = pd->port_id[2]; - fcport->d_id.b.rsvd_1 = 0; - - /* If not target must be initiator or unknown type. */ - if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0) - fcport->port_type = FCT_INITIATOR; - else - fcport->port_type = FCT_TARGET; - - /* Passback COS information. */ - fcport->supported_classes = (pd->options & BIT_4) ? - FC_COS_CLASS2: FC_COS_CLASS3; - } - -gpd_error_out: - dma_pool_free(ha->s_dma_pool, pd, pd_dma); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1052, - "Failed=%x mb[0]=%x mb[1]=%x.\n", rval, - mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1053, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_get_firmware_state - * Get adapter firmware state. - * - * Input: - * ha = adapter block pointer. - * dptr = pointer for firmware state. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1054, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_FIRMWARE_STATE; - mcp->out_mb = MBX_0; - if (IS_FWI2_CAPABLE(vha->hw)) - mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - else - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - /* Return firmware states. */ - states[0] = mcp->mb[1]; - if (IS_FWI2_CAPABLE(vha->hw)) { - states[1] = mcp->mb[2]; - states[2] = mcp->mb[3]; - states[3] = mcp->mb[4]; - states[4] = mcp->mb[5]; - } - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1056, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_get_port_name - * Issue get port name mailbox command. - * Returned name is in big endian format. - * - * Input: - * ha = adapter block pointer. - * loop_id = loop ID of device. - * name = pointer for name. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_port_name(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t *name, - uint8_t opt) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1057, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_PORT_NAME; - mcp->mb[9] = vha->vp_idx; - mcp->out_mb = MBX_9|MBX_1|MBX_0; - if (HAS_EXTENDED_IDS(vha->hw)) { - mcp->mb[1] = loop_id; - mcp->mb[10] = opt; - mcp->out_mb |= MBX_10; - } else { - mcp->mb[1] = loop_id << 8 | opt; - } - - mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1058, "Failed=%x.\n", rval); - } else { - if (name != NULL) { - /* This function returns name in big endian. */ - name[0] = MSB(mcp->mb[2]); - name[1] = LSB(mcp->mb[2]); - name[2] = MSB(mcp->mb[3]); - name[3] = LSB(mcp->mb[3]); - name[4] = MSB(mcp->mb[6]); - name[5] = LSB(mcp->mb[6]); - name[6] = MSB(mcp->mb[7]); - name[7] = LSB(mcp->mb[7]); - } - - ql_dbg(ql_dbg_mbx, vha, 0x1059, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_lip_reset - * Issue LIP reset mailbox command. - * - * Input: - * ha = adapter block pointer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_lip_reset(scsi_qla_host_t *vha) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x105a, "Entered %s.\n", __func__); - - if (IS_CNA_CAPABLE(vha->hw)) { - /* Logout across all FCFs. */ - mcp->mb[0] = MBC_LIP_FULL_LOGIN; - mcp->mb[1] = BIT_1; - mcp->mb[2] = 0; - mcp->out_mb = MBX_2|MBX_1|MBX_0; - } else if (IS_FWI2_CAPABLE(vha->hw)) { - mcp->mb[0] = MBC_LIP_FULL_LOGIN; - mcp->mb[1] = BIT_6; - mcp->mb[2] = 0; - mcp->mb[3] = vha->hw->loop_reset_delay; - mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; - } else { - mcp->mb[0] = MBC_LIP_RESET; - mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; - if (HAS_EXTENDED_IDS(vha->hw)) { - mcp->mb[1] = 0x00ff; - mcp->mb[10] = 0; - mcp->out_mb |= MBX_10; - } else { - mcp->mb[1] = 0xff00; - } - mcp->mb[2] = vha->hw->loop_reset_delay; - mcp->mb[3] = 0; - } - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x105b, "Failed=%x.\n", rval); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x105c, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_send_sns - * Send SNS command. - * - * Input: - * ha = adapter block pointer. - * sns = pointer for command. - * cmd_size = command size. - * buf_size = response/command size. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_send_sns(scsi_qla_host_t *vha, dma_addr_t sns_phys_address, - uint16_t cmd_size, size_t buf_size) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x105d, "Entered %s.\n", __func__); - - ql_dbg(ql_dbg_mbx, vha, 0x105e, - "Retry cnt=%d ratov=%d total tov=%d.\n", - vha->hw->retry_count, vha->hw->login_timeout, mcp->tov); - - mcp->mb[0] = MBC_SEND_SNS_COMMAND; - mcp->mb[1] = cmd_size; - mcp->mb[2] = MSW(sns_phys_address); - mcp->mb[3] = LSW(sns_phys_address); - mcp->mb[6] = MSW(MSD(sns_phys_address)); - mcp->mb[7] = LSW(MSD(sns_phys_address)); - mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0|MBX_1; - mcp->buf_size = buf_size; - mcp->flags = MBX_DMA_OUT|MBX_DMA_IN; - mcp->tov = (vha->hw->login_timeout * 2) + (vha->hw->login_timeout / 2); - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x105f, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1060, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, - uint8_t area, uint8_t al_pa, uint16_t *mb, uint8_t opt) -{ - int rval; - - struct logio_entry_24xx *lg; - dma_addr_t lg_dma; - uint32_t iop[2]; - struct qla_hw_data *ha = vha->hw; - struct req_que *req; - struct rsp_que *rsp; - - ql_dbg(ql_dbg_mbx, vha, 0x1061, "Entered %s.\n", __func__); - - if (ha->flags.cpu_affinity_enabled) - req = ha->req_q_map[0]; - else - req = vha->req; - rsp = req->rsp; - - lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); - if (lg == NULL) { - ql_log(ql_log_warn, vha, 0x1062, - "Failed to allocate login IOCB.\n"); - return QLA_MEMORY_ALLOC_FAILED; - } - memset(lg, 0, sizeof(struct logio_entry_24xx)); - - lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; - lg->entry_count = 1; - lg->handle = MAKE_HANDLE(req->id, lg->handle); - lg->nport_handle = cpu_to_le16(loop_id); - lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI); - if (opt & BIT_0) - lg->control_flags |= __constant_cpu_to_le16(LCF_COND_PLOGI); - if (opt & BIT_1) - lg->control_flags |= __constant_cpu_to_le16(LCF_SKIP_PRLI); - lg->port_id[0] = al_pa; - lg->port_id[1] = area; - lg->port_id[2] = domain; - lg->vp_index = vha->vp_idx; - rval = qla2x00_issue_iocb_timeout(vha, lg, lg_dma, 0, - (ha->r_a_tov / 10 * 2) + 2); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1063, - "Failed to issue login IOCB (%x).\n", rval); - } else if (lg->entry_status != 0) { - ql_dbg(ql_dbg_mbx, vha, 0x1064, - "Failed to complete IOCB -- error status (%x).\n", - lg->entry_status); - rval = QLA_FUNCTION_FAILED; - } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { - iop[0] = le32_to_cpu(lg->io_parameter[0]); - iop[1] = le32_to_cpu(lg->io_parameter[1]); - - ql_dbg(ql_dbg_mbx, vha, 0x1065, - "Failed to complete IOCB -- completion status (%x) " - "ioparam=%x/%x.\n", le16_to_cpu(lg->comp_status), - iop[0], iop[1]); - - switch (iop[0]) { - case LSC_SCODE_PORTID_USED: - mb[0] = MBS_PORT_ID_USED; - mb[1] = LSW(iop[1]); - break; - case LSC_SCODE_NPORT_USED: - mb[0] = MBS_LOOP_ID_USED; - break; - case LSC_SCODE_NOLINK: - case LSC_SCODE_NOIOCB: - case LSC_SCODE_NOXCB: - case LSC_SCODE_CMD_FAILED: - case LSC_SCODE_NOFABRIC: - case LSC_SCODE_FW_NOT_READY: - case LSC_SCODE_NOT_LOGGED_IN: - case LSC_SCODE_NOPCB: - case LSC_SCODE_ELS_REJECT: - case LSC_SCODE_CMD_PARAM_ERR: - case LSC_SCODE_NONPORT: - case LSC_SCODE_LOGGED_IN: - case LSC_SCODE_NOFLOGI_ACC: - default: - mb[0] = MBS_COMMAND_ERROR; - break; - } - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1066, "Done %s.\n", __func__); - - iop[0] = le32_to_cpu(lg->io_parameter[0]); - - mb[0] = MBS_COMMAND_COMPLETE; - mb[1] = 0; - if (iop[0] & BIT_4) { - if (iop[0] & BIT_8) - mb[1] |= BIT_1; - } else - mb[1] = BIT_0; - - /* Passback COS information. */ - mb[10] = 0; - if (lg->io_parameter[7] || lg->io_parameter[8]) - mb[10] |= BIT_0; /* Class 2. */ - if (lg->io_parameter[9] || lg->io_parameter[10]) - mb[10] |= BIT_1; /* Class 3. */ - } - - dma_pool_free(ha->s_dma_pool, lg, lg_dma); - - return rval; -} - -/* - * qla2x00_login_fabric - * Issue login fabric port mailbox command. - * - * Input: - * ha = adapter block pointer. - * loop_id = device loop ID. - * domain = device domain. - * area = device area. - * al_pa = device AL_PA. - * status = pointer for return status. - * opt = command options. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, - uint8_t area, uint8_t al_pa, uint16_t *mb, uint8_t opt) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x1067, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_LOGIN_FABRIC_PORT; - mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; - if (HAS_EXTENDED_IDS(ha)) { - mcp->mb[1] = loop_id; - mcp->mb[10] = opt; - mcp->out_mb |= MBX_10; - } else { - mcp->mb[1] = (loop_id << 8) | opt; - } - mcp->mb[2] = domain; - mcp->mb[3] = area << 8 | al_pa; - - mcp->in_mb = MBX_7|MBX_6|MBX_2|MBX_1|MBX_0; - mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2); - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - /* Return mailbox statuses. */ - if (mb != NULL) { - mb[0] = mcp->mb[0]; - mb[1] = mcp->mb[1]; - mb[2] = mcp->mb[2]; - mb[6] = mcp->mb[6]; - mb[7] = mcp->mb[7]; - /* COS retrieved from Get-Port-Database mailbox command. */ - mb[10] = 0; - } - - if (rval != QLA_SUCCESS) { - /* RLU tmp code: need to change main mailbox_command function to - * return ok even when the mailbox completion value is not - * SUCCESS. The caller needs to be responsible to interpret - * the return values of this mailbox command if we're not - * to change too much of the existing code. - */ - if (mcp->mb[0] == 0x4001 || mcp->mb[0] == 0x4002 || - mcp->mb[0] == 0x4003 || mcp->mb[0] == 0x4005 || - mcp->mb[0] == 0x4006) - rval = QLA_SUCCESS; - - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1068, - "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n", - rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1069, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_login_local_device - * Issue login loop port mailbox command. - * - * Input: - * ha = adapter block pointer. - * loop_id = device loop ID. - * opt = command options. - * - * Returns: - * Return status code. - * - * Context: - * Kernel context. - * - */ -int -qla2x00_login_local_device(scsi_qla_host_t *vha, fc_port_t *fcport, - uint16_t *mb_ret, uint8_t opt) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x106a, "Entered %s.\n", __func__); - - if (IS_FWI2_CAPABLE(ha)) - return qla24xx_login_fabric(vha, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, mb_ret, opt); - - mcp->mb[0] = MBC_LOGIN_LOOP_PORT; - if (HAS_EXTENDED_IDS(ha)) - mcp->mb[1] = fcport->loop_id; - else - mcp->mb[1] = fcport->loop_id << 8; - mcp->mb[2] = opt; - mcp->out_mb = MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_7|MBX_6|MBX_1|MBX_0; - mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2); - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - /* Return mailbox statuses. */ - if (mb_ret != NULL) { - mb_ret[0] = mcp->mb[0]; - mb_ret[1] = mcp->mb[1]; - mb_ret[6] = mcp->mb[6]; - mb_ret[7] = mcp->mb[7]; - } - - if (rval != QLA_SUCCESS) { - /* AV tmp code: need to change main mailbox_command function to - * return ok even when the mailbox completion value is not - * SUCCESS. The caller needs to be responsible to interpret - * the return values of this mailbox command if we're not - * to change too much of the existing code. - */ - if (mcp->mb[0] == 0x4005 || mcp->mb[0] == 0x4006) - rval = QLA_SUCCESS; - - ql_dbg(ql_dbg_mbx, vha, 0x106b, - "Failed=%x mb[0]=%x mb[1]=%x mb[6]=%x mb[7]=%x.\n", - rval, mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x106c, "Done %s.\n", __func__); - } - - return (rval); -} - -int -qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, - uint8_t area, uint8_t al_pa) -{ - int rval; - struct logio_entry_24xx *lg; - dma_addr_t lg_dma; - struct qla_hw_data *ha = vha->hw; - struct req_que *req; - struct rsp_que *rsp; - - ql_dbg(ql_dbg_mbx, vha, 0x106d, "Entered %s.\n", __func__); - - lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); - if (lg == NULL) { - ql_log(ql_log_warn, vha, 0x106e, - "Failed to allocate logout IOCB.\n"); - return QLA_MEMORY_ALLOC_FAILED; - } - memset(lg, 0, sizeof(struct logio_entry_24xx)); - - if (ql2xmaxqueues > 1) - req = ha->req_q_map[0]; - else - req = vha->req; - rsp = req->rsp; - lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; - lg->entry_count = 1; - lg->handle = MAKE_HANDLE(req->id, lg->handle); - lg->nport_handle = cpu_to_le16(loop_id); - lg->control_flags = - __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO| - LCF_FREE_NPORT); - lg->port_id[0] = al_pa; - lg->port_id[1] = area; - lg->port_id[2] = domain; - lg->vp_index = vha->vp_idx; - rval = qla2x00_issue_iocb_timeout(vha, lg, lg_dma, 0, - (ha->r_a_tov / 10 * 2) + 2); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x106f, - "Failed to issue logout IOCB (%x).\n", rval); - } else if (lg->entry_status != 0) { - ql_dbg(ql_dbg_mbx, vha, 0x1070, - "Failed to complete IOCB -- error status (%x).\n", - lg->entry_status); - rval = QLA_FUNCTION_FAILED; - } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { - ql_dbg(ql_dbg_mbx, vha, 0x1071, - "Failed to complete IOCB -- completion status (%x) " - "ioparam=%x/%x.\n", le16_to_cpu(lg->comp_status), - le32_to_cpu(lg->io_parameter[0]), - le32_to_cpu(lg->io_parameter[1])); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1072, "Done %s.\n", __func__); - } - - dma_pool_free(ha->s_dma_pool, lg, lg_dma); - - return rval; -} - -/* - * qla2x00_fabric_logout - * Issue logout fabric port mailbox command. - * - * Input: - * ha = adapter block pointer. - * loop_id = device loop ID. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, - uint8_t area, uint8_t al_pa) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1073, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT; - mcp->out_mb = MBX_1|MBX_0; - if (HAS_EXTENDED_IDS(vha->hw)) { - mcp->mb[1] = loop_id; - mcp->mb[10] = 0; - mcp->out_mb |= MBX_10; - } else { - mcp->mb[1] = loop_id << 8; - } - - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1074, - "Failed=%x mb[1]=%x.\n", rval, mcp->mb[1]); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1075, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_full_login_lip - * Issue full login LIP mailbox command. - * - * Input: - * ha = adapter block pointer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_full_login_lip(scsi_qla_host_t *vha) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1076, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_LIP_FULL_LOGIN; - mcp->mb[1] = IS_FWI2_CAPABLE(vha->hw) ? BIT_3 : 0; - mcp->mb[2] = 0; - mcp->mb[3] = 0; - mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1077, "Failed=%x.\n", rval); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x1078, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_get_id_list - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_id_list(scsi_qla_host_t *vha, void *id_list, dma_addr_t id_list_dma, - uint16_t *entries) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1079, "Entered %s.\n", __func__); - - if (id_list == NULL) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_GET_ID_LIST; - mcp->out_mb = MBX_0; - if (IS_FWI2_CAPABLE(vha->hw)) { - mcp->mb[2] = MSW(id_list_dma); - mcp->mb[3] = LSW(id_list_dma); - mcp->mb[6] = MSW(MSD(id_list_dma)); - mcp->mb[7] = LSW(MSD(id_list_dma)); - mcp->mb[8] = 0; - mcp->mb[9] = vha->vp_idx; - mcp->out_mb |= MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2; - } else { - mcp->mb[1] = MSW(id_list_dma); - mcp->mb[2] = LSW(id_list_dma); - mcp->mb[3] = MSW(MSD(id_list_dma)); - mcp->mb[6] = LSW(MSD(id_list_dma)); - mcp->out_mb |= MBX_6|MBX_3|MBX_2|MBX_1; - } - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x107a, "Failed=%x.\n", rval); - } else { - *entries = mcp->mb[1]; - ql_dbg(ql_dbg_mbx, vha, 0x107b, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_get_resource_cnts - * Get current firmware resource counts. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_resource_cnts(scsi_qla_host_t *vha, uint16_t *cur_xchg_cnt, - uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt, - uint16_t *orig_iocb_cnt, uint16_t *max_npiv_vports, uint16_t *max_fcfs) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x107c, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_RESOURCE_COUNTS; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw)) - mcp->in_mb |= MBX_12; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x107d, - "Failed mb[0]=%x.\n", mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x107e, - "Done %s mb1=%x mb2=%x mb3=%x mb6=%x mb7=%x mb10=%x " - "mb11=%x mb12=%x.\n", __func__, mcp->mb[1], mcp->mb[2], - mcp->mb[3], mcp->mb[6], mcp->mb[7], mcp->mb[10], - mcp->mb[11], mcp->mb[12]); - - if (cur_xchg_cnt) - *cur_xchg_cnt = mcp->mb[3]; - if (orig_xchg_cnt) - *orig_xchg_cnt = mcp->mb[6]; - if (cur_iocb_cnt) - *cur_iocb_cnt = mcp->mb[7]; - if (orig_iocb_cnt) - *orig_iocb_cnt = mcp->mb[10]; - if (vha->hw->flags.npiv_supported && max_npiv_vports) - *max_npiv_vports = mcp->mb[11]; - if ((IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw)) && max_fcfs) - *max_fcfs = mcp->mb[12]; - } - - return (rval); -} - -/* - * qla2x00_get_fcal_position_map - * Get FCAL (LILP) position map using mailbox command - * - * Input: - * ha = adapter state pointer. - * pos_map = buffer pointer (can be NULL). - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_get_fcal_position_map(scsi_qla_host_t *vha, char *pos_map) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - char *pmap; - dma_addr_t pmap_dma; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x107f, "Entered %s.\n", __func__); - - pmap = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &pmap_dma); - if (pmap == NULL) { - ql_log(ql_log_warn, vha, 0x1080, - "Memory alloc failed.\n"); - return QLA_MEMORY_ALLOC_FAILED; - } - memset(pmap, 0, FCAL_MAP_SIZE); - - mcp->mb[0] = MBC_GET_FC_AL_POSITION_MAP; - mcp->mb[2] = MSW(pmap_dma); - mcp->mb[3] = LSW(pmap_dma); - mcp->mb[6] = MSW(MSD(pmap_dma)); - mcp->mb[7] = LSW(MSD(pmap_dma)); - mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->buf_size = FCAL_MAP_SIZE; - mcp->flags = MBX_DMA_IN; - mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2); - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval == QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1081, - "mb0/mb1=%x/%X FC/AL position map size (%x).\n", - mcp->mb[0], mcp->mb[1], (unsigned)pmap[0]); - ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111d, - pmap, pmap[0] + 1); - - if (pos_map) - memcpy(pos_map, pmap, FCAL_MAP_SIZE); - } - dma_pool_free(ha->s_dma_pool, pmap, pmap_dma); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1082, "Failed=%x.\n", rval); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1083, "Done %s.\n", __func__); - } - - return rval; -} - -/* - * qla2x00_get_link_status - * - * Input: - * ha = adapter block pointer. - * loop_id = device loop ID. - * ret_buf = pointer to link status return buffer. - * - * Returns: - * 0 = success. - * BIT_0 = mem alloc error. - * BIT_1 = mailbox error. - */ -int -qla2x00_get_link_status(scsi_qla_host_t *vha, uint16_t loop_id, - struct link_statistics *stats, dma_addr_t stats_dma) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - uint32_t *siter, *diter, dwords; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x1084, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_LINK_STATUS; - mcp->mb[2] = MSW(stats_dma); - mcp->mb[3] = LSW(stats_dma); - mcp->mb[6] = MSW(MSD(stats_dma)); - mcp->mb[7] = LSW(MSD(stats_dma)); - mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; - mcp->in_mb = MBX_0; - if (IS_FWI2_CAPABLE(ha)) { - mcp->mb[1] = loop_id; - mcp->mb[4] = 0; - mcp->mb[10] = 0; - mcp->out_mb |= MBX_10|MBX_4|MBX_1; - mcp->in_mb |= MBX_1; - } else if (HAS_EXTENDED_IDS(ha)) { - mcp->mb[1] = loop_id; - mcp->mb[10] = 0; - mcp->out_mb |= MBX_10|MBX_1; - } else { - mcp->mb[1] = loop_id << 8; - mcp->out_mb |= MBX_1; - } - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = IOCTL_CMD; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval == QLA_SUCCESS) { - if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { - ql_dbg(ql_dbg_mbx, vha, 0x1085, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - rval = QLA_FUNCTION_FAILED; - } else { - /* Copy over data -- firmware data is LE. */ - ql_dbg(ql_dbg_mbx, vha, 0x1086, "Done %s.\n", __func__); - dwords = offsetof(struct link_statistics, unused1) / 4; - siter = diter = &stats->link_fail_cnt; - while (dwords--) - *diter++ = le32_to_cpu(*siter++); - } - } else { - /* Failed. */ - ql_dbg(ql_dbg_mbx, vha, 0x1087, "Failed=%x.\n", rval); - } - - return rval; -} - -int -qla24xx_get_isp_stats(scsi_qla_host_t *vha, struct link_statistics *stats, - dma_addr_t stats_dma) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - uint32_t *siter, *diter, dwords; - - ql_dbg(ql_dbg_mbx, vha, 0x1088, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GET_LINK_PRIV_STATS; - mcp->mb[2] = MSW(stats_dma); - mcp->mb[3] = LSW(stats_dma); - mcp->mb[6] = MSW(MSD(stats_dma)); - mcp->mb[7] = LSW(MSD(stats_dma)); - mcp->mb[8] = sizeof(struct link_statistics) / 4; - mcp->mb[9] = vha->vp_idx; - mcp->mb[10] = 0; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; - mcp->in_mb = MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = IOCTL_CMD; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval == QLA_SUCCESS) { - if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { - ql_dbg(ql_dbg_mbx, vha, 0x1089, - "Failed mb[0]=%x.\n", mcp->mb[0]); - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_mbx, vha, 0x108a, "Done %s.\n", __func__); - /* Copy over data -- firmware data is LE. */ - dwords = sizeof(struct link_statistics) / 4; - siter = diter = &stats->link_fail_cnt; - while (dwords--) - *diter++ = le32_to_cpu(*siter++); - } - } else { - /* Failed. */ - ql_dbg(ql_dbg_mbx, vha, 0x108b, "Failed=%x.\n", rval); - } - - return rval; -} - -int -qla24xx_abort_command(srb_t *sp) -{ - int rval; - unsigned long flags = 0; - - struct abort_entry_24xx *abt; - dma_addr_t abt_dma; - uint32_t handle; - fc_port_t *fcport = sp->fcport; - struct scsi_qla_host *vha = fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = vha->req; - - ql_dbg(ql_dbg_mbx, vha, 0x108c, "Entered %s.\n", __func__); - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) { - if (req->outstanding_cmds[handle] == sp) - break; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (handle == MAX_OUTSTANDING_COMMANDS) { - /* Command not found. */ - return QLA_FUNCTION_FAILED; - } - - abt = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &abt_dma); - if (abt == NULL) { - ql_log(ql_log_warn, vha, 0x108d, - "Failed to allocate abort IOCB.\n"); - return QLA_MEMORY_ALLOC_FAILED; - } - memset(abt, 0, sizeof(struct abort_entry_24xx)); - - abt->entry_type = ABORT_IOCB_TYPE; - abt->entry_count = 1; - abt->handle = MAKE_HANDLE(req->id, abt->handle); - abt->nport_handle = cpu_to_le16(fcport->loop_id); - abt->handle_to_abort = MAKE_HANDLE(req->id, handle); - abt->port_id[0] = fcport->d_id.b.al_pa; - abt->port_id[1] = fcport->d_id.b.area; - abt->port_id[2] = fcport->d_id.b.domain; - abt->vp_index = fcport->vp_idx; - - abt->req_que_no = cpu_to_le16(req->id); - - rval = qla2x00_issue_iocb(vha, abt, abt_dma, 0); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x108e, - "Failed to issue IOCB (%x).\n", rval); - } else if (abt->entry_status != 0) { - ql_dbg(ql_dbg_mbx, vha, 0x108f, - "Failed to complete IOCB -- error status (%x).\n", - abt->entry_status); - rval = QLA_FUNCTION_FAILED; - } else if (abt->nport_handle != __constant_cpu_to_le16(0)) { - ql_dbg(ql_dbg_mbx, vha, 0x1090, - "Failed to complete IOCB -- completion status (%x).\n", - le16_to_cpu(abt->nport_handle)); - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1091, "Done %s.\n", __func__); - } - - dma_pool_free(ha->s_dma_pool, abt, abt_dma); - - return rval; -} - -struct tsk_mgmt_cmd { - union { - struct tsk_mgmt_entry tsk; - struct sts_entry_24xx sts; - } p; -}; - -static int -__qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, - unsigned int l, int tag) -{ - int rval, rval2; - struct tsk_mgmt_cmd *tsk; - struct sts_entry_24xx *sts; - dma_addr_t tsk_dma; - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct req_que *req; - struct rsp_que *rsp; - - vha = fcport->vha; - ha = vha->hw; - req = vha->req; - - ql_dbg(ql_dbg_mbx, vha, 0x1092, "Entered %s.\n", __func__); - - if (ha->flags.cpu_affinity_enabled) - rsp = ha->rsp_q_map[tag + 1]; - else - rsp = req->rsp; - tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); - if (tsk == NULL) { - ql_log(ql_log_warn, vha, 0x1093, - "Failed to allocate task management IOCB.\n"); - return QLA_MEMORY_ALLOC_FAILED; - } - memset(tsk, 0, sizeof(struct tsk_mgmt_cmd)); - - tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE; - tsk->p.tsk.entry_count = 1; - tsk->p.tsk.handle = MAKE_HANDLE(req->id, tsk->p.tsk.handle); - tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id); - tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - tsk->p.tsk.control_flags = cpu_to_le32(type); - tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa; - tsk->p.tsk.port_id[1] = fcport->d_id.b.area; - tsk->p.tsk.port_id[2] = fcport->d_id.b.domain; - tsk->p.tsk.vp_index = fcport->vp_idx; - if (type == TCF_LUN_RESET) { - int_to_scsilun(l, &tsk->p.tsk.lun); - host_to_fcp_swap((uint8_t *)&tsk->p.tsk.lun, - sizeof(tsk->p.tsk.lun)); - } - - sts = &tsk->p.sts; - rval = qla2x00_issue_iocb(vha, tsk, tsk_dma, 0); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1094, - "Failed to issue %s reset IOCB (%x).\n", name, rval); - } else if (sts->entry_status != 0) { - ql_dbg(ql_dbg_mbx, vha, 0x1095, - "Failed to complete IOCB -- error status (%x).\n", - sts->entry_status); - rval = QLA_FUNCTION_FAILED; - } else if (sts->comp_status != - __constant_cpu_to_le16(CS_COMPLETE)) { - ql_dbg(ql_dbg_mbx, vha, 0x1096, - "Failed to complete IOCB -- completion status (%x).\n", - le16_to_cpu(sts->comp_status)); - rval = QLA_FUNCTION_FAILED; - } else if (le16_to_cpu(sts->scsi_status) & - SS_RESPONSE_INFO_LEN_VALID) { - if (le32_to_cpu(sts->rsp_data_len) < 4) { - ql_dbg(ql_dbg_mbx, vha, 0x1097, - "Ignoring inconsistent data length -- not enough " - "response info (%d).\n", - le32_to_cpu(sts->rsp_data_len)); - } else if (sts->data[3]) { - ql_dbg(ql_dbg_mbx, vha, 0x1098, - "Failed to complete IOCB -- response (%x).\n", - sts->data[3]); - rval = QLA_FUNCTION_FAILED; - } - } - - /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l, - type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID); - if (rval2 != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1099, - "Failed to issue marker IOCB (%x).\n", rval2); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x109a, "Done %s.\n", __func__); - } - - dma_pool_free(ha->s_dma_pool, tsk, tsk_dma); - - return rval; -} - -int -qla24xx_abort_target(struct fc_port *fcport, unsigned int l, int tag) -{ - struct qla_hw_data *ha = fcport->vha->hw; - - if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha)) - return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag); - - return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l, tag); -} - -int -qla24xx_lun_reset(struct fc_port *fcport, unsigned int l, int tag) -{ - struct qla_hw_data *ha = fcport->vha->hw; - - if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha)) - return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag); - - return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l, tag); -} - -int -qla2x00_system_error(scsi_qla_host_t *vha) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA23XX(ha) && !IS_FWI2_CAPABLE(ha)) - return QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x109b, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_GEN_SYSTEM_ERROR; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = 5; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x109c, "Failed=%x.\n", rval); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x109d, "Done %s.\n", __func__); - } - - return rval; -} - -/** - * qla2x00_set_serdes_params() - - * @ha: HA context - * - * Returns - */ -int -qla2x00_set_serdes_params(scsi_qla_host_t *vha, uint16_t sw_em_1g, - uint16_t sw_em_2g, uint16_t sw_em_4g) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x109e, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_SERDES_PARAMS; - mcp->mb[1] = BIT_0; - mcp->mb[2] = sw_em_1g | BIT_15; - mcp->mb[3] = sw_em_2g | BIT_15; - mcp->mb[4] = sw_em_4g | BIT_15; - mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x109f, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - /*EMPTY*/ - ql_dbg(ql_dbg_mbx, vha, 0x10a0, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_stop_firmware(scsi_qla_host_t *vha) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_FWI2_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x10a1, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_STOP_FIRMWARE; - mcp->mb[1] = 0; - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = 5; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10a2, "Failed=%x.\n", rval); - if (mcp->mb[0] == MBS_INVALID_COMMAND) - rval = QLA_INVALID_COMMAND; - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10a3, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_enable_eft_trace(scsi_qla_host_t *vha, dma_addr_t eft_dma, - uint16_t buffers) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10a4, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - if (unlikely(pci_channel_offline(vha->hw->pdev))) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_TRACE_CONTROL; - mcp->mb[1] = TC_EFT_ENABLE; - mcp->mb[2] = LSW(eft_dma); - mcp->mb[3] = MSW(eft_dma); - mcp->mb[4] = LSW(MSD(eft_dma)); - mcp->mb[5] = MSW(MSD(eft_dma)); - mcp->mb[6] = buffers; - mcp->mb[7] = TC_AEN_DISABLE; - mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10a5, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10a6, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_disable_eft_trace(scsi_qla_host_t *vha) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10a7, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - if (unlikely(pci_channel_offline(vha->hw->pdev))) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_TRACE_CONTROL; - mcp->mb[1] = TC_EFT_DISABLE; - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10a8, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10a9, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma, - uint16_t buffers, uint16_t *mb, uint32_t *dwords) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10aa, "Entered %s.\n", __func__); - - if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) && - !IS_QLA83XX(vha->hw)) - return QLA_FUNCTION_FAILED; - - if (unlikely(pci_channel_offline(vha->hw->pdev))) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_TRACE_CONTROL; - mcp->mb[1] = TC_FCE_ENABLE; - mcp->mb[2] = LSW(fce_dma); - mcp->mb[3] = MSW(fce_dma); - mcp->mb[4] = LSW(MSD(fce_dma)); - mcp->mb[5] = MSW(MSD(fce_dma)); - mcp->mb[6] = buffers; - mcp->mb[7] = TC_AEN_DISABLE; - mcp->mb[8] = 0; - mcp->mb[9] = TC_FCE_DEFAULT_RX_SIZE; - mcp->mb[10] = TC_FCE_DEFAULT_TX_SIZE; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2| - MBX_1|MBX_0; - mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10ab, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10ac, "Done %s.\n", __func__); - - if (mb) - memcpy(mb, mcp->mb, 8 * sizeof(*mb)); - if (dwords) - *dwords = buffers; - } - - return rval; -} - -int -qla2x00_disable_fce_trace(scsi_qla_host_t *vha, uint64_t *wr, uint64_t *rd) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10ad, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - if (unlikely(pci_channel_offline(vha->hw->pdev))) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_TRACE_CONTROL; - mcp->mb[1] = TC_FCE_DISABLE; - mcp->mb[2] = TC_FCE_DISABLE_TRACE; - mcp->out_mb = MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2| - MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10ae, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10af, "Done %s.\n", __func__); - - if (wr) - *wr = (uint64_t) mcp->mb[5] << 48 | - (uint64_t) mcp->mb[4] << 32 | - (uint64_t) mcp->mb[3] << 16 | - (uint64_t) mcp->mb[2]; - if (rd) - *rd = (uint64_t) mcp->mb[9] << 48 | - (uint64_t) mcp->mb[8] << 32 | - (uint64_t) mcp->mb[7] << 16 | - (uint64_t) mcp->mb[6]; - } - - return rval; -} - -int -qla2x00_get_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, - uint16_t *port_speed, uint16_t *mb) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10b0, "Entered %s.\n", __func__); - - if (!IS_IIDMA_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_PORT_PARAMS; - mcp->mb[1] = loop_id; - mcp->mb[2] = mcp->mb[3] = 0; - mcp->mb[9] = vha->vp_idx; - mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_3|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - /* Return mailbox statuses. */ - if (mb != NULL) { - mb[0] = mcp->mb[0]; - mb[1] = mcp->mb[1]; - mb[3] = mcp->mb[3]; - } - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10b1, "Failed=%x.\n", rval); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10b2, "Done %s.\n", __func__); - if (port_speed) - *port_speed = mcp->mb[3]; - } - - return rval; -} - -int -qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id, - uint16_t port_speed, uint16_t *mb) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10b3, "Entered %s.\n", __func__); - - if (!IS_IIDMA_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_PORT_PARAMS; - mcp->mb[1] = loop_id; - mcp->mb[2] = BIT_0; - if (IS_CNA_CAPABLE(vha->hw)) - mcp->mb[3] = port_speed & (BIT_5|BIT_4|BIT_3|BIT_2|BIT_1|BIT_0); - else - mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0); - mcp->mb[9] = vha->vp_idx; - mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_3|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - /* Return mailbox statuses. */ - if (mb != NULL) { - mb[0] = mcp->mb[0]; - mb[1] = mcp->mb[1]; - mb[3] = mcp->mb[3]; - } - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10b4, "Failed=%x.\n", rval); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10b5, "Done %s.\n", __func__); - } - - return rval; -} - -void -qla24xx_report_id_acquisition(scsi_qla_host_t *vha, - struct vp_rpt_id_entry_24xx *rptid_entry) -{ - uint8_t vp_idx; - uint16_t stat = le16_to_cpu(rptid_entry->vp_idx); - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *vp; - unsigned long flags; - - ql_dbg(ql_dbg_mbx, vha, 0x10b6, "Entered %s.\n", __func__); - - if (rptid_entry->entry_status != 0) - return; - - if (rptid_entry->format == 0) { - ql_dbg(ql_dbg_mbx, vha, 0x10b7, - "Format 0 : Number of VPs setup %d, number of " - "VPs acquired %d.\n", - MSB(le16_to_cpu(rptid_entry->vp_count)), - LSB(le16_to_cpu(rptid_entry->vp_count))); - ql_dbg(ql_dbg_mbx, vha, 0x10b8, - "Primary port id %02x%02x%02x.\n", - rptid_entry->port_id[2], rptid_entry->port_id[1], - rptid_entry->port_id[0]); - } else if (rptid_entry->format == 1) { - vp_idx = LSB(stat); - ql_dbg(ql_dbg_mbx, vha, 0x10b9, - "Format 1: VP[%d] enabled - status %d - with " - "port id %02x%02x%02x.\n", vp_idx, MSB(stat), - rptid_entry->port_id[2], rptid_entry->port_id[1], - rptid_entry->port_id[0]); - - vp = vha; - if (vp_idx == 0 && (MSB(stat) != 1)) - goto reg_needed; - - if (MSB(stat) != 0) { - ql_dbg(ql_dbg_mbx, vha, 0x10ba, - "Could not acquire ID for VP[%d].\n", vp_idx); - return; - } - - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vp, &ha->vp_list, list) - if (vp_idx == vp->vp_idx) - break; - spin_unlock_irqrestore(&ha->vport_slock, flags); - - if (!vp) - return; - - vp->d_id.b.domain = rptid_entry->port_id[2]; - vp->d_id.b.area = rptid_entry->port_id[1]; - vp->d_id.b.al_pa = rptid_entry->port_id[0]; - - /* - * Cannot configure here as we are still sitting on the - * response queue. Handle it in dpc context. - */ - set_bit(VP_IDX_ACQUIRED, &vp->vp_flags); - -reg_needed: - set_bit(REGISTER_FC4_NEEDED, &vp->dpc_flags); - set_bit(REGISTER_FDMI_NEEDED, &vp->dpc_flags); - set_bit(VP_DPC_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } -} - -/* - * qla24xx_modify_vp_config - * Change VP configuration for vha - * - * Input: - * vha = adapter block pointer. - * - * Returns: - * qla2xxx local function return status code. - * - * Context: - * Kernel context. - */ -int -qla24xx_modify_vp_config(scsi_qla_host_t *vha) -{ - int rval; - struct vp_config_entry_24xx *vpmod; - dma_addr_t vpmod_dma; - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - /* This can be called by the parent */ - - ql_dbg(ql_dbg_mbx, vha, 0x10bb, "Entered %s.\n", __func__); - - vpmod = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vpmod_dma); - if (!vpmod) { - ql_log(ql_log_warn, vha, 0x10bc, - "Failed to allocate modify VP IOCB.\n"); - return QLA_MEMORY_ALLOC_FAILED; - } - - memset(vpmod, 0, sizeof(struct vp_config_entry_24xx)); - vpmod->entry_type = VP_CONFIG_IOCB_TYPE; - vpmod->entry_count = 1; - vpmod->command = VCT_COMMAND_MOD_ENABLE_VPS; - vpmod->vp_count = 1; - vpmod->vp_index1 = vha->vp_idx; - vpmod->options_idx1 = BIT_3|BIT_4|BIT_5; - memcpy(vpmod->node_name_idx1, vha->node_name, WWN_SIZE); - memcpy(vpmod->port_name_idx1, vha->port_name, WWN_SIZE); - vpmod->entry_count = 1; - - rval = qla2x00_issue_iocb(base_vha, vpmod, vpmod_dma, 0); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10bd, - "Failed to issue VP config IOCB (%x).\n", rval); - } else if (vpmod->comp_status != 0) { - ql_dbg(ql_dbg_mbx, vha, 0x10be, - "Failed to complete IOCB -- error status (%x).\n", - vpmod->comp_status); - rval = QLA_FUNCTION_FAILED; - } else if (vpmod->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { - ql_dbg(ql_dbg_mbx, vha, 0x10bf, - "Failed to complete IOCB -- completion status (%x).\n", - le16_to_cpu(vpmod->comp_status)); - rval = QLA_FUNCTION_FAILED; - } else { - /* EMPTY */ - ql_dbg(ql_dbg_mbx, vha, 0x10c0, "Done %s.\n", __func__); - fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING); - } - dma_pool_free(ha->s_dma_pool, vpmod, vpmod_dma); - - return rval; -} - -/* - * qla24xx_control_vp - * Enable a virtual port for given host - * - * Input: - * ha = adapter block pointer. - * vhba = virtual adapter (unused) - * index = index number for enabled VP - * - * Returns: - * qla2xxx local function return status code. - * - * Context: - * Kernel context. - */ -int -qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) -{ - int rval; - int map, pos; - struct vp_ctrl_entry_24xx *vce; - dma_addr_t vce_dma; - struct qla_hw_data *ha = vha->hw; - int vp_index = vha->vp_idx; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - - ql_dbg(ql_dbg_mbx, vha, 0x10c1, - "Entered %s enabling index %d.\n", __func__, vp_index); - - if (vp_index == 0 || vp_index >= ha->max_npiv_vports) - return QLA_PARAMETER_ERROR; - - vce = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &vce_dma); - if (!vce) { - ql_log(ql_log_warn, vha, 0x10c2, - "Failed to allocate VP control IOCB.\n"); - return QLA_MEMORY_ALLOC_FAILED; - } - memset(vce, 0, sizeof(struct vp_ctrl_entry_24xx)); - - vce->entry_type = VP_CTRL_IOCB_TYPE; - vce->entry_count = 1; - vce->command = cpu_to_le16(cmd); - vce->vp_count = __constant_cpu_to_le16(1); - - /* index map in firmware starts with 1; decrement index - * this is ok as we never use index 0 - */ - map = (vp_index - 1) / 8; - pos = (vp_index - 1) & 7; - mutex_lock(&ha->vport_lock); - vce->vp_idx_map[map] |= 1 << pos; - mutex_unlock(&ha->vport_lock); - - rval = qla2x00_issue_iocb(base_vha, vce, vce_dma, 0); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10c3, - "Failed to issue VP control IOCB (%x).\n", rval); - } else if (vce->entry_status != 0) { - ql_dbg(ql_dbg_mbx, vha, 0x10c4, - "Failed to complete IOCB -- error status (%x).\n", - vce->entry_status); - rval = QLA_FUNCTION_FAILED; - } else if (vce->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { - ql_dbg(ql_dbg_mbx, vha, 0x10c5, - "Failed to complet IOCB -- completion status (%x).\n", - le16_to_cpu(vce->comp_status)); - rval = QLA_FUNCTION_FAILED; - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10c6, "Done %s.\n", __func__); - } - - dma_pool_free(ha->s_dma_pool, vce, vce_dma); - - return rval; -} - -/* - * qla2x00_send_change_request - * Receive or disable RSCN request from fabric controller - * - * Input: - * ha = adapter block pointer - * format = registration format: - * 0 - Reserved - * 1 - Fabric detected registration - * 2 - N_port detected registration - * 3 - Full registration - * FF - clear registration - * vp_idx = Virtual port index - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel Context - */ - -int -qla2x00_send_change_request(scsi_qla_host_t *vha, uint16_t format, - uint16_t vp_idx) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10c7, "Entered %s.\n", __func__); - - /* - * This command is implicitly executed by firmware during login for the - * physical hosts - */ - if (vp_idx == 0) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_SEND_CHANGE_REQUEST; - mcp->mb[1] = format; - mcp->mb[9] = vp_idx; - mcp->out_mb = MBX_9|MBX_1|MBX_0; - mcp->in_mb = MBX_0|MBX_1; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval == QLA_SUCCESS) { - if (mcp->mb[0] != MBS_COMMAND_COMPLETE) { - rval = BIT_1; - } - } else - rval = BIT_1; - - return rval; -} - -int -qla2x00_dump_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t addr, - uint32_t size) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1009, "Entered %s.\n", __func__); - - if (MSW(addr) || IS_FWI2_CAPABLE(vha->hw)) { - mcp->mb[0] = MBC_DUMP_RISC_RAM_EXTENDED; - mcp->mb[8] = MSW(addr); - mcp->out_mb = MBX_8|MBX_0; - } else { - mcp->mb[0] = MBC_DUMP_RISC_RAM; - mcp->out_mb = MBX_0; - } - mcp->mb[1] = LSW(addr); - mcp->mb[2] = MSW(req_dma); - mcp->mb[3] = LSW(req_dma); - mcp->mb[6] = MSW(MSD(req_dma)); - mcp->mb[7] = LSW(MSD(req_dma)); - mcp->out_mb |= MBX_7|MBX_6|MBX_3|MBX_2|MBX_1; - if (IS_FWI2_CAPABLE(vha->hw)) { - mcp->mb[4] = MSW(size); - mcp->mb[5] = LSW(size); - mcp->out_mb |= MBX_5|MBX_4; - } else { - mcp->mb[4] = LSW(size); - mcp->out_mb |= MBX_4; - } - - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1008, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1007, "Done %s.\n", __func__); - } - - return rval; -} - -/* 84XX Support **************************************************************/ - -struct cs84xx_mgmt_cmd { - union { - struct verify_chip_entry_84xx req; - struct verify_chip_rsp_84xx rsp; - } p; -}; - -int -qla84xx_verify_chip(struct scsi_qla_host *vha, uint16_t *status) -{ - int rval, retry; - struct cs84xx_mgmt_cmd *mn; - dma_addr_t mn_dma; - uint16_t options; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x10c8, "Entered %s.\n", __func__); - - mn = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &mn_dma); - if (mn == NULL) { - return QLA_MEMORY_ALLOC_FAILED; - } - - /* Force Update? */ - options = ha->cs84xx->fw_update ? VCO_FORCE_UPDATE : 0; - /* Diagnostic firmware? */ - /* options |= MENLO_DIAG_FW; */ - /* We update the firmware with only one data sequence. */ - options |= VCO_END_OF_DATA; - - do { - retry = 0; - memset(mn, 0, sizeof(*mn)); - mn->p.req.entry_type = VERIFY_CHIP_IOCB_TYPE; - mn->p.req.entry_count = 1; - mn->p.req.options = cpu_to_le16(options); - - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111c, - "Dump of Verify Request.\n"); - ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x111e, - (uint8_t *)mn, sizeof(*mn)); - - rval = qla2x00_issue_iocb_timeout(vha, mn, mn_dma, 0, 120); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10cb, - "Failed to issue verify IOCB (%x).\n", rval); - goto verify_done; - } - - ql_dbg(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1110, - "Dump of Verify Response.\n"); - ql_dump_buffer(ql_dbg_mbx + ql_dbg_buffer, vha, 0x1118, - (uint8_t *)mn, sizeof(*mn)); - - status[0] = le16_to_cpu(mn->p.rsp.comp_status); - status[1] = status[0] == CS_VCS_CHIP_FAILURE ? - le16_to_cpu(mn->p.rsp.failure_code) : 0; - ql_dbg(ql_dbg_mbx, vha, 0x10ce, - "cs=%x fc=%x.\n", status[0], status[1]); - - if (status[0] != CS_COMPLETE) { - rval = QLA_FUNCTION_FAILED; - if (!(options & VCO_DONT_UPDATE_FW)) { - ql_dbg(ql_dbg_mbx, vha, 0x10cf, - "Firmware update failed. Retrying " - "without update firmware.\n"); - options |= VCO_DONT_UPDATE_FW; - options &= ~VCO_FORCE_UPDATE; - retry = 1; - } - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10d0, - "Firmware updated to %x.\n", - le32_to_cpu(mn->p.rsp.fw_ver)); - - /* NOTE: we only update OP firmware. */ - spin_lock_irqsave(&ha->cs84xx->access_lock, flags); - ha->cs84xx->op_fw_version = - le32_to_cpu(mn->p.rsp.fw_ver); - spin_unlock_irqrestore(&ha->cs84xx->access_lock, - flags); - } - } while (retry); - -verify_done: - dma_pool_free(ha->s_dma_pool, mn, mn_dma); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10d1, "Failed=%x.\n", rval); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10d2, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req) -{ - int rval; - unsigned long flags; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct device_reg_25xxmq __iomem *reg; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x10d3, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_INITIALIZE_MULTIQ; - mcp->mb[1] = req->options; - mcp->mb[2] = MSW(LSD(req->dma)); - mcp->mb[3] = LSW(LSD(req->dma)); - mcp->mb[6] = MSW(MSD(req->dma)); - mcp->mb[7] = LSW(MSD(req->dma)); - mcp->mb[5] = req->length; - if (req->rsp) - mcp->mb[10] = req->rsp->id; - mcp->mb[12] = req->qos; - mcp->mb[11] = req->vp_idx; - mcp->mb[13] = req->rid; - if (IS_QLA83XX(ha)) - mcp->mb[15] = 0; - - reg = (struct device_reg_25xxmq *)((void *)(ha->mqiobase) + - QLA_QUE_PAGE * req->id); - - mcp->mb[4] = req->id; - /* que in ptr index */ - mcp->mb[8] = 0; - /* que out ptr index */ - mcp->mb[9] = 0; - mcp->out_mb = MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7| - MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->flags = MBX_DMA_OUT; - mcp->tov = MBX_TOV_SECONDS * 2; - - if (IS_QLA81XX(ha) || IS_QLA83XX(ha)) - mcp->in_mb |= MBX_1; - if (IS_QLA83XX(ha)) { - mcp->out_mb |= MBX_15; - /* debug q create issue in SR-IOV */ - mcp->in_mb |= MBX_9 | MBX_8 | MBX_7; - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (!(req->options & BIT_0)) { - WRT_REG_DWORD(®->req_q_in, 0); - if (!IS_QLA83XX(ha)) - WRT_REG_DWORD(®->req_q_out, 0); - } - req->req_q_in = ®->req_q_in; - req->req_q_out = ®->req_q_out; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10d4, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10d5, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) -{ - int rval; - unsigned long flags; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct device_reg_25xxmq __iomem *reg; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x10d6, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_INITIALIZE_MULTIQ; - mcp->mb[1] = rsp->options; - mcp->mb[2] = MSW(LSD(rsp->dma)); - mcp->mb[3] = LSW(LSD(rsp->dma)); - mcp->mb[6] = MSW(MSD(rsp->dma)); - mcp->mb[7] = LSW(MSD(rsp->dma)); - mcp->mb[5] = rsp->length; - mcp->mb[14] = rsp->msix->entry; - mcp->mb[13] = rsp->rid; - if (IS_QLA83XX(ha)) - mcp->mb[15] = 0; - - reg = (struct device_reg_25xxmq *)((void *)(ha->mqiobase) + - QLA_QUE_PAGE * rsp->id); - - mcp->mb[4] = rsp->id; - /* que in ptr index */ - mcp->mb[8] = 0; - /* que out ptr index */ - mcp->mb[9] = 0; - mcp->out_mb = MBX_14|MBX_13|MBX_9|MBX_8|MBX_7 - |MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->flags = MBX_DMA_OUT; - mcp->tov = MBX_TOV_SECONDS * 2; - - if (IS_QLA81XX(ha)) { - mcp->out_mb |= MBX_12|MBX_11|MBX_10; - mcp->in_mb |= MBX_1; - } else if (IS_QLA83XX(ha)) { - mcp->out_mb |= MBX_15|MBX_12|MBX_11|MBX_10; - mcp->in_mb |= MBX_1; - /* debug q create issue in SR-IOV */ - mcp->in_mb |= MBX_9 | MBX_8 | MBX_7; - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (!(rsp->options & BIT_0)) { - WRT_REG_DWORD(®->rsp_q_out, 0); - if (!IS_QLA83XX(ha)) - WRT_REG_DWORD(®->rsp_q_in, 0); - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10d7, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10d8, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10d9, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_IDC_ACK; - memcpy(&mcp->mb[1], mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); - mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10da, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10db, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla81xx_fac_get_sector_size(scsi_qla_host_t *vha, uint32_t *sector_size) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10dc, "Entered %s.\n", __func__); - - if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; - mcp->mb[1] = FAC_OPT_CMD_GET_SECTOR_SIZE; - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10dd, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10de, "Done %s.\n", __func__); - *sector_size = mcp->mb[1]; - } - - return rval; -} - -int -qla81xx_fac_do_write_enable(scsi_qla_host_t *vha, int enable) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw)) - return QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x10df, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; - mcp->mb[1] = enable ? FAC_OPT_CMD_WRITE_ENABLE : - FAC_OPT_CMD_WRITE_PROTECT; - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10e0, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10e1, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla81xx_fac_erase_sector(scsi_qla_host_t *vha, uint32_t start, uint32_t finish) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_QLA81XX(vha->hw) && !IS_QLA83XX(vha->hw)) - return QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x10e2, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_FLASH_ACCESS_CTRL; - mcp->mb[1] = FAC_OPT_CMD_ERASE_SECTOR; - mcp->mb[2] = LSW(start); - mcp->mb[3] = MSW(start); - mcp->mb[4] = LSW(finish); - mcp->mb[5] = MSW(finish); - mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10e3, - "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n", - rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10e4, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla81xx_restart_mpi_firmware(scsi_qla_host_t *vha) -{ - int rval = 0; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10e5, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_RESTART_MPI_FW; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_0|MBX_1; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10e6, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10e7, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_read_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, - uint16_t dev, uint16_t off, uint16_t len, uint16_t opt) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x10e8, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(ha)) - return QLA_FUNCTION_FAILED; - - if (len == 1) - opt |= BIT_0; - - mcp->mb[0] = MBC_READ_SFP; - mcp->mb[1] = dev; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); - mcp->mb[6] = MSW(MSD(sfp_dma)); - mcp->mb[7] = LSW(MSD(sfp_dma)); - mcp->mb[8] = len; - mcp->mb[9] = off; - mcp->mb[10] = opt; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (opt & BIT_0) - *sfp = mcp->mb[1]; - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10e9, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10ea, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_write_sfp(scsi_qla_host_t *vha, dma_addr_t sfp_dma, uint8_t *sfp, - uint16_t dev, uint16_t off, uint16_t len, uint16_t opt) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x10eb, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(ha)) - return QLA_FUNCTION_FAILED; - - if (len == 1) - opt |= BIT_0; - - if (opt & BIT_0) - len = *sfp; - - mcp->mb[0] = MBC_WRITE_SFP; - mcp->mb[1] = dev; - mcp->mb[2] = MSW(sfp_dma); - mcp->mb[3] = LSW(sfp_dma); - mcp->mb[6] = MSW(MSD(sfp_dma)); - mcp->mb[7] = LSW(MSD(sfp_dma)); - mcp->mb[8] = len; - mcp->mb[9] = off; - mcp->mb[10] = opt; - mcp->out_mb = MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10ec, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10ed, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_get_xgmac_stats(scsi_qla_host_t *vha, dma_addr_t stats_dma, - uint16_t size_in_bytes, uint16_t *actual_size) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10ee, "Entered %s.\n", __func__); - - if (!IS_CNA_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_GET_XGMAC_STATS; - mcp->mb[2] = MSW(stats_dma); - mcp->mb[3] = LSW(stats_dma); - mcp->mb[6] = MSW(MSD(stats_dma)); - mcp->mb[7] = LSW(MSD(stats_dma)); - mcp->mb[8] = size_in_bytes >> 2; - mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_0; - mcp->in_mb = MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10ef, - "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n", - rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10f0, "Done %s.\n", __func__); - - - *actual_size = mcp->mb[2] << 2; - } - - return rval; -} - -int -qla2x00_get_dcbx_params(scsi_qla_host_t *vha, dma_addr_t tlv_dma, - uint16_t size) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10f1, "Entered %s.\n", __func__); - - if (!IS_CNA_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_GET_DCBX_PARAMS; - mcp->mb[1] = 0; - mcp->mb[2] = MSW(tlv_dma); - mcp->mb[3] = LSW(tlv_dma); - mcp->mb[6] = MSW(MSD(tlv_dma)); - mcp->mb[7] = LSW(MSD(tlv_dma)); - mcp->mb[8] = size; - mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10f2, - "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x.\n", - rval, mcp->mb[0], mcp->mb[1], mcp->mb[2]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10f3, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_read_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t *data) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10f4, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_READ_RAM_EXTENDED; - mcp->mb[1] = LSW(risc_addr); - mcp->mb[8] = MSW(risc_addr); - mcp->out_mb = MBX_8|MBX_1|MBX_0; - mcp->in_mb = MBX_3|MBX_2|MBX_0; - mcp->tov = 30; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10f5, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10f6, "Done %s.\n", __func__); - *data = mcp->mb[3] << 16 | mcp->mb[2]; - } - - return rval; -} - -int -qla2x00_loopback_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, - uint16_t *mresp) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - uint32_t iter_cnt = 0x1; - - ql_dbg(ql_dbg_mbx, vha, 0x10f7, "Entered %s.\n", __func__); - - memset(mcp->mb, 0 , sizeof(mcp->mb)); - mcp->mb[0] = MBC_DIAGNOSTIC_LOOP_BACK; - mcp->mb[1] = mreq->options | BIT_6; // BIT_6 specifies 64 bit addressing - - /* transfer count */ - mcp->mb[10] = LSW(mreq->transfer_size); - mcp->mb[11] = MSW(mreq->transfer_size); - - /* send data address */ - mcp->mb[14] = LSW(mreq->send_dma); - mcp->mb[15] = MSW(mreq->send_dma); - mcp->mb[20] = LSW(MSD(mreq->send_dma)); - mcp->mb[21] = MSW(MSD(mreq->send_dma)); - - /* receive data address */ - mcp->mb[16] = LSW(mreq->rcv_dma); - mcp->mb[17] = MSW(mreq->rcv_dma); - mcp->mb[6] = LSW(MSD(mreq->rcv_dma)); - mcp->mb[7] = MSW(MSD(mreq->rcv_dma)); - - /* Iteration count */ - mcp->mb[18] = LSW(iter_cnt); - mcp->mb[19] = MSW(iter_cnt); - - mcp->out_mb = MBX_21|MBX_20|MBX_19|MBX_18|MBX_17|MBX_16|MBX_15| - MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; - if (IS_CNA_CAPABLE(vha->hw)) - mcp->out_mb |= MBX_2; - mcp->in_mb = MBX_19|MBX_18|MBX_3|MBX_2|MBX_1|MBX_0; - - mcp->buf_size = mreq->transfer_size; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; - - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10f8, - "Failed=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[3]=%x mb[18]=%x " - "mb[19]=%x.\n", rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], - mcp->mb[3], mcp->mb[18], mcp->mb[19]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10f9, "Done %s.\n", __func__); - } - - /* Copy mailbox information */ - memcpy( mresp, mcp->mb, 64); - return rval; -} - -int -qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq, - uint16_t *mresp) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x10fa, "Entered %s.\n", __func__); - - memset(mcp->mb, 0 , sizeof(mcp->mb)); - mcp->mb[0] = MBC_DIAGNOSTIC_ECHO; - mcp->mb[1] = mreq->options | BIT_6; /* BIT_6 specifies 64bit address */ - if (IS_CNA_CAPABLE(ha)) { - mcp->mb[1] |= BIT_15; - mcp->mb[2] = vha->fcoe_fcf_idx; - } - mcp->mb[16] = LSW(mreq->rcv_dma); - mcp->mb[17] = MSW(mreq->rcv_dma); - mcp->mb[6] = LSW(MSD(mreq->rcv_dma)); - mcp->mb[7] = MSW(MSD(mreq->rcv_dma)); - - mcp->mb[10] = LSW(mreq->transfer_size); - - mcp->mb[14] = LSW(mreq->send_dma); - mcp->mb[15] = MSW(mreq->send_dma); - mcp->mb[20] = LSW(MSD(mreq->send_dma)); - mcp->mb[21] = MSW(MSD(mreq->send_dma)); - - mcp->out_mb = MBX_21|MBX_20|MBX_17|MBX_16|MBX_15| - MBX_14|MBX_10|MBX_7|MBX_6|MBX_1|MBX_0; - if (IS_CNA_CAPABLE(ha)) - mcp->out_mb |= MBX_2; - - mcp->in_mb = MBX_0; - if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) || - IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) - mcp->in_mb |= MBX_1; - if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) - mcp->in_mb |= MBX_3; - - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; - mcp->buf_size = mreq->transfer_size; - - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10fb, - "Failed=%x mb[0]=%x mb[1]=%x.\n", - rval, mcp->mb[0], mcp->mb[1]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10fc, "Done %s.\n", __func__); - } - - /* Copy mailbox information */ - memcpy(mresp, mcp->mb, 64); - return rval; -} - -int -qla84xx_reset_chip(scsi_qla_host_t *vha, uint16_t enable_diagnostic) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x10fd, - "Entered %s enable_diag=%d.\n", __func__, enable_diagnostic); - - mcp->mb[0] = MBC_ISP84XX_RESET; - mcp->mb[1] = enable_diagnostic; - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) - ql_dbg(ql_dbg_mbx, vha, 0x10fe, "Failed=%x.\n", rval); - else - ql_dbg(ql_dbg_mbx, vha, 0x10ff, "Done %s.\n", __func__); - - return rval; -} - -int -qla2x00_write_ram_word(scsi_qla_host_t *vha, uint32_t risc_addr, uint32_t data) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1100, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(vha->hw)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_WRITE_RAM_WORD_EXTENDED; - mcp->mb[1] = LSW(risc_addr); - mcp->mb[2] = LSW(data); - mcp->mb[3] = MSW(data); - mcp->mb[8] = MSW(risc_addr); - mcp->out_mb = MBX_8|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = 30; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1101, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1102, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb) -{ - int rval; - uint32_t stat, timer; - uint16_t mb0 = 0; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - rval = QLA_SUCCESS; - - ql_dbg(ql_dbg_mbx, vha, 0x1103, "Entered %s.\n", __func__); - - clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - - /* Write the MBC data to the registers */ - WRT_REG_WORD(®->mailbox0, MBC_WRITE_MPI_REGISTER); - WRT_REG_WORD(®->mailbox1, mb[0]); - WRT_REG_WORD(®->mailbox2, mb[1]); - WRT_REG_WORD(®->mailbox3, mb[2]); - WRT_REG_WORD(®->mailbox4, mb[3]); - - WRT_REG_DWORD(®->hccr, HCCRX_SET_HOST_INT); - - /* Poll for MBC interrupt */ - for (timer = 6000000; timer; timer--) { - /* Check for pending interrupts. */ - stat = RD_REG_DWORD(®->host_status); - if (stat & HSRX_RISC_INT) { - stat &= 0xff; - - if (stat == 0x1 || stat == 0x2 || - stat == 0x10 || stat == 0x11) { - set_bit(MBX_INTERRUPT, - &ha->mbx_cmd_flags); - mb0 = RD_REG_WORD(®->mailbox0); - WRT_REG_DWORD(®->hccr, - HCCRX_CLR_RISC_INT); - RD_REG_DWORD(®->hccr); - break; - } - } - udelay(5); - } - - if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) - rval = mb0 & MBS_MASK; - else - rval = QLA_FUNCTION_FAILED; - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1104, - "Failed=%x mb[0]=%x.\n", rval, mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1105, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_get_data_rate(scsi_qla_host_t *vha) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x1106, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(ha)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_DATA_RATE; - mcp->mb[1] = 0; - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_2|MBX_1|MBX_0; - if (IS_QLA83XX(ha)) - mcp->in_mb |= MBX_3; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1107, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1108, "Done %s.\n", __func__); - if (mcp->mb[1] != 0x7) - ha->link_data_rate = mcp->mb[1]; - } - - return rval; -} - -int -qla81xx_get_port_config(scsi_qla_host_t *vha, uint16_t *mb) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x1109, "Entered %s.\n", __func__); - - if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha)) - return QLA_FUNCTION_FAILED; - mcp->mb[0] = MBC_GET_PORT_CONFIG; - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x110a, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - /* Copy all bits to preserve original value */ - memcpy(mb, &mcp->mb[1], sizeof(uint16_t) * 4); - - ql_dbg(ql_dbg_mbx, vha, 0x110b, "Done %s.\n", __func__); - } - return rval; -} - -int -qla81xx_set_port_config(scsi_qla_host_t *vha, uint16_t *mb) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x110c, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_SET_PORT_CONFIG; - /* Copy all bits to preserve original setting */ - memcpy(&mcp->mb[1], mb, sizeof(uint16_t) * 4); - mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x110d, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else - ql_dbg(ql_dbg_mbx, vha, 0x110e, "Done %s.\n", __func__); - - return rval; -} - - -int -qla24xx_set_fcp_prio(scsi_qla_host_t *vha, uint16_t loop_id, uint16_t priority, - uint16_t *mb) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x110f, "Entered %s.\n", __func__); - - if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha)) - return QLA_FUNCTION_FAILED; - - mcp->mb[0] = MBC_PORT_PARAMS; - mcp->mb[1] = loop_id; - if (ha->flags.fcp_prio_enabled) - mcp->mb[2] = BIT_1; - else - mcp->mb[2] = BIT_2; - mcp->mb[4] = priority & 0xf; - mcp->mb[9] = vha->vp_idx; - mcp->out_mb = MBX_9|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_4|MBX_3|MBX_1|MBX_0; - mcp->tov = 30; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (mb != NULL) { - mb[0] = mcp->mb[0]; - mb[1] = mcp->mb[1]; - mb[3] = mcp->mb[3]; - mb[4] = mcp->mb[4]; - } - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10cd, "Failed=%x.\n", rval); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x10cc, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_get_thermal_temp(scsi_qla_host_t *vha, uint16_t *temp, uint16_t *frac) -{ - int rval; - uint8_t byte; - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_mbx, vha, 0x10ca, "Entered %s.\n", __func__); - - /* Integer part */ - rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x01, 1, BIT_13|BIT_0); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x10c9, "Failed=%x.\n", rval); - ha->flags.thermal_supported = 0; - goto fail; - } - *temp = byte; - - /* Fraction part */ - rval = qla2x00_read_sfp(vha, 0, &byte, 0x98, 0x10, 1, BIT_13|BIT_0); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1019, "Failed=%x.\n", rval); - ha->flags.thermal_supported = 0; - goto fail; - } - *frac = (byte >> 6) * 25; - - ql_dbg(ql_dbg_mbx, vha, 0x1018, "Done %s.\n", __func__); -fail: - return rval; -} - -int -qla82xx_mbx_intr_enable(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x1017, "Entered %s.\n", __func__); - - if (!IS_FWI2_CAPABLE(ha)) - return QLA_FUNCTION_FAILED; - - memset(mcp, 0, sizeof(mbx_cmd_t)); - mcp->mb[0] = MBC_TOGGLE_INTERRUPT; - mcp->mb[1] = 1; - - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = 30; - mcp->flags = 0; - - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1016, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x100e, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla82xx_mbx_intr_disable(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - ql_dbg(ql_dbg_mbx, vha, 0x100d, "Entered %s.\n", __func__); - - if (!IS_QLA82XX(ha)) - return QLA_FUNCTION_FAILED; - - memset(mcp, 0, sizeof(mbx_cmd_t)); - mcp->mb[0] = MBC_TOGGLE_INTERRUPT; - mcp->mb[1] = 0; - - mcp->out_mb = MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = 30; - mcp->flags = 0; - - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x100c, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x100b, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla82xx_md_get_template_size(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - int rval = QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x111f, "Entered %s.\n", __func__); - - memset(mcp->mb, 0 , sizeof(mcp->mb)); - mcp->mb[0] = LSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); - mcp->mb[1] = MSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); - mcp->mb[2] = LSW(RQST_TMPLT_SIZE); - mcp->mb[3] = MSW(RQST_TMPLT_SIZE); - - mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_14|MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8| - MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - - mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; - mcp->tov = MBX_TOV_SECONDS; - rval = qla2x00_mailbox_command(vha, mcp); - - /* Always copy back return mailbox values. */ - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1120, - "mailbox command FAILED=0x%x, subcode=%x.\n", - (mcp->mb[1] << 16) | mcp->mb[0], - (mcp->mb[3] << 16) | mcp->mb[2]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1121, "Done %s.\n", __func__); - ha->md_template_size = ((mcp->mb[3] << 16) | mcp->mb[2]); - if (!ha->md_template_size) { - ql_dbg(ql_dbg_mbx, vha, 0x1122, - "Null template size obtained.\n"); - rval = QLA_FUNCTION_FAILED; - } - } - return rval; -} - -int -qla82xx_md_get_template(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - int rval = QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x1123, "Entered %s.\n", __func__); - - ha->md_tmplt_hdr = dma_alloc_coherent(&ha->pdev->dev, - ha->md_template_size, &ha->md_tmplt_hdr_dma, GFP_KERNEL); - if (!ha->md_tmplt_hdr) { - ql_log(ql_log_warn, vha, 0x1124, - "Unable to allocate memory for Minidump template.\n"); - return rval; - } - - memset(mcp->mb, 0 , sizeof(mcp->mb)); - mcp->mb[0] = LSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); - mcp->mb[1] = MSW(MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE); - mcp->mb[2] = LSW(RQST_TMPLT); - mcp->mb[3] = MSW(RQST_TMPLT); - mcp->mb[4] = LSW(LSD(ha->md_tmplt_hdr_dma)); - mcp->mb[5] = MSW(LSD(ha->md_tmplt_hdr_dma)); - mcp->mb[6] = LSW(MSD(ha->md_tmplt_hdr_dma)); - mcp->mb[7] = MSW(MSD(ha->md_tmplt_hdr_dma)); - mcp->mb[8] = LSW(ha->md_template_size); - mcp->mb[9] = MSW(ha->md_template_size); - - mcp->flags = MBX_DMA_OUT|MBX_DMA_IN|IOCTL_CMD; - mcp->tov = MBX_TOV_SECONDS; - mcp->out_mb = MBX_11|MBX_10|MBX_9|MBX_8| - MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1125, - "mailbox command FAILED=0x%x, subcode=%x.\n", - ((mcp->mb[1] << 16) | mcp->mb[0]), - ((mcp->mb[3] << 16) | mcp->mb[2])); - } else - ql_dbg(ql_dbg_mbx, vha, 0x1126, "Done %s.\n", __func__); - return rval; -} - -int -qla81xx_set_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) - return QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x1133, "Entered %s.\n", __func__); - - memset(mcp, 0, sizeof(mbx_cmd_t)); - mcp->mb[0] = MBC_SET_LED_CONFIG; - mcp->mb[1] = led_cfg[0]; - mcp->mb[2] = led_cfg[1]; - if (IS_QLA8031(ha)) { - mcp->mb[3] = led_cfg[2]; - mcp->mb[4] = led_cfg[3]; - mcp->mb[5] = led_cfg[4]; - mcp->mb[6] = led_cfg[5]; - } - - mcp->out_mb = MBX_2|MBX_1|MBX_0; - if (IS_QLA8031(ha)) - mcp->out_mb |= MBX_6|MBX_5|MBX_4|MBX_3; - mcp->in_mb = MBX_0; - mcp->tov = 30; - mcp->flags = 0; - - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1134, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1135, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla81xx_get_led_config(scsi_qla_host_t *vha, uint16_t *led_cfg) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha)) - return QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x1136, "Entered %s.\n", __func__); - - memset(mcp, 0, sizeof(mbx_cmd_t)); - mcp->mb[0] = MBC_GET_LED_CONFIG; - - mcp->out_mb = MBX_0; - mcp->in_mb = MBX_2|MBX_1|MBX_0; - if (IS_QLA8031(ha)) - mcp->in_mb |= MBX_6|MBX_5|MBX_4|MBX_3; - mcp->tov = 30; - mcp->flags = 0; - - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1137, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - led_cfg[0] = mcp->mb[1]; - led_cfg[1] = mcp->mb[2]; - if (IS_QLA8031(ha)) { - led_cfg[2] = mcp->mb[3]; - led_cfg[3] = mcp->mb[4]; - led_cfg[4] = mcp->mb[5]; - led_cfg[5] = mcp->mb[6]; - } - ql_dbg(ql_dbg_mbx, vha, 0x1138, "Done %s.\n", __func__); - } - - return rval; -} - -int -qla82xx_mbx_beacon_ctl(scsi_qla_host_t *vha, int enable) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_QLA82XX(ha)) - return QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x1127, - "Entered %s.\n", __func__); - - memset(mcp, 0, sizeof(mbx_cmd_t)); - mcp->mb[0] = MBC_SET_LED_CONFIG; - if (enable) - mcp->mb[7] = 0xE; - else - mcp->mb[7] = 0xD; - - mcp->out_mb = MBX_7|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1128, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1129, - "Done %s.\n", __func__); - } - - return rval; -} - -int -qla83xx_write_remote_reg(scsi_qla_host_t *vha, uint32_t reg, uint32_t data) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (!IS_QLA83XX(ha)) - return QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_mbx, vha, 0x1130, "Entered %s.\n", __func__); - - mcp->mb[0] = MBC_WRITE_REMOTE_REG; - mcp->mb[1] = LSW(reg); - mcp->mb[2] = MSW(reg); - mcp->mb[3] = LSW(data); - mcp->mb[4] = MSW(data); - mcp->out_mb = MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; - - mcp->in_mb = MBX_1|MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_mbx, vha, 0x1131, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - } else { - ql_dbg(ql_dbg_mbx, vha, 0x1132, - "Done %s.\n", __func__); - } - - return rval; -} - -int -qla2x00_port_logout(scsi_qla_host_t *vha, struct fc_port *fcport) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - ql_dbg(ql_dbg_mbx, vha, 0x113b, - "Implicit LOGO Unsupported.\n"); - return QLA_FUNCTION_FAILED; - } - - - ql_dbg(ql_dbg_mbx, vha, 0x113c, "Done %s.\n", __func__); - - /* Perform Implicit LOGO. */ - mcp->mb[0] = MBC_PORT_LOGOUT; - mcp->mb[1] = fcport->loop_id; - mcp->mb[10] = BIT_15; - mcp->out_mb = MBX_10|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = MBX_TOV_SECONDS; - mcp->flags = 0; - rval = qla2x00_mailbox_command(vha, mcp); - if (rval != QLA_SUCCESS) - ql_dbg(ql_dbg_mbx, vha, 0x113d, - "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); - else - ql_dbg(ql_dbg_mbx, vha, 0x113e, "Done %s.\n", __func__); - - return rval; -} - diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mid.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mid.c deleted file mode 100644 index aa062a1b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_mid.c +++ /dev/null @@ -1,836 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" -#include "qla_gbl.h" - -#include -#include -#include -#include - -#include -#include -#include - -void -qla2x00_vp_stop_timer(scsi_qla_host_t *vha) -{ - if (vha->vp_idx && vha->timer_active) { - del_timer_sync(&vha->timer); - vha->timer_active = 0; - } -} - -static uint32_t -qla24xx_allocate_vp_id(scsi_qla_host_t *vha) -{ - uint32_t vp_id; - struct qla_hw_data *ha = vha->hw; - unsigned long flags; - - /* Find an empty slot and assign an vp_id */ - mutex_lock(&ha->vport_lock); - vp_id = find_first_zero_bit(ha->vp_idx_map, ha->max_npiv_vports + 1); - if (vp_id > ha->max_npiv_vports) { - ql_dbg(ql_dbg_vport, vha, 0xa000, - "vp_id %d is bigger than max-supported %d.\n", - vp_id, ha->max_npiv_vports); - mutex_unlock(&ha->vport_lock); - return vp_id; - } - - set_bit(vp_id, ha->vp_idx_map); - ha->num_vhosts++; - vha->vp_idx = vp_id; - - spin_lock_irqsave(&ha->vport_slock, flags); - list_add_tail(&vha->list, &ha->vp_list); - spin_unlock_irqrestore(&ha->vport_slock, flags); - - mutex_unlock(&ha->vport_lock); - return vp_id; -} - -void -qla24xx_deallocate_vp_id(scsi_qla_host_t *vha) -{ - uint16_t vp_id; - struct qla_hw_data *ha = vha->hw; - unsigned long flags = 0; - - mutex_lock(&ha->vport_lock); - /* - * Wait for all pending activities to finish before removing vport from - * the list. - * Lock needs to be held for safe removal from the list (it - * ensures no active vp_list traversal while the vport is removed - * from the queue) - */ - spin_lock_irqsave(&ha->vport_slock, flags); - while (atomic_read(&vha->vref_count)) { - spin_unlock_irqrestore(&ha->vport_slock, flags); - - msleep(500); - - spin_lock_irqsave(&ha->vport_slock, flags); - } - list_del(&vha->list); - spin_unlock_irqrestore(&ha->vport_slock, flags); - - vp_id = vha->vp_idx; - ha->num_vhosts--; - clear_bit(vp_id, ha->vp_idx_map); - - mutex_unlock(&ha->vport_lock); -} - -static scsi_qla_host_t * -qla24xx_find_vhost_by_name(struct qla_hw_data *ha, uint8_t *port_name) -{ - scsi_qla_host_t *vha; - struct scsi_qla_host *tvha; - unsigned long flags; - - spin_lock_irqsave(&ha->vport_slock, flags); - /* Locate matching device in database. */ - list_for_each_entry_safe(vha, tvha, &ha->vp_list, list) { - if (!memcmp(port_name, vha->port_name, WWN_SIZE)) { - spin_unlock_irqrestore(&ha->vport_slock, flags); - return vha; - } - } - spin_unlock_irqrestore(&ha->vport_slock, flags); - return NULL; -} - -/* - * qla2x00_mark_vp_devices_dead - * Updates fcport state when device goes offline. - * - * Input: - * ha = adapter block pointer. - * fcport = port structure pointer. - * - * Return: - * None. - * - * Context: - */ -static void -qla2x00_mark_vp_devices_dead(scsi_qla_host_t *vha) -{ - /* - * !!! NOTE !!! - * This function, if called in contexts other than vp create, disable - * or delete, please make sure this is synchronized with the - * delete thread. - */ - fc_port_t *fcport; - - list_for_each_entry(fcport, &vha->vp_fcports, list) { - ql_dbg(ql_dbg_vport, vha, 0xa001, - "Marking port dead, loop_id=0x%04x : %x.\n", - fcport->loop_id, fcport->vp_idx); - - qla2x00_mark_device_lost(vha, fcport, 0, 0); - qla2x00_set_fcport_state(fcport, FCS_UNCONFIGURED); - } -} - -int -qla24xx_disable_vp(scsi_qla_host_t *vha) -{ - int ret; - - ret = qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); - atomic_set(&vha->loop_state, LOOP_DOWN); - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - - qla2x00_mark_vp_devices_dead(vha); - atomic_set(&vha->vp_state, VP_FAILED); - vha->flags.management_server_logged_in = 0; - if (ret == QLA_SUCCESS) { - fc_vport_set_state(vha->fc_vport, FC_VPORT_DISABLED); - } else { - fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); - return -1; - } - return 0; -} - -int -qla24xx_enable_vp(scsi_qla_host_t *vha) -{ - int ret; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - /* Check if physical ha port is Up */ - if (atomic_read(&base_vha->loop_state) == LOOP_DOWN || - atomic_read(&base_vha->loop_state) == LOOP_DEAD || - !(ha->current_topology & ISP_CFG_F)) { - vha->vp_err_state = VP_ERR_PORTDWN; - fc_vport_set_state(vha->fc_vport, FC_VPORT_LINKDOWN); - goto enable_failed; - } - - /* Initialize the new vport unless it is a persistent port */ - mutex_lock(&ha->vport_lock); - ret = qla24xx_modify_vp_config(vha); - mutex_unlock(&ha->vport_lock); - - if (ret != QLA_SUCCESS) { - fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED); - goto enable_failed; - } - - ql_dbg(ql_dbg_taskm, vha, 0x801a, - "Virtual port with id: %d - Enabled.\n", vha->vp_idx); - return 0; - -enable_failed: - ql_dbg(ql_dbg_taskm, vha, 0x801b, - "Virtual port with id: %d - Disabled.\n", vha->vp_idx); - return 1; -} - -static void -qla24xx_configure_vp(scsi_qla_host_t *vha) -{ - struct fc_vport *fc_vport; - int ret; - - fc_vport = vha->fc_vport; - - ql_dbg(ql_dbg_vport, vha, 0xa002, - "%s: change request #3.\n", __func__); - ret = qla2x00_send_change_request(vha, 0x3, vha->vp_idx); - if (ret != QLA_SUCCESS) { - ql_dbg(ql_dbg_vport, vha, 0xa003, "Failed to enable " - "receiving of RSCN requests: 0x%x.\n", ret); - return; - } else { - /* Corresponds to SCR enabled */ - clear_bit(VP_SCR_NEEDED, &vha->vp_flags); - } - - vha->flags.online = 1; - if (qla24xx_configure_vhba(vha)) - return; - - atomic_set(&vha->vp_state, VP_ACTIVE); - fc_vport_set_state(fc_vport, FC_VPORT_ACTIVE); -} - -void -qla2x00_alert_all_vps(struct rsp_que *rsp, uint16_t *mb) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha = rsp->hw; - int i = 0; - unsigned long flags; - - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vha, &ha->vp_list, list) { - if (vha->vp_idx) { - atomic_inc(&vha->vref_count); - spin_unlock_irqrestore(&ha->vport_slock, flags); - - switch (mb[0]) { - case MBA_LIP_OCCURRED: - case MBA_LOOP_UP: - case MBA_LOOP_DOWN: - case MBA_LIP_RESET: - case MBA_POINT_TO_POINT: - case MBA_CHG_IN_CONNECTION: - case MBA_PORT_UPDATE: - case MBA_RSCN_UPDATE: - ql_dbg(ql_dbg_async, vha, 0x5024, - "Async_event for VP[%d], mb=0x%x vha=%p.\n", - i, *mb, vha); - qla2x00_async_event(vha, rsp, mb); - break; - } - - spin_lock_irqsave(&ha->vport_slock, flags); - atomic_dec(&vha->vref_count); - } - i++; - } - spin_unlock_irqrestore(&ha->vport_slock, flags); -} - -int -qla2x00_vp_abort_isp(scsi_qla_host_t *vha) -{ - /* - * Physical port will do most of the abort and recovery work. We can - * just treat it as a loop down - */ - if (atomic_read(&vha->loop_state) != LOOP_DOWN) { - atomic_set(&vha->loop_state, LOOP_DOWN); - qla2x00_mark_all_devices_lost(vha, 0); - } else { - if (!atomic_read(&vha->loop_down_timer)) - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - } - - /* - * To exclusively reset vport, we need to log it out first. Note: this - * control_vp can fail if ISP reset is already issued, this is - * expected, as the vp would be already logged out due to ISP reset. - */ - if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) - qla24xx_control_vp(vha, VCE_COMMAND_DISABLE_VPS_LOGO_ALL); - - ql_dbg(ql_dbg_taskm, vha, 0x801d, - "Scheduling enable of Vport %d.\n", vha->vp_idx); - return qla24xx_enable_vp(vha); -} - -static int -qla2x00_do_dpc_vp(scsi_qla_host_t *vha) -{ - ql_dbg(ql_dbg_dpc, vha, 0x4012, - "Entering %s.\n", __func__); - ql_dbg(ql_dbg_dpc, vha, 0x4013, - "vp_flags: 0x%lx.\n", vha->vp_flags); - - qla2x00_do_work(vha); - - if (test_and_clear_bit(VP_IDX_ACQUIRED, &vha->vp_flags)) { - /* VP acquired. complete port configuration */ - ql_dbg(ql_dbg_dpc, vha, 0x4014, - "Configure VP scheduled.\n"); - qla24xx_configure_vp(vha); - ql_dbg(ql_dbg_dpc, vha, 0x4015, - "Configure VP end.\n"); - return 0; - } - - if (test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) { - ql_dbg(ql_dbg_dpc, vha, 0x4016, - "FCPort update scheduled.\n"); - qla2x00_update_fcports(vha); - clear_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags); - ql_dbg(ql_dbg_dpc, vha, 0x4017, - "FCPort update end.\n"); - } - - if ((test_and_clear_bit(RELOGIN_NEEDED, &vha->dpc_flags)) && - !test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) && - atomic_read(&vha->loop_state) != LOOP_DOWN) { - - ql_dbg(ql_dbg_dpc, vha, 0x4018, - "Relogin needed scheduled.\n"); - qla2x00_relogin(vha); - ql_dbg(ql_dbg_dpc, vha, 0x4019, - "Relogin needed end.\n"); - } - - if (test_and_clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) && - (!(test_and_set_bit(RESET_ACTIVE, &vha->dpc_flags)))) { - clear_bit(RESET_ACTIVE, &vha->dpc_flags); - } - - if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) { - if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))) { - ql_dbg(ql_dbg_dpc, vha, 0x401a, - "Loop resync scheduled.\n"); - qla2x00_loop_resync(vha); - clear_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags); - ql_dbg(ql_dbg_dpc, vha, 0x401b, - "Loop resync end.\n"); - } - } - - ql_dbg(ql_dbg_dpc, vha, 0x401c, - "Exiting %s.\n", __func__); - return 0; -} - -void -qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) -{ - int ret; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *vp; - unsigned long flags = 0; - - if (vha->vp_idx) - return; - if (list_empty(&ha->vp_list)) - return; - - clear_bit(VP_DPC_NEEDED, &vha->dpc_flags); - - if (!(ha->current_topology & ISP_CFG_F)) - return; - - spin_lock_irqsave(&ha->vport_slock, flags); - list_for_each_entry(vp, &ha->vp_list, list) { - if (vp->vp_idx) { - atomic_inc(&vp->vref_count); - spin_unlock_irqrestore(&ha->vport_slock, flags); - - ret = qla2x00_do_dpc_vp(vp); - - spin_lock_irqsave(&ha->vport_slock, flags); - atomic_dec(&vp->vref_count); - } - } - spin_unlock_irqrestore(&ha->vport_slock, flags); -} - -int -qla24xx_vport_create_req_sanity_check(struct fc_vport *fc_vport) -{ - scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost); - struct qla_hw_data *ha = base_vha->hw; - scsi_qla_host_t *vha; - uint8_t port_name[WWN_SIZE]; - - if (fc_vport->roles != FC_PORT_ROLE_FCP_INITIATOR) - return VPCERR_UNSUPPORTED; - - /* Check up the F/W and H/W support NPIV */ - if (!ha->flags.npiv_supported) - return VPCERR_UNSUPPORTED; - - /* Check up whether npiv supported switch presented */ - if (!(ha->switch_cap & FLOGI_MID_SUPPORT)) - return VPCERR_NO_FABRIC_SUPP; - - /* Check up unique WWPN */ - u64_to_wwn(fc_vport->port_name, port_name); - if (!memcmp(port_name, base_vha->port_name, WWN_SIZE)) - return VPCERR_BAD_WWN; - vha = qla24xx_find_vhost_by_name(ha, port_name); - if (vha) - return VPCERR_BAD_WWN; - - /* Check up max-npiv-supports */ - if (ha->num_vhosts > ha->max_npiv_vports) { - ql_dbg(ql_dbg_vport, vha, 0xa004, - "num_vhosts %ud is bigger " - "than max_npiv_vports %ud.\n", - ha->num_vhosts, ha->max_npiv_vports); - return VPCERR_UNSUPPORTED; - } - return 0; -} - -scsi_qla_host_t * -qla24xx_create_vhost(struct fc_vport *fc_vport) -{ - scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost); - struct qla_hw_data *ha = base_vha->hw; - scsi_qla_host_t *vha; - struct scsi_host_template *sht = &qla2xxx_driver_template; - struct Scsi_Host *host; - - vha = qla2x00_create_host(sht, ha); - if (!vha) { - ql_log(ql_log_warn, vha, 0xa005, - "scsi_host_alloc() failed for vport.\n"); - return(NULL); - } - - host = vha->host; - fc_vport->dd_data = vha; - /* New host info */ - u64_to_wwn(fc_vport->node_name, vha->node_name); - u64_to_wwn(fc_vport->port_name, vha->port_name); - - vha->fc_vport = fc_vport; - vha->device_flags = 0; - vha->vp_idx = qla24xx_allocate_vp_id(vha); - if (vha->vp_idx > ha->max_npiv_vports) { - ql_dbg(ql_dbg_vport, vha, 0xa006, - "Couldn't allocate vp_id.\n"); - goto create_vhost_failed; - } - vha->mgmt_svr_loop_id = 10 + vha->vp_idx; - - vha->dpc_flags = 0L; - - /* - * To fix the issue of processing a parent's RSCN for the vport before - * its SCR is complete. - */ - set_bit(VP_SCR_NEEDED, &vha->vp_flags); - atomic_set(&vha->loop_state, LOOP_DOWN); - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - - qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL); - - vha->req = base_vha->req; - host->can_queue = base_vha->req->length + 128; - host->this_id = 255; - host->cmd_per_lun = 3; - if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) - host->max_cmd_len = 32; - else - host->max_cmd_len = MAX_CMDSZ; - host->max_channel = MAX_BUSES - 1; - host->max_lun = ql2xmaxlun; - host->unique_id = host->host_no; - host->max_id = ha->max_fibre_devices; - host->transportt = qla2xxx_transport_vport_template; - - ql_dbg(ql_dbg_vport, vha, 0xa007, - "Detect vport hba %ld at address = %p.\n", - vha->host_no, vha); - - vha->flags.init_done = 1; - - mutex_lock(&ha->vport_lock); - set_bit(vha->vp_idx, ha->vp_idx_map); - ha->cur_vport_count++; - mutex_unlock(&ha->vport_lock); - - return vha; - -create_vhost_failed: - return NULL; -} - -static void -qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req) -{ - struct qla_hw_data *ha = vha->hw; - uint16_t que_id = req->id; - - dma_free_coherent(&ha->pdev->dev, (req->length + 1) * - sizeof(request_t), req->ring, req->dma); - req->ring = NULL; - req->dma = 0; - if (que_id) { - ha->req_q_map[que_id] = NULL; - mutex_lock(&ha->vport_lock); - clear_bit(que_id, ha->req_qid_map); - mutex_unlock(&ha->vport_lock); - } - kfree(req); - req = NULL; -} - -static void -qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) -{ - struct qla_hw_data *ha = vha->hw; - uint16_t que_id = rsp->id; - - if (rsp->msix && rsp->msix->have_irq) { - free_irq(rsp->msix->vector, rsp); - rsp->msix->have_irq = 0; - rsp->msix->rsp = NULL; - } - dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) * - sizeof(response_t), rsp->ring, rsp->dma); - rsp->ring = NULL; - rsp->dma = 0; - if (que_id) { - ha->rsp_q_map[que_id] = NULL; - mutex_lock(&ha->vport_lock); - clear_bit(que_id, ha->rsp_qid_map); - mutex_unlock(&ha->vport_lock); - } - kfree(rsp); - rsp = NULL; -} - -int -qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req) -{ - int ret = -1; - - if (req) { - req->options |= BIT_0; - ret = qla25xx_init_req_que(vha, req); - } - if (ret == QLA_SUCCESS) - qla25xx_free_req_que(vha, req); - - return ret; -} - -static int -qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) -{ - int ret = -1; - - if (rsp) { - rsp->options |= BIT_0; - ret = qla25xx_init_rsp_que(vha, rsp); - } - if (ret == QLA_SUCCESS) - qla25xx_free_rsp_que(vha, rsp); - - return ret; -} - -/* Delete all queues for a given vhost */ -int -qla25xx_delete_queues(struct scsi_qla_host *vha) -{ - int cnt, ret = 0; - struct req_que *req = NULL; - struct rsp_que *rsp = NULL; - struct qla_hw_data *ha = vha->hw; - - /* Delete request queues */ - for (cnt = 1; cnt < ha->max_req_queues; cnt++) { - req = ha->req_q_map[cnt]; - if (req) { - ret = qla25xx_delete_req_que(vha, req); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x00ea, - "Couldn't delete req que %d.\n", - req->id); - return ret; - } - } - } - - /* Delete response queues */ - for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) { - rsp = ha->rsp_q_map[cnt]; - if (rsp) { - ret = qla25xx_delete_rsp_que(vha, rsp); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x00eb, - "Couldn't delete rsp que %d.\n", - rsp->id); - return ret; - } - } - } - return ret; -} - -int -qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, - uint8_t vp_idx, uint16_t rid, int rsp_que, uint8_t qos) -{ - int ret = 0; - struct req_que *req = NULL; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - uint16_t que_id = 0; - device_reg_t __iomem *reg; - uint32_t cnt; - - req = kzalloc(sizeof(struct req_que), GFP_KERNEL); - if (req == NULL) { - ql_log(ql_log_fatal, base_vha, 0x00d9, - "Failed to allocate memory for request queue.\n"); - goto failed; - } - - req->length = REQUEST_ENTRY_CNT_24XX; - req->ring = dma_alloc_coherent(&ha->pdev->dev, - (req->length + 1) * sizeof(request_t), - &req->dma, GFP_KERNEL); - if (req->ring == NULL) { - ql_log(ql_log_fatal, base_vha, 0x00da, - "Failed to allocte memory for request_ring.\n"); - goto que_failed; - } - - mutex_lock(&ha->vport_lock); - que_id = find_first_zero_bit(ha->req_qid_map, ha->max_req_queues); - if (que_id >= ha->max_req_queues) { - mutex_unlock(&ha->vport_lock); - ql_log(ql_log_warn, base_vha, 0x00db, - "No resources to create additional request queue.\n"); - goto que_failed; - } - set_bit(que_id, ha->req_qid_map); - ha->req_q_map[que_id] = req; - req->rid = rid; - req->vp_idx = vp_idx; - req->qos = qos; - - ql_dbg(ql_dbg_multiq, base_vha, 0xc002, - "queue_id=%d rid=%d vp_idx=%d qos=%d.\n", - que_id, req->rid, req->vp_idx, req->qos); - ql_dbg(ql_dbg_init, base_vha, 0x00dc, - "queue_id=%d rid=%d vp_idx=%d qos=%d.\n", - que_id, req->rid, req->vp_idx, req->qos); - if (rsp_que < 0) - req->rsp = NULL; - else - req->rsp = ha->rsp_q_map[rsp_que]; - /* Use alternate PCI bus number */ - if (MSB(req->rid)) - options |= BIT_4; - /* Use alternate PCI devfn */ - if (LSB(req->rid)) - options |= BIT_5; - req->options = options; - - ql_dbg(ql_dbg_multiq, base_vha, 0xc003, - "options=0x%x.\n", req->options); - ql_dbg(ql_dbg_init, base_vha, 0x00dd, - "options=0x%x.\n", req->options); - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) - req->outstanding_cmds[cnt] = NULL; - req->current_outstanding_cmd = 1; - - req->ring_ptr = req->ring; - req->ring_index = 0; - req->cnt = req->length; - req->id = que_id; - reg = ISP_QUE_REG(ha, que_id); - req->max_q_depth = ha->req_q_map[0]->max_q_depth; - mutex_unlock(&ha->vport_lock); - ql_dbg(ql_dbg_multiq, base_vha, 0xc004, - "ring_ptr=%p ring_index=%d, " - "cnt=%d id=%d max_q_depth=%d.\n", - req->ring_ptr, req->ring_index, - req->cnt, req->id, req->max_q_depth); - ql_dbg(ql_dbg_init, base_vha, 0x00de, - "ring_ptr=%p ring_index=%d, " - "cnt=%d id=%d max_q_depth=%d.\n", - req->ring_ptr, req->ring_index, req->cnt, - req->id, req->max_q_depth); - - ret = qla25xx_init_req_que(base_vha, req); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_fatal, base_vha, 0x00df, - "%s failed.\n", __func__); - mutex_lock(&ha->vport_lock); - clear_bit(que_id, ha->req_qid_map); - mutex_unlock(&ha->vport_lock); - goto que_failed; - } - - return req->id; - -que_failed: - qla25xx_free_req_que(base_vha, req); -failed: - return 0; -} - -static void qla_do_work(struct work_struct *work) -{ - unsigned long flags; - struct rsp_que *rsp = container_of(work, struct rsp_que, q_work); - struct scsi_qla_host *vha; - struct qla_hw_data *ha = rsp->hw; - - spin_lock_irqsave(&rsp->hw->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - qla24xx_process_response_queue(vha, rsp); - spin_unlock_irqrestore(&rsp->hw->hardware_lock, flags); -} - -/* create response queue */ -int -qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, - uint8_t vp_idx, uint16_t rid, int req) -{ - int ret = 0; - struct rsp_que *rsp = NULL; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - uint16_t que_id = 0; - device_reg_t __iomem *reg; - - rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); - if (rsp == NULL) { - ql_log(ql_log_warn, base_vha, 0x0066, - "Failed to allocate memory for response queue.\n"); - goto failed; - } - - rsp->length = RESPONSE_ENTRY_CNT_MQ; - rsp->ring = dma_alloc_coherent(&ha->pdev->dev, - (rsp->length + 1) * sizeof(response_t), - &rsp->dma, GFP_KERNEL); - if (rsp->ring == NULL) { - ql_log(ql_log_warn, base_vha, 0x00e1, - "Failed to allocate memory for response ring.\n"); - goto que_failed; - } - - mutex_lock(&ha->vport_lock); - que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues); - if (que_id >= ha->max_rsp_queues) { - mutex_unlock(&ha->vport_lock); - ql_log(ql_log_warn, base_vha, 0x00e2, - "No resources to create additional request queue.\n"); - goto que_failed; - } - set_bit(que_id, ha->rsp_qid_map); - - if (ha->flags.msix_enabled) - rsp->msix = &ha->msix_entries[que_id + 1]; - else - ql_log(ql_log_warn, base_vha, 0x00e3, - "MSIX not enalbled.\n"); - - ha->rsp_q_map[que_id] = rsp; - rsp->rid = rid; - rsp->vp_idx = vp_idx; - rsp->hw = ha; - ql_dbg(ql_dbg_init, base_vha, 0x00e4, - "queue_id=%d rid=%d vp_idx=%d hw=%p.\n", - que_id, rsp->rid, rsp->vp_idx, rsp->hw); - /* Use alternate PCI bus number */ - if (MSB(rsp->rid)) - options |= BIT_4; - /* Use alternate PCI devfn */ - if (LSB(rsp->rid)) - options |= BIT_5; - /* Enable MSIX handshake mode on for uncapable adapters */ - if (!IS_MSIX_NACK_CAPABLE(ha)) - options |= BIT_6; - - rsp->options = options; - rsp->id = que_id; - reg = ISP_QUE_REG(ha, que_id); - rsp->rsp_q_in = ®->isp25mq.rsp_q_in; - rsp->rsp_q_out = ®->isp25mq.rsp_q_out; - mutex_unlock(&ha->vport_lock); - ql_dbg(ql_dbg_multiq, base_vha, 0xc00b, - "options=%x id=%d rsp_q_in=%p rsp_q_out=%p", - rsp->options, rsp->id, rsp->rsp_q_in, - rsp->rsp_q_out); - ql_dbg(ql_dbg_init, base_vha, 0x00e5, - "options=%x id=%d rsp_q_in=%p rsp_q_out=%p", - rsp->options, rsp->id, rsp->rsp_q_in, - rsp->rsp_q_out); - - ret = qla25xx_request_irq(rsp); - if (ret) - goto que_failed; - - ret = qla25xx_init_rsp_que(base_vha, rsp); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_fatal, base_vha, 0x00e7, - "%s failed.\n", __func__); - mutex_lock(&ha->vport_lock); - clear_bit(que_id, ha->rsp_qid_map); - mutex_unlock(&ha->vport_lock); - goto que_failed; - } - if (req >= 0) - rsp->req = ha->req_q_map[req]; - else - rsp->req = NULL; - - qla2x00_init_response_q_entries(rsp); - if (rsp->hw->wq) - INIT_WORK(&rsp->q_work, qla_do_work); - return rsp->id; - -que_failed: - qla25xx_free_rsp_que(base_vha, rsp); -failed: - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.c deleted file mode 100644 index de722a93..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.c +++ /dev/null @@ -1,4428 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" -#include -#include -#include -#include -#include - -#define MASK(n) ((1ULL<<(n))-1) -#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \ - ((addr >> 25) & 0x3ff)) -#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | \ - ((addr >> 25) & 0x3ff)) -#define MS_WIN(addr) (addr & 0x0ffc0000) -#define QLA82XX_PCI_MN_2M (0) -#define QLA82XX_PCI_MS_2M (0x80000) -#define QLA82XX_PCI_OCM0_2M (0xc0000) -#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800) -#define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) -#define BLOCK_PROTECT_BITS 0x0F - -/* CRB window related */ -#define CRB_BLK(off) ((off >> 20) & 0x3f) -#define CRB_SUBBLK(off) ((off >> 16) & 0xf) -#define CRB_WINDOW_2M (0x130060) -#define QLA82XX_PCI_CAMQM_2M_END (0x04800800UL) -#define CRB_HI(off) ((qla82xx_crb_hub_agt[CRB_BLK(off)] << 20) | \ - ((off) & 0xf0000)) -#define QLA82XX_PCI_CAMQM_2M_BASE (0x000ff800UL) -#define CRB_INDIRECT_2M (0x1e0000UL) - -#define MAX_CRB_XFORM 60 -static unsigned long crb_addr_xform[MAX_CRB_XFORM]; -int qla82xx_crb_table_initialized; - -#define qla82xx_crb_addr_transform(name) \ - (crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \ - QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20) - -static void qla82xx_crb_addr_transform_setup(void) -{ - qla82xx_crb_addr_transform(XDMA); - qla82xx_crb_addr_transform(TIMR); - qla82xx_crb_addr_transform(SRE); - qla82xx_crb_addr_transform(SQN3); - qla82xx_crb_addr_transform(SQN2); - qla82xx_crb_addr_transform(SQN1); - qla82xx_crb_addr_transform(SQN0); - qla82xx_crb_addr_transform(SQS3); - qla82xx_crb_addr_transform(SQS2); - qla82xx_crb_addr_transform(SQS1); - qla82xx_crb_addr_transform(SQS0); - qla82xx_crb_addr_transform(RPMX7); - qla82xx_crb_addr_transform(RPMX6); - qla82xx_crb_addr_transform(RPMX5); - qla82xx_crb_addr_transform(RPMX4); - qla82xx_crb_addr_transform(RPMX3); - qla82xx_crb_addr_transform(RPMX2); - qla82xx_crb_addr_transform(RPMX1); - qla82xx_crb_addr_transform(RPMX0); - qla82xx_crb_addr_transform(ROMUSB); - qla82xx_crb_addr_transform(SN); - qla82xx_crb_addr_transform(QMN); - qla82xx_crb_addr_transform(QMS); - qla82xx_crb_addr_transform(PGNI); - qla82xx_crb_addr_transform(PGND); - qla82xx_crb_addr_transform(PGN3); - qla82xx_crb_addr_transform(PGN2); - qla82xx_crb_addr_transform(PGN1); - qla82xx_crb_addr_transform(PGN0); - qla82xx_crb_addr_transform(PGSI); - qla82xx_crb_addr_transform(PGSD); - qla82xx_crb_addr_transform(PGS3); - qla82xx_crb_addr_transform(PGS2); - qla82xx_crb_addr_transform(PGS1); - qla82xx_crb_addr_transform(PGS0); - qla82xx_crb_addr_transform(PS); - qla82xx_crb_addr_transform(PH); - qla82xx_crb_addr_transform(NIU); - qla82xx_crb_addr_transform(I2Q); - qla82xx_crb_addr_transform(EG); - qla82xx_crb_addr_transform(MN); - qla82xx_crb_addr_transform(MS); - qla82xx_crb_addr_transform(CAS2); - qla82xx_crb_addr_transform(CAS1); - qla82xx_crb_addr_transform(CAS0); - qla82xx_crb_addr_transform(CAM); - qla82xx_crb_addr_transform(C2C1); - qla82xx_crb_addr_transform(C2C0); - qla82xx_crb_addr_transform(SMB); - qla82xx_crb_addr_transform(OCM0); - /* - * Used only in P3 just define it for P2 also. - */ - qla82xx_crb_addr_transform(I2C0); - - qla82xx_crb_table_initialized = 1; -} - -struct crb_128M_2M_block_map crb_128M_2M_map[64] = { - {{{0, 0, 0, 0} } }, - {{{1, 0x0100000, 0x0102000, 0x120000}, - {1, 0x0110000, 0x0120000, 0x130000}, - {1, 0x0120000, 0x0122000, 0x124000}, - {1, 0x0130000, 0x0132000, 0x126000}, - {1, 0x0140000, 0x0142000, 0x128000}, - {1, 0x0150000, 0x0152000, 0x12a000}, - {1, 0x0160000, 0x0170000, 0x110000}, - {1, 0x0170000, 0x0172000, 0x12e000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x01e0000, 0x01e0800, 0x122000}, - {0, 0x0000000, 0x0000000, 0x000000} } } , - {{{1, 0x0200000, 0x0210000, 0x180000} } }, - {{{0, 0, 0, 0} } }, - {{{1, 0x0400000, 0x0401000, 0x169000} } }, - {{{1, 0x0500000, 0x0510000, 0x140000} } }, - {{{1, 0x0600000, 0x0610000, 0x1c0000} } }, - {{{1, 0x0700000, 0x0704000, 0x1b8000} } }, - {{{1, 0x0800000, 0x0802000, 0x170000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x08f0000, 0x08f2000, 0x172000} } }, - {{{1, 0x0900000, 0x0902000, 0x174000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x09f0000, 0x09f2000, 0x176000} } }, - {{{0, 0x0a00000, 0x0a02000, 0x178000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x0af0000, 0x0af2000, 0x17a000} } }, - {{{0, 0x0b00000, 0x0b02000, 0x17c000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x0bf0000, 0x0bf2000, 0x17e000} } }, - {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } }, - {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } }, - {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } }, - {{{1, 0x0f00000, 0x0f01000, 0x164000} } }, - {{{0, 0x1000000, 0x1004000, 0x1a8000} } }, - {{{1, 0x1100000, 0x1101000, 0x160000} } }, - {{{1, 0x1200000, 0x1201000, 0x161000} } }, - {{{1, 0x1300000, 0x1301000, 0x162000} } }, - {{{1, 0x1400000, 0x1401000, 0x163000} } }, - {{{1, 0x1500000, 0x1501000, 0x165000} } }, - {{{1, 0x1600000, 0x1601000, 0x166000} } }, - {{{0, 0, 0, 0} } }, - {{{0, 0, 0, 0} } }, - {{{0, 0, 0, 0} } }, - {{{0, 0, 0, 0} } }, - {{{0, 0, 0, 0} } }, - {{{0, 0, 0, 0} } }, - {{{1, 0x1d00000, 0x1d10000, 0x190000} } }, - {{{1, 0x1e00000, 0x1e01000, 0x16a000} } }, - {{{1, 0x1f00000, 0x1f10000, 0x150000} } }, - {{{0} } }, - {{{1, 0x2100000, 0x2102000, 0x120000}, - {1, 0x2110000, 0x2120000, 0x130000}, - {1, 0x2120000, 0x2122000, 0x124000}, - {1, 0x2130000, 0x2132000, 0x126000}, - {1, 0x2140000, 0x2142000, 0x128000}, - {1, 0x2150000, 0x2152000, 0x12a000}, - {1, 0x2160000, 0x2170000, 0x110000}, - {1, 0x2170000, 0x2172000, 0x12e000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000} } }, - {{{1, 0x2200000, 0x2204000, 0x1b0000} } }, - {{{0} } }, - {{{0} } }, - {{{0} } }, - {{{0} } }, - {{{0} } }, - {{{1, 0x2800000, 0x2804000, 0x1a4000} } }, - {{{1, 0x2900000, 0x2901000, 0x16b000} } }, - {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } }, - {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } }, - {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } }, - {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } }, - {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } }, - {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } }, - {{{1, 0x3000000, 0x3000400, 0x1adc00} } }, - {{{0, 0x3100000, 0x3104000, 0x1a8000} } }, - {{{1, 0x3200000, 0x3204000, 0x1d4000} } }, - {{{1, 0x3300000, 0x3304000, 0x1a0000} } }, - {{{0} } }, - {{{1, 0x3500000, 0x3500400, 0x1ac000} } }, - {{{1, 0x3600000, 0x3600400, 0x1ae000} } }, - {{{1, 0x3700000, 0x3700400, 0x1ae400} } }, - {{{1, 0x3800000, 0x3804000, 0x1d0000} } }, - {{{1, 0x3900000, 0x3904000, 0x1b4000} } }, - {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } }, - {{{0} } }, - {{{0} } }, - {{{1, 0x3d00000, 0x3d04000, 0x1dc000} } }, - {{{1, 0x3e00000, 0x3e01000, 0x167000} } }, - {{{1, 0x3f00000, 0x3f01000, 0x168000} } } -}; - -/* - * top 12 bits of crb internal address (hub, agent) - */ -unsigned qla82xx_crb_hub_agt[64] = { - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PS, - QLA82XX_HW_CRB_HUB_AGT_ADR_MN, - QLA82XX_HW_CRB_HUB_AGT_ADR_MS, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_SRE, - QLA82XX_HW_CRB_HUB_AGT_ADR_NIU, - QLA82XX_HW_CRB_HUB_AGT_ADR_QMN, - QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0, - QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1, - QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2, - QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3, - QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q, - QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR, - QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4, - QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGND, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI, - QLA82XX_HW_CRB_HUB_AGT_ADR_SN, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_EG, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PS, - QLA82XX_HW_CRB_HUB_AGT_ADR_CAM, - 0, - 0, - 0, - 0, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7, - QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA, - QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q, - QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9, - QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_SMB, - QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0, - QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC, - 0, -}; - -/* Device states */ -char *q_dev_state[] = { - "Unknown", - "Cold", - "Initializing", - "Ready", - "Need Reset", - "Need Quiescent", - "Failed", - "Quiescent", -}; - -char *qdev_state(uint32_t dev_state) -{ - return q_dev_state[dev_state]; -} - -/* - * In: 'off' is offset from CRB space in 128M pci map - * Out: 'off' is 2M pci map addr - * side effect: lock crb window - */ -static void -qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off) -{ - u32 win_read; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - ha->crb_win = CRB_HI(*off); - writel(ha->crb_win, - (void *)(CRB_WINDOW_2M + ha->nx_pcibase)); - - /* Read back value to make sure write has gone through before trying - * to use it. - */ - win_read = RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase)); - if (win_read != ha->crb_win) { - ql_dbg(ql_dbg_p3p, vha, 0xb000, - "%s: Written crbwin (0x%x) " - "!= Read crbwin (0x%x), off=0x%lx.\n", - __func__, ha->crb_win, win_read, *off); - } - *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; -} - -static inline unsigned long -qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off) -{ - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - /* See if we are currently pointing to the region we want to use next */ - if ((off >= QLA82XX_CRB_PCIX_HOST) && (off < QLA82XX_CRB_DDR_NET)) { - /* No need to change window. PCIX and PCIEregs are in both - * regs are in both windows. - */ - return off; - } - - if ((off >= QLA82XX_CRB_PCIX_HOST) && (off < QLA82XX_CRB_PCIX_HOST2)) { - /* We are in first CRB window */ - if (ha->curr_window != 0) - WARN_ON(1); - return off; - } - - if ((off > QLA82XX_CRB_PCIX_HOST2) && (off < QLA82XX_CRB_MAX)) { - /* We are in second CRB window */ - off = off - QLA82XX_CRB_PCIX_HOST2 + QLA82XX_CRB_PCIX_HOST; - - if (ha->curr_window != 1) - return off; - - /* We are in the QM or direct access - * register region - do nothing - */ - if ((off >= QLA82XX_PCI_DIRECT_CRB) && - (off < QLA82XX_PCI_CAMQM_MAX)) - return off; - } - /* strange address given */ - ql_dbg(ql_dbg_p3p, vha, 0xb001, - "%s: Warning: unm_nic_pci_set_crbwindow " - "called with an unknown address(%llx).\n", - QLA2XXX_DRIVER_NAME, off); - return off; -} - -static int -qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong *off) -{ - struct crb_128M_2M_sub_block_map *m; - - if (*off >= QLA82XX_CRB_MAX) - return -1; - - if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) { - *off = (*off - QLA82XX_PCI_CAMQM) + - QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase; - return 0; - } - - if (*off < QLA82XX_PCI_CRBSPACE) - return -1; - - *off -= QLA82XX_PCI_CRBSPACE; - - /* Try direct map */ - m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; - - if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { - *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase; - return 0; - } - /* Not in direct map, use crb window */ - return 1; -} - -#define CRB_WIN_LOCK_TIMEOUT 100000000 -static int qla82xx_crb_win_lock(struct qla_hw_data *ha) -{ - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore3 from PCI HW block */ - done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); - if (done == 1) - break; - if (timeout >= CRB_WIN_LOCK_TIMEOUT) - return -1; - timeout++; - } - qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum); - return 0; -} - -int -qla82xx_wr_32(struct qla_hw_data *ha, ulong off, u32 data) -{ - unsigned long flags = 0; - int rv; - - rv = qla82xx_pci_get_crb_addr_2M(ha, &off); - - BUG_ON(rv == -1); - - if (rv == 1) { - write_lock_irqsave(&ha->hw_lock, flags); - qla82xx_crb_win_lock(ha); - qla82xx_pci_set_crbwindow_2M(ha, &off); - } - - writel(data, (void __iomem *)off); - - if (rv == 1) { - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); - write_unlock_irqrestore(&ha->hw_lock, flags); - } - return 0; -} - -int -qla82xx_rd_32(struct qla_hw_data *ha, ulong off) -{ - unsigned long flags = 0; - int rv; - u32 data; - - rv = qla82xx_pci_get_crb_addr_2M(ha, &off); - - BUG_ON(rv == -1); - - if (rv == 1) { - write_lock_irqsave(&ha->hw_lock, flags); - qla82xx_crb_win_lock(ha); - qla82xx_pci_set_crbwindow_2M(ha, &off); - } - data = RD_REG_DWORD((void __iomem *)off); - - if (rv == 1) { - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); - write_unlock_irqrestore(&ha->hw_lock, flags); - } - return data; -} - -#define IDC_LOCK_TIMEOUT 100000000 -int qla82xx_idc_lock(struct qla_hw_data *ha) -{ - int i; - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore5 from PCI HW block */ - done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK)); - if (done == 1) - break; - if (timeout >= IDC_LOCK_TIMEOUT) - return -1; - - timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); - } - } - - return 0; -} - -void qla82xx_idc_unlock(struct qla_hw_data *ha) -{ - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK)); -} - -/* PCI Windowing for DDR regions. */ -#define QLA82XX_ADDR_IN_RANGE(addr, low, high) \ - (((addr) <= (high)) && ((addr) >= (low))) -/* - * check memory access boundary. - * used by test agent. support ddr access only for now - */ -static unsigned long -qla82xx_pci_mem_bound_check(struct qla_hw_data *ha, - unsigned long long addr, int size) -{ - if (!QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, - QLA82XX_ADDR_DDR_NET_MAX) || - !QLA82XX_ADDR_IN_RANGE(addr + size - 1, QLA82XX_ADDR_DDR_NET, - QLA82XX_ADDR_DDR_NET_MAX) || - ((size != 1) && (size != 2) && (size != 4) && (size != 8))) - return 0; - else - return 1; -} - -int qla82xx_pci_set_window_warning_count; - -static unsigned long -qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr) -{ - int window; - u32 win_read; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, - QLA82XX_ADDR_DDR_NET_MAX)) { - /* DDR network side */ - window = MN_WIN(addr); - ha->ddr_mn_window = window; - qla82xx_wr_32(ha, - ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window); - win_read = qla82xx_rd_32(ha, - ha->mn_win_crb | QLA82XX_PCI_CRBSPACE); - if ((win_read << 17) != window) { - ql_dbg(ql_dbg_p3p, vha, 0xb003, - "%s: Written MNwin (0x%x) != Read MNwin (0x%x).\n", - __func__, window, win_read); - } - addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET; - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, - QLA82XX_ADDR_OCM0_MAX)) { - unsigned int temp1; - if ((addr & 0x00ff800) == 0xff800) { - ql_log(ql_log_warn, vha, 0xb004, - "%s: QM access not handled.\n", __func__); - addr = -1UL; - } - window = OCM_WIN(addr); - ha->ddr_mn_window = window; - qla82xx_wr_32(ha, - ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window); - win_read = qla82xx_rd_32(ha, - ha->mn_win_crb | QLA82XX_PCI_CRBSPACE); - temp1 = ((window & 0x1FF) << 7) | - ((window & 0x0FFFE0000) >> 17); - if (win_read != temp1) { - ql_log(ql_log_warn, vha, 0xb005, - "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x).\n", - __func__, temp1, win_read); - } - addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M; - - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, - QLA82XX_P3_ADDR_QDR_NET_MAX)) { - /* QDR network side */ - window = MS_WIN(addr); - ha->qdr_sn_window = window; - qla82xx_wr_32(ha, - ha->ms_win_crb | QLA82XX_PCI_CRBSPACE, window); - win_read = qla82xx_rd_32(ha, - ha->ms_win_crb | QLA82XX_PCI_CRBSPACE); - if (win_read != window) { - ql_log(ql_log_warn, vha, 0xb006, - "%s: Written MSwin (0x%x) != Read MSwin (0x%x).\n", - __func__, window, win_read); - } - addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET; - } else { - /* - * peg gdb frequently accesses memory that doesn't exist, - * this limits the chit chat so debugging isn't slowed down. - */ - if ((qla82xx_pci_set_window_warning_count++ < 8) || - (qla82xx_pci_set_window_warning_count%64 == 0)) { - ql_log(ql_log_warn, vha, 0xb007, - "%s: Warning:%s Unknown address range!.\n", - __func__, QLA2XXX_DRIVER_NAME); - } - addr = -1UL; - } - return addr; -} - -/* check if address is in the same windows as the previous access */ -static int qla82xx_pci_is_same_window(struct qla_hw_data *ha, - unsigned long long addr) -{ - int window; - unsigned long long qdr_max; - - qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX; - - /* DDR network side */ - if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, - QLA82XX_ADDR_DDR_NET_MAX)) - BUG(); - else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, - QLA82XX_ADDR_OCM0_MAX)) - return 1; - else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM1, - QLA82XX_ADDR_OCM1_MAX)) - return 1; - else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, qdr_max)) { - /* QDR network side */ - window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f; - if (ha->qdr_sn_window == window) - return 1; - } - return 0; -} - -static int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha, - u64 off, void *data, int size) -{ - unsigned long flags; - void *addr = NULL; - int ret = 0; - u64 start; - uint8_t *mem_ptr = NULL; - unsigned long mem_base; - unsigned long mem_page; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - write_lock_irqsave(&ha->hw_lock, flags); - - /* - * If attempting to access unknown address or straddle hw windows, - * do not access. - */ - start = qla82xx_pci_set_window(ha, off); - if ((start == -1UL) || - (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) { - write_unlock_irqrestore(&ha->hw_lock, flags); - ql_log(ql_log_fatal, vha, 0xb008, - "%s out of bound pci memory " - "access, offset is 0x%llx.\n", - QLA2XXX_DRIVER_NAME, off); - return -1; - } - - write_unlock_irqrestore(&ha->hw_lock, flags); - mem_base = pci_resource_start(ha->pdev, 0); - mem_page = start & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - * consecutive pages. - */ - if (mem_page != ((start + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) { - *(u8 *)data = 0; - return -1; - } - addr = mem_ptr; - addr += start & (PAGE_SIZE - 1); - write_lock_irqsave(&ha->hw_lock, flags); - - switch (size) { - case 1: - *(u8 *)data = readb(addr); - break; - case 2: - *(u16 *)data = readw(addr); - break; - case 4: - *(u32 *)data = readl(addr); - break; - case 8: - *(u64 *)data = readq(addr); - break; - default: - ret = -1; - break; - } - write_unlock_irqrestore(&ha->hw_lock, flags); - - if (mem_ptr) - iounmap(mem_ptr); - return ret; -} - -static int -qla82xx_pci_mem_write_direct(struct qla_hw_data *ha, - u64 off, void *data, int size) -{ - unsigned long flags; - void *addr = NULL; - int ret = 0; - u64 start; - uint8_t *mem_ptr = NULL; - unsigned long mem_base; - unsigned long mem_page; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - write_lock_irqsave(&ha->hw_lock, flags); - - /* - * If attempting to access unknown address or straddle hw windows, - * do not access. - */ - start = qla82xx_pci_set_window(ha, off); - if ((start == -1UL) || - (qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) { - write_unlock_irqrestore(&ha->hw_lock, flags); - ql_log(ql_log_fatal, vha, 0xb009, - "%s out of bount memory " - "access, offset is 0x%llx.\n", - QLA2XXX_DRIVER_NAME, off); - return -1; - } - - write_unlock_irqrestore(&ha->hw_lock, flags); - mem_base = pci_resource_start(ha->pdev, 0); - mem_page = start & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - * consecutive pages. - */ - if (mem_page != ((start + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) - return -1; - - addr = mem_ptr; - addr += start & (PAGE_SIZE - 1); - write_lock_irqsave(&ha->hw_lock, flags); - - switch (size) { - case 1: - writeb(*(u8 *)data, addr); - break; - case 2: - writew(*(u16 *)data, addr); - break; - case 4: - writel(*(u32 *)data, addr); - break; - case 8: - writeq(*(u64 *)data, addr); - break; - default: - ret = -1; - break; - } - write_unlock_irqrestore(&ha->hw_lock, flags); - if (mem_ptr) - iounmap(mem_ptr); - return ret; -} - -#define MTU_FUDGE_FACTOR 100 -static unsigned long -qla82xx_decode_crb_addr(unsigned long addr) -{ - int i; - unsigned long base_addr, offset, pci_base; - - if (!qla82xx_crb_table_initialized) - qla82xx_crb_addr_transform_setup(); - - pci_base = ADDR_ERROR; - base_addr = addr & 0xfff00000; - offset = addr & 0x000fffff; - - for (i = 0; i < MAX_CRB_XFORM; i++) { - if (crb_addr_xform[i] == base_addr) { - pci_base = i << 20; - break; - } - } - if (pci_base == ADDR_ERROR) - return pci_base; - return pci_base + offset; -} - -static long rom_max_timeout = 100; -static long qla82xx_rom_lock_timeout = 100; - -static int -qla82xx_rom_lock(struct qla_hw_data *ha) -{ - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore2 from PCI HW block */ - done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK)); - if (done == 1) - break; - if (timeout >= qla82xx_rom_lock_timeout) - return -1; - timeout++; - } - qla82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER); - return 0; -} - -static void -qla82xx_rom_unlock(struct qla_hw_data *ha) -{ - qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); -} - -static int -qla82xx_wait_rom_busy(struct qla_hw_data *ha) -{ - long timeout = 0; - long done = 0 ; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - while (done == 0) { - done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS); - done &= 4; - timeout++; - if (timeout >= rom_max_timeout) { - ql_dbg(ql_dbg_p3p, vha, 0xb00a, - "%s: Timeout reached waiting for rom busy.\n", - QLA2XXX_DRIVER_NAME); - return -1; - } - } - return 0; -} - -static int -qla82xx_wait_rom_done(struct qla_hw_data *ha) -{ - long timeout = 0; - long done = 0 ; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - while (done == 0) { - done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS); - done &= 2; - timeout++; - if (timeout >= rom_max_timeout) { - ql_dbg(ql_dbg_p3p, vha, 0xb00b, - "%s: Timeout reached waiting for rom done.\n", - QLA2XXX_DRIVER_NAME); - return -1; - } - } - return 0; -} - -int -qla82xx_md_rw_32(struct qla_hw_data *ha, uint32_t off, u32 data, uint8_t flag) -{ - uint32_t off_value, rval = 0; - - WRT_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase), - (off & 0xFFFF0000)); - - /* Read back value to make sure write has gone through */ - RD_REG_DWORD((void *)(CRB_WINDOW_2M + ha->nx_pcibase)); - off_value = (off & 0x0000FFFF); - - if (flag) - WRT_REG_DWORD((void *) - (off_value + CRB_INDIRECT_2M + ha->nx_pcibase), - data); - else - rval = RD_REG_DWORD((void *) - (off_value + CRB_INDIRECT_2M + ha->nx_pcibase)); - - return rval; -} - -static int -qla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) -{ - /* Dword reads to flash. */ - qla82xx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW, (addr & 0xFFFF0000), 1); - *valp = qla82xx_md_rw_32(ha, MD_DIRECT_ROM_READ_BASE + - (addr & 0x0000FFFF), 0, 0); - - return 0; -} - -static int -qla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp) -{ - int ret, loops = 0; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) { - udelay(100); - schedule(); - loops++; - } - if (loops >= 50000) { - ql_log(ql_log_fatal, vha, 0x00b9, - "Failed to aquire SEM2 lock.\n"); - return -1; - } - ret = qla82xx_do_rom_fast_read(ha, addr, valp); - qla82xx_rom_unlock(ha); - return ret; -} - -static int -qla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val) -{ - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR); - qla82xx_wait_rom_busy(ha); - if (qla82xx_wait_rom_done(ha)) { - ql_log(ql_log_warn, vha, 0xb00c, - "Error waiting for rom done.\n"); - return -1; - } - *val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA); - return 0; -} - -static int -qla82xx_flash_wait_write_finish(struct qla_hw_data *ha) -{ - long timeout = 0; - uint32_t done = 1 ; - uint32_t val; - int ret = 0; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0); - while ((done != 0) && (ret == 0)) { - ret = qla82xx_read_status_reg(ha, &val); - done = val & 1; - timeout++; - udelay(10); - cond_resched(); - if (timeout >= 50000) { - ql_log(ql_log_warn, vha, 0xb00d, - "Timeout reached waiting for write finish.\n"); - return -1; - } - } - return ret; -} - -static int -qla82xx_flash_set_write_enable(struct qla_hw_data *ha) -{ - uint32_t val; - qla82xx_wait_rom_busy(ha); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WREN); - qla82xx_wait_rom_busy(ha); - if (qla82xx_wait_rom_done(ha)) - return -1; - if (qla82xx_read_status_reg(ha, &val) != 0) - return -1; - if ((val & 2) != 2) - return -1; - return 0; -} - -static int -qla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val) -{ - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - if (qla82xx_flash_set_write_enable(ha)) - return -1; - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0x1); - if (qla82xx_wait_rom_done(ha)) { - ql_log(ql_log_warn, vha, 0xb00e, - "Error waiting for rom done.\n"); - return -1; - } - return qla82xx_flash_wait_write_finish(ha); -} - -static int -qla82xx_write_disable_flash(struct qla_hw_data *ha) -{ - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI); - if (qla82xx_wait_rom_done(ha)) { - ql_log(ql_log_warn, vha, 0xb00f, - "Error waiting for rom done.\n"); - return -1; - } - return 0; -} - -static int -ql82xx_rom_lock_d(struct qla_hw_data *ha) -{ - int loops = 0; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) { - udelay(100); - cond_resched(); - loops++; - } - if (loops >= 50000) { - ql_log(ql_log_warn, vha, 0xb010, - "ROM lock failed.\n"); - return -1; - } - return 0; -} - -static int -qla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr, - uint32_t data) -{ - int ret = 0; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - ret = ql82xx_rom_lock_d(ha); - if (ret < 0) { - ql_log(ql_log_warn, vha, 0xb011, - "ROM lock failed.\n"); - return ret; - } - - if (qla82xx_flash_set_write_enable(ha)) - goto done_write; - - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, data); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, flashaddr); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_PP); - qla82xx_wait_rom_busy(ha); - if (qla82xx_wait_rom_done(ha)) { - ql_log(ql_log_warn, vha, 0xb012, - "Error waiting for rom done.\n"); - ret = -1; - goto done_write; - } - - ret = qla82xx_flash_wait_write_finish(ha); - -done_write: - qla82xx_rom_unlock(ha); - return ret; -} - -/* This routine does CRB initialize sequence - * to put the ISP into operational state - */ -static int -qla82xx_pinit_from_rom(scsi_qla_host_t *vha) -{ - int addr, val; - int i ; - struct crb_addr_pair *buf; - unsigned long off; - unsigned offset, n; - struct qla_hw_data *ha = vha->hw; - - struct crb_addr_pair { - long addr; - long data; - }; - - /* Halt all the indiviual PEGs and other blocks of the ISP */ - qla82xx_rom_lock(ha); - - /* disable all I2Q */ - qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x10, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x14, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x18, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x1c, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x20, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x24, 0x0); - - /* disable all niu interrupts */ - qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff); - /* disable xge rx/tx */ - qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00); - /* disable xg1 rx/tx */ - qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00); - /* disable sideband mac */ - qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x90000, 0x00); - /* disable ap0 mac */ - qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xa0000, 0x00); - /* disable ap1 mac */ - qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xb0000, 0x00); - - /* halt sre */ - val = qla82xx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000); - qla82xx_wr_32(ha, QLA82XX_CRB_SRE + 0x1000, val & (~(0x1))); - - /* halt epg */ - qla82xx_wr_32(ha, QLA82XX_CRB_EPG + 0x1300, 0x1); - - /* halt timers */ - qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x0, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x8, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0); - qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x200, 0x0); - - /* halt pegs */ - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c, 1); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1); - msleep(20); - - /* big hammer */ - if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) - /* don't reset CAM block on reset */ - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff); - else - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff); - qla82xx_rom_unlock(ha); - - /* Read the signature value from the flash. - * Offset 0: Contain signature (0xcafecafe) - * Offset 4: Offset and number of addr/value pairs - * that present in CRB initialize sequence - */ - if (qla82xx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL || - qla82xx_rom_fast_read(ha, 4, &n) != 0) { - ql_log(ql_log_fatal, vha, 0x006e, - "Error Reading crb_init area: n: %08x.\n", n); - return -1; - } - - /* Offset in flash = lower 16 bits - * Number of enteries = upper 16 bits - */ - offset = n & 0xffffU; - n = (n >> 16) & 0xffffU; - - /* number of addr/value pair should not exceed 1024 enteries */ - if (n >= 1024) { - ql_log(ql_log_fatal, vha, 0x0071, - "Card flash not initialized:n=0x%x.\n", n); - return -1; - } - - ql_log(ql_log_info, vha, 0x0072, - "%d CRB init values found in ROM.\n", n); - - buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL); - if (buf == NULL) { - ql_log(ql_log_fatal, vha, 0x010c, - "Unable to allocate memory.\n"); - return -1; - } - - for (i = 0; i < n; i++) { - if (qla82xx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 || - qla82xx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) != 0) { - kfree(buf); - return -1; - } - - buf[i].addr = addr; - buf[i].data = val; - } - - for (i = 0; i < n; i++) { - /* Translate internal CRB initialization - * address to PCI bus address - */ - off = qla82xx_decode_crb_addr((unsigned long)buf[i].addr) + - QLA82XX_PCI_CRBSPACE; - /* Not all CRB addr/value pair to be written, - * some of them are skipped - */ - - /* skipping cold reboot MAGIC */ - if (off == QLA82XX_CAM_RAM(0x1fc)) - continue; - - /* do not reset PCI */ - if (off == (ROMUSB_GLB + 0xbc)) - continue; - - /* skip core clock, so that firmware can increase the clock */ - if (off == (ROMUSB_GLB + 0xc8)) - continue; - - /* skip the function enable register */ - if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION)) - continue; - - if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2)) - continue; - - if ((off & 0x0ff00000) == QLA82XX_CRB_SMB) - continue; - - if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET) - continue; - - if (off == ADDR_ERROR) { - ql_log(ql_log_fatal, vha, 0x0116, - "Unknow addr: 0x%08lx.\n", buf[i].addr); - continue; - } - - qla82xx_wr_32(ha, off, buf[i].data); - - /* ISP requires much bigger delay to settle down, - * else crb_window returns 0xffffffff - */ - if (off == QLA82XX_ROMUSB_GLB_SW_RESET) - msleep(1000); - - /* ISP requires millisec delay between - * successive CRB register updation - */ - msleep(1); - } - - kfree(buf); - - /* Resetting the data and instruction cache */ - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8); - - /* Clear all protocol processing engines */ - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0); - return 0; -} - -static int -qla82xx_pci_mem_write_2M(struct qla_hw_data *ha, - u64 off, void *data, int size) -{ - int i, j, ret = 0, loop, sz[2], off0; - int scale, shift_amount, startword; - uint32_t temp; - uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; - - /* - * If not MN, go check for MS or invalid. - */ - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) - mem_crb = QLA82XX_CRB_QDR_NET; - else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) - return qla82xx_pci_mem_write_direct(ha, - off, data, size); - } - - off0 = off & 0x7; - sz[0] = (size < (8 - off0)) ? size : (8 - off0); - sz[1] = size - sz[0]; - - off8 = off & 0xfffffff0; - loop = (((off & 0xf) + size - 1) >> 4) + 1; - shift_amount = 4; - scale = 2; - startword = (off & 0xf)/8; - - for (i = 0; i < loop; i++) { - if (qla82xx_pci_mem_read_2M(ha, off8 + - (i << shift_amount), &word[i * scale], 8)) - return -1; - } - - switch (size) { - case 1: - tmpw = *((uint8_t *)data); - break; - case 2: - tmpw = *((uint16_t *)data); - break; - case 4: - tmpw = *((uint32_t *)data); - break; - case 8: - default: - tmpw = *((uint64_t *)data); - break; - } - - if (sz[0] == 8) { - word[startword] = tmpw; - } else { - word[startword] &= - ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); - word[startword] |= tmpw << (off0 * 8); - } - if (sz[1] != 0) { - word[startword+1] &= ~(~0ULL << (sz[1] * 8)); - word[startword+1] |= tmpw >> (sz[0] * 8); - } - - for (i = 0; i < loop; i++) { - temp = off8 + (i << shift_amount); - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); - temp = word[i * scale] & 0xffffffff; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); - temp = (word[i * scale] >> 32) & 0xffffffff; - qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); - temp = word[i*scale + 1] & 0xffffffff; - qla82xx_wr_32(ha, mem_crb + - MIU_TEST_AGT_WRDATA_UPPER_LO, temp); - temp = (word[i*scale + 1] >> 32) & 0xffffffff; - qla82xx_wr_32(ha, mem_crb + - MIU_TEST_AGT_WRDATA_UPPER_HI, temp); - - temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - if (printk_ratelimit()) - dev_err(&ha->pdev->dev, - "failed to write through agent.\n"); - ret = -1; - break; - } - } - - return ret; -} - -static int -qla82xx_fw_load_from_flash(struct qla_hw_data *ha) -{ - int i; - long size = 0; - long flashaddr = ha->flt_region_bootload << 2; - long memaddr = BOOTLD_START; - u64 data; - u32 high, low; - size = (IMAGE_START - BOOTLD_START) / 8; - - for (i = 0; i < size; i++) { - if ((qla82xx_rom_fast_read(ha, flashaddr, (int *)&low)) || - (qla82xx_rom_fast_read(ha, flashaddr + 4, (int *)&high))) { - return -1; - } - data = ((u64)high << 32) | low ; - qla82xx_pci_mem_write_2M(ha, memaddr, &data, 8); - flashaddr += 8; - memaddr += 8; - - if (i % 0x1000 == 0) - msleep(1); - } - udelay(100); - read_lock(&ha->hw_lock); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); - read_unlock(&ha->hw_lock); - return 0; -} - -int -qla82xx_pci_mem_read_2M(struct qla_hw_data *ha, - u64 off, void *data, int size) -{ - int i, j = 0, k, start, end, loop, sz[2], off0[2]; - int shift_amount; - uint32_t temp; - uint64_t off8, val, mem_crb, word[2] = {0, 0}; - - /* - * If not MN, go check for MS or invalid. - */ - - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) - mem_crb = QLA82XX_CRB_QDR_NET; - else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla82xx_pci_mem_bound_check(ha, off, size) == 0) - return qla82xx_pci_mem_read_direct(ha, - off, data, size); - } - - off8 = off & 0xfffffff0; - off0[0] = off & 0xf; - sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]); - shift_amount = 4; - loop = ((off0[0] + size - 1) >> shift_amount) + 1; - off0[1] = 0; - sz[1] = size - sz[0]; - - for (i = 0; i < loop; i++) { - temp = off8 + (i << shift_amount); - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); - temp = MIU_TA_CTL_ENABLE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - if (printk_ratelimit()) - dev_err(&ha->pdev->dev, - "failed to read through agent.\n"); - break; - } - - start = off0[i] >> 2; - end = (off0[i] + sz[i] - 1) >> 2; - for (k = start; k <= end; k++) { - temp = qla82xx_rd_32(ha, - mem_crb + MIU_TEST_AGT_RDDATA(k)); - word[i] |= ((uint64_t)temp << (32 * (k & 1))); - } - } - - if (j >= MAX_CTL_CHECK) - return -1; - - if ((off0[0] & 7) == 0) { - val = word[0]; - } else { - val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) | - ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8)); - } - - switch (size) { - case 1: - *(uint8_t *)data = val; - break; - case 2: - *(uint16_t *)data = val; - break; - case 4: - *(uint32_t *)data = val; - break; - case 8: - *(uint64_t *)data = val; - break; - } - return 0; -} - - -static struct qla82xx_uri_table_desc * -qla82xx_get_table_desc(const u8 *unirom, int section) -{ - uint32_t i; - struct qla82xx_uri_table_desc *directory = - (struct qla82xx_uri_table_desc *)&unirom[0]; - __le32 offset; - __le32 tab_type; - __le32 entries = cpu_to_le32(directory->num_entries); - - for (i = 0; i < entries; i++) { - offset = cpu_to_le32(directory->findex) + - (i * cpu_to_le32(directory->entry_size)); - tab_type = cpu_to_le32(*((u32 *)&unirom[offset] + 8)); - - if (tab_type == section) - return (struct qla82xx_uri_table_desc *)&unirom[offset]; - } - - return NULL; -} - -static struct qla82xx_uri_data_desc * -qla82xx_get_data_desc(struct qla_hw_data *ha, - u32 section, u32 idx_offset) -{ - const u8 *unirom = ha->hablob->fw->data; - int idx = cpu_to_le32(*((int *)&unirom[ha->file_prd_off] + idx_offset)); - struct qla82xx_uri_table_desc *tab_desc = NULL; - __le32 offset; - - tab_desc = qla82xx_get_table_desc(unirom, section); - if (!tab_desc) - return NULL; - - offset = cpu_to_le32(tab_desc->findex) + - (cpu_to_le32(tab_desc->entry_size) * idx); - - return (struct qla82xx_uri_data_desc *)&unirom[offset]; -} - -static u8 * -qla82xx_get_bootld_offset(struct qla_hw_data *ha) -{ - u32 offset = BOOTLD_START; - struct qla82xx_uri_data_desc *uri_desc = NULL; - - if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { - uri_desc = qla82xx_get_data_desc(ha, - QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF); - if (uri_desc) - offset = cpu_to_le32(uri_desc->findex); - } - - return (u8 *)&ha->hablob->fw->data[offset]; -} - -static __le32 -qla82xx_get_fw_size(struct qla_hw_data *ha) -{ - struct qla82xx_uri_data_desc *uri_desc = NULL; - - if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { - uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW, - QLA82XX_URI_FIRMWARE_IDX_OFF); - if (uri_desc) - return cpu_to_le32(uri_desc->size); - } - - return cpu_to_le32(*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET]); -} - -static u8 * -qla82xx_get_fw_offs(struct qla_hw_data *ha) -{ - u32 offset = IMAGE_START; - struct qla82xx_uri_data_desc *uri_desc = NULL; - - if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) { - uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW, - QLA82XX_URI_FIRMWARE_IDX_OFF); - if (uri_desc) - offset = cpu_to_le32(uri_desc->findex); - } - - return (u8 *)&ha->hablob->fw->data[offset]; -} - -/* PCI related functions */ -char * -qla82xx_pci_info_str(struct scsi_qla_host *vha, char *str) -{ - int pcie_reg; - struct qla_hw_data *ha = vha->hw; - char lwstr[6]; - uint16_t lnk; - - pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); - pci_read_config_word(ha->pdev, pcie_reg + PCI_EXP_LNKSTA, &lnk); - ha->link_width = (lnk >> 4) & 0x3f; - - strcpy(str, "PCIe ("); - strcat(str, "2.5Gb/s "); - snprintf(lwstr, sizeof(lwstr), "x%d)", ha->link_width); - strcat(str, lwstr); - return str; -} - -int qla82xx_pci_region_offset(struct pci_dev *pdev, int region) -{ - unsigned long val = 0; - u32 control; - - switch (region) { - case 0: - val = 0; - break; - case 1: - pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control); - val = control + QLA82XX_MSIX_TBL_SPACE; - break; - } - return val; -} - - -int -qla82xx_iospace_config(struct qla_hw_data *ha) -{ - uint32_t len = 0; - - if (pci_request_regions(ha->pdev, QLA2XXX_DRIVER_NAME)) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x000c, - "Failed to reserver selected regions.\n"); - goto iospace_error_exit; - } - - /* Use MMIO operations for all accesses. */ - if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x000d, - "Region #0 not an MMIO resource, aborting.\n"); - goto iospace_error_exit; - } - - len = pci_resource_len(ha->pdev, 0); - ha->nx_pcibase = - (unsigned long)ioremap(pci_resource_start(ha->pdev, 0), len); - if (!ha->nx_pcibase) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x000e, - "Cannot remap pcibase MMIO, aborting.\n"); - pci_release_regions(ha->pdev); - goto iospace_error_exit; - } - - /* Mapping of IO base pointer */ - ha->iobase = (device_reg_t __iomem *)((uint8_t *)ha->nx_pcibase + - 0xbc000 + (ha->pdev->devfn << 11)); - - if (!ql2xdbwr) { - ha->nxdb_wr_ptr = - (unsigned long)ioremap((pci_resource_start(ha->pdev, 4) + - (ha->pdev->devfn << 12)), 4); - if (!ha->nxdb_wr_ptr) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x000f, - "Cannot remap MMIO, aborting.\n"); - pci_release_regions(ha->pdev); - goto iospace_error_exit; - } - - /* Mapping of IO base pointer, - * door bell read and write pointer - */ - ha->nxdb_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) + - (ha->pdev->devfn * 8); - } else { - ha->nxdb_wr_ptr = (ha->pdev->devfn == 6 ? - QLA82XX_CAMRAM_DB1 : - QLA82XX_CAMRAM_DB2); - } - - ha->max_req_queues = ha->max_rsp_queues = 1; - ha->msix_count = ha->max_rsp_queues + 1; - ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc006, - "nx_pci_base=%p iobase=%p " - "max_req_queues=%d msix_count=%d.\n", - (void *)ha->nx_pcibase, ha->iobase, - ha->max_req_queues, ha->msix_count); - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0010, - "nx_pci_base=%p iobase=%p " - "max_req_queues=%d msix_count=%d.\n", - (void *)ha->nx_pcibase, ha->iobase, - ha->max_req_queues, ha->msix_count); - return 0; - -iospace_error_exit: - return -ENOMEM; -} - -/* GS related functions */ - -/* Initialization related functions */ - -/** - * qla82xx_pci_config() - Setup ISP82xx PCI configuration registers. - * @ha: HA context - * - * Returns 0 on success. -*/ -int -qla82xx_pci_config(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - int ret; - - pci_set_master(ha->pdev); - ret = pci_set_mwi(ha->pdev); - ha->chip_revision = ha->pdev->revision; - ql_dbg(ql_dbg_init, vha, 0x0043, - "Chip revision:%d.\n", - ha->chip_revision); - return 0; -} - -/** - * qla82xx_reset_chip() - Setup ISP82xx PCI configuration registers. - * @ha: HA context - * - * Returns 0 on success. - */ -void -qla82xx_reset_chip(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - ha->isp_ops->disable_intrs(ha); -} - -void qla82xx_config_rings(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; - struct init_cb_81xx *icb; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; - - /* Setup ring parameters in initialization control block. */ - icb = (struct init_cb_81xx *)ha->init_cb; - icb->request_q_outpointer = __constant_cpu_to_le16(0); - icb->response_q_inpointer = __constant_cpu_to_le16(0); - icb->request_q_length = cpu_to_le16(req->length); - icb->response_q_length = cpu_to_le16(rsp->length); - icb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); - icb->request_q_address[1] = cpu_to_le32(MSD(req->dma)); - icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); - icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); - - WRT_REG_DWORD((unsigned long __iomem *)®->req_q_out[0], 0); - WRT_REG_DWORD((unsigned long __iomem *)®->rsp_q_in[0], 0); - WRT_REG_DWORD((unsigned long __iomem *)®->rsp_q_out[0], 0); -} - -void qla82xx_reset_adapter(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - vha->flags.online = 0; - qla2x00_try_to_stop_firmware(vha); - ha->isp_ops->disable_intrs(ha); -} - -static int -qla82xx_fw_load_from_blob(struct qla_hw_data *ha) -{ - u64 *ptr64; - u32 i, flashaddr, size; - __le64 data; - - size = (IMAGE_START - BOOTLD_START) / 8; - - ptr64 = (u64 *)qla82xx_get_bootld_offset(ha); - flashaddr = BOOTLD_START; - - for (i = 0; i < size; i++) { - data = cpu_to_le64(ptr64[i]); - if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8)) - return -EIO; - flashaddr += 8; - } - - flashaddr = FLASH_ADDR_START; - size = (__force u32)qla82xx_get_fw_size(ha) / 8; - ptr64 = (u64 *)qla82xx_get_fw_offs(ha); - - for (i = 0; i < size; i++) { - data = cpu_to_le64(ptr64[i]); - - if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8)) - return -EIO; - flashaddr += 8; - } - udelay(100); - - /* Write a magic value to CAMRAM register - * at a specified offset to indicate - * that all data is written and - * ready for firmware to initialize. - */ - qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC); - - read_lock(&ha->hw_lock); - qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); - read_unlock(&ha->hw_lock); - return 0; -} - -static int -qla82xx_set_product_offset(struct qla_hw_data *ha) -{ - struct qla82xx_uri_table_desc *ptab_desc = NULL; - const uint8_t *unirom = ha->hablob->fw->data; - uint32_t i; - __le32 entries; - __le32 flags, file_chiprev, offset; - uint8_t chiprev = ha->chip_revision; - /* Hardcoding mn_present flag for P3P */ - int mn_present = 0; - uint32_t flagbit; - - ptab_desc = qla82xx_get_table_desc(unirom, - QLA82XX_URI_DIR_SECT_PRODUCT_TBL); - if (!ptab_desc) - return -1; - - entries = cpu_to_le32(ptab_desc->num_entries); - - for (i = 0; i < entries; i++) { - offset = cpu_to_le32(ptab_desc->findex) + - (i * cpu_to_le32(ptab_desc->entry_size)); - flags = cpu_to_le32(*((int *)&unirom[offset] + - QLA82XX_URI_FLAGS_OFF)); - file_chiprev = cpu_to_le32(*((int *)&unirom[offset] + - QLA82XX_URI_CHIP_REV_OFF)); - - flagbit = mn_present ? 1 : 2; - - if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) { - ha->file_prd_off = offset; - return 0; - } - } - return -1; -} - -int -qla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type) -{ - __le32 val; - uint32_t min_size; - struct qla_hw_data *ha = vha->hw; - const struct firmware *fw = ha->hablob->fw; - - ha->fw_type = fw_type; - - if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) { - if (qla82xx_set_product_offset(ha)) - return -EINVAL; - - min_size = QLA82XX_URI_FW_MIN_SIZE; - } else { - val = cpu_to_le32(*(u32 *)&fw->data[QLA82XX_FW_MAGIC_OFFSET]); - if ((__force u32)val != QLA82XX_BDINFO_MAGIC) - return -EINVAL; - - min_size = QLA82XX_FW_MIN_SIZE; - } - - if (fw->size < min_size) - return -EINVAL; - return 0; -} - -static int -qla82xx_check_cmdpeg_state(struct qla_hw_data *ha) -{ - u32 val = 0; - int retries = 60; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - do { - read_lock(&ha->hw_lock); - val = qla82xx_rd_32(ha, CRB_CMDPEG_STATE); - read_unlock(&ha->hw_lock); - - switch (val) { - case PHAN_INITIALIZE_COMPLETE: - case PHAN_INITIALIZE_ACK: - return QLA_SUCCESS; - case PHAN_INITIALIZE_FAILED: - break; - default: - break; - } - ql_log(ql_log_info, vha, 0x00a8, - "CRB_CMDPEG_STATE: 0x%x and retries:0x%x.\n", - val, retries); - - msleep(500); - - } while (--retries); - - ql_log(ql_log_fatal, vha, 0x00a9, - "Cmd Peg initialization failed: 0x%x.\n", val); - - val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_PEGTUNE_DONE); - read_lock(&ha->hw_lock); - qla82xx_wr_32(ha, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED); - read_unlock(&ha->hw_lock); - return QLA_FUNCTION_FAILED; -} - -static int -qla82xx_check_rcvpeg_state(struct qla_hw_data *ha) -{ - u32 val = 0; - int retries = 60; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - do { - read_lock(&ha->hw_lock); - val = qla82xx_rd_32(ha, CRB_RCVPEG_STATE); - read_unlock(&ha->hw_lock); - - switch (val) { - case PHAN_INITIALIZE_COMPLETE: - case PHAN_INITIALIZE_ACK: - return QLA_SUCCESS; - case PHAN_INITIALIZE_FAILED: - break; - default: - break; - } - ql_log(ql_log_info, vha, 0x00ab, - "CRB_RCVPEG_STATE: 0x%x and retries: 0x%x.\n", - val, retries); - - msleep(500); - - } while (--retries); - - ql_log(ql_log_fatal, vha, 0x00ac, - "Rcv Peg initializatin failed: 0x%x.\n", val); - read_lock(&ha->hw_lock); - qla82xx_wr_32(ha, CRB_RCVPEG_STATE, PHAN_INITIALIZE_FAILED); - read_unlock(&ha->hw_lock); - return QLA_FUNCTION_FAILED; -} - -/* ISR related functions */ -uint32_t qla82xx_isr_int_target_mask_enable[8] = { - ISR_INT_TARGET_MASK, ISR_INT_TARGET_MASK_F1, - ISR_INT_TARGET_MASK_F2, ISR_INT_TARGET_MASK_F3, - ISR_INT_TARGET_MASK_F4, ISR_INT_TARGET_MASK_F5, - ISR_INT_TARGET_MASK_F7, ISR_INT_TARGET_MASK_F7 -}; - -uint32_t qla82xx_isr_int_target_status[8] = { - ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1, - ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3, - ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5, - ISR_INT_TARGET_STATUS_F7, ISR_INT_TARGET_STATUS_F7 -}; - -static struct qla82xx_legacy_intr_set legacy_intr[] = \ - QLA82XX_LEGACY_INTR_CONFIG; - -/* - * qla82xx_mbx_completion() - Process mailbox command completions. - * @ha: SCSI driver HA context - * @mb0: Mailbox0 register - */ -static void -qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) -{ - uint16_t cnt; - uint16_t __iomem *wptr; - struct qla_hw_data *ha = vha->hw; - struct device_reg_82xx __iomem *reg = &ha->iobase->isp82; - wptr = (uint16_t __iomem *)®->mailbox_out[1]; - - /* Load return mailbox registers. */ - ha->flags.mbox_int = 1; - ha->mailbox_out[0] = mb0; - - for (cnt = 1; cnt < ha->mbx_count; cnt++) { - ha->mailbox_out[cnt] = RD_REG_WORD(wptr); - wptr++; - } - - if (!ha->mcp) - ql_dbg(ql_dbg_async, vha, 0x5053, - "MBX pointer ERROR.\n"); -} - -/* - * qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. - * @irq: - * @dev_id: SCSI driver HA context - * @regs: - * - * Called by system whenever the host adapter generates an interrupt. - * - * Returns handled flag. - */ -irqreturn_t -qla82xx_intr_handler(int irq, void *dev_id) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct rsp_que *rsp; - struct device_reg_82xx __iomem *reg; - int status = 0, status1 = 0; - unsigned long flags; - unsigned long iter; - uint32_t stat = 0; - uint16_t mb[4]; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - ql_log(ql_log_info, NULL, 0xb054, - "%s: NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - ha = rsp->hw; - - if (!ha->flags.msi_enabled) { - status = qla82xx_rd_32(ha, ISR_INT_VECTOR); - if (!(status & ha->nx_legacy_intr.int_vec_bit)) - return IRQ_NONE; - - status1 = qla82xx_rd_32(ha, ISR_INT_STATE_REG); - if (!ISR_IS_LEGACY_INTR_TRIGGERED(status1)) - return IRQ_NONE; - } - - /* clear the interrupt */ - qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff); - - /* read twice to ensure write is flushed */ - qla82xx_rd_32(ha, ISR_INT_VECTOR); - qla82xx_rd_32(ha, ISR_INT_VECTOR); - - reg = &ha->iobase->isp82; - - spin_lock_irqsave(&ha->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - for (iter = 1; iter--; ) { - - if (RD_REG_DWORD(®->host_int)) { - stat = RD_REG_DWORD(®->host_status); - - switch (stat & 0xff) { - case 0x1: - case 0x2: - case 0x10: - case 0x11: - qla82xx_mbx_completion(vha, MSW(stat)); - status |= MBX_INTERRUPT; - break; - case 0x12: - mb[0] = MSW(stat); - mb[1] = RD_REG_WORD(®->mailbox_out[1]); - mb[2] = RD_REG_WORD(®->mailbox_out[2]); - mb[3] = RD_REG_WORD(®->mailbox_out[3]); - qla2x00_async_event(vha, rsp, mb); - break; - case 0x13: - qla24xx_process_response_queue(vha, rsp); - break; - default: - ql_dbg(ql_dbg_async, vha, 0x5054, - "Unrecognized interrupt type (%d).\n", - stat & 0xff); - break; - } - } - WRT_REG_DWORD(®->host_int, 0); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (!ha->flags.msi_enabled) - qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); - -#ifdef QL_DEBUG_LEVEL_17 - if (!irq && ha->flags.eeh_busy) - ql_log(ql_log_warn, vha, 0x503d, - "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n", - status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat); -#endif - - if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && - (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - complete(&ha->mbx_intr_comp); - } - return IRQ_HANDLED; -} - -irqreturn_t -qla82xx_msix_default(int irq, void *dev_id) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct rsp_que *rsp; - struct device_reg_82xx __iomem *reg; - int status = 0; - unsigned long flags; - uint32_t stat = 0; - uint16_t mb[4]; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - printk(KERN_INFO - "%s(): NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - ha = rsp->hw; - - reg = &ha->iobase->isp82; - - spin_lock_irqsave(&ha->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - do { - if (RD_REG_DWORD(®->host_int)) { - stat = RD_REG_DWORD(®->host_status); - - switch (stat & 0xff) { - case 0x1: - case 0x2: - case 0x10: - case 0x11: - qla82xx_mbx_completion(vha, MSW(stat)); - status |= MBX_INTERRUPT; - break; - case 0x12: - mb[0] = MSW(stat); - mb[1] = RD_REG_WORD(®->mailbox_out[1]); - mb[2] = RD_REG_WORD(®->mailbox_out[2]); - mb[3] = RD_REG_WORD(®->mailbox_out[3]); - qla2x00_async_event(vha, rsp, mb); - break; - case 0x13: - qla24xx_process_response_queue(vha, rsp); - break; - default: - ql_dbg(ql_dbg_async, vha, 0x5041, - "Unrecognized interrupt type (%d).\n", - stat & 0xff); - break; - } - } - WRT_REG_DWORD(®->host_int, 0); - } while (0); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - -#ifdef QL_DEBUG_LEVEL_17 - if (!irq && ha->flags.eeh_busy) - ql_log(ql_log_warn, vha, 0x5044, - "isr:status %x, cmd_flags %lx, mbox_int %x, stat %x.\n", - status, ha->mbx_cmd_flags, ha->flags.mbox_int, stat); -#endif - - if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && - (status & MBX_INTERRUPT) && ha->flags.mbox_int) { - set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); - complete(&ha->mbx_intr_comp); - } - return IRQ_HANDLED; -} - -irqreturn_t -qla82xx_msix_rsp_q(int irq, void *dev_id) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct rsp_que *rsp; - struct device_reg_82xx __iomem *reg; - unsigned long flags; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - printk(KERN_INFO - "%s(): NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - - ha = rsp->hw; - reg = &ha->iobase->isp82; - spin_lock_irqsave(&ha->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - qla24xx_process_response_queue(vha, rsp); - WRT_REG_DWORD(®->host_int, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return IRQ_HANDLED; -} - -void -qla82xx_poll(int irq, void *dev_id) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - struct rsp_que *rsp; - struct device_reg_82xx __iomem *reg; - int status = 0; - uint32_t stat; - uint16_t mb[4]; - unsigned long flags; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - printk(KERN_INFO - "%s(): NULL response queue pointer.\n", __func__); - return; - } - ha = rsp->hw; - - reg = &ha->iobase->isp82; - spin_lock_irqsave(&ha->hardware_lock, flags); - vha = pci_get_drvdata(ha->pdev); - - if (RD_REG_DWORD(®->host_int)) { - stat = RD_REG_DWORD(®->host_status); - switch (stat & 0xff) { - case 0x1: - case 0x2: - case 0x10: - case 0x11: - qla82xx_mbx_completion(vha, MSW(stat)); - status |= MBX_INTERRUPT; - break; - case 0x12: - mb[0] = MSW(stat); - mb[1] = RD_REG_WORD(®->mailbox_out[1]); - mb[2] = RD_REG_WORD(®->mailbox_out[2]); - mb[3] = RD_REG_WORD(®->mailbox_out[3]); - qla2x00_async_event(vha, rsp, mb); - break; - case 0x13: - qla24xx_process_response_queue(vha, rsp); - break; - default: - ql_dbg(ql_dbg_p3p, vha, 0xb013, - "Unrecognized interrupt type (%d).\n", - stat * 0xff); - break; - } - } - WRT_REG_DWORD(®->host_int, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void -qla82xx_enable_intrs(struct qla_hw_data *ha) -{ - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - qla82xx_mbx_intr_enable(vha); - spin_lock_irq(&ha->hardware_lock); - qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); - spin_unlock_irq(&ha->hardware_lock); - ha->interrupts_on = 1; -} - -void -qla82xx_disable_intrs(struct qla_hw_data *ha) -{ - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - qla82xx_mbx_intr_disable(vha); - spin_lock_irq(&ha->hardware_lock); - qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400); - spin_unlock_irq(&ha->hardware_lock); - ha->interrupts_on = 0; -} - -void qla82xx_init_flags(struct qla_hw_data *ha) -{ - struct qla82xx_legacy_intr_set *nx_legacy_intr; - - /* ISP 8021 initializations */ - rwlock_init(&ha->hw_lock); - ha->qdr_sn_window = -1; - ha->ddr_mn_window = -1; - ha->curr_window = 255; - ha->portnum = PCI_FUNC(ha->pdev->devfn); - nx_legacy_intr = &legacy_intr[ha->portnum]; - ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; - ha->nx_legacy_intr.tgt_status_reg = nx_legacy_intr->tgt_status_reg; - ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; - ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; -} - -inline void -qla82xx_set_drv_active(scsi_qla_host_t *vha) -{ - uint32_t drv_active; - struct qla_hw_data *ha = vha->hw; - - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - - /* If reset value is all FF's, initialize DRV_ACTIVE */ - if (drv_active == 0xffffffff) { - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, - QLA82XX_DRV_NOT_ACTIVE); - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - } - drv_active |= (QLA82XX_DRV_ACTIVE << (ha->portnum * 4)); - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); -} - -inline void -qla82xx_clear_drv_active(struct qla_hw_data *ha) -{ - uint32_t drv_active; - - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - drv_active &= ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4)); - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); -} - -static inline int -qla82xx_need_reset(struct qla_hw_data *ha) -{ - uint32_t drv_state; - int rval; - - if (ha->flags.isp82xx_reset_owner) - return 1; - else { - drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - rval = drv_state & (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); - return rval; - } -} - -static inline void -qla82xx_set_rst_ready(struct qla_hw_data *ha) -{ - uint32_t drv_state; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - - /* If reset value is all FF's, initialize DRV_STATE */ - if (drv_state == 0xffffffff) { - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, QLA82XX_DRVST_NOT_RDY); - drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - } - drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); - ql_dbg(ql_dbg_init, vha, 0x00bb, - "drv_state = 0x%08x.\n", drv_state); - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); -} - -static inline void -qla82xx_clear_rst_ready(struct qla_hw_data *ha) -{ - uint32_t drv_state; - - drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_state &= ~(QLA82XX_DRVST_RST_RDY << (ha->portnum * 4)); - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); -} - -static inline void -qla82xx_set_qsnt_ready(struct qla_hw_data *ha) -{ - uint32_t qsnt_state; - - qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - qsnt_state |= (QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4)); - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state); -} - -void -qla82xx_clear_qsnt_ready(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t qsnt_state; - - qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - qsnt_state &= ~(QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4)); - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state); -} - -static int -qla82xx_load_fw(scsi_qla_host_t *vha) -{ - int rst; - struct fw_blob *blob; - struct qla_hw_data *ha = vha->hw; - - if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) { - ql_log(ql_log_fatal, vha, 0x009f, - "Error during CRB initialization.\n"); - return QLA_FUNCTION_FAILED; - } - udelay(500); - - /* Bring QM and CAMRAM out of reset */ - rst = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET); - rst &= ~((1 << 28) | (1 << 24)); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst); - - /* - * FW Load priority: - * 1) Operational firmware residing in flash. - * 2) Firmware via request-firmware interface (.bin file). - */ - if (ql2xfwloadbin == 2) - goto try_blob_fw; - - ql_log(ql_log_info, vha, 0x00a0, - "Attempting to load firmware from flash.\n"); - - if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) { - ql_log(ql_log_info, vha, 0x00a1, - "Firmware loaded successully from flash.\n"); - return QLA_SUCCESS; - } else { - ql_log(ql_log_warn, vha, 0x0108, - "Firmware load from flash failed.\n"); - } - -try_blob_fw: - ql_log(ql_log_info, vha, 0x00a2, - "Attempting to load firmware from blob.\n"); - - /* Load firmware blob. */ - blob = ha->hablob = qla2x00_request_firmware(vha); - if (!blob) { - ql_log(ql_log_fatal, vha, 0x00a3, - "Firmware image not preset.\n"); - goto fw_load_failed; - } - - /* Validating firmware blob */ - if (qla82xx_validate_firmware_blob(vha, - QLA82XX_FLASH_ROMIMAGE)) { - /* Fallback to URI format */ - if (qla82xx_validate_firmware_blob(vha, - QLA82XX_UNIFIED_ROMIMAGE)) { - ql_log(ql_log_fatal, vha, 0x00a4, - "No valid firmware image found.\n"); - return QLA_FUNCTION_FAILED; - } - } - - if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) { - ql_log(ql_log_info, vha, 0x00a5, - "Firmware loaded successfully from binary blob.\n"); - return QLA_SUCCESS; - } else { - ql_log(ql_log_fatal, vha, 0x00a6, - "Firmware load failed for binary blob.\n"); - blob->fw = NULL; - blob = NULL; - goto fw_load_failed; - } - return QLA_SUCCESS; - -fw_load_failed: - return QLA_FUNCTION_FAILED; -} - -int -qla82xx_start_firmware(scsi_qla_host_t *vha) -{ - int pcie_cap; - uint16_t lnk; - struct qla_hw_data *ha = vha->hw; - - /* scrub dma mask expansion register */ - qla82xx_wr_32(ha, CRB_DMA_SHIFT, QLA82XX_DMA_SHIFT_VALUE); - - /* Put both the PEG CMD and RCV PEG to default state - * of 0 before resetting the hardware - */ - qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0); - qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0); - - /* Overwrite stale initialization register values */ - qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0); - qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0); - - if (qla82xx_load_fw(vha) != QLA_SUCCESS) { - ql_log(ql_log_fatal, vha, 0x00a7, - "Error trying to start fw.\n"); - return QLA_FUNCTION_FAILED; - } - - /* Handshake with the card before we register the devices. */ - if (qla82xx_check_cmdpeg_state(ha) != QLA_SUCCESS) { - ql_log(ql_log_fatal, vha, 0x00aa, - "Error during card handshake.\n"); - return QLA_FUNCTION_FAILED; - } - - /* Negotiated Link width */ - pcie_cap = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); - pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk); - ha->link_width = (lnk >> 4) & 0x3f; - - /* Synchronize with Receive peg */ - return qla82xx_check_rcvpeg_state(ha); -} - -static uint32_t * -qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, - uint32_t length) -{ - uint32_t i; - uint32_t val; - struct qla_hw_data *ha = vha->hw; - - /* Dword reads to flash. */ - for (i = 0; i < length/4; i++, faddr += 4) { - if (qla82xx_rom_fast_read(ha, faddr, &val)) { - ql_log(ql_log_warn, vha, 0x0106, - "Do ROM fast read failed.\n"); - goto done_read; - } - dwptr[i] = __constant_cpu_to_le32(val); - } -done_read: - return dwptr; -} - -static int -qla82xx_unprotect_flash(struct qla_hw_data *ha) -{ - int ret; - uint32_t val; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - ret = ql82xx_rom_lock_d(ha); - if (ret < 0) { - ql_log(ql_log_warn, vha, 0xb014, - "ROM Lock failed.\n"); - return ret; - } - - ret = qla82xx_read_status_reg(ha, &val); - if (ret < 0) - goto done_unprotect; - - val &= ~(BLOCK_PROTECT_BITS << 2); - ret = qla82xx_write_status_reg(ha, val); - if (ret < 0) { - val |= (BLOCK_PROTECT_BITS << 2); - qla82xx_write_status_reg(ha, val); - } - - if (qla82xx_write_disable_flash(ha) != 0) - ql_log(ql_log_warn, vha, 0xb015, - "Write disable failed.\n"); - -done_unprotect: - qla82xx_rom_unlock(ha); - return ret; -} - -static int -qla82xx_protect_flash(struct qla_hw_data *ha) -{ - int ret; - uint32_t val; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - ret = ql82xx_rom_lock_d(ha); - if (ret < 0) { - ql_log(ql_log_warn, vha, 0xb016, - "ROM Lock failed.\n"); - return ret; - } - - ret = qla82xx_read_status_reg(ha, &val); - if (ret < 0) - goto done_protect; - - val |= (BLOCK_PROTECT_BITS << 2); - /* LOCK all sectors */ - ret = qla82xx_write_status_reg(ha, val); - if (ret < 0) - ql_log(ql_log_warn, vha, 0xb017, - "Write status register failed.\n"); - - if (qla82xx_write_disable_flash(ha) != 0) - ql_log(ql_log_warn, vha, 0xb018, - "Write disable failed.\n"); -done_protect: - qla82xx_rom_unlock(ha); - return ret; -} - -static int -qla82xx_erase_sector(struct qla_hw_data *ha, int addr) -{ - int ret = 0; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - ret = ql82xx_rom_lock_d(ha); - if (ret < 0) { - ql_log(ql_log_warn, vha, 0xb019, - "ROM Lock failed.\n"); - return ret; - } - - qla82xx_flash_set_write_enable(ha); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3); - qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_SE); - - if (qla82xx_wait_rom_done(ha)) { - ql_log(ql_log_warn, vha, 0xb01a, - "Error waiting for rom done.\n"); - ret = -1; - goto done; - } - ret = qla82xx_flash_wait_write_finish(ha); -done: - qla82xx_rom_unlock(ha); - return ret; -} - -/* - * Address and length are byte address - */ -uint8_t * -qla82xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, - uint32_t offset, uint32_t length) -{ - scsi_block_requests(vha->host); - qla82xx_read_flash_data(vha, (uint32_t *)buf, offset, length); - scsi_unblock_requests(vha->host); - return buf; -} - -static int -qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr, - uint32_t faddr, uint32_t dwords) -{ - int ret; - uint32_t liter; - uint32_t sec_mask, rest_addr; - dma_addr_t optrom_dma; - void *optrom = NULL; - int page_mode = 0; - struct qla_hw_data *ha = vha->hw; - - ret = -1; - - /* Prepare burst-capable write on supported ISPs. */ - if (page_mode && !(faddr & 0xfff) && - dwords > OPTROM_BURST_DWORDS) { - optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, - &optrom_dma, GFP_KERNEL); - if (!optrom) { - ql_log(ql_log_warn, vha, 0xb01b, - "Unable to allocate memory " - "for optron burst write (%x KB).\n", - OPTROM_BURST_SIZE / 1024); - } - } - - rest_addr = ha->fdt_block_size - 1; - sec_mask = ~rest_addr; - - ret = qla82xx_unprotect_flash(ha); - if (ret) { - ql_log(ql_log_warn, vha, 0xb01c, - "Unable to unprotect flash for update.\n"); - goto write_done; - } - - for (liter = 0; liter < dwords; liter++, faddr += 4, dwptr++) { - /* Are we at the beginning of a sector? */ - if ((faddr & rest_addr) == 0) { - - ret = qla82xx_erase_sector(ha, faddr); - if (ret) { - ql_log(ql_log_warn, vha, 0xb01d, - "Unable to erase sector: address=%x.\n", - faddr); - break; - } - } - - /* Go with burst-write. */ - if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) { - /* Copy data to DMA'ble buffer. */ - memcpy(optrom, dwptr, OPTROM_BURST_SIZE); - - ret = qla2x00_load_ram(vha, optrom_dma, - (ha->flash_data_off | faddr), - OPTROM_BURST_DWORDS); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0xb01e, - "Unable to burst-write optrom segment " - "(%x/%x/%llx).\n", ret, - (ha->flash_data_off | faddr), - (unsigned long long)optrom_dma); - ql_log(ql_log_warn, vha, 0xb01f, - "Reverting to slow-write.\n"); - - dma_free_coherent(&ha->pdev->dev, - OPTROM_BURST_SIZE, optrom, optrom_dma); - optrom = NULL; - } else { - liter += OPTROM_BURST_DWORDS - 1; - faddr += OPTROM_BURST_DWORDS - 1; - dwptr += OPTROM_BURST_DWORDS - 1; - continue; - } - } - - ret = qla82xx_write_flash_dword(ha, faddr, - cpu_to_le32(*dwptr)); - if (ret) { - ql_dbg(ql_dbg_p3p, vha, 0xb020, - "Unable to program flash address=%x data=%x.\n", - faddr, *dwptr); - break; - } - } - - ret = qla82xx_protect_flash(ha); - if (ret) - ql_log(ql_log_warn, vha, 0xb021, - "Unable to protect flash after update.\n"); -write_done: - if (optrom) - dma_free_coherent(&ha->pdev->dev, - OPTROM_BURST_SIZE, optrom, optrom_dma); - return ret; -} - -int -qla82xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, - uint32_t offset, uint32_t length) -{ - int rval; - - /* Suspend HBA. */ - scsi_block_requests(vha->host); - rval = qla82xx_write_flash_data(vha, (uint32_t *)buf, offset, - length >> 2); - scsi_unblock_requests(vha->host); - - /* Convert return ISP82xx to generic */ - if (rval) - rval = QLA_FUNCTION_FAILED; - else - rval = QLA_SUCCESS; - return rval; -} - -void -qla82xx_start_iocbs(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - struct device_reg_82xx __iomem *reg; - uint32_t dbval; - - /* Adjust ring index. */ - req->ring_index++; - if (req->ring_index == req->length) { - req->ring_index = 0; - req->ring_ptr = req->ring; - } else - req->ring_ptr++; - - reg = &ha->iobase->isp82; - dbval = 0x04 | (ha->portnum << 5); - - dbval = dbval | (req->id << 8) | (req->ring_index << 16); - if (ql2xdbwr) - qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); - else { - WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); - wmb(); - while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { - WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, - dbval); - wmb(); - } - } -} - -void qla82xx_rom_lock_recovery(struct qla_hw_data *ha) -{ - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - if (qla82xx_rom_lock(ha)) - /* Someone else is holding the lock. */ - ql_log(ql_log_info, vha, 0xb022, - "Resetting rom_lock.\n"); - - /* - * Either we got the lock, or someone - * else died while holding it. - * In either case, unlock. - */ - qla82xx_rom_unlock(ha); -} - -/* - * qla82xx_device_bootstrap - * Initialize device, set DEV_READY, start fw - * - * Note: - * IDC lock must be held upon entry - * - * Return: - * Success : 0 - * Failed : 1 - */ -static int -qla82xx_device_bootstrap(scsi_qla_host_t *vha) -{ - int rval = QLA_SUCCESS; - int i, timeout; - uint32_t old_count, count; - struct qla_hw_data *ha = vha->hw; - int need_reset = 0, peg_stuck = 1; - - need_reset = qla82xx_need_reset(ha); - - old_count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); - - for (i = 0; i < 10; i++) { - timeout = msleep_interruptible(200); - if (timeout) { - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - return QLA_FUNCTION_FAILED; - } - - count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); - if (count != old_count) - peg_stuck = 0; - } - - if (need_reset) { - /* We are trying to perform a recovery here. */ - if (peg_stuck) - qla82xx_rom_lock_recovery(ha); - goto dev_initialize; - } else { - /* Start of day for this ha context. */ - if (peg_stuck) { - /* Either we are the first or recovery in progress. */ - qla82xx_rom_lock_recovery(ha); - goto dev_initialize; - } else - /* Firmware already running. */ - goto dev_ready; - } - - return rval; - -dev_initialize: - /* set to DEV_INITIALIZING */ - ql_log(ql_log_info, vha, 0x009e, - "HW State: INITIALIZING.\n"); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING); - - /* Driver that sets device state to initializating sets IDC version */ - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION); - - qla82xx_idc_unlock(ha); - rval = qla82xx_start_firmware(vha); - qla82xx_idc_lock(ha); - - if (rval != QLA_SUCCESS) { - ql_log(ql_log_fatal, vha, 0x00ad, - "HW State: FAILED.\n"); - qla82xx_clear_drv_active(ha); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED); - return rval; - } - -dev_ready: - ql_log(ql_log_info, vha, 0x00ae, - "HW State: READY.\n"); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY); - - return QLA_SUCCESS; -} - -/* -* qla82xx_need_qsnt_handler -* Code to start quiescence sequence -* -* Note: -* IDC lock must be held upon entry -* -* Return: void -*/ - -static void -qla82xx_need_qsnt_handler(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t dev_state, drv_state, drv_active; - unsigned long reset_timeout; - - if (vha->flags.online) { - /*Block any further I/O and wait for pending cmnds to complete*/ - qla82xx_quiescent_state_cleanup(vha); - } - - /* Set the quiescence ready bit */ - qla82xx_set_qsnt_ready(ha); - - /*wait for 30 secs for other functions to ack */ - reset_timeout = jiffies + (30 * HZ); - - drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - /* Its 2 that is written when qsnt is acked, moving one bit */ - drv_active = drv_active << 0x01; - - while (drv_state != drv_active) { - - if (time_after_eq(jiffies, reset_timeout)) { - /* quiescence timeout, other functions didn't ack - * changing the state to DEV_READY - */ - ql_log(ql_log_info, vha, 0xb023, - "%s : QUIESCENT TIMEOUT.\n", QLA2XXX_DRIVER_NAME); - ql_log(ql_log_info, vha, 0xb024, - "DRV_ACTIVE:%d DRV_STATE:%d.\n", - drv_active, drv_state); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_READY); - ql_log(ql_log_info, vha, 0xb025, - "HW State: DEV_READY.\n"); - qla82xx_idc_unlock(ha); - qla2x00_perform_loop_resync(vha); - qla82xx_idc_lock(ha); - - qla82xx_clear_qsnt_ready(vha); - return; - } - - qla82xx_idc_unlock(ha); - msleep(1000); - qla82xx_idc_lock(ha); - - drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - drv_active = drv_active << 0x01; - } - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - /* everyone acked so set the state to DEV_QUIESCENCE */ - if (dev_state == QLA82XX_DEV_NEED_QUIESCENT) { - ql_log(ql_log_info, vha, 0xb026, - "HW State: DEV_QUIESCENT.\n"); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_QUIESCENT); - } -} - -/* -* qla82xx_wait_for_state_change -* Wait for device state to change from given current state -* -* Note: -* IDC lock must not be held upon entry -* -* Return: -* Changed device state. -*/ -uint32_t -qla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t dev_state; - - do { - msleep(1000); - qla82xx_idc_lock(ha); - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla82xx_idc_unlock(ha); - } while (dev_state == curr_state); - - return dev_state; -} - -static void -qla82xx_dev_failed_handler(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - /* Disable the board */ - ql_log(ql_log_fatal, vha, 0x00b8, - "Disabling the board.\n"); - - qla82xx_idc_lock(ha); - qla82xx_clear_drv_active(ha); - qla82xx_idc_unlock(ha); - - /* Set DEV_FAILED flag to disable timer */ - vha->device_flags |= DFLG_DEV_FAILED; - qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); - qla2x00_mark_all_devices_lost(vha, 0); - vha->flags.online = 0; - vha->flags.init_done = 0; -} - -/* - * qla82xx_need_reset_handler - * Code to start reset sequence - * - * Note: - * IDC lock must be held upon entry - * - * Return: - * Success : 0 - * Failed : 1 - */ -static void -qla82xx_need_reset_handler(scsi_qla_host_t *vha) -{ - uint32_t dev_state, drv_state, drv_active; - uint32_t active_mask = 0; - unsigned long reset_timeout; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - if (vha->flags.online) { - qla82xx_idc_unlock(ha); - qla2x00_abort_isp_cleanup(vha); - ha->isp_ops->get_flash_version(vha, req->ring); - ha->isp_ops->nvram_config(vha); - qla82xx_idc_lock(ha); - } - - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - if (!ha->flags.isp82xx_reset_owner) { - ql_dbg(ql_dbg_p3p, vha, 0xb028, - "reset_acknowledged by 0x%x\n", ha->portnum); - qla82xx_set_rst_ready(ha); - } else { - active_mask = ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4)); - drv_active &= active_mask; - ql_dbg(ql_dbg_p3p, vha, 0xb029, - "active_mask: 0x%08x\n", active_mask); - } - - /* wait for 10 seconds for reset ack from all functions */ - reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); - - drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - - ql_dbg(ql_dbg_p3p, vha, 0xb02a, - "drv_state: 0x%08x, drv_active: 0x%08x, " - "dev_state: 0x%08x, active_mask: 0x%08x\n", - drv_state, drv_active, dev_state, active_mask); - - while (drv_state != drv_active && - dev_state != QLA82XX_DEV_INITIALIZING) { - if (time_after_eq(jiffies, reset_timeout)) { - ql_log(ql_log_warn, vha, 0x00b5, - "Reset timeout.\n"); - break; - } - qla82xx_idc_unlock(ha); - msleep(1000); - qla82xx_idc_lock(ha); - drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - if (ha->flags.isp82xx_reset_owner) - drv_active &= active_mask; - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - } - - ql_dbg(ql_dbg_p3p, vha, 0xb02b, - "drv_state: 0x%08x, drv_active: 0x%08x, " - "dev_state: 0x%08x, active_mask: 0x%08x\n", - drv_state, drv_active, dev_state, active_mask); - - ql_log(ql_log_info, vha, 0x00b6, - "Device state is 0x%x = %s.\n", - dev_state, - dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown"); - - /* Force to DEV_COLD unless someone else is starting a reset */ - if (dev_state != QLA82XX_DEV_INITIALIZING && - dev_state != QLA82XX_DEV_COLD) { - ql_log(ql_log_info, vha, 0x00b7, - "HW State: COLD/RE-INIT.\n"); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); - qla82xx_set_rst_ready(ha); - if (ql2xmdenable) { - if (qla82xx_md_collect(vha)) - ql_log(ql_log_warn, vha, 0xb02c, - "Not able to collect minidump.\n"); - } else - ql_log(ql_log_warn, vha, 0xb04f, - "Minidump disabled.\n"); - } -} - -int -qla82xx_check_md_needed(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - uint16_t fw_major_version, fw_minor_version, fw_subminor_version; - int rval = QLA_SUCCESS; - - fw_major_version = ha->fw_major_version; - fw_minor_version = ha->fw_minor_version; - fw_subminor_version = ha->fw_subminor_version; - - rval = qla2x00_get_fw_version(vha); - if (rval != QLA_SUCCESS) - return rval; - - if (ql2xmdenable) { - if (!ha->fw_dumped) { - if (fw_major_version != ha->fw_major_version || - fw_minor_version != ha->fw_minor_version || - fw_subminor_version != ha->fw_subminor_version) { - ql_log(ql_log_info, vha, 0xb02d, - "Firmware version differs " - "Previous version: %d:%d:%d - " - "New version: %d:%d:%d\n", - ha->fw_major_version, - ha->fw_minor_version, - ha->fw_subminor_version, - fw_major_version, fw_minor_version, - fw_subminor_version); - /* Release MiniDump resources */ - qla82xx_md_free(vha); - /* ALlocate MiniDump resources */ - qla82xx_md_prep(vha); - } - } else - ql_log(ql_log_info, vha, 0xb02e, - "Firmware dump available to retrieve\n"); - } - return rval; -} - - -int -qla82xx_check_fw_alive(scsi_qla_host_t *vha) -{ - uint32_t fw_heartbeat_counter; - int status = 0; - - fw_heartbeat_counter = qla82xx_rd_32(vha->hw, - QLA82XX_PEG_ALIVE_COUNTER); - /* all 0xff, assume AER/EEH in progress, ignore */ - if (fw_heartbeat_counter == 0xffffffff) { - ql_dbg(ql_dbg_timer, vha, 0x6003, - "FW heartbeat counter is 0xffffffff, " - "returning status=%d.\n", status); - return status; - } - if (vha->fw_heartbeat_counter == fw_heartbeat_counter) { - vha->seconds_since_last_heartbeat++; - /* FW not alive after 2 seconds */ - if (vha->seconds_since_last_heartbeat == 2) { - vha->seconds_since_last_heartbeat = 0; - status = 1; - } - } else - vha->seconds_since_last_heartbeat = 0; - vha->fw_heartbeat_counter = fw_heartbeat_counter; - if (status) - ql_dbg(ql_dbg_timer, vha, 0x6004, - "Returning status=%d.\n", status); - return status; -} - -/* - * qla82xx_device_state_handler - * Main state handler - * - * Note: - * IDC lock must be held upon entry - * - * Return: - * Success : 0 - * Failed : 1 - */ -int -qla82xx_device_state_handler(scsi_qla_host_t *vha) -{ - uint32_t dev_state; - uint32_t old_dev_state; - int rval = QLA_SUCCESS; - unsigned long dev_init_timeout; - struct qla_hw_data *ha = vha->hw; - int loopcount = 0; - - qla82xx_idc_lock(ha); - if (!vha->flags.init_done) - qla82xx_set_drv_active(vha); - - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - old_dev_state = dev_state; - ql_log(ql_log_info, vha, 0x009b, - "Device state is 0x%x = %s.\n", - dev_state, - dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown"); - - /* wait for 30 seconds for device to go ready */ - dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); - - while (1) { - - if (time_after_eq(jiffies, dev_init_timeout)) { - ql_log(ql_log_fatal, vha, 0x009c, - "Device init failed.\n"); - rval = QLA_FUNCTION_FAILED; - break; - } - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - if (old_dev_state != dev_state) { - loopcount = 0; - old_dev_state = dev_state; - } - if (loopcount < 5) { - ql_log(ql_log_info, vha, 0x009d, - "Device state is 0x%x = %s.\n", - dev_state, - dev_state < MAX_STATES ? qdev_state(dev_state) : - "Unknown"); - } - - switch (dev_state) { - case QLA82XX_DEV_READY: - ha->flags.isp82xx_reset_owner = 0; - goto exit; - case QLA82XX_DEV_COLD: - rval = qla82xx_device_bootstrap(vha); - break; - case QLA82XX_DEV_INITIALIZING: - qla82xx_idc_unlock(ha); - msleep(1000); - qla82xx_idc_lock(ha); - break; - case QLA82XX_DEV_NEED_RESET: - if (!ql2xdontresethba) - qla82xx_need_reset_handler(vha); - else { - qla82xx_idc_unlock(ha); - msleep(1000); - qla82xx_idc_lock(ha); - } - dev_init_timeout = jiffies + - (ha->nx_dev_init_timeout * HZ); - break; - case QLA82XX_DEV_NEED_QUIESCENT: - qla82xx_need_qsnt_handler(vha); - /* Reset timeout value after quiescence handler */ - dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\ - * HZ); - break; - case QLA82XX_DEV_QUIESCENT: - /* Owner will exit and other will wait for the state - * to get changed - */ - if (ha->flags.quiesce_owner) - goto exit; - - qla82xx_idc_unlock(ha); - msleep(1000); - qla82xx_idc_lock(ha); - - /* Reset timeout value after quiescence handler */ - dev_init_timeout = jiffies + (ha->nx_dev_init_timeout\ - * HZ); - break; - case QLA82XX_DEV_FAILED: - qla82xx_dev_failed_handler(vha); - rval = QLA_FUNCTION_FAILED; - goto exit; - default: - qla82xx_idc_unlock(ha); - msleep(1000); - qla82xx_idc_lock(ha); - } - loopcount++; - } -exit: - qla82xx_idc_unlock(ha); - return rval; -} - -void qla82xx_clear_pending_mbx(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - if (ha->flags.mbox_busy) { - ha->flags.mbox_int = 1; - ha->flags.mbox_busy = 0; - ql_log(ql_log_warn, vha, 0x6010, - "Doing premature completion of mbx command.\n"); - if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags)) - complete(&ha->mbx_intr_comp); - } -} - -void qla82xx_watchdog(scsi_qla_host_t *vha) -{ - uint32_t dev_state, halt_status; - struct qla_hw_data *ha = vha->hw; - - /* don't poll if reset is going on */ - if (!ha->flags.isp82xx_reset_hdlr_active) { - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - if (dev_state == QLA82XX_DEV_NEED_RESET && - !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) { - ql_log(ql_log_warn, vha, 0x6001, - "Adapter reset needed.\n"); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && - !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) { - ql_log(ql_log_warn, vha, 0x6002, - "Quiescent needed.\n"); - set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } else { - if (qla82xx_check_fw_alive(vha)) { - ql_dbg(ql_dbg_timer, vha, 0x6011, - "disabling pause transmit on port 0 & 1.\n"); - qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, - CRB_NIU_XG_PAUSE_CTL_P0|CRB_NIU_XG_PAUSE_CTL_P1); - halt_status = qla82xx_rd_32(ha, - QLA82XX_PEG_HALT_STATUS1); - ql_log(ql_log_info, vha, 0x6005, - "dumping hw/fw registers:.\n " - " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,.\n " - " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,.\n " - " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,.\n " - " PEG_NET_4_PC: 0x%x.\n", halt_status, - qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS2), - qla82xx_rd_32(ha, - QLA82XX_CRB_PEG_NET_0 + 0x3c), - qla82xx_rd_32(ha, - QLA82XX_CRB_PEG_NET_1 + 0x3c), - qla82xx_rd_32(ha, - QLA82XX_CRB_PEG_NET_2 + 0x3c), - qla82xx_rd_32(ha, - QLA82XX_CRB_PEG_NET_3 + 0x3c), - qla82xx_rd_32(ha, - QLA82XX_CRB_PEG_NET_4 + 0x3c)); - if (((halt_status & 0x1fffff00) >> 8) == 0x67) - ql_log(ql_log_warn, vha, 0xb052, - "Firmware aborted with " - "error code 0x00006700. Device is " - "being reset.\n"); - if (halt_status & HALT_STATUS_UNRECOVERABLE) { - set_bit(ISP_UNRECOVERABLE, - &vha->dpc_flags); - } else { - ql_log(ql_log_info, vha, 0x6006, - "Detect abort needed.\n"); - set_bit(ISP_ABORT_NEEDED, - &vha->dpc_flags); - } - qla2xxx_wake_dpc(vha); - ha->flags.isp82xx_fw_hung = 1; - ql_log(ql_log_warn, vha, 0x6007, "Firmware hung.\n"); - qla82xx_clear_pending_mbx(vha); - } - } - } -} - -int qla82xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr) -{ - int rval; - rval = qla82xx_device_state_handler(vha); - return rval; -} - -void -qla82xx_set_reset_owner(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t dev_state; - - dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - if (dev_state == QLA82XX_DEV_READY) { - ql_log(ql_log_info, vha, 0xb02f, - "HW State: NEED RESET\n"); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_NEED_RESET); - ha->flags.isp82xx_reset_owner = 1; - ql_dbg(ql_dbg_p3p, vha, 0xb030, - "reset_owner is 0x%x\n", ha->portnum); - } else - ql_log(ql_log_info, vha, 0xb031, - "Device state is 0x%x = %s.\n", - dev_state, - dev_state < MAX_STATES ? qdev_state(dev_state) : "Unknown"); -} - -/* - * qla82xx_abort_isp - * Resets ISP and aborts all outstanding commands. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = success - */ -int -qla82xx_abort_isp(scsi_qla_host_t *vha) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - - if (vha->device_flags & DFLG_DEV_FAILED) { - ql_log(ql_log_warn, vha, 0x8024, - "Device in failed state, exiting.\n"); - return QLA_SUCCESS; - } - ha->flags.isp82xx_reset_hdlr_active = 1; - - qla82xx_idc_lock(ha); - qla82xx_set_reset_owner(vha); - qla82xx_idc_unlock(ha); - - rval = qla82xx_device_state_handler(vha); - - qla82xx_idc_lock(ha); - qla82xx_clear_rst_ready(ha); - qla82xx_idc_unlock(ha); - - if (rval == QLA_SUCCESS) { - ha->flags.isp82xx_fw_hung = 0; - ha->flags.isp82xx_reset_hdlr_active = 0; - qla82xx_restart_isp(vha); - } - - if (rval) { - vha->flags.online = 1; - if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) { - if (ha->isp_abort_cnt == 0) { - ql_log(ql_log_warn, vha, 0x8027, - "ISP error recover failed - board " - "disabled.\n"); - /* - * The next call disables the board - * completely. - */ - ha->isp_ops->reset_adapter(vha); - vha->flags.online = 0; - clear_bit(ISP_ABORT_RETRY, - &vha->dpc_flags); - rval = QLA_SUCCESS; - } else { /* schedule another ISP abort */ - ha->isp_abort_cnt--; - ql_log(ql_log_warn, vha, 0x8036, - "ISP abort - retry remaining %d.\n", - ha->isp_abort_cnt); - rval = QLA_FUNCTION_FAILED; - } - } else { - ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT; - ql_dbg(ql_dbg_taskm, vha, 0x8029, - "ISP error recovery - retrying (%d) more times.\n", - ha->isp_abort_cnt); - set_bit(ISP_ABORT_RETRY, &vha->dpc_flags); - rval = QLA_FUNCTION_FAILED; - } - } - return rval; -} - -/* - * qla82xx_fcoe_ctx_reset - * Perform a quick reset and aborts all outstanding commands. - * This will only perform an FCoE context reset and avoids a full blown - * chip reset. - * - * Input: - * ha = adapter block pointer. - * is_reset_path = flag for identifying the reset path. - * - * Returns: - * 0 = success - */ -int qla82xx_fcoe_ctx_reset(scsi_qla_host_t *vha) -{ - int rval = QLA_FUNCTION_FAILED; - - if (vha->flags.online) { - /* Abort all outstanding commands, so as to be requeued later */ - qla2x00_abort_isp_cleanup(vha); - } - - /* Stop currently executing firmware. - * This will destroy existing FCoE context at the F/W end. - */ - qla2x00_try_to_stop_firmware(vha); - - /* Restart. Creates a new FCoE context on INIT_FIRMWARE. */ - rval = qla82xx_restart_isp(vha); - - return rval; -} - -/* - * qla2x00_wait_for_fcoe_ctx_reset - * Wait till the FCoE context is reset. - * - * Note: - * Does context switching here. - * Release SPIN_LOCK (if any) before calling this routine. - * - * Return: - * Success (fcoe_ctx reset is done) : 0 - * Failed (fcoe_ctx reset not completed within max loop timout ) : 1 - */ -int qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha) -{ - int status = QLA_FUNCTION_FAILED; - unsigned long wait_reset; - - wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ); - while ((test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) || - test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) - && time_before(jiffies, wait_reset)) { - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - - if (!test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) && - !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { - status = QLA_SUCCESS; - break; - } - } - ql_dbg(ql_dbg_p3p, vha, 0xb027, - "%s: status=%d.\n", __func__, status); - - return status; -} - -void -qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) -{ - int i; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - - /* Check if 82XX firmware is alive or not - * We may have arrived here from NEED_RESET - * detection only - */ - if (!ha->flags.isp82xx_fw_hung) { - for (i = 0; i < 2; i++) { - msleep(1000); - if (qla82xx_check_fw_alive(vha)) { - ha->flags.isp82xx_fw_hung = 1; - qla82xx_clear_pending_mbx(vha); - break; - } - } - } - ql_dbg(ql_dbg_init, vha, 0x00b0, - "Entered %s fw_hung=%d.\n", - __func__, ha->flags.isp82xx_fw_hung); - - /* Abort all commands gracefully if fw NOT hung */ - if (!ha->flags.isp82xx_fw_hung) { - int cnt, que; - srb_t *sp; - struct req_que *req; - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (que = 0; que < ha->max_req_queues; que++) { - req = ha->req_q_map[que]; - if (!req) - continue; - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (sp) { - if (!sp->u.scmd.ctx || - (sp->flags & SRB_FCP_CMND_DMA_VALID)) { - spin_unlock_irqrestore( - &ha->hardware_lock, flags); - if (ha->isp_ops->abort_command(sp)) { - ql_log(ql_log_info, vha, - 0x00b1, - "mbx abort failed.\n"); - } else { - ql_log(ql_log_info, vha, - 0x00b2, - "mbx abort success.\n"); - } - spin_lock_irqsave(&ha->hardware_lock, flags); - } - } - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* Wait for pending cmds (physical and virtual) to complete */ - if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0, - WAIT_HOST) == QLA_SUCCESS) { - ql_dbg(ql_dbg_init, vha, 0x00b3, - "Done wait for " - "pending commands.\n"); - } - } -} - -/* Minidump related functions */ -static int -qla82xx_minidump_process_control(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - struct qla82xx_md_entry_crb *crb_entry; - uint32_t read_value, opcode, poll_time; - uint32_t addr, index, crb_addr; - unsigned long wtime; - struct qla82xx_md_template_hdr *tmplt_hdr; - uint32_t rval = QLA_SUCCESS; - int i; - - tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr; - crb_entry = (struct qla82xx_md_entry_crb *)entry_hdr; - crb_addr = crb_entry->addr; - - for (i = 0; i < crb_entry->op_count; i++) { - opcode = crb_entry->crb_ctrl.opcode; - if (opcode & QLA82XX_DBG_OPCODE_WR) { - qla82xx_md_rw_32(ha, crb_addr, - crb_entry->value_1, 1); - opcode &= ~QLA82XX_DBG_OPCODE_WR; - } - - if (opcode & QLA82XX_DBG_OPCODE_RW) { - read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0); - qla82xx_md_rw_32(ha, crb_addr, read_value, 1); - opcode &= ~QLA82XX_DBG_OPCODE_RW; - } - - if (opcode & QLA82XX_DBG_OPCODE_AND) { - read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0); - read_value &= crb_entry->value_2; - opcode &= ~QLA82XX_DBG_OPCODE_AND; - if (opcode & QLA82XX_DBG_OPCODE_OR) { - read_value |= crb_entry->value_3; - opcode &= ~QLA82XX_DBG_OPCODE_OR; - } - qla82xx_md_rw_32(ha, crb_addr, read_value, 1); - } - - if (opcode & QLA82XX_DBG_OPCODE_OR) { - read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0); - read_value |= crb_entry->value_3; - qla82xx_md_rw_32(ha, crb_addr, read_value, 1); - opcode &= ~QLA82XX_DBG_OPCODE_OR; - } - - if (opcode & QLA82XX_DBG_OPCODE_POLL) { - poll_time = crb_entry->crb_strd.poll_timeout; - wtime = jiffies + poll_time; - read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0); - - do { - if ((read_value & crb_entry->value_2) - == crb_entry->value_1) - break; - else if (time_after_eq(jiffies, wtime)) { - /* capturing dump failed */ - rval = QLA_FUNCTION_FAILED; - break; - } else - read_value = qla82xx_md_rw_32(ha, - crb_addr, 0, 0); - } while (1); - opcode &= ~QLA82XX_DBG_OPCODE_POLL; - } - - if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) { - if (crb_entry->crb_strd.state_index_a) { - index = crb_entry->crb_strd.state_index_a; - addr = tmplt_hdr->saved_state_array[index]; - } else - addr = crb_addr; - - read_value = qla82xx_md_rw_32(ha, addr, 0, 0); - index = crb_entry->crb_ctrl.state_index_v; - tmplt_hdr->saved_state_array[index] = read_value; - opcode &= ~QLA82XX_DBG_OPCODE_RDSTATE; - } - - if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) { - if (crb_entry->crb_strd.state_index_a) { - index = crb_entry->crb_strd.state_index_a; - addr = tmplt_hdr->saved_state_array[index]; - } else - addr = crb_addr; - - if (crb_entry->crb_ctrl.state_index_v) { - index = crb_entry->crb_ctrl.state_index_v; - read_value = - tmplt_hdr->saved_state_array[index]; - } else - read_value = crb_entry->value_1; - - qla82xx_md_rw_32(ha, addr, read_value, 1); - opcode &= ~QLA82XX_DBG_OPCODE_WRSTATE; - } - - if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) { - index = crb_entry->crb_ctrl.state_index_v; - read_value = tmplt_hdr->saved_state_array[index]; - read_value <<= crb_entry->crb_ctrl.shl; - read_value >>= crb_entry->crb_ctrl.shr; - if (crb_entry->value_2) - read_value &= crb_entry->value_2; - read_value |= crb_entry->value_3; - read_value += crb_entry->value_1; - tmplt_hdr->saved_state_array[index] = read_value; - opcode &= ~QLA82XX_DBG_OPCODE_MDSTATE; - } - crb_addr += crb_entry->crb_strd.addr_stride; - } - return rval; -} - -static void -qla82xx_minidump_process_rdocm(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t r_addr, r_stride, loop_cnt, i, r_value; - struct qla82xx_md_entry_rdocm *ocm_hdr; - uint32_t *data_ptr = *d_ptr; - - ocm_hdr = (struct qla82xx_md_entry_rdocm *)entry_hdr; - r_addr = ocm_hdr->read_addr; - r_stride = ocm_hdr->read_addr_stride; - loop_cnt = ocm_hdr->op_count; - - for (i = 0; i < loop_cnt; i++) { - r_value = RD_REG_DWORD((void *)(r_addr + ha->nx_pcibase)); - *data_ptr++ = cpu_to_le32(r_value); - r_addr += r_stride; - } - *d_ptr = data_ptr; -} - -static void -qla82xx_minidump_process_rdmux(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value; - struct qla82xx_md_entry_mux *mux_hdr; - uint32_t *data_ptr = *d_ptr; - - mux_hdr = (struct qla82xx_md_entry_mux *)entry_hdr; - r_addr = mux_hdr->read_addr; - s_addr = mux_hdr->select_addr; - s_stride = mux_hdr->select_value_stride; - s_value = mux_hdr->select_value; - loop_cnt = mux_hdr->op_count; - - for (i = 0; i < loop_cnt; i++) { - qla82xx_md_rw_32(ha, s_addr, s_value, 1); - r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0); - *data_ptr++ = cpu_to_le32(s_value); - *data_ptr++ = cpu_to_le32(r_value); - s_value += s_stride; - } - *d_ptr = data_ptr; -} - -static void -qla82xx_minidump_process_rdcrb(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t r_addr, r_stride, loop_cnt, i, r_value; - struct qla82xx_md_entry_crb *crb_hdr; - uint32_t *data_ptr = *d_ptr; - - crb_hdr = (struct qla82xx_md_entry_crb *)entry_hdr; - r_addr = crb_hdr->addr; - r_stride = crb_hdr->crb_strd.addr_stride; - loop_cnt = crb_hdr->op_count; - - for (i = 0; i < loop_cnt; i++) { - r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0); - *data_ptr++ = cpu_to_le32(r_addr); - *data_ptr++ = cpu_to_le32(r_value); - r_addr += r_stride; - } - *d_ptr = data_ptr; -} - -static int -qla82xx_minidump_process_l2tag(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t addr, r_addr, c_addr, t_r_addr; - uint32_t i, k, loop_count, t_value, r_cnt, r_value; - unsigned long p_wait, w_time, p_mask; - uint32_t c_value_w, c_value_r; - struct qla82xx_md_entry_cache *cache_hdr; - int rval = QLA_FUNCTION_FAILED; - uint32_t *data_ptr = *d_ptr; - - cache_hdr = (struct qla82xx_md_entry_cache *)entry_hdr; - loop_count = cache_hdr->op_count; - r_addr = cache_hdr->read_addr; - c_addr = cache_hdr->control_addr; - c_value_w = cache_hdr->cache_ctrl.write_value; - - t_r_addr = cache_hdr->tag_reg_addr; - t_value = cache_hdr->addr_ctrl.init_tag_value; - r_cnt = cache_hdr->read_ctrl.read_addr_cnt; - p_wait = cache_hdr->cache_ctrl.poll_wait; - p_mask = cache_hdr->cache_ctrl.poll_mask; - - for (i = 0; i < loop_count; i++) { - qla82xx_md_rw_32(ha, t_r_addr, t_value, 1); - if (c_value_w) - qla82xx_md_rw_32(ha, c_addr, c_value_w, 1); - - if (p_mask) { - w_time = jiffies + p_wait; - do { - c_value_r = qla82xx_md_rw_32(ha, c_addr, 0, 0); - if ((c_value_r & p_mask) == 0) - break; - else if (time_after_eq(jiffies, w_time)) { - /* capturing dump failed */ - ql_dbg(ql_dbg_p3p, vha, 0xb032, - "c_value_r: 0x%x, poll_mask: 0x%lx, " - "w_time: 0x%lx\n", - c_value_r, p_mask, w_time); - return rval; - } - } while (1); - } - - addr = r_addr; - for (k = 0; k < r_cnt; k++) { - r_value = qla82xx_md_rw_32(ha, addr, 0, 0); - *data_ptr++ = cpu_to_le32(r_value); - addr += cache_hdr->read_ctrl.read_addr_stride; - } - t_value += cache_hdr->addr_ctrl.tag_value_stride; - } - *d_ptr = data_ptr; - return QLA_SUCCESS; -} - -static void -qla82xx_minidump_process_l1cache(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t addr, r_addr, c_addr, t_r_addr; - uint32_t i, k, loop_count, t_value, r_cnt, r_value; - uint32_t c_value_w; - struct qla82xx_md_entry_cache *cache_hdr; - uint32_t *data_ptr = *d_ptr; - - cache_hdr = (struct qla82xx_md_entry_cache *)entry_hdr; - loop_count = cache_hdr->op_count; - r_addr = cache_hdr->read_addr; - c_addr = cache_hdr->control_addr; - c_value_w = cache_hdr->cache_ctrl.write_value; - - t_r_addr = cache_hdr->tag_reg_addr; - t_value = cache_hdr->addr_ctrl.init_tag_value; - r_cnt = cache_hdr->read_ctrl.read_addr_cnt; - - for (i = 0; i < loop_count; i++) { - qla82xx_md_rw_32(ha, t_r_addr, t_value, 1); - qla82xx_md_rw_32(ha, c_addr, c_value_w, 1); - addr = r_addr; - for (k = 0; k < r_cnt; k++) { - r_value = qla82xx_md_rw_32(ha, addr, 0, 0); - *data_ptr++ = cpu_to_le32(r_value); - addr += cache_hdr->read_ctrl.read_addr_stride; - } - t_value += cache_hdr->addr_ctrl.tag_value_stride; - } - *d_ptr = data_ptr; -} - -static void -qla82xx_minidump_process_queue(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t s_addr, r_addr; - uint32_t r_stride, r_value, r_cnt, qid = 0; - uint32_t i, k, loop_cnt; - struct qla82xx_md_entry_queue *q_hdr; - uint32_t *data_ptr = *d_ptr; - - q_hdr = (struct qla82xx_md_entry_queue *)entry_hdr; - s_addr = q_hdr->select_addr; - r_cnt = q_hdr->rd_strd.read_addr_cnt; - r_stride = q_hdr->rd_strd.read_addr_stride; - loop_cnt = q_hdr->op_count; - - for (i = 0; i < loop_cnt; i++) { - qla82xx_md_rw_32(ha, s_addr, qid, 1); - r_addr = q_hdr->read_addr; - for (k = 0; k < r_cnt; k++) { - r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0); - *data_ptr++ = cpu_to_le32(r_value); - r_addr += r_stride; - } - qid += q_hdr->q_strd.queue_id_stride; - } - *d_ptr = data_ptr; -} - -static void -qla82xx_minidump_process_rdrom(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t r_addr, r_value; - uint32_t i, loop_cnt; - struct qla82xx_md_entry_rdrom *rom_hdr; - uint32_t *data_ptr = *d_ptr; - - rom_hdr = (struct qla82xx_md_entry_rdrom *)entry_hdr; - r_addr = rom_hdr->read_addr; - loop_cnt = rom_hdr->read_data_size/sizeof(uint32_t); - - for (i = 0; i < loop_cnt; i++) { - qla82xx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW, - (r_addr & 0xFFFF0000), 1); - r_value = qla82xx_md_rw_32(ha, - MD_DIRECT_ROM_READ_BASE + - (r_addr & 0x0000FFFF), 0, 0); - *data_ptr++ = cpu_to_le32(r_value); - r_addr += sizeof(uint32_t); - } - *d_ptr = data_ptr; -} - -static int -qla82xx_minidump_process_rdmem(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, uint32_t **d_ptr) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t r_addr, r_value, r_data; - uint32_t i, j, loop_cnt; - struct qla82xx_md_entry_rdmem *m_hdr; - unsigned long flags; - int rval = QLA_FUNCTION_FAILED; - uint32_t *data_ptr = *d_ptr; - - m_hdr = (struct qla82xx_md_entry_rdmem *)entry_hdr; - r_addr = m_hdr->read_addr; - loop_cnt = m_hdr->read_data_size/16; - - if (r_addr & 0xf) { - ql_log(ql_log_warn, vha, 0xb033, - "Read addr 0x%x not 16 bytes alligned\n", r_addr); - return rval; - } - - if (m_hdr->read_data_size % 16) { - ql_log(ql_log_warn, vha, 0xb034, - "Read data[0x%x] not multiple of 16 bytes\n", - m_hdr->read_data_size); - return rval; - } - - ql_dbg(ql_dbg_p3p, vha, 0xb035, - "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n", - __func__, r_addr, m_hdr->read_data_size, loop_cnt); - - write_lock_irqsave(&ha->hw_lock, flags); - for (i = 0; i < loop_cnt; i++) { - qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_LO, r_addr, 1); - r_value = 0; - qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_HI, r_value, 1); - r_value = MIU_TA_CTL_ENABLE; - qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1); - r_value = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - r_value = qla82xx_md_rw_32(ha, - MD_MIU_TEST_AGT_CTRL, 0, 0); - if ((r_value & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - printk_ratelimited(KERN_ERR - "failed to read through agent\n"); - write_unlock_irqrestore(&ha->hw_lock, flags); - return rval; - } - - for (j = 0; j < 4; j++) { - r_data = qla82xx_md_rw_32(ha, - MD_MIU_TEST_AGT_RDDATA[j], 0, 0); - *data_ptr++ = cpu_to_le32(r_data); - } - r_addr += 16; - } - write_unlock_irqrestore(&ha->hw_lock, flags); - *d_ptr = data_ptr; - return QLA_SUCCESS; -} - -static int -qla82xx_validate_template_chksum(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - uint64_t chksum = 0; - uint32_t *d_ptr = (uint32_t *)ha->md_tmplt_hdr; - int count = ha->md_template_size/sizeof(uint32_t); - - while (count-- > 0) - chksum += *d_ptr++; - while (chksum >> 32) - chksum = (chksum & 0xFFFFFFFF) + (chksum >> 32); - return ~chksum; -} - -static void -qla82xx_mark_entry_skipped(scsi_qla_host_t *vha, - qla82xx_md_entry_hdr_t *entry_hdr, int index) -{ - entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG; - ql_dbg(ql_dbg_p3p, vha, 0xb036, - "Skipping entry[%d]: " - "ETYPE[0x%x]-ELEVEL[0x%x]\n", - index, entry_hdr->entry_type, - entry_hdr->d_ctrl.entry_capture_mask); -} - -int -qla82xx_md_collect(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - int no_entry_hdr = 0; - qla82xx_md_entry_hdr_t *entry_hdr; - struct qla82xx_md_template_hdr *tmplt_hdr; - uint32_t *data_ptr; - uint32_t total_data_size = 0, f_capture_mask, data_collected = 0; - int i = 0, rval = QLA_FUNCTION_FAILED; - - tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr; - data_ptr = (uint32_t *)ha->md_dump; - - if (ha->fw_dumped) { - ql_log(ql_log_warn, vha, 0xb037, - "Firmware has been previously dumped (%p) " - "-- ignoring request.\n", ha->fw_dump); - goto md_failed; - } - - ha->fw_dumped = 0; - - if (!ha->md_tmplt_hdr || !ha->md_dump) { - ql_log(ql_log_warn, vha, 0xb038, - "Memory not allocated for minidump capture\n"); - goto md_failed; - } - - if (qla82xx_validate_template_chksum(vha)) { - ql_log(ql_log_info, vha, 0xb039, - "Template checksum validation error\n"); - goto md_failed; - } - - no_entry_hdr = tmplt_hdr->num_of_entries; - ql_dbg(ql_dbg_p3p, vha, 0xb03a, - "No of entry headers in Template: 0x%x\n", no_entry_hdr); - - ql_dbg(ql_dbg_p3p, vha, 0xb03b, - "Capture Mask obtained: 0x%x\n", tmplt_hdr->capture_debug_level); - - f_capture_mask = tmplt_hdr->capture_debug_level & 0xFF; - - /* Validate whether required debug level is set */ - if ((f_capture_mask & 0x3) != 0x3) { - ql_log(ql_log_warn, vha, 0xb03c, - "Minimum required capture mask[0x%x] level not set\n", - f_capture_mask); - goto md_failed; - } - tmplt_hdr->driver_capture_mask = ql2xmdcapmask; - - tmplt_hdr->driver_info[0] = vha->host_no; - tmplt_hdr->driver_info[1] = (QLA_DRIVER_MAJOR_VER << 24) | - (QLA_DRIVER_MINOR_VER << 16) | (QLA_DRIVER_PATCH_VER << 8) | - QLA_DRIVER_BETA_VER; - - total_data_size = ha->md_dump_size; - - ql_dbg(ql_dbg_p3p, vha, 0xb03d, - "Total minidump data_size 0x%x to be captured\n", total_data_size); - - /* Check whether template obtained is valid */ - if (tmplt_hdr->entry_type != QLA82XX_TLHDR) { - ql_log(ql_log_warn, vha, 0xb04e, - "Bad template header entry type: 0x%x obtained\n", - tmplt_hdr->entry_type); - goto md_failed; - } - - entry_hdr = (qla82xx_md_entry_hdr_t *) \ - (((uint8_t *)ha->md_tmplt_hdr) + tmplt_hdr->first_entry_offset); - - /* Walk through the entry headers */ - for (i = 0; i < no_entry_hdr; i++) { - - if (data_collected > total_data_size) { - ql_log(ql_log_warn, vha, 0xb03e, - "More MiniDump data collected: [0x%x]\n", - data_collected); - goto md_failed; - } - - if (!(entry_hdr->d_ctrl.entry_capture_mask & - ql2xmdcapmask)) { - entry_hdr->d_ctrl.driver_flags |= - QLA82XX_DBG_SKIPPED_FLAG; - ql_dbg(ql_dbg_p3p, vha, 0xb03f, - "Skipping entry[%d]: " - "ETYPE[0x%x]-ELEVEL[0x%x]\n", - i, entry_hdr->entry_type, - entry_hdr->d_ctrl.entry_capture_mask); - goto skip_nxt_entry; - } - - ql_dbg(ql_dbg_p3p, vha, 0xb040, - "[%s]: data ptr[%d]: %p, entry_hdr: %p\n" - "entry_type: 0x%x, captrue_mask: 0x%x\n", - __func__, i, data_ptr, entry_hdr, - entry_hdr->entry_type, - entry_hdr->d_ctrl.entry_capture_mask); - - ql_dbg(ql_dbg_p3p, vha, 0xb041, - "Data collected: [0x%x], Dump size left:[0x%x]\n", - data_collected, (ha->md_dump_size - data_collected)); - - /* Decode the entry type and take - * required action to capture debug data */ - switch (entry_hdr->entry_type) { - case QLA82XX_RDEND: - qla82xx_mark_entry_skipped(vha, entry_hdr, i); - break; - case QLA82XX_CNTRL: - rval = qla82xx_minidump_process_control(vha, - entry_hdr, &data_ptr); - if (rval != QLA_SUCCESS) { - qla82xx_mark_entry_skipped(vha, entry_hdr, i); - goto md_failed; - } - break; - case QLA82XX_RDCRB: - qla82xx_minidump_process_rdcrb(vha, - entry_hdr, &data_ptr); - break; - case QLA82XX_RDMEM: - rval = qla82xx_minidump_process_rdmem(vha, - entry_hdr, &data_ptr); - if (rval != QLA_SUCCESS) { - qla82xx_mark_entry_skipped(vha, entry_hdr, i); - goto md_failed; - } - break; - case QLA82XX_BOARD: - case QLA82XX_RDROM: - qla82xx_minidump_process_rdrom(vha, - entry_hdr, &data_ptr); - break; - case QLA82XX_L2DTG: - case QLA82XX_L2ITG: - case QLA82XX_L2DAT: - case QLA82XX_L2INS: - rval = qla82xx_minidump_process_l2tag(vha, - entry_hdr, &data_ptr); - if (rval != QLA_SUCCESS) { - qla82xx_mark_entry_skipped(vha, entry_hdr, i); - goto md_failed; - } - break; - case QLA82XX_L1DAT: - case QLA82XX_L1INS: - qla82xx_minidump_process_l1cache(vha, - entry_hdr, &data_ptr); - break; - case QLA82XX_RDOCM: - qla82xx_minidump_process_rdocm(vha, - entry_hdr, &data_ptr); - break; - case QLA82XX_RDMUX: - qla82xx_minidump_process_rdmux(vha, - entry_hdr, &data_ptr); - break; - case QLA82XX_QUEUE: - qla82xx_minidump_process_queue(vha, - entry_hdr, &data_ptr); - break; - case QLA82XX_RDNOP: - default: - qla82xx_mark_entry_skipped(vha, entry_hdr, i); - break; - } - - ql_dbg(ql_dbg_p3p, vha, 0xb042, - "[%s]: data ptr[%d]: %p\n", __func__, i, data_ptr); - - data_collected = (uint8_t *)data_ptr - - (uint8_t *)ha->md_dump; -skip_nxt_entry: - entry_hdr = (qla82xx_md_entry_hdr_t *) \ - (((uint8_t *)entry_hdr) + entry_hdr->entry_size); - } - - if (data_collected != total_data_size) { - ql_dbg(ql_dbg_p3p, vha, 0xb043, - "MiniDump data mismatch: Data collected: [0x%x]," - "total_data_size:[0x%x]\n", - data_collected, total_data_size); - goto md_failed; - } - - ql_log(ql_log_info, vha, 0xb044, - "Firmware dump saved to temp buffer (%ld/%p %ld/%p).\n", - vha->host_no, ha->md_tmplt_hdr, vha->host_no, ha->md_dump); - ha->fw_dumped = 1; - qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP); - -md_failed: - return rval; -} - -int -qla82xx_md_alloc(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - int i, k; - struct qla82xx_md_template_hdr *tmplt_hdr; - - tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr; - - if (ql2xmdcapmask < 0x3 || ql2xmdcapmask > 0x7F) { - ql2xmdcapmask = tmplt_hdr->capture_debug_level & 0xFF; - ql_log(ql_log_info, vha, 0xb045, - "Forcing driver capture mask to firmware default capture mask: 0x%x.\n", - ql2xmdcapmask); - } - - for (i = 0x2, k = 1; (i & QLA82XX_DEFAULT_CAP_MASK); i <<= 1, k++) { - if (i & ql2xmdcapmask) - ha->md_dump_size += tmplt_hdr->capture_size_array[k]; - } - - if (ha->md_dump) { - ql_log(ql_log_warn, vha, 0xb046, - "Firmware dump previously allocated.\n"); - return 1; - } - - ha->md_dump = vmalloc(ha->md_dump_size); - if (ha->md_dump == NULL) { - ql_log(ql_log_warn, vha, 0xb047, - "Unable to allocate memory for Minidump size " - "(0x%x).\n", ha->md_dump_size); - return 1; - } - return 0; -} - -void -qla82xx_md_free(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - /* Release the template header allocated */ - if (ha->md_tmplt_hdr) { - ql_log(ql_log_info, vha, 0xb048, - "Free MiniDump template: %p, size (%d KB)\n", - ha->md_tmplt_hdr, ha->md_template_size / 1024); - dma_free_coherent(&ha->pdev->dev, ha->md_template_size, - ha->md_tmplt_hdr, ha->md_tmplt_hdr_dma); - ha->md_tmplt_hdr = 0; - } - - /* Release the template data buffer allocated */ - if (ha->md_dump) { - ql_log(ql_log_info, vha, 0xb049, - "Free MiniDump memory: %p, size (%d KB)\n", - ha->md_dump, ha->md_dump_size / 1024); - vfree(ha->md_dump); - ha->md_dump_size = 0; - ha->md_dump = 0; - } -} - -void -qla82xx_md_prep(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - int rval; - - /* Get Minidump template size */ - rval = qla82xx_md_get_template_size(vha); - if (rval == QLA_SUCCESS) { - ql_log(ql_log_info, vha, 0xb04a, - "MiniDump Template size obtained (%d KB)\n", - ha->md_template_size / 1024); - - /* Get Minidump template */ - rval = qla82xx_md_get_template(vha); - if (rval == QLA_SUCCESS) { - ql_dbg(ql_dbg_p3p, vha, 0xb04b, - "MiniDump Template obtained\n"); - - /* Allocate memory for minidump */ - rval = qla82xx_md_alloc(vha); - if (rval == QLA_SUCCESS) - ql_log(ql_log_info, vha, 0xb04c, - "MiniDump memory allocated (%d KB)\n", - ha->md_dump_size / 1024); - else { - ql_log(ql_log_info, vha, 0xb04d, - "Free MiniDump template: %p, size: (%d KB)\n", - ha->md_tmplt_hdr, - ha->md_template_size / 1024); - dma_free_coherent(&ha->pdev->dev, - ha->md_template_size, - ha->md_tmplt_hdr, ha->md_tmplt_hdr_dma); - ha->md_tmplt_hdr = 0; - } - - } - } -} - -int -qla82xx_beacon_on(struct scsi_qla_host *vha) -{ - - int rval; - struct qla_hw_data *ha = vha->hw; - qla82xx_idc_lock(ha); - rval = qla82xx_mbx_beacon_ctl(vha, 1); - - if (rval) { - ql_log(ql_log_warn, vha, 0xb050, - "mbx set led config failed in %s\n", __func__); - goto exit; - } - ha->beacon_blink_led = 1; -exit: - qla82xx_idc_unlock(ha); - return rval; -} - -int -qla82xx_beacon_off(struct scsi_qla_host *vha) -{ - - int rval; - struct qla_hw_data *ha = vha->hw; - qla82xx_idc_lock(ha); - rval = qla82xx_mbx_beacon_ctl(vha, 0); - - if (rval) { - ql_log(ql_log_warn, vha, 0xb051, - "mbx set led config failed in %s\n", __func__); - goto exit; - } - ha->beacon_blink_led = 0; -exit: - qla82xx_idc_unlock(ha); - return rval; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.h deleted file mode 100644 index 4ac50e27..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_nx.h +++ /dev/null @@ -1,1181 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#ifndef __QLA_NX_H -#define __QLA_NX_H - -/* - * Following are the states of the Phantom. Phantom will set them and - * Host will read to check if the fields are correct. -*/ -#define PHAN_INITIALIZE_FAILED 0xffff -#define PHAN_INITIALIZE_COMPLETE 0xff01 - -/* Host writes the following to notify that it has done the init-handshake */ -#define PHAN_INITIALIZE_ACK 0xf00f -#define PHAN_PEG_RCV_INITIALIZED 0xff01 - -/*CRB_RELATED*/ -#define QLA82XX_CRB_BASE QLA82XX_CAM_RAM(0x200) -#define QLA82XX_REG(X) (QLA82XX_CRB_BASE+(X)) - -#define CRB_CMDPEG_STATE QLA82XX_REG(0x50) -#define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) -#define BOOT_LOADER_DIMM_STATUS QLA82XX_REG(0x54) -#define CRB_DMA_SHIFT QLA82XX_REG(0xcc) -#define QLA82XX_DMA_SHIFT_VALUE 0x55555555 - -#define QLA82XX_HW_H0_CH_HUB_ADR 0x05 -#define QLA82XX_HW_H1_CH_HUB_ADR 0x0E -#define QLA82XX_HW_H2_CH_HUB_ADR 0x03 -#define QLA82XX_HW_H3_CH_HUB_ADR 0x01 -#define QLA82XX_HW_H4_CH_HUB_ADR 0x06 -#define QLA82XX_HW_H5_CH_HUB_ADR 0x07 -#define QLA82XX_HW_H6_CH_HUB_ADR 0x08 - -/* Hub 0 */ -#define QLA82XX_HW_MN_CRB_AGT_ADR 0x15 -#define QLA82XX_HW_MS_CRB_AGT_ADR 0x25 - -/* Hub 1 */ -#define QLA82XX_HW_PS_CRB_AGT_ADR 0x73 -#define QLA82XX_HW_QMS_CRB_AGT_ADR 0x00 -#define QLA82XX_HW_RPMX3_CRB_AGT_ADR 0x0b -#define QLA82XX_HW_SQGS0_CRB_AGT_ADR 0x01 -#define QLA82XX_HW_SQGS1_CRB_AGT_ADR 0x02 -#define QLA82XX_HW_SQGS2_CRB_AGT_ADR 0x03 -#define QLA82XX_HW_SQGS3_CRB_AGT_ADR 0x04 -#define QLA82XX_HW_C2C0_CRB_AGT_ADR 0x58 -#define QLA82XX_HW_C2C1_CRB_AGT_ADR 0x59 -#define QLA82XX_HW_C2C2_CRB_AGT_ADR 0x5a -#define QLA82XX_HW_RPMX2_CRB_AGT_ADR 0x0a -#define QLA82XX_HW_RPMX4_CRB_AGT_ADR 0x0c -#define QLA82XX_HW_RPMX7_CRB_AGT_ADR 0x0f -#define QLA82XX_HW_RPMX9_CRB_AGT_ADR 0x12 -#define QLA82XX_HW_SMB_CRB_AGT_ADR 0x18 - -/* Hub 2 */ -#define QLA82XX_HW_NIU_CRB_AGT_ADR 0x31 -#define QLA82XX_HW_I2C0_CRB_AGT_ADR 0x19 -#define QLA82XX_HW_I2C1_CRB_AGT_ADR 0x29 - -#define QLA82XX_HW_SN_CRB_AGT_ADR 0x10 -#define QLA82XX_HW_I2Q_CRB_AGT_ADR 0x20 -#define QLA82XX_HW_LPC_CRB_AGT_ADR 0x22 -#define QLA82XX_HW_ROMUSB_CRB_AGT_ADR 0x21 -#define QLA82XX_HW_QM_CRB_AGT_ADR 0x66 -#define QLA82XX_HW_SQG0_CRB_AGT_ADR 0x60 -#define QLA82XX_HW_SQG1_CRB_AGT_ADR 0x61 -#define QLA82XX_HW_SQG2_CRB_AGT_ADR 0x62 -#define QLA82XX_HW_SQG3_CRB_AGT_ADR 0x63 -#define QLA82XX_HW_RPMX1_CRB_AGT_ADR 0x09 -#define QLA82XX_HW_RPMX5_CRB_AGT_ADR 0x0d -#define QLA82XX_HW_RPMX6_CRB_AGT_ADR 0x0e -#define QLA82XX_HW_RPMX8_CRB_AGT_ADR 0x11 - -/* Hub 3 */ -#define QLA82XX_HW_PH_CRB_AGT_ADR 0x1A -#define QLA82XX_HW_SRE_CRB_AGT_ADR 0x50 -#define QLA82XX_HW_EG_CRB_AGT_ADR 0x51 -#define QLA82XX_HW_RPMX0_CRB_AGT_ADR 0x08 - -/* Hub 4 */ -#define QLA82XX_HW_PEGN0_CRB_AGT_ADR 0x40 -#define QLA82XX_HW_PEGN1_CRB_AGT_ADR 0x41 -#define QLA82XX_HW_PEGN2_CRB_AGT_ADR 0x42 -#define QLA82XX_HW_PEGN3_CRB_AGT_ADR 0x43 -#define QLA82XX_HW_PEGNI_CRB_AGT_ADR 0x44 -#define QLA82XX_HW_PEGND_CRB_AGT_ADR 0x45 -#define QLA82XX_HW_PEGNC_CRB_AGT_ADR 0x46 -#define QLA82XX_HW_PEGR0_CRB_AGT_ADR 0x47 -#define QLA82XX_HW_PEGR1_CRB_AGT_ADR 0x48 -#define QLA82XX_HW_PEGR2_CRB_AGT_ADR 0x49 -#define QLA82XX_HW_PEGR3_CRB_AGT_ADR 0x4a -#define QLA82XX_HW_PEGN4_CRB_AGT_ADR 0x4b - -/* Hub 5 */ -#define QLA82XX_HW_PEGS0_CRB_AGT_ADR 0x40 -#define QLA82XX_HW_PEGS1_CRB_AGT_ADR 0x41 -#define QLA82XX_HW_PEGS2_CRB_AGT_ADR 0x42 -#define QLA82XX_HW_PEGS3_CRB_AGT_ADR 0x43 -#define QLA82XX_HW_PEGSI_CRB_AGT_ADR 0x44 -#define QLA82XX_HW_PEGSD_CRB_AGT_ADR 0x45 -#define QLA82XX_HW_PEGSC_CRB_AGT_ADR 0x46 - -/* Hub 6 */ -#define QLA82XX_HW_CAS0_CRB_AGT_ADR 0x46 -#define QLA82XX_HW_CAS1_CRB_AGT_ADR 0x47 -#define QLA82XX_HW_CAS2_CRB_AGT_ADR 0x48 -#define QLA82XX_HW_CAS3_CRB_AGT_ADR 0x49 -#define QLA82XX_HW_NCM_CRB_AGT_ADR 0x16 -#define QLA82XX_HW_TMR_CRB_AGT_ADR 0x17 -#define QLA82XX_HW_XDMA_CRB_AGT_ADR 0x05 -#define QLA82XX_HW_OCM0_CRB_AGT_ADR 0x06 -#define QLA82XX_HW_OCM1_CRB_AGT_ADR 0x07 - -/* This field defines PCI/X adr [25:20] of agents on the CRB */ -/* */ -#define QLA82XX_HW_PX_MAP_CRB_PH 0 -#define QLA82XX_HW_PX_MAP_CRB_PS 1 -#define QLA82XX_HW_PX_MAP_CRB_MN 2 -#define QLA82XX_HW_PX_MAP_CRB_MS 3 -#define QLA82XX_HW_PX_MAP_CRB_SRE 5 -#define QLA82XX_HW_PX_MAP_CRB_NIU 6 -#define QLA82XX_HW_PX_MAP_CRB_QMN 7 -#define QLA82XX_HW_PX_MAP_CRB_SQN0 8 -#define QLA82XX_HW_PX_MAP_CRB_SQN1 9 -#define QLA82XX_HW_PX_MAP_CRB_SQN2 10 -#define QLA82XX_HW_PX_MAP_CRB_SQN3 11 -#define QLA82XX_HW_PX_MAP_CRB_QMS 12 -#define QLA82XX_HW_PX_MAP_CRB_SQS0 13 -#define QLA82XX_HW_PX_MAP_CRB_SQS1 14 -#define QLA82XX_HW_PX_MAP_CRB_SQS2 15 -#define QLA82XX_HW_PX_MAP_CRB_SQS3 16 -#define QLA82XX_HW_PX_MAP_CRB_PGN0 17 -#define QLA82XX_HW_PX_MAP_CRB_PGN1 18 -#define QLA82XX_HW_PX_MAP_CRB_PGN2 19 -#define QLA82XX_HW_PX_MAP_CRB_PGN3 20 -#define QLA82XX_HW_PX_MAP_CRB_PGN4 QLA82XX_HW_PX_MAP_CRB_SQS2 -#define QLA82XX_HW_PX_MAP_CRB_PGND 21 -#define QLA82XX_HW_PX_MAP_CRB_PGNI 22 -#define QLA82XX_HW_PX_MAP_CRB_PGS0 23 -#define QLA82XX_HW_PX_MAP_CRB_PGS1 24 -#define QLA82XX_HW_PX_MAP_CRB_PGS2 25 -#define QLA82XX_HW_PX_MAP_CRB_PGS3 26 -#define QLA82XX_HW_PX_MAP_CRB_PGSD 27 -#define QLA82XX_HW_PX_MAP_CRB_PGSI 28 -#define QLA82XX_HW_PX_MAP_CRB_SN 29 -#define QLA82XX_HW_PX_MAP_CRB_EG 31 -#define QLA82XX_HW_PX_MAP_CRB_PH2 32 -#define QLA82XX_HW_PX_MAP_CRB_PS2 33 -#define QLA82XX_HW_PX_MAP_CRB_CAM 34 -#define QLA82XX_HW_PX_MAP_CRB_CAS0 35 -#define QLA82XX_HW_PX_MAP_CRB_CAS1 36 -#define QLA82XX_HW_PX_MAP_CRB_CAS2 37 -#define QLA82XX_HW_PX_MAP_CRB_C2C0 38 -#define QLA82XX_HW_PX_MAP_CRB_C2C1 39 -#define QLA82XX_HW_PX_MAP_CRB_TIMR 40 -#define QLA82XX_HW_PX_MAP_CRB_RPMX1 42 -#define QLA82XX_HW_PX_MAP_CRB_RPMX2 43 -#define QLA82XX_HW_PX_MAP_CRB_RPMX3 44 -#define QLA82XX_HW_PX_MAP_CRB_RPMX4 45 -#define QLA82XX_HW_PX_MAP_CRB_RPMX5 46 -#define QLA82XX_HW_PX_MAP_CRB_RPMX6 47 -#define QLA82XX_HW_PX_MAP_CRB_RPMX7 48 -#define QLA82XX_HW_PX_MAP_CRB_XDMA 49 -#define QLA82XX_HW_PX_MAP_CRB_I2Q 50 -#define QLA82XX_HW_PX_MAP_CRB_ROMUSB 51 -#define QLA82XX_HW_PX_MAP_CRB_CAS3 52 -#define QLA82XX_HW_PX_MAP_CRB_RPMX0 53 -#define QLA82XX_HW_PX_MAP_CRB_RPMX8 54 -#define QLA82XX_HW_PX_MAP_CRB_RPMX9 55 -#define QLA82XX_HW_PX_MAP_CRB_OCM0 56 -#define QLA82XX_HW_PX_MAP_CRB_OCM1 57 -#define QLA82XX_HW_PX_MAP_CRB_SMB 58 -#define QLA82XX_HW_PX_MAP_CRB_I2C0 59 -#define QLA82XX_HW_PX_MAP_CRB_I2C1 60 -#define QLA82XX_HW_PX_MAP_CRB_LPC 61 -#define QLA82XX_HW_PX_MAP_CRB_PGNC 62 -#define QLA82XX_HW_PX_MAP_CRB_PGR0 63 -#define QLA82XX_HW_PX_MAP_CRB_PGR1 4 -#define QLA82XX_HW_PX_MAP_CRB_PGR2 30 -#define QLA82XX_HW_PX_MAP_CRB_PGR3 41 - -/* This field defines CRB adr [31:20] of the agents */ -/* */ - -#define QLA82XX_HW_CRB_HUB_AGT_ADR_MN ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ - QLA82XX_HW_MN_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PH ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PH_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_MS ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ - QLA82XX_HW_MS_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PS_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SS_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_QMS_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS0 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQGS0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS1 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQGS1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS2 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQGS2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS3 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQGS3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C0 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_C2C0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C1 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_C2C1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX4_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX7_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX9_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SMB ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SMB_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_NIU ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ - QLA82XX_HW_NIU_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0 ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ - QLA82XX_HW_I2C0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1 ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ - QLA82XX_HW_I2C1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SRE ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SRE_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_EG ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_EG_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMN ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_QM_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQG0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQG1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQG2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQG3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX5_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX6_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX8_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_CAS0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_CAS1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS2 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_CAS2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS3 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_CAS3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGNI_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGND ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGND_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN4_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGNC_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR0 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGR0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR1 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGR1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR2 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGR2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR3 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGR3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGSI_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSD ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGSD_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGS0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGS1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGS2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGS3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSC ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGSC_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAM ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_NCM_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_TMR_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_XDMA_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SN ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SN_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_I2Q_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_ROMUSB_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0 ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_OCM0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM1 ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_OCM1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_LPC ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_LPC_CRB_AGT_ADR) - -#define ROMUSB_GLB (QLA82XX_CRB_ROMUSB + 0x00000) -#define QLA82XX_ROMUSB_GLB_PEGTUNE_DONE (ROMUSB_GLB + 0x005c) -#define QLA82XX_ROMUSB_GLB_STATUS (ROMUSB_GLB + 0x0004) -#define QLA82XX_ROMUSB_GLB_SW_RESET (ROMUSB_GLB + 0x0008) -#define QLA82XX_ROMUSB_ROM_ADDRESS (ROMUSB_ROM + 0x0008) -#define QLA82XX_ROMUSB_ROM_WDATA (ROMUSB_ROM + 0x000c) -#define QLA82XX_ROMUSB_ROM_ABYTE_CNT (ROMUSB_ROM + 0x0010) -#define QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014) -#define QLA82XX_ROMUSB_ROM_RDATA (ROMUSB_ROM + 0x0018) - -#define ROMUSB_ROM (QLA82XX_CRB_ROMUSB + 0x10000) -#define QLA82XX_ROMUSB_ROM_INSTR_OPCODE (ROMUSB_ROM + 0x0004) -#define QLA82XX_ROMUSB_GLB_CAS_RST (ROMUSB_GLB + 0x0038) - -/* Lock IDs for ROM lock */ -#define ROM_LOCK_DRIVER 0x0d417340 - -#define QLA82XX_PCI_CRB_WINDOWSIZE 0x00100000 /* all are 1MB windows */ -#define QLA82XX_PCI_CRB_WINDOW(A) \ - (QLA82XX_PCI_CRBSPACE + (A)*QLA82XX_PCI_CRB_WINDOWSIZE) -#define QLA82XX_CRB_C2C_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C0) -#define QLA82XX_CRB_C2C_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C1) -#define QLA82XX_CRB_C2C_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C2) -#define QLA82XX_CRB_CAM \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAM) -#define QLA82XX_CRB_CASPER \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS) -#define QLA82XX_CRB_CASPER_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS0) -#define QLA82XX_CRB_CASPER_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS1) -#define QLA82XX_CRB_CASPER_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS2) -#define QLA82XX_CRB_DDR_MD \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MS) -#define QLA82XX_CRB_DDR_NET \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MN) -#define QLA82XX_CRB_EPG \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_EG) -#define QLA82XX_CRB_I2Q \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2Q) -#define QLA82XX_CRB_NIU \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_NIU) - -#define QLA82XX_CRB_PCIX_HOST \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH) -#define QLA82XX_CRB_PCIX_HOST2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH2) -#define QLA82XX_CRB_PCIX_MD \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS) -#define QLA82XX_CRB_PCIE \ - QLA82XX_CRB_PCIX_MD - -/* window 1 pcie slot */ -#define QLA82XX_CRB_PCIE2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS2) -#define QLA82XX_CRB_PEG_MD_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS0) -#define QLA82XX_CRB_PEG_MD_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS1) -#define QLA82XX_CRB_PEG_MD_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS2) -#define QLA82XX_CRB_PEG_MD_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3) -#define QLA82XX_CRB_PEG_MD_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3) -#define QLA82XX_CRB_PEG_MD_D \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSD) -#define QLA82XX_CRB_PEG_MD_I \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSI) -#define QLA82XX_CRB_PEG_NET_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN0) -#define QLA82XX_CRB_PEG_NET_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN1) -#define QLA82XX_CRB_PEG_NET_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN2) -#define QLA82XX_CRB_PEG_NET_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN3) -#define QLA82XX_CRB_PEG_NET_4 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN4) -#define QLA82XX_CRB_PEG_NET_D \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGND) -#define QLA82XX_CRB_PEG_NET_I \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGNI) -#define QLA82XX_CRB_PQM_MD \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMS) -#define QLA82XX_CRB_PQM_NET \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMN) -#define QLA82XX_CRB_QDR_MD \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SS) -#define QLA82XX_CRB_QDR_NET \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SN) -#define QLA82XX_CRB_ROMUSB \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_ROMUSB) -#define QLA82XX_CRB_RPMX_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX0) -#define QLA82XX_CRB_RPMX_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX1) -#define QLA82XX_CRB_RPMX_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX2) -#define QLA82XX_CRB_RPMX_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX3) -#define QLA82XX_CRB_RPMX_4 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX4) -#define QLA82XX_CRB_RPMX_5 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX5) -#define QLA82XX_CRB_RPMX_6 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX6) -#define QLA82XX_CRB_RPMX_7 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX7) -#define QLA82XX_CRB_SQM_MD_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS0) -#define QLA82XX_CRB_SQM_MD_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS1) -#define QLA82XX_CRB_SQM_MD_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS2) -#define QLA82XX_CRB_SQM_MD_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS3) -#define QLA82XX_CRB_SQM_NET_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN0) -#define QLA82XX_CRB_SQM_NET_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN1) -#define QLA82XX_CRB_SQM_NET_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN2) -#define QLA82XX_CRB_SQM_NET_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN3) -#define QLA82XX_CRB_SRE \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SRE) -#define QLA82XX_CRB_TIMER \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_TIMR) -#define QLA82XX_CRB_XDMA \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_XDMA) -#define QLA82XX_CRB_I2C0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C0) -#define QLA82XX_CRB_I2C1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C1) -#define QLA82XX_CRB_OCM0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_OCM0) -#define QLA82XX_CRB_SMB \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SMB) -#define QLA82XX_CRB_MAX \ - QLA82XX_PCI_CRB_WINDOW(64) - -/* - * ====================== BASE ADDRESSES ON-CHIP ====================== - * Base addresses of major components on-chip. - * ====================== BASE ADDRESSES ON-CHIP ====================== - */ -#define QLA82XX_ADDR_DDR_NET (0x0000000000000000ULL) -#define QLA82XX_ADDR_DDR_NET_MAX (0x000000000fffffffULL) - -/* Imbus address bit used to indicate a host address. This bit is - * eliminated by the pcie bar and bar select before presentation - * over pcie. */ -/* host memory via IMBUS */ -#define QLA82XX_P2_ADDR_PCIE (0x0000000800000000ULL) -#define QLA82XX_P3_ADDR_PCIE (0x0000008000000000ULL) -#define QLA82XX_ADDR_PCIE_MAX (0x0000000FFFFFFFFFULL) -#define QLA82XX_ADDR_OCM0 (0x0000000200000000ULL) -#define QLA82XX_ADDR_OCM0_MAX (0x00000002000fffffULL) -#define QLA82XX_ADDR_OCM1 (0x0000000200400000ULL) -#define QLA82XX_ADDR_OCM1_MAX (0x00000002004fffffULL) -#define QLA82XX_ADDR_QDR_NET (0x0000000300000000ULL) -#define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL) - -#define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000 -#define QLA82XX_PCI_DIRECT_CRB (unsigned long)0x04400000 -#define QLA82XX_PCI_CAMQM (unsigned long)0x04800000 -#define QLA82XX_PCI_CAMQM_MAX (unsigned long)0x04ffffff -#define QLA82XX_PCI_DDR_NET (unsigned long)0x00000000 -#define QLA82XX_PCI_QDR_NET (unsigned long)0x04000000 -#define QLA82XX_PCI_QDR_NET_MAX (unsigned long)0x043fffff - -/* - * Register offsets for MN - */ -#define MIU_CONTROL (0x000) -#define MIU_TAG (0x004) -#define MIU_TEST_AGT_CTRL (0x090) -#define MIU_TEST_AGT_ADDR_LO (0x094) -#define MIU_TEST_AGT_ADDR_HI (0x098) -#define MIU_TEST_AGT_WRDATA_LO (0x0a0) -#define MIU_TEST_AGT_WRDATA_HI (0x0a4) -#define MIU_TEST_AGT_WRDATA(i) (0x0a0+(4*(i))) -#define MIU_TEST_AGT_RDDATA_LO (0x0a8) -#define MIU_TEST_AGT_RDDATA_HI (0x0ac) -#define MIU_TEST_AGT_RDDATA(i) (0x0a8+(4*(i))) -#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8 -#define MIU_TEST_AGT_UPPER_ADDR(off) (0) - -/* MIU_TEST_AGT_CTRL flags. work for SIU as well */ -#define MIU_TA_CTL_START 1 -#define MIU_TA_CTL_ENABLE 2 -#define MIU_TA_CTL_WRITE 4 -#define MIU_TA_CTL_BUSY 8 - -/*CAM RAM */ -# define QLA82XX_CAM_RAM_BASE (QLA82XX_CRB_CAM + 0x02000) -# define QLA82XX_CAM_RAM(reg) (QLA82XX_CAM_RAM_BASE + (reg)) - -#define QLA82XX_PORT_MODE_ADDR (QLA82XX_CAM_RAM(0x24)) -#define QLA82XX_PEG_HALT_STATUS1 (QLA82XX_CAM_RAM(0xa8)) -#define QLA82XX_PEG_HALT_STATUS2 (QLA82XX_CAM_RAM(0xac)) -#define QLA82XX_PEG_ALIVE_COUNTER (QLA82XX_CAM_RAM(0xb0)) - -#define QLA82XX_CAMRAM_DB1 (QLA82XX_CAM_RAM(0x1b8)) -#define QLA82XX_CAMRAM_DB2 (QLA82XX_CAM_RAM(0x1bc)) - -#define HALT_STATUS_UNRECOVERABLE 0x80000000 -#define HALT_STATUS_RECOVERABLE 0x40000000 - -/* Driver Coexistence Defines */ -#define QLA82XX_CRB_DRV_ACTIVE (QLA82XX_CAM_RAM(0x138)) -#define QLA82XX_CRB_DEV_STATE (QLA82XX_CAM_RAM(0x140)) -#define QLA82XX_CRB_DRV_STATE (QLA82XX_CAM_RAM(0x144)) -#define QLA82XX_CRB_DRV_SCRATCH (QLA82XX_CAM_RAM(0x148)) -#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c)) -#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174)) - -/* Every driver should use these Device State */ -#define QLA82XX_DEV_COLD 1 -#define QLA82XX_DEV_INITIALIZING 2 -#define QLA82XX_DEV_READY 3 -#define QLA82XX_DEV_NEED_RESET 4 -#define QLA82XX_DEV_NEED_QUIESCENT 5 -#define QLA82XX_DEV_FAILED 6 -#define QLA82XX_DEV_QUIESCENT 7 -#define MAX_STATES 8 /* Increment if new state added */ - -#define QLA82XX_IDC_VERSION 1 -#define QLA82XX_ROM_DEV_INIT_TIMEOUT 30 -#define QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT 10 - -#define QLA82XX_ROM_LOCK_ID (QLA82XX_CAM_RAM(0x100)) -#define QLA82XX_CRB_WIN_LOCK_ID (QLA82XX_CAM_RAM(0x124)) -#define QLA82XX_FW_VERSION_MAJOR (QLA82XX_CAM_RAM(0x150)) -#define QLA82XX_FW_VERSION_MINOR (QLA82XX_CAM_RAM(0x154)) -#define QLA82XX_FW_VERSION_SUB (QLA82XX_CAM_RAM(0x158)) -#define QLA82XX_PCIE_REG(reg) (QLA82XX_CRB_PCIE + (reg)) - -#define PCIE_CHICKEN3 (0x120c8) -#define PCIE_SETUP_FUNCTION (0x12040) -#define PCIE_SETUP_FUNCTION2 (0x12048) - -#define QLA82XX_PCIX_PS_REG(reg) (QLA82XX_CRB_PCIX_MD + (reg)) -#define QLA82XX_PCIX_PS2_REG(reg) (QLA82XX_CRB_PCIE2 + (reg)) - -#define PCIE_SEM2_LOCK (0x1c010) /* Flash lock */ -#define PCIE_SEM2_UNLOCK (0x1c014) /* Flash unlock */ -#define PCIE_SEM5_LOCK (0x1c028) /* Coexistence lock */ -#define PCIE_SEM5_UNLOCK (0x1c02c) /* Coexistence unlock */ -#define PCIE_SEM7_LOCK (0x1c038) /* crb win lock */ -#define PCIE_SEM7_UNLOCK (0x1c03c) /* crbwin unlock*/ - -/* Different drive state */ -#define QLA82XX_DRVST_NOT_RDY 0 -#define QLA82XX_DRVST_RST_RDY 1 -#define QLA82XX_DRVST_QSNT_RDY 2 - -/* Different drive active state */ -#define QLA82XX_DRV_NOT_ACTIVE 0 -#define QLA82XX_DRV_ACTIVE 1 - -/* - * The PCI VendorID and DeviceID for our board. - */ -#define PCI_DEVICE_ID_QLOGIC_ISP8021 0x8021 - -#define QLA82XX_MSIX_TBL_SPACE 8192 -#define QLA82XX_PCI_REG_MSIX_TBL 0x44 -#define QLA82XX_PCI_MSIX_CONTROL 0x40 - -struct crb_128M_2M_sub_block_map { - unsigned valid; - unsigned start_128M; - unsigned end_128M; - unsigned start_2M; -}; - -struct crb_128M_2M_block_map { - struct crb_128M_2M_sub_block_map sub_block[16]; -}; - -struct crb_addr_pair { - long addr; - long data; -}; - -#define ADDR_ERROR ((unsigned long) 0xffffffff) -#define MAX_CTL_CHECK 1000 - -/*************************************************************************** - * PCI related defines. - **************************************************************************/ - -/* - * Interrupt related defines. - */ -#define PCIX_TARGET_STATUS (0x10118) -#define PCIX_TARGET_STATUS_F1 (0x10160) -#define PCIX_TARGET_STATUS_F2 (0x10164) -#define PCIX_TARGET_STATUS_F3 (0x10168) -#define PCIX_TARGET_STATUS_F4 (0x10360) -#define PCIX_TARGET_STATUS_F5 (0x10364) -#define PCIX_TARGET_STATUS_F6 (0x10368) -#define PCIX_TARGET_STATUS_F7 (0x1036c) - -#define PCIX_TARGET_MASK (0x10128) -#define PCIX_TARGET_MASK_F1 (0x10170) -#define PCIX_TARGET_MASK_F2 (0x10174) -#define PCIX_TARGET_MASK_F3 (0x10178) -#define PCIX_TARGET_MASK_F4 (0x10370) -#define PCIX_TARGET_MASK_F5 (0x10374) -#define PCIX_TARGET_MASK_F6 (0x10378) -#define PCIX_TARGET_MASK_F7 (0x1037c) - -/* - * Message Signaled Interrupts - */ -#define PCIX_MSI_F0 (0x13000) -#define PCIX_MSI_F1 (0x13004) -#define PCIX_MSI_F2 (0x13008) -#define PCIX_MSI_F3 (0x1300c) -#define PCIX_MSI_F4 (0x13010) -#define PCIX_MSI_F5 (0x13014) -#define PCIX_MSI_F6 (0x13018) -#define PCIX_MSI_F7 (0x1301c) -#define PCIX_MSI_F(FUNC) (0x13000 + ((FUNC) * 4)) -#define PCIX_INT_VECTOR (0x10100) -#define PCIX_INT_MASK (0x10104) - -/* - * Interrupt state machine and other bits. - */ -#define PCIE_MISCCFG_RC (0x1206c) - -#define ISR_INT_TARGET_STATUS \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS)) -#define ISR_INT_TARGET_STATUS_F1 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F1)) -#define ISR_INT_TARGET_STATUS_F2 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F2)) -#define ISR_INT_TARGET_STATUS_F3 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F3)) -#define ISR_INT_TARGET_STATUS_F4 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F4)) -#define ISR_INT_TARGET_STATUS_F5 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F5)) -#define ISR_INT_TARGET_STATUS_F6 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F6)) -#define ISR_INT_TARGET_STATUS_F7 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F7)) - -#define ISR_INT_TARGET_MASK \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK)) -#define ISR_INT_TARGET_MASK_F1 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F1)) -#define ISR_INT_TARGET_MASK_F2 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F2)) -#define ISR_INT_TARGET_MASK_F3 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F3)) -#define ISR_INT_TARGET_MASK_F4 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F4)) -#define ISR_INT_TARGET_MASK_F5 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F5)) -#define ISR_INT_TARGET_MASK_F6 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F6)) -#define ISR_INT_TARGET_MASK_F7 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F7)) - -#define ISR_INT_VECTOR \ - (QLA82XX_PCIX_PS_REG(PCIX_INT_VECTOR)) -#define ISR_INT_MASK \ - (QLA82XX_PCIX_PS_REG(PCIX_INT_MASK)) -#define ISR_INT_STATE_REG \ - (QLA82XX_PCIX_PS_REG(PCIE_MISCCFG_RC)) - -#define ISR_MSI_INT_TRIGGER(FUNC) \ - (QLA82XX_PCIX_PS_REG(PCIX_MSI_F(FUNC))) - -#define ISR_IS_LEGACY_INTR_IDLE(VAL) (((VAL) & 0x300) == 0) -#define ISR_IS_LEGACY_INTR_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200) - -/* - * PCI Interrupt Vector Values. - */ -#define PCIX_INT_VECTOR_BIT_F0 0x0080 -#define PCIX_INT_VECTOR_BIT_F1 0x0100 -#define PCIX_INT_VECTOR_BIT_F2 0x0200 -#define PCIX_INT_VECTOR_BIT_F3 0x0400 -#define PCIX_INT_VECTOR_BIT_F4 0x0800 -#define PCIX_INT_VECTOR_BIT_F5 0x1000 -#define PCIX_INT_VECTOR_BIT_F6 0x2000 -#define PCIX_INT_VECTOR_BIT_F7 0x4000 - -struct qla82xx_legacy_intr_set { - uint32_t int_vec_bit; - uint32_t tgt_status_reg; - uint32_t tgt_mask_reg; - uint32_t pci_int_reg; -}; - -#define QLA82XX_LEGACY_INTR_CONFIG \ -{ \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F0, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(0) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F1, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F1, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F1, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(1) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F2, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F2, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F2, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(2) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F3, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F3, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F3, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(3) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F4, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F4, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F4, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(4) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F5, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F5, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F5, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(5) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F6, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F6, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F6, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(6) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F7, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F7, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F7, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \ -} - -#define BRDCFG_START 0x4000 -#define BOOTLD_START 0x10000 -#define IMAGE_START 0x100000 -#define FLASH_ADDR_START 0x43000 - -/* Magic number to let user know flash is programmed */ -#define QLA82XX_BDINFO_MAGIC 0x12345678 -#define QLA82XX_FW_MAGIC_OFFSET (BRDCFG_START + 0x128) -#define FW_SIZE_OFFSET (0x3e840c) -#define QLA82XX_FW_MIN_SIZE 0x3fffff - -/* UNIFIED ROMIMAGE START */ -#define QLA82XX_URI_FW_MIN_SIZE 0xc8000 -#define QLA82XX_URI_DIR_SECT_PRODUCT_TBL 0x0 -#define QLA82XX_URI_DIR_SECT_BOOTLD 0x6 -#define QLA82XX_URI_DIR_SECT_FW 0x7 - -/* Offsets */ -#define QLA82XX_URI_CHIP_REV_OFF 10 -#define QLA82XX_URI_FLAGS_OFF 11 -#define QLA82XX_URI_BIOS_VERSION_OFF 12 -#define QLA82XX_URI_BOOTLD_IDX_OFF 27 -#define QLA82XX_URI_FIRMWARE_IDX_OFF 29 - -struct qla82xx_uri_table_desc{ - uint32_t findex; - uint32_t num_entries; - uint32_t entry_size; - uint32_t reserved[5]; -}; - -struct qla82xx_uri_data_desc{ - uint32_t findex; - uint32_t size; - uint32_t reserved[5]; -}; - -/* UNIFIED ROMIMAGE END */ - -#define QLA82XX_UNIFIED_ROMIMAGE 3 -#define QLA82XX_FLASH_ROMIMAGE 4 -#define QLA82XX_UNKNOWN_ROMIMAGE 0xff - -#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) -#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4) - -#ifndef readq -static inline u64 readq(void __iomem *addr) -{ - return readl(addr) | (((u64) readl(addr + 4)) << 32LL); -} -#endif - -#ifndef writeq -static inline void writeq(u64 val, void __iomem *addr) -{ - writel(((u32) (val)), (addr)); - writel(((u32) (val >> 32)), (addr + 4)); -} -#endif - -/* Request and response queue size */ -#define REQUEST_ENTRY_CNT_82XX 128 /* Number of request entries. */ -#define RESPONSE_ENTRY_CNT_82XX 128 /* Number of response entries.*/ - -/* - * ISP 8021 I/O Register Set structure definitions. - */ -struct device_reg_82xx { - uint32_t req_q_out[64]; /* Request Queue out-Pointer (64 * 4) */ - uint32_t rsp_q_in[64]; /* Response Queue In-Pointer. */ - uint32_t rsp_q_out[64]; /* Response Queue Out-Pointer. */ - - uint16_t mailbox_in[32]; /* Mail box In registers */ - uint16_t unused_1[32]; - uint32_t hint; /* Host interrupt register */ -#define HINT_MBX_INT_PENDING BIT_0 - uint16_t unused_2[62]; - uint16_t mailbox_out[32]; /* Mail box Out registers */ - uint32_t unused_3[48]; - - uint32_t host_status; /* host status */ -#define HSRX_RISC_INT BIT_15 /* RISC to Host interrupt. */ -#define HSRX_RISC_PAUSED BIT_8 /* RISC Paused. */ - uint32_t host_int; /* Interrupt status. */ -#define ISRX_NX_RISC_INT BIT_0 /* RISC interrupt. */ -}; - -struct fcp_cmnd { - struct scsi_lun lun; - uint8_t crn; - uint8_t task_attribute; - uint8_t task_management; - uint8_t additional_cdb_len; - uint8_t cdb[260]; /* 256 for CDB len and 4 for FCP_DL */ -}; - -struct dsd_dma { - struct list_head list; - dma_addr_t dsd_list_dma; - void *dsd_addr; -}; - -#define QLA_DSDS_PER_IOCB 37 -#define QLA_DSD_SIZE 12 -struct ct6_dsd { - uint16_t fcp_cmnd_len; - dma_addr_t fcp_cmnd_dma; - struct fcp_cmnd *fcp_cmnd; - int dsd_use_cnt; - struct list_head dsd_list; -}; - -#define MBC_TOGGLE_INTERRUPT 0x10 -#define MBC_SET_LED_CONFIG 0x125 /* FCoE specific LED control */ -#define MBC_GET_LED_CONFIG 0x126 /* FCoE specific LED control */ - -/* Flash offset */ -#define FLT_REG_BOOTLOAD_82XX 0x72 -#define FLT_REG_BOOT_CODE_82XX 0x78 -#define FLT_REG_FW_82XX 0x74 -#define FLT_REG_GOLD_FW_82XX 0x75 -#define FLT_REG_VPD_82XX 0x81 - -#define FA_VPD_SIZE_82XX 0x400 - -#define FA_FLASH_LAYOUT_ADDR_82 0xFC400 - -/****************************************************************************** -* -* Definitions specific to M25P flash -* -******************************************************************************* -* Instructions -*/ -#define M25P_INSTR_WREN 0x06 -#define M25P_INSTR_WRDI 0x04 -#define M25P_INSTR_RDID 0x9f -#define M25P_INSTR_RDSR 0x05 -#define M25P_INSTR_WRSR 0x01 -#define M25P_INSTR_READ 0x03 -#define M25P_INSTR_FAST_READ 0x0b -#define M25P_INSTR_PP 0x02 -#define M25P_INSTR_SE 0xd8 -#define M25P_INSTR_BE 0xc7 -#define M25P_INSTR_DP 0xb9 -#define M25P_INSTR_RES 0xab - -/* Minidump related */ - -/* - * Version of the template - * 4 Bytes - * X.Major.Minor.RELEASE - */ -#define QLA82XX_MINIDUMP_VERSION 0x10101 - -/* - * Entry Type Defines - */ -#define QLA82XX_RDNOP 0 -#define QLA82XX_RDCRB 1 -#define QLA82XX_RDMUX 2 -#define QLA82XX_QUEUE 3 -#define QLA82XX_BOARD 4 -#define QLA82XX_RDSRE 5 -#define QLA82XX_RDOCM 6 -#define QLA82XX_CACHE 10 -#define QLA82XX_L1DAT 11 -#define QLA82XX_L1INS 12 -#define QLA82XX_L2DTG 21 -#define QLA82XX_L2ITG 22 -#define QLA82XX_L2DAT 23 -#define QLA82XX_L2INS 24 -#define QLA82XX_RDROM 71 -#define QLA82XX_RDMEM 72 -#define QLA82XX_CNTRL 98 -#define QLA82XX_TLHDR 99 -#define QLA82XX_RDEND 255 - -/* - * Opcodes for Control Entries. - * These Flags are bit fields. - */ -#define QLA82XX_DBG_OPCODE_WR 0x01 -#define QLA82XX_DBG_OPCODE_RW 0x02 -#define QLA82XX_DBG_OPCODE_AND 0x04 -#define QLA82XX_DBG_OPCODE_OR 0x08 -#define QLA82XX_DBG_OPCODE_POLL 0x10 -#define QLA82XX_DBG_OPCODE_RDSTATE 0x20 -#define QLA82XX_DBG_OPCODE_WRSTATE 0x40 -#define QLA82XX_DBG_OPCODE_MDSTATE 0x80 - -/* - * Template Header and Entry Header definitions start here. - */ - -/* - * Template Header - * Parts of the template header can be modified by the driver. - * These include the saved_state_array, capture_debug_level, driver_timestamp - */ - -#define QLA82XX_DBG_STATE_ARRAY_LEN 16 -#define QLA82XX_DBG_CAP_SIZE_ARRAY_LEN 8 -#define QLA82XX_DBG_RSVD_ARRAY_LEN 8 - -/* - * Driver Flags - */ -#define QLA82XX_DBG_SKIPPED_FLAG 0x80 /* driver skipped this entry */ -#define QLA82XX_DEFAULT_CAP_MASK 0xFF /* default capture mask */ - -struct qla82xx_md_template_hdr { - uint32_t entry_type; - uint32_t first_entry_offset; - uint32_t size_of_template; - uint32_t capture_debug_level; - - uint32_t num_of_entries; - uint32_t version; - uint32_t driver_timestamp; - uint32_t template_checksum; - - uint32_t driver_capture_mask; - uint32_t driver_info[3]; - - uint32_t saved_state_array[QLA82XX_DBG_STATE_ARRAY_LEN]; - uint32_t capture_size_array[QLA82XX_DBG_CAP_SIZE_ARRAY_LEN]; - - /* markers_array used to capture some special locations on board */ - uint32_t markers_array[QLA82XX_DBG_RSVD_ARRAY_LEN]; - uint32_t num_of_free_entries; /* For internal use */ - uint32_t free_entry_offset; /* For internal use */ - uint32_t total_table_size; /* For internal use */ - uint32_t bkup_table_offset; /* For internal use */ -} __packed; - -/* - * Entry Header: Common to All Entry Types - */ - -/* - * Driver Code is for driver to write some info about the entry. - * Currently not used. - */ -typedef struct qla82xx_md_entry_hdr { - uint32_t entry_type; - uint32_t entry_size; - uint32_t entry_capture_size; - struct { - uint8_t entry_capture_mask; - uint8_t entry_code; - uint8_t driver_code; - uint8_t driver_flags; - } d_ctrl; -} __packed qla82xx_md_entry_hdr_t; - -/* - * Read CRB entry header - */ -struct qla82xx_md_entry_crb { - qla82xx_md_entry_hdr_t h; - uint32_t addr; - struct { - uint8_t addr_stride; - uint8_t state_index_a; - uint16_t poll_timeout; - } crb_strd; - - uint32_t data_size; - uint32_t op_count; - - struct { - uint8_t opcode; - uint8_t state_index_v; - uint8_t shl; - uint8_t shr; - } crb_ctrl; - - uint32_t value_1; - uint32_t value_2; - uint32_t value_3; -} __packed; - -/* - * Cache entry header - */ -struct qla82xx_md_entry_cache { - qla82xx_md_entry_hdr_t h; - - uint32_t tag_reg_addr; - struct { - uint16_t tag_value_stride; - uint16_t init_tag_value; - } addr_ctrl; - - uint32_t data_size; - uint32_t op_count; - - uint32_t control_addr; - struct { - uint16_t write_value; - uint8_t poll_mask; - uint8_t poll_wait; - } cache_ctrl; - - uint32_t read_addr; - struct { - uint8_t read_addr_stride; - uint8_t read_addr_cnt; - uint16_t rsvd_1; - } read_ctrl; -} __packed; - -/* - * Read OCM - */ -struct qla82xx_md_entry_rdocm { - qla82xx_md_entry_hdr_t h; - - uint32_t rsvd_0; - uint32_t rsvd_1; - uint32_t data_size; - uint32_t op_count; - - uint32_t rsvd_2; - uint32_t rsvd_3; - uint32_t read_addr; - uint32_t read_addr_stride; - uint32_t read_addr_cntrl; -} __packed; - -/* - * Read Memory - */ -struct qla82xx_md_entry_rdmem { - qla82xx_md_entry_hdr_t h; - uint32_t rsvd[6]; - uint32_t read_addr; - uint32_t read_data_size; -} __packed; - -/* - * Read ROM - */ -struct qla82xx_md_entry_rdrom { - qla82xx_md_entry_hdr_t h; - uint32_t rsvd[6]; - uint32_t read_addr; - uint32_t read_data_size; -} __packed; - -struct qla82xx_md_entry_mux { - qla82xx_md_entry_hdr_t h; - - uint32_t select_addr; - uint32_t rsvd_0; - uint32_t data_size; - uint32_t op_count; - - uint32_t select_value; - uint32_t select_value_stride; - uint32_t read_addr; - uint32_t rsvd_1; -} __packed; - -struct qla82xx_md_entry_queue { - qla82xx_md_entry_hdr_t h; - - uint32_t select_addr; - struct { - uint16_t queue_id_stride; - uint16_t rsvd_0; - } q_strd; - - uint32_t data_size; - uint32_t op_count; - uint32_t rsvd_1; - uint32_t rsvd_2; - - uint32_t read_addr; - struct { - uint8_t read_addr_stride; - uint8_t read_addr_cnt; - uint16_t rsvd_3; - } rd_strd; -} __packed; - -#define MBC_DIAGNOSTIC_MINIDUMP_TEMPLATE 0x129 -#define RQST_TMPLT_SIZE 0x0 -#define RQST_TMPLT 0x1 -#define MD_DIRECT_ROM_WINDOW 0x42110030 -#define MD_DIRECT_ROM_READ_BASE 0x42150000 -#define MD_MIU_TEST_AGT_CTRL 0x41000090 -#define MD_MIU_TEST_AGT_ADDR_LO 0x41000094 -#define MD_MIU_TEST_AGT_ADDR_HI 0x41000098 - -static const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8, 0x410000AC, - 0x410000B8, 0x410000BC }; - -#define CRB_NIU_XG_PAUSE_CTL_P0 0x1 -#define CRB_NIU_XG_PAUSE_CTL_P1 0x8 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_os.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_os.c deleted file mode 100644 index 7db80337..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_os.c +++ /dev/null @@ -1,4533 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * Driver version - */ -char qla2x00_version_str[40]; - -static int apidev_major; - -/* - * SRB allocation cache - */ -static struct kmem_cache *srb_cachep; - -/* - * CT6 CTX allocation cache - */ -static struct kmem_cache *ctx_cachep; -/* - * error level for logging - */ -int ql_errlev = ql_log_all; - -int ql2xlogintimeout = 20; -module_param(ql2xlogintimeout, int, S_IRUGO); -MODULE_PARM_DESC(ql2xlogintimeout, - "Login timeout value in seconds."); - -int qlport_down_retry; -module_param(qlport_down_retry, int, S_IRUGO); -MODULE_PARM_DESC(qlport_down_retry, - "Maximum number of command retries to a port that returns " - "a PORT-DOWN status."); - -int ql2xplogiabsentdevice; -module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql2xplogiabsentdevice, - "Option to enable PLOGI to devices that are not present after " - "a Fabric scan. This is needed for several broken switches. " - "Default is 0 - no PLOGI. 1 - perfom PLOGI."); - -int ql2xloginretrycount = 0; -module_param(ql2xloginretrycount, int, S_IRUGO); -MODULE_PARM_DESC(ql2xloginretrycount, - "Specify an alternate value for the NVRAM login retry count."); - -int ql2xallocfwdump = 1; -module_param(ql2xallocfwdump, int, S_IRUGO); -MODULE_PARM_DESC(ql2xallocfwdump, - "Option to enable allocation of memory for a firmware dump " - "during HBA initialization. Memory allocation requirements " - "vary by ISP type. Default is 1 - allocate memory."); - -int ql2xextended_error_logging; -module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql2xextended_error_logging, - "Option to enable extended error logging,\n" - "\t\tDefault is 0 - no logging. 0x40000000 - Module Init & Probe.\n" - "\t\t0x20000000 - Mailbox Cmnds. 0x10000000 - Device Discovery.\n" - "\t\t0x08000000 - IO tracing. 0x04000000 - DPC Thread.\n" - "\t\t0x02000000 - Async events. 0x01000000 - Timer routines.\n" - "\t\t0x00800000 - User space. 0x00400000 - Task Management.\n" - "\t\t0x00200000 - AER/EEH. 0x00100000 - Multi Q.\n" - "\t\t0x00080000 - P3P Specific. 0x00040000 - Virtual Port.\n" - "\t\t0x00020000 - Buffer Dump. 0x00010000 - Misc.\n" - "\t\t0x7fffffff - For enabling all logs, can be too many logs.\n" - "\t\t0x1e400000 - Preferred value for capturing essential " - "debug information (equivalent to old " - "ql2xextended_error_logging=1).\n" - "\t\tDo LOGICAL OR of the value to enable more than one level"); - -int ql2xshiftctondsd = 6; -module_param(ql2xshiftctondsd, int, S_IRUGO); -MODULE_PARM_DESC(ql2xshiftctondsd, - "Set to control shifting of command type processing " - "based on total number of SG elements."); - -static void qla2x00_free_device(scsi_qla_host_t *); - -int ql2xfdmienable=1; -module_param(ql2xfdmienable, int, S_IRUGO); -MODULE_PARM_DESC(ql2xfdmienable, - "Enables FDMI registrations. " - "0 - no FDMI. Default is 1 - perform FDMI."); - -#define MAX_Q_DEPTH 32 -static int ql2xmaxqdepth = MAX_Q_DEPTH; -module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql2xmaxqdepth, - "Maximum queue depth to report for target devices."); - -/* Do not change the value of this after module load */ -int ql2xenabledif = 0; -module_param(ql2xenabledif, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql2xenabledif, - " Enable T10-CRC-DIF " - " Default is 0 - No DIF Support. 1 - Enable it" - ", 2 - Enable DIF for all types, except Type 0."); - -int ql2xenablehba_err_chk = 2; -module_param(ql2xenablehba_err_chk, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql2xenablehba_err_chk, - " Enable T10-CRC-DIF Error isolation by HBA:\n" - " Default is 1.\n" - " 0 -- Error isolation disabled\n" - " 1 -- Error isolation enabled only for DIX Type 0\n" - " 2 -- Error isolation enabled for all Types\n"); - -int ql2xiidmaenable=1; -module_param(ql2xiidmaenable, int, S_IRUGO); -MODULE_PARM_DESC(ql2xiidmaenable, - "Enables iIDMA settings " - "Default is 1 - perform iIDMA. 0 - no iIDMA."); - -int ql2xmaxqueues = 1; -module_param(ql2xmaxqueues, int, S_IRUGO); -MODULE_PARM_DESC(ql2xmaxqueues, - "Enables MQ settings " - "Default is 1 for single queue. Set it to number " - "of queues in MQ mode."); - -int ql2xmultique_tag; -module_param(ql2xmultique_tag, int, S_IRUGO); -MODULE_PARM_DESC(ql2xmultique_tag, - "Enables CPU affinity settings for the driver " - "Default is 0 for no affinity of request and response IO. " - "Set it to 1 to turn on the cpu affinity."); - -int ql2xfwloadbin; -module_param(ql2xfwloadbin, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql2xfwloadbin, - "Option to specify location from which to load ISP firmware:.\n" - " 2 -- load firmware via the request_firmware() (hotplug).\n" - " interface.\n" - " 1 -- load firmware from flash.\n" - " 0 -- use default semantics.\n"); - -int ql2xetsenable; -module_param(ql2xetsenable, int, S_IRUGO); -MODULE_PARM_DESC(ql2xetsenable, - "Enables firmware ETS burst." - "Default is 0 - skip ETS enablement."); - -int ql2xdbwr = 1; -module_param(ql2xdbwr, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql2xdbwr, - "Option to specify scheme for request queue posting.\n" - " 0 -- Regular doorbell.\n" - " 1 -- CAMRAM doorbell (faster).\n"); - -int ql2xtargetreset = 1; -module_param(ql2xtargetreset, int, S_IRUGO); -MODULE_PARM_DESC(ql2xtargetreset, - "Enable target reset." - "Default is 1 - use hw defaults."); - -int ql2xgffidenable; -module_param(ql2xgffidenable, int, S_IRUGO); -MODULE_PARM_DESC(ql2xgffidenable, - "Enables GFF_ID checks of port type. " - "Default is 0 - Do not use GFF_ID information."); - -int ql2xasynctmfenable; -module_param(ql2xasynctmfenable, int, S_IRUGO); -MODULE_PARM_DESC(ql2xasynctmfenable, - "Enables issue of TM IOCBs asynchronously via IOCB mechanism" - "Default is 0 - Issue TM IOCBs via mailbox mechanism."); - -int ql2xdontresethba; -module_param(ql2xdontresethba, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql2xdontresethba, - "Option to specify reset behaviour.\n" - " 0 (Default) -- Reset on failure.\n" - " 1 -- Do not reset on failure.\n"); - -uint ql2xmaxlun = MAX_LUNS; -module_param(ql2xmaxlun, uint, S_IRUGO); -MODULE_PARM_DESC(ql2xmaxlun, - "Defines the maximum LU number to register with the SCSI " - "midlayer. Default is 65535."); - -int ql2xmdcapmask = 0x1F; -module_param(ql2xmdcapmask, int, S_IRUGO); -MODULE_PARM_DESC(ql2xmdcapmask, - "Set the Minidump driver capture mask level. " - "Default is 0x1F - Can be set to 0x3, 0x7, 0xF, 0x1F, 0x7F."); - -int ql2xmdenable = 1; -module_param(ql2xmdenable, int, S_IRUGO); -MODULE_PARM_DESC(ql2xmdenable, - "Enable/disable MiniDump. " - "0 - MiniDump disabled. " - "1 (Default) - MiniDump enabled."); - -/* - * SCSI host template entry points - */ -static int qla2xxx_slave_configure(struct scsi_device * device); -static int qla2xxx_slave_alloc(struct scsi_device *); -static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time); -static void qla2xxx_scan_start(struct Scsi_Host *); -static void qla2xxx_slave_destroy(struct scsi_device *); -static int qla2xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); -static int qla2xxx_eh_abort(struct scsi_cmnd *); -static int qla2xxx_eh_device_reset(struct scsi_cmnd *); -static int qla2xxx_eh_target_reset(struct scsi_cmnd *); -static int qla2xxx_eh_bus_reset(struct scsi_cmnd *); -static int qla2xxx_eh_host_reset(struct scsi_cmnd *); - -static int qla2x00_change_queue_depth(struct scsi_device *, int, int); -static int qla2x00_change_queue_type(struct scsi_device *, int); - -struct scsi_host_template qla2xxx_driver_template = { - .module = THIS_MODULE, - .name = QLA2XXX_DRIVER_NAME, - .queuecommand = qla2xxx_queuecommand, - - .eh_abort_handler = qla2xxx_eh_abort, - .eh_device_reset_handler = qla2xxx_eh_device_reset, - .eh_target_reset_handler = qla2xxx_eh_target_reset, - .eh_bus_reset_handler = qla2xxx_eh_bus_reset, - .eh_host_reset_handler = qla2xxx_eh_host_reset, - - .slave_configure = qla2xxx_slave_configure, - - .slave_alloc = qla2xxx_slave_alloc, - .slave_destroy = qla2xxx_slave_destroy, - .scan_finished = qla2xxx_scan_finished, - .scan_start = qla2xxx_scan_start, - .change_queue_depth = qla2x00_change_queue_depth, - .change_queue_type = qla2x00_change_queue_type, - .this_id = -1, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = SG_ALL, - - .max_sectors = 0xFFFF, - .shost_attrs = qla2x00_host_attrs, -}; - -static struct scsi_transport_template *qla2xxx_transport_template = NULL; -struct scsi_transport_template *qla2xxx_transport_vport_template = NULL; - -/* TODO Convert to inlines - * - * Timer routines - */ - -__inline__ void -qla2x00_start_timer(scsi_qla_host_t *vha, void *func, unsigned long interval) -{ - init_timer(&vha->timer); - vha->timer.expires = jiffies + interval * HZ; - vha->timer.data = (unsigned long)vha; - vha->timer.function = (void (*)(unsigned long))func; - add_timer(&vha->timer); - vha->timer_active = 1; -} - -static inline void -qla2x00_restart_timer(scsi_qla_host_t *vha, unsigned long interval) -{ - /* Currently used for 82XX only. */ - if (vha->device_flags & DFLG_DEV_FAILED) { - ql_dbg(ql_dbg_timer, vha, 0x600d, - "Device in a failed state, returning.\n"); - return; - } - - mod_timer(&vha->timer, jiffies + interval * HZ); -} - -static __inline__ void -qla2x00_stop_timer(scsi_qla_host_t *vha) -{ - del_timer_sync(&vha->timer); - vha->timer_active = 0; -} - -static int qla2x00_do_dpc(void *data); - -static void qla2x00_rst_aen(scsi_qla_host_t *); - -static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t, - struct req_que **, struct rsp_que **); -static void qla2x00_free_fw_dump(struct qla_hw_data *); -static void qla2x00_mem_free(struct qla_hw_data *); - -/* -------------------------------------------------------------------------- */ -static int qla2x00_alloc_queues(struct qla_hw_data *ha) -{ - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - ha->req_q_map = kzalloc(sizeof(struct req_que *) * ha->max_req_queues, - GFP_KERNEL); - if (!ha->req_q_map) { - ql_log(ql_log_fatal, vha, 0x003b, - "Unable to allocate memory for request queue ptrs.\n"); - goto fail_req_map; - } - - ha->rsp_q_map = kzalloc(sizeof(struct rsp_que *) * ha->max_rsp_queues, - GFP_KERNEL); - if (!ha->rsp_q_map) { - ql_log(ql_log_fatal, vha, 0x003c, - "Unable to allocate memory for response queue ptrs.\n"); - goto fail_rsp_map; - } - set_bit(0, ha->rsp_qid_map); - set_bit(0, ha->req_qid_map); - return 1; - -fail_rsp_map: - kfree(ha->req_q_map); - ha->req_q_map = NULL; -fail_req_map: - return -ENOMEM; -} - -static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) -{ - if (req && req->ring) - dma_free_coherent(&ha->pdev->dev, - (req->length + 1) * sizeof(request_t), - req->ring, req->dma); - - kfree(req); - req = NULL; -} - -static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) -{ - if (rsp && rsp->ring) - dma_free_coherent(&ha->pdev->dev, - (rsp->length + 1) * sizeof(response_t), - rsp->ring, rsp->dma); - - kfree(rsp); - rsp = NULL; -} - -static void qla2x00_free_queues(struct qla_hw_data *ha) -{ - struct req_que *req; - struct rsp_que *rsp; - int cnt; - - for (cnt = 0; cnt < ha->max_req_queues; cnt++) { - req = ha->req_q_map[cnt]; - qla2x00_free_req_que(ha, req); - } - kfree(ha->req_q_map); - ha->req_q_map = NULL; - - for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) { - rsp = ha->rsp_q_map[cnt]; - qla2x00_free_rsp_que(ha, rsp); - } - kfree(ha->rsp_q_map); - ha->rsp_q_map = NULL; -} - -static int qla25xx_setup_mode(struct scsi_qla_host *vha) -{ - uint16_t options = 0; - int ques, req, ret; - struct qla_hw_data *ha = vha->hw; - - if (!(ha->fw_attributes & BIT_6)) { - ql_log(ql_log_warn, vha, 0x00d8, - "Firmware is not multi-queue capable.\n"); - goto fail; - } - if (ql2xmultique_tag) { - /* create a request queue for IO */ - options |= BIT_7; - req = qla25xx_create_req_que(ha, options, 0, 0, -1, - QLA_DEFAULT_QUE_QOS); - if (!req) { - ql_log(ql_log_warn, vha, 0x00e0, - "Failed to create request queue.\n"); - goto fail; - } - ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); - vha->req = ha->req_q_map[req]; - options |= BIT_1; - for (ques = 1; ques < ha->max_rsp_queues; ques++) { - ret = qla25xx_create_rsp_que(ha, options, 0, 0, req); - if (!ret) { - ql_log(ql_log_warn, vha, 0x00e8, - "Failed to create response queue.\n"); - goto fail2; - } - } - ha->flags.cpu_affinity_enabled = 1; - ql_dbg(ql_dbg_multiq, vha, 0xc007, - "CPU affinity mode enalbed, " - "no. of response queues:%d no. of request queues:%d.\n", - ha->max_rsp_queues, ha->max_req_queues); - ql_dbg(ql_dbg_init, vha, 0x00e9, - "CPU affinity mode enalbed, " - "no. of response queues:%d no. of request queues:%d.\n", - ha->max_rsp_queues, ha->max_req_queues); - } - return 0; -fail2: - qla25xx_delete_queues(vha); - destroy_workqueue(ha->wq); - ha->wq = NULL; - vha->req = ha->req_q_map[0]; -fail: - ha->mqenable = 0; - kfree(ha->req_q_map); - kfree(ha->rsp_q_map); - ha->max_req_queues = ha->max_rsp_queues = 1; - return 1; -} - -static char * -qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str) -{ - struct qla_hw_data *ha = vha->hw; - static char *pci_bus_modes[] = { - "33", "66", "100", "133", - }; - uint16_t pci_bus; - - strcpy(str, "PCI"); - pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9; - if (pci_bus) { - strcat(str, "-X ("); - strcat(str, pci_bus_modes[pci_bus]); - } else { - pci_bus = (ha->pci_attr & BIT_8) >> 8; - strcat(str, " ("); - strcat(str, pci_bus_modes[pci_bus]); - } - strcat(str, " MHz)"); - - return (str); -} - -static char * -qla24xx_pci_info_str(struct scsi_qla_host *vha, char *str) -{ - static char *pci_bus_modes[] = { "33", "66", "100", "133", }; - struct qla_hw_data *ha = vha->hw; - uint32_t pci_bus; - int pcie_reg; - - pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); - if (pcie_reg) { - char lwstr[6]; - uint16_t pcie_lstat, lspeed, lwidth; - - pcie_reg += 0x12; - pci_read_config_word(ha->pdev, pcie_reg, &pcie_lstat); - lspeed = pcie_lstat & (BIT_0 | BIT_1 | BIT_2 | BIT_3); - lwidth = (pcie_lstat & - (BIT_4 | BIT_5 | BIT_6 | BIT_7 | BIT_8 | BIT_9)) >> 4; - - strcpy(str, "PCIe ("); - if (lspeed == 1) - strcat(str, "2.5GT/s "); - else if (lspeed == 2) - strcat(str, "5.0GT/s "); - else - strcat(str, " "); - snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth); - strcat(str, lwstr); - - return str; - } - - strcpy(str, "PCI"); - pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8; - if (pci_bus == 0 || pci_bus == 8) { - strcat(str, " ("); - strcat(str, pci_bus_modes[pci_bus >> 3]); - } else { - strcat(str, "-X "); - if (pci_bus & BIT_2) - strcat(str, "Mode 2"); - else - strcat(str, "Mode 1"); - strcat(str, " ("); - strcat(str, pci_bus_modes[pci_bus & ~BIT_2]); - } - strcat(str, " MHz)"); - - return str; -} - -static char * -qla2x00_fw_version_str(struct scsi_qla_host *vha, char *str) -{ - char un_str[10]; - struct qla_hw_data *ha = vha->hw; - - sprintf(str, "%d.%02d.%02d ", ha->fw_major_version, - ha->fw_minor_version, - ha->fw_subminor_version); - - if (ha->fw_attributes & BIT_9) { - strcat(str, "FLX"); - return (str); - } - - switch (ha->fw_attributes & 0xFF) { - case 0x7: - strcat(str, "EF"); - break; - case 0x17: - strcat(str, "TP"); - break; - case 0x37: - strcat(str, "IP"); - break; - case 0x77: - strcat(str, "VI"); - break; - default: - sprintf(un_str, "(%x)", ha->fw_attributes); - strcat(str, un_str); - break; - } - if (ha->fw_attributes & 0x100) - strcat(str, "X"); - - return (str); -} - -static char * -qla24xx_fw_version_str(struct scsi_qla_host *vha, char *str) -{ - struct qla_hw_data *ha = vha->hw; - - sprintf(str, "%d.%02d.%02d (%x)", ha->fw_major_version, - ha->fw_minor_version, ha->fw_subminor_version, ha->fw_attributes); - return str; -} - -void -qla2x00_sp_free_dma(void *vha, void *ptr) -{ - srb_t *sp = (srb_t *)ptr; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - struct qla_hw_data *ha = sp->fcport->vha->hw; - void *ctx = GET_CMD_CTX_SP(sp); - - if (sp->flags & SRB_DMA_VALID) { - scsi_dma_unmap(cmd); - sp->flags &= ~SRB_DMA_VALID; - } - - if (sp->flags & SRB_CRC_PROT_DMA_VALID) { - dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), - scsi_prot_sg_count(cmd), cmd->sc_data_direction); - sp->flags &= ~SRB_CRC_PROT_DMA_VALID; - } - - if (sp->flags & SRB_CRC_CTX_DSD_VALID) { - /* List assured to be having elements */ - qla2x00_clean_dsd_pool(ha, sp); - sp->flags &= ~SRB_CRC_CTX_DSD_VALID; - } - - if (sp->flags & SRB_CRC_CTX_DMA_VALID) { - dma_pool_free(ha->dl_dma_pool, ctx, - ((struct crc_context *)ctx)->crc_ctx_dma); - sp->flags &= ~SRB_CRC_CTX_DMA_VALID; - } - - if (sp->flags & SRB_FCP_CMND_DMA_VALID) { - struct ct6_dsd *ctx1 = (struct ct6_dsd *)ctx; - - dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, - ctx1->fcp_cmnd_dma); - list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list); - ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; - ha->gbl_dsd_avail += ctx1->dsd_use_cnt; - mempool_free(ctx1, ha->ctx_mempool); - ctx1 = NULL; - } - - CMD_SP(cmd) = NULL; - mempool_free(sp, ha->srb_mempool); -} - -static void -qla2x00_sp_compl(void *data, void *ptr, int res) -{ - struct qla_hw_data *ha = (struct qla_hw_data *)data; - srb_t *sp = (srb_t *)ptr; - struct scsi_cmnd *cmd = GET_CMD_SP(sp); - - cmd->result = res; - - if (atomic_read(&sp->ref_count) == 0) { - ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3015, - "SP reference-count to ZERO -- sp=%p cmd=%p.\n", - sp, GET_CMD_SP(sp)); - if (ql2xextended_error_logging & ql_dbg_io) - BUG(); - return; - } - if (!atomic_dec_and_test(&sp->ref_count)) - return; - - qla2x00_sp_free_dma(ha, sp); - cmd->scsi_done(cmd); -} - -static int -qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) -{ - scsi_qla_host_t *vha = shost_priv(host); - fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); - struct qla_hw_data *ha = vha->hw; - struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - srb_t *sp; - int rval; - - if (ha->flags.eeh_busy) { - if (ha->flags.pci_channel_io_perm_failure) { - ql_dbg(ql_dbg_io, vha, 0x3001, - "PCI Channel IO permanent failure, exiting " - "cmd=%p.\n", cmd); - cmd->result = DID_NO_CONNECT << 16; - } else { - ql_dbg(ql_dbg_io, vha, 0x3002, - "EEH_Busy, Requeuing the cmd=%p.\n", cmd); - cmd->result = DID_REQUEUE << 16; - } - goto qc24_fail_command; - } - - rval = fc_remote_port_chkready(rport); - if (rval) { - cmd->result = rval; - ql_dbg(ql_dbg_io, vha, 0x3003, - "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n", - cmd, rval); - goto qc24_fail_command; - } - - if (!vha->flags.difdix_supported && - scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { - ql_dbg(ql_dbg_io, vha, 0x3004, - "DIF Cap not reg, fail DIF capable cmd's:%p.\n", - cmd); - cmd->result = DID_NO_CONNECT << 16; - goto qc24_fail_command; - } - - if (!fcport) { - cmd->result = DID_NO_CONNECT << 16; - goto qc24_fail_command; - } - - if (atomic_read(&fcport->state) != FCS_ONLINE) { - if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || - atomic_read(&base_vha->loop_state) == LOOP_DEAD) { - ql_dbg(ql_dbg_io, vha, 0x3005, - "Returning DNC, fcport_state=%d loop_state=%d.\n", - atomic_read(&fcport->state), - atomic_read(&base_vha->loop_state)); - cmd->result = DID_NO_CONNECT << 16; - goto qc24_fail_command; - } - goto qc24_target_busy; - } - - sp = qla2x00_get_sp(base_vha, fcport, GFP_ATOMIC); - if (!sp) - goto qc24_host_busy; - - sp->u.scmd.cmd = cmd; - sp->type = SRB_SCSI_CMD; - atomic_set(&sp->ref_count, 1); - CMD_SP(cmd) = (void *)sp; - sp->free = qla2x00_sp_free_dma; - sp->done = qla2x00_sp_compl; - - rval = ha->isp_ops->start_scsi(sp); - if (rval != QLA_SUCCESS) { - ql_dbg(ql_dbg_io, vha, 0x3013, - "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd); - goto qc24_host_busy_free_sp; - } - - return 0; - -qc24_host_busy_free_sp: - qla2x00_sp_free_dma(ha, sp); - -qc24_host_busy: - return SCSI_MLQUEUE_HOST_BUSY; - -qc24_target_busy: - return SCSI_MLQUEUE_TARGET_BUSY; - -qc24_fail_command: - cmd->scsi_done(cmd); - - return 0; -} - -/* - * qla2x00_eh_wait_on_command - * Waits for the command to be returned by the Firmware for some - * max time. - * - * Input: - * cmd = Scsi Command to wait on. - * - * Return: - * Not Found : 0 - * Found : 1 - */ -static int -qla2x00_eh_wait_on_command(struct scsi_cmnd *cmd) -{ -#define ABORT_POLLING_PERIOD 1000 -#define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD)) - unsigned long wait_iter = ABORT_WAIT_ITER; - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - struct qla_hw_data *ha = vha->hw; - int ret = QLA_SUCCESS; - - if (unlikely(pci_channel_offline(ha->pdev)) || ha->flags.eeh_busy) { - ql_dbg(ql_dbg_taskm, vha, 0x8005, - "Return:eh_wait.\n"); - return ret; - } - - while (CMD_SP(cmd) && wait_iter--) { - msleep(ABORT_POLLING_PERIOD); - } - if (CMD_SP(cmd)) - ret = QLA_FUNCTION_FAILED; - - return ret; -} - -/* - * qla2x00_wait_for_hba_online - * Wait till the HBA is online after going through - * <= MAX_RETRIES_OF_ISP_ABORT or - * finally HBA is disabled ie marked offline - * - * Input: - * ha - pointer to host adapter structure - * - * Note: - * Does context switching-Release SPIN_LOCK - * (if any) before calling this routine. - * - * Return: - * Success (Adapter is online) : 0 - * Failed (Adapter is offline/disabled) : 1 - */ -int -qla2x00_wait_for_hba_online(scsi_qla_host_t *vha) -{ - int return_status; - unsigned long wait_online; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); - while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || - test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || - ha->dpc_active) && time_before(jiffies, wait_online)) { - - msleep(1000); - } - if (base_vha->flags.online) - return_status = QLA_SUCCESS; - else - return_status = QLA_FUNCTION_FAILED; - - return (return_status); -} - -/* - * qla2x00_wait_for_reset_ready - * Wait till the HBA is online after going through - * <= MAX_RETRIES_OF_ISP_ABORT or - * finally HBA is disabled ie marked offline or flash - * operations are in progress. - * - * Input: - * ha - pointer to host adapter structure - * - * Note: - * Does context switching-Release SPIN_LOCK - * (if any) before calling this routine. - * - * Return: - * Success (Adapter is online/no flash ops) : 0 - * Failed (Adapter is offline/disabled/flash ops in progress) : 1 - */ -static int -qla2x00_wait_for_reset_ready(scsi_qla_host_t *vha) -{ - int return_status; - unsigned long wait_online; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); - while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || - test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || - ha->optrom_state != QLA_SWAITING || - ha->dpc_active) && time_before(jiffies, wait_online)) - msleep(1000); - - if (base_vha->flags.online && ha->optrom_state == QLA_SWAITING) - return_status = QLA_SUCCESS; - else - return_status = QLA_FUNCTION_FAILED; - - ql_dbg(ql_dbg_taskm, vha, 0x8019, - "%s return status=%d.\n", __func__, return_status); - - return return_status; -} - -int -qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) -{ - int return_status; - unsigned long wait_reset; - struct qla_hw_data *ha = vha->hw; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ); - while (((test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) || - test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || - test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || - ha->dpc_active) && time_before(jiffies, wait_reset)) { - - msleep(1000); - - if (!test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) && - ha->flags.chip_reset_done) - break; - } - if (ha->flags.chip_reset_done) - return_status = QLA_SUCCESS; - else - return_status = QLA_FUNCTION_FAILED; - - return return_status; -} - -static void -sp_get(struct srb *sp) -{ - atomic_inc(&sp->ref_count); -} - -/************************************************************************** -* qla2xxx_eh_abort -* -* Description: -* The abort function will abort the specified command. -* -* Input: -* cmd = Linux SCSI command packet to be aborted. -* -* Returns: -* Either SUCCESS or FAILED. -* -* Note: -* Only return FAILED if command not returned by firmware. -**************************************************************************/ -static int -qla2xxx_eh_abort(struct scsi_cmnd *cmd) -{ - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - srb_t *sp; - int ret; - unsigned int id, lun; - unsigned long flags; - int wait = 0; - struct qla_hw_data *ha = vha->hw; - - if (!CMD_SP(cmd)) - return SUCCESS; - - ret = fc_block_scsi_eh(cmd); - if (ret != 0) - return ret; - ret = SUCCESS; - - id = cmd->device->id; - lun = cmd->device->lun; - - spin_lock_irqsave(&ha->hardware_lock, flags); - sp = (srb_t *) CMD_SP(cmd); - if (!sp) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return SUCCESS; - } - - ql_dbg(ql_dbg_taskm, vha, 0x8002, - "Aborting from RISC nexus=%ld:%d:%d sp=%p cmd=%p\n", - vha->host_no, id, lun, sp, cmd); - - /* Get a reference to the sp and drop the lock.*/ - sp_get(sp); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (ha->isp_ops->abort_command(sp)) { - ret = FAILED; - ql_dbg(ql_dbg_taskm, vha, 0x8003, - "Abort command mbx failed cmd=%p.\n", cmd); - } else { - ql_dbg(ql_dbg_taskm, vha, 0x8004, - "Abort command mbx success cmd=%p.\n", cmd); - wait = 1; - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - sp->done(ha, sp, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* Did the command return during mailbox execution? */ - if (ret == FAILED && !CMD_SP(cmd)) - ret = SUCCESS; - - /* Wait for the command to be returned. */ - if (wait) { - if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x8006, - "Abort handler timed out cmd=%p.\n", cmd); - ret = FAILED; - } - } - - ql_log(ql_log_info, vha, 0x801c, - "Abort command issued nexus=%ld:%d:%d -- %d %x.\n", - vha->host_no, id, lun, wait, ret); - - return ret; -} - -int -qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *vha, unsigned int t, - unsigned int l, enum nexus_wait_type type) -{ - int cnt, match, status; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - struct req_que *req; - srb_t *sp; - struct scsi_cmnd *cmd; - - status = QLA_SUCCESS; - - spin_lock_irqsave(&ha->hardware_lock, flags); - req = vha->req; - for (cnt = 1; status == QLA_SUCCESS && - cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (!sp) - continue; - if (sp->type != SRB_SCSI_CMD) - continue; - if (vha->vp_idx != sp->fcport->vha->vp_idx) - continue; - match = 0; - cmd = GET_CMD_SP(sp); - switch (type) { - case WAIT_HOST: - match = 1; - break; - case WAIT_TARGET: - match = cmd->device->id == t; - break; - case WAIT_LUN: - match = (cmd->device->id == t && - cmd->device->lun == l); - break; - } - if (!match) - continue; - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - status = qla2x00_eh_wait_on_command(cmd); - spin_lock_irqsave(&ha->hardware_lock, flags); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return status; -} - -static char *reset_errors[] = { - "HBA not online", - "HBA not ready", - "Task management failed", - "Waiting for command completions", -}; - -static int -__qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, - struct scsi_cmnd *cmd, int (*do_reset)(struct fc_port *, unsigned int, int)) -{ - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - int err; - - if (!fcport) { - return FAILED; - } - - err = fc_block_scsi_eh(cmd); - if (err != 0) - return err; - - ql_log(ql_log_info, vha, 0x8009, - "%s RESET ISSUED nexus=%ld:%d:%d cmd=%p.\n", name, vha->host_no, - cmd->device->id, cmd->device->lun, cmd); - - err = 0; - if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x800a, - "Wait for hba online failed for cmd=%p.\n", cmd); - goto eh_reset_failed; - } - err = 2; - if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1) - != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x800c, - "do_reset failed for cmd=%p.\n", cmd); - goto eh_reset_failed; - } - err = 3; - if (qla2x00_eh_wait_for_pending_commands(vha, cmd->device->id, - cmd->device->lun, type) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x800d, - "wait for peding cmds failed for cmd=%p.\n", cmd); - goto eh_reset_failed; - } - - ql_log(ql_log_info, vha, 0x800e, - "%s RESET SUCCEEDED nexus:%ld:%d:%d cmd=%p.\n", name, - vha->host_no, cmd->device->id, cmd->device->lun, cmd); - - return SUCCESS; - -eh_reset_failed: - ql_log(ql_log_info, vha, 0x800f, - "%s RESET FAILED: %s nexus=%ld:%d:%d cmd=%p.\n", name, - reset_errors[err], vha->host_no, cmd->device->id, cmd->device->lun, - cmd); - return FAILED; -} - -static int -qla2xxx_eh_device_reset(struct scsi_cmnd *cmd) -{ - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - struct qla_hw_data *ha = vha->hw; - - return __qla2xxx_eh_generic_reset("DEVICE", WAIT_LUN, cmd, - ha->isp_ops->lun_reset); -} - -static int -qla2xxx_eh_target_reset(struct scsi_cmnd *cmd) -{ - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - struct qla_hw_data *ha = vha->hw; - - return __qla2xxx_eh_generic_reset("TARGET", WAIT_TARGET, cmd, - ha->isp_ops->target_reset); -} - -/************************************************************************** -* qla2xxx_eh_bus_reset -* -* Description: -* The bus reset function will reset the bus and abort any executing -* commands. -* -* Input: -* cmd = Linux SCSI command packet of the command that cause the -* bus reset. -* -* Returns: -* SUCCESS/FAILURE (defined as macro in scsi.h). -* -**************************************************************************/ -static int -qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd) -{ - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; - int ret = FAILED; - unsigned int id, lun; - - id = cmd->device->id; - lun = cmd->device->lun; - - if (!fcport) { - return ret; - } - - ret = fc_block_scsi_eh(cmd); - if (ret != 0) - return ret; - ret = FAILED; - - ql_log(ql_log_info, vha, 0x8012, - "BUS RESET ISSUED nexus=%ld:%d%d.\n", vha->host_no, id, lun); - - if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { - ql_log(ql_log_fatal, vha, 0x8013, - "Wait for hba online failed board disabled.\n"); - goto eh_bus_reset_done; - } - - if (qla2x00_loop_reset(vha) == QLA_SUCCESS) - ret = SUCCESS; - - if (ret == FAILED) - goto eh_bus_reset_done; - - /* Flush outstanding commands. */ - if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) != - QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x8014, - "Wait for pending commands failed.\n"); - ret = FAILED; - } - -eh_bus_reset_done: - ql_log(ql_log_warn, vha, 0x802b, - "BUS RESET %s nexus=%ld:%d:%d.\n", - (ret == FAILED) ? "FAILED" : "SUCCEDED", vha->host_no, id, lun); - - return ret; -} - -/************************************************************************** -* qla2xxx_eh_host_reset -* -* Description: -* The reset function will reset the Adapter. -* -* Input: -* cmd = Linux SCSI command packet of the command that cause the -* adapter reset. -* -* Returns: -* Either SUCCESS or FAILED. -* -* Note: -**************************************************************************/ -static int -qla2xxx_eh_host_reset(struct scsi_cmnd *cmd) -{ - scsi_qla_host_t *vha = shost_priv(cmd->device->host); - struct qla_hw_data *ha = vha->hw; - int ret = FAILED; - unsigned int id, lun; - scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - - id = cmd->device->id; - lun = cmd->device->lun; - - ql_log(ql_log_info, vha, 0x8018, - "ADAPTER RESET ISSUED nexus=%ld:%d:%d.\n", vha->host_no, id, lun); - - if (qla2x00_wait_for_reset_ready(vha) != QLA_SUCCESS) - goto eh_host_reset_lock; - - if (vha != base_vha) { - if (qla2x00_vp_abort_isp(vha)) - goto eh_host_reset_lock; - } else { - if (IS_QLA82XX(vha->hw)) { - if (!qla82xx_fcoe_ctx_reset(vha)) { - /* Ctx reset success */ - ret = SUCCESS; - goto eh_host_reset_lock; - } - /* fall thru if ctx reset failed */ - } - if (ha->wq) - flush_workqueue(ha->wq); - - set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - if (ha->isp_ops->abort_isp(base_vha)) { - clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - /* failed. schedule dpc to try */ - set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags); - - if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x802a, - "wait for hba online failed.\n"); - goto eh_host_reset_lock; - } - } - clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - } - - /* Waiting for command to be returned to OS.*/ - if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, WAIT_HOST) == - QLA_SUCCESS) - ret = SUCCESS; - -eh_host_reset_lock: - ql_log(ql_log_info, vha, 0x8017, - "ADAPTER RESET %s nexus=%ld:%d:%d.\n", - (ret == FAILED) ? "FAILED" : "SUCCEEDED", vha->host_no, id, lun); - - return ret; -} - -/* -* qla2x00_loop_reset -* Issue loop reset. -* -* Input: -* ha = adapter block pointer. -* -* Returns: -* 0 = success -*/ -int -qla2x00_loop_reset(scsi_qla_host_t *vha) -{ - int ret; - struct fc_port *fcport; - struct qla_hw_data *ha = vha->hw; - - if (ql2xtargetreset == 1 && ha->flags.enable_target_reset) { - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (fcport->port_type != FCT_TARGET) - continue; - - ret = ha->isp_ops->target_reset(fcport, 0, 0); - if (ret != QLA_SUCCESS) { - ql_dbg(ql_dbg_taskm, vha, 0x802c, - "Bus Reset failed: Target Reset=%d " - "d_id=%x.\n", ret, fcport->d_id.b24); - } - } - } - - if (ha->flags.enable_lip_full_login && !IS_CNA_CAPABLE(ha)) { - ret = qla2x00_full_login_lip(vha); - if (ret != QLA_SUCCESS) { - ql_dbg(ql_dbg_taskm, vha, 0x802d, - "full_login_lip=%d.\n", ret); - } - atomic_set(&vha->loop_state, LOOP_DOWN); - atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - qla2x00_mark_all_devices_lost(vha, 0); - } - - if (ha->flags.enable_lip_reset) { - ret = qla2x00_lip_reset(vha); - if (ret != QLA_SUCCESS) - ql_dbg(ql_dbg_taskm, vha, 0x802e, - "lip_reset failed (%d).\n", ret); - } - - /* Issue marker command only when we are going to start the I/O */ - vha->marker_needed = 1; - - return QLA_SUCCESS; -} - -void -qla2x00_abort_all_cmds(scsi_qla_host_t *vha, int res) -{ - int que, cnt; - unsigned long flags; - srb_t *sp; - struct qla_hw_data *ha = vha->hw; - struct req_que *req; - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (que = 0; que < ha->max_req_queues; que++) { - req = ha->req_q_map[que]; - if (!req) - continue; - for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) { - sp = req->outstanding_cmds[cnt]; - if (sp) { - req->outstanding_cmds[cnt] = NULL; - sp->done(vha, sp, res); - } - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -static int -qla2xxx_slave_alloc(struct scsi_device *sdev) -{ - struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); - - if (!rport || fc_remote_port_chkready(rport)) - return -ENXIO; - - sdev->hostdata = *(fc_port_t **)rport->dd_data; - - return 0; -} - -static int -qla2xxx_slave_configure(struct scsi_device *sdev) -{ - scsi_qla_host_t *vha = shost_priv(sdev->host); - struct req_que *req = vha->req; - - if (sdev->tagged_supported) - scsi_activate_tcq(sdev, req->max_q_depth); - else - scsi_deactivate_tcq(sdev, req->max_q_depth); - return 0; -} - -static void -qla2xxx_slave_destroy(struct scsi_device *sdev) -{ - sdev->hostdata = NULL; -} - -static void qla2x00_handle_queue_full(struct scsi_device *sdev, int qdepth) -{ - fc_port_t *fcport = (struct fc_port *) sdev->hostdata; - - if (!scsi_track_queue_full(sdev, qdepth)) - return; - - ql_dbg(ql_dbg_io, fcport->vha, 0x3029, - "Queue depth adjusted-down to %d for nexus=%ld:%d:%d.\n", - sdev->queue_depth, fcport->vha->host_no, sdev->id, sdev->lun); -} - -static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth) -{ - fc_port_t *fcport = sdev->hostdata; - struct scsi_qla_host *vha = fcport->vha; - struct req_que *req = NULL; - - req = vha->req; - if (!req) - return; - - if (req->max_q_depth <= sdev->queue_depth || req->max_q_depth < qdepth) - return; - - if (sdev->ordered_tags) - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, qdepth); - else - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, qdepth); - - ql_dbg(ql_dbg_io, vha, 0x302a, - "Queue depth adjusted-up to %d for nexus=%ld:%d:%d.\n", - sdev->queue_depth, fcport->vha->host_no, sdev->id, sdev->lun); -} - -static int -qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason) -{ - switch (reason) { - case SCSI_QDEPTH_DEFAULT: - scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); - break; - case SCSI_QDEPTH_QFULL: - qla2x00_handle_queue_full(sdev, qdepth); - break; - case SCSI_QDEPTH_RAMP_UP: - qla2x00_adjust_sdev_qdepth_up(sdev, qdepth); - break; - default: - return -EOPNOTSUPP; - } - - return sdev->queue_depth; -} - -static int -qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type) -{ - if (sdev->tagged_supported) { - scsi_set_tag_type(sdev, tag_type); - if (tag_type) - scsi_activate_tcq(sdev, sdev->queue_depth); - else - scsi_deactivate_tcq(sdev, sdev->queue_depth); - } else - tag_type = 0; - - return tag_type; -} - -/** - * qla2x00_config_dma_addressing() - Configure OS DMA addressing method. - * @ha: HA context - * - * At exit, the @ha's flags.enable_64bit_addressing set to indicated - * supported addressing method. - */ -static void -qla2x00_config_dma_addressing(struct qla_hw_data *ha) -{ - /* Assume a 32bit DMA mask. */ - ha->flags.enable_64bit_addressing = 0; - - if (!dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(64))) { - /* Any upper-dword bits set? */ - if (MSD(dma_get_required_mask(&ha->pdev->dev)) && - !pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { - /* Ok, a 64bit DMA mask is applicable. */ - ha->flags.enable_64bit_addressing = 1; - ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64; - ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64; - return; - } - } - - dma_set_mask(&ha->pdev->dev, DMA_BIT_MASK(32)); - pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(32)); -} - -static void -qla2x00_enable_intrs(struct qla_hw_data *ha) -{ - unsigned long flags = 0; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->interrupts_on = 1; - /* enable risc and host interrupts */ - WRT_REG_WORD(®->ictrl, ICR_EN_INT | ICR_EN_RISC); - RD_REG_WORD(®->ictrl); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - -} - -static void -qla2x00_disable_intrs(struct qla_hw_data *ha) -{ - unsigned long flags = 0; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->interrupts_on = 0; - /* disable risc and host interrupts */ - WRT_REG_WORD(®->ictrl, 0); - RD_REG_WORD(®->ictrl); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -static void -qla24xx_enable_intrs(struct qla_hw_data *ha) -{ - unsigned long flags = 0; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->interrupts_on = 1; - WRT_REG_DWORD(®->ictrl, ICRX_EN_RISC_INT); - RD_REG_DWORD(®->ictrl); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -static void -qla24xx_disable_intrs(struct qla_hw_data *ha) -{ - unsigned long flags = 0; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - if (IS_NOPOLLING_TYPE(ha)) - return; - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->interrupts_on = 0; - WRT_REG_DWORD(®->ictrl, 0); - RD_REG_DWORD(®->ictrl); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -static int -qla2x00_iospace_config(struct qla_hw_data *ha) -{ - resource_size_t pio; - uint16_t msix; - int cpus; - - if (pci_request_selected_regions(ha->pdev, ha->bars, - QLA2XXX_DRIVER_NAME)) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0011, - "Failed to reserve PIO/MMIO regions (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - if (!(ha->bars & 1)) - goto skip_pio; - - /* We only need PIO for Flash operations on ISP2312 v2 chips. */ - pio = pci_resource_start(ha->pdev, 0); - if (pci_resource_flags(ha->pdev, 0) & IORESOURCE_IO) { - if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) { - ql_log_pci(ql_log_warn, ha->pdev, 0x0012, - "Invalid pci I/O region size (%s).\n", - pci_name(ha->pdev)); - pio = 0; - } - } else { - ql_log_pci(ql_log_warn, ha->pdev, 0x0013, - "Region #0 no a PIO resource (%s).\n", - pci_name(ha->pdev)); - pio = 0; - } - ha->pio_address = pio; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0014, - "PIO address=%llu.\n", - (unsigned long long)ha->pio_address); - -skip_pio: - /* Use MMIO operations for all accesses. */ - if (!(pci_resource_flags(ha->pdev, 1) & IORESOURCE_MEM)) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0015, - "Region #1 not an MMIO resource (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - if (pci_resource_len(ha->pdev, 1) < MIN_IOBASE_LEN) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0016, - "Invalid PCI mem region size (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - - ha->iobase = ioremap(pci_resource_start(ha->pdev, 1), MIN_IOBASE_LEN); - if (!ha->iobase) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0017, - "Cannot remap MMIO (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - - /* Determine queue resources */ - ha->max_req_queues = ha->max_rsp_queues = 1; - if ((ql2xmaxqueues <= 1 && !ql2xmultique_tag) || - (ql2xmaxqueues > 1 && ql2xmultique_tag) || - (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) - goto mqiobase_exit; - - ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), - pci_resource_len(ha->pdev, 3)); - if (ha->mqiobase) { - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0018, - "MQIO Base=%p.\n", ha->mqiobase); - /* Read MSIX vector size of the board */ - pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix); - ha->msix_count = msix; - /* Max queues are bounded by available msix vectors */ - /* queue 0 uses two msix vectors */ - if (ql2xmultique_tag) { - cpus = num_online_cpus(); - ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ? - (cpus + 1) : (ha->msix_count - 1); - ha->max_req_queues = 2; - } else if (ql2xmaxqueues > 1) { - ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? - QLA_MQ_SIZE : ql2xmaxqueues; - ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc008, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0019, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - } - ql_log_pci(ql_log_info, ha->pdev, 0x001a, - "MSI-X vector count: %d.\n", msix); - } else - ql_log_pci(ql_log_info, ha->pdev, 0x001b, - "BAR 3 not enabled.\n"); - -mqiobase_exit: - ha->msix_count = ha->max_rsp_queues + 1; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x001c, - "MSIX Count:%d.\n", ha->msix_count); - return (0); - -iospace_error_exit: - return (-ENOMEM); -} - - -static int -qla83xx_iospace_config(struct qla_hw_data *ha) -{ - uint16_t msix; - int cpus; - - if (pci_request_selected_regions(ha->pdev, ha->bars, - QLA2XXX_DRIVER_NAME)) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0117, - "Failed to reserve PIO/MMIO regions (%s), aborting.\n", - pci_name(ha->pdev)); - - goto iospace_error_exit; - } - - /* Use MMIO operations for all accesses. */ - if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) { - ql_log_pci(ql_log_warn, ha->pdev, 0x0118, - "Invalid pci I/O region size (%s).\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - if (pci_resource_len(ha->pdev, 0) < MIN_IOBASE_LEN) { - ql_log_pci(ql_log_warn, ha->pdev, 0x0119, - "Invalid PCI mem region size (%s), aborting\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - - ha->iobase = ioremap(pci_resource_start(ha->pdev, 0), MIN_IOBASE_LEN); - if (!ha->iobase) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x011a, - "Cannot remap MMIO (%s), aborting.\n", - pci_name(ha->pdev)); - goto iospace_error_exit; - } - - /* 64bit PCI BAR - BAR2 will correspoond to region 4 */ - /* 83XX 26XX always use MQ type access for queues - * - mbar 2, a.k.a region 4 */ - ha->max_req_queues = ha->max_rsp_queues = 1; - ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 4), - pci_resource_len(ha->pdev, 4)); - - if (!ha->mqiobase) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x011d, - "BAR2/region4 not enabled\n"); - goto mqiobase_exit; - } - - ha->msixbase = ioremap(pci_resource_start(ha->pdev, 2), - pci_resource_len(ha->pdev, 2)); - if (ha->msixbase) { - /* Read MSIX vector size of the board */ - pci_read_config_word(ha->pdev, - QLA_83XX_PCI_MSIX_CONTROL, &msix); - ha->msix_count = msix; - /* Max queues are bounded by available msix vectors */ - /* queue 0 uses two msix vectors */ - if (ql2xmultique_tag) { - cpus = num_online_cpus(); - ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ? - (cpus + 1) : (ha->msix_count - 1); - ha->max_req_queues = 2; - } else if (ql2xmaxqueues > 1) { - ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? - QLA_MQ_SIZE : ql2xmaxqueues; - ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc00c, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - } - ql_log_pci(ql_log_info, ha->pdev, 0x011c, - "MSI-X vector count: %d.\n", msix); - } else - ql_log_pci(ql_log_info, ha->pdev, 0x011e, - "BAR 1 not enabled.\n"); - -mqiobase_exit: - ha->msix_count = ha->max_rsp_queues + 1; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011f, - "MSIX Count:%d.\n", ha->msix_count); - return 0; - -iospace_error_exit: - return -ENOMEM; -} - -static struct isp_operations qla2100_isp_ops = { - .pci_config = qla2100_pci_config, - .reset_chip = qla2x00_reset_chip, - .chip_diag = qla2x00_chip_diag, - .config_rings = qla2x00_config_rings, - .reset_adapter = qla2x00_reset_adapter, - .nvram_config = qla2x00_nvram_config, - .update_fw_options = qla2x00_update_fw_options, - .load_risc = qla2x00_load_risc, - .pci_info_str = qla2x00_pci_info_str, - .fw_version_str = qla2x00_fw_version_str, - .intr_handler = qla2100_intr_handler, - .enable_intrs = qla2x00_enable_intrs, - .disable_intrs = qla2x00_disable_intrs, - .abort_command = qla2x00_abort_command, - .target_reset = qla2x00_abort_target, - .lun_reset = qla2x00_lun_reset, - .fabric_login = qla2x00_login_fabric, - .fabric_logout = qla2x00_fabric_logout, - .calc_req_entries = qla2x00_calc_iocbs_32, - .build_iocbs = qla2x00_build_scsi_iocbs_32, - .prep_ms_iocb = qla2x00_prep_ms_iocb, - .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb, - .read_nvram = qla2x00_read_nvram_data, - .write_nvram = qla2x00_write_nvram_data, - .fw_dump = qla2100_fw_dump, - .beacon_on = NULL, - .beacon_off = NULL, - .beacon_blink = NULL, - .read_optrom = qla2x00_read_optrom_data, - .write_optrom = qla2x00_write_optrom_data, - .get_flash_version = qla2x00_get_flash_version, - .start_scsi = qla2x00_start_scsi, - .abort_isp = qla2x00_abort_isp, - .iospace_config = qla2x00_iospace_config, -}; - -static struct isp_operations qla2300_isp_ops = { - .pci_config = qla2300_pci_config, - .reset_chip = qla2x00_reset_chip, - .chip_diag = qla2x00_chip_diag, - .config_rings = qla2x00_config_rings, - .reset_adapter = qla2x00_reset_adapter, - .nvram_config = qla2x00_nvram_config, - .update_fw_options = qla2x00_update_fw_options, - .load_risc = qla2x00_load_risc, - .pci_info_str = qla2x00_pci_info_str, - .fw_version_str = qla2x00_fw_version_str, - .intr_handler = qla2300_intr_handler, - .enable_intrs = qla2x00_enable_intrs, - .disable_intrs = qla2x00_disable_intrs, - .abort_command = qla2x00_abort_command, - .target_reset = qla2x00_abort_target, - .lun_reset = qla2x00_lun_reset, - .fabric_login = qla2x00_login_fabric, - .fabric_logout = qla2x00_fabric_logout, - .calc_req_entries = qla2x00_calc_iocbs_32, - .build_iocbs = qla2x00_build_scsi_iocbs_32, - .prep_ms_iocb = qla2x00_prep_ms_iocb, - .prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb, - .read_nvram = qla2x00_read_nvram_data, - .write_nvram = qla2x00_write_nvram_data, - .fw_dump = qla2300_fw_dump, - .beacon_on = qla2x00_beacon_on, - .beacon_off = qla2x00_beacon_off, - .beacon_blink = qla2x00_beacon_blink, - .read_optrom = qla2x00_read_optrom_data, - .write_optrom = qla2x00_write_optrom_data, - .get_flash_version = qla2x00_get_flash_version, - .start_scsi = qla2x00_start_scsi, - .abort_isp = qla2x00_abort_isp, - .iospace_config = qla2x00_iospace_config, -}; - -static struct isp_operations qla24xx_isp_ops = { - .pci_config = qla24xx_pci_config, - .reset_chip = qla24xx_reset_chip, - .chip_diag = qla24xx_chip_diag, - .config_rings = qla24xx_config_rings, - .reset_adapter = qla24xx_reset_adapter, - .nvram_config = qla24xx_nvram_config, - .update_fw_options = qla24xx_update_fw_options, - .load_risc = qla24xx_load_risc, - .pci_info_str = qla24xx_pci_info_str, - .fw_version_str = qla24xx_fw_version_str, - .intr_handler = qla24xx_intr_handler, - .enable_intrs = qla24xx_enable_intrs, - .disable_intrs = qla24xx_disable_intrs, - .abort_command = qla24xx_abort_command, - .target_reset = qla24xx_abort_target, - .lun_reset = qla24xx_lun_reset, - .fabric_login = qla24xx_login_fabric, - .fabric_logout = qla24xx_fabric_logout, - .calc_req_entries = NULL, - .build_iocbs = NULL, - .prep_ms_iocb = qla24xx_prep_ms_iocb, - .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, - .read_nvram = qla24xx_read_nvram_data, - .write_nvram = qla24xx_write_nvram_data, - .fw_dump = qla24xx_fw_dump, - .beacon_on = qla24xx_beacon_on, - .beacon_off = qla24xx_beacon_off, - .beacon_blink = qla24xx_beacon_blink, - .read_optrom = qla24xx_read_optrom_data, - .write_optrom = qla24xx_write_optrom_data, - .get_flash_version = qla24xx_get_flash_version, - .start_scsi = qla24xx_start_scsi, - .abort_isp = qla2x00_abort_isp, - .iospace_config = qla2x00_iospace_config, -}; - -static struct isp_operations qla25xx_isp_ops = { - .pci_config = qla25xx_pci_config, - .reset_chip = qla24xx_reset_chip, - .chip_diag = qla24xx_chip_diag, - .config_rings = qla24xx_config_rings, - .reset_adapter = qla24xx_reset_adapter, - .nvram_config = qla24xx_nvram_config, - .update_fw_options = qla24xx_update_fw_options, - .load_risc = qla24xx_load_risc, - .pci_info_str = qla24xx_pci_info_str, - .fw_version_str = qla24xx_fw_version_str, - .intr_handler = qla24xx_intr_handler, - .enable_intrs = qla24xx_enable_intrs, - .disable_intrs = qla24xx_disable_intrs, - .abort_command = qla24xx_abort_command, - .target_reset = qla24xx_abort_target, - .lun_reset = qla24xx_lun_reset, - .fabric_login = qla24xx_login_fabric, - .fabric_logout = qla24xx_fabric_logout, - .calc_req_entries = NULL, - .build_iocbs = NULL, - .prep_ms_iocb = qla24xx_prep_ms_iocb, - .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, - .read_nvram = qla25xx_read_nvram_data, - .write_nvram = qla25xx_write_nvram_data, - .fw_dump = qla25xx_fw_dump, - .beacon_on = qla24xx_beacon_on, - .beacon_off = qla24xx_beacon_off, - .beacon_blink = qla24xx_beacon_blink, - .read_optrom = qla25xx_read_optrom_data, - .write_optrom = qla24xx_write_optrom_data, - .get_flash_version = qla24xx_get_flash_version, - .start_scsi = qla24xx_dif_start_scsi, - .abort_isp = qla2x00_abort_isp, - .iospace_config = qla2x00_iospace_config, -}; - -static struct isp_operations qla81xx_isp_ops = { - .pci_config = qla25xx_pci_config, - .reset_chip = qla24xx_reset_chip, - .chip_diag = qla24xx_chip_diag, - .config_rings = qla24xx_config_rings, - .reset_adapter = qla24xx_reset_adapter, - .nvram_config = qla81xx_nvram_config, - .update_fw_options = qla81xx_update_fw_options, - .load_risc = qla81xx_load_risc, - .pci_info_str = qla24xx_pci_info_str, - .fw_version_str = qla24xx_fw_version_str, - .intr_handler = qla24xx_intr_handler, - .enable_intrs = qla24xx_enable_intrs, - .disable_intrs = qla24xx_disable_intrs, - .abort_command = qla24xx_abort_command, - .target_reset = qla24xx_abort_target, - .lun_reset = qla24xx_lun_reset, - .fabric_login = qla24xx_login_fabric, - .fabric_logout = qla24xx_fabric_logout, - .calc_req_entries = NULL, - .build_iocbs = NULL, - .prep_ms_iocb = qla24xx_prep_ms_iocb, - .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, - .read_nvram = NULL, - .write_nvram = NULL, - .fw_dump = qla81xx_fw_dump, - .beacon_on = qla24xx_beacon_on, - .beacon_off = qla24xx_beacon_off, - .beacon_blink = qla83xx_beacon_blink, - .read_optrom = qla25xx_read_optrom_data, - .write_optrom = qla24xx_write_optrom_data, - .get_flash_version = qla24xx_get_flash_version, - .start_scsi = qla24xx_dif_start_scsi, - .abort_isp = qla2x00_abort_isp, - .iospace_config = qla2x00_iospace_config, -}; - -static struct isp_operations qla82xx_isp_ops = { - .pci_config = qla82xx_pci_config, - .reset_chip = qla82xx_reset_chip, - .chip_diag = qla24xx_chip_diag, - .config_rings = qla82xx_config_rings, - .reset_adapter = qla24xx_reset_adapter, - .nvram_config = qla81xx_nvram_config, - .update_fw_options = qla24xx_update_fw_options, - .load_risc = qla82xx_load_risc, - .pci_info_str = qla82xx_pci_info_str, - .fw_version_str = qla24xx_fw_version_str, - .intr_handler = qla82xx_intr_handler, - .enable_intrs = qla82xx_enable_intrs, - .disable_intrs = qla82xx_disable_intrs, - .abort_command = qla24xx_abort_command, - .target_reset = qla24xx_abort_target, - .lun_reset = qla24xx_lun_reset, - .fabric_login = qla24xx_login_fabric, - .fabric_logout = qla24xx_fabric_logout, - .calc_req_entries = NULL, - .build_iocbs = NULL, - .prep_ms_iocb = qla24xx_prep_ms_iocb, - .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, - .read_nvram = qla24xx_read_nvram_data, - .write_nvram = qla24xx_write_nvram_data, - .fw_dump = qla24xx_fw_dump, - .beacon_on = qla82xx_beacon_on, - .beacon_off = qla82xx_beacon_off, - .beacon_blink = NULL, - .read_optrom = qla82xx_read_optrom_data, - .write_optrom = qla82xx_write_optrom_data, - .get_flash_version = qla24xx_get_flash_version, - .start_scsi = qla82xx_start_scsi, - .abort_isp = qla82xx_abort_isp, - .iospace_config = qla82xx_iospace_config, -}; - -static struct isp_operations qla83xx_isp_ops = { - .pci_config = qla25xx_pci_config, - .reset_chip = qla24xx_reset_chip, - .chip_diag = qla24xx_chip_diag, - .config_rings = qla24xx_config_rings, - .reset_adapter = qla24xx_reset_adapter, - .nvram_config = qla81xx_nvram_config, - .update_fw_options = qla81xx_update_fw_options, - .load_risc = qla81xx_load_risc, - .pci_info_str = qla24xx_pci_info_str, - .fw_version_str = qla24xx_fw_version_str, - .intr_handler = qla24xx_intr_handler, - .enable_intrs = qla24xx_enable_intrs, - .disable_intrs = qla24xx_disable_intrs, - .abort_command = qla24xx_abort_command, - .target_reset = qla24xx_abort_target, - .lun_reset = qla24xx_lun_reset, - .fabric_login = qla24xx_login_fabric, - .fabric_logout = qla24xx_fabric_logout, - .calc_req_entries = NULL, - .build_iocbs = NULL, - .prep_ms_iocb = qla24xx_prep_ms_iocb, - .prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb, - .read_nvram = NULL, - .write_nvram = NULL, - .fw_dump = qla83xx_fw_dump, - .beacon_on = qla24xx_beacon_on, - .beacon_off = qla24xx_beacon_off, - .beacon_blink = qla83xx_beacon_blink, - .read_optrom = qla25xx_read_optrom_data, - .write_optrom = qla24xx_write_optrom_data, - .get_flash_version = qla24xx_get_flash_version, - .start_scsi = qla24xx_dif_start_scsi, - .abort_isp = qla2x00_abort_isp, - .iospace_config = qla83xx_iospace_config, -}; - -static inline void -qla2x00_set_isp_flags(struct qla_hw_data *ha) -{ - ha->device_type = DT_EXTENDED_IDS; - switch (ha->pdev->device) { - case PCI_DEVICE_ID_QLOGIC_ISP2100: - ha->device_type |= DT_ISP2100; - ha->device_type &= ~DT_EXTENDED_IDS; - ha->fw_srisc_address = RISC_START_ADDRESS_2100; - break; - case PCI_DEVICE_ID_QLOGIC_ISP2200: - ha->device_type |= DT_ISP2200; - ha->device_type &= ~DT_EXTENDED_IDS; - ha->fw_srisc_address = RISC_START_ADDRESS_2100; - break; - case PCI_DEVICE_ID_QLOGIC_ISP2300: - ha->device_type |= DT_ISP2300; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->fw_srisc_address = RISC_START_ADDRESS_2300; - break; - case PCI_DEVICE_ID_QLOGIC_ISP2312: - ha->device_type |= DT_ISP2312; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->fw_srisc_address = RISC_START_ADDRESS_2300; - break; - case PCI_DEVICE_ID_QLOGIC_ISP2322: - ha->device_type |= DT_ISP2322; - ha->device_type |= DT_ZIO_SUPPORTED; - if (ha->pdev->subsystem_vendor == 0x1028 && - ha->pdev->subsystem_device == 0x0170) - ha->device_type |= DT_OEM_001; - ha->fw_srisc_address = RISC_START_ADDRESS_2300; - break; - case PCI_DEVICE_ID_QLOGIC_ISP6312: - ha->device_type |= DT_ISP6312; - ha->fw_srisc_address = RISC_START_ADDRESS_2300; - break; - case PCI_DEVICE_ID_QLOGIC_ISP6322: - ha->device_type |= DT_ISP6322; - ha->fw_srisc_address = RISC_START_ADDRESS_2300; - break; - case PCI_DEVICE_ID_QLOGIC_ISP2422: - ha->device_type |= DT_ISP2422; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->device_type |= DT_FWI2; - ha->device_type |= DT_IIDMA; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - case PCI_DEVICE_ID_QLOGIC_ISP2432: - ha->device_type |= DT_ISP2432; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->device_type |= DT_FWI2; - ha->device_type |= DT_IIDMA; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - case PCI_DEVICE_ID_QLOGIC_ISP8432: - ha->device_type |= DT_ISP8432; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->device_type |= DT_FWI2; - ha->device_type |= DT_IIDMA; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - case PCI_DEVICE_ID_QLOGIC_ISP5422: - ha->device_type |= DT_ISP5422; - ha->device_type |= DT_FWI2; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - case PCI_DEVICE_ID_QLOGIC_ISP5432: - ha->device_type |= DT_ISP5432; - ha->device_type |= DT_FWI2; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - case PCI_DEVICE_ID_QLOGIC_ISP2532: - ha->device_type |= DT_ISP2532; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->device_type |= DT_FWI2; - ha->device_type |= DT_IIDMA; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - case PCI_DEVICE_ID_QLOGIC_ISP8001: - ha->device_type |= DT_ISP8001; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->device_type |= DT_FWI2; - ha->device_type |= DT_IIDMA; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - case PCI_DEVICE_ID_QLOGIC_ISP8021: - ha->device_type |= DT_ISP8021; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->device_type |= DT_FWI2; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - /* Initialize 82XX ISP flags */ - qla82xx_init_flags(ha); - break; - case PCI_DEVICE_ID_QLOGIC_ISP2031: - ha->device_type |= DT_ISP2031; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->device_type |= DT_FWI2; - ha->device_type |= DT_IIDMA; - ha->device_type |= DT_T10_PI; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - case PCI_DEVICE_ID_QLOGIC_ISP8031: - ha->device_type |= DT_ISP8031; - ha->device_type |= DT_ZIO_SUPPORTED; - ha->device_type |= DT_FWI2; - ha->device_type |= DT_IIDMA; - ha->device_type |= DT_T10_PI; - ha->fw_srisc_address = RISC_START_ADDRESS_2400; - break; - } - - if (IS_QLA82XX(ha)) - ha->port_no = !(ha->portnum & 1); - else - /* Get adapter physical port no from interrupt pin register. */ - pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no); - - if (ha->port_no & 1) - ha->flags.port0 = 1; - else - ha->flags.port0 = 0; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x000b, - "device_type=0x%x port=%d fw_srisc_address=0x%x.\n", - ha->device_type, ha->flags.port0, ha->fw_srisc_address); -} - -static void -qla2xxx_scan_start(struct Scsi_Host *shost) -{ - scsi_qla_host_t *vha = shost_priv(shost); - - if (vha->hw->flags.running_gold_fw) - return; - - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - set_bit(RSCN_UPDATE, &vha->dpc_flags); - set_bit(NPIV_CONFIG_NEEDED, &vha->dpc_flags); -} - -static int -qla2xxx_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - scsi_qla_host_t *vha = shost_priv(shost); - - if (!vha->host) - return 1; - if (time > vha->hw->loop_reset_delay * HZ) - return 1; - - return atomic_read(&vha->loop_state) == LOOP_READY; -} - -/* - * PCI driver interface - */ -static int __devinit -qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) -{ - int ret = -ENODEV; - struct Scsi_Host *host; - scsi_qla_host_t *base_vha = NULL; - struct qla_hw_data *ha; - char pci_info[30]; - char fw_str[30]; - struct scsi_host_template *sht; - int bars, mem_only = 0; - uint16_t req_length = 0, rsp_length = 0; - struct req_que *req = NULL; - struct rsp_que *rsp = NULL; - - bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); - sht = &qla2xxx_driver_template; - if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2432 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8432 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5422 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP5432 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2532 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8001 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8021 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2031 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8031) { - bars = pci_select_bars(pdev, IORESOURCE_MEM); - mem_only = 1; - ql_dbg_pci(ql_dbg_init, pdev, 0x0007, - "Mem only adapter.\n"); - } - ql_dbg_pci(ql_dbg_init, pdev, 0x0008, - "Bars=%d.\n", bars); - - if (mem_only) { - if (pci_enable_device_mem(pdev)) - goto probe_out; - } else { - if (pci_enable_device(pdev)) - goto probe_out; - } - - /* This may fail but that's ok */ - pci_enable_pcie_error_reporting(pdev); - - ha = kzalloc(sizeof(struct qla_hw_data), GFP_KERNEL); - if (!ha) { - ql_log_pci(ql_log_fatal, pdev, 0x0009, - "Unable to allocate memory for ha.\n"); - goto probe_out; - } - ql_dbg_pci(ql_dbg_init, pdev, 0x000a, - "Memory allocated for ha=%p.\n", ha); - ha->pdev = pdev; - - /* Clear our data area */ - ha->bars = bars; - ha->mem_only = mem_only; - spin_lock_init(&ha->hardware_lock); - spin_lock_init(&ha->vport_slock); - - /* Set ISP-type information. */ - qla2x00_set_isp_flags(ha); - - /* Set EEH reset type to fundamental if required by hba */ - if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha)) - pdev->needs_freset = 1; - - ha->prev_topology = 0; - ha->init_cb_size = sizeof(init_cb_t); - ha->link_data_rate = PORT_SPEED_UNKNOWN; - ha->optrom_size = OPTROM_SIZE_2300; - - /* Assign ISP specific operations. */ - if (IS_QLA2100(ha)) { - ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100; - ha->mbx_count = MAILBOX_REGISTER_COUNT_2100; - req_length = REQUEST_ENTRY_CNT_2100; - rsp_length = RESPONSE_ENTRY_CNT_2100; - ha->max_loop_id = SNS_LAST_LOOP_ID_2100; - ha->gid_list_info_size = 4; - ha->flash_conf_off = ~0; - ha->flash_data_off = ~0; - ha->nvram_conf_off = ~0; - ha->nvram_data_off = ~0; - ha->isp_ops = &qla2100_isp_ops; - } else if (IS_QLA2200(ha)) { - ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100; - ha->mbx_count = MAILBOX_REGISTER_COUNT_2200; - req_length = REQUEST_ENTRY_CNT_2200; - rsp_length = RESPONSE_ENTRY_CNT_2100; - ha->max_loop_id = SNS_LAST_LOOP_ID_2100; - ha->gid_list_info_size = 4; - ha->flash_conf_off = ~0; - ha->flash_data_off = ~0; - ha->nvram_conf_off = ~0; - ha->nvram_data_off = ~0; - ha->isp_ops = &qla2100_isp_ops; - } else if (IS_QLA23XX(ha)) { - ha->max_fibre_devices = MAX_FIBRE_DEVICES_2100; - ha->mbx_count = MAILBOX_REGISTER_COUNT; - req_length = REQUEST_ENTRY_CNT_2200; - rsp_length = RESPONSE_ENTRY_CNT_2300; - ha->max_loop_id = SNS_LAST_LOOP_ID_2300; - ha->gid_list_info_size = 6; - if (IS_QLA2322(ha) || IS_QLA6322(ha)) - ha->optrom_size = OPTROM_SIZE_2322; - ha->flash_conf_off = ~0; - ha->flash_data_off = ~0; - ha->nvram_conf_off = ~0; - ha->nvram_data_off = ~0; - ha->isp_ops = &qla2300_isp_ops; - } else if (IS_QLA24XX_TYPE(ha)) { - ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; - ha->mbx_count = MAILBOX_REGISTER_COUNT; - req_length = REQUEST_ENTRY_CNT_24XX; - rsp_length = RESPONSE_ENTRY_CNT_2300; - ha->max_loop_id = SNS_LAST_LOOP_ID_2300; - ha->init_cb_size = sizeof(struct mid_init_cb_24xx); - ha->gid_list_info_size = 8; - ha->optrom_size = OPTROM_SIZE_24XX; - ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA24XX; - ha->isp_ops = &qla24xx_isp_ops; - ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; - ha->flash_data_off = FARX_ACCESS_FLASH_DATA; - ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; - ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; - } else if (IS_QLA25XX(ha)) { - ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; - ha->mbx_count = MAILBOX_REGISTER_COUNT; - req_length = REQUEST_ENTRY_CNT_24XX; - rsp_length = RESPONSE_ENTRY_CNT_2300; - ha->max_loop_id = SNS_LAST_LOOP_ID_2300; - ha->init_cb_size = sizeof(struct mid_init_cb_24xx); - ha->gid_list_info_size = 8; - ha->optrom_size = OPTROM_SIZE_25XX; - ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; - ha->isp_ops = &qla25xx_isp_ops; - ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; - ha->flash_data_off = FARX_ACCESS_FLASH_DATA; - ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; - ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; - } else if (IS_QLA81XX(ha)) { - ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; - ha->mbx_count = MAILBOX_REGISTER_COUNT; - req_length = REQUEST_ENTRY_CNT_24XX; - rsp_length = RESPONSE_ENTRY_CNT_2300; - ha->max_loop_id = SNS_LAST_LOOP_ID_2300; - ha->init_cb_size = sizeof(struct mid_init_cb_81xx); - ha->gid_list_info_size = 8; - ha->optrom_size = OPTROM_SIZE_81XX; - ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; - ha->isp_ops = &qla81xx_isp_ops; - ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX; - ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; - ha->nvram_conf_off = ~0; - ha->nvram_data_off = ~0; - } else if (IS_QLA82XX(ha)) { - ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; - ha->mbx_count = MAILBOX_REGISTER_COUNT; - req_length = REQUEST_ENTRY_CNT_82XX; - rsp_length = RESPONSE_ENTRY_CNT_82XX; - ha->max_loop_id = SNS_LAST_LOOP_ID_2300; - ha->init_cb_size = sizeof(struct mid_init_cb_81xx); - ha->gid_list_info_size = 8; - ha->optrom_size = OPTROM_SIZE_82XX; - ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; - ha->isp_ops = &qla82xx_isp_ops; - ha->flash_conf_off = FARX_ACCESS_FLASH_CONF; - ha->flash_data_off = FARX_ACCESS_FLASH_DATA; - ha->nvram_conf_off = FARX_ACCESS_NVRAM_CONF; - ha->nvram_data_off = FARX_ACCESS_NVRAM_DATA; - } else if (IS_QLA83XX(ha)) { - ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400; - ha->mbx_count = MAILBOX_REGISTER_COUNT; - req_length = REQUEST_ENTRY_CNT_24XX; - rsp_length = RESPONSE_ENTRY_CNT_2300; - ha->max_loop_id = SNS_LAST_LOOP_ID_2300; - ha->init_cb_size = sizeof(struct mid_init_cb_81xx); - ha->gid_list_info_size = 8; - ha->optrom_size = OPTROM_SIZE_83XX; - ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX; - ha->isp_ops = &qla83xx_isp_ops; - ha->flash_conf_off = FARX_ACCESS_FLASH_CONF_81XX; - ha->flash_data_off = FARX_ACCESS_FLASH_DATA_81XX; - ha->nvram_conf_off = ~0; - ha->nvram_data_off = ~0; - } - - ql_dbg_pci(ql_dbg_init, pdev, 0x001e, - "mbx_count=%d, req_length=%d, " - "rsp_length=%d, max_loop_id=%d, init_cb_size=%d, " - "gid_list_info_size=%d, optrom_size=%d, nvram_npiv_size=%d, " - "max_fibre_devices=%d.\n", - ha->mbx_count, req_length, rsp_length, ha->max_loop_id, - ha->init_cb_size, ha->gid_list_info_size, ha->optrom_size, - ha->nvram_npiv_size, ha->max_fibre_devices); - ql_dbg_pci(ql_dbg_init, pdev, 0x001f, - "isp_ops=%p, flash_conf_off=%d, " - "flash_data_off=%d, nvram_conf_off=%d, nvram_data_off=%d.\n", - ha->isp_ops, ha->flash_conf_off, ha->flash_data_off, - ha->nvram_conf_off, ha->nvram_data_off); - - /* Configure PCI I/O space */ - ret = ha->isp_ops->iospace_config(ha); - if (ret) - goto probe_hw_failed; - - ql_log_pci(ql_log_info, pdev, 0x001d, - "Found an ISP%04X irq %d iobase 0x%p.\n", - pdev->device, pdev->irq, ha->iobase); - mutex_init(&ha->vport_lock); - init_completion(&ha->mbx_cmd_comp); - complete(&ha->mbx_cmd_comp); - init_completion(&ha->mbx_intr_comp); - init_completion(&ha->dcbx_comp); - - set_bit(0, (unsigned long *) ha->vp_idx_map); - - qla2x00_config_dma_addressing(ha); - ql_dbg_pci(ql_dbg_init, pdev, 0x0020, - "64 Bit addressing is %s.\n", - ha->flags.enable_64bit_addressing ? "enable" : - "disable"); - ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp); - if (!ret) { - ql_log_pci(ql_log_fatal, pdev, 0x0031, - "Failed to allocate memory for adapter, aborting.\n"); - - goto probe_hw_failed; - } - - req->max_q_depth = MAX_Q_DEPTH; - if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU) - req->max_q_depth = ql2xmaxqdepth; - - - base_vha = qla2x00_create_host(sht, ha); - if (!base_vha) { - ret = -ENOMEM; - qla2x00_mem_free(ha); - qla2x00_free_req_que(ha, req); - qla2x00_free_rsp_que(ha, rsp); - goto probe_hw_failed; - } - - pci_set_drvdata(pdev, base_vha); - - host = base_vha->host; - base_vha->req = req; - host->can_queue = req->length + 128; - if (IS_QLA2XXX_MIDTYPE(ha)) - base_vha->mgmt_svr_loop_id = 10 + base_vha->vp_idx; - else - base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER + - base_vha->vp_idx; - - /* Set the SG table size based on ISP type */ - if (!IS_FWI2_CAPABLE(ha)) { - if (IS_QLA2100(ha)) - host->sg_tablesize = 32; - } else { - if (!IS_QLA82XX(ha)) - host->sg_tablesize = QLA_SG_ALL; - } - ql_dbg(ql_dbg_init, base_vha, 0x0032, - "can_queue=%d, req=%p, " - "mgmt_svr_loop_id=%d, sg_tablesize=%d.\n", - host->can_queue, base_vha->req, - base_vha->mgmt_svr_loop_id, host->sg_tablesize); - host->max_id = ha->max_fibre_devices; - host->this_id = 255; - host->cmd_per_lun = 3; - host->unique_id = host->host_no; - if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) - host->max_cmd_len = 32; - else - host->max_cmd_len = MAX_CMDSZ; - host->max_channel = MAX_BUSES - 1; - host->max_lun = ql2xmaxlun; - host->transportt = qla2xxx_transport_template; - sht->vendor_id = (SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC); - - ql_dbg(ql_dbg_init, base_vha, 0x0033, - "max_id=%d this_id=%d " - "cmd_per_len=%d unique_id=%d max_cmd_len=%d max_channel=%d " - "max_lun=%d transportt=%p, vendor_id=%llu.\n", host->max_id, - host->this_id, host->cmd_per_lun, host->unique_id, - host->max_cmd_len, host->max_channel, host->max_lun, - host->transportt, sht->vendor_id); - - /* Set up the irqs */ - ret = qla2x00_request_irqs(ha, rsp); - if (ret) - goto probe_init_failed; - - pci_save_state(pdev); - - /* Alloc arrays of request and response ring ptrs */ -que_init: - if (!qla2x00_alloc_queues(ha)) { - ql_log(ql_log_fatal, base_vha, 0x003d, - "Failed to allocate memory for queue pointers.. aborting.\n"); - goto probe_init_failed; - } - - ha->rsp_q_map[0] = rsp; - ha->req_q_map[0] = req; - rsp->req = req; - req->rsp = rsp; - set_bit(0, ha->req_qid_map); - set_bit(0, ha->rsp_qid_map); - /* FWI2-capable only. */ - req->req_q_in = &ha->iobase->isp24.req_q_in; - req->req_q_out = &ha->iobase->isp24.req_q_out; - rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in; - rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out; - if (ha->mqenable || IS_QLA83XX(ha)) { - req->req_q_in = &ha->mqiobase->isp25mq.req_q_in; - req->req_q_out = &ha->mqiobase->isp25mq.req_q_out; - rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in; - rsp->rsp_q_out = &ha->mqiobase->isp25mq.rsp_q_out; - } - - if (IS_QLA82XX(ha)) { - req->req_q_out = &ha->iobase->isp82.req_q_out[0]; - rsp->rsp_q_in = &ha->iobase->isp82.rsp_q_in[0]; - rsp->rsp_q_out = &ha->iobase->isp82.rsp_q_out[0]; - } - - ql_dbg(ql_dbg_multiq, base_vha, 0xc009, - "rsp_q_map=%p req_q_map=%p rsp->req=%p req->rsp=%p.\n", - ha->rsp_q_map, ha->req_q_map, rsp->req, req->rsp); - ql_dbg(ql_dbg_multiq, base_vha, 0xc00a, - "req->req_q_in=%p req->req_q_out=%p " - "rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n", - req->req_q_in, req->req_q_out, - rsp->rsp_q_in, rsp->rsp_q_out); - ql_dbg(ql_dbg_init, base_vha, 0x003e, - "rsp_q_map=%p req_q_map=%p rsp->req=%p req->rsp=%p.\n", - ha->rsp_q_map, ha->req_q_map, rsp->req, req->rsp); - ql_dbg(ql_dbg_init, base_vha, 0x003f, - "req->req_q_in=%p req->req_q_out=%p rsp->rsp_q_in=%p rsp->rsp_q_out=%p.\n", - req->req_q_in, req->req_q_out, rsp->rsp_q_in, rsp->rsp_q_out); - - if (qla2x00_initialize_adapter(base_vha)) { - ql_log(ql_log_fatal, base_vha, 0x00d6, - "Failed to initialize adapter - Adapter flags %x.\n", - base_vha->device_flags); - - if (IS_QLA82XX(ha)) { - qla82xx_idc_lock(ha); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - qla82xx_idc_unlock(ha); - ql_log(ql_log_fatal, base_vha, 0x00d7, - "HW State: FAILED.\n"); - } - - ret = -ENODEV; - goto probe_failed; - } - - if (ha->mqenable) { - if (qla25xx_setup_mode(base_vha)) { - ql_log(ql_log_warn, base_vha, 0x00ec, - "Failed to create queues, falling back to single queue mode.\n"); - goto que_init; - } - } - - if (ha->flags.running_gold_fw) - goto skip_dpc; - - /* - * Startup the kernel thread for this host adapter - */ - ha->dpc_thread = kthread_create(qla2x00_do_dpc, ha, - "%s_dpc", base_vha->host_str); - if (IS_ERR(ha->dpc_thread)) { - ql_log(ql_log_fatal, base_vha, 0x00ed, - "Failed to start DPC thread.\n"); - ret = PTR_ERR(ha->dpc_thread); - goto probe_failed; - } - ql_dbg(ql_dbg_init, base_vha, 0x00ee, - "DPC thread started successfully.\n"); - -skip_dpc: - list_add_tail(&base_vha->list, &ha->vp_list); - base_vha->host->irq = ha->pdev->irq; - - /* Initialized the timer */ - qla2x00_start_timer(base_vha, qla2x00_timer, WATCH_INTERVAL); - ql_dbg(ql_dbg_init, base_vha, 0x00ef, - "Started qla2x00_timer with " - "interval=%d.\n", WATCH_INTERVAL); - ql_dbg(ql_dbg_init, base_vha, 0x00f0, - "Detected hba at address=%p.\n", - ha); - - if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { - if (ha->fw_attributes & BIT_4) { - int prot = 0; - base_vha->flags.difdix_supported = 1; - ql_dbg(ql_dbg_init, base_vha, 0x00f1, - "Registering for DIF/DIX type 1 and 3 protection.\n"); - if (ql2xenabledif == 1) - prot = SHOST_DIX_TYPE0_PROTECTION; - scsi_host_set_prot(host, - prot | SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE2_PROTECTION - | SHOST_DIF_TYPE3_PROTECTION - | SHOST_DIX_TYPE1_PROTECTION - | SHOST_DIX_TYPE2_PROTECTION - | SHOST_DIX_TYPE3_PROTECTION); - scsi_host_set_guard(host, SHOST_DIX_GUARD_CRC); - } else - base_vha->flags.difdix_supported = 0; - } - - ha->isp_ops->enable_intrs(ha); - - ret = scsi_add_host(host, &pdev->dev); - if (ret) - goto probe_failed; - - base_vha->flags.init_done = 1; - base_vha->flags.online = 1; - - ql_dbg(ql_dbg_init, base_vha, 0x00f2, - "Init done and hba is online.\n"); - - scsi_scan_host(host); - - qla2x00_alloc_sysfs_attr(base_vha); - - qla2x00_init_host_attr(base_vha); - - qla2x00_dfs_setup(base_vha); - - ql_log(ql_log_info, base_vha, 0x00fb, - "QLogic %s - %s.\n", - ha->model_number, ha->model_desc ? ha->model_desc : ""); - ql_log(ql_log_info, base_vha, 0x00fc, - "ISP%04X: %s @ %s hdma%c host#=%ld fw=%s.\n", - pdev->device, ha->isp_ops->pci_info_str(base_vha, pci_info), - pci_name(pdev), ha->flags.enable_64bit_addressing ? '+' : '-', - base_vha->host_no, - ha->isp_ops->fw_version_str(base_vha, fw_str)); - - return 0; - -probe_init_failed: - qla2x00_free_req_que(ha, req); - qla2x00_free_rsp_que(ha, rsp); - ha->max_req_queues = ha->max_rsp_queues = 0; - -probe_failed: - if (base_vha->timer_active) - qla2x00_stop_timer(base_vha); - base_vha->flags.online = 0; - if (ha->dpc_thread) { - struct task_struct *t = ha->dpc_thread; - - ha->dpc_thread = NULL; - kthread_stop(t); - } - - qla2x00_free_device(base_vha); - - scsi_host_put(base_vha->host); - -probe_hw_failed: - if (IS_QLA82XX(ha)) { - qla82xx_idc_lock(ha); - qla82xx_clear_drv_active(ha); - qla82xx_idc_unlock(ha); - iounmap((device_reg_t __iomem *)ha->nx_pcibase); - if (!ql2xdbwr) - iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr); - } else { - if (ha->iobase) - iounmap(ha->iobase); - } - pci_release_selected_regions(ha->pdev, ha->bars); - kfree(ha); - ha = NULL; - -probe_out: - pci_disable_device(pdev); - return ret; -} - -static void -qla2x00_shutdown(struct pci_dev *pdev) -{ - scsi_qla_host_t *vha; - struct qla_hw_data *ha; - - vha = pci_get_drvdata(pdev); - ha = vha->hw; - - /* Turn-off FCE trace */ - if (ha->flags.fce_enabled) { - qla2x00_disable_fce_trace(vha, NULL, NULL); - ha->flags.fce_enabled = 0; - } - - /* Turn-off EFT trace */ - if (ha->eft) - qla2x00_disable_eft_trace(vha); - - /* Stop currently executing firmware. */ - qla2x00_try_to_stop_firmware(vha); - - /* Turn adapter off line */ - vha->flags.online = 0; - - /* turn-off interrupts on the card */ - if (ha->interrupts_on) { - vha->flags.init_done = 0; - ha->isp_ops->disable_intrs(ha); - } - - qla2x00_free_irqs(vha); - - qla2x00_free_fw_dump(ha); -} - -static void -qla2x00_remove_one(struct pci_dev *pdev) -{ - scsi_qla_host_t *base_vha, *vha; - struct qla_hw_data *ha; - unsigned long flags; - - base_vha = pci_get_drvdata(pdev); - ha = base_vha->hw; - - mutex_lock(&ha->vport_lock); - while (ha->cur_vport_count) { - struct Scsi_Host *scsi_host; - - spin_lock_irqsave(&ha->vport_slock, flags); - - BUG_ON(base_vha->list.next == &ha->vp_list); - /* This assumes first entry in ha->vp_list is always base vha */ - vha = list_first_entry(&base_vha->list, scsi_qla_host_t, list); - scsi_host = scsi_host_get(vha->host); - - spin_unlock_irqrestore(&ha->vport_slock, flags); - mutex_unlock(&ha->vport_lock); - - fc_vport_terminate(vha->fc_vport); - scsi_host_put(vha->host); - - mutex_lock(&ha->vport_lock); - } - mutex_unlock(&ha->vport_lock); - - set_bit(UNLOADING, &base_vha->dpc_flags); - - qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); - - qla2x00_dfs_remove(base_vha); - - qla84xx_put_chip(base_vha); - - /* Disable timer */ - if (base_vha->timer_active) - qla2x00_stop_timer(base_vha); - - base_vha->flags.online = 0; - - /* Flush the work queue and remove it */ - if (ha->wq) { - flush_workqueue(ha->wq); - destroy_workqueue(ha->wq); - ha->wq = NULL; - } - - /* Kill the kernel thread for this host */ - if (ha->dpc_thread) { - struct task_struct *t = ha->dpc_thread; - - /* - * qla2xxx_wake_dpc checks for ->dpc_thread - * so we need to zero it out. - */ - ha->dpc_thread = NULL; - kthread_stop(t); - } - - qla2x00_free_sysfs_attr(base_vha); - - fc_remove_host(base_vha->host); - - scsi_remove_host(base_vha->host); - - qla2x00_free_device(base_vha); - - scsi_host_put(base_vha->host); - - if (IS_QLA82XX(ha)) { - qla82xx_idc_lock(ha); - qla82xx_clear_drv_active(ha); - qla82xx_idc_unlock(ha); - - iounmap((device_reg_t __iomem *)ha->nx_pcibase); - if (!ql2xdbwr) - iounmap((device_reg_t __iomem *)ha->nxdb_wr_ptr); - } else { - if (ha->iobase) - iounmap(ha->iobase); - - if (ha->mqiobase) - iounmap(ha->mqiobase); - - if (IS_QLA83XX(ha) && ha->msixbase) - iounmap(ha->msixbase); - } - - pci_release_selected_regions(ha->pdev, ha->bars); - kfree(ha); - ha = NULL; - - pci_disable_pcie_error_reporting(pdev); - - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - -static void -qla2x00_free_device(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - - qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); - - /* Disable timer */ - if (vha->timer_active) - qla2x00_stop_timer(vha); - - /* Kill the kernel thread for this host */ - if (ha->dpc_thread) { - struct task_struct *t = ha->dpc_thread; - - /* - * qla2xxx_wake_dpc checks for ->dpc_thread - * so we need to zero it out. - */ - ha->dpc_thread = NULL; - kthread_stop(t); - } - - qla25xx_delete_queues(vha); - - if (ha->flags.fce_enabled) - qla2x00_disable_fce_trace(vha, NULL, NULL); - - if (ha->eft) - qla2x00_disable_eft_trace(vha); - - /* Stop currently executing firmware. */ - qla2x00_try_to_stop_firmware(vha); - - vha->flags.online = 0; - - /* turn-off interrupts on the card */ - if (ha->interrupts_on) { - vha->flags.init_done = 0; - ha->isp_ops->disable_intrs(ha); - } - - qla2x00_free_irqs(vha); - - qla2x00_free_fcports(vha); - - qla2x00_mem_free(ha); - - qla82xx_md_free(vha); - - qla2x00_free_queues(ha); -} - -void qla2x00_free_fcports(struct scsi_qla_host *vha) -{ - fc_port_t *fcport, *tfcport; - - list_for_each_entry_safe(fcport, tfcport, &vha->vp_fcports, list) { - list_del(&fcport->list); - kfree(fcport); - fcport = NULL; - } -} - -static inline void -qla2x00_schedule_rport_del(struct scsi_qla_host *vha, fc_port_t *fcport, - int defer) -{ - struct fc_rport *rport; - scsi_qla_host_t *base_vha; - unsigned long flags; - - if (!fcport->rport) - return; - - rport = fcport->rport; - if (defer) { - base_vha = pci_get_drvdata(vha->hw->pdev); - spin_lock_irqsave(vha->host->host_lock, flags); - fcport->drport = rport; - spin_unlock_irqrestore(vha->host->host_lock, flags); - set_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); - qla2xxx_wake_dpc(base_vha); - } else - fc_remote_port_delete(rport); -} - -/* - * qla2x00_mark_device_lost Updates fcport state when device goes offline. - * - * Input: ha = adapter block pointer. fcport = port structure pointer. - * - * Return: None. - * - * Context: - */ -void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, - int do_login, int defer) -{ - if (atomic_read(&fcport->state) == FCS_ONLINE && - vha->vp_idx == fcport->vp_idx) { - qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); - qla2x00_schedule_rport_del(vha, fcport, defer); - } - /* - * We may need to retry the login, so don't change the state of the - * port but do the retries. - */ - if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD) - qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); - - if (!do_login) - return; - - if (fcport->login_retry == 0) { - fcport->login_retry = vha->hw->login_retry_count; - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - - ql_dbg(ql_dbg_disc, vha, 0x2067, - "Port login retry " - "%02x%02x%02x%02x%02x%02x%02x%02x, " - "id = 0x%04x retry cnt=%d.\n", - fcport->port_name[0], fcport->port_name[1], - fcport->port_name[2], fcport->port_name[3], - fcport->port_name[4], fcport->port_name[5], - fcport->port_name[6], fcport->port_name[7], - fcport->loop_id, fcport->login_retry); - } -} - -/* - * qla2x00_mark_all_devices_lost - * Updates fcport state when device goes offline. - * - * Input: - * ha = adapter block pointer. - * fcport = port structure pointer. - * - * Return: - * None. - * - * Context: - */ -void -qla2x00_mark_all_devices_lost(scsi_qla_host_t *vha, int defer) -{ - fc_port_t *fcport; - - list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (vha->vp_idx != 0 && vha->vp_idx != fcport->vp_idx) - continue; - - /* - * No point in marking the device as lost, if the device is - * already DEAD. - */ - if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) - continue; - if (atomic_read(&fcport->state) == FCS_ONLINE) { - qla2x00_set_fcport_state(fcport, FCS_DEVICE_LOST); - if (defer) - qla2x00_schedule_rport_del(vha, fcport, defer); - else if (vha->vp_idx == fcport->vp_idx) - qla2x00_schedule_rport_del(vha, fcport, defer); - } - } -} - -/* -* qla2x00_mem_alloc -* Allocates adapter memory. -* -* Returns: -* 0 = success. -* !0 = failure. -*/ -static int -qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, - struct req_que **req, struct rsp_que **rsp) -{ - char name[16]; - - ha->init_cb = dma_alloc_coherent(&ha->pdev->dev, ha->init_cb_size, - &ha->init_cb_dma, GFP_KERNEL); - if (!ha->init_cb) - goto fail; - - ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, - qla2x00_gid_list_size(ha), &ha->gid_list_dma, GFP_KERNEL); - if (!ha->gid_list) - goto fail_free_init_cb; - - ha->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); - if (!ha->srb_mempool) - goto fail_free_gid_list; - - if (IS_QLA82XX(ha)) { - /* Allocate cache for CT6 Ctx. */ - if (!ctx_cachep) { - ctx_cachep = kmem_cache_create("qla2xxx_ctx", - sizeof(struct ct6_dsd), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!ctx_cachep) - goto fail_free_gid_list; - } - ha->ctx_mempool = mempool_create_slab_pool(SRB_MIN_REQ, - ctx_cachep); - if (!ha->ctx_mempool) - goto fail_free_srb_mempool; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0021, - "ctx_cachep=%p ctx_mempool=%p.\n", - ctx_cachep, ha->ctx_mempool); - } - - /* Get memory for cached NVRAM */ - ha->nvram = kzalloc(MAX_NVRAM_SIZE, GFP_KERNEL); - if (!ha->nvram) - goto fail_free_ctx_mempool; - - snprintf(name, sizeof(name), "%s_%d", QLA2XXX_DRIVER_NAME, - ha->pdev->device); - ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev, - DMA_POOL_SIZE, 8, 0); - if (!ha->s_dma_pool) - goto fail_free_nvram; - - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0022, - "init_cb=%p gid_list=%p, srb_mempool=%p s_dma_pool=%p.\n", - ha->init_cb, ha->gid_list, ha->srb_mempool, ha->s_dma_pool); - - if (IS_QLA82XX(ha) || ql2xenabledif) { - ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev, - DSD_LIST_DMA_POOL_SIZE, 8, 0); - if (!ha->dl_dma_pool) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0023, - "Failed to allocate memory for dl_dma_pool.\n"); - goto fail_s_dma_pool; - } - - ha->fcp_cmnd_dma_pool = dma_pool_create(name, &ha->pdev->dev, - FCP_CMND_DMA_POOL_SIZE, 8, 0); - if (!ha->fcp_cmnd_dma_pool) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0024, - "Failed to allocate memory for fcp_cmnd_dma_pool.\n"); - goto fail_dl_dma_pool; - } - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0025, - "dl_dma_pool=%p fcp_cmnd_dma_pool=%p.\n", - ha->dl_dma_pool, ha->fcp_cmnd_dma_pool); - } - - /* Allocate memory for SNS commands */ - if (IS_QLA2100(ha) || IS_QLA2200(ha)) { - /* Get consistent memory allocated for SNS commands */ - ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma, GFP_KERNEL); - if (!ha->sns_cmd) - goto fail_dma_pool; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0026, - "sns_cmd: %p.\n", ha->sns_cmd); - } else { - /* Get consistent memory allocated for MS IOCB */ - ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->ms_iocb_dma); - if (!ha->ms_iocb) - goto fail_dma_pool; - /* Get consistent memory allocated for CT SNS commands */ - ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct ct_sns_pkt), &ha->ct_sns_dma, GFP_KERNEL); - if (!ha->ct_sns) - goto fail_free_ms_iocb; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0027, - "ms_iocb=%p ct_sns=%p.\n", - ha->ms_iocb, ha->ct_sns); - } - - /* Allocate memory for request ring */ - *req = kzalloc(sizeof(struct req_que), GFP_KERNEL); - if (!*req) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0028, - "Failed to allocate memory for req.\n"); - goto fail_req; - } - (*req)->length = req_len; - (*req)->ring = dma_alloc_coherent(&ha->pdev->dev, - ((*req)->length + 1) * sizeof(request_t), - &(*req)->dma, GFP_KERNEL); - if (!(*req)->ring) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0029, - "Failed to allocate memory for req_ring.\n"); - goto fail_req_ring; - } - /* Allocate memory for response ring */ - *rsp = kzalloc(sizeof(struct rsp_que), GFP_KERNEL); - if (!*rsp) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x002a, - "Failed to allocate memory for rsp.\n"); - goto fail_rsp; - } - (*rsp)->hw = ha; - (*rsp)->length = rsp_len; - (*rsp)->ring = dma_alloc_coherent(&ha->pdev->dev, - ((*rsp)->length + 1) * sizeof(response_t), - &(*rsp)->dma, GFP_KERNEL); - if (!(*rsp)->ring) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x002b, - "Failed to allocate memory for rsp_ring.\n"); - goto fail_rsp_ring; - } - (*req)->rsp = *rsp; - (*rsp)->req = *req; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002c, - "req=%p req->length=%d req->ring=%p rsp=%p " - "rsp->length=%d rsp->ring=%p.\n", - *req, (*req)->length, (*req)->ring, *rsp, (*rsp)->length, - (*rsp)->ring); - /* Allocate memory for NVRAM data for vports */ - if (ha->nvram_npiv_size) { - ha->npiv_info = kzalloc(sizeof(struct qla_npiv_entry) * - ha->nvram_npiv_size, GFP_KERNEL); - if (!ha->npiv_info) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x002d, - "Failed to allocate memory for npiv_info.\n"); - goto fail_npiv_info; - } - } else - ha->npiv_info = NULL; - - /* Get consistent memory allocated for EX-INIT-CB. */ - if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha)) { - ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->ex_init_cb_dma); - if (!ha->ex_init_cb) - goto fail_ex_init_cb; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002e, - "ex_init_cb=%p.\n", ha->ex_init_cb); - } - - INIT_LIST_HEAD(&ha->gbl_dsd_list); - - /* Get consistent memory allocated for Async Port-Database. */ - if (!IS_FWI2_CAPABLE(ha)) { - ha->async_pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, - &ha->async_pd_dma); - if (!ha->async_pd) - goto fail_async_pd; - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002f, - "async_pd=%p.\n", ha->async_pd); - } - - INIT_LIST_HEAD(&ha->vp_list); - return 1; - -fail_async_pd: - dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma); -fail_ex_init_cb: - kfree(ha->npiv_info); -fail_npiv_info: - dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) * - sizeof(response_t), (*rsp)->ring, (*rsp)->dma); - (*rsp)->ring = NULL; - (*rsp)->dma = 0; -fail_rsp_ring: - kfree(*rsp); -fail_rsp: - dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) * - sizeof(request_t), (*req)->ring, (*req)->dma); - (*req)->ring = NULL; - (*req)->dma = 0; -fail_req_ring: - kfree(*req); -fail_req: - dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), - ha->ct_sns, ha->ct_sns_dma); - ha->ct_sns = NULL; - ha->ct_sns_dma = 0; -fail_free_ms_iocb: - dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); - ha->ms_iocb = NULL; - ha->ms_iocb_dma = 0; -fail_dma_pool: - if (IS_QLA82XX(ha) || ql2xenabledif) { - dma_pool_destroy(ha->fcp_cmnd_dma_pool); - ha->fcp_cmnd_dma_pool = NULL; - } -fail_dl_dma_pool: - if (IS_QLA82XX(ha) || ql2xenabledif) { - dma_pool_destroy(ha->dl_dma_pool); - ha->dl_dma_pool = NULL; - } -fail_s_dma_pool: - dma_pool_destroy(ha->s_dma_pool); - ha->s_dma_pool = NULL; -fail_free_nvram: - kfree(ha->nvram); - ha->nvram = NULL; -fail_free_ctx_mempool: - mempool_destroy(ha->ctx_mempool); - ha->ctx_mempool = NULL; -fail_free_srb_mempool: - mempool_destroy(ha->srb_mempool); - ha->srb_mempool = NULL; -fail_free_gid_list: - dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), - ha->gid_list, - ha->gid_list_dma); - ha->gid_list = NULL; - ha->gid_list_dma = 0; -fail_free_init_cb: - dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, ha->init_cb, - ha->init_cb_dma); - ha->init_cb = NULL; - ha->init_cb_dma = 0; -fail: - ql_log(ql_log_fatal, NULL, 0x0030, - "Memory allocation failure.\n"); - return -ENOMEM; -} - -/* -* qla2x00_free_fw_dump -* Frees fw dump stuff. -* -* Input: -* ha = adapter block pointer. -*/ -static void -qla2x00_free_fw_dump(struct qla_hw_data *ha) -{ - if (ha->fce) - dma_free_coherent(&ha->pdev->dev, FCE_SIZE, ha->fce, - ha->fce_dma); - - if (ha->fw_dump) { - if (ha->eft) - dma_free_coherent(&ha->pdev->dev, - ntohl(ha->fw_dump->eft_size), ha->eft, ha->eft_dma); - vfree(ha->fw_dump); - } - ha->fce = NULL; - ha->fce_dma = 0; - ha->eft = NULL; - ha->eft_dma = 0; - ha->fw_dump = NULL; - ha->fw_dumped = 0; - ha->fw_dump_reading = 0; -} - -/* -* qla2x00_mem_free -* Frees all adapter allocated memory. -* -* Input: -* ha = adapter block pointer. -*/ -static void -qla2x00_mem_free(struct qla_hw_data *ha) -{ - qla2x00_free_fw_dump(ha); - - if (ha->srb_mempool) - mempool_destroy(ha->srb_mempool); - - if (ha->dcbx_tlv) - dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, - ha->dcbx_tlv, ha->dcbx_tlv_dma); - - if (ha->xgmac_data) - dma_free_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE, - ha->xgmac_data, ha->xgmac_data_dma); - - if (ha->sns_cmd) - dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), - ha->sns_cmd, ha->sns_cmd_dma); - - if (ha->ct_sns) - dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), - ha->ct_sns, ha->ct_sns_dma); - - if (ha->sfp_data) - dma_pool_free(ha->s_dma_pool, ha->sfp_data, ha->sfp_data_dma); - - if (ha->ms_iocb) - dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma); - - if (ha->ex_init_cb) - dma_pool_free(ha->s_dma_pool, - ha->ex_init_cb, ha->ex_init_cb_dma); - - if (ha->async_pd) - dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); - - if (ha->s_dma_pool) - dma_pool_destroy(ha->s_dma_pool); - - if (ha->gid_list) - dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), - ha->gid_list, ha->gid_list_dma); - - if (IS_QLA82XX(ha)) { - if (!list_empty(&ha->gbl_dsd_list)) { - struct dsd_dma *dsd_ptr, *tdsd_ptr; - - /* clean up allocated prev pool */ - list_for_each_entry_safe(dsd_ptr, - tdsd_ptr, &ha->gbl_dsd_list, list) { - dma_pool_free(ha->dl_dma_pool, - dsd_ptr->dsd_addr, dsd_ptr->dsd_list_dma); - list_del(&dsd_ptr->list); - kfree(dsd_ptr); - } - } - } - - if (ha->dl_dma_pool) - dma_pool_destroy(ha->dl_dma_pool); - - if (ha->fcp_cmnd_dma_pool) - dma_pool_destroy(ha->fcp_cmnd_dma_pool); - - if (ha->ctx_mempool) - mempool_destroy(ha->ctx_mempool); - - if (ha->init_cb) - dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, - ha->init_cb, ha->init_cb_dma); - vfree(ha->optrom_buffer); - kfree(ha->nvram); - kfree(ha->npiv_info); - kfree(ha->swl); - - ha->srb_mempool = NULL; - ha->ctx_mempool = NULL; - ha->sns_cmd = NULL; - ha->sns_cmd_dma = 0; - ha->ct_sns = NULL; - ha->ct_sns_dma = 0; - ha->ms_iocb = NULL; - ha->ms_iocb_dma = 0; - ha->init_cb = NULL; - ha->init_cb_dma = 0; - ha->ex_init_cb = NULL; - ha->ex_init_cb_dma = 0; - ha->async_pd = NULL; - ha->async_pd_dma = 0; - - ha->s_dma_pool = NULL; - ha->dl_dma_pool = NULL; - ha->fcp_cmnd_dma_pool = NULL; - - ha->gid_list = NULL; - ha->gid_list_dma = 0; -} - -struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, - struct qla_hw_data *ha) -{ - struct Scsi_Host *host; - struct scsi_qla_host *vha = NULL; - - host = scsi_host_alloc(sht, sizeof(scsi_qla_host_t)); - if (host == NULL) { - ql_log_pci(ql_log_fatal, ha->pdev, 0x0107, - "Failed to allocate host from the scsi layer, aborting.\n"); - goto fail; - } - - /* Clear our data area */ - vha = shost_priv(host); - memset(vha, 0, sizeof(scsi_qla_host_t)); - - vha->host = host; - vha->host_no = host->host_no; - vha->hw = ha; - - INIT_LIST_HEAD(&vha->vp_fcports); - INIT_LIST_HEAD(&vha->work_list); - INIT_LIST_HEAD(&vha->list); - - spin_lock_init(&vha->work_lock); - - sprintf(vha->host_str, "%s_%ld", QLA2XXX_DRIVER_NAME, vha->host_no); - ql_dbg(ql_dbg_init, vha, 0x0041, - "Allocated the host=%p hw=%p vha=%p dev_name=%s", - vha->host, vha->hw, vha, - dev_name(&(ha->pdev->dev))); - - return vha; - -fail: - return vha; -} - -static struct qla_work_evt * -qla2x00_alloc_work(struct scsi_qla_host *vha, enum qla_work_type type) -{ - struct qla_work_evt *e; - uint8_t bail; - - QLA_VHA_MARK_BUSY(vha, bail); - if (bail) - return NULL; - - e = kzalloc(sizeof(struct qla_work_evt), GFP_ATOMIC); - if (!e) { - QLA_VHA_MARK_NOT_BUSY(vha); - return NULL; - } - - INIT_LIST_HEAD(&e->list); - e->type = type; - e->flags = QLA_EVT_FLAG_FREE; - return e; -} - -static int -qla2x00_post_work(struct scsi_qla_host *vha, struct qla_work_evt *e) -{ - unsigned long flags; - - spin_lock_irqsave(&vha->work_lock, flags); - list_add_tail(&e->list, &vha->work_list); - spin_unlock_irqrestore(&vha->work_lock, flags); - qla2xxx_wake_dpc(vha); - - return QLA_SUCCESS; -} - -int -qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code, - u32 data) -{ - struct qla_work_evt *e; - - e = qla2x00_alloc_work(vha, QLA_EVT_AEN); - if (!e) - return QLA_FUNCTION_FAILED; - - e->u.aen.code = code; - e->u.aen.data = data; - return qla2x00_post_work(vha, e); -} - -int -qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb) -{ - struct qla_work_evt *e; - - e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK); - if (!e) - return QLA_FUNCTION_FAILED; - - memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t)); - return qla2x00_post_work(vha, e); -} - -#define qla2x00_post_async_work(name, type) \ -int qla2x00_post_async_##name##_work( \ - struct scsi_qla_host *vha, \ - fc_port_t *fcport, uint16_t *data) \ -{ \ - struct qla_work_evt *e; \ - \ - e = qla2x00_alloc_work(vha, type); \ - if (!e) \ - return QLA_FUNCTION_FAILED; \ - \ - e->u.logio.fcport = fcport; \ - if (data) { \ - e->u.logio.data[0] = data[0]; \ - e->u.logio.data[1] = data[1]; \ - } \ - return qla2x00_post_work(vha, e); \ -} - -qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN); -qla2x00_post_async_work(login_done, QLA_EVT_ASYNC_LOGIN_DONE); -qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT); -qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE); -qla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC); -qla2x00_post_async_work(adisc_done, QLA_EVT_ASYNC_ADISC_DONE); - -int -qla2x00_post_uevent_work(struct scsi_qla_host *vha, u32 code) -{ - struct qla_work_evt *e; - - e = qla2x00_alloc_work(vha, QLA_EVT_UEVENT); - if (!e) - return QLA_FUNCTION_FAILED; - - e->u.uevent.code = code; - return qla2x00_post_work(vha, e); -} - -static void -qla2x00_uevent_emit(struct scsi_qla_host *vha, u32 code) -{ - char event_string[40]; - char *envp[] = { event_string, NULL }; - - switch (code) { - case QLA_UEVENT_CODE_FW_DUMP: - snprintf(event_string, sizeof(event_string), "FW_DUMP=%ld", - vha->host_no); - break; - default: - /* do nothing */ - break; - } - kobject_uevent_env(&vha->hw->pdev->dev.kobj, KOBJ_CHANGE, envp); -} - -void -qla2x00_do_work(struct scsi_qla_host *vha) -{ - struct qla_work_evt *e, *tmp; - unsigned long flags; - LIST_HEAD(work); - - spin_lock_irqsave(&vha->work_lock, flags); - list_splice_init(&vha->work_list, &work); - spin_unlock_irqrestore(&vha->work_lock, flags); - - list_for_each_entry_safe(e, tmp, &work, list) { - list_del_init(&e->list); - - switch (e->type) { - case QLA_EVT_AEN: - fc_host_post_event(vha->host, fc_get_event_number(), - e->u.aen.code, e->u.aen.data); - break; - case QLA_EVT_IDC_ACK: - qla81xx_idc_ack(vha, e->u.idc_ack.mb); - break; - case QLA_EVT_ASYNC_LOGIN: - qla2x00_async_login(vha, e->u.logio.fcport, - e->u.logio.data); - break; - case QLA_EVT_ASYNC_LOGIN_DONE: - qla2x00_async_login_done(vha, e->u.logio.fcport, - e->u.logio.data); - break; - case QLA_EVT_ASYNC_LOGOUT: - qla2x00_async_logout(vha, e->u.logio.fcport); - break; - case QLA_EVT_ASYNC_LOGOUT_DONE: - qla2x00_async_logout_done(vha, e->u.logio.fcport, - e->u.logio.data); - break; - case QLA_EVT_ASYNC_ADISC: - qla2x00_async_adisc(vha, e->u.logio.fcport, - e->u.logio.data); - break; - case QLA_EVT_ASYNC_ADISC_DONE: - qla2x00_async_adisc_done(vha, e->u.logio.fcport, - e->u.logio.data); - break; - case QLA_EVT_UEVENT: - qla2x00_uevent_emit(vha, e->u.uevent.code); - break; - } - if (e->flags & QLA_EVT_FLAG_FREE) - kfree(e); - - /* For each work completed decrement vha ref count */ - QLA_VHA_MARK_NOT_BUSY(vha); - } -} - -/* Relogins all the fcports of a vport - * Context: dpc thread - */ -void qla2x00_relogin(struct scsi_qla_host *vha) -{ - fc_port_t *fcport; - int status; - uint16_t next_loopid = 0; - struct qla_hw_data *ha = vha->hw; - uint16_t data[2]; - - list_for_each_entry(fcport, &vha->vp_fcports, list) { - /* - * If the port is not ONLINE then try to login - * to it if we haven't run out of retries. - */ - if (atomic_read(&fcport->state) != FCS_ONLINE && - fcport->login_retry && !(fcport->flags & FCF_ASYNC_SENT)) { - fcport->login_retry--; - if (fcport->flags & FCF_FABRIC_DEVICE) { - if (fcport->flags & FCF_FCP2_DEVICE) - ha->isp_ops->fabric_logout(vha, - fcport->loop_id, - fcport->d_id.b.domain, - fcport->d_id.b.area, - fcport->d_id.b.al_pa); - - if (fcport->loop_id == FC_NO_LOOP_ID) { - fcport->loop_id = next_loopid = - ha->min_external_loopid; - status = qla2x00_find_new_loop_id( - vha, fcport); - if (status != QLA_SUCCESS) { - /* Ran out of IDs to use */ - break; - } - } - - if (IS_ALOGIO_CAPABLE(ha)) { - fcport->flags |= FCF_ASYNC_SENT; - data[0] = 0; - data[1] = QLA_LOGIO_LOGIN_RETRIED; - status = qla2x00_post_async_login_work( - vha, fcport, data); - if (status == QLA_SUCCESS) - continue; - /* Attempt a retry. */ - status = 1; - } else { - status = qla2x00_fabric_login(vha, - fcport, &next_loopid); - if (status == QLA_SUCCESS) { - int status2; - uint8_t opts; - - opts = 0; - if (fcport->flags & - FCF_FCP2_DEVICE) - opts |= BIT_1; - status2 = - qla2x00_get_port_database( - vha, fcport, - opts); - if (status2 != QLA_SUCCESS) - status = 1; - } - } - } else - status = qla2x00_local_device_login(vha, - fcport); - - if (status == QLA_SUCCESS) { - fcport->old_loop_id = fcport->loop_id; - - ql_dbg(ql_dbg_disc, vha, 0x2003, - "Port login OK: logged in ID 0x%x.\n", - fcport->loop_id); - - qla2x00_update_fcport(vha, fcport); - - } else if (status == 1) { - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - /* retry the login again */ - ql_dbg(ql_dbg_disc, vha, 0x2007, - "Retrying %d login again loop_id 0x%x.\n", - fcport->login_retry, fcport->loop_id); - } else { - fcport->login_retry = 0; - } - - if (fcport->login_retry == 0 && status != QLA_SUCCESS) - fcport->loop_id = FC_NO_LOOP_ID; - } - if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) - break; - } -} - -/************************************************************************** -* qla2x00_do_dpc -* This kernel thread is a task that is schedule by the interrupt handler -* to perform the background processing for interrupts. -* -* Notes: -* This task always run in the context of a kernel thread. It -* is kick-off by the driver's detect code and starts up -* up one per adapter. It immediately goes to sleep and waits for -* some fibre event. When either the interrupt handler or -* the timer routine detects a event it will one of the task -* bits then wake us up. -**************************************************************************/ -static int -qla2x00_do_dpc(void *data) -{ - int rval; - scsi_qla_host_t *base_vha; - struct qla_hw_data *ha; - - ha = (struct qla_hw_data *)data; - base_vha = pci_get_drvdata(ha->pdev); - - set_user_nice(current, -20); - - set_current_state(TASK_INTERRUPTIBLE); - while (!kthread_should_stop()) { - ql_dbg(ql_dbg_dpc, base_vha, 0x4000, - "DPC handler sleeping.\n"); - - schedule(); - __set_current_state(TASK_RUNNING); - - if (!base_vha->flags.init_done || ha->flags.mbox_busy) - goto end_loop; - - if (ha->flags.eeh_busy) { - ql_dbg(ql_dbg_dpc, base_vha, 0x4003, - "eeh_busy=%d.\n", ha->flags.eeh_busy); - goto end_loop; - } - - ha->dpc_active = 1; - - ql_dbg(ql_dbg_dpc, base_vha, 0x4001, - "DPC handler waking up.\n"); - ql_dbg(ql_dbg_dpc, base_vha, 0x4002, - "dpc_flags=0x%lx.\n", base_vha->dpc_flags); - - qla2x00_do_work(base_vha); - - if (IS_QLA82XX(ha)) { - if (test_and_clear_bit(ISP_UNRECOVERABLE, - &base_vha->dpc_flags)) { - qla82xx_idc_lock(ha); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - qla82xx_idc_unlock(ha); - ql_log(ql_log_info, base_vha, 0x4004, - "HW State: FAILED.\n"); - qla82xx_device_state_handler(base_vha); - continue; - } - - if (test_and_clear_bit(FCOE_CTX_RESET_NEEDED, - &base_vha->dpc_flags)) { - - ql_dbg(ql_dbg_dpc, base_vha, 0x4005, - "FCoE context reset scheduled.\n"); - if (!(test_and_set_bit(ABORT_ISP_ACTIVE, - &base_vha->dpc_flags))) { - if (qla82xx_fcoe_ctx_reset(base_vha)) { - /* FCoE-ctx reset failed. - * Escalate to chip-reset - */ - set_bit(ISP_ABORT_NEEDED, - &base_vha->dpc_flags); - } - clear_bit(ABORT_ISP_ACTIVE, - &base_vha->dpc_flags); - } - - ql_dbg(ql_dbg_dpc, base_vha, 0x4006, - "FCoE context reset end.\n"); - } - } - - if (test_and_clear_bit(ISP_ABORT_NEEDED, - &base_vha->dpc_flags)) { - - ql_dbg(ql_dbg_dpc, base_vha, 0x4007, - "ISP abort scheduled.\n"); - if (!(test_and_set_bit(ABORT_ISP_ACTIVE, - &base_vha->dpc_flags))) { - - if (ha->isp_ops->abort_isp(base_vha)) { - /* failed. retry later */ - set_bit(ISP_ABORT_NEEDED, - &base_vha->dpc_flags); - } - clear_bit(ABORT_ISP_ACTIVE, - &base_vha->dpc_flags); - } - - ql_dbg(ql_dbg_dpc, base_vha, 0x4008, - "ISP abort end.\n"); - } - - if (test_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags)) { - qla2x00_update_fcports(base_vha); - clear_bit(FCPORT_UPDATE_NEEDED, &base_vha->dpc_flags); - } - - if (test_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags)) { - ql_dbg(ql_dbg_dpc, base_vha, 0x4009, - "Quiescence mode scheduled.\n"); - qla82xx_device_state_handler(base_vha); - clear_bit(ISP_QUIESCE_NEEDED, &base_vha->dpc_flags); - if (!ha->flags.quiesce_owner) { - qla2x00_perform_loop_resync(base_vha); - - qla82xx_idc_lock(ha); - qla82xx_clear_qsnt_ready(base_vha); - qla82xx_idc_unlock(ha); - } - ql_dbg(ql_dbg_dpc, base_vha, 0x400a, - "Quiescence mode end.\n"); - } - - if (test_and_clear_bit(RESET_MARKER_NEEDED, - &base_vha->dpc_flags) && - (!(test_and_set_bit(RESET_ACTIVE, &base_vha->dpc_flags)))) { - - ql_dbg(ql_dbg_dpc, base_vha, 0x400b, - "Reset marker scheduled.\n"); - qla2x00_rst_aen(base_vha); - clear_bit(RESET_ACTIVE, &base_vha->dpc_flags); - ql_dbg(ql_dbg_dpc, base_vha, 0x400c, - "Reset marker end.\n"); - } - - /* Retry each device up to login retry count */ - if ((test_and_clear_bit(RELOGIN_NEEDED, - &base_vha->dpc_flags)) && - !test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags) && - atomic_read(&base_vha->loop_state) != LOOP_DOWN) { - - ql_dbg(ql_dbg_dpc, base_vha, 0x400d, - "Relogin scheduled.\n"); - qla2x00_relogin(base_vha); - ql_dbg(ql_dbg_dpc, base_vha, 0x400e, - "Relogin end.\n"); - } - - if (test_and_clear_bit(LOOP_RESYNC_NEEDED, - &base_vha->dpc_flags)) { - - ql_dbg(ql_dbg_dpc, base_vha, 0x400f, - "Loop resync scheduled.\n"); - - if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, - &base_vha->dpc_flags))) { - - rval = qla2x00_loop_resync(base_vha); - - clear_bit(LOOP_RESYNC_ACTIVE, - &base_vha->dpc_flags); - } - - ql_dbg(ql_dbg_dpc, base_vha, 0x4010, - "Loop resync end.\n"); - } - - if (test_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags) && - atomic_read(&base_vha->loop_state) == LOOP_READY) { - clear_bit(NPIV_CONFIG_NEEDED, &base_vha->dpc_flags); - qla2xxx_flash_npiv_conf(base_vha); - } - - if (!ha->interrupts_on) - ha->isp_ops->enable_intrs(ha); - - if (test_and_clear_bit(BEACON_BLINK_NEEDED, - &base_vha->dpc_flags)) - ha->isp_ops->beacon_blink(base_vha); - - qla2x00_do_dpc_all_vps(base_vha); - - ha->dpc_active = 0; -end_loop: - set_current_state(TASK_INTERRUPTIBLE); - } /* End of while(1) */ - __set_current_state(TASK_RUNNING); - - ql_dbg(ql_dbg_dpc, base_vha, 0x4011, - "DPC handler exiting.\n"); - - /* - * Make sure that nobody tries to wake us up again. - */ - ha->dpc_active = 0; - - /* Cleanup any residual CTX SRBs. */ - qla2x00_abort_all_cmds(base_vha, DID_NO_CONNECT << 16); - - return 0; -} - -void -qla2xxx_wake_dpc(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct task_struct *t = ha->dpc_thread; - - if (!test_bit(UNLOADING, &vha->dpc_flags) && t) - wake_up_process(t); -} - -/* -* qla2x00_rst_aen -* Processes asynchronous reset. -* -* Input: -* ha = adapter block pointer. -*/ -static void -qla2x00_rst_aen(scsi_qla_host_t *vha) -{ - if (vha->flags.online && !vha->flags.reset_active && - !atomic_read(&vha->loop_down_timer) && - !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))) { - do { - clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - - /* - * Issue marker command only when we are going to start - * the I/O. - */ - vha->marker_needed = 1; - } while (!atomic_read(&vha->loop_down_timer) && - (test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags))); - } -} - -/************************************************************************** -* qla2x00_timer -* -* Description: -* One second timer -* -* Context: Interrupt -***************************************************************************/ -void -qla2x00_timer(scsi_qla_host_t *vha) -{ - unsigned long cpu_flags = 0; - int start_dpc = 0; - int index; - srb_t *sp; - uint16_t w; - struct qla_hw_data *ha = vha->hw; - struct req_que *req; - - if (ha->flags.eeh_busy) { - ql_dbg(ql_dbg_timer, vha, 0x6000, - "EEH = %d, restarting timer.\n", - ha->flags.eeh_busy); - qla2x00_restart_timer(vha, WATCH_INTERVAL); - return; - } - - /* Hardware read to raise pending EEH errors during mailbox waits. */ - if (!pci_channel_offline(ha->pdev)) - pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); - - /* Make sure qla82xx_watchdog is run only for physical port */ - if (!vha->vp_idx && IS_QLA82XX(ha)) { - if (test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) - start_dpc++; - qla82xx_watchdog(vha); - } - - /* Loop down handler. */ - if (atomic_read(&vha->loop_down_timer) > 0 && - !(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) && - !(test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags)) - && vha->flags.online) { - - if (atomic_read(&vha->loop_down_timer) == - vha->loop_down_abort_time) { - - ql_log(ql_log_info, vha, 0x6008, - "Loop down - aborting the queues before time expires.\n"); - - if (!IS_QLA2100(ha) && vha->link_down_timeout) - atomic_set(&vha->loop_state, LOOP_DEAD); - - /* - * Schedule an ISP abort to return any FCP2-device - * commands. - */ - /* NPIV - scan physical port only */ - if (!vha->vp_idx) { - spin_lock_irqsave(&ha->hardware_lock, - cpu_flags); - req = ha->req_q_map[0]; - for (index = 1; - index < MAX_OUTSTANDING_COMMANDS; - index++) { - fc_port_t *sfcp; - - sp = req->outstanding_cmds[index]; - if (!sp) - continue; - if (sp->type != SRB_SCSI_CMD) - continue; - sfcp = sp->fcport; - if (!(sfcp->flags & FCF_FCP2_DEVICE)) - continue; - - if (IS_QLA82XX(ha)) - set_bit(FCOE_CTX_RESET_NEEDED, - &vha->dpc_flags); - else - set_bit(ISP_ABORT_NEEDED, - &vha->dpc_flags); - break; - } - spin_unlock_irqrestore(&ha->hardware_lock, - cpu_flags); - } - start_dpc++; - } - - /* if the loop has been down for 4 minutes, reinit adapter */ - if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { - if (!(vha->device_flags & DFLG_NO_CABLE)) { - ql_log(ql_log_warn, vha, 0x6009, - "Loop down - aborting ISP.\n"); - - if (IS_QLA82XX(ha)) - set_bit(FCOE_CTX_RESET_NEEDED, - &vha->dpc_flags); - else - set_bit(ISP_ABORT_NEEDED, - &vha->dpc_flags); - } - } - ql_dbg(ql_dbg_timer, vha, 0x600a, - "Loop down - seconds remaining %d.\n", - atomic_read(&vha->loop_down_timer)); - } - - /* Check if beacon LED needs to be blinked for physical host only */ - if (!vha->vp_idx && (ha->beacon_blink_led == 1)) { - /* There is no beacon_blink function for ISP82xx */ - if (!IS_QLA82XX(ha)) { - set_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags); - start_dpc++; - } - } - - /* Process any deferred work. */ - if (!list_empty(&vha->work_list)) - start_dpc++; - - /* Schedule the DPC routine if needed */ - if ((test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || - test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags) || - test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags) || - start_dpc || - test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags) || - test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags) || - test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) || - test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) || - test_bit(VP_DPC_NEEDED, &vha->dpc_flags) || - test_bit(RELOGIN_NEEDED, &vha->dpc_flags))) { - ql_dbg(ql_dbg_timer, vha, 0x600b, - "isp_abort_needed=%d loop_resync_needed=%d " - "fcport_update_needed=%d start_dpc=%d " - "reset_marker_needed=%d", - test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags), - test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags), - test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags), - start_dpc, - test_bit(RESET_MARKER_NEEDED, &vha->dpc_flags)); - ql_dbg(ql_dbg_timer, vha, 0x600c, - "beacon_blink_needed=%d isp_unrecoverable=%d " - "fcoe_ctx_reset_needed=%d vp_dpc_needed=%d " - "relogin_needed=%d.\n", - test_bit(BEACON_BLINK_NEEDED, &vha->dpc_flags), - test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags), - test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags), - test_bit(VP_DPC_NEEDED, &vha->dpc_flags), - test_bit(RELOGIN_NEEDED, &vha->dpc_flags)); - qla2xxx_wake_dpc(vha); - } - - qla2x00_restart_timer(vha, WATCH_INTERVAL); -} - -/* Firmware interface routines. */ - -#define FW_BLOBS 10 -#define FW_ISP21XX 0 -#define FW_ISP22XX 1 -#define FW_ISP2300 2 -#define FW_ISP2322 3 -#define FW_ISP24XX 4 -#define FW_ISP25XX 5 -#define FW_ISP81XX 6 -#define FW_ISP82XX 7 -#define FW_ISP2031 8 -#define FW_ISP8031 9 - -#define FW_FILE_ISP21XX "ql2100_fw.bin" -#define FW_FILE_ISP22XX "ql2200_fw.bin" -#define FW_FILE_ISP2300 "ql2300_fw.bin" -#define FW_FILE_ISP2322 "ql2322_fw.bin" -#define FW_FILE_ISP24XX "ql2400_fw.bin" -#define FW_FILE_ISP25XX "ql2500_fw.bin" -#define FW_FILE_ISP81XX "ql8100_fw.bin" -#define FW_FILE_ISP82XX "ql8200_fw.bin" -#define FW_FILE_ISP2031 "ql2600_fw.bin" -#define FW_FILE_ISP8031 "ql8300_fw.bin" - -static DEFINE_MUTEX(qla_fw_lock); - -static struct fw_blob qla_fw_blobs[FW_BLOBS] = { - { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, }, - { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, }, - { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, }, - { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, }, - { .name = FW_FILE_ISP24XX, }, - { .name = FW_FILE_ISP25XX, }, - { .name = FW_FILE_ISP81XX, }, - { .name = FW_FILE_ISP82XX, }, - { .name = FW_FILE_ISP2031, }, - { .name = FW_FILE_ISP8031, }, -}; - -struct fw_blob * -qla2x00_request_firmware(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct fw_blob *blob; - - if (IS_QLA2100(ha)) { - blob = &qla_fw_blobs[FW_ISP21XX]; - } else if (IS_QLA2200(ha)) { - blob = &qla_fw_blobs[FW_ISP22XX]; - } else if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) { - blob = &qla_fw_blobs[FW_ISP2300]; - } else if (IS_QLA2322(ha) || IS_QLA6322(ha)) { - blob = &qla_fw_blobs[FW_ISP2322]; - } else if (IS_QLA24XX_TYPE(ha)) { - blob = &qla_fw_blobs[FW_ISP24XX]; - } else if (IS_QLA25XX(ha)) { - blob = &qla_fw_blobs[FW_ISP25XX]; - } else if (IS_QLA81XX(ha)) { - blob = &qla_fw_blobs[FW_ISP81XX]; - } else if (IS_QLA82XX(ha)) { - blob = &qla_fw_blobs[FW_ISP82XX]; - } else if (IS_QLA2031(ha)) { - blob = &qla_fw_blobs[FW_ISP2031]; - } else if (IS_QLA8031(ha)) { - blob = &qla_fw_blobs[FW_ISP8031]; - } else { - return NULL; - } - - mutex_lock(&qla_fw_lock); - if (blob->fw) - goto out; - - if (request_firmware(&blob->fw, blob->name, &ha->pdev->dev)) { - ql_log(ql_log_warn, vha, 0x0063, - "Failed to load firmware image (%s).\n", blob->name); - blob->fw = NULL; - blob = NULL; - goto out; - } - -out: - mutex_unlock(&qla_fw_lock); - return blob; -} - -static void -qla2x00_release_firmware(void) -{ - int idx; - - mutex_lock(&qla_fw_lock); - for (idx = 0; idx < FW_BLOBS; idx++) - if (qla_fw_blobs[idx].fw) - release_firmware(qla_fw_blobs[idx].fw); - mutex_unlock(&qla_fw_lock); -} - -static pci_ers_result_t -qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) -{ - scsi_qla_host_t *vha = pci_get_drvdata(pdev); - struct qla_hw_data *ha = vha->hw; - - ql_dbg(ql_dbg_aer, vha, 0x9000, - "PCI error detected, state %x.\n", state); - - switch (state) { - case pci_channel_io_normal: - ha->flags.eeh_busy = 0; - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - ha->flags.eeh_busy = 1; - /* For ISP82XX complete any pending mailbox cmd */ - if (IS_QLA82XX(ha)) { - ha->flags.isp82xx_fw_hung = 1; - ql_dbg(ql_dbg_aer, vha, 0x9001, "Pci channel io frozen\n"); - qla82xx_clear_pending_mbx(vha); - } - qla2x00_free_irqs(vha); - pci_disable_device(pdev); - /* Return back all IOs */ - qla2x00_abort_all_cmds(vha, DID_RESET << 16); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - ha->flags.pci_channel_io_perm_failure = 1; - qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); - return PCI_ERS_RESULT_DISCONNECT; - } - return PCI_ERS_RESULT_NEED_RESET; -} - -static pci_ers_result_t -qla2xxx_pci_mmio_enabled(struct pci_dev *pdev) -{ - int risc_paused = 0; - uint32_t stat; - unsigned long flags; - scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); - struct qla_hw_data *ha = base_vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; - - if (IS_QLA82XX(ha)) - return PCI_ERS_RESULT_RECOVERED; - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (IS_QLA2100(ha) || IS_QLA2200(ha)){ - stat = RD_REG_DWORD(®->hccr); - if (stat & HCCR_RISC_PAUSE) - risc_paused = 1; - } else if (IS_QLA23XX(ha)) { - stat = RD_REG_DWORD(®->u.isp2300.host_status); - if (stat & HSR_RISC_PAUSED) - risc_paused = 1; - } else if (IS_FWI2_CAPABLE(ha)) { - stat = RD_REG_DWORD(®24->host_status); - if (stat & HSRX_RISC_PAUSED) - risc_paused = 1; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (risc_paused) { - ql_log(ql_log_info, base_vha, 0x9003, - "RISC paused -- mmio_enabled, Dumping firmware.\n"); - ha->isp_ops->fw_dump(base_vha, 0); - - return PCI_ERS_RESULT_NEED_RESET; - } else - return PCI_ERS_RESULT_RECOVERED; -} - -uint32_t qla82xx_error_recovery(scsi_qla_host_t *base_vha) -{ - uint32_t rval = QLA_FUNCTION_FAILED; - uint32_t drv_active = 0; - struct qla_hw_data *ha = base_vha->hw; - int fn; - struct pci_dev *other_pdev = NULL; - - ql_dbg(ql_dbg_aer, base_vha, 0x9006, - "Entered %s.\n", __func__); - - set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - - if (base_vha->flags.online) { - /* Abort all outstanding commands, - * so as to be requeued later */ - qla2x00_abort_isp_cleanup(base_vha); - } - - - fn = PCI_FUNC(ha->pdev->devfn); - while (fn > 0) { - fn--; - ql_dbg(ql_dbg_aer, base_vha, 0x9007, - "Finding pci device at function = 0x%x.\n", fn); - other_pdev = - pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), - ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), - fn)); - - if (!other_pdev) - continue; - if (atomic_read(&other_pdev->enable_cnt)) { - ql_dbg(ql_dbg_aer, base_vha, 0x9008, - "Found PCI func available and enable at 0x%x.\n", - fn); - pci_dev_put(other_pdev); - break; - } - pci_dev_put(other_pdev); - } - - if (!fn) { - /* Reset owner */ - ql_dbg(ql_dbg_aer, base_vha, 0x9009, - "This devfn is reset owner = 0x%x.\n", - ha->pdev->devfn); - qla82xx_idc_lock(ha); - - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_INITIALIZING); - - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, - QLA82XX_IDC_VERSION); - - drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - ql_dbg(ql_dbg_aer, base_vha, 0x900a, - "drv_active = 0x%x.\n", drv_active); - - qla82xx_idc_unlock(ha); - /* Reset if device is not already reset - * drv_active would be 0 if a reset has already been done - */ - if (drv_active) - rval = qla82xx_start_firmware(base_vha); - else - rval = QLA_SUCCESS; - qla82xx_idc_lock(ha); - - if (rval != QLA_SUCCESS) { - ql_log(ql_log_info, base_vha, 0x900b, - "HW State: FAILED.\n"); - qla82xx_clear_drv_active(ha); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - } else { - ql_log(ql_log_info, base_vha, 0x900c, - "HW State: READY.\n"); - qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_READY); - qla82xx_idc_unlock(ha); - ha->flags.isp82xx_fw_hung = 0; - rval = qla82xx_restart_isp(base_vha); - qla82xx_idc_lock(ha); - /* Clear driver state register */ - qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); - qla82xx_set_drv_active(base_vha); - } - qla82xx_idc_unlock(ha); - } else { - ql_dbg(ql_dbg_aer, base_vha, 0x900d, - "This devfn is not reset owner = 0x%x.\n", - ha->pdev->devfn); - if ((qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == - QLA82XX_DEV_READY)) { - ha->flags.isp82xx_fw_hung = 0; - rval = qla82xx_restart_isp(base_vha); - qla82xx_idc_lock(ha); - qla82xx_set_drv_active(base_vha); - qla82xx_idc_unlock(ha); - } - } - clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - - return rval; -} - -static pci_ers_result_t -qla2xxx_pci_slot_reset(struct pci_dev *pdev) -{ - pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; - scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); - struct qla_hw_data *ha = base_vha->hw; - struct rsp_que *rsp; - int rc, retries = 10; - - ql_dbg(ql_dbg_aer, base_vha, 0x9004, - "Slot Reset.\n"); - - /* Workaround: qla2xxx driver which access hardware earlier - * needs error state to be pci_channel_io_online. - * Otherwise mailbox command timesout. - */ - pdev->error_state = pci_channel_io_normal; - - pci_restore_state(pdev); - - /* pci_restore_state() clears the saved_state flag of the device - * save restored state which resets saved_state flag - */ - pci_save_state(pdev); - - if (ha->mem_only) - rc = pci_enable_device_mem(pdev); - else - rc = pci_enable_device(pdev); - - if (rc) { - ql_log(ql_log_warn, base_vha, 0x9005, - "Can't re-enable PCI device after reset.\n"); - goto exit_slot_reset; - } - - rsp = ha->rsp_q_map[0]; - if (qla2x00_request_irqs(ha, rsp)) - goto exit_slot_reset; - - if (ha->isp_ops->pci_config(base_vha)) - goto exit_slot_reset; - - if (IS_QLA82XX(ha)) { - if (qla82xx_error_recovery(base_vha) == QLA_SUCCESS) { - ret = PCI_ERS_RESULT_RECOVERED; - goto exit_slot_reset; - } else - goto exit_slot_reset; - } - - while (ha->flags.mbox_busy && retries--) - msleep(1000); - - set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - if (ha->isp_ops->abort_isp(base_vha) == QLA_SUCCESS) - ret = PCI_ERS_RESULT_RECOVERED; - clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - - -exit_slot_reset: - ql_dbg(ql_dbg_aer, base_vha, 0x900e, - "slot_reset return %x.\n", ret); - - return ret; -} - -static void -qla2xxx_pci_resume(struct pci_dev *pdev) -{ - scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); - struct qla_hw_data *ha = base_vha->hw; - int ret; - - ql_dbg(ql_dbg_aer, base_vha, 0x900f, - "pci_resume.\n"); - - ret = qla2x00_wait_for_hba_online(base_vha); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_fatal, base_vha, 0x9002, - "The device failed to resume I/O from slot/link_reset.\n"); - } - - pci_cleanup_aer_uncorrect_error_status(pdev); - - ha->flags.eeh_busy = 0; -} - -static struct pci_error_handlers qla2xxx_err_handler = { - .error_detected = qla2xxx_pci_error_detected, - .mmio_enabled = qla2xxx_pci_mmio_enabled, - .slot_reset = qla2xxx_pci_slot_reset, - .resume = qla2xxx_pci_resume, -}; - -static struct pci_device_id qla2xxx_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2100) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2200) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2300) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2312) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2322) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6312) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP6322) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2422) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2432) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8432) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5422) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP5432) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2532) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2031) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8001) }, - { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8021) }, - { 0 }, -}; -MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); - -static struct pci_driver qla2xxx_pci_driver = { - .name = QLA2XXX_DRIVER_NAME, - .driver = { - .owner = THIS_MODULE, - }, - .id_table = qla2xxx_pci_tbl, - .probe = qla2x00_probe_one, - .remove = qla2x00_remove_one, - .shutdown = qla2x00_shutdown, - .err_handler = &qla2xxx_err_handler, -}; - -static struct file_operations apidev_fops = { - .owner = THIS_MODULE, - .llseek = noop_llseek, -}; - -/** - * qla2x00_module_init - Module initialization. - **/ -static int __init -qla2x00_module_init(void) -{ - int ret = 0; - - /* Allocate cache for SRBs. */ - srb_cachep = kmem_cache_create("qla2xxx_srbs", sizeof(srb_t), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (srb_cachep == NULL) { - ql_log(ql_log_fatal, NULL, 0x0001, - "Unable to allocate SRB cache...Failing load!.\n"); - return -ENOMEM; - } - - /* Derive version string. */ - strcpy(qla2x00_version_str, QLA2XXX_VERSION); - if (ql2xextended_error_logging) - strcat(qla2x00_version_str, "-debug"); - - qla2xxx_transport_template = - fc_attach_transport(&qla2xxx_transport_functions); - if (!qla2xxx_transport_template) { - kmem_cache_destroy(srb_cachep); - ql_log(ql_log_fatal, NULL, 0x0002, - "fc_attach_transport failed...Failing load!.\n"); - return -ENODEV; - } - - apidev_major = register_chrdev(0, QLA2XXX_APIDEV, &apidev_fops); - if (apidev_major < 0) { - ql_log(ql_log_fatal, NULL, 0x0003, - "Unable to register char device %s.\n", QLA2XXX_APIDEV); - } - - qla2xxx_transport_vport_template = - fc_attach_transport(&qla2xxx_transport_vport_functions); - if (!qla2xxx_transport_vport_template) { - kmem_cache_destroy(srb_cachep); - fc_release_transport(qla2xxx_transport_template); - ql_log(ql_log_fatal, NULL, 0x0004, - "fc_attach_transport vport failed...Failing load!.\n"); - return -ENODEV; - } - ql_log(ql_log_info, NULL, 0x0005, - "QLogic Fibre Channel HBA Driver: %s.\n", - qla2x00_version_str); - ret = pci_register_driver(&qla2xxx_pci_driver); - if (ret) { - kmem_cache_destroy(srb_cachep); - fc_release_transport(qla2xxx_transport_template); - fc_release_transport(qla2xxx_transport_vport_template); - ql_log(ql_log_fatal, NULL, 0x0006, - "pci_register_driver failed...ret=%d Failing load!.\n", - ret); - } - return ret; -} - -/** - * qla2x00_module_exit - Module cleanup. - **/ -static void __exit -qla2x00_module_exit(void) -{ - unregister_chrdev(apidev_major, QLA2XXX_APIDEV); - pci_unregister_driver(&qla2xxx_pci_driver); - qla2x00_release_firmware(); - kmem_cache_destroy(srb_cachep); - if (ctx_cachep) - kmem_cache_destroy(ctx_cachep); - fc_release_transport(qla2xxx_transport_template); - fc_release_transport(qla2xxx_transport_vport_template); -} - -module_init(qla2x00_module_init); -module_exit(qla2x00_module_exit); - -MODULE_AUTHOR("QLogic Corporation"); -MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(QLA2XXX_VERSION); -MODULE_FIRMWARE(FW_FILE_ISP21XX); -MODULE_FIRMWARE(FW_FILE_ISP22XX); -MODULE_FIRMWARE(FW_FILE_ISP2300); -MODULE_FIRMWARE(FW_FILE_ISP2322); -MODULE_FIRMWARE(FW_FILE_ISP24XX); -MODULE_FIRMWARE(FW_FILE_ISP25XX); diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_settings.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_settings.h deleted file mode 100644 index d70f0300..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_settings.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#define MAX_RETRIES_OF_ISP_ABORT 5 - -/* Max time to wait for the loop to be in LOOP_READY state */ -#define MAX_LOOP_TIMEOUT (60 * 5) - -#include "qla_version.h" diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_sup.c b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_sup.c deleted file mode 100644 index a683e766..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_sup.c +++ /dev/null @@ -1,3044 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -#include "qla_def.h" - -#include -#include -#include -#include - -/* - * NVRAM support routines - */ - -/** - * qla2x00_lock_nvram_access() - - * @ha: HA context - */ -static void -qla2x00_lock_nvram_access(struct qla_hw_data *ha) -{ - uint16_t data; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) { - data = RD_REG_WORD(®->nvram); - while (data & NVR_BUSY) { - udelay(100); - data = RD_REG_WORD(®->nvram); - } - - /* Lock resource */ - WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); - RD_REG_WORD(®->u.isp2300.host_semaphore); - udelay(5); - data = RD_REG_WORD(®->u.isp2300.host_semaphore); - while ((data & BIT_0) == 0) { - /* Lock failed */ - udelay(100); - WRT_REG_WORD(®->u.isp2300.host_semaphore, 0x1); - RD_REG_WORD(®->u.isp2300.host_semaphore); - udelay(5); - data = RD_REG_WORD(®->u.isp2300.host_semaphore); - } - } -} - -/** - * qla2x00_unlock_nvram_access() - - * @ha: HA context - */ -static void -qla2x00_unlock_nvram_access(struct qla_hw_data *ha) -{ - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) { - WRT_REG_WORD(®->u.isp2300.host_semaphore, 0); - RD_REG_WORD(®->u.isp2300.host_semaphore); - } -} - -/** - * qla2x00_nv_write() - Prepare for NVRAM read/write operation. - * @ha: HA context - * @data: Serial interface selector - */ -static void -qla2x00_nv_write(struct qla_hw_data *ha, uint16_t data) -{ - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - WRT_REG_WORD(®->nvram, data | NVR_SELECT | NVR_WRT_ENABLE); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - NVRAM_DELAY(); - WRT_REG_WORD(®->nvram, data | NVR_SELECT | NVR_CLOCK | - NVR_WRT_ENABLE); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - NVRAM_DELAY(); - WRT_REG_WORD(®->nvram, data | NVR_SELECT | NVR_WRT_ENABLE); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - NVRAM_DELAY(); -} - -/** - * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from - * NVRAM. - * @ha: HA context - * @nv_cmd: NVRAM command - * - * Bit definitions for NVRAM command: - * - * Bit 26 = start bit - * Bit 25, 24 = opcode - * Bit 23-16 = address - * Bit 15-0 = write data - * - * Returns the word read from nvram @addr. - */ -static uint16_t -qla2x00_nvram_request(struct qla_hw_data *ha, uint32_t nv_cmd) -{ - uint8_t cnt; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - uint16_t data = 0; - uint16_t reg_data; - - /* Send command to NVRAM. */ - nv_cmd <<= 5; - for (cnt = 0; cnt < 11; cnt++) { - if (nv_cmd & BIT_31) - qla2x00_nv_write(ha, NVR_DATA_OUT); - else - qla2x00_nv_write(ha, 0); - nv_cmd <<= 1; - } - - /* Read data from NVRAM. */ - for (cnt = 0; cnt < 16; cnt++) { - WRT_REG_WORD(®->nvram, NVR_SELECT | NVR_CLOCK); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - NVRAM_DELAY(); - data <<= 1; - reg_data = RD_REG_WORD(®->nvram); - if (reg_data & NVR_DATA_IN) - data |= BIT_0; - WRT_REG_WORD(®->nvram, NVR_SELECT); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - NVRAM_DELAY(); - } - - /* Deselect chip. */ - WRT_REG_WORD(®->nvram, NVR_DESELECT); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - NVRAM_DELAY(); - - return data; -} - - -/** - * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the - * request routine to get the word from NVRAM. - * @ha: HA context - * @addr: Address in NVRAM to read - * - * Returns the word read from nvram @addr. - */ -static uint16_t -qla2x00_get_nvram_word(struct qla_hw_data *ha, uint32_t addr) -{ - uint16_t data; - uint32_t nv_cmd; - - nv_cmd = addr << 16; - nv_cmd |= NV_READ_OP; - data = qla2x00_nvram_request(ha, nv_cmd); - - return (data); -} - -/** - * qla2x00_nv_deselect() - Deselect NVRAM operations. - * @ha: HA context - */ -static void -qla2x00_nv_deselect(struct qla_hw_data *ha) -{ - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - WRT_REG_WORD(®->nvram, NVR_DESELECT); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - NVRAM_DELAY(); -} - -/** - * qla2x00_write_nvram_word() - Write NVRAM data. - * @ha: HA context - * @addr: Address in NVRAM to write - * @data: word to program - */ -static void -qla2x00_write_nvram_word(struct qla_hw_data *ha, uint32_t addr, uint16_t data) -{ - int count; - uint16_t word; - uint32_t nv_cmd, wait_cnt; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - qla2x00_nv_write(ha, NVR_DATA_OUT); - qla2x00_nv_write(ha, 0); - qla2x00_nv_write(ha, 0); - - for (word = 0; word < 8; word++) - qla2x00_nv_write(ha, NVR_DATA_OUT); - - qla2x00_nv_deselect(ha); - - /* Write data */ - nv_cmd = (addr << 16) | NV_WRITE_OP; - nv_cmd |= data; - nv_cmd <<= 5; - for (count = 0; count < 27; count++) { - if (nv_cmd & BIT_31) - qla2x00_nv_write(ha, NVR_DATA_OUT); - else - qla2x00_nv_write(ha, 0); - - nv_cmd <<= 1; - } - - qla2x00_nv_deselect(ha); - - /* Wait for NVRAM to become ready */ - WRT_REG_WORD(®->nvram, NVR_SELECT); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - wait_cnt = NVR_WAIT_CNT; - do { - if (!--wait_cnt) { - ql_dbg(ql_dbg_user, vha, 0x708d, - "NVRAM didn't go ready...\n"); - break; - } - NVRAM_DELAY(); - word = RD_REG_WORD(®->nvram); - } while ((word & NVR_DATA_IN) == 0); - - qla2x00_nv_deselect(ha); - - /* Disable writes */ - qla2x00_nv_write(ha, NVR_DATA_OUT); - for (count = 0; count < 10; count++) - qla2x00_nv_write(ha, 0); - - qla2x00_nv_deselect(ha); -} - -static int -qla2x00_write_nvram_word_tmo(struct qla_hw_data *ha, uint32_t addr, - uint16_t data, uint32_t tmo) -{ - int ret, count; - uint16_t word; - uint32_t nv_cmd; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - ret = QLA_SUCCESS; - - qla2x00_nv_write(ha, NVR_DATA_OUT); - qla2x00_nv_write(ha, 0); - qla2x00_nv_write(ha, 0); - - for (word = 0; word < 8; word++) - qla2x00_nv_write(ha, NVR_DATA_OUT); - - qla2x00_nv_deselect(ha); - - /* Write data */ - nv_cmd = (addr << 16) | NV_WRITE_OP; - nv_cmd |= data; - nv_cmd <<= 5; - for (count = 0; count < 27; count++) { - if (nv_cmd & BIT_31) - qla2x00_nv_write(ha, NVR_DATA_OUT); - else - qla2x00_nv_write(ha, 0); - - nv_cmd <<= 1; - } - - qla2x00_nv_deselect(ha); - - /* Wait for NVRAM to become ready */ - WRT_REG_WORD(®->nvram, NVR_SELECT); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - do { - NVRAM_DELAY(); - word = RD_REG_WORD(®->nvram); - if (!--tmo) { - ret = QLA_FUNCTION_FAILED; - break; - } - } while ((word & NVR_DATA_IN) == 0); - - qla2x00_nv_deselect(ha); - - /* Disable writes */ - qla2x00_nv_write(ha, NVR_DATA_OUT); - for (count = 0; count < 10; count++) - qla2x00_nv_write(ha, 0); - - qla2x00_nv_deselect(ha); - - return ret; -} - -/** - * qla2x00_clear_nvram_protection() - - * @ha: HA context - */ -static int -qla2x00_clear_nvram_protection(struct qla_hw_data *ha) -{ - int ret, stat; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - uint32_t word, wait_cnt; - uint16_t wprot, wprot_old; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - /* Clear NVRAM write protection. */ - ret = QLA_FUNCTION_FAILED; - - wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base)); - stat = qla2x00_write_nvram_word_tmo(ha, ha->nvram_base, - __constant_cpu_to_le16(0x1234), 100000); - wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base)); - if (stat != QLA_SUCCESS || wprot != 0x1234) { - /* Write enable. */ - qla2x00_nv_write(ha, NVR_DATA_OUT); - qla2x00_nv_write(ha, 0); - qla2x00_nv_write(ha, 0); - for (word = 0; word < 8; word++) - qla2x00_nv_write(ha, NVR_DATA_OUT); - - qla2x00_nv_deselect(ha); - - /* Enable protection register. */ - qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); - qla2x00_nv_write(ha, NVR_PR_ENABLE); - qla2x00_nv_write(ha, NVR_PR_ENABLE); - for (word = 0; word < 8; word++) - qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); - - qla2x00_nv_deselect(ha); - - /* Clear protection register (ffff is cleared). */ - qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); - qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); - qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); - for (word = 0; word < 8; word++) - qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); - - qla2x00_nv_deselect(ha); - - /* Wait for NVRAM to become ready. */ - WRT_REG_WORD(®->nvram, NVR_SELECT); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - wait_cnt = NVR_WAIT_CNT; - do { - if (!--wait_cnt) { - ql_dbg(ql_dbg_user, vha, 0x708e, - "NVRAM didn't go ready...\n"); - break; - } - NVRAM_DELAY(); - word = RD_REG_WORD(®->nvram); - } while ((word & NVR_DATA_IN) == 0); - - if (wait_cnt) - ret = QLA_SUCCESS; - } else - qla2x00_write_nvram_word(ha, ha->nvram_base, wprot_old); - - return ret; -} - -static void -qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat) -{ - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - uint32_t word, wait_cnt; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - if (stat != QLA_SUCCESS) - return; - - /* Set NVRAM write protection. */ - /* Write enable. */ - qla2x00_nv_write(ha, NVR_DATA_OUT); - qla2x00_nv_write(ha, 0); - qla2x00_nv_write(ha, 0); - for (word = 0; word < 8; word++) - qla2x00_nv_write(ha, NVR_DATA_OUT); - - qla2x00_nv_deselect(ha); - - /* Enable protection register. */ - qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); - qla2x00_nv_write(ha, NVR_PR_ENABLE); - qla2x00_nv_write(ha, NVR_PR_ENABLE); - for (word = 0; word < 8; word++) - qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE); - - qla2x00_nv_deselect(ha); - - /* Enable protection register. */ - qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); - qla2x00_nv_write(ha, NVR_PR_ENABLE); - qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT); - for (word = 0; word < 8; word++) - qla2x00_nv_write(ha, NVR_PR_ENABLE); - - qla2x00_nv_deselect(ha); - - /* Wait for NVRAM to become ready. */ - WRT_REG_WORD(®->nvram, NVR_SELECT); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - wait_cnt = NVR_WAIT_CNT; - do { - if (!--wait_cnt) { - ql_dbg(ql_dbg_user, vha, 0x708f, - "NVRAM didn't go ready...\n"); - break; - } - NVRAM_DELAY(); - word = RD_REG_WORD(®->nvram); - } while ((word & NVR_DATA_IN) == 0); -} - - -/*****************************************************************************/ -/* Flash Manipulation Routines */ -/*****************************************************************************/ - -static inline uint32_t -flash_conf_addr(struct qla_hw_data *ha, uint32_t faddr) -{ - return ha->flash_conf_off | faddr; -} - -static inline uint32_t -flash_data_addr(struct qla_hw_data *ha, uint32_t faddr) -{ - return ha->flash_data_off | faddr; -} - -static inline uint32_t -nvram_conf_addr(struct qla_hw_data *ha, uint32_t naddr) -{ - return ha->nvram_conf_off | naddr; -} - -static inline uint32_t -nvram_data_addr(struct qla_hw_data *ha, uint32_t naddr) -{ - return ha->nvram_data_off | naddr; -} - -static uint32_t -qla24xx_read_flash_dword(struct qla_hw_data *ha, uint32_t addr) -{ - int rval; - uint32_t cnt, data; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - WRT_REG_DWORD(®->flash_addr, addr & ~FARX_DATA_FLAG); - /* Wait for READ cycle to complete. */ - rval = QLA_SUCCESS; - for (cnt = 3000; - (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) == 0 && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(10); - else - rval = QLA_FUNCTION_TIMEOUT; - cond_resched(); - } - - /* TODO: What happens if we time out? */ - data = 0xDEADDEAD; - if (rval == QLA_SUCCESS) - data = RD_REG_DWORD(®->flash_data); - - return data; -} - -uint32_t * -qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, - uint32_t dwords) -{ - uint32_t i; - struct qla_hw_data *ha = vha->hw; - - /* Dword reads to flash. */ - for (i = 0; i < dwords; i++, faddr++) - dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, - flash_data_addr(ha, faddr))); - - return dwptr; -} - -static int -qla24xx_write_flash_dword(struct qla_hw_data *ha, uint32_t addr, uint32_t data) -{ - int rval; - uint32_t cnt; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - WRT_REG_DWORD(®->flash_data, data); - RD_REG_DWORD(®->flash_data); /* PCI Posting. */ - WRT_REG_DWORD(®->flash_addr, addr | FARX_DATA_FLAG); - /* Wait for Write cycle to complete. */ - rval = QLA_SUCCESS; - for (cnt = 500000; (RD_REG_DWORD(®->flash_addr) & FARX_DATA_FLAG) && - rval == QLA_SUCCESS; cnt--) { - if (cnt) - udelay(10); - else - rval = QLA_FUNCTION_TIMEOUT; - cond_resched(); - } - return rval; -} - -static void -qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id, - uint8_t *flash_id) -{ - uint32_t ids; - - ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x03ab)); - *man_id = LSB(ids); - *flash_id = MSB(ids); - - /* Check if man_id and flash_id are valid. */ - if (ids != 0xDEADDEAD && (*man_id == 0 || *flash_id == 0)) { - /* Read information using 0x9f opcode - * Device ID, Mfg ID would be read in the format: - * - * Example: ATMEL 0x00 01 45 1F - * Extract MFG and Dev ID from last two bytes. - */ - ids = qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x009f)); - *man_id = LSB(ids); - *flash_id = MSB(ids); - } -} - -static int -qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start) -{ - const char *loc, *locations[] = { "DEF", "PCI" }; - uint32_t pcihdr, pcids; - uint32_t *dcode; - uint8_t *buf, *bcode, last_image; - uint16_t cnt, chksum, *wptr; - struct qla_flt_location *fltl; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - /* - * FLT-location structure resides after the last PCI region. - */ - - /* Begin with sane defaults. */ - loc = locations[0]; - *start = 0; - if (IS_QLA24XX_TYPE(ha)) - *start = FA_FLASH_LAYOUT_ADDR_24; - else if (IS_QLA25XX(ha)) - *start = FA_FLASH_LAYOUT_ADDR; - else if (IS_QLA81XX(ha)) - *start = FA_FLASH_LAYOUT_ADDR_81; - else if (IS_QLA82XX(ha)) { - *start = FA_FLASH_LAYOUT_ADDR_82; - goto end; - } else if (IS_QLA83XX(ha)) { - *start = FA_FLASH_LAYOUT_ADDR_83; - goto end; - } - /* Begin with first PCI expansion ROM header. */ - buf = (uint8_t *)req->ring; - dcode = (uint32_t *)req->ring; - pcihdr = 0; - last_image = 1; - do { - /* Verify PCI expansion ROM header. */ - qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20); - bcode = buf + (pcihdr % 4); - if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) - goto end; - - /* Locate PCI data structure. */ - pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]); - qla24xx_read_flash_data(vha, dcode, pcids >> 2, 0x20); - bcode = buf + (pcihdr % 4); - - /* Validate signature of PCI data structure. */ - if (bcode[0x0] != 'P' || bcode[0x1] != 'C' || - bcode[0x2] != 'I' || bcode[0x3] != 'R') - goto end; - - last_image = bcode[0x15] & BIT_7; - - /* Locate next PCI expansion ROM. */ - pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512; - } while (!last_image); - - /* Now verify FLT-location structure. */ - fltl = (struct qla_flt_location *)req->ring; - qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, - sizeof(struct qla_flt_location) >> 2); - if (fltl->sig[0] != 'Q' || fltl->sig[1] != 'F' || - fltl->sig[2] != 'L' || fltl->sig[3] != 'T') - goto end; - - wptr = (uint16_t *)req->ring; - cnt = sizeof(struct qla_flt_location) >> 1; - for (chksum = 0; cnt; cnt--) - chksum += le16_to_cpu(*wptr++); - if (chksum) { - ql_log(ql_log_fatal, vha, 0x0045, - "Inconsistent FLTL detected: checksum=0x%x.\n", chksum); - ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010e, - buf, sizeof(struct qla_flt_location)); - return QLA_FUNCTION_FAILED; - } - - /* Good data. Use specified location. */ - loc = locations[1]; - *start = (le16_to_cpu(fltl->start_hi) << 16 | - le16_to_cpu(fltl->start_lo)) >> 2; -end: - ql_dbg(ql_dbg_init, vha, 0x0046, - "FLTL[%s] = 0x%x.\n", - loc, *start); - return QLA_SUCCESS; -} - -static void -qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) -{ - const char *loc, *locations[] = { "DEF", "FLT" }; - const uint32_t def_fw[] = - { FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 }; - const uint32_t def_boot[] = - { FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR_81 }; - const uint32_t def_vpd_nvram[] = - { FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR_81 }; - const uint32_t def_vpd0[] = - { 0, 0, FA_VPD0_ADDR_81 }; - const uint32_t def_vpd1[] = - { 0, 0, FA_VPD1_ADDR_81 }; - const uint32_t def_nvram0[] = - { 0, 0, FA_NVRAM0_ADDR_81 }; - const uint32_t def_nvram1[] = - { 0, 0, FA_NVRAM1_ADDR_81 }; - const uint32_t def_fdt[] = - { FA_FLASH_DESCR_ADDR_24, FA_FLASH_DESCR_ADDR, - FA_FLASH_DESCR_ADDR_81 }; - const uint32_t def_npiv_conf0[] = - { FA_NPIV_CONF0_ADDR_24, FA_NPIV_CONF0_ADDR, - FA_NPIV_CONF0_ADDR_81 }; - const uint32_t def_npiv_conf1[] = - { FA_NPIV_CONF1_ADDR_24, FA_NPIV_CONF1_ADDR, - FA_NPIV_CONF1_ADDR_81 }; - const uint32_t fcp_prio_cfg0[] = - { FA_FCP_PRIO0_ADDR, FA_FCP_PRIO0_ADDR_25, - 0 }; - const uint32_t fcp_prio_cfg1[] = - { FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25, - 0 }; - uint32_t def; - uint16_t *wptr; - uint16_t cnt, chksum; - uint32_t start; - struct qla_flt_header *flt; - struct qla_flt_region *region; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - def = 0; - if (IS_QLA25XX(ha)) - def = 1; - else if (IS_QLA81XX(ha)) - def = 2; - - /* Assign FCP prio region since older adapters may not have FLT, or - FCP prio region in it's FLT. - */ - ha->flt_region_fcp_prio = ha->flags.port0 ? - fcp_prio_cfg0[def] : fcp_prio_cfg1[def]; - - ha->flt_region_flt = flt_addr; - wptr = (uint16_t *)req->ring; - flt = (struct qla_flt_header *)req->ring; - region = (struct qla_flt_region *)&flt[1]; - ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, - flt_addr << 2, OPTROM_BURST_SIZE); - if (*wptr == __constant_cpu_to_le16(0xffff)) - goto no_flash_data; - if (flt->version != __constant_cpu_to_le16(1)) { - ql_log(ql_log_warn, vha, 0x0047, - "Unsupported FLT detected: version=0x%x length=0x%x checksum=0x%x.\n", - le16_to_cpu(flt->version), le16_to_cpu(flt->length), - le16_to_cpu(flt->checksum)); - goto no_flash_data; - } - - cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1; - for (chksum = 0; cnt; cnt--) - chksum += le16_to_cpu(*wptr++); - if (chksum) { - ql_log(ql_log_fatal, vha, 0x0048, - "Inconsistent FLT detected: version=0x%x length=0x%x checksum=0x%x.\n", - le16_to_cpu(flt->version), le16_to_cpu(flt->length), - le16_to_cpu(flt->checksum)); - goto no_flash_data; - } - - loc = locations[1]; - cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region); - for ( ; cnt; cnt--, region++) { - /* Store addresses as DWORD offsets. */ - start = le32_to_cpu(region->start) >> 2; - ql_dbg(ql_dbg_init, vha, 0x0049, - "FLT[%02x]: start=0x%x " - "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), - start, le32_to_cpu(region->end) >> 2, - le32_to_cpu(region->size)); - - switch (le32_to_cpu(region->code) & 0xff) { - case FLT_REG_FCOE_FW: - if (!IS_QLA8031(ha)) - break; - ha->flt_region_fw = start; - break; - case FLT_REG_FW: - if (IS_QLA8031(ha)) - break; - ha->flt_region_fw = start; - break; - case FLT_REG_BOOT_CODE: - ha->flt_region_boot = start; - break; - case FLT_REG_VPD_0: - if (IS_QLA8031(ha)) - break; - ha->flt_region_vpd_nvram = start; - if (IS_QLA82XX(ha)) - break; - if (ha->flags.port0) - ha->flt_region_vpd = start; - break; - case FLT_REG_VPD_1: - if (IS_QLA82XX(ha) || IS_QLA8031(ha)) - break; - if (!ha->flags.port0) - ha->flt_region_vpd = start; - break; - case FLT_REG_NVRAM_0: - if (IS_QLA8031(ha)) - break; - if (ha->flags.port0) - ha->flt_region_nvram = start; - break; - case FLT_REG_NVRAM_1: - if (IS_QLA8031(ha)) - break; - if (!ha->flags.port0) - ha->flt_region_nvram = start; - break; - case FLT_REG_FDT: - ha->flt_region_fdt = start; - break; - case FLT_REG_NPIV_CONF_0: - if (ha->flags.port0) - ha->flt_region_npiv_conf = start; - break; - case FLT_REG_NPIV_CONF_1: - if (!ha->flags.port0) - ha->flt_region_npiv_conf = start; - break; - case FLT_REG_GOLD_FW: - ha->flt_region_gold_fw = start; - break; - case FLT_REG_FCP_PRIO_0: - if (ha->flags.port0) - ha->flt_region_fcp_prio = start; - break; - case FLT_REG_FCP_PRIO_1: - if (!ha->flags.port0) - ha->flt_region_fcp_prio = start; - break; - case FLT_REG_BOOT_CODE_82XX: - ha->flt_region_boot = start; - break; - case FLT_REG_FW_82XX: - ha->flt_region_fw = start; - break; - case FLT_REG_GOLD_FW_82XX: - ha->flt_region_gold_fw = start; - break; - case FLT_REG_BOOTLOAD_82XX: - ha->flt_region_bootload = start; - break; - case FLT_REG_VPD_82XX: - ha->flt_region_vpd = start; - break; - case FLT_REG_FCOE_VPD_0: - if (!IS_QLA8031(ha)) - break; - ha->flt_region_vpd_nvram = start; - if (ha->flags.port0) - ha->flt_region_vpd = start; - break; - case FLT_REG_FCOE_VPD_1: - if (!IS_QLA8031(ha)) - break; - if (!ha->flags.port0) - ha->flt_region_vpd = start; - break; - case FLT_REG_FCOE_NVRAM_0: - if (!IS_QLA8031(ha)) - break; - if (ha->flags.port0) - ha->flt_region_nvram = start; - break; - case FLT_REG_FCOE_NVRAM_1: - if (!IS_QLA8031(ha)) - break; - if (!ha->flags.port0) - ha->flt_region_nvram = start; - break; - } - } - goto done; - -no_flash_data: - /* Use hardcoded defaults. */ - loc = locations[0]; - ha->flt_region_fw = def_fw[def]; - ha->flt_region_boot = def_boot[def]; - ha->flt_region_vpd_nvram = def_vpd_nvram[def]; - ha->flt_region_vpd = ha->flags.port0 ? - def_vpd0[def] : def_vpd1[def]; - ha->flt_region_nvram = ha->flags.port0 ? - def_nvram0[def] : def_nvram1[def]; - ha->flt_region_fdt = def_fdt[def]; - ha->flt_region_npiv_conf = ha->flags.port0 ? - def_npiv_conf0[def] : def_npiv_conf1[def]; -done: - ql_dbg(ql_dbg_init, vha, 0x004a, - "FLT[%s]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x nvram=0x%x " - "fdt=0x%x flt=0x%x npiv=0x%x fcp_prif_cfg=0x%x.\n", - loc, ha->flt_region_boot, ha->flt_region_fw, - ha->flt_region_vpd_nvram, ha->flt_region_vpd, ha->flt_region_nvram, - ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf, - ha->flt_region_fcp_prio); -} - -static void -qla2xxx_get_fdt_info(scsi_qla_host_t *vha) -{ -#define FLASH_BLK_SIZE_4K 0x1000 -#define FLASH_BLK_SIZE_32K 0x8000 -#define FLASH_BLK_SIZE_64K 0x10000 - const char *loc, *locations[] = { "MID", "FDT" }; - uint16_t cnt, chksum; - uint16_t *wptr; - struct qla_fdt_layout *fdt; - uint8_t man_id, flash_id; - uint16_t mid = 0, fid = 0; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - wptr = (uint16_t *)req->ring; - fdt = (struct qla_fdt_layout *)req->ring; - ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, - ha->flt_region_fdt << 2, OPTROM_BURST_SIZE); - if (*wptr == __constant_cpu_to_le16(0xffff)) - goto no_flash_data; - if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || - fdt->sig[3] != 'D') - goto no_flash_data; - - for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1; - cnt++) - chksum += le16_to_cpu(*wptr++); - if (chksum) { - ql_dbg(ql_dbg_init, vha, 0x004c, - "Inconsistent FDT detected:" - " checksum=0x%x id=%c version0x%x.\n", chksum, - fdt->sig[0], le16_to_cpu(fdt->version)); - ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113, - (uint8_t *)fdt, sizeof(*fdt)); - goto no_flash_data; - } - - loc = locations[1]; - mid = le16_to_cpu(fdt->man_id); - fid = le16_to_cpu(fdt->id); - ha->fdt_wrt_disable = fdt->wrt_disable_bits; - ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0300 | fdt->erase_cmd); - ha->fdt_block_size = le32_to_cpu(fdt->block_size); - if (fdt->unprotect_sec_cmd) { - ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0300 | - fdt->unprotect_sec_cmd); - ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? - flash_conf_addr(ha, 0x0300 | fdt->protect_sec_cmd): - flash_conf_addr(ha, 0x0336); - } - goto done; -no_flash_data: - loc = locations[0]; - if (IS_QLA82XX(ha)) { - ha->fdt_block_size = FLASH_BLK_SIZE_64K; - goto done; - } - qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); - mid = man_id; - fid = flash_id; - ha->fdt_wrt_disable = 0x9c; - ha->fdt_erase_cmd = flash_conf_addr(ha, 0x03d8); - switch (man_id) { - case 0xbf: /* STT flash. */ - if (flash_id == 0x8e) - ha->fdt_block_size = FLASH_BLK_SIZE_64K; - else - ha->fdt_block_size = FLASH_BLK_SIZE_32K; - - if (flash_id == 0x80) - ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0352); - break; - case 0x13: /* ST M25P80. */ - ha->fdt_block_size = FLASH_BLK_SIZE_64K; - break; - case 0x1f: /* Atmel 26DF081A. */ - ha->fdt_block_size = FLASH_BLK_SIZE_4K; - ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0320); - ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0339); - ha->fdt_protect_sec_cmd = flash_conf_addr(ha, 0x0336); - break; - default: - /* Default to 64 kb sector size. */ - ha->fdt_block_size = FLASH_BLK_SIZE_64K; - break; - } -done: - ql_dbg(ql_dbg_init, vha, 0x004d, - "FDT[%s]: (0x%x/0x%x) erase=0x%x " - "pr=%x wrtd=0x%x blk=0x%x.\n", - loc, mid, fid, - ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd, - ha->fdt_wrt_disable, ha->fdt_block_size); - -} - -static void -qla2xxx_get_idc_param(scsi_qla_host_t *vha) -{ -#define QLA82XX_IDC_PARAM_ADDR 0x003e885c - uint32_t *wptr; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - - if (!IS_QLA82XX(ha)) - return; - - wptr = (uint32_t *)req->ring; - ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, - QLA82XX_IDC_PARAM_ADDR , 8); - - if (*wptr == __constant_cpu_to_le32(0xffffffff)) { - ha->nx_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT; - ha->nx_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT; - } else { - ha->nx_dev_init_timeout = le32_to_cpu(*wptr++); - ha->nx_reset_timeout = le32_to_cpu(*wptr); - } - ql_dbg(ql_dbg_init, vha, 0x004e, - "nx_dev_init_timeout=%d " - "nx_reset_timeout=%d.\n", ha->nx_dev_init_timeout, - ha->nx_reset_timeout); - return; -} - -int -qla2xxx_get_flash_info(scsi_qla_host_t *vha) -{ - int ret; - uint32_t flt_addr; - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && - !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha)) - return QLA_SUCCESS; - - ret = qla2xxx_find_flt_start(vha, &flt_addr); - if (ret != QLA_SUCCESS) - return ret; - - qla2xxx_get_flt_info(vha, flt_addr); - qla2xxx_get_fdt_info(vha); - qla2xxx_get_idc_param(vha); - - return QLA_SUCCESS; -} - -void -qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) -{ -#define NPIV_CONFIG_SIZE (16*1024) - void *data; - uint16_t *wptr; - uint16_t cnt, chksum; - int i; - struct qla_npiv_header hdr; - struct qla_npiv_entry *entry; - struct qla_hw_data *ha = vha->hw; - - if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && - !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha)) - return; - - if (ha->flags.isp82xx_reset_hdlr_active) - return; - - ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr, - ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header)); - if (hdr.version == __constant_cpu_to_le16(0xffff)) - return; - if (hdr.version != __constant_cpu_to_le16(1)) { - ql_dbg(ql_dbg_user, vha, 0x7090, - "Unsupported NPIV-Config " - "detected: version=0x%x entries=0x%x checksum=0x%x.\n", - le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries), - le16_to_cpu(hdr.checksum)); - return; - } - - data = kmalloc(NPIV_CONFIG_SIZE, GFP_KERNEL); - if (!data) { - ql_log(ql_log_warn, vha, 0x7091, - "Unable to allocate memory for data.\n"); - return; - } - - ha->isp_ops->read_optrom(vha, (uint8_t *)data, - ha->flt_region_npiv_conf << 2, NPIV_CONFIG_SIZE); - - cnt = (sizeof(struct qla_npiv_header) + le16_to_cpu(hdr.entries) * - sizeof(struct qla_npiv_entry)) >> 1; - for (wptr = data, chksum = 0; cnt; cnt--) - chksum += le16_to_cpu(*wptr++); - if (chksum) { - ql_dbg(ql_dbg_user, vha, 0x7092, - "Inconsistent NPIV-Config " - "detected: version=0x%x entries=0x%x checksum=0x%x.\n", - le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries), - le16_to_cpu(hdr.checksum)); - goto done; - } - - entry = data + sizeof(struct qla_npiv_header); - cnt = le16_to_cpu(hdr.entries); - for (i = 0; cnt; cnt--, entry++, i++) { - uint16_t flags; - struct fc_vport_identifiers vid; - struct fc_vport *vport; - - memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry)); - - flags = le16_to_cpu(entry->flags); - if (flags == 0xffff) - continue; - if ((flags & BIT_0) == 0) - continue; - - memset(&vid, 0, sizeof(vid)); - vid.roles = FC_PORT_ROLE_FCP_INITIATOR; - vid.vport_type = FC_PORTTYPE_NPIV; - vid.disable = false; - vid.port_name = wwn_to_u64(entry->port_name); - vid.node_name = wwn_to_u64(entry->node_name); - - ql_dbg(ql_dbg_user, vha, 0x7093, - "NPIV[%02x]: wwpn=%llx " - "wwnn=%llx vf_id=0x%x Q_qos=0x%x F_qos=0x%x.\n", cnt, - (unsigned long long)vid.port_name, - (unsigned long long)vid.node_name, - le16_to_cpu(entry->vf_id), - entry->q_qos, entry->f_qos); - - if (i < QLA_PRECONFIG_VPORTS) { - vport = fc_vport_create(vha->host, 0, &vid); - if (!vport) - ql_log(ql_log_warn, vha, 0x7094, - "NPIV-Config Failed to create vport [%02x]: " - "wwpn=%llx wwnn=%llx.\n", cnt, - (unsigned long long)vid.port_name, - (unsigned long long)vid.node_name); - } - } -done: - kfree(data); -} - -static int -qla24xx_unprotect_flash(scsi_qla_host_t *vha) -{ - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - if (ha->flags.fac_supported) - return qla81xx_fac_do_write_enable(vha, 1); - - /* Enable flash write. */ - WRT_REG_DWORD(®->ctrl_status, - RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); - RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - - if (!ha->fdt_wrt_disable) - goto done; - - /* Disable flash write-protection, first clear SR protection bit */ - qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); - /* Then write zero again to clear remaining SR bits.*/ - qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0); -done: - return QLA_SUCCESS; -} - -static int -qla24xx_protect_flash(scsi_qla_host_t *vha) -{ - uint32_t cnt; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - if (ha->flags.fac_supported) - return qla81xx_fac_do_write_enable(vha, 0); - - if (!ha->fdt_wrt_disable) - goto skip_wrt_protect; - - /* Enable flash write-protection and wait for completion. */ - qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), - ha->fdt_wrt_disable); - for (cnt = 300; cnt && - qla24xx_read_flash_dword(ha, flash_conf_addr(ha, 0x005)) & BIT_0; - cnt--) { - udelay(10); - } - -skip_wrt_protect: - /* Disable flash write. */ - WRT_REG_DWORD(®->ctrl_status, - RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); - RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - - return QLA_SUCCESS; -} - -static int -qla24xx_erase_sector(scsi_qla_host_t *vha, uint32_t fdata) -{ - struct qla_hw_data *ha = vha->hw; - uint32_t start, finish; - - if (ha->flags.fac_supported) { - start = fdata >> 2; - finish = start + (ha->fdt_block_size >> 2) - 1; - return qla81xx_fac_erase_sector(vha, flash_data_addr(ha, - start), flash_data_addr(ha, finish)); - } - - return qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd, - (fdata & 0xff00) | ((fdata << 16) & 0xff0000) | - ((fdata >> 16) & 0xff)); -} - -static int -qla24xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, - uint32_t dwords) -{ - int ret; - uint32_t liter; - uint32_t sec_mask, rest_addr; - uint32_t fdata; - dma_addr_t optrom_dma; - void *optrom = NULL; - struct qla_hw_data *ha = vha->hw; - - /* Prepare burst-capable write on supported ISPs. */ - if ((IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha)) && - !(faddr & 0xfff) && dwords > OPTROM_BURST_DWORDS) { - optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, - &optrom_dma, GFP_KERNEL); - if (!optrom) { - ql_log(ql_log_warn, vha, 0x7095, - "Unable to allocate " - "memory for optrom burst write (%x KB).\n", - OPTROM_BURST_SIZE / 1024); - } - } - - rest_addr = (ha->fdt_block_size >> 2) - 1; - sec_mask = ~rest_addr; - - ret = qla24xx_unprotect_flash(vha); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7096, - "Unable to unprotect flash for update.\n"); - goto done; - } - - for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) { - fdata = (faddr & sec_mask) << 2; - - /* Are we at the beginning of a sector? */ - if ((faddr & rest_addr) == 0) { - /* Do sector unprotect. */ - if (ha->fdt_unprotect_sec_cmd) - qla24xx_write_flash_dword(ha, - ha->fdt_unprotect_sec_cmd, - (fdata & 0xff00) | ((fdata << 16) & - 0xff0000) | ((fdata >> 16) & 0xff)); - ret = qla24xx_erase_sector(vha, fdata); - if (ret != QLA_SUCCESS) { - ql_dbg(ql_dbg_user, vha, 0x7007, - "Unable to erase erase sector: address=%x.\n", - faddr); - break; - } - } - - /* Go with burst-write. */ - if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) { - /* Copy data to DMA'ble buffer. */ - memcpy(optrom, dwptr, OPTROM_BURST_SIZE); - - ret = qla2x00_load_ram(vha, optrom_dma, - flash_data_addr(ha, faddr), - OPTROM_BURST_DWORDS); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7097, - "Unable to burst-write optrom segment " - "(%x/%x/%llx).\n", ret, - flash_data_addr(ha, faddr), - (unsigned long long)optrom_dma); - ql_log(ql_log_warn, vha, 0x7098, - "Reverting to slow-write.\n"); - - dma_free_coherent(&ha->pdev->dev, - OPTROM_BURST_SIZE, optrom, optrom_dma); - optrom = NULL; - } else { - liter += OPTROM_BURST_DWORDS - 1; - faddr += OPTROM_BURST_DWORDS - 1; - dwptr += OPTROM_BURST_DWORDS - 1; - continue; - } - } - - ret = qla24xx_write_flash_dword(ha, - flash_data_addr(ha, faddr), cpu_to_le32(*dwptr)); - if (ret != QLA_SUCCESS) { - ql_dbg(ql_dbg_user, vha, 0x7006, - "Unable to program flash address=%x data=%x.\n", - faddr, *dwptr); - break; - } - - /* Do sector protect. */ - if (ha->fdt_unprotect_sec_cmd && - ((faddr & rest_addr) == rest_addr)) - qla24xx_write_flash_dword(ha, - ha->fdt_protect_sec_cmd, - (fdata & 0xff00) | ((fdata << 16) & - 0xff0000) | ((fdata >> 16) & 0xff)); - } - - ret = qla24xx_protect_flash(vha); - if (ret != QLA_SUCCESS) - ql_log(ql_log_warn, vha, 0x7099, - "Unable to protect flash after update.\n"); -done: - if (optrom) - dma_free_coherent(&ha->pdev->dev, - OPTROM_BURST_SIZE, optrom, optrom_dma); - - return ret; -} - -uint8_t * -qla2x00_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, - uint32_t bytes) -{ - uint32_t i; - uint16_t *wptr; - struct qla_hw_data *ha = vha->hw; - - /* Word reads to NVRAM via registers. */ - wptr = (uint16_t *)buf; - qla2x00_lock_nvram_access(ha); - for (i = 0; i < bytes >> 1; i++, naddr++) - wptr[i] = cpu_to_le16(qla2x00_get_nvram_word(ha, - naddr)); - qla2x00_unlock_nvram_access(ha); - - return buf; -} - -uint8_t * -qla24xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, - uint32_t bytes) -{ - uint32_t i; - uint32_t *dwptr; - struct qla_hw_data *ha = vha->hw; - - if (IS_QLA82XX(ha)) - return buf; - - /* Dword reads to flash. */ - dwptr = (uint32_t *)buf; - for (i = 0; i < bytes >> 2; i++, naddr++) - dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, - nvram_data_addr(ha, naddr))); - - return buf; -} - -int -qla2x00_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, - uint32_t bytes) -{ - int ret, stat; - uint32_t i; - uint16_t *wptr; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - - ret = QLA_SUCCESS; - - spin_lock_irqsave(&ha->hardware_lock, flags); - qla2x00_lock_nvram_access(ha); - - /* Disable NVRAM write-protection. */ - stat = qla2x00_clear_nvram_protection(ha); - - wptr = (uint16_t *)buf; - for (i = 0; i < bytes >> 1; i++, naddr++) { - qla2x00_write_nvram_word(ha, naddr, - cpu_to_le16(*wptr)); - wptr++; - } - - /* Enable NVRAM write-protection. */ - qla2x00_set_nvram_protection(ha, stat); - - qla2x00_unlock_nvram_access(ha); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return ret; -} - -int -qla24xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, - uint32_t bytes) -{ - int ret; - uint32_t i; - uint32_t *dwptr; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - ret = QLA_SUCCESS; - - if (IS_QLA82XX(ha)) - return ret; - - /* Enable flash write. */ - WRT_REG_DWORD(®->ctrl_status, - RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); - RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - - /* Disable NVRAM write-protection. */ - qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0); - qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0); - - /* Dword writes to flash. */ - dwptr = (uint32_t *)buf; - for (i = 0; i < bytes >> 2; i++, naddr++, dwptr++) { - ret = qla24xx_write_flash_dword(ha, - nvram_data_addr(ha, naddr), cpu_to_le32(*dwptr)); - if (ret != QLA_SUCCESS) { - ql_dbg(ql_dbg_user, vha, 0x709a, - "Unable to program nvram address=%x data=%x.\n", - naddr, *dwptr); - break; - } - } - - /* Enable NVRAM write-protection. */ - qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0x8c); - - /* Disable flash write. */ - WRT_REG_DWORD(®->ctrl_status, - RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); - RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - - return ret; -} - -uint8_t * -qla25xx_read_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, - uint32_t bytes) -{ - uint32_t i; - uint32_t *dwptr; - struct qla_hw_data *ha = vha->hw; - - /* Dword reads to flash. */ - dwptr = (uint32_t *)buf; - for (i = 0; i < bytes >> 2; i++, naddr++) - dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, - flash_data_addr(ha, ha->flt_region_vpd_nvram | naddr))); - - return buf; -} - -int -qla25xx_write_nvram_data(scsi_qla_host_t *vha, uint8_t *buf, uint32_t naddr, - uint32_t bytes) -{ - struct qla_hw_data *ha = vha->hw; -#define RMW_BUFFER_SIZE (64 * 1024) - uint8_t *dbuf; - - dbuf = vmalloc(RMW_BUFFER_SIZE); - if (!dbuf) - return QLA_MEMORY_ALLOC_FAILED; - ha->isp_ops->read_optrom(vha, dbuf, ha->flt_region_vpd_nvram << 2, - RMW_BUFFER_SIZE); - memcpy(dbuf + (naddr << 2), buf, bytes); - ha->isp_ops->write_optrom(vha, dbuf, ha->flt_region_vpd_nvram << 2, - RMW_BUFFER_SIZE); - vfree(dbuf); - - return QLA_SUCCESS; -} - -static inline void -qla2x00_flip_colors(struct qla_hw_data *ha, uint16_t *pflags) -{ - if (IS_QLA2322(ha)) { - /* Flip all colors. */ - if (ha->beacon_color_state == QLA_LED_ALL_ON) { - /* Turn off. */ - ha->beacon_color_state = 0; - *pflags = GPIO_LED_ALL_OFF; - } else { - /* Turn on. */ - ha->beacon_color_state = QLA_LED_ALL_ON; - *pflags = GPIO_LED_RGA_ON; - } - } else { - /* Flip green led only. */ - if (ha->beacon_color_state == QLA_LED_GRN_ON) { - /* Turn off. */ - ha->beacon_color_state = 0; - *pflags = GPIO_LED_GREEN_OFF_AMBER_OFF; - } else { - /* Turn on. */ - ha->beacon_color_state = QLA_LED_GRN_ON; - *pflags = GPIO_LED_GREEN_ON_AMBER_OFF; - } - } -} - -#define PIO_REG(h, r) ((h)->pio_address + offsetof(struct device_reg_2xxx, r)) - -void -qla2x00_beacon_blink(struct scsi_qla_host *vha) -{ - uint16_t gpio_enable; - uint16_t gpio_data; - uint16_t led_color = 0; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - if (IS_QLA82XX(ha)) - return; - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Save the Original GPIOE. */ - if (ha->pio_address) { - gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe)); - gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod)); - } else { - gpio_enable = RD_REG_WORD(®->gpioe); - gpio_data = RD_REG_WORD(®->gpiod); - } - - /* Set the modified gpio_enable values */ - gpio_enable |= GPIO_LED_MASK; - - if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable); - } else { - WRT_REG_WORD(®->gpioe, gpio_enable); - RD_REG_WORD(®->gpioe); - } - - qla2x00_flip_colors(ha, &led_color); - - /* Clear out any previously set LED color. */ - gpio_data &= ~GPIO_LED_MASK; - - /* Set the new input LED color to GPIOD. */ - gpio_data |= led_color; - - /* Set the modified gpio_data values */ - if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data); - } else { - WRT_REG_WORD(®->gpiod, gpio_data); - RD_REG_WORD(®->gpiod); - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -int -qla2x00_beacon_on(struct scsi_qla_host *vha) -{ - uint16_t gpio_enable; - uint16_t gpio_data; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; - ha->fw_options[1] |= FO1_DISABLE_GPIO6_7; - - if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x709b, - "Unable to update fw options (beacon on).\n"); - return QLA_FUNCTION_FAILED; - } - - /* Turn off LEDs. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - if (ha->pio_address) { - gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe)); - gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod)); - } else { - gpio_enable = RD_REG_WORD(®->gpioe); - gpio_data = RD_REG_WORD(®->gpiod); - } - gpio_enable |= GPIO_LED_MASK; - - /* Set the modified gpio_enable values. */ - if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable); - } else { - WRT_REG_WORD(®->gpioe, gpio_enable); - RD_REG_WORD(®->gpioe); - } - - /* Clear out previously set LED colour. */ - gpio_data &= ~GPIO_LED_MASK; - if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data); - } else { - WRT_REG_WORD(®->gpiod, gpio_data); - RD_REG_WORD(®->gpiod); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* - * Let the per HBA timer kick off the blinking process based on - * the following flags. No need to do anything else now. - */ - ha->beacon_blink_led = 1; - ha->beacon_color_state = 0; - - return QLA_SUCCESS; -} - -int -qla2x00_beacon_off(struct scsi_qla_host *vha) -{ - int rval = QLA_SUCCESS; - struct qla_hw_data *ha = vha->hw; - - ha->beacon_blink_led = 0; - - /* Set the on flag so when it gets flipped it will be off. */ - if (IS_QLA2322(ha)) - ha->beacon_color_state = QLA_LED_ALL_ON; - else - ha->beacon_color_state = QLA_LED_GRN_ON; - - ha->isp_ops->beacon_blink(vha); /* This turns green LED off */ - - ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING; - ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7; - - rval = qla2x00_set_fw_options(vha, ha->fw_options); - if (rval != QLA_SUCCESS) - ql_log(ql_log_warn, vha, 0x709c, - "Unable to update fw options (beacon off).\n"); - return rval; -} - - -static inline void -qla24xx_flip_colors(struct qla_hw_data *ha, uint16_t *pflags) -{ - /* Flip all colors. */ - if (ha->beacon_color_state == QLA_LED_ALL_ON) { - /* Turn off. */ - ha->beacon_color_state = 0; - *pflags = 0; - } else { - /* Turn on. */ - ha->beacon_color_state = QLA_LED_ALL_ON; - *pflags = GPDX_LED_YELLOW_ON | GPDX_LED_AMBER_ON; - } -} - -void -qla24xx_beacon_blink(struct scsi_qla_host *vha) -{ - uint16_t led_color = 0; - uint32_t gpio_data; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Save the Original GPIOD. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - gpio_data = RD_REG_DWORD(®->gpiod); - - /* Enable the gpio_data reg for update. */ - gpio_data |= GPDX_LED_UPDATE_MASK; - - WRT_REG_DWORD(®->gpiod, gpio_data); - gpio_data = RD_REG_DWORD(®->gpiod); - - /* Set the color bits. */ - qla24xx_flip_colors(ha, &led_color); - - /* Clear out any previously set LED color. */ - gpio_data &= ~GPDX_LED_COLOR_MASK; - - /* Set the new input LED color to GPIOD. */ - gpio_data |= led_color; - - /* Set the modified gpio_data values. */ - WRT_REG_DWORD(®->gpiod, gpio_data); - gpio_data = RD_REG_DWORD(®->gpiod); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void -qla83xx_beacon_blink(struct scsi_qla_host *vha) -{ - uint32_t led_select_value; - struct qla_hw_data *ha = vha->hw; - uint16_t led_cfg[6]; - uint16_t orig_led_cfg[6]; - - if (!IS_QLA83XX(ha) && !IS_QLA81XX(ha)) - return; - - if (IS_QLA2031(ha) && ha->beacon_blink_led) { - if (ha->flags.port0) - led_select_value = 0x00201320; - else - led_select_value = 0x00201328; - - qla83xx_write_remote_reg(vha, led_select_value, 0x40002000); - qla83xx_write_remote_reg(vha, led_select_value + 4, 0x40002000); - msleep(1000); - qla83xx_write_remote_reg(vha, led_select_value, 0x40004000); - qla83xx_write_remote_reg(vha, led_select_value + 4, 0x40004000); - } else if ((IS_QLA8031(ha) || IS_QLA81XX(ha)) && ha->beacon_blink_led) { - int rval; - - /* Save Current */ - rval = qla81xx_get_led_config(vha, orig_led_cfg); - /* Do the blink */ - if (rval == QLA_SUCCESS) { - if (IS_QLA81XX(ha)) { - led_cfg[0] = 0x4000; - led_cfg[1] = 0x2000; - led_cfg[2] = 0; - led_cfg[3] = 0; - led_cfg[4] = 0; - led_cfg[5] = 0; - } else { - led_cfg[0] = 0x4000; - led_cfg[1] = 0x4000; - led_cfg[2] = 0x4000; - led_cfg[3] = 0x2000; - led_cfg[4] = 0; - led_cfg[5] = 0x2000; - } - rval = qla81xx_set_led_config(vha, led_cfg); - msleep(1000); - if (IS_QLA81XX(ha)) { - led_cfg[0] = 0x4000; - led_cfg[1] = 0x2000; - led_cfg[2] = 0; - } else { - led_cfg[0] = 0x4000; - led_cfg[1] = 0x2000; - led_cfg[2] = 0x4000; - led_cfg[3] = 0x4000; - led_cfg[4] = 0; - led_cfg[5] = 0x2000; - } - rval = qla81xx_set_led_config(vha, led_cfg); - } - /* On exit, restore original (presumes no status change) */ - qla81xx_set_led_config(vha, orig_led_cfg); - } -} - -int -qla24xx_beacon_on(struct scsi_qla_host *vha) -{ - uint32_t gpio_data; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - if (IS_QLA82XX(ha)) - return QLA_SUCCESS; - - if (IS_QLA8031(ha) || IS_QLA81XX(ha)) - goto skip_gpio; /* let blink handle it */ - - if (ha->beacon_blink_led == 0) { - /* Enable firmware for update */ - ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL; - - if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) - return QLA_FUNCTION_FAILED; - - if (qla2x00_get_fw_options(vha, ha->fw_options) != - QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x7009, - "Unable to update fw options (beacon on).\n"); - return QLA_FUNCTION_FAILED; - } - - if (IS_QLA2031(ha)) - goto skip_gpio; - - spin_lock_irqsave(&ha->hardware_lock, flags); - gpio_data = RD_REG_DWORD(®->gpiod); - - /* Enable the gpio_data reg for update. */ - gpio_data |= GPDX_LED_UPDATE_MASK; - WRT_REG_DWORD(®->gpiod, gpio_data); - RD_REG_DWORD(®->gpiod); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - - /* So all colors blink together. */ - ha->beacon_color_state = 0; - -skip_gpio: - /* Let the per HBA timer kick off the blinking process. */ - ha->beacon_blink_led = 1; - - return QLA_SUCCESS; -} - -int -qla24xx_beacon_off(struct scsi_qla_host *vha) -{ - uint32_t gpio_data; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - if (IS_QLA82XX(ha)) - return QLA_SUCCESS; - - ha->beacon_blink_led = 0; - - if (IS_QLA2031(ha)) - goto set_fw_options; - - if (IS_QLA8031(ha) || IS_QLA81XX(ha)) - return QLA_SUCCESS; - - ha->beacon_color_state = QLA_LED_ALL_ON; - - ha->isp_ops->beacon_blink(vha); /* Will flip to all off. */ - - /* Give control back to firmware. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - gpio_data = RD_REG_DWORD(®->gpiod); - - /* Disable the gpio_data reg for update. */ - gpio_data &= ~GPDX_LED_UPDATE_MASK; - WRT_REG_DWORD(®->gpiod, gpio_data); - RD_REG_DWORD(®->gpiod); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - -set_fw_options: - ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL; - - if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x704d, - "Unable to update fw options (beacon on).\n"); - return QLA_FUNCTION_FAILED; - } - - if (qla2x00_get_fw_options(vha, ha->fw_options) != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x704e, - "Unable to update fw options (beacon on).\n"); - return QLA_FUNCTION_FAILED; - } - - return QLA_SUCCESS; -} - - -/* - * Flash support routines - */ - -/** - * qla2x00_flash_enable() - Setup flash for reading and writing. - * @ha: HA context - */ -static void -qla2x00_flash_enable(struct qla_hw_data *ha) -{ - uint16_t data; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - data = RD_REG_WORD(®->ctrl_status); - data |= CSR_FLASH_ENABLE; - WRT_REG_WORD(®->ctrl_status, data); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ -} - -/** - * qla2x00_flash_disable() - Disable flash and allow RISC to run. - * @ha: HA context - */ -static void -qla2x00_flash_disable(struct qla_hw_data *ha) -{ - uint16_t data; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - data = RD_REG_WORD(®->ctrl_status); - data &= ~(CSR_FLASH_ENABLE); - WRT_REG_WORD(®->ctrl_status, data); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ -} - -/** - * qla2x00_read_flash_byte() - Reads a byte from flash - * @ha: HA context - * @addr: Address in flash to read - * - * A word is read from the chip, but, only the lower byte is valid. - * - * Returns the byte read from flash @addr. - */ -static uint8_t -qla2x00_read_flash_byte(struct qla_hw_data *ha, uint32_t addr) -{ - uint16_t data; - uint16_t bank_select; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - bank_select = RD_REG_WORD(®->ctrl_status); - - if (IS_QLA2322(ha) || IS_QLA6322(ha)) { - /* Specify 64K address range: */ - /* clear out Module Select and Flash Address bits [19:16]. */ - bank_select &= ~0xf8; - bank_select |= addr >> 12 & 0xf0; - bank_select |= CSR_FLASH_64K_BANK; - WRT_REG_WORD(®->ctrl_status, bank_select); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - - WRT_REG_WORD(®->flash_address, (uint16_t)addr); - data = RD_REG_WORD(®->flash_data); - - return (uint8_t)data; - } - - /* Setup bit 16 of flash address. */ - if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) { - bank_select |= CSR_FLASH_64K_BANK; - WRT_REG_WORD(®->ctrl_status, bank_select); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - } else if (((addr & BIT_16) == 0) && - (bank_select & CSR_FLASH_64K_BANK)) { - bank_select &= ~(CSR_FLASH_64K_BANK); - WRT_REG_WORD(®->ctrl_status, bank_select); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - } - - /* Always perform IO mapped accesses to the FLASH registers. */ - if (ha->pio_address) { - uint16_t data2; - - WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr); - do { - data = RD_REG_WORD_PIO(PIO_REG(ha, flash_data)); - barrier(); - cpu_relax(); - data2 = RD_REG_WORD_PIO(PIO_REG(ha, flash_data)); - } while (data != data2); - } else { - WRT_REG_WORD(®->flash_address, (uint16_t)addr); - data = qla2x00_debounce_register(®->flash_data); - } - - return (uint8_t)data; -} - -/** - * qla2x00_write_flash_byte() - Write a byte to flash - * @ha: HA context - * @addr: Address in flash to write - * @data: Data to write - */ -static void -qla2x00_write_flash_byte(struct qla_hw_data *ha, uint32_t addr, uint8_t data) -{ - uint16_t bank_select; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - bank_select = RD_REG_WORD(®->ctrl_status); - if (IS_QLA2322(ha) || IS_QLA6322(ha)) { - /* Specify 64K address range: */ - /* clear out Module Select and Flash Address bits [19:16]. */ - bank_select &= ~0xf8; - bank_select |= addr >> 12 & 0xf0; - bank_select |= CSR_FLASH_64K_BANK; - WRT_REG_WORD(®->ctrl_status, bank_select); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - - WRT_REG_WORD(®->flash_address, (uint16_t)addr); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - WRT_REG_WORD(®->flash_data, (uint16_t)data); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - - return; - } - - /* Setup bit 16 of flash address. */ - if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) { - bank_select |= CSR_FLASH_64K_BANK; - WRT_REG_WORD(®->ctrl_status, bank_select); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - } else if (((addr & BIT_16) == 0) && - (bank_select & CSR_FLASH_64K_BANK)) { - bank_select &= ~(CSR_FLASH_64K_BANK); - WRT_REG_WORD(®->ctrl_status, bank_select); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - } - - /* Always perform IO mapped accesses to the FLASH registers. */ - if (ha->pio_address) { - WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr); - WRT_REG_WORD_PIO(PIO_REG(ha, flash_data), (uint16_t)data); - } else { - WRT_REG_WORD(®->flash_address, (uint16_t)addr); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - WRT_REG_WORD(®->flash_data, (uint16_t)data); - RD_REG_WORD(®->ctrl_status); /* PCI Posting. */ - } -} - -/** - * qla2x00_poll_flash() - Polls flash for completion. - * @ha: HA context - * @addr: Address in flash to poll - * @poll_data: Data to be polled - * @man_id: Flash manufacturer ID - * @flash_id: Flash ID - * - * This function polls the device until bit 7 of what is read matches data - * bit 7 or until data bit 5 becomes a 1. If that hapens, the flash ROM timed - * out (a fatal error). The flash book recommeds reading bit 7 again after - * reading bit 5 as a 1. - * - * Returns 0 on success, else non-zero. - */ -static int -qla2x00_poll_flash(struct qla_hw_data *ha, uint32_t addr, uint8_t poll_data, - uint8_t man_id, uint8_t flash_id) -{ - int status; - uint8_t flash_data; - uint32_t cnt; - - status = 1; - - /* Wait for 30 seconds for command to finish. */ - poll_data &= BIT_7; - for (cnt = 3000000; cnt; cnt--) { - flash_data = qla2x00_read_flash_byte(ha, addr); - if ((flash_data & BIT_7) == poll_data) { - status = 0; - break; - } - - if (man_id != 0x40 && man_id != 0xda) { - if ((flash_data & BIT_5) && cnt > 2) - cnt = 2; - } - udelay(10); - barrier(); - cond_resched(); - } - return status; -} - -/** - * qla2x00_program_flash_address() - Programs a flash address - * @ha: HA context - * @addr: Address in flash to program - * @data: Data to be written in flash - * @man_id: Flash manufacturer ID - * @flash_id: Flash ID - * - * Returns 0 on success, else non-zero. - */ -static int -qla2x00_program_flash_address(struct qla_hw_data *ha, uint32_t addr, - uint8_t data, uint8_t man_id, uint8_t flash_id) -{ - /* Write Program Command Sequence. */ - if (IS_OEM_001(ha)) { - qla2x00_write_flash_byte(ha, 0xaaa, 0xaa); - qla2x00_write_flash_byte(ha, 0x555, 0x55); - qla2x00_write_flash_byte(ha, 0xaaa, 0xa0); - qla2x00_write_flash_byte(ha, addr, data); - } else { - if (man_id == 0xda && flash_id == 0xc1) { - qla2x00_write_flash_byte(ha, addr, data); - if (addr & 0x7e) - return 0; - } else { - qla2x00_write_flash_byte(ha, 0x5555, 0xaa); - qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); - qla2x00_write_flash_byte(ha, 0x5555, 0xa0); - qla2x00_write_flash_byte(ha, addr, data); - } - } - - udelay(150); - - /* Wait for write to complete. */ - return qla2x00_poll_flash(ha, addr, data, man_id, flash_id); -} - -/** - * qla2x00_erase_flash() - Erase the flash. - * @ha: HA context - * @man_id: Flash manufacturer ID - * @flash_id: Flash ID - * - * Returns 0 on success, else non-zero. - */ -static int -qla2x00_erase_flash(struct qla_hw_data *ha, uint8_t man_id, uint8_t flash_id) -{ - /* Individual Sector Erase Command Sequence */ - if (IS_OEM_001(ha)) { - qla2x00_write_flash_byte(ha, 0xaaa, 0xaa); - qla2x00_write_flash_byte(ha, 0x555, 0x55); - qla2x00_write_flash_byte(ha, 0xaaa, 0x80); - qla2x00_write_flash_byte(ha, 0xaaa, 0xaa); - qla2x00_write_flash_byte(ha, 0x555, 0x55); - qla2x00_write_flash_byte(ha, 0xaaa, 0x10); - } else { - qla2x00_write_flash_byte(ha, 0x5555, 0xaa); - qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); - qla2x00_write_flash_byte(ha, 0x5555, 0x80); - qla2x00_write_flash_byte(ha, 0x5555, 0xaa); - qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); - qla2x00_write_flash_byte(ha, 0x5555, 0x10); - } - - udelay(150); - - /* Wait for erase to complete. */ - return qla2x00_poll_flash(ha, 0x00, 0x80, man_id, flash_id); -} - -/** - * qla2x00_erase_flash_sector() - Erase a flash sector. - * @ha: HA context - * @addr: Flash sector to erase - * @sec_mask: Sector address mask - * @man_id: Flash manufacturer ID - * @flash_id: Flash ID - * - * Returns 0 on success, else non-zero. - */ -static int -qla2x00_erase_flash_sector(struct qla_hw_data *ha, uint32_t addr, - uint32_t sec_mask, uint8_t man_id, uint8_t flash_id) -{ - /* Individual Sector Erase Command Sequence */ - qla2x00_write_flash_byte(ha, 0x5555, 0xaa); - qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); - qla2x00_write_flash_byte(ha, 0x5555, 0x80); - qla2x00_write_flash_byte(ha, 0x5555, 0xaa); - qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); - if (man_id == 0x1f && flash_id == 0x13) - qla2x00_write_flash_byte(ha, addr & sec_mask, 0x10); - else - qla2x00_write_flash_byte(ha, addr & sec_mask, 0x30); - - udelay(150); - - /* Wait for erase to complete. */ - return qla2x00_poll_flash(ha, addr, 0x80, man_id, flash_id); -} - -/** - * qla2x00_get_flash_manufacturer() - Read manufacturer ID from flash chip. - * @man_id: Flash manufacturer ID - * @flash_id: Flash ID - */ -static void -qla2x00_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id, - uint8_t *flash_id) -{ - qla2x00_write_flash_byte(ha, 0x5555, 0xaa); - qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); - qla2x00_write_flash_byte(ha, 0x5555, 0x90); - *man_id = qla2x00_read_flash_byte(ha, 0x0000); - *flash_id = qla2x00_read_flash_byte(ha, 0x0001); - qla2x00_write_flash_byte(ha, 0x5555, 0xaa); - qla2x00_write_flash_byte(ha, 0x2aaa, 0x55); - qla2x00_write_flash_byte(ha, 0x5555, 0xf0); -} - -static void -qla2x00_read_flash_data(struct qla_hw_data *ha, uint8_t *tmp_buf, - uint32_t saddr, uint32_t length) -{ - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - uint32_t midpoint, ilength; - uint8_t data; - - midpoint = length / 2; - - WRT_REG_WORD(®->nvram, 0); - RD_REG_WORD(®->nvram); - for (ilength = 0; ilength < length; saddr++, ilength++, tmp_buf++) { - if (ilength == midpoint) { - WRT_REG_WORD(®->nvram, NVR_SELECT); - RD_REG_WORD(®->nvram); - } - data = qla2x00_read_flash_byte(ha, saddr); - if (saddr % 100) - udelay(10); - *tmp_buf = data; - cond_resched(); - } -} - -static inline void -qla2x00_suspend_hba(struct scsi_qla_host *vha) -{ - int cnt; - unsigned long flags; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - /* Suspend HBA. */ - scsi_block_requests(vha->host); - ha->isp_ops->disable_intrs(ha); - set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); - - /* Pause RISC. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_WORD(®->hccr, HCCR_PAUSE_RISC); - RD_REG_WORD(®->hccr); - if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) { - for (cnt = 0; cnt < 30000; cnt++) { - if ((RD_REG_WORD(®->hccr) & HCCR_RISC_PAUSE) != 0) - break; - udelay(100); - } - } else { - udelay(10); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -static inline void -qla2x00_resume_hba(struct scsi_qla_host *vha) -{ - struct qla_hw_data *ha = vha->hw; - - /* Resume HBA. */ - clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - qla2x00_wait_for_chip_reset(vha); - scsi_unblock_requests(vha->host); -} - -uint8_t * -qla2x00_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, - uint32_t offset, uint32_t length) -{ - uint32_t addr, midpoint; - uint8_t *data; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - /* Suspend HBA. */ - qla2x00_suspend_hba(vha); - - /* Go with read. */ - midpoint = ha->optrom_size / 2; - - qla2x00_flash_enable(ha); - WRT_REG_WORD(®->nvram, 0); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - for (addr = offset, data = buf; addr < length; addr++, data++) { - if (addr == midpoint) { - WRT_REG_WORD(®->nvram, NVR_SELECT); - RD_REG_WORD(®->nvram); /* PCI Posting. */ - } - - *data = qla2x00_read_flash_byte(ha, addr); - } - qla2x00_flash_disable(ha); - - /* Resume HBA. */ - qla2x00_resume_hba(vha); - - return buf; -} - -int -qla2x00_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, - uint32_t offset, uint32_t length) -{ - - int rval; - uint8_t man_id, flash_id, sec_number, data; - uint16_t wd; - uint32_t addr, liter, sec_mask, rest_addr; - struct qla_hw_data *ha = vha->hw; - struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; - - /* Suspend HBA. */ - qla2x00_suspend_hba(vha); - - rval = QLA_SUCCESS; - sec_number = 0; - - /* Reset ISP chip. */ - WRT_REG_WORD(®->ctrl_status, CSR_ISP_SOFT_RESET); - pci_read_config_word(ha->pdev, PCI_COMMAND, &wd); - - /* Go with write. */ - qla2x00_flash_enable(ha); - do { /* Loop once to provide quick error exit */ - /* Structure of flash memory based on manufacturer */ - if (IS_OEM_001(ha)) { - /* OEM variant with special flash part. */ - man_id = flash_id = 0; - rest_addr = 0xffff; - sec_mask = 0x10000; - goto update_flash; - } - qla2x00_get_flash_manufacturer(ha, &man_id, &flash_id); - switch (man_id) { - case 0x20: /* ST flash. */ - if (flash_id == 0xd2 || flash_id == 0xe3) { - /* - * ST m29w008at part - 64kb sector size with - * 32kb,8kb,8kb,16kb sectors at memory address - * 0xf0000. - */ - rest_addr = 0xffff; - sec_mask = 0x10000; - break; - } - /* - * ST m29w010b part - 16kb sector size - * Default to 16kb sectors - */ - rest_addr = 0x3fff; - sec_mask = 0x1c000; - break; - case 0x40: /* Mostel flash. */ - /* Mostel v29c51001 part - 512 byte sector size. */ - rest_addr = 0x1ff; - sec_mask = 0x1fe00; - break; - case 0xbf: /* SST flash. */ - /* SST39sf10 part - 4kb sector size. */ - rest_addr = 0xfff; - sec_mask = 0x1f000; - break; - case 0xda: /* Winbond flash. */ - /* Winbond W29EE011 part - 256 byte sector size. */ - rest_addr = 0x7f; - sec_mask = 0x1ff80; - break; - case 0xc2: /* Macronix flash. */ - /* 64k sector size. */ - if (flash_id == 0x38 || flash_id == 0x4f) { - rest_addr = 0xffff; - sec_mask = 0x10000; - break; - } - /* Fall through... */ - - case 0x1f: /* Atmel flash. */ - /* 512k sector size. */ - if (flash_id == 0x13) { - rest_addr = 0x7fffffff; - sec_mask = 0x80000000; - break; - } - /* Fall through... */ - - case 0x01: /* AMD flash. */ - if (flash_id == 0x38 || flash_id == 0x40 || - flash_id == 0x4f) { - /* Am29LV081 part - 64kb sector size. */ - /* Am29LV002BT part - 64kb sector size. */ - rest_addr = 0xffff; - sec_mask = 0x10000; - break; - } else if (flash_id == 0x3e) { - /* - * Am29LV008b part - 64kb sector size with - * 32kb,8kb,8kb,16kb sector at memory address - * h0xf0000. - */ - rest_addr = 0xffff; - sec_mask = 0x10000; - break; - } else if (flash_id == 0x20 || flash_id == 0x6e) { - /* - * Am29LV010 part or AM29f010 - 16kb sector - * size. - */ - rest_addr = 0x3fff; - sec_mask = 0x1c000; - break; - } else if (flash_id == 0x6d) { - /* Am29LV001 part - 8kb sector size. */ - rest_addr = 0x1fff; - sec_mask = 0x1e000; - break; - } - default: - /* Default to 16 kb sector size. */ - rest_addr = 0x3fff; - sec_mask = 0x1c000; - break; - } - -update_flash: - if (IS_QLA2322(ha) || IS_QLA6322(ha)) { - if (qla2x00_erase_flash(ha, man_id, flash_id)) { - rval = QLA_FUNCTION_FAILED; - break; - } - } - - for (addr = offset, liter = 0; liter < length; liter++, - addr++) { - data = buf[liter]; - /* Are we at the beginning of a sector? */ - if ((addr & rest_addr) == 0) { - if (IS_QLA2322(ha) || IS_QLA6322(ha)) { - if (addr >= 0x10000UL) { - if (((addr >> 12) & 0xf0) && - ((man_id == 0x01 && - flash_id == 0x3e) || - (man_id == 0x20 && - flash_id == 0xd2))) { - sec_number++; - if (sec_number == 1) { - rest_addr = - 0x7fff; - sec_mask = - 0x18000; - } else if ( - sec_number == 2 || - sec_number == 3) { - rest_addr = - 0x1fff; - sec_mask = - 0x1e000; - } else if ( - sec_number == 4) { - rest_addr = - 0x3fff; - sec_mask = - 0x1c000; - } - } - } - } else if (addr == ha->optrom_size / 2) { - WRT_REG_WORD(®->nvram, NVR_SELECT); - RD_REG_WORD(®->nvram); - } - - if (flash_id == 0xda && man_id == 0xc1) { - qla2x00_write_flash_byte(ha, 0x5555, - 0xaa); - qla2x00_write_flash_byte(ha, 0x2aaa, - 0x55); - qla2x00_write_flash_byte(ha, 0x5555, - 0xa0); - } else if (!IS_QLA2322(ha) && !IS_QLA6322(ha)) { - /* Then erase it */ - if (qla2x00_erase_flash_sector(ha, - addr, sec_mask, man_id, - flash_id)) { - rval = QLA_FUNCTION_FAILED; - break; - } - if (man_id == 0x01 && flash_id == 0x6d) - sec_number++; - } - } - - if (man_id == 0x01 && flash_id == 0x6d) { - if (sec_number == 1 && - addr == (rest_addr - 1)) { - rest_addr = 0x0fff; - sec_mask = 0x1f000; - } else if (sec_number == 3 && (addr & 0x7ffe)) { - rest_addr = 0x3fff; - sec_mask = 0x1c000; - } - } - - if (qla2x00_program_flash_address(ha, addr, data, - man_id, flash_id)) { - rval = QLA_FUNCTION_FAILED; - break; - } - cond_resched(); - } - } while (0); - qla2x00_flash_disable(ha); - - /* Resume HBA. */ - qla2x00_resume_hba(vha); - - return rval; -} - -uint8_t * -qla24xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, - uint32_t offset, uint32_t length) -{ - struct qla_hw_data *ha = vha->hw; - - /* Suspend HBA. */ - scsi_block_requests(vha->host); - set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); - - /* Go with read. */ - qla24xx_read_flash_data(vha, (uint32_t *)buf, offset >> 2, length >> 2); - - /* Resume HBA. */ - clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); - scsi_unblock_requests(vha->host); - - return buf; -} - -int -qla24xx_write_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, - uint32_t offset, uint32_t length) -{ - int rval; - struct qla_hw_data *ha = vha->hw; - - /* Suspend HBA. */ - scsi_block_requests(vha->host); - set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); - - /* Go with write. */ - rval = qla24xx_write_flash_data(vha, (uint32_t *)buf, offset >> 2, - length >> 2); - - clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags); - scsi_unblock_requests(vha->host); - - return rval; -} - -uint8_t * -qla25xx_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, - uint32_t offset, uint32_t length) -{ - int rval; - dma_addr_t optrom_dma; - void *optrom; - uint8_t *pbuf; - uint32_t faddr, left, burst; - struct qla_hw_data *ha = vha->hw; - - if (IS_QLA25XX(ha) || IS_QLA81XX(ha)) - goto try_fast; - if (offset & 0xfff) - goto slow_read; - if (length < OPTROM_BURST_SIZE) - goto slow_read; - -try_fast: - optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, - &optrom_dma, GFP_KERNEL); - if (!optrom) { - ql_log(ql_log_warn, vha, 0x00cc, - "Unable to allocate memory for optrom burst read (%x KB).\n", - OPTROM_BURST_SIZE / 1024); - goto slow_read; - } - - pbuf = buf; - faddr = offset >> 2; - left = length >> 2; - burst = OPTROM_BURST_DWORDS; - while (left != 0) { - if (burst > left) - burst = left; - - rval = qla2x00_dump_ram(vha, optrom_dma, - flash_data_addr(ha, faddr), burst); - if (rval) { - ql_log(ql_log_warn, vha, 0x00f5, - "Unable to burst-read optrom segment (%x/%x/%llx).\n", - rval, flash_data_addr(ha, faddr), - (unsigned long long)optrom_dma); - ql_log(ql_log_warn, vha, 0x00f6, - "Reverting to slow-read.\n"); - - dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, - optrom, optrom_dma); - goto slow_read; - } - - memcpy(pbuf, optrom, burst * 4); - - left -= burst; - faddr += burst; - pbuf += burst * 4; - } - - dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom, - optrom_dma); - - return buf; - -slow_read: - return qla24xx_read_optrom_data(vha, buf, offset, length); -} - -/** - * qla2x00_get_fcode_version() - Determine an FCODE image's version. - * @ha: HA context - * @pcids: Pointer to the FCODE PCI data structure - * - * The process of retrieving the FCODE version information is at best - * described as interesting. - * - * Within the first 100h bytes of the image an ASCII string is present - * which contains several pieces of information including the FCODE - * version. Unfortunately it seems the only reliable way to retrieve - * the version is by scanning for another sentinel within the string, - * the FCODE build date: - * - * ... 2.00.02 10/17/02 ... - * - * Returns QLA_SUCCESS on successful retrieval of version. - */ -static void -qla2x00_get_fcode_version(struct qla_hw_data *ha, uint32_t pcids) -{ - int ret = QLA_FUNCTION_FAILED; - uint32_t istart, iend, iter, vend; - uint8_t do_next, rbyte, *vbyte; - - memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); - - /* Skip the PCI data structure. */ - istart = pcids + - ((qla2x00_read_flash_byte(ha, pcids + 0x0B) << 8) | - qla2x00_read_flash_byte(ha, pcids + 0x0A)); - iend = istart + 0x100; - do { - /* Scan for the sentinel date string...eeewww. */ - do_next = 0; - iter = istart; - while ((iter < iend) && !do_next) { - iter++; - if (qla2x00_read_flash_byte(ha, iter) == '/') { - if (qla2x00_read_flash_byte(ha, iter + 2) == - '/') - do_next++; - else if (qla2x00_read_flash_byte(ha, - iter + 3) == '/') - do_next++; - } - } - if (!do_next) - break; - - /* Backtrack to previous ' ' (space). */ - do_next = 0; - while ((iter > istart) && !do_next) { - iter--; - if (qla2x00_read_flash_byte(ha, iter) == ' ') - do_next++; - } - if (!do_next) - break; - - /* - * Mark end of version tag, and find previous ' ' (space) or - * string length (recent FCODE images -- major hack ahead!!!). - */ - vend = iter - 1; - do_next = 0; - while ((iter > istart) && !do_next) { - iter--; - rbyte = qla2x00_read_flash_byte(ha, iter); - if (rbyte == ' ' || rbyte == 0xd || rbyte == 0x10) - do_next++; - } - if (!do_next) - break; - - /* Mark beginning of version tag, and copy data. */ - iter++; - if ((vend - iter) && - ((vend - iter) < sizeof(ha->fcode_revision))) { - vbyte = ha->fcode_revision; - while (iter <= vend) { - *vbyte++ = qla2x00_read_flash_byte(ha, iter); - iter++; - } - ret = QLA_SUCCESS; - } - } while (0); - - if (ret != QLA_SUCCESS) - memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); -} - -int -qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf) -{ - int ret = QLA_SUCCESS; - uint8_t code_type, last_image; - uint32_t pcihdr, pcids; - uint8_t *dbyte; - uint16_t *dcode; - struct qla_hw_data *ha = vha->hw; - - if (!ha->pio_address || !mbuf) - return QLA_FUNCTION_FAILED; - - memset(ha->bios_revision, 0, sizeof(ha->bios_revision)); - memset(ha->efi_revision, 0, sizeof(ha->efi_revision)); - memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); - memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); - - qla2x00_flash_enable(ha); - - /* Begin with first PCI expansion ROM header. */ - pcihdr = 0; - last_image = 1; - do { - /* Verify PCI expansion ROM header. */ - if (qla2x00_read_flash_byte(ha, pcihdr) != 0x55 || - qla2x00_read_flash_byte(ha, pcihdr + 0x01) != 0xaa) { - /* No signature */ - ql_log(ql_log_fatal, vha, 0x0050, - "No matching ROM signature.\n"); - ret = QLA_FUNCTION_FAILED; - break; - } - - /* Locate PCI data structure. */ - pcids = pcihdr + - ((qla2x00_read_flash_byte(ha, pcihdr + 0x19) << 8) | - qla2x00_read_flash_byte(ha, pcihdr + 0x18)); - - /* Validate signature of PCI data structure. */ - if (qla2x00_read_flash_byte(ha, pcids) != 'P' || - qla2x00_read_flash_byte(ha, pcids + 0x1) != 'C' || - qla2x00_read_flash_byte(ha, pcids + 0x2) != 'I' || - qla2x00_read_flash_byte(ha, pcids + 0x3) != 'R') { - /* Incorrect header. */ - ql_log(ql_log_fatal, vha, 0x0051, - "PCI data struct not found pcir_adr=%x.\n", pcids); - ret = QLA_FUNCTION_FAILED; - break; - } - - /* Read version */ - code_type = qla2x00_read_flash_byte(ha, pcids + 0x14); - switch (code_type) { - case ROM_CODE_TYPE_BIOS: - /* Intel x86, PC-AT compatible. */ - ha->bios_revision[0] = - qla2x00_read_flash_byte(ha, pcids + 0x12); - ha->bios_revision[1] = - qla2x00_read_flash_byte(ha, pcids + 0x13); - ql_dbg(ql_dbg_init, vha, 0x0052, - "Read BIOS %d.%d.\n", - ha->bios_revision[1], ha->bios_revision[0]); - break; - case ROM_CODE_TYPE_FCODE: - /* Open Firmware standard for PCI (FCode). */ - /* Eeeewww... */ - qla2x00_get_fcode_version(ha, pcids); - break; - case ROM_CODE_TYPE_EFI: - /* Extensible Firmware Interface (EFI). */ - ha->efi_revision[0] = - qla2x00_read_flash_byte(ha, pcids + 0x12); - ha->efi_revision[1] = - qla2x00_read_flash_byte(ha, pcids + 0x13); - ql_dbg(ql_dbg_init, vha, 0x0053, - "Read EFI %d.%d.\n", - ha->efi_revision[1], ha->efi_revision[0]); - break; - default: - ql_log(ql_log_warn, vha, 0x0054, - "Unrecognized code type %x at pcids %x.\n", - code_type, pcids); - break; - } - - last_image = qla2x00_read_flash_byte(ha, pcids + 0x15) & BIT_7; - - /* Locate next PCI expansion ROM. */ - pcihdr += ((qla2x00_read_flash_byte(ha, pcids + 0x11) << 8) | - qla2x00_read_flash_byte(ha, pcids + 0x10)) * 512; - } while (!last_image); - - if (IS_QLA2322(ha)) { - /* Read firmware image information. */ - memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); - dbyte = mbuf; - memset(dbyte, 0, 8); - dcode = (uint16_t *)dbyte; - - qla2x00_read_flash_data(ha, dbyte, ha->flt_region_fw * 4 + 10, - 8); - ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010a, - "Dumping fw " - "ver from flash:.\n"); - ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010b, - (uint8_t *)dbyte, 8); - - if ((dcode[0] == 0xffff && dcode[1] == 0xffff && - dcode[2] == 0xffff && dcode[3] == 0xffff) || - (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && - dcode[3] == 0)) { - ql_log(ql_log_warn, vha, 0x0057, - "Unrecognized fw revision at %x.\n", - ha->flt_region_fw * 4); - } else { - /* values are in big endian */ - ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1]; - ha->fw_revision[1] = dbyte[2] << 16 | dbyte[3]; - ha->fw_revision[2] = dbyte[4] << 16 | dbyte[5]; - ql_dbg(ql_dbg_init, vha, 0x0058, - "FW Version: " - "%d.%d.%d.\n", ha->fw_revision[0], - ha->fw_revision[1], ha->fw_revision[2]); - } - } - - qla2x00_flash_disable(ha); - - return ret; -} - -int -qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf) -{ - int ret = QLA_SUCCESS; - uint32_t pcihdr, pcids; - uint32_t *dcode; - uint8_t *bcode; - uint8_t code_type, last_image; - int i; - struct qla_hw_data *ha = vha->hw; - - if (IS_QLA82XX(ha)) - return ret; - - if (!mbuf) - return QLA_FUNCTION_FAILED; - - memset(ha->bios_revision, 0, sizeof(ha->bios_revision)); - memset(ha->efi_revision, 0, sizeof(ha->efi_revision)); - memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision)); - memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); - - dcode = mbuf; - - /* Begin with first PCI expansion ROM header. */ - pcihdr = ha->flt_region_boot << 2; - last_image = 1; - do { - /* Verify PCI expansion ROM header. */ - qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20); - bcode = mbuf + (pcihdr % 4); - if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa) { - /* No signature */ - ql_log(ql_log_fatal, vha, 0x0059, - "No matching ROM signature.\n"); - ret = QLA_FUNCTION_FAILED; - break; - } - - /* Locate PCI data structure. */ - pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]); - - qla24xx_read_flash_data(vha, dcode, pcids >> 2, 0x20); - bcode = mbuf + (pcihdr % 4); - - /* Validate signature of PCI data structure. */ - if (bcode[0x0] != 'P' || bcode[0x1] != 'C' || - bcode[0x2] != 'I' || bcode[0x3] != 'R') { - /* Incorrect header. */ - ql_log(ql_log_fatal, vha, 0x005a, - "PCI data struct not found pcir_adr=%x.\n", pcids); - ret = QLA_FUNCTION_FAILED; - break; - } - - /* Read version */ - code_type = bcode[0x14]; - switch (code_type) { - case ROM_CODE_TYPE_BIOS: - /* Intel x86, PC-AT compatible. */ - ha->bios_revision[0] = bcode[0x12]; - ha->bios_revision[1] = bcode[0x13]; - ql_dbg(ql_dbg_init, vha, 0x005b, - "Read BIOS %d.%d.\n", - ha->bios_revision[1], ha->bios_revision[0]); - break; - case ROM_CODE_TYPE_FCODE: - /* Open Firmware standard for PCI (FCode). */ - ha->fcode_revision[0] = bcode[0x12]; - ha->fcode_revision[1] = bcode[0x13]; - ql_dbg(ql_dbg_init, vha, 0x005c, - "Read FCODE %d.%d.\n", - ha->fcode_revision[1], ha->fcode_revision[0]); - break; - case ROM_CODE_TYPE_EFI: - /* Extensible Firmware Interface (EFI). */ - ha->efi_revision[0] = bcode[0x12]; - ha->efi_revision[1] = bcode[0x13]; - ql_dbg(ql_dbg_init, vha, 0x005d, - "Read EFI %d.%d.\n", - ha->efi_revision[1], ha->efi_revision[0]); - break; - default: - ql_log(ql_log_warn, vha, 0x005e, - "Unrecognized code type %x at pcids %x.\n", - code_type, pcids); - break; - } - - last_image = bcode[0x15] & BIT_7; - - /* Locate next PCI expansion ROM. */ - pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512; - } while (!last_image); - - /* Read firmware image information. */ - memset(ha->fw_revision, 0, sizeof(ha->fw_revision)); - dcode = mbuf; - - qla24xx_read_flash_data(vha, dcode, ha->flt_region_fw + 4, 4); - for (i = 0; i < 4; i++) - dcode[i] = be32_to_cpu(dcode[i]); - - if ((dcode[0] == 0xffffffff && dcode[1] == 0xffffffff && - dcode[2] == 0xffffffff && dcode[3] == 0xffffffff) || - (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 && - dcode[3] == 0)) { - ql_log(ql_log_warn, vha, 0x005f, - "Unrecognized fw revision at %x.\n", - ha->flt_region_fw * 4); - } else { - ha->fw_revision[0] = dcode[0]; - ha->fw_revision[1] = dcode[1]; - ha->fw_revision[2] = dcode[2]; - ha->fw_revision[3] = dcode[3]; - ql_dbg(ql_dbg_init, vha, 0x0060, - "Firmware revision %d.%d.%d.%d.\n", - ha->fw_revision[0], ha->fw_revision[1], - ha->fw_revision[2], ha->fw_revision[3]); - } - - /* Check for golden firmware and get version if available */ - if (!IS_QLA81XX(ha)) { - /* Golden firmware is not present in non 81XX adapters */ - return ret; - } - - memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version)); - dcode = mbuf; - ha->isp_ops->read_optrom(vha, (uint8_t *)dcode, - ha->flt_region_gold_fw << 2, 32); - - if (dcode[4] == 0xFFFFFFFF && dcode[5] == 0xFFFFFFFF && - dcode[6] == 0xFFFFFFFF && dcode[7] == 0xFFFFFFFF) { - ql_log(ql_log_warn, vha, 0x0056, - "Unrecognized golden fw at 0x%x.\n", - ha->flt_region_gold_fw * 4); - return ret; - } - - for (i = 4; i < 8; i++) - ha->gold_fw_version[i-4] = be32_to_cpu(dcode[i]); - - return ret; -} - -static int -qla2xxx_is_vpd_valid(uint8_t *pos, uint8_t *end) -{ - if (pos >= end || *pos != 0x82) - return 0; - - pos += 3 + pos[1]; - if (pos >= end || *pos != 0x90) - return 0; - - pos += 3 + pos[1]; - if (pos >= end || *pos != 0x78) - return 0; - - return 1; -} - -int -qla2xxx_get_vpd_field(scsi_qla_host_t *vha, char *key, char *str, size_t size) -{ - struct qla_hw_data *ha = vha->hw; - uint8_t *pos = ha->vpd; - uint8_t *end = pos + ha->vpd_size; - int len = 0; - - if (!IS_FWI2_CAPABLE(ha) || !qla2xxx_is_vpd_valid(pos, end)) - return 0; - - while (pos < end && *pos != 0x78) { - len = (*pos == 0x82) ? pos[1] : pos[2]; - - if (!strncmp(pos, key, strlen(key))) - break; - - if (*pos != 0x90 && *pos != 0x91) - pos += len; - - pos += 3; - } - - if (pos < end - len && *pos != 0x78) - return snprintf(str, size, "%.*s", len, pos + 3); - - return 0; -} - -int -qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha) -{ - int len, max_len; - uint32_t fcp_prio_addr; - struct qla_hw_data *ha = vha->hw; - - if (!ha->fcp_prio_cfg) { - ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE); - if (!ha->fcp_prio_cfg) { - ql_log(ql_log_warn, vha, 0x00d5, - "Unable to allocate memory for fcp priorty data (%x).\n", - FCP_PRIO_CFG_SIZE); - return QLA_FUNCTION_FAILED; - } - } - memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE); - - fcp_prio_addr = ha->flt_region_fcp_prio; - - /* first read the fcp priority data header from flash */ - ha->isp_ops->read_optrom(vha, (uint8_t *)ha->fcp_prio_cfg, - fcp_prio_addr << 2, FCP_PRIO_CFG_HDR_SIZE); - - if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 0)) - goto fail; - - /* read remaining FCP CMD config data from flash */ - fcp_prio_addr += (FCP_PRIO_CFG_HDR_SIZE >> 2); - len = ha->fcp_prio_cfg->num_entries * FCP_PRIO_CFG_ENTRY_SIZE; - max_len = FCP_PRIO_CFG_SIZE - FCP_PRIO_CFG_HDR_SIZE; - - ha->isp_ops->read_optrom(vha, (uint8_t *)&ha->fcp_prio_cfg->entry[0], - fcp_prio_addr << 2, (len < max_len ? len : max_len)); - - /* revalidate the entire FCP priority config data, including entries */ - if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 1)) - goto fail; - - ha->flags.fcp_prio_enabled = 1; - return QLA_SUCCESS; -fail: - vfree(ha->fcp_prio_cfg); - ha->fcp_prio_cfg = NULL; - return QLA_FUNCTION_FAILED; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_version.h b/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_version.h deleted file mode 100644 index f5fdb16b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla2xxx/qla_version.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * QLogic Fibre Channel HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla2xxx for copyright and licensing details. - */ -/* - * Driver version - */ -#define QLA2XXX_VERSION "8.04.00.03-k" - -#define QLA_DRIVER_MAJOR_VER 8 -#define QLA_DRIVER_MINOR_VER 4 -#define QLA_DRIVER_PATCH_VER 0 -#define QLA_DRIVER_BETA_VER 3 diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/Kconfig b/ANDROID_3.4.5/drivers/scsi/qla4xxx/Kconfig deleted file mode 100644 index f1ad02ea..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config SCSI_QLA_ISCSI - tristate "QLogic ISP4XXX and ISP82XX host adapter family support" - depends on PCI && SCSI && NET - select SCSI_ISCSI_ATTRS - select ISCSI_BOOT_SYSFS - ---help--- - This driver supports the QLogic 40xx (ISP4XXX) and 8022 (ISP82XX) - iSCSI host adapter family. diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/Makefile b/ANDROID_3.4.5/drivers/scsi/qla4xxx/Makefile deleted file mode 100644 index 5b44139f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \ - ql4_nx.o ql4_nvram.o ql4_dbg.o ql4_attr.o ql4_bsg.o - -obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o - diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_attr.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_attr.c deleted file mode 100644 index 0b0a7d42..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_attr.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2011 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#include "ql4_def.h" -#include "ql4_glbl.h" -#include "ql4_dbg.h" - -/* Scsi_Host attributes. */ -static ssize_t -qla4xxx_fw_version_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - - if (is_qla8022(ha)) - return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n", - ha->firmware_version[0], - ha->firmware_version[1], - ha->patch_number, ha->build_number); - else - return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d.%02d\n", - ha->firmware_version[0], - ha->firmware_version[1], - ha->patch_number, ha->build_number); -} - -static ssize_t -qla4xxx_serial_num_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - return snprintf(buf, PAGE_SIZE, "%s\n", ha->serial_number); -} - -static ssize_t -qla4xxx_iscsi_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->iscsi_major, - ha->iscsi_minor); -} - -static ssize_t -qla4xxx_optrom_version_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d.%02d\n", - ha->bootload_major, ha->bootload_minor, - ha->bootload_patch, ha->bootload_build); -} - -static ssize_t -qla4xxx_board_id_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - return snprintf(buf, PAGE_SIZE, "0x%08X\n", ha->board_id); -} - -static ssize_t -qla4xxx_fw_state_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - - qla4xxx_get_firmware_state(ha); - return snprintf(buf, PAGE_SIZE, "0x%08X%8X\n", ha->firmware_state, - ha->addl_fw_state); -} - -static ssize_t -qla4xxx_phy_port_cnt_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - - if (!is_qla8022(ha)) - return -ENOSYS; - - return snprintf(buf, PAGE_SIZE, "0x%04X\n", ha->phy_port_cnt); -} - -static ssize_t -qla4xxx_phy_port_num_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - - if (!is_qla8022(ha)) - return -ENOSYS; - - return snprintf(buf, PAGE_SIZE, "0x%04X\n", ha->phy_port_num); -} - -static ssize_t -qla4xxx_iscsi_func_cnt_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - - if (!is_qla8022(ha)) - return -ENOSYS; - - return snprintf(buf, PAGE_SIZE, "0x%04X\n", ha->iscsi_pci_func_cnt); -} - -static ssize_t -qla4xxx_hba_model_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(class_to_shost(dev)); - - return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_name); -} - -static DEVICE_ATTR(fw_version, S_IRUGO, qla4xxx_fw_version_show, NULL); -static DEVICE_ATTR(serial_num, S_IRUGO, qla4xxx_serial_num_show, NULL); -static DEVICE_ATTR(iscsi_version, S_IRUGO, qla4xxx_iscsi_version_show, NULL); -static DEVICE_ATTR(optrom_version, S_IRUGO, qla4xxx_optrom_version_show, NULL); -static DEVICE_ATTR(board_id, S_IRUGO, qla4xxx_board_id_show, NULL); -static DEVICE_ATTR(fw_state, S_IRUGO, qla4xxx_fw_state_show, NULL); -static DEVICE_ATTR(phy_port_cnt, S_IRUGO, qla4xxx_phy_port_cnt_show, NULL); -static DEVICE_ATTR(phy_port_num, S_IRUGO, qla4xxx_phy_port_num_show, NULL); -static DEVICE_ATTR(iscsi_func_cnt, S_IRUGO, qla4xxx_iscsi_func_cnt_show, NULL); -static DEVICE_ATTR(hba_model, S_IRUGO, qla4xxx_hba_model_show, NULL); - -struct device_attribute *qla4xxx_host_attrs[] = { - &dev_attr_fw_version, - &dev_attr_serial_num, - &dev_attr_iscsi_version, - &dev_attr_optrom_version, - &dev_attr_board_id, - &dev_attr_fw_state, - &dev_attr_phy_port_cnt, - &dev_attr_phy_port_num, - &dev_attr_iscsi_func_cnt, - &dev_attr_hba_model, - NULL, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.c deleted file mode 100644 index 8acdc582..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.c +++ /dev/null @@ -1,513 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2011 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#include "ql4_def.h" -#include "ql4_glbl.h" -#include "ql4_bsg.h" - -static int -qla4xxx_read_flash(struct bsg_job *bsg_job) -{ - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; - struct iscsi_bsg_request *bsg_req = bsg_job->request; - uint32_t offset = 0; - uint32_t length = 0; - dma_addr_t flash_dma; - uint8_t *flash = NULL; - int rval = -EINVAL; - - bsg_reply->reply_payload_rcv_len = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - goto leave; - - if (ql4xxx_reset_active(ha)) { - ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); - rval = -EBUSY; - goto leave; - } - - if (ha->flash_state != QLFLASH_WAITING) { - ql4_printk(KERN_ERR, ha, "%s: another flash operation " - "active\n", __func__); - rval = -EBUSY; - goto leave; - } - - ha->flash_state = QLFLASH_READING; - offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; - length = bsg_job->reply_payload.payload_len; - - flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma, - GFP_KERNEL); - if (!flash) { - ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " - "data\n", __func__); - rval = -ENOMEM; - goto leave; - } - - rval = qla4xxx_get_flash(ha, flash_dma, offset, length); - if (rval) { - ql4_printk(KERN_ERR, ha, "%s: get flash failed\n", __func__); - bsg_reply->result = DID_ERROR << 16; - rval = -EIO; - } else { - bsg_reply->reply_payload_rcv_len = - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, - flash, length); - bsg_reply->result = DID_OK << 16; - } - - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); - dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma); -leave: - ha->flash_state = QLFLASH_WAITING; - return rval; -} - -static int -qla4xxx_update_flash(struct bsg_job *bsg_job) -{ - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; - struct iscsi_bsg_request *bsg_req = bsg_job->request; - uint32_t length = 0; - uint32_t offset = 0; - uint32_t options = 0; - dma_addr_t flash_dma; - uint8_t *flash = NULL; - int rval = -EINVAL; - - bsg_reply->reply_payload_rcv_len = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - goto leave; - - if (ql4xxx_reset_active(ha)) { - ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); - rval = -EBUSY; - goto leave; - } - - if (ha->flash_state != QLFLASH_WAITING) { - ql4_printk(KERN_ERR, ha, "%s: another flash operation " - "active\n", __func__); - rval = -EBUSY; - goto leave; - } - - ha->flash_state = QLFLASH_WRITING; - length = bsg_job->request_payload.payload_len; - offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; - options = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; - - flash = dma_alloc_coherent(&ha->pdev->dev, length, &flash_dma, - GFP_KERNEL); - if (!flash) { - ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " - "data\n", __func__); - rval = -ENOMEM; - goto leave; - } - - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, flash, length); - - rval = qla4xxx_set_flash(ha, flash_dma, offset, length, options); - if (rval) { - ql4_printk(KERN_ERR, ha, "%s: set flash failed\n", __func__); - bsg_reply->result = DID_ERROR << 16; - rval = -EIO; - } else - bsg_reply->result = DID_OK << 16; - - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); - dma_free_coherent(&ha->pdev->dev, length, flash, flash_dma); -leave: - ha->flash_state = QLFLASH_WAITING; - return rval; -} - -static int -qla4xxx_get_acb_state(struct bsg_job *bsg_job) -{ - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - struct iscsi_bsg_request *bsg_req = bsg_job->request; - struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; - uint32_t status[MBOX_REG_COUNT]; - uint32_t acb_idx; - uint32_t ip_idx; - int rval = -EINVAL; - - bsg_reply->reply_payload_rcv_len = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - goto leave; - - /* Only 4022 and above adapters are supported */ - if (is_qla4010(ha)) - goto leave; - - if (ql4xxx_reset_active(ha)) { - ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); - rval = -EBUSY; - goto leave; - } - - if (bsg_job->reply_payload.payload_len < sizeof(status)) { - ql4_printk(KERN_ERR, ha, "%s: invalid payload len %d\n", - __func__, bsg_job->reply_payload.payload_len); - rval = -EINVAL; - goto leave; - } - - acb_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; - ip_idx = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; - - rval = qla4xxx_get_ip_state(ha, acb_idx, ip_idx, status); - if (rval) { - ql4_printk(KERN_ERR, ha, "%s: get ip state failed\n", - __func__); - bsg_reply->result = DID_ERROR << 16; - rval = -EIO; - } else { - bsg_reply->reply_payload_rcv_len = - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, - status, sizeof(status)); - bsg_reply->result = DID_OK << 16; - } - - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); -leave: - return rval; -} - -static int -qla4xxx_read_nvram(struct bsg_job *bsg_job) -{ - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - struct iscsi_bsg_request *bsg_req = bsg_job->request; - struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; - uint32_t offset = 0; - uint32_t len = 0; - uint32_t total_len = 0; - dma_addr_t nvram_dma; - uint8_t *nvram = NULL; - int rval = -EINVAL; - - bsg_reply->reply_payload_rcv_len = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - goto leave; - - /* Only 40xx adapters are supported */ - if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) - goto leave; - - if (ql4xxx_reset_active(ha)) { - ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); - rval = -EBUSY; - goto leave; - } - - offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; - len = bsg_job->reply_payload.payload_len; - total_len = offset + len; - - /* total len should not be greater than max NVRAM size */ - if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || - ((is_qla4022(ha) || is_qla4032(ha)) && - total_len > QL40X2_NVRAM_SIZE)) { - ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" - " nvram size, offset=%d len=%d\n", - __func__, offset, len); - goto leave; - } - - nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, - GFP_KERNEL); - if (!nvram) { - ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for nvram " - "data\n", __func__); - rval = -ENOMEM; - goto leave; - } - - rval = qla4xxx_get_nvram(ha, nvram_dma, offset, len); - if (rval) { - ql4_printk(KERN_ERR, ha, "%s: get nvram failed\n", __func__); - bsg_reply->result = DID_ERROR << 16; - rval = -EIO; - } else { - bsg_reply->reply_payload_rcv_len = - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, - nvram, len); - bsg_reply->result = DID_OK << 16; - } - - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); - dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); -leave: - return rval; -} - -static int -qla4xxx_update_nvram(struct bsg_job *bsg_job) -{ - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - struct iscsi_bsg_request *bsg_req = bsg_job->request; - struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; - uint32_t offset = 0; - uint32_t len = 0; - uint32_t total_len = 0; - dma_addr_t nvram_dma; - uint8_t *nvram = NULL; - int rval = -EINVAL; - - bsg_reply->reply_payload_rcv_len = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - goto leave; - - if (!(is_qla4010(ha) || is_qla4022(ha) || is_qla4032(ha))) - goto leave; - - if (ql4xxx_reset_active(ha)) { - ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); - rval = -EBUSY; - goto leave; - } - - offset = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; - len = bsg_job->request_payload.payload_len; - total_len = offset + len; - - /* total len should not be greater than max NVRAM size */ - if ((is_qla4010(ha) && total_len > QL4010_NVRAM_SIZE) || - ((is_qla4022(ha) || is_qla4032(ha)) && - total_len > QL40X2_NVRAM_SIZE)) { - ql4_printk(KERN_ERR, ha, "%s: offset+len greater than max" - " nvram size, offset=%d len=%d\n", - __func__, offset, len); - goto leave; - } - - nvram = dma_alloc_coherent(&ha->pdev->dev, len, &nvram_dma, - GFP_KERNEL); - if (!nvram) { - ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for flash " - "data\n", __func__); - rval = -ENOMEM; - goto leave; - } - - sg_copy_to_buffer(bsg_job->request_payload.sg_list, - bsg_job->request_payload.sg_cnt, nvram, len); - - rval = qla4xxx_set_nvram(ha, nvram_dma, offset, len); - if (rval) { - ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__); - bsg_reply->result = DID_ERROR << 16; - rval = -EIO; - } else - bsg_reply->result = DID_OK << 16; - - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); - dma_free_coherent(&ha->pdev->dev, len, nvram, nvram_dma); -leave: - return rval; -} - -static int -qla4xxx_restore_defaults(struct bsg_job *bsg_job) -{ - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - struct iscsi_bsg_request *bsg_req = bsg_job->request; - struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; - uint32_t region = 0; - uint32_t field0 = 0; - uint32_t field1 = 0; - int rval = -EINVAL; - - bsg_reply->reply_payload_rcv_len = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - goto leave; - - if (is_qla4010(ha)) - goto leave; - - if (ql4xxx_reset_active(ha)) { - ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); - rval = -EBUSY; - goto leave; - } - - region = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; - field0 = bsg_req->rqst_data.h_vendor.vendor_cmd[2]; - field1 = bsg_req->rqst_data.h_vendor.vendor_cmd[3]; - - rval = qla4xxx_restore_factory_defaults(ha, region, field0, field1); - if (rval) { - ql4_printk(KERN_ERR, ha, "%s: set nvram failed\n", __func__); - bsg_reply->result = DID_ERROR << 16; - rval = -EIO; - } else - bsg_reply->result = DID_OK << 16; - - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); -leave: - return rval; -} - -static int -qla4xxx_bsg_get_acb(struct bsg_job *bsg_job) -{ - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - struct iscsi_bsg_request *bsg_req = bsg_job->request; - struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; - uint32_t acb_type = 0; - uint32_t len = 0; - dma_addr_t acb_dma; - uint8_t *acb = NULL; - int rval = -EINVAL; - - bsg_reply->reply_payload_rcv_len = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - goto leave; - - /* Only 4022 and above adapters are supported */ - if (is_qla4010(ha)) - goto leave; - - if (ql4xxx_reset_active(ha)) { - ql4_printk(KERN_ERR, ha, "%s: reset active\n", __func__); - rval = -EBUSY; - goto leave; - } - - acb_type = bsg_req->rqst_data.h_vendor.vendor_cmd[1]; - len = bsg_job->reply_payload.payload_len; - if (len < sizeof(struct addr_ctrl_blk)) { - ql4_printk(KERN_ERR, ha, "%s: invalid acb len %d\n", - __func__, len); - rval = -EINVAL; - goto leave; - } - - acb = dma_alloc_coherent(&ha->pdev->dev, len, &acb_dma, GFP_KERNEL); - if (!acb) { - ql4_printk(KERN_ERR, ha, "%s: dma alloc failed for acb " - "data\n", __func__); - rval = -ENOMEM; - goto leave; - } - - rval = qla4xxx_get_acb(ha, acb_dma, acb_type, len); - if (rval) { - ql4_printk(KERN_ERR, ha, "%s: get acb failed\n", __func__); - bsg_reply->result = DID_ERROR << 16; - rval = -EIO; - } else { - bsg_reply->reply_payload_rcv_len = - sg_copy_from_buffer(bsg_job->reply_payload.sg_list, - bsg_job->reply_payload.sg_cnt, - acb, len); - bsg_reply->result = DID_OK << 16; - } - - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); - dma_free_coherent(&ha->pdev->dev, len, acb, acb_dma); -leave: - return rval; -} - -/** - * qla4xxx_process_vendor_specific - handle vendor specific bsg request - * @job: iscsi_bsg_job to handle - **/ -int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job) -{ - struct iscsi_bsg_reply *bsg_reply = bsg_job->reply; - struct iscsi_bsg_request *bsg_req = bsg_job->request; - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - - switch (bsg_req->rqst_data.h_vendor.vendor_cmd[0]) { - case QLISCSI_VND_READ_FLASH: - return qla4xxx_read_flash(bsg_job); - - case QLISCSI_VND_UPDATE_FLASH: - return qla4xxx_update_flash(bsg_job); - - case QLISCSI_VND_GET_ACB_STATE: - return qla4xxx_get_acb_state(bsg_job); - - case QLISCSI_VND_READ_NVRAM: - return qla4xxx_read_nvram(bsg_job); - - case QLISCSI_VND_UPDATE_NVRAM: - return qla4xxx_update_nvram(bsg_job); - - case QLISCSI_VND_RESTORE_DEFAULTS: - return qla4xxx_restore_defaults(bsg_job); - - case QLISCSI_VND_GET_ACB: - return qla4xxx_bsg_get_acb(bsg_job); - - default: - ql4_printk(KERN_ERR, ha, "%s: invalid BSG vendor command: " - "0x%x\n", __func__, bsg_req->msgcode); - bsg_reply->result = (DID_ERROR << 16); - bsg_reply->reply_payload_rcv_len = 0; - bsg_job_done(bsg_job, bsg_reply->result, - bsg_reply->reply_payload_rcv_len); - return -ENOSYS; - } -} - -/** - * qla4xxx_bsg_request - handle bsg request from ISCSI transport - * @job: iscsi_bsg_job to handle - */ -int qla4xxx_bsg_request(struct bsg_job *bsg_job) -{ - struct iscsi_bsg_request *bsg_req = bsg_job->request; - struct Scsi_Host *host = iscsi_job_to_shost(bsg_job); - struct scsi_qla_host *ha = to_qla_host(host); - - switch (bsg_req->msgcode) { - case ISCSI_BSG_HST_VENDOR: - return qla4xxx_process_vendor_specific(bsg_job); - - default: - ql4_printk(KERN_ERR, ha, "%s: invalid BSG command: 0x%x\n", - __func__, bsg_req->msgcode); - } - - return -ENOSYS; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.h deleted file mode 100644 index c6a03645..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_bsg.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2011 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ -#ifndef __QL4_BSG_H -#define __QL4_BSG_H - -/* BSG Vendor specific commands */ -#define QLISCSI_VND_READ_FLASH 1 -#define QLISCSI_VND_UPDATE_FLASH 2 -#define QLISCSI_VND_GET_ACB_STATE 3 -#define QLISCSI_VND_READ_NVRAM 4 -#define QLISCSI_VND_UPDATE_NVRAM 5 -#define QLISCSI_VND_RESTORE_DEFAULTS 6 -#define QLISCSI_VND_GET_ACB 7 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.c deleted file mode 100644 index 8d58ae27..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#include "ql4_def.h" -#include "ql4_glbl.h" -#include "ql4_dbg.h" -#include "ql4_inline.h" - -void qla4xxx_dump_buffer(void *b, uint32_t size) -{ - uint32_t cnt; - uint8_t *c = b; - - printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh " - "Fh\n"); - printk("------------------------------------------------------------" - "--\n"); - for (cnt = 0; cnt < size; c++) { - printk("%02x", *c); - if (!(++cnt % 16)) - printk("\n"); - - else - printk(" "); - } - printk(KERN_INFO "\n"); -} - -void qla4xxx_dump_registers(struct scsi_qla_host *ha) -{ - uint8_t i; - - if (is_qla8022(ha)) { - for (i = 1; i < MBOX_REG_COUNT; i++) - printk(KERN_INFO "mailbox[%d] = 0x%08X\n", - i, readl(&ha->qla4_8xxx_reg->mailbox_in[i])); - return; - } - - for (i = 0; i < MBOX_REG_COUNT; i++) { - printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, mailbox[i]), i, - readw(&ha->reg->mailbox[i])); - } - - printk(KERN_INFO "0x%02X flash_address = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, flash_address), - readw(&ha->reg->flash_address)); - printk(KERN_INFO "0x%02X flash_data = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, flash_data), - readw(&ha->reg->flash_data)); - printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, ctrl_status), - readw(&ha->reg->ctrl_status)); - - if (is_qla4010(ha)) { - printk(KERN_INFO "0x%02X nvram = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram), - readw(&ha->reg->u1.isp4010.nvram)); - } else if (is_qla4022(ha) | is_qla4032(ha)) { - printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u1.isp4022.intr_mask), - readw(&ha->reg->u1.isp4022.intr_mask)); - printk(KERN_INFO "0x%02X nvram = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram), - readw(&ha->reg->u1.isp4022.nvram)); - printk(KERN_INFO "0x%02X semaphore = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u1.isp4022.semaphore), - readw(&ha->reg->u1.isp4022.semaphore)); - } - printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, req_q_in), - readw(&ha->reg->req_q_in)); - printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, rsp_q_out), - readw(&ha->reg->rsp_q_out)); - - if (is_qla4010(ha)) { - printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4010.ext_hw_conf), - readw(&ha->reg->u2.isp4010.ext_hw_conf)); - printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4010.port_ctrl), - readw(&ha->reg->u2.isp4010.port_ctrl)); - printk(KERN_INFO "0x%02X port_status = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4010.port_status), - readw(&ha->reg->u2.isp4010.port_status)); - printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4010.req_q_out), - readw(&ha->reg->u2.isp4010.req_q_out)); - printk(KERN_INFO "0x%02X gp_out = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out), - readw(&ha->reg->u2.isp4010.gp_out)); - printk(KERN_INFO "0x%02X gp_in = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in), - readw(&ha->reg->u2.isp4010.gp_in)); - printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", (uint8_t) - offsetof(struct isp_reg, u2.isp4010.port_err_status), - readw(&ha->reg->u2.isp4010.port_err_status)); - } else if (is_qla4022(ha) | is_qla4032(ha)) { - printk(KERN_INFO "Page 0 Registers:\n"); - printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n", (uint8_t) - offsetof(struct isp_reg, u2.isp4022.p0.ext_hw_conf), - readw(&ha->reg->u2.isp4022.p0.ext_hw_conf)); - printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n", (uint8_t) - offsetof(struct isp_reg, u2.isp4022.p0.port_ctrl), - readw(&ha->reg->u2.isp4022.p0.port_ctrl)); - printk(KERN_INFO "0x%02X port_status = 0x%08X\n", (uint8_t) - offsetof(struct isp_reg, u2.isp4022.p0.port_status), - readw(&ha->reg->u2.isp4022.p0.port_status)); - printk(KERN_INFO "0x%02X gp_out = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_out), - readw(&ha->reg->u2.isp4022.p0.gp_out)); - printk(KERN_INFO "0x%02X gp_in = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in), - readw(&ha->reg->u2.isp4022.p0.gp_in)); - printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n", (uint8_t) - offsetof(struct isp_reg, u2.isp4022.p0.port_err_status), - readw(&ha->reg->u2.isp4022.p0.port_err_status)); - printk(KERN_INFO "Page 1 Registers:\n"); - writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT), - &ha->reg->ctrl_status); - printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n", - (uint8_t) offsetof(struct isp_reg, u2.isp4022.p1.req_q_out), - readw(&ha->reg->u2.isp4022.p1.req_q_out)); - writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT), - &ha->reg->ctrl_status); - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.h deleted file mode 100644 index abd83602..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_dbg.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -/* - * Driver debug definitions. - */ -/* #define QL_DEBUG */ /* DEBUG messages */ -/* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */ -/* #define QL_DEBUG_LEVEL_4 */ -/* #define QL_DEBUG_LEVEL_5 */ -/* #define QL_DEBUG_LEVEL_9 */ - -#define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */ -#if defined(QL_DEBUG) -#define DEBUG(x) do {x;} while (0); -#else -#define DEBUG(x) do {} while (0); -#endif - -#if defined(QL_DEBUG_LEVEL_2) -#define DEBUG2(x) do {if(ql4xextended_error_logging == 2) x;} while (0); -#define DEBUG2_3(x) do {x;} while (0); -#else /* */ -#define DEBUG2(x) do {} while (0); -#endif /* */ - -#if defined(QL_DEBUG_LEVEL_3) -#define DEBUG3(x) do {if(ql4xextended_error_logging == 3) x;} while (0); -#else /* */ -#define DEBUG3(x) do {} while (0); -#if !defined(QL_DEBUG_LEVEL_2) -#define DEBUG2_3(x) do {} while (0); -#endif /* */ -#endif /* */ -#if defined(QL_DEBUG_LEVEL_4) -#define DEBUG4(x) do {x;} while (0); -#else /* */ -#define DEBUG4(x) do {} while (0); -#endif /* */ - -#if defined(QL_DEBUG_LEVEL_5) -#define DEBUG5(x) do {x;} while (0); -#else /* */ -#define DEBUG5(x) do {} while (0); -#endif /* */ - -#if defined(QL_DEBUG_LEVEL_9) -#define DEBUG9(x) do {x;} while (0); -#else /* */ -#define DEBUG9(x) do {} while (0); -#endif /* */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_def.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_def.h deleted file mode 100644 index 7f2492e8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_def.h +++ /dev/null @@ -1,939 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#ifndef __QL4_DEF_H -#define __QL4_DEF_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ql4_dbg.h" -#include "ql4_nx.h" -#include "ql4_fw.h" -#include "ql4_nvram.h" - -#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010 -#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010 -#endif - -#ifndef PCI_DEVICE_ID_QLOGIC_ISP4022 -#define PCI_DEVICE_ID_QLOGIC_ISP4022 0x4022 -#endif - -#ifndef PCI_DEVICE_ID_QLOGIC_ISP4032 -#define PCI_DEVICE_ID_QLOGIC_ISP4032 0x4032 -#endif - -#ifndef PCI_DEVICE_ID_QLOGIC_ISP8022 -#define PCI_DEVICE_ID_QLOGIC_ISP8022 0x8022 -#endif - -#define ISP4XXX_PCI_FN_1 0x1 -#define ISP4XXX_PCI_FN_2 0x3 - -#define QLA_SUCCESS 0 -#define QLA_ERROR 1 - -/* - * Data bit definitions - */ -#define BIT_0 0x1 -#define BIT_1 0x2 -#define BIT_2 0x4 -#define BIT_3 0x8 -#define BIT_4 0x10 -#define BIT_5 0x20 -#define BIT_6 0x40 -#define BIT_7 0x80 -#define BIT_8 0x100 -#define BIT_9 0x200 -#define BIT_10 0x400 -#define BIT_11 0x800 -#define BIT_12 0x1000 -#define BIT_13 0x2000 -#define BIT_14 0x4000 -#define BIT_15 0x8000 -#define BIT_16 0x10000 -#define BIT_17 0x20000 -#define BIT_18 0x40000 -#define BIT_19 0x80000 -#define BIT_20 0x100000 -#define BIT_21 0x200000 -#define BIT_22 0x400000 -#define BIT_23 0x800000 -#define BIT_24 0x1000000 -#define BIT_25 0x2000000 -#define BIT_26 0x4000000 -#define BIT_27 0x8000000 -#define BIT_28 0x10000000 -#define BIT_29 0x20000000 -#define BIT_30 0x40000000 -#define BIT_31 0x80000000 - -/** - * Macros to help code, maintain, etc. - **/ -#define ql4_printk(level, ha, format, arg...) \ - dev_printk(level , &((ha)->pdev->dev) , format , ## arg) - - -/* - * Host adapter default definitions - ***********************************/ -#define MAX_HBAS 16 -#define MAX_BUSES 1 -#define MAX_TARGETS MAX_DEV_DB_ENTRIES -#define MAX_LUNS 0xffff -#define MAX_AEN_ENTRIES MAX_DEV_DB_ENTRIES -#define MAX_DDB_ENTRIES MAX_DEV_DB_ENTRIES -#define MAX_PDU_ENTRIES 32 -#define INVALID_ENTRY 0xFFFF -#define MAX_CMDS_TO_RISC 1024 -#define MAX_SRBS MAX_CMDS_TO_RISC -#define MBOX_AEN_REG_COUNT 8 -#define MAX_INIT_RETRIES 5 - -/* - * Buffer sizes - */ -#define REQUEST_QUEUE_DEPTH MAX_CMDS_TO_RISC -#define RESPONSE_QUEUE_DEPTH 64 -#define QUEUE_SIZE 64 -#define DMA_BUFFER_SIZE 512 - -/* - * Misc - */ -#define MAC_ADDR_LEN 6 /* in bytes */ -#define IP_ADDR_LEN 4 /* in bytes */ -#define IPv6_ADDR_LEN 16 /* IPv6 address size */ -#define DRIVER_NAME "qla4xxx" - -#define MAX_LINKED_CMDS_PER_LUN 3 -#define MAX_REQS_SERVICED_PER_INTR 1 - -#define ISCSI_IPADDR_SIZE 4 /* IP address size */ -#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alias name size */ -#define ISCSI_NAME_SIZE 0xE0 /* ISCSI Name size */ - -#define QL4_SESS_RECOVERY_TMO 120 /* iSCSI session */ - /* recovery timeout */ - -#define LSDW(x) ((u32)((u64)(x))) -#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16)) - -/* - * Retry & Timeout Values - */ -#define MBOX_TOV 60 -#define SOFT_RESET_TOV 30 -#define RESET_INTR_TOV 3 -#define SEMAPHORE_TOV 10 -#define ADAPTER_INIT_TOV 30 -#define ADAPTER_RESET_TOV 180 -#define EXTEND_CMD_TOV 60 -#define WAIT_CMD_TOV 30 -#define EH_WAIT_CMD_TOV 120 -#define FIRMWARE_UP_TOV 60 -#define RESET_FIRMWARE_TOV 30 -#define LOGOUT_TOV 10 -#define IOCB_TOV_MARGIN 10 -#define RELOGIN_TOV 18 -#define ISNS_DEREG_TOV 5 -#define HBA_ONLINE_TOV 30 -#define DISABLE_ACB_TOV 30 -#define IP_CONFIG_TOV 30 -#define LOGIN_TOV 12 - -#define MAX_RESET_HA_RETRIES 2 -#define FW_ALIVE_WAIT_TOV 3 - -#define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) - -/* - * SCSI Request Block structure (srb) that is placed - * on cmd->SCp location of every I/O [We have 22 bytes available] - */ -struct srb { - struct list_head list; /* (8) */ - struct scsi_qla_host *ha; /* HA the SP is queued on */ - struct ddb_entry *ddb; - uint16_t flags; /* (1) Status flags. */ - -#define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */ -#define SRB_GOT_SENSE BIT_4 /* sense data received. */ - uint8_t state; /* (1) Status flags. */ - -#define SRB_NO_QUEUE_STATE 0 /* Request is in between states */ -#define SRB_FREE_STATE 1 -#define SRB_ACTIVE_STATE 3 -#define SRB_ACTIVE_TIMEOUT_STATE 4 -#define SRB_SUSPENDED_STATE 7 /* Request in suspended state */ - - struct scsi_cmnd *cmd; /* (4) SCSI command block */ - dma_addr_t dma_handle; /* (4) for unmap of single transfers */ - struct kref srb_ref; /* reference count for this srb */ - uint8_t err_id; /* error id */ -#define SRB_ERR_PORT 1 /* Request failed because "port down" */ -#define SRB_ERR_LOOP 2 /* Request failed because "loop down" */ -#define SRB_ERR_DEVICE 3 /* Request failed because "device error" */ -#define SRB_ERR_OTHER 4 - - uint16_t reserved; - uint16_t iocb_tov; - uint16_t iocb_cnt; /* Number of used iocbs */ - uint16_t cc_stat; - - /* Used for extended sense / status continuation */ - uint8_t *req_sense_ptr; - uint16_t req_sense_len; - uint16_t reserved2; -}; - -/* Mailbox request block structure */ -struct mrb { - struct scsi_qla_host *ha; - struct mbox_cmd_iocb *mbox; - uint32_t mbox_cmd; - uint16_t iocb_cnt; /* Number of used iocbs */ - uint32_t pid; -}; - -/* - * Asynchronous Event Queue structure - */ -struct aen { - uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; -}; - -struct ql4_aen_log { - int count; - struct aen entry[MAX_AEN_ENTRIES]; -}; - -/* - * Device Database (DDB) structure - */ -struct ddb_entry { - struct scsi_qla_host *ha; - struct iscsi_cls_session *sess; - struct iscsi_cls_conn *conn; - - uint16_t fw_ddb_index; /* DDB firmware index */ - uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */ - uint16_t ddb_type; -#define FLASH_DDB 0x01 - - struct dev_db_entry fw_ddb_entry; - int (*unblock_sess)(struct iscsi_cls_session *cls_session); - int (*ddb_change)(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - struct ddb_entry *ddb_entry, uint32_t state); - - /* Driver Re-login */ - unsigned long flags; /* DDB Flags */ - uint16_t default_relogin_timeout; /* Max time to wait for - * relogin to complete */ - atomic_t retry_relogin_timer; /* Min Time between relogins - * (4000 only) */ - atomic_t relogin_timer; /* Max Time to wait for - * relogin to complete */ - atomic_t relogin_retry_count; /* Num of times relogin has been - * retried */ - uint32_t default_time2wait; /* Default Min time between - * relogins (+aens) */ - uint16_t chap_tbl_idx; -}; - -struct qla_ddb_index { - struct list_head list; - uint16_t fw_ddb_idx; - struct dev_db_entry fw_ddb; -}; - -#define DDB_IPADDR_LEN 64 - -struct ql4_tuple_ddb { - int port; - int tpgt; - char ip_addr[DDB_IPADDR_LEN]; - char iscsi_name[ISCSI_NAME_SIZE]; - uint16_t options; -#define DDB_OPT_IPV6 0x0e0e -#define DDB_OPT_IPV4 0x0f0f - uint8_t isid[6]; -}; - -/* - * DDB states. - */ -#define DDB_STATE_DEAD 0 /* We can no longer talk to - * this device */ -#define DDB_STATE_ONLINE 1 /* Device ready to accept - * commands */ -#define DDB_STATE_MISSING 2 /* Device logged off, trying - * to re-login */ - -/* - * DDB flags. - */ -#define DF_RELOGIN 0 /* Relogin to device */ -#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */ -#define DF_FO_MASKED 3 - -enum qla4_work_type { - QLA4_EVENT_AEN, - QLA4_EVENT_PING_STATUS, -}; - -struct qla4_work_evt { - struct list_head list; - enum qla4_work_type type; - union { - struct { - enum iscsi_host_event_code code; - uint32_t data_size; - uint8_t data[0]; - } aen; - struct { - uint32_t status; - uint32_t pid; - uint32_t data_size; - uint8_t data[0]; - } ping; - } u; -}; - -struct ql82xx_hw_data { - /* Offsets for flash/nvram access (set to ~0 if not used). */ - uint32_t flash_conf_off; - uint32_t flash_data_off; - - uint32_t fdt_wrt_disable; - uint32_t fdt_erase_cmd; - uint32_t fdt_block_size; - uint32_t fdt_unprotect_sec_cmd; - uint32_t fdt_protect_sec_cmd; - - uint32_t flt_region_flt; - uint32_t flt_region_fdt; - uint32_t flt_region_boot; - uint32_t flt_region_bootload; - uint32_t flt_region_fw; - - uint32_t flt_iscsi_param; - uint32_t flt_region_chap; - uint32_t flt_chap_size; -}; - -struct qla4_8xxx_legacy_intr_set { - uint32_t int_vec_bit; - uint32_t tgt_status_reg; - uint32_t tgt_mask_reg; - uint32_t pci_int_reg; -}; - -/* MSI-X Support */ - -#define QLA_MSIX_DEFAULT 0x00 -#define QLA_MSIX_RSP_Q 0x01 - -#define QLA_MSIX_ENTRIES 2 -#define QLA_MIDX_DEFAULT 0 -#define QLA_MIDX_RSP_Q 1 - -struct ql4_msix_entry { - int have_irq; - uint16_t msix_vector; - uint16_t msix_entry; -}; - -/* - * ISP Operations - */ -struct isp_operations { - int (*iospace_config) (struct scsi_qla_host *ha); - void (*pci_config) (struct scsi_qla_host *); - void (*disable_intrs) (struct scsi_qla_host *); - void (*enable_intrs) (struct scsi_qla_host *); - int (*start_firmware) (struct scsi_qla_host *); - irqreturn_t (*intr_handler) (int , void *); - void (*interrupt_service_routine) (struct scsi_qla_host *, uint32_t); - int (*reset_chip) (struct scsi_qla_host *); - int (*reset_firmware) (struct scsi_qla_host *); - void (*queue_iocb) (struct scsi_qla_host *); - void (*complete_iocb) (struct scsi_qla_host *); - uint16_t (*rd_shdw_req_q_out) (struct scsi_qla_host *); - uint16_t (*rd_shdw_rsp_q_in) (struct scsi_qla_host *); - int (*get_sys_info) (struct scsi_qla_host *); -}; - -/*qla4xxx ipaddress configuration details */ -struct ipaddress_config { - uint16_t ipv4_options; - uint16_t tcp_options; - uint16_t ipv4_vlan_tag; - uint8_t ipv4_addr_state; - uint8_t ip_address[IP_ADDR_LEN]; - uint8_t subnet_mask[IP_ADDR_LEN]; - uint8_t gateway[IP_ADDR_LEN]; - uint32_t ipv6_options; - uint32_t ipv6_addl_options; - uint8_t ipv6_link_local_state; - uint8_t ipv6_addr0_state; - uint8_t ipv6_addr1_state; - uint8_t ipv6_default_router_state; - uint16_t ipv6_vlan_tag; - struct in6_addr ipv6_link_local_addr; - struct in6_addr ipv6_addr0; - struct in6_addr ipv6_addr1; - struct in6_addr ipv6_default_router_addr; - uint16_t eth_mtu_size; - uint16_t ipv4_port; - uint16_t ipv6_port; -}; - -#define QL4_CHAP_MAX_NAME_LEN 256 -#define QL4_CHAP_MAX_SECRET_LEN 100 -#define LOCAL_CHAP 0 -#define BIDI_CHAP 1 - -struct ql4_chap_format { - u8 intr_chap_name[QL4_CHAP_MAX_NAME_LEN]; - u8 intr_secret[QL4_CHAP_MAX_SECRET_LEN]; - u8 target_chap_name[QL4_CHAP_MAX_NAME_LEN]; - u8 target_secret[QL4_CHAP_MAX_SECRET_LEN]; - u16 intr_chap_name_length; - u16 intr_secret_length; - u16 target_chap_name_length; - u16 target_secret_length; -}; - -struct ip_address_format { - u8 ip_type; - u8 ip_address[16]; -}; - -struct ql4_conn_info { - u16 dest_port; - struct ip_address_format dest_ipaddr; - struct ql4_chap_format chap; -}; - -struct ql4_boot_session_info { - u8 target_name[224]; - struct ql4_conn_info conn_list[1]; -}; - -struct ql4_boot_tgt_info { - struct ql4_boot_session_info boot_pri_sess; - struct ql4_boot_session_info boot_sec_sess; -}; - -/* - * Linux Host Adapter structure - */ -struct scsi_qla_host { - /* Linux adapter configuration data */ - unsigned long flags; - -#define AF_ONLINE 0 /* 0x00000001 */ -#define AF_INIT_DONE 1 /* 0x00000002 */ -#define AF_MBOX_COMMAND 2 /* 0x00000004 */ -#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */ -#define AF_INTERRUPTS_ON 6 /* 0x00000040 */ -#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */ -#define AF_LINK_UP 8 /* 0x00000100 */ -#define AF_IRQ_ATTACHED 10 /* 0x00000400 */ -#define AF_DISABLE_ACB_COMPLETE 11 /* 0x00000800 */ -#define AF_HA_REMOVAL 12 /* 0x00001000 */ -#define AF_INTx_ENABLED 15 /* 0x00008000 */ -#define AF_MSI_ENABLED 16 /* 0x00010000 */ -#define AF_MSIX_ENABLED 17 /* 0x00020000 */ -#define AF_MBOX_COMMAND_NOPOLL 18 /* 0x00040000 */ -#define AF_FW_RECOVERY 19 /* 0x00080000 */ -#define AF_EEH_BUSY 20 /* 0x00100000 */ -#define AF_PCI_CHANNEL_IO_PERM_FAILURE 21 /* 0x00200000 */ -#define AF_BUILD_DDB_LIST 22 /* 0x00400000 */ - unsigned long dpc_flags; - -#define DPC_RESET_HA 1 /* 0x00000002 */ -#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */ -#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */ -#define DPC_RESET_HA_FW_CONTEXT 4 /* 0x00000010 */ -#define DPC_RESET_HA_INTR 5 /* 0x00000020 */ -#define DPC_ISNS_RESTART 7 /* 0x00000080 */ -#define DPC_AEN 9 /* 0x00000200 */ -#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */ -#define DPC_LINK_CHANGED 18 /* 0x00040000 */ -#define DPC_RESET_ACTIVE 20 /* 0x00040000 */ -#define DPC_HA_UNRECOVERABLE 21 /* 0x00080000 ISP-82xx only*/ -#define DPC_HA_NEED_QUIESCENT 22 /* 0x00100000 ISP-82xx only*/ - - - struct Scsi_Host *host; /* pointer to host data */ - uint32_t tot_ddbs; - - uint16_t iocb_cnt; - - /* SRB cache. */ -#define SRB_MIN_REQ 128 - mempool_t *srb_mempool; - - /* pci information */ - struct pci_dev *pdev; - - struct isp_reg __iomem *reg; /* Base I/O address */ - unsigned long pio_address; - unsigned long pio_length; -#define MIN_IOBASE_LEN 0x100 - - uint16_t req_q_count; - - unsigned long host_no; - - /* NVRAM registers */ - struct eeprom_data *nvram; - spinlock_t hardware_lock ____cacheline_aligned; - uint32_t eeprom_cmd_data; - - /* Counters for general statistics */ - uint64_t isr_count; - uint64_t adapter_error_count; - uint64_t device_error_count; - uint64_t total_io_count; - uint64_t total_mbytes_xferred; - uint64_t link_failure_count; - uint64_t invalid_crc_count; - uint32_t bytes_xfered; - uint32_t spurious_int_count; - uint32_t aborted_io_count; - uint32_t io_timeout_count; - uint32_t mailbox_timeout_count; - uint32_t seconds_since_last_intr; - uint32_t seconds_since_last_heartbeat; - uint32_t mac_index; - - /* Info Needed for Management App */ - /* --- From GetFwVersion --- */ - uint32_t firmware_version[2]; - uint32_t patch_number; - uint32_t build_number; - uint32_t board_id; - - /* --- From Init_FW --- */ - /* init_cb_t *init_cb; */ - uint16_t firmware_options; - uint8_t alias[32]; - uint8_t name_string[256]; - uint8_t heartbeat_interval; - - /* --- From FlashSysInfo --- */ - uint8_t my_mac[MAC_ADDR_LEN]; - uint8_t serial_number[16]; - uint16_t port_num; - /* --- From GetFwState --- */ - uint32_t firmware_state; - uint32_t addl_fw_state; - - /* Linux kernel thread */ - struct workqueue_struct *dpc_thread; - struct work_struct dpc_work; - - /* Linux timer thread */ - struct timer_list timer; - uint32_t timer_active; - - /* Recovery Timers */ - atomic_t check_relogin_timeouts; - uint32_t retry_reset_ha_cnt; - uint32_t isp_reset_timer; /* reset test timer */ - uint32_t nic_reset_timer; /* simulated nic reset test timer */ - int eh_start; - struct list_head free_srb_q; - uint16_t free_srb_q_count; - uint16_t num_srbs_allocated; - - /* DMA Memory Block */ - void *queues; - dma_addr_t queues_dma; - unsigned long queues_len; - -#define MEM_ALIGN_VALUE \ - ((max(REQUEST_QUEUE_DEPTH, RESPONSE_QUEUE_DEPTH)) * \ - sizeof(struct queue_entry)) - /* request and response queue variables */ - dma_addr_t request_dma; - struct queue_entry *request_ring; - struct queue_entry *request_ptr; - dma_addr_t response_dma; - struct queue_entry *response_ring; - struct queue_entry *response_ptr; - dma_addr_t shadow_regs_dma; - struct shadow_regs *shadow_regs; - uint16_t request_in; /* Current indexes. */ - uint16_t request_out; - uint16_t response_in; - uint16_t response_out; - - /* aen queue variables */ - uint16_t aen_q_count; /* Number of available aen_q entries */ - uint16_t aen_in; /* Current indexes */ - uint16_t aen_out; - struct aen aen_q[MAX_AEN_ENTRIES]; - - struct ql4_aen_log aen_log;/* tracks all aens */ - - /* This mutex protects several threads to do mailbox commands - * concurrently. - */ - struct mutex mbox_sem; - - /* temporary mailbox status registers */ - volatile uint8_t mbox_status_count; - volatile uint32_t mbox_status[MBOX_REG_COUNT]; - - /* FW ddb index map */ - struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES]; - - /* Saved srb for status continuation entry processing */ - struct srb *status_srb; - - uint8_t acb_version; - - /* qla82xx specific fields */ - struct device_reg_82xx __iomem *qla4_8xxx_reg; /* Base I/O address */ - unsigned long nx_pcibase; /* Base I/O address */ - uint8_t *nx_db_rd_ptr; /* Doorbell read pointer */ - unsigned long nx_db_wr_ptr; /* Door bell write pointer */ - unsigned long first_page_group_start; - unsigned long first_page_group_end; - - uint32_t crb_win; - uint32_t curr_window; - uint32_t ddr_mn_window; - unsigned long mn_win_crb; - unsigned long ms_win_crb; - int qdr_sn_window; - rwlock_t hw_lock; - uint16_t func_num; - int link_width; - - struct qla4_8xxx_legacy_intr_set nx_legacy_intr; - u32 nx_crb_mask; - - uint8_t revision_id; - uint32_t fw_heartbeat_counter; - - struct isp_operations *isp_ops; - struct ql82xx_hw_data hw; - - struct ql4_msix_entry msix_entries[QLA_MSIX_ENTRIES]; - - uint32_t nx_dev_init_timeout; - uint32_t nx_reset_timeout; - - struct completion mbx_intr_comp; - - struct ipaddress_config ip_config; - struct iscsi_iface *iface_ipv4; - struct iscsi_iface *iface_ipv6_0; - struct iscsi_iface *iface_ipv6_1; - - /* --- From About Firmware --- */ - uint16_t iscsi_major; - uint16_t iscsi_minor; - uint16_t bootload_major; - uint16_t bootload_minor; - uint16_t bootload_patch; - uint16_t bootload_build; - uint16_t def_timeout; /* Default login timeout */ - - uint32_t flash_state; -#define QLFLASH_WAITING 0 -#define QLFLASH_READING 1 -#define QLFLASH_WRITING 2 - struct dma_pool *chap_dma_pool; - uint8_t *chap_list; /* CHAP table cache */ - struct mutex chap_sem; - -#define CHAP_DMA_BLOCK_SIZE 512 - struct workqueue_struct *task_wq; - unsigned long ddb_idx_map[MAX_DDB_ENTRIES / BITS_PER_LONG]; -#define SYSFS_FLAG_FW_SEL_BOOT 2 - struct iscsi_boot_kset *boot_kset; - struct ql4_boot_tgt_info boot_tgt; - uint16_t phy_port_num; - uint16_t phy_port_cnt; - uint16_t iscsi_pci_func_cnt; - uint8_t model_name[16]; - struct completion disable_acb_comp; - struct dma_pool *fw_ddb_dma_pool; -#define DDB_DMA_BLOCK_SIZE 512 - uint16_t pri_ddb_idx; - uint16_t sec_ddb_idx; - int is_reset; - uint16_t temperature; - - /* event work list */ - struct list_head work_list; - spinlock_t work_lock; - - /* mbox iocb */ -#define MAX_MRB 128 - struct mrb *active_mrb_array[MAX_MRB]; - uint32_t mrb_index; -}; - -struct ql4_task_data { - struct scsi_qla_host *ha; - uint8_t iocb_req_cnt; - dma_addr_t data_dma; - void *req_buffer; - dma_addr_t req_dma; - uint32_t req_len; - void *resp_buffer; - dma_addr_t resp_dma; - uint32_t resp_len; - struct iscsi_task *task; - struct passthru_status sts; - struct work_struct task_work; -}; - -struct qla_endpoint { - struct Scsi_Host *host; - struct sockaddr dst_addr; -}; - -struct qla_conn { - struct qla_endpoint *qla_ep; -}; - -static inline int is_ipv4_enabled(struct scsi_qla_host *ha) -{ - return ((ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE) != 0); -} - -static inline int is_ipv6_enabled(struct scsi_qla_host *ha) -{ - return ((ha->ip_config.ipv6_options & - IPV6_OPT_IPV6_PROTOCOL_ENABLE) != 0); -} - -static inline int is_qla4010(struct scsi_qla_host *ha) -{ - return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010; -} - -static inline int is_qla4022(struct scsi_qla_host *ha) -{ - return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022; -} - -static inline int is_qla4032(struct scsi_qla_host *ha) -{ - return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4032; -} - -static inline int is_qla40XX(struct scsi_qla_host *ha) -{ - return is_qla4032(ha) || is_qla4022(ha) || is_qla4010(ha); -} - -static inline int is_qla8022(struct scsi_qla_host *ha) -{ - return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; -} - -/* Note: Currently AER/EEH is now supported only for 8022 cards - * This function needs to be updated when AER/EEH is enabled - * for other cards. - */ -static inline int is_aer_supported(struct scsi_qla_host *ha) -{ - return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8022; -} - -static inline int adapter_up(struct scsi_qla_host *ha) -{ - return (test_bit(AF_ONLINE, &ha->flags) != 0) && - (test_bit(AF_LINK_UP, &ha->flags) != 0); -} - -static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost) -{ - return (struct scsi_qla_host *)iscsi_host_priv(shost); -} - -static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha) -{ - return (is_qla4010(ha) ? - &ha->reg->u1.isp4010.nvram : - &ha->reg->u1.isp4022.semaphore); -} - -static inline void __iomem* isp_nvram(struct scsi_qla_host *ha) -{ - return (is_qla4010(ha) ? - &ha->reg->u1.isp4010.nvram : - &ha->reg->u1.isp4022.nvram); -} - -static inline void __iomem* isp_ext_hw_conf(struct scsi_qla_host *ha) -{ - return (is_qla4010(ha) ? - &ha->reg->u2.isp4010.ext_hw_conf : - &ha->reg->u2.isp4022.p0.ext_hw_conf); -} - -static inline void __iomem* isp_port_status(struct scsi_qla_host *ha) -{ - return (is_qla4010(ha) ? - &ha->reg->u2.isp4010.port_status : - &ha->reg->u2.isp4022.p0.port_status); -} - -static inline void __iomem* isp_port_ctrl(struct scsi_qla_host *ha) -{ - return (is_qla4010(ha) ? - &ha->reg->u2.isp4010.port_ctrl : - &ha->reg->u2.isp4022.p0.port_ctrl); -} - -static inline void __iomem* isp_port_error_status(struct scsi_qla_host *ha) -{ - return (is_qla4010(ha) ? - &ha->reg->u2.isp4010.port_err_status : - &ha->reg->u2.isp4022.p0.port_err_status); -} - -static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha) -{ - return (is_qla4010(ha) ? - &ha->reg->u2.isp4010.gp_out : - &ha->reg->u2.isp4022.p0.gp_out); -} - -static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha) -{ - return (is_qla4010(ha) ? - offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2 : - offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2); -} - -int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits); -void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask); -int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits); - -static inline int ql4xxx_lock_flash(struct scsi_qla_host *a) -{ - if (is_qla4010(a)) - return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK, - QL4010_FLASH_SEM_BITS); - else - return ql4xxx_sem_spinlock(a, QL4022_FLASH_SEM_MASK, - (QL4022_RESOURCE_BITS_BASE_CODE | - (a->mac_index)) << 13); -} - -static inline void ql4xxx_unlock_flash(struct scsi_qla_host *a) -{ - if (is_qla4010(a)) - ql4xxx_sem_unlock(a, QL4010_FLASH_SEM_MASK); - else - ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK); -} - -static inline int ql4xxx_lock_nvram(struct scsi_qla_host *a) -{ - if (is_qla4010(a)) - return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK, - QL4010_NVRAM_SEM_BITS); - else - return ql4xxx_sem_spinlock(a, QL4022_NVRAM_SEM_MASK, - (QL4022_RESOURCE_BITS_BASE_CODE | - (a->mac_index)) << 10); -} - -static inline void ql4xxx_unlock_nvram(struct scsi_qla_host *a) -{ - if (is_qla4010(a)) - ql4xxx_sem_unlock(a, QL4010_NVRAM_SEM_MASK); - else - ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK); -} - -static inline int ql4xxx_lock_drvr(struct scsi_qla_host *a) -{ - if (is_qla4010(a)) - return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK, - QL4010_DRVR_SEM_BITS); - else - return ql4xxx_sem_lock(a, QL4022_DRVR_SEM_MASK, - (QL4022_RESOURCE_BITS_BASE_CODE | - (a->mac_index)) << 1); -} - -static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a) -{ - if (is_qla4010(a)) - ql4xxx_sem_unlock(a, QL4010_DRVR_SEM_MASK); - else - ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK); -} - -static inline int ql4xxx_reset_active(struct scsi_qla_host *ha) -{ - return test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || - test_bit(DPC_RESET_HA, &ha->dpc_flags) || - test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || - test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || - test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || - test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); - -} -/*---------------------------------------------------------------------------*/ - -/* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */ - -#define INIT_ADAPTER 0 -#define RESET_ADAPTER 1 - -#define PRESERVE_DDB_LIST 0 -#define REBUILD_DDB_LIST 1 - -/* Defines for process_aen() */ -#define PROCESS_ALL_AENS 0 -#define FLUSH_DDB_CHANGED_AENS 1 - -#endif /*_QLA4XXX_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_fw.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_fw.h deleted file mode 100644 index 210cd1d6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_fw.h +++ /dev/null @@ -1,1193 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#ifndef _QLA4X_FW_H -#define _QLA4X_FW_H - - -#define MAX_PRST_DEV_DB_ENTRIES 64 -#define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES -#define MAX_DEV_DB_ENTRIES 512 -#define MAX_DEV_DB_ENTRIES_40XX 256 - -/************************************************************************* - * - * ISP 4010 I/O Register Set Structure and Definitions - * - *************************************************************************/ - -struct port_ctrl_stat_regs { - __le32 ext_hw_conf; /* 0x50 R/W */ - __le32 rsrvd0; /* 0x54 */ - __le32 port_ctrl; /* 0x58 */ - __le32 port_status; /* 0x5c */ - __le32 rsrvd1[32]; /* 0x60-0xdf */ - __le32 gp_out; /* 0xe0 */ - __le32 gp_in; /* 0xe4 */ - __le32 rsrvd2[5]; /* 0xe8-0xfb */ - __le32 port_err_status; /* 0xfc */ -}; - -struct host_mem_cfg_regs { - __le32 rsrvd0[12]; /* 0x50-0x79 */ - __le32 req_q_out; /* 0x80 */ - __le32 rsrvd1[31]; /* 0x84-0xFF */ -}; - -/* - * ISP 82xx I/O Register Set structure definitions. - */ -struct device_reg_82xx { - __le32 req_q_out; /* 0x0000 (R): Request Queue out-Pointer. */ - __le32 reserve1[63]; /* Request Queue out-Pointer. (64 * 4) */ - __le32 rsp_q_in; /* 0x0100 (R/W): Response Queue In-Pointer. */ - __le32 reserve2[63]; /* Response Queue In-Pointer. */ - __le32 rsp_q_out; /* 0x0200 (R/W): Response Queue Out-Pointer. */ - __le32 reserve3[63]; /* Response Queue Out-Pointer. */ - - __le32 mailbox_in[8]; /* 0x0300 (R/W): Mail box In registers */ - __le32 reserve4[24]; - __le32 hint; /* 0x0380 (R/W): Host interrupt register */ -#define HINT_MBX_INT_PENDING BIT_0 - __le32 reserve5[31]; - __le32 mailbox_out[8]; /* 0x0400 (R): Mail box Out registers */ - __le32 reserve6[56]; - - __le32 host_status; /* Offset 0x500 (R): host status */ -#define HSRX_RISC_MB_INT BIT_0 /* RISC to Host Mailbox interrupt */ -#define HSRX_RISC_IOCB_INT BIT_1 /* RISC to Host IOCB interrupt */ - - __le32 host_int; /* Offset 0x0504 (R/W): Interrupt status. */ -#define ISRX_82XX_RISC_INT BIT_0 /* RISC interrupt. */ -}; - -/* remote register set (access via PCI memory read/write) */ -struct isp_reg { -#define MBOX_REG_COUNT 8 - __le32 mailbox[MBOX_REG_COUNT]; - - __le32 flash_address; /* 0x20 */ - __le32 flash_data; - __le32 ctrl_status; - - union { - struct { - __le32 nvram; - __le32 reserved1[2]; /* 0x30 */ - } __attribute__ ((packed)) isp4010; - struct { - __le32 intr_mask; - __le32 nvram; /* 0x30 */ - __le32 semaphore; - } __attribute__ ((packed)) isp4022; - } u1; - - __le32 req_q_in; /* SCSI Request Queue Producer Index */ - __le32 rsp_q_out; /* SCSI Completion Queue Consumer Index */ - - __le32 reserved2[4]; /* 0x40 */ - - union { - struct { - __le32 ext_hw_conf; /* 0x50 */ - __le32 flow_ctrl; - __le32 port_ctrl; - __le32 port_status; - - __le32 reserved3[8]; /* 0x60 */ - - __le32 req_q_out; /* 0x80 */ - - __le32 reserved4[23]; /* 0x84 */ - - __le32 gp_out; /* 0xe0 */ - __le32 gp_in; - - __le32 reserved5[5]; - - __le32 port_err_status; /* 0xfc */ - } __attribute__ ((packed)) isp4010; - struct { - union { - struct port_ctrl_stat_regs p0; - struct host_mem_cfg_regs p1; - }; - } __attribute__ ((packed)) isp4022; - } u2; -}; /* 256 x100 */ - - -/* Semaphore Defines for 4010 */ -#define QL4010_DRVR_SEM_BITS 0x00000030 -#define QL4010_GPIO_SEM_BITS 0x000000c0 -#define QL4010_SDRAM_SEM_BITS 0x00000300 -#define QL4010_PHY_SEM_BITS 0x00000c00 -#define QL4010_NVRAM_SEM_BITS 0x00003000 -#define QL4010_FLASH_SEM_BITS 0x0000c000 - -#define QL4010_DRVR_SEM_MASK 0x00300000 -#define QL4010_GPIO_SEM_MASK 0x00c00000 -#define QL4010_SDRAM_SEM_MASK 0x03000000 -#define QL4010_PHY_SEM_MASK 0x0c000000 -#define QL4010_NVRAM_SEM_MASK 0x30000000 -#define QL4010_FLASH_SEM_MASK 0xc0000000 - -/* Semaphore Defines for 4022 */ -#define QL4022_RESOURCE_MASK_BASE_CODE 0x7 -#define QL4022_RESOURCE_BITS_BASE_CODE 0x4 - - -#define QL4022_DRVR_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (1+16)) -#define QL4022_DDR_RAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (4+16)) -#define QL4022_PHY_GIO_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (7+16)) -#define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16)) -#define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16)) - -/* nvram address for 4032 */ -#define NVRAM_PORT0_BOOT_MODE 0x03b1 -#define NVRAM_PORT0_BOOT_PRI_TGT 0x03b2 -#define NVRAM_PORT0_BOOT_SEC_TGT 0x03bb -#define NVRAM_PORT1_BOOT_MODE 0x07b1 -#define NVRAM_PORT1_BOOT_PRI_TGT 0x07b2 -#define NVRAM_PORT1_BOOT_SEC_TGT 0x07bb - - -/* Page # defines for 4022 */ -#define PORT_CTRL_STAT_PAGE 0 /* 4022 */ -#define HOST_MEM_CFG_PAGE 1 /* 4022 */ -#define LOCAL_RAM_CFG_PAGE 2 /* 4022 */ -#define PROT_STAT_PAGE 3 /* 4022 */ - -/* Register Mask - sets corresponding mask bits in the upper word */ -static inline uint32_t set_rmask(uint32_t val) -{ - return (val & 0xffff) | (val << 16); -} - - -static inline uint32_t clr_rmask(uint32_t val) -{ - return 0 | (val << 16); -} - -/* ctrl_status definitions */ -#define CSR_SCSI_PAGE_SELECT 0x00000003 -#define CSR_SCSI_INTR_ENABLE 0x00000004 /* 4010 */ -#define CSR_SCSI_RESET_INTR 0x00000008 -#define CSR_SCSI_COMPLETION_INTR 0x00000010 -#define CSR_SCSI_PROCESSOR_INTR 0x00000020 -#define CSR_INTR_RISC 0x00000040 -#define CSR_BOOT_ENABLE 0x00000080 -#define CSR_NET_PAGE_SELECT 0x00000300 /* 4010 */ -#define CSR_FUNC_NUM 0x00000700 /* 4022 */ -#define CSR_NET_RESET_INTR 0x00000800 /* 4010 */ -#define CSR_FORCE_SOFT_RESET 0x00002000 /* 4022 */ -#define CSR_FATAL_ERROR 0x00004000 -#define CSR_SOFT_RESET 0x00008000 -#define ISP_CONTROL_FN_MASK CSR_FUNC_NUM -#define ISP_CONTROL_FN0_SCSI 0x0500 -#define ISP_CONTROL_FN1_SCSI 0x0700 - -#define INTR_PENDING (CSR_SCSI_COMPLETION_INTR |\ - CSR_SCSI_PROCESSOR_INTR |\ - CSR_SCSI_RESET_INTR) - -/* ISP InterruptMask definitions */ -#define IMR_SCSI_INTR_ENABLE 0x00000004 /* 4022 */ - -/* ISP 4022 nvram definitions */ -#define NVR_WRITE_ENABLE 0x00000010 /* 4022 */ - -#define QL4010_NVRAM_SIZE 0x200 -#define QL40X2_NVRAM_SIZE 0x800 - -/* ISP port_status definitions */ - -/* ISP Semaphore definitions */ - -/* ISP General Purpose Output definitions */ -#define GPOR_TOPCAT_RESET 0x00000004 - -/* shadow registers (DMA'd from HA to system memory. read only) */ -struct shadow_regs { - /* SCSI Request Queue Consumer Index */ - __le32 req_q_out; /* 0 x0 R */ - - /* SCSI Completion Queue Producer Index */ - __le32 rsp_q_in; /* 4 x4 R */ -}; /* 8 x8 */ - - -/* External hardware configuration register */ -union external_hw_config_reg { - struct { - /* FIXME: Do we even need this? All values are - * referred to by 16 bit quantities. Platform and - * endianess issues. */ - __le32 bReserved0:1; - __le32 bSDRAMProtectionMethod:2; - __le32 bSDRAMBanks:1; - __le32 bSDRAMChipWidth:1; - __le32 bSDRAMChipSize:2; - __le32 bParityDisable:1; - __le32 bExternalMemoryType:1; - __le32 bFlashBIOSWriteEnable:1; - __le32 bFlashUpperBankSelect:1; - __le32 bWriteBurst:2; - __le32 bReserved1:3; - __le32 bMask:16; - }; - uint32_t Asuint32_t; -}; - -/* 82XX Support start */ -/* 82xx Default FLT Addresses */ -#define FA_FLASH_LAYOUT_ADDR_82 0xFC400 -#define FA_FLASH_DESCR_ADDR_82 0xFC000 -#define FA_BOOT_LOAD_ADDR_82 0x04000 -#define FA_BOOT_CODE_ADDR_82 0x20000 -#define FA_RISC_CODE_ADDR_82 0x40000 -#define FA_GOLD_RISC_CODE_ADDR_82 0x80000 -#define FA_FLASH_ISCSI_CHAP 0x540000 -#define FA_FLASH_CHAP_SIZE 0xC0000 - -/* Flash Description Table */ -struct qla_fdt_layout { - uint8_t sig[4]; - uint16_t version; - uint16_t len; - uint16_t checksum; - uint8_t unused1[2]; - uint8_t model[16]; - uint16_t man_id; - uint16_t id; - uint8_t flags; - uint8_t erase_cmd; - uint8_t alt_erase_cmd; - uint8_t wrt_enable_cmd; - uint8_t wrt_enable_bits; - uint8_t wrt_sts_reg_cmd; - uint8_t unprotect_sec_cmd; - uint8_t read_man_id_cmd; - uint32_t block_size; - uint32_t alt_block_size; - uint32_t flash_size; - uint32_t wrt_enable_data; - uint8_t read_id_addr_len; - uint8_t wrt_disable_bits; - uint8_t read_dev_id_len; - uint8_t chip_erase_cmd; - uint16_t read_timeout; - uint8_t protect_sec_cmd; - uint8_t unused2[65]; -}; - -/* Flash Layout Table */ - -struct qla_flt_location { - uint8_t sig[4]; - uint16_t start_lo; - uint16_t start_hi; - uint8_t version; - uint8_t unused[5]; - uint16_t checksum; -}; - -struct qla_flt_header { - uint16_t version; - uint16_t length; - uint16_t checksum; - uint16_t unused; -}; - -/* 82xx FLT Regions */ -#define FLT_REG_FDT 0x1a -#define FLT_REG_FLT 0x1c -#define FLT_REG_BOOTLOAD_82 0x72 -#define FLT_REG_FW_82 0x74 -#define FLT_REG_FW_82_1 0x97 -#define FLT_REG_GOLD_FW_82 0x75 -#define FLT_REG_BOOT_CODE_82 0x78 -#define FLT_REG_ISCSI_PARAM 0x65 -#define FLT_REG_ISCSI_CHAP 0x63 - -struct qla_flt_region { - uint32_t code; - uint32_t size; - uint32_t start; - uint32_t end; -}; - -/************************************************************************* - * - * Mailbox Commands Structures and Definitions - * - *************************************************************************/ - -/* Mailbox command definitions */ -#define MBOX_CMD_ABOUT_FW 0x0009 -#define MBOX_CMD_PING 0x000B -#define PING_IPV6_PROTOCOL_ENABLE 0x1 -#define PING_IPV6_LINKLOCAL_ADDR 0x4 -#define PING_IPV6_ADDR0 0x8 -#define PING_IPV6_ADDR1 0xC -#define MBOX_CMD_ENABLE_INTRS 0x0010 -#define INTR_DISABLE 0 -#define INTR_ENABLE 1 -#define MBOX_CMD_STOP_FW 0x0014 -#define MBOX_CMD_ABORT_TASK 0x0015 -#define MBOX_CMD_LUN_RESET 0x0016 -#define MBOX_CMD_TARGET_WARM_RESET 0x0017 -#define MBOX_CMD_GET_MANAGEMENT_DATA 0x001E -#define MBOX_CMD_GET_FW_STATUS 0x001F -#define MBOX_CMD_SET_ISNS_SERVICE 0x0021 -#define ISNS_DISABLE 0 -#define ISNS_ENABLE 1 -#define MBOX_CMD_COPY_FLASH 0x0024 -#define MBOX_CMD_WRITE_FLASH 0x0025 -#define MBOX_CMD_READ_FLASH 0x0026 -#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031 -#define MBOX_CMD_CONN_OPEN 0x0074 -#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056 -#define LOGOUT_OPTION_CLOSE_SESSION 0x0002 -#define LOGOUT_OPTION_RELOGIN 0x0004 -#define LOGOUT_OPTION_FREE_DDB 0x0008 -#define MBOX_CMD_EXECUTE_IOCB_A64 0x005A -#define MBOX_CMD_INITIALIZE_FIRMWARE 0x0060 -#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK 0x0061 -#define MBOX_CMD_REQUEST_DATABASE_ENTRY 0x0062 -#define MBOX_CMD_SET_DATABASE_ENTRY 0x0063 -#define MBOX_CMD_GET_DATABASE_ENTRY 0x0064 -#define DDB_DS_UNASSIGNED 0x00 -#define DDB_DS_NO_CONNECTION_ACTIVE 0x01 -#define DDB_DS_DISCOVERY 0x02 -#define DDB_DS_SESSION_ACTIVE 0x04 -#define DDB_DS_SESSION_FAILED 0x06 -#define DDB_DS_LOGIN_IN_PROCESS 0x07 -#define MBOX_CMD_GET_FW_STATE 0x0069 -#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK_DEFAULTS 0x006A -#define MBOX_CMD_GET_SYS_INFO 0x0078 -#define MBOX_CMD_GET_NVRAM 0x0078 /* For 40xx */ -#define MBOX_CMD_SET_NVRAM 0x0079 /* For 40xx */ -#define MBOX_CMD_RESTORE_FACTORY_DEFAULTS 0x0087 -#define MBOX_CMD_SET_ACB 0x0088 -#define MBOX_CMD_GET_ACB 0x0089 -#define MBOX_CMD_DISABLE_ACB 0x008A -#define MBOX_CMD_GET_IPV6_NEIGHBOR_CACHE 0x008B -#define MBOX_CMD_GET_IPV6_DEST_CACHE 0x008C -#define MBOX_CMD_GET_IPV6_DEF_ROUTER_LIST 0x008D -#define MBOX_CMD_GET_IPV6_LCL_PREFIX_LIST 0x008E -#define MBOX_CMD_SET_IPV6_NEIGHBOR_CACHE 0x0090 -#define MBOX_CMD_GET_IP_ADDR_STATE 0x0091 -#define MBOX_CMD_SEND_IPV6_ROUTER_SOL 0x0092 -#define MBOX_CMD_GET_DB_ENTRY_CURRENT_IP_ADDR 0x0093 - -/* Mailbox 1 */ -#define FW_STATE_READY 0x0000 -#define FW_STATE_CONFIG_WAIT 0x0001 -#define FW_STATE_WAIT_AUTOCONNECT 0x0002 -#define FW_STATE_ERROR 0x0004 -#define FW_STATE_CONFIGURING_IP 0x0008 - -/* Mailbox 3 */ -#define FW_ADDSTATE_OPTICAL_MEDIA 0x0001 -#define FW_ADDSTATE_DHCPv4_ENABLED 0x0002 -#define FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED 0x0004 -#define FW_ADDSTATE_DHCPv4_LEASE_EXPIRED 0x0008 -#define FW_ADDSTATE_LINK_UP 0x0010 -#define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020 -#define FW_ADDSTATE_LINK_SPEED_10MBPS 0x0100 -#define FW_ADDSTATE_LINK_SPEED_100MBPS 0x0200 -#define FW_ADDSTATE_LINK_SPEED_1GBPS 0x0400 -#define FW_ADDSTATE_LINK_SPEED_10GBPS 0x0800 - -#define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B -#define IPV6_DEFAULT_DDB_ENTRY 0x0001 - -#define MBOX_CMD_CONN_OPEN_SESS_LOGIN 0x0074 -#define MBOX_CMD_GET_CRASH_RECORD 0x0076 /* 4010 only */ -#define MBOX_CMD_GET_CONN_EVENT_LOG 0x0077 - -/* Mailbox status definitions */ -#define MBOX_COMPLETION_STATUS 4 -#define MBOX_STS_BUSY 0x0007 -#define MBOX_STS_INTERMEDIATE_COMPLETION 0x1000 -#define MBOX_STS_COMMAND_COMPLETE 0x4000 -#define MBOX_STS_COMMAND_ERROR 0x4005 - -#define MBOX_ASYNC_EVENT_STATUS 8 -#define MBOX_ASTS_SYSTEM_ERROR 0x8002 -#define MBOX_ASTS_REQUEST_TRANSFER_ERROR 0x8003 -#define MBOX_ASTS_RESPONSE_TRANSFER_ERROR 0x8004 -#define MBOX_ASTS_PROTOCOL_STATISTIC_ALARM 0x8005 -#define MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED 0x8006 -#define MBOX_ASTS_LINK_UP 0x8010 -#define MBOX_ASTS_LINK_DOWN 0x8011 -#define MBOX_ASTS_DATABASE_CHANGED 0x8014 -#define MBOX_ASTS_UNSOLICITED_PDU_RECEIVED 0x8015 -#define MBOX_ASTS_SELF_TEST_FAILED 0x8016 -#define MBOX_ASTS_LOGIN_FAILED 0x8017 -#define MBOX_ASTS_DNS 0x8018 -#define MBOX_ASTS_HEARTBEAT 0x8019 -#define MBOX_ASTS_NVRAM_INVALID 0x801A -#define MBOX_ASTS_MAC_ADDRESS_CHANGED 0x801B -#define MBOX_ASTS_IP_ADDRESS_CHANGED 0x801C -#define MBOX_ASTS_DHCP_LEASE_EXPIRED 0x801D -#define MBOX_ASTS_DHCP_LEASE_ACQUIRED 0x801F -#define MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED 0x8021 -#define MBOX_ASTS_DUPLICATE_IP 0x8025 -#define MBOX_ASTS_ARP_COMPLETE 0x8026 -#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027 -#define MBOX_ASTS_RESPONSE_QUEUE_FULL 0x8028 -#define MBOX_ASTS_IP_ADDR_STATE_CHANGED 0x8029 -#define MBOX_ASTS_IPV6_PREFIX_EXPIRED 0x802B -#define MBOX_ASTS_IPV6_ND_PREFIX_IGNORED 0x802C -#define MBOX_ASTS_IPV6_LCL_PREFIX_IGNORED 0x802D -#define MBOX_ASTS_ICMPV6_ERROR_MSG_RCVD 0x802E -#define MBOX_ASTS_TXSCVR_INSERTED 0x8130 -#define MBOX_ASTS_TXSCVR_REMOVED 0x8131 - -#define ISNS_EVENT_DATA_RECEIVED 0x0000 -#define ISNS_EVENT_CONNECTION_OPENED 0x0001 -#define ISNS_EVENT_CONNECTION_FAILED 0x0002 -#define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022 -#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027 - -/* ACB State Defines */ -#define ACB_STATE_UNCONFIGURED 0x00 -#define ACB_STATE_INVALID 0x01 -#define ACB_STATE_ACQUIRING 0x02 -#define ACB_STATE_TENTATIVE 0x03 -#define ACB_STATE_DEPRICATED 0x04 -#define ACB_STATE_VALID 0x05 -#define ACB_STATE_DISABLING 0x06 - -/* FLASH offsets */ -#define FLASH_SEGMENT_IFCB 0x04000000 - -#define FLASH_OPT_RMW_HOLD 0 -#define FLASH_OPT_RMW_INIT 1 -#define FLASH_OPT_COMMIT 2 -#define FLASH_OPT_RMW_COMMIT 3 - -/*************************************************************************/ - -/* Host Adapter Initialization Control Block (from host) */ -struct addr_ctrl_blk { - uint8_t version; /* 00 */ -#define IFCB_VER_MIN 0x01 -#define IFCB_VER_MAX 0x02 - uint8_t control; /* 01 */ - - uint16_t fw_options; /* 02-03 */ -#define FWOPT_HEARTBEAT_ENABLE 0x1000 -#define FWOPT_SESSION_MODE 0x0040 -#define FWOPT_INITIATOR_MODE 0x0020 -#define FWOPT_TARGET_MODE 0x0010 -#define FWOPT_ENABLE_CRBDB 0x8000 - - uint16_t exec_throttle; /* 04-05 */ - uint8_t zio_count; /* 06 */ - uint8_t res0; /* 07 */ - uint16_t eth_mtu_size; /* 08-09 */ - uint16_t add_fw_options; /* 0A-0B */ -#define ADFWOPT_SERIALIZE_TASK_MGMT 0x0400 -#define ADFWOPT_AUTOCONN_DISABLE 0x0002 - - uint8_t hb_interval; /* 0C */ - uint8_t inst_num; /* 0D */ - uint16_t res1; /* 0E-0F */ - uint16_t rqq_consumer_idx; /* 10-11 */ - uint16_t compq_producer_idx; /* 12-13 */ - uint16_t rqq_len; /* 14-15 */ - uint16_t compq_len; /* 16-17 */ - uint32_t rqq_addr_lo; /* 18-1B */ - uint32_t rqq_addr_hi; /* 1C-1F */ - uint32_t compq_addr_lo; /* 20-23 */ - uint32_t compq_addr_hi; /* 24-27 */ - uint32_t shdwreg_addr_lo; /* 28-2B */ - uint32_t shdwreg_addr_hi; /* 2C-2F */ - - uint16_t iscsi_opts; /* 30-31 */ - uint16_t ipv4_tcp_opts; /* 32-33 */ -#define TCPOPT_DHCP_ENABLE 0x0200 - uint16_t ipv4_ip_opts; /* 34-35 */ -#define IPOPT_IPV4_PROTOCOL_ENABLE 0x8000 -#define IPOPT_VLAN_TAGGING_ENABLE 0x2000 - - uint16_t iscsi_max_pdu_size; /* 36-37 */ - uint8_t ipv4_tos; /* 38 */ - uint8_t ipv4_ttl; /* 39 */ - uint8_t acb_version; /* 3A */ -#define ACB_NOT_SUPPORTED 0x00 -#define ACB_SUPPORTED 0x02 /* Capable of ACB Version 2 - Features */ - - uint8_t res2; /* 3B */ - uint16_t def_timeout; /* 3C-3D */ - uint16_t iscsi_fburst_len; /* 3E-3F */ - uint16_t iscsi_def_time2wait; /* 40-41 */ - uint16_t iscsi_def_time2retain; /* 42-43 */ - uint16_t iscsi_max_outstnd_r2t; /* 44-45 */ - uint16_t conn_ka_timeout; /* 46-47 */ - uint16_t ipv4_port; /* 48-49 */ - uint16_t iscsi_max_burst_len; /* 4A-4B */ - uint32_t res5; /* 4C-4F */ - uint8_t ipv4_addr[4]; /* 50-53 */ - uint16_t ipv4_vlan_tag; /* 54-55 */ - uint8_t ipv4_addr_state; /* 56 */ - uint8_t ipv4_cacheid; /* 57 */ - uint8_t res6[8]; /* 58-5F */ - uint8_t ipv4_subnet[4]; /* 60-63 */ - uint8_t res7[12]; /* 64-6F */ - uint8_t ipv4_gw_addr[4]; /* 70-73 */ - uint8_t res8[0xc]; /* 74-7F */ - uint8_t pri_dns_srvr_ip[4];/* 80-83 */ - uint8_t sec_dns_srvr_ip[4];/* 84-87 */ - uint16_t min_eph_port; /* 88-89 */ - uint16_t max_eph_port; /* 8A-8B */ - uint8_t res9[4]; /* 8C-8F */ - uint8_t iscsi_alias[32];/* 90-AF */ - uint8_t res9_1[0x16]; /* B0-C5 */ - uint16_t tgt_portal_grp;/* C6-C7 */ - uint8_t abort_timer; /* C8 */ - uint8_t ipv4_tcp_wsf; /* C9 */ - uint8_t res10[6]; /* CA-CF */ - uint8_t ipv4_sec_ip_addr[4]; /* D0-D3 */ - uint8_t ipv4_dhcp_vid_len; /* D4 */ - uint8_t ipv4_dhcp_vid[11]; /* D5-DF */ - uint8_t res11[20]; /* E0-F3 */ - uint8_t ipv4_dhcp_alt_cid_len; /* F4 */ - uint8_t ipv4_dhcp_alt_cid[11]; /* F5-FF */ - uint8_t iscsi_name[224]; /* 100-1DF */ - uint8_t res12[32]; /* 1E0-1FF */ - uint32_t cookie; /* 200-203 */ - uint16_t ipv6_port; /* 204-205 */ - uint16_t ipv6_opts; /* 206-207 */ -#define IPV6_OPT_IPV6_PROTOCOL_ENABLE 0x8000 -#define IPV6_OPT_VLAN_TAGGING_ENABLE 0x2000 - - uint16_t ipv6_addtl_opts; /* 208-209 */ -#define IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE 0x0002 /* Pri ACB - Only */ -#define IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR 0x0001 - - uint16_t ipv6_tcp_opts; /* 20A-20B */ - uint8_t ipv6_tcp_wsf; /* 20C */ - uint16_t ipv6_flow_lbl; /* 20D-20F */ - uint8_t ipv6_dflt_rtr_addr[16]; /* 210-21F */ - uint16_t ipv6_vlan_tag; /* 220-221 */ - uint8_t ipv6_lnk_lcl_addr_state;/* 222 */ - uint8_t ipv6_addr0_state; /* 223 */ - uint8_t ipv6_addr1_state; /* 224 */ -#define IP_ADDRSTATE_UNCONFIGURED 0 -#define IP_ADDRSTATE_INVALID 1 -#define IP_ADDRSTATE_ACQUIRING 2 -#define IP_ADDRSTATE_TENTATIVE 3 -#define IP_ADDRSTATE_DEPRICATED 4 -#define IP_ADDRSTATE_PREFERRED 5 -#define IP_ADDRSTATE_DISABLING 6 - - uint8_t ipv6_dflt_rtr_state; /* 225 */ -#define IPV6_RTRSTATE_UNKNOWN 0 -#define IPV6_RTRSTATE_MANUAL 1 -#define IPV6_RTRSTATE_ADVERTISED 3 -#define IPV6_RTRSTATE_STALE 4 - - uint8_t ipv6_traffic_class; /* 226 */ - uint8_t ipv6_hop_limit; /* 227 */ - uint8_t ipv6_if_id[8]; /* 228-22F */ - uint8_t ipv6_addr0[16]; /* 230-23F */ - uint8_t ipv6_addr1[16]; /* 240-24F */ - uint32_t ipv6_nd_reach_time; /* 250-253 */ - uint32_t ipv6_nd_rexmit_timer; /* 254-257 */ - uint32_t ipv6_nd_stale_timeout; /* 258-25B */ - uint8_t ipv6_dup_addr_detect_count; /* 25C */ - uint8_t ipv6_cache_id; /* 25D */ - uint8_t res13[18]; /* 25E-26F */ - uint32_t ipv6_gw_advrt_mtu; /* 270-273 */ - uint8_t res14[140]; /* 274-2FF */ -}; - -#define IP_ADDR_COUNT 4 /* Total 4 IP address supported in one interface - * One IPv4, one IPv6 link local and 2 IPv6 - */ - -#define IP_STATE_MASK 0x0F000000 -#define IP_STATE_SHIFT 24 - -struct init_fw_ctrl_blk { - struct addr_ctrl_blk pri; -/* struct addr_ctrl_blk sec;*/ -}; - -#define PRIMARI_ACB 0 -#define SECONDARY_ACB 1 - -struct addr_ctrl_blk_def { - uint8_t reserved1[1]; /* 00 */ - uint8_t control; /* 01 */ - uint8_t reserved2[11]; /* 02-0C */ - uint8_t inst_num; /* 0D */ - uint8_t reserved3[34]; /* 0E-2F */ - uint16_t iscsi_opts; /* 30-31 */ - uint16_t ipv4_tcp_opts; /* 32-33 */ - uint16_t ipv4_ip_opts; /* 34-35 */ - uint16_t iscsi_max_pdu_size; /* 36-37 */ - uint8_t ipv4_tos; /* 38 */ - uint8_t ipv4_ttl; /* 39 */ - uint8_t reserved4[2]; /* 3A-3B */ - uint16_t def_timeout; /* 3C-3D */ - uint16_t iscsi_fburst_len; /* 3E-3F */ - uint8_t reserved5[4]; /* 40-43 */ - uint16_t iscsi_max_outstnd_r2t; /* 44-45 */ - uint8_t reserved6[2]; /* 46-47 */ - uint16_t ipv4_port; /* 48-49 */ - uint16_t iscsi_max_burst_len; /* 4A-4B */ - uint8_t reserved7[4]; /* 4C-4F */ - uint8_t ipv4_addr[4]; /* 50-53 */ - uint16_t ipv4_vlan_tag; /* 54-55 */ - uint8_t ipv4_addr_state; /* 56 */ - uint8_t ipv4_cacheid; /* 57 */ - uint8_t reserved8[8]; /* 58-5F */ - uint8_t ipv4_subnet[4]; /* 60-63 */ - uint8_t reserved9[12]; /* 64-6F */ - uint8_t ipv4_gw_addr[4]; /* 70-73 */ - uint8_t reserved10[84]; /* 74-C7 */ - uint8_t abort_timer; /* C8 */ - uint8_t ipv4_tcp_wsf; /* C9 */ - uint8_t reserved11[10]; /* CA-D3 */ - uint8_t ipv4_dhcp_vid_len; /* D4 */ - uint8_t ipv4_dhcp_vid[11]; /* D5-DF */ - uint8_t reserved12[20]; /* E0-F3 */ - uint8_t ipv4_dhcp_alt_cid_len; /* F4 */ - uint8_t ipv4_dhcp_alt_cid[11]; /* F5-FF */ - uint8_t iscsi_name[224]; /* 100-1DF */ - uint8_t reserved13[32]; /* 1E0-1FF */ - uint32_t cookie; /* 200-203 */ - uint16_t ipv6_port; /* 204-205 */ - uint16_t ipv6_opts; /* 206-207 */ - uint16_t ipv6_addtl_opts; /* 208-209 */ - uint16_t ipv6_tcp_opts; /* 20A-20B */ - uint8_t ipv6_tcp_wsf; /* 20C */ - uint16_t ipv6_flow_lbl; /* 20D-20F */ - uint8_t ipv6_dflt_rtr_addr[16]; /* 210-21F */ - uint16_t ipv6_vlan_tag; /* 220-221 */ - uint8_t ipv6_lnk_lcl_addr_state; /* 222 */ - uint8_t ipv6_addr0_state; /* 223 */ - uint8_t ipv6_addr1_state; /* 224 */ - uint8_t ipv6_dflt_rtr_state; /* 225 */ - uint8_t ipv6_traffic_class; /* 226 */ - uint8_t ipv6_hop_limit; /* 227 */ - uint8_t ipv6_if_id[8]; /* 228-22F */ - uint8_t ipv6_addr0[16]; /* 230-23F */ - uint8_t ipv6_addr1[16]; /* 240-24F */ - uint32_t ipv6_nd_reach_time; /* 250-253 */ - uint32_t ipv6_nd_rexmit_timer; /* 254-257 */ - uint32_t ipv6_nd_stale_timeout; /* 258-25B */ - uint8_t ipv6_dup_addr_detect_count; /* 25C */ - uint8_t ipv6_cache_id; /* 25D */ - uint8_t reserved14[18]; /* 25E-26F */ - uint32_t ipv6_gw_advrt_mtu; /* 270-273 */ - uint8_t reserved15[140]; /* 274-2FF */ -}; - -/*************************************************************************/ - -#define MAX_CHAP_ENTRIES_40XX 128 -#define MAX_CHAP_ENTRIES_82XX 1024 -#define MAX_RESRV_CHAP_IDX 3 -#define FLASH_CHAP_OFFSET 0x06000000 - -struct ql4_chap_table { - uint16_t link; - uint8_t flags; - uint8_t secret_len; -#define MIN_CHAP_SECRET_LEN 12 -#define MAX_CHAP_SECRET_LEN 100 - uint8_t secret[MAX_CHAP_SECRET_LEN]; -#define MAX_CHAP_NAME_LEN 256 - uint8_t name[MAX_CHAP_NAME_LEN]; - uint16_t reserved; -#define CHAP_VALID_COOKIE 0x4092 -#define CHAP_INVALID_COOKIE 0xFFEE - uint16_t cookie; -}; - -struct dev_db_entry { - uint16_t options; /* 00-01 */ -#define DDB_OPT_DISC_SESSION 0x10 -#define DDB_OPT_TARGET 0x02 /* device is a target */ -#define DDB_OPT_IPV6_DEVICE 0x100 -#define DDB_OPT_AUTO_SENDTGTS_DISABLE 0x40 -#define DDB_OPT_IPV6_NULL_LINK_LOCAL 0x800 /* post connection */ -#define DDB_OPT_IPV6_FW_DEFINED_LINK_LOCAL 0x800 /* pre connection */ - - uint16_t exec_throttle; /* 02-03 */ - uint16_t exec_count; /* 04-05 */ - uint16_t res0; /* 06-07 */ - uint16_t iscsi_options; /* 08-09 */ - uint16_t tcp_options; /* 0A-0B */ - uint16_t ip_options; /* 0C-0D */ - uint16_t iscsi_max_rcv_data_seg_len; /* 0E-0F */ -#define BYTE_UNITS 512 - uint32_t res1; /* 10-13 */ - uint16_t iscsi_max_snd_data_seg_len; /* 14-15 */ - uint16_t iscsi_first_burst_len; /* 16-17 */ - uint16_t iscsi_def_time2wait; /* 18-19 */ - uint16_t iscsi_def_time2retain; /* 1A-1B */ - uint16_t iscsi_max_outsnd_r2t; /* 1C-1D */ - uint16_t ka_timeout; /* 1E-1F */ - uint8_t isid[6]; /* 20-25 big-endian, must be converted - * to little-endian */ - uint16_t tsid; /* 26-27 */ - uint16_t port; /* 28-29 */ - uint16_t iscsi_max_burst_len; /* 2A-2B */ - uint16_t def_timeout; /* 2C-2D */ - uint16_t res2; /* 2E-2F */ - uint8_t ip_addr[0x10]; /* 30-3F */ - uint8_t iscsi_alias[0x20]; /* 40-5F */ - uint8_t tgt_addr[0x20]; /* 60-7F */ - uint16_t mss; /* 80-81 */ - uint16_t res3; /* 82-83 */ - uint16_t lcl_port; /* 84-85 */ - uint8_t ipv4_tos; /* 86 */ - uint16_t ipv6_flow_lbl; /* 87-89 */ - uint8_t res4[0x36]; /* 8A-BF */ - uint8_t iscsi_name[0xE0]; /* C0-19F : xxzzy Make this a - * pointer to a string so we - * don't have to reserve so - * much RAM */ - uint8_t link_local_ipv6_addr[0x10]; /* 1A0-1AF */ - uint8_t res5[0x10]; /* 1B0-1BF */ - uint16_t ddb_link; /* 1C0-1C1 */ - uint16_t chap_tbl_idx; /* 1C2-1C3 */ - uint16_t tgt_portal_grp; /* 1C4-1C5 */ - uint8_t tcp_xmt_wsf; /* 1C6 */ - uint8_t tcp_rcv_wsf; /* 1C7 */ - uint32_t stat_sn; /* 1C8-1CB */ - uint32_t exp_stat_sn; /* 1CC-1CF */ - uint8_t res6[0x2b]; /* 1D0-1FB */ -#define DDB_VALID_COOKIE 0x9034 - uint16_t cookie; /* 1FC-1FD */ - uint16_t len; /* 1FE-1FF */ -}; - -/*************************************************************************/ - -/* Flash definitions */ - -#define FLASH_OFFSET_SYS_INFO 0x02000000 -#define FLASH_DEFAULTBLOCKSIZE 0x20000 -#define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes - * for EOF - * signature */ -#define FLASH_RAW_ACCESS_ADDR 0x8e000000 - -#define BOOT_PARAM_OFFSET_PORT0 0x3b0 -#define BOOT_PARAM_OFFSET_PORT1 0x7b0 - -#define FLASH_OFFSET_DB_INFO 0x05000000 -#define FLASH_OFFSET_DB_END (FLASH_OFFSET_DB_INFO + 0x7fff) - - -struct sys_info_phys_addr { - uint8_t address[6]; /* 00-05 */ - uint8_t filler[2]; /* 06-07 */ -}; - -struct flash_sys_info { - uint32_t cookie; /* 00-03 */ - uint32_t physAddrCount; /* 04-07 */ - struct sys_info_phys_addr physAddr[4]; /* 08-27 */ - uint8_t vendorId[128]; /* 28-A7 */ - uint8_t productId[128]; /* A8-127 */ - uint32_t serialNumber; /* 128-12B */ - - /* PCI Configuration values */ - uint32_t pciDeviceVendor; /* 12C-12F */ - uint32_t pciDeviceId; /* 130-133 */ - uint32_t pciSubsysVendor; /* 134-137 */ - uint32_t pciSubsysId; /* 138-13B */ - - /* This validates version 1. */ - uint32_t crumbs; /* 13C-13F */ - - uint32_t enterpriseNumber; /* 140-143 */ - - uint32_t mtu; /* 144-147 */ - uint32_t reserved0; /* 148-14b */ - uint32_t crumbs2; /* 14c-14f */ - uint8_t acSerialNumber[16]; /* 150-15f */ - uint32_t crumbs3; /* 160-16f */ - - /* Leave this last in the struct so it is declared invalid if - * any new items are added. - */ - uint32_t reserved1[39]; /* 170-1ff */ -}; /* 200 */ - -struct mbx_sys_info { - uint8_t board_id_str[16]; /* 0-f Keep board ID string first */ - /* in this structure for GUI. */ - uint16_t board_id; /* 10-11 board ID code */ - uint16_t phys_port_cnt; /* 12-13 number of physical network ports */ - uint16_t port_num; /* 14-15 network port for this PCI function */ - /* (port 0 is first port) */ - uint8_t mac_addr[6]; /* 16-1b MAC address for this PCI function */ - uint32_t iscsi_pci_func_cnt; /* 1c-1f number of iSCSI PCI functions */ - uint32_t pci_func; /* 20-23 this PCI function */ - unsigned char serial_number[16]; /* 24-33 serial number string */ - uint8_t reserved[12]; /* 34-3f */ -}; - -struct about_fw_info { - uint16_t fw_major; /* 00 - 01 */ - uint16_t fw_minor; /* 02 - 03 */ - uint16_t fw_patch; /* 04 - 05 */ - uint16_t fw_build; /* 06 - 07 */ - uint8_t fw_build_date[16]; /* 08 - 17 ASCII String */ - uint8_t fw_build_time[16]; /* 18 - 27 ASCII String */ - uint8_t fw_build_user[16]; /* 28 - 37 ASCII String */ - uint16_t fw_load_source; /* 38 - 39 */ - /* 1 = Flash Primary, - 2 = Flash Secondary, - 3 = Host Download - */ - uint8_t reserved1[6]; /* 3A - 3F */ - uint16_t iscsi_major; /* 40 - 41 */ - uint16_t iscsi_minor; /* 42 - 43 */ - uint16_t bootload_major; /* 44 - 45 */ - uint16_t bootload_minor; /* 46 - 47 */ - uint16_t bootload_patch; /* 48 - 49 */ - uint16_t bootload_build; /* 4A - 4B */ - uint8_t reserved2[180]; /* 4C - FF */ -}; - -struct crash_record { - uint16_t fw_major_version; /* 00 - 01 */ - uint16_t fw_minor_version; /* 02 - 03 */ - uint16_t fw_patch_version; /* 04 - 05 */ - uint16_t fw_build_version; /* 06 - 07 */ - - uint8_t build_date[16]; /* 08 - 17 */ - uint8_t build_time[16]; /* 18 - 27 */ - uint8_t build_user[16]; /* 28 - 37 */ - uint8_t card_serial_num[16]; /* 38 - 47 */ - - uint32_t time_of_crash_in_secs; /* 48 - 4B */ - uint32_t time_of_crash_in_ms; /* 4C - 4F */ - - uint16_t out_RISC_sd_num_frames; /* 50 - 51 */ - uint16_t OAP_sd_num_words; /* 52 - 53 */ - uint16_t IAP_sd_num_frames; /* 54 - 55 */ - uint16_t in_RISC_sd_num_words; /* 56 - 57 */ - - uint8_t reserved1[28]; /* 58 - 7F */ - - uint8_t out_RISC_reg_dump[256]; /* 80 -17F */ - uint8_t in_RISC_reg_dump[256]; /*180 -27F */ - uint8_t in_out_RISC_stack_dump[0]; /*280 - ??? */ -}; - -struct conn_event_log_entry { -#define MAX_CONN_EVENT_LOG_ENTRIES 100 - uint32_t timestamp_sec; /* 00 - 03 seconds since boot */ - uint32_t timestamp_ms; /* 04 - 07 milliseconds since boot */ - uint16_t device_index; /* 08 - 09 */ - uint16_t fw_conn_state; /* 0A - 0B */ - uint8_t event_type; /* 0C - 0C */ - uint8_t error_code; /* 0D - 0D */ - uint16_t error_code_detail; /* 0E - 0F */ - uint8_t num_consecutive_events; /* 10 - 10 */ - uint8_t rsvd[3]; /* 11 - 13 */ -}; - -/************************************************************************* - * - * IOCB Commands Structures and Definitions - * - *************************************************************************/ -#define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */ -#define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */ -#define IOCB_MAX_EXT_SENSEDATA_LEN 60 /* Bytes of extended sense data */ - -/* IOCB header structure */ -struct qla4_header { - uint8_t entryType; -#define ET_STATUS 0x03 -#define ET_MARKER 0x04 -#define ET_CONT_T1 0x0A -#define ET_STATUS_CONTINUATION 0x10 -#define ET_CMND_T3 0x19 -#define ET_PASSTHRU0 0x3A -#define ET_PASSTHRU_STATUS 0x3C -#define ET_MBOX_CMD 0x38 -#define ET_MBOX_STATUS 0x39 - - uint8_t entryStatus; - uint8_t systemDefined; -#define SD_ISCSI_PDU 0x01 - uint8_t entryCount; - - /* SyetemDefined definition */ -}; - -/* Generic queue entry structure*/ -struct queue_entry { - uint8_t data[60]; - uint32_t signature; - -}; - -/* 64 bit addressing segment counts*/ - -#define COMMAND_SEG_A64 1 -#define CONTINUE_SEG_A64 5 - -/* 64 bit addressing segment definition*/ - -struct data_seg_a64 { - struct { - uint32_t addrLow; - uint32_t addrHigh; - - } base; - - uint32_t count; - -}; - -/* Command Type 3 entry structure*/ - -struct command_t3_entry { - struct qla4_header hdr; /* 00-03 */ - - uint32_t handle; /* 04-07 */ - uint16_t target; /* 08-09 */ - uint16_t connection_id; /* 0A-0B */ - - uint8_t control_flags; /* 0C */ - - /* data direction (bits 5-6) */ -#define CF_WRITE 0x20 -#define CF_READ 0x40 -#define CF_NO_DATA 0x00 - - /* task attributes (bits 2-0) */ -#define CF_HEAD_TAG 0x03 -#define CF_ORDERED_TAG 0x02 -#define CF_SIMPLE_TAG 0x01 - - /* STATE FLAGS FIELD IS A PLACE HOLDER. THE FW WILL SET BITS - * IN THIS FIELD AS THE COMMAND IS PROCESSED. WHEN THE IOCB IS - * CHANGED TO AN IOSB THIS FIELD WILL HAVE THE STATE FLAGS SET - * PROPERLY. - */ - uint8_t state_flags; /* 0D */ - uint8_t cmdRefNum; /* 0E */ - uint8_t reserved1; /* 0F */ - uint8_t cdb[IOCB_MAX_CDB_LEN]; /* 10-1F */ - struct scsi_lun lun; /* FCP LUN (BE). */ - uint32_t cmdSeqNum; /* 28-2B */ - uint16_t timeout; /* 2C-2D */ - uint16_t dataSegCnt; /* 2E-2F */ - uint32_t ttlByteCnt; /* 30-33 */ - struct data_seg_a64 dataseg[COMMAND_SEG_A64]; /* 34-3F */ - -}; - - -/* Continuation Type 1 entry structure*/ -struct continuation_t1_entry { - struct qla4_header hdr; - - struct data_seg_a64 dataseg[CONTINUE_SEG_A64]; - -}; - -/* Parameterize for 64 or 32 bits */ -#define COMMAND_SEG COMMAND_SEG_A64 -#define CONTINUE_SEG CONTINUE_SEG_A64 - -#define ET_COMMAND ET_CMND_T3 -#define ET_CONTINUE ET_CONT_T1 - -/* Marker entry structure*/ -struct qla4_marker_entry { - struct qla4_header hdr; /* 00-03 */ - - uint32_t system_defined; /* 04-07 */ - uint16_t target; /* 08-09 */ - uint16_t modifier; /* 0A-0B */ -#define MM_LUN_RESET 0 -#define MM_TGT_WARM_RESET 1 - - uint16_t flags; /* 0C-0D */ - uint16_t reserved1; /* 0E-0F */ - struct scsi_lun lun; /* FCP LUN (BE). */ - uint64_t reserved2; /* 18-1F */ - uint64_t reserved3; /* 20-27 */ - uint64_t reserved4; /* 28-2F */ - uint64_t reserved5; /* 30-37 */ - uint64_t reserved6; /* 38-3F */ -}; - -/* Status entry structure*/ -struct status_entry { - struct qla4_header hdr; /* 00-03 */ - - uint32_t handle; /* 04-07 */ - - uint8_t scsiStatus; /* 08 */ -#define SCSI_CHECK_CONDITION 0x02 - - uint8_t iscsiFlags; /* 09 */ -#define ISCSI_FLAG_RESIDUAL_UNDER 0x02 -#define ISCSI_FLAG_RESIDUAL_OVER 0x04 - - uint8_t iscsiResponse; /* 0A */ - - uint8_t completionStatus; /* 0B */ -#define SCS_COMPLETE 0x00 -#define SCS_INCOMPLETE 0x01 -#define SCS_RESET_OCCURRED 0x04 -#define SCS_ABORTED 0x05 -#define SCS_TIMEOUT 0x06 -#define SCS_DATA_OVERRUN 0x07 -#define SCS_DATA_UNDERRUN 0x15 -#define SCS_QUEUE_FULL 0x1C -#define SCS_DEVICE_UNAVAILABLE 0x28 -#define SCS_DEVICE_LOGGED_OUT 0x29 - - uint8_t reserved1; /* 0C */ - - /* state_flags MUST be at the same location as state_flags in - * the Command_T3/4_Entry */ - uint8_t state_flags; /* 0D */ - - uint16_t senseDataByteCnt; /* 0E-0F */ - uint32_t residualByteCnt; /* 10-13 */ - uint32_t bidiResidualByteCnt; /* 14-17 */ - uint32_t expSeqNum; /* 18-1B */ - uint32_t maxCmdSeqNum; /* 1C-1F */ - uint8_t senseData[IOCB_MAX_SENSEDATA_LEN]; /* 20-3F */ - -}; - -/* Status Continuation entry */ -struct status_cont_entry { - struct qla4_header hdr; /* 00-03 */ - uint8_t ext_sense_data[IOCB_MAX_EXT_SENSEDATA_LEN]; /* 04-63 */ -}; - -struct passthru0 { - struct qla4_header hdr; /* 00-03 */ - uint32_t handle; /* 04-07 */ - uint16_t target; /* 08-09 */ - uint16_t connection_id; /* 0A-0B */ -#define ISNS_DEFAULT_SERVER_CONN_ID ((uint16_t)0x8000) - - uint16_t control_flags; /* 0C-0D */ -#define PT_FLAG_ETHERNET_FRAME 0x8000 -#define PT_FLAG_ISNS_PDU 0x8000 -#define PT_FLAG_SEND_BUFFER 0x0200 -#define PT_FLAG_WAIT_4_RESPONSE 0x0100 -#define PT_FLAG_ISCSI_PDU 0x1000 - - uint16_t timeout; /* 0E-0F */ -#define PT_DEFAULT_TIMEOUT 30 /* seconds */ - - struct data_seg_a64 out_dsd; /* 10-1B */ - uint32_t res1; /* 1C-1F */ - struct data_seg_a64 in_dsd; /* 20-2B */ - uint8_t res2[20]; /* 2C-3F */ -}; - -struct passthru_status { - struct qla4_header hdr; /* 00-03 */ - uint32_t handle; /* 04-07 */ - uint16_t target; /* 08-09 */ - uint16_t connectionID; /* 0A-0B */ - - uint8_t completionStatus; /* 0C */ -#define PASSTHRU_STATUS_COMPLETE 0x01 - - uint8_t residualFlags; /* 0D */ - - uint16_t timeout; /* 0E-0F */ - uint16_t portNumber; /* 10-11 */ - uint8_t res1[10]; /* 12-1B */ - uint32_t outResidual; /* 1C-1F */ - uint8_t res2[12]; /* 20-2B */ - uint32_t inResidual; /* 2C-2F */ - uint8_t res4[16]; /* 30-3F */ -}; - -struct mbox_cmd_iocb { - struct qla4_header hdr; /* 00-03 */ - uint32_t handle; /* 04-07 */ - uint32_t in_mbox[8]; /* 08-25 */ - uint32_t res1[6]; /* 26-3F */ -}; - -struct mbox_status_iocb { - struct qla4_header hdr; /* 00-03 */ - uint32_t handle; /* 04-07 */ - uint32_t out_mbox[8]; /* 08-25 */ - uint32_t res1[6]; /* 26-3F */ -}; - -/* - * ISP queue - response queue entry definition. - */ -struct response { - uint8_t data[60]; - uint32_t signature; -#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */ -}; - -struct ql_iscsi_stats { - uint8_t reserved1[656]; /* 0000-028F */ - uint32_t tx_cmd_pdu; /* 0290-0293 */ - uint32_t tx_resp_pdu; /* 0294-0297 */ - uint32_t rx_cmd_pdu; /* 0298-029B */ - uint32_t rx_resp_pdu; /* 029C-029F */ - - uint64_t tx_data_octets; /* 02A0-02A7 */ - uint64_t rx_data_octets; /* 02A8-02AF */ - - uint32_t hdr_digest_err; /* 02B0–02B3 */ - uint32_t data_digest_err; /* 02B4–02B7 */ - uint32_t conn_timeout_err; /* 02B8–02BB */ - uint32_t framing_err; /* 02BC–02BF */ - - uint32_t tx_nopout_pdus; /* 02C0–02C3 */ - uint32_t tx_scsi_cmd_pdus; /* 02C4–02C7 */ - uint32_t tx_tmf_cmd_pdus; /* 02C8–02CB */ - uint32_t tx_login_cmd_pdus; /* 02CC–02CF */ - uint32_t tx_text_cmd_pdus; /* 02D0–02D3 */ - uint32_t tx_scsi_write_pdus; /* 02D4–02D7 */ - uint32_t tx_logout_cmd_pdus; /* 02D8–02DB */ - uint32_t tx_snack_req_pdus; /* 02DC–02DF */ - - uint32_t rx_nopin_pdus; /* 02E0–02E3 */ - uint32_t rx_scsi_resp_pdus; /* 02E4–02E7 */ - uint32_t rx_tmf_resp_pdus; /* 02E8–02EB */ - uint32_t rx_login_resp_pdus; /* 02EC–02EF */ - uint32_t rx_text_resp_pdus; /* 02F0–02F3 */ - uint32_t rx_scsi_read_pdus; /* 02F4–02F7 */ - uint32_t rx_logout_resp_pdus; /* 02F8–02FB */ - - uint32_t rx_r2t_pdus; /* 02FC–02FF */ - uint32_t rx_async_pdus; /* 0300–0303 */ - uint32_t rx_reject_pdus; /* 0304–0307 */ - - uint8_t reserved2[264]; /* 0x0308 - 0x040F */ -}; - -#endif /* _QLA4X_FW_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_glbl.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_glbl.h deleted file mode 100644 index 91053666..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_glbl.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#ifndef __QLA4x_GBL_H -#define __QLA4x_GBL_H - -struct iscsi_cls_conn; - -int qla4xxx_hw_reset(struct scsi_qla_host *ha); -int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a); -int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb *srb); -int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset); -int qla4xxx_soft_reset(struct scsi_qla_host *ha); -irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); - -void qla4xxx_free_ddb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry); -void qla4xxx_process_aen(struct scsi_qla_host *ha, uint8_t process_aen); - -int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host *ha); -int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb); -int qla4xxx_reset_lun(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry, - int lun); -int qla4xxx_reset_target(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry); -int qla4xxx_get_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, - uint32_t offset, uint32_t len); -int qla4xxx_get_firmware_status(struct scsi_qla_host *ha); -int qla4xxx_get_firmware_state(struct scsi_qla_host *ha); -int qla4xxx_initialize_fw_cb(struct scsi_qla_host *ha); - -/* FIXME: Goodness! this really wants a small struct to hold the - * parameters. On x86 the args will get passed on the stack! */ -int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, - uint16_t fw_ddb_index, - struct dev_db_entry *fw_ddb_entry, - dma_addr_t fw_ddb_entry_dma, - uint32_t *num_valid_ddb_entries, - uint32_t *next_ddb_index, - uint32_t *fw_ddb_device_state, - uint32_t *conn_err_detail, - uint16_t *tcp_source_port_num, - uint16_t *connection_id); - -int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, - dma_addr_t fw_ddb_entry_dma, uint32_t *mbx_sts); -uint8_t qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, - uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma); -int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha, - uint16_t fw_ddb_index, - uint16_t connection_id, - uint16_t option); -int qla4xxx_disable_acb(struct scsi_qla_host *ha); -int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, - uint32_t *mbox_sts, dma_addr_t acb_dma); -int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t acb_dma, - uint32_t acb_type, uint32_t len); -int qla4xxx_get_ip_state(struct scsi_qla_host *ha, uint32_t acb_idx, - uint32_t ip_idx, uint32_t *sts); -void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session); -u16 rd_nvram_word(struct scsi_qla_host *ha, int offset); -u8 rd_nvram_byte(struct scsi_qla_host *ha, int offset); -void qla4xxx_get_crash_record(struct scsi_qla_host *ha); -int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host *ha); -int qla4xxx_about_firmware(struct scsi_qla_host *ha); -void qla4xxx_interrupt_service_routine(struct scsi_qla_host *ha, - uint32_t intr_status); -int qla4xxx_init_rings(struct scsi_qla_host *ha); -void qla4xxx_srb_compl(struct kref *ref); -struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, - uint32_t index); -int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - uint32_t state, uint32_t conn_error); -void qla4xxx_dump_buffer(void *b, uint32_t size); -int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod); -int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, - uint32_t offset, uint32_t length, uint32_t options); -int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, - uint8_t outCount, uint32_t *mbx_cmd, uint32_t *mbx_sts); -int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username, - char *password, int bidi, uint16_t *chap_index); - -void qla4xxx_queue_iocb(struct scsi_qla_host *ha); -void qla4xxx_complete_iocb(struct scsi_qla_host *ha); -int qla4xxx_get_sys_info(struct scsi_qla_host *ha); -int qla4xxx_iospace_config(struct scsi_qla_host *ha); -void qla4xxx_pci_config(struct scsi_qla_host *ha); -int qla4xxx_start_firmware(struct scsi_qla_host *ha); -irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id); -uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha); -uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha); -int qla4xxx_request_irqs(struct scsi_qla_host *ha); -void qla4xxx_free_irqs(struct scsi_qla_host *ha); -void qla4xxx_process_response_queue(struct scsi_qla_host *ha); -void qla4xxx_wake_dpc(struct scsi_qla_host *ha); -void qla4xxx_get_conn_event_log(struct scsi_qla_host *ha); -void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha); -void qla4xxx_dump_registers(struct scsi_qla_host *ha); -uint8_t qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, - uint32_t *mbox_cmd, - uint32_t *mbox_sts, - struct addr_ctrl_blk *init_fw_cb, - dma_addr_t init_fw_cb_dma); - -void qla4_8xxx_pci_config(struct scsi_qla_host *); -int qla4_8xxx_iospace_config(struct scsi_qla_host *ha); -int qla4_8xxx_load_risc(struct scsi_qla_host *); -irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id); -void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha); -void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha); - -int qla4_8xxx_crb_win_lock(struct scsi_qla_host *); -void qla4_8xxx_crb_win_unlock(struct scsi_qla_host *); -int qla4_8xxx_pci_get_crb_addr_2M(struct scsi_qla_host *, ulong *); -void qla4_8xxx_wr_32(struct scsi_qla_host *, ulong, u32); -int qla4_8xxx_rd_32(struct scsi_qla_host *, ulong); -int qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *, u64, void *, int); -int qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha, u64, void *, int); -int qla4_8xxx_isp_reset(struct scsi_qla_host *ha); -void qla4_8xxx_interrupt_service_routine(struct scsi_qla_host *ha, - uint32_t intr_status); -uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha); -uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha); -int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha); -void qla4_8xxx_watchdog(struct scsi_qla_host *ha); -int qla4_8xxx_stop_firmware(struct scsi_qla_host *ha); -int qla4_8xxx_get_flash_info(struct scsi_qla_host *ha); -void qla4_8xxx_enable_intrs(struct scsi_qla_host *ha); -void qla4_8xxx_disable_intrs(struct scsi_qla_host *ha); -int qla4_8xxx_enable_msix(struct scsi_qla_host *ha); -void qla4_8xxx_disable_msix(struct scsi_qla_host *ha); -irqreturn_t qla4_8xxx_msi_handler(int irq, void *dev_id); -irqreturn_t qla4_8xxx_default_intr_handler(int irq, void *dev_id); -irqreturn_t qla4_8xxx_msix_rsp_q(int irq, void *dev_id); -void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha); -void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha); -int qla4_8xxx_idc_lock(struct scsi_qla_host *ha); -void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha); -int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha); -void qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha); -void qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha); -void qla4_8xxx_set_drv_active(struct scsi_qla_host *ha); -int qla4xxx_conn_open(struct scsi_qla_host *ha, uint16_t fw_ddb_index); -int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, - struct iscsi_cls_conn *cls_conn, - uint32_t *mbx_sts); -int qla4xxx_session_logout_ddb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, int options); -int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - uint32_t *mbx_sts); -int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t fw_ddb_index); -int qla4xxx_send_passthru0(struct iscsi_task *task); -void qla4xxx_free_ddb_index(struct scsi_qla_host *ha); -int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index, - uint16_t stats_size, dma_addr_t stats_dma); -void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry); -void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry); -int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha, - struct dev_db_entry *fw_ddb_entry, - dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index); -int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, - char *password, uint16_t idx); -int qla4xxx_get_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, - uint32_t offset, uint32_t size); -int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, - uint32_t offset, uint32_t size); -int qla4xxx_restore_factory_defaults(struct scsi_qla_host *ha, - uint32_t region, uint32_t field0, - uint32_t field1); -int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index); -void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session); -int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session); -int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session); -int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - struct ddb_entry *ddb_entry, uint32_t state); -int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - struct ddb_entry *ddb_entry, uint32_t state); -void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset); -int qla4xxx_post_aen_work(struct scsi_qla_host *ha, uint32_t aen_code, - uint32_t data_size, uint8_t *data); -int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options, - uint32_t payload_size, uint32_t pid, uint8_t *ipaddr); -int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, - uint32_t status, uint32_t pid, - uint32_t data_size, uint8_t *data); - -/* BSG Functions */ -int qla4xxx_bsg_request(struct bsg_job *bsg_job); -int qla4xxx_process_vendor_specific(struct bsg_job *bsg_job); - -void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry); - -extern int ql4xextended_error_logging; -extern int ql4xdontresethba; -extern int ql4xenablemsix; - -extern struct device_attribute *qla4xxx_host_attrs[]; -#endif /* _QLA4x_GBL_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_init.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_init.c deleted file mode 100644 index 90ee5d8f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_init.c +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#include -#include "ql4_def.h" -#include "ql4_glbl.h" -#include "ql4_dbg.h" -#include "ql4_inline.h" - -static void ql4xxx_set_mac_number(struct scsi_qla_host *ha) -{ - uint32_t value; - uint8_t func_number; - unsigned long flags; - - /* Get the function number */ - spin_lock_irqsave(&ha->hardware_lock, flags); - value = readw(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - func_number = (uint8_t) ((value >> 4) & 0x30); - switch (value & ISP_CONTROL_FN_MASK) { - case ISP_CONTROL_FN0_SCSI: - ha->mac_index = 1; - break; - case ISP_CONTROL_FN1_SCSI: - ha->mac_index = 3; - break; - default: - DEBUG2(printk("scsi%ld: %s: Invalid function number, " - "ispControlStatus = 0x%x\n", ha->host_no, - __func__, value)); - break; - } - DEBUG2(printk("scsi%ld: %s: mac_index %d.\n", ha->host_no, __func__, - ha->mac_index)); -} - -/** - * qla4xxx_free_ddb - deallocate ddb - * @ha: pointer to host adapter structure. - * @ddb_entry: pointer to device database entry - * - * This routine marks a DDB entry INVALID - **/ -void qla4xxx_free_ddb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry) -{ - /* Remove device pointer from index mapping arrays */ - ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = - (struct ddb_entry *) INVALID_ENTRY; - ha->tot_ddbs--; -} - -/** - * qla4xxx_init_response_q_entries() - Initializes response queue entries. - * @ha: HA context - * - * Beginning of request ring has initialization control block already built - * by nvram config routine. - **/ -static void qla4xxx_init_response_q_entries(struct scsi_qla_host *ha) -{ - uint16_t cnt; - struct response *pkt; - - pkt = (struct response *)ha->response_ptr; - for (cnt = 0; cnt < RESPONSE_QUEUE_DEPTH; cnt++) { - pkt->signature = RESPONSE_PROCESSED; - pkt++; - } -} - -/** - * qla4xxx_init_rings - initialize hw queues - * @ha: pointer to host adapter structure. - * - * This routine initializes the internal queues for the specified adapter. - * The QLA4010 requires us to restart the queues at index 0. - * The QLA4000 doesn't care, so just default to QLA4010's requirement. - **/ -int qla4xxx_init_rings(struct scsi_qla_host *ha) -{ - unsigned long flags = 0; - int i; - - /* Initialize request queue. */ - spin_lock_irqsave(&ha->hardware_lock, flags); - ha->request_out = 0; - ha->request_in = 0; - ha->request_ptr = &ha->request_ring[ha->request_in]; - ha->req_q_count = REQUEST_QUEUE_DEPTH; - - /* Initialize response queue. */ - ha->response_in = 0; - ha->response_out = 0; - ha->response_ptr = &ha->response_ring[ha->response_out]; - - if (is_qla8022(ha)) { - writel(0, - (unsigned long __iomem *)&ha->qla4_8xxx_reg->req_q_out); - writel(0, - (unsigned long __iomem *)&ha->qla4_8xxx_reg->rsp_q_in); - writel(0, - (unsigned long __iomem *)&ha->qla4_8xxx_reg->rsp_q_out); - } else { - /* - * Initialize DMA Shadow registers. The firmware is really - * supposed to take care of this, but on some uniprocessor - * systems, the shadow registers aren't cleared-- causing - * the interrupt_handler to think there are responses to be - * processed when there aren't. - */ - ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0); - ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0); - wmb(); - - writel(0, &ha->reg->req_q_in); - writel(0, &ha->reg->rsp_q_out); - readl(&ha->reg->rsp_q_out); - } - - qla4xxx_init_response_q_entries(ha); - - /* Initialize mabilbox active array */ - for (i = 0; i < MAX_MRB; i++) - ha->active_mrb_array[i] = NULL; - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_SUCCESS; -} - -/** - * qla4xxx_get_sys_info - validate adapter MAC address(es) - * @ha: pointer to host adapter structure. - * - **/ -int qla4xxx_get_sys_info(struct scsi_qla_host *ha) -{ - struct flash_sys_info *sys_info; - dma_addr_t sys_info_dma; - int status = QLA_ERROR; - - sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info), - &sys_info_dma, GFP_KERNEL); - if (sys_info == NULL) { - DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", - ha->host_no, __func__)); - - goto exit_get_sys_info_no_free; - } - memset(sys_info, 0, sizeof(*sys_info)); - - /* Get flash sys info */ - if (qla4xxx_get_flash(ha, sys_info_dma, FLASH_OFFSET_SYS_INFO, - sizeof(*sys_info)) != QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO " - "failed\n", ha->host_no, __func__)); - - goto exit_get_sys_info; - } - - /* Save M.A.C. address & serial_number */ - memcpy(ha->my_mac, &sys_info->physAddr[0].address[0], - min(sizeof(ha->my_mac), - sizeof(sys_info->physAddr[0].address))); - memcpy(ha->serial_number, &sys_info->acSerialNumber, - min(sizeof(ha->serial_number), - sizeof(sys_info->acSerialNumber))); - - status = QLA_SUCCESS; - -exit_get_sys_info: - dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info, - sys_info_dma); - -exit_get_sys_info_no_free: - return status; -} - -/** - * qla4xxx_init_local_data - initialize adapter specific local data - * @ha: pointer to host adapter structure. - * - **/ -static int qla4xxx_init_local_data(struct scsi_qla_host *ha) -{ - /* Initialize aen queue */ - ha->aen_q_count = MAX_AEN_ENTRIES; - - return qla4xxx_get_firmware_status(ha); -} - -static uint8_t -qla4xxx_wait_for_ip_config(struct scsi_qla_host *ha) -{ - uint8_t ipv4_wait = 0; - uint8_t ipv6_wait = 0; - int8_t ip_address[IPv6_ADDR_LEN] = {0} ; - - /* If both IPv4 & IPv6 are enabled, possibly only one - * IP address may be acquired, so check to see if we - * need to wait for another */ - if (is_ipv4_enabled(ha) && is_ipv6_enabled(ha)) { - if (((ha->addl_fw_state & FW_ADDSTATE_DHCPv4_ENABLED) != 0) && - ((ha->addl_fw_state & - FW_ADDSTATE_DHCPv4_LEASE_ACQUIRED) == 0)) { - ipv4_wait = 1; - } - if (((ha->ip_config.ipv6_addl_options & - IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) != 0) && - ((ha->ip_config.ipv6_link_local_state == - IP_ADDRSTATE_ACQUIRING) || - (ha->ip_config.ipv6_addr0_state == - IP_ADDRSTATE_ACQUIRING) || - (ha->ip_config.ipv6_addr1_state == - IP_ADDRSTATE_ACQUIRING))) { - - ipv6_wait = 1; - - if ((ha->ip_config.ipv6_link_local_state == - IP_ADDRSTATE_PREFERRED) || - (ha->ip_config.ipv6_addr0_state == - IP_ADDRSTATE_PREFERRED) || - (ha->ip_config.ipv6_addr1_state == - IP_ADDRSTATE_PREFERRED)) { - DEBUG2(printk(KERN_INFO "scsi%ld: %s: " - "Preferred IP configured." - " Don't wait!\n", ha->host_no, - __func__)); - ipv6_wait = 0; - } - if (memcmp(&ha->ip_config.ipv6_default_router_addr, - ip_address, IPv6_ADDR_LEN) == 0) { - DEBUG2(printk(KERN_INFO "scsi%ld: %s: " - "No Router configured. " - "Don't wait!\n", ha->host_no, - __func__)); - ipv6_wait = 0; - } - if ((ha->ip_config.ipv6_default_router_state == - IPV6_RTRSTATE_MANUAL) && - (ha->ip_config.ipv6_link_local_state == - IP_ADDRSTATE_TENTATIVE) && - (memcmp(&ha->ip_config.ipv6_link_local_addr, - &ha->ip_config.ipv6_default_router_addr, 4) == - 0)) { - DEBUG2(printk("scsi%ld: %s: LinkLocal Router & " - "IP configured. Don't wait!\n", - ha->host_no, __func__)); - ipv6_wait = 0; - } - } - if (ipv4_wait || ipv6_wait) { - DEBUG2(printk("scsi%ld: %s: Wait for additional " - "IP(s) \"", ha->host_no, __func__)); - if (ipv4_wait) - DEBUG2(printk("IPv4 ")); - if (ha->ip_config.ipv6_link_local_state == - IP_ADDRSTATE_ACQUIRING) - DEBUG2(printk("IPv6LinkLocal ")); - if (ha->ip_config.ipv6_addr0_state == - IP_ADDRSTATE_ACQUIRING) - DEBUG2(printk("IPv6Addr0 ")); - if (ha->ip_config.ipv6_addr1_state == - IP_ADDRSTATE_ACQUIRING) - DEBUG2(printk("IPv6Addr1 ")); - DEBUG2(printk("\"\n")); - } - } - - return ipv4_wait|ipv6_wait; -} - -static int qla4xxx_fw_ready(struct scsi_qla_host *ha) -{ - uint32_t timeout_count; - int ready = 0; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Waiting for Firmware Ready..\n")); - for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0; - timeout_count--) { - if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) - qla4xxx_get_dhcp_ip_address(ha); - - /* Get firmware state. */ - if (qla4xxx_get_firmware_state(ha) != QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: unable to get firmware " - "state\n", ha->host_no, __func__)); - break; - } - - if (ha->firmware_state & FW_STATE_ERROR) { - DEBUG2(printk("scsi%ld: %s: an unrecoverable error has" - " occurred\n", ha->host_no, __func__)); - break; - - } - if (ha->firmware_state & FW_STATE_CONFIG_WAIT) { - /* - * The firmware has not yet been issued an Initialize - * Firmware command, so issue it now. - */ - if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) - break; - - /* Go back and test for ready state - no wait. */ - continue; - } - - if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { - DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" - "AUTOCONNECT in progress\n", - ha->host_no, __func__)); - } - - if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { - DEBUG2(printk(KERN_INFO "scsi%ld: %s: fwstate:" - " CONFIGURING IP\n", - ha->host_no, __func__)); - /* - * Check for link state after 15 secs and if link is - * still DOWN then, cable is unplugged. Ignore "DHCP - * in Progress/CONFIGURING IP" bit to check if firmware - * is in ready state or not after 15 secs. - * This is applicable for both 2.x & 3.x firmware - */ - if (timeout_count <= (ADAPTER_INIT_TOV - 15)) { - if (ha->addl_fw_state & FW_ADDSTATE_LINK_UP) { - DEBUG2(printk(KERN_INFO "scsi%ld: %s:" - " LINK UP (Cable plugged)\n", - ha->host_no, __func__)); - } else if (ha->firmware_state & - (FW_STATE_CONFIGURING_IP | - FW_STATE_READY)) { - DEBUG2(printk(KERN_INFO "scsi%ld: %s: " - "LINK DOWN (Cable unplugged)\n", - ha->host_no, __func__)); - ha->firmware_state = FW_STATE_READY; - } - } - } - - if (ha->firmware_state == FW_STATE_READY) { - /* If DHCP IP Addr is available, retrieve it now. */ - if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, - &ha->dpc_flags)) - qla4xxx_get_dhcp_ip_address(ha); - - if (!qla4xxx_wait_for_ip_config(ha) || - timeout_count == 1) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Firmware Ready..\n")); - /* The firmware is ready to process SCSI - commands. */ - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: %s: MEDIA TYPE" - " - %s\n", ha->host_no, - __func__, (ha->addl_fw_state & - FW_ADDSTATE_OPTICAL_MEDIA) - != 0 ? "OPTICAL" : "COPPER")); - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: %s: DHCPv4 STATE" - " Enabled %s\n", ha->host_no, - __func__, (ha->addl_fw_state & - FW_ADDSTATE_DHCPv4_ENABLED) != 0 ? - "YES" : "NO")); - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: %s: LINK %s\n", - ha->host_no, __func__, - (ha->addl_fw_state & - FW_ADDSTATE_LINK_UP) != 0 ? - "UP" : "DOWN")); - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: %s: iSNS Service " - "Started %s\n", - ha->host_no, __func__, - (ha->addl_fw_state & - FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ? - "YES" : "NO")); - - ready = 1; - break; - } - } - DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - " - "seconds expired= %d\n", ha->host_no, __func__, - ha->firmware_state, ha->addl_fw_state, - timeout_count)); - if (is_qla4032(ha) && - !(ha->addl_fw_state & FW_ADDSTATE_LINK_UP) && - (timeout_count < ADAPTER_INIT_TOV - 5)) { - break; - } - - msleep(1000); - } /* end of for */ - - if (timeout_count <= 0) - DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n", - ha->host_no, __func__)); - - if (ha->firmware_state & FW_STATE_CONFIGURING_IP) { - DEBUG2(printk("scsi%ld: %s: FW initialized, but is reporting " - "it's waiting to configure an IP address\n", - ha->host_no, __func__)); - ready = 1; - } else if (ha->firmware_state & FW_STATE_WAIT_AUTOCONNECT) { - DEBUG2(printk("scsi%ld: %s: FW initialized, but " - "auto-discovery still in process\n", - ha->host_no, __func__)); - ready = 1; - } - - return ready; -} - -/** - * qla4xxx_init_firmware - initializes the firmware. - * @ha: pointer to host adapter structure. - * - **/ -static int qla4xxx_init_firmware(struct scsi_qla_host *ha) -{ - int status = QLA_ERROR; - - if (is_aer_supported(ha) && - test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) - return status; - - /* For 82xx, stop firmware before initializing because if BIOS - * has previously initialized firmware, then driver's initialize - * firmware will fail. */ - if (is_qla8022(ha)) - qla4_8xxx_stop_firmware(ha); - - ql4_printk(KERN_INFO, ha, "Initializing firmware..\n"); - if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) { - DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware " - "control block\n", ha->host_no, __func__)); - return status; - } - if (!qla4xxx_fw_ready(ha)) - return status; - - return qla4xxx_get_firmware_status(ha); -} - -static void qla4xxx_set_model_info(struct scsi_qla_host *ha) -{ - uint16_t board_id_string[8]; - int i; - int size = sizeof(ha->nvram->isp4022.boardIdStr); - int offset = offsetof(struct eeprom_data, isp4022.boardIdStr) / 2; - - for (i = 0; i < (size / 2) ; i++) { - board_id_string[i] = rd_nvram_word(ha, offset); - offset += 1; - } - - memcpy(ha->model_name, board_id_string, size); -} - -static int qla4xxx_config_nvram(struct scsi_qla_host *ha) -{ - unsigned long flags; - union external_hw_config_reg extHwConfig; - - DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n", ha->host_no, - __func__)); - if (ql4xxx_lock_flash(ha) != QLA_SUCCESS) - return QLA_ERROR; - if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) { - ql4xxx_unlock_flash(ha); - return QLA_ERROR; - } - - /* Get EEPRom Parameters from NVRAM and validate */ - ql4_printk(KERN_INFO, ha, "Configuring NVRAM ...\n"); - if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) { - spin_lock_irqsave(&ha->hardware_lock, flags); - extHwConfig.Asuint32_t = - rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha)); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } else { - ql4_printk(KERN_WARNING, ha, - "scsi%ld: %s: EEProm checksum invalid. " - "Please update your EEPROM\n", ha->host_no, - __func__); - - /* Attempt to set defaults */ - if (is_qla4010(ha)) - extHwConfig.Asuint32_t = 0x1912; - else if (is_qla4022(ha) | is_qla4032(ha)) - extHwConfig.Asuint32_t = 0x0023; - else - return QLA_ERROR; - } - - if (is_qla4022(ha) || is_qla4032(ha)) - qla4xxx_set_model_info(ha); - else - strcpy(ha->model_name, "QLA4010"); - - DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n", - ha->host_no, __func__, extHwConfig.Asuint32_t)); - - spin_lock_irqsave(&ha->hardware_lock, flags); - writel((0xFFFF << 16) | extHwConfig.Asuint32_t, isp_ext_hw_conf(ha)); - readl(isp_ext_hw_conf(ha)); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - ql4xxx_unlock_nvram(ha); - ql4xxx_unlock_flash(ha); - - return QLA_SUCCESS; -} - -/** - * qla4_8xxx_pci_config() - Setup ISP82xx PCI configuration registers. - * @ha: HA context - */ -void qla4_8xxx_pci_config(struct scsi_qla_host *ha) -{ - pci_set_master(ha->pdev); -} - -void qla4xxx_pci_config(struct scsi_qla_host *ha) -{ - uint16_t w; - int status; - - ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n"); - - pci_set_master(ha->pdev); - status = pci_set_mwi(ha->pdev); - /* - * We want to respect framework's setting of PCI configuration space - * command register and also want to make sure that all bits of - * interest to us are properly set in command register. - */ - pci_read_config_word(ha->pdev, PCI_COMMAND, &w); - w |= PCI_COMMAND_PARITY | PCI_COMMAND_SERR; - w &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(ha->pdev, PCI_COMMAND, w); -} - -static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha) -{ - int status = QLA_ERROR; - unsigned long max_wait_time; - unsigned long flags; - uint32_t mbox_status; - - ql4_printk(KERN_INFO, ha, "Starting firmware ...\n"); - - /* - * Start firmware from flash ROM - * - * WORKAROUND: Stuff a non-constant value that the firmware can - * use as a seed for a random number generator in MB7 prior to - * setting BOOT_ENABLE. Fixes problem where the TCP - * connections use the same TCP ports after each reboot, - * causing some connections to not get re-established. - */ - DEBUG(printk("scsi%d: %s: Start firmware from flash ROM\n", - ha->host_no, __func__)); - - spin_lock_irqsave(&ha->hardware_lock, flags); - writel(jiffies, &ha->reg->mailbox[7]); - if (is_qla4022(ha) | is_qla4032(ha)) - writel(set_rmask(NVR_WRITE_ENABLE), - &ha->reg->u1.isp4022.nvram); - - writel(2, &ha->reg->mailbox[6]); - readl(&ha->reg->mailbox[6]); - - writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* Wait for firmware to come UP. */ - DEBUG2(printk(KERN_INFO "scsi%ld: %s: Wait up to %d seconds for " - "boot firmware to complete...\n", - ha->host_no, __func__, FIRMWARE_UP_TOV)); - max_wait_time = jiffies + (FIRMWARE_UP_TOV * HZ); - do { - uint32_t ctrl_status; - - spin_lock_irqsave(&ha->hardware_lock, flags); - ctrl_status = readw(&ha->reg->ctrl_status); - mbox_status = readw(&ha->reg->mailbox[0]); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (ctrl_status & set_rmask(CSR_SCSI_PROCESSOR_INTR)) - break; - if (mbox_status == MBOX_STS_COMMAND_COMPLETE) - break; - - DEBUG2(printk(KERN_INFO "scsi%ld: %s: Waiting for boot " - "firmware to complete... ctrl_sts=0x%x, remaining=%ld\n", - ha->host_no, __func__, ctrl_status, max_wait_time)); - - msleep_interruptible(250); - } while (!time_after_eq(jiffies, max_wait_time)); - - if (mbox_status == MBOX_STS_COMMAND_COMPLETE) { - DEBUG(printk(KERN_INFO "scsi%ld: %s: Firmware has started\n", - ha->host_no, __func__)); - - spin_lock_irqsave(&ha->hardware_lock, flags); - writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), - &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - status = QLA_SUCCESS; - } else { - printk(KERN_INFO "scsi%ld: %s: Boot firmware failed " - "- mbox status 0x%x\n", ha->host_no, __func__, - mbox_status); - status = QLA_ERROR; - } - return status; -} - -int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a) -{ -#define QL4_LOCK_DRVR_WAIT 60 -#define QL4_LOCK_DRVR_SLEEP 1 - - int drvr_wait = QL4_LOCK_DRVR_WAIT; - while (drvr_wait) { - if (ql4xxx_lock_drvr(a) == 0) { - ssleep(QL4_LOCK_DRVR_SLEEP); - if (drvr_wait) { - DEBUG2(printk("scsi%ld: %s: Waiting for " - "Global Init Semaphore(%d)...\n", - a->host_no, - __func__, drvr_wait)); - } - drvr_wait -= QL4_LOCK_DRVR_SLEEP; - } else { - DEBUG2(printk("scsi%ld: %s: Global Init Semaphore " - "acquired\n", a->host_no, __func__)); - return QLA_SUCCESS; - } - } - return QLA_ERROR; -} - -/** - * qla4xxx_start_firmware - starts qla4xxx firmware - * @ha: Pointer to host adapter structure. - * - * This routine performs the necessary steps to start the firmware for - * the QLA4010 adapter. - **/ -int qla4xxx_start_firmware(struct scsi_qla_host *ha) -{ - unsigned long flags = 0; - uint32_t mbox_status; - int status = QLA_ERROR; - int soft_reset = 1; - int config_chip = 0; - - if (is_qla4022(ha) | is_qla4032(ha)) - ql4xxx_set_mac_number(ha); - - if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) - return QLA_ERROR; - - spin_lock_irqsave(&ha->hardware_lock, flags); - - DEBUG2(printk("scsi%ld: %s: port_ctrl = 0x%08X\n", ha->host_no, - __func__, readw(isp_port_ctrl(ha)))); - DEBUG(printk("scsi%ld: %s: port_status = 0x%08X\n", ha->host_no, - __func__, readw(isp_port_status(ha)))); - - /* Is Hardware already initialized? */ - if ((readw(isp_port_ctrl(ha)) & 0x8000) != 0) { - DEBUG(printk("scsi%ld: %s: Hardware has already been " - "initialized\n", ha->host_no, __func__)); - - /* Receive firmware boot acknowledgement */ - mbox_status = readw(&ha->reg->mailbox[0]); - - DEBUG2(printk("scsi%ld: %s: H/W Config complete - mbox[0]= " - "0x%x\n", ha->host_no, __func__, mbox_status)); - - /* Is firmware already booted? */ - if (mbox_status == 0) { - /* F/W not running, must be config by net driver */ - config_chip = 1; - soft_reset = 0; - } else { - writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), - &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - writel(set_rmask(CSR_SCSI_COMPLETION_INTR), - &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: Get firmware " - "state -- state = 0x%x\n", - ha->host_no, - __func__, ha->firmware_state)); - /* F/W is running */ - if (ha->firmware_state & - FW_STATE_CONFIG_WAIT) { - DEBUG2(printk("scsi%ld: %s: Firmware " - "in known state -- " - "config and " - "boot, state = 0x%x\n", - ha->host_no, __func__, - ha->firmware_state)); - config_chip = 1; - soft_reset = 0; - } - } else { - DEBUG2(printk("scsi%ld: %s: Firmware in " - "unknown state -- resetting," - " state = " - "0x%x\n", ha->host_no, __func__, - ha->firmware_state)); - } - spin_lock_irqsave(&ha->hardware_lock, flags); - } - } else { - DEBUG(printk("scsi%ld: %s: H/W initialization hasn't been " - "started - resetting\n", ha->host_no, __func__)); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - DEBUG(printk("scsi%ld: %s: Flags soft_rest=%d, config= %d\n ", - ha->host_no, __func__, soft_reset, config_chip)); - if (soft_reset) { - DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no, - __func__)); - status = qla4xxx_soft_reset(ha); /* NOTE: acquires drvr - * lock again, but ok */ - if (status == QLA_ERROR) { - DEBUG(printk("scsi%d: %s: Soft Reset failed!\n", - ha->host_no, __func__)); - ql4xxx_unlock_drvr(ha); - return QLA_ERROR; - } - config_chip = 1; - - /* Reset clears the semaphore, so acquire again */ - if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) - return QLA_ERROR; - } - - if (config_chip) { - if ((status = qla4xxx_config_nvram(ha)) == QLA_SUCCESS) - status = qla4xxx_start_firmware_from_flash(ha); - } - - ql4xxx_unlock_drvr(ha); - if (status == QLA_SUCCESS) { - if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags)) - qla4xxx_get_crash_record(ha); - } else { - DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n", - ha->host_no, __func__)); - } - return status; -} -/** - * qla4xxx_free_ddb_index - Free DDBs reserved by firmware - * @ha: pointer to adapter structure - * - * Since firmware is not running in autoconnect mode the DDB indices should - * be freed so that when login happens from user space there are free DDB - * indices available. - **/ -void qla4xxx_free_ddb_index(struct scsi_qla_host *ha) -{ - int max_ddbs; - int ret; - uint32_t idx = 0, next_idx = 0; - uint32_t state = 0, conn_err = 0; - - max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : - MAX_DEV_DB_ENTRIES; - - for (idx = 0; idx < max_ddbs; idx = next_idx) { - ret = qla4xxx_get_fwddb_entry(ha, idx, NULL, 0, NULL, - &next_idx, &state, &conn_err, - NULL, NULL); - if (ret == QLA_ERROR) { - next_idx++; - continue; - } - if (state == DDB_DS_NO_CONNECTION_ACTIVE || - state == DDB_DS_SESSION_FAILED) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Freeing DDB index = 0x%x\n", idx)); - ret = qla4xxx_clear_ddb_entry(ha, idx); - if (ret == QLA_ERROR) - ql4_printk(KERN_ERR, ha, - "Unable to clear DDB index = " - "0x%x\n", idx); - } - if (next_idx == 0) - break; - } -} - -/** - * qla4xxx_initialize_adapter - initiailizes hba - * @ha: Pointer to host adapter structure. - * - * This routine parforms all of the steps necessary to initialize the adapter. - * - **/ -int qla4xxx_initialize_adapter(struct scsi_qla_host *ha, int is_reset) -{ - int status = QLA_ERROR; - - ha->eeprom_cmd_data = 0; - - ql4_printk(KERN_INFO, ha, "Configuring PCI space...\n"); - ha->isp_ops->pci_config(ha); - - ha->isp_ops->disable_intrs(ha); - - /* Initialize the Host adapter request/response queues and firmware */ - if (ha->isp_ops->start_firmware(ha) == QLA_ERROR) - goto exit_init_hba; - - if (qla4xxx_about_firmware(ha) == QLA_ERROR) - goto exit_init_hba; - - if (ha->isp_ops->get_sys_info(ha) == QLA_ERROR) - goto exit_init_hba; - - if (qla4xxx_init_local_data(ha) == QLA_ERROR) - goto exit_init_hba; - - status = qla4xxx_init_firmware(ha); - if (status == QLA_ERROR) - goto exit_init_hba; - - if (is_reset == RESET_ADAPTER) - qla4xxx_build_ddb_list(ha, is_reset); - - set_bit(AF_ONLINE, &ha->flags); -exit_init_hba: - if (is_qla8022(ha) && (status == QLA_ERROR)) { - /* Since interrupts are registered in start_firmware for - * 82xx, release them here if initialize_adapter fails */ - qla4xxx_free_irqs(ha); - } - - DEBUG2(printk("scsi%ld: initialize adapter: %s\n", ha->host_no, - status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); - return status; -} - -int qla4xxx_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - struct ddb_entry *ddb_entry, uint32_t state) -{ - uint32_t old_fw_ddb_device_state; - int status = QLA_ERROR; - - old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: DDB - old state = 0x%x, new state = 0x%x for " - "index [%d]\n", __func__, - ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); - - ddb_entry->fw_ddb_device_state = state; - - switch (old_fw_ddb_device_state) { - case DDB_DS_LOGIN_IN_PROCESS: - switch (state) { - case DDB_DS_SESSION_ACTIVE: - case DDB_DS_DISCOVERY: - ddb_entry->unblock_sess(ddb_entry->sess); - qla4xxx_update_session_conn_param(ha, ddb_entry); - status = QLA_SUCCESS; - break; - case DDB_DS_SESSION_FAILED: - case DDB_DS_NO_CONNECTION_ACTIVE: - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_FREE); - status = QLA_SUCCESS; - break; - } - break; - case DDB_DS_SESSION_ACTIVE: - switch (state) { - case DDB_DS_SESSION_FAILED: - /* - * iscsi_session failure will cause userspace to - * stop the connection which in turn would block the - * iscsi_session and start relogin - */ - iscsi_session_failure(ddb_entry->sess->dd_data, - ISCSI_ERR_CONN_FAILED); - status = QLA_SUCCESS; - break; - case DDB_DS_NO_CONNECTION_ACTIVE: - clear_bit(fw_ddb_index, ha->ddb_idx_map); - status = QLA_SUCCESS; - break; - } - break; - case DDB_DS_SESSION_FAILED: - switch (state) { - case DDB_DS_SESSION_ACTIVE: - case DDB_DS_DISCOVERY: - ddb_entry->unblock_sess(ddb_entry->sess); - qla4xxx_update_session_conn_param(ha, ddb_entry); - status = QLA_SUCCESS; - break; - case DDB_DS_SESSION_FAILED: - iscsi_session_failure(ddb_entry->sess->dd_data, - ISCSI_ERR_CONN_FAILED); - status = QLA_SUCCESS; - break; - } - break; - default: - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n", - __func__)); - break; - } - return status; -} - -void qla4xxx_arm_relogin_timer(struct ddb_entry *ddb_entry) -{ - /* - * This triggers a relogin. After the relogin_timer - * expires, the relogin gets scheduled. We must wait a - * minimum amount of time since receiving an 0x8014 AEN - * with failed device_state or a logout response before - * we can issue another relogin. - * - * Firmware pads this timeout: (time2wait +1). - * Driver retry to login should be longer than F/W. - * Otherwise F/W will fail - * set_ddb() mbx cmd with 0x4005 since it still - * counting down its time2wait. - */ - atomic_set(&ddb_entry->relogin_timer, 0); - atomic_set(&ddb_entry->retry_relogin_timer, - ddb_entry->default_time2wait + 4); - -} - -int qla4xxx_flash_ddb_change(struct scsi_qla_host *ha, uint32_t fw_ddb_index, - struct ddb_entry *ddb_entry, uint32_t state) -{ - uint32_t old_fw_ddb_device_state; - int status = QLA_ERROR; - - old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state; - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: DDB - old state = 0x%x, new state = 0x%x for " - "index [%d]\n", __func__, - ddb_entry->fw_ddb_device_state, state, fw_ddb_index)); - - ddb_entry->fw_ddb_device_state = state; - - switch (old_fw_ddb_device_state) { - case DDB_DS_LOGIN_IN_PROCESS: - case DDB_DS_NO_CONNECTION_ACTIVE: - switch (state) { - case DDB_DS_SESSION_ACTIVE: - ddb_entry->unblock_sess(ddb_entry->sess); - qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); - status = QLA_SUCCESS; - break; - case DDB_DS_SESSION_FAILED: - iscsi_block_session(ddb_entry->sess); - if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) - qla4xxx_arm_relogin_timer(ddb_entry); - status = QLA_SUCCESS; - break; - } - break; - case DDB_DS_SESSION_ACTIVE: - switch (state) { - case DDB_DS_SESSION_FAILED: - iscsi_block_session(ddb_entry->sess); - if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) - qla4xxx_arm_relogin_timer(ddb_entry); - status = QLA_SUCCESS; - break; - } - break; - case DDB_DS_SESSION_FAILED: - switch (state) { - case DDB_DS_SESSION_ACTIVE: - ddb_entry->unblock_sess(ddb_entry->sess); - qla4xxx_update_session_conn_fwddb_param(ha, ddb_entry); - status = QLA_SUCCESS; - break; - case DDB_DS_SESSION_FAILED: - if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) - qla4xxx_arm_relogin_timer(ddb_entry); - status = QLA_SUCCESS; - break; - } - break; - default: - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unknown Event\n", - __func__)); - break; - } - return status; -} - -/** - * qla4xxx_process_ddb_changed - process ddb state change - * @ha - Pointer to host adapter structure. - * @fw_ddb_index - Firmware's device database index - * @state - Device state - * - * This routine processes a Decive Database Changed AEN Event. - **/ -int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, - uint32_t fw_ddb_index, - uint32_t state, uint32_t conn_err) -{ - struct ddb_entry *ddb_entry; - int status = QLA_ERROR; - - /* check for out of range index */ - if (fw_ddb_index >= MAX_DDB_ENTRIES) - goto exit_ddb_event; - - /* Get the corresponging ddb entry */ - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); - /* Device does not currently exist in our database. */ - if (ddb_entry == NULL) { - ql4_printk(KERN_ERR, ha, "%s: No ddb_entry at FW index [%d]\n", - __func__, fw_ddb_index); - - if (state == DDB_DS_NO_CONNECTION_ACTIVE) - clear_bit(fw_ddb_index, ha->ddb_idx_map); - - goto exit_ddb_event; - } - - ddb_entry->ddb_change(ha, fw_ddb_index, ddb_entry, state); - -exit_ddb_event: - return status; -} - -/** - * qla4xxx_login_flash_ddb - Login to target (DDB) - * @cls_session: Pointer to the session to login - * - * This routine logins to the target. - * Issues setddb and conn open mbx - **/ -void qla4xxx_login_flash_ddb(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - struct dev_db_entry *fw_ddb_entry = NULL; - dma_addr_t fw_ddb_dma; - uint32_t mbx_sts = 0; - int ret; - - sess = cls_session->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - - if (!test_bit(AF_LINK_UP, &ha->flags)) - return; - - if (ddb_entry->ddb_type != FLASH_DDB) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Skipping login to non FLASH DB")); - goto exit_login; - } - - fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, - &fw_ddb_dma); - if (fw_ddb_entry == NULL) { - DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); - goto exit_login; - } - - if (ddb_entry->fw_ddb_index == INVALID_ENTRY) { - ret = qla4xxx_get_ddb_index(ha, &ddb_entry->fw_ddb_index); - if (ret == QLA_ERROR) - goto exit_login; - - ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; - ha->tot_ddbs++; - } - - memcpy(fw_ddb_entry, &ddb_entry->fw_ddb_entry, - sizeof(struct dev_db_entry)); - ddb_entry->sess->target_id = ddb_entry->fw_ddb_index; - - ret = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, - fw_ddb_dma, &mbx_sts); - if (ret == QLA_ERROR) { - DEBUG2(ql4_printk(KERN_ERR, ha, "Set DDB failed\n")); - goto exit_login; - } - - ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; - ret = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); - if (ret == QLA_ERROR) { - ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, - sess->targetname); - goto exit_login; - } - -exit_login: - if (fw_ddb_entry) - dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_inline.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_inline.h deleted file mode 100644 index 62f90bde..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_inline.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -/* - * - * qla4xxx_lookup_ddb_by_fw_index - * This routine locates a device handle given the firmware device - * database index. If device doesn't exist, returns NULL. - * - * Input: - * ha - Pointer to host adapter structure. - * fw_ddb_index - Firmware's device database index - * - * Returns: - * Pointer to the corresponding internal device database structure - */ -static inline struct ddb_entry * -qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index) -{ - struct ddb_entry *ddb_entry = NULL; - - if ((fw_ddb_index < MAX_DDB_ENTRIES) && - (ha->fw_ddb_index_map[fw_ddb_index] != - (struct ddb_entry *) INVALID_ENTRY)) { - ddb_entry = ha->fw_ddb_index_map[fw_ddb_index]; - } - - DEBUG3(printk("scsi%d: %s: ddb [%d], ddb_entry = %p\n", - ha->host_no, __func__, fw_ddb_index, ddb_entry)); - - return ddb_entry; -} - -static inline void -__qla4xxx_enable_intrs(struct scsi_qla_host *ha) -{ - if (is_qla4022(ha) | is_qla4032(ha)) { - writel(set_rmask(IMR_SCSI_INTR_ENABLE), - &ha->reg->u1.isp4022.intr_mask); - readl(&ha->reg->u1.isp4022.intr_mask); - } else { - writel(set_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - } - set_bit(AF_INTERRUPTS_ON, &ha->flags); -} - -static inline void -__qla4xxx_disable_intrs(struct scsi_qla_host *ha) -{ - if (is_qla4022(ha) | is_qla4032(ha)) { - writel(clr_rmask(IMR_SCSI_INTR_ENABLE), - &ha->reg->u1.isp4022.intr_mask); - readl(&ha->reg->u1.isp4022.intr_mask); - } else { - writel(clr_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - } - clear_bit(AF_INTERRUPTS_ON, &ha->flags); -} - -static inline void -qla4xxx_enable_intrs(struct scsi_qla_host *ha) -{ - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - __qla4xxx_enable_intrs(ha); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -static inline void -qla4xxx_disable_intrs(struct scsi_qla_host *ha) -{ - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - __qla4xxx_disable_intrs(ha); - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_iocb.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_iocb.c deleted file mode 100644 index 2a2022a6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_iocb.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#include "ql4_def.h" -#include "ql4_glbl.h" -#include "ql4_dbg.h" -#include "ql4_inline.h" - -#include - -static int -qla4xxx_space_in_req_ring(struct scsi_qla_host *ha, uint16_t req_cnt) -{ - uint16_t cnt; - - /* Calculate number of free request entries. */ - if ((req_cnt + 2) >= ha->req_q_count) { - cnt = (uint16_t) ha->isp_ops->rd_shdw_req_q_out(ha); - if (ha->request_in < cnt) - ha->req_q_count = cnt - ha->request_in; - else - ha->req_q_count = REQUEST_QUEUE_DEPTH - - (ha->request_in - cnt); - } - - /* Check if room for request in request ring. */ - if ((req_cnt + 2) < ha->req_q_count) - return 1; - else - return 0; -} - -static void qla4xxx_advance_req_ring_ptr(struct scsi_qla_host *ha) -{ - /* Advance request queue pointer */ - if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) { - ha->request_in = 0; - ha->request_ptr = ha->request_ring; - } else { - ha->request_in++; - ha->request_ptr++; - } -} - -/** - * qla4xxx_get_req_pkt - returns a valid entry in request queue. - * @ha: Pointer to host adapter structure. - * @queue_entry: Pointer to pointer to queue entry structure - * - * This routine performs the following tasks: - * - returns the current request_in pointer (if queue not full) - * - advances the request_in pointer - * - checks for queue full - **/ -static int qla4xxx_get_req_pkt(struct scsi_qla_host *ha, - struct queue_entry **queue_entry) -{ - uint16_t req_cnt = 1; - - if (qla4xxx_space_in_req_ring(ha, req_cnt)) { - *queue_entry = ha->request_ptr; - memset(*queue_entry, 0, sizeof(**queue_entry)); - - qla4xxx_advance_req_ring_ptr(ha); - ha->req_q_count -= req_cnt; - return QLA_SUCCESS; - } - - return QLA_ERROR; -} - -/** - * qla4xxx_send_marker_iocb - issues marker iocb to HBA - * @ha: Pointer to host adapter structure. - * @ddb_entry: Pointer to device database entry - * @lun: SCSI LUN - * @marker_type: marker identifier - * - * This routine issues a marker IOCB. - **/ -int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod) -{ - struct qla4_marker_entry *marker_entry; - unsigned long flags = 0; - uint8_t status = QLA_SUCCESS; - - /* Acquire hardware specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Get pointer to the queue entry for the marker */ - if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) != - QLA_SUCCESS) { - status = QLA_ERROR; - goto exit_send_marker; - } - - /* Put the marker in the request queue */ - marker_entry->hdr.entryType = ET_MARKER; - marker_entry->hdr.entryCount = 1; - marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); - marker_entry->modifier = cpu_to_le16(mrkr_mod); - int_to_scsilun(lun, &marker_entry->lun); - wmb(); - - /* Tell ISP it's got a new I/O request */ - ha->isp_ops->queue_iocb(ha); - -exit_send_marker: - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return status; -} - -static struct continuation_t1_entry * -qla4xxx_alloc_cont_entry(struct scsi_qla_host *ha) -{ - struct continuation_t1_entry *cont_entry; - - cont_entry = (struct continuation_t1_entry *)ha->request_ptr; - - qla4xxx_advance_req_ring_ptr(ha); - - /* Load packet defaults */ - cont_entry->hdr.entryType = ET_CONTINUE; - cont_entry->hdr.entryCount = 1; - cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in); - - return cont_entry; -} - -static uint16_t qla4xxx_calc_request_entries(uint16_t dsds) -{ - uint16_t iocbs; - - iocbs = 1; - if (dsds > COMMAND_SEG) { - iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG; - if ((dsds - COMMAND_SEG) % CONTINUE_SEG) - iocbs++; - } - return iocbs; -} - -static void qla4xxx_build_scsi_iocbs(struct srb *srb, - struct command_t3_entry *cmd_entry, - uint16_t tot_dsds) -{ - struct scsi_qla_host *ha; - uint16_t avail_dsds; - struct data_seg_a64 *cur_dsd; - struct scsi_cmnd *cmd; - struct scatterlist *sg; - int i; - - cmd = srb->cmd; - ha = srb->ha; - - if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - /* No data being transferred */ - cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0); - return; - } - - avail_dsds = COMMAND_SEG; - cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]); - - scsi_for_each_sg(cmd, sg, tot_dsds, i) { - dma_addr_t sle_dma; - - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - struct continuation_t1_entry *cont_entry; - - cont_entry = qla4xxx_alloc_cont_entry(ha); - cur_dsd = - (struct data_seg_a64 *) - &cont_entry->dataseg[0]; - avail_dsds = CONTINUE_SEG; - } - - sle_dma = sg_dma_address(sg); - cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma)); - cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma)); - cur_dsd->count = cpu_to_le32(sg_dma_len(sg)); - avail_dsds--; - - cur_dsd++; - } -} - -/** - * qla4_8xxx_queue_iocb - Tell ISP it's got new request(s) - * @ha: pointer to host adapter structure. - * - * This routine notifies the ISP that one or more new request - * queue entries have been placed on the request queue. - **/ -void qla4_8xxx_queue_iocb(struct scsi_qla_host *ha) -{ - uint32_t dbval = 0; - - dbval = 0x14 | (ha->func_num << 5); - dbval = dbval | (0 << 8) | (ha->request_in << 16); - - qla4_8xxx_wr_32(ha, ha->nx_db_wr_ptr, ha->request_in); -} - -/** - * qla4_8xxx_complete_iocb - Tell ISP we're done with response(s) - * @ha: pointer to host adapter structure. - * - * This routine notifies the ISP that one or more response/completion - * queue entries have been processed by the driver. - * This also clears the interrupt. - **/ -void qla4_8xxx_complete_iocb(struct scsi_qla_host *ha) -{ - writel(ha->response_out, &ha->qla4_8xxx_reg->rsp_q_out); - readl(&ha->qla4_8xxx_reg->rsp_q_out); -} - -/** - * qla4xxx_queue_iocb - Tell ISP it's got new request(s) - * @ha: pointer to host adapter structure. - * - * This routine is notifies the ISP that one or more new request - * queue entries have been placed on the request queue. - **/ -void qla4xxx_queue_iocb(struct scsi_qla_host *ha) -{ - writel(ha->request_in, &ha->reg->req_q_in); - readl(&ha->reg->req_q_in); -} - -/** - * qla4xxx_complete_iocb - Tell ISP we're done with response(s) - * @ha: pointer to host adapter structure. - * - * This routine is notifies the ISP that one or more response/completion - * queue entries have been processed by the driver. - * This also clears the interrupt. - **/ -void qla4xxx_complete_iocb(struct scsi_qla_host *ha) -{ - writel(ha->response_out, &ha->reg->rsp_q_out); - readl(&ha->reg->rsp_q_out); -} - -/** - * qla4xxx_send_command_to_isp - issues command to HBA - * @ha: pointer to host adapter structure. - * @srb: pointer to SCSI Request Block to be sent to ISP - * - * This routine is called by qla4xxx_queuecommand to build an ISP - * command and pass it to the ISP for execution. - **/ -int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb) -{ - struct scsi_cmnd *cmd = srb->cmd; - struct ddb_entry *ddb_entry; - struct command_t3_entry *cmd_entry; - int nseg; - uint16_t tot_dsds; - uint16_t req_cnt; - unsigned long flags; - uint32_t index; - char tag[2]; - - /* Get real lun and adapter */ - ddb_entry = srb->ddb; - - tot_dsds = 0; - - /* Acquire hardware specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); - - index = (uint32_t)cmd->request->tag; - - /* - * Check to see if adapter is online before placing request on - * request queue. If a reset occurs and a request is in the queue, - * the firmware will still attempt to process the request, retrieving - * garbage for pointers. - */ - if (!test_bit(AF_ONLINE, &ha->flags)) { - DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! " - "Do not issue command.\n", - ha->host_no, __func__)); - goto queuing_error; - } - - /* Calculate the number of request entries needed. */ - nseg = scsi_dma_map(cmd); - if (nseg < 0) - goto queuing_error; - tot_dsds = nseg; - - req_cnt = qla4xxx_calc_request_entries(tot_dsds); - if (!qla4xxx_space_in_req_ring(ha, req_cnt)) - goto queuing_error; - - /* total iocbs active */ - if ((ha->iocb_cnt + req_cnt) >= REQUEST_QUEUE_DEPTH) - goto queuing_error; - - /* Build command packet */ - cmd_entry = (struct command_t3_entry *) ha->request_ptr; - memset(cmd_entry, 0, sizeof(struct command_t3_entry)); - cmd_entry->hdr.entryType = ET_COMMAND; - cmd_entry->handle = cpu_to_le32(index); - cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index); - - int_to_scsilun(cmd->device->lun, &cmd_entry->lun); - cmd_entry->ttlByteCnt = cpu_to_le32(scsi_bufflen(cmd)); - memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len); - cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds); - cmd_entry->hdr.entryCount = req_cnt; - - /* Set data transfer direction control flags - * NOTE: Look at data_direction bits iff there is data to be - * transferred, as the data direction bit is sometimed filled - * in when there is no data to be transferred */ - cmd_entry->control_flags = CF_NO_DATA; - if (scsi_bufflen(cmd)) { - if (cmd->sc_data_direction == DMA_TO_DEVICE) - cmd_entry->control_flags = CF_WRITE; - else if (cmd->sc_data_direction == DMA_FROM_DEVICE) - cmd_entry->control_flags = CF_READ; - - ha->bytes_xfered += scsi_bufflen(cmd); - if (ha->bytes_xfered & ~0xFFFFF){ - ha->total_mbytes_xferred += ha->bytes_xfered >> 20; - ha->bytes_xfered &= 0xFFFFF; - } - } - - /* Set tagged queueing control flags */ - cmd_entry->control_flags |= CF_SIMPLE_TAG; - if (scsi_populate_tag_msg(cmd, tag)) - switch (tag[0]) { - case MSG_HEAD_TAG: - cmd_entry->control_flags |= CF_HEAD_TAG; - break; - case MSG_ORDERED_TAG: - cmd_entry->control_flags |= CF_ORDERED_TAG; - break; - } - - qla4xxx_advance_req_ring_ptr(ha); - qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds); - wmb(); - - srb->cmd->host_scribble = (unsigned char *)(unsigned long)index; - - /* update counters */ - srb->state = SRB_ACTIVE_STATE; - srb->flags |= SRB_DMA_VALID; - - /* Track IOCB used */ - ha->iocb_cnt += req_cnt; - srb->iocb_cnt = req_cnt; - ha->req_q_count -= req_cnt; - - ha->isp_ops->queue_iocb(ha); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_SUCCESS; - -queuing_error: - if (tot_dsds) - scsi_dma_unmap(cmd); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return QLA_ERROR; -} - -int qla4xxx_send_passthru0(struct iscsi_task *task) -{ - struct passthru0 *passthru_iocb; - struct iscsi_session *sess = task->conn->session; - struct ddb_entry *ddb_entry = sess->dd_data; - struct scsi_qla_host *ha = ddb_entry->ha; - struct ql4_task_data *task_data = task->dd_data; - uint16_t ctrl_flags = 0; - unsigned long flags; - int ret = QLA_ERROR; - - spin_lock_irqsave(&ha->hardware_lock, flags); - task_data->iocb_req_cnt = 1; - /* Put the IOCB on the request queue */ - if (!qla4xxx_space_in_req_ring(ha, task_data->iocb_req_cnt)) - goto queuing_error; - - passthru_iocb = (struct passthru0 *) ha->request_ptr; - - memset(passthru_iocb, 0, sizeof(struct passthru0)); - passthru_iocb->hdr.entryType = ET_PASSTHRU0; - passthru_iocb->hdr.systemDefined = SD_ISCSI_PDU; - passthru_iocb->hdr.entryCount = task_data->iocb_req_cnt; - passthru_iocb->handle = task->itt; - passthru_iocb->target = cpu_to_le16(ddb_entry->fw_ddb_index); - passthru_iocb->timeout = cpu_to_le16(PT_DEFAULT_TIMEOUT); - - /* Setup the out & in DSDs */ - if (task_data->req_len) { - memcpy((uint8_t *)task_data->req_buffer + - sizeof(struct iscsi_hdr), task->data, task->data_count); - ctrl_flags |= PT_FLAG_SEND_BUFFER; - passthru_iocb->out_dsd.base.addrLow = - cpu_to_le32(LSDW(task_data->req_dma)); - passthru_iocb->out_dsd.base.addrHigh = - cpu_to_le32(MSDW(task_data->req_dma)); - passthru_iocb->out_dsd.count = - cpu_to_le32(task->data_count + - sizeof(struct iscsi_hdr)); - } - if (task_data->resp_len) { - passthru_iocb->in_dsd.base.addrLow = - cpu_to_le32(LSDW(task_data->resp_dma)); - passthru_iocb->in_dsd.base.addrHigh = - cpu_to_le32(MSDW(task_data->resp_dma)); - passthru_iocb->in_dsd.count = - cpu_to_le32(task_data->resp_len); - } - - ctrl_flags |= (PT_FLAG_ISCSI_PDU | PT_FLAG_WAIT_4_RESPONSE); - passthru_iocb->control_flags = cpu_to_le16(ctrl_flags); - - /* Update the request pointer */ - qla4xxx_advance_req_ring_ptr(ha); - wmb(); - - /* Track IOCB used */ - ha->iocb_cnt += task_data->iocb_req_cnt; - ha->req_q_count -= task_data->iocb_req_cnt; - ha->isp_ops->queue_iocb(ha); - ret = QLA_SUCCESS; - -queuing_error: - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return ret; -} - -static struct mrb *qla4xxx_get_new_mrb(struct scsi_qla_host *ha) -{ - struct mrb *mrb; - - mrb = kzalloc(sizeof(*mrb), GFP_KERNEL); - if (!mrb) - return mrb; - - mrb->ha = ha; - return mrb; -} - -static int qla4xxx_send_mbox_iocb(struct scsi_qla_host *ha, struct mrb *mrb, - uint32_t *in_mbox) -{ - int rval = QLA_SUCCESS; - uint32_t i; - unsigned long flags; - uint32_t index = 0; - - /* Acquire hardware specific lock */ - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* Get pointer to the queue entry for the marker */ - rval = qla4xxx_get_req_pkt(ha, (struct queue_entry **) &(mrb->mbox)); - if (rval != QLA_SUCCESS) - goto exit_mbox_iocb; - - index = ha->mrb_index; - /* get valid mrb index*/ - for (i = 0; i < MAX_MRB; i++) { - index++; - if (index == MAX_MRB) - index = 1; - if (ha->active_mrb_array[index] == NULL) { - ha->mrb_index = index; - break; - } - } - - mrb->iocb_cnt = 1; - ha->active_mrb_array[index] = mrb; - mrb->mbox->handle = index; - mrb->mbox->hdr.entryType = ET_MBOX_CMD; - mrb->mbox->hdr.entryCount = mrb->iocb_cnt; - memcpy(mrb->mbox->in_mbox, in_mbox, 32); - mrb->mbox_cmd = in_mbox[0]; - wmb(); - - ha->isp_ops->queue_iocb(ha); -exit_mbox_iocb: - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return rval; -} - -int qla4xxx_ping_iocb(struct scsi_qla_host *ha, uint32_t options, - uint32_t payload_size, uint32_t pid, uint8_t *ipaddr) -{ - uint32_t in_mbox[8]; - struct mrb *mrb = NULL; - int rval = QLA_SUCCESS; - - memset(in_mbox, 0, sizeof(in_mbox)); - - mrb = qla4xxx_get_new_mrb(ha); - if (!mrb) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: fail to get new mrb\n", - __func__)); - rval = QLA_ERROR; - goto exit_ping; - } - - in_mbox[0] = MBOX_CMD_PING; - in_mbox[1] = options; - memcpy(&in_mbox[2], &ipaddr[0], 4); - memcpy(&in_mbox[3], &ipaddr[4], 4); - memcpy(&in_mbox[4], &ipaddr[8], 4); - memcpy(&in_mbox[5], &ipaddr[12], 4); - in_mbox[6] = payload_size; - - mrb->pid = pid; - rval = qla4xxx_send_mbox_iocb(ha, mrb, in_mbox); - - if (rval != QLA_SUCCESS) - goto exit_ping; - - return rval; -exit_ping: - kfree(mrb); - return rval; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_isr.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_isr.c deleted file mode 100644 index fc542a9b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_isr.c +++ /dev/null @@ -1,1253 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#include "ql4_def.h" -#include "ql4_glbl.h" -#include "ql4_dbg.h" -#include "ql4_inline.h" - -/** - * qla4xxx_copy_sense - copy sense data into cmd sense buffer - * @ha: Pointer to host adapter structure. - * @sts_entry: Pointer to status entry structure. - * @srb: Pointer to srb structure. - **/ -static void qla4xxx_copy_sense(struct scsi_qla_host *ha, - struct status_entry *sts_entry, - struct srb *srb) -{ - struct scsi_cmnd *cmd = srb->cmd; - uint16_t sense_len; - - memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - sense_len = le16_to_cpu(sts_entry->senseDataByteCnt); - if (sense_len == 0) { - DEBUG2(ql4_printk(KERN_INFO, ha, "scsi%ld:%d:%d:%d: %s:" - " sense len 0\n", ha->host_no, - cmd->device->channel, cmd->device->id, - cmd->device->lun, __func__)); - ha->status_srb = NULL; - return; - } - /* Save total available sense length, - * not to exceed cmd's sense buffer size */ - sense_len = min_t(uint16_t, sense_len, SCSI_SENSE_BUFFERSIZE); - srb->req_sense_ptr = cmd->sense_buffer; - srb->req_sense_len = sense_len; - - /* Copy sense from sts_entry pkt */ - sense_len = min_t(uint16_t, sense_len, IOCB_MAX_SENSEDATA_LEN); - memcpy(cmd->sense_buffer, sts_entry->senseData, sense_len); - - DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: %s: sense key = %x, " - "ASL= %02x, ASC/ASCQ = %02x/%02x\n", ha->host_no, - cmd->device->channel, cmd->device->id, - cmd->device->lun, __func__, - sts_entry->senseData[2] & 0x0f, - sts_entry->senseData[7], - sts_entry->senseData[12], - sts_entry->senseData[13])); - - DEBUG5(qla4xxx_dump_buffer(cmd->sense_buffer, sense_len)); - srb->flags |= SRB_GOT_SENSE; - - /* Update srb, in case a sts_cont pkt follows */ - srb->req_sense_ptr += sense_len; - srb->req_sense_len -= sense_len; - if (srb->req_sense_len != 0) - ha->status_srb = srb; - else - ha->status_srb = NULL; -} - -/** - * qla4xxx_status_cont_entry - Process a Status Continuations entry. - * @ha: SCSI driver HA context - * @sts_cont: Entry pointer - * - * Extended sense data. - */ -static void -qla4xxx_status_cont_entry(struct scsi_qla_host *ha, - struct status_cont_entry *sts_cont) -{ - struct srb *srb = ha->status_srb; - struct scsi_cmnd *cmd; - uint16_t sense_len; - - if (srb == NULL) - return; - - cmd = srb->cmd; - if (cmd == NULL) { - DEBUG2(printk(KERN_INFO "scsi%ld: %s: Cmd already returned " - "back to OS srb=%p srb->state:%d\n", ha->host_no, - __func__, srb, srb->state)); - ha->status_srb = NULL; - return; - } - - /* Copy sense data. */ - sense_len = min_t(uint16_t, srb->req_sense_len, - IOCB_MAX_EXT_SENSEDATA_LEN); - memcpy(srb->req_sense_ptr, sts_cont->ext_sense_data, sense_len); - DEBUG5(qla4xxx_dump_buffer(srb->req_sense_ptr, sense_len)); - - srb->req_sense_ptr += sense_len; - srb->req_sense_len -= sense_len; - - /* Place command on done queue. */ - if (srb->req_sense_len == 0) { - kref_put(&srb->srb_ref, qla4xxx_srb_compl); - ha->status_srb = NULL; - } -} - -/** - * qla4xxx_status_entry - processes status IOCBs - * @ha: Pointer to host adapter structure. - * @sts_entry: Pointer to status entry structure. - **/ -static void qla4xxx_status_entry(struct scsi_qla_host *ha, - struct status_entry *sts_entry) -{ - uint8_t scsi_status; - struct scsi_cmnd *cmd; - struct srb *srb; - struct ddb_entry *ddb_entry; - uint32_t residual; - - srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle)); - if (!srb) { - ql4_printk(KERN_WARNING, ha, "%s invalid status entry: " - "handle=0x%0x, srb=%p\n", __func__, - sts_entry->handle, srb); - if (is_qla8022(ha)) - set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); - else - set_bit(DPC_RESET_HA, &ha->dpc_flags); - return; - } - - cmd = srb->cmd; - if (cmd == NULL) { - DEBUG2(printk("scsi%ld: %s: Command already returned back to " - "OS pkt->handle=%d srb=%p srb->state:%d\n", - ha->host_no, __func__, sts_entry->handle, - srb, srb->state)); - ql4_printk(KERN_WARNING, ha, "Command is NULL:" - " already returned to OS (srb=%p)\n", srb); - return; - } - - ddb_entry = srb->ddb; - if (ddb_entry == NULL) { - cmd->result = DID_NO_CONNECT << 16; - goto status_entry_exit; - } - - residual = le32_to_cpu(sts_entry->residualByteCnt); - - /* Translate ISP error to a Linux SCSI error. */ - scsi_status = sts_entry->scsiStatus; - switch (sts_entry->completionStatus) { - case SCS_COMPLETE: - - if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) { - cmd->result = DID_ERROR << 16; - break; - } - - if (sts_entry->iscsiFlags &ISCSI_FLAG_RESIDUAL_UNDER) { - scsi_set_resid(cmd, residual); - if (!scsi_status && ((scsi_bufflen(cmd) - residual) < - cmd->underflow)) { - - cmd->result = DID_ERROR << 16; - - DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " - "Mid-layer Data underrun0, " - "xferlen = 0x%x, " - "residual = 0x%x\n", ha->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, __func__, - scsi_bufflen(cmd), residual)); - break; - } - } - - cmd->result = DID_OK << 16 | scsi_status; - - if (scsi_status != SCSI_CHECK_CONDITION) - break; - - /* Copy Sense Data into sense buffer. */ - qla4xxx_copy_sense(ha, sts_entry, srb); - break; - - case SCS_INCOMPLETE: - /* Always set the status to DID_ERROR, since - * all conditions result in that status anyway */ - cmd->result = DID_ERROR << 16; - break; - - case SCS_RESET_OCCURRED: - DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Device RESET occurred\n", - ha->host_no, cmd->device->channel, - cmd->device->id, cmd->device->lun, __func__)); - - cmd->result = DID_RESET << 16; - break; - - case SCS_ABORTED: - DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Abort occurred\n", - ha->host_no, cmd->device->channel, - cmd->device->id, cmd->device->lun, __func__)); - - cmd->result = DID_RESET << 16; - break; - - case SCS_TIMEOUT: - DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: Timeout\n", - ha->host_no, cmd->device->channel, - cmd->device->id, cmd->device->lun)); - - cmd->result = DID_TRANSPORT_DISRUPTED << 16; - - /* - * Mark device missing so that we won't continue to send - * I/O to this device. We should get a ddb state change - * AEN soon. - */ - if (iscsi_is_session_online(ddb_entry->sess)) - qla4xxx_mark_device_missing(ddb_entry->sess); - break; - - case SCS_DATA_UNDERRUN: - case SCS_DATA_OVERRUN: - if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) || - (sts_entry->completionStatus == SCS_DATA_OVERRUN)) { - DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun\n", - ha->host_no, - cmd->device->channel, cmd->device->id, - cmd->device->lun, __func__)); - - cmd->result = DID_ERROR << 16; - break; - } - - scsi_set_resid(cmd, residual); - - /* - * If there is scsi_status, it takes precedense over - * underflow condition. - */ - if (scsi_status != 0) { - cmd->result = DID_OK << 16 | scsi_status; - - if (scsi_status != SCSI_CHECK_CONDITION) - break; - - /* Copy Sense Data into sense buffer. */ - qla4xxx_copy_sense(ha, sts_entry, srb); - } else { - /* - * If RISC reports underrun and target does not - * report it then we must have a lost frame, so - * tell upper layer to retry it by reporting a - * bus busy. - */ - if ((sts_entry->iscsiFlags & - ISCSI_FLAG_RESIDUAL_UNDER) == 0) { - cmd->result = DID_BUS_BUSY << 16; - } else if ((scsi_bufflen(cmd) - residual) < - cmd->underflow) { - /* - * Handle mid-layer underflow??? - * - * For kernels less than 2.4, the driver must - * return an error if an underflow is detected. - * For kernels equal-to and above 2.4, the - * mid-layer will appearantly handle the - * underflow by detecting the residual count -- - * unfortunately, we do not see where this is - * actually being done. In the interim, we - * will return DID_ERROR. - */ - DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " - "Mid-layer Data underrun1, " - "xferlen = 0x%x, " - "residual = 0x%x\n", ha->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, __func__, - scsi_bufflen(cmd), residual)); - - cmd->result = DID_ERROR << 16; - } else { - cmd->result = DID_OK << 16; - } - } - break; - - case SCS_DEVICE_LOGGED_OUT: - case SCS_DEVICE_UNAVAILABLE: - DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: SCS_DEVICE " - "state: 0x%x\n", ha->host_no, - cmd->device->channel, cmd->device->id, - cmd->device->lun, sts_entry->completionStatus)); - /* - * Mark device missing so that we won't continue to - * send I/O to this device. We should get a ddb - * state change AEN soon. - */ - if (iscsi_is_session_online(ddb_entry->sess)) - qla4xxx_mark_device_missing(ddb_entry->sess); - - cmd->result = DID_TRANSPORT_DISRUPTED << 16; - break; - - case SCS_QUEUE_FULL: - /* - * SCSI Mid-Layer handles device queue full - */ - cmd->result = DID_OK << 16 | sts_entry->scsiStatus; - DEBUG2(printk("scsi%ld:%d:%d: %s: QUEUE FULL detected " - "compl=%02x, scsi=%02x, state=%02x, iFlags=%02x," - " iResp=%02x\n", ha->host_no, cmd->device->id, - cmd->device->lun, __func__, - sts_entry->completionStatus, - sts_entry->scsiStatus, sts_entry->state_flags, - sts_entry->iscsiFlags, - sts_entry->iscsiResponse)); - break; - - default: - cmd->result = DID_ERROR << 16; - break; - } - -status_entry_exit: - - /* complete the request, if not waiting for status_continuation pkt */ - srb->cc_stat = sts_entry->completionStatus; - if (ha->status_srb == NULL) - kref_put(&srb->srb_ref, qla4xxx_srb_compl); -} - -/** - * qla4xxx_passthru_status_entry - processes passthru status IOCBs (0x3C) - * @ha: Pointer to host adapter structure. - * @sts_entry: Pointer to status entry structure. - **/ -static void qla4xxx_passthru_status_entry(struct scsi_qla_host *ha, - struct passthru_status *sts_entry) -{ - struct iscsi_task *task; - struct ddb_entry *ddb_entry; - struct ql4_task_data *task_data; - struct iscsi_cls_conn *cls_conn; - struct iscsi_conn *conn; - itt_t itt; - uint32_t fw_ddb_index; - - itt = sts_entry->handle; - fw_ddb_index = le32_to_cpu(sts_entry->target); - - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index); - - if (ddb_entry == NULL) { - ql4_printk(KERN_ERR, ha, "%s: Invalid target index = 0x%x\n", - __func__, sts_entry->target); - return; - } - - cls_conn = ddb_entry->conn; - conn = cls_conn->dd_data; - spin_lock(&conn->session->lock); - task = iscsi_itt_to_task(conn, itt); - spin_unlock(&conn->session->lock); - - if (task == NULL) { - ql4_printk(KERN_ERR, ha, "%s: Task is NULL\n", __func__); - return; - } - - task_data = task->dd_data; - memcpy(&task_data->sts, sts_entry, sizeof(struct passthru_status)); - ha->req_q_count += task_data->iocb_req_cnt; - ha->iocb_cnt -= task_data->iocb_req_cnt; - queue_work(ha->task_wq, &task_data->task_work); -} - -static struct mrb *qla4xxx_del_mrb_from_active_array(struct scsi_qla_host *ha, - uint32_t index) -{ - struct mrb *mrb = NULL; - - /* validate handle and remove from active array */ - if (index >= MAX_MRB) - return mrb; - - mrb = ha->active_mrb_array[index]; - ha->active_mrb_array[index] = NULL; - if (!mrb) - return mrb; - - /* update counters */ - ha->req_q_count += mrb->iocb_cnt; - ha->iocb_cnt -= mrb->iocb_cnt; - - return mrb; -} - -static void qla4xxx_mbox_status_entry(struct scsi_qla_host *ha, - struct mbox_status_iocb *mbox_sts_entry) -{ - struct mrb *mrb; - uint32_t status; - uint32_t data_size; - - mrb = qla4xxx_del_mrb_from_active_array(ha, - le32_to_cpu(mbox_sts_entry->handle)); - - if (mrb == NULL) { - ql4_printk(KERN_WARNING, ha, "%s: mrb[%d] is null\n", __func__, - mbox_sts_entry->handle); - return; - } - - switch (mrb->mbox_cmd) { - case MBOX_CMD_PING: - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: mbox_cmd = 0x%x, " - "mbox_sts[0] = 0x%x, mbox_sts[6] = 0x%x\n", - __func__, mrb->mbox_cmd, - mbox_sts_entry->out_mbox[0], - mbox_sts_entry->out_mbox[6])); - - if (mbox_sts_entry->out_mbox[0] == MBOX_STS_COMMAND_COMPLETE) - status = ISCSI_PING_SUCCESS; - else - status = mbox_sts_entry->out_mbox[6]; - - data_size = sizeof(mbox_sts_entry->out_mbox); - - qla4xxx_post_ping_evt_work(ha, status, mrb->pid, data_size, - (uint8_t *) mbox_sts_entry->out_mbox); - break; - - default: - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: invalid mbox_cmd = " - "0x%x\n", __func__, mrb->mbox_cmd)); - } - - kfree(mrb); - return; -} - -/** - * qla4xxx_process_response_queue - process response queue completions - * @ha: Pointer to host adapter structure. - * - * This routine process response queue completions in interrupt context. - * Hardware_lock locked upon entry - **/ -void qla4xxx_process_response_queue(struct scsi_qla_host *ha) -{ - uint32_t count = 0; - struct srb *srb = NULL; - struct status_entry *sts_entry; - - /* Process all responses from response queue */ - while ((ha->response_ptr->signature != RESPONSE_PROCESSED)) { - sts_entry = (struct status_entry *) ha->response_ptr; - count++; - - /* Advance pointers for next entry */ - if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) { - ha->response_out = 0; - ha->response_ptr = ha->response_ring; - } else { - ha->response_out++; - ha->response_ptr++; - } - - /* process entry */ - switch (sts_entry->hdr.entryType) { - case ET_STATUS: - /* Common status */ - qla4xxx_status_entry(ha, sts_entry); - break; - - case ET_PASSTHRU_STATUS: - if (sts_entry->hdr.systemDefined == SD_ISCSI_PDU) - qla4xxx_passthru_status_entry(ha, - (struct passthru_status *)sts_entry); - else - ql4_printk(KERN_ERR, ha, - "%s: Invalid status received\n", - __func__); - - break; - - case ET_STATUS_CONTINUATION: - qla4xxx_status_cont_entry(ha, - (struct status_cont_entry *) sts_entry); - break; - - case ET_COMMAND: - /* ISP device queue is full. Command not - * accepted by ISP. Queue command for - * later */ - - srb = qla4xxx_del_from_active_array(ha, - le32_to_cpu(sts_entry-> - handle)); - if (srb == NULL) - goto exit_prq_invalid_handle; - - DEBUG2(printk("scsi%ld: %s: FW device queue full, " - "srb %p\n", ha->host_no, __func__, srb)); - - /* ETRY normally by sending it back with - * DID_BUS_BUSY */ - srb->cmd->result = DID_BUS_BUSY << 16; - kref_put(&srb->srb_ref, qla4xxx_srb_compl); - break; - - case ET_CONTINUE: - /* Just throw away the continuation entries */ - DEBUG2(printk("scsi%ld: %s: Continuation entry - " - "ignoring\n", ha->host_no, __func__)); - break; - - case ET_MBOX_STATUS: - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: mbox status IOCB\n", __func__)); - qla4xxx_mbox_status_entry(ha, - (struct mbox_status_iocb *)sts_entry); - break; - - default: - /* - * Invalid entry in response queue, reset RISC - * firmware. - */ - DEBUG2(printk("scsi%ld: %s: Invalid entry %x in " - "response queue \n", ha->host_no, - __func__, - sts_entry->hdr.entryType)); - goto exit_prq_error; - } - ((struct response *)sts_entry)->signature = RESPONSE_PROCESSED; - wmb(); - } - - /* - * Tell ISP we're done with response(s). This also clears the interrupt. - */ - ha->isp_ops->complete_iocb(ha); - - return; - -exit_prq_invalid_handle: - DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n", - ha->host_no, __func__, srb, sts_entry->hdr.entryType, - sts_entry->completionStatus)); - -exit_prq_error: - ha->isp_ops->complete_iocb(ha); - set_bit(DPC_RESET_HA, &ha->dpc_flags); -} - -/** - * qla4xxx_isr_decode_mailbox - decodes mailbox status - * @ha: Pointer to host adapter structure. - * @mailbox_status: Mailbox status. - * - * This routine decodes the mailbox status during the ISR. - * Hardware_lock locked upon entry. runs in interrupt context. - **/ -static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha, - uint32_t mbox_status) -{ - int i; - uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; - - if ((mbox_status == MBOX_STS_BUSY) || - (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) || - (mbox_status >> 12 == MBOX_COMPLETION_STATUS)) { - ha->mbox_status[0] = mbox_status; - - if (test_bit(AF_MBOX_COMMAND, &ha->flags)) { - /* - * Copy all mailbox registers to a temporary - * location and set mailbox command done flag - */ - for (i = 0; i < ha->mbox_status_count; i++) - ha->mbox_status[i] = is_qla8022(ha) - ? readl(&ha->qla4_8xxx_reg->mailbox_out[i]) - : readl(&ha->reg->mailbox[i]); - - set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); - - if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags)) - complete(&ha->mbx_intr_comp); - } - } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) { - for (i = 0; i < MBOX_AEN_REG_COUNT; i++) - mbox_sts[i] = is_qla8022(ha) - ? readl(&ha->qla4_8xxx_reg->mailbox_out[i]) - : readl(&ha->reg->mailbox[i]); - - /* Immediately process the AENs that don't require much work. - * Only queue the database_changed AENs */ - if (ha->aen_log.count < MAX_AEN_ENTRIES) { - for (i = 0; i < MBOX_AEN_REG_COUNT; i++) - ha->aen_log.entry[ha->aen_log.count].mbox_sts[i] = - mbox_sts[i]; - ha->aen_log.count++; - } - switch (mbox_status) { - case MBOX_ASTS_SYSTEM_ERROR: - /* Log Mailbox registers */ - ql4_printk(KERN_INFO, ha, "%s: System Err\n", __func__); - qla4xxx_dump_registers(ha); - - if (ql4xdontresethba) { - DEBUG2(printk("scsi%ld: %s:Don't Reset HBA\n", - ha->host_no, __func__)); - } else { - set_bit(AF_GET_CRASH_RECORD, &ha->flags); - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } - break; - - case MBOX_ASTS_REQUEST_TRANSFER_ERROR: - case MBOX_ASTS_RESPONSE_TRANSFER_ERROR: - case MBOX_ASTS_NVRAM_INVALID: - case MBOX_ASTS_IP_ADDRESS_CHANGED: - case MBOX_ASTS_DHCP_LEASE_EXPIRED: - DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, " - "Reset HA\n", ha->host_no, mbox_status)); - if (is_qla8022(ha)) - set_bit(DPC_RESET_HA_FW_CONTEXT, - &ha->dpc_flags); - else - set_bit(DPC_RESET_HA, &ha->dpc_flags); - break; - - case MBOX_ASTS_LINK_UP: - set_bit(AF_LINK_UP, &ha->flags); - if (test_bit(AF_INIT_DONE, &ha->flags)) - set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); - - ql4_printk(KERN_INFO, ha, "%s: LINK UP\n", __func__); - qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKUP, - sizeof(mbox_sts), - (uint8_t *) mbox_sts); - break; - - case MBOX_ASTS_LINK_DOWN: - clear_bit(AF_LINK_UP, &ha->flags); - if (test_bit(AF_INIT_DONE, &ha->flags)) - set_bit(DPC_LINK_CHANGED, &ha->dpc_flags); - - ql4_printk(KERN_INFO, ha, "%s: LINK DOWN\n", __func__); - qla4xxx_post_aen_work(ha, ISCSI_EVENT_LINKDOWN, - sizeof(mbox_sts), - (uint8_t *) mbox_sts); - break; - - case MBOX_ASTS_HEARTBEAT: - ha->seconds_since_last_heartbeat = 0; - break; - - case MBOX_ASTS_DHCP_LEASE_ACQUIRED: - DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE " - "ACQUIRED\n", ha->host_no, mbox_status)); - set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); - break; - - case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM: - case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target - * mode - * only */ - case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED: /* Connection mode */ - case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR: - case MBOX_ASTS_SUBNET_STATE_CHANGE: - case MBOX_ASTS_DUPLICATE_IP: - /* No action */ - DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no, - mbox_status)); - break; - - case MBOX_ASTS_IP_ADDR_STATE_CHANGED: - printk("scsi%ld: AEN %04x, mbox_sts[2]=%04x, " - "mbox_sts[3]=%04x\n", ha->host_no, mbox_sts[0], - mbox_sts[2], mbox_sts[3]); - - /* mbox_sts[2] = Old ACB state - * mbox_sts[3] = new ACB state */ - if ((mbox_sts[3] == ACB_STATE_VALID) && - ((mbox_sts[2] == ACB_STATE_TENTATIVE) || - (mbox_sts[2] == ACB_STATE_ACQUIRING))) - set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags); - else if ((mbox_sts[3] == ACB_STATE_ACQUIRING) && - (mbox_sts[2] == ACB_STATE_VALID)) { - if (is_qla8022(ha)) - set_bit(DPC_RESET_HA_FW_CONTEXT, - &ha->dpc_flags); - else - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } else if ((mbox_sts[3] == ACB_STATE_UNCONFIGURED)) - complete(&ha->disable_acb_comp); - break; - - case MBOX_ASTS_MAC_ADDRESS_CHANGED: - case MBOX_ASTS_DNS: - /* No action */ - DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, " - "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n", - ha->host_no, mbox_sts[0], - mbox_sts[1], mbox_sts[2])); - break; - - case MBOX_ASTS_SELF_TEST_FAILED: - case MBOX_ASTS_LOGIN_FAILED: - /* No action */ - DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, " - "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n", - ha->host_no, mbox_sts[0], mbox_sts[1], - mbox_sts[2], mbox_sts[3])); - break; - - case MBOX_ASTS_DATABASE_CHANGED: - /* Queue AEN information and process it in the DPC - * routine */ - if (ha->aen_q_count > 0) { - - /* decrement available counter */ - ha->aen_q_count--; - - for (i = 0; i < MBOX_AEN_REG_COUNT; i++) - ha->aen_q[ha->aen_in].mbox_sts[i] = - mbox_sts[i]; - - /* print debug message */ - DEBUG2(printk("scsi%ld: AEN[%d] %04x queued " - "mb1:0x%x mb2:0x%x mb3:0x%x " - "mb4:0x%x mb5:0x%x\n", - ha->host_no, ha->aen_in, - mbox_sts[0], mbox_sts[1], - mbox_sts[2], mbox_sts[3], - mbox_sts[4], mbox_sts[5])); - - /* advance pointer */ - ha->aen_in++; - if (ha->aen_in == MAX_AEN_ENTRIES) - ha->aen_in = 0; - - /* The DPC routine will process the aen */ - set_bit(DPC_AEN, &ha->dpc_flags); - } else { - DEBUG2(printk("scsi%ld: %s: aen %04x, queue " - "overflowed! AEN LOST!!\n", - ha->host_no, __func__, - mbox_sts[0])); - - DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n", - ha->host_no)); - - for (i = 0; i < MAX_AEN_ENTRIES; i++) { - DEBUG2(printk("AEN[%d] %04x %04x %04x " - "%04x\n", i, mbox_sts[0], - mbox_sts[1], mbox_sts[2], - mbox_sts[3])); - } - } - break; - - case MBOX_ASTS_TXSCVR_INSERTED: - DEBUG2(printk(KERN_WARNING - "scsi%ld: AEN %04x Transceiver" - " inserted\n", ha->host_no, mbox_sts[0])); - break; - - case MBOX_ASTS_TXSCVR_REMOVED: - DEBUG2(printk(KERN_WARNING - "scsi%ld: AEN %04x Transceiver" - " removed\n", ha->host_no, mbox_sts[0])); - break; - - default: - DEBUG2(printk(KERN_WARNING - "scsi%ld: AEN %04x UNKNOWN\n", - ha->host_no, mbox_sts[0])); - break; - } - } else { - DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n", - ha->host_no, mbox_status)); - - ha->mbox_status[0] = mbox_status; - } -} - -/** - * qla4_8xxx_interrupt_service_routine - isr - * @ha: pointer to host adapter structure. - * - * This is the main interrupt service routine. - * hardware_lock locked upon entry. runs in interrupt context. - **/ -void qla4_8xxx_interrupt_service_routine(struct scsi_qla_host *ha, - uint32_t intr_status) -{ - /* Process response queue interrupt. */ - if (intr_status & HSRX_RISC_IOCB_INT) - qla4xxx_process_response_queue(ha); - - /* Process mailbox/asynch event interrupt.*/ - if (intr_status & HSRX_RISC_MB_INT) - qla4xxx_isr_decode_mailbox(ha, - readl(&ha->qla4_8xxx_reg->mailbox_out[0])); - - /* clear the interrupt */ - writel(0, &ha->qla4_8xxx_reg->host_int); - readl(&ha->qla4_8xxx_reg->host_int); -} - -/** - * qla4xxx_interrupt_service_routine - isr - * @ha: pointer to host adapter structure. - * - * This is the main interrupt service routine. - * hardware_lock locked upon entry. runs in interrupt context. - **/ -void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha, - uint32_t intr_status) -{ - /* Process response queue interrupt. */ - if (intr_status & CSR_SCSI_COMPLETION_INTR) - qla4xxx_process_response_queue(ha); - - /* Process mailbox/asynch event interrupt.*/ - if (intr_status & CSR_SCSI_PROCESSOR_INTR) { - qla4xxx_isr_decode_mailbox(ha, - readl(&ha->reg->mailbox[0])); - - /* Clear Mailbox Interrupt */ - writel(set_rmask(CSR_SCSI_PROCESSOR_INTR), - &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - } -} - -/** - * qla4_8xxx_spurious_interrupt - processes spurious interrupt - * @ha: pointer to host adapter structure. - * @reqs_count: . - * - **/ -static void qla4_8xxx_spurious_interrupt(struct scsi_qla_host *ha, - uint8_t reqs_count) -{ - if (reqs_count) - return; - - DEBUG2(ql4_printk(KERN_INFO, ha, "Spurious Interrupt\n")); - if (is_qla8022(ha)) { - writel(0, &ha->qla4_8xxx_reg->host_int); - if (test_bit(AF_INTx_ENABLED, &ha->flags)) - qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, - 0xfbff); - } - ha->spurious_int_count++; -} - -/** - * qla4xxx_intr_handler - hardware interrupt handler. - * @irq: Unused - * @dev_id: Pointer to host adapter structure - **/ -irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id) -{ - struct scsi_qla_host *ha; - uint32_t intr_status; - unsigned long flags = 0; - uint8_t reqs_count = 0; - - ha = (struct scsi_qla_host *) dev_id; - if (!ha) { - DEBUG2(printk(KERN_INFO - "qla4xxx: Interrupt with NULL host ptr\n")); - return IRQ_NONE; - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - - ha->isr_count++; - /* - * Repeatedly service interrupts up to a maximum of - * MAX_REQS_SERVICED_PER_INTR - */ - while (1) { - /* - * Read interrupt status - */ - if (ha->isp_ops->rd_shdw_rsp_q_in(ha) != - ha->response_out) - intr_status = CSR_SCSI_COMPLETION_INTR; - else - intr_status = readl(&ha->reg->ctrl_status); - - if ((intr_status & - (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) == 0) { - if (reqs_count == 0) - ha->spurious_int_count++; - break; - } - - if (intr_status & CSR_FATAL_ERROR) { - DEBUG2(printk(KERN_INFO "scsi%ld: Fatal Error, " - "Status 0x%04x\n", ha->host_no, - readl(isp_port_error_status (ha)))); - - /* Issue Soft Reset to clear this error condition. - * This will prevent the RISC from repeatedly - * interrupting the driver; thus, allowing the DPC to - * get scheduled to continue error recovery. - * NOTE: Disabling RISC interrupts does not work in - * this case, as CSR_FATAL_ERROR overrides - * CSR_SCSI_INTR_ENABLE */ - if ((readl(&ha->reg->ctrl_status) & - CSR_SCSI_RESET_INTR) == 0) { - writel(set_rmask(CSR_SOFT_RESET), - &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - } - - writel(set_rmask(CSR_FATAL_ERROR), - &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - - __qla4xxx_disable_intrs(ha); - - set_bit(DPC_RESET_HA, &ha->dpc_flags); - - break; - } else if (intr_status & CSR_SCSI_RESET_INTR) { - clear_bit(AF_ONLINE, &ha->flags); - __qla4xxx_disable_intrs(ha); - - writel(set_rmask(CSR_SCSI_RESET_INTR), - &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - - if (!test_bit(AF_HA_REMOVAL, &ha->flags)) - set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); - - break; - } else if (intr_status & INTR_PENDING) { - ha->isp_ops->interrupt_service_routine(ha, intr_status); - ha->total_io_count++; - if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) - break; - } - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - return IRQ_HANDLED; -} - -/** - * qla4_8xxx_intr_handler - hardware interrupt handler. - * @irq: Unused - * @dev_id: Pointer to host adapter structure - **/ -irqreturn_t qla4_8xxx_intr_handler(int irq, void *dev_id) -{ - struct scsi_qla_host *ha = dev_id; - uint32_t intr_status; - uint32_t status; - unsigned long flags = 0; - uint8_t reqs_count = 0; - - if (unlikely(pci_channel_offline(ha->pdev))) - return IRQ_HANDLED; - - ha->isr_count++; - status = qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); - if (!(status & ha->nx_legacy_intr.int_vec_bit)) - return IRQ_NONE; - - status = qla4_8xxx_rd_32(ha, ISR_INT_STATE_REG); - if (!ISR_IS_LEGACY_INTR_TRIGGERED(status)) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s legacy Int not triggered\n", __func__)); - return IRQ_NONE; - } - - /* clear the interrupt */ - qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff); - - /* read twice to ensure write is flushed */ - qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); - qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); - - spin_lock_irqsave(&ha->hardware_lock, flags); - while (1) { - if (!(readl(&ha->qla4_8xxx_reg->host_int) & - ISRX_82XX_RISC_INT)) { - qla4_8xxx_spurious_interrupt(ha, reqs_count); - break; - } - intr_status = readl(&ha->qla4_8xxx_reg->host_status); - if ((intr_status & - (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { - qla4_8xxx_spurious_interrupt(ha, reqs_count); - break; - } - - ha->isp_ops->interrupt_service_routine(ha, intr_status); - - /* Enable Interrupt */ - qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); - - if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) - break; - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return IRQ_HANDLED; -} - -irqreturn_t -qla4_8xxx_msi_handler(int irq, void *dev_id) -{ - struct scsi_qla_host *ha; - - ha = (struct scsi_qla_host *) dev_id; - if (!ha) { - DEBUG2(printk(KERN_INFO - "qla4xxx: MSIX: Interrupt with NULL host ptr\n")); - return IRQ_NONE; - } - - ha->isr_count++; - /* clear the interrupt */ - qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff); - - /* read twice to ensure write is flushed */ - qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); - qla4_8xxx_rd_32(ha, ISR_INT_VECTOR); - - return qla4_8xxx_default_intr_handler(irq, dev_id); -} - -/** - * qla4_8xxx_default_intr_handler - hardware interrupt handler. - * @irq: Unused - * @dev_id: Pointer to host adapter structure - * - * This interrupt handler is called directly for MSI-X, and - * called indirectly for MSI. - **/ -irqreturn_t -qla4_8xxx_default_intr_handler(int irq, void *dev_id) -{ - struct scsi_qla_host *ha = dev_id; - unsigned long flags; - uint32_t intr_status; - uint8_t reqs_count = 0; - - spin_lock_irqsave(&ha->hardware_lock, flags); - while (1) { - if (!(readl(&ha->qla4_8xxx_reg->host_int) & - ISRX_82XX_RISC_INT)) { - qla4_8xxx_spurious_interrupt(ha, reqs_count); - break; - } - - intr_status = readl(&ha->qla4_8xxx_reg->host_status); - if ((intr_status & - (HSRX_RISC_MB_INT | HSRX_RISC_IOCB_INT)) == 0) { - qla4_8xxx_spurious_interrupt(ha, reqs_count); - break; - } - - ha->isp_ops->interrupt_service_routine(ha, intr_status); - - if (++reqs_count == MAX_REQS_SERVICED_PER_INTR) - break; - } - - ha->isr_count++; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return IRQ_HANDLED; -} - -irqreturn_t -qla4_8xxx_msix_rsp_q(int irq, void *dev_id) -{ - struct scsi_qla_host *ha = dev_id; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - qla4xxx_process_response_queue(ha); - writel(0, &ha->qla4_8xxx_reg->host_int); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - ha->isr_count++; - return IRQ_HANDLED; -} - -/** - * qla4xxx_process_aen - processes AENs generated by firmware - * @ha: pointer to host adapter structure. - * @process_aen: type of AENs to process - * - * Processes specific types of Asynchronous Events generated by firmware. - * The type of AENs to process is specified by process_aen and can be - * PROCESS_ALL_AENS 0 - * FLUSH_DDB_CHANGED_AENS 1 - * RELOGIN_DDB_CHANGED_AENS 2 - **/ -void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen) -{ - uint32_t mbox_sts[MBOX_AEN_REG_COUNT]; - struct aen *aen; - int i; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - while (ha->aen_out != ha->aen_in) { - aen = &ha->aen_q[ha->aen_out]; - /* copy aen information to local structure */ - for (i = 0; i < MBOX_AEN_REG_COUNT; i++) - mbox_sts[i] = aen->mbox_sts[i]; - - ha->aen_q_count++; - ha->aen_out++; - - if (ha->aen_out == MAX_AEN_ENTRIES) - ha->aen_out = 0; - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - DEBUG2(printk("qla4xxx(%ld): AEN[%d]=0x%08x, mbx1=0x%08x mbx2=0x%08x" - " mbx3=0x%08x mbx4=0x%08x\n", ha->host_no, - (ha->aen_out ? (ha->aen_out-1): (MAX_AEN_ENTRIES-1)), - mbox_sts[0], mbox_sts[1], mbox_sts[2], - mbox_sts[3], mbox_sts[4])); - - switch (mbox_sts[0]) { - case MBOX_ASTS_DATABASE_CHANGED: - switch (process_aen) { - case FLUSH_DDB_CHANGED_AENS: - DEBUG2(printk("scsi%ld: AEN[%d] %04x, index " - "[%d] state=%04x FLUSHED!\n", - ha->host_no, ha->aen_out, - mbox_sts[0], mbox_sts[2], - mbox_sts[3])); - break; - case PROCESS_ALL_AENS: - default: - /* Specific device. */ - if (mbox_sts[1] == 1) - qla4xxx_process_ddb_changed(ha, - mbox_sts[2], mbox_sts[3], - mbox_sts[4]); - break; - } - } - spin_lock_irqsave(&ha->hardware_lock, flags); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -int qla4xxx_request_irqs(struct scsi_qla_host *ha) -{ - int ret; - - if (!is_qla8022(ha)) - goto try_intx; - - if (ql4xenablemsix == 2) - goto try_msi; - - if (ql4xenablemsix == 0 || ql4xenablemsix != 1) - goto try_intx; - - /* Trying MSI-X */ - ret = qla4_8xxx_enable_msix(ha); - if (!ret) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "MSI-X: Enabled (0x%X).\n", ha->revision_id)); - goto irq_attached; - } - - ql4_printk(KERN_WARNING, ha, - "MSI-X: Falling back-to MSI mode -- %d.\n", ret); - -try_msi: - /* Trying MSI */ - ret = pci_enable_msi(ha->pdev); - if (!ret) { - ret = request_irq(ha->pdev->irq, qla4_8xxx_msi_handler, - 0, DRIVER_NAME, ha); - if (!ret) { - DEBUG2(ql4_printk(KERN_INFO, ha, "MSI: Enabled.\n")); - set_bit(AF_MSI_ENABLED, &ha->flags); - goto irq_attached; - } else { - ql4_printk(KERN_WARNING, ha, - "MSI: Failed to reserve interrupt %d " - "already in use.\n", ha->pdev->irq); - pci_disable_msi(ha->pdev); - } - } - ql4_printk(KERN_WARNING, ha, - "MSI: Falling back-to INTx mode -- %d.\n", ret); - -try_intx: - /* Trying INTx */ - ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler, - IRQF_SHARED, DRIVER_NAME, ha); - if (!ret) { - DEBUG2(ql4_printk(KERN_INFO, ha, "INTx: Enabled.\n")); - set_bit(AF_INTx_ENABLED, &ha->flags); - goto irq_attached; - - } else { - ql4_printk(KERN_WARNING, ha, - "INTx: Failed to reserve interrupt %d already in" - " use.\n", ha->pdev->irq); - return ret; - } - -irq_attached: - set_bit(AF_IRQ_ATTACHED, &ha->flags); - ha->host->irq = ha->pdev->irq; - ql4_printk(KERN_INFO, ha, "%s: irq %d attached\n", - __func__, ha->pdev->irq); - return ret; -} - -void qla4xxx_free_irqs(struct scsi_qla_host *ha) -{ - if (test_bit(AF_MSIX_ENABLED, &ha->flags)) - qla4_8xxx_disable_msix(ha); - else if (test_and_clear_bit(AF_MSI_ENABLED, &ha->flags)) { - free_irq(ha->pdev->irq, ha); - pci_disable_msi(ha->pdev); - } else if (test_and_clear_bit(AF_INTx_ENABLED, &ha->flags)) - free_irq(ha->pdev->irq, ha); -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_mbx.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_mbx.c deleted file mode 100644 index 7ac21dab..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_mbx.c +++ /dev/null @@ -1,1882 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#include "ql4_def.h" -#include "ql4_glbl.h" -#include "ql4_dbg.h" -#include "ql4_inline.h" - - -/** - * qla4xxx_mailbox_command - issues mailbox commands - * @ha: Pointer to host adapter structure. - * @inCount: number of mailbox registers to load. - * @outCount: number of mailbox registers to return. - * @mbx_cmd: data pointer for mailbox in registers. - * @mbx_sts: data pointer for mailbox out registers. - * - * This routine issue mailbox commands and waits for completion. - * If outCount is 0, this routine completes successfully WITHOUT waiting - * for the mailbox command to complete. - **/ -int qla4xxx_mailbox_command(struct scsi_qla_host *ha, uint8_t inCount, - uint8_t outCount, uint32_t *mbx_cmd, - uint32_t *mbx_sts) -{ - int status = QLA_ERROR; - uint8_t i; - u_long wait_count; - uint32_t intr_status; - unsigned long flags = 0; - uint32_t dev_state; - - /* Make sure that pointers are valid */ - if (!mbx_cmd || !mbx_sts) { - DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts " - "pointer\n", ha->host_no, __func__)); - return status; - } - - if (is_qla40XX(ha)) { - if (test_bit(AF_HA_REMOVAL, &ha->flags)) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " - "prematurely completing mbx cmd as " - "adapter removal detected\n", - ha->host_no, __func__)); - return status; - } - } - - if (is_qla8022(ha)) { - if (test_bit(AF_FW_RECOVERY, &ha->flags)) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: " - "prematurely completing mbx cmd as firmware " - "recovery detected\n", ha->host_no, __func__)); - return status; - } - /* Do not send any mbx cmd if h/w is in failed state*/ - qla4_8xxx_idc_lock(ha); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla4_8xxx_idc_unlock(ha); - if (dev_state == QLA82XX_DEV_FAILED) { - ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: H/W is in " - "failed state, do not send any mailbox commands\n", - ha->host_no, __func__); - return status; - } - } - - if ((is_aer_supported(ha)) && - (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags))) { - DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Perm failure on EEH, " - "timeout MBX Exiting.\n", ha->host_no, __func__)); - return status; - } - - /* Mailbox code active */ - wait_count = MBOX_TOV * 100; - - while (wait_count--) { - mutex_lock(&ha->mbox_sem); - if (!test_bit(AF_MBOX_COMMAND, &ha->flags)) { - set_bit(AF_MBOX_COMMAND, &ha->flags); - mutex_unlock(&ha->mbox_sem); - break; - } - mutex_unlock(&ha->mbox_sem); - if (!wait_count) { - DEBUG2(printk("scsi%ld: %s: mbox_sem failed\n", - ha->host_no, __func__)); - return status; - } - msleep(10); - } - - spin_lock_irqsave(&ha->hardware_lock, flags); - - ha->mbox_status_count = outCount; - for (i = 0; i < outCount; i++) - ha->mbox_status[i] = 0; - - if (is_qla8022(ha)) { - /* Load all mailbox registers, except mailbox 0. */ - DEBUG5( - printk("scsi%ld: %s: Cmd ", ha->host_no, __func__); - for (i = 0; i < inCount; i++) - printk("mb%d=%04x ", i, mbx_cmd[i]); - printk("\n")); - - for (i = 1; i < inCount; i++) - writel(mbx_cmd[i], &ha->qla4_8xxx_reg->mailbox_in[i]); - writel(mbx_cmd[0], &ha->qla4_8xxx_reg->mailbox_in[0]); - readl(&ha->qla4_8xxx_reg->mailbox_in[0]); - writel(HINT_MBX_INT_PENDING, &ha->qla4_8xxx_reg->hint); - } else { - /* Load all mailbox registers, except mailbox 0. */ - for (i = 1; i < inCount; i++) - writel(mbx_cmd[i], &ha->reg->mailbox[i]); - - /* Wakeup firmware */ - writel(mbx_cmd[0], &ha->reg->mailbox[0]); - readl(&ha->reg->mailbox[0]); - writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - } - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* Wait for completion */ - - /* - * If we don't want status, don't wait for the mailbox command to - * complete. For example, MBOX_CMD_RESET_FW doesn't return status, - * you must poll the inbound Interrupt Mask for completion. - */ - if (outCount == 0) { - status = QLA_SUCCESS; - goto mbox_exit; - } - - /* - * Wait for completion: Poll or completion queue - */ - if (test_bit(AF_IRQ_ATTACHED, &ha->flags) && - test_bit(AF_INTERRUPTS_ON, &ha->flags) && - test_bit(AF_ONLINE, &ha->flags) && - !test_bit(AF_HA_REMOVAL, &ha->flags)) { - /* Do not poll for completion. Use completion queue */ - set_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); - wait_for_completion_timeout(&ha->mbx_intr_comp, MBOX_TOV * HZ); - clear_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags); - } else { - /* Poll for command to complete */ - wait_count = jiffies + MBOX_TOV * HZ; - while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) { - if (time_after_eq(jiffies, wait_count)) - break; - - /* - * Service the interrupt. - * The ISR will save the mailbox status registers - * to a temporary storage location in the adapter - * structure. - */ - - spin_lock_irqsave(&ha->hardware_lock, flags); - if (is_qla8022(ha)) { - intr_status = - readl(&ha->qla4_8xxx_reg->host_int); - if (intr_status & ISRX_82XX_RISC_INT) { - ha->mbox_status_count = outCount; - intr_status = - readl(&ha->qla4_8xxx_reg->host_status); - ha->isp_ops->interrupt_service_routine( - ha, intr_status); - if (test_bit(AF_INTERRUPTS_ON, - &ha->flags) && - test_bit(AF_INTx_ENABLED, - &ha->flags)) - qla4_8xxx_wr_32(ha, - ha->nx_legacy_intr.tgt_mask_reg, - 0xfbff); - } - } else { - intr_status = readl(&ha->reg->ctrl_status); - if (intr_status & INTR_PENDING) { - /* - * Service the interrupt. - * The ISR will save the mailbox status - * registers to a temporary storage - * location in the adapter structure. - */ - ha->mbox_status_count = outCount; - ha->isp_ops->interrupt_service_routine( - ha, intr_status); - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - msleep(10); - } - } - - /* Check for mailbox timeout. */ - if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) { - if (is_qla8022(ha) && - test_bit(AF_FW_RECOVERY, &ha->flags)) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: %s: prematurely completing mbx cmd as " - "firmware recovery detected\n", - ha->host_no, __func__)); - goto mbox_exit; - } - DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...," - " Scheduling Adapter Reset\n", ha->host_no, - mbx_cmd[0])); - ha->mailbox_timeout_count++; - mbx_sts[0] = (-1); - set_bit(DPC_RESET_HA, &ha->dpc_flags); - if (is_qla8022(ha)) { - ql4_printk(KERN_INFO, ha, - "disabling pause transmit on port 0 & 1.\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, - CRB_NIU_XG_PAUSE_CTL_P0 | - CRB_NIU_XG_PAUSE_CTL_P1); - } - goto mbox_exit; - } - - /* - * Copy the mailbox out registers to the caller's mailbox in/out - * structure. - */ - spin_lock_irqsave(&ha->hardware_lock, flags); - for (i = 0; i < outCount; i++) - mbx_sts[i] = ha->mbox_status[i]; - - /* Set return status and error flags (if applicable). */ - switch (ha->mbox_status[0]) { - case MBOX_STS_COMMAND_COMPLETE: - status = QLA_SUCCESS; - break; - - case MBOX_STS_INTERMEDIATE_COMPLETION: - status = QLA_SUCCESS; - break; - - case MBOX_STS_BUSY: - DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n", - ha->host_no, __func__, mbx_cmd[0])); - ha->mailbox_timeout_count++; - break; - - default: - DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, " - "sts = %08X ****\n", ha->host_no, __func__, - mbx_cmd[0], mbx_sts[0])); - break; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - -mbox_exit: - mutex_lock(&ha->mbox_sem); - clear_bit(AF_MBOX_COMMAND, &ha->flags); - mutex_unlock(&ha->mbox_sem); - clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags); - - return status; -} - -void qla4xxx_mailbox_premature_completion(struct scsi_qla_host *ha) -{ - set_bit(AF_FW_RECOVERY, &ha->flags); - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: set FW RECOVERY!\n", - ha->host_no, __func__); - - if (test_bit(AF_MBOX_COMMAND, &ha->flags)) { - if (test_bit(AF_MBOX_COMMAND_NOPOLL, &ha->flags)) { - complete(&ha->mbx_intr_comp); - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Due to fw " - "recovery, doing premature completion of " - "mbx cmd\n", ha->host_no, __func__); - - } else { - set_bit(AF_MBOX_COMMAND_DONE, &ha->flags); - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Due to fw " - "recovery, doing premature completion of " - "polling mbx cmd\n", ha->host_no, __func__); - } - } -} - -static uint8_t -qla4xxx_set_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, - uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) -{ - memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); - memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); - - if (is_qla8022(ha)) - qla4_8xxx_wr_32(ha, ha->nx_db_wr_ptr, 0); - - mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE; - mbox_cmd[1] = 0; - mbox_cmd[2] = LSDW(init_fw_cb_dma); - mbox_cmd[3] = MSDW(init_fw_cb_dma); - mbox_cmd[4] = sizeof(struct addr_ctrl_blk); - mbox_cmd[5] = (IFCB_VER_MAX << 8) | IFCB_VER_MIN; - - if (qla4xxx_mailbox_command(ha, 6, 6, mbox_cmd, mbox_sts) != - QLA_SUCCESS) { - DEBUG2(printk(KERN_WARNING "scsi%ld: %s: " - "MBOX_CMD_INITIALIZE_FIRMWARE" - " failed w/ status %04X\n", - ha->host_no, __func__, mbox_sts[0])); - return QLA_ERROR; - } - return QLA_SUCCESS; -} - -uint8_t -qla4xxx_get_ifcb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, - uint32_t *mbox_sts, dma_addr_t init_fw_cb_dma) -{ - memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); - memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); - mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK; - mbox_cmd[2] = LSDW(init_fw_cb_dma); - mbox_cmd[3] = MSDW(init_fw_cb_dma); - mbox_cmd[4] = sizeof(struct addr_ctrl_blk); - - if (qla4xxx_mailbox_command(ha, 5, 5, mbox_cmd, mbox_sts) != - QLA_SUCCESS) { - DEBUG2(printk(KERN_WARNING "scsi%ld: %s: " - "MBOX_CMD_GET_INIT_FW_CTRL_BLOCK" - " failed w/ status %04X\n", - ha->host_no, __func__, mbox_sts[0])); - return QLA_ERROR; - } - return QLA_SUCCESS; -} - -static void -qla4xxx_update_local_ip(struct scsi_qla_host *ha, - struct addr_ctrl_blk *init_fw_cb) -{ - ha->ip_config.tcp_options = le16_to_cpu(init_fw_cb->ipv4_tcp_opts); - ha->ip_config.ipv4_options = le16_to_cpu(init_fw_cb->ipv4_ip_opts); - ha->ip_config.ipv4_addr_state = - le16_to_cpu(init_fw_cb->ipv4_addr_state); - ha->ip_config.eth_mtu_size = - le16_to_cpu(init_fw_cb->eth_mtu_size); - ha->ip_config.ipv4_port = le16_to_cpu(init_fw_cb->ipv4_port); - - if (ha->acb_version == ACB_SUPPORTED) { - ha->ip_config.ipv6_options = le16_to_cpu(init_fw_cb->ipv6_opts); - ha->ip_config.ipv6_addl_options = - le16_to_cpu(init_fw_cb->ipv6_addtl_opts); - } - - /* Save IPv4 Address Info */ - memcpy(ha->ip_config.ip_address, init_fw_cb->ipv4_addr, - min(sizeof(ha->ip_config.ip_address), - sizeof(init_fw_cb->ipv4_addr))); - memcpy(ha->ip_config.subnet_mask, init_fw_cb->ipv4_subnet, - min(sizeof(ha->ip_config.subnet_mask), - sizeof(init_fw_cb->ipv4_subnet))); - memcpy(ha->ip_config.gateway, init_fw_cb->ipv4_gw_addr, - min(sizeof(ha->ip_config.gateway), - sizeof(init_fw_cb->ipv4_gw_addr))); - - ha->ip_config.ipv4_vlan_tag = be16_to_cpu(init_fw_cb->ipv4_vlan_tag); - - if (is_ipv6_enabled(ha)) { - /* Save IPv6 Address */ - ha->ip_config.ipv6_link_local_state = - le16_to_cpu(init_fw_cb->ipv6_lnk_lcl_addr_state); - ha->ip_config.ipv6_addr0_state = - le16_to_cpu(init_fw_cb->ipv6_addr0_state); - ha->ip_config.ipv6_addr1_state = - le16_to_cpu(init_fw_cb->ipv6_addr1_state); - ha->ip_config.ipv6_default_router_state = - le16_to_cpu(init_fw_cb->ipv6_dflt_rtr_state); - ha->ip_config.ipv6_link_local_addr.in6_u.u6_addr8[0] = 0xFE; - ha->ip_config.ipv6_link_local_addr.in6_u.u6_addr8[1] = 0x80; - - memcpy(&ha->ip_config.ipv6_link_local_addr.in6_u.u6_addr8[8], - init_fw_cb->ipv6_if_id, - min(sizeof(ha->ip_config.ipv6_link_local_addr)/2, - sizeof(init_fw_cb->ipv6_if_id))); - memcpy(&ha->ip_config.ipv6_addr0, init_fw_cb->ipv6_addr0, - min(sizeof(ha->ip_config.ipv6_addr0), - sizeof(init_fw_cb->ipv6_addr0))); - memcpy(&ha->ip_config.ipv6_addr1, init_fw_cb->ipv6_addr1, - min(sizeof(ha->ip_config.ipv6_addr1), - sizeof(init_fw_cb->ipv6_addr1))); - memcpy(&ha->ip_config.ipv6_default_router_addr, - init_fw_cb->ipv6_dflt_rtr_addr, - min(sizeof(ha->ip_config.ipv6_default_router_addr), - sizeof(init_fw_cb->ipv6_dflt_rtr_addr))); - ha->ip_config.ipv6_vlan_tag = - be16_to_cpu(init_fw_cb->ipv6_vlan_tag); - ha->ip_config.ipv6_port = le16_to_cpu(init_fw_cb->ipv6_port); - } -} - -uint8_t -qla4xxx_update_local_ifcb(struct scsi_qla_host *ha, - uint32_t *mbox_cmd, - uint32_t *mbox_sts, - struct addr_ctrl_blk *init_fw_cb, - dma_addr_t init_fw_cb_dma) -{ - if (qla4xxx_get_ifcb(ha, mbox_cmd, mbox_sts, init_fw_cb_dma) - != QLA_SUCCESS) { - DEBUG2(printk(KERN_WARNING - "scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", - ha->host_no, __func__)); - return QLA_ERROR; - } - - DEBUG2(qla4xxx_dump_buffer(init_fw_cb, sizeof(struct addr_ctrl_blk))); - - /* Save some info in adapter structure. */ - ha->acb_version = init_fw_cb->acb_version; - ha->firmware_options = le16_to_cpu(init_fw_cb->fw_options); - ha->heartbeat_interval = init_fw_cb->hb_interval; - memcpy(ha->name_string, init_fw_cb->iscsi_name, - min(sizeof(ha->name_string), - sizeof(init_fw_cb->iscsi_name))); - ha->def_timeout = le16_to_cpu(init_fw_cb->def_timeout); - /*memcpy(ha->alias, init_fw_cb->Alias, - min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));*/ - - qla4xxx_update_local_ip(ha, init_fw_cb); - - return QLA_SUCCESS; -} - -/** - * qla4xxx_initialize_fw_cb - initializes firmware control block. - * @ha: Pointer to host adapter structure. - **/ -int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) -{ - struct addr_ctrl_blk *init_fw_cb; - dma_addr_t init_fw_cb_dma; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_ERROR; - - init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - &init_fw_cb_dma, GFP_KERNEL); - if (init_fw_cb == NULL) { - DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n", - ha->host_no, __func__)); - goto exit_init_fw_cb_no_free; - } - memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); - - /* Get Initialize Firmware Control Block. */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != - QLA_SUCCESS) { - dma_free_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - init_fw_cb, init_fw_cb_dma); - goto exit_init_fw_cb; - } - - /* Initialize request and response queues. */ - qla4xxx_init_rings(ha); - - /* Fill in the request and response queue information. */ - init_fw_cb->rqq_consumer_idx = cpu_to_le16(ha->request_out); - init_fw_cb->compq_producer_idx = cpu_to_le16(ha->response_in); - init_fw_cb->rqq_len = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH); - init_fw_cb->compq_len = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH); - init_fw_cb->rqq_addr_lo = cpu_to_le32(LSDW(ha->request_dma)); - init_fw_cb->rqq_addr_hi = cpu_to_le32(MSDW(ha->request_dma)); - init_fw_cb->compq_addr_lo = cpu_to_le32(LSDW(ha->response_dma)); - init_fw_cb->compq_addr_hi = cpu_to_le32(MSDW(ha->response_dma)); - init_fw_cb->shdwreg_addr_lo = cpu_to_le32(LSDW(ha->shadow_regs_dma)); - init_fw_cb->shdwreg_addr_hi = cpu_to_le32(MSDW(ha->shadow_regs_dma)); - - /* Set up required options. */ - init_fw_cb->fw_options |= - __constant_cpu_to_le16(FWOPT_SESSION_MODE | - FWOPT_INITIATOR_MODE); - - if (is_qla8022(ha)) - init_fw_cb->fw_options |= - __constant_cpu_to_le16(FWOPT_ENABLE_CRBDB); - - init_fw_cb->fw_options &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE); - - init_fw_cb->add_fw_options = 0; - init_fw_cb->add_fw_options |= - __constant_cpu_to_le16(ADFWOPT_SERIALIZE_TASK_MGMT); - init_fw_cb->add_fw_options |= - __constant_cpu_to_le16(ADFWOPT_AUTOCONN_DISABLE); - - if (qla4xxx_set_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) - != QLA_SUCCESS) { - DEBUG2(printk(KERN_WARNING - "scsi%ld: %s: Failed to set init_fw_ctrl_blk\n", - ha->host_no, __func__)); - goto exit_init_fw_cb; - } - - if (qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], - init_fw_cb, init_fw_cb_dma) != QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: Failed to update local ifcb\n", - ha->host_no, __func__)); - goto exit_init_fw_cb; - } - status = QLA_SUCCESS; - -exit_init_fw_cb: - dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), - init_fw_cb, init_fw_cb_dma); -exit_init_fw_cb_no_free: - return status; -} - -/** - * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP - * @ha: Pointer to host adapter structure. - **/ -int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha) -{ - struct addr_ctrl_blk *init_fw_cb; - dma_addr_t init_fw_cb_dma; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - &init_fw_cb_dma, GFP_KERNEL); - if (init_fw_cb == NULL) { - printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no, - __func__); - return QLA_ERROR; - } - - /* Get Initialize Firmware Control Block. */ - memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); - if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != - QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n", - ha->host_no, __func__)); - dma_free_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - init_fw_cb, init_fw_cb_dma); - return QLA_ERROR; - } - - /* Save IP Address. */ - qla4xxx_update_local_ip(ha, init_fw_cb); - dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), - init_fw_cb, init_fw_cb_dma); - - return QLA_SUCCESS; -} - -/** - * qla4xxx_get_firmware_state - gets firmware state of HBA - * @ha: Pointer to host adapter structure. - **/ -int qla4xxx_get_firmware_state(struct scsi_qla_host * ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - /* Get firmware version */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_GET_FW_STATE; - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 4, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ " - "status %04X\n", ha->host_no, __func__, - mbox_sts[0])); - return QLA_ERROR; - } - ha->firmware_state = mbox_sts[1]; - ha->board_id = mbox_sts[2]; - ha->addl_fw_state = mbox_sts[3]; - DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n", - ha->host_no, __func__, ha->firmware_state);) - - return QLA_SUCCESS; -} - -/** - * qla4xxx_get_firmware_status - retrieves firmware status - * @ha: Pointer to host adapter structure. - **/ -int qla4xxx_get_firmware_status(struct scsi_qla_host * ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - /* Get firmware version */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS; - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ " - "status %04X\n", ha->host_no, __func__, - mbox_sts[0])); - return QLA_ERROR; - } - - ql4_printk(KERN_INFO, ha, "%ld firmware IOCBs available (%d).\n", - ha->host_no, mbox_sts[2]); - - return QLA_SUCCESS; -} - -/** - * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry - * @ha: Pointer to host adapter structure. - * @fw_ddb_index: Firmware's device database index - * @fw_ddb_entry: Pointer to firmware's device database entry structure - * @num_valid_ddb_entries: Pointer to number of valid ddb entries - * @next_ddb_index: Pointer to next valid device database index - * @fw_ddb_device_state: Pointer to device state - **/ -int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha, - uint16_t fw_ddb_index, - struct dev_db_entry *fw_ddb_entry, - dma_addr_t fw_ddb_entry_dma, - uint32_t *num_valid_ddb_entries, - uint32_t *next_ddb_index, - uint32_t *fw_ddb_device_state, - uint32_t *conn_err_detail, - uint16_t *tcp_source_port_num, - uint16_t *connection_id) -{ - int status = QLA_ERROR; - uint16_t options; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - /* Make sure the device index is valid */ - if (fw_ddb_index >= MAX_DDB_ENTRIES) { - DEBUG2(printk("scsi%ld: %s: ddb [%d] out of range.\n", - ha->host_no, __func__, fw_ddb_index)); - goto exit_get_fwddb; - } - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - if (fw_ddb_entry) - memset(fw_ddb_entry, 0, sizeof(struct dev_db_entry)); - - mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY; - mbox_cmd[1] = (uint32_t) fw_ddb_index; - mbox_cmd[2] = LSDW(fw_ddb_entry_dma); - mbox_cmd[3] = MSDW(fw_ddb_entry_dma); - mbox_cmd[4] = sizeof(struct dev_db_entry); - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 7, &mbox_cmd[0], &mbox_sts[0]) == - QLA_ERROR) { - DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed" - " with status 0x%04X\n", ha->host_no, __func__, - mbox_sts[0])); - goto exit_get_fwddb; - } - if (fw_ddb_index != mbox_sts[1]) { - DEBUG2(printk("scsi%ld: %s: ddb mismatch [%d] != [%d].\n", - ha->host_no, __func__, fw_ddb_index, - mbox_sts[1])); - goto exit_get_fwddb; - } - if (fw_ddb_entry) { - options = le16_to_cpu(fw_ddb_entry->options); - if (options & DDB_OPT_IPV6_DEVICE) { - ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d " - "Next %d State %04x ConnErr %08x %pI6 " - ":%04d \"%s\"\n", __func__, fw_ddb_index, - mbox_sts[0], mbox_sts[2], mbox_sts[3], - mbox_sts[4], mbox_sts[5], - fw_ddb_entry->ip_addr, - le16_to_cpu(fw_ddb_entry->port), - fw_ddb_entry->iscsi_name); - } else { - ql4_printk(KERN_INFO, ha, "%s: DDB[%d] MB0 %04x Tot %d " - "Next %d State %04x ConnErr %08x %pI4 " - ":%04d \"%s\"\n", __func__, fw_ddb_index, - mbox_sts[0], mbox_sts[2], mbox_sts[3], - mbox_sts[4], mbox_sts[5], - fw_ddb_entry->ip_addr, - le16_to_cpu(fw_ddb_entry->port), - fw_ddb_entry->iscsi_name); - } - } - if (num_valid_ddb_entries) - *num_valid_ddb_entries = mbox_sts[2]; - if (next_ddb_index) - *next_ddb_index = mbox_sts[3]; - if (fw_ddb_device_state) - *fw_ddb_device_state = mbox_sts[4]; - - /* - * RA: This mailbox has been changed to pass connection error and - * details. Its true for ISP4010 as per Version E - Not sure when it - * was changed. Get the time2wait from the fw_dd_entry field : - * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY - * struct. - */ - if (conn_err_detail) - *conn_err_detail = mbox_sts[5]; - if (tcp_source_port_num) - *tcp_source_port_num = (uint16_t) (mbox_sts[6] >> 16); - if (connection_id) - *connection_id = (uint16_t) mbox_sts[6] & 0x00FF; - status = QLA_SUCCESS; - -exit_get_fwddb: - return status; -} - -int qla4xxx_conn_open(struct scsi_qla_host *ha, uint16_t fw_ddb_index) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_CONN_OPEN; - mbox_cmd[1] = fw_ddb_index; - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], - &mbox_sts[0]); - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: status = %d mbx0 = 0x%x mbx1 = 0x%x\n", - __func__, status, mbox_sts[0], mbox_sts[1])); - return status; -} - -/** - * qla4xxx_set_fwddb_entry - sets a ddb entry. - * @ha: Pointer to host adapter structure. - * @fw_ddb_index: Firmware's device database index - * @fw_ddb_entry_dma: dma address of ddb entry - * @mbx_sts: mailbox 0 to be returned or NULL - * - * This routine initializes or updates the adapter's device database - * entry for the specified device. - **/ -int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index, - dma_addr_t fw_ddb_entry_dma, uint32_t *mbx_sts) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status; - - /* Do not wait for completion. The firmware will send us an - * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status. - */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY; - mbox_cmd[1] = (uint32_t) fw_ddb_index; - mbox_cmd[2] = LSDW(fw_ddb_entry_dma); - mbox_cmd[3] = MSDW(fw_ddb_entry_dma); - mbox_cmd[4] = sizeof(struct dev_db_entry); - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], - &mbox_sts[0]); - if (mbx_sts) - *mbx_sts = mbox_sts[0]; - DEBUG2(printk("scsi%ld: %s: status=%d mbx0=0x%x mbx4=0x%x\n", - ha->host_no, __func__, status, mbox_sts[0], mbox_sts[4]);) - - return status; -} - -int qla4xxx_session_logout_ddb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, int options) -{ - int status; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT; - mbox_cmd[1] = ddb_entry->fw_ddb_index; - mbox_cmd[3] = options; - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], - &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT " - "failed sts %04X %04X", __func__, - mbox_sts[0], mbox_sts[1])); - } - - return status; -} - -/** - * qla4xxx_get_crash_record - retrieves crash record. - * @ha: Pointer to host adapter structure. - * - * This routine retrieves a crash record from the QLA4010 after an 8002h aen. - **/ -void qla4xxx_get_crash_record(struct scsi_qla_host * ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - struct crash_record *crash_record = NULL; - dma_addr_t crash_record_dma = 0; - uint32_t crash_record_size = 0; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_cmd)); - - /* Get size of crash record. */ - mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n", - ha->host_no, __func__)); - goto exit_get_crash_record; - } - crash_record_size = mbox_sts[4]; - if (crash_record_size == 0) { - DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n", - ha->host_no, __func__)); - goto exit_get_crash_record; - } - - /* Alloc Memory for Crash Record. */ - crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size, - &crash_record_dma, GFP_KERNEL); - if (crash_record == NULL) - goto exit_get_crash_record; - - /* Get Crash Record. */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_cmd)); - - mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD; - mbox_cmd[2] = LSDW(crash_record_dma); - mbox_cmd[3] = MSDW(crash_record_dma); - mbox_cmd[4] = crash_record_size; - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) - goto exit_get_crash_record; - - /* Dump Crash Record. */ - -exit_get_crash_record: - if (crash_record) - dma_free_coherent(&ha->pdev->dev, crash_record_size, - crash_record, crash_record_dma); -} - -/** - * qla4xxx_get_conn_event_log - retrieves connection event log - * @ha: Pointer to host adapter structure. - **/ -void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - struct conn_event_log_entry *event_log = NULL; - dma_addr_t event_log_dma = 0; - uint32_t event_log_size = 0; - uint32_t num_valid_entries; - uint32_t oldest_entry = 0; - uint32_t max_event_log_entries; - uint8_t i; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_cmd)); - - /* Get size of crash record. */ - mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) - goto exit_get_event_log; - - event_log_size = mbox_sts[4]; - if (event_log_size == 0) - goto exit_get_event_log; - - /* Alloc Memory for Crash Record. */ - event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size, - &event_log_dma, GFP_KERNEL); - if (event_log == NULL) - goto exit_get_event_log; - - /* Get Crash Record. */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_cmd)); - - mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG; - mbox_cmd[2] = LSDW(event_log_dma); - mbox_cmd[3] = MSDW(event_log_dma); - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event " - "log!\n", ha->host_no, __func__)); - goto exit_get_event_log; - } - - /* Dump Event Log. */ - num_valid_entries = mbox_sts[1]; - - max_event_log_entries = event_log_size / - sizeof(struct conn_event_log_entry); - - if (num_valid_entries > max_event_log_entries) - oldest_entry = num_valid_entries % max_event_log_entries; - - DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n", - ha->host_no, num_valid_entries)); - - if (ql4xextended_error_logging == 3) { - if (oldest_entry == 0) { - /* Circular Buffer has not wrapped around */ - for (i=0; i < num_valid_entries; i++) { - qla4xxx_dump_buffer((uint8_t *)event_log+ - (i*sizeof(*event_log)), - sizeof(*event_log)); - } - } - else { - /* Circular Buffer has wrapped around - - * display accordingly*/ - for (i=oldest_entry; i < max_event_log_entries; i++) { - qla4xxx_dump_buffer((uint8_t *)event_log+ - (i*sizeof(*event_log)), - sizeof(*event_log)); - } - for (i=0; i < oldest_entry; i++) { - qla4xxx_dump_buffer((uint8_t *)event_log+ - (i*sizeof(*event_log)), - sizeof(*event_log)); - } - } - } - -exit_get_event_log: - if (event_log) - dma_free_coherent(&ha->pdev->dev, event_log_size, event_log, - event_log_dma); -} - -/** - * qla4xxx_abort_task - issues Abort Task - * @ha: Pointer to host adapter structure. - * @srb: Pointer to srb entry - * - * This routine performs a LUN RESET on the specified target/lun. - * The caller must ensure that the ddb_entry and lun_entry pointers - * are valid before calling this routine. - **/ -int qla4xxx_abort_task(struct scsi_qla_host *ha, struct srb *srb) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - struct scsi_cmnd *cmd = srb->cmd; - int status = QLA_SUCCESS; - unsigned long flags = 0; - uint32_t index; - - /* - * Send abort task command to ISP, so that the ISP will return - * request with ABORT status - */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - spin_lock_irqsave(&ha->hardware_lock, flags); - index = (unsigned long)(unsigned char *)cmd->host_scribble; - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* Firmware already posted completion on response queue */ - if (index == MAX_SRBS) - return status; - - mbox_cmd[0] = MBOX_CMD_ABORT_TASK; - mbox_cmd[1] = srb->ddb->fw_ddb_index; - mbox_cmd[2] = index; - /* Immediate Command Enable */ - mbox_cmd[5] = 0x01; - - qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 5, &mbox_cmd[0], - &mbox_sts[0]); - if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE) { - status = QLA_ERROR; - - DEBUG2(printk(KERN_WARNING "scsi%ld:%d:%d: abort task FAILED: " - "mbx0=%04X, mb1=%04X, mb2=%04X, mb3=%04X, mb4=%04X\n", - ha->host_no, cmd->device->id, cmd->device->lun, mbox_sts[0], - mbox_sts[1], mbox_sts[2], mbox_sts[3], mbox_sts[4])); - } - - return status; -} - -/** - * qla4xxx_reset_lun - issues LUN Reset - * @ha: Pointer to host adapter structure. - * @ddb_entry: Pointer to device database entry - * @lun: lun number - * - * This routine performs a LUN RESET on the specified target/lun. - * The caller must ensure that the ddb_entry and lun_entry pointers - * are valid before calling this routine. - **/ -int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry, - int lun) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_SUCCESS; - - DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no, - ddb_entry->fw_ddb_index, lun)); - - /* - * Send lun reset command to ISP, so that the ISP will return all - * outstanding requests with RESET status - */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_LUN_RESET; - mbox_cmd[1] = ddb_entry->fw_ddb_index; - mbox_cmd[2] = lun << 8; - mbox_cmd[5] = 0x01; /* Immediate Command Enable */ - - qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]); - if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && - mbox_sts[0] != MBOX_STS_COMMAND_ERROR) - status = QLA_ERROR; - - return status; -} - -/** - * qla4xxx_reset_target - issues target Reset - * @ha: Pointer to host adapter structure. - * @db_entry: Pointer to device database entry - * @un_entry: Pointer to lun entry structure - * - * This routine performs a TARGET RESET on the specified target. - * The caller must ensure that the ddb_entry pointers - * are valid before calling this routine. - **/ -int qla4xxx_reset_target(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_SUCCESS; - - DEBUG2(printk("scsi%ld:%d: target reset issued\n", ha->host_no, - ddb_entry->fw_ddb_index)); - - /* - * Send target reset command to ISP, so that the ISP will return all - * outstanding requests with RESET status - */ - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_TARGET_WARM_RESET; - mbox_cmd[1] = ddb_entry->fw_ddb_index; - mbox_cmd[5] = 0x01; /* Immediate Command Enable */ - - qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], - &mbox_sts[0]); - if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE && - mbox_sts[0] != MBOX_STS_COMMAND_ERROR) - status = QLA_ERROR; - - return status; -} - -int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr, - uint32_t offset, uint32_t len) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_READ_FLASH; - mbox_cmd[1] = LSDW(dma_addr); - mbox_cmd[2] = MSDW(dma_addr); - mbox_cmd[3] = offset; - mbox_cmd[4] = len; - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 2, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ " - "status %04X %04X, offset %08x, len %08x\n", ha->host_no, - __func__, mbox_sts[0], mbox_sts[1], offset, len)); - return QLA_ERROR; - } - return QLA_SUCCESS; -} - -/** - * qla4xxx_about_firmware - gets FW, iscsi draft and boot loader version - * @ha: Pointer to host adapter structure. - * - * Retrieves the FW version, iSCSI draft version & bootloader version of HBA. - * Mailboxes 2 & 3 may hold an address for data. Make sure that we write 0 to - * those mailboxes, if unused. - **/ -int qla4xxx_about_firmware(struct scsi_qla_host *ha) -{ - struct about_fw_info *about_fw = NULL; - dma_addr_t about_fw_dma; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_ERROR; - - about_fw = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct about_fw_info), - &about_fw_dma, GFP_KERNEL); - if (!about_fw) { - DEBUG2(ql4_printk(KERN_ERR, ha, "%s: Unable to alloc memory " - "for about_fw\n", __func__)); - return status; - } - - memset(about_fw, 0, sizeof(struct about_fw_info)); - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_ABOUT_FW; - mbox_cmd[2] = LSDW(about_fw_dma); - mbox_cmd[3] = MSDW(about_fw_dma); - mbox_cmd[4] = sizeof(struct about_fw_info); - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, MBOX_REG_COUNT, - &mbox_cmd[0], &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_ABOUT_FW " - "failed w/ status %04X\n", __func__, - mbox_sts[0])); - goto exit_about_fw; - } - - /* Save version information. */ - ha->firmware_version[0] = le16_to_cpu(about_fw->fw_major); - ha->firmware_version[1] = le16_to_cpu(about_fw->fw_minor); - ha->patch_number = le16_to_cpu(about_fw->fw_patch); - ha->build_number = le16_to_cpu(about_fw->fw_build); - ha->iscsi_major = le16_to_cpu(about_fw->iscsi_major); - ha->iscsi_minor = le16_to_cpu(about_fw->iscsi_minor); - ha->bootload_major = le16_to_cpu(about_fw->bootload_major); - ha->bootload_minor = le16_to_cpu(about_fw->bootload_minor); - ha->bootload_patch = le16_to_cpu(about_fw->bootload_patch); - ha->bootload_build = le16_to_cpu(about_fw->bootload_build); - status = QLA_SUCCESS; - -exit_about_fw: - dma_free_coherent(&ha->pdev->dev, sizeof(struct about_fw_info), - about_fw, about_fw_dma); - return status; -} - -static int qla4xxx_get_default_ddb(struct scsi_qla_host *ha, uint32_t options, - dma_addr_t dma_addr) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS; - mbox_cmd[1] = options; - mbox_cmd[2] = LSDW(dma_addr); - mbox_cmd[3] = MSDW(dma_addr); - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], &mbox_sts[0]) != - QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: failed status %04X\n", - ha->host_no, __func__, mbox_sts[0])); - return QLA_ERROR; - } - return QLA_SUCCESS; -} - -int qla4xxx_req_ddb_entry(struct scsi_qla_host *ha, uint32_t ddb_index, - uint32_t *mbx_sts) -{ - int status; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY; - mbox_cmd[1] = ddb_index; - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], - &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n", - __func__, mbox_sts[0])); - } - - *mbx_sts = mbox_sts[0]; - return status; -} - -int qla4xxx_clear_ddb_entry(struct scsi_qla_host *ha, uint32_t ddb_index) -{ - int status; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY; - mbox_cmd[1] = ddb_index; - - status = qla4xxx_mailbox_command(ha, 2, 1, &mbox_cmd[0], - &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_ERR, ha, "%s: failed status %04X\n", - __func__, mbox_sts[0])); - } - - return status; -} - -int qla4xxx_set_flash(struct scsi_qla_host *ha, dma_addr_t dma_addr, - uint32_t offset, uint32_t length, uint32_t options) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_SUCCESS; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_WRITE_FLASH; - mbox_cmd[1] = LSDW(dma_addr); - mbox_cmd[2] = MSDW(dma_addr); - mbox_cmd[3] = offset; - mbox_cmd[4] = length; - mbox_cmd[5] = options; - - status = qla4xxx_mailbox_command(ha, 6, 2, &mbox_cmd[0], &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_WRITE_FLASH " - "failed w/ status %04X, mbx1 %04X\n", - __func__, mbox_sts[0], mbox_sts[1])); - } - return status; -} - -int qla4xxx_bootdb_by_index(struct scsi_qla_host *ha, - struct dev_db_entry *fw_ddb_entry, - dma_addr_t fw_ddb_entry_dma, uint16_t ddb_index) -{ - uint32_t dev_db_start_offset = FLASH_OFFSET_DB_INFO; - uint32_t dev_db_end_offset; - int status = QLA_ERROR; - - memset(fw_ddb_entry, 0, sizeof(*fw_ddb_entry)); - - dev_db_start_offset += (ddb_index * sizeof(*fw_ddb_entry)); - dev_db_end_offset = FLASH_OFFSET_DB_END; - - if (dev_db_start_offset > dev_db_end_offset) { - DEBUG2(ql4_printk(KERN_ERR, ha, - "%s:Invalid DDB index %d", __func__, - ddb_index)); - goto exit_bootdb_failed; - } - - if (qla4xxx_get_flash(ha, fw_ddb_entry_dma, dev_db_start_offset, - sizeof(*fw_ddb_entry)) != QLA_SUCCESS) { - ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash" - "failed\n", ha->host_no, __func__); - goto exit_bootdb_failed; - } - - if (fw_ddb_entry->cookie == DDB_VALID_COOKIE) - status = QLA_SUCCESS; - -exit_bootdb_failed: - return status; -} - -int qla4xxx_get_chap(struct scsi_qla_host *ha, char *username, char *password, - uint16_t idx) -{ - int ret = 0; - int rval = QLA_ERROR; - uint32_t offset = 0, chap_size; - struct ql4_chap_table *chap_table; - dma_addr_t chap_dma; - - chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); - if (chap_table == NULL) { - ret = -ENOMEM; - goto exit_get_chap; - } - - chap_size = sizeof(struct ql4_chap_table); - memset(chap_table, 0, chap_size); - - if (is_qla40XX(ha)) - offset = FLASH_CHAP_OFFSET | (idx * chap_size); - else { - offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); - /* flt_chap_size is CHAP table size for both ports - * so divide it by 2 to calculate the offset for second port - */ - if (ha->port_num == 1) - offset += (ha->hw.flt_chap_size / 2); - offset += (idx * chap_size); - } - - rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); - if (rval != QLA_SUCCESS) { - ret = -EINVAL; - goto exit_get_chap; - } - - DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n", - __le16_to_cpu(chap_table->cookie))); - - if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) { - ql4_printk(KERN_ERR, ha, "No valid chap entry found\n"); - goto exit_get_chap; - } - - strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN); - strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN); - chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE); - -exit_get_chap: - dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma); - return ret; -} - -static int qla4xxx_set_chap(struct scsi_qla_host *ha, char *username, - char *password, uint16_t idx, int bidi) -{ - int ret = 0; - int rval = QLA_ERROR; - uint32_t offset = 0; - struct ql4_chap_table *chap_table; - dma_addr_t chap_dma; - - chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); - if (chap_table == NULL) { - ret = -ENOMEM; - goto exit_set_chap; - } - - memset(chap_table, 0, sizeof(struct ql4_chap_table)); - if (bidi) - chap_table->flags |= BIT_6; /* peer */ - else - chap_table->flags |= BIT_7; /* local */ - chap_table->secret_len = strlen(password); - strncpy(chap_table->secret, password, MAX_CHAP_SECRET_LEN); - strncpy(chap_table->name, username, MAX_CHAP_NAME_LEN); - chap_table->cookie = __constant_cpu_to_le16(CHAP_VALID_COOKIE); - offset = FLASH_CHAP_OFFSET | (idx * sizeof(struct ql4_chap_table)); - rval = qla4xxx_set_flash(ha, chap_dma, offset, - sizeof(struct ql4_chap_table), - FLASH_OPT_RMW_COMMIT); - - if (rval == QLA_SUCCESS && ha->chap_list) { - /* Update ha chap_list cache */ - memcpy((struct ql4_chap_table *)ha->chap_list + idx, - chap_table, sizeof(struct ql4_chap_table)); - } - dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma); - if (rval != QLA_SUCCESS) - ret = -EINVAL; - -exit_set_chap: - return ret; -} - -/** - * qla4xxx_get_chap_index - Get chap index given username and secret - * @ha: pointer to adapter structure - * @username: CHAP username to be searched - * @password: CHAP password to be searched - * @bidi: Is this a BIDI CHAP - * @chap_index: CHAP index to be returned - * - * Match the username and password in the chap_list, return the index if a - * match is found. If a match is not found then add the entry in FLASH and - * return the index at which entry is written in the FLASH. - **/ -int qla4xxx_get_chap_index(struct scsi_qla_host *ha, char *username, - char *password, int bidi, uint16_t *chap_index) -{ - int i, rval; - int free_index = -1; - int found_index = 0; - int max_chap_entries = 0; - struct ql4_chap_table *chap_table; - - if (is_qla8022(ha)) - max_chap_entries = (ha->hw.flt_chap_size / 2) / - sizeof(struct ql4_chap_table); - else - max_chap_entries = MAX_CHAP_ENTRIES_40XX; - - if (!ha->chap_list) { - ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n"); - return QLA_ERROR; - } - - if (!username || !password) { - ql4_printk(KERN_ERR, ha, "Do not have username and psw\n"); - return QLA_ERROR; - } - - mutex_lock(&ha->chap_sem); - for (i = 0; i < max_chap_entries; i++) { - chap_table = (struct ql4_chap_table *)ha->chap_list + i; - if (chap_table->cookie != - __constant_cpu_to_le16(CHAP_VALID_COOKIE)) { - if (i > MAX_RESRV_CHAP_IDX && free_index == -1) - free_index = i; - continue; - } - if (bidi) { - if (chap_table->flags & BIT_7) - continue; - } else { - if (chap_table->flags & BIT_6) - continue; - } - if (!strncmp(chap_table->secret, password, - MAX_CHAP_SECRET_LEN) && - !strncmp(chap_table->name, username, - MAX_CHAP_NAME_LEN)) { - *chap_index = i; - found_index = 1; - break; - } - } - - /* If chap entry is not present and a free index is available then - * write the entry in flash - */ - if (!found_index && free_index != -1) { - rval = qla4xxx_set_chap(ha, username, password, - free_index, bidi); - if (!rval) { - *chap_index = free_index; - found_index = 1; - } - } - - mutex_unlock(&ha->chap_sem); - - if (found_index) - return QLA_SUCCESS; - return QLA_ERROR; -} - -int qla4xxx_conn_close_sess_logout(struct scsi_qla_host *ha, - uint16_t fw_ddb_index, - uint16_t connection_id, - uint16_t option) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_SUCCESS; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT; - mbox_cmd[1] = fw_ddb_index; - mbox_cmd[2] = connection_id; - mbox_cmd[3] = option; - - status = qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_CONN_CLOSE " - "option %04x failed w/ status %04X %04X\n", - __func__, option, mbox_sts[0], mbox_sts[1])); - } - return status; -} - -int qla4xxx_disable_acb(struct scsi_qla_host *ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_SUCCESS; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_DISABLE_ACB; - - status = qla4xxx_mailbox_command(ha, 8, 5, &mbox_cmd[0], &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_DISABLE_ACB " - "failed w/ status %04X %04X %04X", __func__, - mbox_sts[0], mbox_sts[1], mbox_sts[2])); - } - return status; -} - -int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t acb_dma, - uint32_t acb_type, uint32_t len) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_SUCCESS; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_GET_ACB; - mbox_cmd[1] = acb_type; - mbox_cmd[2] = LSDW(acb_dma); - mbox_cmd[3] = MSDW(acb_dma); - mbox_cmd[4] = len; - - status = qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_GET_ACB " - "failed w/ status %04X\n", __func__, - mbox_sts[0])); - } - return status; -} - -int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd, - uint32_t *mbox_sts, dma_addr_t acb_dma) -{ - int status = QLA_SUCCESS; - - memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); - memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); - mbox_cmd[0] = MBOX_CMD_SET_ACB; - mbox_cmd[1] = 0; /* Primary ACB */ - mbox_cmd[2] = LSDW(acb_dma); - mbox_cmd[3] = MSDW(acb_dma); - mbox_cmd[4] = sizeof(struct addr_ctrl_blk); - - status = qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: MBOX_CMD_SET_ACB " - "failed w/ status %04X\n", __func__, - mbox_sts[0])); - } - return status; -} - -int qla4xxx_set_param_ddbentry(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, - struct iscsi_cls_conn *cls_conn, - uint32_t *mbx_sts) -{ - struct dev_db_entry *fw_ddb_entry; - struct iscsi_conn *conn; - struct iscsi_session *sess; - struct qla_conn *qla_conn; - struct sockaddr *dst_addr; - dma_addr_t fw_ddb_entry_dma; - int status = QLA_SUCCESS; - int rval = 0; - struct sockaddr_in *addr; - struct sockaddr_in6 *addr6; - char *ip; - uint16_t iscsi_opts = 0; - uint32_t options = 0; - uint16_t idx, *ptid; - - fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - &fw_ddb_entry_dma, GFP_KERNEL); - if (!fw_ddb_entry) { - DEBUG2(ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer.\n", - __func__)); - rval = -ENOMEM; - goto exit_set_param_no_free; - } - - conn = cls_conn->dd_data; - qla_conn = conn->dd_data; - sess = conn->session; - dst_addr = &qla_conn->qla_ep->dst_addr; - - if (dst_addr->sa_family == AF_INET6) - options |= IPV6_DEFAULT_DDB_ENTRY; - - status = qla4xxx_get_default_ddb(ha, options, fw_ddb_entry_dma); - if (status == QLA_ERROR) { - rval = -EINVAL; - goto exit_set_param; - } - - ptid = (uint16_t *)&fw_ddb_entry->isid[1]; - *ptid = cpu_to_le16((uint16_t)ddb_entry->sess->target_id); - - DEBUG2(ql4_printk(KERN_INFO, ha, "ISID [%02x%02x%02x%02x%02x%02x]\n", - fw_ddb_entry->isid[5], fw_ddb_entry->isid[4], - fw_ddb_entry->isid[3], fw_ddb_entry->isid[2], - fw_ddb_entry->isid[1], fw_ddb_entry->isid[0])); - - iscsi_opts = le16_to_cpu(fw_ddb_entry->iscsi_options); - memset(fw_ddb_entry->iscsi_alias, 0, sizeof(fw_ddb_entry->iscsi_alias)); - - memset(fw_ddb_entry->iscsi_name, 0, sizeof(fw_ddb_entry->iscsi_name)); - - if (sess->targetname != NULL) { - memcpy(fw_ddb_entry->iscsi_name, sess->targetname, - min(strlen(sess->targetname), - sizeof(fw_ddb_entry->iscsi_name))); - } - - memset(fw_ddb_entry->ip_addr, 0, sizeof(fw_ddb_entry->ip_addr)); - memset(fw_ddb_entry->tgt_addr, 0, sizeof(fw_ddb_entry->tgt_addr)); - - fw_ddb_entry->options = DDB_OPT_TARGET | DDB_OPT_AUTO_SENDTGTS_DISABLE; - - if (dst_addr->sa_family == AF_INET) { - addr = (struct sockaddr_in *)dst_addr; - ip = (char *)&addr->sin_addr; - memcpy(fw_ddb_entry->ip_addr, ip, IP_ADDR_LEN); - fw_ddb_entry->port = cpu_to_le16(ntohs(addr->sin_port)); - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: Destination Address [%pI4]: index [%d]\n", - __func__, fw_ddb_entry->ip_addr, - ddb_entry->fw_ddb_index)); - } else if (dst_addr->sa_family == AF_INET6) { - addr6 = (struct sockaddr_in6 *)dst_addr; - ip = (char *)&addr6->sin6_addr; - memcpy(fw_ddb_entry->ip_addr, ip, IPv6_ADDR_LEN); - fw_ddb_entry->port = cpu_to_le16(ntohs(addr6->sin6_port)); - fw_ddb_entry->options |= DDB_OPT_IPV6_DEVICE; - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: Destination Address [%pI6]: index [%d]\n", - __func__, fw_ddb_entry->ip_addr, - ddb_entry->fw_ddb_index)); - } else { - ql4_printk(KERN_ERR, ha, - "%s: Failed to get IP Address\n", - __func__); - rval = -EINVAL; - goto exit_set_param; - } - - /* CHAP */ - if (sess->username != NULL && sess->password != NULL) { - if (strlen(sess->username) && strlen(sess->password)) { - iscsi_opts |= BIT_7; - - rval = qla4xxx_get_chap_index(ha, sess->username, - sess->password, - LOCAL_CHAP, &idx); - if (rval) - goto exit_set_param; - - fw_ddb_entry->chap_tbl_idx = cpu_to_le16(idx); - } - } - - if (sess->username_in != NULL && sess->password_in != NULL) { - /* Check if BIDI CHAP */ - if (strlen(sess->username_in) && strlen(sess->password_in)) { - iscsi_opts |= BIT_4; - - rval = qla4xxx_get_chap_index(ha, sess->username_in, - sess->password_in, - BIDI_CHAP, &idx); - if (rval) - goto exit_set_param; - } - } - - if (sess->initial_r2t_en) - iscsi_opts |= BIT_10; - - if (sess->imm_data_en) - iscsi_opts |= BIT_11; - - fw_ddb_entry->iscsi_options = cpu_to_le16(iscsi_opts); - - if (conn->max_recv_dlength) - fw_ddb_entry->iscsi_max_rcv_data_seg_len = - __constant_cpu_to_le16((conn->max_recv_dlength / BYTE_UNITS)); - - if (sess->max_r2t) - fw_ddb_entry->iscsi_max_outsnd_r2t = cpu_to_le16(sess->max_r2t); - - if (sess->first_burst) - fw_ddb_entry->iscsi_first_burst_len = - __constant_cpu_to_le16((sess->first_burst / BYTE_UNITS)); - - if (sess->max_burst) - fw_ddb_entry->iscsi_max_burst_len = - __constant_cpu_to_le16((sess->max_burst / BYTE_UNITS)); - - if (sess->time2wait) - fw_ddb_entry->iscsi_def_time2wait = - cpu_to_le16(sess->time2wait); - - if (sess->time2retain) - fw_ddb_entry->iscsi_def_time2retain = - cpu_to_le16(sess->time2retain); - - status = qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, - fw_ddb_entry_dma, mbx_sts); - - if (status != QLA_SUCCESS) - rval = -EINVAL; -exit_set_param: - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); -exit_set_param_no_free: - return rval; -} - -int qla4xxx_get_mgmt_data(struct scsi_qla_host *ha, uint16_t fw_ddb_index, - uint16_t stats_size, dma_addr_t stats_dma) -{ - int status = QLA_SUCCESS; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(mbox_cmd, 0, sizeof(mbox_cmd[0]) * MBOX_REG_COUNT); - memset(mbox_sts, 0, sizeof(mbox_sts[0]) * MBOX_REG_COUNT); - mbox_cmd[0] = MBOX_CMD_GET_MANAGEMENT_DATA; - mbox_cmd[1] = fw_ddb_index; - mbox_cmd[2] = LSDW(stats_dma); - mbox_cmd[3] = MSDW(stats_dma); - mbox_cmd[4] = stats_size; - - status = qla4xxx_mailbox_command(ha, 5, 1, &mbox_cmd[0], &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_WARNING, ha, - "%s: MBOX_CMD_GET_MANAGEMENT_DATA " - "failed w/ status %04X\n", __func__, - mbox_sts[0])); - } - return status; -} - -int qla4xxx_get_ip_state(struct scsi_qla_host *ha, uint32_t acb_idx, - uint32_t ip_idx, uint32_t *sts) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - int status = QLA_SUCCESS; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - mbox_cmd[0] = MBOX_CMD_GET_IP_ADDR_STATE; - mbox_cmd[1] = acb_idx; - mbox_cmd[2] = ip_idx; - - status = qla4xxx_mailbox_command(ha, 3, 8, &mbox_cmd[0], &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_WARNING, ha, "%s: " - "MBOX_CMD_GET_IP_ADDR_STATE failed w/ " - "status %04X\n", __func__, mbox_sts[0])); - } - memcpy(sts, mbox_sts, sizeof(mbox_sts)); - return status; -} - -int qla4xxx_get_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, - uint32_t offset, uint32_t size) -{ - int status = QLA_SUCCESS; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_GET_NVRAM; - mbox_cmd[1] = LSDW(nvram_dma); - mbox_cmd[2] = MSDW(nvram_dma); - mbox_cmd[3] = offset; - mbox_cmd[4] = size; - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], - &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " - "status %04X\n", ha->host_no, __func__, - mbox_sts[0])); - } - return status; -} - -int qla4xxx_set_nvram(struct scsi_qla_host *ha, dma_addr_t nvram_dma, - uint32_t offset, uint32_t size) -{ - int status = QLA_SUCCESS; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_SET_NVRAM; - mbox_cmd[1] = LSDW(nvram_dma); - mbox_cmd[2] = MSDW(nvram_dma); - mbox_cmd[3] = offset; - mbox_cmd[4] = size; - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], - &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " - "status %04X\n", ha->host_no, __func__, - mbox_sts[0])); - } - return status; -} - -int qla4xxx_restore_factory_defaults(struct scsi_qla_host *ha, - uint32_t region, uint32_t field0, - uint32_t field1) -{ - int status = QLA_SUCCESS; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_RESTORE_FACTORY_DEFAULTS; - mbox_cmd[3] = region; - mbox_cmd[4] = field0; - mbox_cmd[5] = field1; - - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 3, &mbox_cmd[0], - &mbox_sts[0]); - if (status != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " - "status %04X\n", ha->host_no, __func__, - mbox_sts[0])); - } - return status; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.c deleted file mode 100644 index 7851f314..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#include "ql4_def.h" -#include "ql4_glbl.h" -#include "ql4_dbg.h" -#include "ql4_inline.h" - -static inline void eeprom_cmd(uint32_t cmd, struct scsi_qla_host *ha) -{ - writel(cmd, isp_nvram(ha)); - readl(isp_nvram(ha)); - udelay(1); -} - -static inline int eeprom_size(struct scsi_qla_host *ha) -{ - return is_qla4010(ha) ? FM93C66A_SIZE_16 : FM93C86A_SIZE_16; -} - -static inline int eeprom_no_addr_bits(struct scsi_qla_host *ha) -{ - return is_qla4010(ha) ? FM93C56A_NO_ADDR_BITS_16 : - FM93C86A_NO_ADDR_BITS_16 ; -} - -static inline int eeprom_no_data_bits(struct scsi_qla_host *ha) -{ - return FM93C56A_DATA_BITS_16; -} - -static int fm93c56a_select(struct scsi_qla_host * ha) -{ - DEBUG5(printk(KERN_ERR "fm93c56a_select:\n")); - - ha->eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000; - eeprom_cmd(ha->eeprom_cmd_data, ha); - return 1; -} - -static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr) -{ - int i; - int mask; - int dataBit; - int previousBit; - - /* Clock in a zero, then do the start bit. */ - eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, ha); - - eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 | - AUBURN_EEPROM_CLK_RISE, ha); - eeprom_cmd(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 | - AUBURN_EEPROM_CLK_FALL, ha); - - mask = 1 << (FM93C56A_CMD_BITS - 1); - - /* Force the previous data bit to be different. */ - previousBit = 0xffff; - for (i = 0; i < FM93C56A_CMD_BITS; i++) { - dataBit = - (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0; - if (previousBit != dataBit) { - - /* - * If the bit changed, then change the DO state to - * match. - */ - eeprom_cmd(ha->eeprom_cmd_data | dataBit, ha); - previousBit = dataBit; - } - eeprom_cmd(ha->eeprom_cmd_data | dataBit | - AUBURN_EEPROM_CLK_RISE, ha); - eeprom_cmd(ha->eeprom_cmd_data | dataBit | - AUBURN_EEPROM_CLK_FALL, ha); - - cmd = cmd << 1; - } - mask = 1 << (eeprom_no_addr_bits(ha) - 1); - - /* Force the previous data bit to be different. */ - previousBit = 0xffff; - for (i = 0; i < eeprom_no_addr_bits(ha); i++) { - dataBit = addr & mask ? AUBURN_EEPROM_DO_1 : - AUBURN_EEPROM_DO_0; - if (previousBit != dataBit) { - /* - * If the bit changed, then change the DO state to - * match. - */ - eeprom_cmd(ha->eeprom_cmd_data | dataBit, ha); - - previousBit = dataBit; - } - eeprom_cmd(ha->eeprom_cmd_data | dataBit | - AUBURN_EEPROM_CLK_RISE, ha); - eeprom_cmd(ha->eeprom_cmd_data | dataBit | - AUBURN_EEPROM_CLK_FALL, ha); - - addr = addr << 1; - } - return 1; -} - -static int fm93c56a_deselect(struct scsi_qla_host * ha) -{ - ha->eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000; - eeprom_cmd(ha->eeprom_cmd_data, ha); - return 1; -} - -static int fm93c56a_datain(struct scsi_qla_host * ha, unsigned short *value) -{ - int i; - int data = 0; - int dataBit; - - /* Read the data bits - * The first bit is a dummy. Clock right over it. */ - for (i = 0; i < eeprom_no_data_bits(ha); i++) { - eeprom_cmd(ha->eeprom_cmd_data | - AUBURN_EEPROM_CLK_RISE, ha); - eeprom_cmd(ha->eeprom_cmd_data | - AUBURN_EEPROM_CLK_FALL, ha); - - dataBit = (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0; - - data = (data << 1) | dataBit; - } - - *value = data; - return 1; -} - -static int eeprom_readword(int eepromAddr, u16 * value, - struct scsi_qla_host * ha) -{ - fm93c56a_select(ha); - fm93c56a_cmd(ha, FM93C56A_READ, eepromAddr); - fm93c56a_datain(ha, value); - fm93c56a_deselect(ha); - return 1; -} - -/* Hardware_lock must be set before calling */ -u16 rd_nvram_word(struct scsi_qla_host * ha, int offset) -{ - u16 val = 0; - - /* NOTE: NVRAM uses half-word addresses */ - eeprom_readword(offset, &val, ha); - return val; -} - -u8 rd_nvram_byte(struct scsi_qla_host *ha, int offset) -{ - u16 val = 0; - u8 rval = 0; - int index = 0; - - if (offset & 0x1) - index = (offset - 1) / 2; - else - index = offset / 2; - - val = le16_to_cpu(rd_nvram_word(ha, index)); - - if (offset & 0x1) - rval = (u8)((val & 0xff00) >> 8); - else - rval = (u8)((val & 0x00ff)); - - return rval; -} - -int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha) -{ - int status = QLA_ERROR; - uint16_t checksum = 0; - uint32_t index; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (index = 0; index < eeprom_size(ha); index++) - checksum += rd_nvram_word(ha, index); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (checksum == 0) - status = QLA_SUCCESS; - - return status; -} - -/************************************************************************* - * - * Hardware Semaphore routines - * - *************************************************************************/ -int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits) -{ - uint32_t value; - unsigned long flags; - unsigned int seconds = 30; - - DEBUG2(printk("scsi%ld : Trying to get SEM lock - mask= 0x%x, code = " - "0x%x\n", ha->host_no, sem_mask, sem_bits)); - do { - spin_lock_irqsave(&ha->hardware_lock, flags); - writel((sem_mask | sem_bits), isp_semaphore(ha)); - value = readw(isp_semaphore(ha)); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if ((value & (sem_mask >> 16)) == sem_bits) { - DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, " - "code = 0x%x\n", ha->host_no, - sem_mask, sem_bits)); - return QLA_SUCCESS; - } - ssleep(1); - } while (--seconds); - return QLA_ERROR; -} - -void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask) -{ - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - writel(sem_mask, isp_semaphore(ha)); - readl(isp_semaphore(ha)); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - DEBUG2(printk("scsi%ld : UNLOCK SEM - mask= 0x%x\n", ha->host_no, - sem_mask)); -} - -int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits) -{ - uint32_t value; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - writel((sem_mask | sem_bits), isp_semaphore(ha)); - value = readw(isp_semaphore(ha)); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - if ((value & (sem_mask >> 16)) == sem_bits) { - DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, code = " - "0x%x, sema code=0x%x\n", ha->host_no, - sem_mask, sem_bits, value)); - return 1; - } - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.h deleted file mode 100644 index 945cc328..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nvram.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#ifndef _QL4XNVRM_H_ -#define _QL4XNVRM_H_ - -/** - * AM29LV Flash definitions - **/ -#define FM93C56A_SIZE_8 0x100 -#define FM93C56A_SIZE_16 0x80 -#define FM93C66A_SIZE_8 0x200 -#define FM93C66A_SIZE_16 0x100/* 4010 */ -#define FM93C86A_SIZE_16 0x400/* 4022 */ - -#define FM93C56A_START 0x1 - -/* Commands */ -#define FM93C56A_READ 0x2 -#define FM93C56A_WEN 0x0 -#define FM93C56A_WRITE 0x1 -#define FM93C56A_WRITE_ALL 0x0 -#define FM93C56A_WDS 0x0 -#define FM93C56A_ERASE 0x3 -#define FM93C56A_ERASE_ALL 0x0 - -/* Command Extensions */ -#define FM93C56A_WEN_EXT 0x3 -#define FM93C56A_WRITE_ALL_EXT 0x1 -#define FM93C56A_WDS_EXT 0x0 -#define FM93C56A_ERASE_ALL_EXT 0x2 - -/* Address Bits */ -#define FM93C56A_NO_ADDR_BITS_16 8 /* 4010 */ -#define FM93C56A_NO_ADDR_BITS_8 9 /* 4010 */ -#define FM93C86A_NO_ADDR_BITS_16 10 /* 4022 */ - -/* Data Bits */ -#define FM93C56A_DATA_BITS_16 16 -#define FM93C56A_DATA_BITS_8 8 - -/* Special Bits */ -#define FM93C56A_READ_DUMMY_BITS 1 -#define FM93C56A_READY 0 -#define FM93C56A_BUSY 1 -#define FM93C56A_CMD_BITS 2 - -/* Auburn Bits */ -#define AUBURN_EEPROM_DI 0x8 -#define AUBURN_EEPROM_DI_0 0x0 -#define AUBURN_EEPROM_DI_1 0x8 -#define AUBURN_EEPROM_DO 0x4 -#define AUBURN_EEPROM_DO_0 0x0 -#define AUBURN_EEPROM_DO_1 0x4 -#define AUBURN_EEPROM_CS 0x2 -#define AUBURN_EEPROM_CS_0 0x0 -#define AUBURN_EEPROM_CS_1 0x2 -#define AUBURN_EEPROM_CLK_RISE 0x1 -#define AUBURN_EEPROM_CLK_FALL 0x0 - -/**/ -/* EEPROM format */ -/**/ -struct bios_params { - uint16_t SpinUpDelay:1; - uint16_t BIOSDisable:1; - uint16_t MMAPEnable:1; - uint16_t BootEnable:1; - uint16_t Reserved0:12; - uint8_t bootID0:7; - uint8_t bootID0Valid:1; - uint8_t bootLUN0[8]; - uint8_t bootID1:7; - uint8_t bootID1Valid:1; - uint8_t bootLUN1[8]; - uint16_t MaxLunsPerTarget; - uint8_t Reserved1[10]; -}; - -struct eeprom_port_cfg { - - /* MTU MAC 0 */ - u16 etherMtu_mac; - - /* Flow Control MAC 0 */ - u16 pauseThreshold_mac; - u16 resumeThreshold_mac; - u16 reserved[13]; -}; - -struct eeprom_function_cfg { - u8 reserved[30]; - - /* MAC ADDR */ - u8 macAddress[6]; - u8 macAddressSecondary[6]; - u16 subsysVendorId; - u16 subsysDeviceId; -}; - -struct eeprom_data { - union { - struct { /* isp4010 */ - u8 asic_id[4]; /* x00 */ - u8 version; /* x04 */ - u8 reserved; /* x05 */ - u16 board_id; /* x06 */ -#define EEPROM_BOARDID_ELDORADO 1 -#define EEPROM_BOARDID_PLACER 2 - -#define EEPROM_SERIAL_NUM_SIZE 16 - u8 serial_number[EEPROM_SERIAL_NUM_SIZE]; /* x08 */ - - /* ExtHwConfig: */ - /* Offset = 24bytes - * - * | SSRAM Size| |ST|PD|SDRAM SZ| W| B| SP | | - * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0| - * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - */ - u16 ext_hw_conf; /* x18 */ - u8 mac0[6]; /* x1A */ - u8 mac1[6]; /* x20 */ - u8 mac2[6]; /* x26 */ - u8 mac3[6]; /* x2C */ - u16 etherMtu; /* x32 */ - u16 macConfig; /* x34 */ -#define MAC_CONFIG_ENABLE_ANEG 0x0001 -#define MAC_CONFIG_ENABLE_PAUSE 0x0002 - u16 phyConfig; /* x36 */ -#define PHY_CONFIG_PHY_ADDR_MASK 0x1f -#define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20 - u16 reserved_56; /* x38 */ - -#define EEPROM_UNUSED_1_SIZE 2 - u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */ - u16 bufletSize; /* x3C */ - u16 bufletCount; /* x3E */ - u16 bufletPauseThreshold; /* x40 */ - u16 tcpWindowThreshold50; /* x42 */ - u16 tcpWindowThreshold25; /* x44 */ - u16 tcpWindowThreshold0; /* x46 */ - u16 ipHashTableBaseHi; /* x48 */ - u16 ipHashTableBaseLo; /* x4A */ - u16 ipHashTableSize; /* x4C */ - u16 tcpHashTableBaseHi; /* x4E */ - u16 tcpHashTableBaseLo; /* x50 */ - u16 tcpHashTableSize; /* x52 */ - u16 ncbTableBaseHi; /* x54 */ - u16 ncbTableBaseLo; /* x56 */ - u16 ncbTableSize; /* x58 */ - u16 drbTableBaseHi; /* x5A */ - u16 drbTableBaseLo; /* x5C */ - u16 drbTableSize; /* x5E */ - -#define EEPROM_UNUSED_2_SIZE 4 - u8 unused_2[EEPROM_UNUSED_2_SIZE]; /* x60 */ - u16 ipReassemblyTimeout; /* x64 */ - u16 tcpMaxWindowSizeHi; /* x66 */ - u16 tcpMaxWindowSizeLo; /* x68 */ - u32 net_ip_addr0; /* x6A Added for TOE - * functionality. */ - u32 net_ip_addr1; /* x6E */ - u32 scsi_ip_addr0; /* x72 */ - u32 scsi_ip_addr1; /* x76 */ -#define EEPROM_UNUSED_3_SIZE 128 /* changed from 144 to account - * for ip addresses */ - u8 unused_3[EEPROM_UNUSED_3_SIZE]; /* x7A */ - u16 subsysVendorId_f0; /* xFA */ - u16 subsysDeviceId_f0; /* xFC */ - - /* Address = 0x7F */ -#define FM93C56A_SIGNATURE 0x9356 -#define FM93C66A_SIGNATURE 0x9366 - u16 signature; /* xFE */ - -#define EEPROM_UNUSED_4_SIZE 250 - u8 unused_4[EEPROM_UNUSED_4_SIZE]; /* x100 */ - u16 subsysVendorId_f1; /* x1FA */ - u16 subsysDeviceId_f1; /* x1FC */ - u16 checksum; /* x1FE */ - } __attribute__ ((packed)) isp4010; - struct { /* isp4022 */ - u8 asicId[4]; /* x00 */ - u8 version; /* x04 */ - u8 reserved_5; /* x05 */ - u16 boardId; /* x06 */ - u8 boardIdStr[16]; /* x08 */ - u8 serialNumber[16]; /* x18 */ - - /* External Hardware Configuration */ - u16 ext_hw_conf; /* x28 */ - - /* MAC 0 CONFIGURATION */ - struct eeprom_port_cfg macCfg_port0; /* x2A */ - - /* MAC 1 CONFIGURATION */ - struct eeprom_port_cfg macCfg_port1; /* x4A */ - - /* DDR SDRAM Configuration */ - u16 bufletSize; /* x6A */ - u16 bufletCount; /* x6C */ - u16 tcpWindowThreshold50; /* x6E */ - u16 tcpWindowThreshold25; /* x70 */ - u16 tcpWindowThreshold0; /* x72 */ - u16 ipHashTableBaseHi; /* x74 */ - u16 ipHashTableBaseLo; /* x76 */ - u16 ipHashTableSize; /* x78 */ - u16 tcpHashTableBaseHi; /* x7A */ - u16 tcpHashTableBaseLo; /* x7C */ - u16 tcpHashTableSize; /* x7E */ - u16 ncbTableBaseHi; /* x80 */ - u16 ncbTableBaseLo; /* x82 */ - u16 ncbTableSize; /* x84 */ - u16 drbTableBaseHi; /* x86 */ - u16 drbTableBaseLo; /* x88 */ - u16 drbTableSize; /* x8A */ - u16 reserved_142[4]; /* x8C */ - - /* TCP/IP Parameters */ - u16 ipReassemblyTimeout; /* x94 */ - u16 tcpMaxWindowSize; /* x96 */ - u16 ipSecurity; /* x98 */ - u8 reserved_156[294]; /* x9A */ - u16 qDebug[8]; /* QLOGIC USE ONLY x1C0 */ - struct eeprom_function_cfg funcCfg_fn0; /* x1D0 */ - u16 reserved_510; /* x1FE */ - - /* Address = 512 */ - u8 oemSpace[432]; /* x200 */ - struct bios_params sBIOSParams_fn1; /* x3B0 */ - struct eeprom_function_cfg funcCfg_fn1; /* x3D0 */ - u16 reserved_1022; /* x3FE */ - - /* Address = 1024 */ - u8 reserved_1024[464]; /* x400 */ - struct eeprom_function_cfg funcCfg_fn2; /* x5D0 */ - u16 reserved_1534; /* x5FE */ - - /* Address = 1536 */ - u8 reserved_1536[432]; /* x600 */ - struct bios_params sBIOSParams_fn3; /* x7B0 */ - struct eeprom_function_cfg funcCfg_fn3; /* x7D0 */ - u16 checksum; /* x7FE */ - } __attribute__ ((packed)) isp4022; - }; -}; - - -#endif /* _QL4XNVRM_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.c deleted file mode 100644 index e1e46b6d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.c +++ /dev/null @@ -1,2420 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ -#include -#include -#include -#include "ql4_def.h" -#include "ql4_glbl.h" - -#include - -#define MASK(n) DMA_BIT_MASK(n) -#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff)) -#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff)) -#define MS_WIN(addr) (addr & 0x0ffc0000) -#define QLA82XX_PCI_MN_2M (0) -#define QLA82XX_PCI_MS_2M (0x80000) -#define QLA82XX_PCI_OCM0_2M (0xc0000) -#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800) -#define GET_MEM_OFFS_2M(addr) (addr & MASK(18)) - -/* CRB window related */ -#define CRB_BLK(off) ((off >> 20) & 0x3f) -#define CRB_SUBBLK(off) ((off >> 16) & 0xf) -#define CRB_WINDOW_2M (0x130060) -#define CRB_HI(off) ((qla4_8xxx_crb_hub_agt[CRB_BLK(off)] << 20) | \ - ((off) & 0xf0000)) -#define QLA82XX_PCI_CAMQM_2M_END (0x04800800UL) -#define QLA82XX_PCI_CAMQM_2M_BASE (0x000ff800UL) -#define CRB_INDIRECT_2M (0x1e0000UL) - -static inline void __iomem * -qla4_8xxx_pci_base_offsetfset(struct scsi_qla_host *ha, unsigned long off) -{ - if ((off < ha->first_page_group_end) && - (off >= ha->first_page_group_start)) - return (void __iomem *)(ha->nx_pcibase + off); - - return NULL; -} - -#define MAX_CRB_XFORM 60 -static unsigned long crb_addr_xform[MAX_CRB_XFORM]; -static int qla4_8xxx_crb_table_initialized; - -#define qla4_8xxx_crb_addr_transform(name) \ - (crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \ - QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20) -static void -qla4_8xxx_crb_addr_transform_setup(void) -{ - qla4_8xxx_crb_addr_transform(XDMA); - qla4_8xxx_crb_addr_transform(TIMR); - qla4_8xxx_crb_addr_transform(SRE); - qla4_8xxx_crb_addr_transform(SQN3); - qla4_8xxx_crb_addr_transform(SQN2); - qla4_8xxx_crb_addr_transform(SQN1); - qla4_8xxx_crb_addr_transform(SQN0); - qla4_8xxx_crb_addr_transform(SQS3); - qla4_8xxx_crb_addr_transform(SQS2); - qla4_8xxx_crb_addr_transform(SQS1); - qla4_8xxx_crb_addr_transform(SQS0); - qla4_8xxx_crb_addr_transform(RPMX7); - qla4_8xxx_crb_addr_transform(RPMX6); - qla4_8xxx_crb_addr_transform(RPMX5); - qla4_8xxx_crb_addr_transform(RPMX4); - qla4_8xxx_crb_addr_transform(RPMX3); - qla4_8xxx_crb_addr_transform(RPMX2); - qla4_8xxx_crb_addr_transform(RPMX1); - qla4_8xxx_crb_addr_transform(RPMX0); - qla4_8xxx_crb_addr_transform(ROMUSB); - qla4_8xxx_crb_addr_transform(SN); - qla4_8xxx_crb_addr_transform(QMN); - qla4_8xxx_crb_addr_transform(QMS); - qla4_8xxx_crb_addr_transform(PGNI); - qla4_8xxx_crb_addr_transform(PGND); - qla4_8xxx_crb_addr_transform(PGN3); - qla4_8xxx_crb_addr_transform(PGN2); - qla4_8xxx_crb_addr_transform(PGN1); - qla4_8xxx_crb_addr_transform(PGN0); - qla4_8xxx_crb_addr_transform(PGSI); - qla4_8xxx_crb_addr_transform(PGSD); - qla4_8xxx_crb_addr_transform(PGS3); - qla4_8xxx_crb_addr_transform(PGS2); - qla4_8xxx_crb_addr_transform(PGS1); - qla4_8xxx_crb_addr_transform(PGS0); - qla4_8xxx_crb_addr_transform(PS); - qla4_8xxx_crb_addr_transform(PH); - qla4_8xxx_crb_addr_transform(NIU); - qla4_8xxx_crb_addr_transform(I2Q); - qla4_8xxx_crb_addr_transform(EG); - qla4_8xxx_crb_addr_transform(MN); - qla4_8xxx_crb_addr_transform(MS); - qla4_8xxx_crb_addr_transform(CAS2); - qla4_8xxx_crb_addr_transform(CAS1); - qla4_8xxx_crb_addr_transform(CAS0); - qla4_8xxx_crb_addr_transform(CAM); - qla4_8xxx_crb_addr_transform(C2C1); - qla4_8xxx_crb_addr_transform(C2C0); - qla4_8xxx_crb_addr_transform(SMB); - qla4_8xxx_crb_addr_transform(OCM0); - qla4_8xxx_crb_addr_transform(I2C0); - - qla4_8xxx_crb_table_initialized = 1; -} - -static struct crb_128M_2M_block_map crb_128M_2M_map[64] = { - {{{0, 0, 0, 0} } }, /* 0: PCI */ - {{{1, 0x0100000, 0x0102000, 0x120000}, /* 1: PCIE */ - {1, 0x0110000, 0x0120000, 0x130000}, - {1, 0x0120000, 0x0122000, 0x124000}, - {1, 0x0130000, 0x0132000, 0x126000}, - {1, 0x0140000, 0x0142000, 0x128000}, - {1, 0x0150000, 0x0152000, 0x12a000}, - {1, 0x0160000, 0x0170000, 0x110000}, - {1, 0x0170000, 0x0172000, 0x12e000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x01e0000, 0x01e0800, 0x122000}, - {0, 0x0000000, 0x0000000, 0x000000} } }, - {{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */ - {{{0, 0, 0, 0} } }, /* 3: */ - {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */ - {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE */ - {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU */ - {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM */ - {{{1, 0x0800000, 0x0802000, 0x170000}, /* 8: SQM0 */ - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x08f0000, 0x08f2000, 0x172000} } }, - {{{1, 0x0900000, 0x0902000, 0x174000}, /* 9: SQM1*/ - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x09f0000, 0x09f2000, 0x176000} } }, - {{{0, 0x0a00000, 0x0a02000, 0x178000}, /* 10: SQM2*/ - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x0af0000, 0x0af2000, 0x17a000} } }, - {{{0, 0x0b00000, 0x0b02000, 0x17c000}, /* 11: SQM3*/ - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {1, 0x0bf0000, 0x0bf2000, 0x17e000} } }, - {{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */ - {{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */ - {{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */ - {{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */ - {{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */ - {{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */ - {{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */ - {{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */ - {{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */ - {{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */ - {{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */ - {{{0, 0, 0, 0} } }, /* 23: */ - {{{0, 0, 0, 0} } }, /* 24: */ - {{{0, 0, 0, 0} } }, /* 25: */ - {{{0, 0, 0, 0} } }, /* 26: */ - {{{0, 0, 0, 0} } }, /* 27: */ - {{{0, 0, 0, 0} } }, /* 28: */ - {{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */ - {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */ - {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */ - {{{0} } }, /* 32: PCI */ - {{{1, 0x2100000, 0x2102000, 0x120000}, /* 33: PCIE */ - {1, 0x2110000, 0x2120000, 0x130000}, - {1, 0x2120000, 0x2122000, 0x124000}, - {1, 0x2130000, 0x2132000, 0x126000}, - {1, 0x2140000, 0x2142000, 0x128000}, - {1, 0x2150000, 0x2152000, 0x12a000}, - {1, 0x2160000, 0x2170000, 0x110000}, - {1, 0x2170000, 0x2172000, 0x12e000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000}, - {0, 0x0000000, 0x0000000, 0x000000} } }, - {{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */ - {{{0} } }, /* 35: */ - {{{0} } }, /* 36: */ - {{{0} } }, /* 37: */ - {{{0} } }, /* 38: */ - {{{0} } }, /* 39: */ - {{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */ - {{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */ - {{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */ - {{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */ - {{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */ - {{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */ - {{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */ - {{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */ - {{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */ - {{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */ - {{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */ - {{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */ - {{{0} } }, /* 52: */ - {{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */ - {{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */ - {{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */ - {{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */ - {{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */ - {{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */ - {{{0} } }, /* 59: I2C0 */ - {{{0} } }, /* 60: I2C1 */ - {{{1, 0x3d00000, 0x3d04000, 0x1dc000} } },/* 61: LPC */ - {{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */ - {{{1, 0x3f00000, 0x3f01000, 0x168000} } } /* 63: P2NR0 */ -}; - -/* - * top 12 bits of crb internal address (hub, agent) - */ -static unsigned qla4_8xxx_crb_hub_agt[64] = { - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PS, - QLA82XX_HW_CRB_HUB_AGT_ADR_MN, - QLA82XX_HW_CRB_HUB_AGT_ADR_MS, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_SRE, - QLA82XX_HW_CRB_HUB_AGT_ADR_NIU, - QLA82XX_HW_CRB_HUB_AGT_ADR_QMN, - QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0, - QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1, - QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2, - QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3, - QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q, - QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR, - QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4, - QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGND, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI, - QLA82XX_HW_CRB_HUB_AGT_ADR_SN, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_EG, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PS, - QLA82XX_HW_CRB_HUB_AGT_ADR_CAM, - 0, - 0, - 0, - 0, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7, - QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA, - QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q, - QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8, - QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9, - QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_SMB, - QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0, - QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1, - 0, - QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC, - 0, -}; - -/* Device states */ -static char *qdev_state[] = { - "Unknown", - "Cold", - "Initializing", - "Ready", - "Need Reset", - "Need Quiescent", - "Failed", - "Quiescent", -}; - -/* - * In: 'off' is offset from CRB space in 128M pci map - * Out: 'off' is 2M pci map addr - * side effect: lock crb window - */ -static void -qla4_8xxx_pci_set_crbwindow_2M(struct scsi_qla_host *ha, ulong *off) -{ - u32 win_read; - - ha->crb_win = CRB_HI(*off); - writel(ha->crb_win, - (void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); - - /* Read back value to make sure write has gone through before trying - * to use it. */ - win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); - if (win_read != ha->crb_win) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: Written crbwin (0x%x) != Read crbwin (0x%x)," - " off=0x%lx\n", __func__, ha->crb_win, win_read, *off)); - } - *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; -} - -void -qla4_8xxx_wr_32(struct scsi_qla_host *ha, ulong off, u32 data) -{ - unsigned long flags = 0; - int rv; - - rv = qla4_8xxx_pci_get_crb_addr_2M(ha, &off); - - BUG_ON(rv == -1); - - if (rv == 1) { - write_lock_irqsave(&ha->hw_lock, flags); - qla4_8xxx_crb_win_lock(ha); - qla4_8xxx_pci_set_crbwindow_2M(ha, &off); - } - - writel(data, (void __iomem *)off); - - if (rv == 1) { - qla4_8xxx_crb_win_unlock(ha); - write_unlock_irqrestore(&ha->hw_lock, flags); - } -} - -int -qla4_8xxx_rd_32(struct scsi_qla_host *ha, ulong off) -{ - unsigned long flags = 0; - int rv; - u32 data; - - rv = qla4_8xxx_pci_get_crb_addr_2M(ha, &off); - - BUG_ON(rv == -1); - - if (rv == 1) { - write_lock_irqsave(&ha->hw_lock, flags); - qla4_8xxx_crb_win_lock(ha); - qla4_8xxx_pci_set_crbwindow_2M(ha, &off); - } - data = readl((void __iomem *)off); - - if (rv == 1) { - qla4_8xxx_crb_win_unlock(ha); - write_unlock_irqrestore(&ha->hw_lock, flags); - } - return data; -} - -#define CRB_WIN_LOCK_TIMEOUT 100000000 - -int qla4_8xxx_crb_win_lock(struct scsi_qla_host *ha) -{ - int i; - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore3 from PCI HW block */ - done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK)); - if (done == 1) - break; - if (timeout >= CRB_WIN_LOCK_TIMEOUT) - return -1; - - timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); /*This a nop instr on i386*/ - } - } - qla4_8xxx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num); - return 0; -} - -void qla4_8xxx_crb_win_unlock(struct scsi_qla_host *ha) -{ - qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); -} - -#define IDC_LOCK_TIMEOUT 100000000 - -/** - * qla4_8xxx_idc_lock - hw_lock - * @ha: pointer to adapter structure - * - * General purpose lock used to synchronize access to - * CRB_DEV_STATE, CRB_DEV_REF_COUNT, etc. - **/ -int qla4_8xxx_idc_lock(struct scsi_qla_host *ha) -{ - int i; - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore5 from PCI HW block */ - done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK)); - if (done == 1) - break; - if (timeout >= IDC_LOCK_TIMEOUT) - return -1; - - timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); /*This a nop instr on i386*/ - } - } - return 0; -} - -void qla4_8xxx_idc_unlock(struct scsi_qla_host *ha) -{ - qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK)); -} - -int -qla4_8xxx_pci_get_crb_addr_2M(struct scsi_qla_host *ha, ulong *off) -{ - struct crb_128M_2M_sub_block_map *m; - - if (*off >= QLA82XX_CRB_MAX) - return -1; - - if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) { - *off = (*off - QLA82XX_PCI_CAMQM) + - QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase; - return 0; - } - - if (*off < QLA82XX_PCI_CRBSPACE) - return -1; - - *off -= QLA82XX_PCI_CRBSPACE; - /* - * Try direct map - */ - - m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; - - if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { - *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase; - return 0; - } - - /* - * Not in direct map, use crb window - */ - return 1; -} - -/* PCI Windowing for DDR regions. */ -#define QLA82XX_ADDR_IN_RANGE(addr, low, high) \ - (((addr) <= (high)) && ((addr) >= (low))) - -/* -* check memory access boundary. -* used by test agent. support ddr access only for now -*/ -static unsigned long -qla4_8xxx_pci_mem_bound_check(struct scsi_qla_host *ha, - unsigned long long addr, int size) -{ - if (!QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, - QLA82XX_ADDR_DDR_NET_MAX) || - !QLA82XX_ADDR_IN_RANGE(addr + size - 1, - QLA82XX_ADDR_DDR_NET, QLA82XX_ADDR_DDR_NET_MAX) || - ((size != 1) && (size != 2) && (size != 4) && (size != 8))) { - return 0; - } - return 1; -} - -static int qla4_8xxx_pci_set_window_warning_count; - -static unsigned long -qla4_8xxx_pci_set_window(struct scsi_qla_host *ha, unsigned long long addr) -{ - int window; - u32 win_read; - - if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, - QLA82XX_ADDR_DDR_NET_MAX)) { - /* DDR network side */ - window = MN_WIN(addr); - ha->ddr_mn_window = window; - qla4_8xxx_wr_32(ha, ha->mn_win_crb | - QLA82XX_PCI_CRBSPACE, window); - win_read = qla4_8xxx_rd_32(ha, ha->mn_win_crb | - QLA82XX_PCI_CRBSPACE); - if ((win_read << 17) != window) { - ql4_printk(KERN_WARNING, ha, - "%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n", - __func__, window, win_read); - } - addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET; - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, - QLA82XX_ADDR_OCM0_MAX)) { - unsigned int temp1; - /* if bits 19:18&17:11 are on */ - if ((addr & 0x00ff800) == 0xff800) { - printk("%s: QM access not handled.\n", __func__); - addr = -1UL; - } - - window = OCM_WIN(addr); - ha->ddr_mn_window = window; - qla4_8xxx_wr_32(ha, ha->mn_win_crb | - QLA82XX_PCI_CRBSPACE, window); - win_read = qla4_8xxx_rd_32(ha, ha->mn_win_crb | - QLA82XX_PCI_CRBSPACE); - temp1 = ((window & 0x1FF) << 7) | - ((window & 0x0FFFE0000) >> 17); - if (win_read != temp1) { - printk("%s: Written OCMwin (0x%x) != Read" - " OCMwin (0x%x)\n", __func__, temp1, win_read); - } - addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M; - - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, - QLA82XX_P3_ADDR_QDR_NET_MAX)) { - /* QDR network side */ - window = MS_WIN(addr); - ha->qdr_sn_window = window; - qla4_8xxx_wr_32(ha, ha->ms_win_crb | - QLA82XX_PCI_CRBSPACE, window); - win_read = qla4_8xxx_rd_32(ha, - ha->ms_win_crb | QLA82XX_PCI_CRBSPACE); - if (win_read != window) { - printk("%s: Written MSwin (0x%x) != Read " - "MSwin (0x%x)\n", __func__, window, win_read); - } - addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET; - - } else { - /* - * peg gdb frequently accesses memory that doesn't exist, - * this limits the chit chat so debugging isn't slowed down. - */ - if ((qla4_8xxx_pci_set_window_warning_count++ < 8) || - (qla4_8xxx_pci_set_window_warning_count%64 == 0)) { - printk("%s: Warning:%s Unknown address range!\n", - __func__, DRIVER_NAME); - } - addr = -1UL; - } - return addr; -} - -/* check if address is in the same windows as the previous access */ -static int qla4_8xxx_pci_is_same_window(struct scsi_qla_host *ha, - unsigned long long addr) -{ - int window; - unsigned long long qdr_max; - - qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX; - - if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, - QLA82XX_ADDR_DDR_NET_MAX)) { - /* DDR network side */ - BUG(); /* MN access can not come here */ - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, - QLA82XX_ADDR_OCM0_MAX)) { - return 1; - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM1, - QLA82XX_ADDR_OCM1_MAX)) { - return 1; - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, - qdr_max)) { - /* QDR network side */ - window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f; - if (ha->qdr_sn_window == window) - return 1; - } - - return 0; -} - -static int qla4_8xxx_pci_mem_read_direct(struct scsi_qla_host *ha, - u64 off, void *data, int size) -{ - unsigned long flags; - void __iomem *addr; - int ret = 0; - u64 start; - void __iomem *mem_ptr = NULL; - unsigned long mem_base; - unsigned long mem_page; - - write_lock_irqsave(&ha->hw_lock, flags); - - /* - * If attempting to access unknown address or straddle hw windows, - * do not access. - */ - start = qla4_8xxx_pci_set_window(ha, off); - if ((start == -1UL) || - (qla4_8xxx_pci_is_same_window(ha, off + size - 1) == 0)) { - write_unlock_irqrestore(&ha->hw_lock, flags); - printk(KERN_ERR"%s out of bound pci memory access. " - "offset is 0x%llx\n", DRIVER_NAME, off); - return -1; - } - - addr = qla4_8xxx_pci_base_offsetfset(ha, start); - if (!addr) { - write_unlock_irqrestore(&ha->hw_lock, flags); - mem_base = pci_resource_start(ha->pdev, 0); - mem_page = start & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - consecutive pages. - */ - if (mem_page != ((start + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - - if (mem_ptr == NULL) { - *(u8 *)data = 0; - return -1; - } - addr = mem_ptr; - addr += start & (PAGE_SIZE - 1); - write_lock_irqsave(&ha->hw_lock, flags); - } - - switch (size) { - case 1: - *(u8 *)data = readb(addr); - break; - case 2: - *(u16 *)data = readw(addr); - break; - case 4: - *(u32 *)data = readl(addr); - break; - case 8: - *(u64 *)data = readq(addr); - break; - default: - ret = -1; - break; - } - write_unlock_irqrestore(&ha->hw_lock, flags); - - if (mem_ptr) - iounmap(mem_ptr); - return ret; -} - -static int -qla4_8xxx_pci_mem_write_direct(struct scsi_qla_host *ha, u64 off, - void *data, int size) -{ - unsigned long flags; - void __iomem *addr; - int ret = 0; - u64 start; - void __iomem *mem_ptr = NULL; - unsigned long mem_base; - unsigned long mem_page; - - write_lock_irqsave(&ha->hw_lock, flags); - - /* - * If attempting to access unknown address or straddle hw windows, - * do not access. - */ - start = qla4_8xxx_pci_set_window(ha, off); - if ((start == -1UL) || - (qla4_8xxx_pci_is_same_window(ha, off + size - 1) == 0)) { - write_unlock_irqrestore(&ha->hw_lock, flags); - printk(KERN_ERR"%s out of bound pci memory access. " - "offset is 0x%llx\n", DRIVER_NAME, off); - return -1; - } - - addr = qla4_8xxx_pci_base_offsetfset(ha, start); - if (!addr) { - write_unlock_irqrestore(&ha->hw_lock, flags); - mem_base = pci_resource_start(ha->pdev, 0); - mem_page = start & PAGE_MASK; - /* Map two pages whenever user tries to access addresses in two - consecutive pages. - */ - if (mem_page != ((start + size - 1) & PAGE_MASK)) - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2); - else - mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == NULL) - return -1; - - addr = mem_ptr; - addr += start & (PAGE_SIZE - 1); - write_lock_irqsave(&ha->hw_lock, flags); - } - - switch (size) { - case 1: - writeb(*(u8 *)data, addr); - break; - case 2: - writew(*(u16 *)data, addr); - break; - case 4: - writel(*(u32 *)data, addr); - break; - case 8: - writeq(*(u64 *)data, addr); - break; - default: - ret = -1; - break; - } - write_unlock_irqrestore(&ha->hw_lock, flags); - if (mem_ptr) - iounmap(mem_ptr); - return ret; -} - -#define MTU_FUDGE_FACTOR 100 - -static unsigned long -qla4_8xxx_decode_crb_addr(unsigned long addr) -{ - int i; - unsigned long base_addr, offset, pci_base; - - if (!qla4_8xxx_crb_table_initialized) - qla4_8xxx_crb_addr_transform_setup(); - - pci_base = ADDR_ERROR; - base_addr = addr & 0xfff00000; - offset = addr & 0x000fffff; - - for (i = 0; i < MAX_CRB_XFORM; i++) { - if (crb_addr_xform[i] == base_addr) { - pci_base = i << 20; - break; - } - } - if (pci_base == ADDR_ERROR) - return pci_base; - else - return pci_base + offset; -} - -static long rom_max_timeout = 100; -static long qla4_8xxx_rom_lock_timeout = 100; - -static int -qla4_8xxx_rom_lock(struct scsi_qla_host *ha) -{ - int i; - int done = 0, timeout = 0; - - while (!done) { - /* acquire semaphore2 from PCI HW block */ - - done = qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK)); - if (done == 1) - break; - if (timeout >= qla4_8xxx_rom_lock_timeout) - return -1; - - timeout++; - - /* Yield CPU */ - if (!in_interrupt()) - schedule(); - else { - for (i = 0; i < 20; i++) - cpu_relax(); /*This a nop instr on i386*/ - } - } - qla4_8xxx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER); - return 0; -} - -static void -qla4_8xxx_rom_unlock(struct scsi_qla_host *ha) -{ - qla4_8xxx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK)); -} - -static int -qla4_8xxx_wait_rom_done(struct scsi_qla_host *ha) -{ - long timeout = 0; - long done = 0 ; - - while (done == 0) { - done = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS); - done &= 2; - timeout++; - if (timeout >= rom_max_timeout) { - printk("%s: Timeout reached waiting for rom done", - DRIVER_NAME); - return -1; - } - } - return 0; -} - -static int -qla4_8xxx_do_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp) -{ - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr); - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3); - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb); - if (qla4_8xxx_wait_rom_done(ha)) { - printk("%s: Error waiting for rom done\n", DRIVER_NAME); - return -1; - } - /* reset abyte_cnt and dummy_byte_cnt */ - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0); - udelay(10); - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0); - - *valp = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA); - return 0; -} - -static int -qla4_8xxx_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp) -{ - int ret, loops = 0; - - while ((qla4_8xxx_rom_lock(ha) != 0) && (loops < 50000)) { - udelay(100); - loops++; - } - if (loops >= 50000) { - printk("%s: qla4_8xxx_rom_lock failed\n", DRIVER_NAME); - return -1; - } - ret = qla4_8xxx_do_rom_fast_read(ha, addr, valp); - qla4_8xxx_rom_unlock(ha); - return ret; -} - -/** - * This routine does CRB initialize sequence - * to put the ISP into operational state - **/ -static int -qla4_8xxx_pinit_from_rom(struct scsi_qla_host *ha, int verbose) -{ - int addr, val; - int i ; - struct crb_addr_pair *buf; - unsigned long off; - unsigned offset, n; - - struct crb_addr_pair { - long addr; - long data; - }; - - /* Halt all the indiviual PEGs and other blocks of the ISP */ - qla4_8xxx_rom_lock(ha); - - /* disable all I2Q */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x10, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x14, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x18, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x1c, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x20, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_I2Q + 0x24, 0x0); - - /* disable all niu interrupts */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff); - /* disable xge rx/tx */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00); - /* disable xg1 rx/tx */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00); - /* disable sideband mac */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x90000, 0x00); - /* disable ap0 mac */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0xa0000, 0x00); - /* disable ap1 mac */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0xb0000, 0x00); - - /* halt sre */ - val = qla4_8xxx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_SRE + 0x1000, val & (~(0x1))); - - /* halt epg */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_EPG + 0x1300, 0x1); - - /* halt timers */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x0, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x8, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_TIMER + 0x200, 0x0); - - /* halt pegs */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c, 1); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1); - msleep(5); - - /* big hammer */ - if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) - /* don't reset CAM block on reset */ - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff); - else - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff); - - qla4_8xxx_rom_unlock(ha); - - /* Read the signature value from the flash. - * Offset 0: Contain signature (0xcafecafe) - * Offset 4: Offset and number of addr/value pairs - * that present in CRB initialize sequence - */ - if (qla4_8xxx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL || - qla4_8xxx_rom_fast_read(ha, 4, &n) != 0) { - ql4_printk(KERN_WARNING, ha, - "[ERROR] Reading crb_init area: n: %08x\n", n); - return -1; - } - - /* Offset in flash = lower 16 bits - * Number of enteries = upper 16 bits - */ - offset = n & 0xffffU; - n = (n >> 16) & 0xffffU; - - /* number of addr/value pair should not exceed 1024 enteries */ - if (n >= 1024) { - ql4_printk(KERN_WARNING, ha, - "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n", - DRIVER_NAME, __func__, n); - return -1; - } - - ql4_printk(KERN_INFO, ha, - "%s: %d CRB init values found in ROM.\n", DRIVER_NAME, n); - - buf = kmalloc(n * sizeof(struct crb_addr_pair), GFP_KERNEL); - if (buf == NULL) { - ql4_printk(KERN_WARNING, ha, - "%s: [ERROR] Unable to malloc memory.\n", DRIVER_NAME); - return -1; - } - - for (i = 0; i < n; i++) { - if (qla4_8xxx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 || - qla4_8xxx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) != - 0) { - kfree(buf); - return -1; - } - - buf[i].addr = addr; - buf[i].data = val; - } - - for (i = 0; i < n; i++) { - /* Translate internal CRB initialization - * address to PCI bus address - */ - off = qla4_8xxx_decode_crb_addr((unsigned long)buf[i].addr) + - QLA82XX_PCI_CRBSPACE; - /* Not all CRB addr/value pair to be written, - * some of them are skipped - */ - - /* skip if LS bit is set*/ - if (off & 0x1) { - DEBUG2(ql4_printk(KERN_WARNING, ha, - "Skip CRB init replay for offset = 0x%lx\n", off)); - continue; - } - - /* skipping cold reboot MAGIC */ - if (off == QLA82XX_CAM_RAM(0x1fc)) - continue; - - /* do not reset PCI */ - if (off == (ROMUSB_GLB + 0xbc)) - continue; - - /* skip core clock, so that firmware can increase the clock */ - if (off == (ROMUSB_GLB + 0xc8)) - continue; - - /* skip the function enable register */ - if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION)) - continue; - - if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2)) - continue; - - if ((off & 0x0ff00000) == QLA82XX_CRB_SMB) - continue; - - if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET) - continue; - - if (off == ADDR_ERROR) { - ql4_printk(KERN_WARNING, ha, - "%s: [ERROR] Unknown addr: 0x%08lx\n", - DRIVER_NAME, buf[i].addr); - continue; - } - - qla4_8xxx_wr_32(ha, off, buf[i].data); - - /* ISP requires much bigger delay to settle down, - * else crb_window returns 0xffffffff - */ - if (off == QLA82XX_ROMUSB_GLB_SW_RESET) - msleep(1000); - - /* ISP requires millisec delay between - * successive CRB register updation - */ - msleep(1); - } - - kfree(buf); - - /* Resetting the data and instruction cache */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8); - - /* Clear all protocol processing engines */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0); - - return 0; -} - -static int -qla4_8xxx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start) -{ - int i, rval = 0; - long size = 0; - long flashaddr, memaddr; - u64 data; - u32 high, low; - - flashaddr = memaddr = ha->hw.flt_region_bootload; - size = (image_start - flashaddr) / 8; - - DEBUG2(printk("scsi%ld: %s: bootldr=0x%lx, fw_image=0x%x\n", - ha->host_no, __func__, flashaddr, image_start)); - - for (i = 0; i < size; i++) { - if ((qla4_8xxx_rom_fast_read(ha, flashaddr, (int *)&low)) || - (qla4_8xxx_rom_fast_read(ha, flashaddr + 4, - (int *)&high))) { - rval = -1; - goto exit_load_from_flash; - } - data = ((u64)high << 32) | low ; - rval = qla4_8xxx_pci_mem_write_2M(ha, memaddr, &data, 8); - if (rval) - goto exit_load_from_flash; - - flashaddr += 8; - memaddr += 8; - - if (i % 0x1000 == 0) - msleep(1); - - } - - udelay(100); - - read_lock(&ha->hw_lock); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020); - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e); - read_unlock(&ha->hw_lock); - -exit_load_from_flash: - return rval; -} - -static int qla4_8xxx_load_fw(struct scsi_qla_host *ha, uint32_t image_start) -{ - u32 rst; - - qla4_8xxx_wr_32(ha, CRB_CMDPEG_STATE, 0); - if (qla4_8xxx_pinit_from_rom(ha, 0) != QLA_SUCCESS) { - printk(KERN_WARNING "%s: Error during CRB Initialization\n", - __func__); - return QLA_ERROR; - } - - udelay(500); - - /* at this point, QM is in reset. This could be a problem if there are - * incoming d* transition queue messages. QM/PCIE could wedge. - * To get around this, QM is brought out of reset. - */ - - rst = qla4_8xxx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET); - /* unreset qm */ - rst &= ~(1 << 28); - qla4_8xxx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst); - - if (qla4_8xxx_load_from_flash(ha, image_start)) { - printk("%s: Error trying to load fw from flash!\n", __func__); - return QLA_ERROR; - } - - return QLA_SUCCESS; -} - -int -qla4_8xxx_pci_mem_read_2M(struct scsi_qla_host *ha, - u64 off, void *data, int size) -{ - int i, j = 0, k, start, end, loop, sz[2], off0[2]; - int shift_amount; - uint32_t temp; - uint64_t off8, val, mem_crb, word[2] = {0, 0}; - - /* - * If not MN, go check for MS or invalid. - */ - - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) - mem_crb = QLA82XX_CRB_QDR_NET; - else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla4_8xxx_pci_mem_bound_check(ha, off, size) == 0) - return qla4_8xxx_pci_mem_read_direct(ha, - off, data, size); - } - - - off8 = off & 0xfffffff0; - off0[0] = off & 0xf; - sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]); - shift_amount = 4; - - loop = ((off0[0] + size - 1) >> shift_amount) + 1; - off0[1] = 0; - sz[1] = size - sz[0]; - - for (i = 0; i < loop; i++) { - temp = off8 + (i << shift_amount); - qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp); - temp = MIU_TA_CTL_ENABLE; - qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE; - qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla4_8xxx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - if (printk_ratelimit()) - ql4_printk(KERN_ERR, ha, - "failed to read through agent\n"); - break; - } - - start = off0[i] >> 2; - end = (off0[i] + sz[i] - 1) >> 2; - for (k = start; k <= end; k++) { - temp = qla4_8xxx_rd_32(ha, - mem_crb + MIU_TEST_AGT_RDDATA(k)); - word[i] |= ((uint64_t)temp << (32 * (k & 1))); - } - } - - if (j >= MAX_CTL_CHECK) - return -1; - - if ((off0[0] & 7) == 0) { - val = word[0]; - } else { - val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) | - ((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8)); - } - - switch (size) { - case 1: - *(uint8_t *)data = val; - break; - case 2: - *(uint16_t *)data = val; - break; - case 4: - *(uint32_t *)data = val; - break; - case 8: - *(uint64_t *)data = val; - break; - } - return 0; -} - -int -qla4_8xxx_pci_mem_write_2M(struct scsi_qla_host *ha, - u64 off, void *data, int size) -{ - int i, j, ret = 0, loop, sz[2], off0; - int scale, shift_amount, startword; - uint32_t temp; - uint64_t off8, mem_crb, tmpw, word[2] = {0, 0}; - - /* - * If not MN, go check for MS or invalid. - */ - if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX) - mem_crb = QLA82XX_CRB_QDR_NET; - else { - mem_crb = QLA82XX_CRB_DDR_NET; - if (qla4_8xxx_pci_mem_bound_check(ha, off, size) == 0) - return qla4_8xxx_pci_mem_write_direct(ha, - off, data, size); - } - - off0 = off & 0x7; - sz[0] = (size < (8 - off0)) ? size : (8 - off0); - sz[1] = size - sz[0]; - - off8 = off & 0xfffffff0; - loop = (((off & 0xf) + size - 1) >> 4) + 1; - shift_amount = 4; - scale = 2; - startword = (off & 0xf)/8; - - for (i = 0; i < loop; i++) { - if (qla4_8xxx_pci_mem_read_2M(ha, off8 + - (i << shift_amount), &word[i * scale], 8)) - return -1; - } - - switch (size) { - case 1: - tmpw = *((uint8_t *)data); - break; - case 2: - tmpw = *((uint16_t *)data); - break; - case 4: - tmpw = *((uint32_t *)data); - break; - case 8: - default: - tmpw = *((uint64_t *)data); - break; - } - - if (sz[0] == 8) - word[startword] = tmpw; - else { - word[startword] &= - ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8)); - word[startword] |= tmpw << (off0 * 8); - } - - if (sz[1] != 0) { - word[startword+1] &= ~(~0ULL << (sz[1] * 8)); - word[startword+1] |= tmpw >> (sz[0] * 8); - } - - for (i = 0; i < loop; i++) { - temp = off8 + (i << shift_amount); - qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp); - temp = 0; - qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp); - temp = word[i * scale] & 0xffffffff; - qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp); - temp = (word[i * scale] >> 32) & 0xffffffff; - qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp); - temp = word[i*scale + 1] & 0xffffffff; - qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_LO, - temp); - temp = (word[i*scale + 1] >> 32) & 0xffffffff; - qla4_8xxx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_HI, - temp); - - temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); - temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE; - qla4_8xxx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp); - - for (j = 0; j < MAX_CTL_CHECK; j++) { - temp = qla4_8xxx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL); - if ((temp & MIU_TA_CTL_BUSY) == 0) - break; - } - - if (j >= MAX_CTL_CHECK) { - if (printk_ratelimit()) - ql4_printk(KERN_ERR, ha, - "failed to write through agent\n"); - ret = -1; - break; - } - } - - return ret; -} - -static int qla4_8xxx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val) -{ - u32 val = 0; - int retries = 60; - - if (!pegtune_val) { - do { - val = qla4_8xxx_rd_32(ha, CRB_CMDPEG_STATE); - if ((val == PHAN_INITIALIZE_COMPLETE) || - (val == PHAN_INITIALIZE_ACK)) - return 0; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(500); - - } while (--retries); - - if (!retries) { - pegtune_val = qla4_8xxx_rd_32(ha, - QLA82XX_ROMUSB_GLB_PEGTUNE_DONE); - printk(KERN_WARNING "%s: init failed, " - "pegtune_val = %x\n", __func__, pegtune_val); - return -1; - } - } - return 0; -} - -static int qla4_8xxx_rcvpeg_ready(struct scsi_qla_host *ha) -{ - uint32_t state = 0; - int loops = 0; - - /* Window 1 call */ - read_lock(&ha->hw_lock); - state = qla4_8xxx_rd_32(ha, CRB_RCVPEG_STATE); - read_unlock(&ha->hw_lock); - - while ((state != PHAN_PEG_RCV_INITIALIZED) && (loops < 30000)) { - udelay(100); - /* Window 1 call */ - read_lock(&ha->hw_lock); - state = qla4_8xxx_rd_32(ha, CRB_RCVPEG_STATE); - read_unlock(&ha->hw_lock); - - loops++; - } - - if (loops >= 30000) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Receive Peg initialization not complete: 0x%x.\n", state)); - return QLA_ERROR; - } - - return QLA_SUCCESS; -} - -void -qla4_8xxx_set_drv_active(struct scsi_qla_host *ha) -{ - uint32_t drv_active; - - drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - drv_active |= (1 << (ha->func_num * 4)); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); -} - -void -qla4_8xxx_clear_drv_active(struct scsi_qla_host *ha) -{ - uint32_t drv_active; - - drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - drv_active &= ~(1 << (ha->func_num * 4)); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active); -} - -static inline int -qla4_8xxx_need_reset(struct scsi_qla_host *ha) -{ - uint32_t drv_state, drv_active; - int rval; - - drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - rval = drv_state & (1 << (ha->func_num * 4)); - if ((test_bit(AF_EEH_BUSY, &ha->flags)) && drv_active) - rval = 1; - - return rval; -} - -static inline void -qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha) -{ - uint32_t drv_state; - - drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_state |= (1 << (ha->func_num * 4)); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); -} - -static inline void -qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha) -{ - uint32_t drv_state; - - drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_state &= ~(1 << (ha->func_num * 4)); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state); -} - -static inline void -qla4_8xxx_set_qsnt_ready(struct scsi_qla_host *ha) -{ - uint32_t qsnt_state; - - qsnt_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - qsnt_state |= (2 << (ha->func_num * 4)); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state); -} - - -static int -qla4_8xxx_start_firmware(struct scsi_qla_host *ha, uint32_t image_start) -{ - int pcie_cap; - uint16_t lnk; - - /* scrub dma mask expansion register */ - qla4_8xxx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555); - - /* Overwrite stale initialization register values */ - qla4_8xxx_wr_32(ha, CRB_CMDPEG_STATE, 0); - qla4_8xxx_wr_32(ha, CRB_RCVPEG_STATE, 0); - qla4_8xxx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0); - qla4_8xxx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0); - - if (qla4_8xxx_load_fw(ha, image_start) != QLA_SUCCESS) { - printk("%s: Error trying to start fw!\n", __func__); - return QLA_ERROR; - } - - /* Handshake with the card before we register the devices. */ - if (qla4_8xxx_cmdpeg_ready(ha, 0) != QLA_SUCCESS) { - printk("%s: Error during card handshake!\n", __func__); - return QLA_ERROR; - } - - /* Negotiated Link width */ - pcie_cap = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP); - pci_read_config_word(ha->pdev, pcie_cap + PCI_EXP_LNKSTA, &lnk); - ha->link_width = (lnk >> 4) & 0x3f; - - /* Synchronize with Receive peg */ - return qla4_8xxx_rcvpeg_ready(ha); -} - -static int -qla4_8xxx_try_start_fw(struct scsi_qla_host *ha) -{ - int rval = QLA_ERROR; - - /* - * FW Load priority: - * 1) Operational firmware residing in flash. - * 2) Fail - */ - - ql4_printk(KERN_INFO, ha, - "FW: Retrieving flash offsets from FLT/FDT ...\n"); - rval = qla4_8xxx_get_flash_info(ha); - if (rval != QLA_SUCCESS) - return rval; - - ql4_printk(KERN_INFO, ha, - "FW: Attempting to load firmware from flash...\n"); - rval = qla4_8xxx_start_firmware(ha, ha->hw.flt_region_fw); - - if (rval != QLA_SUCCESS) { - ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash" - " FAILED...\n"); - return rval; - } - - return rval; -} - -static void qla4_8xxx_rom_lock_recovery(struct scsi_qla_host *ha) -{ - if (qla4_8xxx_rom_lock(ha)) { - /* Someone else is holding the lock. */ - dev_info(&ha->pdev->dev, "Resetting rom_lock\n"); - } - - /* - * Either we got the lock, or someone - * else died while holding it. - * In either case, unlock. - */ - qla4_8xxx_rom_unlock(ha); -} - -/** - * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw - * @ha: pointer to adapter structure - * - * Note: IDC lock must be held upon entry - **/ -static int -qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha) -{ - int rval = QLA_ERROR; - int i, timeout; - uint32_t old_count, count; - int need_reset = 0, peg_stuck = 1; - - need_reset = qla4_8xxx_need_reset(ha); - - old_count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); - - for (i = 0; i < 10; i++) { - timeout = msleep_interruptible(200); - if (timeout) { - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - return rval; - } - - count = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); - if (count != old_count) - peg_stuck = 0; - } - - if (need_reset) { - /* We are trying to perform a recovery here. */ - if (peg_stuck) - qla4_8xxx_rom_lock_recovery(ha); - goto dev_initialize; - } else { - /* Start of day for this ha context. */ - if (peg_stuck) { - /* Either we are the first or recovery in progress. */ - qla4_8xxx_rom_lock_recovery(ha); - goto dev_initialize; - } else { - /* Firmware already running. */ - rval = QLA_SUCCESS; - goto dev_ready; - } - } - -dev_initialize: - /* set to DEV_INITIALIZING */ - ql4_printk(KERN_INFO, ha, "HW State: INITIALIZING\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_INITIALIZING); - - /* Driver that sets device state to initializating sets IDC version */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, QLA82XX_IDC_VERSION); - - qla4_8xxx_idc_unlock(ha); - rval = qla4_8xxx_try_start_fw(ha); - qla4_8xxx_idc_lock(ha); - - if (rval != QLA_SUCCESS) { - ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); - qla4_8xxx_clear_drv_active(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_FAILED); - return rval; - } - -dev_ready: - ql4_printk(KERN_INFO, ha, "HW State: READY\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_READY); - - return rval; -} - -/** - * qla4_8xxx_need_reset_handler - Code to start reset sequence - * @ha: pointer to adapter structure - * - * Note: IDC lock must be held upon entry - **/ -static void -qla4_8xxx_need_reset_handler(struct scsi_qla_host *ha) -{ - uint32_t dev_state, drv_state, drv_active; - unsigned long reset_timeout; - - ql4_printk(KERN_INFO, ha, - "Performing ISP error recovery\n"); - - if (test_and_clear_bit(AF_ONLINE, &ha->flags)) { - qla4_8xxx_idc_unlock(ha); - ha->isp_ops->disable_intrs(ha); - qla4_8xxx_idc_lock(ha); - } - - qla4_8xxx_set_rst_ready(ha); - - /* wait for 10 seconds for reset ack from all functions */ - reset_timeout = jiffies + (ha->nx_reset_timeout * HZ); - - drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - - ql4_printk(KERN_INFO, ha, - "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n", - __func__, ha->host_no, drv_state, drv_active); - - while (drv_state != drv_active) { - if (time_after_eq(jiffies, reset_timeout)) { - printk("%s: RESET TIMEOUT!\n", DRIVER_NAME); - break; - } - - qla4_8xxx_idc_unlock(ha); - msleep(1000); - qla4_8xxx_idc_lock(ha); - - drv_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_STATE); - drv_active = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE); - } - - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - ql4_printk(KERN_INFO, ha, "3:Device state is 0x%x = %s\n", dev_state, - dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); - - /* Force to DEV_COLD unless someone else is starting a reset */ - if (dev_state != QLA82XX_DEV_INITIALIZING) { - ql4_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA82XX_DEV_COLD); - } -} - -/** - * qla4_8xxx_need_qsnt_handler - Code to start qsnt - * @ha: pointer to adapter structure - **/ -void -qla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha) -{ - qla4_8xxx_idc_lock(ha); - qla4_8xxx_set_qsnt_ready(ha); - qla4_8xxx_idc_unlock(ha); -} - -/** - * qla4_8xxx_device_state_handler - Adapter state machine - * @ha: pointer to host adapter structure. - * - * Note: IDC lock must be UNLOCKED upon entry - **/ -int qla4_8xxx_device_state_handler(struct scsi_qla_host *ha) -{ - uint32_t dev_state; - int rval = QLA_SUCCESS; - unsigned long dev_init_timeout; - - if (!test_bit(AF_INIT_DONE, &ha->flags)) { - qla4_8xxx_idc_lock(ha); - qla4_8xxx_set_drv_active(ha); - qla4_8xxx_idc_unlock(ha); - } - - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - ql4_printk(KERN_INFO, ha, "1:Device state is 0x%x = %s\n", dev_state, - dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); - - /* wait for 30 seconds for device to go ready */ - dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ); - - qla4_8xxx_idc_lock(ha); - while (1) { - - if (time_after_eq(jiffies, dev_init_timeout)) { - ql4_printk(KERN_WARNING, ha, "Device init failed!\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - } - - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - ql4_printk(KERN_INFO, ha, - "2:Device state is 0x%x = %s\n", dev_state, - dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown"); - - /* NOTE: Make sure idc unlocked upon exit of switch statement */ - switch (dev_state) { - case QLA82XX_DEV_READY: - goto exit; - case QLA82XX_DEV_COLD: - rval = qla4_8xxx_device_bootstrap(ha); - goto exit; - case QLA82XX_DEV_INITIALIZING: - qla4_8xxx_idc_unlock(ha); - msleep(1000); - qla4_8xxx_idc_lock(ha); - break; - case QLA82XX_DEV_NEED_RESET: - if (!ql4xdontresethba) { - qla4_8xxx_need_reset_handler(ha); - /* Update timeout value after need - * reset handler */ - dev_init_timeout = jiffies + - (ha->nx_dev_init_timeout * HZ); - } else { - qla4_8xxx_idc_unlock(ha); - msleep(1000); - qla4_8xxx_idc_lock(ha); - } - break; - case QLA82XX_DEV_NEED_QUIESCENT: - /* idc locked/unlocked in handler */ - qla4_8xxx_need_qsnt_handler(ha); - break; - case QLA82XX_DEV_QUIESCENT: - qla4_8xxx_idc_unlock(ha); - msleep(1000); - qla4_8xxx_idc_lock(ha); - break; - case QLA82XX_DEV_FAILED: - qla4_8xxx_idc_unlock(ha); - qla4xxx_dead_adapter_cleanup(ha); - rval = QLA_ERROR; - qla4_8xxx_idc_lock(ha); - goto exit; - default: - qla4_8xxx_idc_unlock(ha); - qla4xxx_dead_adapter_cleanup(ha); - rval = QLA_ERROR; - qla4_8xxx_idc_lock(ha); - goto exit; - } - } -exit: - qla4_8xxx_idc_unlock(ha); - return rval; -} - -int qla4_8xxx_load_risc(struct scsi_qla_host *ha) -{ - int retval; - - /* clear the interrupt */ - writel(0, &ha->qla4_8xxx_reg->host_int); - readl(&ha->qla4_8xxx_reg->host_int); - - retval = qla4_8xxx_device_state_handler(ha); - - if (retval == QLA_SUCCESS && !test_bit(AF_INIT_DONE, &ha->flags)) - retval = qla4xxx_request_irqs(ha); - - return retval; -} - -/*****************************************************************************/ -/* Flash Manipulation Routines */ -/*****************************************************************************/ - -#define OPTROM_BURST_SIZE 0x1000 -#define OPTROM_BURST_DWORDS (OPTROM_BURST_SIZE / 4) - -#define FARX_DATA_FLAG BIT_31 -#define FARX_ACCESS_FLASH_CONF 0x7FFD0000 -#define FARX_ACCESS_FLASH_DATA 0x7FF00000 - -static inline uint32_t -flash_conf_addr(struct ql82xx_hw_data *hw, uint32_t faddr) -{ - return hw->flash_conf_off | faddr; -} - -static inline uint32_t -flash_data_addr(struct ql82xx_hw_data *hw, uint32_t faddr) -{ - return hw->flash_data_off | faddr; -} - -static uint32_t * -qla4_8xxx_read_flash_data(struct scsi_qla_host *ha, uint32_t *dwptr, - uint32_t faddr, uint32_t length) -{ - uint32_t i; - uint32_t val; - int loops = 0; - while ((qla4_8xxx_rom_lock(ha) != 0) && (loops < 50000)) { - udelay(100); - cond_resched(); - loops++; - } - if (loops >= 50000) { - ql4_printk(KERN_WARNING, ha, "ROM lock failed\n"); - return dwptr; - } - - /* Dword reads to flash. */ - for (i = 0; i < length/4; i++, faddr += 4) { - if (qla4_8xxx_do_rom_fast_read(ha, faddr, &val)) { - ql4_printk(KERN_WARNING, ha, - "Do ROM fast read failed\n"); - goto done_read; - } - dwptr[i] = __constant_cpu_to_le32(val); - } - -done_read: - qla4_8xxx_rom_unlock(ha); - return dwptr; -} - -/** - * Address and length are byte address - **/ -static uint8_t * -qla4_8xxx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf, - uint32_t offset, uint32_t length) -{ - qla4_8xxx_read_flash_data(ha, (uint32_t *)buf, offset, length); - return buf; -} - -static int -qla4_8xxx_find_flt_start(struct scsi_qla_host *ha, uint32_t *start) -{ - const char *loc, *locations[] = { "DEF", "PCI" }; - - /* - * FLT-location structure resides after the last PCI region. - */ - - /* Begin with sane defaults. */ - loc = locations[0]; - *start = FA_FLASH_LAYOUT_ADDR_82; - - DEBUG2(ql4_printk(KERN_INFO, ha, "FLTL[%s] = 0x%x.\n", loc, *start)); - return QLA_SUCCESS; -} - -static void -qla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr) -{ - const char *loc, *locations[] = { "DEF", "FLT" }; - uint16_t *wptr; - uint16_t cnt, chksum; - uint32_t start; - struct qla_flt_header *flt; - struct qla_flt_region *region; - struct ql82xx_hw_data *hw = &ha->hw; - - hw->flt_region_flt = flt_addr; - wptr = (uint16_t *)ha->request_ring; - flt = (struct qla_flt_header *)ha->request_ring; - region = (struct qla_flt_region *)&flt[1]; - qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring, - flt_addr << 2, OPTROM_BURST_SIZE); - if (*wptr == __constant_cpu_to_le16(0xffff)) - goto no_flash_data; - if (flt->version != __constant_cpu_to_le16(1)) { - DEBUG2(ql4_printk(KERN_INFO, ha, "Unsupported FLT detected: " - "version=0x%x length=0x%x checksum=0x%x.\n", - le16_to_cpu(flt->version), le16_to_cpu(flt->length), - le16_to_cpu(flt->checksum))); - goto no_flash_data; - } - - cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1; - for (chksum = 0; cnt; cnt--) - chksum += le16_to_cpu(*wptr++); - if (chksum) { - DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FLT detected: " - "version=0x%x length=0x%x checksum=0x%x.\n", - le16_to_cpu(flt->version), le16_to_cpu(flt->length), - chksum)); - goto no_flash_data; - } - - loc = locations[1]; - cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region); - for ( ; cnt; cnt--, region++) { - /* Store addresses as DWORD offsets. */ - start = le32_to_cpu(region->start) >> 2; - - DEBUG3(ql4_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x " - "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start, - le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size))); - - switch (le32_to_cpu(region->code) & 0xff) { - case FLT_REG_FDT: - hw->flt_region_fdt = start; - break; - case FLT_REG_BOOT_CODE_82: - hw->flt_region_boot = start; - break; - case FLT_REG_FW_82: - case FLT_REG_FW_82_1: - hw->flt_region_fw = start; - break; - case FLT_REG_BOOTLOAD_82: - hw->flt_region_bootload = start; - break; - case FLT_REG_ISCSI_PARAM: - hw->flt_iscsi_param = start; - break; - case FLT_REG_ISCSI_CHAP: - hw->flt_region_chap = start; - hw->flt_chap_size = le32_to_cpu(region->size); - break; - } - } - goto done; - -no_flash_data: - /* Use hardcoded defaults. */ - loc = locations[0]; - - hw->flt_region_fdt = FA_FLASH_DESCR_ADDR_82; - hw->flt_region_boot = FA_BOOT_CODE_ADDR_82; - hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82; - hw->flt_region_fw = FA_RISC_CODE_ADDR_82; - hw->flt_region_chap = FA_FLASH_ISCSI_CHAP; - hw->flt_chap_size = FA_FLASH_CHAP_SIZE; - -done: - DEBUG2(ql4_printk(KERN_INFO, ha, "FLT[%s]: flt=0x%x fdt=0x%x " - "boot=0x%x bootload=0x%x fw=0x%x\n", loc, hw->flt_region_flt, - hw->flt_region_fdt, hw->flt_region_boot, hw->flt_region_bootload, - hw->flt_region_fw)); -} - -static void -qla4_8xxx_get_fdt_info(struct scsi_qla_host *ha) -{ -#define FLASH_BLK_SIZE_4K 0x1000 -#define FLASH_BLK_SIZE_32K 0x8000 -#define FLASH_BLK_SIZE_64K 0x10000 - const char *loc, *locations[] = { "MID", "FDT" }; - uint16_t cnt, chksum; - uint16_t *wptr; - struct qla_fdt_layout *fdt; - uint16_t mid = 0; - uint16_t fid = 0; - struct ql82xx_hw_data *hw = &ha->hw; - - hw->flash_conf_off = FARX_ACCESS_FLASH_CONF; - hw->flash_data_off = FARX_ACCESS_FLASH_DATA; - - wptr = (uint16_t *)ha->request_ring; - fdt = (struct qla_fdt_layout *)ha->request_ring; - qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring, - hw->flt_region_fdt << 2, OPTROM_BURST_SIZE); - - if (*wptr == __constant_cpu_to_le16(0xffff)) - goto no_flash_data; - - if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || - fdt->sig[3] != 'D') - goto no_flash_data; - - for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1; - cnt++) - chksum += le16_to_cpu(*wptr++); - - if (chksum) { - DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FDT detected: " - "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0], - le16_to_cpu(fdt->version))); - goto no_flash_data; - } - - loc = locations[1]; - mid = le16_to_cpu(fdt->man_id); - fid = le16_to_cpu(fdt->id); - hw->fdt_wrt_disable = fdt->wrt_disable_bits; - hw->fdt_erase_cmd = flash_conf_addr(hw, 0x0300 | fdt->erase_cmd); - hw->fdt_block_size = le32_to_cpu(fdt->block_size); - - if (fdt->unprotect_sec_cmd) { - hw->fdt_unprotect_sec_cmd = flash_conf_addr(hw, 0x0300 | - fdt->unprotect_sec_cmd); - hw->fdt_protect_sec_cmd = fdt->protect_sec_cmd ? - flash_conf_addr(hw, 0x0300 | fdt->protect_sec_cmd) : - flash_conf_addr(hw, 0x0336); - } - goto done; - -no_flash_data: - loc = locations[0]; - hw->fdt_block_size = FLASH_BLK_SIZE_64K; -done: - DEBUG2(ql4_printk(KERN_INFO, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x " - "pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid, - hw->fdt_erase_cmd, hw->fdt_protect_sec_cmd, - hw->fdt_unprotect_sec_cmd, hw->fdt_wrt_disable, - hw->fdt_block_size)); -} - -static void -qla4_8xxx_get_idc_param(struct scsi_qla_host *ha) -{ -#define QLA82XX_IDC_PARAM_ADDR 0x003e885c - uint32_t *wptr; - - if (!is_qla8022(ha)) - return; - wptr = (uint32_t *)ha->request_ring; - qla4_8xxx_read_optrom_data(ha, (uint8_t *)ha->request_ring, - QLA82XX_IDC_PARAM_ADDR , 8); - - if (*wptr == __constant_cpu_to_le32(0xffffffff)) { - ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT; - ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT; - } else { - ha->nx_dev_init_timeout = le32_to_cpu(*wptr++); - ha->nx_reset_timeout = le32_to_cpu(*wptr); - } - - DEBUG2(ql4_printk(KERN_DEBUG, ha, - "ha->nx_dev_init_timeout = %d\n", ha->nx_dev_init_timeout)); - DEBUG2(ql4_printk(KERN_DEBUG, ha, - "ha->nx_reset_timeout = %d\n", ha->nx_reset_timeout)); - return; -} - -int -qla4_8xxx_get_flash_info(struct scsi_qla_host *ha) -{ - int ret; - uint32_t flt_addr; - - ret = qla4_8xxx_find_flt_start(ha, &flt_addr); - if (ret != QLA_SUCCESS) - return ret; - - qla4_8xxx_get_flt_info(ha, flt_addr); - qla4_8xxx_get_fdt_info(ha); - qla4_8xxx_get_idc_param(ha); - - return QLA_SUCCESS; -} - -/** - * qla4_8xxx_stop_firmware - stops firmware on specified adapter instance - * @ha: pointer to host adapter structure. - * - * Remarks: - * For iSCSI, throws away all I/O and AENs into bit bucket, so they will - * not be available after successful return. Driver must cleanup potential - * outstanding I/O's after calling this funcion. - **/ -int -qla4_8xxx_stop_firmware(struct scsi_qla_host *ha) -{ - int status; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_STOP_FW; - status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, - &mbox_cmd[0], &mbox_sts[0]); - - DEBUG2(printk("scsi%ld: %s: status = %d\n", ha->host_no, - __func__, status)); - return status; -} - -/** - * qla4_8xxx_isp_reset - Resets ISP and aborts all outstanding commands. - * @ha: pointer to host adapter structure. - **/ -int -qla4_8xxx_isp_reset(struct scsi_qla_host *ha) -{ - int rval; - uint32_t dev_state; - - qla4_8xxx_idc_lock(ha); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - - if (dev_state == QLA82XX_DEV_READY) { - ql4_printk(KERN_INFO, ha, "HW State: NEED RESET\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_NEED_RESET); - } else - ql4_printk(KERN_INFO, ha, "HW State: DEVICE INITIALIZING\n"); - - qla4_8xxx_idc_unlock(ha); - - rval = qla4_8xxx_device_state_handler(ha); - - qla4_8xxx_idc_lock(ha); - qla4_8xxx_clear_rst_ready(ha); - qla4_8xxx_idc_unlock(ha); - - if (rval == QLA_SUCCESS) - clear_bit(AF_FW_RECOVERY, &ha->flags); - - return rval; -} - -/** - * qla4_8xxx_get_sys_info - get adapter MAC address(es) and serial number - * @ha: pointer to host adapter structure. - * - **/ -int qla4_8xxx_get_sys_info(struct scsi_qla_host *ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - struct mbx_sys_info *sys_info; - dma_addr_t sys_info_dma; - int status = QLA_ERROR; - - sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info), - &sys_info_dma, GFP_KERNEL); - if (sys_info == NULL) { - DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n", - ha->host_no, __func__)); - return status; - } - - memset(sys_info, 0, sizeof(*sys_info)); - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - mbox_cmd[0] = MBOX_CMD_GET_SYS_INFO; - mbox_cmd[1] = LSDW(sys_info_dma); - mbox_cmd[2] = MSDW(sys_info_dma); - mbox_cmd[4] = sizeof(*sys_info); - - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 6, &mbox_cmd[0], - &mbox_sts[0]) != QLA_SUCCESS) { - DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO failed\n", - ha->host_no, __func__)); - goto exit_validate_mac82; - } - - /* Make sure we receive the minimum required data to cache internally */ - if (mbox_sts[4] < offsetof(struct mbx_sys_info, reserved)) { - DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO data receive" - " error (%x)\n", ha->host_no, __func__, mbox_sts[4])); - goto exit_validate_mac82; - - } - - /* Save M.A.C. address & serial_number */ - ha->port_num = sys_info->port_num; - memcpy(ha->my_mac, &sys_info->mac_addr[0], - min(sizeof(ha->my_mac), sizeof(sys_info->mac_addr))); - memcpy(ha->serial_number, &sys_info->serial_number, - min(sizeof(ha->serial_number), sizeof(sys_info->serial_number))); - memcpy(ha->model_name, &sys_info->board_id_str, - min(sizeof(ha->model_name), sizeof(sys_info->board_id_str))); - ha->phy_port_cnt = sys_info->phys_port_cnt; - ha->phy_port_num = sys_info->port_num; - ha->iscsi_pci_func_cnt = sys_info->iscsi_pci_func_cnt; - - DEBUG2(printk("scsi%ld: %s: " - "mac %02x:%02x:%02x:%02x:%02x:%02x " - "serial %s\n", ha->host_no, __func__, - ha->my_mac[0], ha->my_mac[1], ha->my_mac[2], - ha->my_mac[3], ha->my_mac[4], ha->my_mac[5], - ha->serial_number)); - - status = QLA_SUCCESS; - -exit_validate_mac82: - dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info, - sys_info_dma); - return status; -} - -/* Interrupt handling helpers. */ - -static int -qla4_8xxx_mbx_intr_enable(struct scsi_qla_host *ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__)); - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS; - mbox_cmd[1] = INTR_ENABLE; - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], - &mbox_sts[0]) != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n", - __func__, mbox_sts[0])); - return QLA_ERROR; - } - return QLA_SUCCESS; -} - -static int -qla4_8xxx_mbx_intr_disable(struct scsi_qla_host *ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - - DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__)); - - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS; - mbox_cmd[1] = INTR_DISABLE; - if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0], - &mbox_sts[0]) != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n", - __func__, mbox_sts[0])); - return QLA_ERROR; - } - - return QLA_SUCCESS; -} - -void -qla4_8xxx_enable_intrs(struct scsi_qla_host *ha) -{ - qla4_8xxx_mbx_intr_enable(ha); - - spin_lock_irq(&ha->hardware_lock); - /* BIT 10 - reset */ - qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff); - spin_unlock_irq(&ha->hardware_lock); - set_bit(AF_INTERRUPTS_ON, &ha->flags); -} - -void -qla4_8xxx_disable_intrs(struct scsi_qla_host *ha) -{ - if (test_and_clear_bit(AF_INTERRUPTS_ON, &ha->flags)) - qla4_8xxx_mbx_intr_disable(ha); - - spin_lock_irq(&ha->hardware_lock); - /* BIT 10 - set */ - qla4_8xxx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400); - spin_unlock_irq(&ha->hardware_lock); -} - -struct ql4_init_msix_entry { - uint16_t entry; - uint16_t index; - const char *name; - irq_handler_t handler; -}; - -static struct ql4_init_msix_entry qla4_8xxx_msix_entries[QLA_MSIX_ENTRIES] = { - { QLA_MSIX_DEFAULT, QLA_MIDX_DEFAULT, - "qla4xxx (default)", - (irq_handler_t)qla4_8xxx_default_intr_handler }, - { QLA_MSIX_RSP_Q, QLA_MIDX_RSP_Q, - "qla4xxx (rsp_q)", (irq_handler_t)qla4_8xxx_msix_rsp_q }, -}; - -void -qla4_8xxx_disable_msix(struct scsi_qla_host *ha) -{ - int i; - struct ql4_msix_entry *qentry; - - for (i = 0; i < QLA_MSIX_ENTRIES; i++) { - qentry = &ha->msix_entries[qla4_8xxx_msix_entries[i].index]; - if (qentry->have_irq) { - free_irq(qentry->msix_vector, ha); - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %s\n", - __func__, qla4_8xxx_msix_entries[i].name)); - } - } - pci_disable_msix(ha->pdev); - clear_bit(AF_MSIX_ENABLED, &ha->flags); -} - -int -qla4_8xxx_enable_msix(struct scsi_qla_host *ha) -{ - int i, ret; - struct msix_entry entries[QLA_MSIX_ENTRIES]; - struct ql4_msix_entry *qentry; - - for (i = 0; i < QLA_MSIX_ENTRIES; i++) - entries[i].entry = qla4_8xxx_msix_entries[i].entry; - - ret = pci_enable_msix(ha->pdev, entries, ARRAY_SIZE(entries)); - if (ret) { - ql4_printk(KERN_WARNING, ha, - "MSI-X: Failed to enable support -- %d/%d\n", - QLA_MSIX_ENTRIES, ret); - goto msix_out; - } - set_bit(AF_MSIX_ENABLED, &ha->flags); - - for (i = 0; i < QLA_MSIX_ENTRIES; i++) { - qentry = &ha->msix_entries[qla4_8xxx_msix_entries[i].index]; - qentry->msix_vector = entries[i].vector; - qentry->msix_entry = entries[i].entry; - qentry->have_irq = 0; - ret = request_irq(qentry->msix_vector, - qla4_8xxx_msix_entries[i].handler, 0, - qla4_8xxx_msix_entries[i].name, ha); - if (ret) { - ql4_printk(KERN_WARNING, ha, - "MSI-X: Unable to register handler -- %x/%d.\n", - qla4_8xxx_msix_entries[i].index, ret); - qla4_8xxx_disable_msix(ha); - goto msix_out; - } - qentry->have_irq = 1; - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %s\n", - __func__, qla4_8xxx_msix_entries[i].name)); - } -msix_out: - return ret; -} diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.h deleted file mode 100644 index dc7500e4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_nx.h +++ /dev/null @@ -1,795 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ -#ifndef __QLA_NX_H -#define __QLA_NX_H - -/* - * Following are the states of the Phantom. Phantom will set them and - * Host will read to check if the fields are correct. -*/ -#define PHAN_INITIALIZE_FAILED 0xffff -#define PHAN_INITIALIZE_COMPLETE 0xff01 - -/* Host writes the following to notify that it has done the init-handshake */ -#define PHAN_INITIALIZE_ACK 0xf00f -#define PHAN_PEG_RCV_INITIALIZED 0xff01 - -/*CRB_RELATED*/ -#define QLA82XX_CRB_BASE (QLA82XX_CAM_RAM(0x200)) -#define QLA82XX_REG(X) (QLA82XX_CRB_BASE+(X)) -#define CRB_CMDPEG_STATE QLA82XX_REG(0x50) -#define CRB_RCVPEG_STATE QLA82XX_REG(0x13c) -#define CRB_DMA_SHIFT QLA82XX_REG(0xcc) -#define CRB_TEMP_STATE QLA82XX_REG(0x1b4) - -#define qla82xx_get_temp_val(x) ((x) >> 16) -#define qla82xx_get_temp_state(x) ((x) & 0xffff) -#define qla82xx_encode_temp(val, state) (((val) << 16) | (state)) - -/* - * Temperature control. - */ -enum { - QLA82XX_TEMP_NORMAL = 0x1, /* Normal operating range */ - QLA82XX_TEMP_WARN, /* Sound alert, temperature getting high */ - QLA82XX_TEMP_PANIC /* Fatal error, hardware has shut down. */ -}; - -#define CRB_NIU_XG_PAUSE_CTL_P0 0x1 -#define CRB_NIU_XG_PAUSE_CTL_P1 0x8 - -#define QLA82XX_HW_H0_CH_HUB_ADR 0x05 -#define QLA82XX_HW_H1_CH_HUB_ADR 0x0E -#define QLA82XX_HW_H2_CH_HUB_ADR 0x03 -#define QLA82XX_HW_H3_CH_HUB_ADR 0x01 -#define QLA82XX_HW_H4_CH_HUB_ADR 0x06 -#define QLA82XX_HW_H5_CH_HUB_ADR 0x07 -#define QLA82XX_HW_H6_CH_HUB_ADR 0x08 - -/* Hub 0 */ -#define QLA82XX_HW_MN_CRB_AGT_ADR 0x15 -#define QLA82XX_HW_MS_CRB_AGT_ADR 0x25 - -/* Hub 1 */ -#define QLA82XX_HW_PS_CRB_AGT_ADR 0x73 -#define QLA82XX_HW_QMS_CRB_AGT_ADR 0x00 -#define QLA82XX_HW_RPMX3_CRB_AGT_ADR 0x0b -#define QLA82XX_HW_SQGS0_CRB_AGT_ADR 0x01 -#define QLA82XX_HW_SQGS1_CRB_AGT_ADR 0x02 -#define QLA82XX_HW_SQGS2_CRB_AGT_ADR 0x03 -#define QLA82XX_HW_SQGS3_CRB_AGT_ADR 0x04 -#define QLA82XX_HW_C2C0_CRB_AGT_ADR 0x58 -#define QLA82XX_HW_C2C1_CRB_AGT_ADR 0x59 -#define QLA82XX_HW_C2C2_CRB_AGT_ADR 0x5a -#define QLA82XX_HW_RPMX2_CRB_AGT_ADR 0x0a -#define QLA82XX_HW_RPMX4_CRB_AGT_ADR 0x0c -#define QLA82XX_HW_RPMX7_CRB_AGT_ADR 0x0f -#define QLA82XX_HW_RPMX9_CRB_AGT_ADR 0x12 -#define QLA82XX_HW_SMB_CRB_AGT_ADR 0x18 - -/* Hub 2 */ -#define QLA82XX_HW_NIU_CRB_AGT_ADR 0x31 -#define QLA82XX_HW_I2C0_CRB_AGT_ADR 0x19 -#define QLA82XX_HW_I2C1_CRB_AGT_ADR 0x29 - -#define QLA82XX_HW_SN_CRB_AGT_ADR 0x10 -#define QLA82XX_HW_I2Q_CRB_AGT_ADR 0x20 -#define QLA82XX_HW_LPC_CRB_AGT_ADR 0x22 -#define QLA82XX_HW_ROMUSB_CRB_AGT_ADR 0x21 -#define QLA82XX_HW_QM_CRB_AGT_ADR 0x66 -#define QLA82XX_HW_SQG0_CRB_AGT_ADR 0x60 -#define QLA82XX_HW_SQG1_CRB_AGT_ADR 0x61 -#define QLA82XX_HW_SQG2_CRB_AGT_ADR 0x62 -#define QLA82XX_HW_SQG3_CRB_AGT_ADR 0x63 -#define QLA82XX_HW_RPMX1_CRB_AGT_ADR 0x09 -#define QLA82XX_HW_RPMX5_CRB_AGT_ADR 0x0d -#define QLA82XX_HW_RPMX6_CRB_AGT_ADR 0x0e -#define QLA82XX_HW_RPMX8_CRB_AGT_ADR 0x11 - -/* Hub 3 */ -#define QLA82XX_HW_PH_CRB_AGT_ADR 0x1A -#define QLA82XX_HW_SRE_CRB_AGT_ADR 0x50 -#define QLA82XX_HW_EG_CRB_AGT_ADR 0x51 -#define QLA82XX_HW_RPMX0_CRB_AGT_ADR 0x08 - -/* Hub 4 */ -#define QLA82XX_HW_PEGN0_CRB_AGT_ADR 0x40 -#define QLA82XX_HW_PEGN1_CRB_AGT_ADR 0x41 -#define QLA82XX_HW_PEGN2_CRB_AGT_ADR 0x42 -#define QLA82XX_HW_PEGN3_CRB_AGT_ADR 0x43 -#define QLA82XX_HW_PEGNI_CRB_AGT_ADR 0x44 -#define QLA82XX_HW_PEGND_CRB_AGT_ADR 0x45 -#define QLA82XX_HW_PEGNC_CRB_AGT_ADR 0x46 -#define QLA82XX_HW_PEGR0_CRB_AGT_ADR 0x47 -#define QLA82XX_HW_PEGR1_CRB_AGT_ADR 0x48 -#define QLA82XX_HW_PEGR2_CRB_AGT_ADR 0x49 -#define QLA82XX_HW_PEGR3_CRB_AGT_ADR 0x4a -#define QLA82XX_HW_PEGN4_CRB_AGT_ADR 0x4b - -/* Hub 5 */ -#define QLA82XX_HW_PEGS0_CRB_AGT_ADR 0x40 -#define QLA82XX_HW_PEGS1_CRB_AGT_ADR 0x41 -#define QLA82XX_HW_PEGS2_CRB_AGT_ADR 0x42 -#define QLA82XX_HW_PEGS3_CRB_AGT_ADR 0x43 - -#define QLA82XX_HW_PEGSI_CRB_AGT_ADR 0x44 -#define QLA82XX_HW_PEGSD_CRB_AGT_ADR 0x45 -#define QLA82XX_HW_PEGSC_CRB_AGT_ADR 0x46 - -/* Hub 6 */ -#define QLA82XX_HW_CAS0_CRB_AGT_ADR 0x46 -#define QLA82XX_HW_CAS1_CRB_AGT_ADR 0x47 -#define QLA82XX_HW_CAS2_CRB_AGT_ADR 0x48 -#define QLA82XX_HW_CAS3_CRB_AGT_ADR 0x49 -#define QLA82XX_HW_NCM_CRB_AGT_ADR 0x16 -#define QLA82XX_HW_TMR_CRB_AGT_ADR 0x17 -#define QLA82XX_HW_XDMA_CRB_AGT_ADR 0x05 -#define QLA82XX_HW_OCM0_CRB_AGT_ADR 0x06 -#define QLA82XX_HW_OCM1_CRB_AGT_ADR 0x07 - -/* This field defines PCI/X adr [25:20] of agents on the CRB */ -/* */ -#define QLA82XX_HW_PX_MAP_CRB_PH 0 -#define QLA82XX_HW_PX_MAP_CRB_PS 1 -#define QLA82XX_HW_PX_MAP_CRB_MN 2 -#define QLA82XX_HW_PX_MAP_CRB_MS 3 -#define QLA82XX_HW_PX_MAP_CRB_SRE 5 -#define QLA82XX_HW_PX_MAP_CRB_NIU 6 -#define QLA82XX_HW_PX_MAP_CRB_QMN 7 -#define QLA82XX_HW_PX_MAP_CRB_SQN0 8 -#define QLA82XX_HW_PX_MAP_CRB_SQN1 9 -#define QLA82XX_HW_PX_MAP_CRB_SQN2 10 -#define QLA82XX_HW_PX_MAP_CRB_SQN3 11 -#define QLA82XX_HW_PX_MAP_CRB_QMS 12 -#define QLA82XX_HW_PX_MAP_CRB_SQS0 13 -#define QLA82XX_HW_PX_MAP_CRB_SQS1 14 -#define QLA82XX_HW_PX_MAP_CRB_SQS2 15 -#define QLA82XX_HW_PX_MAP_CRB_SQS3 16 -#define QLA82XX_HW_PX_MAP_CRB_PGN0 17 -#define QLA82XX_HW_PX_MAP_CRB_PGN1 18 -#define QLA82XX_HW_PX_MAP_CRB_PGN2 19 -#define QLA82XX_HW_PX_MAP_CRB_PGN3 20 -#define QLA82XX_HW_PX_MAP_CRB_PGN4 QLA82XX_HW_PX_MAP_CRB_SQS2 -#define QLA82XX_HW_PX_MAP_CRB_PGND 21 -#define QLA82XX_HW_PX_MAP_CRB_PGNI 22 -#define QLA82XX_HW_PX_MAP_CRB_PGS0 23 -#define QLA82XX_HW_PX_MAP_CRB_PGS1 24 -#define QLA82XX_HW_PX_MAP_CRB_PGS2 25 -#define QLA82XX_HW_PX_MAP_CRB_PGS3 26 -#define QLA82XX_HW_PX_MAP_CRB_PGSD 27 -#define QLA82XX_HW_PX_MAP_CRB_PGSI 28 -#define QLA82XX_HW_PX_MAP_CRB_SN 29 -#define QLA82XX_HW_PX_MAP_CRB_EG 31 -#define QLA82XX_HW_PX_MAP_CRB_PH2 32 -#define QLA82XX_HW_PX_MAP_CRB_PS2 33 -#define QLA82XX_HW_PX_MAP_CRB_CAM 34 -#define QLA82XX_HW_PX_MAP_CRB_CAS0 35 -#define QLA82XX_HW_PX_MAP_CRB_CAS1 36 -#define QLA82XX_HW_PX_MAP_CRB_CAS2 37 -#define QLA82XX_HW_PX_MAP_CRB_C2C0 38 -#define QLA82XX_HW_PX_MAP_CRB_C2C1 39 -#define QLA82XX_HW_PX_MAP_CRB_TIMR 40 -#define QLA82XX_HW_PX_MAP_CRB_RPMX1 42 -#define QLA82XX_HW_PX_MAP_CRB_RPMX2 43 -#define QLA82XX_HW_PX_MAP_CRB_RPMX3 44 -#define QLA82XX_HW_PX_MAP_CRB_RPMX4 45 -#define QLA82XX_HW_PX_MAP_CRB_RPMX5 46 -#define QLA82XX_HW_PX_MAP_CRB_RPMX6 47 -#define QLA82XX_HW_PX_MAP_CRB_RPMX7 48 -#define QLA82XX_HW_PX_MAP_CRB_XDMA 49 -#define QLA82XX_HW_PX_MAP_CRB_I2Q 50 -#define QLA82XX_HW_PX_MAP_CRB_ROMUSB 51 -#define QLA82XX_HW_PX_MAP_CRB_CAS3 52 -#define QLA82XX_HW_PX_MAP_CRB_RPMX0 53 -#define QLA82XX_HW_PX_MAP_CRB_RPMX8 54 -#define QLA82XX_HW_PX_MAP_CRB_RPMX9 55 -#define QLA82XX_HW_PX_MAP_CRB_OCM0 56 -#define QLA82XX_HW_PX_MAP_CRB_OCM1 57 -#define QLA82XX_HW_PX_MAP_CRB_SMB 58 -#define QLA82XX_HW_PX_MAP_CRB_I2C0 59 -#define QLA82XX_HW_PX_MAP_CRB_I2C1 60 -#define QLA82XX_HW_PX_MAP_CRB_LPC 61 -#define QLA82XX_HW_PX_MAP_CRB_PGNC 62 -#define QLA82XX_HW_PX_MAP_CRB_PGR0 63 -#define QLA82XX_HW_PX_MAP_CRB_PGR1 4 -#define QLA82XX_HW_PX_MAP_CRB_PGR2 30 -#define QLA82XX_HW_PX_MAP_CRB_PGR3 41 - -/* This field defines CRB adr [31:20] of the agents */ -/* */ - -#define QLA82XX_HW_CRB_HUB_AGT_ADR_MN ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ - QLA82XX_HW_MN_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PH ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PH_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_MS ((QLA82XX_HW_H0_CH_HUB_ADR << 7) | \ - QLA82XX_HW_MS_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PS_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SS_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMS ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_QMS_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS0 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQGS0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS1 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQGS1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS2 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQGS2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQS3 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQGS3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C0 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_C2C0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_C2C1 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_C2C1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX4_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX7_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9 ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX9_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SMB ((QLA82XX_HW_H1_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SMB_CRB_AGT_ADR) - -#define QLA82XX_HW_CRB_HUB_AGT_ADR_NIU ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ - QLA82XX_HW_NIU_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0 ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ - QLA82XX_HW_I2C0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1 ((QLA82XX_HW_H2_CH_HUB_ADR << 7) | \ - QLA82XX_HW_I2C1_CRB_AGT_ADR) - -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SRE ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SRE_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_EG ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_EG_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_QMN ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_QM_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQG0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQG1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQG2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SQG3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX5_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX6_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_RPMX8_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS0 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_CAS0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS1 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_CAS1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS2 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_CAS2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAS3 ((QLA82XX_HW_H3_CH_HUB_ADR << 7) | \ - QLA82XX_HW_CAS3_CRB_AGT_ADR) - -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGNI_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGND ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGND_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGN4_CRB_AGT_ADR) - -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGNC_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR0 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGR0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR1 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGR1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR2 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGR2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGR3 ((QLA82XX_HW_H4_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGR3_CRB_AGT_ADR) - -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGSI_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSD ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGSD_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGS0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGS1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGS2_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3 ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGS3_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_PGSC ((QLA82XX_HW_H5_CH_HUB_ADR << 7) | \ - QLA82XX_HW_PEGSC_CRB_AGT_ADR) - -#define QLA82XX_HW_CRB_HUB_AGT_ADR_CAM ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_NCM_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_TMR_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_XDMA_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_SN ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_SN_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_I2Q_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_ROMUSB_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0 ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_OCM0_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_OCM1 ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_OCM1_CRB_AGT_ADR) -#define QLA82XX_HW_CRB_HUB_AGT_ADR_LPC ((QLA82XX_HW_H6_CH_HUB_ADR << 7) | \ - QLA82XX_HW_LPC_CRB_AGT_ADR) - -#define ROMUSB_GLB (QLA82XX_CRB_ROMUSB + 0x00000) -#define QLA82XX_ROMUSB_GLB_PEGTUNE_DONE (ROMUSB_GLB + 0x005c) -#define QLA82XX_ROMUSB_GLB_STATUS (ROMUSB_GLB + 0x0004) -#define QLA82XX_ROMUSB_GLB_SW_RESET (ROMUSB_GLB + 0x0008) -#define QLA82XX_ROMUSB_ROM_ADDRESS (ROMUSB_ROM + 0x0008) -#define QLA82XX_ROMUSB_ROM_WDATA (ROMUSB_ROM + 0x000c) -#define QLA82XX_ROMUSB_ROM_ABYTE_CNT (ROMUSB_ROM + 0x0010) -#define QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT (ROMUSB_ROM + 0x0014) -#define QLA82XX_ROMUSB_ROM_RDATA (ROMUSB_ROM + 0x0018) - -#define ROMUSB_ROM (QLA82XX_CRB_ROMUSB + 0x10000) -#define QLA82XX_ROMUSB_ROM_INSTR_OPCODE (ROMUSB_ROM + 0x0004) -#define QLA82XX_ROMUSB_GLB_CAS_RST (ROMUSB_GLB + 0x0038) - -/* Lock IDs for ROM lock */ -#define ROM_LOCK_DRIVER 0x0d417340 - -#define QLA82XX_PCI_CRB_WINDOWSIZE 0x00100000 /* all are 1MB windows */ -#define QLA82XX_PCI_CRB_WINDOW(A) (QLA82XX_PCI_CRBSPACE + \ - (A)*QLA82XX_PCI_CRB_WINDOWSIZE) - -#define QLA82XX_CRB_C2C_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C0) -#define QLA82XX_CRB_C2C_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C1) -#define QLA82XX_CRB_C2C_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_C2C2) -#define QLA82XX_CRB_CAM \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAM) -#define QLA82XX_CRB_CASPER \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS) -#define QLA82XX_CRB_CASPER_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS0) -#define QLA82XX_CRB_CASPER_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS1) -#define QLA82XX_CRB_CASPER_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_CAS2) -#define QLA82XX_CRB_DDR_MD \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MS) -#define QLA82XX_CRB_DDR_NET \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_MN) -#define QLA82XX_CRB_EPG \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_EG) -#define QLA82XX_CRB_I2Q \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2Q) -#define QLA82XX_CRB_NIU \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_NIU) -/* HACK upon HACK upon HACK (for PCIE builds) */ -#define QLA82XX_CRB_PCIX_HOST \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH) -#define QLA82XX_CRB_PCIX_HOST2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PH2) -#define QLA82XX_CRB_PCIX_MD \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS) -#define QLA82XX_CRB_PCIE QLA82XX_CRB_PCIX_MD -/* window 1 pcie slot */ -#define QLA82XX_CRB_PCIE2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PS2) - -#define QLA82XX_CRB_PEG_MD_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS0) -#define QLA82XX_CRB_PEG_MD_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS1) -#define QLA82XX_CRB_PEG_MD_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS2) -#define QLA82XX_CRB_PEG_MD_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3) -#define QLA82XX_CRB_PEG_MD_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGS3) -#define QLA82XX_CRB_PEG_MD_D \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSD) -#define QLA82XX_CRB_PEG_MD_I \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGSI) -#define QLA82XX_CRB_PEG_NET_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN0) -#define QLA82XX_CRB_PEG_NET_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN1) -#define QLA82XX_CRB_PEG_NET_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN2) -#define QLA82XX_CRB_PEG_NET_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN3) -#define QLA82XX_CRB_PEG_NET_4 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGN4) -#define QLA82XX_CRB_PEG_NET_D \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGND) -#define QLA82XX_CRB_PEG_NET_I \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_PGNI) -#define QLA82XX_CRB_PQM_MD \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMS) -#define QLA82XX_CRB_PQM_NET \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_QMN) -#define QLA82XX_CRB_QDR_MD \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SS) -#define QLA82XX_CRB_QDR_NET \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SN) -#define QLA82XX_CRB_ROMUSB \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_ROMUSB) -#define QLA82XX_CRB_RPMX_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX0) -#define QLA82XX_CRB_RPMX_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX1) -#define QLA82XX_CRB_RPMX_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX2) -#define QLA82XX_CRB_RPMX_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX3) -#define QLA82XX_CRB_RPMX_4 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX4) -#define QLA82XX_CRB_RPMX_5 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX5) -#define QLA82XX_CRB_RPMX_6 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX6) -#define QLA82XX_CRB_RPMX_7 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_RPMX7) -#define QLA82XX_CRB_SQM_MD_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS0) -#define QLA82XX_CRB_SQM_MD_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS1) -#define QLA82XX_CRB_SQM_MD_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS2) -#define QLA82XX_CRB_SQM_MD_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQS3) -#define QLA82XX_CRB_SQM_NET_0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN0) -#define QLA82XX_CRB_SQM_NET_1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN1) -#define QLA82XX_CRB_SQM_NET_2 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN2) -#define QLA82XX_CRB_SQM_NET_3 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SQN3) -#define QLA82XX_CRB_SRE \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SRE) -#define QLA82XX_CRB_TIMER \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_TIMR) -#define QLA82XX_CRB_XDMA \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_XDMA) -#define QLA82XX_CRB_I2C0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C0) -#define QLA82XX_CRB_I2C1 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_I2C1) -#define QLA82XX_CRB_OCM0 \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_OCM0) -#define QLA82XX_CRB_SMB \ - QLA82XX_PCI_CRB_WINDOW(QLA82XX_HW_PX_MAP_CRB_SMB) - -#define QLA82XX_CRB_MAX QLA82XX_PCI_CRB_WINDOW(64) - -/* - * ====================== BASE ADDRESSES ON-CHIP ====================== - * Base addresses of major components on-chip. - * ====================== BASE ADDRESSES ON-CHIP ====================== - */ -#define QLA82XX_ADDR_DDR_NET (0x0000000000000000ULL) -#define QLA82XX_ADDR_DDR_NET_MAX (0x000000000fffffffULL) - -/* Imbus address bit used to indicate a host address. This bit is - * eliminated by the pcie bar and bar select before presentation - * over pcie. */ -/* host memory via IMBUS */ -#define QLA82XX_P2_ADDR_PCIE (0x0000000800000000ULL) -#define QLA82XX_P3_ADDR_PCIE (0x0000008000000000ULL) -#define QLA82XX_ADDR_PCIE_MAX (0x0000000FFFFFFFFFULL) -#define QLA82XX_ADDR_OCM0 (0x0000000200000000ULL) -#define QLA82XX_ADDR_OCM0_MAX (0x00000002000fffffULL) -#define QLA82XX_ADDR_OCM1 (0x0000000200400000ULL) -#define QLA82XX_ADDR_OCM1_MAX (0x00000002004fffffULL) -#define QLA82XX_ADDR_QDR_NET (0x0000000300000000ULL) - -#define QLA82XX_P2_ADDR_QDR_NET_MAX (0x00000003001fffffULL) -#define QLA82XX_P3_ADDR_QDR_NET_MAX (0x0000000303ffffffULL) - -#define QLA82XX_PCI_CRBSPACE (unsigned long)0x06000000 -#define QLA82XX_PCI_DIRECT_CRB (unsigned long)0x04400000 -#define QLA82XX_PCI_CAMQM (unsigned long)0x04800000 -#define QLA82XX_PCI_CAMQM_MAX (unsigned long)0x04ffffff -#define QLA82XX_PCI_DDR_NET (unsigned long)0x00000000 -#define QLA82XX_PCI_QDR_NET (unsigned long)0x04000000 -#define QLA82XX_PCI_QDR_NET_MAX (unsigned long)0x043fffff - -/* - * Register offsets for MN - */ -#define MIU_CONTROL (0x000) -#define MIU_TAG (0x004) -#define MIU_TEST_AGT_CTRL (0x090) -#define MIU_TEST_AGT_ADDR_LO (0x094) -#define MIU_TEST_AGT_ADDR_HI (0x098) -#define MIU_TEST_AGT_WRDATA_LO (0x0a0) -#define MIU_TEST_AGT_WRDATA_HI (0x0a4) -#define MIU_TEST_AGT_WRDATA(i) (0x0a0+(4*(i))) -#define MIU_TEST_AGT_RDDATA_LO (0x0a8) -#define MIU_TEST_AGT_RDDATA_HI (0x0ac) -#define MIU_TEST_AGT_RDDATA(i) (0x0a8+(4*(i))) -#define MIU_TEST_AGT_ADDR_MASK 0xfffffff8 -#define MIU_TEST_AGT_UPPER_ADDR(off) (0) - -/* MIU_TEST_AGT_CTRL flags. work for SIU as well */ -#define MIU_TA_CTL_START 1 -#define MIU_TA_CTL_ENABLE 2 -#define MIU_TA_CTL_WRITE 4 -#define MIU_TA_CTL_BUSY 8 - -/*CAM RAM */ -# define QLA82XX_CAM_RAM_BASE (QLA82XX_CRB_CAM + 0x02000) -# define QLA82XX_CAM_RAM(reg) (QLA82XX_CAM_RAM_BASE + (reg)) - -#define QLA82XX_PORT_MODE_ADDR (QLA82XX_CAM_RAM(0x24)) -#define QLA82XX_PEG_HALT_STATUS1 (QLA82XX_CAM_RAM(0xa8)) -#define QLA82XX_PEG_HALT_STATUS2 (QLA82XX_CAM_RAM(0xac)) -#define QLA82XX_PEG_ALIVE_COUNTER (QLA82XX_CAM_RAM(0xb0)) -#define QLA82XX_CAM_RAM_DB1 (QLA82XX_CAM_RAM(0x1b0)) -#define QLA82XX_CAM_RAM_DB2 (QLA82XX_CAM_RAM(0x1b4)) - -#define HALT_STATUS_UNRECOVERABLE 0x80000000 -#define HALT_STATUS_RECOVERABLE 0x40000000 - - -#define QLA82XX_ROM_LOCK_ID (QLA82XX_CAM_RAM(0x100)) -#define QLA82XX_CRB_WIN_LOCK_ID (QLA82XX_CAM_RAM(0x124)) -#define QLA82XX_FW_VERSION_MAJOR (QLA82XX_CAM_RAM(0x150)) -#define QLA82XX_FW_VERSION_MINOR (QLA82XX_CAM_RAM(0x154)) -#define QLA82XX_FW_VERSION_SUB (QLA82XX_CAM_RAM(0x158)) -#define QLA82XX_PCIE_REG(reg) (QLA82XX_CRB_PCIE + (reg)) - -/* Driver Coexistence Defines */ -#define QLA82XX_CRB_DRV_ACTIVE (QLA82XX_CAM_RAM(0x138)) -#define QLA82XX_CRB_DEV_STATE (QLA82XX_CAM_RAM(0x140)) -#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c)) -#define QLA82XX_CRB_DRV_IDC_VERSION (QLA82XX_CAM_RAM(0x174)) -#define QLA82XX_CRB_DRV_STATE (QLA82XX_CAM_RAM(0x144)) -#define QLA82XX_CRB_DRV_SCRATCH (QLA82XX_CAM_RAM(0x148)) -#define QLA82XX_CRB_DEV_PART_INFO (QLA82XX_CAM_RAM(0x14c)) - -/* Every driver should use these Device State */ -#define QLA82XX_DEV_COLD 1 -#define QLA82XX_DEV_INITIALIZING 2 -#define QLA82XX_DEV_READY 3 -#define QLA82XX_DEV_NEED_RESET 4 -#define QLA82XX_DEV_NEED_QUIESCENT 5 -#define QLA82XX_DEV_FAILED 6 -#define QLA82XX_DEV_QUIESCENT 7 -#define MAX_STATES 8 /* Increment if new state added */ - -#define QLA82XX_IDC_VERSION 0x1 -#define ROM_DEV_INIT_TIMEOUT 30 -#define ROM_DRV_RESET_ACK_TIMEOUT 10 - -#define PCIE_SETUP_FUNCTION (0x12040) -#define PCIE_SETUP_FUNCTION2 (0x12048) - -#define QLA82XX_PCIX_PS_REG(reg) (QLA82XX_CRB_PCIX_MD + (reg)) -#define QLA82XX_PCIX_PS2_REG(reg) (QLA82XX_CRB_PCIE2 + (reg)) - -#define PCIE_SEM2_LOCK (0x1c010) /* Flash lock */ -#define PCIE_SEM2_UNLOCK (0x1c014) /* Flash unlock */ -#define PCIE_SEM5_LOCK (0x1c028) /* Coexistence lock */ -#define PCIE_SEM5_UNLOCK (0x1c02c) /* Coexistence unlock */ -#define PCIE_SEM7_LOCK (0x1c038) /* crb win lock */ -#define PCIE_SEM7_UNLOCK (0x1c03c) /* crbwin unlock*/ - -/* - * The PCI VendorID and DeviceID for our board. - */ -#define QLA82XX_MSIX_TBL_SPACE 8192 -#define QLA82XX_PCI_REG_MSIX_TBL 0x44 -#define QLA82XX_PCI_MSIX_CONTROL 0x40 - -struct crb_128M_2M_sub_block_map { - unsigned valid; - unsigned start_128M; - unsigned end_128M; - unsigned start_2M; -}; - -struct crb_128M_2M_block_map { - struct crb_128M_2M_sub_block_map sub_block[16]; -}; - -struct crb_addr_pair { - long addr; - long data; -}; - -#define ADDR_ERROR ((unsigned long) 0xffffffff) -#define MAX_CTL_CHECK 1000 -#define QLA82XX_FWERROR_CODE(code) ((code >> 8) & 0x1fffff) - -/*************************************************************************** - * PCI related defines. - **************************************************************************/ - -/* - * Interrupt related defines. - */ -#define PCIX_TARGET_STATUS (0x10118) -#define PCIX_TARGET_STATUS_F1 (0x10160) -#define PCIX_TARGET_STATUS_F2 (0x10164) -#define PCIX_TARGET_STATUS_F3 (0x10168) -#define PCIX_TARGET_STATUS_F4 (0x10360) -#define PCIX_TARGET_STATUS_F5 (0x10364) -#define PCIX_TARGET_STATUS_F6 (0x10368) -#define PCIX_TARGET_STATUS_F7 (0x1036c) - -#define PCIX_TARGET_MASK (0x10128) -#define PCIX_TARGET_MASK_F1 (0x10170) -#define PCIX_TARGET_MASK_F2 (0x10174) -#define PCIX_TARGET_MASK_F3 (0x10178) -#define PCIX_TARGET_MASK_F4 (0x10370) -#define PCIX_TARGET_MASK_F5 (0x10374) -#define PCIX_TARGET_MASK_F6 (0x10378) -#define PCIX_TARGET_MASK_F7 (0x1037c) - -/* - * Message Signaled Interrupts - */ -#define PCIX_MSI_F0 (0x13000) -#define PCIX_MSI_F1 (0x13004) -#define PCIX_MSI_F2 (0x13008) -#define PCIX_MSI_F3 (0x1300c) -#define PCIX_MSI_F4 (0x13010) -#define PCIX_MSI_F5 (0x13014) -#define PCIX_MSI_F6 (0x13018) -#define PCIX_MSI_F7 (0x1301c) -#define PCIX_MSI_F(FUNC) (0x13000 + ((FUNC) * 4)) - -/* - * - */ -#define PCIX_INT_VECTOR (0x10100) -#define PCIX_INT_MASK (0x10104) - -/* - * Interrupt state machine and other bits. - */ -#define PCIE_MISCCFG_RC (0x1206c) - - -#define ISR_INT_TARGET_STATUS \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS)) -#define ISR_INT_TARGET_STATUS_F1 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F1)) -#define ISR_INT_TARGET_STATUS_F2 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F2)) -#define ISR_INT_TARGET_STATUS_F3 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F3)) -#define ISR_INT_TARGET_STATUS_F4 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F4)) -#define ISR_INT_TARGET_STATUS_F5 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F5)) -#define ISR_INT_TARGET_STATUS_F6 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F6)) -#define ISR_INT_TARGET_STATUS_F7 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_STATUS_F7)) - -#define ISR_INT_TARGET_MASK \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK)) -#define ISR_INT_TARGET_MASK_F1 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F1)) -#define ISR_INT_TARGET_MASK_F2 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F2)) -#define ISR_INT_TARGET_MASK_F3 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F3)) -#define ISR_INT_TARGET_MASK_F4 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F4)) -#define ISR_INT_TARGET_MASK_F5 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F5)) -#define ISR_INT_TARGET_MASK_F6 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F6)) -#define ISR_INT_TARGET_MASK_F7 \ - (QLA82XX_PCIX_PS_REG(PCIX_TARGET_MASK_F7)) - -#define ISR_INT_VECTOR (QLA82XX_PCIX_PS_REG(PCIX_INT_VECTOR)) -#define ISR_INT_MASK (QLA82XX_PCIX_PS_REG(PCIX_INT_MASK)) -#define ISR_INT_STATE_REG (QLA82XX_PCIX_PS_REG(PCIE_MISCCFG_RC)) - -#define ISR_MSI_INT_TRIGGER(FUNC) (QLA82XX_PCIX_PS_REG(PCIX_MSI_F(FUNC))) - - -#define ISR_IS_LEGACY_INTR_IDLE(VAL) (((VAL) & 0x300) == 0) -#define ISR_IS_LEGACY_INTR_TRIGGERED(VAL) (((VAL) & 0x300) == 0x200) - -/* - * PCI Interrupt Vector Values. - */ -#define PCIX_INT_VECTOR_BIT_F0 0x0080 -#define PCIX_INT_VECTOR_BIT_F1 0x0100 -#define PCIX_INT_VECTOR_BIT_F2 0x0200 -#define PCIX_INT_VECTOR_BIT_F3 0x0400 -#define PCIX_INT_VECTOR_BIT_F4 0x0800 -#define PCIX_INT_VECTOR_BIT_F5 0x1000 -#define PCIX_INT_VECTOR_BIT_F6 0x2000 -#define PCIX_INT_VECTOR_BIT_F7 0x4000 - -/* struct qla4_8xxx_legacy_intr_set defined in ql4_def.h */ - -#define QLA82XX_LEGACY_INTR_CONFIG \ -{ \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F0, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(0) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F1, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F1, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F1, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(1) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F2, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F2, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F2, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(2) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F3, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F3, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F3, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(3) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F4, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F4, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F4, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(4) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F5, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F5, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F5, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(5) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F6, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F6, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F6, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(6) }, \ - \ - { \ - .int_vec_bit = PCIX_INT_VECTOR_BIT_F7, \ - .tgt_status_reg = ISR_INT_TARGET_STATUS_F7, \ - .tgt_mask_reg = ISR_INT_TARGET_MASK_F7, \ - .pci_int_reg = ISR_MSI_INT_TRIGGER(7) }, \ -} - -/* Magic number to let user know flash is programmed */ -#define QLA82XX_BDINFO_MAGIC 0x12345678 -#define FW_SIZE_OFFSET (0x3e840c) - -/* QLA82XX additions */ -#define MIU_TEST_AGT_WRDATA_UPPER_LO (0x0b0) -#define MIU_TEST_AGT_WRDATA_UPPER_HI (0x0b4) - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_os.c b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_os.c deleted file mode 100644 index ee47820c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_os.c +++ /dev/null @@ -1,6044 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ -#include -#include -#include -#include -#include - -#include -#include - -#include "ql4_def.h" -#include "ql4_version.h" -#include "ql4_glbl.h" -#include "ql4_dbg.h" -#include "ql4_inline.h" - -/* - * Driver version - */ -static char qla4xxx_version_str[40]; - -/* - * SRB allocation cache - */ -static struct kmem_cache *srb_cachep; - -/* - * Module parameter information and variables - */ -static int ql4xdisablesysfsboot = 1; -module_param(ql4xdisablesysfsboot, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ql4xdisablesysfsboot, - " Set to disable exporting boot targets to sysfs.\n" - "\t\t 0 - Export boot targets\n" - "\t\t 1 - Do not export boot targets (Default)"); - -int ql4xdontresethba; -module_param(ql4xdontresethba, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ql4xdontresethba, - " Don't reset the HBA for driver recovery.\n" - "\t\t 0 - It will reset HBA (Default)\n" - "\t\t 1 - It will NOT reset HBA"); - -int ql4xextended_error_logging; -module_param(ql4xextended_error_logging, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ql4xextended_error_logging, - " Option to enable extended error logging.\n" - "\t\t 0 - no logging (Default)\n" - "\t\t 2 - debug logging"); - -int ql4xenablemsix = 1; -module_param(ql4xenablemsix, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(ql4xenablemsix, - " Set to enable MSI or MSI-X interrupt mechanism.\n" - "\t\t 0 = enable INTx interrupt mechanism.\n" - "\t\t 1 = enable MSI-X interrupt mechanism (Default).\n" - "\t\t 2 = enable MSI interrupt mechanism."); - -#define QL4_DEF_QDEPTH 32 -static int ql4xmaxqdepth = QL4_DEF_QDEPTH; -module_param(ql4xmaxqdepth, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ql4xmaxqdepth, - " Maximum queue depth to report for target devices.\n" - "\t\t Default: 32."); - -static int ql4xsess_recovery_tmo = QL4_SESS_RECOVERY_TMO; -module_param(ql4xsess_recovery_tmo, int, S_IRUGO); -MODULE_PARM_DESC(ql4xsess_recovery_tmo, - " Target Session Recovery Timeout.\n" - "\t\t Default: 120 sec."); - -static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha); -/* - * SCSI host template entry points - */ -static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha); - -/* - * iSCSI template entry points - */ -static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess, - enum iscsi_param param, char *buf); -static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, - enum iscsi_param param, char *buf); -static int qla4xxx_host_get_param(struct Scsi_Host *shost, - enum iscsi_host_param param, char *buf); -static int qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, - uint32_t len); -static int qla4xxx_get_iface_param(struct iscsi_iface *iface, - enum iscsi_param_type param_type, - int param, char *buf); -static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc); -static struct iscsi_endpoint *qla4xxx_ep_connect(struct Scsi_Host *shost, - struct sockaddr *dst_addr, - int non_blocking); -static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms); -static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep); -static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, - enum iscsi_param param, char *buf); -static int qla4xxx_conn_start(struct iscsi_cls_conn *conn); -static struct iscsi_cls_conn * -qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx); -static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, - uint64_t transport_fd, int is_leading); -static void qla4xxx_conn_destroy(struct iscsi_cls_conn *conn); -static struct iscsi_cls_session * -qla4xxx_session_create(struct iscsi_endpoint *ep, uint16_t cmds_max, - uint16_t qdepth, uint32_t initial_cmdsn); -static void qla4xxx_session_destroy(struct iscsi_cls_session *sess); -static void qla4xxx_task_work(struct work_struct *wdata); -static int qla4xxx_alloc_pdu(struct iscsi_task *, uint8_t); -static int qla4xxx_task_xmit(struct iscsi_task *); -static void qla4xxx_task_cleanup(struct iscsi_task *); -static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session); -static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats); -static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, - uint32_t iface_type, uint32_t payload_size, - uint32_t pid, struct sockaddr *dst_addr); -static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx, - uint32_t *num_entries, char *buf); -static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx); - -/* - * SCSI host template entry points - */ -static int qla4xxx_queuecommand(struct Scsi_Host *h, struct scsi_cmnd *cmd); -static int qla4xxx_eh_abort(struct scsi_cmnd *cmd); -static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd); -static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd); -static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd); -static int qla4xxx_slave_alloc(struct scsi_device *device); -static int qla4xxx_slave_configure(struct scsi_device *device); -static void qla4xxx_slave_destroy(struct scsi_device *sdev); -static umode_t ql4_attr_is_visible(int param_type, int param); -static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type); - -static struct qla4_8xxx_legacy_intr_set legacy_intr[] = - QLA82XX_LEGACY_INTR_CONFIG; - -static struct scsi_host_template qla4xxx_driver_template = { - .module = THIS_MODULE, - .name = DRIVER_NAME, - .proc_name = DRIVER_NAME, - .queuecommand = qla4xxx_queuecommand, - - .eh_abort_handler = qla4xxx_eh_abort, - .eh_device_reset_handler = qla4xxx_eh_device_reset, - .eh_target_reset_handler = qla4xxx_eh_target_reset, - .eh_host_reset_handler = qla4xxx_eh_host_reset, - .eh_timed_out = qla4xxx_eh_cmd_timed_out, - - .slave_configure = qla4xxx_slave_configure, - .slave_alloc = qla4xxx_slave_alloc, - .slave_destroy = qla4xxx_slave_destroy, - - .this_id = -1, - .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, - .sg_tablesize = SG_ALL, - - .max_sectors = 0xFFFF, - .shost_attrs = qla4xxx_host_attrs, - .host_reset = qla4xxx_host_reset, - .vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC, -}; - -static struct iscsi_transport qla4xxx_iscsi_transport = { - .owner = THIS_MODULE, - .name = DRIVER_NAME, - .caps = CAP_TEXT_NEGO | - CAP_DATA_PATH_OFFLOAD | CAP_HDRDGST | - CAP_DATADGST | CAP_LOGIN_OFFLOAD | - CAP_MULTI_R2T, - .attr_is_visible = ql4_attr_is_visible, - .create_session = qla4xxx_session_create, - .destroy_session = qla4xxx_session_destroy, - .start_conn = qla4xxx_conn_start, - .create_conn = qla4xxx_conn_create, - .bind_conn = qla4xxx_conn_bind, - .stop_conn = iscsi_conn_stop, - .destroy_conn = qla4xxx_conn_destroy, - .set_param = iscsi_set_param, - .get_conn_param = qla4xxx_conn_get_param, - .get_session_param = qla4xxx_session_get_param, - .get_ep_param = qla4xxx_get_ep_param, - .ep_connect = qla4xxx_ep_connect, - .ep_poll = qla4xxx_ep_poll, - .ep_disconnect = qla4xxx_ep_disconnect, - .get_stats = qla4xxx_conn_get_stats, - .send_pdu = iscsi_conn_send_pdu, - .xmit_task = qla4xxx_task_xmit, - .cleanup_task = qla4xxx_task_cleanup, - .alloc_pdu = qla4xxx_alloc_pdu, - - .get_host_param = qla4xxx_host_get_param, - .set_iface_param = qla4xxx_iface_set_param, - .get_iface_param = qla4xxx_get_iface_param, - .bsg_request = qla4xxx_bsg_request, - .send_ping = qla4xxx_send_ping, - .get_chap = qla4xxx_get_chap_list, - .delete_chap = qla4xxx_delete_chap, -}; - -static struct scsi_transport_template *qla4xxx_scsi_transport; - -static int qla4xxx_send_ping(struct Scsi_Host *shost, uint32_t iface_num, - uint32_t iface_type, uint32_t payload_size, - uint32_t pid, struct sockaddr *dst_addr) -{ - struct scsi_qla_host *ha = to_qla_host(shost); - struct sockaddr_in *addr; - struct sockaddr_in6 *addr6; - uint32_t options = 0; - uint8_t ipaddr[IPv6_ADDR_LEN]; - int rval; - - memset(ipaddr, 0, IPv6_ADDR_LEN); - /* IPv4 to IPv4 */ - if ((iface_type == ISCSI_IFACE_TYPE_IPV4) && - (dst_addr->sa_family == AF_INET)) { - addr = (struct sockaddr_in *)dst_addr; - memcpy(ipaddr, &addr->sin_addr.s_addr, IP_ADDR_LEN); - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv4 Ping src: %pI4 " - "dest: %pI4\n", __func__, - &ha->ip_config.ip_address, ipaddr)); - rval = qla4xxx_ping_iocb(ha, options, payload_size, pid, - ipaddr); - if (rval) - rval = -EINVAL; - } else if ((iface_type == ISCSI_IFACE_TYPE_IPV6) && - (dst_addr->sa_family == AF_INET6)) { - /* IPv6 to IPv6 */ - addr6 = (struct sockaddr_in6 *)dst_addr; - memcpy(ipaddr, &addr6->sin6_addr.in6_u.u6_addr8, IPv6_ADDR_LEN); - - options |= PING_IPV6_PROTOCOL_ENABLE; - - /* Ping using LinkLocal address */ - if ((iface_num == 0) || (iface_num == 1)) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: LinkLocal Ping " - "src: %pI6 dest: %pI6\n", __func__, - &ha->ip_config.ipv6_link_local_addr, - ipaddr)); - options |= PING_IPV6_LINKLOCAL_ADDR; - rval = qla4xxx_ping_iocb(ha, options, payload_size, - pid, ipaddr); - } else { - ql4_printk(KERN_WARNING, ha, "%s: iface num = %d " - "not supported\n", __func__, iface_num); - rval = -ENOSYS; - goto exit_send_ping; - } - - /* - * If ping using LinkLocal address fails, try ping using - * IPv6 address - */ - if (rval != QLA_SUCCESS) { - options &= ~PING_IPV6_LINKLOCAL_ADDR; - if (iface_num == 0) { - options |= PING_IPV6_ADDR0; - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " - "Ping src: %pI6 " - "dest: %pI6\n", __func__, - &ha->ip_config.ipv6_addr0, - ipaddr)); - } else if (iface_num == 1) { - options |= PING_IPV6_ADDR1; - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: IPv6 " - "Ping src: %pI6 " - "dest: %pI6\n", __func__, - &ha->ip_config.ipv6_addr1, - ipaddr)); - } - rval = qla4xxx_ping_iocb(ha, options, payload_size, - pid, ipaddr); - if (rval) - rval = -EINVAL; - } - } else - rval = -ENOSYS; -exit_send_ping: - return rval; -} - -static umode_t ql4_attr_is_visible(int param_type, int param) -{ - switch (param_type) { - case ISCSI_HOST_PARAM: - switch (param) { - case ISCSI_HOST_PARAM_HWADDRESS: - case ISCSI_HOST_PARAM_IPADDRESS: - case ISCSI_HOST_PARAM_INITIATOR_NAME: - case ISCSI_HOST_PARAM_PORT_STATE: - case ISCSI_HOST_PARAM_PORT_SPEED: - return S_IRUGO; - default: - return 0; - } - case ISCSI_PARAM: - switch (param) { - case ISCSI_PARAM_PERSISTENT_ADDRESS: - case ISCSI_PARAM_PERSISTENT_PORT: - case ISCSI_PARAM_CONN_ADDRESS: - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_TARGET_NAME: - case ISCSI_PARAM_TPGT: - case ISCSI_PARAM_TARGET_ALIAS: - case ISCSI_PARAM_MAX_BURST: - case ISCSI_PARAM_MAX_R2T: - case ISCSI_PARAM_FIRST_BURST: - case ISCSI_PARAM_MAX_RECV_DLENGTH: - case ISCSI_PARAM_MAX_XMIT_DLENGTH: - case ISCSI_PARAM_IFACE_NAME: - case ISCSI_PARAM_CHAP_OUT_IDX: - case ISCSI_PARAM_CHAP_IN_IDX: - case ISCSI_PARAM_USERNAME: - case ISCSI_PARAM_PASSWORD: - case ISCSI_PARAM_USERNAME_IN: - case ISCSI_PARAM_PASSWORD_IN: - return S_IRUGO; - default: - return 0; - } - case ISCSI_NET_PARAM: - switch (param) { - case ISCSI_NET_PARAM_IPV4_ADDR: - case ISCSI_NET_PARAM_IPV4_SUBNET: - case ISCSI_NET_PARAM_IPV4_GW: - case ISCSI_NET_PARAM_IPV4_BOOTPROTO: - case ISCSI_NET_PARAM_IFACE_ENABLE: - case ISCSI_NET_PARAM_IPV6_LINKLOCAL: - case ISCSI_NET_PARAM_IPV6_ADDR: - case ISCSI_NET_PARAM_IPV6_ROUTER: - case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: - case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: - case ISCSI_NET_PARAM_VLAN_ID: - case ISCSI_NET_PARAM_VLAN_PRIORITY: - case ISCSI_NET_PARAM_VLAN_ENABLED: - case ISCSI_NET_PARAM_MTU: - case ISCSI_NET_PARAM_PORT: - return S_IRUGO; - default: - return 0; - } - } - - return 0; -} - -static int qla4xxx_get_chap_list(struct Scsi_Host *shost, uint16_t chap_tbl_idx, - uint32_t *num_entries, char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(shost); - struct ql4_chap_table *chap_table; - struct iscsi_chap_rec *chap_rec; - int max_chap_entries = 0; - int valid_chap_entries = 0; - int ret = 0, i; - - if (is_qla8022(ha)) - max_chap_entries = (ha->hw.flt_chap_size / 2) / - sizeof(struct ql4_chap_table); - else - max_chap_entries = MAX_CHAP_ENTRIES_40XX; - - ql4_printk(KERN_INFO, ha, "%s: num_entries = %d, CHAP idx = %d\n", - __func__, *num_entries, chap_tbl_idx); - - if (!buf) { - ret = -ENOMEM; - goto exit_get_chap_list; - } - - chap_rec = (struct iscsi_chap_rec *) buf; - mutex_lock(&ha->chap_sem); - for (i = chap_tbl_idx; i < max_chap_entries; i++) { - chap_table = (struct ql4_chap_table *)ha->chap_list + i; - if (chap_table->cookie != - __constant_cpu_to_le16(CHAP_VALID_COOKIE)) - continue; - - chap_rec->chap_tbl_idx = i; - strncpy(chap_rec->username, chap_table->name, - ISCSI_CHAP_AUTH_NAME_MAX_LEN); - strncpy(chap_rec->password, chap_table->secret, - QL4_CHAP_MAX_SECRET_LEN); - chap_rec->password_length = chap_table->secret_len; - - if (chap_table->flags & BIT_7) /* local */ - chap_rec->chap_type = CHAP_TYPE_OUT; - - if (chap_table->flags & BIT_6) /* peer */ - chap_rec->chap_type = CHAP_TYPE_IN; - - chap_rec++; - - valid_chap_entries++; - if (valid_chap_entries == *num_entries) - break; - else - continue; - } - mutex_unlock(&ha->chap_sem); - -exit_get_chap_list: - ql4_printk(KERN_INFO, ha, "%s: Valid CHAP Entries = %d\n", - __func__, valid_chap_entries); - *num_entries = valid_chap_entries; - return ret; -} - -static int __qla4xxx_is_chap_active(struct device *dev, void *data) -{ - int ret = 0; - uint16_t *chap_tbl_idx = (uint16_t *) data; - struct iscsi_cls_session *cls_session; - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - - if (!iscsi_is_session_dev(dev)) - goto exit_is_chap_active; - - cls_session = iscsi_dev_to_session(dev); - sess = cls_session->dd_data; - ddb_entry = sess->dd_data; - - if (iscsi_session_chkready(cls_session)) - goto exit_is_chap_active; - - if (ddb_entry->chap_tbl_idx == *chap_tbl_idx) - ret = 1; - -exit_is_chap_active: - return ret; -} - -static int qla4xxx_is_chap_active(struct Scsi_Host *shost, - uint16_t chap_tbl_idx) -{ - int ret = 0; - - ret = device_for_each_child(&shost->shost_gendev, &chap_tbl_idx, - __qla4xxx_is_chap_active); - - return ret; -} - -static int qla4xxx_delete_chap(struct Scsi_Host *shost, uint16_t chap_tbl_idx) -{ - struct scsi_qla_host *ha = to_qla_host(shost); - struct ql4_chap_table *chap_table; - dma_addr_t chap_dma; - int max_chap_entries = 0; - uint32_t offset = 0; - uint32_t chap_size; - int ret = 0; - - chap_table = dma_pool_alloc(ha->chap_dma_pool, GFP_KERNEL, &chap_dma); - if (chap_table == NULL) - return -ENOMEM; - - memset(chap_table, 0, sizeof(struct ql4_chap_table)); - - if (is_qla8022(ha)) - max_chap_entries = (ha->hw.flt_chap_size / 2) / - sizeof(struct ql4_chap_table); - else - max_chap_entries = MAX_CHAP_ENTRIES_40XX; - - if (chap_tbl_idx > max_chap_entries) { - ret = -EINVAL; - goto exit_delete_chap; - } - - /* Check if chap index is in use. - * If chap is in use don't delet chap entry */ - ret = qla4xxx_is_chap_active(shost, chap_tbl_idx); - if (ret) { - ql4_printk(KERN_INFO, ha, "CHAP entry %d is in use, cannot " - "delete from flash\n", chap_tbl_idx); - ret = -EBUSY; - goto exit_delete_chap; - } - - chap_size = sizeof(struct ql4_chap_table); - if (is_qla40XX(ha)) - offset = FLASH_CHAP_OFFSET | (chap_tbl_idx * chap_size); - else { - offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); - /* flt_chap_size is CHAP table size for both ports - * so divide it by 2 to calculate the offset for second port - */ - if (ha->port_num == 1) - offset += (ha->hw.flt_chap_size / 2); - offset += (chap_tbl_idx * chap_size); - } - - ret = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); - if (ret != QLA_SUCCESS) { - ret = -EINVAL; - goto exit_delete_chap; - } - - DEBUG2(ql4_printk(KERN_INFO, ha, "Chap Cookie: x%x\n", - __le16_to_cpu(chap_table->cookie))); - - if (__le16_to_cpu(chap_table->cookie) != CHAP_VALID_COOKIE) { - ql4_printk(KERN_ERR, ha, "No valid chap entry found\n"); - goto exit_delete_chap; - } - - chap_table->cookie = __constant_cpu_to_le16(0xFFFF); - - offset = FLASH_CHAP_OFFSET | - (chap_tbl_idx * sizeof(struct ql4_chap_table)); - ret = qla4xxx_set_flash(ha, chap_dma, offset, chap_size, - FLASH_OPT_RMW_COMMIT); - if (ret == QLA_SUCCESS && ha->chap_list) { - mutex_lock(&ha->chap_sem); - /* Update ha chap_list cache */ - memcpy((struct ql4_chap_table *)ha->chap_list + chap_tbl_idx, - chap_table, sizeof(struct ql4_chap_table)); - mutex_unlock(&ha->chap_sem); - } - if (ret != QLA_SUCCESS) - ret = -EINVAL; - -exit_delete_chap: - dma_pool_free(ha->chap_dma_pool, chap_table, chap_dma); - return ret; -} - -static int qla4xxx_get_iface_param(struct iscsi_iface *iface, - enum iscsi_param_type param_type, - int param, char *buf) -{ - struct Scsi_Host *shost = iscsi_iface_to_shost(iface); - struct scsi_qla_host *ha = to_qla_host(shost); - int len = -ENOSYS; - - if (param_type != ISCSI_NET_PARAM) - return -ENOSYS; - - switch (param) { - case ISCSI_NET_PARAM_IPV4_ADDR: - len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); - break; - case ISCSI_NET_PARAM_IPV4_SUBNET: - len = sprintf(buf, "%pI4\n", &ha->ip_config.subnet_mask); - break; - case ISCSI_NET_PARAM_IPV4_GW: - len = sprintf(buf, "%pI4\n", &ha->ip_config.gateway); - break; - case ISCSI_NET_PARAM_IFACE_ENABLE: - if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) - len = sprintf(buf, "%s\n", - (ha->ip_config.ipv4_options & - IPOPT_IPV4_PROTOCOL_ENABLE) ? - "enabled" : "disabled"); - else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) - len = sprintf(buf, "%s\n", - (ha->ip_config.ipv6_options & - IPV6_OPT_IPV6_PROTOCOL_ENABLE) ? - "enabled" : "disabled"); - break; - case ISCSI_NET_PARAM_IPV4_BOOTPROTO: - len = sprintf(buf, "%s\n", - (ha->ip_config.tcp_options & TCPOPT_DHCP_ENABLE) ? - "dhcp" : "static"); - break; - case ISCSI_NET_PARAM_IPV6_ADDR: - if (iface->iface_num == 0) - len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr0); - if (iface->iface_num == 1) - len = sprintf(buf, "%pI6\n", &ha->ip_config.ipv6_addr1); - break; - case ISCSI_NET_PARAM_IPV6_LINKLOCAL: - len = sprintf(buf, "%pI6\n", - &ha->ip_config.ipv6_link_local_addr); - break; - case ISCSI_NET_PARAM_IPV6_ROUTER: - len = sprintf(buf, "%pI6\n", - &ha->ip_config.ipv6_default_router_addr); - break; - case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: - len = sprintf(buf, "%s\n", - (ha->ip_config.ipv6_addl_options & - IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE) ? - "nd" : "static"); - break; - case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: - len = sprintf(buf, "%s\n", - (ha->ip_config.ipv6_addl_options & - IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR) ? - "auto" : "static"); - break; - case ISCSI_NET_PARAM_VLAN_ID: - if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) - len = sprintf(buf, "%d\n", - (ha->ip_config.ipv4_vlan_tag & - ISCSI_MAX_VLAN_ID)); - else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) - len = sprintf(buf, "%d\n", - (ha->ip_config.ipv6_vlan_tag & - ISCSI_MAX_VLAN_ID)); - break; - case ISCSI_NET_PARAM_VLAN_PRIORITY: - if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) - len = sprintf(buf, "%d\n", - ((ha->ip_config.ipv4_vlan_tag >> 13) & - ISCSI_MAX_VLAN_PRIORITY)); - else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) - len = sprintf(buf, "%d\n", - ((ha->ip_config.ipv6_vlan_tag >> 13) & - ISCSI_MAX_VLAN_PRIORITY)); - break; - case ISCSI_NET_PARAM_VLAN_ENABLED: - if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) - len = sprintf(buf, "%s\n", - (ha->ip_config.ipv4_options & - IPOPT_VLAN_TAGGING_ENABLE) ? - "enabled" : "disabled"); - else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) - len = sprintf(buf, "%s\n", - (ha->ip_config.ipv6_options & - IPV6_OPT_VLAN_TAGGING_ENABLE) ? - "enabled" : "disabled"); - break; - case ISCSI_NET_PARAM_MTU: - len = sprintf(buf, "%d\n", ha->ip_config.eth_mtu_size); - break; - case ISCSI_NET_PARAM_PORT: - if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) - len = sprintf(buf, "%d\n", ha->ip_config.ipv4_port); - else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) - len = sprintf(buf, "%d\n", ha->ip_config.ipv6_port); - break; - default: - len = -ENOSYS; - } - - return len; -} - -static struct iscsi_endpoint * -qla4xxx_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, - int non_blocking) -{ - int ret; - struct iscsi_endpoint *ep; - struct qla_endpoint *qla_ep; - struct scsi_qla_host *ha; - struct sockaddr_in *addr; - struct sockaddr_in6 *addr6; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - if (!shost) { - ret = -ENXIO; - printk(KERN_ERR "%s: shost is NULL\n", - __func__); - return ERR_PTR(ret); - } - - ha = iscsi_host_priv(shost); - - ep = iscsi_create_endpoint(sizeof(struct qla_endpoint)); - if (!ep) { - ret = -ENOMEM; - return ERR_PTR(ret); - } - - qla_ep = ep->dd_data; - memset(qla_ep, 0, sizeof(struct qla_endpoint)); - if (dst_addr->sa_family == AF_INET) { - memcpy(&qla_ep->dst_addr, dst_addr, sizeof(struct sockaddr_in)); - addr = (struct sockaddr_in *)&qla_ep->dst_addr; - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI4\n", __func__, - (char *)&addr->sin_addr)); - } else if (dst_addr->sa_family == AF_INET6) { - memcpy(&qla_ep->dst_addr, dst_addr, - sizeof(struct sockaddr_in6)); - addr6 = (struct sockaddr_in6 *)&qla_ep->dst_addr; - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: %pI6\n", __func__, - (char *)&addr6->sin6_addr)); - } - - qla_ep->host = shost; - - return ep; -} - -static int qla4xxx_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) -{ - struct qla_endpoint *qla_ep; - struct scsi_qla_host *ha; - int ret = 0; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - qla_ep = ep->dd_data; - ha = to_qla_host(qla_ep->host); - - if (adapter_up(ha) && !test_bit(AF_BUILD_DDB_LIST, &ha->flags)) - ret = 1; - - return ret; -} - -static void qla4xxx_ep_disconnect(struct iscsi_endpoint *ep) -{ - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - iscsi_destroy_endpoint(ep); -} - -static int qla4xxx_get_ep_param(struct iscsi_endpoint *ep, - enum iscsi_param param, - char *buf) -{ - struct qla_endpoint *qla_ep = ep->dd_data; - struct sockaddr *dst_addr; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - - switch (param) { - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_CONN_ADDRESS: - if (!qla_ep) - return -ENOTCONN; - - dst_addr = (struct sockaddr *)&qla_ep->dst_addr; - if (!dst_addr) - return -ENOTCONN; - - return iscsi_conn_get_addr_param((struct sockaddr_storage *) - &qla_ep->dst_addr, param, buf); - default: - return -ENOSYS; - } -} - -static void qla4xxx_conn_get_stats(struct iscsi_cls_conn *cls_conn, - struct iscsi_stats *stats) -{ - struct iscsi_session *sess; - struct iscsi_cls_session *cls_sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - struct ql_iscsi_stats *ql_iscsi_stats; - int stats_size; - int ret; - dma_addr_t iscsi_stats_dma; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - - cls_sess = iscsi_conn_to_session(cls_conn); - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - - stats_size = PAGE_ALIGN(sizeof(struct ql_iscsi_stats)); - /* Allocate memory */ - ql_iscsi_stats = dma_alloc_coherent(&ha->pdev->dev, stats_size, - &iscsi_stats_dma, GFP_KERNEL); - if (!ql_iscsi_stats) { - ql4_printk(KERN_ERR, ha, - "Unable to allocate memory for iscsi stats\n"); - goto exit_get_stats; - } - - ret = qla4xxx_get_mgmt_data(ha, ddb_entry->fw_ddb_index, stats_size, - iscsi_stats_dma); - if (ret != QLA_SUCCESS) { - ql4_printk(KERN_ERR, ha, - "Unable to retreive iscsi stats\n"); - goto free_stats; - } - - /* octets */ - stats->txdata_octets = le64_to_cpu(ql_iscsi_stats->tx_data_octets); - stats->rxdata_octets = le64_to_cpu(ql_iscsi_stats->rx_data_octets); - /* xmit pdus */ - stats->noptx_pdus = le32_to_cpu(ql_iscsi_stats->tx_nopout_pdus); - stats->scsicmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_cmd_pdus); - stats->tmfcmd_pdus = le32_to_cpu(ql_iscsi_stats->tx_tmf_cmd_pdus); - stats->login_pdus = le32_to_cpu(ql_iscsi_stats->tx_login_cmd_pdus); - stats->text_pdus = le32_to_cpu(ql_iscsi_stats->tx_text_cmd_pdus); - stats->dataout_pdus = le32_to_cpu(ql_iscsi_stats->tx_scsi_write_pdus); - stats->logout_pdus = le32_to_cpu(ql_iscsi_stats->tx_logout_cmd_pdus); - stats->snack_pdus = le32_to_cpu(ql_iscsi_stats->tx_snack_req_pdus); - /* recv pdus */ - stats->noprx_pdus = le32_to_cpu(ql_iscsi_stats->rx_nopin_pdus); - stats->scsirsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_resp_pdus); - stats->tmfrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_tmf_resp_pdus); - stats->textrsp_pdus = le32_to_cpu(ql_iscsi_stats->rx_text_resp_pdus); - stats->datain_pdus = le32_to_cpu(ql_iscsi_stats->rx_scsi_read_pdus); - stats->logoutrsp_pdus = - le32_to_cpu(ql_iscsi_stats->rx_logout_resp_pdus); - stats->r2t_pdus = le32_to_cpu(ql_iscsi_stats->rx_r2t_pdus); - stats->async_pdus = le32_to_cpu(ql_iscsi_stats->rx_async_pdus); - stats->rjt_pdus = le32_to_cpu(ql_iscsi_stats->rx_reject_pdus); - -free_stats: - dma_free_coherent(&ha->pdev->dev, stats_size, ql_iscsi_stats, - iscsi_stats_dma); -exit_get_stats: - return; -} - -static enum blk_eh_timer_return qla4xxx_eh_cmd_timed_out(struct scsi_cmnd *sc) -{ - struct iscsi_cls_session *session; - struct iscsi_session *sess; - unsigned long flags; - enum blk_eh_timer_return ret = BLK_EH_NOT_HANDLED; - - session = starget_to_session(scsi_target(sc->device)); - sess = session->dd_data; - - spin_lock_irqsave(&session->lock, flags); - if (session->state == ISCSI_SESSION_FAILED) - ret = BLK_EH_RESET_TIMER; - spin_unlock_irqrestore(&session->lock, flags); - - return ret; -} - -static void qla4xxx_set_port_speed(struct Scsi_Host *shost) -{ - struct scsi_qla_host *ha = to_qla_host(shost); - struct iscsi_cls_host *ihost = shost->shost_data; - uint32_t speed = ISCSI_PORT_SPEED_UNKNOWN; - - qla4xxx_get_firmware_state(ha); - - switch (ha->addl_fw_state & 0x0F00) { - case FW_ADDSTATE_LINK_SPEED_10MBPS: - speed = ISCSI_PORT_SPEED_10MBPS; - break; - case FW_ADDSTATE_LINK_SPEED_100MBPS: - speed = ISCSI_PORT_SPEED_100MBPS; - break; - case FW_ADDSTATE_LINK_SPEED_1GBPS: - speed = ISCSI_PORT_SPEED_1GBPS; - break; - case FW_ADDSTATE_LINK_SPEED_10GBPS: - speed = ISCSI_PORT_SPEED_10GBPS; - break; - } - ihost->port_speed = speed; -} - -static void qla4xxx_set_port_state(struct Scsi_Host *shost) -{ - struct scsi_qla_host *ha = to_qla_host(shost); - struct iscsi_cls_host *ihost = shost->shost_data; - uint32_t state = ISCSI_PORT_STATE_DOWN; - - if (test_bit(AF_LINK_UP, &ha->flags)) - state = ISCSI_PORT_STATE_UP; - - ihost->port_state = state; -} - -static int qla4xxx_host_get_param(struct Scsi_Host *shost, - enum iscsi_host_param param, char *buf) -{ - struct scsi_qla_host *ha = to_qla_host(shost); - int len; - - switch (param) { - case ISCSI_HOST_PARAM_HWADDRESS: - len = sysfs_format_mac(buf, ha->my_mac, MAC_ADDR_LEN); - break; - case ISCSI_HOST_PARAM_IPADDRESS: - len = sprintf(buf, "%pI4\n", &ha->ip_config.ip_address); - break; - case ISCSI_HOST_PARAM_INITIATOR_NAME: - len = sprintf(buf, "%s\n", ha->name_string); - break; - case ISCSI_HOST_PARAM_PORT_STATE: - qla4xxx_set_port_state(shost); - len = sprintf(buf, "%s\n", iscsi_get_port_state_name(shost)); - break; - case ISCSI_HOST_PARAM_PORT_SPEED: - qla4xxx_set_port_speed(shost); - len = sprintf(buf, "%s\n", iscsi_get_port_speed_name(shost)); - break; - default: - return -ENOSYS; - } - - return len; -} - -static void qla4xxx_create_ipv4_iface(struct scsi_qla_host *ha) -{ - if (ha->iface_ipv4) - return; - - /* IPv4 */ - ha->iface_ipv4 = iscsi_create_iface(ha->host, - &qla4xxx_iscsi_transport, - ISCSI_IFACE_TYPE_IPV4, 0, 0); - if (!ha->iface_ipv4) - ql4_printk(KERN_ERR, ha, "Could not create IPv4 iSCSI " - "iface0.\n"); -} - -static void qla4xxx_create_ipv6_iface(struct scsi_qla_host *ha) -{ - if (!ha->iface_ipv6_0) - /* IPv6 iface-0 */ - ha->iface_ipv6_0 = iscsi_create_iface(ha->host, - &qla4xxx_iscsi_transport, - ISCSI_IFACE_TYPE_IPV6, 0, - 0); - if (!ha->iface_ipv6_0) - ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " - "iface0.\n"); - - if (!ha->iface_ipv6_1) - /* IPv6 iface-1 */ - ha->iface_ipv6_1 = iscsi_create_iface(ha->host, - &qla4xxx_iscsi_transport, - ISCSI_IFACE_TYPE_IPV6, 1, - 0); - if (!ha->iface_ipv6_1) - ql4_printk(KERN_ERR, ha, "Could not create IPv6 iSCSI " - "iface1.\n"); -} - -static void qla4xxx_create_ifaces(struct scsi_qla_host *ha) -{ - if (ha->ip_config.ipv4_options & IPOPT_IPV4_PROTOCOL_ENABLE) - qla4xxx_create_ipv4_iface(ha); - - if (ha->ip_config.ipv6_options & IPV6_OPT_IPV6_PROTOCOL_ENABLE) - qla4xxx_create_ipv6_iface(ha); -} - -static void qla4xxx_destroy_ipv4_iface(struct scsi_qla_host *ha) -{ - if (ha->iface_ipv4) { - iscsi_destroy_iface(ha->iface_ipv4); - ha->iface_ipv4 = NULL; - } -} - -static void qla4xxx_destroy_ipv6_iface(struct scsi_qla_host *ha) -{ - if (ha->iface_ipv6_0) { - iscsi_destroy_iface(ha->iface_ipv6_0); - ha->iface_ipv6_0 = NULL; - } - if (ha->iface_ipv6_1) { - iscsi_destroy_iface(ha->iface_ipv6_1); - ha->iface_ipv6_1 = NULL; - } -} - -static void qla4xxx_destroy_ifaces(struct scsi_qla_host *ha) -{ - qla4xxx_destroy_ipv4_iface(ha); - qla4xxx_destroy_ipv6_iface(ha); -} - -static void qla4xxx_set_ipv6(struct scsi_qla_host *ha, - struct iscsi_iface_param_info *iface_param, - struct addr_ctrl_blk *init_fw_cb) -{ - /* - * iface_num 0 is valid for IPv6 Addr, linklocal, router, autocfg. - * iface_num 1 is valid only for IPv6 Addr. - */ - switch (iface_param->param) { - case ISCSI_NET_PARAM_IPV6_ADDR: - if (iface_param->iface_num & 0x1) - /* IPv6 Addr 1 */ - memcpy(init_fw_cb->ipv6_addr1, iface_param->value, - sizeof(init_fw_cb->ipv6_addr1)); - else - /* IPv6 Addr 0 */ - memcpy(init_fw_cb->ipv6_addr0, iface_param->value, - sizeof(init_fw_cb->ipv6_addr0)); - break; - case ISCSI_NET_PARAM_IPV6_LINKLOCAL: - if (iface_param->iface_num & 0x1) - break; - memcpy(init_fw_cb->ipv6_if_id, &iface_param->value[8], - sizeof(init_fw_cb->ipv6_if_id)); - break; - case ISCSI_NET_PARAM_IPV6_ROUTER: - if (iface_param->iface_num & 0x1) - break; - memcpy(init_fw_cb->ipv6_dflt_rtr_addr, iface_param->value, - sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); - break; - case ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG: - /* Autocfg applies to even interface */ - if (iface_param->iface_num & 0x1) - break; - - if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_DISABLE) - init_fw_cb->ipv6_addtl_opts &= - cpu_to_le16( - ~IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); - else if (iface_param->value[0] == ISCSI_IPV6_AUTOCFG_ND_ENABLE) - init_fw_cb->ipv6_addtl_opts |= - cpu_to_le16( - IPV6_ADDOPT_NEIGHBOR_DISCOVERY_ADDR_ENABLE); - else - ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " - "IPv6 addr\n"); - break; - case ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG: - /* Autocfg applies to even interface */ - if (iface_param->iface_num & 0x1) - break; - - if (iface_param->value[0] == - ISCSI_IPV6_LINKLOCAL_AUTOCFG_ENABLE) - init_fw_cb->ipv6_addtl_opts |= cpu_to_le16( - IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); - else if (iface_param->value[0] == - ISCSI_IPV6_LINKLOCAL_AUTOCFG_DISABLE) - init_fw_cb->ipv6_addtl_opts &= cpu_to_le16( - ~IPV6_ADDOPT_AUTOCONFIG_LINK_LOCAL_ADDR); - else - ql4_printk(KERN_ERR, ha, "Invalid autocfg setting for " - "IPv6 linklocal addr\n"); - break; - case ISCSI_NET_PARAM_IPV6_ROUTER_AUTOCFG: - /* Autocfg applies to even interface */ - if (iface_param->iface_num & 0x1) - break; - - if (iface_param->value[0] == ISCSI_IPV6_ROUTER_AUTOCFG_ENABLE) - memset(init_fw_cb->ipv6_dflt_rtr_addr, 0, - sizeof(init_fw_cb->ipv6_dflt_rtr_addr)); - break; - case ISCSI_NET_PARAM_IFACE_ENABLE: - if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { - init_fw_cb->ipv6_opts |= - cpu_to_le16(IPV6_OPT_IPV6_PROTOCOL_ENABLE); - qla4xxx_create_ipv6_iface(ha); - } else { - init_fw_cb->ipv6_opts &= - cpu_to_le16(~IPV6_OPT_IPV6_PROTOCOL_ENABLE & - 0xFFFF); - qla4xxx_destroy_ipv6_iface(ha); - } - break; - case ISCSI_NET_PARAM_VLAN_TAG: - if (iface_param->len != sizeof(init_fw_cb->ipv6_vlan_tag)) - break; - init_fw_cb->ipv6_vlan_tag = - cpu_to_be16(*(uint16_t *)iface_param->value); - break; - case ISCSI_NET_PARAM_VLAN_ENABLED: - if (iface_param->value[0] == ISCSI_VLAN_ENABLE) - init_fw_cb->ipv6_opts |= - cpu_to_le16(IPV6_OPT_VLAN_TAGGING_ENABLE); - else - init_fw_cb->ipv6_opts &= - cpu_to_le16(~IPV6_OPT_VLAN_TAGGING_ENABLE); - break; - case ISCSI_NET_PARAM_MTU: - init_fw_cb->eth_mtu_size = - cpu_to_le16(*(uint16_t *)iface_param->value); - break; - case ISCSI_NET_PARAM_PORT: - /* Autocfg applies to even interface */ - if (iface_param->iface_num & 0x1) - break; - - init_fw_cb->ipv6_port = - cpu_to_le16(*(uint16_t *)iface_param->value); - break; - default: - ql4_printk(KERN_ERR, ha, "Unknown IPv6 param = %d\n", - iface_param->param); - break; - } -} - -static void qla4xxx_set_ipv4(struct scsi_qla_host *ha, - struct iscsi_iface_param_info *iface_param, - struct addr_ctrl_blk *init_fw_cb) -{ - switch (iface_param->param) { - case ISCSI_NET_PARAM_IPV4_ADDR: - memcpy(init_fw_cb->ipv4_addr, iface_param->value, - sizeof(init_fw_cb->ipv4_addr)); - break; - case ISCSI_NET_PARAM_IPV4_SUBNET: - memcpy(init_fw_cb->ipv4_subnet, iface_param->value, - sizeof(init_fw_cb->ipv4_subnet)); - break; - case ISCSI_NET_PARAM_IPV4_GW: - memcpy(init_fw_cb->ipv4_gw_addr, iface_param->value, - sizeof(init_fw_cb->ipv4_gw_addr)); - break; - case ISCSI_NET_PARAM_IPV4_BOOTPROTO: - if (iface_param->value[0] == ISCSI_BOOTPROTO_DHCP) - init_fw_cb->ipv4_tcp_opts |= - cpu_to_le16(TCPOPT_DHCP_ENABLE); - else if (iface_param->value[0] == ISCSI_BOOTPROTO_STATIC) - init_fw_cb->ipv4_tcp_opts &= - cpu_to_le16(~TCPOPT_DHCP_ENABLE); - else - ql4_printk(KERN_ERR, ha, "Invalid IPv4 bootproto\n"); - break; - case ISCSI_NET_PARAM_IFACE_ENABLE: - if (iface_param->value[0] == ISCSI_IFACE_ENABLE) { - init_fw_cb->ipv4_ip_opts |= - cpu_to_le16(IPOPT_IPV4_PROTOCOL_ENABLE); - qla4xxx_create_ipv4_iface(ha); - } else { - init_fw_cb->ipv4_ip_opts &= - cpu_to_le16(~IPOPT_IPV4_PROTOCOL_ENABLE & - 0xFFFF); - qla4xxx_destroy_ipv4_iface(ha); - } - break; - case ISCSI_NET_PARAM_VLAN_TAG: - if (iface_param->len != sizeof(init_fw_cb->ipv4_vlan_tag)) - break; - init_fw_cb->ipv4_vlan_tag = - cpu_to_be16(*(uint16_t *)iface_param->value); - break; - case ISCSI_NET_PARAM_VLAN_ENABLED: - if (iface_param->value[0] == ISCSI_VLAN_ENABLE) - init_fw_cb->ipv4_ip_opts |= - cpu_to_le16(IPOPT_VLAN_TAGGING_ENABLE); - else - init_fw_cb->ipv4_ip_opts &= - cpu_to_le16(~IPOPT_VLAN_TAGGING_ENABLE); - break; - case ISCSI_NET_PARAM_MTU: - init_fw_cb->eth_mtu_size = - cpu_to_le16(*(uint16_t *)iface_param->value); - break; - case ISCSI_NET_PARAM_PORT: - init_fw_cb->ipv4_port = - cpu_to_le16(*(uint16_t *)iface_param->value); - break; - default: - ql4_printk(KERN_ERR, ha, "Unknown IPv4 param = %d\n", - iface_param->param); - break; - } -} - -static void -qla4xxx_initcb_to_acb(struct addr_ctrl_blk *init_fw_cb) -{ - struct addr_ctrl_blk_def *acb; - acb = (struct addr_ctrl_blk_def *)init_fw_cb; - memset(acb->reserved1, 0, sizeof(acb->reserved1)); - memset(acb->reserved2, 0, sizeof(acb->reserved2)); - memset(acb->reserved3, 0, sizeof(acb->reserved3)); - memset(acb->reserved4, 0, sizeof(acb->reserved4)); - memset(acb->reserved5, 0, sizeof(acb->reserved5)); - memset(acb->reserved6, 0, sizeof(acb->reserved6)); - memset(acb->reserved7, 0, sizeof(acb->reserved7)); - memset(acb->reserved8, 0, sizeof(acb->reserved8)); - memset(acb->reserved9, 0, sizeof(acb->reserved9)); - memset(acb->reserved10, 0, sizeof(acb->reserved10)); - memset(acb->reserved11, 0, sizeof(acb->reserved11)); - memset(acb->reserved12, 0, sizeof(acb->reserved12)); - memset(acb->reserved13, 0, sizeof(acb->reserved13)); - memset(acb->reserved14, 0, sizeof(acb->reserved14)); - memset(acb->reserved15, 0, sizeof(acb->reserved15)); -} - -static int -qla4xxx_iface_set_param(struct Scsi_Host *shost, void *data, uint32_t len) -{ - struct scsi_qla_host *ha = to_qla_host(shost); - int rval = 0; - struct iscsi_iface_param_info *iface_param = NULL; - struct addr_ctrl_blk *init_fw_cb = NULL; - dma_addr_t init_fw_cb_dma; - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - uint32_t rem = len; - struct nlattr *attr; - - init_fw_cb = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - &init_fw_cb_dma, GFP_KERNEL); - if (!init_fw_cb) { - ql4_printk(KERN_ERR, ha, "%s: Unable to alloc init_cb\n", - __func__); - return -ENOMEM; - } - - memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); - memset(&mbox_cmd, 0, sizeof(mbox_cmd)); - memset(&mbox_sts, 0, sizeof(mbox_sts)); - - if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma)) { - ql4_printk(KERN_ERR, ha, "%s: get ifcb failed\n", __func__); - rval = -EIO; - goto exit_init_fw_cb; - } - - nla_for_each_attr(attr, data, len, rem) { - iface_param = nla_data(attr); - - if (iface_param->param_type != ISCSI_NET_PARAM) - continue; - - switch (iface_param->iface_type) { - case ISCSI_IFACE_TYPE_IPV4: - switch (iface_param->iface_num) { - case 0: - qla4xxx_set_ipv4(ha, iface_param, init_fw_cb); - break; - default: - /* Cannot have more than one IPv4 interface */ - ql4_printk(KERN_ERR, ha, "Invalid IPv4 iface " - "number = %d\n", - iface_param->iface_num); - break; - } - break; - case ISCSI_IFACE_TYPE_IPV6: - switch (iface_param->iface_num) { - case 0: - case 1: - qla4xxx_set_ipv6(ha, iface_param, init_fw_cb); - break; - default: - /* Cannot have more than two IPv6 interface */ - ql4_printk(KERN_ERR, ha, "Invalid IPv6 iface " - "number = %d\n", - iface_param->iface_num); - break; - } - break; - default: - ql4_printk(KERN_ERR, ha, "Invalid iface type\n"); - break; - } - } - - init_fw_cb->cookie = cpu_to_le32(0x11BEAD5A); - - rval = qla4xxx_set_flash(ha, init_fw_cb_dma, FLASH_SEGMENT_IFCB, - sizeof(struct addr_ctrl_blk), - FLASH_OPT_RMW_COMMIT); - if (rval != QLA_SUCCESS) { - ql4_printk(KERN_ERR, ha, "%s: set flash mbx failed\n", - __func__); - rval = -EIO; - goto exit_init_fw_cb; - } - - rval = qla4xxx_disable_acb(ha); - if (rval != QLA_SUCCESS) { - ql4_printk(KERN_ERR, ha, "%s: disable acb mbx failed\n", - __func__); - rval = -EIO; - goto exit_init_fw_cb; - } - - wait_for_completion_timeout(&ha->disable_acb_comp, - DISABLE_ACB_TOV * HZ); - - qla4xxx_initcb_to_acb(init_fw_cb); - - rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma); - if (rval != QLA_SUCCESS) { - ql4_printk(KERN_ERR, ha, "%s: set acb mbx failed\n", - __func__); - rval = -EIO; - goto exit_init_fw_cb; - } - - memset(init_fw_cb, 0, sizeof(struct addr_ctrl_blk)); - qla4xxx_update_local_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb, - init_fw_cb_dma); - -exit_init_fw_cb: - dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk), - init_fw_cb, init_fw_cb_dma); - - return rval; -} - -static int qla4xxx_session_get_param(struct iscsi_cls_session *cls_sess, - enum iscsi_param param, char *buf) -{ - struct iscsi_session *sess = cls_sess->dd_data; - struct ddb_entry *ddb_entry = sess->dd_data; - struct scsi_qla_host *ha = ddb_entry->ha; - int rval, len; - uint16_t idx; - - switch (param) { - case ISCSI_PARAM_CHAP_IN_IDX: - rval = qla4xxx_get_chap_index(ha, sess->username_in, - sess->password_in, BIDI_CHAP, - &idx); - if (rval) - return -EINVAL; - - len = sprintf(buf, "%hu\n", idx); - break; - case ISCSI_PARAM_CHAP_OUT_IDX: - rval = qla4xxx_get_chap_index(ha, sess->username, - sess->password, LOCAL_CHAP, - &idx); - if (rval) - return -EINVAL; - - len = sprintf(buf, "%hu\n", idx); - break; - default: - return iscsi_session_get_param(cls_sess, param, buf); - } - - return len; -} - -static int qla4xxx_conn_get_param(struct iscsi_cls_conn *cls_conn, - enum iscsi_param param, char *buf) -{ - struct iscsi_conn *conn; - struct qla_conn *qla_conn; - struct sockaddr *dst_addr; - int len = 0; - - conn = cls_conn->dd_data; - qla_conn = conn->dd_data; - dst_addr = &qla_conn->qla_ep->dst_addr; - - switch (param) { - case ISCSI_PARAM_CONN_PORT: - case ISCSI_PARAM_CONN_ADDRESS: - return iscsi_conn_get_addr_param((struct sockaddr_storage *) - dst_addr, param, buf); - default: - return iscsi_conn_get_param(cls_conn, param, buf); - } - - return len; - -} - -int qla4xxx_get_ddb_index(struct scsi_qla_host *ha, uint16_t *ddb_index) -{ - uint32_t mbx_sts = 0; - uint16_t tmp_ddb_index; - int ret; - -get_ddb_index: - tmp_ddb_index = find_first_zero_bit(ha->ddb_idx_map, MAX_DDB_ENTRIES); - - if (tmp_ddb_index >= MAX_DDB_ENTRIES) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "Free DDB index not available\n")); - ret = QLA_ERROR; - goto exit_get_ddb_index; - } - - if (test_and_set_bit(tmp_ddb_index, ha->ddb_idx_map)) - goto get_ddb_index; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Found a free DDB index at %d\n", tmp_ddb_index)); - ret = qla4xxx_req_ddb_entry(ha, tmp_ddb_index, &mbx_sts); - if (ret == QLA_ERROR) { - if (mbx_sts == MBOX_STS_COMMAND_ERROR) { - ql4_printk(KERN_INFO, ha, - "DDB index = %d not available trying next\n", - tmp_ddb_index); - goto get_ddb_index; - } - DEBUG2(ql4_printk(KERN_INFO, ha, - "Free FW DDB not available\n")); - } - - *ddb_index = tmp_ddb_index; - -exit_get_ddb_index: - return ret; -} - -static int qla4xxx_match_ipaddress(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, - char *existing_ipaddr, - char *user_ipaddr) -{ - uint8_t dst_ipaddr[IPv6_ADDR_LEN]; - char formatted_ipaddr[DDB_IPADDR_LEN]; - int status = QLA_SUCCESS, ret = 0; - - if (ddb_entry->fw_ddb_entry.options & DDB_OPT_IPV6_DEVICE) { - ret = in6_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, - '\0', NULL); - if (ret == 0) { - status = QLA_ERROR; - goto out_match; - } - ret = sprintf(formatted_ipaddr, "%pI6", dst_ipaddr); - } else { - ret = in4_pton(user_ipaddr, strlen(user_ipaddr), dst_ipaddr, - '\0', NULL); - if (ret == 0) { - status = QLA_ERROR; - goto out_match; - } - ret = sprintf(formatted_ipaddr, "%pI4", dst_ipaddr); - } - - if (strcmp(existing_ipaddr, formatted_ipaddr)) - status = QLA_ERROR; - -out_match: - return status; -} - -static int qla4xxx_match_fwdb_session(struct scsi_qla_host *ha, - struct iscsi_cls_conn *cls_conn) -{ - int idx = 0, max_ddbs, rval; - struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); - struct iscsi_session *sess, *existing_sess; - struct iscsi_conn *conn, *existing_conn; - struct ddb_entry *ddb_entry; - - sess = cls_sess->dd_data; - conn = cls_conn->dd_data; - - if (sess->targetname == NULL || - conn->persistent_address == NULL || - conn->persistent_port == 0) - return QLA_ERROR; - - max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : - MAX_DEV_DB_ENTRIES; - - for (idx = 0; idx < max_ddbs; idx++) { - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); - if (ddb_entry == NULL) - continue; - - if (ddb_entry->ddb_type != FLASH_DDB) - continue; - - existing_sess = ddb_entry->sess->dd_data; - existing_conn = ddb_entry->conn->dd_data; - - if (existing_sess->targetname == NULL || - existing_conn->persistent_address == NULL || - existing_conn->persistent_port == 0) - continue; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "IQN = %s User IQN = %s\n", - existing_sess->targetname, - sess->targetname)); - - DEBUG2(ql4_printk(KERN_INFO, ha, - "IP = %s User IP = %s\n", - existing_conn->persistent_address, - conn->persistent_address)); - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Port = %d User Port = %d\n", - existing_conn->persistent_port, - conn->persistent_port)); - - if (strcmp(existing_sess->targetname, sess->targetname)) - continue; - rval = qla4xxx_match_ipaddress(ha, ddb_entry, - existing_conn->persistent_address, - conn->persistent_address); - if (rval == QLA_ERROR) - continue; - if (existing_conn->persistent_port != conn->persistent_port) - continue; - break; - } - - if (idx == max_ddbs) - return QLA_ERROR; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Match found in fwdb sessions\n")); - return QLA_SUCCESS; -} - -static struct iscsi_cls_session * -qla4xxx_session_create(struct iscsi_endpoint *ep, - uint16_t cmds_max, uint16_t qdepth, - uint32_t initial_cmdsn) -{ - struct iscsi_cls_session *cls_sess; - struct scsi_qla_host *ha; - struct qla_endpoint *qla_ep; - struct ddb_entry *ddb_entry; - uint16_t ddb_index; - struct iscsi_session *sess; - struct sockaddr *dst_addr; - int ret; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - if (!ep) { - printk(KERN_ERR "qla4xxx: missing ep.\n"); - return NULL; - } - - qla_ep = ep->dd_data; - dst_addr = (struct sockaddr *)&qla_ep->dst_addr; - ha = to_qla_host(qla_ep->host); - - ret = qla4xxx_get_ddb_index(ha, &ddb_index); - if (ret == QLA_ERROR) - return NULL; - - cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, qla_ep->host, - cmds_max, sizeof(struct ddb_entry), - sizeof(struct ql4_task_data), - initial_cmdsn, ddb_index); - if (!cls_sess) - return NULL; - - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ddb_entry->fw_ddb_index = ddb_index; - ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; - ddb_entry->ha = ha; - ddb_entry->sess = cls_sess; - ddb_entry->unblock_sess = qla4xxx_unblock_ddb; - ddb_entry->ddb_change = qla4xxx_ddb_change; - cls_sess->recovery_tmo = ql4xsess_recovery_tmo; - ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] = ddb_entry; - ha->tot_ddbs++; - - return cls_sess; -} - -static void qla4xxx_session_destroy(struct iscsi_cls_session *cls_sess) -{ - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - unsigned long flags; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - - qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); - - spin_lock_irqsave(&ha->hardware_lock, flags); - qla4xxx_free_ddb(ha, ddb_entry); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - iscsi_session_teardown(cls_sess); -} - -static struct iscsi_cls_conn * -qla4xxx_conn_create(struct iscsi_cls_session *cls_sess, uint32_t conn_idx) -{ - struct iscsi_cls_conn *cls_conn; - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), - conn_idx); - if (!cls_conn) - return NULL; - - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ddb_entry->conn = cls_conn; - - return cls_conn; -} - -static int qla4xxx_conn_bind(struct iscsi_cls_session *cls_session, - struct iscsi_cls_conn *cls_conn, - uint64_t transport_fd, int is_leading) -{ - struct iscsi_conn *conn; - struct qla_conn *qla_conn; - struct iscsi_endpoint *ep; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - - if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) - return -EINVAL; - ep = iscsi_lookup_endpoint(transport_fd); - conn = cls_conn->dd_data; - qla_conn = conn->dd_data; - qla_conn->qla_ep = ep->dd_data; - return 0; -} - -static int qla4xxx_conn_start(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - struct dev_db_entry *fw_ddb_entry = NULL; - dma_addr_t fw_ddb_entry_dma; - uint32_t mbx_sts = 0; - int ret = 0; - int status = QLA_SUCCESS; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - - /* Check if we have matching FW DDB, if yes then do not - * login to this target. This could cause target to logout previous - * connection - */ - ret = qla4xxx_match_fwdb_session(ha, cls_conn); - if (ret == QLA_SUCCESS) { - ql4_printk(KERN_INFO, ha, - "Session already exist in FW.\n"); - ret = -EEXIST; - goto exit_conn_start; - } - - fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - &fw_ddb_entry_dma, GFP_KERNEL); - if (!fw_ddb_entry) { - ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer\n", __func__); - ret = -ENOMEM; - goto exit_conn_start; - } - - ret = qla4xxx_set_param_ddbentry(ha, ddb_entry, cls_conn, &mbx_sts); - if (ret) { - /* If iscsid is stopped and started then no need to do - * set param again since ddb state will be already - * active and FW does not allow set ddb to an - * active session. - */ - if (mbx_sts) - if (ddb_entry->fw_ddb_device_state == - DDB_DS_SESSION_ACTIVE) { - ddb_entry->unblock_sess(ddb_entry->sess); - goto exit_set_param; - } - - ql4_printk(KERN_ERR, ha, "%s: Failed set param for index[%d]\n", - __func__, ddb_entry->fw_ddb_index); - goto exit_conn_start; - } - - status = qla4xxx_conn_open(ha, ddb_entry->fw_ddb_index); - if (status == QLA_ERROR) { - ql4_printk(KERN_ERR, ha, "%s: Login failed: %s\n", __func__, - sess->targetname); - ret = -EINVAL; - goto exit_conn_start; - } - - if (ddb_entry->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) - ddb_entry->fw_ddb_device_state = DDB_DS_LOGIN_IN_PROCESS; - - DEBUG2(printk(KERN_INFO "%s: DDB state [%d]\n", __func__, - ddb_entry->fw_ddb_device_state)); - -exit_set_param: - ret = 0; - -exit_conn_start: - if (fw_ddb_entry) - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); - return ret; -} - -static void qla4xxx_conn_destroy(struct iscsi_cls_conn *cls_conn) -{ - struct iscsi_cls_session *cls_sess = iscsi_conn_to_session(cls_conn); - struct iscsi_session *sess; - struct scsi_qla_host *ha; - struct ddb_entry *ddb_entry; - int options; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - - options = LOGOUT_OPTION_CLOSE_SESSION; - if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) == QLA_ERROR) - ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", __func__); -} - -static void qla4xxx_task_work(struct work_struct *wdata) -{ - struct ql4_task_data *task_data; - struct scsi_qla_host *ha; - struct passthru_status *sts; - struct iscsi_task *task; - struct iscsi_hdr *hdr; - uint8_t *data; - uint32_t data_len; - struct iscsi_conn *conn; - int hdr_len; - itt_t itt; - - task_data = container_of(wdata, struct ql4_task_data, task_work); - ha = task_data->ha; - task = task_data->task; - sts = &task_data->sts; - hdr_len = sizeof(struct iscsi_hdr); - - DEBUG3(printk(KERN_INFO "Status returned\n")); - DEBUG3(qla4xxx_dump_buffer(sts, 64)); - DEBUG3(printk(KERN_INFO "Response buffer")); - DEBUG3(qla4xxx_dump_buffer(task_data->resp_buffer, 64)); - - conn = task->conn; - - switch (sts->completionStatus) { - case PASSTHRU_STATUS_COMPLETE: - hdr = (struct iscsi_hdr *)task_data->resp_buffer; - /* Assign back the itt in hdr, until we use the PREASSIGN_TAG */ - itt = sts->handle; - hdr->itt = itt; - data = task_data->resp_buffer + hdr_len; - data_len = task_data->resp_len - hdr_len; - iscsi_complete_pdu(conn, hdr, data, data_len); - break; - default: - ql4_printk(KERN_ERR, ha, "Passthru failed status = 0x%x\n", - sts->completionStatus); - break; - } - return; -} - -static int qla4xxx_alloc_pdu(struct iscsi_task *task, uint8_t opcode) -{ - struct ql4_task_data *task_data; - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - int hdr_len; - - sess = task->conn->session; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - task_data = task->dd_data; - memset(task_data, 0, sizeof(struct ql4_task_data)); - - if (task->sc) { - ql4_printk(KERN_INFO, ha, - "%s: SCSI Commands not implemented\n", __func__); - return -EINVAL; - } - - hdr_len = sizeof(struct iscsi_hdr); - task_data->ha = ha; - task_data->task = task; - - if (task->data_count) { - task_data->data_dma = dma_map_single(&ha->pdev->dev, task->data, - task->data_count, - PCI_DMA_TODEVICE); - } - - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", - __func__, task->conn->max_recv_dlength, hdr_len)); - - task_data->resp_len = task->conn->max_recv_dlength + hdr_len; - task_data->resp_buffer = dma_alloc_coherent(&ha->pdev->dev, - task_data->resp_len, - &task_data->resp_dma, - GFP_ATOMIC); - if (!task_data->resp_buffer) - goto exit_alloc_pdu; - - task_data->req_len = task->data_count + hdr_len; - task_data->req_buffer = dma_alloc_coherent(&ha->pdev->dev, - task_data->req_len, - &task_data->req_dma, - GFP_ATOMIC); - if (!task_data->req_buffer) - goto exit_alloc_pdu; - - task->hdr = task_data->req_buffer; - - INIT_WORK(&task_data->task_work, qla4xxx_task_work); - - return 0; - -exit_alloc_pdu: - if (task_data->resp_buffer) - dma_free_coherent(&ha->pdev->dev, task_data->resp_len, - task_data->resp_buffer, task_data->resp_dma); - - if (task_data->req_buffer) - dma_free_coherent(&ha->pdev->dev, task_data->req_len, - task_data->req_buffer, task_data->req_dma); - return -ENOMEM; -} - -static void qla4xxx_task_cleanup(struct iscsi_task *task) -{ - struct ql4_task_data *task_data; - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - int hdr_len; - - hdr_len = sizeof(struct iscsi_hdr); - sess = task->conn->session; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - task_data = task->dd_data; - - if (task->data_count) { - dma_unmap_single(&ha->pdev->dev, task_data->data_dma, - task->data_count, PCI_DMA_TODEVICE); - } - - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: MaxRecvLen %u, iscsi hrd %d\n", - __func__, task->conn->max_recv_dlength, hdr_len)); - - dma_free_coherent(&ha->pdev->dev, task_data->resp_len, - task_data->resp_buffer, task_data->resp_dma); - dma_free_coherent(&ha->pdev->dev, task_data->req_len, - task_data->req_buffer, task_data->req_dma); - return; -} - -static int qla4xxx_task_xmit(struct iscsi_task *task) -{ - struct scsi_cmnd *sc = task->sc; - struct iscsi_session *sess = task->conn->session; - struct ddb_entry *ddb_entry = sess->dd_data; - struct scsi_qla_host *ha = ddb_entry->ha; - - if (!sc) - return qla4xxx_send_passthru0(task); - - ql4_printk(KERN_INFO, ha, "%s: scsi cmd xmit not implemented\n", - __func__); - return -ENOSYS; -} - -static void qla4xxx_copy_fwddb_param(struct scsi_qla_host *ha, - struct dev_db_entry *fw_ddb_entry, - struct iscsi_cls_session *cls_sess, - struct iscsi_cls_conn *cls_conn) -{ - int buflen = 0; - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct iscsi_conn *conn; - char ip_addr[DDB_IPADDR_LEN]; - uint16_t options = 0; - - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - conn = cls_conn->dd_data; - - ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx); - - conn->max_recv_dlength = BYTE_UNITS * - le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); - - conn->max_xmit_dlength = BYTE_UNITS * - le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); - - sess->initial_r2t_en = - (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); - - sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); - - sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); - - sess->first_burst = BYTE_UNITS * - le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); - - sess->max_burst = BYTE_UNITS * - le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); - - sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); - - sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); - - conn->persistent_port = le16_to_cpu(fw_ddb_entry->port); - - sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); - - options = le16_to_cpu(fw_ddb_entry->options); - if (options & DDB_OPT_IPV6_DEVICE) - sprintf(ip_addr, "%pI6", fw_ddb_entry->ip_addr); - else - sprintf(ip_addr, "%pI4", fw_ddb_entry->ip_addr); - - iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_NAME, - (char *)fw_ddb_entry->iscsi_name, buflen); - iscsi_set_param(cls_conn, ISCSI_PARAM_INITIATOR_NAME, - (char *)ha->name_string, buflen); - iscsi_set_param(cls_conn, ISCSI_PARAM_PERSISTENT_ADDRESS, - (char *)ip_addr, buflen); - iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS, - (char *)fw_ddb_entry->iscsi_alias, buflen); -} - -void qla4xxx_update_session_conn_fwddb_param(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry) -{ - struct iscsi_cls_session *cls_sess; - struct iscsi_cls_conn *cls_conn; - uint32_t ddb_state; - dma_addr_t fw_ddb_entry_dma; - struct dev_db_entry *fw_ddb_entry; - - fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - &fw_ddb_entry_dma, GFP_KERNEL); - if (!fw_ddb_entry) { - ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer\n", __func__); - goto exit_session_conn_fwddb_param; - } - - if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, - fw_ddb_entry_dma, NULL, NULL, &ddb_state, - NULL, NULL, NULL) == QLA_ERROR) { - DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " - "get_ddb_entry for fw_ddb_index %d\n", - ha->host_no, __func__, - ddb_entry->fw_ddb_index)); - goto exit_session_conn_fwddb_param; - } - - cls_sess = ddb_entry->sess; - - cls_conn = ddb_entry->conn; - - /* Update params */ - qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); - -exit_session_conn_fwddb_param: - if (fw_ddb_entry) - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); -} - -void qla4xxx_update_session_conn_param(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry) -{ - struct iscsi_cls_session *cls_sess; - struct iscsi_cls_conn *cls_conn; - struct iscsi_session *sess; - struct iscsi_conn *conn; - uint32_t ddb_state; - dma_addr_t fw_ddb_entry_dma; - struct dev_db_entry *fw_ddb_entry; - - fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - &fw_ddb_entry_dma, GFP_KERNEL); - if (!fw_ddb_entry) { - ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer\n", __func__); - goto exit_session_conn_param; - } - - if (qla4xxx_get_fwddb_entry(ha, ddb_entry->fw_ddb_index, fw_ddb_entry, - fw_ddb_entry_dma, NULL, NULL, &ddb_state, - NULL, NULL, NULL) == QLA_ERROR) { - DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: failed " - "get_ddb_entry for fw_ddb_index %d\n", - ha->host_no, __func__, - ddb_entry->fw_ddb_index)); - goto exit_session_conn_param; - } - - cls_sess = ddb_entry->sess; - sess = cls_sess->dd_data; - - cls_conn = ddb_entry->conn; - conn = cls_conn->dd_data; - - /* Update timers after login */ - ddb_entry->default_relogin_timeout = - (le16_to_cpu(fw_ddb_entry->def_timeout) > LOGIN_TOV) && - (le16_to_cpu(fw_ddb_entry->def_timeout) < LOGIN_TOV * 10) ? - le16_to_cpu(fw_ddb_entry->def_timeout) : LOGIN_TOV; - ddb_entry->default_time2wait = - le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); - - /* Update params */ - ddb_entry->chap_tbl_idx = le16_to_cpu(fw_ddb_entry->chap_tbl_idx); - conn->max_recv_dlength = BYTE_UNITS * - le16_to_cpu(fw_ddb_entry->iscsi_max_rcv_data_seg_len); - - conn->max_xmit_dlength = BYTE_UNITS * - le16_to_cpu(fw_ddb_entry->iscsi_max_snd_data_seg_len); - - sess->initial_r2t_en = - (BIT_10 & le16_to_cpu(fw_ddb_entry->iscsi_options)); - - sess->max_r2t = le16_to_cpu(fw_ddb_entry->iscsi_max_outsnd_r2t); - - sess->imm_data_en = (BIT_11 & le16_to_cpu(fw_ddb_entry->iscsi_options)); - - sess->first_burst = BYTE_UNITS * - le16_to_cpu(fw_ddb_entry->iscsi_first_burst_len); - - sess->max_burst = BYTE_UNITS * - le16_to_cpu(fw_ddb_entry->iscsi_max_burst_len); - - sess->time2wait = le16_to_cpu(fw_ddb_entry->iscsi_def_time2wait); - - sess->time2retain = le16_to_cpu(fw_ddb_entry->iscsi_def_time2retain); - - sess->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); - - memcpy(sess->initiatorname, ha->name_string, - min(sizeof(ha->name_string), sizeof(sess->initiatorname))); - - iscsi_set_param(cls_conn, ISCSI_PARAM_TARGET_ALIAS, - (char *)fw_ddb_entry->iscsi_alias, 0); - -exit_session_conn_param: - if (fw_ddb_entry) - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); -} - -/* - * Timer routines - */ - -static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, - unsigned long interval) -{ - DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", - __func__, ha->host->host_no)); - init_timer(&ha->timer); - ha->timer.expires = jiffies + interval * HZ; - ha->timer.data = (unsigned long)ha; - ha->timer.function = (void (*)(unsigned long))func; - add_timer(&ha->timer); - ha->timer_active = 1; -} - -static void qla4xxx_stop_timer(struct scsi_qla_host *ha) -{ - del_timer_sync(&ha->timer); - ha->timer_active = 0; -} - -/*** - * qla4xxx_mark_device_missing - blocks the session - * @cls_session: Pointer to the session to be blocked - * @ddb_entry: Pointer to device database entry - * - * This routine marks a device missing and close connection. - **/ -void qla4xxx_mark_device_missing(struct iscsi_cls_session *cls_session) -{ - iscsi_block_session(cls_session); -} - -/** - * qla4xxx_mark_all_devices_missing - mark all devices as missing. - * @ha: Pointer to host adapter structure. - * - * This routine marks a device missing and resets the relogin retry count. - **/ -void qla4xxx_mark_all_devices_missing(struct scsi_qla_host *ha) -{ - iscsi_host_for_each_session(ha->host, qla4xxx_mark_device_missing); -} - -static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry, - struct scsi_cmnd *cmd) -{ - struct srb *srb; - - srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); - if (!srb) - return srb; - - kref_init(&srb->srb_ref); - srb->ha = ha; - srb->ddb = ddb_entry; - srb->cmd = cmd; - srb->flags = 0; - CMD_SP(cmd) = (void *)srb; - - return srb; -} - -static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb) -{ - struct scsi_cmnd *cmd = srb->cmd; - - if (srb->flags & SRB_DMA_VALID) { - scsi_dma_unmap(cmd); - srb->flags &= ~SRB_DMA_VALID; - } - CMD_SP(cmd) = NULL; -} - -void qla4xxx_srb_compl(struct kref *ref) -{ - struct srb *srb = container_of(ref, struct srb, srb_ref); - struct scsi_cmnd *cmd = srb->cmd; - struct scsi_qla_host *ha = srb->ha; - - qla4xxx_srb_free_dma(ha, srb); - - mempool_free(srb, ha->srb_mempool); - - cmd->scsi_done(cmd); -} - -/** - * qla4xxx_queuecommand - scsi layer issues scsi command to driver. - * @host: scsi host - * @cmd: Pointer to Linux's SCSI command structure - * - * Remarks: - * This routine is invoked by Linux to send a SCSI command to the driver. - * The mid-level driver tries to ensure that queuecommand never gets - * invoked concurrently with itself or the interrupt handler (although - * the interrupt handler may call this routine as part of request- - * completion handling). Unfortunely, it sometimes calls the scheduler - * in interrupt context which is a big NO! NO!. - **/ -static int qla4xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) -{ - struct scsi_qla_host *ha = to_qla_host(host); - struct ddb_entry *ddb_entry = cmd->device->hostdata; - struct iscsi_cls_session *sess = ddb_entry->sess; - struct srb *srb; - int rval; - - if (test_bit(AF_EEH_BUSY, &ha->flags)) { - if (test_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags)) - cmd->result = DID_NO_CONNECT << 16; - else - cmd->result = DID_REQUEUE << 16; - goto qc_fail_command; - } - - if (!sess) { - cmd->result = DID_IMM_RETRY << 16; - goto qc_fail_command; - } - - rval = iscsi_session_chkready(sess); - if (rval) { - cmd->result = rval; - goto qc_fail_command; - } - - if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || - test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || - test_bit(DPC_RESET_HA, &ha->dpc_flags) || - test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || - test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || - !test_bit(AF_ONLINE, &ha->flags) || - !test_bit(AF_LINK_UP, &ha->flags) || - test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) - goto qc_host_busy; - - srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd); - if (!srb) - goto qc_host_busy; - - rval = qla4xxx_send_command_to_isp(ha, srb); - if (rval != QLA_SUCCESS) - goto qc_host_busy_free_sp; - - return 0; - -qc_host_busy_free_sp: - qla4xxx_srb_free_dma(ha, srb); - mempool_free(srb, ha->srb_mempool); - -qc_host_busy: - return SCSI_MLQUEUE_HOST_BUSY; - -qc_fail_command: - cmd->scsi_done(cmd); - - return 0; -} - -/** - * qla4xxx_mem_free - frees memory allocated to adapter - * @ha: Pointer to host adapter structure. - * - * Frees memory previously allocated by qla4xxx_mem_alloc - **/ -static void qla4xxx_mem_free(struct scsi_qla_host *ha) -{ - if (ha->queues) - dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues, - ha->queues_dma); - - ha->queues_len = 0; - ha->queues = NULL; - ha->queues_dma = 0; - ha->request_ring = NULL; - ha->request_dma = 0; - ha->response_ring = NULL; - ha->response_dma = 0; - ha->shadow_regs = NULL; - ha->shadow_regs_dma = 0; - - /* Free srb pool. */ - if (ha->srb_mempool) - mempool_destroy(ha->srb_mempool); - - ha->srb_mempool = NULL; - - if (ha->chap_dma_pool) - dma_pool_destroy(ha->chap_dma_pool); - - if (ha->chap_list) - vfree(ha->chap_list); - ha->chap_list = NULL; - - if (ha->fw_ddb_dma_pool) - dma_pool_destroy(ha->fw_ddb_dma_pool); - - /* release io space registers */ - if (is_qla8022(ha)) { - if (ha->nx_pcibase) - iounmap( - (struct device_reg_82xx __iomem *)ha->nx_pcibase); - } else if (ha->reg) - iounmap(ha->reg); - pci_release_regions(ha->pdev); -} - -/** - * qla4xxx_mem_alloc - allocates memory for use by adapter. - * @ha: Pointer to host adapter structure - * - * Allocates DMA memory for request and response queues. Also allocates memory - * for srbs. - **/ -static int qla4xxx_mem_alloc(struct scsi_qla_host *ha) -{ - unsigned long align; - - /* Allocate contiguous block of DMA memory for queues. */ - ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + - (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) + - sizeof(struct shadow_regs) + - MEM_ALIGN_VALUE + - (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); - ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len, - &ha->queues_dma, GFP_KERNEL); - if (ha->queues == NULL) { - ql4_printk(KERN_WARNING, ha, - "Memory Allocation failed - queues.\n"); - - goto mem_alloc_error_exit; - } - memset(ha->queues, 0, ha->queues_len); - - /* - * As per RISC alignment requirements -- the bus-address must be a - * multiple of the request-ring size (in bytes). - */ - align = 0; - if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1)) - align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma & - (MEM_ALIGN_VALUE - 1)); - - /* Update request and response queue pointers. */ - ha->request_dma = ha->queues_dma + align; - ha->request_ring = (struct queue_entry *) (ha->queues + align); - ha->response_dma = ha->queues_dma + align + - (REQUEST_QUEUE_DEPTH * QUEUE_SIZE); - ha->response_ring = (struct queue_entry *) (ha->queues + align + - (REQUEST_QUEUE_DEPTH * - QUEUE_SIZE)); - ha->shadow_regs_dma = ha->queues_dma + align + - (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) + - (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE); - ha->shadow_regs = (struct shadow_regs *) (ha->queues + align + - (REQUEST_QUEUE_DEPTH * - QUEUE_SIZE) + - (RESPONSE_QUEUE_DEPTH * - QUEUE_SIZE)); - - /* Allocate memory for srb pool. */ - ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab, - mempool_free_slab, srb_cachep); - if (ha->srb_mempool == NULL) { - ql4_printk(KERN_WARNING, ha, - "Memory Allocation failed - SRB Pool.\n"); - - goto mem_alloc_error_exit; - } - - ha->chap_dma_pool = dma_pool_create("ql4_chap", &ha->pdev->dev, - CHAP_DMA_BLOCK_SIZE, 8, 0); - - if (ha->chap_dma_pool == NULL) { - ql4_printk(KERN_WARNING, ha, - "%s: chap_dma_pool allocation failed..\n", __func__); - goto mem_alloc_error_exit; - } - - ha->fw_ddb_dma_pool = dma_pool_create("ql4_fw_ddb", &ha->pdev->dev, - DDB_DMA_BLOCK_SIZE, 8, 0); - - if (ha->fw_ddb_dma_pool == NULL) { - ql4_printk(KERN_WARNING, ha, - "%s: fw_ddb_dma_pool allocation failed..\n", - __func__); - goto mem_alloc_error_exit; - } - - return QLA_SUCCESS; - -mem_alloc_error_exit: - qla4xxx_mem_free(ha); - return QLA_ERROR; -} - -/** - * qla4_8xxx_check_temp - Check the ISP82XX temperature. - * @ha: adapter block pointer. - * - * Note: The caller should not hold the idc lock. - **/ -static int qla4_8xxx_check_temp(struct scsi_qla_host *ha) -{ - uint32_t temp, temp_state, temp_val; - int status = QLA_SUCCESS; - - temp = qla4_8xxx_rd_32(ha, CRB_TEMP_STATE); - - temp_state = qla82xx_get_temp_state(temp); - temp_val = qla82xx_get_temp_val(temp); - - if (temp_state == QLA82XX_TEMP_PANIC) { - ql4_printk(KERN_WARNING, ha, "Device temperature %d degrees C" - " exceeds maximum allowed. Hardware has been shut" - " down.\n", temp_val); - status = QLA_ERROR; - } else if (temp_state == QLA82XX_TEMP_WARN) { - if (ha->temperature == QLA82XX_TEMP_NORMAL) - ql4_printk(KERN_WARNING, ha, "Device temperature %d" - " degrees C exceeds operating range." - " Immediate action needed.\n", temp_val); - } else { - if (ha->temperature == QLA82XX_TEMP_WARN) - ql4_printk(KERN_INFO, ha, "Device temperature is" - " now %d degrees C in normal range.\n", - temp_val); - } - ha->temperature = temp_state; - return status; -} - -/** - * qla4_8xxx_check_fw_alive - Check firmware health - * @ha: Pointer to host adapter structure. - * - * Context: Interrupt - **/ -static int qla4_8xxx_check_fw_alive(struct scsi_qla_host *ha) -{ - uint32_t fw_heartbeat_counter; - int status = QLA_SUCCESS; - - fw_heartbeat_counter = qla4_8xxx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER); - /* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */ - if (fw_heartbeat_counter == 0xffffffff) { - DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Device in frozen " - "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n", - ha->host_no, __func__)); - return status; - } - - if (ha->fw_heartbeat_counter == fw_heartbeat_counter) { - ha->seconds_since_last_heartbeat++; - /* FW not alive after 2 seconds */ - if (ha->seconds_since_last_heartbeat == 2) { - ha->seconds_since_last_heartbeat = 0; - - ql4_printk(KERN_INFO, ha, - "scsi(%ld): %s, Dumping hw/fw registers:\n " - " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2:" - " 0x%x,\n PEG_NET_0_PC: 0x%x, PEG_NET_1_PC:" - " 0x%x,\n PEG_NET_2_PC: 0x%x, PEG_NET_3_PC:" - " 0x%x,\n PEG_NET_4_PC: 0x%x\n", - ha->host_no, __func__, - qla4_8xxx_rd_32(ha, - QLA82XX_PEG_HALT_STATUS1), - qla4_8xxx_rd_32(ha, - QLA82XX_PEG_HALT_STATUS2), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_0 + - 0x3c), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_1 + - 0x3c), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_2 + - 0x3c), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_3 + - 0x3c), - qla4_8xxx_rd_32(ha, QLA82XX_CRB_PEG_NET_4 + - 0x3c)); - status = QLA_ERROR; - } - } else - ha->seconds_since_last_heartbeat = 0; - - ha->fw_heartbeat_counter = fw_heartbeat_counter; - return status; -} - -/** - * qla4_8xxx_watchdog - Poll dev state - * @ha: Pointer to host adapter structure. - * - * Context: Interrupt - **/ -void qla4_8xxx_watchdog(struct scsi_qla_host *ha) -{ - uint32_t dev_state, halt_status; - - /* don't poll if reset is going on */ - if (!(test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) || - test_bit(DPC_RESET_HA, &ha->dpc_flags) || - test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags))) { - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - - if (qla4_8xxx_check_temp(ha)) { - ql4_printk(KERN_INFO, ha, "disabling pause" - " transmit on port 0 & 1.\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, - CRB_NIU_XG_PAUSE_CTL_P0 | - CRB_NIU_XG_PAUSE_CTL_P1); - set_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags); - qla4xxx_wake_dpc(ha); - } else if (dev_state == QLA82XX_DEV_NEED_RESET && - !test_bit(DPC_RESET_HA, &ha->dpc_flags)) { - if (!ql4xdontresethba) { - ql4_printk(KERN_INFO, ha, "%s: HW State: " - "NEED RESET!\n", __func__); - set_bit(DPC_RESET_HA, &ha->dpc_flags); - qla4xxx_wake_dpc(ha); - } - } else if (dev_state == QLA82XX_DEV_NEED_QUIESCENT && - !test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { - ql4_printk(KERN_INFO, ha, "%s: HW State: NEED QUIES!\n", - __func__); - set_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags); - qla4xxx_wake_dpc(ha); - } else { - /* Check firmware health */ - if (qla4_8xxx_check_fw_alive(ha)) { - ql4_printk(KERN_INFO, ha, "disabling pause" - " transmit on port 0 & 1.\n"); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_NIU + 0x98, - CRB_NIU_XG_PAUSE_CTL_P0 | - CRB_NIU_XG_PAUSE_CTL_P1); - halt_status = qla4_8xxx_rd_32(ha, - QLA82XX_PEG_HALT_STATUS1); - - if (QLA82XX_FWERROR_CODE(halt_status) == 0x67) - ql4_printk(KERN_ERR, ha, "%s:" - " Firmware aborted with" - " error code 0x00006700." - " Device is being reset\n", - __func__); - - /* Since we cannot change dev_state in interrupt - * context, set appropriate DPC flag then wakeup - * DPC */ - if (halt_status & HALT_STATUS_UNRECOVERABLE) - set_bit(DPC_HA_UNRECOVERABLE, - &ha->dpc_flags); - else { - ql4_printk(KERN_INFO, ha, "%s: detect " - "abort needed!\n", __func__); - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } - qla4xxx_mailbox_premature_completion(ha); - qla4xxx_wake_dpc(ha); - } - } - } -} - -static void qla4xxx_check_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) -{ - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - - if (!(ddb_entry->ddb_type == FLASH_DDB)) - return; - - if (adapter_up(ha) && !test_bit(DF_RELOGIN, &ddb_entry->flags) && - !iscsi_is_session_online(cls_sess)) { - if (atomic_read(&ddb_entry->retry_relogin_timer) != - INVALID_ENTRY) { - if (atomic_read(&ddb_entry->retry_relogin_timer) == - 0) { - atomic_set(&ddb_entry->retry_relogin_timer, - INVALID_ENTRY); - set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); - set_bit(DF_RELOGIN, &ddb_entry->flags); - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: index [%d] login device\n", - __func__, ddb_entry->fw_ddb_index)); - } else - atomic_dec(&ddb_entry->retry_relogin_timer); - } - } - - /* Wait for relogin to timeout */ - if (atomic_read(&ddb_entry->relogin_timer) && - (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) { - /* - * If the relogin times out and the device is - * still NOT ONLINE then try and relogin again. - */ - if (!iscsi_is_session_online(cls_sess)) { - /* Reset retry relogin timer */ - atomic_inc(&ddb_entry->relogin_retry_count); - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: index[%d] relogin timed out-retrying" - " relogin (%d), retry (%d)\n", __func__, - ddb_entry->fw_ddb_index, - atomic_read(&ddb_entry->relogin_retry_count), - ddb_entry->default_time2wait + 4)); - set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); - atomic_set(&ddb_entry->retry_relogin_timer, - ddb_entry->default_time2wait + 4); - } - } -} - -/** - * qla4xxx_timer - checks every second for work to do. - * @ha: Pointer to host adapter structure. - **/ -static void qla4xxx_timer(struct scsi_qla_host *ha) -{ - int start_dpc = 0; - uint16_t w; - - iscsi_host_for_each_session(ha->host, qla4xxx_check_relogin_flash_ddb); - - /* If we are in the middle of AER/EEH processing - * skip any processing and reschedule the timer - */ - if (test_bit(AF_EEH_BUSY, &ha->flags)) { - mod_timer(&ha->timer, jiffies + HZ); - return; - } - - /* Hardware read to trigger an EEH error during mailbox waits. */ - if (!pci_channel_offline(ha->pdev)) - pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); - - if (is_qla8022(ha)) { - qla4_8xxx_watchdog(ha); - } - - if (!is_qla8022(ha)) { - /* Check for heartbeat interval. */ - if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE && - ha->heartbeat_interval != 0) { - ha->seconds_since_last_heartbeat++; - if (ha->seconds_since_last_heartbeat > - ha->heartbeat_interval + 2) - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } - } - - /* Process any deferred work. */ - if (!list_empty(&ha->work_list)) - start_dpc++; - - /* Wakeup the dpc routine for this adapter, if needed. */ - if (start_dpc || - test_bit(DPC_RESET_HA, &ha->dpc_flags) || - test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) || - test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) || - test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || - test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || - test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) || - test_bit(DPC_LINK_CHANGED, &ha->dpc_flags) || - test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags) || - test_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags) || - test_bit(DPC_AEN, &ha->dpc_flags)) { - DEBUG2(printk("scsi%ld: %s: scheduling dpc routine" - " - dpc flags = 0x%lx\n", - ha->host_no, __func__, ha->dpc_flags)); - qla4xxx_wake_dpc(ha); - } - - /* Reschedule timer thread to call us back in one second */ - mod_timer(&ha->timer, jiffies + HZ); - - DEBUG2(ha->seconds_since_last_intr++); -} - -/** - * qla4xxx_cmd_wait - waits for all outstanding commands to complete - * @ha: Pointer to host adapter structure. - * - * This routine stalls the driver until all outstanding commands are returned. - * Caller must release the Hardware Lock prior to calling this routine. - **/ -static int qla4xxx_cmd_wait(struct scsi_qla_host *ha) -{ - uint32_t index = 0; - unsigned long flags; - struct scsi_cmnd *cmd; - - unsigned long wtime = jiffies + (WAIT_CMD_TOV * HZ); - - DEBUG2(ql4_printk(KERN_INFO, ha, "Wait up to %d seconds for cmds to " - "complete\n", WAIT_CMD_TOV)); - - while (!time_after_eq(jiffies, wtime)) { - spin_lock_irqsave(&ha->hardware_lock, flags); - /* Find a command that hasn't completed. */ - for (index = 0; index < ha->host->can_queue; index++) { - cmd = scsi_host_find_tag(ha->host, index); - /* - * We cannot just check if the index is valid, - * becase if we are run from the scsi eh, then - * the scsi/block layer is going to prevent - * the tag from being released. - */ - if (cmd != NULL && CMD_SP(cmd)) - break; - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* If No Commands are pending, wait is complete */ - if (index == ha->host->can_queue) - return QLA_SUCCESS; - - msleep(1000); - } - /* If we timed out on waiting for commands to come back - * return ERROR. */ - return QLA_ERROR; -} - -int qla4xxx_hw_reset(struct scsi_qla_host *ha) -{ - uint32_t ctrl_status; - unsigned long flags = 0; - - DEBUG2(printk(KERN_ERR "scsi%ld: %s\n", ha->host_no, __func__)); - - if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS) - return QLA_ERROR; - - spin_lock_irqsave(&ha->hardware_lock, flags); - - /* - * If the SCSI Reset Interrupt bit is set, clear it. - * Otherwise, the Soft Reset won't work. - */ - ctrl_status = readw(&ha->reg->ctrl_status); - if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) - writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); - - /* Issue Soft Reset */ - writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return QLA_SUCCESS; -} - -/** - * qla4xxx_soft_reset - performs soft reset. - * @ha: Pointer to host adapter structure. - **/ -int qla4xxx_soft_reset(struct scsi_qla_host *ha) -{ - uint32_t max_wait_time; - unsigned long flags = 0; - int status; - uint32_t ctrl_status; - - status = qla4xxx_hw_reset(ha); - if (status != QLA_SUCCESS) - return status; - - status = QLA_ERROR; - /* Wait until the Network Reset Intr bit is cleared */ - max_wait_time = RESET_INTR_TOV; - do { - spin_lock_irqsave(&ha->hardware_lock, flags); - ctrl_status = readw(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if ((ctrl_status & CSR_NET_RESET_INTR) == 0) - break; - - msleep(1000); - } while ((--max_wait_time)); - - if ((ctrl_status & CSR_NET_RESET_INTR) != 0) { - DEBUG2(printk(KERN_WARNING - "scsi%ld: Network Reset Intr not cleared by " - "Network function, clearing it now!\n", - ha->host_no)); - spin_lock_irqsave(&ha->hardware_lock, flags); - writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - - /* Wait until the firmware tells us the Soft Reset is done */ - max_wait_time = SOFT_RESET_TOV; - do { - spin_lock_irqsave(&ha->hardware_lock, flags); - ctrl_status = readw(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if ((ctrl_status & CSR_SOFT_RESET) == 0) { - status = QLA_SUCCESS; - break; - } - - msleep(1000); - } while ((--max_wait_time)); - - /* - * Also, make sure that the SCSI Reset Interrupt bit has been cleared - * after the soft reset has taken place. - */ - spin_lock_irqsave(&ha->hardware_lock, flags); - ctrl_status = readw(&ha->reg->ctrl_status); - if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) { - writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - /* If soft reset fails then most probably the bios on other - * function is also enabled. - * Since the initialization is sequential the other fn - * wont be able to acknowledge the soft reset. - * Issue a force soft reset to workaround this scenario. - */ - if (max_wait_time == 0) { - /* Issue Force Soft Reset */ - spin_lock_irqsave(&ha->hardware_lock, flags); - writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status); - readl(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - /* Wait until the firmware tells us the Soft Reset is done */ - max_wait_time = SOFT_RESET_TOV; - do { - spin_lock_irqsave(&ha->hardware_lock, flags); - ctrl_status = readw(&ha->reg->ctrl_status); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) { - status = QLA_SUCCESS; - break; - } - - msleep(1000); - } while ((--max_wait_time)); - } - - return status; -} - -/** - * qla4xxx_abort_active_cmds - returns all outstanding i/o requests to O.S. - * @ha: Pointer to host adapter structure. - * @res: returned scsi status - * - * This routine is called just prior to a HARD RESET to return all - * outstanding commands back to the Operating System. - * Caller should make sure that the following locks are released - * before this calling routine: Hardware lock, and io_request_lock. - **/ -static void qla4xxx_abort_active_cmds(struct scsi_qla_host *ha, int res) -{ - struct srb *srb; - int i; - unsigned long flags; - - spin_lock_irqsave(&ha->hardware_lock, flags); - for (i = 0; i < ha->host->can_queue; i++) { - srb = qla4xxx_del_from_active_array(ha, i); - if (srb != NULL) { - srb->cmd->result = res; - kref_put(&srb->srb_ref, qla4xxx_srb_compl); - } - } - spin_unlock_irqrestore(&ha->hardware_lock, flags); -} - -void qla4xxx_dead_adapter_cleanup(struct scsi_qla_host *ha) -{ - clear_bit(AF_ONLINE, &ha->flags); - - /* Disable the board */ - ql4_printk(KERN_INFO, ha, "Disabling the board\n"); - - qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); - qla4xxx_mark_all_devices_missing(ha); - clear_bit(AF_INIT_DONE, &ha->flags); -} - -static void qla4xxx_fail_session(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - - sess = cls_session->dd_data; - ddb_entry = sess->dd_data; - ddb_entry->fw_ddb_device_state = DDB_DS_SESSION_FAILED; - - if (ddb_entry->ddb_type == FLASH_DDB) - iscsi_block_session(ddb_entry->sess); - else - iscsi_session_failure(cls_session->dd_data, - ISCSI_ERR_CONN_FAILED); -} - -/** - * qla4xxx_recover_adapter - recovers adapter after a fatal error - * @ha: Pointer to host adapter structure. - **/ -static int qla4xxx_recover_adapter(struct scsi_qla_host *ha) -{ - int status = QLA_ERROR; - uint8_t reset_chip = 0; - uint32_t dev_state; - unsigned long wait; - - /* Stall incoming I/O until we are done */ - scsi_block_requests(ha->host); - clear_bit(AF_ONLINE, &ha->flags); - clear_bit(AF_LINK_UP, &ha->flags); - - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: adapter OFFLINE\n", __func__)); - - set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); - - iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); - - if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) - reset_chip = 1; - - /* For the DPC_RESET_HA_INTR case (ISP-4xxx specific) - * do not reset adapter, jump to initialize_adapter */ - if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { - status = QLA_SUCCESS; - goto recover_ha_init_adapter; - } - - /* For the ISP-82xx adapter, issue a stop_firmware if invoked - * from eh_host_reset or ioctl module */ - if (is_qla8022(ha) && !reset_chip && - test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags)) { - - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: %s - Performing stop_firmware...\n", - ha->host_no, __func__)); - status = ha->isp_ops->reset_firmware(ha); - if (status == QLA_SUCCESS) { - if (!test_bit(AF_FW_RECOVERY, &ha->flags)) - qla4xxx_cmd_wait(ha); - ha->isp_ops->disable_intrs(ha); - qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - qla4xxx_abort_active_cmds(ha, DID_RESET << 16); - } else { - /* If the stop_firmware fails then - * reset the entire chip */ - reset_chip = 1; - clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } - } - - /* Issue full chip reset if recovering from a catastrophic error, - * or if stop_firmware fails for ISP-82xx. - * This is the default case for ISP-4xxx */ - if (!is_qla8022(ha) || reset_chip) { - if (!is_qla8022(ha)) - goto chip_reset; - - /* Check if 82XX firmware is alive or not - * We may have arrived here from NEED_RESET - * detection only */ - if (test_bit(AF_FW_RECOVERY, &ha->flags)) - goto chip_reset; - - wait = jiffies + (FW_ALIVE_WAIT_TOV * HZ); - while (time_before(jiffies, wait)) { - if (qla4_8xxx_check_fw_alive(ha)) { - qla4xxx_mailbox_premature_completion(ha); - break; - } - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ); - } - - if (!test_bit(AF_FW_RECOVERY, &ha->flags)) - qla4xxx_cmd_wait(ha); -chip_reset: - qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - qla4xxx_abort_active_cmds(ha, DID_RESET << 16); - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: %s - Performing chip reset..\n", - ha->host_no, __func__)); - status = ha->isp_ops->reset_chip(ha); - } - - /* Flush any pending ddb changed AENs */ - qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - -recover_ha_init_adapter: - /* Upon successful firmware/chip reset, re-initialize the adapter */ - if (status == QLA_SUCCESS) { - /* For ISP-4xxx, force function 1 to always initialize - * before function 3 to prevent both funcions from - * stepping on top of the other */ - if (!is_qla8022(ha) && (ha->mac_index == 3)) - ssleep(6); - - /* NOTE: AF_ONLINE flag set upon successful completion of - * qla4xxx_initialize_adapter */ - status = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); - } - - /* Retry failed adapter initialization, if necessary - * Do not retry initialize_adapter for RESET_HA_INTR (ISP-4xxx specific) - * case to prevent ping-pong resets between functions */ - if (!test_bit(AF_ONLINE, &ha->flags) && - !test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { - /* Adapter initialization failed, see if we can retry - * resetting the ha. - * Since we don't want to block the DPC for too long - * with multiple resets in the same thread, - * utilize DPC to retry */ - if (is_qla8022(ha)) { - qla4_8xxx_idc_lock(ha); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla4_8xxx_idc_unlock(ha); - if (dev_state == QLA82XX_DEV_FAILED) { - ql4_printk(KERN_INFO, ha, "%s: don't retry " - "recover adapter. H/W is in Failed " - "state\n", __func__); - qla4xxx_dead_adapter_cleanup(ha); - clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); - clear_bit(DPC_RESET_HA, &ha->dpc_flags); - clear_bit(DPC_RESET_HA_FW_CONTEXT, - &ha->dpc_flags); - status = QLA_ERROR; - - goto exit_recover; - } - } - - if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) { - ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES; - DEBUG2(printk("scsi%ld: recover adapter - retrying " - "(%d) more times\n", ha->host_no, - ha->retry_reset_ha_cnt)); - set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); - status = QLA_ERROR; - } else { - if (ha->retry_reset_ha_cnt > 0) { - /* Schedule another Reset HA--DPC will retry */ - ha->retry_reset_ha_cnt--; - DEBUG2(printk("scsi%ld: recover adapter - " - "retry remaining %d\n", - ha->host_no, - ha->retry_reset_ha_cnt)); - status = QLA_ERROR; - } - - if (ha->retry_reset_ha_cnt == 0) { - /* Recover adapter retries have been exhausted. - * Adapter DEAD */ - DEBUG2(printk("scsi%ld: recover adapter " - "failed - board disabled\n", - ha->host_no)); - qla4xxx_dead_adapter_cleanup(ha); - clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); - clear_bit(DPC_RESET_HA, &ha->dpc_flags); - clear_bit(DPC_RESET_HA_FW_CONTEXT, - &ha->dpc_flags); - status = QLA_ERROR; - } - } - } else { - clear_bit(DPC_RESET_HA, &ha->dpc_flags); - clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); - clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags); - } - -exit_recover: - ha->adapter_error_count++; - - if (test_bit(AF_ONLINE, &ha->flags)) - ha->isp_ops->enable_intrs(ha); - - scsi_unblock_requests(ha->host); - - clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); - DEBUG2(printk("scsi%ld: recover adapter: %s\n", ha->host_no, - status == QLA_ERROR ? "FAILED" : "SUCCEEDED")); - - return status; -} - -static void qla4xxx_relogin_devices(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - - sess = cls_session->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - if (!iscsi_is_session_online(cls_session)) { - if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) { - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" - " unblock session\n", ha->host_no, __func__, - ddb_entry->fw_ddb_index); - iscsi_unblock_session(ddb_entry->sess); - } else { - /* Trigger relogin */ - if (ddb_entry->ddb_type == FLASH_DDB) { - if (!test_bit(DF_RELOGIN, &ddb_entry->flags)) - qla4xxx_arm_relogin_timer(ddb_entry); - } else - iscsi_session_failure(cls_session->dd_data, - ISCSI_ERR_CONN_FAILED); - } - } -} - -int qla4xxx_unblock_flash_ddb(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - - sess = cls_session->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" - " unblock session\n", ha->host_no, __func__, - ddb_entry->fw_ddb_index); - - iscsi_unblock_session(ddb_entry->sess); - - /* Start scan target */ - if (test_bit(AF_ONLINE, &ha->flags)) { - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" - " start scan\n", ha->host_no, __func__, - ddb_entry->fw_ddb_index); - scsi_queue_work(ha->host, &ddb_entry->sess->scan_work); - } - return QLA_SUCCESS; -} - -int qla4xxx_unblock_ddb(struct iscsi_cls_session *cls_session) -{ - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - - sess = cls_session->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: ddb[%d]" - " unblock user space session\n", ha->host_no, __func__, - ddb_entry->fw_ddb_index); - iscsi_conn_start(ddb_entry->conn); - iscsi_conn_login_event(ddb_entry->conn, - ISCSI_CONN_STATE_LOGGED_IN); - - return QLA_SUCCESS; -} - -static void qla4xxx_relogin_all_devices(struct scsi_qla_host *ha) -{ - iscsi_host_for_each_session(ha->host, qla4xxx_relogin_devices); -} - -static void qla4xxx_relogin_flash_ddb(struct iscsi_cls_session *cls_sess) -{ - uint16_t relogin_timer; - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - - relogin_timer = max(ddb_entry->default_relogin_timeout, - (uint16_t)RELOGIN_TOV); - atomic_set(&ddb_entry->relogin_timer, relogin_timer); - - DEBUG2(ql4_printk(KERN_INFO, ha, - "scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no, - ddb_entry->fw_ddb_index, relogin_timer)); - - qla4xxx_login_flash_ddb(cls_sess); -} - -static void qla4xxx_dpc_relogin(struct iscsi_cls_session *cls_sess) -{ - struct iscsi_session *sess; - struct ddb_entry *ddb_entry; - struct scsi_qla_host *ha; - - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ha = ddb_entry->ha; - - if (!(ddb_entry->ddb_type == FLASH_DDB)) - return; - - if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) && - !iscsi_is_session_online(cls_sess)) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "relogin issued\n")); - qla4xxx_relogin_flash_ddb(cls_sess); - } -} - -void qla4xxx_wake_dpc(struct scsi_qla_host *ha) -{ - if (ha->dpc_thread) - queue_work(ha->dpc_thread, &ha->dpc_work); -} - -static struct qla4_work_evt * -qla4xxx_alloc_work(struct scsi_qla_host *ha, uint32_t data_size, - enum qla4_work_type type) -{ - struct qla4_work_evt *e; - uint32_t size = sizeof(struct qla4_work_evt) + data_size; - - e = kzalloc(size, GFP_ATOMIC); - if (!e) - return NULL; - - INIT_LIST_HEAD(&e->list); - e->type = type; - return e; -} - -static void qla4xxx_post_work(struct scsi_qla_host *ha, - struct qla4_work_evt *e) -{ - unsigned long flags; - - spin_lock_irqsave(&ha->work_lock, flags); - list_add_tail(&e->list, &ha->work_list); - spin_unlock_irqrestore(&ha->work_lock, flags); - qla4xxx_wake_dpc(ha); -} - -int qla4xxx_post_aen_work(struct scsi_qla_host *ha, - enum iscsi_host_event_code aen_code, - uint32_t data_size, uint8_t *data) -{ - struct qla4_work_evt *e; - - e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_AEN); - if (!e) - return QLA_ERROR; - - e->u.aen.code = aen_code; - e->u.aen.data_size = data_size; - memcpy(e->u.aen.data, data, data_size); - - qla4xxx_post_work(ha, e); - - return QLA_SUCCESS; -} - -int qla4xxx_post_ping_evt_work(struct scsi_qla_host *ha, - uint32_t status, uint32_t pid, - uint32_t data_size, uint8_t *data) -{ - struct qla4_work_evt *e; - - e = qla4xxx_alloc_work(ha, data_size, QLA4_EVENT_PING_STATUS); - if (!e) - return QLA_ERROR; - - e->u.ping.status = status; - e->u.ping.pid = pid; - e->u.ping.data_size = data_size; - memcpy(e->u.ping.data, data, data_size); - - qla4xxx_post_work(ha, e); - - return QLA_SUCCESS; -} - -static void qla4xxx_do_work(struct scsi_qla_host *ha) -{ - struct qla4_work_evt *e, *tmp; - unsigned long flags; - LIST_HEAD(work); - - spin_lock_irqsave(&ha->work_lock, flags); - list_splice_init(&ha->work_list, &work); - spin_unlock_irqrestore(&ha->work_lock, flags); - - list_for_each_entry_safe(e, tmp, &work, list) { - list_del_init(&e->list); - - switch (e->type) { - case QLA4_EVENT_AEN: - iscsi_post_host_event(ha->host_no, - &qla4xxx_iscsi_transport, - e->u.aen.code, - e->u.aen.data_size, - e->u.aen.data); - break; - case QLA4_EVENT_PING_STATUS: - iscsi_ping_comp_event(ha->host_no, - &qla4xxx_iscsi_transport, - e->u.ping.status, - e->u.ping.pid, - e->u.ping.data_size, - e->u.ping.data); - break; - default: - ql4_printk(KERN_WARNING, ha, "event type: 0x%x not " - "supported", e->type); - } - kfree(e); - } -} - -/** - * qla4xxx_do_dpc - dpc routine - * @data: in our case pointer to adapter structure - * - * This routine is a task that is schedule by the interrupt handler - * to perform the background processing for interrupts. We put it - * on a task queue that is consumed whenever the scheduler runs; that's - * so you can do anything (i.e. put the process to sleep etc). In fact, - * the mid-level tries to sleep when it reaches the driver threshold - * "host->can_queue". This can cause a panic if we were in our interrupt code. - **/ -static void qla4xxx_do_dpc(struct work_struct *work) -{ - struct scsi_qla_host *ha = - container_of(work, struct scsi_qla_host, dpc_work); - int status = QLA_ERROR; - - DEBUG2(printk("scsi%ld: %s: DPC handler waking up." - "flags = 0x%08lx, dpc_flags = 0x%08lx\n", - ha->host_no, __func__, ha->flags, ha->dpc_flags)) - - /* Initialization not yet finished. Don't do anything yet. */ - if (!test_bit(AF_INIT_DONE, &ha->flags)) - return; - - if (test_bit(AF_EEH_BUSY, &ha->flags)) { - DEBUG2(printk(KERN_INFO "scsi%ld: %s: flags = %lx\n", - ha->host_no, __func__, ha->flags)); - return; - } - - /* post events to application */ - qla4xxx_do_work(ha); - - if (is_qla8022(ha)) { - if (test_bit(DPC_HA_UNRECOVERABLE, &ha->dpc_flags)) { - qla4_8xxx_idc_lock(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - qla4_8xxx_idc_unlock(ha); - ql4_printk(KERN_INFO, ha, "HW State: FAILED\n"); - qla4_8xxx_device_state_handler(ha); - } - if (test_and_clear_bit(DPC_HA_NEED_QUIESCENT, &ha->dpc_flags)) { - qla4_8xxx_need_qsnt_handler(ha); - } - } - - if (!test_bit(DPC_RESET_ACTIVE, &ha->dpc_flags) && - (test_bit(DPC_RESET_HA, &ha->dpc_flags) || - test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) || - test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags))) { - if (ql4xdontresethba) { - DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", - ha->host_no, __func__)); - clear_bit(DPC_RESET_HA, &ha->dpc_flags); - clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); - clear_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); - goto dpc_post_reset_ha; - } - if (test_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags) || - test_bit(DPC_RESET_HA, &ha->dpc_flags)) - qla4xxx_recover_adapter(ha); - - if (test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) { - uint8_t wait_time = RESET_INTR_TOV; - - while ((readw(&ha->reg->ctrl_status) & - (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) { - if (--wait_time == 0) - break; - msleep(1000); - } - if (wait_time == 0) - DEBUG2(printk("scsi%ld: %s: SR|FSR " - "bit not cleared-- resetting\n", - ha->host_no, __func__)); - qla4xxx_abort_active_cmds(ha, DID_RESET << 16); - if (ql4xxx_lock_drvr_wait(ha) == QLA_SUCCESS) { - qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - status = qla4xxx_recover_adapter(ha); - } - clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags); - if (status == QLA_SUCCESS) - ha->isp_ops->enable_intrs(ha); - } - } - -dpc_post_reset_ha: - /* ---- process AEN? --- */ - if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) - qla4xxx_process_aen(ha, PROCESS_ALL_AENS); - - /* ---- Get DHCP IP Address? --- */ - if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags)) - qla4xxx_get_dhcp_ip_address(ha); - - /* ---- relogin device? --- */ - if (adapter_up(ha) && - test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) { - iscsi_host_for_each_session(ha->host, qla4xxx_dpc_relogin); - } - - /* ---- link change? --- */ - if (test_and_clear_bit(DPC_LINK_CHANGED, &ha->dpc_flags)) { - if (!test_bit(AF_LINK_UP, &ha->flags)) { - /* ---- link down? --- */ - qla4xxx_mark_all_devices_missing(ha); - } else { - /* ---- link up? --- * - * F/W will auto login to all devices ONLY ONCE after - * link up during driver initialization and runtime - * fatal error recovery. Therefore, the driver must - * manually relogin to devices when recovering from - * connection failures, logouts, expired KATO, etc. */ - if (test_and_clear_bit(AF_BUILD_DDB_LIST, &ha->flags)) { - qla4xxx_build_ddb_list(ha, ha->is_reset); - iscsi_host_for_each_session(ha->host, - qla4xxx_login_flash_ddb); - } else - qla4xxx_relogin_all_devices(ha); - } - } -} - -/** - * qla4xxx_free_adapter - release the adapter - * @ha: pointer to adapter structure - **/ -static void qla4xxx_free_adapter(struct scsi_qla_host *ha) -{ - qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); - - if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) { - /* Turn-off interrupts on the card. */ - ha->isp_ops->disable_intrs(ha); - } - - /* Remove timer thread, if present */ - if (ha->timer_active) - qla4xxx_stop_timer(ha); - - /* Kill the kernel thread for this host */ - if (ha->dpc_thread) - destroy_workqueue(ha->dpc_thread); - - /* Kill the kernel thread for this host */ - if (ha->task_wq) - destroy_workqueue(ha->task_wq); - - /* Put firmware in known state */ - ha->isp_ops->reset_firmware(ha); - - if (is_qla8022(ha)) { - qla4_8xxx_idc_lock(ha); - qla4_8xxx_clear_drv_active(ha); - qla4_8xxx_idc_unlock(ha); - } - - /* Detach interrupts */ - if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags)) - qla4xxx_free_irqs(ha); - - /* free extra memory */ - qla4xxx_mem_free(ha); -} - -int qla4_8xxx_iospace_config(struct scsi_qla_host *ha) -{ - int status = 0; - unsigned long mem_base, mem_len, db_base, db_len; - struct pci_dev *pdev = ha->pdev; - - status = pci_request_regions(pdev, DRIVER_NAME); - if (status) { - printk(KERN_WARNING - "scsi(%ld) Failed to reserve PIO regions (%s) " - "status=%d\n", ha->host_no, pci_name(pdev), status); - goto iospace_error_exit; - } - - DEBUG2(printk(KERN_INFO "%s: revision-id=%d\n", - __func__, pdev->revision)); - ha->revision_id = pdev->revision; - - /* remap phys address */ - mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ - mem_len = pci_resource_len(pdev, 0); - DEBUG2(printk(KERN_INFO "%s: ioremap from %lx a size of %lx\n", - __func__, mem_base, mem_len)); - - /* mapping of pcibase pointer */ - ha->nx_pcibase = (unsigned long)ioremap(mem_base, mem_len); - if (!ha->nx_pcibase) { - printk(KERN_ERR - "cannot remap MMIO (%s), aborting\n", pci_name(pdev)); - pci_release_regions(ha->pdev); - goto iospace_error_exit; - } - - /* Mapping of IO base pointer, door bell read and write pointer */ - - /* mapping of IO base pointer */ - ha->qla4_8xxx_reg = - (struct device_reg_82xx __iomem *)((uint8_t *)ha->nx_pcibase + - 0xbc000 + (ha->pdev->devfn << 11)); - - db_base = pci_resource_start(pdev, 4); /* doorbell is on bar 4 */ - db_len = pci_resource_len(pdev, 4); - - ha->nx_db_wr_ptr = (ha->pdev->devfn == 4 ? QLA82XX_CAM_RAM_DB1 : - QLA82XX_CAM_RAM_DB2); - - return 0; -iospace_error_exit: - return -ENOMEM; -} - -/*** - * qla4xxx_iospace_config - maps registers - * @ha: pointer to adapter structure - * - * This routines maps HBA's registers from the pci address space - * into the kernel virtual address space for memory mapped i/o. - **/ -int qla4xxx_iospace_config(struct scsi_qla_host *ha) -{ - unsigned long pio, pio_len, pio_flags; - unsigned long mmio, mmio_len, mmio_flags; - - pio = pci_resource_start(ha->pdev, 0); - pio_len = pci_resource_len(ha->pdev, 0); - pio_flags = pci_resource_flags(ha->pdev, 0); - if (pio_flags & IORESOURCE_IO) { - if (pio_len < MIN_IOBASE_LEN) { - ql4_printk(KERN_WARNING, ha, - "Invalid PCI I/O region size\n"); - pio = 0; - } - } else { - ql4_printk(KERN_WARNING, ha, "region #0 not a PIO resource\n"); - pio = 0; - } - - /* Use MMIO operations for all accesses. */ - mmio = pci_resource_start(ha->pdev, 1); - mmio_len = pci_resource_len(ha->pdev, 1); - mmio_flags = pci_resource_flags(ha->pdev, 1); - - if (!(mmio_flags & IORESOURCE_MEM)) { - ql4_printk(KERN_ERR, ha, - "region #0 not an MMIO resource, aborting\n"); - - goto iospace_error_exit; - } - - if (mmio_len < MIN_IOBASE_LEN) { - ql4_printk(KERN_ERR, ha, - "Invalid PCI mem region size, aborting\n"); - goto iospace_error_exit; - } - - if (pci_request_regions(ha->pdev, DRIVER_NAME)) { - ql4_printk(KERN_WARNING, ha, - "Failed to reserve PIO/MMIO regions\n"); - - goto iospace_error_exit; - } - - ha->pio_address = pio; - ha->pio_length = pio_len; - ha->reg = ioremap(mmio, MIN_IOBASE_LEN); - if (!ha->reg) { - ql4_printk(KERN_ERR, ha, - "cannot remap MMIO, aborting\n"); - - goto iospace_error_exit; - } - - return 0; - -iospace_error_exit: - return -ENOMEM; -} - -static struct isp_operations qla4xxx_isp_ops = { - .iospace_config = qla4xxx_iospace_config, - .pci_config = qla4xxx_pci_config, - .disable_intrs = qla4xxx_disable_intrs, - .enable_intrs = qla4xxx_enable_intrs, - .start_firmware = qla4xxx_start_firmware, - .intr_handler = qla4xxx_intr_handler, - .interrupt_service_routine = qla4xxx_interrupt_service_routine, - .reset_chip = qla4xxx_soft_reset, - .reset_firmware = qla4xxx_hw_reset, - .queue_iocb = qla4xxx_queue_iocb, - .complete_iocb = qla4xxx_complete_iocb, - .rd_shdw_req_q_out = qla4xxx_rd_shdw_req_q_out, - .rd_shdw_rsp_q_in = qla4xxx_rd_shdw_rsp_q_in, - .get_sys_info = qla4xxx_get_sys_info, -}; - -static struct isp_operations qla4_8xxx_isp_ops = { - .iospace_config = qla4_8xxx_iospace_config, - .pci_config = qla4_8xxx_pci_config, - .disable_intrs = qla4_8xxx_disable_intrs, - .enable_intrs = qla4_8xxx_enable_intrs, - .start_firmware = qla4_8xxx_load_risc, - .intr_handler = qla4_8xxx_intr_handler, - .interrupt_service_routine = qla4_8xxx_interrupt_service_routine, - .reset_chip = qla4_8xxx_isp_reset, - .reset_firmware = qla4_8xxx_stop_firmware, - .queue_iocb = qla4_8xxx_queue_iocb, - .complete_iocb = qla4_8xxx_complete_iocb, - .rd_shdw_req_q_out = qla4_8xxx_rd_shdw_req_q_out, - .rd_shdw_rsp_q_in = qla4_8xxx_rd_shdw_rsp_q_in, - .get_sys_info = qla4_8xxx_get_sys_info, -}; - -uint16_t qla4xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) -{ - return (uint16_t)le32_to_cpu(ha->shadow_regs->req_q_out); -} - -uint16_t qla4_8xxx_rd_shdw_req_q_out(struct scsi_qla_host *ha) -{ - return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->req_q_out)); -} - -uint16_t qla4xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) -{ - return (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in); -} - -uint16_t qla4_8xxx_rd_shdw_rsp_q_in(struct scsi_qla_host *ha) -{ - return (uint16_t)le32_to_cpu(readl(&ha->qla4_8xxx_reg->rsp_q_in)); -} - -static ssize_t qla4xxx_show_boot_eth_info(void *data, int type, char *buf) -{ - struct scsi_qla_host *ha = data; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_ETH_FLAGS: - rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); - break; - case ISCSI_BOOT_ETH_INDEX: - rc = sprintf(str, "0\n"); - break; - case ISCSI_BOOT_ETH_MAC: - rc = sysfs_format_mac(str, ha->my_mac, - MAC_ADDR_LEN); - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - -static umode_t qla4xxx_eth_get_attr_visibility(void *data, int type) -{ - int rc; - - switch (type) { - case ISCSI_BOOT_ETH_FLAGS: - case ISCSI_BOOT_ETH_MAC: - case ISCSI_BOOT_ETH_INDEX: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - -static ssize_t qla4xxx_show_boot_ini_info(void *data, int type, char *buf) -{ - struct scsi_qla_host *ha = data; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = sprintf(str, "%s\n", ha->name_string); - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - -static umode_t qla4xxx_ini_get_attr_visibility(void *data, int type) -{ - int rc; - - switch (type) { - case ISCSI_BOOT_INI_INITIATOR_NAME: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - -static ssize_t -qla4xxx_show_boot_tgt_info(struct ql4_boot_session_info *boot_sess, int type, - char *buf) -{ - struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; - char *str = buf; - int rc; - - switch (type) { - case ISCSI_BOOT_TGT_NAME: - rc = sprintf(buf, "%s\n", (char *)&boot_sess->target_name); - break; - case ISCSI_BOOT_TGT_IP_ADDR: - if (boot_sess->conn_list[0].dest_ipaddr.ip_type == 0x1) - rc = sprintf(buf, "%pI4\n", - &boot_conn->dest_ipaddr.ip_address); - else - rc = sprintf(str, "%pI6\n", - &boot_conn->dest_ipaddr.ip_address); - break; - case ISCSI_BOOT_TGT_PORT: - rc = sprintf(str, "%d\n", boot_conn->dest_port); - break; - case ISCSI_BOOT_TGT_CHAP_NAME: - rc = sprintf(str, "%.*s\n", - boot_conn->chap.target_chap_name_length, - (char *)&boot_conn->chap.target_chap_name); - break; - case ISCSI_BOOT_TGT_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->chap.target_secret_length, - (char *)&boot_conn->chap.target_secret); - break; - case ISCSI_BOOT_TGT_REV_CHAP_NAME: - rc = sprintf(str, "%.*s\n", - boot_conn->chap.intr_chap_name_length, - (char *)&boot_conn->chap.intr_chap_name); - break; - case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - rc = sprintf(str, "%.*s\n", - boot_conn->chap.intr_secret_length, - (char *)&boot_conn->chap.intr_secret); - break; - case ISCSI_BOOT_TGT_FLAGS: - rc = sprintf(str, "%d\n", SYSFS_FLAG_FW_SEL_BOOT); - break; - case ISCSI_BOOT_TGT_NIC_ASSOC: - rc = sprintf(str, "0\n"); - break; - default: - rc = -ENOSYS; - break; - } - return rc; -} - -static ssize_t qla4xxx_show_boot_tgt_pri_info(void *data, int type, char *buf) -{ - struct scsi_qla_host *ha = data; - struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_pri_sess); - - return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); -} - -static ssize_t qla4xxx_show_boot_tgt_sec_info(void *data, int type, char *buf) -{ - struct scsi_qla_host *ha = data; - struct ql4_boot_session_info *boot_sess = &(ha->boot_tgt.boot_sec_sess); - - return qla4xxx_show_boot_tgt_info(boot_sess, type, buf); -} - -static umode_t qla4xxx_tgt_get_attr_visibility(void *data, int type) -{ - int rc; - - switch (type) { - case ISCSI_BOOT_TGT_NAME: - case ISCSI_BOOT_TGT_IP_ADDR: - case ISCSI_BOOT_TGT_PORT: - case ISCSI_BOOT_TGT_CHAP_NAME: - case ISCSI_BOOT_TGT_CHAP_SECRET: - case ISCSI_BOOT_TGT_REV_CHAP_NAME: - case ISCSI_BOOT_TGT_REV_CHAP_SECRET: - case ISCSI_BOOT_TGT_NIC_ASSOC: - case ISCSI_BOOT_TGT_FLAGS: - rc = S_IRUGO; - break; - default: - rc = 0; - break; - } - return rc; -} - -static void qla4xxx_boot_release(void *data) -{ - struct scsi_qla_host *ha = data; - - scsi_host_put(ha->host); -} - -static int get_fw_boot_info(struct scsi_qla_host *ha, uint16_t ddb_index[]) -{ - dma_addr_t buf_dma; - uint32_t addr, pri_addr, sec_addr; - uint32_t offset; - uint16_t func_num; - uint8_t val; - uint8_t *buf = NULL; - size_t size = 13 * sizeof(uint8_t); - int ret = QLA_SUCCESS; - - func_num = PCI_FUNC(ha->pdev->devfn); - - ql4_printk(KERN_INFO, ha, "%s: Get FW boot info for 0x%x func %d\n", - __func__, ha->pdev->device, func_num); - - if (is_qla40XX(ha)) { - if (func_num == 1) { - addr = NVRAM_PORT0_BOOT_MODE; - pri_addr = NVRAM_PORT0_BOOT_PRI_TGT; - sec_addr = NVRAM_PORT0_BOOT_SEC_TGT; - } else if (func_num == 3) { - addr = NVRAM_PORT1_BOOT_MODE; - pri_addr = NVRAM_PORT1_BOOT_PRI_TGT; - sec_addr = NVRAM_PORT1_BOOT_SEC_TGT; - } else { - ret = QLA_ERROR; - goto exit_boot_info; - } - - /* Check Boot Mode */ - val = rd_nvram_byte(ha, addr); - if (!(val & 0x07)) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Adapter boot " - "options : 0x%x\n", __func__, val)); - ret = QLA_ERROR; - goto exit_boot_info; - } - - /* get primary valid target index */ - val = rd_nvram_byte(ha, pri_addr); - if (val & BIT_7) - ddb_index[0] = (val & 0x7f); - - /* get secondary valid target index */ - val = rd_nvram_byte(ha, sec_addr); - if (val & BIT_7) - ddb_index[1] = (val & 0x7f); - - } else if (is_qla8022(ha)) { - buf = dma_alloc_coherent(&ha->pdev->dev, size, - &buf_dma, GFP_KERNEL); - if (!buf) { - DEBUG2(ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer\n", - __func__)); - ret = QLA_ERROR; - goto exit_boot_info; - } - - if (ha->port_num == 0) - offset = BOOT_PARAM_OFFSET_PORT0; - else if (ha->port_num == 1) - offset = BOOT_PARAM_OFFSET_PORT1; - else { - ret = QLA_ERROR; - goto exit_boot_info_free; - } - addr = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_iscsi_param * 4) + - offset; - if (qla4xxx_get_flash(ha, buf_dma, addr, - 13 * sizeof(uint8_t)) != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_ERR, ha, "scsi%ld: %s: Get Flash" - " failed\n", ha->host_no, __func__)); - ret = QLA_ERROR; - goto exit_boot_info_free; - } - /* Check Boot Mode */ - if (!(buf[1] & 0x07)) { - DEBUG2(ql4_printk(KERN_INFO, ha, "Firmware boot options" - " : 0x%x\n", buf[1])); - ret = QLA_ERROR; - goto exit_boot_info_free; - } - - /* get primary valid target index */ - if (buf[2] & BIT_7) - ddb_index[0] = buf[2] & 0x7f; - - /* get secondary valid target index */ - if (buf[11] & BIT_7) - ddb_index[1] = buf[11] & 0x7f; - } else { - ret = QLA_ERROR; - goto exit_boot_info; - } - - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary target ID %d, Secondary" - " target ID %d\n", __func__, ddb_index[0], - ddb_index[1])); - -exit_boot_info_free: - dma_free_coherent(&ha->pdev->dev, size, buf, buf_dma); -exit_boot_info: - ha->pri_ddb_idx = ddb_index[0]; - ha->sec_ddb_idx = ddb_index[1]; - return ret; -} - -/** - * qla4xxx_get_bidi_chap - Get a BIDI CHAP user and password - * @ha: pointer to adapter structure - * @username: CHAP username to be returned - * @password: CHAP password to be returned - * - * If a boot entry has BIDI CHAP enabled then we need to set the BIDI CHAP - * user and password in the sysfs entry in /sys/firmware/iscsi_boot#/. - * So from the CHAP cache find the first BIDI CHAP entry and set it - * to the boot record in sysfs. - **/ -static int qla4xxx_get_bidi_chap(struct scsi_qla_host *ha, char *username, - char *password) -{ - int i, ret = -EINVAL; - int max_chap_entries = 0; - struct ql4_chap_table *chap_table; - - if (is_qla8022(ha)) - max_chap_entries = (ha->hw.flt_chap_size / 2) / - sizeof(struct ql4_chap_table); - else - max_chap_entries = MAX_CHAP_ENTRIES_40XX; - - if (!ha->chap_list) { - ql4_printk(KERN_ERR, ha, "Do not have CHAP table cache\n"); - return ret; - } - - mutex_lock(&ha->chap_sem); - for (i = 0; i < max_chap_entries; i++) { - chap_table = (struct ql4_chap_table *)ha->chap_list + i; - if (chap_table->cookie != - __constant_cpu_to_le16(CHAP_VALID_COOKIE)) { - continue; - } - - if (chap_table->flags & BIT_7) /* local */ - continue; - - if (!(chap_table->flags & BIT_6)) /* Not BIDI */ - continue; - - strncpy(password, chap_table->secret, QL4_CHAP_MAX_SECRET_LEN); - strncpy(username, chap_table->name, QL4_CHAP_MAX_NAME_LEN); - ret = 0; - break; - } - mutex_unlock(&ha->chap_sem); - - return ret; -} - - -static int qla4xxx_get_boot_target(struct scsi_qla_host *ha, - struct ql4_boot_session_info *boot_sess, - uint16_t ddb_index) -{ - struct ql4_conn_info *boot_conn = &boot_sess->conn_list[0]; - struct dev_db_entry *fw_ddb_entry; - dma_addr_t fw_ddb_entry_dma; - uint16_t idx; - uint16_t options; - int ret = QLA_SUCCESS; - - fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - &fw_ddb_entry_dma, GFP_KERNEL); - if (!fw_ddb_entry) { - DEBUG2(ql4_printk(KERN_ERR, ha, - "%s: Unable to allocate dma buffer.\n", - __func__)); - ret = QLA_ERROR; - return ret; - } - - if (qla4xxx_bootdb_by_index(ha, fw_ddb_entry, - fw_ddb_entry_dma, ddb_index)) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: No Flash DDB found at " - "index [%d]\n", __func__, ddb_index)); - ret = QLA_ERROR; - goto exit_boot_target; - } - - /* Update target name and IP from DDB */ - memcpy(boot_sess->target_name, fw_ddb_entry->iscsi_name, - min(sizeof(boot_sess->target_name), - sizeof(fw_ddb_entry->iscsi_name))); - - options = le16_to_cpu(fw_ddb_entry->options); - if (options & DDB_OPT_IPV6_DEVICE) { - memcpy(&boot_conn->dest_ipaddr.ip_address, - &fw_ddb_entry->ip_addr[0], IPv6_ADDR_LEN); - } else { - boot_conn->dest_ipaddr.ip_type = 0x1; - memcpy(&boot_conn->dest_ipaddr.ip_address, - &fw_ddb_entry->ip_addr[0], IP_ADDR_LEN); - } - - boot_conn->dest_port = le16_to_cpu(fw_ddb_entry->port); - - /* update chap information */ - idx = __le16_to_cpu(fw_ddb_entry->chap_tbl_idx); - - if (BIT_7 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { - - DEBUG2(ql4_printk(KERN_INFO, ha, "Setting chap\n")); - - ret = qla4xxx_get_chap(ha, (char *)&boot_conn->chap. - target_chap_name, - (char *)&boot_conn->chap.target_secret, - idx); - if (ret) { - ql4_printk(KERN_ERR, ha, "Failed to set chap\n"); - ret = QLA_ERROR; - goto exit_boot_target; - } - - boot_conn->chap.target_chap_name_length = QL4_CHAP_MAX_NAME_LEN; - boot_conn->chap.target_secret_length = QL4_CHAP_MAX_SECRET_LEN; - } - - if (BIT_4 & le16_to_cpu(fw_ddb_entry->iscsi_options)) { - - DEBUG2(ql4_printk(KERN_INFO, ha, "Setting BIDI chap\n")); - - ret = qla4xxx_get_bidi_chap(ha, - (char *)&boot_conn->chap.intr_chap_name, - (char *)&boot_conn->chap.intr_secret); - - if (ret) { - ql4_printk(KERN_ERR, ha, "Failed to set BIDI chap\n"); - ret = QLA_ERROR; - goto exit_boot_target; - } - - boot_conn->chap.intr_chap_name_length = QL4_CHAP_MAX_NAME_LEN; - boot_conn->chap.intr_secret_length = QL4_CHAP_MAX_SECRET_LEN; - } - -exit_boot_target: - dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), - fw_ddb_entry, fw_ddb_entry_dma); - return ret; -} - -static int qla4xxx_get_boot_info(struct scsi_qla_host *ha) -{ - uint16_t ddb_index[2]; - int ret = QLA_ERROR; - int rval; - - memset(ddb_index, 0, sizeof(ddb_index)); - ddb_index[0] = 0xffff; - ddb_index[1] = 0xffff; - ret = get_fw_boot_info(ha, ddb_index); - if (ret != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, - "%s: No boot target configured.\n", __func__)); - return ret; - } - - if (ql4xdisablesysfsboot) - return QLA_SUCCESS; - - if (ddb_index[0] == 0xffff) - goto sec_target; - - rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_pri_sess), - ddb_index[0]); - if (rval != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Primary boot target not " - "configured\n", __func__)); - } else - ret = QLA_SUCCESS; - -sec_target: - if (ddb_index[1] == 0xffff) - goto exit_get_boot_info; - - rval = qla4xxx_get_boot_target(ha, &(ha->boot_tgt.boot_sec_sess), - ddb_index[1]); - if (rval != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Secondary boot target not" - " configured\n", __func__)); - } else - ret = QLA_SUCCESS; - -exit_get_boot_info: - return ret; -} - -static int qla4xxx_setup_boot_info(struct scsi_qla_host *ha) -{ - struct iscsi_boot_kobj *boot_kobj; - - if (qla4xxx_get_boot_info(ha) != QLA_SUCCESS) - return QLA_ERROR; - - if (ql4xdisablesysfsboot) { - ql4_printk(KERN_INFO, ha, - "%s: syfsboot disabled - driver will trigger login " - "and publish session for discovery .\n", __func__); - return QLA_SUCCESS; - } - - - ha->boot_kset = iscsi_boot_create_host_kset(ha->host->host_no); - if (!ha->boot_kset) - goto kset_free; - - if (!scsi_host_get(ha->host)) - goto kset_free; - boot_kobj = iscsi_boot_create_target(ha->boot_kset, 0, ha, - qla4xxx_show_boot_tgt_pri_info, - qla4xxx_tgt_get_attr_visibility, - qla4xxx_boot_release); - if (!boot_kobj) - goto put_host; - - if (!scsi_host_get(ha->host)) - goto kset_free; - boot_kobj = iscsi_boot_create_target(ha->boot_kset, 1, ha, - qla4xxx_show_boot_tgt_sec_info, - qla4xxx_tgt_get_attr_visibility, - qla4xxx_boot_release); - if (!boot_kobj) - goto put_host; - - if (!scsi_host_get(ha->host)) - goto kset_free; - boot_kobj = iscsi_boot_create_initiator(ha->boot_kset, 0, ha, - qla4xxx_show_boot_ini_info, - qla4xxx_ini_get_attr_visibility, - qla4xxx_boot_release); - if (!boot_kobj) - goto put_host; - - if (!scsi_host_get(ha->host)) - goto kset_free; - boot_kobj = iscsi_boot_create_ethernet(ha->boot_kset, 0, ha, - qla4xxx_show_boot_eth_info, - qla4xxx_eth_get_attr_visibility, - qla4xxx_boot_release); - if (!boot_kobj) - goto put_host; - - return QLA_SUCCESS; - -put_host: - scsi_host_put(ha->host); -kset_free: - iscsi_boot_destroy_kset(ha->boot_kset); - return -ENOMEM; -} - - -/** - * qla4xxx_create chap_list - Create CHAP list from FLASH - * @ha: pointer to adapter structure - * - * Read flash and make a list of CHAP entries, during login when a CHAP entry - * is received, it will be checked in this list. If entry exist then the CHAP - * entry index is set in the DDB. If CHAP entry does not exist in this list - * then a new entry is added in FLASH in CHAP table and the index obtained is - * used in the DDB. - **/ -static void qla4xxx_create_chap_list(struct scsi_qla_host *ha) -{ - int rval = 0; - uint8_t *chap_flash_data = NULL; - uint32_t offset; - dma_addr_t chap_dma; - uint32_t chap_size = 0; - - if (is_qla40XX(ha)) - chap_size = MAX_CHAP_ENTRIES_40XX * - sizeof(struct ql4_chap_table); - else /* Single region contains CHAP info for both - * ports which is divided into half for each port. - */ - chap_size = ha->hw.flt_chap_size / 2; - - chap_flash_data = dma_alloc_coherent(&ha->pdev->dev, chap_size, - &chap_dma, GFP_KERNEL); - if (!chap_flash_data) { - ql4_printk(KERN_ERR, ha, "No memory for chap_flash_data\n"); - return; - } - if (is_qla40XX(ha)) - offset = FLASH_CHAP_OFFSET; - else { - offset = FLASH_RAW_ACCESS_ADDR + (ha->hw.flt_region_chap << 2); - if (ha->port_num == 1) - offset += chap_size; - } - - rval = qla4xxx_get_flash(ha, chap_dma, offset, chap_size); - if (rval != QLA_SUCCESS) - goto exit_chap_list; - - if (ha->chap_list == NULL) - ha->chap_list = vmalloc(chap_size); - if (ha->chap_list == NULL) { - ql4_printk(KERN_ERR, ha, "No memory for ha->chap_list\n"); - goto exit_chap_list; - } - - memcpy(ha->chap_list, chap_flash_data, chap_size); - -exit_chap_list: - dma_free_coherent(&ha->pdev->dev, chap_size, - chap_flash_data, chap_dma); -} - -static void qla4xxx_get_param_ddb(struct ddb_entry *ddb_entry, - struct ql4_tuple_ddb *tddb) -{ - struct scsi_qla_host *ha; - struct iscsi_cls_session *cls_sess; - struct iscsi_cls_conn *cls_conn; - struct iscsi_session *sess; - struct iscsi_conn *conn; - - DEBUG2(printk(KERN_INFO "Func: %s\n", __func__)); - ha = ddb_entry->ha; - cls_sess = ddb_entry->sess; - sess = cls_sess->dd_data; - cls_conn = ddb_entry->conn; - conn = cls_conn->dd_data; - - tddb->tpgt = sess->tpgt; - tddb->port = conn->persistent_port; - strncpy(tddb->iscsi_name, sess->targetname, ISCSI_NAME_SIZE); - strncpy(tddb->ip_addr, conn->persistent_address, DDB_IPADDR_LEN); -} - -static void qla4xxx_convert_param_ddb(struct dev_db_entry *fw_ddb_entry, - struct ql4_tuple_ddb *tddb) -{ - uint16_t options = 0; - - tddb->tpgt = le32_to_cpu(fw_ddb_entry->tgt_portal_grp); - memcpy(&tddb->iscsi_name[0], &fw_ddb_entry->iscsi_name[0], - min(sizeof(tddb->iscsi_name), sizeof(fw_ddb_entry->iscsi_name))); - - options = le16_to_cpu(fw_ddb_entry->options); - if (options & DDB_OPT_IPV6_DEVICE) - sprintf(tddb->ip_addr, "%pI6", fw_ddb_entry->ip_addr); - else - sprintf(tddb->ip_addr, "%pI4", fw_ddb_entry->ip_addr); - - tddb->port = le16_to_cpu(fw_ddb_entry->port); - memcpy(&tddb->isid[0], &fw_ddb_entry->isid[0], sizeof(tddb->isid)); -} - -static int qla4xxx_compare_tuple_ddb(struct scsi_qla_host *ha, - struct ql4_tuple_ddb *old_tddb, - struct ql4_tuple_ddb *new_tddb, - uint8_t is_isid_compare) -{ - if (strcmp(old_tddb->iscsi_name, new_tddb->iscsi_name)) - return QLA_ERROR; - - if (strcmp(old_tddb->ip_addr, new_tddb->ip_addr)) - return QLA_ERROR; - - if (old_tddb->port != new_tddb->port) - return QLA_ERROR; - - /* For multi sessions, driver generates the ISID, so do not compare - * ISID in reset path since it would be a comparision between the - * driver generated ISID and firmware generated ISID. This could - * lead to adding duplicated DDBs in the list as driver generated - * ISID would not match firmware generated ISID. - */ - if (is_isid_compare) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: old ISID [%02x%02x%02x" - "%02x%02x%02x] New ISID [%02x%02x%02x%02x%02x%02x]\n", - __func__, old_tddb->isid[5], old_tddb->isid[4], - old_tddb->isid[3], old_tddb->isid[2], old_tddb->isid[1], - old_tddb->isid[0], new_tddb->isid[5], new_tddb->isid[4], - new_tddb->isid[3], new_tddb->isid[2], new_tddb->isid[1], - new_tddb->isid[0])); - - if (memcmp(&old_tddb->isid[0], &new_tddb->isid[0], - sizeof(old_tddb->isid))) - return QLA_ERROR; - } - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Match Found, fw[%d,%d,%s,%s], [%d,%d,%s,%s]", - old_tddb->port, old_tddb->tpgt, old_tddb->ip_addr, - old_tddb->iscsi_name, new_tddb->port, new_tddb->tpgt, - new_tddb->ip_addr, new_tddb->iscsi_name)); - - return QLA_SUCCESS; -} - -static int qla4xxx_is_session_exists(struct scsi_qla_host *ha, - struct dev_db_entry *fw_ddb_entry) -{ - struct ddb_entry *ddb_entry; - struct ql4_tuple_ddb *fw_tddb = NULL; - struct ql4_tuple_ddb *tmp_tddb = NULL; - int idx; - int ret = QLA_ERROR; - - fw_tddb = vzalloc(sizeof(*fw_tddb)); - if (!fw_tddb) { - DEBUG2(ql4_printk(KERN_WARNING, ha, - "Memory Allocation failed.\n")); - ret = QLA_SUCCESS; - goto exit_check; - } - - tmp_tddb = vzalloc(sizeof(*tmp_tddb)); - if (!tmp_tddb) { - DEBUG2(ql4_printk(KERN_WARNING, ha, - "Memory Allocation failed.\n")); - ret = QLA_SUCCESS; - goto exit_check; - } - - qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); - - for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); - if (ddb_entry == NULL) - continue; - - qla4xxx_get_param_ddb(ddb_entry, tmp_tddb); - if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, false)) { - ret = QLA_SUCCESS; /* found */ - goto exit_check; - } - } - -exit_check: - if (fw_tddb) - vfree(fw_tddb); - if (tmp_tddb) - vfree(tmp_tddb); - return ret; -} - -static int qla4xxx_is_flash_ddb_exists(struct scsi_qla_host *ha, - struct list_head *list_nt, - struct dev_db_entry *fw_ddb_entry) -{ - struct qla_ddb_index *nt_ddb_idx, *nt_ddb_idx_tmp; - struct ql4_tuple_ddb *fw_tddb = NULL; - struct ql4_tuple_ddb *tmp_tddb = NULL; - int ret = QLA_ERROR; - - fw_tddb = vzalloc(sizeof(*fw_tddb)); - if (!fw_tddb) { - DEBUG2(ql4_printk(KERN_WARNING, ha, - "Memory Allocation failed.\n")); - ret = QLA_SUCCESS; - goto exit_check; - } - - tmp_tddb = vzalloc(sizeof(*tmp_tddb)); - if (!tmp_tddb) { - DEBUG2(ql4_printk(KERN_WARNING, ha, - "Memory Allocation failed.\n")); - ret = QLA_SUCCESS; - goto exit_check; - } - - qla4xxx_convert_param_ddb(fw_ddb_entry, fw_tddb); - - list_for_each_entry_safe(nt_ddb_idx, nt_ddb_idx_tmp, list_nt, list) { - qla4xxx_convert_param_ddb(&nt_ddb_idx->fw_ddb, tmp_tddb); - if (!qla4xxx_compare_tuple_ddb(ha, fw_tddb, tmp_tddb, true)) { - ret = QLA_SUCCESS; /* found */ - goto exit_check; - } - } - -exit_check: - if (fw_tddb) - vfree(fw_tddb); - if (tmp_tddb) - vfree(tmp_tddb); - return ret; -} - -static void qla4xxx_free_ddb_list(struct list_head *list_ddb) -{ - struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; - - list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { - list_del_init(&ddb_idx->list); - vfree(ddb_idx); - } -} - -static struct iscsi_endpoint *qla4xxx_get_ep_fwdb(struct scsi_qla_host *ha, - struct dev_db_entry *fw_ddb_entry) -{ - struct iscsi_endpoint *ep; - struct sockaddr_in *addr; - struct sockaddr_in6 *addr6; - struct sockaddr *dst_addr; - char *ip; - - /* TODO: need to destroy on unload iscsi_endpoint*/ - dst_addr = vmalloc(sizeof(*dst_addr)); - if (!dst_addr) - return NULL; - - if (fw_ddb_entry->options & DDB_OPT_IPV6_DEVICE) { - dst_addr->sa_family = AF_INET6; - addr6 = (struct sockaddr_in6 *)dst_addr; - ip = (char *)&addr6->sin6_addr; - memcpy(ip, fw_ddb_entry->ip_addr, IPv6_ADDR_LEN); - addr6->sin6_port = htons(le16_to_cpu(fw_ddb_entry->port)); - - } else { - dst_addr->sa_family = AF_INET; - addr = (struct sockaddr_in *)dst_addr; - ip = (char *)&addr->sin_addr; - memcpy(ip, fw_ddb_entry->ip_addr, IP_ADDR_LEN); - addr->sin_port = htons(le16_to_cpu(fw_ddb_entry->port)); - } - - ep = qla4xxx_ep_connect(ha->host, dst_addr, 0); - vfree(dst_addr); - return ep; -} - -static int qla4xxx_verify_boot_idx(struct scsi_qla_host *ha, uint16_t idx) -{ - if (ql4xdisablesysfsboot) - return QLA_SUCCESS; - if (idx == ha->pri_ddb_idx || idx == ha->sec_ddb_idx) - return QLA_ERROR; - return QLA_SUCCESS; -} - -static void qla4xxx_setup_flash_ddb_entry(struct scsi_qla_host *ha, - struct ddb_entry *ddb_entry) -{ - uint16_t def_timeout; - - ddb_entry->ddb_type = FLASH_DDB; - ddb_entry->fw_ddb_index = INVALID_ENTRY; - ddb_entry->fw_ddb_device_state = DDB_DS_NO_CONNECTION_ACTIVE; - ddb_entry->ha = ha; - ddb_entry->unblock_sess = qla4xxx_unblock_flash_ddb; - ddb_entry->ddb_change = qla4xxx_flash_ddb_change; - - atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY); - atomic_set(&ddb_entry->relogin_timer, 0); - atomic_set(&ddb_entry->relogin_retry_count, 0); - def_timeout = le16_to_cpu(ddb_entry->fw_ddb_entry.def_timeout); - ddb_entry->default_relogin_timeout = - (def_timeout > LOGIN_TOV) && (def_timeout < LOGIN_TOV * 10) ? - def_timeout : LOGIN_TOV; - ddb_entry->default_time2wait = - le16_to_cpu(ddb_entry->fw_ddb_entry.iscsi_def_time2wait); -} - -static void qla4xxx_wait_for_ip_configuration(struct scsi_qla_host *ha) -{ - uint32_t idx = 0; - uint32_t ip_idx[IP_ADDR_COUNT] = {0, 1, 2, 3}; /* 4 IP interfaces */ - uint32_t sts[MBOX_REG_COUNT]; - uint32_t ip_state; - unsigned long wtime; - int ret; - - wtime = jiffies + (HZ * IP_CONFIG_TOV); - do { - for (idx = 0; idx < IP_ADDR_COUNT; idx++) { - if (ip_idx[idx] == -1) - continue; - - ret = qla4xxx_get_ip_state(ha, 0, ip_idx[idx], sts); - - if (ret == QLA_ERROR) { - ip_idx[idx] = -1; - continue; - } - - ip_state = (sts[1] & IP_STATE_MASK) >> IP_STATE_SHIFT; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Waiting for IP state for idx = %d, state = 0x%x\n", - ip_idx[idx], ip_state)); - if (ip_state == IP_ADDRSTATE_UNCONFIGURED || - ip_state == IP_ADDRSTATE_INVALID || - ip_state == IP_ADDRSTATE_PREFERRED || - ip_state == IP_ADDRSTATE_DEPRICATED || - ip_state == IP_ADDRSTATE_DISABLING) - ip_idx[idx] = -1; - } - - /* Break if all IP states checked */ - if ((ip_idx[0] == -1) && - (ip_idx[1] == -1) && - (ip_idx[2] == -1) && - (ip_idx[3] == -1)) - break; - schedule_timeout_uninterruptible(HZ); - } while (time_after(wtime, jiffies)); -} - -static void qla4xxx_build_st_list(struct scsi_qla_host *ha, - struct list_head *list_st) -{ - struct qla_ddb_index *st_ddb_idx; - int max_ddbs; - int fw_idx_size; - struct dev_db_entry *fw_ddb_entry; - dma_addr_t fw_ddb_dma; - int ret; - uint32_t idx = 0, next_idx = 0; - uint32_t state = 0, conn_err = 0; - uint16_t conn_id = 0; - - fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, - &fw_ddb_dma); - if (fw_ddb_entry == NULL) { - DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); - goto exit_st_list; - } - - max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : - MAX_DEV_DB_ENTRIES; - fw_idx_size = sizeof(struct qla_ddb_index); - - for (idx = 0; idx < max_ddbs; idx = next_idx) { - ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, - NULL, &next_idx, &state, - &conn_err, NULL, &conn_id); - if (ret == QLA_ERROR) - break; - - /* Ignore DDB if invalid state (unassigned) */ - if (state == DDB_DS_UNASSIGNED) - goto continue_next_st; - - /* Check if ST, add to the list_st */ - if (strlen((char *) fw_ddb_entry->iscsi_name) != 0) - goto continue_next_st; - - st_ddb_idx = vzalloc(fw_idx_size); - if (!st_ddb_idx) - break; - - st_ddb_idx->fw_ddb_idx = idx; - - list_add_tail(&st_ddb_idx->list, list_st); -continue_next_st: - if (next_idx == 0) - break; - } - -exit_st_list: - if (fw_ddb_entry) - dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); -} - -/** - * qla4xxx_remove_failed_ddb - Remove inactive or failed ddb from list - * @ha: pointer to adapter structure - * @list_ddb: List from which failed ddb to be removed - * - * Iterate over the list of DDBs and find and remove DDBs that are either in - * no connection active state or failed state - **/ -static void qla4xxx_remove_failed_ddb(struct scsi_qla_host *ha, - struct list_head *list_ddb) -{ - struct qla_ddb_index *ddb_idx, *ddb_idx_tmp; - uint32_t next_idx = 0; - uint32_t state = 0, conn_err = 0; - int ret; - - list_for_each_entry_safe(ddb_idx, ddb_idx_tmp, list_ddb, list) { - ret = qla4xxx_get_fwddb_entry(ha, ddb_idx->fw_ddb_idx, - NULL, 0, NULL, &next_idx, &state, - &conn_err, NULL, NULL); - if (ret == QLA_ERROR) - continue; - - if (state == DDB_DS_NO_CONNECTION_ACTIVE || - state == DDB_DS_SESSION_FAILED) { - list_del_init(&ddb_idx->list); - vfree(ddb_idx); - } - } -} - -static int qla4xxx_sess_conn_setup(struct scsi_qla_host *ha, - struct dev_db_entry *fw_ddb_entry, - int is_reset) -{ - struct iscsi_cls_session *cls_sess; - struct iscsi_session *sess; - struct iscsi_cls_conn *cls_conn; - struct iscsi_endpoint *ep; - uint16_t cmds_max = 32; - uint16_t conn_id = 0; - uint32_t initial_cmdsn = 0; - int ret = QLA_SUCCESS; - - struct ddb_entry *ddb_entry = NULL; - - /* Create session object, with INVALID_ENTRY, - * the targer_id would get set when we issue the login - */ - cls_sess = iscsi_session_setup(&qla4xxx_iscsi_transport, ha->host, - cmds_max, sizeof(struct ddb_entry), - sizeof(struct ql4_task_data), - initial_cmdsn, INVALID_ENTRY); - if (!cls_sess) { - ret = QLA_ERROR; - goto exit_setup; - } - - /* - * so calling module_put function to decrement the - * reference count. - **/ - module_put(qla4xxx_iscsi_transport.owner); - sess = cls_sess->dd_data; - ddb_entry = sess->dd_data; - ddb_entry->sess = cls_sess; - - cls_sess->recovery_tmo = ql4xsess_recovery_tmo; - memcpy(&ddb_entry->fw_ddb_entry, fw_ddb_entry, - sizeof(struct dev_db_entry)); - - qla4xxx_setup_flash_ddb_entry(ha, ddb_entry); - - cls_conn = iscsi_conn_setup(cls_sess, sizeof(struct qla_conn), conn_id); - - if (!cls_conn) { - ret = QLA_ERROR; - goto exit_setup; - } - - ddb_entry->conn = cls_conn; - - /* Setup ep, for displaying attributes in sysfs */ - ep = qla4xxx_get_ep_fwdb(ha, fw_ddb_entry); - if (ep) { - ep->conn = cls_conn; - cls_conn->ep = ep; - } else { - DEBUG2(ql4_printk(KERN_ERR, ha, "Unable to get ep\n")); - ret = QLA_ERROR; - goto exit_setup; - } - - /* Update sess/conn params */ - qla4xxx_copy_fwddb_param(ha, fw_ddb_entry, cls_sess, cls_conn); - - if (is_reset == RESET_ADAPTER) { - iscsi_block_session(cls_sess); - /* Use the relogin path to discover new devices - * by short-circuting the logic of setting - * timer to relogin - instead set the flags - * to initiate login right away. - */ - set_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags); - set_bit(DF_RELOGIN, &ddb_entry->flags); - } - -exit_setup: - return ret; -} - -static void qla4xxx_build_nt_list(struct scsi_qla_host *ha, - struct list_head *list_nt, int is_reset) -{ - struct dev_db_entry *fw_ddb_entry; - dma_addr_t fw_ddb_dma; - int max_ddbs; - int fw_idx_size; - int ret; - uint32_t idx = 0, next_idx = 0; - uint32_t state = 0, conn_err = 0; - uint16_t conn_id = 0; - struct qla_ddb_index *nt_ddb_idx; - - fw_ddb_entry = dma_pool_alloc(ha->fw_ddb_dma_pool, GFP_KERNEL, - &fw_ddb_dma); - if (fw_ddb_entry == NULL) { - DEBUG2(ql4_printk(KERN_ERR, ha, "Out of memory\n")); - goto exit_nt_list; - } - max_ddbs = is_qla40XX(ha) ? MAX_DEV_DB_ENTRIES_40XX : - MAX_DEV_DB_ENTRIES; - fw_idx_size = sizeof(struct qla_ddb_index); - - for (idx = 0; idx < max_ddbs; idx = next_idx) { - ret = qla4xxx_get_fwddb_entry(ha, idx, fw_ddb_entry, fw_ddb_dma, - NULL, &next_idx, &state, - &conn_err, NULL, &conn_id); - if (ret == QLA_ERROR) - break; - - if (qla4xxx_verify_boot_idx(ha, idx) != QLA_SUCCESS) - goto continue_next_nt; - - /* Check if NT, then add to list it */ - if (strlen((char *) fw_ddb_entry->iscsi_name) == 0) - goto continue_next_nt; - - if (!(state == DDB_DS_NO_CONNECTION_ACTIVE || - state == DDB_DS_SESSION_FAILED)) - goto continue_next_nt; - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Adding DDB to session = 0x%x\n", idx)); - if (is_reset == INIT_ADAPTER) { - nt_ddb_idx = vmalloc(fw_idx_size); - if (!nt_ddb_idx) - break; - - nt_ddb_idx->fw_ddb_idx = idx; - - memcpy(&nt_ddb_idx->fw_ddb, fw_ddb_entry, - sizeof(struct dev_db_entry)); - - if (qla4xxx_is_flash_ddb_exists(ha, list_nt, - fw_ddb_entry) == QLA_SUCCESS) { - vfree(nt_ddb_idx); - goto continue_next_nt; - } - list_add_tail(&nt_ddb_idx->list, list_nt); - } else if (is_reset == RESET_ADAPTER) { - if (qla4xxx_is_session_exists(ha, fw_ddb_entry) == - QLA_SUCCESS) - goto continue_next_nt; - } - - ret = qla4xxx_sess_conn_setup(ha, fw_ddb_entry, is_reset); - if (ret == QLA_ERROR) - goto exit_nt_list; - -continue_next_nt: - if (next_idx == 0) - break; - } - -exit_nt_list: - if (fw_ddb_entry) - dma_pool_free(ha->fw_ddb_dma_pool, fw_ddb_entry, fw_ddb_dma); -} - -/** - * qla4xxx_build_ddb_list - Build ddb list and setup sessions - * @ha: pointer to adapter structure - * @is_reset: Is this init path or reset path - * - * Create a list of sendtargets (st) from firmware DDBs, issue send targets - * using connection open, then create the list of normal targets (nt) - * from firmware DDBs. Based on the list of nt setup session and connection - * objects. - **/ -void qla4xxx_build_ddb_list(struct scsi_qla_host *ha, int is_reset) -{ - uint16_t tmo = 0; - struct list_head list_st, list_nt; - struct qla_ddb_index *st_ddb_idx, *st_ddb_idx_tmp; - unsigned long wtime; - - if (!test_bit(AF_LINK_UP, &ha->flags)) { - set_bit(AF_BUILD_DDB_LIST, &ha->flags); - ha->is_reset = is_reset; - return; - } - - INIT_LIST_HEAD(&list_st); - INIT_LIST_HEAD(&list_nt); - - qla4xxx_build_st_list(ha, &list_st); - - /* Before issuing conn open mbox, ensure all IPs states are configured - * Note, conn open fails if IPs are not configured - */ - qla4xxx_wait_for_ip_configuration(ha); - - /* Go thru the STs and fire the sendtargets by issuing conn open mbx */ - list_for_each_entry_safe(st_ddb_idx, st_ddb_idx_tmp, &list_st, list) { - qla4xxx_conn_open(ha, st_ddb_idx->fw_ddb_idx); - } - - /* Wait to ensure all sendtargets are done for min 12 sec wait */ - tmo = ((ha->def_timeout > LOGIN_TOV) && - (ha->def_timeout < LOGIN_TOV * 10) ? - ha->def_timeout : LOGIN_TOV); - - DEBUG2(ql4_printk(KERN_INFO, ha, - "Default time to wait for build ddb %d\n", tmo)); - - wtime = jiffies + (HZ * tmo); - do { - if (list_empty(&list_st)) - break; - - qla4xxx_remove_failed_ddb(ha, &list_st); - schedule_timeout_uninterruptible(HZ / 10); - } while (time_after(wtime, jiffies)); - - /* Free up the sendtargets list */ - qla4xxx_free_ddb_list(&list_st); - - qla4xxx_build_nt_list(ha, &list_nt, is_reset); - - qla4xxx_free_ddb_list(&list_nt); - - qla4xxx_free_ddb_index(ha); -} - -/** - * qla4xxx_probe_adapter - callback function to probe HBA - * @pdev: pointer to pci_dev structure - * @pci_device_id: pointer to pci_device entry - * - * This routine will probe for Qlogic 4xxx iSCSI host adapters. - * It returns zero if successful. It also initializes all data necessary for - * the driver. - **/ -static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int ret = -ENODEV, status; - struct Scsi_Host *host; - struct scsi_qla_host *ha; - uint8_t init_retry_count = 0; - char buf[34]; - struct qla4_8xxx_legacy_intr_set *nx_legacy_intr; - uint32_t dev_state; - - if (pci_enable_device(pdev)) - return -1; - - host = iscsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha), 0); - if (host == NULL) { - printk(KERN_WARNING - "qla4xxx: Couldn't allocate host from scsi layer!\n"); - goto probe_disable_device; - } - - /* Clear our data area */ - ha = to_qla_host(host); - memset(ha, 0, sizeof(*ha)); - - /* Save the information from PCI BIOS. */ - ha->pdev = pdev; - ha->host = host; - ha->host_no = host->host_no; - - pci_enable_pcie_error_reporting(pdev); - - /* Setup Runtime configurable options */ - if (is_qla8022(ha)) { - ha->isp_ops = &qla4_8xxx_isp_ops; - rwlock_init(&ha->hw_lock); - ha->qdr_sn_window = -1; - ha->ddr_mn_window = -1; - ha->curr_window = 255; - ha->func_num = PCI_FUNC(ha->pdev->devfn); - nx_legacy_intr = &legacy_intr[ha->func_num]; - ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit; - ha->nx_legacy_intr.tgt_status_reg = - nx_legacy_intr->tgt_status_reg; - ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg; - ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; - } else { - ha->isp_ops = &qla4xxx_isp_ops; - } - - /* Set EEH reset type to fundamental if required by hba */ - if (is_qla8022(ha)) - pdev->needs_freset = 1; - - /* Configure PCI I/O space. */ - ret = ha->isp_ops->iospace_config(ha); - if (ret) - goto probe_failed_ioconfig; - - ql4_printk(KERN_INFO, ha, "Found an ISP%04x, irq %d, iobase 0x%p\n", - pdev->device, pdev->irq, ha->reg); - - qla4xxx_config_dma_addressing(ha); - - /* Initialize lists and spinlocks. */ - INIT_LIST_HEAD(&ha->free_srb_q); - - mutex_init(&ha->mbox_sem); - mutex_init(&ha->chap_sem); - init_completion(&ha->mbx_intr_comp); - init_completion(&ha->disable_acb_comp); - - spin_lock_init(&ha->hardware_lock); - - /* Initialize work list */ - INIT_LIST_HEAD(&ha->work_list); - - /* Allocate dma buffers */ - if (qla4xxx_mem_alloc(ha)) { - ql4_printk(KERN_WARNING, ha, - "[ERROR] Failed to allocate memory for adapter\n"); - - ret = -ENOMEM; - goto probe_failed; - } - - host->cmd_per_lun = 3; - host->max_channel = 0; - host->max_lun = MAX_LUNS - 1; - host->max_id = MAX_TARGETS; - host->max_cmd_len = IOCB_MAX_CDB_LEN; - host->can_queue = MAX_SRBS ; - host->transportt = qla4xxx_scsi_transport; - - ret = scsi_init_shared_tag_map(host, MAX_SRBS); - if (ret) { - ql4_printk(KERN_WARNING, ha, - "%s: scsi_init_shared_tag_map failed\n", __func__); - goto probe_failed; - } - - pci_set_drvdata(pdev, ha); - - ret = scsi_add_host(host, &pdev->dev); - if (ret) - goto probe_failed; - - if (is_qla8022(ha)) - (void) qla4_8xxx_get_flash_info(ha); - - /* - * Initialize the Host adapter request/response queues and - * firmware - * NOTE: interrupts enabled upon successful completion - */ - status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); - while ((!test_bit(AF_ONLINE, &ha->flags)) && - init_retry_count++ < MAX_INIT_RETRIES) { - - if (is_qla8022(ha)) { - qla4_8xxx_idc_lock(ha); - dev_state = qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE); - qla4_8xxx_idc_unlock(ha); - if (dev_state == QLA82XX_DEV_FAILED) { - ql4_printk(KERN_WARNING, ha, "%s: don't retry " - "initialize adapter. H/W is in failed state\n", - __func__); - break; - } - } - DEBUG2(printk("scsi: %s: retrying adapter initialization " - "(%d)\n", __func__, init_retry_count)); - - if (ha->isp_ops->reset_chip(ha) == QLA_ERROR) - continue; - - status = qla4xxx_initialize_adapter(ha, INIT_ADAPTER); - } - - if (!test_bit(AF_ONLINE, &ha->flags)) { - ql4_printk(KERN_WARNING, ha, "Failed to initialize adapter\n"); - - if (is_qla8022(ha) && ql4xdontresethba) { - /* Put the device in failed state. */ - DEBUG2(printk(KERN_ERR "HW STATE: FAILED\n")); - qla4_8xxx_idc_lock(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - qla4_8xxx_idc_unlock(ha); - } - ret = -ENODEV; - goto remove_host; - } - - /* Startup the kernel thread for this host adapter. */ - DEBUG2(printk("scsi: %s: Starting kernel thread for " - "qla4xxx_dpc\n", __func__)); - sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no); - ha->dpc_thread = create_singlethread_workqueue(buf); - if (!ha->dpc_thread) { - ql4_printk(KERN_WARNING, ha, "Unable to start DPC thread!\n"); - ret = -ENODEV; - goto remove_host; - } - INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc); - - sprintf(buf, "qla4xxx_%lu_task", ha->host_no); - ha->task_wq = alloc_workqueue(buf, WQ_MEM_RECLAIM, 1); - if (!ha->task_wq) { - ql4_printk(KERN_WARNING, ha, "Unable to start task thread!\n"); - ret = -ENODEV; - goto remove_host; - } - - /* For ISP-82XX, request_irqs is called in qla4_8xxx_load_risc - * (which is called indirectly by qla4xxx_initialize_adapter), - * so that irqs will be registered after crbinit but before - * mbx_intr_enable. - */ - if (!is_qla8022(ha)) { - ret = qla4xxx_request_irqs(ha); - if (ret) { - ql4_printk(KERN_WARNING, ha, "Failed to reserve " - "interrupt %d already in use.\n", pdev->irq); - goto remove_host; - } - } - - pci_save_state(ha->pdev); - ha->isp_ops->enable_intrs(ha); - - /* Start timer thread. */ - qla4xxx_start_timer(ha, qla4xxx_timer, 1); - - set_bit(AF_INIT_DONE, &ha->flags); - - printk(KERN_INFO - " QLogic iSCSI HBA Driver version: %s\n" - " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n", - qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev), - ha->host_no, ha->firmware_version[0], ha->firmware_version[1], - ha->patch_number, ha->build_number); - - if (qla4xxx_setup_boot_info(ha)) - ql4_printk(KERN_ERR, ha, - "%s: No iSCSI boot target configured\n", __func__); - - /* Perform the build ddb list and login to each */ - qla4xxx_build_ddb_list(ha, INIT_ADAPTER); - iscsi_host_for_each_session(ha->host, qla4xxx_login_flash_ddb); - - qla4xxx_create_chap_list(ha); - - qla4xxx_create_ifaces(ha); - return 0; - -remove_host: - scsi_remove_host(ha->host); - -probe_failed: - qla4xxx_free_adapter(ha); - -probe_failed_ioconfig: - pci_disable_pcie_error_reporting(pdev); - scsi_host_put(ha->host); - -probe_disable_device: - pci_disable_device(pdev); - - return ret; -} - -/** - * qla4xxx_prevent_other_port_reinit - prevent other port from re-initialize - * @ha: pointer to adapter structure - * - * Mark the other ISP-4xxx port to indicate that the driver is being removed, - * so that the other port will not re-initialize while in the process of - * removing the ha due to driver unload or hba hotplug. - **/ -static void qla4xxx_prevent_other_port_reinit(struct scsi_qla_host *ha) -{ - struct scsi_qla_host *other_ha = NULL; - struct pci_dev *other_pdev = NULL; - int fn = ISP4XXX_PCI_FN_2; - - /*iscsi function numbers for ISP4xxx is 1 and 3*/ - if (PCI_FUNC(ha->pdev->devfn) & BIT_1) - fn = ISP4XXX_PCI_FN_1; - - other_pdev = - pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), - ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), - fn)); - - /* Get other_ha if other_pdev is valid and state is enable*/ - if (other_pdev) { - if (atomic_read(&other_pdev->enable_cnt)) { - other_ha = pci_get_drvdata(other_pdev); - if (other_ha) { - set_bit(AF_HA_REMOVAL, &other_ha->flags); - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: " - "Prevent %s reinit\n", __func__, - dev_name(&other_ha->pdev->dev))); - } - } - pci_dev_put(other_pdev); - } -} - -static void qla4xxx_destroy_fw_ddb_session(struct scsi_qla_host *ha) -{ - struct ddb_entry *ddb_entry; - int options; - int idx; - - for (idx = 0; idx < MAX_DDB_ENTRIES; idx++) { - - ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, idx); - if ((ddb_entry != NULL) && - (ddb_entry->ddb_type == FLASH_DDB)) { - - options = LOGOUT_OPTION_CLOSE_SESSION; - if (qla4xxx_session_logout_ddb(ha, ddb_entry, options) - == QLA_ERROR) - ql4_printk(KERN_ERR, ha, "%s: Logout failed\n", - __func__); - - qla4xxx_clear_ddb_entry(ha, ddb_entry->fw_ddb_index); - /* - * we have decremented the reference count of the driver - * when we setup the session to have the driver unload - * to be seamless without actually destroying the - * session - **/ - try_module_get(qla4xxx_iscsi_transport.owner); - iscsi_destroy_endpoint(ddb_entry->conn->ep); - qla4xxx_free_ddb(ha, ddb_entry); - iscsi_session_teardown(ddb_entry->sess); - } - } -} -/** - * qla4xxx_remove_adapter - calback function to remove adapter. - * @pci_dev: PCI device pointer - **/ -static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev) -{ - struct scsi_qla_host *ha; - - ha = pci_get_drvdata(pdev); - - if (!is_qla8022(ha)) - qla4xxx_prevent_other_port_reinit(ha); - - /* destroy iface from sysfs */ - qla4xxx_destroy_ifaces(ha); - - if ((!ql4xdisablesysfsboot) && ha->boot_kset) - iscsi_boot_destroy_kset(ha->boot_kset); - - qla4xxx_destroy_fw_ddb_session(ha); - - scsi_remove_host(ha->host); - - qla4xxx_free_adapter(ha); - - scsi_host_put(ha->host); - - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - pci_set_drvdata(pdev, NULL); -} - -/** - * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method. - * @ha: HA context - * - * At exit, the @ha's flags.enable_64bit_addressing set to indicated - * supported addressing method. - */ -static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha) -{ - int retval; - - /* Update our PCI device dma_mask for full 64 bit mask */ - if (pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(64)) == 0) { - if (pci_set_consistent_dma_mask(ha->pdev, DMA_BIT_MASK(64))) { - dev_dbg(&ha->pdev->dev, - "Failed to set 64 bit PCI consistent mask; " - "using 32 bit.\n"); - retval = pci_set_consistent_dma_mask(ha->pdev, - DMA_BIT_MASK(32)); - } - } else - retval = pci_set_dma_mask(ha->pdev, DMA_BIT_MASK(32)); -} - -static int qla4xxx_slave_alloc(struct scsi_device *sdev) -{ - struct iscsi_cls_session *cls_sess; - struct iscsi_session *sess; - struct ddb_entry *ddb; - int queue_depth = QL4_DEF_QDEPTH; - - cls_sess = starget_to_session(sdev->sdev_target); - sess = cls_sess->dd_data; - ddb = sess->dd_data; - - sdev->hostdata = ddb; - sdev->tagged_supported = 1; - - if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU) - queue_depth = ql4xmaxqdepth; - - scsi_activate_tcq(sdev, queue_depth); - return 0; -} - -static int qla4xxx_slave_configure(struct scsi_device *sdev) -{ - sdev->tagged_supported = 1; - return 0; -} - -static void qla4xxx_slave_destroy(struct scsi_device *sdev) -{ - scsi_deactivate_tcq(sdev, 1); -} - -/** - * qla4xxx_del_from_active_array - returns an active srb - * @ha: Pointer to host adapter structure. - * @index: index into the active_array - * - * This routine removes and returns the srb at the specified index - **/ -struct srb *qla4xxx_del_from_active_array(struct scsi_qla_host *ha, - uint32_t index) -{ - struct srb *srb = NULL; - struct scsi_cmnd *cmd = NULL; - - cmd = scsi_host_find_tag(ha->host, index); - if (!cmd) - return srb; - - srb = (struct srb *)CMD_SP(cmd); - if (!srb) - return srb; - - /* update counters */ - if (srb->flags & SRB_DMA_VALID) { - ha->req_q_count += srb->iocb_cnt; - ha->iocb_cnt -= srb->iocb_cnt; - if (srb->cmd) - srb->cmd->host_scribble = - (unsigned char *)(unsigned long) MAX_SRBS; - } - return srb; -} - -/** - * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware - * @ha: Pointer to host adapter structure. - * @cmd: Scsi Command to wait on. - * - * This routine waits for the command to be returned by the Firmware - * for some max time. - **/ -static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha, - struct scsi_cmnd *cmd) -{ - int done = 0; - struct srb *rp; - uint32_t max_wait_time = EH_WAIT_CMD_TOV; - int ret = SUCCESS; - - /* Dont wait on command if PCI error is being handled - * by PCI AER driver - */ - if (unlikely(pci_channel_offline(ha->pdev)) || - (test_bit(AF_EEH_BUSY, &ha->flags))) { - ql4_printk(KERN_WARNING, ha, "scsi%ld: Return from %s\n", - ha->host_no, __func__); - return ret; - } - - do { - /* Checking to see if its returned to OS */ - rp = (struct srb *) CMD_SP(cmd); - if (rp == NULL) { - done++; - break; - } - - msleep(2000); - } while (max_wait_time--); - - return done; -} - -/** - * qla4xxx_wait_for_hba_online - waits for HBA to come online - * @ha: Pointer to host adapter structure - **/ -static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha) -{ - unsigned long wait_online; - - wait_online = jiffies + (HBA_ONLINE_TOV * HZ); - while (time_before(jiffies, wait_online)) { - - if (adapter_up(ha)) - return QLA_SUCCESS; - - msleep(2000); - } - - return QLA_ERROR; -} - -/** - * qla4xxx_eh_wait_for_commands - wait for active cmds to finish. - * @ha: pointer to HBA - * @t: target id - * @l: lun id - * - * This function waits for all outstanding commands to a lun to complete. It - * returns 0 if all pending commands are returned and 1 otherwise. - **/ -static int qla4xxx_eh_wait_for_commands(struct scsi_qla_host *ha, - struct scsi_target *stgt, - struct scsi_device *sdev) -{ - int cnt; - int status = 0; - struct scsi_cmnd *cmd; - - /* - * Waiting for all commands for the designated target or dev - * in the active array - */ - for (cnt = 0; cnt < ha->host->can_queue; cnt++) { - cmd = scsi_host_find_tag(ha->host, cnt); - if (cmd && stgt == scsi_target(cmd->device) && - (!sdev || sdev == cmd->device)) { - if (!qla4xxx_eh_wait_on_command(ha, cmd)) { - status++; - break; - } - } - } - return status; -} - -/** - * qla4xxx_eh_abort - callback for abort task. - * @cmd: Pointer to Linux's SCSI command structure - * - * This routine is called by the Linux OS to abort the specified - * command. - **/ -static int qla4xxx_eh_abort(struct scsi_cmnd *cmd) -{ - struct scsi_qla_host *ha = to_qla_host(cmd->device->host); - unsigned int id = cmd->device->id; - unsigned int lun = cmd->device->lun; - unsigned long flags; - struct srb *srb = NULL; - int ret = SUCCESS; - int wait = 0; - - ql4_printk(KERN_INFO, ha, - "scsi%ld:%d:%d: Abort command issued cmd=%p\n", - ha->host_no, id, lun, cmd); - - spin_lock_irqsave(&ha->hardware_lock, flags); - srb = (struct srb *) CMD_SP(cmd); - if (!srb) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); - return SUCCESS; - } - kref_get(&srb->srb_ref); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - - if (qla4xxx_abort_task(ha, srb) != QLA_SUCCESS) { - DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx failed.\n", - ha->host_no, id, lun)); - ret = FAILED; - } else { - DEBUG3(printk("scsi%ld:%d:%d: Abort_task mbx success.\n", - ha->host_no, id, lun)); - wait = 1; - } - - kref_put(&srb->srb_ref, qla4xxx_srb_compl); - - /* Wait for command to complete */ - if (wait) { - if (!qla4xxx_eh_wait_on_command(ha, cmd)) { - DEBUG2(printk("scsi%ld:%d:%d: Abort handler timed out\n", - ha->host_no, id, lun)); - ret = FAILED; - } - } - - ql4_printk(KERN_INFO, ha, - "scsi%ld:%d:%d: Abort command - %s\n", - ha->host_no, id, lun, (ret == SUCCESS) ? "succeeded" : "failed"); - - return ret; -} - -/** - * qla4xxx_eh_device_reset - callback for target reset. - * @cmd: Pointer to Linux's SCSI command structure - * - * This routine is called by the Linux OS to reset all luns on the - * specified target. - **/ -static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd) -{ - struct scsi_qla_host *ha = to_qla_host(cmd->device->host); - struct ddb_entry *ddb_entry = cmd->device->hostdata; - int ret = FAILED, stat; - - if (!ddb_entry) - return ret; - - ret = iscsi_block_scsi_eh(cmd); - if (ret) - return ret; - ret = FAILED; - - ql4_printk(KERN_INFO, ha, - "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no, - cmd->device->channel, cmd->device->id, cmd->device->lun); - - DEBUG2(printk(KERN_INFO - "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x," - "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no, - cmd, jiffies, cmd->request->timeout / HZ, - ha->dpc_flags, cmd->result, cmd->allowed)); - - /* FIXME: wait for hba to go online */ - stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun); - if (stat != QLA_SUCCESS) { - ql4_printk(KERN_INFO, ha, "DEVICE RESET FAILED. %d\n", stat); - goto eh_dev_reset_done; - } - - if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), - cmd->device)) { - ql4_printk(KERN_INFO, ha, - "DEVICE RESET FAILED - waiting for " - "commands.\n"); - goto eh_dev_reset_done; - } - - /* Send marker. */ - if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, - MM_LUN_RESET) != QLA_SUCCESS) - goto eh_dev_reset_done; - - ql4_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n", - ha->host_no, cmd->device->channel, cmd->device->id, - cmd->device->lun); - - ret = SUCCESS; - -eh_dev_reset_done: - - return ret; -} - -/** - * qla4xxx_eh_target_reset - callback for target reset. - * @cmd: Pointer to Linux's SCSI command structure - * - * This routine is called by the Linux OS to reset the target. - **/ -static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd) -{ - struct scsi_qla_host *ha = to_qla_host(cmd->device->host); - struct ddb_entry *ddb_entry = cmd->device->hostdata; - int stat, ret; - - if (!ddb_entry) - return FAILED; - - ret = iscsi_block_scsi_eh(cmd); - if (ret) - return ret; - - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET RESET ISSUED.\n"); - - DEBUG2(printk(KERN_INFO - "scsi%ld: TARGET_DEVICE_RESET cmd=%p jiffies = 0x%lx, " - "to=%x,dpc_flags=%lx, status=%x allowed=%d\n", - ha->host_no, cmd, jiffies, cmd->request->timeout / HZ, - ha->dpc_flags, cmd->result, cmd->allowed)); - - stat = qla4xxx_reset_target(ha, ddb_entry); - if (stat != QLA_SUCCESS) { - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET RESET FAILED.\n"); - return FAILED; - } - - if (qla4xxx_eh_wait_for_commands(ha, scsi_target(cmd->device), - NULL)) { - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET DEVICE RESET FAILED - " - "waiting for commands.\n"); - return FAILED; - } - - /* Send marker. */ - if (qla4xxx_send_marker_iocb(ha, ddb_entry, cmd->device->lun, - MM_TGT_WARM_RESET) != QLA_SUCCESS) { - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET DEVICE RESET FAILED - " - "marker iocb failed.\n"); - return FAILED; - } - - starget_printk(KERN_INFO, scsi_target(cmd->device), - "WARM TARGET RESET SUCCEEDED.\n"); - return SUCCESS; -} - -/** - * qla4xxx_is_eh_active - check if error handler is running - * @shost: Pointer to SCSI Host struct - * - * This routine finds that if reset host is called in EH - * scenario or from some application like sg_reset - **/ -static int qla4xxx_is_eh_active(struct Scsi_Host *shost) -{ - if (shost->shost_state == SHOST_RECOVERY) - return 1; - return 0; -} - -/** - * qla4xxx_eh_host_reset - kernel callback - * @cmd: Pointer to Linux's SCSI command structure - * - * This routine is invoked by the Linux kernel to perform fatal error - * recovery on the specified adapter. - **/ -static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd) -{ - int return_status = FAILED; - struct scsi_qla_host *ha; - - ha = to_qla_host(cmd->device->host); - - if (ql4xdontresethba) { - DEBUG2(printk("scsi%ld: %s: Don't Reset HBA\n", - ha->host_no, __func__)); - - /* Clear outstanding srb in queues */ - if (qla4xxx_is_eh_active(cmd->device->host)) - qla4xxx_abort_active_cmds(ha, DID_ABORT << 16); - - return FAILED; - } - - ql4_printk(KERN_INFO, ha, - "scsi(%ld:%d:%d:%d): HOST RESET ISSUED.\n", ha->host_no, - cmd->device->channel, cmd->device->id, cmd->device->lun); - - if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) { - DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter " - "DEAD.\n", ha->host_no, cmd->device->channel, - __func__)); - - return FAILED; - } - - if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { - if (is_qla8022(ha)) - set_bit(DPC_RESET_HA_FW_CONTEXT, &ha->dpc_flags); - else - set_bit(DPC_RESET_HA, &ha->dpc_flags); - } - - if (qla4xxx_recover_adapter(ha) == QLA_SUCCESS) - return_status = SUCCESS; - - ql4_printk(KERN_INFO, ha, "HOST RESET %s.\n", - return_status == FAILED ? "FAILED" : "SUCCEEDED"); - - return return_status; -} - -static int qla4xxx_context_reset(struct scsi_qla_host *ha) -{ - uint32_t mbox_cmd[MBOX_REG_COUNT]; - uint32_t mbox_sts[MBOX_REG_COUNT]; - struct addr_ctrl_blk_def *acb = NULL; - uint32_t acb_len = sizeof(struct addr_ctrl_blk_def); - int rval = QLA_SUCCESS; - dma_addr_t acb_dma; - - acb = dma_alloc_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk_def), - &acb_dma, GFP_KERNEL); - if (!acb) { - ql4_printk(KERN_ERR, ha, "%s: Unable to alloc acb\n", - __func__); - rval = -ENOMEM; - goto exit_port_reset; - } - - memset(acb, 0, acb_len); - - rval = qla4xxx_get_acb(ha, acb_dma, PRIMARI_ACB, acb_len); - if (rval != QLA_SUCCESS) { - rval = -EIO; - goto exit_free_acb; - } - - rval = qla4xxx_disable_acb(ha); - if (rval != QLA_SUCCESS) { - rval = -EIO; - goto exit_free_acb; - } - - wait_for_completion_timeout(&ha->disable_acb_comp, - DISABLE_ACB_TOV * HZ); - - rval = qla4xxx_set_acb(ha, &mbox_cmd[0], &mbox_sts[0], acb_dma); - if (rval != QLA_SUCCESS) { - rval = -EIO; - goto exit_free_acb; - } - -exit_free_acb: - dma_free_coherent(&ha->pdev->dev, sizeof(struct addr_ctrl_blk_def), - acb, acb_dma); -exit_port_reset: - DEBUG2(ql4_printk(KERN_INFO, ha, "%s %s\n", __func__, - rval == QLA_SUCCESS ? "SUCCEEDED" : "FAILED")); - return rval; -} - -static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type) -{ - struct scsi_qla_host *ha = to_qla_host(shost); - int rval = QLA_SUCCESS; - - if (ql4xdontresethba) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Don't Reset HBA\n", - __func__)); - rval = -EPERM; - goto exit_host_reset; - } - - rval = qla4xxx_wait_for_hba_online(ha); - if (rval != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: Unable to reset host " - "adapter\n", __func__)); - rval = -EIO; - goto exit_host_reset; - } - - if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) - goto recover_adapter; - - switch (reset_type) { - case SCSI_ADAPTER_RESET: - set_bit(DPC_RESET_HA, &ha->dpc_flags); - break; - case SCSI_FIRMWARE_RESET: - if (!test_bit(DPC_RESET_HA, &ha->dpc_flags)) { - if (is_qla8022(ha)) - /* set firmware context reset */ - set_bit(DPC_RESET_HA_FW_CONTEXT, - &ha->dpc_flags); - else { - rval = qla4xxx_context_reset(ha); - goto exit_host_reset; - } - } - break; - } - -recover_adapter: - rval = qla4xxx_recover_adapter(ha); - if (rval != QLA_SUCCESS) { - DEBUG2(ql4_printk(KERN_INFO, ha, "%s: recover adapter fail\n", - __func__)); - rval = -EIO; - } - -exit_host_reset: - return rval; -} - -/* PCI AER driver recovers from all correctable errors w/o - * driver intervention. For uncorrectable errors PCI AER - * driver calls the following device driver's callbacks - * - * - Fatal Errors - link_reset - * - Non-Fatal Errors - driver's pci_error_detected() which - * returns CAN_RECOVER, NEED_RESET or DISCONNECT. - * - * PCI AER driver calls - * CAN_RECOVER - driver's pci_mmio_enabled(), mmio_enabled - * returns RECOVERED or NEED_RESET if fw_hung - * NEED_RESET - driver's slot_reset() - * DISCONNECT - device is dead & cannot recover - * RECOVERED - driver's pci_resume() - */ -static pci_ers_result_t -qla4xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) -{ - struct scsi_qla_host *ha = pci_get_drvdata(pdev); - - ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: error detected:state %x\n", - ha->host_no, __func__, state); - - if (!is_aer_supported(ha)) - return PCI_ERS_RESULT_NONE; - - switch (state) { - case pci_channel_io_normal: - clear_bit(AF_EEH_BUSY, &ha->flags); - return PCI_ERS_RESULT_CAN_RECOVER; - case pci_channel_io_frozen: - set_bit(AF_EEH_BUSY, &ha->flags); - qla4xxx_mailbox_premature_completion(ha); - qla4xxx_free_irqs(ha); - pci_disable_device(pdev); - /* Return back all IOs */ - qla4xxx_abort_active_cmds(ha, DID_RESET << 16); - return PCI_ERS_RESULT_NEED_RESET; - case pci_channel_io_perm_failure: - set_bit(AF_EEH_BUSY, &ha->flags); - set_bit(AF_PCI_CHANNEL_IO_PERM_FAILURE, &ha->flags); - qla4xxx_abort_active_cmds(ha, DID_NO_CONNECT << 16); - return PCI_ERS_RESULT_DISCONNECT; - } - return PCI_ERS_RESULT_NEED_RESET; -} - -/** - * qla4xxx_pci_mmio_enabled() gets called if - * qla4xxx_pci_error_detected() returns PCI_ERS_RESULT_CAN_RECOVER - * and read/write to the device still works. - **/ -static pci_ers_result_t -qla4xxx_pci_mmio_enabled(struct pci_dev *pdev) -{ - struct scsi_qla_host *ha = pci_get_drvdata(pdev); - - if (!is_aer_supported(ha)) - return PCI_ERS_RESULT_NONE; - - return PCI_ERS_RESULT_RECOVERED; -} - -static uint32_t qla4_8xxx_error_recovery(struct scsi_qla_host *ha) -{ - uint32_t rval = QLA_ERROR; - uint32_t ret = 0; - int fn; - struct pci_dev *other_pdev = NULL; - - ql4_printk(KERN_WARNING, ha, "scsi%ld: In %s\n", ha->host_no, __func__); - - set_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); - - if (test_bit(AF_ONLINE, &ha->flags)) { - clear_bit(AF_ONLINE, &ha->flags); - clear_bit(AF_LINK_UP, &ha->flags); - iscsi_host_for_each_session(ha->host, qla4xxx_fail_session); - qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS); - } - - fn = PCI_FUNC(ha->pdev->devfn); - while (fn > 0) { - fn--; - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Finding PCI device at " - "func %x\n", ha->host_no, __func__, fn); - /* Get the pci device given the domain, bus, - * slot/function number */ - other_pdev = - pci_get_domain_bus_and_slot(pci_domain_nr(ha->pdev->bus), - ha->pdev->bus->number, PCI_DEVFN(PCI_SLOT(ha->pdev->devfn), - fn)); - - if (!other_pdev) - continue; - - if (atomic_read(&other_pdev->enable_cnt)) { - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: Found PCI " - "func in enabled state%x\n", ha->host_no, - __func__, fn); - pci_dev_put(other_pdev); - break; - } - pci_dev_put(other_pdev); - } - - /* The first function on the card, the reset owner will - * start & initialize the firmware. The other functions - * on the card will reset the firmware context - */ - if (!fn) { - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn being reset " - "0x%x is the owner\n", ha->host_no, __func__, - ha->pdev->devfn); - - qla4_8xxx_idc_lock(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_COLD); - - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION, - QLA82XX_IDC_VERSION); - - qla4_8xxx_idc_unlock(ha); - clear_bit(AF_FW_RECOVERY, &ha->flags); - rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); - qla4_8xxx_idc_lock(ha); - - if (rval != QLA_SUCCESS) { - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " - "FAILED\n", ha->host_no, __func__); - qla4_8xxx_clear_drv_active(ha); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_FAILED); - } else { - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: HW State: " - "READY\n", ha->host_no, __func__); - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DEV_STATE, - QLA82XX_DEV_READY); - /* Clear driver state register */ - qla4_8xxx_wr_32(ha, QLA82XX_CRB_DRV_STATE, 0); - qla4_8xxx_set_drv_active(ha); - ret = qla4xxx_request_irqs(ha); - if (ret) { - ql4_printk(KERN_WARNING, ha, "Failed to " - "reserve interrupt %d already in use.\n", - ha->pdev->irq); - rval = QLA_ERROR; - } else { - ha->isp_ops->enable_intrs(ha); - rval = QLA_SUCCESS; - } - } - qla4_8xxx_idc_unlock(ha); - } else { - ql4_printk(KERN_INFO, ha, "scsi%ld: %s: devfn 0x%x is not " - "the reset owner\n", ha->host_no, __func__, - ha->pdev->devfn); - if ((qla4_8xxx_rd_32(ha, QLA82XX_CRB_DEV_STATE) == - QLA82XX_DEV_READY)) { - clear_bit(AF_FW_RECOVERY, &ha->flags); - rval = qla4xxx_initialize_adapter(ha, RESET_ADAPTER); - if (rval == QLA_SUCCESS) { - ret = qla4xxx_request_irqs(ha); - if (ret) { - ql4_printk(KERN_WARNING, ha, "Failed to" - " reserve interrupt %d already in" - " use.\n", ha->pdev->irq); - rval = QLA_ERROR; - } else { - ha->isp_ops->enable_intrs(ha); - rval = QLA_SUCCESS; - } - } - qla4_8xxx_idc_lock(ha); - qla4_8xxx_set_drv_active(ha); - qla4_8xxx_idc_unlock(ha); - } - } - clear_bit(DPC_RESET_ACTIVE, &ha->dpc_flags); - return rval; -} - -static pci_ers_result_t -qla4xxx_pci_slot_reset(struct pci_dev *pdev) -{ - pci_ers_result_t ret = PCI_ERS_RESULT_DISCONNECT; - struct scsi_qla_host *ha = pci_get_drvdata(pdev); - int rc; - - ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: slot_reset\n", - ha->host_no, __func__); - - if (!is_aer_supported(ha)) - return PCI_ERS_RESULT_NONE; - - /* Restore the saved state of PCIe device - - * BAR registers, PCI Config space, PCIX, MSI, - * IOV states - */ - pci_restore_state(pdev); - - /* pci_restore_state() clears the saved_state flag of the device - * save restored state which resets saved_state flag - */ - pci_save_state(pdev); - - /* Initialize device or resume if in suspended state */ - rc = pci_enable_device(pdev); - if (rc) { - ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Can't re-enable " - "device after reset\n", ha->host_no, __func__); - goto exit_slot_reset; - } - - ha->isp_ops->disable_intrs(ha); - - if (is_qla8022(ha)) { - if (qla4_8xxx_error_recovery(ha) == QLA_SUCCESS) { - ret = PCI_ERS_RESULT_RECOVERED; - goto exit_slot_reset; - } else - goto exit_slot_reset; - } - -exit_slot_reset: - ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: Return=%x\n" - "device after reset\n", ha->host_no, __func__, ret); - return ret; -} - -static void -qla4xxx_pci_resume(struct pci_dev *pdev) -{ - struct scsi_qla_host *ha = pci_get_drvdata(pdev); - int ret; - - ql4_printk(KERN_WARNING, ha, "scsi%ld: %s: pci_resume\n", - ha->host_no, __func__); - - ret = qla4xxx_wait_for_hba_online(ha); - if (ret != QLA_SUCCESS) { - ql4_printk(KERN_ERR, ha, "scsi%ld: %s: the device failed to " - "resume I/O from slot/link_reset\n", ha->host_no, - __func__); - } - - pci_cleanup_aer_uncorrect_error_status(pdev); - clear_bit(AF_EEH_BUSY, &ha->flags); -} - -static struct pci_error_handlers qla4xxx_err_handler = { - .error_detected = qla4xxx_pci_error_detected, - .mmio_enabled = qla4xxx_pci_mmio_enabled, - .slot_reset = qla4xxx_pci_slot_reset, - .resume = qla4xxx_pci_resume, -}; - -static struct pci_device_id qla4xxx_pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_QLOGIC, - .device = PCI_DEVICE_ID_QLOGIC_ISP4010, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_QLOGIC, - .device = PCI_DEVICE_ID_QLOGIC_ISP4022, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_QLOGIC, - .device = PCI_DEVICE_ID_QLOGIC_ISP4032, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - { - .vendor = PCI_VENDOR_ID_QLOGIC, - .device = PCI_DEVICE_ID_QLOGIC_ISP8022, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - {0, 0}, -}; -MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl); - -static struct pci_driver qla4xxx_pci_driver = { - .name = DRIVER_NAME, - .id_table = qla4xxx_pci_tbl, - .probe = qla4xxx_probe_adapter, - .remove = qla4xxx_remove_adapter, - .err_handler = &qla4xxx_err_handler, -}; - -static int __init qla4xxx_module_init(void) -{ - int ret; - - /* Allocate cache for SRBs. */ - srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (srb_cachep == NULL) { - printk(KERN_ERR - "%s: Unable to allocate SRB cache..." - "Failing load!\n", DRIVER_NAME); - ret = -ENOMEM; - goto no_srp_cache; - } - - /* Derive version string. */ - strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION); - if (ql4xextended_error_logging) - strcat(qla4xxx_version_str, "-debug"); - - qla4xxx_scsi_transport = - iscsi_register_transport(&qla4xxx_iscsi_transport); - if (!qla4xxx_scsi_transport){ - ret = -ENODEV; - goto release_srb_cache; - } - - ret = pci_register_driver(&qla4xxx_pci_driver); - if (ret) - goto unregister_transport; - - printk(KERN_INFO "QLogic iSCSI HBA Driver\n"); - return 0; - -unregister_transport: - iscsi_unregister_transport(&qla4xxx_iscsi_transport); -release_srb_cache: - kmem_cache_destroy(srb_cachep); -no_srp_cache: - return ret; -} - -static void __exit qla4xxx_module_exit(void) -{ - pci_unregister_driver(&qla4xxx_pci_driver); - iscsi_unregister_transport(&qla4xxx_iscsi_transport); - kmem_cache_destroy(srb_cachep); -} - -module_init(qla4xxx_module_init); -module_exit(qla4xxx_module_exit); - -MODULE_AUTHOR("QLogic Corporation"); -MODULE_DESCRIPTION("QLogic iSCSI HBA Driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(QLA4XXX_DRIVER_VERSION); diff --git a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_version.h b/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_version.h deleted file mode 100644 index 97b30c10..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qla4xxx/ql4_version.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * QLogic iSCSI HBA Driver - * Copyright (c) 2003-2010 QLogic Corporation - * - * See LICENSE.qla4xxx for copyright and licensing details. - */ - -#define QLA4XXX_DRIVER_VERSION "5.02.00-k16" diff --git a/ANDROID_3.4.5/drivers/scsi/qlogicfas.c b/ANDROID_3.4.5/drivers/scsi/qlogicfas.c deleted file mode 100644 index 1e874f1f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qlogicfas.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Qlogic FAS408 ISA card driver - * - * Copyright 1994, Tom Zerucha. - * tz@execpc.com - * - * Redistributable under terms of the GNU General Public License - * - * For the avoidance of doubt the "preferred form" of this code is one which - * is in an open non patent encumbered format. Where cryptographic key signing - * forms part of the process of creating an executable the information - * including keys needed to generate an equivalently functional executable - * are deemed to be part of the source code. - * - * Check qlogicfas408.c for more credits and info. - */ - -#include -#include /* to get disk capacity */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "scsi.h" -#include -#include "qlogicfas408.h" - -/* Set the following to 2 to use normal interrupt (active high/totempole- - * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open - * drain - */ -#define INT_TYPE 2 - -static char qlogicfas_name[] = "qlogicfas"; - -/* - * Look for qlogic card and init if found - */ - -static struct Scsi_Host *__qlogicfas_detect(struct scsi_host_template *host, - int qbase, - int qlirq) -{ - int qltyp; /* type of chip */ - int qinitid; - struct Scsi_Host *hreg; /* registered host structure */ - struct qlogicfas408_priv *priv; - - /* Qlogic Cards only exist at 0x230 or 0x330 (the chip itself - * decodes the address - I check 230 first since MIDI cards are - * typically at 0x330 - * - * Theoretically, two Qlogic cards can coexist in the same system. - * This should work by simply using this as a loadable module for - * the second card, but I haven't tested this. - */ - - if (!qbase || qlirq == -1) - goto err; - - if (!request_region(qbase, 0x10, qlogicfas_name)) { - printk(KERN_INFO "%s: address %#x is busy\n", qlogicfas_name, - qbase); - goto err; - } - - if (!qlogicfas408_detect(qbase, INT_TYPE)) { - printk(KERN_WARNING "%s: probe failed for %#x\n", - qlogicfas_name, - qbase); - goto err_release_mem; - } - - printk(KERN_INFO "%s: Using preset base address of %03x," - " IRQ %d\n", qlogicfas_name, qbase, qlirq); - - qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE); - qinitid = host->this_id; - if (qinitid < 0) - qinitid = 7; /* if no ID, use 7 */ - - qlogicfas408_setup(qbase, qinitid, INT_TYPE); - - hreg = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv)); - if (!hreg) - goto err_release_mem; - priv = get_priv_by_host(hreg); - hreg->io_port = qbase; - hreg->n_io_port = 16; - hreg->dma_channel = -1; - if (qlirq != -1) - hreg->irq = qlirq; - priv->qbase = qbase; - priv->qlirq = qlirq; - priv->qinitid = qinitid; - priv->shost = hreg; - priv->int_type = INT_TYPE; - - sprintf(priv->qinfo, - "Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d", - qltyp, qbase, qlirq, QL_TURBO_PDMA); - host->name = qlogicfas_name; - - if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogicfas_name, hreg)) - goto free_scsi_host; - - if (scsi_add_host(hreg, NULL)) - goto free_interrupt; - - scsi_scan_host(hreg); - - return hreg; - -free_interrupt: - free_irq(qlirq, hreg); - -free_scsi_host: - scsi_host_put(hreg); - -err_release_mem: - release_region(qbase, 0x10); -err: - return NULL; -} - -#define MAX_QLOGICFAS 8 -static struct qlogicfas408_priv *cards; -static int iobase[MAX_QLOGICFAS]; -static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 }; -module_param_array(iobase, int, NULL, 0); -module_param_array(irq, int, NULL, 0); -MODULE_PARM_DESC(iobase, "I/O address"); -MODULE_PARM_DESC(irq, "IRQ"); - -static int __devinit qlogicfas_detect(struct scsi_host_template *sht) -{ - struct Scsi_Host *shost; - struct qlogicfas408_priv *priv; - int num; - - for (num = 0; num < MAX_QLOGICFAS; num++) { - shost = __qlogicfas_detect(sht, iobase[num], irq[num]); - if (shost == NULL) { - /* no more devices */ - break; - } - priv = get_priv_by_host(shost); - priv->next = cards; - cards = priv; - } - - return num; -} - -static int qlogicfas_release(struct Scsi_Host *shost) -{ - struct qlogicfas408_priv *priv = get_priv_by_host(shost); - - scsi_remove_host(shost); - if (shost->irq) { - qlogicfas408_disable_ints(priv); - free_irq(shost->irq, shost); - } - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_host_put(shost); - - return 0; -} - -/* - * The driver template is also needed for PCMCIA - */ -static struct scsi_host_template qlogicfas_driver_template = { - .module = THIS_MODULE, - .name = qlogicfas_name, - .proc_name = qlogicfas_name, - .info = qlogicfas408_info, - .queuecommand = qlogicfas408_queuecommand, - .eh_abort_handler = qlogicfas408_abort, - .eh_bus_reset_handler = qlogicfas408_bus_reset, - .bios_param = qlogicfas408_biosparam, - .can_queue = 1, - .this_id = -1, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = DISABLE_CLUSTERING, -}; - -static __init int qlogicfas_init(void) -{ - if (!qlogicfas_detect(&qlogicfas_driver_template)) { - /* no cards found */ - printk(KERN_INFO "%s: no cards were found, please specify " - "I/O address and IRQ using iobase= and irq= " - "options", qlogicfas_name); - return -ENODEV; - } - - return 0; -} - -static __exit void qlogicfas_exit(void) -{ - struct qlogicfas408_priv *priv; - - for (priv = cards; priv != NULL; priv = priv->next) - qlogicfas_release(priv->shost); -} - -MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); -MODULE_DESCRIPTION("Driver for the Qlogic FAS408 based ISA card"); -MODULE_LICENSE("GPL"); -module_init(qlogicfas_init); -module_exit(qlogicfas_exit); - diff --git a/ANDROID_3.4.5/drivers/scsi/qlogicfas408.c b/ANDROID_3.4.5/drivers/scsi/qlogicfas408.c deleted file mode 100644 index c3a9151c..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qlogicfas408.c +++ /dev/null @@ -1,617 +0,0 @@ -/*----------------------------------------------------------------*/ -/* - Qlogic linux driver - work in progress. No Warranty express or implied. - Use at your own risk. Support Tort Reform so you won't have to read all - these silly disclaimers. - - Copyright 1994, Tom Zerucha. - tz@execpc.com - - Additional Code, and much appreciated help by - Michael A. Griffith - grif@cs.ucr.edu - - Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA - help respectively, and for suffering through my foolishness during the - debugging process. - - Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994 - (you can reference it, but it is incomplete and inaccurate in places) - - Version 0.46 1/30/97 - kernel 1.2.0+ - - Functions as standalone, loadable, and PCMCIA driver, the latter from - Dave Hinds' PCMCIA package. - - Cleaned up 26/10/2002 by Alan Cox as part of the 2.5 - SCSI driver cleanup and audit. This driver still needs work on the - following - - Non terminating hardware waits - - Some layering violations with its pcmcia stub - - Redistributable under terms of the GNU General Public License - - For the avoidance of doubt the "preferred form" of this code is one which - is in an open non patent encumbered format. Where cryptographic key signing - forms part of the process of creating an executable the information - including keys needed to generate an equivalently functional executable - are deemed to be part of the source code. - -*/ - -#include -#include /* to get disk capacity */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "scsi.h" -#include -#include "qlogicfas408.h" - -/*----------------------------------------------------------------*/ -static int qlcfg5 = (XTALFREQ << 5); /* 15625/512 */ -static int qlcfg6 = SYNCXFRPD; -static int qlcfg7 = SYNCOFFST; -static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4); -static int qlcfg9 = ((XTALFREQ + 4) / 5); -static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4); - -/*----------------------------------------------------------------*/ - -/*----------------------------------------------------------------*/ -/* local functions */ -/*----------------------------------------------------------------*/ - -/* error recovery - reset everything */ - -static void ql_zap(struct qlogicfas408_priv *priv) -{ - int x; - int qbase = priv->qbase; - int int_type = priv->int_type; - - x = inb(qbase + 0xd); - REG0; - outb(3, qbase + 3); /* reset SCSI */ - outb(2, qbase + 3); /* reset chip */ - if (x & 0x80) - REG1; -} - -/* - * Do a pseudo-dma tranfer - */ - -static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int reqlen) -{ - int j; - int qbase = priv->qbase; - j = 0; - if (phase & 1) { /* in */ -#if QL_TURBO_PDMA - rtrc(4) - /* empty fifo in large chunks */ - if (reqlen >= 128 && (inb(qbase + 8) & 2)) { /* full */ - insl(qbase + 4, request, 32); - reqlen -= 128; - request += 128; - } - while (reqlen >= 84 && !(j & 0xc0)) /* 2/3 */ - if ((j = inb(qbase + 8)) & 4) - { - insl(qbase + 4, request, 21); - reqlen -= 84; - request += 84; - } - if (reqlen >= 44 && (inb(qbase + 8) & 8)) { /* 1/3 */ - insl(qbase + 4, request, 11); - reqlen -= 44; - request += 44; - } -#endif - /* until both empty and int (or until reclen is 0) */ - rtrc(7) - j = 0; - while (reqlen && !((j & 0x10) && (j & 0xc0))) - { - /* while bytes to receive and not empty */ - j &= 0xc0; - while (reqlen && !((j = inb(qbase + 8)) & 0x10)) - { - *request++ = inb(qbase + 4); - reqlen--; - } - if (j & 0x10) - j = inb(qbase + 8); - - } - } else { /* out */ -#if QL_TURBO_PDMA - rtrc(4) - if (reqlen >= 128 && inb(qbase + 8) & 0x10) { /* empty */ - outsl(qbase + 4, request, 32); - reqlen -= 128; - request += 128; - } - while (reqlen >= 84 && !(j & 0xc0)) /* 1/3 */ - if (!((j = inb(qbase + 8)) & 8)) { - outsl(qbase + 4, request, 21); - reqlen -= 84; - request += 84; - } - if (reqlen >= 40 && !(inb(qbase + 8) & 4)) { /* 2/3 */ - outsl(qbase + 4, request, 10); - reqlen -= 40; - request += 40; - } -#endif - /* until full and int (or until reclen is 0) */ - rtrc(7) - j = 0; - while (reqlen && !((j & 2) && (j & 0xc0))) { - /* while bytes to send and not full */ - while (reqlen && !((j = inb(qbase + 8)) & 2)) - { - outb(*request++, qbase + 4); - reqlen--; - } - if (j & 2) - j = inb(qbase + 8); - } - } - /* maybe return reqlen */ - return inb(qbase + 8) & 0xc0; -} - -/* - * Wait for interrupt flag (polled - not real hardware interrupt) - */ - -static int ql_wai(struct qlogicfas408_priv *priv) -{ - int k; - int qbase = priv->qbase; - unsigned long i; - - k = 0; - i = jiffies + WATCHDOG; - while (time_before(jiffies, i) && !priv->qabort && - !((k = inb(qbase + 4)) & 0xe0)) { - barrier(); - cpu_relax(); - } - if (time_after_eq(jiffies, i)) - return (DID_TIME_OUT); - if (priv->qabort) - return (priv->qabort == 1 ? DID_ABORT : DID_RESET); - if (k & 0x60) - ql_zap(priv); - if (k & 0x20) - return (DID_PARITY); - if (k & 0x40) - return (DID_ERROR); - return 0; -} - -/* - * Initiate scsi command - queueing handler - * caller must hold host lock - */ - -static void ql_icmd(struct scsi_cmnd *cmd) -{ - struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); - int qbase = priv->qbase; - int int_type = priv->int_type; - unsigned int i; - - priv->qabort = 0; - - REG0; - /* clearing of interrupts and the fifo is needed */ - - inb(qbase + 5); /* clear interrupts */ - if (inb(qbase + 5)) /* if still interrupting */ - outb(2, qbase + 3); /* reset chip */ - else if (inb(qbase + 7) & 0x1f) - outb(1, qbase + 3); /* clear fifo */ - while (inb(qbase + 5)); /* clear ints */ - REG1; - outb(1, qbase + 8); /* set for PIO pseudo DMA */ - outb(0, qbase + 0xb); /* disable ints */ - inb(qbase + 8); /* clear int bits */ - REG0; - outb(0x40, qbase + 0xb); /* enable features */ - - /* configurables */ - outb(qlcfgc, qbase + 0xc); - /* config: no reset interrupt, (initiator) bus id */ - outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8); - outb(qlcfg7, qbase + 7); - outb(qlcfg6, qbase + 6); - /**/ outb(qlcfg5, qbase + 5); /* select timer */ - outb(qlcfg9 & 7, qbase + 9); /* prescaler */ -/* outb(0x99, qbase + 5); */ - outb(scmd_id(cmd), qbase + 4); - - for (i = 0; i < cmd->cmd_len; i++) - outb(cmd->cmnd[i], qbase + 2); - - priv->qlcmd = cmd; - outb(0x41, qbase + 3); /* select and send command */ -} - -/* - * Process scsi command - usually after interrupt - */ - -static unsigned int ql_pcmd(struct scsi_cmnd *cmd) -{ - unsigned int i, j; - unsigned long k; - unsigned int result; /* ultimate return result */ - unsigned int status; /* scsi returned status */ - unsigned int message; /* scsi returned message */ - unsigned int phase; /* recorded scsi phase */ - unsigned int reqlen; /* total length of transfer */ - char *buf; - struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); - int qbase = priv->qbase; - int int_type = priv->int_type; - - rtrc(1) - j = inb(qbase + 6); - i = inb(qbase + 5); - if (i == 0x20) { - return (DID_NO_CONNECT << 16); - } - i |= inb(qbase + 5); /* the 0x10 bit can be set after the 0x08 */ - if (i != 0x18) { - printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i); - ql_zap(priv); - return (DID_BAD_INTR << 16); - } - j &= 7; /* j = inb( qbase + 7 ) >> 5; */ - - /* correct status is supposed to be step 4 */ - /* it sometimes returns step 3 but with 0 bytes left to send */ - /* We can try stuffing the FIFO with the max each time, but we will get a - sequence of 3 if any bytes are left (but we do flush the FIFO anyway */ - - if (j != 3 && j != 4) { - printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n", - j, i, inb(qbase + 7) & 0x1f); - ql_zap(priv); - return (DID_ERROR << 16); - } - result = DID_OK; - if (inb(qbase + 7) & 0x1f) /* if some bytes in fifo */ - outb(1, qbase + 3); /* clear fifo */ - /* note that request_bufflen is the total xfer size when sg is used */ - reqlen = scsi_bufflen(cmd); - /* note that it won't work if transfers > 16M are requested */ - if (reqlen && !((phase = inb(qbase + 4)) & 6)) { /* data phase */ - struct scatterlist *sg; - rtrc(2) - outb(reqlen, qbase); /* low-mid xfer cnt */ - outb(reqlen >> 8, qbase + 1); /* low-mid xfer cnt */ - outb(reqlen >> 16, qbase + 0xe); /* high xfer cnt */ - outb(0x90, qbase + 3); /* command do xfer */ - /* PIO pseudo DMA to buffer or sglist */ - REG1; - - scsi_for_each_sg(cmd, sg, scsi_sg_count(cmd), i) { - if (priv->qabort) { - REG0; - return ((priv->qabort == 1 ? - DID_ABORT : DID_RESET) << 16); - } - buf = sg_virt(sg); - if (ql_pdma(priv, phase, buf, sg->length)) - break; - } - REG0; - rtrc(2) - /* - * Wait for irq (split into second state of irq handler - * if this can take time) - */ - if ((k = ql_wai(priv))) - return (k << 16); - k = inb(qbase + 5); /* should be 0x10, bus service */ - } - - /* - * Enter Status (and Message In) Phase - */ - - k = jiffies + WATCHDOG; - - while (time_before(jiffies, k) && !priv->qabort && - !(inb(qbase + 4) & 6)) - cpu_relax(); /* wait for status phase */ - - if (time_after_eq(jiffies, k)) { - ql_zap(priv); - return (DID_TIME_OUT << 16); - } - - /* FIXME: timeout ?? */ - while (inb(qbase + 5)) - cpu_relax(); /* clear pending ints */ - - if (priv->qabort) - return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); - - outb(0x11, qbase + 3); /* get status and message */ - if ((k = ql_wai(priv))) - return (k << 16); - i = inb(qbase + 5); /* get chip irq stat */ - j = inb(qbase + 7) & 0x1f; /* and bytes rec'd */ - status = inb(qbase + 2); - message = inb(qbase + 2); - - /* - * Should get function complete int if Status and message, else - * bus serv if only status - */ - if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) { - printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j); - result = DID_ERROR; - } - outb(0x12, qbase + 3); /* done, disconnect */ - rtrc(1) - if ((k = ql_wai(priv))) - return (k << 16); - - /* - * Should get bus service interrupt and disconnect interrupt - */ - - i = inb(qbase + 5); /* should be bus service */ - while (!priv->qabort && ((i & 0x20) != 0x20)) { - barrier(); - cpu_relax(); - i |= inb(qbase + 5); - } - rtrc(0) - - if (priv->qabort) - return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16); - - return (result << 16) | (message << 8) | (status & STATUS_MASK); -} - -/* - * Interrupt handler - */ - -static void ql_ihandl(void *dev_id) -{ - struct scsi_cmnd *icmd; - struct Scsi_Host *host = dev_id; - struct qlogicfas408_priv *priv = get_priv_by_host(host); - int qbase = priv->qbase; - REG0; - - if (!(inb(qbase + 4) & 0x80)) /* false alarm? */ - return; - - if (priv->qlcmd == NULL) { /* no command to process? */ - int i; - i = 16; - while (i-- && inb(qbase + 5)); /* maybe also ql_zap() */ - return; - } - icmd = priv->qlcmd; - icmd->result = ql_pcmd(icmd); - priv->qlcmd = NULL; - /* - * If result is CHECK CONDITION done calls qcommand to request - * sense - */ - (icmd->scsi_done) (icmd); -} - -irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *host = dev_id; - - spin_lock_irqsave(host->host_lock, flags); - ql_ihandl(dev_id); - spin_unlock_irqrestore(host->host_lock, flags); - return IRQ_HANDLED; -} - -/* - * Queued command - */ - -static int qlogicfas408_queuecommand_lck(struct scsi_cmnd *cmd, - void (*done) (struct scsi_cmnd *)) -{ - struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); - if (scmd_id(cmd) == priv->qinitid) { - cmd->result = DID_BAD_TARGET << 16; - done(cmd); - return 0; - } - - cmd->scsi_done = done; - /* wait for the last command's interrupt to finish */ - while (priv->qlcmd != NULL) { - barrier(); - cpu_relax(); - } - ql_icmd(cmd); - return 0; -} - -DEF_SCSI_QCMD(qlogicfas408_queuecommand) - -/* - * Return bios parameters - */ - -int qlogicfas408_biosparam(struct scsi_device *disk, struct block_device *dev, - sector_t capacity, int ip[]) -{ -/* This should mimic the DOS Qlogic driver's behavior exactly */ - ip[0] = 0x40; - ip[1] = 0x20; - ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); - if (ip[2] > 1024) { - ip[0] = 0xff; - ip[1] = 0x3f; - ip[2] = (unsigned long) capacity / (ip[0] * ip[1]); -#if 0 - if (ip[2] > 1023) - ip[2] = 1023; -#endif - } - return 0; -} - -/* - * Abort a command in progress - */ - -int qlogicfas408_abort(struct scsi_cmnd *cmd) -{ - struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); - priv->qabort = 1; - ql_zap(priv); - return SUCCESS; -} - -/* - * Reset SCSI bus - * FIXME: This function is invoked with cmd = NULL directly by - * the PCMCIA qlogic_stub code. This wants fixing - */ - -int qlogicfas408_bus_reset(struct scsi_cmnd *cmd) -{ - struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd); - unsigned long flags; - - priv->qabort = 2; - - spin_lock_irqsave(cmd->device->host->host_lock, flags); - ql_zap(priv); - spin_unlock_irqrestore(cmd->device->host->host_lock, flags); - - return SUCCESS; -} - -/* - * Return info string - */ - -const char *qlogicfas408_info(struct Scsi_Host *host) -{ - struct qlogicfas408_priv *priv = get_priv_by_host(host); - return priv->qinfo; -} - -/* - * Get type of chip - */ - -int qlogicfas408_get_chip_type(int qbase, int int_type) -{ - REG1; - return inb(qbase + 0xe) & 0xf8; -} - -/* - * Perform initialization tasks - */ - -void qlogicfas408_setup(int qbase, int id, int int_type) -{ - outb(1, qbase + 8); /* set for PIO pseudo DMA */ - REG0; - outb(0x40 | qlcfg8 | id, qbase + 8); /* (ini) bus id, disable scsi rst */ - outb(qlcfg5, qbase + 5); /* select timer */ - outb(qlcfg9, qbase + 9); /* prescaler */ - -#if QL_RESET_AT_START - outb(3, qbase + 3); - - REG1; - /* FIXME: timeout */ - while (inb(qbase + 0xf) & 4) - cpu_relax(); - - REG0; -#endif -} - -/* - * Checks if this is a QLogic FAS 408 - */ - -int qlogicfas408_detect(int qbase, int int_type) -{ - REG1; - return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) && - ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7)); -} - -/* - * Disable interrupts - */ - -void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv) -{ - int qbase = priv->qbase; - int int_type = priv->int_type; - - REG1; - outb(0, qbase + 0xb); /* disable ints */ -} - -/* - * Init and exit functions - */ - -static int __init qlogicfas408_init(void) -{ - return 0; -} - -static void __exit qlogicfas408_exit(void) -{ - -} - -MODULE_AUTHOR("Tom Zerucha, Michael Griffith"); -MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers"); -MODULE_LICENSE("GPL"); -module_init(qlogicfas408_init); -module_exit(qlogicfas408_exit); - -EXPORT_SYMBOL(qlogicfas408_info); -EXPORT_SYMBOL(qlogicfas408_queuecommand); -EXPORT_SYMBOL(qlogicfas408_abort); -EXPORT_SYMBOL(qlogicfas408_bus_reset); -EXPORT_SYMBOL(qlogicfas408_biosparam); -EXPORT_SYMBOL(qlogicfas408_ihandl); -EXPORT_SYMBOL(qlogicfas408_get_chip_type); -EXPORT_SYMBOL(qlogicfas408_setup); -EXPORT_SYMBOL(qlogicfas408_detect); -EXPORT_SYMBOL(qlogicfas408_disable_ints); - diff --git a/ANDROID_3.4.5/drivers/scsi/qlogicfas408.h b/ANDROID_3.4.5/drivers/scsi/qlogicfas408.h deleted file mode 100644 index 2f6c0a16..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qlogicfas408.h +++ /dev/null @@ -1,118 +0,0 @@ -/* to be used by qlogicfas and qlogic_cs */ -#ifndef __QLOGICFAS408_H -#define __QLOGICFAS408_H - -/*----------------------------------------------------------------*/ -/* Configuration */ - -/* Set the following to max out the speed of the PIO PseudoDMA transfers, - again, 0 tends to be slower, but more stable. */ - -#define QL_TURBO_PDMA 1 - -/* This should be 1 to enable parity detection */ - -#define QL_ENABLE_PARITY 1 - -/* This will reset all devices when the driver is initialized (during bootup). - The other linux drivers don't do this, but the DOS drivers do, and after - using DOS or some kind of crash or lockup this will bring things back - without requiring a cold boot. It does take some time to recover from a - reset, so it is slower, and I have seen timeouts so that devices weren't - recognized when this was set. */ - -#define QL_RESET_AT_START 0 - -/* crystal frequency in megahertz (for offset 5 and 9) - Please set this for your card. Most Qlogic cards are 40 Mhz. The - Control Concepts ISA (not VLB) is 24 Mhz */ - -#define XTALFREQ 40 - -/**********/ -/* DANGER! modify these at your own risk */ -/* SLOWCABLE can usually be reset to zero if you have a clean setup and - proper termination. The rest are for synchronous transfers and other - advanced features if your device can transfer faster than 5Mb/sec. - If you are really curious, email me for a quick howto until I have - something official */ -/**********/ - -/*****/ -/* config register 1 (offset 8) options */ -/* This needs to be set to 1 if your cabling is long or noisy */ -#define SLOWCABLE 1 - -/*****/ -/* offset 0xc */ -/* This will set fast (10Mhz) synchronous timing when set to 1 - For this to have an effect, FASTCLK must also be 1 */ -#define FASTSCSI 0 - -/* This when set to 1 will set a faster sync transfer rate */ -#define FASTCLK 0 /*(XTALFREQ>25?1:0)*/ - -/*****/ -/* offset 6 */ -/* This is the sync transfer divisor, XTALFREQ/X will be the maximum - achievable data rate (assuming the rest of the system is capable - and set properly) */ -#define SYNCXFRPD 5 /*(XTALFREQ/5)*/ - -/*****/ -/* offset 7 */ -/* This is the count of how many synchronous transfers can take place - i.e. how many reqs can occur before an ack is given. - The maximum value for this is 15, the upper bits can modify - REQ/ACK assertion and deassertion during synchronous transfers - If this is 0, the bus will only transfer asynchronously */ -#define SYNCOFFST 0 -/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles - of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will - cause the deassertion to be early by 1/2 clock. Bits 5&4 control - the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */ - -/*----------------------------------------------------------------*/ - -struct qlogicfas408_priv { - int qbase; /* Port */ - int qinitid; /* initiator ID */ - int qabort; /* Flag to cause an abort */ - int qlirq; /* IRQ being used */ - int int_type; /* type of irq, 2 for ISA board, 0 for PCMCIA */ - char qinfo[80]; /* description */ - struct scsi_cmnd *qlcmd; /* current command being processed */ - struct Scsi_Host *shost; /* pointer back to host */ - struct qlogicfas408_priv *next; /* next private struct */ -}; - -/* The qlogic card uses two register maps - These macros select which one */ -#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd )) -#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | int_type, qbase + 0xd )) - -/* following is watchdog timeout in microseconds */ -#define WATCHDOG 5000000 - -/*----------------------------------------------------------------*/ -/* the following will set the monitor border color (useful to find - where something crashed or gets stuck at and as a simple profiler) */ - -#define rtrc(i) {} - -#define get_priv_by_cmd(x) (struct qlogicfas408_priv *)&((x)->device->host->hostdata[0]) -#define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0]) - -irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id); -int qlogicfas408_queuecommand(struct Scsi_Host *h, struct scsi_cmnd * cmd); -int qlogicfas408_biosparam(struct scsi_device * disk, - struct block_device *dev, - sector_t capacity, int ip[]); -int qlogicfas408_abort(struct scsi_cmnd * cmd); -int qlogicfas408_bus_reset(struct scsi_cmnd * cmd); -const char *qlogicfas408_info(struct Scsi_Host *host); -int qlogicfas408_get_chip_type(int qbase, int int_type); -void qlogicfas408_setup(int qbase, int id, int int_type); -int qlogicfas408_detect(int qbase, int int_type); -void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv); -#endif /* __QLOGICFAS408_H */ - diff --git a/ANDROID_3.4.5/drivers/scsi/qlogicpti.c b/ANDROID_3.4.5/drivers/scsi/qlogicpti.c deleted file mode 100644 index b191dd54..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qlogicpti.c +++ /dev/null @@ -1,1493 +0,0 @@ -/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver. - * - * Copyright (C) 1996, 2006, 2008 David S. Miller (davem@davemloft.net) - * - * A lot of this driver was directly stolen from Erik H. Moe's PCI - * Qlogic ISP driver. Mucho kudos to him for this code. - * - * An even bigger kudos to John Grana at Performance Technologies - * for providing me with the hardware to write this driver, you rule - * John you really do. - * - * May, 2, 1997: Added support for QLGC,isp --jj - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "qlogicpti.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define MAX_TARGETS 16 -#define MAX_LUNS 8 /* 32 for 1.31 F/W */ - -#define DEFAULT_LOOP_COUNT 10000 - -static struct qlogicpti *qptichain = NULL; -static DEFINE_SPINLOCK(qptichain_lock); - -#define PACKB(a, b) (((a)<<4)|(b)) - -static const u_char mbox_param[] = { - PACKB(1, 1), /* MBOX_NO_OP */ - PACKB(5, 5), /* MBOX_LOAD_RAM */ - PACKB(2, 0), /* MBOX_EXEC_FIRMWARE */ - PACKB(5, 5), /* MBOX_DUMP_RAM */ - PACKB(3, 3), /* MBOX_WRITE_RAM_WORD */ - PACKB(2, 3), /* MBOX_READ_RAM_WORD */ - PACKB(6, 6), /* MBOX_MAILBOX_REG_TEST */ - PACKB(2, 3), /* MBOX_VERIFY_CHECKSUM */ - PACKB(1, 3), /* MBOX_ABOUT_FIRMWARE */ - PACKB(0, 0), /* 0x0009 */ - PACKB(0, 0), /* 0x000a */ - PACKB(0, 0), /* 0x000b */ - PACKB(0, 0), /* 0x000c */ - PACKB(0, 0), /* 0x000d */ - PACKB(1, 2), /* MBOX_CHECK_FIRMWARE */ - PACKB(0, 0), /* 0x000f */ - PACKB(5, 5), /* MBOX_INIT_REQ_QUEUE */ - PACKB(6, 6), /* MBOX_INIT_RES_QUEUE */ - PACKB(4, 4), /* MBOX_EXECUTE_IOCB */ - PACKB(2, 2), /* MBOX_WAKE_UP */ - PACKB(1, 6), /* MBOX_STOP_FIRMWARE */ - PACKB(4, 4), /* MBOX_ABORT */ - PACKB(2, 2), /* MBOX_ABORT_DEVICE */ - PACKB(3, 3), /* MBOX_ABORT_TARGET */ - PACKB(2, 2), /* MBOX_BUS_RESET */ - PACKB(2, 3), /* MBOX_STOP_QUEUE */ - PACKB(2, 3), /* MBOX_START_QUEUE */ - PACKB(2, 3), /* MBOX_SINGLE_STEP_QUEUE */ - PACKB(2, 3), /* MBOX_ABORT_QUEUE */ - PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_STATUS */ - PACKB(0, 0), /* 0x001e */ - PACKB(1, 3), /* MBOX_GET_FIRMWARE_STATUS */ - PACKB(1, 2), /* MBOX_GET_INIT_SCSI_ID */ - PACKB(1, 2), /* MBOX_GET_SELECT_TIMEOUT */ - PACKB(1, 3), /* MBOX_GET_RETRY_COUNT */ - PACKB(1, 2), /* MBOX_GET_TAG_AGE_LIMIT */ - PACKB(1, 2), /* MBOX_GET_CLOCK_RATE */ - PACKB(1, 2), /* MBOX_GET_ACT_NEG_STATE */ - PACKB(1, 2), /* MBOX_GET_ASYNC_DATA_SETUP_TIME */ - PACKB(1, 3), /* MBOX_GET_SBUS_PARAMS */ - PACKB(2, 4), /* MBOX_GET_TARGET_PARAMS */ - PACKB(2, 4), /* MBOX_GET_DEV_QUEUE_PARAMS */ - PACKB(0, 0), /* 0x002a */ - PACKB(0, 0), /* 0x002b */ - PACKB(0, 0), /* 0x002c */ - PACKB(0, 0), /* 0x002d */ - PACKB(0, 0), /* 0x002e */ - PACKB(0, 0), /* 0x002f */ - PACKB(2, 2), /* MBOX_SET_INIT_SCSI_ID */ - PACKB(2, 2), /* MBOX_SET_SELECT_TIMEOUT */ - PACKB(3, 3), /* MBOX_SET_RETRY_COUNT */ - PACKB(2, 2), /* MBOX_SET_TAG_AGE_LIMIT */ - PACKB(2, 2), /* MBOX_SET_CLOCK_RATE */ - PACKB(2, 2), /* MBOX_SET_ACTIVE_NEG_STATE */ - PACKB(2, 2), /* MBOX_SET_ASYNC_DATA_SETUP_TIME */ - PACKB(3, 3), /* MBOX_SET_SBUS_CONTROL_PARAMS */ - PACKB(4, 4), /* MBOX_SET_TARGET_PARAMS */ - PACKB(4, 4), /* MBOX_SET_DEV_QUEUE_PARAMS */ - PACKB(0, 0), /* 0x003a */ - PACKB(0, 0), /* 0x003b */ - PACKB(0, 0), /* 0x003c */ - PACKB(0, 0), /* 0x003d */ - PACKB(0, 0), /* 0x003e */ - PACKB(0, 0), /* 0x003f */ - PACKB(0, 0), /* 0x0040 */ - PACKB(0, 0), /* 0x0041 */ - PACKB(0, 0) /* 0x0042 */ -}; - -#define MAX_MBOX_COMMAND ARRAY_SIZE(mbox_param) - -/* queue length's _must_ be power of two: */ -#define QUEUE_DEPTH(in, out, ql) ((in - out) & (ql)) -#define REQ_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, \ - QLOGICPTI_REQ_QUEUE_LEN) -#define RES_QUEUE_DEPTH(in, out) QUEUE_DEPTH(in, out, RES_QUEUE_LEN) - -static inline void qlogicpti_enable_irqs(struct qlogicpti *qpti) -{ - sbus_writew(SBUS_CTRL_ERIRQ | SBUS_CTRL_GENAB, - qpti->qregs + SBUS_CTRL); -} - -static inline void qlogicpti_disable_irqs(struct qlogicpti *qpti) -{ - sbus_writew(0, qpti->qregs + SBUS_CTRL); -} - -static inline void set_sbus_cfg1(struct qlogicpti *qpti) -{ - u16 val; - u8 bursts = qpti->bursts; - -#if 0 /* It appears that at least PTI cards do not support - * 64-byte bursts and that setting the B64 bit actually - * is a nop and the chip ends up using the smallest burst - * size. -DaveM - */ - if (sbus_can_burst64() && (bursts & DMA_BURST64)) { - val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64); - } else -#endif - if (bursts & DMA_BURST32) { - val = (SBUS_CFG1_BENAB | SBUS_CFG1_B32); - } else if (bursts & DMA_BURST16) { - val = (SBUS_CFG1_BENAB | SBUS_CFG1_B16); - } else if (bursts & DMA_BURST8) { - val = (SBUS_CFG1_BENAB | SBUS_CFG1_B8); - } else { - val = 0; /* No sbus bursts for you... */ - } - sbus_writew(val, qpti->qregs + SBUS_CFG1); -} - -static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int force) -{ - int loop_count; - u16 tmp; - - if (mbox_param[param[0]] == 0) - return 1; - - /* Set SBUS semaphore. */ - tmp = sbus_readw(qpti->qregs + SBUS_SEMAPHORE); - tmp |= SBUS_SEMAPHORE_LCK; - sbus_writew(tmp, qpti->qregs + SBUS_SEMAPHORE); - - /* Wait for host IRQ bit to clear. */ - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && (sbus_readw(qpti->qregs + HCCTRL) & HCCTRL_HIRQ)) { - barrier(); - cpu_relax(); - } - if (!loop_count) - printk(KERN_EMERG "qlogicpti%d: mbox_command loop timeout #1\n", - qpti->qpti_id); - - /* Write mailbox command registers. */ - switch (mbox_param[param[0]] >> 4) { - case 6: sbus_writew(param[5], qpti->qregs + MBOX5); - case 5: sbus_writew(param[4], qpti->qregs + MBOX4); - case 4: sbus_writew(param[3], qpti->qregs + MBOX3); - case 3: sbus_writew(param[2], qpti->qregs + MBOX2); - case 2: sbus_writew(param[1], qpti->qregs + MBOX1); - case 1: sbus_writew(param[0], qpti->qregs + MBOX0); - } - - /* Clear RISC interrupt. */ - tmp = sbus_readw(qpti->qregs + HCCTRL); - tmp |= HCCTRL_CRIRQ; - sbus_writew(tmp, qpti->qregs + HCCTRL); - - /* Clear SBUS semaphore. */ - sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE); - - /* Set HOST interrupt. */ - tmp = sbus_readw(qpti->qregs + HCCTRL); - tmp |= HCCTRL_SHIRQ; - sbus_writew(tmp, qpti->qregs + HCCTRL); - - /* Wait for HOST interrupt clears. */ - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && - (sbus_readw(qpti->qregs + HCCTRL) & HCCTRL_CRIRQ)) - udelay(20); - if (!loop_count) - printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #2\n", - qpti->qpti_id, param[0]); - - /* Wait for SBUS semaphore to get set. */ - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && - !(sbus_readw(qpti->qregs + SBUS_SEMAPHORE) & SBUS_SEMAPHORE_LCK)) { - udelay(20); - - /* Workaround for some buggy chips. */ - if (sbus_readw(qpti->qregs + MBOX0) & 0x4000) - break; - } - if (!loop_count) - printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #3\n", - qpti->qpti_id, param[0]); - - /* Wait for MBOX busy condition to go away. */ - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && (sbus_readw(qpti->qregs + MBOX0) == 0x04)) - udelay(20); - if (!loop_count) - printk(KERN_EMERG "qlogicpti%d: mbox_command[%04x] loop timeout #4\n", - qpti->qpti_id, param[0]); - - /* Read back output parameters. */ - switch (mbox_param[param[0]] & 0xf) { - case 6: param[5] = sbus_readw(qpti->qregs + MBOX5); - case 5: param[4] = sbus_readw(qpti->qregs + MBOX4); - case 4: param[3] = sbus_readw(qpti->qregs + MBOX3); - case 3: param[2] = sbus_readw(qpti->qregs + MBOX2); - case 2: param[1] = sbus_readw(qpti->qregs + MBOX1); - case 1: param[0] = sbus_readw(qpti->qregs + MBOX0); - } - - /* Clear RISC interrupt. */ - tmp = sbus_readw(qpti->qregs + HCCTRL); - tmp |= HCCTRL_CRIRQ; - sbus_writew(tmp, qpti->qregs + HCCTRL); - - /* Release SBUS semaphore. */ - tmp = sbus_readw(qpti->qregs + SBUS_SEMAPHORE); - tmp &= ~(SBUS_SEMAPHORE_LCK); - sbus_writew(tmp, qpti->qregs + SBUS_SEMAPHORE); - - /* We're done. */ - return 0; -} - -static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti) -{ - int i; - - qpti->host_param.initiator_scsi_id = qpti->scsi_id; - qpti->host_param.bus_reset_delay = 3; - qpti->host_param.retry_count = 0; - qpti->host_param.retry_delay = 5; - qpti->host_param.async_data_setup_time = 3; - qpti->host_param.req_ack_active_negation = 1; - qpti->host_param.data_line_active_negation = 1; - qpti->host_param.data_dma_burst_enable = 1; - qpti->host_param.command_dma_burst_enable = 1; - qpti->host_param.tag_aging = 8; - qpti->host_param.selection_timeout = 250; - qpti->host_param.max_queue_depth = 256; - - for(i = 0; i < MAX_TARGETS; i++) { - /* - * disconnect, parity, arq, reneg on reset, and, oddly enough - * tags...the midlayer's notion of tagged support has to match - * our device settings, and since we base whether we enable a - * tag on a per-cmnd basis upon what the midlayer sez, we - * actually enable the capability here. - */ - qpti->dev_param[i].device_flags = 0xcd; - qpti->dev_param[i].execution_throttle = 16; - if (qpti->ultra) { - qpti->dev_param[i].synchronous_period = 12; - qpti->dev_param[i].synchronous_offset = 8; - } else { - qpti->dev_param[i].synchronous_period = 25; - qpti->dev_param[i].synchronous_offset = 12; - } - qpti->dev_param[i].device_enable = 1; - } -} - -static int qlogicpti_reset_hardware(struct Scsi_Host *host) -{ - struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - u_short param[6]; - unsigned short risc_code_addr; - int loop_count, i; - unsigned long flags; - - risc_code_addr = 0x1000; /* all load addresses are at 0x1000 */ - - spin_lock_irqsave(host->host_lock, flags); - - sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL); - - /* Only reset the scsi bus if it is not free. */ - if (sbus_readw(qpti->qregs + CPU_PCTRL) & CPU_PCTRL_BSY) { - sbus_writew(CPU_ORIDE_RMOD, qpti->qregs + CPU_ORIDE); - sbus_writew(CPU_CMD_BRESET, qpti->qregs + CPU_CMD); - udelay(400); - } - - sbus_writew(SBUS_CTRL_RESET, qpti->qregs + SBUS_CTRL); - sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + CMD_DMA_CTRL); - sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + DATA_DMA_CTRL); - - loop_count = DEFAULT_LOOP_COUNT; - while (--loop_count && ((sbus_readw(qpti->qregs + MBOX0) & 0xff) == 0x04)) - udelay(20); - if (!loop_count) - printk(KERN_EMERG "qlogicpti%d: reset_hardware loop timeout\n", - qpti->qpti_id); - - sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL); - set_sbus_cfg1(qpti); - qlogicpti_enable_irqs(qpti); - - if (sbus_readw(qpti->qregs + RISC_PSR) & RISC_PSR_ULTRA) { - qpti->ultra = 1; - sbus_writew((RISC_MTREG_P0ULTRA | RISC_MTREG_P1ULTRA), - qpti->qregs + RISC_MTREG); - } else { - qpti->ultra = 0; - sbus_writew((RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT), - qpti->qregs + RISC_MTREG); - } - - /* reset adapter and per-device default values. */ - /* do it after finding out whether we're ultra mode capable */ - qlogicpti_set_hostdev_defaults(qpti); - - /* Release the RISC processor. */ - sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL); - - /* Get RISC to start executing the firmware code. */ - param[0] = MBOX_EXEC_FIRMWARE; - param[1] = risc_code_addr; - if (qlogicpti_mbox_command(qpti, param, 1)) { - printk(KERN_EMERG "qlogicpti%d: Cannot execute ISP firmware.\n", - qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; - } - - /* Set initiator scsi ID. */ - param[0] = MBOX_SET_INIT_SCSI_ID; - param[1] = qpti->host_param.initiator_scsi_id; - if (qlogicpti_mbox_command(qpti, param, 1) || - (param[0] != MBOX_COMMAND_COMPLETE)) { - printk(KERN_EMERG "qlogicpti%d: Cannot set initiator SCSI ID.\n", - qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; - } - - /* Initialize state of the queues, both hw and sw. */ - qpti->req_in_ptr = qpti->res_out_ptr = 0; - - param[0] = MBOX_INIT_RES_QUEUE; - param[1] = RES_QUEUE_LEN + 1; - param[2] = (u_short) (qpti->res_dvma >> 16); - param[3] = (u_short) (qpti->res_dvma & 0xffff); - param[4] = param[5] = 0; - if (qlogicpti_mbox_command(qpti, param, 1)) { - printk(KERN_EMERG "qlogicpti%d: Cannot init response queue.\n", - qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; - } - - param[0] = MBOX_INIT_REQ_QUEUE; - param[1] = QLOGICPTI_REQ_QUEUE_LEN + 1; - param[2] = (u_short) (qpti->req_dvma >> 16); - param[3] = (u_short) (qpti->req_dvma & 0xffff); - param[4] = param[5] = 0; - if (qlogicpti_mbox_command(qpti, param, 1)) { - printk(KERN_EMERG "qlogicpti%d: Cannot init request queue.\n", - qpti->qpti_id); - spin_unlock_irqrestore(host->host_lock, flags); - return 1; - } - - param[0] = MBOX_SET_RETRY_COUNT; - param[1] = qpti->host_param.retry_count; - param[2] = qpti->host_param.retry_delay; - qlogicpti_mbox_command(qpti, param, 0); - - param[0] = MBOX_SET_TAG_AGE_LIMIT; - param[1] = qpti->host_param.tag_aging; - qlogicpti_mbox_command(qpti, param, 0); - - for (i = 0; i < MAX_TARGETS; i++) { - param[0] = MBOX_GET_DEV_QUEUE_PARAMS; - param[1] = (i << 8); - qlogicpti_mbox_command(qpti, param, 0); - } - - param[0] = MBOX_GET_FIRMWARE_STATUS; - qlogicpti_mbox_command(qpti, param, 0); - - param[0] = MBOX_SET_SELECT_TIMEOUT; - param[1] = qpti->host_param.selection_timeout; - qlogicpti_mbox_command(qpti, param, 0); - - for (i = 0; i < MAX_TARGETS; i++) { - param[0] = MBOX_SET_TARGET_PARAMS; - param[1] = (i << 8); - param[2] = (qpti->dev_param[i].device_flags << 8); - /* - * Since we're now loading 1.31 f/w, force narrow/async. - */ - param[2] |= 0xc0; - param[3] = 0; /* no offset, we do not have sync mode yet */ - qlogicpti_mbox_command(qpti, param, 0); - } - - /* - * Always (sigh) do an initial bus reset (kicks f/w). - */ - param[0] = MBOX_BUS_RESET; - param[1] = qpti->host_param.bus_reset_delay; - qlogicpti_mbox_command(qpti, param, 0); - qpti->send_marker = 1; - - spin_unlock_irqrestore(host->host_lock, flags); - return 0; -} - -#define PTI_RESET_LIMIT 400 - -static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti) -{ - const struct firmware *fw; - const char fwname[] = "qlogic/isp1000.bin"; - const __le16 *fw_data; - struct Scsi_Host *host = qpti->qhost; - unsigned short csum = 0; - unsigned short param[6]; - unsigned short risc_code_addr, risc_code_length; - int err; - unsigned long flags; - int i, timeout; - - err = request_firmware(&fw, fwname, &qpti->op->dev); - if (err) { - printk(KERN_ERR "Failed to load image \"%s\" err %d\n", - fwname, err); - return err; - } - if (fw->size % 2) { - printk(KERN_ERR "Bogus length %zu in image \"%s\"\n", - fw->size, fwname); - err = -EINVAL; - goto outfirm; - } - fw_data = (const __le16 *)&fw->data[0]; - risc_code_addr = 0x1000; /* all f/w modules load at 0x1000 */ - risc_code_length = fw->size / 2; - - spin_lock_irqsave(host->host_lock, flags); - - /* Verify the checksum twice, one before loading it, and once - * afterwards via the mailbox commands. - */ - for (i = 0; i < risc_code_length; i++) - csum += __le16_to_cpu(fw_data[i]); - if (csum) { - printk(KERN_EMERG "qlogicpti%d: Aieee, firmware checksum failed!", - qpti->qpti_id); - err = 1; - goto out; - } - sbus_writew(SBUS_CTRL_RESET, qpti->qregs + SBUS_CTRL); - sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + CMD_DMA_CTRL); - sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + DATA_DMA_CTRL); - timeout = PTI_RESET_LIMIT; - while (--timeout && (sbus_readw(qpti->qregs + SBUS_CTRL) & SBUS_CTRL_RESET)) - udelay(20); - if (!timeout) { - printk(KERN_EMERG "qlogicpti%d: Cannot reset the ISP.", qpti->qpti_id); - err = 1; - goto out; - } - - sbus_writew(HCCTRL_RESET, qpti->qregs + HCCTRL); - mdelay(1); - - sbus_writew((SBUS_CTRL_GENAB | SBUS_CTRL_ERIRQ), qpti->qregs + SBUS_CTRL); - set_sbus_cfg1(qpti); - sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE); - - if (sbus_readw(qpti->qregs + RISC_PSR) & RISC_PSR_ULTRA) { - qpti->ultra = 1; - sbus_writew((RISC_MTREG_P0ULTRA | RISC_MTREG_P1ULTRA), - qpti->qregs + RISC_MTREG); - } else { - qpti->ultra = 0; - sbus_writew((RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT), - qpti->qregs + RISC_MTREG); - } - - sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL); - - /* Pin lines are only stable while RISC is paused. */ - sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL); - if (sbus_readw(qpti->qregs + CPU_PDIFF) & CPU_PDIFF_MODE) - qpti->differential = 1; - else - qpti->differential = 0; - sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL); - - /* This shouldn't be necessary- we've reset things so we should be - running from the ROM now.. */ - - param[0] = MBOX_STOP_FIRMWARE; - param[1] = param[2] = param[3] = param[4] = param[5] = 0; - if (qlogicpti_mbox_command(qpti, param, 1)) { - printk(KERN_EMERG "qlogicpti%d: Cannot stop firmware for reload.\n", - qpti->qpti_id); - err = 1; - goto out; - } - - /* Load it up.. */ - for (i = 0; i < risc_code_length; i++) { - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = risc_code_addr + i; - param[2] = __le16_to_cpu(fw_data[i]); - if (qlogicpti_mbox_command(qpti, param, 1) || - param[0] != MBOX_COMMAND_COMPLETE) { - printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n", - qpti->qpti_id); - err = 1; - goto out; - } - } - - /* Reset the ISP again. */ - sbus_writew(HCCTRL_RESET, qpti->qregs + HCCTRL); - mdelay(1); - - qlogicpti_enable_irqs(qpti); - sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE); - sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL); - - /* Ask ISP to verify the checksum of the new code. */ - param[0] = MBOX_VERIFY_CHECKSUM; - param[1] = risc_code_addr; - if (qlogicpti_mbox_command(qpti, param, 1) || - (param[0] != MBOX_COMMAND_COMPLETE)) { - printk(KERN_EMERG "qlogicpti%d: New firmware csum failure!\n", - qpti->qpti_id); - err = 1; - goto out; - } - - /* Start using newly downloaded firmware. */ - param[0] = MBOX_EXEC_FIRMWARE; - param[1] = risc_code_addr; - qlogicpti_mbox_command(qpti, param, 1); - - param[0] = MBOX_ABOUT_FIRMWARE; - if (qlogicpti_mbox_command(qpti, param, 1) || - (param[0] != MBOX_COMMAND_COMPLETE)) { - printk(KERN_EMERG "qlogicpti%d: AboutFirmware cmd fails.\n", - qpti->qpti_id); - err = 1; - goto out; - } - - /* Snag the major and minor revisions from the result. */ - qpti->fware_majrev = param[1]; - qpti->fware_minrev = param[2]; - qpti->fware_micrev = param[3]; - - /* Set the clock rate */ - param[0] = MBOX_SET_CLOCK_RATE; - param[1] = qpti->clock; - if (qlogicpti_mbox_command(qpti, param, 1) || - (param[0] != MBOX_COMMAND_COMPLETE)) { - printk(KERN_EMERG "qlogicpti%d: could not set clock rate.\n", - qpti->qpti_id); - err = 1; - goto out; - } - - if (qpti->is_pti != 0) { - /* Load scsi initiator ID and interrupt level into sbus static ram. */ - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = 0xff80; - param[2] = (unsigned short) qpti->scsi_id; - qlogicpti_mbox_command(qpti, param, 1); - - param[0] = MBOX_WRITE_RAM_WORD; - param[1] = 0xff00; - param[2] = (unsigned short) 3; - qlogicpti_mbox_command(qpti, param, 1); - } - -out: - spin_unlock_irqrestore(host->host_lock, flags); -outfirm: - release_firmware(fw); - return err; -} - -static int qlogicpti_verify_tmon(struct qlogicpti *qpti) -{ - int curstat = sbus_readb(qpti->sreg); - - curstat &= 0xf0; - if (!(curstat & SREG_FUSE) && (qpti->swsreg & SREG_FUSE)) - printk("qlogicpti%d: Fuse returned to normal state.\n", qpti->qpti_id); - if (!(curstat & SREG_TPOWER) && (qpti->swsreg & SREG_TPOWER)) - printk("qlogicpti%d: termpwr back to normal state.\n", qpti->qpti_id); - if (curstat != qpti->swsreg) { - int error = 0; - if (curstat & SREG_FUSE) { - error++; - printk("qlogicpti%d: Fuse is open!\n", qpti->qpti_id); - } - if (curstat & SREG_TPOWER) { - error++; - printk("qlogicpti%d: termpwr failure\n", qpti->qpti_id); - } - if (qpti->differential && - (curstat & SREG_DSENSE) != SREG_DSENSE) { - error++; - printk("qlogicpti%d: You have a single ended device on a " - "differential bus! Please fix!\n", qpti->qpti_id); - } - qpti->swsreg = curstat; - return error; - } - return 0; -} - -static irqreturn_t qpti_intr(int irq, void *dev_id); - -static void __devinit qpti_chain_add(struct qlogicpti *qpti) -{ - spin_lock_irq(&qptichain_lock); - if (qptichain != NULL) { - struct qlogicpti *qlink = qptichain; - - while(qlink->next) - qlink = qlink->next; - qlink->next = qpti; - } else { - qptichain = qpti; - } - qpti->next = NULL; - spin_unlock_irq(&qptichain_lock); -} - -static void __devexit qpti_chain_del(struct qlogicpti *qpti) -{ - spin_lock_irq(&qptichain_lock); - if (qptichain == qpti) { - qptichain = qpti->next; - } else { - struct qlogicpti *qlink = qptichain; - while(qlink->next != qpti) - qlink = qlink->next; - qlink->next = qpti->next; - } - qpti->next = NULL; - spin_unlock_irq(&qptichain_lock); -} - -static int __devinit qpti_map_regs(struct qlogicpti *qpti) -{ - struct platform_device *op = qpti->op; - - qpti->qregs = of_ioremap(&op->resource[0], 0, - resource_size(&op->resource[0]), - "PTI Qlogic/ISP"); - if (!qpti->qregs) { - printk("PTI: Qlogic/ISP registers are unmappable\n"); - return -1; - } - if (qpti->is_pti) { - qpti->sreg = of_ioremap(&op->resource[0], (16 * 4096), - sizeof(unsigned char), - "PTI Qlogic/ISP statreg"); - if (!qpti->sreg) { - printk("PTI: Qlogic/ISP status register is unmappable\n"); - return -1; - } - } - return 0; -} - -static int __devinit qpti_register_irq(struct qlogicpti *qpti) -{ - struct platform_device *op = qpti->op; - - qpti->qhost->irq = qpti->irq = op->archdata.irqs[0]; - - /* We used to try various overly-clever things to - * reduce the interrupt processing overhead on - * sun4c/sun4m when multiple PTI's shared the - * same IRQ. It was too complex and messy to - * sanely maintain. - */ - if (request_irq(qpti->irq, qpti_intr, - IRQF_SHARED, "QlogicPTI", qpti)) - goto fail; - - printk("qlogicpti%d: IRQ %d ", qpti->qpti_id, qpti->irq); - - return 0; - -fail: - printk("qlogicpti%d: Cannot acquire irq line\n", qpti->qpti_id); - return -1; -} - -static void __devinit qpti_get_scsi_id(struct qlogicpti *qpti) -{ - struct platform_device *op = qpti->op; - struct device_node *dp; - - dp = op->dev.of_node; - - qpti->scsi_id = of_getintprop_default(dp, "initiator-id", -1); - if (qpti->scsi_id == -1) - qpti->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", - -1); - if (qpti->scsi_id == -1) - qpti->scsi_id = - of_getintprop_default(dp->parent, - "scsi-initiator-id", 7); - qpti->qhost->this_id = qpti->scsi_id; - qpti->qhost->max_sectors = 64; - - printk("SCSI ID %d ", qpti->scsi_id); -} - -static void qpti_get_bursts(struct qlogicpti *qpti) -{ - struct platform_device *op = qpti->op; - u8 bursts, bmask; - - bursts = of_getintprop_default(op->dev.of_node, "burst-sizes", 0xff); - bmask = of_getintprop_default(op->dev.of_node->parent, "burst-sizes", 0xff); - if (bmask != 0xff) - bursts &= bmask; - if (bursts == 0xff || - (bursts & DMA_BURST16) == 0 || - (bursts & DMA_BURST32) == 0) - bursts = (DMA_BURST32 - 1); - - qpti->bursts = bursts; -} - -static void qpti_get_clock(struct qlogicpti *qpti) -{ - unsigned int cfreq; - - /* Check for what the clock input to this card is. - * Default to 40Mhz. - */ - cfreq = prom_getintdefault(qpti->prom_node,"clock-frequency",40000000); - qpti->clock = (cfreq + 500000)/1000000; - if (qpti->clock == 0) /* bullshit */ - qpti->clock = 40; -} - -/* The request and response queues must each be aligned - * on a page boundary. - */ -static int __devinit qpti_map_queues(struct qlogicpti *qpti) -{ - struct platform_device *op = qpti->op; - -#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - qpti->res_cpu = dma_alloc_coherent(&op->dev, - QSIZE(RES_QUEUE_LEN), - &qpti->res_dvma, GFP_ATOMIC); - if (qpti->res_cpu == NULL || - qpti->res_dvma == 0) { - printk("QPTI: Cannot map response queue.\n"); - return -1; - } - - qpti->req_cpu = dma_alloc_coherent(&op->dev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - &qpti->req_dvma, GFP_ATOMIC); - if (qpti->req_cpu == NULL || - qpti->req_dvma == 0) { - dma_free_coherent(&op->dev, QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - printk("QPTI: Cannot map request queue.\n"); - return -1; - } - memset(qpti->res_cpu, 0, QSIZE(RES_QUEUE_LEN)); - memset(qpti->req_cpu, 0, QSIZE(QLOGICPTI_REQ_QUEUE_LEN)); - return 0; -} - -const char *qlogicpti_info(struct Scsi_Host *host) -{ - static char buf[80]; - struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - - sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %d regs at %p", - qpti->qhost->irq, qpti->qregs); - return buf; -} - -/* I am a certified frobtronicist. */ -static inline void marker_frob(struct Command_Entry *cmd) -{ - struct Marker_Entry *marker = (struct Marker_Entry *) cmd; - - memset(marker, 0, sizeof(struct Marker_Entry)); - marker->hdr.entry_cnt = 1; - marker->hdr.entry_type = ENTRY_MARKER; - marker->modifier = SYNC_ALL; - marker->rsvd = 0; -} - -static inline void cmd_frob(struct Command_Entry *cmd, struct scsi_cmnd *Cmnd, - struct qlogicpti *qpti) -{ - memset(cmd, 0, sizeof(struct Command_Entry)); - cmd->hdr.entry_cnt = 1; - cmd->hdr.entry_type = ENTRY_COMMAND; - cmd->target_id = Cmnd->device->id; - cmd->target_lun = Cmnd->device->lun; - cmd->cdb_length = Cmnd->cmd_len; - cmd->control_flags = 0; - if (Cmnd->device->tagged_supported) { - if (qpti->cmd_count[Cmnd->device->id] == 0) - qpti->tag_ages[Cmnd->device->id] = jiffies; - if (time_after(jiffies, qpti->tag_ages[Cmnd->device->id] + (5*HZ))) { - cmd->control_flags = CFLAG_ORDERED_TAG; - qpti->tag_ages[Cmnd->device->id] = jiffies; - } else - cmd->control_flags = CFLAG_SIMPLE_TAG; - } - if ((Cmnd->cmnd[0] == WRITE_6) || - (Cmnd->cmnd[0] == WRITE_10) || - (Cmnd->cmnd[0] == WRITE_12)) - cmd->control_flags |= CFLAG_WRITE; - else - cmd->control_flags |= CFLAG_READ; - cmd->time_out = Cmnd->request->timeout/HZ; - memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len); -} - -/* Do it to it baby. */ -static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd, - struct qlogicpti *qpti, u_int in_ptr, u_int out_ptr) -{ - struct dataseg *ds; - struct scatterlist *sg, *s; - int i, n; - - if (scsi_bufflen(Cmnd)) { - int sg_count; - - sg = scsi_sglist(Cmnd); - sg_count = dma_map_sg(&qpti->op->dev, sg, - scsi_sg_count(Cmnd), - Cmnd->sc_data_direction); - - ds = cmd->dataseg; - cmd->segment_cnt = sg_count; - - /* Fill in first four sg entries: */ - n = sg_count; - if (n > 4) - n = 4; - for_each_sg(sg, s, n, i) { - ds[i].d_base = sg_dma_address(s); - ds[i].d_count = sg_dma_len(s); - } - sg_count -= 4; - sg = s; - while (sg_count > 0) { - struct Continuation_Entry *cont; - - ++cmd->hdr.entry_cnt; - cont = (struct Continuation_Entry *) &qpti->req_cpu[in_ptr]; - in_ptr = NEXT_REQ_PTR(in_ptr); - if (in_ptr == out_ptr) - return -1; - - cont->hdr.entry_type = ENTRY_CONTINUATION; - cont->hdr.entry_cnt = 0; - cont->hdr.sys_def_1 = 0; - cont->hdr.flags = 0; - cont->reserved = 0; - ds = cont->dataseg; - n = sg_count; - if (n > 7) - n = 7; - for_each_sg(sg, s, n, i) { - ds[i].d_base = sg_dma_address(s); - ds[i].d_count = sg_dma_len(s); - } - sg_count -= n; - sg = s; - } - } else { - cmd->dataseg[0].d_base = 0; - cmd->dataseg[0].d_count = 0; - cmd->segment_cnt = 1; /* Shouldn't this be 0? */ - } - - /* Committed, record Scsi_Cmd so we can find it later. */ - cmd->handle = in_ptr; - qpti->cmd_slots[in_ptr] = Cmnd; - - qpti->cmd_count[Cmnd->device->id]++; - sbus_writew(in_ptr, qpti->qregs + MBOX4); - qpti->req_in_ptr = in_ptr; - - return in_ptr; -} - -static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int out_ptr) -{ - /* Temporary workaround until bug is found and fixed (one bug has been found - already, but fixing it makes things even worse) -jj */ - int num_free = QLOGICPTI_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr) - 64; - host->can_queue = host->host_busy + num_free; - host->sg_tablesize = QLOGICPTI_MAX_SG(num_free); -} - -static int qlogicpti_slave_configure(struct scsi_device *sdev) -{ - struct qlogicpti *qpti = shost_priv(sdev->host); - int tgt = sdev->id; - u_short param[6]; - - /* tags handled in midlayer */ - /* enable sync mode? */ - if (sdev->sdtr) { - qpti->dev_param[tgt].device_flags |= 0x10; - } else { - qpti->dev_param[tgt].synchronous_offset = 0; - qpti->dev_param[tgt].synchronous_period = 0; - } - /* are we wide capable? */ - if (sdev->wdtr) - qpti->dev_param[tgt].device_flags |= 0x20; - - param[0] = MBOX_SET_TARGET_PARAMS; - param[1] = (tgt << 8); - param[2] = (qpti->dev_param[tgt].device_flags << 8); - if (qpti->dev_param[tgt].device_flags & 0x10) { - param[3] = (qpti->dev_param[tgt].synchronous_offset << 8) | - qpti->dev_param[tgt].synchronous_period; - } else { - param[3] = 0; - } - qlogicpti_mbox_command(qpti, param, 0); - return 0; -} - -/* - * The middle SCSI layer ensures that queuecommand never gets invoked - * concurrently with itself or the interrupt handler (though the - * interrupt handler may call this routine as part of - * request-completion handling). - * - * "This code must fly." -davem - */ -static int qlogicpti_queuecommand_lck(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *)) -{ - struct Scsi_Host *host = Cmnd->device->host; - struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - struct Command_Entry *cmd; - u_int out_ptr; - int in_ptr; - - Cmnd->scsi_done = done; - - in_ptr = qpti->req_in_ptr; - cmd = (struct Command_Entry *) &qpti->req_cpu[in_ptr]; - out_ptr = sbus_readw(qpti->qregs + MBOX4); - in_ptr = NEXT_REQ_PTR(in_ptr); - if (in_ptr == out_ptr) - goto toss_command; - - if (qpti->send_marker) { - marker_frob(cmd); - qpti->send_marker = 0; - if (NEXT_REQ_PTR(in_ptr) == out_ptr) { - sbus_writew(in_ptr, qpti->qregs + MBOX4); - qpti->req_in_ptr = in_ptr; - goto toss_command; - } - cmd = (struct Command_Entry *) &qpti->req_cpu[in_ptr]; - in_ptr = NEXT_REQ_PTR(in_ptr); - } - cmd_frob(cmd, Cmnd, qpti); - if ((in_ptr = load_cmd(Cmnd, cmd, qpti, in_ptr, out_ptr)) == -1) - goto toss_command; - - update_can_queue(host, in_ptr, out_ptr); - - return 0; - -toss_command: - printk(KERN_EMERG "qlogicpti%d: request queue overflow\n", - qpti->qpti_id); - - /* Unfortunately, unless you use the new EH code, which - * we don't, the midlayer will ignore the return value, - * which is insane. We pick up the pieces like this. - */ - Cmnd->result = DID_BUS_BUSY; - done(Cmnd); - return 1; -} - -static DEF_SCSI_QCMD(qlogicpti_queuecommand) - -static int qlogicpti_return_status(struct Status_Entry *sts, int id) -{ - int host_status = DID_ERROR; - - switch (sts->completion_status) { - case CS_COMPLETE: - host_status = DID_OK; - break; - case CS_INCOMPLETE: - if (!(sts->state_flags & SF_GOT_BUS)) - host_status = DID_NO_CONNECT; - else if (!(sts->state_flags & SF_GOT_TARGET)) - host_status = DID_BAD_TARGET; - else if (!(sts->state_flags & SF_SENT_CDB)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_TRANSFERRED_DATA)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_STATUS)) - host_status = DID_ERROR; - else if (!(sts->state_flags & SF_GOT_SENSE)) - host_status = DID_ERROR; - break; - case CS_DMA_ERROR: - case CS_TRANSPORT_ERROR: - host_status = DID_ERROR; - break; - case CS_RESET_OCCURRED: - case CS_BUS_RESET: - host_status = DID_RESET; - break; - case CS_ABORTED: - host_status = DID_ABORT; - break; - case CS_TIMEOUT: - host_status = DID_TIME_OUT; - break; - case CS_DATA_OVERRUN: - case CS_COMMAND_OVERRUN: - case CS_STATUS_OVERRUN: - case CS_BAD_MESSAGE: - case CS_NO_MESSAGE_OUT: - case CS_EXT_ID_FAILED: - case CS_IDE_MSG_FAILED: - case CS_ABORT_MSG_FAILED: - case CS_NOP_MSG_FAILED: - case CS_PARITY_ERROR_MSG_FAILED: - case CS_DEVICE_RESET_MSG_FAILED: - case CS_ID_MSG_FAILED: - case CS_UNEXP_BUS_FREE: - host_status = DID_ERROR; - break; - case CS_DATA_UNDERRUN: - host_status = DID_OK; - break; - default: - printk(KERN_EMERG "qlogicpti%d: unknown completion status 0x%04x\n", - id, sts->completion_status); - host_status = DID_ERROR; - break; - } - - return (sts->scsi_status & STATUS_MASK) | (host_status << 16); -} - -static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti) -{ - struct scsi_cmnd *Cmnd, *done_queue = NULL; - struct Status_Entry *sts; - u_int in_ptr, out_ptr; - - if (!(sbus_readw(qpti->qregs + SBUS_STAT) & SBUS_STAT_RINT)) - return NULL; - - in_ptr = sbus_readw(qpti->qregs + MBOX5); - sbus_writew(HCCTRL_CRIRQ, qpti->qregs + HCCTRL); - if (sbus_readw(qpti->qregs + SBUS_SEMAPHORE) & SBUS_SEMAPHORE_LCK) { - switch (sbus_readw(qpti->qregs + MBOX0)) { - case ASYNC_SCSI_BUS_RESET: - case EXECUTION_TIMEOUT_RESET: - qpti->send_marker = 1; - break; - case INVALID_COMMAND: - case HOST_INTERFACE_ERROR: - case COMMAND_ERROR: - case COMMAND_PARAM_ERROR: - break; - }; - sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE); - } - - /* This looks like a network driver! */ - out_ptr = qpti->res_out_ptr; - while (out_ptr != in_ptr) { - u_int cmd_slot; - - sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr]; - out_ptr = NEXT_RES_PTR(out_ptr); - - /* We store an index in the handle, not the pointer in - * some form. This avoids problems due to the fact - * that the handle provided is only 32-bits. -DaveM - */ - cmd_slot = sts->handle; - Cmnd = qpti->cmd_slots[cmd_slot]; - qpti->cmd_slots[cmd_slot] = NULL; - - if (sts->completion_status == CS_RESET_OCCURRED || - sts->completion_status == CS_ABORTED || - (sts->status_flags & STF_BUS_RESET)) - qpti->send_marker = 1; - - if (sts->state_flags & SF_GOT_SENSE) - memcpy(Cmnd->sense_buffer, sts->req_sense_data, - SCSI_SENSE_BUFFERSIZE); - - if (sts->hdr.entry_type == ENTRY_STATUS) - Cmnd->result = - qlogicpti_return_status(sts, qpti->qpti_id); - else - Cmnd->result = DID_ERROR << 16; - - if (scsi_bufflen(Cmnd)) - dma_unmap_sg(&qpti->op->dev, - scsi_sglist(Cmnd), scsi_sg_count(Cmnd), - Cmnd->sc_data_direction); - - qpti->cmd_count[Cmnd->device->id]--; - sbus_writew(out_ptr, qpti->qregs + MBOX5); - Cmnd->host_scribble = (unsigned char *) done_queue; - done_queue = Cmnd; - } - qpti->res_out_ptr = out_ptr; - - return done_queue; -} - -static irqreturn_t qpti_intr(int irq, void *dev_id) -{ - struct qlogicpti *qpti = dev_id; - unsigned long flags; - struct scsi_cmnd *dq; - - spin_lock_irqsave(qpti->qhost->host_lock, flags); - dq = qlogicpti_intr_handler(qpti); - - if (dq != NULL) { - do { - struct scsi_cmnd *next; - - next = (struct scsi_cmnd *) dq->host_scribble; - dq->scsi_done(dq); - dq = next; - } while (dq != NULL); - } - spin_unlock_irqrestore(qpti->qhost->host_lock, flags); - - return IRQ_HANDLED; -} - -static int qlogicpti_abort(struct scsi_cmnd *Cmnd) -{ - u_short param[6]; - struct Scsi_Host *host = Cmnd->device->host; - struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - int return_status = SUCCESS; - u32 cmd_cookie; - int i; - - printk(KERN_WARNING "qlogicpti%d: Aborting cmd for tgt[%d] lun[%d]\n", - qpti->qpti_id, (int)Cmnd->device->id, (int)Cmnd->device->lun); - - qlogicpti_disable_irqs(qpti); - - /* Find the 32-bit cookie we gave to the firmware for - * this command. - */ - for (i = 0; i < QLOGICPTI_REQ_QUEUE_LEN + 1; i++) - if (qpti->cmd_slots[i] == Cmnd) - break; - cmd_cookie = i; - - param[0] = MBOX_ABORT; - param[1] = (((u_short) Cmnd->device->id) << 8) | Cmnd->device->lun; - param[2] = cmd_cookie >> 16; - param[3] = cmd_cookie & 0xffff; - if (qlogicpti_mbox_command(qpti, param, 0) || - (param[0] != MBOX_COMMAND_COMPLETE)) { - printk(KERN_EMERG "qlogicpti%d: scsi abort failure: %x\n", - qpti->qpti_id, param[0]); - return_status = FAILED; - } - - qlogicpti_enable_irqs(qpti); - - return return_status; -} - -static int qlogicpti_reset(struct scsi_cmnd *Cmnd) -{ - u_short param[6]; - struct Scsi_Host *host = Cmnd->device->host; - struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata; - int return_status = SUCCESS; - - printk(KERN_WARNING "qlogicpti%d: Resetting SCSI bus!\n", - qpti->qpti_id); - - qlogicpti_disable_irqs(qpti); - - param[0] = MBOX_BUS_RESET; - param[1] = qpti->host_param.bus_reset_delay; - if (qlogicpti_mbox_command(qpti, param, 0) || - (param[0] != MBOX_COMMAND_COMPLETE)) { - printk(KERN_EMERG "qlogicisp%d: scsi bus reset failure: %x\n", - qpti->qpti_id, param[0]); - return_status = FAILED; - } - - qlogicpti_enable_irqs(qpti); - - return return_status; -} - -static struct scsi_host_template qpti_template = { - .module = THIS_MODULE, - .name = "qlogicpti", - .info = qlogicpti_info, - .queuecommand = qlogicpti_queuecommand, - .slave_configure = qlogicpti_slave_configure, - .eh_abort_handler = qlogicpti_abort, - .eh_bus_reset_handler = qlogicpti_reset, - .can_queue = QLOGICPTI_REQ_QUEUE_LEN, - .this_id = 7, - .sg_tablesize = QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN), - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -static const struct of_device_id qpti_match[]; -static int __devinit qpti_sbus_probe(struct platform_device *op) -{ - const struct of_device_id *match; - struct scsi_host_template *tpnt; - struct device_node *dp = op->dev.of_node; - struct Scsi_Host *host; - struct qlogicpti *qpti; - static int nqptis; - const char *fcode; - - match = of_match_device(qpti_match, &op->dev); - if (!match) - return -EINVAL; - tpnt = match->data; - - /* Sometimes Antares cards come up not completely - * setup, and we get a report of a zero IRQ. - */ - if (op->archdata.irqs[0] == 0) - return -ENODEV; - - host = scsi_host_alloc(tpnt, sizeof(struct qlogicpti)); - if (!host) - return -ENOMEM; - - qpti = shost_priv(host); - - host->max_id = MAX_TARGETS; - qpti->qhost = host; - qpti->op = op; - qpti->qpti_id = nqptis; - strcpy(qpti->prom_name, op->dev.of_node->name); - qpti->is_pti = strcmp(qpti->prom_name, "QLGC,isp"); - - if (qpti_map_regs(qpti) < 0) - goto fail_unlink; - - if (qpti_register_irq(qpti) < 0) - goto fail_unmap_regs; - - qpti_get_scsi_id(qpti); - qpti_get_bursts(qpti); - qpti_get_clock(qpti); - - /* Clear out scsi_cmnd array. */ - memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots)); - - if (qpti_map_queues(qpti) < 0) - goto fail_free_irq; - - /* Load the firmware. */ - if (qlogicpti_load_firmware(qpti)) - goto fail_unmap_queues; - if (qpti->is_pti) { - /* Check the PTI status reg. */ - if (qlogicpti_verify_tmon(qpti)) - goto fail_unmap_queues; - } - - /* Reset the ISP and init res/req queues. */ - if (qlogicpti_reset_hardware(host)) - goto fail_unmap_queues; - - printk("(Firmware v%d.%d.%d)", qpti->fware_majrev, - qpti->fware_minrev, qpti->fware_micrev); - - fcode = of_get_property(dp, "isp-fcode", NULL); - if (fcode && fcode[0]) - printk("(FCode %s)", fcode); - if (of_find_property(dp, "differential", NULL) != NULL) - qpti->differential = 1; - - printk("\nqlogicpti%d: [%s Wide, using %s interface]\n", - qpti->qpti_id, - (qpti->ultra ? "Ultra" : "Fast"), - (qpti->differential ? "differential" : "single ended")); - - if (scsi_add_host(host, &op->dev)) { - printk("qlogicpti%d: Failed scsi_add_host\n", qpti->qpti_id); - goto fail_unmap_queues; - } - - dev_set_drvdata(&op->dev, qpti); - - qpti_chain_add(qpti); - - scsi_scan_host(host); - nqptis++; - - return 0; - -fail_unmap_queues: -#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - dma_free_coherent(&op->dev, - QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - dma_free_coherent(&op->dev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - qpti->req_cpu, qpti->req_dvma); -#undef QSIZE - -fail_unmap_regs: - of_iounmap(&op->resource[0], qpti->qregs, - resource_size(&op->resource[0])); - if (qpti->is_pti) - of_iounmap(&op->resource[0], qpti->sreg, - sizeof(unsigned char)); - -fail_free_irq: - free_irq(qpti->irq, qpti); - -fail_unlink: - scsi_host_put(host); - - return -ENODEV; -} - -static int __devexit qpti_sbus_remove(struct platform_device *op) -{ - struct qlogicpti *qpti = dev_get_drvdata(&op->dev); - - qpti_chain_del(qpti); - - scsi_remove_host(qpti->qhost); - - /* Shut up the card. */ - sbus_writew(0, qpti->qregs + SBUS_CTRL); - - /* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */ - free_irq(qpti->irq, qpti); - -#define QSIZE(entries) (((entries) + 1) * QUEUE_ENTRY_LEN) - dma_free_coherent(&op->dev, - QSIZE(RES_QUEUE_LEN), - qpti->res_cpu, qpti->res_dvma); - dma_free_coherent(&op->dev, - QSIZE(QLOGICPTI_REQ_QUEUE_LEN), - qpti->req_cpu, qpti->req_dvma); -#undef QSIZE - - of_iounmap(&op->resource[0], qpti->qregs, - resource_size(&op->resource[0])); - if (qpti->is_pti) - of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char)); - - scsi_host_put(qpti->qhost); - - return 0; -} - -static const struct of_device_id qpti_match[] = { - { - .name = "ptisp", - .data = &qpti_template, - }, - { - .name = "PTI,ptisp", - .data = &qpti_template, - }, - { - .name = "QLGC,isp", - .data = &qpti_template, - }, - { - .name = "SUNW,isp", - .data = &qpti_template, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, qpti_match); - -static struct platform_driver qpti_sbus_driver = { - .driver = { - .name = "qpti", - .owner = THIS_MODULE, - .of_match_table = qpti_match, - }, - .probe = qpti_sbus_probe, - .remove = __devexit_p(qpti_sbus_remove), -}; - -static int __init qpti_init(void) -{ - return platform_driver_register(&qpti_sbus_driver); -} - -static void __exit qpti_exit(void) -{ - platform_driver_unregister(&qpti_sbus_driver); -} - -MODULE_DESCRIPTION("QlogicISP SBUS driver"); -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("2.1"); -MODULE_FIRMWARE("qlogic/isp1000.bin"); - -module_init(qpti_init); -module_exit(qpti_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/qlogicpti.h b/ANDROID_3.4.5/drivers/scsi/qlogicpti.h deleted file mode 100644 index 4377e87e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/qlogicpti.h +++ /dev/null @@ -1,507 +0,0 @@ -/* qlogicpti.h: Performance Technologies QlogicISP sbus card defines. - * - * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) - */ - -#ifndef _QLOGICPTI_H -#define _QLOGICPTI_H - -/* Qlogic/SBUS controller registers. */ -#define SBUS_CFG1 0x006UL -#define SBUS_CTRL 0x008UL -#define SBUS_STAT 0x00aUL -#define SBUS_SEMAPHORE 0x00cUL -#define CMD_DMA_CTRL 0x022UL -#define DATA_DMA_CTRL 0x042UL -#define MBOX0 0x080UL -#define MBOX1 0x082UL -#define MBOX2 0x084UL -#define MBOX3 0x086UL -#define MBOX4 0x088UL -#define MBOX5 0x08aUL -#define CPU_CMD 0x214UL -#define CPU_ORIDE 0x224UL -#define CPU_PCTRL 0x272UL -#define CPU_PDIFF 0x276UL -#define RISC_PSR 0x420UL -#define RISC_MTREG 0x42EUL -#define HCCTRL 0x440UL - -/* SCSI parameters for this driver. */ -#define MAX_TARGETS 16 -#define MAX_LUNS 8 - -/* With the qlogic interface, every queue slot can hold a SCSI - * command with up to 4 scatter/gather entries. If we need more - * than 4 entries, continuation entries can be used that hold - * another 7 entries each. Unlike for other drivers, this means - * that the maximum number of scatter/gather entries we can - * support at any given time is a function of the number of queue - * slots available. That is, host->can_queue and host->sg_tablesize - * are dynamic and _not_ independent. This all works fine because - * requests are queued serially and the scatter/gather limit is - * determined for each queue request anew. - */ -#define QLOGICPTI_REQ_QUEUE_LEN 255 /* must be power of two - 1 */ -#define QLOGICPTI_MAX_SG(ql) (4 + (((ql) > 0) ? 7*((ql) - 1) : 0)) - -/* mailbox command complete status codes */ -#define MBOX_COMMAND_COMPLETE 0x4000 -#define INVALID_COMMAND 0x4001 -#define HOST_INTERFACE_ERROR 0x4002 -#define TEST_FAILED 0x4003 -#define COMMAND_ERROR 0x4005 -#define COMMAND_PARAM_ERROR 0x4006 - -/* async event status codes */ -#define ASYNC_SCSI_BUS_RESET 0x8001 -#define SYSTEM_ERROR 0x8002 -#define REQUEST_TRANSFER_ERROR 0x8003 -#define RESPONSE_TRANSFER_ERROR 0x8004 -#define REQUEST_QUEUE_WAKEUP 0x8005 -#define EXECUTION_TIMEOUT_RESET 0x8006 - -/* Am I fucking pedantic or what? */ -struct Entry_header { -#ifdef __BIG_ENDIAN - u8 entry_cnt; - u8 entry_type; - u8 flags; - u8 sys_def_1; -#else /* __LITTLE_ENDIAN */ - u8 entry_type; - u8 entry_cnt; - u8 sys_def_1; - u8 flags; -#endif -}; - -/* entry header type commands */ -#define ENTRY_COMMAND 1 -#define ENTRY_CONTINUATION 2 -#define ENTRY_STATUS 3 -#define ENTRY_MARKER 4 -#define ENTRY_EXTENDED_COMMAND 5 - -/* entry header flag definitions */ -#define EFLAG_CONTINUATION 1 -#define EFLAG_BUSY 2 -#define EFLAG_BAD_HEADER 4 -#define EFLAG_BAD_PAYLOAD 8 - -struct dataseg { - u32 d_base; - u32 d_count; -}; - -struct Command_Entry { - struct Entry_header hdr; - u32 handle; -#ifdef __BIG_ENDIAN - u8 target_id; - u8 target_lun; -#else /* __LITTLE_ENDIAN */ - u8 target_lun; - u8 target_id; -#endif - u16 cdb_length; - u16 control_flags; - u16 rsvd; - u16 time_out; - u16 segment_cnt; - u8 cdb[12]; - struct dataseg dataseg[4]; -}; - -/* command entry control flag definitions */ -#define CFLAG_NODISC 0x01 -#define CFLAG_HEAD_TAG 0x02 -#define CFLAG_ORDERED_TAG 0x04 -#define CFLAG_SIMPLE_TAG 0x08 -#define CFLAG_TAR_RTN 0x10 -#define CFLAG_READ 0x20 -#define CFLAG_WRITE 0x40 - -struct Ext_Command_Entry { - struct Entry_header hdr; - u32 handle; -#ifdef __BIG_ENDIAN - u8 target_id; - u8 target_lun; -#else /* __LITTLE_ENDIAN */ - u8 target_lun; - u8 target_id; -#endif - u16 cdb_length; - u16 control_flags; - u16 rsvd; - u16 time_out; - u16 segment_cnt; - u8 cdb[44]; -}; - -struct Continuation_Entry { - struct Entry_header hdr; - u32 reserved; - struct dataseg dataseg[7]; -}; - -struct Marker_Entry { - struct Entry_header hdr; - u32 reserved; -#ifdef __BIG_ENDIAN - u8 target_id; - u8 target_lun; -#else /* __LITTLE_ENDIAN */ - u8 target_lun; - u8 target_id; -#endif -#ifdef __BIG_ENDIAN - u8 rsvd; - u8 modifier; -#else /* __LITTLE_ENDIAN */ - u8 modifier; - u8 rsvd; -#endif - u8 rsvds[52]; -}; - -/* marker entry modifier definitions */ -#define SYNC_DEVICE 0 -#define SYNC_TARGET 1 -#define SYNC_ALL 2 - -struct Status_Entry { - struct Entry_header hdr; - u32 handle; - u16 scsi_status; - u16 completion_status; - u16 state_flags; - u16 status_flags; - u16 time; - u16 req_sense_len; - u32 residual; - u8 rsvd[8]; - u8 req_sense_data[32]; -}; - -/* status entry completion status definitions */ -#define CS_COMPLETE 0x0000 -#define CS_INCOMPLETE 0x0001 -#define CS_DMA_ERROR 0x0002 -#define CS_TRANSPORT_ERROR 0x0003 -#define CS_RESET_OCCURRED 0x0004 -#define CS_ABORTED 0x0005 -#define CS_TIMEOUT 0x0006 -#define CS_DATA_OVERRUN 0x0007 -#define CS_COMMAND_OVERRUN 0x0008 -#define CS_STATUS_OVERRUN 0x0009 -#define CS_BAD_MESSAGE 0x000a -#define CS_NO_MESSAGE_OUT 0x000b -#define CS_EXT_ID_FAILED 0x000c -#define CS_IDE_MSG_FAILED 0x000d -#define CS_ABORT_MSG_FAILED 0x000e -#define CS_REJECT_MSG_FAILED 0x000f -#define CS_NOP_MSG_FAILED 0x0010 -#define CS_PARITY_ERROR_MSG_FAILED 0x0011 -#define CS_DEVICE_RESET_MSG_FAILED 0x0012 -#define CS_ID_MSG_FAILED 0x0013 -#define CS_UNEXP_BUS_FREE 0x0014 -#define CS_DATA_UNDERRUN 0x0015 -#define CS_BUS_RESET 0x001c - -/* status entry state flag definitions */ -#define SF_GOT_BUS 0x0100 -#define SF_GOT_TARGET 0x0200 -#define SF_SENT_CDB 0x0400 -#define SF_TRANSFERRED_DATA 0x0800 -#define SF_GOT_STATUS 0x1000 -#define SF_GOT_SENSE 0x2000 - -/* status entry status flag definitions */ -#define STF_DISCONNECT 0x0001 -#define STF_SYNCHRONOUS 0x0002 -#define STF_PARITY_ERROR 0x0004 -#define STF_BUS_RESET 0x0008 -#define STF_DEVICE_RESET 0x0010 -#define STF_ABORTED 0x0020 -#define STF_TIMEOUT 0x0040 -#define STF_NEGOTIATION 0x0080 - -/* mailbox commands */ -#define MBOX_NO_OP 0x0000 -#define MBOX_LOAD_RAM 0x0001 -#define MBOX_EXEC_FIRMWARE 0x0002 -#define MBOX_DUMP_RAM 0x0003 -#define MBOX_WRITE_RAM_WORD 0x0004 -#define MBOX_READ_RAM_WORD 0x0005 -#define MBOX_MAILBOX_REG_TEST 0x0006 -#define MBOX_VERIFY_CHECKSUM 0x0007 -#define MBOX_ABOUT_FIRMWARE 0x0008 -#define MBOX_CHECK_FIRMWARE 0x000e -#define MBOX_INIT_REQ_QUEUE 0x0010 -#define MBOX_INIT_RES_QUEUE 0x0011 -#define MBOX_EXECUTE_IOCB 0x0012 -#define MBOX_WAKE_UP 0x0013 -#define MBOX_STOP_FIRMWARE 0x0014 -#define MBOX_ABORT 0x0015 -#define MBOX_ABORT_DEVICE 0x0016 -#define MBOX_ABORT_TARGET 0x0017 -#define MBOX_BUS_RESET 0x0018 -#define MBOX_STOP_QUEUE 0x0019 -#define MBOX_START_QUEUE 0x001a -#define MBOX_SINGLE_STEP_QUEUE 0x001b -#define MBOX_ABORT_QUEUE 0x001c -#define MBOX_GET_DEV_QUEUE_STATUS 0x001d -#define MBOX_GET_FIRMWARE_STATUS 0x001f -#define MBOX_GET_INIT_SCSI_ID 0x0020 -#define MBOX_GET_SELECT_TIMEOUT 0x0021 -#define MBOX_GET_RETRY_COUNT 0x0022 -#define MBOX_GET_TAG_AGE_LIMIT 0x0023 -#define MBOX_GET_CLOCK_RATE 0x0024 -#define MBOX_GET_ACT_NEG_STATE 0x0025 -#define MBOX_GET_ASYNC_DATA_SETUP_TIME 0x0026 -#define MBOX_GET_SBUS_PARAMS 0x0027 -#define MBOX_GET_TARGET_PARAMS 0x0028 -#define MBOX_GET_DEV_QUEUE_PARAMS 0x0029 -#define MBOX_SET_INIT_SCSI_ID 0x0030 -#define MBOX_SET_SELECT_TIMEOUT 0x0031 -#define MBOX_SET_RETRY_COUNT 0x0032 -#define MBOX_SET_TAG_AGE_LIMIT 0x0033 -#define MBOX_SET_CLOCK_RATE 0x0034 -#define MBOX_SET_ACTIVE_NEG_STATE 0x0035 -#define MBOX_SET_ASYNC_DATA_SETUP_TIME 0x0036 -#define MBOX_SET_SBUS_CONTROL_PARAMS 0x0037 -#define MBOX_SET_TARGET_PARAMS 0x0038 -#define MBOX_SET_DEV_QUEUE_PARAMS 0x0039 - -struct host_param { - u_short initiator_scsi_id; - u_short bus_reset_delay; - u_short retry_count; - u_short retry_delay; - u_short async_data_setup_time; - u_short req_ack_active_negation; - u_short data_line_active_negation; - u_short data_dma_burst_enable; - u_short command_dma_burst_enable; - u_short tag_aging; - u_short selection_timeout; - u_short max_queue_depth; -}; - -/* - * Device Flags: - * - * Bit Name - * --------- - * 7 Disconnect Privilege - * 6 Parity Checking - * 5 Wide Data Transfers - * 4 Synchronous Data Transfers - * 3 Tagged Queuing - * 2 Automatic Request Sense - * 1 Stop Queue on Check Condition - * 0 Renegotiate on Error - */ - -struct dev_param { - u_short device_flags; - u_short execution_throttle; - u_short synchronous_period; - u_short synchronous_offset; - u_short device_enable; - u_short reserved; /* pad */ -}; - -/* - * The result queue can be quite a bit smaller since continuation entries - * do not show up there: - */ -#define RES_QUEUE_LEN 255 /* Must be power of two - 1 */ -#define QUEUE_ENTRY_LEN 64 - -#define NEXT_REQ_PTR(wheee) (((wheee) + 1) & QLOGICPTI_REQ_QUEUE_LEN) -#define NEXT_RES_PTR(wheee) (((wheee) + 1) & RES_QUEUE_LEN) -#define PREV_REQ_PTR(wheee) (((wheee) - 1) & QLOGICPTI_REQ_QUEUE_LEN) -#define PREV_RES_PTR(wheee) (((wheee) - 1) & RES_QUEUE_LEN) - -struct pti_queue_entry { - char __opaque[QUEUE_ENTRY_LEN]; -}; - -struct scsi_cmnd; - -/* Software state for the driver. */ -struct qlogicpti { - /* These are the hot elements in the cache, so they come first. */ - void __iomem *qregs; /* Adapter registers */ - struct pti_queue_entry *res_cpu; /* Ptr to RESPONSE bufs (CPU) */ - struct pti_queue_entry *req_cpu; /* Ptr to REQUEST bufs (CPU) */ - - u_int req_in_ptr; /* index of next request slot */ - u_int res_out_ptr; /* index of next result slot */ - long send_marker; /* must we send a marker? */ - struct platform_device *op; - unsigned long __pad; - - int cmd_count[MAX_TARGETS]; - unsigned long tag_ages[MAX_TARGETS]; - - /* The cmd->handler is only 32-bits, so that things work even on monster - * Ex000 sparc64 machines with >4GB of ram we just keep track of the - * scsi command pointers here. This is essentially what Matt Jacob does. -DaveM - */ - struct scsi_cmnd *cmd_slots[QLOGICPTI_REQ_QUEUE_LEN + 1]; - - /* The rest of the elements are unimportant for performance. */ - struct qlogicpti *next; - __u32 res_dvma; /* Ptr to RESPONSE bufs (DVMA)*/ - __u32 req_dvma; /* Ptr to REQUEST bufs (DVMA) */ - u_char fware_majrev, fware_minrev, fware_micrev; - struct Scsi_Host *qhost; - int qpti_id; - int scsi_id; - int prom_node; - char prom_name[64]; - int irq; - char differential, ultra, clock; - unsigned char bursts; - struct host_param host_param; - struct dev_param dev_param[MAX_TARGETS]; - - void __iomem *sreg; -#define SREG_TPOWER 0x80 /* State of termpwr */ -#define SREG_FUSE 0x40 /* State of on board fuse */ -#define SREG_PDISAB 0x20 /* Disable state for power on */ -#define SREG_DSENSE 0x10 /* Sense for differential */ -#define SREG_IMASK 0x0c /* Interrupt level */ -#define SREG_SPMASK 0x03 /* Mask for switch pack */ - unsigned char swsreg; - unsigned int - gotirq : 1, /* this instance got an irq */ - is_pti : 1; /* Non-zero if this is a PTI board. */ -}; - -/* How to twiddle them bits... */ - -/* SBUS config register one. */ -#define SBUS_CFG1_EPAR 0x0100 /* Enable parity checking */ -#define SBUS_CFG1_FMASK 0x00f0 /* Forth code cycle mask */ -#define SBUS_CFG1_BENAB 0x0004 /* Burst dvma enable */ -#define SBUS_CFG1_B64 0x0003 /* Enable 64byte bursts */ -#define SBUS_CFG1_B32 0x0002 /* Enable 32byte bursts */ -#define SBUS_CFG1_B16 0x0001 /* Enable 16byte bursts */ -#define SBUS_CFG1_B8 0x0008 /* Enable 8byte bursts */ - -/* SBUS control register */ -#define SBUS_CTRL_EDIRQ 0x0020 /* Enable Data DVMA Interrupts */ -#define SBUS_CTRL_ECIRQ 0x0010 /* Enable Command DVMA Interrupts */ -#define SBUS_CTRL_ESIRQ 0x0008 /* Enable SCSI Processor Interrupts */ -#define SBUS_CTRL_ERIRQ 0x0004 /* Enable RISC Processor Interrupts */ -#define SBUS_CTRL_GENAB 0x0002 /* Global Interrupt Enable */ -#define SBUS_CTRL_RESET 0x0001 /* Soft Reset */ - -/* SBUS status register */ -#define SBUS_STAT_DINT 0x0020 /* Data DVMA IRQ pending */ -#define SBUS_STAT_CINT 0x0010 /* Command DVMA IRQ pending */ -#define SBUS_STAT_SINT 0x0008 /* SCSI Processor IRQ pending */ -#define SBUS_STAT_RINT 0x0004 /* RISC Processor IRQ pending */ -#define SBUS_STAT_GINT 0x0002 /* Global IRQ pending */ - -/* SBUS semaphore register */ -#define SBUS_SEMAPHORE_STAT 0x0002 /* Semaphore status bit */ -#define SBUS_SEMAPHORE_LCK 0x0001 /* Semaphore lock bit */ - -/* DVMA control register */ -#define DMA_CTRL_CSUSPEND 0x0010 /* DMA channel suspend */ -#define DMA_CTRL_CCLEAR 0x0008 /* DMA channel clear and reset */ -#define DMA_CTRL_FCLEAR 0x0004 /* DMA fifo clear */ -#define DMA_CTRL_CIRQ 0x0002 /* DMA irq clear */ -#define DMA_CTRL_DMASTART 0x0001 /* DMA transfer start */ - -/* SCSI processor override register */ -#define CPU_ORIDE_ETRIG 0x8000 /* External trigger enable */ -#define CPU_ORIDE_STEP 0x4000 /* Single step mode enable */ -#define CPU_ORIDE_BKPT 0x2000 /* Breakpoint reg enable */ -#define CPU_ORIDE_PWRITE 0x1000 /* SCSI pin write enable */ -#define CPU_ORIDE_OFORCE 0x0800 /* Force outputs on */ -#define CPU_ORIDE_LBACK 0x0400 /* SCSI loopback enable */ -#define CPU_ORIDE_PTEST 0x0200 /* Parity test enable */ -#define CPU_ORIDE_TENAB 0x0100 /* SCSI pins tristate enable */ -#define CPU_ORIDE_TPINS 0x0080 /* SCSI pins enable */ -#define CPU_ORIDE_FRESET 0x0008 /* FIFO reset */ -#define CPU_ORIDE_CTERM 0x0004 /* Command terminate */ -#define CPU_ORIDE_RREG 0x0002 /* Reset SCSI processor regs */ -#define CPU_ORIDE_RMOD 0x0001 /* Reset SCSI processor module */ - -/* SCSI processor commands */ -#define CPU_CMD_BRESET 0x300b /* Reset SCSI bus */ - -/* SCSI processor pin control register */ -#define CPU_PCTRL_PVALID 0x8000 /* Phase bits are valid */ -#define CPU_PCTRL_PHI 0x0400 /* Parity bit high */ -#define CPU_PCTRL_PLO 0x0200 /* Parity bit low */ -#define CPU_PCTRL_REQ 0x0100 /* REQ bus signal */ -#define CPU_PCTRL_ACK 0x0080 /* ACK bus signal */ -#define CPU_PCTRL_RST 0x0040 /* RST bus signal */ -#define CPU_PCTRL_BSY 0x0020 /* BSY bus signal */ -#define CPU_PCTRL_SEL 0x0010 /* SEL bus signal */ -#define CPU_PCTRL_ATN 0x0008 /* ATN bus signal */ -#define CPU_PCTRL_MSG 0x0004 /* MSG bus signal */ -#define CPU_PCTRL_CD 0x0002 /* CD bus signal */ -#define CPU_PCTRL_IO 0x0001 /* IO bus signal */ - -/* SCSI processor differential pins register */ -#define CPU_PDIFF_SENSE 0x0200 /* Differential sense */ -#define CPU_PDIFF_MODE 0x0100 /* Differential mode */ -#define CPU_PDIFF_OENAB 0x0080 /* Outputs enable */ -#define CPU_PDIFF_PMASK 0x007c /* Differential control pins */ -#define CPU_PDIFF_TGT 0x0002 /* Target mode enable */ -#define CPU_PDIFF_INIT 0x0001 /* Initiator mode enable */ - -/* RISC processor status register */ -#define RISC_PSR_FTRUE 0x8000 /* Force true */ -#define RISC_PSR_LCD 0x4000 /* Loop counter shows done status */ -#define RISC_PSR_RIRQ 0x2000 /* RISC irq status */ -#define RISC_PSR_TOFLOW 0x1000 /* Timer overflow (rollover) */ -#define RISC_PSR_AOFLOW 0x0800 /* Arithmetic overflow */ -#define RISC_PSR_AMSB 0x0400 /* Arithmetic big endian */ -#define RISC_PSR_ACARRY 0x0200 /* Arithmetic carry */ -#define RISC_PSR_AZERO 0x0100 /* Arithmetic zero */ -#define RISC_PSR_ULTRA 0x0020 /* Ultra mode */ -#define RISC_PSR_DIRQ 0x0010 /* DVMA interrupt */ -#define RISC_PSR_SIRQ 0x0008 /* SCSI processor interrupt */ -#define RISC_PSR_HIRQ 0x0004 /* Host interrupt */ -#define RISC_PSR_IPEND 0x0002 /* Interrupt pending */ -#define RISC_PSR_FFALSE 0x0001 /* Force false */ - -/* RISC processor memory timing register */ -#define RISC_MTREG_P1DFLT 0x1200 /* Default read/write timing, pg1 */ -#define RISC_MTREG_P0DFLT 0x0012 /* Default read/write timing, pg0 */ -#define RISC_MTREG_P1ULTRA 0x2300 /* Ultra-mode rw timing, pg1 */ -#define RISC_MTREG_P0ULTRA 0x0023 /* Ultra-mode rw timing, pg0 */ - -/* Host command/ctrl register */ -#define HCCTRL_NOP 0x0000 /* CMD: No operation */ -#define HCCTRL_RESET 0x1000 /* CMD: Reset RISC cpu */ -#define HCCTRL_PAUSE 0x2000 /* CMD: Pause RISC cpu */ -#define HCCTRL_REL 0x3000 /* CMD: Release paused RISC cpu */ -#define HCCTRL_STEP 0x4000 /* CMD: Single step RISC cpu */ -#define HCCTRL_SHIRQ 0x5000 /* CMD: Set host irq */ -#define HCCTRL_CHIRQ 0x6000 /* CMD: Clear host irq */ -#define HCCTRL_CRIRQ 0x7000 /* CMD: Clear RISC cpu irq */ -#define HCCTRL_BKPT 0x8000 /* CMD: Breakpoint enables change */ -#define HCCTRL_TMODE 0xf000 /* CMD: Enable test mode */ -#define HCCTRL_HIRQ 0x0080 /* Host IRQ pending */ -#define HCCTRL_RRIP 0x0040 /* RISC cpu reset in happening now */ -#define HCCTRL_RPAUSED 0x0020 /* RISC cpu is paused now */ -#define HCCTRL_EBENAB 0x0010 /* External breakpoint enable */ -#define HCCTRL_B1ENAB 0x0008 /* Breakpoint 1 enable */ -#define HCCTRL_B0ENAB 0x0004 /* Breakpoint 0 enable */ - -/* For our interrupt engine. */ -#define for_each_qlogicpti(qp) \ - for((qp) = qptichain; (qp); (qp) = (qp)->next) - -#endif /* !(_QLOGICPTI_H) */ diff --git a/ANDROID_3.4.5/drivers/scsi/raid_class.c b/ANDROID_3.4.5/drivers/scsi/raid_class.c deleted file mode 100644 index 2c146b44..00000000 --- a/ANDROID_3.4.5/drivers/scsi/raid_class.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * raid_class.c - implementation of a simple raid visualisation class - * - * Copyright (c) 2005 - James Bottomley - * - * This file is licensed under GPLv2 - * - * This class is designed to allow raid attributes to be visualised and - * manipulated in a form independent of the underlying raid. Ultimately this - * should work for both hardware and software raids. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define RAID_NUM_ATTRS 3 - -struct raid_internal { - struct raid_template r; - struct raid_function_template *f; - /* The actual attributes */ - struct device_attribute private_attrs[RAID_NUM_ATTRS]; - /* The array of null terminated pointers to attributes - * needed by scsi_sysfs.c */ - struct device_attribute *attrs[RAID_NUM_ATTRS + 1]; -}; - -struct raid_component { - struct list_head node; - struct device dev; - int num; -}; - -#define to_raid_internal(tmpl) container_of(tmpl, struct raid_internal, r) - -#define tc_to_raid_internal(tcont) ({ \ - struct raid_template *r = \ - container_of(tcont, struct raid_template, raid_attrs); \ - to_raid_internal(r); \ -}) - -#define ac_to_raid_internal(acont) ({ \ - struct transport_container *tc = \ - container_of(acont, struct transport_container, ac); \ - tc_to_raid_internal(tc); \ -}) - -#define device_to_raid_internal(dev) ({ \ - struct attribute_container *ac = \ - attribute_container_classdev_to_container(dev); \ - ac_to_raid_internal(ac); \ -}) - - -static int raid_match(struct attribute_container *cont, struct device *dev) -{ - /* We have to look for every subsystem that could house - * emulated RAID devices, so start with SCSI */ - struct raid_internal *i = ac_to_raid_internal(cont); - -#if defined(CONFIG_SCSI) || defined(CONFIG_SCSI_MODULE) - if (scsi_is_sdev_device(dev)) { - struct scsi_device *sdev = to_scsi_device(dev); - - if (i->f->cookie != sdev->host->hostt) - return 0; - - return i->f->is_raid(dev); - } -#endif - /* FIXME: look at other subsystems too */ - return 0; -} - -static int raid_setup(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct raid_data *rd; - - BUG_ON(dev_get_drvdata(cdev)); - - rd = kzalloc(sizeof(*rd), GFP_KERNEL); - if (!rd) - return -ENOMEM; - - INIT_LIST_HEAD(&rd->component_list); - dev_set_drvdata(cdev, rd); - - return 0; -} - -static int raid_remove(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct raid_data *rd = dev_get_drvdata(cdev); - struct raid_component *rc, *next; - dev_printk(KERN_ERR, dev, "RAID REMOVE\n"); - dev_set_drvdata(cdev, NULL); - list_for_each_entry_safe(rc, next, &rd->component_list, node) { - list_del(&rc->node); - dev_printk(KERN_ERR, rc->dev.parent, "RAID COMPONENT REMOVE\n"); - device_unregister(&rc->dev); - } - dev_printk(KERN_ERR, dev, "RAID REMOVE DONE\n"); - kfree(rd); - return 0; -} - -static DECLARE_TRANSPORT_CLASS(raid_class, - "raid_devices", - raid_setup, - raid_remove, - NULL); - -static const struct { - enum raid_state value; - char *name; -} raid_states[] = { - { RAID_STATE_UNKNOWN, "unknown" }, - { RAID_STATE_ACTIVE, "active" }, - { RAID_STATE_DEGRADED, "degraded" }, - { RAID_STATE_RESYNCING, "resyncing" }, - { RAID_STATE_OFFLINE, "offline" }, -}; - -static const char *raid_state_name(enum raid_state state) -{ - int i; - char *name = NULL; - - for (i = 0; i < ARRAY_SIZE(raid_states); i++) { - if (raid_states[i].value == state) { - name = raid_states[i].name; - break; - } - } - return name; -} - -static struct { - enum raid_level value; - char *name; -} raid_levels[] = { - { RAID_LEVEL_UNKNOWN, "unknown" }, - { RAID_LEVEL_LINEAR, "linear" }, - { RAID_LEVEL_0, "raid0" }, - { RAID_LEVEL_1, "raid1" }, - { RAID_LEVEL_10, "raid10" }, - { RAID_LEVEL_1E, "raid1e" }, - { RAID_LEVEL_3, "raid3" }, - { RAID_LEVEL_4, "raid4" }, - { RAID_LEVEL_5, "raid5" }, - { RAID_LEVEL_50, "raid50" }, - { RAID_LEVEL_6, "raid6" }, -}; - -static const char *raid_level_name(enum raid_level level) -{ - int i; - char *name = NULL; - - for (i = 0; i < ARRAY_SIZE(raid_levels); i++) { - if (raid_levels[i].value == level) { - name = raid_levels[i].name; - break; - } - } - return name; -} - -#define raid_attr_show_internal(attr, fmt, var, code) \ -static ssize_t raid_show_##attr(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct raid_data *rd = dev_get_drvdata(dev); \ - code \ - return snprintf(buf, 20, #fmt "\n", var); \ -} - -#define raid_attr_ro_states(attr, states, code) \ -raid_attr_show_internal(attr, %s, name, \ - const char *name; \ - code \ - name = raid_##states##_name(rd->attr); \ -) \ -static DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL) - - -#define raid_attr_ro_internal(attr, code) \ -raid_attr_show_internal(attr, %d, rd->attr, code) \ -static DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL) - -#define ATTR_CODE(attr) \ - struct raid_internal *i = device_to_raid_internal(dev); \ - if (i->f->get_##attr) \ - i->f->get_##attr(dev->parent); - -#define raid_attr_ro(attr) raid_attr_ro_internal(attr, ) -#define raid_attr_ro_fn(attr) raid_attr_ro_internal(attr, ATTR_CODE(attr)) -#define raid_attr_ro_state(attr) raid_attr_ro_states(attr, attr, ) -#define raid_attr_ro_state_fn(attr) raid_attr_ro_states(attr, attr, ATTR_CODE(attr)) - - -raid_attr_ro_state(level); -raid_attr_ro_fn(resync); -raid_attr_ro_state_fn(state); - -static void raid_component_release(struct device *dev) -{ - struct raid_component *rc = - container_of(dev, struct raid_component, dev); - dev_printk(KERN_ERR, rc->dev.parent, "COMPONENT RELEASE\n"); - put_device(rc->dev.parent); - kfree(rc); -} - -int raid_component_add(struct raid_template *r,struct device *raid_dev, - struct device *component_dev) -{ - struct device *cdev = - attribute_container_find_class_device(&r->raid_attrs.ac, - raid_dev); - struct raid_component *rc; - struct raid_data *rd = dev_get_drvdata(cdev); - int err; - - rc = kzalloc(sizeof(*rc), GFP_KERNEL); - if (!rc) - return -ENOMEM; - - INIT_LIST_HEAD(&rc->node); - device_initialize(&rc->dev); - rc->dev.release = raid_component_release; - rc->dev.parent = get_device(component_dev); - rc->num = rd->component_count++; - - dev_set_name(&rc->dev, "component-%d", rc->num); - list_add_tail(&rc->node, &rd->component_list); - rc->dev.class = &raid_class.class; - err = device_add(&rc->dev); - if (err) - goto err_out; - - return 0; - -err_out: - list_del(&rc->node); - rd->component_count--; - put_device(component_dev); - kfree(rc); - return err; -} -EXPORT_SYMBOL(raid_component_add); - -struct raid_template * -raid_class_attach(struct raid_function_template *ft) -{ - struct raid_internal *i = kzalloc(sizeof(struct raid_internal), - GFP_KERNEL); - int count = 0; - - if (unlikely(!i)) - return NULL; - - i->f = ft; - - i->r.raid_attrs.ac.class = &raid_class.class; - i->r.raid_attrs.ac.match = raid_match; - i->r.raid_attrs.ac.attrs = &i->attrs[0]; - - attribute_container_register(&i->r.raid_attrs.ac); - - i->attrs[count++] = &dev_attr_level; - i->attrs[count++] = &dev_attr_resync; - i->attrs[count++] = &dev_attr_state; - - i->attrs[count] = NULL; - BUG_ON(count > RAID_NUM_ATTRS); - - return &i->r; -} -EXPORT_SYMBOL(raid_class_attach); - -void -raid_class_release(struct raid_template *r) -{ - struct raid_internal *i = to_raid_internal(r); - - BUG_ON(attribute_container_unregister(&i->r.raid_attrs.ac)); - - kfree(i); -} -EXPORT_SYMBOL(raid_class_release); - -static __init int raid_init(void) -{ - return transport_class_register(&raid_class); -} - -static __exit void raid_exit(void) -{ - transport_class_unregister(&raid_class); -} - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("RAID device class"); -MODULE_LICENSE("GPL"); - -module_init(raid_init); -module_exit(raid_exit); - diff --git a/ANDROID_3.4.5/drivers/scsi/script_asm.pl b/ANDROID_3.4.5/drivers/scsi/script_asm.pl deleted file mode 100644 index 7d651d99..00000000 --- a/ANDROID_3.4.5/drivers/scsi/script_asm.pl +++ /dev/null @@ -1,984 +0,0 @@ -#!/usr/bin/perl -s - -# NCR 53c810 script assembler -# Sponsored by -# iX Multiuser Multitasking Magazine -# -# Copyright 1993, Drew Eckhardt -# Visionary Computing -# (Unix and Linux consulting and custom programming) -# drew@Colorado.EDU -# +1 (303) 786-7975 -# -# Support for 53c710 (via -ncr7x0_family switch) added by Richard -# Hirst - 15th March 1997 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -# -# TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation. -# - -# -# Basically, I follow the NCR syntax documented in the NCR53c710 -# Programmer's guide, with the new instructions, registers, etc. -# from the NCR53c810. -# -# Differences between this assembler and NCR's are that -# 1. PASS, REL (data, JUMPs work fine), and the option to start a new -# script, are unimplemented, since I didn't use them in my scripts. -# -# 2. I also emit a script_u.h file, which will undefine all of -# the A_*, E_*, etc. symbols defined in the script. This -# makes including multiple scripts in one program easier -# -# 3. This is a single pass assembler, which only emits -# .h files. -# - - -# XXX - set these with command line options -$debug = 0; # Print general debugging messages -$debug_external = 0; # Print external/forward reference messages -$list_in_array = 1; # Emit original SCRIPTS assembler in comments in - # script.h -#$prefix; # (set by perl -s) - # define all arrays having this prefix so we - # don't have name space collisions after - # assembling this file in different ways for - # different host adapters - -# Constants - - -# Table of the SCSI phase encodings -%scsi_phases = ( - 'DATA_OUT', 0x00_00_00_00, 'DATA_IN', 0x01_00_00_00, 'CMD', 0x02_00_00_00, - 'STATUS', 0x03_00_00_00, 'MSG_OUT', 0x06_00_00_00, 'MSG_IN', 0x07_00_00_00 -); - -# XXX - replace references to the *_810 constants with general constants -# assigned at compile time based on chip type. - -# Table of operator encodings -# XXX - NCR53c710 only implements -# move (nop) = 0x00_00_00_00 -# or = 0x02_00_00_00 -# and = 0x04_00_00_00 -# add = 0x06_00_00_00 - -if ($ncr7x0_family) { - %operators = ( - '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, - '&', 0x04_00_00_00, 'AND', 0x04_00_00_00, - '+', 0x06_00_00_00 - ); -} -else { - %operators = ( - 'SHL', 0x01_00_00_00, - '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, - 'XOR', 0x03_00_00_00, - '&', 0x04_00_00_00, 'AND', 0x04_00_00_00, - 'SHR', 0x05_00_00_00, - # Note : low bit of the operator bit should be set for add with - # carry. - '+', 0x06_00_00_00 - ); -} - -# Table of register addresses - -if ($ncr7x0_family) { - %registers = ( - 'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3, - 'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7, - 'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11, - 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15, - 'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19, - 'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23, - 'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27, - 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31, - 'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35, - 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39, - 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43, - 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47, - 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51, - 'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55, - 'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59, - 'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63, - ); -} -else { - %registers = ( - 'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3, - 'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7, - 'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11, - 'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15, - 'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19, - 'ISTAT', 20, - 'CTEST0', 24, 'CTEST1', 25, 'CTEST2', 26, 'CTEST3', 27, - 'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31, - 'DFIFO', 32, 'CTEST4', 33, 'CTEST5', 34, 'CTEST6', 35, - 'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39, - 'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43, - 'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47, - 'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51, - 'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55, - 'SCRATCHA0', 52, 'SCRATCHA1', 53, 'SCRATCHA2', 54, 'SCRATCHA3', 55, - 'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59, - 'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63, - 'SIEN0', 64, 'SIEN1', 65, 'SIST0', 66, 'SIST1', 67, - 'SLPAR', 68, 'MACNTL', 70, 'GPCNTL', 71, - 'STIME0', 72, 'STIME1', 73, 'RESPID', 74, - 'STEST0', 76, 'STEST1', 77, 'STEST2', 78, 'STEST3', 79, - 'SIDL', 80, - 'SODL', 84, - 'SBDL', 88, - 'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95 - ); -} - -# Parsing regular expressions -$identifier = '[A-Za-z_][A-Za-z_0-9]*'; -$decnum = '-?\\d+'; -$hexnum = '0[xX][0-9A-Fa-f]+'; -$constant = "$hexnum|$decnum"; - -# yucky - since we can't control grouping of # $constant, we need to -# expand out each alternative for $value. - -$value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|". - "$identifier\\s*[+-]\s*$hexnum|$constant"; - -print STDERR "value regex = $value\n" if ($debug); - -$phase = join ('|', keys %scsi_phases); -print STDERR "phase regex = $phase\n" if ($debug); -$register = join ('|', keys %registers); - -# yucky - since %operators includes meta-characters which must -# be escaped, I can't use the join() trick I used for the register -# regex - -if ($ncr7x0_family) { - $operator = '\||OR|AND|\&|\+'; -} -else { - $operator = '\||OR|AND|XOR|\&|\+'; -} - -# Global variables - -%symbol_values = (%registers) ; # Traditional symbol table - -%symbol_references = () ; # Table of symbol references, where - # the index is the symbol name, - # and the contents a white space - # delimited list of address,size - # tuples where size is in bytes. - -@code = (); # Array of 32 bit words for SIOP - -@entry = (); # Array of entry point names - -@label = (); # Array of label names - -@absolute = (); # Array of absolute names - -@relative = (); # Array of relative names - -@external = (); # Array of external names - -$address = 0; # Address of current instruction - -$lineno = 0; # Line number we are parsing - -$output = 'script.h'; # Output file -$outputu = 'scriptu.h'; - -# &patch ($address, $offset, $length, $value) patches $code[$address] -# so that the $length bytes at $offset have $value added to -# them. - -@inverted_masks = (0x00_00_00_00, 0x00_00_00_ff, 0x00_00_ff_ff, 0x00_ff_ff_ff, - 0xff_ff_ff_ff); - -sub patch { - local ($address, $offset, $length, $value) = @_; - if ($debug) { - print STDERR "Patching $address at offset $offset, length $length to $value\n"; - printf STDERR "Old code : %08x\n", $code[$address]; - } - - $mask = ($inverted_masks[$length] << ($offset * 8)); - - $code[$address] = ($code[$address] & ~$mask) | - (($code[$address] & $mask) + ($value << ($offset * 8)) & - $mask); - - printf STDERR "New code : %08x\n", $code[$address] if ($debug); -} - -# &parse_value($value, $word, $offset, $length) where $value is -# an identifier or constant, $word is the word offset relative to -# $address, $offset is the starting byte within that word, and -# $length is the length of the field in bytes. -# -# Side effects are that the bytes are combined into the @code array -# relative to $address, and that the %symbol_references table is -# updated as appropriate. - -sub parse_value { - local ($value, $word, $offset, $length) = @_; - local ($tmp); - - $symbol = ''; - - if ($value =~ /^REL\s*\(\s*($identifier)\s*\)\s*(.*)/i) { - $relative = 'REL'; - $symbol = $1; - $value = $2; -print STDERR "Relative reference $symbol\n" if ($debug); - } elsif ($value =~ /^($identifier)\s*(.*)/) { - $relative = 'ABS'; - $symbol = $1; - $value = $2; -print STDERR "Absolute reference $symbol\n" if ($debug); - } - - if ($symbol ne '') { -print STDERR "Referencing symbol $1, length = $length in $_\n" if ($debug); - $tmp = ($address + $word) * 4 + $offset; - if ($symbol_references{$symbol} ne undef) { - $symbol_references{$symbol} = - "$symbol_references{$symbol} $relative,$tmp,$length"; - } else { - if (!defined($symbol_values{$symbol})) { -print STDERR "forward $1\n" if ($debug_external); - $forward{$symbol} = "line $lineno : $_"; - } - $symbol_references{$symbol} = "$relative,$tmp,$length"; - } - } - - $value = eval $value; - &patch ($address + $word, $offset, $length, $value); -} - -# &parse_conditional ($conditional) where $conditional is the conditional -# clause from a transfer control instruction (RETURN, CALL, JUMP, INT). - -sub parse_conditional { - local ($conditional) = @_; - if ($conditional =~ /^\s*(IF|WHEN)\s*(.*)/i) { - $if = $1; - $conditional = $2; - if ($if =~ /WHEN/i) { - $allow_atn = 0; - $code[$address] |= 0x00_01_00_00; - $allow_atn = 0; - print STDERR "$0 : parsed WHEN\n" if ($debug); - } else { - $allow_atn = 1; - print STDERR "$0 : parsed IF\n" if ($debug); - } - } else { - die "$0 : syntax error in line $lineno : $_ - expected IF or WHEN -"; - } - - if ($conditional =~ /^NOT\s+(.*)$/i) { - $not = 'NOT '; - $other = 'OR'; - $conditional = $1; - print STDERR "$0 : parsed NOT\n" if ($debug); - } else { - $code[$address] |= 0x00_08_00_00; - $not = ''; - $other = 'AND' - } - - $need_data = 0; - if ($conditional =~ /^ATN\s*(.*)/i) {# - die "$0 : syntax error in line $lineno : $_ - WHEN conditional is incompatible with ATN -" if (!$allow_atn); - $code[$address] |= 0x00_02_00_00; - $conditional = $1; - print STDERR "$0 : parsed ATN\n" if ($debug); - } elsif ($conditional =~ /^($phase)\s*(.*)/i) { - $phase_index = "\U$1\E"; - $p = $scsi_phases{$phase_index}; - $code[$address] |= $p | 0x00_02_00_00; - $conditional = $2; - print STDERR "$0 : parsed phase $phase_index\n" if ($debug); - } else { - $other = ''; - $need_data = 1; - } - -print STDERR "Parsing conjunction, expecting $other\n" if ($debug); - if ($conditional =~ /^(AND|OR)\s*(.*)/i) { - $conjunction = $1; - $conditional = $2; - $need_data = 1; - die "$0 : syntax error in line $lineno : $_ - Illegal use of $1. Valid uses are - ".$not." $1 data - ".$not."ATN $1 data -" if ($other eq ''); - die "$0 : syntax error in line $lineno : $_ - Illegal use of $conjunction. Valid syntaxes are - NOT |ATN OR data - |ATN AND data -" if ($conjunction !~ /\s*$other\s*/i); - print STDERR "$0 : parsed $1\n" if ($debug); - } - - if ($need_data) { -print STDERR "looking for data in $conditional\n" if ($debug); - if ($conditional=~ /^($value)\s*(.*)/i) { - $code[$address] |= 0x00_04_00_00; - $conditional = $2; - &parse_value($1, 0, 0, 1); - print STDERR "$0 : parsed data\n" if ($debug); - } else { - die "$0 : syntax error in line $lineno : $_ - expected . -"; - } - } - - if ($conditional =~ /^\s*,\s*(.*)/) { - $conditional = $1; - if ($conditional =~ /^AND\s\s*MASK\s\s*($value)\s*(.*)/i) { - &parse_value ($1, 0, 1, 1); - print STDERR "$0 parsed AND MASK $1\n" if ($debug); - die "$0 : syntax error in line $lineno : $_ - expected end of line, not \"$2\" -" if ($2 ne ''); - } else { - die "$0 : syntax error in line $lineno : $_ - expected \",AND MASK \", not \"$2\" -"; - } - } elsif ($conditional !~ /^\s*$/) { - die "$0 : syntax error in line $lineno : $_ - expected end of line" . (($need_data) ? " or \"AND MASK \"" : "") . " - not \"$conditional\" -"; - } -} - -# Parse command line -$output = shift; -$outputu = shift; - - -# Main loop -while () { - $lineno = $lineno + 1; - $list[$address] = $list[$address].$_; - s/;.*$//; # Strip comments - - - chop; # Leave new line out of error messages - -# Handle symbol definitions of the form label: - if (/^\s*($identifier)\s*:(.*)/) { - if (!defined($symbol_values{$1})) { - $symbol_values{$1} = $address * 4; # Address is an index into - delete $forward{$1}; # an array of longs - push (@label, $1); - $_ = $2; - } else { - die "$0 : redefinition of symbol $1 in line $lineno : $_\n"; - } - } - -# Handle symbol definitions of the form ABSOLUTE or RELATIVE identifier = -# value - if (/^\s*(ABSOLUTE|RELATIVE)\s+(.*)/i) { - $is_absolute = $1; - $rest = $2; - foreach $rest (split (/\s*,\s*/, $rest)) { - if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) { - local ($id, $cnst) = ($1, $2); - if ($symbol_values{$id} eq undef) { - $symbol_values{$id} = eval $cnst; - delete $forward{$id}; - if ($is_absolute =~ /ABSOLUTE/i) { - push (@absolute , $id); - } else { - push (@relative, $id); - } - } else { - die "$0 : redefinition of symbol $id in line $lineno : $_\n"; - } - } else { - die -"$0 : syntax error in line $lineno : $_ - expected = -"; - } - } - } elsif (/^\s*EXTERNAL\s+(.*)/i) { - $externals = $1; - foreach $external (split (/,/,$externals)) { - if ($external =~ /\s*($identifier)\s*$/) { - $external = $1; - push (@external, $external); - delete $forward{$external}; - if (defined($symbol_values{$external})) { - die "$0 : redefinition of symbol $1 in line $lineno : $_\n"; - } - $symbol_values{$external} = $external; -print STDERR "defined external $1 to $external\n" if ($debug_external); - } else { - die -"$0 : syntax error in line $lineno : $_ - expected , got $external -"; - } - } -# Process ENTRY identifier declarations - } elsif (/^\s*ENTRY\s+(.*)/i) { - if ($1 =~ /^($identifier)\s*$/) { - push (@entry, $1); - } else { - die -"$0 : syntax error in line $lineno : $_ - expected ENTRY -"; - } -# Process MOVE length, address, WITH|WHEN phase instruction - } elsif (/^\s*MOVE\s+(.*)/i) { - $rest = $1; - if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) { - $transfer_addr = $1; - $with_when = $2; - $scsi_phase = $3; -print STDERR "Parsing MOVE FROM $transfer_addr, $with_when $3\n" if ($debug); - $code[$address] = 0x18_00_00_00 | (($with_when =~ /WITH/i) ? - 0x00_00_00_00 : 0x08_00_00_00) | $scsi_phases{$scsi_phase}; - &parse_value ($transfer_addr, 1, 0, 4); - $address += 2; - } elsif ($rest =~ /^($value)\s*,\s*(PTR\s+|)($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) { - $transfer_len = $1; - $ptr = $2; - $transfer_addr = $3; - $with_when = $4; - $scsi_phase = $5; - $code[$address] = (($with_when =~ /WITH/i) ? 0x00_00_00_00 : - 0x08_00_00_00) | (($ptr =~ /PTR/i) ? (1 << 29) : 0) | - $scsi_phases{$scsi_phase}; - &parse_value ($transfer_len, 0, 0, 3); - &parse_value ($transfer_addr, 1, 0, 4); - $address += 2; - } elsif ($rest =~ /^MEMORY\s+(.*)/i) { - $rest = $1; - $code[$address] = 0xc0_00_00_00; - if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) { - $count = $1; - $source = $2; - $dest = $3; -print STDERR "Parsing MOVE MEMORY $count, $source, $dest\n" if ($debug); - &parse_value ($count, 0, 0, 3); - &parse_value ($source, 1, 0, 4); - &parse_value ($dest, 2, 0, 4); -printf STDERR "Move memory instruction = %08x,%08x,%08x\n", - $code[$address], $code[$address+1], $code[$address +2] if - ($debug); - $address += 3; - - } else { - die -"$0 : syntax error in line $lineno : $_ - expected , , -" - } - } elsif ($1 =~ /^(.*)\s+(TO|SHL|SHR)\s+(.*)/i) { -print STDERR "Parsing register to register move\n" if ($debug); - $src = $1; - $op = "\U$2\E"; - $rest = $3; - - $code[$address] = 0x40_00_00_00; - - $force = ($op !~ /TO/i); - - -print STDERR "Forcing register source \n" if ($force && $debug); - - if (!$force && $src =~ - /^($register)\s+(-|$operator)\s+($value)\s*$/i) { -print STDERR "register operand data8 source\n" if ($debug); - $src_reg = "\U$1\E"; - $op = "\U$2\E"; - if ($op ne '-') { - $data8 = $3; - } else { - die "- is not implemented yet.\n" - } - } elsif ($src =~ /^($register)\s*$/i) { -print STDERR "register source\n" if ($debug); - $src_reg = "\U$1\E"; - # Encode register to register move as a register | 0 - # move to register. - if (!$force) { - $op = '|'; - } - $data8 = 0; - } elsif (!$force && $src =~ /^($value)\s*$/i) { -print STDERR "data8 source\n" if ($debug); - $src_reg = undef; - $op = 'NONE'; - $data8 = $1; - } else { - if (!$force) { - die -"$0 : syntax error in line $lineno : $_ - expected - - -"; - } else { - die -"$0 : syntax error in line $lineno : $_ - expected -"; - } - } - if ($rest =~ /^($register)\s*(.*)$/i) { - $dst_reg = "\U$1\E"; - $rest = $2; - } else { - die -"$0 : syntax error in $lineno : $_ - expected , got $rest -"; - } - - if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) { - $rest = $1; - if ($op eq '+') { - $code[$address] |= 0x01_00_00_00; - } else { - die -"$0 : syntax error in $lineno : $_ - WITH CARRY option is incompatible with the $op operator. -"; - } - } - - if ($rest !~ /^\s*$/) { - die -"$0 : syntax error in $lineno : $_ - Expected end of line, got $rest -"; - } - - print STDERR "source = $src_reg, data = $data8 , destination = $dst_reg\n" - if ($debug); - # Note that Move data8 to reg is encoded as a read-modify-write - # instruction. - if (($src_reg eq undef) || ($src_reg eq $dst_reg)) { - $code[$address] |= 0x38_00_00_00 | - ($registers{$dst_reg} << 16); - } elsif ($dst_reg =~ /SFBR/i) { - $code[$address] |= 0x30_00_00_00 | - ($registers{$src_reg} << 16); - } elsif ($src_reg =~ /SFBR/i) { - $code[$address] |= 0x28_00_00_00 | - ($registers{$dst_reg} << 16); - } else { - die -"$0 : Illegal combination of registers in line $lineno : $_ - Either source and destination registers must be the same, - or either source or destination register must be SFBR. -"; - } - - $code[$address] |= $operators{$op}; - - &parse_value ($data8, 0, 1, 1); - $code[$address] |= $operators{$op}; - $code[$address + 1] = 0x00_00_00_00;# Reserved - $address += 2; - } else { - die -"$0 : syntax error in line $lineno : $_ - expected (initiator) ,
, WHEN - (target) ,
, WITH - MEMORY , , - TO -"; - } -# Process SELECT {ATN|} id, fail_address - } elsif (/^\s*(SELECT|RESELECT)\s+(.*)/i) { - $rest = $2; - if ($rest =~ /^(ATN|)\s*($value)\s*,\s*($identifier)\s*$/i) { - $atn = $1; - $id = $2; - $alt_addr = $3; - $code[$address] = 0x40_00_00_00 | - (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0); - $code[$address + 1] = 0x00_00_00_00; - &parse_value($id, 0, 2, 1); - &parse_value($alt_addr, 1, 0, 4); - $address += 2; - } elsif ($rest =~ /^(ATN|)\s*FROM\s+($value)\s*,\s*($identifier)\s*$/i) { - $atn = $1; - $addr = $2; - $alt_addr = $3; - $code[$address] = 0x42_00_00_00 | - (($atn =~ /ATN/i) ? 0x01_00_00_00 : 0); - $code[$address + 1] = 0x00_00_00_00; - &parse_value($addr, 0, 0, 3); - &parse_value($alt_addr, 1, 0, 4); - $address += 2; - } else { - die -"$0 : syntax error in line $lineno : $_ - expected SELECT id, alternate_address or - SELECT FROM address, alternate_address or - RESELECT id, alternate_address or - RESELECT FROM address, alternate_address -"; - } - } elsif (/^\s*WAIT\s+(.*)/i) { - $rest = $1; -print STDERR "Parsing WAIT $rest\n" if ($debug); - if ($rest =~ /^DISCONNECT\s*$/i) { - $code[$address] = 0x48_00_00_00; - $code[$address + 1] = 0x00_00_00_00; - $address += 2; - } elsif ($rest =~ /^(RESELECT|SELECT)\s+($identifier)\s*$/i) { - $alt_addr = $2; - $code[$address] = 0x50_00_00_00; - &parse_value ($alt_addr, 1, 0, 4); - $address += 2; - } else { - die -"$0 : syntax error in line $lineno : $_ - expected (initiator) WAIT DISCONNECT or - (initiator) WAIT RESELECT alternate_address or - (target) WAIT SELECT alternate_address -"; - } -# Handle SET and CLEAR instructions. Note that we should also do something -# with this syntax to set target mode. - } elsif (/^\s*(SET|CLEAR)\s+(.*)/i) { - $set = $1; - $list = $2; - $code[$address] = ($set =~ /SET/i) ? 0x58_00_00_00 : - 0x60_00_00_00; - foreach $arg (split (/\s+AND\s+/i,$list)) { - if ($arg =~ /ATN/i) { - $code[$address] |= 0x00_00_00_08; - } elsif ($arg =~ /ACK/i) { - $code[$address] |= 0x00_00_00_40; - } elsif ($arg =~ /TARGET/i) { - $code[$address] |= 0x00_00_02_00; - } elsif ($arg =~ /CARRY/i) { - $code[$address] |= 0x00_00_04_00; - } else { - die -"$0 : syntax error in line $lineno : $_ - expected $set followed by a AND delimited list of one or - more strings from the list ACK, ATN, CARRY, TARGET. -"; - } - } - $code[$address + 1] = 0x00_00_00_00; - $address += 2; - } elsif (/^\s*(JUMP|CALL|INT)\s+(.*)/i) { - $instruction = $1; - $rest = $2; - if ($instruction =~ /JUMP/i) { - $code[$address] = 0x80_00_00_00; - } elsif ($instruction =~ /CALL/i) { - $code[$address] = 0x88_00_00_00; - } else { - $code[$address] = 0x98_00_00_00; - } -print STDERR "parsing JUMP, rest = $rest\n" if ($debug); - -# Relative jump. - if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) { - $addr = $1; - $rest = $2; -print STDERR "parsing JUMP REL, addr = $addr, rest = $rest\n" if ($debug); - $code[$address] |= 0x00_80_00_00; - &parse_value($addr, 1, 0, 4); -# Absolute jump, requires no more gunk - } elsif ($rest =~ /^($value)\s*(.*)/) { - $addr = $1; - $rest = $2; - &parse_value($addr, 1, 0, 4); - } else { - die -"$0 : syntax error in line $lineno : $_ - expected
or REL (address) -"; - } - - if ($rest =~ /^,\s*(.*)/) { - &parse_conditional($1); - } elsif ($rest =~ /^\s*$/) { - $code[$address] |= (1 << 19); - } else { - die -"$0 : syntax error in line $lineno : $_ - expected , or end of line, got $1 -"; - } - - $address += 2; - } elsif (/^\s*(RETURN|INTFLY)\s*(.*)/i) { - $instruction = $1; - $conditional = $2; -print STDERR "Parsing $instruction\n" if ($debug); - $code[$address] = ($instruction =~ /RETURN/i) ? 0x90_00_00_00 : - 0x98_10_00_00; - if ($conditional =~ /^,\s*(.*)/) { - $conditional = $1; - &parse_conditional ($conditional); - } elsif ($conditional !~ /^\s*$/) { - die -"$0 : syntax error in line $lineno : $_ - expected , -"; - } else { - $code[$address] |= 0x00_08_00_00; - } - - $code[$address + 1] = 0x00_00_00_00; - $address += 2; - } elsif (/^\s*DISCONNECT\s*$/) { - $code[$address] = 0x48_00_00_00; - $code[$address + 1] = 0x00_00_00_00; - $address += 2; -# I'm not sure that I should be including this extension, but -# what the hell? - } elsif (/^\s*NOP\s*$/i) { - $code[$address] = 0x80_88_00_00; - $code[$address + 1] = 0x00_00_00_00; - $address += 2; -# Ignore lines consisting entirely of white space - } elsif (/^\s*$/) { - } else { - die -"$0 : syntax error in line $lineno: $_ - expected label:, ABSOLUTE, CLEAR, DISCONNECT, EXTERNAL, MOVE, RESELECT, - SELECT SET, or WAIT -"; - } -} - -# Fill in label references - -@undefined = keys %forward; -if ($#undefined >= 0) { - print STDERR "Undefined symbols : \n"; - foreach $undef (@undefined) { - print STDERR "$undef in $forward{$undef}\n"; - } - exit 1; -} - -@label_patches = (); - -@external_patches = (); - -@absolute = sort @absolute; - -foreach $i (@absolute) { - foreach $j (split (/\s+/,$symbol_references{$i})) { - $j =~ /(REL|ABS),(.*),(.*)/; - $type = $1; - $address = $2; - $length = $3; - die -"$0 : $symbol $i has invalid relative reference at address $address, - size $length\n" - if ($type eq 'REL'); - - &patch ($address / 4, $address % 4, $length, $symbol_values{$i}); - } -} - -foreach $external (@external) { -print STDERR "checking external $external \n" if ($debug_external); - if ($symbol_references{$external} ne undef) { - for $reference (split(/\s+/,$symbol_references{$external})) { - $reference =~ /(REL|ABS),(.*),(.*)/; - $type = $1; - $address = $2; - $length = $3; - - die -"$0 : symbol $label is external, has invalid relative reference at $address, - size $length\n" - if ($type eq 'REL'); - - die -"$0 : symbol $label has invalid reference at $address, size $length\n" - if ((($address % 4) !=0) || ($length != 4)); - - $symbol = $symbol_values{$external}; - $add = $code[$address / 4]; - if ($add eq 0) { - $code[$address / 4] = $symbol; - } else { - $add = sprintf ("0x%08x", $add); - $code[$address / 4] = "$symbol + $add"; - } - -print STDERR "referenced external $external at $1\n" if ($debug_external); - } - } -} - -foreach $label (@label) { - if ($symbol_references{$label} ne undef) { - for $reference (split(/\s+/,$symbol_references{$label})) { - $reference =~ /(REL|ABS),(.*),(.*)/; - $type = $1; - $address = $2; - $length = $3; - - if ((($address % 4) !=0) || ($length != 4)) { - die "$0 : symbol $label has invalid reference at $1, size $2\n"; - } - - if ($type eq 'ABS') { - $code[$address / 4] += $symbol_values{$label}; - push (@label_patches, $address / 4); - } else { -# -# - The address of the reference should be in the second and last word -# of an instruction -# - Relative jumps, etc. are relative to the DSP of the _next_ instruction -# -# So, we need to add four to the address of the reference, to get -# the address of the next instruction, when computing the reference. - - $tmp = $symbol_values{$label} - - ($address + 4); - die -# Relative addressing is limited to 24 bits. -"$0 : symbol $label is too far ($tmp) from $address to reference as - relative/\n" if (($tmp >= 0x80_00_00) || ($tmp < -0x80_00_00)); - $code[$address / 4] = $tmp & 0x00_ff_ff_ff; - } - } - } -} - -# Output SCRIPT[] array, one instruction per line. Optionally -# print the original code too. - -open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n"; -open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n"; - -($_ = $0) =~ s:.*/::; -print OUTPUT "/* DO NOT EDIT - Generated automatically by ".$_." */\n"; -print OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n"; -$instructions = 0; -for ($i = 0; $i < $#code; ) { - if ($list_in_array) { - printf OUTPUT "/*\n$list[$i]\nat 0x%08x : */", $i; - } - printf OUTPUT "\t0x%08x,", $code[$i]; - printf STDERR "Address $i = %x\n", $code[$i] if ($debug); - if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) { - push (@external_patches, $i+1, $1); - printf OUTPUT "0%s,", $2 - } else { - printf OUTPUT "0x%08x,",$code[$i+1]; - } - - if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) { - if ($code[$i + 2] =~ /$identifier/) { - push (@external_patches, $i+2, $code[$i+2]); - printf OUTPUT "0,\n"; - } else { - printf OUTPUT "0x%08x,\n",$code[$i+2]; - } - $i += 3; - } else { - printf OUTPUT "\n"; - $i += 2; - } - $instructions += 1; -} -print OUTPUT "};\n\n"; - -foreach $i (@absolute) { - printf OUTPUT "#define A_$i\t0x%08x\n", $symbol_values{$i}; - if (defined($prefix) && $prefix ne '') { - printf OUTPUT "#define A_".$i."_used ".$prefix."A_".$i."_used\n"; - printf OUTPUTU "#undef A_".$i."_used\n"; - } - printf OUTPUTU "#undef A_$i\n"; - - printf OUTPUT "static u32 A_".$i."_used\[\] __attribute((unused)) = {\n"; -printf STDERR "$i is used $symbol_references{$i}\n" if ($debug); - foreach $j (split (/\s+/,$symbol_references{$i})) { - $j =~ /(ABS|REL),(.*),(.*)/; - if ($1 eq 'ABS') { - $address = $2; - $length = $3; - printf OUTPUT "\t0x%08x,\n", $address / 4; - } - } - printf OUTPUT "};\n\n"; -} - -foreach $i (sort @entry) { - printf OUTPUT "#define Ent_$i\t0x%08x\n", $symbol_values{$i}; - printf OUTPUTU "#undef Ent_$i\n", $symbol_values{$i}; -} - -# -# NCR assembler outputs label patches in the form of indices into -# the code. -# -printf OUTPUT "static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n"; -for $patch (sort {$a <=> $b} @label_patches) { - printf OUTPUT "\t0x%08x,\n", $patch; -} -printf OUTPUT "};\n\n"; - -$num_external_patches = 0; -printf OUTPUT "static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n". - "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n"; -while ($ident = pop(@external_patches)) { - $off = pop(@external_patches); - printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident; - ++$num_external_patches; -} -printf OUTPUT "};\n\n"; - -printf OUTPUT "static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n", - $instructions; -printf OUTPUT "static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n", - $#label_patches+1; -printf OUTPUT "static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n", - $num_external_patches; -close OUTPUT; -close OUTPUTU; diff --git a/ANDROID_3.4.5/drivers/scsi/scsi.c b/ANDROID_3.4.5/drivers/scsi/scsi.c deleted file mode 100644 index 07322ecf..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi.c +++ /dev/null @@ -1,1356 +0,0 @@ -/* - * scsi.c Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale - * Copyright (C) 2002, 2003 Christoph Hellwig - * - * generic mid-level SCSI driver - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * - * - * - * Bug correction thanks go to : - * Rik Faith - * Tommy Thorn - * Thomas Wuensche - * - * Modified by Eric Youngdale eric@andante.org or ericy@gnu.ai.mit.edu to - * add scatter-gather, multiple outstanding request, and other - * enhancements. - * - * Native multichannel, wide scsi, /proc/scsi and hot plugging - * support added by Michael Neuffer - * - * Added request_module("scsi_hostadapter") for kerneld: - * (Put an "alias scsi_hostadapter your_hostadapter" in /etc/modprobe.conf) - * Bjorn Ekwall - * (changed to kmod) - * - * Major improvements to the timeout, abort, and reset processing, - * as well as performance modifications for large queue depths by - * Leonard N. Zubkoff - * - * Converted cli() code to spinlocks, Ingo Molnar - * - * Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli - * - * out_of_space hacks, D. Gilbert (dpg) 990608 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi_priv.h" -#include "scsi_logging.h" - -#define CREATE_TRACE_POINTS -#include - -static void scsi_done(struct scsi_cmnd *cmd); - -/* - * Definitions and constants. - */ - -#define MIN_RESET_DELAY (2*HZ) - -/* Do not call reset on error if we just did a reset within 15 sec. */ -#define MIN_RESET_PERIOD (15*HZ) - -/* - * Note - the initial logging level can be set here to log events at boot time. - * After the system is up, you may enable logging via the /proc interface. - */ -unsigned int scsi_logging_level; -#if defined(CONFIG_SCSI_LOGGING) -EXPORT_SYMBOL(scsi_logging_level); -#endif - -/* NB: These are exposed through /proc/scsi/scsi and form part of the ABI. - * You may not alter any existing entry (although adding new ones is - * encouraged once assigned by ANSI/INCITS T10 - */ -static const char *const scsi_device_types[] = { - "Direct-Access ", - "Sequential-Access", - "Printer ", - "Processor ", - "WORM ", - "CD-ROM ", - "Scanner ", - "Optical Device ", - "Medium Changer ", - "Communications ", - "ASC IT8 ", - "ASC IT8 ", - "RAID ", - "Enclosure ", - "Direct-Access-RBC", - "Optical card ", - "Bridge controller", - "Object storage ", - "Automation/Drive ", -}; - -/** - * scsi_device_type - Return 17 char string indicating device type. - * @type: type number to look up - */ - -const char * scsi_device_type(unsigned type) -{ - if (type == 0x1e) - return "Well-known LUN "; - if (type == 0x1f) - return "No Device "; - if (type >= ARRAY_SIZE(scsi_device_types)) - return "Unknown "; - return scsi_device_types[type]; -} - -EXPORT_SYMBOL(scsi_device_type); - -struct scsi_host_cmd_pool { - struct kmem_cache *cmd_slab; - struct kmem_cache *sense_slab; - unsigned int users; - char *cmd_name; - char *sense_name; - unsigned int slab_flags; - gfp_t gfp_mask; -}; - -static struct scsi_host_cmd_pool scsi_cmd_pool = { - .cmd_name = "scsi_cmd_cache", - .sense_name = "scsi_sense_cache", - .slab_flags = SLAB_HWCACHE_ALIGN, -}; - -static struct scsi_host_cmd_pool scsi_cmd_dma_pool = { - .cmd_name = "scsi_cmd_cache(DMA)", - .sense_name = "scsi_sense_cache(DMA)", - .slab_flags = SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA, - .gfp_mask = __GFP_DMA, -}; - -static DEFINE_MUTEX(host_cmd_pool_mutex); - -/** - * scsi_pool_alloc_command - internal function to get a fully allocated command - * @pool: slab pool to allocate the command from - * @gfp_mask: mask for the allocation - * - * Returns a fully allocated command (with the allied sense buffer) or - * NULL on failure - */ -static struct scsi_cmnd * -scsi_pool_alloc_command(struct scsi_host_cmd_pool *pool, gfp_t gfp_mask) -{ - struct scsi_cmnd *cmd; - - cmd = kmem_cache_zalloc(pool->cmd_slab, gfp_mask | pool->gfp_mask); - if (!cmd) - return NULL; - - cmd->sense_buffer = kmem_cache_alloc(pool->sense_slab, - gfp_mask | pool->gfp_mask); - if (!cmd->sense_buffer) { - kmem_cache_free(pool->cmd_slab, cmd); - return NULL; - } - - return cmd; -} - -/** - * scsi_pool_free_command - internal function to release a command - * @pool: slab pool to allocate the command from - * @cmd: command to release - * - * the command must previously have been allocated by - * scsi_pool_alloc_command. - */ -static void -scsi_pool_free_command(struct scsi_host_cmd_pool *pool, - struct scsi_cmnd *cmd) -{ - if (cmd->prot_sdb) - kmem_cache_free(scsi_sdb_cache, cmd->prot_sdb); - - kmem_cache_free(pool->sense_slab, cmd->sense_buffer); - kmem_cache_free(pool->cmd_slab, cmd); -} - -/** - * scsi_host_alloc_command - internal function to allocate command - * @shost: SCSI host whose pool to allocate from - * @gfp_mask: mask for the allocation - * - * Returns a fully allocated command with sense buffer and protection - * data buffer (where applicable) or NULL on failure - */ -static struct scsi_cmnd * -scsi_host_alloc_command(struct Scsi_Host *shost, gfp_t gfp_mask) -{ - struct scsi_cmnd *cmd; - - cmd = scsi_pool_alloc_command(shost->cmd_pool, gfp_mask); - if (!cmd) - return NULL; - - if (scsi_host_get_prot(shost) >= SHOST_DIX_TYPE0_PROTECTION) { - cmd->prot_sdb = kmem_cache_zalloc(scsi_sdb_cache, gfp_mask); - - if (!cmd->prot_sdb) { - scsi_pool_free_command(shost->cmd_pool, cmd); - return NULL; - } - } - - return cmd; -} - -/** - * __scsi_get_command - Allocate a struct scsi_cmnd - * @shost: host to transmit command - * @gfp_mask: allocation mask - * - * Description: allocate a struct scsi_cmd from host's slab, recycling from the - * host's free_list if necessary. - */ -struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost, gfp_t gfp_mask) -{ - struct scsi_cmnd *cmd = scsi_host_alloc_command(shost, gfp_mask); - - if (unlikely(!cmd)) { - unsigned long flags; - - spin_lock_irqsave(&shost->free_list_lock, flags); - if (likely(!list_empty(&shost->free_list))) { - cmd = list_entry(shost->free_list.next, - struct scsi_cmnd, list); - list_del_init(&cmd->list); - } - spin_unlock_irqrestore(&shost->free_list_lock, flags); - - if (cmd) { - void *buf, *prot; - - buf = cmd->sense_buffer; - prot = cmd->prot_sdb; - - memset(cmd, 0, sizeof(*cmd)); - - cmd->sense_buffer = buf; - cmd->prot_sdb = prot; - } - } - - return cmd; -} -EXPORT_SYMBOL_GPL(__scsi_get_command); - -/** - * scsi_get_command - Allocate and setup a scsi command block - * @dev: parent scsi device - * @gfp_mask: allocator flags - * - * Returns: The allocated scsi command structure. - */ -struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, gfp_t gfp_mask) -{ - struct scsi_cmnd *cmd; - - /* Bail if we can't get a reference to the device */ - if (!get_device(&dev->sdev_gendev)) - return NULL; - - cmd = __scsi_get_command(dev->host, gfp_mask); - - if (likely(cmd != NULL)) { - unsigned long flags; - - cmd->device = dev; - INIT_LIST_HEAD(&cmd->list); - spin_lock_irqsave(&dev->list_lock, flags); - list_add_tail(&cmd->list, &dev->cmd_list); - spin_unlock_irqrestore(&dev->list_lock, flags); - cmd->jiffies_at_alloc = jiffies; - } else - put_device(&dev->sdev_gendev); - - return cmd; -} -EXPORT_SYMBOL(scsi_get_command); - -/** - * __scsi_put_command - Free a struct scsi_cmnd - * @shost: dev->host - * @cmd: Command to free - * @dev: parent scsi device - */ -void __scsi_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd, - struct device *dev) -{ - unsigned long flags; - - /* changing locks here, don't need to restore the irq state */ - spin_lock_irqsave(&shost->free_list_lock, flags); - if (unlikely(list_empty(&shost->free_list))) { - list_add(&cmd->list, &shost->free_list); - cmd = NULL; - } - spin_unlock_irqrestore(&shost->free_list_lock, flags); - - if (likely(cmd != NULL)) - scsi_pool_free_command(shost->cmd_pool, cmd); - - put_device(dev); -} -EXPORT_SYMBOL(__scsi_put_command); - -/** - * scsi_put_command - Free a scsi command block - * @cmd: command block to free - * - * Returns: Nothing. - * - * Notes: The command must not belong to any lists. - */ -void scsi_put_command(struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - unsigned long flags; - - /* serious error if the command hasn't come from a device list */ - spin_lock_irqsave(&cmd->device->list_lock, flags); - BUG_ON(list_empty(&cmd->list)); - list_del_init(&cmd->list); - spin_unlock_irqrestore(&cmd->device->list_lock, flags); - - __scsi_put_command(cmd->device->host, cmd, &sdev->sdev_gendev); -} -EXPORT_SYMBOL(scsi_put_command); - -static struct scsi_host_cmd_pool *scsi_get_host_cmd_pool(gfp_t gfp_mask) -{ - struct scsi_host_cmd_pool *retval = NULL, *pool; - /* - * Select a command slab for this host and create it if not - * yet existent. - */ - mutex_lock(&host_cmd_pool_mutex); - pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : - &scsi_cmd_pool; - if (!pool->users) { - pool->cmd_slab = kmem_cache_create(pool->cmd_name, - sizeof(struct scsi_cmnd), 0, - pool->slab_flags, NULL); - if (!pool->cmd_slab) - goto fail; - - pool->sense_slab = kmem_cache_create(pool->sense_name, - SCSI_SENSE_BUFFERSIZE, 0, - pool->slab_flags, NULL); - if (!pool->sense_slab) { - kmem_cache_destroy(pool->cmd_slab); - goto fail; - } - } - - pool->users++; - retval = pool; - fail: - mutex_unlock(&host_cmd_pool_mutex); - return retval; -} - -static void scsi_put_host_cmd_pool(gfp_t gfp_mask) -{ - struct scsi_host_cmd_pool *pool; - - mutex_lock(&host_cmd_pool_mutex); - pool = (gfp_mask & __GFP_DMA) ? &scsi_cmd_dma_pool : - &scsi_cmd_pool; - /* - * This may happen if a driver has a mismatched get and put - * of the command pool; the driver should be implicated in - * the stack trace - */ - BUG_ON(pool->users == 0); - - if (!--pool->users) { - kmem_cache_destroy(pool->cmd_slab); - kmem_cache_destroy(pool->sense_slab); - } - mutex_unlock(&host_cmd_pool_mutex); -} - -/** - * scsi_allocate_command - get a fully allocated SCSI command - * @gfp_mask: allocation mask - * - * This function is for use outside of the normal host based pools. - * It allocates the relevant command and takes an additional reference - * on the pool it used. This function *must* be paired with - * scsi_free_command which also has the identical mask, otherwise the - * free pool counts will eventually go wrong and you'll trigger a bug. - * - * This function should *only* be used by drivers that need a static - * command allocation at start of day for internal functions. - */ -struct scsi_cmnd *scsi_allocate_command(gfp_t gfp_mask) -{ - struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask); - - if (!pool) - return NULL; - - return scsi_pool_alloc_command(pool, gfp_mask); -} -EXPORT_SYMBOL(scsi_allocate_command); - -/** - * scsi_free_command - free a command allocated by scsi_allocate_command - * @gfp_mask: mask used in the original allocation - * @cmd: command to free - * - * Note: using the original allocation mask is vital because that's - * what determines which command pool we use to free the command. Any - * mismatch will cause the system to BUG eventually. - */ -void scsi_free_command(gfp_t gfp_mask, struct scsi_cmnd *cmd) -{ - struct scsi_host_cmd_pool *pool = scsi_get_host_cmd_pool(gfp_mask); - - /* - * this could trigger if the mask to scsi_allocate_command - * doesn't match this mask. Otherwise we're guaranteed that this - * succeeds because scsi_allocate_command must have taken a reference - * on the pool - */ - BUG_ON(!pool); - - scsi_pool_free_command(pool, cmd); - /* - * scsi_put_host_cmd_pool is called twice; once to release the - * reference we took above, and once to release the reference - * originally taken by scsi_allocate_command - */ - scsi_put_host_cmd_pool(gfp_mask); - scsi_put_host_cmd_pool(gfp_mask); -} -EXPORT_SYMBOL(scsi_free_command); - -/** - * scsi_setup_command_freelist - Setup the command freelist for a scsi host. - * @shost: host to allocate the freelist for. - * - * Description: The command freelist protects against system-wide out of memory - * deadlock by preallocating one SCSI command structure for each host, so the - * system can always write to a swap file on a device associated with that host. - * - * Returns: Nothing. - */ -int scsi_setup_command_freelist(struct Scsi_Host *shost) -{ - struct scsi_cmnd *cmd; - const gfp_t gfp_mask = shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL; - - spin_lock_init(&shost->free_list_lock); - INIT_LIST_HEAD(&shost->free_list); - - shost->cmd_pool = scsi_get_host_cmd_pool(gfp_mask); - - if (!shost->cmd_pool) - return -ENOMEM; - - /* - * Get one backup command for this host. - */ - cmd = scsi_host_alloc_command(shost, gfp_mask); - if (!cmd) { - scsi_put_host_cmd_pool(gfp_mask); - shost->cmd_pool = NULL; - return -ENOMEM; - } - list_add(&cmd->list, &shost->free_list); - return 0; -} - -/** - * scsi_destroy_command_freelist - Release the command freelist for a scsi host. - * @shost: host whose freelist is going to be destroyed - */ -void scsi_destroy_command_freelist(struct Scsi_Host *shost) -{ - /* - * If cmd_pool is NULL the free list was not initialized, so - * do not attempt to release resources. - */ - if (!shost->cmd_pool) - return; - - while (!list_empty(&shost->free_list)) { - struct scsi_cmnd *cmd; - - cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list); - list_del_init(&cmd->list); - scsi_pool_free_command(shost->cmd_pool, cmd); - } - shost->cmd_pool = NULL; - scsi_put_host_cmd_pool(shost->unchecked_isa_dma ? GFP_DMA : GFP_KERNEL); -} - -#ifdef CONFIG_SCSI_LOGGING -void scsi_log_send(struct scsi_cmnd *cmd) -{ - unsigned int level; - - /* - * If ML QUEUE log level is greater than or equal to: - * - * 1: nothing (match completion) - * - * 2: log opcode + command of all commands - * - * 3: same as 2 plus dump cmd address - * - * 4: same as 3 plus dump extra junk - */ - if (unlikely(scsi_logging_level)) { - level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT, - SCSI_LOG_MLQUEUE_BITS); - if (level > 1) { - scmd_printk(KERN_INFO, cmd, "Send: "); - if (level > 2) - printk("0x%p ", cmd); - printk("\n"); - scsi_print_command(cmd); - if (level > 3) { - printk(KERN_INFO "buffer = 0x%p, bufflen = %d," - " queuecommand 0x%p\n", - scsi_sglist(cmd), scsi_bufflen(cmd), - cmd->device->host->hostt->queuecommand); - - } - } - } -} - -void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) -{ - unsigned int level; - - /* - * If ML COMPLETE log level is greater than or equal to: - * - * 1: log disposition, result, opcode + command, and conditionally - * sense data for failures or non SUCCESS dispositions. - * - * 2: same as 1 but for all command completions. - * - * 3: same as 2 plus dump cmd address - * - * 4: same as 3 plus dump extra junk - */ - if (unlikely(scsi_logging_level)) { - level = SCSI_LOG_LEVEL(SCSI_LOG_MLCOMPLETE_SHIFT, - SCSI_LOG_MLCOMPLETE_BITS); - if (((level > 0) && (cmd->result || disposition != SUCCESS)) || - (level > 1)) { - scmd_printk(KERN_INFO, cmd, "Done: "); - if (level > 2) - printk("0x%p ", cmd); - /* - * Dump truncated values, so we usually fit within - * 80 chars. - */ - switch (disposition) { - case SUCCESS: - printk("SUCCESS\n"); - break; - case NEEDS_RETRY: - printk("RETRY\n"); - break; - case ADD_TO_MLQUEUE: - printk("MLQUEUE\n"); - break; - case FAILED: - printk("FAILED\n"); - break; - case TIMEOUT_ERROR: - /* - * If called via scsi_times_out. - */ - printk("TIMEOUT\n"); - break; - default: - printk("UNKNOWN\n"); - } - scsi_print_result(cmd); - scsi_print_command(cmd); - if (status_byte(cmd->result) & CHECK_CONDITION) - scsi_print_sense("", cmd); - if (level > 3) - scmd_printk(KERN_INFO, cmd, - "scsi host busy %d failed %d\n", - cmd->device->host->host_busy, - cmd->device->host->host_failed); - } - } -} -#endif - -/** - * scsi_cmd_get_serial - Assign a serial number to a command - * @host: the scsi host - * @cmd: command to assign serial number to - * - * Description: a serial number identifies a request for error recovery - * and debugging purposes. Protected by the Host_Lock of host. - */ -void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd) -{ - cmd->serial_number = host->cmd_serial_number++; - if (cmd->serial_number == 0) - cmd->serial_number = host->cmd_serial_number++; -} -EXPORT_SYMBOL(scsi_cmd_get_serial); - -/** - * scsi_dispatch_command - Dispatch a command to the low-level driver. - * @cmd: command block we are dispatching. - * - * Return: nonzero return request was rejected and device's queue needs to be - * plugged. - */ -int scsi_dispatch_cmd(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host = cmd->device->host; - unsigned long timeout; - int rtn = 0; - - atomic_inc(&cmd->device->iorequest_cnt); - - /* check if the device is still usable */ - if (unlikely(cmd->device->sdev_state == SDEV_DEL)) { - /* in SDEV_DEL we error all commands. DID_NO_CONNECT - * returns an immediate error upwards, and signals - * that the device is no longer present */ - cmd->result = DID_NO_CONNECT << 16; - scsi_done(cmd); - /* return 0 (because the command has been processed) */ - goto out; - } - - /* Check to see if the scsi lld made this device blocked. */ - if (unlikely(scsi_device_blocked(cmd->device))) { - /* - * in blocked state, the command is just put back on - * the device queue. The suspend state has already - * blocked the queue so future requests should not - * occur until the device transitions out of the - * suspend state. - */ - - scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); - - SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n")); - - /* - * NOTE: rtn is still zero here because we don't need the - * queue to be plugged on return (it's already stopped) - */ - goto out; - } - - /* - * If SCSI-2 or lower, store the LUN value in cmnd. - */ - if (cmd->device->scsi_level <= SCSI_2 && - cmd->device->scsi_level != SCSI_UNKNOWN) { - cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) | - (cmd->device->lun << 5 & 0xe0); - } - - /* - * We will wait MIN_RESET_DELAY clock ticks after the last reset so - * we can avoid the drive not being ready. - */ - timeout = host->last_reset + MIN_RESET_DELAY; - - if (host->resetting && time_before(jiffies, timeout)) { - int ticks_remaining = timeout - jiffies; - /* - * NOTE: This may be executed from within an interrupt - * handler! This is bad, but for now, it'll do. The irq - * level of the interrupt handler has been masked out by the - * platform dependent interrupt handling code already, so the - * sti() here will not cause another call to the SCSI host's - * interrupt handler (assuming there is one irq-level per - * host). - */ - while (--ticks_remaining >= 0) - mdelay(1 + 999 / HZ); - host->resetting = 0; - } - - scsi_log_send(cmd); - - /* - * Before we queue this command, check if the command - * length exceeds what the host adapter can handle. - */ - if (cmd->cmd_len > cmd->device->host->max_cmd_len) { - SCSI_LOG_MLQUEUE(3, - printk("queuecommand : command too long. " - "cdb_size=%d host->max_cmd_len=%d\n", - cmd->cmd_len, cmd->device->host->max_cmd_len)); - cmd->result = (DID_ABORT << 16); - - scsi_done(cmd); - goto out; - } - - if (unlikely(host->shost_state == SHOST_DEL)) { - cmd->result = (DID_NO_CONNECT << 16); - scsi_done(cmd); - } else { - trace_scsi_dispatch_cmd_start(cmd); - cmd->scsi_done = scsi_done; - rtn = host->hostt->queuecommand(host, cmd); - } - - if (rtn) { - trace_scsi_dispatch_cmd_error(cmd, rtn); - if (rtn != SCSI_MLQUEUE_DEVICE_BUSY && - rtn != SCSI_MLQUEUE_TARGET_BUSY) - rtn = SCSI_MLQUEUE_HOST_BUSY; - - scsi_queue_insert(cmd, rtn); - - SCSI_LOG_MLQUEUE(3, - printk("queuecommand : request rejected\n")); - } - - out: - SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n")); - return rtn; -} - -/** - * scsi_done - Enqueue the finished SCSI command into the done queue. - * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives - * ownership back to SCSI Core -- i.e. the LLDD has finished with it. - * - * Description: This function is the mid-level's (SCSI Core) interrupt routine, - * which regains ownership of the SCSI command (de facto) from a LLDD, and - * enqueues the command to the done queue for further processing. - * - * This is the producer of the done queue who enqueues at the tail. - * - * This function is interrupt context safe. - */ -static void scsi_done(struct scsi_cmnd *cmd) -{ - trace_scsi_dispatch_cmd_done(cmd); - blk_complete_request(cmd->request); -} - -/** - * scsi_finish_command - cleanup and pass command back to upper layer - * @cmd: the command - * - * Description: Pass command off to upper layer for finishing of I/O - * request, waking processes that are waiting on results, - * etc. - */ -void scsi_finish_command(struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct scsi_target *starget = scsi_target(sdev); - struct Scsi_Host *shost = sdev->host; - struct scsi_driver *drv; - unsigned int good_bytes; - - scsi_device_unbusy(sdev); - - /* - * Clear the flags which say that the device/host is no longer - * capable of accepting new commands. These are set in scsi_queue.c - * for both the queue full condition on a device, and for a - * host full condition on the host. - * - * XXX(hch): What about locking? - */ - shost->host_blocked = 0; - starget->target_blocked = 0; - sdev->device_blocked = 0; - - /* - * If we have valid sense information, then some kind of recovery - * must have taken place. Make a note of this. - */ - if (SCSI_SENSE_VALID(cmd)) - cmd->result |= (DRIVER_SENSE << 24); - - SCSI_LOG_MLCOMPLETE(4, sdev_printk(KERN_INFO, sdev, - "Notifying upper driver of completion " - "(result %x)\n", cmd->result)); - - good_bytes = scsi_bufflen(cmd); - if (cmd->request->cmd_type != REQ_TYPE_BLOCK_PC) { - int old_good_bytes = good_bytes; - drv = scsi_cmd_to_driver(cmd); - if (drv->done) - good_bytes = drv->done(cmd); - /* - * USB may not give sense identifying bad sector and - * simply return a residue instead, so subtract off the - * residue if drv->done() error processing indicates no - * change to the completion length. - */ - if (good_bytes == old_good_bytes) - good_bytes -= scsi_get_resid(cmd); - } - scsi_io_completion(cmd, good_bytes); -} -EXPORT_SYMBOL(scsi_finish_command); - -/** - * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth - * @sdev: SCSI Device in question - * @tagged: Do we use tagged queueing (non-0) or do we treat - * this device as an untagged device (0) - * @tags: Number of tags allowed if tagged queueing enabled, - * or number of commands the low level driver can - * queue up in non-tagged mode (as per cmd_per_lun). - * - * Returns: Nothing - * - * Lock Status: None held on entry - * - * Notes: Low level drivers may call this at any time and we will do - * the right thing depending on whether or not the device is - * currently active and whether or not it even has the - * command blocks built yet. - */ -void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags) -{ - unsigned long flags; - - /* - * refuse to set tagged depth to an unworkable size - */ - if (tags <= 0) - return; - - spin_lock_irqsave(sdev->request_queue->queue_lock, flags); - - /* - * Check to see if the queue is managed by the block layer. - * If it is, and we fail to adjust the depth, exit. - * - * Do not resize the tag map if it is a host wide share bqt, - * because the size should be the hosts's can_queue. If there - * is more IO than the LLD's can_queue (so there are not enuogh - * tags) request_fn's host queue ready check will handle it. - */ - if (!sdev->host->bqt) { - if (blk_queue_tagged(sdev->request_queue) && - blk_queue_resize_tags(sdev->request_queue, tags) != 0) - goto out; - } - - sdev->queue_depth = tags; - switch (tagged) { - case MSG_ORDERED_TAG: - sdev->ordered_tags = 1; - sdev->simple_tags = 1; - break; - case MSG_SIMPLE_TAG: - sdev->ordered_tags = 0; - sdev->simple_tags = 1; - break; - default: - sdev_printk(KERN_WARNING, sdev, - "scsi_adjust_queue_depth, bad queue type, " - "disabled\n"); - case 0: - sdev->ordered_tags = sdev->simple_tags = 0; - sdev->queue_depth = tags; - break; - } - out: - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); -} -EXPORT_SYMBOL(scsi_adjust_queue_depth); - -/** - * scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth - * @sdev: SCSI Device in question - * @depth: Current number of outstanding SCSI commands on this device, - * not counting the one returned as QUEUE_FULL. - * - * Description: This function will track successive QUEUE_FULL events on a - * specific SCSI device to determine if and when there is a - * need to adjust the queue depth on the device. - * - * Returns: 0 - No change needed, >0 - Adjust queue depth to this new depth, - * -1 - Drop back to untagged operation using host->cmd_per_lun - * as the untagged command depth - * - * Lock Status: None held on entry - * - * Notes: Low level drivers may call this at any time and we will do - * "The Right Thing." We are interrupt context safe. - */ -int scsi_track_queue_full(struct scsi_device *sdev, int depth) -{ - - /* - * Don't let QUEUE_FULLs on the same - * jiffies count, they could all be from - * same event. - */ - if ((jiffies >> 4) == (sdev->last_queue_full_time >> 4)) - return 0; - - sdev->last_queue_full_time = jiffies; - if (sdev->last_queue_full_depth != depth) { - sdev->last_queue_full_count = 1; - sdev->last_queue_full_depth = depth; - } else { - sdev->last_queue_full_count++; - } - - if (sdev->last_queue_full_count <= 10) - return 0; - if (sdev->last_queue_full_depth < 8) { - /* Drop back to untagged */ - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); - return -1; - } - - if (sdev->ordered_tags) - scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth); - else - scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth); - return depth; -} -EXPORT_SYMBOL(scsi_track_queue_full); - -/** - * scsi_vpd_inquiry - Request a device provide us with a VPD page - * @sdev: The device to ask - * @buffer: Where to put the result - * @page: Which Vital Product Data to return - * @len: The length of the buffer - * - * This is an internal helper function. You probably want to use - * scsi_get_vpd_page instead. - * - * Returns 0 on success or a negative error number. - */ -static int scsi_vpd_inquiry(struct scsi_device *sdev, unsigned char *buffer, - u8 page, unsigned len) -{ - int result; - unsigned char cmd[16]; - - cmd[0] = INQUIRY; - cmd[1] = 1; /* EVPD */ - cmd[2] = page; - cmd[3] = len >> 8; - cmd[4] = len & 0xff; - cmd[5] = 0; /* Control byte */ - - /* - * I'm not convinced we need to try quite this hard to get VPD, but - * all the existing users tried this hard. - */ - result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, - len, NULL, 30 * HZ, 3, NULL); - if (result) - return result; - - /* Sanity check that we got the page back that we asked for */ - if (buffer[1] != page) - return -EIO; - - return 0; -} - -/** - * scsi_get_vpd_page - Get Vital Product Data from a SCSI device - * @sdev: The device to ask - * @page: Which Vital Product Data to return - * @buf: where to store the VPD - * @buf_len: number of bytes in the VPD buffer area - * - * SCSI devices may optionally supply Vital Product Data. Each 'page' - * of VPD is defined in the appropriate SCSI document (eg SPC, SBC). - * If the device supports this VPD page, this routine returns a pointer - * to a buffer containing the data from that page. The caller is - * responsible for calling kfree() on this pointer when it is no longer - * needed. If we cannot retrieve the VPD page this routine returns %NULL. - */ -int scsi_get_vpd_page(struct scsi_device *sdev, u8 page, unsigned char *buf, - int buf_len) -{ - int i, result; - - /* Ask for all the pages supported by this device */ - result = scsi_vpd_inquiry(sdev, buf, 0, buf_len); - if (result) - goto fail; - - /* If the user actually wanted this page, we can skip the rest */ - if (page == 0) - return 0; - - for (i = 0; i < min((int)buf[3], buf_len - 4); i++) - if (buf[i + 4] == page) - goto found; - - if (i < buf[3] && i >= buf_len - 4) - /* ran off the end of the buffer, give us benefit of doubt */ - goto found; - /* The device claims it doesn't support the requested page */ - goto fail; - - found: - result = scsi_vpd_inquiry(sdev, buf, page, buf_len); - if (result) - goto fail; - - return 0; - - fail: - return -EINVAL; -} -EXPORT_SYMBOL_GPL(scsi_get_vpd_page); - -/** - * scsi_device_get - get an additional reference to a scsi_device - * @sdev: device to get a reference to - * - * Description: Gets a reference to the scsi_device and increments the use count - * of the underlying LLDD module. You must hold host_lock of the - * parent Scsi_Host or already have a reference when calling this. - */ -int scsi_device_get(struct scsi_device *sdev) -{ - if (sdev->sdev_state == SDEV_DEL) - return -ENXIO; - if (!get_device(&sdev->sdev_gendev)) - return -ENXIO; - /* We can fail this if we're doing SCSI operations - * from module exit (like cache flush) */ - try_module_get(sdev->host->hostt->module); - - return 0; -} -EXPORT_SYMBOL(scsi_device_get); - -/** - * scsi_device_put - release a reference to a scsi_device - * @sdev: device to release a reference on. - * - * Description: Release a reference to the scsi_device and decrements the use - * count of the underlying LLDD module. The device is freed once the last - * user vanishes. - */ -void scsi_device_put(struct scsi_device *sdev) -{ -#ifdef CONFIG_MODULE_UNLOAD - struct module *module = sdev->host->hostt->module; - - /* The module refcount will be zero if scsi_device_get() - * was called from a module removal routine */ - if (module && module_refcount(module) != 0) - module_put(module); -#endif - put_device(&sdev->sdev_gendev); -} -EXPORT_SYMBOL(scsi_device_put); - -/* helper for shost_for_each_device, see that for documentation */ -struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost, - struct scsi_device *prev) -{ - struct list_head *list = (prev ? &prev->siblings : &shost->__devices); - struct scsi_device *next = NULL; - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - while (list->next != &shost->__devices) { - next = list_entry(list->next, struct scsi_device, siblings); - /* skip devices that we can't get a reference to */ - if (!scsi_device_get(next)) - break; - next = NULL; - list = list->next; - } - spin_unlock_irqrestore(shost->host_lock, flags); - - if (prev) - scsi_device_put(prev); - return next; -} -EXPORT_SYMBOL(__scsi_iterate_devices); - -/** - * starget_for_each_device - helper to walk all devices of a target - * @starget: target whose devices we want to iterate over. - * @data: Opaque passed to each function call. - * @fn: Function to call on each device - * - * This traverses over each device of @starget. The devices have - * a reference that must be released by scsi_host_put when breaking - * out of the loop. - */ -void starget_for_each_device(struct scsi_target *starget, void *data, - void (*fn)(struct scsi_device *, void *)) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct scsi_device *sdev; - - shost_for_each_device(sdev, shost) { - if ((sdev->channel == starget->channel) && - (sdev->id == starget->id)) - fn(sdev, data); - } -} -EXPORT_SYMBOL(starget_for_each_device); - -/** - * __starget_for_each_device - helper to walk all devices of a target (UNLOCKED) - * @starget: target whose devices we want to iterate over. - * @data: parameter for callback @fn() - * @fn: callback function that is invoked for each device - * - * This traverses over each device of @starget. It does _not_ - * take a reference on the scsi_device, so the whole loop must be - * protected by shost->host_lock. - * - * Note: The only reason why drivers would want to use this is because - * they need to access the device list in irq context. Otherwise you - * really want to use starget_for_each_device instead. - **/ -void __starget_for_each_device(struct scsi_target *starget, void *data, - void (*fn)(struct scsi_device *, void *)) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct scsi_device *sdev; - - __shost_for_each_device(sdev, shost) { - if ((sdev->channel == starget->channel) && - (sdev->id == starget->id)) - fn(sdev, data); - } -} -EXPORT_SYMBOL(__starget_for_each_device); - -/** - * __scsi_device_lookup_by_target - find a device given the target (UNLOCKED) - * @starget: SCSI target pointer - * @lun: SCSI Logical Unit Number - * - * Description: Looks up the scsi_device with the specified @lun for a given - * @starget. The returned scsi_device does not have an additional - * reference. You must hold the host's host_lock over this call and - * any access to the returned scsi_device. A scsi_device in state - * SDEV_DEL is skipped. - * - * Note: The only reason why drivers should use this is because - * they need to access the device list in irq context. Otherwise you - * really want to use scsi_device_lookup_by_target instead. - **/ -struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget, - uint lun) -{ - struct scsi_device *sdev; - - list_for_each_entry(sdev, &starget->devices, same_target_siblings) { - if (sdev->sdev_state == SDEV_DEL) - continue; - if (sdev->lun ==lun) - return sdev; - } - - return NULL; -} -EXPORT_SYMBOL(__scsi_device_lookup_by_target); - -/** - * scsi_device_lookup_by_target - find a device given the target - * @starget: SCSI target pointer - * @lun: SCSI Logical Unit Number - * - * Description: Looks up the scsi_device with the specified @lun for a given - * @starget. The returned scsi_device has an additional reference that - * needs to be released with scsi_device_put once you're done with it. - **/ -struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget, - uint lun) -{ - struct scsi_device *sdev; - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - sdev = __scsi_device_lookup_by_target(starget, lun); - if (sdev && scsi_device_get(sdev)) - sdev = NULL; - spin_unlock_irqrestore(shost->host_lock, flags); - - return sdev; -} -EXPORT_SYMBOL(scsi_device_lookup_by_target); - -/** - * __scsi_device_lookup - find a device given the host (UNLOCKED) - * @shost: SCSI host pointer - * @channel: SCSI channel (zero if only one channel) - * @id: SCSI target number (physical unit number) - * @lun: SCSI Logical Unit Number - * - * Description: Looks up the scsi_device with the specified @channel, @id, @lun - * for a given host. The returned scsi_device does not have an additional - * reference. You must hold the host's host_lock over this call and any access - * to the returned scsi_device. - * - * Note: The only reason why drivers would want to use this is because - * they need to access the device list in irq context. Otherwise you - * really want to use scsi_device_lookup instead. - **/ -struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost, - uint channel, uint id, uint lun) -{ - struct scsi_device *sdev; - - list_for_each_entry(sdev, &shost->__devices, siblings) { - if (sdev->channel == channel && sdev->id == id && - sdev->lun ==lun) - return sdev; - } - - return NULL; -} -EXPORT_SYMBOL(__scsi_device_lookup); - -/** - * scsi_device_lookup - find a device given the host - * @shost: SCSI host pointer - * @channel: SCSI channel (zero if only one channel) - * @id: SCSI target number (physical unit number) - * @lun: SCSI Logical Unit Number - * - * Description: Looks up the scsi_device with the specified @channel, @id, @lun - * for a given host. The returned scsi_device has an additional reference that - * needs to be released with scsi_device_put once you're done with it. - **/ -struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost, - uint channel, uint id, uint lun) -{ - struct scsi_device *sdev; - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - sdev = __scsi_device_lookup(shost, channel, id, lun); - if (sdev && scsi_device_get(sdev)) - sdev = NULL; - spin_unlock_irqrestore(shost->host_lock, flags); - - return sdev; -} -EXPORT_SYMBOL(scsi_device_lookup); - -MODULE_DESCRIPTION("SCSI core"); -MODULE_LICENSE("GPL"); - -module_param(scsi_logging_level, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels"); - -static int __init init_scsi(void) -{ - int error; - - error = scsi_init_queue(); - if (error) - return error; - error = scsi_init_procfs(); - if (error) - goto cleanup_queue; - error = scsi_init_devinfo(); - if (error) - goto cleanup_procfs; - error = scsi_init_hosts(); - if (error) - goto cleanup_devlist; - error = scsi_init_sysctl(); - if (error) - goto cleanup_hosts; - error = scsi_sysfs_register(); - if (error) - goto cleanup_sysctl; - - scsi_netlink_init(); - - printk(KERN_NOTICE "SCSI subsystem initialized\n"); - return 0; - -cleanup_sysctl: - scsi_exit_sysctl(); -cleanup_hosts: - scsi_exit_hosts(); -cleanup_devlist: - scsi_exit_devinfo(); -cleanup_procfs: - scsi_exit_procfs(); -cleanup_queue: - scsi_exit_queue(); - printk(KERN_ERR "SCSI subsystem failed to initialize, error = %d\n", - -error); - return error; -} - -static void __exit exit_scsi(void) -{ - scsi_netlink_exit(); - scsi_sysfs_unregister(); - scsi_exit_sysctl(); - scsi_exit_hosts(); - scsi_exit_devinfo(); - scsi_exit_procfs(); - scsi_exit_queue(); -} - -subsys_initcall(init_scsi); -module_exit(exit_scsi); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi.h b/ANDROID_3.4.5/drivers/scsi/scsi.h deleted file mode 100644 index d5a55fae..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * scsi.h Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale - * generic SCSI package header file by - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * - * - * - * Modified by Eric Youngdale eric@andante.org to - * add scatter-gather, multiple outstanding request, and other - * enhancements. - */ -/* - * NOTE: this file only contains compatibility glue for old drivers. All - * these wrappers will be removed sooner or later. For new code please use - * the interfaces declared in the headers in include/scsi/ - */ - -#ifndef _SCSI_H -#define _SCSI_H - -#include -#include -#include -#include -#include - -/* - * Some defs, in case these are not defined elsewhere. - */ -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -struct Scsi_Host; -struct scsi_cmnd; -struct scsi_device; -struct scsi_target; -struct scatterlist; - -/* obsolete typedef junk. */ -#include "scsi_typedefs.h" - -#endif /* _SCSI_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_debug.c b/ANDROID_3.4.5/drivers/scsi/scsi_debug.c deleted file mode 100644 index 182d5a57..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_debug.c +++ /dev/null @@ -1,4076 +0,0 @@ -/* - * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv - * Copyright (C) 1992 Eric Youngdale - * Simulate a host adapter with 2 disks attached. Do a lot of checking - * to make sure that we are not getting blocks mixed up, and PANIC if - * anything out of the ordinary is seen. - * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - * - * This version is more generic, simulating a variable number of disk - * (or disk like devices) sharing a common amount of RAM. To be more - * realistic, the simulated devices have the transport attributes of - * SAS disks. - * - * - * For documentation see http://sg.danny.cz/sg/sdebug26.html - * - * D. Gilbert (dpg) work for Magneto-Optical device test [20010421] - * dpg: work for devfs large number of disks [20010809] - * forked for lk 2.5 series [20011216, 20020101] - * use vmalloc() more inquiry+mode_sense [20020302] - * add timers for delayed responses [20020721] - * Patrick Mansfield max_luns+scsi_level [20021031] - * Mike Anderson sysfs work [20021118] - * dpg: change style of boot options to "scsi_debug.num_tgts=2" and - * module options to "modprobe scsi_debug num_tgts=2" [20021221] - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "sd.h" -#include "scsi_logging.h" - -#define SCSI_DEBUG_VERSION "1.82" -static const char * scsi_debug_version_date = "20100324"; - -/* Additional Sense Code (ASC) */ -#define NO_ADDITIONAL_SENSE 0x0 -#define LOGICAL_UNIT_NOT_READY 0x4 -#define UNRECOVERED_READ_ERR 0x11 -#define PARAMETER_LIST_LENGTH_ERR 0x1a -#define INVALID_OPCODE 0x20 -#define ADDR_OUT_OF_RANGE 0x21 -#define INVALID_COMMAND_OPCODE 0x20 -#define INVALID_FIELD_IN_CDB 0x24 -#define INVALID_FIELD_IN_PARAM_LIST 0x26 -#define POWERON_RESET 0x29 -#define SAVING_PARAMS_UNSUP 0x39 -#define TRANSPORT_PROBLEM 0x4b -#define THRESHOLD_EXCEEDED 0x5d -#define LOW_POWER_COND_ON 0x5e - -/* Additional Sense Code Qualifier (ASCQ) */ -#define ACK_NAK_TO 0x3 - -#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ - -/* Default values for driver parameters */ -#define DEF_NUM_HOST 1 -#define DEF_NUM_TGTS 1 -#define DEF_MAX_LUNS 1 -/* With these defaults, this driver will make 1 host with 1 target - * (id 0) containing 1 logical unit (lun 0). That is 1 device. - */ -#define DEF_ATO 1 -#define DEF_DELAY 1 -#define DEF_DEV_SIZE_MB 8 -#define DEF_DIF 0 -#define DEF_DIX 0 -#define DEF_D_SENSE 0 -#define DEF_EVERY_NTH 0 -#define DEF_FAKE_RW 0 -#define DEF_GUARD 0 -#define DEF_LBPU 0 -#define DEF_LBPWS 0 -#define DEF_LBPWS10 0 -#define DEF_LBPRZ 1 -#define DEF_LOWEST_ALIGNED 0 -#define DEF_NO_LUN_0 0 -#define DEF_NUM_PARTS 0 -#define DEF_OPTS 0 -#define DEF_OPT_BLKS 64 -#define DEF_PHYSBLK_EXP 0 -#define DEF_PTYPE 0 -#define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ -#define DEF_SECTOR_SIZE 512 -#define DEF_UNMAP_ALIGNMENT 0 -#define DEF_UNMAP_GRANULARITY 1 -#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF -#define DEF_UNMAP_MAX_DESC 256 -#define DEF_VIRTUAL_GB 0 -#define DEF_VPD_USE_HOSTNO 1 -#define DEF_WRITESAME_LENGTH 0xFFFF - -/* bit mask values for scsi_debug_opts */ -#define SCSI_DEBUG_OPT_NOISE 1 -#define SCSI_DEBUG_OPT_MEDIUM_ERR 2 -#define SCSI_DEBUG_OPT_TIMEOUT 4 -#define SCSI_DEBUG_OPT_RECOVERED_ERR 8 -#define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 -#define SCSI_DEBUG_OPT_DIF_ERR 32 -#define SCSI_DEBUG_OPT_DIX_ERR 64 -#define SCSI_DEBUG_OPT_MAC_TIMEOUT 128 -/* When "every_nth" > 0 then modulo "every_nth" commands: - * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set - * - a RECOVERED_ERROR is simulated on successful read and write - * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. - * - a TRANSPORT_ERROR is simulated on successful read and write - * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. - * - * When "every_nth" < 0 then after "- every_nth" commands: - * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set - * - a RECOVERED_ERROR is simulated on successful read and write - * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. - * - a TRANSPORT_ERROR is simulated on successful read and write - * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. - * This will continue until some other action occurs (e.g. the user - * writing a new value (other than -1 or 1) to every_nth via sysfs). - */ - -/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this - * sector on read commands: */ -#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ -#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ - -/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) - * or "peripheral device" addressing (value 0) */ -#define SAM2_LUN_ADDRESS_METHOD 0 -#define SAM2_WLUN_REPORT_LUNS 0xc101 - -/* Can queue up to this number of commands. Typically commands that - * that have a non-zero delay are queued. */ -#define SCSI_DEBUG_CANQUEUE 255 - -static int scsi_debug_add_host = DEF_NUM_HOST; -static int scsi_debug_ato = DEF_ATO; -static int scsi_debug_delay = DEF_DELAY; -static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; -static int scsi_debug_dif = DEF_DIF; -static int scsi_debug_dix = DEF_DIX; -static int scsi_debug_dsense = DEF_D_SENSE; -static int scsi_debug_every_nth = DEF_EVERY_NTH; -static int scsi_debug_fake_rw = DEF_FAKE_RW; -static int scsi_debug_guard = DEF_GUARD; -static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; -static int scsi_debug_max_luns = DEF_MAX_LUNS; -static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE; -static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; -static int scsi_debug_no_uld = 0; -static int scsi_debug_num_parts = DEF_NUM_PARTS; -static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ -static int scsi_debug_opt_blks = DEF_OPT_BLKS; -static int scsi_debug_opts = DEF_OPTS; -static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; -static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ -static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; -static int scsi_debug_sector_size = DEF_SECTOR_SIZE; -static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; -static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; -static unsigned int scsi_debug_lbpu = DEF_LBPU; -static unsigned int scsi_debug_lbpws = DEF_LBPWS; -static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10; -static unsigned int scsi_debug_lbprz = DEF_LBPRZ; -static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; -static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; -static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; -static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; -static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH; - -static int scsi_debug_cmnd_count = 0; - -#define DEV_READONLY(TGT) (0) -#define DEV_REMOVEABLE(TGT) (0) - -static unsigned int sdebug_store_sectors; -static sector_t sdebug_capacity; /* in sectors */ - -/* old BIOS stuff, kernel may get rid of them but some mode sense pages - may still need them */ -static int sdebug_heads; /* heads per disk */ -static int sdebug_cylinders_per; /* cylinders per surface */ -static int sdebug_sectors_per; /* sectors per cylinder */ - -#define SDEBUG_MAX_PARTS 4 - -#define SDEBUG_SENSE_LEN 32 - -#define SCSI_DEBUG_MAX_CMD_LEN 32 - -static unsigned int scsi_debug_lbp(void) -{ - return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10; -} - -struct sdebug_dev_info { - struct list_head dev_list; - unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ - unsigned int channel; - unsigned int target; - unsigned int lun; - struct sdebug_host_info *sdbg_host; - unsigned int wlun; - char reset; - char stopped; - char used; -}; - -struct sdebug_host_info { - struct list_head host_list; - struct Scsi_Host *shost; - struct device dev; - struct list_head dev_info_list; -}; - -#define to_sdebug_host(d) \ - container_of(d, struct sdebug_host_info, dev) - -static LIST_HEAD(sdebug_host_list); -static DEFINE_SPINLOCK(sdebug_host_list_lock); - -typedef void (* done_funct_t) (struct scsi_cmnd *); - -struct sdebug_queued_cmd { - int in_use; - struct timer_list cmnd_timer; - done_funct_t done_funct; - struct scsi_cmnd * a_cmnd; - int scsi_result; -}; -static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; - -static unsigned char * fake_storep; /* ramdisk storage */ -static unsigned char *dif_storep; /* protection info */ -static void *map_storep; /* provisioning map */ - -static unsigned long map_size; -static int num_aborts = 0; -static int num_dev_resets = 0; -static int num_bus_resets = 0; -static int num_host_resets = 0; -static int dix_writes; -static int dix_reads; -static int dif_errors; - -static DEFINE_SPINLOCK(queued_arr_lock); -static DEFINE_RWLOCK(atomic_rw); - -static char sdebug_proc_name[] = "scsi_debug"; - -static struct bus_type pseudo_lld_bus; - -static inline sector_t dif_offset(sector_t sector) -{ - return sector << 3; -} - -static struct device_driver sdebug_driverfs_driver = { - .name = sdebug_proc_name, - .bus = &pseudo_lld_bus, -}; - -static const int check_condition_result = - (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - -static const int illegal_condition_result = - (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; - -static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, - 0, 0, 0x2, 0x4b}; -static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; - -static int sdebug_add_adapter(void); -static void sdebug_remove_adapter(void); - -static void sdebug_max_tgts_luns(void) -{ - struct sdebug_host_info *sdbg_host; - struct Scsi_Host *hpnt; - - spin_lock(&sdebug_host_list_lock); - list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { - hpnt = sdbg_host->shost; - if ((hpnt->this_id >= 0) && - (scsi_debug_num_tgts > hpnt->this_id)) - hpnt->max_id = scsi_debug_num_tgts + 1; - else - hpnt->max_id = scsi_debug_num_tgts; - /* scsi_debug_max_luns; */ - hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; - } - spin_unlock(&sdebug_host_list_lock); -} - -static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, - int asc, int asq) -{ - unsigned char *sbuff; - - sbuff = devip->sense_buff; - memset(sbuff, 0, SDEBUG_SENSE_LEN); - - scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); - - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " - "[0x%x,0x%x,0x%x]\n", key, asc, asq); -} - -static void get_data_transfer_info(unsigned char *cmd, - unsigned long long *lba, unsigned int *num, - u32 *ei_lba) -{ - *ei_lba = 0; - - switch (*cmd) { - case VARIABLE_LENGTH_CMD: - *lba = (u64)cmd[19] | (u64)cmd[18] << 8 | - (u64)cmd[17] << 16 | (u64)cmd[16] << 24 | - (u64)cmd[15] << 32 | (u64)cmd[14] << 40 | - (u64)cmd[13] << 48 | (u64)cmd[12] << 56; - - *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 | - (u32)cmd[21] << 16 | (u32)cmd[20] << 24; - - *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 | - (u32)cmd[28] << 24; - break; - - case WRITE_SAME_16: - case WRITE_16: - case READ_16: - *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | - (u64)cmd[7] << 16 | (u64)cmd[6] << 24 | - (u64)cmd[5] << 32 | (u64)cmd[4] << 40 | - (u64)cmd[3] << 48 | (u64)cmd[2] << 56; - - *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 | - (u32)cmd[10] << 24; - break; - case WRITE_12: - case READ_12: - *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | - (u32)cmd[2] << 24; - - *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | - (u32)cmd[6] << 24; - break; - case WRITE_SAME: - case WRITE_10: - case READ_10: - case XDWRITEREAD_10: - *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | - (u32)cmd[2] << 24; - - *num = (u32)cmd[8] | (u32)cmd[7] << 8; - break; - case WRITE_6: - case READ_6: - *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | - (u32)(cmd[1] & 0x1f) << 16; - *num = (0 == cmd[4]) ? 256 : cmd[4]; - break; - default: - break; - } -} - -static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) -{ - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { - printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); - } - return -EINVAL; - /* return -ENOTTY; // correct return but upsets fdisk */ -} - -static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, - struct sdebug_dev_info * devip) -{ - if (devip->reset) { - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Reporting Unit " - "attention: power on reset\n"); - devip->reset = 0; - mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); - return check_condition_result; - } - if ((0 == reset_only) && devip->stopped) { - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Reporting Not " - "ready: initializing command required\n"); - mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, - 0x2); - return check_condition_result; - } - return 0; -} - -/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ -static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, - int arr_len) -{ - int act_len; - struct scsi_data_buffer *sdb = scsi_in(scp); - - if (!sdb->length) - return 0; - if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) - return (DID_ERROR << 16); - - act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, - arr, arr_len); - if (sdb->resid) - sdb->resid -= act_len; - else - sdb->resid = scsi_bufflen(scp) - act_len; - - return 0; -} - -/* Returns number of bytes fetched into 'arr' or -1 if error. */ -static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, - int arr_len) -{ - if (!scsi_bufflen(scp)) - return 0; - if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) - return -1; - - return scsi_sg_copy_to_buffer(scp, arr, arr_len); -} - - -static const char * inq_vendor_id = "Linux "; -static const char * inq_product_id = "scsi_debug "; -static const char * inq_product_rev = "0004"; - -static int inquiry_evpd_83(unsigned char * arr, int port_group_id, - int target_dev_id, int dev_id_num, - const char * dev_id_str, - int dev_id_str_len) -{ - int num, port_a; - char b[32]; - - port_a = target_dev_id + 1; - /* T10 vendor identifier field format (faked) */ - arr[0] = 0x2; /* ASCII */ - arr[1] = 0x1; - arr[2] = 0x0; - memcpy(&arr[4], inq_vendor_id, 8); - memcpy(&arr[12], inq_product_id, 16); - memcpy(&arr[28], dev_id_str, dev_id_str_len); - num = 8 + 16 + dev_id_str_len; - arr[3] = num; - num += 4; - if (dev_id_num >= 0) { - /* NAA-5, Logical unit identifier (binary) */ - arr[num++] = 0x1; /* binary (not necessarily sas) */ - arr[num++] = 0x3; /* PIV=0, lu, naa */ - arr[num++] = 0x0; - arr[num++] = 0x8; - arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ - arr[num++] = 0x33; - arr[num++] = 0x33; - arr[num++] = 0x30; - arr[num++] = (dev_id_num >> 24); - arr[num++] = (dev_id_num >> 16) & 0xff; - arr[num++] = (dev_id_num >> 8) & 0xff; - arr[num++] = dev_id_num & 0xff; - /* Target relative port number */ - arr[num++] = 0x61; /* proto=sas, binary */ - arr[num++] = 0x94; /* PIV=1, target port, rel port */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x4; /* length */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x0; - arr[num++] = 0x1; /* relative port A */ - } - /* NAA-5, Target port identifier */ - arr[num++] = 0x61; /* proto=sas, binary */ - arr[num++] = 0x93; /* piv=1, target port, naa */ - arr[num++] = 0x0; - arr[num++] = 0x8; - arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ - arr[num++] = 0x22; - arr[num++] = 0x22; - arr[num++] = 0x20; - arr[num++] = (port_a >> 24); - arr[num++] = (port_a >> 16) & 0xff; - arr[num++] = (port_a >> 8) & 0xff; - arr[num++] = port_a & 0xff; - /* NAA-5, Target port group identifier */ - arr[num++] = 0x61; /* proto=sas, binary */ - arr[num++] = 0x95; /* piv=1, target port group id */ - arr[num++] = 0x0; - arr[num++] = 0x4; - arr[num++] = 0; - arr[num++] = 0; - arr[num++] = (port_group_id >> 8) & 0xff; - arr[num++] = port_group_id & 0xff; - /* NAA-5, Target device identifier */ - arr[num++] = 0x61; /* proto=sas, binary */ - arr[num++] = 0xa3; /* piv=1, target device, naa */ - arr[num++] = 0x0; - arr[num++] = 0x8; - arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ - arr[num++] = 0x22; - arr[num++] = 0x22; - arr[num++] = 0x20; - arr[num++] = (target_dev_id >> 24); - arr[num++] = (target_dev_id >> 16) & 0xff; - arr[num++] = (target_dev_id >> 8) & 0xff; - arr[num++] = target_dev_id & 0xff; - /* SCSI name string: Target device identifier */ - arr[num++] = 0x63; /* proto=sas, UTF-8 */ - arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ - arr[num++] = 0x0; - arr[num++] = 24; - memcpy(arr + num, "naa.52222220", 12); - num += 12; - snprintf(b, sizeof(b), "%08X", target_dev_id); - memcpy(arr + num, b, 8); - num += 8; - memset(arr + num, 0, 4); - num += 4; - return num; -} - - -static unsigned char vpd84_data[] = { -/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, - 0x22,0x22,0x22,0x0,0xbb,0x1, - 0x22,0x22,0x22,0x0,0xbb,0x2, -}; - -static int inquiry_evpd_84(unsigned char * arr) -{ - memcpy(arr, vpd84_data, sizeof(vpd84_data)); - return sizeof(vpd84_data); -} - -static int inquiry_evpd_85(unsigned char * arr) -{ - int num = 0; - const char * na1 = "https://www.kernel.org/config"; - const char * na2 = "http://www.kernel.org/log"; - int plen, olen; - - arr[num++] = 0x1; /* lu, storage config */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x0; - olen = strlen(na1); - plen = olen + 1; - if (plen % 4) - plen = ((plen / 4) + 1) * 4; - arr[num++] = plen; /* length, null termianted, padded */ - memcpy(arr + num, na1, olen); - memset(arr + num + olen, 0, plen - olen); - num += plen; - - arr[num++] = 0x4; /* lu, logging */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x0; - olen = strlen(na2); - plen = olen + 1; - if (plen % 4) - plen = ((plen / 4) + 1) * 4; - arr[num++] = plen; /* length, null terminated, padded */ - memcpy(arr + num, na2, olen); - memset(arr + num + olen, 0, plen - olen); - num += plen; - - return num; -} - -/* SCSI ports VPD page */ -static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) -{ - int num = 0; - int port_a, port_b; - - port_a = target_dev_id + 1; - port_b = port_a + 1; - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x0; - arr[num++] = 0x1; /* relative port 1 (primary) */ - memset(arr + num, 0, 6); - num += 6; - arr[num++] = 0x0; - arr[num++] = 12; /* length tp descriptor */ - /* naa-5 target port identifier (A) */ - arr[num++] = 0x61; /* proto=sas, binary */ - arr[num++] = 0x93; /* PIV=1, target port, NAA */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x8; /* length */ - arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ - arr[num++] = 0x22; - arr[num++] = 0x22; - arr[num++] = 0x20; - arr[num++] = (port_a >> 24); - arr[num++] = (port_a >> 16) & 0xff; - arr[num++] = (port_a >> 8) & 0xff; - arr[num++] = port_a & 0xff; - - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x0; - arr[num++] = 0x2; /* relative port 2 (secondary) */ - memset(arr + num, 0, 6); - num += 6; - arr[num++] = 0x0; - arr[num++] = 12; /* length tp descriptor */ - /* naa-5 target port identifier (B) */ - arr[num++] = 0x61; /* proto=sas, binary */ - arr[num++] = 0x93; /* PIV=1, target port, NAA */ - arr[num++] = 0x0; /* reserved */ - arr[num++] = 0x8; /* length */ - arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ - arr[num++] = 0x22; - arr[num++] = 0x22; - arr[num++] = 0x20; - arr[num++] = (port_b >> 24); - arr[num++] = (port_b >> 16) & 0xff; - arr[num++] = (port_b >> 8) & 0xff; - arr[num++] = port_b & 0xff; - - return num; -} - - -static unsigned char vpd89_data[] = { -/* from 4th byte */ 0,0,0,0, -'l','i','n','u','x',' ',' ',' ', -'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', -'1','2','3','4', -0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, -0xec,0,0,0, -0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, -0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, -0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, -0x53,0x41, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, -0x20,0x20, -0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, -0x10,0x80, -0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, -0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, -0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, -0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, -0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, -0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, -0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, -0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, -0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, -}; - -static int inquiry_evpd_89(unsigned char * arr) -{ - memcpy(arr, vpd89_data, sizeof(vpd89_data)); - return sizeof(vpd89_data); -} - - -/* Block limits VPD page (SBC-3) */ -static unsigned char vpdb0_data[] = { - /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -}; - -static int inquiry_evpd_b0(unsigned char * arr) -{ - unsigned int gran; - - memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); - - /* Optimal transfer length granularity */ - gran = 1 << scsi_debug_physblk_exp; - arr[2] = (gran >> 8) & 0xff; - arr[3] = gran & 0xff; - - /* Maximum Transfer Length */ - if (sdebug_store_sectors > 0x400) { - arr[4] = (sdebug_store_sectors >> 24) & 0xff; - arr[5] = (sdebug_store_sectors >> 16) & 0xff; - arr[6] = (sdebug_store_sectors >> 8) & 0xff; - arr[7] = sdebug_store_sectors & 0xff; - } - - /* Optimal Transfer Length */ - put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); - - if (scsi_debug_lbpu) { - /* Maximum Unmap LBA Count */ - put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); - - /* Maximum Unmap Block Descriptor Count */ - put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); - } - - /* Unmap Granularity Alignment */ - if (scsi_debug_unmap_alignment) { - put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]); - arr[28] |= 0x80; /* UGAVALID */ - } - - /* Optimal Unmap Granularity */ - put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); - - /* Maximum WRITE SAME Length */ - put_unaligned_be64(scsi_debug_write_same_length, &arr[32]); - - return 0x3c; /* Mandatory page length for Logical Block Provisioning */ - - return sizeof(vpdb0_data); -} - -/* Block device characteristics VPD page (SBC-3) */ -static int inquiry_evpd_b1(unsigned char *arr) -{ - memset(arr, 0, 0x3c); - arr[0] = 0; - arr[1] = 1; /* non rotating medium (e.g. solid state) */ - arr[2] = 0; - arr[3] = 5; /* less than 1.8" */ - - return 0x3c; -} - -/* Logical block provisioning VPD page (SBC-3) */ -static int inquiry_evpd_b2(unsigned char *arr) -{ - memset(arr, 0, 0x4); - arr[0] = 0; /* threshold exponent */ - - if (scsi_debug_lbpu) - arr[1] = 1 << 7; - - if (scsi_debug_lbpws) - arr[1] |= 1 << 6; - - if (scsi_debug_lbpws10) - arr[1] |= 1 << 5; - - if (scsi_debug_lbprz) - arr[1] |= 1 << 2; - - return 0x4; -} - -#define SDEBUG_LONG_INQ_SZ 96 -#define SDEBUG_MAX_INQ_ARR_SZ 584 - -static int resp_inquiry(struct scsi_cmnd * scp, int target, - struct sdebug_dev_info * devip) -{ - unsigned char pq_pdt; - unsigned char * arr; - unsigned char *cmd = (unsigned char *)scp->cmnd; - int alloc_len, n, ret; - - alloc_len = (cmd[3] << 8) + cmd[4]; - arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); - if (! arr) - return DID_REQUEUE << 16; - if (devip->wlun) - pq_pdt = 0x1e; /* present, wlun */ - else if (scsi_debug_no_lun_0 && (0 == devip->lun)) - pq_pdt = 0x7f; /* not present, no device type */ - else - pq_pdt = (scsi_debug_ptype & 0x1f); - arr[0] = pq_pdt; - if (0x2 & cmd[1]) { /* CMDDT bit set */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); - kfree(arr); - return check_condition_result; - } else if (0x1 & cmd[1]) { /* EVPD bit set */ - int lu_id_num, port_group_id, target_dev_id, len; - char lu_id_str[6]; - int host_no = devip->sdbg_host->shost->host_no; - - port_group_id = (((host_no + 1) & 0x7f) << 8) + - (devip->channel & 0x7f); - if (0 == scsi_debug_vpd_use_hostno) - host_no = 0; - lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + - (devip->target * 1000) + devip->lun); - target_dev_id = ((host_no + 1) * 2000) + - (devip->target * 1000) - 3; - len = scnprintf(lu_id_str, 6, "%d", lu_id_num); - if (0 == cmd[2]) { /* supported vital product data pages */ - arr[1] = cmd[2]; /*sanity */ - n = 4; - arr[n++] = 0x0; /* this page */ - arr[n++] = 0x80; /* unit serial number */ - arr[n++] = 0x83; /* device identification */ - arr[n++] = 0x84; /* software interface ident. */ - arr[n++] = 0x85; /* management network addresses */ - arr[n++] = 0x86; /* extended inquiry */ - arr[n++] = 0x87; /* mode page policy */ - arr[n++] = 0x88; /* SCSI ports */ - arr[n++] = 0x89; /* ATA information */ - arr[n++] = 0xb0; /* Block limits (SBC) */ - arr[n++] = 0xb1; /* Block characteristics (SBC) */ - if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */ - arr[n++] = 0xb2; - arr[3] = n - 4; /* number of supported VPD pages */ - } else if (0x80 == cmd[2]) { /* unit serial number */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = len; - memcpy(&arr[4], lu_id_str, len); - } else if (0x83 == cmd[2]) { /* device identification */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_83(&arr[4], port_group_id, - target_dev_id, lu_id_num, - lu_id_str, len); - } else if (0x84 == cmd[2]) { /* Software interface ident. */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_84(&arr[4]); - } else if (0x85 == cmd[2]) { /* Management network addresses */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_85(&arr[4]); - } else if (0x86 == cmd[2]) { /* extended inquiry */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = 0x3c; /* number of following entries */ - if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) - arr[4] = 0x4; /* SPT: GRD_CHK:1 */ - else if (scsi_debug_dif) - arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ - else - arr[4] = 0x0; /* no protection stuff */ - arr[5] = 0x7; /* head of q, ordered + simple q's */ - } else if (0x87 == cmd[2]) { /* mode page policy */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = 0x8; /* number of following entries */ - arr[4] = 0x2; /* disconnect-reconnect mp */ - arr[6] = 0x80; /* mlus, shared */ - arr[8] = 0x18; /* protocol specific lu */ - arr[10] = 0x82; /* mlus, per initiator port */ - } else if (0x88 == cmd[2]) { /* SCSI Ports */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); - } else if (0x89 == cmd[2]) { /* ATA information */ - arr[1] = cmd[2]; /*sanity */ - n = inquiry_evpd_89(&arr[4]); - arr[2] = (n >> 8); - arr[3] = (n & 0xff); - } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_b0(&arr[4]); - } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_b1(&arr[4]); - } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */ - arr[1] = cmd[2]; /*sanity */ - arr[3] = inquiry_evpd_b2(&arr[4]); - } else { - /* Illegal request, invalid field in cdb */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - kfree(arr); - return check_condition_result; - } - len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); - ret = fill_from_dev_buffer(scp, arr, - min(len, SDEBUG_MAX_INQ_ARR_SZ)); - kfree(arr); - return ret; - } - /* drops through here for a standard inquiry */ - arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ - arr[2] = scsi_debug_scsi_level; - arr[3] = 2; /* response_data_format==2 */ - arr[4] = SDEBUG_LONG_INQ_SZ - 5; - arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */ - if (0 == scsi_debug_vpd_use_hostno) - arr[5] = 0x10; /* claim: implicit TGPS */ - arr[6] = 0x10; /* claim: MultiP */ - /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ - arr[7] = 0xa; /* claim: LINKED + CMDQUE */ - memcpy(&arr[8], inq_vendor_id, 8); - memcpy(&arr[16], inq_product_id, 16); - memcpy(&arr[32], inq_product_rev, 4); - /* version descriptors (2 bytes each) follow */ - arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ - arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ - n = 62; - if (scsi_debug_ptype == 0) { - arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ - } else if (scsi_debug_ptype == 1) { - arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ - } - arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ - ret = fill_from_dev_buffer(scp, arr, - min(alloc_len, SDEBUG_LONG_INQ_SZ)); - kfree(arr); - return ret; -} - -static int resp_requests(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) -{ - unsigned char * sbuff; - unsigned char *cmd = (unsigned char *)scp->cmnd; - unsigned char arr[SDEBUG_SENSE_LEN]; - int want_dsense; - int len = 18; - - memset(arr, 0, sizeof(arr)); - if (devip->reset == 1) - mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); - want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; - sbuff = devip->sense_buff; - if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { - if (want_dsense) { - arr[0] = 0x72; - arr[1] = 0x0; /* NO_SENSE in sense_key */ - arr[2] = THRESHOLD_EXCEEDED; - arr[3] = 0xff; /* TEST set and MRIE==6 */ - } else { - arr[0] = 0x70; - arr[2] = 0x0; /* NO_SENSE in sense_key */ - arr[7] = 0xa; /* 18 byte sense buffer */ - arr[12] = THRESHOLD_EXCEEDED; - arr[13] = 0xff; /* TEST set and MRIE==6 */ - } - } else { - memcpy(arr, sbuff, SDEBUG_SENSE_LEN); - if ((cmd[1] & 1) && (! scsi_debug_dsense)) { - /* DESC bit set and sense_buff in fixed format */ - memset(arr, 0, sizeof(arr)); - arr[0] = 0x72; - arr[1] = sbuff[2]; /* sense key */ - arr[2] = sbuff[12]; /* asc */ - arr[3] = sbuff[13]; /* ascq */ - len = 8; - } - } - mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); - return fill_from_dev_buffer(scp, arr, len); -} - -static int resp_start_stop(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) -{ - unsigned char *cmd = (unsigned char *)scp->cmnd; - int power_cond, errsts, start; - - if ((errsts = check_readiness(scp, 1, devip))) - return errsts; - power_cond = (cmd[4] & 0xf0) >> 4; - if (power_cond) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); - return check_condition_result; - } - start = cmd[4] & 1; - if (start == devip->stopped) - devip->stopped = !start; - return 0; -} - -static sector_t get_sdebug_capacity(void) -{ - if (scsi_debug_virtual_gb > 0) - return (sector_t)scsi_debug_virtual_gb * - (1073741824 / scsi_debug_sector_size); - else - return sdebug_store_sectors; -} - -#define SDEBUG_READCAP_ARR_SZ 8 -static int resp_readcap(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) -{ - unsigned char arr[SDEBUG_READCAP_ARR_SZ]; - unsigned int capac; - int errsts; - - if ((errsts = check_readiness(scp, 1, devip))) - return errsts; - /* following just in case virtual_gb changed */ - sdebug_capacity = get_sdebug_capacity(); - memset(arr, 0, SDEBUG_READCAP_ARR_SZ); - if (sdebug_capacity < 0xffffffff) { - capac = (unsigned int)sdebug_capacity - 1; - arr[0] = (capac >> 24); - arr[1] = (capac >> 16) & 0xff; - arr[2] = (capac >> 8) & 0xff; - arr[3] = capac & 0xff; - } else { - arr[0] = 0xff; - arr[1] = 0xff; - arr[2] = 0xff; - arr[3] = 0xff; - } - arr[6] = (scsi_debug_sector_size >> 8) & 0xff; - arr[7] = scsi_debug_sector_size & 0xff; - return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); -} - -#define SDEBUG_READCAP16_ARR_SZ 32 -static int resp_readcap16(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) -{ - unsigned char *cmd = (unsigned char *)scp->cmnd; - unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; - unsigned long long capac; - int errsts, k, alloc_len; - - if ((errsts = check_readiness(scp, 1, devip))) - return errsts; - alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) - + cmd[13]); - /* following just in case virtual_gb changed */ - sdebug_capacity = get_sdebug_capacity(); - memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); - capac = sdebug_capacity - 1; - for (k = 0; k < 8; ++k, capac >>= 8) - arr[7 - k] = capac & 0xff; - arr[8] = (scsi_debug_sector_size >> 24) & 0xff; - arr[9] = (scsi_debug_sector_size >> 16) & 0xff; - arr[10] = (scsi_debug_sector_size >> 8) & 0xff; - arr[11] = scsi_debug_sector_size & 0xff; - arr[13] = scsi_debug_physblk_exp & 0xf; - arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; - - if (scsi_debug_lbp()) { - arr[14] |= 0x80; /* LBPME */ - if (scsi_debug_lbprz) - arr[14] |= 0x40; /* LBPRZ */ - } - - arr[15] = scsi_debug_lowest_aligned & 0xff; - - if (scsi_debug_dif) { - arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ - arr[12] |= 1; /* PROT_EN */ - } - - return fill_from_dev_buffer(scp, arr, - min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); -} - -#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 - -static int resp_report_tgtpgs(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) -{ - unsigned char *cmd = (unsigned char *)scp->cmnd; - unsigned char * arr; - int host_no = devip->sdbg_host->shost->host_no; - int n, ret, alen, rlen; - int port_group_a, port_group_b, port_a, port_b; - - alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) - + cmd[9]); - - arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); - if (! arr) - return DID_REQUEUE << 16; - /* - * EVPD page 0x88 states we have two ports, one - * real and a fake port with no device connected. - * So we create two port groups with one port each - * and set the group with port B to unavailable. - */ - port_a = 0x1; /* relative port A */ - port_b = 0x2; /* relative port B */ - port_group_a = (((host_no + 1) & 0x7f) << 8) + - (devip->channel & 0x7f); - port_group_b = (((host_no + 1) & 0x7f) << 8) + - (devip->channel & 0x7f) + 0x80; - - /* - * The asymmetric access state is cycled according to the host_id. - */ - n = 4; - if (0 == scsi_debug_vpd_use_hostno) { - arr[n++] = host_no % 3; /* Asymm access state */ - arr[n++] = 0x0F; /* claim: all states are supported */ - } else { - arr[n++] = 0x0; /* Active/Optimized path */ - arr[n++] = 0x01; /* claim: only support active/optimized paths */ - } - arr[n++] = (port_group_a >> 8) & 0xff; - arr[n++] = port_group_a & 0xff; - arr[n++] = 0; /* Reserved */ - arr[n++] = 0; /* Status code */ - arr[n++] = 0; /* Vendor unique */ - arr[n++] = 0x1; /* One port per group */ - arr[n++] = 0; /* Reserved */ - arr[n++] = 0; /* Reserved */ - arr[n++] = (port_a >> 8) & 0xff; - arr[n++] = port_a & 0xff; - arr[n++] = 3; /* Port unavailable */ - arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ - arr[n++] = (port_group_b >> 8) & 0xff; - arr[n++] = port_group_b & 0xff; - arr[n++] = 0; /* Reserved */ - arr[n++] = 0; /* Status code */ - arr[n++] = 0; /* Vendor unique */ - arr[n++] = 0x1; /* One port per group */ - arr[n++] = 0; /* Reserved */ - arr[n++] = 0; /* Reserved */ - arr[n++] = (port_b >> 8) & 0xff; - arr[n++] = port_b & 0xff; - - rlen = n - 4; - arr[0] = (rlen >> 24) & 0xff; - arr[1] = (rlen >> 16) & 0xff; - arr[2] = (rlen >> 8) & 0xff; - arr[3] = rlen & 0xff; - - /* - * Return the smallest value of either - * - The allocated length - * - The constructed command length - * - The maximum array size - */ - rlen = min(alen,n); - ret = fill_from_dev_buffer(scp, arr, - min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); - kfree(arr); - return ret; -} - -/* <> */ - -static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) -{ /* Read-Write Error Recovery page for mode_sense */ - unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, - 5, 0, 0xff, 0xff}; - - memcpy(p, err_recov_pg, sizeof(err_recov_pg)); - if (1 == pcontrol) - memset(p + 2, 0, sizeof(err_recov_pg) - 2); - return sizeof(err_recov_pg); -} - -static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) -{ /* Disconnect-Reconnect page for mode_sense */ - unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; - - memcpy(p, disconnect_pg, sizeof(disconnect_pg)); - if (1 == pcontrol) - memset(p + 2, 0, sizeof(disconnect_pg) - 2); - return sizeof(disconnect_pg); -} - -static int resp_format_pg(unsigned char * p, int pcontrol, int target) -{ /* Format device page for mode_sense */ - unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0x40, 0, 0, 0}; - - memcpy(p, format_pg, sizeof(format_pg)); - p[10] = (sdebug_sectors_per >> 8) & 0xff; - p[11] = sdebug_sectors_per & 0xff; - p[12] = (scsi_debug_sector_size >> 8) & 0xff; - p[13] = scsi_debug_sector_size & 0xff; - if (DEV_REMOVEABLE(target)) - p[20] |= 0x20; /* should agree with INQUIRY */ - if (1 == pcontrol) - memset(p + 2, 0, sizeof(format_pg) - 2); - return sizeof(format_pg); -} - -static int resp_caching_pg(unsigned char * p, int pcontrol, int target) -{ /* Caching page for mode_sense */ - unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, - 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; - - memcpy(p, caching_pg, sizeof(caching_pg)); - if (1 == pcontrol) - memset(p + 2, 0, sizeof(caching_pg) - 2); - return sizeof(caching_pg); -} - -static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) -{ /* Control mode page for mode_sense */ - unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, - 0, 0, 0, 0}; - unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, - 0, 0, 0x2, 0x4b}; - - if (scsi_debug_dsense) - ctrl_m_pg[2] |= 0x4; - else - ctrl_m_pg[2] &= ~0x4; - - if (scsi_debug_ato) - ctrl_m_pg[5] |= 0x80; /* ATO=1 */ - - memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); - if (1 == pcontrol) - memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); - else if (2 == pcontrol) - memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); - return sizeof(ctrl_m_pg); -} - - -static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) -{ /* Informational Exceptions control mode page for mode_sense */ - unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; - unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, - 0, 0, 0x0, 0x0}; - - memcpy(p, iec_m_pg, sizeof(iec_m_pg)); - if (1 == pcontrol) - memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); - else if (2 == pcontrol) - memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); - return sizeof(iec_m_pg); -} - -static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) -{ /* SAS SSP mode page - short format for mode_sense */ - unsigned char sas_sf_m_pg[] = {0x19, 0x6, - 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; - - memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); - if (1 == pcontrol) - memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); - return sizeof(sas_sf_m_pg); -} - - -static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, - int target_dev_id) -{ /* SAS phy control and discover mode page for mode_sense */ - unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, - 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, - 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, - 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, - 0x2, 0, 0, 0, 0, 0, 0, 0, - 0x88, 0x99, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, - 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, - 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, - 0x3, 0, 0, 0, 0, 0, 0, 0, - 0x88, 0x99, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - }; - int port_a, port_b; - - port_a = target_dev_id + 1; - port_b = port_a + 1; - memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); - p[20] = (port_a >> 24); - p[21] = (port_a >> 16) & 0xff; - p[22] = (port_a >> 8) & 0xff; - p[23] = port_a & 0xff; - p[48 + 20] = (port_b >> 24); - p[48 + 21] = (port_b >> 16) & 0xff; - p[48 + 22] = (port_b >> 8) & 0xff; - p[48 + 23] = port_b & 0xff; - if (1 == pcontrol) - memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); - return sizeof(sas_pcd_m_pg); -} - -static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) -{ /* SAS SSP shared protocol specific port mode subpage */ - unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - }; - - memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); - if (1 == pcontrol) - memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); - return sizeof(sas_sha_m_pg); -} - -#define SDEBUG_MAX_MSENSE_SZ 256 - -static int resp_mode_sense(struct scsi_cmnd * scp, int target, - struct sdebug_dev_info * devip) -{ - unsigned char dbd, llbaa; - int pcontrol, pcode, subpcode, bd_len; - unsigned char dev_spec; - int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; - unsigned char * ap; - unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; - unsigned char *cmd = (unsigned char *)scp->cmnd; - - if ((errsts = check_readiness(scp, 1, devip))) - return errsts; - dbd = !!(cmd[1] & 0x8); - pcontrol = (cmd[2] & 0xc0) >> 6; - pcode = cmd[2] & 0x3f; - subpcode = cmd[3]; - msense_6 = (MODE_SENSE == cmd[0]); - llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); - if ((0 == scsi_debug_ptype) && (0 == dbd)) - bd_len = llbaa ? 16 : 8; - else - bd_len = 0; - alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); - memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); - if (0x3 == pcontrol) { /* Saving values not supported */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, - 0); - return check_condition_result; - } - target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + - (devip->target * 1000) - 3; - /* set DPOFUA bit for disks */ - if (0 == scsi_debug_ptype) - dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; - else - dev_spec = 0x0; - if (msense_6) { - arr[2] = dev_spec; - arr[3] = bd_len; - offset = 4; - } else { - arr[3] = dev_spec; - if (16 == bd_len) - arr[4] = 0x1; /* set LONGLBA bit */ - arr[7] = bd_len; /* assume 255 or less */ - offset = 8; - } - ap = arr + offset; - if ((bd_len > 0) && (!sdebug_capacity)) - sdebug_capacity = get_sdebug_capacity(); - - if (8 == bd_len) { - if (sdebug_capacity > 0xfffffffe) { - ap[0] = 0xff; - ap[1] = 0xff; - ap[2] = 0xff; - ap[3] = 0xff; - } else { - ap[0] = (sdebug_capacity >> 24) & 0xff; - ap[1] = (sdebug_capacity >> 16) & 0xff; - ap[2] = (sdebug_capacity >> 8) & 0xff; - ap[3] = sdebug_capacity & 0xff; - } - ap[6] = (scsi_debug_sector_size >> 8) & 0xff; - ap[7] = scsi_debug_sector_size & 0xff; - offset += bd_len; - ap = arr + offset; - } else if (16 == bd_len) { - unsigned long long capac = sdebug_capacity; - - for (k = 0; k < 8; ++k, capac >>= 8) - ap[7 - k] = capac & 0xff; - ap[12] = (scsi_debug_sector_size >> 24) & 0xff; - ap[13] = (scsi_debug_sector_size >> 16) & 0xff; - ap[14] = (scsi_debug_sector_size >> 8) & 0xff; - ap[15] = scsi_debug_sector_size & 0xff; - offset += bd_len; - ap = arr + offset; - } - - if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { - /* TODO: Control Extension page */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); - return check_condition_result; - } - switch (pcode) { - case 0x1: /* Read-Write error recovery page, direct access */ - len = resp_err_recov_pg(ap, pcontrol, target); - offset += len; - break; - case 0x2: /* Disconnect-Reconnect page, all devices */ - len = resp_disconnect_pg(ap, pcontrol, target); - offset += len; - break; - case 0x3: /* Format device page, direct access */ - len = resp_format_pg(ap, pcontrol, target); - offset += len; - break; - case 0x8: /* Caching page, direct access */ - len = resp_caching_pg(ap, pcontrol, target); - offset += len; - break; - case 0xa: /* Control Mode page, all devices */ - len = resp_ctrl_m_pg(ap, pcontrol, target); - offset += len; - break; - case 0x19: /* if spc==1 then sas phy, control+discover */ - if ((subpcode > 0x2) && (subpcode < 0xff)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - len = 0; - if ((0x0 == subpcode) || (0xff == subpcode)) - len += resp_sas_sf_m_pg(ap + len, pcontrol, target); - if ((0x1 == subpcode) || (0xff == subpcode)) - len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, - target_dev_id); - if ((0x2 == subpcode) || (0xff == subpcode)) - len += resp_sas_sha_m_spg(ap + len, pcontrol); - offset += len; - break; - case 0x1c: /* Informational Exceptions Mode page, all devices */ - len = resp_iec_m_pg(ap, pcontrol, target); - offset += len; - break; - case 0x3f: /* Read all Mode pages */ - if ((0 == subpcode) || (0xff == subpcode)) { - len = resp_err_recov_pg(ap, pcontrol, target); - len += resp_disconnect_pg(ap + len, pcontrol, target); - len += resp_format_pg(ap + len, pcontrol, target); - len += resp_caching_pg(ap + len, pcontrol, target); - len += resp_ctrl_m_pg(ap + len, pcontrol, target); - len += resp_sas_sf_m_pg(ap + len, pcontrol, target); - if (0xff == subpcode) { - len += resp_sas_pcd_m_spg(ap + len, pcontrol, - target, target_dev_id); - len += resp_sas_sha_m_spg(ap + len, pcontrol); - } - len += resp_iec_m_pg(ap + len, pcontrol, target); - } else { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - offset += len; - break; - default: - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); - return check_condition_result; - } - if (msense_6) - arr[0] = offset - 1; - else { - arr[0] = ((offset - 2) >> 8) & 0xff; - arr[1] = (offset - 2) & 0xff; - } - return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); -} - -#define SDEBUG_MAX_MSELECT_SZ 512 - -static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, - struct sdebug_dev_info * devip) -{ - int pf, sp, ps, md_len, bd_len, off, spf, pg_len; - int param_len, res, errsts, mpage; - unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; - unsigned char *cmd = (unsigned char *)scp->cmnd; - - if ((errsts = check_readiness(scp, 1, devip))) - return errsts; - memset(arr, 0, sizeof(arr)); - pf = cmd[1] & 0x10; - sp = cmd[1] & 0x1; - param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); - if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - res = fetch_to_dev_buffer(scp, arr, param_len); - if (-1 == res) - return (DID_ERROR << 16); - else if ((res < param_len) && - (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) - printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " - " IO sent=%d bytes\n", param_len, res); - md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); - bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); - if (md_len > 2) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_PARAM_LIST, 0); - return check_condition_result; - } - off = bd_len + (mselect6 ? 4 : 8); - mpage = arr[off] & 0x3f; - ps = !!(arr[off] & 0x80); - if (ps) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_PARAM_LIST, 0); - return check_condition_result; - } - spf = !!(arr[off] & 0x40); - pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : - (arr[off + 1] + 2); - if ((pg_len + off) > param_len) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - PARAMETER_LIST_LENGTH_ERR, 0); - return check_condition_result; - } - switch (mpage) { - case 0xa: /* Control Mode page */ - if (ctrl_m_pg[1] == arr[off + 1]) { - memcpy(ctrl_m_pg + 2, arr + off + 2, - sizeof(ctrl_m_pg) - 2); - scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); - return 0; - } - break; - case 0x1c: /* Informational Exceptions Mode page */ - if (iec_m_pg[1] == arr[off + 1]) { - memcpy(iec_m_pg + 2, arr + off + 2, - sizeof(iec_m_pg) - 2); - return 0; - } - break; - default: - break; - } - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_PARAM_LIST, 0); - return check_condition_result; -} - -static int resp_temp_l_pg(unsigned char * arr) -{ - unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, - 0x0, 0x1, 0x3, 0x2, 0x0, 65, - }; - - memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); - return sizeof(temp_l_pg); -} - -static int resp_ie_l_pg(unsigned char * arr) -{ - unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, - }; - - memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); - if (iec_m_pg[2] & 0x4) { /* TEST bit set */ - arr[4] = THRESHOLD_EXCEEDED; - arr[5] = 0xff; - } - return sizeof(ie_l_pg); -} - -#define SDEBUG_MAX_LSENSE_SZ 512 - -static int resp_log_sense(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) -{ - int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; - unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; - unsigned char *cmd = (unsigned char *)scp->cmnd; - - if ((errsts = check_readiness(scp, 1, devip))) - return errsts; - memset(arr, 0, sizeof(arr)); - ppc = cmd[1] & 0x2; - sp = cmd[1] & 0x1; - if (ppc || sp) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - pcontrol = (cmd[2] & 0xc0) >> 6; - pcode = cmd[2] & 0x3f; - subpcode = cmd[3] & 0xff; - alloc_len = (cmd[7] << 8) + cmd[8]; - arr[0] = pcode; - if (0 == subpcode) { - switch (pcode) { - case 0x0: /* Supported log pages log page */ - n = 4; - arr[n++] = 0x0; /* this page */ - arr[n++] = 0xd; /* Temperature */ - arr[n++] = 0x2f; /* Informational exceptions */ - arr[3] = n - 4; - break; - case 0xd: /* Temperature log page */ - arr[3] = resp_temp_l_pg(arr + 4); - break; - case 0x2f: /* Informational exceptions log page */ - arr[3] = resp_ie_l_pg(arr + 4); - break; - default: - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - } else if (0xff == subpcode) { - arr[0] |= 0x40; - arr[1] = subpcode; - switch (pcode) { - case 0x0: /* Supported log pages and subpages log page */ - n = 4; - arr[n++] = 0x0; - arr[n++] = 0x0; /* 0,0 page */ - arr[n++] = 0x0; - arr[n++] = 0xff; /* this page */ - arr[n++] = 0xd; - arr[n++] = 0x0; /* Temperature */ - arr[n++] = 0x2f; - arr[n++] = 0x0; /* Informational exceptions */ - arr[3] = n - 4; - break; - case 0xd: /* Temperature subpages */ - n = 4; - arr[n++] = 0xd; - arr[n++] = 0x0; /* Temperature */ - arr[3] = n - 4; - break; - case 0x2f: /* Informational exceptions subpages */ - n = 4; - arr[n++] = 0x2f; - arr[n++] = 0x0; /* Informational exceptions */ - arr[3] = n - 4; - break; - default: - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - } else { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); - return fill_from_dev_buffer(scp, arr, - min(len, SDEBUG_MAX_INQ_ARR_SZ)); -} - -static int check_device_access_params(struct sdebug_dev_info *devi, - unsigned long long lba, unsigned int num) -{ - if (lba + num > sdebug_capacity) { - mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); - return check_condition_result; - } - /* transfer length excessive (tie in to block limits VPD page) */ - if (num > sdebug_store_sectors) { - mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); - return check_condition_result; - } - return 0; -} - -static int do_device_access(struct scsi_cmnd *scmd, - struct sdebug_dev_info *devi, - unsigned long long lba, unsigned int num, int write) -{ - int ret; - unsigned long long block, rest = 0; - int (*func)(struct scsi_cmnd *, unsigned char *, int); - - func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; - - block = do_div(lba, sdebug_store_sectors); - if (block + num > sdebug_store_sectors) - rest = block + num - sdebug_store_sectors; - - ret = func(scmd, fake_storep + (block * scsi_debug_sector_size), - (num - rest) * scsi_debug_sector_size); - if (!ret && rest) - ret = func(scmd, fake_storep, rest * scsi_debug_sector_size); - - return ret; -} - -static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, - unsigned int sectors, u32 ei_lba) -{ - unsigned int i, resid; - struct scatterlist *psgl; - struct sd_dif_tuple *sdt; - sector_t sector; - sector_t tmp_sec = start_sec; - void *paddr; - - start_sec = do_div(tmp_sec, sdebug_store_sectors); - - sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec)); - - for (i = 0 ; i < sectors ; i++) { - u16 csum; - - if (sdt[i].app_tag == 0xffff) - continue; - - sector = start_sec + i; - - switch (scsi_debug_guard) { - case 1: - csum = ip_compute_csum(fake_storep + - sector * scsi_debug_sector_size, - scsi_debug_sector_size); - break; - case 0: - csum = crc_t10dif(fake_storep + - sector * scsi_debug_sector_size, - scsi_debug_sector_size); - csum = cpu_to_be16(csum); - break; - default: - BUG(); - } - - if (sdt[i].guard_tag != csum) { - printk(KERN_ERR "%s: GUARD check failed on sector %lu" \ - " rcvd 0x%04x, data 0x%04x\n", __func__, - (unsigned long)sector, - be16_to_cpu(sdt[i].guard_tag), - be16_to_cpu(csum)); - dif_errors++; - return 0x01; - } - - if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && - be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { - printk(KERN_ERR "%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); - dif_errors++; - return 0x03; - } - - if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && - be32_to_cpu(sdt[i].ref_tag) != ei_lba) { - printk(KERN_ERR "%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); - dif_errors++; - return 0x03; - } - - ei_lba++; - } - - resid = sectors * 8; /* Bytes of protection data to copy into sgl */ - sector = start_sec; - - scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { - int len = min(psgl->length, resid); - - paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; - memcpy(paddr, dif_storep + dif_offset(sector), len); - - sector += len >> 3; - if (sector >= sdebug_store_sectors) { - /* Force wrap */ - tmp_sec = sector; - sector = do_div(tmp_sec, sdebug_store_sectors); - } - resid -= len; - kunmap_atomic(paddr); - } - - dix_reads++; - - return 0; -} - -static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info *devip, - u32 ei_lba) -{ - unsigned long iflags; - int ret; - - ret = check_device_access_params(devip, lba, num); - if (ret) - return ret; - - if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && - (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && - ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { - /* claim unrecoverable read error */ - mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); - /* set info field and valid bit for fixed descriptor */ - if (0x70 == (devip->sense_buff[0] & 0x7f)) { - devip->sense_buff[0] |= 0x80; /* Valid bit */ - ret = (lba < OPT_MEDIUM_ERR_ADDR) - ? OPT_MEDIUM_ERR_ADDR : (int)lba; - devip->sense_buff[3] = (ret >> 24) & 0xff; - devip->sense_buff[4] = (ret >> 16) & 0xff; - devip->sense_buff[5] = (ret >> 8) & 0xff; - devip->sense_buff[6] = ret & 0xff; - } - scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); - return check_condition_result; - } - - /* DIX + T10 DIF */ - if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { - int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba); - - if (prot_ret) { - mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); - return illegal_condition_result; - } - } - - read_lock_irqsave(&atomic_rw, iflags); - ret = do_device_access(SCpnt, devip, lba, num, 0); - read_unlock_irqrestore(&atomic_rw, iflags); - return ret; -} - -void dump_sector(unsigned char *buf, int len) -{ - int i, j; - - printk(KERN_ERR ">>> Sector Dump <<<\n"); - - for (i = 0 ; i < len ; i += 16) { - printk(KERN_ERR "%04d: ", i); - - for (j = 0 ; j < 16 ; j++) { - unsigned char c = buf[i+j]; - if (c >= 0x20 && c < 0x7e) - printk(" %c ", buf[i+j]); - else - printk("%02x ", buf[i+j]); - } - - printk("\n"); - } -} - -static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, - unsigned int sectors, u32 ei_lba) -{ - int i, j, ret; - struct sd_dif_tuple *sdt; - struct scatterlist *dsgl = scsi_sglist(SCpnt); - struct scatterlist *psgl = scsi_prot_sglist(SCpnt); - void *daddr, *paddr; - sector_t tmp_sec = start_sec; - sector_t sector; - int ppage_offset; - unsigned short csum; - - sector = do_div(tmp_sec, sdebug_store_sectors); - - BUG_ON(scsi_sg_count(SCpnt) == 0); - BUG_ON(scsi_prot_sg_count(SCpnt) == 0); - - paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; - ppage_offset = 0; - - /* For each data page */ - scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { - daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset; - - /* For each sector-sized chunk in data page */ - for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { - - /* If we're at the end of the current - * protection page advance to the next one - */ - if (ppage_offset >= psgl->length) { - kunmap_atomic(paddr); - psgl = sg_next(psgl); - BUG_ON(psgl == NULL); - paddr = kmap_atomic(sg_page(psgl)) - + psgl->offset; - ppage_offset = 0; - } - - sdt = paddr + ppage_offset; - - switch (scsi_debug_guard) { - case 1: - csum = ip_compute_csum(daddr, - scsi_debug_sector_size); - break; - case 0: - csum = cpu_to_be16(crc_t10dif(daddr, - scsi_debug_sector_size)); - break; - default: - BUG(); - ret = 0; - goto out; - } - - if (sdt->guard_tag != csum) { - printk(KERN_ERR - "%s: GUARD check failed on sector %lu " \ - "rcvd 0x%04x, calculated 0x%04x\n", - __func__, (unsigned long)sector, - be16_to_cpu(sdt->guard_tag), - be16_to_cpu(csum)); - ret = 0x01; - dump_sector(daddr, scsi_debug_sector_size); - goto out; - } - - if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && - be32_to_cpu(sdt->ref_tag) - != (start_sec & 0xffffffff)) { - printk(KERN_ERR - "%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); - ret = 0x03; - dump_sector(daddr, scsi_debug_sector_size); - goto out; - } - - if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && - be32_to_cpu(sdt->ref_tag) != ei_lba) { - printk(KERN_ERR - "%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); - ret = 0x03; - dump_sector(daddr, scsi_debug_sector_size); - goto out; - } - - /* Would be great to copy this in bigger - * chunks. However, for the sake of - * correctness we need to verify each sector - * before writing it to "stable" storage - */ - memcpy(dif_storep + dif_offset(sector), sdt, 8); - - sector++; - - if (sector == sdebug_store_sectors) - sector = 0; /* Force wrap */ - - start_sec++; - ei_lba++; - daddr += scsi_debug_sector_size; - ppage_offset += sizeof(struct sd_dif_tuple); - } - - kunmap_atomic(daddr); - } - - kunmap_atomic(paddr); - - dix_writes++; - - return 0; - -out: - dif_errors++; - kunmap_atomic(daddr); - kunmap_atomic(paddr); - return ret; -} - -static unsigned int map_state(sector_t lba, unsigned int *num) -{ - unsigned int granularity, alignment, mapped; - sector_t block, next, end; - - granularity = scsi_debug_unmap_granularity; - alignment = granularity - scsi_debug_unmap_alignment; - block = lba + alignment; - do_div(block, granularity); - - mapped = test_bit(block, map_storep); - - if (mapped) - next = find_next_zero_bit(map_storep, map_size, block); - else - next = find_next_bit(map_storep, map_size, block); - - end = next * granularity - scsi_debug_unmap_alignment; - *num = end - lba; - - return mapped; -} - -static void map_region(sector_t lba, unsigned int len) -{ - unsigned int granularity, alignment; - sector_t end = lba + len; - - granularity = scsi_debug_unmap_granularity; - alignment = granularity - scsi_debug_unmap_alignment; - - while (lba < end) { - sector_t block, rem; - - block = lba + alignment; - rem = do_div(block, granularity); - - if (block < map_size) - set_bit(block, map_storep); - - lba += granularity - rem; - } -} - -static void unmap_region(sector_t lba, unsigned int len) -{ - unsigned int granularity, alignment; - sector_t end = lba + len; - - granularity = scsi_debug_unmap_granularity; - alignment = granularity - scsi_debug_unmap_alignment; - - while (lba < end) { - sector_t block, rem; - - block = lba + alignment; - rem = do_div(block, granularity); - - if (rem == 0 && lba + granularity <= end && block < map_size) { - clear_bit(block, map_storep); - if (scsi_debug_lbprz) - memset(fake_storep + - block * scsi_debug_sector_size, 0, - scsi_debug_sector_size); - } - lba += granularity - rem; - } -} - -static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, - unsigned int num, struct sdebug_dev_info *devip, - u32 ei_lba) -{ - unsigned long iflags; - int ret; - - ret = check_device_access_params(devip, lba, num); - if (ret) - return ret; - - /* DIX + T10 DIF */ - if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { - int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba); - - if (prot_ret) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); - return illegal_condition_result; - } - } - - write_lock_irqsave(&atomic_rw, iflags); - ret = do_device_access(SCpnt, devip, lba, num, 1); - if (scsi_debug_unmap_granularity) - map_region(lba, num); - write_unlock_irqrestore(&atomic_rw, iflags); - if (-1 == ret) - return (DID_ERROR << 16); - else if ((ret < (num * scsi_debug_sector_size)) && - (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) - printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " - " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); - - return 0; -} - -static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba, - unsigned int num, struct sdebug_dev_info *devip, - u32 ei_lba, unsigned int unmap) -{ - unsigned long iflags; - unsigned long long i; - int ret; - - ret = check_device_access_params(devip, lba, num); - if (ret) - return ret; - - if (num > scsi_debug_write_same_length) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); - return check_condition_result; - } - - write_lock_irqsave(&atomic_rw, iflags); - - if (unmap && scsi_debug_unmap_granularity) { - unmap_region(lba, num); - goto out; - } - - /* Else fetch one logical block */ - ret = fetch_to_dev_buffer(scmd, - fake_storep + (lba * scsi_debug_sector_size), - scsi_debug_sector_size); - - if (-1 == ret) { - write_unlock_irqrestore(&atomic_rw, iflags); - return (DID_ERROR << 16); - } else if ((ret < (num * scsi_debug_sector_size)) && - (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) - printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, " - " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); - - /* Copy first sector to remaining blocks */ - for (i = 1 ; i < num ; i++) - memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size), - fake_storep + (lba * scsi_debug_sector_size), - scsi_debug_sector_size); - - if (scsi_debug_unmap_granularity) - map_region(lba, num); -out: - write_unlock_irqrestore(&atomic_rw, iflags); - - return 0; -} - -struct unmap_block_desc { - __be64 lba; - __be32 blocks; - __be32 __reserved; -}; - -static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip) -{ - unsigned char *buf; - struct unmap_block_desc *desc; - unsigned int i, payload_len, descriptors; - int ret; - - ret = check_readiness(scmd, 1, devip); - if (ret) - return ret; - - payload_len = get_unaligned_be16(&scmd->cmnd[7]); - BUG_ON(scsi_bufflen(scmd) != payload_len); - - descriptors = (payload_len - 8) / 16; - - buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC); - if (!buf) - return check_condition_result; - - scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd)); - - BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); - BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); - - desc = (void *)&buf[8]; - - for (i = 0 ; i < descriptors ; i++) { - unsigned long long lba = get_unaligned_be64(&desc[i].lba); - unsigned int num = get_unaligned_be32(&desc[i].blocks); - - ret = check_device_access_params(devip, lba, num); - if (ret) - goto out; - - unmap_region(lba, num); - } - - ret = 0; - -out: - kfree(buf); - - return ret; -} - -#define SDEBUG_GET_LBA_STATUS_LEN 32 - -static int resp_get_lba_status(struct scsi_cmnd * scmd, - struct sdebug_dev_info * devip) -{ - unsigned long long lba; - unsigned int alloc_len, mapped, num; - unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN]; - int ret; - - ret = check_readiness(scmd, 1, devip); - if (ret) - return ret; - - lba = get_unaligned_be64(&scmd->cmnd[2]); - alloc_len = get_unaligned_be32(&scmd->cmnd[10]); - - if (alloc_len < 24) - return 0; - - ret = check_device_access_params(devip, lba, 1); - if (ret) - return ret; - - mapped = map_state(lba, &num); - - memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); - put_unaligned_be32(20, &arr[0]); /* Parameter Data Length */ - put_unaligned_be64(lba, &arr[8]); /* LBA */ - put_unaligned_be32(num, &arr[16]); /* Number of blocks */ - arr[20] = !mapped; /* mapped = 0, unmapped = 1 */ - - return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN); -} - -#define SDEBUG_RLUN_ARR_SZ 256 - -static int resp_report_luns(struct scsi_cmnd * scp, - struct sdebug_dev_info * devip) -{ - unsigned int alloc_len; - int lun_cnt, i, upper, num, n, wlun, lun; - unsigned char *cmd = (unsigned char *)scp->cmnd; - int select_report = (int)cmd[2]; - struct scsi_lun *one_lun; - unsigned char arr[SDEBUG_RLUN_ARR_SZ]; - unsigned char * max_addr; - - alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); - if ((alloc_len < 4) || (select_report > 2)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, - 0); - return check_condition_result; - } - /* can produce response with up to 16k luns (lun 0 to lun 16383) */ - memset(arr, 0, SDEBUG_RLUN_ARR_SZ); - lun_cnt = scsi_debug_max_luns; - if (1 == select_report) - lun_cnt = 0; - else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) - --lun_cnt; - wlun = (select_report > 0) ? 1 : 0; - num = lun_cnt + wlun; - arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; - arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; - n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / - sizeof(struct scsi_lun)), num); - if (n < num) { - wlun = 0; - lun_cnt = n; - } - one_lun = (struct scsi_lun *) &arr[8]; - max_addr = arr + SDEBUG_RLUN_ARR_SZ; - for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); - ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); - i++, lun++) { - upper = (lun >> 8) & 0x3f; - if (upper) - one_lun[i].scsi_lun[0] = - (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); - one_lun[i].scsi_lun[1] = lun & 0xff; - } - if (wlun) { - one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; - one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; - i++; - } - alloc_len = (unsigned char *)(one_lun + i) - arr; - return fill_from_dev_buffer(scp, arr, - min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); -} - -static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, - unsigned int num, struct sdebug_dev_info *devip) -{ - int i, j, ret = -1; - unsigned char *kaddr, *buf; - unsigned int offset; - struct scatterlist *sg; - struct scsi_data_buffer *sdb = scsi_in(scp); - - /* better not to use temporary buffer. */ - buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); - if (!buf) - return ret; - - scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); - - offset = 0; - for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { - kaddr = (unsigned char *)kmap_atomic(sg_page(sg)); - if (!kaddr) - goto out; - - for (j = 0; j < sg->length; j++) - *(kaddr + sg->offset + j) ^= *(buf + offset + j); - - offset += sg->length; - kunmap_atomic(kaddr); - } - ret = 0; -out: - kfree(buf); - - return ret; -} - -/* When timer goes off this function is called. */ -static void timer_intr_handler(unsigned long indx) -{ - struct sdebug_queued_cmd * sqcp; - unsigned long iflags; - - if (indx >= scsi_debug_max_queue) { - printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " - "large\n"); - return; - } - spin_lock_irqsave(&queued_arr_lock, iflags); - sqcp = &queued_arr[(int)indx]; - if (! sqcp->in_use) { - printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " - "interrupt\n"); - spin_unlock_irqrestore(&queued_arr_lock, iflags); - return; - } - sqcp->in_use = 0; - if (sqcp->done_funct) { - sqcp->a_cmnd->result = sqcp->scsi_result; - sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ - } - sqcp->done_funct = NULL; - spin_unlock_irqrestore(&queued_arr_lock, iflags); -} - - -static struct sdebug_dev_info * -sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) -{ - struct sdebug_dev_info *devip; - - devip = kzalloc(sizeof(*devip), flags); - if (devip) { - devip->sdbg_host = sdbg_host; - list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); - } - return devip; -} - -static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) -{ - struct sdebug_host_info * sdbg_host; - struct sdebug_dev_info * open_devip = NULL; - struct sdebug_dev_info * devip = - (struct sdebug_dev_info *)sdev->hostdata; - - if (devip) - return devip; - sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); - if (!sdbg_host) { - printk(KERN_ERR "Host info NULL\n"); - return NULL; - } - list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { - if ((devip->used) && (devip->channel == sdev->channel) && - (devip->target == sdev->id) && - (devip->lun == sdev->lun)) - return devip; - else { - if ((!devip->used) && (!open_devip)) - open_devip = devip; - } - } - if (!open_devip) { /* try and make a new one */ - open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); - if (!open_devip) { - printk(KERN_ERR "%s: out of memory at line %d\n", - __func__, __LINE__); - return NULL; - } - } - - open_devip->channel = sdev->channel; - open_devip->target = sdev->id; - open_devip->lun = sdev->lun; - open_devip->sdbg_host = sdbg_host; - open_devip->reset = 1; - open_devip->used = 1; - memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); - if (scsi_debug_dsense) - open_devip->sense_buff[0] = 0x72; - else { - open_devip->sense_buff[0] = 0x70; - open_devip->sense_buff[7] = 0xa; - } - if (sdev->lun == SAM2_WLUN_REPORT_LUNS) - open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; - - return open_devip; -} - -static int scsi_debug_slave_alloc(struct scsi_device *sdp) -{ - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", - sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); - return 0; -} - -static int scsi_debug_slave_configure(struct scsi_device *sdp) -{ - struct sdebug_dev_info *devip; - - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", - sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) - sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; - devip = devInfoReg(sdp); - if (NULL == devip) - return 1; /* no resources, will be marked offline */ - sdp->hostdata = devip; - if (sdp->host->cmd_per_lun) - scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, - sdp->host->cmd_per_lun); - blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); - if (scsi_debug_no_uld) - sdp->no_uld_attach = 1; - return 0; -} - -static void scsi_debug_slave_destroy(struct scsi_device *sdp) -{ - struct sdebug_dev_info *devip = - (struct sdebug_dev_info *)sdp->hostdata; - - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", - sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); - if (devip) { - /* make this slot available for re-use */ - devip->used = 0; - sdp->hostdata = NULL; - } -} - -/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ -static int stop_queued_cmnd(struct scsi_cmnd *cmnd) -{ - unsigned long iflags; - int k; - struct sdebug_queued_cmd *sqcp; - - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < scsi_debug_max_queue; ++k) { - sqcp = &queued_arr[k]; - if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { - del_timer_sync(&sqcp->cmnd_timer); - sqcp->in_use = 0; - sqcp->a_cmnd = NULL; - break; - } - } - spin_unlock_irqrestore(&queued_arr_lock, iflags); - return (k < scsi_debug_max_queue) ? 1 : 0; -} - -/* Deletes (stops) timers of all queued commands */ -static void stop_all_queued(void) -{ - unsigned long iflags; - int k; - struct sdebug_queued_cmd *sqcp; - - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < scsi_debug_max_queue; ++k) { - sqcp = &queued_arr[k]; - if (sqcp->in_use && sqcp->a_cmnd) { - del_timer_sync(&sqcp->cmnd_timer); - sqcp->in_use = 0; - sqcp->a_cmnd = NULL; - } - } - spin_unlock_irqrestore(&queued_arr_lock, iflags); -} - -static int scsi_debug_abort(struct scsi_cmnd * SCpnt) -{ - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: abort\n"); - ++num_aborts; - stop_queued_cmnd(SCpnt); - return SUCCESS; -} - -static int scsi_debug_biosparam(struct scsi_device *sdev, - struct block_device * bdev, sector_t capacity, int *info) -{ - int res; - unsigned char *buf; - - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: biosparam\n"); - buf = scsi_bios_ptable(bdev); - if (buf) { - res = scsi_partsize(buf, capacity, - &info[2], &info[0], &info[1]); - kfree(buf); - if (! res) - return res; - } - info[0] = sdebug_heads; - info[1] = sdebug_sectors_per; - info[2] = sdebug_cylinders_per; - return 0; -} - -static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) -{ - struct sdebug_dev_info * devip; - - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: device_reset\n"); - ++num_dev_resets; - if (SCpnt) { - devip = devInfoReg(SCpnt->device); - if (devip) - devip->reset = 1; - } - return SUCCESS; -} - -static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) -{ - struct sdebug_host_info *sdbg_host; - struct sdebug_dev_info * dev_info; - struct scsi_device * sdp; - struct Scsi_Host * hp; - - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: bus_reset\n"); - ++num_bus_resets; - if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { - sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); - if (sdbg_host) { - list_for_each_entry(dev_info, - &sdbg_host->dev_info_list, - dev_list) - dev_info->reset = 1; - } - } - return SUCCESS; -} - -static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) -{ - struct sdebug_host_info * sdbg_host; - struct sdebug_dev_info * dev_info; - - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: host_reset\n"); - ++num_host_resets; - spin_lock(&sdebug_host_list_lock); - list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { - list_for_each_entry(dev_info, &sdbg_host->dev_info_list, - dev_list) - dev_info->reset = 1; - } - spin_unlock(&sdebug_host_list_lock); - stop_all_queued(); - return SUCCESS; -} - -/* Initializes timers in queued array */ -static void __init init_all_queued(void) -{ - unsigned long iflags; - int k; - struct sdebug_queued_cmd * sqcp; - - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < scsi_debug_max_queue; ++k) { - sqcp = &queued_arr[k]; - init_timer(&sqcp->cmnd_timer); - sqcp->in_use = 0; - sqcp->a_cmnd = NULL; - } - spin_unlock_irqrestore(&queued_arr_lock, iflags); -} - -static void __init sdebug_build_parts(unsigned char *ramp, - unsigned long store_size) -{ - struct partition * pp; - int starts[SDEBUG_MAX_PARTS + 2]; - int sectors_per_part, num_sectors, k; - int heads_by_sects, start_sec, end_sec; - - /* assume partition table already zeroed */ - if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) - return; - if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { - scsi_debug_num_parts = SDEBUG_MAX_PARTS; - printk(KERN_WARNING "scsi_debug:build_parts: reducing " - "partitions to %d\n", SDEBUG_MAX_PARTS); - } - num_sectors = (int)sdebug_store_sectors; - sectors_per_part = (num_sectors - sdebug_sectors_per) - / scsi_debug_num_parts; - heads_by_sects = sdebug_heads * sdebug_sectors_per; - starts[0] = sdebug_sectors_per; - for (k = 1; k < scsi_debug_num_parts; ++k) - starts[k] = ((k * sectors_per_part) / heads_by_sects) - * heads_by_sects; - starts[scsi_debug_num_parts] = num_sectors; - starts[scsi_debug_num_parts + 1] = 0; - - ramp[510] = 0x55; /* magic partition markings */ - ramp[511] = 0xAA; - pp = (struct partition *)(ramp + 0x1be); - for (k = 0; starts[k + 1]; ++k, ++pp) { - start_sec = starts[k]; - end_sec = starts[k + 1] - 1; - pp->boot_ind = 0; - - pp->cyl = start_sec / heads_by_sects; - pp->head = (start_sec - (pp->cyl * heads_by_sects)) - / sdebug_sectors_per; - pp->sector = (start_sec % sdebug_sectors_per) + 1; - - pp->end_cyl = end_sec / heads_by_sects; - pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) - / sdebug_sectors_per; - pp->end_sector = (end_sec % sdebug_sectors_per) + 1; - - pp->start_sect = start_sec; - pp->nr_sects = end_sec - start_sec + 1; - pp->sys_ind = 0x83; /* plain Linux partition */ - } -} - -static int schedule_resp(struct scsi_cmnd * cmnd, - struct sdebug_dev_info * devip, - done_funct_t done, int scsi_result, int delta_jiff) -{ - if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { - if (scsi_result) { - struct scsi_device * sdp = cmnd->device; - - printk(KERN_INFO "scsi_debug: <%u %u %u %u> " - "non-zero result=0x%x\n", sdp->host->host_no, - sdp->channel, sdp->id, sdp->lun, scsi_result); - } - } - if (cmnd && devip) { - /* simulate autosense by this driver */ - if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) - memcpy(cmnd->sense_buffer, devip->sense_buff, - (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? - SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); - } - if (delta_jiff <= 0) { - if (cmnd) - cmnd->result = scsi_result; - if (done) - done(cmnd); - return 0; - } else { - unsigned long iflags; - int k; - struct sdebug_queued_cmd * sqcp = NULL; - - spin_lock_irqsave(&queued_arr_lock, iflags); - for (k = 0; k < scsi_debug_max_queue; ++k) { - sqcp = &queued_arr[k]; - if (! sqcp->in_use) - break; - } - if (k >= scsi_debug_max_queue) { - spin_unlock_irqrestore(&queued_arr_lock, iflags); - printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); - return 1; /* report busy to mid level */ - } - sqcp->in_use = 1; - sqcp->a_cmnd = cmnd; - sqcp->scsi_result = scsi_result; - sqcp->done_funct = done; - sqcp->cmnd_timer.function = timer_intr_handler; - sqcp->cmnd_timer.data = k; - sqcp->cmnd_timer.expires = jiffies + delta_jiff; - add_timer(&sqcp->cmnd_timer); - spin_unlock_irqrestore(&queued_arr_lock, iflags); - if (cmnd) - cmnd->result = 0; - return 0; - } -} -/* Note: The following macros create attribute files in the - /sys/module/scsi_debug/parameters directory. Unfortunately this - driver is unaware of a change and cannot trigger auxiliary actions - as it can when the corresponding attribute in the - /sys/bus/pseudo/drivers/scsi_debug directory is changed. - */ -module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); -module_param_named(ato, scsi_debug_ato, int, S_IRUGO); -module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); -module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); -module_param_named(dif, scsi_debug_dif, int, S_IRUGO); -module_param_named(dix, scsi_debug_dix, int, S_IRUGO); -module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); -module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); -module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); -module_param_named(guard, scsi_debug_guard, int, S_IRUGO); -module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO); -module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO); -module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO); -module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO); -module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); -module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); -module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR); -module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); -module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO); -module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); -module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); -module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO); -module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); -module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); -module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); -module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); -module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); -module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); -module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); -module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); -module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); -module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); -module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, - S_IRUGO | S_IWUSR); -module_param_named(write_same_length, scsi_debug_write_same_length, int, - S_IRUGO | S_IWUSR); - -MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); -MODULE_DESCRIPTION("SCSI debug adapter driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(SCSI_DEBUG_VERSION); - -MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); -MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); -MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); -MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); -MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); -MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); -MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); -MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); -MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); -MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); -MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); -MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); -MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); -MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)"); -MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); -MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); -MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))"); -MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); -MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); -MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); -MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); -MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)"); -MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); -MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); -MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); -MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); -MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); -MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); -MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); -MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); -MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); -MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); -MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); -MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); - -static char sdebug_info[256]; - -static const char * scsi_debug_info(struct Scsi_Host * shp) -{ - sprintf(sdebug_info, "scsi_debug, version %s [%s], " - "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, - scsi_debug_version_date, scsi_debug_dev_size_mb, - scsi_debug_opts); - return sdebug_info; -} - -/* scsi_debug_proc_info - * Used if the driver currently has no own support for /proc/scsi - */ -static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, - int length, int inout) -{ - int len, pos, begin; - int orig_length; - - orig_length = length; - - if (inout == 1) { - char arr[16]; - int minLen = length > 15 ? 15 : length; - - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - memcpy(arr, buffer, minLen); - arr[minLen] = '\0'; - if (1 != sscanf(arr, "%d", &pos)) - return -EINVAL; - scsi_debug_opts = pos; - if (scsi_debug_every_nth != 0) - scsi_debug_cmnd_count = 0; - return length; - } - begin = 0; - pos = len = sprintf(buffer, "scsi_debug adapter driver, version " - "%s [%s]\n" - "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " - "every_nth=%d(curr:%d)\n" - "delay=%d, max_luns=%d, scsi_level=%d\n" - "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" - "number of aborts=%d, device_reset=%d, bus_resets=%d, " - "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n", - SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, - scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, - scsi_debug_cmnd_count, scsi_debug_delay, - scsi_debug_max_luns, scsi_debug_scsi_level, - scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, - sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, - num_host_resets, dix_reads, dix_writes, dif_errors); - if (pos < offset) { - len = 0; - begin = pos; - } - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); - if (len > length) - len = length; - return len; -} - -static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); -} - -static ssize_t sdebug_delay_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int delay; - char work[20]; - - if (1 == sscanf(buf, "%10s", work)) { - if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { - scsi_debug_delay = delay; - return count; - } - } - return -EINVAL; -} -DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, - sdebug_delay_store); - -static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); -} - -static ssize_t sdebug_opts_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int opts; - char work[20]; - - if (1 == sscanf(buf, "%10s", work)) { - if (0 == strnicmp(work,"0x", 2)) { - if (1 == sscanf(&work[2], "%x", &opts)) - goto opts_done; - } else { - if (1 == sscanf(work, "%d", &opts)) - goto opts_done; - } - } - return -EINVAL; -opts_done: - scsi_debug_opts = opts; - scsi_debug_cmnd_count = 0; - return count; -} -DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, - sdebug_opts_store); - -static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); -} -static ssize_t sdebug_ptype_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_ptype = n; - return count; - } - return -EINVAL; -} -DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); - -static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); -} -static ssize_t sdebug_dsense_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_dsense = n; - return count; - } - return -EINVAL; -} -DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, - sdebug_dsense_store); - -static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); -} -static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_fake_rw = n; - return count; - } - return -EINVAL; -} -DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, - sdebug_fake_rw_store); - -static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); -} -static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_no_lun_0 = n; - return count; - } - return -EINVAL; -} -DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, - sdebug_no_lun_0_store); - -static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); -} -static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_num_tgts = n; - sdebug_max_tgts_luns(); - return count; - } - return -EINVAL; -} -DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, - sdebug_num_tgts_store); - -static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); -} -DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); - -static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); -} -DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); - -static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); -} -static ssize_t sdebug_every_nth_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int nth; - - if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { - scsi_debug_every_nth = nth; - scsi_debug_cmnd_count = 0; - return count; - } - return -EINVAL; -} -DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, - sdebug_every_nth_store); - -static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); -} -static ssize_t sdebug_max_luns_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_max_luns = n; - sdebug_max_tgts_luns(); - return count; - } - return -EINVAL; -} -DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, - sdebug_max_luns_store); - -static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue); -} -static ssize_t sdebug_max_queue_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && - (n <= SCSI_DEBUG_CANQUEUE)) { - scsi_debug_max_queue = n; - return count; - } - return -EINVAL; -} -DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show, - sdebug_max_queue_store); - -static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld); -} -DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL); - -static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); -} -DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); - -static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); -} -static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_virtual_gb = n; - - sdebug_capacity = get_sdebug_capacity(); - - return count; - } - return -EINVAL; -} -DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, - sdebug_virtual_gb_store); - -static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); -} - -static ssize_t sdebug_add_host_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int delta_hosts; - - if (sscanf(buf, "%d", &delta_hosts) != 1) - return -EINVAL; - if (delta_hosts > 0) { - do { - sdebug_add_adapter(); - } while (--delta_hosts); - } else if (delta_hosts < 0) { - do { - sdebug_remove_adapter(); - } while (++delta_hosts); - } - return count; -} -DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, - sdebug_add_host_store); - -static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, - char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); -} -static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - int n; - - if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { - scsi_debug_vpd_use_hostno = n; - return count; - } - return -EINVAL; -} -DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, - sdebug_vpd_use_hostno_store); - -static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) -{ - return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); -} -DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); - -static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix); -} -DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL); - -static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif); -} -DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL); - -static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard); -} -DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL); - -static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf) -{ - return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato); -} -DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL); - -static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf) -{ - ssize_t count; - - if (!scsi_debug_lbp()) - return scnprintf(buf, PAGE_SIZE, "0-%u\n", - sdebug_store_sectors); - - count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size); - - buf[count++] = '\n'; - buf[count++] = 0; - - return count; -} -DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL); - - -/* Note: The following function creates attribute files in the - /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these - files (over those found in the /sys/module/scsi_debug/parameters - directory) is that auxiliary actions can be triggered when an attribute - is changed. For example see: sdebug_add_host_store() above. - */ -static int do_create_driverfs_files(void) -{ - int ret; - - ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato); - ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map); - return ret; -} - -static void do_remove_driverfs_files(void) -{ - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); - driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); -} - -struct device *pseudo_primary; - -static int __init scsi_debug_init(void) -{ - unsigned long sz; - int host_to_add; - int k; - int ret; - - switch (scsi_debug_sector_size) { - case 512: - case 1024: - case 2048: - case 4096: - break; - default: - printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n", - scsi_debug_sector_size); - return -EINVAL; - } - - switch (scsi_debug_dif) { - - case SD_DIF_TYPE0_PROTECTION: - case SD_DIF_TYPE1_PROTECTION: - case SD_DIF_TYPE2_PROTECTION: - case SD_DIF_TYPE3_PROTECTION: - break; - - default: - printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n"); - return -EINVAL; - } - - if (scsi_debug_guard > 1) { - printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n"); - return -EINVAL; - } - - if (scsi_debug_ato > 1) { - printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n"); - return -EINVAL; - } - - if (scsi_debug_physblk_exp > 15) { - printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n", - scsi_debug_physblk_exp); - return -EINVAL; - } - - if (scsi_debug_lowest_aligned > 0x3fff) { - printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n", - scsi_debug_lowest_aligned); - return -EINVAL; - } - - if (scsi_debug_dev_size_mb < 1) - scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ - sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; - sdebug_store_sectors = sz / scsi_debug_sector_size; - sdebug_capacity = get_sdebug_capacity(); - - /* play around with geometry, don't waste too much on track 0 */ - sdebug_heads = 8; - sdebug_sectors_per = 32; - if (scsi_debug_dev_size_mb >= 16) - sdebug_heads = 32; - else if (scsi_debug_dev_size_mb >= 256) - sdebug_heads = 64; - sdebug_cylinders_per = (unsigned long)sdebug_capacity / - (sdebug_sectors_per * sdebug_heads); - if (sdebug_cylinders_per >= 1024) { - /* other LLDs do this; implies >= 1GB ram disk ... */ - sdebug_heads = 255; - sdebug_sectors_per = 63; - sdebug_cylinders_per = (unsigned long)sdebug_capacity / - (sdebug_sectors_per * sdebug_heads); - } - - fake_storep = vmalloc(sz); - if (NULL == fake_storep) { - printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); - return -ENOMEM; - } - memset(fake_storep, 0, sz); - if (scsi_debug_num_parts > 0) - sdebug_build_parts(fake_storep, sz); - - if (scsi_debug_dif) { - int dif_size; - - dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); - dif_storep = vmalloc(dif_size); - - printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n", - dif_size, dif_storep); - - if (dif_storep == NULL) { - printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n"); - ret = -ENOMEM; - goto free_vm; - } - - memset(dif_storep, 0xff, dif_size); - } - - /* Logical Block Provisioning */ - if (scsi_debug_lbp()) { - unsigned int map_bytes; - - scsi_debug_unmap_max_blocks = - clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); - - scsi_debug_unmap_max_desc = - clamp(scsi_debug_unmap_max_desc, 0U, 256U); - - scsi_debug_unmap_granularity = - clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); - - if (scsi_debug_unmap_alignment && - scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { - printk(KERN_ERR - "%s: ERR: unmap_granularity < unmap_alignment\n", - __func__); - return -EINVAL; - } - - map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity); - map_bytes = map_size >> 3; - map_storep = vmalloc(map_bytes); - - printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n", - map_size); - - if (map_storep == NULL) { - printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n"); - ret = -ENOMEM; - goto free_vm; - } - - memset(map_storep, 0x0, map_bytes); - - /* Map first 1KB for partition table */ - if (scsi_debug_num_parts) - map_region(0, 2); - } - - pseudo_primary = root_device_register("pseudo_0"); - if (IS_ERR(pseudo_primary)) { - printk(KERN_WARNING "scsi_debug: root_device_register() error\n"); - ret = PTR_ERR(pseudo_primary); - goto free_vm; - } - ret = bus_register(&pseudo_lld_bus); - if (ret < 0) { - printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", - ret); - goto dev_unreg; - } - ret = driver_register(&sdebug_driverfs_driver); - if (ret < 0) { - printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", - ret); - goto bus_unreg; - } - ret = do_create_driverfs_files(); - if (ret < 0) { - printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", - ret); - goto del_files; - } - - init_all_queued(); - - host_to_add = scsi_debug_add_host; - scsi_debug_add_host = 0; - - for (k = 0; k < host_to_add; k++) { - if (sdebug_add_adapter()) { - printk(KERN_ERR "scsi_debug_init: " - "sdebug_add_adapter failed k=%d\n", k); - break; - } - } - - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { - printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", - scsi_debug_add_host); - } - return 0; - -del_files: - do_remove_driverfs_files(); - driver_unregister(&sdebug_driverfs_driver); -bus_unreg: - bus_unregister(&pseudo_lld_bus); -dev_unreg: - root_device_unregister(pseudo_primary); -free_vm: - if (map_storep) - vfree(map_storep); - if (dif_storep) - vfree(dif_storep); - vfree(fake_storep); - - return ret; -} - -static void __exit scsi_debug_exit(void) -{ - int k = scsi_debug_add_host; - - stop_all_queued(); - for (; k; k--) - sdebug_remove_adapter(); - do_remove_driverfs_files(); - driver_unregister(&sdebug_driverfs_driver); - bus_unregister(&pseudo_lld_bus); - root_device_unregister(pseudo_primary); - - if (dif_storep) - vfree(dif_storep); - - vfree(fake_storep); -} - -device_initcall(scsi_debug_init); -module_exit(scsi_debug_exit); - -static void sdebug_release_adapter(struct device * dev) -{ - struct sdebug_host_info *sdbg_host; - - sdbg_host = to_sdebug_host(dev); - kfree(sdbg_host); -} - -static int sdebug_add_adapter(void) -{ - int k, devs_per_host; - int error = 0; - struct sdebug_host_info *sdbg_host; - struct sdebug_dev_info *sdbg_devinfo, *tmp; - - sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); - if (NULL == sdbg_host) { - printk(KERN_ERR "%s: out of memory at line %d\n", - __func__, __LINE__); - return -ENOMEM; - } - - INIT_LIST_HEAD(&sdbg_host->dev_info_list); - - devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; - for (k = 0; k < devs_per_host; k++) { - sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); - if (!sdbg_devinfo) { - printk(KERN_ERR "%s: out of memory at line %d\n", - __func__, __LINE__); - error = -ENOMEM; - goto clean; - } - } - - spin_lock(&sdebug_host_list_lock); - list_add_tail(&sdbg_host->host_list, &sdebug_host_list); - spin_unlock(&sdebug_host_list_lock); - - sdbg_host->dev.bus = &pseudo_lld_bus; - sdbg_host->dev.parent = pseudo_primary; - sdbg_host->dev.release = &sdebug_release_adapter; - dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); - - error = device_register(&sdbg_host->dev); - - if (error) - goto clean; - - ++scsi_debug_add_host; - return error; - -clean: - list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, - dev_list) { - list_del(&sdbg_devinfo->dev_list); - kfree(sdbg_devinfo); - } - - kfree(sdbg_host); - return error; -} - -static void sdebug_remove_adapter(void) -{ - struct sdebug_host_info * sdbg_host = NULL; - - spin_lock(&sdebug_host_list_lock); - if (!list_empty(&sdebug_host_list)) { - sdbg_host = list_entry(sdebug_host_list.prev, - struct sdebug_host_info, host_list); - list_del(&sdbg_host->host_list); - } - spin_unlock(&sdebug_host_list_lock); - - if (!sdbg_host) - return; - - device_unregister(&sdbg_host->dev); - --scsi_debug_add_host; -} - -static -int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done) -{ - unsigned char *cmd = (unsigned char *) SCpnt->cmnd; - int len, k; - unsigned int num; - unsigned long long lba; - u32 ei_lba; - int errsts = 0; - int target = SCpnt->device->id; - struct sdebug_dev_info *devip = NULL; - int inj_recovered = 0; - int inj_transport = 0; - int inj_dif = 0; - int inj_dix = 0; - int delay_override = 0; - int unmap = 0; - - scsi_set_resid(SCpnt, 0); - if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { - printk(KERN_INFO "scsi_debug: cmd "); - for (k = 0, len = SCpnt->cmd_len; k < len; ++k) - printk("%02x ", (int)cmd[k]); - printk("\n"); - } - - if (target == SCpnt->device->host->hostt->this_id) { - printk(KERN_INFO "scsi_debug: initiator's id used as " - "target!\n"); - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - } - - if ((SCpnt->device->lun >= scsi_debug_max_luns) && - (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - devip = devInfoReg(SCpnt->device); - if (NULL == devip) - return schedule_resp(SCpnt, NULL, done, - DID_NO_CONNECT << 16, 0); - - if ((scsi_debug_every_nth != 0) && - (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { - scsi_debug_cmnd_count = 0; - if (scsi_debug_every_nth < -1) - scsi_debug_every_nth = -1; - if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) - return 0; /* ignore command causing timeout */ - else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts && - scsi_medium_access_command(SCpnt)) - return 0; /* time out reads and writes */ - else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) - inj_recovered = 1; /* to reads and writes below */ - else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) - inj_transport = 1; /* to reads and writes below */ - else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts) - inj_dif = 1; /* to reads and writes below */ - else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts) - inj_dix = 1; /* to reads and writes below */ - } - - if (devip->wlun) { - switch (*cmd) { - case INQUIRY: - case REQUEST_SENSE: - case TEST_UNIT_READY: - case REPORT_LUNS: - break; /* only allowable wlun commands */ - default: - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Opcode: 0x%x " - "not supported for wlun\n", *cmd); - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_OPCODE, 0); - errsts = check_condition_result; - return schedule_resp(SCpnt, devip, done, errsts, - 0); - } - } - - switch (*cmd) { - case INQUIRY: /* mandatory, ignore unit attention */ - delay_override = 1; - errsts = resp_inquiry(SCpnt, target, devip); - break; - case REQUEST_SENSE: /* mandatory, ignore unit attention */ - delay_override = 1; - errsts = resp_requests(SCpnt, devip); - break; - case REZERO_UNIT: /* actually this is REWIND for SSC */ - case START_STOP: - errsts = resp_start_stop(SCpnt, devip); - break; - case ALLOW_MEDIUM_REMOVAL: - errsts = check_readiness(SCpnt, 1, devip); - if (errsts) - break; - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Medium removal %s\n", - cmd[4] ? "inhibited" : "enabled"); - break; - case SEND_DIAGNOSTIC: /* mandatory */ - errsts = check_readiness(SCpnt, 1, devip); - break; - case TEST_UNIT_READY: /* mandatory */ - delay_override = 1; - errsts = check_readiness(SCpnt, 0, devip); - break; - case RESERVE: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RESERVE_10: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RELEASE: - errsts = check_readiness(SCpnt, 1, devip); - break; - case RELEASE_10: - errsts = check_readiness(SCpnt, 1, devip); - break; - case READ_CAPACITY: - errsts = resp_readcap(SCpnt, devip); - break; - case SERVICE_ACTION_IN: - if (cmd[1] == SAI_READ_CAPACITY_16) - errsts = resp_readcap16(SCpnt, devip); - else if (cmd[1] == SAI_GET_LBA_STATUS) { - - if (scsi_debug_lbp() == 0) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_COMMAND_OPCODE, 0); - errsts = check_condition_result; - } else - errsts = resp_get_lba_status(SCpnt, devip); - } else { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_OPCODE, 0); - errsts = check_condition_result; - } - break; - case MAINTENANCE_IN: - if (MI_REPORT_TARGET_PGS != cmd[1]) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_OPCODE, 0); - errsts = check_condition_result; - break; - } - errsts = resp_report_tgtpgs(SCpnt, devip); - break; - case READ_16: - case READ_12: - case READ_10: - /* READ{10,12,16} and DIF Type 2 are natural enemies */ - if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && - cmd[1] & 0xe0) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_COMMAND_OPCODE, 0); - errsts = check_condition_result; - break; - } - - if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || - scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && - (cmd[1] & 0xe0) == 0) - printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); - - /* fall through */ - case READ_6: -read: - errsts = check_readiness(SCpnt, 0, devip); - if (errsts) - break; - if (scsi_debug_fake_rw) - break; - get_data_transfer_info(cmd, &lba, &num, &ei_lba); - errsts = resp_read(SCpnt, lba, num, devip, ei_lba); - if (inj_recovered && (0 == errsts)) { - mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHOLD_EXCEEDED, 0); - errsts = check_condition_result; - } else if (inj_transport && (0 == errsts)) { - mk_sense_buffer(devip, ABORTED_COMMAND, - TRANSPORT_PROBLEM, ACK_NAK_TO); - errsts = check_condition_result; - } else if (inj_dif && (0 == errsts)) { - mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); - errsts = illegal_condition_result; - } else if (inj_dix && (0 == errsts)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); - errsts = illegal_condition_result; - } - break; - case REPORT_LUNS: /* mandatory, ignore unit attention */ - delay_override = 1; - errsts = resp_report_luns(SCpnt, devip); - break; - case VERIFY: /* 10 byte SBC-2 command */ - errsts = check_readiness(SCpnt, 0, devip); - break; - case WRITE_16: - case WRITE_12: - case WRITE_10: - /* WRITE{10,12,16} and DIF Type 2 are natural enemies */ - if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && - cmd[1] & 0xe0) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_COMMAND_OPCODE, 0); - errsts = check_condition_result; - break; - } - - if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || - scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && - (cmd[1] & 0xe0) == 0) - printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); - - /* fall through */ - case WRITE_6: -write: - errsts = check_readiness(SCpnt, 0, devip); - if (errsts) - break; - if (scsi_debug_fake_rw) - break; - get_data_transfer_info(cmd, &lba, &num, &ei_lba); - errsts = resp_write(SCpnt, lba, num, devip, ei_lba); - if (inj_recovered && (0 == errsts)) { - mk_sense_buffer(devip, RECOVERED_ERROR, - THRESHOLD_EXCEEDED, 0); - errsts = check_condition_result; - } else if (inj_dif && (0 == errsts)) { - mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); - errsts = illegal_condition_result; - } else if (inj_dix && (0 == errsts)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); - errsts = illegal_condition_result; - } - break; - case WRITE_SAME_16: - case WRITE_SAME: - if (cmd[1] & 0x8) { - if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) || - (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - errsts = check_condition_result; - } else - unmap = 1; - } - if (errsts) - break; - errsts = check_readiness(SCpnt, 0, devip); - if (errsts) - break; - get_data_transfer_info(cmd, &lba, &num, &ei_lba); - errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap); - break; - case UNMAP: - errsts = check_readiness(SCpnt, 0, devip); - if (errsts) - break; - - if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_COMMAND_OPCODE, 0); - errsts = check_condition_result; - } else - errsts = resp_unmap(SCpnt, devip); - break; - case MODE_SENSE: - case MODE_SENSE_10: - errsts = resp_mode_sense(SCpnt, target, devip); - break; - case MODE_SELECT: - errsts = resp_mode_select(SCpnt, 1, devip); - break; - case MODE_SELECT_10: - errsts = resp_mode_select(SCpnt, 0, devip); - break; - case LOG_SENSE: - errsts = resp_log_sense(SCpnt, devip); - break; - case SYNCHRONIZE_CACHE: - delay_override = 1; - errsts = check_readiness(SCpnt, 0, devip); - break; - case WRITE_BUFFER: - errsts = check_readiness(SCpnt, 1, devip); - break; - case XDWRITEREAD_10: - if (!scsi_bidi_cmnd(SCpnt)) { - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - errsts = check_condition_result; - break; - } - - errsts = check_readiness(SCpnt, 0, devip); - if (errsts) - break; - if (scsi_debug_fake_rw) - break; - get_data_transfer_info(cmd, &lba, &num, &ei_lba); - errsts = resp_read(SCpnt, lba, num, devip, ei_lba); - if (errsts) - break; - errsts = resp_write(SCpnt, lba, num, devip, ei_lba); - if (errsts) - break; - errsts = resp_xdwriteread(SCpnt, lba, num, devip); - break; - case VARIABLE_LENGTH_CMD: - if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) { - - if ((cmd[10] & 0xe0) == 0) - printk(KERN_ERR - "Unprotected RD/WR to DIF device\n"); - - if (cmd[9] == READ_32) { - BUG_ON(SCpnt->cmd_len < 32); - goto read; - } - - if (cmd[9] == WRITE_32) { - BUG_ON(SCpnt->cmd_len < 32); - goto write; - } - } - - mk_sense_buffer(devip, ILLEGAL_REQUEST, - INVALID_FIELD_IN_CDB, 0); - errsts = check_condition_result; - break; - - default: - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " - "supported\n", *cmd); - errsts = check_readiness(SCpnt, 1, devip); - if (errsts) - break; /* Unit attention takes precedence */ - mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); - errsts = check_condition_result; - break; - } - return schedule_resp(SCpnt, devip, done, errsts, - (delay_override ? 0 : scsi_debug_delay)); -} - -static DEF_SCSI_QCMD(scsi_debug_queuecommand) - -static struct scsi_host_template sdebug_driver_template = { - .proc_info = scsi_debug_proc_info, - .proc_name = sdebug_proc_name, - .name = "SCSI DEBUG", - .info = scsi_debug_info, - .slave_alloc = scsi_debug_slave_alloc, - .slave_configure = scsi_debug_slave_configure, - .slave_destroy = scsi_debug_slave_destroy, - .ioctl = scsi_debug_ioctl, - .queuecommand = scsi_debug_queuecommand, - .eh_abort_handler = scsi_debug_abort, - .eh_bus_reset_handler = scsi_debug_bus_reset, - .eh_device_reset_handler = scsi_debug_device_reset, - .eh_host_reset_handler = scsi_debug_host_reset, - .bios_param = scsi_debug_biosparam, - .can_queue = SCSI_DEBUG_CANQUEUE, - .this_id = 7, - .sg_tablesize = 256, - .cmd_per_lun = 16, - .max_sectors = 0xffff, - .use_clustering = DISABLE_CLUSTERING, - .module = THIS_MODULE, -}; - -static int sdebug_driver_probe(struct device * dev) -{ - int error = 0; - struct sdebug_host_info *sdbg_host; - struct Scsi_Host *hpnt; - int host_prot; - - sdbg_host = to_sdebug_host(dev); - - sdebug_driver_template.can_queue = scsi_debug_max_queue; - hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); - if (NULL == hpnt) { - printk(KERN_ERR "%s: scsi_register failed\n", __func__); - error = -ENODEV; - return error; - } - - sdbg_host->shost = hpnt; - *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; - if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) - hpnt->max_id = scsi_debug_num_tgts + 1; - else - hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ - - host_prot = 0; - - switch (scsi_debug_dif) { - - case SD_DIF_TYPE1_PROTECTION: - host_prot = SHOST_DIF_TYPE1_PROTECTION; - if (scsi_debug_dix) - host_prot |= SHOST_DIX_TYPE1_PROTECTION; - break; - - case SD_DIF_TYPE2_PROTECTION: - host_prot = SHOST_DIF_TYPE2_PROTECTION; - if (scsi_debug_dix) - host_prot |= SHOST_DIX_TYPE2_PROTECTION; - break; - - case SD_DIF_TYPE3_PROTECTION: - host_prot = SHOST_DIF_TYPE3_PROTECTION; - if (scsi_debug_dix) - host_prot |= SHOST_DIX_TYPE3_PROTECTION; - break; - - default: - if (scsi_debug_dix) - host_prot |= SHOST_DIX_TYPE0_PROTECTION; - break; - } - - scsi_host_set_prot(hpnt, host_prot); - - printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n", - (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", - (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", - (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", - (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", - (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", - (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", - (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); - - if (scsi_debug_guard == 1) - scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); - else - scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); - - error = scsi_add_host(hpnt, &sdbg_host->dev); - if (error) { - printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); - error = -ENODEV; - scsi_host_put(hpnt); - } else - scsi_scan_host(hpnt); - - - return error; -} - -static int sdebug_driver_remove(struct device * dev) -{ - struct sdebug_host_info *sdbg_host; - struct sdebug_dev_info *sdbg_devinfo, *tmp; - - sdbg_host = to_sdebug_host(dev); - - if (!sdbg_host) { - printk(KERN_ERR "%s: Unable to locate host info\n", - __func__); - return -ENODEV; - } - - scsi_remove_host(sdbg_host->shost); - - list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, - dev_list) { - list_del(&sdbg_devinfo->dev_list); - kfree(sdbg_devinfo); - } - - scsi_host_put(sdbg_host->shost); - return 0; -} - -static int pseudo_lld_bus_match(struct device *dev, - struct device_driver *dev_driver) -{ - return 1; -} - -static struct bus_type pseudo_lld_bus = { - .name = "pseudo", - .match = pseudo_lld_bus_match, - .probe = sdebug_driver_probe, - .remove = sdebug_driver_remove, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_devinfo.c b/ANDROID_3.4.5/drivers/scsi/scsi_devinfo.c deleted file mode 100644 index cf8dfab9..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_devinfo.c +++ /dev/null @@ -1,896 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "scsi_priv.h" - - -/* - * scsi_dev_info_list: structure to hold black/white listed devices. - */ -struct scsi_dev_info_list { - struct list_head dev_info_list; - char vendor[8]; - char model[16]; - unsigned flags; - unsigned compatible; /* for use with scsi_static_device_list entries */ -}; - -struct scsi_dev_info_list_table { - struct list_head node; /* our node for being on the master list */ - struct list_head scsi_dev_info_list; /* head of dev info list */ - const char *name; /* name of list for /proc (NULL for global) */ - int key; /* unique numeric identifier */ -}; - - -static const char spaces[] = " "; /* 16 of them */ -static unsigned scsi_default_dev_flags; -static LIST_HEAD(scsi_dev_info_list); -static char scsi_dev_flags[256]; - -/* - * scsi_static_device_list: deprecated list of devices that require - * settings that differ from the default, includes black-listed (broken) - * devices. The entries here are added to the tail of scsi_dev_info_list - * via scsi_dev_info_list_init. - * - * Do not add to this list, use the command line or proc interface to add - * to the scsi_dev_info_list. This table will eventually go away. - */ -static struct { - char *vendor; - char *model; - char *revision; /* revision known to be bad, unused */ - unsigned flags; -} scsi_static_device_list[] __initdata = { - /* - * The following devices are known not to tolerate a lun != 0 scan - * for one reason or another. Some will respond to all luns, - * others will lock up. - */ - {"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN}, /* locks up */ - {"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN}, /* locks up */ - {"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN}, /* locks up */ - {"DENON", "DRD-25X", "V", BLIST_NOLUN}, /* locks up */ - {"HITACHI", "DK312C", "CM81", BLIST_NOLUN}, /* responds to all lun */ - {"HITACHI", "DK314C", "CR21", BLIST_NOLUN}, /* responds to all lun */ - {"IBM", "2104-DU3", NULL, BLIST_NOLUN}, /* locks up */ - {"IBM", "2104-TU3", NULL, BLIST_NOLUN}, /* locks up */ - {"IMS", "CDD521/10", "2.06", BLIST_NOLUN}, /* locks up */ - {"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN}, /* locks up */ - {"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN}, /* locks up */ - {"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN}, /* locks up */ - {"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN}, /* locks up */ - {"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN}, /* locks up */ - {"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN}, /* responds to all lun */ - {"MICROTEK", "ScanMakerIII", "2.30", BLIST_NOLUN}, /* responds to all lun */ - {"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */ - {"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN}, /* responds to all lun */ - {"RODIME", "RO3000S", "2.33", BLIST_NOLUN}, /* locks up */ - {"SUN", "SENA", NULL, BLIST_NOLUN}, /* responds to all luns */ - /* - * The following causes a failed REQUEST SENSE on lun 1 for - * aha152x controller, which causes SCSI code to reset bus. - */ - {"SANYO", "CRD-250S", "1.20", BLIST_NOLUN}, - /* - * The following causes a failed REQUEST SENSE on lun 1 for - * aha152x controller, which causes SCSI code to reset bus. - */ - {"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN}, - {"SEAGATE", "ST296", "921", BLIST_NOLUN}, /* responds to all lun */ - {"SEAGATE", "ST1581", "6538", BLIST_NOLUN}, /* responds to all lun */ - {"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN}, - {"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN}, - {"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN}, - {"SONY", "CD-ROM CDU-8012", NULL, BLIST_NOLUN}, - {"SONY", "SDT-5000", "3.17", BLIST_SELECT_NO_ATN}, - {"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN}, /* locks up */ - {"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN}, /* locks up */ - /* - * The following causes a failed REQUEST SENSE on lun 1 for - * seagate controller, which causes SCSI code to reset bus. - */ - {"TEAC", "CD-ROM", "1.06", BLIST_NOLUN}, - {"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN}, /* responds to all lun */ - /* - * The following causes a failed REQUEST SENSE on lun 1 for - * seagate controller, which causes SCSI code to reset bus. - */ - {"HP", "C1750A", "3226", BLIST_NOLUN}, /* scanjet iic */ - {"HP", "C1790A", "", BLIST_NOLUN}, /* scanjet iip */ - {"HP", "C2500A", "", BLIST_NOLUN}, /* scanjet iicx */ - {"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN}, /* locks up */ - {"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN}, /* responds to all lun */ - {"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN}, /* locks up */ - {"NEC", "D3856", "0009", BLIST_NOLUN}, - {"QUANTUM", "LPS525S", "3110", BLIST_NOLUN}, /* locks up */ - {"QUANTUM", "PD1225S", "3110", BLIST_NOLUN}, /* locks up */ - {"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN}, /* locks up */ - {"RELISYS", "Scorpio", NULL, BLIST_NOLUN}, /* responds to all lun */ - {"SANKYO", "CP525", "6.64", BLIST_NOLUN}, /* causes failed REQ SENSE, extra reset */ - {"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN}, - {"transtec", "T5008", "0001", BLIST_NOREPORTLUN }, - {"YAMAHA", "CDR100", "1.00", BLIST_NOLUN}, /* locks up */ - {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */ - {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */ - {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* locks up */ - {"", "Scanner", "1.80", BLIST_NOLUN}, /* responds to all lun */ - - /* - * Other types of devices that have special flags. - * Note that all USB devices should have the BLIST_INQUIRY_36 flag. - */ - {"3PARdata", "VV", NULL, BLIST_REPORTLUN2}, - {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, - {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, - {"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN}, - {"BELKIN", "USB 2 HS-CF", "1.95", BLIST_FORCELUN | BLIST_INQUIRY_36}, - {"BROWNIE", "1200U3P", NULL, BLIST_NOREPORTLUN}, - {"BROWNIE", "1600U3P", NULL, BLIST_NOREPORTLUN}, - {"CANON", "IPUBJD", NULL, BLIST_SPARSELUN}, - {"CBOX3", "USB Storage-SMC", "300A", BLIST_FORCELUN | BLIST_INQUIRY_36}, - {"CMD", "CRA-7280", NULL, BLIST_SPARSELUN}, /* CMD RAID Controller */ - {"CNSI", "G7324", NULL, BLIST_SPARSELUN}, /* Chaparral G7324 RAID */ - {"CNSi", "G8324", NULL, BLIST_SPARSELUN}, /* Chaparral G8324 RAID */ - {"COMPAQ", "ARRAY CONTROLLER", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | - BLIST_MAX_512 | BLIST_REPORTLUN2}, /* Compaq RA4x00 */ - {"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN | BLIST_MAX_512}, /* Compaq RA4x00 */ - {"COMPAQ", "CR3500", NULL, BLIST_FORCELUN}, - {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, - {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, - {"COMPAQ", "HSV110", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, - {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN}, - {"DEC", "HSG80", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, - {"DELL", "PV660F", NULL, BLIST_SPARSELUN}, - {"DELL", "PV660F PSEUDO", NULL, BLIST_SPARSELUN}, - {"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN}, /* Dell PV 530F */ - {"DELL", "PV530F", NULL, BLIST_SPARSELUN}, - {"DELL", "PERCRAID", NULL, BLIST_FORCELUN}, - {"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */ - {"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */ - {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN}, - {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, - {"easyRAID", "16P", NULL, BLIST_NOREPORTLUN}, - {"easyRAID", "X6P", NULL, BLIST_NOREPORTLUN}, - {"easyRAID", "F8", NULL, BLIST_NOREPORTLUN}, - {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN | BLIST_INQUIRY_36}, - {"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN | BLIST_INQUIRY_36}, - {"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN | BLIST_INQUIRY_36}, - {"HITACHI", "DF400", "*", BLIST_REPORTLUN2}, - {"HITACHI", "DF500", "*", BLIST_REPORTLUN2}, - {"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_REPORTLUN2}, - {"HITACHI", "OPEN-", "*", BLIST_REPORTLUN2}, - {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */ - {"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */ - {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, - {"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, - {"HP", "C1557A", NULL, BLIST_FORCELUN}, - {"HP", "C3323-300", "4269", BLIST_NOTQ}, - {"HP", "C5713A", NULL, BLIST_NOREPORTLUN}, - {"HP", "DF400", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "DF500", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "DF600", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN}, - {"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"IBM", "2105", NULL, BLIST_RETRY_HWERROR}, - {"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN}, - {"IOMEGA", "ZIP", NULL, BLIST_NOTQ | BLIST_NOLUN}, - {"IOMEGA", "Io20S *F", NULL, BLIST_KEY}, - {"INSITE", "Floptical F*8I", NULL, BLIST_KEY}, - {"INSITE", "I325VM", NULL, BLIST_KEY}, - {"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36}, - {"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN}, - {"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36}, - {"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36}, - {"Medion", "Flash XL MMC/SD", "2.6D", BLIST_FORCELUN}, - {"MegaRAID", "LD", NULL, BLIST_FORCELUN}, - {"MICROP", "4110", NULL, BLIST_NOTQ}, - {"MYLEX", "DACARMRB", "*", BLIST_REPORTLUN2}, - {"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN}, - {"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"NEC", "iStorage", NULL, BLIST_REPORTLUN2}, - {"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, - {"Promise", "", NULL, BLIST_SPARSELUN}, - {"QUANTUM", "XP34301", "1071", BLIST_NOTQ}, - {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, - {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, - {"SEAGATE", "ST34555N", "0930", BLIST_NOTQ}, /* Chokes on tagged INQUIRY */ - {"SEAGATE", "ST3390N", "9546", BLIST_NOTQ}, - {"SGI", "RAID3", "*", BLIST_SPARSELUN}, - {"SGI", "RAID5", "*", BLIST_SPARSELUN}, - {"SGI", "TP9100", "*", BLIST_REPORTLUN2}, - {"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, - {"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, - {"SUN", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, - {"DELL", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, - {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36}, - {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, - {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ - {"ST650211", "CF", NULL, BLIST_RETRY_HWERROR}, - {"SUN", "T300", "*", BLIST_SPARSELUN}, - {"SUN", "T4", "*", BLIST_SPARSELUN}, - {"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN}, - {"Tornado-", "F4", "*", BLIST_NOREPORTLUN}, - {"TOSHIBA", "CDROM", NULL, BLIST_ISROM}, - {"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM}, - {"Traxdata", "CDR4120", NULL, BLIST_NOLUN}, /* locks up */ - {"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36}, - {"WangDAT", "Model 2600", "01.7", BLIST_SELECT_NO_ATN}, - {"WangDAT", "Model 3200", "02.2", BLIST_SELECT_NO_ATN}, - {"WangDAT", "Model 1300", "02.4", BLIST_SELECT_NO_ATN}, - {"WDC WD25", "00JB-00FUA0", NULL, BLIST_NOREPORTLUN}, - {"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, - {"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN}, - {"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN}, - { NULL, NULL, NULL, 0 }, -}; - -static struct scsi_dev_info_list_table *scsi_devinfo_lookup_by_key(int key) -{ - struct scsi_dev_info_list_table *devinfo_table; - int found = 0; - - list_for_each_entry(devinfo_table, &scsi_dev_info_list, node) - if (devinfo_table->key == key) { - found = 1; - break; - } - if (!found) - return ERR_PTR(-EINVAL); - - return devinfo_table; -} - -/* - * scsi_strcpy_devinfo: called from scsi_dev_info_list_add to copy into - * devinfo vendor and model strings. - */ -static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length, - char *from, int compatible) -{ - size_t from_length; - - from_length = strlen(from); - strncpy(to, from, min(to_length, from_length)); - if (from_length < to_length) { - if (compatible) { - /* - * NUL terminate the string if it is short. - */ - to[from_length] = '\0'; - } else { - /* - * space pad the string if it is short. - */ - strncpy(&to[from_length], spaces, - to_length - from_length); - } - } - if (from_length > to_length) - printk(KERN_WARNING "%s: %s string '%s' is too long\n", - __func__, name, from); -} - -/** - * scsi_dev_info_list_add - add one dev_info list entry. - * @compatible: if true, null terminate short strings. Otherwise space pad. - * @vendor: vendor string - * @model: model (product) string - * @strflags: integer string - * @flags: if strflags NULL, use this flag value - * - * Description: - * Create and add one dev_info entry for @vendor, @model, @strflags or - * @flag. If @compatible, add to the tail of the list, do not space - * pad, and set devinfo->compatible. The scsi_static_device_list entries - * are added with @compatible 1 and @clfags NULL. - * - * Returns: 0 OK, -error on failure. - **/ -static int scsi_dev_info_list_add(int compatible, char *vendor, char *model, - char *strflags, int flags) -{ - return scsi_dev_info_list_add_keyed(compatible, vendor, model, - strflags, flags, - SCSI_DEVINFO_GLOBAL); -} - -/** - * scsi_dev_info_list_add_keyed - add one dev_info list entry. - * @compatible: if true, null terminate short strings. Otherwise space pad. - * @vendor: vendor string - * @model: model (product) string - * @strflags: integer string - * @flags: if strflags NULL, use this flag value - * @key: specify list to use - * - * Description: - * Create and add one dev_info entry for @vendor, @model, - * @strflags or @flag in list specified by @key. If @compatible, - * add to the tail of the list, do not space pad, and set - * devinfo->compatible. The scsi_static_device_list entries are - * added with @compatible 1 and @clfags NULL. - * - * Returns: 0 OK, -error on failure. - **/ -int scsi_dev_info_list_add_keyed(int compatible, char *vendor, char *model, - char *strflags, int flags, int key) -{ - struct scsi_dev_info_list *devinfo; - struct scsi_dev_info_list_table *devinfo_table = - scsi_devinfo_lookup_by_key(key); - - if (IS_ERR(devinfo_table)) - return PTR_ERR(devinfo_table); - - devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL); - if (!devinfo) { - printk(KERN_ERR "%s: no memory\n", __func__); - return -ENOMEM; - } - - scsi_strcpy_devinfo("vendor", devinfo->vendor, sizeof(devinfo->vendor), - vendor, compatible); - scsi_strcpy_devinfo("model", devinfo->model, sizeof(devinfo->model), - model, compatible); - - if (strflags) - devinfo->flags = simple_strtoul(strflags, NULL, 0); - else - devinfo->flags = flags; - - devinfo->compatible = compatible; - - if (compatible) - list_add_tail(&devinfo->dev_info_list, - &devinfo_table->scsi_dev_info_list); - else - list_add(&devinfo->dev_info_list, - &devinfo_table->scsi_dev_info_list); - - return 0; -} -EXPORT_SYMBOL(scsi_dev_info_list_add_keyed); - -/** - * scsi_dev_info_list_del_keyed - remove one dev_info list entry. - * @vendor: vendor string - * @model: model (product) string - * @key: specify list to use - * - * Description: - * Remove and destroy one dev_info entry for @vendor, @model - * in list specified by @key. - * - * Returns: 0 OK, -error on failure. - **/ -int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key) -{ - struct scsi_dev_info_list *devinfo, *found = NULL; - struct scsi_dev_info_list_table *devinfo_table = - scsi_devinfo_lookup_by_key(key); - - if (IS_ERR(devinfo_table)) - return PTR_ERR(devinfo_table); - - list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, - dev_info_list) { - if (devinfo->compatible) { - /* - * Behave like the older version of get_device_flags. - */ - size_t max; - /* - * XXX why skip leading spaces? If an odd INQUIRY - * value, that should have been part of the - * scsi_static_device_list[] entry, such as " FOO" - * rather than "FOO". Since this code is already - * here, and we don't know what device it is - * trying to work with, leave it as-is. - */ - max = 8; /* max length of vendor */ - while ((max > 0) && *vendor == ' ') { - max--; - vendor++; - } - /* - * XXX removing the following strlen() would be - * good, using it means that for a an entry not in - * the list, we scan every byte of every vendor - * listed in scsi_static_device_list[], and never match - * a single one (and still have to compare at - * least the first byte of each vendor). - */ - if (memcmp(devinfo->vendor, vendor, - min(max, strlen(devinfo->vendor)))) - continue; - /* - * Skip spaces again. - */ - max = 16; /* max length of model */ - while ((max > 0) && *model == ' ') { - max--; - model++; - } - if (memcmp(devinfo->model, model, - min(max, strlen(devinfo->model)))) - continue; - found = devinfo; - } else { - if (!memcmp(devinfo->vendor, vendor, - sizeof(devinfo->vendor)) && - !memcmp(devinfo->model, model, - sizeof(devinfo->model))) - found = devinfo; - } - if (found) - break; - } - - if (found) { - list_del(&found->dev_info_list); - kfree(found); - return 0; - } - - return -ENOENT; -} -EXPORT_SYMBOL(scsi_dev_info_list_del_keyed); - -/** - * scsi_dev_info_list_add_str - parse dev_list and add to the scsi_dev_info_list. - * @dev_list: string of device flags to add - * - * Description: - * Parse dev_list, and add entries to the scsi_dev_info_list. - * dev_list is of the form "vendor:product:flag,vendor:product:flag". - * dev_list is modified via strsep. Can be called for command line - * addition, for proc or mabye a sysfs interface. - * - * Returns: 0 if OK, -error on failure. - **/ -static int scsi_dev_info_list_add_str(char *dev_list) -{ - char *vendor, *model, *strflags, *next; - char *next_check; - int res = 0; - - next = dev_list; - if (next && next[0] == '"') { - /* - * Ignore both the leading and trailing quote. - */ - next++; - next_check = ",\""; - } else { - next_check = ","; - } - - /* - * For the leading and trailing '"' case, the for loop comes - * through the last time with vendor[0] == '\0'. - */ - for (vendor = strsep(&next, ":"); vendor && (vendor[0] != '\0') - && (res == 0); vendor = strsep(&next, ":")) { - strflags = NULL; - model = strsep(&next, ":"); - if (model) - strflags = strsep(&next, next_check); - if (!model || !strflags) { - printk(KERN_ERR "%s: bad dev info string '%s' '%s'" - " '%s'\n", __func__, vendor, model, - strflags); - res = -EINVAL; - } else - res = scsi_dev_info_list_add(0 /* compatible */, vendor, - model, strflags, 0); - } - return res; -} - -/** - * get_device_flags - get device specific flags from the dynamic device list. - * @sdev: &scsi_device to get flags for - * @vendor: vendor name - * @model: model name - * - * Description: - * Search the global scsi_dev_info_list (specified by list zero) - * for an entry matching @vendor and @model, if found, return the - * matching flags value, else return the host or global default - * settings. Called during scan time. - **/ -int scsi_get_device_flags(struct scsi_device *sdev, - const unsigned char *vendor, - const unsigned char *model) -{ - return scsi_get_device_flags_keyed(sdev, vendor, model, - SCSI_DEVINFO_GLOBAL); -} - - -/** - * scsi_get_device_flags_keyed - get device specific flags from the dynamic device list - * @sdev: &scsi_device to get flags for - * @vendor: vendor name - * @model: model name - * @key: list to look up - * - * Description: - * Search the scsi_dev_info_list specified by @key for an entry - * matching @vendor and @model, if found, return the matching - * flags value, else return the host or global default settings. - * Called during scan time. - **/ -int scsi_get_device_flags_keyed(struct scsi_device *sdev, - const unsigned char *vendor, - const unsigned char *model, - int key) -{ - struct scsi_dev_info_list *devinfo; - struct scsi_dev_info_list_table *devinfo_table; - - devinfo_table = scsi_devinfo_lookup_by_key(key); - - if (IS_ERR(devinfo_table)) - return PTR_ERR(devinfo_table); - - list_for_each_entry(devinfo, &devinfo_table->scsi_dev_info_list, - dev_info_list) { - if (devinfo->compatible) { - /* - * Behave like the older version of get_device_flags. - */ - size_t max; - /* - * XXX why skip leading spaces? If an odd INQUIRY - * value, that should have been part of the - * scsi_static_device_list[] entry, such as " FOO" - * rather than "FOO". Since this code is already - * here, and we don't know what device it is - * trying to work with, leave it as-is. - */ - max = 8; /* max length of vendor */ - while ((max > 0) && *vendor == ' ') { - max--; - vendor++; - } - /* - * XXX removing the following strlen() would be - * good, using it means that for a an entry not in - * the list, we scan every byte of every vendor - * listed in scsi_static_device_list[], and never match - * a single one (and still have to compare at - * least the first byte of each vendor). - */ - if (memcmp(devinfo->vendor, vendor, - min(max, strlen(devinfo->vendor)))) - continue; - /* - * Skip spaces again. - */ - max = 16; /* max length of model */ - while ((max > 0) && *model == ' ') { - max--; - model++; - } - if (memcmp(devinfo->model, model, - min(max, strlen(devinfo->model)))) - continue; - return devinfo->flags; - } else { - if (!memcmp(devinfo->vendor, vendor, - sizeof(devinfo->vendor)) && - !memcmp(devinfo->model, model, - sizeof(devinfo->model))) - return devinfo->flags; - } - } - /* nothing found, return nothing */ - if (key != SCSI_DEVINFO_GLOBAL) - return 0; - - /* except for the global list, where we have an exception */ - if (sdev->sdev_bflags) - return sdev->sdev_bflags; - - return scsi_default_dev_flags; -} -EXPORT_SYMBOL(scsi_get_device_flags_keyed); - -#ifdef CONFIG_SCSI_PROC_FS -struct double_list { - struct list_head *top; - struct list_head *bottom; -}; - -static int devinfo_seq_show(struct seq_file *m, void *v) -{ - struct double_list *dl = v; - struct scsi_dev_info_list_table *devinfo_table = - list_entry(dl->top, struct scsi_dev_info_list_table, node); - struct scsi_dev_info_list *devinfo = - list_entry(dl->bottom, struct scsi_dev_info_list, - dev_info_list); - - if (devinfo_table->scsi_dev_info_list.next == dl->bottom && - devinfo_table->name) - seq_printf(m, "[%s]:\n", devinfo_table->name); - - seq_printf(m, "'%.8s' '%.16s' 0x%x\n", - devinfo->vendor, devinfo->model, devinfo->flags); - return 0; -} - -static void *devinfo_seq_start(struct seq_file *m, loff_t *ppos) -{ - struct double_list *dl = kmalloc(sizeof(*dl), GFP_KERNEL); - loff_t pos = *ppos; - - if (!dl) - return NULL; - - list_for_each(dl->top, &scsi_dev_info_list) { - struct scsi_dev_info_list_table *devinfo_table = - list_entry(dl->top, struct scsi_dev_info_list_table, - node); - list_for_each(dl->bottom, &devinfo_table->scsi_dev_info_list) - if (pos-- == 0) - return dl; - } - - kfree(dl); - return NULL; -} - -static void *devinfo_seq_next(struct seq_file *m, void *v, loff_t *ppos) -{ - struct double_list *dl = v; - struct scsi_dev_info_list_table *devinfo_table = - list_entry(dl->top, struct scsi_dev_info_list_table, node); - - ++*ppos; - dl->bottom = dl->bottom->next; - while (&devinfo_table->scsi_dev_info_list == dl->bottom) { - dl->top = dl->top->next; - if (dl->top == &scsi_dev_info_list) { - kfree(dl); - return NULL; - } - devinfo_table = list_entry(dl->top, - struct scsi_dev_info_list_table, - node); - dl->bottom = devinfo_table->scsi_dev_info_list.next; - } - - return dl; -} - -static void devinfo_seq_stop(struct seq_file *m, void *v) -{ - kfree(v); -} - -static const struct seq_operations scsi_devinfo_seq_ops = { - .start = devinfo_seq_start, - .next = devinfo_seq_next, - .stop = devinfo_seq_stop, - .show = devinfo_seq_show, -}; - -static int proc_scsi_devinfo_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &scsi_devinfo_seq_ops); -} - -/* - * proc_scsi_dev_info_write - allow additions to scsi_dev_info_list via /proc. - * - * Description: Adds a black/white list entry for vendor and model with an - * integer value of flag to the scsi device info list. - * To use, echo "vendor:model:flag" > /proc/scsi/device_info - */ -static ssize_t proc_scsi_devinfo_write(struct file *file, - const char __user *buf, - size_t length, loff_t *ppos) -{ - char *buffer; - ssize_t err = length; - - if (!buf || length>PAGE_SIZE) - return -EINVAL; - if (!(buffer = (char *) __get_free_page(GFP_KERNEL))) - return -ENOMEM; - if (copy_from_user(buffer, buf, length)) { - err =-EFAULT; - goto out; - } - - if (length < PAGE_SIZE) - buffer[length] = '\0'; - else if (buffer[PAGE_SIZE-1]) { - err = -EINVAL; - goto out; - } - - scsi_dev_info_list_add_str(buffer); - -out: - free_page((unsigned long)buffer); - return err; -} - -static const struct file_operations scsi_devinfo_proc_fops = { - .owner = THIS_MODULE, - .open = proc_scsi_devinfo_open, - .read = seq_read, - .write = proc_scsi_devinfo_write, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif /* CONFIG_SCSI_PROC_FS */ - -module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); -MODULE_PARM_DESC(dev_flags, - "Given scsi_dev_flags=vendor:model:flags[,v:m:f] add black/white" - " list entries for vendor and model with an integer value of flags" - " to the scsi device info list"); - -module_param_named(default_dev_flags, scsi_default_dev_flags, int, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(default_dev_flags, - "scsi default device flag integer value"); - -/** - * scsi_exit_devinfo - remove /proc/scsi/device_info & the scsi_dev_info_list - **/ -void scsi_exit_devinfo(void) -{ -#ifdef CONFIG_SCSI_PROC_FS - remove_proc_entry("scsi/device_info", NULL); -#endif - - scsi_dev_info_remove_list(SCSI_DEVINFO_GLOBAL); -} - -/** - * scsi_dev_info_add_list - add a new devinfo list - * @key: key of the list to add - * @name: Name of the list to add (for /proc/scsi/device_info) - * - * Adds the requested list, returns zero on success, -EEXIST if the - * key is already registered to a list, or other error on failure. - */ -int scsi_dev_info_add_list(int key, const char *name) -{ - struct scsi_dev_info_list_table *devinfo_table = - scsi_devinfo_lookup_by_key(key); - - if (!IS_ERR(devinfo_table)) - /* list already exists */ - return -EEXIST; - - devinfo_table = kmalloc(sizeof(*devinfo_table), GFP_KERNEL); - - if (!devinfo_table) - return -ENOMEM; - - INIT_LIST_HEAD(&devinfo_table->node); - INIT_LIST_HEAD(&devinfo_table->scsi_dev_info_list); - devinfo_table->name = name; - devinfo_table->key = key; - list_add_tail(&devinfo_table->node, &scsi_dev_info_list); - - return 0; -} -EXPORT_SYMBOL(scsi_dev_info_add_list); - -/** - * scsi_dev_info_remove_list - destroy an added devinfo list - * @key: key of the list to destroy - * - * Iterates over the entire list first, freeing all the values, then - * frees the list itself. Returns 0 on success or -EINVAL if the key - * can't be found. - */ -int scsi_dev_info_remove_list(int key) -{ - struct list_head *lh, *lh_next; - struct scsi_dev_info_list_table *devinfo_table = - scsi_devinfo_lookup_by_key(key); - - if (IS_ERR(devinfo_table)) - /* no such list */ - return -EINVAL; - - /* remove from the master list */ - list_del(&devinfo_table->node); - - list_for_each_safe(lh, lh_next, &devinfo_table->scsi_dev_info_list) { - struct scsi_dev_info_list *devinfo; - - devinfo = list_entry(lh, struct scsi_dev_info_list, - dev_info_list); - kfree(devinfo); - } - kfree(devinfo_table); - - return 0; -} -EXPORT_SYMBOL(scsi_dev_info_remove_list); - -/** - * scsi_init_devinfo - set up the dynamic device list. - * - * Description: - * Add command line entries from scsi_dev_flags, then add - * scsi_static_device_list entries to the scsi device info list. - */ -int __init scsi_init_devinfo(void) -{ -#ifdef CONFIG_SCSI_PROC_FS - struct proc_dir_entry *p; -#endif - int error, i; - - error = scsi_dev_info_add_list(SCSI_DEVINFO_GLOBAL, NULL); - if (error) - return error; - - error = scsi_dev_info_list_add_str(scsi_dev_flags); - if (error) - goto out; - - for (i = 0; scsi_static_device_list[i].vendor; i++) { - error = scsi_dev_info_list_add(1 /* compatibile */, - scsi_static_device_list[i].vendor, - scsi_static_device_list[i].model, - NULL, - scsi_static_device_list[i].flags); - if (error) - goto out; - } - -#ifdef CONFIG_SCSI_PROC_FS - p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops); - if (!p) { - error = -ENOMEM; - goto out; - } -#endif /* CONFIG_SCSI_PROC_FS */ - - out: - if (error) - scsi_exit_devinfo(); - return error; -} diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_error.c b/ANDROID_3.4.5/drivers/scsi/scsi_error.c deleted file mode 100644 index 386f0c53..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_error.c +++ /dev/null @@ -1,2207 +0,0 @@ -/* - * scsi_error.c Copyright (C) 1997 Eric Youngdale - * - * SCSI error/timeout handling - * Initial versions: Eric Youngdale. Based upon conversations with - * Leonard Zubkoff and David Miller at Linux Expo, - * ideas originating from all over the place. - * - * Restructured scsi_unjam_host and associated functions. - * September 04, 2002 Mike Anderson (andmike@us.ibm.com) - * - * Forward port of Russell King's (rmk@arm.linux.org.uk) changes and - * minor cleanups. - * September 30, 2002 Mike Anderson (andmike@us.ibm.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi_priv.h" -#include "scsi_logging.h" -#include "scsi_transport_api.h" - -#include - -#define SENSE_TIMEOUT (10*HZ) - -/* - * These should *probably* be handled by the host itself. - * Since it is allowed to sleep, it probably should. - */ -#define BUS_RESET_SETTLE_TIME (10) -#define HOST_RESET_SETTLE_TIME (10) - -static int scsi_eh_try_stu(struct scsi_cmnd *scmd); - -/* called with shost->host_lock held */ -void scsi_eh_wakeup(struct Scsi_Host *shost) -{ - if (shost->host_busy == shost->host_failed) { - trace_scsi_eh_wakeup(shost); - wake_up_process(shost->ehandler); - SCSI_LOG_ERROR_RECOVERY(5, - printk("Waking error handler thread\n")); - } -} - -/** - * scsi_schedule_eh - schedule EH for SCSI host - * @shost: SCSI host to invoke error handling on. - * - * Schedule SCSI EH without scmd. - */ -void scsi_schedule_eh(struct Scsi_Host *shost) -{ - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - - if (scsi_host_set_state(shost, SHOST_RECOVERY) == 0 || - scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY) == 0) { - shost->host_eh_scheduled++; - scsi_eh_wakeup(shost); - } - - spin_unlock_irqrestore(shost->host_lock, flags); -} -EXPORT_SYMBOL_GPL(scsi_schedule_eh); - -/** - * scsi_eh_scmd_add - add scsi cmd to error handling. - * @scmd: scmd to run eh on. - * @eh_flag: optional SCSI_EH flag. - * - * Return value: - * 0 on failure. - */ -int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) -{ - struct Scsi_Host *shost = scmd->device->host; - unsigned long flags; - int ret = 0; - - if (!shost->ehandler) - return 0; - - spin_lock_irqsave(shost->host_lock, flags); - if (scsi_host_set_state(shost, SHOST_RECOVERY)) - if (scsi_host_set_state(shost, SHOST_CANCEL_RECOVERY)) - goto out_unlock; - - ret = 1; - scmd->eh_eflags |= eh_flag; - list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); - shost->host_failed++; - scsi_eh_wakeup(shost); - out_unlock: - spin_unlock_irqrestore(shost->host_lock, flags); - return ret; -} - -/** - * scsi_times_out - Timeout function for normal scsi commands. - * @req: request that is timing out. - * - * Notes: - * We do not need to lock this. There is the potential for a race - * only in that the normal completion handling might run, but if the - * normal completion function determines that the timer has already - * fired, then it mustn't do anything. - */ -enum blk_eh_timer_return scsi_times_out(struct request *req) -{ - struct scsi_cmnd *scmd = req->special; - enum blk_eh_timer_return rtn = BLK_EH_NOT_HANDLED; - struct Scsi_Host *host = scmd->device->host; - - trace_scsi_dispatch_cmd_timeout(scmd); - scsi_log_completion(scmd, TIMEOUT_ERROR); - - if (host->transportt->eh_timed_out) - rtn = host->transportt->eh_timed_out(scmd); - else if (host->hostt->eh_timed_out) - rtn = host->hostt->eh_timed_out(scmd); - - scmd->result |= DID_TIME_OUT << 16; - - if (unlikely(rtn == BLK_EH_NOT_HANDLED && - !scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) - rtn = BLK_EH_HANDLED; - - return rtn; -} - -/** - * scsi_block_when_processing_errors - Prevent cmds from being queued. - * @sdev: Device on which we are performing recovery. - * - * Description: - * We block until the host is out of error recovery, and then check to - * see whether the host or the device is offline. - * - * Return value: - * 0 when dev was taken offline by error recovery. 1 OK to proceed. - */ -int scsi_block_when_processing_errors(struct scsi_device *sdev) -{ - int online; - - wait_event(sdev->host->host_wait, !scsi_host_in_recovery(sdev->host)); - - online = scsi_device_online(sdev); - - SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __func__, - online)); - - return online; -} -EXPORT_SYMBOL(scsi_block_when_processing_errors); - -#ifdef CONFIG_SCSI_LOGGING -/** - * scsi_eh_prt_fail_stats - Log info on failures. - * @shost: scsi host being recovered. - * @work_q: Queue of scsi cmds to process. - */ -static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost, - struct list_head *work_q) -{ - struct scsi_cmnd *scmd; - struct scsi_device *sdev; - int total_failures = 0; - int cmd_failed = 0; - int cmd_cancel = 0; - int devices_failed = 0; - - shost_for_each_device(sdev, shost) { - list_for_each_entry(scmd, work_q, eh_entry) { - if (scmd->device == sdev) { - ++total_failures; - if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) - ++cmd_cancel; - else - ++cmd_failed; - } - } - - if (cmd_cancel || cmd_failed) { - SCSI_LOG_ERROR_RECOVERY(3, - sdev_printk(KERN_INFO, sdev, - "%s: cmds failed: %d, cancel: %d\n", - __func__, cmd_failed, - cmd_cancel)); - cmd_cancel = 0; - cmd_failed = 0; - ++devices_failed; - } - } - - SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d" - " devices require eh work\n", - total_failures, devices_failed)); -} -#endif - -/** - * scsi_check_sense - Examine scsi cmd sense - * @scmd: Cmd to have sense checked. - * - * Return value: - * SUCCESS or FAILED or NEEDS_RETRY or TARGET_ERROR - * - * Notes: - * When a deferred error is detected the current command has - * not been executed and needs retrying. - */ -static int scsi_check_sense(struct scsi_cmnd *scmd) -{ - struct scsi_device *sdev = scmd->device; - struct scsi_sense_hdr sshdr; - - if (! scsi_command_normalize_sense(scmd, &sshdr)) - return FAILED; /* no valid sense data */ - - if (scsi_sense_is_deferred(&sshdr)) - return NEEDS_RETRY; - - if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh && - sdev->scsi_dh_data->scsi_dh->check_sense) { - int rc; - - rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr); - if (rc != SCSI_RETURN_NOT_HANDLED) - return rc; - /* handler does not care. Drop down to default handling */ - } - - /* - * Previous logic looked for FILEMARK, EOM or ILI which are - * mainly associated with tapes and returned SUCCESS. - */ - if (sshdr.response_code == 0x70) { - /* fixed format */ - if (scmd->sense_buffer[2] & 0xe0) - return SUCCESS; - } else { - /* - * descriptor format: look for "stream commands sense data - * descriptor" (see SSC-3). Assume single sense data - * descriptor. Ignore ILI from SBC-2 READ LONG and WRITE LONG. - */ - if ((sshdr.additional_length > 3) && - (scmd->sense_buffer[8] == 0x4) && - (scmd->sense_buffer[11] & 0xe0)) - return SUCCESS; - } - - switch (sshdr.sense_key) { - case NO_SENSE: - return SUCCESS; - case RECOVERED_ERROR: - return /* soft_error */ SUCCESS; - - case ABORTED_COMMAND: - if (sshdr.asc == 0x10) /* DIF */ - return SUCCESS; - - return NEEDS_RETRY; - case NOT_READY: - case UNIT_ATTENTION: - /* - * if we are expecting a cc/ua because of a bus reset that we - * performed, treat this just as a retry. otherwise this is - * information that we should pass up to the upper-level driver - * so that we can deal with it there. - */ - if (scmd->device->expecting_cc_ua) { - /* - * Because some device does not queue unit - * attentions correctly, we carefully check - * additional sense code and qualifier so as - * not to squash media change unit attention. - */ - if (sshdr.asc != 0x28 || sshdr.ascq != 0x00) { - scmd->device->expecting_cc_ua = 0; - return NEEDS_RETRY; - } - } - /* - * if the device is in the process of becoming ready, we - * should retry. - */ - if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01)) - return NEEDS_RETRY; - /* - * if the device is not started, we need to wake - * the error handler to start the motor - */ - if (scmd->device->allow_restart && - (sshdr.asc == 0x04) && (sshdr.ascq == 0x02)) - return FAILED; - - if (sshdr.asc == 0x3f && sshdr.ascq == 0x0e) - scmd_printk(KERN_WARNING, scmd, - "Warning! Received an indication that the " - "LUN assignments on this target have " - "changed. The Linux SCSI layer does not " - "automatically remap LUN assignments.\n"); - else if (sshdr.asc == 0x3f) - scmd_printk(KERN_WARNING, scmd, - "Warning! Received an indication that the " - "operating parameters on this target have " - "changed. The Linux SCSI layer does not " - "automatically adjust these parameters.\n"); - - if (sshdr.asc == 0x38 && sshdr.ascq == 0x07) - scmd_printk(KERN_WARNING, scmd, - "Warning! Received an indication that the " - "LUN reached a thin provisioning soft " - "threshold.\n"); - - /* - * Pass the UA upwards for a determination in the completion - * functions. - */ - return SUCCESS; - - /* these are not supported */ - case COPY_ABORTED: - case VOLUME_OVERFLOW: - case MISCOMPARE: - case BLANK_CHECK: - case DATA_PROTECT: - return TARGET_ERROR; - - case MEDIUM_ERROR: - if (sshdr.asc == 0x11 || /* UNRECOVERED READ ERR */ - sshdr.asc == 0x13 || /* AMNF DATA FIELD */ - sshdr.asc == 0x14) { /* RECORD NOT FOUND */ - return TARGET_ERROR; - } - return NEEDS_RETRY; - - case HARDWARE_ERROR: - if (scmd->device->retry_hwerror) - return ADD_TO_MLQUEUE; - else - return TARGET_ERROR; - - case ILLEGAL_REQUEST: - if (sshdr.asc == 0x20 || /* Invalid command operation code */ - sshdr.asc == 0x21 || /* Logical block address out of range */ - sshdr.asc == 0x24 || /* Invalid field in cdb */ - sshdr.asc == 0x26) { /* Parameter value invalid */ - return TARGET_ERROR; - } - return SUCCESS; - - default: - return SUCCESS; - } -} - -static void scsi_handle_queue_ramp_up(struct scsi_device *sdev) -{ - struct scsi_host_template *sht = sdev->host->hostt; - struct scsi_device *tmp_sdev; - - if (!sht->change_queue_depth || - sdev->queue_depth >= sdev->max_queue_depth) - return; - - if (time_before(jiffies, - sdev->last_queue_ramp_up + sdev->queue_ramp_up_period)) - return; - - if (time_before(jiffies, - sdev->last_queue_full_time + sdev->queue_ramp_up_period)) - return; - - /* - * Walk all devices of a target and do - * ramp up on them. - */ - shost_for_each_device(tmp_sdev, sdev->host) { - if (tmp_sdev->channel != sdev->channel || - tmp_sdev->id != sdev->id || - tmp_sdev->queue_depth == sdev->max_queue_depth) - continue; - /* - * call back into LLD to increase queue_depth by one - * with ramp up reason code. - */ - sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1, - SCSI_QDEPTH_RAMP_UP); - sdev->last_queue_ramp_up = jiffies; - } -} - -static void scsi_handle_queue_full(struct scsi_device *sdev) -{ - struct scsi_host_template *sht = sdev->host->hostt; - struct scsi_device *tmp_sdev; - - if (!sht->change_queue_depth) - return; - - shost_for_each_device(tmp_sdev, sdev->host) { - if (tmp_sdev->channel != sdev->channel || - tmp_sdev->id != sdev->id) - continue; - /* - * We do not know the number of commands that were at - * the device when we got the queue full so we start - * from the highest possible value and work our way down. - */ - sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth - 1, - SCSI_QDEPTH_QFULL); - } -} - -/** - * scsi_eh_completed_normally - Disposition a eh cmd on return from LLD. - * @scmd: SCSI cmd to examine. - * - * Notes: - * This is *only* called when we are examining the status of commands - * queued during error recovery. the main difference here is that we - * don't allow for the possibility of retries here, and we are a lot - * more restrictive about what we consider acceptable. - */ -static int scsi_eh_completed_normally(struct scsi_cmnd *scmd) -{ - /* - * first check the host byte, to see if there is anything in there - * that would indicate what we need to do. - */ - if (host_byte(scmd->result) == DID_RESET) { - /* - * rats. we are already in the error handler, so we now - * get to try and figure out what to do next. if the sense - * is valid, we have a pretty good idea of what to do. - * if not, we mark it as FAILED. - */ - return scsi_check_sense(scmd); - } - if (host_byte(scmd->result) != DID_OK) - return FAILED; - - /* - * next, check the message byte. - */ - if (msg_byte(scmd->result) != COMMAND_COMPLETE) - return FAILED; - - /* - * now, check the status byte to see if this indicates - * anything special. - */ - switch (status_byte(scmd->result)) { - case GOOD: - scsi_handle_queue_ramp_up(scmd->device); - case COMMAND_TERMINATED: - return SUCCESS; - case CHECK_CONDITION: - return scsi_check_sense(scmd); - case CONDITION_GOOD: - case INTERMEDIATE_GOOD: - case INTERMEDIATE_C_GOOD: - /* - * who knows? FIXME(eric) - */ - return SUCCESS; - case RESERVATION_CONFLICT: - if (scmd->cmnd[0] == TEST_UNIT_READY) - /* it is a success, we probed the device and - * found it */ - return SUCCESS; - /* otherwise, we failed to send the command */ - return FAILED; - case QUEUE_FULL: - scsi_handle_queue_full(scmd->device); - /* fall through */ - case BUSY: - return NEEDS_RETRY; - default: - return FAILED; - } - return FAILED; -} - -/** - * scsi_eh_done - Completion function for error handling. - * @scmd: Cmd that is done. - */ -static void scsi_eh_done(struct scsi_cmnd *scmd) -{ - struct completion *eh_action; - - SCSI_LOG_ERROR_RECOVERY(3, - printk("%s scmd: %p result: %x\n", - __func__, scmd, scmd->result)); - - eh_action = scmd->device->host->eh_action; - if (eh_action) - complete(eh_action); -} - -/** - * scsi_try_host_reset - ask host adapter to reset itself - * @scmd: SCSI cmd to send hsot reset. - */ -static int scsi_try_host_reset(struct scsi_cmnd *scmd) -{ - unsigned long flags; - int rtn; - struct Scsi_Host *host = scmd->device->host; - struct scsi_host_template *hostt = host->hostt; - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n", - __func__)); - - if (!hostt->eh_host_reset_handler) - return FAILED; - - rtn = hostt->eh_host_reset_handler(scmd); - - if (rtn == SUCCESS) { - if (!hostt->skip_settle_delay) - ssleep(HOST_RESET_SETTLE_TIME); - spin_lock_irqsave(host->host_lock, flags); - scsi_report_bus_reset(host, scmd_channel(scmd)); - spin_unlock_irqrestore(host->host_lock, flags); - } - - return rtn; -} - -/** - * scsi_try_bus_reset - ask host to perform a bus reset - * @scmd: SCSI cmd to send bus reset. - */ -static int scsi_try_bus_reset(struct scsi_cmnd *scmd) -{ - unsigned long flags; - int rtn; - struct Scsi_Host *host = scmd->device->host; - struct scsi_host_template *hostt = host->hostt; - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n", - __func__)); - - if (!hostt->eh_bus_reset_handler) - return FAILED; - - rtn = hostt->eh_bus_reset_handler(scmd); - - if (rtn == SUCCESS) { - if (!hostt->skip_settle_delay) - ssleep(BUS_RESET_SETTLE_TIME); - spin_lock_irqsave(host->host_lock, flags); - scsi_report_bus_reset(host, scmd_channel(scmd)); - spin_unlock_irqrestore(host->host_lock, flags); - } - - return rtn; -} - -static void __scsi_report_device_reset(struct scsi_device *sdev, void *data) -{ - sdev->was_reset = 1; - sdev->expecting_cc_ua = 1; -} - -/** - * scsi_try_target_reset - Ask host to perform a target reset - * @scmd: SCSI cmd used to send a target reset - * - * Notes: - * There is no timeout for this operation. if this operation is - * unreliable for a given host, then the host itself needs to put a - * timer on it, and set the host back to a consistent state prior to - * returning. - */ -static int scsi_try_target_reset(struct scsi_cmnd *scmd) -{ - unsigned long flags; - int rtn; - struct Scsi_Host *host = scmd->device->host; - struct scsi_host_template *hostt = host->hostt; - - if (!hostt->eh_target_reset_handler) - return FAILED; - - rtn = hostt->eh_target_reset_handler(scmd); - if (rtn == SUCCESS) { - spin_lock_irqsave(host->host_lock, flags); - __starget_for_each_device(scsi_target(scmd->device), NULL, - __scsi_report_device_reset); - spin_unlock_irqrestore(host->host_lock, flags); - } - - return rtn; -} - -/** - * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev - * @scmd: SCSI cmd used to send BDR - * - * Notes: - * There is no timeout for this operation. if this operation is - * unreliable for a given host, then the host itself needs to put a - * timer on it, and set the host back to a consistent state prior to - * returning. - */ -static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd) -{ - int rtn; - struct scsi_host_template *hostt = scmd->device->host->hostt; - - if (!hostt->eh_device_reset_handler) - return FAILED; - - rtn = hostt->eh_device_reset_handler(scmd); - if (rtn == SUCCESS) - __scsi_report_device_reset(scmd->device, NULL); - return rtn; -} - -static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt, struct scsi_cmnd *scmd) -{ - if (!hostt->eh_abort_handler) - return FAILED; - - return hostt->eh_abort_handler(scmd); -} - -static void scsi_abort_eh_cmnd(struct scsi_cmnd *scmd) -{ - if (scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd) != SUCCESS) - if (scsi_try_bus_device_reset(scmd) != SUCCESS) - if (scsi_try_target_reset(scmd) != SUCCESS) - if (scsi_try_bus_reset(scmd) != SUCCESS) - scsi_try_host_reset(scmd); -} - -/** - * scsi_eh_prep_cmnd - Save a scsi command info as part of error recory - * @scmd: SCSI command structure to hijack - * @ses: structure to save restore information - * @cmnd: CDB to send. Can be NULL if no new cmnd is needed - * @cmnd_size: size in bytes of @cmnd (must be <= BLK_MAX_CDB) - * @sense_bytes: size of sense data to copy. or 0 (if != 0 @cmnd is ignored) - * - * This function is used to save a scsi command information before re-execution - * as part of the error recovery process. If @sense_bytes is 0 the command - * sent must be one that does not transfer any data. If @sense_bytes != 0 - * @cmnd is ignored and this functions sets up a REQUEST_SENSE command - * and cmnd buffers to read @sense_bytes into @scmd->sense_buffer. - */ -void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd, struct scsi_eh_save *ses, - unsigned char *cmnd, int cmnd_size, unsigned sense_bytes) -{ - struct scsi_device *sdev = scmd->device; - - /* - * We need saved copies of a number of fields - this is because - * error handling may need to overwrite these with different values - * to run different commands, and once error handling is complete, - * we will need to restore these values prior to running the actual - * command. - */ - ses->cmd_len = scmd->cmd_len; - ses->cmnd = scmd->cmnd; - ses->data_direction = scmd->sc_data_direction; - ses->sdb = scmd->sdb; - ses->next_rq = scmd->request->next_rq; - ses->result = scmd->result; - ses->underflow = scmd->underflow; - ses->prot_op = scmd->prot_op; - - scmd->prot_op = SCSI_PROT_NORMAL; - scmd->cmnd = ses->eh_cmnd; - memset(scmd->cmnd, 0, BLK_MAX_CDB); - memset(&scmd->sdb, 0, sizeof(scmd->sdb)); - scmd->request->next_rq = NULL; - - if (sense_bytes) { - scmd->sdb.length = min_t(unsigned, SCSI_SENSE_BUFFERSIZE, - sense_bytes); - sg_init_one(&ses->sense_sgl, scmd->sense_buffer, - scmd->sdb.length); - scmd->sdb.table.sgl = &ses->sense_sgl; - scmd->sc_data_direction = DMA_FROM_DEVICE; - scmd->sdb.table.nents = 1; - scmd->cmnd[0] = REQUEST_SENSE; - scmd->cmnd[4] = scmd->sdb.length; - scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); - } else { - scmd->sc_data_direction = DMA_NONE; - if (cmnd) { - BUG_ON(cmnd_size > BLK_MAX_CDB); - memcpy(scmd->cmnd, cmnd, cmnd_size); - scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); - } - } - - scmd->underflow = 0; - - if (sdev->scsi_level <= SCSI_2 && sdev->scsi_level != SCSI_UNKNOWN) - scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) | - (sdev->lun << 5 & 0xe0); - - /* - * Zero the sense buffer. The scsi spec mandates that any - * untransferred sense data should be interpreted as being zero. - */ - memset(scmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); -} -EXPORT_SYMBOL(scsi_eh_prep_cmnd); - -/** - * scsi_eh_restore_cmnd - Restore a scsi command info as part of error recory - * @scmd: SCSI command structure to restore - * @ses: saved information from a coresponding call to scsi_eh_prep_cmnd - * - * Undo any damage done by above scsi_eh_prep_cmnd(). - */ -void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd, struct scsi_eh_save *ses) -{ - /* - * Restore original data - */ - scmd->cmd_len = ses->cmd_len; - scmd->cmnd = ses->cmnd; - scmd->sc_data_direction = ses->data_direction; - scmd->sdb = ses->sdb; - scmd->request->next_rq = ses->next_rq; - scmd->result = ses->result; - scmd->underflow = ses->underflow; - scmd->prot_op = ses->prot_op; -} -EXPORT_SYMBOL(scsi_eh_restore_cmnd); - -/** - * scsi_send_eh_cmnd - submit a scsi command as part of error recory - * @scmd: SCSI command structure to hijack - * @cmnd: CDB to send - * @cmnd_size: size in bytes of @cmnd - * @timeout: timeout for this request - * @sense_bytes: size of sense data to copy or 0 - * - * This function is used to send a scsi command down to a target device - * as part of the error recovery process. See also scsi_eh_prep_cmnd() above. - * - * Return value: - * SUCCESS or FAILED or NEEDS_RETRY - */ -static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd, - int cmnd_size, int timeout, unsigned sense_bytes) -{ - struct scsi_device *sdev = scmd->device; - struct scsi_driver *sdrv = scsi_cmd_to_driver(scmd); - struct Scsi_Host *shost = sdev->host; - DECLARE_COMPLETION_ONSTACK(done); - unsigned long timeleft; - struct scsi_eh_save ses; - int rtn; - - scsi_eh_prep_cmnd(scmd, &ses, cmnd, cmnd_size, sense_bytes); - shost->eh_action = &done; - - scsi_log_send(scmd); - scmd->scsi_done = scsi_eh_done; - shost->hostt->queuecommand(shost, scmd); - - timeleft = wait_for_completion_timeout(&done, timeout); - - shost->eh_action = NULL; - - scsi_log_completion(scmd, SUCCESS); - - SCSI_LOG_ERROR_RECOVERY(3, - printk("%s: scmd: %p, timeleft: %ld\n", - __func__, scmd, timeleft)); - - /* - * If there is time left scsi_eh_done got called, and we will - * examine the actual status codes to see whether the command - * actually did complete normally, else tell the host to forget - * about this command. - */ - if (timeleft) { - rtn = scsi_eh_completed_normally(scmd); - SCSI_LOG_ERROR_RECOVERY(3, - printk("%s: scsi_eh_completed_normally %x\n", - __func__, rtn)); - - switch (rtn) { - case SUCCESS: - case NEEDS_RETRY: - case FAILED: - case TARGET_ERROR: - break; - case ADD_TO_MLQUEUE: - rtn = NEEDS_RETRY; - break; - default: - rtn = FAILED; - break; - } - } else { - scsi_abort_eh_cmnd(scmd); - rtn = FAILED; - } - - scsi_eh_restore_cmnd(scmd, &ses); - - if (sdrv && sdrv->eh_action) - rtn = sdrv->eh_action(scmd, cmnd, cmnd_size, rtn); - - return rtn; -} - -/** - * scsi_request_sense - Request sense data from a particular target. - * @scmd: SCSI cmd for request sense. - * - * Notes: - * Some hosts automatically obtain this information, others require - * that we obtain it on our own. This function will *not* return until - * the command either times out, or it completes. - */ -static int scsi_request_sense(struct scsi_cmnd *scmd) -{ - return scsi_send_eh_cmnd(scmd, NULL, 0, SENSE_TIMEOUT, ~0); -} - -/** - * scsi_eh_finish_cmd - Handle a cmd that eh is finished with. - * @scmd: Original SCSI cmd that eh has finished. - * @done_q: Queue for processed commands. - * - * Notes: - * We don't want to use the normal command completion while we are are - * still handling errors - it may cause other commands to be queued, - * and that would disturb what we are doing. Thus we really want to - * keep a list of pending commands for final completion, and once we - * are ready to leave error handling we handle completion for real. - */ -void scsi_eh_finish_cmd(struct scsi_cmnd *scmd, struct list_head *done_q) -{ - scmd->device->host->host_failed--; - scmd->eh_eflags = 0; - list_move_tail(&scmd->eh_entry, done_q); -} -EXPORT_SYMBOL(scsi_eh_finish_cmd); - -/** - * scsi_eh_get_sense - Get device sense data. - * @work_q: Queue of commands to process. - * @done_q: Queue of processed commands. - * - * Description: - * See if we need to request sense information. if so, then get it - * now, so we have a better idea of what to do. - * - * Notes: - * This has the unfortunate side effect that if a shost adapter does - * not automatically request sense information, we end up shutting - * it down before we request it. - * - * All drivers should request sense information internally these days, - * so for now all I have to say is tough noogies if you end up in here. - * - * XXX: Long term this code should go away, but that needs an audit of - * all LLDDs first. - */ -int scsi_eh_get_sense(struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *next; - int rtn; - - list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - if ((scmd->eh_eflags & SCSI_EH_CANCEL_CMD) || - SCSI_SENSE_VALID(scmd)) - continue; - - SCSI_LOG_ERROR_RECOVERY(2, scmd_printk(KERN_INFO, scmd, - "%s: requesting sense\n", - current->comm)); - rtn = scsi_request_sense(scmd); - if (rtn != SUCCESS) - continue; - - SCSI_LOG_ERROR_RECOVERY(3, printk("sense requested for %p" - " result %x\n", scmd, - scmd->result)); - SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense("bh", scmd)); - - rtn = scsi_decide_disposition(scmd); - - /* - * if the result was normal, then just pass it along to the - * upper level. - */ - if (rtn == SUCCESS) - /* we don't want this command reissued, just - * finished with the sense data, so set - * retries to the max allowed to ensure it - * won't get reissued */ - scmd->retries = scmd->allowed; - else if (rtn != NEEDS_RETRY) - continue; - - scsi_eh_finish_cmd(scmd, done_q); - } - - return list_empty(work_q); -} -EXPORT_SYMBOL_GPL(scsi_eh_get_sense); - -/** - * scsi_eh_tur - Send TUR to device. - * @scmd: &scsi_cmnd to send TUR - * - * Return value: - * 0 - Device is ready. 1 - Device NOT ready. - */ -static int scsi_eh_tur(struct scsi_cmnd *scmd) -{ - static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; - int retry_cnt = 1, rtn; - -retry_tur: - rtn = scsi_send_eh_cmnd(scmd, tur_command, 6, SENSE_TIMEOUT, 0); - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n", - __func__, scmd, rtn)); - - switch (rtn) { - case NEEDS_RETRY: - if (retry_cnt--) - goto retry_tur; - /*FALLTHRU*/ - case SUCCESS: - return 0; - default: - return 1; - } -} - -/** - * scsi_eh_test_devices - check if devices are responding from error recovery. - * @cmd_list: scsi commands in error recovery. - * @work_q: queue for commands which still need more error recovery - * @done_q: queue for commands which are finished - * @try_stu: boolean on if a STU command should be tried in addition to TUR. - * - * Decription: - * Tests if devices are in a working state. Commands to devices now in - * a working state are sent to the done_q while commands to devices which - * are still failing to respond are returned to the work_q for more - * processing. - **/ -static int scsi_eh_test_devices(struct list_head *cmd_list, - struct list_head *work_q, - struct list_head *done_q, int try_stu) -{ - struct scsi_cmnd *scmd, *next; - struct scsi_device *sdev; - int finish_cmds; - - while (!list_empty(cmd_list)) { - scmd = list_entry(cmd_list->next, struct scsi_cmnd, eh_entry); - sdev = scmd->device; - - finish_cmds = !scsi_device_online(scmd->device) || - (try_stu && !scsi_eh_try_stu(scmd) && - !scsi_eh_tur(scmd)) || - !scsi_eh_tur(scmd); - - list_for_each_entry_safe(scmd, next, cmd_list, eh_entry) - if (scmd->device == sdev) { - if (finish_cmds) - scsi_eh_finish_cmd(scmd, done_q); - else - list_move_tail(&scmd->eh_entry, work_q); - } - } - return list_empty(work_q); -} - - -/** - * scsi_eh_abort_cmds - abort pending commands. - * @work_q: &list_head for pending commands. - * @done_q: &list_head for processed commands. - * - * Decription: - * Try and see whether or not it makes sense to try and abort the - * running command. This only works out to be the case if we have one - * command that has timed out. If the command simply failed, it makes - * no sense to try and abort the command, since as far as the shost - * adapter is concerned, it isn't running. - */ -static int scsi_eh_abort_cmds(struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *next; - LIST_HEAD(check_list); - int rtn; - - list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - if (!(scmd->eh_eflags & SCSI_EH_CANCEL_CMD)) - continue; - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting cmd:" - "0x%p\n", current->comm, - scmd)); - rtn = scsi_try_to_abort_cmd(scmd->device->host->hostt, scmd); - if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { - scmd->eh_eflags &= ~SCSI_EH_CANCEL_CMD; - if (rtn == FAST_IO_FAIL) - scsi_eh_finish_cmd(scmd, done_q); - else - list_move_tail(&scmd->eh_entry, &check_list); - } else - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting" - " cmd failed:" - "0x%p\n", - current->comm, - scmd)); - } - - return scsi_eh_test_devices(&check_list, work_q, done_q, 0); -} - -/** - * scsi_eh_try_stu - Send START_UNIT to device. - * @scmd: &scsi_cmnd to send START_UNIT - * - * Return value: - * 0 - Device is ready. 1 - Device NOT ready. - */ -static int scsi_eh_try_stu(struct scsi_cmnd *scmd) -{ - static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0}; - - if (scmd->device->allow_restart) { - int i, rtn = NEEDS_RETRY; - - for (i = 0; rtn == NEEDS_RETRY && i < 2; i++) - rtn = scsi_send_eh_cmnd(scmd, stu_command, 6, scmd->device->request_queue->rq_timeout, 0); - - if (rtn == SUCCESS) - return 0; - } - - return 1; -} - - /** - * scsi_eh_stu - send START_UNIT if needed - * @shost: &scsi host being recovered. - * @work_q: &list_head for pending commands. - * @done_q: &list_head for processed commands. - * - * Notes: - * If commands are failing due to not ready, initializing command required, - * try revalidating the device, which will end up sending a start unit. - */ -static int scsi_eh_stu(struct Scsi_Host *shost, - struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *stu_scmd, *next; - struct scsi_device *sdev; - - shost_for_each_device(sdev, shost) { - stu_scmd = NULL; - list_for_each_entry(scmd, work_q, eh_entry) - if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) && - scsi_check_sense(scmd) == FAILED ) { - stu_scmd = scmd; - break; - } - - if (!stu_scmd) - continue; - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending START_UNIT to sdev:" - " 0x%p\n", current->comm, sdev)); - - if (!scsi_eh_try_stu(stu_scmd)) { - if (!scsi_device_online(sdev) || - !scsi_eh_tur(stu_scmd)) { - list_for_each_entry_safe(scmd, next, - work_q, eh_entry) { - if (scmd->device == sdev) - scsi_eh_finish_cmd(scmd, done_q); - } - } - } else { - SCSI_LOG_ERROR_RECOVERY(3, - printk("%s: START_UNIT failed to sdev:" - " 0x%p\n", current->comm, sdev)); - } - } - - return list_empty(work_q); -} - - -/** - * scsi_eh_bus_device_reset - send bdr if needed - * @shost: scsi host being recovered. - * @work_q: &list_head for pending commands. - * @done_q: &list_head for processed commands. - * - * Notes: - * Try a bus device reset. Still, look to see whether we have multiple - * devices that are jammed or not - if we have multiple devices, it - * makes no sense to try bus_device_reset - we really would need to try - * a bus_reset instead. - */ -static int scsi_eh_bus_device_reset(struct Scsi_Host *shost, - struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *bdr_scmd, *next; - struct scsi_device *sdev; - int rtn; - - shost_for_each_device(sdev, shost) { - bdr_scmd = NULL; - list_for_each_entry(scmd, work_q, eh_entry) - if (scmd->device == sdev) { - bdr_scmd = scmd; - break; - } - - if (!bdr_scmd) - continue; - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending BDR sdev:" - " 0x%p\n", current->comm, - sdev)); - rtn = scsi_try_bus_device_reset(bdr_scmd); - if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { - if (!scsi_device_online(sdev) || - rtn == FAST_IO_FAIL || - !scsi_eh_tur(bdr_scmd)) { - list_for_each_entry_safe(scmd, next, - work_q, eh_entry) { - if (scmd->device == sdev) - scsi_eh_finish_cmd(scmd, - done_q); - } - } - } else { - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BDR" - " failed sdev:" - "0x%p\n", - current->comm, - sdev)); - } - } - - return list_empty(work_q); -} - -/** - * scsi_eh_target_reset - send target reset if needed - * @shost: scsi host being recovered. - * @work_q: &list_head for pending commands. - * @done_q: &list_head for processed commands. - * - * Notes: - * Try a target reset. - */ -static int scsi_eh_target_reset(struct Scsi_Host *shost, - struct list_head *work_q, - struct list_head *done_q) -{ - LIST_HEAD(tmp_list); - LIST_HEAD(check_list); - - list_splice_init(work_q, &tmp_list); - - while (!list_empty(&tmp_list)) { - struct scsi_cmnd *next, *scmd; - int rtn; - unsigned int id; - - scmd = list_entry(tmp_list.next, struct scsi_cmnd, eh_entry); - id = scmd_id(scmd); - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending target reset " - "to target %d\n", - current->comm, id)); - rtn = scsi_try_target_reset(scmd); - if (rtn != SUCCESS && rtn != FAST_IO_FAIL) - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Target reset" - " failed target: " - "%d\n", - current->comm, id)); - list_for_each_entry_safe(scmd, next, &tmp_list, eh_entry) { - if (scmd_id(scmd) != id) - continue; - - if (rtn == SUCCESS) - list_move_tail(&scmd->eh_entry, &check_list); - else if (rtn == FAST_IO_FAIL) - scsi_eh_finish_cmd(scmd, done_q); - else - /* push back on work queue for further processing */ - list_move(&scmd->eh_entry, work_q); - } - } - - return scsi_eh_test_devices(&check_list, work_q, done_q, 0); -} - -/** - * scsi_eh_bus_reset - send a bus reset - * @shost: &scsi host being recovered. - * @work_q: &list_head for pending commands. - * @done_q: &list_head for processed commands. - */ -static int scsi_eh_bus_reset(struct Scsi_Host *shost, - struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *chan_scmd, *next; - LIST_HEAD(check_list); - unsigned int channel; - int rtn; - - /* - * we really want to loop over the various channels, and do this on - * a channel by channel basis. we should also check to see if any - * of the failed commands are on soft_reset devices, and if so, skip - * the reset. - */ - - for (channel = 0; channel <= shost->max_channel; channel++) { - chan_scmd = NULL; - list_for_each_entry(scmd, work_q, eh_entry) { - if (channel == scmd_channel(scmd)) { - chan_scmd = scmd; - break; - /* - * FIXME add back in some support for - * soft_reset devices. - */ - } - } - - if (!chan_scmd) - continue; - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending BRST chan:" - " %d\n", current->comm, - channel)); - rtn = scsi_try_bus_reset(chan_scmd); - if (rtn == SUCCESS || rtn == FAST_IO_FAIL) { - list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - if (channel == scmd_channel(scmd)) { - if (rtn == FAST_IO_FAIL) - scsi_eh_finish_cmd(scmd, - done_q); - else - list_move_tail(&scmd->eh_entry, - &check_list); - } - } - } else { - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BRST" - " failed chan: %d\n", - current->comm, - channel)); - } - } - return scsi_eh_test_devices(&check_list, work_q, done_q, 0); -} - -/** - * scsi_eh_host_reset - send a host reset - * @work_q: list_head for processed commands. - * @done_q: list_head for processed commands. - */ -static int scsi_eh_host_reset(struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *next; - LIST_HEAD(check_list); - int rtn; - - if (!list_empty(work_q)) { - scmd = list_entry(work_q->next, - struct scsi_cmnd, eh_entry); - - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending HRST\n" - , current->comm)); - - rtn = scsi_try_host_reset(scmd); - if (rtn == SUCCESS) { - list_splice_init(work_q, &check_list); - } else if (rtn == FAST_IO_FAIL) { - list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - scsi_eh_finish_cmd(scmd, done_q); - } - } else { - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: HRST" - " failed\n", - current->comm)); - } - } - return scsi_eh_test_devices(&check_list, work_q, done_q, 1); -} - -/** - * scsi_eh_offline_sdevs - offline scsi devices that fail to recover - * @work_q: list_head for processed commands. - * @done_q: list_head for processed commands. - */ -static void scsi_eh_offline_sdevs(struct list_head *work_q, - struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *next; - - list_for_each_entry_safe(scmd, next, work_q, eh_entry) { - sdev_printk(KERN_INFO, scmd->device, "Device offlined - " - "not ready after error recovery\n"); - scsi_device_set_state(scmd->device, SDEV_OFFLINE); - if (scmd->eh_eflags & SCSI_EH_CANCEL_CMD) { - /* - * FIXME: Handle lost cmds. - */ - } - scsi_eh_finish_cmd(scmd, done_q); - } - return; -} - -/** - * scsi_noretry_cmd - determinte if command should be failed fast - * @scmd: SCSI cmd to examine. - */ -int scsi_noretry_cmd(struct scsi_cmnd *scmd) -{ - switch (host_byte(scmd->result)) { - case DID_OK: - break; - case DID_BUS_BUSY: - return (scmd->request->cmd_flags & REQ_FAILFAST_TRANSPORT); - case DID_PARITY: - return (scmd->request->cmd_flags & REQ_FAILFAST_DEV); - case DID_ERROR: - if (msg_byte(scmd->result) == COMMAND_COMPLETE && - status_byte(scmd->result) == RESERVATION_CONFLICT) - return 0; - /* fall through */ - case DID_SOFT_ERROR: - return (scmd->request->cmd_flags & REQ_FAILFAST_DRIVER); - } - - switch (status_byte(scmd->result)) { - case CHECK_CONDITION: - /* - * assume caller has checked sense and determinted - * the check condition was retryable. - */ - if (scmd->request->cmd_flags & REQ_FAILFAST_DEV || - scmd->request->cmd_type == REQ_TYPE_BLOCK_PC) - return 1; - } - - return 0; -} - -/** - * scsi_decide_disposition - Disposition a cmd on return from LLD. - * @scmd: SCSI cmd to examine. - * - * Notes: - * This is *only* called when we are examining the status after sending - * out the actual data command. any commands that are queued for error - * recovery (e.g. test_unit_ready) do *not* come through here. - * - * When this routine returns failed, it means the error handler thread - * is woken. In cases where the error code indicates an error that - * doesn't require the error handler read (i.e. we don't need to - * abort/reset), this function should return SUCCESS. - */ -int scsi_decide_disposition(struct scsi_cmnd *scmd) -{ - int rtn; - - /* - * if the device is offline, then we clearly just pass the result back - * up to the top level. - */ - if (!scsi_device_online(scmd->device)) { - SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report" - " as SUCCESS\n", - __func__)); - return SUCCESS; - } - - /* - * first check the host byte, to see if there is anything in there - * that would indicate what we need to do. - */ - switch (host_byte(scmd->result)) { - case DID_PASSTHROUGH: - /* - * no matter what, pass this through to the upper layer. - * nuke this special code so that it looks like we are saying - * did_ok. - */ - scmd->result &= 0xff00ffff; - return SUCCESS; - case DID_OK: - /* - * looks good. drop through, and check the next byte. - */ - break; - case DID_NO_CONNECT: - case DID_BAD_TARGET: - case DID_ABORT: - /* - * note - this means that we just report the status back - * to the top level driver, not that we actually think - * that it indicates SUCCESS. - */ - return SUCCESS; - /* - * when the low level driver returns did_soft_error, - * it is responsible for keeping an internal retry counter - * in order to avoid endless loops (db) - * - * actually this is a bug in this function here. we should - * be mindful of the maximum number of retries specified - * and not get stuck in a loop. - */ - case DID_SOFT_ERROR: - goto maybe_retry; - case DID_IMM_RETRY: - return NEEDS_RETRY; - - case DID_REQUEUE: - return ADD_TO_MLQUEUE; - case DID_TRANSPORT_DISRUPTED: - /* - * LLD/transport was disrupted during processing of the IO. - * The transport class is now blocked/blocking, - * and the transport will decide what to do with the IO - * based on its timers and recovery capablilities if - * there are enough retries. - */ - goto maybe_retry; - case DID_TRANSPORT_FAILFAST: - /* - * The transport decided to failfast the IO (most likely - * the fast io fail tmo fired), so send IO directly upwards. - */ - return SUCCESS; - case DID_ERROR: - if (msg_byte(scmd->result) == COMMAND_COMPLETE && - status_byte(scmd->result) == RESERVATION_CONFLICT) - /* - * execute reservation conflict processing code - * lower down - */ - break; - /* fallthrough */ - case DID_BUS_BUSY: - case DID_PARITY: - goto maybe_retry; - case DID_TIME_OUT: - /* - * when we scan the bus, we get timeout messages for - * these commands if there is no device available. - * other hosts report did_no_connect for the same thing. - */ - if ((scmd->cmnd[0] == TEST_UNIT_READY || - scmd->cmnd[0] == INQUIRY)) { - return SUCCESS; - } else { - return FAILED; - } - case DID_RESET: - return SUCCESS; - default: - return FAILED; - } - - /* - * next, check the message byte. - */ - if (msg_byte(scmd->result) != COMMAND_COMPLETE) - return FAILED; - - /* - * check the status byte to see if this indicates anything special. - */ - switch (status_byte(scmd->result)) { - case QUEUE_FULL: - scsi_handle_queue_full(scmd->device); - /* - * the case of trying to send too many commands to a - * tagged queueing device. - */ - case BUSY: - /* - * device can't talk to us at the moment. Should only - * occur (SAM-3) when the task queue is empty, so will cause - * the empty queue handling to trigger a stall in the - * device. - */ - return ADD_TO_MLQUEUE; - case GOOD: - scsi_handle_queue_ramp_up(scmd->device); - case COMMAND_TERMINATED: - return SUCCESS; - case TASK_ABORTED: - goto maybe_retry; - case CHECK_CONDITION: - rtn = scsi_check_sense(scmd); - if (rtn == NEEDS_RETRY) - goto maybe_retry; - else if (rtn == TARGET_ERROR) { - /* - * Need to modify host byte to signal a - * permanent target failure - */ - set_host_byte(scmd, DID_TARGET_FAILURE); - rtn = SUCCESS; - } - /* if rtn == FAILED, we have no sense information; - * returning FAILED will wake the error handler thread - * to collect the sense and redo the decide - * disposition */ - return rtn; - case CONDITION_GOOD: - case INTERMEDIATE_GOOD: - case INTERMEDIATE_C_GOOD: - case ACA_ACTIVE: - /* - * who knows? FIXME(eric) - */ - return SUCCESS; - - case RESERVATION_CONFLICT: - sdev_printk(KERN_INFO, scmd->device, - "reservation conflict\n"); - set_host_byte(scmd, DID_NEXUS_FAILURE); - return SUCCESS; /* causes immediate i/o error */ - default: - return FAILED; - } - return FAILED; - - maybe_retry: - - /* we requeue for retry because the error was retryable, and - * the request was not marked fast fail. Note that above, - * even if the request is marked fast fail, we still requeue - * for queue congestion conditions (QUEUE_FULL or BUSY) */ - if ((++scmd->retries) <= scmd->allowed - && !scsi_noretry_cmd(scmd)) { - return NEEDS_RETRY; - } else { - /* - * no more retries - report this one back to upper level. - */ - return SUCCESS; - } -} - -static void eh_lock_door_done(struct request *req, int uptodate) -{ - __blk_put_request(req->q, req); -} - -/** - * scsi_eh_lock_door - Prevent medium removal for the specified device - * @sdev: SCSI device to prevent medium removal - * - * Locking: - * We must be called from process context. - * - * Notes: - * We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the - * head of the devices request queue, and continue. - */ -static void scsi_eh_lock_door(struct scsi_device *sdev) -{ - struct request *req; - - /* - * blk_get_request with GFP_KERNEL (__GFP_WAIT) sleeps until a - * request becomes available - */ - req = blk_get_request(sdev->request_queue, READ, GFP_KERNEL); - - req->cmd[0] = ALLOW_MEDIUM_REMOVAL; - req->cmd[1] = 0; - req->cmd[2] = 0; - req->cmd[3] = 0; - req->cmd[4] = SCSI_REMOVAL_PREVENT; - req->cmd[5] = 0; - - req->cmd_len = COMMAND_SIZE(req->cmd[0]); - - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_QUIET; - req->timeout = 10 * HZ; - req->retries = 5; - - blk_execute_rq_nowait(req->q, NULL, req, 1, eh_lock_door_done); -} - -/** - * scsi_restart_operations - restart io operations to the specified host. - * @shost: Host we are restarting. - * - * Notes: - * When we entered the error handler, we blocked all further i/o to - * this device. we need to 'reverse' this process. - */ -static void scsi_restart_operations(struct Scsi_Host *shost) -{ - struct scsi_device *sdev; - unsigned long flags; - - /* - * If the door was locked, we need to insert a door lock request - * onto the head of the SCSI request queue for the device. There - * is no point trying to lock the door of an off-line device. - */ - shost_for_each_device(sdev, shost) { - if (scsi_device_online(sdev) && sdev->locked) - scsi_eh_lock_door(sdev); - } - - /* - * next free up anything directly waiting upon the host. this - * will be requests for character device operations, and also for - * ioctls to queued block devices. - */ - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", - __func__)); - - spin_lock_irqsave(shost->host_lock, flags); - if (scsi_host_set_state(shost, SHOST_RUNNING)) - if (scsi_host_set_state(shost, SHOST_CANCEL)) - BUG_ON(scsi_host_set_state(shost, SHOST_DEL)); - spin_unlock_irqrestore(shost->host_lock, flags); - - wake_up(&shost->host_wait); - - /* - * finally we need to re-initiate requests that may be pending. we will - * have had everything blocked while error handling is taking place, and - * now that error recovery is done, we will need to ensure that these - * requests are started. - */ - scsi_run_host_queues(shost); -} - -/** - * scsi_eh_ready_devs - check device ready state and recover if not. - * @shost: host to be recovered. - * @work_q: &list_head for pending commands. - * @done_q: &list_head for processed commands. - */ -void scsi_eh_ready_devs(struct Scsi_Host *shost, - struct list_head *work_q, - struct list_head *done_q) -{ - if (!scsi_eh_stu(shost, work_q, done_q)) - if (!scsi_eh_bus_device_reset(shost, work_q, done_q)) - if (!scsi_eh_target_reset(shost, work_q, done_q)) - if (!scsi_eh_bus_reset(shost, work_q, done_q)) - if (!scsi_eh_host_reset(work_q, done_q)) - scsi_eh_offline_sdevs(work_q, - done_q); -} -EXPORT_SYMBOL_GPL(scsi_eh_ready_devs); - -/** - * scsi_eh_flush_done_q - finish processed commands or retry them. - * @done_q: list_head of processed commands. - */ -void scsi_eh_flush_done_q(struct list_head *done_q) -{ - struct scsi_cmnd *scmd, *next; - - list_for_each_entry_safe(scmd, next, done_q, eh_entry) { - list_del_init(&scmd->eh_entry); - if (scsi_device_online(scmd->device) && - !scsi_noretry_cmd(scmd) && - (++scmd->retries <= scmd->allowed)) { - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: flush" - " retry cmd: %p\n", - current->comm, - scmd)); - scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY); - } else { - /* - * If just we got sense for the device (called - * scsi_eh_get_sense), scmd->result is already - * set, do not set DRIVER_TIMEOUT. - */ - if (!scmd->result) - scmd->result |= (DRIVER_TIMEOUT << 24); - SCSI_LOG_ERROR_RECOVERY(3, printk("%s: flush finish" - " cmd: %p\n", - current->comm, scmd)); - scsi_finish_command(scmd); - } - } -} -EXPORT_SYMBOL(scsi_eh_flush_done_q); - -/** - * scsi_unjam_host - Attempt to fix a host which has a cmd that failed. - * @shost: Host to unjam. - * - * Notes: - * When we come in here, we *know* that all commands on the bus have - * either completed, failed or timed out. we also know that no further - * commands are being sent to the host, so things are relatively quiet - * and we have freedom to fiddle with things as we wish. - * - * This is only the *default* implementation. it is possible for - * individual drivers to supply their own version of this function, and - * if the maintainer wishes to do this, it is strongly suggested that - * this function be taken as a template and modified. this function - * was designed to correctly handle problems for about 95% of the - * different cases out there, and it should always provide at least a - * reasonable amount of error recovery. - * - * Any command marked 'failed' or 'timeout' must eventually have - * scsi_finish_cmd() called for it. we do all of the retry stuff - * here, so when we restart the host after we return it should have an - * empty queue. - */ -static void scsi_unjam_host(struct Scsi_Host *shost) -{ - unsigned long flags; - LIST_HEAD(eh_work_q); - LIST_HEAD(eh_done_q); - - spin_lock_irqsave(shost->host_lock, flags); - list_splice_init(&shost->eh_cmd_q, &eh_work_q); - spin_unlock_irqrestore(shost->host_lock, flags); - - SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(shost, &eh_work_q)); - - if (!scsi_eh_get_sense(&eh_work_q, &eh_done_q)) - if (!scsi_eh_abort_cmds(&eh_work_q, &eh_done_q)) - scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q); - - scsi_eh_flush_done_q(&eh_done_q); -} - -/** - * scsi_error_handler - SCSI error handler thread - * @data: Host for which we are running. - * - * Notes: - * This is the main error handling loop. This is run as a kernel thread - * for every SCSI host and handles all error handling activity. - */ -int scsi_error_handler(void *data) -{ - struct Scsi_Host *shost = data; - - /* - * We use TASK_INTERRUPTIBLE so that the thread is not - * counted against the load average as a running process. - * We never actually get interrupted because kthread_run - * disables signal delivery for the created thread. - */ - set_current_state(TASK_INTERRUPTIBLE); - while (!kthread_should_stop()) { - if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) || - shost->host_failed != shost->host_busy) { - SCSI_LOG_ERROR_RECOVERY(1, - printk("Error handler scsi_eh_%d sleeping\n", - shost->host_no)); - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - continue; - } - - __set_current_state(TASK_RUNNING); - SCSI_LOG_ERROR_RECOVERY(1, - printk("Error handler scsi_eh_%d waking up\n", - shost->host_no)); - - /* - * We have a host that is failing for some reason. Figure out - * what we need to do to get it up and online again (if we can). - * If we fail, we end up taking the thing offline. - */ - if (!shost->eh_noresume && scsi_autopm_get_host(shost) != 0) { - SCSI_LOG_ERROR_RECOVERY(1, - printk(KERN_ERR "Error handler scsi_eh_%d " - "unable to autoresume\n", - shost->host_no)); - continue; - } - - if (shost->transportt->eh_strategy_handler) - shost->transportt->eh_strategy_handler(shost); - else - scsi_unjam_host(shost); - - /* - * Note - if the above fails completely, the action is to take - * individual devices offline and flush the queue of any - * outstanding requests that may have been pending. When we - * restart, we restart any I/O to any other devices on the bus - * which are still online. - */ - scsi_restart_operations(shost); - if (!shost->eh_noresume) - scsi_autopm_put_host(shost); - set_current_state(TASK_INTERRUPTIBLE); - } - __set_current_state(TASK_RUNNING); - - SCSI_LOG_ERROR_RECOVERY(1, - printk("Error handler scsi_eh_%d exiting\n", shost->host_no)); - shost->ehandler = NULL; - return 0; -} - -/* - * Function: scsi_report_bus_reset() - * - * Purpose: Utility function used by low-level drivers to report that - * they have observed a bus reset on the bus being handled. - * - * Arguments: shost - Host in question - * channel - channel on which reset was observed. - * - * Returns: Nothing - * - * Lock status: Host lock must be held. - * - * Notes: This only needs to be called if the reset is one which - * originates from an unknown location. Resets originated - * by the mid-level itself don't need to call this, but there - * should be no harm. - * - * The main purpose of this is to make sure that a CHECK_CONDITION - * is properly treated. - */ -void scsi_report_bus_reset(struct Scsi_Host *shost, int channel) -{ - struct scsi_device *sdev; - - __shost_for_each_device(sdev, shost) { - if (channel == sdev_channel(sdev)) - __scsi_report_device_reset(sdev, NULL); - } -} -EXPORT_SYMBOL(scsi_report_bus_reset); - -/* - * Function: scsi_report_device_reset() - * - * Purpose: Utility function used by low-level drivers to report that - * they have observed a device reset on the device being handled. - * - * Arguments: shost - Host in question - * channel - channel on which reset was observed - * target - target on which reset was observed - * - * Returns: Nothing - * - * Lock status: Host lock must be held - * - * Notes: This only needs to be called if the reset is one which - * originates from an unknown location. Resets originated - * by the mid-level itself don't need to call this, but there - * should be no harm. - * - * The main purpose of this is to make sure that a CHECK_CONDITION - * is properly treated. - */ -void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target) -{ - struct scsi_device *sdev; - - __shost_for_each_device(sdev, shost) { - if (channel == sdev_channel(sdev) && - target == sdev_id(sdev)) - __scsi_report_device_reset(sdev, NULL); - } -} -EXPORT_SYMBOL(scsi_report_device_reset); - -static void -scsi_reset_provider_done_command(struct scsi_cmnd *scmd) -{ -} - -/* - * Function: scsi_reset_provider - * - * Purpose: Send requested reset to a bus or device at any phase. - * - * Arguments: device - device to send reset to - * flag - reset type (see scsi.h) - * - * Returns: SUCCESS/FAILURE. - * - * Notes: This is used by the SCSI Generic driver to provide - * Bus/Device reset capability. - */ -int -scsi_reset_provider(struct scsi_device *dev, int flag) -{ - struct scsi_cmnd *scmd; - struct Scsi_Host *shost = dev->host; - struct request req; - unsigned long flags; - int rtn; - - if (scsi_autopm_get_host(shost) < 0) - return FAILED; - - scmd = scsi_get_command(dev, GFP_KERNEL); - blk_rq_init(NULL, &req); - scmd->request = &req; - - scmd->cmnd = req.cmd; - - scmd->scsi_done = scsi_reset_provider_done_command; - memset(&scmd->sdb, 0, sizeof(scmd->sdb)); - - scmd->cmd_len = 0; - - scmd->sc_data_direction = DMA_BIDIRECTIONAL; - - spin_lock_irqsave(shost->host_lock, flags); - shost->tmf_in_progress = 1; - spin_unlock_irqrestore(shost->host_lock, flags); - - switch (flag) { - case SCSI_TRY_RESET_DEVICE: - rtn = scsi_try_bus_device_reset(scmd); - if (rtn == SUCCESS) - break; - /* FALLTHROUGH */ - case SCSI_TRY_RESET_TARGET: - rtn = scsi_try_target_reset(scmd); - if (rtn == SUCCESS) - break; - /* FALLTHROUGH */ - case SCSI_TRY_RESET_BUS: - rtn = scsi_try_bus_reset(scmd); - if (rtn == SUCCESS) - break; - /* FALLTHROUGH */ - case SCSI_TRY_RESET_HOST: - rtn = scsi_try_host_reset(scmd); - break; - default: - rtn = FAILED; - } - - spin_lock_irqsave(shost->host_lock, flags); - shost->tmf_in_progress = 0; - spin_unlock_irqrestore(shost->host_lock, flags); - - /* - * be sure to wake up anyone who was sleeping or had their queue - * suspended while we performed the TMF. - */ - SCSI_LOG_ERROR_RECOVERY(3, - printk("%s: waking up host to restart after TMF\n", - __func__)); - - wake_up(&shost->host_wait); - - scsi_run_host_queues(shost); - - scsi_next_command(scmd); - scsi_autopm_put_host(shost); - return rtn; -} -EXPORT_SYMBOL(scsi_reset_provider); - -/** - * scsi_normalize_sense - normalize main elements from either fixed or - * descriptor sense data format into a common format. - * - * @sense_buffer: byte array containing sense data returned by device - * @sb_len: number of valid bytes in sense_buffer - * @sshdr: pointer to instance of structure that common - * elements are written to. - * - * Notes: - * The "main elements" from sense data are: response_code, sense_key, - * asc, ascq and additional_length (only for descriptor format). - * - * Typically this function can be called after a device has - * responded to a SCSI command with the CHECK_CONDITION status. - * - * Return value: - * 1 if valid sense data information found, else 0; - */ -int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, - struct scsi_sense_hdr *sshdr) -{ - if (!sense_buffer || !sb_len) - return 0; - - memset(sshdr, 0, sizeof(struct scsi_sense_hdr)); - - sshdr->response_code = (sense_buffer[0] & 0x7f); - - if (!scsi_sense_valid(sshdr)) - return 0; - - if (sshdr->response_code >= 0x72) { - /* - * descriptor format - */ - if (sb_len > 1) - sshdr->sense_key = (sense_buffer[1] & 0xf); - if (sb_len > 2) - sshdr->asc = sense_buffer[2]; - if (sb_len > 3) - sshdr->ascq = sense_buffer[3]; - if (sb_len > 7) - sshdr->additional_length = sense_buffer[7]; - } else { - /* - * fixed format - */ - if (sb_len > 2) - sshdr->sense_key = (sense_buffer[2] & 0xf); - if (sb_len > 7) { - sb_len = (sb_len < (sense_buffer[7] + 8)) ? - sb_len : (sense_buffer[7] + 8); - if (sb_len > 12) - sshdr->asc = sense_buffer[12]; - if (sb_len > 13) - sshdr->ascq = sense_buffer[13]; - } - } - - return 1; -} -EXPORT_SYMBOL(scsi_normalize_sense); - -int scsi_command_normalize_sense(struct scsi_cmnd *cmd, - struct scsi_sense_hdr *sshdr) -{ - return scsi_normalize_sense(cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, sshdr); -} -EXPORT_SYMBOL(scsi_command_normalize_sense); - -/** - * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format. - * @sense_buffer: byte array of descriptor format sense data - * @sb_len: number of valid bytes in sense_buffer - * @desc_type: value of descriptor type to find - * (e.g. 0 -> information) - * - * Notes: - * only valid when sense data is in descriptor format - * - * Return value: - * pointer to start of (first) descriptor if found else NULL - */ -const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, - int desc_type) -{ - int add_sen_len, add_len, desc_len, k; - const u8 * descp; - - if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7]))) - return NULL; - if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73)) - return NULL; - add_sen_len = (add_sen_len < (sb_len - 8)) ? - add_sen_len : (sb_len - 8); - descp = &sense_buffer[8]; - for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { - descp += desc_len; - add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; - desc_len = add_len + 2; - if (descp[0] == desc_type) - return descp; - if (add_len < 0) // short descriptor ?? - break; - } - return NULL; -} -EXPORT_SYMBOL(scsi_sense_desc_find); - -/** - * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format) - * @sense_buffer: byte array of sense data - * @sb_len: number of valid bytes in sense_buffer - * @info_out: pointer to 64 integer where 8 or 4 byte information - * field will be placed if found. - * - * Return value: - * 1 if information field found, 0 if not found. - */ -int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, - u64 * info_out) -{ - int j; - const u8 * ucp; - u64 ull; - - if (sb_len < 7) - return 0; - switch (sense_buffer[0] & 0x7f) { - case 0x70: - case 0x71: - if (sense_buffer[0] & 0x80) { - *info_out = (sense_buffer[3] << 24) + - (sense_buffer[4] << 16) + - (sense_buffer[5] << 8) + sense_buffer[6]; - return 1; - } else - return 0; - case 0x72: - case 0x73: - ucp = scsi_sense_desc_find(sense_buffer, sb_len, - 0 /* info desc */); - if (ucp && (0xa == ucp[1])) { - ull = 0; - for (j = 0; j < 8; ++j) { - if (j > 0) - ull <<= 8; - ull |= ucp[4 + j]; - } - *info_out = ull; - return 1; - } else - return 0; - default: - return 0; - } -} -EXPORT_SYMBOL(scsi_get_sense_info_fld); - -/** - * scsi_build_sense_buffer - build sense data in a buffer - * @desc: Sense format (non zero == descriptor format, - * 0 == fixed format) - * @buf: Where to build sense data - * @key: Sense key - * @asc: Additional sense code - * @ascq: Additional sense code qualifier - * - **/ -void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) -{ - if (desc) { - buf[0] = 0x72; /* descriptor, current */ - buf[1] = key; - buf[2] = asc; - buf[3] = ascq; - buf[7] = 0; - } else { - buf[0] = 0x70; /* fixed, current */ - buf[2] = key; - buf[7] = 0xa; - buf[12] = asc; - buf[13] = ascq; - } -} -EXPORT_SYMBOL(scsi_build_sense_buffer); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_ioctl.c b/ANDROID_3.4.5/drivers/scsi/scsi_ioctl.c deleted file mode 100644 index d9564fb0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_ioctl.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Changes: - * Arnaldo Carvalho de Melo 08/23/2000 - * - get rid of some verify_areas and use __copy*user and __get/put_user - * for the ones that remain - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi_logging.h" - -#define NORMAL_RETRIES 5 -#define IOCTL_NORMAL_TIMEOUT (10 * HZ) - -#define MAX_BUF PAGE_SIZE - -/** - * ioctl_probe -- return host identification - * @host: host to identify - * @buffer: userspace buffer for identification - * - * Return an identifying string at @buffer, if @buffer is non-NULL, filling - * to the length stored at * (int *) @buffer. - */ -static int ioctl_probe(struct Scsi_Host *host, void __user *buffer) -{ - unsigned int len, slen; - const char *string; - - if (buffer) { - if (get_user(len, (unsigned int __user *) buffer)) - return -EFAULT; - - if (host->hostt->info) - string = host->hostt->info(host); - else - string = host->hostt->name; - if (string) { - slen = strlen(string); - if (len > slen) - len = slen + 1; - if (copy_to_user(buffer, string, len)) - return -EFAULT; - } - } - return 1; -} - -/* - - * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host. - * The IOCTL_NORMAL_TIMEOUT and NORMAL_RETRIES variables are used. - * - * dev is the SCSI device struct ptr, *(int *) arg is the length of the - * input data, if any, not including the command string & counts, - * *((int *)arg + 1) is the output buffer size in bytes. - * - * *(char *) ((int *) arg)[2] the actual command byte. - * - * Note that if more than MAX_BUF bytes are requested to be transferred, - * the ioctl will fail with error EINVAL. - * - * This size *does not* include the initial lengths that were passed. - * - * The SCSI command is read from the memory location immediately after the - * length words, and the input data is right after the command. The SCSI - * routines know the command size based on the opcode decode. - * - * The output area is then filled in starting from the command byte. - */ - -static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, - int timeout, int retries) -{ - int result; - struct scsi_sense_hdr sshdr; - - SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); - - result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, - &sshdr, timeout, retries, NULL); - - SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", result)); - - if ((driver_byte(result) & DRIVER_SENSE) && - (scsi_sense_valid(&sshdr))) { - switch (sshdr.sense_key) { - case ILLEGAL_REQUEST: - if (cmd[0] == ALLOW_MEDIUM_REMOVAL) - sdev->lockable = 0; - else - printk(KERN_INFO "ioctl_internal_command: " - "ILLEGAL REQUEST asc=0x%x ascq=0x%x\n", - sshdr.asc, sshdr.ascq); - break; - case NOT_READY: /* This happens if there is no disc in drive */ - if (sdev->removable) - break; - case UNIT_ATTENTION: - if (sdev->removable) { - sdev->changed = 1; - result = 0; /* This is no longer considered an error */ - break; - } - default: /* Fall through for non-removable media */ - sdev_printk(KERN_INFO, sdev, - "ioctl_internal_command return code = %x\n", - result); - scsi_print_sense_hdr(" ", &sshdr); - break; - } - } - - SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); - return result; -} - -int scsi_set_medium_removal(struct scsi_device *sdev, char state) -{ - char scsi_cmd[MAX_COMMAND_SIZE]; - int ret; - - if (!sdev->removable || !sdev->lockable) - return 0; - - scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; - scsi_cmd[1] = 0; - scsi_cmd[2] = 0; - scsi_cmd[3] = 0; - scsi_cmd[4] = state; - scsi_cmd[5] = 0; - - ret = ioctl_internal_command(sdev, scsi_cmd, - IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES); - if (ret == 0) - sdev->locked = (state == SCSI_REMOVAL_PREVENT); - return ret; -} -EXPORT_SYMBOL(scsi_set_medium_removal); - -/* - * The scsi_ioctl_get_pci() function places into arg the value - * pci_dev::slot_name (8 characters) for the PCI device (if any). - * Returns: 0 on success - * -ENXIO if there isn't a PCI device pointer - * (could be because the SCSI driver hasn't been - * updated yet, or because it isn't a SCSI - * device) - * any copy_to_user() error on failure there - */ -static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg) -{ - struct device *dev = scsi_get_device(sdev->host); - const char *name; - - if (!dev) - return -ENXIO; - - name = dev_name(dev); - - /* compatibility with old ioctl which only returned - * 20 characters */ - return copy_to_user(arg, name, min(strlen(name), (size_t)20)) - ? -EFAULT: 0; -} - - -/** - * scsi_ioctl - Dispatch ioctl to scsi device - * @sdev: scsi device receiving ioctl - * @cmd: which ioctl is it - * @arg: data associated with ioctl - * - * Description: The scsi_ioctl() function differs from most ioctls in that it - * does not take a major/minor number as the dev field. Rather, it takes - * a pointer to a &struct scsi_device. - */ -int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) -{ - char scsi_cmd[MAX_COMMAND_SIZE]; - - /* No idea how this happens.... */ - if (!sdev) - return -ENXIO; - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if (!scsi_block_when_processing_errors(sdev)) - return -ENODEV; - - /* Check for deprecated ioctls ... all the ioctls which don't - * follow the new unique numbering scheme are deprecated */ - switch (cmd) { - case SCSI_IOCTL_SEND_COMMAND: - case SCSI_IOCTL_TEST_UNIT_READY: - case SCSI_IOCTL_BENCHMARK_COMMAND: - case SCSI_IOCTL_SYNC: - case SCSI_IOCTL_START_UNIT: - case SCSI_IOCTL_STOP_UNIT: - printk(KERN_WARNING "program %s is using a deprecated SCSI " - "ioctl, please convert it to SG_IO\n", current->comm); - break; - default: - break; - } - - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - if (!access_ok(VERIFY_WRITE, arg, sizeof(struct scsi_idlun))) - return -EFAULT; - - __put_user((sdev->id & 0xff) - + ((sdev->lun & 0xff) << 8) - + ((sdev->channel & 0xff) << 16) - + ((sdev->host->host_no & 0xff) << 24), - &((struct scsi_idlun __user *)arg)->dev_id); - __put_user(sdev->host->unique_id, - &((struct scsi_idlun __user *)arg)->host_unique_id); - return 0; - case SCSI_IOCTL_GET_BUS_NUMBER: - return put_user(sdev->host->host_no, (int __user *)arg); - case SCSI_IOCTL_PROBE_HOST: - return ioctl_probe(sdev->host, arg); - case SCSI_IOCTL_SEND_COMMAND: - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - return sg_scsi_ioctl(sdev->request_queue, NULL, 0, arg); - case SCSI_IOCTL_DOORLOCK: - return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); - case SCSI_IOCTL_DOORUNLOCK: - return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); - case SCSI_IOCTL_TEST_UNIT_READY: - return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT, - NORMAL_RETRIES, NULL); - case SCSI_IOCTL_START_UNIT: - scsi_cmd[0] = START_STOP; - scsi_cmd[1] = 0; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = 1; - return ioctl_internal_command(sdev, scsi_cmd, - START_STOP_TIMEOUT, NORMAL_RETRIES); - case SCSI_IOCTL_STOP_UNIT: - scsi_cmd[0] = START_STOP; - scsi_cmd[1] = 0; - scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; - scsi_cmd[4] = 0; - return ioctl_internal_command(sdev, scsi_cmd, - START_STOP_TIMEOUT, NORMAL_RETRIES); - case SCSI_IOCTL_GET_PCI: - return scsi_ioctl_get_pci(sdev, arg); - default: - if (sdev->host->hostt->ioctl) - return sdev->host->hostt->ioctl(sdev, cmd, arg); - } - return -EINVAL; -} -EXPORT_SYMBOL(scsi_ioctl); - -/** - * scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET - * @sdev: scsi device receiving ioctl - * @cmd: Must be SC_SCSI_RESET - * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST} - * @ndelay: file mode O_NDELAY flag - */ -int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, - void __user *arg, int ndelay) -{ - int val, result; - - /* The first set of iocts may be executed even if we're doing - * error processing, as long as the device was opened - * non-blocking */ - if (ndelay) { - if (scsi_host_in_recovery(sdev->host)) - return -ENODEV; - } else if (!scsi_block_when_processing_errors(sdev)) - return -ENODEV; - - switch (cmd) { - case SG_SCSI_RESET: - result = get_user(val, (int __user *)arg); - if (result) - return result; - if (val == SG_SCSI_RESET_NOTHING) - return 0; - switch (val) { - case SG_SCSI_RESET_DEVICE: - val = SCSI_TRY_RESET_DEVICE; - break; - case SG_SCSI_RESET_TARGET: - val = SCSI_TRY_RESET_TARGET; - break; - case SG_SCSI_RESET_BUS: - val = SCSI_TRY_RESET_BUS; - break; - case SG_SCSI_RESET_HOST: - val = SCSI_TRY_RESET_HOST; - break; - default: - return -EINVAL; - } - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - return (scsi_reset_provider(sdev, val) == - SUCCESS) ? 0 : -EIO; - } - return -ENODEV; -} -EXPORT_SYMBOL(scsi_nonblockable_ioctl); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_lib.c b/ANDROID_3.4.5/drivers/scsi/scsi_lib.c deleted file mode 100644 index 7ca46131..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_lib.c +++ /dev/null @@ -1,2589 +0,0 @@ -/* - * scsi_lib.c Copyright (C) 1999 Eric Youngdale - * - * SCSI queueing library. - * Initial versions: Eric Youngdale (eric@andante.org). - * Based upon conversations with large numbers - * of people at Linux Expo. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "scsi_priv.h" -#include "scsi_logging.h" - - -#define SG_MEMPOOL_NR ARRAY_SIZE(scsi_sg_pools) -#define SG_MEMPOOL_SIZE 2 - -struct scsi_host_sg_pool { - size_t size; - char *name; - struct kmem_cache *slab; - mempool_t *pool; -}; - -#define SP(x) { x, "sgpool-" __stringify(x) } -#if (SCSI_MAX_SG_SEGMENTS < 32) -#error SCSI_MAX_SG_SEGMENTS is too small (must be 32 or greater) -#endif -static struct scsi_host_sg_pool scsi_sg_pools[] = { - SP(8), - SP(16), -#if (SCSI_MAX_SG_SEGMENTS > 32) - SP(32), -#if (SCSI_MAX_SG_SEGMENTS > 64) - SP(64), -#if (SCSI_MAX_SG_SEGMENTS > 128) - SP(128), -#if (SCSI_MAX_SG_SEGMENTS > 256) -#error SCSI_MAX_SG_SEGMENTS is too large (256 MAX) -#endif -#endif -#endif -#endif - SP(SCSI_MAX_SG_SEGMENTS) -}; -#undef SP - -struct kmem_cache *scsi_sdb_cache; - -/* - * When to reinvoke queueing after a resource shortage. It's 3 msecs to - * not change behaviour from the previous unplug mechanism, experimentation - * may prove this needs changing. - */ -#define SCSI_QUEUE_DELAY 3 - -/* - * Function: scsi_unprep_request() - * - * Purpose: Remove all preparation done for a request, including its - * associated scsi_cmnd, so that it can be requeued. - * - * Arguments: req - request to unprepare - * - * Lock status: Assumed that no locks are held upon entry. - * - * Returns: Nothing. - */ -static void scsi_unprep_request(struct request *req) -{ - struct scsi_cmnd *cmd = req->special; - - blk_unprep_request(req); - req->special = NULL; - - scsi_put_command(cmd); -} - -/** - * __scsi_queue_insert - private queue insertion - * @cmd: The SCSI command being requeued - * @reason: The reason for the requeue - * @unbusy: Whether the queue should be unbusied - * - * This is a private queue insertion. The public interface - * scsi_queue_insert() always assumes the queue should be unbusied - * because it's always called before the completion. This function is - * for a requeue after completion, which should only occur in this - * file. - */ -static int __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, int unbusy) -{ - struct Scsi_Host *host = cmd->device->host; - struct scsi_device *device = cmd->device; - struct scsi_target *starget = scsi_target(device); - struct request_queue *q = device->request_queue; - unsigned long flags; - - SCSI_LOG_MLQUEUE(1, - printk("Inserting command %p into mlqueue\n", cmd)); - - /* - * Set the appropriate busy bit for the device/host. - * - * If the host/device isn't busy, assume that something actually - * completed, and that we should be able to queue a command now. - * - * Note that the prior mid-layer assumption that any host could - * always queue at least one command is now broken. The mid-layer - * will implement a user specifiable stall (see - * scsi_host.max_host_blocked and scsi_device.max_device_blocked) - * if a command is requeued with no other commands outstanding - * either for the device or for the host. - */ - switch (reason) { - case SCSI_MLQUEUE_HOST_BUSY: - host->host_blocked = host->max_host_blocked; - break; - case SCSI_MLQUEUE_DEVICE_BUSY: - case SCSI_MLQUEUE_EH_RETRY: - device->device_blocked = device->max_device_blocked; - break; - case SCSI_MLQUEUE_TARGET_BUSY: - starget->target_blocked = starget->max_target_blocked; - break; - } - - /* - * Decrement the counters, since these commands are no longer - * active on the host/device. - */ - if (unbusy) - scsi_device_unbusy(device); - - /* - * Requeue this command. It will go before all other commands - * that are already in the queue. - */ - spin_lock_irqsave(q->queue_lock, flags); - blk_requeue_request(q, cmd->request); - spin_unlock_irqrestore(q->queue_lock, flags); - - kblockd_schedule_work(q, &device->requeue_work); - - return 0; -} - -/* - * Function: scsi_queue_insert() - * - * Purpose: Insert a command in the midlevel queue. - * - * Arguments: cmd - command that we are adding to queue. - * reason - why we are inserting command to queue. - * - * Lock status: Assumed that lock is not held upon entry. - * - * Returns: Nothing. - * - * Notes: We do this for one of two cases. Either the host is busy - * and it cannot accept any more commands for the time being, - * or the device returned QUEUE_FULL and can accept no more - * commands. - * Notes: This could be called either from an interrupt context or a - * normal process context. - */ -int scsi_queue_insert(struct scsi_cmnd *cmd, int reason) -{ - return __scsi_queue_insert(cmd, reason, 1); -} -/** - * scsi_execute - insert request and wait for the result - * @sdev: scsi device - * @cmd: scsi command - * @data_direction: data direction - * @buffer: data buffer - * @bufflen: len of buffer - * @sense: optional sense buffer - * @timeout: request timeout in seconds - * @retries: number of times to retry request - * @flags: or into request flags; - * @resid: optional residual length - * - * returns the req->errors value which is the scsi_cmnd result - * field. - */ -int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - unsigned char *sense, int timeout, int retries, int flags, - int *resid) -{ - struct request *req; - int write = (data_direction == DMA_TO_DEVICE); - int ret = DRIVER_ERROR << 24; - - req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); - if (!req) - return ret; - - if (bufflen && blk_rq_map_kern(sdev->request_queue, req, - buffer, bufflen, __GFP_WAIT)) - goto out; - - req->cmd_len = COMMAND_SIZE(cmd[0]); - memcpy(req->cmd, cmd, req->cmd_len); - req->sense = sense; - req->sense_len = 0; - req->retries = retries; - req->timeout = timeout; - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT; - - /* - * head injection *required* here otherwise quiesce won't work - */ - blk_execute_rq(req->q, NULL, req, 1); - - /* - * Some devices (USB mass-storage in particular) may transfer - * garbage data together with a residue indicating that the data - * is invalid. Prevent the garbage from being misinterpreted - * and prevent security leaks by zeroing out the excess data. - */ - if (unlikely(req->resid_len > 0 && req->resid_len <= bufflen)) - memset(buffer + (bufflen - req->resid_len), 0, req->resid_len); - - if (resid) - *resid = req->resid_len; - ret = req->errors; - out: - blk_put_request(req); - - return ret; -} -EXPORT_SYMBOL(scsi_execute); - - -int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - struct scsi_sense_hdr *sshdr, int timeout, int retries, - int *resid) -{ - char *sense = NULL; - int result; - - if (sshdr) { - sense = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO); - if (!sense) - return DRIVER_ERROR << 24; - } - result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, - sense, timeout, retries, 0, resid); - if (sshdr) - scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr); - - kfree(sense); - return result; -} -EXPORT_SYMBOL(scsi_execute_req); - -/* - * Function: scsi_init_cmd_errh() - * - * Purpose: Initialize cmd fields related to error handling. - * - * Arguments: cmd - command that is ready to be queued. - * - * Notes: This function has the job of initializing a number of - * fields related to error handling. Typically this will - * be called once for each command, as required. - */ -static void scsi_init_cmd_errh(struct scsi_cmnd *cmd) -{ - cmd->serial_number = 0; - scsi_set_resid(cmd, 0); - memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - if (cmd->cmd_len == 0) - cmd->cmd_len = scsi_command_size(cmd->cmnd); -} - -void scsi_device_unbusy(struct scsi_device *sdev) -{ - struct Scsi_Host *shost = sdev->host; - struct scsi_target *starget = scsi_target(sdev); - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - shost->host_busy--; - starget->target_busy--; - if (unlikely(scsi_host_in_recovery(shost) && - (shost->host_failed || shost->host_eh_scheduled))) - scsi_eh_wakeup(shost); - spin_unlock(shost->host_lock); - spin_lock(sdev->request_queue->queue_lock); - sdev->device_busy--; - spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags); -} - -/* - * Called for single_lun devices on IO completion. Clear starget_sdev_user, - * and call blk_run_queue for all the scsi_devices on the target - - * including current_sdev first. - * - * Called with *no* scsi locks held. - */ -static void scsi_single_lun_run(struct scsi_device *current_sdev) -{ - struct Scsi_Host *shost = current_sdev->host; - struct scsi_device *sdev, *tmp; - struct scsi_target *starget = scsi_target(current_sdev); - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - starget->starget_sdev_user = NULL; - spin_unlock_irqrestore(shost->host_lock, flags); - - /* - * Call blk_run_queue for all LUNs on the target, starting with - * current_sdev. We race with others (to set starget_sdev_user), - * but in most cases, we will be first. Ideally, each LU on the - * target would get some limited time or requests on the target. - */ - blk_run_queue(current_sdev->request_queue); - - spin_lock_irqsave(shost->host_lock, flags); - if (starget->starget_sdev_user) - goto out; - list_for_each_entry_safe(sdev, tmp, &starget->devices, - same_target_siblings) { - if (sdev == current_sdev) - continue; - if (scsi_device_get(sdev)) - continue; - - spin_unlock_irqrestore(shost->host_lock, flags); - blk_run_queue(sdev->request_queue); - spin_lock_irqsave(shost->host_lock, flags); - - scsi_device_put(sdev); - } - out: - spin_unlock_irqrestore(shost->host_lock, flags); -} - -static inline int scsi_device_is_busy(struct scsi_device *sdev) -{ - if (sdev->device_busy >= sdev->queue_depth || sdev->device_blocked) - return 1; - - return 0; -} - -static inline int scsi_target_is_busy(struct scsi_target *starget) -{ - return ((starget->can_queue > 0 && - starget->target_busy >= starget->can_queue) || - starget->target_blocked); -} - -static inline int scsi_host_is_busy(struct Scsi_Host *shost) -{ - if ((shost->can_queue > 0 && shost->host_busy >= shost->can_queue) || - shost->host_blocked || shost->host_self_blocked) - return 1; - - return 0; -} - -/* - * Function: scsi_run_queue() - * - * Purpose: Select a proper request queue to serve next - * - * Arguments: q - last request's queue - * - * Returns: Nothing - * - * Notes: The previous command was completely finished, start - * a new one if possible. - */ -static void scsi_run_queue(struct request_queue *q) -{ - struct scsi_device *sdev = q->queuedata; - struct Scsi_Host *shost; - LIST_HEAD(starved_list); - unsigned long flags; - - /* if the device is dead, sdev will be NULL, so no queue to run */ - if (!sdev) - return; - - shost = sdev->host; - if (scsi_target(sdev)->single_lun) - scsi_single_lun_run(sdev); - - spin_lock_irqsave(shost->host_lock, flags); - list_splice_init(&shost->starved_list, &starved_list); - - while (!list_empty(&starved_list)) { - /* - * As long as shost is accepting commands and we have - * starved queues, call blk_run_queue. scsi_request_fn - * drops the queue_lock and can add us back to the - * starved_list. - * - * host_lock protects the starved_list and starved_entry. - * scsi_request_fn must get the host_lock before checking - * or modifying starved_list or starved_entry. - */ - if (scsi_host_is_busy(shost)) - break; - - sdev = list_entry(starved_list.next, - struct scsi_device, starved_entry); - list_del_init(&sdev->starved_entry); - if (scsi_target_is_busy(scsi_target(sdev))) { - list_move_tail(&sdev->starved_entry, - &shost->starved_list); - continue; - } - - spin_unlock(shost->host_lock); - spin_lock(sdev->request_queue->queue_lock); - __blk_run_queue(sdev->request_queue); - spin_unlock(sdev->request_queue->queue_lock); - spin_lock(shost->host_lock); - } - /* put any unprocessed entries back */ - list_splice(&starved_list, &shost->starved_list); - spin_unlock_irqrestore(shost->host_lock, flags); - - blk_run_queue(q); -} - -void scsi_requeue_run_queue(struct work_struct *work) -{ - struct scsi_device *sdev; - struct request_queue *q; - - sdev = container_of(work, struct scsi_device, requeue_work); - q = sdev->request_queue; - scsi_run_queue(q); -} - -/* - * Function: scsi_requeue_command() - * - * Purpose: Handle post-processing of completed commands. - * - * Arguments: q - queue to operate on - * cmd - command that may need to be requeued. - * - * Returns: Nothing - * - * Notes: After command completion, there may be blocks left - * over which weren't finished by the previous command - * this can be for a number of reasons - the main one is - * I/O errors in the middle of the request, in which case - * we need to request the blocks that come after the bad - * sector. - * Notes: Upon return, cmd is a stale pointer. - */ -static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd) -{ - struct request *req = cmd->request; - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - scsi_unprep_request(req); - blk_requeue_request(q, req); - spin_unlock_irqrestore(q->queue_lock, flags); - - scsi_run_queue(q); -} - -void scsi_next_command(struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct request_queue *q = sdev->request_queue; - - /* need to hold a reference on the device before we let go of the cmd */ - get_device(&sdev->sdev_gendev); - - scsi_put_command(cmd); - scsi_run_queue(q); - - /* ok to remove device now */ - put_device(&sdev->sdev_gendev); -} - -void scsi_run_host_queues(struct Scsi_Host *shost) -{ - struct scsi_device *sdev; - - shost_for_each_device(sdev, shost) - scsi_run_queue(sdev->request_queue); -} - -static void __scsi_release_buffers(struct scsi_cmnd *, int); - -/* - * Function: scsi_end_request() - * - * Purpose: Post-processing of completed commands (usually invoked at end - * of upper level post-processing and scsi_io_completion). - * - * Arguments: cmd - command that is complete. - * error - 0 if I/O indicates success, < 0 for I/O error. - * bytes - number of bytes of completed I/O - * requeue - indicates whether we should requeue leftovers. - * - * Lock status: Assumed that lock is not held upon entry. - * - * Returns: cmd if requeue required, NULL otherwise. - * - * Notes: This is called for block device requests in order to - * mark some number of sectors as complete. - * - * We are guaranteeing that the request queue will be goosed - * at some point during this call. - * Notes: If cmd was requeued, upon return it will be a stale pointer. - */ -static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int error, - int bytes, int requeue) -{ - struct request_queue *q = cmd->device->request_queue; - struct request *req = cmd->request; - - /* - * If there are blocks left over at the end, set up the command - * to queue the remainder of them. - */ - if (blk_end_request(req, error, bytes)) { - /* kill remainder if no retrys */ - if (error && scsi_noretry_cmd(cmd)) - blk_end_request_all(req, error); - else { - if (requeue) { - /* - * Bleah. Leftovers again. Stick the - * leftovers in the front of the - * queue, and goose the queue again. - */ - scsi_release_buffers(cmd); - scsi_requeue_command(q, cmd); - cmd = NULL; - } - return cmd; - } - } - - /* - * This will goose the queue request function at the end, so we don't - * need to worry about launching another command. - */ - __scsi_release_buffers(cmd, 0); - scsi_next_command(cmd); - return NULL; -} - -static inline unsigned int scsi_sgtable_index(unsigned short nents) -{ - unsigned int index; - - BUG_ON(nents > SCSI_MAX_SG_SEGMENTS); - - if (nents <= 8) - index = 0; - else - index = get_count_order(nents) - 3; - - return index; -} - -static void scsi_sg_free(struct scatterlist *sgl, unsigned int nents) -{ - struct scsi_host_sg_pool *sgp; - - sgp = scsi_sg_pools + scsi_sgtable_index(nents); - mempool_free(sgl, sgp->pool); -} - -static struct scatterlist *scsi_sg_alloc(unsigned int nents, gfp_t gfp_mask) -{ - struct scsi_host_sg_pool *sgp; - - sgp = scsi_sg_pools + scsi_sgtable_index(nents); - return mempool_alloc(sgp->pool, gfp_mask); -} - -static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents, - gfp_t gfp_mask) -{ - int ret; - - BUG_ON(!nents); - - ret = __sg_alloc_table(&sdb->table, nents, SCSI_MAX_SG_SEGMENTS, - gfp_mask, scsi_sg_alloc); - if (unlikely(ret)) - __sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, - scsi_sg_free); - - return ret; -} - -static void scsi_free_sgtable(struct scsi_data_buffer *sdb) -{ - __sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, scsi_sg_free); -} - -static void __scsi_release_buffers(struct scsi_cmnd *cmd, int do_bidi_check) -{ - - if (cmd->sdb.table.nents) - scsi_free_sgtable(&cmd->sdb); - - memset(&cmd->sdb, 0, sizeof(cmd->sdb)); - - if (do_bidi_check && scsi_bidi_cmnd(cmd)) { - struct scsi_data_buffer *bidi_sdb = - cmd->request->next_rq->special; - scsi_free_sgtable(bidi_sdb); - kmem_cache_free(scsi_sdb_cache, bidi_sdb); - cmd->request->next_rq->special = NULL; - } - - if (scsi_prot_sg_count(cmd)) - scsi_free_sgtable(cmd->prot_sdb); -} - -/* - * Function: scsi_release_buffers() - * - * Purpose: Completion processing for block device I/O requests. - * - * Arguments: cmd - command that we are bailing. - * - * Lock status: Assumed that no lock is held upon entry. - * - * Returns: Nothing - * - * Notes: In the event that an upper level driver rejects a - * command, we must release resources allocated during - * the __init_io() function. Primarily this would involve - * the scatter-gather table, and potentially any bounce - * buffers. - */ -void scsi_release_buffers(struct scsi_cmnd *cmd) -{ - __scsi_release_buffers(cmd, 1); -} -EXPORT_SYMBOL(scsi_release_buffers); - -static int __scsi_error_from_host_byte(struct scsi_cmnd *cmd, int result) -{ - int error = 0; - - switch(host_byte(result)) { - case DID_TRANSPORT_FAILFAST: - error = -ENOLINK; - break; - case DID_TARGET_FAILURE: - set_host_byte(cmd, DID_OK); - error = -EREMOTEIO; - break; - case DID_NEXUS_FAILURE: - set_host_byte(cmd, DID_OK); - error = -EBADE; - break; - default: - error = -EIO; - break; - } - - return error; -} - -/* - * Function: scsi_io_completion() - * - * Purpose: Completion processing for block device I/O requests. - * - * Arguments: cmd - command that is finished. - * - * Lock status: Assumed that no lock is held upon entry. - * - * Returns: Nothing - * - * Notes: This function is matched in terms of capabilities to - * the function that created the scatter-gather list. - * In other words, if there are no bounce buffers - * (the normal case for most drivers), we don't need - * the logic to deal with cleaning up afterwards. - * - * We must call scsi_end_request(). This will finish off - * the specified number of sectors. If we are done, the - * command block will be released and the queue function - * will be goosed. If we are not done then we have to - * figure out what to do next: - * - * a) We can call scsi_requeue_command(). The request - * will be unprepared and put back on the queue. Then - * a new command will be created for it. This should - * be used if we made forward progress, or if we want - * to switch from READ(10) to READ(6) for example. - * - * b) We can call scsi_queue_insert(). The request will - * be put back on the queue and retried using the same - * command as before, possibly after a delay. - * - * c) We can call blk_end_request() with -EIO to fail - * the remainder of the request. - */ -void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes) -{ - int result = cmd->result; - struct request_queue *q = cmd->device->request_queue; - struct request *req = cmd->request; - int error = 0; - struct scsi_sense_hdr sshdr; - int sense_valid = 0; - int sense_deferred = 0; - enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY, - ACTION_DELAYED_RETRY} action; - char *description = NULL; - - if (result) { - sense_valid = scsi_command_normalize_sense(cmd, &sshdr); - if (sense_valid) - sense_deferred = scsi_sense_is_deferred(&sshdr); - } - - if (req->cmd_type == REQ_TYPE_BLOCK_PC) { /* SG_IO ioctl from block level */ - req->errors = result; - if (result) { - if (sense_valid && req->sense) { - /* - * SG_IO wants current and deferred errors - */ - int len = 8 + cmd->sense_buffer[7]; - - if (len > SCSI_SENSE_BUFFERSIZE) - len = SCSI_SENSE_BUFFERSIZE; - memcpy(req->sense, cmd->sense_buffer, len); - req->sense_len = len; - } - if (!sense_deferred) - error = __scsi_error_from_host_byte(cmd, result); - } - - req->resid_len = scsi_get_resid(cmd); - - if (scsi_bidi_cmnd(cmd)) { - /* - * Bidi commands Must be complete as a whole, - * both sides at once. - */ - req->next_rq->resid_len = scsi_in(cmd)->resid; - - scsi_release_buffers(cmd); - blk_end_request_all(req, 0); - - scsi_next_command(cmd); - return; - } - } - - /* no bidi support for !REQ_TYPE_BLOCK_PC yet */ - BUG_ON(blk_bidi_rq(req)); - - /* - * Next deal with any sectors which we were able to correctly - * handle. - */ - SCSI_LOG_HLCOMPLETE(1, printk("%u sectors total, " - "%d bytes done.\n", - blk_rq_sectors(req), good_bytes)); - - /* - * Recovered errors need reporting, but they're always treated - * as success, so fiddle the result code here. For BLOCK_PC - * we already took a copy of the original into rq->errors which - * is what gets returned to the user - */ - if (sense_valid && (sshdr.sense_key == RECOVERED_ERROR)) { - /* if ATA PASS-THROUGH INFORMATION AVAILABLE skip - * print since caller wants ATA registers. Only occurs on - * SCSI ATA PASS_THROUGH commands when CK_COND=1 - */ - if ((sshdr.asc == 0x0) && (sshdr.ascq == 0x1d)) - ; - else if (!(req->cmd_flags & REQ_QUIET)) - scsi_print_sense("", cmd); - result = 0; - /* BLOCK_PC may have set error */ - error = 0; - } - - /* - * A number of bytes were successfully read. If there - * are leftovers and there is some kind of error - * (result != 0), retry the rest. - */ - if (scsi_end_request(cmd, error, good_bytes, result == 0) == NULL) - return; - - error = __scsi_error_from_host_byte(cmd, result); - - if (host_byte(result) == DID_RESET) { - /* Third party bus reset or reset for error recovery - * reasons. Just retry the command and see what - * happens. - */ - action = ACTION_RETRY; - } else if (sense_valid && !sense_deferred) { - switch (sshdr.sense_key) { - case UNIT_ATTENTION: - if (cmd->device->removable) { - /* Detected disc change. Set a bit - * and quietly refuse further access. - */ - cmd->device->changed = 1; - description = "Media Changed"; - action = ACTION_FAIL; - } else { - /* Must have been a power glitch, or a - * bus reset. Could not have been a - * media change, so we just retry the - * command and see what happens. - */ - action = ACTION_RETRY; - } - break; - case ILLEGAL_REQUEST: - /* If we had an ILLEGAL REQUEST returned, then - * we may have performed an unsupported - * command. The only thing this should be - * would be a ten byte read where only a six - * byte read was supported. Also, on a system - * where READ CAPACITY failed, we may have - * read past the end of the disk. - */ - if ((cmd->device->use_10_for_rw && - sshdr.asc == 0x20 && sshdr.ascq == 0x00) && - (cmd->cmnd[0] == READ_10 || - cmd->cmnd[0] == WRITE_10)) { - /* This will issue a new 6-byte command. */ - cmd->device->use_10_for_rw = 0; - action = ACTION_REPREP; - } else if (sshdr.asc == 0x10) /* DIX */ { - description = "Host Data Integrity Failure"; - action = ACTION_FAIL; - error = -EILSEQ; - /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - } else if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && - (cmd->cmnd[0] == UNMAP || - cmd->cmnd[0] == WRITE_SAME_16 || - cmd->cmnd[0] == WRITE_SAME)) { - description = "Discard failure"; - action = ACTION_FAIL; - error = -EREMOTEIO; - } else - action = ACTION_FAIL; - break; - case ABORTED_COMMAND: - action = ACTION_FAIL; - if (sshdr.asc == 0x10) { /* DIF */ - description = "Target Data Integrity Failure"; - error = -EILSEQ; - } - break; - case NOT_READY: - /* If the device is in the process of becoming - * ready, or has a temporary blockage, retry. - */ - if (sshdr.asc == 0x04) { - switch (sshdr.ascq) { - case 0x01: /* becoming ready */ - case 0x04: /* format in progress */ - case 0x05: /* rebuild in progress */ - case 0x06: /* recalculation in progress */ - case 0x07: /* operation in progress */ - case 0x08: /* Long write in progress */ - case 0x09: /* self test in progress */ - case 0x14: /* space allocation in progress */ - action = ACTION_DELAYED_RETRY; - break; - default: - description = "Device not ready"; - action = ACTION_FAIL; - break; - } - } else { - description = "Device not ready"; - action = ACTION_FAIL; - } - break; - case VOLUME_OVERFLOW: - /* See SSC3rXX or current. */ - action = ACTION_FAIL; - break; - default: - description = "Unhandled sense code"; - action = ACTION_FAIL; - break; - } - } else { - description = "Unhandled error code"; - action = ACTION_FAIL; - } - - switch (action) { - case ACTION_FAIL: - /* Give up and fail the remainder of the request */ - scsi_release_buffers(cmd); - if (!(req->cmd_flags & REQ_QUIET)) { - if (description) - scmd_printk(KERN_INFO, cmd, "%s\n", - description); - scsi_print_result(cmd); - if (driver_byte(result) & DRIVER_SENSE) - scsi_print_sense("", cmd); - scsi_print_command(cmd); - } - if (blk_end_request_err(req, error)) - scsi_requeue_command(q, cmd); - else - scsi_next_command(cmd); - break; - case ACTION_REPREP: - /* Unprep the request and put it back at the head of the queue. - * A new command will be prepared and issued. - */ - scsi_release_buffers(cmd); - scsi_requeue_command(q, cmd); - break; - case ACTION_RETRY: - /* Retry the same command immediately */ - __scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY, 0); - break; - case ACTION_DELAYED_RETRY: - /* Retry the same command after a delay */ - __scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY, 0); - break; - } -} - -static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb, - gfp_t gfp_mask) -{ - int count; - - /* - * If sg table allocation fails, requeue request later. - */ - if (unlikely(scsi_alloc_sgtable(sdb, req->nr_phys_segments, - gfp_mask))) { - return BLKPREP_DEFER; - } - - req->buffer = NULL; - - /* - * Next, walk the list, and fill in the addresses and sizes of - * each segment. - */ - count = blk_rq_map_sg(req->q, req, sdb->table.sgl); - BUG_ON(count > sdb->table.nents); - sdb->table.nents = count; - sdb->length = blk_rq_bytes(req); - return BLKPREP_OK; -} - -/* - * Function: scsi_init_io() - * - * Purpose: SCSI I/O initialize function. - * - * Arguments: cmd - Command descriptor we wish to initialize - * - * Returns: 0 on success - * BLKPREP_DEFER if the failure is retryable - * BLKPREP_KILL if the failure is fatal - */ -int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask) -{ - struct request *rq = cmd->request; - - int error = scsi_init_sgtable(rq, &cmd->sdb, gfp_mask); - if (error) - goto err_exit; - - if (blk_bidi_rq(rq)) { - struct scsi_data_buffer *bidi_sdb = kmem_cache_zalloc( - scsi_sdb_cache, GFP_ATOMIC); - if (!bidi_sdb) { - error = BLKPREP_DEFER; - goto err_exit; - } - - rq->next_rq->special = bidi_sdb; - error = scsi_init_sgtable(rq->next_rq, bidi_sdb, GFP_ATOMIC); - if (error) - goto err_exit; - } - - if (blk_integrity_rq(rq)) { - struct scsi_data_buffer *prot_sdb = cmd->prot_sdb; - int ivecs, count; - - BUG_ON(prot_sdb == NULL); - ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio); - - if (scsi_alloc_sgtable(prot_sdb, ivecs, gfp_mask)) { - error = BLKPREP_DEFER; - goto err_exit; - } - - count = blk_rq_map_integrity_sg(rq->q, rq->bio, - prot_sdb->table.sgl); - BUG_ON(unlikely(count > ivecs)); - BUG_ON(unlikely(count > queue_max_integrity_segments(rq->q))); - - cmd->prot_sdb = prot_sdb; - cmd->prot_sdb->table.nents = count; - } - - return BLKPREP_OK ; - -err_exit: - scsi_release_buffers(cmd); - cmd->request->special = NULL; - scsi_put_command(cmd); - return error; -} -EXPORT_SYMBOL(scsi_init_io); - -static struct scsi_cmnd *scsi_get_cmd_from_req(struct scsi_device *sdev, - struct request *req) -{ - struct scsi_cmnd *cmd; - - if (!req->special) { - cmd = scsi_get_command(sdev, GFP_ATOMIC); - if (unlikely(!cmd)) - return NULL; - req->special = cmd; - } else { - cmd = req->special; - } - - /* pull a tag out of the request if we have one */ - cmd->tag = req->tag; - cmd->request = req; - - cmd->cmnd = req->cmd; - cmd->prot_op = SCSI_PROT_NORMAL; - - return cmd; -} - -int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req) -{ - struct scsi_cmnd *cmd; - int ret = scsi_prep_state_check(sdev, req); - - if (ret != BLKPREP_OK) - return ret; - - cmd = scsi_get_cmd_from_req(sdev, req); - if (unlikely(!cmd)) - return BLKPREP_DEFER; - - /* - * BLOCK_PC requests may transfer data, in which case they must - * a bio attached to them. Or they might contain a SCSI command - * that does not transfer data, in which case they may optionally - * submit a request without an attached bio. - */ - if (req->bio) { - int ret; - - BUG_ON(!req->nr_phys_segments); - - ret = scsi_init_io(cmd, GFP_ATOMIC); - if (unlikely(ret)) - return ret; - } else { - BUG_ON(blk_rq_bytes(req)); - - memset(&cmd->sdb, 0, sizeof(cmd->sdb)); - req->buffer = NULL; - } - - cmd->cmd_len = req->cmd_len; - if (!blk_rq_bytes(req)) - cmd->sc_data_direction = DMA_NONE; - else if (rq_data_dir(req) == WRITE) - cmd->sc_data_direction = DMA_TO_DEVICE; - else - cmd->sc_data_direction = DMA_FROM_DEVICE; - - cmd->transfersize = blk_rq_bytes(req); - cmd->allowed = req->retries; - return BLKPREP_OK; -} -EXPORT_SYMBOL(scsi_setup_blk_pc_cmnd); - -/* - * Setup a REQ_TYPE_FS command. These are simple read/write request - * from filesystems that still need to be translated to SCSI CDBs from - * the ULD. - */ -int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) -{ - struct scsi_cmnd *cmd; - int ret = scsi_prep_state_check(sdev, req); - - if (ret != BLKPREP_OK) - return ret; - - if (unlikely(sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh - && sdev->scsi_dh_data->scsi_dh->prep_fn)) { - ret = sdev->scsi_dh_data->scsi_dh->prep_fn(sdev, req); - if (ret != BLKPREP_OK) - return ret; - } - - /* - * Filesystem requests must transfer data. - */ - BUG_ON(!req->nr_phys_segments); - - cmd = scsi_get_cmd_from_req(sdev, req); - if (unlikely(!cmd)) - return BLKPREP_DEFER; - - memset(cmd->cmnd, 0, BLK_MAX_CDB); - return scsi_init_io(cmd, GFP_ATOMIC); -} -EXPORT_SYMBOL(scsi_setup_fs_cmnd); - -int scsi_prep_state_check(struct scsi_device *sdev, struct request *req) -{ - int ret = BLKPREP_OK; - if(sdev==NULL){ - ret = BLKPREP_KILL; - return ret; - } - /* - * If the device is not in running state we will reject some - * or all commands. - */ - if (unlikely(sdev->sdev_state != SDEV_RUNNING)) { - switch (sdev->sdev_state) { - case SDEV_OFFLINE: - /* - * If the device is offline we refuse to process any - * commands. The device must be brought online - * before trying any recovery commands. - */ - sdev_printk(KERN_ERR, sdev, - "rejecting I/O to offline device\n"); - ret = BLKPREP_KILL; - break; - case SDEV_DEL: - /* - * If the device is fully deleted, we refuse to - * process any commands as well. - */ - sdev_printk(KERN_ERR, sdev, - "rejecting I/O to dead device\n"); - ret = BLKPREP_KILL; - break; - case SDEV_QUIESCE: - case SDEV_BLOCK: - case SDEV_CREATED_BLOCK: - /* - * If the devices is blocked we defer normal commands. - */ - if (!(req->cmd_flags & REQ_PREEMPT)) - ret = BLKPREP_DEFER; - break; - default: - /* - * For any other not fully online state we only allow - * special commands. In particular any user initiated - * command is not allowed. - */ - if (!(req->cmd_flags & REQ_PREEMPT)) - ret = BLKPREP_KILL; - break; - } - } - return ret; -} -EXPORT_SYMBOL(scsi_prep_state_check); - -int scsi_prep_return(struct request_queue *q, struct request *req, int ret) -{ - struct scsi_device *sdev = q->queuedata; - - switch (ret) { - case BLKPREP_KILL: - req->errors = DID_NO_CONNECT << 16; - /* release the command and kill it */ - if (req->special) { - struct scsi_cmnd *cmd = req->special; - scsi_release_buffers(cmd); - scsi_put_command(cmd); - req->special = NULL; - } - break; - case BLKPREP_DEFER: - /* - * If we defer, the blk_peek_request() returns NULL, but the - * queue must be restarted, so we schedule a callback to happen - * shortly. - */ - if (sdev->device_busy == 0) - blk_delay_queue(q, SCSI_QUEUE_DELAY); - break; - default: - req->cmd_flags |= REQ_DONTPREP; - } - - return ret; -} -EXPORT_SYMBOL(scsi_prep_return); - -int scsi_prep_fn(struct request_queue *q, struct request *req) -{ - struct scsi_device *sdev = q->queuedata; - int ret = BLKPREP_KILL; - - if (req->cmd_type == REQ_TYPE_BLOCK_PC) - ret = scsi_setup_blk_pc_cmnd(sdev, req); - return scsi_prep_return(q, req, ret); -} -EXPORT_SYMBOL(scsi_prep_fn); - -/* - * scsi_dev_queue_ready: if we can send requests to sdev, return 1 else - * return 0. - * - * Called with the queue_lock held. - */ -static inline int scsi_dev_queue_ready(struct request_queue *q, - struct scsi_device *sdev) -{ - if (sdev->device_busy == 0 && sdev->device_blocked) { - /* - * unblock after device_blocked iterates to zero - */ - if (--sdev->device_blocked == 0) { - SCSI_LOG_MLQUEUE(3, - sdev_printk(KERN_INFO, sdev, - "unblocking device at zero depth\n")); - } else { - blk_delay_queue(q, SCSI_QUEUE_DELAY); - return 0; - } - } - if (scsi_device_is_busy(sdev)) - return 0; - - return 1; -} - - -/* - * scsi_target_queue_ready: checks if there we can send commands to target - * @sdev: scsi device on starget to check. - * - * Called with the host lock held. - */ -static inline int scsi_target_queue_ready(struct Scsi_Host *shost, - struct scsi_device *sdev) -{ - struct scsi_target *starget = scsi_target(sdev); - - if (starget->single_lun) { - if (starget->starget_sdev_user && - starget->starget_sdev_user != sdev) - return 0; - starget->starget_sdev_user = sdev; - } - - if (starget->target_busy == 0 && starget->target_blocked) { - /* - * unblock after target_blocked iterates to zero - */ - if (--starget->target_blocked == 0) { - SCSI_LOG_MLQUEUE(3, starget_printk(KERN_INFO, starget, - "unblocking target at zero depth\n")); - } else - return 0; - } - - if (scsi_target_is_busy(starget)) { - list_move_tail(&sdev->starved_entry, &shost->starved_list); - return 0; - } - - return 1; -} - -/* - * scsi_host_queue_ready: if we can send requests to shost, return 1 else - * return 0. We must end up running the queue again whenever 0 is - * returned, else IO can hang. - * - * Called with host_lock held. - */ -static inline int scsi_host_queue_ready(struct request_queue *q, - struct Scsi_Host *shost, - struct scsi_device *sdev) -{ - if (scsi_host_in_recovery(shost)) - return 0; - if (shost->host_busy == 0 && shost->host_blocked) { - /* - * unblock after host_blocked iterates to zero - */ - if (--shost->host_blocked == 0) { - SCSI_LOG_MLQUEUE(3, - printk("scsi%d unblocking host at zero depth\n", - shost->host_no)); - } else { - return 0; - } - } - if (scsi_host_is_busy(shost)) { - if (list_empty(&sdev->starved_entry)) - list_add_tail(&sdev->starved_entry, &shost->starved_list); - return 0; - } - - /* We're OK to process the command, so we can't be starved */ - if (!list_empty(&sdev->starved_entry)) - list_del_init(&sdev->starved_entry); - - return 1; -} - -/* - * Busy state exporting function for request stacking drivers. - * - * For efficiency, no lock is taken to check the busy state of - * shost/starget/sdev, since the returned value is not guaranteed and - * may be changed after request stacking drivers call the function, - * regardless of taking lock or not. - * - * When scsi can't dispatch I/Os anymore and needs to kill I/Os - * (e.g. !sdev), scsi needs to return 'not busy'. - * Otherwise, request stacking drivers may hold requests forever. - */ -static int scsi_lld_busy(struct request_queue *q) -{ - struct scsi_device *sdev = q->queuedata; - struct Scsi_Host *shost; - - if (!sdev) - return 0; - - shost = sdev->host; - - /* - * Ignore host/starget busy state. - * Since block layer does not have a concept of fairness across - * multiple queues, congestion of host/starget needs to be handled - * in SCSI layer. - */ - if (scsi_host_in_recovery(shost) || scsi_device_is_busy(sdev)) - return 1; - - return 0; -} - -/* - * Kill a request for a dead device - */ -static void scsi_kill_request(struct request *req, struct request_queue *q) -{ - struct scsi_cmnd *cmd = req->special; - struct scsi_device *sdev; - struct scsi_target *starget; - struct Scsi_Host *shost; - - blk_start_request(req); - - scmd_printk(KERN_INFO, cmd, "killing request\n"); - - sdev = cmd->device; - starget = scsi_target(sdev); - shost = sdev->host; - scsi_init_cmd_errh(cmd); - cmd->result = DID_NO_CONNECT << 16; - atomic_inc(&cmd->device->iorequest_cnt); - - /* - * SCSI request completion path will do scsi_device_unbusy(), - * bump busy counts. To bump the counters, we need to dance - * with the locks as normal issue path does. - */ - sdev->device_busy++; - spin_unlock(sdev->request_queue->queue_lock); - spin_lock(shost->host_lock); - shost->host_busy++; - starget->target_busy++; - spin_unlock(shost->host_lock); - spin_lock(sdev->request_queue->queue_lock); - - blk_complete_request(req); -} - -static void scsi_softirq_done(struct request *rq) -{ - struct scsi_cmnd *cmd = rq->special; - unsigned long wait_for = (cmd->allowed + 1) * rq->timeout; - int disposition; - - INIT_LIST_HEAD(&cmd->eh_entry); - - atomic_inc(&cmd->device->iodone_cnt); - if (cmd->result) - atomic_inc(&cmd->device->ioerr_cnt); - - disposition = scsi_decide_disposition(cmd); - if (disposition != SUCCESS && - time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { - sdev_printk(KERN_ERR, cmd->device, - "timing out command, waited %lus\n", - wait_for/HZ); - disposition = SUCCESS; - } - - scsi_log_completion(cmd, disposition); - - switch (disposition) { - case SUCCESS: - scsi_finish_command(cmd); - break; - case NEEDS_RETRY: - scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY); - break; - case ADD_TO_MLQUEUE: - scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY); - break; - default: - if (!scsi_eh_scmd_add(cmd, 0)) - scsi_finish_command(cmd); - } -} - -/* - * Function: scsi_request_fn() - * - * Purpose: Main strategy routine for SCSI. - * - * Arguments: q - Pointer to actual queue. - * - * Returns: Nothing - * - * Lock status: IO request lock assumed to be held when called. - */ -static void scsi_request_fn(struct request_queue *q) -{ - struct scsi_device *sdev = q->queuedata; - struct Scsi_Host *shost; - struct scsi_cmnd *cmd; - struct request *req; - - if (!sdev) { - while ((req = blk_peek_request(q)) != NULL) - scsi_kill_request(req, q); - return; - } - - if(!get_device(&sdev->sdev_gendev)) - /* We must be tearing the block queue down already */ - return; - - /* - * To start with, we keep looping until the queue is empty, or until - * the host is no longer able to accept any more requests. - */ - shost = sdev->host; - for (;;) { - int rtn; - /* - * get next queueable request. We do this early to make sure - * that the request is fully prepared even if we cannot - * accept it. - */ - req = blk_peek_request(q); - if (!req || !scsi_dev_queue_ready(q, sdev)) - break; - - if (unlikely(!scsi_device_online(sdev))) { - sdev_printk(KERN_ERR, sdev, - "rejecting I/O to offline device\n"); - scsi_kill_request(req, q); - continue; - } - - - /* - * Remove the request from the request list. - */ - if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req))) - blk_start_request(req); - sdev->device_busy++; - - spin_unlock(q->queue_lock); - cmd = req->special; - if (unlikely(cmd == NULL)) { - printk(KERN_CRIT "impossible request in %s.\n" - "please mail a stack trace to " - "linux-scsi@vger.kernel.org\n", - __func__); - blk_dump_rq_flags(req, "foo"); - BUG(); - } - spin_lock(shost->host_lock); - - /* - * We hit this when the driver is using a host wide - * tag map. For device level tag maps the queue_depth check - * in the device ready fn would prevent us from trying - * to allocate a tag. Since the map is a shared host resource - * we add the dev to the starved list so it eventually gets - * a run when a tag is freed. - */ - if (blk_queue_tagged(q) && !blk_rq_tagged(req)) { - if (list_empty(&sdev->starved_entry)) - list_add_tail(&sdev->starved_entry, - &shost->starved_list); - goto not_ready; - } - - if (!scsi_target_queue_ready(shost, sdev)) - goto not_ready; - - if (!scsi_host_queue_ready(q, shost, sdev)) - goto not_ready; - - scsi_target(sdev)->target_busy++; - shost->host_busy++; - - /* - * XXX(hch): This is rather suboptimal, scsi_dispatch_cmd will - * take the lock again. - */ - spin_unlock_irq(shost->host_lock); - - /* - * Finally, initialize any error handling parameters, and set up - * the timers for timeouts. - */ - scsi_init_cmd_errh(cmd); - - /* - * Dispatch the command to the low-level driver. - */ - rtn = scsi_dispatch_cmd(cmd); - spin_lock_irq(q->queue_lock); - if (rtn) - goto out_delay; - } - - goto out; - - not_ready: - spin_unlock_irq(shost->host_lock); - - /* - * lock q, handle tag, requeue req, and decrement device_busy. We - * must return with queue_lock held. - * - * Decrementing device_busy without checking it is OK, as all such - * cases (host limits or settings) should run the queue at some - * later time. - */ - spin_lock_irq(q->queue_lock); - blk_requeue_request(q, req); - sdev->device_busy--; -out_delay: - if (sdev->device_busy == 0) - blk_delay_queue(q, SCSI_QUEUE_DELAY); -out: - /* must be careful here...if we trigger the ->remove() function - * we cannot be holding the q lock */ - spin_unlock_irq(q->queue_lock); - put_device(&sdev->sdev_gendev); - spin_lock_irq(q->queue_lock); -} - -u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) -{ - struct device *host_dev; - u64 bounce_limit = 0xffffffff; - - if (shost->unchecked_isa_dma) - return BLK_BOUNCE_ISA; - /* - * Platforms with virtual-DMA translation - * hardware have no practical limit. - */ - if (!PCI_DMA_BUS_IS_PHYS) - return BLK_BOUNCE_ANY; - - host_dev = scsi_get_device(shost); - if (host_dev && host_dev->dma_mask) - bounce_limit = *host_dev->dma_mask; - - return bounce_limit; -} -EXPORT_SYMBOL(scsi_calculate_bounce_limit); - -struct request_queue *__scsi_alloc_queue(struct Scsi_Host *shost, - request_fn_proc *request_fn) -{ - struct request_queue *q; - struct device *dev = shost->dma_dev; - - q = blk_init_queue(request_fn, NULL); - if (!q) - return NULL; - - /* - * this limit is imposed by hardware restrictions - */ - blk_queue_max_segments(q, min_t(unsigned short, shost->sg_tablesize, - SCSI_MAX_SG_CHAIN_SEGMENTS)); - - if (scsi_host_prot_dma(shost)) { - shost->sg_prot_tablesize = - min_not_zero(shost->sg_prot_tablesize, - (unsigned short)SCSI_MAX_PROT_SG_SEGMENTS); - BUG_ON(shost->sg_prot_tablesize < shost->sg_tablesize); - blk_queue_max_integrity_segments(q, shost->sg_prot_tablesize); - } - - blk_queue_max_hw_sectors(q, shost->max_sectors); - blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost)); - blk_queue_segment_boundary(q, shost->dma_boundary); - dma_set_seg_boundary(dev, shost->dma_boundary); - - blk_queue_max_segment_size(q, dma_get_max_seg_size(dev)); - - if (!shost->use_clustering) - q->limits.cluster = 0; - - /* - * set a reasonable default alignment on word boundaries: the - * host and device may alter it using - * blk_queue_update_dma_alignment() later. - */ - blk_queue_dma_alignment(q, 0x03); - - return q; -} -EXPORT_SYMBOL(__scsi_alloc_queue); - -struct request_queue *scsi_alloc_queue(struct scsi_device *sdev) -{ - struct request_queue *q; - - q = __scsi_alloc_queue(sdev->host, scsi_request_fn); - if (!q) - return NULL; - - blk_queue_prep_rq(q, scsi_prep_fn); - blk_queue_softirq_done(q, scsi_softirq_done); - blk_queue_rq_timed_out(q, scsi_times_out); - blk_queue_lld_busy(q, scsi_lld_busy); - return q; -} - -void scsi_free_queue(struct request_queue *q) -{ - unsigned long flags; - - WARN_ON(q->queuedata); - - /* cause scsi_request_fn() to kill all non-finished requests */ - spin_lock_irqsave(q->queue_lock, flags); - q->request_fn(q); - spin_unlock_irqrestore(q->queue_lock, flags); - - blk_cleanup_queue(q); -} - -/* - * Function: scsi_block_requests() - * - * Purpose: Utility function used by low-level drivers to prevent further - * commands from being queued to the device. - * - * Arguments: shost - Host in question - * - * Returns: Nothing - * - * Lock status: No locks are assumed held. - * - * Notes: There is no timer nor any other means by which the requests - * get unblocked other than the low-level driver calling - * scsi_unblock_requests(). - */ -void scsi_block_requests(struct Scsi_Host *shost) -{ - shost->host_self_blocked = 1; -} -EXPORT_SYMBOL(scsi_block_requests); - -/* - * Function: scsi_unblock_requests() - * - * Purpose: Utility function used by low-level drivers to allow further - * commands from being queued to the device. - * - * Arguments: shost - Host in question - * - * Returns: Nothing - * - * Lock status: No locks are assumed held. - * - * Notes: There is no timer nor any other means by which the requests - * get unblocked other than the low-level driver calling - * scsi_unblock_requests(). - * - * This is done as an API function so that changes to the - * internals of the scsi mid-layer won't require wholesale - * changes to drivers that use this feature. - */ -void scsi_unblock_requests(struct Scsi_Host *shost) -{ - shost->host_self_blocked = 0; - scsi_run_host_queues(shost); -} -EXPORT_SYMBOL(scsi_unblock_requests); - -int __init scsi_init_queue(void) -{ - int i; - - scsi_sdb_cache = kmem_cache_create("scsi_data_buffer", - sizeof(struct scsi_data_buffer), - 0, 0, NULL); - if (!scsi_sdb_cache) { - printk(KERN_ERR "SCSI: can't init scsi sdb cache\n"); - return -ENOMEM; - } - - for (i = 0; i < SG_MEMPOOL_NR; i++) { - struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; - int size = sgp->size * sizeof(struct scatterlist); - - sgp->slab = kmem_cache_create(sgp->name, size, 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!sgp->slab) { - printk(KERN_ERR "SCSI: can't init sg slab %s\n", - sgp->name); - goto cleanup_sdb; - } - - sgp->pool = mempool_create_slab_pool(SG_MEMPOOL_SIZE, - sgp->slab); - if (!sgp->pool) { - printk(KERN_ERR "SCSI: can't init sg mempool %s\n", - sgp->name); - goto cleanup_sdb; - } - } - - return 0; - -cleanup_sdb: - for (i = 0; i < SG_MEMPOOL_NR; i++) { - struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; - if (sgp->pool) - mempool_destroy(sgp->pool); - if (sgp->slab) - kmem_cache_destroy(sgp->slab); - } - kmem_cache_destroy(scsi_sdb_cache); - - return -ENOMEM; -} - -void scsi_exit_queue(void) -{ - int i; - - kmem_cache_destroy(scsi_sdb_cache); - - for (i = 0; i < SG_MEMPOOL_NR; i++) { - struct scsi_host_sg_pool *sgp = scsi_sg_pools + i; - mempool_destroy(sgp->pool); - kmem_cache_destroy(sgp->slab); - } -} - -/** - * scsi_mode_select - issue a mode select - * @sdev: SCSI device to be queried - * @pf: Page format bit (1 == standard, 0 == vendor specific) - * @sp: Save page bit (0 == don't save, 1 == save) - * @modepage: mode page being requested - * @buffer: request buffer (may not be smaller than eight bytes) - * @len: length of request buffer. - * @timeout: command timeout - * @retries: number of retries before failing - * @data: returns a structure abstracting the mode header data - * @sshdr: place to put sense data (or NULL if no sense to be collected). - * must be SCSI_SENSE_BUFFERSIZE big. - * - * Returns zero if successful; negative error number or scsi - * status on error - * - */ -int -scsi_mode_select(struct scsi_device *sdev, int pf, int sp, int modepage, - unsigned char *buffer, int len, int timeout, int retries, - struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) -{ - unsigned char cmd[10]; - unsigned char *real_buffer; - int ret; - - memset(cmd, 0, sizeof(cmd)); - cmd[1] = (pf ? 0x10 : 0) | (sp ? 0x01 : 0); - - if (sdev->use_10_for_ms) { - if (len > 65535) - return -EINVAL; - real_buffer = kmalloc(8 + len, GFP_KERNEL); - if (!real_buffer) - return -ENOMEM; - memcpy(real_buffer + 8, buffer, len); - len += 8; - real_buffer[0] = 0; - real_buffer[1] = 0; - real_buffer[2] = data->medium_type; - real_buffer[3] = data->device_specific; - real_buffer[4] = data->longlba ? 0x01 : 0; - real_buffer[5] = 0; - real_buffer[6] = data->block_descriptor_length >> 8; - real_buffer[7] = data->block_descriptor_length; - - cmd[0] = MODE_SELECT_10; - cmd[7] = len >> 8; - cmd[8] = len; - } else { - if (len > 255 || data->block_descriptor_length > 255 || - data->longlba) - return -EINVAL; - - real_buffer = kmalloc(4 + len, GFP_KERNEL); - if (!real_buffer) - return -ENOMEM; - memcpy(real_buffer + 4, buffer, len); - len += 4; - real_buffer[0] = 0; - real_buffer[1] = data->medium_type; - real_buffer[2] = data->device_specific; - real_buffer[3] = data->block_descriptor_length; - - - cmd[0] = MODE_SELECT; - cmd[4] = len; - } - - ret = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, real_buffer, len, - sshdr, timeout, retries, NULL); - kfree(real_buffer); - return ret; -} -EXPORT_SYMBOL_GPL(scsi_mode_select); - -/** - * scsi_mode_sense - issue a mode sense, falling back from 10 to six bytes if necessary. - * @sdev: SCSI device to be queried - * @dbd: set if mode sense will allow block descriptors to be returned - * @modepage: mode page being requested - * @buffer: request buffer (may not be smaller than eight bytes) - * @len: length of request buffer. - * @timeout: command timeout - * @retries: number of retries before failing - * @data: returns a structure abstracting the mode header data - * @sshdr: place to put sense data (or NULL if no sense to be collected). - * must be SCSI_SENSE_BUFFERSIZE big. - * - * Returns zero if unsuccessful, or the header offset (either 4 - * or 8 depending on whether a six or ten byte command was - * issued) if successful. - */ -int -scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, - unsigned char *buffer, int len, int timeout, int retries, - struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) -{ - unsigned char cmd[12]; - int use_10_for_ms; - int header_length; - int result; - struct scsi_sense_hdr my_sshdr; - - memset(data, 0, sizeof(*data)); - memset(&cmd[0], 0, 12); - cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */ - cmd[2] = modepage; - - /* caller might not be interested in sense, but we need it */ - if (!sshdr) - sshdr = &my_sshdr; - - retry: - use_10_for_ms = sdev->use_10_for_ms; - - if (use_10_for_ms) { - if (len < 8) - len = 8; - - cmd[0] = MODE_SENSE_10; - cmd[8] = len; - header_length = 8; - } else { - if (len < 4) - len = 4; - - cmd[0] = MODE_SENSE; - cmd[4] = len; - header_length = 4; - } - - memset(buffer, 0, len); - - result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, - sshdr, timeout, retries, NULL); - - /* This code looks awful: what it's doing is making sure an - * ILLEGAL REQUEST sense return identifies the actual command - * byte as the problem. MODE_SENSE commands can return - * ILLEGAL REQUEST if the code page isn't supported */ - - if (use_10_for_ms && !scsi_status_is_good(result) && - (driver_byte(result) & DRIVER_SENSE)) { - if (scsi_sense_valid(sshdr)) { - if ((sshdr->sense_key == ILLEGAL_REQUEST) && - (sshdr->asc == 0x20) && (sshdr->ascq == 0)) { - /* - * Invalid command operation code - */ - sdev->use_10_for_ms = 0; - goto retry; - } - } - } - - if(scsi_status_is_good(result)) { - if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b && - (modepage == 6 || modepage == 8))) { - /* Initio breakage? */ - header_length = 0; - data->length = 13; - data->medium_type = 0; - data->device_specific = 0; - data->longlba = 0; - data->block_descriptor_length = 0; - } else if(use_10_for_ms) { - data->length = buffer[0]*256 + buffer[1] + 2; - data->medium_type = buffer[2]; - data->device_specific = buffer[3]; - data->longlba = buffer[4] & 0x01; - data->block_descriptor_length = buffer[6]*256 - + buffer[7]; - } else { - data->length = buffer[0] + 1; - data->medium_type = buffer[1]; - data->device_specific = buffer[2]; - data->block_descriptor_length = buffer[3]; - } - data->header_length = header_length; - } - - return result; -} -EXPORT_SYMBOL(scsi_mode_sense); - -/** - * scsi_test_unit_ready - test if unit is ready - * @sdev: scsi device to change the state of. - * @timeout: command timeout - * @retries: number of retries before failing - * @sshdr_external: Optional pointer to struct scsi_sense_hdr for - * returning sense. Make sure that this is cleared before passing - * in. - * - * Returns zero if unsuccessful or an error if TUR failed. For - * removable media, UNIT_ATTENTION sets ->changed flag. - **/ -int -scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries, - struct scsi_sense_hdr *sshdr_external) -{ - char cmd[] = { - TEST_UNIT_READY, 0, 0, 0, 0, 0, - }; - struct scsi_sense_hdr *sshdr; - int result; - - if (!sshdr_external) - sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); - else - sshdr = sshdr_external; - - /* try to eat the UNIT_ATTENTION if there are enough retries */ - do { - result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sshdr, - timeout, retries, NULL); - if (sdev->removable && scsi_sense_valid(sshdr) && - sshdr->sense_key == UNIT_ATTENTION) - sdev->changed = 1; - } while (scsi_sense_valid(sshdr) && - sshdr->sense_key == UNIT_ATTENTION && --retries); - - if (!sshdr_external) - kfree(sshdr); - return result; -} -EXPORT_SYMBOL(scsi_test_unit_ready); - -/** - * scsi_device_set_state - Take the given device through the device state model. - * @sdev: scsi device to change the state of. - * @state: state to change to. - * - * Returns zero if unsuccessful or an error if the requested - * transition is illegal. - */ -int -scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state) -{ - enum scsi_device_state oldstate = sdev->sdev_state; - - if (state == oldstate) - return 0; - - switch (state) { - case SDEV_CREATED: - switch (oldstate) { - case SDEV_CREATED_BLOCK: - break; - default: - goto illegal; - } - break; - - case SDEV_RUNNING: - switch (oldstate) { - case SDEV_CREATED: - case SDEV_OFFLINE: - case SDEV_QUIESCE: - case SDEV_BLOCK: - break; - default: - goto illegal; - } - break; - - case SDEV_QUIESCE: - switch (oldstate) { - case SDEV_RUNNING: - case SDEV_OFFLINE: - break; - default: - goto illegal; - } - break; - - case SDEV_OFFLINE: - switch (oldstate) { - case SDEV_CREATED: - case SDEV_RUNNING: - case SDEV_QUIESCE: - case SDEV_BLOCK: - break; - default: - goto illegal; - } - break; - - case SDEV_BLOCK: - switch (oldstate) { - case SDEV_RUNNING: - case SDEV_CREATED_BLOCK: - break; - default: - goto illegal; - } - break; - - case SDEV_CREATED_BLOCK: - switch (oldstate) { - case SDEV_CREATED: - break; - default: - goto illegal; - } - break; - - case SDEV_CANCEL: - switch (oldstate) { - case SDEV_CREATED: - case SDEV_RUNNING: - case SDEV_QUIESCE: - case SDEV_OFFLINE: - case SDEV_BLOCK: - break; - default: - goto illegal; - } - break; - - case SDEV_DEL: - switch (oldstate) { - case SDEV_CREATED: - case SDEV_RUNNING: - case SDEV_OFFLINE: - case SDEV_CANCEL: - break; - default: - goto illegal; - } - break; - - } - sdev->sdev_state = state; - return 0; - - illegal: - SCSI_LOG_ERROR_RECOVERY(1, - sdev_printk(KERN_ERR, sdev, - "Illegal state transition %s->%s\n", - scsi_device_state_name(oldstate), - scsi_device_state_name(state)) - ); - return -EINVAL; -} -EXPORT_SYMBOL(scsi_device_set_state); - -/** - * sdev_evt_emit - emit a single SCSI device uevent - * @sdev: associated SCSI device - * @evt: event to emit - * - * Send a single uevent (scsi_event) to the associated scsi_device. - */ -static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt) -{ - int idx = 0; - char *envp[3]; - - switch (evt->evt_type) { - case SDEV_EVT_MEDIA_CHANGE: - envp[idx++] = "SDEV_MEDIA_CHANGE=1"; - break; - - default: - /* do nothing */ - break; - } - - envp[idx++] = NULL; - - kobject_uevent_env(&sdev->sdev_gendev.kobj, KOBJ_CHANGE, envp); -} - -/** - * sdev_evt_thread - send a uevent for each scsi event - * @work: work struct for scsi_device - * - * Dispatch queued events to their associated scsi_device kobjects - * as uevents. - */ -void scsi_evt_thread(struct work_struct *work) -{ - struct scsi_device *sdev; - LIST_HEAD(event_list); - - sdev = container_of(work, struct scsi_device, event_work); - - while (1) { - struct scsi_event *evt; - struct list_head *this, *tmp; - unsigned long flags; - - spin_lock_irqsave(&sdev->list_lock, flags); - list_splice_init(&sdev->event_list, &event_list); - spin_unlock_irqrestore(&sdev->list_lock, flags); - - if (list_empty(&event_list)) - break; - - list_for_each_safe(this, tmp, &event_list) { - evt = list_entry(this, struct scsi_event, node); - list_del(&evt->node); - scsi_evt_emit(sdev, evt); - kfree(evt); - } - } -} - -/** - * sdev_evt_send - send asserted event to uevent thread - * @sdev: scsi_device event occurred on - * @evt: event to send - * - * Assert scsi device event asynchronously. - */ -void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt) -{ - unsigned long flags; - -#if 0 - /* FIXME: currently this check eliminates all media change events - * for polled devices. Need to update to discriminate between AN - * and polled events */ - if (!test_bit(evt->evt_type, sdev->supported_events)) { - kfree(evt); - return; - } -#endif - - spin_lock_irqsave(&sdev->list_lock, flags); - list_add_tail(&evt->node, &sdev->event_list); - schedule_work(&sdev->event_work); - spin_unlock_irqrestore(&sdev->list_lock, flags); -} -EXPORT_SYMBOL_GPL(sdev_evt_send); - -/** - * sdev_evt_alloc - allocate a new scsi event - * @evt_type: type of event to allocate - * @gfpflags: GFP flags for allocation - * - * Allocates and returns a new scsi_event. - */ -struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, - gfp_t gfpflags) -{ - struct scsi_event *evt = kzalloc(sizeof(struct scsi_event), gfpflags); - if (!evt) - return NULL; - - evt->evt_type = evt_type; - INIT_LIST_HEAD(&evt->node); - - /* evt_type-specific initialization, if any */ - switch (evt_type) { - case SDEV_EVT_MEDIA_CHANGE: - default: - /* do nothing */ - break; - } - - return evt; -} -EXPORT_SYMBOL_GPL(sdev_evt_alloc); - -/** - * sdev_evt_send_simple - send asserted event to uevent thread - * @sdev: scsi_device event occurred on - * @evt_type: type of event to send - * @gfpflags: GFP flags for allocation - * - * Assert scsi device event asynchronously, given an event type. - */ -void sdev_evt_send_simple(struct scsi_device *sdev, - enum scsi_device_event evt_type, gfp_t gfpflags) -{ - struct scsi_event *evt = sdev_evt_alloc(evt_type, gfpflags); - if (!evt) { - sdev_printk(KERN_ERR, sdev, "event %d eaten due to OOM\n", - evt_type); - return; - } - - sdev_evt_send(sdev, evt); -} -EXPORT_SYMBOL_GPL(sdev_evt_send_simple); - -/** - * scsi_device_quiesce - Block user issued commands. - * @sdev: scsi device to quiesce. - * - * This works by trying to transition to the SDEV_QUIESCE state - * (which must be a legal transition). When the device is in this - * state, only special requests will be accepted, all others will - * be deferred. Since special requests may also be requeued requests, - * a successful return doesn't guarantee the device will be - * totally quiescent. - * - * Must be called with user context, may sleep. - * - * Returns zero if unsuccessful or an error if not. - */ -int -scsi_device_quiesce(struct scsi_device *sdev) -{ - int err = scsi_device_set_state(sdev, SDEV_QUIESCE); - if (err) - return err; - - scsi_run_queue(sdev->request_queue); - while (sdev->device_busy) { - msleep_interruptible(200); - scsi_run_queue(sdev->request_queue); - } - return 0; -} -EXPORT_SYMBOL(scsi_device_quiesce); - -/** - * scsi_device_resume - Restart user issued commands to a quiesced device. - * @sdev: scsi device to resume. - * - * Moves the device from quiesced back to running and restarts the - * queues. - * - * Must be called with user context, may sleep. - */ -void -scsi_device_resume(struct scsi_device *sdev) -{ - if(scsi_device_set_state(sdev, SDEV_RUNNING)) - return; - scsi_run_queue(sdev->request_queue); -} -EXPORT_SYMBOL(scsi_device_resume); - -static void -device_quiesce_fn(struct scsi_device *sdev, void *data) -{ - scsi_device_quiesce(sdev); -} - -void -scsi_target_quiesce(struct scsi_target *starget) -{ - starget_for_each_device(starget, NULL, device_quiesce_fn); -} -EXPORT_SYMBOL(scsi_target_quiesce); - -static void -device_resume_fn(struct scsi_device *sdev, void *data) -{ - scsi_device_resume(sdev); -} - -void -scsi_target_resume(struct scsi_target *starget) -{ - starget_for_each_device(starget, NULL, device_resume_fn); -} -EXPORT_SYMBOL(scsi_target_resume); - -/** - * scsi_internal_device_block - internal function to put a device temporarily into the SDEV_BLOCK state - * @sdev: device to block - * - * Block request made by scsi lld's to temporarily stop all - * scsi commands on the specified device. Called from interrupt - * or normal process context. - * - * Returns zero if successful or error if not - * - * Notes: - * This routine transitions the device to the SDEV_BLOCK state - * (which must be a legal transition). When the device is in this - * state, all commands are deferred until the scsi lld reenables - * the device with scsi_device_unblock or device_block_tmo fires. - * This routine assumes the host_lock is held on entry. - */ -int -scsi_internal_device_block(struct scsi_device *sdev) -{ - struct request_queue *q = sdev->request_queue; - unsigned long flags; - int err = 0; - - err = scsi_device_set_state(sdev, SDEV_BLOCK); - if (err) { - err = scsi_device_set_state(sdev, SDEV_CREATED_BLOCK); - - if (err) - return err; - } - - /* - * The device has transitioned to SDEV_BLOCK. Stop the - * block layer from calling the midlayer with this device's - * request queue. - */ - spin_lock_irqsave(q->queue_lock, flags); - blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); - - return 0; -} -EXPORT_SYMBOL_GPL(scsi_internal_device_block); - -/** - * scsi_internal_device_unblock - resume a device after a block request - * @sdev: device to resume - * - * Called by scsi lld's or the midlayer to restart the device queue - * for the previously suspended scsi device. Called from interrupt or - * normal process context. - * - * Returns zero if successful or error if not. - * - * Notes: - * This routine transitions the device to the SDEV_RUNNING state - * (which must be a legal transition) allowing the midlayer to - * goose the queue for this device. This routine assumes the - * host_lock is held upon entry. - */ -int -scsi_internal_device_unblock(struct scsi_device *sdev) -{ - struct request_queue *q = sdev->request_queue; - unsigned long flags; - - /* - * Try to transition the scsi device to SDEV_RUNNING - * and goose the device queue if successful. - */ - if (sdev->sdev_state == SDEV_BLOCK) - sdev->sdev_state = SDEV_RUNNING; - else if (sdev->sdev_state == SDEV_CREATED_BLOCK) - sdev->sdev_state = SDEV_CREATED; - else if (sdev->sdev_state != SDEV_CANCEL && - sdev->sdev_state != SDEV_OFFLINE) - return -EINVAL; - - spin_lock_irqsave(q->queue_lock, flags); - blk_start_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); - - return 0; -} -EXPORT_SYMBOL_GPL(scsi_internal_device_unblock); - -static void -device_block(struct scsi_device *sdev, void *data) -{ - scsi_internal_device_block(sdev); -} - -static int -target_block(struct device *dev, void *data) -{ - if (scsi_is_target_device(dev)) - starget_for_each_device(to_scsi_target(dev), NULL, - device_block); - return 0; -} - -void -scsi_target_block(struct device *dev) -{ - if (scsi_is_target_device(dev)) - starget_for_each_device(to_scsi_target(dev), NULL, - device_block); - else - device_for_each_child(dev, NULL, target_block); -} -EXPORT_SYMBOL_GPL(scsi_target_block); - -static void -device_unblock(struct scsi_device *sdev, void *data) -{ - scsi_internal_device_unblock(sdev); -} - -static int -target_unblock(struct device *dev, void *data) -{ - if (scsi_is_target_device(dev)) - starget_for_each_device(to_scsi_target(dev), NULL, - device_unblock); - return 0; -} - -void -scsi_target_unblock(struct device *dev) -{ - if (scsi_is_target_device(dev)) - starget_for_each_device(to_scsi_target(dev), NULL, - device_unblock); - else - device_for_each_child(dev, NULL, target_unblock); -} -EXPORT_SYMBOL_GPL(scsi_target_unblock); - -/** - * scsi_kmap_atomic_sg - find and atomically map an sg-elemnt - * @sgl: scatter-gather list - * @sg_count: number of segments in sg - * @offset: offset in bytes into sg, on return offset into the mapped area - * @len: bytes to map, on return number of bytes mapped - * - * Returns virtual address of the start of the mapped page - */ -void *scsi_kmap_atomic_sg(struct scatterlist *sgl, int sg_count, - size_t *offset, size_t *len) -{ - int i; - size_t sg_len = 0, len_complete = 0; - struct scatterlist *sg; - struct page *page; - - WARN_ON(!irqs_disabled()); - - for_each_sg(sgl, sg, sg_count, i) { - len_complete = sg_len; /* Complete sg-entries */ - sg_len += sg->length; - if (sg_len > *offset) - break; - } - - if (unlikely(i == sg_count)) { - printk(KERN_ERR "%s: Bytes in sg: %zu, requested offset %zu, " - "elements %d\n", - __func__, sg_len, *offset, sg_count); - WARN_ON(1); - return NULL; - } - - /* Offset starting from the beginning of first page in this sg-entry */ - *offset = *offset - len_complete + sg->offset; - - /* Assumption: contiguous pages can be accessed as "page + i" */ - page = nth_page(sg_page(sg), (*offset >> PAGE_SHIFT)); - *offset &= ~PAGE_MASK; - - /* Bytes in this sg-entry from *offset to the end of the page */ - sg_len = PAGE_SIZE - *offset; - if (*len > sg_len) - *len = sg_len; - - return kmap_atomic(page); -} -EXPORT_SYMBOL(scsi_kmap_atomic_sg); - -/** - * scsi_kunmap_atomic_sg - atomically unmap a virtual address, previously mapped with scsi_kmap_atomic_sg - * @virt: virtual address to be unmapped - */ -void scsi_kunmap_atomic_sg(void *virt) -{ - kunmap_atomic(virt); -} -EXPORT_SYMBOL(scsi_kunmap_atomic_sg); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_lib_dma.c b/ANDROID_3.4.5/drivers/scsi/scsi_lib_dma.c deleted file mode 100644 index 2ac3f397..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_lib_dma.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SCSI library functions depending on DMA - */ - -#include -#include -#include -#include - -#include -#include -#include -#include - -/** - * scsi_dma_map - perform DMA mapping against command's sg lists - * @cmd: scsi command - * - * Returns the number of sg lists actually used, zero if the sg lists - * is NULL, or -ENOMEM if the mapping failed. - */ -int scsi_dma_map(struct scsi_cmnd *cmd) -{ - int nseg = 0; - - if (scsi_sg_count(cmd)) { - struct device *dev = cmd->device->host->dma_dev; - - nseg = dma_map_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd), - cmd->sc_data_direction); - if (unlikely(!nseg)) - return -ENOMEM; - } - return nseg; -} -EXPORT_SYMBOL(scsi_dma_map); - -/** - * scsi_dma_unmap - unmap command's sg lists mapped by scsi_dma_map - * @cmd: scsi command - */ -void scsi_dma_unmap(struct scsi_cmnd *cmd) -{ - if (scsi_sg_count(cmd)) { - struct device *dev = cmd->device->host->dma_dev; - - dma_unmap_sg(dev, scsi_sglist(cmd), scsi_sg_count(cmd), - cmd->sc_data_direction); - } -} -EXPORT_SYMBOL(scsi_dma_unmap); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_logging.h b/ANDROID_3.4.5/drivers/scsi/scsi_logging.h deleted file mode 100644 index 1f65139e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_logging.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _SCSI_LOGGING_H -#define _SCSI_LOGGING_H - - -/* - * This defines the scsi logging feature. It is a means by which the user - * can select how much information they get about various goings on, and it - * can be really useful for fault tracing. The logging word is divided into - * 8 nibbles, each of which describes a loglevel. The division of things is - * somewhat arbitrary, and the division of the word could be changed if it - * were really needed for any reason. The numbers below are the only place - * where these are specified. For a first go-around, 3 bits is more than - * enough, since this gives 8 levels of logging (really 7, since 0 is always - * off). Cutting to 2 bits might be wise at some point. - */ - -#define SCSI_LOG_ERROR_SHIFT 0 -#define SCSI_LOG_TIMEOUT_SHIFT 3 -#define SCSI_LOG_SCAN_SHIFT 6 -#define SCSI_LOG_MLQUEUE_SHIFT 9 -#define SCSI_LOG_MLCOMPLETE_SHIFT 12 -#define SCSI_LOG_LLQUEUE_SHIFT 15 -#define SCSI_LOG_LLCOMPLETE_SHIFT 18 -#define SCSI_LOG_HLQUEUE_SHIFT 21 -#define SCSI_LOG_HLCOMPLETE_SHIFT 24 -#define SCSI_LOG_IOCTL_SHIFT 27 - -#define SCSI_LOG_ERROR_BITS 3 -#define SCSI_LOG_TIMEOUT_BITS 3 -#define SCSI_LOG_SCAN_BITS 3 -#define SCSI_LOG_MLQUEUE_BITS 3 -#define SCSI_LOG_MLCOMPLETE_BITS 3 -#define SCSI_LOG_LLQUEUE_BITS 3 -#define SCSI_LOG_LLCOMPLETE_BITS 3 -#define SCSI_LOG_HLQUEUE_BITS 3 -#define SCSI_LOG_HLCOMPLETE_BITS 3 -#define SCSI_LOG_IOCTL_BITS 3 - -extern unsigned int scsi_logging_level; - -#ifdef CONFIG_SCSI_LOGGING - -#define SCSI_LOG_LEVEL(SHIFT, BITS) \ - ((scsi_logging_level >> (SHIFT)) & ((1 << (BITS)) - 1)) - -#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD) \ -do { \ - if (unlikely((SCSI_LOG_LEVEL(SHIFT, BITS)) > (LEVEL))) \ - do { \ - CMD; \ - } while (0); \ -} while (0) -#else -#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD) -#endif /* CONFIG_SCSI_LOGGING */ - -/* - * These are the macros that are actually used throughout the code to - * log events. If logging isn't enabled, they are no-ops and will be - * completely absent from the user's code. - */ -#define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD); -#define SCSI_LOG_TIMEOUT(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL,CMD); -#define SCSI_LOG_SCAN_BUS(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL,CMD); -#define SCSI_LOG_MLQUEUE(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL,CMD); -#define SCSI_LOG_MLCOMPLETE(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL,CMD); -#define SCSI_LOG_LLQUEUE(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL,CMD); -#define SCSI_LOG_LLCOMPLETE(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL,CMD); -#define SCSI_LOG_HLQUEUE(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL,CMD); -#define SCSI_LOG_HLCOMPLETE(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD); -#define SCSI_LOG_IOCTL(LEVEL,CMD) \ - SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD); - -#endif /* _SCSI_LOGGING_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_module.c b/ANDROID_3.4.5/drivers/scsi/scsi_module.c deleted file mode 100644 index 48917583..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_module.c +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2003 Christoph Hellwig. - * Released under GPL v2. - * - * Support for old-style host templates. - * - * NOTE: Do not use this for new drivers ever. - */ - -#include -#include -#include - -#include - - -static int __init init_this_scsi_driver(void) -{ - struct scsi_host_template *sht = &driver_template; - struct Scsi_Host *shost; - struct list_head *l; - int error; - - if (!sht->release) { - printk(KERN_ERR - "scsi HBA driver %s didn't set a release method.\n", - sht->name); - return -EINVAL; - } - - sht->module = THIS_MODULE; - INIT_LIST_HEAD(&sht->legacy_hosts); - - sht->detect(sht); - if (list_empty(&sht->legacy_hosts)) - return -ENODEV; - - list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) { - error = scsi_add_host(shost, NULL); - if (error) - goto fail; - scsi_scan_host(shost); - } - return 0; - fail: - l = &shost->sht_legacy_list; - while ((l = l->prev) != &sht->legacy_hosts) - scsi_remove_host(list_entry(l, struct Scsi_Host, sht_legacy_list)); - return error; -} - -static void __exit exit_this_scsi_driver(void) -{ - struct scsi_host_template *sht = &driver_template; - struct Scsi_Host *shost, *s; - - list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) - scsi_remove_host(shost); - list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list) - sht->release(shost); - - if (list_empty(&sht->legacy_hosts)) - return; - - printk(KERN_WARNING "%s did not call scsi_unregister\n", sht->name); - dump_stack(); - - list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list) - scsi_unregister(shost); -} - -module_init(init_this_scsi_driver); -module_exit(exit_this_scsi_driver); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_netlink.c b/ANDROID_3.4.5/drivers/scsi/scsi_netlink.c deleted file mode 100644 index c77628af..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_netlink.c +++ /dev/null @@ -1,680 +0,0 @@ -/* - * scsi_netlink.c - SCSI Transport Netlink Interface - * - * Copyright (C) 2006 James Smart, Emulex Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "scsi_priv.h" - -struct sock *scsi_nl_sock = NULL; -EXPORT_SYMBOL_GPL(scsi_nl_sock); - -static DEFINE_SPINLOCK(scsi_nl_lock); -static struct list_head scsi_nl_drivers; - -static u32 scsi_nl_state; -#define STATE_EHANDLER_BSY 0x00000001 - -struct scsi_nl_transport { - int (*msg_handler)(struct sk_buff *); - void (*event_handler)(struct notifier_block *, unsigned long, void *); - unsigned int refcnt; - int flags; -}; - -/* flags values (bit flags) */ -#define HANDLER_DELETING 0x1 - -static struct scsi_nl_transport transports[SCSI_NL_MAX_TRANSPORTS] = - { {NULL, }, }; - - -struct scsi_nl_drvr { - struct list_head next; - int (*dmsg_handler)(struct Scsi_Host *shost, void *payload, - u32 len, u32 pid); - void (*devt_handler)(struct notifier_block *nb, - unsigned long event, void *notify_ptr); - struct scsi_host_template *hostt; - u64 vendor_id; - unsigned int refcnt; - int flags; -}; - - - -/** - * scsi_nl_rcv_msg - Receive message handler. - * @skb: socket receive buffer - * - * Description: Extracts message from a receive buffer. - * Validates message header and calls appropriate transport message handler - * - * - **/ -static void -scsi_nl_rcv_msg(struct sk_buff *skb) -{ - struct nlmsghdr *nlh; - struct scsi_nl_hdr *hdr; - unsigned long flags; - u32 rlen; - int err, tport; - - while (skb->len >= NLMSG_SPACE(0)) { - err = 0; - - nlh = nlmsg_hdr(skb); - if ((nlh->nlmsg_len < (sizeof(*nlh) + sizeof(*hdr))) || - (skb->len < nlh->nlmsg_len)) { - printk(KERN_WARNING "%s: discarding partial skb\n", - __func__); - return; - } - - rlen = NLMSG_ALIGN(nlh->nlmsg_len); - if (rlen > skb->len) - rlen = skb->len; - - if (nlh->nlmsg_type != SCSI_TRANSPORT_MSG) { - err = -EBADMSG; - goto next_msg; - } - - hdr = NLMSG_DATA(nlh); - if ((hdr->version != SCSI_NL_VERSION) || - (hdr->magic != SCSI_NL_MAGIC)) { - err = -EPROTOTYPE; - goto next_msg; - } - - if (!capable(CAP_SYS_ADMIN)) { - err = -EPERM; - goto next_msg; - } - - if (nlh->nlmsg_len < (sizeof(*nlh) + hdr->msglen)) { - printk(KERN_WARNING "%s: discarding partial message\n", - __func__); - goto next_msg; - } - - /* - * Deliver message to the appropriate transport - */ - spin_lock_irqsave(&scsi_nl_lock, flags); - - tport = hdr->transport; - if ((tport < SCSI_NL_MAX_TRANSPORTS) && - !(transports[tport].flags & HANDLER_DELETING) && - (transports[tport].msg_handler)) { - transports[tport].refcnt++; - spin_unlock_irqrestore(&scsi_nl_lock, flags); - err = transports[tport].msg_handler(skb); - spin_lock_irqsave(&scsi_nl_lock, flags); - transports[tport].refcnt--; - } else - err = -ENOENT; - - spin_unlock_irqrestore(&scsi_nl_lock, flags); - -next_msg: - if ((err) || (nlh->nlmsg_flags & NLM_F_ACK)) - netlink_ack(skb, nlh, err); - - skb_pull(skb, rlen); - } -} - - -/** - * scsi_nl_rcv_event - Event handler for a netlink socket. - * @this: event notifier block - * @event: event type - * @ptr: event payload - * - **/ -static int -scsi_nl_rcv_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct netlink_notify *n = ptr; - struct scsi_nl_drvr *driver; - unsigned long flags; - int tport; - - if (n->protocol != NETLINK_SCSITRANSPORT) - return NOTIFY_DONE; - - spin_lock_irqsave(&scsi_nl_lock, flags); - scsi_nl_state |= STATE_EHANDLER_BSY; - - /* - * Pass event on to any transports that may be listening - */ - for (tport = 0; tport < SCSI_NL_MAX_TRANSPORTS; tport++) { - if (!(transports[tport].flags & HANDLER_DELETING) && - (transports[tport].event_handler)) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - transports[tport].event_handler(this, event, ptr); - spin_lock_irqsave(&scsi_nl_lock, flags); - } - } - - /* - * Pass event on to any drivers that may be listening - */ - list_for_each_entry(driver, &scsi_nl_drivers, next) { - if (!(driver->flags & HANDLER_DELETING) && - (driver->devt_handler)) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - driver->devt_handler(this, event, ptr); - spin_lock_irqsave(&scsi_nl_lock, flags); - } - } - - scsi_nl_state &= ~STATE_EHANDLER_BSY; - spin_unlock_irqrestore(&scsi_nl_lock, flags); - - return NOTIFY_DONE; -} - -static struct notifier_block scsi_netlink_notifier = { - .notifier_call = scsi_nl_rcv_event, -}; - - -/* - * GENERIC SCSI transport receive and event handlers - */ - -/** - * scsi_generic_msg_handler - receive message handler for GENERIC transport messages - * @skb: socket receive buffer - **/ -static int -scsi_generic_msg_handler(struct sk_buff *skb) -{ - struct nlmsghdr *nlh = nlmsg_hdr(skb); - struct scsi_nl_hdr *snlh = NLMSG_DATA(nlh); - struct scsi_nl_drvr *driver; - struct Scsi_Host *shost; - unsigned long flags; - int err = 0, match, pid; - - pid = NETLINK_CREDS(skb)->pid; - - switch (snlh->msgtype) { - case SCSI_NL_SHOST_VENDOR: - { - struct scsi_nl_host_vendor_msg *msg = NLMSG_DATA(nlh); - - /* Locate the driver that corresponds to the message */ - spin_lock_irqsave(&scsi_nl_lock, flags); - match = 0; - list_for_each_entry(driver, &scsi_nl_drivers, next) { - if (driver->vendor_id == msg->vendor_id) { - match = 1; - break; - } - } - - if ((!match) || (!driver->dmsg_handler)) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - err = -ESRCH; - goto rcv_exit; - } - - if (driver->flags & HANDLER_DELETING) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - err = -ESHUTDOWN; - goto rcv_exit; - } - - driver->refcnt++; - spin_unlock_irqrestore(&scsi_nl_lock, flags); - - - /* if successful, scsi_host_lookup takes a shost reference */ - shost = scsi_host_lookup(msg->host_no); - if (!shost) { - err = -ENODEV; - goto driver_exit; - } - - /* is this host owned by the vendor ? */ - if (shost->hostt != driver->hostt) { - err = -EINVAL; - goto vendormsg_put; - } - - /* pass message on to the driver */ - err = driver->dmsg_handler(shost, (void *)&msg[1], - msg->vmsg_datalen, pid); - -vendormsg_put: - /* release reference by scsi_host_lookup */ - scsi_host_put(shost); - -driver_exit: - /* release our own reference on the registration object */ - spin_lock_irqsave(&scsi_nl_lock, flags); - driver->refcnt--; - spin_unlock_irqrestore(&scsi_nl_lock, flags); - break; - } - - default: - err = -EBADR; - break; - } - -rcv_exit: - if (err) - printk(KERN_WARNING "%s: Msgtype %d failed - err %d\n", - __func__, snlh->msgtype, err); - return err; -} - - -/** - * scsi_nl_add_transport - - * Registers message and event handlers for a transport. Enables - * receipt of netlink messages and events to a transport. - * - * @tport: transport registering handlers - * @msg_handler: receive message handler callback - * @event_handler: receive event handler callback - **/ -int -scsi_nl_add_transport(u8 tport, - int (*msg_handler)(struct sk_buff *), - void (*event_handler)(struct notifier_block *, unsigned long, void *)) -{ - unsigned long flags; - int err = 0; - - if (tport >= SCSI_NL_MAX_TRANSPORTS) - return -EINVAL; - - spin_lock_irqsave(&scsi_nl_lock, flags); - - if (scsi_nl_state & STATE_EHANDLER_BSY) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - msleep(1); - spin_lock_irqsave(&scsi_nl_lock, flags); - } - - if (transports[tport].msg_handler || transports[tport].event_handler) { - err = -EALREADY; - goto register_out; - } - - transports[tport].msg_handler = msg_handler; - transports[tport].event_handler = event_handler; - transports[tport].flags = 0; - transports[tport].refcnt = 0; - -register_out: - spin_unlock_irqrestore(&scsi_nl_lock, flags); - - return err; -} -EXPORT_SYMBOL_GPL(scsi_nl_add_transport); - - -/** - * scsi_nl_remove_transport - - * Disable transport receiption of messages and events - * - * @tport: transport deregistering handlers - * - **/ -void -scsi_nl_remove_transport(u8 tport) -{ - unsigned long flags; - - spin_lock_irqsave(&scsi_nl_lock, flags); - if (scsi_nl_state & STATE_EHANDLER_BSY) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - msleep(1); - spin_lock_irqsave(&scsi_nl_lock, flags); - } - - if (tport < SCSI_NL_MAX_TRANSPORTS) { - transports[tport].flags |= HANDLER_DELETING; - - while (transports[tport].refcnt != 0) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - schedule_timeout_uninterruptible(HZ/4); - spin_lock_irqsave(&scsi_nl_lock, flags); - } - transports[tport].msg_handler = NULL; - transports[tport].event_handler = NULL; - transports[tport].flags = 0; - } - - spin_unlock_irqrestore(&scsi_nl_lock, flags); - - return; -} -EXPORT_SYMBOL_GPL(scsi_nl_remove_transport); - - -/** - * scsi_nl_add_driver - - * A driver is registering its interfaces for SCSI netlink messages - * - * @vendor_id: A unique identification value for the driver. - * @hostt: address of the driver's host template. Used - * to verify an shost is bound to the driver - * @nlmsg_handler: receive message handler callback - * @nlevt_handler: receive event handler callback - * - * Returns: - * 0 on Success - * error result otherwise - **/ -int -scsi_nl_add_driver(u64 vendor_id, struct scsi_host_template *hostt, - int (*nlmsg_handler)(struct Scsi_Host *shost, void *payload, - u32 len, u32 pid), - void (*nlevt_handler)(struct notifier_block *nb, - unsigned long event, void *notify_ptr)) -{ - struct scsi_nl_drvr *driver; - unsigned long flags; - - driver = kzalloc(sizeof(*driver), GFP_KERNEL); - if (unlikely(!driver)) { - printk(KERN_ERR "%s: allocation failure\n", __func__); - return -ENOMEM; - } - - driver->dmsg_handler = nlmsg_handler; - driver->devt_handler = nlevt_handler; - driver->hostt = hostt; - driver->vendor_id = vendor_id; - - spin_lock_irqsave(&scsi_nl_lock, flags); - if (scsi_nl_state & STATE_EHANDLER_BSY) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - msleep(1); - spin_lock_irqsave(&scsi_nl_lock, flags); - } - list_add_tail(&driver->next, &scsi_nl_drivers); - spin_unlock_irqrestore(&scsi_nl_lock, flags); - - return 0; -} -EXPORT_SYMBOL_GPL(scsi_nl_add_driver); - - -/** - * scsi_nl_remove_driver - - * An driver is unregistering with the SCSI netlink messages - * - * @vendor_id: The unique identification value for the driver. - **/ -void -scsi_nl_remove_driver(u64 vendor_id) -{ - struct scsi_nl_drvr *driver; - unsigned long flags; - - spin_lock_irqsave(&scsi_nl_lock, flags); - if (scsi_nl_state & STATE_EHANDLER_BSY) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - msleep(1); - spin_lock_irqsave(&scsi_nl_lock, flags); - } - - list_for_each_entry(driver, &scsi_nl_drivers, next) { - if (driver->vendor_id == vendor_id) { - driver->flags |= HANDLER_DELETING; - while (driver->refcnt != 0) { - spin_unlock_irqrestore(&scsi_nl_lock, flags); - schedule_timeout_uninterruptible(HZ/4); - spin_lock_irqsave(&scsi_nl_lock, flags); - } - list_del(&driver->next); - kfree(driver); - spin_unlock_irqrestore(&scsi_nl_lock, flags); - return; - } - } - - spin_unlock_irqrestore(&scsi_nl_lock, flags); - - printk(KERN_ERR "%s: removal of driver failed - vendor_id 0x%llx\n", - __func__, (unsigned long long)vendor_id); - return; -} -EXPORT_SYMBOL_GPL(scsi_nl_remove_driver); - - -/** - * scsi_netlink_init - Called by SCSI subsystem to initialize - * the SCSI transport netlink interface - * - **/ -void -scsi_netlink_init(void) -{ - int error; - - INIT_LIST_HEAD(&scsi_nl_drivers); - - error = netlink_register_notifier(&scsi_netlink_notifier); - if (error) { - printk(KERN_ERR "%s: register of event handler failed - %d\n", - __func__, error); - return; - } - - scsi_nl_sock = netlink_kernel_create(&init_net, NETLINK_SCSITRANSPORT, - SCSI_NL_GRP_CNT, scsi_nl_rcv_msg, NULL, - THIS_MODULE); - if (!scsi_nl_sock) { - printk(KERN_ERR "%s: register of receive handler failed\n", - __func__); - netlink_unregister_notifier(&scsi_netlink_notifier); - return; - } - - /* Register the entry points for the generic SCSI transport */ - error = scsi_nl_add_transport(SCSI_NL_TRANSPORT, - scsi_generic_msg_handler, NULL); - if (error) - printk(KERN_ERR "%s: register of GENERIC transport handler" - " failed - %d\n", __func__, error); - return; -} - - -/** - * scsi_netlink_exit - Called by SCSI subsystem to disable the SCSI transport netlink interface - * - **/ -void -scsi_netlink_exit(void) -{ - scsi_nl_remove_transport(SCSI_NL_TRANSPORT); - - if (scsi_nl_sock) { - netlink_kernel_release(scsi_nl_sock); - netlink_unregister_notifier(&scsi_netlink_notifier); - } - - return; -} - - -/* - * Exported Interfaces - */ - -/** - * scsi_nl_send_transport_msg - - * Generic function to send a single message from a SCSI transport to - * a single process - * - * @pid: receiving pid - * @hdr: message payload - * - **/ -void -scsi_nl_send_transport_msg(u32 pid, struct scsi_nl_hdr *hdr) -{ - struct sk_buff *skb; - struct nlmsghdr *nlh; - const char *fn; - char *datab; - u32 len, skblen; - int err; - - if (!scsi_nl_sock) { - err = -ENOENT; - fn = "netlink socket"; - goto msg_fail; - } - - len = NLMSG_SPACE(hdr->msglen); - skblen = NLMSG_SPACE(len); - - skb = alloc_skb(skblen, GFP_KERNEL); - if (!skb) { - err = -ENOBUFS; - fn = "alloc_skb"; - goto msg_fail; - } - - nlh = nlmsg_put(skb, pid, 0, SCSI_TRANSPORT_MSG, len - sizeof(*nlh), 0); - if (!nlh) { - err = -ENOBUFS; - fn = "nlmsg_put"; - goto msg_fail_skb; - } - datab = NLMSG_DATA(nlh); - memcpy(datab, hdr, hdr->msglen); - - err = nlmsg_unicast(scsi_nl_sock, skb, pid); - if (err < 0) { - fn = "nlmsg_unicast"; - /* nlmsg_unicast already kfree_skb'd */ - goto msg_fail; - } - - return; - -msg_fail_skb: - kfree_skb(skb); -msg_fail: - printk(KERN_WARNING - "%s: Dropped Message : pid %d Transport %d, msgtype x%x, " - "msglen %d: %s : err %d\n", - __func__, pid, hdr->transport, hdr->msgtype, hdr->msglen, - fn, err); - return; -} -EXPORT_SYMBOL_GPL(scsi_nl_send_transport_msg); - - -/** - * scsi_nl_send_vendor_msg - called to send a shost vendor unique message - * to a specific process id. - * - * @pid: process id of the receiver - * @host_no: host # sending the message - * @vendor_id: unique identifier for the driver's vendor - * @data_len: amount, in bytes, of vendor unique payload data - * @data_buf: pointer to vendor unique data buffer - * - * Returns: - * 0 on successful return - * otherwise, failing error code - * - * Notes: - * This routine assumes no locks are held on entry. - */ -int -scsi_nl_send_vendor_msg(u32 pid, unsigned short host_no, u64 vendor_id, - char *data_buf, u32 data_len) -{ - struct sk_buff *skb; - struct nlmsghdr *nlh; - struct scsi_nl_host_vendor_msg *msg; - u32 len, skblen; - int err; - - if (!scsi_nl_sock) { - err = -ENOENT; - goto send_vendor_fail; - } - - len = SCSI_NL_MSGALIGN(sizeof(*msg) + data_len); - skblen = NLMSG_SPACE(len); - - skb = alloc_skb(skblen, GFP_KERNEL); - if (!skb) { - err = -ENOBUFS; - goto send_vendor_fail; - } - - nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, - skblen - sizeof(*nlh), 0); - if (!nlh) { - err = -ENOBUFS; - goto send_vendor_fail_skb; - } - msg = NLMSG_DATA(nlh); - - INIT_SCSI_NL_HDR(&msg->snlh, SCSI_NL_TRANSPORT, - SCSI_NL_SHOST_VENDOR, len); - msg->vendor_id = vendor_id; - msg->host_no = host_no; - msg->vmsg_datalen = data_len; /* bytes */ - memcpy(&msg[1], data_buf, data_len); - - err = nlmsg_unicast(scsi_nl_sock, skb, pid); - if (err) - /* nlmsg_multicast already kfree_skb'd */ - goto send_vendor_fail; - - return 0; - -send_vendor_fail_skb: - kfree_skb(skb); -send_vendor_fail: - printk(KERN_WARNING - "%s: Dropped SCSI Msg : host %d vendor_unique - err %d\n", - __func__, host_no, err); - return err; -} -EXPORT_SYMBOL(scsi_nl_send_vendor_msg); - - diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_pm.c b/ANDROID_3.4.5/drivers/scsi/scsi_pm.c deleted file mode 100644 index c4670642..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_pm.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * scsi_pm.c Copyright (C) 2010 Alan Stern - * - * SCSI dynamic Power Management - * Initial version: Alan Stern - */ - -#include -#include -#include - -#include -#include -#include -#include - -#include "scsi_priv.h" - -static int scsi_dev_type_suspend(struct device *dev, pm_message_t msg) -{ - struct device_driver *drv; - int err; - - err = scsi_device_quiesce(to_scsi_device(dev)); - if (err == 0) { - drv = dev->driver; - if (drv && drv->suspend) - err = drv->suspend(dev, msg); - } - dev_dbg(dev, "scsi suspend: %d\n", err); - return err; -} - -static int scsi_dev_type_resume(struct device *dev) -{ - struct device_driver *drv; - int err = 0; - - drv = dev->driver; - if (drv && drv->resume) - err = drv->resume(dev); - scsi_device_resume(to_scsi_device(dev)); - dev_dbg(dev, "scsi resume: %d\n", err); - return err; -} - -#ifdef CONFIG_PM_SLEEP - -static int scsi_bus_suspend_common(struct device *dev, pm_message_t msg) -{ - int err = 0; - - if (scsi_is_sdev_device(dev)) { - /* - * sd is the only high-level SCSI driver to implement runtime - * PM, and sd treats runtime suspend, system suspend, and - * system hibernate identically (but not system freeze). - */ - if (pm_runtime_suspended(dev)) { - if (msg.event == PM_EVENT_SUSPEND || - msg.event == PM_EVENT_HIBERNATE) - return 0; /* already suspended */ - - /* wake up device so that FREEZE will succeed */ - pm_runtime_resume(dev); - } - err = scsi_dev_type_suspend(dev, msg); - } - return err; -} - -static int scsi_bus_resume_common(struct device *dev) -{ - int err = 0; - - if (scsi_is_sdev_device(dev)) { - /* - * Parent device may have runtime suspended as soon as - * it is woken up during the system resume. - * - * Resume it on behalf of child. - */ - pm_runtime_get_sync(dev->parent); - err = scsi_dev_type_resume(dev); - pm_runtime_put_sync(dev->parent); - } - - if (err == 0) { - pm_runtime_disable(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - } - return err; -} - -static int scsi_bus_prepare(struct device *dev) -{ - if (scsi_is_sdev_device(dev)) { - /* sd probing uses async_schedule. Wait until it finishes. */ - async_synchronize_full(); - - } else if (scsi_is_host_device(dev)) { - /* Wait until async scanning is finished */ - scsi_complete_async_scans(); - } - return 0; -} - -static int scsi_bus_suspend(struct device *dev) -{ - return scsi_bus_suspend_common(dev, PMSG_SUSPEND); -} - -static int scsi_bus_freeze(struct device *dev) -{ - return scsi_bus_suspend_common(dev, PMSG_FREEZE); -} - -static int scsi_bus_poweroff(struct device *dev) -{ - return scsi_bus_suspend_common(dev, PMSG_HIBERNATE); -} - -#else /* CONFIG_PM_SLEEP */ - -#define scsi_bus_resume_common NULL -#define scsi_bus_prepare NULL -#define scsi_bus_suspend NULL -#define scsi_bus_freeze NULL -#define scsi_bus_poweroff NULL - -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_PM_RUNTIME - -static int scsi_runtime_suspend(struct device *dev) -{ - int err = 0; - - dev_dbg(dev, "scsi_runtime_suspend\n"); - if (scsi_is_sdev_device(dev)) { - err = scsi_dev_type_suspend(dev, PMSG_AUTO_SUSPEND); - if (err == -EAGAIN) - pm_schedule_suspend(dev, jiffies_to_msecs( - round_jiffies_up_relative(HZ/10))); - } - - /* Insert hooks here for targets, hosts, and transport classes */ - - return err; -} - -static int scsi_runtime_resume(struct device *dev) -{ - int err = 0; - - dev_dbg(dev, "scsi_runtime_resume\n"); - if (scsi_is_sdev_device(dev)) - err = scsi_dev_type_resume(dev); - - /* Insert hooks here for targets, hosts, and transport classes */ - - return err; -} - -static int scsi_runtime_idle(struct device *dev) -{ - int err; - - dev_dbg(dev, "scsi_runtime_idle\n"); - - /* Insert hooks here for targets, hosts, and transport classes */ - - if (scsi_is_sdev_device(dev)) - err = pm_schedule_suspend(dev, 100); - else - err = pm_runtime_suspend(dev); - return err; -} - -int scsi_autopm_get_device(struct scsi_device *sdev) -{ - int err; - - err = pm_runtime_get_sync(&sdev->sdev_gendev); - if (err < 0 && err !=-EACCES) - pm_runtime_put_sync(&sdev->sdev_gendev); - else - err = 0; - return err; -} -EXPORT_SYMBOL_GPL(scsi_autopm_get_device); - -void scsi_autopm_put_device(struct scsi_device *sdev) -{ - pm_runtime_put_sync(&sdev->sdev_gendev); -} -EXPORT_SYMBOL_GPL(scsi_autopm_put_device); - -void scsi_autopm_get_target(struct scsi_target *starget) -{ - pm_runtime_get_sync(&starget->dev); -} - -void scsi_autopm_put_target(struct scsi_target *starget) -{ - pm_runtime_put_sync(&starget->dev); -} - -int scsi_autopm_get_host(struct Scsi_Host *shost) -{ - int err; - - err = pm_runtime_get_sync(&shost->shost_gendev); - if (err < 0 && err !=-EACCES) - pm_runtime_put_sync(&shost->shost_gendev); - else - err = 0; - return err; -} - -void scsi_autopm_put_host(struct Scsi_Host *shost) -{ - pm_runtime_put_sync(&shost->shost_gendev); -} - -#else - -#define scsi_runtime_suspend NULL -#define scsi_runtime_resume NULL -#define scsi_runtime_idle NULL - -#endif /* CONFIG_PM_RUNTIME */ - -const struct dev_pm_ops scsi_bus_pm_ops = { - .prepare = scsi_bus_prepare, - .suspend = scsi_bus_suspend, - .resume = scsi_bus_resume_common, - .freeze = scsi_bus_freeze, - .thaw = scsi_bus_resume_common, - .poweroff = scsi_bus_poweroff, - .restore = scsi_bus_resume_common, - .runtime_suspend = scsi_runtime_suspend, - .runtime_resume = scsi_runtime_resume, - .runtime_idle = scsi_runtime_idle, -}; diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_priv.h b/ANDROID_3.4.5/drivers/scsi/scsi_priv.h deleted file mode 100644 index be4fa6d1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_priv.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef _SCSI_PRIV_H -#define _SCSI_PRIV_H - -#include - -struct request_queue; -struct request; -struct scsi_cmnd; -struct scsi_device; -struct scsi_target; -struct scsi_host_template; -struct Scsi_Host; -struct scsi_nl_hdr; - - -/* - * Scsi Error Handler Flags - */ -#define SCSI_EH_CANCEL_CMD 0x0001 /* Cancel this cmd */ - -#define SCSI_SENSE_VALID(scmd) \ - (((scmd)->sense_buffer[0] & 0x70) == 0x70) - -/* hosts.c */ -extern int scsi_init_hosts(void); -extern void scsi_exit_hosts(void); - -/* scsi.c */ -extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd); -extern int scsi_setup_command_freelist(struct Scsi_Host *shost); -extern void scsi_destroy_command_freelist(struct Scsi_Host *shost); -#ifdef CONFIG_SCSI_LOGGING -void scsi_log_send(struct scsi_cmnd *cmd); -void scsi_log_completion(struct scsi_cmnd *cmd, int disposition); -#else -static inline void scsi_log_send(struct scsi_cmnd *cmd) - { }; -static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition) - { }; -#endif - -/* scsi_devinfo.c */ - -/* list of keys for the lists */ -enum { - SCSI_DEVINFO_GLOBAL = 0, - SCSI_DEVINFO_SPI, -}; - -extern int scsi_get_device_flags(struct scsi_device *sdev, - const unsigned char *vendor, - const unsigned char *model); -extern int scsi_get_device_flags_keyed(struct scsi_device *sdev, - const unsigned char *vendor, - const unsigned char *model, int key); -extern int scsi_dev_info_list_add_keyed(int compatible, char *vendor, - char *model, char *strflags, - int flags, int key); -extern int scsi_dev_info_list_del_keyed(char *vendor, char *model, int key); -extern int scsi_dev_info_add_list(int key, const char *name); -extern int scsi_dev_info_remove_list(int key); - -extern int __init scsi_init_devinfo(void); -extern void scsi_exit_devinfo(void); - -/* scsi_error.c */ -extern enum blk_eh_timer_return scsi_times_out(struct request *req); -extern int scsi_error_handler(void *host); -extern int scsi_decide_disposition(struct scsi_cmnd *cmd); -extern void scsi_eh_wakeup(struct Scsi_Host *shost); -extern int scsi_eh_scmd_add(struct scsi_cmnd *, int); -void scsi_eh_ready_devs(struct Scsi_Host *shost, - struct list_head *work_q, - struct list_head *done_q); -int scsi_eh_get_sense(struct list_head *work_q, - struct list_head *done_q); -int scsi_noretry_cmd(struct scsi_cmnd *scmd); - -/* scsi_lib.c */ -extern int scsi_maybe_unblock_host(struct scsi_device *sdev); -extern void scsi_device_unbusy(struct scsi_device *sdev); -extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason); -extern void scsi_next_command(struct scsi_cmnd *cmd); -extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); -extern void scsi_run_host_queues(struct Scsi_Host *shost); -extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev); -extern void scsi_free_queue(struct request_queue *q); -extern int scsi_init_queue(void); -extern void scsi_exit_queue(void); -struct request_queue; -struct request; -extern struct kmem_cache *scsi_sdb_cache; - -/* scsi_proc.c */ -#ifdef CONFIG_SCSI_PROC_FS -extern void scsi_proc_hostdir_add(struct scsi_host_template *); -extern void scsi_proc_hostdir_rm(struct scsi_host_template *); -extern void scsi_proc_host_add(struct Scsi_Host *); -extern void scsi_proc_host_rm(struct Scsi_Host *); -extern int scsi_init_procfs(void); -extern void scsi_exit_procfs(void); -#else -# define scsi_proc_hostdir_add(sht) do { } while (0) -# define scsi_proc_hostdir_rm(sht) do { } while (0) -# define scsi_proc_host_add(shost) do { } while (0) -# define scsi_proc_host_rm(shost) do { } while (0) -# define scsi_init_procfs() (0) -# define scsi_exit_procfs() do { } while (0) -#endif /* CONFIG_PROC_FS */ - -/* scsi_scan.c */ -extern int scsi_complete_async_scans(void); -extern int scsi_scan_host_selected(struct Scsi_Host *, unsigned int, - unsigned int, unsigned int, int); -extern void scsi_forget_host(struct Scsi_Host *); -extern void scsi_rescan_device(struct device *); - -/* scsi_sysctl.c */ -#ifdef CONFIG_SYSCTL -extern int scsi_init_sysctl(void); -extern void scsi_exit_sysctl(void); -#else -# define scsi_init_sysctl() (0) -# define scsi_exit_sysctl() do { } while (0) -#endif /* CONFIG_SYSCTL */ - -/* scsi_sysfs.c */ -extern int scsi_sysfs_add_sdev(struct scsi_device *); -extern int scsi_sysfs_add_host(struct Scsi_Host *); -extern int scsi_sysfs_register(void); -extern void scsi_sysfs_unregister(void); -extern void scsi_sysfs_device_initialize(struct scsi_device *); -extern int scsi_sysfs_target_initialize(struct scsi_device *); -extern struct scsi_transport_template blank_transport_template; -extern void __scsi_remove_device(struct scsi_device *); - -extern struct bus_type scsi_bus_type; -extern const struct attribute_group *scsi_sysfs_shost_attr_groups[]; - -/* scsi_netlink.c */ -#ifdef CONFIG_SCSI_NETLINK -extern void scsi_netlink_init(void); -extern void scsi_netlink_exit(void); -extern struct sock *scsi_nl_sock; -#else -static inline void scsi_netlink_init(void) {} -static inline void scsi_netlink_exit(void) {} -#endif - -/* scsi_pm.c */ -#ifdef CONFIG_PM -extern const struct dev_pm_ops scsi_bus_pm_ops; -#endif -#ifdef CONFIG_PM_RUNTIME -extern void scsi_autopm_get_target(struct scsi_target *); -extern void scsi_autopm_put_target(struct scsi_target *); -extern int scsi_autopm_get_host(struct Scsi_Host *); -extern void scsi_autopm_put_host(struct Scsi_Host *); -#else -static inline void scsi_autopm_get_target(struct scsi_target *t) {} -static inline void scsi_autopm_put_target(struct scsi_target *t) {} -static inline int scsi_autopm_get_host(struct Scsi_Host *h) { return 0; } -static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} -#endif /* CONFIG_PM_RUNTIME */ - -/* - * internal scsi timeout functions: for use by mid-layer and transport - * classes. - */ - -#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT 600 /* units in seconds */ -extern int scsi_internal_device_block(struct scsi_device *sdev); -extern int scsi_internal_device_unblock(struct scsi_device *sdev); - -#endif /* _SCSI_PRIV_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_proc.c b/ANDROID_3.4.5/drivers/scsi/scsi_proc.c deleted file mode 100644 index ad747dc3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_proc.c +++ /dev/null @@ -1,492 +0,0 @@ -/* - * linux/drivers/scsi/scsi_proc.c - * - * The functions in this file provide an interface between - * the PROC file system and the SCSI device drivers - * It is mainly used for debugging, statistics and to pass - * information directly to the lowlevel driver. - * - * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de - * Version: 0.99.8 last change: 95/09/13 - * - * generic command parser provided by: - * Andreas Heilwagen - * - * generic_proc_info() support of xxxx_info() by: - * Michael A. Griffith - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "scsi_priv.h" -#include "scsi_logging.h" - - -/* 4K page size, but our output routines, use some slack for overruns */ -#define PROC_BLOCK_SIZE (3*1024) - -static struct proc_dir_entry *proc_scsi; - -/* Protect sht->present and sht->proc_dir */ -static DEFINE_MUTEX(global_host_template_mutex); - -/** - * proc_scsi_read - handle read from /proc by calling host's proc_info() command - * @buffer: passed to proc_info - * @start: passed to proc_info - * @offset: passed to proc_info - * @length: passed to proc_info - * @eof: returns whether length read was less than requested - * @data: pointer to a &struct Scsi_Host - */ - -static int proc_scsi_read(char *buffer, char **start, off_t offset, - int length, int *eof, void *data) -{ - struct Scsi_Host *shost = data; - int n; - - n = shost->hostt->proc_info(shost, buffer, start, offset, length, 0); - *eof = (n < length); - - return n; -} - -/** - * proc_scsi_write_proc - Handle write to /proc by calling host's proc_info() - * @file: not used - * @buf: source of data to write. - * @count: number of bytes (at most PROC_BLOCK_SIZE) to write. - * @data: pointer to &struct Scsi_Host - */ -static int proc_scsi_write_proc(struct file *file, const char __user *buf, - unsigned long count, void *data) -{ - struct Scsi_Host *shost = data; - ssize_t ret = -ENOMEM; - char *page; - char *start; - - if (count > PROC_BLOCK_SIZE) - return -EOVERFLOW; - - page = (char *)__get_free_page(GFP_KERNEL); - if (page) { - ret = -EFAULT; - if (copy_from_user(page, buf, count)) - goto out; - ret = shost->hostt->proc_info(shost, page, &start, 0, count, 1); - } -out: - free_page((unsigned long)page); - return ret; -} - -/** - * scsi_proc_hostdir_add - Create directory in /proc for a scsi host - * @sht: owner of this directory - * - * Sets sht->proc_dir to the new directory. - */ - -void scsi_proc_hostdir_add(struct scsi_host_template *sht) -{ - if (!sht->proc_info) - return; - - mutex_lock(&global_host_template_mutex); - if (!sht->present++) { - sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi); - if (!sht->proc_dir) - printk(KERN_ERR "%s: proc_mkdir failed for %s\n", - __func__, sht->proc_name); - } - mutex_unlock(&global_host_template_mutex); -} - -/** - * scsi_proc_hostdir_rm - remove directory in /proc for a scsi host - * @sht: owner of directory - */ -void scsi_proc_hostdir_rm(struct scsi_host_template *sht) -{ - if (!sht->proc_info) - return; - - mutex_lock(&global_host_template_mutex); - if (!--sht->present && sht->proc_dir) { - remove_proc_entry(sht->proc_name, proc_scsi); - sht->proc_dir = NULL; - } - mutex_unlock(&global_host_template_mutex); -} - - -/** - * scsi_proc_host_add - Add entry for this host to appropriate /proc dir - * @shost: host to add - */ -void scsi_proc_host_add(struct Scsi_Host *shost) -{ - struct scsi_host_template *sht = shost->hostt; - struct proc_dir_entry *p; - char name[10]; - - if (!sht->proc_dir) - return; - - sprintf(name,"%d", shost->host_no); - p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR, - sht->proc_dir, proc_scsi_read, shost); - if (!p) { - printk(KERN_ERR "%s: Failed to register host %d in" - "%s\n", __func__, shost->host_no, - sht->proc_name); - return; - } - - p->write_proc = proc_scsi_write_proc; -} - -/** - * scsi_proc_host_rm - remove this host's entry from /proc - * @shost: which host - */ -void scsi_proc_host_rm(struct Scsi_Host *shost) -{ - char name[10]; - - if (!shost->hostt->proc_dir) - return; - - sprintf(name,"%d", shost->host_no); - remove_proc_entry(name, shost->hostt->proc_dir); -} -/** - * proc_print_scsidevice - return data about this host - * @dev: A scsi device - * @data: &struct seq_file to output to. - * - * Description: prints Host, Channel, Id, Lun, Vendor, Model, Rev, Type, - * and revision. - */ -static int proc_print_scsidevice(struct device *dev, void *data) -{ - struct scsi_device *sdev; - struct seq_file *s = data; - int i; - - if (!scsi_is_sdev_device(dev)) - goto out; - - sdev = to_scsi_device(dev); - seq_printf(s, - "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", - sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - for (i = 0; i < 8; i++) { - if (sdev->vendor[i] >= 0x20) - seq_printf(s, "%c", sdev->vendor[i]); - else - seq_printf(s, " "); - } - - seq_printf(s, " Model: "); - for (i = 0; i < 16; i++) { - if (sdev->model[i] >= 0x20) - seq_printf(s, "%c", sdev->model[i]); - else - seq_printf(s, " "); - } - - seq_printf(s, " Rev: "); - for (i = 0; i < 4; i++) { - if (sdev->rev[i] >= 0x20) - seq_printf(s, "%c", sdev->rev[i]); - else - seq_printf(s, " "); - } - - seq_printf(s, "\n"); - - seq_printf(s, " Type: %s ", scsi_device_type(sdev->type)); - seq_printf(s, " ANSI SCSI revision: %02x", - sdev->scsi_level - (sdev->scsi_level > 1)); - if (sdev->scsi_level == 2) - seq_printf(s, " CCS\n"); - else - seq_printf(s, "\n"); - -out: - return 0; -} - -/** - * scsi_add_single_device - Respond to user request to probe for/add device - * @host: user-supplied decimal integer - * @channel: user-supplied decimal integer - * @id: user-supplied decimal integer - * @lun: user-supplied decimal integer - * - * Description: called by writing "scsi add-single-device" to /proc/scsi/scsi. - * - * does scsi_host_lookup() and either user_scan() if that transport - * type supports it, or else scsi_scan_host_selected() - * - * Note: this seems to be aimed exclusively at SCSI parallel busses. - */ - -static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) -{ - struct Scsi_Host *shost; - int error = -ENXIO; - - shost = scsi_host_lookup(host); - if (!shost) - return error; - - if (shost->transportt->user_scan) - error = shost->transportt->user_scan(shost, channel, id, lun); - else - error = scsi_scan_host_selected(shost, channel, id, lun, 1); - scsi_host_put(shost); - return error; -} - -/** - * scsi_remove_single_device - Respond to user request to remove a device - * @host: user-supplied decimal integer - * @channel: user-supplied decimal integer - * @id: user-supplied decimal integer - * @lun: user-supplied decimal integer - * - * Description: called by writing "scsi remove-single-device" to - * /proc/scsi/scsi. Does a scsi_device_lookup() and scsi_remove_device() - */ -static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun) -{ - struct scsi_device *sdev; - struct Scsi_Host *shost; - int error = -ENXIO; - - shost = scsi_host_lookup(host); - if (!shost) - return error; - sdev = scsi_device_lookup(shost, channel, id, lun); - if (sdev) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - error = 0; - } - - scsi_host_put(shost); - return error; -} - -/** - * proc_scsi_write - handle writes to /proc/scsi/scsi - * @file: not used - * @buf: buffer to write - * @length: length of buf, at most PAGE_SIZE - * @ppos: not used - * - * Description: this provides a legacy mechanism to add or remove devices by - * Host, Channel, ID, and Lun. To use, - * "echo 'scsi add-single-device 0 1 2 3' > /proc/scsi/scsi" or - * "echo 'scsi remove-single-device 0 1 2 3' > /proc/scsi/scsi" with - * "0 1 2 3" replaced by the Host, Channel, Id, and Lun. - * - * Note: this seems to be aimed at parallel SCSI. Most modern busses (USB, - * SATA, Firewire, Fibre Channel, etc) dynamically assign these values to - * provide a unique identifier and nothing more. - */ - - -static ssize_t proc_scsi_write(struct file *file, const char __user *buf, - size_t length, loff_t *ppos) -{ - int host, channel, id, lun; - char *buffer, *p; - int err; - - if (!buf || length > PAGE_SIZE) - return -EINVAL; - - buffer = (char *)__get_free_page(GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - err = -EFAULT; - if (copy_from_user(buffer, buf, length)) - goto out; - - err = -EINVAL; - if (length < PAGE_SIZE) - buffer[length] = '\0'; - else if (buffer[PAGE_SIZE-1]) - goto out; - - /* - * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi - * with "0 1 2 3" replaced by your "Host Channel Id Lun". - */ - if (!strncmp("scsi add-single-device", buffer, 22)) { - p = buffer + 23; - - host = simple_strtoul(p, &p, 0); - channel = simple_strtoul(p + 1, &p, 0); - id = simple_strtoul(p + 1, &p, 0); - lun = simple_strtoul(p + 1, &p, 0); - - err = scsi_add_single_device(host, channel, id, lun); - - /* - * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi - * with "0 1 2 3" replaced by your "Host Channel Id Lun". - */ - } else if (!strncmp("scsi remove-single-device", buffer, 25)) { - p = buffer + 26; - - host = simple_strtoul(p, &p, 0); - channel = simple_strtoul(p + 1, &p, 0); - id = simple_strtoul(p + 1, &p, 0); - lun = simple_strtoul(p + 1, &p, 0); - - err = scsi_remove_single_device(host, channel, id, lun); - } - - /* - * convert success returns so that we return the - * number of bytes consumed. - */ - if (!err) - err = length; - - out: - free_page((unsigned long)buffer); - return err; -} - -static int always_match(struct device *dev, void *data) -{ - return 1; -} - -static inline struct device *next_scsi_device(struct device *start) -{ - struct device *next = bus_find_device(&scsi_bus_type, start, NULL, - always_match); - put_device(start); - return next; -} - -static void *scsi_seq_start(struct seq_file *sfile, loff_t *pos) -{ - struct device *dev = NULL; - loff_t n = *pos; - - while ((dev = next_scsi_device(dev))) { - if (!n--) - break; - sfile->private++; - } - return dev; -} - -static void *scsi_seq_next(struct seq_file *sfile, void *v, loff_t *pos) -{ - (*pos)++; - sfile->private++; - return next_scsi_device(v); -} - -static void scsi_seq_stop(struct seq_file *sfile, void *v) -{ - put_device(v); -} - -static int scsi_seq_show(struct seq_file *sfile, void *dev) -{ - if (!sfile->private) - seq_puts(sfile, "Attached devices:\n"); - - return proc_print_scsidevice(dev, sfile); -} - -static const struct seq_operations scsi_seq_ops = { - .start = scsi_seq_start, - .next = scsi_seq_next, - .stop = scsi_seq_stop, - .show = scsi_seq_show -}; - -/** - * proc_scsi_open - glue function - * @inode: not used - * @file: passed to single_open() - * - * Associates proc_scsi_show with this file - */ -static int proc_scsi_open(struct inode *inode, struct file *file) -{ - /* - * We don't really need this for the write case but it doesn't - * harm either. - */ - return seq_open(file, &scsi_seq_ops); -} - -static const struct file_operations proc_scsi_operations = { - .owner = THIS_MODULE, - .open = proc_scsi_open, - .read = seq_read, - .write = proc_scsi_write, - .llseek = seq_lseek, - .release = seq_release, -}; - -/** - * scsi_init_procfs - create scsi and scsi/scsi in procfs - */ -int __init scsi_init_procfs(void) -{ - struct proc_dir_entry *pde; - - proc_scsi = proc_mkdir("scsi", NULL); - if (!proc_scsi) - goto err1; - - pde = proc_create("scsi/scsi", 0, NULL, &proc_scsi_operations); - if (!pde) - goto err2; - - return 0; - -err2: - remove_proc_entry("scsi", NULL); -err1: - return -ENOMEM; -} - -/** - * scsi_exit_procfs - Remove scsi/scsi and scsi from procfs - */ -void scsi_exit_procfs(void) -{ - remove_proc_entry("scsi/scsi", NULL); - remove_proc_entry("scsi", NULL); -} diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_sas_internal.h b/ANDROID_3.4.5/drivers/scsi/scsi_sas_internal.h deleted file mode 100644 index 6266a5d7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_sas_internal.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _SCSI_SAS_INTERNAL_H -#define _SCSI_SAS_INTERNAL_H - -#define SAS_HOST_ATTRS 0 -#define SAS_PHY_ATTRS 17 -#define SAS_PORT_ATTRS 1 -#define SAS_RPORT_ATTRS 7 -#define SAS_END_DEV_ATTRS 5 -#define SAS_EXPANDER_ATTRS 7 - -struct sas_internal { - struct scsi_transport_template t; - struct sas_function_template *f; - struct sas_domain_function_template *dft; - - struct device_attribute private_host_attrs[SAS_HOST_ATTRS]; - struct device_attribute private_phy_attrs[SAS_PHY_ATTRS]; - struct device_attribute private_port_attrs[SAS_PORT_ATTRS]; - struct device_attribute private_rphy_attrs[SAS_RPORT_ATTRS]; - struct device_attribute private_end_dev_attrs[SAS_END_DEV_ATTRS]; - struct device_attribute private_expander_attrs[SAS_EXPANDER_ATTRS]; - - struct transport_container phy_attr_cont; - struct transport_container port_attr_cont; - struct transport_container rphy_attr_cont; - struct transport_container end_dev_attr_cont; - struct transport_container expander_attr_cont; - - /* - * The array of null terminated pointers to attributes - * needed by scsi_sysfs.c - */ - struct device_attribute *host_attrs[SAS_HOST_ATTRS + 1]; - struct device_attribute *phy_attrs[SAS_PHY_ATTRS + 1]; - struct device_attribute *port_attrs[SAS_PORT_ATTRS + 1]; - struct device_attribute *rphy_attrs[SAS_RPORT_ATTRS + 1]; - struct device_attribute *end_dev_attrs[SAS_END_DEV_ATTRS + 1]; - struct device_attribute *expander_attrs[SAS_EXPANDER_ATTRS + 1]; -}; -#define to_sas_internal(tmpl) container_of(tmpl, struct sas_internal, t) - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_scan.c b/ANDROID_3.4.5/drivers/scsi/scsi_scan.c deleted file mode 100644 index 01b03744..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_scan.c +++ /dev/null @@ -1,1953 +0,0 @@ -/* - * scsi_scan.c - * - * Copyright (C) 2000 Eric Youngdale, - * Copyright (C) 2002 Patrick Mansfield - * - * The general scanning/probing algorithm is as follows, exceptions are - * made to it depending on device specific flags, compilation options, and - * global variable (boot or module load time) settings. - * - * A specific LUN is scanned via an INQUIRY command; if the LUN has a - * device attached, a scsi_device is allocated and setup for it. - * - * For every id of every channel on the given host: - * - * Scan LUN 0; if the target responds to LUN 0 (even if there is no - * device or storage attached to LUN 0): - * - * If LUN 0 has a device attached, allocate and setup a - * scsi_device for it. - * - * If target is SCSI-3 or up, issue a REPORT LUN, and scan - * all of the LUNs returned by the REPORT LUN; else, - * sequentially scan LUNs up until some maximum is reached, - * or a LUN is seen that cannot have a device attached to it. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi_priv.h" -#include "scsi_logging.h" - -#define ALLOC_FAILURE_MSG KERN_ERR "%s: Allocation failure during" \ - " SCSI scanning, some SCSI devices might not be configured\n" - -/* - * Default timeout - */ -#define SCSI_TIMEOUT (2*HZ) - -/* - * Prefix values for the SCSI id's (stored in sysfs name field) - */ -#define SCSI_UID_SER_NUM 'S' -#define SCSI_UID_UNKNOWN 'Z' - -/* - * Return values of some of the scanning functions. - * - * SCSI_SCAN_NO_RESPONSE: no valid response received from the target, this - * includes allocation or general failures preventing IO from being sent. - * - * SCSI_SCAN_TARGET_PRESENT: target responded, but no device is available - * on the given LUN. - * - * SCSI_SCAN_LUN_PRESENT: target responded, and a device is available on a - * given LUN. - */ -#define SCSI_SCAN_NO_RESPONSE 0 -#define SCSI_SCAN_TARGET_PRESENT 1 -#define SCSI_SCAN_LUN_PRESENT 2 - -static const char *scsi_null_device_strs = "nullnullnullnull"; - -#define MAX_SCSI_LUNS 512 - -#ifdef CONFIG_SCSI_MULTI_LUN -static unsigned int max_scsi_luns = MAX_SCSI_LUNS; -#else -static unsigned int max_scsi_luns = 1; -#endif - -module_param_named(max_luns, max_scsi_luns, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(max_luns, - "last scsi LUN (should be between 1 and 2^32-1)"); - -#ifdef CONFIG_SCSI_SCAN_ASYNC -#define SCSI_SCAN_TYPE_DEFAULT "async" -#else -#define SCSI_SCAN_TYPE_DEFAULT "sync" -#endif - -static char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT; - -module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO); -MODULE_PARM_DESC(scan, "sync, async or none"); - -/* - * max_scsi_report_luns: the maximum number of LUNS that will be - * returned from the REPORT LUNS command. 8 times this value must - * be allocated. In theory this could be up to an 8 byte value, but - * in practice, the maximum number of LUNs suppored by any device - * is about 16k. - */ -static unsigned int max_scsi_report_luns = 511; - -module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(max_report_luns, - "REPORT LUNS maximum number of LUNS received (should be" - " between 1 and 16384)"); - -static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18; - -module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(inq_timeout, - "Timeout (in seconds) waiting for devices to answer INQUIRY." - " Default is 20. Some devices may need more; most need less."); - -/* This lock protects only this list */ -static DEFINE_SPINLOCK(async_scan_lock); -static LIST_HEAD(scanning_hosts); - -struct async_scan_data { - struct list_head list; - struct Scsi_Host *shost; - struct completion prev_finished; -}; - -/** - * scsi_complete_async_scans - Wait for asynchronous scans to complete - * - * When this function returns, any host which started scanning before - * this function was called will have finished its scan. Hosts which - * started scanning after this function was called may or may not have - * finished. - */ -int scsi_complete_async_scans(void) -{ - struct async_scan_data *data; - - do { - if (list_empty(&scanning_hosts)) - return 0; - /* If we can't get memory immediately, that's OK. Just - * sleep a little. Even if we never get memory, the async - * scans will finish eventually. - */ - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (!data) - msleep(1); - } while (!data); - - data->shost = NULL; - init_completion(&data->prev_finished); - - spin_lock(&async_scan_lock); - /* Check that there's still somebody else on the list */ - if (list_empty(&scanning_hosts)) - goto done; - list_add_tail(&data->list, &scanning_hosts); - spin_unlock(&async_scan_lock); - - printk(KERN_INFO "scsi: waiting for bus probes to complete ...\n"); - wait_for_completion(&data->prev_finished); - - spin_lock(&async_scan_lock); - list_del(&data->list); - if (!list_empty(&scanning_hosts)) { - struct async_scan_data *next = list_entry(scanning_hosts.next, - struct async_scan_data, list); - complete(&next->prev_finished); - } - done: - spin_unlock(&async_scan_lock); - - kfree(data); - return 0; -} - -/* Only exported for the benefit of scsi_wait_scan */ -EXPORT_SYMBOL_GPL(scsi_complete_async_scans); - -#ifndef MODULE -/* - * For async scanning we need to wait for all the scans to complete before - * trying to mount the root fs. Otherwise non-modular drivers may not be ready - * yet. - */ -late_initcall(scsi_complete_async_scans); -#endif - -/** - * scsi_unlock_floptical - unlock device via a special MODE SENSE command - * @sdev: scsi device to send command to - * @result: area to store the result of the MODE SENSE - * - * Description: - * Send a vendor specific MODE SENSE (not a MODE SELECT) command. - * Called for BLIST_KEY devices. - **/ -static void scsi_unlock_floptical(struct scsi_device *sdev, - unsigned char *result) -{ - unsigned char scsi_cmd[MAX_COMMAND_SIZE]; - - printk(KERN_NOTICE "scsi: unlocking floptical drive\n"); - scsi_cmd[0] = MODE_SENSE; - scsi_cmd[1] = 0; - scsi_cmd[2] = 0x2e; - scsi_cmd[3] = 0; - scsi_cmd[4] = 0x2a; /* size */ - scsi_cmd[5] = 0; - scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL, - SCSI_TIMEOUT, 3, NULL); -} - -/** - * scsi_alloc_sdev - allocate and setup a scsi_Device - * @starget: which target to allocate a &scsi_device for - * @lun: which lun - * @hostdata: usually NULL and set by ->slave_alloc instead - * - * Description: - * Allocate, initialize for io, and return a pointer to a scsi_Device. - * Stores the @shost, @channel, @id, and @lun in the scsi_Device, and - * adds scsi_Device to the appropriate list. - * - * Return value: - * scsi_Device pointer, or NULL on failure. - **/ -static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget, - unsigned int lun, void *hostdata) -{ - struct scsi_device *sdev; - int display_failure_msg = 1, ret; - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - extern void scsi_evt_thread(struct work_struct *work); - extern void scsi_requeue_run_queue(struct work_struct *work); - - sdev = kzalloc(sizeof(*sdev) + shost->transportt->device_size, - GFP_ATOMIC); - if (!sdev) - goto out; - - sdev->vendor = scsi_null_device_strs; - sdev->model = scsi_null_device_strs; - sdev->rev = scsi_null_device_strs; - sdev->host = shost; - sdev->queue_ramp_up_period = SCSI_DEFAULT_RAMP_UP_PERIOD; - sdev->id = starget->id; - sdev->lun = lun; - sdev->channel = starget->channel; - sdev->sdev_state = SDEV_CREATED; - INIT_LIST_HEAD(&sdev->siblings); - INIT_LIST_HEAD(&sdev->same_target_siblings); - INIT_LIST_HEAD(&sdev->cmd_list); - INIT_LIST_HEAD(&sdev->starved_entry); - INIT_LIST_HEAD(&sdev->event_list); - spin_lock_init(&sdev->list_lock); - INIT_WORK(&sdev->event_work, scsi_evt_thread); - INIT_WORK(&sdev->requeue_work, scsi_requeue_run_queue); - - sdev->sdev_gendev.parent = get_device(&starget->dev); - sdev->sdev_target = starget; - - /* usually NULL and set by ->slave_alloc instead */ - sdev->hostdata = hostdata; - - /* if the device needs this changing, it may do so in the - * slave_configure function */ - sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED; - - /* - * Some low level driver could use device->type - */ - sdev->type = -1; - - /* - * Assume that the device will have handshaking problems, - * and then fix this field later if it turns out it - * doesn't - */ - sdev->borken = 1; - - sdev->request_queue = scsi_alloc_queue(sdev); - if (!sdev->request_queue) { - /* release fn is set up in scsi_sysfs_device_initialise, so - * have to free and put manually here */ - put_device(&starget->dev); - kfree(sdev); - goto out; - } - WARN_ON_ONCE(!blk_get_queue(sdev->request_queue)); - sdev->request_queue->queuedata = sdev; - scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun); - - scsi_sysfs_device_initialize(sdev); - - if (shost->hostt->slave_alloc) { - ret = shost->hostt->slave_alloc(sdev); - if (ret) { - /* - * if LLDD reports slave not present, don't clutter - * console with alloc failure messages - */ - if (ret == -ENXIO) - display_failure_msg = 0; - goto out_device_destroy; - } - } - - return sdev; - -out_device_destroy: - __scsi_remove_device(sdev); -out: - if (display_failure_msg) - printk(ALLOC_FAILURE_MSG, __func__); - return NULL; -} - -static void scsi_target_destroy(struct scsi_target *starget) -{ - struct device *dev = &starget->dev; - struct Scsi_Host *shost = dev_to_shost(dev->parent); - unsigned long flags; - - transport_destroy_device(dev); - spin_lock_irqsave(shost->host_lock, flags); - if (shost->hostt->target_destroy) - shost->hostt->target_destroy(starget); - list_del_init(&starget->siblings); - spin_unlock_irqrestore(shost->host_lock, flags); - put_device(dev); -} - -static void scsi_target_dev_release(struct device *dev) -{ - struct device *parent = dev->parent; - struct scsi_target *starget = to_scsi_target(dev); - - kfree(starget); - put_device(parent); -} - -static struct device_type scsi_target_type = { - .name = "scsi_target", - .release = scsi_target_dev_release, -}; - -int scsi_is_target_device(const struct device *dev) -{ - return dev->type == &scsi_target_type; -} -EXPORT_SYMBOL(scsi_is_target_device); - -static struct scsi_target *__scsi_find_target(struct device *parent, - int channel, uint id) -{ - struct scsi_target *starget, *found_starget = NULL; - struct Scsi_Host *shost = dev_to_shost(parent); - /* - * Search for an existing target for this sdev. - */ - list_for_each_entry(starget, &shost->__targets, siblings) { - if (starget->id == id && - starget->channel == channel) { - found_starget = starget; - break; - } - } - if (found_starget) - get_device(&found_starget->dev); - - return found_starget; -} - -/** - * scsi_alloc_target - allocate a new or find an existing target - * @parent: parent of the target (need not be a scsi host) - * @channel: target channel number (zero if no channels) - * @id: target id number - * - * Return an existing target if one exists, provided it hasn't already - * gone into STARGET_DEL state, otherwise allocate a new target. - * - * The target is returned with an incremented reference, so the caller - * is responsible for both reaping and doing a last put - */ -static struct scsi_target *scsi_alloc_target(struct device *parent, - int channel, uint id) -{ - struct Scsi_Host *shost = dev_to_shost(parent); - struct device *dev = NULL; - unsigned long flags; - const int size = sizeof(struct scsi_target) - + shost->transportt->target_size; - struct scsi_target *starget; - struct scsi_target *found_target; - int error; - - starget = kzalloc(size, GFP_KERNEL); - if (!starget) { - printk(KERN_ERR "%s: allocation failure\n", __func__); - return NULL; - } - dev = &starget->dev; - device_initialize(dev); - starget->reap_ref = 1; - dev->parent = get_device(parent); - dev_set_name(dev, "target%d:%d:%d", shost->host_no, channel, id); - dev->bus = &scsi_bus_type; - dev->type = &scsi_target_type; - starget->id = id; - starget->channel = channel; - starget->can_queue = 0; - INIT_LIST_HEAD(&starget->siblings); - INIT_LIST_HEAD(&starget->devices); - starget->state = STARGET_CREATED; - starget->scsi_level = SCSI_2; - starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED; - retry: - spin_lock_irqsave(shost->host_lock, flags); - - found_target = __scsi_find_target(parent, channel, id); - if (found_target) - goto found; - - list_add_tail(&starget->siblings, &shost->__targets); - spin_unlock_irqrestore(shost->host_lock, flags); - /* allocate and add */ - transport_setup_device(dev); - if (shost->hostt->target_alloc) { - error = shost->hostt->target_alloc(starget); - - if(error) { - dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error); - /* don't want scsi_target_reap to do the final - * put because it will be under the host lock */ - scsi_target_destroy(starget); - return NULL; - } - } - get_device(dev); - - return starget; - - found: - found_target->reap_ref++; - spin_unlock_irqrestore(shost->host_lock, flags); - if (found_target->state != STARGET_DEL) { - put_device(dev); - return found_target; - } - /* Unfortunately, we found a dying target; need to - * wait until it's dead before we can get a new one */ - put_device(&found_target->dev); - flush_scheduled_work(); - goto retry; -} - -static void scsi_target_reap_usercontext(struct work_struct *work) -{ - struct scsi_target *starget = - container_of(work, struct scsi_target, ew.work); - - transport_remove_device(&starget->dev); - device_del(&starget->dev); - scsi_target_destroy(starget); -} - -/** - * scsi_target_reap - check to see if target is in use and destroy if not - * @starget: target to be checked - * - * This is used after removing a LUN or doing a last put of the target - * it checks atomically that nothing is using the target and removes - * it if so. - */ -void scsi_target_reap(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - unsigned long flags; - enum scsi_target_state state; - int empty = 0; - - spin_lock_irqsave(shost->host_lock, flags); - state = starget->state; - if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { - empty = 1; - starget->state = STARGET_DEL; - } - spin_unlock_irqrestore(shost->host_lock, flags); - - if (!empty) - return; - - BUG_ON(state == STARGET_DEL); - if (state == STARGET_CREATED) - scsi_target_destroy(starget); - else - execute_in_process_context(scsi_target_reap_usercontext, - &starget->ew); -} - -/** - * sanitize_inquiry_string - remove non-graphical chars from an INQUIRY result string - * @s: INQUIRY result string to sanitize - * @len: length of the string - * - * Description: - * The SCSI spec says that INQUIRY vendor, product, and revision - * strings must consist entirely of graphic ASCII characters, - * padded on the right with spaces. Since not all devices obey - * this rule, we will replace non-graphic or non-ASCII characters - * with spaces. Exception: a NUL character is interpreted as a - * string terminator, so all the following characters are set to - * spaces. - **/ -static void sanitize_inquiry_string(unsigned char *s, int len) -{ - int terminated = 0; - - for (; len > 0; (--len, ++s)) { - if (*s == 0) - terminated = 1; - if (terminated || *s < 0x20 || *s > 0x7e) - *s = ' '; - } -} - -/** - * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY - * @sdev: scsi_device to probe - * @inq_result: area to store the INQUIRY result - * @result_len: len of inq_result - * @bflags: store any bflags found here - * - * Description: - * Probe the lun associated with @req using a standard SCSI INQUIRY; - * - * If the INQUIRY is successful, zero is returned and the - * INQUIRY data is in @inq_result; the scsi_level and INQUIRY length - * are copied to the scsi_device any flags value is stored in *@bflags. - **/ -static int scsi_probe_lun(struct scsi_device *sdev, unsigned char *inq_result, - int result_len, int *bflags) -{ - unsigned char scsi_cmd[MAX_COMMAND_SIZE]; - int first_inquiry_len, try_inquiry_len, next_inquiry_len; - int response_len = 0; - int pass, count, result; - struct scsi_sense_hdr sshdr; - - *bflags = 0; - - /* Perform up to 3 passes. The first pass uses a conservative - * transfer length of 36 unless sdev->inquiry_len specifies a - * different value. */ - first_inquiry_len = sdev->inquiry_len ? sdev->inquiry_len : 36; - try_inquiry_len = first_inquiry_len; - pass = 1; - - next_pass: - SCSI_LOG_SCAN_BUS(3, sdev_printk(KERN_INFO, sdev, - "scsi scan: INQUIRY pass %d length %d\n", - pass, try_inquiry_len)); - - /* Each pass gets up to three chances to ignore Unit Attention */ - for (count = 0; count < 3; ++count) { - int resid; - - memset(scsi_cmd, 0, 6); - scsi_cmd[0] = INQUIRY; - scsi_cmd[4] = (unsigned char) try_inquiry_len; - - memset(inq_result, 0, try_inquiry_len); - - result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, - inq_result, try_inquiry_len, &sshdr, - HZ / 2 + HZ * scsi_inq_timeout, 3, - &resid); - - SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s " - "with code 0x%x\n", - result ? "failed" : "successful", result)); - - if (result) { - /* - * not-ready to ready transition [asc/ascq=0x28/0x0] - * or power-on, reset [asc/ascq=0x29/0x0], continue. - * INQUIRY should not yield UNIT_ATTENTION - * but many buggy devices do so anyway. - */ - if ((driver_byte(result) & DRIVER_SENSE) && - scsi_sense_valid(&sshdr)) { - if ((sshdr.sense_key == UNIT_ATTENTION) && - ((sshdr.asc == 0x28) || - (sshdr.asc == 0x29)) && - (sshdr.ascq == 0)) - continue; - } - } else { - /* - * if nothing was transferred, we try - * again. It's a workaround for some USB - * devices. - */ - if (resid == try_inquiry_len) - continue; - } - break; - } - - if (result == 0) { - sanitize_inquiry_string(&inq_result[8], 8); - sanitize_inquiry_string(&inq_result[16], 16); - sanitize_inquiry_string(&inq_result[32], 4); - - response_len = inq_result[4] + 5; - if (response_len > 255) - response_len = first_inquiry_len; /* sanity */ - - /* - * Get any flags for this device. - * - * XXX add a bflags to scsi_device, and replace the - * corresponding bit fields in scsi_device, so bflags - * need not be passed as an argument. - */ - *bflags = scsi_get_device_flags(sdev, &inq_result[8], - &inq_result[16]); - - /* When the first pass succeeds we gain information about - * what larger transfer lengths might work. */ - if (pass == 1) { - if (BLIST_INQUIRY_36 & *bflags) - next_inquiry_len = 36; - else if (BLIST_INQUIRY_58 & *bflags) - next_inquiry_len = 58; - else if (sdev->inquiry_len) - next_inquiry_len = sdev->inquiry_len; - else - next_inquiry_len = response_len; - - /* If more data is available perform the second pass */ - if (next_inquiry_len > try_inquiry_len) { - try_inquiry_len = next_inquiry_len; - pass = 2; - goto next_pass; - } - } - - } else if (pass == 2) { - printk(KERN_INFO "scsi scan: %d byte inquiry failed. " - "Consider BLIST_INQUIRY_36 for this device\n", - try_inquiry_len); - - /* If this pass failed, the third pass goes back and transfers - * the same amount as we successfully got in the first pass. */ - try_inquiry_len = first_inquiry_len; - pass = 3; - goto next_pass; - } - - /* If the last transfer attempt got an error, assume the - * peripheral doesn't exist or is dead. */ - if (result) - return -EIO; - - /* Don't report any more data than the device says is valid */ - sdev->inquiry_len = min(try_inquiry_len, response_len); - - /* - * XXX Abort if the response length is less than 36? If less than - * 32, the lookup of the device flags (above) could be invalid, - * and it would be possible to take an incorrect action - we do - * not want to hang because of a short INQUIRY. On the flip side, - * if the device is spun down or becoming ready (and so it gives a - * short INQUIRY), an abort here prevents any further use of the - * device, including spin up. - * - * On the whole, the best approach seems to be to assume the first - * 36 bytes are valid no matter what the device says. That's - * better than copying < 36 bytes to the inquiry-result buffer - * and displaying garbage for the Vendor, Product, or Revision - * strings. - */ - if (sdev->inquiry_len < 36) { - printk(KERN_INFO "scsi scan: INQUIRY result too short (%d)," - " using 36\n", sdev->inquiry_len); - sdev->inquiry_len = 36; - } - - /* - * Related to the above issue: - * - * XXX Devices (disk or all?) should be sent a TEST UNIT READY, - * and if not ready, sent a START_STOP to start (maybe spin up) and - * then send the INQUIRY again, since the INQUIRY can change after - * a device is initialized. - * - * Ideally, start a device if explicitly asked to do so. This - * assumes that a device is spun up on power on, spun down on - * request, and then spun up on request. - */ - - /* - * The scanning code needs to know the scsi_level, even if no - * device is attached at LUN 0 (SCSI_SCAN_TARGET_PRESENT) so - * non-zero LUNs can be scanned. - */ - sdev->scsi_level = inq_result[2] & 0x07; - if (sdev->scsi_level >= 2 || - (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1)) - sdev->scsi_level++; - sdev->sdev_target->scsi_level = sdev->scsi_level; - - return 0; -} - -/** - * scsi_add_lun - allocate and fully initialze a scsi_device - * @sdev: holds information to be stored in the new scsi_device - * @inq_result: holds the result of a previous INQUIRY to the LUN - * @bflags: black/white list flag - * @async: 1 if this device is being scanned asynchronously - * - * Description: - * Initialize the scsi_device @sdev. Optionally set fields based - * on values in *@bflags. - * - * Return: - * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device - * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized - **/ -static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result, - int *bflags, int async) -{ - int ret; - - /* - * XXX do not save the inquiry, since it can change underneath us, - * save just vendor/model/rev. - * - * Rather than save it and have an ioctl that retrieves the saved - * value, have an ioctl that executes the same INQUIRY code used - * in scsi_probe_lun, let user level programs doing INQUIRY - * scanning run at their own risk, or supply a user level program - * that can correctly scan. - */ - - /* - * Copy at least 36 bytes of INQUIRY data, so that we don't - * dereference unallocated memory when accessing the Vendor, - * Product, and Revision strings. Badly behaved devices may set - * the INQUIRY Additional Length byte to a small value, indicating - * these strings are invalid, but often they contain plausible data - * nonetheless. It doesn't matter if the device sent < 36 bytes - * total, since scsi_probe_lun() initializes inq_result with 0s. - */ - sdev->inquiry = kmemdup(inq_result, - max_t(size_t, sdev->inquiry_len, 36), - GFP_ATOMIC); - if (sdev->inquiry == NULL) - return SCSI_SCAN_NO_RESPONSE; - - sdev->vendor = (char *) (sdev->inquiry + 8); - sdev->model = (char *) (sdev->inquiry + 16); - sdev->rev = (char *) (sdev->inquiry + 32); - - if (*bflags & BLIST_ISROM) { - sdev->type = TYPE_ROM; - sdev->removable = 1; - } else { - sdev->type = (inq_result[0] & 0x1f); - sdev->removable = (inq_result[1] & 0x80) >> 7; - } - - switch (sdev->type) { - case TYPE_RBC: - case TYPE_TAPE: - case TYPE_DISK: - case TYPE_PRINTER: - case TYPE_MOD: - case TYPE_PROCESSOR: - case TYPE_SCANNER: - case TYPE_MEDIUM_CHANGER: - case TYPE_ENCLOSURE: - case TYPE_COMM: - case TYPE_RAID: - case TYPE_OSD: - sdev->writeable = 1; - break; - case TYPE_ROM: - case TYPE_WORM: - sdev->writeable = 0; - break; - default: - printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type); - } - - if (sdev->type == TYPE_RBC || sdev->type == TYPE_ROM) { - /* RBC and MMC devices can return SCSI-3 compliance and yet - * still not support REPORT LUNS, so make them act as - * BLIST_NOREPORTLUN unless BLIST_REPORTLUN2 is - * specifically set */ - if ((*bflags & BLIST_REPORTLUN2) == 0) - *bflags |= BLIST_NOREPORTLUN; - } - - /* - * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI - * spec says: The device server is capable of supporting the - * specified peripheral device type on this logical unit. However, - * the physical device is not currently connected to this logical - * unit. - * - * The above is vague, as it implies that we could treat 001 and - * 011 the same. Stay compatible with previous code, and create a - * scsi_device for a PQ of 1 - * - * Don't set the device offline here; rather let the upper - * level drivers eval the PQ to decide whether they should - * attach. So remove ((inq_result[0] >> 5) & 7) == 1 check. - */ - - sdev->inq_periph_qual = (inq_result[0] >> 5) & 7; - sdev->lockable = sdev->removable; - sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2); - - if (sdev->scsi_level >= SCSI_3 || - (sdev->inquiry_len > 56 && inq_result[56] & 0x04)) - sdev->ppr = 1; - if (inq_result[7] & 0x60) - sdev->wdtr = 1; - if (inq_result[7] & 0x10) - sdev->sdtr = 1; - - sdev_printk(KERN_NOTICE, sdev, "%s %.8s %.16s %.4s PQ: %d " - "ANSI: %d%s\n", scsi_device_type(sdev->type), - sdev->vendor, sdev->model, sdev->rev, - sdev->inq_periph_qual, inq_result[2] & 0x07, - (inq_result[3] & 0x0f) == 1 ? " CCS" : ""); - - if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) && - !(*bflags & BLIST_NOTQ)) - sdev->tagged_supported = 1; - - /* - * Some devices (Texel CD ROM drives) have handshaking problems - * when used with the Seagate controllers. borken is initialized - * to 1, and then set it to 0 here. - */ - if ((*bflags & BLIST_BORKEN) == 0) - sdev->borken = 0; - - if (*bflags & BLIST_NO_ULD_ATTACH) - sdev->no_uld_attach = 1; - - /* - * Apparently some really broken devices (contrary to the SCSI - * standards) need to be selected without asserting ATN - */ - if (*bflags & BLIST_SELECT_NO_ATN) - sdev->select_no_atn = 1; - - /* - * Maximum 512 sector transfer length - * broken RA4x00 Compaq Disk Array - */ - if (*bflags & BLIST_MAX_512) - blk_queue_max_hw_sectors(sdev->request_queue, 512); - - /* - * Some devices may not want to have a start command automatically - * issued when a device is added. - */ - if (*bflags & BLIST_NOSTARTONADD) - sdev->no_start_on_add = 1; - - if (*bflags & BLIST_SINGLELUN) - scsi_target(sdev)->single_lun = 1; - - sdev->use_10_for_rw = 1; - - if (*bflags & BLIST_MS_SKIP_PAGE_08) - sdev->skip_ms_page_8 = 1; - - if (*bflags & BLIST_MS_SKIP_PAGE_3F) - sdev->skip_ms_page_3f = 1; - - if (*bflags & BLIST_USE_10_BYTE_MS) - sdev->use_10_for_ms = 1; - - /* set the device running here so that slave configure - * may do I/O */ - ret = scsi_device_set_state(sdev, SDEV_RUNNING); - if (ret) { - ret = scsi_device_set_state(sdev, SDEV_BLOCK); - - if (ret) { - sdev_printk(KERN_ERR, sdev, - "in wrong state %s to complete scan\n", - scsi_device_state_name(sdev->sdev_state)); - return SCSI_SCAN_NO_RESPONSE; - } - } - - if (*bflags & BLIST_MS_192_BYTES_FOR_3F) - sdev->use_192_bytes_for_3f = 1; - - if (*bflags & BLIST_NOT_LOCKABLE) - sdev->lockable = 0; - - if (*bflags & BLIST_RETRY_HWERROR) - sdev->retry_hwerror = 1; - - transport_configure_device(&sdev->sdev_gendev); - - if (sdev->host->hostt->slave_configure) { - ret = sdev->host->hostt->slave_configure(sdev); - if (ret) { - /* - * if LLDD reports slave not present, don't clutter - * console with alloc failure messages - */ - if (ret != -ENXIO) { - sdev_printk(KERN_ERR, sdev, - "failed to configure device\n"); - } - return SCSI_SCAN_NO_RESPONSE; - } - } - - sdev->max_queue_depth = sdev->queue_depth; - - /* - * Ok, the device is now all set up, we can - * register it and tell the rest of the kernel - * about it. - */ - if (!async && scsi_sysfs_add_sdev(sdev) != 0) - return SCSI_SCAN_NO_RESPONSE; - - return SCSI_SCAN_LUN_PRESENT; -} - -#ifdef CONFIG_SCSI_LOGGING -/** - * scsi_inq_str - print INQUIRY data from min to max index, strip trailing whitespace - * @buf: Output buffer with at least end-first+1 bytes of space - * @inq: Inquiry buffer (input) - * @first: Offset of string into inq - * @end: Index after last character in inq - */ -static unsigned char *scsi_inq_str(unsigned char *buf, unsigned char *inq, - unsigned first, unsigned end) -{ - unsigned term = 0, idx; - - for (idx = 0; idx + first < end && idx + first < inq[4] + 5; idx++) { - if (inq[idx+first] > ' ') { - buf[idx] = inq[idx+first]; - term = idx+1; - } else { - buf[idx] = ' '; - } - } - buf[term] = 0; - return buf; -} -#endif - -/** - * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it - * @starget: pointer to target device structure - * @lun: LUN of target device - * @bflagsp: store bflags here if not NULL - * @sdevp: probe the LUN corresponding to this scsi_device - * @rescan: if nonzero skip some code only needed on first scan - * @hostdata: passed to scsi_alloc_sdev() - * - * Description: - * Call scsi_probe_lun, if a LUN with an attached device is found, - * allocate and set it up by calling scsi_add_lun. - * - * Return: - * SCSI_SCAN_NO_RESPONSE: could not allocate or setup a scsi_device - * SCSI_SCAN_TARGET_PRESENT: target responded, but no device is - * attached at the LUN - * SCSI_SCAN_LUN_PRESENT: a new scsi_device was allocated and initialized - **/ -static int scsi_probe_and_add_lun(struct scsi_target *starget, - uint lun, int *bflagsp, - struct scsi_device **sdevp, int rescan, - void *hostdata) -{ - struct scsi_device *sdev; - unsigned char *result; - int bflags, res = SCSI_SCAN_NO_RESPONSE, result_len = 256; - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - - /* - * The rescan flag is used as an optimization, the first scan of a - * host adapter calls into here with rescan == 0. - */ - sdev = scsi_device_lookup_by_target(starget, lun); - if (sdev) { - if (rescan || !scsi_device_created(sdev)) { - SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO - "scsi scan: device exists on %s\n", - dev_name(&sdev->sdev_gendev))); - if (sdevp) - *sdevp = sdev; - else - scsi_device_put(sdev); - - if (bflagsp) - *bflagsp = scsi_get_device_flags(sdev, - sdev->vendor, - sdev->model); - return SCSI_SCAN_LUN_PRESENT; - } - scsi_device_put(sdev); - } else - sdev = scsi_alloc_sdev(starget, lun, hostdata); - if (!sdev) - goto out; - - result = kmalloc(result_len, GFP_ATOMIC | - ((shost->unchecked_isa_dma) ? __GFP_DMA : 0)); - if (!result) - goto out_free_sdev; - - if (scsi_probe_lun(sdev, result, result_len, &bflags)) - goto out_free_result; - - if (bflagsp) - *bflagsp = bflags; - /* - * result contains valid SCSI INQUIRY data. - */ - if (((result[0] >> 5) == 3) && !(bflags & BLIST_ATTACH_PQ3)) { - /* - * For a Peripheral qualifier 3 (011b), the SCSI - * spec says: The device server is not capable of - * supporting a physical device on this logical - * unit. - * - * For disks, this implies that there is no - * logical disk configured at sdev->lun, but there - * is a target id responding. - */ - SCSI_LOG_SCAN_BUS(2, sdev_printk(KERN_INFO, sdev, "scsi scan:" - " peripheral qualifier of 3, device not" - " added\n")) - if (lun == 0) { - SCSI_LOG_SCAN_BUS(1, { - unsigned char vend[9]; - unsigned char mod[17]; - - sdev_printk(KERN_INFO, sdev, - "scsi scan: consider passing scsi_mod." - "dev_flags=%s:%s:0x240 or 0x1000240\n", - scsi_inq_str(vend, result, 8, 16), - scsi_inq_str(mod, result, 16, 32)); - }); - - } - - res = SCSI_SCAN_TARGET_PRESENT; - goto out_free_result; - } - - /* - * Some targets may set slight variations of PQ and PDT to signal - * that no LUN is present, so don't add sdev in these cases. - * Two specific examples are: - * 1) NetApp targets: return PQ=1, PDT=0x1f - * 2) USB UFI: returns PDT=0x1f, with the PQ bits being "reserved" - * in the UFI 1.0 spec (we cannot rely on reserved bits). - * - * References: - * 1) SCSI SPC-3, pp. 145-146 - * PQ=1: "A peripheral device having the specified peripheral - * device type is not connected to this logical unit. However, the - * device server is capable of supporting the specified peripheral - * device type on this logical unit." - * PDT=0x1f: "Unknown or no device type" - * 2) USB UFI 1.0, p. 20 - * PDT=00h Direct-access device (floppy) - * PDT=1Fh none (no FDD connected to the requested logical unit) - */ - if (((result[0] >> 5) == 1 || starget->pdt_1f_for_no_lun) && - (result[0] & 0x1f) == 0x1f && - !scsi_is_wlun(lun)) { - SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO - "scsi scan: peripheral device type" - " of 31, no device added\n")); - res = SCSI_SCAN_TARGET_PRESENT; - goto out_free_result; - } - - res = scsi_add_lun(sdev, result, &bflags, shost->async_scan); - if (res == SCSI_SCAN_LUN_PRESENT) { - if (bflags & BLIST_KEY) { - sdev->lockable = 0; - scsi_unlock_floptical(sdev, result); - } - } - - out_free_result: - kfree(result); - out_free_sdev: - if (res == SCSI_SCAN_LUN_PRESENT) { - if (sdevp) { - if (scsi_device_get(sdev) == 0) { - *sdevp = sdev; - } else { - __scsi_remove_device(sdev); - res = SCSI_SCAN_NO_RESPONSE; - } - } - } else - __scsi_remove_device(sdev); - out: - return res; -} - -/** - * scsi_sequential_lun_scan - sequentially scan a SCSI target - * @starget: pointer to target structure to scan - * @bflags: black/white list flag for LUN 0 - * @scsi_level: Which version of the standard does this device adhere to - * @rescan: passed to scsi_probe_add_lun() - * - * Description: - * Generally, scan from LUN 1 (LUN 0 is assumed to already have been - * scanned) to some maximum lun until a LUN is found with no device - * attached. Use the bflags to figure out any oddities. - * - * Modifies sdevscan->lun. - **/ -static void scsi_sequential_lun_scan(struct scsi_target *starget, - int bflags, int scsi_level, int rescan) -{ - unsigned int sparse_lun, lun, max_dev_lun; - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - - SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: Sequential scan of" - "%s\n", dev_name(&starget->dev))); - - max_dev_lun = min(max_scsi_luns, shost->max_lun); - /* - * If this device is known to support sparse multiple units, - * override the other settings, and scan all of them. Normally, - * SCSI-3 devices should be scanned via the REPORT LUNS. - */ - if (bflags & BLIST_SPARSELUN) { - max_dev_lun = shost->max_lun; - sparse_lun = 1; - } else - sparse_lun = 0; - - /* - * If less than SCSI_1_CSS, and no special lun scaning, stop - * scanning; this matches 2.4 behaviour, but could just be a bug - * (to continue scanning a SCSI_1_CSS device). - * - * This test is broken. We might not have any device on lun0 for - * a sparselun device, and if that's the case then how would we - * know the real scsi_level, eh? It might make sense to just not - * scan any SCSI_1 device for non-0 luns, but that check would best - * go into scsi_alloc_sdev() and just have it return null when asked - * to alloc an sdev for lun > 0 on an already found SCSI_1 device. - * - if ((sdevscan->scsi_level < SCSI_1_CCS) && - ((bflags & (BLIST_FORCELUN | BLIST_SPARSELUN | BLIST_MAX5LUN)) - == 0)) - return; - */ - /* - * If this device is known to support multiple units, override - * the other settings, and scan all of them. - */ - if (bflags & BLIST_FORCELUN) - max_dev_lun = shost->max_lun; - /* - * REGAL CDC-4X: avoid hang after LUN 4 - */ - if (bflags & BLIST_MAX5LUN) - max_dev_lun = min(5U, max_dev_lun); - /* - * Do not scan SCSI-2 or lower device past LUN 7, unless - * BLIST_LARGELUN. - */ - if (scsi_level < SCSI_3 && !(bflags & BLIST_LARGELUN)) - max_dev_lun = min(8U, max_dev_lun); - - /* - * We have already scanned LUN 0, so start at LUN 1. Keep scanning - * until we reach the max, or no LUN is found and we are not - * sparse_lun. - */ - for (lun = 1; lun < max_dev_lun; ++lun) - if ((scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan, - NULL) != SCSI_SCAN_LUN_PRESENT) && - !sparse_lun) - return; -} - -/** - * scsilun_to_int - convert a scsi_lun to an int - * @scsilun: struct scsi_lun to be converted. - * - * Description: - * Convert @scsilun from a struct scsi_lun to a four byte host byte-ordered - * integer, and return the result. The caller must check for - * truncation before using this function. - * - * Notes: - * The struct scsi_lun is assumed to be four levels, with each level - * effectively containing a SCSI byte-ordered (big endian) short; the - * addressing bits of each level are ignored (the highest two bits). - * For a description of the LUN format, post SCSI-3 see the SCSI - * Architecture Model, for SCSI-3 see the SCSI Controller Commands. - * - * Given a struct scsi_lun of: 0a 04 0b 03 00 00 00 00, this function returns - * the integer: 0x0b030a04 - **/ -int scsilun_to_int(struct scsi_lun *scsilun) -{ - int i; - unsigned int lun; - - lun = 0; - for (i = 0; i < sizeof(lun); i += 2) - lun = lun | (((scsilun->scsi_lun[i] << 8) | - scsilun->scsi_lun[i + 1]) << (i * 8)); - return lun; -} -EXPORT_SYMBOL(scsilun_to_int); - -/** - * int_to_scsilun - reverts an int into a scsi_lun - * @lun: integer to be reverted - * @scsilun: struct scsi_lun to be set. - * - * Description: - * Reverts the functionality of the scsilun_to_int, which packed - * an 8-byte lun value into an int. This routine unpacks the int - * back into the lun value. - * Note: the scsilun_to_int() routine does not truly handle all - * 8bytes of the lun value. This functions restores only as much - * as was set by the routine. - * - * Notes: - * Given an integer : 0x0b030a04, this function returns a - * scsi_lun of : struct scsi_lun of: 0a 04 0b 03 00 00 00 00 - * - **/ -void int_to_scsilun(unsigned int lun, struct scsi_lun *scsilun) -{ - int i; - - memset(scsilun->scsi_lun, 0, sizeof(scsilun->scsi_lun)); - - for (i = 0; i < sizeof(lun); i += 2) { - scsilun->scsi_lun[i] = (lun >> 8) & 0xFF; - scsilun->scsi_lun[i+1] = lun & 0xFF; - lun = lun >> 16; - } -} -EXPORT_SYMBOL(int_to_scsilun); - -/** - * scsi_report_lun_scan - Scan using SCSI REPORT LUN results - * @starget: which target - * @bflags: Zero or a mix of BLIST_NOLUN, BLIST_REPORTLUN2, or BLIST_NOREPORTLUN - * @rescan: nonzero if we can skip code only needed on first scan - * - * Description: - * Fast scanning for modern (SCSI-3) devices by sending a REPORT LUN command. - * Scan the resulting list of LUNs by calling scsi_probe_and_add_lun. - * - * If BLINK_REPORTLUN2 is set, scan a target that supports more than 8 - * LUNs even if it's older than SCSI-3. - * If BLIST_NOREPORTLUN is set, return 1 always. - * If BLIST_NOLUN is set, return 0 always. - * If starget->no_report_luns is set, return 1 always. - * - * Return: - * 0: scan completed (or no memory, so further scanning is futile) - * 1: could not scan with REPORT LUN - **/ -static int scsi_report_lun_scan(struct scsi_target *starget, int bflags, - int rescan) -{ - char devname[64]; - unsigned char scsi_cmd[MAX_COMMAND_SIZE]; - unsigned int length; - unsigned int lun; - unsigned int num_luns; - unsigned int retries; - int result; - struct scsi_lun *lunp, *lun_data; - u8 *data; - struct scsi_sense_hdr sshdr; - struct scsi_device *sdev; - struct Scsi_Host *shost = dev_to_shost(&starget->dev); - int ret = 0; - - /* - * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set. - * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does - * support more than 8 LUNs. - * Don't attempt if the target doesn't support REPORT LUNS. - */ - if (bflags & BLIST_NOREPORTLUN) - return 1; - if (starget->scsi_level < SCSI_2 && - starget->scsi_level != SCSI_UNKNOWN) - return 1; - if (starget->scsi_level < SCSI_3 && - (!(bflags & BLIST_REPORTLUN2) || shost->max_lun <= 8)) - return 1; - if (bflags & BLIST_NOLUN) - return 0; - if (starget->no_report_luns) - return 1; - - if (!(sdev = scsi_device_lookup_by_target(starget, 0))) { - sdev = scsi_alloc_sdev(starget, 0, NULL); - if (!sdev) - return 0; - if (scsi_device_get(sdev)) { - __scsi_remove_device(sdev); - return 0; - } - } - - sprintf(devname, "host %d channel %d id %d", - shost->host_no, sdev->channel, sdev->id); - - /* - * Allocate enough to hold the header (the same size as one scsi_lun) - * plus the max number of luns we are requesting. - * - * Reallocating and trying again (with the exact amount we need) - * would be nice, but then we need to somehow limit the size - * allocated based on the available memory and the limits of - * kmalloc - we don't want a kmalloc() failure of a huge value to - * prevent us from finding any LUNs on this target. - */ - length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun); - lun_data = kmalloc(length, GFP_ATOMIC | - (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); - if (!lun_data) { - printk(ALLOC_FAILURE_MSG, __func__); - goto out; - } - - scsi_cmd[0] = REPORT_LUNS; - - /* - * bytes 1 - 5: reserved, set to zero. - */ - memset(&scsi_cmd[1], 0, 5); - - /* - * bytes 6 - 9: length of the command. - */ - scsi_cmd[6] = (unsigned char) (length >> 24) & 0xff; - scsi_cmd[7] = (unsigned char) (length >> 16) & 0xff; - scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff; - scsi_cmd[9] = (unsigned char) length & 0xff; - - scsi_cmd[10] = 0; /* reserved */ - scsi_cmd[11] = 0; /* control */ - - /* - * We can get a UNIT ATTENTION, for example a power on/reset, so - * retry a few times (like sd.c does for TEST UNIT READY). - * Experience shows some combinations of adapter/devices get at - * least two power on/resets. - * - * Illegal requests (for devices that do not support REPORT LUNS) - * should come through as a check condition, and will not generate - * a retry. - */ - for (retries = 0; retries < 3; retries++) { - SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: Sending" - " REPORT LUNS to %s (try %d)\n", devname, - retries)); - - result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, - lun_data, length, &sshdr, - SCSI_TIMEOUT + 4 * HZ, 3, NULL); - - SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS" - " %s (try %d) result 0x%x\n", result - ? "failed" : "successful", retries, result)); - if (result == 0) - break; - else if (scsi_sense_valid(&sshdr)) { - if (sshdr.sense_key != UNIT_ATTENTION) - break; - } - } - - if (result) { - /* - * The device probably does not support a REPORT LUN command - */ - ret = 1; - goto out_err; - } - - /* - * Get the length from the first four bytes of lun_data. - */ - data = (u8 *) lun_data->scsi_lun; - length = ((data[0] << 24) | (data[1] << 16) | - (data[2] << 8) | (data[3] << 0)); - - num_luns = (length / sizeof(struct scsi_lun)); - if (num_luns > max_scsi_report_luns) { - printk(KERN_WARNING "scsi: On %s only %d (max_scsi_report_luns)" - " of %d luns reported, try increasing" - " max_scsi_report_luns.\n", devname, - max_scsi_report_luns, num_luns); - num_luns = max_scsi_report_luns; - } - - SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev, - "scsi scan: REPORT LUN scan\n")); - - /* - * Scan the luns in lun_data. The entry at offset 0 is really - * the header, so start at 1 and go up to and including num_luns. - */ - for (lunp = &lun_data[1]; lunp <= &lun_data[num_luns]; lunp++) { - lun = scsilun_to_int(lunp); - - /* - * Check if the unused part of lunp is non-zero, and so - * does not fit in lun. - */ - if (memcmp(&lunp->scsi_lun[sizeof(lun)], "\0\0\0\0", 4)) { - int i; - - /* - * Output an error displaying the LUN in byte order, - * this differs from what linux would print for the - * integer LUN value. - */ - printk(KERN_WARNING "scsi: %s lun 0x", devname); - data = (char *)lunp->scsi_lun; - for (i = 0; i < sizeof(struct scsi_lun); i++) - printk("%02x", data[i]); - printk(" has a LUN larger than currently supported.\n"); - } else if (lun > sdev->host->max_lun) { - printk(KERN_WARNING "scsi: %s lun%d has a LUN larger" - " than allowed by the host adapter\n", - devname, lun); - } else { - int res; - - res = scsi_probe_and_add_lun(starget, - lun, NULL, NULL, rescan, NULL); - if (res == SCSI_SCAN_NO_RESPONSE) { - /* - * Got some results, but now none, abort. - */ - sdev_printk(KERN_ERR, sdev, - "Unexpected response" - " from lun %d while scanning, scan" - " aborted\n", lun); - break; - } - } - } - - out_err: - kfree(lun_data); - out: - scsi_device_put(sdev); - if (scsi_device_created(sdev)) - /* - * the sdev we used didn't appear in the report luns scan - */ - __scsi_remove_device(sdev); - return ret; -} - -struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, - uint id, uint lun, void *hostdata) -{ - struct scsi_device *sdev = ERR_PTR(-ENODEV); - struct device *parent = &shost->shost_gendev; - struct scsi_target *starget; - - if (strncmp(scsi_scan_type, "none", 4) == 0) - return ERR_PTR(-ENODEV); - - starget = scsi_alloc_target(parent, channel, id); - if (!starget) - return ERR_PTR(-ENOMEM); - scsi_autopm_get_target(starget); - - mutex_lock(&shost->scan_mutex); - if (!shost->async_scan) - scsi_complete_async_scans(); - - if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { - scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); - scsi_autopm_put_host(shost); - } - mutex_unlock(&shost->scan_mutex); - scsi_autopm_put_target(starget); - scsi_target_reap(starget); - put_device(&starget->dev); - - return sdev; -} -EXPORT_SYMBOL(__scsi_add_device); - -int scsi_add_device(struct Scsi_Host *host, uint channel, - uint target, uint lun) -{ - struct scsi_device *sdev = - __scsi_add_device(host, channel, target, lun, NULL); - if (IS_ERR(sdev)) - return PTR_ERR(sdev); - - scsi_device_put(sdev); - return 0; -} -EXPORT_SYMBOL(scsi_add_device); - -void scsi_rescan_device(struct device *dev) -{ - struct scsi_driver *drv; - - if (!dev->driver) - return; - - drv = to_scsi_driver(dev->driver); - if (try_module_get(drv->owner)) { - if (drv->rescan) - drv->rescan(dev); - module_put(drv->owner); - } -} -EXPORT_SYMBOL(scsi_rescan_device); - -static void __scsi_scan_target(struct device *parent, unsigned int channel, - unsigned int id, unsigned int lun, int rescan) -{ - struct Scsi_Host *shost = dev_to_shost(parent); - int bflags = 0; - int res; - struct scsi_target *starget; - - if (shost->this_id == id) - /* - * Don't scan the host adapter - */ - return; - - starget = scsi_alloc_target(parent, channel, id); - if (!starget) - return; - scsi_autopm_get_target(starget); - - if (lun != SCAN_WILD_CARD) { - /* - * Scan for a specific host/chan/id/lun. - */ - scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan, NULL); - goto out_reap; - } - - /* - * Scan LUN 0, if there is some response, scan further. Ideally, we - * would not configure LUN 0 until all LUNs are scanned. - */ - res = scsi_probe_and_add_lun(starget, 0, &bflags, NULL, rescan, NULL); - if (res == SCSI_SCAN_LUN_PRESENT || res == SCSI_SCAN_TARGET_PRESENT) { - if (scsi_report_lun_scan(starget, bflags, rescan) != 0) - /* - * The REPORT LUN did not scan the target, - * do a sequential scan. - */ - scsi_sequential_lun_scan(starget, bflags, - starget->scsi_level, rescan); - } - - out_reap: - scsi_autopm_put_target(starget); - /* now determine if the target has any children at all - * and if not, nuke it */ - scsi_target_reap(starget); - - put_device(&starget->dev); -} - -/** - * scsi_scan_target - scan a target id, possibly including all LUNs on the target. - * @parent: host to scan - * @channel: channel to scan - * @id: target id to scan - * @lun: Specific LUN to scan or SCAN_WILD_CARD - * @rescan: passed to LUN scanning routines - * - * Description: - * Scan the target id on @parent, @channel, and @id. Scan at least LUN 0, - * and possibly all LUNs on the target id. - * - * First try a REPORT LUN scan, if that does not scan the target, do a - * sequential scan of LUNs on the target id. - **/ -void scsi_scan_target(struct device *parent, unsigned int channel, - unsigned int id, unsigned int lun, int rescan) -{ - struct Scsi_Host *shost = dev_to_shost(parent); - - if (strncmp(scsi_scan_type, "none", 4) == 0) - return; - - mutex_lock(&shost->scan_mutex); - if (!shost->async_scan) - scsi_complete_async_scans(); - - if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { - __scsi_scan_target(parent, channel, id, lun, rescan); - scsi_autopm_put_host(shost); - } - mutex_unlock(&shost->scan_mutex); -} -EXPORT_SYMBOL(scsi_scan_target); - -static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel, - unsigned int id, unsigned int lun, int rescan) -{ - uint order_id; - - if (id == SCAN_WILD_CARD) - for (id = 0; id < shost->max_id; ++id) { - /* - * XXX adapter drivers when possible (FCP, iSCSI) - * could modify max_id to match the current max, - * not the absolute max. - * - * XXX add a shost id iterator, so for example, - * the FC ID can be the same as a target id - * without a huge overhead of sparse id's. - */ - if (shost->reverse_ordering) - /* - * Scan from high to low id. - */ - order_id = shost->max_id - id - 1; - else - order_id = id; - __scsi_scan_target(&shost->shost_gendev, channel, - order_id, lun, rescan); - } - else - __scsi_scan_target(&shost->shost_gendev, channel, - id, lun, rescan); -} - -int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, - unsigned int id, unsigned int lun, int rescan) -{ - SCSI_LOG_SCAN_BUS(3, shost_printk (KERN_INFO, shost, - "%s: <%u:%u:%u>\n", - __func__, channel, id, lun)); - - if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || - ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || - ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) - return -EINVAL; - - mutex_lock(&shost->scan_mutex); - if (!shost->async_scan) - scsi_complete_async_scans(); - - if (scsi_host_scan_allowed(shost) && scsi_autopm_get_host(shost) == 0) { - if (channel == SCAN_WILD_CARD) - for (channel = 0; channel <= shost->max_channel; - channel++) - scsi_scan_channel(shost, channel, id, lun, - rescan); - else - scsi_scan_channel(shost, channel, id, lun, rescan); - scsi_autopm_put_host(shost); - } - mutex_unlock(&shost->scan_mutex); - - return 0; -} - -static void scsi_sysfs_add_devices(struct Scsi_Host *shost) -{ - struct scsi_device *sdev; - shost_for_each_device(sdev, shost) { - if (!scsi_host_scan_allowed(shost) || - scsi_sysfs_add_sdev(sdev) != 0) - __scsi_remove_device(sdev); - } -} - -/** - * scsi_prep_async_scan - prepare for an async scan - * @shost: the host which will be scanned - * Returns: a cookie to be passed to scsi_finish_async_scan() - * - * Tells the midlayer this host is going to do an asynchronous scan. - * It reserves the host's position in the scanning list and ensures - * that other asynchronous scans started after this one won't affect the - * ordering of the discovered devices. - */ -static struct async_scan_data *scsi_prep_async_scan(struct Scsi_Host *shost) -{ - struct async_scan_data *data; - unsigned long flags; - - if (strncmp(scsi_scan_type, "sync", 4) == 0) - return NULL; - - if (shost->async_scan) { - printk("%s called twice for host %d", __func__, - shost->host_no); - dump_stack(); - return NULL; - } - - data = kmalloc(sizeof(*data), GFP_KERNEL); - if (!data) - goto err; - data->shost = scsi_host_get(shost); - if (!data->shost) - goto err; - init_completion(&data->prev_finished); - - mutex_lock(&shost->scan_mutex); - spin_lock_irqsave(shost->host_lock, flags); - shost->async_scan = 1; - spin_unlock_irqrestore(shost->host_lock, flags); - mutex_unlock(&shost->scan_mutex); - - spin_lock(&async_scan_lock); - if (list_empty(&scanning_hosts)) - complete(&data->prev_finished); - list_add_tail(&data->list, &scanning_hosts); - spin_unlock(&async_scan_lock); - - return data; - - err: - kfree(data); - return NULL; -} - -/** - * scsi_finish_async_scan - asynchronous scan has finished - * @data: cookie returned from earlier call to scsi_prep_async_scan() - * - * All the devices currently attached to this host have been found. - * This function announces all the devices it has found to the rest - * of the system. - */ -static void scsi_finish_async_scan(struct async_scan_data *data) -{ - struct Scsi_Host *shost; - unsigned long flags; - - if (!data) - return; - - shost = data->shost; - - mutex_lock(&shost->scan_mutex); - - if (!shost->async_scan) { - printk("%s called twice for host %d", __func__, - shost->host_no); - dump_stack(); - mutex_unlock(&shost->scan_mutex); - return; - } - - wait_for_completion(&data->prev_finished); - - scsi_sysfs_add_devices(shost); - - spin_lock_irqsave(shost->host_lock, flags); - shost->async_scan = 0; - spin_unlock_irqrestore(shost->host_lock, flags); - - mutex_unlock(&shost->scan_mutex); - - spin_lock(&async_scan_lock); - list_del(&data->list); - if (!list_empty(&scanning_hosts)) { - struct async_scan_data *next = list_entry(scanning_hosts.next, - struct async_scan_data, list); - complete(&next->prev_finished); - } - spin_unlock(&async_scan_lock); - - scsi_autopm_put_host(shost); - scsi_host_put(shost); - kfree(data); -} - -static void do_scsi_scan_host(struct Scsi_Host *shost) -{ - if (shost->hostt->scan_finished) { - unsigned long start = jiffies; - if (shost->hostt->scan_start) - shost->hostt->scan_start(shost); - - while (!shost->hostt->scan_finished(shost, jiffies - start)) - msleep(10); - } else { - scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD, - SCAN_WILD_CARD, 0); - } -} - -static int do_scan_async(void *_data) -{ - struct async_scan_data *data = _data; - struct Scsi_Host *shost = data->shost; - - do_scsi_scan_host(shost); - scsi_finish_async_scan(data); - return 0; -} - -/** - * scsi_scan_host - scan the given adapter - * @shost: adapter to scan - **/ -void scsi_scan_host(struct Scsi_Host *shost) -{ - struct task_struct *p; - struct async_scan_data *data; - - if (strncmp(scsi_scan_type, "none", 4) == 0) - return; - if (scsi_autopm_get_host(shost) < 0) - return; - - data = scsi_prep_async_scan(shost); - if (!data) { - do_scsi_scan_host(shost); - scsi_autopm_put_host(shost); - return; - } - - p = kthread_run(do_scan_async, data, "scsi_scan_%d", shost->host_no); - if (IS_ERR(p)) - do_scan_async(data); - /* scsi_autopm_put_host(shost) is called in scsi_finish_async_scan() */ -} -EXPORT_SYMBOL(scsi_scan_host); - -void scsi_forget_host(struct Scsi_Host *shost) -{ - struct scsi_device *sdev; - unsigned long flags; - - restart: - spin_lock_irqsave(shost->host_lock, flags); - list_for_each_entry(sdev, &shost->__devices, siblings) { - if (sdev->sdev_state == SDEV_DEL) - continue; - spin_unlock_irqrestore(shost->host_lock, flags); - __scsi_remove_device(sdev); - goto restart; - } - spin_unlock_irqrestore(shost->host_lock, flags); -} - -/** - * scsi_get_host_dev - Create a scsi_device that points to the host adapter itself - * @shost: Host that needs a scsi_device - * - * Lock status: None assumed. - * - * Returns: The scsi_device or NULL - * - * Notes: - * Attach a single scsi_device to the Scsi_Host - this should - * be made to look like a "pseudo-device" that points to the - * HA itself. - * - * Note - this device is not accessible from any high-level - * drivers (including generics), which is probably not - * optimal. We can add hooks later to attach. - */ -struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) -{ - struct scsi_device *sdev = NULL; - struct scsi_target *starget; - - mutex_lock(&shost->scan_mutex); - if (!scsi_host_scan_allowed(shost)) - goto out; - starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id); - if (!starget) - goto out; - - sdev = scsi_alloc_sdev(starget, 0, NULL); - if (sdev) - sdev->borken = 0; - else - scsi_target_reap(starget); - put_device(&starget->dev); - out: - mutex_unlock(&shost->scan_mutex); - return sdev; -} -EXPORT_SYMBOL(scsi_get_host_dev); - -/** - * scsi_free_host_dev - Free a scsi_device that points to the host adapter itself - * @sdev: Host device to be freed - * - * Lock status: None assumed. - * - * Returns: Nothing - */ -void scsi_free_host_dev(struct scsi_device *sdev) -{ - BUG_ON(sdev->id != sdev->host->this_id); - - __scsi_remove_device(sdev); -} -EXPORT_SYMBOL(scsi_free_host_dev); - diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_sysctl.c b/ANDROID_3.4.5/drivers/scsi/scsi_sysctl.c deleted file mode 100644 index 2b6b93f7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_sysctl.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2003 Christoph Hellwig. - * Released under GPL v2. - */ - -#include -#include -#include -#include - -#include "scsi_logging.h" -#include "scsi_priv.h" - - -static ctl_table scsi_table[] = { - { .procname = "logging_level", - .data = &scsi_logging_level, - .maxlen = sizeof(scsi_logging_level), - .mode = 0644, - .proc_handler = proc_dointvec }, - { } -}; - -static ctl_table scsi_dir_table[] = { - { .procname = "scsi", - .mode = 0555, - .child = scsi_table }, - { } -}; - -static ctl_table scsi_root_table[] = { - { .procname = "dev", - .mode = 0555, - .child = scsi_dir_table }, - { } -}; - -static struct ctl_table_header *scsi_table_header; - -int __init scsi_init_sysctl(void) -{ - scsi_table_header = register_sysctl_table(scsi_root_table); - if (!scsi_table_header) - return -ENOMEM; - return 0; -} - -void scsi_exit_sysctl(void) -{ - unregister_sysctl_table(scsi_table_header); -} diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_sysfs.c b/ANDROID_3.4.5/drivers/scsi/scsi_sysfs.c deleted file mode 100644 index 04c2a278..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_sysfs.c +++ /dev/null @@ -1,1126 +0,0 @@ -/* - * scsi_sysfs.c - * - * SCSI sysfs interface routines. - * - * Created to pull SCSI mid layer sysfs routines into one file. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "scsi_priv.h" -#include "scsi_logging.h" - -static struct device_type scsi_dev_type; - -static const struct { - enum scsi_device_state value; - char *name; -} sdev_states[] = { - { SDEV_CREATED, "created" }, - { SDEV_RUNNING, "running" }, - { SDEV_CANCEL, "cancel" }, - { SDEV_DEL, "deleted" }, - { SDEV_QUIESCE, "quiesce" }, - { SDEV_OFFLINE, "offline" }, - { SDEV_BLOCK, "blocked" }, - { SDEV_CREATED_BLOCK, "created-blocked" }, -}; - -const char *scsi_device_state_name(enum scsi_device_state state) -{ - int i; - char *name = NULL; - - for (i = 0; i < ARRAY_SIZE(sdev_states); i++) { - if (sdev_states[i].value == state) { - name = sdev_states[i].name; - break; - } - } - return name; -} - -static const struct { - enum scsi_host_state value; - char *name; -} shost_states[] = { - { SHOST_CREATED, "created" }, - { SHOST_RUNNING, "running" }, - { SHOST_CANCEL, "cancel" }, - { SHOST_DEL, "deleted" }, - { SHOST_RECOVERY, "recovery" }, - { SHOST_CANCEL_RECOVERY, "cancel/recovery" }, - { SHOST_DEL_RECOVERY, "deleted/recovery", }, -}; -const char *scsi_host_state_name(enum scsi_host_state state) -{ - int i; - char *name = NULL; - - for (i = 0; i < ARRAY_SIZE(shost_states); i++) { - if (shost_states[i].value == state) { - name = shost_states[i].name; - break; - } - } - return name; -} - -static int check_set(unsigned int *val, char *src) -{ - char *last; - - if (strncmp(src, "-", 20) == 0) { - *val = SCAN_WILD_CARD; - } else { - /* - * Doesn't check for int overflow - */ - *val = simple_strtoul(src, &last, 0); - if (*last != '\0') - return 1; - } - return 0; -} - -static int scsi_scan(struct Scsi_Host *shost, const char *str) -{ - char s1[15], s2[15], s3[15], junk; - unsigned int channel, id, lun; - int res; - - res = sscanf(str, "%10s %10s %10s %c", s1, s2, s3, &junk); - if (res != 3) - return -EINVAL; - if (check_set(&channel, s1)) - return -EINVAL; - if (check_set(&id, s2)) - return -EINVAL; - if (check_set(&lun, s3)) - return -EINVAL; - if (shost->transportt->user_scan) - res = shost->transportt->user_scan(shost, channel, id, lun); - else - res = scsi_scan_host_selected(shost, channel, id, lun, 1); - return res; -} - -/* - * shost_show_function: macro to create an attr function that can be used to - * show a non-bit field. - */ -#define shost_show_function(name, field, format_string) \ -static ssize_t \ -show_##name (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct Scsi_Host *shost = class_to_shost(dev); \ - return snprintf (buf, 20, format_string, shost->field); \ -} - -/* - * shost_rd_attr: macro to create a function and attribute variable for a - * read only field. - */ -#define shost_rd_attr2(name, field, format_string) \ - shost_show_function(name, field, format_string) \ -static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL); - -#define shost_rd_attr(field, format_string) \ -shost_rd_attr2(field, field, format_string) - -/* - * Create the actual show/store functions and data structures. - */ - -static ssize_t -store_scan(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - int res; - - res = scsi_scan(shost, buf); - if (res == 0) - res = count; - return res; -}; -static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); - -static ssize_t -store_shost_state(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int i; - struct Scsi_Host *shost = class_to_shost(dev); - enum scsi_host_state state = 0; - - for (i = 0; i < ARRAY_SIZE(shost_states); i++) { - const int len = strlen(shost_states[i].name); - if (strncmp(shost_states[i].name, buf, len) == 0 && - buf[len] == '\n') { - state = shost_states[i].value; - break; - } - } - if (!state) - return -EINVAL; - - if (scsi_host_set_state(shost, state)) - return -EINVAL; - return count; -} - -static ssize_t -show_shost_state(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - const char *name = scsi_host_state_name(shost->shost_state); - - if (!name) - return -EINVAL; - - return snprintf(buf, 20, "%s\n", name); -} - -/* DEVICE_ATTR(state) clashes with dev_attr_state for sdev */ -struct device_attribute dev_attr_hstate = - __ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state); - -static ssize_t -show_shost_mode(unsigned int mode, char *buf) -{ - ssize_t len = 0; - - if (mode & MODE_INITIATOR) - len = sprintf(buf, "%s", "Initiator"); - - if (mode & MODE_TARGET) - len += sprintf(buf + len, "%s%s", len ? ", " : "", "Target"); - - len += sprintf(buf + len, "\n"); - - return len; -} - -static ssize_t -show_shost_supported_mode(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - unsigned int supported_mode = shost->hostt->supported_mode; - - if (supported_mode == MODE_UNKNOWN) - /* by default this should be initiator */ - supported_mode = MODE_INITIATOR; - - return show_shost_mode(supported_mode, buf); -} - -static DEVICE_ATTR(supported_mode, S_IRUGO | S_IWUSR, show_shost_supported_mode, NULL); - -static ssize_t -show_shost_active_mode(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = class_to_shost(dev); - - if (shost->active_mode == MODE_UNKNOWN) - return snprintf(buf, 20, "unknown\n"); - else - return show_shost_mode(shost->active_mode, buf); -} - -static DEVICE_ATTR(active_mode, S_IRUGO | S_IWUSR, show_shost_active_mode, NULL); - -static int check_reset_type(char *str) -{ - if (strncmp(str, "adapter", 10) == 0) - return SCSI_ADAPTER_RESET; - else if (strncmp(str, "firmware", 10) == 0) - return SCSI_FIRMWARE_RESET; - else - return 0; -} - -static ssize_t -store_host_reset(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = class_to_shost(dev); - struct scsi_host_template *sht = shost->hostt; - int ret = -EINVAL; - char str[10]; - int type; - - sscanf(buf, "%s", str); - type = check_reset_type(str); - - if (!type) - goto exit_store_host_reset; - - if (sht->host_reset) - ret = sht->host_reset(shost, type); - -exit_store_host_reset: - if (ret == 0) - ret = count; - return ret; -} - -static DEVICE_ATTR(host_reset, S_IWUSR, NULL, store_host_reset); - -shost_rd_attr(unique_id, "%u\n"); -shost_rd_attr(host_busy, "%hu\n"); -shost_rd_attr(cmd_per_lun, "%hd\n"); -shost_rd_attr(can_queue, "%hd\n"); -shost_rd_attr(sg_tablesize, "%hu\n"); -shost_rd_attr(sg_prot_tablesize, "%hu\n"); -shost_rd_attr(unchecked_isa_dma, "%d\n"); -shost_rd_attr(prot_capabilities, "%u\n"); -shost_rd_attr(prot_guard_type, "%hd\n"); -shost_rd_attr2(proc_name, hostt->proc_name, "%s\n"); - -static struct attribute *scsi_sysfs_shost_attrs[] = { - &dev_attr_unique_id.attr, - &dev_attr_host_busy.attr, - &dev_attr_cmd_per_lun.attr, - &dev_attr_can_queue.attr, - &dev_attr_sg_tablesize.attr, - &dev_attr_sg_prot_tablesize.attr, - &dev_attr_unchecked_isa_dma.attr, - &dev_attr_proc_name.attr, - &dev_attr_scan.attr, - &dev_attr_hstate.attr, - &dev_attr_supported_mode.attr, - &dev_attr_active_mode.attr, - &dev_attr_prot_capabilities.attr, - &dev_attr_prot_guard_type.attr, - &dev_attr_host_reset.attr, - NULL -}; - -struct attribute_group scsi_shost_attr_group = { - .attrs = scsi_sysfs_shost_attrs, -}; - -const struct attribute_group *scsi_sysfs_shost_attr_groups[] = { - &scsi_shost_attr_group, - NULL -}; - -static void scsi_device_cls_release(struct device *class_dev) -{ - struct scsi_device *sdev; - - sdev = class_to_sdev(class_dev); - put_device(&sdev->sdev_gendev); -} - -static void scsi_device_dev_release_usercontext(struct work_struct *work) -{ - struct scsi_device *sdev; - struct device *parent; - struct scsi_target *starget; - struct list_head *this, *tmp; - unsigned long flags; - - sdev = container_of(work, struct scsi_device, ew.work); - - parent = sdev->sdev_gendev.parent; - starget = to_scsi_target(parent); - - spin_lock_irqsave(sdev->host->host_lock, flags); - starget->reap_ref++; - list_del(&sdev->siblings); - list_del(&sdev->same_target_siblings); - list_del(&sdev->starved_entry); - spin_unlock_irqrestore(sdev->host->host_lock, flags); - - cancel_work_sync(&sdev->event_work); - - list_for_each_safe(this, tmp, &sdev->event_list) { - struct scsi_event *evt; - - evt = list_entry(this, struct scsi_event, node); - list_del(&evt->node); - kfree(evt); - } - - blk_put_queue(sdev->request_queue); - /* NULL queue means the device can't be used */ - sdev->request_queue = NULL; - - scsi_target_reap(scsi_target(sdev)); - - kfree(sdev->inquiry); - kfree(sdev); - - if (parent) - put_device(parent); -} - -static void scsi_device_dev_release(struct device *dev) -{ - struct scsi_device *sdp = to_scsi_device(dev); - execute_in_process_context(scsi_device_dev_release_usercontext, - &sdp->ew); -} - -static struct class sdev_class = { - .name = "scsi_device", - .dev_release = scsi_device_cls_release, -}; - -/* all probing is done in the individual ->probe routines */ -static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) -{ - struct scsi_device *sdp; - - if (dev->type != &scsi_dev_type) - return 0; - - sdp = to_scsi_device(dev); - if (sdp->no_uld_attach) - return 0; - return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0; -} - -static int scsi_bus_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct scsi_device *sdev; - - if (dev->type != &scsi_dev_type) - return 0; - - sdev = to_scsi_device(dev); - - add_uevent_var(env, "MODALIAS=" SCSI_DEVICE_MODALIAS_FMT, sdev->type); - return 0; -} - -struct bus_type scsi_bus_type = { - .name = "scsi", - .match = scsi_bus_match, - .uevent = scsi_bus_uevent, -#ifdef CONFIG_PM - .pm = &scsi_bus_pm_ops, -#endif -}; -EXPORT_SYMBOL_GPL(scsi_bus_type); - -int scsi_sysfs_register(void) -{ - int error; - - error = bus_register(&scsi_bus_type); - if (!error) { - error = class_register(&sdev_class); - if (error) - bus_unregister(&scsi_bus_type); - } - - return error; -} - -void scsi_sysfs_unregister(void) -{ - class_unregister(&sdev_class); - bus_unregister(&scsi_bus_type); -} - -/* - * sdev_show_function: macro to create an attr function that can be used to - * show a non-bit field. - */ -#define sdev_show_function(field, format_string) \ -static ssize_t \ -sdev_show_##field (struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct scsi_device *sdev; \ - sdev = to_scsi_device(dev); \ - return snprintf (buf, 20, format_string, sdev->field); \ -} \ - -/* - * sdev_rd_attr: macro to create a function and attribute variable for a - * read only field. - */ -#define sdev_rd_attr(field, format_string) \ - sdev_show_function(field, format_string) \ -static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL); - - -/* - * sdev_rw_attr: create a function and attribute variable for a - * read/write field. - */ -#define sdev_rw_attr(field, format_string) \ - sdev_show_function(field, format_string) \ - \ -static ssize_t \ -sdev_store_##field (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct scsi_device *sdev; \ - sdev = to_scsi_device(dev); \ - sscanf (buf, format_string, &sdev->field); \ - return count; \ -} \ -static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); - -/* Currently we don't export bit fields, but we might in future, - * so leave this code in */ -#if 0 -/* - * sdev_rd_attr: create a function and attribute variable for a - * read/write bit field. - */ -#define sdev_rw_attr_bit(field) \ - sdev_show_function(field, "%d\n") \ - \ -static ssize_t \ -sdev_store_##field (struct device *dev, struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int ret; \ - struct scsi_device *sdev; \ - ret = scsi_sdev_check_buf_bit(buf); \ - if (ret >= 0) { \ - sdev = to_scsi_device(dev); \ - sdev->field = ret; \ - ret = count; \ - } \ - return ret; \ -} \ -static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field); - -/* - * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1", - * else return -EINVAL. - */ -static int scsi_sdev_check_buf_bit(const char *buf) -{ - if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) { - if (buf[0] == '1') - return 1; - else if (buf[0] == '0') - return 0; - else - return -EINVAL; - } else - return -EINVAL; -} -#endif -/* - * Create the actual show/store functions and data structures. - */ -sdev_rd_attr (device_blocked, "%d\n"); -sdev_rd_attr (queue_depth, "%d\n"); -sdev_rd_attr (type, "%d\n"); -sdev_rd_attr (scsi_level, "%d\n"); -sdev_rd_attr (vendor, "%.8s\n"); -sdev_rd_attr (model, "%.16s\n"); -sdev_rd_attr (rev, "%.4s\n"); - -/* - * TODO: can we make these symlinks to the block layer ones? - */ -static ssize_t -sdev_show_timeout (struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev; - sdev = to_scsi_device(dev); - return snprintf(buf, 20, "%d\n", sdev->request_queue->rq_timeout / HZ); -} - -static ssize_t -sdev_store_timeout (struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev; - int timeout; - sdev = to_scsi_device(dev); - sscanf (buf, "%d\n", &timeout); - blk_queue_rq_timeout(sdev->request_queue, timeout * HZ); - return count; -} -static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout); - -static ssize_t -store_rescan_field (struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - scsi_rescan_device(dev); - return count; -} -static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field); - -static void sdev_store_delete_callback(struct device *dev) -{ - scsi_remove_device(to_scsi_device(dev)); -} - -static ssize_t -sdev_store_delete(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int rc; - - /* An attribute cannot be unregistered by one of its own methods, - * so we have to use this roundabout approach. - */ - rc = device_schedule_callback(dev, sdev_store_delete_callback); - if (rc) - count = rc; - return count; -}; -static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete); - -static ssize_t -store_state_field(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int i; - struct scsi_device *sdev = to_scsi_device(dev); - enum scsi_device_state state = 0; - - for (i = 0; i < ARRAY_SIZE(sdev_states); i++) { - const int len = strlen(sdev_states[i].name); - if (strncmp(sdev_states[i].name, buf, len) == 0 && - buf[len] == '\n') { - state = sdev_states[i].value; - break; - } - } - if (!state) - return -EINVAL; - - if (scsi_device_set_state(sdev, state)) - return -EINVAL; - return count; -} - -static ssize_t -show_state_field(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - const char *name = scsi_device_state_name(sdev->sdev_state); - - if (!name) - return -EINVAL; - - return snprintf(buf, 20, "%s\n", name); -} - -static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field); - -static ssize_t -show_queue_type_field(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_device *sdev = to_scsi_device(dev); - const char *name = "none"; - - if (sdev->ordered_tags) - name = "ordered"; - else if (sdev->simple_tags) - name = "simple"; - - return snprintf(buf, 20, "%s\n", name); -} - -static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL); - -static ssize_t -show_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf) -{ - return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8); -} - -static DEVICE_ATTR(iocounterbits, S_IRUGO, show_iostat_counterbits, NULL); - -#define show_sdev_iostat(field) \ -static ssize_t \ -show_iostat_##field(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct scsi_device *sdev = to_scsi_device(dev); \ - unsigned long long count = atomic_read(&sdev->field); \ - return snprintf(buf, 20, "0x%llx\n", count); \ -} \ -static DEVICE_ATTR(field, S_IRUGO, show_iostat_##field, NULL) - -show_sdev_iostat(iorequest_cnt); -show_sdev_iostat(iodone_cnt); -show_sdev_iostat(ioerr_cnt); - -static ssize_t -sdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_device *sdev; - sdev = to_scsi_device(dev); - return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type); -} -static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL); - -#define DECLARE_EVT_SHOW(name, Cap_name) \ -static ssize_t \ -sdev_show_evt_##name(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct scsi_device *sdev = to_scsi_device(dev); \ - int val = test_bit(SDEV_EVT_##Cap_name, sdev->supported_events);\ - return snprintf(buf, 20, "%d\n", val); \ -} - -#define DECLARE_EVT_STORE(name, Cap_name) \ -static ssize_t \ -sdev_store_evt_##name(struct device *dev, struct device_attribute *attr,\ - const char *buf, size_t count) \ -{ \ - struct scsi_device *sdev = to_scsi_device(dev); \ - int val = simple_strtoul(buf, NULL, 0); \ - if (val == 0) \ - clear_bit(SDEV_EVT_##Cap_name, sdev->supported_events); \ - else if (val == 1) \ - set_bit(SDEV_EVT_##Cap_name, sdev->supported_events); \ - else \ - return -EINVAL; \ - return count; \ -} - -#define DECLARE_EVT(name, Cap_name) \ - DECLARE_EVT_SHOW(name, Cap_name) \ - DECLARE_EVT_STORE(name, Cap_name) \ - static DEVICE_ATTR(evt_##name, S_IRUGO, sdev_show_evt_##name, \ - sdev_store_evt_##name); -#define REF_EVT(name) &dev_attr_evt_##name.attr - -DECLARE_EVT(media_change, MEDIA_CHANGE) - -/* Default template for device attributes. May NOT be modified */ -static struct attribute *scsi_sdev_attrs[] = { - &dev_attr_device_blocked.attr, - &dev_attr_type.attr, - &dev_attr_scsi_level.attr, - &dev_attr_vendor.attr, - &dev_attr_model.attr, - &dev_attr_rev.attr, - &dev_attr_rescan.attr, - &dev_attr_delete.attr, - &dev_attr_state.attr, - &dev_attr_timeout.attr, - &dev_attr_iocounterbits.attr, - &dev_attr_iorequest_cnt.attr, - &dev_attr_iodone_cnt.attr, - &dev_attr_ioerr_cnt.attr, - &dev_attr_modalias.attr, - REF_EVT(media_change), - NULL -}; - -static struct attribute_group scsi_sdev_attr_group = { - .attrs = scsi_sdev_attrs, -}; - -static const struct attribute_group *scsi_sdev_attr_groups[] = { - &scsi_sdev_attr_group, - NULL -}; - -static ssize_t -sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int depth, retval; - struct scsi_device *sdev = to_scsi_device(dev); - struct scsi_host_template *sht = sdev->host->hostt; - - if (!sht->change_queue_depth) - return -EINVAL; - - depth = simple_strtoul(buf, NULL, 0); - - if (depth < 1) - return -EINVAL; - - retval = sht->change_queue_depth(sdev, depth, - SCSI_QDEPTH_DEFAULT); - if (retval < 0) - return retval; - - sdev->max_queue_depth = sdev->queue_depth; - - return count; -} - -static struct device_attribute sdev_attr_queue_depth_rw = - __ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth, - sdev_store_queue_depth_rw); - -static ssize_t -sdev_show_queue_ramp_up_period(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct scsi_device *sdev; - sdev = to_scsi_device(dev); - return snprintf(buf, 20, "%u\n", - jiffies_to_msecs(sdev->queue_ramp_up_period)); -} - -static ssize_t -sdev_store_queue_ramp_up_period(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - unsigned long period; - - if (strict_strtoul(buf, 10, &period)) - return -EINVAL; - - sdev->queue_ramp_up_period = msecs_to_jiffies(period); - return period; -} - -static struct device_attribute sdev_attr_queue_ramp_up_period = - __ATTR(queue_ramp_up_period, S_IRUGO | S_IWUSR, - sdev_show_queue_ramp_up_period, - sdev_store_queue_ramp_up_period); - -static ssize_t -sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct scsi_host_template *sht = sdev->host->hostt; - int tag_type = 0, retval; - int prev_tag_type = scsi_get_tag_type(sdev); - - if (!sdev->tagged_supported || !sht->change_queue_type) - return -EINVAL; - - if (strncmp(buf, "ordered", 7) == 0) - tag_type = MSG_ORDERED_TAG; - else if (strncmp(buf, "simple", 6) == 0) - tag_type = MSG_SIMPLE_TAG; - else if (strncmp(buf, "none", 4) != 0) - return -EINVAL; - - if (tag_type == prev_tag_type) - return count; - - retval = sht->change_queue_type(sdev, tag_type); - if (retval < 0) - return retval; - - return count; -} - -static int scsi_target_add(struct scsi_target *starget) -{ - int error; - - if (starget->state != STARGET_CREATED) - return 0; - - error = device_add(&starget->dev); - if (error) { - dev_err(&starget->dev, "target device_add failed, error %d\n", error); - return error; - } - transport_add_device(&starget->dev); - starget->state = STARGET_RUNNING; - - pm_runtime_set_active(&starget->dev); - pm_runtime_enable(&starget->dev); - device_enable_async_suspend(&starget->dev); - - return 0; -} - -static struct device_attribute sdev_attr_queue_type_rw = - __ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field, - sdev_store_queue_type_rw); - -/** - * scsi_sysfs_add_sdev - add scsi device to sysfs - * @sdev: scsi_device to add - * - * Return value: - * 0 on Success / non-zero on Failure - **/ -int scsi_sysfs_add_sdev(struct scsi_device *sdev) -{ - int error, i; - struct request_queue *rq = sdev->request_queue; - struct scsi_target *starget = sdev->sdev_target; - - error = scsi_device_set_state(sdev, SDEV_RUNNING); - if (error) - return error; - - error = scsi_target_add(starget); - if (error) - return error; - - transport_configure_device(&starget->dev); - - device_enable_async_suspend(&sdev->sdev_gendev); - scsi_autopm_get_target(starget); - pm_runtime_set_active(&sdev->sdev_gendev); - pm_runtime_forbid(&sdev->sdev_gendev); - pm_runtime_enable(&sdev->sdev_gendev); - scsi_autopm_put_target(starget); - - /* The following call will keep sdev active indefinitely, until - * its driver does a corresponding scsi_autopm_pm_device(). Only - * drivers supporting autosuspend will do this. - */ - scsi_autopm_get_device(sdev); - - error = device_add(&sdev->sdev_gendev); - if (error) { - sdev_printk(KERN_INFO, sdev, - "failed to add device: %d\n", error); - return error; - } - device_enable_async_suspend(&sdev->sdev_dev); - error = device_add(&sdev->sdev_dev); - if (error) { - sdev_printk(KERN_INFO, sdev, - "failed to add class device: %d\n", error); - device_del(&sdev->sdev_gendev); - return error; - } - transport_add_device(&sdev->sdev_gendev); - sdev->is_visible = 1; - - /* create queue files, which may be writable, depending on the host */ - if (sdev->host->hostt->change_queue_depth) { - error = device_create_file(&sdev->sdev_gendev, - &sdev_attr_queue_depth_rw); - error = device_create_file(&sdev->sdev_gendev, - &sdev_attr_queue_ramp_up_period); - } - else - error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth); - if (error) - return error; - - if (sdev->host->hostt->change_queue_type) - error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw); - else - error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type); - if (error) - return error; - - error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL, NULL); - - if (error) - /* we're treating error on bsg register as non-fatal, - * so pretend nothing went wrong */ - sdev_printk(KERN_INFO, sdev, - "Failed to register bsg queue, errno=%d\n", error); - - /* add additional host specific attributes */ - if (sdev->host->hostt->sdev_attrs) { - for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) { - error = device_create_file(&sdev->sdev_gendev, - sdev->host->hostt->sdev_attrs[i]); - if (error) - return error; - } - } - - return error; -} - -void __scsi_remove_device(struct scsi_device *sdev) -{ - struct device *dev = &sdev->sdev_gendev; - - if (sdev->is_visible) { - if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0) - return; - - bsg_unregister_queue(sdev->request_queue); - device_unregister(&sdev->sdev_dev); - transport_remove_device(dev); - device_del(dev); - } else - put_device(&sdev->sdev_dev); - scsi_device_set_state(sdev, SDEV_DEL); - if (sdev->host->hostt->slave_destroy) - sdev->host->hostt->slave_destroy(sdev); - transport_destroy_device(dev); - - /* cause the request function to reject all I/O requests */ - sdev->request_queue->queuedata = NULL; - - /* Freeing the queue signals to block that we're done */ - scsi_free_queue(sdev->request_queue); - put_device(dev); -} - -/** - * scsi_remove_device - unregister a device from the scsi bus - * @sdev: scsi_device to unregister - **/ -void scsi_remove_device(struct scsi_device *sdev) -{ - struct Scsi_Host *shost = sdev->host; - - mutex_lock(&shost->scan_mutex); - __scsi_remove_device(sdev); - mutex_unlock(&shost->scan_mutex); -} -EXPORT_SYMBOL(scsi_remove_device); - -static void __scsi_remove_target(struct scsi_target *starget) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - unsigned long flags; - struct scsi_device *sdev; - - spin_lock_irqsave(shost->host_lock, flags); - starget->reap_ref++; - restart: - list_for_each_entry(sdev, &shost->__devices, siblings) { - if (sdev->channel != starget->channel || - sdev->id != starget->id || - scsi_device_get(sdev)) - continue; - spin_unlock_irqrestore(shost->host_lock, flags); - scsi_remove_device(sdev); - scsi_device_put(sdev); - spin_lock_irqsave(shost->host_lock, flags); - goto restart; - } - spin_unlock_irqrestore(shost->host_lock, flags); - scsi_target_reap(starget); -} - -static int __remove_child (struct device * dev, void * data) -{ - if (scsi_is_target_device(dev)) - __scsi_remove_target(to_scsi_target(dev)); - return 0; -} - -/** - * scsi_remove_target - try to remove a target and all its devices - * @dev: generic starget or parent of generic stargets to be removed - * - * Note: This is slightly racy. It is possible that if the user - * requests the addition of another device then the target won't be - * removed. - */ -void scsi_remove_target(struct device *dev) -{ - if (scsi_is_target_device(dev)) { - __scsi_remove_target(to_scsi_target(dev)); - return; - } - - get_device(dev); - device_for_each_child(dev, NULL, __remove_child); - put_device(dev); -} -EXPORT_SYMBOL(scsi_remove_target); - -int scsi_register_driver(struct device_driver *drv) -{ - drv->bus = &scsi_bus_type; - - return driver_register(drv); -} -EXPORT_SYMBOL(scsi_register_driver); - -int scsi_register_interface(struct class_interface *intf) -{ - intf->class = &sdev_class; - - return class_interface_register(intf); -} -EXPORT_SYMBOL(scsi_register_interface); - -/** - * scsi_sysfs_add_host - add scsi host to subsystem - * @shost: scsi host struct to add to subsystem - **/ -int scsi_sysfs_add_host(struct Scsi_Host *shost) -{ - int error, i; - - /* add host specific attributes */ - if (shost->hostt->shost_attrs) { - for (i = 0; shost->hostt->shost_attrs[i]; i++) { - error = device_create_file(&shost->shost_dev, - shost->hostt->shost_attrs[i]); - if (error) - return error; - } - } - - transport_register_device(&shost->shost_gendev); - transport_configure_device(&shost->shost_gendev); - return 0; -} - -static struct device_type scsi_dev_type = { - .name = "scsi_device", - .release = scsi_device_dev_release, - .groups = scsi_sdev_attr_groups, -}; - -void scsi_sysfs_device_initialize(struct scsi_device *sdev) -{ - unsigned long flags; - struct Scsi_Host *shost = sdev->host; - struct scsi_target *starget = sdev->sdev_target; - - device_initialize(&sdev->sdev_gendev); - sdev->sdev_gendev.bus = &scsi_bus_type; - sdev->sdev_gendev.type = &scsi_dev_type; - dev_set_name(&sdev->sdev_gendev, "%d:%d:%d:%d", - sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - - device_initialize(&sdev->sdev_dev); - sdev->sdev_dev.parent = get_device(&sdev->sdev_gendev); - sdev->sdev_dev.class = &sdev_class; - dev_set_name(&sdev->sdev_dev, "%d:%d:%d:%d", - sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - sdev->scsi_level = starget->scsi_level; - transport_setup_device(&sdev->sdev_gendev); - spin_lock_irqsave(shost->host_lock, flags); - list_add_tail(&sdev->same_target_siblings, &starget->devices); - list_add_tail(&sdev->siblings, &shost->__devices); - spin_unlock_irqrestore(shost->host_lock, flags); -} - -int scsi_is_sdev_device(const struct device *dev) -{ - return dev->type == &scsi_dev_type; -} -EXPORT_SYMBOL(scsi_is_sdev_device); - -/* A blank transport template that is used in drivers that don't - * yet implement Transport Attributes */ -struct scsi_transport_template blank_transport_template = { { { {NULL, }, }, }, }; diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_tgt_if.c b/ANDROID_3.4.5/drivers/scsi/scsi_tgt_if.c deleted file mode 100644 index 6209110f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_tgt_if.c +++ /dev/null @@ -1,399 +0,0 @@ -/* - * SCSI target kernel/user interface functions - * - * Copyright (C) 2005 FUJITA Tomonori - * Copyright (C) 2005 Mike Christie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "scsi_tgt_priv.h" - -#if TGT_RING_SIZE < PAGE_SIZE -# define TGT_RING_SIZE PAGE_SIZE -#endif - -#define TGT_RING_PAGES (TGT_RING_SIZE >> PAGE_SHIFT) -#define TGT_EVENT_PER_PAGE (PAGE_SIZE / sizeof(struct tgt_event)) -#define TGT_MAX_EVENTS (TGT_EVENT_PER_PAGE * TGT_RING_PAGES) - -struct tgt_ring { - u32 tr_idx; - unsigned long tr_pages[TGT_RING_PAGES]; - spinlock_t tr_lock; -}; - -/* tx_ring : kernel->user, rx_ring : user->kernel */ -static struct tgt_ring tx_ring, rx_ring; -static DECLARE_WAIT_QUEUE_HEAD(tgt_poll_wait); - -static inline void tgt_ring_idx_inc(struct tgt_ring *ring) -{ - if (ring->tr_idx == TGT_MAX_EVENTS - 1) - ring->tr_idx = 0; - else - ring->tr_idx++; -} - -static struct tgt_event *tgt_head_event(struct tgt_ring *ring, u32 idx) -{ - u32 pidx, off; - - pidx = idx / TGT_EVENT_PER_PAGE; - off = idx % TGT_EVENT_PER_PAGE; - - return (struct tgt_event *) - (ring->tr_pages[pidx] + sizeof(struct tgt_event) * off); -} - -static int tgt_uspace_send_event(u32 type, struct tgt_event *p) -{ - struct tgt_event *ev; - struct tgt_ring *ring = &tx_ring; - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&ring->tr_lock, flags); - - ev = tgt_head_event(ring, ring->tr_idx); - if (!ev->hdr.status) - tgt_ring_idx_inc(ring); - else - err = -BUSY; - - spin_unlock_irqrestore(&ring->tr_lock, flags); - - if (err) - return err; - - memcpy(ev, p, sizeof(*ev)); - ev->hdr.type = type; - mb(); - ev->hdr.status = 1; - - flush_dcache_page(virt_to_page(ev)); - - wake_up_interruptible(&tgt_poll_wait); - - return 0; -} - -int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 itn_id, - struct scsi_lun *lun, u64 tag) -{ - struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); - struct tgt_event ev; - int err; - - memset(&ev, 0, sizeof(ev)); - ev.p.cmd_req.host_no = shost->host_no; - ev.p.cmd_req.itn_id = itn_id; - ev.p.cmd_req.data_len = scsi_bufflen(cmd); - memcpy(ev.p.cmd_req.scb, cmd->cmnd, sizeof(ev.p.cmd_req.scb)); - memcpy(ev.p.cmd_req.lun, lun, sizeof(ev.p.cmd_req.lun)); - ev.p.cmd_req.attribute = cmd->tag; - ev.p.cmd_req.tag = tag; - - dprintk("%p %d %u %x %llx\n", cmd, shost->host_no, - ev.p.cmd_req.data_len, cmd->tag, - (unsigned long long) ev.p.cmd_req.tag); - - err = tgt_uspace_send_event(TGT_KEVENT_CMD_REQ, &ev); - if (err) - eprintk("tx buf is full, could not send\n"); - - return err; -} - -int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 itn_id, u64 tag) -{ - struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); - struct tgt_event ev; - int err; - - memset(&ev, 0, sizeof(ev)); - ev.p.cmd_done.host_no = shost->host_no; - ev.p.cmd_done.itn_id = itn_id; - ev.p.cmd_done.tag = tag; - ev.p.cmd_done.result = cmd->result; - - dprintk("%p %d %llu %u %x\n", cmd, shost->host_no, - (unsigned long long) ev.p.cmd_req.tag, - ev.p.cmd_req.data_len, cmd->tag); - - err = tgt_uspace_send_event(TGT_KEVENT_CMD_DONE, &ev); - if (err) - eprintk("tx buf is full, could not send\n"); - - return err; -} - -int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 itn_id, int function, - u64 tag, struct scsi_lun *scsilun, void *data) -{ - struct tgt_event ev; - int err; - - memset(&ev, 0, sizeof(ev)); - ev.p.tsk_mgmt_req.host_no = host_no; - ev.p.tsk_mgmt_req.itn_id = itn_id; - ev.p.tsk_mgmt_req.function = function; - ev.p.tsk_mgmt_req.tag = tag; - memcpy(ev.p.tsk_mgmt_req.lun, scsilun, sizeof(ev.p.tsk_mgmt_req.lun)); - ev.p.tsk_mgmt_req.mid = (u64) (unsigned long) data; - - dprintk("%d %x %llx %llx\n", host_no, function, (unsigned long long) tag, - (unsigned long long) ev.p.tsk_mgmt_req.mid); - - err = tgt_uspace_send_event(TGT_KEVENT_TSK_MGMT_REQ, &ev); - if (err) - eprintk("tx buf is full, could not send\n"); - - return err; -} - -int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 itn_id, - int function, char *initiator_id) -{ - struct tgt_event ev; - int err; - - memset(&ev, 0, sizeof(ev)); - ev.p.it_nexus_req.host_no = host_no; - ev.p.it_nexus_req.function = function; - ev.p.it_nexus_req.itn_id = itn_id; - if (initiator_id) - strncpy(ev.p.it_nexus_req.initiator_id, initiator_id, - sizeof(ev.p.it_nexus_req.initiator_id)); - - dprintk("%d %x %llx\n", host_no, function, (unsigned long long)itn_id); - - err = tgt_uspace_send_event(TGT_KEVENT_IT_NEXUS_REQ, &ev); - if (err) - eprintk("tx buf is full, could not send\n"); - - return err; -} - -static int event_recv_msg(struct tgt_event *ev) -{ - int err = 0; - - switch (ev->hdr.type) { - case TGT_UEVENT_CMD_RSP: - err = scsi_tgt_kspace_exec(ev->p.cmd_rsp.host_no, - ev->p.cmd_rsp.itn_id, - ev->p.cmd_rsp.result, - ev->p.cmd_rsp.tag, - ev->p.cmd_rsp.uaddr, - ev->p.cmd_rsp.len, - ev->p.cmd_rsp.sense_uaddr, - ev->p.cmd_rsp.sense_len, - ev->p.cmd_rsp.rw); - break; - case TGT_UEVENT_TSK_MGMT_RSP: - err = scsi_tgt_kspace_tsk_mgmt(ev->p.tsk_mgmt_rsp.host_no, - ev->p.tsk_mgmt_rsp.itn_id, - ev->p.tsk_mgmt_rsp.mid, - ev->p.tsk_mgmt_rsp.result); - break; - case TGT_UEVENT_IT_NEXUS_RSP: - err = scsi_tgt_kspace_it_nexus_rsp(ev->p.it_nexus_rsp.host_no, - ev->p.it_nexus_rsp.itn_id, - ev->p.it_nexus_rsp.result); - break; - default: - eprintk("unknown type %d\n", ev->hdr.type); - err = -EINVAL; - } - - return err; -} - -static ssize_t tgt_write(struct file *file, const char __user * buffer, - size_t count, loff_t * ppos) -{ - struct tgt_event *ev; - struct tgt_ring *ring = &rx_ring; - - while (1) { - ev = tgt_head_event(ring, ring->tr_idx); - /* do we need this? */ - flush_dcache_page(virt_to_page(ev)); - - if (!ev->hdr.status) - break; - - tgt_ring_idx_inc(ring); - event_recv_msg(ev); - ev->hdr.status = 0; - }; - - return count; -} - -static unsigned int tgt_poll(struct file * file, struct poll_table_struct *wait) -{ - struct tgt_event *ev; - struct tgt_ring *ring = &tx_ring; - unsigned long flags; - unsigned int mask = 0; - u32 idx; - - poll_wait(file, &tgt_poll_wait, wait); - - spin_lock_irqsave(&ring->tr_lock, flags); - - idx = ring->tr_idx ? ring->tr_idx - 1 : TGT_MAX_EVENTS - 1; - ev = tgt_head_event(ring, idx); - if (ev->hdr.status) - mask |= POLLIN | POLLRDNORM; - - spin_unlock_irqrestore(&ring->tr_lock, flags); - - return mask; -} - -static int uspace_ring_map(struct vm_area_struct *vma, unsigned long addr, - struct tgt_ring *ring) -{ - int i, err; - - for (i = 0; i < TGT_RING_PAGES; i++) { - struct page *page = virt_to_page(ring->tr_pages[i]); - err = vm_insert_page(vma, addr, page); - if (err) - return err; - addr += PAGE_SIZE; - } - - return 0; -} - -static int tgt_mmap(struct file *filp, struct vm_area_struct *vma) -{ - unsigned long addr; - int err; - - if (vma->vm_pgoff) - return -EINVAL; - - if (vma->vm_end - vma->vm_start != TGT_RING_SIZE * 2) { - eprintk("mmap size must be %lu, not %lu \n", - TGT_RING_SIZE * 2, vma->vm_end - vma->vm_start); - return -EINVAL; - } - - addr = vma->vm_start; - err = uspace_ring_map(vma, addr, &tx_ring); - if (err) - return err; - err = uspace_ring_map(vma, addr + TGT_RING_SIZE, &rx_ring); - - return err; -} - -static int tgt_open(struct inode *inode, struct file *file) -{ - tx_ring.tr_idx = rx_ring.tr_idx = 0; - - return 0; -} - -static const struct file_operations tgt_fops = { - .owner = THIS_MODULE, - .open = tgt_open, - .poll = tgt_poll, - .write = tgt_write, - .mmap = tgt_mmap, - .llseek = noop_llseek, -}; - -static struct miscdevice tgt_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "tgt", - .fops = &tgt_fops, -}; - -static void tgt_ring_exit(struct tgt_ring *ring) -{ - int i; - - for (i = 0; i < TGT_RING_PAGES; i++) - free_page(ring->tr_pages[i]); -} - -static int tgt_ring_init(struct tgt_ring *ring) -{ - int i; - - spin_lock_init(&ring->tr_lock); - - for (i = 0; i < TGT_RING_PAGES; i++) { - ring->tr_pages[i] = get_zeroed_page(GFP_KERNEL); - if (!ring->tr_pages[i]) { - eprintk("out of memory\n"); - return -ENOMEM; - } - } - - return 0; -} - -void scsi_tgt_if_exit(void) -{ - tgt_ring_exit(&tx_ring); - tgt_ring_exit(&rx_ring); - misc_deregister(&tgt_miscdev); -} - -int scsi_tgt_if_init(void) -{ - int err; - - err = tgt_ring_init(&tx_ring); - if (err) - return err; - - err = tgt_ring_init(&rx_ring); - if (err) - goto free_tx_ring; - - err = misc_register(&tgt_miscdev); - if (err) - goto free_rx_ring; - - return 0; -free_rx_ring: - tgt_ring_exit(&rx_ring); -free_tx_ring: - tgt_ring_exit(&tx_ring); - - return err; -} diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_tgt_lib.c b/ANDROID_3.4.5/drivers/scsi/scsi_tgt_lib.c deleted file mode 100644 index 84a1fdf6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_tgt_lib.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * SCSI target lib functions - * - * Copyright (C) 2005 Mike Christie - * Copyright (C) 2005 FUJITA Tomonori - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi_tgt_priv.h" - -static struct workqueue_struct *scsi_tgtd; -static struct kmem_cache *scsi_tgt_cmd_cache; - -/* - * TODO: this struct will be killed when the block layer supports large bios - * and James's work struct code is in - */ -struct scsi_tgt_cmd { - /* TODO replace work with James b's code */ - struct work_struct work; - /* TODO fix limits of some drivers */ - struct bio *bio; - - struct list_head hash_list; - struct request *rq; - u64 itn_id; - u64 tag; -}; - -#define TGT_HASH_ORDER 4 -#define cmd_hashfn(tag) hash_long((unsigned long) (tag), TGT_HASH_ORDER) - -struct scsi_tgt_queuedata { - struct Scsi_Host *shost; - struct list_head cmd_hash[1 << TGT_HASH_ORDER]; - spinlock_t cmd_hash_lock; -}; - -/* - * Function: scsi_host_get_command() - * - * Purpose: Allocate and setup a scsi command block and blk request - * - * Arguments: shost - scsi host - * data_dir - dma data dir - * gfp_mask- allocator flags - * - * Returns: The allocated scsi command structure. - * - * This should be called by target LLDs to get a command. - */ -struct scsi_cmnd *scsi_host_get_command(struct Scsi_Host *shost, - enum dma_data_direction data_dir, - gfp_t gfp_mask) -{ - int write = (data_dir == DMA_TO_DEVICE); - struct request *rq; - struct scsi_cmnd *cmd; - struct scsi_tgt_cmd *tcmd; - - /* Bail if we can't get a reference to the device */ - if (!get_device(&shost->shost_gendev)) - return NULL; - - tcmd = kmem_cache_alloc(scsi_tgt_cmd_cache, GFP_ATOMIC); - if (!tcmd) - goto put_dev; - - /* - * The blk helpers are used to the READ/WRITE requests - * transferring data from a initiator point of view. Since - * we are in target mode we want the opposite. - */ - rq = blk_get_request(shost->uspace_req_q, !write, gfp_mask); - if (!rq) - goto free_tcmd; - - cmd = __scsi_get_command(shost, gfp_mask); - if (!cmd) - goto release_rq; - - cmd->sc_data_direction = data_dir; - cmd->jiffies_at_alloc = jiffies; - cmd->request = rq; - - cmd->cmnd = rq->cmd; - - rq->special = cmd; - rq->cmd_type = REQ_TYPE_SPECIAL; - rq->cmd_flags |= REQ_TYPE_BLOCK_PC; - rq->end_io_data = tcmd; - - tcmd->rq = rq; - - return cmd; - -release_rq: - blk_put_request(rq); -free_tcmd: - kmem_cache_free(scsi_tgt_cmd_cache, tcmd); -put_dev: - put_device(&shost->shost_gendev); - return NULL; - -} -EXPORT_SYMBOL_GPL(scsi_host_get_command); - -/* - * Function: scsi_host_put_command() - * - * Purpose: Free a scsi command block - * - * Arguments: shost - scsi host - * cmd - command block to free - * - * Returns: Nothing. - * - * Notes: The command must not belong to any lists. - */ -void scsi_host_put_command(struct Scsi_Host *shost, struct scsi_cmnd *cmd) -{ - struct request_queue *q = shost->uspace_req_q; - struct request *rq = cmd->request; - struct scsi_tgt_cmd *tcmd = rq->end_io_data; - unsigned long flags; - - kmem_cache_free(scsi_tgt_cmd_cache, tcmd); - - spin_lock_irqsave(q->queue_lock, flags); - __blk_put_request(q, rq); - spin_unlock_irqrestore(q->queue_lock, flags); - - __scsi_put_command(shost, cmd, &shost->shost_gendev); -} -EXPORT_SYMBOL_GPL(scsi_host_put_command); - -static void cmd_hashlist_del(struct scsi_cmnd *cmd) -{ - struct request_queue *q = cmd->request->q; - struct scsi_tgt_queuedata *qdata = q->queuedata; - unsigned long flags; - struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; - - spin_lock_irqsave(&qdata->cmd_hash_lock, flags); - list_del(&tcmd->hash_list); - spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); -} - -static void scsi_unmap_user_pages(struct scsi_tgt_cmd *tcmd) -{ - blk_rq_unmap_user(tcmd->bio); -} - -static void scsi_tgt_cmd_destroy(struct work_struct *work) -{ - struct scsi_tgt_cmd *tcmd = - container_of(work, struct scsi_tgt_cmd, work); - struct scsi_cmnd *cmd = tcmd->rq->special; - - dprintk("cmd %p %d %u\n", cmd, cmd->sc_data_direction, - rq_data_dir(cmd->request)); - scsi_unmap_user_pages(tcmd); - tcmd->rq->bio = NULL; - scsi_host_put_command(scsi_tgt_cmd_to_host(cmd), cmd); -} - -static void init_scsi_tgt_cmd(struct request *rq, struct scsi_tgt_cmd *tcmd, - u64 itn_id, u64 tag) -{ - struct scsi_tgt_queuedata *qdata = rq->q->queuedata; - unsigned long flags; - struct list_head *head; - - tcmd->itn_id = itn_id; - tcmd->tag = tag; - tcmd->bio = NULL; - INIT_WORK(&tcmd->work, scsi_tgt_cmd_destroy); - spin_lock_irqsave(&qdata->cmd_hash_lock, flags); - head = &qdata->cmd_hash[cmd_hashfn(tag)]; - list_add(&tcmd->hash_list, head); - spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); -} - -/* - * scsi_tgt_alloc_queue - setup queue used for message passing - * shost: scsi host - * - * This should be called by the LLD after host allocation. - * And will be released when the host is released. - */ -int scsi_tgt_alloc_queue(struct Scsi_Host *shost) -{ - struct scsi_tgt_queuedata *queuedata; - struct request_queue *q; - int err, i; - - /* - * Do we need to send a netlink event or should uspace - * just respond to the hotplug event? - */ - q = __scsi_alloc_queue(shost, NULL); - if (!q) - return -ENOMEM; - - queuedata = kzalloc(sizeof(*queuedata), GFP_KERNEL); - if (!queuedata) { - err = -ENOMEM; - goto cleanup_queue; - } - queuedata->shost = shost; - q->queuedata = queuedata; - - /* - * this is a silly hack. We should probably just queue as many - * command as is recvd to userspace. uspace can then make - * sure we do not overload the HBA - */ - q->nr_requests = shost->can_queue; - /* - * We currently only support software LLDs so this does - * not matter for now. Do we need this for the cards we support? - * If so we should make it a host template value. - */ - blk_queue_dma_alignment(q, 0); - shost->uspace_req_q = q; - - for (i = 0; i < ARRAY_SIZE(queuedata->cmd_hash); i++) - INIT_LIST_HEAD(&queuedata->cmd_hash[i]); - spin_lock_init(&queuedata->cmd_hash_lock); - - return 0; - -cleanup_queue: - blk_cleanup_queue(q); - return err; -} -EXPORT_SYMBOL_GPL(scsi_tgt_alloc_queue); - -void scsi_tgt_free_queue(struct Scsi_Host *shost) -{ - int i; - unsigned long flags; - struct request_queue *q = shost->uspace_req_q; - struct scsi_cmnd *cmd; - struct scsi_tgt_queuedata *qdata = q->queuedata; - struct scsi_tgt_cmd *tcmd, *n; - LIST_HEAD(cmds); - - spin_lock_irqsave(&qdata->cmd_hash_lock, flags); - - for (i = 0; i < ARRAY_SIZE(qdata->cmd_hash); i++) { - list_for_each_entry_safe(tcmd, n, &qdata->cmd_hash[i], - hash_list) - list_move(&tcmd->hash_list, &cmds); - } - - spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); - - while (!list_empty(&cmds)) { - tcmd = list_entry(cmds.next, struct scsi_tgt_cmd, hash_list); - list_del(&tcmd->hash_list); - cmd = tcmd->rq->special; - - shost->hostt->eh_abort_handler(cmd); - scsi_tgt_cmd_destroy(&tcmd->work); - } -} -EXPORT_SYMBOL_GPL(scsi_tgt_free_queue); - -struct Scsi_Host *scsi_tgt_cmd_to_host(struct scsi_cmnd *cmd) -{ - struct scsi_tgt_queuedata *queue = cmd->request->q->queuedata; - return queue->shost; -} -EXPORT_SYMBOL_GPL(scsi_tgt_cmd_to_host); - -/* - * scsi_tgt_queue_command - queue command for userspace processing - * @cmd: scsi command - * @scsilun: scsi lun - * @tag: unique value to identify this command for tmf - */ -int scsi_tgt_queue_command(struct scsi_cmnd *cmd, u64 itn_id, - struct scsi_lun *scsilun, u64 tag) -{ - struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; - int err; - - init_scsi_tgt_cmd(cmd->request, tcmd, itn_id, tag); - err = scsi_tgt_uspace_send_cmd(cmd, itn_id, scsilun, tag); - if (err) - cmd_hashlist_del(cmd); - - return err; -} -EXPORT_SYMBOL_GPL(scsi_tgt_queue_command); - -/* - * This is run from a interrupt handler normally and the unmap - * needs process context so we must queue - */ -static void scsi_tgt_cmd_done(struct scsi_cmnd *cmd) -{ - struct scsi_tgt_cmd *tcmd = cmd->request->end_io_data; - - dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request)); - - scsi_tgt_uspace_send_status(cmd, tcmd->itn_id, tcmd->tag); - - scsi_release_buffers(cmd); - - queue_work(scsi_tgtd, &tcmd->work); -} - -static int scsi_tgt_transfer_response(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *shost = scsi_tgt_cmd_to_host(cmd); - int err; - - dprintk("cmd %p %u\n", cmd, rq_data_dir(cmd->request)); - - err = shost->hostt->transfer_response(cmd, scsi_tgt_cmd_done); - switch (err) { - case SCSI_MLQUEUE_HOST_BUSY: - case SCSI_MLQUEUE_DEVICE_BUSY: - return -EAGAIN; - } - return 0; -} - -/* TODO: test this crap and replace bio_map_user with new interface maybe */ -static int scsi_map_user_pages(struct scsi_tgt_cmd *tcmd, struct scsi_cmnd *cmd, - unsigned long uaddr, unsigned int len, int rw) -{ - struct request_queue *q = cmd->request->q; - struct request *rq = cmd->request; - int err; - - dprintk("%lx %u\n", uaddr, len); - err = blk_rq_map_user(q, rq, NULL, (void *)uaddr, len, GFP_KERNEL); - if (err) { - /* - * TODO: need to fixup sg_tablesize, max_segment_size, - * max_sectors, etc for modern HW and software drivers - * where this value is bogus. - * - * TODO2: we can alloc a reserve buffer of max size - * we can handle and do the slow copy path for really large - * IO. - */ - eprintk("Could not handle request of size %u.\n", len); - return err; - } - - tcmd->bio = rq->bio; - err = scsi_init_io(cmd, GFP_KERNEL); - if (err) { - scsi_release_buffers(cmd); - goto unmap_rq; - } - /* - * we use REQ_TYPE_BLOCK_PC so scsi_init_io doesn't set the - * length for us. - */ - cmd->sdb.length = blk_rq_bytes(rq); - - return 0; - -unmap_rq: - scsi_unmap_user_pages(tcmd); - return err; -} - -static int scsi_tgt_copy_sense(struct scsi_cmnd *cmd, unsigned long uaddr, - unsigned len) -{ - char __user *p = (char __user *) uaddr; - - if (copy_from_user(cmd->sense_buffer, p, - min_t(unsigned, SCSI_SENSE_BUFFERSIZE, len))) { - printk(KERN_ERR "Could not copy the sense buffer\n"); - return -EIO; - } - return 0; -} - -static int scsi_tgt_abort_cmd(struct Scsi_Host *shost, struct scsi_cmnd *cmd) -{ - struct scsi_tgt_cmd *tcmd; - int err; - - err = shost->hostt->eh_abort_handler(cmd); - if (err) - eprintk("fail to abort %p\n", cmd); - - tcmd = cmd->request->end_io_data; - scsi_tgt_cmd_destroy(&tcmd->work); - return err; -} - -static struct request *tgt_cmd_hash_lookup(struct request_queue *q, u64 tag) -{ - struct scsi_tgt_queuedata *qdata = q->queuedata; - struct request *rq = NULL; - struct list_head *head; - struct scsi_tgt_cmd *tcmd; - unsigned long flags; - - head = &qdata->cmd_hash[cmd_hashfn(tag)]; - spin_lock_irqsave(&qdata->cmd_hash_lock, flags); - list_for_each_entry(tcmd, head, hash_list) { - if (tcmd->tag == tag) { - rq = tcmd->rq; - list_del(&tcmd->hash_list); - break; - } - } - spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); - - return rq; -} - -int scsi_tgt_kspace_exec(int host_no, u64 itn_id, int result, u64 tag, - unsigned long uaddr, u32 len, unsigned long sense_uaddr, - u32 sense_len, u8 rw) -{ - struct Scsi_Host *shost; - struct scsi_cmnd *cmd; - struct request *rq; - struct scsi_tgt_cmd *tcmd; - int err = 0; - - dprintk("%d %llu %d %u %lx %u\n", host_no, (unsigned long long) tag, - result, len, uaddr, rw); - - /* TODO: replace with a O(1) alg */ - shost = scsi_host_lookup(host_no); - if (!shost) { - printk(KERN_ERR "Could not find host no %d\n", host_no); - return -EINVAL; - } - - if (!shost->uspace_req_q) { - printk(KERN_ERR "Not target scsi host %d\n", host_no); - goto done; - } - - rq = tgt_cmd_hash_lookup(shost->uspace_req_q, tag); - if (!rq) { - printk(KERN_ERR "Could not find tag %llu\n", - (unsigned long long) tag); - err = -EINVAL; - goto done; - } - cmd = rq->special; - - dprintk("cmd %p scb %x result %d len %d bufflen %u %u %x\n", - cmd, cmd->cmnd[0], result, len, scsi_bufflen(cmd), - rq_data_dir(rq), cmd->cmnd[0]); - - if (result == TASK_ABORTED) { - scsi_tgt_abort_cmd(shost, cmd); - goto done; - } - /* - * store the userspace values here, the working values are - * in the request_* values - */ - tcmd = cmd->request->end_io_data; - cmd->result = result; - - if (cmd->result == SAM_STAT_CHECK_CONDITION) - scsi_tgt_copy_sense(cmd, sense_uaddr, sense_len); - - if (len) { - err = scsi_map_user_pages(rq->end_io_data, cmd, uaddr, len, rw); - if (err) { - /* - * user-space daemon bugs or OOM - * TODO: we can do better for OOM. - */ - struct scsi_tgt_queuedata *qdata; - struct list_head *head; - unsigned long flags; - - eprintk("cmd %p ret %d uaddr %lx len %d rw %d\n", - cmd, err, uaddr, len, rw); - - qdata = shost->uspace_req_q->queuedata; - head = &qdata->cmd_hash[cmd_hashfn(tcmd->tag)]; - - spin_lock_irqsave(&qdata->cmd_hash_lock, flags); - list_add(&tcmd->hash_list, head); - spin_unlock_irqrestore(&qdata->cmd_hash_lock, flags); - - goto done; - } - } - err = scsi_tgt_transfer_response(cmd); -done: - scsi_host_put(shost); - return err; -} - -int scsi_tgt_tsk_mgmt_request(struct Scsi_Host *shost, u64 itn_id, - int function, u64 tag, struct scsi_lun *scsilun, - void *data) -{ - int err; - - /* TODO: need to retry if this fails. */ - err = scsi_tgt_uspace_send_tsk_mgmt(shost->host_no, itn_id, - function, tag, scsilun, data); - if (err < 0) - eprintk("The task management request lost!\n"); - return err; -} -EXPORT_SYMBOL_GPL(scsi_tgt_tsk_mgmt_request); - -int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 itn_id, u64 mid, int result) -{ - struct Scsi_Host *shost; - int err = -EINVAL; - - dprintk("%d %d %llx\n", host_no, result, (unsigned long long) mid); - - shost = scsi_host_lookup(host_no); - if (!shost) { - printk(KERN_ERR "Could not find host no %d\n", host_no); - return err; - } - - if (!shost->uspace_req_q) { - printk(KERN_ERR "Not target scsi host %d\n", host_no); - goto done; - } - - err = shost->transportt->tsk_mgmt_response(shost, itn_id, mid, result); -done: - scsi_host_put(shost); - return err; -} - -int scsi_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, - char *initiator) -{ - int err; - - /* TODO: need to retry if this fails. */ - err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, itn_id, 0, - initiator); - if (err < 0) - eprintk("The i_t_neuxs request lost, %d %llx!\n", - shost->host_no, (unsigned long long)itn_id); - return err; -} -EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_create); - -int scsi_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) -{ - int err; - - /* TODO: need to retry if this fails. */ - err = scsi_tgt_uspace_send_it_nexus_request(shost->host_no, - itn_id, 1, NULL); - if (err < 0) - eprintk("The i_t_neuxs request lost, %d %llx!\n", - shost->host_no, (unsigned long long)itn_id); - return err; -} -EXPORT_SYMBOL_GPL(scsi_tgt_it_nexus_destroy); - -int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 itn_id, int result) -{ - struct Scsi_Host *shost; - int err = -EINVAL; - - dprintk("%d %d%llx\n", host_no, result, (unsigned long long)itn_id); - - shost = scsi_host_lookup(host_no); - if (!shost) { - printk(KERN_ERR "Could not find host no %d\n", host_no); - return err; - } - - if (!shost->uspace_req_q) { - printk(KERN_ERR "Not target scsi host %d\n", host_no); - goto done; - } - - err = shost->transportt->it_nexus_response(shost, itn_id, result); -done: - scsi_host_put(shost); - return err; -} - -static int __init scsi_tgt_init(void) -{ - int err; - - scsi_tgt_cmd_cache = KMEM_CACHE(scsi_tgt_cmd, 0); - if (!scsi_tgt_cmd_cache) - return -ENOMEM; - - scsi_tgtd = alloc_workqueue("scsi_tgtd", 0, 1); - if (!scsi_tgtd) { - err = -ENOMEM; - goto free_kmemcache; - } - - err = scsi_tgt_if_init(); - if (err) - goto destroy_wq; - - return 0; - -destroy_wq: - destroy_workqueue(scsi_tgtd); -free_kmemcache: - kmem_cache_destroy(scsi_tgt_cmd_cache); - return err; -} - -static void __exit scsi_tgt_exit(void) -{ - destroy_workqueue(scsi_tgtd); - scsi_tgt_if_exit(); - kmem_cache_destroy(scsi_tgt_cmd_cache); -} - -module_init(scsi_tgt_init); -module_exit(scsi_tgt_exit); - -MODULE_DESCRIPTION("SCSI target core"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_tgt_priv.h b/ANDROID_3.4.5/drivers/scsi/scsi_tgt_priv.h deleted file mode 100644 index fe4c6217..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_tgt_priv.h +++ /dev/null @@ -1,32 +0,0 @@ -struct scsi_cmnd; -struct scsi_lun; -struct Scsi_Host; -struct task_struct; - -/* tmp - will replace with SCSI logging stuff */ -#define eprintk(fmt, args...) \ -do { \ - printk("%s(%d) " fmt, __func__, __LINE__, ##args); \ -} while (0) - -#define dprintk(fmt, args...) -/* #define dprintk eprintk */ - -extern void scsi_tgt_if_exit(void); -extern int scsi_tgt_if_init(void); - -extern int scsi_tgt_uspace_send_cmd(struct scsi_cmnd *cmd, u64 it_nexus_id, - struct scsi_lun *lun, u64 tag); -extern int scsi_tgt_uspace_send_status(struct scsi_cmnd *cmd, u64 it_nexus_id, - u64 tag); -extern int scsi_tgt_kspace_exec(int host_no, u64 it_nexus_id, int result, u64 tag, - unsigned long uaddr, u32 len, - unsigned long sense_uaddr, u32 sense_len, u8 rw); -extern int scsi_tgt_uspace_send_tsk_mgmt(int host_no, u64 it_nexus_id, - int function, u64 tag, - struct scsi_lun *scsilun, void *data); -extern int scsi_tgt_kspace_tsk_mgmt(int host_no, u64 it_nexus_id, - u64 mid, int result); -extern int scsi_tgt_uspace_send_it_nexus_request(int host_no, u64 it_nexus_id, - int function, char *initiator); -extern int scsi_tgt_kspace_it_nexus_rsp(int host_no, u64 it_nexus_id, int result); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_trace.c b/ANDROID_3.4.5/drivers/scsi/scsi_trace.c deleted file mode 100644 index 2bea4f0b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_trace.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2010 FUJITSU LIMITED - * Copyright (C) 2010 Tomohiro Kusumi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include -#include -#include - -#define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) -#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) - -static const char * -scsi_trace_misc(struct trace_seq *, unsigned char *, int); - -static const char * -scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) -{ - const char *ret = p->buffer + p->len; - sector_t lba = 0, txlen = 0; - - lba |= ((cdb[1] & 0x1F) << 16); - lba |= (cdb[2] << 8); - lba |= cdb[3]; - txlen = cdb[4]; - - trace_seq_printf(p, "lba=%llu txlen=%llu", - (unsigned long long)lba, (unsigned long long)txlen); - trace_seq_putc(p, 0); - - return ret; -} - -static const char * -scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) -{ - const char *ret = p->buffer + p->len; - sector_t lba = 0, txlen = 0; - - lba |= (cdb[2] << 24); - lba |= (cdb[3] << 16); - lba |= (cdb[4] << 8); - lba |= cdb[5]; - txlen |= (cdb[7] << 8); - txlen |= cdb[8]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, - cdb[1] >> 5); - - if (cdb[0] == WRITE_SAME) - trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); - - trace_seq_putc(p, 0); - - return ret; -} - -static const char * -scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) -{ - const char *ret = p->buffer + p->len; - sector_t lba = 0, txlen = 0; - - lba |= (cdb[2] << 24); - lba |= (cdb[3] << 16); - lba |= (cdb[4] << 8); - lba |= cdb[5]; - txlen |= (cdb[6] << 24); - txlen |= (cdb[7] << 16); - txlen |= (cdb[8] << 8); - txlen |= cdb[9]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, - cdb[1] >> 5); - trace_seq_putc(p, 0); - - return ret; -} - -static const char * -scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) -{ - const char *ret = p->buffer + p->len; - sector_t lba = 0, txlen = 0; - - lba |= ((u64)cdb[2] << 56); - lba |= ((u64)cdb[3] << 48); - lba |= ((u64)cdb[4] << 40); - lba |= ((u64)cdb[5] << 32); - lba |= (cdb[6] << 24); - lba |= (cdb[7] << 16); - lba |= (cdb[8] << 8); - lba |= cdb[9]; - txlen |= (cdb[10] << 24); - txlen |= (cdb[11] << 16); - txlen |= (cdb[12] << 8); - txlen |= cdb[13]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, - cdb[1] >> 5); - - if (cdb[0] == WRITE_SAME_16) - trace_seq_printf(p, " unmap=%u", cdb[1] >> 3 & 1); - - trace_seq_putc(p, 0); - - return ret; -} - -static const char * -scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) -{ - const char *ret = p->buffer + p->len, *cmd; - sector_t lba = 0, txlen = 0; - u32 ei_lbrt = 0; - - switch (SERVICE_ACTION32(cdb)) { - case READ_32: - cmd = "READ"; - break; - case VERIFY_32: - cmd = "VERIFY"; - break; - case WRITE_32: - cmd = "WRITE"; - break; - case WRITE_SAME_32: - cmd = "WRITE_SAME"; - break; - default: - trace_seq_printf(p, "UNKNOWN"); - goto out; - } - - lba |= ((u64)cdb[12] << 56); - lba |= ((u64)cdb[13] << 48); - lba |= ((u64)cdb[14] << 40); - lba |= ((u64)cdb[15] << 32); - lba |= (cdb[16] << 24); - lba |= (cdb[17] << 16); - lba |= (cdb[18] << 8); - lba |= cdb[19]; - ei_lbrt |= (cdb[20] << 24); - ei_lbrt |= (cdb[21] << 16); - ei_lbrt |= (cdb[22] << 8); - ei_lbrt |= cdb[23]; - txlen |= (cdb[28] << 24); - txlen |= (cdb[29] << 16); - txlen |= (cdb[30] << 8); - txlen |= cdb[31]; - - trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", - cmd, (unsigned long long)lba, - (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); - - if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) - trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); - -out: - trace_seq_putc(p, 0); - - return ret; -} - -static const char * -scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) -{ - const char *ret = p->buffer + p->len; - unsigned int regions = cdb[7] << 8 | cdb[8]; - - trace_seq_printf(p, "regions=%u", (regions - 8) / 16); - trace_seq_putc(p, 0); - - return ret; -} - -static const char * -scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) -{ - const char *ret = p->buffer + p->len, *cmd; - sector_t lba = 0; - u32 alloc_len = 0; - - switch (SERVICE_ACTION16(cdb)) { - case SAI_READ_CAPACITY_16: - cmd = "READ_CAPACITY_16"; - break; - case SAI_GET_LBA_STATUS: - cmd = "GET_LBA_STATUS"; - break; - default: - trace_seq_printf(p, "UNKNOWN"); - goto out; - } - - lba |= ((u64)cdb[2] << 56); - lba |= ((u64)cdb[3] << 48); - lba |= ((u64)cdb[4] << 40); - lba |= ((u64)cdb[5] << 32); - lba |= (cdb[6] << 24); - lba |= (cdb[7] << 16); - lba |= (cdb[8] << 8); - lba |= cdb[9]; - alloc_len |= (cdb[10] << 24); - alloc_len |= (cdb[11] << 16); - alloc_len |= (cdb[12] << 8); - alloc_len |= cdb[13]; - - trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, - (unsigned long long)lba, alloc_len); - -out: - trace_seq_putc(p, 0); - - return ret; -} - -static const char * -scsi_trace_varlen(struct trace_seq *p, unsigned char *cdb, int len) -{ - switch (SERVICE_ACTION32(cdb)) { - case READ_32: - case VERIFY_32: - case WRITE_32: - case WRITE_SAME_32: - return scsi_trace_rw32(p, cdb, len); - default: - return scsi_trace_misc(p, cdb, len); - } -} - -static const char * -scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len) -{ - const char *ret = p->buffer + p->len; - - trace_seq_printf(p, "-"); - trace_seq_putc(p, 0); - - return ret; -} - -const char * -scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len) -{ - switch (cdb[0]) { - case READ_6: - case WRITE_6: - return scsi_trace_rw6(p, cdb, len); - case READ_10: - case VERIFY: - case WRITE_10: - case WRITE_SAME: - return scsi_trace_rw10(p, cdb, len); - case READ_12: - case VERIFY_12: - case WRITE_12: - return scsi_trace_rw12(p, cdb, len); - case READ_16: - case VERIFY_16: - case WRITE_16: - case WRITE_SAME_16: - return scsi_trace_rw16(p, cdb, len); - case UNMAP: - return scsi_trace_unmap(p, cdb, len); - case SERVICE_ACTION_IN: - return scsi_trace_service_action_in(p, cdb, len); - case VARIABLE_LENGTH_CMD: - return scsi_trace_varlen(p, cdb, len); - default: - return scsi_trace_misc(p, cdb, len); - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_transport_api.h b/ANDROID_3.4.5/drivers/scsi/scsi_transport_api.h deleted file mode 100644 index 934f0e62..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_transport_api.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _SCSI_TRANSPORT_API_H -#define _SCSI_TRANSPORT_API_H - -void scsi_schedule_eh(struct Scsi_Host *shost); - -#endif /* _SCSI_TRANSPORT_API_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_transport_fc.c b/ANDROID_3.4.5/drivers/scsi/scsi_transport_fc.c deleted file mode 100644 index 80fbe2ac..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_transport_fc.c +++ /dev/null @@ -1,4180 +0,0 @@ -/* - * FiberChannel transport specific attributes exported to sysfs. - * - * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * ======== - * - * Copyright (C) 2004-2007 James Smart, Emulex Corporation - * Rewrite for host, target, device, and remote port attributes, - * statistics, and service functions... - * Add vports, etc - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "scsi_priv.h" -#include "scsi_transport_fc_internal.h" - -static int fc_queue_work(struct Scsi_Host *, struct work_struct *); -static void fc_vport_sched_delete(struct work_struct *work); -static int fc_vport_setup(struct Scsi_Host *shost, int channel, - struct device *pdev, struct fc_vport_identifiers *ids, - struct fc_vport **vport); -static int fc_bsg_hostadd(struct Scsi_Host *, struct fc_host_attrs *); -static int fc_bsg_rportadd(struct Scsi_Host *, struct fc_rport *); -static void fc_bsg_remove(struct request_queue *); -static void fc_bsg_goose_queue(struct fc_rport *); - -/* - * Module Parameters - */ - -/* - * dev_loss_tmo: the default number of seconds that the FC transport - * should insulate the loss of a remote port. - * The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT. - */ -static unsigned int fc_dev_loss_tmo = 60; /* seconds */ - -module_param_named(dev_loss_tmo, fc_dev_loss_tmo, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(dev_loss_tmo, - "Maximum number of seconds that the FC transport should" - " insulate the loss of a remote port. Once this value is" - " exceeded, the scsi target is removed. Value should be" - " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT if" - " fast_io_fail_tmo is not set."); - -/* - * Redefine so that we can have same named attributes in the - * sdev/starget/host objects. - */ -#define FC_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ -struct device_attribute device_attr_##_prefix##_##_name = \ - __ATTR(_name,_mode,_show,_store) - -#define fc_enum_name_search(title, table_type, table) \ -static const char *get_fc_##title##_name(enum table_type table_key) \ -{ \ - int i; \ - char *name = NULL; \ - \ - for (i = 0; i < ARRAY_SIZE(table); i++) { \ - if (table[i].value == table_key) { \ - name = table[i].name; \ - break; \ - } \ - } \ - return name; \ -} - -#define fc_enum_name_match(title, table_type, table) \ -static int get_fc_##title##_match(const char *table_key, \ - enum table_type *value) \ -{ \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(table); i++) { \ - if (strncmp(table_key, table[i].name, \ - table[i].matchlen) == 0) { \ - *value = table[i].value; \ - return 0; /* success */ \ - } \ - } \ - return 1; /* failure */ \ -} - - -/* Convert fc_port_type values to ascii string name */ -static struct { - enum fc_port_type value; - char *name; -} fc_port_type_names[] = { - { FC_PORTTYPE_UNKNOWN, "Unknown" }, - { FC_PORTTYPE_OTHER, "Other" }, - { FC_PORTTYPE_NOTPRESENT, "Not Present" }, - { FC_PORTTYPE_NPORT, "NPort (fabric via point-to-point)" }, - { FC_PORTTYPE_NLPORT, "NLPort (fabric via loop)" }, - { FC_PORTTYPE_LPORT, "LPort (private loop)" }, - { FC_PORTTYPE_PTP, "Point-To-Point (direct nport connection)" }, - { FC_PORTTYPE_NPIV, "NPIV VPORT" }, -}; -fc_enum_name_search(port_type, fc_port_type, fc_port_type_names) -#define FC_PORTTYPE_MAX_NAMELEN 50 - -/* Reuse fc_port_type enum function for vport_type */ -#define get_fc_vport_type_name get_fc_port_type_name - - -/* Convert fc_host_event_code values to ascii string name */ -static const struct { - enum fc_host_event_code value; - char *name; -} fc_host_event_code_names[] = { - { FCH_EVT_LIP, "lip" }, - { FCH_EVT_LINKUP, "link_up" }, - { FCH_EVT_LINKDOWN, "link_down" }, - { FCH_EVT_LIPRESET, "lip_reset" }, - { FCH_EVT_RSCN, "rscn" }, - { FCH_EVT_ADAPTER_CHANGE, "adapter_chg" }, - { FCH_EVT_PORT_UNKNOWN, "port_unknown" }, - { FCH_EVT_PORT_ONLINE, "port_online" }, - { FCH_EVT_PORT_OFFLINE, "port_offline" }, - { FCH_EVT_PORT_FABRIC, "port_fabric" }, - { FCH_EVT_LINK_UNKNOWN, "link_unknown" }, - { FCH_EVT_VENDOR_UNIQUE, "vendor_unique" }, -}; -fc_enum_name_search(host_event_code, fc_host_event_code, - fc_host_event_code_names) -#define FC_HOST_EVENT_CODE_MAX_NAMELEN 30 - - -/* Convert fc_port_state values to ascii string name */ -static struct { - enum fc_port_state value; - char *name; -} fc_port_state_names[] = { - { FC_PORTSTATE_UNKNOWN, "Unknown" }, - { FC_PORTSTATE_NOTPRESENT, "Not Present" }, - { FC_PORTSTATE_ONLINE, "Online" }, - { FC_PORTSTATE_OFFLINE, "Offline" }, - { FC_PORTSTATE_BLOCKED, "Blocked" }, - { FC_PORTSTATE_BYPASSED, "Bypassed" }, - { FC_PORTSTATE_DIAGNOSTICS, "Diagnostics" }, - { FC_PORTSTATE_LINKDOWN, "Linkdown" }, - { FC_PORTSTATE_ERROR, "Error" }, - { FC_PORTSTATE_LOOPBACK, "Loopback" }, - { FC_PORTSTATE_DELETED, "Deleted" }, -}; -fc_enum_name_search(port_state, fc_port_state, fc_port_state_names) -#define FC_PORTSTATE_MAX_NAMELEN 20 - - -/* Convert fc_vport_state values to ascii string name */ -static struct { - enum fc_vport_state value; - char *name; -} fc_vport_state_names[] = { - { FC_VPORT_UNKNOWN, "Unknown" }, - { FC_VPORT_ACTIVE, "Active" }, - { FC_VPORT_DISABLED, "Disabled" }, - { FC_VPORT_LINKDOWN, "Linkdown" }, - { FC_VPORT_INITIALIZING, "Initializing" }, - { FC_VPORT_NO_FABRIC_SUPP, "No Fabric Support" }, - { FC_VPORT_NO_FABRIC_RSCS, "No Fabric Resources" }, - { FC_VPORT_FABRIC_LOGOUT, "Fabric Logout" }, - { FC_VPORT_FABRIC_REJ_WWN, "Fabric Rejected WWN" }, - { FC_VPORT_FAILED, "VPort Failed" }, -}; -fc_enum_name_search(vport_state, fc_vport_state, fc_vport_state_names) -#define FC_VPORTSTATE_MAX_NAMELEN 24 - -/* Reuse fc_vport_state enum function for vport_last_state */ -#define get_fc_vport_last_state_name get_fc_vport_state_name - - -/* Convert fc_tgtid_binding_type values to ascii string name */ -static const struct { - enum fc_tgtid_binding_type value; - char *name; - int matchlen; -} fc_tgtid_binding_type_names[] = { - { FC_TGTID_BIND_NONE, "none", 4 }, - { FC_TGTID_BIND_BY_WWPN, "wwpn (World Wide Port Name)", 4 }, - { FC_TGTID_BIND_BY_WWNN, "wwnn (World Wide Node Name)", 4 }, - { FC_TGTID_BIND_BY_ID, "port_id (FC Address)", 7 }, -}; -fc_enum_name_search(tgtid_bind_type, fc_tgtid_binding_type, - fc_tgtid_binding_type_names) -fc_enum_name_match(tgtid_bind_type, fc_tgtid_binding_type, - fc_tgtid_binding_type_names) -#define FC_BINDTYPE_MAX_NAMELEN 30 - - -#define fc_bitfield_name_search(title, table) \ -static ssize_t \ -get_fc_##title##_names(u32 table_key, char *buf) \ -{ \ - char *prefix = ""; \ - ssize_t len = 0; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(table); i++) { \ - if (table[i].value & table_key) { \ - len += sprintf(buf + len, "%s%s", \ - prefix, table[i].name); \ - prefix = ", "; \ - } \ - } \ - len += sprintf(buf + len, "\n"); \ - return len; \ -} - - -/* Convert FC_COS bit values to ascii string name */ -static const struct { - u32 value; - char *name; -} fc_cos_names[] = { - { FC_COS_CLASS1, "Class 1" }, - { FC_COS_CLASS2, "Class 2" }, - { FC_COS_CLASS3, "Class 3" }, - { FC_COS_CLASS4, "Class 4" }, - { FC_COS_CLASS6, "Class 6" }, -}; -fc_bitfield_name_search(cos, fc_cos_names) - - -/* Convert FC_PORTSPEED bit values to ascii string name */ -static const struct { - u32 value; - char *name; -} fc_port_speed_names[] = { - { FC_PORTSPEED_1GBIT, "1 Gbit" }, - { FC_PORTSPEED_2GBIT, "2 Gbit" }, - { FC_PORTSPEED_4GBIT, "4 Gbit" }, - { FC_PORTSPEED_10GBIT, "10 Gbit" }, - { FC_PORTSPEED_8GBIT, "8 Gbit" }, - { FC_PORTSPEED_16GBIT, "16 Gbit" }, - { FC_PORTSPEED_NOT_NEGOTIATED, "Not Negotiated" }, -}; -fc_bitfield_name_search(port_speed, fc_port_speed_names) - - -static int -show_fc_fc4s (char *buf, u8 *fc4_list) -{ - int i, len=0; - - for (i = 0; i < FC_FC4_LIST_SIZE; i++, fc4_list++) - len += sprintf(buf + len , "0x%02x ", *fc4_list); - len += sprintf(buf + len, "\n"); - return len; -} - - -/* Convert FC_PORT_ROLE bit values to ascii string name */ -static const struct { - u32 value; - char *name; -} fc_port_role_names[] = { - { FC_PORT_ROLE_FCP_TARGET, "FCP Target" }, - { FC_PORT_ROLE_FCP_INITIATOR, "FCP Initiator" }, - { FC_PORT_ROLE_IP_PORT, "IP Port" }, -}; -fc_bitfield_name_search(port_roles, fc_port_role_names) - -/* - * Define roles that are specific to port_id. Values are relative to ROLE_MASK. - */ -#define FC_WELLKNOWN_PORTID_MASK 0xfffff0 -#define FC_WELLKNOWN_ROLE_MASK 0x00000f -#define FC_FPORT_PORTID 0x00000e -#define FC_FABCTLR_PORTID 0x00000d -#define FC_DIRSRVR_PORTID 0x00000c -#define FC_TIMESRVR_PORTID 0x00000b -#define FC_MGMTSRVR_PORTID 0x00000a - - -static void fc_timeout_deleted_rport(struct work_struct *work); -static void fc_timeout_fail_rport_io(struct work_struct *work); -static void fc_scsi_scan_rport(struct work_struct *work); - -/* - * Attribute counts pre object type... - * Increase these values if you add attributes - */ -#define FC_STARGET_NUM_ATTRS 3 -#define FC_RPORT_NUM_ATTRS 10 -#define FC_VPORT_NUM_ATTRS 9 -#define FC_HOST_NUM_ATTRS 29 - -struct fc_internal { - struct scsi_transport_template t; - struct fc_function_template *f; - - /* - * For attributes : each object has : - * An array of the actual attributes structures - * An array of null-terminated pointers to the attribute - * structures - used for mid-layer interaction. - * - * The attribute containers for the starget and host are are - * part of the midlayer. As the remote port is specific to the - * fc transport, we must provide the attribute container. - */ - struct device_attribute private_starget_attrs[ - FC_STARGET_NUM_ATTRS]; - struct device_attribute *starget_attrs[FC_STARGET_NUM_ATTRS + 1]; - - struct device_attribute private_host_attrs[FC_HOST_NUM_ATTRS]; - struct device_attribute *host_attrs[FC_HOST_NUM_ATTRS + 1]; - - struct transport_container rport_attr_cont; - struct device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS]; - struct device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1]; - - struct transport_container vport_attr_cont; - struct device_attribute private_vport_attrs[FC_VPORT_NUM_ATTRS]; - struct device_attribute *vport_attrs[FC_VPORT_NUM_ATTRS + 1]; -}; - -#define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) - -static int fc_target_setup(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct scsi_target *starget = to_scsi_target(dev); - struct fc_rport *rport = starget_to_rport(starget); - - /* - * if parent is remote port, use values from remote port. - * Otherwise, this host uses the fc_transport, but not the - * remote port interface. As such, initialize to known non-values. - */ - if (rport) { - fc_starget_node_name(starget) = rport->node_name; - fc_starget_port_name(starget) = rport->port_name; - fc_starget_port_id(starget) = rport->port_id; - } else { - fc_starget_node_name(starget) = -1; - fc_starget_port_name(starget) = -1; - fc_starget_port_id(starget) = -1; - } - - return 0; -} - -static DECLARE_TRANSPORT_CLASS(fc_transport_class, - "fc_transport", - fc_target_setup, - NULL, - NULL); - -static int fc_host_setup(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - - /* - * Set default values easily detected by the midlayer as - * failure cases. The scsi lldd is responsible for initializing - * all transport attributes to valid values per host. - */ - fc_host->node_name = -1; - fc_host->port_name = -1; - fc_host->permanent_port_name = -1; - fc_host->supported_classes = FC_COS_UNSPECIFIED; - memset(fc_host->supported_fc4s, 0, - sizeof(fc_host->supported_fc4s)); - fc_host->supported_speeds = FC_PORTSPEED_UNKNOWN; - fc_host->maxframe_size = -1; - fc_host->max_npiv_vports = 0; - memset(fc_host->serial_number, 0, - sizeof(fc_host->serial_number)); - memset(fc_host->manufacturer, 0, - sizeof(fc_host->manufacturer)); - memset(fc_host->model, 0, - sizeof(fc_host->model)); - memset(fc_host->model_description, 0, - sizeof(fc_host->model_description)); - memset(fc_host->hardware_version, 0, - sizeof(fc_host->hardware_version)); - memset(fc_host->driver_version, 0, - sizeof(fc_host->driver_version)); - memset(fc_host->firmware_version, 0, - sizeof(fc_host->firmware_version)); - memset(fc_host->optionrom_version, 0, - sizeof(fc_host->optionrom_version)); - - fc_host->port_id = -1; - fc_host->port_type = FC_PORTTYPE_UNKNOWN; - fc_host->port_state = FC_PORTSTATE_UNKNOWN; - memset(fc_host->active_fc4s, 0, - sizeof(fc_host->active_fc4s)); - fc_host->speed = FC_PORTSPEED_UNKNOWN; - fc_host->fabric_name = -1; - memset(fc_host->symbolic_name, 0, sizeof(fc_host->symbolic_name)); - memset(fc_host->system_hostname, 0, sizeof(fc_host->system_hostname)); - - fc_host->tgtid_bind_type = FC_TGTID_BIND_BY_WWPN; - - INIT_LIST_HEAD(&fc_host->rports); - INIT_LIST_HEAD(&fc_host->rport_bindings); - INIT_LIST_HEAD(&fc_host->vports); - fc_host->next_rport_number = 0; - fc_host->next_target_id = 0; - fc_host->next_vport_number = 0; - fc_host->npiv_vports_inuse = 0; - - snprintf(fc_host->work_q_name, sizeof(fc_host->work_q_name), - "fc_wq_%d", shost->host_no); - fc_host->work_q = alloc_workqueue(fc_host->work_q_name, 0, 0); - if (!fc_host->work_q) - return -ENOMEM; - - fc_host->dev_loss_tmo = fc_dev_loss_tmo; - snprintf(fc_host->devloss_work_q_name, - sizeof(fc_host->devloss_work_q_name), - "fc_dl_%d", shost->host_no); - fc_host->devloss_work_q = - alloc_workqueue(fc_host->devloss_work_q_name, 0, 0); - if (!fc_host->devloss_work_q) { - destroy_workqueue(fc_host->work_q); - fc_host->work_q = NULL; - return -ENOMEM; - } - - fc_bsg_hostadd(shost, fc_host); - /* ignore any bsg add error - we just can't do sgio */ - - return 0; -} - -static int fc_host_remove(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - - fc_bsg_remove(fc_host->rqst_q); - return 0; -} - -static DECLARE_TRANSPORT_CLASS(fc_host_class, - "fc_host", - fc_host_setup, - fc_host_remove, - NULL); - -/* - * Setup and Remove actions for remote ports are handled - * in the service functions below. - */ -static DECLARE_TRANSPORT_CLASS(fc_rport_class, - "fc_remote_ports", - NULL, - NULL, - NULL); - -/* - * Setup and Remove actions for virtual ports are handled - * in the service functions below. - */ -static DECLARE_TRANSPORT_CLASS(fc_vport_class, - "fc_vports", - NULL, - NULL, - NULL); - -/* - * Netlink Infrastructure - */ - -static atomic_t fc_event_seq; - -/** - * fc_get_event_number - Obtain the next sequential FC event number - * - * Notes: - * We could have inlined this, but it would have required fc_event_seq to - * be exposed. For now, live with the subroutine call. - * Atomic used to avoid lock/unlock... - */ -u32 -fc_get_event_number(void) -{ - return atomic_add_return(1, &fc_event_seq); -} -EXPORT_SYMBOL(fc_get_event_number); - - -/** - * fc_host_post_event - called to post an even on an fc_host. - * @shost: host the event occurred on - * @event_number: fc event number obtained from get_fc_event_number() - * @event_code: fc_host event being posted - * @event_data: 32bits of data for the event being posted - * - * Notes: - * This routine assumes no locks are held on entry. - */ -void -fc_host_post_event(struct Scsi_Host *shost, u32 event_number, - enum fc_host_event_code event_code, u32 event_data) -{ - struct sk_buff *skb; - struct nlmsghdr *nlh; - struct fc_nl_event *event; - const char *name; - u32 len, skblen; - int err; - - if (!scsi_nl_sock) { - err = -ENOENT; - goto send_fail; - } - - len = FC_NL_MSGALIGN(sizeof(*event)); - skblen = NLMSG_SPACE(len); - - skb = alloc_skb(skblen, GFP_KERNEL); - if (!skb) { - err = -ENOBUFS; - goto send_fail; - } - - nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, - skblen - sizeof(*nlh), 0); - if (!nlh) { - err = -ENOBUFS; - goto send_fail_skb; - } - event = NLMSG_DATA(nlh); - - INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, - FC_NL_ASYNC_EVENT, len); - event->seconds = get_seconds(); - event->vendor_id = 0; - event->host_no = shost->host_no; - event->event_datalen = sizeof(u32); /* bytes */ - event->event_num = event_number; - event->event_code = event_code; - event->event_data = event_data; - - nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, - GFP_KERNEL); - return; - -send_fail_skb: - kfree_skb(skb); -send_fail: - name = get_fc_host_event_code_name(event_code); - printk(KERN_WARNING - "%s: Dropped Event : host %d %s data 0x%08x - err %d\n", - __func__, shost->host_no, - (name) ? name : "", event_data, err); - return; -} -EXPORT_SYMBOL(fc_host_post_event); - - -/** - * fc_host_post_vendor_event - called to post a vendor unique event on an fc_host - * @shost: host the event occurred on - * @event_number: fc event number obtained from get_fc_event_number() - * @data_len: amount, in bytes, of vendor unique data - * @data_buf: pointer to vendor unique data - * @vendor_id: Vendor id - * - * Notes: - * This routine assumes no locks are held on entry. - */ -void -fc_host_post_vendor_event(struct Scsi_Host *shost, u32 event_number, - u32 data_len, char * data_buf, u64 vendor_id) -{ - struct sk_buff *skb; - struct nlmsghdr *nlh; - struct fc_nl_event *event; - u32 len, skblen; - int err; - - if (!scsi_nl_sock) { - err = -ENOENT; - goto send_vendor_fail; - } - - len = FC_NL_MSGALIGN(sizeof(*event) + data_len); - skblen = NLMSG_SPACE(len); - - skb = alloc_skb(skblen, GFP_KERNEL); - if (!skb) { - err = -ENOBUFS; - goto send_vendor_fail; - } - - nlh = nlmsg_put(skb, 0, 0, SCSI_TRANSPORT_MSG, - skblen - sizeof(*nlh), 0); - if (!nlh) { - err = -ENOBUFS; - goto send_vendor_fail_skb; - } - event = NLMSG_DATA(nlh); - - INIT_SCSI_NL_HDR(&event->snlh, SCSI_NL_TRANSPORT_FC, - FC_NL_ASYNC_EVENT, len); - event->seconds = get_seconds(); - event->vendor_id = vendor_id; - event->host_no = shost->host_no; - event->event_datalen = data_len; /* bytes */ - event->event_num = event_number; - event->event_code = FCH_EVT_VENDOR_UNIQUE; - memcpy(&event->event_data, data_buf, data_len); - - nlmsg_multicast(scsi_nl_sock, skb, 0, SCSI_NL_GRP_FC_EVENTS, - GFP_KERNEL); - return; - -send_vendor_fail_skb: - kfree_skb(skb); -send_vendor_fail: - printk(KERN_WARNING - "%s: Dropped Event : host %d vendor_unique - err %d\n", - __func__, shost->host_no, err); - return; -} -EXPORT_SYMBOL(fc_host_post_vendor_event); - - - -static __init int fc_transport_init(void) -{ - int error; - - atomic_set(&fc_event_seq, 0); - - error = transport_class_register(&fc_host_class); - if (error) - return error; - error = transport_class_register(&fc_vport_class); - if (error) - goto unreg_host_class; - error = transport_class_register(&fc_rport_class); - if (error) - goto unreg_vport_class; - error = transport_class_register(&fc_transport_class); - if (error) - goto unreg_rport_class; - return 0; - -unreg_rport_class: - transport_class_unregister(&fc_rport_class); -unreg_vport_class: - transport_class_unregister(&fc_vport_class); -unreg_host_class: - transport_class_unregister(&fc_host_class); - return error; -} - -static void __exit fc_transport_exit(void) -{ - transport_class_unregister(&fc_transport_class); - transport_class_unregister(&fc_rport_class); - transport_class_unregister(&fc_host_class); - transport_class_unregister(&fc_vport_class); -} - -/* - * FC Remote Port Attribute Management - */ - -#define fc_rport_show_function(field, format_string, sz, cast) \ -static ssize_t \ -show_fc_rport_##field (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct fc_rport *rport = transport_class_to_rport(dev); \ - struct Scsi_Host *shost = rport_to_shost(rport); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - if ((i->f->get_rport_##field) && \ - !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ - (rport->port_state == FC_PORTSTATE_DELETED) || \ - (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ - i->f->get_rport_##field(rport); \ - return snprintf(buf, sz, format_string, cast rport->field); \ -} - -#define fc_rport_store_function(field) \ -static ssize_t \ -store_fc_rport_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int val; \ - struct fc_rport *rport = transport_class_to_rport(dev); \ - struct Scsi_Host *shost = rport_to_shost(rport); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - char *cp; \ - if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ - (rport->port_state == FC_PORTSTATE_DELETED) || \ - (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ - return -EBUSY; \ - val = simple_strtoul(buf, &cp, 0); \ - if (*cp && (*cp != '\n')) \ - return -EINVAL; \ - i->f->set_rport_##field(rport, val); \ - return count; \ -} - -#define fc_rport_rd_attr(field, format_string, sz) \ - fc_rport_show_function(field, format_string, sz, ) \ -static FC_DEVICE_ATTR(rport, field, S_IRUGO, \ - show_fc_rport_##field, NULL) - -#define fc_rport_rd_attr_cast(field, format_string, sz, cast) \ - fc_rport_show_function(field, format_string, sz, (cast)) \ -static FC_DEVICE_ATTR(rport, field, S_IRUGO, \ - show_fc_rport_##field, NULL) - -#define fc_rport_rw_attr(field, format_string, sz) \ - fc_rport_show_function(field, format_string, sz, ) \ - fc_rport_store_function(field) \ -static FC_DEVICE_ATTR(rport, field, S_IRUGO | S_IWUSR, \ - show_fc_rport_##field, \ - store_fc_rport_##field) - - -#define fc_private_rport_show_function(field, format_string, sz, cast) \ -static ssize_t \ -show_fc_rport_##field (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct fc_rport *rport = transport_class_to_rport(dev); \ - return snprintf(buf, sz, format_string, cast rport->field); \ -} - -#define fc_private_rport_rd_attr(field, format_string, sz) \ - fc_private_rport_show_function(field, format_string, sz, ) \ -static FC_DEVICE_ATTR(rport, field, S_IRUGO, \ - show_fc_rport_##field, NULL) - -#define fc_private_rport_rd_attr_cast(field, format_string, sz, cast) \ - fc_private_rport_show_function(field, format_string, sz, (cast)) \ -static FC_DEVICE_ATTR(rport, field, S_IRUGO, \ - show_fc_rport_##field, NULL) - - -#define fc_private_rport_rd_enum_attr(title, maxlen) \ -static ssize_t \ -show_fc_rport_##title (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct fc_rport *rport = transport_class_to_rport(dev); \ - const char *name; \ - name = get_fc_##title##_name(rport->title); \ - if (!name) \ - return -EINVAL; \ - return snprintf(buf, maxlen, "%s\n", name); \ -} \ -static FC_DEVICE_ATTR(rport, title, S_IRUGO, \ - show_fc_rport_##title, NULL) - - -#define SETUP_RPORT_ATTRIBUTE_RD(field) \ - i->private_rport_attrs[count] = device_attr_rport_##field; \ - i->private_rport_attrs[count].attr.mode = S_IRUGO; \ - i->private_rport_attrs[count].store = NULL; \ - i->rport_attrs[count] = &i->private_rport_attrs[count]; \ - if (i->f->show_rport_##field) \ - count++ - -#define SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(field) \ - i->private_rport_attrs[count] = device_attr_rport_##field; \ - i->private_rport_attrs[count].attr.mode = S_IRUGO; \ - i->private_rport_attrs[count].store = NULL; \ - i->rport_attrs[count] = &i->private_rport_attrs[count]; \ - count++ - -#define SETUP_RPORT_ATTRIBUTE_RW(field) \ - i->private_rport_attrs[count] = device_attr_rport_##field; \ - if (!i->f->set_rport_##field) { \ - i->private_rport_attrs[count].attr.mode = S_IRUGO; \ - i->private_rport_attrs[count].store = NULL; \ - } \ - i->rport_attrs[count] = &i->private_rport_attrs[count]; \ - if (i->f->show_rport_##field) \ - count++ - -#define SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(field) \ -{ \ - i->private_rport_attrs[count] = device_attr_rport_##field; \ - i->rport_attrs[count] = &i->private_rport_attrs[count]; \ - count++; \ -} - - -/* The FC Transport Remote Port Attributes: */ - -/* Fixed Remote Port Attributes */ - -fc_private_rport_rd_attr(maxframe_size, "%u bytes\n", 20); - -static ssize_t -show_fc_rport_supported_classes (struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fc_rport *rport = transport_class_to_rport(dev); - if (rport->supported_classes == FC_COS_UNSPECIFIED) - return snprintf(buf, 20, "unspecified\n"); - return get_fc_cos_names(rport->supported_classes, buf); -} -static FC_DEVICE_ATTR(rport, supported_classes, S_IRUGO, - show_fc_rport_supported_classes, NULL); - -/* Dynamic Remote Port Attributes */ - -/* - * dev_loss_tmo attribute - */ -static int fc_str_to_dev_loss(const char *buf, unsigned long *val) -{ - char *cp; - - *val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || (*val < 0)) - return -EINVAL; - /* - * Check for overflow; dev_loss_tmo is u32 - */ - if (*val > UINT_MAX) - return -EINVAL; - - return 0; -} - -static int fc_rport_set_dev_loss_tmo(struct fc_rport *rport, - unsigned long val) -{ - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); - - if ((rport->port_state == FC_PORTSTATE_BLOCKED) || - (rport->port_state == FC_PORTSTATE_DELETED) || - (rport->port_state == FC_PORTSTATE_NOTPRESENT)) - return -EBUSY; - /* - * Check for overflow; dev_loss_tmo is u32 - */ - if (val > UINT_MAX) - return -EINVAL; - - /* - * If fast_io_fail is off we have to cap - * dev_loss_tmo at SCSI_DEVICE_BLOCK_MAX_TIMEOUT - */ - if (rport->fast_io_fail_tmo == -1 && - val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT) - return -EINVAL; - - i->f->set_rport_dev_loss_tmo(rport, val); - return 0; -} - -fc_rport_show_function(dev_loss_tmo, "%d\n", 20, ) -static ssize_t -store_fc_rport_dev_loss_tmo(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fc_rport *rport = transport_class_to_rport(dev); - unsigned long val; - int rc; - - rc = fc_str_to_dev_loss(buf, &val); - if (rc) - return rc; - - rc = fc_rport_set_dev_loss_tmo(rport, val); - if (rc) - return rc; - return count; -} -static FC_DEVICE_ATTR(rport, dev_loss_tmo, S_IRUGO | S_IWUSR, - show_fc_rport_dev_loss_tmo, store_fc_rport_dev_loss_tmo); - - -/* Private Remote Port Attributes */ - -fc_private_rport_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long); -fc_private_rport_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long); -fc_private_rport_rd_attr(port_id, "0x%06x\n", 20); - -static ssize_t -show_fc_rport_roles (struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fc_rport *rport = transport_class_to_rport(dev); - - /* identify any roles that are port_id specific */ - if ((rport->port_id != -1) && - (rport->port_id & FC_WELLKNOWN_PORTID_MASK) == - FC_WELLKNOWN_PORTID_MASK) { - switch (rport->port_id & FC_WELLKNOWN_ROLE_MASK) { - case FC_FPORT_PORTID: - return snprintf(buf, 30, "Fabric Port\n"); - case FC_FABCTLR_PORTID: - return snprintf(buf, 30, "Fabric Controller\n"); - case FC_DIRSRVR_PORTID: - return snprintf(buf, 30, "Directory Server\n"); - case FC_TIMESRVR_PORTID: - return snprintf(buf, 30, "Time Server\n"); - case FC_MGMTSRVR_PORTID: - return snprintf(buf, 30, "Management Server\n"); - default: - return snprintf(buf, 30, "Unknown Fabric Entity\n"); - } - } else { - if (rport->roles == FC_PORT_ROLE_UNKNOWN) - return snprintf(buf, 20, "unknown\n"); - return get_fc_port_roles_names(rport->roles, buf); - } -} -static FC_DEVICE_ATTR(rport, roles, S_IRUGO, - show_fc_rport_roles, NULL); - -fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN); -fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20); - -/* - * fast_io_fail_tmo attribute - */ -static ssize_t -show_fc_rport_fast_io_fail_tmo (struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct fc_rport *rport = transport_class_to_rport(dev); - - if (rport->fast_io_fail_tmo == -1) - return snprintf(buf, 5, "off\n"); - return snprintf(buf, 20, "%d\n", rport->fast_io_fail_tmo); -} - -static ssize_t -store_fc_rport_fast_io_fail_tmo(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - int val; - char *cp; - struct fc_rport *rport = transport_class_to_rport(dev); - - if ((rport->port_state == FC_PORTSTATE_BLOCKED) || - (rport->port_state == FC_PORTSTATE_DELETED) || - (rport->port_state == FC_PORTSTATE_NOTPRESENT)) - return -EBUSY; - if (strncmp(buf, "off", 3) == 0) - rport->fast_io_fail_tmo = -1; - else { - val = simple_strtoul(buf, &cp, 0); - if ((*cp && (*cp != '\n')) || (val < 0)) - return -EINVAL; - /* - * Cap fast_io_fail by dev_loss_tmo or - * SCSI_DEVICE_BLOCK_MAX_TIMEOUT. - */ - if ((val >= rport->dev_loss_tmo) || - (val > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)) - return -EINVAL; - - rport->fast_io_fail_tmo = val; - } - return count; -} -static FC_DEVICE_ATTR(rport, fast_io_fail_tmo, S_IRUGO | S_IWUSR, - show_fc_rport_fast_io_fail_tmo, store_fc_rport_fast_io_fail_tmo); - - -/* - * FC SCSI Target Attribute Management - */ - -/* - * Note: in the target show function we recognize when the remote - * port is in the hierarchy and do not allow the driver to get - * involved in sysfs functions. The driver only gets involved if - * it's the "old" style that doesn't use rports. - */ -#define fc_starget_show_function(field, format_string, sz, cast) \ -static ssize_t \ -show_fc_starget_##field (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct scsi_target *starget = transport_class_to_starget(dev); \ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - struct fc_rport *rport = starget_to_rport(starget); \ - if (rport) \ - fc_starget_##field(starget) = rport->field; \ - else if (i->f->get_starget_##field) \ - i->f->get_starget_##field(starget); \ - return snprintf(buf, sz, format_string, \ - cast fc_starget_##field(starget)); \ -} - -#define fc_starget_rd_attr(field, format_string, sz) \ - fc_starget_show_function(field, format_string, sz, ) \ -static FC_DEVICE_ATTR(starget, field, S_IRUGO, \ - show_fc_starget_##field, NULL) - -#define fc_starget_rd_attr_cast(field, format_string, sz, cast) \ - fc_starget_show_function(field, format_string, sz, (cast)) \ -static FC_DEVICE_ATTR(starget, field, S_IRUGO, \ - show_fc_starget_##field, NULL) - -#define SETUP_STARGET_ATTRIBUTE_RD(field) \ - i->private_starget_attrs[count] = device_attr_starget_##field; \ - i->private_starget_attrs[count].attr.mode = S_IRUGO; \ - i->private_starget_attrs[count].store = NULL; \ - i->starget_attrs[count] = &i->private_starget_attrs[count]; \ - if (i->f->show_starget_##field) \ - count++ - -#define SETUP_STARGET_ATTRIBUTE_RW(field) \ - i->private_starget_attrs[count] = device_attr_starget_##field; \ - if (!i->f->set_starget_##field) { \ - i->private_starget_attrs[count].attr.mode = S_IRUGO; \ - i->private_starget_attrs[count].store = NULL; \ - } \ - i->starget_attrs[count] = &i->private_starget_attrs[count]; \ - if (i->f->show_starget_##field) \ - count++ - -/* The FC Transport SCSI Target Attributes: */ -fc_starget_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long); -fc_starget_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long); -fc_starget_rd_attr(port_id, "0x%06x\n", 20); - - -/* - * FC Virtual Port Attribute Management - */ - -#define fc_vport_show_function(field, format_string, sz, cast) \ -static ssize_t \ -show_fc_vport_##field (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct fc_vport *vport = transport_class_to_vport(dev); \ - struct Scsi_Host *shost = vport_to_shost(vport); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - if ((i->f->get_vport_##field) && \ - !(vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING))) \ - i->f->get_vport_##field(vport); \ - return snprintf(buf, sz, format_string, cast vport->field); \ -} - -#define fc_vport_store_function(field) \ -static ssize_t \ -store_fc_vport_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int val; \ - struct fc_vport *vport = transport_class_to_vport(dev); \ - struct Scsi_Host *shost = vport_to_shost(vport); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - char *cp; \ - if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) \ - return -EBUSY; \ - val = simple_strtoul(buf, &cp, 0); \ - if (*cp && (*cp != '\n')) \ - return -EINVAL; \ - i->f->set_vport_##field(vport, val); \ - return count; \ -} - -#define fc_vport_store_str_function(field, slen) \ -static ssize_t \ -store_fc_vport_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct fc_vport *vport = transport_class_to_vport(dev); \ - struct Scsi_Host *shost = vport_to_shost(vport); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - unsigned int cnt=count; \ - \ - /* count may include a LF at end of string */ \ - if (buf[cnt-1] == '\n') \ - cnt--; \ - if (cnt > ((slen) - 1)) \ - return -EINVAL; \ - memcpy(vport->field, buf, cnt); \ - i->f->set_vport_##field(vport); \ - return count; \ -} - -#define fc_vport_rd_attr(field, format_string, sz) \ - fc_vport_show_function(field, format_string, sz, ) \ -static FC_DEVICE_ATTR(vport, field, S_IRUGO, \ - show_fc_vport_##field, NULL) - -#define fc_vport_rd_attr_cast(field, format_string, sz, cast) \ - fc_vport_show_function(field, format_string, sz, (cast)) \ -static FC_DEVICE_ATTR(vport, field, S_IRUGO, \ - show_fc_vport_##field, NULL) - -#define fc_vport_rw_attr(field, format_string, sz) \ - fc_vport_show_function(field, format_string, sz, ) \ - fc_vport_store_function(field) \ -static FC_DEVICE_ATTR(vport, field, S_IRUGO | S_IWUSR, \ - show_fc_vport_##field, \ - store_fc_vport_##field) - -#define fc_private_vport_show_function(field, format_string, sz, cast) \ -static ssize_t \ -show_fc_vport_##field (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct fc_vport *vport = transport_class_to_vport(dev); \ - return snprintf(buf, sz, format_string, cast vport->field); \ -} - -#define fc_private_vport_store_u32_function(field) \ -static ssize_t \ -store_fc_vport_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - u32 val; \ - struct fc_vport *vport = transport_class_to_vport(dev); \ - char *cp; \ - if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) \ - return -EBUSY; \ - val = simple_strtoul(buf, &cp, 0); \ - if (*cp && (*cp != '\n')) \ - return -EINVAL; \ - vport->field = val; \ - return count; \ -} - - -#define fc_private_vport_rd_attr(field, format_string, sz) \ - fc_private_vport_show_function(field, format_string, sz, ) \ -static FC_DEVICE_ATTR(vport, field, S_IRUGO, \ - show_fc_vport_##field, NULL) - -#define fc_private_vport_rd_attr_cast(field, format_string, sz, cast) \ - fc_private_vport_show_function(field, format_string, sz, (cast)) \ -static FC_DEVICE_ATTR(vport, field, S_IRUGO, \ - show_fc_vport_##field, NULL) - -#define fc_private_vport_rw_u32_attr(field, format_string, sz) \ - fc_private_vport_show_function(field, format_string, sz, ) \ - fc_private_vport_store_u32_function(field) \ -static FC_DEVICE_ATTR(vport, field, S_IRUGO | S_IWUSR, \ - show_fc_vport_##field, \ - store_fc_vport_##field) - - -#define fc_private_vport_rd_enum_attr(title, maxlen) \ -static ssize_t \ -show_fc_vport_##title (struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct fc_vport *vport = transport_class_to_vport(dev); \ - const char *name; \ - name = get_fc_##title##_name(vport->title); \ - if (!name) \ - return -EINVAL; \ - return snprintf(buf, maxlen, "%s\n", name); \ -} \ -static FC_DEVICE_ATTR(vport, title, S_IRUGO, \ - show_fc_vport_##title, NULL) - - -#define SETUP_VPORT_ATTRIBUTE_RD(field) \ - i->private_vport_attrs[count] = device_attr_vport_##field; \ - i->private_vport_attrs[count].attr.mode = S_IRUGO; \ - i->private_vport_attrs[count].store = NULL; \ - i->vport_attrs[count] = &i->private_vport_attrs[count]; \ - if (i->f->get_##field) \ - count++ - /* NOTE: Above MACRO differs: checks function not show bit */ - -#define SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(field) \ - i->private_vport_attrs[count] = device_attr_vport_##field; \ - i->private_vport_attrs[count].attr.mode = S_IRUGO; \ - i->private_vport_attrs[count].store = NULL; \ - i->vport_attrs[count] = &i->private_vport_attrs[count]; \ - count++ - -#define SETUP_VPORT_ATTRIBUTE_WR(field) \ - i->private_vport_attrs[count] = device_attr_vport_##field; \ - i->vport_attrs[count] = &i->private_vport_attrs[count]; \ - if (i->f->field) \ - count++ - /* NOTE: Above MACRO differs: checks function */ - -#define SETUP_VPORT_ATTRIBUTE_RW(field) \ - i->private_vport_attrs[count] = device_attr_vport_##field; \ - if (!i->f->set_vport_##field) { \ - i->private_vport_attrs[count].attr.mode = S_IRUGO; \ - i->private_vport_attrs[count].store = NULL; \ - } \ - i->vport_attrs[count] = &i->private_vport_attrs[count]; \ - count++ - /* NOTE: Above MACRO differs: does not check show bit */ - -#define SETUP_PRIVATE_VPORT_ATTRIBUTE_RW(field) \ -{ \ - i->private_vport_attrs[count] = device_attr_vport_##field; \ - i->vport_attrs[count] = &i->private_vport_attrs[count]; \ - count++; \ -} - - -/* The FC Transport Virtual Port Attributes: */ - -/* Fixed Virtual Port Attributes */ - -/* Dynamic Virtual Port Attributes */ - -/* Private Virtual Port Attributes */ - -fc_private_vport_rd_enum_attr(vport_state, FC_VPORTSTATE_MAX_NAMELEN); -fc_private_vport_rd_enum_attr(vport_last_state, FC_VPORTSTATE_MAX_NAMELEN); -fc_private_vport_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long); -fc_private_vport_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long); - -static ssize_t -show_fc_vport_roles (struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct fc_vport *vport = transport_class_to_vport(dev); - - if (vport->roles == FC_PORT_ROLE_UNKNOWN) - return snprintf(buf, 20, "unknown\n"); - return get_fc_port_roles_names(vport->roles, buf); -} -static FC_DEVICE_ATTR(vport, roles, S_IRUGO, show_fc_vport_roles, NULL); - -fc_private_vport_rd_enum_attr(vport_type, FC_PORTTYPE_MAX_NAMELEN); - -fc_private_vport_show_function(symbolic_name, "%s\n", - FC_VPORT_SYMBOLIC_NAMELEN + 1, ) -fc_vport_store_str_function(symbolic_name, FC_VPORT_SYMBOLIC_NAMELEN) -static FC_DEVICE_ATTR(vport, symbolic_name, S_IRUGO | S_IWUSR, - show_fc_vport_symbolic_name, store_fc_vport_symbolic_name); - -static ssize_t -store_fc_vport_delete(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct fc_vport *vport = transport_class_to_vport(dev); - struct Scsi_Host *shost = vport_to_shost(vport); - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) { - spin_unlock_irqrestore(shost->host_lock, flags); - return -EBUSY; - } - vport->flags |= FC_VPORT_DELETING; - spin_unlock_irqrestore(shost->host_lock, flags); - - fc_queue_work(shost, &vport->vport_delete_work); - return count; -} -static FC_DEVICE_ATTR(vport, vport_delete, S_IWUSR, - NULL, store_fc_vport_delete); - - -/* - * Enable/Disable vport - * Write "1" to disable, write "0" to enable - */ -static ssize_t -store_fc_vport_disable(struct device *dev, struct device_attribute *attr, - const char *buf, - size_t count) -{ - struct fc_vport *vport = transport_class_to_vport(dev); - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_internal *i = to_fc_internal(shost->transportt); - int stat; - - if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) - return -EBUSY; - - if (*buf == '0') { - if (vport->vport_state != FC_VPORT_DISABLED) - return -EALREADY; - } else if (*buf == '1') { - if (vport->vport_state == FC_VPORT_DISABLED) - return -EALREADY; - } else - return -EINVAL; - - stat = i->f->vport_disable(vport, ((*buf == '0') ? false : true)); - return stat ? stat : count; -} -static FC_DEVICE_ATTR(vport, vport_disable, S_IWUSR, - NULL, store_fc_vport_disable); - - -/* - * Host Attribute Management - */ - -#define fc_host_show_function(field, format_string, sz, cast) \ -static ssize_t \ -show_fc_host_##field (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct Scsi_Host *shost = transport_class_to_shost(dev); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - if (i->f->get_host_##field) \ - i->f->get_host_##field(shost); \ - return snprintf(buf, sz, format_string, cast fc_host_##field(shost)); \ -} - -#define fc_host_store_function(field) \ -static ssize_t \ -store_fc_host_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int val; \ - struct Scsi_Host *shost = transport_class_to_shost(dev); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - char *cp; \ - \ - val = simple_strtoul(buf, &cp, 0); \ - if (*cp && (*cp != '\n')) \ - return -EINVAL; \ - i->f->set_host_##field(shost, val); \ - return count; \ -} - -#define fc_host_store_str_function(field, slen) \ -static ssize_t \ -store_fc_host_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct Scsi_Host *shost = transport_class_to_shost(dev); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - unsigned int cnt=count; \ - \ - /* count may include a LF at end of string */ \ - if (buf[cnt-1] == '\n') \ - cnt--; \ - if (cnt > ((slen) - 1)) \ - return -EINVAL; \ - memcpy(fc_host_##field(shost), buf, cnt); \ - i->f->set_host_##field(shost); \ - return count; \ -} - -#define fc_host_rd_attr(field, format_string, sz) \ - fc_host_show_function(field, format_string, sz, ) \ -static FC_DEVICE_ATTR(host, field, S_IRUGO, \ - show_fc_host_##field, NULL) - -#define fc_host_rd_attr_cast(field, format_string, sz, cast) \ - fc_host_show_function(field, format_string, sz, (cast)) \ -static FC_DEVICE_ATTR(host, field, S_IRUGO, \ - show_fc_host_##field, NULL) - -#define fc_host_rw_attr(field, format_string, sz) \ - fc_host_show_function(field, format_string, sz, ) \ - fc_host_store_function(field) \ -static FC_DEVICE_ATTR(host, field, S_IRUGO | S_IWUSR, \ - show_fc_host_##field, \ - store_fc_host_##field) - -#define fc_host_rd_enum_attr(title, maxlen) \ -static ssize_t \ -show_fc_host_##title (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct Scsi_Host *shost = transport_class_to_shost(dev); \ - struct fc_internal *i = to_fc_internal(shost->transportt); \ - const char *name; \ - if (i->f->get_host_##title) \ - i->f->get_host_##title(shost); \ - name = get_fc_##title##_name(fc_host_##title(shost)); \ - if (!name) \ - return -EINVAL; \ - return snprintf(buf, maxlen, "%s\n", name); \ -} \ -static FC_DEVICE_ATTR(host, title, S_IRUGO, show_fc_host_##title, NULL) - -#define SETUP_HOST_ATTRIBUTE_RD(field) \ - i->private_host_attrs[count] = device_attr_host_##field; \ - i->private_host_attrs[count].attr.mode = S_IRUGO; \ - i->private_host_attrs[count].store = NULL; \ - i->host_attrs[count] = &i->private_host_attrs[count]; \ - if (i->f->show_host_##field) \ - count++ - -#define SETUP_HOST_ATTRIBUTE_RD_NS(field) \ - i->private_host_attrs[count] = device_attr_host_##field; \ - i->private_host_attrs[count].attr.mode = S_IRUGO; \ - i->private_host_attrs[count].store = NULL; \ - i->host_attrs[count] = &i->private_host_attrs[count]; \ - count++ - -#define SETUP_HOST_ATTRIBUTE_RW(field) \ - i->private_host_attrs[count] = device_attr_host_##field; \ - if (!i->f->set_host_##field) { \ - i->private_host_attrs[count].attr.mode = S_IRUGO; \ - i->private_host_attrs[count].store = NULL; \ - } \ - i->host_attrs[count] = &i->private_host_attrs[count]; \ - if (i->f->show_host_##field) \ - count++ - - -#define fc_private_host_show_function(field, format_string, sz, cast) \ -static ssize_t \ -show_fc_host_##field (struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct Scsi_Host *shost = transport_class_to_shost(dev); \ - return snprintf(buf, sz, format_string, cast fc_host_##field(shost)); \ -} - -#define fc_private_host_rd_attr(field, format_string, sz) \ - fc_private_host_show_function(field, format_string, sz, ) \ -static FC_DEVICE_ATTR(host, field, S_IRUGO, \ - show_fc_host_##field, NULL) - -#define fc_private_host_rd_attr_cast(field, format_string, sz, cast) \ - fc_private_host_show_function(field, format_string, sz, (cast)) \ -static FC_DEVICE_ATTR(host, field, S_IRUGO, \ - show_fc_host_##field, NULL) - -#define SETUP_PRIVATE_HOST_ATTRIBUTE_RD(field) \ - i->private_host_attrs[count] = device_attr_host_##field; \ - i->private_host_attrs[count].attr.mode = S_IRUGO; \ - i->private_host_attrs[count].store = NULL; \ - i->host_attrs[count] = &i->private_host_attrs[count]; \ - count++ - -#define SETUP_PRIVATE_HOST_ATTRIBUTE_RW(field) \ -{ \ - i->private_host_attrs[count] = device_attr_host_##field; \ - i->host_attrs[count] = &i->private_host_attrs[count]; \ - count++; \ -} - - -/* Fixed Host Attributes */ - -static ssize_t -show_fc_host_supported_classes (struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - - if (fc_host_supported_classes(shost) == FC_COS_UNSPECIFIED) - return snprintf(buf, 20, "unspecified\n"); - - return get_fc_cos_names(fc_host_supported_classes(shost), buf); -} -static FC_DEVICE_ATTR(host, supported_classes, S_IRUGO, - show_fc_host_supported_classes, NULL); - -static ssize_t -show_fc_host_supported_fc4s (struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - return (ssize_t)show_fc_fc4s(buf, fc_host_supported_fc4s(shost)); -} -static FC_DEVICE_ATTR(host, supported_fc4s, S_IRUGO, - show_fc_host_supported_fc4s, NULL); - -static ssize_t -show_fc_host_supported_speeds (struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - - if (fc_host_supported_speeds(shost) == FC_PORTSPEED_UNKNOWN) - return snprintf(buf, 20, "unknown\n"); - - return get_fc_port_speed_names(fc_host_supported_speeds(shost), buf); -} -static FC_DEVICE_ATTR(host, supported_speeds, S_IRUGO, - show_fc_host_supported_speeds, NULL); - - -fc_private_host_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long); -fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long); -fc_private_host_rd_attr_cast(permanent_port_name, "0x%llx\n", 20, - unsigned long long); -fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20); -fc_private_host_rd_attr(max_npiv_vports, "%u\n", 20); -fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1)); -fc_private_host_rd_attr(manufacturer, "%s\n", FC_SERIAL_NUMBER_SIZE + 1); -fc_private_host_rd_attr(model, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1); -fc_private_host_rd_attr(model_description, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1); -fc_private_host_rd_attr(hardware_version, "%s\n", FC_VERSION_STRING_SIZE + 1); -fc_private_host_rd_attr(driver_version, "%s\n", FC_VERSION_STRING_SIZE + 1); -fc_private_host_rd_attr(firmware_version, "%s\n", FC_VERSION_STRING_SIZE + 1); -fc_private_host_rd_attr(optionrom_version, "%s\n", FC_VERSION_STRING_SIZE + 1); - - -/* Dynamic Host Attributes */ - -static ssize_t -show_fc_host_active_fc4s (struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_internal *i = to_fc_internal(shost->transportt); - - if (i->f->get_host_active_fc4s) - i->f->get_host_active_fc4s(shost); - - return (ssize_t)show_fc_fc4s(buf, fc_host_active_fc4s(shost)); -} -static FC_DEVICE_ATTR(host, active_fc4s, S_IRUGO, - show_fc_host_active_fc4s, NULL); - -static ssize_t -show_fc_host_speed (struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_internal *i = to_fc_internal(shost->transportt); - - if (i->f->get_host_speed) - i->f->get_host_speed(shost); - - if (fc_host_speed(shost) == FC_PORTSPEED_UNKNOWN) - return snprintf(buf, 20, "unknown\n"); - - return get_fc_port_speed_names(fc_host_speed(shost), buf); -} -static FC_DEVICE_ATTR(host, speed, S_IRUGO, - show_fc_host_speed, NULL); - - -fc_host_rd_attr(port_id, "0x%06x\n", 20); -fc_host_rd_enum_attr(port_type, FC_PORTTYPE_MAX_NAMELEN); -fc_host_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN); -fc_host_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long); -fc_host_rd_attr(symbolic_name, "%s\n", FC_SYMBOLIC_NAME_SIZE + 1); - -fc_private_host_show_function(system_hostname, "%s\n", - FC_SYMBOLIC_NAME_SIZE + 1, ) -fc_host_store_str_function(system_hostname, FC_SYMBOLIC_NAME_SIZE) -static FC_DEVICE_ATTR(host, system_hostname, S_IRUGO | S_IWUSR, - show_fc_host_system_hostname, store_fc_host_system_hostname); - - -/* Private Host Attributes */ - -static ssize_t -show_fc_private_host_tgtid_bind_type(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - const char *name; - - name = get_fc_tgtid_bind_type_name(fc_host_tgtid_bind_type(shost)); - if (!name) - return -EINVAL; - return snprintf(buf, FC_BINDTYPE_MAX_NAMELEN, "%s\n", name); -} - -#define get_list_head_entry(pos, head, member) \ - pos = list_entry((head)->next, typeof(*pos), member) - -static ssize_t -store_fc_private_host_tgtid_bind_type(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_rport *rport; - enum fc_tgtid_binding_type val; - unsigned long flags; - - if (get_fc_tgtid_bind_type_match(buf, &val)) - return -EINVAL; - - /* if changing bind type, purge all unused consistent bindings */ - if (val != fc_host_tgtid_bind_type(shost)) { - spin_lock_irqsave(shost->host_lock, flags); - while (!list_empty(&fc_host_rport_bindings(shost))) { - get_list_head_entry(rport, - &fc_host_rport_bindings(shost), peers); - list_del(&rport->peers); - rport->port_state = FC_PORTSTATE_DELETED; - fc_queue_work(shost, &rport->rport_delete_work); - } - spin_unlock_irqrestore(shost->host_lock, flags); - } - - fc_host_tgtid_bind_type(shost) = val; - return count; -} - -static FC_DEVICE_ATTR(host, tgtid_bind_type, S_IRUGO | S_IWUSR, - show_fc_private_host_tgtid_bind_type, - store_fc_private_host_tgtid_bind_type); - -static ssize_t -store_fc_private_host_issue_lip(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_internal *i = to_fc_internal(shost->transportt); - int ret; - - /* ignore any data value written to the attribute */ - if (i->f->issue_fc_host_lip) { - ret = i->f->issue_fc_host_lip(shost); - return ret ? ret: count; - } - - return -ENOENT; -} - -static FC_DEVICE_ATTR(host, issue_lip, S_IWUSR, NULL, - store_fc_private_host_issue_lip); - -static ssize_t -store_fc_private_host_dev_loss_tmo(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - struct fc_rport *rport; - unsigned long val, flags; - int rc; - - rc = fc_str_to_dev_loss(buf, &val); - if (rc) - return rc; - - fc_host_dev_loss_tmo(shost) = val; - spin_lock_irqsave(shost->host_lock, flags); - list_for_each_entry(rport, &fc_host->rports, peers) - fc_rport_set_dev_loss_tmo(rport, val); - spin_unlock_irqrestore(shost->host_lock, flags); - return count; -} - -fc_private_host_show_function(dev_loss_tmo, "%d\n", 20, ); -static FC_DEVICE_ATTR(host, dev_loss_tmo, S_IRUGO | S_IWUSR, - show_fc_host_dev_loss_tmo, - store_fc_private_host_dev_loss_tmo); - -fc_private_host_rd_attr(npiv_vports_inuse, "%u\n", 20); - -/* - * Host Statistics Management - */ - -/* Show a given an attribute in the statistics group */ -static ssize_t -fc_stat_show(const struct device *dev, char *buf, unsigned long offset) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_internal *i = to_fc_internal(shost->transportt); - struct fc_host_statistics *stats; - ssize_t ret = -ENOENT; - - if (offset > sizeof(struct fc_host_statistics) || - offset % sizeof(u64) != 0) - WARN_ON(1); - - if (i->f->get_fc_host_stats) { - stats = (i->f->get_fc_host_stats)(shost); - if (stats) - ret = snprintf(buf, 20, "0x%llx\n", - (unsigned long long)*(u64 *)(((u8 *) stats) + offset)); - } - return ret; -} - - -/* generate a read-only statistics attribute */ -#define fc_host_statistic(name) \ -static ssize_t show_fcstat_##name(struct device *cd, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return fc_stat_show(cd, buf, \ - offsetof(struct fc_host_statistics, name)); \ -} \ -static FC_DEVICE_ATTR(host, name, S_IRUGO, show_fcstat_##name, NULL) - -fc_host_statistic(seconds_since_last_reset); -fc_host_statistic(tx_frames); -fc_host_statistic(tx_words); -fc_host_statistic(rx_frames); -fc_host_statistic(rx_words); -fc_host_statistic(lip_count); -fc_host_statistic(nos_count); -fc_host_statistic(error_frames); -fc_host_statistic(dumped_frames); -fc_host_statistic(link_failure_count); -fc_host_statistic(loss_of_sync_count); -fc_host_statistic(loss_of_signal_count); -fc_host_statistic(prim_seq_protocol_err_count); -fc_host_statistic(invalid_tx_word_count); -fc_host_statistic(invalid_crc_count); -fc_host_statistic(fcp_input_requests); -fc_host_statistic(fcp_output_requests); -fc_host_statistic(fcp_control_requests); -fc_host_statistic(fcp_input_megabytes); -fc_host_statistic(fcp_output_megabytes); - -static ssize_t -fc_reset_statistics(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_internal *i = to_fc_internal(shost->transportt); - - /* ignore any data value written to the attribute */ - if (i->f->reset_fc_host_stats) { - i->f->reset_fc_host_stats(shost); - return count; - } - - return -ENOENT; -} -static FC_DEVICE_ATTR(host, reset_statistics, S_IWUSR, NULL, - fc_reset_statistics); - -static struct attribute *fc_statistics_attrs[] = { - &device_attr_host_seconds_since_last_reset.attr, - &device_attr_host_tx_frames.attr, - &device_attr_host_tx_words.attr, - &device_attr_host_rx_frames.attr, - &device_attr_host_rx_words.attr, - &device_attr_host_lip_count.attr, - &device_attr_host_nos_count.attr, - &device_attr_host_error_frames.attr, - &device_attr_host_dumped_frames.attr, - &device_attr_host_link_failure_count.attr, - &device_attr_host_loss_of_sync_count.attr, - &device_attr_host_loss_of_signal_count.attr, - &device_attr_host_prim_seq_protocol_err_count.attr, - &device_attr_host_invalid_tx_word_count.attr, - &device_attr_host_invalid_crc_count.attr, - &device_attr_host_fcp_input_requests.attr, - &device_attr_host_fcp_output_requests.attr, - &device_attr_host_fcp_control_requests.attr, - &device_attr_host_fcp_input_megabytes.attr, - &device_attr_host_fcp_output_megabytes.attr, - &device_attr_host_reset_statistics.attr, - NULL -}; - -static struct attribute_group fc_statistics_group = { - .name = "statistics", - .attrs = fc_statistics_attrs, -}; - - -/* Host Vport Attributes */ - -static int -fc_parse_wwn(const char *ns, u64 *nm) -{ - unsigned int i, j; - u8 wwn[8]; - - memset(wwn, 0, sizeof(wwn)); - - /* Validate and store the new name */ - for (i=0, j=0; i < 16; i++) { - int value; - - value = hex_to_bin(*ns++); - if (value >= 0) - j = (j << 4) | value; - else - return -EINVAL; - if (i % 2) { - wwn[i/2] = j & 0xff; - j = 0; - } - } - - *nm = wwn_to_u64(wwn); - - return 0; -} - - -/* - * "Short-cut" sysfs variable to create a new vport on a FC Host. - * Input is a string of the form ":". Other attributes - * will default to a NPIV-based FCP_Initiator; The WWNs are specified - * as hex characters, and may *not* contain any prefixes (e.g. 0x, x, etc) - */ -static ssize_t -store_fc_host_vport_create(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_vport_identifiers vid; - struct fc_vport *vport; - unsigned int cnt=count; - int stat; - - memset(&vid, 0, sizeof(vid)); - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - /* validate we have enough characters for WWPN */ - if ((cnt != (16+1+16)) || (buf[16] != ':')) - return -EINVAL; - - stat = fc_parse_wwn(&buf[0], &vid.port_name); - if (stat) - return stat; - - stat = fc_parse_wwn(&buf[17], &vid.node_name); - if (stat) - return stat; - - vid.roles = FC_PORT_ROLE_FCP_INITIATOR; - vid.vport_type = FC_PORTTYPE_NPIV; - /* vid.symbolic_name is already zero/NULL's */ - vid.disable = false; /* always enabled */ - - /* we only allow support on Channel 0 !!! */ - stat = fc_vport_setup(shost, 0, &shost->shost_gendev, &vid, &vport); - return stat ? stat : count; -} -static FC_DEVICE_ATTR(host, vport_create, S_IWUSR, NULL, - store_fc_host_vport_create); - - -/* - * "Short-cut" sysfs variable to delete a vport on a FC Host. - * Vport is identified by a string containing ":". - * The WWNs are specified as hex characters, and may *not* contain - * any prefixes (e.g. 0x, x, etc) - */ -static ssize_t -store_fc_host_vport_delete(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - struct fc_vport *vport; - u64 wwpn, wwnn; - unsigned long flags; - unsigned int cnt=count; - int stat, match; - - /* count may include a LF at end of string */ - if (buf[cnt-1] == '\n') - cnt--; - - /* validate we have enough characters for WWPN */ - if ((cnt != (16+1+16)) || (buf[16] != ':')) - return -EINVAL; - - stat = fc_parse_wwn(&buf[0], &wwpn); - if (stat) - return stat; - - stat = fc_parse_wwn(&buf[17], &wwnn); - if (stat) - return stat; - - spin_lock_irqsave(shost->host_lock, flags); - match = 0; - /* we only allow support on Channel 0 !!! */ - list_for_each_entry(vport, &fc_host->vports, peers) { - if ((vport->channel == 0) && - (vport->port_name == wwpn) && (vport->node_name == wwnn)) { - if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) - break; - vport->flags |= FC_VPORT_DELETING; - match = 1; - break; - } - } - spin_unlock_irqrestore(shost->host_lock, flags); - - if (!match) - return -ENODEV; - - stat = fc_vport_terminate(vport); - return stat ? stat : count; -} -static FC_DEVICE_ATTR(host, vport_delete, S_IWUSR, NULL, - store_fc_host_vport_delete); - - -static int fc_host_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct fc_internal *i; - - if (!scsi_is_host_device(dev)) - return 0; - - shost = dev_to_shost(dev); - if (!shost->transportt || shost->transportt->host_attrs.ac.class - != &fc_host_class.class) - return 0; - - i = to_fc_internal(shost->transportt); - - return &i->t.host_attrs.ac == cont; -} - -static int fc_target_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct fc_internal *i; - - if (!scsi_is_target_device(dev)) - return 0; - - shost = dev_to_shost(dev->parent); - if (!shost->transportt || shost->transportt->host_attrs.ac.class - != &fc_host_class.class) - return 0; - - i = to_fc_internal(shost->transportt); - - return &i->t.target_attrs.ac == cont; -} - -static void fc_rport_dev_release(struct device *dev) -{ - struct fc_rport *rport = dev_to_rport(dev); - put_device(dev->parent); - kfree(rport); -} - -int scsi_is_fc_rport(const struct device *dev) -{ - return dev->release == fc_rport_dev_release; -} -EXPORT_SYMBOL(scsi_is_fc_rport); - -static int fc_rport_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct fc_internal *i; - - if (!scsi_is_fc_rport(dev)) - return 0; - - shost = dev_to_shost(dev->parent); - if (!shost->transportt || shost->transportt->host_attrs.ac.class - != &fc_host_class.class) - return 0; - - i = to_fc_internal(shost->transportt); - - return &i->rport_attr_cont.ac == cont; -} - - -static void fc_vport_dev_release(struct device *dev) -{ - struct fc_vport *vport = dev_to_vport(dev); - put_device(dev->parent); /* release kobj parent */ - kfree(vport); -} - -int scsi_is_fc_vport(const struct device *dev) -{ - return dev->release == fc_vport_dev_release; -} -EXPORT_SYMBOL(scsi_is_fc_vport); - -static int fc_vport_match(struct attribute_container *cont, - struct device *dev) -{ - struct fc_vport *vport; - struct Scsi_Host *shost; - struct fc_internal *i; - - if (!scsi_is_fc_vport(dev)) - return 0; - vport = dev_to_vport(dev); - - shost = vport_to_shost(vport); - if (!shost->transportt || shost->transportt->host_attrs.ac.class - != &fc_host_class.class) - return 0; - - i = to_fc_internal(shost->transportt); - return &i->vport_attr_cont.ac == cont; -} - - -/** - * fc_timed_out - FC Transport I/O timeout intercept handler - * @scmd: The SCSI command which timed out - * - * This routine protects against error handlers getting invoked while a - * rport is in a blocked state, typically due to a temporarily loss of - * connectivity. If the error handlers are allowed to proceed, requests - * to abort i/o, reset the target, etc will likely fail as there is no way - * to communicate with the device to perform the requested function. These - * failures may result in the midlayer taking the device offline, requiring - * manual intervention to restore operation. - * - * This routine, called whenever an i/o times out, validates the state of - * the underlying rport. If the rport is blocked, it returns - * EH_RESET_TIMER, which will continue to reschedule the timeout. - * Eventually, either the device will return, or devloss_tmo will fire, - * and when the timeout then fires, it will be handled normally. - * If the rport is not blocked, normal error handling continues. - * - * Notes: - * This routine assumes no locks are held on entry. - */ -static enum blk_eh_timer_return -fc_timed_out(struct scsi_cmnd *scmd) -{ - struct fc_rport *rport = starget_to_rport(scsi_target(scmd->device)); - - if (rport->port_state == FC_PORTSTATE_BLOCKED) - return BLK_EH_RESET_TIMER; - - return BLK_EH_NOT_HANDLED; -} - -/* - * Called by fc_user_scan to locate an rport on the shost that - * matches the channel and target id, and invoke scsi_scan_target() - * on the rport. - */ -static void -fc_user_scan_tgt(struct Scsi_Host *shost, uint channel, uint id, uint lun) -{ - struct fc_rport *rport; - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - - list_for_each_entry(rport, &fc_host_rports(shost), peers) { - if (rport->scsi_target_id == -1) - continue; - - if (rport->port_state != FC_PORTSTATE_ONLINE) - continue; - - if ((channel == rport->channel) && - (id == rport->scsi_target_id)) { - spin_unlock_irqrestore(shost->host_lock, flags); - scsi_scan_target(&rport->dev, channel, id, lun, 1); - return; - } - } - - spin_unlock_irqrestore(shost->host_lock, flags); -} - -/* - * Called via sysfs scan routines. Necessary, as the FC transport - * wants to place all target objects below the rport object. So this - * routine must invoke the scsi_scan_target() routine with the rport - * object as the parent. - */ -static int -fc_user_scan(struct Scsi_Host *shost, uint channel, uint id, uint lun) -{ - uint chlo, chhi; - uint tgtlo, tgthi; - - if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) || - ((id != SCAN_WILD_CARD) && (id >= shost->max_id)) || - ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun))) - return -EINVAL; - - if (channel == SCAN_WILD_CARD) { - chlo = 0; - chhi = shost->max_channel + 1; - } else { - chlo = channel; - chhi = channel + 1; - } - - if (id == SCAN_WILD_CARD) { - tgtlo = 0; - tgthi = shost->max_id; - } else { - tgtlo = id; - tgthi = id + 1; - } - - for ( ; chlo < chhi; chlo++) - for ( ; tgtlo < tgthi; tgtlo++) - fc_user_scan_tgt(shost, chlo, tgtlo, lun); - - return 0; -} - -static int fc_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id, - int result) -{ - struct fc_internal *i = to_fc_internal(shost->transportt); - return i->f->tsk_mgmt_response(shost, nexus, tm_id, result); -} - -static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result) -{ - struct fc_internal *i = to_fc_internal(shost->transportt); - return i->f->it_nexus_response(shost, nexus, result); -} - -struct scsi_transport_template * -fc_attach_transport(struct fc_function_template *ft) -{ - int count; - struct fc_internal *i = kzalloc(sizeof(struct fc_internal), - GFP_KERNEL); - - if (unlikely(!i)) - return NULL; - - i->t.target_attrs.ac.attrs = &i->starget_attrs[0]; - i->t.target_attrs.ac.class = &fc_transport_class.class; - i->t.target_attrs.ac.match = fc_target_match; - i->t.target_size = sizeof(struct fc_starget_attrs); - transport_container_register(&i->t.target_attrs); - - i->t.host_attrs.ac.attrs = &i->host_attrs[0]; - i->t.host_attrs.ac.class = &fc_host_class.class; - i->t.host_attrs.ac.match = fc_host_match; - i->t.host_size = sizeof(struct fc_host_attrs); - if (ft->get_fc_host_stats) - i->t.host_attrs.statistics = &fc_statistics_group; - transport_container_register(&i->t.host_attrs); - - i->rport_attr_cont.ac.attrs = &i->rport_attrs[0]; - i->rport_attr_cont.ac.class = &fc_rport_class.class; - i->rport_attr_cont.ac.match = fc_rport_match; - transport_container_register(&i->rport_attr_cont); - - i->vport_attr_cont.ac.attrs = &i->vport_attrs[0]; - i->vport_attr_cont.ac.class = &fc_vport_class.class; - i->vport_attr_cont.ac.match = fc_vport_match; - transport_container_register(&i->vport_attr_cont); - - i->f = ft; - - /* Transport uses the shost workq for scsi scanning */ - i->t.create_work_queue = 1; - - i->t.eh_timed_out = fc_timed_out; - - i->t.user_scan = fc_user_scan; - - /* target-mode drivers' functions */ - i->t.tsk_mgmt_response = fc_tsk_mgmt_response; - i->t.it_nexus_response = fc_it_nexus_response; - - /* - * Setup SCSI Target Attributes. - */ - count = 0; - SETUP_STARGET_ATTRIBUTE_RD(node_name); - SETUP_STARGET_ATTRIBUTE_RD(port_name); - SETUP_STARGET_ATTRIBUTE_RD(port_id); - - BUG_ON(count > FC_STARGET_NUM_ATTRS); - - i->starget_attrs[count] = NULL; - - - /* - * Setup SCSI Host Attributes. - */ - count=0; - SETUP_HOST_ATTRIBUTE_RD(node_name); - SETUP_HOST_ATTRIBUTE_RD(port_name); - SETUP_HOST_ATTRIBUTE_RD(permanent_port_name); - SETUP_HOST_ATTRIBUTE_RD(supported_classes); - SETUP_HOST_ATTRIBUTE_RD(supported_fc4s); - SETUP_HOST_ATTRIBUTE_RD(supported_speeds); - SETUP_HOST_ATTRIBUTE_RD(maxframe_size); - if (ft->vport_create) { - SETUP_HOST_ATTRIBUTE_RD_NS(max_npiv_vports); - SETUP_HOST_ATTRIBUTE_RD_NS(npiv_vports_inuse); - } - SETUP_HOST_ATTRIBUTE_RD(serial_number); - SETUP_HOST_ATTRIBUTE_RD(manufacturer); - SETUP_HOST_ATTRIBUTE_RD(model); - SETUP_HOST_ATTRIBUTE_RD(model_description); - SETUP_HOST_ATTRIBUTE_RD(hardware_version); - SETUP_HOST_ATTRIBUTE_RD(driver_version); - SETUP_HOST_ATTRIBUTE_RD(firmware_version); - SETUP_HOST_ATTRIBUTE_RD(optionrom_version); - - SETUP_HOST_ATTRIBUTE_RD(port_id); - SETUP_HOST_ATTRIBUTE_RD(port_type); - SETUP_HOST_ATTRIBUTE_RD(port_state); - SETUP_HOST_ATTRIBUTE_RD(active_fc4s); - SETUP_HOST_ATTRIBUTE_RD(speed); - SETUP_HOST_ATTRIBUTE_RD(fabric_name); - SETUP_HOST_ATTRIBUTE_RD(symbolic_name); - SETUP_HOST_ATTRIBUTE_RW(system_hostname); - - /* Transport-managed attributes */ - SETUP_PRIVATE_HOST_ATTRIBUTE_RW(dev_loss_tmo); - SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type); - if (ft->issue_fc_host_lip) - SETUP_PRIVATE_HOST_ATTRIBUTE_RW(issue_lip); - if (ft->vport_create) - SETUP_PRIVATE_HOST_ATTRIBUTE_RW(vport_create); - if (ft->vport_delete) - SETUP_PRIVATE_HOST_ATTRIBUTE_RW(vport_delete); - - BUG_ON(count > FC_HOST_NUM_ATTRS); - - i->host_attrs[count] = NULL; - - /* - * Setup Remote Port Attributes. - */ - count=0; - SETUP_RPORT_ATTRIBUTE_RD(maxframe_size); - SETUP_RPORT_ATTRIBUTE_RD(supported_classes); - SETUP_RPORT_ATTRIBUTE_RW(dev_loss_tmo); - SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(node_name); - SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_name); - SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_id); - SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles); - SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state); - SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id); - SETUP_PRIVATE_RPORT_ATTRIBUTE_RW(fast_io_fail_tmo); - - BUG_ON(count > FC_RPORT_NUM_ATTRS); - - i->rport_attrs[count] = NULL; - - /* - * Setup Virtual Port Attributes. - */ - count=0; - SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_state); - SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_last_state); - SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(node_name); - SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(port_name); - SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(roles); - SETUP_PRIVATE_VPORT_ATTRIBUTE_RD(vport_type); - SETUP_VPORT_ATTRIBUTE_RW(symbolic_name); - SETUP_VPORT_ATTRIBUTE_WR(vport_delete); - SETUP_VPORT_ATTRIBUTE_WR(vport_disable); - - BUG_ON(count > FC_VPORT_NUM_ATTRS); - - i->vport_attrs[count] = NULL; - - return &i->t; -} -EXPORT_SYMBOL(fc_attach_transport); - -void fc_release_transport(struct scsi_transport_template *t) -{ - struct fc_internal *i = to_fc_internal(t); - - transport_container_unregister(&i->t.target_attrs); - transport_container_unregister(&i->t.host_attrs); - transport_container_unregister(&i->rport_attr_cont); - transport_container_unregister(&i->vport_attr_cont); - - kfree(i); -} -EXPORT_SYMBOL(fc_release_transport); - -/** - * fc_queue_work - Queue work to the fc_host workqueue. - * @shost: Pointer to Scsi_Host bound to fc_host. - * @work: Work to queue for execution. - * - * Return value: - * 1 - work queued for execution - * 0 - work is already queued - * -EINVAL - work queue doesn't exist - */ -static int -fc_queue_work(struct Scsi_Host *shost, struct work_struct *work) -{ - if (unlikely(!fc_host_work_q(shost))) { - printk(KERN_ERR - "ERROR: FC host '%s' attempted to queue work, " - "when no workqueue created.\n", shost->hostt->name); - dump_stack(); - - return -EINVAL; - } - - return queue_work(fc_host_work_q(shost), work); -} - -/** - * fc_flush_work - Flush a fc_host's workqueue. - * @shost: Pointer to Scsi_Host bound to fc_host. - */ -static void -fc_flush_work(struct Scsi_Host *shost) -{ - if (!fc_host_work_q(shost)) { - printk(KERN_ERR - "ERROR: FC host '%s' attempted to flush work, " - "when no workqueue created.\n", shost->hostt->name); - dump_stack(); - return; - } - - flush_workqueue(fc_host_work_q(shost)); -} - -/** - * fc_queue_devloss_work - Schedule work for the fc_host devloss workqueue. - * @shost: Pointer to Scsi_Host bound to fc_host. - * @work: Work to queue for execution. - * @delay: jiffies to delay the work queuing - * - * Return value: - * 1 on success / 0 already queued / < 0 for error - */ -static int -fc_queue_devloss_work(struct Scsi_Host *shost, struct delayed_work *work, - unsigned long delay) -{ - if (unlikely(!fc_host_devloss_work_q(shost))) { - printk(KERN_ERR - "ERROR: FC host '%s' attempted to queue work, " - "when no workqueue created.\n", shost->hostt->name); - dump_stack(); - - return -EINVAL; - } - - return queue_delayed_work(fc_host_devloss_work_q(shost), work, delay); -} - -/** - * fc_flush_devloss - Flush a fc_host's devloss workqueue. - * @shost: Pointer to Scsi_Host bound to fc_host. - */ -static void -fc_flush_devloss(struct Scsi_Host *shost) -{ - if (!fc_host_devloss_work_q(shost)) { - printk(KERN_ERR - "ERROR: FC host '%s' attempted to flush work, " - "when no workqueue created.\n", shost->hostt->name); - dump_stack(); - return; - } - - flush_workqueue(fc_host_devloss_work_q(shost)); -} - - -/** - * fc_remove_host - called to terminate any fc_transport-related elements for a scsi host. - * @shost: Which &Scsi_Host - * - * This routine is expected to be called immediately preceding the - * a driver's call to scsi_remove_host(). - * - * WARNING: A driver utilizing the fc_transport, which fails to call - * this routine prior to scsi_remove_host(), will leave dangling - * objects in /sys/class/fc_remote_ports. Access to any of these - * objects can result in a system crash !!! - * - * Notes: - * This routine assumes no locks are held on entry. - */ -void -fc_remove_host(struct Scsi_Host *shost) -{ - struct fc_vport *vport = NULL, *next_vport = NULL; - struct fc_rport *rport = NULL, *next_rport = NULL; - struct workqueue_struct *work_q; - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - - /* Remove any vports */ - list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) - fc_queue_work(shost, &vport->vport_delete_work); - - /* Remove any remote ports */ - list_for_each_entry_safe(rport, next_rport, - &fc_host->rports, peers) { - list_del(&rport->peers); - rport->port_state = FC_PORTSTATE_DELETED; - fc_queue_work(shost, &rport->rport_delete_work); - } - - list_for_each_entry_safe(rport, next_rport, - &fc_host->rport_bindings, peers) { - list_del(&rport->peers); - rport->port_state = FC_PORTSTATE_DELETED; - fc_queue_work(shost, &rport->rport_delete_work); - } - - spin_unlock_irqrestore(shost->host_lock, flags); - - /* flush all scan work items */ - scsi_flush_work(shost); - - /* flush all stgt delete, and rport delete work items, then kill it */ - if (fc_host->work_q) { - work_q = fc_host->work_q; - fc_host->work_q = NULL; - destroy_workqueue(work_q); - } - - /* flush all devloss work items, then kill it */ - if (fc_host->devloss_work_q) { - work_q = fc_host->devloss_work_q; - fc_host->devloss_work_q = NULL; - destroy_workqueue(work_q); - } -} -EXPORT_SYMBOL(fc_remove_host); - -static void fc_terminate_rport_io(struct fc_rport *rport) -{ - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); - - /* Involve the LLDD if possible to terminate all io on the rport. */ - if (i->f->terminate_rport_io) - i->f->terminate_rport_io(rport); - - /* - * must unblock to flush queued IO. The caller will have set - * the port_state or flags, so that fc_remote_port_chkready will - * fail IO. - */ - scsi_target_unblock(&rport->dev); -} - -/** - * fc_starget_delete - called to delete the scsi descendants of an rport - * @work: remote port to be operated on. - * - * Deletes target and all sdevs. - */ -static void -fc_starget_delete(struct work_struct *work) -{ - struct fc_rport *rport = - container_of(work, struct fc_rport, stgt_delete_work); - - fc_terminate_rport_io(rport); - scsi_remove_target(&rport->dev); -} - - -/** - * fc_rport_final_delete - finish rport termination and delete it. - * @work: remote port to be deleted. - */ -static void -fc_rport_final_delete(struct work_struct *work) -{ - struct fc_rport *rport = - container_of(work, struct fc_rport, rport_delete_work); - struct device *dev = &rport->dev; - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); - unsigned long flags; - int do_callback = 0; - - fc_terminate_rport_io(rport); - - /* - * if a scan is pending, flush the SCSI Host work_q so that - * that we can reclaim the rport scan work element. - */ - if (rport->flags & FC_RPORT_SCAN_PENDING) - scsi_flush_work(shost); - - /* - * Cancel any outstanding timers. These should really exist - * only when rmmod'ing the LLDD and we're asking for - * immediate termination of the rports - */ - spin_lock_irqsave(shost->host_lock, flags); - if (rport->flags & FC_RPORT_DEVLOSS_PENDING) { - spin_unlock_irqrestore(shost->host_lock, flags); - if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); - if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); - spin_lock_irqsave(shost->host_lock, flags); - rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; - } - spin_unlock_irqrestore(shost->host_lock, flags); - - /* Delete SCSI target and sdevs */ - if (rport->scsi_target_id != -1) - fc_starget_delete(&rport->stgt_delete_work); - - /* - * Notify the driver that the rport is now dead. The LLDD will - * also guarantee that any communication to the rport is terminated - * - * Avoid this call if we already called it when we preserved the - * rport for the binding. - */ - spin_lock_irqsave(shost->host_lock, flags); - if (!(rport->flags & FC_RPORT_DEVLOSS_CALLBK_DONE) && - (i->f->dev_loss_tmo_callbk)) { - rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; - do_callback = 1; - } - spin_unlock_irqrestore(shost->host_lock, flags); - - if (do_callback) - i->f->dev_loss_tmo_callbk(rport); - - fc_bsg_remove(rport->rqst_q); - - transport_remove_device(dev); - device_del(dev); - transport_destroy_device(dev); - put_device(&shost->shost_gendev); /* for fc_host->rport list */ - put_device(dev); /* for self-reference */ -} - - -/** - * fc_rport_create - allocates and creates a remote FC port. - * @shost: scsi host the remote port is connected to. - * @channel: Channel on shost port connected to. - * @ids: The world wide names, fc address, and FC4 port - * roles for the remote port. - * - * Allocates and creates the remoter port structure, including the - * class and sysfs creation. - * - * Notes: - * This routine assumes no locks are held on entry. - */ -static struct fc_rport * -fc_rport_create(struct Scsi_Host *shost, int channel, - struct fc_rport_identifiers *ids) -{ - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - struct fc_internal *fci = to_fc_internal(shost->transportt); - struct fc_rport *rport; - struct device *dev; - unsigned long flags; - int error; - size_t size; - - size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size); - rport = kzalloc(size, GFP_KERNEL); - if (unlikely(!rport)) { - printk(KERN_ERR "%s: allocation failure\n", __func__); - return NULL; - } - - rport->maxframe_size = -1; - rport->supported_classes = FC_COS_UNSPECIFIED; - rport->dev_loss_tmo = fc_host->dev_loss_tmo; - memcpy(&rport->node_name, &ids->node_name, sizeof(rport->node_name)); - memcpy(&rport->port_name, &ids->port_name, sizeof(rport->port_name)); - rport->port_id = ids->port_id; - rport->roles = ids->roles; - rport->port_state = FC_PORTSTATE_ONLINE; - if (fci->f->dd_fcrport_size) - rport->dd_data = &rport[1]; - rport->channel = channel; - rport->fast_io_fail_tmo = -1; - - INIT_DELAYED_WORK(&rport->dev_loss_work, fc_timeout_deleted_rport); - INIT_DELAYED_WORK(&rport->fail_io_work, fc_timeout_fail_rport_io); - INIT_WORK(&rport->scan_work, fc_scsi_scan_rport); - INIT_WORK(&rport->stgt_delete_work, fc_starget_delete); - INIT_WORK(&rport->rport_delete_work, fc_rport_final_delete); - - spin_lock_irqsave(shost->host_lock, flags); - - rport->number = fc_host->next_rport_number++; - if (rport->roles & FC_PORT_ROLE_FCP_TARGET) - rport->scsi_target_id = fc_host->next_target_id++; - else - rport->scsi_target_id = -1; - list_add_tail(&rport->peers, &fc_host->rports); - get_device(&shost->shost_gendev); /* for fc_host->rport list */ - - spin_unlock_irqrestore(shost->host_lock, flags); - - dev = &rport->dev; - device_initialize(dev); /* takes self reference */ - dev->parent = get_device(&shost->shost_gendev); /* parent reference */ - dev->release = fc_rport_dev_release; - dev_set_name(dev, "rport-%d:%d-%d", - shost->host_no, channel, rport->number); - transport_setup_device(dev); - - error = device_add(dev); - if (error) { - printk(KERN_ERR "FC Remote Port device_add failed\n"); - goto delete_rport; - } - transport_add_device(dev); - transport_configure_device(dev); - - fc_bsg_rportadd(shost, rport); - /* ignore any bsg add error - we just can't do sgio */ - - if (rport->roles & FC_PORT_ROLE_FCP_TARGET) { - /* initiate a scan of the target */ - rport->flags |= FC_RPORT_SCAN_PENDING; - scsi_queue_work(shost, &rport->scan_work); - } - - return rport; - -delete_rport: - transport_destroy_device(dev); - spin_lock_irqsave(shost->host_lock, flags); - list_del(&rport->peers); - put_device(&shost->shost_gendev); /* for fc_host->rport list */ - spin_unlock_irqrestore(shost->host_lock, flags); - put_device(dev->parent); - kfree(rport); - return NULL; -} - -/** - * fc_remote_port_add - notify fc transport of the existence of a remote FC port. - * @shost: scsi host the remote port is connected to. - * @channel: Channel on shost port connected to. - * @ids: The world wide names, fc address, and FC4 port - * roles for the remote port. - * - * The LLDD calls this routine to notify the transport of the existence - * of a remote port. The LLDD provides the unique identifiers (wwpn,wwn) - * of the port, it's FC address (port_id), and the FC4 roles that are - * active for the port. - * - * For ports that are FCP targets (aka scsi targets), the FC transport - * maintains consistent target id bindings on behalf of the LLDD. - * A consistent target id binding is an assignment of a target id to - * a remote port identifier, which persists while the scsi host is - * attached. The remote port can disappear, then later reappear, and - * it's target id assignment remains the same. This allows for shifts - * in FC addressing (if binding by wwpn or wwnn) with no apparent - * changes to the scsi subsystem which is based on scsi host number and - * target id values. Bindings are only valid during the attachment of - * the scsi host. If the host detaches, then later re-attaches, target - * id bindings may change. - * - * This routine is responsible for returning a remote port structure. - * The routine will search the list of remote ports it maintains - * internally on behalf of consistent target id mappings. If found, the - * remote port structure will be reused. Otherwise, a new remote port - * structure will be allocated. - * - * Whenever a remote port is allocated, a new fc_remote_port class - * device is created. - * - * Should not be called from interrupt context. - * - * Notes: - * This routine assumes no locks are held on entry. - */ -struct fc_rport * -fc_remote_port_add(struct Scsi_Host *shost, int channel, - struct fc_rport_identifiers *ids) -{ - struct fc_internal *fci = to_fc_internal(shost->transportt); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - struct fc_rport *rport; - unsigned long flags; - int match = 0; - - /* ensure any stgt delete functions are done */ - fc_flush_work(shost); - - /* - * Search the list of "active" rports, for an rport that has been - * deleted, but we've held off the real delete while the target - * is in a "blocked" state. - */ - spin_lock_irqsave(shost->host_lock, flags); - - list_for_each_entry(rport, &fc_host->rports, peers) { - - if ((rport->port_state == FC_PORTSTATE_BLOCKED) && - (rport->channel == channel)) { - - switch (fc_host->tgtid_bind_type) { - case FC_TGTID_BIND_BY_WWPN: - case FC_TGTID_BIND_NONE: - if (rport->port_name == ids->port_name) - match = 1; - break; - case FC_TGTID_BIND_BY_WWNN: - if (rport->node_name == ids->node_name) - match = 1; - break; - case FC_TGTID_BIND_BY_ID: - if (rport->port_id == ids->port_id) - match = 1; - break; - } - - if (match) { - - memcpy(&rport->node_name, &ids->node_name, - sizeof(rport->node_name)); - memcpy(&rport->port_name, &ids->port_name, - sizeof(rport->port_name)); - rport->port_id = ids->port_id; - - rport->port_state = FC_PORTSTATE_ONLINE; - rport->roles = ids->roles; - - spin_unlock_irqrestore(shost->host_lock, flags); - - if (fci->f->dd_fcrport_size) - memset(rport->dd_data, 0, - fci->f->dd_fcrport_size); - - /* - * If we were not a target, cancel the - * io terminate and rport timers, and - * we're done. - * - * If we were a target, but our new role - * doesn't indicate a target, leave the - * timers running expecting the role to - * change as the target fully logs in. If - * it doesn't, the target will be torn down. - * - * If we were a target, and our role shows - * we're still a target, cancel the timers - * and kick off a scan. - */ - - /* was a target, not in roles */ - if ((rport->scsi_target_id != -1) && - (!(ids->roles & FC_PORT_ROLE_FCP_TARGET))) - return rport; - - /* - * Stop the fail io and dev_loss timers. - * If they flush, the port_state will - * be checked and will NOOP the function. - */ - if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); - if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); - - spin_lock_irqsave(shost->host_lock, flags); - - rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | - FC_RPORT_DEVLOSS_PENDING | - FC_RPORT_DEVLOSS_CALLBK_DONE); - - /* if target, initiate a scan */ - if (rport->scsi_target_id != -1) { - rport->flags |= FC_RPORT_SCAN_PENDING; - scsi_queue_work(shost, - &rport->scan_work); - spin_unlock_irqrestore(shost->host_lock, - flags); - scsi_target_unblock(&rport->dev); - } else - spin_unlock_irqrestore(shost->host_lock, - flags); - - fc_bsg_goose_queue(rport); - - return rport; - } - } - } - - /* - * Search the bindings array - * Note: if never a FCP target, you won't be on this list - */ - if (fc_host->tgtid_bind_type != FC_TGTID_BIND_NONE) { - - /* search for a matching consistent binding */ - - list_for_each_entry(rport, &fc_host->rport_bindings, - peers) { - if (rport->channel != channel) - continue; - - switch (fc_host->tgtid_bind_type) { - case FC_TGTID_BIND_BY_WWPN: - if (rport->port_name == ids->port_name) - match = 1; - break; - case FC_TGTID_BIND_BY_WWNN: - if (rport->node_name == ids->node_name) - match = 1; - break; - case FC_TGTID_BIND_BY_ID: - if (rport->port_id == ids->port_id) - match = 1; - break; - case FC_TGTID_BIND_NONE: /* to keep compiler happy */ - break; - } - - if (match) { - list_move_tail(&rport->peers, &fc_host->rports); - break; - } - } - - if (match) { - memcpy(&rport->node_name, &ids->node_name, - sizeof(rport->node_name)); - memcpy(&rport->port_name, &ids->port_name, - sizeof(rport->port_name)); - rport->port_id = ids->port_id; - rport->roles = ids->roles; - rport->port_state = FC_PORTSTATE_ONLINE; - rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; - - if (fci->f->dd_fcrport_size) - memset(rport->dd_data, 0, - fci->f->dd_fcrport_size); - - if (rport->roles & FC_PORT_ROLE_FCP_TARGET) { - /* initiate a scan of the target */ - rport->flags |= FC_RPORT_SCAN_PENDING; - scsi_queue_work(shost, &rport->scan_work); - spin_unlock_irqrestore(shost->host_lock, flags); - scsi_target_unblock(&rport->dev); - } else - spin_unlock_irqrestore(shost->host_lock, flags); - - return rport; - } - } - - spin_unlock_irqrestore(shost->host_lock, flags); - - /* No consistent binding found - create new remote port entry */ - rport = fc_rport_create(shost, channel, ids); - - return rport; -} -EXPORT_SYMBOL(fc_remote_port_add); - - -/** - * fc_remote_port_delete - notifies the fc transport that a remote port is no longer in existence. - * @rport: The remote port that no longer exists - * - * The LLDD calls this routine to notify the transport that a remote - * port is no longer part of the topology. Note: Although a port - * may no longer be part of the topology, it may persist in the remote - * ports displayed by the fc_host. We do this under 2 conditions: - * 1) If the port was a scsi target, we delay its deletion by "blocking" it. - * This allows the port to temporarily disappear, then reappear without - * disrupting the SCSI device tree attached to it. During the "blocked" - * period the port will still exist. - * 2) If the port was a scsi target and disappears for longer than we - * expect, we'll delete the port and the tear down the SCSI device tree - * attached to it. However, we want to semi-persist the target id assigned - * to that port if it eventually does exist. The port structure will - * remain (although with minimal information) so that the target id - * bindings remails. - * - * If the remote port is not an FCP Target, it will be fully torn down - * and deallocated, including the fc_remote_port class device. - * - * If the remote port is an FCP Target, the port will be placed in a - * temporary blocked state. From the LLDD's perspective, the rport no - * longer exists. From the SCSI midlayer's perspective, the SCSI target - * exists, but all sdevs on it are blocked from further I/O. The following - * is then expected. - * - * If the remote port does not return (signaled by a LLDD call to - * fc_remote_port_add()) within the dev_loss_tmo timeout, then the - * scsi target is removed - killing all outstanding i/o and removing the - * scsi devices attached ot it. The port structure will be marked Not - * Present and be partially cleared, leaving only enough information to - * recognize the remote port relative to the scsi target id binding if - * it later appears. The port will remain as long as there is a valid - * binding (e.g. until the user changes the binding type or unloads the - * scsi host with the binding). - * - * If the remote port returns within the dev_loss_tmo value (and matches - * according to the target id binding type), the port structure will be - * reused. If it is no longer a SCSI target, the target will be torn - * down. If it continues to be a SCSI target, then the target will be - * unblocked (allowing i/o to be resumed), and a scan will be activated - * to ensure that all luns are detected. - * - * Called from normal process context only - cannot be called from interrupt. - * - * Notes: - * This routine assumes no locks are held on entry. - */ -void -fc_remote_port_delete(struct fc_rport *rport) -{ - struct Scsi_Host *shost = rport_to_shost(rport); - unsigned long timeout = rport->dev_loss_tmo; - unsigned long flags; - - /* - * No need to flush the fc_host work_q's, as all adds are synchronous. - * - * We do need to reclaim the rport scan work element, so eventually - * (in fc_rport_final_delete()) we'll flush the scsi host work_q if - * there's still a scan pending. - */ - - spin_lock_irqsave(shost->host_lock, flags); - - if (rport->port_state != FC_PORTSTATE_ONLINE) { - spin_unlock_irqrestore(shost->host_lock, flags); - return; - } - - /* - * In the past, we if this was not an FCP-Target, we would - * unconditionally just jump to deleting the rport. - * However, rports can be used as node containers by the LLDD, - * and its not appropriate to just terminate the rport at the - * first sign of a loss in connectivity. The LLDD may want to - * send ELS traffic to re-validate the login. If the rport is - * immediately deleted, it makes it inappropriate for a node - * container. - * So... we now unconditionally wait dev_loss_tmo before - * destroying an rport. - */ - - rport->port_state = FC_PORTSTATE_BLOCKED; - - rport->flags |= FC_RPORT_DEVLOSS_PENDING; - - spin_unlock_irqrestore(shost->host_lock, flags); - - if (rport->roles & FC_PORT_ROLE_FCP_INITIATOR && - shost->active_mode & MODE_TARGET) - fc_tgt_it_nexus_destroy(shost, (unsigned long)rport); - - scsi_target_block(&rport->dev); - - /* see if we need to kill io faster than waiting for device loss */ - if ((rport->fast_io_fail_tmo != -1) && - (rport->fast_io_fail_tmo < timeout)) - fc_queue_devloss_work(shost, &rport->fail_io_work, - rport->fast_io_fail_tmo * HZ); - - /* cap the length the devices can be blocked until they are deleted */ - fc_queue_devloss_work(shost, &rport->dev_loss_work, timeout * HZ); -} -EXPORT_SYMBOL(fc_remote_port_delete); - -/** - * fc_remote_port_rolechg - notifies the fc transport that the roles on a remote may have changed. - * @rport: The remote port that changed. - * @roles: New roles for this port. - * - * Description: The LLDD calls this routine to notify the transport that the - * roles on a remote port may have changed. The largest effect of this is - * if a port now becomes a FCP Target, it must be allocated a - * scsi target id. If the port is no longer a FCP target, any - * scsi target id value assigned to it will persist in case the - * role changes back to include FCP Target. No changes in the scsi - * midlayer will be invoked if the role changes (in the expectation - * that the role will be resumed. If it doesn't normal error processing - * will take place). - * - * Should not be called from interrupt context. - * - * Notes: - * This routine assumes no locks are held on entry. - */ -void -fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) -{ - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - unsigned long flags; - int create = 0; - int ret; - - spin_lock_irqsave(shost->host_lock, flags); - if (roles & FC_PORT_ROLE_FCP_TARGET) { - if (rport->scsi_target_id == -1) { - rport->scsi_target_id = fc_host->next_target_id++; - create = 1; - } else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET)) - create = 1; - } else if (shost->active_mode & MODE_TARGET) { - ret = fc_tgt_it_nexus_create(shost, (unsigned long)rport, - (char *)&rport->node_name); - if (ret) - printk(KERN_ERR "FC Remore Port tgt nexus failed %d\n", - ret); - } - - rport->roles = roles; - - spin_unlock_irqrestore(shost->host_lock, flags); - - if (create) { - /* - * There may have been a delete timer running on the - * port. Ensure that it is cancelled as we now know - * the port is an FCP Target. - * Note: we know the rport is exists and in an online - * state as the LLDD would not have had an rport - * reference to pass us. - * - * Take no action on the del_timer failure as the state - * machine state change will validate the - * transaction. - */ - if (!cancel_delayed_work(&rport->fail_io_work)) - fc_flush_devloss(shost); - if (!cancel_delayed_work(&rport->dev_loss_work)) - fc_flush_devloss(shost); - - spin_lock_irqsave(shost->host_lock, flags); - rport->flags &= ~(FC_RPORT_FAST_FAIL_TIMEDOUT | - FC_RPORT_DEVLOSS_PENDING | - FC_RPORT_DEVLOSS_CALLBK_DONE); - spin_unlock_irqrestore(shost->host_lock, flags); - - /* ensure any stgt delete functions are done */ - fc_flush_work(shost); - - /* initiate a scan of the target */ - spin_lock_irqsave(shost->host_lock, flags); - rport->flags |= FC_RPORT_SCAN_PENDING; - scsi_queue_work(shost, &rport->scan_work); - spin_unlock_irqrestore(shost->host_lock, flags); - scsi_target_unblock(&rport->dev); - } -} -EXPORT_SYMBOL(fc_remote_port_rolechg); - -/** - * fc_timeout_deleted_rport - Timeout handler for a deleted remote port. - * @work: rport target that failed to reappear in the allotted time. - * - * Description: An attempt to delete a remote port blocks, and if it fails - * to return in the allotted time this gets called. - */ -static void -fc_timeout_deleted_rport(struct work_struct *work) -{ - struct fc_rport *rport = - container_of(work, struct fc_rport, dev_loss_work.work); - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - unsigned long flags; - int do_callback = 0; - - spin_lock_irqsave(shost->host_lock, flags); - - rport->flags &= ~FC_RPORT_DEVLOSS_PENDING; - - /* - * If the port is ONLINE, then it came back. If it was a SCSI - * target, validate it still is. If not, tear down the - * scsi_target on it. - */ - if ((rport->port_state == FC_PORTSTATE_ONLINE) && - (rport->scsi_target_id != -1) && - !(rport->roles & FC_PORT_ROLE_FCP_TARGET)) { - dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: no longer" - " a FCP target, removing starget\n"); - spin_unlock_irqrestore(shost->host_lock, flags); - scsi_target_unblock(&rport->dev); - fc_queue_work(shost, &rport->stgt_delete_work); - return; - } - - /* NOOP state - we're flushing workq's */ - if (rport->port_state != FC_PORTSTATE_BLOCKED) { - spin_unlock_irqrestore(shost->host_lock, flags); - dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: leaving" - " rport%s alone\n", - (rport->scsi_target_id != -1) ? " and starget" : ""); - return; - } - - if ((fc_host->tgtid_bind_type == FC_TGTID_BIND_NONE) || - (rport->scsi_target_id == -1)) { - list_del(&rport->peers); - rport->port_state = FC_PORTSTATE_DELETED; - dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: removing" - " rport%s\n", - (rport->scsi_target_id != -1) ? " and starget" : ""); - fc_queue_work(shost, &rport->rport_delete_work); - spin_unlock_irqrestore(shost->host_lock, flags); - return; - } - - dev_printk(KERN_ERR, &rport->dev, - "blocked FC remote port time out: removing target and " - "saving binding\n"); - - list_move_tail(&rport->peers, &fc_host->rport_bindings); - - /* - * Note: We do not remove or clear the hostdata area. This allows - * host-specific target data to persist along with the - * scsi_target_id. It's up to the host to manage it's hostdata area. - */ - - /* - * Reinitialize port attributes that may change if the port comes back. - */ - rport->maxframe_size = -1; - rport->supported_classes = FC_COS_UNSPECIFIED; - rport->roles = FC_PORT_ROLE_UNKNOWN; - rport->port_state = FC_PORTSTATE_NOTPRESENT; - rport->flags &= ~FC_RPORT_FAST_FAIL_TIMEDOUT; - - /* - * Pre-emptively kill I/O rather than waiting for the work queue - * item to teardown the starget. (FCOE libFC folks prefer this - * and to have the rport_port_id still set when it's done). - */ - spin_unlock_irqrestore(shost->host_lock, flags); - fc_terminate_rport_io(rport); - - spin_lock_irqsave(shost->host_lock, flags); - - if (rport->port_state == FC_PORTSTATE_NOTPRESENT) { /* still missing */ - - /* remove the identifiers that aren't used in the consisting binding */ - switch (fc_host->tgtid_bind_type) { - case FC_TGTID_BIND_BY_WWPN: - rport->node_name = -1; - rport->port_id = -1; - break; - case FC_TGTID_BIND_BY_WWNN: - rport->port_name = -1; - rport->port_id = -1; - break; - case FC_TGTID_BIND_BY_ID: - rport->node_name = -1; - rport->port_name = -1; - break; - case FC_TGTID_BIND_NONE: /* to keep compiler happy */ - break; - } - - /* - * As this only occurs if the remote port (scsi target) - * went away and didn't come back - we'll remove - * all attached scsi devices. - */ - rport->flags |= FC_RPORT_DEVLOSS_CALLBK_DONE; - fc_queue_work(shost, &rport->stgt_delete_work); - - do_callback = 1; - } - - spin_unlock_irqrestore(shost->host_lock, flags); - - /* - * Notify the driver that the rport is now dead. The LLDD will - * also guarantee that any communication to the rport is terminated - * - * Note: we set the CALLBK_DONE flag above to correspond - */ - if (do_callback && i->f->dev_loss_tmo_callbk) - i->f->dev_loss_tmo_callbk(rport); -} - - -/** - * fc_timeout_fail_rport_io - Timeout handler for a fast io failing on a disconnected SCSI target. - * @work: rport to terminate io on. - * - * Notes: Only requests the failure of the io, not that all are flushed - * prior to returning. - */ -static void -fc_timeout_fail_rport_io(struct work_struct *work) -{ - struct fc_rport *rport = - container_of(work, struct fc_rport, fail_io_work.work); - - if (rport->port_state != FC_PORTSTATE_BLOCKED) - return; - - rport->flags |= FC_RPORT_FAST_FAIL_TIMEDOUT; - fc_terminate_rport_io(rport); -} - -/** - * fc_scsi_scan_rport - called to perform a scsi scan on a remote port. - * @work: remote port to be scanned. - */ -static void -fc_scsi_scan_rport(struct work_struct *work) -{ - struct fc_rport *rport = - container_of(work, struct fc_rport, scan_work); - struct Scsi_Host *shost = rport_to_shost(rport); - struct fc_internal *i = to_fc_internal(shost->transportt); - unsigned long flags; - - if ((rport->port_state == FC_PORTSTATE_ONLINE) && - (rport->roles & FC_PORT_ROLE_FCP_TARGET) && - !(i->f->disable_target_scan)) { - scsi_scan_target(&rport->dev, rport->channel, - rport->scsi_target_id, SCAN_WILD_CARD, 1); - } - - spin_lock_irqsave(shost->host_lock, flags); - rport->flags &= ~FC_RPORT_SCAN_PENDING; - spin_unlock_irqrestore(shost->host_lock, flags); -} - -/** - * fc_block_scsi_eh - Block SCSI eh thread for blocked fc_rport - * @cmnd: SCSI command that scsi_eh is trying to recover - * - * This routine can be called from a FC LLD scsi_eh callback. It - * blocks the scsi_eh thread until the fc_rport leaves the - * FC_PORTSTATE_BLOCKED, or the fast_io_fail_tmo fires. This is - * necessary to avoid the scsi_eh failing recovery actions for blocked - * rports which would lead to offlined SCSI devices. - * - * Returns: 0 if the fc_rport left the state FC_PORTSTATE_BLOCKED. - * FAST_IO_FAIL if the fast_io_fail_tmo fired, this should be - * passed back to scsi_eh. - */ -int fc_block_scsi_eh(struct scsi_cmnd *cmnd) -{ - struct Scsi_Host *shost = cmnd->device->host; - struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device)); - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - while (rport->port_state == FC_PORTSTATE_BLOCKED && - !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) { - spin_unlock_irqrestore(shost->host_lock, flags); - msleep(1000); - spin_lock_irqsave(shost->host_lock, flags); - } - spin_unlock_irqrestore(shost->host_lock, flags); - - if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT) - return FAST_IO_FAIL; - - return 0; -} -EXPORT_SYMBOL(fc_block_scsi_eh); - -/** - * fc_vport_setup - allocates and creates a FC virtual port. - * @shost: scsi host the virtual port is connected to. - * @channel: Channel on shost port connected to. - * @pdev: parent device for vport - * @ids: The world wide names, FC4 port roles, etc for - * the virtual port. - * @ret_vport: The pointer to the created vport. - * - * Allocates and creates the vport structure, calls the parent host - * to instantiate the vport, the completes w/ class and sysfs creation. - * - * Notes: - * This routine assumes no locks are held on entry. - */ -static int -fc_vport_setup(struct Scsi_Host *shost, int channel, struct device *pdev, - struct fc_vport_identifiers *ids, struct fc_vport **ret_vport) -{ - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - struct fc_internal *fci = to_fc_internal(shost->transportt); - struct fc_vport *vport; - struct device *dev; - unsigned long flags; - size_t size; - int error; - - *ret_vport = NULL; - - if ( ! fci->f->vport_create) - return -ENOENT; - - size = (sizeof(struct fc_vport) + fci->f->dd_fcvport_size); - vport = kzalloc(size, GFP_KERNEL); - if (unlikely(!vport)) { - printk(KERN_ERR "%s: allocation failure\n", __func__); - return -ENOMEM; - } - - vport->vport_state = FC_VPORT_UNKNOWN; - vport->vport_last_state = FC_VPORT_UNKNOWN; - vport->node_name = ids->node_name; - vport->port_name = ids->port_name; - vport->roles = ids->roles; - vport->vport_type = ids->vport_type; - if (fci->f->dd_fcvport_size) - vport->dd_data = &vport[1]; - vport->shost = shost; - vport->channel = channel; - vport->flags = FC_VPORT_CREATING; - INIT_WORK(&vport->vport_delete_work, fc_vport_sched_delete); - - spin_lock_irqsave(shost->host_lock, flags); - - if (fc_host->npiv_vports_inuse >= fc_host->max_npiv_vports) { - spin_unlock_irqrestore(shost->host_lock, flags); - kfree(vport); - return -ENOSPC; - } - fc_host->npiv_vports_inuse++; - vport->number = fc_host->next_vport_number++; - list_add_tail(&vport->peers, &fc_host->vports); - get_device(&shost->shost_gendev); /* for fc_host->vport list */ - - spin_unlock_irqrestore(shost->host_lock, flags); - - dev = &vport->dev; - device_initialize(dev); /* takes self reference */ - dev->parent = get_device(pdev); /* takes parent reference */ - dev->release = fc_vport_dev_release; - dev_set_name(dev, "vport-%d:%d-%d", - shost->host_no, channel, vport->number); - transport_setup_device(dev); - - error = device_add(dev); - if (error) { - printk(KERN_ERR "FC Virtual Port device_add failed\n"); - goto delete_vport; - } - transport_add_device(dev); - transport_configure_device(dev); - - error = fci->f->vport_create(vport, ids->disable); - if (error) { - printk(KERN_ERR "FC Virtual Port LLDD Create failed\n"); - goto delete_vport_all; - } - - /* - * if the parent isn't the physical adapter's Scsi_Host, ensure - * the Scsi_Host at least contains ia symlink to the vport. - */ - if (pdev != &shost->shost_gendev) { - error = sysfs_create_link(&shost->shost_gendev.kobj, - &dev->kobj, dev_name(dev)); - if (error) - printk(KERN_ERR - "%s: Cannot create vport symlinks for " - "%s, err=%d\n", - __func__, dev_name(dev), error); - } - spin_lock_irqsave(shost->host_lock, flags); - vport->flags &= ~FC_VPORT_CREATING; - spin_unlock_irqrestore(shost->host_lock, flags); - - dev_printk(KERN_NOTICE, pdev, - "%s created via shost%d channel %d\n", dev_name(dev), - shost->host_no, channel); - - *ret_vport = vport; - - return 0; - -delete_vport_all: - transport_remove_device(dev); - device_del(dev); -delete_vport: - transport_destroy_device(dev); - spin_lock_irqsave(shost->host_lock, flags); - list_del(&vport->peers); - put_device(&shost->shost_gendev); /* for fc_host->vport list */ - fc_host->npiv_vports_inuse--; - spin_unlock_irqrestore(shost->host_lock, flags); - put_device(dev->parent); - kfree(vport); - - return error; -} - -/** - * fc_vport_create - Admin App or LLDD requests creation of a vport - * @shost: scsi host the virtual port is connected to. - * @channel: channel on shost port connected to. - * @ids: The world wide names, FC4 port roles, etc for - * the virtual port. - * - * Notes: - * This routine assumes no locks are held on entry. - */ -struct fc_vport * -fc_vport_create(struct Scsi_Host *shost, int channel, - struct fc_vport_identifiers *ids) -{ - int stat; - struct fc_vport *vport; - - stat = fc_vport_setup(shost, channel, &shost->shost_gendev, - ids, &vport); - return stat ? NULL : vport; -} -EXPORT_SYMBOL(fc_vport_create); - -/** - * fc_vport_terminate - Admin App or LLDD requests termination of a vport - * @vport: fc_vport to be terminated - * - * Calls the LLDD vport_delete() function, then deallocates and removes - * the vport from the shost and object tree. - * - * Notes: - * This routine assumes no locks are held on entry. - */ -int -fc_vport_terminate(struct fc_vport *vport) -{ - struct Scsi_Host *shost = vport_to_shost(vport); - struct fc_host_attrs *fc_host = shost_to_fc_host(shost); - struct fc_internal *i = to_fc_internal(shost->transportt); - struct device *dev = &vport->dev; - unsigned long flags; - int stat; - - if (i->f->vport_delete) - stat = i->f->vport_delete(vport); - else - stat = -ENOENT; - - spin_lock_irqsave(shost->host_lock, flags); - vport->flags &= ~FC_VPORT_DELETING; - if (!stat) { - vport->flags |= FC_VPORT_DELETED; - list_del(&vport->peers); - fc_host->npiv_vports_inuse--; - put_device(&shost->shost_gendev); /* for fc_host->vport list */ - } - spin_unlock_irqrestore(shost->host_lock, flags); - - if (stat) - return stat; - - if (dev->parent != &shost->shost_gendev) - sysfs_remove_link(&shost->shost_gendev.kobj, dev_name(dev)); - transport_remove_device(dev); - device_del(dev); - transport_destroy_device(dev); - - /* - * Removing our self-reference should mean our - * release function gets called, which will drop the remaining - * parent reference and free the data structure. - */ - put_device(dev); /* for self-reference */ - - return 0; /* SUCCESS */ -} -EXPORT_SYMBOL(fc_vport_terminate); - -/** - * fc_vport_sched_delete - workq-based delete request for a vport - * @work: vport to be deleted. - */ -static void -fc_vport_sched_delete(struct work_struct *work) -{ - struct fc_vport *vport = - container_of(work, struct fc_vport, vport_delete_work); - int stat; - - stat = fc_vport_terminate(vport); - if (stat) - dev_printk(KERN_ERR, vport->dev.parent, - "%s: %s could not be deleted created via " - "shost%d channel %d - error %d\n", __func__, - dev_name(&vport->dev), vport->shost->host_no, - vport->channel, stat); -} - - -/* - * BSG support - */ - - -/** - * fc_destroy_bsgjob - routine to teardown/delete a fc bsg job - * @job: fc_bsg_job that is to be torn down - */ -static void -fc_destroy_bsgjob(struct fc_bsg_job *job) -{ - unsigned long flags; - - spin_lock_irqsave(&job->job_lock, flags); - if (job->ref_cnt) { - spin_unlock_irqrestore(&job->job_lock, flags); - return; - } - spin_unlock_irqrestore(&job->job_lock, flags); - - put_device(job->dev); /* release reference for the request */ - - kfree(job->request_payload.sg_list); - kfree(job->reply_payload.sg_list); - kfree(job); -} - -/** - * fc_bsg_jobdone - completion routine for bsg requests that the LLD has - * completed - * @job: fc_bsg_job that is complete - */ -static void -fc_bsg_jobdone(struct fc_bsg_job *job) -{ - struct request *req = job->req; - struct request *rsp = req->next_rq; - int err; - - err = job->req->errors = job->reply->result; - - if (err < 0) - /* we're only returning the result field in the reply */ - job->req->sense_len = sizeof(uint32_t); - else - job->req->sense_len = job->reply_len; - - /* we assume all request payload was transferred, residual == 0 */ - req->resid_len = 0; - - if (rsp) { - WARN_ON(job->reply->reply_payload_rcv_len > rsp->resid_len); - - /* set reply (bidi) residual */ - rsp->resid_len -= min(job->reply->reply_payload_rcv_len, - rsp->resid_len); - } - blk_complete_request(req); -} - -/** - * fc_bsg_softirq_done - softirq done routine for destroying the bsg requests - * @rq: BSG request that holds the job to be destroyed - */ -static void fc_bsg_softirq_done(struct request *rq) -{ - struct fc_bsg_job *job = rq->special; - unsigned long flags; - - spin_lock_irqsave(&job->job_lock, flags); - job->state_flags |= FC_RQST_STATE_DONE; - job->ref_cnt--; - spin_unlock_irqrestore(&job->job_lock, flags); - - blk_end_request_all(rq, rq->errors); - fc_destroy_bsgjob(job); -} - -/** - * fc_bsg_job_timeout - handler for when a bsg request timesout - * @req: request that timed out - */ -static enum blk_eh_timer_return -fc_bsg_job_timeout(struct request *req) -{ - struct fc_bsg_job *job = (void *) req->special; - struct Scsi_Host *shost = job->shost; - struct fc_internal *i = to_fc_internal(shost->transportt); - unsigned long flags; - int err = 0, done = 0; - - if (job->rport && job->rport->port_state == FC_PORTSTATE_BLOCKED) - return BLK_EH_RESET_TIMER; - - spin_lock_irqsave(&job->job_lock, flags); - if (job->state_flags & FC_RQST_STATE_DONE) - done = 1; - else - job->ref_cnt++; - spin_unlock_irqrestore(&job->job_lock, flags); - - if (!done && i->f->bsg_timeout) { - /* call LLDD to abort the i/o as it has timed out */ - err = i->f->bsg_timeout(job); - if (err == -EAGAIN) { - job->ref_cnt--; - return BLK_EH_RESET_TIMER; - } else if (err) - printk(KERN_ERR "ERROR: FC BSG request timeout - LLD " - "abort failed with status %d\n", err); - } - - /* the blk_end_sync_io() doesn't check the error */ - if (done) - return BLK_EH_NOT_HANDLED; - else - return BLK_EH_HANDLED; -} - -static int -fc_bsg_map_buffer(struct fc_bsg_buffer *buf, struct request *req) -{ - size_t sz = (sizeof(struct scatterlist) * req->nr_phys_segments); - - BUG_ON(!req->nr_phys_segments); - - buf->sg_list = kzalloc(sz, GFP_KERNEL); - if (!buf->sg_list) - return -ENOMEM; - sg_init_table(buf->sg_list, req->nr_phys_segments); - buf->sg_cnt = blk_rq_map_sg(req->q, req, buf->sg_list); - buf->payload_len = blk_rq_bytes(req); - return 0; -} - - -/** - * fc_req_to_bsgjob - Allocate/create the fc_bsg_job structure for the - * bsg request - * @shost: SCSI Host corresponding to the bsg object - * @rport: (optional) FC Remote Port corresponding to the bsg object - * @req: BSG request that needs a job structure - */ -static int -fc_req_to_bsgjob(struct Scsi_Host *shost, struct fc_rport *rport, - struct request *req) -{ - struct fc_internal *i = to_fc_internal(shost->transportt); - struct request *rsp = req->next_rq; - struct fc_bsg_job *job; - int ret; - - BUG_ON(req->special); - - job = kzalloc(sizeof(struct fc_bsg_job) + i->f->dd_bsg_size, - GFP_KERNEL); - if (!job) - return -ENOMEM; - - /* - * Note: this is a bit silly. - * The request gets formatted as a SGIO v4 ioctl request, which - * then gets reformatted as a blk request, which then gets - * reformatted as a fc bsg request. And on completion, we have - * to wrap return results such that SGIO v4 thinks it was a scsi - * status. I hope this was all worth it. - */ - - req->special = job; - job->shost = shost; - job->rport = rport; - job->req = req; - if (i->f->dd_bsg_size) - job->dd_data = (void *)&job[1]; - spin_lock_init(&job->job_lock); - job->request = (struct fc_bsg_request *)req->cmd; - job->request_len = req->cmd_len; - job->reply = req->sense; - job->reply_len = SCSI_SENSE_BUFFERSIZE; /* Size of sense buffer - * allocated */ - if (req->bio) { - ret = fc_bsg_map_buffer(&job->request_payload, req); - if (ret) - goto failjob_rls_job; - } - if (rsp && rsp->bio) { - ret = fc_bsg_map_buffer(&job->reply_payload, rsp); - if (ret) - goto failjob_rls_rqst_payload; - } - job->job_done = fc_bsg_jobdone; - if (rport) - job->dev = &rport->dev; - else - job->dev = &shost->shost_gendev; - get_device(job->dev); /* take a reference for the request */ - - job->ref_cnt = 1; - - return 0; - - -failjob_rls_rqst_payload: - kfree(job->request_payload.sg_list); -failjob_rls_job: - kfree(job); - return -ENOMEM; -} - - -enum fc_dispatch_result { - FC_DISPATCH_BREAK, /* on return, q is locked, break from q loop */ - FC_DISPATCH_LOCKED, /* on return, q is locked, continue on */ - FC_DISPATCH_UNLOCKED, /* on return, q is unlocked, continue on */ -}; - - -/** - * fc_bsg_host_dispatch - process fc host bsg requests and dispatch to LLDD - * @q: fc host request queue - * @shost: scsi host rport attached to - * @job: bsg job to be processed - */ -static enum fc_dispatch_result -fc_bsg_host_dispatch(struct request_queue *q, struct Scsi_Host *shost, - struct fc_bsg_job *job) -{ - struct fc_internal *i = to_fc_internal(shost->transportt); - int cmdlen = sizeof(uint32_t); /* start with length of msgcode */ - int ret; - - /* Validate the host command */ - switch (job->request->msgcode) { - case FC_BSG_HST_ADD_RPORT: - cmdlen += sizeof(struct fc_bsg_host_add_rport); - break; - - case FC_BSG_HST_DEL_RPORT: - cmdlen += sizeof(struct fc_bsg_host_del_rport); - break; - - case FC_BSG_HST_ELS_NOLOGIN: - cmdlen += sizeof(struct fc_bsg_host_els); - /* there better be a xmt and rcv payloads */ - if ((!job->request_payload.payload_len) || - (!job->reply_payload.payload_len)) { - ret = -EINVAL; - goto fail_host_msg; - } - break; - - case FC_BSG_HST_CT: - cmdlen += sizeof(struct fc_bsg_host_ct); - /* there better be xmt and rcv payloads */ - if ((!job->request_payload.payload_len) || - (!job->reply_payload.payload_len)) { - ret = -EINVAL; - goto fail_host_msg; - } - break; - - case FC_BSG_HST_VENDOR: - cmdlen += sizeof(struct fc_bsg_host_vendor); - if ((shost->hostt->vendor_id == 0L) || - (job->request->rqst_data.h_vendor.vendor_id != - shost->hostt->vendor_id)) { - ret = -ESRCH; - goto fail_host_msg; - } - break; - - default: - ret = -EBADR; - goto fail_host_msg; - } - - /* check if we really have all the request data needed */ - if (job->request_len < cmdlen) { - ret = -ENOMSG; - goto fail_host_msg; - } - - ret = i->f->bsg_request(job); - if (!ret) - return FC_DISPATCH_UNLOCKED; - -fail_host_msg: - /* return the errno failure code as the only status */ - BUG_ON(job->reply_len < sizeof(uint32_t)); - job->reply->reply_payload_rcv_len = 0; - job->reply->result = ret; - job->reply_len = sizeof(uint32_t); - fc_bsg_jobdone(job); - return FC_DISPATCH_UNLOCKED; -} - - -/* - * fc_bsg_goose_queue - restart rport queue in case it was stopped - * @rport: rport to be restarted - */ -static void -fc_bsg_goose_queue(struct fc_rport *rport) -{ - if (!rport->rqst_q) - return; - - /* - * This get/put dance makes no sense - */ - get_device(&rport->dev); - blk_run_queue_async(rport->rqst_q); - put_device(&rport->dev); -} - -/** - * fc_bsg_rport_dispatch - process rport bsg requests and dispatch to LLDD - * @q: rport request queue - * @shost: scsi host rport attached to - * @rport: rport request destined to - * @job: bsg job to be processed - */ -static enum fc_dispatch_result -fc_bsg_rport_dispatch(struct request_queue *q, struct Scsi_Host *shost, - struct fc_rport *rport, struct fc_bsg_job *job) -{ - struct fc_internal *i = to_fc_internal(shost->transportt); - int cmdlen = sizeof(uint32_t); /* start with length of msgcode */ - int ret; - - /* Validate the rport command */ - switch (job->request->msgcode) { - case FC_BSG_RPT_ELS: - cmdlen += sizeof(struct fc_bsg_rport_els); - goto check_bidi; - - case FC_BSG_RPT_CT: - cmdlen += sizeof(struct fc_bsg_rport_ct); -check_bidi: - /* there better be xmt and rcv payloads */ - if ((!job->request_payload.payload_len) || - (!job->reply_payload.payload_len)) { - ret = -EINVAL; - goto fail_rport_msg; - } - break; - default: - ret = -EBADR; - goto fail_rport_msg; - } - - /* check if we really have all the request data needed */ - if (job->request_len < cmdlen) { - ret = -ENOMSG; - goto fail_rport_msg; - } - - ret = i->f->bsg_request(job); - if (!ret) - return FC_DISPATCH_UNLOCKED; - -fail_rport_msg: - /* return the errno failure code as the only status */ - BUG_ON(job->reply_len < sizeof(uint32_t)); - job->reply->reply_payload_rcv_len = 0; - job->reply->result = ret; - job->reply_len = sizeof(uint32_t); - fc_bsg_jobdone(job); - return FC_DISPATCH_UNLOCKED; -} - - -/** - * fc_bsg_request_handler - generic handler for bsg requests - * @q: request queue to manage - * @shost: Scsi_Host related to the bsg object - * @rport: FC remote port related to the bsg object (optional) - * @dev: device structure for bsg object - */ -static void -fc_bsg_request_handler(struct request_queue *q, struct Scsi_Host *shost, - struct fc_rport *rport, struct device *dev) -{ - struct request *req; - struct fc_bsg_job *job; - enum fc_dispatch_result ret; - - if (!get_device(dev)) - return; - - while (1) { - if (rport && (rport->port_state == FC_PORTSTATE_BLOCKED) && - !(rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT)) - break; - - req = blk_fetch_request(q); - if (!req) - break; - - if (rport && (rport->port_state != FC_PORTSTATE_ONLINE)) { - req->errors = -ENXIO; - spin_unlock_irq(q->queue_lock); - blk_end_request_all(req, -ENXIO); - spin_lock_irq(q->queue_lock); - continue; - } - - spin_unlock_irq(q->queue_lock); - - ret = fc_req_to_bsgjob(shost, rport, req); - if (ret) { - req->errors = ret; - blk_end_request_all(req, ret); - spin_lock_irq(q->queue_lock); - continue; - } - - job = req->special; - - /* check if we have the msgcode value at least */ - if (job->request_len < sizeof(uint32_t)) { - BUG_ON(job->reply_len < sizeof(uint32_t)); - job->reply->reply_payload_rcv_len = 0; - job->reply->result = -ENOMSG; - job->reply_len = sizeof(uint32_t); - fc_bsg_jobdone(job); - spin_lock_irq(q->queue_lock); - continue; - } - - /* the dispatch routines will unlock the queue_lock */ - if (rport) - ret = fc_bsg_rport_dispatch(q, shost, rport, job); - else - ret = fc_bsg_host_dispatch(q, shost, job); - - /* did dispatcher hit state that can't process any more */ - if (ret == FC_DISPATCH_BREAK) - break; - - /* did dispatcher had released the lock */ - if (ret == FC_DISPATCH_UNLOCKED) - spin_lock_irq(q->queue_lock); - } - - spin_unlock_irq(q->queue_lock); - put_device(dev); - spin_lock_irq(q->queue_lock); -} - - -/** - * fc_bsg_host_handler - handler for bsg requests for a fc host - * @q: fc host request queue - */ -static void -fc_bsg_host_handler(struct request_queue *q) -{ - struct Scsi_Host *shost = q->queuedata; - - fc_bsg_request_handler(q, shost, NULL, &shost->shost_gendev); -} - - -/** - * fc_bsg_rport_handler - handler for bsg requests for a fc rport - * @q: rport request queue - */ -static void -fc_bsg_rport_handler(struct request_queue *q) -{ - struct fc_rport *rport = q->queuedata; - struct Scsi_Host *shost = rport_to_shost(rport); - - fc_bsg_request_handler(q, shost, rport, &rport->dev); -} - - -/** - * fc_bsg_hostadd - Create and add the bsg hooks so we can receive requests - * @shost: shost for fc_host - * @fc_host: fc_host adding the structures to - */ -static int -fc_bsg_hostadd(struct Scsi_Host *shost, struct fc_host_attrs *fc_host) -{ - struct device *dev = &shost->shost_gendev; - struct fc_internal *i = to_fc_internal(shost->transportt); - struct request_queue *q; - int err; - char bsg_name[20]; - - fc_host->rqst_q = NULL; - - if (!i->f->bsg_request) - return -ENOTSUPP; - - snprintf(bsg_name, sizeof(bsg_name), - "fc_host%d", shost->host_no); - - q = __scsi_alloc_queue(shost, fc_bsg_host_handler); - if (!q) { - printk(KERN_ERR "fc_host%d: bsg interface failed to " - "initialize - no request queue\n", - shost->host_no); - return -ENOMEM; - } - - q->queuedata = shost; - queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); - blk_queue_softirq_done(q, fc_bsg_softirq_done); - blk_queue_rq_timed_out(q, fc_bsg_job_timeout); - blk_queue_rq_timeout(q, FC_DEFAULT_BSG_TIMEOUT); - - err = bsg_register_queue(q, dev, bsg_name, NULL); - if (err) { - printk(KERN_ERR "fc_host%d: bsg interface failed to " - "initialize - register queue\n", - shost->host_no); - blk_cleanup_queue(q); - return err; - } - - fc_host->rqst_q = q; - return 0; -} - - -/** - * fc_bsg_rportadd - Create and add the bsg hooks so we can receive requests - * @shost: shost that rport is attached to - * @rport: rport that the bsg hooks are being attached to - */ -static int -fc_bsg_rportadd(struct Scsi_Host *shost, struct fc_rport *rport) -{ - struct device *dev = &rport->dev; - struct fc_internal *i = to_fc_internal(shost->transportt); - struct request_queue *q; - int err; - - rport->rqst_q = NULL; - - if (!i->f->bsg_request) - return -ENOTSUPP; - - q = __scsi_alloc_queue(shost, fc_bsg_rport_handler); - if (!q) { - printk(KERN_ERR "%s: bsg interface failed to " - "initialize - no request queue\n", - dev->kobj.name); - return -ENOMEM; - } - - q->queuedata = rport; - queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); - blk_queue_softirq_done(q, fc_bsg_softirq_done); - blk_queue_rq_timed_out(q, fc_bsg_job_timeout); - blk_queue_rq_timeout(q, BLK_DEFAULT_SG_TIMEOUT); - - err = bsg_register_queue(q, dev, NULL, NULL); - if (err) { - printk(KERN_ERR "%s: bsg interface failed to " - "initialize - register queue\n", - dev->kobj.name); - blk_cleanup_queue(q); - return err; - } - - rport->rqst_q = q; - return 0; -} - - -/** - * fc_bsg_remove - Deletes the bsg hooks on fchosts/rports - * @q: the request_queue that is to be torn down. - * - * Notes: - * Before unregistering the queue empty any requests that are blocked - * - * - */ -static void -fc_bsg_remove(struct request_queue *q) -{ - struct request *req; /* block request */ - int counts; /* totals for request_list count and starved */ - - if (q) { - /* Stop taking in new requests */ - spin_lock_irq(q->queue_lock); - blk_stop_queue(q); - - /* drain all requests in the queue */ - while (1) { - /* need the lock to fetch a request - * this may fetch the same reqeust as the previous pass - */ - req = blk_fetch_request(q); - /* save requests in use and starved */ - counts = q->rq.count[0] + q->rq.count[1] + - q->rq.starved[0] + q->rq.starved[1]; - spin_unlock_irq(q->queue_lock); - /* any requests still outstanding? */ - if (counts == 0) - break; - - /* This may be the same req as the previous iteration, - * always send the blk_end_request_all after a prefetch. - * It is not okay to not end the request because the - * prefetch started the request. - */ - if (req) { - /* return -ENXIO to indicate that this queue is - * going away - */ - req->errors = -ENXIO; - blk_end_request_all(req, -ENXIO); - } - - msleep(200); /* allow bsg to possibly finish */ - spin_lock_irq(q->queue_lock); - } - - bsg_unregister_queue(q); - blk_cleanup_queue(q); - } -} - - -/* Original Author: Martin Hicks */ -MODULE_AUTHOR("James Smart"); -MODULE_DESCRIPTION("FC Transport Attributes"); -MODULE_LICENSE("GPL"); - -module_init(fc_transport_init); -module_exit(fc_transport_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_transport_fc_internal.h b/ANDROID_3.4.5/drivers/scsi/scsi_transport_fc_internal.h deleted file mode 100644 index e7bfbe75..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_transport_fc_internal.h +++ /dev/null @@ -1,26 +0,0 @@ -#include - -#ifdef CONFIG_SCSI_FC_TGT_ATTRS -static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, - char *initiator) -{ - return scsi_tgt_it_nexus_create(shost, itn_id, initiator); -} - -static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) -{ - return scsi_tgt_it_nexus_destroy(shost, itn_id); -} -#else -static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, - char *initiator) -{ - return 0; -} - -static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) -{ - return 0; -} - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_transport_iscsi.c b/ANDROID_3.4.5/drivers/scsi/scsi_transport_iscsi.c deleted file mode 100644 index 1cf640e5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_transport_iscsi.c +++ /dev/null @@ -1,3020 +0,0 @@ -/* - * iSCSI transport class definitions - * - * Copyright (C) IBM Corporation, 2004 - * Copyright (C) Mike Christie, 2004 - 2005 - * Copyright (C) Dmitry Yusupov, 2004 - 2005 - * Copyright (C) Alex Aizman, 2004 - 2005 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ISCSI_TRANSPORT_VERSION "2.0-870" - -static int dbg_session; -module_param_named(debug_session, dbg_session, int, - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_session, - "Turn on debugging for sessions in scsi_transport_iscsi " - "module. Set to 1 to turn on, and zero to turn off. Default " - "is off."); - -static int dbg_conn; -module_param_named(debug_conn, dbg_conn, int, - S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(debug_conn, - "Turn on debugging for connections in scsi_transport_iscsi " - "module. Set to 1 to turn on, and zero to turn off. Default " - "is off."); - -#define ISCSI_DBG_TRANS_SESSION(_session, dbg_fmt, arg...) \ - do { \ - if (dbg_session) \ - iscsi_cls_session_printk(KERN_INFO, _session, \ - "%s: " dbg_fmt, \ - __func__, ##arg); \ - } while (0); - -#define ISCSI_DBG_TRANS_CONN(_conn, dbg_fmt, arg...) \ - do { \ - if (dbg_conn) \ - iscsi_cls_conn_printk(KERN_INFO, _conn, \ - "%s: " dbg_fmt, \ - __func__, ##arg); \ - } while (0); - -struct iscsi_internal { - struct scsi_transport_template t; - struct iscsi_transport *iscsi_transport; - struct list_head list; - struct device dev; - - struct transport_container conn_cont; - struct transport_container session_cont; -}; - -static atomic_t iscsi_session_nr; /* sysfs session id for next new session */ -static struct workqueue_struct *iscsi_eh_timer_workq; - -static DEFINE_IDA(iscsi_sess_ida); -/* - * list of registered transports and lock that must - * be held while accessing list. The iscsi_transport_lock must - * be acquired after the rx_queue_mutex. - */ -static LIST_HEAD(iscsi_transports); -static DEFINE_SPINLOCK(iscsi_transport_lock); - -#define to_iscsi_internal(tmpl) \ - container_of(tmpl, struct iscsi_internal, t) - -#define dev_to_iscsi_internal(_dev) \ - container_of(_dev, struct iscsi_internal, dev) - -static void iscsi_transport_release(struct device *dev) -{ - struct iscsi_internal *priv = dev_to_iscsi_internal(dev); - kfree(priv); -} - -/* - * iscsi_transport_class represents the iscsi_transports that are - * registered. - */ -static struct class iscsi_transport_class = { - .name = "iscsi_transport", - .dev_release = iscsi_transport_release, -}; - -static ssize_t -show_transport_handle(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct iscsi_internal *priv = dev_to_iscsi_internal(dev); - return sprintf(buf, "%llu\n", (unsigned long long)iscsi_handle(priv->iscsi_transport)); -} -static DEVICE_ATTR(handle, S_IRUGO, show_transport_handle, NULL); - -#define show_transport_attr(name, format) \ -static ssize_t \ -show_transport_##name(struct device *dev, \ - struct device_attribute *attr,char *buf) \ -{ \ - struct iscsi_internal *priv = dev_to_iscsi_internal(dev); \ - return sprintf(buf, format"\n", priv->iscsi_transport->name); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, show_transport_##name, NULL); - -show_transport_attr(caps, "0x%x"); - -static struct attribute *iscsi_transport_attrs[] = { - &dev_attr_handle.attr, - &dev_attr_caps.attr, - NULL, -}; - -static struct attribute_group iscsi_transport_group = { - .attrs = iscsi_transport_attrs, -}; - -/* - * iSCSI endpoint attrs - */ -#define iscsi_dev_to_endpoint(_dev) \ - container_of(_dev, struct iscsi_endpoint, dev) - -#define ISCSI_ATTR(_prefix,_name,_mode,_show,_store) \ -struct device_attribute dev_attr_##_prefix##_##_name = \ - __ATTR(_name,_mode,_show,_store) - -static void iscsi_endpoint_release(struct device *dev) -{ - struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); - kfree(ep); -} - -static struct class iscsi_endpoint_class = { - .name = "iscsi_endpoint", - .dev_release = iscsi_endpoint_release, -}; - -static ssize_t -show_ep_handle(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); - return sprintf(buf, "%llu\n", (unsigned long long) ep->id); -} -static ISCSI_ATTR(ep, handle, S_IRUGO, show_ep_handle, NULL); - -static struct attribute *iscsi_endpoint_attrs[] = { - &dev_attr_ep_handle.attr, - NULL, -}; - -static struct attribute_group iscsi_endpoint_group = { - .attrs = iscsi_endpoint_attrs, -}; - -#define ISCSI_MAX_EPID -1 - -static int iscsi_match_epid(struct device *dev, void *data) -{ - struct iscsi_endpoint *ep = iscsi_dev_to_endpoint(dev); - uint64_t *epid = (uint64_t *) data; - - return *epid == ep->id; -} - -struct iscsi_endpoint * -iscsi_create_endpoint(int dd_size) -{ - struct device *dev; - struct iscsi_endpoint *ep; - uint64_t id; - int err; - - for (id = 1; id < ISCSI_MAX_EPID; id++) { - dev = class_find_device(&iscsi_endpoint_class, NULL, &id, - iscsi_match_epid); - if (!dev) - break; - } - if (id == ISCSI_MAX_EPID) { - printk(KERN_ERR "Too many connections. Max supported %u\n", - ISCSI_MAX_EPID - 1); - return NULL; - } - - ep = kzalloc(sizeof(*ep) + dd_size, GFP_KERNEL); - if (!ep) - return NULL; - - ep->id = id; - ep->dev.class = &iscsi_endpoint_class; - dev_set_name(&ep->dev, "ep-%llu", (unsigned long long) id); - err = device_register(&ep->dev); - if (err) - goto free_ep; - - err = sysfs_create_group(&ep->dev.kobj, &iscsi_endpoint_group); - if (err) - goto unregister_dev; - - if (dd_size) - ep->dd_data = &ep[1]; - return ep; - -unregister_dev: - device_unregister(&ep->dev); - return NULL; - -free_ep: - kfree(ep); - return NULL; -} -EXPORT_SYMBOL_GPL(iscsi_create_endpoint); - -void iscsi_destroy_endpoint(struct iscsi_endpoint *ep) -{ - sysfs_remove_group(&ep->dev.kobj, &iscsi_endpoint_group); - device_unregister(&ep->dev); -} -EXPORT_SYMBOL_GPL(iscsi_destroy_endpoint); - -struct iscsi_endpoint *iscsi_lookup_endpoint(u64 handle) -{ - struct iscsi_endpoint *ep; - struct device *dev; - - dev = class_find_device(&iscsi_endpoint_class, NULL, &handle, - iscsi_match_epid); - if (!dev) - return NULL; - - ep = iscsi_dev_to_endpoint(dev); - /* - * we can drop this now because the interface will prevent - * removals and lookups from racing. - */ - put_device(dev); - return ep; -} -EXPORT_SYMBOL_GPL(iscsi_lookup_endpoint); - -/* - * Interface to display network param to sysfs - */ - -static void iscsi_iface_release(struct device *dev) -{ - struct iscsi_iface *iface = iscsi_dev_to_iface(dev); - struct device *parent = iface->dev.parent; - - kfree(iface); - put_device(parent); -} - - -static struct class iscsi_iface_class = { - .name = "iscsi_iface", - .dev_release = iscsi_iface_release, -}; - -#define ISCSI_IFACE_ATTR(_prefix, _name, _mode, _show, _store) \ -struct device_attribute dev_attr_##_prefix##_##_name = \ - __ATTR(_name, _mode, _show, _store) - -/* iface attrs show */ -#define iscsi_iface_attr_show(type, name, param_type, param) \ -static ssize_t \ -show_##type##_##name(struct device *dev, struct device_attribute *attr, \ - char *buf) \ -{ \ - struct iscsi_iface *iface = iscsi_dev_to_iface(dev); \ - struct iscsi_transport *t = iface->transport; \ - return t->get_iface_param(iface, param_type, param, buf); \ -} \ - -#define iscsi_iface_net_attr(type, name, param) \ - iscsi_iface_attr_show(type, name, ISCSI_NET_PARAM, param) \ -static ISCSI_IFACE_ATTR(type, name, S_IRUGO, show_##type##_##name, NULL); - -/* generic read only ipvi4 attribute */ -iscsi_iface_net_attr(ipv4_iface, ipaddress, ISCSI_NET_PARAM_IPV4_ADDR); -iscsi_iface_net_attr(ipv4_iface, gateway, ISCSI_NET_PARAM_IPV4_GW); -iscsi_iface_net_attr(ipv4_iface, subnet, ISCSI_NET_PARAM_IPV4_SUBNET); -iscsi_iface_net_attr(ipv4_iface, bootproto, ISCSI_NET_PARAM_IPV4_BOOTPROTO); - -/* generic read only ipv6 attribute */ -iscsi_iface_net_attr(ipv6_iface, ipaddress, ISCSI_NET_PARAM_IPV6_ADDR); -iscsi_iface_net_attr(ipv6_iface, link_local_addr, ISCSI_NET_PARAM_IPV6_LINKLOCAL); -iscsi_iface_net_attr(ipv6_iface, router_addr, ISCSI_NET_PARAM_IPV6_ROUTER); -iscsi_iface_net_attr(ipv6_iface, ipaddr_autocfg, - ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG); -iscsi_iface_net_attr(ipv6_iface, link_local_autocfg, - ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG); - -/* common read only iface attribute */ -iscsi_iface_net_attr(iface, enabled, ISCSI_NET_PARAM_IFACE_ENABLE); -iscsi_iface_net_attr(iface, vlan_id, ISCSI_NET_PARAM_VLAN_ID); -iscsi_iface_net_attr(iface, vlan_priority, ISCSI_NET_PARAM_VLAN_PRIORITY); -iscsi_iface_net_attr(iface, vlan_enabled, ISCSI_NET_PARAM_VLAN_ENABLED); -iscsi_iface_net_attr(iface, mtu, ISCSI_NET_PARAM_MTU); -iscsi_iface_net_attr(iface, port, ISCSI_NET_PARAM_PORT); - -static umode_t iscsi_iface_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct iscsi_iface *iface = iscsi_dev_to_iface(dev); - struct iscsi_transport *t = iface->transport; - int param; - - if (attr == &dev_attr_iface_enabled.attr) - param = ISCSI_NET_PARAM_IFACE_ENABLE; - else if (attr == &dev_attr_iface_vlan_id.attr) - param = ISCSI_NET_PARAM_VLAN_ID; - else if (attr == &dev_attr_iface_vlan_priority.attr) - param = ISCSI_NET_PARAM_VLAN_PRIORITY; - else if (attr == &dev_attr_iface_vlan_enabled.attr) - param = ISCSI_NET_PARAM_VLAN_ENABLED; - else if (attr == &dev_attr_iface_mtu.attr) - param = ISCSI_NET_PARAM_MTU; - else if (attr == &dev_attr_iface_port.attr) - param = ISCSI_NET_PARAM_PORT; - else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV4) { - if (attr == &dev_attr_ipv4_iface_ipaddress.attr) - param = ISCSI_NET_PARAM_IPV4_ADDR; - else if (attr == &dev_attr_ipv4_iface_gateway.attr) - param = ISCSI_NET_PARAM_IPV4_GW; - else if (attr == &dev_attr_ipv4_iface_subnet.attr) - param = ISCSI_NET_PARAM_IPV4_SUBNET; - else if (attr == &dev_attr_ipv4_iface_bootproto.attr) - param = ISCSI_NET_PARAM_IPV4_BOOTPROTO; - else - return 0; - } else if (iface->iface_type == ISCSI_IFACE_TYPE_IPV6) { - if (attr == &dev_attr_ipv6_iface_ipaddress.attr) - param = ISCSI_NET_PARAM_IPV6_ADDR; - else if (attr == &dev_attr_ipv6_iface_link_local_addr.attr) - param = ISCSI_NET_PARAM_IPV6_LINKLOCAL; - else if (attr == &dev_attr_ipv6_iface_router_addr.attr) - param = ISCSI_NET_PARAM_IPV6_ROUTER; - else if (attr == &dev_attr_ipv6_iface_ipaddr_autocfg.attr) - param = ISCSI_NET_PARAM_IPV6_ADDR_AUTOCFG; - else if (attr == &dev_attr_ipv6_iface_link_local_autocfg.attr) - param = ISCSI_NET_PARAM_IPV6_LINKLOCAL_AUTOCFG; - else - return 0; - } else { - WARN_ONCE(1, "Invalid iface attr"); - return 0; - } - - return t->attr_is_visible(ISCSI_NET_PARAM, param); -} - -static struct attribute *iscsi_iface_attrs[] = { - &dev_attr_iface_enabled.attr, - &dev_attr_iface_vlan_id.attr, - &dev_attr_iface_vlan_priority.attr, - &dev_attr_iface_vlan_enabled.attr, - &dev_attr_ipv4_iface_ipaddress.attr, - &dev_attr_ipv4_iface_gateway.attr, - &dev_attr_ipv4_iface_subnet.attr, - &dev_attr_ipv4_iface_bootproto.attr, - &dev_attr_ipv6_iface_ipaddress.attr, - &dev_attr_ipv6_iface_link_local_addr.attr, - &dev_attr_ipv6_iface_router_addr.attr, - &dev_attr_ipv6_iface_ipaddr_autocfg.attr, - &dev_attr_ipv6_iface_link_local_autocfg.attr, - &dev_attr_iface_mtu.attr, - &dev_attr_iface_port.attr, - NULL, -}; - -static struct attribute_group iscsi_iface_group = { - .attrs = iscsi_iface_attrs, - .is_visible = iscsi_iface_attr_is_visible, -}; - -struct iscsi_iface * -iscsi_create_iface(struct Scsi_Host *shost, struct iscsi_transport *transport, - uint32_t iface_type, uint32_t iface_num, int dd_size) -{ - struct iscsi_iface *iface; - int err; - - iface = kzalloc(sizeof(*iface) + dd_size, GFP_KERNEL); - if (!iface) - return NULL; - - iface->transport = transport; - iface->iface_type = iface_type; - iface->iface_num = iface_num; - iface->dev.release = iscsi_iface_release; - iface->dev.class = &iscsi_iface_class; - /* parent reference released in iscsi_iface_release */ - iface->dev.parent = get_device(&shost->shost_gendev); - if (iface_type == ISCSI_IFACE_TYPE_IPV4) - dev_set_name(&iface->dev, "ipv4-iface-%u-%u", shost->host_no, - iface_num); - else - dev_set_name(&iface->dev, "ipv6-iface-%u-%u", shost->host_no, - iface_num); - - err = device_register(&iface->dev); - if (err) - goto free_iface; - - err = sysfs_create_group(&iface->dev.kobj, &iscsi_iface_group); - if (err) - goto unreg_iface; - - if (dd_size) - iface->dd_data = &iface[1]; - return iface; - -unreg_iface: - device_unregister(&iface->dev); - return NULL; - -free_iface: - put_device(iface->dev.parent); - kfree(iface); - return NULL; -} -EXPORT_SYMBOL_GPL(iscsi_create_iface); - -void iscsi_destroy_iface(struct iscsi_iface *iface) -{ - sysfs_remove_group(&iface->dev.kobj, &iscsi_iface_group); - device_unregister(&iface->dev); -} -EXPORT_SYMBOL_GPL(iscsi_destroy_iface); - -/* - * BSG support - */ -/** - * iscsi_bsg_host_dispatch - Dispatch command to LLD. - * @job: bsg job to be processed - */ -static int iscsi_bsg_host_dispatch(struct bsg_job *job) -{ - struct Scsi_Host *shost = iscsi_job_to_shost(job); - struct iscsi_bsg_request *req = job->request; - struct iscsi_bsg_reply *reply = job->reply; - struct iscsi_internal *i = to_iscsi_internal(shost->transportt); - int cmdlen = sizeof(uint32_t); /* start with length of msgcode */ - int ret; - - /* check if we have the msgcode value at least */ - if (job->request_len < sizeof(uint32_t)) { - ret = -ENOMSG; - goto fail_host_msg; - } - - /* Validate the host command */ - switch (req->msgcode) { - case ISCSI_BSG_HST_VENDOR: - cmdlen += sizeof(struct iscsi_bsg_host_vendor); - if ((shost->hostt->vendor_id == 0L) || - (req->rqst_data.h_vendor.vendor_id != - shost->hostt->vendor_id)) { - ret = -ESRCH; - goto fail_host_msg; - } - break; - default: - ret = -EBADR; - goto fail_host_msg; - } - - /* check if we really have all the request data needed */ - if (job->request_len < cmdlen) { - ret = -ENOMSG; - goto fail_host_msg; - } - - ret = i->iscsi_transport->bsg_request(job); - if (!ret) - return 0; - -fail_host_msg: - /* return the errno failure code as the only status */ - BUG_ON(job->reply_len < sizeof(uint32_t)); - reply->reply_payload_rcv_len = 0; - reply->result = ret; - job->reply_len = sizeof(uint32_t); - bsg_job_done(job, ret, 0); - return 0; -} - -/** - * iscsi_bsg_host_add - Create and add the bsg hooks to receive requests - * @shost: shost for iscsi_host - * @ihost: iscsi_cls_host adding the structures to - */ -static int -iscsi_bsg_host_add(struct Scsi_Host *shost, struct iscsi_cls_host *ihost) -{ - struct device *dev = &shost->shost_gendev; - struct iscsi_internal *i = to_iscsi_internal(shost->transportt); - struct request_queue *q; - char bsg_name[20]; - int ret; - - if (!i->iscsi_transport->bsg_request) - return -ENOTSUPP; - - snprintf(bsg_name, sizeof(bsg_name), "iscsi_host%d", shost->host_no); - - q = __scsi_alloc_queue(shost, bsg_request_fn); - if (!q) - return -ENOMEM; - - ret = bsg_setup_queue(dev, q, bsg_name, iscsi_bsg_host_dispatch, 0); - if (ret) { - shost_printk(KERN_ERR, shost, "bsg interface failed to " - "initialize - no request queue\n"); - blk_cleanup_queue(q); - return ret; - } - - ihost->bsg_q = q; - return 0; -} - -static int iscsi_setup_host(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct iscsi_cls_host *ihost = shost->shost_data; - - memset(ihost, 0, sizeof(*ihost)); - atomic_set(&ihost->nr_scans, 0); - mutex_init(&ihost->mutex); - - iscsi_bsg_host_add(shost, ihost); - /* ignore any bsg add error - we just can't do sgio */ - - return 0; -} - -static int iscsi_remove_host(struct transport_container *tc, - struct device *dev, struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct iscsi_cls_host *ihost = shost->shost_data; - - if (ihost->bsg_q) { - bsg_remove_queue(ihost->bsg_q); - blk_cleanup_queue(ihost->bsg_q); - } - return 0; -} - -static DECLARE_TRANSPORT_CLASS(iscsi_host_class, - "iscsi_host", - iscsi_setup_host, - iscsi_remove_host, - NULL); - -static DECLARE_TRANSPORT_CLASS(iscsi_session_class, - "iscsi_session", - NULL, - NULL, - NULL); - -static DECLARE_TRANSPORT_CLASS(iscsi_connection_class, - "iscsi_connection", - NULL, - NULL, - NULL); - -static struct sock *nls; -static DEFINE_MUTEX(rx_queue_mutex); - -static LIST_HEAD(sesslist); -static DEFINE_SPINLOCK(sesslock); -static LIST_HEAD(connlist); -static DEFINE_SPINLOCK(connlock); - -static uint32_t iscsi_conn_get_sid(struct iscsi_cls_conn *conn) -{ - struct iscsi_cls_session *sess = iscsi_dev_to_session(conn->dev.parent); - return sess->sid; -} - -/* - * Returns the matching session to a given sid - */ -static struct iscsi_cls_session *iscsi_session_lookup(uint32_t sid) -{ - unsigned long flags; - struct iscsi_cls_session *sess; - - spin_lock_irqsave(&sesslock, flags); - list_for_each_entry(sess, &sesslist, sess_list) { - if (sess->sid == sid) { - spin_unlock_irqrestore(&sesslock, flags); - return sess; - } - } - spin_unlock_irqrestore(&sesslock, flags); - return NULL; -} - -/* - * Returns the matching connection to a given sid / cid tuple - */ -static struct iscsi_cls_conn *iscsi_conn_lookup(uint32_t sid, uint32_t cid) -{ - unsigned long flags; - struct iscsi_cls_conn *conn; - - spin_lock_irqsave(&connlock, flags); - list_for_each_entry(conn, &connlist, conn_list) { - if ((conn->cid == cid) && (iscsi_conn_get_sid(conn) == sid)) { - spin_unlock_irqrestore(&connlock, flags); - return conn; - } - } - spin_unlock_irqrestore(&connlock, flags); - return NULL; -} - -/* - * The following functions can be used by LLDs that allocate - * their own scsi_hosts or by software iscsi LLDs - */ -static struct { - int value; - char *name; -} iscsi_session_state_names[] = { - { ISCSI_SESSION_LOGGED_IN, "LOGGED_IN" }, - { ISCSI_SESSION_FAILED, "FAILED" }, - { ISCSI_SESSION_FREE, "FREE" }, -}; - -static const char *iscsi_session_state_name(int state) -{ - int i; - char *name = NULL; - - for (i = 0; i < ARRAY_SIZE(iscsi_session_state_names); i++) { - if (iscsi_session_state_names[i].value == state) { - name = iscsi_session_state_names[i].name; - break; - } - } - return name; -} - -int iscsi_session_chkready(struct iscsi_cls_session *session) -{ - unsigned long flags; - int err; - - spin_lock_irqsave(&session->lock, flags); - switch (session->state) { - case ISCSI_SESSION_LOGGED_IN: - err = 0; - break; - case ISCSI_SESSION_FAILED: - err = DID_IMM_RETRY << 16; - break; - case ISCSI_SESSION_FREE: - err = DID_TRANSPORT_FAILFAST << 16; - break; - default: - err = DID_NO_CONNECT << 16; - break; - } - spin_unlock_irqrestore(&session->lock, flags); - return err; -} -EXPORT_SYMBOL_GPL(iscsi_session_chkready); - -int iscsi_is_session_online(struct iscsi_cls_session *session) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&session->lock, flags); - if (session->state == ISCSI_SESSION_LOGGED_IN) - ret = 1; - spin_unlock_irqrestore(&session->lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(iscsi_is_session_online); - -static void iscsi_session_release(struct device *dev) -{ - struct iscsi_cls_session *session = iscsi_dev_to_session(dev); - struct Scsi_Host *shost; - - shost = iscsi_session_to_shost(session); - scsi_host_put(shost); - ISCSI_DBG_TRANS_SESSION(session, "Completing session release\n"); - kfree(session); -} - -int iscsi_is_session_dev(const struct device *dev) -{ - return dev->release == iscsi_session_release; -} -EXPORT_SYMBOL_GPL(iscsi_is_session_dev); - -static int iscsi_iter_session_fn(struct device *dev, void *data) -{ - void (* fn) (struct iscsi_cls_session *) = data; - - if (!iscsi_is_session_dev(dev)) - return 0; - fn(iscsi_dev_to_session(dev)); - return 0; -} - -void iscsi_host_for_each_session(struct Scsi_Host *shost, - void (*fn)(struct iscsi_cls_session *)) -{ - device_for_each_child(&shost->shost_gendev, fn, - iscsi_iter_session_fn); -} -EXPORT_SYMBOL_GPL(iscsi_host_for_each_session); - -/** - * iscsi_scan_finished - helper to report when running scans are done - * @shost: scsi host - * @time: scan run time - * - * This function can be used by drives like qla4xxx to report to the scsi - * layer when the scans it kicked off at module load time are done. - */ -int iscsi_scan_finished(struct Scsi_Host *shost, unsigned long time) -{ - struct iscsi_cls_host *ihost = shost->shost_data; - /* - * qla4xxx will have kicked off some session unblocks before calling - * scsi_scan_host, so just wait for them to complete. - */ - return !atomic_read(&ihost->nr_scans); -} -EXPORT_SYMBOL_GPL(iscsi_scan_finished); - -struct iscsi_scan_data { - unsigned int channel; - unsigned int id; - unsigned int lun; -}; - -static int iscsi_user_scan_session(struct device *dev, void *data) -{ - struct iscsi_scan_data *scan_data = data; - struct iscsi_cls_session *session; - struct Scsi_Host *shost; - struct iscsi_cls_host *ihost; - unsigned long flags; - unsigned int id; - - if (!iscsi_is_session_dev(dev)) - return 0; - - session = iscsi_dev_to_session(dev); - - ISCSI_DBG_TRANS_SESSION(session, "Scanning session\n"); - - shost = iscsi_session_to_shost(session); - ihost = shost->shost_data; - - mutex_lock(&ihost->mutex); - spin_lock_irqsave(&session->lock, flags); - if (session->state != ISCSI_SESSION_LOGGED_IN) { - spin_unlock_irqrestore(&session->lock, flags); - goto user_scan_exit; - } - id = session->target_id; - spin_unlock_irqrestore(&session->lock, flags); - - if (id != ISCSI_MAX_TARGET) { - if ((scan_data->channel == SCAN_WILD_CARD || - scan_data->channel == 0) && - (scan_data->id == SCAN_WILD_CARD || - scan_data->id == id)) - scsi_scan_target(&session->dev, 0, id, - scan_data->lun, 1); - } - -user_scan_exit: - mutex_unlock(&ihost->mutex); - ISCSI_DBG_TRANS_SESSION(session, "Completed session scan\n"); - return 0; -} - -static int iscsi_user_scan(struct Scsi_Host *shost, uint channel, - uint id, uint lun) -{ - struct iscsi_scan_data scan_data; - - scan_data.channel = channel; - scan_data.id = id; - scan_data.lun = lun; - - return device_for_each_child(&shost->shost_gendev, &scan_data, - iscsi_user_scan_session); -} - -static void iscsi_scan_session(struct work_struct *work) -{ - struct iscsi_cls_session *session = - container_of(work, struct iscsi_cls_session, scan_work); - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_cls_host *ihost = shost->shost_data; - struct iscsi_scan_data scan_data; - - scan_data.channel = 0; - scan_data.id = SCAN_WILD_CARD; - scan_data.lun = SCAN_WILD_CARD; - - iscsi_user_scan_session(&session->dev, &scan_data); - atomic_dec(&ihost->nr_scans); -} - -/** - * iscsi_block_scsi_eh - block scsi eh until session state has transistioned - * @cmd: scsi cmd passed to scsi eh handler - * - * If the session is down this function will wait for the recovery - * timer to fire or for the session to be logged back in. If the - * recovery timer fires then FAST_IO_FAIL is returned. The caller - * should pass this error value to the scsi eh. - */ -int iscsi_block_scsi_eh(struct scsi_cmnd *cmd) -{ - struct iscsi_cls_session *session = - starget_to_session(scsi_target(cmd->device)); - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&session->lock, flags); - while (session->state != ISCSI_SESSION_LOGGED_IN) { - if (session->state == ISCSI_SESSION_FREE) { - ret = FAST_IO_FAIL; - break; - } - spin_unlock_irqrestore(&session->lock, flags); - msleep(1000); - spin_lock_irqsave(&session->lock, flags); - } - spin_unlock_irqrestore(&session->lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(iscsi_block_scsi_eh); - -static void session_recovery_timedout(struct work_struct *work) -{ - struct iscsi_cls_session *session = - container_of(work, struct iscsi_cls_session, - recovery_work.work); - unsigned long flags; - - iscsi_cls_session_printk(KERN_INFO, session, - "session recovery timed out after %d secs\n", - session->recovery_tmo); - - spin_lock_irqsave(&session->lock, flags); - switch (session->state) { - case ISCSI_SESSION_FAILED: - session->state = ISCSI_SESSION_FREE; - break; - case ISCSI_SESSION_LOGGED_IN: - case ISCSI_SESSION_FREE: - /* we raced with the unblock's flush */ - spin_unlock_irqrestore(&session->lock, flags); - return; - } - spin_unlock_irqrestore(&session->lock, flags); - - if (session->transport->session_recovery_timedout) - session->transport->session_recovery_timedout(session); - - ISCSI_DBG_TRANS_SESSION(session, "Unblocking SCSI target\n"); - scsi_target_unblock(&session->dev); - ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking SCSI target\n"); -} - -static void __iscsi_unblock_session(struct work_struct *work) -{ - struct iscsi_cls_session *session = - container_of(work, struct iscsi_cls_session, - unblock_work); - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_cls_host *ihost = shost->shost_data; - unsigned long flags; - - ISCSI_DBG_TRANS_SESSION(session, "Unblocking session\n"); - /* - * The recovery and unblock work get run from the same workqueue, - * so try to cancel it if it was going to run after this unblock. - */ - cancel_delayed_work(&session->recovery_work); - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_LOGGED_IN; - spin_unlock_irqrestore(&session->lock, flags); - /* start IO */ - scsi_target_unblock(&session->dev); - /* - * Only do kernel scanning if the driver is properly hooked into - * the async scanning code (drivers like iscsi_tcp do login and - * scanning from userspace). - */ - if (shost->hostt->scan_finished) { - if (scsi_queue_work(shost, &session->scan_work)) - atomic_inc(&ihost->nr_scans); - } - ISCSI_DBG_TRANS_SESSION(session, "Completed unblocking session\n"); -} - -/** - * iscsi_unblock_session - set a session as logged in and start IO. - * @session: iscsi session - * - * Mark a session as ready to accept IO. - */ -void iscsi_unblock_session(struct iscsi_cls_session *session) -{ - queue_work(iscsi_eh_timer_workq, &session->unblock_work); - /* - * make sure all the events have completed before tell the driver - * it is safe - */ - flush_workqueue(iscsi_eh_timer_workq); -} -EXPORT_SYMBOL_GPL(iscsi_unblock_session); - -static void __iscsi_block_session(struct work_struct *work) -{ - struct iscsi_cls_session *session = - container_of(work, struct iscsi_cls_session, - block_work); - unsigned long flags; - - ISCSI_DBG_TRANS_SESSION(session, "Blocking session\n"); - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_FAILED; - spin_unlock_irqrestore(&session->lock, flags); - scsi_target_block(&session->dev); - ISCSI_DBG_TRANS_SESSION(session, "Completed SCSI target blocking\n"); - if (session->recovery_tmo >= 0) - queue_delayed_work(iscsi_eh_timer_workq, - &session->recovery_work, - session->recovery_tmo * HZ); -} - -void iscsi_block_session(struct iscsi_cls_session *session) -{ - queue_work(iscsi_eh_timer_workq, &session->block_work); -} -EXPORT_SYMBOL_GPL(iscsi_block_session); - -static void __iscsi_unbind_session(struct work_struct *work) -{ - struct iscsi_cls_session *session = - container_of(work, struct iscsi_cls_session, - unbind_work); - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_cls_host *ihost = shost->shost_data; - unsigned long flags; - unsigned int target_id; - - ISCSI_DBG_TRANS_SESSION(session, "Unbinding session\n"); - - /* Prevent new scans and make sure scanning is not in progress */ - mutex_lock(&ihost->mutex); - spin_lock_irqsave(&session->lock, flags); - if (session->target_id == ISCSI_MAX_TARGET) { - spin_unlock_irqrestore(&session->lock, flags); - mutex_unlock(&ihost->mutex); - return; - } - - target_id = session->target_id; - session->target_id = ISCSI_MAX_TARGET; - spin_unlock_irqrestore(&session->lock, flags); - mutex_unlock(&ihost->mutex); - - if (session->ida_used) - ida_simple_remove(&iscsi_sess_ida, target_id); - - scsi_remove_target(&session->dev); - iscsi_session_event(session, ISCSI_KEVENT_UNBIND_SESSION); - ISCSI_DBG_TRANS_SESSION(session, "Completed target removal\n"); -} - -struct iscsi_cls_session * -iscsi_alloc_session(struct Scsi_Host *shost, struct iscsi_transport *transport, - int dd_size) -{ - struct iscsi_cls_session *session; - - session = kzalloc(sizeof(*session) + dd_size, - GFP_KERNEL); - if (!session) - return NULL; - - session->transport = transport; - session->creator = -1; - session->recovery_tmo = 120; - session->state = ISCSI_SESSION_FREE; - INIT_DELAYED_WORK(&session->recovery_work, session_recovery_timedout); - INIT_LIST_HEAD(&session->sess_list); - INIT_WORK(&session->unblock_work, __iscsi_unblock_session); - INIT_WORK(&session->block_work, __iscsi_block_session); - INIT_WORK(&session->unbind_work, __iscsi_unbind_session); - INIT_WORK(&session->scan_work, iscsi_scan_session); - spin_lock_init(&session->lock); - - /* this is released in the dev's release function */ - scsi_host_get(shost); - session->dev.parent = &shost->shost_gendev; - session->dev.release = iscsi_session_release; - device_initialize(&session->dev); - if (dd_size) - session->dd_data = &session[1]; - - ISCSI_DBG_TRANS_SESSION(session, "Completed session allocation\n"); - return session; -} -EXPORT_SYMBOL_GPL(iscsi_alloc_session); - -int iscsi_add_session(struct iscsi_cls_session *session, unsigned int target_id) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(session); - struct iscsi_cls_host *ihost; - unsigned long flags; - int id = 0; - int err; - - ihost = shost->shost_data; - session->sid = atomic_add_return(1, &iscsi_session_nr); - - if (target_id == ISCSI_MAX_TARGET) { - id = ida_simple_get(&iscsi_sess_ida, 0, 0, GFP_KERNEL); - - if (id < 0) { - iscsi_cls_session_printk(KERN_ERR, session, - "Failure in Target ID Allocation\n"); - return id; - } - session->target_id = (unsigned int)id; - session->ida_used = true; - } else - session->target_id = target_id; - - dev_set_name(&session->dev, "session%u", session->sid); - err = device_add(&session->dev); - if (err) { - iscsi_cls_session_printk(KERN_ERR, session, - "could not register session's dev\n"); - goto release_ida; - } - transport_register_device(&session->dev); - - spin_lock_irqsave(&sesslock, flags); - list_add(&session->sess_list, &sesslist); - spin_unlock_irqrestore(&sesslock, flags); - - iscsi_session_event(session, ISCSI_KEVENT_CREATE_SESSION); - ISCSI_DBG_TRANS_SESSION(session, "Completed session adding\n"); - return 0; - -release_ida: - if (session->ida_used) - ida_simple_remove(&iscsi_sess_ida, session->target_id); - - return err; -} -EXPORT_SYMBOL_GPL(iscsi_add_session); - -/** - * iscsi_create_session - create iscsi class session - * @shost: scsi host - * @transport: iscsi transport - * @dd_size: private driver data size - * @target_id: which target - * - * This can be called from a LLD or iscsi_transport. - */ -struct iscsi_cls_session * -iscsi_create_session(struct Scsi_Host *shost, struct iscsi_transport *transport, - int dd_size, unsigned int target_id) -{ - struct iscsi_cls_session *session; - - session = iscsi_alloc_session(shost, transport, dd_size); - if (!session) - return NULL; - - if (iscsi_add_session(session, target_id)) { - iscsi_free_session(session); - return NULL; - } - return session; -} -EXPORT_SYMBOL_GPL(iscsi_create_session); - -static void iscsi_conn_release(struct device *dev) -{ - struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev); - struct device *parent = conn->dev.parent; - - ISCSI_DBG_TRANS_CONN(conn, "Releasing conn\n"); - kfree(conn); - put_device(parent); -} - -static int iscsi_is_conn_dev(const struct device *dev) -{ - return dev->release == iscsi_conn_release; -} - -static int iscsi_iter_destroy_conn_fn(struct device *dev, void *data) -{ - if (!iscsi_is_conn_dev(dev)) - return 0; - return iscsi_destroy_conn(iscsi_dev_to_conn(dev)); -} - -void iscsi_remove_session(struct iscsi_cls_session *session) -{ - struct Scsi_Host *shost = iscsi_session_to_shost(session); - unsigned long flags; - int err; - - ISCSI_DBG_TRANS_SESSION(session, "Removing session\n"); - - spin_lock_irqsave(&sesslock, flags); - list_del(&session->sess_list); - spin_unlock_irqrestore(&sesslock, flags); - - /* make sure there are no blocks/unblocks queued */ - flush_workqueue(iscsi_eh_timer_workq); - /* make sure the timedout callout is not running */ - if (!cancel_delayed_work(&session->recovery_work)) - flush_workqueue(iscsi_eh_timer_workq); - /* - * If we are blocked let commands flow again. The lld or iscsi - * layer should set up the queuecommand to fail commands. - * We assume that LLD will not be calling block/unblock while - * removing the session. - */ - spin_lock_irqsave(&session->lock, flags); - session->state = ISCSI_SESSION_FREE; - spin_unlock_irqrestore(&session->lock, flags); - - scsi_target_unblock(&session->dev); - /* flush running scans then delete devices */ - scsi_flush_work(shost); - __iscsi_unbind_session(&session->unbind_work); - - /* hw iscsi may not have removed all connections from session */ - err = device_for_each_child(&session->dev, NULL, - iscsi_iter_destroy_conn_fn); - if (err) - iscsi_cls_session_printk(KERN_ERR, session, - "Could not delete all connections " - "for session. Error %d.\n", err); - - transport_unregister_device(&session->dev); - - ISCSI_DBG_TRANS_SESSION(session, "Completing session removal\n"); - device_del(&session->dev); -} -EXPORT_SYMBOL_GPL(iscsi_remove_session); - -void iscsi_free_session(struct iscsi_cls_session *session) -{ - ISCSI_DBG_TRANS_SESSION(session, "Freeing session\n"); - iscsi_session_event(session, ISCSI_KEVENT_DESTROY_SESSION); - put_device(&session->dev); -} -EXPORT_SYMBOL_GPL(iscsi_free_session); - -/** - * iscsi_destroy_session - destroy iscsi session - * @session: iscsi_session - * - * Can be called by a LLD or iscsi_transport. There must not be - * any running connections. - */ -int iscsi_destroy_session(struct iscsi_cls_session *session) -{ - iscsi_remove_session(session); - ISCSI_DBG_TRANS_SESSION(session, "Completing session destruction\n"); - iscsi_free_session(session); - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_destroy_session); - -/** - * iscsi_create_conn - create iscsi class connection - * @session: iscsi cls session - * @dd_size: private driver data size - * @cid: connection id - * - * This can be called from a LLD or iscsi_transport. The connection - * is child of the session so cid must be unique for all connections - * on the session. - * - * Since we do not support MCS, cid will normally be zero. In some cases - * for software iscsi we could be trying to preallocate a connection struct - * in which case there could be two connection structs and cid would be - * non-zero. - */ -struct iscsi_cls_conn * -iscsi_create_conn(struct iscsi_cls_session *session, int dd_size, uint32_t cid) -{ - struct iscsi_transport *transport = session->transport; - struct iscsi_cls_conn *conn; - unsigned long flags; - int err; - - conn = kzalloc(sizeof(*conn) + dd_size, GFP_KERNEL); - if (!conn) - return NULL; - if (dd_size) - conn->dd_data = &conn[1]; - - mutex_init(&conn->ep_mutex); - INIT_LIST_HEAD(&conn->conn_list); - conn->transport = transport; - conn->cid = cid; - - /* this is released in the dev's release function */ - if (!get_device(&session->dev)) - goto free_conn; - - dev_set_name(&conn->dev, "connection%d:%u", session->sid, cid); - conn->dev.parent = &session->dev; - conn->dev.release = iscsi_conn_release; - err = device_register(&conn->dev); - if (err) { - iscsi_cls_session_printk(KERN_ERR, session, "could not " - "register connection's dev\n"); - goto release_parent_ref; - } - transport_register_device(&conn->dev); - - spin_lock_irqsave(&connlock, flags); - list_add(&conn->conn_list, &connlist); - spin_unlock_irqrestore(&connlock, flags); - - ISCSI_DBG_TRANS_CONN(conn, "Completed conn creation\n"); - return conn; - -release_parent_ref: - put_device(&session->dev); -free_conn: - kfree(conn); - return NULL; -} - -EXPORT_SYMBOL_GPL(iscsi_create_conn); - -/** - * iscsi_destroy_conn - destroy iscsi class connection - * @conn: iscsi cls session - * - * This can be called from a LLD or iscsi_transport. - */ -int iscsi_destroy_conn(struct iscsi_cls_conn *conn) -{ - unsigned long flags; - - spin_lock_irqsave(&connlock, flags); - list_del(&conn->conn_list); - spin_unlock_irqrestore(&connlock, flags); - - transport_unregister_device(&conn->dev); - ISCSI_DBG_TRANS_CONN(conn, "Completing conn destruction\n"); - device_unregister(&conn->dev); - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_destroy_conn); - -/* - * iscsi interface functions - */ -static struct iscsi_internal * -iscsi_if_transport_lookup(struct iscsi_transport *tt) -{ - struct iscsi_internal *priv; - unsigned long flags; - - spin_lock_irqsave(&iscsi_transport_lock, flags); - list_for_each_entry(priv, &iscsi_transports, list) { - if (tt == priv->iscsi_transport) { - spin_unlock_irqrestore(&iscsi_transport_lock, flags); - return priv; - } - } - spin_unlock_irqrestore(&iscsi_transport_lock, flags); - return NULL; -} - -static int -iscsi_multicast_skb(struct sk_buff *skb, uint32_t group, gfp_t gfp) -{ - return nlmsg_multicast(nls, skb, 0, group, gfp); -} - -int iscsi_recv_pdu(struct iscsi_cls_conn *conn, struct iscsi_hdr *hdr, - char *data, uint32_t data_size) -{ - struct nlmsghdr *nlh; - struct sk_buff *skb; - struct iscsi_uevent *ev; - char *pdu; - struct iscsi_internal *priv; - int len = NLMSG_SPACE(sizeof(*ev) + sizeof(struct iscsi_hdr) + - data_size); - - priv = iscsi_if_transport_lookup(conn->transport); - if (!priv) - return -EINVAL; - - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - iscsi_conn_error_event(conn, ISCSI_ERR_CONN_FAILED); - iscsi_cls_conn_printk(KERN_ERR, conn, "can not deliver " - "control PDU: OOM\n"); - return -ENOMEM; - } - - nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); - ev = NLMSG_DATA(nlh); - memset(ev, 0, sizeof(*ev)); - ev->transport_handle = iscsi_handle(conn->transport); - ev->type = ISCSI_KEVENT_RECV_PDU; - ev->r.recv_req.cid = conn->cid; - ev->r.recv_req.sid = iscsi_conn_get_sid(conn); - pdu = (char*)ev + sizeof(*ev); - memcpy(pdu, hdr, sizeof(struct iscsi_hdr)); - memcpy(pdu + sizeof(struct iscsi_hdr), data, data_size); - - return iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC); -} -EXPORT_SYMBOL_GPL(iscsi_recv_pdu); - -int iscsi_offload_mesg(struct Scsi_Host *shost, - struct iscsi_transport *transport, uint32_t type, - char *data, uint16_t data_size) -{ - struct nlmsghdr *nlh; - struct sk_buff *skb; - struct iscsi_uevent *ev; - int len = NLMSG_SPACE(sizeof(*ev) + data_size); - - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "can not deliver iscsi offload message:OOM\n"); - return -ENOMEM; - } - - nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); - ev = NLMSG_DATA(nlh); - memset(ev, 0, sizeof(*ev)); - ev->type = type; - ev->transport_handle = iscsi_handle(transport); - switch (type) { - case ISCSI_KEVENT_PATH_REQ: - ev->r.req_path.host_no = shost->host_no; - break; - case ISCSI_KEVENT_IF_DOWN: - ev->r.notify_if_down.host_no = shost->host_no; - break; - } - - memcpy((char *)ev + sizeof(*ev), data, data_size); - - return iscsi_multicast_skb(skb, ISCSI_NL_GRP_UIP, GFP_ATOMIC); -} -EXPORT_SYMBOL_GPL(iscsi_offload_mesg); - -void iscsi_conn_error_event(struct iscsi_cls_conn *conn, enum iscsi_err error) -{ - struct nlmsghdr *nlh; - struct sk_buff *skb; - struct iscsi_uevent *ev; - struct iscsi_internal *priv; - int len = NLMSG_SPACE(sizeof(*ev)); - - priv = iscsi_if_transport_lookup(conn->transport); - if (!priv) - return; - - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " - "conn error (%d)\n", error); - return; - } - - nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); - ev = NLMSG_DATA(nlh); - ev->transport_handle = iscsi_handle(conn->transport); - ev->type = ISCSI_KEVENT_CONN_ERROR; - ev->r.connerror.error = error; - ev->r.connerror.cid = conn->cid; - ev->r.connerror.sid = iscsi_conn_get_sid(conn); - - iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC); - - iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn error (%d)\n", - error); -} -EXPORT_SYMBOL_GPL(iscsi_conn_error_event); - -void iscsi_conn_login_event(struct iscsi_cls_conn *conn, - enum iscsi_conn_state state) -{ - struct nlmsghdr *nlh; - struct sk_buff *skb; - struct iscsi_uevent *ev; - struct iscsi_internal *priv; - int len = NLMSG_SPACE(sizeof(*ev)); - - priv = iscsi_if_transport_lookup(conn->transport); - if (!priv) - return; - - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - iscsi_cls_conn_printk(KERN_ERR, conn, "gracefully ignored " - "conn login (%d)\n", state); - return; - } - - nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); - ev = NLMSG_DATA(nlh); - ev->transport_handle = iscsi_handle(conn->transport); - ev->type = ISCSI_KEVENT_CONN_LOGIN_STATE; - ev->r.conn_login.state = state; - ev->r.conn_login.cid = conn->cid; - ev->r.conn_login.sid = iscsi_conn_get_sid(conn); - iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_ATOMIC); - - iscsi_cls_conn_printk(KERN_INFO, conn, "detected conn login (%d)\n", - state); -} -EXPORT_SYMBOL_GPL(iscsi_conn_login_event); - -void iscsi_post_host_event(uint32_t host_no, struct iscsi_transport *transport, - enum iscsi_host_event_code code, uint32_t data_size, - uint8_t *data) -{ - struct nlmsghdr *nlh; - struct sk_buff *skb; - struct iscsi_uevent *ev; - int len = NLMSG_SPACE(sizeof(*ev) + data_size); - - skb = alloc_skb(len, GFP_NOIO); - if (!skb) { - printk(KERN_ERR "gracefully ignored host event (%d):%d OOM\n", - host_no, code); - return; - } - - nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); - ev = NLMSG_DATA(nlh); - ev->transport_handle = iscsi_handle(transport); - ev->type = ISCSI_KEVENT_HOST_EVENT; - ev->r.host_event.host_no = host_no; - ev->r.host_event.code = code; - ev->r.host_event.data_size = data_size; - - if (data_size) - memcpy((char *)ev + sizeof(*ev), data, data_size); - - iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO); -} -EXPORT_SYMBOL_GPL(iscsi_post_host_event); - -void iscsi_ping_comp_event(uint32_t host_no, struct iscsi_transport *transport, - uint32_t status, uint32_t pid, uint32_t data_size, - uint8_t *data) -{ - struct nlmsghdr *nlh; - struct sk_buff *skb; - struct iscsi_uevent *ev; - int len = NLMSG_SPACE(sizeof(*ev) + data_size); - - skb = alloc_skb(len, GFP_NOIO); - if (!skb) { - printk(KERN_ERR "gracefully ignored ping comp: OOM\n"); - return; - } - - nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); - ev = NLMSG_DATA(nlh); - ev->transport_handle = iscsi_handle(transport); - ev->type = ISCSI_KEVENT_PING_COMP; - ev->r.ping_comp.host_no = host_no; - ev->r.ping_comp.status = status; - ev->r.ping_comp.pid = pid; - ev->r.ping_comp.data_size = data_size; - memcpy((char *)ev + sizeof(*ev), data, data_size); - - iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_NOIO); -} -EXPORT_SYMBOL_GPL(iscsi_ping_comp_event); - -static int -iscsi_if_send_reply(uint32_t group, int seq, int type, int done, int multi, - void *payload, int size) -{ - struct sk_buff *skb; - struct nlmsghdr *nlh; - int len = NLMSG_SPACE(size); - int flags = multi ? NLM_F_MULTI : 0; - int t = done ? NLMSG_DONE : type; - - skb = alloc_skb(len, GFP_ATOMIC); - if (!skb) { - printk(KERN_ERR "Could not allocate skb to send reply.\n"); - return -ENOMEM; - } - - nlh = __nlmsg_put(skb, 0, 0, t, (len - sizeof(*nlh)), 0); - nlh->nlmsg_flags = flags; - memcpy(NLMSG_DATA(nlh), payload, size); - return iscsi_multicast_skb(skb, group, GFP_ATOMIC); -} - -static int -iscsi_if_get_stats(struct iscsi_transport *transport, struct nlmsghdr *nlh) -{ - struct iscsi_uevent *ev = NLMSG_DATA(nlh); - struct iscsi_stats *stats; - struct sk_buff *skbstat; - struct iscsi_cls_conn *conn; - struct nlmsghdr *nlhstat; - struct iscsi_uevent *evstat; - struct iscsi_internal *priv; - int len = NLMSG_SPACE(sizeof(*ev) + - sizeof(struct iscsi_stats) + - sizeof(struct iscsi_stats_custom) * - ISCSI_STATS_CUSTOM_MAX); - int err = 0; - - priv = iscsi_if_transport_lookup(transport); - if (!priv) - return -EINVAL; - - conn = iscsi_conn_lookup(ev->u.get_stats.sid, ev->u.get_stats.cid); - if (!conn) - return -EEXIST; - - do { - int actual_size; - - skbstat = alloc_skb(len, GFP_ATOMIC); - if (!skbstat) { - iscsi_cls_conn_printk(KERN_ERR, conn, "can not " - "deliver stats: OOM\n"); - return -ENOMEM; - } - - nlhstat = __nlmsg_put(skbstat, 0, 0, 0, - (len - sizeof(*nlhstat)), 0); - evstat = NLMSG_DATA(nlhstat); - memset(evstat, 0, sizeof(*evstat)); - evstat->transport_handle = iscsi_handle(conn->transport); - evstat->type = nlh->nlmsg_type; - evstat->u.get_stats.cid = - ev->u.get_stats.cid; - evstat->u.get_stats.sid = - ev->u.get_stats.sid; - stats = (struct iscsi_stats *) - ((char*)evstat + sizeof(*evstat)); - memset(stats, 0, sizeof(*stats)); - - transport->get_stats(conn, stats); - actual_size = NLMSG_SPACE(sizeof(struct iscsi_uevent) + - sizeof(struct iscsi_stats) + - sizeof(struct iscsi_stats_custom) * - stats->custom_length); - actual_size -= sizeof(*nlhstat); - actual_size = NLMSG_LENGTH(actual_size); - skb_trim(skbstat, NLMSG_ALIGN(actual_size)); - nlhstat->nlmsg_len = actual_size; - - err = iscsi_multicast_skb(skbstat, ISCSI_NL_GRP_ISCSID, - GFP_ATOMIC); - } while (err < 0 && err != -ECONNREFUSED); - - return err; -} - -/** - * iscsi_session_event - send session destr. completion event - * @session: iscsi class session - * @event: type of event - */ -int iscsi_session_event(struct iscsi_cls_session *session, - enum iscsi_uevent_e event) -{ - struct iscsi_internal *priv; - struct Scsi_Host *shost; - struct iscsi_uevent *ev; - struct sk_buff *skb; - struct nlmsghdr *nlh; - int rc, len = NLMSG_SPACE(sizeof(*ev)); - - priv = iscsi_if_transport_lookup(session->transport); - if (!priv) - return -EINVAL; - shost = iscsi_session_to_shost(session); - - skb = alloc_skb(len, GFP_KERNEL); - if (!skb) { - iscsi_cls_session_printk(KERN_ERR, session, - "Cannot notify userspace of session " - "event %u\n", event); - return -ENOMEM; - } - - nlh = __nlmsg_put(skb, 0, 0, 0, (len - sizeof(*nlh)), 0); - ev = NLMSG_DATA(nlh); - ev->transport_handle = iscsi_handle(session->transport); - - ev->type = event; - switch (event) { - case ISCSI_KEVENT_DESTROY_SESSION: - ev->r.d_session.host_no = shost->host_no; - ev->r.d_session.sid = session->sid; - break; - case ISCSI_KEVENT_CREATE_SESSION: - ev->r.c_session_ret.host_no = shost->host_no; - ev->r.c_session_ret.sid = session->sid; - break; - case ISCSI_KEVENT_UNBIND_SESSION: - ev->r.unbind_session.host_no = shost->host_no; - ev->r.unbind_session.sid = session->sid; - break; - default: - iscsi_cls_session_printk(KERN_ERR, session, "Invalid event " - "%u.\n", event); - kfree_skb(skb); - return -EINVAL; - } - - /* - * this will occur if the daemon is not up, so we just warn - * the user and when the daemon is restarted it will handle it - */ - rc = iscsi_multicast_skb(skb, ISCSI_NL_GRP_ISCSID, GFP_KERNEL); - if (rc == -ESRCH) - iscsi_cls_session_printk(KERN_ERR, session, - "Cannot notify userspace of session " - "event %u. Check iscsi daemon\n", - event); - - ISCSI_DBG_TRANS_SESSION(session, "Completed handling event %d rc %d\n", - event, rc); - return rc; -} -EXPORT_SYMBOL_GPL(iscsi_session_event); - -static int -iscsi_if_create_session(struct iscsi_internal *priv, struct iscsi_endpoint *ep, - struct iscsi_uevent *ev, pid_t pid, - uint32_t initial_cmdsn, uint16_t cmds_max, - uint16_t queue_depth) -{ - struct iscsi_transport *transport = priv->iscsi_transport; - struct iscsi_cls_session *session; - struct Scsi_Host *shost; - - session = transport->create_session(ep, cmds_max, queue_depth, - initial_cmdsn); - if (!session) - return -ENOMEM; - - session->creator = pid; - shost = iscsi_session_to_shost(session); - ev->r.c_session_ret.host_no = shost->host_no; - ev->r.c_session_ret.sid = session->sid; - ISCSI_DBG_TRANS_SESSION(session, - "Completed creating transport session\n"); - return 0; -} - -static int -iscsi_if_create_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) -{ - struct iscsi_cls_conn *conn; - struct iscsi_cls_session *session; - - session = iscsi_session_lookup(ev->u.c_conn.sid); - if (!session) { - printk(KERN_ERR "iscsi: invalid session %d.\n", - ev->u.c_conn.sid); - return -EINVAL; - } - - conn = transport->create_conn(session, ev->u.c_conn.cid); - if (!conn) { - iscsi_cls_session_printk(KERN_ERR, session, - "couldn't create a new connection."); - return -ENOMEM; - } - - ev->r.c_conn_ret.sid = session->sid; - ev->r.c_conn_ret.cid = conn->cid; - - ISCSI_DBG_TRANS_CONN(conn, "Completed creating transport conn\n"); - return 0; -} - -static int -iscsi_if_destroy_conn(struct iscsi_transport *transport, struct iscsi_uevent *ev) -{ - struct iscsi_cls_conn *conn; - - conn = iscsi_conn_lookup(ev->u.d_conn.sid, ev->u.d_conn.cid); - if (!conn) - return -EINVAL; - - ISCSI_DBG_TRANS_CONN(conn, "Destroying transport conn\n"); - if (transport->destroy_conn) - transport->destroy_conn(conn); - - return 0; -} - -static int -iscsi_set_param(struct iscsi_transport *transport, struct iscsi_uevent *ev) -{ - char *data = (char*)ev + sizeof(*ev); - struct iscsi_cls_conn *conn; - struct iscsi_cls_session *session; - int err = 0, value = 0; - - session = iscsi_session_lookup(ev->u.set_param.sid); - conn = iscsi_conn_lookup(ev->u.set_param.sid, ev->u.set_param.cid); - if (!conn || !session) - return -EINVAL; - - switch (ev->u.set_param.param) { - case ISCSI_PARAM_SESS_RECOVERY_TMO: - sscanf(data, "%d", &value); - session->recovery_tmo = value; - break; - default: - err = transport->set_param(conn, ev->u.set_param.param, - data, ev->u.set_param.len); - } - - return err; -} - -static int iscsi_if_ep_connect(struct iscsi_transport *transport, - struct iscsi_uevent *ev, int msg_type) -{ - struct iscsi_endpoint *ep; - struct sockaddr *dst_addr; - struct Scsi_Host *shost = NULL; - int non_blocking, err = 0; - - if (!transport->ep_connect) - return -EINVAL; - - if (msg_type == ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST) { - shost = scsi_host_lookup(ev->u.ep_connect_through_host.host_no); - if (!shost) { - printk(KERN_ERR "ep connect failed. Could not find " - "host no %u\n", - ev->u.ep_connect_through_host.host_no); - return -ENODEV; - } - non_blocking = ev->u.ep_connect_through_host.non_blocking; - } else - non_blocking = ev->u.ep_connect.non_blocking; - - dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); - ep = transport->ep_connect(shost, dst_addr, non_blocking); - if (IS_ERR(ep)) { - err = PTR_ERR(ep); - goto release_host; - } - - ev->r.ep_connect_ret.handle = ep->id; -release_host: - if (shost) - scsi_host_put(shost); - return err; -} - -static int iscsi_if_ep_disconnect(struct iscsi_transport *transport, - u64 ep_handle) -{ - struct iscsi_cls_conn *conn; - struct iscsi_endpoint *ep; - - if (!transport->ep_disconnect) - return -EINVAL; - - ep = iscsi_lookup_endpoint(ep_handle); - if (!ep) - return -EINVAL; - conn = ep->conn; - if (conn) { - mutex_lock(&conn->ep_mutex); - conn->ep = NULL; - mutex_unlock(&conn->ep_mutex); - } - - transport->ep_disconnect(ep); - return 0; -} - -static int -iscsi_if_transport_ep(struct iscsi_transport *transport, - struct iscsi_uevent *ev, int msg_type) -{ - struct iscsi_endpoint *ep; - int rc = 0; - - switch (msg_type) { - case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: - case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: - rc = iscsi_if_ep_connect(transport, ev, msg_type); - break; - case ISCSI_UEVENT_TRANSPORT_EP_POLL: - if (!transport->ep_poll) - return -EINVAL; - - ep = iscsi_lookup_endpoint(ev->u.ep_poll.ep_handle); - if (!ep) - return -EINVAL; - - ev->r.retcode = transport->ep_poll(ep, - ev->u.ep_poll.timeout_ms); - break; - case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: - rc = iscsi_if_ep_disconnect(transport, - ev->u.ep_disconnect.ep_handle); - break; - } - return rc; -} - -static int -iscsi_tgt_dscvr(struct iscsi_transport *transport, - struct iscsi_uevent *ev) -{ - struct Scsi_Host *shost; - struct sockaddr *dst_addr; - int err; - - if (!transport->tgt_dscvr) - return -EINVAL; - - shost = scsi_host_lookup(ev->u.tgt_dscvr.host_no); - if (!shost) { - printk(KERN_ERR "target discovery could not find host no %u\n", - ev->u.tgt_dscvr.host_no); - return -ENODEV; - } - - - dst_addr = (struct sockaddr *)((char*)ev + sizeof(*ev)); - err = transport->tgt_dscvr(shost, ev->u.tgt_dscvr.type, - ev->u.tgt_dscvr.enable, dst_addr); - scsi_host_put(shost); - return err; -} - -static int -iscsi_set_host_param(struct iscsi_transport *transport, - struct iscsi_uevent *ev) -{ - char *data = (char*)ev + sizeof(*ev); - struct Scsi_Host *shost; - int err; - - if (!transport->set_host_param) - return -ENOSYS; - - shost = scsi_host_lookup(ev->u.set_host_param.host_no); - if (!shost) { - printk(KERN_ERR "set_host_param could not find host no %u\n", - ev->u.set_host_param.host_no); - return -ENODEV; - } - - err = transport->set_host_param(shost, ev->u.set_host_param.param, - data, ev->u.set_host_param.len); - scsi_host_put(shost); - return err; -} - -static int -iscsi_set_path(struct iscsi_transport *transport, struct iscsi_uevent *ev) -{ - struct Scsi_Host *shost; - struct iscsi_path *params; - int err; - - if (!transport->set_path) - return -ENOSYS; - - shost = scsi_host_lookup(ev->u.set_path.host_no); - if (!shost) { - printk(KERN_ERR "set path could not find host no %u\n", - ev->u.set_path.host_no); - return -ENODEV; - } - - params = (struct iscsi_path *)((char *)ev + sizeof(*ev)); - err = transport->set_path(shost, params); - - scsi_host_put(shost); - return err; -} - -static int -iscsi_set_iface_params(struct iscsi_transport *transport, - struct iscsi_uevent *ev, uint32_t len) -{ - char *data = (char *)ev + sizeof(*ev); - struct Scsi_Host *shost; - int err; - - if (!transport->set_iface_param) - return -ENOSYS; - - shost = scsi_host_lookup(ev->u.set_iface_params.host_no); - if (!shost) { - printk(KERN_ERR "set_iface_params could not find host no %u\n", - ev->u.set_iface_params.host_no); - return -ENODEV; - } - - err = transport->set_iface_param(shost, data, len); - scsi_host_put(shost); - return err; -} - -static int -iscsi_send_ping(struct iscsi_transport *transport, struct iscsi_uevent *ev) -{ - struct Scsi_Host *shost; - struct sockaddr *dst_addr; - int err; - - if (!transport->send_ping) - return -ENOSYS; - - shost = scsi_host_lookup(ev->u.iscsi_ping.host_no); - if (!shost) { - printk(KERN_ERR "iscsi_ping could not find host no %u\n", - ev->u.iscsi_ping.host_no); - return -ENODEV; - } - - dst_addr = (struct sockaddr *)((char *)ev + sizeof(*ev)); - err = transport->send_ping(shost, ev->u.iscsi_ping.iface_num, - ev->u.iscsi_ping.iface_type, - ev->u.iscsi_ping.payload_size, - ev->u.iscsi_ping.pid, - dst_addr); - scsi_host_put(shost); - return err; -} - -static int -iscsi_get_chap(struct iscsi_transport *transport, struct nlmsghdr *nlh) -{ - struct iscsi_uevent *ev = NLMSG_DATA(nlh); - struct Scsi_Host *shost = NULL; - struct iscsi_chap_rec *chap_rec; - struct iscsi_internal *priv; - struct sk_buff *skbchap; - struct nlmsghdr *nlhchap; - struct iscsi_uevent *evchap; - uint32_t chap_buf_size; - int len, err = 0; - char *buf; - - if (!transport->get_chap) - return -EINVAL; - - priv = iscsi_if_transport_lookup(transport); - if (!priv) - return -EINVAL; - - chap_buf_size = (ev->u.get_chap.num_entries * sizeof(*chap_rec)); - len = NLMSG_SPACE(sizeof(*ev) + chap_buf_size); - - shost = scsi_host_lookup(ev->u.get_chap.host_no); - if (!shost) { - printk(KERN_ERR "%s: failed. Cound not find host no %u\n", - __func__, ev->u.get_chap.host_no); - return -ENODEV; - } - - do { - int actual_size; - - skbchap = alloc_skb(len, GFP_KERNEL); - if (!skbchap) { - printk(KERN_ERR "can not deliver chap: OOM\n"); - err = -ENOMEM; - goto exit_get_chap; - } - - nlhchap = __nlmsg_put(skbchap, 0, 0, 0, - (len - sizeof(*nlhchap)), 0); - evchap = NLMSG_DATA(nlhchap); - memset(evchap, 0, sizeof(*evchap)); - evchap->transport_handle = iscsi_handle(transport); - evchap->type = nlh->nlmsg_type; - evchap->u.get_chap.host_no = ev->u.get_chap.host_no; - evchap->u.get_chap.chap_tbl_idx = ev->u.get_chap.chap_tbl_idx; - evchap->u.get_chap.num_entries = ev->u.get_chap.num_entries; - buf = (char *) ((char *)evchap + sizeof(*evchap)); - memset(buf, 0, chap_buf_size); - - err = transport->get_chap(shost, ev->u.get_chap.chap_tbl_idx, - &evchap->u.get_chap.num_entries, buf); - - actual_size = NLMSG_SPACE(sizeof(*ev) + chap_buf_size); - skb_trim(skbchap, NLMSG_ALIGN(actual_size)); - nlhchap->nlmsg_len = actual_size; - - err = iscsi_multicast_skb(skbchap, ISCSI_NL_GRP_ISCSID, - GFP_KERNEL); - } while (err < 0 && err != -ECONNREFUSED); - -exit_get_chap: - scsi_host_put(shost); - return err; -} - -static int iscsi_delete_chap(struct iscsi_transport *transport, - struct iscsi_uevent *ev) -{ - struct Scsi_Host *shost; - int err = 0; - - if (!transport->delete_chap) - return -ENOSYS; - - shost = scsi_host_lookup(ev->u.delete_chap.host_no); - if (!shost) { - printk(KERN_ERR "%s could not find host no %u\n", - __func__, ev->u.delete_chap.host_no); - return -ENODEV; - } - - err = transport->delete_chap(shost, ev->u.delete_chap.chap_tbl_idx); - scsi_host_put(shost); - return err; -} - -static int -iscsi_if_recv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, uint32_t *group) -{ - int err = 0; - struct iscsi_uevent *ev = NLMSG_DATA(nlh); - struct iscsi_transport *transport = NULL; - struct iscsi_internal *priv; - struct iscsi_cls_session *session; - struct iscsi_cls_conn *conn; - struct iscsi_endpoint *ep = NULL; - - if (nlh->nlmsg_type == ISCSI_UEVENT_PATH_UPDATE) - *group = ISCSI_NL_GRP_UIP; - else - *group = ISCSI_NL_GRP_ISCSID; - - priv = iscsi_if_transport_lookup(iscsi_ptr(ev->transport_handle)); - if (!priv) - return -EINVAL; - transport = priv->iscsi_transport; - - if (!try_module_get(transport->owner)) - return -EINVAL; - - switch (nlh->nlmsg_type) { - case ISCSI_UEVENT_CREATE_SESSION: - err = iscsi_if_create_session(priv, ep, ev, - NETLINK_CB(skb).pid, - ev->u.c_session.initial_cmdsn, - ev->u.c_session.cmds_max, - ev->u.c_session.queue_depth); - break; - case ISCSI_UEVENT_CREATE_BOUND_SESSION: - ep = iscsi_lookup_endpoint(ev->u.c_bound_session.ep_handle); - if (!ep) { - err = -EINVAL; - break; - } - - err = iscsi_if_create_session(priv, ep, ev, - NETLINK_CB(skb).pid, - ev->u.c_bound_session.initial_cmdsn, - ev->u.c_bound_session.cmds_max, - ev->u.c_bound_session.queue_depth); - break; - case ISCSI_UEVENT_DESTROY_SESSION: - session = iscsi_session_lookup(ev->u.d_session.sid); - if (session) - transport->destroy_session(session); - else - err = -EINVAL; - break; - case ISCSI_UEVENT_UNBIND_SESSION: - session = iscsi_session_lookup(ev->u.d_session.sid); - if (session) - scsi_queue_work(iscsi_session_to_shost(session), - &session->unbind_work); - else - err = -EINVAL; - break; - case ISCSI_UEVENT_CREATE_CONN: - err = iscsi_if_create_conn(transport, ev); - break; - case ISCSI_UEVENT_DESTROY_CONN: - err = iscsi_if_destroy_conn(transport, ev); - break; - case ISCSI_UEVENT_BIND_CONN: - session = iscsi_session_lookup(ev->u.b_conn.sid); - conn = iscsi_conn_lookup(ev->u.b_conn.sid, ev->u.b_conn.cid); - - if (conn && conn->ep) - iscsi_if_ep_disconnect(transport, conn->ep->id); - - if (!session || !conn) { - err = -EINVAL; - break; - } - - ev->r.retcode = transport->bind_conn(session, conn, - ev->u.b_conn.transport_eph, - ev->u.b_conn.is_leading); - if (ev->r.retcode || !transport->ep_connect) - break; - - ep = iscsi_lookup_endpoint(ev->u.b_conn.transport_eph); - if (ep) { - ep->conn = conn; - - mutex_lock(&conn->ep_mutex); - conn->ep = ep; - mutex_unlock(&conn->ep_mutex); - } else - iscsi_cls_conn_printk(KERN_ERR, conn, - "Could not set ep conn " - "binding\n"); - break; - case ISCSI_UEVENT_SET_PARAM: - err = iscsi_set_param(transport, ev); - break; - case ISCSI_UEVENT_START_CONN: - conn = iscsi_conn_lookup(ev->u.start_conn.sid, ev->u.start_conn.cid); - if (conn) - ev->r.retcode = transport->start_conn(conn); - else - err = -EINVAL; - break; - case ISCSI_UEVENT_STOP_CONN: - conn = iscsi_conn_lookup(ev->u.stop_conn.sid, ev->u.stop_conn.cid); - if (conn) - transport->stop_conn(conn, ev->u.stop_conn.flag); - else - err = -EINVAL; - break; - case ISCSI_UEVENT_SEND_PDU: - conn = iscsi_conn_lookup(ev->u.send_pdu.sid, ev->u.send_pdu.cid); - if (conn) - ev->r.retcode = transport->send_pdu(conn, - (struct iscsi_hdr*)((char*)ev + sizeof(*ev)), - (char*)ev + sizeof(*ev) + ev->u.send_pdu.hdr_size, - ev->u.send_pdu.data_size); - else - err = -EINVAL; - break; - case ISCSI_UEVENT_GET_STATS: - err = iscsi_if_get_stats(transport, nlh); - break; - case ISCSI_UEVENT_TRANSPORT_EP_CONNECT: - case ISCSI_UEVENT_TRANSPORT_EP_POLL: - case ISCSI_UEVENT_TRANSPORT_EP_DISCONNECT: - case ISCSI_UEVENT_TRANSPORT_EP_CONNECT_THROUGH_HOST: - err = iscsi_if_transport_ep(transport, ev, nlh->nlmsg_type); - break; - case ISCSI_UEVENT_TGT_DSCVR: - err = iscsi_tgt_dscvr(transport, ev); - break; - case ISCSI_UEVENT_SET_HOST_PARAM: - err = iscsi_set_host_param(transport, ev); - break; - case ISCSI_UEVENT_PATH_UPDATE: - err = iscsi_set_path(transport, ev); - break; - case ISCSI_UEVENT_SET_IFACE_PARAMS: - err = iscsi_set_iface_params(transport, ev, - nlmsg_attrlen(nlh, sizeof(*ev))); - break; - case ISCSI_UEVENT_PING: - err = iscsi_send_ping(transport, ev); - break; - case ISCSI_UEVENT_GET_CHAP: - err = iscsi_get_chap(transport, nlh); - break; - case ISCSI_UEVENT_DELETE_CHAP: - err = iscsi_delete_chap(transport, ev); - break; - default: - err = -ENOSYS; - break; - } - - module_put(transport->owner); - return err; -} - -/* - * Get message from skb. Each message is processed by iscsi_if_recv_msg. - * Malformed skbs with wrong lengths or invalid creds are not processed. - */ -static void -iscsi_if_rx(struct sk_buff *skb) -{ - mutex_lock(&rx_queue_mutex); - while (skb->len >= NLMSG_SPACE(0)) { - int err; - uint32_t rlen; - struct nlmsghdr *nlh; - struct iscsi_uevent *ev; - uint32_t group; - - nlh = nlmsg_hdr(skb); - if (nlh->nlmsg_len < sizeof(*nlh) || - skb->len < nlh->nlmsg_len) { - break; - } - - ev = NLMSG_DATA(nlh); - rlen = NLMSG_ALIGN(nlh->nlmsg_len); - if (rlen > skb->len) - rlen = skb->len; - - err = iscsi_if_recv_msg(skb, nlh, &group); - if (err) { - ev->type = ISCSI_KEVENT_IF_ERROR; - ev->iferror = err; - } - do { - /* - * special case for GET_STATS: - * on success - sending reply and stats from - * inside of if_recv_msg(), - * on error - fall through. - */ - if (ev->type == ISCSI_UEVENT_GET_STATS && !err) - break; - if (ev->type == ISCSI_UEVENT_GET_CHAP && !err) - break; - err = iscsi_if_send_reply(group, nlh->nlmsg_seq, - nlh->nlmsg_type, 0, 0, ev, sizeof(*ev)); - } while (err < 0 && err != -ECONNREFUSED && err != -ESRCH); - skb_pull(skb, rlen); - } - mutex_unlock(&rx_queue_mutex); -} - -#define ISCSI_CLASS_ATTR(_prefix,_name,_mode,_show,_store) \ -struct device_attribute dev_attr_##_prefix##_##_name = \ - __ATTR(_name,_mode,_show,_store) - -/* - * iSCSI connection attrs - */ -#define iscsi_conn_attr_show(param) \ -static ssize_t \ -show_conn_param_##param(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \ - struct iscsi_transport *t = conn->transport; \ - return t->get_conn_param(conn, param, buf); \ -} - -#define iscsi_conn_attr(field, param) \ - iscsi_conn_attr_show(param) \ -static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, show_conn_param_##param, \ - NULL); - -iscsi_conn_attr(max_recv_dlength, ISCSI_PARAM_MAX_RECV_DLENGTH); -iscsi_conn_attr(max_xmit_dlength, ISCSI_PARAM_MAX_XMIT_DLENGTH); -iscsi_conn_attr(header_digest, ISCSI_PARAM_HDRDGST_EN); -iscsi_conn_attr(data_digest, ISCSI_PARAM_DATADGST_EN); -iscsi_conn_attr(ifmarker, ISCSI_PARAM_IFMARKER_EN); -iscsi_conn_attr(ofmarker, ISCSI_PARAM_OFMARKER_EN); -iscsi_conn_attr(persistent_port, ISCSI_PARAM_PERSISTENT_PORT); -iscsi_conn_attr(exp_statsn, ISCSI_PARAM_EXP_STATSN); -iscsi_conn_attr(persistent_address, ISCSI_PARAM_PERSISTENT_ADDRESS); -iscsi_conn_attr(ping_tmo, ISCSI_PARAM_PING_TMO); -iscsi_conn_attr(recv_tmo, ISCSI_PARAM_RECV_TMO); - -#define iscsi_conn_ep_attr_show(param) \ -static ssize_t show_conn_ep_param_##param(struct device *dev, \ - struct device_attribute *attr,\ - char *buf) \ -{ \ - struct iscsi_cls_conn *conn = iscsi_dev_to_conn(dev->parent); \ - struct iscsi_transport *t = conn->transport; \ - struct iscsi_endpoint *ep; \ - ssize_t rc; \ - \ - /* \ - * Need to make sure ep_disconnect does not free the LLD's \ - * interconnect resources while we are trying to read them. \ - */ \ - mutex_lock(&conn->ep_mutex); \ - ep = conn->ep; \ - if (!ep && t->ep_connect) { \ - mutex_unlock(&conn->ep_mutex); \ - return -ENOTCONN; \ - } \ - \ - if (ep) \ - rc = t->get_ep_param(ep, param, buf); \ - else \ - rc = t->get_conn_param(conn, param, buf); \ - mutex_unlock(&conn->ep_mutex); \ - return rc; \ -} - -#define iscsi_conn_ep_attr(field, param) \ - iscsi_conn_ep_attr_show(param) \ -static ISCSI_CLASS_ATTR(conn, field, S_IRUGO, \ - show_conn_ep_param_##param, NULL); - -iscsi_conn_ep_attr(address, ISCSI_PARAM_CONN_ADDRESS); -iscsi_conn_ep_attr(port, ISCSI_PARAM_CONN_PORT); - -static struct attribute *iscsi_conn_attrs[] = { - &dev_attr_conn_max_recv_dlength.attr, - &dev_attr_conn_max_xmit_dlength.attr, - &dev_attr_conn_header_digest.attr, - &dev_attr_conn_data_digest.attr, - &dev_attr_conn_ifmarker.attr, - &dev_attr_conn_ofmarker.attr, - &dev_attr_conn_address.attr, - &dev_attr_conn_port.attr, - &dev_attr_conn_exp_statsn.attr, - &dev_attr_conn_persistent_address.attr, - &dev_attr_conn_persistent_port.attr, - &dev_attr_conn_ping_tmo.attr, - &dev_attr_conn_recv_tmo.attr, - NULL, -}; - -static umode_t iscsi_conn_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) -{ - struct device *cdev = container_of(kobj, struct device, kobj); - struct iscsi_cls_conn *conn = transport_class_to_conn(cdev); - struct iscsi_transport *t = conn->transport; - int param; - - if (attr == &dev_attr_conn_max_recv_dlength.attr) - param = ISCSI_PARAM_MAX_RECV_DLENGTH; - else if (attr == &dev_attr_conn_max_xmit_dlength.attr) - param = ISCSI_PARAM_MAX_XMIT_DLENGTH; - else if (attr == &dev_attr_conn_header_digest.attr) - param = ISCSI_PARAM_HDRDGST_EN; - else if (attr == &dev_attr_conn_data_digest.attr) - param = ISCSI_PARAM_DATADGST_EN; - else if (attr == &dev_attr_conn_ifmarker.attr) - param = ISCSI_PARAM_IFMARKER_EN; - else if (attr == &dev_attr_conn_ofmarker.attr) - param = ISCSI_PARAM_OFMARKER_EN; - else if (attr == &dev_attr_conn_address.attr) - param = ISCSI_PARAM_CONN_ADDRESS; - else if (attr == &dev_attr_conn_port.attr) - param = ISCSI_PARAM_CONN_PORT; - else if (attr == &dev_attr_conn_exp_statsn.attr) - param = ISCSI_PARAM_EXP_STATSN; - else if (attr == &dev_attr_conn_persistent_address.attr) - param = ISCSI_PARAM_PERSISTENT_ADDRESS; - else if (attr == &dev_attr_conn_persistent_port.attr) - param = ISCSI_PARAM_PERSISTENT_PORT; - else if (attr == &dev_attr_conn_ping_tmo.attr) - param = ISCSI_PARAM_PING_TMO; - else if (attr == &dev_attr_conn_recv_tmo.attr) - param = ISCSI_PARAM_RECV_TMO; - else { - WARN_ONCE(1, "Invalid conn attr"); - return 0; - } - - return t->attr_is_visible(ISCSI_PARAM, param); -} - -static struct attribute_group iscsi_conn_group = { - .attrs = iscsi_conn_attrs, - .is_visible = iscsi_conn_attr_is_visible, -}; - -/* - * iSCSI session attrs - */ -#define iscsi_session_attr_show(param, perm) \ -static ssize_t \ -show_session_param_##param(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct iscsi_cls_session *session = \ - iscsi_dev_to_session(dev->parent); \ - struct iscsi_transport *t = session->transport; \ - \ - if (perm && !capable(CAP_SYS_ADMIN)) \ - return -EACCES; \ - return t->get_session_param(session, param, buf); \ -} - -#define iscsi_session_attr(field, param, perm) \ - iscsi_session_attr_show(param, perm) \ -static ISCSI_CLASS_ATTR(sess, field, S_IRUGO, show_session_param_##param, \ - NULL); -iscsi_session_attr(targetname, ISCSI_PARAM_TARGET_NAME, 0); -iscsi_session_attr(initial_r2t, ISCSI_PARAM_INITIAL_R2T_EN, 0); -iscsi_session_attr(max_outstanding_r2t, ISCSI_PARAM_MAX_R2T, 0); -iscsi_session_attr(immediate_data, ISCSI_PARAM_IMM_DATA_EN, 0); -iscsi_session_attr(first_burst_len, ISCSI_PARAM_FIRST_BURST, 0); -iscsi_session_attr(max_burst_len, ISCSI_PARAM_MAX_BURST, 0); -iscsi_session_attr(data_pdu_in_order, ISCSI_PARAM_PDU_INORDER_EN, 0); -iscsi_session_attr(data_seq_in_order, ISCSI_PARAM_DATASEQ_INORDER_EN, 0); -iscsi_session_attr(erl, ISCSI_PARAM_ERL, 0); -iscsi_session_attr(tpgt, ISCSI_PARAM_TPGT, 0); -iscsi_session_attr(username, ISCSI_PARAM_USERNAME, 1); -iscsi_session_attr(username_in, ISCSI_PARAM_USERNAME_IN, 1); -iscsi_session_attr(password, ISCSI_PARAM_PASSWORD, 1); -iscsi_session_attr(password_in, ISCSI_PARAM_PASSWORD_IN, 1); -iscsi_session_attr(chap_out_idx, ISCSI_PARAM_CHAP_OUT_IDX, 1); -iscsi_session_attr(chap_in_idx, ISCSI_PARAM_CHAP_IN_IDX, 1); -iscsi_session_attr(fast_abort, ISCSI_PARAM_FAST_ABORT, 0); -iscsi_session_attr(abort_tmo, ISCSI_PARAM_ABORT_TMO, 0); -iscsi_session_attr(lu_reset_tmo, ISCSI_PARAM_LU_RESET_TMO, 0); -iscsi_session_attr(tgt_reset_tmo, ISCSI_PARAM_TGT_RESET_TMO, 0); -iscsi_session_attr(ifacename, ISCSI_PARAM_IFACE_NAME, 0); -iscsi_session_attr(initiatorname, ISCSI_PARAM_INITIATOR_NAME, 0); -iscsi_session_attr(targetalias, ISCSI_PARAM_TARGET_ALIAS, 0); - -static ssize_t -show_priv_session_state(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent); - return sprintf(buf, "%s\n", iscsi_session_state_name(session->state)); -} -static ISCSI_CLASS_ATTR(priv_sess, state, S_IRUGO, show_priv_session_state, - NULL); -static ssize_t -show_priv_session_creator(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct iscsi_cls_session *session = iscsi_dev_to_session(dev->parent); - return sprintf(buf, "%d\n", session->creator); -} -static ISCSI_CLASS_ATTR(priv_sess, creator, S_IRUGO, show_priv_session_creator, - NULL); - -#define iscsi_priv_session_attr_show(field, format) \ -static ssize_t \ -show_priv_session_##field(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct iscsi_cls_session *session = \ - iscsi_dev_to_session(dev->parent); \ - if (session->field == -1) \ - return sprintf(buf, "off\n"); \ - return sprintf(buf, format"\n", session->field); \ -} - -#define iscsi_priv_session_attr_store(field) \ -static ssize_t \ -store_priv_session_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int val; \ - char *cp; \ - struct iscsi_cls_session *session = \ - iscsi_dev_to_session(dev->parent); \ - if ((session->state == ISCSI_SESSION_FREE) || \ - (session->state == ISCSI_SESSION_FAILED)) \ - return -EBUSY; \ - if (strncmp(buf, "off", 3) == 0) \ - session->field = -1; \ - else { \ - val = simple_strtoul(buf, &cp, 0); \ - if (*cp != '\0' && *cp != '\n') \ - return -EINVAL; \ - session->field = val; \ - } \ - return count; \ -} - -#define iscsi_priv_session_rw_attr(field, format) \ - iscsi_priv_session_attr_show(field, format) \ - iscsi_priv_session_attr_store(field) \ -static ISCSI_CLASS_ATTR(priv_sess, field, S_IRUGO | S_IWUSR, \ - show_priv_session_##field, \ - store_priv_session_##field) -iscsi_priv_session_rw_attr(recovery_tmo, "%d"); - -static struct attribute *iscsi_session_attrs[] = { - &dev_attr_sess_initial_r2t.attr, - &dev_attr_sess_max_outstanding_r2t.attr, - &dev_attr_sess_immediate_data.attr, - &dev_attr_sess_first_burst_len.attr, - &dev_attr_sess_max_burst_len.attr, - &dev_attr_sess_data_pdu_in_order.attr, - &dev_attr_sess_data_seq_in_order.attr, - &dev_attr_sess_erl.attr, - &dev_attr_sess_targetname.attr, - &dev_attr_sess_tpgt.attr, - &dev_attr_sess_password.attr, - &dev_attr_sess_password_in.attr, - &dev_attr_sess_username.attr, - &dev_attr_sess_username_in.attr, - &dev_attr_sess_fast_abort.attr, - &dev_attr_sess_abort_tmo.attr, - &dev_attr_sess_lu_reset_tmo.attr, - &dev_attr_sess_tgt_reset_tmo.attr, - &dev_attr_sess_ifacename.attr, - &dev_attr_sess_initiatorname.attr, - &dev_attr_sess_targetalias.attr, - &dev_attr_priv_sess_recovery_tmo.attr, - &dev_attr_priv_sess_state.attr, - &dev_attr_priv_sess_creator.attr, - &dev_attr_sess_chap_out_idx.attr, - &dev_attr_sess_chap_in_idx.attr, - NULL, -}; - -static umode_t iscsi_session_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) -{ - struct device *cdev = container_of(kobj, struct device, kobj); - struct iscsi_cls_session *session = transport_class_to_session(cdev); - struct iscsi_transport *t = session->transport; - int param; - - if (attr == &dev_attr_sess_initial_r2t.attr) - param = ISCSI_PARAM_INITIAL_R2T_EN; - else if (attr == &dev_attr_sess_max_outstanding_r2t.attr) - param = ISCSI_PARAM_MAX_R2T; - else if (attr == &dev_attr_sess_immediate_data.attr) - param = ISCSI_PARAM_IMM_DATA_EN; - else if (attr == &dev_attr_sess_first_burst_len.attr) - param = ISCSI_PARAM_FIRST_BURST; - else if (attr == &dev_attr_sess_max_burst_len.attr) - param = ISCSI_PARAM_MAX_BURST; - else if (attr == &dev_attr_sess_data_pdu_in_order.attr) - param = ISCSI_PARAM_PDU_INORDER_EN; - else if (attr == &dev_attr_sess_data_seq_in_order.attr) - param = ISCSI_PARAM_DATASEQ_INORDER_EN; - else if (attr == &dev_attr_sess_erl.attr) - param = ISCSI_PARAM_ERL; - else if (attr == &dev_attr_sess_targetname.attr) - param = ISCSI_PARAM_TARGET_NAME; - else if (attr == &dev_attr_sess_tpgt.attr) - param = ISCSI_PARAM_TPGT; - else if (attr == &dev_attr_sess_chap_in_idx.attr) - param = ISCSI_PARAM_CHAP_IN_IDX; - else if (attr == &dev_attr_sess_chap_out_idx.attr) - param = ISCSI_PARAM_CHAP_OUT_IDX; - else if (attr == &dev_attr_sess_password.attr) - param = ISCSI_PARAM_USERNAME; - else if (attr == &dev_attr_sess_password_in.attr) - param = ISCSI_PARAM_USERNAME_IN; - else if (attr == &dev_attr_sess_username.attr) - param = ISCSI_PARAM_PASSWORD; - else if (attr == &dev_attr_sess_username_in.attr) - param = ISCSI_PARAM_PASSWORD_IN; - else if (attr == &dev_attr_sess_fast_abort.attr) - param = ISCSI_PARAM_FAST_ABORT; - else if (attr == &dev_attr_sess_abort_tmo.attr) - param = ISCSI_PARAM_ABORT_TMO; - else if (attr == &dev_attr_sess_lu_reset_tmo.attr) - param = ISCSI_PARAM_LU_RESET_TMO; - else if (attr == &dev_attr_sess_tgt_reset_tmo.attr) - param = ISCSI_PARAM_TGT_RESET_TMO; - else if (attr == &dev_attr_sess_ifacename.attr) - param = ISCSI_PARAM_IFACE_NAME; - else if (attr == &dev_attr_sess_initiatorname.attr) - param = ISCSI_PARAM_INITIATOR_NAME; - else if (attr == &dev_attr_sess_targetalias.attr) - param = ISCSI_PARAM_TARGET_ALIAS; - else if (attr == &dev_attr_priv_sess_recovery_tmo.attr) - return S_IRUGO | S_IWUSR; - else if (attr == &dev_attr_priv_sess_state.attr) - return S_IRUGO; - else if (attr == &dev_attr_priv_sess_creator.attr) - return S_IRUGO; - else { - WARN_ONCE(1, "Invalid session attr"); - return 0; - } - - return t->attr_is_visible(ISCSI_PARAM, param); -} - -static struct attribute_group iscsi_session_group = { - .attrs = iscsi_session_attrs, - .is_visible = iscsi_session_attr_is_visible, -}; - -/* - * iSCSI host attrs - */ -#define iscsi_host_attr_show(param) \ -static ssize_t \ -show_host_param_##param(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct Scsi_Host *shost = transport_class_to_shost(dev); \ - struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); \ - return priv->iscsi_transport->get_host_param(shost, param, buf); \ -} - -#define iscsi_host_attr(field, param) \ - iscsi_host_attr_show(param) \ -static ISCSI_CLASS_ATTR(host, field, S_IRUGO, show_host_param_##param, \ - NULL); - -iscsi_host_attr(netdev, ISCSI_HOST_PARAM_NETDEV_NAME); -iscsi_host_attr(hwaddress, ISCSI_HOST_PARAM_HWADDRESS); -iscsi_host_attr(ipaddress, ISCSI_HOST_PARAM_IPADDRESS); -iscsi_host_attr(initiatorname, ISCSI_HOST_PARAM_INITIATOR_NAME); -iscsi_host_attr(port_state, ISCSI_HOST_PARAM_PORT_STATE); -iscsi_host_attr(port_speed, ISCSI_HOST_PARAM_PORT_SPEED); - -static struct attribute *iscsi_host_attrs[] = { - &dev_attr_host_netdev.attr, - &dev_attr_host_hwaddress.attr, - &dev_attr_host_ipaddress.attr, - &dev_attr_host_initiatorname.attr, - &dev_attr_host_port_state.attr, - &dev_attr_host_port_speed.attr, - NULL, -}; - -static umode_t iscsi_host_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int i) -{ - struct device *cdev = container_of(kobj, struct device, kobj); - struct Scsi_Host *shost = transport_class_to_shost(cdev); - struct iscsi_internal *priv = to_iscsi_internal(shost->transportt); - int param; - - if (attr == &dev_attr_host_netdev.attr) - param = ISCSI_HOST_PARAM_NETDEV_NAME; - else if (attr == &dev_attr_host_hwaddress.attr) - param = ISCSI_HOST_PARAM_HWADDRESS; - else if (attr == &dev_attr_host_ipaddress.attr) - param = ISCSI_HOST_PARAM_IPADDRESS; - else if (attr == &dev_attr_host_initiatorname.attr) - param = ISCSI_HOST_PARAM_INITIATOR_NAME; - else if (attr == &dev_attr_host_port_state.attr) - param = ISCSI_HOST_PARAM_PORT_STATE; - else if (attr == &dev_attr_host_port_speed.attr) - param = ISCSI_HOST_PARAM_PORT_SPEED; - else { - WARN_ONCE(1, "Invalid host attr"); - return 0; - } - - return priv->iscsi_transport->attr_is_visible(ISCSI_HOST_PARAM, param); -} - -static struct attribute_group iscsi_host_group = { - .attrs = iscsi_host_attrs, - .is_visible = iscsi_host_attr_is_visible, -}; - -/* convert iscsi_port_speed values to ascii string name */ -static const struct { - enum iscsi_port_speed value; - char *name; -} iscsi_port_speed_names[] = { - {ISCSI_PORT_SPEED_UNKNOWN, "Unknown" }, - {ISCSI_PORT_SPEED_10MBPS, "10 Mbps" }, - {ISCSI_PORT_SPEED_100MBPS, "100 Mbps" }, - {ISCSI_PORT_SPEED_1GBPS, "1 Gbps" }, - {ISCSI_PORT_SPEED_10GBPS, "10 Gbps" }, -}; - -char *iscsi_get_port_speed_name(struct Scsi_Host *shost) -{ - int i; - char *speed = "Unknown!"; - struct iscsi_cls_host *ihost = shost->shost_data; - uint32_t port_speed = ihost->port_speed; - - for (i = 0; i < ARRAY_SIZE(iscsi_port_speed_names); i++) { - if (iscsi_port_speed_names[i].value & port_speed) { - speed = iscsi_port_speed_names[i].name; - break; - } - } - return speed; -} -EXPORT_SYMBOL_GPL(iscsi_get_port_speed_name); - -/* convert iscsi_port_state values to ascii string name */ -static const struct { - enum iscsi_port_state value; - char *name; -} iscsi_port_state_names[] = { - {ISCSI_PORT_STATE_DOWN, "LINK DOWN" }, - {ISCSI_PORT_STATE_UP, "LINK UP" }, -}; - -char *iscsi_get_port_state_name(struct Scsi_Host *shost) -{ - int i; - char *state = "Unknown!"; - struct iscsi_cls_host *ihost = shost->shost_data; - uint32_t port_state = ihost->port_state; - - for (i = 0; i < ARRAY_SIZE(iscsi_port_state_names); i++) { - if (iscsi_port_state_names[i].value & port_state) { - state = iscsi_port_state_names[i].name; - break; - } - } - return state; -} -EXPORT_SYMBOL_GPL(iscsi_get_port_state_name); - -static int iscsi_session_match(struct attribute_container *cont, - struct device *dev) -{ - struct iscsi_cls_session *session; - struct Scsi_Host *shost; - struct iscsi_internal *priv; - - if (!iscsi_is_session_dev(dev)) - return 0; - - session = iscsi_dev_to_session(dev); - shost = iscsi_session_to_shost(session); - if (!shost->transportt) - return 0; - - priv = to_iscsi_internal(shost->transportt); - if (priv->session_cont.ac.class != &iscsi_session_class.class) - return 0; - - return &priv->session_cont.ac == cont; -} - -static int iscsi_conn_match(struct attribute_container *cont, - struct device *dev) -{ - struct iscsi_cls_session *session; - struct iscsi_cls_conn *conn; - struct Scsi_Host *shost; - struct iscsi_internal *priv; - - if (!iscsi_is_conn_dev(dev)) - return 0; - - conn = iscsi_dev_to_conn(dev); - session = iscsi_dev_to_session(conn->dev.parent); - shost = iscsi_session_to_shost(session); - - if (!shost->transportt) - return 0; - - priv = to_iscsi_internal(shost->transportt); - if (priv->conn_cont.ac.class != &iscsi_connection_class.class) - return 0; - - return &priv->conn_cont.ac == cont; -} - -static int iscsi_host_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct iscsi_internal *priv; - - if (!scsi_is_host_device(dev)) - return 0; - - shost = dev_to_shost(dev); - if (!shost->transportt || - shost->transportt->host_attrs.ac.class != &iscsi_host_class.class) - return 0; - - priv = to_iscsi_internal(shost->transportt); - return &priv->t.host_attrs.ac == cont; -} - -struct scsi_transport_template * -iscsi_register_transport(struct iscsi_transport *tt) -{ - struct iscsi_internal *priv; - unsigned long flags; - int err; - - BUG_ON(!tt); - - priv = iscsi_if_transport_lookup(tt); - if (priv) - return NULL; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return NULL; - INIT_LIST_HEAD(&priv->list); - priv->iscsi_transport = tt; - priv->t.user_scan = iscsi_user_scan; - priv->t.create_work_queue = 1; - - priv->dev.class = &iscsi_transport_class; - dev_set_name(&priv->dev, "%s", tt->name); - err = device_register(&priv->dev); - if (err) - goto free_priv; - - err = sysfs_create_group(&priv->dev.kobj, &iscsi_transport_group); - if (err) - goto unregister_dev; - - /* host parameters */ - priv->t.host_attrs.ac.class = &iscsi_host_class.class; - priv->t.host_attrs.ac.match = iscsi_host_match; - priv->t.host_attrs.ac.grp = &iscsi_host_group; - priv->t.host_size = sizeof(struct iscsi_cls_host); - transport_container_register(&priv->t.host_attrs); - - /* connection parameters */ - priv->conn_cont.ac.class = &iscsi_connection_class.class; - priv->conn_cont.ac.match = iscsi_conn_match; - priv->conn_cont.ac.grp = &iscsi_conn_group; - transport_container_register(&priv->conn_cont); - - /* session parameters */ - priv->session_cont.ac.class = &iscsi_session_class.class; - priv->session_cont.ac.match = iscsi_session_match; - priv->session_cont.ac.grp = &iscsi_session_group; - transport_container_register(&priv->session_cont); - - spin_lock_irqsave(&iscsi_transport_lock, flags); - list_add(&priv->list, &iscsi_transports); - spin_unlock_irqrestore(&iscsi_transport_lock, flags); - - printk(KERN_NOTICE "iscsi: registered transport (%s)\n", tt->name); - return &priv->t; - -unregister_dev: - device_unregister(&priv->dev); - return NULL; -free_priv: - kfree(priv); - return NULL; -} -EXPORT_SYMBOL_GPL(iscsi_register_transport); - -int iscsi_unregister_transport(struct iscsi_transport *tt) -{ - struct iscsi_internal *priv; - unsigned long flags; - - BUG_ON(!tt); - - mutex_lock(&rx_queue_mutex); - - priv = iscsi_if_transport_lookup(tt); - BUG_ON (!priv); - - spin_lock_irqsave(&iscsi_transport_lock, flags); - list_del(&priv->list); - spin_unlock_irqrestore(&iscsi_transport_lock, flags); - - transport_container_unregister(&priv->conn_cont); - transport_container_unregister(&priv->session_cont); - transport_container_unregister(&priv->t.host_attrs); - - sysfs_remove_group(&priv->dev.kobj, &iscsi_transport_group); - device_unregister(&priv->dev); - mutex_unlock(&rx_queue_mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(iscsi_unregister_transport); - -static __init int iscsi_transport_init(void) -{ - int err; - - printk(KERN_INFO "Loading iSCSI transport class v%s.\n", - ISCSI_TRANSPORT_VERSION); - - atomic_set(&iscsi_session_nr, 0); - - err = class_register(&iscsi_transport_class); - if (err) - return err; - - err = class_register(&iscsi_endpoint_class); - if (err) - goto unregister_transport_class; - - err = class_register(&iscsi_iface_class); - if (err) - goto unregister_endpoint_class; - - err = transport_class_register(&iscsi_host_class); - if (err) - goto unregister_iface_class; - - err = transport_class_register(&iscsi_connection_class); - if (err) - goto unregister_host_class; - - err = transport_class_register(&iscsi_session_class); - if (err) - goto unregister_conn_class; - - nls = netlink_kernel_create(&init_net, NETLINK_ISCSI, 1, iscsi_if_rx, - NULL, THIS_MODULE); - if (!nls) { - err = -ENOBUFS; - goto unregister_session_class; - } - - iscsi_eh_timer_workq = create_singlethread_workqueue("iscsi_eh"); - if (!iscsi_eh_timer_workq) - goto release_nls; - - return 0; - -release_nls: - netlink_kernel_release(nls); -unregister_session_class: - transport_class_unregister(&iscsi_session_class); -unregister_conn_class: - transport_class_unregister(&iscsi_connection_class); -unregister_host_class: - transport_class_unregister(&iscsi_host_class); -unregister_iface_class: - class_unregister(&iscsi_iface_class); -unregister_endpoint_class: - class_unregister(&iscsi_endpoint_class); -unregister_transport_class: - class_unregister(&iscsi_transport_class); - return err; -} - -static void __exit iscsi_transport_exit(void) -{ - destroy_workqueue(iscsi_eh_timer_workq); - netlink_kernel_release(nls); - transport_class_unregister(&iscsi_connection_class); - transport_class_unregister(&iscsi_session_class); - transport_class_unregister(&iscsi_host_class); - class_unregister(&iscsi_endpoint_class); - class_unregister(&iscsi_iface_class); - class_unregister(&iscsi_transport_class); -} - -module_init(iscsi_transport_init); -module_exit(iscsi_transport_exit); - -MODULE_AUTHOR("Mike Christie , " - "Dmitry Yusupov , " - "Alex Aizman "); -MODULE_DESCRIPTION("iSCSI Transport Interface"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(ISCSI_TRANSPORT_VERSION); -MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_ISCSI); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_transport_sas.c b/ANDROID_3.4.5/drivers/scsi/scsi_transport_sas.c deleted file mode 100644 index f7565fc4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_transport_sas.c +++ /dev/null @@ -1,1971 +0,0 @@ -/* - * Copyright (C) 2005-2006 Dell Inc. - * Released under GPL v2. - * - * Serial Attached SCSI (SAS) transport class. - * - * The SAS transport class contains common code to deal with SAS HBAs, - * an aproximated representation of SAS topologies in the driver model, - * and various sysfs attributes to expose these topologies and management - * interfaces to userspace. - * - * In addition to the basic SCSI core objects this transport class - * introduces two additional intermediate objects: The SAS PHY - * as represented by struct sas_phy defines an "outgoing" PHY on - * a SAS HBA or Expander, and the SAS remote PHY represented by - * struct sas_rphy defines an "incoming" PHY on a SAS Expander or - * end device. Note that this is purely a software concept, the - * underlying hardware for a PHY and a remote PHY is the exactly - * the same. - * - * There is no concept of a SAS port in this code, users can see - * what PHYs form a wide port based on the port_identifier attribute, - * which is the same for all PHYs in a port. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "scsi_sas_internal.h" -struct sas_host_attrs { - struct list_head rphy_list; - struct mutex lock; - struct request_queue *q; - u32 next_target_id; - u32 next_expander_id; - int next_port_id; -}; -#define to_sas_host_attrs(host) ((struct sas_host_attrs *)(host)->shost_data) - - -/* - * Hack to allow attributes of the same name in different objects. - */ -#define SAS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store) \ - struct device_attribute dev_attr_##_prefix##_##_name = \ - __ATTR(_name,_mode,_show,_store) - - -/* - * Pretty printing helpers - */ - -#define sas_bitfield_name_match(title, table) \ -static ssize_t \ -get_sas_##title##_names(u32 table_key, char *buf) \ -{ \ - char *prefix = ""; \ - ssize_t len = 0; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(table); i++) { \ - if (table[i].value & table_key) { \ - len += sprintf(buf + len, "%s%s", \ - prefix, table[i].name); \ - prefix = ", "; \ - } \ - } \ - len += sprintf(buf + len, "\n"); \ - return len; \ -} - -#define sas_bitfield_name_set(title, table) \ -static ssize_t \ -set_sas_##title##_names(u32 *table_key, const char *buf) \ -{ \ - ssize_t len = 0; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(table); i++) { \ - len = strlen(table[i].name); \ - if (strncmp(buf, table[i].name, len) == 0 && \ - (buf[len] == '\n' || buf[len] == '\0')) { \ - *table_key = table[i].value; \ - return 0; \ - } \ - } \ - return -EINVAL; \ -} - -#define sas_bitfield_name_search(title, table) \ -static ssize_t \ -get_sas_##title##_names(u32 table_key, char *buf) \ -{ \ - ssize_t len = 0; \ - int i; \ - \ - for (i = 0; i < ARRAY_SIZE(table); i++) { \ - if (table[i].value == table_key) { \ - len += sprintf(buf + len, "%s", \ - table[i].name); \ - break; \ - } \ - } \ - len += sprintf(buf + len, "\n"); \ - return len; \ -} - -static struct { - u32 value; - char *name; -} sas_device_type_names[] = { - { SAS_PHY_UNUSED, "unused" }, - { SAS_END_DEVICE, "end device" }, - { SAS_EDGE_EXPANDER_DEVICE, "edge expander" }, - { SAS_FANOUT_EXPANDER_DEVICE, "fanout expander" }, -}; -sas_bitfield_name_search(device_type, sas_device_type_names) - - -static struct { - u32 value; - char *name; -} sas_protocol_names[] = { - { SAS_PROTOCOL_SATA, "sata" }, - { SAS_PROTOCOL_SMP, "smp" }, - { SAS_PROTOCOL_STP, "stp" }, - { SAS_PROTOCOL_SSP, "ssp" }, -}; -sas_bitfield_name_match(protocol, sas_protocol_names) - -static struct { - u32 value; - char *name; -} sas_linkspeed_names[] = { - { SAS_LINK_RATE_UNKNOWN, "Unknown" }, - { SAS_PHY_DISABLED, "Phy disabled" }, - { SAS_LINK_RATE_FAILED, "Link Rate failed" }, - { SAS_SATA_SPINUP_HOLD, "Spin-up hold" }, - { SAS_LINK_RATE_1_5_GBPS, "1.5 Gbit" }, - { SAS_LINK_RATE_3_0_GBPS, "3.0 Gbit" }, - { SAS_LINK_RATE_6_0_GBPS, "6.0 Gbit" }, -}; -sas_bitfield_name_search(linkspeed, sas_linkspeed_names) -sas_bitfield_name_set(linkspeed, sas_linkspeed_names) - -static struct sas_end_device *sas_sdev_to_rdev(struct scsi_device *sdev) -{ - struct sas_rphy *rphy = target_to_rphy(sdev->sdev_target); - struct sas_end_device *rdev; - - BUG_ON(rphy->identify.device_type != SAS_END_DEVICE); - - rdev = rphy_to_end_device(rphy); - return rdev; -} - -static void sas_smp_request(struct request_queue *q, struct Scsi_Host *shost, - struct sas_rphy *rphy) -{ - struct request *req; - int ret; - int (*handler)(struct Scsi_Host *, struct sas_rphy *, struct request *); - - while ((req = blk_fetch_request(q)) != NULL) { - spin_unlock_irq(q->queue_lock); - - handler = to_sas_internal(shost->transportt)->f->smp_handler; - ret = handler(shost, rphy, req); - req->errors = ret; - - blk_end_request_all(req, ret); - - spin_lock_irq(q->queue_lock); - } -} - -static void sas_host_smp_request(struct request_queue *q) -{ - sas_smp_request(q, (struct Scsi_Host *)q->queuedata, NULL); -} - -static void sas_non_host_smp_request(struct request_queue *q) -{ - struct sas_rphy *rphy = q->queuedata; - sas_smp_request(q, rphy_to_shost(rphy), rphy); -} - -static void sas_host_release(struct device *dev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - struct request_queue *q = sas_host->q; - - if (q) - blk_cleanup_queue(q); -} - -static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) -{ - struct request_queue *q; - int error; - struct device *dev; - char namebuf[20]; - const char *name; - void (*release)(struct device *); - - if (!to_sas_internal(shost->transportt)->f->smp_handler) { - printk("%s can't handle SMP requests\n", shost->hostt->name); - return 0; - } - - if (rphy) { - q = blk_init_queue(sas_non_host_smp_request, NULL); - dev = &rphy->dev; - name = dev_name(dev); - release = NULL; - } else { - q = blk_init_queue(sas_host_smp_request, NULL); - dev = &shost->shost_gendev; - snprintf(namebuf, sizeof(namebuf), - "sas_host%d", shost->host_no); - name = namebuf; - release = sas_host_release; - } - if (!q) - return -ENOMEM; - - error = bsg_register_queue(q, dev, name, release); - if (error) { - blk_cleanup_queue(q); - return -ENOMEM; - } - - if (rphy) - rphy->q = q; - else - to_sas_host_attrs(shost)->q = q; - - if (rphy) - q->queuedata = rphy; - else - q->queuedata = shost; - - queue_flag_set_unlocked(QUEUE_FLAG_BIDI, q); - return 0; -} - -static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy) -{ - struct request_queue *q; - - if (rphy) - q = rphy->q; - else - q = to_sas_host_attrs(shost)->q; - - if (!q) - return; - - bsg_unregister_queue(q); -} - -/* - * SAS host attributes - */ - -static int sas_host_setup(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - - INIT_LIST_HEAD(&sas_host->rphy_list); - mutex_init(&sas_host->lock); - sas_host->next_target_id = 0; - sas_host->next_expander_id = 0; - sas_host->next_port_id = 0; - - if (sas_bsg_initialize(shost, NULL)) - dev_printk(KERN_ERR, dev, "fail to a bsg device %d\n", - shost->host_no); - - return 0; -} - -static int sas_host_remove(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - - sas_bsg_remove(shost, NULL); - - return 0; -} - -static DECLARE_TRANSPORT_CLASS(sas_host_class, - "sas_host", sas_host_setup, sas_host_remove, NULL); - -static int sas_host_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct sas_internal *i; - - if (!scsi_is_host_device(dev)) - return 0; - shost = dev_to_shost(dev); - - if (!shost->transportt) - return 0; - if (shost->transportt->host_attrs.ac.class != - &sas_host_class.class) - return 0; - - i = to_sas_internal(shost->transportt); - return &i->t.host_attrs.ac == cont; -} - -static int do_sas_phy_delete(struct device *dev, void *data) -{ - int pass = (int)(unsigned long)data; - - if (pass == 0 && scsi_is_sas_port(dev)) - sas_port_delete(dev_to_sas_port(dev)); - else if (pass == 1 && scsi_is_sas_phy(dev)) - sas_phy_delete(dev_to_phy(dev)); - return 0; -} - -/** - * sas_remove_children - tear down a devices SAS data structures - * @dev: device belonging to the sas object - * - * Removes all SAS PHYs and remote PHYs for a given object - */ -void sas_remove_children(struct device *dev) -{ - device_for_each_child(dev, (void *)0, do_sas_phy_delete); - device_for_each_child(dev, (void *)1, do_sas_phy_delete); -} -EXPORT_SYMBOL(sas_remove_children); - -/** - * sas_remove_host - tear down a Scsi_Host's SAS data structures - * @shost: Scsi Host that is torn down - * - * Removes all SAS PHYs and remote PHYs for a given Scsi_Host. - * Must be called just before scsi_remove_host for SAS HBAs. - */ -void sas_remove_host(struct Scsi_Host *shost) -{ - sas_remove_children(&shost->shost_gendev); -} -EXPORT_SYMBOL(sas_remove_host); - -/** - * sas_tlr_supported - checking TLR bit in vpd 0x90 - * @sdev: scsi device struct - * - * Check Transport Layer Retries are supported or not. - * If vpd page 0x90 is present, TRL is supported. - * - */ -unsigned int -sas_tlr_supported(struct scsi_device *sdev) -{ - const int vpd_len = 32; - struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); - char *buffer = kzalloc(vpd_len, GFP_KERNEL); - int ret = 0; - - if (scsi_get_vpd_page(sdev, 0x90, buffer, vpd_len)) - goto out; - - /* - * Magic numbers: the VPD Protocol page (0x90) - * has a 4 byte header and then one entry per device port - * the TLR bit is at offset 8 on each port entry - * if we take the first port, that's at total offset 12 - */ - ret = buffer[12] & 0x01; - - out: - kfree(buffer); - rdev->tlr_supported = ret; - return ret; - -} -EXPORT_SYMBOL_GPL(sas_tlr_supported); - -/** - * sas_disable_tlr - setting TLR flags - * @sdev: scsi device struct - * - * Seting tlr_enabled flag to 0. - * - */ -void -sas_disable_tlr(struct scsi_device *sdev) -{ - struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); - - rdev->tlr_enabled = 0; -} -EXPORT_SYMBOL_GPL(sas_disable_tlr); - -/** - * sas_enable_tlr - setting TLR flags - * @sdev: scsi device struct - * - * Seting tlr_enabled flag 1. - * - */ -void sas_enable_tlr(struct scsi_device *sdev) -{ - unsigned int tlr_supported = 0; - tlr_supported = sas_tlr_supported(sdev); - - if (tlr_supported) { - struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); - - rdev->tlr_enabled = 1; - } - - return; -} -EXPORT_SYMBOL_GPL(sas_enable_tlr); - -unsigned int sas_is_tlr_enabled(struct scsi_device *sdev) -{ - struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); - return rdev->tlr_enabled; -} -EXPORT_SYMBOL_GPL(sas_is_tlr_enabled); - -/* - * SAS Phy attributes - */ - -#define sas_phy_show_simple(field, name, format_string, cast) \ -static ssize_t \ -show_sas_phy_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_phy *phy = transport_class_to_phy(dev); \ - \ - return snprintf(buf, 20, format_string, cast phy->field); \ -} - -#define sas_phy_simple_attr(field, name, format_string, type) \ - sas_phy_show_simple(field, name, format_string, (type)) \ -static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) - -#define sas_phy_show_protocol(field, name) \ -static ssize_t \ -show_sas_phy_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_phy *phy = transport_class_to_phy(dev); \ - \ - if (!phy->field) \ - return snprintf(buf, 20, "none\n"); \ - return get_sas_protocol_names(phy->field, buf); \ -} - -#define sas_phy_protocol_attr(field, name) \ - sas_phy_show_protocol(field, name) \ -static DEVICE_ATTR(name, S_IRUGO, show_sas_phy_##name, NULL) - -#define sas_phy_show_linkspeed(field) \ -static ssize_t \ -show_sas_phy_##field(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_phy *phy = transport_class_to_phy(dev); \ - \ - return get_sas_linkspeed_names(phy->field, buf); \ -} - -/* Fudge to tell if we're minimum or maximum */ -#define sas_phy_store_linkspeed(field) \ -static ssize_t \ -store_sas_phy_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct sas_phy *phy = transport_class_to_phy(dev); \ - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ - struct sas_internal *i = to_sas_internal(shost->transportt); \ - u32 value; \ - struct sas_phy_linkrates rates = {0}; \ - int error; \ - \ - error = set_sas_linkspeed_names(&value, buf); \ - if (error) \ - return error; \ - rates.field = value; \ - error = i->f->set_phy_speed(phy, &rates); \ - \ - return error ? error : count; \ -} - -#define sas_phy_linkspeed_rw_attr(field) \ - sas_phy_show_linkspeed(field) \ - sas_phy_store_linkspeed(field) \ -static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, \ - store_sas_phy_##field) - -#define sas_phy_linkspeed_attr(field) \ - sas_phy_show_linkspeed(field) \ -static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) - - -#define sas_phy_show_linkerror(field) \ -static ssize_t \ -show_sas_phy_##field(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_phy *phy = transport_class_to_phy(dev); \ - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); \ - struct sas_internal *i = to_sas_internal(shost->transportt); \ - int error; \ - \ - error = i->f->get_linkerrors ? i->f->get_linkerrors(phy) : 0; \ - if (error) \ - return error; \ - return snprintf(buf, 20, "%u\n", phy->field); \ -} - -#define sas_phy_linkerror_attr(field) \ - sas_phy_show_linkerror(field) \ -static DEVICE_ATTR(field, S_IRUGO, show_sas_phy_##field, NULL) - - -static ssize_t -show_sas_device_type(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sas_phy *phy = transport_class_to_phy(dev); - - if (!phy->identify.device_type) - return snprintf(buf, 20, "none\n"); - return get_sas_device_type_names(phy->identify.device_type, buf); -} -static DEVICE_ATTR(device_type, S_IRUGO, show_sas_device_type, NULL); - -static ssize_t do_sas_phy_enable(struct device *dev, - size_t count, int enable) -{ - struct sas_phy *phy = transport_class_to_phy(dev); - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_internal *i = to_sas_internal(shost->transportt); - int error; - - error = i->f->phy_enable(phy, enable); - if (error) - return error; - phy->enabled = enable; - return count; -}; - -static ssize_t -store_sas_phy_enable(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - if (count < 1) - return -EINVAL; - - switch (buf[0]) { - case '0': - do_sas_phy_enable(dev, count, 0); - break; - case '1': - do_sas_phy_enable(dev, count, 1); - break; - default: - return -EINVAL; - } - - return count; -} - -static ssize_t -show_sas_phy_enable(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct sas_phy *phy = transport_class_to_phy(dev); - - return snprintf(buf, 20, "%d", phy->enabled); -} - -static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, show_sas_phy_enable, - store_sas_phy_enable); - -static ssize_t -do_sas_phy_reset(struct device *dev, size_t count, int hard_reset) -{ - struct sas_phy *phy = transport_class_to_phy(dev); - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_internal *i = to_sas_internal(shost->transportt); - int error; - - error = i->f->phy_reset(phy, hard_reset); - if (error) - return error; - phy->enabled = 1; - return count; -}; - -static ssize_t -store_sas_link_reset(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return do_sas_phy_reset(dev, count, 0); -} -static DEVICE_ATTR(link_reset, S_IWUSR, NULL, store_sas_link_reset); - -static ssize_t -store_sas_hard_reset(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - return do_sas_phy_reset(dev, count, 1); -} -static DEVICE_ATTR(hard_reset, S_IWUSR, NULL, store_sas_hard_reset); - -sas_phy_protocol_attr(identify.initiator_port_protocols, - initiator_port_protocols); -sas_phy_protocol_attr(identify.target_port_protocols, - target_port_protocols); -sas_phy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", - unsigned long long); -sas_phy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); -//sas_phy_simple_attr(port_identifier, port_identifier, "%d\n", int); -sas_phy_linkspeed_attr(negotiated_linkrate); -sas_phy_linkspeed_attr(minimum_linkrate_hw); -sas_phy_linkspeed_rw_attr(minimum_linkrate); -sas_phy_linkspeed_attr(maximum_linkrate_hw); -sas_phy_linkspeed_rw_attr(maximum_linkrate); -sas_phy_linkerror_attr(invalid_dword_count); -sas_phy_linkerror_attr(running_disparity_error_count); -sas_phy_linkerror_attr(loss_of_dword_sync_count); -sas_phy_linkerror_attr(phy_reset_problem_count); - -static int sas_phy_setup(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct sas_phy *phy = dev_to_phy(dev); - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_internal *i = to_sas_internal(shost->transportt); - - if (i->f->phy_setup) - i->f->phy_setup(phy); - - return 0; -} - -static DECLARE_TRANSPORT_CLASS(sas_phy_class, - "sas_phy", sas_phy_setup, NULL, NULL); - -static int sas_phy_match(struct attribute_container *cont, struct device *dev) -{ - struct Scsi_Host *shost; - struct sas_internal *i; - - if (!scsi_is_sas_phy(dev)) - return 0; - shost = dev_to_shost(dev->parent); - - if (!shost->transportt) - return 0; - if (shost->transportt->host_attrs.ac.class != - &sas_host_class.class) - return 0; - - i = to_sas_internal(shost->transportt); - return &i->phy_attr_cont.ac == cont; -} - -static void sas_phy_release(struct device *dev) -{ - struct sas_phy *phy = dev_to_phy(dev); - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_internal *i = to_sas_internal(shost->transportt); - - if (i->f->phy_release) - i->f->phy_release(phy); - put_device(dev->parent); - kfree(phy); -} - -/** - * sas_phy_alloc - allocates and initialize a SAS PHY structure - * @parent: Parent device - * @number: Phy index - * - * Allocates an SAS PHY structure. It will be added in the device tree - * below the device specified by @parent, which has to be either a Scsi_Host - * or sas_rphy. - * - * Returns: - * SAS PHY allocated or %NULL if the allocation failed. - */ -struct sas_phy *sas_phy_alloc(struct device *parent, int number) -{ - struct Scsi_Host *shost = dev_to_shost(parent); - struct sas_phy *phy; - - phy = kzalloc(sizeof(*phy), GFP_KERNEL); - if (!phy) - return NULL; - - phy->number = number; - phy->enabled = 1; - - device_initialize(&phy->dev); - phy->dev.parent = get_device(parent); - phy->dev.release = sas_phy_release; - INIT_LIST_HEAD(&phy->port_siblings); - if (scsi_is_sas_expander_device(parent)) { - struct sas_rphy *rphy = dev_to_rphy(parent); - dev_set_name(&phy->dev, "phy-%d:%d:%d", shost->host_no, - rphy->scsi_target_id, number); - } else - dev_set_name(&phy->dev, "phy-%d:%d", shost->host_no, number); - - transport_setup_device(&phy->dev); - - return phy; -} -EXPORT_SYMBOL(sas_phy_alloc); - -/** - * sas_phy_add - add a SAS PHY to the device hierarchy - * @phy: The PHY to be added - * - * Publishes a SAS PHY to the rest of the system. - */ -int sas_phy_add(struct sas_phy *phy) -{ - int error; - - error = device_add(&phy->dev); - if (!error) { - transport_add_device(&phy->dev); - transport_configure_device(&phy->dev); - } - - return error; -} -EXPORT_SYMBOL(sas_phy_add); - -/** - * sas_phy_free - free a SAS PHY - * @phy: SAS PHY to free - * - * Frees the specified SAS PHY. - * - * Note: - * This function must only be called on a PHY that has not - * successfully been added using sas_phy_add(). - */ -void sas_phy_free(struct sas_phy *phy) -{ - transport_destroy_device(&phy->dev); - put_device(&phy->dev); -} -EXPORT_SYMBOL(sas_phy_free); - -/** - * sas_phy_delete - remove SAS PHY - * @phy: SAS PHY to remove - * - * Removes the specified SAS PHY. If the SAS PHY has an - * associated remote PHY it is removed before. - */ -void -sas_phy_delete(struct sas_phy *phy) -{ - struct device *dev = &phy->dev; - - /* this happens if the phy is still part of a port when deleted */ - BUG_ON(!list_empty(&phy->port_siblings)); - - transport_remove_device(dev); - device_del(dev); - transport_destroy_device(dev); - put_device(dev); -} -EXPORT_SYMBOL(sas_phy_delete); - -/** - * scsi_is_sas_phy - check if a struct device represents a SAS PHY - * @dev: device to check - * - * Returns: - * %1 if the device represents a SAS PHY, %0 else - */ -int scsi_is_sas_phy(const struct device *dev) -{ - return dev->release == sas_phy_release; -} -EXPORT_SYMBOL(scsi_is_sas_phy); - -/* - * SAS Port attributes - */ -#define sas_port_show_simple(field, name, format_string, cast) \ -static ssize_t \ -show_sas_port_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_port *port = transport_class_to_sas_port(dev); \ - \ - return snprintf(buf, 20, format_string, cast port->field); \ -} - -#define sas_port_simple_attr(field, name, format_string, type) \ - sas_port_show_simple(field, name, format_string, (type)) \ -static DEVICE_ATTR(name, S_IRUGO, show_sas_port_##name, NULL) - -sas_port_simple_attr(num_phys, num_phys, "%d\n", int); - -static DECLARE_TRANSPORT_CLASS(sas_port_class, - "sas_port", NULL, NULL, NULL); - -static int sas_port_match(struct attribute_container *cont, struct device *dev) -{ - struct Scsi_Host *shost; - struct sas_internal *i; - - if (!scsi_is_sas_port(dev)) - return 0; - shost = dev_to_shost(dev->parent); - - if (!shost->transportt) - return 0; - if (shost->transportt->host_attrs.ac.class != - &sas_host_class.class) - return 0; - - i = to_sas_internal(shost->transportt); - return &i->port_attr_cont.ac == cont; -} - - -static void sas_port_release(struct device *dev) -{ - struct sas_port *port = dev_to_sas_port(dev); - - BUG_ON(!list_empty(&port->phy_list)); - - put_device(dev->parent); - kfree(port); -} - -static void sas_port_create_link(struct sas_port *port, - struct sas_phy *phy) -{ - int res; - - res = sysfs_create_link(&port->dev.kobj, &phy->dev.kobj, - dev_name(&phy->dev)); - if (res) - goto err; - res = sysfs_create_link(&phy->dev.kobj, &port->dev.kobj, "port"); - if (res) - goto err; - return; -err: - printk(KERN_ERR "%s: Cannot create port links, err=%d\n", - __func__, res); -} - -static void sas_port_delete_link(struct sas_port *port, - struct sas_phy *phy) -{ - sysfs_remove_link(&port->dev.kobj, dev_name(&phy->dev)); - sysfs_remove_link(&phy->dev.kobj, "port"); -} - -/** sas_port_alloc - allocate and initialize a SAS port structure - * - * @parent: parent device - * @port_id: port number - * - * Allocates a SAS port structure. It will be added to the device tree - * below the device specified by @parent which must be either a Scsi_Host - * or a sas_expander_device. - * - * Returns %NULL on error - */ -struct sas_port *sas_port_alloc(struct device *parent, int port_id) -{ - struct Scsi_Host *shost = dev_to_shost(parent); - struct sas_port *port; - - port = kzalloc(sizeof(*port), GFP_KERNEL); - if (!port) - return NULL; - - port->port_identifier = port_id; - - device_initialize(&port->dev); - - port->dev.parent = get_device(parent); - port->dev.release = sas_port_release; - - mutex_init(&port->phy_list_mutex); - INIT_LIST_HEAD(&port->phy_list); - - if (scsi_is_sas_expander_device(parent)) { - struct sas_rphy *rphy = dev_to_rphy(parent); - dev_set_name(&port->dev, "port-%d:%d:%d", shost->host_no, - rphy->scsi_target_id, port->port_identifier); - } else - dev_set_name(&port->dev, "port-%d:%d", shost->host_no, - port->port_identifier); - - transport_setup_device(&port->dev); - - return port; -} -EXPORT_SYMBOL(sas_port_alloc); - -/** sas_port_alloc_num - allocate and initialize a SAS port structure - * - * @parent: parent device - * - * Allocates a SAS port structure and a number to go with it. This - * interface is really for adapters where the port number has no - * meansing, so the sas class should manage them. It will be added to - * the device tree below the device specified by @parent which must be - * either a Scsi_Host or a sas_expander_device. - * - * Returns %NULL on error - */ -struct sas_port *sas_port_alloc_num(struct device *parent) -{ - int index; - struct Scsi_Host *shost = dev_to_shost(parent); - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - - /* FIXME: use idr for this eventually */ - mutex_lock(&sas_host->lock); - if (scsi_is_sas_expander_device(parent)) { - struct sas_rphy *rphy = dev_to_rphy(parent); - struct sas_expander_device *exp = rphy_to_expander_device(rphy); - - index = exp->next_port_id++; - } else - index = sas_host->next_port_id++; - mutex_unlock(&sas_host->lock); - return sas_port_alloc(parent, index); -} -EXPORT_SYMBOL(sas_port_alloc_num); - -/** - * sas_port_add - add a SAS port to the device hierarchy - * @port: port to be added - * - * publishes a port to the rest of the system - */ -int sas_port_add(struct sas_port *port) -{ - int error; - - /* No phys should be added until this is made visible */ - BUG_ON(!list_empty(&port->phy_list)); - - error = device_add(&port->dev); - - if (error) - return error; - - transport_add_device(&port->dev); - transport_configure_device(&port->dev); - - return 0; -} -EXPORT_SYMBOL(sas_port_add); - -/** - * sas_port_free - free a SAS PORT - * @port: SAS PORT to free - * - * Frees the specified SAS PORT. - * - * Note: - * This function must only be called on a PORT that has not - * successfully been added using sas_port_add(). - */ -void sas_port_free(struct sas_port *port) -{ - transport_destroy_device(&port->dev); - put_device(&port->dev); -} -EXPORT_SYMBOL(sas_port_free); - -/** - * sas_port_delete - remove SAS PORT - * @port: SAS PORT to remove - * - * Removes the specified SAS PORT. If the SAS PORT has an - * associated phys, unlink them from the port as well. - */ -void sas_port_delete(struct sas_port *port) -{ - struct device *dev = &port->dev; - struct sas_phy *phy, *tmp_phy; - - if (port->rphy) { - sas_rphy_delete(port->rphy); - port->rphy = NULL; - } - - mutex_lock(&port->phy_list_mutex); - list_for_each_entry_safe(phy, tmp_phy, &port->phy_list, - port_siblings) { - sas_port_delete_link(port, phy); - list_del_init(&phy->port_siblings); - } - mutex_unlock(&port->phy_list_mutex); - - if (port->is_backlink) { - struct device *parent = port->dev.parent; - - sysfs_remove_link(&port->dev.kobj, dev_name(parent)); - port->is_backlink = 0; - } - - transport_remove_device(dev); - device_del(dev); - transport_destroy_device(dev); - put_device(dev); -} -EXPORT_SYMBOL(sas_port_delete); - -/** - * scsi_is_sas_port - check if a struct device represents a SAS port - * @dev: device to check - * - * Returns: - * %1 if the device represents a SAS Port, %0 else - */ -int scsi_is_sas_port(const struct device *dev) -{ - return dev->release == sas_port_release; -} -EXPORT_SYMBOL(scsi_is_sas_port); - -/** - * sas_port_get_phy - try to take a reference on a port member - * @port: port to check - */ -struct sas_phy *sas_port_get_phy(struct sas_port *port) -{ - struct sas_phy *phy; - - mutex_lock(&port->phy_list_mutex); - if (list_empty(&port->phy_list)) - phy = NULL; - else { - struct list_head *ent = port->phy_list.next; - - phy = list_entry(ent, typeof(*phy), port_siblings); - get_device(&phy->dev); - } - mutex_unlock(&port->phy_list_mutex); - - return phy; -} -EXPORT_SYMBOL(sas_port_get_phy); - -/** - * sas_port_add_phy - add another phy to a port to form a wide port - * @port: port to add the phy to - * @phy: phy to add - * - * When a port is initially created, it is empty (has no phys). All - * ports must have at least one phy to operated, and all wide ports - * must have at least two. The current code makes no difference - * between ports and wide ports, but the only object that can be - * connected to a remote device is a port, so ports must be formed on - * all devices with phys if they're connected to anything. - */ -void sas_port_add_phy(struct sas_port *port, struct sas_phy *phy) -{ - mutex_lock(&port->phy_list_mutex); - if (unlikely(!list_empty(&phy->port_siblings))) { - /* make sure we're already on this port */ - struct sas_phy *tmp; - - list_for_each_entry(tmp, &port->phy_list, port_siblings) - if (tmp == phy) - break; - /* If this trips, you added a phy that was already - * part of a different port */ - if (unlikely(tmp != phy)) { - dev_printk(KERN_ERR, &port->dev, "trying to add phy %s fails: it's already part of another port\n", - dev_name(&phy->dev)); - BUG(); - } - } else { - sas_port_create_link(port, phy); - list_add_tail(&phy->port_siblings, &port->phy_list); - port->num_phys++; - } - mutex_unlock(&port->phy_list_mutex); -} -EXPORT_SYMBOL(sas_port_add_phy); - -/** - * sas_port_delete_phy - remove a phy from a port or wide port - * @port: port to remove the phy from - * @phy: phy to remove - * - * This operation is used for tearing down ports again. It must be - * done to every port or wide port before calling sas_port_delete. - */ -void sas_port_delete_phy(struct sas_port *port, struct sas_phy *phy) -{ - mutex_lock(&port->phy_list_mutex); - sas_port_delete_link(port, phy); - list_del_init(&phy->port_siblings); - port->num_phys--; - mutex_unlock(&port->phy_list_mutex); -} -EXPORT_SYMBOL(sas_port_delete_phy); - -void sas_port_mark_backlink(struct sas_port *port) -{ - int res; - struct device *parent = port->dev.parent->parent->parent; - - if (port->is_backlink) - return; - port->is_backlink = 1; - res = sysfs_create_link(&port->dev.kobj, &parent->kobj, - dev_name(parent)); - if (res) - goto err; - return; -err: - printk(KERN_ERR "%s: Cannot create port backlink, err=%d\n", - __func__, res); - -} -EXPORT_SYMBOL(sas_port_mark_backlink); - -/* - * SAS remote PHY attributes. - */ - -#define sas_rphy_show_simple(field, name, format_string, cast) \ -static ssize_t \ -show_sas_rphy_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_rphy *rphy = transport_class_to_rphy(dev); \ - \ - return snprintf(buf, 20, format_string, cast rphy->field); \ -} - -#define sas_rphy_simple_attr(field, name, format_string, type) \ - sas_rphy_show_simple(field, name, format_string, (type)) \ -static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, \ - show_sas_rphy_##name, NULL) - -#define sas_rphy_show_protocol(field, name) \ -static ssize_t \ -show_sas_rphy_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_rphy *rphy = transport_class_to_rphy(dev); \ - \ - if (!rphy->field) \ - return snprintf(buf, 20, "none\n"); \ - return get_sas_protocol_names(rphy->field, buf); \ -} - -#define sas_rphy_protocol_attr(field, name) \ - sas_rphy_show_protocol(field, name) \ -static SAS_DEVICE_ATTR(rphy, name, S_IRUGO, \ - show_sas_rphy_##name, NULL) - -static ssize_t -show_sas_rphy_device_type(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sas_rphy *rphy = transport_class_to_rphy(dev); - - if (!rphy->identify.device_type) - return snprintf(buf, 20, "none\n"); - return get_sas_device_type_names( - rphy->identify.device_type, buf); -} - -static SAS_DEVICE_ATTR(rphy, device_type, S_IRUGO, - show_sas_rphy_device_type, NULL); - -static ssize_t -show_sas_rphy_enclosure_identifier(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sas_rphy *rphy = transport_class_to_rphy(dev); - struct sas_phy *phy = dev_to_phy(rphy->dev.parent); - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_internal *i = to_sas_internal(shost->transportt); - u64 identifier; - int error; - - /* - * Only devices behind an expander are supported, because the - * enclosure identifier is a SMP feature. - */ - if (scsi_is_sas_phy_local(phy)) - return -EINVAL; - - error = i->f->get_enclosure_identifier(rphy, &identifier); - if (error) - return error; - return sprintf(buf, "0x%llx\n", (unsigned long long)identifier); -} - -static SAS_DEVICE_ATTR(rphy, enclosure_identifier, S_IRUGO, - show_sas_rphy_enclosure_identifier, NULL); - -static ssize_t -show_sas_rphy_bay_identifier(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct sas_rphy *rphy = transport_class_to_rphy(dev); - struct sas_phy *phy = dev_to_phy(rphy->dev.parent); - struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); - struct sas_internal *i = to_sas_internal(shost->transportt); - int val; - - if (scsi_is_sas_phy_local(phy)) - return -EINVAL; - - val = i->f->get_bay_identifier(rphy); - if (val < 0) - return val; - return sprintf(buf, "%d\n", val); -} - -static SAS_DEVICE_ATTR(rphy, bay_identifier, S_IRUGO, - show_sas_rphy_bay_identifier, NULL); - -sas_rphy_protocol_attr(identify.initiator_port_protocols, - initiator_port_protocols); -sas_rphy_protocol_attr(identify.target_port_protocols, target_port_protocols); -sas_rphy_simple_attr(identify.sas_address, sas_address, "0x%016llx\n", - unsigned long long); -sas_rphy_simple_attr(identify.phy_identifier, phy_identifier, "%d\n", u8); - -/* only need 8 bytes of data plus header (4 or 8) */ -#define BUF_SIZE 64 - -int sas_read_port_mode_page(struct scsi_device *sdev) -{ - char *buffer = kzalloc(BUF_SIZE, GFP_KERNEL), *msdata; - struct sas_end_device *rdev = sas_sdev_to_rdev(sdev); - struct scsi_mode_data mode_data; - int res, error; - - if (!buffer) - return -ENOMEM; - - res = scsi_mode_sense(sdev, 1, 0x19, buffer, BUF_SIZE, 30*HZ, 3, - &mode_data, NULL); - - error = -EINVAL; - if (!scsi_status_is_good(res)) - goto out; - - msdata = buffer + mode_data.header_length + - mode_data.block_descriptor_length; - - if (msdata - buffer > BUF_SIZE - 8) - goto out; - - error = 0; - - rdev->ready_led_meaning = msdata[2] & 0x10 ? 1 : 0; - rdev->I_T_nexus_loss_timeout = (msdata[4] << 8) + msdata[5]; - rdev->initiator_response_timeout = (msdata[6] << 8) + msdata[7]; - - out: - kfree(buffer); - return error; -} -EXPORT_SYMBOL(sas_read_port_mode_page); - -static DECLARE_TRANSPORT_CLASS(sas_end_dev_class, - "sas_end_device", NULL, NULL, NULL); - -#define sas_end_dev_show_simple(field, name, format_string, cast) \ -static ssize_t \ -show_sas_end_dev_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_rphy *rphy = transport_class_to_rphy(dev); \ - struct sas_end_device *rdev = rphy_to_end_device(rphy); \ - \ - return snprintf(buf, 20, format_string, cast rdev->field); \ -} - -#define sas_end_dev_simple_attr(field, name, format_string, type) \ - sas_end_dev_show_simple(field, name, format_string, (type)) \ -static SAS_DEVICE_ATTR(end_dev, name, S_IRUGO, \ - show_sas_end_dev_##name, NULL) - -sas_end_dev_simple_attr(ready_led_meaning, ready_led_meaning, "%d\n", int); -sas_end_dev_simple_attr(I_T_nexus_loss_timeout, I_T_nexus_loss_timeout, - "%d\n", int); -sas_end_dev_simple_attr(initiator_response_timeout, initiator_response_timeout, - "%d\n", int); -sas_end_dev_simple_attr(tlr_supported, tlr_supported, - "%d\n", int); -sas_end_dev_simple_attr(tlr_enabled, tlr_enabled, - "%d\n", int); - -static DECLARE_TRANSPORT_CLASS(sas_expander_class, - "sas_expander", NULL, NULL, NULL); - -#define sas_expander_show_simple(field, name, format_string, cast) \ -static ssize_t \ -show_sas_expander_##name(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct sas_rphy *rphy = transport_class_to_rphy(dev); \ - struct sas_expander_device *edev = rphy_to_expander_device(rphy); \ - \ - return snprintf(buf, 20, format_string, cast edev->field); \ -} - -#define sas_expander_simple_attr(field, name, format_string, type) \ - sas_expander_show_simple(field, name, format_string, (type)) \ -static SAS_DEVICE_ATTR(expander, name, S_IRUGO, \ - show_sas_expander_##name, NULL) - -sas_expander_simple_attr(vendor_id, vendor_id, "%s\n", char *); -sas_expander_simple_attr(product_id, product_id, "%s\n", char *); -sas_expander_simple_attr(product_rev, product_rev, "%s\n", char *); -sas_expander_simple_attr(component_vendor_id, component_vendor_id, - "%s\n", char *); -sas_expander_simple_attr(component_id, component_id, "%u\n", unsigned int); -sas_expander_simple_attr(component_revision_id, component_revision_id, "%u\n", - unsigned int); -sas_expander_simple_attr(level, level, "%d\n", int); - -static DECLARE_TRANSPORT_CLASS(sas_rphy_class, - "sas_device", NULL, NULL, NULL); - -static int sas_rphy_match(struct attribute_container *cont, struct device *dev) -{ - struct Scsi_Host *shost; - struct sas_internal *i; - - if (!scsi_is_sas_rphy(dev)) - return 0; - shost = dev_to_shost(dev->parent->parent); - - if (!shost->transportt) - return 0; - if (shost->transportt->host_attrs.ac.class != - &sas_host_class.class) - return 0; - - i = to_sas_internal(shost->transportt); - return &i->rphy_attr_cont.ac == cont; -} - -static int sas_end_dev_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct sas_internal *i; - struct sas_rphy *rphy; - - if (!scsi_is_sas_rphy(dev)) - return 0; - shost = dev_to_shost(dev->parent->parent); - rphy = dev_to_rphy(dev); - - if (!shost->transportt) - return 0; - if (shost->transportt->host_attrs.ac.class != - &sas_host_class.class) - return 0; - - i = to_sas_internal(shost->transportt); - return &i->end_dev_attr_cont.ac == cont && - rphy->identify.device_type == SAS_END_DEVICE; -} - -static int sas_expander_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct sas_internal *i; - struct sas_rphy *rphy; - - if (!scsi_is_sas_rphy(dev)) - return 0; - shost = dev_to_shost(dev->parent->parent); - rphy = dev_to_rphy(dev); - - if (!shost->transportt) - return 0; - if (shost->transportt->host_attrs.ac.class != - &sas_host_class.class) - return 0; - - i = to_sas_internal(shost->transportt); - return &i->expander_attr_cont.ac == cont && - (rphy->identify.device_type == SAS_EDGE_EXPANDER_DEVICE || - rphy->identify.device_type == SAS_FANOUT_EXPANDER_DEVICE); -} - -static void sas_expander_release(struct device *dev) -{ - struct sas_rphy *rphy = dev_to_rphy(dev); - struct sas_expander_device *edev = rphy_to_expander_device(rphy); - - if (rphy->q) - blk_cleanup_queue(rphy->q); - - put_device(dev->parent); - kfree(edev); -} - -static void sas_end_device_release(struct device *dev) -{ - struct sas_rphy *rphy = dev_to_rphy(dev); - struct sas_end_device *edev = rphy_to_end_device(rphy); - - if (rphy->q) - blk_cleanup_queue(rphy->q); - - put_device(dev->parent); - kfree(edev); -} - -/** - * sas_rphy_initialize - common rphy intialization - * @rphy: rphy to initialise - * - * Used by both sas_end_device_alloc() and sas_expander_alloc() to - * initialise the common rphy component of each. - */ -static void sas_rphy_initialize(struct sas_rphy *rphy) -{ - INIT_LIST_HEAD(&rphy->list); -} - -/** - * sas_end_device_alloc - allocate an rphy for an end device - * @parent: which port - * - * Allocates an SAS remote PHY structure, connected to @parent. - * - * Returns: - * SAS PHY allocated or %NULL if the allocation failed. - */ -struct sas_rphy *sas_end_device_alloc(struct sas_port *parent) -{ - struct Scsi_Host *shost = dev_to_shost(&parent->dev); - struct sas_end_device *rdev; - - rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); - if (!rdev) { - return NULL; - } - - device_initialize(&rdev->rphy.dev); - rdev->rphy.dev.parent = get_device(&parent->dev); - rdev->rphy.dev.release = sas_end_device_release; - if (scsi_is_sas_expander_device(parent->dev.parent)) { - struct sas_rphy *rphy = dev_to_rphy(parent->dev.parent); - dev_set_name(&rdev->rphy.dev, "end_device-%d:%d:%d", - shost->host_no, rphy->scsi_target_id, - parent->port_identifier); - } else - dev_set_name(&rdev->rphy.dev, "end_device-%d:%d", - shost->host_no, parent->port_identifier); - rdev->rphy.identify.device_type = SAS_END_DEVICE; - sas_rphy_initialize(&rdev->rphy); - transport_setup_device(&rdev->rphy.dev); - - return &rdev->rphy; -} -EXPORT_SYMBOL(sas_end_device_alloc); - -/** - * sas_expander_alloc - allocate an rphy for an end device - * @parent: which port - * @type: SAS_EDGE_EXPANDER_DEVICE or SAS_FANOUT_EXPANDER_DEVICE - * - * Allocates an SAS remote PHY structure, connected to @parent. - * - * Returns: - * SAS PHY allocated or %NULL if the allocation failed. - */ -struct sas_rphy *sas_expander_alloc(struct sas_port *parent, - enum sas_device_type type) -{ - struct Scsi_Host *shost = dev_to_shost(&parent->dev); - struct sas_expander_device *rdev; - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - - BUG_ON(type != SAS_EDGE_EXPANDER_DEVICE && - type != SAS_FANOUT_EXPANDER_DEVICE); - - rdev = kzalloc(sizeof(*rdev), GFP_KERNEL); - if (!rdev) { - return NULL; - } - - device_initialize(&rdev->rphy.dev); - rdev->rphy.dev.parent = get_device(&parent->dev); - rdev->rphy.dev.release = sas_expander_release; - mutex_lock(&sas_host->lock); - rdev->rphy.scsi_target_id = sas_host->next_expander_id++; - mutex_unlock(&sas_host->lock); - dev_set_name(&rdev->rphy.dev, "expander-%d:%d", - shost->host_no, rdev->rphy.scsi_target_id); - rdev->rphy.identify.device_type = type; - sas_rphy_initialize(&rdev->rphy); - transport_setup_device(&rdev->rphy.dev); - - return &rdev->rphy; -} -EXPORT_SYMBOL(sas_expander_alloc); - -/** - * sas_rphy_add - add a SAS remote PHY to the device hierarchy - * @rphy: The remote PHY to be added - * - * Publishes a SAS remote PHY to the rest of the system. - */ -int sas_rphy_add(struct sas_rphy *rphy) -{ - struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); - struct Scsi_Host *shost = dev_to_shost(parent->dev.parent); - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - struct sas_identify *identify = &rphy->identify; - int error; - - if (parent->rphy) - return -ENXIO; - parent->rphy = rphy; - - error = device_add(&rphy->dev); - if (error) - return error; - transport_add_device(&rphy->dev); - transport_configure_device(&rphy->dev); - if (sas_bsg_initialize(shost, rphy)) - printk("fail to a bsg device %s\n", dev_name(&rphy->dev)); - - - mutex_lock(&sas_host->lock); - list_add_tail(&rphy->list, &sas_host->rphy_list); - if (identify->device_type == SAS_END_DEVICE && - (identify->target_port_protocols & - (SAS_PROTOCOL_SSP|SAS_PROTOCOL_STP|SAS_PROTOCOL_SATA))) - rphy->scsi_target_id = sas_host->next_target_id++; - else if (identify->device_type == SAS_END_DEVICE) - rphy->scsi_target_id = -1; - mutex_unlock(&sas_host->lock); - - if (identify->device_type == SAS_END_DEVICE && - rphy->scsi_target_id != -1) { - int lun; - - if (identify->target_port_protocols & SAS_PROTOCOL_SSP) - lun = SCAN_WILD_CARD; - else - lun = 0; - - scsi_scan_target(&rphy->dev, 0, rphy->scsi_target_id, lun, 0); - } - - return 0; -} -EXPORT_SYMBOL(sas_rphy_add); - -/** - * sas_rphy_free - free a SAS remote PHY - * @rphy: SAS remote PHY to free - * - * Frees the specified SAS remote PHY. - * - * Note: - * This function must only be called on a remote - * PHY that has not successfully been added using - * sas_rphy_add() (or has been sas_rphy_remove()'d) - */ -void sas_rphy_free(struct sas_rphy *rphy) -{ - struct device *dev = &rphy->dev; - struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - - mutex_lock(&sas_host->lock); - list_del(&rphy->list); - mutex_unlock(&sas_host->lock); - - sas_bsg_remove(shost, rphy); - - transport_destroy_device(dev); - - put_device(dev); -} -EXPORT_SYMBOL(sas_rphy_free); - -/** - * sas_rphy_delete - remove and free SAS remote PHY - * @rphy: SAS remote PHY to remove and free - * - * Removes the specified SAS remote PHY and frees it. - */ -void -sas_rphy_delete(struct sas_rphy *rphy) -{ - sas_rphy_remove(rphy); - sas_rphy_free(rphy); -} -EXPORT_SYMBOL(sas_rphy_delete); - -/** - * sas_rphy_unlink - unlink SAS remote PHY - * @rphy: SAS remote phy to unlink from its parent port - * - * Removes port reference to an rphy - */ -void sas_rphy_unlink(struct sas_rphy *rphy) -{ - struct sas_port *parent = dev_to_sas_port(rphy->dev.parent); - - parent->rphy = NULL; -} -EXPORT_SYMBOL(sas_rphy_unlink); - -/** - * sas_rphy_remove - remove SAS remote PHY - * @rphy: SAS remote phy to remove - * - * Removes the specified SAS remote PHY. - */ -void -sas_rphy_remove(struct sas_rphy *rphy) -{ - struct device *dev = &rphy->dev; - - switch (rphy->identify.device_type) { - case SAS_END_DEVICE: - scsi_remove_target(dev); - break; - case SAS_EDGE_EXPANDER_DEVICE: - case SAS_FANOUT_EXPANDER_DEVICE: - sas_remove_children(dev); - break; - default: - break; - } - - sas_rphy_unlink(rphy); - transport_remove_device(dev); - device_del(dev); -} -EXPORT_SYMBOL(sas_rphy_remove); - -/** - * scsi_is_sas_rphy - check if a struct device represents a SAS remote PHY - * @dev: device to check - * - * Returns: - * %1 if the device represents a SAS remote PHY, %0 else - */ -int scsi_is_sas_rphy(const struct device *dev) -{ - return dev->release == sas_end_device_release || - dev->release == sas_expander_release; -} -EXPORT_SYMBOL(scsi_is_sas_rphy); - - -/* - * SCSI scan helper - */ - -static int sas_user_scan(struct Scsi_Host *shost, uint channel, - uint id, uint lun) -{ - struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); - struct sas_rphy *rphy; - - mutex_lock(&sas_host->lock); - list_for_each_entry(rphy, &sas_host->rphy_list, list) { - if (rphy->identify.device_type != SAS_END_DEVICE || - rphy->scsi_target_id == -1) - continue; - - if ((channel == SCAN_WILD_CARD || channel == 0) && - (id == SCAN_WILD_CARD || id == rphy->scsi_target_id)) { - scsi_scan_target(&rphy->dev, 0, - rphy->scsi_target_id, lun, 1); - } - } - mutex_unlock(&sas_host->lock); - - return 0; -} - - -/* - * Setup / Teardown code - */ - -#define SETUP_TEMPLATE(attrb, field, perm, test) \ - i->private_##attrb[count] = dev_attr_##field; \ - i->private_##attrb[count].attr.mode = perm; \ - i->attrb[count] = &i->private_##attrb[count]; \ - if (test) \ - count++ - -#define SETUP_TEMPLATE_RW(attrb, field, perm, test, ro_test, ro_perm) \ - i->private_##attrb[count] = dev_attr_##field; \ - i->private_##attrb[count].attr.mode = perm; \ - if (ro_test) { \ - i->private_##attrb[count].attr.mode = ro_perm; \ - i->private_##attrb[count].store = NULL; \ - } \ - i->attrb[count] = &i->private_##attrb[count]; \ - if (test) \ - count++ - -#define SETUP_RPORT_ATTRIBUTE(field) \ - SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, 1) - -#define SETUP_OPTIONAL_RPORT_ATTRIBUTE(field, func) \ - SETUP_TEMPLATE(rphy_attrs, field, S_IRUGO, i->f->func) - -#define SETUP_PHY_ATTRIBUTE(field) \ - SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, 1) - -#define SETUP_PHY_ATTRIBUTE_RW(field) \ - SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \ - !i->f->set_phy_speed, S_IRUGO) - -#define SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(field, func) \ - SETUP_TEMPLATE_RW(phy_attrs, field, S_IRUGO | S_IWUSR, 1, \ - !i->f->func, S_IRUGO) - -#define SETUP_PORT_ATTRIBUTE(field) \ - SETUP_TEMPLATE(port_attrs, field, S_IRUGO, 1) - -#define SETUP_OPTIONAL_PHY_ATTRIBUTE(field, func) \ - SETUP_TEMPLATE(phy_attrs, field, S_IRUGO, i->f->func) - -#define SETUP_PHY_ATTRIBUTE_WRONLY(field) \ - SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, 1) - -#define SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(field, func) \ - SETUP_TEMPLATE(phy_attrs, field, S_IWUSR, i->f->func) - -#define SETUP_END_DEV_ATTRIBUTE(field) \ - SETUP_TEMPLATE(end_dev_attrs, field, S_IRUGO, 1) - -#define SETUP_EXPANDER_ATTRIBUTE(field) \ - SETUP_TEMPLATE(expander_attrs, expander_##field, S_IRUGO, 1) - -/** - * sas_attach_transport - instantiate SAS transport template - * @ft: SAS transport class function template - */ -struct scsi_transport_template * -sas_attach_transport(struct sas_function_template *ft) -{ - struct sas_internal *i; - int count; - - i = kzalloc(sizeof(struct sas_internal), GFP_KERNEL); - if (!i) - return NULL; - - i->t.user_scan = sas_user_scan; - - i->t.host_attrs.ac.attrs = &i->host_attrs[0]; - i->t.host_attrs.ac.class = &sas_host_class.class; - i->t.host_attrs.ac.match = sas_host_match; - transport_container_register(&i->t.host_attrs); - i->t.host_size = sizeof(struct sas_host_attrs); - - i->phy_attr_cont.ac.class = &sas_phy_class.class; - i->phy_attr_cont.ac.attrs = &i->phy_attrs[0]; - i->phy_attr_cont.ac.match = sas_phy_match; - transport_container_register(&i->phy_attr_cont); - - i->port_attr_cont.ac.class = &sas_port_class.class; - i->port_attr_cont.ac.attrs = &i->port_attrs[0]; - i->port_attr_cont.ac.match = sas_port_match; - transport_container_register(&i->port_attr_cont); - - i->rphy_attr_cont.ac.class = &sas_rphy_class.class; - i->rphy_attr_cont.ac.attrs = &i->rphy_attrs[0]; - i->rphy_attr_cont.ac.match = sas_rphy_match; - transport_container_register(&i->rphy_attr_cont); - - i->end_dev_attr_cont.ac.class = &sas_end_dev_class.class; - i->end_dev_attr_cont.ac.attrs = &i->end_dev_attrs[0]; - i->end_dev_attr_cont.ac.match = sas_end_dev_match; - transport_container_register(&i->end_dev_attr_cont); - - i->expander_attr_cont.ac.class = &sas_expander_class.class; - i->expander_attr_cont.ac.attrs = &i->expander_attrs[0]; - i->expander_attr_cont.ac.match = sas_expander_match; - transport_container_register(&i->expander_attr_cont); - - i->f = ft; - - count = 0; - SETUP_PHY_ATTRIBUTE(initiator_port_protocols); - SETUP_PHY_ATTRIBUTE(target_port_protocols); - SETUP_PHY_ATTRIBUTE(device_type); - SETUP_PHY_ATTRIBUTE(sas_address); - SETUP_PHY_ATTRIBUTE(phy_identifier); - //SETUP_PHY_ATTRIBUTE(port_identifier); - SETUP_PHY_ATTRIBUTE(negotiated_linkrate); - SETUP_PHY_ATTRIBUTE(minimum_linkrate_hw); - SETUP_PHY_ATTRIBUTE_RW(minimum_linkrate); - SETUP_PHY_ATTRIBUTE(maximum_linkrate_hw); - SETUP_PHY_ATTRIBUTE_RW(maximum_linkrate); - - SETUP_PHY_ATTRIBUTE(invalid_dword_count); - SETUP_PHY_ATTRIBUTE(running_disparity_error_count); - SETUP_PHY_ATTRIBUTE(loss_of_dword_sync_count); - SETUP_PHY_ATTRIBUTE(phy_reset_problem_count); - SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(link_reset, phy_reset); - SETUP_OPTIONAL_PHY_ATTRIBUTE_WRONLY(hard_reset, phy_reset); - SETUP_OPTIONAL_PHY_ATTRIBUTE_RW(enable, phy_enable); - i->phy_attrs[count] = NULL; - - count = 0; - SETUP_PORT_ATTRIBUTE(num_phys); - i->port_attrs[count] = NULL; - - count = 0; - SETUP_RPORT_ATTRIBUTE(rphy_initiator_port_protocols); - SETUP_RPORT_ATTRIBUTE(rphy_target_port_protocols); - SETUP_RPORT_ATTRIBUTE(rphy_device_type); - SETUP_RPORT_ATTRIBUTE(rphy_sas_address); - SETUP_RPORT_ATTRIBUTE(rphy_phy_identifier); - SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_enclosure_identifier, - get_enclosure_identifier); - SETUP_OPTIONAL_RPORT_ATTRIBUTE(rphy_bay_identifier, - get_bay_identifier); - i->rphy_attrs[count] = NULL; - - count = 0; - SETUP_END_DEV_ATTRIBUTE(end_dev_ready_led_meaning); - SETUP_END_DEV_ATTRIBUTE(end_dev_I_T_nexus_loss_timeout); - SETUP_END_DEV_ATTRIBUTE(end_dev_initiator_response_timeout); - SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_supported); - SETUP_END_DEV_ATTRIBUTE(end_dev_tlr_enabled); - i->end_dev_attrs[count] = NULL; - - count = 0; - SETUP_EXPANDER_ATTRIBUTE(vendor_id); - SETUP_EXPANDER_ATTRIBUTE(product_id); - SETUP_EXPANDER_ATTRIBUTE(product_rev); - SETUP_EXPANDER_ATTRIBUTE(component_vendor_id); - SETUP_EXPANDER_ATTRIBUTE(component_id); - SETUP_EXPANDER_ATTRIBUTE(component_revision_id); - SETUP_EXPANDER_ATTRIBUTE(level); - i->expander_attrs[count] = NULL; - - return &i->t; -} -EXPORT_SYMBOL(sas_attach_transport); - -/** - * sas_release_transport - release SAS transport template instance - * @t: transport template instance - */ -void sas_release_transport(struct scsi_transport_template *t) -{ - struct sas_internal *i = to_sas_internal(t); - - transport_container_unregister(&i->t.host_attrs); - transport_container_unregister(&i->phy_attr_cont); - transport_container_unregister(&i->port_attr_cont); - transport_container_unregister(&i->rphy_attr_cont); - transport_container_unregister(&i->end_dev_attr_cont); - transport_container_unregister(&i->expander_attr_cont); - - kfree(i); -} -EXPORT_SYMBOL(sas_release_transport); - -static __init int sas_transport_init(void) -{ - int error; - - error = transport_class_register(&sas_host_class); - if (error) - goto out; - error = transport_class_register(&sas_phy_class); - if (error) - goto out_unregister_transport; - error = transport_class_register(&sas_port_class); - if (error) - goto out_unregister_phy; - error = transport_class_register(&sas_rphy_class); - if (error) - goto out_unregister_port; - error = transport_class_register(&sas_end_dev_class); - if (error) - goto out_unregister_rphy; - error = transport_class_register(&sas_expander_class); - if (error) - goto out_unregister_end_dev; - - return 0; - - out_unregister_end_dev: - transport_class_unregister(&sas_end_dev_class); - out_unregister_rphy: - transport_class_unregister(&sas_rphy_class); - out_unregister_port: - transport_class_unregister(&sas_port_class); - out_unregister_phy: - transport_class_unregister(&sas_phy_class); - out_unregister_transport: - transport_class_unregister(&sas_host_class); - out: - return error; - -} - -static void __exit sas_transport_exit(void) -{ - transport_class_unregister(&sas_host_class); - transport_class_unregister(&sas_phy_class); - transport_class_unregister(&sas_port_class); - transport_class_unregister(&sas_rphy_class); - transport_class_unregister(&sas_end_dev_class); - transport_class_unregister(&sas_expander_class); -} - -MODULE_AUTHOR("Christoph Hellwig"); -MODULE_DESCRIPTION("SAS Transport Attributes"); -MODULE_LICENSE("GPL"); - -module_init(sas_transport_init); -module_exit(sas_transport_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_transport_spi.c b/ANDROID_3.4.5/drivers/scsi/scsi_transport_spi.c deleted file mode 100644 index a2715c31..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_transport_spi.c +++ /dev/null @@ -1,1609 +0,0 @@ -/* - * Parallel SCSI (SPI) transport specific attributes exported to sysfs. - * - * Copyright (c) 2003 Silicon Graphics, Inc. All rights reserved. - * Copyright (c) 2004, 2005 James Bottomley - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "scsi_priv.h" -#include -#include -#include -#include -#include -#include - -#define SPI_NUM_ATTRS 14 /* increase this if you add attributes */ -#define SPI_OTHER_ATTRS 1 /* Increase this if you add "always - * on" attributes */ -#define SPI_HOST_ATTRS 1 - -#define SPI_MAX_ECHO_BUFFER_SIZE 4096 - -#define DV_LOOPS 3 -#define DV_TIMEOUT (10*HZ) -#define DV_RETRIES 3 /* should only need at most - * two cc/ua clears */ - -/* Our blacklist flags */ -enum { - SPI_BLIST_NOIUS = 0x1, -}; - -/* blacklist table, modelled on scsi_devinfo.c */ -static struct { - char *vendor; - char *model; - unsigned flags; -} spi_static_device_list[] __initdata = { - {"HP", "Ultrium 3-SCSI", SPI_BLIST_NOIUS }, - {"IBM", "ULTRIUM-TD3", SPI_BLIST_NOIUS }, - {NULL, NULL, 0} -}; - -/* Private data accessors (keep these out of the header file) */ -#define spi_dv_in_progress(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_in_progress) -#define spi_dv_mutex(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_mutex) - -struct spi_internal { - struct scsi_transport_template t; - struct spi_function_template *f; -}; - -#define to_spi_internal(tmpl) container_of(tmpl, struct spi_internal, t) - -static const int ppr_to_ps[] = { - /* The PPR values 0-6 are reserved, fill them in when - * the committee defines them */ - -1, /* 0x00 */ - -1, /* 0x01 */ - -1, /* 0x02 */ - -1, /* 0x03 */ - -1, /* 0x04 */ - -1, /* 0x05 */ - -1, /* 0x06 */ - 3125, /* 0x07 */ - 6250, /* 0x08 */ - 12500, /* 0x09 */ - 25000, /* 0x0a */ - 30300, /* 0x0b */ - 50000, /* 0x0c */ -}; -/* The PPR values at which you calculate the period in ns by multiplying - * by 4 */ -#define SPI_STATIC_PPR 0x0c - -static int sprint_frac(char *dest, int value, int denom) -{ - int frac = value % denom; - int result = sprintf(dest, "%d", value / denom); - - if (frac == 0) - return result; - dest[result++] = '.'; - - do { - denom /= 10; - sprintf(dest + result, "%d", frac / denom); - result++; - frac %= denom; - } while (frac); - - dest[result++] = '\0'; - return result; -} - -static int spi_execute(struct scsi_device *sdev, const void *cmd, - enum dma_data_direction dir, - void *buffer, unsigned bufflen, - struct scsi_sense_hdr *sshdr) -{ - int i, result; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - - for(i = 0; i < DV_RETRIES; i++) { - result = scsi_execute(sdev, cmd, dir, buffer, bufflen, - sense, DV_TIMEOUT, /* retries */ 1, - REQ_FAILFAST_DEV | - REQ_FAILFAST_TRANSPORT | - REQ_FAILFAST_DRIVER, - NULL); - if (driver_byte(result) & DRIVER_SENSE) { - struct scsi_sense_hdr sshdr_tmp; - if (!sshdr) - sshdr = &sshdr_tmp; - - if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, - sshdr) - && sshdr->sense_key == UNIT_ATTENTION) - continue; - } - break; - } - return result; -} - -static struct { - enum spi_signal_type value; - char *name; -} signal_types[] = { - { SPI_SIGNAL_UNKNOWN, "unknown" }, - { SPI_SIGNAL_SE, "SE" }, - { SPI_SIGNAL_LVD, "LVD" }, - { SPI_SIGNAL_HVD, "HVD" }, -}; - -static inline const char *spi_signal_to_string(enum spi_signal_type type) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(signal_types); i++) { - if (type == signal_types[i].value) - return signal_types[i].name; - } - return NULL; -} -static inline enum spi_signal_type spi_signal_to_value(const char *name) -{ - int i, len; - - for (i = 0; i < ARRAY_SIZE(signal_types); i++) { - len = strlen(signal_types[i].name); - if (strncmp(name, signal_types[i].name, len) == 0 && - (name[len] == '\n' || name[len] == '\0')) - return signal_types[i].value; - } - return SPI_SIGNAL_UNKNOWN; -} - -static int spi_host_setup(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - - spi_signalling(shost) = SPI_SIGNAL_UNKNOWN; - - return 0; -} - -static int spi_host_configure(struct transport_container *tc, - struct device *dev, - struct device *cdev); - -static DECLARE_TRANSPORT_CLASS(spi_host_class, - "spi_host", - spi_host_setup, - NULL, - spi_host_configure); - -static int spi_host_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - - if (!scsi_is_host_device(dev)) - return 0; - - shost = dev_to_shost(dev); - if (!shost->transportt || shost->transportt->host_attrs.ac.class - != &spi_host_class.class) - return 0; - - return &shost->transportt->host_attrs.ac == cont; -} - -static int spi_target_configure(struct transport_container *tc, - struct device *dev, - struct device *cdev); - -static int spi_device_configure(struct transport_container *tc, - struct device *dev, - struct device *cdev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct scsi_target *starget = sdev->sdev_target; - unsigned bflags = scsi_get_device_flags_keyed(sdev, &sdev->inquiry[8], - &sdev->inquiry[16], - SCSI_DEVINFO_SPI); - - /* Populate the target capability fields with the values - * gleaned from the device inquiry */ - - spi_support_sync(starget) = scsi_device_sync(sdev); - spi_support_wide(starget) = scsi_device_wide(sdev); - spi_support_dt(starget) = scsi_device_dt(sdev); - spi_support_dt_only(starget) = scsi_device_dt_only(sdev); - spi_support_ius(starget) = scsi_device_ius(sdev); - if (bflags & SPI_BLIST_NOIUS) { - dev_info(dev, "Information Units disabled by blacklist\n"); - spi_support_ius(starget) = 0; - } - spi_support_qas(starget) = scsi_device_qas(sdev); - - return 0; -} - -static int spi_setup_transport_attrs(struct transport_container *tc, - struct device *dev, - struct device *cdev) -{ - struct scsi_target *starget = to_scsi_target(dev); - - spi_period(starget) = -1; /* illegal value */ - spi_min_period(starget) = 0; - spi_offset(starget) = 0; /* async */ - spi_max_offset(starget) = 255; - spi_width(starget) = 0; /* narrow */ - spi_max_width(starget) = 1; - spi_iu(starget) = 0; /* no IU */ - spi_max_iu(starget) = 1; - spi_dt(starget) = 0; /* ST */ - spi_qas(starget) = 0; - spi_max_qas(starget) = 1; - spi_wr_flow(starget) = 0; - spi_rd_strm(starget) = 0; - spi_rti(starget) = 0; - spi_pcomp_en(starget) = 0; - spi_hold_mcs(starget) = 0; - spi_dv_pending(starget) = 0; - spi_dv_in_progress(starget) = 0; - spi_initial_dv(starget) = 0; - mutex_init(&spi_dv_mutex(starget)); - - return 0; -} - -#define spi_transport_show_simple(field, format_string) \ - \ -static ssize_t \ -show_spi_transport_##field(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct scsi_target *starget = transport_class_to_starget(dev); \ - struct spi_transport_attrs *tp; \ - \ - tp = (struct spi_transport_attrs *)&starget->starget_data; \ - return snprintf(buf, 20, format_string, tp->field); \ -} - -#define spi_transport_store_simple(field, format_string) \ - \ -static ssize_t \ -store_spi_transport_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int val; \ - struct scsi_target *starget = transport_class_to_starget(dev); \ - struct spi_transport_attrs *tp; \ - \ - tp = (struct spi_transport_attrs *)&starget->starget_data; \ - val = simple_strtoul(buf, NULL, 0); \ - tp->field = val; \ - return count; \ -} - -#define spi_transport_show_function(field, format_string) \ - \ -static ssize_t \ -show_spi_transport_##field(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct scsi_target *starget = transport_class_to_starget(dev); \ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ - struct spi_transport_attrs *tp; \ - struct spi_internal *i = to_spi_internal(shost->transportt); \ - tp = (struct spi_transport_attrs *)&starget->starget_data; \ - if (i->f->get_##field) \ - i->f->get_##field(starget); \ - return snprintf(buf, 20, format_string, tp->field); \ -} - -#define spi_transport_store_function(field, format_string) \ -static ssize_t \ -store_spi_transport_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int val; \ - struct scsi_target *starget = transport_class_to_starget(dev); \ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ - struct spi_internal *i = to_spi_internal(shost->transportt); \ - \ - if (!i->f->set_##field) \ - return -EINVAL; \ - val = simple_strtoul(buf, NULL, 0); \ - i->f->set_##field(starget, val); \ - return count; \ -} - -#define spi_transport_store_max(field, format_string) \ -static ssize_t \ -store_spi_transport_##field(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - int val; \ - struct scsi_target *starget = transport_class_to_starget(dev); \ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); \ - struct spi_internal *i = to_spi_internal(shost->transportt); \ - struct spi_transport_attrs *tp \ - = (struct spi_transport_attrs *)&starget->starget_data; \ - \ - if (i->f->set_##field) \ - return -EINVAL; \ - val = simple_strtoul(buf, NULL, 0); \ - if (val > tp->max_##field) \ - val = tp->max_##field; \ - i->f->set_##field(starget, val); \ - return count; \ -} - -#define spi_transport_rd_attr(field, format_string) \ - spi_transport_show_function(field, format_string) \ - spi_transport_store_function(field, format_string) \ -static DEVICE_ATTR(field, S_IRUGO, \ - show_spi_transport_##field, \ - store_spi_transport_##field); - -#define spi_transport_simple_attr(field, format_string) \ - spi_transport_show_simple(field, format_string) \ - spi_transport_store_simple(field, format_string) \ -static DEVICE_ATTR(field, S_IRUGO, \ - show_spi_transport_##field, \ - store_spi_transport_##field); - -#define spi_transport_max_attr(field, format_string) \ - spi_transport_show_function(field, format_string) \ - spi_transport_store_max(field, format_string) \ - spi_transport_simple_attr(max_##field, format_string) \ -static DEVICE_ATTR(field, S_IRUGO, \ - show_spi_transport_##field, \ - store_spi_transport_##field); - -/* The Parallel SCSI Tranport Attributes: */ -spi_transport_max_attr(offset, "%d\n"); -spi_transport_max_attr(width, "%d\n"); -spi_transport_max_attr(iu, "%d\n"); -spi_transport_rd_attr(dt, "%d\n"); -spi_transport_max_attr(qas, "%d\n"); -spi_transport_rd_attr(wr_flow, "%d\n"); -spi_transport_rd_attr(rd_strm, "%d\n"); -spi_transport_rd_attr(rti, "%d\n"); -spi_transport_rd_attr(pcomp_en, "%d\n"); -spi_transport_rd_attr(hold_mcs, "%d\n"); - -/* we only care about the first child device that's a real SCSI device - * so we return 1 to terminate the iteration when we find it */ -static int child_iter(struct device *dev, void *data) -{ - if (!scsi_is_sdev_device(dev)) - return 0; - - spi_dv_device(to_scsi_device(dev)); - return 1; -} - -static ssize_t -store_spi_revalidate(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_target *starget = transport_class_to_starget(dev); - - device_for_each_child(&starget->dev, NULL, child_iter); - return count; -} -static DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate); - -/* Translate the period into ns according to the current spec - * for SDTR/PPR messages */ -static int period_to_str(char *buf, int period) -{ - int len, picosec; - - if (period < 0 || period > 0xff) { - picosec = -1; - } else if (period <= SPI_STATIC_PPR) { - picosec = ppr_to_ps[period]; - } else { - picosec = period * 4000; - } - - if (picosec == -1) { - len = sprintf(buf, "reserved"); - } else { - len = sprint_frac(buf, picosec, 1000); - } - - return len; -} - -static ssize_t -show_spi_transport_period_helper(char *buf, int period) -{ - int len = period_to_str(buf, period); - buf[len++] = '\n'; - buf[len] = '\0'; - return len; -} - -static ssize_t -store_spi_transport_period_helper(struct device *dev, const char *buf, - size_t count, int *periodp) -{ - int j, picosec, period = -1; - char *endp; - - picosec = simple_strtoul(buf, &endp, 10) * 1000; - if (*endp == '.') { - int mult = 100; - do { - endp++; - if (!isdigit(*endp)) - break; - picosec += (*endp - '0') * mult; - mult /= 10; - } while (mult > 0); - } - - for (j = 0; j <= SPI_STATIC_PPR; j++) { - if (ppr_to_ps[j] < picosec) - continue; - period = j; - break; - } - - if (period == -1) - period = picosec / 4000; - - if (period > 0xff) - period = 0xff; - - *periodp = period; - - return count; -} - -static ssize_t -show_spi_transport_period(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct scsi_target *starget = transport_class_to_starget(dev); - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct spi_internal *i = to_spi_internal(shost->transportt); - struct spi_transport_attrs *tp = - (struct spi_transport_attrs *)&starget->starget_data; - - if (i->f->get_period) - i->f->get_period(starget); - - return show_spi_transport_period_helper(buf, tp->period); -} - -static ssize_t -store_spi_transport_period(struct device *cdev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_target *starget = transport_class_to_starget(cdev); - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct spi_internal *i = to_spi_internal(shost->transportt); - struct spi_transport_attrs *tp = - (struct spi_transport_attrs *)&starget->starget_data; - int period, retval; - - if (!i->f->set_period) - return -EINVAL; - - retval = store_spi_transport_period_helper(cdev, buf, count, &period); - - if (period < tp->min_period) - period = tp->min_period; - - i->f->set_period(starget, period); - - return retval; -} - -static DEVICE_ATTR(period, S_IRUGO, - show_spi_transport_period, - store_spi_transport_period); - -static ssize_t -show_spi_transport_min_period(struct device *cdev, - struct device_attribute *attr, char *buf) -{ - struct scsi_target *starget = transport_class_to_starget(cdev); - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct spi_internal *i = to_spi_internal(shost->transportt); - struct spi_transport_attrs *tp = - (struct spi_transport_attrs *)&starget->starget_data; - - if (!i->f->set_period) - return -EINVAL; - - return show_spi_transport_period_helper(buf, tp->min_period); -} - -static ssize_t -store_spi_transport_min_period(struct device *cdev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_target *starget = transport_class_to_starget(cdev); - struct spi_transport_attrs *tp = - (struct spi_transport_attrs *)&starget->starget_data; - - return store_spi_transport_period_helper(cdev, buf, count, - &tp->min_period); -} - - -static DEVICE_ATTR(min_period, S_IRUGO, - show_spi_transport_min_period, - store_spi_transport_min_period); - - -static ssize_t show_spi_host_signalling(struct device *cdev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(cdev); - struct spi_internal *i = to_spi_internal(shost->transportt); - - if (i->f->get_signalling) - i->f->get_signalling(shost); - - return sprintf(buf, "%s\n", spi_signal_to_string(spi_signalling(shost))); -} -static ssize_t store_spi_host_signalling(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct Scsi_Host *shost = transport_class_to_shost(dev); - struct spi_internal *i = to_spi_internal(shost->transportt); - enum spi_signal_type type = spi_signal_to_value(buf); - - if (!i->f->set_signalling) - return -EINVAL; - - if (type != SPI_SIGNAL_UNKNOWN) - i->f->set_signalling(shost, type); - - return count; -} -static DEVICE_ATTR(signalling, S_IRUGO, - show_spi_host_signalling, - store_spi_host_signalling); - -static ssize_t show_spi_host_width(struct device *cdev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(cdev); - - return sprintf(buf, "%s\n", shost->max_id == 16 ? "wide" : "narrow"); -} -static DEVICE_ATTR(host_width, S_IRUGO, - show_spi_host_width, NULL); - -static ssize_t show_spi_host_hba_id(struct device *cdev, - struct device_attribute *attr, - char *buf) -{ - struct Scsi_Host *shost = transport_class_to_shost(cdev); - - return sprintf(buf, "%d\n", shost->this_id); -} -static DEVICE_ATTR(hba_id, S_IRUGO, - show_spi_host_hba_id, NULL); - -#define DV_SET(x, y) \ - if(i->f->set_##x) \ - i->f->set_##x(sdev->sdev_target, y) - -enum spi_compare_returns { - SPI_COMPARE_SUCCESS, - SPI_COMPARE_FAILURE, - SPI_COMPARE_SKIP_TEST, -}; - - -/* This is for read/write Domain Validation: If the device supports - * an echo buffer, we do read/write tests to it */ -static enum spi_compare_returns -spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer, - u8 *ptr, const int retries) -{ - int len = ptr - buffer; - int j, k, r, result; - unsigned int pattern = 0x0000ffff; - struct scsi_sense_hdr sshdr; - - const char spi_write_buffer[] = { - WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0 - }; - const char spi_read_buffer[] = { - READ_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0 - }; - - /* set up the pattern buffer. Doesn't matter if we spill - * slightly beyond since that's where the read buffer is */ - for (j = 0; j < len; ) { - - /* fill the buffer with counting (test a) */ - for ( ; j < min(len, 32); j++) - buffer[j] = j; - k = j; - /* fill the buffer with alternating words of 0x0 and - * 0xffff (test b) */ - for ( ; j < min(len, k + 32); j += 2) { - u16 *word = (u16 *)&buffer[j]; - - *word = (j & 0x02) ? 0x0000 : 0xffff; - } - k = j; - /* fill with crosstalk (alternating 0x5555 0xaaa) - * (test c) */ - for ( ; j < min(len, k + 32); j += 2) { - u16 *word = (u16 *)&buffer[j]; - - *word = (j & 0x02) ? 0x5555 : 0xaaaa; - } - k = j; - /* fill with shifting bits (test d) */ - for ( ; j < min(len, k + 32); j += 4) { - u32 *word = (unsigned int *)&buffer[j]; - u32 roll = (pattern & 0x80000000) ? 1 : 0; - - *word = pattern; - pattern = (pattern << 1) | roll; - } - /* don't bother with random data (test e) */ - } - - for (r = 0; r < retries; r++) { - result = spi_execute(sdev, spi_write_buffer, DMA_TO_DEVICE, - buffer, len, &sshdr); - if(result || !scsi_device_online(sdev)) { - - scsi_device_set_state(sdev, SDEV_QUIESCE); - if (scsi_sense_valid(&sshdr) - && sshdr.sense_key == ILLEGAL_REQUEST - /* INVALID FIELD IN CDB */ - && sshdr.asc == 0x24 && sshdr.ascq == 0x00) - /* This would mean that the drive lied - * to us about supporting an echo - * buffer (unfortunately some Western - * Digital drives do precisely this) - */ - return SPI_COMPARE_SKIP_TEST; - - - sdev_printk(KERN_ERR, sdev, "Write Buffer failure %x\n", result); - return SPI_COMPARE_FAILURE; - } - - memset(ptr, 0, len); - spi_execute(sdev, spi_read_buffer, DMA_FROM_DEVICE, - ptr, len, NULL); - scsi_device_set_state(sdev, SDEV_QUIESCE); - - if (memcmp(buffer, ptr, len) != 0) - return SPI_COMPARE_FAILURE; - } - return SPI_COMPARE_SUCCESS; -} - -/* This is for the simplest form of Domain Validation: a read test - * on the inquiry data from the device */ -static enum spi_compare_returns -spi_dv_device_compare_inquiry(struct scsi_device *sdev, u8 *buffer, - u8 *ptr, const int retries) -{ - int r, result; - const int len = sdev->inquiry_len; - const char spi_inquiry[] = { - INQUIRY, 0, 0, 0, len, 0 - }; - - for (r = 0; r < retries; r++) { - memset(ptr, 0, len); - - result = spi_execute(sdev, spi_inquiry, DMA_FROM_DEVICE, - ptr, len, NULL); - - if(result || !scsi_device_online(sdev)) { - scsi_device_set_state(sdev, SDEV_QUIESCE); - return SPI_COMPARE_FAILURE; - } - - /* If we don't have the inquiry data already, the - * first read gets it */ - if (ptr == buffer) { - ptr += len; - --r; - continue; - } - - if (memcmp(buffer, ptr, len) != 0) - /* failure */ - return SPI_COMPARE_FAILURE; - } - return SPI_COMPARE_SUCCESS; -} - -static enum spi_compare_returns -spi_dv_retrain(struct scsi_device *sdev, u8 *buffer, u8 *ptr, - enum spi_compare_returns - (*compare_fn)(struct scsi_device *, u8 *, u8 *, int)) -{ - struct spi_internal *i = to_spi_internal(sdev->host->transportt); - struct scsi_target *starget = sdev->sdev_target; - int period = 0, prevperiod = 0; - enum spi_compare_returns retval; - - - for (;;) { - int newperiod; - retval = compare_fn(sdev, buffer, ptr, DV_LOOPS); - - if (retval == SPI_COMPARE_SUCCESS - || retval == SPI_COMPARE_SKIP_TEST) - break; - - /* OK, retrain, fallback */ - if (i->f->get_iu) - i->f->get_iu(starget); - if (i->f->get_qas) - i->f->get_qas(starget); - if (i->f->get_period) - i->f->get_period(sdev->sdev_target); - - /* Here's the fallback sequence; first try turning off - * IU, then QAS (if we can control them), then finally - * fall down the periods */ - if (i->f->set_iu && spi_iu(starget)) { - starget_printk(KERN_ERR, starget, "Domain Validation Disabing Information Units\n"); - DV_SET(iu, 0); - } else if (i->f->set_qas && spi_qas(starget)) { - starget_printk(KERN_ERR, starget, "Domain Validation Disabing Quick Arbitration and Selection\n"); - DV_SET(qas, 0); - } else { - newperiod = spi_period(starget); - period = newperiod > period ? newperiod : period; - if (period < 0x0d) - period++; - else - period += period >> 1; - - if (unlikely(period > 0xff || period == prevperiod)) { - /* Total failure; set to async and return */ - starget_printk(KERN_ERR, starget, "Domain Validation Failure, dropping back to Asynchronous\n"); - DV_SET(offset, 0); - return SPI_COMPARE_FAILURE; - } - starget_printk(KERN_ERR, starget, "Domain Validation detected failure, dropping back\n"); - DV_SET(period, period); - prevperiod = period; - } - } - return retval; -} - -static int -spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer) -{ - int l, result; - - /* first off do a test unit ready. This can error out - * because of reservations or some other reason. If it - * fails, the device won't let us write to the echo buffer - * so just return failure */ - - const char spi_test_unit_ready[] = { - TEST_UNIT_READY, 0, 0, 0, 0, 0 - }; - - const char spi_read_buffer_descriptor[] = { - READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0 - }; - - - /* We send a set of three TURs to clear any outstanding - * unit attention conditions if they exist (Otherwise the - * buffer tests won't be happy). If the TUR still fails - * (reservation conflict, device not ready, etc) just - * skip the write tests */ - for (l = 0; ; l++) { - result = spi_execute(sdev, spi_test_unit_ready, DMA_NONE, - NULL, 0, NULL); - - if(result) { - if(l >= 3) - return 0; - } else { - /* TUR succeeded */ - break; - } - } - - result = spi_execute(sdev, spi_read_buffer_descriptor, - DMA_FROM_DEVICE, buffer, 4, NULL); - - if (result) - /* Device has no echo buffer */ - return 0; - - return buffer[3] + ((buffer[2] & 0x1f) << 8); -} - -static void -spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) -{ - struct spi_internal *i = to_spi_internal(sdev->host->transportt); - struct scsi_target *starget = sdev->sdev_target; - struct Scsi_Host *shost = sdev->host; - int len = sdev->inquiry_len; - int min_period = spi_min_period(starget); - int max_width = spi_max_width(starget); - /* first set us up for narrow async */ - DV_SET(offset, 0); - DV_SET(width, 0); - - if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS) - != SPI_COMPARE_SUCCESS) { - starget_printk(KERN_ERR, starget, "Domain Validation Initial Inquiry Failed\n"); - /* FIXME: should probably offline the device here? */ - return; - } - - if (!spi_support_wide(starget)) { - spi_max_width(starget) = 0; - max_width = 0; - } - - /* test width */ - if (i->f->set_width && max_width) { - i->f->set_width(starget, 1); - - if (spi_dv_device_compare_inquiry(sdev, buffer, - buffer + len, - DV_LOOPS) - != SPI_COMPARE_SUCCESS) { - starget_printk(KERN_ERR, starget, "Wide Transfers Fail\n"); - i->f->set_width(starget, 0); - /* Make sure we don't force wide back on by asking - * for a transfer period that requires it */ - max_width = 0; - if (min_period < 10) - min_period = 10; - } - } - - if (!i->f->set_period) - return; - - /* device can't handle synchronous */ - if (!spi_support_sync(starget) && !spi_support_dt(starget)) - return; - - /* len == -1 is the signal that we need to ascertain the - * presence of an echo buffer before trying to use it. len == - * 0 means we don't have an echo buffer */ - len = -1; - - retry: - - /* now set up to the maximum */ - DV_SET(offset, spi_max_offset(starget)); - DV_SET(period, min_period); - - /* try QAS requests; this should be harmless to set if the - * target supports it */ - if (spi_support_qas(starget) && spi_max_qas(starget)) { - DV_SET(qas, 1); - } else { - DV_SET(qas, 0); - } - - if (spi_support_ius(starget) && spi_max_iu(starget) && - min_period < 9) { - /* This u320 (or u640). Set IU transfers */ - DV_SET(iu, 1); - /* Then set the optional parameters */ - DV_SET(rd_strm, 1); - DV_SET(wr_flow, 1); - DV_SET(rti, 1); - if (min_period == 8) - DV_SET(pcomp_en, 1); - } else { - DV_SET(iu, 0); - } - - /* now that we've done all this, actually check the bus - * signal type (if known). Some devices are stupid on - * a SE bus and still claim they can try LVD only settings */ - if (i->f->get_signalling) - i->f->get_signalling(shost); - if (spi_signalling(shost) == SPI_SIGNAL_SE || - spi_signalling(shost) == SPI_SIGNAL_HVD || - !spi_support_dt(starget)) { - DV_SET(dt, 0); - } else { - DV_SET(dt, 1); - } - /* set width last because it will pull all the other - * parameters down to required values */ - DV_SET(width, max_width); - - /* Do the read only INQUIRY tests */ - spi_dv_retrain(sdev, buffer, buffer + sdev->inquiry_len, - spi_dv_device_compare_inquiry); - /* See if we actually managed to negotiate and sustain DT */ - if (i->f->get_dt) - i->f->get_dt(starget); - - /* see if the device has an echo buffer. If it does we can do - * the SPI pattern write tests. Because of some broken - * devices, we *only* try this on a device that has actually - * negotiated DT */ - - if (len == -1 && spi_dt(starget)) - len = spi_dv_device_get_echo_buffer(sdev, buffer); - - if (len <= 0) { - starget_printk(KERN_INFO, starget, "Domain Validation skipping write tests\n"); - return; - } - - if (len > SPI_MAX_ECHO_BUFFER_SIZE) { - starget_printk(KERN_WARNING, starget, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE); - len = SPI_MAX_ECHO_BUFFER_SIZE; - } - - if (spi_dv_retrain(sdev, buffer, buffer + len, - spi_dv_device_echo_buffer) - == SPI_COMPARE_SKIP_TEST) { - /* OK, the stupid drive can't do a write echo buffer - * test after all, fall back to the read tests */ - len = 0; - goto retry; - } -} - - -/** spi_dv_device - Do Domain Validation on the device - * @sdev: scsi device to validate - * - * Performs the domain validation on the given device in the - * current execution thread. Since DV operations may sleep, - * the current thread must have user context. Also no SCSI - * related locks that would deadlock I/O issued by the DV may - * be held. - */ -void -spi_dv_device(struct scsi_device *sdev) -{ - struct scsi_target *starget = sdev->sdev_target; - u8 *buffer; - const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; - - if (unlikely(scsi_device_get(sdev))) - return; - - if (unlikely(spi_dv_in_progress(starget))) - return; - spi_dv_in_progress(starget) = 1; - - buffer = kzalloc(len, GFP_KERNEL); - - if (unlikely(!buffer)) - goto out_put; - - /* We need to verify that the actual device will quiesce; the - * later target quiesce is just a nice to have */ - if (unlikely(scsi_device_quiesce(sdev))) - goto out_free; - - scsi_target_quiesce(starget); - - spi_dv_pending(starget) = 1; - mutex_lock(&spi_dv_mutex(starget)); - - starget_printk(KERN_INFO, starget, "Beginning Domain Validation\n"); - - spi_dv_device_internal(sdev, buffer); - - starget_printk(KERN_INFO, starget, "Ending Domain Validation\n"); - - mutex_unlock(&spi_dv_mutex(starget)); - spi_dv_pending(starget) = 0; - - scsi_target_resume(starget); - - spi_initial_dv(starget) = 1; - - out_free: - kfree(buffer); - out_put: - spi_dv_in_progress(starget) = 0; - scsi_device_put(sdev); -} -EXPORT_SYMBOL(spi_dv_device); - -struct work_queue_wrapper { - struct work_struct work; - struct scsi_device *sdev; -}; - -static void -spi_dv_device_work_wrapper(struct work_struct *work) -{ - struct work_queue_wrapper *wqw = - container_of(work, struct work_queue_wrapper, work); - struct scsi_device *sdev = wqw->sdev; - - kfree(wqw); - spi_dv_device(sdev); - spi_dv_pending(sdev->sdev_target) = 0; - scsi_device_put(sdev); -} - - -/** - * spi_schedule_dv_device - schedule domain validation to occur on the device - * @sdev: The device to validate - * - * Identical to spi_dv_device() above, except that the DV will be - * scheduled to occur in a workqueue later. All memory allocations - * are atomic, so may be called from any context including those holding - * SCSI locks. - */ -void -spi_schedule_dv_device(struct scsi_device *sdev) -{ - struct work_queue_wrapper *wqw = - kmalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); - - if (unlikely(!wqw)) - return; - - if (unlikely(spi_dv_pending(sdev->sdev_target))) { - kfree(wqw); - return; - } - /* Set pending early (dv_device doesn't check it, only sets it) */ - spi_dv_pending(sdev->sdev_target) = 1; - if (unlikely(scsi_device_get(sdev))) { - kfree(wqw); - spi_dv_pending(sdev->sdev_target) = 0; - return; - } - - INIT_WORK(&wqw->work, spi_dv_device_work_wrapper); - wqw->sdev = sdev; - - schedule_work(&wqw->work); -} -EXPORT_SYMBOL(spi_schedule_dv_device); - -/** - * spi_display_xfer_agreement - Print the current target transfer agreement - * @starget: The target for which to display the agreement - * - * Each SPI port is required to maintain a transfer agreement for each - * other port on the bus. This function prints a one-line summary of - * the current agreement; more detailed information is available in sysfs. - */ -void spi_display_xfer_agreement(struct scsi_target *starget) -{ - struct spi_transport_attrs *tp; - tp = (struct spi_transport_attrs *)&starget->starget_data; - - if (tp->offset > 0 && tp->period > 0) { - unsigned int picosec, kb100; - char *scsi = "FAST-?"; - char tmp[8]; - - if (tp->period <= SPI_STATIC_PPR) { - picosec = ppr_to_ps[tp->period]; - switch (tp->period) { - case 7: scsi = "FAST-320"; break; - case 8: scsi = "FAST-160"; break; - case 9: scsi = "FAST-80"; break; - case 10: - case 11: scsi = "FAST-40"; break; - case 12: scsi = "FAST-20"; break; - } - } else { - picosec = tp->period * 4000; - if (tp->period < 25) - scsi = "FAST-20"; - else if (tp->period < 50) - scsi = "FAST-10"; - else - scsi = "FAST-5"; - } - - kb100 = (10000000 + picosec / 2) / picosec; - if (tp->width) - kb100 *= 2; - sprint_frac(tmp, picosec, 1000); - - dev_info(&starget->dev, - "%s %sSCSI %d.%d MB/s %s%s%s%s%s%s%s%s (%s ns, offset %d)\n", - scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10, - tp->dt ? "DT" : "ST", - tp->iu ? " IU" : "", - tp->qas ? " QAS" : "", - tp->rd_strm ? " RDSTRM" : "", - tp->rti ? " RTI" : "", - tp->wr_flow ? " WRFLOW" : "", - tp->pcomp_en ? " PCOMP" : "", - tp->hold_mcs ? " HMCS" : "", - tmp, tp->offset); - } else { - dev_info(&starget->dev, "%sasynchronous\n", - tp->width ? "wide " : ""); - } -} -EXPORT_SYMBOL(spi_display_xfer_agreement); - -int spi_populate_width_msg(unsigned char *msg, int width) -{ - msg[0] = EXTENDED_MESSAGE; - msg[1] = 2; - msg[2] = EXTENDED_WDTR; - msg[3] = width; - return 4; -} -EXPORT_SYMBOL_GPL(spi_populate_width_msg); - -int spi_populate_sync_msg(unsigned char *msg, int period, int offset) -{ - msg[0] = EXTENDED_MESSAGE; - msg[1] = 3; - msg[2] = EXTENDED_SDTR; - msg[3] = period; - msg[4] = offset; - return 5; -} -EXPORT_SYMBOL_GPL(spi_populate_sync_msg); - -int spi_populate_ppr_msg(unsigned char *msg, int period, int offset, - int width, int options) -{ - msg[0] = EXTENDED_MESSAGE; - msg[1] = 6; - msg[2] = EXTENDED_PPR; - msg[3] = period; - msg[4] = 0; - msg[5] = offset; - msg[6] = width; - msg[7] = options; - return 8; -} -EXPORT_SYMBOL_GPL(spi_populate_ppr_msg); - -#ifdef CONFIG_SCSI_CONSTANTS -static const char * const one_byte_msgs[] = { -/* 0x00 */ "Task Complete", NULL /* Extended Message */, "Save Pointers", -/* 0x03 */ "Restore Pointers", "Disconnect", "Initiator Error", -/* 0x06 */ "Abort Task Set", "Message Reject", "Nop", "Message Parity Error", -/* 0x0a */ "Linked Command Complete", "Linked Command Complete w/flag", -/* 0x0c */ "Target Reset", "Abort Task", "Clear Task Set", -/* 0x0f */ "Initiate Recovery", "Release Recovery", -/* 0x11 */ "Terminate Process", "Continue Task", "Target Transfer Disable", -/* 0x14 */ NULL, NULL, "Clear ACA", "LUN Reset" -}; - -static const char * const two_byte_msgs[] = { -/* 0x20 */ "Simple Queue Tag", "Head of Queue Tag", "Ordered Queue Tag", -/* 0x23 */ "Ignore Wide Residue", "ACA" -}; - -static const char * const extended_msgs[] = { -/* 0x00 */ "Modify Data Pointer", "Synchronous Data Transfer Request", -/* 0x02 */ "SCSI-I Extended Identify", "Wide Data Transfer Request", -/* 0x04 */ "Parallel Protocol Request", "Modify Bidirectional Data Pointer" -}; - -static void print_nego(const unsigned char *msg, int per, int off, int width) -{ - if (per) { - char buf[20]; - period_to_str(buf, msg[per]); - printk("period = %s ns ", buf); - } - - if (off) - printk("offset = %d ", msg[off]); - if (width) - printk("width = %d ", 8 << msg[width]); -} - -static void print_ptr(const unsigned char *msg, int msb, const char *desc) -{ - int ptr = (msg[msb] << 24) | (msg[msb+1] << 16) | (msg[msb+2] << 8) | - msg[msb+3]; - printk("%s = %d ", desc, ptr); -} - -int spi_print_msg(const unsigned char *msg) -{ - int len = 1, i; - if (msg[0] == EXTENDED_MESSAGE) { - len = 2 + msg[1]; - if (len == 2) - len += 256; - if (msg[2] < ARRAY_SIZE(extended_msgs)) - printk ("%s ", extended_msgs[msg[2]]); - else - printk ("Extended Message, reserved code (0x%02x) ", - (int) msg[2]); - switch (msg[2]) { - case EXTENDED_MODIFY_DATA_POINTER: - print_ptr(msg, 3, "pointer"); - break; - case EXTENDED_SDTR: - print_nego(msg, 3, 4, 0); - break; - case EXTENDED_WDTR: - print_nego(msg, 0, 0, 3); - break; - case EXTENDED_PPR: - print_nego(msg, 3, 5, 6); - break; - case EXTENDED_MODIFY_BIDI_DATA_PTR: - print_ptr(msg, 3, "out"); - print_ptr(msg, 7, "in"); - break; - default: - for (i = 2; i < len; ++i) - printk("%02x ", msg[i]); - } - /* Identify */ - } else if (msg[0] & 0x80) { - printk("Identify disconnect %sallowed %s %d ", - (msg[0] & 0x40) ? "" : "not ", - (msg[0] & 0x20) ? "target routine" : "lun", - msg[0] & 0x7); - /* Normal One byte */ - } else if (msg[0] < 0x1f) { - if (msg[0] < ARRAY_SIZE(one_byte_msgs) && one_byte_msgs[msg[0]]) - printk("%s ", one_byte_msgs[msg[0]]); - else - printk("reserved (%02x) ", msg[0]); - } else if (msg[0] == 0x55) { - printk("QAS Request "); - /* Two byte */ - } else if (msg[0] <= 0x2f) { - if ((msg[0] - 0x20) < ARRAY_SIZE(two_byte_msgs)) - printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], - msg[1]); - else - printk("reserved two byte (%02x %02x) ", - msg[0], msg[1]); - len = 2; - } else - printk("reserved "); - return len; -} -EXPORT_SYMBOL(spi_print_msg); - -#else /* ifndef CONFIG_SCSI_CONSTANTS */ - -int spi_print_msg(const unsigned char *msg) -{ - int len = 1, i; - - if (msg[0] == EXTENDED_MESSAGE) { - len = 2 + msg[1]; - if (len == 2) - len += 256; - for (i = 0; i < len; ++i) - printk("%02x ", msg[i]); - /* Identify */ - } else if (msg[0] & 0x80) { - printk("%02x ", msg[0]); - /* Normal One byte */ - } else if ((msg[0] < 0x1f) || (msg[0] == 0x55)) { - printk("%02x ", msg[0]); - /* Two byte */ - } else if (msg[0] <= 0x2f) { - printk("%02x %02x", msg[0], msg[1]); - len = 2; - } else - printk("%02x ", msg[0]); - return len; -} -EXPORT_SYMBOL(spi_print_msg); -#endif /* ! CONFIG_SCSI_CONSTANTS */ - -static int spi_device_match(struct attribute_container *cont, - struct device *dev) -{ - struct scsi_device *sdev; - struct Scsi_Host *shost; - struct spi_internal *i; - - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - shost = sdev->host; - if (!shost->transportt || shost->transportt->host_attrs.ac.class - != &spi_host_class.class) - return 0; - /* Note: this class has no device attributes, so it has - * no per-HBA allocation and thus we don't need to distinguish - * the attribute containers for the device */ - i = to_spi_internal(shost->transportt); - if (i->f->deny_binding && i->f->deny_binding(sdev->sdev_target)) - return 0; - return 1; -} - -static int spi_target_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct scsi_target *starget; - struct spi_internal *i; - - if (!scsi_is_target_device(dev)) - return 0; - - shost = dev_to_shost(dev->parent); - if (!shost->transportt || shost->transportt->host_attrs.ac.class - != &spi_host_class.class) - return 0; - - i = to_spi_internal(shost->transportt); - starget = to_scsi_target(dev); - - if (i->f->deny_binding && i->f->deny_binding(starget)) - return 0; - - return &i->t.target_attrs.ac == cont; -} - -static DECLARE_TRANSPORT_CLASS(spi_transport_class, - "spi_transport", - spi_setup_transport_attrs, - NULL, - spi_target_configure); - -static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class, - spi_device_match, - spi_device_configure); - -static struct attribute *host_attributes[] = { - &dev_attr_signalling.attr, - &dev_attr_host_width.attr, - &dev_attr_hba_id.attr, - NULL -}; - -static struct attribute_group host_attribute_group = { - .attrs = host_attributes, -}; - -static int spi_host_configure(struct transport_container *tc, - struct device *dev, - struct device *cdev) -{ - struct kobject *kobj = &cdev->kobj; - struct Scsi_Host *shost = transport_class_to_shost(cdev); - struct spi_internal *si = to_spi_internal(shost->transportt); - struct attribute *attr = &dev_attr_signalling.attr; - int rc = 0; - - if (si->f->set_signalling) - rc = sysfs_chmod_file(kobj, attr, attr->mode | S_IWUSR); - - return rc; -} - -/* returns true if we should be showing the variable. Also - * overloads the return by setting 1<<1 if the attribute should - * be writeable */ -#define TARGET_ATTRIBUTE_HELPER(name) \ - (si->f->show_##name ? S_IRUGO : 0) | \ - (si->f->set_##name ? S_IWUSR : 0) - -static umode_t target_attribute_is_visible(struct kobject *kobj, - struct attribute *attr, int i) -{ - struct device *cdev = container_of(kobj, struct device, kobj); - struct scsi_target *starget = transport_class_to_starget(cdev); - struct Scsi_Host *shost = transport_class_to_shost(cdev); - struct spi_internal *si = to_spi_internal(shost->transportt); - - if (attr == &dev_attr_period.attr && - spi_support_sync(starget)) - return TARGET_ATTRIBUTE_HELPER(period); - else if (attr == &dev_attr_min_period.attr && - spi_support_sync(starget)) - return TARGET_ATTRIBUTE_HELPER(period); - else if (attr == &dev_attr_offset.attr && - spi_support_sync(starget)) - return TARGET_ATTRIBUTE_HELPER(offset); - else if (attr == &dev_attr_max_offset.attr && - spi_support_sync(starget)) - return TARGET_ATTRIBUTE_HELPER(offset); - else if (attr == &dev_attr_width.attr && - spi_support_wide(starget)) - return TARGET_ATTRIBUTE_HELPER(width); - else if (attr == &dev_attr_max_width.attr && - spi_support_wide(starget)) - return TARGET_ATTRIBUTE_HELPER(width); - else if (attr == &dev_attr_iu.attr && - spi_support_ius(starget)) - return TARGET_ATTRIBUTE_HELPER(iu); - else if (attr == &dev_attr_max_iu.attr && - spi_support_ius(starget)) - return TARGET_ATTRIBUTE_HELPER(iu); - else if (attr == &dev_attr_dt.attr && - spi_support_dt(starget)) - return TARGET_ATTRIBUTE_HELPER(dt); - else if (attr == &dev_attr_qas.attr && - spi_support_qas(starget)) - return TARGET_ATTRIBUTE_HELPER(qas); - else if (attr == &dev_attr_max_qas.attr && - spi_support_qas(starget)) - return TARGET_ATTRIBUTE_HELPER(qas); - else if (attr == &dev_attr_wr_flow.attr && - spi_support_ius(starget)) - return TARGET_ATTRIBUTE_HELPER(wr_flow); - else if (attr == &dev_attr_rd_strm.attr && - spi_support_ius(starget)) - return TARGET_ATTRIBUTE_HELPER(rd_strm); - else if (attr == &dev_attr_rti.attr && - spi_support_ius(starget)) - return TARGET_ATTRIBUTE_HELPER(rti); - else if (attr == &dev_attr_pcomp_en.attr && - spi_support_ius(starget)) - return TARGET_ATTRIBUTE_HELPER(pcomp_en); - else if (attr == &dev_attr_hold_mcs.attr && - spi_support_ius(starget)) - return TARGET_ATTRIBUTE_HELPER(hold_mcs); - else if (attr == &dev_attr_revalidate.attr) - return S_IWUSR; - - return 0; -} - -static struct attribute *target_attributes[] = { - &dev_attr_period.attr, - &dev_attr_min_period.attr, - &dev_attr_offset.attr, - &dev_attr_max_offset.attr, - &dev_attr_width.attr, - &dev_attr_max_width.attr, - &dev_attr_iu.attr, - &dev_attr_max_iu.attr, - &dev_attr_dt.attr, - &dev_attr_qas.attr, - &dev_attr_max_qas.attr, - &dev_attr_wr_flow.attr, - &dev_attr_rd_strm.attr, - &dev_attr_rti.attr, - &dev_attr_pcomp_en.attr, - &dev_attr_hold_mcs.attr, - &dev_attr_revalidate.attr, - NULL -}; - -static struct attribute_group target_attribute_group = { - .attrs = target_attributes, - .is_visible = target_attribute_is_visible, -}; - -static int spi_target_configure(struct transport_container *tc, - struct device *dev, - struct device *cdev) -{ - struct kobject *kobj = &cdev->kobj; - - /* force an update based on parameters read from the device */ - sysfs_update_group(kobj, &target_attribute_group); - - return 0; -} - -struct scsi_transport_template * -spi_attach_transport(struct spi_function_template *ft) -{ - struct spi_internal *i = kzalloc(sizeof(struct spi_internal), - GFP_KERNEL); - - if (unlikely(!i)) - return NULL; - - i->t.target_attrs.ac.class = &spi_transport_class.class; - i->t.target_attrs.ac.grp = &target_attribute_group; - i->t.target_attrs.ac.match = spi_target_match; - transport_container_register(&i->t.target_attrs); - i->t.target_size = sizeof(struct spi_transport_attrs); - i->t.host_attrs.ac.class = &spi_host_class.class; - i->t.host_attrs.ac.grp = &host_attribute_group; - i->t.host_attrs.ac.match = spi_host_match; - transport_container_register(&i->t.host_attrs); - i->t.host_size = sizeof(struct spi_host_attrs); - i->f = ft; - - return &i->t; -} -EXPORT_SYMBOL(spi_attach_transport); - -void spi_release_transport(struct scsi_transport_template *t) -{ - struct spi_internal *i = to_spi_internal(t); - - transport_container_unregister(&i->t.target_attrs); - transport_container_unregister(&i->t.host_attrs); - - kfree(i); -} -EXPORT_SYMBOL(spi_release_transport); - -static __init int spi_transport_init(void) -{ - int error = scsi_dev_info_add_list(SCSI_DEVINFO_SPI, - "SCSI Parallel Transport Class"); - if (!error) { - int i; - - for (i = 0; spi_static_device_list[i].vendor; i++) - scsi_dev_info_list_add_keyed(1, /* compatible */ - spi_static_device_list[i].vendor, - spi_static_device_list[i].model, - NULL, - spi_static_device_list[i].flags, - SCSI_DEVINFO_SPI); - } - - error = transport_class_register(&spi_transport_class); - if (error) - return error; - error = anon_transport_class_register(&spi_device_class); - return transport_class_register(&spi_host_class); -} - -static void __exit spi_transport_exit(void) -{ - transport_class_unregister(&spi_transport_class); - anon_transport_class_unregister(&spi_device_class); - transport_class_unregister(&spi_host_class); - scsi_dev_info_remove_list(SCSI_DEVINFO_SPI); -} - -MODULE_AUTHOR("Martin Hicks"); -MODULE_DESCRIPTION("SPI Transport Attributes"); -MODULE_LICENSE("GPL"); - -module_init(spi_transport_init); -module_exit(spi_transport_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_transport_srp.c b/ANDROID_3.4.5/drivers/scsi/scsi_transport_srp.c deleted file mode 100644 index 21a045e0..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_transport_srp.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - * SCSI RDMA (SRP) transport class - * - * Copyright (C) 2007 FUJITA Tomonori - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "scsi_transport_srp_internal.h" - -struct srp_host_attrs { - atomic_t next_port_id; -}; -#define to_srp_host_attrs(host) ((struct srp_host_attrs *)(host)->shost_data) - -#define SRP_HOST_ATTRS 0 -#define SRP_RPORT_ATTRS 2 - -struct srp_internal { - struct scsi_transport_template t; - struct srp_function_template *f; - - struct device_attribute *host_attrs[SRP_HOST_ATTRS + 1]; - - struct device_attribute *rport_attrs[SRP_RPORT_ATTRS + 1]; - struct device_attribute private_rport_attrs[SRP_RPORT_ATTRS]; - struct transport_container rport_attr_cont; -}; - -#define to_srp_internal(tmpl) container_of(tmpl, struct srp_internal, t) - -#define dev_to_rport(d) container_of(d, struct srp_rport, dev) -#define transport_class_to_srp_rport(dev) dev_to_rport((dev)->parent) - -static int srp_host_setup(struct transport_container *tc, struct device *dev, - struct device *cdev) -{ - struct Scsi_Host *shost = dev_to_shost(dev); - struct srp_host_attrs *srp_host = to_srp_host_attrs(shost); - - atomic_set(&srp_host->next_port_id, 0); - return 0; -} - -static DECLARE_TRANSPORT_CLASS(srp_host_class, "srp_host", srp_host_setup, - NULL, NULL); - -static DECLARE_TRANSPORT_CLASS(srp_rport_class, "srp_remote_ports", - NULL, NULL, NULL); - -#define SETUP_TEMPLATE(attrb, field, perm, test, ro_test, ro_perm) \ - i->private_##attrb[count] = dev_attr_##field; \ - i->private_##attrb[count].attr.mode = perm; \ - if (ro_test) { \ - i->private_##attrb[count].attr.mode = ro_perm; \ - i->private_##attrb[count].store = NULL; \ - } \ - i->attrb[count] = &i->private_##attrb[count]; \ - if (test) \ - count++ - -#define SETUP_RPORT_ATTRIBUTE_RD(field) \ - SETUP_TEMPLATE(rport_attrs, field, S_IRUGO, 1, 0, 0) - -#define SETUP_RPORT_ATTRIBUTE_RW(field) \ - SETUP_TEMPLATE(rport_attrs, field, S_IRUGO | S_IWUSR, \ - 1, 1, S_IRUGO) - -#define SRP_PID(p) \ - (p)->port_id[0], (p)->port_id[1], (p)->port_id[2], (p)->port_id[3], \ - (p)->port_id[4], (p)->port_id[5], (p)->port_id[6], (p)->port_id[7], \ - (p)->port_id[8], (p)->port_id[9], (p)->port_id[10], (p)->port_id[11], \ - (p)->port_id[12], (p)->port_id[13], (p)->port_id[14], (p)->port_id[15] - -#define SRP_PID_FMT "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:" \ - "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x" - -static ssize_t -show_srp_rport_id(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct srp_rport *rport = transport_class_to_srp_rport(dev); - return sprintf(buf, SRP_PID_FMT "\n", SRP_PID(rport)); -} - -static DEVICE_ATTR(port_id, S_IRUGO, show_srp_rport_id, NULL); - -static const struct { - u32 value; - char *name; -} srp_rport_role_names[] = { - {SRP_RPORT_ROLE_INITIATOR, "SRP Initiator"}, - {SRP_RPORT_ROLE_TARGET, "SRP Target"}, -}; - -static ssize_t -show_srp_rport_roles(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct srp_rport *rport = transport_class_to_srp_rport(dev); - int i; - char *name = NULL; - - for (i = 0; i < ARRAY_SIZE(srp_rport_role_names); i++) - if (srp_rport_role_names[i].value == rport->roles) { - name = srp_rport_role_names[i].name; - break; - } - return sprintf(buf, "%s\n", name ? : "unknown"); -} - -static DEVICE_ATTR(roles, S_IRUGO, show_srp_rport_roles, NULL); - -static void srp_rport_release(struct device *dev) -{ - struct srp_rport *rport = dev_to_rport(dev); - - put_device(dev->parent); - kfree(rport); -} - -static int scsi_is_srp_rport(const struct device *dev) -{ - return dev->release == srp_rport_release; -} - -static int srp_rport_match(struct attribute_container *cont, - struct device *dev) -{ - struct Scsi_Host *shost; - struct srp_internal *i; - - if (!scsi_is_srp_rport(dev)) - return 0; - - shost = dev_to_shost(dev->parent); - if (!shost->transportt) - return 0; - if (shost->transportt->host_attrs.ac.class != &srp_host_class.class) - return 0; - - i = to_srp_internal(shost->transportt); - return &i->rport_attr_cont.ac == cont; -} - -static int srp_host_match(struct attribute_container *cont, struct device *dev) -{ - struct Scsi_Host *shost; - struct srp_internal *i; - - if (!scsi_is_host_device(dev)) - return 0; - - shost = dev_to_shost(dev); - if (!shost->transportt) - return 0; - if (shost->transportt->host_attrs.ac.class != &srp_host_class.class) - return 0; - - i = to_srp_internal(shost->transportt); - return &i->t.host_attrs.ac == cont; -} - -/** - * srp_rport_add - add a SRP remote port to the device hierarchy - * @shost: scsi host the remote port is connected to. - * @ids: The port id for the remote port. - * - * Publishes a port to the rest of the system. - */ -struct srp_rport *srp_rport_add(struct Scsi_Host *shost, - struct srp_rport_identifiers *ids) -{ - struct srp_rport *rport; - struct device *parent = &shost->shost_gendev; - int id, ret; - - rport = kzalloc(sizeof(*rport), GFP_KERNEL); - if (!rport) - return ERR_PTR(-ENOMEM); - - device_initialize(&rport->dev); - - rport->dev.parent = get_device(parent); - rport->dev.release = srp_rport_release; - - memcpy(rport->port_id, ids->port_id, sizeof(rport->port_id)); - rport->roles = ids->roles; - - id = atomic_inc_return(&to_srp_host_attrs(shost)->next_port_id); - dev_set_name(&rport->dev, "port-%d:%d", shost->host_no, id); - - transport_setup_device(&rport->dev); - - ret = device_add(&rport->dev); - if (ret) { - transport_destroy_device(&rport->dev); - put_device(&rport->dev); - return ERR_PTR(ret); - } - - if (shost->active_mode & MODE_TARGET && - ids->roles == SRP_RPORT_ROLE_INITIATOR) { - ret = srp_tgt_it_nexus_create(shost, (unsigned long)rport, - rport->port_id); - if (ret) { - device_del(&rport->dev); - transport_destroy_device(&rport->dev); - put_device(&rport->dev); - return ERR_PTR(ret); - } - } - - transport_add_device(&rport->dev); - transport_configure_device(&rport->dev); - - return rport; -} -EXPORT_SYMBOL_GPL(srp_rport_add); - -/** - * srp_rport_del - remove a SRP remote port - * @rport: SRP remote port to remove - * - * Removes the specified SRP remote port. - */ -void srp_rport_del(struct srp_rport *rport) -{ - struct device *dev = &rport->dev; - struct Scsi_Host *shost = dev_to_shost(dev->parent); - - if (shost->active_mode & MODE_TARGET && - rport->roles == SRP_RPORT_ROLE_INITIATOR) - srp_tgt_it_nexus_destroy(shost, (unsigned long)rport); - - transport_remove_device(dev); - device_del(dev); - transport_destroy_device(dev); - put_device(dev); -} -EXPORT_SYMBOL_GPL(srp_rport_del); - -static int do_srp_rport_del(struct device *dev, void *data) -{ - if (scsi_is_srp_rport(dev)) - srp_rport_del(dev_to_rport(dev)); - return 0; -} - -/** - * srp_remove_host - tear down a Scsi_Host's SRP data structures - * @shost: Scsi Host that is torn down - * - * Removes all SRP remote ports for a given Scsi_Host. - * Must be called just before scsi_remove_host for SRP HBAs. - */ -void srp_remove_host(struct Scsi_Host *shost) -{ - device_for_each_child(&shost->shost_gendev, NULL, do_srp_rport_del); -} -EXPORT_SYMBOL_GPL(srp_remove_host); - -static int srp_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id, - int result) -{ - struct srp_internal *i = to_srp_internal(shost->transportt); - return i->f->tsk_mgmt_response(shost, nexus, tm_id, result); -} - -static int srp_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result) -{ - struct srp_internal *i = to_srp_internal(shost->transportt); - return i->f->it_nexus_response(shost, nexus, result); -} - -/** - * srp_attach_transport - instantiate SRP transport template - * @ft: SRP transport class function template - */ -struct scsi_transport_template * -srp_attach_transport(struct srp_function_template *ft) -{ - int count; - struct srp_internal *i; - - i = kzalloc(sizeof(*i), GFP_KERNEL); - if (!i) - return NULL; - - i->t.tsk_mgmt_response = srp_tsk_mgmt_response; - i->t.it_nexus_response = srp_it_nexus_response; - - i->t.host_size = sizeof(struct srp_host_attrs); - i->t.host_attrs.ac.attrs = &i->host_attrs[0]; - i->t.host_attrs.ac.class = &srp_host_class.class; - i->t.host_attrs.ac.match = srp_host_match; - i->host_attrs[0] = NULL; - transport_container_register(&i->t.host_attrs); - - i->rport_attr_cont.ac.attrs = &i->rport_attrs[0]; - i->rport_attr_cont.ac.class = &srp_rport_class.class; - i->rport_attr_cont.ac.match = srp_rport_match; - transport_container_register(&i->rport_attr_cont); - - count = 0; - SETUP_RPORT_ATTRIBUTE_RD(port_id); - SETUP_RPORT_ATTRIBUTE_RD(roles); - i->rport_attrs[count] = NULL; - - i->f = ft; - - return &i->t; -} -EXPORT_SYMBOL_GPL(srp_attach_transport); - -/** - * srp_release_transport - release SRP transport template instance - * @t: transport template instance - */ -void srp_release_transport(struct scsi_transport_template *t) -{ - struct srp_internal *i = to_srp_internal(t); - - transport_container_unregister(&i->t.host_attrs); - transport_container_unregister(&i->rport_attr_cont); - - kfree(i); -} -EXPORT_SYMBOL_GPL(srp_release_transport); - -static __init int srp_transport_init(void) -{ - int ret; - - ret = transport_class_register(&srp_host_class); - if (ret) - return ret; - ret = transport_class_register(&srp_rport_class); - if (ret) - goto unregister_host_class; - - return 0; -unregister_host_class: - transport_class_unregister(&srp_host_class); - return ret; -} - -static void __exit srp_transport_exit(void) -{ - transport_class_unregister(&srp_host_class); - transport_class_unregister(&srp_rport_class); -} - -MODULE_AUTHOR("FUJITA Tomonori"); -MODULE_DESCRIPTION("SRP Transport Attributes"); -MODULE_LICENSE("GPL"); - -module_init(srp_transport_init); -module_exit(srp_transport_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_transport_srp_internal.h b/ANDROID_3.4.5/drivers/scsi/scsi_transport_srp_internal.h deleted file mode 100644 index 8a79747f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_transport_srp_internal.h +++ /dev/null @@ -1,25 +0,0 @@ -#include - -#ifdef CONFIG_SCSI_SRP_TGT_ATTRS -static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, - char *initiator) -{ - return scsi_tgt_it_nexus_create(shost, itn_id, initiator); -} - -static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) -{ - return scsi_tgt_it_nexus_destroy(shost, itn_id); -} - -#else -static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, - char *initiator) -{ - return 0; -} -static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) -{ - return 0; -} -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_typedefs.h b/ANDROID_3.4.5/drivers/scsi/scsi_typedefs.h deleted file mode 100644 index 2ed4c5cb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_typedefs.h +++ /dev/null @@ -1,2 +0,0 @@ - -typedef struct scsi_cmnd Scsi_Cmnd; diff --git a/ANDROID_3.4.5/drivers/scsi/scsi_wait_scan.c b/ANDROID_3.4.5/drivers/scsi/scsi_wait_scan.c deleted file mode 100644 index ae781487..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsi_wait_scan.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * scsi_wait_scan.c - * - * Copyright (C) 2006 James Bottomley - * - * This is a simple module to wait until all the async scans are - * complete. The idea is to use it in initrd/initramfs scripts. You - * modprobe it after all the modprobes of the root SCSI drivers and it - * will wait until they have all finished scanning their busses before - * allowing the boot to proceed - */ - -#include -#include -#include "scsi_priv.h" - -static int __init wait_scan_init(void) -{ - /* - * First we need to wait for device probing to finish; - * the drivers we just loaded might just still be probing - * and might not yet have reached the scsi async scanning - */ - wait_for_device_probe(); - /* - * and then we wait for the actual asynchronous scsi scan - * to finish. - */ - scsi_complete_async_scans(); - return 0; -} - -static void __exit wait_scan_exit(void) -{ -} - -MODULE_DESCRIPTION("SCSI wait for scans"); -MODULE_AUTHOR("James Bottomley"); -MODULE_LICENSE("GPL"); - -late_initcall(wait_scan_init); -module_exit(wait_scan_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/scsicam.c b/ANDROID_3.4.5/drivers/scsi/scsicam.c deleted file mode 100644 index 92d24d6d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/scsicam.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * scsicam.c - SCSI CAM support functions, use for HDIO_GETGEO, etc. - * - * Copyright 1993, 1994 Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@Colorado.EDU - * +1 (303) 786-7975 - * - * For more information, please consult the SCSI-CAM draft. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - - -static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, - unsigned int *secs); - -/** - * scsi_bios_ptable - Read PC partition table out of first sector of device. - * @dev: from this device - * - * Description: Reads the first sector from the device and returns %0x42 bytes - * starting at offset %0x1be. - * Returns: partition table in kmalloc(GFP_KERNEL) memory, or NULL on error. - */ -unsigned char *scsi_bios_ptable(struct block_device *dev) -{ - unsigned char *res = kmalloc(66, GFP_KERNEL); - if (res) { - struct block_device *bdev = dev->bd_contains; - Sector sect; - void *data = read_dev_sector(bdev, 0, §); - if (data) { - memcpy(res, data + 0x1be, 66); - put_dev_sector(sect); - } else { - kfree(res); - res = NULL; - } - } - return res; -} -EXPORT_SYMBOL(scsi_bios_ptable); - -/** - * scsicam_bios_param - Determine geometry of a disk in cylinders/heads/sectors. - * @bdev: which device - * @capacity: size of the disk in sectors - * @ip: return value: ip[0]=heads, ip[1]=sectors, ip[2]=cylinders - * - * Description : determine the BIOS mapping/geometry used for a drive in a - * SCSI-CAM system, storing the results in ip as required - * by the HDIO_GETGEO ioctl(). - * - * Returns : -1 on failure, 0 on success. - */ - -int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip) -{ - unsigned char *p; - u64 capacity64 = capacity; /* Suppress gcc warning */ - int ret; - - p = scsi_bios_ptable(bdev); - if (!p) - return -1; - - /* try to infer mapping from partition table */ - ret = scsi_partsize(p, (unsigned long)capacity, (unsigned int *)ip + 2, - (unsigned int *)ip + 0, (unsigned int *)ip + 1); - kfree(p); - - if (ret == -1 && capacity64 < (1ULL << 32)) { - /* pick some standard mapping with at most 1024 cylinders, - and at most 62 sectors per track - this works up to - 7905 MB */ - ret = setsize((unsigned long)capacity, (unsigned int *)ip + 2, - (unsigned int *)ip + 0, (unsigned int *)ip + 1); - } - - /* if something went wrong, then apparently we have to return - a geometry with more than 1024 cylinders */ - if (ret || ip[0] > 255 || ip[1] > 63) { - if ((capacity >> 11) > 65534) { - ip[0] = 255; - ip[1] = 63; - } else { - ip[0] = 64; - ip[1] = 32; - } - - if (capacity > 65535*63*255) - ip[2] = 65535; - else - ip[2] = (unsigned long)capacity / (ip[0] * ip[1]); - } - - return 0; -} -EXPORT_SYMBOL(scsicam_bios_param); - -/** - * scsi_partsize - Parse cylinders/heads/sectors from PC partition table - * @buf: partition table, see scsi_bios_ptable() - * @capacity: size of the disk in sectors - * @cyls: put cylinders here - * @hds: put heads here - * @secs: put sectors here - * - * Description: determine the BIOS mapping/geometry used to create the partition - * table, storing the results in *cyls, *hds, and *secs - * - * Returns: -1 on failure, 0 on success. - */ - -int scsi_partsize(unsigned char *buf, unsigned long capacity, - unsigned int *cyls, unsigned int *hds, unsigned int *secs) -{ - struct partition *p = (struct partition *)buf, *largest = NULL; - int i, largest_cyl; - int cyl, ext_cyl, end_head, end_cyl, end_sector; - unsigned int logical_end, physical_end, ext_physical_end; - - - if (*(unsigned short *) (buf + 64) == 0xAA55) { - for (largest_cyl = -1, i = 0; i < 4; ++i, ++p) { - if (!p->sys_ind) - continue; -#ifdef DEBUG - printk("scsicam_bios_param : partition %d has system \n", - i); -#endif - cyl = p->cyl + ((p->sector & 0xc0) << 2); - if (cyl > largest_cyl) { - largest_cyl = cyl; - largest = p; - } - } - } - if (largest) { - end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2); - end_head = largest->end_head; - end_sector = largest->end_sector & 0x3f; - - if (end_head + 1 == 0 || end_sector == 0) - return -1; - -#ifdef DEBUG - printk("scsicam_bios_param : end at h = %d, c = %d, s = %d\n", - end_head, end_cyl, end_sector); -#endif - - physical_end = end_cyl * (end_head + 1) * end_sector + - end_head * end_sector + end_sector; - - /* This is the actual _sector_ number at the end */ - logical_end = get_unaligned(&largest->start_sect) - + get_unaligned(&largest->nr_sects); - - /* This is for >1023 cylinders */ - ext_cyl = (logical_end - (end_head * end_sector + end_sector)) - / (end_head + 1) / end_sector; - ext_physical_end = ext_cyl * (end_head + 1) * end_sector + - end_head * end_sector + end_sector; - -#ifdef DEBUG - printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n" - ,logical_end, physical_end, ext_physical_end, ext_cyl); -#endif - - if ((logical_end == physical_end) || - (end_cyl == 1023 && ext_physical_end == logical_end)) { - *secs = end_sector; - *hds = end_head + 1; - *cyls = capacity / ((end_head + 1) * end_sector); - return 0; - } -#ifdef DEBUG - printk("scsicam_bios_param : logical (%u) != physical (%u)\n", - logical_end, physical_end); -#endif - } - return -1; -} -EXPORT_SYMBOL(scsi_partsize); - -/* - * Function : static int setsize(unsigned long capacity,unsigned int *cyls, - * unsigned int *hds, unsigned int *secs); - * - * Purpose : to determine a near-optimal int 0x13 mapping for a - * SCSI disk in terms of lost space of size capacity, storing - * the results in *cyls, *hds, and *secs. - * - * Returns : -1 on failure, 0 on success. - * - * Extracted from - * - * WORKING X3T9.2 - * DRAFT 792D - * see http://www.t10.org/ftp/t10/drafts/cam/cam-r12b.pdf - * - * Revision 6 - * 10-MAR-94 - * Information technology - - * SCSI-2 Common access method - * transport and SCSI interface module - * - * ANNEX A : - * - * setsize() converts a read capacity value to int 13h - * head-cylinder-sector requirements. It minimizes the value for - * number of heads and maximizes the number of cylinders. This - * will support rather large disks before the number of heads - * will not fit in 4 bits (or 6 bits). This algorithm also - * minimizes the number of sectors that will be unused at the end - * of the disk while allowing for very large disks to be - * accommodated. This algorithm does not use physical geometry. - */ - -static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, - unsigned int *secs) -{ - unsigned int rv = 0; - unsigned long heads, sectors, cylinders, temp; - - cylinders = 1024L; /* Set number of cylinders to max */ - sectors = 62L; /* Maximize sectors per track */ - - temp = cylinders * sectors; /* Compute divisor for heads */ - heads = capacity / temp; /* Compute value for number of heads */ - if (capacity % temp) { /* If no remainder, done! */ - heads++; /* Else, increment number of heads */ - temp = cylinders * heads; /* Compute divisor for sectors */ - sectors = capacity / temp; /* Compute value for sectors per - track */ - if (capacity % temp) { /* If no remainder, done! */ - sectors++; /* Else, increment number of sectors */ - temp = heads * sectors; /* Compute divisor for cylinders */ - cylinders = capacity / temp; /* Compute number of cylinders */ - } - } - if (cylinders == 0) - rv = (unsigned) -1; /* Give error if 0 cylinders */ - - *cyls = (unsigned int) cylinders; /* Stuff return values */ - *secs = (unsigned int) sectors; - *hds = (unsigned int) heads; - return (rv); -} diff --git a/ANDROID_3.4.5/drivers/scsi/sd.c b/ANDROID_3.4.5/drivers/scsi/sd.c deleted file mode 100644 index a239382b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sd.c +++ /dev/null @@ -1,2990 +0,0 @@ -/* - * sd.c Copyright (C) 1992 Drew Eckhardt - * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale - * - * Linux scsi disk driver - * Initial versions: Drew Eckhardt - * Subsequent revisions: Eric Youngdale - * Modification history: - * - Drew Eckhardt original - * - Eric Youngdale add scatter-gather, multiple - * outstanding request, and other enhancements. - * Support loadable low-level scsi drivers. - * - Jirka Hanika support more scsi disks using - * eight major numbers. - * - Richard Gooch support devfs. - * - Torben Mathiasen Resource allocation fixes in - * sd_init and cleanups. - * - Alex Davis Fix problem where partition info - * not being read in sd_open. Fix problem where removable media - * could be ejected after sd_open. - * - Douglas Gilbert cleanup for lk 2.5.x - * - Badari Pulavarty , Matthew Wilcox - * , Kurt Garloff : - * Support 32k/1M disks. - * - * Logging policy (needs CONFIG_SCSI_LOGGING defined): - * - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2 - * - end of transfer (bh + scsi_lib): SCSI_LOG_HLCOMPLETE level 1 - * - entering sd_ioctl: SCSI_LOG_IOCTL level 1 - * - entering other commands: SCSI_LOG_HLQUEUE level 3 - * Note: when the logging level is set by the user, it must be greater - * than the level indicated above to trigger output. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sd.h" -#include "scsi_logging.h" - -MODULE_AUTHOR("Eric Youngdale"); -MODULE_DESCRIPTION("SCSI disk (sd) driver"); -MODULE_LICENSE("GPL"); - -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK0_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK1_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK2_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK3_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK4_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK5_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK6_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK7_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK8_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK9_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK10_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK11_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK); -MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD); -MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC); - -#if !defined(CONFIG_DEBUG_BLOCK_EXT_DEVT) -#define SD_MINORS 16 -#else -#define SD_MINORS 0 -#endif - -static void sd_config_discard(struct scsi_disk *, unsigned int); -static int sd_revalidate_disk(struct gendisk *); -static void sd_unlock_native_capacity(struct gendisk *disk); -static int sd_probe(struct device *); -static int sd_remove(struct device *); -static void sd_shutdown(struct device *); -static int sd_suspend(struct device *, pm_message_t state); -static int sd_resume(struct device *); -static void sd_rescan(struct device *); -static int sd_done(struct scsi_cmnd *); -static int sd_eh_action(struct scsi_cmnd *, unsigned char *, int, int); -static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer); -static void scsi_disk_release(struct device *cdev); -static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *); -static void sd_print_result(struct scsi_disk *, int); - -static DEFINE_SPINLOCK(sd_index_lock); -static DEFINE_IDA(sd_index_ida); - -/* This semaphore is used to mediate the 0->1 reference get in the - * face of object destruction (i.e. we can't allow a get on an - * object after last put) */ -static DEFINE_MUTEX(sd_ref_mutex); - -static struct kmem_cache *sd_cdb_cache; -static mempool_t *sd_cdb_pool; - -static const char *sd_cache_types[] = { - "write through", "none", "write back", - "write back, no read (daft)" -}; - -static ssize_t -sd_store_cache_type(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - int i, ct = -1, rcd, wce, sp; - struct scsi_disk *sdkp = to_scsi_disk(dev); - struct scsi_device *sdp = sdkp->device; - char buffer[64]; - char *buffer_data; - struct scsi_mode_data data; - struct scsi_sense_hdr sshdr; - int len; - - if (sdp->type != TYPE_DISK) - /* no cache control on RBC devices; theoretically they - * can do it, but there's probably so many exceptions - * it's not worth the risk */ - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) { - len = strlen(sd_cache_types[i]); - if (strncmp(sd_cache_types[i], buf, len) == 0 && - buf[len] == '\n') { - ct = i; - break; - } - } - if (ct < 0) - return -EINVAL; - rcd = ct & 0x01 ? 1 : 0; - wce = ct & 0x02 ? 1 : 0; - if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT, - SD_MAX_RETRIES, &data, NULL)) - return -EINVAL; - len = min_t(size_t, sizeof(buffer), data.length - data.header_length - - data.block_descriptor_length); - buffer_data = buffer + data.header_length + - data.block_descriptor_length; - buffer_data[2] &= ~0x05; - buffer_data[2] |= wce << 2 | rcd; - sp = buffer_data[0] & 0x80 ? 1 : 0; - - if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, - SD_MAX_RETRIES, &data, &sshdr)) { - if (scsi_sense_valid(&sshdr)) - sd_print_sense_hdr(sdkp, &sshdr); - return -EINVAL; - } - revalidate_disk(sdkp->disk); - return count; -} - -static ssize_t -sd_store_manage_start_stop(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - struct scsi_device *sdp = sdkp->device; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - sdp->manage_start_stop = simple_strtoul(buf, NULL, 10); - - return count; -} - -static ssize_t -sd_store_allow_restart(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - struct scsi_device *sdp = sdkp->device; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (sdp->type != TYPE_DISK) - return -EINVAL; - - sdp->allow_restart = simple_strtoul(buf, NULL, 10); - - return count; -} - -static ssize_t -sd_show_cache_type(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - int ct = sdkp->RCD + 2*sdkp->WCE; - - return snprintf(buf, 40, "%s\n", sd_cache_types[ct]); -} - -static ssize_t -sd_show_fua(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); -} - -static ssize_t -sd_show_manage_start_stop(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - struct scsi_device *sdp = sdkp->device; - - return snprintf(buf, 20, "%u\n", sdp->manage_start_stop); -} - -static ssize_t -sd_show_allow_restart(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart); -} - -static ssize_t -sd_show_protection_type(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - return snprintf(buf, 20, "%u\n", sdkp->protection_type); -} - -static ssize_t -sd_show_protection_mode(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - struct scsi_device *sdp = sdkp->device; - unsigned int dif, dix; - - dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); - dix = scsi_host_dix_capable(sdp->host, sdkp->protection_type); - - if (!dix && scsi_host_dix_capable(sdp->host, SD_DIF_TYPE0_PROTECTION)) { - dif = 0; - dix = 1; - } - - if (!dif && !dix) - return snprintf(buf, 20, "none\n"); - - return snprintf(buf, 20, "%s%u\n", dix ? "dix" : "dif", dif); -} - -static ssize_t -sd_show_app_tag_own(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - return snprintf(buf, 20, "%u\n", sdkp->ATO); -} - -static ssize_t -sd_show_thin_provisioning(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - return snprintf(buf, 20, "%u\n", sdkp->lbpme); -} - -static const char *lbp_mode[] = { - [SD_LBP_FULL] = "full", - [SD_LBP_UNMAP] = "unmap", - [SD_LBP_WS16] = "writesame_16", - [SD_LBP_WS10] = "writesame_10", - [SD_LBP_ZERO] = "writesame_zero", - [SD_LBP_DISABLE] = "disabled", -}; - -static ssize_t -sd_show_provisioning_mode(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - return snprintf(buf, 20, "%s\n", lbp_mode[sdkp->provisioning_mode]); -} - -static ssize_t -sd_store_provisioning_mode(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - struct scsi_device *sdp = sdkp->device; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - if (sdp->type != TYPE_DISK) - return -EINVAL; - - if (!strncmp(buf, lbp_mode[SD_LBP_UNMAP], 20)) - sd_config_discard(sdkp, SD_LBP_UNMAP); - else if (!strncmp(buf, lbp_mode[SD_LBP_WS16], 20)) - sd_config_discard(sdkp, SD_LBP_WS16); - else if (!strncmp(buf, lbp_mode[SD_LBP_WS10], 20)) - sd_config_discard(sdkp, SD_LBP_WS10); - else if (!strncmp(buf, lbp_mode[SD_LBP_ZERO], 20)) - sd_config_discard(sdkp, SD_LBP_ZERO); - else if (!strncmp(buf, lbp_mode[SD_LBP_DISABLE], 20)) - sd_config_discard(sdkp, SD_LBP_DISABLE); - else - return -EINVAL; - - return count; -} - -static ssize_t -sd_show_max_medium_access_timeouts(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - - return snprintf(buf, 20, "%u\n", sdkp->max_medium_access_timeouts); -} - -static ssize_t -sd_store_max_medium_access_timeouts(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - int err; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - err = kstrtouint(buf, 10, &sdkp->max_medium_access_timeouts); - - return err ? err : count; -} - -static struct device_attribute sd_disk_attrs[] = { - __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, - sd_store_cache_type), - __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), - __ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart, - sd_store_allow_restart), - __ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop, - sd_store_manage_start_stop), - __ATTR(protection_type, S_IRUGO, sd_show_protection_type, NULL), - __ATTR(protection_mode, S_IRUGO, sd_show_protection_mode, NULL), - __ATTR(app_tag_own, S_IRUGO, sd_show_app_tag_own, NULL), - __ATTR(thin_provisioning, S_IRUGO, sd_show_thin_provisioning, NULL), - __ATTR(provisioning_mode, S_IRUGO|S_IWUSR, sd_show_provisioning_mode, - sd_store_provisioning_mode), - __ATTR(max_medium_access_timeouts, S_IRUGO|S_IWUSR, - sd_show_max_medium_access_timeouts, - sd_store_max_medium_access_timeouts), - __ATTR_NULL, -}; - -static struct class sd_disk_class = { - .name = "scsi_disk", - .owner = THIS_MODULE, - .dev_release = scsi_disk_release, - .dev_attrs = sd_disk_attrs, -}; - -static struct scsi_driver sd_template = { - .owner = THIS_MODULE, - .gendrv = { - .name = "sd", - .probe = sd_probe, - .remove = sd_remove, - .suspend = sd_suspend, - .resume = sd_resume, - .shutdown = sd_shutdown, - }, - .rescan = sd_rescan, - .done = sd_done, - .eh_action = sd_eh_action, -}; - -/* - * Device no to disk mapping: - * - * major disc2 disc p1 - * |............|.............|....|....| <- dev_t - * 31 20 19 8 7 4 3 0 - * - * Inside a major, we have 16k disks, however mapped non- - * contiguously. The first 16 disks are for major0, the next - * ones with major1, ... Disk 256 is for major0 again, disk 272 - * for major1, ... - * As we stay compatible with our numbering scheme, we can reuse - * the well-know SCSI majors 8, 65--71, 136--143. - */ -static int sd_major(int major_idx) -{ - switch (major_idx) { - case 0: - return SCSI_DISK0_MAJOR; - case 1 ... 7: - return SCSI_DISK1_MAJOR + major_idx - 1; - case 8 ... 15: - return SCSI_DISK8_MAJOR + major_idx - 8; - default: - BUG(); - return 0; /* shut up gcc */ - } -} - -static struct scsi_disk *__scsi_disk_get(struct gendisk *disk) -{ - struct scsi_disk *sdkp = NULL; - - if (disk->private_data) { - sdkp = scsi_disk(disk); - if (scsi_device_get(sdkp->device) == 0) - get_device(&sdkp->dev); - else - sdkp = NULL; - } - return sdkp; -} - -static struct scsi_disk *scsi_disk_get(struct gendisk *disk) -{ - struct scsi_disk *sdkp; - - mutex_lock(&sd_ref_mutex); - sdkp = __scsi_disk_get(disk); - mutex_unlock(&sd_ref_mutex); - return sdkp; -} - -static struct scsi_disk *scsi_disk_get_from_dev(struct device *dev) -{ - struct scsi_disk *sdkp; - - mutex_lock(&sd_ref_mutex); - sdkp = dev_get_drvdata(dev); - if (sdkp) - sdkp = __scsi_disk_get(sdkp->disk); - mutex_unlock(&sd_ref_mutex); - return sdkp; -} - -static void scsi_disk_put(struct scsi_disk *sdkp) -{ - struct scsi_device *sdev = sdkp->device; - - mutex_lock(&sd_ref_mutex); - put_device(&sdkp->dev); - scsi_device_put(sdev); - mutex_unlock(&sd_ref_mutex); -} - -static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif) -{ - unsigned int prot_op = SCSI_PROT_NORMAL; - unsigned int dix = scsi_prot_sg_count(scmd); - - if (scmd->sc_data_direction == DMA_FROM_DEVICE) { - if (dif && dix) - prot_op = SCSI_PROT_READ_PASS; - else if (dif && !dix) - prot_op = SCSI_PROT_READ_STRIP; - else if (!dif && dix) - prot_op = SCSI_PROT_READ_INSERT; - } else { - if (dif && dix) - prot_op = SCSI_PROT_WRITE_PASS; - else if (dif && !dix) - prot_op = SCSI_PROT_WRITE_INSERT; - else if (!dif && dix) - prot_op = SCSI_PROT_WRITE_STRIP; - } - - scsi_set_prot_op(scmd, prot_op); - scsi_set_prot_type(scmd, dif); -} - -static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) -{ - struct request_queue *q = sdkp->disk->queue; - unsigned int logical_block_size = sdkp->device->sector_size; - unsigned int max_blocks = 0; - - q->limits.discard_zeroes_data = sdkp->lbprz; - q->limits.discard_alignment = sdkp->unmap_alignment * - logical_block_size; - q->limits.discard_granularity = - max(sdkp->physical_block_size, - sdkp->unmap_granularity * logical_block_size); - - sdkp->provisioning_mode = mode; - - switch (mode) { - - case SD_LBP_DISABLE: - q->limits.max_discard_sectors = 0; - queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); - return; - - case SD_LBP_UNMAP: - max_blocks = min_not_zero(sdkp->max_unmap_blocks, 0xffffffff); - break; - - case SD_LBP_WS16: - max_blocks = min_not_zero(sdkp->max_ws_blocks, 0xffffffff); - break; - - case SD_LBP_WS10: - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); - break; - - case SD_LBP_ZERO: - max_blocks = min_not_zero(sdkp->max_ws_blocks, (u32)0xffff); - q->limits.discard_zeroes_data = 1; - break; - } - - q->limits.max_discard_sectors = max_blocks * (logical_block_size >> 9); - queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); -} - -/** - * scsi_setup_discard_cmnd - unmap blocks on thinly provisioned device - * @sdp: scsi device to operate one - * @rq: Request to prepare - * - * Will issue either UNMAP or WRITE SAME(16) depending on preference - * indicated by target device. - **/ -static int scsi_setup_discard_cmnd(struct scsi_device *sdp, struct request *rq) -{ - struct scsi_disk *sdkp = scsi_disk(rq->rq_disk); - struct bio *bio = rq->bio; - sector_t sector = bio->bi_sector; - unsigned int nr_sectors = bio_sectors(bio); - unsigned int len; - int ret; - char *buf; - struct page *page; - - if (sdkp->device->sector_size == 4096) { - sector >>= 3; - nr_sectors >>= 3; - } - - rq->timeout = SD_TIMEOUT; - - memset(rq->cmd, 0, rq->cmd_len); - - page = alloc_page(GFP_ATOMIC | __GFP_ZERO); - if (!page) - return BLKPREP_DEFER; - - switch (sdkp->provisioning_mode) { - case SD_LBP_UNMAP: - buf = page_address(page); - - rq->cmd_len = 10; - rq->cmd[0] = UNMAP; - rq->cmd[8] = 24; - - put_unaligned_be16(6 + 16, &buf[0]); - put_unaligned_be16(16, &buf[2]); - put_unaligned_be64(sector, &buf[8]); - put_unaligned_be32(nr_sectors, &buf[16]); - - len = 24; - break; - - case SD_LBP_WS16: - rq->cmd_len = 16; - rq->cmd[0] = WRITE_SAME_16; - rq->cmd[1] = 0x8; /* UNMAP */ - put_unaligned_be64(sector, &rq->cmd[2]); - put_unaligned_be32(nr_sectors, &rq->cmd[10]); - - len = sdkp->device->sector_size; - break; - - case SD_LBP_WS10: - case SD_LBP_ZERO: - rq->cmd_len = 10; - rq->cmd[0] = WRITE_SAME; - if (sdkp->provisioning_mode == SD_LBP_WS10) - rq->cmd[1] = 0x8; /* UNMAP */ - put_unaligned_be32(sector, &rq->cmd[2]); - put_unaligned_be16(nr_sectors, &rq->cmd[7]); - - len = sdkp->device->sector_size; - break; - - default: - ret = BLKPREP_KILL; - goto out; - } - - blk_add_request_payload(rq, page, len); - ret = scsi_setup_blk_pc_cmnd(sdp, rq); - rq->buffer = page_address(page); - -out: - if (ret != BLKPREP_OK) { - __free_page(page); - rq->buffer = NULL; - } - return ret; -} - -static int scsi_setup_flush_cmnd(struct scsi_device *sdp, struct request *rq) -{ - rq->timeout = SD_FLUSH_TIMEOUT; - rq->retries = SD_MAX_RETRIES; - rq->cmd[0] = SYNCHRONIZE_CACHE; - rq->cmd_len = 10; - - return scsi_setup_blk_pc_cmnd(sdp, rq); -} - -static void sd_unprep_fn(struct request_queue *q, struct request *rq) -{ - if (rq->cmd_flags & REQ_DISCARD) { - free_page((unsigned long)rq->buffer); - rq->buffer = NULL; - } -} - -/** - * sd_prep_fn - build a scsi (read or write) command from - * information in the request structure. - * @SCpnt: pointer to mid-level's per scsi command structure that - * contains request and into which the scsi command is written - * - * Returns 1 if successful and 0 if error (or cannot be done now). - **/ -static int sd_prep_fn(struct request_queue *q, struct request *rq) -{ - struct scsi_cmnd *SCpnt; - struct scsi_device *sdp = q->queuedata; - struct gendisk *disk = rq->rq_disk; - struct scsi_disk *sdkp; - sector_t block = blk_rq_pos(rq); - sector_t threshold; - unsigned int this_count = blk_rq_sectors(rq); - int ret, host_dif; - unsigned char protect; - - /* - * Discard request come in as REQ_TYPE_FS but we turn them into - * block PC requests to make life easier. - */ - if (rq->cmd_flags & REQ_DISCARD) { - ret = scsi_setup_discard_cmnd(sdp, rq); - goto out; - } else if (rq->cmd_flags & REQ_FLUSH) { - ret = scsi_setup_flush_cmnd(sdp, rq); - goto out; - } else if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - ret = scsi_setup_blk_pc_cmnd(sdp, rq); - goto out; - } else if (rq->cmd_type != REQ_TYPE_FS) { - ret = BLKPREP_KILL; - goto out; - } - ret = scsi_setup_fs_cmnd(sdp, rq); - if (ret != BLKPREP_OK) - goto out; - SCpnt = rq->special; - sdkp = scsi_disk(disk); - - /* from here on until we're complete, any goto out - * is used for a killable error condition */ - ret = BLKPREP_KILL; - - SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt, - "sd_prep_fn: block=%llu, " - "count=%d\n", - (unsigned long long)block, - this_count)); - - if (!sdp || !scsi_device_online(sdp) || - block + blk_rq_sectors(rq) > get_capacity(disk)) { - SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "Finishing %u sectors\n", - blk_rq_sectors(rq))); - SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "Retry with 0x%p\n", SCpnt)); - goto out; - } - - if (sdp->changed) { - /* - * quietly refuse to do anything to a changed disc until - * the changed bit has been reset - */ - /* printk("SCSI disk has been changed or is not present. Prohibiting further I/O.\n"); */ - goto out; - } - - /* - * Some SD card readers can't handle multi-sector accesses which touch - * the last one or two hardware sectors. Split accesses as needed. - */ - threshold = get_capacity(disk) - SD_LAST_BUGGY_SECTORS * - (sdp->sector_size / 512); - - if (unlikely(sdp->last_sector_bug && block + this_count > threshold)) { - if (block < threshold) { - /* Access up to the threshold but not beyond */ - this_count = threshold - block; - } else { - /* Access only a single hardware sector */ - this_count = sdp->sector_size / 512; - } - } - - SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n", - (unsigned long long)block)); - - /* - * If we have a 1K hardware sectorsize, prevent access to single - * 512 byte sectors. In theory we could handle this - in fact - * the scsi cdrom driver must be able to handle this because - * we typically use 1K blocksizes, and cdroms typically have - * 2K hardware sectorsizes. Of course, things are simpler - * with the cdrom, since it is read-only. For performance - * reasons, the filesystems should be able to handle this - * and not force the scsi disk driver to use bounce buffers - * for this. - */ - if (sdp->sector_size == 1024) { - if ((block & 1) || (blk_rq_sectors(rq) & 1)) { - scmd_printk(KERN_ERR, SCpnt, - "Bad block number requested\n"); - goto out; - } else { - block = block >> 1; - this_count = this_count >> 1; - } - } - if (sdp->sector_size == 2048) { - if ((block & 3) || (blk_rq_sectors(rq) & 3)) { - scmd_printk(KERN_ERR, SCpnt, - "Bad block number requested\n"); - goto out; - } else { - block = block >> 2; - this_count = this_count >> 2; - } - } - if (sdp->sector_size == 4096) { - if ((block & 7) || (blk_rq_sectors(rq) & 7)) { - scmd_printk(KERN_ERR, SCpnt, - "Bad block number requested\n"); - goto out; - } else { - block = block >> 3; - this_count = this_count >> 3; - } - } - if (rq_data_dir(rq) == WRITE) { - if (!sdp->writeable) { - goto out; - } - SCpnt->cmnd[0] = WRITE_6; - SCpnt->sc_data_direction = DMA_TO_DEVICE; - - if (blk_integrity_rq(rq) && - sd_dif_prepare(rq, block, sdp->sector_size) == -EIO) - goto out; - - } else if (rq_data_dir(rq) == READ) { - SCpnt->cmnd[0] = READ_6; - SCpnt->sc_data_direction = DMA_FROM_DEVICE; - } else { - scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags); - goto out; - } - - SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, - "%s %d/%u 512 byte blocks.\n", - (rq_data_dir(rq) == WRITE) ? - "writing" : "reading", this_count, - blk_rq_sectors(rq))); - - /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ - host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); - if (host_dif) - protect = 1 << 5; - else - protect = 0; - - if (host_dif == SD_DIF_TYPE2_PROTECTION) { - SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC); - - if (unlikely(SCpnt->cmnd == NULL)) { - ret = BLKPREP_DEFER; - goto out; - } - - SCpnt->cmd_len = SD_EXT_CDB_SIZE; - memset(SCpnt->cmnd, 0, SCpnt->cmd_len); - SCpnt->cmnd[0] = VARIABLE_LENGTH_CMD; - SCpnt->cmnd[7] = 0x18; - SCpnt->cmnd[9] = (rq_data_dir(rq) == READ) ? READ_32 : WRITE_32; - SCpnt->cmnd[10] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0); - - /* LBA */ - SCpnt->cmnd[12] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; - SCpnt->cmnd[13] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; - SCpnt->cmnd[14] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; - SCpnt->cmnd[15] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0; - SCpnt->cmnd[16] = (unsigned char) (block >> 24) & 0xff; - SCpnt->cmnd[17] = (unsigned char) (block >> 16) & 0xff; - SCpnt->cmnd[18] = (unsigned char) (block >> 8) & 0xff; - SCpnt->cmnd[19] = (unsigned char) block & 0xff; - - /* Expected Indirect LBA */ - SCpnt->cmnd[20] = (unsigned char) (block >> 24) & 0xff; - SCpnt->cmnd[21] = (unsigned char) (block >> 16) & 0xff; - SCpnt->cmnd[22] = (unsigned char) (block >> 8) & 0xff; - SCpnt->cmnd[23] = (unsigned char) block & 0xff; - - /* Transfer length */ - SCpnt->cmnd[28] = (unsigned char) (this_count >> 24) & 0xff; - SCpnt->cmnd[29] = (unsigned char) (this_count >> 16) & 0xff; - SCpnt->cmnd[30] = (unsigned char) (this_count >> 8) & 0xff; - SCpnt->cmnd[31] = (unsigned char) this_count & 0xff; - } else if (block > 0xffffffff) { - SCpnt->cmnd[0] += READ_16 - READ_6; - SCpnt->cmnd[1] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0); - SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; - SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; - SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; - SCpnt->cmnd[5] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0; - SCpnt->cmnd[6] = (unsigned char) (block >> 24) & 0xff; - SCpnt->cmnd[7] = (unsigned char) (block >> 16) & 0xff; - SCpnt->cmnd[8] = (unsigned char) (block >> 8) & 0xff; - SCpnt->cmnd[9] = (unsigned char) block & 0xff; - SCpnt->cmnd[10] = (unsigned char) (this_count >> 24) & 0xff; - SCpnt->cmnd[11] = (unsigned char) (this_count >> 16) & 0xff; - SCpnt->cmnd[12] = (unsigned char) (this_count >> 8) & 0xff; - SCpnt->cmnd[13] = (unsigned char) this_count & 0xff; - SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0; - } else if ((this_count > 0xff) || (block > 0x1fffff) || - scsi_device_protection(SCpnt->device) || - SCpnt->device->use_10_for_rw) { - if (this_count > 0xffff) - this_count = 0xffff; - - SCpnt->cmnd[0] += READ_10 - READ_6; - SCpnt->cmnd[1] = protect | ((rq->cmd_flags & REQ_FUA) ? 0x8 : 0); - SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; - SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; - SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; - SCpnt->cmnd[5] = (unsigned char) block & 0xff; - SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0; - SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff; - SCpnt->cmnd[8] = (unsigned char) this_count & 0xff; - } else { - if (unlikely(rq->cmd_flags & REQ_FUA)) { - /* - * This happens only if this drive failed - * 10byte rw command with ILLEGAL_REQUEST - * during operation and thus turned off - * use_10_for_rw. - */ - scmd_printk(KERN_ERR, SCpnt, - "FUA write on READ/WRITE(6) drive\n"); - goto out; - } - - SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f); - SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff); - SCpnt->cmnd[3] = (unsigned char) block & 0xff; - SCpnt->cmnd[4] = (unsigned char) this_count; - SCpnt->cmnd[5] = 0; - } - SCpnt->sdb.length = this_count * sdp->sector_size; - - /* If DIF or DIX is enabled, tell HBA how to handle request */ - if (host_dif || scsi_prot_sg_count(SCpnt)) - sd_prot_op(SCpnt, host_dif); - - /* - * We shouldn't disconnect in the middle of a sector, so with a dumb - * host adapter, it's safe to assume that we can at least transfer - * this many bytes between each connect / disconnect. - */ - SCpnt->transfersize = sdp->sector_size; - SCpnt->underflow = this_count << 9; - SCpnt->allowed = SD_MAX_RETRIES; - - /* - * This indicates that the command is ready from our end to be - * queued. - */ - ret = BLKPREP_OK; - out: - return scsi_prep_return(q, rq, ret); -} - -/** - * sd_open - open a scsi disk device - * @inode: only i_rdev member may be used - * @filp: only f_mode and f_flags may be used - * - * Returns 0 if successful. Returns a negated errno value in case - * of error. - * - * Note: This can be called from a user context (e.g. fsck(1) ) - * or from within the kernel (e.g. as a result of a mount(1) ). - * In the latter case @inode and @filp carry an abridged amount - * of information as noted above. - * - * Locking: called with bdev->bd_mutex held. - **/ -static int sd_open(struct block_device *bdev, fmode_t mode) -{ - struct scsi_disk *sdkp = scsi_disk_get(bdev->bd_disk); - struct scsi_device *sdev; - int retval; - - if (!sdkp) - return -ENXIO; - - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_open\n")); - - sdev = sdkp->device; - - retval = scsi_autopm_get_device(sdev); - if (retval) - goto error_autopm; - - /* - * If the device is in error recovery, wait until it is done. - * If the device is offline, then disallow any access to it. - */ - retval = -ENXIO; - if (!scsi_block_when_processing_errors(sdev)) - goto error_out; - - if (sdev->removable || sdkp->write_prot) - check_disk_change(bdev); - - /* - * If the drive is empty, just let the open fail. - */ - retval = -ENOMEDIUM; - if (sdev->removable && !sdkp->media_present && !(mode & FMODE_NDELAY)) - goto error_out; - - /* - * If the device has the write protect tab set, have the open fail - * if the user expects to be able to write to the thing. - */ - retval = -EROFS; - if (sdkp->write_prot && (mode & FMODE_WRITE)) - goto error_out; - - /* - * It is possible that the disk changing stuff resulted in - * the device being taken offline. If this is the case, - * report this to the user, and don't pretend that the - * open actually succeeded. - */ - retval = -ENXIO; - if (!scsi_device_online(sdev)) - goto error_out; - - if ((atomic_inc_return(&sdkp->openers) == 1) && sdev->removable) { - if (scsi_block_when_processing_errors(sdev)) - scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT); - } - - return 0; - -error_out: - scsi_autopm_put_device(sdev); -error_autopm: - scsi_disk_put(sdkp); - return retval; -} - -/** - * sd_release - invoked when the (last) close(2) is called on this - * scsi disk. - * @inode: only i_rdev member may be used - * @filp: only f_mode and f_flags may be used - * - * Returns 0. - * - * Note: may block (uninterruptible) if error recovery is underway - * on this disk. - * - * Locking: called with bdev->bd_mutex held. - **/ -static int sd_release(struct gendisk *disk, fmode_t mode) -{ - struct scsi_disk *sdkp = scsi_disk(disk); - struct scsi_device *sdev = sdkp->device; - - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_release\n")); - - if (atomic_dec_return(&sdkp->openers) == 0 && sdev->removable) { - if (scsi_block_when_processing_errors(sdev)) - scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); - } - - /* - * XXX and what if there are packets in flight and this close() - * XXX is followed by a "rmmod sd_mod"? - */ - - scsi_autopm_put_device(sdev); - scsi_disk_put(sdkp); - return 0; -} - -static int sd_getgeo(struct block_device *bdev, struct hd_geometry *geo) -{ - struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk); - struct scsi_device *sdp = sdkp->device; - struct Scsi_Host *host = sdp->host; - int diskinfo[4]; - - /* default to most commonly used values */ - diskinfo[0] = 0x40; /* 1 << 6 */ - diskinfo[1] = 0x20; /* 1 << 5 */ - diskinfo[2] = sdkp->capacity >> 11; - - /* override with calculated, extended default, or driver values */ - if (host->hostt->bios_param) - host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo); - else - scsicam_bios_param(bdev, sdkp->capacity, diskinfo); - - geo->heads = diskinfo[0]; - geo->sectors = diskinfo[1]; - geo->cylinders = diskinfo[2]; - return 0; -} - -/** - * sd_ioctl - process an ioctl - * @inode: only i_rdev/i_bdev members may be used - * @filp: only f_mode and f_flags may be used - * @cmd: ioctl command number - * @arg: this is third argument given to ioctl(2) system call. - * Often contains a pointer. - * - * Returns 0 if successful (some ioctls return positive numbers on - * success as well). Returns a negated errno value in case of error. - * - * Note: most ioctls are forward onto the block subsystem or further - * down in the scsi subsystem. - **/ -static int sd_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct gendisk *disk = bdev->bd_disk; - struct scsi_disk *sdkp = scsi_disk(disk); - struct scsi_device *sdp = sdkp->device; - void __user *p = (void __user *)arg; - int error; - - SCSI_LOG_IOCTL(1, sd_printk(KERN_INFO, sdkp, "sd_ioctl: disk=%s, " - "cmd=0x%x\n", disk->disk_name, cmd)); - - error = scsi_verify_blk_ioctl(bdev, cmd); - if (error < 0) - return error; - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - error = scsi_nonblockable_ioctl(sdp, cmd, p, - (mode & FMODE_NDELAY) != 0); - if (!scsi_block_when_processing_errors(sdp) || !error) - goto out; - - /* - * Send SCSI addressing ioctls directly to mid level, send other - * ioctls to block level and then onto mid level if they can't be - * resolved. - */ - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - error = scsi_ioctl(sdp, cmd, p); - break; - default: - error = scsi_cmd_blk_ioctl(bdev, mode, cmd, p); - if (error != -ENOTTY) - break; - error = scsi_ioctl(sdp, cmd, p); - break; - } -out: - return error; -} - -static void set_media_not_present(struct scsi_disk *sdkp) -{ - if (sdkp->media_present) - sdkp->device->changed = 1; - - if (sdkp->device->removable) { - sdkp->media_present = 0; - sdkp->capacity = 0; - } -} - -static int media_not_present(struct scsi_disk *sdkp, - struct scsi_sense_hdr *sshdr) -{ - if (!scsi_sense_valid(sshdr)) - return 0; - - /* not invoked for commands that could return deferred errors */ - switch (sshdr->sense_key) { - case UNIT_ATTENTION: - case NOT_READY: - /* medium not present */ - if (sshdr->asc == 0x3A) { - set_media_not_present(sdkp); - return 1; - } - } - return 0; -} - -/** - * sd_check_events - check media events - * @disk: kernel device descriptor - * @clearing: disk events currently being cleared - * - * Returns mask of DISK_EVENT_*. - * - * Note: this function is invoked from the block subsystem. - **/ -static unsigned int sd_check_events(struct gendisk *disk, unsigned int clearing) -{ - struct scsi_disk *sdkp = scsi_disk(disk); - struct scsi_device *sdp = sdkp->device; - struct scsi_sense_hdr *sshdr = NULL; - int retval; - - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_check_events\n")); - - /* - * If the device is offline, don't send any commands - just pretend as - * if the command failed. If the device ever comes back online, we - * can deal with it then. It is only because of unrecoverable errors - * that we would ever take a device offline in the first place. - */ - if (!scsi_device_online(sdp)) { - set_media_not_present(sdkp); - goto out; - } - - /* - * Using TEST_UNIT_READY enables differentiation between drive with - * no cartridge loaded - NOT READY, drive with changed cartridge - - * UNIT ATTENTION, or with same cartridge - GOOD STATUS. - * - * Drives that auto spin down. eg iomega jaz 1G, will be started - * by sd_spinup_disk() from sd_revalidate_disk(), which happens whenever - * sd_revalidate() is called. - */ - retval = -ENODEV; - - if (scsi_block_when_processing_errors(sdp)) { - retval = scsi_autopm_get_device(sdp); - if (retval) - goto out; - - sshdr = kzalloc(sizeof(*sshdr), GFP_KERNEL); - retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES, - sshdr); - scsi_autopm_put_device(sdp); - } - - /* failed to execute TUR, assume media not present */ - if (host_byte(retval)) { - set_media_not_present(sdkp); - goto out; - } - - if (media_not_present(sdkp, sshdr)) - goto out; - - /* - * For removable scsi disk we have to recognise the presence - * of a disk in the drive. - */ - if (!sdkp->media_present) - sdp->changed = 1; - sdkp->media_present = 1; -out: - /* - * sdp->changed is set under the following conditions: - * - * Medium present state has changed in either direction. - * Device has indicated UNIT_ATTENTION. - */ - kfree(sshdr); - retval = sdp->changed ? DISK_EVENT_MEDIA_CHANGE : 0; - sdp->changed = 0; - return retval; -} - -static int sd_sync_cache(struct scsi_disk *sdkp) -{ - int retries, res; - struct scsi_device *sdp = sdkp->device; - struct scsi_sense_hdr sshdr; - - if (!scsi_device_online(sdp)) - return -ENODEV; - - - for (retries = 3; retries > 0; --retries) { - unsigned char cmd[10] = { 0 }; - - cmd[0] = SYNCHRONIZE_CACHE; - /* - * Leave the rest of the command zero to indicate - * flush everything. - */ - res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, - SD_FLUSH_TIMEOUT, SD_MAX_RETRIES, NULL); - if (res == 0) - break; - } - - if (res) { - sd_print_result(sdkp, res); - if (driver_byte(res) & DRIVER_SENSE) - sd_print_sense_hdr(sdkp, &sshdr); - } - - if (res) - return -EIO; - return 0; -} - -static void sd_rescan(struct device *dev) -{ - struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); - - if (sdkp) { - revalidate_disk(sdkp->disk); - scsi_disk_put(sdkp); - } -} - - -#ifdef CONFIG_COMPAT -/* - * This gets directly called from VFS. When the ioctl - * is not recognized we go back to the other translation paths. - */ -static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long arg) -{ - struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device; - int ret; - - ret = scsi_verify_blk_ioctl(bdev, cmd); - if (ret < 0) - return ret; - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if (!scsi_block_when_processing_errors(sdev)) - return -ENODEV; - - if (sdev->host->hostt->compat_ioctl) { - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); - - return ret; - } - - /* - * Let the static ioctl translation table take care of it. - */ - return -ENOIOCTLCMD; -} -#endif - -static const struct block_device_operations sd_fops = { - .owner = THIS_MODULE, - .open = sd_open, - .release = sd_release, - .ioctl = sd_ioctl, - .getgeo = sd_getgeo, -#ifdef CONFIG_COMPAT - .compat_ioctl = sd_compat_ioctl, -#endif - .check_events = sd_check_events, - .revalidate_disk = sd_revalidate_disk, - .unlock_native_capacity = sd_unlock_native_capacity, -}; - -/** - * sd_eh_action - error handling callback - * @scmd: sd-issued command that has failed - * @eh_cmnd: The command that was sent during error handling - * @eh_cmnd_len: Length of eh_cmnd in bytes - * @eh_disp: The recovery disposition suggested by the midlayer - * - * This function is called by the SCSI midlayer upon completion of - * an error handling command (TEST UNIT READY, START STOP UNIT, - * etc.) The command sent to the device by the error handler is - * stored in eh_cmnd. The result of sending the eh command is - * passed in eh_disp. - **/ -static int sd_eh_action(struct scsi_cmnd *scmd, unsigned char *eh_cmnd, - int eh_cmnd_len, int eh_disp) -{ - struct scsi_disk *sdkp = scsi_disk(scmd->request->rq_disk); - - if (!scsi_device_online(scmd->device) || - !scsi_medium_access_command(scmd)) - return eh_disp; - - /* - * The device has timed out executing a medium access command. - * However, the TEST UNIT READY command sent during error - * handling completed successfully. Either the device is in the - * process of recovering or has it suffered an internal failure - * that prevents access to the storage medium. - */ - if (host_byte(scmd->result) == DID_TIME_OUT && eh_disp == SUCCESS && - eh_cmnd_len && eh_cmnd[0] == TEST_UNIT_READY) - sdkp->medium_access_timed_out++; - - /* - * If the device keeps failing read/write commands but TEST UNIT - * READY always completes successfully we assume that medium - * access is no longer possible and take the device offline. - */ - if (sdkp->medium_access_timed_out >= sdkp->max_medium_access_timeouts) { - scmd_printk(KERN_ERR, scmd, - "Medium access timeout failure. Offlining disk!\n"); - scsi_device_set_state(scmd->device, SDEV_OFFLINE); - - return FAILED; - } - - return eh_disp; -} - -static unsigned int sd_completed_bytes(struct scsi_cmnd *scmd) -{ - u64 start_lba = blk_rq_pos(scmd->request); - u64 end_lba = blk_rq_pos(scmd->request) + (scsi_bufflen(scmd) / 512); - u64 bad_lba; - int info_valid; - /* - * resid is optional but mostly filled in. When it's unused, - * its value is zero, so we assume the whole buffer transferred - */ - unsigned int transferred = scsi_bufflen(scmd) - scsi_get_resid(scmd); - unsigned int good_bytes; - - if (scmd->request->cmd_type != REQ_TYPE_FS) - return 0; - - info_valid = scsi_get_sense_info_fld(scmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - &bad_lba); - if (!info_valid) - return 0; - - if (scsi_bufflen(scmd) <= scmd->device->sector_size) - return 0; - - if (scmd->device->sector_size < 512) { - /* only legitimate sector_size here is 256 */ - start_lba <<= 1; - end_lba <<= 1; - } else { - /* be careful ... don't want any overflows */ - u64 factor = scmd->device->sector_size / 512; - do_div(start_lba, factor); - do_div(end_lba, factor); - } - - /* The bad lba was reported incorrectly, we have no idea where - * the error is. - */ - if (bad_lba < start_lba || bad_lba >= end_lba) - return 0; - - /* This computation should always be done in terms of - * the resolution of the device's medium. - */ - good_bytes = (bad_lba - start_lba) * scmd->device->sector_size; - return min(good_bytes, transferred); -} - -/** - * sd_done - bottom half handler: called when the lower level - * driver has completed (successfully or otherwise) a scsi command. - * @SCpnt: mid-level's per command structure. - * - * Note: potentially run from within an ISR. Must not block. - **/ -static int sd_done(struct scsi_cmnd *SCpnt) -{ - int result = SCpnt->result; - unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); - struct scsi_sense_hdr sshdr; - struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); - int sense_valid = 0; - int sense_deferred = 0; - unsigned char op = SCpnt->cmnd[0]; - - if ((SCpnt->request->cmd_flags & REQ_DISCARD) && !result) - scsi_set_resid(SCpnt, 0); - - if (result) { - sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr); - if (sense_valid) - sense_deferred = scsi_sense_is_deferred(&sshdr); - } -#ifdef CONFIG_SCSI_LOGGING - SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt)); - if (sense_valid) { - SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt, - "sd_done: sb[respc,sk,asc," - "ascq]=%x,%x,%x,%x\n", - sshdr.response_code, - sshdr.sense_key, sshdr.asc, - sshdr.ascq)); - } -#endif - if (driver_byte(result) != DRIVER_SENSE && - (!sense_valid || sense_deferred)) - goto out; - - sdkp->medium_access_timed_out = 0; - - switch (sshdr.sense_key) { - case HARDWARE_ERROR: - case MEDIUM_ERROR: - good_bytes = sd_completed_bytes(SCpnt); - break; - case RECOVERED_ERROR: - good_bytes = scsi_bufflen(SCpnt); - break; - case NO_SENSE: - /* This indicates a false check condition, so ignore it. An - * unknown amount of data was transferred so treat it as an - * error. - */ - scsi_print_sense("sd", SCpnt); - SCpnt->result = 0; - memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - break; - case ABORTED_COMMAND: - if (sshdr.asc == 0x10) /* DIF: Target detected corruption */ - good_bytes = sd_completed_bytes(SCpnt); - break; - case ILLEGAL_REQUEST: - if (sshdr.asc == 0x10) /* DIX: Host detected corruption */ - good_bytes = sd_completed_bytes(SCpnt); - /* INVALID COMMAND OPCODE or INVALID FIELD IN CDB */ - if ((sshdr.asc == 0x20 || sshdr.asc == 0x24) && - (op == UNMAP || op == WRITE_SAME_16 || op == WRITE_SAME)) - sd_config_discard(sdkp, SD_LBP_DISABLE); - break; - default: - break; - } - out: - if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt)) - sd_dif_complete(SCpnt, good_bytes); - - if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type) - == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd) { - - /* We have to print a failed command here as the - * extended CDB gets freed before scsi_io_completion() - * is called. - */ - if (result) - scsi_print_command(SCpnt); - - mempool_free(SCpnt->cmnd, sd_cdb_pool); - SCpnt->cmnd = NULL; - SCpnt->cmd_len = 0; - } - - return good_bytes; -} - -/* - * spinup disk - called only in sd_revalidate_disk() - */ -static void -sd_spinup_disk(struct scsi_disk *sdkp) -{ - unsigned char cmd[10]; - unsigned long spintime_expire = 0; - int retries, spintime; - unsigned int the_result; - struct scsi_sense_hdr sshdr; - int sense_valid = 0; - - spintime = 0; - - /* Spin up drives, as required. Only do this at boot time */ - /* Spinup needs to be done for module loads too. */ - do { - retries = 0; - - do { - cmd[0] = TEST_UNIT_READY; - memset((void *) &cmd[1], 0, 9); - - the_result = scsi_execute_req(sdkp->device, cmd, - DMA_NONE, NULL, 0, - &sshdr, SD_TIMEOUT, - SD_MAX_RETRIES, NULL); - - /* - * If the drive has indicated to us that it - * doesn't have any media in it, don't bother - * with any more polling. - */ - if (media_not_present(sdkp, &sshdr)) - return; - - if (the_result) - sense_valid = scsi_sense_valid(&sshdr); - retries++; - } while (retries < 3 && - (!scsi_status_is_good(the_result) || - ((driver_byte(the_result) & DRIVER_SENSE) && - sense_valid && sshdr.sense_key == UNIT_ATTENTION))); - - if ((driver_byte(the_result) & DRIVER_SENSE) == 0) { - /* no sense, TUR either succeeded or failed - * with a status error */ - if(!spintime && !scsi_status_is_good(the_result)) { - sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n"); - sd_print_result(sdkp, the_result); - } - break; - } - - /* - * The device does not want the automatic start to be issued. - */ - if (sdkp->device->no_start_on_add) - break; - - if (sense_valid && sshdr.sense_key == NOT_READY) { - if (sshdr.asc == 4 && sshdr.ascq == 3) - break; /* manual intervention required */ - if (sshdr.asc == 4 && sshdr.ascq == 0xb) - break; /* standby */ - if (sshdr.asc == 4 && sshdr.ascq == 0xc) - break; /* unavailable */ - /* - * Issue command to spin up drive when not ready - */ - if (!spintime) { - sd_printk(KERN_NOTICE, sdkp, "Spinning up disk..."); - cmd[0] = START_STOP; - cmd[1] = 1; /* Return immediately */ - memset((void *) &cmd[2], 0, 8); - cmd[4] = 1; /* Start spin cycle */ - if (sdkp->device->start_stop_pwr_cond) - cmd[4] |= 1 << 4; - scsi_execute_req(sdkp->device, cmd, DMA_NONE, - NULL, 0, &sshdr, - SD_TIMEOUT, SD_MAX_RETRIES, - NULL); - spintime_expire = jiffies + 100 * HZ; - spintime = 1; - } - /* Wait 1 second for next try */ - msleep(1000); - printk("."); - - /* - * Wait for USB flash devices with slow firmware. - * Yes, this sense key/ASC combination shouldn't - * occur here. It's characteristic of these devices. - */ - } else if (sense_valid && - sshdr.sense_key == UNIT_ATTENTION && - sshdr.asc == 0x28) { - if (!spintime) { - spintime_expire = jiffies + 5 * HZ; - spintime = 1; - } - /* Wait 1 second for next try */ - msleep(1000); - } else { - /* we don't understand the sense code, so it's - * probably pointless to loop */ - if(!spintime) { - sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n"); - sd_print_sense_hdr(sdkp, &sshdr); - } - break; - } - - } while (spintime && time_before_eq(jiffies, spintime_expire)); - - if (spintime) { - if (scsi_status_is_good(the_result)) - printk("ready\n"); - else - printk("not responding...\n"); - } -} - - -/* - * Determine whether disk supports Data Integrity Field. - */ -static void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) -{ - struct scsi_device *sdp = sdkp->device; - u8 type; - - if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) - return; - - type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ - - if (type == sdkp->protection_type || !sdkp->first_scan) - return; - - sdkp->protection_type = type; - - if (type > SD_DIF_TYPE3_PROTECTION) { - sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \ - "protection type %u. Disabling disk!\n", type); - sdkp->capacity = 0; - return; - } - - if (scsi_host_dif_capable(sdp->host, type)) - sd_printk(KERN_NOTICE, sdkp, - "Enabling DIF Type %u protection\n", type); - else - sd_printk(KERN_NOTICE, sdkp, - "Disabling DIF Type %u protection\n", type); -} - -static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, - struct scsi_sense_hdr *sshdr, int sense_valid, - int the_result) -{ - sd_print_result(sdkp, the_result); - if (driver_byte(the_result) & DRIVER_SENSE) - sd_print_sense_hdr(sdkp, sshdr); - else - sd_printk(KERN_NOTICE, sdkp, "Sense not available.\n"); - - /* - * Set dirty bit for removable devices if not ready - - * sometimes drives will not report this properly. - */ - if (sdp->removable && - sense_valid && sshdr->sense_key == NOT_READY) - set_media_not_present(sdkp); - - /* - * We used to set media_present to 0 here to indicate no media - * in the drive, but some drives fail read capacity even with - * media present, so we can't do that. - */ - sdkp->capacity = 0; /* unknown mapped to zero - as usual */ -} - -#define RC16_LEN 32 -#if RC16_LEN > SD_BUF_SIZE -#error RC16_LEN must not be more than SD_BUF_SIZE -#endif - -#define READ_CAPACITY_RETRIES_ON_RESET 10 - -static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, - unsigned char *buffer) -{ - unsigned char cmd[16]; - struct scsi_sense_hdr sshdr; - int sense_valid = 0; - int the_result; - int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET; - unsigned int alignment; - unsigned long long lba; - unsigned sector_size; - - if (sdp->no_read_capacity_16) - return -EINVAL; - - do { - memset(cmd, 0, 16); - cmd[0] = SERVICE_ACTION_IN; - cmd[1] = SAI_READ_CAPACITY_16; - cmd[13] = RC16_LEN; - memset(buffer, 0, RC16_LEN); - - the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, - buffer, RC16_LEN, &sshdr, - SD_TIMEOUT, SD_MAX_RETRIES, NULL); - - if (media_not_present(sdkp, &sshdr)) - return -ENODEV; - - if (the_result) { - sense_valid = scsi_sense_valid(&sshdr); - if (sense_valid && - sshdr.sense_key == ILLEGAL_REQUEST && - (sshdr.asc == 0x20 || sshdr.asc == 0x24) && - sshdr.ascq == 0x00) - /* Invalid Command Operation Code or - * Invalid Field in CDB, just retry - * silently with RC10 */ - return -EINVAL; - if (sense_valid && - sshdr.sense_key == UNIT_ATTENTION && - sshdr.asc == 0x29 && sshdr.ascq == 0x00) - /* Device reset might occur several times, - * give it one more chance */ - if (--reset_retries > 0) - continue; - } - retries--; - - } while (the_result && retries); - - if (the_result) { - sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n"); - read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result); - return -EINVAL; - } - - sector_size = get_unaligned_be32(&buffer[8]); - lba = get_unaligned_be64(&buffer[0]); - - sd_read_protection_type(sdkp, buffer); - - if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) { - sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " - "kernel compiled with support for large block " - "devices.\n"); - sdkp->capacity = 0; - return -EOVERFLOW; - } - - /* Logical blocks per physical block exponent */ - sdkp->physical_block_size = (1 << (buffer[13] & 0xf)) * sector_size; - - /* Lowest aligned logical block */ - alignment = ((buffer[14] & 0x3f) << 8 | buffer[15]) * sector_size; - blk_queue_alignment_offset(sdp->request_queue, alignment); - if (alignment && sdkp->first_scan) - sd_printk(KERN_NOTICE, sdkp, - "physical block alignment offset: %u\n", alignment); - - if (buffer[14] & 0x80) { /* LBPME */ - sdkp->lbpme = 1; - - if (buffer[14] & 0x40) /* LBPRZ */ - sdkp->lbprz = 1; - - sd_config_discard(sdkp, SD_LBP_WS16); - } - - sdkp->capacity = lba + 1; - return sector_size; -} - -static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp, - unsigned char *buffer) -{ - unsigned char cmd[16]; - struct scsi_sense_hdr sshdr; - int sense_valid = 0; - int the_result; - int retries = 3, reset_retries = READ_CAPACITY_RETRIES_ON_RESET; - sector_t lba; - unsigned sector_size; - - do { - cmd[0] = READ_CAPACITY; - memset(&cmd[1], 0, 9); - memset(buffer, 0, 8); - - the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, - buffer, 8, &sshdr, - SD_TIMEOUT, SD_MAX_RETRIES, NULL); - - if (media_not_present(sdkp, &sshdr)) - return -ENODEV; - - if (the_result) { - sense_valid = scsi_sense_valid(&sshdr); - if (sense_valid && - sshdr.sense_key == UNIT_ATTENTION && - sshdr.asc == 0x29 && sshdr.ascq == 0x00) - /* Device reset might occur several times, - * give it one more chance */ - if (--reset_retries > 0) - continue; - } - retries--; - - } while (the_result && retries); - - if (the_result) { - sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n"); - read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result); - return -EINVAL; - } - - sector_size = get_unaligned_be32(&buffer[4]); - lba = get_unaligned_be32(&buffer[0]); - - if (sdp->no_read_capacity_16 && (lba == 0xffffffff)) { - /* Some buggy (usb cardreader) devices return an lba of - 0xffffffff when the want to report a size of 0 (with - which they really mean no media is present) */ - sdkp->capacity = 0; - sdkp->physical_block_size = sector_size; - return sector_size; - } - - if ((sizeof(sdkp->capacity) == 4) && (lba == 0xffffffff)) { - sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " - "kernel compiled with support for large block " - "devices.\n"); - sdkp->capacity = 0; - return -EOVERFLOW; - } - - sdkp->capacity = lba + 1; - sdkp->physical_block_size = sector_size; - return sector_size; -} - -static int sd_try_rc16_first(struct scsi_device *sdp) -{ - if (sdp->host->max_cmd_len < 16) - return 0; - if (sdp->try_rc_10_first) - return 0; - if (sdp->scsi_level > SCSI_SPC_2) - return 1; - if (scsi_device_protection(sdp)) - return 1; - return 0; -} - -/* - * read disk capacity - */ -static void -sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer) -{ - int sector_size; - struct scsi_device *sdp = sdkp->device; - sector_t old_capacity = sdkp->capacity; - - if (sd_try_rc16_first(sdp)) { - sector_size = read_capacity_16(sdkp, sdp, buffer); - if (sector_size == -EOVERFLOW) - goto got_data; - if (sector_size == -ENODEV) - return; - if (sector_size < 0) - sector_size = read_capacity_10(sdkp, sdp, buffer); - if (sector_size < 0) - return; - } else { - sector_size = read_capacity_10(sdkp, sdp, buffer); - if (sector_size == -EOVERFLOW) - goto got_data; - if (sector_size < 0) - return; - if ((sizeof(sdkp->capacity) > 4) && - (sdkp->capacity > 0xffffffffULL)) { - int old_sector_size = sector_size; - sd_printk(KERN_NOTICE, sdkp, "Very big device. " - "Trying to use READ CAPACITY(16).\n"); - sector_size = read_capacity_16(sdkp, sdp, buffer); - if (sector_size < 0) { - sd_printk(KERN_NOTICE, sdkp, - "Using 0xffffffff as device size\n"); - sdkp->capacity = 1 + (sector_t) 0xffffffff; - sector_size = old_sector_size; - goto got_data; - } - } - } - - /* Some devices are known to return the total number of blocks, - * not the highest block number. Some devices have versions - * which do this and others which do not. Some devices we might - * suspect of doing this but we don't know for certain. - * - * If we know the reported capacity is wrong, decrement it. If - * we can only guess, then assume the number of blocks is even - * (usually true but not always) and err on the side of lowering - * the capacity. - */ - if (sdp->fix_capacity || - (sdp->guess_capacity && (sdkp->capacity & 0x01))) { - sd_printk(KERN_INFO, sdkp, "Adjusting the sector count " - "from its reported value: %llu\n", - (unsigned long long) sdkp->capacity); - --sdkp->capacity; - } - -got_data: - if (sector_size == 0) { - sector_size = 512; - sd_printk(KERN_NOTICE, sdkp, "Sector size 0 reported, " - "assuming 512.\n"); - } - - if (sector_size != 512 && - sector_size != 1024 && - sector_size != 2048 && - sector_size != 4096 && - sector_size != 256) { - sd_printk(KERN_NOTICE, sdkp, "Unsupported sector size %d.\n", - sector_size); - /* - * The user might want to re-format the drive with - * a supported sectorsize. Once this happens, it - * would be relatively trivial to set the thing up. - * For this reason, we leave the thing in the table. - */ - sdkp->capacity = 0; - /* - * set a bogus sector size so the normal read/write - * logic in the block layer will eventually refuse any - * request on this device without tripping over power - * of two sector size assumptions - */ - sector_size = 512; - } - blk_queue_logical_block_size(sdp->request_queue, sector_size); - - { - char cap_str_2[10], cap_str_10[10]; - u64 sz = (u64)sdkp->capacity << ilog2(sector_size); - - string_get_size(sz, STRING_UNITS_2, cap_str_2, - sizeof(cap_str_2)); - string_get_size(sz, STRING_UNITS_10, cap_str_10, - sizeof(cap_str_10)); - - if (sdkp->first_scan || old_capacity != sdkp->capacity) { - sd_printk(KERN_NOTICE, sdkp, - "%llu %d-byte logical blocks: (%s/%s)\n", - (unsigned long long)sdkp->capacity, - sector_size, cap_str_10, cap_str_2); - - if (sdkp->physical_block_size != sector_size) - sd_printk(KERN_NOTICE, sdkp, - "%u-byte physical blocks\n", - sdkp->physical_block_size); - } - } - - /* Rescale capacity to 512-byte units */ - if (sector_size == 4096) - sdkp->capacity <<= 3; - else if (sector_size == 2048) - sdkp->capacity <<= 2; - else if (sector_size == 1024) - sdkp->capacity <<= 1; - else if (sector_size == 256) - sdkp->capacity >>= 1; - - blk_queue_physical_block_size(sdp->request_queue, - sdkp->physical_block_size); - sdkp->device->sector_size = sector_size; -} - -/* called with buffer of length 512 */ -static inline int -sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage, - unsigned char *buffer, int len, struct scsi_mode_data *data, - struct scsi_sense_hdr *sshdr) -{ - return scsi_mode_sense(sdp, dbd, modepage, buffer, len, - SD_TIMEOUT, SD_MAX_RETRIES, data, - sshdr); -} - -/* - * read write protect setting, if possible - called only in sd_revalidate_disk() - * called with buffer of length SD_BUF_SIZE - */ -static void -sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) -{ - int res; - struct scsi_device *sdp = sdkp->device; - struct scsi_mode_data data; - int old_wp = sdkp->write_prot; - - set_disk_ro(sdkp->disk, 0); - if (sdp->skip_ms_page_3f) { - sd_printk(KERN_NOTICE, sdkp, "Assuming Write Enabled\n"); - return; - } - - if (sdp->use_192_bytes_for_3f) { - res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 192, &data, NULL); - } else { - /* - * First attempt: ask for all pages (0x3F), but only 4 bytes. - * We have to start carefully: some devices hang if we ask - * for more than is available. - */ - res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 4, &data, NULL); - - /* - * Second attempt: ask for page 0 When only page 0 is - * implemented, a request for page 3F may return Sense Key - * 5: Illegal Request, Sense Code 24: Invalid field in - * CDB. - */ - if (!scsi_status_is_good(res)) - res = sd_do_mode_sense(sdp, 0, 0, buffer, 4, &data, NULL); - - /* - * Third attempt: ask 255 bytes, as we did earlier. - */ - if (!scsi_status_is_good(res)) - res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 255, - &data, NULL); - } - - if (!scsi_status_is_good(res)) { - sd_printk(KERN_WARNING, sdkp, - "Test WP failed, assume Write Enabled\n"); - } else { - sdkp->write_prot = ((data.device_specific & 0x80) != 0); - set_disk_ro(sdkp->disk, sdkp->write_prot); - if (sdkp->first_scan || old_wp != sdkp->write_prot) { - sd_printk(KERN_NOTICE, sdkp, "Write Protect is %s\n", - sdkp->write_prot ? "on" : "off"); - sd_printk(KERN_DEBUG, sdkp, - "Mode Sense: %02x %02x %02x %02x\n", - buffer[0], buffer[1], buffer[2], buffer[3]); - } - } -} - -/* - * sd_read_cache_type - called only from sd_revalidate_disk() - * called with buffer of length SD_BUF_SIZE - */ -static void -sd_read_cache_type(struct scsi_disk *sdkp, unsigned char *buffer) -{ - int len = 0, res; - struct scsi_device *sdp = sdkp->device; - - int dbd; - int modepage; - int first_len; - struct scsi_mode_data data; - struct scsi_sense_hdr sshdr; - int old_wce = sdkp->WCE; - int old_rcd = sdkp->RCD; - int old_dpofua = sdkp->DPOFUA; - - first_len = 4; - if (sdp->skip_ms_page_8) { - if (sdp->type == TYPE_RBC) - goto defaults; - else { - if (sdp->skip_ms_page_3f) - goto defaults; - modepage = 0x3F; - if (sdp->use_192_bytes_for_3f) - first_len = 192; - dbd = 0; - } - } else if (sdp->type == TYPE_RBC) { - modepage = 6; - dbd = 8; - } else { - modepage = 8; - dbd = 0; - } - - /* cautiously ask */ - res = sd_do_mode_sense(sdp, dbd, modepage, buffer, first_len, - &data, &sshdr); - - if (!scsi_status_is_good(res)) - goto bad_sense; - - if (!data.header_length) { - modepage = 6; - first_len = 0; - sd_printk(KERN_ERR, sdkp, "Missing header in MODE_SENSE response\n"); - } - - /* that went OK, now ask for the proper length */ - len = data.length; - - /* - * We're only interested in the first three bytes, actually. - * But the data cache page is defined for the first 20. - */ - if (len < 3) - goto bad_sense; - else if (len > SD_BUF_SIZE) { - sd_printk(KERN_NOTICE, sdkp, "Truncating mode parameter " - "data from %d to %d bytes\n", len, SD_BUF_SIZE); - len = SD_BUF_SIZE; - } - if (modepage == 0x3F && sdp->use_192_bytes_for_3f) - len = 192; - - /* Get the data */ - if (len > first_len) - res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, - &data, &sshdr); - - if (scsi_status_is_good(res)) { - int offset = data.header_length + data.block_descriptor_length; - - while (offset < len) { - u8 page_code = buffer[offset] & 0x3F; - u8 spf = buffer[offset] & 0x40; - - if (page_code == 8 || page_code == 6) { - /* We're interested only in the first 3 bytes. - */ - if (len - offset <= 2) { - sd_printk(KERN_ERR, sdkp, "Incomplete " - "mode parameter data\n"); - goto defaults; - } else { - modepage = page_code; - goto Page_found; - } - } else { - /* Go to the next page */ - if (spf && len - offset > 3) - offset += 4 + (buffer[offset+2] << 8) + - buffer[offset+3]; - else if (!spf && len - offset > 1) - offset += 2 + buffer[offset+1]; - else { - sd_printk(KERN_ERR, sdkp, "Incomplete " - "mode parameter data\n"); - goto defaults; - } - } - } - - if (modepage == 0x3F) { - sd_printk(KERN_ERR, sdkp, "No Caching mode page " - "present\n"); - goto defaults; - } else if ((buffer[offset] & 0x3f) != modepage) { - sd_printk(KERN_ERR, sdkp, "Got wrong page\n"); - goto defaults; - } - Page_found: - if (modepage == 8) { - sdkp->WCE = ((buffer[offset + 2] & 0x04) != 0); - sdkp->RCD = ((buffer[offset + 2] & 0x01) != 0); - } else { - sdkp->WCE = ((buffer[offset + 2] & 0x01) == 0); - sdkp->RCD = 0; - } - - sdkp->DPOFUA = (data.device_specific & 0x10) != 0; - if (sdkp->DPOFUA && !sdkp->device->use_10_for_rw) { - sd_printk(KERN_NOTICE, sdkp, - "Uses READ/WRITE(6), disabling FUA\n"); - sdkp->DPOFUA = 0; - } - - if (sdkp->first_scan || old_wce != sdkp->WCE || - old_rcd != sdkp->RCD || old_dpofua != sdkp->DPOFUA) - sd_printk(KERN_NOTICE, sdkp, - "Write cache: %s, read cache: %s, %s\n", - sdkp->WCE ? "enabled" : "disabled", - sdkp->RCD ? "disabled" : "enabled", - sdkp->DPOFUA ? "supports DPO and FUA" - : "doesn't support DPO or FUA"); - - return; - } - -bad_sense: - if (scsi_sense_valid(&sshdr) && - sshdr.sense_key == ILLEGAL_REQUEST && - sshdr.asc == 0x24 && sshdr.ascq == 0x0) - /* Invalid field in CDB */ - sd_printk(KERN_NOTICE, sdkp, "Cache data unavailable\n"); - else - sd_printk(KERN_ERR, sdkp, "Asking for cache data failed\n"); - -defaults: - sd_printk(KERN_ERR, sdkp, "Assuming drive cache: write through\n"); - sdkp->WCE = 0; - sdkp->RCD = 0; - sdkp->DPOFUA = 0; -} - -/* - * The ATO bit indicates whether the DIF application tag is available - * for use by the operating system. - */ -static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) -{ - int res, offset; - struct scsi_device *sdp = sdkp->device; - struct scsi_mode_data data; - struct scsi_sense_hdr sshdr; - - if (sdp->type != TYPE_DISK) - return; - - if (sdkp->protection_type == 0) - return; - - res = scsi_mode_sense(sdp, 1, 0x0a, buffer, 36, SD_TIMEOUT, - SD_MAX_RETRIES, &data, &sshdr); - - if (!scsi_status_is_good(res) || !data.header_length || - data.length < 6) { - sd_printk(KERN_WARNING, sdkp, - "getting Control mode page failed, assume no ATO\n"); - - if (scsi_sense_valid(&sshdr)) - sd_print_sense_hdr(sdkp, &sshdr); - - return; - } - - offset = data.header_length + data.block_descriptor_length; - - if ((buffer[offset] & 0x3f) != 0x0a) { - sd_printk(KERN_ERR, sdkp, "ATO Got wrong page\n"); - return; - } - - if ((buffer[offset + 5] & 0x80) == 0) - return; - - sdkp->ATO = 1; - - return; -} - -/** - * sd_read_block_limits - Query disk device for preferred I/O sizes. - * @disk: disk to query - */ -static void sd_read_block_limits(struct scsi_disk *sdkp) -{ - unsigned int sector_sz = sdkp->device->sector_size; - const int vpd_len = 64; - unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL); - - if (!buffer || - /* Block Limits VPD */ - scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len)) - goto out; - - blk_queue_io_min(sdkp->disk->queue, - get_unaligned_be16(&buffer[6]) * sector_sz); - blk_queue_io_opt(sdkp->disk->queue, - get_unaligned_be32(&buffer[12]) * sector_sz); - - if (buffer[3] == 0x3c) { - unsigned int lba_count, desc_count; - - sdkp->max_ws_blocks = - (u32) min_not_zero(get_unaligned_be64(&buffer[36]), - (u64)0xffffffff); - - if (!sdkp->lbpme) - goto out; - - lba_count = get_unaligned_be32(&buffer[20]); - desc_count = get_unaligned_be32(&buffer[24]); - - if (lba_count && desc_count) - sdkp->max_unmap_blocks = lba_count; - - sdkp->unmap_granularity = get_unaligned_be32(&buffer[28]); - - if (buffer[32] & 0x80) - sdkp->unmap_alignment = - get_unaligned_be32(&buffer[32]) & ~(1 << 31); - - if (!sdkp->lbpvpd) { /* LBP VPD page not provided */ - - if (sdkp->max_unmap_blocks) - sd_config_discard(sdkp, SD_LBP_UNMAP); - else - sd_config_discard(sdkp, SD_LBP_WS16); - - } else { /* LBP VPD page tells us what to use */ - - if (sdkp->lbpu && sdkp->max_unmap_blocks) - sd_config_discard(sdkp, SD_LBP_UNMAP); - else if (sdkp->lbpws) - sd_config_discard(sdkp, SD_LBP_WS16); - else if (sdkp->lbpws10) - sd_config_discard(sdkp, SD_LBP_WS10); - else - sd_config_discard(sdkp, SD_LBP_DISABLE); - } - } - - out: - kfree(buffer); -} - -/** - * sd_read_block_characteristics - Query block dev. characteristics - * @disk: disk to query - */ -static void sd_read_block_characteristics(struct scsi_disk *sdkp) -{ - unsigned char *buffer; - u16 rot; - const int vpd_len = 64; - - buffer = kmalloc(vpd_len, GFP_KERNEL); - - if (!buffer || - /* Block Device Characteristics VPD */ - scsi_get_vpd_page(sdkp->device, 0xb1, buffer, vpd_len)) - goto out; - - rot = get_unaligned_be16(&buffer[4]); - - if (rot == 1) - queue_flag_set_unlocked(QUEUE_FLAG_NONROT, sdkp->disk->queue); - - out: - kfree(buffer); -} - -/** - * sd_read_block_provisioning - Query provisioning VPD page - * @disk: disk to query - */ -static void sd_read_block_provisioning(struct scsi_disk *sdkp) -{ - unsigned char *buffer; - const int vpd_len = 8; - - if (sdkp->lbpme == 0) - return; - - buffer = kmalloc(vpd_len, GFP_KERNEL); - - if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb2, buffer, vpd_len)) - goto out; - - sdkp->lbpvpd = 1; - sdkp->lbpu = (buffer[5] >> 7) & 1; /* UNMAP */ - sdkp->lbpws = (buffer[5] >> 6) & 1; /* WRITE SAME(16) with UNMAP */ - sdkp->lbpws10 = (buffer[5] >> 5) & 1; /* WRITE SAME(10) with UNMAP */ - - out: - kfree(buffer); -} - -static int sd_try_extended_inquiry(struct scsi_device *sdp) -{ - /* - * Although VPD inquiries can go to SCSI-2 type devices, - * some USB ones crash on receiving them, and the pages - * we currently ask for are for SPC-3 and beyond - */ - if (sdp->scsi_level > SCSI_SPC_2 && !sdp->skip_vpd_pages) - return 1; - return 0; -} - -/** - * sd_revalidate_disk - called the first time a new disk is seen, - * performs disk spin up, read_capacity, etc. - * @disk: struct gendisk we care about - **/ -static int sd_revalidate_disk(struct gendisk *disk) -{ - struct scsi_disk *sdkp = scsi_disk(disk); - struct scsi_device *sdp = sdkp->device; - unsigned char *buffer; - unsigned flush = 0; - - SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, - "sd_revalidate_disk\n")); - - /* - * If the device is offline, don't try and read capacity or any - * of the other niceties. - */ - if (!scsi_device_online(sdp)) - goto out; - - buffer = kmalloc(SD_BUF_SIZE, GFP_KERNEL); - if (!buffer) { - sd_printk(KERN_WARNING, sdkp, "sd_revalidate_disk: Memory " - "allocation failure.\n"); - goto out; - } - - sd_spinup_disk(sdkp); - - /* - * Without media there is no reason to ask; moreover, some devices - * react badly if we do. - */ - if (sdkp->media_present) { - sd_read_capacity(sdkp, buffer); - - if (sd_try_extended_inquiry(sdp)) { - sd_read_block_provisioning(sdkp); - sd_read_block_limits(sdkp); - sd_read_block_characteristics(sdkp); - } - - sd_read_write_protect_flag(sdkp, buffer); - sd_read_cache_type(sdkp, buffer); - sd_read_app_tag_own(sdkp, buffer); - } - - sdkp->first_scan = 0; - - /* - * We now have all cache related info, determine how we deal - * with flush requests. - */ - if (sdkp->WCE) { - flush |= REQ_FLUSH; - if (sdkp->DPOFUA) - flush |= REQ_FUA; - } - - blk_queue_flush(sdkp->disk->queue, flush); - - set_capacity(disk, sdkp->capacity); - kfree(buffer); - - out: - return 0; -} - -/** - * sd_unlock_native_capacity - unlock native capacity - * @disk: struct gendisk to set capacity for - * - * Block layer calls this function if it detects that partitions - * on @disk reach beyond the end of the device. If the SCSI host - * implements ->unlock_native_capacity() method, it's invoked to - * give it a chance to adjust the device capacity. - * - * CONTEXT: - * Defined by block layer. Might sleep. - */ -static void sd_unlock_native_capacity(struct gendisk *disk) -{ - struct scsi_device *sdev = scsi_disk(disk)->device; - - if (sdev->host->hostt->unlock_native_capacity) - sdev->host->hostt->unlock_native_capacity(sdev); -} - -/** - * sd_format_disk_name - format disk name - * @prefix: name prefix - ie. "sd" for SCSI disks - * @index: index of the disk to format name for - * @buf: output buffer - * @buflen: length of the output buffer - * - * SCSI disk names starts at sda. The 26th device is sdz and the - * 27th is sdaa. The last one for two lettered suffix is sdzz - * which is followed by sdaaa. - * - * This is basically 26 base counting with one extra 'nil' entry - * at the beginning from the second digit on and can be - * determined using similar method as 26 base conversion with the - * index shifted -1 after each digit is computed. - * - * CONTEXT: - * Don't care. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -static int sd_format_disk_name(char *prefix, int index, char *buf, int buflen) -{ - const int base = 'z' - 'a' + 1; - char *begin = buf + strlen(prefix); - char *end = buf + buflen; - char *p; - int unit; - - p = end - 1; - *p = '\0'; - unit = base; - do { - if (p == begin) - return -EINVAL; - *--p = 'a' + (index % unit); - index = (index / unit) - 1; - } while (index >= 0); - - memmove(begin, p, end - p); - memcpy(buf, prefix, strlen(prefix)); - - return 0; -} - -/* - * The asynchronous part of sd_probe - */ -static void sd_probe_async(void *data, async_cookie_t cookie) -{ - struct scsi_disk *sdkp = data; - struct scsi_device *sdp; - struct gendisk *gd; - u32 index; - struct device *dev; - - sdp = sdkp->device; - gd = sdkp->disk; - index = sdkp->index; - dev = &sdp->sdev_gendev; - - gd->major = sd_major((index & 0xf0) >> 4); - gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00); - gd->minors = SD_MINORS; - - gd->fops = &sd_fops; - gd->private_data = &sdkp->driver; - gd->queue = sdkp->device->request_queue; - - /* defaults, until the device tells us otherwise */ - sdp->sector_size = 512; - sdkp->capacity = 0; - sdkp->media_present = 1; - sdkp->write_prot = 0; - sdkp->WCE = 0; - sdkp->RCD = 0; - sdkp->ATO = 0; - sdkp->first_scan = 1; - sdkp->max_medium_access_timeouts = SD_MAX_MEDIUM_TIMEOUTS; - - sd_revalidate_disk(gd); - - blk_queue_prep_rq(sdp->request_queue, sd_prep_fn); - blk_queue_unprep_rq(sdp->request_queue, sd_unprep_fn); - - gd->driverfs_dev = &sdp->sdev_gendev; - gd->flags = GENHD_FL_EXT_DEVT; - if (sdp->removable) { - gd->flags |= GENHD_FL_REMOVABLE; - gd->events |= DISK_EVENT_MEDIA_CHANGE; - } - - add_disk(gd); - sd_dif_config_host(sdkp); - - sd_revalidate_disk(gd); - - sd_printk(KERN_NOTICE, sdkp, "Attached SCSI %sdisk\n", - sdp->removable ? "removable " : ""); - scsi_autopm_put_device(sdp); - put_device(&sdkp->dev); -} - -/** - * sd_probe - called during driver initialization and whenever a - * new scsi device is attached to the system. It is called once - * for each scsi device (not just disks) present. - * @dev: pointer to device object - * - * Returns 0 if successful (or not interested in this scsi device - * (e.g. scanner)); 1 when there is an error. - * - * Note: this function is invoked from the scsi mid-level. - * This function sets up the mapping between a given - * (found in sdp) and new device name - * (e.g. /dev/sda). More precisely it is the block device major - * and minor number that is chosen here. - * - * Assume sd_probe is not re-entrant (for time being) - * Also think about sd_probe() and sd_remove() running coincidentally. - **/ -static int sd_probe(struct device *dev) -{ - struct scsi_device *sdp = to_scsi_device(dev); - struct scsi_disk *sdkp; - struct gendisk *gd; - int index; - int error; - - error = -ENODEV; - if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD && sdp->type != TYPE_RBC) - goto out; - - SCSI_LOG_HLQUEUE(3, sdev_printk(KERN_INFO, sdp, - "sd_probe\n")); - - error = -ENOMEM; - sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL); - if (!sdkp) - goto out; - - gd = alloc_disk(SD_MINORS); - if (!gd) - goto out_free; - - do { - if (!ida_pre_get(&sd_index_ida, GFP_KERNEL)) - goto out_put; - - spin_lock(&sd_index_lock); - error = ida_get_new(&sd_index_ida, &index); - spin_unlock(&sd_index_lock); - } while (error == -EAGAIN); - - if (error) { - sdev_printk(KERN_WARNING, sdp, "sd_probe: memory exhausted.\n"); - goto out_put; - } - - error = sd_format_disk_name("sd", index, gd->disk_name, DISK_NAME_LEN); - if (error) { - sdev_printk(KERN_WARNING, sdp, "SCSI disk (sd) name length exceeded.\n"); - goto out_free_index; - } - - sdkp->device = sdp; - sdkp->driver = &sd_template; - sdkp->disk = gd; - sdkp->index = index; - atomic_set(&sdkp->openers, 0); - - if (!sdp->request_queue->rq_timeout) { - if (sdp->type != TYPE_MOD) - blk_queue_rq_timeout(sdp->request_queue, SD_TIMEOUT); - else - blk_queue_rq_timeout(sdp->request_queue, - SD_MOD_TIMEOUT); - } - - device_initialize(&sdkp->dev); - sdkp->dev.parent = dev; - sdkp->dev.class = &sd_disk_class; - dev_set_name(&sdkp->dev, dev_name(dev)); - - if (device_add(&sdkp->dev)) - goto out_free_index; - - get_device(dev); - dev_set_drvdata(dev, sdkp); - - get_device(&sdkp->dev); /* prevent release before async_schedule */ - async_schedule(sd_probe_async, sdkp); - - return 0; - - out_free_index: - spin_lock(&sd_index_lock); - ida_remove(&sd_index_ida, index); - spin_unlock(&sd_index_lock); - out_put: - put_disk(gd); - out_free: - kfree(sdkp); - out: - return error; -} - -/** - * sd_remove - called whenever a scsi disk (previously recognized by - * sd_probe) is detached from the system. It is called (potentially - * multiple times) during sd module unload. - * @sdp: pointer to mid level scsi device object - * - * Note: this function is invoked from the scsi mid-level. - * This function potentially frees up a device name (e.g. /dev/sdc) - * that could be re-used by a subsequent sd_probe(). - * This function is not called when the built-in sd driver is "exit-ed". - **/ -static int sd_remove(struct device *dev) -{ - struct scsi_disk *sdkp; - - sdkp = dev_get_drvdata(dev); - scsi_autopm_get_device(sdkp->device); - - async_synchronize_full(); - blk_queue_prep_rq(sdkp->device->request_queue, scsi_prep_fn); - blk_queue_unprep_rq(sdkp->device->request_queue, NULL); - device_del(&sdkp->dev); - del_gendisk(sdkp->disk); - sd_shutdown(dev); - - mutex_lock(&sd_ref_mutex); - dev_set_drvdata(dev, NULL); - put_device(&sdkp->dev); - mutex_unlock(&sd_ref_mutex); - - return 0; -} - -/** - * scsi_disk_release - Called to free the scsi_disk structure - * @dev: pointer to embedded class device - * - * sd_ref_mutex must be held entering this routine. Because it is - * called on last put, you should always use the scsi_disk_get() - * scsi_disk_put() helpers which manipulate the semaphore directly - * and never do a direct put_device. - **/ -static void scsi_disk_release(struct device *dev) -{ - struct scsi_disk *sdkp = to_scsi_disk(dev); - struct gendisk *disk = sdkp->disk; - - spin_lock(&sd_index_lock); - ida_remove(&sd_index_ida, sdkp->index); - spin_unlock(&sd_index_lock); - - disk->private_data = NULL; - put_disk(disk); - put_device(&sdkp->device->sdev_gendev); - - kfree(sdkp); -} - -static int sd_start_stop_device(struct scsi_disk *sdkp, int start) -{ - unsigned char cmd[6] = { START_STOP }; /* START_VALID */ - struct scsi_sense_hdr sshdr; - struct scsi_device *sdp = sdkp->device; - int res; - - if (start) - cmd[4] |= 1; /* START */ - - if (sdp->start_stop_pwr_cond) - cmd[4] |= start ? 1 << 4 : 3 << 4; /* Active or Standby */ - - if (!scsi_device_online(sdp)) - return -ENODEV; - - res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, - SD_TIMEOUT, SD_MAX_RETRIES, NULL); - if (res) { - sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n"); - sd_print_result(sdkp, res); - if (driver_byte(res) & DRIVER_SENSE) - sd_print_sense_hdr(sdkp, &sshdr); - } - - return res; -} - -/* - * Send a SYNCHRONIZE CACHE instruction down to the device through - * the normal SCSI command structure. Wait for the command to - * complete. - */ -static void sd_shutdown(struct device *dev) -{ - struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); - - if (!sdkp) - return; /* this can happen */ - - if (pm_runtime_suspended(dev)) - goto exit; - - if (sdkp->WCE) { - sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); - sd_sync_cache(sdkp); - } - - if (system_state != SYSTEM_RESTART && sdkp->device->manage_start_stop) { - sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); - sd_start_stop_device(sdkp, 0); - } - -exit: - scsi_disk_put(sdkp); -} - -static int sd_suspend(struct device *dev, pm_message_t mesg) -{ - struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); - int ret = 0; - - if (!sdkp) - return 0; /* this can happen */ - - if (sdkp->WCE) { - sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); - ret = sd_sync_cache(sdkp); - if (ret) - goto done; - } - - if ((mesg.event & PM_EVENT_SLEEP) && sdkp->device->manage_start_stop) { - sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); - ret = sd_start_stop_device(sdkp, 0); - } - -done: - scsi_disk_put(sdkp); - return ret; -} - -static int sd_resume(struct device *dev) -{ - struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); - int ret = 0; - - if (!sdkp->device->manage_start_stop) - goto done; - - sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); - ret = sd_start_stop_device(sdkp, 1); - -done: - scsi_disk_put(sdkp); - return ret; -} - -/** - * init_sd - entry point for this driver (both when built in or when - * a module). - * - * Note: this function registers this driver with the scsi mid-level. - **/ -static int __init init_sd(void) -{ - int majors = 0, i, err; - - SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); - - for (i = 0; i < SD_MAJORS; i++) - if (register_blkdev(sd_major(i), "sd") == 0) - majors++; - - if (!majors) - return -ENODEV; - - err = class_register(&sd_disk_class); - if (err) - goto err_out; - - err = scsi_register_driver(&sd_template.gendrv); - if (err) - goto err_out_class; - - sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE, - 0, 0, NULL); - if (!sd_cdb_cache) { - printk(KERN_ERR "sd: can't init extended cdb cache\n"); - goto err_out_class; - } - - sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache); - if (!sd_cdb_pool) { - printk(KERN_ERR "sd: can't init extended cdb pool\n"); - goto err_out_cache; - } - - return 0; - -err_out_cache: - kmem_cache_destroy(sd_cdb_cache); - -err_out_class: - class_unregister(&sd_disk_class); -err_out: - for (i = 0; i < SD_MAJORS; i++) - unregister_blkdev(sd_major(i), "sd"); - return err; -} - -/** - * exit_sd - exit point for this driver (when it is a module). - * - * Note: this function unregisters this driver from the scsi mid-level. - **/ -static void __exit exit_sd(void) -{ - int i; - - SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); - - mempool_destroy(sd_cdb_pool); - kmem_cache_destroy(sd_cdb_cache); - - scsi_unregister_driver(&sd_template.gendrv); - class_unregister(&sd_disk_class); - - for (i = 0; i < SD_MAJORS; i++) - unregister_blkdev(sd_major(i), "sd"); -} - -module_init(init_sd); -module_exit(exit_sd); - -static void sd_print_sense_hdr(struct scsi_disk *sdkp, - struct scsi_sense_hdr *sshdr) -{ - sd_printk(KERN_INFO, sdkp, " "); - scsi_show_sense_hdr(sshdr); - sd_printk(KERN_INFO, sdkp, " "); - scsi_show_extd_sense(sshdr->asc, sshdr->ascq); -} - -static void sd_print_result(struct scsi_disk *sdkp, int result) -{ - sd_printk(KERN_INFO, sdkp, " "); - scsi_show_result(result); -} - diff --git a/ANDROID_3.4.5/drivers/scsi/sd.h b/ANDROID_3.4.5/drivers/scsi/sd.h deleted file mode 100644 index f703f482..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sd.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef _SCSI_DISK_H -#define _SCSI_DISK_H - -/* - * More than enough for everybody ;) The huge number of majors - * is a leftover from 16bit dev_t days, we don't really need that - * much numberspace. - */ -#define SD_MAJORS 16 - -/* - * Time out in seconds for disks and Magneto-opticals (which are slower). - */ -#define SD_TIMEOUT (30 * HZ) -#define SD_MOD_TIMEOUT (75 * HZ) -#define SD_FLUSH_TIMEOUT (60 * HZ) - -/* - * Number of allowed retries - */ -#define SD_MAX_RETRIES 5 -#define SD_PASSTHROUGH_RETRIES 1 -#define SD_MAX_MEDIUM_TIMEOUTS 2 - -/* - * Size of the initial data buffer for mode and read capacity data - */ -#define SD_BUF_SIZE 512 - -/* - * Number of sectors at the end of the device to avoid multi-sector - * accesses to in the case of last_sector_bug - */ -#define SD_LAST_BUGGY_SECTORS 8 - -enum { - SD_EXT_CDB_SIZE = 32, /* Extended CDB size */ - SD_MEMPOOL_SIZE = 2, /* CDB pool size */ -}; - -enum { - SD_LBP_FULL = 0, /* Full logical block provisioning */ - SD_LBP_UNMAP, /* Use UNMAP command */ - SD_LBP_WS16, /* Use WRITE SAME(16) with UNMAP bit */ - SD_LBP_WS10, /* Use WRITE SAME(10) with UNMAP bit */ - SD_LBP_ZERO, /* Use WRITE SAME(10) with zero payload */ - SD_LBP_DISABLE, /* Discard disabled due to failed cmd */ -}; - -struct scsi_disk { - struct scsi_driver *driver; /* always &sd_template */ - struct scsi_device *device; - struct device dev; - struct gendisk *disk; - atomic_t openers; - sector_t capacity; /* size in 512-byte sectors */ - u32 max_ws_blocks; - u32 max_unmap_blocks; - u32 unmap_granularity; - u32 unmap_alignment; - u32 index; - unsigned int physical_block_size; - unsigned int max_medium_access_timeouts; - unsigned int medium_access_timed_out; - u8 media_present; - u8 write_prot; - u8 protection_type;/* Data Integrity Field */ - u8 provisioning_mode; - unsigned ATO : 1; /* state of disk ATO bit */ - unsigned WCE : 1; /* state of disk WCE bit */ - unsigned RCD : 1; /* state of disk RCD bit, unused */ - unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ - unsigned first_scan : 1; - unsigned lbpme : 1; - unsigned lbprz : 1; - unsigned lbpu : 1; - unsigned lbpws : 1; - unsigned lbpws10 : 1; - unsigned lbpvpd : 1; -}; -#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) - -static inline struct scsi_disk *scsi_disk(struct gendisk *disk) -{ - return container_of(disk->private_data, struct scsi_disk, driver); -} - -#define sd_printk(prefix, sdsk, fmt, a...) \ - (sdsk)->disk ? \ - sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \ - (sdsk)->disk->disk_name, ##a) : \ - sdev_printk(prefix, (sdsk)->device, fmt, ##a) - -static inline int scsi_medium_access_command(struct scsi_cmnd *scmd) -{ - switch (scmd->cmnd[0]) { - case READ_6: - case READ_10: - case READ_12: - case READ_16: - case SYNCHRONIZE_CACHE: - case VERIFY: - case VERIFY_12: - case VERIFY_16: - case WRITE_6: - case WRITE_10: - case WRITE_12: - case WRITE_16: - case WRITE_SAME: - case WRITE_SAME_16: - case UNMAP: - return 1; - case VARIABLE_LENGTH_CMD: - switch (scmd->cmnd[9]) { - case READ_32: - case VERIFY_32: - case WRITE_32: - case WRITE_SAME_32: - return 1; - } - } - - return 0; -} - -/* - * A DIF-capable target device can be formatted with different - * protection schemes. Currently 0 through 3 are defined: - * - * Type 0 is regular (unprotected) I/O - * - * Type 1 defines the contents of the guard and reference tags - * - * Type 2 defines the contents of the guard and reference tags and - * uses 32-byte commands to seed the latter - * - * Type 3 defines the contents of the guard tag only - */ - -enum sd_dif_target_protection_types { - SD_DIF_TYPE0_PROTECTION = 0x0, - SD_DIF_TYPE1_PROTECTION = 0x1, - SD_DIF_TYPE2_PROTECTION = 0x2, - SD_DIF_TYPE3_PROTECTION = 0x3, -}; - -/* - * Data Integrity Field tuple. - */ -struct sd_dif_tuple { - __be16 guard_tag; /* Checksum */ - __be16 app_tag; /* Opaque storage */ - __be32 ref_tag; /* Target LBA or indirect LBA */ -}; - -#ifdef CONFIG_BLK_DEV_INTEGRITY - -extern void sd_dif_config_host(struct scsi_disk *); -extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int); -extern void sd_dif_complete(struct scsi_cmnd *, unsigned int); - -#else /* CONFIG_BLK_DEV_INTEGRITY */ - -static inline void sd_dif_config_host(struct scsi_disk *disk) -{ -} -static inline int sd_dif_prepare(struct request *rq, sector_t s, unsigned int a) -{ - return 0; -} -static inline void sd_dif_complete(struct scsi_cmnd *cmd, unsigned int a) -{ -} - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -#endif /* _SCSI_DISK_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/sd_dif.c b/ANDROID_3.4.5/drivers/scsi/sd_dif.c deleted file mode 100644 index e52d5bc4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sd_dif.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * sd_dif.c - SCSI Data Integrity Field - * - * Copyright (C) 2007, 2008 Oracle Corporation - * Written by: Martin K. Petersen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, - * USA. - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sd.h" - -typedef __u16 (csum_fn) (void *, unsigned int); - -static __u16 sd_dif_crc_fn(void *data, unsigned int len) -{ - return cpu_to_be16(crc_t10dif(data, len)); -} - -static __u16 sd_dif_ip_fn(void *data, unsigned int len) -{ - return ip_compute_csum(data, len); -} - -/* - * Type 1 and Type 2 protection use the same format: 16 bit guard tag, - * 16 bit app tag, 32 bit reference tag. - */ -static void sd_dif_type1_generate(struct blk_integrity_exchg *bix, csum_fn *fn) -{ - void *buf = bix->data_buf; - struct sd_dif_tuple *sdt = bix->prot_buf; - sector_t sector = bix->sector; - unsigned int i; - - for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { - sdt->guard_tag = fn(buf, bix->sector_size); - sdt->ref_tag = cpu_to_be32(sector & 0xffffffff); - sdt->app_tag = 0; - - buf += bix->sector_size; - sector++; - } -} - -static void sd_dif_type1_generate_crc(struct blk_integrity_exchg *bix) -{ - sd_dif_type1_generate(bix, sd_dif_crc_fn); -} - -static void sd_dif_type1_generate_ip(struct blk_integrity_exchg *bix) -{ - sd_dif_type1_generate(bix, sd_dif_ip_fn); -} - -static int sd_dif_type1_verify(struct blk_integrity_exchg *bix, csum_fn *fn) -{ - void *buf = bix->data_buf; - struct sd_dif_tuple *sdt = bix->prot_buf; - sector_t sector = bix->sector; - unsigned int i; - __u16 csum; - - for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { - /* Unwritten sectors */ - if (sdt->app_tag == 0xffff) - return 0; - - /* Bad ref tag received from disk */ - if (sdt->ref_tag == 0xffffffff) { - printk(KERN_ERR - "%s: bad phys ref tag on sector %lu\n", - bix->disk_name, (unsigned long)sector); - return -EIO; - } - - if (be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { - printk(KERN_ERR - "%s: ref tag error on sector %lu (rcvd %u)\n", - bix->disk_name, (unsigned long)sector, - be32_to_cpu(sdt->ref_tag)); - return -EIO; - } - - csum = fn(buf, bix->sector_size); - - if (sdt->guard_tag != csum) { - printk(KERN_ERR "%s: guard tag error on sector %lu " \ - "(rcvd %04x, data %04x)\n", bix->disk_name, - (unsigned long)sector, - be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); - return -EIO; - } - - buf += bix->sector_size; - sector++; - } - - return 0; -} - -static int sd_dif_type1_verify_crc(struct blk_integrity_exchg *bix) -{ - return sd_dif_type1_verify(bix, sd_dif_crc_fn); -} - -static int sd_dif_type1_verify_ip(struct blk_integrity_exchg *bix) -{ - return sd_dif_type1_verify(bix, sd_dif_ip_fn); -} - -/* - * Functions for interleaving and deinterleaving application tags - */ -static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors) -{ - struct sd_dif_tuple *sdt = prot; - u8 *tag = tag_buf; - unsigned int i, j; - - for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { - sdt->app_tag = tag[j] << 8 | tag[j+1]; - BUG_ON(sdt->app_tag == 0xffff); - } -} - -static void sd_dif_type1_get_tag(void *prot, void *tag_buf, unsigned int sectors) -{ - struct sd_dif_tuple *sdt = prot; - u8 *tag = tag_buf; - unsigned int i, j; - - for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { - tag[j] = (sdt->app_tag & 0xff00) >> 8; - tag[j+1] = sdt->app_tag & 0xff; - } -} - -static struct blk_integrity dif_type1_integrity_crc = { - .name = "T10-DIF-TYPE1-CRC", - .generate_fn = sd_dif_type1_generate_crc, - .verify_fn = sd_dif_type1_verify_crc, - .get_tag_fn = sd_dif_type1_get_tag, - .set_tag_fn = sd_dif_type1_set_tag, - .tuple_size = sizeof(struct sd_dif_tuple), - .tag_size = 0, -}; - -static struct blk_integrity dif_type1_integrity_ip = { - .name = "T10-DIF-TYPE1-IP", - .generate_fn = sd_dif_type1_generate_ip, - .verify_fn = sd_dif_type1_verify_ip, - .get_tag_fn = sd_dif_type1_get_tag, - .set_tag_fn = sd_dif_type1_set_tag, - .tuple_size = sizeof(struct sd_dif_tuple), - .tag_size = 0, -}; - - -/* - * Type 3 protection has a 16-bit guard tag and 16 + 32 bits of opaque - * tag space. - */ -static void sd_dif_type3_generate(struct blk_integrity_exchg *bix, csum_fn *fn) -{ - void *buf = bix->data_buf; - struct sd_dif_tuple *sdt = bix->prot_buf; - unsigned int i; - - for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { - sdt->guard_tag = fn(buf, bix->sector_size); - sdt->ref_tag = 0; - sdt->app_tag = 0; - - buf += bix->sector_size; - } -} - -static void sd_dif_type3_generate_crc(struct blk_integrity_exchg *bix) -{ - sd_dif_type3_generate(bix, sd_dif_crc_fn); -} - -static void sd_dif_type3_generate_ip(struct blk_integrity_exchg *bix) -{ - sd_dif_type3_generate(bix, sd_dif_ip_fn); -} - -static int sd_dif_type3_verify(struct blk_integrity_exchg *bix, csum_fn *fn) -{ - void *buf = bix->data_buf; - struct sd_dif_tuple *sdt = bix->prot_buf; - sector_t sector = bix->sector; - unsigned int i; - __u16 csum; - - for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) { - /* Unwritten sectors */ - if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff) - return 0; - - csum = fn(buf, bix->sector_size); - - if (sdt->guard_tag != csum) { - printk(KERN_ERR "%s: guard tag error on sector %lu " \ - "(rcvd %04x, data %04x)\n", bix->disk_name, - (unsigned long)sector, - be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); - return -EIO; - } - - buf += bix->sector_size; - sector++; - } - - return 0; -} - -static int sd_dif_type3_verify_crc(struct blk_integrity_exchg *bix) -{ - return sd_dif_type3_verify(bix, sd_dif_crc_fn); -} - -static int sd_dif_type3_verify_ip(struct blk_integrity_exchg *bix) -{ - return sd_dif_type3_verify(bix, sd_dif_ip_fn); -} - -static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors) -{ - struct sd_dif_tuple *sdt = prot; - u8 *tag = tag_buf; - unsigned int i, j; - - for (i = 0, j = 0 ; i < sectors ; i++, j += 6, sdt++) { - sdt->app_tag = tag[j] << 8 | tag[j+1]; - sdt->ref_tag = tag[j+2] << 24 | tag[j+3] << 16 | - tag[j+4] << 8 | tag[j+5]; - } -} - -static void sd_dif_type3_get_tag(void *prot, void *tag_buf, unsigned int sectors) -{ - struct sd_dif_tuple *sdt = prot; - u8 *tag = tag_buf; - unsigned int i, j; - - for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) { - tag[j] = (sdt->app_tag & 0xff00) >> 8; - tag[j+1] = sdt->app_tag & 0xff; - tag[j+2] = (sdt->ref_tag & 0xff000000) >> 24; - tag[j+3] = (sdt->ref_tag & 0xff0000) >> 16; - tag[j+4] = (sdt->ref_tag & 0xff00) >> 8; - tag[j+5] = sdt->ref_tag & 0xff; - BUG_ON(sdt->app_tag == 0xffff || sdt->ref_tag == 0xffffffff); - } -} - -static struct blk_integrity dif_type3_integrity_crc = { - .name = "T10-DIF-TYPE3-CRC", - .generate_fn = sd_dif_type3_generate_crc, - .verify_fn = sd_dif_type3_verify_crc, - .get_tag_fn = sd_dif_type3_get_tag, - .set_tag_fn = sd_dif_type3_set_tag, - .tuple_size = sizeof(struct sd_dif_tuple), - .tag_size = 0, -}; - -static struct blk_integrity dif_type3_integrity_ip = { - .name = "T10-DIF-TYPE3-IP", - .generate_fn = sd_dif_type3_generate_ip, - .verify_fn = sd_dif_type3_verify_ip, - .get_tag_fn = sd_dif_type3_get_tag, - .set_tag_fn = sd_dif_type3_set_tag, - .tuple_size = sizeof(struct sd_dif_tuple), - .tag_size = 0, -}; - -/* - * Configure exchange of protection information between OS and HBA. - */ -void sd_dif_config_host(struct scsi_disk *sdkp) -{ - struct scsi_device *sdp = sdkp->device; - struct gendisk *disk = sdkp->disk; - u8 type = sdkp->protection_type; - int dif, dix; - - dif = scsi_host_dif_capable(sdp->host, type); - dix = scsi_host_dix_capable(sdp->host, type); - - if (!dix && scsi_host_dix_capable(sdp->host, 0)) { - dif = 0; dix = 1; - } - - if (!dix) - return; - - /* Enable DMA of protection information */ - if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) - if (type == SD_DIF_TYPE3_PROTECTION) - blk_integrity_register(disk, &dif_type3_integrity_ip); - else - blk_integrity_register(disk, &dif_type1_integrity_ip); - else - if (type == SD_DIF_TYPE3_PROTECTION) - blk_integrity_register(disk, &dif_type3_integrity_crc); - else - blk_integrity_register(disk, &dif_type1_integrity_crc); - - sd_printk(KERN_NOTICE, sdkp, - "Enabling DIX %s protection\n", disk->integrity->name); - - /* Signal to block layer that we support sector tagging */ - if (dif && type && sdkp->ATO) { - if (type == SD_DIF_TYPE3_PROTECTION) - disk->integrity->tag_size = sizeof(u16) + sizeof(u32); - else - disk->integrity->tag_size = sizeof(u16); - - sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n", - disk->integrity->tag_size); - } -} - -/* - * The virtual start sector is the one that was originally submitted - * by the block layer. Due to partitioning, MD/DM cloning, etc. the - * actual physical start sector is likely to be different. Remap - * protection information to match the physical LBA. - * - * From a protocol perspective there's a slight difference between - * Type 1 and 2. The latter uses 32-byte CDBs exclusively, and the - * reference tag is seeded in the CDB. This gives us the potential to - * avoid virt->phys remapping during write. However, at read time we - * don't know whether the virt sector is the same as when we wrote it - * (we could be reading from real disk as opposed to MD/DM device. So - * we always remap Type 2 making it identical to Type 1. - * - * Type 3 does not have a reference tag so no remapping is required. - */ -int sd_dif_prepare(struct request *rq, sector_t hw_sector, unsigned int sector_sz) -{ - const int tuple_sz = sizeof(struct sd_dif_tuple); - struct bio *bio; - struct scsi_disk *sdkp; - struct sd_dif_tuple *sdt; - unsigned int i, j; - u32 phys, virt; - - sdkp = rq->bio->bi_bdev->bd_disk->private_data; - - if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION) - return 0; - - phys = hw_sector & 0xffffffff; - - __rq_for_each_bio(bio, rq) { - struct bio_vec *iv; - - /* Already remapped? */ - if (bio_flagged(bio, BIO_MAPPED_INTEGRITY)) - break; - - virt = bio->bi_integrity->bip_sector & 0xffffffff; - - bip_for_each_vec(iv, bio->bi_integrity, i) { - sdt = kmap_atomic(iv->bv_page) - + iv->bv_offset; - - for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { - - if (be32_to_cpu(sdt->ref_tag) != virt) - goto error; - - sdt->ref_tag = cpu_to_be32(phys); - virt++; - phys++; - } - - kunmap_atomic(sdt); - } - - bio->bi_flags |= (1 << BIO_MAPPED_INTEGRITY); - } - - return 0; - -error: - kunmap_atomic(sdt); - sd_printk(KERN_ERR, sdkp, "%s: virt %u, phys %u, ref %u, app %4x\n", - __func__, virt, phys, be32_to_cpu(sdt->ref_tag), - be16_to_cpu(sdt->app_tag)); - - return -EILSEQ; -} - -/* - * Remap physical sector values in the reference tag to the virtual - * values expected by the block layer. - */ -void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes) -{ - const int tuple_sz = sizeof(struct sd_dif_tuple); - struct scsi_disk *sdkp; - struct bio *bio; - struct sd_dif_tuple *sdt; - unsigned int i, j, sectors, sector_sz; - u32 phys, virt; - - sdkp = scsi_disk(scmd->request->rq_disk); - - if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0) - return; - - sector_sz = scmd->device->sector_size; - sectors = good_bytes / sector_sz; - - phys = blk_rq_pos(scmd->request) & 0xffffffff; - if (sector_sz == 4096) - phys >>= 3; - - __rq_for_each_bio(bio, scmd->request) { - struct bio_vec *iv; - - virt = bio->bi_integrity->bip_sector & 0xffffffff; - - bip_for_each_vec(iv, bio->bi_integrity, i) { - sdt = kmap_atomic(iv->bv_page) - + iv->bv_offset; - - for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) { - - if (sectors == 0) { - kunmap_atomic(sdt); - return; - } - - if (be32_to_cpu(sdt->ref_tag) != phys && - sdt->app_tag != 0xffff) - sdt->ref_tag = 0xffffffff; /* Bad ref */ - else - sdt->ref_tag = cpu_to_be32(virt); - - virt++; - phys++; - sectors--; - } - - kunmap_atomic(sdt); - } - } -} - diff --git a/ANDROID_3.4.5/drivers/scsi/ses.c b/ANDROID_3.4.5/drivers/scsi/ses.c deleted file mode 100644 index eba183c4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ses.c +++ /dev/null @@ -1,754 +0,0 @@ -/* - * SCSI Enclosure Services - * - * Copyright (C) 2008 James Bottomley - * -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License -** version 2 as published by the Free Software Foundation. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -struct ses_device { - unsigned char *page1; - unsigned char *page1_types; - unsigned char *page2; - unsigned char *page10; - short page1_len; - short page1_num_types; - short page2_len; - short page10_len; -}; - -struct ses_component { - u64 addr; - unsigned char *desc; -}; - -static int ses_probe(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - int err = -ENODEV; - - if (sdev->type != TYPE_ENCLOSURE) - goto out; - - err = 0; - sdev_printk(KERN_NOTICE, sdev, "Attached Enclosure device\n"); - - out: - return err; -} - -#define SES_TIMEOUT (30 * HZ) -#define SES_RETRIES 3 - -static int ses_recv_diag(struct scsi_device *sdev, int page_code, - void *buf, int bufflen) -{ - unsigned char cmd[] = { - RECEIVE_DIAGNOSTIC, - 1, /* Set PCV bit */ - page_code, - bufflen >> 8, - bufflen & 0xff, - 0 - }; - - return scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, bufflen, - NULL, SES_TIMEOUT, SES_RETRIES, NULL); -} - -static int ses_send_diag(struct scsi_device *sdev, int page_code, - void *buf, int bufflen) -{ - u32 result; - - unsigned char cmd[] = { - SEND_DIAGNOSTIC, - 0x10, /* Set PF bit */ - 0, - bufflen >> 8, - bufflen & 0xff, - 0 - }; - - result = scsi_execute_req(sdev, cmd, DMA_TO_DEVICE, buf, bufflen, - NULL, SES_TIMEOUT, SES_RETRIES, NULL); - if (result) - sdev_printk(KERN_ERR, sdev, "SEND DIAGNOSTIC result: %8x\n", - result); - return result; -} - -static int ses_set_page2_descriptor(struct enclosure_device *edev, - struct enclosure_component *ecomp, - unsigned char *desc) -{ - int i, j, count = 0, descriptor = ecomp->number; - struct scsi_device *sdev = to_scsi_device(edev->edev.parent); - struct ses_device *ses_dev = edev->scratch; - unsigned char *type_ptr = ses_dev->page1_types; - unsigned char *desc_ptr = ses_dev->page2 + 8; - - /* Clear everything */ - memset(desc_ptr, 0, ses_dev->page2_len - 8); - for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - desc_ptr += 4; - if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && - type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) - continue; - if (count++ == descriptor) { - memcpy(desc_ptr, desc, 4); - /* set select */ - desc_ptr[0] |= 0x80; - /* clear reserved, just in case */ - desc_ptr[0] &= 0xf0; - } - } - } - - return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); -} - -static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - int i, j, count = 0, descriptor = ecomp->number; - struct scsi_device *sdev = to_scsi_device(edev->edev.parent); - struct ses_device *ses_dev = edev->scratch; - unsigned char *type_ptr = ses_dev->page1_types; - unsigned char *desc_ptr = ses_dev->page2 + 8; - - ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); - - for (i = 0; i < ses_dev->page1_num_types; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - desc_ptr += 4; - if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && - type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) - continue; - if (count++ == descriptor) - return desc_ptr; - } - } - return NULL; -} - -/* For device slot and array device slot elements, byte 3 bit 6 - * is "fault sensed" while byte 3 bit 5 is "fault reqstd". As this - * code stands these bits are shifted 4 positions right so in - * sysfs they will appear as bits 2 and 1 respectively. Strange. */ -static void ses_get_fault(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - unsigned char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - if (desc) - ecomp->fault = (desc[3] & 0x60) >> 4; -} - -static int ses_set_fault(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - unsigned char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - break; - case ENCLOSURE_SETTING_ENABLED: - desc[3] = 0x20; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static void ses_get_status(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - unsigned char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - if (desc) - ecomp->status = (desc[0] & 0x0f); -} - -static void ses_get_locate(struct enclosure_device *edev, - struct enclosure_component *ecomp) -{ - unsigned char *desc; - - desc = ses_get_page2_descriptor(edev, ecomp); - if (desc) - ecomp->locate = (desc[2] & 0x02) ? 1 : 0; -} - -static int ses_set_locate(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - unsigned char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - break; - case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x02; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static int ses_set_active(struct enclosure_device *edev, - struct enclosure_component *ecomp, - enum enclosure_component_setting val) -{ - unsigned char desc[4] = {0 }; - - switch (val) { - case ENCLOSURE_SETTING_DISABLED: - /* zero is disabled */ - ecomp->active = 0; - break; - case ENCLOSURE_SETTING_ENABLED: - desc[2] = 0x80; - ecomp->active = 1; - break; - default: - /* SES doesn't do the SGPIO blink settings */ - return -EINVAL; - } - return ses_set_page2_descriptor(edev, ecomp, desc); -} - -static struct enclosure_component_callbacks ses_enclosure_callbacks = { - .get_fault = ses_get_fault, - .set_fault = ses_set_fault, - .get_status = ses_get_status, - .get_locate = ses_get_locate, - .set_locate = ses_set_locate, - .set_active = ses_set_active, -}; - -struct ses_host_edev { - struct Scsi_Host *shost; - struct enclosure_device *edev; -}; - -#if 0 -int ses_match_host(struct enclosure_device *edev, void *data) -{ - struct ses_host_edev *sed = data; - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(edev->edev.parent)) - return 0; - - sdev = to_scsi_device(edev->edev.parent); - - if (sdev->host != sed->shost) - return 0; - - sed->edev = edev; - return 1; -} -#endif /* 0 */ - -static void ses_process_descriptor(struct enclosure_component *ecomp, - unsigned char *desc) -{ - int eip = desc[0] & 0x10; - int invalid = desc[0] & 0x80; - enum scsi_protocol proto = desc[0] & 0x0f; - u64 addr = 0; - struct ses_component *scomp = ecomp->scratch; - unsigned char *d; - - scomp->desc = desc; - - if (invalid) - return; - - switch (proto) { - case SCSI_PROTOCOL_SAS: - if (eip) - d = desc + 8; - else - d = desc + 4; - /* only take the phy0 addr */ - addr = (u64)d[12] << 56 | - (u64)d[13] << 48 | - (u64)d[14] << 40 | - (u64)d[15] << 32 | - (u64)d[16] << 24 | - (u64)d[17] << 16 | - (u64)d[18] << 8 | - (u64)d[19]; - break; - default: - /* FIXME: Need to add more protocols than just SAS */ - break; - } - scomp->addr = addr; -} - -struct efd { - u64 addr; - struct device *dev; -}; - -static int ses_enclosure_find_by_addr(struct enclosure_device *edev, - void *data) -{ - struct efd *efd = data; - int i; - struct ses_component *scomp; - - if (!edev->component[0].scratch) - return 0; - - for (i = 0; i < edev->components; i++) { - scomp = edev->component[i].scratch; - if (scomp->addr != efd->addr) - continue; - - enclosure_add_device(edev, i, efd->dev); - return 1; - } - return 0; -} - -#define INIT_ALLOC_SIZE 32 - -static void ses_enclosure_data_process(struct enclosure_device *edev, - struct scsi_device *sdev, - int create) -{ - u32 result; - unsigned char *buf = NULL, *type_ptr, *desc_ptr, *addl_desc_ptr = NULL; - int i, j, page7_len, len, components; - struct ses_device *ses_dev = edev->scratch; - int types = ses_dev->page1_num_types; - unsigned char *hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); - - if (!hdr_buf) - goto simple_populate; - - /* re-read page 10 */ - if (ses_dev->page10) - ses_recv_diag(sdev, 10, ses_dev->page10, ses_dev->page10_len); - /* Page 7 for the descriptors is optional */ - result = ses_recv_diag(sdev, 7, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto simple_populate; - - page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - /* add 1 for trailing '\0' we'll use */ - buf = kzalloc(len + 1, GFP_KERNEL); - if (!buf) - goto simple_populate; - result = ses_recv_diag(sdev, 7, buf, len); - if (result) { - simple_populate: - kfree(buf); - buf = NULL; - desc_ptr = NULL; - len = 0; - page7_len = 0; - } else { - desc_ptr = buf + 8; - len = (desc_ptr[2] << 8) + desc_ptr[3]; - /* skip past overall descriptor */ - desc_ptr += len + 4; - } - if (ses_dev->page10) - addl_desc_ptr = ses_dev->page10 + 8; - type_ptr = ses_dev->page1_types; - components = 0; - for (i = 0; i < types; i++, type_ptr += 4) { - for (j = 0; j < type_ptr[1]; j++) { - char *name = NULL; - struct enclosure_component *ecomp; - - if (desc_ptr) { - if (desc_ptr >= buf + page7_len) { - desc_ptr = NULL; - } else { - len = (desc_ptr[2] << 8) + desc_ptr[3]; - desc_ptr += 4; - /* Add trailing zero - pushes into - * reserved space */ - desc_ptr[len] = '\0'; - name = desc_ptr; - } - } - if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || - type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) { - - if (create) - ecomp = enclosure_component_register(edev, - components++, - type_ptr[0], - name); - else - ecomp = &edev->component[components++]; - - if (!IS_ERR(ecomp) && addl_desc_ptr) - ses_process_descriptor(ecomp, - addl_desc_ptr); - } - if (desc_ptr) - desc_ptr += len; - - if (addl_desc_ptr) - addl_desc_ptr += addl_desc_ptr[1] + 2; - - } - } - kfree(buf); - kfree(hdr_buf); -} - -static void ses_match_to_enclosure(struct enclosure_device *edev, - struct scsi_device *sdev) -{ - unsigned char *buf; - unsigned char *desc; - unsigned int vpd_len; - struct efd efd = { - .addr = 0, - }; - - buf = kmalloc(INIT_ALLOC_SIZE, GFP_KERNEL); - if (!buf || scsi_get_vpd_page(sdev, 0x83, buf, INIT_ALLOC_SIZE)) - goto free; - - ses_enclosure_data_process(edev, to_scsi_device(edev->edev.parent), 0); - - vpd_len = ((buf[2] << 8) | buf[3]) + 4; - kfree(buf); - buf = kmalloc(vpd_len, GFP_KERNEL); - if (!buf ||scsi_get_vpd_page(sdev, 0x83, buf, vpd_len)) - goto free; - - desc = buf + 4; - while (desc < buf + vpd_len) { - enum scsi_protocol proto = desc[0] >> 4; - u8 code_set = desc[0] & 0x0f; - u8 piv = desc[1] & 0x80; - u8 assoc = (desc[1] & 0x30) >> 4; - u8 type = desc[1] & 0x0f; - u8 len = desc[3]; - - if (piv && code_set == 1 && assoc == 1 - && proto == SCSI_PROTOCOL_SAS && type == 3 && len == 8) - efd.addr = (u64)desc[4] << 56 | - (u64)desc[5] << 48 | - (u64)desc[6] << 40 | - (u64)desc[7] << 32 | - (u64)desc[8] << 24 | - (u64)desc[9] << 16 | - (u64)desc[10] << 8 | - (u64)desc[11]; - - desc += len + 4; - } - if (!efd.addr) - goto free; - - efd.dev = &sdev->sdev_gendev; - - enclosure_for_each_device(ses_enclosure_find_by_addr, &efd); - free: - kfree(buf); -} - -static int ses_intf_add(struct device *cdev, - struct class_interface *intf) -{ - struct scsi_device *sdev = to_scsi_device(cdev->parent); - struct scsi_device *tmp_sdev; - unsigned char *buf = NULL, *hdr_buf, *type_ptr; - struct ses_device *ses_dev; - u32 result; - int i, types, len, components = 0; - int err = -ENOMEM; - int num_enclosures; - struct enclosure_device *edev; - struct ses_component *scomp = NULL; - - if (!scsi_device_enclosure(sdev)) { - /* not an enclosure, but might be in one */ - struct enclosure_device *prev = NULL; - - while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { - ses_match_to_enclosure(edev, sdev); - prev = edev; - } - return -ENODEV; - } - - /* TYPE_ENCLOSURE prints a message in probe */ - if (sdev->type != TYPE_ENCLOSURE) - sdev_printk(KERN_NOTICE, sdev, "Embedded Enclosure Device\n"); - - ses_dev = kzalloc(sizeof(*ses_dev), GFP_KERNEL); - hdr_buf = kzalloc(INIT_ALLOC_SIZE, GFP_KERNEL); - if (!hdr_buf || !ses_dev) - goto err_init_free; - - result = ses_recv_diag(sdev, 1, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto recv_failed; - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - result = ses_recv_diag(sdev, 1, buf, len); - if (result) - goto recv_failed; - - types = 0; - - /* we always have one main enclosure and the rest are referred - * to as secondary subenclosures */ - num_enclosures = buf[1] + 1; - - /* begin at the enclosure descriptor */ - type_ptr = buf + 8; - /* skip all the enclosure descriptors */ - for (i = 0; i < num_enclosures && type_ptr < buf + len; i++) { - types += type_ptr[2]; - type_ptr += type_ptr[3] + 4; - } - - ses_dev->page1_types = type_ptr; - ses_dev->page1_num_types = types; - - for (i = 0; i < types && type_ptr < buf + len; i++, type_ptr += 4) { - if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || - type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) - components += type_ptr[1]; - } - ses_dev->page1 = buf; - ses_dev->page1_len = len; - buf = NULL; - - result = ses_recv_diag(sdev, 2, hdr_buf, INIT_ALLOC_SIZE); - if (result) - goto recv_failed; - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - /* make sure getting page 2 actually works */ - result = ses_recv_diag(sdev, 2, buf, len); - if (result) - goto recv_failed; - ses_dev->page2 = buf; - ses_dev->page2_len = len; - buf = NULL; - - /* The additional information page --- allows us - * to match up the devices */ - result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE); - if (!result) { - - len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; - buf = kzalloc(len, GFP_KERNEL); - if (!buf) - goto err_free; - - result = ses_recv_diag(sdev, 10, buf, len); - if (result) - goto recv_failed; - ses_dev->page10 = buf; - ses_dev->page10_len = len; - buf = NULL; - } - scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL); - if (!scomp) - goto err_free; - - edev = enclosure_register(cdev->parent, dev_name(&sdev->sdev_gendev), - components, &ses_enclosure_callbacks); - if (IS_ERR(edev)) { - err = PTR_ERR(edev); - goto err_free; - } - - kfree(hdr_buf); - - edev->scratch = ses_dev; - for (i = 0; i < components; i++) - edev->component[i].scratch = scomp + i; - - ses_enclosure_data_process(edev, sdev, 1); - - /* see if there are any devices matching before - * we found the enclosure */ - shost_for_each_device(tmp_sdev, sdev->host) { - if (tmp_sdev->lun != 0 || scsi_device_enclosure(tmp_sdev)) - continue; - ses_match_to_enclosure(edev, tmp_sdev); - } - - return 0; - - recv_failed: - sdev_printk(KERN_ERR, sdev, "Failed to get diagnostic page 0x%x\n", - result); - err = -ENODEV; - err_free: - kfree(buf); - kfree(scomp); - kfree(ses_dev->page10); - kfree(ses_dev->page2); - kfree(ses_dev->page1); - err_init_free: - kfree(ses_dev); - kfree(hdr_buf); - sdev_printk(KERN_ERR, sdev, "Failed to bind enclosure %d\n", err); - return err; -} - -static int ses_remove(struct device *dev) -{ - return 0; -} - -static void ses_intf_remove_component(struct scsi_device *sdev) -{ - struct enclosure_device *edev, *prev = NULL; - - while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { - prev = edev; - if (!enclosure_remove_device(edev, &sdev->sdev_gendev)) - break; - } - if (edev) - put_device(&edev->edev); -} - -static void ses_intf_remove_enclosure(struct scsi_device *sdev) -{ - struct enclosure_device *edev; - struct ses_device *ses_dev; - - /* exact match to this enclosure */ - edev = enclosure_find(&sdev->sdev_gendev, NULL); - if (!edev) - return; - - ses_dev = edev->scratch; - edev->scratch = NULL; - - kfree(ses_dev->page10); - kfree(ses_dev->page1); - kfree(ses_dev->page2); - kfree(ses_dev); - - kfree(edev->component[0].scratch); - - put_device(&edev->edev); - enclosure_unregister(edev); -} - -static void ses_intf_remove(struct device *cdev, - struct class_interface *intf) -{ - struct scsi_device *sdev = to_scsi_device(cdev->parent); - - if (!scsi_device_enclosure(sdev)) - ses_intf_remove_component(sdev); - else - ses_intf_remove_enclosure(sdev); -} - -static struct class_interface ses_interface = { - .add_dev = ses_intf_add, - .remove_dev = ses_intf_remove, -}; - -static struct scsi_driver ses_template = { - .owner = THIS_MODULE, - .gendrv = { - .name = "ses", - .probe = ses_probe, - .remove = ses_remove, - }, -}; - -static int __init ses_init(void) -{ - int err; - - err = scsi_register_interface(&ses_interface); - if (err) - return err; - - err = scsi_register_driver(&ses_template.gendrv); - if (err) - goto out_unreg; - - return 0; - - out_unreg: - scsi_unregister_interface(&ses_interface); - return err; -} - -static void __exit ses_exit(void) -{ - scsi_unregister_driver(&ses_template.gendrv); - scsi_unregister_interface(&ses_interface); -} - -module_init(ses_init); -module_exit(ses_exit); - -MODULE_ALIAS_SCSI_DEVICE(TYPE_ENCLOSURE); - -MODULE_AUTHOR("James Bottomley"); -MODULE_DESCRIPTION("SCSI Enclosure Services (ses) driver"); -MODULE_LICENSE("GPL v2"); diff --git a/ANDROID_3.4.5/drivers/scsi/sg.c b/ANDROID_3.4.5/drivers/scsi/sg.c deleted file mode 100644 index eacd46bb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sg.c +++ /dev/null @@ -1,2625 +0,0 @@ -/* - * History: - * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), - * to allow user process control of SCSI devices. - * Development Sponsored by Killy Corp. NY NY - * - * Original driver (sg.c): - * Copyright (C) 1992 Lawrence Foard - * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2005 Douglas Gilbert - * - * Modified 19-JAN-1998 Richard Gooch Devfs support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - */ - -static int sg_version_num = 30534; /* 2 digits for each component */ -#define SG_VERSION_STR "3.5.34" - -/* - * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: - * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First - * the kernel/module needs to be built with CONFIG_SCSI_LOGGING - * (otherwise the macros compile to empty statements). - * - */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include -#include -#include -#include - -#include "scsi_logging.h" - -#ifdef CONFIG_SCSI_PROC_FS -#include -static char *sg_version_date = "20061027"; - -static int sg_proc_init(void); -static void sg_proc_cleanup(void); -#endif - -#define SG_ALLOW_DIO_DEF 0 - -#define SG_MAX_DEVS 32768 - -/* - * Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d) - * Then when using 32 bit integers x * m may overflow during the calculation. - * Replacing muldiv(x) by muldiv(x)=((x % d) * m) / d + int(x / d) * m - * calculates the same, but prevents the overflow when both m and d - * are "small" numbers (like HZ and USER_HZ). - * Of course an overflow is inavoidable if the result of muldiv doesn't fit - * in 32 bits. - */ -#define MULDIV(X,MUL,DIV) ((((X % DIV) * MUL) / DIV) + ((X / DIV) * MUL)) - -#define SG_DEFAULT_TIMEOUT MULDIV(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ) - -int sg_big_buff = SG_DEF_RESERVED_SIZE; -/* N.B. This variable is readable and writeable via - /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer - of this size (or less if there is not enough memory) will be reserved - for use by this file descriptor. [Deprecated usage: this variable is also - readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into - the kernel (i.e. it is not a module).] */ -static int def_reserved_size = -1; /* picks up init parameter */ -static int sg_allow_dio = SG_ALLOW_DIO_DEF; - -static int scatter_elem_sz = SG_SCATTER_SZ; -static int scatter_elem_sz_prev = SG_SCATTER_SZ; - -#define SG_SECTOR_SZ 512 - -static int sg_add(struct device *, struct class_interface *); -static void sg_remove(struct device *, struct class_interface *); - -static DEFINE_MUTEX(sg_mutex); - -static DEFINE_IDR(sg_index_idr); -static DEFINE_RWLOCK(sg_index_lock); /* Also used to lock - file descriptor list for device */ - -static struct class_interface sg_interface = { - .add_dev = sg_add, - .remove_dev = sg_remove, -}; - -typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */ - unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */ - unsigned sglist_len; /* size of malloc'd scatter-gather list ++ */ - unsigned bufflen; /* Size of (aggregate) data buffer */ - struct page **pages; - int page_order; - char dio_in_use; /* 0->indirect IO (or mmap), 1->dio */ - unsigned char cmd_opcode; /* first byte of command */ -} Sg_scatter_hold; - -struct sg_device; /* forward declarations */ -struct sg_fd; - -typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */ - struct sg_request *nextrp; /* NULL -> tail request (slist) */ - struct sg_fd *parentfp; /* NULL -> not in use */ - Sg_scatter_hold data; /* hold buffer, perhaps scatter list */ - sg_io_hdr_t header; /* scsi command+info, see */ - unsigned char sense_b[SCSI_SENSE_BUFFERSIZE]; - char res_used; /* 1 -> using reserve buffer, 0 -> not ... */ - char orphan; /* 1 -> drop on sight, 0 -> normal */ - char sg_io_owned; /* 1 -> packet belongs to SG_IO */ - volatile char done; /* 0->before bh, 1->before read, 2->read */ - struct request *rq; - struct bio *bio; - struct execute_work ew; -} Sg_request; - -typedef struct sg_fd { /* holds the state of a file descriptor */ - struct list_head sfd_siblings; - struct sg_device *parentdp; /* owning device */ - wait_queue_head_t read_wait; /* queue read until command done */ - rwlock_t rq_list_lock; /* protect access to list in req_arr */ - int timeout; /* defaults to SG_DEFAULT_TIMEOUT */ - int timeout_user; /* defaults to SG_DEFAULT_TIMEOUT_USER */ - Sg_scatter_hold reserve; /* buffer held for this file descriptor */ - unsigned save_scat_len; /* original length of trunc. scat. element */ - Sg_request *headrp; /* head of request slist, NULL->empty */ - struct fasync_struct *async_qp; /* used by asynchronous notification */ - Sg_request req_arr[SG_MAX_QUEUE]; /* used as singly-linked list */ - char low_dma; /* as in parent but possibly overridden to 1 */ - char force_packid; /* 1 -> pack_id input to read(), 0 -> ignored */ - volatile char closed; /* 1 -> fd closed but request(s) outstanding */ - char cmd_q; /* 1 -> allow command queuing, 0 -> don't */ - char next_cmd_len; /* 0 -> automatic (def), >0 -> use on next write() */ - char keep_orphan; /* 0 -> drop orphan (def), 1 -> keep for read() */ - char mmap_called; /* 0 -> mmap() never called on this fd */ - struct kref f_ref; - struct execute_work ew; -} Sg_fd; - -typedef struct sg_device { /* holds the state of each scsi generic device */ - struct scsi_device *device; - wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ - int sg_tablesize; /* adapter's max scatter-gather table size */ - u32 index; /* device index number */ - struct list_head sfds; - volatile char detached; /* 0->attached, 1->detached pending removal */ - volatile char exclude; /* opened for exclusive access */ - char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ - struct gendisk *disk; - struct cdev * cdev; /* char_dev [sysfs: /sys/cdev/major/sg] */ - struct kref d_ref; -} Sg_device; - -/* tasklet or soft irq callback */ -static void sg_rq_end_io(struct request *rq, int uptodate); -static int sg_start_req(Sg_request *srp, unsigned char *cmd); -static int sg_finish_rem_req(Sg_request * srp); -static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size); -static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, - Sg_request * srp); -static ssize_t sg_new_write(Sg_fd *sfp, struct file *file, - const char __user *buf, size_t count, int blocking, - int read_only, int sg_io_owned, Sg_request **o_srp); -static int sg_common_write(Sg_fd * sfp, Sg_request * srp, - unsigned char *cmnd, int timeout, int blocking); -static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer); -static void sg_remove_scat(Sg_scatter_hold * schp); -static void sg_build_reserve(Sg_fd * sfp, int req_size); -static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size); -static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp); -static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev); -static void sg_remove_sfp(struct kref *); -static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id); -static Sg_request *sg_add_request(Sg_fd * sfp); -static int sg_remove_request(Sg_fd * sfp, Sg_request * srp); -static int sg_res_in_use(Sg_fd * sfp); -static Sg_device *sg_get_dev(int dev); -static void sg_put_dev(Sg_device *sdp); - -#define SZ_SG_HEADER sizeof(struct sg_header) -#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t) -#define SZ_SG_IOVEC sizeof(sg_iovec_t) -#define SZ_SG_REQ_INFO sizeof(sg_req_info_t) - -static int sg_allow_access(struct file *filp, unsigned char *cmd) -{ - struct sg_fd *sfp = filp->private_data; - - if (sfp->parentdp->device->type == TYPE_SCANNER) - return 0; - - return blk_verify_command(cmd, filp->f_mode & FMODE_WRITE); -} - -static int -sg_open(struct inode *inode, struct file *filp) -{ - int dev = iminor(inode); - int flags = filp->f_flags; - struct request_queue *q; - Sg_device *sdp; - Sg_fd *sfp; - int res; - int retval; - - mutex_lock(&sg_mutex); - nonseekable_open(inode, filp); - SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags)); - sdp = sg_get_dev(dev); - if (IS_ERR(sdp)) { - retval = PTR_ERR(sdp); - sdp = NULL; - goto sg_put; - } - - /* This driver's module count bumped by fops_get in */ - /* Prevent the device driver from vanishing while we sleep */ - retval = scsi_device_get(sdp->device); - if (retval) - goto sg_put; - - retval = scsi_autopm_get_device(sdp->device); - if (retval) - goto sdp_put; - - if (!((flags & O_NONBLOCK) || - scsi_block_when_processing_errors(sdp->device))) { - retval = -ENXIO; - /* we are in error recovery for this device */ - goto error_out; - } - - if (flags & O_EXCL) { - if (O_RDONLY == (flags & O_ACCMODE)) { - retval = -EPERM; /* Can't lock it with read only access */ - goto error_out; - } - if (!list_empty(&sdp->sfds) && (flags & O_NONBLOCK)) { - retval = -EBUSY; - goto error_out; - } - res = 0; - __wait_event_interruptible(sdp->o_excl_wait, - ((!list_empty(&sdp->sfds) || sdp->exclude) ? 0 : (sdp->exclude = 1)), res); - if (res) { - retval = res; /* -ERESTARTSYS because signal hit process */ - goto error_out; - } - } else if (sdp->exclude) { /* some other fd has an exclusive lock on dev */ - if (flags & O_NONBLOCK) { - retval = -EBUSY; - goto error_out; - } - res = 0; - __wait_event_interruptible(sdp->o_excl_wait, (!sdp->exclude), - res); - if (res) { - retval = res; /* -ERESTARTSYS because signal hit process */ - goto error_out; - } - } - if (sdp->detached) { - retval = -ENODEV; - goto error_out; - } - if (list_empty(&sdp->sfds)) { /* no existing opens on this device */ - sdp->sgdebug = 0; - q = sdp->device->request_queue; - sdp->sg_tablesize = queue_max_segments(q); - } - if ((sfp = sg_add_sfp(sdp, dev))) - filp->private_data = sfp; - else { - if (flags & O_EXCL) { - sdp->exclude = 0; /* undo if error */ - wake_up_interruptible(&sdp->o_excl_wait); - } - retval = -ENOMEM; - goto error_out; - } - retval = 0; -error_out: - if (retval) { - scsi_autopm_put_device(sdp->device); -sdp_put: - scsi_device_put(sdp->device); - } -sg_put: - if (sdp) - sg_put_dev(sdp); - mutex_unlock(&sg_mutex); - return retval; -} - -/* Following function was formerly called 'sg_close' */ -static int -sg_release(struct inode *inode, struct file *filp) -{ - Sg_device *sdp; - Sg_fd *sfp; - - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) - return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name)); - - sfp->closed = 1; - - sdp->exclude = 0; - wake_up_interruptible(&sdp->o_excl_wait); - - scsi_autopm_put_device(sdp->device); - kref_put(&sfp->f_ref, sg_remove_sfp); - return 0; -} - -static ssize_t -sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) -{ - Sg_device *sdp; - Sg_fd *sfp; - Sg_request *srp; - int req_pack_id = -1; - sg_io_hdr_t *hp; - struct sg_header *old_hdr = NULL; - int retval = 0; - - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) - return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n", - sdp->disk->disk_name, (int) count)); - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - if (sfp->force_packid && (count >= SZ_SG_HEADER)) { - old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL); - if (!old_hdr) - return -ENOMEM; - if (__copy_from_user(old_hdr, buf, SZ_SG_HEADER)) { - retval = -EFAULT; - goto free_old_hdr; - } - if (old_hdr->reply_len < 0) { - if (count >= SZ_SG_IO_HDR) { - sg_io_hdr_t *new_hdr; - new_hdr = kmalloc(SZ_SG_IO_HDR, GFP_KERNEL); - if (!new_hdr) { - retval = -ENOMEM; - goto free_old_hdr; - } - retval =__copy_from_user - (new_hdr, buf, SZ_SG_IO_HDR); - req_pack_id = new_hdr->pack_id; - kfree(new_hdr); - if (retval) { - retval = -EFAULT; - goto free_old_hdr; - } - } - } else - req_pack_id = old_hdr->pack_id; - } - srp = sg_get_rq_mark(sfp, req_pack_id); - if (!srp) { /* now wait on packet to arrive */ - if (sdp->detached) { - retval = -ENODEV; - goto free_old_hdr; - } - if (filp->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - goto free_old_hdr; - } - while (1) { - retval = 0; /* following macro beats race condition */ - __wait_event_interruptible(sfp->read_wait, - (sdp->detached || - (srp = sg_get_rq_mark(sfp, req_pack_id))), - retval); - if (sdp->detached) { - retval = -ENODEV; - goto free_old_hdr; - } - if (0 == retval) - break; - - /* -ERESTARTSYS as signal hit process */ - goto free_old_hdr; - } - } - if (srp->header.interface_id != '\0') { - retval = sg_new_read(sfp, buf, count, srp); - goto free_old_hdr; - } - - hp = &srp->header; - if (old_hdr == NULL) { - old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL); - if (! old_hdr) { - retval = -ENOMEM; - goto free_old_hdr; - } - } - memset(old_hdr, 0, SZ_SG_HEADER); - old_hdr->reply_len = (int) hp->timeout; - old_hdr->pack_len = old_hdr->reply_len; /* old, strange behaviour */ - old_hdr->pack_id = hp->pack_id; - old_hdr->twelve_byte = - ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0; - old_hdr->target_status = hp->masked_status; - old_hdr->host_status = hp->host_status; - old_hdr->driver_status = hp->driver_status; - if ((CHECK_CONDITION & hp->masked_status) || - (DRIVER_SENSE & hp->driver_status)) - memcpy(old_hdr->sense_buffer, srp->sense_b, - sizeof (old_hdr->sense_buffer)); - switch (hp->host_status) { - /* This setup of 'result' is for backward compatibility and is best - ignored by the user who should use target, host + driver status */ - case DID_OK: - case DID_PASSTHROUGH: - case DID_SOFT_ERROR: - old_hdr->result = 0; - break; - case DID_NO_CONNECT: - case DID_BUS_BUSY: - case DID_TIME_OUT: - old_hdr->result = EBUSY; - break; - case DID_BAD_TARGET: - case DID_ABORT: - case DID_PARITY: - case DID_RESET: - case DID_BAD_INTR: - old_hdr->result = EIO; - break; - case DID_ERROR: - old_hdr->result = (srp->sense_b[0] == 0 && - hp->masked_status == GOOD) ? 0 : EIO; - break; - default: - old_hdr->result = EIO; - break; - } - - /* Now copy the result back to the user buffer. */ - if (count >= SZ_SG_HEADER) { - if (__copy_to_user(buf, old_hdr, SZ_SG_HEADER)) { - retval = -EFAULT; - goto free_old_hdr; - } - buf += SZ_SG_HEADER; - if (count > old_hdr->reply_len) - count = old_hdr->reply_len; - if (count > SZ_SG_HEADER) { - if (sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)) { - retval = -EFAULT; - goto free_old_hdr; - } - } - } else - count = (old_hdr->result == 0) ? 0 : -EIO; - sg_finish_rem_req(srp); - retval = count; -free_old_hdr: - kfree(old_hdr); - return retval; -} - -static ssize_t -sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp) -{ - sg_io_hdr_t *hp = &srp->header; - int err = 0; - int len; - - if (count < SZ_SG_IO_HDR) { - err = -EINVAL; - goto err_out; - } - hp->sb_len_wr = 0; - if ((hp->mx_sb_len > 0) && hp->sbp) { - if ((CHECK_CONDITION & hp->masked_status) || - (DRIVER_SENSE & hp->driver_status)) { - int sb_len = SCSI_SENSE_BUFFERSIZE; - sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len; - len = 8 + (int) srp->sense_b[7]; /* Additional sense length field */ - len = (len > sb_len) ? sb_len : len; - if (copy_to_user(hp->sbp, srp->sense_b, len)) { - err = -EFAULT; - goto err_out; - } - hp->sb_len_wr = len; - } - } - if (hp->masked_status || hp->host_status || hp->driver_status) - hp->info |= SG_INFO_CHECK; - if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) { - err = -EFAULT; - goto err_out; - } -err_out: - err = sg_finish_rem_req(srp); - return (0 == err) ? count : err; -} - -static ssize_t -sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) -{ - int mxsize, cmd_size, k; - int input_size, blocking; - unsigned char opcode; - Sg_device *sdp; - Sg_fd *sfp; - Sg_request *srp; - struct sg_header old_hdr; - sg_io_hdr_t *hp; - unsigned char cmnd[MAX_COMMAND_SIZE]; - - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) - return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_write: %s, count=%d\n", - sdp->disk->disk_name, (int) count)); - if (sdp->detached) - return -ENODEV; - if (!((filp->f_flags & O_NONBLOCK) || - scsi_block_when_processing_errors(sdp->device))) - return -ENXIO; - - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; /* protects following copy_from_user()s + get_user()s */ - if (count < SZ_SG_HEADER) - return -EIO; - if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER)) - return -EFAULT; - blocking = !(filp->f_flags & O_NONBLOCK); - if (old_hdr.reply_len < 0) - return sg_new_write(sfp, filp, buf, count, - blocking, 0, 0, NULL); - if (count < (SZ_SG_HEADER + 6)) - return -EIO; /* The minimum scsi command length is 6 bytes. */ - - if (!(srp = sg_add_request(sfp))) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n")); - return -EDOM; - } - buf += SZ_SG_HEADER; - __get_user(opcode, buf); - if (sfp->next_cmd_len > 0) { - if (sfp->next_cmd_len > MAX_COMMAND_SIZE) { - SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n")); - sfp->next_cmd_len = 0; - sg_remove_request(sfp, srp); - return -EIO; - } - cmd_size = sfp->next_cmd_len; - sfp->next_cmd_len = 0; /* reset so only this write() effected */ - } else { - cmd_size = COMMAND_SIZE(opcode); /* based on SCSI command group */ - if ((opcode >= 0xc0) && old_hdr.twelve_byte) - cmd_size = 12; - } - SCSI_LOG_TIMEOUT(4, printk( - "sg_write: scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size)); -/* Determine buffer size. */ - input_size = count - cmd_size; - mxsize = (input_size > old_hdr.reply_len) ? input_size : old_hdr.reply_len; - mxsize -= SZ_SG_HEADER; - input_size -= SZ_SG_HEADER; - if (input_size < 0) { - sg_remove_request(sfp, srp); - return -EIO; /* User did not pass enough bytes for this command. */ - } - hp = &srp->header; - hp->interface_id = '\0'; /* indicator of old interface tunnelled */ - hp->cmd_len = (unsigned char) cmd_size; - hp->iovec_count = 0; - hp->mx_sb_len = 0; - if (input_size > 0) - hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ? - SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV; - else - hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE; - hp->dxfer_len = mxsize; - if (hp->dxfer_direction == SG_DXFER_TO_DEV) - hp->dxferp = (char __user *)buf + cmd_size; - else - hp->dxferp = NULL; - hp->sbp = NULL; - hp->timeout = old_hdr.reply_len; /* structure abuse ... */ - hp->flags = input_size; /* structure abuse ... */ - hp->pack_id = old_hdr.pack_id; - hp->usr_ptr = NULL; - if (__copy_from_user(cmnd, buf, cmd_size)) - return -EFAULT; - /* - * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV, - * but is is possible that the app intended SG_DXFER_TO_DEV, because there - * is a non-zero input_size, so emit a warning. - */ - if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV) { - static char cmd[TASK_COMM_LEN]; - if (strcmp(current->comm, cmd)) { - printk_ratelimited(KERN_WARNING - "sg_write: data in/out %d/%d bytes " - "for SCSI command 0x%x-- guessing " - "data in;\n program %s not setting " - "count and/or reply_len properly\n", - old_hdr.reply_len - (int)SZ_SG_HEADER, - input_size, (unsigned int) cmnd[0], - current->comm); - strcpy(cmd, current->comm); - } - } - k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking); - return (k < 0) ? k : count; -} - -static ssize_t -sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, - size_t count, int blocking, int read_only, int sg_io_owned, - Sg_request **o_srp) -{ - int k; - Sg_request *srp; - sg_io_hdr_t *hp; - unsigned char cmnd[MAX_COMMAND_SIZE]; - int timeout; - unsigned long ul_timeout; - - if (count < SZ_SG_IO_HDR) - return -EINVAL; - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; /* protects following copy_from_user()s + get_user()s */ - - sfp->cmd_q = 1; /* when sg_io_hdr seen, set command queuing on */ - if (!(srp = sg_add_request(sfp))) { - SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n")); - return -EDOM; - } - srp->sg_io_owned = sg_io_owned; - hp = &srp->header; - if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) { - sg_remove_request(sfp, srp); - return -EFAULT; - } - if (hp->interface_id != 'S') { - sg_remove_request(sfp, srp); - return -ENOSYS; - } - if (hp->flags & SG_FLAG_MMAP_IO) { - if (hp->dxfer_len > sfp->reserve.bufflen) { - sg_remove_request(sfp, srp); - return -ENOMEM; /* MMAP_IO size must fit in reserve buffer */ - } - if (hp->flags & SG_FLAG_DIRECT_IO) { - sg_remove_request(sfp, srp); - return -EINVAL; /* either MMAP_IO or DIRECT_IO (not both) */ - } - if (sg_res_in_use(sfp)) { - sg_remove_request(sfp, srp); - return -EBUSY; /* reserve buffer already being used */ - } - } - ul_timeout = msecs_to_jiffies(srp->header.timeout); - timeout = (ul_timeout < INT_MAX) ? ul_timeout : INT_MAX; - if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) { - sg_remove_request(sfp, srp); - return -EMSGSIZE; - } - if (!access_ok(VERIFY_READ, hp->cmdp, hp->cmd_len)) { - sg_remove_request(sfp, srp); - return -EFAULT; /* protects following copy_from_user()s + get_user()s */ - } - if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) { - sg_remove_request(sfp, srp); - return -EFAULT; - } - if (read_only && sg_allow_access(file, cmnd)) { - sg_remove_request(sfp, srp); - return -EPERM; - } - k = sg_common_write(sfp, srp, cmnd, timeout, blocking); - if (k < 0) - return k; - if (o_srp) - *o_srp = srp; - return count; -} - -static int -sg_common_write(Sg_fd * sfp, Sg_request * srp, - unsigned char *cmnd, int timeout, int blocking) -{ - int k, data_dir; - Sg_device *sdp = sfp->parentdp; - sg_io_hdr_t *hp = &srp->header; - - srp->data.cmd_opcode = cmnd[0]; /* hold opcode of command */ - hp->status = 0; - hp->masked_status = 0; - hp->msg_status = 0; - hp->info = 0; - hp->host_status = 0; - hp->driver_status = 0; - hp->resid = 0; - SCSI_LOG_TIMEOUT(4, printk("sg_common_write: scsi opcode=0x%02x, cmd_size=%d\n", - (int) cmnd[0], (int) hp->cmd_len)); - - k = sg_start_req(srp, cmnd); - if (k) { - SCSI_LOG_TIMEOUT(1, printk("sg_common_write: start_req err=%d\n", k)); - sg_finish_rem_req(srp); - return k; /* probably out of space --> ENOMEM */ - } - if (sdp->detached) { - if (srp->bio) - blk_end_request_all(srp->rq, -EIO); - sg_finish_rem_req(srp); - return -ENODEV; - } - - switch (hp->dxfer_direction) { - case SG_DXFER_TO_FROM_DEV: - case SG_DXFER_FROM_DEV: - data_dir = DMA_FROM_DEVICE; - break; - case SG_DXFER_TO_DEV: - data_dir = DMA_TO_DEVICE; - break; - case SG_DXFER_UNKNOWN: - data_dir = DMA_BIDIRECTIONAL; - break; - default: - data_dir = DMA_NONE; - break; - } - hp->duration = jiffies_to_msecs(jiffies); - - srp->rq->timeout = timeout; - kref_get(&sfp->f_ref); /* sg_rq_end_io() does kref_put(). */ - blk_execute_rq_nowait(sdp->device->request_queue, sdp->disk, - srp->rq, 1, sg_rq_end_io); - return 0; -} - -static int -sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) -{ - void __user *p = (void __user *)arg; - int __user *ip = p; - int result, val, read_only; - Sg_device *sdp; - Sg_fd *sfp; - Sg_request *srp; - unsigned long iflags; - - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) - return -ENXIO; - - SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: %s, cmd=0x%x\n", - sdp->disk->disk_name, (int) cmd_in)); - read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); - - switch (cmd_in) { - case SG_IO: - { - int blocking = 1; /* ignore O_NONBLOCK flag */ - - if (sdp->detached) - return -ENODEV; - if (!scsi_block_when_processing_errors(sdp->device)) - return -ENXIO; - if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR)) - return -EFAULT; - result = - sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, - blocking, read_only, 1, &srp); - if (result < 0) - return result; - while (1) { - result = 0; /* following macro to beat race condition */ - __wait_event_interruptible(sfp->read_wait, - (srp->done || sdp->detached), - result); - if (sdp->detached) - return -ENODEV; - write_lock_irq(&sfp->rq_list_lock); - if (srp->done) { - srp->done = 2; - write_unlock_irq(&sfp->rq_list_lock); - break; - } - srp->orphan = 1; - write_unlock_irq(&sfp->rq_list_lock); - return result; /* -ERESTARTSYS because signal hit process */ - } - result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp); - return (result < 0) ? result : 0; - } - case SG_SET_TIMEOUT: - result = get_user(val, ip); - if (result) - return result; - if (val < 0) - return -EIO; - if (val >= MULDIV (INT_MAX, USER_HZ, HZ)) - val = MULDIV (INT_MAX, USER_HZ, HZ); - sfp->timeout_user = val; - sfp->timeout = MULDIV (val, HZ, USER_HZ); - - return 0; - case SG_GET_TIMEOUT: /* N.B. User receives timeout as return value */ - /* strange ..., for backward compatibility */ - return sfp->timeout_user; - case SG_SET_FORCE_LOW_DMA: - result = get_user(val, ip); - if (result) - return result; - if (val) { - sfp->low_dma = 1; - if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) { - val = (int) sfp->reserve.bufflen; - sg_remove_scat(&sfp->reserve); - sg_build_reserve(sfp, val); - } - } else { - if (sdp->detached) - return -ENODEV; - sfp->low_dma = sdp->device->host->unchecked_isa_dma; - } - return 0; - case SG_GET_LOW_DMA: - return put_user((int) sfp->low_dma, ip); - case SG_GET_SCSI_ID: - if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t))) - return -EFAULT; - else { - sg_scsi_id_t __user *sg_idp = p; - - if (sdp->detached) - return -ENODEV; - __put_user((int) sdp->device->host->host_no, - &sg_idp->host_no); - __put_user((int) sdp->device->channel, - &sg_idp->channel); - __put_user((int) sdp->device->id, &sg_idp->scsi_id); - __put_user((int) sdp->device->lun, &sg_idp->lun); - __put_user((int) sdp->device->type, &sg_idp->scsi_type); - __put_user((short) sdp->device->host->cmd_per_lun, - &sg_idp->h_cmd_per_lun); - __put_user((short) sdp->device->queue_depth, - &sg_idp->d_queue_depth); - __put_user(0, &sg_idp->unused[0]); - __put_user(0, &sg_idp->unused[1]); - return 0; - } - case SG_SET_FORCE_PACK_ID: - result = get_user(val, ip); - if (result) - return result; - sfp->force_packid = val ? 1 : 0; - return 0; - case SG_GET_PACK_ID: - if (!access_ok(VERIFY_WRITE, ip, sizeof (int))) - return -EFAULT; - read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) { - if ((1 == srp->done) && (!srp->sg_io_owned)) { - read_unlock_irqrestore(&sfp->rq_list_lock, - iflags); - __put_user(srp->header.pack_id, ip); - return 0; - } - } - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - __put_user(-1, ip); - return 0; - case SG_GET_NUM_WAITING: - read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) { - if ((1 == srp->done) && (!srp->sg_io_owned)) - ++val; - } - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return put_user(val, ip); - case SG_GET_SG_TABLESIZE: - return put_user(sdp->sg_tablesize, ip); - case SG_SET_RESERVED_SIZE: - result = get_user(val, ip); - if (result) - return result; - if (val < 0) - return -EINVAL; - val = min_t(int, val, - queue_max_sectors(sdp->device->request_queue) * 512); - if (val != sfp->reserve.bufflen) { - if (sg_res_in_use(sfp) || sfp->mmap_called) - return -EBUSY; - sg_remove_scat(&sfp->reserve); - sg_build_reserve(sfp, val); - } - return 0; - case SG_GET_RESERVED_SIZE: - val = min_t(int, sfp->reserve.bufflen, - queue_max_sectors(sdp->device->request_queue) * 512); - return put_user(val, ip); - case SG_SET_COMMAND_Q: - result = get_user(val, ip); - if (result) - return result; - sfp->cmd_q = val ? 1 : 0; - return 0; - case SG_GET_COMMAND_Q: - return put_user((int) sfp->cmd_q, ip); - case SG_SET_KEEP_ORPHAN: - result = get_user(val, ip); - if (result) - return result; - sfp->keep_orphan = val; - return 0; - case SG_GET_KEEP_ORPHAN: - return put_user((int) sfp->keep_orphan, ip); - case SG_NEXT_CMD_LEN: - result = get_user(val, ip); - if (result) - return result; - sfp->next_cmd_len = (val > 0) ? val : 0; - return 0; - case SG_GET_VERSION_NUM: - return put_user(sg_version_num, ip); - case SG_GET_ACCESS_COUNT: - /* faked - we don't have a real access count anymore */ - val = (sdp->device ? 1 : 0); - return put_user(val, ip); - case SG_GET_REQUEST_TABLE: - if (!access_ok(VERIFY_WRITE, p, SZ_SG_REQ_INFO * SG_MAX_QUEUE)) - return -EFAULT; - else { - sg_req_info_t *rinfo; - unsigned int ms; - - rinfo = kmalloc(SZ_SG_REQ_INFO * SG_MAX_QUEUE, - GFP_KERNEL); - if (!rinfo) - return -ENOMEM; - read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE; - ++val, srp = srp ? srp->nextrp : srp) { - memset(&rinfo[val], 0, SZ_SG_REQ_INFO); - if (srp) { - rinfo[val].req_state = srp->done + 1; - rinfo[val].problem = - srp->header.masked_status & - srp->header.host_status & - srp->header.driver_status; - if (srp->done) - rinfo[val].duration = - srp->header.duration; - else { - ms = jiffies_to_msecs(jiffies); - rinfo[val].duration = - (ms > srp->header.duration) ? - (ms - srp->header.duration) : 0; - } - rinfo[val].orphan = srp->orphan; - rinfo[val].sg_io_owned = - srp->sg_io_owned; - rinfo[val].pack_id = - srp->header.pack_id; - rinfo[val].usr_ptr = - srp->header.usr_ptr; - } - } - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - result = __copy_to_user(p, rinfo, - SZ_SG_REQ_INFO * SG_MAX_QUEUE); - result = result ? -EFAULT : 0; - kfree(rinfo); - return result; - } - case SG_EMULATED_HOST: - if (sdp->detached) - return -ENODEV; - return put_user(sdp->device->host->hostt->emulated, ip); - case SG_SCSI_RESET: - if (sdp->detached) - return -ENODEV; - if (filp->f_flags & O_NONBLOCK) { - if (scsi_host_in_recovery(sdp->device->host)) - return -EBUSY; - } else if (!scsi_block_when_processing_errors(sdp->device)) - return -EBUSY; - result = get_user(val, ip); - if (result) - return result; - if (SG_SCSI_RESET_NOTHING == val) - return 0; - switch (val) { - case SG_SCSI_RESET_DEVICE: - val = SCSI_TRY_RESET_DEVICE; - break; - case SG_SCSI_RESET_TARGET: - val = SCSI_TRY_RESET_TARGET; - break; - case SG_SCSI_RESET_BUS: - val = SCSI_TRY_RESET_BUS; - break; - case SG_SCSI_RESET_HOST: - val = SCSI_TRY_RESET_HOST; - break; - default: - return -EINVAL; - } - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - return (scsi_reset_provider(sdp->device, val) == - SUCCESS) ? 0 : -EIO; - case SCSI_IOCTL_SEND_COMMAND: - if (sdp->detached) - return -ENODEV; - if (read_only) { - unsigned char opcode = WRITE_6; - Scsi_Ioctl_Command __user *siocp = p; - - if (copy_from_user(&opcode, siocp->data, 1)) - return -EFAULT; - if (sg_allow_access(filp, &opcode)) - return -EPERM; - } - return sg_scsi_ioctl(sdp->device->request_queue, NULL, filp->f_mode, p); - case SG_SET_DEBUG: - result = get_user(val, ip); - if (result) - return result; - sdp->sgdebug = (char) val; - return 0; - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - case SCSI_IOCTL_PROBE_HOST: - case SG_GET_TRANSFORM: - if (sdp->detached) - return -ENODEV; - return scsi_ioctl(sdp->device, cmd_in, p); - case BLKSECTGET: - return put_user(queue_max_sectors(sdp->device->request_queue) * 512, - ip); - case BLKTRACESETUP: - return blk_trace_setup(sdp->device->request_queue, - sdp->disk->disk_name, - MKDEV(SCSI_GENERIC_MAJOR, sdp->index), - NULL, - (char *)arg); - case BLKTRACESTART: - return blk_trace_startstop(sdp->device->request_queue, 1); - case BLKTRACESTOP: - return blk_trace_startstop(sdp->device->request_queue, 0); - case BLKTRACETEARDOWN: - return blk_trace_remove(sdp->device->request_queue); - default: - if (read_only) - return -EPERM; /* don't know so take safe approach */ - return scsi_ioctl(sdp->device, cmd_in, p); - } -} - -static long -sg_unlocked_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) -{ - int ret; - - mutex_lock(&sg_mutex); - ret = sg_ioctl(filp, cmd_in, arg); - mutex_unlock(&sg_mutex); - - return ret; -} - -#ifdef CONFIG_COMPAT -static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) -{ - Sg_device *sdp; - Sg_fd *sfp; - struct scsi_device *sdev; - - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) - return -ENXIO; - - sdev = sdp->device; - if (sdev->host->hostt->compat_ioctl) { - int ret; - - ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); - - return ret; - } - - return -ENOIOCTLCMD; -} -#endif - -static unsigned int -sg_poll(struct file *filp, poll_table * wait) -{ - unsigned int res = 0; - Sg_device *sdp; - Sg_fd *sfp; - Sg_request *srp; - int count = 0; - unsigned long iflags; - - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)) - || sfp->closed) - return POLLERR; - poll_wait(filp, &sfp->read_wait, wait); - read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) { - /* if any read waiting, flag it */ - if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned)) - res = POLLIN | POLLRDNORM; - ++count; - } - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - - if (sdp->detached) - res |= POLLHUP; - else if (!sfp->cmd_q) { - if (0 == count) - res |= POLLOUT | POLLWRNORM; - } else if (count < SG_MAX_QUEUE) - res |= POLLOUT | POLLWRNORM; - SCSI_LOG_TIMEOUT(3, printk("sg_poll: %s, res=0x%x\n", - sdp->disk->disk_name, (int) res)); - return res; -} - -static int -sg_fasync(int fd, struct file *filp, int mode) -{ - Sg_device *sdp; - Sg_fd *sfp; - - if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) - return -ENXIO; - SCSI_LOG_TIMEOUT(3, printk("sg_fasync: %s, mode=%d\n", - sdp->disk->disk_name, mode)); - - return fasync_helper(fd, filp, mode, &sfp->async_qp); -} - -static int -sg_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - Sg_fd *sfp; - unsigned long offset, len, sa; - Sg_scatter_hold *rsv_schp; - int k, length; - - if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data))) - return VM_FAULT_SIGBUS; - rsv_schp = &sfp->reserve; - offset = vmf->pgoff << PAGE_SHIFT; - if (offset >= rsv_schp->bufflen) - return VM_FAULT_SIGBUS; - SCSI_LOG_TIMEOUT(3, printk("sg_vma_fault: offset=%lu, scatg=%d\n", - offset, rsv_schp->k_use_sg)); - sa = vma->vm_start; - length = 1 << (PAGE_SHIFT + rsv_schp->page_order); - for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) { - len = vma->vm_end - sa; - len = (len < length) ? len : length; - if (offset < len) { - struct page *page = nth_page(rsv_schp->pages[k], - offset >> PAGE_SHIFT); - get_page(page); /* increment page count */ - vmf->page = page; - return 0; /* success */ - } - sa += len; - offset -= len; - } - - return VM_FAULT_SIGBUS; -} - -static const struct vm_operations_struct sg_mmap_vm_ops = { - .fault = sg_vma_fault, -}; - -static int -sg_mmap(struct file *filp, struct vm_area_struct *vma) -{ - Sg_fd *sfp; - unsigned long req_sz, len, sa; - Sg_scatter_hold *rsv_schp; - int k, length; - - if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data))) - return -ENXIO; - req_sz = vma->vm_end - vma->vm_start; - SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n", - (void *) vma->vm_start, (int) req_sz)); - if (vma->vm_pgoff) - return -EINVAL; /* want no offset */ - rsv_schp = &sfp->reserve; - if (req_sz > rsv_schp->bufflen) - return -ENOMEM; /* cannot map more than reserved buffer */ - - sa = vma->vm_start; - length = 1 << (PAGE_SHIFT + rsv_schp->page_order); - for (k = 0; k < rsv_schp->k_use_sg && sa < vma->vm_end; k++) { - len = vma->vm_end - sa; - len = (len < length) ? len : length; - sa += len; - } - - sfp->mmap_called = 1; - vma->vm_flags |= VM_RESERVED; - vma->vm_private_data = sfp; - vma->vm_ops = &sg_mmap_vm_ops; - return 0; -} - -static void sg_rq_end_io_usercontext(struct work_struct *work) -{ - struct sg_request *srp = container_of(work, struct sg_request, ew.work); - struct sg_fd *sfp = srp->parentfp; - - sg_finish_rem_req(srp); - kref_put(&sfp->f_ref, sg_remove_sfp); -} - -/* - * This function is a "bottom half" handler that is called by the mid - * level when a command is completed (or has failed). - */ -static void sg_rq_end_io(struct request *rq, int uptodate) -{ - struct sg_request *srp = rq->end_io_data; - Sg_device *sdp; - Sg_fd *sfp; - unsigned long iflags; - unsigned int ms; - char *sense; - int result, resid, done = 1; - - if (WARN_ON(srp->done != 0)) - return; - - sfp = srp->parentfp; - if (WARN_ON(sfp == NULL)) - return; - - sdp = sfp->parentdp; - if (unlikely(sdp->detached)) - printk(KERN_INFO "sg_rq_end_io: device detached\n"); - - sense = rq->sense; - result = rq->errors; - resid = rq->resid_len; - - SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n", - sdp->disk->disk_name, srp->header.pack_id, result)); - srp->header.resid = resid; - ms = jiffies_to_msecs(jiffies); - srp->header.duration = (ms > srp->header.duration) ? - (ms - srp->header.duration) : 0; - if (0 != result) { - struct scsi_sense_hdr sshdr; - - srp->header.status = 0xff & result; - srp->header.masked_status = status_byte(result); - srp->header.msg_status = msg_byte(result); - srp->header.host_status = host_byte(result); - srp->header.driver_status = driver_byte(result); - if ((sdp->sgdebug > 0) && - ((CHECK_CONDITION == srp->header.masked_status) || - (COMMAND_TERMINATED == srp->header.masked_status))) - __scsi_print_sense("sg_cmd_done", sense, - SCSI_SENSE_BUFFERSIZE); - - /* Following if statement is a patch supplied by Eric Youngdale */ - if (driver_byte(result) != 0 - && scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr) - && !scsi_sense_is_deferred(&sshdr) - && sshdr.sense_key == UNIT_ATTENTION - && sdp->device->removable) { - /* Detected possible disc change. Set the bit - this */ - /* may be used if there are filesystems using this device */ - sdp->device->changed = 1; - } - } - /* Rely on write phase to clean out srp status values, so no "else" */ - - write_lock_irqsave(&sfp->rq_list_lock, iflags); - if (unlikely(srp->orphan)) { - if (sfp->keep_orphan) - srp->sg_io_owned = 0; - else - done = 0; - } - srp->done = done; - write_unlock_irqrestore(&sfp->rq_list_lock, iflags); - - if (likely(done)) { - /* Now wake up any sg_read() that is waiting for this - * packet. - */ - wake_up_interruptible(&sfp->read_wait); - kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN); - kref_put(&sfp->f_ref, sg_remove_sfp); - } else { - INIT_WORK(&srp->ew.work, sg_rq_end_io_usercontext); - schedule_work(&srp->ew.work); - } -} - -static const struct file_operations sg_fops = { - .owner = THIS_MODULE, - .read = sg_read, - .write = sg_write, - .poll = sg_poll, - .unlocked_ioctl = sg_unlocked_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = sg_compat_ioctl, -#endif - .open = sg_open, - .mmap = sg_mmap, - .release = sg_release, - .fasync = sg_fasync, - .llseek = no_llseek, -}; - -static struct class *sg_sysfs_class; - -static int sg_sysfs_valid = 0; - -static Sg_device *sg_alloc(struct gendisk *disk, struct scsi_device *scsidp) -{ - struct request_queue *q = scsidp->request_queue; - Sg_device *sdp; - unsigned long iflags; - int error; - u32 k; - - sdp = kzalloc(sizeof(Sg_device), GFP_KERNEL); - if (!sdp) { - printk(KERN_WARNING "kmalloc Sg_device failure\n"); - return ERR_PTR(-ENOMEM); - } - - if (!idr_pre_get(&sg_index_idr, GFP_KERNEL)) { - printk(KERN_WARNING "idr expansion Sg_device failure\n"); - error = -ENOMEM; - goto out; - } - - write_lock_irqsave(&sg_index_lock, iflags); - - error = idr_get_new(&sg_index_idr, sdp, &k); - if (error) { - write_unlock_irqrestore(&sg_index_lock, iflags); - printk(KERN_WARNING "idr allocation Sg_device failure: %d\n", - error); - goto out; - } - - if (unlikely(k >= SG_MAX_DEVS)) - goto overflow; - - SCSI_LOG_TIMEOUT(3, printk("sg_alloc: dev=%d \n", k)); - sprintf(disk->disk_name, "sg%d", k); - disk->first_minor = k; - sdp->disk = disk; - sdp->device = scsidp; - INIT_LIST_HEAD(&sdp->sfds); - init_waitqueue_head(&sdp->o_excl_wait); - sdp->sg_tablesize = queue_max_segments(q); - sdp->index = k; - kref_init(&sdp->d_ref); - - write_unlock_irqrestore(&sg_index_lock, iflags); - - error = 0; - out: - if (error) { - kfree(sdp); - return ERR_PTR(error); - } - return sdp; - - overflow: - idr_remove(&sg_index_idr, k); - write_unlock_irqrestore(&sg_index_lock, iflags); - sdev_printk(KERN_WARNING, scsidp, - "Unable to attach sg device type=%d, minor " - "number exceeds %d\n", scsidp->type, SG_MAX_DEVS - 1); - error = -ENODEV; - goto out; -} - -static int -sg_add(struct device *cl_dev, struct class_interface *cl_intf) -{ - struct scsi_device *scsidp = to_scsi_device(cl_dev->parent); - struct gendisk *disk; - Sg_device *sdp = NULL; - struct cdev * cdev = NULL; - int error; - unsigned long iflags; - - disk = alloc_disk(1); - if (!disk) { - printk(KERN_WARNING "alloc_disk failed\n"); - return -ENOMEM; - } - disk->major = SCSI_GENERIC_MAJOR; - - error = -ENOMEM; - cdev = cdev_alloc(); - if (!cdev) { - printk(KERN_WARNING "cdev_alloc failed\n"); - goto out; - } - cdev->owner = THIS_MODULE; - cdev->ops = &sg_fops; - - sdp = sg_alloc(disk, scsidp); - if (IS_ERR(sdp)) { - printk(KERN_WARNING "sg_alloc failed\n"); - error = PTR_ERR(sdp); - goto out; - } - - error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, sdp->index), 1); - if (error) - goto cdev_add_err; - - sdp->cdev = cdev; - if (sg_sysfs_valid) { - struct device *sg_class_member; - - sg_class_member = device_create(sg_sysfs_class, cl_dev->parent, - MKDEV(SCSI_GENERIC_MAJOR, - sdp->index), - sdp, "%s", disk->disk_name); - if (IS_ERR(sg_class_member)) { - printk(KERN_ERR "sg_add: " - "device_create failed\n"); - error = PTR_ERR(sg_class_member); - goto cdev_add_err; - } - error = sysfs_create_link(&scsidp->sdev_gendev.kobj, - &sg_class_member->kobj, "generic"); - if (error) - printk(KERN_ERR "sg_add: unable to make symlink " - "'generic' back to sg%d\n", sdp->index); - } else - printk(KERN_WARNING "sg_add: sg_sys Invalid\n"); - - sdev_printk(KERN_NOTICE, scsidp, - "Attached scsi generic sg%d type %d\n", sdp->index, - scsidp->type); - - dev_set_drvdata(cl_dev, sdp); - - return 0; - -cdev_add_err: - write_lock_irqsave(&sg_index_lock, iflags); - idr_remove(&sg_index_idr, sdp->index); - write_unlock_irqrestore(&sg_index_lock, iflags); - kfree(sdp); - -out: - put_disk(disk); - if (cdev) - cdev_del(cdev); - return error; -} - -static void sg_device_destroy(struct kref *kref) -{ - struct sg_device *sdp = container_of(kref, struct sg_device, d_ref); - unsigned long flags; - - /* CAUTION! Note that the device can still be found via idr_find() - * even though the refcount is 0. Therefore, do idr_remove() BEFORE - * any other cleanup. - */ - - write_lock_irqsave(&sg_index_lock, flags); - idr_remove(&sg_index_idr, sdp->index); - write_unlock_irqrestore(&sg_index_lock, flags); - - SCSI_LOG_TIMEOUT(3, - printk("sg_device_destroy: %s\n", - sdp->disk->disk_name)); - - put_disk(sdp->disk); - kfree(sdp); -} - -static void sg_remove(struct device *cl_dev, struct class_interface *cl_intf) -{ - struct scsi_device *scsidp = to_scsi_device(cl_dev->parent); - Sg_device *sdp = dev_get_drvdata(cl_dev); - unsigned long iflags; - Sg_fd *sfp; - - if (!sdp || sdp->detached) - return; - - SCSI_LOG_TIMEOUT(3, printk("sg_remove: %s\n", sdp->disk->disk_name)); - - /* Need a write lock to set sdp->detached. */ - write_lock_irqsave(&sg_index_lock, iflags); - sdp->detached = 1; - list_for_each_entry(sfp, &sdp->sfds, sfd_siblings) { - wake_up_interruptible(&sfp->read_wait); - kill_fasync(&sfp->async_qp, SIGPOLL, POLL_HUP); - } - write_unlock_irqrestore(&sg_index_lock, iflags); - - sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic"); - device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, sdp->index)); - cdev_del(sdp->cdev); - sdp->cdev = NULL; - - sg_put_dev(sdp); -} - -module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR); -module_param_named(def_reserved_size, def_reserved_size, int, - S_IRUGO | S_IWUSR); -module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR); - -MODULE_AUTHOR("Douglas Gilbert"); -MODULE_DESCRIPTION("SCSI generic (sg) driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(SG_VERSION_STR); -MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR); - -MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element " - "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))"); -MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); -MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); - -static int __init -init_sg(void) -{ - int rc; - - if (scatter_elem_sz < PAGE_SIZE) { - scatter_elem_sz = PAGE_SIZE; - scatter_elem_sz_prev = scatter_elem_sz; - } - if (def_reserved_size >= 0) - sg_big_buff = def_reserved_size; - else - def_reserved_size = sg_big_buff; - - rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), - SG_MAX_DEVS, "sg"); - if (rc) - return rc; - sg_sysfs_class = class_create(THIS_MODULE, "scsi_generic"); - if ( IS_ERR(sg_sysfs_class) ) { - rc = PTR_ERR(sg_sysfs_class); - goto err_out; - } - sg_sysfs_valid = 1; - rc = scsi_register_interface(&sg_interface); - if (0 == rc) { -#ifdef CONFIG_SCSI_PROC_FS - sg_proc_init(); -#endif /* CONFIG_SCSI_PROC_FS */ - return 0; - } - class_destroy(sg_sysfs_class); -err_out: - unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS); - return rc; -} - -static void __exit -exit_sg(void) -{ -#ifdef CONFIG_SCSI_PROC_FS - sg_proc_cleanup(); -#endif /* CONFIG_SCSI_PROC_FS */ - scsi_unregister_interface(&sg_interface); - class_destroy(sg_sysfs_class); - sg_sysfs_valid = 0; - unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), - SG_MAX_DEVS); - idr_destroy(&sg_index_idr); -} - -static int sg_start_req(Sg_request *srp, unsigned char *cmd) -{ - int res; - struct request *rq; - Sg_fd *sfp = srp->parentfp; - sg_io_hdr_t *hp = &srp->header; - int dxfer_len = (int) hp->dxfer_len; - int dxfer_dir = hp->dxfer_direction; - unsigned int iov_count = hp->iovec_count; - Sg_scatter_hold *req_schp = &srp->data; - Sg_scatter_hold *rsv_schp = &sfp->reserve; - struct request_queue *q = sfp->parentdp->device->request_queue; - struct rq_map_data *md, map_data; - int rw = hp->dxfer_direction == SG_DXFER_TO_DEV ? WRITE : READ; - - SCSI_LOG_TIMEOUT(4, printk(KERN_INFO "sg_start_req: dxfer_len=%d\n", - dxfer_len)); - - rq = blk_get_request(q, rw, GFP_ATOMIC); - if (!rq) - return -ENOMEM; - - memcpy(rq->cmd, cmd, hp->cmd_len); - - rq->cmd_len = hp->cmd_len; - rq->cmd_type = REQ_TYPE_BLOCK_PC; - - srp->rq = rq; - rq->end_io_data = srp; - rq->sense = srp->sense_b; - rq->retries = SG_DEFAULT_RETRIES; - - if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE)) - return 0; - - if (sg_allow_dio && hp->flags & SG_FLAG_DIRECT_IO && - dxfer_dir != SG_DXFER_UNKNOWN && !iov_count && - !sfp->parentdp->device->host->unchecked_isa_dma && - blk_rq_aligned(q, (unsigned long)hp->dxferp, dxfer_len)) - md = NULL; - else - md = &map_data; - - if (md) { - if (!sg_res_in_use(sfp) && dxfer_len <= rsv_schp->bufflen) - sg_link_reserve(sfp, srp, dxfer_len); - else { - res = sg_build_indirect(req_schp, sfp, dxfer_len); - if (res) - return res; - } - - md->pages = req_schp->pages; - md->page_order = req_schp->page_order; - md->nr_entries = req_schp->k_use_sg; - md->offset = 0; - md->null_mapped = hp->dxferp ? 0 : 1; - if (dxfer_dir == SG_DXFER_TO_FROM_DEV) - md->from_user = 1; - else - md->from_user = 0; - } - - if (iov_count) { - int len, size = sizeof(struct sg_iovec) * iov_count; - struct iovec *iov; - - iov = memdup_user(hp->dxferp, size); - if (IS_ERR(iov)) - return PTR_ERR(iov); - - len = iov_length(iov, iov_count); - if (hp->dxfer_len < len) { - iov_count = iov_shorten(iov, iov_count, hp->dxfer_len); - len = hp->dxfer_len; - } - - res = blk_rq_map_user_iov(q, rq, md, (struct sg_iovec *)iov, - iov_count, - len, GFP_ATOMIC); - kfree(iov); - } else - res = blk_rq_map_user(q, rq, md, hp->dxferp, - hp->dxfer_len, GFP_ATOMIC); - - if (!res) { - srp->bio = rq->bio; - - if (!md) { - req_schp->dio_in_use = 1; - hp->info |= SG_INFO_DIRECT_IO; - } - } - return res; -} - -static int sg_finish_rem_req(Sg_request * srp) -{ - int ret = 0; - - Sg_fd *sfp = srp->parentfp; - Sg_scatter_hold *req_schp = &srp->data; - - SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", (int) srp->res_used)); - if (srp->rq) { - if (srp->bio) - ret = blk_rq_unmap_user(srp->bio); - - blk_put_request(srp->rq); - } - - if (srp->res_used) - sg_unlink_reserve(sfp, srp); - else - sg_remove_scat(req_schp); - - sg_remove_request(sfp, srp); - - return ret; -} - -static int -sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize) -{ - int sg_bufflen = tablesize * sizeof(struct page *); - gfp_t gfp_flags = GFP_ATOMIC | __GFP_NOWARN; - - schp->pages = kzalloc(sg_bufflen, gfp_flags); - if (!schp->pages) - return -ENOMEM; - schp->sglist_len = sg_bufflen; - return tablesize; /* number of scat_gath elements allocated */ -} - -static int -sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size) -{ - int ret_sz = 0, i, k, rem_sz, num, mx_sc_elems; - int sg_tablesize = sfp->parentdp->sg_tablesize; - int blk_size = buff_size, order; - gfp_t gfp_mask = GFP_ATOMIC | __GFP_COMP | __GFP_NOWARN; - - if (blk_size < 0) - return -EFAULT; - if (0 == blk_size) - ++blk_size; /* don't know why */ - /* round request up to next highest SG_SECTOR_SZ byte boundary */ - blk_size = ALIGN(blk_size, SG_SECTOR_SZ); - SCSI_LOG_TIMEOUT(4, printk("sg_build_indirect: buff_size=%d, blk_size=%d\n", - buff_size, blk_size)); - - /* N.B. ret_sz carried into this block ... */ - mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize); - if (mx_sc_elems < 0) - return mx_sc_elems; /* most likely -ENOMEM */ - - num = scatter_elem_sz; - if (unlikely(num != scatter_elem_sz_prev)) { - if (num < PAGE_SIZE) { - scatter_elem_sz = PAGE_SIZE; - scatter_elem_sz_prev = PAGE_SIZE; - } else - scatter_elem_sz_prev = num; - } - - if (sfp->low_dma) - gfp_mask |= GFP_DMA; - - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - gfp_mask |= __GFP_ZERO; - - order = get_order(num); -retry: - ret_sz = 1 << (PAGE_SHIFT + order); - - for (k = 0, rem_sz = blk_size; rem_sz > 0 && k < mx_sc_elems; - k++, rem_sz -= ret_sz) { - - num = (rem_sz > scatter_elem_sz_prev) ? - scatter_elem_sz_prev : rem_sz; - - schp->pages[k] = alloc_pages(gfp_mask, order); - if (!schp->pages[k]) - goto out; - - if (num == scatter_elem_sz_prev) { - if (unlikely(ret_sz > scatter_elem_sz_prev)) { - scatter_elem_sz = ret_sz; - scatter_elem_sz_prev = ret_sz; - } - } - - SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k=%d, num=%d, " - "ret_sz=%d\n", k, num, ret_sz)); - } /* end of for loop */ - - schp->page_order = order; - schp->k_use_sg = k; - SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, " - "rem_sz=%d\n", k, rem_sz)); - - schp->bufflen = blk_size; - if (rem_sz > 0) /* must have failed */ - return -ENOMEM; - return 0; -out: - for (i = 0; i < k; i++) - __free_pages(schp->pages[i], order); - - if (--order >= 0) - goto retry; - - return -ENOMEM; -} - -static void -sg_remove_scat(Sg_scatter_hold * schp) -{ - SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n", schp->k_use_sg)); - if (schp->pages && schp->sglist_len > 0) { - if (!schp->dio_in_use) { - int k; - - for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) { - SCSI_LOG_TIMEOUT(5, printk( - "sg_remove_scat: k=%d, pg=0x%p\n", - k, schp->pages[k])); - __free_pages(schp->pages[k], schp->page_order); - } - - kfree(schp->pages); - } - } - memset(schp, 0, sizeof (*schp)); -} - -static int -sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer) -{ - Sg_scatter_hold *schp = &srp->data; - int k, num; - - SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n", - num_read_xfer)); - if ((!outp) || (num_read_xfer <= 0)) - return 0; - - num = 1 << (PAGE_SHIFT + schp->page_order); - for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) { - if (num > num_read_xfer) { - if (__copy_to_user(outp, page_address(schp->pages[k]), - num_read_xfer)) - return -EFAULT; - break; - } else { - if (__copy_to_user(outp, page_address(schp->pages[k]), - num)) - return -EFAULT; - num_read_xfer -= num; - if (num_read_xfer <= 0) - break; - outp += num; - } - } - - return 0; -} - -static void -sg_build_reserve(Sg_fd * sfp, int req_size) -{ - Sg_scatter_hold *schp = &sfp->reserve; - - SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size)); - do { - if (req_size < PAGE_SIZE) - req_size = PAGE_SIZE; - if (0 == sg_build_indirect(schp, sfp, req_size)) - return; - else - sg_remove_scat(schp); - req_size >>= 1; /* divide by 2 */ - } while (req_size > (PAGE_SIZE / 2)); -} - -static void -sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size) -{ - Sg_scatter_hold *req_schp = &srp->data; - Sg_scatter_hold *rsv_schp = &sfp->reserve; - int k, num, rem; - - srp->res_used = 1; - SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size)); - rem = size; - - num = 1 << (PAGE_SHIFT + rsv_schp->page_order); - for (k = 0; k < rsv_schp->k_use_sg; k++) { - if (rem <= num) { - req_schp->k_use_sg = k + 1; - req_schp->sglist_len = rsv_schp->sglist_len; - req_schp->pages = rsv_schp->pages; - - req_schp->bufflen = size; - req_schp->page_order = rsv_schp->page_order; - break; - } else - rem -= num; - } - - if (k >= rsv_schp->k_use_sg) - SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n")); -} - -static void -sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp) -{ - Sg_scatter_hold *req_schp = &srp->data; - - SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n", - (int) req_schp->k_use_sg)); - req_schp->k_use_sg = 0; - req_schp->bufflen = 0; - req_schp->pages = NULL; - req_schp->page_order = 0; - req_schp->sglist_len = 0; - sfp->save_scat_len = 0; - srp->res_used = 0; -} - -static Sg_request * -sg_get_rq_mark(Sg_fd * sfp, int pack_id) -{ - Sg_request *resp; - unsigned long iflags; - - write_lock_irqsave(&sfp->rq_list_lock, iflags); - for (resp = sfp->headrp; resp; resp = resp->nextrp) { - /* look for requests that are ready + not SG_IO owned */ - if ((1 == resp->done) && (!resp->sg_io_owned) && - ((-1 == pack_id) || (resp->header.pack_id == pack_id))) { - resp->done = 2; /* guard against other readers */ - break; - } - } - write_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return resp; -} - -/* always adds to end of list */ -static Sg_request * -sg_add_request(Sg_fd * sfp) -{ - int k; - unsigned long iflags; - Sg_request *resp; - Sg_request *rp = sfp->req_arr; - - write_lock_irqsave(&sfp->rq_list_lock, iflags); - resp = sfp->headrp; - if (!resp) { - memset(rp, 0, sizeof (Sg_request)); - rp->parentfp = sfp; - resp = rp; - sfp->headrp = resp; - } else { - if (0 == sfp->cmd_q) - resp = NULL; /* command queuing disallowed */ - else { - for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) { - if (!rp->parentfp) - break; - } - if (k < SG_MAX_QUEUE) { - memset(rp, 0, sizeof (Sg_request)); - rp->parentfp = sfp; - while (resp->nextrp) - resp = resp->nextrp; - resp->nextrp = rp; - resp = rp; - } else - resp = NULL; - } - } - if (resp) { - resp->nextrp = NULL; - resp->header.duration = jiffies_to_msecs(jiffies); - } - write_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return resp; -} - -/* Return of 1 for found; 0 for not found */ -static int -sg_remove_request(Sg_fd * sfp, Sg_request * srp) -{ - Sg_request *prev_rp; - Sg_request *rp; - unsigned long iflags; - int res = 0; - - if ((!sfp) || (!srp) || (!sfp->headrp)) - return res; - write_lock_irqsave(&sfp->rq_list_lock, iflags); - prev_rp = sfp->headrp; - if (srp == prev_rp) { - sfp->headrp = prev_rp->nextrp; - prev_rp->parentfp = NULL; - res = 1; - } else { - while ((rp = prev_rp->nextrp)) { - if (srp == rp) { - prev_rp->nextrp = rp->nextrp; - rp->parentfp = NULL; - res = 1; - break; - } - prev_rp = rp; - } - } - write_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return res; -} - -static Sg_fd * -sg_add_sfp(Sg_device * sdp, int dev) -{ - Sg_fd *sfp; - unsigned long iflags; - int bufflen; - - sfp = kzalloc(sizeof(*sfp), GFP_ATOMIC | __GFP_NOWARN); - if (!sfp) - return NULL; - - init_waitqueue_head(&sfp->read_wait); - rwlock_init(&sfp->rq_list_lock); - - kref_init(&sfp->f_ref); - sfp->timeout = SG_DEFAULT_TIMEOUT; - sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER; - sfp->force_packid = SG_DEF_FORCE_PACK_ID; - sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ? - sdp->device->host->unchecked_isa_dma : 1; - sfp->cmd_q = SG_DEF_COMMAND_Q; - sfp->keep_orphan = SG_DEF_KEEP_ORPHAN; - sfp->parentdp = sdp; - write_lock_irqsave(&sg_index_lock, iflags); - list_add_tail(&sfp->sfd_siblings, &sdp->sfds); - write_unlock_irqrestore(&sg_index_lock, iflags); - SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp)); - if (unlikely(sg_big_buff != def_reserved_size)) - sg_big_buff = def_reserved_size; - - bufflen = min_t(int, sg_big_buff, - queue_max_sectors(sdp->device->request_queue) * 512); - sg_build_reserve(sfp, bufflen); - SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n", - sfp->reserve.bufflen, sfp->reserve.k_use_sg)); - - kref_get(&sdp->d_ref); - __module_get(THIS_MODULE); - return sfp; -} - -static void sg_remove_sfp_usercontext(struct work_struct *work) -{ - struct sg_fd *sfp = container_of(work, struct sg_fd, ew.work); - struct sg_device *sdp = sfp->parentdp; - - /* Cleanup any responses which were never read(). */ - while (sfp->headrp) - sg_finish_rem_req(sfp->headrp); - - if (sfp->reserve.bufflen > 0) { - SCSI_LOG_TIMEOUT(6, - printk("sg_remove_sfp: bufflen=%d, k_use_sg=%d\n", - (int) sfp->reserve.bufflen, - (int) sfp->reserve.k_use_sg)); - sg_remove_scat(&sfp->reserve); - } - - SCSI_LOG_TIMEOUT(6, - printk("sg_remove_sfp: %s, sfp=0x%p\n", - sdp->disk->disk_name, - sfp)); - kfree(sfp); - - scsi_device_put(sdp->device); - sg_put_dev(sdp); - module_put(THIS_MODULE); -} - -static void sg_remove_sfp(struct kref *kref) -{ - struct sg_fd *sfp = container_of(kref, struct sg_fd, f_ref); - struct sg_device *sdp = sfp->parentdp; - unsigned long iflags; - - write_lock_irqsave(&sg_index_lock, iflags); - list_del(&sfp->sfd_siblings); - write_unlock_irqrestore(&sg_index_lock, iflags); - wake_up_interruptible(&sdp->o_excl_wait); - - INIT_WORK(&sfp->ew.work, sg_remove_sfp_usercontext); - schedule_work(&sfp->ew.work); -} - -static int -sg_res_in_use(Sg_fd * sfp) -{ - const Sg_request *srp; - unsigned long iflags; - - read_lock_irqsave(&sfp->rq_list_lock, iflags); - for (srp = sfp->headrp; srp; srp = srp->nextrp) - if (srp->res_used) - break; - read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - return srp ? 1 : 0; -} - -#ifdef CONFIG_SCSI_PROC_FS -static int -sg_idr_max_id(int id, void *p, void *data) -{ - int *k = data; - - if (*k < id) - *k = id; - - return 0; -} - -static int -sg_last_dev(void) -{ - int k = -1; - unsigned long iflags; - - read_lock_irqsave(&sg_index_lock, iflags); - idr_for_each(&sg_index_idr, sg_idr_max_id, &k); - read_unlock_irqrestore(&sg_index_lock, iflags); - return k + 1; /* origin 1 */ -} -#endif - -/* must be called with sg_index_lock held */ -static Sg_device *sg_lookup_dev(int dev) -{ - return idr_find(&sg_index_idr, dev); -} - -static Sg_device *sg_get_dev(int dev) -{ - struct sg_device *sdp; - unsigned long flags; - - read_lock_irqsave(&sg_index_lock, flags); - sdp = sg_lookup_dev(dev); - if (!sdp) - sdp = ERR_PTR(-ENXIO); - else if (sdp->detached) { - /* If sdp->detached, then the refcount may already be 0, in - * which case it would be a bug to do kref_get(). - */ - sdp = ERR_PTR(-ENODEV); - } else - kref_get(&sdp->d_ref); - read_unlock_irqrestore(&sg_index_lock, flags); - - return sdp; -} - -static void sg_put_dev(struct sg_device *sdp) -{ - kref_put(&sdp->d_ref, sg_device_destroy); -} - -#ifdef CONFIG_SCSI_PROC_FS - -static struct proc_dir_entry *sg_proc_sgp = NULL; - -static char sg_proc_sg_dirname[] = "scsi/sg"; - -static int sg_proc_seq_show_int(struct seq_file *s, void *v); - -static int sg_proc_single_open_adio(struct inode *inode, struct file *file); -static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer, - size_t count, loff_t *off); -static const struct file_operations adio_fops = { - .owner = THIS_MODULE, - .open = sg_proc_single_open_adio, - .read = seq_read, - .llseek = seq_lseek, - .write = sg_proc_write_adio, - .release = single_release, -}; - -static int sg_proc_single_open_dressz(struct inode *inode, struct file *file); -static ssize_t sg_proc_write_dressz(struct file *filp, - const char __user *buffer, size_t count, loff_t *off); -static const struct file_operations dressz_fops = { - .owner = THIS_MODULE, - .open = sg_proc_single_open_dressz, - .read = seq_read, - .llseek = seq_lseek, - .write = sg_proc_write_dressz, - .release = single_release, -}; - -static int sg_proc_seq_show_version(struct seq_file *s, void *v); -static int sg_proc_single_open_version(struct inode *inode, struct file *file); -static const struct file_operations version_fops = { - .owner = THIS_MODULE, - .open = sg_proc_single_open_version, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v); -static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file); -static const struct file_operations devhdr_fops = { - .owner = THIS_MODULE, - .open = sg_proc_single_open_devhdr, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int sg_proc_seq_show_dev(struct seq_file *s, void *v); -static int sg_proc_open_dev(struct inode *inode, struct file *file); -static void * dev_seq_start(struct seq_file *s, loff_t *pos); -static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos); -static void dev_seq_stop(struct seq_file *s, void *v); -static const struct file_operations dev_fops = { - .owner = THIS_MODULE, - .open = sg_proc_open_dev, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -static const struct seq_operations dev_seq_ops = { - .start = dev_seq_start, - .next = dev_seq_next, - .stop = dev_seq_stop, - .show = sg_proc_seq_show_dev, -}; - -static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v); -static int sg_proc_open_devstrs(struct inode *inode, struct file *file); -static const struct file_operations devstrs_fops = { - .owner = THIS_MODULE, - .open = sg_proc_open_devstrs, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -static const struct seq_operations devstrs_seq_ops = { - .start = dev_seq_start, - .next = dev_seq_next, - .stop = dev_seq_stop, - .show = sg_proc_seq_show_devstrs, -}; - -static int sg_proc_seq_show_debug(struct seq_file *s, void *v); -static int sg_proc_open_debug(struct inode *inode, struct file *file); -static const struct file_operations debug_fops = { - .owner = THIS_MODULE, - .open = sg_proc_open_debug, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -static const struct seq_operations debug_seq_ops = { - .start = dev_seq_start, - .next = dev_seq_next, - .stop = dev_seq_stop, - .show = sg_proc_seq_show_debug, -}; - - -struct sg_proc_leaf { - const char * name; - const struct file_operations * fops; -}; - -static struct sg_proc_leaf sg_proc_leaf_arr[] = { - {"allow_dio", &adio_fops}, - {"debug", &debug_fops}, - {"def_reserved_size", &dressz_fops}, - {"device_hdr", &devhdr_fops}, - {"devices", &dev_fops}, - {"device_strs", &devstrs_fops}, - {"version", &version_fops} -}; - -static int -sg_proc_init(void) -{ - int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr); - int k; - - sg_proc_sgp = proc_mkdir(sg_proc_sg_dirname, NULL); - if (!sg_proc_sgp) - return 1; - for (k = 0; k < num_leaves; ++k) { - struct sg_proc_leaf *leaf = &sg_proc_leaf_arr[k]; - umode_t mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO; - proc_create(leaf->name, mask, sg_proc_sgp, leaf->fops); - } - return 0; -} - -static void -sg_proc_cleanup(void) -{ - int k; - int num_leaves = ARRAY_SIZE(sg_proc_leaf_arr); - - if (!sg_proc_sgp) - return; - for (k = 0; k < num_leaves; ++k) - remove_proc_entry(sg_proc_leaf_arr[k].name, sg_proc_sgp); - remove_proc_entry(sg_proc_sg_dirname, NULL); -} - - -static int sg_proc_seq_show_int(struct seq_file *s, void *v) -{ - seq_printf(s, "%d\n", *((int *)s->private)); - return 0; -} - -static int sg_proc_single_open_adio(struct inode *inode, struct file *file) -{ - return single_open(file, sg_proc_seq_show_int, &sg_allow_dio); -} - -static ssize_t -sg_proc_write_adio(struct file *filp, const char __user *buffer, - size_t count, loff_t *off) -{ - int err; - unsigned long num; - - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - err = kstrtoul_from_user(buffer, count, 0, &num); - if (err) - return err; - sg_allow_dio = num ? 1 : 0; - return count; -} - -static int sg_proc_single_open_dressz(struct inode *inode, struct file *file) -{ - return single_open(file, sg_proc_seq_show_int, &sg_big_buff); -} - -static ssize_t -sg_proc_write_dressz(struct file *filp, const char __user *buffer, - size_t count, loff_t *off) -{ - int err; - unsigned long k = ULONG_MAX; - - if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) - return -EACCES; - - err = kstrtoul_from_user(buffer, count, 0, &k); - if (err) - return err; - if (k <= 1048576) { /* limit "big buff" to 1 MB */ - sg_big_buff = k; - return count; - } - return -ERANGE; -} - -static int sg_proc_seq_show_version(struct seq_file *s, void *v) -{ - seq_printf(s, "%d\t%s [%s]\n", sg_version_num, SG_VERSION_STR, - sg_version_date); - return 0; -} - -static int sg_proc_single_open_version(struct inode *inode, struct file *file) -{ - return single_open(file, sg_proc_seq_show_version, NULL); -} - -static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v) -{ - seq_printf(s, "host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\t" - "online\n"); - return 0; -} - -static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file) -{ - return single_open(file, sg_proc_seq_show_devhdr, NULL); -} - -struct sg_proc_deviter { - loff_t index; - size_t max; -}; - -static void * dev_seq_start(struct seq_file *s, loff_t *pos) -{ - struct sg_proc_deviter * it = kmalloc(sizeof(*it), GFP_KERNEL); - - s->private = it; - if (! it) - return NULL; - - it->index = *pos; - it->max = sg_last_dev(); - if (it->index >= it->max) - return NULL; - return it; -} - -static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos) -{ - struct sg_proc_deviter * it = s->private; - - *pos = ++it->index; - return (it->index < it->max) ? it : NULL; -} - -static void dev_seq_stop(struct seq_file *s, void *v) -{ - kfree(s->private); -} - -static int sg_proc_open_dev(struct inode *inode, struct file *file) -{ - return seq_open(file, &dev_seq_ops); -} - -static int sg_proc_seq_show_dev(struct seq_file *s, void *v) -{ - struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; - Sg_device *sdp; - struct scsi_device *scsidp; - unsigned long iflags; - - read_lock_irqsave(&sg_index_lock, iflags); - sdp = it ? sg_lookup_dev(it->index) : NULL; - if (sdp && (scsidp = sdp->device) && (!sdp->detached)) - seq_printf(s, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n", - scsidp->host->host_no, scsidp->channel, - scsidp->id, scsidp->lun, (int) scsidp->type, - 1, - (int) scsidp->queue_depth, - (int) scsidp->device_busy, - (int) scsi_device_online(scsidp)); - else - seq_printf(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n"); - read_unlock_irqrestore(&sg_index_lock, iflags); - return 0; -} - -static int sg_proc_open_devstrs(struct inode *inode, struct file *file) -{ - return seq_open(file, &devstrs_seq_ops); -} - -static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v) -{ - struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; - Sg_device *sdp; - struct scsi_device *scsidp; - unsigned long iflags; - - read_lock_irqsave(&sg_index_lock, iflags); - sdp = it ? sg_lookup_dev(it->index) : NULL; - if (sdp && (scsidp = sdp->device) && (!sdp->detached)) - seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n", - scsidp->vendor, scsidp->model, scsidp->rev); - else - seq_printf(s, "\n"); - read_unlock_irqrestore(&sg_index_lock, iflags); - return 0; -} - -/* must be called while holding sg_index_lock */ -static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp) -{ - int k, m, new_interface, blen, usg; - Sg_request *srp; - Sg_fd *fp; - const sg_io_hdr_t *hp; - const char * cp; - unsigned int ms; - - k = 0; - list_for_each_entry(fp, &sdp->sfds, sfd_siblings) { - k++; - read_lock(&fp->rq_list_lock); /* irqs already disabled */ - seq_printf(s, " FD(%d): timeout=%dms bufflen=%d " - "(res)sgat=%d low_dma=%d\n", k, - jiffies_to_msecs(fp->timeout), - fp->reserve.bufflen, - (int) fp->reserve.k_use_sg, - (int) fp->low_dma); - seq_printf(s, " cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n", - (int) fp->cmd_q, (int) fp->force_packid, - (int) fp->keep_orphan, (int) fp->closed); - for (m = 0, srp = fp->headrp; - srp != NULL; - ++m, srp = srp->nextrp) { - hp = &srp->header; - new_interface = (hp->interface_id == '\0') ? 0 : 1; - if (srp->res_used) { - if (new_interface && - (SG_FLAG_MMAP_IO & hp->flags)) - cp = " mmap>> "; - else - cp = " rb>> "; - } else { - if (SG_INFO_DIRECT_IO_MASK & hp->info) - cp = " dio>> "; - else - cp = " "; - } - seq_printf(s, cp); - blen = srp->data.bufflen; - usg = srp->data.k_use_sg; - seq_printf(s, srp->done ? - ((1 == srp->done) ? "rcv:" : "fin:") - : "act:"); - seq_printf(s, " id=%d blen=%d", - srp->header.pack_id, blen); - if (srp->done) - seq_printf(s, " dur=%d", hp->duration); - else { - ms = jiffies_to_msecs(jiffies); - seq_printf(s, " t_o/elap=%d/%d", - (new_interface ? hp->timeout : - jiffies_to_msecs(fp->timeout)), - (ms > hp->duration ? ms - hp->duration : 0)); - } - seq_printf(s, "ms sgat=%d op=0x%02x\n", usg, - (int) srp->data.cmd_opcode); - } - if (0 == m) - seq_printf(s, " No requests active\n"); - read_unlock(&fp->rq_list_lock); - } -} - -static int sg_proc_open_debug(struct inode *inode, struct file *file) -{ - return seq_open(file, &debug_seq_ops); -} - -static int sg_proc_seq_show_debug(struct seq_file *s, void *v) -{ - struct sg_proc_deviter * it = (struct sg_proc_deviter *) v; - Sg_device *sdp; - unsigned long iflags; - - if (it && (0 == it->index)) { - seq_printf(s, "max_active_device=%d(origin 1)\n", - (int)it->max); - seq_printf(s, " def_reserved_size=%d\n", sg_big_buff); - } - - read_lock_irqsave(&sg_index_lock, iflags); - sdp = it ? sg_lookup_dev(it->index) : NULL; - if (sdp && !list_empty(&sdp->sfds)) { - struct scsi_device *scsidp = sdp->device; - - seq_printf(s, " >>> device=%s ", sdp->disk->disk_name); - if (sdp->detached) - seq_printf(s, "detached pending close "); - else - seq_printf - (s, "scsi%d chan=%d id=%d lun=%d em=%d", - scsidp->host->host_no, - scsidp->channel, scsidp->id, - scsidp->lun, - scsidp->host->hostt->emulated); - seq_printf(s, " sg_tablesize=%d excl=%d\n", - sdp->sg_tablesize, sdp->exclude); - sg_proc_debug_helper(s, sdp); - } - read_unlock_irqrestore(&sg_index_lock, iflags); - return 0; -} - -#endif /* CONFIG_SCSI_PROC_FS */ - -module_init(init_sg); -module_exit(exit_sg); diff --git a/ANDROID_3.4.5/drivers/scsi/sgiwd93.c b/ANDROID_3.4.5/drivers/scsi/sgiwd93.c deleted file mode 100644 index 3a9d85ca..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sgiwd93.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (C) 1996 David S. Miller (davem@davemloft.net) - * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) - * Copyright (C) 2001 Florian Lohoff (flo@rfc822.org) - * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org) - * - * (In all truth, Jed Schimmel wrote all this code.) - */ - -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "scsi.h" -#include "wd33c93.h" - -struct ip22_hostdata { - struct WD33C93_hostdata wh; - dma_addr_t dma; - void *cpu; - struct device *dev; -}; - -#define host_to_hostdata(host) ((struct ip22_hostdata *)((host)->hostdata)) - -struct hpc_chunk { - struct hpc_dma_desc desc; - u32 _padding; /* align to quadword boundary */ -}; - -/* space for hpc dma descriptors */ -#define HPC_DMA_SIZE PAGE_SIZE - -#define DMA_DIR(d) ((d == DATA_OUT_DIR) ? DMA_TO_DEVICE : DMA_FROM_DEVICE) - -static irqreturn_t sgiwd93_intr(int irq, void *dev_id) -{ - struct Scsi_Host * host = dev_id; - unsigned long flags; - - spin_lock_irqsave(host->host_lock, flags); - wd33c93_intr(host); - spin_unlock_irqrestore(host->host_lock, flags); - - return IRQ_HANDLED; -} - -static inline -void fill_hpc_entries(struct ip22_hostdata *hd, struct scsi_cmnd *cmd, int din) -{ - unsigned long len = cmd->SCp.this_residual; - void *addr = cmd->SCp.ptr; - dma_addr_t physaddr; - unsigned long count; - struct hpc_chunk *hcp; - - physaddr = dma_map_single(hd->dev, addr, len, DMA_DIR(din)); - cmd->SCp.dma_handle = physaddr; - hcp = hd->cpu; - - while (len) { - /* - * even cntinfo could be up to 16383, without - * magic only 8192 works correctly - */ - count = len > 8192 ? 8192 : len; - hcp->desc.pbuf = physaddr; - hcp->desc.cntinfo = count; - hcp++; - len -= count; - physaddr += count; - } - - /* - * To make sure, if we trip an HPC bug, that we transfer every single - * byte, we tag on an extra zero length dma descriptor at the end of - * the chain. - */ - hcp->desc.pbuf = 0; - hcp->desc.cntinfo = HPCDMA_EOX; - dma_cache_sync(hd->dev, hd->cpu, - (unsigned long)(hcp + 1) - (unsigned long)hd->cpu, - DMA_TO_DEVICE); -} - -static int dma_setup(struct scsi_cmnd *cmd, int datainp) -{ - struct ip22_hostdata *hdata = host_to_hostdata(cmd->device->host); - struct hpc3_scsiregs *hregs = - (struct hpc3_scsiregs *) cmd->device->host->base; - - pr_debug("dma_setup: datainp<%d> hcp<%p> ", datainp, hdata->cpu); - - hdata->wh.dma_dir = datainp; - - /* - * wd33c93 shouldn't pass us bogus dma_setups, but it does:-( The - * other wd33c93 drivers deal with it the same way (which isn't that - * obvious). IMHO a better fix would be, not to do these dma setups - * in the first place. - */ - if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0) - return 1; - - fill_hpc_entries(hdata, cmd, datainp); - - pr_debug(" HPCGO\n"); - - /* Start up the HPC. */ - hregs->ndptr = hdata->dma; - if (datainp) - hregs->ctrl = HPC3_SCTRL_ACTIVE; - else - hregs->ctrl = HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR; - - return 0; -} - -static void dma_stop(struct Scsi_Host *instance, struct scsi_cmnd *SCpnt, - int status) -{ - struct ip22_hostdata *hdata = host_to_hostdata(instance); - struct hpc3_scsiregs *hregs; - - if (!SCpnt) - return; - - if (SCpnt->SCp.ptr == NULL || SCpnt->SCp.this_residual == 0) - return; - - hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base; - - pr_debug("dma_stop: status<%d> ", status); - - /* First stop the HPC and flush it's FIFO. */ - if (hdata->wh.dma_dir) { - hregs->ctrl |= HPC3_SCTRL_FLUSH; - while (hregs->ctrl & HPC3_SCTRL_ACTIVE) - barrier(); - } - hregs->ctrl = 0; - dma_unmap_single(hdata->dev, SCpnt->SCp.dma_handle, - SCpnt->SCp.this_residual, - DMA_DIR(hdata->wh.dma_dir)); - - pr_debug("\n"); -} - -void sgiwd93_reset(unsigned long base) -{ - struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) base; - - hregs->ctrl = HPC3_SCTRL_CRESET; - udelay(50); - hregs->ctrl = 0; -} -EXPORT_SYMBOL_GPL(sgiwd93_reset); - -static inline void init_hpc_chain(struct ip22_hostdata *hdata) -{ - struct hpc_chunk *hcp = (struct hpc_chunk *)hdata->cpu; - dma_addr_t dma = hdata->dma; - unsigned long start, end; - - start = (unsigned long) hcp; - end = start + HPC_DMA_SIZE; - while (start < end) { - hcp->desc.pnext = (u32) (dma + sizeof(struct hpc_chunk)); - hcp->desc.cntinfo = HPCDMA_EOX; - hcp++; - dma += sizeof(struct hpc_chunk); - start += sizeof(struct hpc_chunk); - }; - hcp--; - hcp->desc.pnext = hdata->dma; -} - -static int sgiwd93_bus_reset(struct scsi_cmnd *cmd) -{ - /* FIXME perform bus-specific reset */ - - /* FIXME 2: kill this function, and let midlayer fallback - to the same result, calling wd33c93_host_reset() */ - - spin_lock_irq(cmd->device->host->host_lock); - wd33c93_host_reset(cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return SUCCESS; -} - -/* - * Kludge alert - the SCSI code calls the abort and reset method with int - * arguments not with pointers. So this is going to blow up beautyfully - * on 64-bit systems with memory outside the compat address spaces. - */ -static struct scsi_host_template sgiwd93_template = { - .module = THIS_MODULE, - .proc_name = "SGIWD93", - .name = "SGI WD93", - .queuecommand = wd33c93_queuecommand, - .eh_abort_handler = wd33c93_abort, - .eh_bus_reset_handler = sgiwd93_bus_reset, - .eh_host_reset_handler = wd33c93_host_reset, - .can_queue = 16, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 8, - .use_clustering = DISABLE_CLUSTERING, -}; - -static int __devinit sgiwd93_probe(struct platform_device *pdev) -{ - struct sgiwd93_platform_data *pd = pdev->dev.platform_data; - unsigned char *wdregs = pd->wdregs; - struct hpc3_scsiregs *hregs = pd->hregs; - struct ip22_hostdata *hdata; - struct Scsi_Host *host; - wd33c93_regs regs; - unsigned int unit = pd->unit; - unsigned int irq = pd->irq; - int err; - - host = scsi_host_alloc(&sgiwd93_template, sizeof(struct ip22_hostdata)); - if (!host) { - err = -ENOMEM; - goto out; - } - - host->base = (unsigned long) hregs; - host->irq = irq; - - hdata = host_to_hostdata(host); - hdata->dev = &pdev->dev; - hdata->cpu = dma_alloc_noncoherent(&pdev->dev, HPC_DMA_SIZE, - &hdata->dma, GFP_KERNEL); - if (!hdata->cpu) { - printk(KERN_WARNING "sgiwd93: Could not allocate memory for " - "host %d buffer.\n", unit); - err = -ENOMEM; - goto out_put; - } - - init_hpc_chain(hdata); - - regs.SASR = wdregs + 3; - regs.SCMD = wdregs + 7; - - hdata->wh.no_sync = 0; - hdata->wh.fast = 1; - hdata->wh.dma_mode = CTRL_BURST; - - wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_MHZ(20)); - - err = request_irq(irq, sgiwd93_intr, 0, "SGI WD93", host); - if (err) { - printk(KERN_WARNING "sgiwd93: Could not register irq %d " - "for host %d.\n", irq, unit); - goto out_free; - } - - platform_set_drvdata(pdev, host); - - err = scsi_add_host(host, NULL); - if (err) - goto out_irq; - - scsi_scan_host(host); - - return 0; - -out_irq: - free_irq(irq, host); -out_free: - dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma); -out_put: - scsi_host_put(host); -out: - - return err; -} - -static int __exit sgiwd93_remove(struct platform_device *pdev) -{ - struct Scsi_Host *host = platform_get_drvdata(pdev); - struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata; - struct sgiwd93_platform_data *pd = pdev->dev.platform_data; - - scsi_remove_host(host); - free_irq(pd->irq, host); - dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma); - scsi_host_put(host); - return 0; -} - -static struct platform_driver sgiwd93_driver = { - .probe = sgiwd93_probe, - .remove = __devexit_p(sgiwd93_remove), - .driver = { - .name = "sgiwd93", - .owner = THIS_MODULE, - } -}; - -static int __init sgiwd93_module_init(void) -{ - return platform_driver_register(&sgiwd93_driver); -} - -static void __exit sgiwd93_module_exit(void) -{ - return platform_driver_unregister(&sgiwd93_driver); -} - -module_init(sgiwd93_module_init); -module_exit(sgiwd93_module_exit); - -MODULE_DESCRIPTION("SGI WD33C93 driver"); -MODULE_AUTHOR("Ralf Baechle "); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:sgiwd93"); diff --git a/ANDROID_3.4.5/drivers/scsi/sim710.c b/ANDROID_3.4.5/drivers/scsi/sim710.c deleted file mode 100644 index 8ac6ce79..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sim710.c +++ /dev/null @@ -1,375 +0,0 @@ -/* - * sim710.c - Copyright (C) 1999 Richard Hirst - * - *---------------------------------------------------------------------------- - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - *---------------------------------------------------------------------------- - * - * MCA card detection code by Trent McNair. - * Fixes to not explicitly nul bss data from Xavier Bestel. - * Some multiboard fixes from Rolf Eike Beer. - * Auto probing of EISA config space from Trevor Hemsley. - * - * Rewritten to use 53c700.c by James.Bottomley@SteelEye.com - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "53c700.h" - - -/* Must be enough for both EISA and MCA */ -#define MAX_SLOTS 8 -static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 }; - -static char *sim710; /* command line passed by insmod */ - -MODULE_AUTHOR("Richard Hirst"); -MODULE_DESCRIPTION("Simple NCR53C710 driver"); -MODULE_LICENSE("GPL"); - -module_param(sim710, charp, 0); - -#ifdef MODULE -#define ARG_SEP ' ' -#else -#define ARG_SEP ',' -#endif - -static __init int -param_setup(char *str) -{ - char *pos = str, *next; - int slot = -1; - - while(pos != NULL && (next = strchr(pos, ':')) != NULL) { - int val = (int)simple_strtoul(++next, NULL, 0); - - if(!strncmp(pos, "slot:", 5)) - slot = val; - else if(!strncmp(pos, "id:", 3)) { - if(slot == -1) { - printk(KERN_WARNING "sim710: Must specify slot for id parameter\n"); - } else if(slot >= MAX_SLOTS) { - printk(KERN_WARNING "sim710: Illegal slot %d for id %d\n", slot, val); - } else { - id_array[slot] = val; - } - } - if((pos = strchr(pos, ARG_SEP)) != NULL) - pos++; - } - return 1; -} -__setup("sim710=", param_setup); - -static struct scsi_host_template sim710_driver_template = { - .name = "LSI (Symbios) 710 MCA/EISA", - .proc_name = "sim710", - .this_id = 7, - .module = THIS_MODULE, -}; - -static __devinit int -sim710_probe_common(struct device *dev, unsigned long base_addr, - int irq, int clock, int differential, int scsi_id) -{ - struct Scsi_Host * host = NULL; - struct NCR_700_Host_Parameters *hostdata = - kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); - - printk(KERN_NOTICE "sim710: %s\n", dev_name(dev)); - printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n", - irq, clock, base_addr, scsi_id); - - if(hostdata == NULL) { - printk(KERN_ERR "sim710: Failed to allocate host data\n"); - goto out; - } - - if(request_region(base_addr, 64, "sim710") == NULL) { - printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n", - base_addr); - goto out_free; - } - - /* Fill in the three required pieces of hostdata */ - hostdata->base = ioport_map(base_addr, 64); - hostdata->differential = differential; - hostdata->clock = clock; - hostdata->chip710 = 1; - hostdata->burst_length = 8; - - /* and register the chip */ - if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev)) - == NULL) { - printk(KERN_ERR "sim710: No host detected; card configuration problem?\n"); - goto out_release; - } - host->this_id = scsi_id; - host->base = base_addr; - host->irq = irq; - if (request_irq(irq, NCR_700_intr, IRQF_SHARED, "sim710", host)) { - printk(KERN_ERR "sim710: request_irq failed\n"); - goto out_put_host; - } - - dev_set_drvdata(dev, host); - scsi_scan_host(host); - - return 0; - - out_put_host: - scsi_host_put(host); - out_release: - release_region(base_addr, 64); - out_free: - kfree(hostdata); - out: - return -ENODEV; -} - -static __devexit int -sim710_device_remove(struct device *dev) -{ - struct Scsi_Host *host = dev_get_drvdata(dev); - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - - scsi_remove_host(host); - NCR_700_release(host); - kfree(hostdata); - free_irq(host->irq, host); - release_region(host->base, 64); - return 0; -} - -#ifdef CONFIG_MCA - -/* CARD ID 01BB and 01BA use the same pos values */ -#define MCA_01BB_IO_PORTS { 0x0000, 0x0000, 0x0800, 0x0C00, 0x1000, 0x1400, \ - 0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, \ - 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, \ - 0x4000, 0x4400, 0x4800, 0x4C00, 0x5000 } - -#define MCA_01BB_IRQS { 3, 5, 11, 14 } - -/* CARD ID 004f */ -#define MCA_004F_IO_PORTS { 0x0000, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600 } -#define MCA_004F_IRQS { 5, 9, 14 } - -static short sim710_mca_id_table[] = { 0x01bb, 0x01ba, 0x004f, 0}; - -static __init int -sim710_mca_probe(struct device *dev) -{ - struct mca_device *mca_dev = to_mca_device(dev); - int slot = mca_dev->slot; - int pos[3]; - unsigned int base; - int irq_vector; - short id = sim710_mca_id_table[mca_dev->index]; - static int io_004f_by_pos[] = MCA_004F_IO_PORTS; - static int irq_004f_by_pos[] = MCA_004F_IRQS; - static int io_01bb_by_pos[] = MCA_01BB_IO_PORTS; - static int irq_01bb_by_pos[] = MCA_01BB_IRQS; - char *name; - int clock; - - pos[0] = mca_device_read_stored_pos(mca_dev, 2); - pos[1] = mca_device_read_stored_pos(mca_dev, 3); - pos[2] = mca_device_read_stored_pos(mca_dev, 4); - - /* - * 01BB & 01BA port base by bits 7,6,5,4,3,2 in pos[2] - * - * 000000 001010 0x2800 - * 000001 001011 0x2C00 - * 000010 0x0800 001100 0x3000 - * 000011 0x0C00 001101 0x3400 - * 000100 0x1000 001110 0x3800 - * 000101 0x1400 001111 0x3C00 - * 000110 0x1800 010000 0x4000 - * 000111 0x1C00 010001 0x4400 - * 001000 0x2000 010010 0x4800 - * 001001 0x2400 010011 0x4C00 - * 010100 0x5000 - * - * 00F4 port base by bits 3,2,1 in pos[0] - * - * 000 001 0x200 - * 010 0x300 011 0x400 - * 100 0x500 101 0x600 - * - * 01BB & 01BA IRQ is specified in pos[0] bits 7 and 6: - * - * 00 3 10 11 - * 01 5 11 14 - * - * 00F4 IRQ specified by bits 6,5,4 in pos[0] - * - * 100 5 101 9 - * 110 14 - */ - - if (id == 0x01bb || id == 0x01ba) { - base = io_01bb_by_pos[(pos[2] & 0xFC) >> 2]; - irq_vector = - irq_01bb_by_pos[((pos[0] & 0xC0) >> 6)]; - - clock = 50; - if (id == 0x01bb) - name = "NCR 3360/3430 SCSI SubSystem"; - else - name = "NCR Dual SIOP SCSI Host Adapter Board"; - } else if ( id == 0x004f ) { - base = io_004f_by_pos[((pos[0] & 0x0E) >> 1)]; - irq_vector = - irq_004f_by_pos[((pos[0] & 0x70) >> 4) - 4]; - clock = 50; - name = "NCR 53c710 SCSI Host Adapter Board"; - } else { - return -ENODEV; - } - mca_device_set_name(mca_dev, name); - mca_device_set_claim(mca_dev, 1); - base = mca_device_transform_ioport(mca_dev, base); - irq_vector = mca_device_transform_irq(mca_dev, irq_vector); - - return sim710_probe_common(dev, base, irq_vector, clock, - 0, id_array[slot]); -} - -static struct mca_driver sim710_mca_driver = { - .id_table = sim710_mca_id_table, - .driver = { - .name = "sim710", - .bus = &mca_bus_type, - .probe = sim710_mca_probe, - .remove = __devexit_p(sim710_device_remove), - }, -}; - -#endif /* CONFIG_MCA */ - -#ifdef CONFIG_EISA -static struct eisa_device_id sim710_eisa_ids[] = { - { "CPQ4410" }, - { "CPQ4411" }, - { "HWP0C80" }, - { "" } -}; -MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids); - -static __init int -sim710_eisa_probe(struct device *dev) -{ - struct eisa_device *edev = to_eisa_device(dev); - unsigned long io_addr = edev->base_addr; - char eisa_cpq_irqs[] = { 11, 14, 15, 10, 9, 0 }; - char eisa_hwp_irqs[] = { 3, 4, 5, 7, 12, 10, 11, 0}; - char *eisa_irqs; - unsigned char irq_index; - unsigned char irq, differential = 0, scsi_id = 7; - - if(strcmp(edev->id.sig, "HWP0C80") == 0) { - __u8 val; - eisa_irqs = eisa_hwp_irqs; - irq_index = (inb(io_addr + 0xc85) & 0x7) - 1; - - val = inb(io_addr + 0x4); - scsi_id = ffs(val) - 1; - - if(scsi_id > 7 || (val & ~(1<= strlen(eisa_irqs)) { - printk("sim710.c: irq nasty\n"); - return -ENODEV; - } - - irq = eisa_irqs[irq_index]; - - return sim710_probe_common(dev, io_addr, irq, 50, - differential, scsi_id); -} - -static struct eisa_driver sim710_eisa_driver = { - .id_table = sim710_eisa_ids, - .driver = { - .name = "sim710", - .probe = sim710_eisa_probe, - .remove = __devexit_p(sim710_device_remove), - }, -}; -#endif /* CONFIG_EISA */ - -static int __init sim710_init(void) -{ - int err = -ENODEV; - -#ifdef MODULE - if (sim710) - param_setup(sim710); -#endif - -#ifdef CONFIG_MCA - err = mca_register_driver(&sim710_mca_driver); -#endif - -#ifdef CONFIG_EISA - err = eisa_driver_register(&sim710_eisa_driver); -#endif - /* FIXME: what we'd really like to return here is -ENODEV if - * no devices have actually been found. Instead, the err - * above actually only reports problems with kobject_register, - * so for the moment return success */ - - return 0; -} - -static void __exit sim710_exit(void) -{ -#ifdef CONFIG_MCA - if (MCA_bus) - mca_unregister_driver(&sim710_mca_driver); -#endif - -#ifdef CONFIG_EISA - eisa_driver_unregister(&sim710_eisa_driver); -#endif -} - -module_init(sim710_init); -module_exit(sim710_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/sni_53c710.c b/ANDROID_3.4.5/drivers/scsi/sni_53c710.c deleted file mode 100644 index cf51432f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sni_53c710.c +++ /dev/null @@ -1,155 +0,0 @@ -/* -*- mode: c; c-basic-offset: 8 -*- */ - -/* SNI RM driver - * - * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com -**----------------------------------------------------------------------------- -** -** This program is free software; you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation; either version 2 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program; if not, write to the Free Software -** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -** -**----------------------------------------------------------------------------- - */ - -/* - * Based on lasi700.c - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "53c700.h" - -MODULE_AUTHOR("Thomas Bogendörfer"); -MODULE_DESCRIPTION("SNI RM 53c710 SCSI Driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:snirm_53c710"); - -#define SNIRM710_CLOCK 32 - -static struct scsi_host_template snirm710_template = { - .name = "SNI RM SCSI 53c710", - .proc_name = "snirm_53c710", - .this_id = 7, - .module = THIS_MODULE, -}; - -static int __devinit snirm710_probe(struct platform_device *dev) -{ - unsigned long base; - struct NCR_700_Host_Parameters *hostdata; - struct Scsi_Host *host; - struct resource *res; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - base = res->start; - hostdata = kzalloc(sizeof(*hostdata), GFP_KERNEL); - if (!hostdata) { - dev_printk(KERN_ERR, dev, "Failed to allocate host data\n"); - return -ENOMEM; - } - - hostdata->dev = &dev->dev; - dma_set_mask(&dev->dev, DMA_BIT_MASK(32)); - hostdata->base = ioremap_nocache(base, 0x100); - hostdata->differential = 0; - - hostdata->clock = SNIRM710_CLOCK; - hostdata->force_le_on_be = 1; - hostdata->chip710 = 1; - hostdata->burst_length = 4; - - host = NCR_700_detect(&snirm710_template, hostdata, &dev->dev); - if (!host) - goto out_kfree; - host->this_id = 7; - host->base = base; - host->irq = platform_get_irq(dev, 0); - if(request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "snirm710", host)) { - printk(KERN_ERR "snirm710: request_irq failed!\n"); - goto out_put_host; - } - - dev_set_drvdata(&dev->dev, host); - scsi_scan_host(host); - - return 0; - - out_put_host: - scsi_host_put(host); - out_kfree: - iounmap(hostdata->base); - kfree(hostdata); - return -ENODEV; -} - -static int __exit snirm710_driver_remove(struct platform_device *dev) -{ - struct Scsi_Host *host = dev_get_drvdata(&dev->dev); - struct NCR_700_Host_Parameters *hostdata = - (struct NCR_700_Host_Parameters *)host->hostdata[0]; - - scsi_remove_host(host); - NCR_700_release(host); - free_irq(host->irq, host); - iounmap(hostdata->base); - kfree(hostdata); - - return 0; -} - -static struct platform_driver snirm710_driver = { - .probe = snirm710_probe, - .remove = __devexit_p(snirm710_driver_remove), - .driver = { - .name = "snirm_53c710", - .owner = THIS_MODULE, - }, -}; - -static int __init snirm710_init(void) -{ - return platform_driver_register(&snirm710_driver); -} - -static void __exit snirm710_exit(void) -{ - platform_driver_unregister(&snirm710_driver); -} - -module_init(snirm710_init); -module_exit(snirm710_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/sr.c b/ANDROID_3.4.5/drivers/scsi/sr.c deleted file mode 100644 index 5fc97d2b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sr.c +++ /dev/null @@ -1,1000 +0,0 @@ -/* - * sr.c Copyright (C) 1992 David Giller - * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale - * - * adapted from: - * sd.c Copyright (C) 1992 Drew Eckhardt - * Linux scsi disk driver by - * Drew Eckhardt - * - * Modified by Eric Youngdale ericy@andante.org to - * add scatter-gather, multiple outstanding request, and other - * enhancements. - * - * Modified by Eric Youngdale eric@andante.org to support loadable - * low-level scsi drivers. - * - * Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to - * provide auto-eject. - * - * Modified by Gerd Knorr to support the - * generic cdrom interface - * - * Modified by Jens Axboe - Uniform sr_packet() - * interface, capabilities probe additions, ioctl cleanups, etc. - * - * Modified by Richard Gooch to support devfs - * - * Modified by Jens Axboe - support DVD-RAM - * transparently and lose the GHOST hack - * - * Modified by Arnaldo Carvalho de Melo - * check resource allocation in sr_init and some cleanups - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include /* For the door lock/unlock commands */ - -#include "scsi_logging.h" -#include "sr.h" - - -MODULE_DESCRIPTION("SCSI cdrom (sr) driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_ROM); -MODULE_ALIAS_SCSI_DEVICE(TYPE_WORM); - -#define SR_DISKS 256 - -#define SR_CAPABILITIES \ - (CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \ - CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \ - CDC_PLAY_AUDIO|CDC_RESET|CDC_DRIVE_STATUS| \ - CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \ - CDC_MRW|CDC_MRW_W|CDC_RAM) - -static DEFINE_MUTEX(sr_mutex); -static int sr_probe(struct device *); -static int sr_remove(struct device *); -static int sr_done(struct scsi_cmnd *); - -static struct scsi_driver sr_template = { - .owner = THIS_MODULE, - .gendrv = { - .name = "sr", - .probe = sr_probe, - .remove = sr_remove, - }, - .done = sr_done, -}; - -static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG]; -static DEFINE_SPINLOCK(sr_index_lock); - -/* This semaphore is used to mediate the 0->1 reference get in the - * face of object destruction (i.e. we can't allow a get on an - * object after last put) */ -static DEFINE_MUTEX(sr_ref_mutex); - -static int sr_open(struct cdrom_device_info *, int); -static void sr_release(struct cdrom_device_info *); - -static void get_sectorsize(struct scsi_cd *); -static void get_capabilities(struct scsi_cd *); - -static unsigned int sr_check_events(struct cdrom_device_info *cdi, - unsigned int clearing, int slot); -static int sr_packet(struct cdrom_device_info *, struct packet_command *); - -static struct cdrom_device_ops sr_dops = { - .open = sr_open, - .release = sr_release, - .drive_status = sr_drive_status, - .check_events = sr_check_events, - .tray_move = sr_tray_move, - .lock_door = sr_lock_door, - .select_speed = sr_select_speed, - .get_last_session = sr_get_last_session, - .get_mcn = sr_get_mcn, - .reset = sr_reset, - .audio_ioctl = sr_audio_ioctl, - .capability = SR_CAPABILITIES, - .generic_packet = sr_packet, -}; - -static void sr_kref_release(struct kref *kref); - -static inline struct scsi_cd *scsi_cd(struct gendisk *disk) -{ - return container_of(disk->private_data, struct scsi_cd, driver); -} - -/* - * The get and put routines for the struct scsi_cd. Note this entity - * has a scsi_device pointer and owns a reference to this. - */ -static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk) -{ - struct scsi_cd *cd = NULL; - - mutex_lock(&sr_ref_mutex); - if (disk->private_data == NULL) - goto out; - cd = scsi_cd(disk); - kref_get(&cd->kref); - if (scsi_device_get(cd->device)) - goto out_put; - goto out; - - out_put: - kref_put(&cd->kref, sr_kref_release); - cd = NULL; - out: - mutex_unlock(&sr_ref_mutex); - return cd; -} - -static void scsi_cd_put(struct scsi_cd *cd) -{ - struct scsi_device *sdev = cd->device; - - mutex_lock(&sr_ref_mutex); - kref_put(&cd->kref, sr_kref_release); - scsi_device_put(sdev); - mutex_unlock(&sr_ref_mutex); -} - -static unsigned int sr_get_events(struct scsi_device *sdev) -{ - u8 buf[8]; - u8 cmd[] = { GET_EVENT_STATUS_NOTIFICATION, - 1, /* polled */ - 0, 0, /* reserved */ - 1 << 4, /* notification class: media */ - 0, 0, /* reserved */ - 0, sizeof(buf), /* allocation length */ - 0, /* control */ - }; - struct event_header *eh = (void *)buf; - struct media_event_desc *med = (void *)(buf + 4); - struct scsi_sense_hdr sshdr; - int result; - - result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buf, sizeof(buf), - &sshdr, SR_TIMEOUT, MAX_RETRIES, NULL); - if (scsi_sense_valid(&sshdr) && sshdr.sense_key == UNIT_ATTENTION) - return DISK_EVENT_MEDIA_CHANGE; - - if (result || be16_to_cpu(eh->data_len) < sizeof(*med)) - return 0; - - if (eh->nea || eh->notification_class != 0x4) - return 0; - - if (med->media_event_code == 1) - return DISK_EVENT_EJECT_REQUEST; - else if (med->media_event_code == 2) - return DISK_EVENT_MEDIA_CHANGE; - return 0; -} - -/* - * This function checks to see if the media has been changed or eject - * button has been pressed. It is possible that we have already - * sensed a change, or the drive may have sensed one and not yet - * reported it. The past events are accumulated in sdev->changed and - * returned together with the current state. - */ -static unsigned int sr_check_events(struct cdrom_device_info *cdi, - unsigned int clearing, int slot) -{ - struct scsi_cd *cd = cdi->handle; - bool last_present; - struct scsi_sense_hdr sshdr; - unsigned int events; - int ret; - - /* no changer support */ - if (CDSL_CURRENT != slot) - return 0; - - events = sr_get_events(cd->device); - cd->get_event_changed |= events & DISK_EVENT_MEDIA_CHANGE; - - /* - * If earlier GET_EVENT_STATUS_NOTIFICATION and TUR did not agree - * for several times in a row. We rely on TUR only for this likely - * broken device, to prevent generating incorrect media changed - * events for every open(). - */ - if (cd->ignore_get_event) { - events &= ~DISK_EVENT_MEDIA_CHANGE; - goto do_tur; - } - - /* - * GET_EVENT_STATUS_NOTIFICATION is enough unless MEDIA_CHANGE - * is being cleared. Note that there are devices which hang - * if asked to execute TUR repeatedly. - */ - if (cd->device->changed) { - events |= DISK_EVENT_MEDIA_CHANGE; - cd->device->changed = 0; - cd->tur_changed = true; - } - - if (!(clearing & DISK_EVENT_MEDIA_CHANGE)) - return events; -do_tur: - /* let's see whether the media is there with TUR */ - last_present = cd->media_present; - ret = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); - - /* - * Media is considered to be present if TUR succeeds or fails with - * sense data indicating something other than media-not-present - * (ASC 0x3a). - */ - cd->media_present = scsi_status_is_good(ret) || - (scsi_sense_valid(&sshdr) && sshdr.asc != 0x3a); - - if (last_present != cd->media_present) - cd->device->changed = 1; - - if (cd->device->changed) { - events |= DISK_EVENT_MEDIA_CHANGE; - cd->device->changed = 0; - cd->tur_changed = true; - } - - if (cd->ignore_get_event) - return events; - - /* check whether GET_EVENT is reporting spurious MEDIA_CHANGE */ - if (!cd->tur_changed) { - if (cd->get_event_changed) { - if (cd->tur_mismatch++ > 8) { - sdev_printk(KERN_WARNING, cd->device, - "GET_EVENT and TUR disagree continuously, suppress GET_EVENT events\n"); - cd->ignore_get_event = true; - } - } else { - cd->tur_mismatch = 0; - } - } - cd->tur_changed = false; - cd->get_event_changed = false; - - return events; -} - -/* - * sr_done is the interrupt routine for the device driver. - * - * It will be notified on the end of a SCSI read / write, and will take one - * of several actions based on success or failure. - */ -static int sr_done(struct scsi_cmnd *SCpnt) -{ - int result = SCpnt->result; - int this_count = scsi_bufflen(SCpnt); - int good_bytes = (result == 0 ? this_count : 0); - int block_sectors = 0; - long error_sector; - struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk); - -#ifdef DEBUG - printk("sr.c done: %x\n", result); -#endif - - /* - * Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial - * success. Since this is a relatively rare error condition, no - * care is taken to avoid unnecessary additional work such as - * memcpy's that could be avoided. - */ - if (driver_byte(result) != 0 && /* An error occurred */ - (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */ - switch (SCpnt->sense_buffer[2]) { - case MEDIUM_ERROR: - case VOLUME_OVERFLOW: - case ILLEGAL_REQUEST: - if (!(SCpnt->sense_buffer[0] & 0x90)) - break; - error_sector = (SCpnt->sense_buffer[3] << 24) | - (SCpnt->sense_buffer[4] << 16) | - (SCpnt->sense_buffer[5] << 8) | - SCpnt->sense_buffer[6]; - if (SCpnt->request->bio != NULL) - block_sectors = - bio_sectors(SCpnt->request->bio); - if (block_sectors < 4) - block_sectors = 4; - if (cd->device->sector_size == 2048) - error_sector <<= 2; - error_sector &= ~(block_sectors - 1); - good_bytes = (error_sector - - blk_rq_pos(SCpnt->request)) << 9; - if (good_bytes < 0 || good_bytes >= this_count) - good_bytes = 0; - /* - * The SCSI specification allows for the value - * returned by READ CAPACITY to be up to 75 2K - * sectors past the last readable block. - * Therefore, if we hit a medium error within the - * last 75 2K sectors, we decrease the saved size - * value. - */ - if (error_sector < get_capacity(cd->disk) && - cd->capacity - error_sector < 4 * 75) - set_capacity(cd->disk, error_sector); - break; - - case RECOVERED_ERROR: - good_bytes = this_count; - break; - - default: - break; - } - } - - return good_bytes; -} - -static int sr_prep_fn(struct request_queue *q, struct request *rq) -{ - int block = 0, this_count, s_size; - struct scsi_cd *cd; - struct scsi_cmnd *SCpnt; - struct scsi_device *sdp = q->queuedata; - int ret; - - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - ret = scsi_setup_blk_pc_cmnd(sdp, rq); - goto out; - } else if (rq->cmd_type != REQ_TYPE_FS) { - ret = BLKPREP_KILL; - goto out; - } - ret = scsi_setup_fs_cmnd(sdp, rq); - if (ret != BLKPREP_OK) - goto out; - SCpnt = rq->special; - cd = scsi_cd(rq->rq_disk); - - /* from here on until we're complete, any goto out - * is used for a killable error condition */ - ret = BLKPREP_KILL; - - SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n", - cd->disk->disk_name, block)); - - if (!cd->device || !scsi_device_online(cd->device)) { - SCSI_LOG_HLQUEUE(2, printk("Finishing %u sectors\n", - blk_rq_sectors(rq))); - SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt)); - goto out; - } - - if (cd->device->changed) { - /* - * quietly refuse to do anything to a changed disc until the - * changed bit has been reset - */ - goto out; - } - - /* - * we do lazy blocksize switching (when reading XA sectors, - * see CDROMREADMODE2 ioctl) - */ - s_size = cd->device->sector_size; - if (s_size > 2048) { - if (!in_interrupt()) - sr_set_blocklength(cd, 2048); - else - printk("sr: can't switch blocksize: in interrupt\n"); - } - - if (s_size != 512 && s_size != 1024 && s_size != 2048) { - scmd_printk(KERN_ERR, SCpnt, "bad sector size %d\n", s_size); - goto out; - } - - if (rq_data_dir(rq) == WRITE) { - if (!cd->device->writeable) - goto out; - SCpnt->cmnd[0] = WRITE_10; - SCpnt->sc_data_direction = DMA_TO_DEVICE; - cd->cdi.media_written = 1; - } else if (rq_data_dir(rq) == READ) { - SCpnt->cmnd[0] = READ_10; - SCpnt->sc_data_direction = DMA_FROM_DEVICE; - } else { - blk_dump_rq_flags(rq, "Unknown sr command"); - goto out; - } - - { - struct scatterlist *sg; - int i, size = 0, sg_count = scsi_sg_count(SCpnt); - - scsi_for_each_sg(SCpnt, sg, sg_count, i) - size += sg->length; - - if (size != scsi_bufflen(SCpnt)) { - scmd_printk(KERN_ERR, SCpnt, - "mismatch count %d, bytes %d\n", - size, scsi_bufflen(SCpnt)); - if (scsi_bufflen(SCpnt) > size) - SCpnt->sdb.length = size; - } - } - - /* - * request doesn't start on hw block boundary, add scatter pads - */ - if (((unsigned int)blk_rq_pos(rq) % (s_size >> 9)) || - (scsi_bufflen(SCpnt) % s_size)) { - scmd_printk(KERN_NOTICE, SCpnt, "unaligned transfer\n"); - goto out; - } - - this_count = (scsi_bufflen(SCpnt) >> 9) / (s_size >> 9); - - - SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%u 512 byte blocks.\n", - cd->cdi.name, - (rq_data_dir(rq) == WRITE) ? - "writing" : "reading", - this_count, blk_rq_sectors(rq))); - - SCpnt->cmnd[1] = 0; - block = (unsigned int)blk_rq_pos(rq) / (s_size >> 9); - - if (this_count > 0xffff) { - this_count = 0xffff; - SCpnt->sdb.length = this_count * s_size; - } - - SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; - SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; - SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; - SCpnt->cmnd[5] = (unsigned char) block & 0xff; - SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0; - SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff; - SCpnt->cmnd[8] = (unsigned char) this_count & 0xff; - - /* - * We shouldn't disconnect in the middle of a sector, so with a dumb - * host adapter, it's safe to assume that we can at least transfer - * this many bytes between each connect / disconnect. - */ - SCpnt->transfersize = cd->device->sector_size; - SCpnt->underflow = this_count << 9; - SCpnt->allowed = MAX_RETRIES; - - /* - * This indicates that the command is ready from our end to be - * queued. - */ - ret = BLKPREP_OK; - out: - return scsi_prep_return(q, rq, ret); -} - -static int sr_block_open(struct block_device *bdev, fmode_t mode) -{ - struct scsi_cd *cd; - int ret = -ENXIO; - - mutex_lock(&sr_mutex); - cd = scsi_cd_get(bdev->bd_disk); - if (cd) { - ret = cdrom_open(&cd->cdi, bdev, mode); - if (ret) - scsi_cd_put(cd); - } - mutex_unlock(&sr_mutex); - return ret; -} - -static int sr_block_release(struct gendisk *disk, fmode_t mode) -{ - struct scsi_cd *cd = scsi_cd(disk); - mutex_lock(&sr_mutex); - cdrom_release(&cd->cdi, mode); - scsi_cd_put(cd); - mutex_unlock(&sr_mutex); - return 0; -} - -static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, - unsigned long arg) -{ - struct scsi_cd *cd = scsi_cd(bdev->bd_disk); - struct scsi_device *sdev = cd->device; - void __user *argp = (void __user *)arg; - int ret; - - mutex_lock(&sr_mutex); - - /* - * Send SCSI addressing ioctls directly to mid level, send other - * ioctls to cdrom/block level. - */ - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - ret = scsi_ioctl(sdev, cmd, argp); - goto out; - } - - ret = cdrom_ioctl(&cd->cdi, bdev, mode, cmd, arg); - if (ret != -ENOSYS) - goto out; - - /* - * ENODEV means that we didn't recognise the ioctl, or that we - * cannot execute it in the current device state. In either - * case fall through to scsi_ioctl, which will return ENDOEV again - * if it doesn't recognise the ioctl - */ - ret = scsi_nonblockable_ioctl(sdev, cmd, argp, - (mode & FMODE_NDELAY) != 0); - if (ret != -ENODEV) - goto out; - ret = scsi_ioctl(sdev, cmd, argp); - -out: - mutex_unlock(&sr_mutex); - return ret; -} - -static unsigned int sr_block_check_events(struct gendisk *disk, - unsigned int clearing) -{ - struct scsi_cd *cd = scsi_cd(disk); - return cdrom_check_events(&cd->cdi, clearing); -} - -static int sr_block_revalidate_disk(struct gendisk *disk) -{ - struct scsi_cd *cd = scsi_cd(disk); - struct scsi_sense_hdr sshdr; - - /* if the unit is not ready, nothing more to do */ - if (scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) - return 0; - - sr_cd_check(&cd->cdi); - get_sectorsize(cd); - return 0; -} - -static const struct block_device_operations sr_bdops = -{ - .owner = THIS_MODULE, - .open = sr_block_open, - .release = sr_block_release, - .ioctl = sr_block_ioctl, - .check_events = sr_block_check_events, - .revalidate_disk = sr_block_revalidate_disk, - /* - * No compat_ioctl for now because sr_block_ioctl never - * seems to pass arbitrary ioctls down to host drivers. - */ -}; - -static int sr_open(struct cdrom_device_info *cdi, int purpose) -{ - struct scsi_cd *cd = cdi->handle; - struct scsi_device *sdev = cd->device; - int retval; - - /* - * If the device is in error recovery, wait until it is done. - * If the device is offline, then disallow any access to it. - */ - retval = -ENXIO; - if (!scsi_block_when_processing_errors(sdev)) - goto error_out; - - return 0; - -error_out: - return retval; -} - -static void sr_release(struct cdrom_device_info *cdi) -{ - struct scsi_cd *cd = cdi->handle; - - if (cd->device->sector_size > 2048) - sr_set_blocklength(cd, 2048); - -} - -static int sr_probe(struct device *dev) -{ - struct scsi_device *sdev = to_scsi_device(dev); - struct gendisk *disk; - struct scsi_cd *cd; - int minor, error; - - error = -ENODEV; - if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM) - goto fail; - - error = -ENOMEM; - cd = kzalloc(sizeof(*cd), GFP_KERNEL); - if (!cd) - goto fail; - - kref_init(&cd->kref); - - disk = alloc_disk(1); - if (!disk) - goto fail_free; - - spin_lock(&sr_index_lock); - minor = find_first_zero_bit(sr_index_bits, SR_DISKS); - if (minor == SR_DISKS) { - spin_unlock(&sr_index_lock); - error = -EBUSY; - goto fail_put; - } - __set_bit(minor, sr_index_bits); - spin_unlock(&sr_index_lock); - - disk->major = SCSI_CDROM_MAJOR; - disk->first_minor = minor; - sprintf(disk->disk_name, "sr%d", minor); - disk->fops = &sr_bdops; - disk->flags = GENHD_FL_CD | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE; - disk->events = DISK_EVENT_MEDIA_CHANGE | DISK_EVENT_EJECT_REQUEST; - - blk_queue_rq_timeout(sdev->request_queue, SR_TIMEOUT); - - cd->device = sdev; - cd->disk = disk; - cd->driver = &sr_template; - cd->disk = disk; - cd->capacity = 0x1fffff; - cd->device->changed = 1; /* force recheck CD type */ - cd->media_present = 1; - cd->use = 1; - cd->readcd_known = 0; - cd->readcd_cdda = 0; - - cd->cdi.ops = &sr_dops; - cd->cdi.handle = cd; - cd->cdi.mask = 0; - cd->cdi.capacity = 1; - sprintf(cd->cdi.name, "sr%d", minor); - - sdev->sector_size = 2048; /* A guess, just in case */ - - /* FIXME: need to handle a get_capabilities failure properly ?? */ - get_capabilities(cd); - blk_queue_prep_rq(sdev->request_queue, sr_prep_fn); - sr_vendor_init(cd); - - disk->driverfs_dev = &sdev->sdev_gendev; - set_capacity(disk, cd->capacity); - disk->private_data = &cd->driver; - disk->queue = sdev->request_queue; - cd->cdi.disk = disk; - - if (register_cdrom(&cd->cdi)) - goto fail_put; - - dev_set_drvdata(dev, cd); - disk->flags |= GENHD_FL_REMOVABLE; - add_disk(disk); - - sdev_printk(KERN_DEBUG, sdev, - "Attached scsi CD-ROM %s\n", cd->cdi.name); - return 0; - -fail_put: - put_disk(disk); -fail_free: - kfree(cd); -fail: - return error; -} - - -static void get_sectorsize(struct scsi_cd *cd) -{ - unsigned char cmd[10]; - unsigned char buffer[8]; - int the_result, retries = 3; - int sector_size; - struct request_queue *queue; - - do { - cmd[0] = READ_CAPACITY; - memset((void *) &cmd[1], 0, 9); - memset(buffer, 0, sizeof(buffer)); - - /* Do the command and wait.. */ - the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE, - buffer, sizeof(buffer), NULL, - SR_TIMEOUT, MAX_RETRIES, NULL); - - retries--; - - } while (the_result && retries); - - - if (the_result) { - cd->capacity = 0x1fffff; - sector_size = 2048; /* A guess, just in case */ - } else { - long last_written; - - cd->capacity = 1 + ((buffer[0] << 24) | (buffer[1] << 16) | - (buffer[2] << 8) | buffer[3]); - /* - * READ_CAPACITY doesn't return the correct size on - * certain UDF media. If last_written is larger, use - * it instead. - * - * http://bugzilla.kernel.org/show_bug.cgi?id=9668 - */ - if (!cdrom_get_last_written(&cd->cdi, &last_written)) - cd->capacity = max_t(long, cd->capacity, last_written); - - sector_size = (buffer[4] << 24) | - (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; - switch (sector_size) { - /* - * HP 4020i CD-Recorder reports 2340 byte sectors - * Philips CD-Writers report 2352 byte sectors - * - * Use 2k sectors for them.. - */ - case 0: - case 2340: - case 2352: - sector_size = 2048; - /* fall through */ - case 2048: - cd->capacity *= 4; - /* fall through */ - case 512: - break; - default: - printk("%s: unsupported sector size %d.\n", - cd->cdi.name, sector_size); - cd->capacity = 0; - } - - cd->device->sector_size = sector_size; - - /* - * Add this so that we have the ability to correctly gauge - * what the device is capable of. - */ - set_capacity(cd->disk, cd->capacity); - } - - queue = cd->device->request_queue; - blk_queue_logical_block_size(queue, sector_size); - - return; -} - -static void get_capabilities(struct scsi_cd *cd) -{ - unsigned char *buffer; - struct scsi_mode_data data; - struct scsi_sense_hdr sshdr; - int rc, n; - - static const char *loadmech[] = - { - "caddy", - "tray", - "pop-up", - "", - "changer", - "cartridge changer", - "", - "" - }; - - - /* allocate transfer buffer */ - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); - if (!buffer) { - printk(KERN_ERR "sr: out of memory.\n"); - return; - } - - /* eat unit attentions */ - scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr); - - /* ask for mode page 0x2a */ - rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, - SR_TIMEOUT, 3, &data, NULL); - - if (!scsi_status_is_good(rc)) { - /* failed, drive doesn't have capabilities mode page */ - cd->cdi.speed = 1; - cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R | - CDC_DVD | CDC_DVD_RAM | - CDC_SELECT_DISC | CDC_SELECT_SPEED | - CDC_MRW | CDC_MRW_W | CDC_RAM); - kfree(buffer); - printk("%s: scsi-1 drive\n", cd->cdi.name); - return; - } - - n = data.header_length + data.block_descriptor_length; - cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176; - cd->readcd_known = 1; - cd->readcd_cdda = buffer[n + 5] & 0x01; - /* print some capability bits */ - printk("%s: scsi3-mmc drive: %dx/%dx %s%s%s%s%s%s\n", cd->cdi.name, - ((buffer[n + 14] << 8) + buffer[n + 15]) / 176, - cd->cdi.speed, - buffer[n + 3] & 0x01 ? "writer " : "", /* CD Writer */ - buffer[n + 3] & 0x20 ? "dvd-ram " : "", - buffer[n + 2] & 0x02 ? "cd/rw " : "", /* can read rewriteable */ - buffer[n + 4] & 0x20 ? "xa/form2 " : "", /* can read xa/from2 */ - buffer[n + 5] & 0x01 ? "cdda " : "", /* can read audio data */ - loadmech[buffer[n + 6] >> 5]); - if ((buffer[n + 6] >> 5) == 0) - /* caddy drives can't close tray... */ - cd->cdi.mask |= CDC_CLOSE_TRAY; - if ((buffer[n + 2] & 0x8) == 0) - /* not a DVD drive */ - cd->cdi.mask |= CDC_DVD; - if ((buffer[n + 3] & 0x20) == 0) - /* can't write DVD-RAM media */ - cd->cdi.mask |= CDC_DVD_RAM; - if ((buffer[n + 3] & 0x10) == 0) - /* can't write DVD-R media */ - cd->cdi.mask |= CDC_DVD_R; - if ((buffer[n + 3] & 0x2) == 0) - /* can't write CD-RW media */ - cd->cdi.mask |= CDC_CD_RW; - if ((buffer[n + 3] & 0x1) == 0) - /* can't write CD-R media */ - cd->cdi.mask |= CDC_CD_R; - if ((buffer[n + 6] & 0x8) == 0) - /* can't eject */ - cd->cdi.mask |= CDC_OPEN_TRAY; - - if ((buffer[n + 6] >> 5) == mechtype_individual_changer || - (buffer[n + 6] >> 5) == mechtype_cartridge_changer) - cd->cdi.capacity = - cdrom_number_of_slots(&cd->cdi); - if (cd->cdi.capacity <= 1) - /* not a changer */ - cd->cdi.mask |= CDC_SELECT_DISC; - /*else I don't think it can close its tray - cd->cdi.mask |= CDC_CLOSE_TRAY; */ - - /* - * if DVD-RAM, MRW-W or CD-RW, we are randomly writable - */ - if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) != - (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) { - cd->device->writeable = 1; - } - - kfree(buffer); -} - -/* - * sr_packet() is the entry point for the generic commands generated - * by the Uniform CD-ROM layer. - */ -static int sr_packet(struct cdrom_device_info *cdi, - struct packet_command *cgc) -{ - struct scsi_cd *cd = cdi->handle; - struct scsi_device *sdev = cd->device; - - if (cgc->cmd[0] == GPCMD_READ_DISC_INFO && sdev->no_read_disc_info) - return -EDRIVE_CANT_DO_THIS; - - if (cgc->timeout <= 0) - cgc->timeout = IOCTL_TIMEOUT; - - sr_do_ioctl(cd, cgc); - - return cgc->stat; -} - -/** - * sr_kref_release - Called to free the scsi_cd structure - * @kref: pointer to embedded kref - * - * sr_ref_mutex must be held entering this routine. Because it is - * called on last put, you should always use the scsi_cd_get() - * scsi_cd_put() helpers which manipulate the semaphore directly - * and never do a direct kref_put(). - **/ -static void sr_kref_release(struct kref *kref) -{ - struct scsi_cd *cd = container_of(kref, struct scsi_cd, kref); - struct gendisk *disk = cd->disk; - - spin_lock(&sr_index_lock); - clear_bit(MINOR(disk_devt(disk)), sr_index_bits); - spin_unlock(&sr_index_lock); - - unregister_cdrom(&cd->cdi); - - disk->private_data = NULL; - - put_disk(disk); - - kfree(cd); -} - -static int sr_remove(struct device *dev) -{ - struct scsi_cd *cd = dev_get_drvdata(dev); - - blk_queue_prep_rq(cd->device->request_queue, scsi_prep_fn); - del_gendisk(cd->disk); - - mutex_lock(&sr_ref_mutex); - kref_put(&cd->kref, sr_kref_release); - mutex_unlock(&sr_ref_mutex); - - return 0; -} - -static int __init init_sr(void) -{ - int rc; - - rc = register_blkdev(SCSI_CDROM_MAJOR, "sr"); - if (rc) - return rc; - rc = scsi_register_driver(&sr_template.gendrv); - if (rc) - unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); - - return rc; -} - -static void __exit exit_sr(void) -{ - scsi_unregister_driver(&sr_template.gendrv); - unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); -} - -module_init(init_sr); -module_exit(exit_sr); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/sr.h b/ANDROID_3.4.5/drivers/scsi/sr.h deleted file mode 100644 index 37c8f6b1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sr.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * sr.h by David Giller - * CD-ROM disk driver header file - * - * adapted from: - * sd.h Copyright (C) 1992 Drew Eckhardt - * SCSI disk driver header file by - * Drew Eckhardt - * - * - * - * Modified by Eric Youngdale eric@andante.org to - * add scatter-gather, multiple outstanding request, and other - * enhancements. - */ - -#ifndef _SR_H -#define _SR_H - -#include -#include - -#define MAX_RETRIES 3 -#define SR_TIMEOUT (30 * HZ) - -struct scsi_device; - -/* The CDROM is fairly slow, so we need a little extra time */ -/* In fact, it is very slow if it has to spin up first */ -#define IOCTL_TIMEOUT 30*HZ - - -typedef struct scsi_cd { - struct scsi_driver *driver; - unsigned capacity; /* size in blocks */ - struct scsi_device *device; - unsigned int vendor; /* vendor code, see sr_vendor.c */ - unsigned long ms_offset; /* for reading multisession-CD's */ - unsigned use:1; /* is this device still supportable */ - unsigned xa_flag:1; /* CD has XA sectors ? */ - unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ - unsigned readcd_cdda:1; /* reading audio data using READ_CD */ - unsigned media_present:1; /* media is present */ - - /* GET_EVENT spurious event handling, blk layer guarantees exclusion */ - int tur_mismatch; /* nr of get_event TUR mismatches */ - bool tur_changed:1; /* changed according to TUR */ - bool get_event_changed:1; /* changed according to GET_EVENT */ - bool ignore_get_event:1; /* GET_EVENT is unreliable, use TUR */ - - struct cdrom_device_info cdi; - /* We hold gendisk and scsi_device references on probe and use - * the refs on this kref to decide when to release them */ - struct kref kref; - struct gendisk *disk; -} Scsi_CD; - -int sr_do_ioctl(Scsi_CD *, struct packet_command *); - -int sr_lock_door(struct cdrom_device_info *, int); -int sr_tray_move(struct cdrom_device_info *, int); -int sr_drive_status(struct cdrom_device_info *, int); -int sr_disk_status(struct cdrom_device_info *); -int sr_get_last_session(struct cdrom_device_info *, struct cdrom_multisession *); -int sr_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *); -int sr_reset(struct cdrom_device_info *); -int sr_select_speed(struct cdrom_device_info *cdi, int speed); -int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *); - -int sr_is_xa(Scsi_CD *); - -/* sr_vendor.c */ -void sr_vendor_init(Scsi_CD *); -int sr_cd_check(struct cdrom_device_info *); -int sr_set_blocklength(Scsi_CD *, int blocklength); - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/sr_ioctl.c b/ANDROID_3.4.5/drivers/scsi/sr_ioctl.c deleted file mode 100644 index a3911c39..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sr_ioctl.c +++ /dev/null @@ -1,598 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "sr.h" - -#if 0 -#define DEBUG -#endif - -/* The sr_is_xa() seems to trigger firmware bugs with some drives :-( - * It is off by default and can be turned on with this module parameter */ -static int xa_test = 0; - -module_param(xa_test, int, S_IRUGO | S_IWUSR); - -/* primitive to determine whether we need to have GFP_DMA set based on - * the status of the unchecked_isa_dma flag in the host structure */ -#define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0) - - -static int sr_read_tochdr(struct cdrom_device_info *cdi, - struct cdrom_tochdr *tochdr) -{ - struct scsi_cd *cd = cdi->handle; - struct packet_command cgc; - int result; - unsigned char *buffer; - - buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd)); - if (!buffer) - return -ENOMEM; - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.timeout = IOCTL_TIMEOUT; - cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - cgc.cmd[8] = 12; /* LSB of length */ - cgc.buffer = buffer; - cgc.buflen = 12; - cgc.quiet = 1; - cgc.data_direction = DMA_FROM_DEVICE; - - result = sr_do_ioctl(cd, &cgc); - - tochdr->cdth_trk0 = buffer[2]; - tochdr->cdth_trk1 = buffer[3]; - - kfree(buffer); - return result; -} - -static int sr_read_tocentry(struct cdrom_device_info *cdi, - struct cdrom_tocentry *tocentry) -{ - struct scsi_cd *cd = cdi->handle; - struct packet_command cgc; - int result; - unsigned char *buffer; - - buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd)); - if (!buffer) - return -ENOMEM; - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.timeout = IOCTL_TIMEOUT; - cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP; - cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0; - cgc.cmd[6] = tocentry->cdte_track; - cgc.cmd[8] = 12; /* LSB of length */ - cgc.buffer = buffer; - cgc.buflen = 12; - cgc.data_direction = DMA_FROM_DEVICE; - - result = sr_do_ioctl(cd, &cgc); - - tocentry->cdte_ctrl = buffer[5] & 0xf; - tocentry->cdte_adr = buffer[5] >> 4; - tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0; - if (tocentry->cdte_format == CDROM_MSF) { - tocentry->cdte_addr.msf.minute = buffer[9]; - tocentry->cdte_addr.msf.second = buffer[10]; - tocentry->cdte_addr.msf.frame = buffer[11]; - } else - tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8) - + buffer[10]) << 8) + buffer[11]; - - kfree(buffer); - return result; -} - -#define IOCTL_RETRIES 3 - -/* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command. When these drives - are emulating a SCSI device via the idescsi module, they need to have - CDROMPLAYTRKIND commands translated into CDROMPLAYMSF commands for them */ - -static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti) -{ - struct cdrom_tocentry trk0_te, trk1_te; - struct cdrom_tochdr tochdr; - struct packet_command cgc; - int ntracks, ret; - - ret = sr_read_tochdr(cdi, &tochdr); - if (ret) - return ret; - - ntracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1; - - if (ti->cdti_trk1 == ntracks) - ti->cdti_trk1 = CDROM_LEADOUT; - else if (ti->cdti_trk1 != CDROM_LEADOUT) - ti->cdti_trk1 ++; - - trk0_te.cdte_track = ti->cdti_trk0; - trk0_te.cdte_format = CDROM_MSF; - trk1_te.cdte_track = ti->cdti_trk1; - trk1_te.cdte_format = CDROM_MSF; - - ret = sr_read_tocentry(cdi, &trk0_te); - if (ret) - return ret; - ret = sr_read_tocentry(cdi, &trk1_te); - if (ret) - return ret; - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF; - cgc.cmd[3] = trk0_te.cdte_addr.msf.minute; - cgc.cmd[4] = trk0_te.cdte_addr.msf.second; - cgc.cmd[5] = trk0_te.cdte_addr.msf.frame; - cgc.cmd[6] = trk1_te.cdte_addr.msf.minute; - cgc.cmd[7] = trk1_te.cdte_addr.msf.second; - cgc.cmd[8] = trk1_te.cdte_addr.msf.frame; - cgc.data_direction = DMA_NONE; - cgc.timeout = IOCTL_TIMEOUT; - return sr_do_ioctl(cdi->handle, &cgc); -} - -static int sr_play_trkind(struct cdrom_device_info *cdi, - struct cdrom_ti *ti) - -{ - struct scsi_cd *cd = cdi->handle; - struct packet_command cgc; - int result; - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.timeout = IOCTL_TIMEOUT; - cgc.cmd[0] = GPCMD_PLAYAUDIO_TI; - cgc.cmd[4] = ti->cdti_trk0; - cgc.cmd[5] = ti->cdti_ind0; - cgc.cmd[7] = ti->cdti_trk1; - cgc.cmd[8] = ti->cdti_ind1; - cgc.data_direction = DMA_NONE; - - result = sr_do_ioctl(cd, &cgc); - if (result == -EDRIVE_CANT_DO_THIS) - result = sr_fake_playtrkind(cdi, ti); - - return result; -} - -/* We do our own retries because we want to know what the specific - error code is. Normally the UNIT_ATTENTION code will automatically - clear after one error */ - -int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) -{ - struct scsi_device *SDev; - struct scsi_sense_hdr sshdr; - int result, err = 0, retries = 0; - struct request_sense *sense = cgc->sense; - - SDev = cd->device; - - if (!sense) { - sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); - if (!sense) { - err = -ENOMEM; - goto out; - } - } - - retry: - if (!scsi_block_when_processing_errors(SDev)) { - err = -ENODEV; - goto out; - } - - memset(sense, 0, sizeof(*sense)); - result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, - cgc->buffer, cgc->buflen, (char *)sense, - cgc->timeout, IOCTL_RETRIES, 0, NULL); - - scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr); - - /* Minimal error checking. Ignore cases we know about, and report the rest. */ - if (driver_byte(result) != 0) { - switch (sshdr.sense_key) { - case UNIT_ATTENTION: - SDev->changed = 1; - if (!cgc->quiet) - printk(KERN_INFO "%s: disc change detected.\n", cd->cdi.name); - if (retries++ < 10) - goto retry; - err = -ENOMEDIUM; - break; - case NOT_READY: /* This happens if there is no disc in drive */ - if (sshdr.asc == 0x04 && - sshdr.ascq == 0x01) { - /* sense: Logical unit is in process of becoming ready */ - if (!cgc->quiet) - printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name); - if (retries++ < 10) { - /* sleep 2 sec and try again */ - ssleep(2); - goto retry; - } else { - /* 20 secs are enough? */ - err = -ENOMEDIUM; - break; - } - } - if (!cgc->quiet) - printk(KERN_INFO "%s: CDROM not ready. Make sure there is a disc in the drive.\n", cd->cdi.name); -#ifdef DEBUG - scsi_print_sense_hdr("sr", &sshdr); -#endif - err = -ENOMEDIUM; - break; - case ILLEGAL_REQUEST: - err = -EIO; - if (sshdr.asc == 0x20 && - sshdr.ascq == 0x00) - /* sense: Invalid command operation code */ - err = -EDRIVE_CANT_DO_THIS; -#ifdef DEBUG - __scsi_print_command(cgc->cmd); - scsi_print_sense_hdr("sr", &sshdr); -#endif - break; - default: - printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name); - __scsi_print_command(cgc->cmd); - scsi_print_sense_hdr("sr", &sshdr); - err = -EIO; - } - } - - /* Wake up a process waiting for device */ - out: - if (!cgc->sense) - kfree(sense); - cgc->stat = err; - return err; -} - -/* ---------------------------------------------------------------------- */ -/* interface to cdrom.c */ - -int sr_tray_move(struct cdrom_device_info *cdi, int pos) -{ - Scsi_CD *cd = cdi->handle; - struct packet_command cgc; - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = GPCMD_START_STOP_UNIT; - cgc.cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ; - cgc.data_direction = DMA_NONE; - cgc.timeout = IOCTL_TIMEOUT; - return sr_do_ioctl(cd, &cgc); -} - -int sr_lock_door(struct cdrom_device_info *cdi, int lock) -{ - Scsi_CD *cd = cdi->handle; - - return scsi_set_medium_removal(cd->device, lock ? - SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW); -} - -int sr_drive_status(struct cdrom_device_info *cdi, int slot) -{ - struct scsi_cd *cd = cdi->handle; - struct scsi_sense_hdr sshdr; - struct media_event_desc med; - - if (CDSL_CURRENT != slot) { - /* we have no changer support */ - return -EINVAL; - } - if (!scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES, &sshdr)) - return CDS_DISC_OK; - - /* SK/ASC/ASCQ of 2/4/1 means "unit is becoming ready" */ - if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY - && sshdr.asc == 0x04 && sshdr.ascq == 0x01) - return CDS_DRIVE_NOT_READY; - - if (!cdrom_get_media_event(cdi, &med)) { - if (med.media_present) - return CDS_DISC_OK; - else if (med.door_open) - return CDS_TRAY_OPEN; - else - return CDS_NO_DISC; - } - - /* - * SK/ASC/ASCQ of 2/4/2 means "initialization required" - * Using CD_TRAY_OPEN results in an START_STOP_UNIT to close - * the tray, which resolves the initialization requirement. - */ - if (scsi_sense_valid(&sshdr) && sshdr.sense_key == NOT_READY - && sshdr.asc == 0x04 && sshdr.ascq == 0x02) - return CDS_TRAY_OPEN; - - /* - * 0x04 is format in progress .. but there must be a disc present! - */ - if (sshdr.sense_key == NOT_READY && sshdr.asc == 0x04) - return CDS_DISC_OK; - - /* - * If not using Mt Fuji extended media tray reports, - * just return TRAY_OPEN since ATAPI doesn't provide - * any other way to detect this... - */ - if (scsi_sense_valid(&sshdr) && - /* 0x3a is medium not present */ - sshdr.asc == 0x3a) - return CDS_NO_DISC; - else - return CDS_TRAY_OPEN; - - return CDS_DRIVE_NOT_READY; -} - -int sr_disk_status(struct cdrom_device_info *cdi) -{ - Scsi_CD *cd = cdi->handle; - struct cdrom_tochdr toc_h; - struct cdrom_tocentry toc_e; - int i, rc, have_datatracks = 0; - - /* look for data tracks */ - rc = sr_read_tochdr(cdi, &toc_h); - if (rc) - return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO; - - for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) { - toc_e.cdte_track = i; - toc_e.cdte_format = CDROM_LBA; - if (sr_read_tocentry(cdi, &toc_e)) - return CDS_NO_INFO; - if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) { - have_datatracks = 1; - break; - } - } - if (!have_datatracks) - return CDS_AUDIO; - - if (cd->xa_flag) - return CDS_XA_2_1; - else - return CDS_DATA_1; -} - -int sr_get_last_session(struct cdrom_device_info *cdi, - struct cdrom_multisession *ms_info) -{ - Scsi_CD *cd = cdi->handle; - - ms_info->addr.lba = cd->ms_offset; - ms_info->xa_flag = cd->xa_flag || cd->ms_offset > 0; - - return 0; -} - -int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) -{ - Scsi_CD *cd = cdi->handle; - struct packet_command cgc; - char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd)); - int result; - - if (!buffer) - return -ENOMEM; - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = GPCMD_READ_SUBCHANNEL; - cgc.cmd[2] = 0x40; /* I do want the subchannel info */ - cgc.cmd[3] = 0x02; /* Give me medium catalog number info */ - cgc.cmd[8] = 24; - cgc.buffer = buffer; - cgc.buflen = 24; - cgc.data_direction = DMA_FROM_DEVICE; - cgc.timeout = IOCTL_TIMEOUT; - result = sr_do_ioctl(cd, &cgc); - - memcpy(mcn->medium_catalog_number, buffer + 9, 13); - mcn->medium_catalog_number[13] = 0; - - kfree(buffer); - return result; -} - -int sr_reset(struct cdrom_device_info *cdi) -{ - return 0; -} - -int sr_select_speed(struct cdrom_device_info *cdi, int speed) -{ - Scsi_CD *cd = cdi->handle; - struct packet_command cgc; - - if (speed == 0) - speed = 0xffff; /* set to max */ - else - speed *= 177; /* Nx to kbyte/s */ - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = GPCMD_SET_SPEED; /* SET CD SPEED */ - cgc.cmd[2] = (speed >> 8) & 0xff; /* MSB for speed (in kbytes/sec) */ - cgc.cmd[3] = speed & 0xff; /* LSB */ - cgc.data_direction = DMA_NONE; - cgc.timeout = IOCTL_TIMEOUT; - - if (sr_do_ioctl(cd, &cgc)) - return -EIO; - return 0; -} - -/* ----------------------------------------------------------------------- */ -/* this is called by the generic cdrom driver. arg is a _kernel_ pointer, */ -/* because the generic cdrom driver does the user access stuff for us. */ -/* only cdromreadtochdr and cdromreadtocentry are left - for use with the */ -/* sr_disk_status interface for the generic cdrom driver. */ - -int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg) -{ - switch (cmd) { - case CDROMREADTOCHDR: - return sr_read_tochdr(cdi, arg); - case CDROMREADTOCENTRY: - return sr_read_tocentry(cdi, arg); - case CDROMPLAYTRKIND: - return sr_play_trkind(cdi, arg); - default: - return -EINVAL; - } -} - -/* ----------------------------------------------------------------------- - * a function to read all sorts of funny cdrom sectors using the READ_CD - * scsi-3 mmc command - * - * lba: linear block address - * format: 0 = data (anything) - * 1 = audio - * 2 = data (mode 1) - * 3 = data (mode 2) - * 4 = data (mode 2 form1) - * 5 = data (mode 2 form2) - * blksize: 2048 | 2336 | 2340 | 2352 - */ - -static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int blksize) -{ - struct packet_command cgc; - -#ifdef DEBUG - printk("%s: sr_read_cd lba=%d format=%d blksize=%d\n", - cd->cdi.name, lba, format, blksize); -#endif - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = GPCMD_READ_CD; /* READ_CD */ - cgc.cmd[1] = ((format & 7) << 2); - cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff; - cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff; - cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff; - cgc.cmd[5] = (unsigned char) lba & 0xff; - cgc.cmd[8] = 1; - switch (blksize) { - case 2336: - cgc.cmd[9] = 0x58; - break; - case 2340: - cgc.cmd[9] = 0x78; - break; - case 2352: - cgc.cmd[9] = 0xf8; - break; - default: - cgc.cmd[9] = 0x10; - break; - } - cgc.buffer = dest; - cgc.buflen = blksize; - cgc.data_direction = DMA_FROM_DEVICE; - cgc.timeout = IOCTL_TIMEOUT; - return sr_do_ioctl(cd, &cgc); -} - -/* - * read sectors with blocksizes other than 2048 - */ - -static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest) -{ - struct packet_command cgc; - int rc; - - /* we try the READ CD command first... */ - if (cd->readcd_known) { - rc = sr_read_cd(cd, dest, lba, 0, blksize); - if (-EDRIVE_CANT_DO_THIS != rc) - return rc; - cd->readcd_known = 0; - printk("CDROM does'nt support READ CD (0xbe) command\n"); - /* fall & retry the other way */ - } - /* ... if this fails, we switch the blocksize using MODE SELECT */ - if (blksize != cd->device->sector_size) { - if (0 != (rc = sr_set_blocklength(cd, blksize))) - return rc; - } -#ifdef DEBUG - printk("%s: sr_read_sector lba=%d blksize=%d\n", cd->cdi.name, lba, blksize); -#endif - - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = GPCMD_READ_10; - cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff; - cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff; - cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff; - cgc.cmd[5] = (unsigned char) lba & 0xff; - cgc.cmd[8] = 1; - cgc.buffer = dest; - cgc.buflen = blksize; - cgc.data_direction = DMA_FROM_DEVICE; - cgc.timeout = IOCTL_TIMEOUT; - rc = sr_do_ioctl(cd, &cgc); - - return rc; -} - -/* - * read a sector in raw mode to check the sector format - * ret: 1 == mode2 (XA), 0 == mode1, <0 == error - */ - -int sr_is_xa(Scsi_CD *cd) -{ - unsigned char *raw_sector; - int is_xa; - - if (!xa_test) - return 0; - - raw_sector = kmalloc(2048, GFP_KERNEL | SR_GFP_DMA(cd)); - if (!raw_sector) - return -ENOMEM; - if (0 == sr_read_sector(cd, cd->ms_offset + 16, - CD_FRAMESIZE_RAW1, raw_sector)) { - is_xa = (raw_sector[3] == 0x02) ? 1 : 0; - } else { - /* read a raw sector failed for some reason. */ - is_xa = -1; - } - kfree(raw_sector); -#ifdef DEBUG - printk("%s: sr_is_xa: %d\n", cd->cdi.name, is_xa); -#endif - return is_xa; -} diff --git a/ANDROID_3.4.5/drivers/scsi/sr_vendor.c b/ANDROID_3.4.5/drivers/scsi/sr_vendor.c deleted file mode 100644 index 92cc2efb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sr_vendor.c +++ /dev/null @@ -1,329 +0,0 @@ -/* -*-linux-c-*- - - * vendor-specific code for SCSI CD-ROM's goes here. - * - * This is needed becauce most of the new features (multisession and - * the like) are too new to be included into the SCSI-II standard (to - * be exact: there is'nt anything in my draft copy). - * - * Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does - * multisession using the READ TOC command (like SONY). - * - * Rearranged stuff here: SCSI-3 is included allways, support - * for NEC/TOSHIBA/HP commands is optional. - * - * Gerd Knorr - * - * -------------------------------------------------------------------------- - * - * support for XA/multisession-CD's - * - * - NEC: Detection and support of multisession CD's. - * - * - TOSHIBA: Detection and support of multisession CD's. - * Some XA-Sector tweaking, required for older drives. - * - * - SONY: Detection and support of multisession CD's. - * added by Thomas Quinot - * - * - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to - * work with SONY (SCSI3 now) code. - * - * - HP: Much like SONY, but a little different... (Thomas) - * HP-Writers only ??? Maybe other CD-Writers work with this too ? - * HP 6020 writers now supported. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "sr.h" - -#if 0 -#define DEBUG -#endif - -/* here are some constants to sort the vendors into groups */ - -#define VENDOR_SCSI3 1 /* default: scsi-3 mmc */ - -#define VENDOR_NEC 2 -#define VENDOR_TOSHIBA 3 -#define VENDOR_WRITER 4 /* pre-scsi3 writers */ - -#define VENDOR_TIMEOUT 30*HZ - -void sr_vendor_init(Scsi_CD *cd) -{ -#ifndef CONFIG_BLK_DEV_SR_VENDOR - cd->vendor = VENDOR_SCSI3; -#else - const char *vendor = cd->device->vendor; - const char *model = cd->device->model; - - /* default */ - cd->vendor = VENDOR_SCSI3; - if (cd->readcd_known) - /* this is true for scsi3/mmc drives - no more checks */ - return; - - if (cd->device->type == TYPE_WORM) { - cd->vendor = VENDOR_WRITER; - - } else if (!strncmp(vendor, "NEC", 3)) { - cd->vendor = VENDOR_NEC; - if (!strncmp(model, "CD-ROM DRIVE:25", 15) || - !strncmp(model, "CD-ROM DRIVE:36", 15) || - !strncmp(model, "CD-ROM DRIVE:83", 15) || - !strncmp(model, "CD-ROM DRIVE:84 ", 16) -#if 0 - /* my NEC 3x returns the read-raw data if a read-raw - is followed by a read for the same sector - aeb */ - || !strncmp(model, "CD-ROM DRIVE:500", 16) -#endif - ) - /* these can't handle multisession, may hang */ - cd->cdi.mask |= CDC_MULTI_SESSION; - - } else if (!strncmp(vendor, "TOSHIBA", 7)) { - cd->vendor = VENDOR_TOSHIBA; - - } -#endif -} - - -/* small handy function for switching block length using MODE SELECT, - * used by sr_read_sector() */ - -int sr_set_blocklength(Scsi_CD *cd, int blocklength) -{ - unsigned char *buffer; /* the buffer for the ioctl */ - struct packet_command cgc; - struct ccs_modesel_head *modesel; - int rc, density = 0; - -#ifdef CONFIG_BLK_DEV_SR_VENDOR - if (cd->vendor == VENDOR_TOSHIBA) - density = (blocklength > 2048) ? 0x81 : 0x83; -#endif - - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - -#ifdef DEBUG - printk("%s: MODE SELECT 0x%x/%d\n", cd->cdi.name, density, blocklength); -#endif - memset(&cgc, 0, sizeof(struct packet_command)); - cgc.cmd[0] = MODE_SELECT; - cgc.cmd[1] = (1 << 4); - cgc.cmd[4] = 12; - modesel = (struct ccs_modesel_head *) buffer; - memset(modesel, 0, sizeof(*modesel)); - modesel->block_desc_length = 0x08; - modesel->density = density; - modesel->block_length_med = (blocklength >> 8) & 0xff; - modesel->block_length_lo = blocklength & 0xff; - cgc.buffer = buffer; - cgc.buflen = sizeof(*modesel); - cgc.data_direction = DMA_TO_DEVICE; - cgc.timeout = VENDOR_TIMEOUT; - if (0 == (rc = sr_do_ioctl(cd, &cgc))) { - cd->device->sector_size = blocklength; - } -#ifdef DEBUG - else - printk("%s: switching blocklength to %d bytes failed\n", - cd->cdi.name, blocklength); -#endif - kfree(buffer); - return rc; -} - -/* This function gets called after a media change. Checks if the CD is - multisession, asks for offset etc. */ - -int sr_cd_check(struct cdrom_device_info *cdi) -{ - Scsi_CD *cd = cdi->handle; - unsigned long sector; - unsigned char *buffer; /* the buffer for the ioctl */ - struct packet_command cgc; - int rc, no_multi; - - if (cd->cdi.mask & CDC_MULTI_SESSION) - return 0; - - buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); - if (!buffer) - return -ENOMEM; - - sector = 0; /* the multisession sector offset goes here */ - no_multi = 0; /* flag: the drive can't handle multisession */ - rc = 0; - - memset(&cgc, 0, sizeof(struct packet_command)); - - switch (cd->vendor) { - - case VENDOR_SCSI3: - cgc.cmd[0] = READ_TOC; - cgc.cmd[8] = 12; - cgc.cmd[9] = 0x40; - cgc.buffer = buffer; - cgc.buflen = 12; - cgc.quiet = 1; - cgc.data_direction = DMA_FROM_DEVICE; - cgc.timeout = VENDOR_TIMEOUT; - rc = sr_do_ioctl(cd, &cgc); - if (rc != 0) - break; - if ((buffer[0] << 8) + buffer[1] < 0x0a) { - printk(KERN_INFO "%s: Hmm, seems the drive " - "doesn't support multisession CD's\n", cd->cdi.name); - no_multi = 1; - break; - } - sector = buffer[11] + (buffer[10] << 8) + - (buffer[9] << 16) + (buffer[8] << 24); - if (buffer[6] <= 1) { - /* ignore sector offsets from first track */ - sector = 0; - } - break; - -#ifdef CONFIG_BLK_DEV_SR_VENDOR - case VENDOR_NEC:{ - unsigned long min, sec, frame; - cgc.cmd[0] = 0xde; - cgc.cmd[1] = 0x03; - cgc.cmd[2] = 0xb0; - cgc.buffer = buffer; - cgc.buflen = 0x16; - cgc.quiet = 1; - cgc.data_direction = DMA_FROM_DEVICE; - cgc.timeout = VENDOR_TIMEOUT; - rc = sr_do_ioctl(cd, &cgc); - if (rc != 0) - break; - if (buffer[14] != 0 && buffer[14] != 0xb0) { - printk(KERN_INFO "%s: Hmm, seems the cdrom " - "doesn't support multisession CD's\n", - cd->cdi.name); - no_multi = 1; - break; - } - min = bcd2bin(buffer[15]); - sec = bcd2bin(buffer[16]); - frame = bcd2bin(buffer[17]); - sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame; - break; - } - - case VENDOR_TOSHIBA:{ - unsigned long min, sec, frame; - - /* we request some disc information (is it a XA-CD ?, - * where starts the last session ?) */ - cgc.cmd[0] = 0xc7; - cgc.cmd[1] = 0x03; - cgc.buffer = buffer; - cgc.buflen = 4; - cgc.quiet = 1; - cgc.data_direction = DMA_FROM_DEVICE; - cgc.timeout = VENDOR_TIMEOUT; - rc = sr_do_ioctl(cd, &cgc); - if (rc == -EINVAL) { - printk(KERN_INFO "%s: Hmm, seems the drive " - "doesn't support multisession CD's\n", - cd->cdi.name); - no_multi = 1; - break; - } - if (rc != 0) - break; - min = bcd2bin(buffer[1]); - sec = bcd2bin(buffer[2]); - frame = bcd2bin(buffer[3]); - sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame; - if (sector) - sector -= CD_MSF_OFFSET; - sr_set_blocklength(cd, 2048); - break; - } - - case VENDOR_WRITER: - cgc.cmd[0] = READ_TOC; - cgc.cmd[8] = 0x04; - cgc.cmd[9] = 0x40; - cgc.buffer = buffer; - cgc.buflen = 0x04; - cgc.quiet = 1; - cgc.data_direction = DMA_FROM_DEVICE; - cgc.timeout = VENDOR_TIMEOUT; - rc = sr_do_ioctl(cd, &cgc); - if (rc != 0) { - break; - } - if ((rc = buffer[2]) == 0) { - printk(KERN_WARNING - "%s: No finished session\n", cd->cdi.name); - break; - } - cgc.cmd[0] = READ_TOC; /* Read TOC */ - cgc.cmd[6] = rc & 0x7f; /* number of last session */ - cgc.cmd[8] = 0x0c; - cgc.cmd[9] = 0x40; - cgc.buffer = buffer; - cgc.buflen = 12; - cgc.quiet = 1; - cgc.data_direction = DMA_FROM_DEVICE; - cgc.timeout = VENDOR_TIMEOUT; - rc = sr_do_ioctl(cd, &cgc); - if (rc != 0) { - break; - } - sector = buffer[11] + (buffer[10] << 8) + - (buffer[9] << 16) + (buffer[8] << 24); - break; -#endif /* CONFIG_BLK_DEV_SR_VENDOR */ - - default: - /* should not happen */ - printk(KERN_WARNING - "%s: unknown vendor code (%i), not initialized ?\n", - cd->cdi.name, cd->vendor); - sector = 0; - no_multi = 1; - break; - } - cd->ms_offset = sector; - cd->xa_flag = 0; - if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(cd)) - cd->xa_flag = 1; - - if (2048 != cd->device->sector_size) { - sr_set_blocklength(cd, 2048); - } - if (no_multi) - cdi->mask |= CDC_MULTI_SESSION; - -#ifdef DEBUG - if (sector) - printk(KERN_DEBUG "%s: multisession offset=%lu\n", - cd->cdi.name, sector); -#endif - kfree(buffer); - return rc; -} diff --git a/ANDROID_3.4.5/drivers/scsi/st.c b/ANDROID_3.4.5/drivers/scsi/st.c deleted file mode 100644 index e41998cb..00000000 --- a/ANDROID_3.4.5/drivers/scsi/st.c +++ /dev/null @@ -1,4649 +0,0 @@ -/* - SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying - file Documentation/scsi/st.txt for more information. - - History: - Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. - Contribution and ideas from several people including (in alphabetical - order) Klaus Ehrenfried, Eugene Exarevsky, Eric Lee Green, Wolfgang Denk, - Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, - Michael Schaefer, J"org Weule, and Eric Youngdale. - - Copyright 1992 - 2010 Kai Makisara - email Kai.Makisara@kolumbus.fi - - Some small formal changes - aeb, 950809 - - Last modified: 18-JAN-1998 Richard Gooch Devfs support - */ - -static const char *verstr = "20101219"; - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - - -/* The driver prints some debugging information on the console if DEBUG - is defined and non-zero. */ -#define DEBUG 0 - -#if DEBUG -/* The message level for the debug messages is currently set to KERN_NOTICE - so that people can easily see the messages. Later when the debugging messages - in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ -#define ST_DEB_MSG KERN_NOTICE -#define DEB(a) a -#define DEBC(a) if (debugging) { a ; } -#else -#define DEB(a) -#define DEBC(a) -#endif - -#define ST_KILOBYTE 1024 - -#include "st_options.h" -#include "st.h" - -static DEFINE_MUTEX(st_mutex); -static int buffer_kbs; -static int max_sg_segs; -static int try_direct_io = TRY_DIRECT_IO; -static int try_rdio = 1; -static int try_wdio = 1; - -static int st_dev_max; -static int st_nr_dev; - -static struct class *st_sysfs_class; - -MODULE_AUTHOR("Kai Makisara"); -MODULE_DESCRIPTION("SCSI tape (st) driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR); -MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); - -/* Set 'perm' (4th argument) to 0 to disable module_param's definition - * of sysfs parameters (which module_param doesn't yet support). - * Sysfs parameters defined explicitly later. - */ -module_param_named(buffer_kbs, buffer_kbs, int, 0); -MODULE_PARM_DESC(buffer_kbs, "Default driver buffer size for fixed block mode (KB; 32)"); -module_param_named(max_sg_segs, max_sg_segs, int, 0); -MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)"); -module_param_named(try_direct_io, try_direct_io, int, 0); -MODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)"); - -/* Extra parameters for testing */ -module_param_named(try_rdio, try_rdio, int, 0); -MODULE_PARM_DESC(try_rdio, "Try direct read i/o when possible"); -module_param_named(try_wdio, try_wdio, int, 0); -MODULE_PARM_DESC(try_wdio, "Try direct write i/o when possible"); - -#ifndef MODULE -static int write_threshold_kbs; /* retained for compatibility */ -static struct st_dev_parm { - char *name; - int *val; -} parms[] __initdata = { - { - "buffer_kbs", &buffer_kbs - }, - { /* Retained for compatibility with 2.4 */ - "write_threshold_kbs", &write_threshold_kbs - }, - { - "max_sg_segs", NULL - }, - { - "try_direct_io", &try_direct_io - } -}; -#endif - -/* Restrict the number of modes so that names for all are assigned */ -#if ST_NBR_MODES > 16 -#error "Maximum number of modes is 16" -#endif -/* Bit reversed order to get same names for same minors with all - mode counts */ -static const char *st_formats[] = { - "", "r", "k", "s", "l", "t", "o", "u", - "m", "v", "p", "x", "a", "y", "q", "z"}; - -/* The default definitions have been moved to st_options.h */ - -#define ST_FIXED_BUFFER_SIZE (ST_FIXED_BUFFER_BLOCKS * ST_KILOBYTE) - -/* The buffer size should fit into the 24 bits for length in the - 6-byte SCSI read and write commands. */ -#if ST_FIXED_BUFFER_SIZE >= (2 << 24 - 1) -#error "Buffer size should not exceed (2 << 24 - 1) bytes!" -#endif - -static int debugging = DEBUG; - -#define MAX_RETRIES 0 -#define MAX_WRITE_RETRIES 0 -#define MAX_READY_RETRIES 0 -#define NO_TAPE NOT_READY - -#define ST_TIMEOUT (900 * HZ) -#define ST_LONG_TIMEOUT (14000 * HZ) - -/* Remove mode bits and auto-rewind bit (7) */ -#define TAPE_NR(x) ( ((iminor(x) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \ - (iminor(x) & ~(-1 << ST_MODE_SHIFT)) ) -#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) - -/* Construct the minor number from the device (d), mode (m), and non-rewind (n) data */ -#define TAPE_MINOR(d, m, n) (((d & ~(255 >> (ST_NBR_MODE_BITS + 1))) << (ST_NBR_MODE_BITS + 1)) | \ - (d & (255 >> (ST_NBR_MODE_BITS + 1))) | (m << ST_MODE_SHIFT) | ((n != 0) << 7) ) - -/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower - 24 bits) */ -#define SET_DENS_AND_BLK 0x10001 - -static DEFINE_RWLOCK(st_dev_arr_lock); - -static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE; -static int st_max_sg_segs = ST_MAX_SG; - -static struct scsi_tape **scsi_tapes = NULL; - -static int modes_defined; - -static int enlarge_buffer(struct st_buffer *, int, int); -static void clear_buffer(struct st_buffer *); -static void normalize_buffer(struct st_buffer *); -static int append_to_buffer(const char __user *, struct st_buffer *, int); -static int from_buffer(struct st_buffer *, char __user *, int); -static void move_buffer_data(struct st_buffer *, int); - -static int sgl_map_user_pages(struct st_buffer *, const unsigned int, - unsigned long, size_t, int); -static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int); - -static int st_probe(struct device *); -static int st_remove(struct device *); - -static int do_create_sysfs_files(void); -static void do_remove_sysfs_files(void); -static int do_create_class_files(struct scsi_tape *, int, int); - -static struct scsi_driver st_template = { - .owner = THIS_MODULE, - .gendrv = { - .name = "st", - .probe = st_probe, - .remove = st_remove, - }, -}; - -static int st_compression(struct scsi_tape *, int); - -static int find_partition(struct scsi_tape *); -static int switch_partition(struct scsi_tape *); - -static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long); - -static void scsi_tape_release(struct kref *); - -#define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref) - -static DEFINE_MUTEX(st_ref_mutex); - - -#include "osst_detect.h" -#ifndef SIGS_FROM_OSST -#define SIGS_FROM_OSST \ - {"OnStream", "SC-", "", "osst"}, \ - {"OnStream", "DI-", "", "osst"}, \ - {"OnStream", "DP-", "", "osst"}, \ - {"OnStream", "USB", "", "osst"}, \ - {"OnStream", "FW-", "", "osst"} -#endif - -static struct scsi_tape *scsi_tape_get(int dev) -{ - struct scsi_tape *STp = NULL; - - mutex_lock(&st_ref_mutex); - write_lock(&st_dev_arr_lock); - - if (dev < st_dev_max && scsi_tapes != NULL) - STp = scsi_tapes[dev]; - if (!STp) goto out; - - kref_get(&STp->kref); - - if (!STp->device) - goto out_put; - - if (scsi_device_get(STp->device)) - goto out_put; - - goto out; - -out_put: - kref_put(&STp->kref, scsi_tape_release); - STp = NULL; -out: - write_unlock(&st_dev_arr_lock); - mutex_unlock(&st_ref_mutex); - return STp; -} - -static void scsi_tape_put(struct scsi_tape *STp) -{ - struct scsi_device *sdev = STp->device; - - mutex_lock(&st_ref_mutex); - kref_put(&STp->kref, scsi_tape_release); - scsi_device_put(sdev); - mutex_unlock(&st_ref_mutex); -} - -struct st_reject_data { - char *vendor; - char *model; - char *rev; - char *driver_hint; /* Name of the correct driver, NULL if unknown */ -}; - -static struct st_reject_data reject_list[] = { - /* {"XXX", "Yy-", "", NULL}, example */ - SIGS_FROM_OSST, - {NULL, }}; - -/* If the device signature is on the list of incompatible drives, the - function returns a pointer to the name of the correct driver (if known) */ -static char * st_incompatible(struct scsi_device* SDp) -{ - struct st_reject_data *rp; - - for (rp=&(reject_list[0]); rp->vendor != NULL; rp++) - if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) && - !strncmp(rp->model, SDp->model, strlen(rp->model)) && - !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) { - if (rp->driver_hint) - return rp->driver_hint; - else - return "unknown"; - } - return NULL; -} - - -static inline char *tape_name(struct scsi_tape *tape) -{ - return tape->disk->disk_name; -} - - -static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s) -{ - const u8 *ucp; - const u8 *sense = SRpnt->sense; - - s->have_sense = scsi_normalize_sense(SRpnt->sense, - SCSI_SENSE_BUFFERSIZE, &s->sense_hdr); - s->flags = 0; - - if (s->have_sense) { - s->deferred = 0; - s->remainder_valid = - scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64); - switch (sense[0] & 0x7f) { - case 0x71: - s->deferred = 1; - case 0x70: - s->fixed_format = 1; - s->flags = sense[2] & 0xe0; - break; - case 0x73: - s->deferred = 1; - case 0x72: - s->fixed_format = 0; - ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4); - s->flags = ucp ? (ucp[3] & 0xe0) : 0; - break; - } - } -} - - -/* Convert the result to success code */ -static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) -{ - int result = SRpnt->result; - u8 scode; - DEB(const char *stp;) - char *name = tape_name(STp); - struct st_cmdstatus *cmdstatp; - - if (!result) - return 0; - - cmdstatp = &STp->buffer->cmdstat; - st_analyze_sense(SRpnt, cmdstatp); - - if (cmdstatp->have_sense) - scode = STp->buffer->cmdstat.sense_hdr.sense_key; - else - scode = 0; - - DEB( - if (debugging) { - printk(ST_DEB_MSG "%s: Error: %x, cmd: %x %x %x %x %x %x\n", - name, result, - SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2], - SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]); - if (cmdstatp->have_sense) - __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE); - } ) /* end DEB */ - if (!debugging) { /* Abnormal conditions for tape */ - if (!cmdstatp->have_sense) - printk(KERN_WARNING - "%s: Error %x (driver bt 0x%x, host bt 0x%x).\n", - name, result, driver_byte(result), - host_byte(result)); - else if (cmdstatp->have_sense && - scode != NO_SENSE && - scode != RECOVERED_ERROR && - /* scode != UNIT_ATTENTION && */ - scode != BLANK_CHECK && - scode != VOLUME_OVERFLOW && - SRpnt->cmd[0] != MODE_SENSE && - SRpnt->cmd[0] != TEST_UNIT_READY) { - - __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE); - } - } - - if (cmdstatp->fixed_format && - STp->cln_mode >= EXTENDED_SENSE_START) { /* Only fixed format sense */ - if (STp->cln_sense_value) - STp->cleaning_req |= ((SRpnt->sense[STp->cln_mode] & - STp->cln_sense_mask) == STp->cln_sense_value); - else - STp->cleaning_req |= ((SRpnt->sense[STp->cln_mode] & - STp->cln_sense_mask) != 0); - } - if (cmdstatp->have_sense && - cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17) - STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */ - - STp->pos_unknown |= STp->device->was_reset; - - if (cmdstatp->have_sense && - scode == RECOVERED_ERROR -#if ST_RECOVERED_WRITE_FATAL - && SRpnt->cmd[0] != WRITE_6 - && SRpnt->cmd[0] != WRITE_FILEMARKS -#endif - ) { - STp->recover_count++; - STp->recover_reg++; - - DEB( - if (debugging) { - if (SRpnt->cmd[0] == READ_6) - stp = "read"; - else if (SRpnt->cmd[0] == WRITE_6) - stp = "write"; - else - stp = "ioctl"; - printk(ST_DEB_MSG "%s: Recovered %s error (%d).\n", name, stp, - STp->recover_count); - } ) /* end DEB */ - - if (cmdstatp->flags == 0) - return 0; - } - return (-EIO); -} - -static struct st_request *st_allocate_request(struct scsi_tape *stp) -{ - struct st_request *streq; - - streq = kzalloc(sizeof(*streq), GFP_KERNEL); - if (streq) - streq->stp = stp; - else { - DEBC(printk(KERN_ERR "%s: Can't get SCSI request.\n", - tape_name(stp));); - if (signal_pending(current)) - stp->buffer->syscall_result = -EINTR; - else - stp->buffer->syscall_result = -EBUSY; - } - - return streq; -} - -static void st_release_request(struct st_request *streq) -{ - kfree(streq); -} - -static void st_scsi_execute_end(struct request *req, int uptodate) -{ - struct st_request *SRpnt = req->end_io_data; - struct scsi_tape *STp = SRpnt->stp; - struct bio *tmp; - - STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; - STp->buffer->cmdstat.residual = req->resid_len; - - tmp = SRpnt->bio; - if (SRpnt->waiting) - complete(SRpnt->waiting); - - blk_rq_unmap_user(tmp); - __blk_put_request(req->q, req); -} - -static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - int timeout, int retries) -{ - struct request *req; - struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - int err = 0; - int write = (data_direction == DMA_TO_DEVICE); - - req = blk_get_request(SRpnt->stp->device->request_queue, write, - GFP_KERNEL); - if (!req) - return DRIVER_ERROR << 24; - - req->cmd_type = REQ_TYPE_BLOCK_PC; - req->cmd_flags |= REQ_QUIET; - - mdata->null_mapped = 1; - - if (bufflen) { - err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, - GFP_KERNEL); - if (err) { - blk_put_request(req); - return DRIVER_ERROR << 24; - } - } - - SRpnt->bio = req->bio; - req->cmd_len = COMMAND_SIZE(cmd[0]); - memset(req->cmd, 0, BLK_MAX_CDB); - memcpy(req->cmd, cmd, req->cmd_len); - req->sense = SRpnt->sense; - req->sense_len = 0; - req->timeout = timeout; - req->retries = retries; - req->end_io_data = SRpnt; - - blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end); - return 0; -} - -/* Do the scsi command. Waits until command performed if do_wait is true. - Otherwise write_behind_check() is used to check that the command - has finished. */ -static struct st_request * -st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd, - int bytes, int direction, int timeout, int retries, int do_wait) -{ - struct completion *waiting; - struct rq_map_data *mdata = &STp->buffer->map_data; - int ret; - - /* if async, make sure there's no command outstanding */ - if (!do_wait && ((STp->buffer)->last_SRpnt)) { - printk(KERN_ERR "%s: Async command already active.\n", - tape_name(STp)); - if (signal_pending(current)) - (STp->buffer)->syscall_result = (-EINTR); - else - (STp->buffer)->syscall_result = (-EBUSY); - return NULL; - } - - if (!SRpnt) { - SRpnt = st_allocate_request(STp); - if (!SRpnt) - return NULL; - } - - /* If async IO, set last_SRpnt. This ptr tells write_behind_check - which IO is outstanding. It's nulled out when the IO completes. */ - if (!do_wait) - (STp->buffer)->last_SRpnt = SRpnt; - - waiting = &STp->wait; - init_completion(waiting); - SRpnt->waiting = waiting; - - if (STp->buffer->do_dio) { - mdata->page_order = 0; - mdata->nr_entries = STp->buffer->sg_segs; - mdata->pages = STp->buffer->mapped_pages; - } else { - mdata->page_order = STp->buffer->reserved_page_order; - mdata->nr_entries = - DIV_ROUND_UP(bytes, PAGE_SIZE << mdata->page_order); - mdata->pages = STp->buffer->reserved_pages; - mdata->offset = 0; - } - - memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); - STp->buffer->cmdstat.have_sense = 0; - STp->buffer->syscall_result = 0; - - ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, timeout, - retries); - if (ret) { - /* could not allocate the buffer or request was too large */ - (STp->buffer)->syscall_result = (-EBUSY); - (STp->buffer)->last_SRpnt = NULL; - } else if (do_wait) { - wait_for_completion(waiting); - SRpnt->waiting = NULL; - (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); - } - - return SRpnt; -} - - -/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if - write has been correct but EOM early warning reached, -EIO if write ended in - error or zero if write successful. Asynchronous writes are used only in - variable block mode. */ -static int write_behind_check(struct scsi_tape * STp) -{ - int retval = 0; - struct st_buffer *STbuffer; - struct st_partstat *STps; - struct st_cmdstatus *cmdstatp; - struct st_request *SRpnt; - - STbuffer = STp->buffer; - if (!STbuffer->writing) - return 0; - - DEB( - if (STp->write_pending) - STp->nbr_waits++; - else - STp->nbr_finished++; - ) /* end DEB */ - - wait_for_completion(&(STp->wait)); - SRpnt = STbuffer->last_SRpnt; - STbuffer->last_SRpnt = NULL; - SRpnt->waiting = NULL; - - (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); - st_release_request(SRpnt); - - STbuffer->buffer_bytes -= STbuffer->writing; - STps = &(STp->ps[STp->partition]); - if (STps->drv_block >= 0) { - if (STp->block_size == 0) - STps->drv_block++; - else - STps->drv_block += STbuffer->writing / STp->block_size; - } - - cmdstatp = &STbuffer->cmdstat; - if (STbuffer->syscall_result) { - retval = -EIO; - if (cmdstatp->have_sense && !cmdstatp->deferred && - (cmdstatp->flags & SENSE_EOM) && - (cmdstatp->sense_hdr.sense_key == NO_SENSE || - cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) { - /* EOM at write-behind, has all data been written? */ - if (!cmdstatp->remainder_valid || - cmdstatp->uremainder64 == 0) - retval = -ENOSPC; - } - if (retval == -EIO) - STps->drv_block = -1; - } - STbuffer->writing = 0; - - DEB(if (debugging && retval) - printk(ST_DEB_MSG "%s: Async write error %x, return value %d.\n", - tape_name(STp), STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */ - - return retval; -} - - -/* Step over EOF if it has been inadvertently crossed (ioctl not used because - it messes up the block number). */ -static int cross_eof(struct scsi_tape * STp, int forward) -{ - struct st_request *SRpnt; - unsigned char cmd[MAX_COMMAND_SIZE]; - - cmd[0] = SPACE; - cmd[1] = 0x01; /* Space FileMarks */ - if (forward) { - cmd[2] = cmd[3] = 0; - cmd[4] = 1; - } else - cmd[2] = cmd[3] = cmd[4] = 0xff; /* -1 filemarks */ - cmd[5] = 0; - - DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n", - tape_name(STp), forward ? "forward" : "backward")); - - SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, - STp->device->request_queue->rq_timeout, - MAX_RETRIES, 1); - if (!SRpnt) - return (STp->buffer)->syscall_result; - - st_release_request(SRpnt); - SRpnt = NULL; - - if ((STp->buffer)->cmdstat.midlevel_result != 0) - printk(KERN_ERR "%s: Stepping over filemark %s failed.\n", - tape_name(STp), forward ? "forward" : "backward"); - - return (STp->buffer)->syscall_result; -} - - -/* Flush the write buffer (never need to write if variable blocksize). */ -static int st_flush_write_buffer(struct scsi_tape * STp) -{ - int transfer, blks; - int result; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; - struct st_partstat *STps; - - result = write_behind_check(STp); - if (result) - return result; - - result = 0; - if (STp->dirty == 1) { - - transfer = STp->buffer->buffer_bytes; - DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n", - tape_name(STp), transfer)); - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = 1; - blks = transfer / STp->block_size; - cmd[2] = blks >> 16; - cmd[3] = blks >> 8; - cmd[4] = blks; - - SRpnt = st_do_scsi(NULL, STp, cmd, transfer, DMA_TO_DEVICE, - STp->device->request_queue->rq_timeout, - MAX_WRITE_RETRIES, 1); - if (!SRpnt) - return (STp->buffer)->syscall_result; - - STps = &(STp->ps[STp->partition]); - if ((STp->buffer)->syscall_result != 0) { - struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; - - if (cmdstatp->have_sense && !cmdstatp->deferred && - (cmdstatp->flags & SENSE_EOM) && - (cmdstatp->sense_hdr.sense_key == NO_SENSE || - cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && - (!cmdstatp->remainder_valid || - cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */ - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - if (STps->drv_block >= 0) - STps->drv_block += blks; - result = (-ENOSPC); - } else { - printk(KERN_ERR "%s: Error on flush.\n", - tape_name(STp)); - STps->drv_block = (-1); - result = (-EIO); - } - } else { - if (STps->drv_block >= 0) - STps->drv_block += blks; - STp->dirty = 0; - (STp->buffer)->buffer_bytes = 0; - } - st_release_request(SRpnt); - SRpnt = NULL; - } - return result; -} - - -/* Flush the tape buffer. The tape will be positioned correctly unless - seek_next is true. */ -static int flush_buffer(struct scsi_tape *STp, int seek_next) -{ - int backspace, result; - struct st_buffer *STbuffer; - struct st_partstat *STps; - - STbuffer = STp->buffer; - - /* - * If there was a bus reset, block further access - * to this device. - */ - if (STp->pos_unknown) - return (-EIO); - - if (STp->ready != ST_READY) - return 0; - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING) /* Writing */ - return st_flush_write_buffer(STp); - - if (STp->block_size == 0) - return 0; - - backspace = ((STp->buffer)->buffer_bytes + - (STp->buffer)->read_pointer) / STp->block_size - - ((STp->buffer)->read_pointer + STp->block_size - 1) / - STp->block_size; - (STp->buffer)->buffer_bytes = 0; - (STp->buffer)->read_pointer = 0; - result = 0; - if (!seek_next) { - if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, 0); /* Back over the EOF hit */ - if (!result) - STps->eof = ST_NOEOF; - else { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - } - } - if (!result && backspace > 0) - result = st_int_ioctl(STp, MTBSR, backspace); - } else if (STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_NOEOF; - } - return result; - -} - -/* Set the mode parameters */ -static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm) -{ - int set_it = 0; - unsigned long arg; - char *name = tape_name(STp); - - if (!STp->density_changed && - STm->default_density >= 0 && - STm->default_density != STp->density) { - arg = STm->default_density; - set_it = 1; - } else - arg = STp->density; - arg <<= MT_ST_DENSITY_SHIFT; - if (!STp->blksize_changed && - STm->default_blksize >= 0 && - STm->default_blksize != STp->block_size) { - arg |= STm->default_blksize; - set_it = 1; - } else - arg |= STp->block_size; - if (set_it && - st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) { - printk(KERN_WARNING - "%s: Can't set default block size to %d bytes and density %x.\n", - name, STm->default_blksize, STm->default_density); - if (modes_defined) - return (-EINVAL); - } - return 0; -} - - -/* Lock or unlock the drive door. Don't use when st_request allocated. */ -static int do_door_lock(struct scsi_tape * STp, int do_lock) -{ - int retval, cmd; - DEB(char *name = tape_name(STp);) - - - cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK; - DEBC(printk(ST_DEB_MSG "%s: %socking drive door.\n", name, - do_lock ? "L" : "Unl")); - retval = scsi_ioctl(STp->device, cmd, NULL); - if (!retval) { - STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED; - } - else { - STp->door_locked = ST_LOCK_FAILS; - } - return retval; -} - - -/* Set the internal state after reset */ -static void reset_state(struct scsi_tape *STp) -{ - int i; - struct st_partstat *STps; - - STp->pos_unknown = 0; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = -1; - STps->drv_file = -1; - } - if (STp->can_partitions) { - STp->partition = find_partition(STp); - if (STp->partition < 0) - STp->partition = 0; - STp->new_partition = STp->partition; - } -} - -/* Test if the drive is ready. Returns either one of the codes below or a negative system - error code. */ -#define CHKRES_READY 0 -#define CHKRES_NEW_SESSION 1 -#define CHKRES_NOT_READY 2 -#define CHKRES_NO_TAPE 3 - -#define MAX_ATTENTIONS 10 - -static int test_ready(struct scsi_tape *STp, int do_wait) -{ - int attentions, waits, max_wait, scode; - int retval = CHKRES_READY, new_session = 0; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt = NULL; - struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; - - max_wait = do_wait ? ST_BLOCK_SECONDS : 0; - - for (attentions=waits=0; ; ) { - memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); - cmd[0] = TEST_UNIT_READY; - SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, - STp->long_timeout, MAX_READY_RETRIES, 1); - - if (!SRpnt) { - retval = (STp->buffer)->syscall_result; - break; - } - - if (cmdstatp->have_sense) { - - scode = cmdstatp->sense_hdr.sense_key; - - if (scode == UNIT_ATTENTION) { /* New media? */ - new_session = 1; - if (attentions < MAX_ATTENTIONS) { - attentions++; - continue; - } - else { - retval = (-EIO); - break; - } - } - - if (scode == NOT_READY) { - if (waits < max_wait) { - if (msleep_interruptible(1000)) { - retval = (-EINTR); - break; - } - waits++; - continue; - } - else { - if ((STp->device)->scsi_level >= SCSI_2 && - cmdstatp->sense_hdr.asc == 0x3a) /* Check ASC */ - retval = CHKRES_NO_TAPE; - else - retval = CHKRES_NOT_READY; - break; - } - } - } - - retval = (STp->buffer)->syscall_result; - if (!retval) - retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY; - break; - } - - if (SRpnt != NULL) - st_release_request(SRpnt); - return retval; -} - - -/* See if the drive is ready and gather information about the tape. Return values: - < 0 negative error code from errno.h - 0 drive ready - 1 drive not ready (possibly no tape) -*/ -static int check_tape(struct scsi_tape *STp, struct file *filp) -{ - int i, retval, new_session = 0, do_wait; - unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning; - unsigned short st_flags = filp->f_flags; - struct st_request *SRpnt = NULL; - struct st_modedef *STm; - struct st_partstat *STps; - char *name = tape_name(STp); - struct inode *inode = filp->f_path.dentry->d_inode; - int mode = TAPE_MODE(inode); - - STp->ready = ST_READY; - - if (mode != STp->current_mode) { - DEBC(printk(ST_DEB_MSG "%s: Mode change from %d to %d.\n", - name, STp->current_mode, mode)); - new_session = 1; - STp->current_mode = mode; - } - STm = &(STp->modes[STp->current_mode]); - - saved_cleaning = STp->cleaning_req; - STp->cleaning_req = 0; - - do_wait = ((filp->f_flags & O_NONBLOCK) == 0); - retval = test_ready(STp, do_wait); - - if (retval < 0) - goto err_out; - - if (retval == CHKRES_NEW_SESSION) { - STp->pos_unknown = 0; - STp->partition = STp->new_partition = 0; - if (STp->can_partitions) - STp->nbr_partitions = 1; /* This guess will be updated later - if necessary */ - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = 0; - STps->drv_file = 0; - } - new_session = 1; - } - else { - STp->cleaning_req |= saved_cleaning; - - if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) { - if (retval == CHKRES_NO_TAPE) - STp->ready = ST_NO_TAPE; - else - STp->ready = ST_NOT_READY; - - STp->density = 0; /* Clear the erroneous "residue" */ - STp->write_prot = 0; - STp->block_size = 0; - STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); - STp->partition = STp->new_partition = 0; - STp->door_locked = ST_UNLOCKED; - return CHKRES_NOT_READY; - } - } - - if (STp->omit_blklims) - STp->min_block = STp->max_block = (-1); - else { - memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); - cmd[0] = READ_BLOCK_LIMITS; - - SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE, - STp->device->request_queue->rq_timeout, - MAX_READY_RETRIES, 1); - if (!SRpnt) { - retval = (STp->buffer)->syscall_result; - goto err_out; - } - - if (!SRpnt->result && !STp->buffer->cmdstat.have_sense) { - STp->max_block = ((STp->buffer)->b_data[1] << 16) | - ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; - STp->min_block = ((STp->buffer)->b_data[4] << 8) | - (STp->buffer)->b_data[5]; - if ( DEB( debugging || ) !STp->inited) - printk(KERN_INFO - "%s: Block limits %d - %d bytes.\n", name, - STp->min_block, STp->max_block); - } else { - STp->min_block = STp->max_block = (-1); - DEBC(printk(ST_DEB_MSG "%s: Can't read block limits.\n", - name)); - } - } - - memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - cmd[4] = 12; - - SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE, - STp->device->request_queue->rq_timeout, - MAX_READY_RETRIES, 1); - if (!SRpnt) { - retval = (STp->buffer)->syscall_result; - goto err_out; - } - - if ((STp->buffer)->syscall_result != 0) { - DEBC(printk(ST_DEB_MSG "%s: No Mode Sense.\n", name)); - STp->block_size = ST_DEFAULT_BLOCK; /* Educated guess (?) */ - (STp->buffer)->syscall_result = 0; /* Prevent error propagation */ - STp->drv_write_prot = 0; - } else { - DEBC(printk(ST_DEB_MSG - "%s: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", - name, - (STp->buffer)->b_data[0], (STp->buffer)->b_data[1], - (STp->buffer)->b_data[2], (STp->buffer)->b_data[3])); - - if ((STp->buffer)->b_data[3] >= 8) { - STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7; - STp->density = (STp->buffer)->b_data[4]; - STp->block_size = (STp->buffer)->b_data[9] * 65536 + - (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]; - DEBC(printk(ST_DEB_MSG - "%s: Density %x, tape length: %x, drv buffer: %d\n", - name, STp->density, (STp->buffer)->b_data[5] * 65536 + - (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], - STp->drv_buffer)); - } - STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; - if (!STp->drv_buffer && STp->immediate_filemark) { - printk(KERN_WARNING - "%s: non-buffered tape: disabling writing immediate filemarks\n", - name); - STp->immediate_filemark = 0; - } - } - st_release_request(SRpnt); - SRpnt = NULL; - STp->inited = 1; - - if (STp->block_size > 0) - (STp->buffer)->buffer_blocks = - (STp->buffer)->buffer_size / STp->block_size; - else - (STp->buffer)->buffer_blocks = 1; - (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; - - DEBC(printk(ST_DEB_MSG - "%s: Block size: %d, buffer size: %d (%d blocks).\n", name, - STp->block_size, (STp->buffer)->buffer_size, - (STp->buffer)->buffer_blocks)); - - if (STp->drv_write_prot) { - STp->write_prot = 1; - - DEBC(printk(ST_DEB_MSG "%s: Write protected\n", name)); - - if (do_wait && - ((st_flags & O_ACCMODE) == O_WRONLY || - (st_flags & O_ACCMODE) == O_RDWR)) { - retval = (-EROFS); - goto err_out; - } - } - - if (STp->can_partitions && STp->nbr_partitions < 1) { - /* This code is reached when the device is opened for the first time - after the driver has been initialized with tape in the drive and the - partition support has been enabled. */ - DEBC(printk(ST_DEB_MSG - "%s: Updating partition number in status.\n", name)); - if ((STp->partition = find_partition(STp)) < 0) { - retval = STp->partition; - goto err_out; - } - STp->new_partition = STp->partition; - STp->nbr_partitions = 1; /* This guess will be updated when necessary */ - } - - if (new_session) { /* Change the drive parameters for the new mode */ - STp->density_changed = STp->blksize_changed = 0; - STp->compression_changed = 0; - if (!(STm->defaults_for_writes) && - (retval = set_mode_densblk(STp, STm)) < 0) - goto err_out; - - if (STp->default_drvbuffer != 0xff) { - if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer)) - printk(KERN_WARNING - "%s: Can't set default drive buffering to %d.\n", - name, STp->default_drvbuffer); - } - } - - return CHKRES_READY; - - err_out: - return retval; -} - - - /* Open the device. Needs to take the BKL only because of incrementing the SCSI host - module count. */ -static int st_open(struct inode *inode, struct file *filp) -{ - int i, retval = (-EIO); - int resumed = 0; - struct scsi_tape *STp; - struct st_partstat *STps; - int dev = TAPE_NR(inode); - char *name; - - mutex_lock(&st_mutex); - /* - * We really want to do nonseekable_open(inode, filp); here, but some - * versions of tar incorrectly call lseek on tapes and bail out if that - * fails. So we disallow pread() and pwrite(), but permit lseeks. - */ - filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); - - if (!(STp = scsi_tape_get(dev))) { - mutex_unlock(&st_mutex); - return -ENXIO; - } - - write_lock(&st_dev_arr_lock); - filp->private_data = STp; - name = tape_name(STp); - - if (STp->in_use) { - write_unlock(&st_dev_arr_lock); - scsi_tape_put(STp); - mutex_unlock(&st_mutex); - DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) - return (-EBUSY); - } - - STp->in_use = 1; - write_unlock(&st_dev_arr_lock); - STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; - - if (scsi_autopm_get_device(STp->device) < 0) { - retval = -EIO; - goto err_out; - } - resumed = 1; - if (!scsi_block_when_processing_errors(STp->device)) { - retval = (-ENXIO); - goto err_out; - } - - /* See that we have at least a one page buffer available */ - if (!enlarge_buffer(STp->buffer, PAGE_SIZE, STp->restr_dma)) { - printk(KERN_WARNING "%s: Can't allocate one page tape buffer.\n", - name); - retval = (-EOVERFLOW); - goto err_out; - } - - (STp->buffer)->cleared = 0; - (STp->buffer)->writing = 0; - (STp->buffer)->syscall_result = 0; - - STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY); - - STp->dirty = 0; - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); - STps->rw = ST_IDLE; - } - STp->try_dio_now = STp->try_dio; - STp->recover_count = 0; - DEB( STp->nbr_waits = STp->nbr_finished = 0; - STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = 0; ) - - retval = check_tape(STp, filp); - if (retval < 0) - goto err_out; - if ((filp->f_flags & O_NONBLOCK) == 0 && - retval != CHKRES_READY) { - if (STp->ready == NO_TAPE) - retval = (-ENOMEDIUM); - else - retval = (-EIO); - goto err_out; - } - mutex_unlock(&st_mutex); - return 0; - - err_out: - normalize_buffer(STp->buffer); - STp->in_use = 0; - scsi_tape_put(STp); - if (resumed) - scsi_autopm_put_device(STp->device); - mutex_unlock(&st_mutex); - return retval; - -} - - -/* Flush the tape buffer before close */ -static int st_flush(struct file *filp, fl_owner_t id) -{ - int result = 0, result2; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; - struct scsi_tape *STp = filp->private_data; - struct st_modedef *STm = &(STp->modes[STp->current_mode]); - struct st_partstat *STps = &(STp->ps[STp->partition]); - char *name = tape_name(STp); - - if (file_count(filp) > 1) - return 0; - - if (STps->rw == ST_WRITING && !STp->pos_unknown) { - result = st_flush_write_buffer(STp); - if (result != 0 && result != (-ENOSPC)) - goto out; - } - - if (STp->can_partitions && - (result2 = switch_partition(STp)) < 0) { - DEBC(printk(ST_DEB_MSG - "%s: switch_partition at close failed.\n", name)); - if (result == 0) - result = result2; - goto out; - } - - DEBC( if (STp->nbr_requests) - printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d.\n", - name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages)); - - if (STps->rw == ST_WRITING && !STp->pos_unknown) { - struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; - - DEBC(printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n", - name, STp->nbr_waits, STp->nbr_finished); - ) - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_FILEMARKS; - if (STp->immediate_filemark) - cmd[1] = 1; - cmd[4] = 1 + STp->two_fm; - - SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, - STp->device->request_queue->rq_timeout, - MAX_WRITE_RETRIES, 1); - if (!SRpnt) { - result = (STp->buffer)->syscall_result; - goto out; - } - - if (STp->buffer->syscall_result == 0 || - (cmdstatp->have_sense && !cmdstatp->deferred && - (cmdstatp->flags & SENSE_EOM) && - (cmdstatp->sense_hdr.sense_key == NO_SENSE || - cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) && - (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) { - /* Write successful at EOM */ - st_release_request(SRpnt); - SRpnt = NULL; - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - if (STp->two_fm) - cross_eof(STp, 0); - STps->eof = ST_FM; - } - else { /* Write error */ - st_release_request(SRpnt); - SRpnt = NULL; - printk(KERN_ERR "%s: Error on write filemark.\n", name); - if (result == 0) - result = (-EIO); - } - - DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n", - name, cmd[4])); - } else if (!STp->rew_at_close) { - STps = &(STp->ps[STp->partition]); - if (!STm->sysv || STps->rw != ST_READING) { - if (STp->can_bsr) - result = flush_buffer(STp, 0); - else if (STps->eof == ST_FM_HIT) { - result = cross_eof(STp, 0); - if (result) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } else - STps->eof = ST_NOEOF; - } - } else if ((STps->eof == ST_NOEOF && - !(result = cross_eof(STp, 1))) || - STps->eof == ST_FM_HIT) { - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } - } - - out: - if (STp->rew_at_close) { - result2 = st_int_ioctl(STp, MTREW, 1); - if (result == 0) - result = result2; - } - return result; -} - - -/* Close the device and release it. BKL is not needed: this is the only thread - accessing this tape. */ -static int st_release(struct inode *inode, struct file *filp) -{ - int result = 0; - struct scsi_tape *STp = filp->private_data; - - if (STp->door_locked == ST_LOCKED_AUTO) - do_door_lock(STp, 0); - - normalize_buffer(STp->buffer); - write_lock(&st_dev_arr_lock); - STp->in_use = 0; - write_unlock(&st_dev_arr_lock); - scsi_autopm_put_device(STp->device); - scsi_tape_put(STp); - - return result; -} - -/* The checks common to both reading and writing */ -static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count) -{ - ssize_t retval = 0; - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - if (!scsi_block_when_processing_errors(STp->device)) { - retval = (-ENXIO); - goto out; - } - - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - retval = (-ENOMEDIUM); - else - retval = (-EIO); - goto out; - } - - if (! STp->modes[STp->current_mode].defined) { - retval = (-ENXIO); - goto out; - } - - - /* - * If there was a bus reset, block further access - * to this device. - */ - if (STp->pos_unknown) { - retval = (-EIO); - goto out; - } - - if (count == 0) - goto out; - - DEB( - if (!STp->in_use) { - printk(ST_DEB_MSG "%s: Incorrect device.\n", tape_name(STp)); - retval = (-EIO); - goto out; - } ) /* end DEB */ - - if (STp->can_partitions && - (retval = switch_partition(STp)) < 0) - goto out; - - if (STp->block_size == 0 && STp->max_block > 0 && - (count < STp->min_block || count > STp->max_block)) { - retval = (-EINVAL); - goto out; - } - - if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && - !do_door_lock(STp, 1)) - STp->door_locked = ST_LOCKED_AUTO; - - out: - return retval; -} - - -static int setup_buffering(struct scsi_tape *STp, const char __user *buf, - size_t count, int is_read) -{ - int i, bufsize, retval = 0; - struct st_buffer *STbp = STp->buffer; - - if (is_read) - i = STp->try_dio_now && try_rdio; - else - i = STp->try_dio_now && try_wdio; - - if (i && ((unsigned long)buf & queue_dma_alignment( - STp->device->request_queue)) == 0) { - i = sgl_map_user_pages(STbp, STbp->use_sg, (unsigned long)buf, - count, (is_read ? READ : WRITE)); - if (i > 0) { - STbp->do_dio = i; - STbp->buffer_bytes = 0; /* can be used as transfer counter */ - } - else - STbp->do_dio = 0; /* fall back to buffering with any error */ - STbp->sg_segs = STbp->do_dio; - DEB( - if (STbp->do_dio) { - STp->nbr_dio++; - STp->nbr_pages += STbp->do_dio; - } - ) - } else - STbp->do_dio = 0; - DEB( STp->nbr_requests++; ) - - if (!STbp->do_dio) { - if (STp->block_size) - bufsize = STp->block_size > st_fixed_buffer_size ? - STp->block_size : st_fixed_buffer_size; - else { - bufsize = count; - /* Make sure that data from previous user is not leaked even if - HBA does not return correct residual */ - if (is_read && STp->sili && !STbp->cleared) - clear_buffer(STbp); - } - - if (bufsize > STbp->buffer_size && - !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { - printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n", - tape_name(STp), bufsize); - retval = (-EOVERFLOW); - goto out; - } - if (STp->block_size) - STbp->buffer_blocks = bufsize / STp->block_size; - } - - out: - return retval; -} - - -/* Can be called more than once after each setup_buffer() */ -static void release_buffering(struct scsi_tape *STp, int is_read) -{ - struct st_buffer *STbp; - - STbp = STp->buffer; - if (STbp->do_dio) { - sgl_unmap_user_pages(STbp, STbp->do_dio, is_read); - STbp->do_dio = 0; - STbp->sg_segs = 0; - } -} - - -/* Write command */ -static ssize_t -st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) -{ - ssize_t total; - ssize_t i, do_count, blks, transfer; - ssize_t retval; - int undone, retry_eot = 0, scode; - int async_write; - unsigned char cmd[MAX_COMMAND_SIZE]; - const char __user *b_point; - struct st_request *SRpnt = NULL; - struct scsi_tape *STp = filp->private_data; - struct st_modedef *STm; - struct st_partstat *STps; - struct st_buffer *STbp; - char *name = tape_name(STp); - - if (mutex_lock_interruptible(&STp->lock)) - return -ERESTARTSYS; - - retval = rw_checks(STp, filp, count); - if (retval || count == 0) - goto out; - - /* Write must be integral number of blocks */ - if (STp->block_size != 0 && (count % STp->block_size) != 0) { - printk(KERN_WARNING "%s: Write not multiple of tape block size.\n", - name); - retval = (-EINVAL); - goto out; - } - - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - - if (STp->write_prot) { - retval = (-EACCES); - goto out; - } - - - if (STps->rw == ST_READING) { - retval = flush_buffer(STp, 0); - if (retval) - goto out; - STps->rw = ST_WRITING; - } else if (STps->rw != ST_WRITING && - STps->drv_file == 0 && STps->drv_block == 0) { - if ((retval = set_mode_densblk(STp, STm)) < 0) - goto out; - if (STm->default_compression != ST_DONT_TOUCH && - !(STp->compression_changed)) { - if (st_compression(STp, (STm->default_compression == ST_YES))) { - printk(KERN_WARNING "%s: Can't set default compression.\n", - name); - if (modes_defined) { - retval = (-EINVAL); - goto out; - } - } - } - } - - STbp = STp->buffer; - i = write_behind_check(STp); - if (i) { - if (i == -ENOSPC) - STps->eof = ST_EOM_OK; - else - STps->eof = ST_EOM_ERROR; - } - - if (STps->eof == ST_EOM_OK) { - STps->eof = ST_EOD_1; /* allow next write */ - retval = (-ENOSPC); - goto out; - } - else if (STps->eof == ST_EOM_ERROR) { - retval = (-EIO); - goto out; - } - - /* Check the buffer readability in cases where copy_user might catch - the problems after some tape movement. */ - if (STp->block_size != 0 && - !STbp->do_dio && - (copy_from_user(&i, buf, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0)) { - retval = (-EFAULT); - goto out; - } - - retval = setup_buffering(STp, buf, count, 0); - if (retval) - goto out; - - total = count; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = WRITE_6; - cmd[1] = (STp->block_size != 0); - - STps->rw = ST_WRITING; - - b_point = buf; - while (count > 0 && !retry_eot) { - - if (STbp->do_dio) { - do_count = count; - } - else { - if (STp->block_size == 0) - do_count = count; - else { - do_count = STbp->buffer_blocks * STp->block_size - - STbp->buffer_bytes; - if (do_count > count) - do_count = count; - } - - i = append_to_buffer(b_point, STbp, do_count); - if (i) { - retval = i; - goto out; - } - } - count -= do_count; - b_point += do_count; - - async_write = STp->block_size == 0 && !STbp->do_dio && - STm->do_async_writes && STps->eof < ST_EOM_OK; - - if (STp->block_size != 0 && STm->do_buffer_writes && - !(STp->try_dio_now && try_wdio) && STps->eof < ST_EOM_OK && - STbp->buffer_bytes < STbp->buffer_size) { - STp->dirty = 1; - /* Don't write a buffer that is not full enough. */ - if (!async_write && count == 0) - break; - } - - retry_write: - if (STp->block_size == 0) - blks = transfer = do_count; - else { - if (!STbp->do_dio) - blks = STbp->buffer_bytes; - else - blks = do_count; - blks /= STp->block_size; - transfer = blks * STp->block_size; - } - cmd[2] = blks >> 16; - cmd[3] = blks >> 8; - cmd[4] = blks; - - SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE, - STp->device->request_queue->rq_timeout, - MAX_WRITE_RETRIES, !async_write); - if (!SRpnt) { - retval = STbp->syscall_result; - goto out; - } - if (async_write && !STbp->syscall_result) { - STbp->writing = transfer; - STp->dirty = !(STbp->writing == - STbp->buffer_bytes); - SRpnt = NULL; /* Prevent releasing this request! */ - DEB( STp->write_pending = 1; ) - break; - } - - if (STbp->syscall_result != 0) { - struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; - - DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name)); - if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) { - scode = cmdstatp->sense_hdr.sense_key; - if (cmdstatp->remainder_valid) - undone = (int)cmdstatp->uremainder64; - else if (STp->block_size == 0 && - scode == VOLUME_OVERFLOW) - undone = transfer; - else - undone = 0; - if (STp->block_size != 0) - undone *= STp->block_size; - if (undone <= do_count) { - /* Only data from this write is not written */ - count += undone; - b_point -= undone; - do_count -= undone; - if (STp->block_size) - blks = (transfer - undone) / STp->block_size; - STps->eof = ST_EOM_OK; - /* Continue in fixed block mode if all written - in this request but still something left to write - (retval left to zero) - */ - if (STp->block_size == 0 || - undone > 0 || count == 0) - retval = (-ENOSPC); /* EOM within current request */ - DEBC(printk(ST_DEB_MSG - "%s: EOM with %d bytes unwritten.\n", - name, (int)count)); - } else { - /* EOT within data buffered earlier (possible only - in fixed block mode without direct i/o) */ - if (!retry_eot && !cmdstatp->deferred && - (scode == NO_SENSE || scode == RECOVERED_ERROR)) { - move_buffer_data(STp->buffer, transfer - undone); - retry_eot = 1; - if (STps->drv_block >= 0) { - STps->drv_block += (transfer - undone) / - STp->block_size; - } - STps->eof = ST_EOM_OK; - DEBC(printk(ST_DEB_MSG - "%s: Retry write of %d bytes at EOM.\n", - name, STp->buffer->buffer_bytes)); - goto retry_write; - } - else { - /* Either error within data buffered by driver or - failed retry */ - count -= do_count; - blks = do_count = 0; - STps->eof = ST_EOM_ERROR; - STps->drv_block = (-1); /* Too cautious? */ - retval = (-EIO); /* EOM for old data */ - DEBC(printk(ST_DEB_MSG - "%s: EOM with lost data.\n", - name)); - } - } - } else { - count += do_count; - STps->drv_block = (-1); /* Too cautious? */ - retval = STbp->syscall_result; - } - - } - - if (STps->drv_block >= 0) { - if (STp->block_size == 0) - STps->drv_block += (do_count > 0); - else - STps->drv_block += blks; - } - - STbp->buffer_bytes = 0; - STp->dirty = 0; - - if (retval || retry_eot) { - if (count < total) - retval = total - count; - goto out; - } - } - - if (STps->eof == ST_EOD_1) - STps->eof = ST_EOM_OK; - else if (STps->eof != ST_EOM_OK) - STps->eof = ST_NOEOF; - retval = total - count; - - out: - if (SRpnt != NULL) - st_release_request(SRpnt); - release_buffering(STp, 0); - mutex_unlock(&STp->lock); - - return retval; -} - -/* Read data from the tape. Returns zero in the normal case, one if the - eof status has changed, and the negative error code in case of a - fatal error. Otherwise updates the buffer and the eof state. - - Does release user buffer mapping if it is set. -*/ -static long read_tape(struct scsi_tape *STp, long count, - struct st_request ** aSRpnt) -{ - int transfer, blks, bytes; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; - struct st_modedef *STm; - struct st_partstat *STps; - struct st_buffer *STbp; - int retval = 0; - char *name = tape_name(STp); - - if (count == 0) - return 0; - - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - if (STps->eof == ST_FM_HIT) - return 1; - STbp = STp->buffer; - - if (STp->block_size == 0) - blks = bytes = count; - else { - if (!(STp->try_dio_now && try_rdio) && STm->do_read_ahead) { - blks = (STp->buffer)->buffer_blocks; - bytes = blks * STp->block_size; - } else { - bytes = count; - if (!STbp->do_dio && bytes > (STp->buffer)->buffer_size) - bytes = (STp->buffer)->buffer_size; - blks = bytes / STp->block_size; - bytes = blks * STp->block_size; - } - } - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = READ_6; - cmd[1] = (STp->block_size != 0); - if (!cmd[1] && STp->sili) - cmd[1] |= 2; - cmd[2] = blks >> 16; - cmd[3] = blks >> 8; - cmd[4] = blks; - - SRpnt = *aSRpnt; - SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE, - STp->device->request_queue->rq_timeout, - MAX_RETRIES, 1); - release_buffering(STp, 1); - *aSRpnt = SRpnt; - if (!SRpnt) - return STbp->syscall_result; - - STbp->read_pointer = 0; - STps->at_sm = 0; - - /* Something to check */ - if (STbp->syscall_result) { - struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; - - retval = 1; - DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", - name, - SRpnt->sense[0], SRpnt->sense[1], - SRpnt->sense[2], SRpnt->sense[3], - SRpnt->sense[4], SRpnt->sense[5], - SRpnt->sense[6], SRpnt->sense[7])); - if (cmdstatp->have_sense) { - - if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK) - cmdstatp->flags &= 0xcf; /* No need for EOM in this case */ - - if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */ - /* Compute the residual count */ - if (cmdstatp->remainder_valid) - transfer = (int)cmdstatp->uremainder64; - else - transfer = 0; - if (STp->block_size == 0 && - cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR) - transfer = bytes; - - if (cmdstatp->flags & SENSE_ILI) { /* ILI */ - if (STp->block_size == 0) { - if (transfer <= 0) { - if (transfer < 0) - printk(KERN_NOTICE - "%s: Failed to read %d byte block with %d byte transfer.\n", - name, bytes - transfer, bytes); - if (STps->drv_block >= 0) - STps->drv_block += 1; - STbp->buffer_bytes = 0; - return (-ENOMEM); - } - STbp->buffer_bytes = bytes - transfer; - } else { - st_release_request(SRpnt); - SRpnt = *aSRpnt = NULL; - if (transfer == blks) { /* We did not get anything, error */ - printk(KERN_NOTICE "%s: Incorrect block size.\n", name); - if (STps->drv_block >= 0) - STps->drv_block += blks - transfer + 1; - st_int_ioctl(STp, MTBSR, 1); - return (-EIO); - } - /* We have some data, deliver it */ - STbp->buffer_bytes = (blks - transfer) * - STp->block_size; - DEBC(printk(ST_DEB_MSG - "%s: ILI but enough data received %ld %d.\n", - name, count, STbp->buffer_bytes)); - if (STps->drv_block >= 0) - STps->drv_block += 1; - if (st_int_ioctl(STp, MTBSR, 1)) - return (-EIO); - } - } else if (cmdstatp->flags & SENSE_FMK) { /* FM overrides EOM */ - if (STps->eof != ST_FM_HIT) - STps->eof = ST_FM_HIT; - else - STps->eof = ST_EOD_2; - if (STp->block_size == 0) - STbp->buffer_bytes = 0; - else - STbp->buffer_bytes = - bytes - transfer * STp->block_size; - DEBC(printk(ST_DEB_MSG - "%s: EOF detected (%d bytes read).\n", - name, STbp->buffer_bytes)); - } else if (cmdstatp->flags & SENSE_EOM) { - if (STps->eof == ST_FM) - STps->eof = ST_EOD_1; - else - STps->eof = ST_EOM_OK; - if (STp->block_size == 0) - STbp->buffer_bytes = bytes - transfer; - else - STbp->buffer_bytes = - bytes - transfer * STp->block_size; - - DEBC(printk(ST_DEB_MSG "%s: EOM detected (%d bytes read).\n", - name, STbp->buffer_bytes)); - } - } - /* end of EOF, EOM, ILI test */ - else { /* nonzero sense key */ - DEBC(printk(ST_DEB_MSG - "%s: Tape error while reading.\n", name)); - STps->drv_block = (-1); - if (STps->eof == ST_FM && - cmdstatp->sense_hdr.sense_key == BLANK_CHECK) { - DEBC(printk(ST_DEB_MSG - "%s: Zero returned for first BLANK CHECK after EOF.\n", - name)); - STps->eof = ST_EOD_2; /* First BLANK_CHECK after FM */ - } else /* Some other extended sense code */ - retval = (-EIO); - } - - if (STbp->buffer_bytes < 0) /* Caused by bogus sense data */ - STbp->buffer_bytes = 0; - } - /* End of extended sense test */ - else { /* Non-extended sense */ - retval = STbp->syscall_result; - } - - } - /* End of error handling */ - else { /* Read successful */ - STbp->buffer_bytes = bytes; - if (STp->sili) /* In fixed block mode residual is always zero here */ - STbp->buffer_bytes -= STp->buffer->cmdstat.residual; - } - - if (STps->drv_block >= 0) { - if (STp->block_size == 0) - STps->drv_block++; - else - STps->drv_block += STbp->buffer_bytes / STp->block_size; - } - return retval; -} - - -/* Read command */ -static ssize_t -st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) -{ - ssize_t total; - ssize_t retval = 0; - ssize_t i, transfer; - int special, do_dio = 0; - struct st_request *SRpnt = NULL; - struct scsi_tape *STp = filp->private_data; - struct st_modedef *STm; - struct st_partstat *STps; - struct st_buffer *STbp = STp->buffer; - DEB( char *name = tape_name(STp); ) - - if (mutex_lock_interruptible(&STp->lock)) - return -ERESTARTSYS; - - retval = rw_checks(STp, filp, count); - if (retval || count == 0) - goto out; - - STm = &(STp->modes[STp->current_mode]); - if (STp->block_size != 0 && (count % STp->block_size) != 0) { - if (!STm->do_read_ahead) { - retval = (-EINVAL); /* Read must be integral number of blocks */ - goto out; - } - STp->try_dio_now = 0; /* Direct i/o can't handle split blocks */ - } - - STps = &(STp->ps[STp->partition]); - if (STps->rw == ST_WRITING) { - retval = flush_buffer(STp, 0); - if (retval) - goto out; - STps->rw = ST_READING; - } - DEB( - if (debugging && STps->eof != ST_NOEOF) - printk(ST_DEB_MSG "%s: EOF/EOM flag up (%d). Bytes %d\n", name, - STps->eof, STbp->buffer_bytes); - ) /* end DEB */ - - retval = setup_buffering(STp, buf, count, 1); - if (retval) - goto out; - do_dio = STbp->do_dio; - - if (STbp->buffer_bytes == 0 && - STps->eof >= ST_EOD_1) { - if (STps->eof < ST_EOD) { - STps->eof += 1; - retval = 0; - goto out; - } - retval = (-EIO); /* EOM or Blank Check */ - goto out; - } - - if (do_dio) { - /* Check the buffer writability before any tape movement. Don't alter - buffer data. */ - if (copy_from_user(&i, buf, 1) != 0 || - copy_to_user(buf, &i, 1) != 0 || - copy_from_user(&i, buf + count - 1, 1) != 0 || - copy_to_user(buf + count - 1, &i, 1) != 0) { - retval = (-EFAULT); - goto out; - } - } - - STps->rw = ST_READING; - - - /* Loop until enough data in buffer or a special condition found */ - for (total = 0, special = 0; total < count && !special;) { - - /* Get new data if the buffer is empty */ - if (STbp->buffer_bytes == 0) { - special = read_tape(STp, count - total, &SRpnt); - if (special < 0) { /* No need to continue read */ - retval = special; - goto out; - } - } - - /* Move the data from driver buffer to user buffer */ - if (STbp->buffer_bytes > 0) { - DEB( - if (debugging && STps->eof != ST_NOEOF) - printk(ST_DEB_MSG - "%s: EOF up (%d). Left %d, needed %d.\n", name, - STps->eof, STbp->buffer_bytes, - (int)(count - total)); - ) /* end DEB */ - transfer = STbp->buffer_bytes < count - total ? - STbp->buffer_bytes : count - total; - if (!do_dio) { - i = from_buffer(STbp, buf, transfer); - if (i) { - retval = i; - goto out; - } - } - buf += transfer; - total += transfer; - } - - if (STp->block_size == 0) - break; /* Read only one variable length block */ - - } /* for (total = 0, special = 0; - total < count && !special; ) */ - - /* Change the eof state if no data from tape or buffer */ - if (total == 0) { - if (STps->eof == ST_FM_HIT) { - STps->eof = ST_FM; - STps->drv_block = 0; - if (STps->drv_file >= 0) - STps->drv_file++; - } else if (STps->eof == ST_EOD_1) { - STps->eof = ST_EOD_2; - STps->drv_block = 0; - if (STps->drv_file >= 0) - STps->drv_file++; - } else if (STps->eof == ST_EOD_2) - STps->eof = ST_EOD; - } else if (STps->eof == ST_FM) - STps->eof = ST_NOEOF; - retval = total; - - out: - if (SRpnt != NULL) { - st_release_request(SRpnt); - SRpnt = NULL; - } - if (do_dio) { - release_buffering(STp, 1); - STbp->buffer_bytes = 0; - } - mutex_unlock(&STp->lock); - - return retval; -} - - - -DEB( -/* Set the driver options */ -static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char *name) -{ - if (debugging) { - printk(KERN_INFO - "%s: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", - name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, - STm->do_read_ahead); - printk(KERN_INFO - "%s: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", - name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); - printk(KERN_INFO - "%s: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", - name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, - STp->scsi2_logical); - printk(KERN_INFO - "%s: sysv: %d nowait: %d sili: %d nowait_filemark: %d\n", - name, STm->sysv, STp->immediate, STp->sili, - STp->immediate_filemark); - printk(KERN_INFO "%s: debugging: %d\n", - name, debugging); - } -} - ) - - -static int st_set_options(struct scsi_tape *STp, long options) -{ - int value; - long code; - struct st_modedef *STm; - char *name = tape_name(STp); - struct cdev *cd0, *cd1; - - STm = &(STp->modes[STp->current_mode]); - if (!STm->defined) { - cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1]; - memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef)); - STm->cdevs[0] = cd0; STm->cdevs[1] = cd1; - modes_defined = 1; - DEBC(printk(ST_DEB_MSG - "%s: Initialized mode %d definition from mode 0\n", - name, STp->current_mode)); - } - - code = options & MT_ST_OPTIONS; - if (code == MT_ST_BOOLEANS) { - STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; - STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; - STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; - STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; - STp->two_fm = (options & MT_ST_TWO_FM) != 0; - STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; - STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; - STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; - STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; - if ((STp->device)->scsi_level >= SCSI_2) - STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; - STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; - STp->immediate = (options & MT_ST_NOWAIT) != 0; - STp->immediate_filemark = (options & MT_ST_NOWAIT_EOF) != 0; - STm->sysv = (options & MT_ST_SYSV) != 0; - STp->sili = (options & MT_ST_SILI) != 0; - DEB( debugging = (options & MT_ST_DEBUGGING) != 0; - st_log_options(STp, STm, name); ) - } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { - value = (code == MT_ST_SETBOOLEANS); - if ((options & MT_ST_BUFFER_WRITES) != 0) - STm->do_buffer_writes = value; - if ((options & MT_ST_ASYNC_WRITES) != 0) - STm->do_async_writes = value; - if ((options & MT_ST_DEF_WRITES) != 0) - STm->defaults_for_writes = value; - if ((options & MT_ST_READ_AHEAD) != 0) - STm->do_read_ahead = value; - if ((options & MT_ST_TWO_FM) != 0) - STp->two_fm = value; - if ((options & MT_ST_FAST_MTEOM) != 0) - STp->fast_mteom = value; - if ((options & MT_ST_AUTO_LOCK) != 0) - STp->do_auto_lock = value; - if ((options & MT_ST_CAN_BSR) != 0) - STp->can_bsr = value; - if ((options & MT_ST_NO_BLKLIMS) != 0) - STp->omit_blklims = value; - if ((STp->device)->scsi_level >= SCSI_2 && - (options & MT_ST_CAN_PARTITIONS) != 0) - STp->can_partitions = value; - if ((options & MT_ST_SCSI2LOGICAL) != 0) - STp->scsi2_logical = value; - if ((options & MT_ST_NOWAIT) != 0) - STp->immediate = value; - if ((options & MT_ST_NOWAIT_EOF) != 0) - STp->immediate_filemark = value; - if ((options & MT_ST_SYSV) != 0) - STm->sysv = value; - if ((options & MT_ST_SILI) != 0) - STp->sili = value; - DEB( - if ((options & MT_ST_DEBUGGING) != 0) - debugging = value; - st_log_options(STp, STm, name); ) - } else if (code == MT_ST_WRITE_THRESHOLD) { - /* Retained for compatibility */ - } else if (code == MT_ST_DEF_BLKSIZE) { - value = (options & ~MT_ST_OPTIONS); - if (value == ~MT_ST_OPTIONS) { - STm->default_blksize = (-1); - DEBC( printk(KERN_INFO "%s: Default block size disabled.\n", name)); - } else { - STm->default_blksize = value; - DEBC( printk(KERN_INFO "%s: Default block size set to %d bytes.\n", - name, STm->default_blksize)); - if (STp->ready == ST_READY) { - STp->blksize_changed = 0; - set_mode_densblk(STp, STm); - } - } - } else if (code == MT_ST_TIMEOUTS) { - value = (options & ~MT_ST_OPTIONS); - if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { - STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; - DEBC( printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name, - (value & ~MT_ST_SET_LONG_TIMEOUT))); - } else { - blk_queue_rq_timeout(STp->device->request_queue, - value * HZ); - DEBC( printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n", - name, value) ); - } - } else if (code == MT_ST_SET_CLN) { - value = (options & ~MT_ST_OPTIONS) & 0xff; - if (value != 0 && - (value < EXTENDED_SENSE_START || - value >= SCSI_SENSE_BUFFERSIZE)) - return (-EINVAL); - STp->cln_mode = value; - STp->cln_sense_mask = (options >> 8) & 0xff; - STp->cln_sense_value = (options >> 16) & 0xff; - printk(KERN_INFO - "%s: Cleaning request mode %d, mask %02x, value %02x\n", - name, value, STp->cln_sense_mask, STp->cln_sense_value); - } else if (code == MT_ST_DEF_OPTIONS) { - code = (options & ~MT_ST_CLEAR_DEFAULT); - value = (options & MT_ST_CLEAR_DEFAULT); - if (code == MT_ST_DEF_DENSITY) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_density = (-1); - DEBC( printk(KERN_INFO "%s: Density default disabled.\n", - name)); - } else { - STm->default_density = value & 0xff; - DEBC( printk(KERN_INFO "%s: Density default set to %x\n", - name, STm->default_density)); - if (STp->ready == ST_READY) { - STp->density_changed = 0; - set_mode_densblk(STp, STm); - } - } - } else if (code == MT_ST_DEF_DRVBUFFER) { - if (value == MT_ST_CLEAR_DEFAULT) { - STp->default_drvbuffer = 0xff; - DEBC( printk(KERN_INFO - "%s: Drive buffer default disabled.\n", name)); - } else { - STp->default_drvbuffer = value & 7; - DEBC( printk(KERN_INFO - "%s: Drive buffer default set to %x\n", - name, STp->default_drvbuffer)); - if (STp->ready == ST_READY) - st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer); - } - } else if (code == MT_ST_DEF_COMPRESSION) { - if (value == MT_ST_CLEAR_DEFAULT) { - STm->default_compression = ST_DONT_TOUCH; - DEBC( printk(KERN_INFO - "%s: Compression default disabled.\n", name)); - } else { - if ((value & 0xff00) != 0) { - STp->c_algo = (value & 0xff00) >> 8; - DEBC( printk(KERN_INFO "%s: Compression algorithm set to 0x%x.\n", - name, STp->c_algo)); - } - if ((value & 0xff) != 0xff) { - STm->default_compression = (value & 1 ? ST_YES : ST_NO); - DEBC( printk(KERN_INFO "%s: Compression default set to %x\n", - name, (value & 1))); - if (STp->ready == ST_READY) { - STp->compression_changed = 0; - st_compression(STp, (STm->default_compression == ST_YES)); - } - } - } - } - } else - return (-EIO); - - return 0; -} - -#define MODE_HEADER_LENGTH 4 - -/* Mode header and page byte offsets */ -#define MH_OFF_DATA_LENGTH 0 -#define MH_OFF_MEDIUM_TYPE 1 -#define MH_OFF_DEV_SPECIFIC 2 -#define MH_OFF_BDESCS_LENGTH 3 -#define MP_OFF_PAGE_NBR 0 -#define MP_OFF_PAGE_LENGTH 1 - -/* Mode header and page bit masks */ -#define MH_BIT_WP 0x80 -#define MP_MSK_PAGE_NBR 0x3f - -/* Don't return block descriptors */ -#define MODE_SENSE_OMIT_BDESCS 0x08 - -#define MODE_SELECT_PAGE_FORMAT 0x10 - -/* Read a mode page into the tape buffer. The block descriptors are included - if incl_block_descs is true. The page control is ored to the page number - parameter, if necessary. */ -static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs) -{ - unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SENSE; - if (omit_block_descs) - cmd[1] = MODE_SENSE_OMIT_BDESCS; - cmd[2] = page; - cmd[4] = 255; - - SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_FROM_DEVICE, - STp->device->request_queue->rq_timeout, 0, 1); - if (SRpnt == NULL) - return (STp->buffer)->syscall_result; - - st_release_request(SRpnt); - - return STp->buffer->syscall_result; -} - - -/* Send the mode page in the tape buffer to the drive. Assumes that the mode data - in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */ -static int write_mode_page(struct scsi_tape *STp, int page, int slow) -{ - int pgo; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; - int timeout; - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = MODE_SELECT; - cmd[1] = MODE_SELECT_PAGE_FORMAT; - pgo = MODE_HEADER_LENGTH + (STp->buffer)->b_data[MH_OFF_BDESCS_LENGTH]; - cmd[4] = pgo + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_LENGTH] + 2; - - /* Clear reserved fields */ - (STp->buffer)->b_data[MH_OFF_DATA_LENGTH] = 0; - (STp->buffer)->b_data[MH_OFF_MEDIUM_TYPE] = 0; - (STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP; - (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR; - - timeout = slow ? - STp->long_timeout : STp->device->request_queue->rq_timeout; - SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_TO_DEVICE, - timeout, 0, 1); - if (SRpnt == NULL) - return (STp->buffer)->syscall_result; - - st_release_request(SRpnt); - - return STp->buffer->syscall_result; -} - - -#define COMPRESSION_PAGE 0x0f -#define COMPRESSION_PAGE_LENGTH 16 - -#define CP_OFF_DCE_DCC 2 -#define CP_OFF_C_ALGO 7 - -#define DCE_MASK 0x80 -#define DCC_MASK 0x40 -#define RED_MASK 0x60 - - -/* Control the compression with mode page 15. Algorithm not changed if zero. - - The block descriptors are read and written because Sony SDT-7000 does not - work without this (suggestion from Michael Schaefer ). - Including block descriptors should not cause any harm to other drives. */ - -static int st_compression(struct scsi_tape * STp, int state) -{ - int retval; - int mpoffs; /* Offset to mode page start */ - unsigned char *b_data = (STp->buffer)->b_data; - DEB( char *name = tape_name(STp); ) - - if (STp->ready != ST_READY) - return (-EIO); - - /* Read the current page contents */ - retval = read_mode_page(STp, COMPRESSION_PAGE, 0); - if (retval) { - DEBC(printk(ST_DEB_MSG "%s: Compression mode page not supported.\n", - name)); - return (-EIO); - } - - mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH]; - DEBC(printk(ST_DEB_MSG "%s: Compression state is %d.\n", name, - (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0))); - - /* Check if compression can be changed */ - if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) { - DEBC(printk(ST_DEB_MSG "%s: Compression not supported.\n", name)); - return (-EIO); - } - - /* Do the change */ - if (state) { - b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK; - if (STp->c_algo != 0) - b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo; - } - else { - b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK; - if (STp->c_algo != 0) - b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */ - } - - retval = write_mode_page(STp, COMPRESSION_PAGE, 0); - if (retval) { - DEBC(printk(ST_DEB_MSG "%s: Compression change failed.\n", name)); - return (-EIO); - } - DEBC(printk(ST_DEB_MSG "%s: Compression state changed to %d.\n", - name, state)); - - STp->compression_changed = 1; - return 0; -} - - -/* Process the load and unload commands (does unload if the load code is zero) */ -static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_code) -{ - int retval = (-EIO), timeout; - DEB( char *name = tape_name(STp); ) - unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_partstat *STps; - struct st_request *SRpnt; - - if (STp->ready != ST_READY && !load_code) { - if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); - else - return (-EIO); - } - - memset(cmd, 0, MAX_COMMAND_SIZE); - cmd[0] = START_STOP; - if (load_code) - cmd[4] |= 1; - /* - * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A - */ - if (load_code >= 1 + MT_ST_HPLOADER_OFFSET - && load_code <= 6 + MT_ST_HPLOADER_OFFSET) { - DEBC(printk(ST_DEB_MSG "%s: Enhanced %sload slot %2d.\n", - name, (cmd[4]) ? "" : "un", - load_code - MT_ST_HPLOADER_OFFSET)); - cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */ - } - if (STp->immediate) { - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->device->request_queue->rq_timeout; - } - else - timeout = STp->long_timeout; - - DEBC( - if (!load_code) - printk(ST_DEB_MSG "%s: Unloading tape.\n", name); - else - printk(ST_DEB_MSG "%s: Loading tape.\n", name); - ); - - SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, - timeout, MAX_RETRIES, 1); - if (!SRpnt) - return (STp->buffer)->syscall_result; - - retval = (STp->buffer)->syscall_result; - st_release_request(SRpnt); - - if (!retval) { /* SCSI command successful */ - - if (!load_code) { - STp->rew_at_close = 0; - STp->ready = ST_NO_TAPE; - } - else { - STp->rew_at_close = STp->autorew_dev; - retval = check_tape(STp, filp); - if (retval > 0) - retval = 0; - } - } - else { - STps = &(STp->ps[STp->partition]); - STps->drv_file = STps->drv_block = (-1); - } - - return retval; -} - -#if DEBUG -#define ST_DEB_FORWARD 0 -#define ST_DEB_BACKWARD 1 -static void deb_space_print(char *name, int direction, char *units, unsigned char *cmd) -{ - s32 sc; - - sc = cmd[2] & 0x80 ? 0xff000000 : 0; - sc |= (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; - if (direction) - sc = -sc; - printk(ST_DEB_MSG "%s: Spacing tape %s over %d %s.\n", name, - direction ? "backward" : "forward", sc, units); -} -#endif - - -/* Internal ioctl function */ -static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg) -{ - int timeout; - long ltmp; - int ioctl_result; - int chg_eof = 1; - unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; - struct st_partstat *STps; - int fileno, blkno, at_sm, undone; - int datalen = 0, direction = DMA_NONE; - char *name = tape_name(STp); - - WARN_ON(STp->buffer->do_dio != 0); - if (STp->ready != ST_READY) { - if (STp->ready == ST_NO_TAPE) - return (-ENOMEDIUM); - else - return (-EIO); - } - timeout = STp->long_timeout; - STps = &(STp->ps[STp->partition]); - fileno = STps->drv_file; - blkno = STps->drv_block; - at_sm = STps->at_sm; - - memset(cmd, 0, MAX_COMMAND_SIZE); - switch (cmd_in) { - case MTFSFM: - chg_eof = 0; /* Changed from the FSF after this */ - case MTFSF: - cmd[0] = SPACE; - cmd[1] = 0x01; /* Space FileMarks */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; - DEBC(deb_space_print(name, ST_DEB_FORWARD, "filemarks", cmd);) - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm &= (arg == 0); - break; - case MTBSFM: - chg_eof = 0; /* Changed from the FSF after this */ - case MTBSF: - cmd[0] = SPACE; - cmd[1] = 0x01; /* Space FileMarks */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; - DEBC(deb_space_print(name, ST_DEB_BACKWARD, "filemarks", cmd);) - if (fileno >= 0) - fileno -= arg; - blkno = (-1); /* We can't know the block number */ - at_sm &= (arg == 0); - break; - case MTFSR: - cmd[0] = SPACE; - cmd[1] = 0x00; /* Space Blocks */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; - DEBC(deb_space_print(name, ST_DEB_FORWARD, "blocks", cmd);) - if (blkno >= 0) - blkno += arg; - at_sm &= (arg == 0); - break; - case MTBSR: - cmd[0] = SPACE; - cmd[1] = 0x00; /* Space Blocks */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; - DEBC(deb_space_print(name, ST_DEB_BACKWARD, "blocks", cmd);) - if (blkno >= 0) - blkno -= arg; - at_sm &= (arg == 0); - break; - case MTFSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; - DEBC(deb_space_print(name, ST_DEB_FORWARD, "setmarks", cmd);) - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTBSS: - cmd[0] = SPACE; - cmd[1] = 0x04; /* Space Setmarks */ - ltmp = (-arg); - cmd[2] = (ltmp >> 16); - cmd[3] = (ltmp >> 8); - cmd[4] = ltmp; - DEBC(deb_space_print(name, ST_DEB_BACKWARD, "setmarks", cmd);) - if (arg != 0) { - blkno = fileno = (-1); - at_sm = 1; - } - break; - case MTWEOF: - case MTWEOFI: - case MTWSM: - if (STp->write_prot) - return (-EACCES); - cmd[0] = WRITE_FILEMARKS; - if (cmd_in == MTWSM) - cmd[1] = 2; - if (cmd_in == MTWEOFI || - (cmd_in == MTWEOF && STp->immediate_filemark)) - cmd[1] |= 1; - cmd[2] = (arg >> 16); - cmd[3] = (arg >> 8); - cmd[4] = arg; - timeout = STp->device->request_queue->rq_timeout; - DEBC( - if (cmd_in != MTWSM) - printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - else - printk(ST_DEB_MSG "%s: Writing %d setmarks.\n", name, - cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); - ) - if (fileno >= 0) - fileno += arg; - blkno = 0; - at_sm = (cmd_in == MTWSM); - break; - case MTREW: - cmd[0] = REZERO_UNIT; - if (STp->immediate) { - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->device->request_queue->rq_timeout; - } - DEBC(printk(ST_DEB_MSG "%s: Rewinding tape.\n", name)); - fileno = blkno = at_sm = 0; - break; - case MTNOP: - DEBC(printk(ST_DEB_MSG "%s: No op on tape.\n", name)); - return 0; /* Should do something ? */ - break; - case MTRETEN: - cmd[0] = START_STOP; - if (STp->immediate) { - cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->device->request_queue->rq_timeout; - } - cmd[4] = 3; - DEBC(printk(ST_DEB_MSG "%s: Retensioning tape.\n", name)); - fileno = blkno = at_sm = 0; - break; - case MTEOM: - if (!STp->fast_mteom) { - /* space to the end of tape */ - ioctl_result = st_int_ioctl(STp, MTFSF, 0x7fffff); - fileno = STps->drv_file; - if (STps->eof >= ST_EOD_1) - return 0; - /* The next lines would hide the number of spaced FileMarks - That's why I inserted the previous lines. I had no luck - with detecting EOM with FSF, so we go now to EOM. - Joerg Weule */ - } else - fileno = (-1); - cmd[0] = SPACE; - cmd[1] = 3; - DEBC(printk(ST_DEB_MSG "%s: Spacing to end of recorded medium.\n", - name)); - blkno = -1; - at_sm = 0; - break; - case MTERASE: - if (STp->write_prot) - return (-EACCES); - cmd[0] = ERASE; - cmd[1] = (arg ? 1 : 0); /* Long erase with non-zero argument */ - if (STp->immediate) { - cmd[1] |= 2; /* Don't wait for completion */ - timeout = STp->device->request_queue->rq_timeout; - } - else - timeout = STp->long_timeout * 8; - - DEBC(printk(ST_DEB_MSG "%s: Erasing tape.\n", name)); - fileno = blkno = at_sm = 0; - break; - case MTSETBLK: /* Set block length */ - case MTSETDENSITY: /* Set tape density */ - case MTSETDRVBUFFER: /* Set drive buffering */ - case SET_DENS_AND_BLK: /* Set density and block size */ - chg_eof = 0; - if (STp->dirty || (STp->buffer)->buffer_bytes != 0) - return (-EIO); /* Not allowed if data in buffer */ - if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && - (arg & MT_ST_BLKSIZE_MASK) != 0 && - STp->max_block > 0 && - ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block || - (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) { - printk(KERN_WARNING "%s: Illegal block size.\n", name); - return (-EINVAL); - } - cmd[0] = MODE_SELECT; - if ((STp->use_pf & USE_PF)) - cmd[1] = MODE_SELECT_PAGE_FORMAT; - cmd[4] = datalen = 12; - direction = DMA_TO_DEVICE; - - memset((STp->buffer)->b_data, 0, 12); - if (cmd_in == MTSETDRVBUFFER) - (STp->buffer)->b_data[2] = (arg & 7) << 4; - else - (STp->buffer)->b_data[2] = - STp->drv_buffer << 4; - (STp->buffer)->b_data[3] = 8; /* block descriptor length */ - if (cmd_in == MTSETDENSITY) { - (STp->buffer)->b_data[4] = arg; - STp->density_changed = 1; /* At least we tried ;-) */ - } else if (cmd_in == SET_DENS_AND_BLK) - (STp->buffer)->b_data[4] = arg >> 24; - else - (STp->buffer)->b_data[4] = STp->density; - if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { - ltmp = arg & MT_ST_BLKSIZE_MASK; - if (cmd_in == MTSETBLK) - STp->blksize_changed = 1; /* At least we tried ;-) */ - } else - ltmp = STp->block_size; - (STp->buffer)->b_data[9] = (ltmp >> 16); - (STp->buffer)->b_data[10] = (ltmp >> 8); - (STp->buffer)->b_data[11] = ltmp; - timeout = STp->device->request_queue->rq_timeout; - DEBC( - if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) - printk(ST_DEB_MSG - "%s: Setting block size to %d bytes.\n", name, - (STp->buffer)->b_data[9] * 65536 + - (STp->buffer)->b_data[10] * 256 + - (STp->buffer)->b_data[11]); - if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK) - printk(ST_DEB_MSG - "%s: Setting density code to %x.\n", name, - (STp->buffer)->b_data[4]); - if (cmd_in == MTSETDRVBUFFER) - printk(ST_DEB_MSG - "%s: Setting drive buffer code to %d.\n", name, - ((STp->buffer)->b_data[2] >> 4) & 7); - ) - break; - default: - return (-ENOSYS); - } - - SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction, - timeout, MAX_RETRIES, 1); - if (!SRpnt) - return (STp->buffer)->syscall_result; - - ioctl_result = (STp->buffer)->syscall_result; - - if (!ioctl_result) { /* SCSI command successful */ - st_release_request(SRpnt); - SRpnt = NULL; - STps->drv_block = blkno; - STps->drv_file = fileno; - STps->at_sm = at_sm; - - if (cmd_in == MTBSFM) - ioctl_result = st_int_ioctl(STp, MTFSF, 1); - else if (cmd_in == MTFSFM) - ioctl_result = st_int_ioctl(STp, MTBSF, 1); - - if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { - STp->block_size = arg & MT_ST_BLKSIZE_MASK; - if (STp->block_size != 0) { - (STp->buffer)->buffer_blocks = - (STp->buffer)->buffer_size / STp->block_size; - } - (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; - if (cmd_in == SET_DENS_AND_BLK) - STp->density = arg >> MT_ST_DENSITY_SHIFT; - } else if (cmd_in == MTSETDRVBUFFER) - STp->drv_buffer = (arg & 7); - else if (cmd_in == MTSETDENSITY) - STp->density = arg; - - if (cmd_in == MTEOM) - STps->eof = ST_EOD; - else if (cmd_in == MTFSF) - STps->eof = ST_FM; - else if (chg_eof) - STps->eof = ST_NOEOF; - - if (cmd_in == MTWEOF || cmd_in == MTWEOFI) - STps->rw = ST_IDLE; /* prevent automatic WEOF at close */ - } else { /* SCSI command was not completely successful. Don't return - from this block without releasing the SCSI command block! */ - struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; - - if (cmdstatp->flags & SENSE_EOM) { - if (cmd_in != MTBSF && cmd_in != MTBSFM && - cmd_in != MTBSR && cmd_in != MTBSS) - STps->eof = ST_EOM_OK; - STps->drv_block = 0; - } - - if (cmdstatp->remainder_valid) - undone = (int)cmdstatp->uremainder64; - else - undone = 0; - - if ((cmd_in == MTWEOF || cmd_in == MTWEOFI) && - cmdstatp->have_sense && - (cmdstatp->flags & SENSE_EOM)) { - if (cmdstatp->sense_hdr.sense_key == NO_SENSE || - cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) { - ioctl_result = 0; /* EOF(s) written successfully at EOM */ - STps->eof = ST_NOEOF; - } else { /* Writing EOF(s) failed */ - if (fileno >= 0) - fileno -= undone; - if (undone < arg) - STps->eof = ST_NOEOF; - } - STps->drv_file = fileno; - } else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) { - if (fileno >= 0) - STps->drv_file = fileno - undone; - else - STps->drv_file = fileno; - STps->drv_block = -1; - STps->eof = ST_NOEOF; - } else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) { - if (arg > 0 && undone < 0) /* Some drives get this wrong */ - undone = (-undone); - if (STps->drv_file >= 0) - STps->drv_file = fileno + undone; - STps->drv_block = 0; - STps->eof = ST_NOEOF; - } else if (cmd_in == MTFSR) { - if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */ - if (STps->drv_file >= 0) - STps->drv_file++; - STps->drv_block = 0; - STps->eof = ST_FM; - } else { - if (blkno >= undone) - STps->drv_block = blkno - undone; - else - STps->drv_block = (-1); - STps->eof = ST_NOEOF; - } - } else if (cmd_in == MTBSR) { - if (cmdstatp->flags & SENSE_FMK) { /* Hit filemark */ - STps->drv_file--; - STps->drv_block = (-1); - } else { - if (arg > 0 && undone < 0) /* Some drives get this wrong */ - undone = (-undone); - if (STps->drv_block >= 0) - STps->drv_block = blkno + undone; - } - STps->eof = ST_NOEOF; - } else if (cmd_in == MTEOM) { - STps->drv_file = (-1); - STps->drv_block = (-1); - STps->eof = ST_EOD; - } else if (cmd_in == MTSETBLK || - cmd_in == MTSETDENSITY || - cmd_in == MTSETDRVBUFFER || - cmd_in == SET_DENS_AND_BLK) { - if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST && - !(STp->use_pf & PF_TESTED)) { - /* Try the other possible state of Page Format if not - already tried */ - STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED; - st_release_request(SRpnt); - SRpnt = NULL; - return st_int_ioctl(STp, cmd_in, arg); - } - } else if (chg_eof) - STps->eof = ST_NOEOF; - - if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK) - STps->eof = ST_EOD; - - st_release_request(SRpnt); - SRpnt = NULL; - } - - return ioctl_result; -} - - -/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc - structure. */ - -static int get_location(struct scsi_tape *STp, unsigned int *block, int *partition, - int logical) -{ - int result; - unsigned char scmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; - DEB( char *name = tape_name(STp); ) - - if (STp->ready != ST_READY) - return (-EIO); - - memset(scmd, 0, MAX_COMMAND_SIZE); - if ((STp->device)->scsi_level < SCSI_2) { - scmd[0] = QFA_REQUEST_BLOCK; - scmd[4] = 3; - } else { - scmd[0] = READ_POSITION; - if (!logical && !STp->scsi2_logical) - scmd[1] = 1; - } - SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE, - STp->device->request_queue->rq_timeout, - MAX_READY_RETRIES, 1); - if (!SRpnt) - return (STp->buffer)->syscall_result; - - if ((STp->buffer)->syscall_result != 0 || - (STp->device->scsi_level >= SCSI_2 && - ((STp->buffer)->b_data[0] & 4) != 0)) { - *block = *partition = 0; - DEBC(printk(ST_DEB_MSG "%s: Can't read tape position.\n", name)); - result = (-EIO); - } else { - result = 0; - if ((STp->device)->scsi_level < SCSI_2) { - *block = ((STp->buffer)->b_data[0] << 16) - + ((STp->buffer)->b_data[1] << 8) - + (STp->buffer)->b_data[2]; - *partition = 0; - } else { - *block = ((STp->buffer)->b_data[4] << 24) - + ((STp->buffer)->b_data[5] << 16) - + ((STp->buffer)->b_data[6] << 8) - + (STp->buffer)->b_data[7]; - *partition = (STp->buffer)->b_data[1]; - if (((STp->buffer)->b_data[0] & 0x80) && - (STp->buffer)->b_data[1] == 0) /* BOP of partition 0 */ - STp->ps[0].drv_block = STp->ps[0].drv_file = 0; - } - DEBC(printk(ST_DEB_MSG "%s: Got tape pos. blk %d part %d.\n", name, - *block, *partition)); - } - st_release_request(SRpnt); - SRpnt = NULL; - - return result; -} - - -/* Set the tape block and partition. Negative partition means that only the - block should be set in vendor specific way. */ -static int set_location(struct scsi_tape *STp, unsigned int block, int partition, - int logical) -{ - struct st_partstat *STps; - int result, p; - unsigned int blk; - int timeout; - unsigned char scmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt; - DEB( char *name = tape_name(STp); ) - - if (STp->ready != ST_READY) - return (-EIO); - timeout = STp->long_timeout; - STps = &(STp->ps[STp->partition]); - - DEBC(printk(ST_DEB_MSG "%s: Setting block to %d and partition to %d.\n", - name, block, partition)); - DEB(if (partition < 0) - return (-EIO); ) - - /* Update the location at the partition we are leaving */ - if ((!STp->can_partitions && partition != 0) || - partition >= ST_NBR_PARTITIONS) - return (-EINVAL); - if (partition != STp->partition) { - if (get_location(STp, &blk, &p, 1)) - STps->last_block_valid = 0; - else { - STps->last_block_valid = 1; - STps->last_block_visited = blk; - DEBC(printk(ST_DEB_MSG - "%s: Visited block %d for partition %d saved.\n", - name, blk, STp->partition)); - } - } - - memset(scmd, 0, MAX_COMMAND_SIZE); - if ((STp->device)->scsi_level < SCSI_2) { - scmd[0] = QFA_SEEK_BLOCK; - scmd[2] = (block >> 16); - scmd[3] = (block >> 8); - scmd[4] = block; - scmd[5] = 0; - } else { - scmd[0] = SEEK_10; - scmd[3] = (block >> 24); - scmd[4] = (block >> 16); - scmd[5] = (block >> 8); - scmd[6] = block; - if (!logical && !STp->scsi2_logical) - scmd[1] = 4; - if (STp->partition != partition) { - scmd[1] |= 2; - scmd[8] = partition; - DEBC(printk(ST_DEB_MSG - "%s: Trying to change partition from %d to %d\n", - name, STp->partition, partition)); - } - } - if (STp->immediate) { - scmd[1] |= 1; /* Don't wait for completion */ - timeout = STp->device->request_queue->rq_timeout; - } - - SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE, - timeout, MAX_READY_RETRIES, 1); - if (!SRpnt) - return (STp->buffer)->syscall_result; - - STps->drv_block = STps->drv_file = (-1); - STps->eof = ST_NOEOF; - if ((STp->buffer)->syscall_result != 0) { - result = (-EIO); - if (STp->can_partitions && - (STp->device)->scsi_level >= SCSI_2 && - (p = find_partition(STp)) >= 0) - STp->partition = p; - } else { - if (STp->can_partitions) { - STp->partition = partition; - STps = &(STp->ps[partition]); - if (!STps->last_block_valid || - STps->last_block_visited != block) { - STps->at_sm = 0; - STps->rw = ST_IDLE; - } - } else - STps->at_sm = 0; - if (block == 0) - STps->drv_block = STps->drv_file = 0; - result = 0; - } - - st_release_request(SRpnt); - SRpnt = NULL; - - return result; -} - - -/* Find the current partition number for the drive status. Called from open and - returns either partition number of negative error code. */ -static int find_partition(struct scsi_tape *STp) -{ - int i, partition; - unsigned int block; - - if ((i = get_location(STp, &block, &partition, 1)) < 0) - return i; - if (partition >= ST_NBR_PARTITIONS) - return (-EIO); - return partition; -} - - -/* Change the partition if necessary */ -static int switch_partition(struct scsi_tape *STp) -{ - struct st_partstat *STps; - - if (STp->partition == STp->new_partition) - return 0; - STps = &(STp->ps[STp->new_partition]); - if (!STps->last_block_valid) - STps->last_block_visited = 0; - return set_location(STp, STps->last_block_visited, STp->new_partition, 1); -} - -/* Functions for reading and writing the medium partition mode page. */ - -#define PART_PAGE 0x11 -#define PART_PAGE_FIXED_LENGTH 8 - -#define PP_OFF_MAX_ADD_PARTS 2 -#define PP_OFF_NBR_ADD_PARTS 3 -#define PP_OFF_FLAGS 4 -#define PP_OFF_PART_UNITS 6 -#define PP_OFF_RESERVED 7 - -#define PP_BIT_IDP 0x20 -#define PP_MSK_PSUM_MB 0x10 - -/* Get the number of partitions on the tape. As a side effect reads the - mode page into the tape buffer. */ -static int nbr_partitions(struct scsi_tape *STp) -{ - int result; - DEB( char *name = tape_name(STp); ) - - if (STp->ready != ST_READY) - return (-EIO); - - result = read_mode_page(STp, PART_PAGE, 1); - - if (result) { - DEBC(printk(ST_DEB_MSG "%s: Can't read medium partition page.\n", - name)); - result = (-EIO); - } else { - result = (STp->buffer)->b_data[MODE_HEADER_LENGTH + - PP_OFF_NBR_ADD_PARTS] + 1; - DEBC(printk(ST_DEB_MSG "%s: Number of partitions %d.\n", name, result)); - } - - return result; -} - - -/* Partition the tape into two partitions if size > 0 or one partition if - size == 0. - - The block descriptors are read and written because Sony SDT-7000 does not - work without this (suggestion from Michael Schaefer ). - - My HP C1533A drive returns only one partition size field. This is used to - set the size of partition 1. There is no size field for the default partition. - Michael Schaefer's Sony SDT-7000 returns two descriptors and the second is - used to set the size of partition 1 (this is what the SCSI-3 standard specifies). - The following algorithm is used to accommodate both drives: if the number of - partition size fields is greater than the maximum number of additional partitions - in the mode page, the second field is used. Otherwise the first field is used. - - For Seagate DDS drives the page length must be 8 when no partitions is defined - and 10 when 1 partition is defined (information from Eric Lee Green). This is - is acceptable also to some other old drives and enforced if the first partition - size field is used for the first additional partition size. - */ -static int partition_tape(struct scsi_tape *STp, int size) -{ - char *name = tape_name(STp); - int result; - int pgo, psd_cnt, psdo; - unsigned char *bp; - - result = read_mode_page(STp, PART_PAGE, 0); - if (result) { - DEBC(printk(ST_DEB_MSG "%s: Can't read partition mode page.\n", name)); - return result; - } - /* The mode page is in the buffer. Let's modify it and write it. */ - bp = (STp->buffer)->b_data; - pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH]; - DEBC(printk(ST_DEB_MSG "%s: Partition page length is %d bytes.\n", - name, bp[pgo + MP_OFF_PAGE_LENGTH] + 2)); - - psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2; - psdo = pgo + PART_PAGE_FIXED_LENGTH; - if (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS]) { - bp[psdo] = bp[psdo + 1] = 0xff; /* Rest of the tape */ - psdo += 2; - } - memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2); - - DEBC(printk("%s: psd_cnt %d, max.parts %d, nbr_parts %d\n", name, - psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS], - bp[pgo + PP_OFF_NBR_ADD_PARTS])); - - if (size <= 0) { - bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0; - if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS]) - bp[pgo + MP_OFF_PAGE_LENGTH] = 6; - DEBC(printk(ST_DEB_MSG "%s: Formatting tape with one partition.\n", - name)); - } else { - bp[psdo] = (size >> 8) & 0xff; - bp[psdo + 1] = size & 0xff; - bp[pgo + 3] = 1; - if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8) - bp[pgo + MP_OFF_PAGE_LENGTH] = 8; - DEBC(printk(ST_DEB_MSG - "%s: Formatting tape with two partitions (1 = %d MB).\n", - name, size)); - } - bp[pgo + PP_OFF_PART_UNITS] = 0; - bp[pgo + PP_OFF_RESERVED] = 0; - bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB; - - result = write_mode_page(STp, PART_PAGE, 1); - if (result) { - printk(KERN_INFO "%s: Partitioning of tape failed.\n", name); - result = (-EIO); - } - - return result; -} - - - -/* The ioctl command */ -static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) -{ - int i, cmd_nr, cmd_type, bt; - int retval = 0; - unsigned int blk; - struct scsi_tape *STp = file->private_data; - struct st_modedef *STm; - struct st_partstat *STps; - char *name = tape_name(STp); - void __user *p = (void __user *)arg; - - if (mutex_lock_interruptible(&STp->lock)) - return -ERESTARTSYS; - - DEB( - if (debugging && !STp->in_use) { - printk(ST_DEB_MSG "%s: Incorrect device.\n", name); - retval = (-EIO); - goto out; - } ) /* end DEB */ - - STm = &(STp->modes[STp->current_mode]); - STps = &(STp->ps[STp->partition]); - - /* - * If we are in the middle of error recovery, don't let anyone - * else try and use this device. Also, if error recovery fails, it - * may try and take the device offline, in which case all further - * access to the device is prohibited. - */ - retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p, - file->f_flags & O_NDELAY); - if (!scsi_block_when_processing_errors(STp->device) || retval != -ENODEV) - goto out; - retval = 0; - - cmd_type = _IOC_TYPE(cmd_in); - cmd_nr = _IOC_NR(cmd_in); - - if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { - struct mtop mtc; - - if (_IOC_SIZE(cmd_in) != sizeof(mtc)) { - retval = (-EINVAL); - goto out; - } - - i = copy_from_user(&mtc, p, sizeof(struct mtop)); - if (i) { - retval = (-EFAULT); - goto out; - } - - if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { - printk(KERN_WARNING - "%s: MTSETDRVBUFFER only allowed for root.\n", name); - retval = (-EPERM); - goto out; - } - if (!STm->defined && - (mtc.mt_op != MTSETDRVBUFFER && - (mtc.mt_count & MT_ST_OPTIONS) == 0)) { - retval = (-ENXIO); - goto out; - } - - if (!STp->pos_unknown) { - - if (STps->eof == ST_FM_HIT) { - if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || - mtc.mt_op == MTEOM) { - mtc.mt_count -= 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { - mtc.mt_count += 1; - if (STps->drv_file >= 0) - STps->drv_file += 1; - } - } - - if (mtc.mt_op == MTSEEK) { - /* Old position must be restored if partition will be - changed */ - i = !STp->can_partitions || - (STp->new_partition != STp->partition); - } else { - i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || - mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || - mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || - mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || - mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM || - mtc.mt_op == MTCOMPRESSION; - } - i = flush_buffer(STp, i); - if (i < 0) { - retval = i; - goto out; - } - if (STps->rw == ST_WRITING && - (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || - mtc.mt_op == MTSEEK || - mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) { - i = st_int_ioctl(STp, MTWEOF, 1); - if (i < 0) { - retval = i; - goto out; - } - if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) - mtc.mt_count++; - STps->rw = ST_IDLE; - } - - } else { - /* - * If there was a bus reset, block further access - * to this device. If the user wants to rewind the tape, - * then reset the flag and allow access again. - */ - if (mtc.mt_op != MTREW && - mtc.mt_op != MTOFFL && - mtc.mt_op != MTRETEN && - mtc.mt_op != MTERASE && - mtc.mt_op != MTSEEK && - mtc.mt_op != MTEOM) { - retval = (-EIO); - goto out; - } - reset_state(STp); - /* remove this when the midlevel properly clears was_reset */ - STp->device->was_reset = 0; - } - - if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && - mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM && - mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART) - STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ - - if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) - do_door_lock(STp, 0); /* Ignore result! */ - - if (mtc.mt_op == MTSETDRVBUFFER && - (mtc.mt_count & MT_ST_OPTIONS) != 0) { - retval = st_set_options(STp, mtc.mt_count); - goto out; - } - - if (mtc.mt_op == MTSETPART) { - if (!STp->can_partitions || - mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) { - retval = (-EINVAL); - goto out; - } - if (mtc.mt_count >= STp->nbr_partitions && - (STp->nbr_partitions = nbr_partitions(STp)) < 0) { - retval = (-EIO); - goto out; - } - if (mtc.mt_count >= STp->nbr_partitions) { - retval = (-EINVAL); - goto out; - } - STp->new_partition = mtc.mt_count; - retval = 0; - goto out; - } - - if (mtc.mt_op == MTMKPART) { - if (!STp->can_partitions) { - retval = (-EINVAL); - goto out; - } - if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 || - (i = partition_tape(STp, mtc.mt_count)) < 0) { - retval = i; - goto out; - } - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STp->ps[i].rw = ST_IDLE; - STp->ps[i].at_sm = 0; - STp->ps[i].last_block_valid = 0; - } - STp->partition = STp->new_partition = 0; - STp->nbr_partitions = 1; /* Bad guess ?-) */ - STps->drv_block = STps->drv_file = 0; - retval = 0; - goto out; - } - - if (mtc.mt_op == MTSEEK) { - i = set_location(STp, mtc.mt_count, STp->new_partition, 0); - if (!STp->can_partitions) - STp->ps[0].rw = ST_IDLE; - retval = i; - goto out; - } - - if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) { - retval = do_load_unload(STp, file, 0); - goto out; - } - - if (mtc.mt_op == MTLOAD) { - retval = do_load_unload(STp, file, max(1, mtc.mt_count)); - goto out; - } - - if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) { - retval = do_door_lock(STp, (mtc.mt_op == MTLOCK)); - goto out; - } - - if (STp->can_partitions && STp->ready == ST_READY && - (i = switch_partition(STp)) < 0) { - retval = i; - goto out; - } - - if (mtc.mt_op == MTCOMPRESSION) - retval = st_compression(STp, (mtc.mt_count & 1)); - else - retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count); - goto out; - } - if (!STm->defined) { - retval = (-ENXIO); - goto out; - } - - if ((i = flush_buffer(STp, 0)) < 0) { - retval = i; - goto out; - } - if (STp->can_partitions && - (i = switch_partition(STp)) < 0) { - retval = i; - goto out; - } - - if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { - struct mtget mt_status; - - if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { - retval = (-EINVAL); - goto out; - } - - mt_status.mt_type = STp->tape_type; - mt_status.mt_dsreg = - ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | - ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); - mt_status.mt_blkno = STps->drv_block; - mt_status.mt_fileno = STps->drv_file; - if (STp->block_size != 0) { - if (STps->rw == ST_WRITING) - mt_status.mt_blkno += - (STp->buffer)->buffer_bytes / STp->block_size; - else if (STps->rw == ST_READING) - mt_status.mt_blkno -= - ((STp->buffer)->buffer_bytes + - STp->block_size - 1) / STp->block_size; - } - - mt_status.mt_gstat = 0; - if (STp->drv_write_prot) - mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff); - if (mt_status.mt_blkno == 0) { - if (mt_status.mt_fileno == 0) - mt_status.mt_gstat |= GMT_BOT(0xffffffff); - else - mt_status.mt_gstat |= GMT_EOF(0xffffffff); - } - mt_status.mt_erreg = (STp->recover_reg << MT_ST_SOFTERR_SHIFT); - mt_status.mt_resid = STp->partition; - if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) - mt_status.mt_gstat |= GMT_EOT(0xffffffff); - else if (STps->eof >= ST_EOM_OK) - mt_status.mt_gstat |= GMT_EOD(0xffffffff); - if (STp->density == 1) - mt_status.mt_gstat |= GMT_D_800(0xffffffff); - else if (STp->density == 2) - mt_status.mt_gstat |= GMT_D_1600(0xffffffff); - else if (STp->density == 3) - mt_status.mt_gstat |= GMT_D_6250(0xffffffff); - if (STp->ready == ST_READY) - mt_status.mt_gstat |= GMT_ONLINE(0xffffffff); - if (STp->ready == ST_NO_TAPE) - mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff); - if (STps->at_sm) - mt_status.mt_gstat |= GMT_SM(0xffffffff); - if (STm->do_async_writes || - (STm->do_buffer_writes && STp->block_size != 0) || - STp->drv_buffer != 0) - mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); - if (STp->cleaning_req) - mt_status.mt_gstat |= GMT_CLN(0xffffffff); - - i = copy_to_user(p, &mt_status, sizeof(struct mtget)); - if (i) { - retval = (-EFAULT); - goto out; - } - - STp->recover_reg = 0; /* Clear after read */ - retval = 0; - goto out; - } /* End of MTIOCGET */ - if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { - struct mtpos mt_pos; - if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) { - retval = (-EINVAL); - goto out; - } - if ((i = get_location(STp, &blk, &bt, 0)) < 0) { - retval = i; - goto out; - } - mt_pos.mt_blkno = blk; - i = copy_to_user(p, &mt_pos, sizeof(struct mtpos)); - if (i) - retval = (-EFAULT); - goto out; - } - mutex_unlock(&STp->lock); - switch (cmd_in) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - break; - default: - if ((cmd_in == SG_IO || - cmd_in == SCSI_IOCTL_SEND_COMMAND || - cmd_in == CDROM_SEND_PACKET) && - !capable(CAP_SYS_RAWIO)) - i = -EPERM; - else - i = scsi_cmd_ioctl(STp->disk->queue, STp->disk, - file->f_mode, cmd_in, p); - if (i != -ENOTTY) - return i; - break; - } - retval = scsi_ioctl(STp->device, cmd_in, p); - if (!retval && cmd_in == SCSI_IOCTL_STOP_UNIT) { /* unload */ - STp->rew_at_close = 0; - STp->ready = ST_NO_TAPE; - } - return retval; - - out: - mutex_unlock(&STp->lock); - return retval; -} - -#ifdef CONFIG_COMPAT -static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct scsi_tape *STp = file->private_data; - struct scsi_device *sdev = STp->device; - int ret = -ENOIOCTLCMD; - if (sdev->host->hostt->compat_ioctl) { - - ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg); - - } - return ret; -} -#endif - - - -/* Try to allocate a new tape buffer. Calling function must not hold - dev_arr_lock. */ -static struct st_buffer *new_tape_buffer(int need_dma, int max_sg) -{ - struct st_buffer *tb; - - tb = kzalloc(sizeof(struct st_buffer), GFP_ATOMIC); - if (!tb) { - printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n"); - return NULL; - } - tb->frp_segs = 0; - tb->use_sg = max_sg; - tb->dma = need_dma; - tb->buffer_size = 0; - - tb->reserved_pages = kzalloc(max_sg * sizeof(struct page *), - GFP_ATOMIC); - if (!tb->reserved_pages) { - kfree(tb); - return NULL; - } - - return tb; -} - - -/* Try to allocate enough space in the tape buffer */ -#define ST_MAX_ORDER 6 - -static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma) -{ - int segs, nbr, max_segs, b_size, order, got; - gfp_t priority; - - if (new_size <= STbuffer->buffer_size) - return 1; - - if (STbuffer->buffer_size <= PAGE_SIZE) - normalize_buffer(STbuffer); /* Avoid extra segment */ - - max_segs = STbuffer->use_sg; - nbr = max_segs - STbuffer->frp_segs; - if (nbr <= 0) - return 0; - - priority = GFP_KERNEL | __GFP_NOWARN; - if (need_dma) - priority |= GFP_DMA; - - if (STbuffer->cleared) - priority |= __GFP_ZERO; - - if (STbuffer->frp_segs) { - order = STbuffer->reserved_page_order; - b_size = PAGE_SIZE << order; - } else { - for (b_size = PAGE_SIZE, order = 0; - order < ST_MAX_ORDER && - max_segs * (PAGE_SIZE << order) < new_size; - order++, b_size *= 2) - ; /* empty */ - STbuffer->reserved_page_order = order; - } - if (max_segs * (PAGE_SIZE << order) < new_size) { - if (order == ST_MAX_ORDER) - return 0; - normalize_buffer(STbuffer); - return enlarge_buffer(STbuffer, new_size, need_dma); - } - - for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size; - segs < max_segs && got < new_size;) { - struct page *page; - - page = alloc_pages(priority, order); - if (!page) { - DEB(STbuffer->buffer_size = got); - normalize_buffer(STbuffer); - return 0; - } - - STbuffer->frp_segs += 1; - got += b_size; - STbuffer->buffer_size = got; - STbuffer->reserved_pages[segs] = page; - segs++; - } - STbuffer->b_data = page_address(STbuffer->reserved_pages[0]); - - return 1; -} - - -/* Make sure that no data from previous user is in the internal buffer */ -static void clear_buffer(struct st_buffer * st_bp) -{ - int i; - - for (i=0; i < st_bp->frp_segs; i++) - memset(page_address(st_bp->reserved_pages[i]), 0, - PAGE_SIZE << st_bp->reserved_page_order); - st_bp->cleared = 1; -} - - -/* Release the extra buffer */ -static void normalize_buffer(struct st_buffer * STbuffer) -{ - int i, order = STbuffer->reserved_page_order; - - for (i = 0; i < STbuffer->frp_segs; i++) { - __free_pages(STbuffer->reserved_pages[i], order); - STbuffer->buffer_size -= (PAGE_SIZE << order); - } - STbuffer->frp_segs = 0; - STbuffer->sg_segs = 0; - STbuffer->reserved_page_order = 0; - STbuffer->map_data.offset = 0; -} - - -/* Move data from the user buffer to the tape buffer. Returns zero (success) or - negative error code. */ -static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count) -{ - int i, cnt, res, offset; - int length = PAGE_SIZE << st_bp->reserved_page_order; - - for (i = 0, offset = st_bp->buffer_bytes; - i < st_bp->frp_segs && offset >= length; i++) - offset -= length; - if (i == st_bp->frp_segs) { /* Should never happen */ - printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); - return (-EIO); - } - for (; i < st_bp->frp_segs && do_count > 0; i++) { - struct page *page = st_bp->reserved_pages[i]; - cnt = length - offset < do_count ? length - offset : do_count; - res = copy_from_user(page_address(page) + offset, ubp, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) /* Should never happen */ - return (-EIO); - - return 0; -} - - -/* Move data from the tape buffer to the user buffer. Returns zero (success) or - negative error code. */ -static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count) -{ - int i, cnt, res, offset; - int length = PAGE_SIZE << st_bp->reserved_page_order; - - for (i = 0, offset = st_bp->read_pointer; - i < st_bp->frp_segs && offset >= length; i++) - offset -= length; - if (i == st_bp->frp_segs) { /* Should never happen */ - printk(KERN_WARNING "st: from_buffer offset overflow.\n"); - return (-EIO); - } - for (; i < st_bp->frp_segs && do_count > 0; i++) { - struct page *page = st_bp->reserved_pages[i]; - cnt = length - offset < do_count ? length - offset : do_count; - res = copy_to_user(ubp, page_address(page) + offset, cnt); - if (res) - return (-EFAULT); - do_count -= cnt; - st_bp->buffer_bytes -= cnt; - st_bp->read_pointer += cnt; - ubp += cnt; - offset = 0; - } - if (do_count) /* Should never happen */ - return (-EIO); - - return 0; -} - - -/* Move data towards start of buffer */ -static void move_buffer_data(struct st_buffer * st_bp, int offset) -{ - int src_seg, dst_seg, src_offset = 0, dst_offset; - int count, total; - int length = PAGE_SIZE << st_bp->reserved_page_order; - - if (offset == 0) - return; - - total=st_bp->buffer_bytes - offset; - for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) { - src_offset = offset; - if (src_offset < length) - break; - offset -= length; - } - - st_bp->buffer_bytes = st_bp->read_pointer = total; - for (dst_seg=dst_offset=0; total > 0; ) { - struct page *dpage = st_bp->reserved_pages[dst_seg]; - struct page *spage = st_bp->reserved_pages[src_seg]; - - count = min(length - dst_offset, length - src_offset); - memmove(page_address(dpage) + dst_offset, - page_address(spage) + src_offset, count); - src_offset += count; - if (src_offset >= length) { - src_seg++; - src_offset = 0; - } - dst_offset += count; - if (dst_offset >= length) { - dst_seg++; - dst_offset = 0; - } - total -= count; - } -} - -/* Validate the options from command line or module parameters */ -static void validate_options(void) -{ - if (buffer_kbs > 0) - st_fixed_buffer_size = buffer_kbs * ST_KILOBYTE; - if (max_sg_segs >= ST_FIRST_SG) - st_max_sg_segs = max_sg_segs; -} - -#ifndef MODULE -/* Set the boot options. Syntax is defined in Documenation/scsi/st.txt. - */ -static int __init st_setup(char *str) -{ - int i, len, ints[5]; - char *stp; - - stp = get_options(str, ARRAY_SIZE(ints), ints); - - if (ints[0] > 0) { - for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) - if (parms[i].val) - *parms[i].val = ints[i + 1]; - } else { - while (stp != NULL) { - for (i = 0; i < ARRAY_SIZE(parms); i++) { - len = strlen(parms[i].name); - if (!strncmp(stp, parms[i].name, len) && - (*(stp + len) == ':' || *(stp + len) == '=')) { - if (parms[i].val) - *parms[i].val = - simple_strtoul(stp + len + 1, NULL, 0); - else - printk(KERN_WARNING "st: Obsolete parameter %s\n", - parms[i].name); - break; - } - } - if (i >= ARRAY_SIZE(parms)) - printk(KERN_WARNING "st: invalid parameter in '%s'\n", - stp); - stp = strchr(stp, ','); - if (stp) - stp++; - } - } - - validate_options(); - - return 1; -} - -__setup("st=", st_setup); - -#endif - -static const struct file_operations st_fops = -{ - .owner = THIS_MODULE, - .read = st_read, - .write = st_write, - .unlocked_ioctl = st_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = st_compat_ioctl, -#endif - .open = st_open, - .flush = st_flush, - .release = st_release, - .llseek = noop_llseek, -}; - -static int st_probe(struct device *dev) -{ - struct scsi_device *SDp = to_scsi_device(dev); - struct gendisk *disk = NULL; - struct cdev *cdev = NULL; - struct scsi_tape *tpnt = NULL; - struct st_modedef *STm; - struct st_partstat *STps; - struct st_buffer *buffer; - int i, j, mode, dev_num, error; - char *stp; - - if (SDp->type != TYPE_TAPE) - return -ENODEV; - if ((stp = st_incompatible(SDp))) { - sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n"); - printk(KERN_INFO "st: The suggested driver is %s.\n", stp); - return -ENODEV; - } - - i = queue_max_segments(SDp->request_queue); - if (st_max_sg_segs < i) - i = st_max_sg_segs; - buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i); - if (buffer == NULL) { - printk(KERN_ERR - "st: Can't allocate new tape buffer. Device not attached.\n"); - goto out; - } - - disk = alloc_disk(1); - if (!disk) { - printk(KERN_ERR "st: out of memory. Device not attached.\n"); - goto out_buffer_free; - } - - write_lock(&st_dev_arr_lock); - if (st_nr_dev >= st_dev_max) { - struct scsi_tape **tmp_da; - int tmp_dev_max; - - tmp_dev_max = max(st_nr_dev * 2, 8); - if (tmp_dev_max > ST_MAX_TAPES) - tmp_dev_max = ST_MAX_TAPES; - if (tmp_dev_max <= st_nr_dev) { - write_unlock(&st_dev_arr_lock); - printk(KERN_ERR "st: Too many tape devices (max. %d).\n", - ST_MAX_TAPES); - goto out_put_disk; - } - - tmp_da = kzalloc(tmp_dev_max * sizeof(struct scsi_tape *), GFP_ATOMIC); - if (tmp_da == NULL) { - write_unlock(&st_dev_arr_lock); - printk(KERN_ERR "st: Can't extend device array.\n"); - goto out_put_disk; - } - - if (scsi_tapes != NULL) { - memcpy(tmp_da, scsi_tapes, - st_dev_max * sizeof(struct scsi_tape *)); - kfree(scsi_tapes); - } - scsi_tapes = tmp_da; - - st_dev_max = tmp_dev_max; - } - - for (i = 0; i < st_dev_max; i++) - if (scsi_tapes[i] == NULL) - break; - if (i >= st_dev_max) - panic("scsi_devices corrupt (st)"); - - tpnt = kzalloc(sizeof(struct scsi_tape), GFP_ATOMIC); - if (tpnt == NULL) { - write_unlock(&st_dev_arr_lock); - printk(KERN_ERR "st: Can't allocate device descriptor.\n"); - goto out_put_disk; - } - kref_init(&tpnt->kref); - tpnt->disk = disk; - sprintf(disk->disk_name, "st%d", i); - disk->private_data = &tpnt->driver; - disk->queue = SDp->request_queue; - tpnt->driver = &st_template; - scsi_tapes[i] = tpnt; - dev_num = i; - - tpnt->device = SDp; - if (SDp->scsi_level <= 2) - tpnt->tape_type = MT_ISSCSI1; - else - tpnt->tape_type = MT_ISSCSI2; - - tpnt->buffer = buffer; - tpnt->buffer->last_SRpnt = NULL; - - tpnt->inited = 0; - tpnt->dirty = 0; - tpnt->in_use = 0; - tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ - tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; - tpnt->use_pf = (SDp->scsi_level >= SCSI_2); - tpnt->density = 0; - tpnt->do_auto_lock = ST_AUTO_LOCK; - tpnt->can_bsr = (SDp->scsi_level > 2 ? 1 : ST_IN_FILE_POS); /* BSR mandatory in SCSI3 */ - tpnt->can_partitions = 0; - tpnt->two_fm = ST_TWO_FM; - tpnt->fast_mteom = ST_FAST_MTEOM; - tpnt->scsi2_logical = ST_SCSI2LOGICAL; - tpnt->sili = ST_SILI; - tpnt->immediate = ST_NOWAIT; - tpnt->immediate_filemark = 0; - tpnt->default_drvbuffer = 0xff; /* No forced buffering */ - tpnt->partition = 0; - tpnt->new_partition = 0; - tpnt->nbr_partitions = 0; - blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT); - tpnt->long_timeout = ST_LONG_TIMEOUT; - tpnt->try_dio = try_direct_io && !SDp->host->unchecked_isa_dma; - - for (i = 0; i < ST_NBR_MODES; i++) { - STm = &(tpnt->modes[i]); - STm->defined = 0; - STm->sysv = ST_SYSV; - STm->defaults_for_writes = 0; - STm->do_async_writes = ST_ASYNC_WRITES; - STm->do_buffer_writes = ST_BUFFER_WRITES; - STm->do_read_ahead = ST_READ_AHEAD; - STm->default_compression = ST_DONT_TOUCH; - STm->default_blksize = (-1); /* No forced size */ - STm->default_density = (-1); /* No forced density */ - } - - for (i = 0; i < ST_NBR_PARTITIONS; i++) { - STps = &(tpnt->ps[i]); - STps->rw = ST_IDLE; - STps->eof = ST_NOEOF; - STps->at_sm = 0; - STps->last_block_valid = 0; - STps->drv_block = (-1); - STps->drv_file = (-1); - } - - tpnt->current_mode = 0; - tpnt->modes[0].defined = 1; - - tpnt->density_changed = tpnt->compression_changed = - tpnt->blksize_changed = 0; - mutex_init(&tpnt->lock); - - st_nr_dev++; - write_unlock(&st_dev_arr_lock); - - for (mode = 0; mode < ST_NBR_MODES; ++mode) { - STm = &(tpnt->modes[mode]); - for (j=0; j < 2; j++) { - cdev = cdev_alloc(); - if (!cdev) { - printk(KERN_ERR - "st%d: out of memory. Device not attached.\n", - dev_num); - goto out_free_tape; - } - cdev->owner = THIS_MODULE; - cdev->ops = &st_fops; - - error = cdev_add(cdev, - MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, j)), - 1); - if (error) { - printk(KERN_ERR "st%d: Can't add %s-rewind mode %d\n", - dev_num, j ? "non" : "auto", mode); - printk(KERN_ERR "st%d: Device not attached.\n", dev_num); - goto out_free_tape; - } - STm->cdevs[j] = cdev; - - } - error = do_create_class_files(tpnt, dev_num, mode); - if (error) - goto out_free_tape; - } - scsi_autopm_put_device(SDp); - - sdev_printk(KERN_NOTICE, SDp, - "Attached scsi tape %s\n", tape_name(tpnt)); - sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n", - tape_name(tpnt), tpnt->try_dio ? "yes" : "no", - queue_dma_alignment(SDp->request_queue) + 1); - - return 0; - -out_free_tape: - for (mode=0; mode < ST_NBR_MODES; mode++) { - STm = &(tpnt->modes[mode]); - sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, - "tape"); - for (j=0; j < 2; j++) { - if (STm->cdevs[j]) { - if (cdev == STm->cdevs[j]) - cdev = NULL; - device_destroy(st_sysfs_class, - MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(i, mode, j))); - cdev_del(STm->cdevs[j]); - } - } - } - if (cdev) - cdev_del(cdev); - write_lock(&st_dev_arr_lock); - scsi_tapes[dev_num] = NULL; - st_nr_dev--; - write_unlock(&st_dev_arr_lock); -out_put_disk: - put_disk(disk); - kfree(tpnt); -out_buffer_free: - kfree(buffer); -out: - return -ENODEV; -}; - - -static int st_remove(struct device *dev) -{ - struct scsi_device *SDp = to_scsi_device(dev); - struct scsi_tape *tpnt; - int i, j, mode; - - scsi_autopm_get_device(SDp); - write_lock(&st_dev_arr_lock); - for (i = 0; i < st_dev_max; i++) { - tpnt = scsi_tapes[i]; - if (tpnt != NULL && tpnt->device == SDp) { - scsi_tapes[i] = NULL; - st_nr_dev--; - write_unlock(&st_dev_arr_lock); - sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, - "tape"); - for (mode = 0; mode < ST_NBR_MODES; ++mode) { - for (j=0; j < 2; j++) { - device_destroy(st_sysfs_class, - MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(i, mode, j))); - cdev_del(tpnt->modes[mode].cdevs[j]); - tpnt->modes[mode].cdevs[j] = NULL; - } - } - - mutex_lock(&st_ref_mutex); - kref_put(&tpnt->kref, scsi_tape_release); - mutex_unlock(&st_ref_mutex); - return 0; - } - } - - write_unlock(&st_dev_arr_lock); - return 0; -} - -/** - * scsi_tape_release - Called to free the Scsi_Tape structure - * @kref: pointer to embedded kref - * - * st_ref_mutex must be held entering this routine. Because it is - * called on last put, you should always use the scsi_tape_get() - * scsi_tape_put() helpers which manipulate the semaphore directly - * and never do a direct kref_put(). - **/ -static void scsi_tape_release(struct kref *kref) -{ - struct scsi_tape *tpnt = to_scsi_tape(kref); - struct gendisk *disk = tpnt->disk; - - tpnt->device = NULL; - - if (tpnt->buffer) { - normalize_buffer(tpnt->buffer); - kfree(tpnt->buffer->reserved_pages); - kfree(tpnt->buffer); - } - - disk->private_data = NULL; - put_disk(disk); - kfree(tpnt); - return; -} - -static int __init init_st(void) -{ - int err; - - validate_options(); - - printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n", - verstr, st_fixed_buffer_size, st_max_sg_segs); - - st_sysfs_class = class_create(THIS_MODULE, "scsi_tape"); - if (IS_ERR(st_sysfs_class)) { - printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n"); - return PTR_ERR(st_sysfs_class); - } - - err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), - ST_MAX_TAPE_ENTRIES, "st"); - if (err) { - printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", - SCSI_TAPE_MAJOR); - goto err_class; - } - - err = scsi_register_driver(&st_template.gendrv); - if (err) - goto err_chrdev; - - err = do_create_sysfs_files(); - if (err) - goto err_scsidrv; - - return 0; - -err_scsidrv: - scsi_unregister_driver(&st_template.gendrv); -err_chrdev: - unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), - ST_MAX_TAPE_ENTRIES); -err_class: - class_destroy(st_sysfs_class); - return err; -} - -static void __exit exit_st(void) -{ - do_remove_sysfs_files(); - scsi_unregister_driver(&st_template.gendrv); - unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), - ST_MAX_TAPE_ENTRIES); - class_destroy(st_sysfs_class); - kfree(scsi_tapes); - printk(KERN_INFO "st: Unloaded.\n"); -} - -module_init(init_st); -module_exit(exit_st); - - -/* The sysfs driver interface. Read-only at the moment */ -static ssize_t st_try_direct_io_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", try_direct_io); -} -static DRIVER_ATTR(try_direct_io, S_IRUGO, st_try_direct_io_show, NULL); - -static ssize_t st_fixed_buffer_size_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", st_fixed_buffer_size); -} -static DRIVER_ATTR(fixed_buffer_size, S_IRUGO, st_fixed_buffer_size_show, NULL); - -static ssize_t st_max_sg_segs_show(struct device_driver *ddp, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", st_max_sg_segs); -} -static DRIVER_ATTR(max_sg_segs, S_IRUGO, st_max_sg_segs_show, NULL); - -static ssize_t st_version_show(struct device_driver *ddd, char *buf) -{ - return snprintf(buf, PAGE_SIZE, "[%s]\n", verstr); -} -static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL); - -static int do_create_sysfs_files(void) -{ - struct device_driver *sysfs = &st_template.gendrv; - int err; - - err = driver_create_file(sysfs, &driver_attr_try_direct_io); - if (err) - return err; - err = driver_create_file(sysfs, &driver_attr_fixed_buffer_size); - if (err) - goto err_try_direct_io; - err = driver_create_file(sysfs, &driver_attr_max_sg_segs); - if (err) - goto err_attr_fixed_buf; - err = driver_create_file(sysfs, &driver_attr_version); - if (err) - goto err_attr_max_sg; - - return 0; - -err_attr_max_sg: - driver_remove_file(sysfs, &driver_attr_max_sg_segs); -err_attr_fixed_buf: - driver_remove_file(sysfs, &driver_attr_fixed_buffer_size); -err_try_direct_io: - driver_remove_file(sysfs, &driver_attr_try_direct_io); - return err; -} - -static void do_remove_sysfs_files(void) -{ - struct device_driver *sysfs = &st_template.gendrv; - - driver_remove_file(sysfs, &driver_attr_version); - driver_remove_file(sysfs, &driver_attr_max_sg_segs); - driver_remove_file(sysfs, &driver_attr_fixed_buffer_size); - driver_remove_file(sysfs, &driver_attr_try_direct_io); -} - - -/* The sysfs simple class interface */ -static ssize_t -st_defined_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct st_modedef *STm = dev_get_drvdata(dev); - ssize_t l = 0; - - l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined); - return l; -} - -DEVICE_ATTR(defined, S_IRUGO, st_defined_show, NULL); - -static ssize_t -st_defblk_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct st_modedef *STm = dev_get_drvdata(dev); - ssize_t l = 0; - - l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize); - return l; -} - -DEVICE_ATTR(default_blksize, S_IRUGO, st_defblk_show, NULL); - -static ssize_t -st_defdensity_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct st_modedef *STm = dev_get_drvdata(dev); - ssize_t l = 0; - char *fmt; - - fmt = STm->default_density >= 0 ? "0x%02x\n" : "%d\n"; - l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density); - return l; -} - -DEVICE_ATTR(default_density, S_IRUGO, st_defdensity_show, NULL); - -static ssize_t -st_defcompression_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct st_modedef *STm = dev_get_drvdata(dev); - ssize_t l = 0; - - l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1); - return l; -} - -DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); - -static ssize_t -st_options_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct st_modedef *STm = dev_get_drvdata(dev); - struct scsi_tape *STp; - int i, j, options; - ssize_t l = 0; - - for (i=0; i < st_dev_max; i++) { - for (j=0; j < ST_NBR_MODES; j++) - if (&scsi_tapes[i]->modes[j] == STm) - break; - if (j < ST_NBR_MODES) - break; - } - if (i == st_dev_max) - return 0; /* should never happen */ - - STp = scsi_tapes[i]; - - options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0; - options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0; - options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0; - DEB( options |= debugging ? MT_ST_DEBUGGING : 0 ); - options |= STp->two_fm ? MT_ST_TWO_FM : 0; - options |= STp->fast_mteom ? MT_ST_FAST_MTEOM : 0; - options |= STm->defaults_for_writes ? MT_ST_DEF_WRITES : 0; - options |= STp->can_bsr ? MT_ST_CAN_BSR : 0; - options |= STp->omit_blklims ? MT_ST_NO_BLKLIMS : 0; - options |= STp->can_partitions ? MT_ST_CAN_PARTITIONS : 0; - options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0; - options |= STm->sysv ? MT_ST_SYSV : 0; - options |= STp->immediate ? MT_ST_NOWAIT : 0; - options |= STp->immediate_filemark ? MT_ST_NOWAIT_EOF : 0; - options |= STp->sili ? MT_ST_SILI : 0; - - l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options); - return l; -} - -DEVICE_ATTR(options, S_IRUGO, st_options_show, NULL); - -static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) -{ - int i, rew, error; - char name[10]; - struct device *st_class_member; - - for (rew=0; rew < 2; rew++) { - /* Make sure that the minor numbers corresponding to the four - first modes always get the same names */ - i = mode << (4 - ST_NBR_MODE_BITS); - snprintf(name, 10, "%s%s%s", rew ? "n" : "", - STp->disk->disk_name, st_formats[i]); - st_class_member = - device_create(st_sysfs_class, &STp->device->sdev_gendev, - MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(dev_num, mode, rew)), - &STp->modes[mode], "%s", name); - if (IS_ERR(st_class_member)) { - printk(KERN_WARNING "st%d: device_create failed\n", - dev_num); - error = PTR_ERR(st_class_member); - goto out; - } - - error = device_create_file(st_class_member, - &dev_attr_defined); - if (error) goto out; - error = device_create_file(st_class_member, - &dev_attr_default_blksize); - if (error) goto out; - error = device_create_file(st_class_member, - &dev_attr_default_density); - if (error) goto out; - error = device_create_file(st_class_member, - &dev_attr_default_compression); - if (error) goto out; - error = device_create_file(st_class_member, - &dev_attr_options); - if (error) goto out; - - if (mode == 0 && rew == 0) { - error = sysfs_create_link(&STp->device->sdev_gendev.kobj, - &st_class_member->kobj, - "tape"); - if (error) { - printk(KERN_ERR - "st%d: Can't create sysfs link from SCSI device.\n", - dev_num); - goto out; - } - } - } - - return 0; - -out: - return error; -} - -/* The following functions may be useful for a larger audience. */ -static int sgl_map_user_pages(struct st_buffer *STbp, - const unsigned int max_pages, unsigned long uaddr, - size_t count, int rw) -{ - unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned long start = uaddr >> PAGE_SHIFT; - const int nr_pages = end - start; - int res, i, j; - struct page **pages; - struct rq_map_data *mdata = &STbp->map_data; - - /* User attempted Overflow! */ - if ((uaddr + count) < uaddr) - return -EINVAL; - - /* Too big */ - if (nr_pages > max_pages) - return -ENOMEM; - - /* Hmm? */ - if (count == 0) - return 0; - - if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_KERNEL)) == NULL) - return -ENOMEM; - - /* Try to fault in all of the necessary pages */ - down_read(¤t->mm->mmap_sem); - /* rw==READ means read from drive, write into memory area */ - res = get_user_pages( - current, - current->mm, - uaddr, - nr_pages, - rw == READ, - 0, /* don't force */ - pages, - NULL); - up_read(¤t->mm->mmap_sem); - - /* Errors and no page mapped should return here */ - if (res < nr_pages) - goto out_unmap; - - for (i=0; i < nr_pages; i++) { - /* FIXME: flush superflous for rw==READ, - * probably wrong function for rw==WRITE - */ - flush_dcache_page(pages[i]); - } - - mdata->offset = uaddr & ~PAGE_MASK; - STbp->mapped_pages = pages; - - return nr_pages; - out_unmap: - if (res > 0) { - for (j=0; j < res; j++) - page_cache_release(pages[j]); - res = 0; - } - kfree(pages); - return res; -} - - -/* And unmap them... */ -static int sgl_unmap_user_pages(struct st_buffer *STbp, - const unsigned int nr_pages, int dirtied) -{ - int i; - - for (i=0; i < nr_pages; i++) { - struct page *page = STbp->mapped_pages[i]; - - if (dirtied) - SetPageDirty(page); - /* FIXME: cache flush missing for rw==READ - * FIXME: call the correct reference counting function - */ - page_cache_release(page); - } - kfree(STbp->mapped_pages); - STbp->mapped_pages = NULL; - - return 0; -} diff --git a/ANDROID_3.4.5/drivers/scsi/st.h b/ANDROID_3.4.5/drivers/scsi/st.h deleted file mode 100644 index ea35632b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/st.h +++ /dev/null @@ -1,224 +0,0 @@ - -#ifndef _ST_H -#define _ST_H - -#include -#include -#include -#include - -/* Descriptor for analyzed sense data */ -struct st_cmdstatus { - int midlevel_result; - struct scsi_sense_hdr sense_hdr; - int have_sense; - int residual; - u64 uremainder64; - u8 flags; - u8 remainder_valid; - u8 fixed_format; - u8 deferred; -}; - -struct scsi_tape; - -/* scsi tape command */ -struct st_request { - unsigned char cmd[MAX_COMMAND_SIZE]; - unsigned char sense[SCSI_SENSE_BUFFERSIZE]; - int result; - struct scsi_tape *stp; - struct completion *waiting; - struct bio *bio; -}; - -/* The tape buffer descriptor. */ -struct st_buffer { - unsigned char dma; /* DMA-able buffer */ - unsigned char do_dio; /* direct i/o set up? */ - unsigned char cleared; /* internal buffer cleared after open? */ - int buffer_size; - int buffer_blocks; - int buffer_bytes; - int read_pointer; - int writing; - int syscall_result; - struct st_request *last_SRpnt; - struct st_cmdstatus cmdstat; - struct page **reserved_pages; - int reserved_page_order; - struct page **mapped_pages; - struct rq_map_data map_data; - unsigned char *b_data; - unsigned short use_sg; /* zero or max number of s/g segments for this adapter */ - unsigned short sg_segs; /* number of segments in s/g list */ - unsigned short frp_segs; /* number of buffer segments */ -}; - -/* The tape mode definition */ -struct st_modedef { - unsigned char defined; - unsigned char sysv; /* SYS V semantics? */ - unsigned char do_async_writes; - unsigned char do_buffer_writes; - unsigned char do_read_ahead; - unsigned char defaults_for_writes; - unsigned char default_compression; /* 0 = don't touch, etc */ - short default_density; /* Forced density, -1 = no value */ - int default_blksize; /* Forced blocksize, -1 = no value */ - struct cdev *cdevs[2]; /* Auto-rewind and non-rewind devices */ -}; - -/* Number of modes can be changed by changing ST_NBR_MODE_BITS. The maximum - number of modes is 16 (ST_NBR_MODE_BITS 4) */ -#define ST_NBR_MODE_BITS 2 -#define ST_NBR_MODES (1 << ST_NBR_MODE_BITS) -#define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS) -#define ST_MODE_MASK ((ST_NBR_MODES - 1) << ST_MODE_SHIFT) - -#define ST_MAX_TAPES 128 -#define ST_MAX_TAPE_ENTRIES (ST_MAX_TAPES << (ST_NBR_MODE_BITS + 1)) - -/* The status related to each partition */ -struct st_partstat { - unsigned char rw; - unsigned char eof; - unsigned char at_sm; - unsigned char last_block_valid; - u32 last_block_visited; - int drv_block; /* The block where the drive head is */ - int drv_file; -}; - -#define ST_NBR_PARTITIONS 4 - -/* The tape drive descriptor */ -struct scsi_tape { - struct scsi_driver *driver; - struct scsi_device *device; - struct mutex lock; /* For serialization */ - struct completion wait; /* For SCSI commands */ - struct st_buffer *buffer; - - /* Drive characteristics */ - unsigned char omit_blklims; - unsigned char do_auto_lock; - unsigned char can_bsr; - unsigned char can_partitions; - unsigned char two_fm; - unsigned char fast_mteom; - unsigned char immediate; - unsigned char restr_dma; - unsigned char scsi2_logical; - unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ - unsigned char cln_mode; /* 0 = none, otherwise sense byte nbr */ - unsigned char cln_sense_value; - unsigned char cln_sense_mask; - unsigned char use_pf; /* Set Page Format bit in all mode selects? */ - unsigned char try_dio; /* try direct i/o in general? */ - unsigned char try_dio_now; /* try direct i/o before next close? */ - unsigned char c_algo; /* compression algorithm */ - unsigned char pos_unknown; /* after reset position unknown */ - unsigned char sili; /* use SILI when reading in variable b mode */ - unsigned char immediate_filemark; /* write filemark immediately */ - int tape_type; - int long_timeout; /* timeout for commands known to take long time */ - - unsigned long max_pfn; /* the maximum page number reachable by the HBA */ - - /* Mode characteristics */ - struct st_modedef modes[ST_NBR_MODES]; - int current_mode; - - /* Status variables */ - int partition; - int new_partition; - int nbr_partitions; /* zero until partition support enabled */ - struct st_partstat ps[ST_NBR_PARTITIONS]; - unsigned char dirty; - unsigned char ready; - unsigned char write_prot; - unsigned char drv_write_prot; - unsigned char in_use; - unsigned char blksize_changed; - unsigned char density_changed; - unsigned char compression_changed; - unsigned char drv_buffer; - unsigned char density; - unsigned char door_locked; - unsigned char autorew_dev; /* auto-rewind device */ - unsigned char rew_at_close; /* rewind necessary at close */ - unsigned char inited; - unsigned char cleaning_req; /* cleaning requested? */ - int block_size; - int min_block; - int max_block; - int recover_count; /* From tape opening */ - int recover_reg; /* From last status call */ - -#if DEBUG - unsigned char write_pending; - int nbr_finished; - int nbr_waits; - int nbr_requests; - int nbr_dio; - int nbr_pages; - unsigned char last_cmnd[6]; - unsigned char last_sense[16]; -#endif - struct gendisk *disk; - struct kref kref; -}; - -/* Bit masks for use_pf */ -#define USE_PF 1 -#define PF_TESTED 2 - -/* Values of eof */ -#define ST_NOEOF 0 -#define ST_FM_HIT 1 -#define ST_FM 2 -#define ST_EOM_OK 3 -#define ST_EOM_ERROR 4 -#define ST_EOD_1 5 -#define ST_EOD_2 6 -#define ST_EOD 7 -/* EOD hit while reading => ST_EOD_1 => return zero => ST_EOD_2 => - return zero => ST_EOD, return ENOSPC */ -/* When writing: ST_EOM_OK == early warning found, write OK - ST_EOD_1 == allow trying new write after early warning - ST_EOM_ERROR == early warning found, not able to write all */ - -/* Values of rw */ -#define ST_IDLE 0 -#define ST_READING 1 -#define ST_WRITING 2 - -/* Values of ready state */ -#define ST_READY 0 -#define ST_NOT_READY 1 -#define ST_NO_TAPE 2 - -/* Values for door lock state */ -#define ST_UNLOCKED 0 -#define ST_LOCKED_EXPLICIT 1 -#define ST_LOCKED_AUTO 2 -#define ST_LOCK_FAILS 3 - -/* Positioning SCSI-commands for Tandberg, etc. drives */ -#define QFA_REQUEST_BLOCK 0x02 -#define QFA_SEEK_BLOCK 0x0c - -/* Setting the binary options */ -#define ST_DONT_TOUCH 0 -#define ST_NO 1 -#define ST_YES 2 - -#define EXTENDED_SENSE_START 18 - -/* Masks for some conditions in the sense data */ -#define SENSE_FMK 0x80 -#define SENSE_EOM 0x40 -#define SENSE_ILI 0x20 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/st_options.h b/ANDROID_3.4.5/drivers/scsi/st_options.h deleted file mode 100644 index d2f94793..00000000 --- a/ANDROID_3.4.5/drivers/scsi/st_options.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - The compile-time configurable defaults for the Linux SCSI tape driver. - - Copyright 1995-2003 Kai Makisara. - - Last modified: Thu Feb 21 21:47:07 2008 by kai.makisara -*/ - -#ifndef _ST_OPTIONS_H -#define _ST_OPTIONS_H - -/* If TRY_DIRECT_IO is non-zero, the driver tries to transfer data directly - between the user buffer and tape drive. If this is not possible, driver - buffer is used. If TRY_DIRECT_IO is zero, driver buffer is always used. */ -#define TRY_DIRECT_IO 1 - -/* The driver does not wait for some operations to finish before returning - to the user program if ST_NOWAIT is non-zero. This helps if the SCSI - adapter does not support multiple outstanding commands. However, the user - should not give a new tape command before the previous one has finished. */ -#define ST_NOWAIT 0 - -/* If ST_IN_FILE_POS is nonzero, the driver positions the tape after the - record been read by the user program even if the tape has moved further - because of buffered reads. Should be set to zero to support also drives - that can't space backwards over records. NOTE: The tape will be - spaced backwards over an "accidentally" crossed filemark in any case. */ -#define ST_IN_FILE_POS 0 - -/* If ST_RECOVERED_WRITE_FATAL is non-zero, recovered errors while writing - are considered "hard errors". */ -#define ST_RECOVERED_WRITE_FATAL 0 - -/* The "guess" for the block size for devices that don't support MODE - SENSE. */ -#define ST_DEFAULT_BLOCK 0 - -/* The minimum tape driver buffer size in kilobytes in fixed block mode. - Must be non-zero. */ -#define ST_FIXED_BUFFER_BLOCKS 32 - -/* Maximum number of scatter/gather segments */ -#define ST_MAX_SG 256 - -/* The number of scatter/gather segments to allocate at first try (must be - smaller or equal to the maximum). */ -#define ST_FIRST_SG 8 - -/* The size of the first scatter/gather segments (determines the maximum block - size for SCSI adapters not supporting scatter/gather). The default is set - to try to allocate the buffer as one chunk. */ -#define ST_FIRST_ORDER 5 - - -/* The following lines define defaults for properties that can be set - separately for each drive using the MTSTOPTIONS ioctl. */ - -/* If ST_TWO_FM is non-zero, the driver writes two filemarks after a - file being written. Some drives can't handle two filemarks at the - end of data. */ -#define ST_TWO_FM 0 - -/* If ST_BUFFER_WRITES is non-zero, writes in fixed block mode are - buffered until the driver buffer is full or asynchronous write is - triggered. May make detection of End-Of-Medium early enough fail. */ -#define ST_BUFFER_WRITES 1 - -/* If ST_ASYNC_WRITES is non-zero, the SCSI write command may be started - without waiting for it to finish. May cause problems in multiple - tape backups. */ -#define ST_ASYNC_WRITES 1 - -/* If ST_READ_AHEAD is non-zero, blocks are read ahead in fixed block - mode. */ -#define ST_READ_AHEAD 1 - -/* If ST_AUTO_LOCK is non-zero, the drive door is locked at the first - read or write command after the device is opened. The door is opened - when the device is closed. */ -#define ST_AUTO_LOCK 0 - -/* If ST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the - direct SCSI command. The file number status is lost but this method - is fast with some drives. Otherwise MTEOM is done by spacing over - files and the file number status is retained. */ -#define ST_FAST_MTEOM 0 - -/* If ST_SCSI2LOGICAL is nonzero, the logical block addresses are used for - MTIOCPOS and MTSEEK by default. Vendor addresses are used if ST_SCSI2LOGICAL - is zero. */ -#define ST_SCSI2LOGICAL 0 - -/* If ST_SYSV is non-zero, the tape behaves according to the SYS V semantics. - The default is BSD semantics. */ -#define ST_SYSV 0 - -/* If ST_SILI is non-zero, the SILI bit is set when reading in variable block - mode and the block size is determined using the residual returned by the HBA. */ -#define ST_SILI 0 - -/* Time to wait for the drive to become ready if blocking open */ -#define ST_BLOCK_SECONDS 120 - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/stex.c b/ANDROID_3.4.5/drivers/scsi/stex.c deleted file mode 100644 index 606215e5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/stex.c +++ /dev/null @@ -1,1837 +0,0 @@ -/* - * SuperTrak EX Series Storage Controller driver for Linux - * - * Copyright (C) 2005-2009 Promise Technology Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Written By: - * Ed Lin - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRV_NAME "stex" -#define ST_DRIVER_VERSION "4.6.0000.4" -#define ST_VER_MAJOR 4 -#define ST_VER_MINOR 6 -#define ST_OEM 0 -#define ST_BUILD_VER 4 - -enum { - /* MU register offset */ - IMR0 = 0x10, /* MU_INBOUND_MESSAGE_REG0 */ - IMR1 = 0x14, /* MU_INBOUND_MESSAGE_REG1 */ - OMR0 = 0x18, /* MU_OUTBOUND_MESSAGE_REG0 */ - OMR1 = 0x1c, /* MU_OUTBOUND_MESSAGE_REG1 */ - IDBL = 0x20, /* MU_INBOUND_DOORBELL */ - IIS = 0x24, /* MU_INBOUND_INTERRUPT_STATUS */ - IIM = 0x28, /* MU_INBOUND_INTERRUPT_MASK */ - ODBL = 0x2c, /* MU_OUTBOUND_DOORBELL */ - OIS = 0x30, /* MU_OUTBOUND_INTERRUPT_STATUS */ - OIM = 0x3c, /* MU_OUTBOUND_INTERRUPT_MASK */ - - YIOA_STATUS = 0x00, - YH2I_INT = 0x20, - YINT_EN = 0x34, - YI2H_INT = 0x9c, - YI2H_INT_C = 0xa0, - YH2I_REQ = 0xc0, - YH2I_REQ_HI = 0xc4, - - /* MU register value */ - MU_INBOUND_DOORBELL_HANDSHAKE = (1 << 0), - MU_INBOUND_DOORBELL_REQHEADCHANGED = (1 << 1), - MU_INBOUND_DOORBELL_STATUSTAILCHANGED = (1 << 2), - MU_INBOUND_DOORBELL_HMUSTOPPED = (1 << 3), - MU_INBOUND_DOORBELL_RESET = (1 << 4), - - MU_OUTBOUND_DOORBELL_HANDSHAKE = (1 << 0), - MU_OUTBOUND_DOORBELL_REQUESTTAILCHANGED = (1 << 1), - MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED = (1 << 2), - MU_OUTBOUND_DOORBELL_BUSCHANGE = (1 << 3), - MU_OUTBOUND_DOORBELL_HASEVENT = (1 << 4), - MU_OUTBOUND_DOORBELL_REQUEST_RESET = (1 << 27), - - /* MU status code */ - MU_STATE_STARTING = 1, - MU_STATE_STARTED = 2, - MU_STATE_RESETTING = 3, - MU_STATE_FAILED = 4, - - MU_MAX_DELAY = 120, - MU_HANDSHAKE_SIGNATURE = 0x55aaaa55, - MU_HANDSHAKE_SIGNATURE_HALF = 0x5a5a0000, - MU_HARD_RESET_WAIT = 30000, - HMU_PARTNER_TYPE = 2, - - /* firmware returned values */ - SRB_STATUS_SUCCESS = 0x01, - SRB_STATUS_ERROR = 0x04, - SRB_STATUS_BUSY = 0x05, - SRB_STATUS_INVALID_REQUEST = 0x06, - SRB_STATUS_SELECTION_TIMEOUT = 0x0A, - SRB_SEE_SENSE = 0x80, - - /* task attribute */ - TASK_ATTRIBUTE_SIMPLE = 0x0, - TASK_ATTRIBUTE_HEADOFQUEUE = 0x1, - TASK_ATTRIBUTE_ORDERED = 0x2, - TASK_ATTRIBUTE_ACA = 0x4, - - SS_STS_NORMAL = 0x80000000, - SS_STS_DONE = 0x40000000, - SS_STS_HANDSHAKE = 0x20000000, - - SS_HEAD_HANDSHAKE = 0x80, - - SS_H2I_INT_RESET = 0x100, - - SS_I2H_REQUEST_RESET = 0x2000, - - SS_MU_OPERATIONAL = 0x80000000, - - STEX_CDB_LENGTH = 16, - STATUS_VAR_LEN = 128, - - /* sg flags */ - SG_CF_EOT = 0x80, /* end of table */ - SG_CF_64B = 0x40, /* 64 bit item */ - SG_CF_HOST = 0x20, /* sg in host memory */ - MSG_DATA_DIR_ND = 0, - MSG_DATA_DIR_IN = 1, - MSG_DATA_DIR_OUT = 2, - - st_shasta = 0, - st_vsc = 1, - st_yosemite = 2, - st_seq = 3, - st_yel = 4, - - PASSTHRU_REQ_TYPE = 0x00000001, - PASSTHRU_REQ_NO_WAKEUP = 0x00000100, - ST_INTERNAL_TIMEOUT = 180, - - ST_TO_CMD = 0, - ST_FROM_CMD = 1, - - /* vendor specific commands of Promise */ - MGT_CMD = 0xd8, - SINBAND_MGT_CMD = 0xd9, - ARRAY_CMD = 0xe0, - CONTROLLER_CMD = 0xe1, - DEBUGGING_CMD = 0xe2, - PASSTHRU_CMD = 0xe3, - - PASSTHRU_GET_ADAPTER = 0x05, - PASSTHRU_GET_DRVVER = 0x10, - - CTLR_CONFIG_CMD = 0x03, - CTLR_SHUTDOWN = 0x0d, - - CTLR_POWER_STATE_CHANGE = 0x0e, - CTLR_POWER_SAVING = 0x01, - - PASSTHRU_SIGNATURE = 0x4e415041, - MGT_CMD_SIGNATURE = 0xba, - - INQUIRY_EVPD = 0x01, - - ST_ADDITIONAL_MEM = 0x200000, - ST_ADDITIONAL_MEM_MIN = 0x80000, -}; - -struct st_sgitem { - u8 ctrl; /* SG_CF_xxx */ - u8 reserved[3]; - __le32 count; - __le64 addr; -}; - -struct st_ss_sgitem { - __le32 addr; - __le32 addr_hi; - __le32 count; -}; - -struct st_sgtable { - __le16 sg_count; - __le16 max_sg_count; - __le32 sz_in_byte; -}; - -struct st_msg_header { - __le64 handle; - u8 flag; - u8 channel; - __le16 timeout; - u32 reserved; -}; - -struct handshake_frame { - __le64 rb_phy; /* request payload queue physical address */ - __le16 req_sz; /* size of each request payload */ - __le16 req_cnt; /* count of reqs the buffer can hold */ - __le16 status_sz; /* size of each status payload */ - __le16 status_cnt; /* count of status the buffer can hold */ - __le64 hosttime; /* seconds from Jan 1, 1970 (GMT) */ - u8 partner_type; /* who sends this frame */ - u8 reserved0[7]; - __le32 partner_ver_major; - __le32 partner_ver_minor; - __le32 partner_ver_oem; - __le32 partner_ver_build; - __le32 extra_offset; /* NEW */ - __le32 extra_size; /* NEW */ - __le32 scratch_size; - u32 reserved1; -}; - -struct req_msg { - __le16 tag; - u8 lun; - u8 target; - u8 task_attr; - u8 task_manage; - u8 data_dir; - u8 payload_sz; /* payload size in 4-byte, not used */ - u8 cdb[STEX_CDB_LENGTH]; - u32 variable[0]; -}; - -struct status_msg { - __le16 tag; - u8 lun; - u8 target; - u8 srb_status; - u8 scsi_status; - u8 reserved; - u8 payload_sz; /* payload size in 4-byte */ - u8 variable[STATUS_VAR_LEN]; -}; - -struct ver_info { - u32 major; - u32 minor; - u32 oem; - u32 build; - u32 reserved[2]; -}; - -struct st_frame { - u32 base[6]; - u32 rom_addr; - - struct ver_info drv_ver; - struct ver_info bios_ver; - - u32 bus; - u32 slot; - u32 irq_level; - u32 irq_vec; - u32 id; - u32 subid; - - u32 dimm_size; - u8 dimm_type; - u8 reserved[3]; - - u32 channel; - u32 reserved1; -}; - -struct st_drvver { - u32 major; - u32 minor; - u32 oem; - u32 build; - u32 signature[2]; - u8 console_id; - u8 host_no; - u8 reserved0[2]; - u32 reserved[3]; -}; - -struct st_ccb { - struct req_msg *req; - struct scsi_cmnd *cmd; - - void *sense_buffer; - unsigned int sense_bufflen; - int sg_count; - - u32 req_type; - u8 srb_status; - u8 scsi_status; - u8 reserved[2]; -}; - -struct st_hba { - void __iomem *mmio_base; /* iomapped PCI memory space */ - void *dma_mem; - dma_addr_t dma_handle; - size_t dma_size; - - struct Scsi_Host *host; - struct pci_dev *pdev; - - struct req_msg * (*alloc_rq) (struct st_hba *); - int (*map_sg)(struct st_hba *, struct req_msg *, struct st_ccb *); - void (*send) (struct st_hba *, struct req_msg *, u16); - - u32 req_head; - u32 req_tail; - u32 status_head; - u32 status_tail; - - struct status_msg *status_buffer; - void *copy_buffer; /* temp buffer for driver-handled commands */ - struct st_ccb *ccb; - struct st_ccb *wait_ccb; - __le32 *scratch; - - char work_q_name[20]; - struct workqueue_struct *work_q; - struct work_struct reset_work; - wait_queue_head_t reset_waitq; - unsigned int mu_status; - unsigned int cardtype; - int msi_enabled; - int out_req_cnt; - u32 extra_offset; - u16 rq_count; - u16 rq_size; - u16 sts_count; -}; - -struct st_card_info { - struct req_msg * (*alloc_rq) (struct st_hba *); - int (*map_sg)(struct st_hba *, struct req_msg *, struct st_ccb *); - void (*send) (struct st_hba *, struct req_msg *, u16); - unsigned int max_id; - unsigned int max_lun; - unsigned int max_channel; - u16 rq_count; - u16 rq_size; - u16 sts_count; -}; - -static int msi; -module_param(msi, int, 0); -MODULE_PARM_DESC(msi, "Enable Message Signaled Interrupts(0=off, 1=on)"); - -static const char console_inq_page[] = -{ - 0x03,0x00,0x03,0x03,0xFA,0x00,0x00,0x30, - 0x50,0x72,0x6F,0x6D,0x69,0x73,0x65,0x20, /* "Promise " */ - 0x52,0x41,0x49,0x44,0x20,0x43,0x6F,0x6E, /* "RAID Con" */ - 0x73,0x6F,0x6C,0x65,0x20,0x20,0x20,0x20, /* "sole " */ - 0x31,0x2E,0x30,0x30,0x20,0x20,0x20,0x20, /* "1.00 " */ - 0x53,0x58,0x2F,0x52,0x53,0x41,0x46,0x2D, /* "SX/RSAF-" */ - 0x54,0x45,0x31,0x2E,0x30,0x30,0x20,0x20, /* "TE1.00 " */ - 0x0C,0x20,0x20,0x20,0x20,0x20,0x20,0x20 -}; - -MODULE_AUTHOR("Ed Lin"); -MODULE_DESCRIPTION("Promise Technology SuperTrak EX Controllers"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(ST_DRIVER_VERSION); - -static void stex_gettime(__le64 *time) -{ - struct timeval tv; - - do_gettimeofday(&tv); - *time = cpu_to_le64(tv.tv_sec); -} - -static struct status_msg *stex_get_status(struct st_hba *hba) -{ - struct status_msg *status = hba->status_buffer + hba->status_tail; - - ++hba->status_tail; - hba->status_tail %= hba->sts_count+1; - - return status; -} - -static void stex_invalid_field(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - - /* "Invalid field in cdb" */ - scsi_build_sense_buffer(0, cmd->sense_buffer, ILLEGAL_REQUEST, 0x24, - 0x0); - done(cmd); -} - -static struct req_msg *stex_alloc_req(struct st_hba *hba) -{ - struct req_msg *req = hba->dma_mem + hba->req_head * hba->rq_size; - - ++hba->req_head; - hba->req_head %= hba->rq_count+1; - - return req; -} - -static struct req_msg *stex_ss_alloc_req(struct st_hba *hba) -{ - return (struct req_msg *)(hba->dma_mem + - hba->req_head * hba->rq_size + sizeof(struct st_msg_header)); -} - -static int stex_map_sg(struct st_hba *hba, - struct req_msg *req, struct st_ccb *ccb) -{ - struct scsi_cmnd *cmd; - struct scatterlist *sg; - struct st_sgtable *dst; - struct st_sgitem *table; - int i, nseg; - - cmd = ccb->cmd; - nseg = scsi_dma_map(cmd); - BUG_ON(nseg < 0); - if (nseg) { - dst = (struct st_sgtable *)req->variable; - - ccb->sg_count = nseg; - dst->sg_count = cpu_to_le16((u16)nseg); - dst->max_sg_count = cpu_to_le16(hba->host->sg_tablesize); - dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); - - table = (struct st_sgitem *)(dst + 1); - scsi_for_each_sg(cmd, sg, nseg, i) { - table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); - table[i].addr = cpu_to_le64(sg_dma_address(sg)); - table[i].ctrl = SG_CF_64B | SG_CF_HOST; - } - table[--i].ctrl |= SG_CF_EOT; - } - - return nseg; -} - -static int stex_ss_map_sg(struct st_hba *hba, - struct req_msg *req, struct st_ccb *ccb) -{ - struct scsi_cmnd *cmd; - struct scatterlist *sg; - struct st_sgtable *dst; - struct st_ss_sgitem *table; - int i, nseg; - - cmd = ccb->cmd; - nseg = scsi_dma_map(cmd); - BUG_ON(nseg < 0); - if (nseg) { - dst = (struct st_sgtable *)req->variable; - - ccb->sg_count = nseg; - dst->sg_count = cpu_to_le16((u16)nseg); - dst->max_sg_count = cpu_to_le16(hba->host->sg_tablesize); - dst->sz_in_byte = cpu_to_le32(scsi_bufflen(cmd)); - - table = (struct st_ss_sgitem *)(dst + 1); - scsi_for_each_sg(cmd, sg, nseg, i) { - table[i].count = cpu_to_le32((u32)sg_dma_len(sg)); - table[i].addr = - cpu_to_le32(sg_dma_address(sg) & 0xffffffff); - table[i].addr_hi = - cpu_to_le32((sg_dma_address(sg) >> 16) >> 16); - } - } - - return nseg; -} - -static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb) -{ - struct st_frame *p; - size_t count = sizeof(struct st_frame); - - p = hba->copy_buffer; - scsi_sg_copy_to_buffer(ccb->cmd, p, count); - memset(p->base, 0, sizeof(u32)*6); - *(unsigned long *)(p->base) = pci_resource_start(hba->pdev, 0); - p->rom_addr = 0; - - p->drv_ver.major = ST_VER_MAJOR; - p->drv_ver.minor = ST_VER_MINOR; - p->drv_ver.oem = ST_OEM; - p->drv_ver.build = ST_BUILD_VER; - - p->bus = hba->pdev->bus->number; - p->slot = hba->pdev->devfn; - p->irq_level = 0; - p->irq_vec = hba->pdev->irq; - p->id = hba->pdev->vendor << 16 | hba->pdev->device; - p->subid = - hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device; - - scsi_sg_copy_from_buffer(ccb->cmd, p, count); -} - -static void -stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) -{ - req->tag = cpu_to_le16(tag); - - hba->ccb[tag].req = req; - hba->out_req_cnt++; - - writel(hba->req_head, hba->mmio_base + IMR0); - writel(MU_INBOUND_DOORBELL_REQHEADCHANGED, hba->mmio_base + IDBL); - readl(hba->mmio_base + IDBL); /* flush */ -} - -static void -stex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag) -{ - struct scsi_cmnd *cmd; - struct st_msg_header *msg_h; - dma_addr_t addr; - - req->tag = cpu_to_le16(tag); - - hba->ccb[tag].req = req; - hba->out_req_cnt++; - - cmd = hba->ccb[tag].cmd; - msg_h = (struct st_msg_header *)req - 1; - if (likely(cmd)) { - msg_h->channel = (u8)cmd->device->channel; - msg_h->timeout = cpu_to_le16(cmd->request->timeout/HZ); - } - addr = hba->dma_handle + hba->req_head * hba->rq_size; - addr += (hba->ccb[tag].sg_count+4)/11; - msg_h->handle = cpu_to_le64(addr); - - ++hba->req_head; - hba->req_head %= hba->rq_count+1; - - writel((addr >> 16) >> 16, hba->mmio_base + YH2I_REQ_HI); - readl(hba->mmio_base + YH2I_REQ_HI); /* flush */ - writel(addr, hba->mmio_base + YH2I_REQ); - readl(hba->mmio_base + YH2I_REQ); /* flush */ -} - -static int -stex_slave_alloc(struct scsi_device *sdev) -{ - /* Cheat: usually extracted from Inquiry data */ - sdev->tagged_supported = 1; - - scsi_activate_tcq(sdev, sdev->host->can_queue); - - return 0; -} - -static int -stex_slave_config(struct scsi_device *sdev) -{ - sdev->use_10_for_rw = 1; - sdev->use_10_for_ms = 1; - blk_queue_rq_timeout(sdev->request_queue, 60 * HZ); - sdev->tagged_supported = 1; - - return 0; -} - -static void -stex_slave_destroy(struct scsi_device *sdev) -{ - scsi_deactivate_tcq(sdev, 1); -} - -static int -stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct st_hba *hba; - struct Scsi_Host *host; - unsigned int id, lun; - struct req_msg *req; - u16 tag; - - host = cmd->device->host; - id = cmd->device->id; - lun = cmd->device->lun; - hba = (struct st_hba *) &host->hostdata[0]; - - if (unlikely(hba->mu_status == MU_STATE_RESETTING)) - return SCSI_MLQUEUE_HOST_BUSY; - - switch (cmd->cmnd[0]) { - case MODE_SENSE_10: - { - static char ms10_caching_page[12] = - { 0, 0x12, 0, 0, 0, 0, 0, 0, 0x8, 0xa, 0x4, 0 }; - unsigned char page; - - page = cmd->cmnd[2] & 0x3f; - if (page == 0x8 || page == 0x3f) { - scsi_sg_copy_from_buffer(cmd, ms10_caching_page, - sizeof(ms10_caching_page)); - cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - done(cmd); - } else - stex_invalid_field(cmd, done); - return 0; - } - case REPORT_LUNS: - /* - * The shasta firmware does not report actual luns in the - * target, so fail the command to force sequential lun scan. - * Also, the console device does not support this command. - */ - if (hba->cardtype == st_shasta || id == host->max_id - 1) { - stex_invalid_field(cmd, done); - return 0; - } - break; - case TEST_UNIT_READY: - if (id == host->max_id - 1) { - cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - done(cmd); - return 0; - } - break; - case INQUIRY: - if (lun >= host->max_lun) { - cmd->result = DID_NO_CONNECT << 16; - done(cmd); - return 0; - } - if (id != host->max_id - 1) - break; - if (!lun && !cmd->device->channel && - (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { - scsi_sg_copy_from_buffer(cmd, (void *)console_inq_page, - sizeof(console_inq_page)); - cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; - done(cmd); - } else - stex_invalid_field(cmd, done); - return 0; - case PASSTHRU_CMD: - if (cmd->cmnd[1] == PASSTHRU_GET_DRVVER) { - struct st_drvver ver; - size_t cp_len = sizeof(ver); - - ver.major = ST_VER_MAJOR; - ver.minor = ST_VER_MINOR; - ver.oem = ST_OEM; - ver.build = ST_BUILD_VER; - ver.signature[0] = PASSTHRU_SIGNATURE; - ver.console_id = host->max_id - 1; - ver.host_no = hba->host->host_no; - cp_len = scsi_sg_copy_from_buffer(cmd, &ver, cp_len); - cmd->result = sizeof(ver) == cp_len ? - DID_OK << 16 | COMMAND_COMPLETE << 8 : - DID_ERROR << 16 | COMMAND_COMPLETE << 8; - done(cmd); - return 0; - } - default: - break; - } - - cmd->scsi_done = done; - - tag = cmd->request->tag; - - if (unlikely(tag >= host->can_queue)) - return SCSI_MLQUEUE_HOST_BUSY; - - req = hba->alloc_rq(hba); - - req->lun = lun; - req->target = id; - - /* cdb */ - memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH); - - if (cmd->sc_data_direction == DMA_FROM_DEVICE) - req->data_dir = MSG_DATA_DIR_IN; - else if (cmd->sc_data_direction == DMA_TO_DEVICE) - req->data_dir = MSG_DATA_DIR_OUT; - else - req->data_dir = MSG_DATA_DIR_ND; - - hba->ccb[tag].cmd = cmd; - hba->ccb[tag].sense_bufflen = SCSI_SENSE_BUFFERSIZE; - hba->ccb[tag].sense_buffer = cmd->sense_buffer; - - if (!hba->map_sg(hba, req, &hba->ccb[tag])) { - hba->ccb[tag].sg_count = 0; - memset(&req->variable[0], 0, 8); - } - - hba->send(hba, req, tag); - return 0; -} - -static DEF_SCSI_QCMD(stex_queuecommand) - -static void stex_scsi_done(struct st_ccb *ccb) -{ - struct scsi_cmnd *cmd = ccb->cmd; - int result; - - if (ccb->srb_status == SRB_STATUS_SUCCESS || ccb->srb_status == 0) { - result = ccb->scsi_status; - switch (ccb->scsi_status) { - case SAM_STAT_GOOD: - result |= DID_OK << 16 | COMMAND_COMPLETE << 8; - break; - case SAM_STAT_CHECK_CONDITION: - result |= DRIVER_SENSE << 24; - break; - case SAM_STAT_BUSY: - result |= DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; - break; - default: - result |= DID_ERROR << 16 | COMMAND_COMPLETE << 8; - break; - } - } - else if (ccb->srb_status & SRB_SEE_SENSE) - result = DRIVER_SENSE << 24 | SAM_STAT_CHECK_CONDITION; - else switch (ccb->srb_status) { - case SRB_STATUS_SELECTION_TIMEOUT: - result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_BUSY: - result = DID_BUS_BUSY << 16 | COMMAND_COMPLETE << 8; - break; - case SRB_STATUS_INVALID_REQUEST: - case SRB_STATUS_ERROR: - default: - result = DID_ERROR << 16 | COMMAND_COMPLETE << 8; - break; - } - - cmd->result = result; - cmd->scsi_done(cmd); -} - -static void stex_copy_data(struct st_ccb *ccb, - struct status_msg *resp, unsigned int variable) -{ - if (resp->scsi_status != SAM_STAT_GOOD) { - if (ccb->sense_buffer != NULL) - memcpy(ccb->sense_buffer, resp->variable, - min(variable, ccb->sense_bufflen)); - return; - } - - if (ccb->cmd == NULL) - return; - scsi_sg_copy_from_buffer(ccb->cmd, resp->variable, variable); -} - -static void stex_check_cmd(struct st_hba *hba, - struct st_ccb *ccb, struct status_msg *resp) -{ - if (ccb->cmd->cmnd[0] == MGT_CMD && - resp->scsi_status != SAM_STAT_CHECK_CONDITION) - scsi_set_resid(ccb->cmd, scsi_bufflen(ccb->cmd) - - le32_to_cpu(*(__le32 *)&resp->variable[0])); -} - -static void stex_mu_intr(struct st_hba *hba, u32 doorbell) -{ - void __iomem *base = hba->mmio_base; - struct status_msg *resp; - struct st_ccb *ccb; - unsigned int size; - u16 tag; - - if (unlikely(!(doorbell & MU_OUTBOUND_DOORBELL_STATUSHEADCHANGED))) - return; - - /* status payloads */ - hba->status_head = readl(base + OMR1); - if (unlikely(hba->status_head > hba->sts_count)) { - printk(KERN_WARNING DRV_NAME "(%s): invalid status head\n", - pci_name(hba->pdev)); - return; - } - - /* - * it's not a valid status payload if: - * 1. there are no pending requests(e.g. during init stage) - * 2. there are some pending requests, but the controller is in - * reset status, and its type is not st_yosemite - * firmware of st_yosemite in reset status will return pending requests - * to driver, so we allow it to pass - */ - if (unlikely(hba->out_req_cnt <= 0 || - (hba->mu_status == MU_STATE_RESETTING && - hba->cardtype != st_yosemite))) { - hba->status_tail = hba->status_head; - goto update_status; - } - - while (hba->status_tail != hba->status_head) { - resp = stex_get_status(hba); - tag = le16_to_cpu(resp->tag); - if (unlikely(tag >= hba->host->can_queue)) { - printk(KERN_WARNING DRV_NAME - "(%s): invalid tag\n", pci_name(hba->pdev)); - continue; - } - - hba->out_req_cnt--; - ccb = &hba->ccb[tag]; - if (unlikely(hba->wait_ccb == ccb)) - hba->wait_ccb = NULL; - if (unlikely(ccb->req == NULL)) { - printk(KERN_WARNING DRV_NAME - "(%s): lagging req\n", pci_name(hba->pdev)); - continue; - } - - size = resp->payload_sz * sizeof(u32); /* payload size */ - if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN || - size > sizeof(*resp))) { - printk(KERN_WARNING DRV_NAME "(%s): bad status size\n", - pci_name(hba->pdev)); - } else { - size -= sizeof(*resp) - STATUS_VAR_LEN; /* copy size */ - if (size) - stex_copy_data(ccb, resp, size); - } - - ccb->req = NULL; - ccb->srb_status = resp->srb_status; - ccb->scsi_status = resp->scsi_status; - - if (likely(ccb->cmd != NULL)) { - if (hba->cardtype == st_yosemite) - stex_check_cmd(hba, ccb, resp); - - if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD && - ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER)) - stex_controller_info(hba, ccb); - - scsi_dma_unmap(ccb->cmd); - stex_scsi_done(ccb); - } else - ccb->req_type = 0; - } - -update_status: - writel(hba->status_head, base + IMR1); - readl(base + IMR1); /* flush */ -} - -static irqreturn_t stex_intr(int irq, void *__hba) -{ - struct st_hba *hba = __hba; - void __iomem *base = hba->mmio_base; - u32 data; - unsigned long flags; - - spin_lock_irqsave(hba->host->host_lock, flags); - - data = readl(base + ODBL); - - if (data && data != 0xffffffff) { - /* clear the interrupt */ - writel(data, base + ODBL); - readl(base + ODBL); /* flush */ - stex_mu_intr(hba, data); - spin_unlock_irqrestore(hba->host->host_lock, flags); - if (unlikely(data & MU_OUTBOUND_DOORBELL_REQUEST_RESET && - hba->cardtype == st_shasta)) - queue_work(hba->work_q, &hba->reset_work); - return IRQ_HANDLED; - } - - spin_unlock_irqrestore(hba->host->host_lock, flags); - - return IRQ_NONE; -} - -static void stex_ss_mu_intr(struct st_hba *hba) -{ - struct status_msg *resp; - struct st_ccb *ccb; - __le32 *scratch; - unsigned int size; - int count = 0; - u32 value; - u16 tag; - - if (unlikely(hba->out_req_cnt <= 0 || - hba->mu_status == MU_STATE_RESETTING)) - return; - - while (count < hba->sts_count) { - scratch = hba->scratch + hba->status_tail; - value = le32_to_cpu(*scratch); - if (unlikely(!(value & SS_STS_NORMAL))) - return; - - resp = hba->status_buffer + hba->status_tail; - *scratch = 0; - ++count; - ++hba->status_tail; - hba->status_tail %= hba->sts_count+1; - - tag = (u16)value; - if (unlikely(tag >= hba->host->can_queue)) { - printk(KERN_WARNING DRV_NAME - "(%s): invalid tag\n", pci_name(hba->pdev)); - continue; - } - - hba->out_req_cnt--; - ccb = &hba->ccb[tag]; - if (unlikely(hba->wait_ccb == ccb)) - hba->wait_ccb = NULL; - if (unlikely(ccb->req == NULL)) { - printk(KERN_WARNING DRV_NAME - "(%s): lagging req\n", pci_name(hba->pdev)); - continue; - } - - ccb->req = NULL; - if (likely(value & SS_STS_DONE)) { /* normal case */ - ccb->srb_status = SRB_STATUS_SUCCESS; - ccb->scsi_status = SAM_STAT_GOOD; - } else { - ccb->srb_status = resp->srb_status; - ccb->scsi_status = resp->scsi_status; - size = resp->payload_sz * sizeof(u32); - if (unlikely(size < sizeof(*resp) - STATUS_VAR_LEN || - size > sizeof(*resp))) { - printk(KERN_WARNING DRV_NAME - "(%s): bad status size\n", - pci_name(hba->pdev)); - } else { - size -= sizeof(*resp) - STATUS_VAR_LEN; - if (size) - stex_copy_data(ccb, resp, size); - } - if (likely(ccb->cmd != NULL)) - stex_check_cmd(hba, ccb, resp); - } - - if (likely(ccb->cmd != NULL)) { - scsi_dma_unmap(ccb->cmd); - stex_scsi_done(ccb); - } else - ccb->req_type = 0; - } -} - -static irqreturn_t stex_ss_intr(int irq, void *__hba) -{ - struct st_hba *hba = __hba; - void __iomem *base = hba->mmio_base; - u32 data; - unsigned long flags; - - spin_lock_irqsave(hba->host->host_lock, flags); - - data = readl(base + YI2H_INT); - if (data && data != 0xffffffff) { - /* clear the interrupt */ - writel(data, base + YI2H_INT_C); - stex_ss_mu_intr(hba); - spin_unlock_irqrestore(hba->host->host_lock, flags); - if (unlikely(data & SS_I2H_REQUEST_RESET)) - queue_work(hba->work_q, &hba->reset_work); - return IRQ_HANDLED; - } - - spin_unlock_irqrestore(hba->host->host_lock, flags); - - return IRQ_NONE; -} - -static int stex_common_handshake(struct st_hba *hba) -{ - void __iomem *base = hba->mmio_base; - struct handshake_frame *h; - dma_addr_t status_phys; - u32 data; - unsigned long before; - - if (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { - writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL); - readl(base + IDBL); - before = jiffies; - while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { - if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { - printk(KERN_ERR DRV_NAME - "(%s): no handshake signature\n", - pci_name(hba->pdev)); - return -1; - } - rmb(); - msleep(1); - } - } - - udelay(10); - - data = readl(base + OMR1); - if ((data & 0xffff0000) == MU_HANDSHAKE_SIGNATURE_HALF) { - data &= 0x0000ffff; - if (hba->host->can_queue > data) { - hba->host->can_queue = data; - hba->host->cmd_per_lun = data; - } - } - - h = (struct handshake_frame *)hba->status_buffer; - h->rb_phy = cpu_to_le64(hba->dma_handle); - h->req_sz = cpu_to_le16(hba->rq_size); - h->req_cnt = cpu_to_le16(hba->rq_count+1); - h->status_sz = cpu_to_le16(sizeof(struct status_msg)); - h->status_cnt = cpu_to_le16(hba->sts_count+1); - stex_gettime(&h->hosttime); - h->partner_type = HMU_PARTNER_TYPE; - if (hba->extra_offset) { - h->extra_offset = cpu_to_le32(hba->extra_offset); - h->extra_size = cpu_to_le32(hba->dma_size - hba->extra_offset); - } else - h->extra_offset = h->extra_size = 0; - - status_phys = hba->dma_handle + (hba->rq_count+1) * hba->rq_size; - writel(status_phys, base + IMR0); - readl(base + IMR0); - writel((status_phys >> 16) >> 16, base + IMR1); - readl(base + IMR1); - - writel((status_phys >> 16) >> 16, base + OMR0); /* old fw compatible */ - readl(base + OMR0); - writel(MU_INBOUND_DOORBELL_HANDSHAKE, base + IDBL); - readl(base + IDBL); /* flush */ - - udelay(10); - before = jiffies; - while (readl(base + OMR0) != MU_HANDSHAKE_SIGNATURE) { - if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { - printk(KERN_ERR DRV_NAME - "(%s): no signature after handshake frame\n", - pci_name(hba->pdev)); - return -1; - } - rmb(); - msleep(1); - } - - writel(0, base + IMR0); - readl(base + IMR0); - writel(0, base + OMR0); - readl(base + OMR0); - writel(0, base + IMR1); - readl(base + IMR1); - writel(0, base + OMR1); - readl(base + OMR1); /* flush */ - return 0; -} - -static int stex_ss_handshake(struct st_hba *hba) -{ - void __iomem *base = hba->mmio_base; - struct st_msg_header *msg_h; - struct handshake_frame *h; - __le32 *scratch; - u32 data, scratch_size; - unsigned long before; - int ret = 0; - - before = jiffies; - while ((readl(base + YIOA_STATUS) & SS_MU_OPERATIONAL) == 0) { - if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { - printk(KERN_ERR DRV_NAME - "(%s): firmware not operational\n", - pci_name(hba->pdev)); - return -1; - } - msleep(1); - } - - msg_h = (struct st_msg_header *)hba->dma_mem; - msg_h->handle = cpu_to_le64(hba->dma_handle); - msg_h->flag = SS_HEAD_HANDSHAKE; - - h = (struct handshake_frame *)(msg_h + 1); - h->rb_phy = cpu_to_le64(hba->dma_handle); - h->req_sz = cpu_to_le16(hba->rq_size); - h->req_cnt = cpu_to_le16(hba->rq_count+1); - h->status_sz = cpu_to_le16(sizeof(struct status_msg)); - h->status_cnt = cpu_to_le16(hba->sts_count+1); - stex_gettime(&h->hosttime); - h->partner_type = HMU_PARTNER_TYPE; - h->extra_offset = h->extra_size = 0; - scratch_size = (hba->sts_count+1)*sizeof(u32); - h->scratch_size = cpu_to_le32(scratch_size); - - data = readl(base + YINT_EN); - data &= ~4; - writel(data, base + YINT_EN); - writel((hba->dma_handle >> 16) >> 16, base + YH2I_REQ_HI); - readl(base + YH2I_REQ_HI); - writel(hba->dma_handle, base + YH2I_REQ); - readl(base + YH2I_REQ); /* flush */ - - scratch = hba->scratch; - before = jiffies; - while (!(le32_to_cpu(*scratch) & SS_STS_HANDSHAKE)) { - if (time_after(jiffies, before + MU_MAX_DELAY * HZ)) { - printk(KERN_ERR DRV_NAME - "(%s): no signature after handshake frame\n", - pci_name(hba->pdev)); - ret = -1; - break; - } - rmb(); - msleep(1); - } - - memset(scratch, 0, scratch_size); - msg_h->flag = 0; - return ret; -} - -static int stex_handshake(struct st_hba *hba) -{ - int err; - unsigned long flags; - unsigned int mu_status; - - err = (hba->cardtype == st_yel) ? - stex_ss_handshake(hba) : stex_common_handshake(hba); - spin_lock_irqsave(hba->host->host_lock, flags); - mu_status = hba->mu_status; - if (err == 0) { - hba->req_head = 0; - hba->req_tail = 0; - hba->status_head = 0; - hba->status_tail = 0; - hba->out_req_cnt = 0; - hba->mu_status = MU_STATE_STARTED; - } else - hba->mu_status = MU_STATE_FAILED; - if (mu_status == MU_STATE_RESETTING) - wake_up_all(&hba->reset_waitq); - spin_unlock_irqrestore(hba->host->host_lock, flags); - return err; -} - -static int stex_abort(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host = cmd->device->host; - struct st_hba *hba = (struct st_hba *)host->hostdata; - u16 tag = cmd->request->tag; - void __iomem *base; - u32 data; - int result = SUCCESS; - unsigned long flags; - - printk(KERN_INFO DRV_NAME - "(%s): aborting command\n", pci_name(hba->pdev)); - scsi_print_command(cmd); - - base = hba->mmio_base; - spin_lock_irqsave(host->host_lock, flags); - if (tag < host->can_queue && - hba->ccb[tag].req && hba->ccb[tag].cmd == cmd) - hba->wait_ccb = &hba->ccb[tag]; - else - goto out; - - if (hba->cardtype == st_yel) { - data = readl(base + YI2H_INT); - if (data == 0 || data == 0xffffffff) - goto fail_out; - - writel(data, base + YI2H_INT_C); - stex_ss_mu_intr(hba); - } else { - data = readl(base + ODBL); - if (data == 0 || data == 0xffffffff) - goto fail_out; - - writel(data, base + ODBL); - readl(base + ODBL); /* flush */ - - stex_mu_intr(hba, data); - } - if (hba->wait_ccb == NULL) { - printk(KERN_WARNING DRV_NAME - "(%s): lost interrupt\n", pci_name(hba->pdev)); - goto out; - } - -fail_out: - scsi_dma_unmap(cmd); - hba->wait_ccb->req = NULL; /* nullify the req's future return */ - hba->wait_ccb = NULL; - result = FAILED; -out: - spin_unlock_irqrestore(host->host_lock, flags); - return result; -} - -static void stex_hard_reset(struct st_hba *hba) -{ - struct pci_bus *bus; - int i; - u16 pci_cmd; - u8 pci_bctl; - - for (i = 0; i < 16; i++) - pci_read_config_dword(hba->pdev, i * 4, - &hba->pdev->saved_config_space[i]); - - /* Reset secondary bus. Our controller(MU/ATU) is the only device on - secondary bus. Consult Intel 80331/3 developer's manual for detail */ - bus = hba->pdev->bus; - pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl); - pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET; - pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); - - /* - * 1 ms may be enough for 8-port controllers. But 16-port controllers - * require more time to finish bus reset. Use 100 ms here for safety - */ - msleep(100); - pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET; - pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); - - for (i = 0; i < MU_HARD_RESET_WAIT; i++) { - pci_read_config_word(hba->pdev, PCI_COMMAND, &pci_cmd); - if (pci_cmd != 0xffff && (pci_cmd & PCI_COMMAND_MASTER)) - break; - msleep(1); - } - - ssleep(5); - for (i = 0; i < 16; i++) - pci_write_config_dword(hba->pdev, i * 4, - hba->pdev->saved_config_space[i]); -} - -static int stex_yos_reset(struct st_hba *hba) -{ - void __iomem *base; - unsigned long flags, before; - int ret = 0; - - base = hba->mmio_base; - writel(MU_INBOUND_DOORBELL_RESET, base + IDBL); - readl(base + IDBL); /* flush */ - before = jiffies; - while (hba->out_req_cnt > 0) { - if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { - printk(KERN_WARNING DRV_NAME - "(%s): reset timeout\n", pci_name(hba->pdev)); - ret = -1; - break; - } - msleep(1); - } - - spin_lock_irqsave(hba->host->host_lock, flags); - if (ret == -1) - hba->mu_status = MU_STATE_FAILED; - else - hba->mu_status = MU_STATE_STARTED; - wake_up_all(&hba->reset_waitq); - spin_unlock_irqrestore(hba->host->host_lock, flags); - - return ret; -} - -static void stex_ss_reset(struct st_hba *hba) -{ - writel(SS_H2I_INT_RESET, hba->mmio_base + YH2I_INT); - readl(hba->mmio_base + YH2I_INT); - ssleep(5); -} - -static int stex_do_reset(struct st_hba *hba) -{ - struct st_ccb *ccb; - unsigned long flags; - unsigned int mu_status = MU_STATE_RESETTING; - u16 tag; - - spin_lock_irqsave(hba->host->host_lock, flags); - if (hba->mu_status == MU_STATE_STARTING) { - spin_unlock_irqrestore(hba->host->host_lock, flags); - printk(KERN_INFO DRV_NAME "(%s): request reset during init\n", - pci_name(hba->pdev)); - return 0; - } - while (hba->mu_status == MU_STATE_RESETTING) { - spin_unlock_irqrestore(hba->host->host_lock, flags); - wait_event_timeout(hba->reset_waitq, - hba->mu_status != MU_STATE_RESETTING, - MU_MAX_DELAY * HZ); - spin_lock_irqsave(hba->host->host_lock, flags); - mu_status = hba->mu_status; - } - - if (mu_status != MU_STATE_RESETTING) { - spin_unlock_irqrestore(hba->host->host_lock, flags); - return (mu_status == MU_STATE_STARTED) ? 0 : -1; - } - - hba->mu_status = MU_STATE_RESETTING; - spin_unlock_irqrestore(hba->host->host_lock, flags); - - if (hba->cardtype == st_yosemite) - return stex_yos_reset(hba); - - if (hba->cardtype == st_shasta) - stex_hard_reset(hba); - else if (hba->cardtype == st_yel) - stex_ss_reset(hba); - - spin_lock_irqsave(hba->host->host_lock, flags); - for (tag = 0; tag < hba->host->can_queue; tag++) { - ccb = &hba->ccb[tag]; - if (ccb->req == NULL) - continue; - ccb->req = NULL; - if (ccb->cmd) { - scsi_dma_unmap(ccb->cmd); - ccb->cmd->result = DID_RESET << 16; - ccb->cmd->scsi_done(ccb->cmd); - ccb->cmd = NULL; - } - } - spin_unlock_irqrestore(hba->host->host_lock, flags); - - if (stex_handshake(hba) == 0) - return 0; - - printk(KERN_WARNING DRV_NAME "(%s): resetting: handshake failed\n", - pci_name(hba->pdev)); - return -1; -} - -static int stex_reset(struct scsi_cmnd *cmd) -{ - struct st_hba *hba; - - hba = (struct st_hba *) &cmd->device->host->hostdata[0]; - - printk(KERN_INFO DRV_NAME - "(%s): resetting host\n", pci_name(hba->pdev)); - scsi_print_command(cmd); - - return stex_do_reset(hba) ? FAILED : SUCCESS; -} - -static void stex_reset_work(struct work_struct *work) -{ - struct st_hba *hba = container_of(work, struct st_hba, reset_work); - - stex_do_reset(hba); -} - -static int stex_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int geom[]) -{ - int heads = 255, sectors = 63; - - if (capacity < 0x200000) { - heads = 64; - sectors = 32; - } - - sector_div(capacity, heads * sectors); - - geom[0] = heads; - geom[1] = sectors; - geom[2] = capacity; - - return 0; -} - -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .name = DRV_NAME, - .proc_name = DRV_NAME, - .bios_param = stex_biosparam, - .queuecommand = stex_queuecommand, - .slave_alloc = stex_slave_alloc, - .slave_configure = stex_slave_config, - .slave_destroy = stex_slave_destroy, - .eh_abort_handler = stex_abort, - .eh_host_reset_handler = stex_reset, - .this_id = -1, -}; - -static struct pci_device_id stex_pci_tbl[] = { - /* st_shasta */ - { 0x105a, 0x8350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_shasta }, /* SuperTrak EX8350/8300/16350/16300 */ - { 0x105a, 0xc350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_shasta }, /* SuperTrak EX12350 */ - { 0x105a, 0x4302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_shasta }, /* SuperTrak EX4350 */ - { 0x105a, 0xe350, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - st_shasta }, /* SuperTrak EX24350 */ - - /* st_vsc */ - { 0x105a, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc }, - - /* st_yosemite */ - { 0x105a, 0x8650, 0x105a, PCI_ANY_ID, 0, 0, st_yosemite }, - - /* st_seq */ - { 0x105a, 0x3360, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_seq }, - - /* st_yel */ - { 0x105a, 0x8650, 0x1033, PCI_ANY_ID, 0, 0, st_yel }, - { 0x105a, 0x8760, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yel }, - { } /* terminate list */ -}; - -static struct st_card_info stex_card_info[] = { - /* st_shasta */ - { - .max_id = 17, - .max_lun = 8, - .max_channel = 0, - .rq_count = 32, - .rq_size = 1048, - .sts_count = 32, - .alloc_rq = stex_alloc_req, - .map_sg = stex_map_sg, - .send = stex_send_cmd, - }, - - /* st_vsc */ - { - .max_id = 129, - .max_lun = 1, - .max_channel = 0, - .rq_count = 32, - .rq_size = 1048, - .sts_count = 32, - .alloc_rq = stex_alloc_req, - .map_sg = stex_map_sg, - .send = stex_send_cmd, - }, - - /* st_yosemite */ - { - .max_id = 2, - .max_lun = 256, - .max_channel = 0, - .rq_count = 256, - .rq_size = 1048, - .sts_count = 256, - .alloc_rq = stex_alloc_req, - .map_sg = stex_map_sg, - .send = stex_send_cmd, - }, - - /* st_seq */ - { - .max_id = 129, - .max_lun = 1, - .max_channel = 0, - .rq_count = 32, - .rq_size = 1048, - .sts_count = 32, - .alloc_rq = stex_alloc_req, - .map_sg = stex_map_sg, - .send = stex_send_cmd, - }, - - /* st_yel */ - { - .max_id = 129, - .max_lun = 256, - .max_channel = 3, - .rq_count = 801, - .rq_size = 512, - .sts_count = 801, - .alloc_rq = stex_ss_alloc_req, - .map_sg = stex_ss_map_sg, - .send = stex_ss_send_cmd, - }, -}; - -static int stex_set_dma_mask(struct pci_dev * pdev) -{ - int ret; - - if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) - && !pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64))) - return 0; - ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (!ret) - ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - return ret; -} - -static int stex_request_irq(struct st_hba *hba) -{ - struct pci_dev *pdev = hba->pdev; - int status; - - if (msi) { - status = pci_enable_msi(pdev); - if (status != 0) - printk(KERN_ERR DRV_NAME - "(%s): error %d setting up MSI\n", - pci_name(pdev), status); - else - hba->msi_enabled = 1; - } else - hba->msi_enabled = 0; - - status = request_irq(pdev->irq, hba->cardtype == st_yel ? - stex_ss_intr : stex_intr, IRQF_SHARED, DRV_NAME, hba); - - if (status != 0) { - if (hba->msi_enabled) - pci_disable_msi(pdev); - } - return status; -} - -static void stex_free_irq(struct st_hba *hba) -{ - struct pci_dev *pdev = hba->pdev; - - free_irq(pdev->irq, hba); - if (hba->msi_enabled) - pci_disable_msi(pdev); -} - -static int __devinit -stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct st_hba *hba; - struct Scsi_Host *host; - const struct st_card_info *ci = NULL; - u32 sts_offset, cp_offset, scratch_offset; - int err; - - err = pci_enable_device(pdev); - if (err) - return err; - - pci_set_master(pdev); - - host = scsi_host_alloc(&driver_template, sizeof(struct st_hba)); - - if (!host) { - printk(KERN_ERR DRV_NAME "(%s): scsi_host_alloc failed\n", - pci_name(pdev)); - err = -ENOMEM; - goto out_disable; - } - - hba = (struct st_hba *)host->hostdata; - memset(hba, 0, sizeof(struct st_hba)); - - err = pci_request_regions(pdev, DRV_NAME); - if (err < 0) { - printk(KERN_ERR DRV_NAME "(%s): request regions failed\n", - pci_name(pdev)); - goto out_scsi_host_put; - } - - hba->mmio_base = pci_ioremap_bar(pdev, 0); - if ( !hba->mmio_base) { - printk(KERN_ERR DRV_NAME "(%s): memory map failed\n", - pci_name(pdev)); - err = -ENOMEM; - goto out_release_regions; - } - - err = stex_set_dma_mask(pdev); - if (err) { - printk(KERN_ERR DRV_NAME "(%s): set dma mask failed\n", - pci_name(pdev)); - goto out_iounmap; - } - - hba->cardtype = (unsigned int) id->driver_data; - ci = &stex_card_info[hba->cardtype]; - sts_offset = scratch_offset = (ci->rq_count+1) * ci->rq_size; - if (hba->cardtype == st_yel) - sts_offset += (ci->sts_count+1) * sizeof(u32); - cp_offset = sts_offset + (ci->sts_count+1) * sizeof(struct status_msg); - hba->dma_size = cp_offset + sizeof(struct st_frame); - if (hba->cardtype == st_seq || - (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) { - hba->extra_offset = hba->dma_size; - hba->dma_size += ST_ADDITIONAL_MEM; - } - hba->dma_mem = dma_alloc_coherent(&pdev->dev, - hba->dma_size, &hba->dma_handle, GFP_KERNEL); - if (!hba->dma_mem) { - /* Retry minimum coherent mapping for st_seq and st_vsc */ - if (hba->cardtype == st_seq || - (hba->cardtype == st_vsc && (pdev->subsystem_device & 1))) { - printk(KERN_WARNING DRV_NAME - "(%s): allocating min buffer for controller\n", - pci_name(pdev)); - hba->dma_size = hba->extra_offset - + ST_ADDITIONAL_MEM_MIN; - hba->dma_mem = dma_alloc_coherent(&pdev->dev, - hba->dma_size, &hba->dma_handle, GFP_KERNEL); - } - - if (!hba->dma_mem) { - err = -ENOMEM; - printk(KERN_ERR DRV_NAME "(%s): dma mem alloc failed\n", - pci_name(pdev)); - goto out_iounmap; - } - } - - hba->ccb = kcalloc(ci->rq_count, sizeof(struct st_ccb), GFP_KERNEL); - if (!hba->ccb) { - err = -ENOMEM; - printk(KERN_ERR DRV_NAME "(%s): ccb alloc failed\n", - pci_name(pdev)); - goto out_pci_free; - } - - if (hba->cardtype == st_yel) - hba->scratch = (__le32 *)(hba->dma_mem + scratch_offset); - hba->status_buffer = (struct status_msg *)(hba->dma_mem + sts_offset); - hba->copy_buffer = hba->dma_mem + cp_offset; - hba->rq_count = ci->rq_count; - hba->rq_size = ci->rq_size; - hba->sts_count = ci->sts_count; - hba->alloc_rq = ci->alloc_rq; - hba->map_sg = ci->map_sg; - hba->send = ci->send; - hba->mu_status = MU_STATE_STARTING; - - if (hba->cardtype == st_yel) - host->sg_tablesize = 38; - else - host->sg_tablesize = 32; - host->can_queue = ci->rq_count; - host->cmd_per_lun = ci->rq_count; - host->max_id = ci->max_id; - host->max_lun = ci->max_lun; - host->max_channel = ci->max_channel; - host->unique_id = host->host_no; - host->max_cmd_len = STEX_CDB_LENGTH; - - hba->host = host; - hba->pdev = pdev; - init_waitqueue_head(&hba->reset_waitq); - - snprintf(hba->work_q_name, sizeof(hba->work_q_name), - "stex_wq_%d", host->host_no); - hba->work_q = create_singlethread_workqueue(hba->work_q_name); - if (!hba->work_q) { - printk(KERN_ERR DRV_NAME "(%s): create workqueue failed\n", - pci_name(pdev)); - err = -ENOMEM; - goto out_ccb_free; - } - INIT_WORK(&hba->reset_work, stex_reset_work); - - err = stex_request_irq(hba); - if (err) { - printk(KERN_ERR DRV_NAME "(%s): request irq failed\n", - pci_name(pdev)); - goto out_free_wq; - } - - err = stex_handshake(hba); - if (err) - goto out_free_irq; - - err = scsi_init_shared_tag_map(host, host->can_queue); - if (err) { - printk(KERN_ERR DRV_NAME "(%s): init shared queue failed\n", - pci_name(pdev)); - goto out_free_irq; - } - - pci_set_drvdata(pdev, hba); - - err = scsi_add_host(host, &pdev->dev); - if (err) { - printk(KERN_ERR DRV_NAME "(%s): scsi_add_host failed\n", - pci_name(pdev)); - goto out_free_irq; - } - - scsi_scan_host(host); - - return 0; - -out_free_irq: - stex_free_irq(hba); -out_free_wq: - destroy_workqueue(hba->work_q); -out_ccb_free: - kfree(hba->ccb); -out_pci_free: - dma_free_coherent(&pdev->dev, hba->dma_size, - hba->dma_mem, hba->dma_handle); -out_iounmap: - iounmap(hba->mmio_base); -out_release_regions: - pci_release_regions(pdev); -out_scsi_host_put: - scsi_host_put(host); -out_disable: - pci_disable_device(pdev); - - return err; -} - -static void stex_hba_stop(struct st_hba *hba) -{ - struct req_msg *req; - struct st_msg_header *msg_h; - unsigned long flags; - unsigned long before; - u16 tag = 0; - - spin_lock_irqsave(hba->host->host_lock, flags); - req = hba->alloc_rq(hba); - if (hba->cardtype == st_yel) { - msg_h = (struct st_msg_header *)req - 1; - memset(msg_h, 0, hba->rq_size); - } else - memset(req, 0, hba->rq_size); - - if (hba->cardtype == st_yosemite || hba->cardtype == st_yel) { - req->cdb[0] = MGT_CMD; - req->cdb[1] = MGT_CMD_SIGNATURE; - req->cdb[2] = CTLR_CONFIG_CMD; - req->cdb[3] = CTLR_SHUTDOWN; - } else { - req->cdb[0] = CONTROLLER_CMD; - req->cdb[1] = CTLR_POWER_STATE_CHANGE; - req->cdb[2] = CTLR_POWER_SAVING; - } - - hba->ccb[tag].cmd = NULL; - hba->ccb[tag].sg_count = 0; - hba->ccb[tag].sense_bufflen = 0; - hba->ccb[tag].sense_buffer = NULL; - hba->ccb[tag].req_type = PASSTHRU_REQ_TYPE; - - hba->send(hba, req, tag); - spin_unlock_irqrestore(hba->host->host_lock, flags); - - before = jiffies; - while (hba->ccb[tag].req_type & PASSTHRU_REQ_TYPE) { - if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) { - hba->ccb[tag].req_type = 0; - return; - } - msleep(1); - } -} - -static void stex_hba_free(struct st_hba *hba) -{ - stex_free_irq(hba); - - destroy_workqueue(hba->work_q); - - iounmap(hba->mmio_base); - - pci_release_regions(hba->pdev); - - kfree(hba->ccb); - - dma_free_coherent(&hba->pdev->dev, hba->dma_size, - hba->dma_mem, hba->dma_handle); -} - -static void stex_remove(struct pci_dev *pdev) -{ - struct st_hba *hba = pci_get_drvdata(pdev); - - scsi_remove_host(hba->host); - - pci_set_drvdata(pdev, NULL); - - stex_hba_stop(hba); - - stex_hba_free(hba); - - scsi_host_put(hba->host); - - pci_disable_device(pdev); -} - -static void stex_shutdown(struct pci_dev *pdev) -{ - struct st_hba *hba = pci_get_drvdata(pdev); - - stex_hba_stop(hba); -} - -MODULE_DEVICE_TABLE(pci, stex_pci_tbl); - -static struct pci_driver stex_pci_driver = { - .name = DRV_NAME, - .id_table = stex_pci_tbl, - .probe = stex_probe, - .remove = __devexit_p(stex_remove), - .shutdown = stex_shutdown, -}; - -static int __init stex_init(void) -{ - printk(KERN_INFO DRV_NAME - ": Promise SuperTrak EX Driver version: %s\n", - ST_DRIVER_VERSION); - - return pci_register_driver(&stex_pci_driver); -} - -static void __exit stex_exit(void) -{ - pci_unregister_driver(&stex_pci_driver); -} - -module_init(stex_init); -module_exit(stex_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/storvsc_drv.c b/ANDROID_3.4.5/drivers/scsi/storvsc_drv.c deleted file mode 100644 index 83a1972a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/storvsc_drv.c +++ /dev/null @@ -1,1548 +0,0 @@ -/* - * Copyright (c) 2009, Microsoft Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - * - * Authors: - * Haiyang Zhang - * Hank Janssen - * K. Y. Srinivasan - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * All wire protocol details (storage protocol between the guest and the host) - * are consolidated here. - * - * Begin protocol definitions. - */ - -/* - * Version history: - * V1 Beta: 0.1 - * V1 RC < 2008/1/31: 1.0 - * V1 RC > 2008/1/31: 2.0 - * Win7: 4.2 - */ - -#define VMSTOR_CURRENT_MAJOR 4 -#define VMSTOR_CURRENT_MINOR 2 - - -/* Packet structure describing virtual storage requests. */ -enum vstor_packet_operation { - VSTOR_OPERATION_COMPLETE_IO = 1, - VSTOR_OPERATION_REMOVE_DEVICE = 2, - VSTOR_OPERATION_EXECUTE_SRB = 3, - VSTOR_OPERATION_RESET_LUN = 4, - VSTOR_OPERATION_RESET_ADAPTER = 5, - VSTOR_OPERATION_RESET_BUS = 6, - VSTOR_OPERATION_BEGIN_INITIALIZATION = 7, - VSTOR_OPERATION_END_INITIALIZATION = 8, - VSTOR_OPERATION_QUERY_PROTOCOL_VERSION = 9, - VSTOR_OPERATION_QUERY_PROPERTIES = 10, - VSTOR_OPERATION_ENUMERATE_BUS = 11, - VSTOR_OPERATION_MAXIMUM = 11 -}; - -/* - * Platform neutral description of a scsi request - - * this remains the same across the write regardless of 32/64 bit - * note: it's patterned off the SCSI_PASS_THROUGH structure - */ -#define STORVSC_MAX_CMD_LEN 0x10 -#define STORVSC_SENSE_BUFFER_SIZE 0x12 -#define STORVSC_MAX_BUF_LEN_WITH_PADDING 0x14 - -struct vmscsi_request { - u16 length; - u8 srb_status; - u8 scsi_status; - - u8 port_number; - u8 path_id; - u8 target_id; - u8 lun; - - u8 cdb_length; - u8 sense_info_length; - u8 data_in; - u8 reserved; - - u32 data_transfer_length; - - union { - u8 cdb[STORVSC_MAX_CMD_LEN]; - u8 sense_data[STORVSC_SENSE_BUFFER_SIZE]; - u8 reserved_array[STORVSC_MAX_BUF_LEN_WITH_PADDING]; - }; -} __attribute((packed)); - - -/* - * This structure is sent during the intialization phase to get the different - * properties of the channel. - */ -struct vmstorage_channel_properties { - u16 protocol_version; - u8 path_id; - u8 target_id; - - /* Note: port number is only really known on the client side */ - u32 port_number; - u32 flags; - u32 max_transfer_bytes; - - /* - * This id is unique for each channel and will correspond with - * vendor specific data in the inquiry data. - */ - - u64 unique_id; -} __packed; - -/* This structure is sent during the storage protocol negotiations. */ -struct vmstorage_protocol_version { - /* Major (MSW) and minor (LSW) version numbers. */ - u16 major_minor; - - /* - * Revision number is auto-incremented whenever this file is changed - * (See FILL_VMSTOR_REVISION macro above). Mismatch does not - * definitely indicate incompatibility--but it does indicate mismatched - * builds. - * This is only used on the windows side. Just set it to 0. - */ - u16 revision; -} __packed; - -/* Channel Property Flags */ -#define STORAGE_CHANNEL_REMOVABLE_FLAG 0x1 -#define STORAGE_CHANNEL_EMULATED_IDE_FLAG 0x2 - -struct vstor_packet { - /* Requested operation type */ - enum vstor_packet_operation operation; - - /* Flags - see below for values */ - u32 flags; - - /* Status of the request returned from the server side. */ - u32 status; - - /* Data payload area */ - union { - /* - * Structure used to forward SCSI commands from the - * client to the server. - */ - struct vmscsi_request vm_srb; - - /* Structure used to query channel properties. */ - struct vmstorage_channel_properties storage_channel_properties; - - /* Used during version negotiations. */ - struct vmstorage_protocol_version version; - }; -} __packed; - -/* - * Packet Flags: - * - * This flag indicates that the server should send back a completion for this - * packet. - */ - -#define REQUEST_COMPLETION_FLAG 0x1 - -/* Matches Windows-end */ -enum storvsc_request_type { - WRITE_TYPE = 0, - READ_TYPE, - UNKNOWN_TYPE, -}; - -/* - * SRB status codes and masks; a subset of the codes used here. - */ - -#define SRB_STATUS_AUTOSENSE_VALID 0x80 -#define SRB_STATUS_INVALID_LUN 0x20 -#define SRB_STATUS_SUCCESS 0x01 -#define SRB_STATUS_ERROR 0x04 - -/* - * This is the end of Protocol specific defines. - */ - - -/* - * We setup a mempool to allocate request structures for this driver - * on a per-lun basis. The following define specifies the number of - * elements in the pool. - */ - -#define STORVSC_MIN_BUF_NR 64 -static int storvsc_ringbuffer_size = (20 * PAGE_SIZE); - -module_param(storvsc_ringbuffer_size, int, S_IRUGO); -MODULE_PARM_DESC(storvsc_ringbuffer_size, "Ring buffer size (bytes)"); - -#define STORVSC_MAX_IO_REQUESTS 128 - -/* - * In Hyper-V, each port/path/target maps to 1 scsi host adapter. In - * reality, the path/target is not used (ie always set to 0) so our - * scsi host adapter essentially has 1 bus with 1 target that contains - * up to 256 luns. - */ -#define STORVSC_MAX_LUNS_PER_TARGET 64 -#define STORVSC_MAX_TARGETS 1 -#define STORVSC_MAX_CHANNELS 1 - - - -struct storvsc_cmd_request { - struct list_head entry; - struct scsi_cmnd *cmd; - - unsigned int bounce_sgl_count; - struct scatterlist *bounce_sgl; - - struct hv_device *device; - - /* Synchronize the request/response if needed */ - struct completion wait_event; - - unsigned char *sense_buffer; - struct hv_multipage_buffer data_buffer; - struct vstor_packet vstor_packet; -}; - - -/* A storvsc device is a device object that contains a vmbus channel */ -struct storvsc_device { - struct hv_device *device; - - bool destroy; - bool drain_notify; - atomic_t num_outstanding_req; - struct Scsi_Host *host; - - wait_queue_head_t waiting_to_drain; - - /* - * Each unique Port/Path/Target represents 1 channel ie scsi - * controller. In reality, the pathid, targetid is always 0 - * and the port is set by us - */ - unsigned int port_number; - unsigned char path_id; - unsigned char target_id; - - /* Used for vsc/vsp channel reset process */ - struct storvsc_cmd_request init_request; - struct storvsc_cmd_request reset_request; -}; - -struct stor_mem_pools { - struct kmem_cache *request_pool; - mempool_t *request_mempool; -}; - -struct hv_host_device { - struct hv_device *dev; - unsigned int port; - unsigned char path; - unsigned char target; -}; - -struct storvsc_scan_work { - struct work_struct work; - struct Scsi_Host *host; - uint lun; -}; - -static void storvsc_bus_scan(struct work_struct *work) -{ - struct storvsc_scan_work *wrk; - int id, order_id; - - wrk = container_of(work, struct storvsc_scan_work, work); - for (id = 0; id < wrk->host->max_id; ++id) { - if (wrk->host->reverse_ordering) - order_id = wrk->host->max_id - id - 1; - else - order_id = id; - - scsi_scan_target(&wrk->host->shost_gendev, 0, - order_id, SCAN_WILD_CARD, 1); - } - kfree(wrk); -} - -static void storvsc_remove_lun(struct work_struct *work) -{ - struct storvsc_scan_work *wrk; - struct scsi_device *sdev; - - wrk = container_of(work, struct storvsc_scan_work, work); - if (!scsi_host_get(wrk->host)) - goto done; - - sdev = scsi_device_lookup(wrk->host, 0, 0, wrk->lun); - - if (sdev) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } - scsi_host_put(wrk->host); - -done: - kfree(wrk); -} - -/* - * Major/minor macros. Minor version is in LSB, meaning that earlier flat - * version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). - */ - -static inline u16 storvsc_get_version(u8 major, u8 minor) -{ - u16 version; - - version = ((major << 8) | minor); - return version; -} - -/* - * We can get incoming messages from the host that are not in response to - * messages that we have sent out. An example of this would be messages - * received by the guest to notify dynamic addition/removal of LUNs. To - * deal with potential race conditions where the driver may be in the - * midst of being unloaded when we might receive an unsolicited message - * from the host, we have implemented a mechanism to gurantee sequential - * consistency: - * - * 1) Once the device is marked as being destroyed, we will fail all - * outgoing messages. - * 2) We permit incoming messages when the device is being destroyed, - * only to properly account for messages already sent out. - */ - -static inline struct storvsc_device *get_out_stor_device( - struct hv_device *device) -{ - struct storvsc_device *stor_device; - - stor_device = hv_get_drvdata(device); - - if (stor_device && stor_device->destroy) - stor_device = NULL; - - return stor_device; -} - - -static inline void storvsc_wait_to_drain(struct storvsc_device *dev) -{ - dev->drain_notify = true; - wait_event(dev->waiting_to_drain, - atomic_read(&dev->num_outstanding_req) == 0); - dev->drain_notify = false; -} - -static inline struct storvsc_device *get_in_stor_device( - struct hv_device *device) -{ - struct storvsc_device *stor_device; - - stor_device = hv_get_drvdata(device); - - if (!stor_device) - goto get_in_err; - - /* - * If the device is being destroyed; allow incoming - * traffic only to cleanup outstanding requests. - */ - - if (stor_device->destroy && - (atomic_read(&stor_device->num_outstanding_req) == 0)) - stor_device = NULL; - -get_in_err: - return stor_device; - -} - -static void destroy_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count) -{ - int i; - struct page *page_buf; - - for (i = 0; i < sg_count; i++) { - page_buf = sg_page((&sgl[i])); - if (page_buf != NULL) - __free_page(page_buf); - } - - kfree(sgl); -} - -static int do_bounce_buffer(struct scatterlist *sgl, unsigned int sg_count) -{ - int i; - - /* No need to check */ - if (sg_count < 2) - return -1; - - /* We have at least 2 sg entries */ - for (i = 0; i < sg_count; i++) { - if (i == 0) { - /* make sure 1st one does not have hole */ - if (sgl[i].offset + sgl[i].length != PAGE_SIZE) - return i; - } else if (i == sg_count - 1) { - /* make sure last one does not have hole */ - if (sgl[i].offset != 0) - return i; - } else { - /* make sure no hole in the middle */ - if (sgl[i].length != PAGE_SIZE || sgl[i].offset != 0) - return i; - } - } - return -1; -} - -static struct scatterlist *create_bounce_buffer(struct scatterlist *sgl, - unsigned int sg_count, - unsigned int len, - int write) -{ - int i; - int num_pages; - struct scatterlist *bounce_sgl; - struct page *page_buf; - unsigned int buf_len = ((write == WRITE_TYPE) ? 0 : PAGE_SIZE); - - num_pages = ALIGN(len, PAGE_SIZE) >> PAGE_SHIFT; - - bounce_sgl = kcalloc(num_pages, sizeof(struct scatterlist), GFP_ATOMIC); - if (!bounce_sgl) - return NULL; - - for (i = 0; i < num_pages; i++) { - page_buf = alloc_page(GFP_ATOMIC); - if (!page_buf) - goto cleanup; - sg_set_page(&bounce_sgl[i], page_buf, buf_len, 0); - } - - return bounce_sgl; - -cleanup: - destroy_bounce_buffer(bounce_sgl, num_pages); - return NULL; -} - -/* Disgusting wrapper functions */ -static inline unsigned long sg_kmap_atomic(struct scatterlist *sgl, int idx) -{ - void *addr = kmap_atomic(sg_page(sgl + idx)); - return (unsigned long)addr; -} - -static inline void sg_kunmap_atomic(unsigned long addr) -{ - kunmap_atomic((void *)addr); -} - - -/* Assume the original sgl has enough room */ -static unsigned int copy_from_bounce_buffer(struct scatterlist *orig_sgl, - struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count, - unsigned int bounce_sgl_count) -{ - int i; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long dest_addr = 0; - unsigned long flags; - - local_irq_save(flags); - - for (i = 0; i < orig_sgl_count; i++) { - dest_addr = sg_kmap_atomic(orig_sgl,i) + orig_sgl[i].offset; - dest = dest_addr; - destlen = orig_sgl[i].length; - - if (bounce_addr == 0) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); - - while (destlen) { - src = bounce_addr + bounce_sgl[j].offset; - srclen = bounce_sgl[j].length - bounce_sgl[j].offset; - - copylen = min(srclen, destlen); - memcpy((void *)dest, (void *)src, copylen); - - total_copied += copylen; - bounce_sgl[j].offset += copylen; - destlen -= copylen; - dest += copylen; - - if (bounce_sgl[j].offset == bounce_sgl[j].length) { - /* full */ - sg_kunmap_atomic(bounce_addr); - j++; - - /* - * It is possible that the number of elements - * in the bounce buffer may not be equal to - * the number of elements in the original - * scatter list. Handle this correctly. - */ - - if (j == bounce_sgl_count) { - /* - * We are done; cleanup and return. - */ - sg_kunmap_atomic(dest_addr - orig_sgl[i].offset); - local_irq_restore(flags); - return total_copied; - } - - /* if we need to use another bounce buffer */ - if (destlen || i != orig_sgl_count - 1) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); - } else if (destlen == 0 && i == orig_sgl_count - 1) { - /* unmap the last bounce that is < PAGE_SIZE */ - sg_kunmap_atomic(bounce_addr); - } - } - - sg_kunmap_atomic(dest_addr - orig_sgl[i].offset); - } - - local_irq_restore(flags); - - return total_copied; -} - -/* Assume the bounce_sgl has enough room ie using the create_bounce_buffer() */ -static unsigned int copy_to_bounce_buffer(struct scatterlist *orig_sgl, - struct scatterlist *bounce_sgl, - unsigned int orig_sgl_count) -{ - int i; - int j = 0; - unsigned long src, dest; - unsigned int srclen, destlen, copylen; - unsigned int total_copied = 0; - unsigned long bounce_addr = 0; - unsigned long src_addr = 0; - unsigned long flags; - - local_irq_save(flags); - - for (i = 0; i < orig_sgl_count; i++) { - src_addr = sg_kmap_atomic(orig_sgl,i) + orig_sgl[i].offset; - src = src_addr; - srclen = orig_sgl[i].length; - - if (bounce_addr == 0) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); - - while (srclen) { - /* assume bounce offset always == 0 */ - dest = bounce_addr + bounce_sgl[j].length; - destlen = PAGE_SIZE - bounce_sgl[j].length; - - copylen = min(srclen, destlen); - memcpy((void *)dest, (void *)src, copylen); - - total_copied += copylen; - bounce_sgl[j].length += copylen; - srclen -= copylen; - src += copylen; - - if (bounce_sgl[j].length == PAGE_SIZE) { - /* full..move to next entry */ - sg_kunmap_atomic(bounce_addr); - j++; - - /* if we need to use another bounce buffer */ - if (srclen || i != orig_sgl_count - 1) - bounce_addr = sg_kmap_atomic(bounce_sgl,j); - - } else if (srclen == 0 && i == orig_sgl_count - 1) { - /* unmap the last bounce that is < PAGE_SIZE */ - sg_kunmap_atomic(bounce_addr); - } - } - - sg_kunmap_atomic(src_addr - orig_sgl[i].offset); - } - - local_irq_restore(flags); - - return total_copied; -} - -static int storvsc_channel_init(struct hv_device *device) -{ - struct storvsc_device *stor_device; - struct storvsc_cmd_request *request; - struct vstor_packet *vstor_packet; - int ret, t; - - stor_device = get_out_stor_device(device); - if (!stor_device) - return -ENODEV; - - request = &stor_device->init_request; - vstor_packet = &request->vstor_packet; - - /* - * Now, initiate the vsc/vsp initialization protocol on the open - * channel - */ - memset(request, 0, sizeof(struct storvsc_cmd_request)); - init_completion(&request->wait_event); - vstor_packet->operation = VSTOR_OPERATION_BEGIN_INITIALIZATION; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) - goto cleanup; - - - /* reuse the packet for version range supported */ - memset(vstor_packet, 0, sizeof(struct vstor_packet)); - vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - - vstor_packet->version.major_minor = - storvsc_get_version(VMSTOR_CURRENT_MAJOR, VMSTOR_CURRENT_MINOR); - - /* - * The revision number is only used in Windows; set it to 0. - */ - vstor_packet->version.revision = 0; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) - goto cleanup; - - - memset(vstor_packet, 0, sizeof(struct vstor_packet)); - vstor_packet->operation = VSTOR_OPERATION_QUERY_PROPERTIES; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - vstor_packet->storage_channel_properties.port_number = - stor_device->port_number; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) - goto cleanup; - - stor_device->path_id = vstor_packet->storage_channel_properties.path_id; - stor_device->target_id - = vstor_packet->storage_channel_properties.target_id; - - memset(vstor_packet, 0, sizeof(struct vstor_packet)); - vstor_packet->operation = VSTOR_OPERATION_END_INITIALIZATION; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - - if (ret != 0) - goto cleanup; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; - } - - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) - goto cleanup; - - -cleanup: - return ret; -} - - -static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request) -{ - struct scsi_cmnd *scmnd = cmd_request->cmd; - struct hv_host_device *host_dev = shost_priv(scmnd->device->host); - void (*scsi_done_fn)(struct scsi_cmnd *); - struct scsi_sense_hdr sense_hdr; - struct vmscsi_request *vm_srb; - struct storvsc_scan_work *wrk; - struct stor_mem_pools *memp = scmnd->device->hostdata; - - vm_srb = &cmd_request->vstor_packet.vm_srb; - if (cmd_request->bounce_sgl_count) { - if (vm_srb->data_in == READ_TYPE) - copy_from_bounce_buffer(scsi_sglist(scmnd), - cmd_request->bounce_sgl, - scsi_sg_count(scmnd), - cmd_request->bounce_sgl_count); - destroy_bounce_buffer(cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - } - - /* - * If there is an error; offline the device since all - * error recovery strategies would have already been - * deployed on the host side. - */ - if (vm_srb->srb_status == SRB_STATUS_ERROR) - scmnd->result = DID_TARGET_FAILURE << 16; - else - scmnd->result = vm_srb->scsi_status; - - /* - * If the LUN is invalid; remove the device. - */ - if (vm_srb->srb_status == SRB_STATUS_INVALID_LUN) { - struct storvsc_device *stor_dev; - struct hv_device *dev = host_dev->dev; - struct Scsi_Host *host; - - stor_dev = get_in_stor_device(dev); - host = stor_dev->host; - - wrk = kmalloc(sizeof(struct storvsc_scan_work), - GFP_ATOMIC); - if (!wrk) { - scmnd->result = DID_TARGET_FAILURE << 16; - } else { - wrk->host = host; - wrk->lun = vm_srb->lun; - INIT_WORK(&wrk->work, storvsc_remove_lun); - schedule_work(&wrk->work); - } - } - - if (scmnd->result) { - if (scsi_normalize_sense(scmnd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, &sense_hdr)) - scsi_print_sense_hdr("storvsc", &sense_hdr); - } - - scsi_set_resid(scmnd, - cmd_request->data_buffer.len - - vm_srb->data_transfer_length); - - scsi_done_fn = scmnd->scsi_done; - - scmnd->host_scribble = NULL; - scmnd->scsi_done = NULL; - - scsi_done_fn(scmnd); - - mempool_free(cmd_request, memp->request_mempool); -} - -static void storvsc_on_io_completion(struct hv_device *device, - struct vstor_packet *vstor_packet, - struct storvsc_cmd_request *request) -{ - struct storvsc_device *stor_device; - struct vstor_packet *stor_pkt; - - stor_device = hv_get_drvdata(device); - stor_pkt = &request->vstor_packet; - - /* - * The current SCSI handling on the host side does - * not correctly handle: - * INQUIRY command with page code parameter set to 0x80 - * MODE_SENSE command with cmd[2] == 0x1c - * - * Setup srb and scsi status so this won't be fatal. - * We do this so we can distinguish truly fatal failues - * (srb status == 0x4) and off-line the device in that case. - */ - - if ((stor_pkt->vm_srb.cdb[0] == INQUIRY) || - (stor_pkt->vm_srb.cdb[0] == MODE_SENSE)) { - vstor_packet->vm_srb.scsi_status = 0; - vstor_packet->vm_srb.srb_status = SRB_STATUS_SUCCESS; - } - - - /* Copy over the status...etc */ - stor_pkt->vm_srb.scsi_status = vstor_packet->vm_srb.scsi_status; - stor_pkt->vm_srb.srb_status = vstor_packet->vm_srb.srb_status; - stor_pkt->vm_srb.sense_info_length = - vstor_packet->vm_srb.sense_info_length; - - if (vstor_packet->vm_srb.scsi_status != 0 || - vstor_packet->vm_srb.srb_status != SRB_STATUS_SUCCESS){ - dev_warn(&device->device, - "cmd 0x%x scsi status 0x%x srb status 0x%x\n", - stor_pkt->vm_srb.cdb[0], - vstor_packet->vm_srb.scsi_status, - vstor_packet->vm_srb.srb_status); - } - - if ((vstor_packet->vm_srb.scsi_status & 0xFF) == 0x02) { - /* CHECK_CONDITION */ - if (vstor_packet->vm_srb.srb_status & - SRB_STATUS_AUTOSENSE_VALID) { - /* autosense data available */ - dev_warn(&device->device, - "stor pkt %p autosense data valid - len %d\n", - request, - vstor_packet->vm_srb.sense_info_length); - - memcpy(request->sense_buffer, - vstor_packet->vm_srb.sense_data, - vstor_packet->vm_srb.sense_info_length); - - } - } - - stor_pkt->vm_srb.data_transfer_length = - vstor_packet->vm_srb.data_transfer_length; - - storvsc_command_completion(request); - - if (atomic_dec_and_test(&stor_device->num_outstanding_req) && - stor_device->drain_notify) - wake_up(&stor_device->waiting_to_drain); - - -} - -static void storvsc_on_receive(struct hv_device *device, - struct vstor_packet *vstor_packet, - struct storvsc_cmd_request *request) -{ - struct storvsc_scan_work *work; - struct storvsc_device *stor_device; - - switch (vstor_packet->operation) { - case VSTOR_OPERATION_COMPLETE_IO: - storvsc_on_io_completion(device, vstor_packet, request); - break; - - case VSTOR_OPERATION_REMOVE_DEVICE: - case VSTOR_OPERATION_ENUMERATE_BUS: - stor_device = get_in_stor_device(device); - work = kmalloc(sizeof(struct storvsc_scan_work), GFP_ATOMIC); - if (!work) - return; - - INIT_WORK(&work->work, storvsc_bus_scan); - work->host = stor_device->host; - schedule_work(&work->work); - break; - - default: - break; - } -} - -static void storvsc_on_channel_callback(void *context) -{ - struct hv_device *device = (struct hv_device *)context; - struct storvsc_device *stor_device; - u32 bytes_recvd; - u64 request_id; - unsigned char packet[ALIGN(sizeof(struct vstor_packet), 8)]; - struct storvsc_cmd_request *request; - int ret; - - - stor_device = get_in_stor_device(device); - if (!stor_device) - return; - - do { - ret = vmbus_recvpacket(device->channel, packet, - ALIGN(sizeof(struct vstor_packet), 8), - &bytes_recvd, &request_id); - if (ret == 0 && bytes_recvd > 0) { - - request = (struct storvsc_cmd_request *) - (unsigned long)request_id; - - if ((request == &stor_device->init_request) || - (request == &stor_device->reset_request)) { - - memcpy(&request->vstor_packet, packet, - sizeof(struct vstor_packet)); - complete(&request->wait_event); - } else { - storvsc_on_receive(device, - (struct vstor_packet *)packet, - request); - } - } else { - break; - } - } while (1); - - return; -} - -static int storvsc_connect_to_vsp(struct hv_device *device, u32 ring_size) -{ - struct vmstorage_channel_properties props; - int ret; - - memset(&props, 0, sizeof(struct vmstorage_channel_properties)); - - ret = vmbus_open(device->channel, - ring_size, - ring_size, - (void *)&props, - sizeof(struct vmstorage_channel_properties), - storvsc_on_channel_callback, device); - - if (ret != 0) - return ret; - - ret = storvsc_channel_init(device); - - return ret; -} - -static int storvsc_dev_remove(struct hv_device *device) -{ - struct storvsc_device *stor_device; - unsigned long flags; - - stor_device = hv_get_drvdata(device); - - spin_lock_irqsave(&device->channel->inbound_lock, flags); - stor_device->destroy = true; - spin_unlock_irqrestore(&device->channel->inbound_lock, flags); - - /* - * At this point, all outbound traffic should be disable. We - * only allow inbound traffic (responses) to proceed so that - * outstanding requests can be completed. - */ - - storvsc_wait_to_drain(stor_device); - - /* - * Since we have already drained, we don't need to busy wait - * as was done in final_release_stor_device() - * Note that we cannot set the ext pointer to NULL until - * we have drained - to drain the outgoing packets, we need to - * allow incoming packets. - */ - spin_lock_irqsave(&device->channel->inbound_lock, flags); - hv_set_drvdata(device, NULL); - spin_unlock_irqrestore(&device->channel->inbound_lock, flags); - - /* Close the channel */ - vmbus_close(device->channel); - - kfree(stor_device); - return 0; -} - -static int storvsc_do_io(struct hv_device *device, - struct storvsc_cmd_request *request) -{ - struct storvsc_device *stor_device; - struct vstor_packet *vstor_packet; - int ret = 0; - - vstor_packet = &request->vstor_packet; - stor_device = get_out_stor_device(device); - - if (!stor_device) - return -ENODEV; - - - request->device = device; - - - vstor_packet->flags |= REQUEST_COMPLETION_FLAG; - - vstor_packet->vm_srb.length = sizeof(struct vmscsi_request); - - - vstor_packet->vm_srb.sense_info_length = STORVSC_SENSE_BUFFER_SIZE; - - - vstor_packet->vm_srb.data_transfer_length = - request->data_buffer.len; - - vstor_packet->operation = VSTOR_OPERATION_EXECUTE_SRB; - - if (request->data_buffer.len) { - ret = vmbus_sendpacket_multipagebuffer(device->channel, - &request->data_buffer, - vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request); - } else { - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - } - - if (ret != 0) - return ret; - - atomic_inc(&stor_device->num_outstanding_req); - - return ret; -} - -static int storvsc_device_alloc(struct scsi_device *sdevice) -{ - struct stor_mem_pools *memp; - int number = STORVSC_MIN_BUF_NR; - - memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL); - if (!memp) - return -ENOMEM; - - memp->request_pool = - kmem_cache_create(dev_name(&sdevice->sdev_dev), - sizeof(struct storvsc_cmd_request), 0, - SLAB_HWCACHE_ALIGN, NULL); - - if (!memp->request_pool) - goto err0; - - memp->request_mempool = mempool_create(number, mempool_alloc_slab, - mempool_free_slab, - memp->request_pool); - - if (!memp->request_mempool) - goto err1; - - sdevice->hostdata = memp; - - return 0; - -err1: - kmem_cache_destroy(memp->request_pool); - -err0: - kfree(memp); - return -ENOMEM; -} - -static void storvsc_device_destroy(struct scsi_device *sdevice) -{ - struct stor_mem_pools *memp = sdevice->hostdata; - - mempool_destroy(memp->request_mempool); - kmem_cache_destroy(memp->request_pool); - kfree(memp); - sdevice->hostdata = NULL; -} - -static int storvsc_device_configure(struct scsi_device *sdevice) -{ - scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG, - STORVSC_MAX_IO_REQUESTS); - - blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE); - - blk_queue_bounce_limit(sdevice->request_queue, BLK_BOUNCE_ANY); - - return 0; -} - -static int storvsc_get_chs(struct scsi_device *sdev, struct block_device * bdev, - sector_t capacity, int *info) -{ - sector_t nsect = capacity; - sector_t cylinders = nsect; - int heads, sectors_pt; - - /* - * We are making up these values; let us keep it simple. - */ - heads = 0xff; - sectors_pt = 0x3f; /* Sectors per track */ - sector_div(cylinders, heads * sectors_pt); - if ((sector_t)(cylinders + 1) * heads * sectors_pt < nsect) - cylinders = 0xffff; - - info[0] = heads; - info[1] = sectors_pt; - info[2] = (int)cylinders; - - return 0; -} - -static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd) -{ - struct hv_host_device *host_dev = shost_priv(scmnd->device->host); - struct hv_device *device = host_dev->dev; - - struct storvsc_device *stor_device; - struct storvsc_cmd_request *request; - struct vstor_packet *vstor_packet; - int ret, t; - - - stor_device = get_out_stor_device(device); - if (!stor_device) - return FAILED; - - request = &stor_device->reset_request; - vstor_packet = &request->vstor_packet; - - init_completion(&request->wait_event); - - vstor_packet->operation = VSTOR_OPERATION_RESET_BUS; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; - vstor_packet->vm_srb.path_id = stor_device->path_id; - - ret = vmbus_sendpacket(device->channel, vstor_packet, - sizeof(struct vstor_packet), - (unsigned long)&stor_device->reset_request, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - return FAILED; - - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) - return TIMEOUT_ERROR; - - - /* - * At this point, all outstanding requests in the adapter - * should have been flushed out and return to us - */ - - return SUCCESS; -} - -static bool storvsc_scsi_cmd_ok(struct scsi_cmnd *scmnd) -{ - bool allowed = true; - u8 scsi_op = scmnd->cmnd[0]; - - switch (scsi_op) { - /* - * smartd sends this command and the host does not handle - * this. So, don't send it. - */ - case SET_WINDOW: - scmnd->result = ILLEGAL_REQUEST << 16; - allowed = false; - break; - default: - break; - } - return allowed; -} - -static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) -{ - int ret; - struct hv_host_device *host_dev = shost_priv(host); - struct hv_device *dev = host_dev->dev; - struct storvsc_cmd_request *cmd_request; - unsigned int request_size = 0; - int i; - struct scatterlist *sgl; - unsigned int sg_count = 0; - struct vmscsi_request *vm_srb; - struct stor_mem_pools *memp = scmnd->device->hostdata; - - if (!storvsc_scsi_cmd_ok(scmnd)) { - scmnd->scsi_done(scmnd); - return 0; - } - - request_size = sizeof(struct storvsc_cmd_request); - - cmd_request = mempool_alloc(memp->request_mempool, - GFP_ATOMIC); - - /* - * We might be invoked in an interrupt context; hence - * mempool_alloc() can fail. - */ - if (!cmd_request) - return SCSI_MLQUEUE_DEVICE_BUSY; - - memset(cmd_request, 0, sizeof(struct storvsc_cmd_request)); - - /* Setup the cmd request */ - cmd_request->cmd = scmnd; - - scmnd->host_scribble = (unsigned char *)cmd_request; - - vm_srb = &cmd_request->vstor_packet.vm_srb; - - - /* Build the SRB */ - switch (scmnd->sc_data_direction) { - case DMA_TO_DEVICE: - vm_srb->data_in = WRITE_TYPE; - break; - case DMA_FROM_DEVICE: - vm_srb->data_in = READ_TYPE; - break; - default: - vm_srb->data_in = UNKNOWN_TYPE; - break; - } - - - vm_srb->port_number = host_dev->port; - vm_srb->path_id = scmnd->device->channel; - vm_srb->target_id = scmnd->device->id; - vm_srb->lun = scmnd->device->lun; - - vm_srb->cdb_length = scmnd->cmd_len; - - memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length); - - cmd_request->sense_buffer = scmnd->sense_buffer; - - - cmd_request->data_buffer.len = scsi_bufflen(scmnd); - if (scsi_sg_count(scmnd)) { - sgl = (struct scatterlist *)scsi_sglist(scmnd); - sg_count = scsi_sg_count(scmnd); - - /* check if we need to bounce the sgl */ - if (do_bounce_buffer(sgl, scsi_sg_count(scmnd)) != -1) { - cmd_request->bounce_sgl = - create_bounce_buffer(sgl, scsi_sg_count(scmnd), - scsi_bufflen(scmnd), - vm_srb->data_in); - if (!cmd_request->bounce_sgl) { - ret = SCSI_MLQUEUE_HOST_BUSY; - goto queue_error; - } - - cmd_request->bounce_sgl_count = - ALIGN(scsi_bufflen(scmnd), PAGE_SIZE) >> - PAGE_SHIFT; - - if (vm_srb->data_in == WRITE_TYPE) - copy_to_bounce_buffer(sgl, - cmd_request->bounce_sgl, - scsi_sg_count(scmnd)); - - sgl = cmd_request->bounce_sgl; - sg_count = cmd_request->bounce_sgl_count; - } - - cmd_request->data_buffer.offset = sgl[0].offset; - - for (i = 0; i < sg_count; i++) - cmd_request->data_buffer.pfn_array[i] = - page_to_pfn(sg_page((&sgl[i]))); - - } else if (scsi_sglist(scmnd)) { - cmd_request->data_buffer.offset = - virt_to_phys(scsi_sglist(scmnd)) & (PAGE_SIZE-1); - cmd_request->data_buffer.pfn_array[0] = - virt_to_phys(scsi_sglist(scmnd)) >> PAGE_SHIFT; - } - - /* Invokes the vsc to start an IO */ - ret = storvsc_do_io(dev, cmd_request); - - if (ret == -EAGAIN) { - /* no more space */ - - if (cmd_request->bounce_sgl_count) { - destroy_bounce_buffer(cmd_request->bounce_sgl, - cmd_request->bounce_sgl_count); - - ret = SCSI_MLQUEUE_DEVICE_BUSY; - goto queue_error; - } - } - - return 0; - -queue_error: - mempool_free(cmd_request, memp->request_mempool); - scmnd->host_scribble = NULL; - return ret; -} - -static struct scsi_host_template scsi_driver = { - .module = THIS_MODULE, - .name = "storvsc_host_t", - .bios_param = storvsc_get_chs, - .queuecommand = storvsc_queuecommand, - .eh_host_reset_handler = storvsc_host_reset_handler, - .slave_alloc = storvsc_device_alloc, - .slave_destroy = storvsc_device_destroy, - .slave_configure = storvsc_device_configure, - .cmd_per_lun = 1, - /* 64 max_queue * 1 target */ - .can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS, - .this_id = -1, - /* no use setting to 0 since ll_blk_rw reset it to 1 */ - /* currently 32 */ - .sg_tablesize = MAX_MULTIPAGE_BUFFER_COUNT, - .use_clustering = DISABLE_CLUSTERING, - /* Make sure we dont get a sg segment crosses a page boundary */ - .dma_boundary = PAGE_SIZE-1, -}; - -enum { - SCSI_GUID, - IDE_GUID, -}; - -static const struct hv_vmbus_device_id id_table[] = { - /* SCSI guid */ - { VMBUS_DEVICE(0xd9, 0x63, 0x61, 0xba, 0xa1, 0x04, 0x29, 0x4d, - 0xb6, 0x05, 0x72, 0xe2, 0xff, 0xb1, 0xdc, 0x7f) - .driver_data = SCSI_GUID }, - /* IDE guid */ - { VMBUS_DEVICE(0x32, 0x26, 0x41, 0x32, 0xcb, 0x86, 0xa2, 0x44, - 0x9b, 0x5c, 0x50, 0xd1, 0x41, 0x73, 0x54, 0xf5) - .driver_data = IDE_GUID }, - { }, -}; - -MODULE_DEVICE_TABLE(vmbus, id_table); - -static int storvsc_probe(struct hv_device *device, - const struct hv_vmbus_device_id *dev_id) -{ - int ret; - struct Scsi_Host *host; - struct hv_host_device *host_dev; - bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false); - int target = 0; - struct storvsc_device *stor_device; - - host = scsi_host_alloc(&scsi_driver, - sizeof(struct hv_host_device)); - if (!host) - return -ENOMEM; - - host_dev = shost_priv(host); - memset(host_dev, 0, sizeof(struct hv_host_device)); - - host_dev->port = host->host_no; - host_dev->dev = device; - - - stor_device = kzalloc(sizeof(struct storvsc_device), GFP_KERNEL); - if (!stor_device) { - ret = -ENOMEM; - goto err_out0; - } - - stor_device->destroy = false; - init_waitqueue_head(&stor_device->waiting_to_drain); - stor_device->device = device; - stor_device->host = host; - hv_set_drvdata(device, stor_device); - - stor_device->port_number = host->host_no; - ret = storvsc_connect_to_vsp(device, storvsc_ringbuffer_size); - if (ret) - goto err_out1; - - host_dev->path = stor_device->path_id; - host_dev->target = stor_device->target_id; - - /* max # of devices per target */ - host->max_lun = STORVSC_MAX_LUNS_PER_TARGET; - /* max # of targets per channel */ - host->max_id = STORVSC_MAX_TARGETS; - /* max # of channels */ - host->max_channel = STORVSC_MAX_CHANNELS - 1; - /* max cmd length */ - host->max_cmd_len = STORVSC_MAX_CMD_LEN; - - /* Register the HBA and start the scsi bus scan */ - ret = scsi_add_host(host, &device->device); - if (ret != 0) - goto err_out2; - - if (!dev_is_ide) { - scsi_scan_host(host); - } else { - target = (device->dev_instance.b[5] << 8 | - device->dev_instance.b[4]); - ret = scsi_add_device(host, 0, target, 0); - if (ret) { - scsi_remove_host(host); - goto err_out2; - } - } - return 0; - -err_out2: - /* - * Once we have connected with the host, we would need to - * to invoke storvsc_dev_remove() to rollback this state and - * this call also frees up the stor_device; hence the jump around - * err_out1 label. - */ - storvsc_dev_remove(device); - goto err_out0; - -err_out1: - kfree(stor_device); - -err_out0: - scsi_host_put(host); - return ret; -} - -static int storvsc_remove(struct hv_device *dev) -{ - struct storvsc_device *stor_device = hv_get_drvdata(dev); - struct Scsi_Host *host = stor_device->host; - - scsi_remove_host(host); - storvsc_dev_remove(dev); - scsi_host_put(host); - - return 0; -} - -static struct hv_driver storvsc_drv = { - .name = KBUILD_MODNAME, - .id_table = id_table, - .probe = storvsc_probe, - .remove = storvsc_remove, -}; - -static int __init storvsc_drv_init(void) -{ - u32 max_outstanding_req_per_channel; - - /* - * Divide the ring buffer data size (which is 1 page less - * than the ring buffer size since that page is reserved for - * the ring buffer indices) by the max request size (which is - * vmbus_channel_packet_multipage_buffer + struct vstor_packet + u64) - */ - max_outstanding_req_per_channel = - ((storvsc_ringbuffer_size - PAGE_SIZE) / - ALIGN(MAX_MULTIPAGE_BUFFER_PACKET + - sizeof(struct vstor_packet) + sizeof(u64), - sizeof(u64))); - - if (max_outstanding_req_per_channel < - STORVSC_MAX_IO_REQUESTS) - return -EINVAL; - - return vmbus_driver_register(&storvsc_drv); -} - -static void __exit storvsc_drv_exit(void) -{ - vmbus_driver_unregister(&storvsc_drv); -} - -MODULE_LICENSE("GPL"); -MODULE_VERSION(HV_DRV_VERSION); -MODULE_DESCRIPTION("Microsoft Hyper-V virtual storage driver"); -module_init(storvsc_drv_init); -module_exit(storvsc_drv_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/sun3_NCR5380.c b/ANDROID_3.4.5/drivers/scsi/sun3_NCR5380.c deleted file mode 100644 index 7e12a2e4..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sun3_NCR5380.c +++ /dev/null @@ -1,2960 +0,0 @@ -/* sun3_NCR5380.c -- adapted from atari_NCR5380.c for the sun3 by - Sam Creasey. */ -/* - * NCR 5380 generic driver routines. These should make it *trivial* - * to implement 5380 SCSI drivers under Linux with a non-trantor - * architecture. - * - * Note that these routines also work with NR53c400 family chips. - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 666-5836 - * - * DISTRIBUTION RELEASE 6. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * ++roman: To port the 5380 driver to the Atari, I had to do some changes in - * this file, too: - * - * - Some of the debug statements were incorrect (undefined variables and the - * like). I fixed that. - * - * - In information_transfer(), I think a #ifdef was wrong. Looking at the - * possible DMA transfer size should also happen for REAL_DMA. I added this - * in the #if statement. - * - * - When using real DMA, information_transfer() should return in a DATAOUT - * phase after starting the DMA. It has nothing more to do. - * - * - The interrupt service routine should run main after end of DMA, too (not - * only after RESELECTION interrupts). Additionally, it should _not_ test - * for more interrupts after running main, since a DMA process may have - * been started and interrupts are turned on now. The new int could happen - * inside the execution of NCR5380_intr(), leading to recursive - * calls. - * - * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA - * and USLEEP, because these were messing up readability and will never be - * needed for Atari SCSI. - * - * - I've revised the NCR5380_main() calling scheme (relax the 'main_running' - * stuff), and 'main' is executed in a bottom half if awoken by an - * interrupt. - * - * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..." - * constructs. In my eyes, this made the source rather unreadable, so I - * finally replaced that by the *_PRINTK() macros. - * - */ -#include -#include - -/* - * Further development / testing that should be done : - * 1. Test linked command handling code after Eric is ready with - * the high level code. - */ - -#if (NDEBUG & NDEBUG_LISTS) -#define LIST(x,y) \ - { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \ - if ((x)==(y)) udelay(5); } -#define REMOVE(w,x,y,z) \ - { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \ - (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \ - if ((x)==(y)) udelay(5); } -#else -#define LIST(x,y) -#define REMOVE(w,x,y,z) -#endif - -#ifndef notyet -#undef LINKED -#endif - -/* - * Design - * Issues : - * - * The other Linux SCSI drivers were written when Linux was Intel PC-only, - * and specifically for each board rather than each chip. This makes their - * adaptation to platforms like the Mac (Some of which use NCR5380's) - * more difficult than it has to be. - * - * Also, many of the SCSI drivers were written before the command queuing - * routines were implemented, meaning their implementations of queued - * commands were hacked on rather than designed in from the start. - * - * When I designed the Linux SCSI drivers I figured that - * while having two different SCSI boards in a system might be useful - * for debugging things, two of the same type wouldn't be used. - * Well, I was wrong and a number of users have mailed me about running - * multiple high-performance SCSI boards in a server. - * - * Finally, when I get questions from users, I have no idea what - * revision of my driver they are running. - * - * This driver attempts to address these problems : - * This is a generic 5380 driver. To use it on a different platform, - * one simply writes appropriate system specific macros (ie, data - * transfer - some PC's will use the I/O bus, 68K's must use - * memory mapped) and drops this file in their 'C' wrapper. - * - * As far as command queueing, two queues are maintained for - * each 5380 in the system - commands that haven't been issued yet, - * and commands that are currently executing. This means that an - * unlimited number of commands may be queued, letting - * more commands propagate from the higher driver levels giving higher - * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported, - * allowing multiple commands to propagate all the way to a SCSI-II device - * while a command is already executing. - * - * To solve the multiple-boards-in-the-same-system problem, - * there is a separate instance structure for each instance - * of a 5380 in the system. So, multiple NCR5380 drivers will - * be able to coexist with appropriate changes to the high level - * SCSI code. - * - * A NCR5380_PUBLIC_REVISION macro is provided, with the release - * number (updated for each public release) printed by the - * NCR5380_print_options command, which should be called from the - * wrapper detect function, so that I know what release of the driver - * users are using. - * - * Issues specific to the NCR5380 : - * - * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead - * piece of hardware that requires you to sit in a loop polling for - * the REQ signal as long as you are connected. Some devices are - * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect - * while doing long seek operations. - * - * The workaround for this is to keep track of devices that have - * disconnected. If the device hasn't disconnected, for commands that - * should disconnect, we do something like - * - * while (!REQ is asserted) { sleep for N usecs; poll for M usecs } - * - * Some tweaking of N and M needs to be done. An algorithm based - * on "time to data" would give the best results as long as short time - * to datas (ie, on the same track) were considered, however these - * broken devices are the exception rather than the rule and I'd rather - * spend my time optimizing for the normal case. - * - * Architecture : - * - * At the heart of the design is a coroutine, NCR5380_main, - * which is started when not running by the interrupt handler, - * timer, and queue command function. It attempts to establish - * I_T_L or I_T_L_Q nexuses by removing the commands from the - * issue queue and calling NCR5380_select() if a nexus - * is not established. - * - * Once a nexus is established, the NCR5380_information_transfer() - * phase goes through the various phases as instructed by the target. - * if the target goes into MSG IN and sends a DISCONNECT message, - * the command structure is placed into the per instance disconnected - * queue, and NCR5380_main tries to find more work. If USLEEP - * was defined, and the target is idle for too long, the system - * will try to sleep. - * - * If a command has disconnected, eventually an interrupt will trigger, - * calling NCR5380_intr() which will in turn call NCR5380_reselect - * to reestablish a nexus. This will run main if necessary. - * - * On command termination, the done function will be called as - * appropriate. - * - * SCSI pointers are maintained in the SCp field of SCSI command - * structures, being initialized after the command is connected - * in NCR5380_select, and set as appropriate in NCR5380_information_transfer. - * Note that in violation of the standard, an implicit SAVE POINTERS operation - * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS. - */ - -/* - * Using this file : - * This file a skeleton Linux SCSI driver for the NCR 5380 series - * of chips. To use it, you write an architecture specific functions - * and macros and include this file in your driver. - * - * These macros control options : - * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. - * - * LINKED - if defined, linked commands are supported. - * - * REAL_DMA - if defined, REAL DMA is used during the data transfer phases. - * - * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible - * - * These macros MUST be defined : - * - * NCR5380_read(register) - read from the specified register - * - * NCR5380_write(register, value) - write to the specific register - * - * Either real DMA *or* pseudo DMA may be implemented - * REAL functions : - * NCR5380_REAL_DMA should be defined if real DMA is to be used. - * Note that the DMA setup functions should return the number of bytes - * that they were able to program the controller for. - * - * Also note that generic i386/PC versions of these macros are - * available as NCR5380_i386_dma_write_setup, - * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. - * - * NCR5380_dma_write_setup(instance, src, count) - initialize - * NCR5380_dma_read_setup(instance, dst, count) - initialize - * NCR5380_dma_residual(instance); - residual count - * - * PSEUDO functions : - * NCR5380_pwrite(instance, src, count) - * NCR5380_pread(instance, dst, count); - * - * If nothing specific to this implementation needs doing (ie, with external - * hardware), you must also define - * - * NCR5380_queue_command - * NCR5380_reset - * NCR5380_abort - * NCR5380_proc_info - * - * to be the global entry points into the specific driver, ie - * #define NCR5380_queue_command t128_queue_command. - * - * If this is not done, the routines will be defined as static functions - * with the NCR5380* names and the user must provide a globally - * accessible wrapper function. - * - * The generic driver is initialized by calling NCR5380_init(instance), - * after setting the appropriate host specific fields and ID. If the - * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, - * possible) function may be used. Before the specific driver initialization - * code finishes, NCR5380_print_options should be called. - */ - -static struct Scsi_Host *first_instance = NULL; -static struct scsi_host_template *the_template = NULL; - -/* Macros ease life... :-) */ -#define SETUP_HOSTDATA(in) \ - struct NCR5380_hostdata *hostdata = \ - (struct NCR5380_hostdata *)(in)->hostdata -#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata) - -#define NEXT(cmd) ((struct scsi_cmnd *)(cmd)->host_scribble) -#define SET_NEXT(cmd, next) ((cmd)->host_scribble = (void *)(next)) -#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble)) - -#define HOSTNO instance->host_no -#define H_NO(cmd) (cmd)->device->host->host_no - -#define SGADDR(buffer) (void *)(((unsigned long)sg_virt(((buffer))))) - -#ifdef SUPPORT_TAGS - -/* - * Functions for handling tagged queuing - * ===================================== - * - * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes: - * - * Using consecutive numbers for the tags is no good idea in my eyes. There - * could be wrong re-usings if the counter (8 bit!) wraps and some early - * command has been preempted for a long time. My solution: a bitfield for - * remembering used tags. - * - * There's also the problem that each target has a certain queue size, but we - * cannot know it in advance :-( We just see a QUEUE_FULL status being - * returned. So, in this case, the driver internal queue size assumption is - * reduced to the number of active tags if QUEUE_FULL is returned by the - * target. The command is returned to the mid-level, but with status changed - * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL - * correctly. - * - * We're also not allowed running tagged commands as long as an untagged - * command is active. And REQUEST SENSE commands after a contingent allegiance - * condition _must_ be untagged. To keep track whether an untagged command has - * been issued, the host->busy array is still employed, as it is without - * support for tagged queuing. - * - * One could suspect that there are possible race conditions between - * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the - * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(), - * which already guaranteed to be running at most once. It is also the only - * place where tags/LUNs are allocated. So no other allocation can slip - * between that pair, there could only happen a reselection, which can free a - * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes - * important: the tag bit must be cleared before 'nr_allocated' is decreased. - */ - -/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */ -#undef TAG_NONE -#define TAG_NONE 0xff - -/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */ -#if (MAX_TAGS % 32) != 0 -#error "MAX_TAGS must be a multiple of 32!" -#endif - -typedef struct { - char allocated[MAX_TAGS/8]; - int nr_allocated; - int queue_size; -} TAG_ALLOC; - -static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */ - - -static void __init init_tags( void ) -{ - int target, lun; - TAG_ALLOC *ta; - - if (!setup_use_tagged_queuing) - return; - - for( target = 0; target < 8; ++target ) { - for( lun = 0; lun < 8; ++lun ) { - ta = &TagAlloc[target][lun]; - memset( &ta->allocated, 0, MAX_TAGS/8 ); - ta->nr_allocated = 0; - /* At the beginning, assume the maximum queue size we could - * support (MAX_TAGS). This value will be decreased if the target - * returns QUEUE_FULL status. - */ - ta->queue_size = MAX_TAGS; - } - } -} - - -/* Check if we can issue a command to this LUN: First see if the LUN is marked - * busy by an untagged command. If the command should use tagged queuing, also - * check that there is a free tag and the target's queue won't overflow. This - * function should be called with interrupts disabled to avoid race - * conditions. - */ - -static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged) -{ - SETUP_HOSTDATA(cmd->device->host); - - if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)) - return( 1 ); - if (!should_be_tagged || - !setup_use_tagged_queuing || !cmd->device->tagged_supported) - return( 0 ); - if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >= - TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) { - TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n", - H_NO(cmd), cmd->device->id, cmd->device->lun ); - return( 1 ); - } - return( 0 ); -} - - -/* Allocate a tag for a command (there are no checks anymore, check_lun_busy() - * must be called before!), or reserve the LUN in 'busy' if the command is - * untagged. - */ - -static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged) -{ - SETUP_HOSTDATA(cmd->device->host); - - /* If we or the target don't support tagged queuing, allocate the LUN for - * an untagged command. - */ - if (!should_be_tagged || - !setup_use_tagged_queuing || !cmd->device->tagged_supported) { - cmd->tag = TAG_NONE; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged " - "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun ); - } - else { - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - - cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS ); - set_bit( cmd->tag, &ta->allocated ); - ta->nr_allocated++; - TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d " - "(now %d tags in use)\n", - H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun, - ta->nr_allocated ); - } -} - - -/* Mark the tag of command 'cmd' as free, or in case of an untagged command, - * unlock the LUN. - */ - -static void cmd_free_tag(struct scsi_cmnd *cmd) -{ - SETUP_HOSTDATA(cmd->device->host); - - if (cmd->tag == TAG_NONE) { - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n", - H_NO(cmd), cmd->device->id, cmd->device->lun ); - } - else if (cmd->tag >= MAX_TAGS) { - printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n", - H_NO(cmd), cmd->tag ); - } - else { - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - clear_bit( cmd->tag, &ta->allocated ); - ta->nr_allocated--; - TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n", - H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun ); - } -} - - -static void free_all_tags( void ) -{ - int target, lun; - TAG_ALLOC *ta; - - if (!setup_use_tagged_queuing) - return; - - for( target = 0; target < 8; ++target ) { - for( lun = 0; lun < 8; ++lun ) { - ta = &TagAlloc[target][lun]; - memset( &ta->allocated, 0, MAX_TAGS/8 ); - ta->nr_allocated = 0; - } - } -} - -#endif /* SUPPORT_TAGS */ - - -/* - * Function : void initialize_SCp(struct scsi_cmnd *cmd) - * - * Purpose : initialize the saved data pointers for cmd to point to the - * start of the buffer. - * - * Inputs : cmd - struct scsi_cmnd structure to have pointers reset. - */ - -static __inline__ void initialize_SCp(struct scsi_cmnd *cmd) -{ - /* - * Initialize the Scsi Pointer field so that all of the commands in the - * various queues are valid. - */ - - if (scsi_bufflen(cmd)) { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; - cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = NULL; - cmd->SCp.this_residual = 0; - } - -} - -#include - -#if 1 -static struct { - unsigned char mask; - const char * name;} -signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, - { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" }, - { SR_SEL, "SEL" }, {0, NULL}}, -basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}}, -icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"}, - {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, - {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, - {0, NULL}}, -mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, - {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, - "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"}, - {MR_MONITOR_BSY, "MODE MONITOR BSY"}, - {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, - {0, NULL}}; - -/* - * Function : void NCR5380_print(struct Scsi_Host *instance) - * - * Purpose : print the SCSI bus signals for debugging purposes - * - * Input : instance - which NCR5380 - */ - -static void NCR5380_print(struct Scsi_Host *instance) { - unsigned char status, data, basr, mr, icr, i; - unsigned long flags; - - local_irq_save(flags); - data = NCR5380_read(CURRENT_SCSI_DATA_REG); - status = NCR5380_read(STATUS_REG); - mr = NCR5380_read(MODE_REG); - icr = NCR5380_read(INITIATOR_COMMAND_REG); - basr = NCR5380_read(BUS_AND_STATUS_REG); - local_irq_restore(flags); - printk("STATUS_REG: %02x ", status); - for (i = 0; signals[i].mask ; ++i) - if (status & signals[i].mask) - printk(",%s", signals[i].name); - printk("\nBASR: %02x ", basr); - for (i = 0; basrs[i].mask ; ++i) - if (basr & basrs[i].mask) - printk(",%s", basrs[i].name); - printk("\nICR: %02x ", icr); - for (i = 0; icrs[i].mask; ++i) - if (icr & icrs[i].mask) - printk(",%s", icrs[i].name); - printk("\nMODE: %02x ", mr); - for (i = 0; mrs[i].mask; ++i) - if (mr & mrs[i].mask) - printk(",%s", mrs[i].name); - printk("\n"); -} - -static struct { - unsigned char value; - const char *name; -} phases[] = { - {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"}, - {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"}, - {PHASE_UNKNOWN, "UNKNOWN"}}; - -/* - * Function : void NCR5380_print_phase(struct Scsi_Host *instance) - * - * Purpose : print the current SCSI phase for debugging purposes - * - * Input : instance - which NCR5380 - */ - -static void NCR5380_print_phase(struct Scsi_Host *instance) -{ - unsigned char status; - int i; - - status = NCR5380_read(STATUS_REG); - if (!(status & SR_REQ)) - printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO); - else { - for (i = 0; (phases[i].value != PHASE_UNKNOWN) && - (phases[i].value != (status & PHASE_MASK)); ++i); - printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name); - } -} - -#else /* !NDEBUG */ - -/* dummies... */ -__inline__ void NCR5380_print(struct Scsi_Host *instance) { }; -__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { }; - -#endif - -/* - * ++roman: New scheme of calling NCR5380_main() - * - * If we're not in an interrupt, we can call our main directly, it cannot be - * already running. Else, we queue it on a task queue, if not 'main_running' - * tells us that a lower level is already executing it. This way, - * 'main_running' needs not be protected in a special way. - * - * queue_main() is a utility function for putting our main onto the task - * queue, if main_running is false. It should be called only from a - * interrupt or bottom half. - */ - -#include -#include -#include - -static volatile int main_running = 0; -static DECLARE_WORK(NCR5380_tqueue, NCR5380_main); - -static __inline__ void queue_main(void) -{ - if (!main_running) { - /* If in interrupt and NCR5380_main() not already running, - queue it on the 'immediate' task queue, to be processed - immediately after the current interrupt processing has - finished. */ - schedule_work(&NCR5380_tqueue); - } - /* else: nothing to do: the running NCR5380_main() will pick up - any newly queued command. */ -} - - -static inline void NCR5380_all_init (void) -{ - static int done = 0; - if (!done) { - INI_PRINTK("scsi : NCR5380_all_init()\n"); - done = 1; - } -} - - -/* - * Function : void NCR58380_print_options (struct Scsi_Host *instance) - * - * Purpose : called by probe code indicating the NCR5380 driver - * options that were selected. - * - * Inputs : instance, pointer to this instance. Unused. - */ - -static void __init NCR5380_print_options (struct Scsi_Host *instance) -{ - printk(" generic options" -#ifdef AUTOSENSE - " AUTOSENSE" -#endif -#ifdef REAL_DMA - " REAL DMA" -#endif -#ifdef PARITY - " PARITY" -#endif -#ifdef SUPPORT_TAGS - " SCSI-2 TAGGED QUEUING" -#endif - ); - printk(" generic release=%d", NCR5380_PUBLIC_RELEASE); -} - -/* - * Function : void NCR5380_print_status (struct Scsi_Host *instance) - * - * Purpose : print commands in the various queues, called from - * NCR5380_abort and NCR5380_debug to aid debugging. - * - * Inputs : instance, pointer to this instance. - */ - -static void NCR5380_print_status (struct Scsi_Host *instance) -{ - char *pr_bfr; - char *start; - int len; - - NCR_PRINT(NDEBUG_ANY); - NCR_PRINT_PHASE(NDEBUG_ANY); - - pr_bfr = (char *) __get_free_page(GFP_ATOMIC); - if (!pr_bfr) { - printk("NCR5380_print_status: no memory for print buffer\n"); - return; - } - len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); - pr_bfr[len] = 0; - printk("\n%s\n", pr_bfr); - free_page((unsigned long) pr_bfr); -} - - -/******************************************/ -/* - * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED] - * - * *buffer: I/O buffer - * **start: if inout == FALSE pointer into buffer where user read should start - * offset: current offset - * length: length of buffer - * hostno: Scsi_Host host_no - * inout: TRUE - user is writing; FALSE - user is reading - * - * Return the number of bytes read from or written -*/ - -#undef SPRINTF -#define SPRINTF(fmt,args...) \ - do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \ - pos += sprintf(pos, fmt , ## args); } while(0) -static -char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer, - int length); - -static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, - char **start, off_t offset, int length, int inout) -{ - char *pos = buffer; - struct NCR5380_hostdata *hostdata; - struct scsi_cmnd *ptr; - unsigned long flags; - off_t begin = 0; -#define check_offset() \ - do { \ - if (pos - buffer < offset - begin) { \ - begin += pos - buffer; \ - pos = buffer; \ - } \ - } while (0) - - hostdata = (struct NCR5380_hostdata *)instance->hostdata; - - if (inout) { /* Has data been written to the file ? */ - return(-ENOSYS); /* Currently this is a no-op */ - } - SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE); - check_offset(); - local_irq_save(flags); - SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't"); - check_offset(); - if (!hostdata->connected) - SPRINTF("scsi%d: no currently connected command\n", HOSTNO); - else - pos = lprint_Scsi_Cmnd ((struct scsi_cmnd *) hostdata->connected, - pos, buffer, length); - SPRINTF("scsi%d: issue_queue\n", HOSTNO); - check_offset(); - for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) - { - pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); - check_offset(); - } - - SPRINTF("scsi%d: disconnected_queue\n", HOSTNO); - check_offset(); - for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr; - ptr = NEXT(ptr)) { - pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length); - check_offset(); - } - - local_irq_restore(flags); - *start = buffer + (offset - begin); - if (pos - buffer < offset - begin) - return 0; - else if (pos - buffer - (offset - begin) < length) - return pos - buffer - (offset - begin); - return length; -} - -static char *lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, char *pos, char *buffer, - int length) -{ - int i, s; - unsigned char *command; - SPRINTF("scsi%d: destination target %d, lun %d\n", - H_NO(cmd), cmd->device->id, cmd->device->lun); - SPRINTF(" command = "); - command = cmd->cmnd; - SPRINTF("%2d (0x%02x)", command[0], command[0]); - for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) - SPRINTF(" %02x", command[i]); - SPRINTF("\n"); - return pos; -} - - -/* - * Function : void NCR5380_init (struct Scsi_Host *instance) - * - * Purpose : initializes *instance and corresponding 5380 chip. - * - * Inputs : instance - instantiation of the 5380 driver. - * - * Notes : I assume that the host, hostno, and id bits have been - * set correctly. I don't care about the irq and other fields. - * - */ - -static int __init NCR5380_init(struct Scsi_Host *instance, int flags) -{ - int i; - SETUP_HOSTDATA(instance); - - NCR5380_all_init(); - - hostdata->aborted = 0; - hostdata->id_mask = 1 << instance->this_id; - hostdata->id_higher_mask = 0; - for (i = hostdata->id_mask; i <= 0x80; i <<= 1) - if (i > hostdata->id_mask) - hostdata->id_higher_mask |= i; - for (i = 0; i < 8; ++i) - hostdata->busy[i] = 0; -#ifdef SUPPORT_TAGS - init_tags(); -#endif -#if defined (REAL_DMA) - hostdata->dma_len = 0; -#endif - hostdata->targets_present = 0; - hostdata->connected = NULL; - hostdata->issue_queue = NULL; - hostdata->disconnected_queue = NULL; - hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; - - if (!the_template) { - the_template = instance->hostt; - first_instance = instance; - } - - -#ifndef AUTOSENSE - if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1)) - printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n" - " without AUTOSENSE option, contingent allegiance conditions may\n" - " be incorrectly cleared.\n", HOSTNO); -#endif /* def AUTOSENSE */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, 0); - - return 0; -} - -static void NCR5380_exit(struct Scsi_Host *instance) -{ - /* Empty, as we didn't schedule any delayed work */ -} - -/* - * Function : int NCR5380_queue_command (struct scsi_cmnd *cmd, - * void (*done)(struct scsi_cmnd *)) - * - * Purpose : enqueues a SCSI command - * - * Inputs : cmd - SCSI command, done - function called on completion, with - * a pointer to the command descriptor. - * - * Returns : 0 - * - * Side effects : - * cmd is added to the per instance issue_queue, with minor - * twiddling done to the host specific fields of cmd. If the - * main coroutine is not running, it is restarted. - * - */ - -/* Only make static if a wrapper function is used */ -static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - SETUP_HOSTDATA(cmd->device->host); - struct scsi_cmnd *tmp; - unsigned long flags; - -#if (NDEBUG & NDEBUG_NO_WRITE) - switch (cmd->cmnd[0]) { - case WRITE_6: - case WRITE_10: - printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n", - H_NO(cmd)); - cmd->result = (DID_ERROR << 16); - done(cmd); - return 0; - } -#endif /* (NDEBUG & NDEBUG_NO_WRITE) */ - - -#ifdef NCR5380_STATS -# if 0 - if (!hostdata->connected && !hostdata->issue_queue && - !hostdata->disconnected_queue) { - hostdata->timebase = jiffies; - } -# endif -# ifdef NCR5380_STAT_LIMIT - if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) -# endif - switch (cmd->cmnd[0]) - { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd); - hostdata->pendingw++; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase); - hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd); - hostdata->pendingr++; - break; - } -#endif - - /* - * We use the host_scribble field as a pointer to the next command - * in a queue - */ - - SET_NEXT(cmd, NULL); - cmd->scsi_done = done; - - cmd->result = 0; - - - /* - * Insert the cmd into the issue queue. Note that REQUEST SENSE - * commands are added to the head of the queue since any command will - * clear the contingent allegiance condition that exists and the - * sense data is only guaranteed to be valid while the condition exists. - */ - - local_irq_save(flags); - /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA. - * Otherwise a running NCR5380_main may steal the lock. - * Lock before actually inserting due to fairness reasons explained in - * atari_scsi.c. If we insert first, then it's impossible for this driver - * to release the lock. - * Stop timer for this command while waiting for the lock, or timeouts - * may happen (and they really do), and it's no good if the command doesn't - * appear in any of the queues. - * ++roman: Just disabling the NCR interrupt isn't sufficient here, - * because also a timer int can trigger an abort or reset, which would - * alter queues and touch the lock. - */ - if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) { - LIST(cmd, hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); - hostdata->issue_queue = cmd; - } else { - for (tmp = (struct scsi_cmnd *)hostdata->issue_queue; - NEXT(tmp); tmp = NEXT(tmp)) - ; - LIST(cmd, tmp); - SET_NEXT(tmp, cmd); - } - - local_irq_restore(flags); - - QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd), - (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"); - - /* If queue_command() is called from an interrupt (real one or bottom - * half), we let queue_main() do the job of taking care about main. If it - * is already running, this is a no-op, else main will be queued. - * - * If we're not in an interrupt, we can call NCR5380_main() - * unconditionally, because it cannot be already running. - */ - if (in_interrupt() || ((flags >> 8) & 7) >= 6) - queue_main(); - else - NCR5380_main(NULL); - return 0; -} - -static DEF_SCSI_QCMD(NCR5380_queue_command) - -/* - * Function : NCR5380_main (void) - * - * Purpose : NCR5380_main is a coroutine that runs as long as more work can - * be done on the NCR5380 host adapters in a system. Both - * NCR5380_queue_command() and NCR5380_intr() will try to start it - * in case it is not running. - * - * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should - * reenable them. This prevents reentrancy and kernel stack overflow. - */ - -static void NCR5380_main (struct work_struct *bl) -{ - struct scsi_cmnd *tmp, *prev; - struct Scsi_Host *instance = first_instance; - struct NCR5380_hostdata *hostdata = HOSTDATA(instance); - int done; - unsigned long flags; - - /* - * We run (with interrupts disabled) until we're sure that none of - * the host adapters have anything that can be done, at which point - * we set main_running to 0 and exit. - * - * Interrupts are enabled before doing various other internal - * instructions, after we've decided that we need to run through - * the loop again. - * - * this should prevent any race conditions. - * - * ++roman: Just disabling the NCR interrupt isn't sufficient here, - * because also a timer int can trigger an abort or reset, which can - * alter queues and touch the Falcon lock. - */ - - /* Tell int handlers main() is now already executing. Note that - no races are possible here. If an int comes in before - 'main_running' is set here, and queues/executes main via the - task queue, it doesn't do any harm, just this instance of main - won't find any work left to do. */ - if (main_running) - return; - main_running = 1; - - local_save_flags(flags); - do { - local_irq_disable(); /* Freeze request queues */ - done = 1; - - if (!hostdata->connected) { - MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO ); - /* - * Search through the issue_queue for a command destined - * for a target that's not busy. - */ -#if (NDEBUG & NDEBUG_LISTS) - for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL; - tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp)) - ; - if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/ -#endif - for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, - prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) { - -#if (NDEBUG & NDEBUG_LISTS) - if (prev != tmp) - printk("MAIN tmp=%p target=%d busy=%d lun=%d\n", - tmp, tmp->target, hostdata->busy[tmp->target], - tmp->lun); -#endif - /* When we find one, remove it from the issue queue. */ - /* ++guenther: possible race with Falcon locking */ - if ( -#ifdef SUPPORT_TAGS - !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE) -#else - !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun)) -#endif - ) { - /* ++guenther: just to be sure, this must be atomic */ - local_irq_disable(); - if (prev) { - REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); - } else { - REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp)); - hostdata->issue_queue = NEXT(tmp); - } - SET_NEXT(tmp, NULL); - - /* reenable interrupts after finding one */ - local_irq_restore(flags); - - /* - * Attempt to establish an I_T_L nexus here. - * On success, instance->hostdata->connected is set. - * On failure, we must add the command back to the - * issue queue so we can keep trying. - */ - MAIN_PRINTK("scsi%d: main(): command for target %d " - "lun %d removed from issue_queue\n", - HOSTNO, tmp->target, tmp->lun); - /* - * REQUEST SENSE commands are issued without tagged - * queueing, even on SCSI-II devices because the - * contingent allegiance condition exists for the - * entire unit. - */ - /* ++roman: ...and the standard also requires that - * REQUEST SENSE command are untagged. - */ - -#ifdef SUPPORT_TAGS - cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE ); -#endif - if (!NCR5380_select(instance, tmp, - (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : - TAG_NEXT)) { - break; - } else { - local_irq_disable(); - LIST(tmp, hostdata->issue_queue); - SET_NEXT(tmp, hostdata->issue_queue); - hostdata->issue_queue = tmp; -#ifdef SUPPORT_TAGS - cmd_free_tag( tmp ); -#endif - local_irq_restore(flags); - MAIN_PRINTK("scsi%d: main(): select() failed, " - "returned to issue_queue\n", HOSTNO); - if (hostdata->connected) - break; - } - } /* if target/lun/target queue is not busy */ - } /* for issue_queue */ - } /* if (!hostdata->connected) */ - if (hostdata->connected -#ifdef REAL_DMA - && !hostdata->dma_len -#endif - ) { - local_irq_restore(flags); - MAIN_PRINTK("scsi%d: main: performing information transfer\n", - HOSTNO); - NCR5380_information_transfer(instance); - MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO); - done = 0; - } - } while (!done); - - /* Better allow ints _after_ 'main_running' has been cleared, else - an interrupt could believe we'll pick up the work it left for - us, but we won't see it anymore here... */ - main_running = 0; - local_irq_restore(flags); -} - - -#ifdef REAL_DMA -/* - * Function : void NCR5380_dma_complete (struct Scsi_Host *instance) - * - * Purpose : Called by interrupt handler when DMA finishes or a phase - * mismatch occurs (which would finish the DMA transfer). - * - * Inputs : instance - this instance of the NCR5380. - * - */ - -static void NCR5380_dma_complete( struct Scsi_Host *instance ) -{ - SETUP_HOSTDATA(instance); - int transfered; - unsigned char **data; - volatile int *count; - - if (!hostdata->connected) { - printk(KERN_WARNING "scsi%d: received end of DMA interrupt with " - "no connected cmd\n", HOSTNO); - return; - } - - DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n", - HOSTNO, NCR5380_read(BUS_AND_STATUS_REG), - NCR5380_read(STATUS_REG)); - - if((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) { - printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO); - printk("please e-mail sammy@sammy.net with a description of how this\n"); - printk("error was produced.\n"); - BUG(); - } - - /* make sure we're not stuck in a data phase */ - if((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | - BASR_ACK)) == - (BASR_PHASE_MATCH | BASR_ACK)) { - printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG)); - printk("scsi%d: bus stuck in data phase -- probably a single byte " - "overrun!\n", HOSTNO); - printk("not prepared for this error!\n"); - printk("please e-mail sammy@sammy.net with a description of how this\n"); - printk("error was produced.\n"); - BUG(); - } - - - - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - transfered = hostdata->dma_len - NCR5380_dma_residual(instance); - hostdata->dma_len = 0; - - data = (unsigned char **) &(hostdata->connected->SCp.ptr); - count = &(hostdata->connected->SCp.this_residual); - *data += transfered; - *count -= transfered; - -} -#endif /* REAL_DMA */ - - -/* - * Function : void NCR5380_intr (int irq) - * - * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses - * from the disconnected queue, and restarting NCR5380_main() - * as required. - * - * Inputs : int irq, irq that caused this interrupt. - * - */ - -static irqreturn_t NCR5380_intr (int irq, void *dev_id) -{ - struct Scsi_Host *instance = first_instance; - int done = 1, handled = 0; - unsigned char basr; - - INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO); - - /* Look for pending interrupts */ - basr = NCR5380_read(BUS_AND_STATUS_REG); - INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr); - /* dispatch to appropriate routine if found and done=0 */ - if (basr & BASR_IRQ) { - NCR_PRINT(NDEBUG_INTR); - if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) { - done = 0; -// ENABLE_IRQ(); - INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO); - NCR5380_reselect(instance); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - else if (basr & BASR_PARITY_ERROR) { - INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) { - INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO); - (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG); - } - else { - /* - * The rest of the interrupt conditions can occur only during a - * DMA transfer - */ - -#if defined(REAL_DMA) - /* - * We should only get PHASE MISMATCH and EOP interrupts if we have - * DMA enabled, so do a sanity check based on the current setting - * of the MODE register. - */ - - if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) && - ((basr & BASR_END_DMA_TRANSFER) || - !(basr & BASR_PHASE_MATCH))) { - - INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO); - NCR5380_dma_complete( instance ); - done = 0; -// ENABLE_IRQ(); - } else -#endif /* REAL_DMA */ - { -/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */ - if (basr & BASR_PHASE_MATCH) - INT_PRINTK("scsi%d: unknown interrupt, " - "BASR 0x%x, MR 0x%x, SR 0x%x\n", - HOSTNO, basr, NCR5380_read(MODE_REG), - NCR5380_read(STATUS_REG)); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); -#ifdef SUN3_SCSI_VME - dregs->csr |= CSR_DMA_ENABLE; -#endif - } - } /* if !(SELECTION || PARITY) */ - handled = 1; - } /* BASR & IRQ */ - else { - - printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, " - "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr, - NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); - (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); -#ifdef SUN3_SCSI_VME - dregs->csr |= CSR_DMA_ENABLE; -#endif - } - - if (!done) { - INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO); - /* Put a call to NCR5380_main() on the queue... */ - queue_main(); - } - return IRQ_RETVAL(handled); -} - -#ifdef NCR5380_STATS -static void collect_stats(struct NCR5380_hostdata *hostdata, - struct scsi_cmnd *cmd) -{ -# ifdef NCR5380_STAT_LIMIT - if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT) -# endif - switch (cmd->cmnd[0]) - { - case WRITE: - case WRITE_6: - case WRITE_10: - hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/ - hostdata->pendingw--; - break; - case READ: - case READ_6: - case READ_10: - hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase); - /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/ - hostdata->pendingr--; - break; - } -} -#endif - -/* - * Function : int NCR5380_select(struct Scsi_Host *instance, - * struct scsi_cmnd *cmd, int tag); - * - * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command, - * including ARBITRATION, SELECTION, and initial message out for - * IDENTIFY and queue messages. - * - * Inputs : instance - instantiation of the 5380 driver on which this - * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for - * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for - * the command that is presently connected. - * - * Returns : -1 if selection could not execute for some reason, - * 0 if selection succeeded or failed because the target - * did not respond. - * - * Side effects : - * If bus busy, arbitration failed, etc, NCR5380_select() will exit - * with registers as they should have been on entry - ie - * SELECT_ENABLE will be set appropriately, the NCR5380 - * will cease to drive any SCSI bus signals. - * - * If successful : I_T_L or I_T_L_Q nexus will be established, - * instance->connected will be set to cmd. - * SELECT interrupt will be disabled. - * - * If failed (no target) : cmd->scsi_done() will be called, and the - * cmd->result host byte set to DID_BAD_TARGET. - */ - -static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd, - int tag) -{ - SETUP_HOSTDATA(instance); - unsigned char tmp[3], phase; - unsigned char *data; - int len; - unsigned long timeout; - unsigned long flags; - - hostdata->restart_select = 0; - NCR_PRINT(NDEBUG_ARBITRATION); - ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO, - instance->this_id); - - /* - * Set the phase bits to 0, otherwise the NCR5380 won't drive the - * data bus during SELECTION. - */ - - local_irq_save(flags); - if (hostdata->connected) { - local_irq_restore(flags); - return -1; - } - NCR5380_write(TARGET_COMMAND_REG, 0); - - - /* - * Start arbitration. - */ - - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(MODE_REG, MR_ARBITRATE); - - local_irq_restore(flags); - - /* Wait for arbitration logic to complete */ -#ifdef NCR_TIMEOUT - { - unsigned long timeout = jiffies + 2*NCR_TIMEOUT; - - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && time_before(jiffies, timeout) && !hostdata->connected) - ; - if (time_after_eq(jiffies, timeout)) - { - printk("scsi : arbitration timeout at %d\n", __LINE__); - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - } -#else /* NCR_TIMEOUT */ - while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS) - && !hostdata->connected); -#endif - - ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO); - - if (hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - return -1; - } - /* - * The arbitration delay is 2.2us, but this is a minimum and there is - * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate - * the integral nature of udelay(). - * - */ - - udelay(3); - - /* Check for lost arbitration */ - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || - (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", - HOSTNO); - return -1; - } - - /* after/during arbitration, BSY should be asserted. - IBM DPES-31080 Version S31Q works now */ - /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL | - ICR_ASSERT_BSY ) ; - - if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || - hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", - HOSTNO); - return -1; - } - - /* - * Again, bus clear + bus settle time is 1.2us, however, this is - * a minimum so we'll udelay ceil(1.2) - */ - -#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY - /* ++roman: But some targets (see above :-) seem to need a bit more... */ - udelay(15); -#else - udelay(2); -#endif - - if (hostdata->connected) { - NCR5380_write(MODE_REG, MR_BASE); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; - } - - ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO); - - /* - * Now that we have won arbitration, start Selection process, asserting - * the host and target ID's on the SCSI bus. - */ - - NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id))); - - /* - * Raise ATN while SEL is true before BSY goes false from arbitration, - * since this is the only way to guarantee that we'll get a MESSAGE OUT - * phase immediately after selection. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL )); - NCR5380_write(MODE_REG, MR_BASE); - - /* - * Reselect interrupts must be turned off prior to the dropping of BSY, - * otherwise we will trigger an interrupt. - */ - - if (hostdata->connected) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; - } - - NCR5380_write(SELECT_ENABLE_REG, 0); - - /* - * The initiator shall then wait at least two deskew delays and release - * the BSY signal. - */ - udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */ - - /* Reset BSY */ - NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | - ICR_ASSERT_ATN | ICR_ASSERT_SEL)); - - /* - * Something weird happens when we cease to drive BSY - looks - * like the board/chip is letting us do another read before the - * appropriate propagation delay has expired, and we're confusing - * a BSY signal from ourselves as the target's response to SELECTION. - * - * A small delay (the 'C++' frontend breaks the pipeline with an - * unnecessary jump, making it work on my 386-33/Trantor T128, the - * tighter 'C' code breaks and requires this) solves the problem - - * the 1 us delay is arbitrary, and only used because this delay will - * be the same on other platforms and since it works here, it should - * work there. - * - * wingel suggests that this could be due to failing to wait - * one deskew delay. - */ - - udelay(1); - - SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id); - - /* - * The SCSI specification calls for a 250 ms timeout for the actual - * selection. - */ - - timeout = jiffies + 25; - - /* - * XXX very interesting - we're seeing a bounce where the BSY we - * asserted is being reflected / still asserted (propagation delay?) - * and it's detecting as true. Sigh. - */ - -#if 0 - /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert - * IO while SEL is true. But again, there are some disks out the in the - * world that do that nevertheless. (Somebody claimed that this announces - * reselection capability of the target.) So we better skip that test and - * only wait for BSY... (Famous german words: Der Klügere gibt nach :-) - */ - - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & - (SR_BSY | SR_IO))); - - if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == - (SR_SEL | SR_IO)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - NCR5380_reselect(instance); - printk (KERN_ERR "scsi%d: reselection after won arbitration?\n", - HOSTNO); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } -#else - while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY)); -#endif - - /* - * No less than two deskew delays after the initiator detects the - * BSY signal is true, it shall release the SEL signal and may - * change the DATA BUS. -wingel - */ - - udelay(1); - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - if (!(NCR5380_read(STATUS_REG) & SR_BSY)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - if (hostdata->targets_present & (1 << cmd->device->id)) { - printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO); - if (hostdata->restart_select) - printk(KERN_NOTICE "\trestart select\n"); - NCR_PRINT(NDEBUG_ANY); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return -1; - } - cmd->result = DID_BAD_TARGET << 16; -#ifdef NCR5380_STATS - collect_stats(hostdata, cmd); -#endif -#ifdef SUPPORT_TAGS - cmd_free_tag( cmd ); -#endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return 0; - } - - hostdata->targets_present |= (1 << cmd->device->id); - - /* - * Since we followed the SCSI spec, and raised ATN while SEL - * was true but before BSY was false during selection, the information - * transfer phase should be a MESSAGE OUT phase so that we can send the - * IDENTIFY message. - * - * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG - * message (2 bytes) with a tag ID that we increment with every command - * until it wraps back to 0. - * - * XXX - it turns out that there are some broken SCSI-II devices, - * which claim to support tagged queuing but fail when more than - * some number of commands are issued at once. - */ - - /* Wait for start of REQ/ACK handshake */ - while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - - SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n", - HOSTNO, cmd->device->id); - tmp[0] = IDENTIFY(1, cmd->device->lun); - -#ifdef SUPPORT_TAGS - if (cmd->tag != TAG_NONE) { - tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG; - tmp[2] = cmd->tag; - len = 3; - } else - len = 1; -#else - len = 1; - cmd->tag=0; -#endif /* SUPPORT_TAGS */ - - /* Send message(s) */ - data = tmp; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio(instance, &phase, &len, &data); - SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO); - /* XXX need to handle errors here */ - hostdata->connected = cmd; -#ifndef SUPPORT_TAGS - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); -#endif -#ifdef SUN3_SCSI_VME - dregs->csr |= CSR_INTR; -#endif - initialize_SCp(cmd); - - - return 0; -} - -/* - * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, - * unsigned char *phase, int *count, unsigned char **data) - * - * Purpose : transfers data in given phase using polled I/O - * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. - * - * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes are transferred or exit - * is in same phase. - * - * Also, *phase, *count, *data are modified in place. - * - * XXX Note : handling for bus free may be useful. - */ - -/* - * Note : this code is not as quick as it could be, however it - * IS 100% reliable, and for the actual data transfer where speed - * counts, we will always do a pseudo DMA or DMA transfer. - */ - -static int NCR5380_transfer_pio( struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data) -{ - register unsigned char p = *phase, tmp; - register int c = *count; - register unsigned char *d = *data; - - /* - * The NCR5380 chip will only drive the SCSI bus when the - * phase specified in the appropriate bits of the TARGET COMMAND - * REGISTER match the STATUS REGISTER - */ - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p)); - - do { - /* - * Wait for assertion of REQ, after which the phase bits will be - * valid - */ - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); - - HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO); - - /* Check for phase mismatch */ - if ((tmp & PHASE_MASK) != p) { - PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO); - NCR_PRINT_PHASE(NDEBUG_PIO); - break; - } - - /* Do actual transfer from SCSI bus to / from memory */ - if (!(p & SR_IO)) - NCR5380_write(OUTPUT_DATA_REG, *d); - else - *d = NCR5380_read(CURRENT_SCSI_DATA_REG); - - ++d; - - /* - * The SCSI standard suggests that in MSGOUT phase, the initiator - * should drop ATN on the last byte of the message phase - * after REQ has been asserted for the handshake but before - * the initiator raises ACK. - */ - - if (!(p & SR_IO)) { - if (!((p & SR_MSG) && c > 1)) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA); - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ACK); - } else { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN); - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK); - } - } else { - NCR_PRINT(NDEBUG_PIO); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); - } - - while (NCR5380_read(STATUS_REG) & SR_REQ); - - HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO); - -/* - * We have several special cases to consider during REQ/ACK handshaking : - * 1. We were in MSGOUT phase, and we are on the last byte of the - * message. ATN must be dropped as ACK is dropped. - * - * 2. We are in a MSGIN phase, and we are on the last byte of the - * message. We must exit with ACK asserted, so that the calling - * code may raise ATN before dropping ACK to reject the message. - * - * 3. ACK and ATN are clear and the target may proceed as normal. - */ - if (!(p == PHASE_MSGIN && c == 1)) { - if (p == PHASE_MSGOUT && c > 1) - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - else - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - } - } while (--c); - - PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c); - - *count = c; - *data = d; - tmp = NCR5380_read(STATUS_REG); - /* The phase read from the bus is valid if either REQ is (already) - * asserted or if ACK hasn't been released yet. The latter is the case if - * we're in MSGIN and all wanted bytes have been received. */ - if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0)) - *phase = tmp & PHASE_MASK; - else - *phase = PHASE_UNKNOWN; - - if (!c || (*phase == p)) - return 0; - else - return -1; -} - -/* - * Function : do_abort (Scsi_Host *host) - * - * Purpose : abort the currently established nexus. Should only be - * called from a routine which can drop into a - * - * Returns : 0 on success, -1 on failure. - */ - -static int do_abort (struct Scsi_Host *host) -{ - unsigned char tmp, *msgptr, phase; - int len; - - /* Request message out phase */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - - /* - * Wait for the target to indicate a valid phase by asserting - * REQ. Once this happens, we'll have either a MSGOUT phase - * and can immediately send the ABORT message, or we'll have some - * other phase and will have to source/sink data. - * - * We really don't care what value was on the bus or what value - * the target sees, so we just handshake. - */ - - while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ)); - - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - if ((tmp & PHASE_MASK) != PHASE_MSGOUT) { - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); - } - - tmp = ABORT; - msgptr = &tmp; - len = 1; - phase = PHASE_MSGOUT; - NCR5380_transfer_pio (host, &phase, &len, &msgptr); - - /* - * If we got here, and the command completed successfully, - * we're about to go into bus free state. - */ - - return len ? -1 : 0; -} - -#if defined(REAL_DMA) -/* - * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, - * unsigned char *phase, int *count, unsigned char **data) - * - * Purpose : transfers data in given phase using either real - * or pseudo DMA. - * - * Inputs : instance - instance of driver, *phase - pointer to - * what phase is expected, *count - pointer to number of - * bytes to transfer, **data - pointer to data pointer. - * - * Returns : -1 when different phase is entered without transferring - * maximum number of bytes, 0 if all bytes or transferred or exit - * is in same phase. - * - * Also, *phase, *count, *data are modified in place. - * - */ - - -static int NCR5380_transfer_dma( struct Scsi_Host *instance, - unsigned char *phase, int *count, - unsigned char **data) -{ - SETUP_HOSTDATA(instance); - register int c = *count; - register unsigned char p = *phase; - unsigned long flags; - - /* sanity check */ - if(!sun3_dma_setup_done) { - printk("scsi%d: transfer_dma without setup!\n", HOSTNO); - BUG(); - } - hostdata->dma_len = c; - - DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n", - HOSTNO, (p & SR_IO) ? "reading" : "writing", - c, (p & SR_IO) ? "to" : "from", *data); - - /* netbsd turns off ints here, why not be safe and do it too */ - local_irq_save(flags); - - /* send start chain */ - sun3scsi_dma_start(c, *data); - - if (p & SR_IO) { - NCR5380_write(TARGET_COMMAND_REG, 1); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(INITIATOR_COMMAND_REG, 0); - NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR)); - NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0); - } else { - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_read(RESET_PARITY_INTERRUPT_REG); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA); - NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR)); - NCR5380_write(START_DMA_SEND_REG, 0); - } - -#ifdef SUN3_SCSI_VME - dregs->csr |= CSR_DMA_ENABLE; -#endif - - local_irq_restore(flags); - - sun3_dma_active = 1; - return 0; -} -#endif /* defined(REAL_DMA) */ - -/* - * Function : NCR5380_information_transfer (struct Scsi_Host *instance) - * - * Purpose : run through the various SCSI phases and do as the target - * directs us to. Operates on the currently connected command, - * instance->connected. - * - * Inputs : instance, instance for which we are doing commands - * - * Side effects : SCSI things happen, the disconnected queue will be - * modified if a command disconnects, *instance->connected will - * change. - * - * XXX Note : we need to watch for bus free or a reset condition here - * to recover from an unexpected bus free condition. - */ - -static void NCR5380_information_transfer (struct Scsi_Host *instance) -{ - SETUP_HOSTDATA(instance); - unsigned long flags; - unsigned char msgout = NOP; - int sink = 0; - int len; -#if defined(REAL_DMA) - int transfersize; -#endif - unsigned char *data; - unsigned char phase, tmp, extended_msg[10], old_phase=0xff; - struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected; - -#ifdef SUN3_SCSI_VME - dregs->csr |= CSR_INTR; -#endif - - while (1) { - tmp = NCR5380_read(STATUS_REG); - /* We only have a valid SCSI phase when REQ is asserted */ - if (tmp & SR_REQ) { - phase = (tmp & PHASE_MASK); - if (phase != old_phase) { - old_phase = phase; - NCR_PRINT_PHASE(NDEBUG_INFORMATION); - } - - if(phase == PHASE_CMDOUT) { - void *d; - unsigned long count; - - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - count = cmd->SCp.buffer->length; - d = SGADDR(cmd->SCp.buffer); - } else { - count = cmd->SCp.this_residual; - d = cmd->SCp.ptr; - } -#ifdef REAL_DMA - /* this command setup for dma yet? */ - if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done - != cmd)) - { - if (cmd->request->cmd_type == REQ_TYPE_FS) { - sun3scsi_dma_setup(d, count, - rq_data_dir(cmd->request)); - sun3_dma_setup_done = cmd; - } - } -#endif -#ifdef SUN3_SCSI_VME - dregs->csr |= CSR_INTR; -#endif - } - - - if (sink && (phase != PHASE_MSGOUT)) { - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp)); - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | - ICR_ASSERT_ACK); - while (NCR5380_read(STATUS_REG) & SR_REQ); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 0; - continue; - } - - switch (phase) { - case PHASE_DATAOUT: -#if (NDEBUG & NDEBUG_NO_DATAOUT) - printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT " - "aborted\n", HOSTNO); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - return; -#endif - case PHASE_DATAIN: - /* - * If there is no room left in the current buffer in the - * scatter-gather list, move onto the next one. - */ - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = SGADDR(cmd->SCp.buffer); - INF_PRINTK("scsi%d: %d bytes and %d buffers left\n", - HOSTNO, cmd->SCp.this_residual, - cmd->SCp.buffers_residual); - } - - /* - * The preferred transfer method is going to be - * PSEUDO-DMA for systems that are strictly PIO, - * since we can let the hardware do the handshaking. - * - * For this to work, we need to know the transfersize - * ahead of time, since the pseudo-DMA code will sit - * in an unconditional loop. - */ - -/* ++roman: I suggest, this should be - * #if def(REAL_DMA) - * instead of leaving REAL_DMA out. - */ - -#if defined(REAL_DMA) -// if (!cmd->device->borken && - if((transfersize = - NCR5380_dma_xfer_len(instance,cmd,phase)) > SUN3_DMA_MINSIZE) { - len = transfersize; - cmd->SCp.phase = phase; - - if (NCR5380_transfer_dma(instance, &phase, - &len, (unsigned char **) &cmd->SCp.ptr)) { - /* - * If the watchdog timer fires, all future - * accesses to this device will use the - * polled-IO. */ - printk(KERN_NOTICE "scsi%d: switching target %d " - "lun %d to slow handshake\n", HOSTNO, - cmd->device->id, cmd->device->lun); - cmd->device->borken = 1; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - sink = 1; - do_abort(instance); - cmd->result = DID_ERROR << 16; - cmd->scsi_done(cmd); - /* XXX - need to source or sink data here, as appropriate */ - } else { -#ifdef REAL_DMA - /* ++roman: When using real DMA, - * information_transfer() should return after - * starting DMA since it has nothing more to - * do. - */ - return; -#else - cmd->SCp.this_residual -= transfersize - len; -#endif - } - } else -#endif /* defined(REAL_DMA) */ - NCR5380_transfer_pio(instance, &phase, - (int *) &cmd->SCp.this_residual, (unsigned char **) - &cmd->SCp.ptr); -#ifdef REAL_DMA - /* if we had intended to dma that command clear it */ - if(sun3_dma_setup_done == cmd) - sun3_dma_setup_done = NULL; -#endif - - break; - case PHASE_MSGIN: - len = 1; - data = &tmp; - NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */ - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Message = tmp; - - switch (tmp) { - /* - * Linking lets us reduce the time required to get the - * next command out to the device, hopefully this will - * mean we don't waste another revolution due to the delays - * required by ARBITRATION and another SELECTION. - * - * In the current implementation proposal, low level drivers - * merely have to start the next command, pointed to by - * next_link, done() is called as with unlinked commands. - */ -#ifdef LINKED - case LINKED_CMD_COMPLETE: - case LINKED_FLG_CMD_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - LNK_PRINTK("scsi%d: target %d lun %d linked command " - "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Sanity check : A linked command should only terminate - * with one of these messages if there are more linked - * commands available. - */ - - if (!cmd->next_link) { - printk(KERN_NOTICE "scsi%d: target %d lun %d " - "linked command complete, no next_link\n", - HOSTNO, cmd->device->id, cmd->device->lun); - sink = 1; - do_abort (instance); - return; - } - - initialize_SCp(cmd->next_link); - /* The next command is still part of this process; copy it - * and don't free it! */ - cmd->next_link->tag = cmd->tag; - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - LNK_PRINTK("scsi%d: target %d lun %d linked request " - "done, calling scsi_done().\n", - HOSTNO, cmd->device->id, cmd->device->lun); -#ifdef NCR5380_STATS - collect_stats(hostdata, cmd); -#endif - cmd->scsi_done(cmd); - cmd = hostdata->connected; - break; -#endif /* def LINKED */ - case ABORT: - case COMMAND_COMPLETE: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - hostdata->connected = NULL; - QU_PRINTK("scsi%d: command for target %d, lun %d " - "completed\n", HOSTNO, cmd->device->id, cmd->device->lun); -#ifdef SUPPORT_TAGS - cmd_free_tag( cmd ); - if (status_byte(cmd->SCp.Status) == QUEUE_FULL) { - /* Turn a QUEUE FULL status into BUSY, I think the - * mid level cannot handle QUEUE FULL :-( (The - * command is retried after BUSY). Also update our - * queue size to the number of currently issued - * commands now. - */ - /* ++Andreas: the mid level code knows about - QUEUE_FULL now. */ - TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun]; - TAG_PRINTK("scsi%d: target %d lun %d returned " - "QUEUE_FULL after %d commands\n", - HOSTNO, cmd->device->id, cmd->device->lun, - ta->nr_allocated); - if (ta->queue_size > ta->nr_allocated) - ta->nr_allocated = ta->queue_size; - } -#else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); -#endif - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - - /* - * I'm not sure what the correct thing to do here is : - * - * If the command that just executed is NOT a request - * sense, the obvious thing to do is to set the result - * code to the values of the stored parameters. - * - * If it was a REQUEST SENSE command, we need some way to - * differentiate between the failure code of the original - * and the failure code of the REQUEST sense - the obvious - * case is success, where we fall through and leave the - * result code unchanged. - * - * The non-obvious place is where the REQUEST SENSE failed - */ - - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (status_byte(cmd->SCp.Status) != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - -#ifdef AUTOSENSE - if ((cmd->cmnd[0] == REQUEST_SENSE) && - hostdata->ses.cmd_len) { - scsi_eh_restore_cmnd(cmd, &hostdata->ses); - hostdata->ses.cmd_len = 0 ; - } - - if ((cmd->cmnd[0] != REQUEST_SENSE) && - (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) { - scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0); - ASEN_PRINTK("scsi%d: performing request sense\n", - HOSTNO); - /* this is initialized from initialize_SCp - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - */ - - local_irq_save(flags); - LIST(cmd,hostdata->issue_queue); - SET_NEXT(cmd, hostdata->issue_queue); - hostdata->issue_queue = (struct scsi_cmnd *) cmd; - local_irq_restore(flags); - QU_PRINTK("scsi%d: REQUEST SENSE added to head of " - "issue queue\n", H_NO(cmd)); - } else -#endif /* def AUTOSENSE */ - { -#ifdef NCR5380_STATS - collect_stats(hostdata, cmd); -#endif - cmd->scsi_done(cmd); - } - - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); - - return; - case MESSAGE_REJECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - switch (hostdata->last_message) { - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - case SIMPLE_QUEUE_TAG: - /* The target obviously doesn't support tagged - * queuing, even though it announced this ability in - * its INQUIRY data ?!? (maybe only this LUN?) Ok, - * clear 'tagged_supported' and lock the LUN, since - * the command is treated as untagged further on. - */ - cmd->device->tagged_supported = 0; - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - cmd->tag = TAG_NONE; - TAG_PRINTK("scsi%d: target %d lun %d rejected " - "QUEUE_TAG message; tagged queuing " - "disabled\n", - HOSTNO, cmd->device->id, cmd->device->lun); - break; - } - break; - case DISCONNECT: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - local_irq_save(flags); - cmd->device->disconnect = 1; - LIST(cmd,hostdata->disconnected_queue); - SET_NEXT(cmd, hostdata->disconnected_queue); - hostdata->connected = NULL; - hostdata->disconnected_queue = cmd; - local_irq_restore(flags); - QU_PRINTK("scsi%d: command for target %d lun %d was " - "moved from connected to the " - "disconnected_queue\n", HOSTNO, - cmd->device->id, cmd->device->lun); - /* - * Restore phase bits to 0 so an interrupted selection, - * arbitration can resume. - */ - NCR5380_write(TARGET_COMMAND_REG, 0); - - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - /* Wait for bus free to avoid nasty timeouts */ - while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected) - barrier(); -#ifdef SUN3_SCSI_VME - dregs->csr |= CSR_DMA_ENABLE; -#endif - return; - /* - * The SCSI data pointer is *IMPLICITLY* saved on a disconnect - * operation, in violation of the SCSI spec so we can safely - * ignore SAVE/RESTORE pointers calls. - * - * Unfortunately, some disks violate the SCSI spec and - * don't issue the required SAVE_POINTERS message before - * disconnecting, and we have to break spec to remain - * compatible. - */ - case SAVE_POINTERS: - case RESTORE_POINTERS: - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interrupts */ - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - break; - case EXTENDED_MESSAGE: -/* - * Extended messages are sent in the following format : - * Byte - * 0 EXTENDED_MESSAGE == 1 - * 1 length (includes one byte for code, doesn't - * include first two bytes) - * 2 code - * 3..length+1 arguments - * - * Start the extended message buffer with the EXTENDED_MESSAGE - * byte, since spi_print_msg() wants the whole thing. - */ - extended_msg[0] = EXTENDED_MESSAGE; - /* Accept first byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO); - - len = 2; - data = extended_msg + 1; - phase = PHASE_MSGIN; - NCR5380_transfer_pio(instance, &phase, &len, &data); - EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO, - (int)extended_msg[1], (int)extended_msg[2]); - - if (!len && extended_msg[1] <= - (sizeof (extended_msg) - 1)) { - /* Accept third byte by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - len = extended_msg[1] - 1; - data = extended_msg + 3; - phase = PHASE_MSGIN; - - NCR5380_transfer_pio(instance, &phase, &len, &data); - EXT_PRINTK("scsi%d: message received, residual %d\n", - HOSTNO, len); - - switch (extended_msg[2]) { - case EXTENDED_SDTR: - case EXTENDED_WDTR: - case EXTENDED_MODIFY_DATA_POINTER: - case EXTENDED_EXTENDED_IDENTIFY: - tmp = 0; - } - } else if (len) { - printk(KERN_NOTICE "scsi%d: error receiving " - "extended message\n", HOSTNO); - tmp = 0; - } else { - printk(KERN_NOTICE "scsi%d: extended message " - "code %02x length %d is too long\n", - HOSTNO, extended_msg[2], extended_msg[1]); - tmp = 0; - } - /* Fall through to reject message */ - - /* - * If we get something weird that we aren't expecting, - * reject it. - */ - default: - if (!tmp) { - printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO); - spi_print_msg(extended_msg); - printk("\n"); - } else if (tmp != EXTENDED_MESSAGE) - printk(KERN_DEBUG "scsi%d: rejecting unknown " - "message %02x from target %d, lun %d\n", - HOSTNO, tmp, cmd->device->id, cmd->device->lun); - else - printk(KERN_DEBUG "scsi%d: rejecting unknown " - "extended message " - "code %02x, length %d from target %d, lun %d\n", - HOSTNO, extended_msg[1], extended_msg[0], - cmd->device->id, cmd->device->lun); - - - msgout = MESSAGE_REJECT; - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | - ICR_ASSERT_ATN); - break; - } /* switch (tmp) */ - break; - case PHASE_MSGOUT: - len = 1; - data = &msgout; - hostdata->last_message = msgout; - NCR5380_transfer_pio(instance, &phase, &len, &data); - if (msgout == ABORT) { -#ifdef SUPPORT_TAGS - cmd_free_tag( cmd ); -#else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); -#endif - hostdata->connected = NULL; - cmd->result = DID_ERROR << 16; -#ifdef NCR5380_STATS - collect_stats(hostdata, cmd); -#endif - cmd->scsi_done(cmd); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - return; - } - msgout = NOP; - break; - case PHASE_CMDOUT: - len = cmd->cmd_len; - data = cmd->cmnd; - /* - * XXX for performance reasons, on machines with a - * PSEUDO-DMA architecture we should probably - * use the dma transfer function. - */ - NCR5380_transfer_pio(instance, &phase, &len, - &data); - break; - case PHASE_STATIN: - len = 1; - data = &tmp; - NCR5380_transfer_pio(instance, &phase, &len, &data); - cmd->SCp.Status = tmp; - break; - default: - printk("scsi%d: unknown phase\n", HOSTNO); - NCR_PRINT(NDEBUG_ANY); - } /* switch(phase) */ - } /* if (tmp * SR_REQ) */ - } /* while (1) */ -} - -/* - * Function : void NCR5380_reselect (struct Scsi_Host *instance) - * - * Purpose : does reselection, initializing the instance->connected - * field to point to the struct scsi_cmnd for which the I_T_L or I_T_L_Q - * nexus has been reestablished, - * - * Inputs : instance - this instance of the NCR5380. - * - */ - -/* it might eventually prove necessary to do a dma setup on - reselection, but it doesn't seem to be needed now -- sam */ - -static void NCR5380_reselect (struct Scsi_Host *instance) -{ - SETUP_HOSTDATA(instance); - unsigned char target_mask; - unsigned char lun; -#ifdef SUPPORT_TAGS - unsigned char tag; -#endif - unsigned char msg[3]; - struct scsi_cmnd *tmp = NULL, *prev; -/* unsigned long flags; */ - - /* - * Disable arbitration, etc. since the host adapter obviously - * lost, and tell an interrupted NCR5380_select() to restart. - */ - - NCR5380_write(MODE_REG, MR_BASE); - hostdata->restart_select = 1; - - target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask); - - RSL_PRINTK("scsi%d: reselect\n", HOSTNO); - - /* - * At this point, we have detected that our SCSI ID is on the bus, - * SEL is true and BSY was false for at least one bus settle delay - * (400 ns). - * - * We must assert BSY ourselves, until the target drops the SEL - * signal. - */ - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY); - - while (NCR5380_read(STATUS_REG) & SR_SEL); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - /* - * Wait for target to go into MSGIN. - */ - - while (!(NCR5380_read(STATUS_REG) & SR_REQ)); - -#if 1 - // acknowledge toggle to MSGIN - NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN)); - - // peek at the byte without really hitting the bus - msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG); -#endif - - if (!(msg[0] & 0x80)) { - printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO); - spi_print_msg(msg); - do_abort(instance); - return; - } - lun = (msg[0] & 0x07); - - /* - * Find the command corresponding to the I_T_L or I_T_L_Q nexus we - * just reestablished, and remove it from the disconnected queue. - */ - - for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL; - tmp; prev = tmp, tmp = NEXT(tmp) ) { - if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun) -#ifdef SUPPORT_TAGS - && (tag == tmp->tag) -#endif - ) { - if (prev) { - REMOVE(prev, NEXT(prev), tmp, NEXT(tmp)); - SET_NEXT(prev, NEXT(tmp)); - } else { - REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp)); - hostdata->disconnected_queue = NEXT(tmp); - } - SET_NEXT(tmp, NULL); - break; - } - } - - if (!tmp) { - printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d " -#ifdef SUPPORT_TAGS - "tag %d " -#endif - "not in disconnected_queue.\n", - HOSTNO, target_mask, lun -#ifdef SUPPORT_TAGS - , tag -#endif - ); - /* - * Since we have an established nexus that we can't do anything - * with, we must abort it. - */ - do_abort(instance); - return; - } -#if 1 - /* engage dma setup for the command we just saw */ - { - void *d; - unsigned long count; - - if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) { - count = tmp->SCp.buffer->length; - d = SGADDR(tmp->SCp.buffer); - } else { - count = tmp->SCp.this_residual; - d = tmp->SCp.ptr; - } -#ifdef REAL_DMA - /* setup this command for dma if not already */ - if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done != tmp)) - { - sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request)); - sun3_dma_setup_done = tmp; - } -#endif - } -#endif - - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK); - /* Accept message by clearing ACK */ - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - -#ifdef SUPPORT_TAGS - /* If the phase is still MSGIN, the target wants to send some more - * messages. In case it supports tagged queuing, this is probably a - * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. - */ - tag = TAG_NONE; - if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { - /* Accept previous IDENTIFY message by clearing ACK */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); - len = 2; - data = msg+1; - if (!NCR5380_transfer_pio(instance, &phase, &len, &data) && - msg[1] == SIMPLE_QUEUE_TAG) - tag = msg[2]; - TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at " - "reselection\n", HOSTNO, target_mask, lun, tag); - } -#endif - - hostdata->connected = tmp; - RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n", - HOSTNO, tmp->target, tmp->lun, tmp->tag); -} - - -/* - * Function : int NCR5380_abort(struct scsi_cmnd *cmd) - * - * Purpose : abort a command - * - * Inputs : cmd - the struct scsi_cmnd to abort, code - code to set the - * host byte of the result field to, if zero DID_ABORTED is - * used. - * - * Returns : 0 - success, -1 on failure. - * - * XXX - there is no way to abort the command that is currently - * connected, you have to wait for it to complete. If this is - * a problem, we could implement longjmp() / setjmp(), setjmp() - * called where the loop started in NCR5380_main(). - */ - -static int NCR5380_abort(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *instance = cmd->device->host; - SETUP_HOSTDATA(instance); - struct scsi_cmnd *tmp, **prev; - unsigned long flags; - - printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO); - scsi_print_command(cmd); - - NCR5380_print_status (instance); - - local_irq_save(flags); - - ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO, - NCR5380_read(BUS_AND_STATUS_REG), - NCR5380_read(STATUS_REG)); - -#if 1 -/* - * Case 1 : If the command is the currently executing command, - * we'll set the aborted flag and return control so that - * information transfer routine can exit cleanly. - */ - - if (hostdata->connected == cmd) { - - ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO); -/* - * We should perform BSY checking, and make sure we haven't slipped - * into BUS FREE. - */ - -/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */ -/* - * Since we can't change phases until we've completed the current - * handshake, we have to source or sink a byte of data if the current - * phase is not MSGOUT. - */ - -/* - * Return control to the executing NCR drive so we can clear the - * aborted flag and get back into our main loop. - */ - - if (do_abort(instance) == 0) { - hostdata->aborted = 1; - hostdata->connected = NULL; - cmd->result = DID_ABORT << 16; -#ifdef SUPPORT_TAGS - cmd_free_tag( cmd ); -#else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); -#endif - local_irq_restore(flags); - cmd->scsi_done(cmd); - return SCSI_ABORT_SUCCESS; - } else { -/* local_irq_restore(flags); */ - printk("scsi%d: abort of connected command failed!\n", HOSTNO); - return SCSI_ABORT_ERROR; - } - } -#endif - -/* - * Case 2 : If the command hasn't been issued yet, we simply remove it - * from the issue queue. - */ - for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue), - tmp = (struct scsi_cmnd *) hostdata->issue_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) - if (cmd == tmp) { - REMOVE(5, *prev, tmp, NEXT(tmp)); - (*prev) = NEXT(tmp); - SET_NEXT(tmp, NULL); - tmp->result = DID_ABORT << 16; - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n", - HOSTNO); - /* Tagged queuing note: no tag to free here, hasn't been assigned - * yet... */ - tmp->scsi_done(tmp); - return SCSI_ABORT_SUCCESS; - } - -/* - * Case 3 : If any commands are connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. - * - * Timeouts, and therefore aborted commands, will be highly unlikely - * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. - */ - - if (hostdata->connected) { - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO); - return SCSI_ABORT_SNOOZE; - } - -/* - * Case 4: If the command is currently disconnected from the bus, and - * there are no connected commands, we reconnect the I_T_L or - * I_T_L_Q nexus associated with it, go into message out, and send - * an abort message. - * - * This case is especially ugly. In order to reestablish the nexus, we - * need to call NCR5380_select(). The easiest way to implement this - * function was to abort if the bus was busy, and let the interrupt - * handler triggered on the SEL for reselect take care of lost arbitrations - * where necessary, meaning interrupts need to be enabled. - * - * When interrupts are enabled, the queues may change - so we - * can't remove it from the disconnected queue before selecting it - * because that could cause a failure in hashing the nexus if that - * device reselected. - * - * Since the queues may change, we can't use the pointers from when we - * first locate it. - * - * So, we must first locate the command, and if NCR5380_select() - * succeeds, then issue the abort, relocate the command and remove - * it from the disconnected queue. - */ - - for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; - tmp = NEXT(tmp)) - if (cmd == tmp) { - local_irq_restore(flags); - ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO); - - if (NCR5380_select (instance, cmd, (int) cmd->tag)) - return SCSI_ABORT_BUSY; - - ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO); - - do_abort (instance); - - local_irq_save(flags); - for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue), - tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; - tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) ) - if (cmd == tmp) { - REMOVE(5, *prev, tmp, NEXT(tmp)); - *prev = NEXT(tmp); - SET_NEXT(tmp, NULL); - tmp->result = DID_ABORT << 16; - /* We must unlock the tag/LUN immediately here, since the - * target goes to BUS FREE and doesn't send us another - * message (COMMAND_COMPLETE or the like) - */ -#ifdef SUPPORT_TAGS - cmd_free_tag( tmp ); -#else - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); -#endif - local_irq_restore(flags); - tmp->scsi_done(tmp); - return SCSI_ABORT_SUCCESS; - } - } - -/* - * Case 5 : If we reached this point, the command was not found in any of - * the queues. - * - * We probably reached this point because of an unlikely race condition - * between the command completing successfully and the abortion code, - * so we won't panic, but we will notify the user in case something really - * broke. - */ - - local_irq_restore(flags); - printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO); - - return SCSI_ABORT_NOT_RUNNING; -} - - -/* - * Function : int NCR5380_bus_reset(struct scsi_cmnd *cmd) - * - * Purpose : reset the SCSI bus. - * - * Returns : SCSI_RESET_WAKEUP - * - */ - -static int NCR5380_bus_reset(struct scsi_cmnd *cmd) -{ - SETUP_HOSTDATA(cmd->device->host); - int i; - unsigned long flags; -#if 1 - struct scsi_cmnd *connected, *disconnected_queue; -#endif - - - NCR5380_print_status (cmd->device->host); - - /* get in phase */ - NCR5380_write( TARGET_COMMAND_REG, - PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); - /* assert RST */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); - udelay (40); - /* reset NCR registers */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); - NCR5380_write( MODE_REG, MR_BASE ); - NCR5380_write( TARGET_COMMAND_REG, 0 ); - NCR5380_write( SELECT_ENABLE_REG, 0 ); - /* ++roman: reset interrupt condition! otherwise no interrupts don't get - * through anymore ... */ - (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - -#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */ - /* XXX see below XXX */ - - /* MSch: old-style reset: actually abort all command processing here */ - - /* After the reset, there are no more connected or disconnected commands - * and no busy units; to avoid problems with re-inserting the commands - * into the issue_queue (via scsi_done()), the aborted commands are - * remembered in local variables first. - */ - local_irq_save(flags); - connected = (struct scsi_cmnd *)hostdata->connected; - hostdata->connected = NULL; - disconnected_queue = (struct scsi_cmnd *)hostdata->disconnected_queue; - hostdata->disconnected_queue = NULL; -#ifdef SUPPORT_TAGS - free_all_tags(); -#endif - for( i = 0; i < 8; ++i ) - hostdata->busy[i] = 0; -#ifdef REAL_DMA - hostdata->dma_len = 0; -#endif - local_irq_restore(flags); - - /* In order to tell the mid-level code which commands were aborted, - * set the command status to DID_RESET and call scsi_done() !!! - * This ultimately aborts processing of these commands in the mid-level. - */ - - if ((cmd = connected)) { - ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); - cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); - cmd->scsi_done( cmd ); - } - - for (i = 0; (cmd = disconnected_queue); ++i) { - disconnected_queue = NEXT(cmd); - SET_NEXT(cmd, NULL); - cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16); - cmd->scsi_done( cmd ); - } - if (i > 0) - ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i); - - - /* since all commands have been explicitly terminated, we need to tell - * the midlevel code that the reset was SUCCESSFUL, and there is no - * need to 'wake up' the commands by a request_sense - */ - return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; -#else /* 1 */ - - /* MSch: new-style reset handling: let the mid-level do what it can */ - - /* ++guenther: MID-LEVEL IS STILL BROKEN. - * Mid-level is supposed to requeue all commands that were active on the - * various low-level queues. In fact it does this, but that's not enough - * because all these commands are subject to timeout. And if a timeout - * happens for any removed command, *_abort() is called but all queues - * are now empty. Abort then gives up the falcon lock, which is fatal, - * since the mid-level will queue more commands and must have the lock - * (it's all happening inside timer interrupt handler!!). - * Even worse, abort will return NOT_RUNNING for all those commands not - * on any queue, so they won't be retried ... - * - * Conclusion: either scsi.c disables timeout for all resetted commands - * immediately, or we lose! As of linux-2.0.20 it doesn't. - */ - - /* After the reset, there are no more connected or disconnected commands - * and no busy units; so clear the low-level status here to avoid - * conflicts when the mid-level code tries to wake up the affected - * commands! - */ - - if (hostdata->issue_queue) - ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd)); - if (hostdata->connected) - ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd)); - if (hostdata->disconnected_queue) - ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd)); - - local_irq_save(flags); - hostdata->issue_queue = NULL; - hostdata->connected = NULL; - hostdata->disconnected_queue = NULL; -#ifdef SUPPORT_TAGS - free_all_tags(); -#endif - for( i = 0; i < 8; ++i ) - hostdata->busy[i] = 0; -#ifdef REAL_DMA - hostdata->dma_len = 0; -#endif - local_irq_restore(flags); - - /* we did no complete reset of all commands, so a wakeup is required */ - return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET; -#endif /* 1 */ -} - -/* Local Variables: */ -/* tab-width: 8 */ -/* End: */ diff --git a/ANDROID_3.4.5/drivers/scsi/sun3_scsi.c b/ANDROID_3.4.5/drivers/scsi/sun3_scsi.c deleted file mode 100644 index 6e25889d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sun3_scsi.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) - * - * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net) - * - * Adapted from mac_scsinew.c: - */ -/* - * Generic Macintosh NCR5380 driver - * - * Copyright 1998, Michael Schmitz - * - * derived in part from: - */ -/* - * Generic Generic NCR5380 driver - * - * Copyright 1995, Russell King - * - * ALPHA RELEASE 1. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - - -/* - * This is from mac_scsi.h, but hey, maybe this is useful for Sun3 too! :) - * - * Options : - * - * PARITY - enable parity checking. Not supported. - * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * - * USLEEP - enable support for devices that don't disconnect. Untested. - */ - -/* - * $Log: sun3_NCR5380.c,v $ - */ - -#define AUTOSENSE - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#define NDEBUG 0 - -#define NDEBUG_ABORT 0x00100000 -#define NDEBUG_TAGS 0x00200000 -#define NDEBUG_MERGING 0x00400000 - -/* dma on! */ -#define REAL_DMA - -#include "scsi.h" -#include "initio.h" -#include -#include "sun3_scsi.h" - -static void NCR5380_print(struct Scsi_Host *instance); - -/* #define OLDDMA */ - -#define USE_WRAPPER -/*#define RESET_BOOT */ -#define DRIVER_SETUP - -/* - * BUG can be used to trigger a strange code-size related hang on 2.1 kernels - */ -#ifdef BUG -#undef RESET_BOOT -#undef DRIVER_SETUP -#endif - -/* #define SUPPORT_TAGS */ - -#define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI ); - - -static irqreturn_t scsi_sun3_intr(int irq, void *dummy); -static inline unsigned char sun3scsi_read(int reg); -static inline void sun3scsi_write(int reg, int value); - -static int setup_can_queue = -1; -module_param(setup_can_queue, int, 0); -static int setup_cmd_per_lun = -1; -module_param(setup_cmd_per_lun, int, 0); -static int setup_sg_tablesize = -1; -module_param(setup_sg_tablesize, int, 0); -#ifdef SUPPORT_TAGS -static int setup_use_tagged_queuing = -1; -module_param(setup_use_tagged_queuing, int, 0); -#endif -static int setup_hostid = -1; -module_param(setup_hostid, int, 0); - -static struct scsi_cmnd *sun3_dma_setup_done = NULL; - -#define AFTER_RESET_DELAY (HZ/2) - -/* ms to wait after hitting dma regs */ -#define SUN3_DMA_DELAY 10 - -/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */ -#define SUN3_DVMA_BUFSIZE 0xe000 - -/* minimum number of bytes to do dma on */ -#define SUN3_DMA_MINSIZE 128 - -static volatile unsigned char *sun3_scsi_regp; -static volatile struct sun3_dma_regs *dregs; -#ifdef OLDDMA -static unsigned char *dmabuf = NULL; /* dma memory buffer */ -#endif -static struct sun3_udc_regs *udc_regs = NULL; -static unsigned char *sun3_dma_orig_addr = NULL; -static unsigned long sun3_dma_orig_count = 0; -static int sun3_dma_active = 0; -static unsigned long last_residual = 0; - -/* - * NCR 5380 register access functions - */ - -static inline unsigned char sun3scsi_read(int reg) -{ - return( sun3_scsi_regp[reg] ); -} - -static inline void sun3scsi_write(int reg, int value) -{ - sun3_scsi_regp[reg] = value; -} - -/* dma controller register access functions */ - -static inline unsigned short sun3_udc_read(unsigned char reg) -{ - unsigned short ret; - - dregs->udc_addr = UDC_CSR; - udelay(SUN3_DMA_DELAY); - ret = dregs->udc_data; - udelay(SUN3_DMA_DELAY); - - return ret; -} - -static inline void sun3_udc_write(unsigned short val, unsigned char reg) -{ - dregs->udc_addr = reg; - udelay(SUN3_DMA_DELAY); - dregs->udc_data = val; - udelay(SUN3_DMA_DELAY); -} - -/* - * XXX: status debug - */ -static struct Scsi_Host *default_instance; - -/* - * Function : int sun3scsi_detect(struct scsi_host_template * tpnt) - * - * Purpose : initializes mac NCR5380 driver based on the - * command line / compile time port and irq definitions. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * - */ - -int __init sun3scsi_detect(struct scsi_host_template * tpnt) -{ - unsigned long ioaddr; - static int called = 0; - struct Scsi_Host *instance; - - /* check that this machine has an onboard 5380 */ - switch(idprom->id_machtype) { - case SM_SUN3|SM_3_50: - case SM_SUN3|SM_3_60: - break; - - default: - return 0; - } - - if(called) - return 0; - - tpnt->proc_name = "Sun3 5380 SCSI"; - - /* setup variables */ - tpnt->can_queue = - (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE; - tpnt->cmd_per_lun = - (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN; - tpnt->sg_tablesize = - (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE; - - if (setup_hostid >= 0) - tpnt->this_id = setup_hostid; - else { - /* use 7 as default */ - tpnt->this_id = 7; - } - - ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE); - sun3_scsi_regp = (unsigned char *)ioaddr; - - dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8); - - if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs))) - == NULL) { - printk("SUN3 Scsi couldn't allocate DVMA memory!\n"); - return 0; - } -#ifdef OLDDMA - if((dmabuf = dvma_malloc_align(SUN3_DVMA_BUFSIZE, 0x10000)) == NULL) { - printk("SUN3 Scsi couldn't allocate DVMA memory!\n"); - return 0; - } -#endif -#ifdef SUPPORT_TAGS - if (setup_use_tagged_queuing < 0) - setup_use_tagged_queuing = USE_TAGGED_QUEUING; -#endif - - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - return 0; - - default_instance = instance; - - instance->io_port = (unsigned long) ioaddr; - instance->irq = IRQ_SUN3_SCSI; - - NCR5380_init(instance, 0); - - instance->n_io_port = 32; - - ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; - - if (request_irq(instance->irq, scsi_sun3_intr, - 0, "Sun3SCSI-5380", instance)) { -#ifndef REAL_DMA - printk("scsi%d: IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = SCSI_IRQ_NONE; -#else - printk("scsi%d: IRQ%d not free, bailing out\n", - instance->host_no, instance->irq); - return 0; -#endif - } - - printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port); - if (instance->irq == SCSI_IRQ_NONE) - printk ("s disabled"); - else - printk (" %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - instance->can_queue, instance->cmd_per_lun, - SUN3SCSI_PUBLIC_RELEASE); - printk("\nscsi%d:", instance->host_no); - NCR5380_print_options(instance); - printk("\n"); - - dregs->csr = 0; - udelay(SUN3_DMA_DELAY); - dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR; - udelay(SUN3_DMA_DELAY); - dregs->fifo_count = 0; - - called = 1; - -#ifdef RESET_BOOT - sun3_scsi_reset_boot(instance); -#endif - - return 1; -} - -int sun3scsi_release (struct Scsi_Host *shpnt) -{ - if (shpnt->irq != SCSI_IRQ_NONE) - free_irq(shpnt->irq, shpnt); - - iounmap((void *)sun3_scsi_regp); - - NCR5380_exit(shpnt); - return 0; -} - -#ifdef RESET_BOOT -/* - * Our 'bus reset on boot' function - */ - -static void sun3_scsi_reset_boot(struct Scsi_Host *instance) -{ - unsigned long end; - - NCR5380_local_declare(); - NCR5380_setup(instance); - - /* - * Do a SCSI reset to clean up the bus during initialization. No - * messing with the queues, interrupts, or locks necessary here. - */ - - printk( "Sun3 SCSI: resetting the SCSI bus..." ); - - /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ -// sun3_disable_irq( IRQ_SUN3_SCSI ); - - /* get in phase */ - NCR5380_write( TARGET_COMMAND_REG, - PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); - - /* assert RST */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); - - /* The min. reset hold time is 25us, so 40us should be enough */ - udelay( 50 ); - - /* reset RST and interrupt */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); - NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - - for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) - barrier(); - - /* switch on SCSI IRQ again */ -// sun3_enable_irq( IRQ_SUN3_SCSI ); - - printk( " done\n" ); -} -#endif - -const char * sun3scsi_info (struct Scsi_Host *spnt) { - return ""; -} - -// safe bits for the CSR -#define CSR_GOOD 0x060f - -static irqreturn_t scsi_sun3_intr(int irq, void *dummy) -{ - unsigned short csr = dregs->csr; - int handled = 0; - - if(csr & ~CSR_GOOD) { - if(csr & CSR_DMA_BUSERR) { - printk("scsi%d: bus error in dma\n", default_instance->host_no); - } - - if(csr & CSR_DMA_CONFLICT) { - printk("scsi%d: dma conflict\n", default_instance->host_no); - } - handled = 1; - } - - if(csr & (CSR_SDB_INT | CSR_DMA_INT)) { - NCR5380_intr(irq, dummy); - handled = 1; - } - - return IRQ_RETVAL(handled); -} - -/* - * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; - * reentering NCR5380_print_status seems to have ugly side effects - */ - -/* this doesn't seem to get used at all -- sam */ -#if 0 -void sun3_sun3_debug (void) -{ - unsigned long flags; - NCR5380_local_declare(); - - if (default_instance) { - local_irq_save(flags); - NCR5380_print_status(default_instance); - local_irq_restore(flags); - } -} -#endif - - -/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */ -static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag) -{ -#ifdef OLDDMA - if(write_flag) - memcpy(dmabuf, data, count); - else { - sun3_dma_orig_addr = data; - sun3_dma_orig_count = count; - } -#else - void *addr; - - if(sun3_dma_orig_addr != NULL) - dvma_unmap(sun3_dma_orig_addr); - -// addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf); - addr = (void *)dvma_map((unsigned long) data, count); - - sun3_dma_orig_addr = addr; - sun3_dma_orig_count = count; -#endif - dregs->fifo_count = 0; - sun3_udc_write(UDC_RESET, UDC_CSR); - - /* reset fifo */ - dregs->csr &= ~CSR_FIFO; - dregs->csr |= CSR_FIFO; - - /* set direction */ - if(write_flag) - dregs->csr |= CSR_SEND; - else - dregs->csr &= ~CSR_SEND; - - /* byte count for fifo */ - dregs->fifo_count = count; - - sun3_udc_write(UDC_RESET, UDC_CSR); - - /* reset fifo */ - dregs->csr &= ~CSR_FIFO; - dregs->csr |= CSR_FIFO; - - if(dregs->fifo_count != count) { - printk("scsi%d: fifo_mismatch %04x not %04x\n", - default_instance->host_no, dregs->fifo_count, - (unsigned int) count); - NCR5380_print(default_instance); - } - - /* setup udc */ -#ifdef OLDDMA - udc_regs->addr_hi = ((dvma_vtob(dmabuf) & 0xff0000) >> 8); - udc_regs->addr_lo = (dvma_vtob(dmabuf) & 0xffff); -#else - udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8); - udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff); -#endif - udc_regs->count = count/2; /* count in words */ - udc_regs->mode_hi = UDC_MODE_HIWORD; - if(write_flag) { - if(count & 1) - udc_regs->count++; - udc_regs->mode_lo = UDC_MODE_LSEND; - udc_regs->rsel = UDC_RSEL_SEND; - } else { - udc_regs->mode_lo = UDC_MODE_LRECV; - udc_regs->rsel = UDC_RSEL_RECV; - } - - /* announce location of regs block */ - sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8), - UDC_CHN_HI); - - sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO); - - /* set dma master on */ - sun3_udc_write(0xd, UDC_MODE); - - /* interrupt enable */ - sun3_udc_write(UDC_INT_ENABLE, UDC_CSR); - - return count; - -} - -static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance) -{ - unsigned short resid; - - dregs->udc_addr = 0x32; - udelay(SUN3_DMA_DELAY); - resid = dregs->udc_data; - udelay(SUN3_DMA_DELAY); - resid *= 2; - - return (unsigned long) resid; -} - -static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) -{ - return last_residual; -} - -static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, - struct scsi_cmnd *cmd, - int write_flag) -{ - if (cmd->request->cmd_type == REQ_TYPE_FS) - return wanted; - else - return 0; -} - -static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data) -{ - - sun3_udc_write(UDC_CHN_START, UDC_CSR); - - return 0; -} - -/* clean up after our dma is done */ -static int sun3scsi_dma_finish(int write_flag) -{ - unsigned short count; - unsigned short fifo; - int ret = 0; - - sun3_dma_active = 0; -#if 1 - // check to empty the fifo on a read - if(!write_flag) { - int tmo = 20000; /* .2 sec */ - - while(1) { - if(dregs->csr & CSR_FIFO_EMPTY) - break; - - if(--tmo <= 0) { - printk("sun3scsi: fifo failed to empty!\n"); - return 1; - } - udelay(10); - } - } - -#endif - - count = sun3scsi_dma_count(default_instance); -#ifdef OLDDMA - - /* if we've finished a read, copy out the data we read */ - if(sun3_dma_orig_addr) { - /* check for residual bytes after dma end */ - if(count && (NCR5380_read(BUS_AND_STATUS_REG) & - (BASR_PHASE_MATCH | BASR_ACK))) { - printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no); - printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG)); - ret = count; - } - - /* copy in what we dma'd no matter what */ - memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count); - sun3_dma_orig_addr = NULL; - - } -#else - - fifo = dregs->fifo_count; - last_residual = fifo; - - /* empty bytes from the fifo which didn't make it */ - if((!write_flag) && (count - fifo) == 2) { - unsigned short data; - unsigned char *vaddr; - - data = dregs->fifo_data; - vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr); - - vaddr += (sun3_dma_orig_count - fifo); - - vaddr[-2] = (data & 0xff00) >> 8; - vaddr[-1] = (data & 0xff); - } - - dvma_unmap(sun3_dma_orig_addr); - sun3_dma_orig_addr = NULL; -#endif - sun3_udc_write(UDC_RESET, UDC_CSR); - dregs->fifo_count = 0; - dregs->csr &= ~CSR_SEND; - - /* reset fifo */ - dregs->csr &= ~CSR_FIFO; - dregs->csr |= CSR_FIFO; - - sun3_dma_setup_done = NULL; - - return ret; - -} - -#include "sun3_NCR5380.c" - -static struct scsi_host_template driver_template = { - .name = SUN3_SCSI_NAME, - .detect = sun3scsi_detect, - .release = sun3scsi_release, - .info = sun3scsi_info, - .queuecommand = sun3scsi_queue_command, - .eh_abort_handler = sun3scsi_abort, - .eh_bus_reset_handler = sun3scsi_bus_reset, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_TABLESIZE, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/sun3_scsi.h b/ANDROID_3.4.5/drivers/scsi/sun3_scsi.h deleted file mode 100644 index bcefd845..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sun3_scsi.h +++ /dev/null @@ -1,379 +0,0 @@ -/* - * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) - * - * Sun3 DMA additions by Sam Creasey (sammy@sammy.net) - * - * Adapted from mac_scsinew.h: - */ -/* - * Cumana Generic NCR5380 driver defines - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * ALPHA RELEASE 1. - * - * For more information, please consult - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * $Log: cumana_NCR5380.h,v $ - */ - -#ifndef SUN3_NCR5380_H -#define SUN3_NCR5380_H - -#define SUN3SCSI_PUBLIC_RELEASE 1 - -/* - * Int: level 2 autovector - * IO: type 1, base 0x00140000, 5 bits phys space: A<4..0> - */ -#define IRQ_SUN3_SCSI 2 -#define IOBASE_SUN3_SCSI 0x00140000 - -#define IOBASE_SUN3_VMESCSI 0xff200000 - -static int sun3scsi_abort(struct scsi_cmnd *); -static int sun3scsi_detect (struct scsi_host_template *); -static const char *sun3scsi_info (struct Scsi_Host *); -static int sun3scsi_bus_reset(struct scsi_cmnd *); -static int sun3scsi_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static int sun3scsi_release (struct Scsi_Host *); - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 16 -#endif - -#ifndef SG_TABLESIZE -#define SG_TABLESIZE SG_NONE -#endif - -#ifndef MAX_TAGS -#define MAX_TAGS 32 -#endif - -#ifndef USE_TAGGED_QUEUING -#define USE_TAGGED_QUEUING 1 -#endif - -#include - -#ifdef SUN3_SCSI_VME -#define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI" -#else -#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI" -#endif - -#ifndef HOSTS_C - -#define NCR5380_implementation_fields \ - int port, ctrl - -#define NCR5380_local_declare() \ - struct Scsi_Host *_instance - -#define NCR5380_setup(instance) \ - _instance = instance - -#define NCR5380_read(reg) sun3scsi_read(reg) -#define NCR5380_write(reg, value) sun3scsi_write(reg, value) - -#define NCR5380_intr sun3scsi_intr -#define NCR5380_queue_command sun3scsi_queue_command -#define NCR5380_bus_reset sun3scsi_bus_reset -#define NCR5380_abort sun3scsi_abort -#define NCR5380_proc_info sun3scsi_proc_info -#define NCR5380_dma_xfer_len(i, cmd, phase) \ - sun3scsi_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1) - -#define NCR5380_dma_write_setup(instance, data, count) sun3scsi_dma_setup(data, count, 1) -#define NCR5380_dma_read_setup(instance, data, count) sun3scsi_dma_setup(data, count, 0) -#define NCR5380_dma_residual sun3scsi_dma_residual - -#define BOARD_NORMAL 0 -#define BOARD_NCR53C400 1 - -/* additional registers - mainly DMA control regs */ -/* these start at regbase + 8 -- directly after the NCR regs */ -struct sun3_dma_regs { - unsigned short dma_addr_hi; /* vme only */ - unsigned short dma_addr_lo; /* vme only */ - unsigned short dma_count_hi; /* vme only */ - unsigned short dma_count_lo; /* vme only */ - unsigned short udc_data; /* udc dma data reg (obio only) */ - unsigned short udc_addr; /* uda dma addr reg (obio only) */ - unsigned short fifo_data; /* fifo data reg, holds extra byte on - odd dma reads */ - unsigned short fifo_count; - unsigned short csr; /* control/status reg */ - unsigned short bpack_hi; /* vme only */ - unsigned short bpack_lo; /* vme only */ - unsigned short ivect; /* vme only */ - unsigned short fifo_count_hi; /* vme only */ -}; - -/* ucd chip specific regs - live in dvma space */ -struct sun3_udc_regs { - unsigned short rsel; /* select regs to load */ - unsigned short addr_hi; /* high word of addr */ - unsigned short addr_lo; /* low word */ - unsigned short count; /* words to be xfer'd */ - unsigned short mode_hi; /* high word of channel mode */ - unsigned short mode_lo; /* low word of channel mode */ -}; - -/* addresses of the udc registers */ -#define UDC_MODE 0x38 -#define UDC_CSR 0x2e /* command/status */ -#define UDC_CHN_HI 0x26 /* chain high word */ -#define UDC_CHN_LO 0x22 /* chain lo word */ -#define UDC_CURA_HI 0x1a /* cur reg A high */ -#define UDC_CURA_LO 0x0a /* cur reg A low */ -#define UDC_CURB_HI 0x12 /* cur reg B high */ -#define UDC_CURB_LO 0x02 /* cur reg B low */ -#define UDC_MODE_HI 0x56 /* mode reg high */ -#define UDC_MODE_LO 0x52 /* mode reg low */ -#define UDC_COUNT 0x32 /* words to xfer */ - -/* some udc commands */ -#define UDC_RESET 0 -#define UDC_CHN_START 0xa0 /* start chain */ -#define UDC_INT_ENABLE 0x32 /* channel 1 int on */ - -/* udc mode words */ -#define UDC_MODE_HIWORD 0x40 -#define UDC_MODE_LSEND 0xc2 -#define UDC_MODE_LRECV 0xd2 - -/* udc reg selections */ -#define UDC_RSEL_SEND 0x282 -#define UDC_RSEL_RECV 0x182 - -/* bits in csr reg */ -#define CSR_DMA_ACTIVE 0x8000 -#define CSR_DMA_CONFLICT 0x4000 -#define CSR_DMA_BUSERR 0x2000 - -#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */ -#define CSR_SDB_INT 0x200 /* sbc interrupt pending */ -#define CSR_DMA_INT 0x100 /* dma interrupt pending */ - -#define CSR_LEFT 0xc0 -#define CSR_LEFT_3 0xc0 -#define CSR_LEFT_2 0x80 -#define CSR_LEFT_1 0x40 -#define CSR_PACK_ENABLE 0x20 - -#define CSR_DMA_ENABLE 0x10 - -#define CSR_SEND 0x8 /* 1 = send 0 = recv */ -#define CSR_FIFO 0x2 /* reset fifo */ -#define CSR_INTR 0x4 /* interrupt enable */ -#define CSR_SCSI 0x1 - -#define VME_DATA24 0x3d00 - -// debugging printk's, taken from atari_scsi.h -/* Debugging printk definitions: - * - * ARB -> arbitration - * ASEN -> auto-sense - * DMA -> DMA - * HSH -> PIO handshake - * INF -> information transfer - * INI -> initialization - * INT -> interrupt - * LNK -> linked commands - * MAIN -> NCR5380_main() control flow - * NDAT -> no data-out phase - * NWR -> no write commands - * PIO -> PIO transfers - * PDMA -> pseudo DMA (unused on Atari) - * QU -> queues - * RSL -> reselections - * SEL -> selections - * USL -> usleep cpde (unused on Atari) - * LBS -> last byte sent (unused on Atari) - * RSS -> restarting of selections - * EXT -> extended messages - * ABRT -> aborting and resetting - * TAG -> queue tag handling - * MER -> merging of consec. buffers - * - */ - -#include "NCR5380.h" - -#if NDEBUG & NDEBUG_ARBITRATION -#define ARB_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define ARB_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_AUTOSENSE -#define ASEN_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define ASEN_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_DMA -#define DMA_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define DMA_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_HANDSHAKE -#define HSH_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define HSH_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_INFORMATION -#define INF_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define INF_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_INIT -#define INI_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define INI_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_INTR -#define INT_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define INT_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_LINKED -#define LNK_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define LNK_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_MAIN -#define MAIN_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define MAIN_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_NO_DATAOUT -#define NDAT_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define NDAT_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_NO_WRITE -#define NWR_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define NWR_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_PIO -#define PIO_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define PIO_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_PSEUDO_DMA -#define PDMA_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define PDMA_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_QUEUES -#define QU_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define QU_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_RESELECTION -#define RSL_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define RSL_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_SELECTION -#define SEL_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define SEL_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_USLEEP -#define USL_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define USL_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_LAST_BYTE_SENT -#define LBS_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define LBS_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_RESTART_SELECT -#define RSS_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define RSS_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_EXTENDED -#define EXT_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define EXT_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_ABORT -#define ABRT_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define ABRT_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_TAGS -#define TAG_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define TAG_PRINTK(format, args...) -#endif -#if NDEBUG & NDEBUG_MERGING -#define MER_PRINTK(format, args...) \ - printk(KERN_DEBUG format , ## args) -#else -#define MER_PRINTK(format, args...) -#endif - -/* conditional macros for NCR5380_print_{,phase,status} */ - -#define NCR_PRINT(mask) \ - ((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0) - -#define NCR_PRINT_PHASE(mask) \ - ((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0) - -#define NCR_PRINT_STATUS(mask) \ - ((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0) - - - -#endif /* ndef HOSTS_C */ -#endif /* SUN3_NCR5380_H */ - diff --git a/ANDROID_3.4.5/drivers/scsi/sun3_scsi_vme.c b/ANDROID_3.4.5/drivers/scsi/sun3_scsi_vme.c deleted file mode 100644 index a3dd55d1..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sun3_scsi_vme.c +++ /dev/null @@ -1,589 +0,0 @@ - /* - * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl) - * - * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net) - * - * VME support added by Sam Creasey - * - * Adapted from sun3_scsi.c -- see there for other headers - * - * TODO: modify this driver to support multiple Sun3 SCSI VME boards - * - */ - -#define AUTOSENSE - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -#define SUN3_SCSI_VME - -#undef SUN3_SCSI_DEBUG - -/* dma on! */ -#define REAL_DMA - -#define NDEBUG 0 - -#define NDEBUG_ABORT 0x00100000 -#define NDEBUG_TAGS 0x00200000 -#define NDEBUG_MERGING 0x00400000 - -#include "scsi.h" -#include "initio.h" -#include -#include "sun3_scsi.h" - -extern int sun3_map_test(unsigned long, char *); - -#define USE_WRAPPER -/*#define RESET_BOOT */ -#define DRIVER_SETUP - -/* - * BUG can be used to trigger a strange code-size related hang on 2.1 kernels - */ -#ifdef BUG -#undef RESET_BOOT -#undef DRIVER_SETUP -#endif - -/* #define SUPPORT_TAGS */ - -//#define ENABLE_IRQ() enable_irq( SUN3_VEC_VMESCSI0 ); -#define ENABLE_IRQ() - - -static irqreturn_t scsi_sun3_intr(int irq, void *dummy); -static inline unsigned char sun3scsi_read(int reg); -static inline void sun3scsi_write(int reg, int value); - -static int setup_can_queue = -1; -module_param(setup_can_queue, int, 0); -static int setup_cmd_per_lun = -1; -module_param(setup_cmd_per_lun, int, 0); -static int setup_sg_tablesize = -1; -module_param(setup_sg_tablesize, int, 0); -#ifdef SUPPORT_TAGS -static int setup_use_tagged_queuing = -1; -module_param(setup_use_tagged_queuing, int, 0); -#endif -static int setup_hostid = -1; -module_param(setup_hostid, int, 0); - -static struct scsi_cmnd *sun3_dma_setup_done = NULL; - -#define AFTER_RESET_DELAY (HZ/2) - -/* ms to wait after hitting dma regs */ -#define SUN3_DMA_DELAY 10 - -/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */ -#define SUN3_DVMA_BUFSIZE 0xe000 - -/* minimum number of bytes to do dma on */ -#define SUN3_DMA_MINSIZE 128 - -static volatile unsigned char *sun3_scsi_regp; -static volatile struct sun3_dma_regs *dregs; -#ifdef OLDDMA -static unsigned char *dmabuf = NULL; /* dma memory buffer */ -#endif -static unsigned char *sun3_dma_orig_addr = NULL; -static unsigned long sun3_dma_orig_count = 0; -static int sun3_dma_active = 0; -static unsigned long last_residual = 0; - -/* - * NCR 5380 register access functions - */ - -static inline unsigned char sun3scsi_read(int reg) -{ - return( sun3_scsi_regp[reg] ); -} - -static inline void sun3scsi_write(int reg, int value) -{ - sun3_scsi_regp[reg] = value; -} - -/* - * XXX: status debug - */ -static struct Scsi_Host *default_instance; - -/* - * Function : int sun3scsi_detect(struct scsi_host_template * tpnt) - * - * Purpose : initializes mac NCR5380 driver based on the - * command line / compile time port and irq definitions. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * - */ - -static int __init sun3scsi_detect(struct scsi_host_template * tpnt) -{ - unsigned long ioaddr, irq = 0; - static int called = 0; - struct Scsi_Host *instance; - int i; - unsigned long addrs[3] = { IOBASE_SUN3_VMESCSI, - IOBASE_SUN3_VMESCSI + 0x4000, - 0 }; - unsigned long vecs[3] = { SUN3_VEC_VMESCSI0, - SUN3_VEC_VMESCSI1, - 0 }; - /* check that this machine has an onboard 5380 */ - switch(idprom->id_machtype) { - case SM_SUN3|SM_3_160: - case SM_SUN3|SM_3_260: - break; - - default: - return 0; - } - - if(called) - return 0; - - tpnt->proc_name = "Sun3 5380 VME SCSI"; - - /* setup variables */ - tpnt->can_queue = - (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE; - tpnt->cmd_per_lun = - (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN; - tpnt->sg_tablesize = - (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE; - - if (setup_hostid >= 0) - tpnt->this_id = setup_hostid; - else { - /* use 7 as default */ - tpnt->this_id = 7; - } - - ioaddr = 0; - for(i = 0; addrs[i] != 0; i++) { - unsigned char x; - - ioaddr = (unsigned long)sun3_ioremap(addrs[i], PAGE_SIZE, - SUN3_PAGE_TYPE_VME16); - irq = vecs[i]; - sun3_scsi_regp = (unsigned char *)ioaddr; - - dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8); - - if(sun3_map_test((unsigned long)dregs, &x)) { - unsigned short oldcsr; - - oldcsr = dregs->csr; - dregs->csr = 0; - udelay(SUN3_DMA_DELAY); - if(dregs->csr == 0x1400) - break; - - dregs->csr = oldcsr; - } - - iounmap((void *)ioaddr); - ioaddr = 0; - } - - if(!ioaddr) - return 0; - -#ifdef SUPPORT_TAGS - if (setup_use_tagged_queuing < 0) - setup_use_tagged_queuing = USE_TAGGED_QUEUING; -#endif - - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - return 0; - - default_instance = instance; - - instance->io_port = (unsigned long) ioaddr; - instance->irq = irq; - - NCR5380_init(instance, 0); - - instance->n_io_port = 32; - - ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0; - - if (request_irq(instance->irq, scsi_sun3_intr, - 0, "Sun3SCSI-5380VME", instance)) { -#ifndef REAL_DMA - printk("scsi%d: IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = SCSI_IRQ_NONE; -#else - printk("scsi%d: IRQ%d not free, bailing out\n", - instance->host_no, instance->irq); - return 0; -#endif - } - - printk("scsi%d: Sun3 5380 VME at port %lX irq", instance->host_no, instance->io_port); - if (instance->irq == SCSI_IRQ_NONE) - printk ("s disabled"); - else - printk (" %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - instance->can_queue, instance->cmd_per_lun, - SUN3SCSI_PUBLIC_RELEASE); - printk("\nscsi%d:", instance->host_no); - NCR5380_print_options(instance); - printk("\n"); - - dregs->csr = 0; - udelay(SUN3_DMA_DELAY); - dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR; - udelay(SUN3_DMA_DELAY); - dregs->fifo_count = 0; - dregs->fifo_count_hi = 0; - dregs->dma_addr_hi = 0; - dregs->dma_addr_lo = 0; - dregs->dma_count_hi = 0; - dregs->dma_count_lo = 0; - - dregs->ivect = VME_DATA24 | (instance->irq & 0xff); - - called = 1; - -#ifdef RESET_BOOT - sun3_scsi_reset_boot(instance); -#endif - - return 1; -} - -int sun3scsi_release (struct Scsi_Host *shpnt) -{ - if (shpnt->irq != SCSI_IRQ_NONE) - free_irq(shpnt->irq, shpnt); - - iounmap((void *)sun3_scsi_regp); - - NCR5380_exit(shpnt); - return 0; -} - -#ifdef RESET_BOOT -/* - * Our 'bus reset on boot' function - */ - -static void sun3_scsi_reset_boot(struct Scsi_Host *instance) -{ - unsigned long end; - - NCR5380_local_declare(); - NCR5380_setup(instance); - - /* - * Do a SCSI reset to clean up the bus during initialization. No - * messing with the queues, interrupts, or locks necessary here. - */ - - printk( "Sun3 SCSI: resetting the SCSI bus..." ); - - /* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */ -// sun3_disable_irq( IRQ_SUN3_SCSI ); - - /* get in phase */ - NCR5380_write( TARGET_COMMAND_REG, - PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) )); - - /* assert RST */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST ); - - /* The min. reset hold time is 25us, so 40us should be enough */ - udelay( 50 ); - - /* reset RST and interrupt */ - NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE ); - NCR5380_read( RESET_PARITY_INTERRUPT_REG ); - - for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); ) - barrier(); - - /* switch on SCSI IRQ again */ -// sun3_enable_irq( IRQ_SUN3_SCSI ); - - printk( " done\n" ); -} -#endif - -static const char * sun3scsi_info (struct Scsi_Host *spnt) { - return ""; -} - -// safe bits for the CSR -#define CSR_GOOD 0x060f - -static irqreturn_t scsi_sun3_intr(int irq, void *dummy) -{ - unsigned short csr = dregs->csr; - int handled = 0; - - dregs->csr &= ~CSR_DMA_ENABLE; - - -#ifdef SUN3_SCSI_DEBUG - printk("scsi_intr csr %x\n", csr); -#endif - - if(csr & ~CSR_GOOD) { - if(csr & CSR_DMA_BUSERR) { - printk("scsi%d: bus error in dma\n", default_instance->host_no); -#ifdef SUN3_SCSI_DEBUG - printk("scsi: residual %x count %x addr %p dmaaddr %x\n", - dregs->fifo_count, - dregs->dma_count_lo | (dregs->dma_count_hi << 16), - sun3_dma_orig_addr, - dregs->dma_addr_lo | (dregs->dma_addr_hi << 16)); -#endif - } - - if(csr & CSR_DMA_CONFLICT) { - printk("scsi%d: dma conflict\n", default_instance->host_no); - } - handled = 1; - } - - if(csr & (CSR_SDB_INT | CSR_DMA_INT)) { - NCR5380_intr(irq, dummy); - handled = 1; - } - - return IRQ_RETVAL(handled); -} - -/* - * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; - * reentering NCR5380_print_status seems to have ugly side effects - */ - -/* this doesn't seem to get used at all -- sam */ -#if 0 -void sun3_sun3_debug (void) -{ - unsigned long flags; - NCR5380_local_declare(); - - if (default_instance) { - local_irq_save(flags); - NCR5380_print_status(default_instance); - local_irq_restore(flags); - } -} -#endif - - -/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */ -static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag) -{ - void *addr; - - if(sun3_dma_orig_addr != NULL) - dvma_unmap(sun3_dma_orig_addr); - -// addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf); - addr = (void *)dvma_map_vme((unsigned long) data, count); - - sun3_dma_orig_addr = addr; - sun3_dma_orig_count = count; - -#ifdef SUN3_SCSI_DEBUG - printk("scsi: dma_setup addr %p count %x\n", addr, count); -#endif - -// dregs->fifo_count = 0; -#if 0 - /* reset fifo */ - dregs->csr &= ~CSR_FIFO; - dregs->csr |= CSR_FIFO; -#endif - /* set direction */ - if(write_flag) - dregs->csr |= CSR_SEND; - else - dregs->csr &= ~CSR_SEND; - - /* reset fifo */ -// dregs->csr &= ~CSR_FIFO; -// dregs->csr |= CSR_FIFO; - - dregs->csr |= CSR_PACK_ENABLE; - - dregs->dma_addr_hi = ((unsigned long)addr >> 16); - dregs->dma_addr_lo = ((unsigned long)addr & 0xffff); - - dregs->dma_count_hi = 0; - dregs->dma_count_lo = 0; - dregs->fifo_count_hi = 0; - dregs->fifo_count = 0; - -#ifdef SUN3_SCSI_DEBUG - printk("scsi: dma_setup done csr %x\n", dregs->csr); -#endif - return count; - -} - -static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance) -{ - return last_residual; -} - -static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, - struct scsi_cmnd *cmd, - int write_flag) -{ - if (cmd->request->cmd_type == REQ_TYPE_FS) - return wanted; - else - return 0; -} - -static int sun3scsi_dma_start(unsigned long count, char *data) -{ - - unsigned short csr; - - csr = dregs->csr; -#ifdef SUN3_SCSI_DEBUG - printk("scsi: dma_start data %p count %x csr %x fifo %x\n", data, count, csr, dregs->fifo_count); -#endif - - dregs->dma_count_hi = (sun3_dma_orig_count >> 16); - dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff); - - dregs->fifo_count_hi = (sun3_dma_orig_count >> 16); - dregs->fifo_count = (sun3_dma_orig_count & 0xffff); - -// if(!(csr & CSR_DMA_ENABLE)) -// dregs->csr |= CSR_DMA_ENABLE; - - return 0; -} - -/* clean up after our dma is done */ -static int sun3scsi_dma_finish(int write_flag) -{ - unsigned short fifo; - int ret = 0; - - sun3_dma_active = 0; - - dregs->csr &= ~CSR_DMA_ENABLE; - - fifo = dregs->fifo_count; - if(write_flag) { - if((fifo > 0) && (fifo < sun3_dma_orig_count)) - fifo++; - } - - last_residual = fifo; -#ifdef SUN3_SCSI_DEBUG - printk("scsi: residual %x total %x\n", fifo, sun3_dma_orig_count); -#endif - /* empty bytes from the fifo which didn't make it */ - if((!write_flag) && (dregs->csr & CSR_LEFT)) { - unsigned char *vaddr; - -#ifdef SUN3_SCSI_DEBUG - printk("scsi: got left over bytes\n"); -#endif - - vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr); - - vaddr += (sun3_dma_orig_count - fifo); - vaddr--; - - switch(dregs->csr & CSR_LEFT) { - case CSR_LEFT_3: - *vaddr = (dregs->bpack_lo & 0xff00) >> 8; - vaddr--; - - case CSR_LEFT_2: - *vaddr = (dregs->bpack_hi & 0x00ff); - vaddr--; - - case CSR_LEFT_1: - *vaddr = (dregs->bpack_hi & 0xff00) >> 8; - break; - } - - - } - - dvma_unmap(sun3_dma_orig_addr); - sun3_dma_orig_addr = NULL; - - dregs->dma_addr_hi = 0; - dregs->dma_addr_lo = 0; - dregs->dma_count_hi = 0; - dregs->dma_count_lo = 0; - - dregs->fifo_count = 0; - dregs->fifo_count_hi = 0; - - dregs->csr &= ~CSR_SEND; - -// dregs->csr |= CSR_DMA_ENABLE; - -#if 0 - /* reset fifo */ - dregs->csr &= ~CSR_FIFO; - dregs->csr |= CSR_FIFO; -#endif - sun3_dma_setup_done = NULL; - - return ret; - -} - -#include "sun3_NCR5380.c" - -static struct scsi_host_template driver_template = { - .name = SUN3_SCSI_NAME, - .detect = sun3scsi_detect, - .release = sun3scsi_release, - .info = sun3scsi_info, - .queuecommand = sun3scsi_queue_command, - .eh_abort_handler = sun3scsi_abort, - .eh_bus_reset_handler = sun3scsi_bus_reset, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_TABLESIZE, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING -}; - - -#include "scsi_module.c" - -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/sun3x_esp.c b/ANDROID_3.4.5/drivers/scsi/sun3x_esp.c deleted file mode 100644 index 0621037f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sun3x_esp.c +++ /dev/null @@ -1,319 +0,0 @@ -/* sun3x_esp.c: ESP front-end for Sun3x systems. - * - * Copyright (C) 2007,2008 Thomas Bogendoerfer (tsbogend@alpha.franken.de) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* DMA controller reg offsets */ -#define DMA_CSR 0x00UL /* rw DMA control/status register 0x00 */ -#define DMA_ADDR 0x04UL /* rw DMA transfer address register 0x04 */ -#define DMA_COUNT 0x08UL /* rw DMA transfer count register 0x08 */ -#define DMA_TEST 0x0cUL /* rw DMA test/debug register 0x0c */ - -#include - -#include "esp_scsi.h" - -#define DRV_MODULE_NAME "sun3x_esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.000" -#define DRV_MODULE_RELDATE "Nov 1, 2007" - -/* - * m68k always assumes readl/writel operate on little endian - * mmio space; this is wrong at least for Sun3x, so we - * need to workaround this until a proper way is found - */ -#if 0 -#define dma_read32(REG) \ - readl(esp->dma_regs + (REG)) -#define dma_write32(VAL, REG) \ - writel((VAL), esp->dma_regs + (REG)) -#else -#define dma_read32(REG) \ - *(volatile u32 *)(esp->dma_regs + (REG)) -#define dma_write32(VAL, REG) \ - do { *(volatile u32 *)(esp->dma_regs + (REG)) = (VAL); } while (0) -#endif - -static void sun3x_esp_write8(struct esp *esp, u8 val, unsigned long reg) -{ - writeb(val, esp->regs + (reg * 4UL)); -} - -static u8 sun3x_esp_read8(struct esp *esp, unsigned long reg) -{ - return readb(esp->regs + (reg * 4UL)); -} - -static dma_addr_t sun3x_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - return dma_map_single(esp->dev, buf, sz, dir); -} - -static int sun3x_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - return dma_map_sg(esp->dev, sg, num_sg, dir); -} - -static void sun3x_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - dma_unmap_single(esp->dev, addr, sz, dir); -} - -static void sun3x_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - dma_unmap_sg(esp->dev, sg, num_sg, dir); -} - -static int sun3x_esp_irq_pending(struct esp *esp) -{ - if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) - return 1; - return 0; -} - -static void sun3x_esp_reset_dma(struct esp *esp) -{ - u32 val; - - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_RST_SCSI, DMA_CSR); - dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); - - /* Enable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_INT_ENAB, DMA_CSR); -} - -static void sun3x_esp_dma_drain(struct esp *esp) -{ - u32 csr; - int lim; - - csr = dma_read32(DMA_CSR); - if (!(csr & DMA_FIFO_ISDRAIN)) - return; - - dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); - - lim = 1000; - while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", - esp->host->unique_id); - break; - } - udelay(1); - } -} - -static void sun3x_esp_dma_invalidate(struct esp *esp) -{ - u32 val; - int lim; - - lim = 1000; - while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not " - "invalidate!\n", esp->host->unique_id); - break; - } - udelay(1); - } - - val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); - val |= DMA_FIFO_INV; - dma_write32(val, DMA_CSR); - val &= ~DMA_FIFO_INV; - dma_write32(val, DMA_CSR); -} - -static void sun3x_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) -{ - u32 csr; - - BUG_ON(!(cmd & ESP_CMD_DMA)); - - sun3x_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); - sun3x_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - csr = dma_read32(DMA_CSR); - csr |= DMA_ENABLE; - if (write) - csr |= DMA_ST_WRITE; - else - csr &= ~DMA_ST_WRITE; - dma_write32(csr, DMA_CSR); - dma_write32(addr, DMA_ADDR); - - scsi_esp_cmd(esp, cmd); -} - -static int sun3x_esp_dma_error(struct esp *esp) -{ - u32 csr = dma_read32(DMA_CSR); - - if (csr & DMA_HNDL_ERROR) - return 1; - - return 0; -} - -static const struct esp_driver_ops sun3x_esp_ops = { - .esp_write8 = sun3x_esp_write8, - .esp_read8 = sun3x_esp_read8, - .map_single = sun3x_esp_map_single, - .map_sg = sun3x_esp_map_sg, - .unmap_single = sun3x_esp_unmap_single, - .unmap_sg = sun3x_esp_unmap_sg, - .irq_pending = sun3x_esp_irq_pending, - .reset_dma = sun3x_esp_reset_dma, - .dma_drain = sun3x_esp_dma_drain, - .dma_invalidate = sun3x_esp_dma_invalidate, - .send_dma_cmd = sun3x_esp_send_dma_cmd, - .dma_error = sun3x_esp_dma_error, -}; - -static int __devinit esp_sun3x_probe(struct platform_device *dev) -{ - struct scsi_host_template *tpnt = &scsi_esp_template; - struct Scsi_Host *host; - struct esp *esp; - struct resource *res; - int err = -ENOMEM; - - host = scsi_host_alloc(tpnt, sizeof(struct esp)); - if (!host) - goto fail; - - host->max_id = 8; - esp = shost_priv(host); - - esp->host = host; - esp->dev = dev; - esp->ops = &sun3x_esp_ops; - - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - if (!res || !res->start) - goto fail_unlink; - - esp->regs = ioremap_nocache(res->start, 0x20); - if (!esp->regs) - goto fail_unmap_regs; - - res = platform_get_resource(dev, IORESOURCE_MEM, 1); - if (!res || !res->start) - goto fail_unmap_regs; - - esp->dma_regs = ioremap_nocache(res->start, 0x10); - - esp->command_block = dma_alloc_coherent(esp->dev, 16, - &esp->command_block_dma, - GFP_KERNEL); - if (!esp->command_block) - goto fail_unmap_regs_dma; - - host->irq = platform_get_irq(dev, 0); - err = request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, - "SUN3X ESP", esp); - if (err < 0) - goto fail_unmap_command_block; - - esp->scsi_id = 7; - esp->host->this_id = esp->scsi_id; - esp->scsi_id_mask = (1 << esp->scsi_id); - esp->cfreq = 20000000; - - dev_set_drvdata(&dev->dev, esp); - - err = scsi_esp_register(esp, &dev->dev); - if (err) - goto fail_free_irq; - - return 0; - -fail_free_irq: - free_irq(host->irq, esp); -fail_unmap_command_block: - dma_free_coherent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); -fail_unmap_regs_dma: - iounmap(esp->dma_regs); -fail_unmap_regs: - iounmap(esp->regs); -fail_unlink: - scsi_host_put(host); -fail: - return err; -} - -static int __devexit esp_sun3x_remove(struct platform_device *dev) -{ - struct esp *esp = dev_get_drvdata(&dev->dev); - unsigned int irq = esp->host->irq; - u32 val; - - scsi_esp_unregister(esp); - - /* Disable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); - - free_irq(irq, esp); - dma_free_coherent(esp->dev, 16, - esp->command_block, - esp->command_block_dma); - - scsi_host_put(esp->host); - - return 0; -} - -static struct platform_driver esp_sun3x_driver = { - .probe = esp_sun3x_probe, - .remove = __devexit_p(esp_sun3x_remove), - .driver = { - .name = "sun3x_esp", - .owner = THIS_MODULE, - }, -}; - -static int __init sun3x_esp_init(void) -{ - return platform_driver_register(&esp_sun3x_driver); -} - -static void __exit sun3x_esp_exit(void) -{ - platform_driver_unregister(&esp_sun3x_driver); -} - -MODULE_DESCRIPTION("Sun3x ESP SCSI driver"); -MODULE_AUTHOR("Thomas Bogendoerfer (tsbogend@alpha.franken.de)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -module_init(sun3x_esp_init); -module_exit(sun3x_esp_exit); -MODULE_ALIAS("platform:sun3x_esp"); diff --git a/ANDROID_3.4.5/drivers/scsi/sun_esp.c b/ANDROID_3.4.5/drivers/scsi/sun_esp.c deleted file mode 100644 index 676fe9ac..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sun_esp.c +++ /dev/null @@ -1,661 +0,0 @@ -/* sun_esp.c: ESP front-end for Sparc SBUS systems. - * - * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "esp_scsi.h" - -#define DRV_MODULE_NAME "sun_esp" -#define PFX DRV_MODULE_NAME ": " -#define DRV_VERSION "1.100" -#define DRV_MODULE_RELDATE "August 27, 2008" - -#define dma_read32(REG) \ - sbus_readl(esp->dma_regs + (REG)) -#define dma_write32(VAL, REG) \ - sbus_writel((VAL), esp->dma_regs + (REG)) - -/* DVMA chip revisions */ -enum dvma_rev { - dvmarev0, - dvmaesc1, - dvmarev1, - dvmarev2, - dvmarev3, - dvmarevplus, - dvmahme -}; - -static int __devinit esp_sbus_setup_dma(struct esp *esp, - struct platform_device *dma_of) -{ - esp->dma = dma_of; - - esp->dma_regs = of_ioremap(&dma_of->resource[0], 0, - resource_size(&dma_of->resource[0]), - "espdma"); - if (!esp->dma_regs) - return -ENOMEM; - - switch (dma_read32(DMA_CSR) & DMA_DEVICE_ID) { - case DMA_VERS0: - esp->dmarev = dvmarev0; - break; - case DMA_ESCV1: - esp->dmarev = dvmaesc1; - break; - case DMA_VERS1: - esp->dmarev = dvmarev1; - break; - case DMA_VERS2: - esp->dmarev = dvmarev2; - break; - case DMA_VERHME: - esp->dmarev = dvmahme; - break; - case DMA_VERSPLUS: - esp->dmarev = dvmarevplus; - break; - } - - return 0; - -} - -static int __devinit esp_sbus_map_regs(struct esp *esp, int hme) -{ - struct platform_device *op = esp->dev; - struct resource *res; - - /* On HME, two reg sets exist, first is DVMA, - * second is ESP registers. - */ - if (hme) - res = &op->resource[1]; - else - res = &op->resource[0]; - - esp->regs = of_ioremap(res, 0, SBUS_ESP_REG_SIZE, "ESP"); - if (!esp->regs) - return -ENOMEM; - - return 0; -} - -static int __devinit esp_sbus_map_command_block(struct esp *esp) -{ - struct platform_device *op = esp->dev; - - esp->command_block = dma_alloc_coherent(&op->dev, 16, - &esp->command_block_dma, - GFP_ATOMIC); - if (!esp->command_block) - return -ENOMEM; - return 0; -} - -static int __devinit esp_sbus_register_irq(struct esp *esp) -{ - struct Scsi_Host *host = esp->host; - struct platform_device *op = esp->dev; - - host->irq = op->archdata.irqs[0]; - return request_irq(host->irq, scsi_esp_intr, IRQF_SHARED, "ESP", esp); -} - -static void __devinit esp_get_scsi_id(struct esp *esp, struct platform_device *espdma) -{ - struct platform_device *op = esp->dev; - struct device_node *dp; - - dp = op->dev.of_node; - esp->scsi_id = of_getintprop_default(dp, "initiator-id", 0xff); - if (esp->scsi_id != 0xff) - goto done; - - esp->scsi_id = of_getintprop_default(dp, "scsi-initiator-id", 0xff); - if (esp->scsi_id != 0xff) - goto done; - - esp->scsi_id = of_getintprop_default(espdma->dev.of_node, - "scsi-initiator-id", 7); - -done: - esp->host->this_id = esp->scsi_id; - esp->scsi_id_mask = (1 << esp->scsi_id); -} - -static void __devinit esp_get_differential(struct esp *esp) -{ - struct platform_device *op = esp->dev; - struct device_node *dp; - - dp = op->dev.of_node; - if (of_find_property(dp, "differential", NULL)) - esp->flags |= ESP_FLAG_DIFFERENTIAL; - else - esp->flags &= ~ESP_FLAG_DIFFERENTIAL; -} - -static void __devinit esp_get_clock_params(struct esp *esp) -{ - struct platform_device *op = esp->dev; - struct device_node *bus_dp, *dp; - int fmhz; - - dp = op->dev.of_node; - bus_dp = dp->parent; - - fmhz = of_getintprop_default(dp, "clock-frequency", 0); - if (fmhz == 0) - fmhz = of_getintprop_default(bus_dp, "clock-frequency", 0); - - esp->cfreq = fmhz; -} - -static void __devinit esp_get_bursts(struct esp *esp, struct platform_device *dma_of) -{ - struct device_node *dma_dp = dma_of->dev.of_node; - struct platform_device *op = esp->dev; - struct device_node *dp; - u8 bursts, val; - - dp = op->dev.of_node; - bursts = of_getintprop_default(dp, "burst-sizes", 0xff); - val = of_getintprop_default(dma_dp, "burst-sizes", 0xff); - if (val != 0xff) - bursts &= val; - - val = of_getintprop_default(dma_dp->parent, "burst-sizes", 0xff); - if (val != 0xff) - bursts &= val; - - if (bursts == 0xff || - (bursts & DMA_BURST16) == 0 || - (bursts & DMA_BURST32) == 0) - bursts = (DMA_BURST32 - 1); - - esp->bursts = bursts; -} - -static void __devinit esp_sbus_get_props(struct esp *esp, struct platform_device *espdma) -{ - esp_get_scsi_id(esp, espdma); - esp_get_differential(esp); - esp_get_clock_params(esp); - esp_get_bursts(esp, espdma); -} - -static void sbus_esp_write8(struct esp *esp, u8 val, unsigned long reg) -{ - sbus_writeb(val, esp->regs + (reg * 4UL)); -} - -static u8 sbus_esp_read8(struct esp *esp, unsigned long reg) -{ - return sbus_readb(esp->regs + (reg * 4UL)); -} - -static dma_addr_t sbus_esp_map_single(struct esp *esp, void *buf, - size_t sz, int dir) -{ - struct platform_device *op = esp->dev; - - return dma_map_single(&op->dev, buf, sz, dir); -} - -static int sbus_esp_map_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - struct platform_device *op = esp->dev; - - return dma_map_sg(&op->dev, sg, num_sg, dir); -} - -static void sbus_esp_unmap_single(struct esp *esp, dma_addr_t addr, - size_t sz, int dir) -{ - struct platform_device *op = esp->dev; - - dma_unmap_single(&op->dev, addr, sz, dir); -} - -static void sbus_esp_unmap_sg(struct esp *esp, struct scatterlist *sg, - int num_sg, int dir) -{ - struct platform_device *op = esp->dev; - - dma_unmap_sg(&op->dev, sg, num_sg, dir); -} - -static int sbus_esp_irq_pending(struct esp *esp) -{ - if (dma_read32(DMA_CSR) & (DMA_HNDL_INTR | DMA_HNDL_ERROR)) - return 1; - return 0; -} - -static void sbus_esp_reset_dma(struct esp *esp) -{ - int can_do_burst16, can_do_burst32, can_do_burst64; - int can_do_sbus64, lim; - struct platform_device *op; - u32 val; - - can_do_burst16 = (esp->bursts & DMA_BURST16) != 0; - can_do_burst32 = (esp->bursts & DMA_BURST32) != 0; - can_do_burst64 = 0; - can_do_sbus64 = 0; - op = esp->dev; - if (sbus_can_dma_64bit()) - can_do_sbus64 = 1; - if (sbus_can_burst64()) - can_do_burst64 = (esp->bursts & DMA_BURST64) != 0; - - /* Put the DVMA into a known state. */ - if (esp->dmarev != dvmahme) { - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_RST_SCSI, DMA_CSR); - dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); - } - switch (esp->dmarev) { - case dvmahme: - dma_write32(DMA_RESET_FAS366, DMA_CSR); - dma_write32(DMA_RST_SCSI, DMA_CSR); - - esp->prev_hme_dmacsr = (DMA_PARITY_OFF | DMA_2CLKS | - DMA_SCSI_DISAB | DMA_INT_ENAB); - - esp->prev_hme_dmacsr &= ~(DMA_ENABLE | DMA_ST_WRITE | - DMA_BRST_SZ); - - if (can_do_burst64) - esp->prev_hme_dmacsr |= DMA_BRST64; - else if (can_do_burst32) - esp->prev_hme_dmacsr |= DMA_BRST32; - - if (can_do_sbus64) { - esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64; - sbus_set_sbus64(&op->dev, esp->bursts); - } - - lim = 1000; - while (dma_read32(DMA_CSR) & DMA_PEND_READ) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA_PEND_READ " - "will not clear!\n", - esp->host->unique_id); - break; - } - udelay(1); - } - - dma_write32(0, DMA_CSR); - dma_write32(esp->prev_hme_dmacsr, DMA_CSR); - - dma_write32(0, DMA_ADDR); - break; - - case dvmarev2: - if (esp->rev != ESP100) { - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_3CLKS, DMA_CSR); - } - break; - - case dvmarev3: - val = dma_read32(DMA_CSR); - val &= ~DMA_3CLKS; - val |= DMA_2CLKS; - if (can_do_burst32) { - val &= ~DMA_BRST_SZ; - val |= DMA_BRST32; - } - dma_write32(val, DMA_CSR); - break; - - case dvmaesc1: - val = dma_read32(DMA_CSR); - val |= DMA_ADD_ENABLE; - val &= ~DMA_BCNT_ENAB; - if (!can_do_burst32 && can_do_burst16) { - val |= DMA_ESC_BURST; - } else { - val &= ~(DMA_ESC_BURST); - } - dma_write32(val, DMA_CSR); - break; - - default: - break; - } - - /* Enable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val | DMA_INT_ENAB, DMA_CSR); -} - -static void sbus_esp_dma_drain(struct esp *esp) -{ - u32 csr; - int lim; - - if (esp->dmarev == dvmahme) - return; - - csr = dma_read32(DMA_CSR); - if (!(csr & DMA_FIFO_ISDRAIN)) - return; - - if (esp->dmarev != dvmarev3 && esp->dmarev != dvmaesc1) - dma_write32(csr | DMA_FIFO_STDRAIN, DMA_CSR); - - lim = 1000; - while (dma_read32(DMA_CSR) & DMA_FIFO_ISDRAIN) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not drain!\n", - esp->host->unique_id); - break; - } - udelay(1); - } -} - -static void sbus_esp_dma_invalidate(struct esp *esp) -{ - if (esp->dmarev == dvmahme) { - dma_write32(DMA_RST_SCSI, DMA_CSR); - - esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr | - (DMA_PARITY_OFF | DMA_2CLKS | - DMA_SCSI_DISAB | DMA_INT_ENAB)) & - ~(DMA_ST_WRITE | DMA_ENABLE)); - - dma_write32(0, DMA_CSR); - dma_write32(esp->prev_hme_dmacsr, DMA_CSR); - - /* This is necessary to avoid having the SCSI channel - * engine lock up on us. - */ - dma_write32(0, DMA_ADDR); - } else { - u32 val; - int lim; - - lim = 1000; - while ((val = dma_read32(DMA_CSR)) & DMA_PEND_READ) { - if (--lim == 0) { - printk(KERN_ALERT PFX "esp%d: DMA will not " - "invalidate!\n", esp->host->unique_id); - break; - } - udelay(1); - } - - val &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB); - val |= DMA_FIFO_INV; - dma_write32(val, DMA_CSR); - val &= ~DMA_FIFO_INV; - dma_write32(val, DMA_CSR); - } -} - -static void sbus_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count, - u32 dma_count, int write, u8 cmd) -{ - u32 csr; - - BUG_ON(!(cmd & ESP_CMD_DMA)); - - sbus_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW); - sbus_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED); - if (esp->rev == FASHME) { - sbus_esp_write8(esp, (esp_count >> 16) & 0xff, FAS_RLO); - sbus_esp_write8(esp, 0, FAS_RHI); - - scsi_esp_cmd(esp, cmd); - - csr = esp->prev_hme_dmacsr; - csr |= DMA_SCSI_DISAB | DMA_ENABLE; - if (write) - csr |= DMA_ST_WRITE; - else - csr &= ~DMA_ST_WRITE; - esp->prev_hme_dmacsr = csr; - - dma_write32(dma_count, DMA_COUNT); - dma_write32(addr, DMA_ADDR); - dma_write32(csr, DMA_CSR); - } else { - csr = dma_read32(DMA_CSR); - csr |= DMA_ENABLE; - if (write) - csr |= DMA_ST_WRITE; - else - csr &= ~DMA_ST_WRITE; - dma_write32(csr, DMA_CSR); - if (esp->dmarev == dvmaesc1) { - u32 end = PAGE_ALIGN(addr + dma_count + 16U); - dma_write32(end - addr, DMA_COUNT); - } - dma_write32(addr, DMA_ADDR); - - scsi_esp_cmd(esp, cmd); - } - -} - -static int sbus_esp_dma_error(struct esp *esp) -{ - u32 csr = dma_read32(DMA_CSR); - - if (csr & DMA_HNDL_ERROR) - return 1; - - return 0; -} - -static const struct esp_driver_ops sbus_esp_ops = { - .esp_write8 = sbus_esp_write8, - .esp_read8 = sbus_esp_read8, - .map_single = sbus_esp_map_single, - .map_sg = sbus_esp_map_sg, - .unmap_single = sbus_esp_unmap_single, - .unmap_sg = sbus_esp_unmap_sg, - .irq_pending = sbus_esp_irq_pending, - .reset_dma = sbus_esp_reset_dma, - .dma_drain = sbus_esp_dma_drain, - .dma_invalidate = sbus_esp_dma_invalidate, - .send_dma_cmd = sbus_esp_send_dma_cmd, - .dma_error = sbus_esp_dma_error, -}; - -static int __devinit esp_sbus_probe_one(struct platform_device *op, - struct platform_device *espdma, - int hme) -{ - struct scsi_host_template *tpnt = &scsi_esp_template; - struct Scsi_Host *host; - struct esp *esp; - int err; - - host = scsi_host_alloc(tpnt, sizeof(struct esp)); - - err = -ENOMEM; - if (!host) - goto fail; - - host->max_id = (hme ? 16 : 8); - esp = shost_priv(host); - - esp->host = host; - esp->dev = op; - esp->ops = &sbus_esp_ops; - - if (hme) - esp->flags |= ESP_FLAG_WIDE_CAPABLE; - - err = esp_sbus_setup_dma(esp, espdma); - if (err < 0) - goto fail_unlink; - - err = esp_sbus_map_regs(esp, hme); - if (err < 0) - goto fail_unlink; - - err = esp_sbus_map_command_block(esp); - if (err < 0) - goto fail_unmap_regs; - - err = esp_sbus_register_irq(esp); - if (err < 0) - goto fail_unmap_command_block; - - esp_sbus_get_props(esp, espdma); - - /* Before we try to touch the ESP chip, ESC1 dma can - * come up with the reset bit set, so make sure that - * is clear first. - */ - if (esp->dmarev == dvmaesc1) { - u32 val = dma_read32(DMA_CSR); - - dma_write32(val & ~DMA_RST_SCSI, DMA_CSR); - } - - dev_set_drvdata(&op->dev, esp); - - err = scsi_esp_register(esp, &op->dev); - if (err) - goto fail_free_irq; - - return 0; - -fail_free_irq: - free_irq(host->irq, esp); -fail_unmap_command_block: - dma_free_coherent(&op->dev, 16, - esp->command_block, - esp->command_block_dma); -fail_unmap_regs: - of_iounmap(&op->resource[(hme ? 1 : 0)], esp->regs, SBUS_ESP_REG_SIZE); -fail_unlink: - scsi_host_put(host); -fail: - return err; -} - -static int __devinit esp_sbus_probe(struct platform_device *op) -{ - struct device_node *dma_node = NULL; - struct device_node *dp = op->dev.of_node; - struct platform_device *dma_of = NULL; - int hme = 0; - - if (dp->parent && - (!strcmp(dp->parent->name, "espdma") || - !strcmp(dp->parent->name, "dma"))) - dma_node = dp->parent; - else if (!strcmp(dp->name, "SUNW,fas")) { - dma_node = op->dev.of_node; - hme = 1; - } - if (dma_node) - dma_of = of_find_device_by_node(dma_node); - if (!dma_of) - return -ENODEV; - - return esp_sbus_probe_one(op, dma_of, hme); -} - -static int __devexit esp_sbus_remove(struct platform_device *op) -{ - struct esp *esp = dev_get_drvdata(&op->dev); - struct platform_device *dma_of = esp->dma; - unsigned int irq = esp->host->irq; - bool is_hme; - u32 val; - - scsi_esp_unregister(esp); - - /* Disable interrupts. */ - val = dma_read32(DMA_CSR); - dma_write32(val & ~DMA_INT_ENAB, DMA_CSR); - - free_irq(irq, esp); - - is_hme = (esp->dmarev == dvmahme); - - dma_free_coherent(&op->dev, 16, - esp->command_block, - esp->command_block_dma); - of_iounmap(&op->resource[(is_hme ? 1 : 0)], esp->regs, - SBUS_ESP_REG_SIZE); - of_iounmap(&dma_of->resource[0], esp->dma_regs, - resource_size(&dma_of->resource[0])); - - scsi_host_put(esp->host); - - dev_set_drvdata(&op->dev, NULL); - - return 0; -} - -static const struct of_device_id esp_match[] = { - { - .name = "SUNW,esp", - }, - { - .name = "SUNW,fas", - }, - { - .name = "esp", - }, - {}, -}; -MODULE_DEVICE_TABLE(of, esp_match); - -static struct platform_driver esp_sbus_driver = { - .driver = { - .name = "esp", - .owner = THIS_MODULE, - .of_match_table = esp_match, - }, - .probe = esp_sbus_probe, - .remove = __devexit_p(esp_sbus_remove), -}; - -static int __init sunesp_init(void) -{ - return platform_driver_register(&esp_sbus_driver); -} - -static void __exit sunesp_exit(void) -{ - platform_driver_unregister(&esp_sbus_driver); -} - -MODULE_DESCRIPTION("Sun ESP SCSI driver"); -MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); - -module_init(sunesp_init); -module_exit(sunesp_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c416.c b/ANDROID_3.4.5/drivers/scsi/sym53c416.c deleted file mode 100644 index ac4eca6a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c416.c +++ /dev/null @@ -1,845 +0,0 @@ -/* - * sym53c416.c - * Low-level SCSI driver for sym53c416 chip. - * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) - * - * Changes : - * - * Marcelo Tosatti : Added io_request_lock locking - * Alan Cox : Cleaned up code formatting - * Fixed an irq locking bug - * Added ISAPnP support - * Bjoern A. Zeeb : Initial irq locking updates - * Added another card with ISAPnP support - * - * LILO command line usage: sym53c416=[,] - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "scsi.h" -#include -#include "sym53c416.h" - -#define VERSION_STRING "Version 1.0.0-ac" - -#define TC_LOW 0x00 /* Transfer counter low */ -#define TC_MID 0x01 /* Transfer counter mid */ -#define SCSI_FIFO 0x02 /* SCSI FIFO register */ -#define COMMAND_REG 0x03 /* Command Register */ -#define STATUS_REG 0x04 /* Status Register (READ) */ -#define DEST_BUS_ID 0x04 /* Destination Bus ID (WRITE) */ -#define INT_REG 0x05 /* Interrupt Register (READ) */ -#define TOM 0x05 /* Time out multiplier (WRITE) */ -#define STP 0x06 /* Synchronous Transfer period */ -#define SYNC_OFFSET 0x07 /* Synchronous Offset */ -#define CONF_REG_1 0x08 /* Configuration register 1 */ -#define CONF_REG_2 0x0B /* Configuration register 2 */ -#define CONF_REG_3 0x0C /* Configuration register 3 */ -#define CONF_REG_4 0x0D /* Configuration register 4 */ -#define TC_HIGH 0x0E /* Transfer counter high */ -#define PIO_FIFO_1 0x10 /* PIO FIFO register 1 */ -#define PIO_FIFO_2 0x11 /* PIO FIFO register 2 */ -#define PIO_FIFO_3 0x12 /* PIO FIFO register 3 */ -#define PIO_FIFO_4 0x13 /* PIO FIFO register 4 */ -#define PIO_FIFO_CNT 0x14 /* PIO FIFO count */ -#define PIO_INT_REG 0x15 /* PIO interrupt register */ -#define CONF_REG_5 0x16 /* Configuration register 5 */ -#define FEATURE_EN 0x1D /* Feature Enable register */ - -/* Configuration register 1 entries: */ -/* Bits 2-0: SCSI ID of host adapter */ -#define SCM 0x80 /* Slow Cable Mode */ -#define SRID 0x40 /* SCSI Reset Interrupt Disable */ -#define PTM 0x20 /* Parity Test Mode */ -#define EPC 0x10 /* Enable Parity Checking */ -#define CTME 0x08 /* Special Test Mode */ - -/* Configuration register 2 entries: */ -#define FE 0x40 /* Features Enable */ -#define SCSI2 0x08 /* SCSI 2 Enable */ -#define TBPA 0x04 /* Target Bad Parity Abort */ - -/* Configuration register 3 entries: */ -#define IDMRC 0x80 /* ID Message Reserved Check */ -#define QTE 0x40 /* Queue Tag Enable */ -#define CDB10 0x20 /* Command Descriptor Block 10 */ -#define FSCSI 0x10 /* FastSCSI */ -#define FCLK 0x08 /* FastClock */ - -/* Configuration register 4 entries: */ -#define RBS 0x08 /* Register bank select */ -#define EAN 0x04 /* Enable Active Negotiation */ - -/* Configuration register 5 entries: */ -#define LPSR 0x80 /* Lower Power SCSI Reset */ -#define IE 0x20 /* Interrupt Enable */ -#define LPM 0x02 /* Low Power Mode */ -#define WSE0 0x01 /* 0WS Enable */ - -/* Interrupt register entries: */ -#define SRST 0x80 /* SCSI Reset */ -#define ILCMD 0x40 /* Illegal Command */ -#define DIS 0x20 /* Disconnect */ -#define BS 0x10 /* Bus Service */ -#define FC 0x08 /* Function Complete */ -#define RESEL 0x04 /* Reselected */ -#define SI 0x03 /* Selection Interrupt */ - -/* Status Register Entries: */ -#define SCI 0x80 /* SCSI Core Int */ -#define GE 0x40 /* Gross Error */ -#define PE 0x20 /* Parity Error */ -#define TC 0x10 /* Terminal Count */ -#define VGC 0x08 /* Valid Group Code */ -#define PHBITS 0x07 /* Phase bits */ - -/* PIO Interrupt Register Entries: */ -#define SCI 0x80 /* SCSI Core Int */ -#define PFI 0x40 /* PIO FIFO Interrupt */ -#define FULL 0x20 /* PIO FIFO Full */ -#define EMPTY 0x10 /* PIO FIFO Empty */ -#define CE 0x08 /* Collision Error */ -#define OUE 0x04 /* Overflow / Underflow error */ -#define FIE 0x02 /* Full Interrupt Enable */ -#define EIE 0x01 /* Empty Interrupt Enable */ - -/* SYM53C416 SCSI phases (lower 3 bits of SYM53C416_STATUS_REG) */ -#define PHASE_DATA_OUT 0x00 -#define PHASE_DATA_IN 0x01 -#define PHASE_COMMAND 0x02 -#define PHASE_STATUS 0x03 -#define PHASE_RESERVED_1 0x04 -#define PHASE_RESERVED_2 0x05 -#define PHASE_MESSAGE_OUT 0x06 -#define PHASE_MESSAGE_IN 0x07 - -/* SYM53C416 core commands */ -#define NOOP 0x00 -#define FLUSH_FIFO 0x01 -#define RESET_CHIP 0x02 -#define RESET_SCSI_BUS 0x03 -#define DISABLE_SEL_RESEL 0x45 -#define RESEL_SEQ 0x40 -#define SEL_WITHOUT_ATN_SEQ 0x41 -#define SEL_WITH_ATN_SEQ 0x42 -#define SEL_WITH_ATN_AND_STOP_SEQ 0x43 -#define ENABLE_SEL_RESEL 0x44 -#define SEL_WITH_ATN3_SEQ 0x46 -#define RESEL3_SEQ 0x47 -#define SND_MSG 0x20 -#define SND_STAT 0x21 -#define SND_DATA 0x22 -#define DISCONNECT_SEQ 0x23 -#define TERMINATE_SEQ 0x24 -#define TARGET_COMM_COMPLETE_SEQ 0x25 -#define DISCONN 0x27 -#define RECV_MSG_SEQ 0x28 -#define RECV_CMD 0x29 -#define RECV_DATA 0x2A -#define RECV_CMD_SEQ 0x2B -#define TARGET_ABORT_PIO 0x04 -#define TRANSFER_INFORMATION 0x10 -#define INIT_COMM_COMPLETE_SEQ 0x11 -#define MSG_ACCEPTED 0x12 -#define TRANSFER_PAD 0x18 -#define SET_ATN 0x1A -#define RESET_ATN 0x1B -#define ILLEGAL 0xFF - -#define PIO_MODE 0x80 - -#define IO_RANGE 0x20 /* 0x00 - 0x1F */ -#define ID "sym53c416" /* Attention: copied to the sym53c416.h */ -#define PIO_SIZE 128 /* Size of PIO fifo is 128 bytes */ - -#define READ_TIMEOUT 150 -#define WRITE_TIMEOUT 150 - -#ifdef MODULE - -#define sym53c416_base sym53c416 -#define sym53c416_base_1 sym53c416_1 -#define sym53c416_base_2 sym53c416_2 -#define sym53c416_base_3 sym53c416_3 - -static unsigned int sym53c416_base[2]; -static unsigned int sym53c416_base_1[2]; -static unsigned int sym53c416_base_2[2]; -static unsigned int sym53c416_base_3[2]; - -#endif - -#define MAXHOSTS 4 - -#define SG_ADDRESS(buffer) ((char *) sg_virt((buffer))) - -enum phases -{ - idle, - data_out, - data_in, - command_ph, - status_ph, - message_out, - message_in -}; - -typedef struct -{ - int base; - int irq; - int scsi_id; -} host; - -static host hosts[MAXHOSTS] = { - {0, 0, SYM53C416_SCSI_ID}, - {0, 0, SYM53C416_SCSI_ID}, - {0, 0, SYM53C416_SCSI_ID}, - {0, 0, SYM53C416_SCSI_ID} - }; - -static int host_index = 0; -static char info[120]; -static Scsi_Cmnd *current_command = NULL; -static int fastpio = 1; - -static int probeaddrs[] = {0x200, 0x220, 0x240, 0}; - -static void sym53c416_set_transfer_counter(int base, unsigned int len) -{ - /* Program Transfer Counter */ - outb(len & 0x0000FF, base + TC_LOW); - outb((len & 0x00FF00) >> 8, base + TC_MID); - outb((len & 0xFF0000) >> 16, base + TC_HIGH); -} - -static DEFINE_SPINLOCK(sym53c416_lock); - -/* Returns the number of bytes read */ -static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len) -{ - unsigned int orig_len = len; - unsigned long flags = 0; - unsigned int bytes_left; - unsigned long i; - int timeout = READ_TIMEOUT; - - /* Do transfer */ - spin_lock_irqsave(&sym53c416_lock, flags); - while(len && timeout) - { - bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */ - if(fastpio && bytes_left > 3) - { - insl(base + PIO_FIFO_1, buffer, bytes_left >> 2); - buffer += bytes_left & 0xFC; - len -= bytes_left & 0xFC; - } - else if(bytes_left > 0) - { - len -= bytes_left; - for(; bytes_left > 0; bytes_left--) - *(buffer++) = inb(base + PIO_FIFO_1); - } - else - { - i = jiffies + timeout; - spin_unlock_irqrestore(&sym53c416_lock, flags); - while(time_before(jiffies, i) && (inb(base + PIO_INT_REG) & EMPTY) && timeout) - if(inb(base + PIO_INT_REG) & SCI) - timeout = 0; - spin_lock_irqsave(&sym53c416_lock, flags); - if(inb(base + PIO_INT_REG) & EMPTY) - timeout = 0; - } - } - spin_unlock_irqrestore(&sym53c416_lock, flags); - return orig_len - len; -} - -/* Returns the number of bytes written */ -static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len) -{ - unsigned int orig_len = len; - unsigned long flags = 0; - unsigned int bufferfree; - unsigned long i; - unsigned int timeout = WRITE_TIMEOUT; - - /* Do transfer */ - spin_lock_irqsave(&sym53c416_lock, flags); - while(len && timeout) - { - bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT); - if(bufferfree > len) - bufferfree = len; - if(fastpio && bufferfree > 3) - { - outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2); - buffer += bufferfree & 0xFC; - len -= bufferfree & 0xFC; - } - else if(bufferfree > 0) - { - len -= bufferfree; - for(; bufferfree > 0; bufferfree--) - outb(*(buffer++), base + PIO_FIFO_1); - } - else - { - i = jiffies + timeout; - spin_unlock_irqrestore(&sym53c416_lock, flags); - while(time_before(jiffies, i) && (inb(base + PIO_INT_REG) & FULL) && timeout) - ; - spin_lock_irqsave(&sym53c416_lock, flags); - if(inb(base + PIO_INT_REG) & FULL) - timeout = 0; - } - } - spin_unlock_irqrestore(&sym53c416_lock, flags); - return orig_len - len; -} - -static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id) -{ - struct Scsi_Host *dev = dev_id; - int base = dev->io_port; - int i; - unsigned long flags = 0; - unsigned char status_reg, pio_int_reg, int_reg; - struct scatterlist *sg; - unsigned int tot_trans = 0; - - spin_lock_irqsave(dev->host_lock,flags); - status_reg = inb(base + STATUS_REG); - pio_int_reg = inb(base + PIO_INT_REG); - int_reg = inb(base + INT_REG); - spin_unlock_irqrestore(dev->host_lock, flags); - - /* First, we handle error conditions */ - if(int_reg & SCI) /* SCSI Reset */ - { - printk(KERN_DEBUG "sym53c416: Reset received\n"); - current_command->SCp.phase = idle; - current_command->result = DID_RESET << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(int_reg & ILCMD) /* Illegal Command */ - { - printk(KERN_WARNING "sym53c416: Illegal Command: 0x%02x.\n", inb(base + COMMAND_REG)); - current_command->SCp.phase = idle; - current_command->result = DID_ERROR << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(status_reg & GE) /* Gross Error */ - { - printk(KERN_WARNING "sym53c416: Controller reports gross error.\n"); - current_command->SCp.phase = idle; - current_command->result = DID_ERROR << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(status_reg & PE) /* Parity Error */ - { - printk(KERN_WARNING "sym53c416:SCSI parity error.\n"); - current_command->SCp.phase = idle; - current_command->result = DID_PARITY << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(pio_int_reg & (CE | OUE)) - { - printk(KERN_WARNING "sym53c416: PIO interrupt error.\n"); - current_command->SCp.phase = idle; - current_command->result = DID_ERROR << 16; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - if(int_reg & DIS) /* Disconnect */ - { - if(current_command->SCp.phase != message_in) - current_command->result = DID_NO_CONNECT << 16; - else - current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16); - current_command->SCp.phase = idle; - spin_lock_irqsave(dev->host_lock, flags); - current_command->scsi_done(current_command); - spin_unlock_irqrestore(dev->host_lock, flags); - goto out; - } - /* Now we handle SCSI phases */ - - switch(status_reg & PHBITS) /* Filter SCSI phase out of status reg */ - { - case PHASE_DATA_OUT: - { - if(int_reg & BS) - { - current_command->SCp.phase = data_out; - outb(FLUSH_FIFO, base + COMMAND_REG); - sym53c416_set_transfer_counter(base, - scsi_bufflen(current_command)); - outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG); - - scsi_for_each_sg(current_command, - sg, scsi_sg_count(current_command), i) { - tot_trans += sym53c416_write(base, - SG_ADDRESS(sg), - sg->length); - } - if(tot_trans < current_command->underflow) - printk(KERN_WARNING "sym53c416: Underflow, wrote %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow); - } - break; - } - - case PHASE_DATA_IN: - { - if(int_reg & BS) - { - current_command->SCp.phase = data_in; - outb(FLUSH_FIFO, base + COMMAND_REG); - sym53c416_set_transfer_counter(base, - scsi_bufflen(current_command)); - - outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG); - - scsi_for_each_sg(current_command, - sg, scsi_sg_count(current_command), i) { - tot_trans += sym53c416_read(base, - SG_ADDRESS(sg), - sg->length); - } - if(tot_trans < current_command->underflow) - printk(KERN_WARNING "sym53c416: Underflow, read %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow); - } - break; - } - - case PHASE_COMMAND: - { - current_command->SCp.phase = command_ph; - printk(KERN_ERR "sym53c416: Unknown interrupt in command phase.\n"); - break; - } - - case PHASE_STATUS: - { - current_command->SCp.phase = status_ph; - outb(FLUSH_FIFO, base + COMMAND_REG); - outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG); - break; - } - - case PHASE_RESERVED_1: - case PHASE_RESERVED_2: - { - printk(KERN_ERR "sym53c416: Reserved phase occurred.\n"); - break; - } - - case PHASE_MESSAGE_OUT: - { - current_command->SCp.phase = message_out; - outb(SET_ATN, base + COMMAND_REG); - outb(MSG_ACCEPTED, base + COMMAND_REG); - break; - } - - case PHASE_MESSAGE_IN: - { - current_command->SCp.phase = message_in; - current_command->SCp.Status = inb(base + SCSI_FIFO); - current_command->SCp.Message = inb(base + SCSI_FIFO); - if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT) - outb(SET_ATN, base + COMMAND_REG); - outb(MSG_ACCEPTED, base + COMMAND_REG); - break; - } - } -out: - return IRQ_HANDLED; -} - -static void sym53c416_init(int base, int scsi_id) -{ - outb(RESET_CHIP, base + COMMAND_REG); - outb(NOOP, base + COMMAND_REG); - outb(0x99, base + TOM); /* Time out of 250 ms */ - outb(0x05, base + STP); - outb(0x00, base + SYNC_OFFSET); - outb(EPC | scsi_id, base + CONF_REG_1); - outb(FE | SCSI2 | TBPA, base + CONF_REG_2); - outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3); - outb(0x83 | EAN, base + CONF_REG_4); - outb(IE | WSE0, base + CONF_REG_5); - outb(0, base + FEATURE_EN); -} - -static int sym53c416_probeirq(int base, int scsi_id) -{ - int irq, irqs; - unsigned long i; - - /* Clear interrupt register */ - inb(base + INT_REG); - /* Start probing for irq's */ - irqs = probe_irq_on(); - /* Reinit chip */ - sym53c416_init(base, scsi_id); - /* Cause interrupt */ - outb(NOOP, base + COMMAND_REG); - outb(ILLEGAL, base + COMMAND_REG); - outb(0x07, base + DEST_BUS_ID); - outb(0x00, base + DEST_BUS_ID); - /* Wait for interrupt to occur */ - i = jiffies + 20; - while(time_before(jiffies, i) && !(inb(base + STATUS_REG) & SCI)) - barrier(); - if(time_before_eq(i, jiffies)) /* timed out */ - return 0; - /* Get occurred irq */ - irq = probe_irq_off(irqs); - sym53c416_init(base, scsi_id); - return irq; -} - -/* Setup: sym53c416=base,irq */ -void sym53c416_setup(char *str, int *ints) -{ - int i; - - if(host_index >= MAXHOSTS) - { - printk(KERN_WARNING "sym53c416: Too many hosts defined\n"); - return; - } - if(ints[0] < 1 || ints[0] > 2) - { - printk(KERN_ERR "sym53c416: Wrong number of parameters:\n"); - printk(KERN_ERR "sym53c416: usage: sym53c416=[,]\n"); - return; - } - for(i = 0; i < host_index && i >= 0; i++) - if(hosts[i].base == ints[1]) - i = -2; - if(i >= 0) - { - hosts[host_index].base = ints[1]; - hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0; - host_index++; - } -} - -static int sym53c416_test(int base) -{ - outb(RESET_CHIP, base + COMMAND_REG); - outb(NOOP, base + COMMAND_REG); - if(inb(base + COMMAND_REG) != NOOP) - return 0; - if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF) - return 0; - if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY) - return 0; - return 1; -} - - -static struct isapnp_device_id id_table[] __devinitdata = { - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4161), 0 }, - { ISAPNP_ANY_ID, ISAPNP_ANY_ID, - ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4163), 0 }, - { ISAPNP_DEVICE_SINGLE_END } -}; - -MODULE_DEVICE_TABLE(isapnp, id_table); - -static void sym53c416_probe(void) -{ - int *base = probeaddrs; - int ints[2]; - - ints[0] = 1; - for(; *base; base++) { - if (request_region(*base, IO_RANGE, ID)) { - if (sym53c416_test(*base)) { - ints[1] = *base; - sym53c416_setup(NULL, ints); - } - release_region(*base, IO_RANGE); - } - } -} - -int __init sym53c416_detect(struct scsi_host_template *tpnt) -{ - unsigned long flags; - struct Scsi_Host * shpnt = NULL; - int i; - int count; - struct pnp_dev *idev = NULL; - -#ifdef MODULE - int ints[3]; - - ints[0] = 2; - if(sym53c416_base[0]) - { - ints[1] = sym53c416_base[0]; - ints[2] = sym53c416_base[1]; - sym53c416_setup(NULL, ints); - } - if(sym53c416_base_1[0]) - { - ints[1] = sym53c416_base_1[0]; - ints[2] = sym53c416_base_1[1]; - sym53c416_setup(NULL, ints); - } - if(sym53c416_base_2[0]) - { - ints[1] = sym53c416_base_2[0]; - ints[2] = sym53c416_base_2[1]; - sym53c416_setup(NULL, ints); - } - if(sym53c416_base_3[0]) - { - ints[1] = sym53c416_base_3[0]; - ints[2] = sym53c416_base_3[1]; - sym53c416_setup(NULL, ints); - } -#endif - printk(KERN_INFO "sym53c416.c: %s\n", VERSION_STRING); - - for (i=0; id_table[i].vendor != 0; i++) { - while((idev=pnp_find_dev(NULL, id_table[i].vendor, - id_table[i].function, idev))!=NULL) - { - int i[3]; - - if(pnp_device_attach(idev)<0) - { - printk(KERN_WARNING "sym53c416: unable to attach PnP device.\n"); - continue; - } - if(pnp_activate_dev(idev) < 0) - { - printk(KERN_WARNING "sym53c416: unable to activate PnP device.\n"); - pnp_device_detach(idev); - continue; - - } - - i[0] = 2; - i[1] = pnp_port_start(idev, 0); - i[2] = pnp_irq(idev, 0); - - printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n", - i[1], i[2]); - sym53c416_setup(NULL, i); - } - } - sym53c416_probe(); - - /* Now we register and set up each host adapter found... */ - for(count = 0, i = 0; i < host_index; i++) { - if (!request_region(hosts[i].base, IO_RANGE, ID)) - continue; - if (!sym53c416_test(hosts[i].base)) { - printk(KERN_WARNING "No sym53c416 found at address 0x%03x\n", hosts[i].base); - goto fail_release_region; - } - - /* We don't have an irq yet, so we should probe for one */ - if (!hosts[i].irq) - hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id); - if (!hosts[i].irq) - goto fail_release_region; - - shpnt = scsi_register(tpnt, 0); - if (!shpnt) - goto fail_release_region; - /* Request for specified IRQ */ - if (request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, shpnt)) - goto fail_free_host; - - spin_lock_irqsave(&sym53c416_lock, flags); - shpnt->unique_id = hosts[i].base; - shpnt->io_port = hosts[i].base; - shpnt->n_io_port = IO_RANGE; - shpnt->irq = hosts[i].irq; - shpnt->this_id = hosts[i].scsi_id; - sym53c416_init(hosts[i].base, hosts[i].scsi_id); - count++; - spin_unlock_irqrestore(&sym53c416_lock, flags); - continue; - - fail_free_host: - scsi_unregister(shpnt); - fail_release_region: - release_region(hosts[i].base, IO_RANGE); - } - return count; -} - -const char *sym53c416_info(struct Scsi_Host *SChost) -{ - int i; - int base = SChost->io_port; - int irq = SChost->irq; - int scsi_id = 0; - int rev = inb(base + TC_HIGH); - - for(i = 0; i < host_index; i++) - if(hosts[i].base == base) - scsi_id = hosts[i].scsi_id; - sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow"); - return info; -} - -static int sym53c416_queuecommand_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) -{ - int base; - unsigned long flags = 0; - int i; - - /* Store base register as we can have more than one controller in the system */ - base = SCpnt->device->host->io_port; - current_command = SCpnt; /* set current command */ - current_command->scsi_done = done; /* set ptr to done function */ - current_command->SCp.phase = command_ph; /* currect phase is the command phase */ - current_command->SCp.Status = 0; - current_command->SCp.Message = 0; - - spin_lock_irqsave(&sym53c416_lock, flags); - outb(scmd_id(SCpnt), base + DEST_BUS_ID); /* Set scsi id target */ - outb(FLUSH_FIFO, base + COMMAND_REG); /* Flush SCSI and PIO FIFO's */ - /* Write SCSI command into the SCSI fifo */ - for(i = 0; i < SCpnt->cmd_len; i++) - outb(SCpnt->cmnd[i], base + SCSI_FIFO); - /* Start selection sequence */ - outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG); - /* Now an interrupt will be generated which we will catch in out interrupt routine */ - spin_unlock_irqrestore(&sym53c416_lock, flags); - return 0; -} - -DEF_SCSI_QCMD(sym53c416_queuecommand) - -static int sym53c416_host_reset(Scsi_Cmnd *SCpnt) -{ - int base; - int scsi_id = -1; - int i; - unsigned long flags; - - spin_lock_irqsave(&sym53c416_lock, flags); - - /* printk("sym53c416_reset\n"); */ - base = SCpnt->device->host->io_port; - /* search scsi_id - fixme, we shouldn't need to iterate for this! */ - for(i = 0; i < host_index && scsi_id == -1; i++) - if(hosts[i].base == base) - scsi_id = hosts[i].scsi_id; - outb(RESET_CHIP, base + COMMAND_REG); - outb(NOOP | PIO_MODE, base + COMMAND_REG); - outb(RESET_SCSI_BUS, base + COMMAND_REG); - sym53c416_init(base, scsi_id); - - spin_unlock_irqrestore(&sym53c416_lock, flags); - return SUCCESS; -} - -static int sym53c416_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, shost); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - return 0; -} - -static int sym53c416_bios_param(struct scsi_device *sdev, - struct block_device *dev, - sector_t capacity, int *ip) -{ - int size; - - size = capacity; - ip[0] = 64; /* heads */ - ip[1] = 32; /* sectors */ - if((ip[2] = size >> 11) > 1024) /* cylinders, test for big disk */ - { - ip[0] = 255; /* heads */ - ip[1] = 63; /* sectors */ - ip[2] = size / (255 * 63); /* cylinders */ - } - return 0; -} - -/* Loadable module support */ -#ifdef MODULE - -MODULE_AUTHOR("Lieven Willems"); -MODULE_LICENSE("GPL"); - -module_param_array(sym53c416, uint, NULL, 0); -module_param_array(sym53c416_1, uint, NULL, 0); -module_param_array(sym53c416_2, uint, NULL, 0); -module_param_array(sym53c416_3, uint, NULL, 0); - -#endif - -static struct scsi_host_template driver_template = { - .proc_name = "sym53c416", - .name = "Symbios Logic 53c416", - .detect = sym53c416_detect, - .info = sym53c416_info, - .queuecommand = sym53c416_queuecommand, - .eh_host_reset_handler =sym53c416_host_reset, - .release = sym53c416_release, - .bios_param = sym53c416_bios_param, - .can_queue = 1, - .this_id = SYM53C416_SCSI_ID, - .sg_tablesize = 32, - .cmd_per_lun = 1, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c416.h b/ANDROID_3.4.5/drivers/scsi/sym53c416.h deleted file mode 100644 index 387de5d8..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c416.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * sym53c416.h - * - * Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2, or (at your option) any - * later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - */ - -#ifndef _SYM53C416_H -#define _SYM53C416_H - -#include - -#define SYM53C416_SCSI_ID 7 - -static int sym53c416_detect(struct scsi_host_template *); -static const char *sym53c416_info(struct Scsi_Host *); -static int sym53c416_release(struct Scsi_Host *); -static int sym53c416_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static int sym53c416_host_reset(Scsi_Cmnd *); -static int sym53c416_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static void sym53c416_setup(char *str, int *ints); -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/Makefile b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/Makefile deleted file mode 100644 index 873e8ced..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver. - -sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_nvram.o -obj-$(CONFIG_SCSI_SYM53C8XX_2) := sym53c8xx.o diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym53c8xx.h deleted file mode 100644 index 62d29cfa..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym53c8xx.h +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SYM53C8XX_H -#define SYM53C8XX_H - - -/* - * DMA addressing mode. - * - * 0 : 32 bit addressing for all chips. - * 1 : 40 bit addressing when supported by chip. - * 2 : 64 bit addressing when supported by chip, - * limited to 16 segments of 4 GB -> 64 GB max. - */ -#define SYM_CONF_DMA_ADDRESSING_MODE CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE - -/* - * NVRAM support. - */ -#if 1 -#define SYM_CONF_NVRAM_SUPPORT (1) -#endif - -/* - * These options are not tunable from 'make config' - */ -#if 1 -#define SYM_LINUX_PROC_INFO_SUPPORT -#define SYM_LINUX_USER_COMMAND_SUPPORT -#define SYM_LINUX_USER_INFO_SUPPORT -#define SYM_LINUX_DEBUG_CONTROL_SUPPORT -#endif - -/* - * Also handle old NCR chips if not (0). - */ -#define SYM_CONF_GENERIC_SUPPORT (1) - -/* - * Allow tags from 2 to 256, default 8 - */ -#ifndef CONFIG_SCSI_SYM53C8XX_MAX_TAGS -#define CONFIG_SCSI_SYM53C8XX_MAX_TAGS (8) -#endif - -#if CONFIG_SCSI_SYM53C8XX_MAX_TAGS < 2 -#define SYM_CONF_MAX_TAG (2) -#elif CONFIG_SCSI_SYM53C8XX_MAX_TAGS > 256 -#define SYM_CONF_MAX_TAG (256) -#else -#define SYM_CONF_MAX_TAG CONFIG_SCSI_SYM53C8XX_MAX_TAGS -#endif - -#ifndef CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS -#define CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS SYM_CONF_MAX_TAG -#endif - -/* - * Anyway, we configure the driver for at least 64 tags per LUN. :) - */ -#if SYM_CONF_MAX_TAG <= 64 -#define SYM_CONF_MAX_TAG_ORDER (6) -#elif SYM_CONF_MAX_TAG <= 128 -#define SYM_CONF_MAX_TAG_ORDER (7) -#else -#define SYM_CONF_MAX_TAG_ORDER (8) -#endif - -/* - * Max number of SG entries. - */ -#define SYM_CONF_MAX_SG (96) - -/* - * Driver setup structure. - * - * This structure is initialized from linux config options. - * It can be overridden at boot-up by the boot command line. - */ -struct sym_driver_setup { - u_short max_tag; - u_char burst_order; - u_char scsi_led; - u_char scsi_diff; - u_char irq_mode; - u_char scsi_bus_check; - u_char host_id; - - u_char verbose; - u_char settle_delay; - u_char use_nvram; - u_long excludes[8]; -}; - -#define SYM_SETUP_MAX_TAG sym_driver_setup.max_tag -#define SYM_SETUP_BURST_ORDER sym_driver_setup.burst_order -#define SYM_SETUP_SCSI_LED sym_driver_setup.scsi_led -#define SYM_SETUP_SCSI_DIFF sym_driver_setup.scsi_diff -#define SYM_SETUP_IRQ_MODE sym_driver_setup.irq_mode -#define SYM_SETUP_SCSI_BUS_CHECK sym_driver_setup.scsi_bus_check -#define SYM_SETUP_HOST_ID sym_driver_setup.host_id -#define boot_verbose sym_driver_setup.verbose - -/* - * Initial setup. - * - * Can be overriden at startup by a command line. - */ -#define SYM_LINUX_DRIVER_SETUP { \ - .max_tag = CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS, \ - .burst_order = 7, \ - .scsi_led = 1, \ - .scsi_diff = 1, \ - .irq_mode = 0, \ - .scsi_bus_check = 1, \ - .host_id = 7, \ - .verbose = 0, \ - .settle_delay = 3, \ - .use_nvram = 1, \ -} - -extern struct sym_driver_setup sym_driver_setup; -extern unsigned int sym_debug_flags; -#define DEBUG_FLAGS sym_debug_flags - -/* - * Max number of targets. - * Maximum is 16 and you are advised not to change this value. - */ -#ifndef SYM_CONF_MAX_TARGET -#define SYM_CONF_MAX_TARGET (16) -#endif - -/* - * Max number of logical units. - * SPI-2 allows up to 64 logical units, but in real life, target - * that implements more that 7 logical units are pretty rare. - * Anyway, the cost of accepting up to 64 logical unit is low in - * this driver, thus going with the maximum is acceptable. - */ -#ifndef SYM_CONF_MAX_LUN -#define SYM_CONF_MAX_LUN (64) -#endif - -/* - * Max number of IO control blocks queued to the controller. - * Each entry needs 8 bytes and the queues are allocated contiguously. - * Since we donnot want to allocate more than a page, the theorical - * maximum is PAGE_SIZE/8. For safety, we announce a bit less to the - * access method. :) - * When not supplied, as it is suggested, the driver compute some - * good value for this parameter. - */ -/* #define SYM_CONF_MAX_START (PAGE_SIZE/8 - 16) */ - -/* - * Support for Immediate Arbitration. - * Not advised. - */ -/* #define SYM_CONF_IARB_SUPPORT */ - -/* - * Only relevant if IARB support configured. - * - Max number of successive settings of IARB hints. - * - Set IARB on arbitration lost. - */ -#define SYM_CONF_IARB_MAX 3 -#define SYM_CONF_SET_IARB_ON_ARB_LOST 1 - -/* - * Returning wrong residuals may make problems. - * When zero, this define tells the driver to - * always return 0 as transfer residual. - * Btw, all my testings of residuals have succeeded. - */ -#define SYM_SETUP_RESIDUAL_SUPPORT 1 - -#endif /* SYM53C8XX_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_defs.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_defs.h deleted file mode 100644 index defccc47..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_defs.h +++ /dev/null @@ -1,792 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SYM_DEFS_H -#define SYM_DEFS_H - -#define SYM_VERSION "2.2.3" -#define SYM_DRIVER_NAME "sym-" SYM_VERSION - -/* - * SYM53C8XX device features descriptor. - */ -struct sym_chip { - u_short device_id; - u_short revision_id; - char *name; - u_char burst_max; /* log-base-2 of max burst */ - u_char offset_max; - u_char nr_divisor; - u_char lp_probe_bit; - u_int features; -#define FE_LED0 (1<<0) -#define FE_WIDE (1<<1) /* Wide data transfers */ -#define FE_ULTRA (1<<2) /* Ultra speed 20Mtrans/sec */ -#define FE_ULTRA2 (1<<3) /* Ultra 2 - 40 Mtrans/sec */ -#define FE_DBLR (1<<4) /* Clock doubler present */ -#define FE_QUAD (1<<5) /* Clock quadrupler present */ -#define FE_ERL (1<<6) /* Enable read line */ -#define FE_CLSE (1<<7) /* Cache line size enable */ -#define FE_WRIE (1<<8) /* Write & Invalidate enable */ -#define FE_ERMP (1<<9) /* Enable read multiple */ -#define FE_BOF (1<<10) /* Burst opcode fetch */ -#define FE_DFS (1<<11) /* DMA fifo size */ -#define FE_PFEN (1<<12) /* Prefetch enable */ -#define FE_LDSTR (1<<13) /* Load/Store supported */ -#define FE_RAM (1<<14) /* On chip RAM present */ -#define FE_VARCLK (1<<15) /* Clock frequency may vary */ -#define FE_RAM8K (1<<16) /* On chip RAM sized 8Kb */ -#define FE_64BIT (1<<17) /* 64-bit PCI BUS interface */ -#define FE_IO256 (1<<18) /* Requires full 256 bytes in PCI space */ -#define FE_NOPM (1<<19) /* Scripts handles phase mismatch */ -#define FE_LEDC (1<<20) /* Hardware control of LED */ -#define FE_ULTRA3 (1<<21) /* Ultra 3 - 80 Mtrans/sec DT */ -#define FE_66MHZ (1<<22) /* 66MHz PCI support */ -#define FE_CRC (1<<23) /* CRC support */ -#define FE_DIFF (1<<24) /* SCSI HVD support */ -#define FE_DFBC (1<<25) /* Have DFBC register */ -#define FE_LCKFRQ (1<<26) /* Have LCKFRQ */ -#define FE_C10 (1<<27) /* Various C10 core (mis)features */ -#define FE_U3EN (1<<28) /* U3EN bit usable */ -#define FE_DAC (1<<29) /* Support PCI DAC (64 bit addressing) */ -#define FE_ISTAT1 (1<<30) /* Have ISTAT1, MBOX0, MBOX1 registers */ - -#define FE_CACHE_SET (FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP) -#define FE_CACHE0_SET (FE_CACHE_SET & ~FE_ERL) -}; - -/* - * SYM53C8XX IO register data structure. - */ -struct sym_reg { -/*00*/ u8 nc_scntl0; /* full arb., ena parity, par->ATN */ - -/*01*/ u8 nc_scntl1; /* no reset */ - #define ISCON 0x10 /* connected to scsi */ - #define CRST 0x08 /* force reset */ - #define IARB 0x02 /* immediate arbitration */ - -/*02*/ u8 nc_scntl2; /* no disconnect expected */ - #define SDU 0x80 /* cmd: disconnect will raise error */ - #define CHM 0x40 /* sta: chained mode */ - #define WSS 0x08 /* sta: wide scsi send [W]*/ - #define WSR 0x01 /* sta: wide scsi received [W]*/ - -/*03*/ u8 nc_scntl3; /* cnf system clock dependent */ - #define EWS 0x08 /* cmd: enable wide scsi [W]*/ - #define ULTRA 0x80 /* cmd: ULTRA enable */ - /* bits 0-2, 7 rsvd for C1010 */ - -/*04*/ u8 nc_scid; /* cnf host adapter scsi address */ - #define RRE 0x40 /* r/w:e enable response to resel. */ - #define SRE 0x20 /* r/w:e enable response to select */ - -/*05*/ u8 nc_sxfer; /* ### Sync speed and count */ - /* bits 6-7 rsvd for C1010 */ - -/*06*/ u8 nc_sdid; /* ### Destination-ID */ - -/*07*/ u8 nc_gpreg; /* ??? IO-Pins */ - -/*08*/ u8 nc_sfbr; /* ### First byte received */ - -/*09*/ u8 nc_socl; - #define CREQ 0x80 /* r/w: SCSI-REQ */ - #define CACK 0x40 /* r/w: SCSI-ACK */ - #define CBSY 0x20 /* r/w: SCSI-BSY */ - #define CSEL 0x10 /* r/w: SCSI-SEL */ - #define CATN 0x08 /* r/w: SCSI-ATN */ - #define CMSG 0x04 /* r/w: SCSI-MSG */ - #define CC_D 0x02 /* r/w: SCSI-C_D */ - #define CI_O 0x01 /* r/w: SCSI-I_O */ - -/*0a*/ u8 nc_ssid; - -/*0b*/ u8 nc_sbcl; - -/*0c*/ u8 nc_dstat; - #define DFE 0x80 /* sta: dma fifo empty */ - #define MDPE 0x40 /* int: master data parity error */ - #define BF 0x20 /* int: script: bus fault */ - #define ABRT 0x10 /* int: script: command aborted */ - #define SSI 0x08 /* int: script: single step */ - #define SIR 0x04 /* int: script: interrupt instruct. */ - #define IID 0x01 /* int: script: illegal instruct. */ - -/*0d*/ u8 nc_sstat0; - #define ILF 0x80 /* sta: data in SIDL register lsb */ - #define ORF 0x40 /* sta: data in SODR register lsb */ - #define OLF 0x20 /* sta: data in SODL register lsb */ - #define AIP 0x10 /* sta: arbitration in progress */ - #define LOA 0x08 /* sta: arbitration lost */ - #define WOA 0x04 /* sta: arbitration won */ - #define IRST 0x02 /* sta: scsi reset signal */ - #define SDP 0x01 /* sta: scsi parity signal */ - -/*0e*/ u8 nc_sstat1; - #define FF3210 0xf0 /* sta: bytes in the scsi fifo */ - -/*0f*/ u8 nc_sstat2; - #define ILF1 0x80 /* sta: data in SIDL register msb[W]*/ - #define ORF1 0x40 /* sta: data in SODR register msb[W]*/ - #define OLF1 0x20 /* sta: data in SODL register msb[W]*/ - #define DM 0x04 /* sta: DIFFSENS mismatch (895/6 only) */ - #define LDSC 0x02 /* sta: disconnect & reconnect */ - -/*10*/ u8 nc_dsa; /* --> Base page */ -/*11*/ u8 nc_dsa1; -/*12*/ u8 nc_dsa2; -/*13*/ u8 nc_dsa3; - -/*14*/ u8 nc_istat; /* --> Main Command and status */ - #define CABRT 0x80 /* cmd: abort current operation */ - #define SRST 0x40 /* mod: reset chip */ - #define SIGP 0x20 /* r/w: message from host to script */ - #define SEM 0x10 /* r/w: message between host + script */ - #define CON 0x08 /* sta: connected to scsi */ - #define INTF 0x04 /* sta: int on the fly (reset by wr)*/ - #define SIP 0x02 /* sta: scsi-interrupt */ - #define DIP 0x01 /* sta: host/script interrupt */ - -/*15*/ u8 nc_istat1; /* 896 only */ - #define FLSH 0x04 /* sta: chip is flushing */ - #define SCRUN 0x02 /* sta: scripts are running */ - #define SIRQD 0x01 /* r/w: disable INT pin */ - -/*16*/ u8 nc_mbox0; /* 896 only */ -/*17*/ u8 nc_mbox1; /* 896 only */ - -/*18*/ u8 nc_ctest0; -/*19*/ u8 nc_ctest1; - -/*1a*/ u8 nc_ctest2; - #define CSIGP 0x40 - /* bits 0-2,7 rsvd for C1010 */ - -/*1b*/ u8 nc_ctest3; - #define FLF 0x08 /* cmd: flush dma fifo */ - #define CLF 0x04 /* cmd: clear dma fifo */ - #define FM 0x02 /* mod: fetch pin mode */ - #define WRIE 0x01 /* mod: write and invalidate enable */ - /* bits 4-7 rsvd for C1010 */ - -/*1c*/ u32 nc_temp; /* ### Temporary stack */ - -/*20*/ u8 nc_dfifo; -/*21*/ u8 nc_ctest4; - #define BDIS 0x80 /* mod: burst disable */ - #define MPEE 0x08 /* mod: master parity error enable */ - -/*22*/ u8 nc_ctest5; - #define DFS 0x20 /* mod: dma fifo size */ - /* bits 0-1, 3-7 rsvd for C1010 */ - -/*23*/ u8 nc_ctest6; - -/*24*/ u32 nc_dbc; /* ### Byte count and command */ -/*28*/ u32 nc_dnad; /* ### Next command register */ -/*2c*/ u32 nc_dsp; /* --> Script Pointer */ -/*30*/ u32 nc_dsps; /* --> Script pointer save/opcode#2 */ - -/*34*/ u8 nc_scratcha; /* Temporary register a */ -/*35*/ u8 nc_scratcha1; -/*36*/ u8 nc_scratcha2; -/*37*/ u8 nc_scratcha3; - -/*38*/ u8 nc_dmode; - #define BL_2 0x80 /* mod: burst length shift value +2 */ - #define BL_1 0x40 /* mod: burst length shift value +1 */ - #define ERL 0x08 /* mod: enable read line */ - #define ERMP 0x04 /* mod: enable read multiple */ - #define BOF 0x02 /* mod: burst op code fetch */ - -/*39*/ u8 nc_dien; -/*3a*/ u8 nc_sbr; - -/*3b*/ u8 nc_dcntl; /* --> Script execution control */ - #define CLSE 0x80 /* mod: cache line size enable */ - #define PFF 0x40 /* cmd: pre-fetch flush */ - #define PFEN 0x20 /* mod: pre-fetch enable */ - #define SSM 0x10 /* mod: single step mode */ - #define IRQM 0x08 /* mod: irq mode (1 = totem pole !) */ - #define STD 0x04 /* cmd: start dma mode */ - #define IRQD 0x02 /* mod: irq disable */ - #define NOCOM 0x01 /* cmd: protect sfbr while reselect */ - /* bits 0-1 rsvd for C1010 */ - -/*3c*/ u32 nc_adder; - -/*40*/ u16 nc_sien; /* -->: interrupt enable */ -/*42*/ u16 nc_sist; /* <--: interrupt status */ - #define SBMC 0x1000/* sta: SCSI Bus Mode Change (895/6 only) */ - #define STO 0x0400/* sta: timeout (select) */ - #define GEN 0x0200/* sta: timeout (general) */ - #define HTH 0x0100/* sta: timeout (handshake) */ - #define MA 0x80 /* sta: phase mismatch */ - #define CMP 0x40 /* sta: arbitration complete */ - #define SEL 0x20 /* sta: selected by another device */ - #define RSL 0x10 /* sta: reselected by another device*/ - #define SGE 0x08 /* sta: gross error (over/underflow)*/ - #define UDC 0x04 /* sta: unexpected disconnect */ - #define RST 0x02 /* sta: scsi bus reset detected */ - #define PAR 0x01 /* sta: scsi parity error */ - -/*44*/ u8 nc_slpar; -/*45*/ u8 nc_swide; -/*46*/ u8 nc_macntl; -/*47*/ u8 nc_gpcntl; -/*48*/ u8 nc_stime0; /* cmd: timeout for select&handshake*/ -/*49*/ u8 nc_stime1; /* cmd: timeout user defined */ -/*4a*/ u16 nc_respid; /* sta: Reselect-IDs */ - -/*4c*/ u8 nc_stest0; - -/*4d*/ u8 nc_stest1; - #define SCLK 0x80 /* Use the PCI clock as SCSI clock */ - #define DBLEN 0x08 /* clock doubler running */ - #define DBLSEL 0x04 /* clock doubler selected */ - - -/*4e*/ u8 nc_stest2; - #define ROF 0x40 /* reset scsi offset (after gross error!) */ - #define EXT 0x02 /* extended filtering */ - -/*4f*/ u8 nc_stest3; - #define TE 0x80 /* c: tolerAnt enable */ - #define HSC 0x20 /* c: Halt SCSI Clock */ - #define CSF 0x02 /* c: clear scsi fifo */ - -/*50*/ u16 nc_sidl; /* Lowlevel: latched from scsi data */ -/*52*/ u8 nc_stest4; - #define SMODE 0xc0 /* SCSI bus mode (895/6 only) */ - #define SMODE_HVD 0x40 /* High Voltage Differential */ - #define SMODE_SE 0x80 /* Single Ended */ - #define SMODE_LVD 0xc0 /* Low Voltage Differential */ - #define LCKFRQ 0x20 /* Frequency Lock (895/6 only) */ - /* bits 0-5 rsvd for C1010 */ - -/*53*/ u8 nc_53_; -/*54*/ u16 nc_sodl; /* Lowlevel: data out to scsi data */ -/*56*/ u8 nc_ccntl0; /* Chip Control 0 (896) */ - #define ENPMJ 0x80 /* Enable Phase Mismatch Jump */ - #define PMJCTL 0x40 /* Phase Mismatch Jump Control */ - #define ENNDJ 0x20 /* Enable Non Data PM Jump */ - #define DISFC 0x10 /* Disable Auto FIFO Clear */ - #define DILS 0x02 /* Disable Internal Load/Store */ - #define DPR 0x01 /* Disable Pipe Req */ - -/*57*/ u8 nc_ccntl1; /* Chip Control 1 (896) */ - #define ZMOD 0x80 /* High Impedance Mode */ - #define DDAC 0x08 /* Disable Dual Address Cycle */ - #define XTIMOD 0x04 /* 64-bit Table Ind. Indexing Mode */ - #define EXTIBMV 0x02 /* Enable 64-bit Table Ind. BMOV */ - #define EXDBMV 0x01 /* Enable 64-bit Direct BMOV */ - -/*58*/ u16 nc_sbdl; /* Lowlevel: data from scsi data */ -/*5a*/ u16 nc_5a_; - -/*5c*/ u8 nc_scr0; /* Working register B */ -/*5d*/ u8 nc_scr1; -/*5e*/ u8 nc_scr2; -/*5f*/ u8 nc_scr3; - -/*60*/ u8 nc_scrx[64]; /* Working register C-R */ -/*a0*/ u32 nc_mmrs; /* Memory Move Read Selector */ -/*a4*/ u32 nc_mmws; /* Memory Move Write Selector */ -/*a8*/ u32 nc_sfs; /* Script Fetch Selector */ -/*ac*/ u32 nc_drs; /* DSA Relative Selector */ -/*b0*/ u32 nc_sbms; /* Static Block Move Selector */ -/*b4*/ u32 nc_dbms; /* Dynamic Block Move Selector */ -/*b8*/ u32 nc_dnad64; /* DMA Next Address 64 */ -/*bc*/ u16 nc_scntl4; /* C1010 only */ - #define U3EN 0x80 /* Enable Ultra 3 */ - #define AIPCKEN 0x40 /* AIP checking enable */ - /* Also enable AIP generation on C10-33*/ - #define XCLKH_DT 0x08 /* Extra clock of data hold on DT edge */ - #define XCLKH_ST 0x04 /* Extra clock of data hold on ST edge */ - #define XCLKS_DT 0x02 /* Extra clock of data set on DT edge */ - #define XCLKS_ST 0x01 /* Extra clock of data set on ST edge */ -/*be*/ u8 nc_aipcntl0; /* AIP Control 0 C1010 only */ -/*bf*/ u8 nc_aipcntl1; /* AIP Control 1 C1010 only */ - #define DISAIP 0x08 /* Disable AIP generation C10-66 only */ -/*c0*/ u32 nc_pmjad1; /* Phase Mismatch Jump Address 1 */ -/*c4*/ u32 nc_pmjad2; /* Phase Mismatch Jump Address 2 */ -/*c8*/ u8 nc_rbc; /* Remaining Byte Count */ -/*c9*/ u8 nc_rbc1; -/*ca*/ u8 nc_rbc2; -/*cb*/ u8 nc_rbc3; - -/*cc*/ u8 nc_ua; /* Updated Address */ -/*cd*/ u8 nc_ua1; -/*ce*/ u8 nc_ua2; -/*cf*/ u8 nc_ua3; -/*d0*/ u32 nc_esa; /* Entry Storage Address */ -/*d4*/ u8 nc_ia; /* Instruction Address */ -/*d5*/ u8 nc_ia1; -/*d6*/ u8 nc_ia2; -/*d7*/ u8 nc_ia3; -/*d8*/ u32 nc_sbc; /* SCSI Byte Count (3 bytes only) */ -/*dc*/ u32 nc_csbc; /* Cumulative SCSI Byte Count */ - /* Following for C1010 only */ -/*e0*/ u16 nc_crcpad; /* CRC Value */ -/*e2*/ u8 nc_crccntl0; /* CRC control register */ - #define SNDCRC 0x10 /* Send CRC Request */ -/*e3*/ u8 nc_crccntl1; /* CRC control register */ -/*e4*/ u32 nc_crcdata; /* CRC data register */ -/*e8*/ u32 nc_e8_; -/*ec*/ u32 nc_ec_; -/*f0*/ u16 nc_dfbc; /* DMA FIFO byte count */ -}; - -/*----------------------------------------------------------- - * - * Utility macros for the script. - * - *----------------------------------------------------------- - */ - -#define REGJ(p,r) (offsetof(struct sym_reg, p ## r)) -#define REG(r) REGJ (nc_, r) - -/*----------------------------------------------------------- - * - * SCSI phases - * - *----------------------------------------------------------- - */ - -#define SCR_DATA_OUT 0x00000000 -#define SCR_DATA_IN 0x01000000 -#define SCR_COMMAND 0x02000000 -#define SCR_STATUS 0x03000000 -#define SCR_DT_DATA_OUT 0x04000000 -#define SCR_DT_DATA_IN 0x05000000 -#define SCR_MSG_OUT 0x06000000 -#define SCR_MSG_IN 0x07000000 -/* DT phases are illegal for non Ultra3 mode */ -#define SCR_ILG_OUT 0x04000000 -#define SCR_ILG_IN 0x05000000 - -/*----------------------------------------------------------- - * - * Data transfer via SCSI. - * - *----------------------------------------------------------- - * - * MOVE_ABS (LEN) - * <> - * - * MOVE_IND (LEN) - * <> - * - * MOVE_TBL - * <> - * - *----------------------------------------------------------- - */ - -#define OPC_MOVE 0x08000000 - -#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l)) -/* #define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l)) */ -#define SCR_MOVE_TBL (0x10000000 | OPC_MOVE) - -#define SCR_CHMOV_ABS(l) ((0x00000000) | (l)) -/* #define SCR_CHMOV_IND(l) ((0x20000000) | (l)) */ -#define SCR_CHMOV_TBL (0x10000000) - -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT -/* We steal the `indirect addressing' flag for target mode MOVE in scripts */ - -#define OPC_TCHMOVE 0x08000000 - -#define SCR_TCHMOVE_ABS(l) ((0x20000000 | OPC_TCHMOVE) | (l)) -#define SCR_TCHMOVE_TBL (0x30000000 | OPC_TCHMOVE) - -#define SCR_TMOV_ABS(l) ((0x20000000) | (l)) -#define SCR_TMOV_TBL (0x30000000) -#endif - -struct sym_tblmove { - u32 size; - u32 addr; -}; - -/*----------------------------------------------------------- - * - * Selection - * - *----------------------------------------------------------- - * - * SEL_ABS | SCR_ID (0..15) [ | REL_JMP] - * <> - * - * SEL_TBL | << dnad_offset>> [ | REL_JMP] - * <> - * - *----------------------------------------------------------- - */ - -#define SCR_SEL_ABS 0x40000000 -#define SCR_SEL_ABS_ATN 0x41000000 -#define SCR_SEL_TBL 0x42000000 -#define SCR_SEL_TBL_ATN 0x43000000 - -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT -#define SCR_RESEL_ABS 0x40000000 -#define SCR_RESEL_ABS_ATN 0x41000000 -#define SCR_RESEL_TBL 0x42000000 -#define SCR_RESEL_TBL_ATN 0x43000000 -#endif - -struct sym_tblsel { - u_char sel_scntl4; /* C1010 only */ - u_char sel_sxfer; - u_char sel_id; - u_char sel_scntl3; -}; - -#define SCR_JMP_REL 0x04000000 -#define SCR_ID(id) (((u32)(id)) << 16) - -/*----------------------------------------------------------- - * - * Waiting for Disconnect or Reselect - * - *----------------------------------------------------------- - * - * WAIT_DISC - * dummy: <> - * - * WAIT_RESEL - * <> - * - *----------------------------------------------------------- - */ - -#define SCR_WAIT_DISC 0x48000000 -#define SCR_WAIT_RESEL 0x50000000 - -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT -#define SCR_DISCONNECT 0x48000000 -#endif - -/*----------------------------------------------------------- - * - * Bit Set / Reset - * - *----------------------------------------------------------- - * - * SET (flags {|.. }) - * - * CLR (flags {|.. }) - * - *----------------------------------------------------------- - */ - -#define SCR_SET(f) (0x58000000 | (f)) -#define SCR_CLR(f) (0x60000000 | (f)) - -#define SCR_CARRY 0x00000400 -#define SCR_TRG 0x00000200 -#define SCR_ACK 0x00000040 -#define SCR_ATN 0x00000008 - - -/*----------------------------------------------------------- - * - * Memory to memory move - * - *----------------------------------------------------------- - * - * COPY (bytecount) - * << source_address >> - * << destination_address >> - * - * SCR_COPY sets the NO FLUSH option by default. - * SCR_COPY_F does not set this option. - * - * For chips which do not support this option, - * sym_fw_bind_script() will remove this bit. - * - *----------------------------------------------------------- - */ - -#define SCR_NO_FLUSH 0x01000000 - -#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n)) -#define SCR_COPY_F(n) (0xc0000000 | (n)) - -/*----------------------------------------------------------- - * - * Register move and binary operations - * - *----------------------------------------------------------- - * - * SFBR_REG (reg, op, data) reg = SFBR op data - * << 0 >> - * - * REG_SFBR (reg, op, data) SFBR = reg op data - * << 0 >> - * - * REG_REG (reg, op, data) reg = reg op data - * << 0 >> - * - *----------------------------------------------------------- - * - * On 825A, 875, 895 and 896 chips the content - * of SFBR register can be used as data (SCR_SFBR_DATA). - * The 896 has additionnal IO registers starting at - * offset 0x80. Bit 7 of register offset is stored in - * bit 7 of the SCRIPTS instruction first DWORD. - * - *----------------------------------------------------------- - */ - -#define SCR_REG_OFS(ofs) ((((ofs) & 0x7f) << 16ul) + ((ofs) & 0x80)) - -#define SCR_SFBR_REG(reg,op,data) \ - (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) - -#define SCR_REG_SFBR(reg,op,data) \ - (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) - -#define SCR_REG_REG(reg,op,data) \ - (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul)) - - -#define SCR_LOAD 0x00000000 -#define SCR_SHL 0x01000000 -#define SCR_OR 0x02000000 -#define SCR_XOR 0x03000000 -#define SCR_AND 0x04000000 -#define SCR_SHR 0x05000000 -#define SCR_ADD 0x06000000 -#define SCR_ADDC 0x07000000 - -#define SCR_SFBR_DATA (0x00800000>>8ul) /* Use SFBR as data */ - -/*----------------------------------------------------------- - * - * FROM_REG (reg) SFBR = reg - * << 0 >> - * - * TO_REG (reg) reg = SFBR - * << 0 >> - * - * LOAD_REG (reg, data) reg = - * << 0 >> - * - * LOAD_SFBR(data) SFBR = - * << 0 >> - * - *----------------------------------------------------------- - */ - -#define SCR_FROM_REG(reg) \ - SCR_REG_SFBR(reg,SCR_OR,0) - -#define SCR_TO_REG(reg) \ - SCR_SFBR_REG(reg,SCR_OR,0) - -#define SCR_LOAD_REG(reg,data) \ - SCR_REG_REG(reg,SCR_LOAD,data) - -#define SCR_LOAD_SFBR(data) \ - (SCR_REG_SFBR (gpreg, SCR_LOAD, data)) - -/*----------------------------------------------------------- - * - * LOAD from memory to register. - * STORE from register to memory. - * - * Only supported by 810A, 860, 825A, 875, 895 and 896. - * - *----------------------------------------------------------- - * - * LOAD_ABS (LEN) - * <> - * - * LOAD_REL (LEN) (DSA relative) - * <> - * - *----------------------------------------------------------- - */ - -#define SCR_REG_OFS2(ofs) (((ofs) & 0xff) << 16ul) -#define SCR_NO_FLUSH2 0x02000000 -#define SCR_DSA_REL2 0x10000000 - -#define SCR_LOAD_R(reg, how, n) \ - (0xe1000000 | how | (SCR_REG_OFS2(REG(reg))) | (n)) - -#define SCR_STORE_R(reg, how, n) \ - (0xe0000000 | how | (SCR_REG_OFS2(REG(reg))) | (n)) - -#define SCR_LOAD_ABS(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2, n) -#define SCR_LOAD_REL(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n) -#define SCR_LOAD_ABS_F(reg, n) SCR_LOAD_R(reg, 0, n) -#define SCR_LOAD_REL_F(reg, n) SCR_LOAD_R(reg, SCR_DSA_REL2, n) - -#define SCR_STORE_ABS(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2, n) -#define SCR_STORE_REL(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n) -#define SCR_STORE_ABS_F(reg, n) SCR_STORE_R(reg, 0, n) -#define SCR_STORE_REL_F(reg, n) SCR_STORE_R(reg, SCR_DSA_REL2, n) - - -/*----------------------------------------------------------- - * - * Waiting for Disconnect or Reselect - * - *----------------------------------------------------------- - * - * JUMP [ | IFTRUE/IFFALSE ( ... ) ] - * <
> - * - * JUMPR [ | IFTRUE/IFFALSE ( ... ) ] - * <> - * - * CALL [ | IFTRUE/IFFALSE ( ... ) ] - * <
> - * - * CALLR [ | IFTRUE/IFFALSE ( ... ) ] - * <> - * - * RETURN [ | IFTRUE/IFFALSE ( ... ) ] - * <> - * - * INT [ | IFTRUE/IFFALSE ( ... ) ] - * <> - * - * INT_FLY [ | IFTRUE/IFFALSE ( ... ) ] - * <> - * - * Conditions: - * WHEN (phase) - * IF (phase) - * CARRYSET - * DATA (data, mask) - * - *----------------------------------------------------------- - */ - -#define SCR_NO_OP 0x80000000 -#define SCR_JUMP 0x80080000 -#define SCR_JUMP64 0x80480000 -#define SCR_JUMPR 0x80880000 -#define SCR_CALL 0x88080000 -#define SCR_CALLR 0x88880000 -#define SCR_RETURN 0x90080000 -#define SCR_INT 0x98080000 -#define SCR_INT_FLY 0x98180000 - -#define IFFALSE(arg) (0x00080000 | (arg)) -#define IFTRUE(arg) (0x00000000 | (arg)) - -#define WHEN(phase) (0x00030000 | (phase)) -#define IF(phase) (0x00020000 | (phase)) - -#define DATA(D) (0x00040000 | ((D) & 0xff)) -#define MASK(D,M) (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff)) - -#define CARRYSET (0x00200000) - -/*----------------------------------------------------------- - * - * SCSI constants. - * - *----------------------------------------------------------- - */ - -/* - * Messages - */ - -#define M_COMPLETE COMMAND_COMPLETE -#define M_EXTENDED EXTENDED_MESSAGE -#define M_SAVE_DP SAVE_POINTERS -#define M_RESTORE_DP RESTORE_POINTERS -#define M_DISCONNECT DISCONNECT -#define M_ID_ERROR INITIATOR_ERROR -#define M_ABORT ABORT_TASK_SET -#define M_REJECT MESSAGE_REJECT -#define M_NOOP NOP -#define M_PARITY MSG_PARITY_ERROR -#define M_LCOMPLETE LINKED_CMD_COMPLETE -#define M_FCOMPLETE LINKED_FLG_CMD_COMPLETE -#define M_RESET TARGET_RESET -#define M_ABORT_TAG ABORT_TASK -#define M_CLEAR_QUEUE CLEAR_TASK_SET -#define M_INIT_REC INITIATE_RECOVERY -#define M_REL_REC RELEASE_RECOVERY -#define M_TERMINATE (0x11) -#define M_SIMPLE_TAG SIMPLE_QUEUE_TAG -#define M_HEAD_TAG HEAD_OF_QUEUE_TAG -#define M_ORDERED_TAG ORDERED_QUEUE_TAG -#define M_IGN_RESIDUE IGNORE_WIDE_RESIDUE - -#define M_X_MODIFY_DP EXTENDED_MODIFY_DATA_POINTER -#define M_X_SYNC_REQ EXTENDED_SDTR -#define M_X_WIDE_REQ EXTENDED_WDTR -#define M_X_PPR_REQ EXTENDED_PPR - -/* - * PPR protocol options - */ -#define PPR_OPT_IU (0x01) -#define PPR_OPT_DT (0x02) -#define PPR_OPT_QAS (0x04) -#define PPR_OPT_MASK (0x07) - -/* - * Status - */ - -#define S_GOOD SAM_STAT_GOOD -#define S_CHECK_COND SAM_STAT_CHECK_CONDITION -#define S_COND_MET SAM_STAT_CONDITION_MET -#define S_BUSY SAM_STAT_BUSY -#define S_INT SAM_STAT_INTERMEDIATE -#define S_INT_COND_MET SAM_STAT_INTERMEDIATE_CONDITION_MET -#define S_CONFLICT SAM_STAT_RESERVATION_CONFLICT -#define S_TERMINATED SAM_STAT_COMMAND_TERMINATED -#define S_QUEUE_FULL SAM_STAT_TASK_SET_FULL -#define S_ILLEGAL (0xff) - -#endif /* defined SYM_DEFS_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.c b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.c deleted file mode 100644 index 190770bd..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.c +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sym_glue.h" - -/* - * Macros used for all firmwares. - */ -#define SYM_GEN_A(s, label) ((short) offsetof(s, label)), -#define SYM_GEN_B(s, label) ((short) offsetof(s, label)), -#define SYM_GEN_Z(s, label) ((short) offsetof(s, label)), -#define PADDR_A(label) SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label) -#define PADDR_B(label) SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label) - - -#if SYM_CONF_GENERIC_SUPPORT -/* - * Allocate firmware #1 script area. - */ -#define SYM_FWA_SCR sym_fw1a_scr -#define SYM_FWB_SCR sym_fw1b_scr -#define SYM_FWZ_SCR sym_fw1z_scr -#include "sym_fw1.h" -static struct sym_fwa_ofs sym_fw1a_ofs = { - SYM_GEN_FW_A(struct SYM_FWA_SCR) -}; -static struct sym_fwb_ofs sym_fw1b_ofs = { - SYM_GEN_FW_B(struct SYM_FWB_SCR) -}; -static struct sym_fwz_ofs sym_fw1z_ofs = { - SYM_GEN_FW_Z(struct SYM_FWZ_SCR) -}; -#undef SYM_FWA_SCR -#undef SYM_FWB_SCR -#undef SYM_FWZ_SCR -#endif /* SYM_CONF_GENERIC_SUPPORT */ - -/* - * Allocate firmware #2 script area. - */ -#define SYM_FWA_SCR sym_fw2a_scr -#define SYM_FWB_SCR sym_fw2b_scr -#define SYM_FWZ_SCR sym_fw2z_scr -#include "sym_fw2.h" -static struct sym_fwa_ofs sym_fw2a_ofs = { - SYM_GEN_FW_A(struct SYM_FWA_SCR) -}; -static struct sym_fwb_ofs sym_fw2b_ofs = { - SYM_GEN_FW_B(struct SYM_FWB_SCR) - SYM_GEN_B(struct SYM_FWB_SCR, start64) - SYM_GEN_B(struct SYM_FWB_SCR, pm_handle) -}; -static struct sym_fwz_ofs sym_fw2z_ofs = { - SYM_GEN_FW_Z(struct SYM_FWZ_SCR) -}; -#undef SYM_FWA_SCR -#undef SYM_FWB_SCR -#undef SYM_FWZ_SCR - -#undef SYM_GEN_A -#undef SYM_GEN_B -#undef SYM_GEN_Z -#undef PADDR_A -#undef PADDR_B - -#if SYM_CONF_GENERIC_SUPPORT -/* - * Patch routine for firmware #1. - */ -static void -sym_fw1_patch(struct Scsi_Host *shost) -{ - struct sym_hcb *np = sym_get_hcb(shost); - struct sym_fw1a_scr *scripta0; - struct sym_fw1b_scr *scriptb0; - - scripta0 = (struct sym_fw1a_scr *) np->scripta0; - scriptb0 = (struct sym_fw1b_scr *) np->scriptb0; - - /* - * Remove LED support if not needed. - */ - if (!(np->features & FE_LED0)) { - scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); - scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); - scripta0->start[0] = cpu_to_scr(SCR_NO_OP); - } - -#ifdef SYM_CONF_IARB_SUPPORT - /* - * If user does not want to use IMMEDIATE ARBITRATION - * when we are reselected while attempting to arbitrate, - * patch the SCRIPTS accordingly with a SCRIPT NO_OP. - */ - if (!SYM_CONF_SET_IARB_ON_ARB_LOST) - scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); -#endif - /* - * Patch some data in SCRIPTS. - * - start and done queue initial bus address. - * - target bus address table bus address. - */ - scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); - scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); - scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); -} -#endif /* SYM_CONF_GENERIC_SUPPORT */ - -/* - * Patch routine for firmware #2. - */ -static void -sym_fw2_patch(struct Scsi_Host *shost) -{ - struct sym_data *sym_data = shost_priv(shost); - struct pci_dev *pdev = sym_data->pdev; - struct sym_hcb *np = sym_data->ncb; - struct sym_fw2a_scr *scripta0; - struct sym_fw2b_scr *scriptb0; - - scripta0 = (struct sym_fw2a_scr *) np->scripta0; - scriptb0 = (struct sym_fw2b_scr *) np->scriptb0; - - /* - * Remove LED support if not needed. - */ - if (!(np->features & FE_LED0)) { - scripta0->idle[0] = cpu_to_scr(SCR_NO_OP); - scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP); - scripta0->start[0] = cpu_to_scr(SCR_NO_OP); - } - -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 - /* - * Remove useless 64 bit DMA specific SCRIPTS, - * when this feature is not available. - */ - if (!use_dac(np)) { - scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP); - scripta0->is_dmap_dirty[1] = 0; - scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP); - scripta0->is_dmap_dirty[3] = 0; - } -#endif - -#ifdef SYM_CONF_IARB_SUPPORT - /* - * If user does not want to use IMMEDIATE ARBITRATION - * when we are reselected while attempting to arbitrate, - * patch the SCRIPTS accordingly with a SCRIPT NO_OP. - */ - if (!SYM_CONF_SET_IARB_ON_ARB_LOST) - scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP); -#endif - /* - * Patch some variable in SCRIPTS. - * - start and done queue initial bus address. - * - target bus address table bus address. - */ - scriptb0->startpos[0] = cpu_to_scr(np->squeue_ba); - scriptb0->done_pos[0] = cpu_to_scr(np->dqueue_ba); - scriptb0->targtbl[0] = cpu_to_scr(np->targtbl_ba); - - /* - * Remove the load of SCNTL4 on reselection if not a C10. - */ - if (!(np->features & FE_C10)) { - scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP); - scripta0->resel_scntl4[1] = cpu_to_scr(0); - } - - /* - * Remove a couple of work-arounds specific to C1010 if - * they are not desirable. See `sym_fw2.h' for more details. - */ - if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 && - pdev->revision < 0x1 && - np->pciclk_khz < 60000)) { - scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP); - scripta0->datao_phase[1] = cpu_to_scr(0); - } - if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* && - pdev->revision < 0xff */)) { - scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP); - scripta0->sel_done[1] = cpu_to_scr(0); - } - - /* - * Patch some other variables in SCRIPTS. - * These ones are loaded by the SCRIPTS processor. - */ - scriptb0->pm0_data_addr[0] = - cpu_to_scr(np->scripta_ba + - offsetof(struct sym_fw2a_scr, pm0_data)); - scriptb0->pm1_data_addr[0] = - cpu_to_scr(np->scripta_ba + - offsetof(struct sym_fw2a_scr, pm1_data)); -} - -/* - * Fill the data area in scripts. - * To be done for all firmwares. - */ -static void -sym_fw_fill_data (u32 *in, u32 *out) -{ - int i; - - for (i = 0; i < SYM_CONF_MAX_SG; i++) { - *in++ = SCR_CHMOV_TBL ^ SCR_DATA_IN; - *in++ = offsetof (struct sym_dsb, data[i]); - *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT; - *out++ = offsetof (struct sym_dsb, data[i]); - } -} - -/* - * Setup useful script bus addresses. - * To be done for all firmwares. - */ -static void -sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw) -{ - u32 *pa; - u_short *po; - int i; - - /* - * Build the bus address table for script A - * from the script A offset table. - */ - po = (u_short *) fw->a_ofs; - pa = (u32 *) &np->fwa_bas; - for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++) - pa[i] = np->scripta_ba + po[i]; - - /* - * Same for script B. - */ - po = (u_short *) fw->b_ofs; - pa = (u32 *) &np->fwb_bas; - for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++) - pa[i] = np->scriptb_ba + po[i]; - - /* - * Same for script Z. - */ - po = (u_short *) fw->z_ofs; - pa = (u32 *) &np->fwz_bas; - for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++) - pa[i] = np->scriptz_ba + po[i]; -} - -#if SYM_CONF_GENERIC_SUPPORT -/* - * Setup routine for firmware #1. - */ -static void -sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw) -{ - struct sym_fw1a_scr *scripta0; - struct sym_fw1b_scr *scriptb0; - - scripta0 = (struct sym_fw1a_scr *) np->scripta0; - scriptb0 = (struct sym_fw1b_scr *) np->scriptb0; - - /* - * Fill variable parts in scripts. - */ - sym_fw_fill_data(scripta0->data_in, scripta0->data_out); - - /* - * Setup bus addresses used from the C code.. - */ - sym_fw_setup_bus_addresses(np, fw); -} -#endif /* SYM_CONF_GENERIC_SUPPORT */ - -/* - * Setup routine for firmware #2. - */ -static void -sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw) -{ - struct sym_fw2a_scr *scripta0; - struct sym_fw2b_scr *scriptb0; - - scripta0 = (struct sym_fw2a_scr *) np->scripta0; - scriptb0 = (struct sym_fw2b_scr *) np->scriptb0; - - /* - * Fill variable parts in scripts. - */ - sym_fw_fill_data(scripta0->data_in, scripta0->data_out); - - /* - * Setup bus addresses used from the C code.. - */ - sym_fw_setup_bus_addresses(np, fw); -} - -/* - * Allocate firmware descriptors. - */ -#if SYM_CONF_GENERIC_SUPPORT -static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic"); -#endif /* SYM_CONF_GENERIC_SUPPORT */ -static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based"); - -/* - * Find the most appropriate firmware for a chip. - */ -struct sym_fw * -sym_find_firmware(struct sym_chip *chip) -{ - if (chip->features & FE_LDSTR) - return &sym_fw2; -#if SYM_CONF_GENERIC_SUPPORT - else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC))) - return &sym_fw1; -#endif - else - return NULL; -} - -/* - * Bind a script to physical addresses. - */ -void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len) -{ - u32 opcode, new, old, tmp1, tmp2; - u32 *end, *cur; - int relocs; - - cur = start; - end = start + len/4; - - while (cur < end) { - - opcode = *cur; - - /* - * If we forget to change the length - * in scripts, a field will be - * padded with 0. This is an illegal - * command. - */ - if (opcode == 0) { - printf ("%s: ERROR0 IN SCRIPT at %d.\n", - sym_name(np), (int) (cur-start)); - ++cur; - continue; - }; - - /* - * We use the bogus value 0xf00ff00f ;-) - * to reserve data area in SCRIPTS. - */ - if (opcode == SCR_DATA_ZERO) { - *cur++ = 0; - continue; - } - - if (DEBUG_FLAGS & DEBUG_SCRIPT) - printf ("%d: <%x>\n", (int) (cur-start), - (unsigned)opcode); - - /* - * We don't have to decode ALL commands - */ - switch (opcode >> 28) { - case 0xf: - /* - * LOAD / STORE DSA relative, don't relocate. - */ - relocs = 0; - break; - case 0xe: - /* - * LOAD / STORE absolute. - */ - relocs = 1; - break; - case 0xc: - /* - * COPY has TWO arguments. - */ - relocs = 2; - tmp1 = cur[1]; - tmp2 = cur[2]; - if ((tmp1 ^ tmp2) & 3) { - printf ("%s: ERROR1 IN SCRIPT at %d.\n", - sym_name(np), (int) (cur-start)); - } - /* - * If PREFETCH feature not enabled, remove - * the NO FLUSH bit if present. - */ - if ((opcode & SCR_NO_FLUSH) && - !(np->features & FE_PFEN)) { - opcode = (opcode & ~SCR_NO_FLUSH); - } - break; - case 0x0: - /* - * MOVE/CHMOV (absolute address) - */ - if (!(np->features & FE_WIDE)) - opcode = (opcode | OPC_MOVE); - relocs = 1; - break; - case 0x1: - /* - * MOVE/CHMOV (table indirect) - */ - if (!(np->features & FE_WIDE)) - opcode = (opcode | OPC_MOVE); - relocs = 0; - break; -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - case 0x2: - /* - * MOVE/CHMOV in target role (absolute address) - */ - opcode &= ~0x20000000; - if (!(np->features & FE_WIDE)) - opcode = (opcode & ~OPC_TCHMOVE); - relocs = 1; - break; - case 0x3: - /* - * MOVE/CHMOV in target role (table indirect) - */ - opcode &= ~0x20000000; - if (!(np->features & FE_WIDE)) - opcode = (opcode & ~OPC_TCHMOVE); - relocs = 0; - break; -#endif - case 0x8: - /* - * JUMP / CALL - * don't relocate if relative :-) - */ - if (opcode & 0x00800000) - relocs = 0; - else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/ - relocs = 2; - else - relocs = 1; - break; - case 0x4: - case 0x5: - case 0x6: - case 0x7: - relocs = 1; - break; - default: - relocs = 0; - break; - }; - - /* - * Scriptify:) the opcode. - */ - *cur++ = cpu_to_scr(opcode); - - /* - * If no relocation, assume 1 argument - * and just scriptize:) it. - */ - if (!relocs) { - *cur = cpu_to_scr(*cur); - ++cur; - continue; - } - - /* - * Otherwise performs all needed relocations. - */ - while (relocs--) { - old = *cur; - - switch (old & RELOC_MASK) { - case RELOC_REGISTER: - new = (old & ~RELOC_MASK) + np->mmio_ba; - break; - case RELOC_LABEL_A: - new = (old & ~RELOC_MASK) + np->scripta_ba; - break; - case RELOC_LABEL_B: - new = (old & ~RELOC_MASK) + np->scriptb_ba; - break; - case RELOC_SOFTC: - new = (old & ~RELOC_MASK) + np->hcb_ba; - break; - case 0: - /* - * Don't relocate a 0 address. - * They are mostly used for patched or - * script self-modified areas. - */ - if (old == 0) { - new = old; - break; - } - /* fall through */ - default: - new = 0; - panic("sym_fw_bind_script: " - "weird relocation %x\n", old); - break; - } - - *cur++ = cpu_to_scr(new); - } - }; -} diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.h deleted file mode 100644 index ae7e0f9e..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SYM_FW_H -#define SYM_FW_H -/* - * Macro used to generate interfaces for script A. - */ -#define SYM_GEN_FW_A(s) \ - SYM_GEN_A(s, start) SYM_GEN_A(s, getjob_begin) \ - SYM_GEN_A(s, getjob_end) \ - SYM_GEN_A(s, select) SYM_GEN_A(s, wf_sel_done) \ - SYM_GEN_A(s, send_ident) \ - SYM_GEN_A(s, dispatch) SYM_GEN_A(s, init) \ - SYM_GEN_A(s, clrack) SYM_GEN_A(s, complete_error) \ - SYM_GEN_A(s, done) SYM_GEN_A(s, done_end) \ - SYM_GEN_A(s, idle) SYM_GEN_A(s, ungetjob) \ - SYM_GEN_A(s, reselect) \ - SYM_GEN_A(s, resel_tag) SYM_GEN_A(s, resel_dsa) \ - SYM_GEN_A(s, resel_no_tag) \ - SYM_GEN_A(s, data_in) SYM_GEN_A(s, data_in2) \ - SYM_GEN_A(s, data_out) SYM_GEN_A(s, data_out2) \ - SYM_GEN_A(s, pm0_data) SYM_GEN_A(s, pm1_data) - -/* - * Macro used to generate interfaces for script B. - */ -#define SYM_GEN_FW_B(s) \ - SYM_GEN_B(s, no_data) \ - SYM_GEN_B(s, sel_for_abort) SYM_GEN_B(s, sel_for_abort_1) \ - SYM_GEN_B(s, msg_bad) SYM_GEN_B(s, msg_weird) \ - SYM_GEN_B(s, wdtr_resp) SYM_GEN_B(s, send_wdtr) \ - SYM_GEN_B(s, sdtr_resp) SYM_GEN_B(s, send_sdtr) \ - SYM_GEN_B(s, ppr_resp) SYM_GEN_B(s, send_ppr) \ - SYM_GEN_B(s, nego_bad_phase) \ - SYM_GEN_B(s, ident_break) SYM_GEN_B(s, ident_break_atn) \ - SYM_GEN_B(s, sdata_in) SYM_GEN_B(s, resel_bad_lun) \ - SYM_GEN_B(s, bad_i_t_l) SYM_GEN_B(s, bad_i_t_l_q) \ - SYM_GEN_B(s, wsr_ma_helper) - -/* - * Macro used to generate interfaces for script Z. - */ -#define SYM_GEN_FW_Z(s) \ - SYM_GEN_Z(s, snooptest) SYM_GEN_Z(s, snoopend) - -/* - * Generates structure interface that contains - * offsets within script A, B and Z. - */ -#define SYM_GEN_A(s, label) s label; -#define SYM_GEN_B(s, label) s label; -#define SYM_GEN_Z(s, label) s label; -struct sym_fwa_ofs { - SYM_GEN_FW_A(u_short) -}; -struct sym_fwb_ofs { - SYM_GEN_FW_B(u_short) - SYM_GEN_B(u_short, start64) - SYM_GEN_B(u_short, pm_handle) -}; -struct sym_fwz_ofs { - SYM_GEN_FW_Z(u_short) -}; - -/* - * Generates structure interface that contains - * bus addresses within script A, B and Z. - */ -struct sym_fwa_ba { - SYM_GEN_FW_A(u32) -}; -struct sym_fwb_ba { - SYM_GEN_FW_B(u32) - SYM_GEN_B(u32, start64); - SYM_GEN_B(u32, pm_handle); -}; -struct sym_fwz_ba { - SYM_GEN_FW_Z(u32) -}; -#undef SYM_GEN_A -#undef SYM_GEN_B -#undef SYM_GEN_Z - -/* - * Let cc know about the name of the controller data structure. - * We need this for function prototype declarations just below. - */ -struct sym_hcb; - -/* - * Generic structure that defines a firmware. - */ -struct sym_fw { - char *name; /* Name we want to print out */ - u32 *a_base; /* Pointer to script A template */ - int a_size; /* Size of script A */ - struct sym_fwa_ofs - *a_ofs; /* Useful offsets in script A */ - u32 *b_base; /* Pointer to script B template */ - int b_size; /* Size of script B */ - struct sym_fwb_ofs - *b_ofs; /* Useful offsets in script B */ - u32 *z_base; /* Pointer to script Z template */ - int z_size; /* Size of script Z */ - struct sym_fwz_ofs - *z_ofs; /* Useful offsets in script Z */ - /* Setup and patch methods for this firmware */ - void (*setup)(struct sym_hcb *, struct sym_fw *); - void (*patch)(struct Scsi_Host *); -}; - -/* - * Macro used to declare a firmware. - */ -#define SYM_FW_ENTRY(fw, name) \ -{ \ - name, \ - (u32 *) &fw##a_scr, sizeof(fw##a_scr), &fw##a_ofs, \ - (u32 *) &fw##b_scr, sizeof(fw##b_scr), &fw##b_ofs, \ - (u32 *) &fw##z_scr, sizeof(fw##z_scr), &fw##z_ofs, \ - fw##_setup, fw##_patch \ -} - -/* - * Macros used from the C code to get useful - * SCRIPTS bus addresses. - */ -#define SCRIPTA_BA(np, label) (np->fwa_bas.label) -#define SCRIPTB_BA(np, label) (np->fwb_bas.label) -#define SCRIPTZ_BA(np, label) (np->fwz_bas.label) - -/* - * Macros used by scripts definitions. - * - * HADDR_1 generates a reference to a field of the controller data. - * HADDR_2 generates a reference to a field of the controller data - * with offset. - * RADDR_1 generates a reference to a script processor register. - * RADDR_2 generates a reference to a script processor register - * with offset. - * PADDR_A generates a reference to another part of script A. - * PADDR_B generates a reference to another part of script B. - * - * SYM_GEN_PADDR_A and SYM_GEN_PADDR_B are used to define respectively - * the PADDR_A and PADDR_B macros for each firmware by setting argument - * `s' to the name of the corresponding structure. - * - * SCR_DATA_ZERO is used to allocate a DWORD of data in scripts areas. - */ - -#define RELOC_SOFTC 0x40000000 -#define RELOC_LABEL_A 0x50000000 -#define RELOC_REGISTER 0x60000000 -#define RELOC_LABEL_B 0x80000000 -#define RELOC_MASK 0xf0000000 - -#define HADDR_1(label) (RELOC_SOFTC | offsetof(struct sym_hcb, label)) -#define HADDR_2(label,ofs) (RELOC_SOFTC | \ - (offsetof(struct sym_hcb, label)+(ofs))) -#define RADDR_1(label) (RELOC_REGISTER | REG(label)) -#define RADDR_2(label,ofs) (RELOC_REGISTER | ((REG(label))+(ofs))) - -#define SYM_GEN_PADDR_A(s, label) (RELOC_LABEL_A | offsetof(s, label)) -#define SYM_GEN_PADDR_B(s, label) (RELOC_LABEL_B | offsetof(s, label)) - -#define SCR_DATA_ZERO 0xf00ff00f - -#endif /* SYM_FW_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw1.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw1.h deleted file mode 100644 index 63952ee3..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw1.h +++ /dev/null @@ -1,1790 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Scripts for SYMBIOS-Processor - * - * We have to know the offsets of all labels before we reach - * them (for forward jumps). Therefore we declare a struct - * here. If you make changes inside the script, - * - * DONT FORGET TO CHANGE THE LENGTHS HERE! - */ - -/* - * Script fragments which are loaded into the on-chip RAM - * of 825A, 875, 876, 895, 895A, 896 and 1010 chips. - * Must not exceed 4K bytes. - */ -struct SYM_FWA_SCR { - u32 start [ 11]; - u32 getjob_begin [ 4]; - u32 _sms_a10 [ 5]; - u32 getjob_end [ 4]; - u32 _sms_a20 [ 4]; -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - u32 select [ 8]; -#else - u32 select [ 6]; -#endif - u32 _sms_a30 [ 5]; - u32 wf_sel_done [ 2]; - u32 send_ident [ 2]; -#ifdef SYM_CONF_IARB_SUPPORT - u32 select2 [ 8]; -#else - u32 select2 [ 2]; -#endif - u32 command [ 2]; - u32 dispatch [ 28]; - u32 sel_no_cmd [ 10]; - u32 init [ 6]; - u32 clrack [ 4]; - u32 datai_done [ 11]; - u32 datai_done_wsr [ 20]; - u32 datao_done [ 11]; - u32 datao_done_wss [ 6]; - u32 datai_phase [ 5]; - u32 datao_phase [ 5]; - u32 msg_in [ 2]; - u32 msg_in2 [ 10]; -#ifdef SYM_CONF_IARB_SUPPORT - u32 status [ 14]; -#else - u32 status [ 10]; -#endif - u32 complete [ 6]; - u32 complete2 [ 8]; - u32 _sms_a40 [ 12]; - u32 done [ 5]; - u32 _sms_a50 [ 5]; - u32 _sms_a60 [ 2]; - u32 done_end [ 4]; - u32 complete_error [ 5]; - u32 save_dp [ 11]; - u32 restore_dp [ 7]; - u32 disconnect [ 11]; - u32 disconnect2 [ 5]; - u32 _sms_a65 [ 3]; -#ifdef SYM_CONF_IARB_SUPPORT - u32 idle [ 4]; -#else - u32 idle [ 2]; -#endif -#ifdef SYM_CONF_IARB_SUPPORT - u32 ungetjob [ 7]; -#else - u32 ungetjob [ 5]; -#endif -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - u32 reselect [ 4]; -#else - u32 reselect [ 2]; -#endif - u32 reselected [ 19]; - u32 _sms_a70 [ 6]; - u32 _sms_a80 [ 4]; - u32 reselected1 [ 25]; - u32 _sms_a90 [ 4]; - u32 resel_lun0 [ 7]; - u32 _sms_a100 [ 4]; - u32 resel_tag [ 8]; -#if SYM_CONF_MAX_TASK*4 > 512 - u32 _sms_a110 [ 23]; -#elif SYM_CONF_MAX_TASK*4 > 256 - u32 _sms_a110 [ 17]; -#else - u32 _sms_a110 [ 13]; -#endif - u32 _sms_a120 [ 2]; - u32 resel_go [ 4]; - u32 _sms_a130 [ 7]; - u32 resel_dsa [ 2]; - u32 resel_dsa1 [ 4]; - u32 _sms_a140 [ 7]; - u32 resel_no_tag [ 4]; - u32 _sms_a145 [ 7]; - u32 data_in [SYM_CONF_MAX_SG * 2]; - u32 data_in2 [ 4]; - u32 data_out [SYM_CONF_MAX_SG * 2]; - u32 data_out2 [ 4]; - u32 pm0_data [ 12]; - u32 pm0_data_out [ 6]; - u32 pm0_data_end [ 7]; - u32 pm_data_end [ 4]; - u32 _sms_a150 [ 4]; - u32 pm1_data [ 12]; - u32 pm1_data_out [ 6]; - u32 pm1_data_end [ 9]; -}; - -/* - * Script fragments which stay in main memory for all chips - * except for chips that support 8K on-chip RAM. - */ -struct SYM_FWB_SCR { - u32 no_data [ 2]; -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - u32 sel_for_abort [ 18]; -#else - u32 sel_for_abort [ 16]; -#endif - u32 sel_for_abort_1 [ 2]; - u32 msg_in_etc [ 12]; - u32 msg_received [ 5]; - u32 msg_weird_seen [ 5]; - u32 msg_extended [ 17]; - u32 _sms_b10 [ 4]; - u32 msg_bad [ 6]; - u32 msg_weird [ 4]; - u32 msg_weird1 [ 8]; - u32 wdtr_resp [ 6]; - u32 send_wdtr [ 4]; - u32 sdtr_resp [ 6]; - u32 send_sdtr [ 4]; - u32 ppr_resp [ 6]; - u32 send_ppr [ 4]; - u32 nego_bad_phase [ 4]; - u32 msg_out [ 4]; - u32 msg_out_done [ 4]; - u32 data_ovrun [ 3]; - u32 data_ovrun1 [ 22]; - u32 data_ovrun2 [ 8]; - u32 abort_resel [ 16]; - u32 resend_ident [ 4]; - u32 ident_break [ 4]; - u32 ident_break_atn [ 4]; - u32 sdata_in [ 6]; - u32 resel_bad_lun [ 4]; - u32 bad_i_t_l [ 4]; - u32 bad_i_t_l_q [ 4]; - u32 bad_status [ 7]; - u32 wsr_ma_helper [ 4]; - - /* Data area */ - u32 zero [ 1]; - u32 scratch [ 1]; - u32 scratch1 [ 1]; - u32 prev_done [ 1]; - u32 done_pos [ 1]; - u32 nextjob [ 1]; - u32 startpos [ 1]; - u32 targtbl [ 1]; -}; - -/* - * Script fragments used at initialisations. - * Only runs out of main memory. - */ -struct SYM_FWZ_SCR { - u32 snooptest [ 9]; - u32 snoopend [ 2]; -}; - -static struct SYM_FWA_SCR SYM_FWA_SCR = { -/*--------------------------< START >----------------------------*/ { - /* - * Switch the LED on. - * Will be patched with a NO_OP if LED - * not needed or not desired. - */ - SCR_REG_REG (gpreg, SCR_AND, 0xfe), - 0, - /* - * Clear SIGP. - */ - SCR_FROM_REG (ctest2), - 0, - /* - * Stop here if the C code wants to perform - * some error recovery procedure manually. - * (Indicate this by setting SEM in ISTAT) - */ - SCR_FROM_REG (istat), - 0, - /* - * Report to the C code the next position in - * the start queue the SCRIPTS will schedule. - * The C code must not change SCRATCHA. - */ - SCR_COPY (4), - PADDR_B (startpos), - RADDR_1 (scratcha), - SCR_INT ^ IFTRUE (MASK (SEM, SEM)), - SIR_SCRIPT_STOPPED, - /* - * Start the next job. - * - * @DSA = start point for this job. - * SCRATCHA = address of this job in the start queue. - * - * We will restore startpos with SCRATCHA if we fails the - * arbitration or if it is the idle job. - * - * The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS - * is a critical path. If it is partially executed, it then - * may happen that the job address is not yet in the DSA - * and the next queue position points to the next JOB. - */ -}/*-------------------------< GETJOB_BEGIN >---------------------*/,{ - /* - * Copy to a fixed location both the next STARTPOS - * and the current JOB address, using self modifying - * SCRIPTS. - */ - SCR_COPY (4), - RADDR_1 (scratcha), - PADDR_A (_sms_a10), - SCR_COPY (8), -}/*-------------------------< _SMS_A10 >-------------------------*/,{ - 0, - PADDR_B (nextjob), - /* - * Move the start address to TEMP using self- - * modifying SCRIPTS and jump indirectly to - * that address. - */ - SCR_COPY (4), - PADDR_B (nextjob), - RADDR_1 (dsa), -}/*-------------------------< GETJOB_END >-----------------------*/,{ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a20), - SCR_COPY (4), -}/*-------------------------< _SMS_A20 >-------------------------*/,{ - 0, - RADDR_1 (temp), - SCR_RETURN, - 0, -}/*-------------------------< SELECT >---------------------------*/,{ - /* - * DSA contains the address of a scheduled - * data structure. - * - * SCRATCHA contains the address of the start queue - * entry which points to the next job. - * - * Set Initiator mode. - * - * (Target mode is left as an exercise for the reader) - */ -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - SCR_CLR (SCR_TRG), - 0, -#endif - /* - * And try to select this target. - */ - SCR_SEL_TBL_ATN ^ offsetof (struct sym_dsb, select), - PADDR_A (ungetjob), - /* - * Now there are 4 possibilities: - * - * (1) The chip loses arbitration. - * This is ok, because it will try again, - * when the bus becomes idle. - * (But beware of the timeout function!) - * - * (2) The chip is reselected. - * Then the script processor takes the jump - * to the RESELECT label. - * - * (3) The chip wins arbitration. - * Then it will execute SCRIPTS instruction until - * the next instruction that checks SCSI phase. - * Then will stop and wait for selection to be - * complete or selection time-out to occur. - * - * After having won arbitration, the SCRIPTS - * processor is able to execute instructions while - * the SCSI core is performing SCSI selection. - */ - - /* - * Copy the CCB header to a fixed location - * in the HCB using self-modifying SCRIPTS. - */ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a30), - SCR_COPY (sizeof(struct sym_ccbh)), -}/*-------------------------< _SMS_A30 >-------------------------*/,{ - 0, - HADDR_1 (ccb_head), - /* - * Initialize the status register - */ - SCR_COPY (4), - HADDR_1 (ccb_head.status), - RADDR_1 (scr0), -}/*-------------------------< WF_SEL_DONE >----------------------*/,{ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), - SIR_SEL_ATN_NO_MSG_OUT, -}/*-------------------------< SEND_IDENT >-----------------------*/,{ - /* - * Selection complete. - * Send the IDENTIFY and possibly the TAG message - * and negotiation message if present. - */ - SCR_MOVE_TBL ^ SCR_MSG_OUT, - offsetof (struct sym_dsb, smsg), -}/*-------------------------< SELECT2 >--------------------------*/,{ -#ifdef SYM_CONF_IARB_SUPPORT - /* - * Set IMMEDIATE ARBITRATION if we have been given - * a hint to do so. (Some job to do after this one). - */ - SCR_FROM_REG (HF_REG), - 0, - SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)), - 8, - SCR_REG_REG (scntl1, SCR_OR, IARB), - 0, -#endif - /* - * Anticipate the COMMAND phase. - * This is the PHASE we expect at this point. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)), - PADDR_A (sel_no_cmd), -}/*-------------------------< COMMAND >--------------------------*/,{ - /* - * ... and send the command - */ - SCR_MOVE_TBL ^ SCR_COMMAND, - offsetof (struct sym_dsb, cmd), -}/*-------------------------< DISPATCH >-------------------------*/,{ - /* - * MSG_IN is the only phase that shall be - * entered at least once for each (re)selection. - * So we test it first. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR_A (msg_in), - SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)), - PADDR_A (datao_phase), - SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)), - PADDR_A (datai_phase), - SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), - PADDR_A (status), - SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), - PADDR_A (command), - SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), - PADDR_B (msg_out), - /* - * Discard as many illegal phases as - * required and tell the C code about. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)), - 16, - SCR_MOVE_ABS (1) ^ SCR_ILG_OUT, - HADDR_1 (scratch), - SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)), - -16, - SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)), - 16, - SCR_MOVE_ABS (1) ^ SCR_ILG_IN, - HADDR_1 (scratch), - SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)), - -16, - SCR_INT, - SIR_BAD_PHASE, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< SEL_NO_CMD >-----------------------*/,{ - /* - * The target does not switch to command - * phase after IDENTIFY has been sent. - * - * If it stays in MSG OUT phase send it - * the IDENTIFY again. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), - PADDR_B (resend_ident), - /* - * If target does not switch to MSG IN phase - * and we sent a negotiation, assert the - * failure immediately. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR_A (dispatch), - SCR_FROM_REG (HS_REG), - 0, - SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), - SIR_NEGO_FAILED, - /* - * Jump to dispatcher. - */ - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< INIT >-----------------------------*/,{ - /* - * Wait for the SCSI RESET signal to be - * inactive before restarting operations, - * since the chip may hang on SEL_ATN - * if SCSI RESET is active. - */ - SCR_FROM_REG (sstat0), - 0, - SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)), - -16, - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< CLRACK >---------------------------*/,{ - /* - * Terminate possible pending message phase. - */ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAI_DONE >-----------------------*/,{ - /* - * Save current pointer to LASTP. - */ - SCR_COPY (4), - RADDR_1 (temp), - HADDR_1 (ccb_head.lastp), - /* - * If the SWIDE is not full, jump to dispatcher. - * We anticipate a STATUS phase. - */ - SCR_FROM_REG (scntl2), - 0, - SCR_JUMP ^ IFTRUE (MASK (WSR, WSR)), - PADDR_A (datai_done_wsr), - SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)), - PADDR_A (status), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAI_DONE_WSR >-------------------*/,{ - /* - * The SWIDE is full. - * Clear this condition. - */ - SCR_REG_REG (scntl2, SCR_OR, WSR), - 0, - /* - * We are expecting an IGNORE RESIDUE message - * from the device, otherwise we are in data - * overrun condition. Check against MSG_IN phase. - */ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), - SIR_SWIDE_OVERRUN, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR_A (dispatch), - /* - * We are in MSG_IN phase, - * Read the first byte of the message. - * If it is not an IGNORE RESIDUE message, - * signal overrun and jump to message - * processing. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[0]), - SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)), - SIR_SWIDE_OVERRUN, - SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)), - PADDR_A (msg_in2), - /* - * We got the message we expected. - * Read the 2nd byte, and jump to dispatcher. - */ - SCR_CLR (SCR_ACK), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[1]), - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAO_DONE >-----------------------*/,{ - /* - * Save current pointer to LASTP. - */ - SCR_COPY (4), - RADDR_1 (temp), - HADDR_1 (ccb_head.lastp), - /* - * If the SODL is not full jump to dispatcher. - * We anticipate a STATUS phase. - */ - SCR_FROM_REG (scntl2), - 0, - SCR_JUMP ^ IFTRUE (MASK (WSS, WSS)), - PADDR_A (datao_done_wss), - SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)), - PADDR_A (status), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAO_DONE_WSS >-------------------*/,{ - /* - * The SODL is full, clear this condition. - */ - SCR_REG_REG (scntl2, SCR_OR, WSS), - 0, - /* - * And signal a DATA UNDERRUN condition - * to the C code. - */ - SCR_INT, - SIR_SODL_UNDERRUN, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAI_PHASE >----------------------*/,{ - /* - * Jump to current pointer. - */ - SCR_COPY (4), - HADDR_1 (ccb_head.lastp), - RADDR_1 (temp), - SCR_RETURN, - 0, -}/*-------------------------< DATAO_PHASE >----------------------*/,{ - /* - * Jump to current pointer. - */ - SCR_COPY (4), - HADDR_1 (ccb_head.lastp), - RADDR_1 (temp), - SCR_RETURN, - 0, -}/*-------------------------< MSG_IN >---------------------------*/,{ - /* - * Get the first byte of the message. - * - * The script processor doesn't negate the - * ACK signal after this transfer. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[0]), -}/*-------------------------< MSG_IN2 >--------------------------*/,{ - /* - * Check first against 1 byte messages - * that we handle from SCRIPTS. - */ - SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)), - PADDR_A (complete), - SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), - PADDR_A (disconnect), - SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)), - PADDR_A (save_dp), - SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)), - PADDR_A (restore_dp), - /* - * We handle all other messages from the - * C code, so no need to waste on-chip RAM - * for those ones. - */ - SCR_JUMP, - PADDR_B (msg_in_etc), -}/*-------------------------< STATUS >---------------------------*/,{ - /* - * get the status - */ - SCR_MOVE_ABS (1) ^ SCR_STATUS, - HADDR_1 (scratch), -#ifdef SYM_CONF_IARB_SUPPORT - /* - * If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, - * since we may have to tamper the start queue from - * the C code. - */ - SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)), - 8, - SCR_REG_REG (scntl1, SCR_AND, ~IARB), - 0, -#endif - /* - * save status to scsi_status. - * mark as complete. - */ - SCR_TO_REG (SS_REG), - 0, - SCR_LOAD_REG (HS_REG, HS_COMPLETE), - 0, - /* - * Anticipate the MESSAGE PHASE for - * the TASK COMPLETE message. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR_A (msg_in), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< COMPLETE >-------------------------*/,{ - /* - * Complete message. - * - * When we terminate the cycle by clearing ACK, - * the target may disconnect immediately. - * - * We don't want to be told of an "unexpected disconnect", - * so we disable this feature. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - /* - * Terminate cycle ... - */ - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - /* - * ... and wait for the disconnect. - */ - SCR_WAIT_DISC, - 0, -}/*-------------------------< COMPLETE2 >------------------------*/,{ - /* - * Save host status. - */ - SCR_COPY (4), - RADDR_1 (scr0), - HADDR_1 (ccb_head.status), - /* - * Move back the CCB header using self-modifying - * SCRIPTS. - */ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a40), - SCR_COPY (sizeof(struct sym_ccbh)), - HADDR_1 (ccb_head), -}/*-------------------------< _SMS_A40 >-------------------------*/,{ - 0, - /* - * Some bridges may reorder DMA writes to memory. - * We donnot want the CPU to deal with completions - * without all the posted write having been flushed - * to memory. This DUMMY READ should flush posted - * buffers prior to the CPU having to deal with - * completions. - */ - SCR_COPY (4), /* DUMMY READ */ - HADDR_1 (ccb_head.status), - RADDR_1 (scr0), - /* - * If command resulted in not GOOD status, - * call the C code if needed. - */ - SCR_FROM_REG (SS_REG), - 0, - SCR_CALL ^ IFFALSE (DATA (S_GOOD)), - PADDR_B (bad_status), - /* - * If we performed an auto-sense, call - * the C code to synchronyze task aborts - * with UNIT ATTENTION conditions. - */ - SCR_FROM_REG (HF_REG), - 0, - SCR_JUMP ^ IFFALSE (MASK (0 ,(HF_SENSE|HF_EXT_ERR))), - PADDR_A (complete_error), -}/*-------------------------< DONE >-----------------------------*/,{ - /* - * Copy the DSA to the DONE QUEUE and - * signal completion to the host. - * If we are interrupted between DONE - * and DONE_END, we must reset, otherwise - * the completed CCB may be lost. - */ - SCR_COPY (4), - PADDR_B (done_pos), - PADDR_A (_sms_a50), - SCR_COPY (4), - RADDR_1 (dsa), -}/*-------------------------< _SMS_A50 >-------------------------*/,{ - 0, - SCR_COPY (4), - PADDR_B (done_pos), - PADDR_A (_sms_a60), - /* - * The instruction below reads the DONE QUEUE next - * free position from memory. - * In addition it ensures that all PCI posted writes - * are flushed and so the DSA value of the done - * CCB is visible by the CPU before INTFLY is raised. - */ - SCR_COPY (8), -}/*-------------------------< _SMS_A60 >-------------------------*/,{ - 0, - PADDR_B (prev_done), -}/*-------------------------< DONE_END >-------------------------*/,{ - SCR_INT_FLY, - 0, - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< COMPLETE_ERROR >-------------------*/,{ - SCR_COPY (4), - PADDR_B (startpos), - RADDR_1 (scratcha), - SCR_INT, - SIR_COMPLETE_ERROR, -}/*-------------------------< SAVE_DP >--------------------------*/,{ - /* - * Clear ACK immediately. - * No need to delay it. - */ - SCR_CLR (SCR_ACK), - 0, - /* - * Keep track we received a SAVE DP, so - * we will switch to the other PM context - * on the next PM since the DP may point - * to the current PM context. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED), - 0, - /* - * SAVE_DP message: - * Copy LASTP to SAVEP. - */ - SCR_COPY (4), - HADDR_1 (ccb_head.lastp), - HADDR_1 (ccb_head.savep), - /* - * Anticipate the MESSAGE PHASE for - * the DISCONNECT message. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR_A (msg_in), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< RESTORE_DP >-----------------------*/,{ - /* - * Clear ACK immediately. - * No need to delay it. - */ - SCR_CLR (SCR_ACK), - 0, - /* - * Copy SAVEP to LASTP. - */ - SCR_COPY (4), - HADDR_1 (ccb_head.savep), - HADDR_1 (ccb_head.lastp), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DISCONNECT >-----------------------*/,{ - /* - * DISCONNECTing ... - * - * disable the "unexpected disconnect" feature, - * and remove the ACK signal. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - /* - * Wait for the disconnect. - */ - SCR_WAIT_DISC, - 0, - /* - * Status is: DISCONNECTED. - */ - SCR_LOAD_REG (HS_REG, HS_DISCONNECT), - 0, - /* - * Save host status. - */ - SCR_COPY (4), - RADDR_1 (scr0), - HADDR_1 (ccb_head.status), -}/*-------------------------< DISCONNECT2 >----------------------*/,{ - /* - * Move back the CCB header using self-modifying - * SCRIPTS. - */ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a65), - SCR_COPY (sizeof(struct sym_ccbh)), - HADDR_1 (ccb_head), -}/*-------------------------< _SMS_A65 >-------------------------*/,{ - 0, - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< IDLE >-----------------------------*/,{ - /* - * Nothing to do? - * Switch the LED off and wait for reselect. - * Will be patched with a NO_OP if LED - * not needed or not desired. - */ - SCR_REG_REG (gpreg, SCR_OR, 0x01), - 0, -#ifdef SYM_CONF_IARB_SUPPORT - SCR_JUMPR, - 8, -#endif -}/*-------------------------< UNGETJOB >-------------------------*/,{ -#ifdef SYM_CONF_IARB_SUPPORT - /* - * Set IMMEDIATE ARBITRATION, for the next time. - * This will give us better chance to win arbitration - * for the job we just wanted to do. - */ - SCR_REG_REG (scntl1, SCR_OR, IARB), - 0, -#endif - /* - * We are not able to restart the SCRIPTS if we are - * interrupted and these instruction haven't been - * all executed. BTW, this is very unlikely to - * happen, but we check that from the C code. - */ - SCR_LOAD_REG (dsa, 0xff), - 0, - SCR_COPY (4), - RADDR_1 (scratcha), - PADDR_B (startpos), -}/*-------------------------< RESELECT >-------------------------*/,{ -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - /* - * Make sure we are in initiator mode. - */ - SCR_CLR (SCR_TRG), - 0, -#endif - /* - * Sleep waiting for a reselection. - */ - SCR_WAIT_RESEL, - PADDR_A(start), -}/*-------------------------< RESELECTED >-----------------------*/,{ - /* - * Switch the LED on. - * Will be patched with a NO_OP if LED - * not needed or not desired. - */ - SCR_REG_REG (gpreg, SCR_AND, 0xfe), - 0, - /* - * load the target id into the sdid - */ - SCR_REG_SFBR (ssid, SCR_AND, 0x8F), - 0, - SCR_TO_REG (sdid), - 0, - /* - * Load the target control block address - */ - SCR_COPY (4), - PADDR_B (targtbl), - RADDR_1 (dsa), - SCR_SFBR_REG (dsa, SCR_SHL, 0), - 0, - SCR_REG_REG (dsa, SCR_SHL, 0), - 0, - SCR_REG_REG (dsa, SCR_AND, 0x3c), - 0, - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a70), - SCR_COPY (4), -}/*-------------------------< _SMS_A70 >-------------------------*/,{ - 0, - RADDR_1 (dsa), - /* - * Copy the TCB header to a fixed place in - * the HCB. - */ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a80), - SCR_COPY (sizeof(struct sym_tcbh)), -}/*-------------------------< _SMS_A80 >-------------------------*/,{ - 0, - HADDR_1 (tcb_head), - /* - * We expect MESSAGE IN phase. - * If not, get help from the C code. - */ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), - SIR_RESEL_NO_MSG_IN, -}/*-------------------------< RESELECTED1 >----------------------*/,{ - /* - * Load the synchronous transfer registers. - */ - SCR_COPY (1), - HADDR_1 (tcb_head.wval), - RADDR_1 (scntl3), - SCR_COPY (1), - HADDR_1 (tcb_head.sval), - RADDR_1 (sxfer), - /* - * Get the IDENTIFY message. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin), - /* - * If IDENTIFY LUN #0, use a faster path - * to find the LCB structure. - */ - SCR_JUMP ^ IFTRUE (MASK (0x80, 0xbf)), - PADDR_A (resel_lun0), - /* - * If message isn't an IDENTIFY, - * tell the C code about. - */ - SCR_INT ^ IFFALSE (MASK (0x80, 0x80)), - SIR_RESEL_NO_IDENTIFY, - /* - * It is an IDENTIFY message, - * Load the LUN control block address. - */ - SCR_COPY (4), - HADDR_1 (tcb_head.luntbl_sa), - RADDR_1 (dsa), - SCR_SFBR_REG (dsa, SCR_SHL, 0), - 0, - SCR_REG_REG (dsa, SCR_SHL, 0), - 0, - SCR_REG_REG (dsa, SCR_AND, 0xfc), - 0, - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a90), - SCR_COPY (4), -}/*-------------------------< _SMS_A90 >-------------------------*/,{ - 0, - RADDR_1 (dsa), - SCR_JUMPR, - 12, -}/*-------------------------< RESEL_LUN0 >-----------------------*/,{ - /* - * LUN 0 special case (but usual one :)) - */ - SCR_COPY (4), - HADDR_1 (tcb_head.lun0_sa), - RADDR_1 (dsa), - /* - * Jump indirectly to the reselect action for this LUN. - * (lcb.head.resel_sa assumed at offset zero of lcb). - */ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a100), - SCR_COPY (4), -}/*-------------------------< _SMS_A100 >------------------------*/,{ - 0, - RADDR_1 (temp), - SCR_RETURN, - 0, - /* In normal situations, we jump to RESEL_TAG or RESEL_NO_TAG */ -}/*-------------------------< RESEL_TAG >------------------------*/,{ - /* - * ACK the IDENTIFY previously received. - */ - SCR_CLR (SCR_ACK), - 0, - /* - * It shall be a tagged command. - * Read SIMPLE+TAG. - * The C code will deal with errors. - * Aggressive optimization, isn't it? :) - */ - SCR_MOVE_ABS (2) ^ SCR_MSG_IN, - HADDR_1 (msgin), - /* - * Copy the LCB header to a fixed place in - * the HCB using self-modifying SCRIPTS. - */ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a110), - SCR_COPY (sizeof(struct sym_lcbh)), -}/*-------------------------< _SMS_A110 >------------------------*/,{ - 0, - HADDR_1 (lcb_head), - /* - * Load the pointer to the tagged task - * table for this LUN. - */ - SCR_COPY (4), - HADDR_1 (lcb_head.itlq_tbl_sa), - RADDR_1 (dsa), - /* - * The SIDL still contains the TAG value. - * Aggressive optimization, isn't it? :):) - */ - SCR_REG_SFBR (sidl, SCR_SHL, 0), - 0, -#if SYM_CONF_MAX_TASK*4 > 512 - SCR_JUMPR ^ IFFALSE (CARRYSET), - 8, - SCR_REG_REG (dsa1, SCR_OR, 2), - 0, - SCR_REG_REG (sfbr, SCR_SHL, 0), - 0, - SCR_JUMPR ^ IFFALSE (CARRYSET), - 8, - SCR_REG_REG (dsa1, SCR_OR, 1), - 0, -#elif SYM_CONF_MAX_TASK*4 > 256 - SCR_JUMPR ^ IFFALSE (CARRYSET), - 8, - SCR_REG_REG (dsa1, SCR_OR, 1), - 0, -#endif - /* - * Retrieve the DSA of this task. - * JUMP indirectly to the restart point of the CCB. - */ - SCR_SFBR_REG (dsa, SCR_AND, 0xfc), - 0, - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a120), - SCR_COPY (4), -}/*-------------------------< _SMS_A120 >------------------------*/,{ - 0, - RADDR_1 (dsa), -}/*-------------------------< RESEL_GO >-------------------------*/,{ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a130), - /* - * Move 'ccb.phys.head.go' action to - * scratch/scratch1. So scratch1 will - * contain the 'restart' field of the - * 'go' structure. - */ - SCR_COPY (8), -}/*-------------------------< _SMS_A130 >------------------------*/,{ - 0, - PADDR_B (scratch), - SCR_COPY (4), - PADDR_B (scratch1), /* phys.head.go.restart */ - RADDR_1 (temp), - SCR_RETURN, - 0, - /* In normal situations we branch to RESEL_DSA */ -}/*-------------------------< RESEL_DSA >------------------------*/,{ - /* - * ACK the IDENTIFY or TAG previously received. - */ - SCR_CLR (SCR_ACK), - 0, -}/*-------------------------< RESEL_DSA1 >-----------------------*/,{ - /* - * Copy the CCB header to a fixed location - * in the HCB using self-modifying SCRIPTS. - */ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a140), - SCR_COPY (sizeof(struct sym_ccbh)), -}/*-------------------------< _SMS_A140 >------------------------*/,{ - 0, - HADDR_1 (ccb_head), - /* - * Initialize the status register - */ - SCR_COPY (4), - HADDR_1 (ccb_head.status), - RADDR_1 (scr0), - /* - * Jump to dispatcher. - */ - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< RESEL_NO_TAG >---------------------*/,{ - /* - * Copy the LCB header to a fixed place in - * the HCB using self-modifying SCRIPTS. - */ - SCR_COPY (4), - RADDR_1 (dsa), - PADDR_A (_sms_a145), - SCR_COPY (sizeof(struct sym_lcbh)), -}/*-------------------------< _SMS_A145 >------------------------*/,{ - 0, - HADDR_1 (lcb_head), - /* - * Load the DSA with the unique ITL task. - */ - SCR_COPY (4), - HADDR_1 (lcb_head.itl_task_sa), - RADDR_1 (dsa), - SCR_JUMP, - PADDR_A (resel_go), -}/*-------------------------< DATA_IN >--------------------------*/,{ -/* - * Because the size depends on the - * #define SYM_CONF_MAX_SG parameter, - * it is filled in at runtime. - * - * ##===========< i=0; i========= - * || SCR_CHMOV_TBL ^ SCR_DATA_IN, - * || offsetof (struct sym_dsb, data[ i]), - * ##========================================== - */ -0 -}/*-------------------------< DATA_IN2 >-------------------------*/,{ - SCR_CALL, - PADDR_A (datai_done), - SCR_JUMP, - PADDR_B (data_ovrun), -}/*-------------------------< DATA_OUT >-------------------------*/,{ -/* - * Because the size depends on the - * #define SYM_CONF_MAX_SG parameter, - * it is filled in at runtime. - * - * ##===========< i=0; i========= - * || SCR_CHMOV_TBL ^ SCR_DATA_OUT, - * || offsetof (struct sym_dsb, data[ i]), - * ##========================================== - */ -0 -}/*-------------------------< DATA_OUT2 >------------------------*/,{ - SCR_CALL, - PADDR_A (datao_done), - SCR_JUMP, - PADDR_B (data_ovrun), -}/*-------------------------< PM0_DATA >-------------------------*/,{ - /* - * Read our host flags to SFBR, so we will be able - * to check against the data direction we expect. - */ - SCR_FROM_REG (HF_REG), - 0, - /* - * Check against actual DATA PHASE. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), - PADDR_A (pm0_data_out), - /* - * Actual phase is DATA IN. - * Check against expected direction. - */ - SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDR_B (data_ovrun), - /* - * Keep track we are moving data from the - * PM0 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), - 0, - /* - * Move the data to memory. - */ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_ccb, phys.pm0.sg), - SCR_JUMP, - PADDR_A (pm0_data_end), -}/*-------------------------< PM0_DATA_OUT >---------------------*/,{ - /* - * Actual phase is DATA OUT. - * Check against expected direction. - */ - SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDR_B (data_ovrun), - /* - * Keep track we are moving data from the - * PM0 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), - 0, - /* - * Move the data from memory. - */ - SCR_CHMOV_TBL ^ SCR_DATA_OUT, - offsetof (struct sym_ccb, phys.pm0.sg), -}/*-------------------------< PM0_DATA_END >---------------------*/,{ - /* - * Clear the flag that told we were moving - * data from the PM0 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)), - 0, - /* - * Return to the previous DATA script which - * is guaranteed by design (if no bug) to be - * the main DATA script for this transfer. - */ - SCR_COPY (4), - RADDR_1 (dsa), - RADDR_1 (scratcha), - SCR_REG_REG (scratcha, SCR_ADD, offsetof (struct sym_ccb,phys.pm0.ret)), - 0, -}/*-------------------------< PM_DATA_END >----------------------*/,{ - SCR_COPY (4), - RADDR_1 (scratcha), - PADDR_A (_sms_a150), - SCR_COPY (4), -}/*-------------------------< _SMS_A150 >------------------------*/,{ - 0, - RADDR_1 (temp), - SCR_RETURN, - 0, -}/*-------------------------< PM1_DATA >-------------------------*/,{ - /* - * Read our host flags to SFBR, so we will be able - * to check against the data direction we expect. - */ - SCR_FROM_REG (HF_REG), - 0, - /* - * Check against actual DATA PHASE. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), - PADDR_A (pm1_data_out), - /* - * Actual phase is DATA IN. - * Check against expected direction. - */ - SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDR_B (data_ovrun), - /* - * Keep track we are moving data from the - * PM1 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), - 0, - /* - * Move the data to memory. - */ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_ccb, phys.pm1.sg), - SCR_JUMP, - PADDR_A (pm1_data_end), -}/*-------------------------< PM1_DATA_OUT >---------------------*/,{ - /* - * Actual phase is DATA OUT. - * Check against expected direction. - */ - SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDR_B (data_ovrun), - /* - * Keep track we are moving data from the - * PM1 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), - 0, - /* - * Move the data from memory. - */ - SCR_CHMOV_TBL ^ SCR_DATA_OUT, - offsetof (struct sym_ccb, phys.pm1.sg), -}/*-------------------------< PM1_DATA_END >---------------------*/,{ - /* - * Clear the flag that told we were moving - * data from the PM1 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)), - 0, - /* - * Return to the previous DATA script which - * is guaranteed by design (if no bug) to be - * the main DATA script for this transfer. - */ - SCR_COPY (4), - RADDR_1 (dsa), - RADDR_1 (scratcha), - SCR_REG_REG (scratcha, SCR_ADD, offsetof (struct sym_ccb,phys.pm1.ret)), - 0, - SCR_JUMP, - PADDR_A (pm_data_end), -}/*--------------------------<>----------------------------------*/ -}; - -static struct SYM_FWB_SCR SYM_FWB_SCR = { -/*-------------------------< NO_DATA >--------------------------*/ { - SCR_JUMP, - PADDR_B (data_ovrun), -}/*-------------------------< SEL_FOR_ABORT >--------------------*/,{ - /* - * We are jumped here by the C code, if we have - * some target to reset or some disconnected - * job to abort. Since error recovery is a serious - * busyness, we will really reset the SCSI BUS, if - * case of a SCSI interrupt occurring in this path. - */ - -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - /* - * Set initiator mode. - */ - SCR_CLR (SCR_TRG), - 0, -#endif - /* - * And try to select this target. - */ - SCR_SEL_TBL_ATN ^ offsetof (struct sym_hcb, abrt_sel), - PADDR_A (reselect), - /* - * Wait for the selection to complete or - * the selection to time out. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), - -8, - /* - * Call the C code. - */ - SCR_INT, - SIR_TARGET_SELECTED, - /* - * The C code should let us continue here. - * Send the 'kiss of death' message. - * We expect an immediate disconnect once - * the target has eaten the message. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_MOVE_TBL ^ SCR_MSG_OUT, - offsetof (struct sym_hcb, abrt_tbl), - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - SCR_WAIT_DISC, - 0, - /* - * Tell the C code that we are done. - */ - SCR_INT, - SIR_ABORT_SENT, -}/*-------------------------< SEL_FOR_ABORT_1 >------------------*/,{ - /* - * Jump at scheduler. - */ - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< MSG_IN_ETC >-----------------------*/,{ - /* - * If it is an EXTENDED (variable size message) - * Handle it. - */ - SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), - PADDR_B (msg_extended), - /* - * Let the C code handle any other - * 1 byte message. - */ - SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)), - PADDR_B (msg_received), - SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)), - PADDR_B (msg_received), - /* - * We donnot handle 2 bytes messages from SCRIPTS. - * So, let the C code deal with these ones too. - */ - SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)), - PADDR_B (msg_weird_seen), - SCR_CLR (SCR_ACK), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[1]), -}/*-------------------------< MSG_RECEIVED >---------------------*/,{ - SCR_COPY (4), /* DUMMY READ */ - HADDR_1 (scratch), - RADDR_1 (scratcha), - SCR_INT, - SIR_MSG_RECEIVED, -}/*-------------------------< MSG_WEIRD_SEEN >-------------------*/,{ - SCR_COPY (4), /* DUMMY READ */ - HADDR_1 (scratch), - RADDR_1 (scratcha), - SCR_INT, - SIR_MSG_WEIRD, -}/*-------------------------< MSG_EXTENDED >---------------------*/,{ - /* - * Clear ACK and get the next byte - * assumed to be the message length. - */ - SCR_CLR (SCR_ACK), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[1]), - /* - * Try to catch some unlikely situations as 0 length - * or too large the length. - */ - SCR_JUMP ^ IFTRUE (DATA (0)), - PADDR_B (msg_weird_seen), - SCR_TO_REG (scratcha), - 0, - SCR_REG_REG (sfbr, SCR_ADD, (256-8)), - 0, - SCR_JUMP ^ IFTRUE (CARRYSET), - PADDR_B (msg_weird_seen), - /* - * We donnot handle extended messages from SCRIPTS. - * Read the amount of data corresponding to the - * message length and call the C code. - */ - SCR_COPY (1), - RADDR_1 (scratcha), - PADDR_B (_sms_b10), - SCR_CLR (SCR_ACK), - 0, -}/*-------------------------< _SMS_B10 >-------------------------*/,{ - SCR_MOVE_ABS (0) ^ SCR_MSG_IN, - HADDR_1 (msgin[2]), - SCR_JUMP, - PADDR_B (msg_received), -}/*-------------------------< MSG_BAD >--------------------------*/,{ - /* - * unimplemented message - reject it. - */ - SCR_INT, - SIR_REJECT_TO_SEND, - SCR_SET (SCR_ATN), - 0, - SCR_JUMP, - PADDR_A (clrack), -}/*-------------------------< MSG_WEIRD >------------------------*/,{ - /* - * weird message received - * ignore all MSG IN phases and reject it. - */ - SCR_INT, - SIR_REJECT_TO_SEND, - SCR_SET (SCR_ATN), - 0, -}/*-------------------------< MSG_WEIRD1 >-----------------------*/,{ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR_A (dispatch), - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (scratch), - SCR_JUMP, - PADDR_B (msg_weird1), -}/*-------------------------< WDTR_RESP >------------------------*/,{ - /* - * let the target fetch our answer. - */ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDR_B (nego_bad_phase), -}/*-------------------------< SEND_WDTR >------------------------*/,{ - /* - * Send the M_X_WIDE_REQ - */ - SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - SCR_JUMP, - PADDR_B (msg_out_done), -}/*-------------------------< SDTR_RESP >------------------------*/,{ - /* - * let the target fetch our answer. - */ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDR_B (nego_bad_phase), -}/*-------------------------< SEND_SDTR >------------------------*/,{ - /* - * Send the M_X_SYNC_REQ - */ - SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - SCR_JUMP, - PADDR_B (msg_out_done), -}/*-------------------------< PPR_RESP >-------------------------*/,{ - /* - * let the target fetch our answer. - */ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDR_B (nego_bad_phase), -}/*-------------------------< SEND_PPR >-------------------------*/,{ - /* - * Send the M_X_PPR_REQ - */ - SCR_MOVE_ABS (8) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - SCR_JUMP, - PADDR_B (msg_out_done), -}/*-------------------------< NEGO_BAD_PHASE >-------------------*/,{ - SCR_INT, - SIR_NEGO_PROTO, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< MSG_OUT >--------------------------*/,{ - /* - * The target requests a message. - * We donnot send messages that may - * require the device to go to bus free. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - /* - * ... wait for the next phase - * if it's a message out, send it again, ... - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), - PADDR_B (msg_out), -}/*-------------------------< MSG_OUT_DONE >---------------------*/,{ - /* - * Let the C code be aware of the - * sent message and clear the message. - */ - SCR_INT, - SIR_MSG_OUT_DONE, - /* - * ... and process the next phase - */ - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATA_OVRUN >-----------------------*/,{ - /* - * Zero scratcha that will count the - * extras bytes. - */ - SCR_COPY (4), - PADDR_B (zero), - RADDR_1 (scratcha), -}/*-------------------------< DATA_OVRUN1 >----------------------*/,{ - /* - * The target may want to transfer too much data. - * - * If phase is DATA OUT write 1 byte and count it. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), - 16, - SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT, - HADDR_1 (scratch), - SCR_JUMP, - PADDR_B (data_ovrun2), - /* - * If WSR is set, clear this condition, and - * count this byte. - */ - SCR_FROM_REG (scntl2), - 0, - SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), - 16, - SCR_REG_REG (scntl2, SCR_OR, WSR), - 0, - SCR_JUMP, - PADDR_B (data_ovrun2), - /* - * Finally check against DATA IN phase. - * Signal data overrun to the C code - * and jump to dispatcher if not so. - * Read 1 byte otherwise and count it. - */ - SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)), - 16, - SCR_INT, - SIR_DATA_OVERRUN, - SCR_JUMP, - PADDR_A (dispatch), - SCR_CHMOV_ABS (1) ^ SCR_DATA_IN, - HADDR_1 (scratch), -}/*-------------------------< DATA_OVRUN2 >----------------------*/,{ - /* - * Count this byte. - * This will allow to return a negative - * residual to user. - */ - SCR_REG_REG (scratcha, SCR_ADD, 0x01), - 0, - SCR_REG_REG (scratcha1, SCR_ADDC, 0), - 0, - SCR_REG_REG (scratcha2, SCR_ADDC, 0), - 0, - /* - * .. and repeat as required. - */ - SCR_JUMP, - PADDR_B (data_ovrun1), -}/*-------------------------< ABORT_RESEL >----------------------*/,{ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - /* - * send the abort/abortag/reset message - * we expect an immediate disconnect - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - SCR_WAIT_DISC, - 0, - SCR_INT, - SIR_RESEL_ABORTED, - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< RESEND_IDENT >---------------------*/,{ - /* - * The target stays in MSG OUT phase after having acked - * Identify [+ Tag [+ Extended message ]]. Targets shall - * behave this way on parity error. - * We must send it again all the messages. - */ - SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */ - 0, /* 1rst ACK = 90 ns. Hope the chip isn't too fast */ - SCR_JUMP, - PADDR_A (send_ident), -}/*-------------------------< IDENT_BREAK >----------------------*/,{ - SCR_CLR (SCR_ATN), - 0, - SCR_JUMP, - PADDR_A (select2), -}/*-------------------------< IDENT_BREAK_ATN >------------------*/,{ - SCR_SET (SCR_ATN), - 0, - SCR_JUMP, - PADDR_A (select2), -}/*-------------------------< SDATA_IN >-------------------------*/,{ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_dsb, sense), - SCR_CALL, - PADDR_A (datai_done), - SCR_JUMP, - PADDR_B (data_ovrun), -}/*-------------------------< RESEL_BAD_LUN >--------------------*/,{ - /* - * Message is an IDENTIFY, but lun is unknown. - * Signal problem to C code for logging the event. - * Send a M_ABORT to clear all pending tasks. - */ - SCR_INT, - SIR_RESEL_BAD_LUN, - SCR_JUMP, - PADDR_B (abort_resel), -}/*-------------------------< BAD_I_T_L >------------------------*/,{ - /* - * We donnot have a task for that I_T_L. - * Signal problem to C code for logging the event. - * Send a M_ABORT message. - */ - SCR_INT, - SIR_RESEL_BAD_I_T_L, - SCR_JUMP, - PADDR_B (abort_resel), -}/*-------------------------< BAD_I_T_L_Q >----------------------*/,{ - /* - * We donnot have a task that matches the tag. - * Signal problem to C code for logging the event. - * Send a M_ABORTTAG message. - */ - SCR_INT, - SIR_RESEL_BAD_I_T_L_Q, - SCR_JUMP, - PADDR_B (abort_resel), -}/*-------------------------< BAD_STATUS >-----------------------*/,{ - /* - * Anything different from INTERMEDIATE - * CONDITION MET should be a bad SCSI status, - * given that GOOD status has already been tested. - * Call the C code. - */ - SCR_COPY (4), - PADDR_B (startpos), - RADDR_1 (scratcha), - SCR_INT ^ IFFALSE (DATA (S_COND_MET)), - SIR_BAD_SCSI_STATUS, - SCR_RETURN, - 0, -}/*-------------------------< WSR_MA_HELPER >--------------------*/,{ - /* - * Helper for the C code when WSR bit is set. - * Perform the move of the residual byte. - */ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_ccb, phys.wresid), - SCR_JUMP, - PADDR_A (dispatch), - -}/*-------------------------< ZERO >-----------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< SCRATCH >--------------------------*/,{ - SCR_DATA_ZERO, /* MUST BE BEFORE SCRATCH1 */ -}/*-------------------------< SCRATCH1 >-------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< PREV_DONE >------------------------*/,{ - SCR_DATA_ZERO, /* MUST BE BEFORE DONE_POS ! */ -}/*-------------------------< DONE_POS >-------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< NEXTJOB >--------------------------*/,{ - SCR_DATA_ZERO, /* MUST BE BEFORE STARTPOS ! */ -}/*-------------------------< STARTPOS >-------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< TARGTBL >--------------------------*/,{ - SCR_DATA_ZERO, -}/*--------------------------<>----------------------------------*/ -}; - -static struct SYM_FWZ_SCR SYM_FWZ_SCR = { - /*-------------------------< SNOOPTEST >------------------------*/{ - /* - * Read the variable. - */ - SCR_COPY (4), - HADDR_1 (scratch), - RADDR_1 (scratcha), - /* - * Write the variable. - */ - SCR_COPY (4), - RADDR_1 (temp), - HADDR_1 (scratch), - /* - * Read back the variable. - */ - SCR_COPY (4), - HADDR_1 (scratch), - RADDR_1 (temp), -}/*-------------------------< SNOOPEND >-------------------------*/,{ - /* - * And stop. - */ - SCR_INT, - 99, -}/*--------------------------<>----------------------------------*/ -}; diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw2.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw2.h deleted file mode 100644 index c87d7244..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_fw2.h +++ /dev/null @@ -1,1875 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * Scripts for SYMBIOS-Processor - * - * We have to know the offsets of all labels before we reach - * them (for forward jumps). Therefore we declare a struct - * here. If you make changes inside the script, - * - * DONT FORGET TO CHANGE THE LENGTHS HERE! - */ - -/* - * Script fragments which are loaded into the on-chip RAM - * of 825A, 875, 876, 895, 895A, 896 and 1010 chips. - * Must not exceed 4K bytes. - */ -struct SYM_FWA_SCR { - u32 start [ 14]; - u32 getjob_begin [ 4]; - u32 getjob_end [ 4]; -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - u32 select [ 6]; -#else - u32 select [ 4]; -#endif -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 - u32 is_dmap_dirty [ 4]; -#endif - u32 wf_sel_done [ 2]; - u32 sel_done [ 2]; - u32 send_ident [ 2]; -#ifdef SYM_CONF_IARB_SUPPORT - u32 select2 [ 8]; -#else - u32 select2 [ 2]; -#endif - u32 command [ 2]; - u32 dispatch [ 28]; - u32 sel_no_cmd [ 10]; - u32 init [ 6]; - u32 clrack [ 4]; - u32 datai_done [ 10]; - u32 datai_done_wsr [ 20]; - u32 datao_done [ 10]; - u32 datao_done_wss [ 6]; - u32 datai_phase [ 4]; - u32 datao_phase [ 6]; - u32 msg_in [ 2]; - u32 msg_in2 [ 10]; -#ifdef SYM_CONF_IARB_SUPPORT - u32 status [ 14]; -#else - u32 status [ 10]; -#endif - u32 complete [ 6]; - u32 complete2 [ 12]; - u32 done [ 14]; - u32 done_end [ 2]; - u32 complete_error [ 4]; - u32 save_dp [ 12]; - u32 restore_dp [ 8]; - u32 disconnect [ 12]; -#ifdef SYM_CONF_IARB_SUPPORT - u32 idle [ 4]; -#else - u32 idle [ 2]; -#endif -#ifdef SYM_CONF_IARB_SUPPORT - u32 ungetjob [ 6]; -#else - u32 ungetjob [ 4]; -#endif -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - u32 reselect [ 4]; -#else - u32 reselect [ 2]; -#endif - u32 reselected [ 22]; - u32 resel_scntl4 [ 20]; - u32 resel_lun0 [ 6]; -#if SYM_CONF_MAX_TASK*4 > 512 - u32 resel_tag [ 26]; -#elif SYM_CONF_MAX_TASK*4 > 256 - u32 resel_tag [ 20]; -#else - u32 resel_tag [ 16]; -#endif - u32 resel_dsa [ 2]; - u32 resel_dsa1 [ 4]; - u32 resel_no_tag [ 6]; - u32 data_in [SYM_CONF_MAX_SG * 2]; - u32 data_in2 [ 4]; - u32 data_out [SYM_CONF_MAX_SG * 2]; - u32 data_out2 [ 4]; - u32 pm0_data [ 12]; - u32 pm0_data_out [ 6]; - u32 pm0_data_end [ 6]; - u32 pm1_data [ 12]; - u32 pm1_data_out [ 6]; - u32 pm1_data_end [ 6]; -}; - -/* - * Script fragments which stay in main memory for all chips - * except for chips that support 8K on-chip RAM. - */ -struct SYM_FWB_SCR { - u32 start64 [ 2]; - u32 no_data [ 2]; -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - u32 sel_for_abort [ 18]; -#else - u32 sel_for_abort [ 16]; -#endif - u32 sel_for_abort_1 [ 2]; - u32 msg_in_etc [ 12]; - u32 msg_received [ 4]; - u32 msg_weird_seen [ 4]; - u32 msg_extended [ 20]; - u32 msg_bad [ 6]; - u32 msg_weird [ 4]; - u32 msg_weird1 [ 8]; - - u32 wdtr_resp [ 6]; - u32 send_wdtr [ 4]; - u32 sdtr_resp [ 6]; - u32 send_sdtr [ 4]; - u32 ppr_resp [ 6]; - u32 send_ppr [ 4]; - u32 nego_bad_phase [ 4]; - u32 msg_out [ 4]; - u32 msg_out_done [ 4]; - u32 data_ovrun [ 2]; - u32 data_ovrun1 [ 22]; - u32 data_ovrun2 [ 8]; - u32 abort_resel [ 16]; - u32 resend_ident [ 4]; - u32 ident_break [ 4]; - u32 ident_break_atn [ 4]; - u32 sdata_in [ 6]; - u32 resel_bad_lun [ 4]; - u32 bad_i_t_l [ 4]; - u32 bad_i_t_l_q [ 4]; - u32 bad_status [ 6]; - u32 pm_handle [ 20]; - u32 pm_handle1 [ 4]; - u32 pm_save [ 4]; - u32 pm0_save [ 12]; - u32 pm_save_end [ 4]; - u32 pm1_save [ 14]; - - /* WSR handling */ - u32 pm_wsr_handle [ 38]; - u32 wsr_ma_helper [ 4]; - - /* Data area */ - u32 zero [ 1]; - u32 scratch [ 1]; - u32 pm0_data_addr [ 1]; - u32 pm1_data_addr [ 1]; - u32 done_pos [ 1]; - u32 startpos [ 1]; - u32 targtbl [ 1]; -}; - -/* - * Script fragments used at initialisations. - * Only runs out of main memory. - */ -struct SYM_FWZ_SCR { - u32 snooptest [ 6]; - u32 snoopend [ 2]; -}; - -static struct SYM_FWA_SCR SYM_FWA_SCR = { -/*--------------------------< START >----------------------------*/ { - /* - * Switch the LED on. - * Will be patched with a NO_OP if LED - * not needed or not desired. - */ - SCR_REG_REG (gpreg, SCR_AND, 0xfe), - 0, - /* - * Clear SIGP. - */ - SCR_FROM_REG (ctest2), - 0, - /* - * Stop here if the C code wants to perform - * some error recovery procedure manually. - * (Indicate this by setting SEM in ISTAT) - */ - SCR_FROM_REG (istat), - 0, - /* - * Report to the C code the next position in - * the start queue the SCRIPTS will schedule. - * The C code must not change SCRATCHA. - */ - SCR_LOAD_ABS (scratcha, 4), - PADDR_B (startpos), - SCR_INT ^ IFTRUE (MASK (SEM, SEM)), - SIR_SCRIPT_STOPPED, - /* - * Start the next job. - * - * @DSA = start point for this job. - * SCRATCHA = address of this job in the start queue. - * - * We will restore startpos with SCRATCHA if we fails the - * arbitration or if it is the idle job. - * - * The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS - * is a critical path. If it is partially executed, it then - * may happen that the job address is not yet in the DSA - * and the next queue position points to the next JOB. - */ - SCR_LOAD_ABS (dsa, 4), - PADDR_B (startpos), - SCR_LOAD_REL (temp, 4), - 4, -}/*-------------------------< GETJOB_BEGIN >---------------------*/,{ - SCR_STORE_ABS (temp, 4), - PADDR_B (startpos), - SCR_LOAD_REL (dsa, 4), - 0, -}/*-------------------------< GETJOB_END >-----------------------*/,{ - SCR_LOAD_REL (temp, 4), - 0, - SCR_RETURN, - 0, -}/*-------------------------< SELECT >---------------------------*/,{ - /* - * DSA contains the address of a scheduled - * data structure. - * - * SCRATCHA contains the address of the start queue - * entry which points to the next job. - * - * Set Initiator mode. - * - * (Target mode is left as an exercise for the reader) - */ -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - SCR_CLR (SCR_TRG), - 0, -#endif - /* - * And try to select this target. - */ - SCR_SEL_TBL_ATN ^ offsetof (struct sym_dsb, select), - PADDR_A (ungetjob), - /* - * Now there are 4 possibilities: - * - * (1) The chip loses arbitration. - * This is ok, because it will try again, - * when the bus becomes idle. - * (But beware of the timeout function!) - * - * (2) The chip is reselected. - * Then the script processor takes the jump - * to the RESELECT label. - * - * (3) The chip wins arbitration. - * Then it will execute SCRIPTS instruction until - * the next instruction that checks SCSI phase. - * Then will stop and wait for selection to be - * complete or selection time-out to occur. - * - * After having won arbitration, the SCRIPTS - * processor is able to execute instructions while - * the SCSI core is performing SCSI selection. - */ - /* - * Initialize the status registers - */ - SCR_LOAD_REL (scr0, 4), - offsetof (struct sym_ccb, phys.head.status), - /* - * We may need help from CPU if the DMA segment - * registers aren't up-to-date for this IO. - * Patched with NOOP for chips that donnot - * support DAC addressing. - */ -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 -}/*-------------------------< IS_DMAP_DIRTY >--------------------*/,{ - SCR_FROM_REG (HX_REG), - 0, - SCR_INT ^ IFTRUE (MASK (HX_DMAP_DIRTY, HX_DMAP_DIRTY)), - SIR_DMAP_DIRTY, -#endif -}/*-------------------------< WF_SEL_DONE >----------------------*/,{ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), - SIR_SEL_ATN_NO_MSG_OUT, -}/*-------------------------< SEL_DONE >-------------------------*/,{ - /* - * C1010-33 errata work-around. - * Due to a race, the SCSI core may not have - * loaded SCNTL3 on SEL_TBL instruction. - * We reload it once phase is stable. - * Patched with a NOOP for other chips. - */ - SCR_LOAD_REL (scntl3, 1), - offsetof(struct sym_dsb, select.sel_scntl3), -}/*-------------------------< SEND_IDENT >-----------------------*/,{ - /* - * Selection complete. - * Send the IDENTIFY and possibly the TAG message - * and negotiation message if present. - */ - SCR_MOVE_TBL ^ SCR_MSG_OUT, - offsetof (struct sym_dsb, smsg), -}/*-------------------------< SELECT2 >--------------------------*/,{ -#ifdef SYM_CONF_IARB_SUPPORT - /* - * Set IMMEDIATE ARBITRATION if we have been given - * a hint to do so. (Some job to do after this one). - */ - SCR_FROM_REG (HF_REG), - 0, - SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)), - 8, - SCR_REG_REG (scntl1, SCR_OR, IARB), - 0, -#endif - /* - * Anticipate the COMMAND phase. - * This is the PHASE we expect at this point. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)), - PADDR_A (sel_no_cmd), -}/*-------------------------< COMMAND >--------------------------*/,{ - /* - * ... and send the command - */ - SCR_MOVE_TBL ^ SCR_COMMAND, - offsetof (struct sym_dsb, cmd), -}/*-------------------------< DISPATCH >-------------------------*/,{ - /* - * MSG_IN is the only phase that shall be - * entered at least once for each (re)selection. - * So we test it first. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR_A (msg_in), - SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)), - PADDR_A (datao_phase), - SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)), - PADDR_A (datai_phase), - SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), - PADDR_A (status), - SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), - PADDR_A (command), - SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), - PADDR_B (msg_out), - /* - * Discard as many illegal phases as - * required and tell the C code about. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)), - 16, - SCR_MOVE_ABS (1) ^ SCR_ILG_OUT, - HADDR_1 (scratch), - SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)), - -16, - SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)), - 16, - SCR_MOVE_ABS (1) ^ SCR_ILG_IN, - HADDR_1 (scratch), - SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)), - -16, - SCR_INT, - SIR_BAD_PHASE, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< SEL_NO_CMD >-----------------------*/,{ - /* - * The target does not switch to command - * phase after IDENTIFY has been sent. - * - * If it stays in MSG OUT phase send it - * the IDENTIFY again. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), - PADDR_B (resend_ident), - /* - * If target does not switch to MSG IN phase - * and we sent a negotiation, assert the - * failure immediately. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR_A (dispatch), - SCR_FROM_REG (HS_REG), - 0, - SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), - SIR_NEGO_FAILED, - /* - * Jump to dispatcher. - */ - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< INIT >-----------------------------*/,{ - /* - * Wait for the SCSI RESET signal to be - * inactive before restarting operations, - * since the chip may hang on SEL_ATN - * if SCSI RESET is active. - */ - SCR_FROM_REG (sstat0), - 0, - SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)), - -16, - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< CLRACK >---------------------------*/,{ - /* - * Terminate possible pending message phase. - */ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAI_DONE >-----------------------*/,{ - /* - * Save current pointer to LASTP. - */ - SCR_STORE_REL (temp, 4), - offsetof (struct sym_ccb, phys.head.lastp), - /* - * If the SWIDE is not full, jump to dispatcher. - * We anticipate a STATUS phase. - */ - SCR_FROM_REG (scntl2), - 0, - SCR_JUMP ^ IFTRUE (MASK (WSR, WSR)), - PADDR_A (datai_done_wsr), - SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)), - PADDR_A (status), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAI_DONE_WSR >-------------------*/,{ - /* - * The SWIDE is full. - * Clear this condition. - */ - SCR_REG_REG (scntl2, SCR_OR, WSR), - 0, - /* - * We are expecting an IGNORE RESIDUE message - * from the device, otherwise we are in data - * overrun condition. Check against MSG_IN phase. - */ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), - SIR_SWIDE_OVERRUN, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR_A (dispatch), - /* - * We are in MSG_IN phase, - * Read the first byte of the message. - * If it is not an IGNORE RESIDUE message, - * signal overrun and jump to message - * processing. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[0]), - SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)), - SIR_SWIDE_OVERRUN, - SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)), - PADDR_A (msg_in2), - /* - * We got the message we expected. - * Read the 2nd byte, and jump to dispatcher. - */ - SCR_CLR (SCR_ACK), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[1]), - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAO_DONE >-----------------------*/,{ - /* - * Save current pointer to LASTP. - */ - SCR_STORE_REL (temp, 4), - offsetof (struct sym_ccb, phys.head.lastp), - /* - * If the SODL is not full jump to dispatcher. - * We anticipate a STATUS phase. - */ - SCR_FROM_REG (scntl2), - 0, - SCR_JUMP ^ IFTRUE (MASK (WSS, WSS)), - PADDR_A (datao_done_wss), - SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)), - PADDR_A (status), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAO_DONE_WSS >-------------------*/,{ - /* - * The SODL is full, clear this condition. - */ - SCR_REG_REG (scntl2, SCR_OR, WSS), - 0, - /* - * And signal a DATA UNDERRUN condition - * to the C code. - */ - SCR_INT, - SIR_SODL_UNDERRUN, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATAI_PHASE >----------------------*/,{ - /* - * Jump to current pointer. - */ - SCR_LOAD_REL (temp, 4), - offsetof (struct sym_ccb, phys.head.lastp), - SCR_RETURN, - 0, -}/*-------------------------< DATAO_PHASE >----------------------*/,{ - /* - * C1010-66 errata work-around. - * Extra clocks of data hold must be inserted - * in DATA OUT phase on 33 MHz PCI BUS. - * Patched with a NOOP for other chips. - */ - SCR_REG_REG (scntl4, SCR_OR, (XCLKH_DT|XCLKH_ST)), - 0, - /* - * Jump to current pointer. - */ - SCR_LOAD_REL (temp, 4), - offsetof (struct sym_ccb, phys.head.lastp), - SCR_RETURN, - 0, -}/*-------------------------< MSG_IN >---------------------------*/,{ - /* - * Get the first byte of the message. - * - * The script processor doesn't negate the - * ACK signal after this transfer. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[0]), -}/*-------------------------< MSG_IN2 >--------------------------*/,{ - /* - * Check first against 1 byte messages - * that we handle from SCRIPTS. - */ - SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)), - PADDR_A (complete), - SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), - PADDR_A (disconnect), - SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)), - PADDR_A (save_dp), - SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)), - PADDR_A (restore_dp), - /* - * We handle all other messages from the - * C code, so no need to waste on-chip RAM - * for those ones. - */ - SCR_JUMP, - PADDR_B (msg_in_etc), -}/*-------------------------< STATUS >---------------------------*/,{ - /* - * get the status - */ - SCR_MOVE_ABS (1) ^ SCR_STATUS, - HADDR_1 (scratch), -#ifdef SYM_CONF_IARB_SUPPORT - /* - * If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, - * since we may have to tamper the start queue from - * the C code. - */ - SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)), - 8, - SCR_REG_REG (scntl1, SCR_AND, ~IARB), - 0, -#endif - /* - * save status to scsi_status. - * mark as complete. - */ - SCR_TO_REG (SS_REG), - 0, - SCR_LOAD_REG (HS_REG, HS_COMPLETE), - 0, - /* - * Anticipate the MESSAGE PHASE for - * the TASK COMPLETE message. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR_A (msg_in), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< COMPLETE >-------------------------*/,{ - /* - * Complete message. - * - * When we terminate the cycle by clearing ACK, - * the target may disconnect immediately. - * - * We don't want to be told of an "unexpected disconnect", - * so we disable this feature. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - /* - * Terminate cycle ... - */ - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - /* - * ... and wait for the disconnect. - */ - SCR_WAIT_DISC, - 0, -}/*-------------------------< COMPLETE2 >------------------------*/,{ - /* - * Save host status. - */ - SCR_STORE_REL (scr0, 4), - offsetof (struct sym_ccb, phys.head.status), - /* - * Some bridges may reorder DMA writes to memory. - * We donnot want the CPU to deal with completions - * without all the posted write having been flushed - * to memory. This DUMMY READ should flush posted - * buffers prior to the CPU having to deal with - * completions. - */ - SCR_LOAD_REL (scr0, 4), /* DUMMY READ */ - offsetof (struct sym_ccb, phys.head.status), - - /* - * If command resulted in not GOOD status, - * call the C code if needed. - */ - SCR_FROM_REG (SS_REG), - 0, - SCR_CALL ^ IFFALSE (DATA (S_GOOD)), - PADDR_B (bad_status), - /* - * If we performed an auto-sense, call - * the C code to synchronyze task aborts - * with UNIT ATTENTION conditions. - */ - SCR_FROM_REG (HF_REG), - 0, - SCR_JUMP ^ IFFALSE (MASK (0 ,(HF_SENSE|HF_EXT_ERR))), - PADDR_A (complete_error), -}/*-------------------------< DONE >-----------------------------*/,{ - /* - * Copy the DSA to the DONE QUEUE and - * signal completion to the host. - * If we are interrupted between DONE - * and DONE_END, we must reset, otherwise - * the completed CCB may be lost. - */ - SCR_STORE_ABS (dsa, 4), - PADDR_B (scratch), - SCR_LOAD_ABS (dsa, 4), - PADDR_B (done_pos), - SCR_LOAD_ABS (scratcha, 4), - PADDR_B (scratch), - SCR_STORE_REL (scratcha, 4), - 0, - /* - * The instruction below reads the DONE QUEUE next - * free position from memory. - * In addition it ensures that all PCI posted writes - * are flushed and so the DSA value of the done - * CCB is visible by the CPU before INTFLY is raised. - */ - SCR_LOAD_REL (scratcha, 4), - 4, - SCR_INT_FLY, - 0, - SCR_STORE_ABS (scratcha, 4), - PADDR_B (done_pos), -}/*-------------------------< DONE_END >-------------------------*/,{ - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< COMPLETE_ERROR >-------------------*/,{ - SCR_LOAD_ABS (scratcha, 4), - PADDR_B (startpos), - SCR_INT, - SIR_COMPLETE_ERROR, -}/*-------------------------< SAVE_DP >--------------------------*/,{ - /* - * Clear ACK immediately. - * No need to delay it. - */ - SCR_CLR (SCR_ACK), - 0, - /* - * Keep track we received a SAVE DP, so - * we will switch to the other PM context - * on the next PM since the DP may point - * to the current PM context. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED), - 0, - /* - * SAVE_DP message: - * Copy LASTP to SAVEP. - */ - SCR_LOAD_REL (scratcha, 4), - offsetof (struct sym_ccb, phys.head.lastp), - SCR_STORE_REL (scratcha, 4), - offsetof (struct sym_ccb, phys.head.savep), - /* - * Anticipate the MESSAGE PHASE for - * the DISCONNECT message. - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), - PADDR_A (msg_in), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< RESTORE_DP >-----------------------*/,{ - /* - * Clear ACK immediately. - * No need to delay it. - */ - SCR_CLR (SCR_ACK), - 0, - /* - * Copy SAVEP to LASTP. - */ - SCR_LOAD_REL (scratcha, 4), - offsetof (struct sym_ccb, phys.head.savep), - SCR_STORE_REL (scratcha, 4), - offsetof (struct sym_ccb, phys.head.lastp), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DISCONNECT >-----------------------*/,{ - /* - * DISCONNECTing ... - * - * disable the "unexpected disconnect" feature, - * and remove the ACK signal. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - /* - * Wait for the disconnect. - */ - SCR_WAIT_DISC, - 0, - /* - * Status is: DISCONNECTED. - */ - SCR_LOAD_REG (HS_REG, HS_DISCONNECT), - 0, - /* - * Save host status. - */ - SCR_STORE_REL (scr0, 4), - offsetof (struct sym_ccb, phys.head.status), - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< IDLE >-----------------------------*/,{ - /* - * Nothing to do? - * Switch the LED off and wait for reselect. - * Will be patched with a NO_OP if LED - * not needed or not desired. - */ - SCR_REG_REG (gpreg, SCR_OR, 0x01), - 0, -#ifdef SYM_CONF_IARB_SUPPORT - SCR_JUMPR, - 8, -#endif -}/*-------------------------< UNGETJOB >-------------------------*/,{ -#ifdef SYM_CONF_IARB_SUPPORT - /* - * Set IMMEDIATE ARBITRATION, for the next time. - * This will give us better chance to win arbitration - * for the job we just wanted to do. - */ - SCR_REG_REG (scntl1, SCR_OR, IARB), - 0, -#endif - /* - * We are not able to restart the SCRIPTS if we are - * interrupted and these instruction haven't been - * all executed. BTW, this is very unlikely to - * happen, but we check that from the C code. - */ - SCR_LOAD_REG (dsa, 0xff), - 0, - SCR_STORE_ABS (scratcha, 4), - PADDR_B (startpos), -}/*-------------------------< RESELECT >-------------------------*/,{ -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - /* - * Make sure we are in initiator mode. - */ - SCR_CLR (SCR_TRG), - 0, -#endif - /* - * Sleep waiting for a reselection. - */ - SCR_WAIT_RESEL, - PADDR_A(start), -}/*-------------------------< RESELECTED >-----------------------*/,{ - /* - * Switch the LED on. - * Will be patched with a NO_OP if LED - * not needed or not desired. - */ - SCR_REG_REG (gpreg, SCR_AND, 0xfe), - 0, - /* - * load the target id into the sdid - */ - SCR_REG_SFBR (ssid, SCR_AND, 0x8F), - 0, - SCR_TO_REG (sdid), - 0, - /* - * Load the target control block address - */ - SCR_LOAD_ABS (dsa, 4), - PADDR_B (targtbl), - SCR_SFBR_REG (dsa, SCR_SHL, 0), - 0, - SCR_REG_REG (dsa, SCR_SHL, 0), - 0, - SCR_REG_REG (dsa, SCR_AND, 0x3c), - 0, - SCR_LOAD_REL (dsa, 4), - 0, - /* - * We expect MESSAGE IN phase. - * If not, get help from the C code. - */ - SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), - SIR_RESEL_NO_MSG_IN, - /* - * Load the legacy synchronous transfer registers. - */ - SCR_LOAD_REL (scntl3, 1), - offsetof(struct sym_tcb, head.wval), - SCR_LOAD_REL (sxfer, 1), - offsetof(struct sym_tcb, head.sval), -}/*-------------------------< RESEL_SCNTL4 >---------------------*/,{ - /* - * The C1010 uses a new synchronous timing scheme. - * Will be patched with a NO_OP if not a C1010. - */ - SCR_LOAD_REL (scntl4, 1), - offsetof(struct sym_tcb, head.uval), - /* - * Get the IDENTIFY message. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin), - /* - * If IDENTIFY LUN #0, use a faster path - * to find the LCB structure. - */ - SCR_JUMP ^ IFTRUE (MASK (0x80, 0xbf)), - PADDR_A (resel_lun0), - /* - * If message isn't an IDENTIFY, - * tell the C code about. - */ - SCR_INT ^ IFFALSE (MASK (0x80, 0x80)), - SIR_RESEL_NO_IDENTIFY, - /* - * It is an IDENTIFY message, - * Load the LUN control block address. - */ - SCR_LOAD_REL (dsa, 4), - offsetof(struct sym_tcb, head.luntbl_sa), - SCR_SFBR_REG (dsa, SCR_SHL, 0), - 0, - SCR_REG_REG (dsa, SCR_SHL, 0), - 0, - SCR_REG_REG (dsa, SCR_AND, 0xfc), - 0, - SCR_LOAD_REL (dsa, 4), - 0, - SCR_JUMPR, - 8, -}/*-------------------------< RESEL_LUN0 >-----------------------*/,{ - /* - * LUN 0 special case (but usual one :)) - */ - SCR_LOAD_REL (dsa, 4), - offsetof(struct sym_tcb, head.lun0_sa), - /* - * Jump indirectly to the reselect action for this LUN. - */ - SCR_LOAD_REL (temp, 4), - offsetof(struct sym_lcb, head.resel_sa), - SCR_RETURN, - 0, - /* In normal situations, we jump to RESEL_TAG or RESEL_NO_TAG */ -}/*-------------------------< RESEL_TAG >------------------------*/,{ - /* - * ACK the IDENTIFY previously received. - */ - SCR_CLR (SCR_ACK), - 0, - /* - * It shall be a tagged command. - * Read SIMPLE+TAG. - * The C code will deal with errors. - * Aggressive optimization, isn't it? :) - */ - SCR_MOVE_ABS (2) ^ SCR_MSG_IN, - HADDR_1 (msgin), - /* - * Load the pointer to the tagged task - * table for this LUN. - */ - SCR_LOAD_REL (dsa, 4), - offsetof(struct sym_lcb, head.itlq_tbl_sa), - /* - * The SIDL still contains the TAG value. - * Aggressive optimization, isn't it? :):) - */ - SCR_REG_SFBR (sidl, SCR_SHL, 0), - 0, -#if SYM_CONF_MAX_TASK*4 > 512 - SCR_JUMPR ^ IFFALSE (CARRYSET), - 8, - SCR_REG_REG (dsa1, SCR_OR, 2), - 0, - SCR_REG_REG (sfbr, SCR_SHL, 0), - 0, - SCR_JUMPR ^ IFFALSE (CARRYSET), - 8, - SCR_REG_REG (dsa1, SCR_OR, 1), - 0, -#elif SYM_CONF_MAX_TASK*4 > 256 - SCR_JUMPR ^ IFFALSE (CARRYSET), - 8, - SCR_REG_REG (dsa1, SCR_OR, 1), - 0, -#endif - /* - * Retrieve the DSA of this task. - * JUMP indirectly to the restart point of the CCB. - */ - SCR_SFBR_REG (dsa, SCR_AND, 0xfc), - 0, - SCR_LOAD_REL (dsa, 4), - 0, - SCR_LOAD_REL (temp, 4), - offsetof(struct sym_ccb, phys.head.go.restart), - SCR_RETURN, - 0, - /* In normal situations we branch to RESEL_DSA */ -}/*-------------------------< RESEL_DSA >------------------------*/,{ - /* - * ACK the IDENTIFY or TAG previously received. - */ - SCR_CLR (SCR_ACK), - 0, -}/*-------------------------< RESEL_DSA1 >-----------------------*/,{ - /* - * Initialize the status registers - */ - SCR_LOAD_REL (scr0, 4), - offsetof (struct sym_ccb, phys.head.status), - /* - * Jump to dispatcher. - */ - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< RESEL_NO_TAG >---------------------*/,{ - /* - * Load the DSA with the unique ITL task. - */ - SCR_LOAD_REL (dsa, 4), - offsetof(struct sym_lcb, head.itl_task_sa), - /* - * JUMP indirectly to the restart point of the CCB. - */ - SCR_LOAD_REL (temp, 4), - offsetof(struct sym_ccb, phys.head.go.restart), - SCR_RETURN, - 0, - /* In normal situations we branch to RESEL_DSA */ -}/*-------------------------< DATA_IN >--------------------------*/,{ -/* - * Because the size depends on the - * #define SYM_CONF_MAX_SG parameter, - * it is filled in at runtime. - * - * ##===========< i=0; i========= - * || SCR_CHMOV_TBL ^ SCR_DATA_IN, - * || offsetof (struct sym_dsb, data[ i]), - * ##========================================== - */ -0 -}/*-------------------------< DATA_IN2 >-------------------------*/,{ - SCR_CALL, - PADDR_A (datai_done), - SCR_JUMP, - PADDR_B (data_ovrun), -}/*-------------------------< DATA_OUT >-------------------------*/,{ -/* - * Because the size depends on the - * #define SYM_CONF_MAX_SG parameter, - * it is filled in at runtime. - * - * ##===========< i=0; i========= - * || SCR_CHMOV_TBL ^ SCR_DATA_OUT, - * || offsetof (struct sym_dsb, data[ i]), - * ##========================================== - */ -0 -}/*-------------------------< DATA_OUT2 >------------------------*/,{ - SCR_CALL, - PADDR_A (datao_done), - SCR_JUMP, - PADDR_B (data_ovrun), -}/*-------------------------< PM0_DATA >-------------------------*/,{ - /* - * Read our host flags to SFBR, so we will be able - * to check against the data direction we expect. - */ - SCR_FROM_REG (HF_REG), - 0, - /* - * Check against actual DATA PHASE. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), - PADDR_A (pm0_data_out), - /* - * Actual phase is DATA IN. - * Check against expected direction. - */ - SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDR_B (data_ovrun), - /* - * Keep track we are moving data from the - * PM0 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), - 0, - /* - * Move the data to memory. - */ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_ccb, phys.pm0.sg), - SCR_JUMP, - PADDR_A (pm0_data_end), -}/*-------------------------< PM0_DATA_OUT >---------------------*/,{ - /* - * Actual phase is DATA OUT. - * Check against expected direction. - */ - SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDR_B (data_ovrun), - /* - * Keep track we are moving data from the - * PM0 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0), - 0, - /* - * Move the data from memory. - */ - SCR_CHMOV_TBL ^ SCR_DATA_OUT, - offsetof (struct sym_ccb, phys.pm0.sg), -}/*-------------------------< PM0_DATA_END >---------------------*/,{ - /* - * Clear the flag that told we were moving - * data from the PM0 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)), - 0, - /* - * Return to the previous DATA script which - * is guaranteed by design (if no bug) to be - * the main DATA script for this transfer. - */ - SCR_LOAD_REL (temp, 4), - offsetof (struct sym_ccb, phys.pm0.ret), - SCR_RETURN, - 0, -}/*-------------------------< PM1_DATA >-------------------------*/,{ - /* - * Read our host flags to SFBR, so we will be able - * to check against the data direction we expect. - */ - SCR_FROM_REG (HF_REG), - 0, - /* - * Check against actual DATA PHASE. - */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), - PADDR_A (pm1_data_out), - /* - * Actual phase is DATA IN. - * Check against expected direction. - */ - SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDR_B (data_ovrun), - /* - * Keep track we are moving data from the - * PM1 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), - 0, - /* - * Move the data to memory. - */ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_ccb, phys.pm1.sg), - SCR_JUMP, - PADDR_A (pm1_data_end), -}/*-------------------------< PM1_DATA_OUT >---------------------*/,{ - /* - * Actual phase is DATA OUT. - * Check against expected direction. - */ - SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)), - PADDR_B (data_ovrun), - /* - * Keep track we are moving data from the - * PM1 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1), - 0, - /* - * Move the data from memory. - */ - SCR_CHMOV_TBL ^ SCR_DATA_OUT, - offsetof (struct sym_ccb, phys.pm1.sg), -}/*-------------------------< PM1_DATA_END >---------------------*/,{ - /* - * Clear the flag that told we were moving - * data from the PM1 DATA mini-script. - */ - SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)), - 0, - /* - * Return to the previous DATA script which - * is guaranteed by design (if no bug) to be - * the main DATA script for this transfer. - */ - SCR_LOAD_REL (temp, 4), - offsetof (struct sym_ccb, phys.pm1.ret), - SCR_RETURN, - 0, -}/*-------------------------<>-----------------------------------*/ -}; - -static struct SYM_FWB_SCR SYM_FWB_SCR = { -/*--------------------------< START64 >--------------------------*/ { - /* - * SCRIPT entry point for the 895A, 896 and 1010. - * For now, there is no specific stuff for those - * chips at this point, but this may come. - */ - SCR_JUMP, - PADDR_A (init), -}/*-------------------------< NO_DATA >--------------------------*/,{ - SCR_JUMP, - PADDR_B (data_ovrun), -}/*-------------------------< SEL_FOR_ABORT >--------------------*/,{ - /* - * We are jumped here by the C code, if we have - * some target to reset or some disconnected - * job to abort. Since error recovery is a serious - * busyness, we will really reset the SCSI BUS, if - * case of a SCSI interrupt occurring in this path. - */ -#ifdef SYM_CONF_TARGET_ROLE_SUPPORT - /* - * Set initiator mode. - */ - SCR_CLR (SCR_TRG), - 0, -#endif - /* - * And try to select this target. - */ - SCR_SEL_TBL_ATN ^ offsetof (struct sym_hcb, abrt_sel), - PADDR_A (reselect), - /* - * Wait for the selection to complete or - * the selection to time out. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)), - -8, - /* - * Call the C code. - */ - SCR_INT, - SIR_TARGET_SELECTED, - /* - * The C code should let us continue here. - * Send the 'kiss of death' message. - * We expect an immediate disconnect once - * the target has eaten the message. - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_MOVE_TBL ^ SCR_MSG_OUT, - offsetof (struct sym_hcb, abrt_tbl), - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - SCR_WAIT_DISC, - 0, - /* - * Tell the C code that we are done. - */ - SCR_INT, - SIR_ABORT_SENT, -}/*-------------------------< SEL_FOR_ABORT_1 >------------------*/,{ - /* - * Jump at scheduler. - */ - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< MSG_IN_ETC >-----------------------*/,{ - /* - * If it is an EXTENDED (variable size message) - * Handle it. - */ - SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), - PADDR_B (msg_extended), - /* - * Let the C code handle any other - * 1 byte message. - */ - SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)), - PADDR_B (msg_received), - SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)), - PADDR_B (msg_received), - /* - * We donnot handle 2 bytes messages from SCRIPTS. - * So, let the C code deal with these ones too. - */ - SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)), - PADDR_B (msg_weird_seen), - SCR_CLR (SCR_ACK), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[1]), -}/*-------------------------< MSG_RECEIVED >---------------------*/,{ - SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */ - 0, - SCR_INT, - SIR_MSG_RECEIVED, -}/*-------------------------< MSG_WEIRD_SEEN >-------------------*/,{ - SCR_LOAD_REL (scratcha, 4), /* DUMMY READ */ - 0, - SCR_INT, - SIR_MSG_WEIRD, -}/*-------------------------< MSG_EXTENDED >---------------------*/,{ - /* - * Clear ACK and get the next byte - * assumed to be the message length. - */ - SCR_CLR (SCR_ACK), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (msgin[1]), - /* - * Try to catch some unlikely situations as 0 length - * or too large the length. - */ - SCR_JUMP ^ IFTRUE (DATA (0)), - PADDR_B (msg_weird_seen), - SCR_TO_REG (scratcha), - 0, - SCR_REG_REG (sfbr, SCR_ADD, (256-8)), - 0, - SCR_JUMP ^ IFTRUE (CARRYSET), - PADDR_B (msg_weird_seen), - /* - * We donnot handle extended messages from SCRIPTS. - * Read the amount of data corresponding to the - * message length and call the C code. - */ - SCR_STORE_REL (scratcha, 1), - offsetof (struct sym_dsb, smsg_ext.size), - SCR_CLR (SCR_ACK), - 0, - SCR_MOVE_TBL ^ SCR_MSG_IN, - offsetof (struct sym_dsb, smsg_ext), - SCR_JUMP, - PADDR_B (msg_received), -}/*-------------------------< MSG_BAD >--------------------------*/,{ - /* - * unimplemented message - reject it. - */ - SCR_INT, - SIR_REJECT_TO_SEND, - SCR_SET (SCR_ATN), - 0, - SCR_JUMP, - PADDR_A (clrack), -}/*-------------------------< MSG_WEIRD >------------------------*/,{ - /* - * weird message received - * ignore all MSG IN phases and reject it. - */ - SCR_INT, - SIR_REJECT_TO_SEND, - SCR_SET (SCR_ATN), - 0, -}/*-------------------------< MSG_WEIRD1 >-----------------------*/,{ - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), - PADDR_A (dispatch), - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - HADDR_1 (scratch), - SCR_JUMP, - PADDR_B (msg_weird1), -}/*-------------------------< WDTR_RESP >------------------------*/,{ - /* - * let the target fetch our answer. - */ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDR_B (nego_bad_phase), -}/*-------------------------< SEND_WDTR >------------------------*/,{ - /* - * Send the M_X_WIDE_REQ - */ - SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - SCR_JUMP, - PADDR_B (msg_out_done), -}/*-------------------------< SDTR_RESP >------------------------*/,{ - /* - * let the target fetch our answer. - */ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDR_B (nego_bad_phase), -}/*-------------------------< SEND_SDTR >------------------------*/,{ - /* - * Send the M_X_SYNC_REQ - */ - SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - SCR_JUMP, - PADDR_B (msg_out_done), -}/*-------------------------< PPR_RESP >-------------------------*/,{ - /* - * let the target fetch our answer. - */ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), - PADDR_B (nego_bad_phase), -}/*-------------------------< SEND_PPR >-------------------------*/,{ - /* - * Send the M_X_PPR_REQ - */ - SCR_MOVE_ABS (8) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - SCR_JUMP, - PADDR_B (msg_out_done), -}/*-------------------------< NEGO_BAD_PHASE >-------------------*/,{ - SCR_INT, - SIR_NEGO_PROTO, - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< MSG_OUT >--------------------------*/,{ - /* - * The target requests a message. - * We donnot send messages that may - * require the device to go to bus free. - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - /* - * ... wait for the next phase - * if it's a message out, send it again, ... - */ - SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), - PADDR_B (msg_out), -}/*-------------------------< MSG_OUT_DONE >---------------------*/,{ - /* - * Let the C code be aware of the - * sent message and clear the message. - */ - SCR_INT, - SIR_MSG_OUT_DONE, - /* - * ... and process the next phase - */ - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< DATA_OVRUN >-----------------------*/,{ - /* - * Use scratcha to count the extra bytes. - */ - SCR_LOAD_ABS (scratcha, 4), - PADDR_B (zero), -}/*-------------------------< DATA_OVRUN1 >----------------------*/,{ - /* - * The target may want to transfer too much data. - * - * If phase is DATA OUT write 1 byte and count it. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)), - 16, - SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT, - HADDR_1 (scratch), - SCR_JUMP, - PADDR_B (data_ovrun2), - /* - * If WSR is set, clear this condition, and - * count this byte. - */ - SCR_FROM_REG (scntl2), - 0, - SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), - 16, - SCR_REG_REG (scntl2, SCR_OR, WSR), - 0, - SCR_JUMP, - PADDR_B (data_ovrun2), - /* - * Finally check against DATA IN phase. - * Signal data overrun to the C code - * and jump to dispatcher if not so. - * Read 1 byte otherwise and count it. - */ - SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)), - 16, - SCR_INT, - SIR_DATA_OVERRUN, - SCR_JUMP, - PADDR_A (dispatch), - SCR_CHMOV_ABS (1) ^ SCR_DATA_IN, - HADDR_1 (scratch), -}/*-------------------------< DATA_OVRUN2 >----------------------*/,{ - /* - * Count this byte. - * This will allow to return a negative - * residual to user. - */ - SCR_REG_REG (scratcha, SCR_ADD, 0x01), - 0, - SCR_REG_REG (scratcha1, SCR_ADDC, 0), - 0, - SCR_REG_REG (scratcha2, SCR_ADDC, 0), - 0, - /* - * .. and repeat as required. - */ - SCR_JUMP, - PADDR_B (data_ovrun1), -}/*-------------------------< ABORT_RESEL >----------------------*/,{ - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), - 0, - /* - * send the abort/abortag/reset message - * we expect an immediate disconnect - */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, - HADDR_1 (msgout), - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - SCR_WAIT_DISC, - 0, - SCR_INT, - SIR_RESEL_ABORTED, - SCR_JUMP, - PADDR_A (start), -}/*-------------------------< RESEND_IDENT >---------------------*/,{ - /* - * The target stays in MSG OUT phase after having acked - * Identify [+ Tag [+ Extended message ]]. Targets shall - * behave this way on parity error. - * We must send it again all the messages. - */ - SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */ - 0, /* 1rst ACK = 90 ns. Hope the chip isn't too fast */ - SCR_JUMP, - PADDR_A (send_ident), -}/*-------------------------< IDENT_BREAK >----------------------*/,{ - SCR_CLR (SCR_ATN), - 0, - SCR_JUMP, - PADDR_A (select2), -}/*-------------------------< IDENT_BREAK_ATN >------------------*/,{ - SCR_SET (SCR_ATN), - 0, - SCR_JUMP, - PADDR_A (select2), -}/*-------------------------< SDATA_IN >-------------------------*/,{ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_dsb, sense), - SCR_CALL, - PADDR_A (datai_done), - SCR_JUMP, - PADDR_B (data_ovrun), -}/*-------------------------< RESEL_BAD_LUN >--------------------*/,{ - /* - * Message is an IDENTIFY, but lun is unknown. - * Signal problem to C code for logging the event. - * Send a M_ABORT to clear all pending tasks. - */ - SCR_INT, - SIR_RESEL_BAD_LUN, - SCR_JUMP, - PADDR_B (abort_resel), -}/*-------------------------< BAD_I_T_L >------------------------*/,{ - /* - * We donnot have a task for that I_T_L. - * Signal problem to C code for logging the event. - * Send a M_ABORT message. - */ - SCR_INT, - SIR_RESEL_BAD_I_T_L, - SCR_JUMP, - PADDR_B (abort_resel), -}/*-------------------------< BAD_I_T_L_Q >----------------------*/,{ - /* - * We donnot have a task that matches the tag. - * Signal problem to C code for logging the event. - * Send a M_ABORTTAG message. - */ - SCR_INT, - SIR_RESEL_BAD_I_T_L_Q, - SCR_JUMP, - PADDR_B (abort_resel), -}/*-------------------------< BAD_STATUS >-----------------------*/,{ - /* - * Anything different from INTERMEDIATE - * CONDITION MET should be a bad SCSI status, - * given that GOOD status has already been tested. - * Call the C code. - */ - SCR_LOAD_ABS (scratcha, 4), - PADDR_B (startpos), - SCR_INT ^ IFFALSE (DATA (S_COND_MET)), - SIR_BAD_SCSI_STATUS, - SCR_RETURN, - 0, -}/*-------------------------< PM_HANDLE >------------------------*/,{ - /* - * Phase mismatch handling. - * - * Since we have to deal with 2 SCSI data pointers - * (current and saved), we need at least 2 contexts. - * Each context (pm0 and pm1) has a saved area, a - * SAVE mini-script and a DATA phase mini-script. - */ - /* - * Get the PM handling flags. - */ - SCR_FROM_REG (HF_REG), - 0, - /* - * If no flags (1rst PM for example), avoid - * all the below heavy flags testing. - * This makes the normal case a bit faster. - */ - SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))), - PADDR_B (pm_handle1), - /* - * If we received a SAVE DP, switch to the - * other PM context since the savep may point - * to the current PM context. - */ - SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)), - 8, - SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM), - 0, - /* - * If we have been interrupt in a PM DATA mini-script, - * we take the return address from the corresponding - * saved area. - * This ensure the return address always points to the - * main DATA script for this transfer. - */ - SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))), - PADDR_B (pm_handle1), - SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)), - 16, - SCR_LOAD_REL (ia, 4), - offsetof(struct sym_ccb, phys.pm0.ret), - SCR_JUMP, - PADDR_B (pm_save), - SCR_LOAD_REL (ia, 4), - offsetof(struct sym_ccb, phys.pm1.ret), - SCR_JUMP, - PADDR_B (pm_save), -}/*-------------------------< PM_HANDLE1 >-----------------------*/,{ - /* - * Normal case. - * Update the return address so that it - * will point after the interrupted MOVE. - */ - SCR_REG_REG (ia, SCR_ADD, 8), - 0, - SCR_REG_REG (ia1, SCR_ADDC, 0), - 0, -}/*-------------------------< PM_SAVE >--------------------------*/,{ - /* - * Clear all the flags that told us if we were - * interrupted in a PM DATA mini-script and/or - * we received a SAVE DP. - */ - SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))), - 0, - /* - * Choose the current PM context. - */ - SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)), - PADDR_B (pm1_save), -}/*-------------------------< PM0_SAVE >-------------------------*/,{ - SCR_STORE_REL (ia, 4), - offsetof(struct sym_ccb, phys.pm0.ret), - /* - * If WSR bit is set, either UA and RBC may - * have to be changed whether the device wants - * to ignore this residue or not. - */ - SCR_FROM_REG (scntl2), - 0, - SCR_CALL ^ IFTRUE (MASK (WSR, WSR)), - PADDR_B (pm_wsr_handle), - /* - * Save the remaining byte count, the updated - * address and the return address. - */ - SCR_STORE_REL (rbc, 4), - offsetof(struct sym_ccb, phys.pm0.sg.size), - SCR_STORE_REL (ua, 4), - offsetof(struct sym_ccb, phys.pm0.sg.addr), - /* - * Set the current pointer at the PM0 DATA mini-script. - */ - SCR_LOAD_ABS (ia, 4), - PADDR_B (pm0_data_addr), -}/*-------------------------< PM_SAVE_END >----------------------*/,{ - SCR_STORE_REL (ia, 4), - offsetof(struct sym_ccb, phys.head.lastp), - SCR_JUMP, - PADDR_A (dispatch), -}/*-------------------------< PM1_SAVE >-------------------------*/,{ - SCR_STORE_REL (ia, 4), - offsetof(struct sym_ccb, phys.pm1.ret), - /* - * If WSR bit is set, either UA and RBC may - * have to be changed whether the device wants - * to ignore this residue or not. - */ - SCR_FROM_REG (scntl2), - 0, - SCR_CALL ^ IFTRUE (MASK (WSR, WSR)), - PADDR_B (pm_wsr_handle), - /* - * Save the remaining byte count, the updated - * address and the return address. - */ - SCR_STORE_REL (rbc, 4), - offsetof(struct sym_ccb, phys.pm1.sg.size), - SCR_STORE_REL (ua, 4), - offsetof(struct sym_ccb, phys.pm1.sg.addr), - /* - * Set the current pointer at the PM1 DATA mini-script. - */ - SCR_LOAD_ABS (ia, 4), - PADDR_B (pm1_data_addr), - SCR_JUMP, - PADDR_B (pm_save_end), -}/*-------------------------< PM_WSR_HANDLE >--------------------*/,{ - /* - * Phase mismatch handling from SCRIPT with WSR set. - * Such a condition can occur if the chip wants to - * execute a CHMOV(size > 1) when the WSR bit is - * set and the target changes PHASE. - * - * We must move the residual byte to memory. - * - * UA contains bit 0..31 of the address to - * move the residual byte. - * Move it to the table indirect. - */ - SCR_STORE_REL (ua, 4), - offsetof (struct sym_ccb, phys.wresid.addr), - /* - * Increment UA (move address to next position). - */ - SCR_REG_REG (ua, SCR_ADD, 1), - 0, - SCR_REG_REG (ua1, SCR_ADDC, 0), - 0, - SCR_REG_REG (ua2, SCR_ADDC, 0), - 0, - SCR_REG_REG (ua3, SCR_ADDC, 0), - 0, - /* - * Compute SCRATCHA as: - * - size to transfer = 1 byte. - * - bit 24..31 = high address bit [32...39]. - */ - SCR_LOAD_ABS (scratcha, 4), - PADDR_B (zero), - SCR_REG_REG (scratcha, SCR_OR, 1), - 0, - SCR_FROM_REG (rbc3), - 0, - SCR_TO_REG (scratcha3), - 0, - /* - * Move this value to the table indirect. - */ - SCR_STORE_REL (scratcha, 4), - offsetof (struct sym_ccb, phys.wresid.size), - /* - * Wait for a valid phase. - * While testing with bogus QUANTUM drives, the C1010 - * sometimes raised a spurious phase mismatch with - * WSR and the CHMOV(1) triggered another PM. - * Waiting explicitly for the PHASE seemed to avoid - * the nested phase mismatch. Btw, this didn't happen - * using my IBM drives. - */ - SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)), - 0, - /* - * Perform the move of the residual byte. - */ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_ccb, phys.wresid), - /* - * We can now handle the phase mismatch with UA fixed. - * RBC[0..23]=0 is a special case that does not require - * a PM context. The C code also checks against this. - */ - SCR_FROM_REG (rbc), - 0, - SCR_RETURN ^ IFFALSE (DATA (0)), - 0, - SCR_FROM_REG (rbc1), - 0, - SCR_RETURN ^ IFFALSE (DATA (0)), - 0, - SCR_FROM_REG (rbc2), - 0, - SCR_RETURN ^ IFFALSE (DATA (0)), - 0, - /* - * RBC[0..23]=0. - * Not only we donnot need a PM context, but this would - * lead to a bogus CHMOV(0). This condition means that - * the residual was the last byte to move from this CHMOV. - * So, we just have to move the current data script pointer - * (i.e. TEMP) to the SCRIPTS address following the - * interrupted CHMOV and jump to dispatcher. - * IA contains the data pointer to save. - */ - SCR_JUMP, - PADDR_B (pm_save_end), -}/*-------------------------< WSR_MA_HELPER >--------------------*/,{ - /* - * Helper for the C code when WSR bit is set. - * Perform the move of the residual byte. - */ - SCR_CHMOV_TBL ^ SCR_DATA_IN, - offsetof (struct sym_ccb, phys.wresid), - SCR_JUMP, - PADDR_A (dispatch), - -}/*-------------------------< ZERO >-----------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< SCRATCH >--------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< PM0_DATA_ADDR >--------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< PM1_DATA_ADDR >--------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< DONE_POS >-------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< STARTPOS >-------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------< TARGTBL >--------------------------*/,{ - SCR_DATA_ZERO, -}/*-------------------------<>-----------------------------------*/ -}; - -static struct SYM_FWZ_SCR SYM_FWZ_SCR = { - /*-------------------------< SNOOPTEST >------------------------*/{ - /* - * Read the variable from memory. - */ - SCR_LOAD_REL (scratcha, 4), - offsetof(struct sym_hcb, scratch), - /* - * Write the variable to memory. - */ - SCR_STORE_REL (temp, 4), - offsetof(struct sym_hcb, scratch), - /* - * Read back the variable from memory. - */ - SCR_LOAD_REL (temp, 4), - offsetof(struct sym_hcb, scratch), -}/*-------------------------< SNOOPEND >-------------------------*/,{ - /* - * And stop. - */ - SCR_INT, - 99, -}/*-------------------------<>-----------------------------------*/ -}; diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.c b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.c deleted file mode 100644 index 36d1ed78..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.c +++ /dev/null @@ -1,2157 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * Copyright (c) 2003-2005 Matthew Wilcox - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sym_glue.h" -#include "sym_nvram.h" - -#define NAME53C "sym53c" -#define NAME53C8XX "sym53c8xx" - -struct sym_driver_setup sym_driver_setup = SYM_LINUX_DRIVER_SETUP; -unsigned int sym_debug_flags = 0; - -static char *excl_string; -static char *safe_string; -module_param_named(cmd_per_lun, sym_driver_setup.max_tag, ushort, 0); -module_param_named(burst, sym_driver_setup.burst_order, byte, 0); -module_param_named(led, sym_driver_setup.scsi_led, byte, 0); -module_param_named(diff, sym_driver_setup.scsi_diff, byte, 0); -module_param_named(irqm, sym_driver_setup.irq_mode, byte, 0); -module_param_named(buschk, sym_driver_setup.scsi_bus_check, byte, 0); -module_param_named(hostid, sym_driver_setup.host_id, byte, 0); -module_param_named(verb, sym_driver_setup.verbose, byte, 0); -module_param_named(debug, sym_debug_flags, uint, 0); -module_param_named(settle, sym_driver_setup.settle_delay, byte, 0); -module_param_named(nvram, sym_driver_setup.use_nvram, byte, 0); -module_param_named(excl, excl_string, charp, 0); -module_param_named(safe, safe_string, charp, 0); - -MODULE_PARM_DESC(cmd_per_lun, "The maximum number of tags to use by default"); -MODULE_PARM_DESC(burst, "Maximum burst. 0 to disable, 255 to read from registers"); -MODULE_PARM_DESC(led, "Set to 1 to enable LED support"); -MODULE_PARM_DESC(diff, "0 for no differential mode, 1 for BIOS, 2 for always, 3 for not GPIO3"); -MODULE_PARM_DESC(irqm, "0 for open drain, 1 to leave alone, 2 for totem pole"); -MODULE_PARM_DESC(buschk, "0 to not check, 1 for detach on error, 2 for warn on error"); -MODULE_PARM_DESC(hostid, "The SCSI ID to use for the host adapters"); -MODULE_PARM_DESC(verb, "0 for minimal verbosity, 1 for normal, 2 for excessive"); -MODULE_PARM_DESC(debug, "Set bits to enable debugging"); -MODULE_PARM_DESC(settle, "Settle delay in seconds. Default 3"); -MODULE_PARM_DESC(nvram, "Option currently not used"); -MODULE_PARM_DESC(excl, "List ioport addresses here to prevent controllers from being attached"); -MODULE_PARM_DESC(safe, "Set other settings to a \"safe mode\""); - -MODULE_LICENSE("GPL"); -MODULE_VERSION(SYM_VERSION); -MODULE_AUTHOR("Matthew Wilcox "); -MODULE_DESCRIPTION("NCR, Symbios and LSI 8xx and 1010 PCI SCSI adapters"); - -static void sym2_setup_params(void) -{ - char *p = excl_string; - int xi = 0; - - while (p && (xi < 8)) { - char *next_p; - int val = (int) simple_strtoul(p, &next_p, 0); - sym_driver_setup.excludes[xi++] = val; - p = next_p; - } - - if (safe_string) { - if (*safe_string == 'y') { - sym_driver_setup.max_tag = 0; - sym_driver_setup.burst_order = 0; - sym_driver_setup.scsi_led = 0; - sym_driver_setup.scsi_diff = 1; - sym_driver_setup.irq_mode = 0; - sym_driver_setup.scsi_bus_check = 2; - sym_driver_setup.host_id = 7; - sym_driver_setup.verbose = 2; - sym_driver_setup.settle_delay = 10; - sym_driver_setup.use_nvram = 1; - } else if (*safe_string != 'n') { - printk(KERN_WARNING NAME53C8XX "Ignoring parameter %s" - " passed to safe option", safe_string); - } - } -} - -static struct scsi_transport_template *sym2_transport_template = NULL; - -/* - * Driver private area in the SCSI command structure. - */ -struct sym_ucmd { /* Override the SCSI pointer structure */ - struct completion *eh_done; /* SCSI error handling */ -}; - -#define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp)) -#define SYM_SOFTC_PTR(cmd) sym_get_hcb(cmd->device->host) - -/* - * Complete a pending CAM CCB. - */ -void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *cmd) -{ - struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); - BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd)); - - if (ucmd->eh_done) - complete(ucmd->eh_done); - - scsi_dma_unmap(cmd); - cmd->scsi_done(cmd); -} - -/* - * Tell the SCSI layer about a BUS RESET. - */ -void sym_xpt_async_bus_reset(struct sym_hcb *np) -{ - printf_notice("%s: SCSI BUS has been reset.\n", sym_name(np)); - np->s.settle_time = jiffies + sym_driver_setup.settle_delay * HZ; - np->s.settle_time_valid = 1; - if (sym_verbose >= 2) - printf_info("%s: command processing suspended for %d seconds\n", - sym_name(np), sym_driver_setup.settle_delay); -} - -/* - * Choose the more appropriate CAM status if - * the IO encountered an extended error. - */ -static int sym_xerr_cam_status(int cam_status, int x_status) -{ - if (x_status) { - if (x_status & XE_PARITY_ERR) - cam_status = DID_PARITY; - else if (x_status &(XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) - cam_status = DID_ERROR; - else if (x_status & XE_BAD_PHASE) - cam_status = DID_ERROR; - else - cam_status = DID_ERROR; - } - return cam_status; -} - -/* - * Build CAM result for a failed or auto-sensed IO. - */ -void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid) -{ - struct scsi_cmnd *cmd = cp->cmd; - u_int cam_status, scsi_status, drv_status; - - drv_status = 0; - cam_status = DID_OK; - scsi_status = cp->ssss_status; - - if (cp->host_flags & HF_SENSE) { - scsi_status = cp->sv_scsi_status; - resid = cp->sv_resid; - if (sym_verbose && cp->sv_xerr_status) - sym_print_xerr(cmd, cp->sv_xerr_status); - if (cp->host_status == HS_COMPLETE && - cp->ssss_status == S_GOOD && - cp->xerr_status == 0) { - cam_status = sym_xerr_cam_status(DID_OK, - cp->sv_xerr_status); - drv_status = DRIVER_SENSE; - /* - * Bounce back the sense data to user. - */ - memset(cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - memcpy(cmd->sense_buffer, cp->sns_bbuf, - min(SCSI_SENSE_BUFFERSIZE, SYM_SNS_BBUF_LEN)); -#if 0 - /* - * If the device reports a UNIT ATTENTION condition - * due to a RESET condition, we should consider all - * disconnect CCBs for this unit as aborted. - */ - if (1) { - u_char *p; - p = (u_char *) cmd->sense_data; - if (p[0]==0x70 && p[2]==0x6 && p[12]==0x29) - sym_clear_tasks(np, DID_ABORT, - cp->target,cp->lun, -1); - } -#endif - } else { - /* - * Error return from our internal request sense. This - * is bad: we must clear the contingent allegiance - * condition otherwise the device will always return - * BUSY. Use a big stick. - */ - sym_reset_scsi_target(np, cmd->device->id); - cam_status = DID_ERROR; - } - } else if (cp->host_status == HS_COMPLETE) /* Bad SCSI status */ - cam_status = DID_OK; - else if (cp->host_status == HS_SEL_TIMEOUT) /* Selection timeout */ - cam_status = DID_NO_CONNECT; - else if (cp->host_status == HS_UNEXPECTED) /* Unexpected BUS FREE*/ - cam_status = DID_ERROR; - else { /* Extended error */ - if (sym_verbose) { - sym_print_addr(cmd, "COMMAND FAILED (%x %x %x).\n", - cp->host_status, cp->ssss_status, - cp->xerr_status); - } - /* - * Set the most appropriate value for CAM status. - */ - cam_status = sym_xerr_cam_status(DID_ERROR, cp->xerr_status); - } - scsi_set_resid(cmd, resid); - cmd->result = (drv_status << 24) + (cam_status << 16) + scsi_status; -} - -static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd) -{ - int segment; - int use_sg; - - cp->data_len = 0; - - use_sg = scsi_dma_map(cmd); - if (use_sg > 0) { - struct scatterlist *sg; - struct sym_tcb *tp = &np->target[cp->target]; - struct sym_tblmove *data; - - if (use_sg > SYM_CONF_MAX_SG) { - scsi_dma_unmap(cmd); - return -1; - } - - data = &cp->phys.data[SYM_CONF_MAX_SG - use_sg]; - - scsi_for_each_sg(cmd, sg, use_sg, segment) { - dma_addr_t baddr = sg_dma_address(sg); - unsigned int len = sg_dma_len(sg); - - if ((len & 1) && (tp->head.wval & EWS)) { - len++; - cp->odd_byte_adjustment++; - } - - sym_build_sge(np, &data[segment], baddr, len); - cp->data_len += len; - } - } else { - segment = -2; - } - - return segment; -} - -/* - * Queue a SCSI command. - */ -static int sym_queue_command(struct sym_hcb *np, struct scsi_cmnd *cmd) -{ - struct scsi_device *sdev = cmd->device; - struct sym_tcb *tp; - struct sym_lcb *lp; - struct sym_ccb *cp; - int order; - - /* - * Retrieve the target descriptor. - */ - tp = &np->target[sdev->id]; - - /* - * Select tagged/untagged. - */ - lp = sym_lp(tp, sdev->lun); - order = (lp && lp->s.reqtags) ? M_SIMPLE_TAG : 0; - - /* - * Queue the SCSI IO. - */ - cp = sym_get_ccb(np, cmd, order); - if (!cp) - return 1; /* Means resource shortage */ - sym_queue_scsiio(np, cmd, cp); - return 0; -} - -/* - * Setup buffers and pointers that address the CDB. - */ -static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) -{ - memcpy(cp->cdb_buf, cmd->cmnd, cmd->cmd_len); - - cp->phys.cmd.addr = CCB_BA(cp, cdb_buf[0]); - cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); - - return 0; -} - -/* - * Setup pointers that address the data and start the I/O. - */ -int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) -{ - u32 lastp, goalp; - int dir; - - /* - * Build the CDB. - */ - if (sym_setup_cdb(np, cmd, cp)) - goto out_abort; - - /* - * No direction means no data. - */ - dir = cmd->sc_data_direction; - if (dir != DMA_NONE) { - cp->segments = sym_scatter(np, cp, cmd); - if (cp->segments < 0) { - sym_set_cam_status(cmd, DID_ERROR); - goto out_abort; - } - - /* - * No segments means no data. - */ - if (!cp->segments) - dir = DMA_NONE; - } else { - cp->data_len = 0; - cp->segments = 0; - } - - /* - * Set the data pointer. - */ - switch (dir) { - case DMA_BIDIRECTIONAL: - scmd_printk(KERN_INFO, cmd, "got DMA_BIDIRECTIONAL command"); - sym_set_cam_status(cmd, DID_ERROR); - goto out_abort; - case DMA_TO_DEVICE: - goalp = SCRIPTA_BA(np, data_out2) + 8; - lastp = goalp - 8 - (cp->segments * (2*4)); - break; - case DMA_FROM_DEVICE: - cp->host_flags |= HF_DATA_IN; - goalp = SCRIPTA_BA(np, data_in2) + 8; - lastp = goalp - 8 - (cp->segments * (2*4)); - break; - case DMA_NONE: - default: - lastp = goalp = SCRIPTB_BA(np, no_data); - break; - } - - /* - * Set all pointers values needed by SCRIPTS. - */ - cp->phys.head.lastp = cpu_to_scr(lastp); - cp->phys.head.savep = cpu_to_scr(lastp); - cp->startp = cp->phys.head.savep; - cp->goalp = cpu_to_scr(goalp); - - /* - * When `#ifed 1', the code below makes the driver - * panic on the first attempt to write to a SCSI device. - * It is the first test we want to do after a driver - * change that does not seem obviously safe. :) - */ -#if 0 - switch (cp->cdb_buf[0]) { - case 0x0A: case 0x2A: case 0xAA: - panic("XXXXXXXXXXXXX WRITE NOT YET ALLOWED XXXXXXXXXXXXXX\n"); - break; - default: - break; - } -#endif - - /* - * activate this job. - */ - sym_put_start_queue(np, cp); - return 0; - -out_abort: - sym_free_ccb(np, cp); - sym_xpt_done(np, cmd); - return 0; -} - - -/* - * timer daemon. - * - * Misused to keep the driver running when - * interrupts are not configured correctly. - */ -static void sym_timer(struct sym_hcb *np) -{ - unsigned long thistime = jiffies; - - /* - * Restart the timer. - */ - np->s.timer.expires = thistime + SYM_CONF_TIMER_INTERVAL; - add_timer(&np->s.timer); - - /* - * If we are resetting the ncr, wait for settle_time before - * clearing it. Then command processing will be resumed. - */ - if (np->s.settle_time_valid) { - if (time_before_eq(np->s.settle_time, thistime)) { - if (sym_verbose >= 2 ) - printk("%s: command processing resumed\n", - sym_name(np)); - np->s.settle_time_valid = 0; - } - return; - } - - /* - * Nothing to do for now, but that may come. - */ - if (np->s.lasttime + 4*HZ < thistime) { - np->s.lasttime = thistime; - } - -#ifdef SYM_CONF_PCIQ_MAY_MISS_COMPLETIONS - /* - * Some way-broken PCI bridges may lead to - * completions being lost when the clearing - * of the INTFLY flag by the CPU occurs - * concurrently with the chip raising this flag. - * If this ever happen, lost completions will - * be reaped here. - */ - sym_wakeup_done(np); -#endif -} - - -/* - * PCI BUS error handler. - */ -void sym_log_bus_error(struct Scsi_Host *shost) -{ - struct sym_data *sym_data = shost_priv(shost); - struct pci_dev *pdev = sym_data->pdev; - unsigned short pci_sts; - pci_read_config_word(pdev, PCI_STATUS, &pci_sts); - if (pci_sts & 0xf900) { - pci_write_config_word(pdev, PCI_STATUS, pci_sts); - shost_printk(KERN_WARNING, shost, - "PCI bus error: status = 0x%04x\n", pci_sts & 0xf900); - } -} - -/* - * queuecommand method. Entered with the host adapter lock held and - * interrupts disabled. - */ -static int sym53c8xx_queue_command_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - struct sym_hcb *np = SYM_SOFTC_PTR(cmd); - struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd); - int sts = 0; - - cmd->scsi_done = done; - memset(ucp, 0, sizeof(*ucp)); - - /* - * Shorten our settle_time if needed for - * this command not to time out. - */ - if (np->s.settle_time_valid && cmd->request->timeout) { - unsigned long tlimit = jiffies + cmd->request->timeout; - tlimit -= SYM_CONF_TIMER_INTERVAL*2; - if (time_after(np->s.settle_time, tlimit)) { - np->s.settle_time = tlimit; - } - } - - if (np->s.settle_time_valid) - return SCSI_MLQUEUE_HOST_BUSY; - - sts = sym_queue_command(np, cmd); - if (sts) - return SCSI_MLQUEUE_HOST_BUSY; - return 0; -} - -static DEF_SCSI_QCMD(sym53c8xx_queue_command) - -/* - * Linux entry point of the interrupt handler. - */ -static irqreturn_t sym53c8xx_intr(int irq, void *dev_id) -{ - struct Scsi_Host *shost = dev_id; - struct sym_data *sym_data = shost_priv(shost); - irqreturn_t result; - - /* Avoid spinloop trying to handle interrupts on frozen device */ - if (pci_channel_offline(sym_data->pdev)) - return IRQ_NONE; - - if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("["); - - spin_lock(shost->host_lock); - result = sym_interrupt(shost); - spin_unlock(shost->host_lock); - - if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("]\n"); - - return result; -} - -/* - * Linux entry point of the timer handler - */ -static void sym53c8xx_timer(unsigned long npref) -{ - struct sym_hcb *np = (struct sym_hcb *)npref; - unsigned long flags; - - spin_lock_irqsave(np->s.host->host_lock, flags); - sym_timer(np); - spin_unlock_irqrestore(np->s.host->host_lock, flags); -} - - -/* - * What the eh thread wants us to perform. - */ -#define SYM_EH_ABORT 0 -#define SYM_EH_DEVICE_RESET 1 -#define SYM_EH_BUS_RESET 2 -#define SYM_EH_HOST_RESET 3 - -/* - * Generic method for our eh processing. - * The 'op' argument tells what we have to do. - */ -static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) -{ - struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); - struct Scsi_Host *shost = cmd->device->host; - struct sym_data *sym_data = shost_priv(shost); - struct pci_dev *pdev = sym_data->pdev; - struct sym_hcb *np = sym_data->ncb; - SYM_QUEHEAD *qp; - int cmd_queued = 0; - int sts = -1; - struct completion eh_done; - - scmd_printk(KERN_WARNING, cmd, "%s operation started\n", opname); - - /* We may be in an error condition because the PCI bus - * went down. In this case, we need to wait until the - * PCI bus is reset, the card is reset, and only then - * proceed with the scsi error recovery. There's no - * point in hurrying; take a leisurely wait. - */ -#define WAIT_FOR_PCI_RECOVERY 35 - if (pci_channel_offline(pdev)) { - int finished_reset = 0; - init_completion(&eh_done); - spin_lock_irq(shost->host_lock); - /* Make sure we didn't race */ - if (pci_channel_offline(pdev)) { - BUG_ON(sym_data->io_reset); - sym_data->io_reset = &eh_done; - } else { - finished_reset = 1; - } - spin_unlock_irq(shost->host_lock); - if (!finished_reset) - finished_reset = wait_for_completion_timeout - (sym_data->io_reset, - WAIT_FOR_PCI_RECOVERY*HZ); - spin_lock_irq(shost->host_lock); - sym_data->io_reset = NULL; - spin_unlock_irq(shost->host_lock); - if (!finished_reset) - return SCSI_FAILED; - } - - spin_lock_irq(shost->host_lock); - /* This one is queued in some place -> to wait for completion */ - FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { - struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); - if (cp->cmd == cmd) { - cmd_queued = 1; - break; - } - } - - /* Try to proceed the operation we have been asked for */ - sts = -1; - switch(op) { - case SYM_EH_ABORT: - sts = sym_abort_scsiio(np, cmd, 1); - break; - case SYM_EH_DEVICE_RESET: - sts = sym_reset_scsi_target(np, cmd->device->id); - break; - case SYM_EH_BUS_RESET: - sym_reset_scsi_bus(np, 1); - sts = 0; - break; - case SYM_EH_HOST_RESET: - sym_reset_scsi_bus(np, 0); - sym_start_up(shost, 1); - sts = 0; - break; - default: - break; - } - - /* On error, restore everything and cross fingers :) */ - if (sts) - cmd_queued = 0; - - if (cmd_queued) { - init_completion(&eh_done); - ucmd->eh_done = &eh_done; - spin_unlock_irq(shost->host_lock); - if (!wait_for_completion_timeout(&eh_done, 5*HZ)) { - ucmd->eh_done = NULL; - sts = -2; - } - } else { - spin_unlock_irq(shost->host_lock); - } - - dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, - sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); - return sts ? SCSI_FAILED : SCSI_SUCCESS; -} - - -/* - * Error handlers called from the eh thread (one thread per HBA). - */ -static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd) -{ - return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd); -} - -static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd) -{ - return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd); -} - -static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd) -{ - return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd); -} - -static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd) -{ - return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd); -} - -/* - * Tune device queuing depth, according to various limits. - */ -static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags) -{ - struct sym_lcb *lp = sym_lp(tp, lun); - u_short oldtags; - - if (!lp) - return; - - oldtags = lp->s.reqtags; - - if (reqtags > lp->s.scdev_depth) - reqtags = lp->s.scdev_depth; - - lp->s.reqtags = reqtags; - - if (reqtags != oldtags) { - dev_info(&tp->starget->dev, - "tagged command queuing %s, command queue depth %d.\n", - lp->s.reqtags ? "enabled" : "disabled", reqtags); - } -} - -static int sym53c8xx_slave_alloc(struct scsi_device *sdev) -{ - struct sym_hcb *np = sym_get_hcb(sdev->host); - struct sym_tcb *tp = &np->target[sdev->id]; - struct sym_lcb *lp; - unsigned long flags; - int error; - - if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN) - return -ENXIO; - - spin_lock_irqsave(np->s.host->host_lock, flags); - - /* - * Fail the device init if the device is flagged NOSCAN at BOOT in - * the NVRAM. This may speed up boot and maintain coherency with - * BIOS device numbering. Clearing the flag allows the user to - * rescan skipped devices later. We also return an error for - * devices not flagged for SCAN LUNS in the NVRAM since some single - * lun devices behave badly when asked for a non zero LUN. - */ - - if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) { - tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED; - starget_printk(KERN_INFO, sdev->sdev_target, - "Scan at boot disabled in NVRAM\n"); - error = -ENXIO; - goto out; - } - - if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) { - if (sdev->lun != 0) { - error = -ENXIO; - goto out; - } - starget_printk(KERN_INFO, sdev->sdev_target, - "Multiple LUNs disabled in NVRAM\n"); - } - - lp = sym_alloc_lcb(np, sdev->id, sdev->lun); - if (!lp) { - error = -ENOMEM; - goto out; - } - if (tp->nlcb == 1) - tp->starget = sdev->sdev_target; - - spi_min_period(tp->starget) = tp->usr_period; - spi_max_width(tp->starget) = tp->usr_width; - - error = 0; -out: - spin_unlock_irqrestore(np->s.host->host_lock, flags); - - return error; -} - -/* - * Linux entry point for device queue sizing. - */ -static int sym53c8xx_slave_configure(struct scsi_device *sdev) -{ - struct sym_hcb *np = sym_get_hcb(sdev->host); - struct sym_tcb *tp = &np->target[sdev->id]; - struct sym_lcb *lp = sym_lp(tp, sdev->lun); - int reqtags, depth_to_use; - - /* - * Get user flags. - */ - lp->curr_flags = lp->user_flags; - - /* - * Select queue depth from driver setup. - * Do not use more than configured by user. - * Use at least 1. - * Do not use more than our maximum. - */ - reqtags = sym_driver_setup.max_tag; - if (reqtags > tp->usrtags) - reqtags = tp->usrtags; - if (!sdev->tagged_supported) - reqtags = 0; - if (reqtags > SYM_CONF_MAX_TAG) - reqtags = SYM_CONF_MAX_TAG; - depth_to_use = reqtags ? reqtags : 1; - scsi_adjust_queue_depth(sdev, - sdev->tagged_supported ? MSG_SIMPLE_TAG : 0, - depth_to_use); - lp->s.scdev_depth = depth_to_use; - sym_tune_dev_queuing(tp, sdev->lun, reqtags); - - if (!spi_initial_dv(sdev->sdev_target)) - spi_dv_device(sdev); - - return 0; -} - -static void sym53c8xx_slave_destroy(struct scsi_device *sdev) -{ - struct sym_hcb *np = sym_get_hcb(sdev->host); - struct sym_tcb *tp = &np->target[sdev->id]; - struct sym_lcb *lp = sym_lp(tp, sdev->lun); - unsigned long flags; - - /* if slave_alloc returned before allocating a sym_lcb, return */ - if (!lp) - return; - - spin_lock_irqsave(np->s.host->host_lock, flags); - - if (lp->busy_itlq || lp->busy_itl) { - /* - * This really shouldn't happen, but we can't return an error - * so let's try to stop all on-going I/O. - */ - starget_printk(KERN_WARNING, tp->starget, - "Removing busy LCB (%d)\n", sdev->lun); - sym_reset_scsi_bus(np, 1); - } - - if (sym_free_lcb(np, sdev->id, sdev->lun) == 0) { - /* - * It was the last unit for this target. - */ - tp->head.sval = 0; - tp->head.wval = np->rv_scntl3; - tp->head.uval = 0; - tp->tgoal.check_nego = 1; - tp->starget = NULL; - } - - spin_unlock_irqrestore(np->s.host->host_lock, flags); -} - -/* - * Linux entry point for info() function - */ -static const char *sym53c8xx_info (struct Scsi_Host *host) -{ - return SYM_DRIVER_NAME; -} - - -#ifdef SYM_LINUX_PROC_INFO_SUPPORT -/* - * Proc file system stuff - * - * A read operation returns adapter information. - * A write operation is a control command. - * The string is parsed in the driver code and the command is passed - * to the sym_usercmd() function. - */ - -#ifdef SYM_LINUX_USER_COMMAND_SUPPORT - -struct sym_usrcmd { - u_long target; - u_long lun; - u_long data; - u_long cmd; -}; - -#define UC_SETSYNC 10 -#define UC_SETTAGS 11 -#define UC_SETDEBUG 12 -#define UC_SETWIDE 14 -#define UC_SETFLAG 15 -#define UC_SETVERBOSE 17 -#define UC_RESETDEV 18 -#define UC_CLEARDEV 19 - -static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc) -{ - struct sym_tcb *tp; - int t, l; - - switch (uc->cmd) { - case 0: return; - -#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT - case UC_SETDEBUG: - sym_debug_flags = uc->data; - break; -#endif - case UC_SETVERBOSE: - np->verbose = uc->data; - break; - default: - /* - * We assume that other commands apply to targets. - * This should always be the case and avoid the below - * 4 lines to be repeated 6 times. - */ - for (t = 0; t < SYM_CONF_MAX_TARGET; t++) { - if (!((uc->target >> t) & 1)) - continue; - tp = &np->target[t]; - if (!tp->nlcb) - continue; - - switch (uc->cmd) { - - case UC_SETSYNC: - if (!uc->data || uc->data >= 255) { - tp->tgoal.iu = tp->tgoal.dt = - tp->tgoal.qas = 0; - tp->tgoal.offset = 0; - } else if (uc->data <= 9 && np->minsync_dt) { - if (uc->data < np->minsync_dt) - uc->data = np->minsync_dt; - tp->tgoal.iu = tp->tgoal.dt = - tp->tgoal.qas = 1; - tp->tgoal.width = 1; - tp->tgoal.period = uc->data; - tp->tgoal.offset = np->maxoffs_dt; - } else { - if (uc->data < np->minsync) - uc->data = np->minsync; - tp->tgoal.iu = tp->tgoal.dt = - tp->tgoal.qas = 0; - tp->tgoal.period = uc->data; - tp->tgoal.offset = np->maxoffs; - } - tp->tgoal.check_nego = 1; - break; - case UC_SETWIDE: - tp->tgoal.width = uc->data ? 1 : 0; - tp->tgoal.check_nego = 1; - break; - case UC_SETTAGS: - for (l = 0; l < SYM_CONF_MAX_LUN; l++) - sym_tune_dev_queuing(tp, l, uc->data); - break; - case UC_RESETDEV: - tp->to_reset = 1; - np->istat_sem = SEM; - OUTB(np, nc_istat, SIGP|SEM); - break; - case UC_CLEARDEV: - for (l = 0; l < SYM_CONF_MAX_LUN; l++) { - struct sym_lcb *lp = sym_lp(tp, l); - if (lp) lp->to_clear = 1; - } - np->istat_sem = SEM; - OUTB(np, nc_istat, SIGP|SEM); - break; - case UC_SETFLAG: - tp->usrflags = uc->data; - break; - } - } - break; - } -} - -static int sym_skip_spaces(char *ptr, int len) -{ - int cnt, c; - - for (cnt = len; cnt > 0 && (c = *ptr++) && isspace(c); cnt--); - - return (len - cnt); -} - -static int get_int_arg(char *ptr, int len, u_long *pv) -{ - char *end; - - *pv = simple_strtoul(ptr, &end, 10); - return (end - ptr); -} - -static int is_keyword(char *ptr, int len, char *verb) -{ - int verb_len = strlen(verb); - - if (len >= verb_len && !memcmp(verb, ptr, verb_len)) - return verb_len; - else - return 0; -} - -#define SKIP_SPACES(ptr, len) \ - if ((arg_len = sym_skip_spaces(ptr, len)) < 1) \ - return -EINVAL; \ - ptr += arg_len; len -= arg_len; - -#define GET_INT_ARG(ptr, len, v) \ - if (!(arg_len = get_int_arg(ptr, len, &(v)))) \ - return -EINVAL; \ - ptr += arg_len; len -= arg_len; - - -/* - * Parse a control command - */ - -static int sym_user_command(struct Scsi_Host *shost, char *buffer, int length) -{ - struct sym_hcb *np = sym_get_hcb(shost); - char *ptr = buffer; - int len = length; - struct sym_usrcmd cmd, *uc = &cmd; - int arg_len; - u_long target; - - memset(uc, 0, sizeof(*uc)); - - if (len > 0 && ptr[len-1] == '\n') - --len; - - if ((arg_len = is_keyword(ptr, len, "setsync")) != 0) - uc->cmd = UC_SETSYNC; - else if ((arg_len = is_keyword(ptr, len, "settags")) != 0) - uc->cmd = UC_SETTAGS; - else if ((arg_len = is_keyword(ptr, len, "setverbose")) != 0) - uc->cmd = UC_SETVERBOSE; - else if ((arg_len = is_keyword(ptr, len, "setwide")) != 0) - uc->cmd = UC_SETWIDE; -#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT - else if ((arg_len = is_keyword(ptr, len, "setdebug")) != 0) - uc->cmd = UC_SETDEBUG; -#endif - else if ((arg_len = is_keyword(ptr, len, "setflag")) != 0) - uc->cmd = UC_SETFLAG; - else if ((arg_len = is_keyword(ptr, len, "resetdev")) != 0) - uc->cmd = UC_RESETDEV; - else if ((arg_len = is_keyword(ptr, len, "cleardev")) != 0) - uc->cmd = UC_CLEARDEV; - else - arg_len = 0; - -#ifdef DEBUG_PROC_INFO -printk("sym_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd); -#endif - - if (!arg_len) - return -EINVAL; - ptr += arg_len; len -= arg_len; - - switch(uc->cmd) { - case UC_SETSYNC: - case UC_SETTAGS: - case UC_SETWIDE: - case UC_SETFLAG: - case UC_RESETDEV: - case UC_CLEARDEV: - SKIP_SPACES(ptr, len); - if ((arg_len = is_keyword(ptr, len, "all")) != 0) { - ptr += arg_len; len -= arg_len; - uc->target = ~0; - } else { - GET_INT_ARG(ptr, len, target); - uc->target = (1<cmd) { - case UC_SETVERBOSE: - case UC_SETSYNC: - case UC_SETTAGS: - case UC_SETWIDE: - SKIP_SPACES(ptr, len); - GET_INT_ARG(ptr, len, uc->data); -#ifdef DEBUG_PROC_INFO -printk("sym_user_command: data=%ld\n", uc->data); -#endif - break; -#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT - case UC_SETDEBUG: - while (len > 0) { - SKIP_SPACES(ptr, len); - if ((arg_len = is_keyword(ptr, len, "alloc"))) - uc->data |= DEBUG_ALLOC; - else if ((arg_len = is_keyword(ptr, len, "phase"))) - uc->data |= DEBUG_PHASE; - else if ((arg_len = is_keyword(ptr, len, "queue"))) - uc->data |= DEBUG_QUEUE; - else if ((arg_len = is_keyword(ptr, len, "result"))) - uc->data |= DEBUG_RESULT; - else if ((arg_len = is_keyword(ptr, len, "scatter"))) - uc->data |= DEBUG_SCATTER; - else if ((arg_len = is_keyword(ptr, len, "script"))) - uc->data |= DEBUG_SCRIPT; - else if ((arg_len = is_keyword(ptr, len, "tiny"))) - uc->data |= DEBUG_TINY; - else if ((arg_len = is_keyword(ptr, len, "timing"))) - uc->data |= DEBUG_TIMING; - else if ((arg_len = is_keyword(ptr, len, "nego"))) - uc->data |= DEBUG_NEGO; - else if ((arg_len = is_keyword(ptr, len, "tags"))) - uc->data |= DEBUG_TAGS; - else if ((arg_len = is_keyword(ptr, len, "pointer"))) - uc->data |= DEBUG_POINTER; - else - return -EINVAL; - ptr += arg_len; len -= arg_len; - } -#ifdef DEBUG_PROC_INFO -printk("sym_user_command: data=%ld\n", uc->data); -#endif - break; -#endif /* SYM_LINUX_DEBUG_CONTROL_SUPPORT */ - case UC_SETFLAG: - while (len > 0) { - SKIP_SPACES(ptr, len); - if ((arg_len = is_keyword(ptr, len, "no_disc"))) - uc->data &= ~SYM_DISC_ENABLED; - else - return -EINVAL; - ptr += arg_len; len -= arg_len; - } - break; - default: - break; - } - - if (len) - return -EINVAL; - else { - unsigned long flags; - - spin_lock_irqsave(shost->host_lock, flags); - sym_exec_user_command(np, uc); - spin_unlock_irqrestore(shost->host_lock, flags); - } - return length; -} - -#endif /* SYM_LINUX_USER_COMMAND_SUPPORT */ - - -#ifdef SYM_LINUX_USER_INFO_SUPPORT -/* - * Informations through the proc file system. - */ -struct info_str { - char *buffer; - int length; - int offset; - int pos; -}; - -static void copy_mem_info(struct info_str *info, char *data, int len) -{ - if (info->pos + len > info->length) - len = info->length - info->pos; - - if (info->pos + len < info->offset) { - info->pos += len; - return; - } - if (info->pos < info->offset) { - data += (info->offset - info->pos); - len -= (info->offset - info->pos); - } - - if (len > 0) { - memcpy(info->buffer + info->pos, data, len); - info->pos += len; - } -} - -static int copy_info(struct info_str *info, char *fmt, ...) -{ - va_list args; - char buf[81]; - int len; - - va_start(args, fmt); - len = vsprintf(buf, fmt, args); - va_end(args); - - copy_mem_info(info, buf, len); - return len; -} - -/* - * Copy formatted information into the input buffer. - */ -static int sym_host_info(struct Scsi_Host *shost, char *ptr, off_t offset, int len) -{ - struct sym_data *sym_data = shost_priv(shost); - struct pci_dev *pdev = sym_data->pdev; - struct sym_hcb *np = sym_data->ncb; - struct info_str info; - - info.buffer = ptr; - info.length = len; - info.offset = offset; - info.pos = 0; - - copy_info(&info, "Chip " NAME53C "%s, device id 0x%x, " - "revision id 0x%x\n", np->s.chip_name, - pdev->device, pdev->revision); - copy_info(&info, "At PCI address %s, IRQ %u\n", - pci_name(pdev), pdev->irq); - copy_info(&info, "Min. period factor %d, %s SCSI BUS%s\n", - (int) (np->minsync_dt ? np->minsync_dt : np->minsync), - np->maxwide ? "Wide" : "Narrow", - np->minsync_dt ? ", DT capable" : ""); - - copy_info(&info, "Max. started commands %d, " - "max. commands per LUN %d\n", - SYM_CONF_MAX_START, SYM_CONF_MAX_TAG); - - return info.pos > info.offset? info.pos - info.offset : 0; -} -#endif /* SYM_LINUX_USER_INFO_SUPPORT */ - -/* - * Entry point of the scsi proc fs of the driver. - * - func = 0 means read (returns adapter infos) - * - func = 1 means write (not yet merget from sym53c8xx) - */ -static int sym53c8xx_proc_info(struct Scsi_Host *shost, char *buffer, - char **start, off_t offset, int length, int func) -{ - int retv; - - if (func) { -#ifdef SYM_LINUX_USER_COMMAND_SUPPORT - retv = sym_user_command(shost, buffer, length); -#else - retv = -EINVAL; -#endif - } else { - if (start) - *start = buffer; -#ifdef SYM_LINUX_USER_INFO_SUPPORT - retv = sym_host_info(shost, buffer, offset, length); -#else - retv = -EINVAL; -#endif - } - - return retv; -} -#endif /* SYM_LINUX_PROC_INFO_SUPPORT */ - -/* - * Free resources claimed by sym_iomap_device(). Note that - * sym_free_resources() should be used instead of this function after calling - * sym_attach(). - */ -static void __devinit -sym_iounmap_device(struct sym_device *device) -{ - if (device->s.ioaddr) - pci_iounmap(device->pdev, device->s.ioaddr); - if (device->s.ramaddr) - pci_iounmap(device->pdev, device->s.ramaddr); -} - -/* - * Free controller resources. - */ -static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev, - int do_free_irq) -{ - /* - * Free O/S specific resources. - */ - if (do_free_irq) - free_irq(pdev->irq, np->s.host); - if (np->s.ioaddr) - pci_iounmap(pdev, np->s.ioaddr); - if (np->s.ramaddr) - pci_iounmap(pdev, np->s.ramaddr); - /* - * Free O/S independent resources. - */ - sym_hcb_free(np); - - sym_mfree_dma(np, sizeof(*np), "HCB"); -} - -/* - * Host attach and initialisations. - * - * Allocate host data and ncb structure. - * Remap MMIO region. - * Do chip initialization. - * If all is OK, install interrupt handling and - * start the timer daemon. - */ -static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt, - int unit, struct sym_device *dev) -{ - struct sym_data *sym_data; - struct sym_hcb *np = NULL; - struct Scsi_Host *shost = NULL; - struct pci_dev *pdev = dev->pdev; - unsigned long flags; - struct sym_fw *fw; - int do_free_irq = 0; - - printk(KERN_INFO "sym%d: <%s> rev 0x%x at pci %s irq %u\n", - unit, dev->chip.name, pdev->revision, pci_name(pdev), - pdev->irq); - - /* - * Get the firmware for this chip. - */ - fw = sym_find_firmware(&dev->chip); - if (!fw) - goto attach_failed; - - shost = scsi_host_alloc(tpnt, sizeof(*sym_data)); - if (!shost) - goto attach_failed; - sym_data = shost_priv(shost); - - /* - * Allocate immediately the host control block, - * since we are only expecting to succeed. :) - * We keep track in the HCB of all the resources that - * are to be released on error. - */ - np = __sym_calloc_dma(&pdev->dev, sizeof(*np), "HCB"); - if (!np) - goto attach_failed; - np->bus_dmat = &pdev->dev; /* Result in 1 DMA pool per HBA */ - sym_data->ncb = np; - sym_data->pdev = pdev; - np->s.host = shost; - - pci_set_drvdata(pdev, shost); - - /* - * Copy some useful infos to the HCB. - */ - np->hcb_ba = vtobus(np); - np->verbose = sym_driver_setup.verbose; - np->s.unit = unit; - np->features = dev->chip.features; - np->clock_divn = dev->chip.nr_divisor; - np->maxoffs = dev->chip.offset_max; - np->maxburst = dev->chip.burst_max; - np->myaddr = dev->host_id; - np->mmio_ba = (u32)dev->mmio_base; - np->ram_ba = (u32)dev->ram_base; - np->s.ioaddr = dev->s.ioaddr; - np->s.ramaddr = dev->s.ramaddr; - - /* - * Edit its name. - */ - strlcpy(np->s.chip_name, dev->chip.name, sizeof(np->s.chip_name)); - sprintf(np->s.inst_name, "sym%d", np->s.unit); - - if ((SYM_CONF_DMA_ADDRESSING_MODE > 0) && (np->features & FE_DAC) && - !pci_set_dma_mask(pdev, DMA_DAC_MASK)) { - set_dac(np); - } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { - printf_warning("%s: No suitable DMA available\n", sym_name(np)); - goto attach_failed; - } - - if (sym_hcb_attach(shost, fw, dev->nvram)) - goto attach_failed; - - /* - * Install the interrupt handler. - * If we synchonize the C code with SCRIPTS on interrupt, - * we do not want to share the INTR line at all. - */ - if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX, - shost)) { - printf_err("%s: request irq %u failure\n", - sym_name(np), pdev->irq); - goto attach_failed; - } - do_free_irq = 1; - - /* - * After SCSI devices have been opened, we cannot - * reset the bus safely, so we do it here. - */ - spin_lock_irqsave(shost->host_lock, flags); - if (sym_reset_scsi_bus(np, 0)) - goto reset_failed; - - /* - * Start the SCRIPTS. - */ - sym_start_up(shost, 1); - - /* - * Start the timer daemon - */ - init_timer(&np->s.timer); - np->s.timer.data = (unsigned long) np; - np->s.timer.function = sym53c8xx_timer; - np->s.lasttime=0; - sym_timer (np); - - /* - * Fill Linux host instance structure - * and return success. - */ - shost->max_channel = 0; - shost->this_id = np->myaddr; - shost->max_id = np->maxwide ? 16 : 8; - shost->max_lun = SYM_CONF_MAX_LUN; - shost->unique_id = pci_resource_start(pdev, 0); - shost->cmd_per_lun = SYM_CONF_MAX_TAG; - shost->can_queue = (SYM_CONF_MAX_START-2); - shost->sg_tablesize = SYM_CONF_MAX_SG; - shost->max_cmd_len = 16; - BUG_ON(sym2_transport_template == NULL); - shost->transportt = sym2_transport_template; - - /* 53c896 rev 1 errata: DMA may not cross 16MB boundary */ - if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && pdev->revision < 2) - shost->dma_boundary = 0xFFFFFF; - - spin_unlock_irqrestore(shost->host_lock, flags); - - return shost; - - reset_failed: - printf_err("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, " - "TERMINATION, DEVICE POWER etc.!\n", sym_name(np)); - spin_unlock_irqrestore(shost->host_lock, flags); - attach_failed: - printf_info("sym%d: giving up ...\n", unit); - if (np) - sym_free_resources(np, pdev, do_free_irq); - else - sym_iounmap_device(dev); - if (shost) - scsi_host_put(shost); - - return NULL; - } - - -/* - * Detect and try to read SYMBIOS and TEKRAM NVRAM. - */ -#if SYM_CONF_NVRAM_SUPPORT -static void __devinit sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp) -{ - devp->nvram = nvp; - nvp->type = 0; - - sym_read_nvram(devp, nvp); -} -#else -static inline void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp) -{ -} -#endif /* SYM_CONF_NVRAM_SUPPORT */ - -static int __devinit sym_check_supported(struct sym_device *device) -{ - struct sym_chip *chip; - struct pci_dev *pdev = device->pdev; - unsigned long io_port = pci_resource_start(pdev, 0); - int i; - - /* - * If user excluded this chip, do not initialize it. - * I hate this code so much. Must kill it. - */ - if (io_port) { - for (i = 0 ; i < 8 ; i++) { - if (sym_driver_setup.excludes[i] == io_port) - return -ENODEV; - } - } - - /* - * Check if the chip is supported. Then copy the chip description - * to our device structure so we can make it match the actual device - * and options. - */ - chip = sym_lookup_chip_table(pdev->device, pdev->revision); - if (!chip) { - dev_info(&pdev->dev, "device not supported\n"); - return -ENODEV; - } - memcpy(&device->chip, chip, sizeof(device->chip)); - - return 0; -} - -/* - * Ignore Symbios chips controlled by various RAID controllers. - * These controllers set value 0x52414944 at RAM end - 16. - */ -static int __devinit sym_check_raid(struct sym_device *device) -{ - unsigned int ram_size, ram_val; - - if (!device->s.ramaddr) - return 0; - - if (device->chip.features & FE_RAM8K) - ram_size = 8192; - else - ram_size = 4096; - - ram_val = readl(device->s.ramaddr + ram_size - 16); - if (ram_val != 0x52414944) - return 0; - - dev_info(&device->pdev->dev, - "not initializing, driven by RAID controller.\n"); - return -ENODEV; -} - -static int __devinit sym_set_workarounds(struct sym_device *device) -{ - struct sym_chip *chip = &device->chip; - struct pci_dev *pdev = device->pdev; - u_short status_reg; - - /* - * (ITEM 12 of a DEL about the 896 I haven't yet). - * We must ensure the chip will use WRITE AND INVALIDATE. - * The revision number limit is for now arbitrary. - */ - if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && pdev->revision < 0x4) { - chip->features |= (FE_WRIE | FE_CLSE); - } - - /* If the chip can do Memory Write Invalidate, enable it */ - if (chip->features & FE_WRIE) { - if (pci_set_mwi(pdev)) - return -ENODEV; - } - - /* - * Work around for errant bit in 895A. The 66Mhz - * capable bit is set erroneously. Clear this bit. - * (Item 1 DEL 533) - * - * Make sure Config space and Features agree. - * - * Recall: writes are not normal to status register - - * write a 1 to clear and a 0 to leave unchanged. - * Can only reset bits. - */ - pci_read_config_word(pdev, PCI_STATUS, &status_reg); - if (chip->features & FE_66MHZ) { - if (!(status_reg & PCI_STATUS_66MHZ)) - chip->features &= ~FE_66MHZ; - } else { - if (status_reg & PCI_STATUS_66MHZ) { - status_reg = PCI_STATUS_66MHZ; - pci_write_config_word(pdev, PCI_STATUS, status_reg); - pci_read_config_word(pdev, PCI_STATUS, &status_reg); - } - } - - return 0; -} - -/* - * Map HBA registers and on-chip SRAM (if present). - */ -static int __devinit -sym_iomap_device(struct sym_device *device) -{ - struct pci_dev *pdev = device->pdev; - struct pci_bus_region bus_addr; - int i = 2; - - pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]); - device->mmio_base = bus_addr.start; - - if (device->chip.features & FE_RAM) { - /* - * If the BAR is 64-bit, resource 2 will be occupied by the - * upper 32 bits - */ - if (!pdev->resource[i].flags) - i++; - pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]); - device->ram_base = bus_addr.start; - } - -#ifdef CONFIG_SCSI_SYM53C8XX_MMIO - if (device->mmio_base) - device->s.ioaddr = pci_iomap(pdev, 1, - pci_resource_len(pdev, 1)); -#endif - if (!device->s.ioaddr) - device->s.ioaddr = pci_iomap(pdev, 0, - pci_resource_len(pdev, 0)); - if (!device->s.ioaddr) { - dev_err(&pdev->dev, "could not map registers; giving up.\n"); - return -EIO; - } - if (device->ram_base) { - device->s.ramaddr = pci_iomap(pdev, i, - pci_resource_len(pdev, i)); - if (!device->s.ramaddr) { - dev_warn(&pdev->dev, - "could not map SRAM; continuing anyway.\n"); - device->ram_base = 0; - } - } - - return 0; -} - -/* - * The NCR PQS and PDS cards are constructed as a DEC bridge - * behind which sits a proprietary NCR memory controller and - * either four or two 53c875s as separate devices. We can tell - * if an 875 is part of a PQS/PDS or not since if it is, it will - * be on the same bus as the memory controller. In its usual - * mode of operation, the 875s are slaved to the memory - * controller for all transfers. To operate with the Linux - * driver, the memory controller is disabled and the 875s - * freed to function independently. The only wrinkle is that - * the preset SCSI ID (which may be zero) must be read in from - * a special configuration space register of the 875. - */ -static void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev) -{ - int slot; - u8 tmp; - - for (slot = 0; slot < 256; slot++) { - struct pci_dev *memc = pci_get_slot(pdev->bus, slot); - - if (!memc || memc->vendor != 0x101a || memc->device == 0x0009) { - pci_dev_put(memc); - continue; - } - - /* bit 1: allow individual 875 configuration */ - pci_read_config_byte(memc, 0x44, &tmp); - if ((tmp & 0x2) == 0) { - tmp |= 0x2; - pci_write_config_byte(memc, 0x44, tmp); - } - - /* bit 2: drive individual 875 interrupts to the bus */ - pci_read_config_byte(memc, 0x45, &tmp); - if ((tmp & 0x4) == 0) { - tmp |= 0x4; - pci_write_config_byte(memc, 0x45, tmp); - } - - pci_dev_put(memc); - break; - } - - pci_read_config_byte(pdev, 0x84, &tmp); - sym_dev->host_id = tmp; -} - -/* - * Called before unloading the module. - * Detach the host. - * We have to free resources and halt the NCR chip. - */ -static int sym_detach(struct Scsi_Host *shost, struct pci_dev *pdev) -{ - struct sym_hcb *np = sym_get_hcb(shost); - printk("%s: detaching ...\n", sym_name(np)); - - del_timer_sync(&np->s.timer); - - /* - * Reset NCR chip. - * We should use sym_soft_reset(), but we don't want to do - * so, since we may not be safe if interrupts occur. - */ - printk("%s: resetting chip\n", sym_name(np)); - OUTB(np, nc_istat, SRST); - INB(np, nc_mbox1); - udelay(10); - OUTB(np, nc_istat, 0); - - sym_free_resources(np, pdev, 1); - scsi_host_put(shost); - - return 1; -} - -/* - * Driver host template. - */ -static struct scsi_host_template sym2_template = { - .module = THIS_MODULE, - .name = "sym53c8xx", - .info = sym53c8xx_info, - .queuecommand = sym53c8xx_queue_command, - .slave_alloc = sym53c8xx_slave_alloc, - .slave_configure = sym53c8xx_slave_configure, - .slave_destroy = sym53c8xx_slave_destroy, - .eh_abort_handler = sym53c8xx_eh_abort_handler, - .eh_device_reset_handler = sym53c8xx_eh_device_reset_handler, - .eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler, - .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, - .this_id = 7, - .use_clustering = ENABLE_CLUSTERING, - .max_sectors = 0xFFFF, -#ifdef SYM_LINUX_PROC_INFO_SUPPORT - .proc_info = sym53c8xx_proc_info, - .proc_name = NAME53C8XX, -#endif -}; - -static int attach_count; - -static int __devinit sym2_probe(struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - struct sym_device sym_dev; - struct sym_nvram nvram; - struct Scsi_Host *shost; - int do_iounmap = 0; - int do_disable_device = 1; - - memset(&sym_dev, 0, sizeof(sym_dev)); - memset(&nvram, 0, sizeof(nvram)); - sym_dev.pdev = pdev; - sym_dev.host_id = SYM_SETUP_HOST_ID; - - if (pci_enable_device(pdev)) - goto leave; - - pci_set_master(pdev); - - if (pci_request_regions(pdev, NAME53C8XX)) - goto disable; - - if (sym_check_supported(&sym_dev)) - goto free; - - if (sym_iomap_device(&sym_dev)) - goto free; - do_iounmap = 1; - - if (sym_check_raid(&sym_dev)) { - do_disable_device = 0; /* Don't disable the device */ - goto free; - } - - if (sym_set_workarounds(&sym_dev)) - goto free; - - sym_config_pqs(pdev, &sym_dev); - - sym_get_nvram(&sym_dev, &nvram); - - do_iounmap = 0; /* Don't sym_iounmap_device() after sym_attach(). */ - shost = sym_attach(&sym2_template, attach_count, &sym_dev); - if (!shost) - goto free; - - if (scsi_add_host(shost, &pdev->dev)) - goto detach; - scsi_scan_host(shost); - - attach_count++; - - return 0; - - detach: - sym_detach(pci_get_drvdata(pdev), pdev); - free: - if (do_iounmap) - sym_iounmap_device(&sym_dev); - pci_release_regions(pdev); - disable: - if (do_disable_device) - pci_disable_device(pdev); - leave: - return -ENODEV; -} - -static void sym2_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - - scsi_remove_host(shost); - sym_detach(shost, pdev); - pci_release_regions(pdev); - pci_disable_device(pdev); - - attach_count--; -} - -/** - * sym2_io_error_detected() - called when PCI error is detected - * @pdev: pointer to PCI device - * @state: current state of the PCI slot - */ -static pci_ers_result_t sym2_io_error_detected(struct pci_dev *pdev, - enum pci_channel_state state) -{ - /* If slot is permanently frozen, turn everything off */ - if (state == pci_channel_io_perm_failure) { - sym2_remove(pdev); - return PCI_ERS_RESULT_DISCONNECT; - } - - disable_irq(pdev->irq); - pci_disable_device(pdev); - - /* Request that MMIO be enabled, so register dump can be taken. */ - return PCI_ERS_RESULT_CAN_RECOVER; -} - -/** - * sym2_io_slot_dump - Enable MMIO and dump debug registers - * @pdev: pointer to PCI device - */ -static pci_ers_result_t sym2_io_slot_dump(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - - sym_dump_registers(shost); - - /* Request a slot reset. */ - return PCI_ERS_RESULT_NEED_RESET; -} - -/** - * sym2_reset_workarounds - hardware-specific work-arounds - * - * This routine is similar to sym_set_workarounds(), except - * that, at this point, we already know that the device was - * successfully initialized at least once before, and so most - * of the steps taken there are un-needed here. - */ -static void sym2_reset_workarounds(struct pci_dev *pdev) -{ - u_short status_reg; - struct sym_chip *chip; - - chip = sym_lookup_chip_table(pdev->device, pdev->revision); - - /* Work around for errant bit in 895A, in a fashion - * similar to what is done in sym_set_workarounds(). - */ - pci_read_config_word(pdev, PCI_STATUS, &status_reg); - if (!(chip->features & FE_66MHZ) && (status_reg & PCI_STATUS_66MHZ)) { - status_reg = PCI_STATUS_66MHZ; - pci_write_config_word(pdev, PCI_STATUS, status_reg); - pci_read_config_word(pdev, PCI_STATUS, &status_reg); - } -} - -/** - * sym2_io_slot_reset() - called when the pci bus has been reset. - * @pdev: pointer to PCI device - * - * Restart the card from scratch. - */ -static pci_ers_result_t sym2_io_slot_reset(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct sym_hcb *np = sym_get_hcb(shost); - - printk(KERN_INFO "%s: recovering from a PCI slot reset\n", - sym_name(np)); - - if (pci_enable_device(pdev)) { - printk(KERN_ERR "%s: Unable to enable after PCI reset\n", - sym_name(np)); - return PCI_ERS_RESULT_DISCONNECT; - } - - pci_set_master(pdev); - enable_irq(pdev->irq); - - /* If the chip can do Memory Write Invalidate, enable it */ - if (np->features & FE_WRIE) { - if (pci_set_mwi(pdev)) - return PCI_ERS_RESULT_DISCONNECT; - } - - /* Perform work-arounds, analogous to sym_set_workarounds() */ - sym2_reset_workarounds(pdev); - - /* Perform host reset only on one instance of the card */ - if (PCI_FUNC(pdev->devfn) == 0) { - if (sym_reset_scsi_bus(np, 0)) { - printk(KERN_ERR "%s: Unable to reset scsi host\n", - sym_name(np)); - return PCI_ERS_RESULT_DISCONNECT; - } - sym_start_up(shost, 1); - } - - return PCI_ERS_RESULT_RECOVERED; -} - -/** - * sym2_io_resume() - resume normal ops after PCI reset - * @pdev: pointer to PCI device - * - * Called when the error recovery driver tells us that its - * OK to resume normal operation. Use completion to allow - * halted scsi ops to resume. - */ -static void sym2_io_resume(struct pci_dev *pdev) -{ - struct Scsi_Host *shost = pci_get_drvdata(pdev); - struct sym_data *sym_data = shost_priv(shost); - - spin_lock_irq(shost->host_lock); - if (sym_data->io_reset) - complete_all(sym_data->io_reset); - spin_unlock_irq(shost->host_lock); -} - -static void sym2_get_signalling(struct Scsi_Host *shost) -{ - struct sym_hcb *np = sym_get_hcb(shost); - enum spi_signal_type type; - - switch (np->scsi_mode) { - case SMODE_SE: - type = SPI_SIGNAL_SE; - break; - case SMODE_LVD: - type = SPI_SIGNAL_LVD; - break; - case SMODE_HVD: - type = SPI_SIGNAL_HVD; - break; - default: - type = SPI_SIGNAL_UNKNOWN; - break; - } - spi_signalling(shost) = type; -} - -static void sym2_set_offset(struct scsi_target *starget, int offset) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct sym_hcb *np = sym_get_hcb(shost); - struct sym_tcb *tp = &np->target[starget->id]; - - tp->tgoal.offset = offset; - tp->tgoal.check_nego = 1; -} - -static void sym2_set_period(struct scsi_target *starget, int period) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct sym_hcb *np = sym_get_hcb(shost); - struct sym_tcb *tp = &np->target[starget->id]; - - /* have to have DT for these transfers, but DT will also - * set width, so check that this is allowed */ - if (period <= np->minsync && spi_width(starget)) - tp->tgoal.dt = 1; - - tp->tgoal.period = period; - tp->tgoal.check_nego = 1; -} - -static void sym2_set_width(struct scsi_target *starget, int width) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct sym_hcb *np = sym_get_hcb(shost); - struct sym_tcb *tp = &np->target[starget->id]; - - /* It is illegal to have DT set on narrow transfers. If DT is - * clear, we must also clear IU and QAS. */ - if (width == 0) - tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; - - tp->tgoal.width = width; - tp->tgoal.check_nego = 1; -} - -static void sym2_set_dt(struct scsi_target *starget, int dt) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct sym_hcb *np = sym_get_hcb(shost); - struct sym_tcb *tp = &np->target[starget->id]; - - /* We must clear QAS and IU if DT is clear */ - if (dt) - tp->tgoal.dt = 1; - else - tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; - tp->tgoal.check_nego = 1; -} - -#if 0 -static void sym2_set_iu(struct scsi_target *starget, int iu) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct sym_hcb *np = sym_get_hcb(shost); - struct sym_tcb *tp = &np->target[starget->id]; - - if (iu) - tp->tgoal.iu = tp->tgoal.dt = 1; - else - tp->tgoal.iu = 0; - tp->tgoal.check_nego = 1; -} - -static void sym2_set_qas(struct scsi_target *starget, int qas) -{ - struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); - struct sym_hcb *np = sym_get_hcb(shost); - struct sym_tcb *tp = &np->target[starget->id]; - - if (qas) - tp->tgoal.dt = tp->tgoal.qas = 1; - else - tp->tgoal.qas = 0; - tp->tgoal.check_nego = 1; -} -#endif - -static struct spi_function_template sym2_transport_functions = { - .set_offset = sym2_set_offset, - .show_offset = 1, - .set_period = sym2_set_period, - .show_period = 1, - .set_width = sym2_set_width, - .show_width = 1, - .set_dt = sym2_set_dt, - .show_dt = 1, -#if 0 - .set_iu = sym2_set_iu, - .show_iu = 1, - .set_qas = sym2_set_qas, - .show_qas = 1, -#endif - .get_signalling = sym2_get_signalling, -}; - -static struct pci_device_id sym2_id_table[] __devinitdata = { - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C810, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C820, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */ - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C825, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C815, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C810AP, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */ - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C860, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1510, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SCSI<<8, 0xffff00, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C896, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C895, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C885, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C1510, - PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SCSI<<8, 0xffff00, 0UL }, /* new */ - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C895A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C875A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1010_33, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1010_66, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875J, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, sym2_id_table); - -static struct pci_error_handlers sym2_err_handler = { - .error_detected = sym2_io_error_detected, - .mmio_enabled = sym2_io_slot_dump, - .slot_reset = sym2_io_slot_reset, - .resume = sym2_io_resume, -}; - -static struct pci_driver sym2_driver = { - .name = NAME53C8XX, - .id_table = sym2_id_table, - .probe = sym2_probe, - .remove = sym2_remove, - .err_handler = &sym2_err_handler, -}; - -static int __init sym2_init(void) -{ - int error; - - sym2_setup_params(); - sym2_transport_template = spi_attach_transport(&sym2_transport_functions); - if (!sym2_transport_template) - return -ENODEV; - - error = pci_register_driver(&sym2_driver); - if (error) - spi_release_transport(sym2_transport_template); - return error; -} - -static void __exit sym2_exit(void) -{ - pci_unregister_driver(&sym2_driver); - spi_release_transport(sym2_transport_template); -} - -module_init(sym2_init); -module_exit(sym2_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.h deleted file mode 100644 index b80bf709..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_glue.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SYM_GLUE_H -#define SYM_GLUE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#ifdef __sparc__ -# include -#endif - -#include -#include -#include -#include -#include - -#include "sym53c8xx.h" -#include "sym_defs.h" -#include "sym_misc.h" - -/* - * Configuration addendum for Linux. - */ -#define SYM_CONF_TIMER_INTERVAL ((HZ+1)/2) - -#undef SYM_OPT_HANDLE_DEVICE_QUEUEING -#define SYM_OPT_LIMIT_COMMAND_REORDERING - -/* - * Print a message with severity. - */ -#define printf_emerg(args...) printk(KERN_EMERG args) -#define printf_alert(args...) printk(KERN_ALERT args) -#define printf_crit(args...) printk(KERN_CRIT args) -#define printf_err(args...) printk(KERN_ERR args) -#define printf_warning(args...) printk(KERN_WARNING args) -#define printf_notice(args...) printk(KERN_NOTICE args) -#define printf_info(args...) printk(KERN_INFO args) -#define printf_debug(args...) printk(KERN_DEBUG args) -#define printf(args...) printk(args) - -/* - * A 'read barrier' flushes any data that have been prefetched - * by the processor due to out of order execution. Such a barrier - * must notably be inserted prior to looking at data that have - * been DMAed, assuming that program does memory READs in proper - * order and that the device ensured proper ordering of WRITEs. - * - * A 'write barrier' prevents any previous WRITEs to pass further - * WRITEs. Such barriers must be inserted each time another agent - * relies on ordering of WRITEs. - * - * Note that, due to posting of PCI memory writes, we also must - * insert dummy PCI read transactions when some ordering involving - * both directions over the PCI does matter. PCI transactions are - * fully ordered in each direction. - */ - -#define MEMORY_READ_BARRIER() rmb() -#define MEMORY_WRITE_BARRIER() wmb() - -/* - * IO functions definition for big/little endian CPU support. - * For now, PCI chips are only supported in little endian addressing mode, - */ - -#ifdef __BIG_ENDIAN - -#define readw_l2b readw -#define readl_l2b readl -#define writew_b2l writew -#define writel_b2l writel - -#else /* little endian */ - -#define readw_raw readw -#define readl_raw readl -#define writew_raw writew -#define writel_raw writel - -#endif /* endian */ - -#ifdef SYM_CONF_CHIP_BIG_ENDIAN -#error "Chips in BIG ENDIAN addressing mode are not (yet) supported" -#endif - -/* - * If the CPU and the chip use same endian-ness addressing, - * no byte reordering is needed for script patching. - * Macro cpu_to_scr() is to be used for script patching. - * Macro scr_to_cpu() is to be used for getting a DWORD - * from the script. - */ - -#define cpu_to_scr(dw) cpu_to_le32(dw) -#define scr_to_cpu(dw) le32_to_cpu(dw) - -/* - * These ones are used as return code from - * error recovery handlers under Linux. - */ -#define SCSI_SUCCESS SUCCESS -#define SCSI_FAILED FAILED - -/* - * System specific target data structure. - * None for now, under Linux. - */ -/* #define SYM_HAVE_STCB */ - -/* - * System specific lun data structure. - */ -#define SYM_HAVE_SLCB -struct sym_slcb { - u_short reqtags; /* Number of tags requested by user */ - u_short scdev_depth; /* Queue depth set in select_queue_depth() */ -}; - -/* - * System specific command data structure. - * Not needed under Linux. - */ -/* struct sym_sccb */ - -/* - * System specific host data structure. - */ -struct sym_shcb { - /* - * Chip and controller indentification. - */ - int unit; - char inst_name[16]; - char chip_name[8]; - - struct Scsi_Host *host; - - void __iomem * ioaddr; /* MMIO kernel io address */ - void __iomem * ramaddr; /* RAM kernel io address */ - - struct timer_list timer; /* Timer handler link header */ - u_long lasttime; - u_long settle_time; /* Resetting the SCSI BUS */ - u_char settle_time_valid; -}; - -/* - * Return the name of the controller. - */ -#define sym_name(np) (np)->s.inst_name - -struct sym_nvram; - -/* - * The IO macros require a struct called 's' and are abused in sym_nvram.c - */ -struct sym_device { - struct pci_dev *pdev; - unsigned long mmio_base; - unsigned long ram_base; - struct { - void __iomem *ioaddr; - void __iomem *ramaddr; - } s; - struct sym_chip chip; - struct sym_nvram *nvram; - u_char host_id; -}; - -/* - * Driver host data structure. - */ -struct sym_data { - struct sym_hcb *ncb; - struct completion *io_reset; /* PCI error handling */ - struct pci_dev *pdev; -}; - -static inline struct sym_hcb * sym_get_hcb(struct Scsi_Host *host) -{ - return ((struct sym_data *)host->hostdata)->ncb; -} - -#include "sym_fw.h" -#include "sym_hipd.h" - -/* - * Set the status field of a CAM CCB. - */ -static inline void -sym_set_cam_status(struct scsi_cmnd *cmd, int status) -{ - cmd->result &= ~(0xff << 16); - cmd->result |= (status << 16); -} - -/* - * Get the status field of a CAM CCB. - */ -static inline int -sym_get_cam_status(struct scsi_cmnd *cmd) -{ - return host_byte(cmd->result); -} - -/* - * Build CAM result for a successful IO and for a failed IO. - */ -static inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid) -{ - scsi_set_resid(cmd, resid); - cmd->result = (((DID_OK) << 16) + ((cp->ssss_status) & 0x7f)); -} -void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid); - -void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *ccb); -#define sym_print_addr(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg) -void sym_xpt_async_bus_reset(struct sym_hcb *np); -int sym_setup_data_and_start (struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp); -void sym_log_bus_error(struct Scsi_Host *); -void sym_dump_registers(struct Scsi_Host *); - -#endif /* SYM_GLUE_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.c b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.c deleted file mode 100644 index d92fe403..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ /dev/null @@ -1,5838 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * Copyright (c) 2003-2005 Matthew Wilcox - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include /* for timeouts in units of HZ */ - -#include "sym_glue.h" -#include "sym_nvram.h" - -#if 0 -#define SYM_DEBUG_GENERIC_SUPPORT -#endif - -/* - * Needed function prototypes. - */ -static void sym_int_ma (struct sym_hcb *np); -static void sym_int_sir(struct sym_hcb *); -static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np); -static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa); -static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln); -static void sym_complete_error (struct sym_hcb *np, struct sym_ccb *cp); -static void sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp); -static int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp); - -/* - * Print a buffer in hexadecimal format with a ".\n" at end. - */ -static void sym_printl_hex(u_char *p, int n) -{ - while (n-- > 0) - printf (" %x", *p++); - printf (".\n"); -} - -static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg) -{ - sym_print_addr(cp->cmd, "%s: ", label); - - spi_print_msg(msg); - printf("\n"); -} - -static void sym_print_nego_msg(struct sym_hcb *np, int target, char *label, u_char *msg) -{ - struct sym_tcb *tp = &np->target[target]; - dev_info(&tp->starget->dev, "%s: ", label); - - spi_print_msg(msg); - printf("\n"); -} - -/* - * Print something that tells about extended errors. - */ -void sym_print_xerr(struct scsi_cmnd *cmd, int x_status) -{ - if (x_status & XE_PARITY_ERR) { - sym_print_addr(cmd, "unrecovered SCSI parity error.\n"); - } - if (x_status & XE_EXTRA_DATA) { - sym_print_addr(cmd, "extraneous data discarded.\n"); - } - if (x_status & XE_BAD_PHASE) { - sym_print_addr(cmd, "illegal scsi phase (4/5).\n"); - } - if (x_status & XE_SODL_UNRUN) { - sym_print_addr(cmd, "ODD transfer in DATA OUT phase.\n"); - } - if (x_status & XE_SWIDE_OVRUN) { - sym_print_addr(cmd, "ODD transfer in DATA IN phase.\n"); - } -} - -/* - * Return a string for SCSI BUS mode. - */ -static char *sym_scsi_bus_mode(int mode) -{ - switch(mode) { - case SMODE_HVD: return "HVD"; - case SMODE_SE: return "SE"; - case SMODE_LVD: return "LVD"; - } - return "??"; -} - -/* - * Soft reset the chip. - * - * Raising SRST when the chip is running may cause - * problems on dual function chips (see below). - * On the other hand, LVD devices need some delay - * to settle and report actual BUS mode in STEST4. - */ -static void sym_chip_reset (struct sym_hcb *np) -{ - OUTB(np, nc_istat, SRST); - INB(np, nc_mbox1); - udelay(10); - OUTB(np, nc_istat, 0); - INB(np, nc_mbox1); - udelay(2000); /* For BUS MODE to settle */ -} - -/* - * Really soft reset the chip.:) - * - * Some 896 and 876 chip revisions may hang-up if we set - * the SRST (soft reset) bit at the wrong time when SCRIPTS - * are running. - * So, we need to abort the current operation prior to - * soft resetting the chip. - */ -static void sym_soft_reset (struct sym_hcb *np) -{ - u_char istat = 0; - int i; - - if (!(np->features & FE_ISTAT1) || !(INB(np, nc_istat1) & SCRUN)) - goto do_chip_reset; - - OUTB(np, nc_istat, CABRT); - for (i = 100000 ; i ; --i) { - istat = INB(np, nc_istat); - if (istat & SIP) { - INW(np, nc_sist); - } - else if (istat & DIP) { - if (INB(np, nc_dstat) & ABRT) - break; - } - udelay(5); - } - OUTB(np, nc_istat, 0); - if (!i) - printf("%s: unable to abort current chip operation, " - "ISTAT=0x%02x.\n", sym_name(np), istat); -do_chip_reset: - sym_chip_reset(np); -} - -/* - * Start reset process. - * - * The interrupt handler will reinitialize the chip. - */ -static void sym_start_reset(struct sym_hcb *np) -{ - sym_reset_scsi_bus(np, 1); -} - -int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int) -{ - u32 term; - int retv = 0; - - sym_soft_reset(np); /* Soft reset the chip */ - if (enab_int) - OUTW(np, nc_sien, RST); - /* - * Enable Tolerant, reset IRQD if present and - * properly set IRQ mode, prior to resetting the bus. - */ - OUTB(np, nc_stest3, TE); - OUTB(np, nc_dcntl, (np->rv_dcntl & IRQM)); - OUTB(np, nc_scntl1, CRST); - INB(np, nc_mbox1); - udelay(200); - - if (!SYM_SETUP_SCSI_BUS_CHECK) - goto out; - /* - * Check for no terminators or SCSI bus shorts to ground. - * Read SCSI data bus, data parity bits and control signals. - * We are expecting RESET to be TRUE and other signals to be - * FALSE. - */ - term = INB(np, nc_sstat0); - term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */ - term |= ((INB(np, nc_sstat2) & 0x01) << 26) | /* sdp1 */ - ((INW(np, nc_sbdl) & 0xff) << 9) | /* d7-0 */ - ((INW(np, nc_sbdl) & 0xff00) << 10) | /* d15-8 */ - INB(np, nc_sbcl); /* req ack bsy sel atn msg cd io */ - - if (!np->maxwide) - term &= 0x3ffff; - - if (term != (2<<7)) { - printf("%s: suspicious SCSI data while resetting the BUS.\n", - sym_name(np)); - printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " - "0x%lx, expecting 0x%lx\n", - sym_name(np), - (np->features & FE_WIDE) ? "dp1,d15-8," : "", - (u_long)term, (u_long)(2<<7)); - if (SYM_SETUP_SCSI_BUS_CHECK == 1) - retv = 1; - } -out: - OUTB(np, nc_scntl1, 0); - return retv; -} - -/* - * Select SCSI clock frequency - */ -static void sym_selectclock(struct sym_hcb *np, u_char scntl3) -{ - /* - * If multiplier not present or not selected, leave here. - */ - if (np->multiplier <= 1) { - OUTB(np, nc_scntl3, scntl3); - return; - } - - if (sym_verbose >= 2) - printf ("%s: enabling clock multiplier\n", sym_name(np)); - - OUTB(np, nc_stest1, DBLEN); /* Enable clock multiplier */ - /* - * Wait for the LCKFRQ bit to be set if supported by the chip. - * Otherwise wait 50 micro-seconds (at least). - */ - if (np->features & FE_LCKFRQ) { - int i = 20; - while (!(INB(np, nc_stest4) & LCKFRQ) && --i > 0) - udelay(20); - if (!i) - printf("%s: the chip cannot lock the frequency\n", - sym_name(np)); - } else { - INB(np, nc_mbox1); - udelay(50+10); - } - OUTB(np, nc_stest3, HSC); /* Halt the scsi clock */ - OUTB(np, nc_scntl3, scntl3); - OUTB(np, nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ - OUTB(np, nc_stest3, 0x00); /* Restart scsi clock */ -} - - -/* - * Determine the chip's clock frequency. - * - * This is essential for the negotiation of the synchronous - * transfer rate. - * - * Note: we have to return the correct value. - * THERE IS NO SAFE DEFAULT VALUE. - * - * Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. - * 53C860 and 53C875 rev. 1 support fast20 transfers but - * do not have a clock doubler and so are provided with a - * 80 MHz clock. All other fast20 boards incorporate a doubler - * and so should be delivered with a 40 MHz clock. - * The recent fast40 chips (895/896/895A/1010) use a 40 Mhz base - * clock and provide a clock quadrupler (160 Mhz). - */ - -/* - * calculate SCSI clock frequency (in KHz) - */ -static unsigned getfreq (struct sym_hcb *np, int gen) -{ - unsigned int ms = 0; - unsigned int f; - - /* - * Measure GEN timer delay in order - * to calculate SCSI clock frequency - * - * This code will never execute too - * many loop iterations (if DELAY is - * reasonably correct). It could get - * too low a delay (too high a freq.) - * if the CPU is slow executing the - * loop for some reason (an NMI, for - * example). For this reason we will - * if multiple measurements are to be - * performed trust the higher delay - * (lower frequency returned). - */ - OUTW(np, nc_sien, 0); /* mask all scsi interrupts */ - INW(np, nc_sist); /* clear pending scsi interrupt */ - OUTB(np, nc_dien, 0); /* mask all dma interrupts */ - INW(np, nc_sist); /* another one, just to be sure :) */ - /* - * The C1010-33 core does not report GEN in SIST, - * if this interrupt is masked in SIEN. - * I don't know yet if the C1010-66 behaves the same way. - */ - if (np->features & FE_C10) { - OUTW(np, nc_sien, GEN); - OUTB(np, nc_istat1, SIRQD); - } - OUTB(np, nc_scntl3, 4); /* set pre-scaler to divide by 3 */ - OUTB(np, nc_stime1, 0); /* disable general purpose timer */ - OUTB(np, nc_stime1, gen); /* set to nominal delay of 1<features & FE_C10) { - OUTW(np, nc_sien, 0); - OUTB(np, nc_istat1, 0); - } - /* - * set prescaler to divide by whatever 0 means - * 0 ought to choose divide by 2, but appears - * to set divide by 3.5 mode in my 53c810 ... - */ - OUTB(np, nc_scntl3, 0); - - /* - * adjust for prescaler, and convert into KHz - */ - f = ms ? ((1 << gen) * (4340*4)) / ms : 0; - - /* - * The C1010-33 result is biased by a factor - * of 2/3 compared to earlier chips. - */ - if (np->features & FE_C10) - f = (f * 2) / 3; - - if (sym_verbose >= 2) - printf ("%s: Delay (GEN=%d): %u msec, %u KHz\n", - sym_name(np), gen, ms/4, f); - - return f; -} - -static unsigned sym_getfreq (struct sym_hcb *np) -{ - u_int f1, f2; - int gen = 8; - - getfreq (np, gen); /* throw away first result */ - f1 = getfreq (np, gen); - f2 = getfreq (np, gen); - if (f1 > f2) f1 = f2; /* trust lower result */ - return f1; -} - -/* - * Get/probe chip SCSI clock frequency - */ -static void sym_getclock (struct sym_hcb *np, int mult) -{ - unsigned char scntl3 = np->sv_scntl3; - unsigned char stest1 = np->sv_stest1; - unsigned f1; - - np->multiplier = 1; - f1 = 40000; - /* - * True with 875/895/896/895A with clock multiplier selected - */ - if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { - if (sym_verbose >= 2) - printf ("%s: clock multiplier found\n", sym_name(np)); - np->multiplier = mult; - } - - /* - * If multiplier not found or scntl3 not 7,5,3, - * reset chip and get frequency from general purpose timer. - * Otherwise trust scntl3 BIOS setting. - */ - if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { - OUTB(np, nc_stest1, 0); /* make sure doubler is OFF */ - f1 = sym_getfreq (np); - - if (sym_verbose) - printf ("%s: chip clock is %uKHz\n", sym_name(np), f1); - - if (f1 < 45000) f1 = 40000; - else if (f1 < 55000) f1 = 50000; - else f1 = 80000; - - if (f1 < 80000 && mult > 1) { - if (sym_verbose >= 2) - printf ("%s: clock multiplier assumed\n", - sym_name(np)); - np->multiplier = mult; - } - } else { - if ((scntl3 & 7) == 3) f1 = 40000; - else if ((scntl3 & 7) == 5) f1 = 80000; - else f1 = 160000; - - f1 /= np->multiplier; - } - - /* - * Compute controller synchronous parameters. - */ - f1 *= np->multiplier; - np->clock_khz = f1; -} - -/* - * Get/probe PCI clock frequency - */ -static int sym_getpciclock (struct sym_hcb *np) -{ - int f = 0; - - /* - * For now, we only need to know about the actual - * PCI BUS clock frequency for C1010-66 chips. - */ -#if 1 - if (np->features & FE_66MHZ) { -#else - if (1) { -#endif - OUTB(np, nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */ - f = sym_getfreq(np); - OUTB(np, nc_stest1, 0); - } - np->pciclk_khz = f; - - return f; -} - -/* - * SYMBIOS chip clock divisor table. - * - * Divisors are multiplied by 10,000,000 in order to make - * calculations more simple. - */ -#define _5M 5000000 -static const u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; - -/* - * Get clock factor and sync divisor for a given - * synchronous factor period. - */ -static int -sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fakp) -{ - u32 clk = np->clock_khz; /* SCSI clock frequency in kHz */ - int div = np->clock_divn; /* Number of divisors supported */ - u32 fak; /* Sync factor in sxfer */ - u32 per; /* Period in tenths of ns */ - u32 kpc; /* (per * clk) */ - int ret; - - /* - * Compute the synchronous period in tenths of nano-seconds - */ - if (dt && sfac <= 9) per = 125; - else if (sfac <= 10) per = 250; - else if (sfac == 11) per = 303; - else if (sfac == 12) per = 500; - else per = 40 * sfac; - ret = per; - - kpc = per * clk; - if (dt) - kpc <<= 1; - - /* - * For earliest C10 revision 0, we cannot use extra - * clocks for the setting of the SCSI clocking. - * Note that this limits the lowest sync data transfer - * to 5 Mega-transfers per second and may result in - * using higher clock divisors. - */ -#if 1 - if ((np->features & (FE_C10|FE_U3EN)) == FE_C10) { - /* - * Look for the lowest clock divisor that allows an - * output speed not faster than the period. - */ - while (div > 0) { - --div; - if (kpc > (div_10M[div] << 2)) { - ++div; - break; - } - } - fak = 0; /* No extra clocks */ - if (div == np->clock_divn) { /* Are we too fast ? */ - ret = -1; - } - *divp = div; - *fakp = fak; - return ret; - } -#endif - - /* - * Look for the greatest clock divisor that allows an - * input speed faster than the period. - */ - while (div-- > 0) - if (kpc >= (div_10M[div] << 2)) break; - - /* - * Calculate the lowest clock factor that allows an output - * speed not faster than the period, and the max output speed. - * If fak >= 1 we will set both XCLKH_ST and XCLKH_DT. - * If fak >= 2 we will also set XCLKS_ST and XCLKS_DT. - */ - if (dt) { - fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2; - /* ret = ((2+fak)*div_10M[div])/np->clock_khz; */ - } else { - fak = (kpc - 1) / div_10M[div] + 1 - 4; - /* ret = ((4+fak)*div_10M[div])/np->clock_khz; */ - } - - /* - * Check against our hardware limits, or bugs :). - */ - if (fak > 2) { - fak = 2; - ret = -1; - } - - /* - * Compute and return sync parameters. - */ - *divp = div; - *fakp = fak; - - return ret; -} - -/* - * SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64, - * 128 transfers. All chips support at least 16 transfers - * bursts. The 825A, 875 and 895 chips support bursts of up - * to 128 transfers and the 895A and 896 support bursts of up - * to 64 transfers. All other chips support up to 16 - * transfers bursts. - * - * For PCI 32 bit data transfers each transfer is a DWORD. - * It is a QUADWORD (8 bytes) for PCI 64 bit data transfers. - * - * We use log base 2 (burst length) as internal code, with - * value 0 meaning "burst disabled". - */ - -/* - * Burst length from burst code. - */ -#define burst_length(bc) (!(bc))? 0 : 1 << (bc) - -/* - * Burst code from io register bits. - */ -#define burst_code(dmode, ctest4, ctest5) \ - (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 - -/* - * Set initial io register bits from burst code. - */ -static inline void sym_init_burst(struct sym_hcb *np, u_char bc) -{ - np->rv_ctest4 &= ~0x80; - np->rv_dmode &= ~(0x3 << 6); - np->rv_ctest5 &= ~0x4; - - if (!bc) { - np->rv_ctest4 |= 0x80; - } - else { - --bc; - np->rv_dmode |= ((bc & 0x3) << 6); - np->rv_ctest5 |= (bc & 0x4); - } -} - -/* - * Save initial settings of some IO registers. - * Assumed to have been set by BIOS. - * We cannot reset the chip prior to reading the - * IO registers, since informations will be lost. - * Since the SCRIPTS processor may be running, this - * is not safe on paper, but it seems to work quite - * well. :) - */ -static void sym_save_initial_setting (struct sym_hcb *np) -{ - np->sv_scntl0 = INB(np, nc_scntl0) & 0x0a; - np->sv_scntl3 = INB(np, nc_scntl3) & 0x07; - np->sv_dmode = INB(np, nc_dmode) & 0xce; - np->sv_dcntl = INB(np, nc_dcntl) & 0xa8; - np->sv_ctest3 = INB(np, nc_ctest3) & 0x01; - np->sv_ctest4 = INB(np, nc_ctest4) & 0x80; - np->sv_gpcntl = INB(np, nc_gpcntl); - np->sv_stest1 = INB(np, nc_stest1); - np->sv_stest2 = INB(np, nc_stest2) & 0x20; - np->sv_stest4 = INB(np, nc_stest4); - if (np->features & FE_C10) { /* Always large DMA fifo + ultra3 */ - np->sv_scntl4 = INB(np, nc_scntl4); - np->sv_ctest5 = INB(np, nc_ctest5) & 0x04; - } - else - np->sv_ctest5 = INB(np, nc_ctest5) & 0x24; -} - -/* - * Set SCSI BUS mode. - * - LVD capable chips (895/895A/896/1010) report the current BUS mode - * through the STEST4 IO register. - * - For previous generation chips (825/825A/875), the user has to tell us - * how to check against HVD, since a 100% safe algorithm is not possible. - */ -static void sym_set_bus_mode(struct sym_hcb *np, struct sym_nvram *nvram) -{ - if (np->scsi_mode) - return; - - np->scsi_mode = SMODE_SE; - if (np->features & (FE_ULTRA2|FE_ULTRA3)) - np->scsi_mode = (np->sv_stest4 & SMODE); - else if (np->features & FE_DIFF) { - if (SYM_SETUP_SCSI_DIFF == 1) { - if (np->sv_scntl3) { - if (np->sv_stest2 & 0x20) - np->scsi_mode = SMODE_HVD; - } else if (nvram->type == SYM_SYMBIOS_NVRAM) { - if (!(INB(np, nc_gpreg) & 0x08)) - np->scsi_mode = SMODE_HVD; - } - } else if (SYM_SETUP_SCSI_DIFF == 2) - np->scsi_mode = SMODE_HVD; - } - if (np->scsi_mode == SMODE_HVD) - np->rv_stest2 |= 0x20; -} - -/* - * Prepare io register values used by sym_start_up() - * according to selected and supported features. - */ -static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) -{ - struct sym_data *sym_data = shost_priv(shost); - struct pci_dev *pdev = sym_data->pdev; - u_char burst_max; - u32 period; - int i; - - np->maxwide = (np->features & FE_WIDE) ? 1 : 0; - - /* - * Guess the frequency of the chip's clock. - */ - if (np->features & (FE_ULTRA3 | FE_ULTRA2)) - np->clock_khz = 160000; - else if (np->features & FE_ULTRA) - np->clock_khz = 80000; - else - np->clock_khz = 40000; - - /* - * Get the clock multiplier factor. - */ - if (np->features & FE_QUAD) - np->multiplier = 4; - else if (np->features & FE_DBLR) - np->multiplier = 2; - else - np->multiplier = 1; - - /* - * Measure SCSI clock frequency for chips - * it may vary from assumed one. - */ - if (np->features & FE_VARCLK) - sym_getclock(np, np->multiplier); - - /* - * Divisor to be used for async (timer pre-scaler). - */ - i = np->clock_divn - 1; - while (--i >= 0) { - if (10ul * SYM_CONF_MIN_ASYNC * np->clock_khz > div_10M[i]) { - ++i; - break; - } - } - np->rv_scntl3 = i+1; - - /* - * The C1010 uses hardwired divisors for async. - * So, we just throw away, the async. divisor.:-) - */ - if (np->features & FE_C10) - np->rv_scntl3 = 0; - - /* - * Minimum synchronous period factor supported by the chip. - * Btw, 'period' is in tenths of nanoseconds. - */ - period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; - - if (period <= 250) np->minsync = 10; - else if (period <= 303) np->minsync = 11; - else if (period <= 500) np->minsync = 12; - else np->minsync = (period + 40 - 1) / 40; - - /* - * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). - */ - if (np->minsync < 25 && - !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3))) - np->minsync = 25; - else if (np->minsync < 12 && - !(np->features & (FE_ULTRA2|FE_ULTRA3))) - np->minsync = 12; - - /* - * Maximum synchronous period factor supported by the chip. - */ - period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz); - np->maxsync = period > 2540 ? 254 : period / 10; - - /* - * If chip is a C1010, guess the sync limits in DT mode. - */ - if ((np->features & (FE_C10|FE_ULTRA3)) == (FE_C10|FE_ULTRA3)) { - if (np->clock_khz == 160000) { - np->minsync_dt = 9; - np->maxsync_dt = 50; - np->maxoffs_dt = nvram->type ? 62 : 31; - } - } - - /* - * 64 bit addressing (895A/896/1010) ? - */ - if (np->features & FE_DAC) { - if (!use_dac(np)) - np->rv_ccntl1 |= (DDAC); - else if (SYM_CONF_DMA_ADDRESSING_MODE == 1) - np->rv_ccntl1 |= (XTIMOD | EXTIBMV); - else if (SYM_CONF_DMA_ADDRESSING_MODE == 2) - np->rv_ccntl1 |= (0 | EXTIBMV); - } - - /* - * Phase mismatch handled by SCRIPTS (895A/896/1010) ? - */ - if (np->features & FE_NOPM) - np->rv_ccntl0 |= (ENPMJ); - - /* - * C1010-33 Errata: Part Number:609-039638 (rev. 1) is fixed. - * In dual channel mode, contention occurs if internal cycles - * are used. Disable internal cycles. - */ - if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 && - pdev->revision < 0x1) - np->rv_ccntl0 |= DILS; - - /* - * Select burst length (dwords) - */ - burst_max = SYM_SETUP_BURST_ORDER; - if (burst_max == 255) - burst_max = burst_code(np->sv_dmode, np->sv_ctest4, - np->sv_ctest5); - if (burst_max > 7) - burst_max = 7; - if (burst_max > np->maxburst) - burst_max = np->maxburst; - - /* - * DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2. - * This chip and the 860 Rev 1 may wrongly use PCI cache line - * based transactions on LOAD/STORE instructions. So we have - * to prevent these chips from using such PCI transactions in - * this driver. The generic ncr driver that does not use - * LOAD/STORE instructions does not need this work-around. - */ - if ((pdev->device == PCI_DEVICE_ID_NCR_53C810 && - pdev->revision >= 0x10 && pdev->revision <= 0x11) || - (pdev->device == PCI_DEVICE_ID_NCR_53C860 && - pdev->revision <= 0x1)) - np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP); - - /* - * Select all supported special features. - * If we are using on-board RAM for scripts, prefetch (PFEN) - * does not help, but burst op fetch (BOF) does. - * Disabling PFEN makes sure BOF will be used. - */ - if (np->features & FE_ERL) - np->rv_dmode |= ERL; /* Enable Read Line */ - if (np->features & FE_BOF) - np->rv_dmode |= BOF; /* Burst Opcode Fetch */ - if (np->features & FE_ERMP) - np->rv_dmode |= ERMP; /* Enable Read Multiple */ -#if 1 - if ((np->features & FE_PFEN) && !np->ram_ba) -#else - if (np->features & FE_PFEN) -#endif - np->rv_dcntl |= PFEN; /* Prefetch Enable */ - if (np->features & FE_CLSE) - np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ - if (np->features & FE_WRIE) - np->rv_ctest3 |= WRIE; /* Write and Invalidate */ - if (np->features & FE_DFS) - np->rv_ctest5 |= DFS; /* Dma Fifo Size */ - - /* - * Select some other - */ - np->rv_ctest4 |= MPEE; /* Master parity checking */ - np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */ - - /* - * Get parity checking, host ID and verbose mode from NVRAM - */ - np->myaddr = 255; - np->scsi_mode = 0; - sym_nvram_setup_host(shost, np, nvram); - - /* - * Get SCSI addr of host adapter (set by bios?). - */ - if (np->myaddr == 255) { - np->myaddr = INB(np, nc_scid) & 0x07; - if (!np->myaddr) - np->myaddr = SYM_SETUP_HOST_ID; - } - - /* - * Prepare initial io register bits for burst length - */ - sym_init_burst(np, burst_max); - - sym_set_bus_mode(np, nvram); - - /* - * Set LED support from SCRIPTS. - * Ignore this feature for boards known to use a - * specific GPIO wiring and for the 895A, 896 - * and 1010 that drive the LED directly. - */ - if ((SYM_SETUP_SCSI_LED || - (nvram->type == SYM_SYMBIOS_NVRAM || - (nvram->type == SYM_TEKRAM_NVRAM && - pdev->device == PCI_DEVICE_ID_NCR_53C895))) && - !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01)) - np->features |= FE_LED0; - - /* - * Set irq mode. - */ - switch(SYM_SETUP_IRQ_MODE & 3) { - case 2: - np->rv_dcntl |= IRQM; - break; - case 1: - np->rv_dcntl |= (np->sv_dcntl & IRQM); - break; - default: - break; - } - - /* - * Configure targets according to driver setup. - * If NVRAM present get targets setup from NVRAM. - */ - for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { - struct sym_tcb *tp = &np->target[i]; - - tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); - tp->usrtags = SYM_SETUP_MAX_TAG; - tp->usr_width = np->maxwide; - tp->usr_period = 9; - - sym_nvram_setup_target(tp, i, nvram); - - if (!tp->usrtags) - tp->usrflags &= ~SYM_TAGS_ENABLED; - } - - /* - * Let user know about the settings. - */ - printf("%s: %s, ID %d, Fast-%d, %s, %s\n", sym_name(np), - sym_nvram_type(nvram), np->myaddr, - (np->features & FE_ULTRA3) ? 80 : - (np->features & FE_ULTRA2) ? 40 : - (np->features & FE_ULTRA) ? 20 : 10, - sym_scsi_bus_mode(np->scsi_mode), - (np->rv_scntl0 & 0xa) ? "parity checking" : "NO parity"); - /* - * Tell him more on demand. - */ - if (sym_verbose) { - printf("%s: %s IRQ line driver%s\n", - sym_name(np), - np->rv_dcntl & IRQM ? "totem pole" : "open drain", - np->ram_ba ? ", using on-chip SRAM" : ""); - printf("%s: using %s firmware.\n", sym_name(np), np->fw_name); - if (np->features & FE_NOPM) - printf("%s: handling phase mismatch from SCRIPTS.\n", - sym_name(np)); - } - /* - * And still more. - */ - if (sym_verbose >= 2) { - printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " - "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", - sym_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, - np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); - - printf ("%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " - "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", - sym_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, - np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); - } - - return 0; -} - -/* - * Test the pci bus snoop logic :-( - * - * Has to be called with interrupts disabled. - */ -#ifdef CONFIG_SCSI_SYM53C8XX_MMIO -static int sym_regtest(struct sym_hcb *np) -{ - register volatile u32 data; - /* - * chip registers may NOT be cached. - * write 0xffffffff to a read only register area, - * and try to read it back. - */ - data = 0xffffffff; - OUTL(np, nc_dstat, data); - data = INL(np, nc_dstat); -#if 1 - if (data == 0xffffffff) { -#else - if ((data & 0xe2f0fffd) != 0x02000080) { -#endif - printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", - (unsigned) data); - return 0x10; - } - return 0; -} -#else -static inline int sym_regtest(struct sym_hcb *np) -{ - return 0; -} -#endif - -static int sym_snooptest(struct sym_hcb *np) -{ - u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; - int i, err; - - err = sym_regtest(np); - if (err) - return err; -restart_test: - /* - * Enable Master Parity Checking as we intend - * to enable it for normal operations. - */ - OUTB(np, nc_ctest4, (np->rv_ctest4 & MPEE)); - /* - * init - */ - pc = SCRIPTZ_BA(np, snooptest); - host_wr = 1; - sym_wr = 2; - /* - * Set memory and register. - */ - np->scratch = cpu_to_scr(host_wr); - OUTL(np, nc_temp, sym_wr); - /* - * Start script (exchange values) - */ - OUTL(np, nc_dsa, np->hcb_ba); - OUTL_DSP(np, pc); - /* - * Wait 'til done (with timeout) - */ - for (i=0; i=SYM_SNOOP_TIMEOUT) { - printf ("CACHE TEST FAILED: timeout.\n"); - return (0x20); - } - /* - * Check for fatal DMA errors. - */ - dstat = INB(np, nc_dstat); -#if 1 /* Band aiding for broken hardwares that fail PCI parity */ - if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) { - printf ("%s: PCI DATA PARITY ERROR DETECTED - " - "DISABLING MASTER DATA PARITY CHECKING.\n", - sym_name(np)); - np->rv_ctest4 &= ~MPEE; - goto restart_test; - } -#endif - if (dstat & (MDPE|BF|IID)) { - printf ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat); - return (0x80); - } - /* - * Save termination position. - */ - pc = INL(np, nc_dsp); - /* - * Read memory and register. - */ - host_rd = scr_to_cpu(np->scratch); - sym_rd = INL(np, nc_scratcha); - sym_bk = INL(np, nc_temp); - /* - * Check termination position. - */ - if (pc != SCRIPTZ_BA(np, snoopend)+8) { - printf ("CACHE TEST FAILED: script execution failed.\n"); - printf ("start=%08lx, pc=%08lx, end=%08lx\n", - (u_long) SCRIPTZ_BA(np, snooptest), (u_long) pc, - (u_long) SCRIPTZ_BA(np, snoopend) +8); - return (0x40); - } - /* - * Show results. - */ - if (host_wr != sym_rd) { - printf ("CACHE TEST FAILED: host wrote %d, chip read %d.\n", - (int) host_wr, (int) sym_rd); - err |= 1; - } - if (host_rd != sym_wr) { - printf ("CACHE TEST FAILED: chip wrote %d, host read %d.\n", - (int) sym_wr, (int) host_rd); - err |= 2; - } - if (sym_bk != sym_wr) { - printf ("CACHE TEST FAILED: chip wrote %d, read back %d.\n", - (int) sym_wr, (int) sym_bk); - err |= 4; - } - - return err; -} - -/* - * log message for real hard errors - * - * sym0 targ 0?: ERROR (ds:si) (so-si-sd) (sx/s3/s4) @ name (dsp:dbc). - * reg: r0 r1 r2 r3 r4 r5 r6 ..... rf. - * - * exception register: - * ds: dstat - * si: sist - * - * SCSI bus lines: - * so: control lines as driven by chip. - * si: control lines as seen by chip. - * sd: scsi data lines as seen by chip. - * - * wide/fastmode: - * sx: sxfer (see the manual) - * s3: scntl3 (see the manual) - * s4: scntl4 (see the manual) - * - * current script command: - * dsp: script address (relative to start of script). - * dbc: first word of script command. - * - * First 24 register of the chip: - * r0..rf - */ -static void sym_log_hard_error(struct Scsi_Host *shost, u_short sist, u_char dstat) -{ - struct sym_hcb *np = sym_get_hcb(shost); - u32 dsp; - int script_ofs; - int script_size; - char *script_name; - u_char *script_base; - int i; - - dsp = INL(np, nc_dsp); - - if (dsp > np->scripta_ba && - dsp <= np->scripta_ba + np->scripta_sz) { - script_ofs = dsp - np->scripta_ba; - script_size = np->scripta_sz; - script_base = (u_char *) np->scripta0; - script_name = "scripta"; - } - else if (np->scriptb_ba < dsp && - dsp <= np->scriptb_ba + np->scriptb_sz) { - script_ofs = dsp - np->scriptb_ba; - script_size = np->scriptb_sz; - script_base = (u_char *) np->scriptb0; - script_name = "scriptb"; - } else { - script_ofs = dsp; - script_size = 0; - script_base = NULL; - script_name = "mem"; - } - - printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x/%x) @ (%s %x:%08x).\n", - sym_name(np), (unsigned)INB(np, nc_sdid)&0x0f, dstat, sist, - (unsigned)INB(np, nc_socl), (unsigned)INB(np, nc_sbcl), - (unsigned)INB(np, nc_sbdl), (unsigned)INB(np, nc_sxfer), - (unsigned)INB(np, nc_scntl3), - (np->features & FE_C10) ? (unsigned)INB(np, nc_scntl4) : 0, - script_name, script_ofs, (unsigned)INL(np, nc_dbc)); - - if (((script_ofs & 3) == 0) && - (unsigned)script_ofs < script_size) { - printf ("%s: script cmd = %08x\n", sym_name(np), - scr_to_cpu((int) *(u32 *)(script_base + script_ofs))); - } - - printf("%s: regdump:", sym_name(np)); - for (i = 0; i < 24; i++) - printf(" %02x", (unsigned)INB_OFF(np, i)); - printf(".\n"); - - /* - * PCI BUS error. - */ - if (dstat & (MDPE|BF)) - sym_log_bus_error(shost); -} - -void sym_dump_registers(struct Scsi_Host *shost) -{ - struct sym_hcb *np = sym_get_hcb(shost); - u_short sist; - u_char dstat; - - sist = INW(np, nc_sist); - dstat = INB(np, nc_dstat); - sym_log_hard_error(shost, sist, dstat); -} - -static struct sym_chip sym_dev_table[] = { - {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, 64, - FE_ERL} - , -#ifdef SYM_DEBUG_GENERIC_SUPPORT - {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4, 8, 4, 1, - FE_BOF} - , -#else - {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4, 8, 4, 1, - FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF} - , -#endif - {PCI_DEVICE_ID_NCR_53C815, 0xff, "815", 4, 8, 4, 64, - FE_BOF|FE_ERL} - , - {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 6, 8, 4, 64, - FE_WIDE|FE_BOF|FE_ERL|FE_DIFF} - , - {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6, 8, 4, 2, - FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF} - , - {PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, 1, - FE_ULTRA|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} - , - {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, 2, - FE_WIDE|FE_ULTRA|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_DIFF|FE_VARCLK} - , - {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 6, 16, 5, 2, - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_DIFF|FE_VARCLK} - , - {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J", 6, 16, 5, 2, - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_DIFF|FE_VARCLK} - , - {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 6, 16, 5, 2, - FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_DIFF|FE_VARCLK} - , -#ifdef SYM_DEBUG_GENERIC_SUPPORT - {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, 2, - FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS| - FE_RAM|FE_LCKFRQ} - , -#else - {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, 2, - FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_LCKFRQ} - , -#endif - {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 6, 31, 7, 4, - FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} - , - {PCI_DEVICE_ID_LSI_53C895A, 0xff, "895a", 6, 31, 7, 4, - FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_RAM8K|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} - , - {PCI_DEVICE_ID_LSI_53C875A, 0xff, "875a", 6, 31, 7, 4, - FE_WIDE|FE_ULTRA|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} - , - {PCI_DEVICE_ID_LSI_53C1010_33, 0x00, "1010-33", 6, 31, 7, 8, - FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| - FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC| - FE_C10} - , - {PCI_DEVICE_ID_LSI_53C1010_33, 0xff, "1010-33", 6, 31, 7, 8, - FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| - FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC| - FE_C10|FE_U3EN} - , - {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66", 6, 31, 7, 8, - FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| - FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_66MHZ|FE_CRC| - FE_C10|FE_U3EN} - , - {PCI_DEVICE_ID_LSI_53C1510, 0xff, "1510d", 6, 31, 7, 4, - FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| - FE_RAM|FE_IO256|FE_LEDC} -}; - -#define sym_num_devs (ARRAY_SIZE(sym_dev_table)) - -/* - * Look up the chip table. - * - * Return a pointer to the chip entry if found, - * zero otherwise. - */ -struct sym_chip * -sym_lookup_chip_table (u_short device_id, u_char revision) -{ - struct sym_chip *chip; - int i; - - for (i = 0; i < sym_num_devs; i++) { - chip = &sym_dev_table[i]; - if (device_id != chip->device_id) - continue; - if (revision > chip->revision_id) - continue; - return chip; - } - - return NULL; -} - -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 -/* - * Lookup the 64 bit DMA segments map. - * This is only used if the direct mapping - * has been unsuccessful. - */ -int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s) -{ - int i; - - if (!use_dac(np)) - goto weird; - - /* Look up existing mappings */ - for (i = SYM_DMAP_SIZE-1; i > 0; i--) { - if (h == np->dmap_bah[i]) - return i; - } - /* If direct mapping is free, get it */ - if (!np->dmap_bah[s]) - goto new; - /* Collision -> lookup free mappings */ - for (s = SYM_DMAP_SIZE-1; s > 0; s--) { - if (!np->dmap_bah[s]) - goto new; - } -weird: - panic("sym: ran out of 64 bit DMA segment registers"); - return -1; -new: - np->dmap_bah[s] = h; - np->dmap_dirty = 1; - return s; -} - -/* - * Update IO registers scratch C..R so they will be - * in sync. with queued CCB expectations. - */ -static void sym_update_dmap_regs(struct sym_hcb *np) -{ - int o, i; - - if (!np->dmap_dirty) - return; - o = offsetof(struct sym_reg, nc_scrx[0]); - for (i = 0; i < SYM_DMAP_SIZE; i++) { - OUTL_OFF(np, o, np->dmap_bah[i]); - o += 4; - } - np->dmap_dirty = 0; -} -#endif - -/* Enforce all the fiddly SPI rules and the chip limitations */ -static void sym_check_goals(struct sym_hcb *np, struct scsi_target *starget, - struct sym_trans *goal) -{ - if (!spi_support_wide(starget)) - goal->width = 0; - - if (!spi_support_sync(starget)) { - goal->iu = 0; - goal->dt = 0; - goal->qas = 0; - goal->offset = 0; - return; - } - - if (spi_support_dt(starget)) { - if (spi_support_dt_only(starget)) - goal->dt = 1; - - if (goal->offset == 0) - goal->dt = 0; - } else { - goal->dt = 0; - } - - /* Some targets fail to properly negotiate DT in SE mode */ - if ((np->scsi_mode != SMODE_LVD) || !(np->features & FE_U3EN)) - goal->dt = 0; - - if (goal->dt) { - /* all DT transfers must be wide */ - goal->width = 1; - if (goal->offset > np->maxoffs_dt) - goal->offset = np->maxoffs_dt; - if (goal->period < np->minsync_dt) - goal->period = np->minsync_dt; - if (goal->period > np->maxsync_dt) - goal->period = np->maxsync_dt; - } else { - goal->iu = goal->qas = 0; - if (goal->offset > np->maxoffs) - goal->offset = np->maxoffs; - if (goal->period < np->minsync) - goal->period = np->minsync; - if (goal->period > np->maxsync) - goal->period = np->maxsync; - } -} - -/* - * Prepare the next negotiation message if needed. - * - * Fill in the part of message buffer that contains the - * negotiation and the nego_status field of the CCB. - * Returns the size of the message in bytes. - */ -static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgptr) -{ - struct sym_tcb *tp = &np->target[cp->target]; - struct scsi_target *starget = tp->starget; - struct sym_trans *goal = &tp->tgoal; - int msglen = 0; - int nego; - - sym_check_goals(np, starget, goal); - - /* - * Many devices implement PPR in a buggy way, so only use it if we - * really want to. - */ - if (goal->renego == NS_PPR || (goal->offset && - (goal->iu || goal->dt || goal->qas || (goal->period < 0xa)))) { - nego = NS_PPR; - } else if (goal->renego == NS_WIDE || goal->width) { - nego = NS_WIDE; - } else if (goal->renego == NS_SYNC || goal->offset) { - nego = NS_SYNC; - } else { - goal->check_nego = 0; - nego = 0; - } - - switch (nego) { - case NS_SYNC: - msglen += spi_populate_sync_msg(msgptr + msglen, goal->period, - goal->offset); - break; - case NS_WIDE: - msglen += spi_populate_width_msg(msgptr + msglen, goal->width); - break; - case NS_PPR: - msglen += spi_populate_ppr_msg(msgptr + msglen, goal->period, - goal->offset, goal->width, - (goal->iu ? PPR_OPT_IU : 0) | - (goal->dt ? PPR_OPT_DT : 0) | - (goal->qas ? PPR_OPT_QAS : 0)); - break; - } - - cp->nego_status = nego; - - if (nego) { - tp->nego_cp = cp; /* Keep track a nego will be performed */ - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_nego_msg(np, cp->target, - nego == NS_SYNC ? "sync msgout" : - nego == NS_WIDE ? "wide msgout" : - "ppr msgout", msgptr); - } - } - - return msglen; -} - -/* - * Insert a job into the start queue. - */ -void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) -{ - u_short qidx; - -#ifdef SYM_CONF_IARB_SUPPORT - /* - * If the previously queued CCB is not yet done, - * set the IARB hint. The SCRIPTS will go with IARB - * for this job when starting the previous one. - * We leave devices a chance to win arbitration by - * not using more than 'iarb_max' consecutive - * immediate arbitrations. - */ - if (np->last_cp && np->iarb_count < np->iarb_max) { - np->last_cp->host_flags |= HF_HINT_IARB; - ++np->iarb_count; - } - else - np->iarb_count = 0; - np->last_cp = cp; -#endif - -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 - /* - * Make SCRIPTS aware of the 64 bit DMA - * segment registers not being up-to-date. - */ - if (np->dmap_dirty) - cp->host_xflags |= HX_DMAP_DIRTY; -#endif - - /* - * Insert first the idle task and then our job. - * The MBs should ensure proper ordering. - */ - qidx = np->squeueput + 2; - if (qidx >= MAX_QUEUE*2) qidx = 0; - - np->squeue [qidx] = cpu_to_scr(np->idletask_ba); - MEMORY_WRITE_BARRIER(); - np->squeue [np->squeueput] = cpu_to_scr(cp->ccb_ba); - - np->squeueput = qidx; - - if (DEBUG_FLAGS & DEBUG_QUEUE) - scmd_printk(KERN_DEBUG, cp->cmd, "queuepos=%d\n", - np->squeueput); - - /* - * Script processor may be waiting for reselect. - * Wake it up. - */ - MEMORY_WRITE_BARRIER(); - OUTB(np, nc_istat, SIGP|np->istat_sem); -} - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING -/* - * Start next ready-to-start CCBs. - */ -void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn) -{ - SYM_QUEHEAD *qp; - struct sym_ccb *cp; - - /* - * Paranoia, as usual. :-) - */ - assert(!lp->started_tags || !lp->started_no_tag); - - /* - * Try to start as many commands as asked by caller. - * Prevent from having both tagged and untagged - * commands queued to the device at the same time. - */ - while (maxn--) { - qp = sym_remque_head(&lp->waiting_ccbq); - if (!qp) - break; - cp = sym_que_entry(qp, struct sym_ccb, link2_ccbq); - if (cp->tag != NO_TAG) { - if (lp->started_no_tag || - lp->started_tags >= lp->started_max) { - sym_insque_head(qp, &lp->waiting_ccbq); - break; - } - lp->itlq_tbl[cp->tag] = cpu_to_scr(cp->ccb_ba); - lp->head.resel_sa = - cpu_to_scr(SCRIPTA_BA(np, resel_tag)); - ++lp->started_tags; - } else { - if (lp->started_no_tag || lp->started_tags) { - sym_insque_head(qp, &lp->waiting_ccbq); - break; - } - lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba); - lp->head.resel_sa = - cpu_to_scr(SCRIPTA_BA(np, resel_no_tag)); - ++lp->started_no_tag; - } - cp->started = 1; - sym_insque_tail(qp, &lp->started_ccbq); - sym_put_start_queue(np, cp); - } -} -#endif /* SYM_OPT_HANDLE_DEVICE_QUEUEING */ - -/* - * The chip may have completed jobs. Look at the DONE QUEUE. - * - * On paper, memory read barriers may be needed here to - * prevent out of order LOADs by the CPU from having - * prefetched stale data prior to DMA having occurred. - */ -static int sym_wakeup_done (struct sym_hcb *np) -{ - struct sym_ccb *cp; - int i, n; - u32 dsa; - - n = 0; - i = np->dqueueget; - - /* MEMORY_READ_BARRIER(); */ - while (1) { - dsa = scr_to_cpu(np->dqueue[i]); - if (!dsa) - break; - np->dqueue[i] = 0; - if ((i = i+2) >= MAX_QUEUE*2) - i = 0; - - cp = sym_ccb_from_dsa(np, dsa); - if (cp) { - MEMORY_READ_BARRIER(); - sym_complete_ok (np, cp); - ++n; - } - else - printf ("%s: bad DSA (%x) in done queue.\n", - sym_name(np), (u_int) dsa); - } - np->dqueueget = i; - - return n; -} - -/* - * Complete all CCBs queued to the COMP queue. - * - * These CCBs are assumed: - * - Not to be referenced either by devices or - * SCRIPTS-related queues and datas. - * - To have to be completed with an error condition - * or requeued. - * - * The device queue freeze count is incremented - * for each CCB that does not prevent this. - * This function is called when all CCBs involved - * in error handling/recovery have been reaped. - */ -static void sym_flush_comp_queue(struct sym_hcb *np, int cam_status) -{ - SYM_QUEHEAD *qp; - struct sym_ccb *cp; - - while ((qp = sym_remque_head(&np->comp_ccbq)) != NULL) { - struct scsi_cmnd *cmd; - cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); - sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); - /* Leave quiet CCBs waiting for resources */ - if (cp->host_status == HS_WAIT) - continue; - cmd = cp->cmd; - if (cam_status) - sym_set_cam_status(cmd, cam_status); -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - if (sym_get_cam_status(cmd) == DID_SOFT_ERROR) { - struct sym_tcb *tp = &np->target[cp->target]; - struct sym_lcb *lp = sym_lp(tp, cp->lun); - if (lp) { - sym_remque(&cp->link2_ccbq); - sym_insque_tail(&cp->link2_ccbq, - &lp->waiting_ccbq); - if (cp->started) { - if (cp->tag != NO_TAG) - --lp->started_tags; - else - --lp->started_no_tag; - } - } - cp->started = 0; - continue; - } -#endif - sym_free_ccb(np, cp); - sym_xpt_done(np, cmd); - } -} - -/* - * Complete all active CCBs with error. - * Used on CHIP/SCSI RESET. - */ -static void sym_flush_busy_queue (struct sym_hcb *np, int cam_status) -{ - /* - * Move all active CCBs to the COMP queue - * and flush this queue. - */ - sym_que_splice(&np->busy_ccbq, &np->comp_ccbq); - sym_que_init(&np->busy_ccbq); - sym_flush_comp_queue(np, cam_status); -} - -/* - * Start chip. - * - * 'reason' means: - * 0: initialisation. - * 1: SCSI BUS RESET delivered or received. - * 2: SCSI BUS MODE changed. - */ -void sym_start_up(struct Scsi_Host *shost, int reason) -{ - struct sym_data *sym_data = shost_priv(shost); - struct pci_dev *pdev = sym_data->pdev; - struct sym_hcb *np = sym_data->ncb; - int i; - u32 phys; - - /* - * Reset chip if asked, otherwise just clear fifos. - */ - if (reason == 1) - sym_soft_reset(np); - else { - OUTB(np, nc_stest3, TE|CSF); - OUTONB(np, nc_ctest3, CLF); - } - - /* - * Clear Start Queue - */ - phys = np->squeue_ba; - for (i = 0; i < MAX_QUEUE*2; i += 2) { - np->squeue[i] = cpu_to_scr(np->idletask_ba); - np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4); - } - np->squeue[MAX_QUEUE*2-1] = cpu_to_scr(phys); - - /* - * Start at first entry. - */ - np->squeueput = 0; - - /* - * Clear Done Queue - */ - phys = np->dqueue_ba; - for (i = 0; i < MAX_QUEUE*2; i += 2) { - np->dqueue[i] = 0; - np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4); - } - np->dqueue[MAX_QUEUE*2-1] = cpu_to_scr(phys); - - /* - * Start at first entry. - */ - np->dqueueget = 0; - - /* - * Install patches in scripts. - * This also let point to first position the start - * and done queue pointers used from SCRIPTS. - */ - np->fw_patch(shost); - - /* - * Wakeup all pending jobs. - */ - sym_flush_busy_queue(np, DID_RESET); - - /* - * Init chip. - */ - OUTB(np, nc_istat, 0x00); /* Remove Reset, abort */ - INB(np, nc_mbox1); - udelay(2000); /* The 895 needs time for the bus mode to settle */ - - OUTB(np, nc_scntl0, np->rv_scntl0 | 0xc0); - /* full arb., ena parity, par->ATN */ - OUTB(np, nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ - - sym_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ - - OUTB(np, nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ - OUTW(np, nc_respid, 1ul<myaddr); /* Id to respond to */ - OUTB(np, nc_istat , SIGP ); /* Signal Process */ - OUTB(np, nc_dmode , np->rv_dmode); /* Burst length, dma mode */ - OUTB(np, nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ - - OUTB(np, nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ - OUTB(np, nc_ctest3, np->rv_ctest3); /* Write and invalidate */ - OUTB(np, nc_ctest4, np->rv_ctest4); /* Master parity checking */ - - /* Extended Sreq/Sack filtering not supported on the C10 */ - if (np->features & FE_C10) - OUTB(np, nc_stest2, np->rv_stest2); - else - OUTB(np, nc_stest2, EXT|np->rv_stest2); - - OUTB(np, nc_stest3, TE); /* TolerANT enable */ - OUTB(np, nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */ - - /* - * For now, disable AIP generation on C1010-66. - */ - if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_66) - OUTB(np, nc_aipcntl1, DISAIP); - - /* - * C10101 rev. 0 errata. - * Errant SGE's when in narrow. Write bits 4 & 5 of - * STEST1 register to disable SGE. We probably should do - * that from SCRIPTS for each selection/reselection, but - * I just don't want. :) - */ - if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 && - pdev->revision < 1) - OUTB(np, nc_stest1, INB(np, nc_stest1) | 0x30); - - /* - * DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2. - * Disable overlapped arbitration for some dual function devices, - * regardless revision id (kind of post-chip-design feature. ;-)) - */ - if (pdev->device == PCI_DEVICE_ID_NCR_53C875) - OUTB(np, nc_ctest0, (1<<5)); - else if (pdev->device == PCI_DEVICE_ID_NCR_53C896) - np->rv_ccntl0 |= DPR; - - /* - * Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing - * and/or hardware phase mismatch, since only such chips - * seem to support those IO registers. - */ - if (np->features & (FE_DAC|FE_NOPM)) { - OUTB(np, nc_ccntl0, np->rv_ccntl0); - OUTB(np, nc_ccntl1, np->rv_ccntl1); - } - -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 - /* - * Set up scratch C and DRS IO registers to map the 32 bit - * DMA address range our data structures are located in. - */ - if (use_dac(np)) { - np->dmap_bah[0] = 0; /* ??? */ - OUTL(np, nc_scrx[0], np->dmap_bah[0]); - OUTL(np, nc_drs, np->dmap_bah[0]); - } -#endif - - /* - * If phase mismatch handled by scripts (895A/896/1010), - * set PM jump addresses. - */ - if (np->features & FE_NOPM) { - OUTL(np, nc_pmjad1, SCRIPTB_BA(np, pm_handle)); - OUTL(np, nc_pmjad2, SCRIPTB_BA(np, pm_handle)); - } - - /* - * Enable GPIO0 pin for writing if LED support from SCRIPTS. - * Also set GPIO5 and clear GPIO6 if hardware LED control. - */ - if (np->features & FE_LED0) - OUTB(np, nc_gpcntl, INB(np, nc_gpcntl) & ~0x01); - else if (np->features & FE_LEDC) - OUTB(np, nc_gpcntl, (INB(np, nc_gpcntl) & ~0x41) | 0x20); - - /* - * enable ints - */ - OUTW(np, nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); - OUTB(np, nc_dien , MDPE|BF|SSI|SIR|IID); - - /* - * For 895/6 enable SBMC interrupt and save current SCSI bus mode. - * Try to eat the spurious SBMC interrupt that may occur when - * we reset the chip but not the SCSI BUS (at initialization). - */ - if (np->features & (FE_ULTRA2|FE_ULTRA3)) { - OUTONW(np, nc_sien, SBMC); - if (reason == 0) { - INB(np, nc_mbox1); - mdelay(100); - INW(np, nc_sist); - } - np->scsi_mode = INB(np, nc_stest4) & SMODE; - } - - /* - * Fill in target structure. - * Reinitialize usrsync. - * Reinitialize usrwide. - * Prepare sync negotiation according to actual SCSI bus mode. - */ - for (i=0;itarget[i]; - - tp->to_reset = 0; - tp->head.sval = 0; - tp->head.wval = np->rv_scntl3; - tp->head.uval = 0; - if (tp->lun0p) - tp->lun0p->to_clear = 0; - if (tp->lunmp) { - int ln; - - for (ln = 1; ln < SYM_CONF_MAX_LUN; ln++) - if (tp->lunmp[ln]) - tp->lunmp[ln]->to_clear = 0; - } - } - - /* - * Download SCSI SCRIPTS to on-chip RAM if present, - * and start script processor. - * We do the download preferently from the CPU. - * For platforms that may not support PCI memory mapping, - * we use simple SCRIPTS that performs MEMORY MOVEs. - */ - phys = SCRIPTA_BA(np, init); - if (np->ram_ba) { - if (sym_verbose >= 2) - printf("%s: Downloading SCSI SCRIPTS.\n", sym_name(np)); - memcpy_toio(np->s.ramaddr, np->scripta0, np->scripta_sz); - if (np->features & FE_RAM8K) { - memcpy_toio(np->s.ramaddr + 4096, np->scriptb0, np->scriptb_sz); - phys = scr_to_cpu(np->scr_ram_seg); - OUTL(np, nc_mmws, phys); - OUTL(np, nc_mmrs, phys); - OUTL(np, nc_sfs, phys); - phys = SCRIPTB_BA(np, start64); - } - } - - np->istat_sem = 0; - - OUTL(np, nc_dsa, np->hcb_ba); - OUTL_DSP(np, phys); - - /* - * Notify the XPT about the RESET condition. - */ - if (reason != 0) - sym_xpt_async_bus_reset(np); -} - -/* - * Switch trans mode for current job and its target. - */ -static void sym_settrans(struct sym_hcb *np, int target, u_char opts, u_char ofs, - u_char per, u_char wide, u_char div, u_char fak) -{ - SYM_QUEHEAD *qp; - u_char sval, wval, uval; - struct sym_tcb *tp = &np->target[target]; - - assert(target == (INB(np, nc_sdid) & 0x0f)); - - sval = tp->head.sval; - wval = tp->head.wval; - uval = tp->head.uval; - -#if 0 - printf("XXXX sval=%x wval=%x uval=%x (%x)\n", - sval, wval, uval, np->rv_scntl3); -#endif - /* - * Set the offset. - */ - if (!(np->features & FE_C10)) - sval = (sval & ~0x1f) | ofs; - else - sval = (sval & ~0x3f) | ofs; - - /* - * Set the sync divisor and extra clock factor. - */ - if (ofs != 0) { - wval = (wval & ~0x70) | ((div+1) << 4); - if (!(np->features & FE_C10)) - sval = (sval & ~0xe0) | (fak << 5); - else { - uval = uval & ~(XCLKH_ST|XCLKH_DT|XCLKS_ST|XCLKS_DT); - if (fak >= 1) uval |= (XCLKH_ST|XCLKH_DT); - if (fak >= 2) uval |= (XCLKS_ST|XCLKS_DT); - } - } - - /* - * Set the bus width. - */ - wval = wval & ~EWS; - if (wide != 0) - wval |= EWS; - - /* - * Set misc. ultra enable bits. - */ - if (np->features & FE_C10) { - uval = uval & ~(U3EN|AIPCKEN); - if (opts) { - assert(np->features & FE_U3EN); - uval |= U3EN; - } - } else { - wval = wval & ~ULTRA; - if (per <= 12) wval |= ULTRA; - } - - /* - * Stop there if sync parameters are unchanged. - */ - if (tp->head.sval == sval && - tp->head.wval == wval && - tp->head.uval == uval) - return; - tp->head.sval = sval; - tp->head.wval = wval; - tp->head.uval = uval; - - /* - * Disable extended Sreq/Sack filtering if per < 50. - * Not supported on the C1010. - */ - if (per < 50 && !(np->features & FE_C10)) - OUTOFFB(np, nc_stest2, EXT); - - /* - * set actual value and sync_status - */ - OUTB(np, nc_sxfer, tp->head.sval); - OUTB(np, nc_scntl3, tp->head.wval); - - if (np->features & FE_C10) { - OUTB(np, nc_scntl4, tp->head.uval); - } - - /* - * patch ALL busy ccbs of this target. - */ - FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { - struct sym_ccb *cp; - cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); - if (cp->target != target) - continue; - cp->phys.select.sel_scntl3 = tp->head.wval; - cp->phys.select.sel_sxfer = tp->head.sval; - if (np->features & FE_C10) { - cp->phys.select.sel_scntl4 = tp->head.uval; - } - } -} - -static void sym_announce_transfer_rate(struct sym_tcb *tp) -{ - struct scsi_target *starget = tp->starget; - - if (tp->tprint.period != spi_period(starget) || - tp->tprint.offset != spi_offset(starget) || - tp->tprint.width != spi_width(starget) || - tp->tprint.iu != spi_iu(starget) || - tp->tprint.dt != spi_dt(starget) || - tp->tprint.qas != spi_qas(starget) || - !tp->tprint.check_nego) { - tp->tprint.period = spi_period(starget); - tp->tprint.offset = spi_offset(starget); - tp->tprint.width = spi_width(starget); - tp->tprint.iu = spi_iu(starget); - tp->tprint.dt = spi_dt(starget); - tp->tprint.qas = spi_qas(starget); - tp->tprint.check_nego = 1; - - spi_display_xfer_agreement(starget); - } -} - -/* - * We received a WDTR. - * Let everything be aware of the changes. - */ -static void sym_setwide(struct sym_hcb *np, int target, u_char wide) -{ - struct sym_tcb *tp = &np->target[target]; - struct scsi_target *starget = tp->starget; - - sym_settrans(np, target, 0, 0, 0, wide, 0, 0); - - if (wide) - tp->tgoal.renego = NS_WIDE; - else - tp->tgoal.renego = 0; - tp->tgoal.check_nego = 0; - tp->tgoal.width = wide; - spi_offset(starget) = 0; - spi_period(starget) = 0; - spi_width(starget) = wide; - spi_iu(starget) = 0; - spi_dt(starget) = 0; - spi_qas(starget) = 0; - - if (sym_verbose >= 3) - sym_announce_transfer_rate(tp); -} - -/* - * We received a SDTR. - * Let everything be aware of the changes. - */ -static void -sym_setsync(struct sym_hcb *np, int target, - u_char ofs, u_char per, u_char div, u_char fak) -{ - struct sym_tcb *tp = &np->target[target]; - struct scsi_target *starget = tp->starget; - u_char wide = (tp->head.wval & EWS) ? BUS_16_BIT : BUS_8_BIT; - - sym_settrans(np, target, 0, ofs, per, wide, div, fak); - - if (wide) - tp->tgoal.renego = NS_WIDE; - else if (ofs) - tp->tgoal.renego = NS_SYNC; - else - tp->tgoal.renego = 0; - spi_period(starget) = per; - spi_offset(starget) = ofs; - spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0; - - if (!tp->tgoal.dt && !tp->tgoal.iu && !tp->tgoal.qas) { - tp->tgoal.period = per; - tp->tgoal.offset = ofs; - tp->tgoal.check_nego = 0; - } - - sym_announce_transfer_rate(tp); -} - -/* - * We received a PPR. - * Let everything be aware of the changes. - */ -static void -sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs, - u_char per, u_char wide, u_char div, u_char fak) -{ - struct sym_tcb *tp = &np->target[target]; - struct scsi_target *starget = tp->starget; - - sym_settrans(np, target, opts, ofs, per, wide, div, fak); - - if (wide || ofs) - tp->tgoal.renego = NS_PPR; - else - tp->tgoal.renego = 0; - spi_width(starget) = tp->tgoal.width = wide; - spi_period(starget) = tp->tgoal.period = per; - spi_offset(starget) = tp->tgoal.offset = ofs; - spi_iu(starget) = tp->tgoal.iu = !!(opts & PPR_OPT_IU); - spi_dt(starget) = tp->tgoal.dt = !!(opts & PPR_OPT_DT); - spi_qas(starget) = tp->tgoal.qas = !!(opts & PPR_OPT_QAS); - tp->tgoal.check_nego = 0; - - sym_announce_transfer_rate(tp); -} - -/* - * generic recovery from scsi interrupt - * - * The doc says that when the chip gets an SCSI interrupt, - * it tries to stop in an orderly fashion, by completing - * an instruction fetch that had started or by flushing - * the DMA fifo for a write to memory that was executing. - * Such a fashion is not enough to know if the instruction - * that was just before the current DSP value has been - * executed or not. - * - * There are some small SCRIPTS sections that deal with - * the start queue and the done queue that may break any - * assomption from the C code if we are interrupted - * inside, so we reset if this happens. Btw, since these - * SCRIPTS sections are executed while the SCRIPTS hasn't - * started SCSI operations, it is very unlikely to happen. - * - * All the driver data structures are supposed to be - * allocated from the same 4 GB memory window, so there - * is a 1 to 1 relationship between DSA and driver data - * structures. Since we are careful :) to invalidate the - * DSA when we complete a command or when the SCRIPTS - * pushes a DSA into a queue, we can trust it when it - * points to a CCB. - */ -static void sym_recover_scsi_int (struct sym_hcb *np, u_char hsts) -{ - u32 dsp = INL(np, nc_dsp); - u32 dsa = INL(np, nc_dsa); - struct sym_ccb *cp = sym_ccb_from_dsa(np, dsa); - - /* - * If we haven't been interrupted inside the SCRIPTS - * critical pathes, we can safely restart the SCRIPTS - * and trust the DSA value if it matches a CCB. - */ - if ((!(dsp > SCRIPTA_BA(np, getjob_begin) && - dsp < SCRIPTA_BA(np, getjob_end) + 1)) && - (!(dsp > SCRIPTA_BA(np, ungetjob) && - dsp < SCRIPTA_BA(np, reselect) + 1)) && - (!(dsp > SCRIPTB_BA(np, sel_for_abort) && - dsp < SCRIPTB_BA(np, sel_for_abort_1) + 1)) && - (!(dsp > SCRIPTA_BA(np, done) && - dsp < SCRIPTA_BA(np, done_end) + 1))) { - OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ - OUTB(np, nc_stest3, TE|CSF); /* clear scsi fifo */ - /* - * If we have a CCB, let the SCRIPTS call us back for - * the handling of the error with SCRATCHA filled with - * STARTPOS. This way, we will be able to freeze the - * device queue and requeue awaiting IOs. - */ - if (cp) { - cp->host_status = hsts; - OUTL_DSP(np, SCRIPTA_BA(np, complete_error)); - } - /* - * Otherwise just restart the SCRIPTS. - */ - else { - OUTL(np, nc_dsa, 0xffffff); - OUTL_DSP(np, SCRIPTA_BA(np, start)); - } - } - else - goto reset_all; - - return; - -reset_all: - sym_start_reset(np); -} - -/* - * chip exception handler for selection timeout - */ -static void sym_int_sto (struct sym_hcb *np) -{ - u32 dsp = INL(np, nc_dsp); - - if (DEBUG_FLAGS & DEBUG_TINY) printf ("T"); - - if (dsp == SCRIPTA_BA(np, wf_sel_done) + 8) - sym_recover_scsi_int(np, HS_SEL_TIMEOUT); - else - sym_start_reset(np); -} - -/* - * chip exception handler for unexpected disconnect - */ -static void sym_int_udc (struct sym_hcb *np) -{ - printf ("%s: unexpected disconnect\n", sym_name(np)); - sym_recover_scsi_int(np, HS_UNEXPECTED); -} - -/* - * chip exception handler for SCSI bus mode change - * - * spi2-r12 11.2.3 says a transceiver mode change must - * generate a reset event and a device that detects a reset - * event shall initiate a hard reset. It says also that a - * device that detects a mode change shall set data transfer - * mode to eight bit asynchronous, etc... - * So, just reinitializing all except chip should be enough. - */ -static void sym_int_sbmc(struct Scsi_Host *shost) -{ - struct sym_hcb *np = sym_get_hcb(shost); - u_char scsi_mode = INB(np, nc_stest4) & SMODE; - - /* - * Notify user. - */ - printf("%s: SCSI BUS mode change from %s to %s.\n", sym_name(np), - sym_scsi_bus_mode(np->scsi_mode), sym_scsi_bus_mode(scsi_mode)); - - /* - * Should suspend command processing for a few seconds and - * reinitialize all except the chip. - */ - sym_start_up(shost, 2); -} - -/* - * chip exception handler for SCSI parity error. - * - * When the chip detects a SCSI parity error and is - * currently executing a (CH)MOV instruction, it does - * not interrupt immediately, but tries to finish the - * transfer of the current scatter entry before - * interrupting. The following situations may occur: - * - * - The complete scatter entry has been transferred - * without the device having changed phase. - * The chip will then interrupt with the DSP pointing - * to the instruction that follows the MOV. - * - * - A phase mismatch occurs before the MOV finished - * and phase errors are to be handled by the C code. - * The chip will then interrupt with both PAR and MA - * conditions set. - * - * - A phase mismatch occurs before the MOV finished and - * phase errors are to be handled by SCRIPTS. - * The chip will load the DSP with the phase mismatch - * JUMP address and interrupt the host processor. - */ -static void sym_int_par (struct sym_hcb *np, u_short sist) -{ - u_char hsts = INB(np, HS_PRT); - u32 dsp = INL(np, nc_dsp); - u32 dbc = INL(np, nc_dbc); - u32 dsa = INL(np, nc_dsa); - u_char sbcl = INB(np, nc_sbcl); - u_char cmd = dbc >> 24; - int phase = cmd & 7; - struct sym_ccb *cp = sym_ccb_from_dsa(np, dsa); - - if (printk_ratelimit()) - printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", - sym_name(np), hsts, dbc, sbcl); - - /* - * Check that the chip is connected to the SCSI BUS. - */ - if (!(INB(np, nc_scntl1) & ISCON)) { - sym_recover_scsi_int(np, HS_UNEXPECTED); - return; - } - - /* - * If the nexus is not clearly identified, reset the bus. - * We will try to do better later. - */ - if (!cp) - goto reset_all; - - /* - * Check instruction was a MOV, direction was INPUT and - * ATN is asserted. - */ - if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8)) - goto reset_all; - - /* - * Keep track of the parity error. - */ - OUTONB(np, HF_PRT, HF_EXT_ERR); - cp->xerr_status |= XE_PARITY_ERR; - - /* - * Prepare the message to send to the device. - */ - np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR; - - /* - * If the old phase was DATA IN phase, we have to deal with - * the 3 situations described above. - * For other input phases (MSG IN and STATUS), the device - * must resend the whole thing that failed parity checking - * or signal error. So, jumping to dispatcher should be OK. - */ - if (phase == 1 || phase == 5) { - /* Phase mismatch handled by SCRIPTS */ - if (dsp == SCRIPTB_BA(np, pm_handle)) - OUTL_DSP(np, dsp); - /* Phase mismatch handled by the C code */ - else if (sist & MA) - sym_int_ma (np); - /* No phase mismatch occurred */ - else { - sym_set_script_dp (np, cp, dsp); - OUTL_DSP(np, SCRIPTA_BA(np, dispatch)); - } - } - else if (phase == 7) /* We definitely cannot handle parity errors */ -#if 1 /* in message-in phase due to the relection */ - goto reset_all; /* path and various message anticipations. */ -#else - OUTL_DSP(np, SCRIPTA_BA(np, clrack)); -#endif - else - OUTL_DSP(np, SCRIPTA_BA(np, dispatch)); - return; - -reset_all: - sym_start_reset(np); - return; -} - -/* - * chip exception handler for phase errors. - * - * We have to construct a new transfer descriptor, - * to transfer the rest of the current block. - */ -static void sym_int_ma (struct sym_hcb *np) -{ - u32 dbc; - u32 rest; - u32 dsp; - u32 dsa; - u32 nxtdsp; - u32 *vdsp; - u32 oadr, olen; - u32 *tblp; - u32 newcmd; - u_int delta; - u_char cmd; - u_char hflags, hflags0; - struct sym_pmc *pm; - struct sym_ccb *cp; - - dsp = INL(np, nc_dsp); - dbc = INL(np, nc_dbc); - dsa = INL(np, nc_dsa); - - cmd = dbc >> 24; - rest = dbc & 0xffffff; - delta = 0; - - /* - * locate matching cp if any. - */ - cp = sym_ccb_from_dsa(np, dsa); - - /* - * Donnot take into account dma fifo and various buffers in - * INPUT phase since the chip flushes everything before - * raising the MA interrupt for interrupted INPUT phases. - * For DATA IN phase, we will check for the SWIDE later. - */ - if ((cmd & 7) != 1 && (cmd & 7) != 5) { - u_char ss0, ss2; - - if (np->features & FE_DFBC) - delta = INW(np, nc_dfbc); - else { - u32 dfifo; - - /* - * Read DFIFO, CTEST[4-6] using 1 PCI bus ownership. - */ - dfifo = INL(np, nc_dfifo); - - /* - * Calculate remaining bytes in DMA fifo. - * (CTEST5 = dfifo >> 16) - */ - if (dfifo & (DFS << 16)) - delta = ((((dfifo >> 8) & 0x300) | - (dfifo & 0xff)) - rest) & 0x3ff; - else - delta = ((dfifo & 0xff) - rest) & 0x7f; - } - - /* - * The data in the dma fifo has not been transferred to - * the target -> add the amount to the rest - * and clear the data. - * Check the sstat2 register in case of wide transfer. - */ - rest += delta; - ss0 = INB(np, nc_sstat0); - if (ss0 & OLF) rest++; - if (!(np->features & FE_C10)) - if (ss0 & ORF) rest++; - if (cp && (cp->phys.select.sel_scntl3 & EWS)) { - ss2 = INB(np, nc_sstat2); - if (ss2 & OLF1) rest++; - if (!(np->features & FE_C10)) - if (ss2 & ORF1) rest++; - } - - /* - * Clear fifos. - */ - OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* dma fifo */ - OUTB(np, nc_stest3, TE|CSF); /* scsi fifo */ - } - - /* - * log the information - */ - if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) - printf ("P%x%x RL=%d D=%d ", cmd&7, INB(np, nc_sbcl)&7, - (unsigned) rest, (unsigned) delta); - - /* - * try to find the interrupted script command, - * and the address at which to continue. - */ - vdsp = NULL; - nxtdsp = 0; - if (dsp > np->scripta_ba && - dsp <= np->scripta_ba + np->scripta_sz) { - vdsp = (u32 *)((char*)np->scripta0 + (dsp-np->scripta_ba-8)); - nxtdsp = dsp; - } - else if (dsp > np->scriptb_ba && - dsp <= np->scriptb_ba + np->scriptb_sz) { - vdsp = (u32 *)((char*)np->scriptb0 + (dsp-np->scriptb_ba-8)); - nxtdsp = dsp; - } - - /* - * log the information - */ - if (DEBUG_FLAGS & DEBUG_PHASE) { - printf ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", - cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd); - } - - if (!vdsp) { - printf ("%s: interrupted SCRIPT address not found.\n", - sym_name (np)); - goto reset_all; - } - - if (!cp) { - printf ("%s: SCSI phase error fixup: CCB already dequeued.\n", - sym_name (np)); - goto reset_all; - } - - /* - * get old startaddress and old length. - */ - oadr = scr_to_cpu(vdsp[1]); - - if (cmd & 0x10) { /* Table indirect */ - tblp = (u32 *) ((char*) &cp->phys + oadr); - olen = scr_to_cpu(tblp[0]); - oadr = scr_to_cpu(tblp[1]); - } else { - tblp = (u32 *) 0; - olen = scr_to_cpu(vdsp[0]) & 0xffffff; - } - - if (DEBUG_FLAGS & DEBUG_PHASE) { - printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", - (unsigned) (scr_to_cpu(vdsp[0]) >> 24), - tblp, - (unsigned) olen, - (unsigned) oadr); - } - - /* - * check cmd against assumed interrupted script command. - * If dt data phase, the MOVE instruction hasn't bit 4 of - * the phase. - */ - if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) { - sym_print_addr(cp->cmd, - "internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", - cmd, scr_to_cpu(vdsp[0]) >> 24); - - goto reset_all; - } - - /* - * if old phase not dataphase, leave here. - */ - if (cmd & 2) { - sym_print_addr(cp->cmd, - "phase change %x-%x %d@%08x resid=%d.\n", - cmd&7, INB(np, nc_sbcl)&7, (unsigned)olen, - (unsigned)oadr, (unsigned)rest); - goto unexpected_phase; - } - - /* - * Choose the correct PM save area. - * - * Look at the PM_SAVE SCRIPT if you want to understand - * this stuff. The equivalent code is implemented in - * SCRIPTS for the 895A, 896 and 1010 that are able to - * handle PM from the SCRIPTS processor. - */ - hflags0 = INB(np, HF_PRT); - hflags = hflags0; - - if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) { - if (hflags & HF_IN_PM0) - nxtdsp = scr_to_cpu(cp->phys.pm0.ret); - else if (hflags & HF_IN_PM1) - nxtdsp = scr_to_cpu(cp->phys.pm1.ret); - - if (hflags & HF_DP_SAVED) - hflags ^= HF_ACT_PM; - } - - if (!(hflags & HF_ACT_PM)) { - pm = &cp->phys.pm0; - newcmd = SCRIPTA_BA(np, pm0_data); - } - else { - pm = &cp->phys.pm1; - newcmd = SCRIPTA_BA(np, pm1_data); - } - - hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED); - if (hflags != hflags0) - OUTB(np, HF_PRT, hflags); - - /* - * fillin the phase mismatch context - */ - pm->sg.addr = cpu_to_scr(oadr + olen - rest); - pm->sg.size = cpu_to_scr(rest); - pm->ret = cpu_to_scr(nxtdsp); - - /* - * If we have a SWIDE, - * - prepare the address to write the SWIDE from SCRIPTS, - * - compute the SCRIPTS address to restart from, - * - move current data pointer context by one byte. - */ - nxtdsp = SCRIPTA_BA(np, dispatch); - if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) && - (INB(np, nc_scntl2) & WSR)) { - u32 tmp; - - /* - * Set up the table indirect for the MOVE - * of the residual byte and adjust the data - * pointer context. - */ - tmp = scr_to_cpu(pm->sg.addr); - cp->phys.wresid.addr = cpu_to_scr(tmp); - pm->sg.addr = cpu_to_scr(tmp + 1); - tmp = scr_to_cpu(pm->sg.size); - cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1); - pm->sg.size = cpu_to_scr(tmp - 1); - - /* - * If only the residual byte is to be moved, - * no PM context is needed. - */ - if ((tmp&0xffffff) == 1) - newcmd = pm->ret; - - /* - * Prepare the address of SCRIPTS that will - * move the residual byte to memory. - */ - nxtdsp = SCRIPTB_BA(np, wsr_ma_helper); - } - - if (DEBUG_FLAGS & DEBUG_PHASE) { - sym_print_addr(cp->cmd, "PM %x %x %x / %x %x %x.\n", - hflags0, hflags, newcmd, - (unsigned)scr_to_cpu(pm->sg.addr), - (unsigned)scr_to_cpu(pm->sg.size), - (unsigned)scr_to_cpu(pm->ret)); - } - - /* - * Restart the SCRIPTS processor. - */ - sym_set_script_dp (np, cp, newcmd); - OUTL_DSP(np, nxtdsp); - return; - - /* - * Unexpected phase changes that occurs when the current phase - * is not a DATA IN or DATA OUT phase are due to error conditions. - * Such event may only happen when the SCRIPTS is using a - * multibyte SCSI MOVE. - * - * Phase change Some possible cause - * - * COMMAND --> MSG IN SCSI parity error detected by target. - * COMMAND --> STATUS Bad command or refused by target. - * MSG OUT --> MSG IN Message rejected by target. - * MSG OUT --> COMMAND Bogus target that discards extended - * negotiation messages. - * - * The code below does not care of the new phase and so - * trusts the target. Why to annoy it ? - * If the interrupted phase is COMMAND phase, we restart at - * dispatcher. - * If a target does not get all the messages after selection, - * the code assumes blindly that the target discards extended - * messages and clears the negotiation status. - * If the target does not want all our response to negotiation, - * we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids - * bloat for such a should_not_happen situation). - * In all other situation, we reset the BUS. - * Are these assumptions reasonable ? (Wait and see ...) - */ -unexpected_phase: - dsp -= 8; - nxtdsp = 0; - - switch (cmd & 7) { - case 2: /* COMMAND phase */ - nxtdsp = SCRIPTA_BA(np, dispatch); - break; -#if 0 - case 3: /* STATUS phase */ - nxtdsp = SCRIPTA_BA(np, dispatch); - break; -#endif - case 6: /* MSG OUT phase */ - /* - * If the device may want to use untagged when we want - * tagged, we prepare an IDENTIFY without disc. granted, - * since we will not be able to handle reselect. - * Otherwise, we just don't care. - */ - if (dsp == SCRIPTA_BA(np, send_ident)) { - if (cp->tag != NO_TAG && olen - rest <= 3) { - cp->host_status = HS_BUSY; - np->msgout[0] = IDENTIFY(0, cp->lun); - nxtdsp = SCRIPTB_BA(np, ident_break_atn); - } - else - nxtdsp = SCRIPTB_BA(np, ident_break); - } - else if (dsp == SCRIPTB_BA(np, send_wdtr) || - dsp == SCRIPTB_BA(np, send_sdtr) || - dsp == SCRIPTB_BA(np, send_ppr)) { - nxtdsp = SCRIPTB_BA(np, nego_bad_phase); - if (dsp == SCRIPTB_BA(np, send_ppr)) { - struct scsi_device *dev = cp->cmd->device; - dev->ppr = 0; - } - } - break; -#if 0 - case 7: /* MSG IN phase */ - nxtdsp = SCRIPTA_BA(np, clrack); - break; -#endif - } - - if (nxtdsp) { - OUTL_DSP(np, nxtdsp); - return; - } - -reset_all: - sym_start_reset(np); -} - -/* - * chip interrupt handler - * - * In normal situations, interrupt conditions occur one at - * a time. But when something bad happens on the SCSI BUS, - * the chip may raise several interrupt flags before - * stopping and interrupting the CPU. The additionnal - * interrupt flags are stacked in some extra registers - * after the SIP and/or DIP flag has been raised in the - * ISTAT. After the CPU has read the interrupt condition - * flag from SIST or DSTAT, the chip unstacks the other - * interrupt flags and sets the corresponding bits in - * SIST or DSTAT. Since the chip starts stacking once the - * SIP or DIP flag is set, there is a small window of time - * where the stacking does not occur. - * - * Typically, multiple interrupt conditions may happen in - * the following situations: - * - * - SCSI parity error + Phase mismatch (PAR|MA) - * When an parity error is detected in input phase - * and the device switches to msg-in phase inside a - * block MOV. - * - SCSI parity error + Unexpected disconnect (PAR|UDC) - * When a stupid device does not want to handle the - * recovery of an SCSI parity error. - * - Some combinations of STO, PAR, UDC, ... - * When using non compliant SCSI stuff, when user is - * doing non compliant hot tampering on the BUS, when - * something really bad happens to a device, etc ... - * - * The heuristic suggested by SYMBIOS to handle - * multiple interrupts is to try unstacking all - * interrupts conditions and to handle them on some - * priority based on error severity. - * This will work when the unstacking has been - * successful, but we cannot be 100 % sure of that, - * since the CPU may have been faster to unstack than - * the chip is able to stack. Hmmm ... But it seems that - * such a situation is very unlikely to happen. - * - * If this happen, for example STO caught by the CPU - * then UDC happenning before the CPU have restarted - * the SCRIPTS, the driver may wrongly complete the - * same command on UDC, since the SCRIPTS didn't restart - * and the DSA still points to the same command. - * We avoid this situation by setting the DSA to an - * invalid value when the CCB is completed and before - * restarting the SCRIPTS. - * - * Another issue is that we need some section of our - * recovery procedures to be somehow uninterruptible but - * the SCRIPTS processor does not provides such a - * feature. For this reason, we handle recovery preferently - * from the C code and check against some SCRIPTS critical - * sections from the C code. - * - * Hopefully, the interrupt handling of the driver is now - * able to resist to weird BUS error conditions, but donnot - * ask me for any guarantee that it will never fail. :-) - * Use at your own decision and risk. - */ - -irqreturn_t sym_interrupt(struct Scsi_Host *shost) -{ - struct sym_data *sym_data = shost_priv(shost); - struct sym_hcb *np = sym_data->ncb; - struct pci_dev *pdev = sym_data->pdev; - u_char istat, istatc; - u_char dstat; - u_short sist; - - /* - * interrupt on the fly ? - * (SCRIPTS may still be running) - * - * A `dummy read' is needed to ensure that the - * clear of the INTF flag reaches the device - * and that posted writes are flushed to memory - * before the scanning of the DONE queue. - * Note that SCRIPTS also (dummy) read to memory - * prior to deliver the INTF interrupt condition. - */ - istat = INB(np, nc_istat); - if (istat & INTF) { - OUTB(np, nc_istat, (istat & SIGP) | INTF | np->istat_sem); - istat |= INB(np, nc_istat); /* DUMMY READ */ - if (DEBUG_FLAGS & DEBUG_TINY) printf ("F "); - sym_wakeup_done(np); - } - - if (!(istat & (SIP|DIP))) - return (istat & INTF) ? IRQ_HANDLED : IRQ_NONE; - -#if 0 /* We should never get this one */ - if (istat & CABRT) - OUTB(np, nc_istat, CABRT); -#endif - - /* - * PAR and MA interrupts may occur at the same time, - * and we need to know of both in order to handle - * this situation properly. We try to unstack SCSI - * interrupts for that reason. BTW, I dislike a LOT - * such a loop inside the interrupt routine. - * Even if DMA interrupt stacking is very unlikely to - * happen, we also try unstacking these ones, since - * this has no performance impact. - */ - sist = 0; - dstat = 0; - istatc = istat; - do { - if (istatc & SIP) - sist |= INW(np, nc_sist); - if (istatc & DIP) - dstat |= INB(np, nc_dstat); - istatc = INB(np, nc_istat); - istat |= istatc; - - /* Prevent deadlock waiting on a condition that may - * never clear. */ - if (unlikely(sist == 0xffff && dstat == 0xff)) { - if (pci_channel_offline(pdev)) - return IRQ_NONE; - } - } while (istatc & (SIP|DIP)); - - if (DEBUG_FLAGS & DEBUG_TINY) - printf ("<%d|%x:%x|%x:%x>", - (int)INB(np, nc_scr0), - dstat,sist, - (unsigned)INL(np, nc_dsp), - (unsigned)INL(np, nc_dbc)); - /* - * On paper, a memory read barrier may be needed here to - * prevent out of order LOADs by the CPU from having - * prefetched stale data prior to DMA having occurred. - * And since we are paranoid ... :) - */ - MEMORY_READ_BARRIER(); - - /* - * First, interrupts we want to service cleanly. - * - * Phase mismatch (MA) is the most frequent interrupt - * for chip earlier than the 896 and so we have to service - * it as quickly as possible. - * A SCSI parity error (PAR) may be combined with a phase - * mismatch condition (MA). - * Programmed interrupts (SIR) are used to call the C code - * from SCRIPTS. - * The single step interrupt (SSI) is not used in this - * driver. - */ - if (!(sist & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) && - !(dstat & (MDPE|BF|ABRT|IID))) { - if (sist & PAR) sym_int_par (np, sist); - else if (sist & MA) sym_int_ma (np); - else if (dstat & SIR) sym_int_sir(np); - else if (dstat & SSI) OUTONB_STD(); - else goto unknown_int; - return IRQ_HANDLED; - } - - /* - * Now, interrupts that donnot happen in normal - * situations and that we may need to recover from. - * - * On SCSI RESET (RST), we reset everything. - * On SCSI BUS MODE CHANGE (SBMC), we complete all - * active CCBs with RESET status, prepare all devices - * for negotiating again and restart the SCRIPTS. - * On STO and UDC, we complete the CCB with the corres- - * ponding status and restart the SCRIPTS. - */ - if (sist & RST) { - printf("%s: SCSI BUS reset detected.\n", sym_name(np)); - sym_start_up(shost, 1); - return IRQ_HANDLED; - } - - OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ - OUTB(np, nc_stest3, TE|CSF); /* clear scsi fifo */ - - if (!(sist & (GEN|HTH|SGE)) && - !(dstat & (MDPE|BF|ABRT|IID))) { - if (sist & SBMC) sym_int_sbmc(shost); - else if (sist & STO) sym_int_sto (np); - else if (sist & UDC) sym_int_udc (np); - else goto unknown_int; - return IRQ_HANDLED; - } - - /* - * Now, interrupts we are not able to recover cleanly. - * - * Log message for hard errors. - * Reset everything. - */ - - sym_log_hard_error(shost, sist, dstat); - - if ((sist & (GEN|HTH|SGE)) || - (dstat & (MDPE|BF|ABRT|IID))) { - sym_start_reset(np); - return IRQ_HANDLED; - } - -unknown_int: - /* - * We just miss the cause of the interrupt. :( - * Print a message. The timeout will do the real work. - */ - printf( "%s: unknown interrupt(s) ignored, " - "ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n", - sym_name(np), istat, dstat, sist); - return IRQ_NONE; -} - -/* - * Dequeue from the START queue all CCBs that match - * a given target/lun/task condition (-1 means all), - * and move them from the BUSY queue to the COMP queue - * with DID_SOFT_ERROR status condition. - * This function is used during error handling/recovery. - * It is called with SCRIPTS not running. - */ -static int -sym_dequeue_from_squeue(struct sym_hcb *np, int i, int target, int lun, int task) -{ - int j; - struct sym_ccb *cp; - - /* - * Make sure the starting index is within range. - */ - assert((i >= 0) && (i < 2*MAX_QUEUE)); - - /* - * Walk until end of START queue and dequeue every job - * that matches the target/lun/task condition. - */ - j = i; - while (i != np->squeueput) { - cp = sym_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); - assert(cp); -#ifdef SYM_CONF_IARB_SUPPORT - /* Forget hints for IARB, they may be no longer relevant */ - cp->host_flags &= ~HF_HINT_IARB; -#endif - if ((target == -1 || cp->target == target) && - (lun == -1 || cp->lun == lun) && - (task == -1 || cp->tag == task)) { - sym_set_cam_status(cp->cmd, DID_SOFT_ERROR); - sym_remque(&cp->link_ccbq); - sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); - } - else { - if (i != j) - np->squeue[j] = np->squeue[i]; - if ((j += 2) >= MAX_QUEUE*2) j = 0; - } - if ((i += 2) >= MAX_QUEUE*2) i = 0; - } - if (i != j) /* Copy back the idle task if needed */ - np->squeue[j] = np->squeue[i]; - np->squeueput = j; /* Update our current start queue pointer */ - - return (i - j) / 2; -} - -/* - * chip handler for bad SCSI status condition - * - * In case of bad SCSI status, we unqueue all the tasks - * currently queued to the controller but not yet started - * and then restart the SCRIPTS processor immediately. - * - * QUEUE FULL and BUSY conditions are handled the same way. - * Basically all the not yet started tasks are requeued in - * device queue and the queue is frozen until a completion. - * - * For CHECK CONDITION and COMMAND TERMINATED status, we use - * the CCB of the failed command to prepare a REQUEST SENSE - * SCSI command and queue it to the controller queue. - * - * SCRATCHA is assumed to have been loaded with STARTPOS - * before the SCRIPTS called the C code. - */ -static void sym_sir_bad_scsi_status(struct sym_hcb *np, int num, struct sym_ccb *cp) -{ - u32 startp; - u_char s_status = cp->ssss_status; - u_char h_flags = cp->host_flags; - int msglen; - int i; - - /* - * Compute the index of the next job to start from SCRIPTS. - */ - i = (INL(np, nc_scratcha) - np->squeue_ba) / 4; - - /* - * The last CCB queued used for IARB hint may be - * no longer relevant. Forget it. - */ -#ifdef SYM_CONF_IARB_SUPPORT - if (np->last_cp) - np->last_cp = 0; -#endif - - /* - * Now deal with the SCSI status. - */ - switch(s_status) { - case S_BUSY: - case S_QUEUE_FULL: - if (sym_verbose >= 2) { - sym_print_addr(cp->cmd, "%s\n", - s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n"); - } - default: /* S_INT, S_INT_COND_MET, S_CONFLICT */ - sym_complete_error (np, cp); - break; - case S_TERMINATED: - case S_CHECK_COND: - /* - * If we get an SCSI error when requesting sense, give up. - */ - if (h_flags & HF_SENSE) { - sym_complete_error (np, cp); - break; - } - - /* - * Dequeue all queued CCBs for that device not yet started, - * and restart the SCRIPTS processor immediately. - */ - sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); - OUTL_DSP(np, SCRIPTA_BA(np, start)); - - /* - * Save some info of the actual IO. - * Compute the data residual. - */ - cp->sv_scsi_status = cp->ssss_status; - cp->sv_xerr_status = cp->xerr_status; - cp->sv_resid = sym_compute_residual(np, cp); - - /* - * Prepare all needed data structures for - * requesting sense data. - */ - - cp->scsi_smsg2[0] = IDENTIFY(0, cp->lun); - msglen = 1; - - /* - * If we are currently using anything different from - * async. 8 bit data transfers with that target, - * start a negotiation, since the device may want - * to report us a UNIT ATTENTION condition due to - * a cause we currently ignore, and we donnot want - * to be stuck with WIDE and/or SYNC data transfer. - * - * cp->nego_status is filled by sym_prepare_nego(). - */ - cp->nego_status = 0; - msglen += sym_prepare_nego(np, cp, &cp->scsi_smsg2[msglen]); - /* - * Message table indirect structure. - */ - cp->phys.smsg.addr = CCB_BA(cp, scsi_smsg2); - cp->phys.smsg.size = cpu_to_scr(msglen); - - /* - * sense command - */ - cp->phys.cmd.addr = CCB_BA(cp, sensecmd); - cp->phys.cmd.size = cpu_to_scr(6); - - /* - * patch requested size into sense command - */ - cp->sensecmd[0] = REQUEST_SENSE; - cp->sensecmd[1] = 0; - if (cp->cmd->device->scsi_level <= SCSI_2 && cp->lun <= 7) - cp->sensecmd[1] = cp->lun << 5; - cp->sensecmd[4] = SYM_SNS_BBUF_LEN; - cp->data_len = SYM_SNS_BBUF_LEN; - - /* - * sense data - */ - memset(cp->sns_bbuf, 0, SYM_SNS_BBUF_LEN); - cp->phys.sense.addr = CCB_BA(cp, sns_bbuf); - cp->phys.sense.size = cpu_to_scr(SYM_SNS_BBUF_LEN); - - /* - * requeue the command. - */ - startp = SCRIPTB_BA(np, sdata_in); - - cp->phys.head.savep = cpu_to_scr(startp); - cp->phys.head.lastp = cpu_to_scr(startp); - cp->startp = cpu_to_scr(startp); - cp->goalp = cpu_to_scr(startp + 16); - - cp->host_xflags = 0; - cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; - cp->ssss_status = S_ILLEGAL; - cp->host_flags = (HF_SENSE|HF_DATA_IN); - cp->xerr_status = 0; - cp->extra_bytes = 0; - - cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA(np, select)); - - /* - * Requeue the command. - */ - sym_put_start_queue(np, cp); - - /* - * Give back to upper layer everything we have dequeued. - */ - sym_flush_comp_queue(np, 0); - break; - } -} - -/* - * After a device has accepted some management message - * as BUS DEVICE RESET, ABORT TASK, etc ..., or when - * a device signals a UNIT ATTENTION condition, some - * tasks are thrown away by the device. We are required - * to reflect that on our tasks list since the device - * will never complete these tasks. - * - * This function move from the BUSY queue to the COMP - * queue all disconnected CCBs for a given target that - * match the following criteria: - * - lun=-1 means any logical UNIT otherwise a given one. - * - task=-1 means any task, otherwise a given one. - */ -int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int task) -{ - SYM_QUEHEAD qtmp, *qp; - int i = 0; - struct sym_ccb *cp; - - /* - * Move the entire BUSY queue to our temporary queue. - */ - sym_que_init(&qtmp); - sym_que_splice(&np->busy_ccbq, &qtmp); - sym_que_init(&np->busy_ccbq); - - /* - * Put all CCBs that matches our criteria into - * the COMP queue and put back other ones into - * the BUSY queue. - */ - while ((qp = sym_remque_head(&qtmp)) != NULL) { - struct scsi_cmnd *cmd; - cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); - cmd = cp->cmd; - if (cp->host_status != HS_DISCONNECT || - cp->target != target || - (lun != -1 && cp->lun != lun) || - (task != -1 && - (cp->tag != NO_TAG && cp->scsi_smsg[2] != task))) { - sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); - continue; - } - sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); - - /* Preserve the software timeout condition */ - if (sym_get_cam_status(cmd) != DID_TIME_OUT) - sym_set_cam_status(cmd, cam_status); - ++i; -#if 0 -printf("XXXX TASK @%p CLEARED\n", cp); -#endif - } - return i; -} - -/* - * chip handler for TASKS recovery - * - * We cannot safely abort a command, while the SCRIPTS - * processor is running, since we just would be in race - * with it. - * - * As long as we have tasks to abort, we keep the SEM - * bit set in the ISTAT. When this bit is set, the - * SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) - * each time it enters the scheduler. - * - * If we have to reset a target, clear tasks of a unit, - * or to perform the abort of a disconnected job, we - * restart the SCRIPTS for selecting the target. Once - * selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED). - * If it loses arbitration, the SCRIPTS will interrupt again - * the next time it will enter its scheduler, and so on ... - * - * On SIR_TARGET_SELECTED, we scan for the more - * appropriate thing to do: - * - * - If nothing, we just sent a M_ABORT message to the - * target to get rid of the useless SCSI bus ownership. - * According to the specs, no tasks shall be affected. - * - If the target is to be reset, we send it a M_RESET - * message. - * - If a logical UNIT is to be cleared , we send the - * IDENTIFY(lun) + M_ABORT. - * - If an untagged task is to be aborted, we send the - * IDENTIFY(lun) + M_ABORT. - * - If a tagged task is to be aborted, we send the - * IDENTIFY(lun) + task attributes + M_ABORT_TAG. - * - * Once our 'kiss of death' :) message has been accepted - * by the target, the SCRIPTS interrupts again - * (SIR_ABORT_SENT). On this interrupt, we complete - * all the CCBs that should have been aborted by the - * target according to our message. - */ -static void sym_sir_task_recovery(struct sym_hcb *np, int num) -{ - SYM_QUEHEAD *qp; - struct sym_ccb *cp; - struct sym_tcb *tp = NULL; /* gcc isn't quite smart enough yet */ - struct scsi_target *starget; - int target=-1, lun=-1, task; - int i, k; - - switch(num) { - /* - * The SCRIPTS processor stopped before starting - * the next command in order to allow us to perform - * some task recovery. - */ - case SIR_SCRIPT_STOPPED: - /* - * Do we have any target to reset or unit to clear ? - */ - for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { - tp = &np->target[i]; - if (tp->to_reset || - (tp->lun0p && tp->lun0p->to_clear)) { - target = i; - break; - } - if (!tp->lunmp) - continue; - for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) { - if (tp->lunmp[k] && tp->lunmp[k]->to_clear) { - target = i; - break; - } - } - if (target != -1) - break; - } - - /* - * If not, walk the busy queue for any - * disconnected CCB to be aborted. - */ - if (target == -1) { - FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { - cp = sym_que_entry(qp,struct sym_ccb,link_ccbq); - if (cp->host_status != HS_DISCONNECT) - continue; - if (cp->to_abort) { - target = cp->target; - break; - } - } - } - - /* - * If some target is to be selected, - * prepare and start the selection. - */ - if (target != -1) { - tp = &np->target[target]; - np->abrt_sel.sel_id = target; - np->abrt_sel.sel_scntl3 = tp->head.wval; - np->abrt_sel.sel_sxfer = tp->head.sval; - OUTL(np, nc_dsa, np->hcb_ba); - OUTL_DSP(np, SCRIPTB_BA(np, sel_for_abort)); - return; - } - - /* - * Now look for a CCB to abort that haven't started yet. - * Btw, the SCRIPTS processor is still stopped, so - * we are not in race. - */ - i = 0; - cp = NULL; - FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { - cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); - if (cp->host_status != HS_BUSY && - cp->host_status != HS_NEGOTIATE) - continue; - if (!cp->to_abort) - continue; -#ifdef SYM_CONF_IARB_SUPPORT - /* - * If we are using IMMEDIATE ARBITRATION, we donnot - * want to cancel the last queued CCB, since the - * SCRIPTS may have anticipated the selection. - */ - if (cp == np->last_cp) { - cp->to_abort = 0; - continue; - } -#endif - i = 1; /* Means we have found some */ - break; - } - if (!i) { - /* - * We are done, so we donnot need - * to synchronize with the SCRIPTS anylonger. - * Remove the SEM flag from the ISTAT. - */ - np->istat_sem = 0; - OUTB(np, nc_istat, SIGP); - break; - } - /* - * Compute index of next position in the start - * queue the SCRIPTS intends to start and dequeue - * all CCBs for that device that haven't been started. - */ - i = (INL(np, nc_scratcha) - np->squeue_ba) / 4; - i = sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); - - /* - * Make sure at least our IO to abort has been dequeued. - */ -#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - assert(i && sym_get_cam_status(cp->cmd) == DID_SOFT_ERROR); -#else - sym_remque(&cp->link_ccbq); - sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); -#endif - /* - * Keep track in cam status of the reason of the abort. - */ - if (cp->to_abort == 2) - sym_set_cam_status(cp->cmd, DID_TIME_OUT); - else - sym_set_cam_status(cp->cmd, DID_ABORT); - - /* - * Complete with error everything that we have dequeued. - */ - sym_flush_comp_queue(np, 0); - break; - /* - * The SCRIPTS processor has selected a target - * we may have some manual recovery to perform for. - */ - case SIR_TARGET_SELECTED: - target = INB(np, nc_sdid) & 0xf; - tp = &np->target[target]; - - np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg)); - - /* - * If the target is to be reset, prepare a - * M_RESET message and clear the to_reset flag - * since we donnot expect this operation to fail. - */ - if (tp->to_reset) { - np->abrt_msg[0] = M_RESET; - np->abrt_tbl.size = 1; - tp->to_reset = 0; - break; - } - - /* - * Otherwise, look for some logical unit to be cleared. - */ - if (tp->lun0p && tp->lun0p->to_clear) - lun = 0; - else if (tp->lunmp) { - for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) { - if (tp->lunmp[k] && tp->lunmp[k]->to_clear) { - lun = k; - break; - } - } - } - - /* - * If a logical unit is to be cleared, prepare - * an IDENTIFY(lun) + ABORT MESSAGE. - */ - if (lun != -1) { - struct sym_lcb *lp = sym_lp(tp, lun); - lp->to_clear = 0; /* We don't expect to fail here */ - np->abrt_msg[0] = IDENTIFY(0, lun); - np->abrt_msg[1] = M_ABORT; - np->abrt_tbl.size = 2; - break; - } - - /* - * Otherwise, look for some disconnected job to - * abort for this target. - */ - i = 0; - cp = NULL; - FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { - cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); - if (cp->host_status != HS_DISCONNECT) - continue; - if (cp->target != target) - continue; - if (!cp->to_abort) - continue; - i = 1; /* Means we have some */ - break; - } - - /* - * If we have none, probably since the device has - * completed the command before we won abitration, - * send a M_ABORT message without IDENTIFY. - * According to the specs, the device must just - * disconnect the BUS and not abort any task. - */ - if (!i) { - np->abrt_msg[0] = M_ABORT; - np->abrt_tbl.size = 1; - break; - } - - /* - * We have some task to abort. - * Set the IDENTIFY(lun) - */ - np->abrt_msg[0] = IDENTIFY(0, cp->lun); - - /* - * If we want to abort an untagged command, we - * will send a IDENTIFY + M_ABORT. - * Otherwise (tagged command), we will send - * a IDENTITFY + task attributes + ABORT TAG. - */ - if (cp->tag == NO_TAG) { - np->abrt_msg[1] = M_ABORT; - np->abrt_tbl.size = 2; - } else { - np->abrt_msg[1] = cp->scsi_smsg[1]; - np->abrt_msg[2] = cp->scsi_smsg[2]; - np->abrt_msg[3] = M_ABORT_TAG; - np->abrt_tbl.size = 4; - } - /* - * Keep track of software timeout condition, since the - * peripheral driver may not count retries on abort - * conditions not due to timeout. - */ - if (cp->to_abort == 2) - sym_set_cam_status(cp->cmd, DID_TIME_OUT); - cp->to_abort = 0; /* We donnot expect to fail here */ - break; - - /* - * The target has accepted our message and switched - * to BUS FREE phase as we expected. - */ - case SIR_ABORT_SENT: - target = INB(np, nc_sdid) & 0xf; - tp = &np->target[target]; - starget = tp->starget; - - /* - ** If we didn't abort anything, leave here. - */ - if (np->abrt_msg[0] == M_ABORT) - break; - - /* - * If we sent a M_RESET, then a hardware reset has - * been performed by the target. - * - Reset everything to async 8 bit - * - Tell ourself to negotiate next time :-) - * - Prepare to clear all disconnected CCBs for - * this target from our task list (lun=task=-1) - */ - lun = -1; - task = -1; - if (np->abrt_msg[0] == M_RESET) { - tp->head.sval = 0; - tp->head.wval = np->rv_scntl3; - tp->head.uval = 0; - spi_period(starget) = 0; - spi_offset(starget) = 0; - spi_width(starget) = 0; - spi_iu(starget) = 0; - spi_dt(starget) = 0; - spi_qas(starget) = 0; - tp->tgoal.check_nego = 1; - tp->tgoal.renego = 0; - } - - /* - * Otherwise, check for the LUN and TASK(s) - * concerned by the cancelation. - * If it is not ABORT_TAG then it is CLEAR_QUEUE - * or an ABORT message :-) - */ - else { - lun = np->abrt_msg[0] & 0x3f; - if (np->abrt_msg[1] == M_ABORT_TAG) - task = np->abrt_msg[2]; - } - - /* - * Complete all the CCBs the device should have - * aborted due to our 'kiss of death' message. - */ - i = (INL(np, nc_scratcha) - np->squeue_ba) / 4; - sym_dequeue_from_squeue(np, i, target, lun, -1); - sym_clear_tasks(np, DID_ABORT, target, lun, task); - sym_flush_comp_queue(np, 0); - - /* - * If we sent a BDR, make upper layer aware of that. - */ - if (np->abrt_msg[0] == M_RESET) - starget_printk(KERN_NOTICE, starget, - "has been reset\n"); - break; - } - - /* - * Print to the log the message we intend to send. - */ - if (num == SIR_TARGET_SELECTED) { - dev_info(&tp->starget->dev, "control msgout:"); - sym_printl_hex(np->abrt_msg, np->abrt_tbl.size); - np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size); - } - - /* - * Let the SCRIPTS processor continue. - */ - OUTONB_STD(); -} - -/* - * Gerard's alchemy:) that deals with with the data - * pointer for both MDP and the residual calculation. - * - * I didn't want to bloat the code by more than 200 - * lines for the handling of both MDP and the residual. - * This has been achieved by using a data pointer - * representation consisting in an index in the data - * array (dp_sg) and a negative offset (dp_ofs) that - * have the following meaning: - * - * - dp_sg = SYM_CONF_MAX_SG - * we are at the end of the data script. - * - dp_sg < SYM_CONF_MAX_SG - * dp_sg points to the next entry of the scatter array - * we want to transfer. - * - dp_ofs < 0 - * dp_ofs represents the residual of bytes of the - * previous entry scatter entry we will send first. - * - dp_ofs = 0 - * no residual to send first. - * - * The function sym_evaluate_dp() accepts an arbitray - * offset (basically from the MDP message) and returns - * the corresponding values of dp_sg and dp_ofs. - */ - -static int sym_evaluate_dp(struct sym_hcb *np, struct sym_ccb *cp, u32 scr, int *ofs) -{ - u32 dp_scr; - int dp_ofs, dp_sg, dp_sgmin; - int tmp; - struct sym_pmc *pm; - - /* - * Compute the resulted data pointer in term of a script - * address within some DATA script and a signed byte offset. - */ - dp_scr = scr; - dp_ofs = *ofs; - if (dp_scr == SCRIPTA_BA(np, pm0_data)) - pm = &cp->phys.pm0; - else if (dp_scr == SCRIPTA_BA(np, pm1_data)) - pm = &cp->phys.pm1; - else - pm = NULL; - - if (pm) { - dp_scr = scr_to_cpu(pm->ret); - dp_ofs -= scr_to_cpu(pm->sg.size) & 0x00ffffff; - } - - /* - * If we are auto-sensing, then we are done. - */ - if (cp->host_flags & HF_SENSE) { - *ofs = dp_ofs; - return 0; - } - - /* - * Deduce the index of the sg entry. - * Keep track of the index of the first valid entry. - * If result is dp_sg = SYM_CONF_MAX_SG, then we are at the - * end of the data. - */ - tmp = scr_to_cpu(cp->goalp); - dp_sg = SYM_CONF_MAX_SG; - if (dp_scr != tmp) - dp_sg -= (tmp - 8 - (int)dp_scr) / (2*4); - dp_sgmin = SYM_CONF_MAX_SG - cp->segments; - - /* - * Move to the sg entry the data pointer belongs to. - * - * If we are inside the data area, we expect result to be: - * - * Either, - * dp_ofs = 0 and dp_sg is the index of the sg entry - * the data pointer belongs to (or the end of the data) - * Or, - * dp_ofs < 0 and dp_sg is the index of the sg entry - * the data pointer belongs to + 1. - */ - if (dp_ofs < 0) { - int n; - while (dp_sg > dp_sgmin) { - --dp_sg; - tmp = scr_to_cpu(cp->phys.data[dp_sg].size); - n = dp_ofs + (tmp & 0xffffff); - if (n > 0) { - ++dp_sg; - break; - } - dp_ofs = n; - } - } - else if (dp_ofs > 0) { - while (dp_sg < SYM_CONF_MAX_SG) { - tmp = scr_to_cpu(cp->phys.data[dp_sg].size); - dp_ofs -= (tmp & 0xffffff); - ++dp_sg; - if (dp_ofs <= 0) - break; - } - } - - /* - * Make sure the data pointer is inside the data area. - * If not, return some error. - */ - if (dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0)) - goto out_err; - else if (dp_sg > SYM_CONF_MAX_SG || - (dp_sg == SYM_CONF_MAX_SG && dp_ofs > 0)) - goto out_err; - - /* - * Save the extreme pointer if needed. - */ - if (dp_sg > cp->ext_sg || - (dp_sg == cp->ext_sg && dp_ofs > cp->ext_ofs)) { - cp->ext_sg = dp_sg; - cp->ext_ofs = dp_ofs; - } - - /* - * Return data. - */ - *ofs = dp_ofs; - return dp_sg; - -out_err: - return -1; -} - -/* - * chip handler for MODIFY DATA POINTER MESSAGE - * - * We also call this function on IGNORE WIDE RESIDUE - * messages that do not match a SWIDE full condition. - * Btw, we assume in that situation that such a message - * is equivalent to a MODIFY DATA POINTER (offset=-1). - */ - -static void sym_modify_dp(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp, int ofs) -{ - int dp_ofs = ofs; - u32 dp_scr = sym_get_script_dp (np, cp); - u32 dp_ret; - u32 tmp; - u_char hflags; - int dp_sg; - struct sym_pmc *pm; - - /* - * Not supported for auto-sense. - */ - if (cp->host_flags & HF_SENSE) - goto out_reject; - - /* - * Apply our alchemy:) (see comments in sym_evaluate_dp()), - * to the resulted data pointer. - */ - dp_sg = sym_evaluate_dp(np, cp, dp_scr, &dp_ofs); - if (dp_sg < 0) - goto out_reject; - - /* - * And our alchemy:) allows to easily calculate the data - * script address we want to return for the next data phase. - */ - dp_ret = cpu_to_scr(cp->goalp); - dp_ret = dp_ret - 8 - (SYM_CONF_MAX_SG - dp_sg) * (2*4); - - /* - * If offset / scatter entry is zero we donnot need - * a context for the new current data pointer. - */ - if (dp_ofs == 0) { - dp_scr = dp_ret; - goto out_ok; - } - - /* - * Get a context for the new current data pointer. - */ - hflags = INB(np, HF_PRT); - - if (hflags & HF_DP_SAVED) - hflags ^= HF_ACT_PM; - - if (!(hflags & HF_ACT_PM)) { - pm = &cp->phys.pm0; - dp_scr = SCRIPTA_BA(np, pm0_data); - } - else { - pm = &cp->phys.pm1; - dp_scr = SCRIPTA_BA(np, pm1_data); - } - - hflags &= ~(HF_DP_SAVED); - - OUTB(np, HF_PRT, hflags); - - /* - * Set up the new current data pointer. - * ofs < 0 there, and for the next data phase, we - * want to transfer part of the data of the sg entry - * corresponding to index dp_sg-1 prior to returning - * to the main data script. - */ - pm->ret = cpu_to_scr(dp_ret); - tmp = scr_to_cpu(cp->phys.data[dp_sg-1].addr); - tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs; - pm->sg.addr = cpu_to_scr(tmp); - pm->sg.size = cpu_to_scr(-dp_ofs); - -out_ok: - sym_set_script_dp (np, cp, dp_scr); - OUTL_DSP(np, SCRIPTA_BA(np, clrack)); - return; - -out_reject: - OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); -} - - -/* - * chip calculation of the data residual. - * - * As I used to say, the requirement of data residual - * in SCSI is broken, useless and cannot be achieved - * without huge complexity. - * But most OSes and even the official CAM require it. - * When stupidity happens to be so widely spread inside - * a community, it gets hard to convince. - * - * Anyway, I don't care, since I am not going to use - * any software that considers this data residual as - * a relevant information. :) - */ - -int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp) -{ - int dp_sg, dp_sgmin, resid = 0; - int dp_ofs = 0; - - /* - * Check for some data lost or just thrown away. - * We are not required to be quite accurate in this - * situation. Btw, if we are odd for output and the - * device claims some more data, it may well happen - * than our residual be zero. :-) - */ - if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) { - if (cp->xerr_status & XE_EXTRA_DATA) - resid -= cp->extra_bytes; - if (cp->xerr_status & XE_SODL_UNRUN) - ++resid; - if (cp->xerr_status & XE_SWIDE_OVRUN) - --resid; - } - - /* - * If all data has been transferred, - * there is no residual. - */ - if (cp->phys.head.lastp == cp->goalp) - return resid; - - /* - * If no data transfer occurs, or if the data - * pointer is weird, return full residual. - */ - if (cp->startp == cp->phys.head.lastp || - sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp), - &dp_ofs) < 0) { - return cp->data_len - cp->odd_byte_adjustment; - } - - /* - * If we were auto-sensing, then we are done. - */ - if (cp->host_flags & HF_SENSE) { - return -dp_ofs; - } - - /* - * We are now full comfortable in the computation - * of the data residual (2's complement). - */ - dp_sgmin = SYM_CONF_MAX_SG - cp->segments; - resid = -cp->ext_ofs; - for (dp_sg = cp->ext_sg; dp_sg < SYM_CONF_MAX_SG; ++dp_sg) { - u_int tmp = scr_to_cpu(cp->phys.data[dp_sg].size); - resid += (tmp & 0xffffff); - } - - resid -= cp->odd_byte_adjustment; - - /* - * Hopefully, the result is not too wrong. - */ - return resid; -} - -/* - * Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER. - * - * When we try to negotiate, we append the negotiation message - * to the identify and (maybe) simple tag message. - * The host status field is set to HS_NEGOTIATE to mark this - * situation. - * - * If the target doesn't answer this message immediately - * (as required by the standard), the SIR_NEGO_FAILED interrupt - * will be raised eventually. - * The handler removes the HS_NEGOTIATE status, and sets the - * negotiated value to the default (async / nowide). - * - * If we receive a matching answer immediately, we check it - * for validity, and set the values. - * - * If we receive a Reject message immediately, we assume the - * negotiation has failed, and fall back to standard values. - * - * If we receive a negotiation message while not in HS_NEGOTIATE - * state, it's a target initiated negotiation. We prepare a - * (hopefully) valid answer, set our parameters, and send back - * this answer to the target. - * - * If the target doesn't fetch the answer (no message out phase), - * we assume the negotiation has failed, and fall back to default - * settings (SIR_NEGO_PROTO interrupt). - * - * When we set the values, we adjust them in all ccbs belonging - * to this target, in the controller's register, and in the "phys" - * field of the controller's struct sym_hcb. - */ - -/* - * chip handler for SYNCHRONOUS DATA TRANSFER REQUEST (SDTR) message. - */ -static int -sym_sync_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp) -{ - int target = cp->target; - u_char chg, ofs, per, fak, div; - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_nego_msg(np, target, "sync msgin", np->msgin); - } - - /* - * Get requested values. - */ - chg = 0; - per = np->msgin[3]; - ofs = np->msgin[4]; - - /* - * Check values against our limits. - */ - if (ofs) { - if (ofs > np->maxoffs) - {chg = 1; ofs = np->maxoffs;} - } - - if (ofs) { - if (per < np->minsync) - {chg = 1; per = np->minsync;} - } - - /* - * Get new chip synchronous parameters value. - */ - div = fak = 0; - if (ofs && sym_getsync(np, 0, per, &div, &fak) < 0) - goto reject_it; - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_addr(cp->cmd, - "sdtr: ofs=%d per=%d div=%d fak=%d chg=%d.\n", - ofs, per, div, fak, chg); - } - - /* - * If it was an answer we want to change, - * then it isn't acceptable. Reject it. - */ - if (!req && chg) - goto reject_it; - - /* - * Apply new values. - */ - sym_setsync (np, target, ofs, per, div, fak); - - /* - * It was an answer. We are done. - */ - if (!req) - return 0; - - /* - * It was a request. Prepare an answer message. - */ - spi_populate_sync_msg(np->msgout, per, ofs); - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_nego_msg(np, target, "sync msgout", np->msgout); - } - - np->msgin [0] = M_NOOP; - - return 0; - -reject_it: - sym_setsync (np, target, 0, 0, 0, 0); - return -1; -} - -static void sym_sync_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) -{ - int req = 1; - int result; - - /* - * Request or answer ? - */ - if (INB(np, HS_PRT) == HS_NEGOTIATE) { - OUTB(np, HS_PRT, HS_BUSY); - if (cp->nego_status && cp->nego_status != NS_SYNC) - goto reject_it; - req = 0; - } - - /* - * Check and apply new values. - */ - result = sym_sync_nego_check(np, req, cp); - if (result) /* Not acceptable, reject it */ - goto reject_it; - if (req) { /* Was a request, send response. */ - cp->nego_status = NS_SYNC; - OUTL_DSP(np, SCRIPTB_BA(np, sdtr_resp)); - } - else /* Was a response, we are done. */ - OUTL_DSP(np, SCRIPTA_BA(np, clrack)); - return; - -reject_it: - OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); -} - -/* - * chip handler for PARALLEL PROTOCOL REQUEST (PPR) message. - */ -static int -sym_ppr_nego_check(struct sym_hcb *np, int req, int target) -{ - struct sym_tcb *tp = &np->target[target]; - unsigned char fak, div; - int dt, chg = 0; - - unsigned char per = np->msgin[3]; - unsigned char ofs = np->msgin[5]; - unsigned char wide = np->msgin[6]; - unsigned char opts = np->msgin[7] & PPR_OPT_MASK; - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_nego_msg(np, target, "ppr msgin", np->msgin); - } - - /* - * Check values against our limits. - */ - if (wide > np->maxwide) { - chg = 1; - wide = np->maxwide; - } - if (!wide || !(np->features & FE_U3EN)) - opts = 0; - - if (opts != (np->msgin[7] & PPR_OPT_MASK)) - chg = 1; - - dt = opts & PPR_OPT_DT; - - if (ofs) { - unsigned char maxoffs = dt ? np->maxoffs_dt : np->maxoffs; - if (ofs > maxoffs) { - chg = 1; - ofs = maxoffs; - } - } - - if (ofs) { - unsigned char minsync = dt ? np->minsync_dt : np->minsync; - if (per < minsync) { - chg = 1; - per = minsync; - } - } - - /* - * Get new chip synchronous parameters value. - */ - div = fak = 0; - if (ofs && sym_getsync(np, dt, per, &div, &fak) < 0) - goto reject_it; - - /* - * If it was an answer we want to change, - * then it isn't acceptable. Reject it. - */ - if (!req && chg) - goto reject_it; - - /* - * Apply new values. - */ - sym_setpprot(np, target, opts, ofs, per, wide, div, fak); - - /* - * It was an answer. We are done. - */ - if (!req) - return 0; - - /* - * It was a request. Prepare an answer message. - */ - spi_populate_ppr_msg(np->msgout, per, ofs, wide, opts); - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_nego_msg(np, target, "ppr msgout", np->msgout); - } - - np->msgin [0] = M_NOOP; - - return 0; - -reject_it: - sym_setpprot (np, target, 0, 0, 0, 0, 0, 0); - /* - * If it is a device response that should result in - * ST, we may want to try a legacy negotiation later. - */ - if (!req && !opts) { - tp->tgoal.period = per; - tp->tgoal.offset = ofs; - tp->tgoal.width = wide; - tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; - tp->tgoal.check_nego = 1; - } - return -1; -} - -static void sym_ppr_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) -{ - int req = 1; - int result; - - /* - * Request or answer ? - */ - if (INB(np, HS_PRT) == HS_NEGOTIATE) { - OUTB(np, HS_PRT, HS_BUSY); - if (cp->nego_status && cp->nego_status != NS_PPR) - goto reject_it; - req = 0; - } - - /* - * Check and apply new values. - */ - result = sym_ppr_nego_check(np, req, cp->target); - if (result) /* Not acceptable, reject it */ - goto reject_it; - if (req) { /* Was a request, send response. */ - cp->nego_status = NS_PPR; - OUTL_DSP(np, SCRIPTB_BA(np, ppr_resp)); - } - else /* Was a response, we are done. */ - OUTL_DSP(np, SCRIPTA_BA(np, clrack)); - return; - -reject_it: - OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); -} - -/* - * chip handler for WIDE DATA TRANSFER REQUEST (WDTR) message. - */ -static int -sym_wide_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp) -{ - int target = cp->target; - u_char chg, wide; - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_nego_msg(np, target, "wide msgin", np->msgin); - } - - /* - * Get requested values. - */ - chg = 0; - wide = np->msgin[3]; - - /* - * Check values against our limits. - */ - if (wide > np->maxwide) { - chg = 1; - wide = np->maxwide; - } - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_addr(cp->cmd, "wdtr: wide=%d chg=%d.\n", - wide, chg); - } - - /* - * If it was an answer we want to change, - * then it isn't acceptable. Reject it. - */ - if (!req && chg) - goto reject_it; - - /* - * Apply new values. - */ - sym_setwide (np, target, wide); - - /* - * It was an answer. We are done. - */ - if (!req) - return 0; - - /* - * It was a request. Prepare an answer message. - */ - spi_populate_width_msg(np->msgout, wide); - - np->msgin [0] = M_NOOP; - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_nego_msg(np, target, "wide msgout", np->msgout); - } - - return 0; - -reject_it: - return -1; -} - -static void sym_wide_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) -{ - int req = 1; - int result; - - /* - * Request or answer ? - */ - if (INB(np, HS_PRT) == HS_NEGOTIATE) { - OUTB(np, HS_PRT, HS_BUSY); - if (cp->nego_status && cp->nego_status != NS_WIDE) - goto reject_it; - req = 0; - } - - /* - * Check and apply new values. - */ - result = sym_wide_nego_check(np, req, cp); - if (result) /* Not acceptable, reject it */ - goto reject_it; - if (req) { /* Was a request, send response. */ - cp->nego_status = NS_WIDE; - OUTL_DSP(np, SCRIPTB_BA(np, wdtr_resp)); - } else { /* Was a response. */ - /* - * Negotiate for SYNC immediately after WIDE response. - * This allows to negotiate for both WIDE and SYNC on - * a single SCSI command (Suggested by Justin Gibbs). - */ - if (tp->tgoal.offset) { - spi_populate_sync_msg(np->msgout, tp->tgoal.period, - tp->tgoal.offset); - - if (DEBUG_FLAGS & DEBUG_NEGO) { - sym_print_nego_msg(np, cp->target, - "sync msgout", np->msgout); - } - - cp->nego_status = NS_SYNC; - OUTB(np, HS_PRT, HS_NEGOTIATE); - OUTL_DSP(np, SCRIPTB_BA(np, sdtr_resp)); - return; - } else - OUTL_DSP(np, SCRIPTA_BA(np, clrack)); - } - - return; - -reject_it: - OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); -} - -/* - * Reset DT, SYNC or WIDE to default settings. - * - * Called when a negotiation does not succeed either - * on rejection or on protocol error. - * - * A target that understands a PPR message should never - * reject it, and messing with it is very unlikely. - * So, if a PPR makes problems, we may just want to - * try a legacy negotiation later. - */ -static void sym_nego_default(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) -{ - switch (cp->nego_status) { - case NS_PPR: -#if 0 - sym_setpprot (np, cp->target, 0, 0, 0, 0, 0, 0); -#else - if (tp->tgoal.period < np->minsync) - tp->tgoal.period = np->minsync; - if (tp->tgoal.offset > np->maxoffs) - tp->tgoal.offset = np->maxoffs; - tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; - tp->tgoal.check_nego = 1; -#endif - break; - case NS_SYNC: - sym_setsync (np, cp->target, 0, 0, 0, 0); - break; - case NS_WIDE: - sym_setwide (np, cp->target, 0); - break; - } - np->msgin [0] = M_NOOP; - np->msgout[0] = M_NOOP; - cp->nego_status = 0; -} - -/* - * chip handler for MESSAGE REJECT received in response to - * PPR, WIDE or SYNCHRONOUS negotiation. - */ -static void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) -{ - sym_nego_default(np, tp, cp); - OUTB(np, HS_PRT, HS_BUSY); -} - -/* - * chip exception handler for programmed interrupts. - */ -static void sym_int_sir(struct sym_hcb *np) -{ - u_char num = INB(np, nc_dsps); - u32 dsa = INL(np, nc_dsa); - struct sym_ccb *cp = sym_ccb_from_dsa(np, dsa); - u_char target = INB(np, nc_sdid) & 0x0f; - struct sym_tcb *tp = &np->target[target]; - int tmp; - - if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num); - - switch (num) { -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 - /* - * SCRIPTS tell us that we may have to update - * 64 bit DMA segment registers. - */ - case SIR_DMAP_DIRTY: - sym_update_dmap_regs(np); - goto out; -#endif - /* - * Command has been completed with error condition - * or has been auto-sensed. - */ - case SIR_COMPLETE_ERROR: - sym_complete_error(np, cp); - return; - /* - * The C code is currently trying to recover from something. - * Typically, user want to abort some command. - */ - case SIR_SCRIPT_STOPPED: - case SIR_TARGET_SELECTED: - case SIR_ABORT_SENT: - sym_sir_task_recovery(np, num); - return; - /* - * The device didn't go to MSG OUT phase after having - * been selected with ATN. We do not want to handle that. - */ - case SIR_SEL_ATN_NO_MSG_OUT: - scmd_printk(KERN_WARNING, cp->cmd, - "No MSG OUT phase after selection with ATN\n"); - goto out_stuck; - /* - * The device didn't switch to MSG IN phase after - * having reselected the initiator. - */ - case SIR_RESEL_NO_MSG_IN: - scmd_printk(KERN_WARNING, cp->cmd, - "No MSG IN phase after reselection\n"); - goto out_stuck; - /* - * After reselection, the device sent a message that wasn't - * an IDENTIFY. - */ - case SIR_RESEL_NO_IDENTIFY: - scmd_printk(KERN_WARNING, cp->cmd, - "No IDENTIFY after reselection\n"); - goto out_stuck; - /* - * The device reselected a LUN we do not know about. - */ - case SIR_RESEL_BAD_LUN: - np->msgout[0] = M_RESET; - goto out; - /* - * The device reselected for an untagged nexus and we - * haven't any. - */ - case SIR_RESEL_BAD_I_T_L: - np->msgout[0] = M_ABORT; - goto out; - /* - * The device reselected for a tagged nexus that we do not have. - */ - case SIR_RESEL_BAD_I_T_L_Q: - np->msgout[0] = M_ABORT_TAG; - goto out; - /* - * The SCRIPTS let us know that the device has grabbed - * our message and will abort the job. - */ - case SIR_RESEL_ABORTED: - np->lastmsg = np->msgout[0]; - np->msgout[0] = M_NOOP; - scmd_printk(KERN_WARNING, cp->cmd, - "message %x sent on bad reselection\n", np->lastmsg); - goto out; - /* - * The SCRIPTS let us know that a message has been - * successfully sent to the device. - */ - case SIR_MSG_OUT_DONE: - np->lastmsg = np->msgout[0]; - np->msgout[0] = M_NOOP; - /* Should we really care of that */ - if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) { - if (cp) { - cp->xerr_status &= ~XE_PARITY_ERR; - if (!cp->xerr_status) - OUTOFFB(np, HF_PRT, HF_EXT_ERR); - } - } - goto out; - /* - * The device didn't send a GOOD SCSI status. - * We may have some work to do prior to allow - * the SCRIPTS processor to continue. - */ - case SIR_BAD_SCSI_STATUS: - if (!cp) - goto out; - sym_sir_bad_scsi_status(np, num, cp); - return; - /* - * We are asked by the SCRIPTS to prepare a - * REJECT message. - */ - case SIR_REJECT_TO_SEND: - sym_print_msg(cp, "M_REJECT to send for ", np->msgin); - np->msgout[0] = M_REJECT; - goto out; - /* - * We have been ODD at the end of a DATA IN - * transfer and the device didn't send a - * IGNORE WIDE RESIDUE message. - * It is a data overrun condition. - */ - case SIR_SWIDE_OVERRUN: - if (cp) { - OUTONB(np, HF_PRT, HF_EXT_ERR); - cp->xerr_status |= XE_SWIDE_OVRUN; - } - goto out; - /* - * We have been ODD at the end of a DATA OUT - * transfer. - * It is a data underrun condition. - */ - case SIR_SODL_UNDERRUN: - if (cp) { - OUTONB(np, HF_PRT, HF_EXT_ERR); - cp->xerr_status |= XE_SODL_UNRUN; - } - goto out; - /* - * The device wants us to tranfer more data than - * expected or in the wrong direction. - * The number of extra bytes is in scratcha. - * It is a data overrun condition. - */ - case SIR_DATA_OVERRUN: - if (cp) { - OUTONB(np, HF_PRT, HF_EXT_ERR); - cp->xerr_status |= XE_EXTRA_DATA; - cp->extra_bytes += INL(np, nc_scratcha); - } - goto out; - /* - * The device switched to an illegal phase (4/5). - */ - case SIR_BAD_PHASE: - if (cp) { - OUTONB(np, HF_PRT, HF_EXT_ERR); - cp->xerr_status |= XE_BAD_PHASE; - } - goto out; - /* - * We received a message. - */ - case SIR_MSG_RECEIVED: - if (!cp) - goto out_stuck; - switch (np->msgin [0]) { - /* - * We received an extended message. - * We handle MODIFY DATA POINTER, SDTR, WDTR - * and reject all other extended messages. - */ - case M_EXTENDED: - switch (np->msgin [2]) { - case M_X_MODIFY_DP: - if (DEBUG_FLAGS & DEBUG_POINTER) - sym_print_msg(cp, "extended msg ", - np->msgin); - tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + - (np->msgin[5]<<8) + (np->msgin[6]); - sym_modify_dp(np, tp, cp, tmp); - return; - case M_X_SYNC_REQ: - sym_sync_nego(np, tp, cp); - return; - case M_X_PPR_REQ: - sym_ppr_nego(np, tp, cp); - return; - case M_X_WIDE_REQ: - sym_wide_nego(np, tp, cp); - return; - default: - goto out_reject; - } - break; - /* - * We received a 1/2 byte message not handled from SCRIPTS. - * We are only expecting MESSAGE REJECT and IGNORE WIDE - * RESIDUE messages that haven't been anticipated by - * SCRIPTS on SWIDE full condition. Unanticipated IGNORE - * WIDE RESIDUE messages are aliased as MODIFY DP (-1). - */ - case M_IGN_RESIDUE: - if (DEBUG_FLAGS & DEBUG_POINTER) - sym_print_msg(cp, "1 or 2 byte ", np->msgin); - if (cp->host_flags & HF_SENSE) - OUTL_DSP(np, SCRIPTA_BA(np, clrack)); - else - sym_modify_dp(np, tp, cp, -1); - return; - case M_REJECT: - if (INB(np, HS_PRT) == HS_NEGOTIATE) - sym_nego_rejected(np, tp, cp); - else { - sym_print_addr(cp->cmd, - "M_REJECT received (%x:%x).\n", - scr_to_cpu(np->lastmsg), np->msgout[0]); - } - goto out_clrack; - break; - default: - goto out_reject; - } - break; - /* - * We received an unknown message. - * Ignore all MSG IN phases and reject it. - */ - case SIR_MSG_WEIRD: - sym_print_msg(cp, "WEIRD message received", np->msgin); - OUTL_DSP(np, SCRIPTB_BA(np, msg_weird)); - return; - /* - * Negotiation failed. - * Target does not send us the reply. - * Remove the HS_NEGOTIATE status. - */ - case SIR_NEGO_FAILED: - OUTB(np, HS_PRT, HS_BUSY); - /* - * Negotiation failed. - * Target does not want answer message. - */ - case SIR_NEGO_PROTO: - sym_nego_default(np, tp, cp); - goto out; - } - -out: - OUTONB_STD(); - return; -out_reject: - OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); - return; -out_clrack: - OUTL_DSP(np, SCRIPTA_BA(np, clrack)); - return; -out_stuck: - return; -} - -/* - * Acquire a control block - */ -struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order) -{ - u_char tn = cmd->device->id; - u_char ln = cmd->device->lun; - struct sym_tcb *tp = &np->target[tn]; - struct sym_lcb *lp = sym_lp(tp, ln); - u_short tag = NO_TAG; - SYM_QUEHEAD *qp; - struct sym_ccb *cp = NULL; - - /* - * Look for a free CCB - */ - if (sym_que_empty(&np->free_ccbq)) - sym_alloc_ccb(np); - qp = sym_remque_head(&np->free_ccbq); - if (!qp) - goto out; - cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); - - { - /* - * If we have been asked for a tagged command. - */ - if (tag_order) { - /* - * Debugging purpose. - */ -#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - if (lp->busy_itl != 0) - goto out_free; -#endif - /* - * Allocate resources for tags if not yet. - */ - if (!lp->cb_tags) { - sym_alloc_lcb_tags(np, tn, ln); - if (!lp->cb_tags) - goto out_free; - } - /* - * Get a tag for this SCSI IO and set up - * the CCB bus address for reselection, - * and count it for this LUN. - * Toggle reselect path to tagged. - */ - if (lp->busy_itlq < SYM_CONF_MAX_TASK) { - tag = lp->cb_tags[lp->ia_tag]; - if (++lp->ia_tag == SYM_CONF_MAX_TASK) - lp->ia_tag = 0; - ++lp->busy_itlq; -#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - lp->itlq_tbl[tag] = cpu_to_scr(cp->ccb_ba); - lp->head.resel_sa = - cpu_to_scr(SCRIPTA_BA(np, resel_tag)); -#endif -#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING - cp->tags_si = lp->tags_si; - ++lp->tags_sum[cp->tags_si]; - ++lp->tags_since; -#endif - } - else - goto out_free; - } - /* - * This command will not be tagged. - * If we already have either a tagged or untagged - * one, refuse to overlap this untagged one. - */ - else { - /* - * Debugging purpose. - */ -#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - if (lp->busy_itl != 0 || lp->busy_itlq != 0) - goto out_free; -#endif - /* - * Count this nexus for this LUN. - * Set up the CCB bus address for reselection. - * Toggle reselect path to untagged. - */ - ++lp->busy_itl; -#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - if (lp->busy_itl == 1) { - lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba); - lp->head.resel_sa = - cpu_to_scr(SCRIPTA_BA(np, resel_no_tag)); - } - else - goto out_free; -#endif - } - } - /* - * Put the CCB into the busy queue. - */ - sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - if (lp) { - sym_remque(&cp->link2_ccbq); - sym_insque_tail(&cp->link2_ccbq, &lp->waiting_ccbq); - } - -#endif - cp->to_abort = 0; - cp->odd_byte_adjustment = 0; - cp->tag = tag; - cp->order = tag_order; - cp->target = tn; - cp->lun = ln; - - if (DEBUG_FLAGS & DEBUG_TAGS) { - sym_print_addr(cmd, "ccb @%p using tag %d.\n", cp, tag); - } - -out: - return cp; -out_free: - sym_insque_head(&cp->link_ccbq, &np->free_ccbq); - return NULL; -} - -/* - * Release one control block - */ -void sym_free_ccb (struct sym_hcb *np, struct sym_ccb *cp) -{ - struct sym_tcb *tp = &np->target[cp->target]; - struct sym_lcb *lp = sym_lp(tp, cp->lun); - - if (DEBUG_FLAGS & DEBUG_TAGS) { - sym_print_addr(cp->cmd, "ccb @%p freeing tag %d.\n", - cp, cp->tag); - } - - /* - * If LCB available, - */ - if (lp) { - /* - * If tagged, release the tag, set the relect path - */ - if (cp->tag != NO_TAG) { -#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING - --lp->tags_sum[cp->tags_si]; -#endif - /* - * Free the tag value. - */ - lp->cb_tags[lp->if_tag] = cp->tag; - if (++lp->if_tag == SYM_CONF_MAX_TASK) - lp->if_tag = 0; - /* - * Make the reselect path invalid, - * and uncount this CCB. - */ - lp->itlq_tbl[cp->tag] = cpu_to_scr(np->bad_itlq_ba); - --lp->busy_itlq; - } else { /* Untagged */ - /* - * Make the reselect path invalid, - * and uncount this CCB. - */ - lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba); - --lp->busy_itl; - } - /* - * If no JOB active, make the LUN reselect path invalid. - */ - if (lp->busy_itlq == 0 && lp->busy_itl == 0) - lp->head.resel_sa = - cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun)); - } - - /* - * We donnot queue more than 1 ccb per target - * with negotiation at any time. If this ccb was - * used for negotiation, clear this info in the tcb. - */ - if (cp == tp->nego_cp) - tp->nego_cp = NULL; - -#ifdef SYM_CONF_IARB_SUPPORT - /* - * If we just complete the last queued CCB, - * clear this info that is no longer relevant. - */ - if (cp == np->last_cp) - np->last_cp = 0; -#endif - - /* - * Make this CCB available. - */ - cp->cmd = NULL; - cp->host_status = HS_IDLE; - sym_remque(&cp->link_ccbq); - sym_insque_head(&cp->link_ccbq, &np->free_ccbq); - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - if (lp) { - sym_remque(&cp->link2_ccbq); - sym_insque_tail(&cp->link2_ccbq, &np->dummy_ccbq); - if (cp->started) { - if (cp->tag != NO_TAG) - --lp->started_tags; - else - --lp->started_no_tag; - } - } - cp->started = 0; -#endif -} - -/* - * Allocate a CCB from memory and initialize its fixed part. - */ -static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np) -{ - struct sym_ccb *cp = NULL; - int hcode; - - /* - * Prevent from allocating more CCBs than we can - * queue to the controller. - */ - if (np->actccbs >= SYM_CONF_MAX_START) - return NULL; - - /* - * Allocate memory for this CCB. - */ - cp = sym_calloc_dma(sizeof(struct sym_ccb), "CCB"); - if (!cp) - goto out_free; - - /* - * Count it. - */ - np->actccbs++; - - /* - * Compute the bus address of this ccb. - */ - cp->ccb_ba = vtobus(cp); - - /* - * Insert this ccb into the hashed list. - */ - hcode = CCB_HASH_CODE(cp->ccb_ba); - cp->link_ccbh = np->ccbh[hcode]; - np->ccbh[hcode] = cp; - - /* - * Initialyze the start and restart actions. - */ - cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA(np, idle)); - cp->phys.head.go.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l)); - - /* - * Initilialyze some other fields. - */ - cp->phys.smsg_ext.addr = cpu_to_scr(HCB_BA(np, msgin[2])); - - /* - * Chain into free ccb queue. - */ - sym_insque_head(&cp->link_ccbq, &np->free_ccbq); - - /* - * Chain into optionnal lists. - */ -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - sym_insque_head(&cp->link2_ccbq, &np->dummy_ccbq); -#endif - return cp; -out_free: - if (cp) - sym_mfree_dma(cp, sizeof(*cp), "CCB"); - return NULL; -} - -/* - * Look up a CCB from a DSA value. - */ -static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa) -{ - int hcode; - struct sym_ccb *cp; - - hcode = CCB_HASH_CODE(dsa); - cp = np->ccbh[hcode]; - while (cp) { - if (cp->ccb_ba == dsa) - break; - cp = cp->link_ccbh; - } - - return cp; -} - -/* - * Target control block initialisation. - * Nothing important to do at the moment. - */ -static void sym_init_tcb (struct sym_hcb *np, u_char tn) -{ -#if 0 /* Hmmm... this checking looks paranoid. */ - /* - * Check some alignments required by the chip. - */ - assert (((offsetof(struct sym_reg, nc_sxfer) ^ - offsetof(struct sym_tcb, head.sval)) &3) == 0); - assert (((offsetof(struct sym_reg, nc_scntl3) ^ - offsetof(struct sym_tcb, head.wval)) &3) == 0); -#endif -} - -/* - * Lun control block allocation and initialization. - */ -struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln) -{ - struct sym_tcb *tp = &np->target[tn]; - struct sym_lcb *lp = NULL; - - /* - * Initialize the target control block if not yet. - */ - sym_init_tcb (np, tn); - - /* - * Allocate the LCB bus address array. - * Compute the bus address of this table. - */ - if (ln && !tp->luntbl) { - int i; - - tp->luntbl = sym_calloc_dma(256, "LUNTBL"); - if (!tp->luntbl) - goto fail; - for (i = 0 ; i < 64 ; i++) - tp->luntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa)); - tp->head.luntbl_sa = cpu_to_scr(vtobus(tp->luntbl)); - } - - /* - * Allocate the table of pointers for LUN(s) > 0, if needed. - */ - if (ln && !tp->lunmp) { - tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *), - GFP_ATOMIC); - if (!tp->lunmp) - goto fail; - } - - /* - * Allocate the lcb. - * Make it available to the chip. - */ - lp = sym_calloc_dma(sizeof(struct sym_lcb), "LCB"); - if (!lp) - goto fail; - if (ln) { - tp->lunmp[ln] = lp; - tp->luntbl[ln] = cpu_to_scr(vtobus(lp)); - } - else { - tp->lun0p = lp; - tp->head.lun0_sa = cpu_to_scr(vtobus(lp)); - } - tp->nlcb++; - - /* - * Let the itl task point to error handling. - */ - lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba); - - /* - * Set the reselect pattern to our default. :) - */ - lp->head.resel_sa = cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun)); - - /* - * Set user capabilities. - */ - lp->user_flags = tp->usrflags & (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - /* - * Initialize device queueing. - */ - sym_que_init(&lp->waiting_ccbq); - sym_que_init(&lp->started_ccbq); - lp->started_max = SYM_CONF_MAX_TASK; - lp->started_limit = SYM_CONF_MAX_TASK; -#endif - -fail: - return lp; -} - -/* - * Allocate LCB resources for tagged command queuing. - */ -static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln) -{ - struct sym_tcb *tp = &np->target[tn]; - struct sym_lcb *lp = sym_lp(tp, ln); - int i; - - /* - * Allocate the task table and and the tag allocation - * circular buffer. We want both or none. - */ - lp->itlq_tbl = sym_calloc_dma(SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); - if (!lp->itlq_tbl) - goto fail; - lp->cb_tags = kcalloc(SYM_CONF_MAX_TASK, 1, GFP_ATOMIC); - if (!lp->cb_tags) { - sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); - lp->itlq_tbl = NULL; - goto fail; - } - - /* - * Initialize the task table with invalid entries. - */ - for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++) - lp->itlq_tbl[i] = cpu_to_scr(np->notask_ba); - - /* - * Fill up the tag buffer with tag numbers. - */ - for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++) - lp->cb_tags[i] = i; - - /* - * Make the task table available to SCRIPTS, - * And accept tagged commands now. - */ - lp->head.itlq_tbl_sa = cpu_to_scr(vtobus(lp->itlq_tbl)); - - return; -fail: - return; -} - -/* - * Lun control block deallocation. Returns the number of valid remaining LCBs - * for the target. - */ -int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln) -{ - struct sym_tcb *tp = &np->target[tn]; - struct sym_lcb *lp = sym_lp(tp, ln); - - tp->nlcb--; - - if (ln) { - if (!tp->nlcb) { - kfree(tp->lunmp); - sym_mfree_dma(tp->luntbl, 256, "LUNTBL"); - tp->lunmp = NULL; - tp->luntbl = NULL; - tp->head.luntbl_sa = cpu_to_scr(vtobus(np->badluntbl)); - } else { - tp->luntbl[ln] = cpu_to_scr(vtobus(&np->badlun_sa)); - tp->lunmp[ln] = NULL; - } - } else { - tp->lun0p = NULL; - tp->head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa)); - } - - if (lp->itlq_tbl) { - sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); - kfree(lp->cb_tags); - } - - sym_mfree_dma(lp, sizeof(*lp), "LCB"); - - return tp->nlcb; -} - -/* - * Queue a SCSI IO to the controller. - */ -int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) -{ - struct scsi_device *sdev = cmd->device; - struct sym_tcb *tp; - struct sym_lcb *lp; - u_char *msgptr; - u_int msglen; - int can_disconnect; - - /* - * Keep track of the IO in our CCB. - */ - cp->cmd = cmd; - - /* - * Retrieve the target descriptor. - */ - tp = &np->target[cp->target]; - - /* - * Retrieve the lun descriptor. - */ - lp = sym_lp(tp, sdev->lun); - - can_disconnect = (cp->tag != NO_TAG) || - (lp && (lp->curr_flags & SYM_DISC_ENABLED)); - - msgptr = cp->scsi_smsg; - msglen = 0; - msgptr[msglen++] = IDENTIFY(can_disconnect, sdev->lun); - - /* - * Build the tag message if present. - */ - if (cp->tag != NO_TAG) { - u_char order = cp->order; - - switch(order) { - case M_ORDERED_TAG: - break; - case M_HEAD_TAG: - break; - default: - order = M_SIMPLE_TAG; - } -#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING - /* - * Avoid too much reordering of SCSI commands. - * The algorithm tries to prevent completion of any - * tagged command from being delayed against more - * than 3 times the max number of queued commands. - */ - if (lp && lp->tags_since > 3*SYM_CONF_MAX_TAG) { - lp->tags_si = !(lp->tags_si); - if (lp->tags_sum[lp->tags_si]) { - order = M_ORDERED_TAG; - if ((DEBUG_FLAGS & DEBUG_TAGS)||sym_verbose>1) { - sym_print_addr(cmd, - "ordered tag forced.\n"); - } - } - lp->tags_since = 0; - } -#endif - msgptr[msglen++] = order; - - /* - * For less than 128 tags, actual tags are numbered - * 1,3,5,..2*MAXTAGS+1,since we may have to deal - * with devices that have problems with #TAG 0 or too - * great #TAG numbers. For more tags (up to 256), - * we use directly our tag number. - */ -#if SYM_CONF_MAX_TASK > (512/4) - msgptr[msglen++] = cp->tag; -#else - msgptr[msglen++] = (cp->tag << 1) + 1; -#endif - } - - /* - * Build a negotiation message if needed. - * (nego_status is filled by sym_prepare_nego()) - * - * Always negotiate on INQUIRY and REQUEST SENSE. - * - */ - cp->nego_status = 0; - if ((tp->tgoal.check_nego || - cmd->cmnd[0] == INQUIRY || cmd->cmnd[0] == REQUEST_SENSE) && - !tp->nego_cp && lp) { - msglen += sym_prepare_nego(np, cp, msgptr + msglen); - } - - /* - * Startqueue - */ - cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA(np, select)); - cp->phys.head.go.restart = cpu_to_scr(SCRIPTA_BA(np, resel_dsa)); - - /* - * select - */ - cp->phys.select.sel_id = cp->target; - cp->phys.select.sel_scntl3 = tp->head.wval; - cp->phys.select.sel_sxfer = tp->head.sval; - cp->phys.select.sel_scntl4 = tp->head.uval; - - /* - * message - */ - cp->phys.smsg.addr = CCB_BA(cp, scsi_smsg); - cp->phys.smsg.size = cpu_to_scr(msglen); - - /* - * status - */ - cp->host_xflags = 0; - cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; - cp->ssss_status = S_ILLEGAL; - cp->xerr_status = 0; - cp->host_flags = 0; - cp->extra_bytes = 0; - - /* - * extreme data pointer. - * shall be positive, so -1 is lower than lowest.:) - */ - cp->ext_sg = -1; - cp->ext_ofs = 0; - - /* - * Build the CDB and DATA descriptor block - * and start the IO. - */ - return sym_setup_data_and_start(np, cmd, cp); -} - -/* - * Reset a SCSI target (all LUNs of this target). - */ -int sym_reset_scsi_target(struct sym_hcb *np, int target) -{ - struct sym_tcb *tp; - - if (target == np->myaddr || (u_int)target >= SYM_CONF_MAX_TARGET) - return -1; - - tp = &np->target[target]; - tp->to_reset = 1; - - np->istat_sem = SEM; - OUTB(np, nc_istat, SIGP|SEM); - - return 0; -} - -/* - * Abort a SCSI IO. - */ -static int sym_abort_ccb(struct sym_hcb *np, struct sym_ccb *cp, int timed_out) -{ - /* - * Check that the IO is active. - */ - if (!cp || !cp->host_status || cp->host_status == HS_WAIT) - return -1; - - /* - * If a previous abort didn't succeed in time, - * perform a BUS reset. - */ - if (cp->to_abort) { - sym_reset_scsi_bus(np, 1); - return 0; - } - - /* - * Mark the CCB for abort and allow time for. - */ - cp->to_abort = timed_out ? 2 : 1; - - /* - * Tell the SCRIPTS processor to stop and synchronize with us. - */ - np->istat_sem = SEM; - OUTB(np, nc_istat, SIGP|SEM); - return 0; -} - -int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, int timed_out) -{ - struct sym_ccb *cp; - SYM_QUEHEAD *qp; - - /* - * Look up our CCB control block. - */ - cp = NULL; - FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { - struct sym_ccb *cp2 = sym_que_entry(qp, struct sym_ccb, link_ccbq); - if (cp2->cmd == cmd) { - cp = cp2; - break; - } - } - - return sym_abort_ccb(np, cp, timed_out); -} - -/* - * Complete execution of a SCSI command with extended - * error, SCSI status error, or having been auto-sensed. - * - * The SCRIPTS processor is not running there, so we - * can safely access IO registers and remove JOBs from - * the START queue. - * SCRATCHA is assumed to have been loaded with STARTPOS - * before the SCRIPTS called the C code. - */ -void sym_complete_error(struct sym_hcb *np, struct sym_ccb *cp) -{ - struct scsi_device *sdev; - struct scsi_cmnd *cmd; - struct sym_tcb *tp; - struct sym_lcb *lp; - int resid; - int i; - - /* - * Paranoid check. :) - */ - if (!cp || !cp->cmd) - return; - - cmd = cp->cmd; - sdev = cmd->device; - if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_RESULT)) { - dev_info(&sdev->sdev_gendev, "CCB=%p STAT=%x/%x/%x\n", cp, - cp->host_status, cp->ssss_status, cp->host_flags); - } - - /* - * Get target and lun pointers. - */ - tp = &np->target[cp->target]; - lp = sym_lp(tp, sdev->lun); - - /* - * Check for extended errors. - */ - if (cp->xerr_status) { - if (sym_verbose) - sym_print_xerr(cmd, cp->xerr_status); - if (cp->host_status == HS_COMPLETE) - cp->host_status = HS_COMP_ERR; - } - - /* - * Calculate the residual. - */ - resid = sym_compute_residual(np, cp); - - if (!SYM_SETUP_RESIDUAL_SUPPORT) {/* If user does not want residuals */ - resid = 0; /* throw them away. :) */ - cp->sv_resid = 0; - } -#ifdef DEBUG_2_0_X -if (resid) - printf("XXXX RESID= %d - 0x%x\n", resid, resid); -#endif - - /* - * Dequeue all queued CCBs for that device - * not yet started by SCRIPTS. - */ - i = (INL(np, nc_scratcha) - np->squeue_ba) / 4; - i = sym_dequeue_from_squeue(np, i, cp->target, sdev->lun, -1); - - /* - * Restart the SCRIPTS processor. - */ - OUTL_DSP(np, SCRIPTA_BA(np, start)); - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - if (cp->host_status == HS_COMPLETE && - cp->ssss_status == S_QUEUE_FULL) { - if (!lp || lp->started_tags - i < 2) - goto weirdness; - /* - * Decrease queue depth as needed. - */ - lp->started_max = lp->started_tags - i - 1; - lp->num_sgood = 0; - - if (sym_verbose >= 2) { - sym_print_addr(cmd, " queue depth is now %d\n", - lp->started_max); - } - - /* - * Repair the CCB. - */ - cp->host_status = HS_BUSY; - cp->ssss_status = S_ILLEGAL; - - /* - * Let's requeue it to device. - */ - sym_set_cam_status(cmd, DID_SOFT_ERROR); - goto finish; - } -weirdness: -#endif - /* - * Build result in CAM ccb. - */ - sym_set_cam_result_error(np, cp, resid); - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING -finish: -#endif - /* - * Add this one to the COMP queue. - */ - sym_remque(&cp->link_ccbq); - sym_insque_head(&cp->link_ccbq, &np->comp_ccbq); - - /* - * Complete all those commands with either error - * or requeue condition. - */ - sym_flush_comp_queue(np, 0); - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - /* - * Donnot start more than 1 command after an error. - */ - sym_start_next_ccbs(np, lp, 1); -#endif -} - -/* - * Complete execution of a successful SCSI command. - * - * Only successful commands go to the DONE queue, - * since we need to have the SCRIPTS processor - * stopped on any error condition. - * The SCRIPTS processor is running while we are - * completing successful commands. - */ -void sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp) -{ - struct sym_tcb *tp; - struct sym_lcb *lp; - struct scsi_cmnd *cmd; - int resid; - - /* - * Paranoid check. :) - */ - if (!cp || !cp->cmd) - return; - assert (cp->host_status == HS_COMPLETE); - - /* - * Get user command. - */ - cmd = cp->cmd; - - /* - * Get target and lun pointers. - */ - tp = &np->target[cp->target]; - lp = sym_lp(tp, cp->lun); - - /* - * If all data have been transferred, given than no - * extended error did occur, there is no residual. - */ - resid = 0; - if (cp->phys.head.lastp != cp->goalp) - resid = sym_compute_residual(np, cp); - - /* - * Wrong transfer residuals may be worse than just always - * returning zero. User can disable this feature in - * sym53c8xx.h. Residual support is enabled by default. - */ - if (!SYM_SETUP_RESIDUAL_SUPPORT) - resid = 0; -#ifdef DEBUG_2_0_X -if (resid) - printf("XXXX RESID= %d - 0x%x\n", resid, resid); -#endif - - /* - * Build result in CAM ccb. - */ - sym_set_cam_result_ok(cp, cmd, resid); - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - /* - * If max number of started ccbs had been reduced, - * increase it if 200 good status received. - */ - if (lp && lp->started_max < lp->started_limit) { - ++lp->num_sgood; - if (lp->num_sgood >= 200) { - lp->num_sgood = 0; - ++lp->started_max; - if (sym_verbose >= 2) { - sym_print_addr(cmd, " queue depth is now %d\n", - lp->started_max); - } - } - } -#endif - - /* - * Free our CCB. - */ - sym_free_ccb (np, cp); - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - /* - * Requeue a couple of awaiting scsi commands. - */ - if (!sym_que_empty(&lp->waiting_ccbq)) - sym_start_next_ccbs(np, lp, 2); -#endif - /* - * Complete the command. - */ - sym_xpt_done(np, cmd); -} - -/* - * Soft-attach the controller. - */ -int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram *nvram) -{ - struct sym_hcb *np = sym_get_hcb(shost); - int i; - - /* - * Get some info about the firmware. - */ - np->scripta_sz = fw->a_size; - np->scriptb_sz = fw->b_size; - np->scriptz_sz = fw->z_size; - np->fw_setup = fw->setup; - np->fw_patch = fw->patch; - np->fw_name = fw->name; - - /* - * Save setting of some IO registers, so we will - * be able to probe specific implementations. - */ - sym_save_initial_setting (np); - - /* - * Reset the chip now, since it has been reported - * that SCSI clock calibration may not work properly - * if the chip is currently active. - */ - sym_chip_reset(np); - - /* - * Prepare controller and devices settings, according - * to chip features, user set-up and driver set-up. - */ - sym_prepare_setting(shost, np, nvram); - - /* - * Check the PCI clock frequency. - * Must be performed after prepare_setting since it destroys - * STEST1 that is used to probe for the clock doubler. - */ - i = sym_getpciclock(np); - if (i > 37000 && !(np->features & FE_66MHZ)) - printf("%s: PCI BUS clock seems too high: %u KHz.\n", - sym_name(np), i); - - /* - * Allocate the start queue. - */ - np->squeue = sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"SQUEUE"); - if (!np->squeue) - goto attach_failed; - np->squeue_ba = vtobus(np->squeue); - - /* - * Allocate the done queue. - */ - np->dqueue = sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"DQUEUE"); - if (!np->dqueue) - goto attach_failed; - np->dqueue_ba = vtobus(np->dqueue); - - /* - * Allocate the target bus address array. - */ - np->targtbl = sym_calloc_dma(256, "TARGTBL"); - if (!np->targtbl) - goto attach_failed; - np->targtbl_ba = vtobus(np->targtbl); - - /* - * Allocate SCRIPTS areas. - */ - np->scripta0 = sym_calloc_dma(np->scripta_sz, "SCRIPTA0"); - np->scriptb0 = sym_calloc_dma(np->scriptb_sz, "SCRIPTB0"); - np->scriptz0 = sym_calloc_dma(np->scriptz_sz, "SCRIPTZ0"); - if (!np->scripta0 || !np->scriptb0 || !np->scriptz0) - goto attach_failed; - - /* - * Allocate the array of lists of CCBs hashed by DSA. - */ - np->ccbh = kcalloc(CCB_HASH_SIZE, sizeof(struct sym_ccb **), GFP_KERNEL); - if (!np->ccbh) - goto attach_failed; - - /* - * Initialyze the CCB free and busy queues. - */ - sym_que_init(&np->free_ccbq); - sym_que_init(&np->busy_ccbq); - sym_que_init(&np->comp_ccbq); - - /* - * Initialization for optional handling - * of device queueing. - */ -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - sym_que_init(&np->dummy_ccbq); -#endif - /* - * Allocate some CCB. We need at least ONE. - */ - if (!sym_alloc_ccb(np)) - goto attach_failed; - - /* - * Calculate BUS addresses where we are going - * to load the SCRIPTS. - */ - np->scripta_ba = vtobus(np->scripta0); - np->scriptb_ba = vtobus(np->scriptb0); - np->scriptz_ba = vtobus(np->scriptz0); - - if (np->ram_ba) { - np->scripta_ba = np->ram_ba; - if (np->features & FE_RAM8K) { - np->scriptb_ba = np->scripta_ba + 4096; -#if 0 /* May get useful for 64 BIT PCI addressing */ - np->scr_ram_seg = cpu_to_scr(np->scripta_ba >> 32); -#endif - } - } - - /* - * Copy scripts to controller instance. - */ - memcpy(np->scripta0, fw->a_base, np->scripta_sz); - memcpy(np->scriptb0, fw->b_base, np->scriptb_sz); - memcpy(np->scriptz0, fw->z_base, np->scriptz_sz); - - /* - * Setup variable parts in scripts and compute - * scripts bus addresses used from the C code. - */ - np->fw_setup(np, fw); - - /* - * Bind SCRIPTS with physical addresses usable by the - * SCRIPTS processor (as seen from the BUS = BUS addresses). - */ - sym_fw_bind_script(np, (u32 *) np->scripta0, np->scripta_sz); - sym_fw_bind_script(np, (u32 *) np->scriptb0, np->scriptb_sz); - sym_fw_bind_script(np, (u32 *) np->scriptz0, np->scriptz_sz); - -#ifdef SYM_CONF_IARB_SUPPORT - /* - * If user wants IARB to be set when we win arbitration - * and have other jobs, compute the max number of consecutive - * settings of IARB hints before we leave devices a chance to - * arbitrate for reselection. - */ -#ifdef SYM_SETUP_IARB_MAX - np->iarb_max = SYM_SETUP_IARB_MAX; -#else - np->iarb_max = 4; -#endif -#endif - - /* - * Prepare the idle and invalid task actions. - */ - np->idletask.start = cpu_to_scr(SCRIPTA_BA(np, idle)); - np->idletask.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l)); - np->idletask_ba = vtobus(&np->idletask); - - np->notask.start = cpu_to_scr(SCRIPTA_BA(np, idle)); - np->notask.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l)); - np->notask_ba = vtobus(&np->notask); - - np->bad_itl.start = cpu_to_scr(SCRIPTA_BA(np, idle)); - np->bad_itl.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l)); - np->bad_itl_ba = vtobus(&np->bad_itl); - - np->bad_itlq.start = cpu_to_scr(SCRIPTA_BA(np, idle)); - np->bad_itlq.restart = cpu_to_scr(SCRIPTB_BA(np,bad_i_t_l_q)); - np->bad_itlq_ba = vtobus(&np->bad_itlq); - - /* - * Allocate and prepare the lun JUMP table that is used - * for a target prior the probing of devices (bad lun table). - * A private table will be allocated for the target on the - * first INQUIRY response received. - */ - np->badluntbl = sym_calloc_dma(256, "BADLUNTBL"); - if (!np->badluntbl) - goto attach_failed; - - np->badlun_sa = cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun)); - for (i = 0 ; i < 64 ; i++) /* 64 luns/target, no less */ - np->badluntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa)); - - /* - * Prepare the bus address array that contains the bus - * address of each target control block. - * For now, assume all logical units are wrong. :) - */ - for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { - np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i])); - np->target[i].head.luntbl_sa = - cpu_to_scr(vtobus(np->badluntbl)); - np->target[i].head.lun0_sa = - cpu_to_scr(vtobus(&np->badlun_sa)); - } - - /* - * Now check the cache handling of the pci chipset. - */ - if (sym_snooptest (np)) { - printf("%s: CACHE INCORRECTLY CONFIGURED.\n", sym_name(np)); - goto attach_failed; - } - - /* - * Sigh! we are done. - */ - return 0; - -attach_failed: - return -ENXIO; -} - -/* - * Free everything that has been allocated for this device. - */ -void sym_hcb_free(struct sym_hcb *np) -{ - SYM_QUEHEAD *qp; - struct sym_ccb *cp; - struct sym_tcb *tp; - int target; - - if (np->scriptz0) - sym_mfree_dma(np->scriptz0, np->scriptz_sz, "SCRIPTZ0"); - if (np->scriptb0) - sym_mfree_dma(np->scriptb0, np->scriptb_sz, "SCRIPTB0"); - if (np->scripta0) - sym_mfree_dma(np->scripta0, np->scripta_sz, "SCRIPTA0"); - if (np->squeue) - sym_mfree_dma(np->squeue, sizeof(u32)*(MAX_QUEUE*2), "SQUEUE"); - if (np->dqueue) - sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE"); - - if (np->actccbs) { - while ((qp = sym_remque_head(&np->free_ccbq)) != NULL) { - cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); - sym_mfree_dma(cp, sizeof(*cp), "CCB"); - } - } - kfree(np->ccbh); - - if (np->badluntbl) - sym_mfree_dma(np->badluntbl, 256,"BADLUNTBL"); - - for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) { - tp = &np->target[target]; - if (tp->luntbl) - sym_mfree_dma(tp->luntbl, 256, "LUNTBL"); -#if SYM_CONF_MAX_LUN > 1 - kfree(tp->lunmp); -#endif - } - if (np->targtbl) - sym_mfree_dma(np->targtbl, 256, "TARGTBL"); -} diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.h deleted file mode 100644 index 5a80cbac..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_hipd.h +++ /dev/null @@ -1,1226 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include - -#ifndef SYM_HIPD_H -#define SYM_HIPD_H - -/* - * Generic driver options. - * - * They may be defined in platform specific headers, if they - * are useful. - * - * SYM_OPT_HANDLE_DEVICE_QUEUEING - * When this option is set, the driver will use a queue per - * device and handle QUEUE FULL status requeuing internally. - * - * SYM_OPT_LIMIT_COMMAND_REORDERING - * When this option is set, the driver tries to limit tagged - * command reordering to some reasonable value. - * (set for Linux) - */ -#if 0 -#define SYM_OPT_HANDLE_DEVICE_QUEUEING -#define SYM_OPT_LIMIT_COMMAND_REORDERING -#endif - -/* - * Active debugging tags and verbosity. - * Both DEBUG_FLAGS and sym_verbose can be redefined - * by the platform specific code to something else. - */ -#define DEBUG_ALLOC (0x0001) -#define DEBUG_PHASE (0x0002) -#define DEBUG_POLL (0x0004) -#define DEBUG_QUEUE (0x0008) -#define DEBUG_RESULT (0x0010) -#define DEBUG_SCATTER (0x0020) -#define DEBUG_SCRIPT (0x0040) -#define DEBUG_TINY (0x0080) -#define DEBUG_TIMING (0x0100) -#define DEBUG_NEGO (0x0200) -#define DEBUG_TAGS (0x0400) -#define DEBUG_POINTER (0x0800) - -#ifndef DEBUG_FLAGS -#define DEBUG_FLAGS (0x0000) -#endif - -#ifndef sym_verbose -#define sym_verbose (np->verbose) -#endif - -/* - * These ones should have been already defined. - */ -#ifndef assert -#define assert(expression) { \ - if (!(expression)) { \ - (void)panic( \ - "assertion \"%s\" failed: file \"%s\", line %d\n", \ - #expression, \ - __FILE__, __LINE__); \ - } \ -} -#endif - -/* - * Number of tasks per device we want to handle. - */ -#if SYM_CONF_MAX_TAG_ORDER > 8 -#error "more than 256 tags per logical unit not allowed." -#endif -#define SYM_CONF_MAX_TASK (1< SYM_CONF_MAX_TASK -#undef SYM_CONF_MAX_TAG -#define SYM_CONF_MAX_TAG SYM_CONF_MAX_TASK -#endif - -/* - * This one means 'NO TAG for this job' - */ -#define NO_TAG (256) - -/* - * Number of SCSI targets. - */ -#if SYM_CONF_MAX_TARGET > 16 -#error "more than 16 targets not allowed." -#endif - -/* - * Number of logical units per target. - */ -#if SYM_CONF_MAX_LUN > 64 -#error "more than 64 logical units per target not allowed." -#endif - -/* - * Asynchronous pre-scaler (ns). Shall be 40 for - * the SCSI timings to be compliant. - */ -#define SYM_CONF_MIN_ASYNC (40) - - -/* - * MEMORY ALLOCATOR. - */ - -#define SYM_MEM_WARN 1 /* Warn on failed operations */ - -#define SYM_MEM_PAGE_ORDER 0 /* 1 PAGE maximum */ -#define SYM_MEM_CLUSTER_SHIFT (PAGE_SHIFT+SYM_MEM_PAGE_ORDER) -#define SYM_MEM_FREE_UNUSED /* Free unused pages immediately */ -/* - * Shortest memory chunk is (1< SYM_MEM_CLUSTER_SIZE/8 -#undef SYM_CONF_MAX_QUEUE -#define SYM_CONF_MAX_QUEUE (SYM_MEM_CLUSTER_SIZE/8) -#undef SYM_CONF_MAX_START -#define SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2) -#endif - -/* - * For this one, we want a short name :-) - */ -#define MAX_QUEUE SYM_CONF_MAX_QUEUE - -/* - * Common definitions for both bus space based and legacy IO methods. - */ - -#define INB_OFF(np, o) ioread8(np->s.ioaddr + (o)) -#define INW_OFF(np, o) ioread16(np->s.ioaddr + (o)) -#define INL_OFF(np, o) ioread32(np->s.ioaddr + (o)) - -#define OUTB_OFF(np, o, val) iowrite8((val), np->s.ioaddr + (o)) -#define OUTW_OFF(np, o, val) iowrite16((val), np->s.ioaddr + (o)) -#define OUTL_OFF(np, o, val) iowrite32((val), np->s.ioaddr + (o)) - -#define INB(np, r) INB_OFF(np, offsetof(struct sym_reg, r)) -#define INW(np, r) INW_OFF(np, offsetof(struct sym_reg, r)) -#define INL(np, r) INL_OFF(np, offsetof(struct sym_reg, r)) - -#define OUTB(np, r, v) OUTB_OFF(np, offsetof(struct sym_reg, r), (v)) -#define OUTW(np, r, v) OUTW_OFF(np, offsetof(struct sym_reg, r), (v)) -#define OUTL(np, r, v) OUTL_OFF(np, offsetof(struct sym_reg, r), (v)) - -#define OUTONB(np, r, m) OUTB(np, r, INB(np, r) | (m)) -#define OUTOFFB(np, r, m) OUTB(np, r, INB(np, r) & ~(m)) -#define OUTONW(np, r, m) OUTW(np, r, INW(np, r) | (m)) -#define OUTOFFW(np, r, m) OUTW(np, r, INW(np, r) & ~(m)) -#define OUTONL(np, r, m) OUTL(np, r, INL(np, r) | (m)) -#define OUTOFFL(np, r, m) OUTL(np, r, INL(np, r) & ~(m)) - -/* - * We normally want the chip to have a consistent view - * of driver internal data structures when we restart it. - * Thus these macros. - */ -#define OUTL_DSP(np, v) \ - do { \ - MEMORY_WRITE_BARRIER(); \ - OUTL(np, nc_dsp, (v)); \ - } while (0) - -#define OUTONB_STD() \ - do { \ - MEMORY_WRITE_BARRIER(); \ - OUTONB(np, nc_dcntl, (STD|NOCOM)); \ - } while (0) - -/* - * Command control block states. - */ -#define HS_IDLE (0) -#define HS_BUSY (1) -#define HS_NEGOTIATE (2) /* sync/wide data transfer*/ -#define HS_DISCONNECT (3) /* Disconnected by target */ -#define HS_WAIT (4) /* waiting for resource */ - -#define HS_DONEMASK (0x80) -#define HS_COMPLETE (4|HS_DONEMASK) -#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */ -#define HS_UNEXPECTED (6|HS_DONEMASK) /* Unexpected disconnect */ -#define HS_COMP_ERR (7|HS_DONEMASK) /* Completed with error */ - -/* - * Software Interrupt Codes - */ -#define SIR_BAD_SCSI_STATUS (1) -#define SIR_SEL_ATN_NO_MSG_OUT (2) -#define SIR_MSG_RECEIVED (3) -#define SIR_MSG_WEIRD (4) -#define SIR_NEGO_FAILED (5) -#define SIR_NEGO_PROTO (6) -#define SIR_SCRIPT_STOPPED (7) -#define SIR_REJECT_TO_SEND (8) -#define SIR_SWIDE_OVERRUN (9) -#define SIR_SODL_UNDERRUN (10) -#define SIR_RESEL_NO_MSG_IN (11) -#define SIR_RESEL_NO_IDENTIFY (12) -#define SIR_RESEL_BAD_LUN (13) -#define SIR_TARGET_SELECTED (14) -#define SIR_RESEL_BAD_I_T_L (15) -#define SIR_RESEL_BAD_I_T_L_Q (16) -#define SIR_ABORT_SENT (17) -#define SIR_RESEL_ABORTED (18) -#define SIR_MSG_OUT_DONE (19) -#define SIR_COMPLETE_ERROR (20) -#define SIR_DATA_OVERRUN (21) -#define SIR_BAD_PHASE (22) -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 -#define SIR_DMAP_DIRTY (23) -#define SIR_MAX (23) -#else -#define SIR_MAX (22) -#endif - -/* - * Extended error bit codes. - * xerr_status field of struct sym_ccb. - */ -#define XE_EXTRA_DATA (1) /* unexpected data phase */ -#define XE_BAD_PHASE (1<<1) /* illegal phase (4/5) */ -#define XE_PARITY_ERR (1<<2) /* unrecovered SCSI parity error */ -#define XE_SODL_UNRUN (1<<3) /* ODD transfer in DATA OUT phase */ -#define XE_SWIDE_OVRUN (1<<4) /* ODD transfer in DATA IN phase */ - -/* - * Negotiation status. - * nego_status field of struct sym_ccb. - */ -#define NS_SYNC (1) -#define NS_WIDE (2) -#define NS_PPR (3) - -/* - * A CCB hashed table is used to retrieve CCB address - * from DSA value. - */ -#define CCB_HASH_SHIFT 8 -#define CCB_HASH_SIZE (1UL << CCB_HASH_SHIFT) -#define CCB_HASH_MASK (CCB_HASH_SIZE-1) -#if 1 -#define CCB_HASH_CODE(dsa) \ - (((dsa) >> (_LGRU16_(sizeof(struct sym_ccb)))) & CCB_HASH_MASK) -#else -#define CCB_HASH_CODE(dsa) (((dsa) >> 9) & CCB_HASH_MASK) -#endif - -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 -/* - * We may want to use segment registers for 64 bit DMA. - * 16 segments registers -> up to 64 GB addressable. - */ -#define SYM_DMAP_SHIFT (4) -#define SYM_DMAP_SIZE (1u< SCNTL4 register */ -/*1*/ u_char sval; /* -> SXFER io register */ -/*2*/ u_char filler1; -/*3*/ u_char wval; /* -> SCNTL3 io register */ -}; - -/* - * Target Control Block - */ -struct sym_tcb { - /* - * TCB header. - * Assumed at offset 0. - */ -/*0*/ struct sym_tcbh head; - - /* - * LUN table used by the SCRIPTS processor. - * An array of bus addresses is used on reselection. - */ - u32 *luntbl; /* LCBs bus address table */ - int nlcb; /* Number of valid LCBs (including LUN #0) */ - - /* - * LUN table used by the C code. - */ - struct sym_lcb *lun0p; /* LCB of LUN #0 (usual case) */ -#if SYM_CONF_MAX_LUN > 1 - struct sym_lcb **lunmp; /* Other LCBs [1..MAX_LUN] */ -#endif - -#ifdef SYM_HAVE_STCB - /* - * O/S specific data structure. - */ - struct sym_stcb s; -#endif - - /* Transfer goal */ - struct sym_trans tgoal; - - /* Last printed transfer speed */ - struct sym_trans tprint; - - /* - * Keep track of the CCB used for the negotiation in order - * to ensure that only 1 negotiation is queued at a time. - */ - struct sym_ccb * nego_cp; /* CCB used for the nego */ - - /* - * Set when we want to reset the device. - */ - u_char to_reset; - - /* - * Other user settable limits and options. - * These limits are read from the NVRAM if present. - */ - unsigned char usrflags; - unsigned char usr_period; - unsigned char usr_width; - unsigned short usrtags; - struct scsi_target *starget; -}; - -/* - * Global LCB HEADER. - * - * Due to lack of indirect addressing on earlier NCR chips, - * this substructure is copied from the LCB to a global - * address after selection. - * For SYMBIOS chips that support LOAD/STORE this copy is - * not needed and thus not performed. - */ -struct sym_lcbh { - /* - * SCRIPTS address jumped by SCRIPTS on reselection. - * For not probed logical units, this address points to - * SCRIPTS that deal with bad LU handling (must be at - * offset zero of the LCB for that reason). - */ -/*0*/ u32 resel_sa; - - /* - * Task (bus address of a CCB) read from SCRIPTS that points - * to the unique ITL nexus allowed to be disconnected. - */ - u32 itl_task_sa; - - /* - * Task table bus address (read from SCRIPTS). - */ - u32 itlq_tbl_sa; -}; - -/* - * Logical Unit Control Block - */ -struct sym_lcb { - /* - * TCB header. - * Assumed at offset 0. - */ -/*0*/ struct sym_lcbh head; - - /* - * Task table read from SCRIPTS that contains pointers to - * ITLQ nexuses. The bus address read from SCRIPTS is - * inside the header. - */ - u32 *itlq_tbl; /* Kernel virtual address */ - - /* - * Busy CCBs management. - */ - u_short busy_itlq; /* Number of busy tagged CCBs */ - u_short busy_itl; /* Number of busy untagged CCBs */ - - /* - * Circular tag allocation buffer. - */ - u_short ia_tag; /* Tag allocation index */ - u_short if_tag; /* Tag release index */ - u_char *cb_tags; /* Circular tags buffer */ - - /* - * O/S specific data structure. - */ -#ifdef SYM_HAVE_SLCB - struct sym_slcb s; -#endif - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - /* - * Optionnaly the driver can handle device queueing, - * and requeues internally command to redo. - */ - SYM_QUEHEAD waiting_ccbq; - SYM_QUEHEAD started_ccbq; - int num_sgood; - u_short started_tags; - u_short started_no_tag; - u_short started_max; - u_short started_limit; -#endif - -#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING - /* - * Optionally the driver can try to prevent SCSI - * IOs from being reordered too much. - */ - u_char tags_si; /* Current index to tags sum */ - u_short tags_sum[2]; /* Tags sum counters */ - u_short tags_since; /* # of tags since last switch */ -#endif - - /* - * Set when we want to clear all tasks. - */ - u_char to_clear; - - /* - * Capabilities. - */ - u_char user_flags; - u_char curr_flags; -}; - -/* - * Action from SCRIPTS on a task. - * Is part of the CCB, but is also used separately to plug - * error handling action to perform from SCRIPTS. - */ -struct sym_actscr { - u32 start; /* Jumped by SCRIPTS after selection */ - u32 restart; /* Jumped by SCRIPTS on relection */ -}; - -/* - * Phase mismatch context. - * - * It is part of the CCB and is used as parameters for the - * DATA pointer. We need two contexts to handle correctly the - * SAVED DATA POINTER. - */ -struct sym_pmc { - struct sym_tblmove sg; /* Updated interrupted SG block */ - u32 ret; /* SCRIPT return address */ -}; - -/* - * LUN control block lookup. - * We use a direct pointer for LUN #0, and a table of - * pointers which is only allocated for devices that support - * LUN(s) > 0. - */ -#if SYM_CONF_MAX_LUN <= 1 -#define sym_lp(tp, lun) (!lun) ? (tp)->lun0p : NULL -#else -#define sym_lp(tp, lun) \ - (!lun) ? (tp)->lun0p : (tp)->lunmp ? (tp)->lunmp[(lun)] : NULL -#endif - -/* - * Status are used by the host and the script processor. - * - * The last four bytes (status[4]) are copied to the - * scratchb register (declared as scr0..scr3) just after the - * select/reselect, and copied back just after disconnecting. - * Inside the script the XX_REG are used. - */ - -/* - * Last four bytes (script) - */ -#define HX_REG scr0 -#define HX_PRT nc_scr0 -#define HS_REG scr1 -#define HS_PRT nc_scr1 -#define SS_REG scr2 -#define SS_PRT nc_scr2 -#define HF_REG scr3 -#define HF_PRT nc_scr3 - -/* - * Last four bytes (host) - */ -#define host_xflags phys.head.status[0] -#define host_status phys.head.status[1] -#define ssss_status phys.head.status[2] -#define host_flags phys.head.status[3] - -/* - * Host flags - */ -#define HF_IN_PM0 1u -#define HF_IN_PM1 (1u<<1) -#define HF_ACT_PM (1u<<2) -#define HF_DP_SAVED (1u<<3) -#define HF_SENSE (1u<<4) -#define HF_EXT_ERR (1u<<5) -#define HF_DATA_IN (1u<<6) -#ifdef SYM_CONF_IARB_SUPPORT -#define HF_HINT_IARB (1u<<7) -#endif - -/* - * More host flags - */ -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 -#define HX_DMAP_DIRTY (1u<<7) -#endif - -/* - * Global CCB HEADER. - * - * Due to lack of indirect addressing on earlier NCR chips, - * this substructure is copied from the ccb to a global - * address after selection (or reselection) and copied back - * before disconnect. - * For SYMBIOS chips that support LOAD/STORE this copy is - * not needed and thus not performed. - */ - -struct sym_ccbh { - /* - * Start and restart SCRIPTS addresses (must be at 0). - */ -/*0*/ struct sym_actscr go; - - /* - * SCRIPTS jump address that deal with data pointers. - * 'savep' points to the position in the script responsible - * for the actual transfer of data. - * It's written on reception of a SAVE_DATA_POINTER message. - */ - u32 savep; /* Jump address to saved data pointer */ - u32 lastp; /* SCRIPTS address at end of data */ - - /* - * Status fields. - */ - u8 status[4]; -}; - -/* - * GET/SET the value of the data pointer used by SCRIPTS. - * - * We must distinguish between the LOAD/STORE-based SCRIPTS - * that use directly the header in the CCB, and the NCR-GENERIC - * SCRIPTS that use the copy of the header in the HCB. - */ -#if SYM_CONF_GENERIC_SUPPORT -#define sym_set_script_dp(np, cp, dp) \ - do { \ - if (np->features & FE_LDSTR) \ - cp->phys.head.lastp = cpu_to_scr(dp); \ - else \ - np->ccb_head.lastp = cpu_to_scr(dp); \ - } while (0) -#define sym_get_script_dp(np, cp) \ - scr_to_cpu((np->features & FE_LDSTR) ? \ - cp->phys.head.lastp : np->ccb_head.lastp) -#else -#define sym_set_script_dp(np, cp, dp) \ - do { \ - cp->phys.head.lastp = cpu_to_scr(dp); \ - } while (0) - -#define sym_get_script_dp(np, cp) (cp->phys.head.lastp) -#endif - -/* - * Data Structure Block - * - * During execution of a ccb by the script processor, the - * DSA (data structure address) register points to this - * substructure of the ccb. - */ -struct sym_dsb { - /* - * CCB header. - * Also assumed at offset 0 of the sym_ccb structure. - */ -/*0*/ struct sym_ccbh head; - - /* - * Phase mismatch contexts. - * We need two to handle correctly the SAVED DATA POINTER. - * MUST BOTH BE AT OFFSET < 256, due to using 8 bit arithmetic - * for address calculation from SCRIPTS. - */ - struct sym_pmc pm0; - struct sym_pmc pm1; - - /* - * Table data for Script - */ - struct sym_tblsel select; - struct sym_tblmove smsg; - struct sym_tblmove smsg_ext; - struct sym_tblmove cmd; - struct sym_tblmove sense; - struct sym_tblmove wresid; - struct sym_tblmove data [SYM_CONF_MAX_SG]; -}; - -/* - * Our Command Control Block - */ -struct sym_ccb { - /* - * This is the data structure which is pointed by the DSA - * register when it is executed by the script processor. - * It must be the first entry. - */ - struct sym_dsb phys; - - /* - * Pointer to CAM ccb and related stuff. - */ - struct scsi_cmnd *cmd; /* CAM scsiio ccb */ - u8 cdb_buf[16]; /* Copy of CDB */ -#define SYM_SNS_BBUF_LEN 32 - u8 sns_bbuf[SYM_SNS_BBUF_LEN]; /* Bounce buffer for sense data */ - int data_len; /* Total data length */ - int segments; /* Number of SG segments */ - - u8 order; /* Tag type (if tagged command) */ - unsigned char odd_byte_adjustment; /* odd-sized req on wide bus */ - - u_char nego_status; /* Negotiation status */ - u_char xerr_status; /* Extended error flags */ - u32 extra_bytes; /* Extraneous bytes transferred */ - - /* - * Message areas. - * We prepare a message to be sent after selection. - * We may use a second one if the command is rescheduled - * due to CHECK_CONDITION or COMMAND TERMINATED. - * Contents are IDENTIFY and SIMPLE_TAG. - * While negotiating sync or wide transfer, - * a SDTR or WDTR message is appended. - */ - u_char scsi_smsg [12]; - u_char scsi_smsg2[12]; - - /* - * Auto request sense related fields. - */ - u_char sensecmd[6]; /* Request Sense command */ - u_char sv_scsi_status; /* Saved SCSI status */ - u_char sv_xerr_status; /* Saved extended status */ - int sv_resid; /* Saved residual */ - - /* - * Other fields. - */ - u32 ccb_ba; /* BUS address of this CCB */ - u_short tag; /* Tag for this transfer */ - /* NO_TAG means no tag */ - u_char target; - u_char lun; - struct sym_ccb *link_ccbh; /* Host adapter CCB hash chain */ - SYM_QUEHEAD link_ccbq; /* Link to free/busy CCB queue */ - u32 startp; /* Initial data pointer */ - u32 goalp; /* Expected last data pointer */ - int ext_sg; /* Extreme data pointer, used */ - int ext_ofs; /* to calculate the residual. */ -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - SYM_QUEHEAD link2_ccbq; /* Link for device queueing */ - u_char started; /* CCB queued to the squeue */ -#endif - u_char to_abort; /* Want this IO to be aborted */ -#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING - u_char tags_si; /* Lun tags sum index (0,1) */ -#endif -}; - -#define CCB_BA(cp,lbl) cpu_to_scr(cp->ccb_ba + offsetof(struct sym_ccb, lbl)) - -typedef struct device *m_pool_ident_t; - -/* - * Host Control Block - */ -struct sym_hcb { - /* - * Global headers. - * Due to poorness of addressing capabilities, earlier - * chips (810, 815, 825) copy part of the data structures - * (CCB, TCB and LCB) in fixed areas. - */ -#if SYM_CONF_GENERIC_SUPPORT - struct sym_ccbh ccb_head; - struct sym_tcbh tcb_head; - struct sym_lcbh lcb_head; -#endif - /* - * Idle task and invalid task actions and - * their bus addresses. - */ - struct sym_actscr idletask, notask, bad_itl, bad_itlq; - u32 idletask_ba, notask_ba, bad_itl_ba, bad_itlq_ba; - - /* - * Dummy lun table to protect us against target - * returning bad lun number on reselection. - */ - u32 *badluntbl; /* Table physical address */ - u32 badlun_sa; /* SCRIPT handler BUS address */ - - /* - * Bus address of this host control block. - */ - u32 hcb_ba; - - /* - * Bit 32-63 of the on-chip RAM bus address in LE format. - * The START_RAM64 script loads the MMRS and MMWS from this - * field. - */ - u32 scr_ram_seg; - - /* - * Initial value of some IO register bits. - * These values are assumed to have been set by BIOS, and may - * be used to probe adapter implementation differences. - */ - u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4, - sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_scntl4, - sv_stest1; - - /* - * Actual initial value of IO register bits used by the - * driver. They are loaded at initialisation according to - * features that are to be enabled/disabled. - */ - u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, - rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4; - - /* - * Target data. - */ - struct sym_tcb target[SYM_CONF_MAX_TARGET]; - - /* - * Target control block bus address array used by the SCRIPT - * on reselection. - */ - u32 *targtbl; - u32 targtbl_ba; - - /* - * DMA pool handle for this HBA. - */ - m_pool_ident_t bus_dmat; - - /* - * O/S specific data structure - */ - struct sym_shcb s; - - /* - * Physical bus addresses of the chip. - */ - u32 mmio_ba; /* MMIO 32 bit BUS address */ - u32 ram_ba; /* RAM 32 bit BUS address */ - - /* - * SCRIPTS virtual and physical bus addresses. - * 'script' is loaded in the on-chip RAM if present. - * 'scripth' stays in main memory for all chips except the - * 53C895A, 53C896 and 53C1010 that provide 8K on-chip RAM. - */ - u_char *scripta0; /* Copy of scripts A, B, Z */ - u_char *scriptb0; - u_char *scriptz0; - u32 scripta_ba; /* Actual scripts A, B, Z */ - u32 scriptb_ba; /* 32 bit bus addresses. */ - u32 scriptz_ba; - u_short scripta_sz; /* Actual size of script A, B, Z*/ - u_short scriptb_sz; - u_short scriptz_sz; - - /* - * Bus addresses, setup and patch methods for - * the selected firmware. - */ - struct sym_fwa_ba fwa_bas; /* Useful SCRIPTA bus addresses */ - struct sym_fwb_ba fwb_bas; /* Useful SCRIPTB bus addresses */ - struct sym_fwz_ba fwz_bas; /* Useful SCRIPTZ bus addresses */ - void (*fw_setup)(struct sym_hcb *np, struct sym_fw *fw); - void (*fw_patch)(struct Scsi_Host *); - char *fw_name; - - /* - * General controller parameters and configuration. - */ - u_int features; /* Chip features map */ - u_char myaddr; /* SCSI id of the adapter */ - u_char maxburst; /* log base 2 of dwords burst */ - u_char maxwide; /* Maximum transfer width */ - u_char minsync; /* Min sync period factor (ST) */ - u_char maxsync; /* Max sync period factor (ST) */ - u_char maxoffs; /* Max scsi offset (ST) */ - u_char minsync_dt; /* Min sync period factor (DT) */ - u_char maxsync_dt; /* Max sync period factor (DT) */ - u_char maxoffs_dt; /* Max scsi offset (DT) */ - u_char multiplier; /* Clock multiplier (1,2,4) */ - u_char clock_divn; /* Number of clock divisors */ - u32 clock_khz; /* SCSI clock frequency in KHz */ - u32 pciclk_khz; /* Estimated PCI clock in KHz */ - /* - * Start queue management. - * It is filled up by the host processor and accessed by the - * SCRIPTS processor in order to start SCSI commands. - */ - volatile /* Prevent code optimizations */ - u32 *squeue; /* Start queue virtual address */ - u32 squeue_ba; /* Start queue BUS address */ - u_short squeueput; /* Next free slot of the queue */ - u_short actccbs; /* Number of allocated CCBs */ - - /* - * Command completion queue. - * It is the same size as the start queue to avoid overflow. - */ - u_short dqueueget; /* Next position to scan */ - volatile /* Prevent code optimizations */ - u32 *dqueue; /* Completion (done) queue */ - u32 dqueue_ba; /* Done queue BUS address */ - - /* - * Miscellaneous buffers accessed by the scripts-processor. - * They shall be DWORD aligned, because they may be read or - * written with a script command. - */ - u_char msgout[8]; /* Buffer for MESSAGE OUT */ - u_char msgin [8]; /* Buffer for MESSAGE IN */ - u32 lastmsg; /* Last SCSI message sent */ - u32 scratch; /* Scratch for SCSI receive */ - /* Also used for cache test */ - /* - * Miscellaneous configuration and status parameters. - */ - u_char usrflags; /* Miscellaneous user flags */ - u_char scsi_mode; /* Current SCSI BUS mode */ - u_char verbose; /* Verbosity for this controller*/ - - /* - * CCB lists and queue. - */ - struct sym_ccb **ccbh; /* CCBs hashed by DSA value */ - /* CCB_HASH_SIZE lists of CCBs */ - SYM_QUEHEAD free_ccbq; /* Queue of available CCBs */ - SYM_QUEHEAD busy_ccbq; /* Queue of busy CCBs */ - - /* - * During error handling and/or recovery, - * active CCBs that are to be completed with - * error or requeued are moved from the busy_ccbq - * to the comp_ccbq prior to completion. - */ - SYM_QUEHEAD comp_ccbq; - -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING - SYM_QUEHEAD dummy_ccbq; -#endif - - /* - * IMMEDIATE ARBITRATION (IARB) control. - * - * We keep track in 'last_cp' of the last CCB that has been - * queued to the SCRIPTS processor and clear 'last_cp' when - * this CCB completes. If last_cp is not zero at the moment - * we queue a new CCB, we set a flag in 'last_cp' that is - * used by the SCRIPTS as a hint for setting IARB. - * We donnot set more than 'iarb_max' consecutive hints for - * IARB in order to leave devices a chance to reselect. - * By the way, any non zero value of 'iarb_max' is unfair. :) - */ -#ifdef SYM_CONF_IARB_SUPPORT - u_short iarb_max; /* Max. # consecutive IARB hints*/ - u_short iarb_count; /* Actual # of these hints */ - struct sym_ccb * last_cp; -#endif - - /* - * Command abort handling. - * We need to synchronize tightly with the SCRIPTS - * processor in order to handle things correctly. - */ - u_char abrt_msg[4]; /* Message to send buffer */ - struct sym_tblmove abrt_tbl; /* Table for the MOV of it */ - struct sym_tblsel abrt_sel; /* Sync params for selection */ - u_char istat_sem; /* Tells the chip to stop (SEM) */ - - /* - * 64 bit DMA handling. - */ -#if SYM_CONF_DMA_ADDRESSING_MODE != 0 - u_char use_dac; /* Use PCI DAC cycles */ -#if SYM_CONF_DMA_ADDRESSING_MODE == 2 - u_char dmap_dirty; /* Dma segments registers dirty */ - u32 dmap_bah[SYM_DMAP_SIZE];/* Segment registers map */ -#endif -#endif -}; - -#if SYM_CONF_DMA_ADDRESSING_MODE == 0 -#define use_dac(np) 0 -#define set_dac(np) do { } while (0) -#else -#define use_dac(np) (np)->use_dac -#define set_dac(np) (np)->use_dac = 1 -#endif - -#define HCB_BA(np, lbl) (np->hcb_ba + offsetof(struct sym_hcb, lbl)) - - -/* - * FIRMWARES (sym_fw.c) - */ -struct sym_fw * sym_find_firmware(struct sym_chip *chip); -void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len); - -/* - * Driver methods called from O/S specific code. - */ -char *sym_driver_name(void); -void sym_print_xerr(struct scsi_cmnd *cmd, int x_status); -int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int); -struct sym_chip *sym_lookup_chip_table(u_short device_id, u_char revision); -#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING -void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn); -#else -void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp); -#endif -void sym_start_up(struct Scsi_Host *, int reason); -irqreturn_t sym_interrupt(struct Scsi_Host *); -int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int task); -struct sym_ccb *sym_get_ccb(struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order); -void sym_free_ccb(struct sym_hcb *np, struct sym_ccb *cp); -struct sym_lcb *sym_alloc_lcb(struct sym_hcb *np, u_char tn, u_char ln); -int sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln); -int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp); -int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *ccb, int timed_out); -int sym_reset_scsi_target(struct sym_hcb *np, int target); -void sym_hcb_free(struct sym_hcb *np); -int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram *nvram); - -/* - * Build a scatter/gather entry. - * - * For 64 bit systems, we use the 8 upper bits of the size field - * to provide bus address bits 32-39 to the SCRIPTS processor. - * This allows the 895A, 896, 1010 to address up to 1 TB of memory. - */ - -#if SYM_CONF_DMA_ADDRESSING_MODE == 0 -#define DMA_DAC_MASK DMA_BIT_MASK(32) -#define sym_build_sge(np, data, badd, len) \ -do { \ - (data)->addr = cpu_to_scr(badd); \ - (data)->size = cpu_to_scr(len); \ -} while (0) -#elif SYM_CONF_DMA_ADDRESSING_MODE == 1 -#define DMA_DAC_MASK DMA_BIT_MASK(40) -#define sym_build_sge(np, data, badd, len) \ -do { \ - (data)->addr = cpu_to_scr(badd); \ - (data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len); \ -} while (0) -#elif SYM_CONF_DMA_ADDRESSING_MODE == 2 -#define DMA_DAC_MASK DMA_BIT_MASK(64) -int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s); -static inline void -sym_build_sge(struct sym_hcb *np, struct sym_tblmove *data, u64 badd, int len) -{ - u32 h = (badd>>32); - int s = (h&SYM_DMAP_MASK); - - if (h != np->dmap_bah[s]) - goto bad; -good: - (data)->addr = cpu_to_scr(badd); - (data)->size = cpu_to_scr((s<<24) + len); - return; -bad: - s = sym_lookup_dmap(np, h, s); - goto good; -} -#else -#error "Unsupported DMA addressing mode" -#endif - -/* - * MEMORY ALLOCATOR. - */ - -#define sym_get_mem_cluster() \ - (void *) __get_free_pages(GFP_ATOMIC, SYM_MEM_PAGE_ORDER) -#define sym_free_mem_cluster(p) \ - free_pages((unsigned long)p, SYM_MEM_PAGE_ORDER) - -/* - * Link between free memory chunks of a given size. - */ -typedef struct sym_m_link { - struct sym_m_link *next; -} *m_link_p; - -/* - * Virtual to bus physical translation for a given cluster. - * Such a structure is only useful with DMA abstraction. - */ -typedef struct sym_m_vtob { /* Virtual to Bus address translation */ - struct sym_m_vtob *next; - void *vaddr; /* Virtual address */ - dma_addr_t baddr; /* Bus physical address */ -} *m_vtob_p; - -/* Hash this stuff a bit to speed up translations */ -#define VTOB_HASH_SHIFT 5 -#define VTOB_HASH_SIZE (1UL << VTOB_HASH_SHIFT) -#define VTOB_HASH_MASK (VTOB_HASH_SIZE-1) -#define VTOB_HASH_CODE(m) \ - ((((unsigned long)(m)) >> SYM_MEM_CLUSTER_SHIFT) & VTOB_HASH_MASK) - -/* - * Memory pool of a given kind. - * Ideally, we want to use: - * 1) 1 pool for memory we donnot need to involve in DMA. - * 2) The same pool for controllers that require same DMA - * constraints and features. - * The OS specific m_pool_id_t thing and the sym_m_pool_match() - * method are expected to tell the driver about. - */ -typedef struct sym_m_pool { - m_pool_ident_t dev_dmat; /* Identifies the pool (see above) */ - void * (*get_mem_cluster)(struct sym_m_pool *); -#ifdef SYM_MEM_FREE_UNUSED - void (*free_mem_cluster)(struct sym_m_pool *, void *); -#endif -#define M_GET_MEM_CLUSTER() mp->get_mem_cluster(mp) -#define M_FREE_MEM_CLUSTER(p) mp->free_mem_cluster(mp, p) - int nump; - m_vtob_p vtob[VTOB_HASH_SIZE]; - struct sym_m_pool *next; - struct sym_m_link h[SYM_MEM_CLUSTER_SHIFT - SYM_MEM_SHIFT + 1]; -} *m_pool_p; - -/* - * Alloc, free and translate addresses to bus physical - * for DMAable memory. - */ -void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name); -void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name); -dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m); - -/* - * Verbs used by the driver code for DMAable memory handling. - * The _uvptv_ macro avoids a nasty warning about pointer to volatile - * being discarded. - */ -#define _uvptv_(p) ((void *)((u_long)(p))) - -#define _sym_calloc_dma(np, l, n) __sym_calloc_dma(np->bus_dmat, l, n) -#define _sym_mfree_dma(np, p, l, n) \ - __sym_mfree_dma(np->bus_dmat, _uvptv_(p), l, n) -#define sym_calloc_dma(l, n) _sym_calloc_dma(np, l, n) -#define sym_mfree_dma(p, l, n) _sym_mfree_dma(np, p, l, n) -#define vtobus(p) __vtobus(np->bus_dmat, _uvptv_(p)) - -/* - * We have to provide the driver memory allocator with methods for - * it to maintain virtual to bus physical address translations. - */ - -#define sym_m_pool_match(mp_id1, mp_id2) (mp_id1 == mp_id2) - -static inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp) -{ - void *vaddr = NULL; - dma_addr_t baddr = 0; - - vaddr = dma_alloc_coherent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE, &baddr, - GFP_ATOMIC); - if (vaddr) { - vbp->vaddr = vaddr; - vbp->baddr = baddr; - } - return vaddr; -} - -static inline void sym_m_free_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp) -{ - dma_free_coherent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE, vbp->vaddr, - vbp->baddr); -} - -#endif /* SYM_HIPD_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_malloc.c b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_malloc.c deleted file mode 100644 index 6f9af0de..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_malloc.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sym_glue.h" - -/* - * Simple power of two buddy-like generic allocator. - * Provides naturally aligned memory chunks. - * - * This simple code is not intended to be fast, but to - * provide power of 2 aligned memory allocations. - * Since the SCRIPTS processor only supplies 8 bit arithmetic, - * this allocator allows simple and fast address calculations - * from the SCRIPTS code. In addition, cache line alignment - * is guaranteed for power of 2 cache line size. - * - * This allocator has been developed for the Linux sym53c8xx - * driver, since this O/S does not provide naturally aligned - * allocations. - * It has the advantage of allowing the driver to use private - * pages of memory that will be useful if we ever need to deal - * with IO MMUs for PCI. - */ -static void *___sym_malloc(m_pool_p mp, int size) -{ - int i = 0; - int s = (1 << SYM_MEM_SHIFT); - int j; - void *a; - m_link_p h = mp->h; - - if (size > SYM_MEM_CLUSTER_SIZE) - return NULL; - - while (size > s) { - s <<= 1; - ++i; - } - - j = i; - while (!h[j].next) { - if (s == SYM_MEM_CLUSTER_SIZE) { - h[j].next = (m_link_p) M_GET_MEM_CLUSTER(); - if (h[j].next) - h[j].next->next = NULL; - break; - } - ++j; - s <<= 1; - } - a = h[j].next; - if (a) { - h[j].next = h[j].next->next; - while (j > i) { - j -= 1; - s >>= 1; - h[j].next = (m_link_p) (a+s); - h[j].next->next = NULL; - } - } -#ifdef DEBUG - printf("___sym_malloc(%d) = %p\n", size, (void *) a); -#endif - return a; -} - -/* - * Counter-part of the generic allocator. - */ -static void ___sym_mfree(m_pool_p mp, void *ptr, int size) -{ - int i = 0; - int s = (1 << SYM_MEM_SHIFT); - m_link_p q; - unsigned long a, b; - m_link_p h = mp->h; - -#ifdef DEBUG - printf("___sym_mfree(%p, %d)\n", ptr, size); -#endif - - if (size > SYM_MEM_CLUSTER_SIZE) - return; - - while (size > s) { - s <<= 1; - ++i; - } - - a = (unsigned long)ptr; - - while (1) { - if (s == SYM_MEM_CLUSTER_SIZE) { -#ifdef SYM_MEM_FREE_UNUSED - M_FREE_MEM_CLUSTER((void *)a); -#else - ((m_link_p) a)->next = h[i].next; - h[i].next = (m_link_p) a; -#endif - break; - } - b = a ^ s; - q = &h[i]; - while (q->next && q->next != (m_link_p) b) { - q = q->next; - } - if (!q->next) { - ((m_link_p) a)->next = h[i].next; - h[i].next = (m_link_p) a; - break; - } - q->next = q->next->next; - a = a & b; - s <<= 1; - ++i; - } -} - -/* - * Verbose and zeroing allocator that wrapps to the generic allocator. - */ -static void *__sym_calloc2(m_pool_p mp, int size, char *name, int uflags) -{ - void *p; - - p = ___sym_malloc(mp, size); - - if (DEBUG_FLAGS & DEBUG_ALLOC) { - printf ("new %-10s[%4d] @%p.\n", name, size, p); - } - - if (p) - memset(p, 0, size); - else if (uflags & SYM_MEM_WARN) - printf ("__sym_calloc2: failed to allocate %s[%d]\n", name, size); - return p; -} -#define __sym_calloc(mp, s, n) __sym_calloc2(mp, s, n, SYM_MEM_WARN) - -/* - * Its counter-part. - */ -static void __sym_mfree(m_pool_p mp, void *ptr, int size, char *name) -{ - if (DEBUG_FLAGS & DEBUG_ALLOC) - printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr); - - ___sym_mfree(mp, ptr, size); -} - -/* - * Default memory pool we donnot need to involve in DMA. - * - * With DMA abstraction, we use functions (methods), to - * distinguish between non DMAable memory and DMAable memory. - */ -static void *___mp0_get_mem_cluster(m_pool_p mp) -{ - void *m = sym_get_mem_cluster(); - if (m) - ++mp->nump; - return m; -} - -#ifdef SYM_MEM_FREE_UNUSED -static void ___mp0_free_mem_cluster(m_pool_p mp, void *m) -{ - sym_free_mem_cluster(m); - --mp->nump; -} -#else -#define ___mp0_free_mem_cluster NULL -#endif - -static struct sym_m_pool mp0 = { - NULL, - ___mp0_get_mem_cluster, - ___mp0_free_mem_cluster -}; - -/* - * Methods that maintains DMAable pools according to user allocations. - * New pools are created on the fly when a new pool id is provided. - * They are deleted on the fly when they get emptied. - */ -/* Get a memory cluster that matches the DMA constraints of a given pool */ -static void * ___get_dma_mem_cluster(m_pool_p mp) -{ - m_vtob_p vbp; - void *vaddr; - - vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB"); - if (!vbp) - goto out_err; - - vaddr = sym_m_get_dma_mem_cluster(mp, vbp); - if (vaddr) { - int hc = VTOB_HASH_CODE(vaddr); - vbp->next = mp->vtob[hc]; - mp->vtob[hc] = vbp; - ++mp->nump; - } - return vaddr; -out_err: - return NULL; -} - -#ifdef SYM_MEM_FREE_UNUSED -/* Free a memory cluster and associated resources for DMA */ -static void ___free_dma_mem_cluster(m_pool_p mp, void *m) -{ - m_vtob_p *vbpp, vbp; - int hc = VTOB_HASH_CODE(m); - - vbpp = &mp->vtob[hc]; - while (*vbpp && (*vbpp)->vaddr != m) - vbpp = &(*vbpp)->next; - if (*vbpp) { - vbp = *vbpp; - *vbpp = (*vbpp)->next; - sym_m_free_dma_mem_cluster(mp, vbp); - __sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB"); - --mp->nump; - } -} -#endif - -/* Fetch the memory pool for a given pool id (i.e. DMA constraints) */ -static inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat) -{ - m_pool_p mp; - for (mp = mp0.next; - mp && !sym_m_pool_match(mp->dev_dmat, dev_dmat); - mp = mp->next); - return mp; -} - -/* Create a new memory DMAable pool (when fetch failed) */ -static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat) -{ - m_pool_p mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL"); - if (mp) { - mp->dev_dmat = dev_dmat; - mp->get_mem_cluster = ___get_dma_mem_cluster; -#ifdef SYM_MEM_FREE_UNUSED - mp->free_mem_cluster = ___free_dma_mem_cluster; -#endif - mp->next = mp0.next; - mp0.next = mp; - return mp; - } - return NULL; -} - -#ifdef SYM_MEM_FREE_UNUSED -/* Destroy a DMAable memory pool (when got emptied) */ -static void ___del_dma_pool(m_pool_p p) -{ - m_pool_p *pp = &mp0.next; - - while (*pp && *pp != p) - pp = &(*pp)->next; - if (*pp) { - *pp = (*pp)->next; - __sym_mfree(&mp0, p, sizeof(*p), "MPOOL"); - } -} -#endif - -/* This lock protects only the memory allocation/free. */ -static DEFINE_SPINLOCK(sym53c8xx_lock); - -/* - * Actual allocator for DMAable memory. - */ -void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name) -{ - unsigned long flags; - m_pool_p mp; - void *m = NULL; - - spin_lock_irqsave(&sym53c8xx_lock, flags); - mp = ___get_dma_pool(dev_dmat); - if (!mp) - mp = ___cre_dma_pool(dev_dmat); - if (!mp) - goto out; - m = __sym_calloc(mp, size, name); -#ifdef SYM_MEM_FREE_UNUSED - if (!mp->nump) - ___del_dma_pool(mp); -#endif - - out: - spin_unlock_irqrestore(&sym53c8xx_lock, flags); - return m; -} - -void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name) -{ - unsigned long flags; - m_pool_p mp; - - spin_lock_irqsave(&sym53c8xx_lock, flags); - mp = ___get_dma_pool(dev_dmat); - if (!mp) - goto out; - __sym_mfree(mp, m, size, name); -#ifdef SYM_MEM_FREE_UNUSED - if (!mp->nump) - ___del_dma_pool(mp); -#endif - out: - spin_unlock_irqrestore(&sym53c8xx_lock, flags); -} - -/* - * Actual virtual to bus physical address translator - * for 32 bit addressable DMAable memory. - */ -dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m) -{ - unsigned long flags; - m_pool_p mp; - int hc = VTOB_HASH_CODE(m); - m_vtob_p vp = NULL; - void *a = (void *)((unsigned long)m & ~SYM_MEM_CLUSTER_MASK); - dma_addr_t b; - - spin_lock_irqsave(&sym53c8xx_lock, flags); - mp = ___get_dma_pool(dev_dmat); - if (mp) { - vp = mp->vtob[hc]; - while (vp && vp->vaddr != a) - vp = vp->next; - } - if (!vp) - panic("sym: VTOBUS FAILED!\n"); - b = vp->baddr + (m - a); - spin_unlock_irqrestore(&sym53c8xx_lock, flags); - return b; -} diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_misc.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_misc.h deleted file mode 100644 index 96c15145..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_misc.h +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SYM_MISC_H -#define SYM_MISC_H - -/* - * A la VMS/CAM-3 queue management. - */ -typedef struct sym_quehead { - struct sym_quehead *flink; /* Forward pointer */ - struct sym_quehead *blink; /* Backward pointer */ -} SYM_QUEHEAD; - -#define sym_que_init(ptr) do { \ - (ptr)->flink = (ptr); (ptr)->blink = (ptr); \ -} while (0) - -static inline struct sym_quehead *sym_que_first(struct sym_quehead *head) -{ - return (head->flink == head) ? 0 : head->flink; -} - -static inline struct sym_quehead *sym_que_last(struct sym_quehead *head) -{ - return (head->blink == head) ? 0 : head->blink; -} - -static inline void __sym_que_add(struct sym_quehead * new, - struct sym_quehead * blink, - struct sym_quehead * flink) -{ - flink->blink = new; - new->flink = flink; - new->blink = blink; - blink->flink = new; -} - -static inline void __sym_que_del(struct sym_quehead * blink, - struct sym_quehead * flink) -{ - flink->blink = blink; - blink->flink = flink; -} - -static inline int sym_que_empty(struct sym_quehead *head) -{ - return head->flink == head; -} - -static inline void sym_que_splice(struct sym_quehead *list, - struct sym_quehead *head) -{ - struct sym_quehead *first = list->flink; - - if (first != list) { - struct sym_quehead *last = list->blink; - struct sym_quehead *at = head->flink; - - first->blink = head; - head->flink = first; - - last->flink = at; - at->blink = last; - } -} - -static inline void sym_que_move(struct sym_quehead *orig, - struct sym_quehead *dest) -{ - struct sym_quehead *first, *last; - - first = orig->flink; - if (first != orig) { - first->blink = dest; - dest->flink = first; - last = orig->blink; - last->flink = dest; - dest->blink = last; - orig->flink = orig; - orig->blink = orig; - } else { - dest->flink = dest; - dest->blink = dest; - } -} - -#define sym_que_entry(ptr, type, member) container_of(ptr, type, member) - -#define sym_insque(new, pos) __sym_que_add(new, pos, (pos)->flink) - -#define sym_remque(el) __sym_que_del((el)->blink, (el)->flink) - -#define sym_insque_head(new, head) __sym_que_add(new, head, (head)->flink) - -static inline struct sym_quehead *sym_remque_head(struct sym_quehead *head) -{ - struct sym_quehead *elem = head->flink; - - if (elem != head) - __sym_que_del(head, elem->flink); - else - elem = NULL; - return elem; -} - -#define sym_insque_tail(new, head) __sym_que_add(new, (head)->blink, head) - -static inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head) -{ - struct sym_quehead *elem = head->blink; - - if (elem != head) - __sym_que_del(elem->blink, head); - else - elem = 0; - return elem; -} - -/* - * This one may be useful. - */ -#define FOR_EACH_QUEUED_ELEMENT(head, qp) \ - for (qp = (head)->flink; qp != (head); qp = qp->flink) -/* - * FreeBSD does not offer our kind of queue in the CAM CCB. - * So, we have to cast. - */ -#define sym_qptr(p) ((struct sym_quehead *) (p)) - -/* - * Simple bitmap operations. - */ -#define sym_set_bit(p, n) (((u32 *)(p))[(n)>>5] |= (1<<((n)&0x1f))) -#define sym_clr_bit(p, n) (((u32 *)(p))[(n)>>5] &= ~(1<<((n)&0x1f))) -#define sym_is_bit(p, n) (((u32 *)(p))[(n)>>5] & (1<<((n)&0x1f))) - -/* - * The below round up/down macros are to be used with a constant - * as argument (sizeof(...) for example), for the compiler to - * optimize the whole thing. - */ -#define _U_(a,m) (a)<=(1< - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "sym_glue.h" -#include "sym_nvram.h" - -#ifdef SYM_CONF_DEBUG_NVRAM -static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120}; -#endif - -/* - * Get host setup from NVRAM. - */ -void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) -{ - /* - * Get parity checking, host ID, verbose mode - * and miscellaneous host flags from NVRAM. - */ - switch (nvram->type) { - case SYM_SYMBIOS_NVRAM: - if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE)) - np->rv_scntl0 &= ~0x0a; - np->myaddr = nvram->data.Symbios.host_id & 0x0f; - if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS) - np->verbose += 1; - if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO) - shost->reverse_ordering = 1; - if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET) - np->usrflags |= SYM_AVOID_BUS_RESET; - break; - case SYM_TEKRAM_NVRAM: - np->myaddr = nvram->data.Tekram.host_id & 0x0f; - break; -#ifdef CONFIG_PARISC - case SYM_PARISC_PDC: - if (nvram->data.parisc.host_id != -1) - np->myaddr = nvram->data.parisc.host_id; - if (nvram->data.parisc.factor != -1) - np->minsync = nvram->data.parisc.factor; - if (nvram->data.parisc.width != -1) - np->maxwide = nvram->data.parisc.width; - switch (nvram->data.parisc.mode) { - case 0: np->scsi_mode = SMODE_SE; break; - case 1: np->scsi_mode = SMODE_HVD; break; - case 2: np->scsi_mode = SMODE_LVD; break; - default: break; - } -#endif - default: - break; - } -} - -/* - * Get target set-up from Symbios format NVRAM. - */ -static void -sym_Symbios_setup_target(struct sym_tcb *tp, int target, Symbios_nvram *nvram) -{ - Symbios_target *tn = &nvram->target[target]; - - if (!(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)) - tp->usrtags = 0; - if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE)) - tp->usrflags &= ~SYM_DISC_ENABLED; - if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)) - tp->usrflags |= SYM_SCAN_BOOT_DISABLED; - if (!(tn->flags & SYMBIOS_SCAN_LUNS)) - tp->usrflags |= SYM_SCAN_LUNS_DISABLED; - tp->usr_period = (tn->sync_period + 3) / 4; - tp->usr_width = (tn->bus_width == 0x8) ? 0 : 1; -} - -static const unsigned char Tekram_sync[16] = { - 25, 31, 37, 43, 50, 62, 75, 125, 12, 15, 18, 21, 6, 7, 9, 10 -}; - -/* - * Get target set-up from Tekram format NVRAM. - */ -static void -sym_Tekram_setup_target(struct sym_tcb *tp, int target, Tekram_nvram *nvram) -{ - struct Tekram_target *tn = &nvram->target[target]; - - if (tn->flags & TEKRAM_TAGGED_COMMANDS) { - tp->usrtags = 2 << nvram->max_tags_index; - } - - if (tn->flags & TEKRAM_DISCONNECT_ENABLE) - tp->usrflags |= SYM_DISC_ENABLED; - - if (tn->flags & TEKRAM_SYNC_NEGO) - tp->usr_period = Tekram_sync[tn->sync_index & 0xf]; - tp->usr_width = (tn->flags & TEKRAM_WIDE_NEGO) ? 1 : 0; -} - -/* - * Get target setup from NVRAM. - */ -void sym_nvram_setup_target(struct sym_tcb *tp, int target, struct sym_nvram *nvp) -{ - switch (nvp->type) { - case SYM_SYMBIOS_NVRAM: - sym_Symbios_setup_target(tp, target, &nvp->data.Symbios); - break; - case SYM_TEKRAM_NVRAM: - sym_Tekram_setup_target(tp, target, &nvp->data.Tekram); - break; - default: - break; - } -} - -#ifdef SYM_CONF_DEBUG_NVRAM -/* - * Dump Symbios format NVRAM for debugging purpose. - */ -static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) -{ - int i; - - /* display Symbios nvram host data */ - printf("%s: HOST ID=%d%s%s%s%s%s%s\n", - sym_name(np), nvram->host_id & 0x0f, - (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", - (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", - (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", - (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", - (nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET" :"", - (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); - - /* display Symbios nvram drive data */ - for (i = 0 ; i < 15 ; i++) { - struct Symbios_target *tn = &nvram->target[i]; - printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", - sym_name(np), i, - (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", - (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", - (tn->flags & SYMBIOS_SCAN_LUNS) ? " SCAN_LUNS" : "", - (tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ" : "", - tn->bus_width, - tn->sync_period / 4, - tn->timeout); - } -} - -/* - * Dump TEKRAM format NVRAM for debugging purpose. - */ -static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) -{ - int i, tags, boot_delay; - char *rem; - - /* display Tekram nvram host data */ - tags = 2 << nvram->max_tags_index; - boot_delay = 0; - if (nvram->boot_delay_index < 6) - boot_delay = Tekram_boot_delay[nvram->boot_delay_index]; - switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) { - default: - case 0: rem = ""; break; - case 1: rem = " REMOVABLE=boot device"; break; - case 2: rem = " REMOVABLE=all"; break; - } - - printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", - sym_name(np), nvram->host_id & 0x0f, - (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", - (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"", - (nvram->flags & TEKRAM_DRIVES_SUP_1GB) ? " >1GB" :"", - (nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET" :"", - (nvram->flags & TEKRAM_ACTIVE_NEGATION) ? " ACT_NEG" :"", - (nvram->flags & TEKRAM_IMMEDIATE_SEEK) ? " IMM_SEEK" :"", - (nvram->flags & TEKRAM_SCAN_LUNS) ? " SCAN_LUNS" :"", - (nvram->flags1 & TEKRAM_F2_F6_ENABLED) ? " F2_F6" :"", - rem, boot_delay, tags); - - /* display Tekram nvram drive data */ - for (i = 0; i <= 15; i++) { - int sync, j; - struct Tekram_target *tn = &nvram->target[i]; - j = tn->sync_index & 0xf; - sync = Tekram_sync[j]; - printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n", - sym_name(np), i, - (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", - (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", - (tn->flags & TEKRAM_DISCONNECT_ENABLE) ? " DISC" : "", - (tn->flags & TEKRAM_START_CMD) ? " START" : "", - (tn->flags & TEKRAM_TAGGED_COMMANDS) ? " TCQ" : "", - (tn->flags & TEKRAM_WIDE_NEGO) ? " WIDE" : "", - sync); - } -} -#else -static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; } -static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; } -#endif /* SYM_CONF_DEBUG_NVRAM */ - - -/* - * 24C16 EEPROM reading. - * - * GPOI0 - data in/data out - * GPIO1 - clock - * Symbios NVRAM wiring now also used by Tekram. - */ - -#define SET_BIT 0 -#define CLR_BIT 1 -#define SET_CLK 2 -#define CLR_CLK 3 - -/* - * Set/clear data/clock bit in GPIO0 - */ -static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg, - int bit_mode) -{ - udelay(5); - switch (bit_mode) { - case SET_BIT: - *gpreg |= write_bit; - break; - case CLR_BIT: - *gpreg &= 0xfe; - break; - case SET_CLK: - *gpreg |= 0x02; - break; - case CLR_CLK: - *gpreg &= 0xfd; - break; - - } - OUTB(np, nc_gpreg, *gpreg); - INB(np, nc_mbox1); - udelay(5); -} - -/* - * Send START condition to NVRAM to wake it up. - */ -static void S24C16_start(struct sym_device *np, u_char *gpreg) -{ - S24C16_set_bit(np, 1, gpreg, SET_BIT); - S24C16_set_bit(np, 0, gpreg, SET_CLK); - S24C16_set_bit(np, 0, gpreg, CLR_BIT); - S24C16_set_bit(np, 0, gpreg, CLR_CLK); -} - -/* - * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!! - */ -static void S24C16_stop(struct sym_device *np, u_char *gpreg) -{ - S24C16_set_bit(np, 0, gpreg, SET_CLK); - S24C16_set_bit(np, 1, gpreg, SET_BIT); -} - -/* - * Read or write a bit to the NVRAM, - * read if GPIO0 input else write if GPIO0 output - */ -static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit, - u_char *gpreg) -{ - S24C16_set_bit(np, write_bit, gpreg, SET_BIT); - S24C16_set_bit(np, 0, gpreg, SET_CLK); - if (read_bit) - *read_bit = INB(np, nc_gpreg); - S24C16_set_bit(np, 0, gpreg, CLR_CLK); - S24C16_set_bit(np, 0, gpreg, CLR_BIT); -} - -/* - * Output an ACK to the NVRAM after reading, - * change GPIO0 to output and when done back to an input - */ -static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg, - u_char *gpcntl) -{ - OUTB(np, nc_gpcntl, *gpcntl & 0xfe); - S24C16_do_bit(np, NULL, write_bit, gpreg); - OUTB(np, nc_gpcntl, *gpcntl); -} - -/* - * Input an ACK from NVRAM after writing, - * change GPIO0 to input and when done back to an output - */ -static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg, - u_char *gpcntl) -{ - OUTB(np, nc_gpcntl, *gpcntl | 0x01); - S24C16_do_bit(np, read_bit, 1, gpreg); - OUTB(np, nc_gpcntl, *gpcntl); -} - -/* - * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK, - * GPIO0 must already be set as an output - */ -static void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data, - u_char *gpreg, u_char *gpcntl) -{ - int x; - - for (x = 0; x < 8; x++) - S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg); - - S24C16_read_ack(np, ack_data, gpreg, gpcntl); -} - -/* - * READ a byte from the NVRAM and then send an ACK to say we have got it, - * GPIO0 must already be set as an input - */ -static void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data, - u_char *gpreg, u_char *gpcntl) -{ - int x; - u_char read_bit; - - *read_data = 0; - for (x = 0; x < 8; x++) { - S24C16_do_bit(np, &read_bit, 1, gpreg); - *read_data |= ((read_bit & 0x01) << (7 - x)); - } - - S24C16_write_ack(np, ack_data, gpreg, gpcntl); -} - -#ifdef SYM_CONF_NVRAM_WRITE_SUPPORT -/* - * Write 'len' bytes starting at 'offset'. - */ -static int sym_write_S24C16_nvram(struct sym_device *np, int offset, - u_char *data, int len) -{ - u_char gpcntl, gpreg; - u_char old_gpcntl, old_gpreg; - u_char ack_data; - int x; - - /* save current state of GPCNTL and GPREG */ - old_gpreg = INB(np, nc_gpreg); - old_gpcntl = INB(np, nc_gpcntl); - gpcntl = old_gpcntl & 0x1c; - - /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ - OUTB(np, nc_gpreg, old_gpreg); - OUTB(np, nc_gpcntl, gpcntl); - - /* this is to set NVRAM into a known state with GPIO0/1 both low */ - gpreg = old_gpreg; - S24C16_set_bit(np, 0, &gpreg, CLR_CLK); - S24C16_set_bit(np, 0, &gpreg, CLR_BIT); - - /* now set NVRAM inactive with GPIO0/1 both high */ - S24C16_stop(np, &gpreg); - - /* NVRAM has to be written in segments of 16 bytes */ - for (x = 0; x < len ; x += 16) { - do { - S24C16_start(np, &gpreg); - S24C16_write_byte(np, &ack_data, - 0xa0 | (((offset+x) >> 7) & 0x0e), - &gpreg, &gpcntl); - } while (ack_data & 0x01); - - S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, - &gpreg, &gpcntl); - - for (y = 0; y < 16; y++) - S24C16_write_byte(np, &ack_data, data[x+y], - &gpreg, &gpcntl); - S24C16_stop(np, &gpreg); - } - - /* return GPIO0/1 to original states after having accessed NVRAM */ - OUTB(np, nc_gpcntl, old_gpcntl); - OUTB(np, nc_gpreg, old_gpreg); - - return 0; -} -#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */ - -/* - * Read 'len' bytes starting at 'offset'. - */ -static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len) -{ - u_char gpcntl, gpreg; - u_char old_gpcntl, old_gpreg; - u_char ack_data; - int retv = 1; - int x; - - /* save current state of GPCNTL and GPREG */ - old_gpreg = INB(np, nc_gpreg); - old_gpcntl = INB(np, nc_gpcntl); - gpcntl = old_gpcntl & 0x1c; - - /* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */ - OUTB(np, nc_gpreg, old_gpreg); - OUTB(np, nc_gpcntl, gpcntl); - - /* this is to set NVRAM into a known state with GPIO0/1 both low */ - gpreg = old_gpreg; - S24C16_set_bit(np, 0, &gpreg, CLR_CLK); - S24C16_set_bit(np, 0, &gpreg, CLR_BIT); - - /* now set NVRAM inactive with GPIO0/1 both high */ - S24C16_stop(np, &gpreg); - - /* activate NVRAM */ - S24C16_start(np, &gpreg); - - /* write device code and random address MSB */ - S24C16_write_byte(np, &ack_data, - 0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); - if (ack_data & 0x01) - goto out; - - /* write random address LSB */ - S24C16_write_byte(np, &ack_data, - offset & 0xff, &gpreg, &gpcntl); - if (ack_data & 0x01) - goto out; - - /* regenerate START state to set up for reading */ - S24C16_start(np, &gpreg); - - /* rewrite device code and address MSB with read bit set (lsb = 0x01) */ - S24C16_write_byte(np, &ack_data, - 0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl); - if (ack_data & 0x01) - goto out; - - /* now set up GPIO0 for inputting data */ - gpcntl |= 0x01; - OUTB(np, nc_gpcntl, gpcntl); - - /* input all requested data - only part of total NVRAM */ - for (x = 0; x < len; x++) - S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl); - - /* finally put NVRAM back in inactive mode */ - gpcntl &= 0xfe; - OUTB(np, nc_gpcntl, gpcntl); - S24C16_stop(np, &gpreg); - retv = 0; -out: - /* return GPIO0/1 to original states after having accessed NVRAM */ - OUTB(np, nc_gpcntl, old_gpcntl); - OUTB(np, nc_gpreg, old_gpreg); - - return retv; -} - -#undef SET_BIT -#undef CLR_BIT -#undef SET_CLK -#undef CLR_CLK - -/* - * Try reading Symbios NVRAM. - * Return 0 if OK. - */ -static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) -{ - static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0}; - u_char *data = (u_char *) nvram; - int len = sizeof(*nvram); - u_short csum; - int x; - - /* probe the 24c16 and read the SYMBIOS 24c16 area */ - if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len)) - return 1; - - /* check valid NVRAM signature, verify byte count and checksum */ - if (nvram->type != 0 || - memcmp(nvram->trailer, Symbios_trailer, 6) || - nvram->byte_count != len - 12) - return 1; - - /* verify checksum */ - for (x = 6, csum = 0; x < len - 6; x++) - csum += data[x]; - if (csum != nvram->checksum) - return 1; - - return 0; -} - -/* - * 93C46 EEPROM reading. - * - * GPOI0 - data in - * GPIO1 - data out - * GPIO2 - clock - * GPIO4 - chip select - * - * Used by Tekram. - */ - -/* - * Pulse clock bit in GPIO0 - */ -static void T93C46_Clk(struct sym_device *np, u_char *gpreg) -{ - OUTB(np, nc_gpreg, *gpreg | 0x04); - INB(np, nc_mbox1); - udelay(2); - OUTB(np, nc_gpreg, *gpreg); -} - -/* - * Read bit from NVRAM - */ -static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg) -{ - udelay(2); - T93C46_Clk(np, gpreg); - *read_bit = INB(np, nc_gpreg); -} - -/* - * Write bit to GPIO0 - */ -static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg) -{ - if (write_bit & 0x01) - *gpreg |= 0x02; - else - *gpreg &= 0xfd; - - *gpreg |= 0x10; - - OUTB(np, nc_gpreg, *gpreg); - INB(np, nc_mbox1); - udelay(2); - - T93C46_Clk(np, gpreg); -} - -/* - * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!! - */ -static void T93C46_Stop(struct sym_device *np, u_char *gpreg) -{ - *gpreg &= 0xef; - OUTB(np, nc_gpreg, *gpreg); - INB(np, nc_mbox1); - udelay(2); - - T93C46_Clk(np, gpreg); -} - -/* - * Send read command and address to NVRAM - */ -static void T93C46_Send_Command(struct sym_device *np, u_short write_data, - u_char *read_bit, u_char *gpreg) -{ - int x; - - /* send 9 bits, start bit (1), command (2), address (6) */ - for (x = 0; x < 9; x++) - T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg); - - *read_bit = INB(np, nc_gpreg); -} - -/* - * READ 2 bytes from the NVRAM - */ -static void T93C46_Read_Word(struct sym_device *np, - unsigned short *nvram_data, unsigned char *gpreg) -{ - int x; - u_char read_bit; - - *nvram_data = 0; - for (x = 0; x < 16; x++) { - T93C46_Read_Bit(np, &read_bit, gpreg); - - if (read_bit & 0x01) - *nvram_data |= (0x01 << (15 - x)); - else - *nvram_data &= ~(0x01 << (15 - x)); - } -} - -/* - * Read Tekram NvRAM data. - */ -static int T93C46_Read_Data(struct sym_device *np, unsigned short *data, - int len, unsigned char *gpreg) -{ - int x; - - for (x = 0; x < len; x++) { - unsigned char read_bit; - /* output read command and address */ - T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg); - if (read_bit & 0x01) - return 1; /* Bad */ - T93C46_Read_Word(np, &data[x], gpreg); - T93C46_Stop(np, gpreg); - } - - return 0; -} - -/* - * Try reading 93C46 Tekram NVRAM. - */ -static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram) -{ - u_char gpcntl, gpreg; - u_char old_gpcntl, old_gpreg; - int retv = 1; - - /* save current state of GPCNTL and GPREG */ - old_gpreg = INB(np, nc_gpreg); - old_gpcntl = INB(np, nc_gpcntl); - - /* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in, - 1/2/4 out */ - gpreg = old_gpreg & 0xe9; - OUTB(np, nc_gpreg, gpreg); - gpcntl = (old_gpcntl & 0xe9) | 0x09; - OUTB(np, nc_gpcntl, gpcntl); - - /* input all of NVRAM, 64 words */ - retv = T93C46_Read_Data(np, (u_short *) nvram, - sizeof(*nvram) / sizeof(short), &gpreg); - - /* return GPIO0/1/2/4 to original states after having accessed NVRAM */ - OUTB(np, nc_gpcntl, old_gpcntl); - OUTB(np, nc_gpreg, old_gpreg); - - return retv; -} - -/* - * Try reading Tekram NVRAM. - * Return 0 if OK. - */ -static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram) -{ - u_char *data = (u_char *) nvram; - int len = sizeof(*nvram); - u_short csum; - int x; - - switch (np->pdev->device) { - case PCI_DEVICE_ID_NCR_53C885: - case PCI_DEVICE_ID_NCR_53C895: - case PCI_DEVICE_ID_NCR_53C896: - x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, - data, len); - break; - case PCI_DEVICE_ID_NCR_53C875: - x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS, - data, len); - if (!x) - break; - default: - x = sym_read_T93C46_nvram(np, nvram); - break; - } - if (x) - return 1; - - /* verify checksum */ - for (x = 0, csum = 0; x < len - 1; x += 2) - csum += data[x] + (data[x+1] << 8); - if (csum != 0x1234) - return 1; - - return 0; -} - -#ifdef CONFIG_PARISC -/* - * Host firmware (PDC) keeps a table for altering SCSI capabilities. - * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD. - * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID. - */ -static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc) -{ - struct hardware_path hwpath; - get_pci_node_path(np->pdev, &hwpath); - if (!pdc_get_initiator(&hwpath, pdc)) - return 0; - - return SYM_PARISC_PDC; -} -#else -static inline int sym_read_parisc_pdc(struct sym_device *np, - struct pdc_initiator *x) -{ - return 0; -} -#endif - -/* - * Try reading Symbios or Tekram NVRAM - */ -int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) -{ - if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) { - nvp->type = SYM_SYMBIOS_NVRAM; - sym_display_Symbios_nvram(np, &nvp->data.Symbios); - } else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) { - nvp->type = SYM_TEKRAM_NVRAM; - sym_display_Tekram_nvram(np, &nvp->data.Tekram); - } else { - nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc); - } - return nvp->type; -} - -char *sym_nvram_type(struct sym_nvram *nvp) -{ - switch (nvp->type) { - case SYM_SYMBIOS_NVRAM: - return "Symbios NVRAM"; - case SYM_TEKRAM_NVRAM: - return "Tekram NVRAM"; - case SYM_PARISC_PDC: - return "PA-RISC Firmware"; - default: - return "No NVRAM"; - } -} diff --git a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_nvram.h b/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_nvram.h deleted file mode 100644 index bdfbbb08..00000000 --- a/ANDROID_3.4.5/drivers/scsi/sym53c8xx_2/sym_nvram.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family - * of PCI-SCSI IO processors. - * - * Copyright (C) 1999-2001 Gerard Roudier - * - * This driver is derived from the Linux sym53c8xx driver. - * Copyright (C) 1998-2000 Gerard Roudier - * - * The sym53c8xx driver is derived from the ncr53c8xx driver that had been - * a port of the FreeBSD ncr driver to Linux-1.2.13. - * - * The original ncr driver has been written for 386bsd and FreeBSD by - * Wolfgang Stanglmeier - * Stefan Esser - * Copyright (C) 1994 Wolfgang Stanglmeier - * - * Other major contributions: - * - * NVRAM detection and reading. - * Copyright (C) 1997 Richard Waltham - * - *----------------------------------------------------------------------------- - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef SYM_NVRAM_H -#define SYM_NVRAM_H - -#include "sym53c8xx.h" - -/* - * Symbios NVRAM data format - */ -#define SYMBIOS_NVRAM_SIZE 368 -#define SYMBIOS_NVRAM_ADDRESS 0x100 - -struct Symbios_nvram { -/* Header 6 bytes */ - u_short type; /* 0x0000 */ - u_short byte_count; /* excluding header/trailer */ - u_short checksum; - -/* Controller set up 20 bytes */ - u_char v_major; /* 0x00 */ - u_char v_minor; /* 0x30 */ - u32 boot_crc; - u_short flags; -#define SYMBIOS_SCAM_ENABLE (1) -#define SYMBIOS_PARITY_ENABLE (1<<1) -#define SYMBIOS_VERBOSE_MSGS (1<<2) -#define SYMBIOS_CHS_MAPPING (1<<3) -#define SYMBIOS_NO_NVRAM (1<<3) /* ??? */ - u_short flags1; -#define SYMBIOS_SCAN_HI_LO (1) - u_short term_state; -#define SYMBIOS_TERM_CANT_PROGRAM (0) -#define SYMBIOS_TERM_ENABLED (1) -#define SYMBIOS_TERM_DISABLED (2) - u_short rmvbl_flags; -#define SYMBIOS_RMVBL_NO_SUPPORT (0) -#define SYMBIOS_RMVBL_BOOT_DEVICE (1) -#define SYMBIOS_RMVBL_MEDIA_INSTALLED (2) - u_char host_id; - u_char num_hba; /* 0x04 */ - u_char num_devices; /* 0x10 */ - u_char max_scam_devices; /* 0x04 */ - u_char num_valid_scam_devices; /* 0x00 */ - u_char flags2; -#define SYMBIOS_AVOID_BUS_RESET (1<<2) - -/* Boot order 14 bytes * 4 */ - struct Symbios_host{ - u_short type; /* 4:8xx / 0:nok */ - u_short device_id; /* PCI device id */ - u_short vendor_id; /* PCI vendor id */ - u_char bus_nr; /* PCI bus number */ - u_char device_fn; /* PCI device/function number << 3*/ - u_short word8; - u_short flags; -#define SYMBIOS_INIT_SCAN_AT_BOOT (1) - u_short io_port; /* PCI io_port address */ - } host[4]; - -/* Targets 8 bytes * 16 */ - struct Symbios_target { - u_char flags; -#define SYMBIOS_DISCONNECT_ENABLE (1) -#define SYMBIOS_SCAN_AT_BOOT_TIME (1<<1) -#define SYMBIOS_SCAN_LUNS (1<<2) -#define SYMBIOS_QUEUE_TAGS_ENABLED (1<<3) - u_char rsvd; - u_char bus_width; /* 0x08/0x10 */ - u_char sync_offset; - u_short sync_period; /* 4*period factor */ - u_short timeout; - } target[16]; -/* Scam table 8 bytes * 4 */ - struct Symbios_scam { - u_short id; - u_short method; -#define SYMBIOS_SCAM_DEFAULT_METHOD (0) -#define SYMBIOS_SCAM_DONT_ASSIGN (1) -#define SYMBIOS_SCAM_SET_SPECIFIC_ID (2) -#define SYMBIOS_SCAM_USE_ORDER_GIVEN (3) - u_short status; -#define SYMBIOS_SCAM_UNKNOWN (0) -#define SYMBIOS_SCAM_DEVICE_NOT_FOUND (1) -#define SYMBIOS_SCAM_ID_NOT_SET (2) -#define SYMBIOS_SCAM_ID_VALID (3) - u_char target_id; - u_char rsvd; - } scam[4]; - - u_char spare_devices[15*8]; - u_char trailer[6]; /* 0xfe 0xfe 0x00 0x00 0x00 0x00 */ -}; -typedef struct Symbios_nvram Symbios_nvram; -typedef struct Symbios_host Symbios_host; -typedef struct Symbios_target Symbios_target; -typedef struct Symbios_scam Symbios_scam; - -/* - * Tekram NvRAM data format. - */ -#define TEKRAM_NVRAM_SIZE 64 -#define TEKRAM_93C46_NVRAM_ADDRESS 0 -#define TEKRAM_24C16_NVRAM_ADDRESS 0x40 - -struct Tekram_nvram { - struct Tekram_target { - u_char flags; -#define TEKRAM_PARITY_CHECK (1) -#define TEKRAM_SYNC_NEGO (1<<1) -#define TEKRAM_DISCONNECT_ENABLE (1<<2) -#define TEKRAM_START_CMD (1<<3) -#define TEKRAM_TAGGED_COMMANDS (1<<4) -#define TEKRAM_WIDE_NEGO (1<<5) - u_char sync_index; - u_short word2; - } target[16]; - u_char host_id; - u_char flags; -#define TEKRAM_MORE_THAN_2_DRIVES (1) -#define TEKRAM_DRIVES_SUP_1GB (1<<1) -#define TEKRAM_RESET_ON_POWER_ON (1<<2) -#define TEKRAM_ACTIVE_NEGATION (1<<3) -#define TEKRAM_IMMEDIATE_SEEK (1<<4) -#define TEKRAM_SCAN_LUNS (1<<5) -#define TEKRAM_REMOVABLE_FLAGS (3<<6) /* 0: disable; */ - /* 1: boot device; 2:all */ - u_char boot_delay_index; - u_char max_tags_index; - u_short flags1; -#define TEKRAM_F2_F6_ENABLED (1) - u_short spare[29]; -}; -typedef struct Tekram_nvram Tekram_nvram; -typedef struct Tekram_target Tekram_target; - -#ifndef CONFIG_PARISC -struct pdc_initiator { int dummy; }; -#endif - -/* - * Union of supported NVRAM formats. - */ -struct sym_nvram { - int type; -#define SYM_SYMBIOS_NVRAM (1) -#define SYM_TEKRAM_NVRAM (2) -#define SYM_PARISC_PDC (3) -#if SYM_CONF_NVRAM_SUPPORT - union { - Symbios_nvram Symbios; - Tekram_nvram Tekram; - struct pdc_initiator parisc; - } data; -#endif -}; - -#if SYM_CONF_NVRAM_SUPPORT -void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram); -void sym_nvram_setup_target (struct sym_tcb *tp, int target, struct sym_nvram *nvp); -int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp); -char *sym_nvram_type(struct sym_nvram *nvp); -#else -static inline void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) { } -static inline void sym_nvram_setup_target(struct sym_tcb *tp, struct sym_nvram *nvram) { } -static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp) -{ - nvp->type = 0; - return 0; -} -static inline char *sym_nvram_type(struct sym_nvram *nvp) -{ - return "No NVRAM"; -} -#endif - -#endif /* SYM_NVRAM_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/t128.c b/ANDROID_3.4.5/drivers/scsi/t128.c deleted file mode 100644 index d672d97f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/t128.c +++ /dev/null @@ -1,446 +0,0 @@ -#define AUTOSENSE -#define PSEUDO_DMA - -/* - * Trantor T128/T128F/T228 driver - * Note : architecturally, the T100 and T130 are different and won't - * work - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * DISTRIBUTION RELEASE 3. - * - * For more information, please consult - * - * Trantor Systems, Ltd. - * T128/T128F/T228 SCSI Host Adapter - * Hardware Specifications - * - * Trantor Systems, Ltd. - * 5415 Randall Place - * Fremont, CA 94538 - * 1+ (415) 770-1400, FAX 1+ (415) 770-9910 - * - * and - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * Options : - * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically - * for commands that return with a CHECK CONDITION status. - * - * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance - * increase compared to polled I/O. - * - * PARITY - enable parity checking. Not supported. - * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * - * - * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You - * only really want to use this if you're having a problem with - * dropped characters during high speed communications, and even - * then, you're going to be better off twiddling with transfersize. - * - * USLEEP - enable support for devices that don't disconnect. Untested. - * - * The card is detected and initialized in one of several ways : - * 1. Autoprobe (default) - since the board is memory mapped, - * a BIOS signature is scanned for to locate the registers. - * An interrupt is triggered to autoprobe for the interrupt - * line. - * - * 2. With command line overrides - t128=address,irq may be - * used on the LILO command line to override the defaults. - * - * 3. With the T128_OVERRIDE compile time define. This is - * specified as an array of address, irq tuples. Ie, for - * one board at the default 0xcc000 address, IRQ5, I could say - * -DT128_OVERRIDE={{0xcc000, 5}} - * - * Note that if the override methods are used, place holders must - * be specified for other boards in the system. - * - * T128/T128F jumper/dipswitch settings (note : on my sample, the switches - * were epoxy'd shut, meaning I couldn't change the 0xcc000 base address) : - * - * T128 Sw7 Sw8 Sw6 = 0ws Sw5 = boot - * T128F Sw6 Sw7 Sw5 = 0ws Sw4 = boot Sw8 = floppy disable - * cc000 off off - * c8000 off on - * dc000 on off - * d8000 on on - * - * - * Interrupts - * There is a 12 pin jumper block, jp1, numbered as follows : - * T128 (JP1) T128F (J5) - * 2 4 6 8 10 12 11 9 7 5 3 1 - * 1 3 5 7 9 11 12 10 8 6 4 2 - * - * 3 2-4 - * 5 1-3 - * 7 3-5 - * T128F only - * 10 8-10 - * 12 7-9 - * 14 10-12 - * 15 9-11 - */ - -/* - * $Log: t128.c,v $ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "scsi.h" -#include -#include "t128.h" -#define AUTOPROBE_IRQ -#include "NCR5380.h" - -static struct override { - unsigned long address; - int irq; -} overrides -#ifdef T128_OVERRIDE - [] __initdata = T128_OVERRIDE; -#else - [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, - {0 ,IRQ_AUTO}, {0, IRQ_AUTO}}; -#endif - -#define NO_OVERRIDES ARRAY_SIZE(overrides) - -static struct base { - unsigned int address; - int noauto; -} bases[] __initdata = { - { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0} -}; - -#define NO_BASES ARRAY_SIZE(bases) - -static struct signature { - const char *string; - int offset; -} signatures[] __initdata = { -{"TSROM: SCSI BIOS, Version 1.12", 0x36}, -}; - -#define NO_SIGNATURES ARRAY_SIZE(signatures) - -/* - * Function : t128_setup(char *str, int *ints) - * - * Purpose : LILO command line initialization of the overrides array, - * - * Inputs : str - unused, ints - array of integer parameters with ints[0] - * equal to the number of ints. - * - */ - -void __init t128_setup(char *str, int *ints){ - static int commandline_current = 0; - int i; - if (ints[0] != 2) - printk("t128_setup : usage t128=address,irq\n"); - else - if (commandline_current < NO_OVERRIDES) { - overrides[commandline_current].address = ints[1]; - overrides[commandline_current].irq = ints[2]; - for (i = 0; i < NO_BASES; ++i) - if (bases[i].address == ints[1]) { - bases[i].noauto = 1; - break; - } - ++commandline_current; - } -} - -/* - * Function : int t128_detect(struct scsi_host_template * tpnt) - * - * Purpose : detects and initializes T128,T128F, or T228 controllers - * that were autoprobed, overridden on the LILO command line, - * or specified at compile time. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * - */ - -int __init t128_detect(struct scsi_host_template * tpnt){ - static int current_override = 0, current_base = 0; - struct Scsi_Host *instance; - unsigned long base; - void __iomem *p; - int sig, count; - - tpnt->proc_name = "t128"; - tpnt->proc_info = &t128_proc_info; - - for (count = 0; current_override < NO_OVERRIDES; ++current_override) { - base = 0; - p = NULL; - - if (overrides[current_override].address) { - base = overrides[current_override].address; - p = ioremap(bases[current_base].address, 0x2000); - if (!p) - base = 0; - } else - for (; !base && (current_base < NO_BASES); ++current_base) { -#if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : probing address %08x\n", bases[current_base].address); -#endif - if (bases[current_base].noauto) - continue; - p = ioremap(bases[current_base].address, 0x2000); - if (!p) - continue; - for (sig = 0; sig < NO_SIGNATURES; ++sig) - if (check_signature(p + signatures[sig].offset, - signatures[sig].string, - strlen(signatures[sig].string))) { - base = bases[current_base].address; -#if (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : detected board.\n"); -#endif - goto found; - } - iounmap(p); - } - -#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) - printk("scsi-t128 : base = %08x\n", (unsigned int) base); -#endif - - if (!base) - break; - -found: - instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if(instance == NULL) - break; - - instance->base = base; - ((struct NCR5380_hostdata *)instance->hostdata)->base = p; - - NCR5380_init(instance, 0); - - if (overrides[current_override].irq != IRQ_AUTO) - instance->irq = overrides[current_override].irq; - else - instance->irq = NCR5380_probe_irq(instance, T128_IRQS); - - if (instance->irq != SCSI_IRQ_NONE) - if (request_irq(instance->irq, t128_intr, IRQF_DISABLED, "t128", - instance)) { - printk("scsi%d : IRQ%d not free, interrupts disabled\n", - instance->host_no, instance->irq); - instance->irq = SCSI_IRQ_NONE; - } - - if (instance->irq == SCSI_IRQ_NONE) { - printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } - -#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT) - printk("scsi%d : irq = %d\n", instance->host_no, instance->irq); -#endif - - printk("scsi%d : at 0x%08lx", instance->host_no, instance->base); - if (instance->irq == SCSI_IRQ_NONE) - printk (" interrupts disabled"); - else - printk (" irq %d", instance->irq); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE); - NCR5380_print_options(instance); - printk("\n"); - - ++current_override; - ++count; - } - return count; -} - -static int t128_release(struct Scsi_Host *shost) -{ - NCR5380_local_declare(); - NCR5380_setup(shost); - if (shost->irq) - free_irq(shost->irq, shost); - NCR5380_exit(shost); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - iounmap(base); - return 0; -} - -/* - * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip) - * - * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for - * the specified device / size. - * - * Inputs : size = size of device in sectors (512 bytes), dev = block device - * major / minor, ip[] = {heads, sectors, cylinders} - * - * Returns : always 0 (success), initializes ip - * - */ - -/* - * XXX Most SCSI boards use this mapping, I could be incorrect. Some one - * using hard disks on a trantor should verify that this mapping corresponds - * to that used by the BIOS / ASPI driver by running the linux fdisk program - * and matching the H_C_S coordinates to what DOS uses. - */ - -int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int * ip) -{ - ip[0] = 64; - ip[1] = 32; - ip[2] = capacity >> 11; - return 0; -} - -/* - * Function : int NCR5380_pread (struct Scsi_Host *instance, - * unsigned char *dst, int len) - * - * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to - * dst - * - * Inputs : dst = destination, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. - */ - -static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst, - int len) { - NCR5380_local_declare(); - void __iomem *reg; - unsigned char *d = dst; - register int i = len; - - NCR5380_setup(instance); - reg = base + T_DATA_REG_OFFSET; - -#if 0 - for (; i; --i) { - while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); -#else - while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); - for (; i; --i) { -#endif - *d++ = readb(reg); - } - - if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) { - unsigned char tmp; - void __iomem *foo = base + T_CONTROL_REG_OFFSET; - tmp = readb(foo); - writeb(tmp | T_CR_CT, foo); - writeb(tmp, foo); - printk("scsi%d : watchdog timer fired in NCR5380_pread()\n", - instance->host_no); - return -1; - } else - return 0; -} - -/* - * Function : int NCR5380_pwrite (struct Scsi_Host *instance, - * unsigned char *src, int len) - * - * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from - * src - * - * Inputs : src = source, len = length in bytes - * - * Returns : 0 on success, non zero on a failure such as a watchdog - * timeout. - */ - -static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src, - int len) { - NCR5380_local_declare(); - void __iomem *reg; - unsigned char *s = src; - register int i = len; - - NCR5380_setup(instance); - reg = base + T_DATA_REG_OFFSET; - -#if 0 - for (; i; --i) { - while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); -#else - while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier(); - for (; i; --i) { -#endif - writeb(*s++, reg); - } - - if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) { - unsigned char tmp; - void __iomem *foo = base + T_CONTROL_REG_OFFSET; - tmp = readb(foo); - writeb(tmp | T_CR_CT, foo); - writeb(tmp, foo); - printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n", - instance->host_no); - return -1; - } else - return 0; -} - -MODULE_LICENSE("GPL"); - -#include "NCR5380.c" - -static struct scsi_host_template driver_template = { - .name = "Trantor T128/T128F/T228", - .detect = t128_detect, - .release = t128_release, - .queuecommand = t128_queue_command, - .eh_abort_handler = t128_abort, - .eh_bus_reset_handler = t128_bus_reset, - .bios_param = t128_biosparam, - .can_queue = CAN_QUEUE, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = CMD_PER_LUN, - .use_clustering = DISABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/t128.h b/ANDROID_3.4.5/drivers/scsi/t128.h deleted file mode 100644 index ada11150..00000000 --- a/ANDROID_3.4.5/drivers/scsi/t128.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Trantor T128/T128F/T228 defines - * Note : architecturally, the T100 and T128 are different and won't work - * - * Copyright 1993, Drew Eckhardt - * Visionary Computing - * (Unix and Linux consulting and custom programming) - * drew@colorado.edu - * +1 (303) 440-4894 - * - * DISTRIBUTION RELEASE 3. - * - * For more information, please consult - * - * Trantor Systems, Ltd. - * T128/T128F/T228 SCSI Host Adapter - * Hardware Specifications - * - * Trantor Systems, Ltd. - * 5415 Randall Place - * Fremont, CA 94538 - * 1+ (415) 770-1400, FAX 1+ (415) 770-9910 - * - * and - * - * NCR 5380 Family - * SCSI Protocol Controller - * Databook - * - * NCR Microelectronics - * 1635 Aeroplaza Drive - * Colorado Springs, CO 80916 - * 1+ (719) 578-3400 - * 1+ (800) 334-5454 - */ - -/* - * $Log: t128.h,v $ - */ - -#ifndef T128_H -#define T128_H - -#define T128_PUBLIC_RELEASE 3 - -#define TDEBUG 0 -#define TDEBUG_INIT 0x1 -#define TDEBUG_TRANSFER 0x2 - -/* - * The trantor boards are memory mapped. They use an NCR5380 or - * equivalent (my sample board had part second sourced from ZILOG). - * NCR's recommended "Pseudo-DMA" architecture is used, where - * a PAL drives the DMA signals on the 5380 allowing fast, blind - * transfers with proper handshaking. - */ - -/* - * Note : a boot switch is provided for the purpose of informing the - * firmware to boot or not boot from attached SCSI devices. So, I imagine - * there are fewer people who've yanked the ROM like they do on the Seagate - * to make bootup faster, and I'll probably use this for autodetection. - */ -#define T_ROM_OFFSET 0 - -/* - * Note : my sample board *WAS NOT* populated with the SRAM, so this - * can't be used for autodetection without a ROM present. - */ -#define T_RAM_OFFSET 0x1800 - -/* - * All of the registers are allocated 32 bytes of address space, except - * for the data register (read/write to/from the 5380 in pseudo-DMA mode) - */ -#define T_CONTROL_REG_OFFSET 0x1c00 /* rw */ -#define T_CR_INT 0x10 /* Enable interrupts */ -#define T_CR_CT 0x02 /* Reset watchdog timer */ - -#define T_STATUS_REG_OFFSET 0x1c20 /* ro */ -#define T_ST_BOOT 0x80 /* Boot switch */ -#define T_ST_S3 0x40 /* User settable switches, */ -#define T_ST_S2 0x20 /* read 0 when switch is on, 1 off */ -#define T_ST_S1 0x10 -#define T_ST_PS2 0x08 /* Set for Microchannel 228 */ -#define T_ST_RDY 0x04 /* 5380 DRQ */ -#define T_ST_TIM 0x02 /* indicates 40us watchdog timer fired */ -#define T_ST_ZERO 0x01 /* Always zero */ - -#define T_5380_OFFSET 0x1d00 /* 8 registers here, see NCR5380.h */ - -#define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */ - -#ifndef ASM -static int t128_abort(struct scsi_cmnd *); -static int t128_biosparam(struct scsi_device *, struct block_device *, - sector_t, int*); -static int t128_detect(struct scsi_host_template *); -static int t128_queue_command(struct Scsi_Host *, struct scsi_cmnd *); -static int t128_bus_reset(struct scsi_cmnd *); - -#ifndef CMD_PER_LUN -#define CMD_PER_LUN 2 -#endif - -#ifndef CAN_QUEUE -#define CAN_QUEUE 32 -#endif - -#ifndef HOSTS_C - -#define NCR5380_implementation_fields \ - void __iomem *base - -#define NCR5380_local_declare() \ - void __iomem *base - -#define NCR5380_setup(instance) \ - base = ((struct NCR5380_hostdata *)(instance->hostdata))->base - -#define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20)) - -#if !(TDEBUG & TDEBUG_TRANSFER) -#define NCR5380_read(reg) readb(T128_address(reg)) -#define NCR5380_write(reg, value) writeb((value),(T128_address(reg))) -#else -#define NCR5380_read(reg) \ - (((unsigned char) printk("scsi%d : read register %d at address %08x\n"\ - , instance->hostno, (reg), T128_address(reg))), readb(T128_address(reg))) - -#define NCR5380_write(reg, value) { \ - printk("scsi%d : write %02x to register %d at address %08x\n", \ - instance->hostno, (value), (reg), T128_address(reg)); \ - writeb((value), (T128_address(reg))); \ -} -#endif - -#define NCR5380_intr t128_intr -#define do_NCR5380_intr do_t128_intr -#define NCR5380_queue_command t128_queue_command -#define NCR5380_abort t128_abort -#define NCR5380_bus_reset t128_bus_reset -#define NCR5380_proc_info t128_proc_info - -/* 15 14 12 10 7 5 3 - 1101 0100 1010 1000 */ - -#define T128_IRQS 0xc4a8 - -#endif /* else def HOSTS_C */ -#endif /* ndef ASM */ -#endif /* T128_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/tmscsim.c b/ANDROID_3.4.5/drivers/scsi/tmscsim.c deleted file mode 100644 index a1baccce..00000000 --- a/ANDROID_3.4.5/drivers/scsi/tmscsim.c +++ /dev/null @@ -1,2622 +0,0 @@ -/************************************************************************ - * FILE NAME : TMSCSIM.C * - * BY : C.L. Huang, ching@tekram.com.tw * - * Description: Device Driver for Tekram DC-390(T) PCI SCSI * - * Bus Master Host Adapter * - * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. * - ************************************************************************ - * (C) Copyright: put under GNU GPL in 10/96 * - * (see Documentation/scsi/tmscsim.txt) * - ************************************************************************ - * $Id: tmscsim.c,v 2.60.2.30 2000/12/20 01:07:12 garloff Exp $ * - * Enhancements and bugfixes by * - * Kurt Garloff * - ************************************************************************ - * HISTORY: * - * * - * REV# DATE NAME DESCRIPTION * - * 1.00 96/04/24 CLH First release * - * 1.01 96/06/12 CLH Fixed bug of Media Change for Removable * - * Device, scan all LUN. Support Pre2.0.10 * - * 1.02 96/06/18 CLH Fixed bug of Command timeout ... * - * 1.03 96/09/25 KG Added tmscsim_proc_info() * - * 1.04 96/10/11 CLH Updating for support KV 2.0.x * - * 1.05 96/10/18 KG Fixed bug in DC390_abort(null ptr deref)* - * 1.06 96/10/25 KG Fixed module support * - * 1.07 96/11/09 KG Fixed tmscsim_proc_info() * - * 1.08 96/11/18 KG Fixed null ptr in DC390_Disconnect() * - * 1.09 96/11/30 KG Added register the allocated IO space * - * 1.10 96/12/05 CLH Modified tmscsim_proc_info(), and reset * - * pending interrupt in DC390_detect() * - * 1.11 97/02/05 KG/CLH Fixeds problem with partitions greater * - * than 1GB * - * 1.12 98/02/15 MJ Rewritten PCI probing * - * 1.13 98/04/08 KG Support for non DC390, __initfunc decls,* - * changed max devs from 10 to 16 * - * 1.14a 98/05/05 KG Dynamic DCB allocation, add-single-dev * - * for LUNs if LUN_SCAN (BIOS) not set * - * runtime config using /proc interface * - * 1.14b 98/05/06 KG eliminated cli (); sti (); spinlocks * - * 1.14c 98/05/07 KG 2.0.x compatibility * - * 1.20a 98/05/07 KG changed names of funcs to be consistent * - * DC390_ (entry points), dc390_ (internal)* - * reworked locking * - * 1.20b 98/05/12 KG bugs: version, kfree, _ctmp * - * debug output * - * 1.20c 98/05/12 KG bugs: kfree, parsing, EEpromDefaults * - * 1.20d 98/05/14 KG bugs: list linkage, clear flag after * - * reset on startup, code cleanup * - * 1.20e 98/05/15 KG spinlock comments, name space cleanup * - * pLastDCB now part of ACB structure * - * added stats, timeout for 2.1, TagQ bug * - * RESET and INQUIRY interface commands * - * 1.20f 98/05/18 KG spinlocks fixes, max_lun fix, free DCBs * - * for missing LUNs, pending int * - * 1.20g 98/05/19 KG Clean up: Avoid short * - * 1.20h 98/05/21 KG Remove AdaptSCSIID, max_lun ... * - * 1.20i 98/05/21 KG Aiiie: Bug with TagQMask * - * 1.20j 98/05/24 KG Handle STAT_BUSY, handle pACB->pLinkDCB * - * == 0 in remove_dev and DoingSRB_Done * - * 1.20k 98/05/25 KG DMA_INT (experimental) * - * 1.20l 98/05/27 KG remove DMA_INT; DMA_IDLE cmds added; * - * 1.20m 98/06/10 KG glitch configurable; made some global * - * vars part of ACB; use DC390_readX * - * 1.20n 98/06/11 KG startup params * - * 1.20o 98/06/15 KG added TagMaxNum to boot/module params * - * Device Nr -> Idx, TagMaxNum power of 2 * - * 1.20p 98/06/17 KG Docu updates. Reset depends on settings * - * pci_set_master added; 2.0.xx: pcibios_* * - * used instead of MechNum things ... * - * 1.20q 98/06/23 KG Changed defaults. Added debug code for * - * removable media and fixed it. TagMaxNum * - * fixed for DC390. Locking: ACB, DRV for * - * better IRQ sharing. Spelling: Queueing * - * Parsing and glitch_cfg changes. Display * - * real SyncSpeed value. Made DisConn * - * functional (!) * - * 1.20r 98/06/30 KG Debug macros, allow disabling DsCn, set * - * BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module * - * param -1 fixed. * - * 1.20s 98/08/20 KG Debug info on abort(), try to check PCI,* - * phys_to_bus instead of phys_to_virt, * - * fixed sel. process, fixed locking, * - * added MODULE_XXX infos, changed IRQ * - * request flags, disable DMA_INT * - * 1.20t 98/09/07 KG TagQ report fixed; Write Erase DMA Stat;* - * initfunc -> __init; better abort; * - * Timeout for XFER_DONE & BLAST_COMPLETE; * - * Allow up to 33 commands being processed * - * 2.0a 98/10/14 KG Max Cmnds back to 17. DMA_Stat clearing * - * all flags. Clear within while() loops * - * in DataIn_0/Out_0. Null ptr in dumpinfo * - * for pSRB==0. Better locking during init.* - * bios_param() now respects part. table. * - * 2.0b 98/10/24 KG Docu fixes. Timeout Msg in DMA Blast. * - * Disallow illegal idx in INQUIRY/REMOVE * - * 2.0c 98/11/19 KG Cleaned up detect/init for SMP boxes, * - * Write Erase DMA (1.20t) caused problems * - * 2.0d 98/12/25 KG Christmas release ;-) Message handling * - * completely reworked. Handle target ini- * - * tiated SDTR correctly. * - * 2.0d1 99/01/25 KG Try to handle RESTORE_PTR * - * 2.0d2 99/02/08 KG Check for failure of kmalloc, correct * - * inclusion of scsicam.h, DelayReset * - * 2.0d3 99/05/31 KG DRIVER_OK -> DID_OK, DID_NO_CONNECT, * - * detect Target mode and warn. * - * pcmd->result handling cleaned up. * - * 2.0d4 99/06/01 KG Cleaned selection process. Found bug * - * which prevented more than 16 tags. Now: * - * 24. SDTR cleanup. Cleaner multi-LUN * - * handling. Don't modify ControlRegs/FIFO * - * when connected. * - * 2.0d5 99/06/01 KG Clear DevID, Fix INQUIRY after cfg chg. * - * 2.0d6 99/06/02 KG Added ADD special command to allow cfg. * - * before detection. Reset SYNC_NEGO_DONE * - * after a bus reset. * - * 2.0d7 99/06/03 KG Fixed bugs wrt add,remove commands * - * 2.0d8 99/06/04 KG Removed copying of cmnd into CmdBlock. * - * Fixed Oops in _release(). * - * 2.0d9 99/06/06 KG Also tag queue INQUIRY, T_U_R, ... * - * Allow arb. no. of Tagged Cmnds. Max 32 * - * 2.0d1099/06/20 KG TagMaxNo changes now honoured! Queueing * - * clearified (renamed ..) TagMask handling* - * cleaned. * - * 2.0d1199/06/28 KG cmd->result now identical to 2.0d2 * - * 2.0d1299/07/04 KG Changed order of processing in IRQ * - * 2.0d1399/07/05 KG Don't update DCB fields if removed * - * 2.0d1499/07/05 KG remove_dev: Move kfree() to the end * - * 2.0d1599/07/12 KG use_new_eh_code: 0, ULONG -> UINT where * - * appropriate * - * 2.0d1699/07/13 KG Reenable StartSCSI interrupt, Retry msg * - * 2.0d1799/07/15 KG Remove debug msg. Disable recfg. when * - * there are queued cmnds * - * 2.0d1899/07/18 KG Selection timeout: Don't requeue * - * 2.0d1999/07/18 KG Abort: Only call scsi_done if dequeued * - * 2.0d2099/07/19 KG Rst_Detect: DoingSRB_Done * - * 2.0d2199/08/15 KG dev_id for request/free_irq, cmnd[0] for* - * RETRY, SRBdone does DID_ABORT for the * - * cmd passed by DC390_reset() * - * 2.0d2299/08/25 KG dev_id fixed. can_queue: 42 * - * 2.0d2399/08/25 KG Removed some debugging code. dev_id * - * now is set to pACB. Use u8,u16,u32. * - * 2.0d2499/11/14 KG Unreg. I/O if failed IRQ alloc. Call * - * done () w/ DID_BAD_TARGET in case of * - * missing DCB. We are old EH!! * - * 2.0d2500/01/15 KG 2.3.3x compat from Andreas Schultz * - * set unique_id. Disable RETRY message. * - * 2.0d2600/01/29 KG Go to new EH. * - * 2.0d2700/01/31 KG ... but maintain 2.0 compat. * - * and fix DCB freeing * - * 2.0d2800/02/14 KG Queue statistics fixed, dump special cmd* - * Waiting_Timer for failed StartSCSI * - * New EH: Don't return cmnds to ML on RST * - * Use old EH (don't have new EH fns yet) * - * Reset: Unlock, but refuse to queue * - * 2.3 __setup function * - * 2.0e 00/05/22 KG Return residual for 2.3 * - * 2.0e1 00/05/25 KG Compile fixes for 2.3.99 * - * 2.0e2 00/05/27 KG Jeff Garzik's pci_enable_device() * - * 2.0e3 00/09/29 KG Some 2.4 changes. Don't try Sync Nego * - * before INQUIRY has reported ability. * - * Recognise INQUIRY as scanning command. * - * 2.0e4 00/10/13 KG Allow compilation into 2.4 kernel * - * 2.0e5 00/11/17 KG Store Inq.flags in DCB * - * 2.0e6 00/11/22 KG 2.4 init function (Thx to O.Schumann) * - * 2.4 PCI device table (Thx to A.Richter) * - * 2.0e7 00/11/28 KG Allow overriding of BIOS settings * - * 2.0f 00/12/20 KG Handle failed INQUIRYs during scan * - * 2.1a 03/11/29 GL, KG Initial fixing for 2.6. Convert to * - * use the current PCI-mapping API, update * - * command-queuing. * - * 2.1b 04/04/13 GL Fix for 64-bit platforms * - * 2.1b1 04/01/31 GL (applied 05.04) Remove internal * - * command-queuing. * - * 2.1b2 04/02/01 CH (applied 05.04) Fix error-handling * - * 2.1c 04/05/23 GL Update to use the new pci_driver API, * - * some scsi EH updates, more cleanup. * - * 2.1d 04/05/27 GL Moved setting of scan_devices to * - * slave_alloc/_configure/_destroy, as * - * suggested by CH. * - ***********************************************************************/ - -/* DEBUG options */ -//#define DC390_DEBUG0 -//#define DC390_DEBUG1 -//#define DC390_DCBDEBUG -//#define DC390_PARSEDEBUG -//#define DC390_REMOVABLEDEBUG -//#define DC390_LOCKDEBUG - -//#define NOP do{}while(0) -#define C_NOP - -/* Debug definitions */ -#ifdef DC390_DEBUG0 -# define DEBUG0(x) x -#else -# define DEBUG0(x) C_NOP -#endif -#ifdef DC390_DEBUG1 -# define DEBUG1(x) x -#else -# define DEBUG1(x) C_NOP -#endif -#ifdef DC390_DCBDEBUG -# define DCBDEBUG(x) x -#else -# define DCBDEBUG(x) C_NOP -#endif -#ifdef DC390_PARSEDEBUG -# define PARSEDEBUG(x) x -#else -# define PARSEDEBUG(x) C_NOP -#endif -#ifdef DC390_REMOVABLEDEBUG -# define REMOVABLEDEBUG(x) x -#else -# define REMOVABLEDEBUG(x) C_NOP -#endif -#define DCBDEBUG1(x) C_NOP - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - - -#define DC390_BANNER "Tekram DC390/AM53C974" -#define DC390_VERSION "2.1d 2004-05-27" - -#define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI - -#include "tmscsim.h" - - -static void dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_Status_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_MsgOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_DataOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_DataInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_StatusPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_MsgOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_MsgInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_Nop_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); -static void dc390_Nop_1( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus); - -static void dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB ); -static void dc390_Disconnect( struct dc390_acb* pACB ); -static void dc390_Reselect( struct dc390_acb* pACB ); -static void dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ); -static void dc390_ScsiRstDetect( struct dc390_acb* pACB ); -static void dc390_EnableMsgOut_Abort(struct dc390_acb*, struct dc390_srb*); -static void dc390_dumpinfo(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB); -static void dc390_ResetDevParam(struct dc390_acb* pACB); - -static u32 dc390_laststatus = 0; -static u8 dc390_adapterCnt = 0; - -static int disable_clustering; -module_param(disable_clustering, int, S_IRUGO); -MODULE_PARM_DESC(disable_clustering, "If you experience problems with your devices, try setting to 1"); - -/* Startup values, to be overriden on the commandline */ -static int tmscsim[] = {-2, -2, -2, -2, -2, -2}; - -module_param_array(tmscsim, int, NULL, 0); -MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)"); -MODULE_AUTHOR("C.L. Huang / Kurt Garloff"); -MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); - -static void *dc390_phase0[]={ - dc390_DataOut_0, - dc390_DataIn_0, - dc390_Command_0, - dc390_Status_0, - dc390_Nop_0, - dc390_Nop_0, - dc390_MsgOut_0, - dc390_MsgIn_0, - dc390_Nop_1 - }; - -static void *dc390_phase1[]={ - dc390_DataOutPhase, - dc390_DataInPhase, - dc390_CommandPhase, - dc390_StatusPhase, - dc390_Nop_0, - dc390_Nop_0, - dc390_MsgOutPhase, - dc390_MsgInPhase, - dc390_Nop_1 - }; - -#ifdef DC390_DEBUG1 -static char* dc390_p0_str[] = { - "dc390_DataOut_0", - "dc390_DataIn_0", - "dc390_Command_0", - "dc390_Status_0", - "dc390_Nop_0", - "dc390_Nop_0", - "dc390_MsgOut_0", - "dc390_MsgIn_0", - "dc390_Nop_1" - }; - -static char* dc390_p1_str[] = { - "dc390_DataOutPhase", - "dc390_DataInPhase", - "dc390_CommandPhase", - "dc390_StatusPhase", - "dc390_Nop_0", - "dc390_Nop_0", - "dc390_MsgOutPhase", - "dc390_MsgInPhase", - "dc390_Nop_1" - }; -#endif - -static u8 dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN]; -static u8 dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20}; -static u8 dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20}; - -/*********************************************************************** - * Functions for the management of the internal structures - * (DCBs, SRBs, Queueing) - * - **********************************************************************/ -static void inline dc390_start_segment(struct dc390_srb* pSRB) -{ - struct scatterlist *psgl = pSRB->pSegmentList; - - /* start new sg segment */ - pSRB->SGBusAddr = sg_dma_address(psgl); - pSRB->SGToBeXferLen = sg_dma_len(psgl); -} - -static unsigned long inline dc390_advance_segment(struct dc390_srb* pSRB, u32 residue) -{ - unsigned long xfer = pSRB->SGToBeXferLen - residue; - - /* xfer more bytes transferred */ - pSRB->SGBusAddr += xfer; - pSRB->TotalXferredLen += xfer; - pSRB->SGToBeXferLen = residue; - - return xfer; -} - -static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun) -{ - struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL; - while (pDCB->TargetID != id || pDCB->TargetLUN != lun) - { - pDCB = pDCB->pNextDCB; - if (pDCB == pACB->pLinkDCB) - return NULL; - } - DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n", \ - pDCB, pDCB->TargetID, pDCB->TargetLUN)); - return pDCB; -} - -/* Insert SRB oin top of free list */ -static __inline__ void dc390_Free_insert (struct dc390_acb* pACB, struct dc390_srb* pSRB) -{ - DEBUG0(printk ("DC390: Free SRB %p\n", pSRB)); - pSRB->pNextSRB = pACB->pFreeSRB; - pACB->pFreeSRB = pSRB; -} - -static __inline__ void dc390_Going_append (struct dc390_dcb* pDCB, struct dc390_srb* pSRB) -{ - pDCB->GoingSRBCnt++; - DEBUG0(printk("DC390: Append SRB %p to Going\n", pSRB)); - /* Append to the list of Going commands */ - if( pDCB->pGoingSRB ) - pDCB->pGoingLast->pNextSRB = pSRB; - else - pDCB->pGoingSRB = pSRB; - - pDCB->pGoingLast = pSRB; - /* No next one in sent list */ - pSRB->pNextSRB = NULL; -} - -static __inline__ void dc390_Going_remove (struct dc390_dcb* pDCB, struct dc390_srb* pSRB) -{ - DEBUG0(printk("DC390: Remove SRB %p from Going\n", pSRB)); - if (pSRB == pDCB->pGoingSRB) - pDCB->pGoingSRB = pSRB->pNextSRB; - else - { - struct dc390_srb* psrb = pDCB->pGoingSRB; - while (psrb && psrb->pNextSRB != pSRB) - psrb = psrb->pNextSRB; - if (!psrb) - { printk (KERN_ERR "DC390: Remove non-ex. SRB %p from Going!\n", pSRB); return; } - psrb->pNextSRB = pSRB->pNextSRB; - if (pSRB == pDCB->pGoingLast) - pDCB->pGoingLast = psrb; - } - pDCB->GoingSRBCnt--; -} - -static struct scatterlist* dc390_sg_build_single(struct scatterlist *sg, void *addr, unsigned int length) -{ - sg_init_one(sg, addr, length); - return sg; -} - -/* Create pci mapping */ -static int dc390_pci_map (struct dc390_srb* pSRB) -{ - int error = 0; - struct scsi_cmnd *pcmd = pSRB->pcmd; - struct pci_dev *pdev = pSRB->pSRBDCB->pDCBACB->pdev; - dc390_cmd_scp_t* cmdp = ((dc390_cmd_scp_t*)(&pcmd->SCp)); - - /* Map sense buffer */ - if (pSRB->SRBFlag & AUTO_REQSENSE) { - pSRB->pSegmentList = dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, SCSI_SENSE_BUFFERSIZE); - pSRB->SGcount = pci_map_sg(pdev, pSRB->pSegmentList, 1, - DMA_FROM_DEVICE); - cmdp->saved_dma_handle = sg_dma_address(pSRB->pSegmentList); - - /* TODO: error handling */ - if (pSRB->SGcount != 1) - error = 1; - DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __func__, pcmd->sense_buffer, cmdp->saved_dma_handle)); - /* Map SG list */ - } else if (scsi_sg_count(pcmd)) { - int nseg; - - nseg = scsi_dma_map(pcmd); - - pSRB->pSegmentList = scsi_sglist(pcmd); - pSRB->SGcount = nseg; - - /* TODO: error handling */ - if (nseg < 0) - error = 1; - DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\ - __func__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd))); - /* Map single segment */ - } else - pSRB->SGcount = 0; - - return error; -} - -/* Remove pci mapping */ -static void dc390_pci_unmap (struct dc390_srb* pSRB) -{ - struct scsi_cmnd *pcmd = pSRB->pcmd; - struct pci_dev *pdev = pSRB->pSRBDCB->pDCBACB->pdev; - DEBUG1(dc390_cmd_scp_t* cmdp = ((dc390_cmd_scp_t*)(&pcmd->SCp))); - - if (pSRB->SRBFlag) { - pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE); - DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __func__, cmdp->saved_dma_handle)); - } else { - scsi_dma_unmap(pcmd); - DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n", - __func__, scsi_sglist(pcmd), scsi_sg_count(pcmd))); - } -} - -static void __inline__ -dc390_freetag (struct dc390_dcb* pDCB, struct dc390_srb* pSRB) -{ - if (pSRB->TagNumber != SCSI_NO_TAG) { - pDCB->TagMask &= ~(1 << pSRB->TagNumber); /* free tag mask */ - pSRB->TagNumber = SCSI_NO_TAG; - } -} - - -static int -dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ) -{ - struct scsi_cmnd *scmd = pSRB->pcmd; - struct scsi_device *sdev = scmd->device; - u8 cmd, disc_allowed, try_sync_nego; - char tag[2]; - - pSRB->ScsiPhase = SCSI_NOP0; - - if (pACB->Connected) - { - // Should not happen normally - printk (KERN_WARNING "DC390: Can't select when connected! (%08x,%02x)\n", - pSRB->SRBState, pSRB->SRBFlag); - pSRB->SRBState = SRB_READY; - pACB->SelConn++; - return 1; - } - if (time_before (jiffies, pACB->pScsiHost->last_reset)) - { - DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n")); - return 1; - } - /* KG: Moved pci mapping here */ - dc390_pci_map(pSRB); - /* TODO: error handling */ - DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); - DC390_write8 (Sync_Period, pDCB->SyncPeriod); - DC390_write8 (Sync_Offset, pDCB->SyncOffset); - DC390_write8 (CtrlReg1, pDCB->CtrlR1); - DC390_write8 (CtrlReg3, pDCB->CtrlR3); - DC390_write8 (CtrlReg4, pDCB->CtrlR4); - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */ - DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\ - scmd->cmnd[0], pDCB->SyncMode)); - - /* Don't disconnect on AUTO_REQSENSE, cause it might be an - * Contingent Allegiance Condition (6.6), where no tags should be used. - * All other have to be allowed to disconnect to prevent Incorrect - * Initiator Connection (6.8.2/6.5.2) */ - /* Changed KG, 99/06/06 */ - if (! (pSRB->SRBFlag & AUTO_REQSENSE)) - disc_allowed = pDCB->DevMode & EN_DISCONNECT_; - else - disc_allowed = 0; - - if ((pDCB->SyncMode & SYNC_ENABLE) && pDCB->TargetLUN == 0 && sdev->sdtr && - (((scmd->cmnd[0] == REQUEST_SENSE || (pSRB->SRBFlag & AUTO_REQSENSE)) && - !(pDCB->SyncMode & SYNC_NEGO_DONE)) || scmd->cmnd[0] == INQUIRY)) - try_sync_nego = 1; - else - try_sync_nego = 0; - - pSRB->MsgCnt = 0; - cmd = SEL_W_ATN; - DC390_write8 (ScsiFifo, IDENTIFY(disc_allowed, pDCB->TargetLUN)); - /* Change 99/05/31: Don't use tags when not disconnecting (BUSY) */ - if ((pDCB->SyncMode & EN_TAG_QUEUEING) && disc_allowed && scsi_populate_tag_msg(scmd, tag)) { - DC390_write8(ScsiFifo, tag[0]); - pDCB->TagMask |= 1 << tag[1]; - pSRB->TagNumber = tag[1]; - DC390_write8(ScsiFifo, tag[1]); - DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for SRB %p, block tag %02x\n", pSRB, tag[1])); - cmd = SEL_W_ATN3; - } else { - /* No TagQ */ -//no_tag: - DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for SRB %p, No TagQ\n", disc_allowed ? "" : "o", pSRB)); - } - - pSRB->SRBState = SRB_START_; - - if (try_sync_nego) - { - u8 Sync_Off = pDCB->SyncOffset; - DEBUG0(printk (KERN_INFO "DC390: NEW Sync Nego code triggered (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN)); - pSRB->MsgOutBuf[0] = EXTENDED_MESSAGE; - pSRB->MsgOutBuf[1] = 3; - pSRB->MsgOutBuf[2] = EXTENDED_SDTR; - pSRB->MsgOutBuf[3] = pDCB->NegoPeriod; - if (!(Sync_Off & 0x0f)) Sync_Off = SYNC_NEGO_OFFSET; - pSRB->MsgOutBuf[4] = Sync_Off; - pSRB->MsgCnt = 5; - //pSRB->SRBState = SRB_MSGOUT_; - pSRB->SRBState |= DO_SYNC_NEGO; - cmd = SEL_W_ATN_STOP; - } - - /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */ - if (cmd != SEL_W_ATN_STOP) - { - if( pSRB->SRBFlag & AUTO_REQSENSE ) - { - DC390_write8 (ScsiFifo, REQUEST_SENSE); - DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); - DC390_write8 (ScsiFifo, 0); - DC390_write8 (ScsiFifo, 0); - DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE); - DC390_write8 (ScsiFifo, 0); - DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n")); - } - else /* write cmnd to bus */ - { - u8 *ptr; u8 i; - ptr = (u8 *)scmd->cmnd; - for (i = 0; i < scmd->cmd_len; i++) - DC390_write8 (ScsiFifo, *(ptr++)); - } - } - DEBUG0(if (pACB->pActiveDCB) \ - printk (KERN_WARNING "DC390: ActiveDCB != 0\n")); - DEBUG0(if (pDCB->pActiveSRB) \ - printk (KERN_WARNING "DC390: ActiveSRB != 0\n")); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - if (DC390_read8 (Scsi_Status) & INTERRUPT) - { - dc390_freetag (pDCB, pSRB); - DEBUG0(printk ("DC390: Interrupt during Start SCSI (target %02i-%02i)\n", - scmd->device->id, scmd->device->lun)); - pSRB->SRBState = SRB_READY; - //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - pACB->SelLost++; - return 1; - } - DC390_write8 (ScsiCmd, cmd); - pACB->pActiveDCB = pDCB; - pDCB->pActiveSRB = pSRB; - pACB->Connected = 1; - pSRB->ScsiPhase = SCSI_NOP1; - return 0; -} - - -static void __inline__ -dc390_InvalidCmd(struct dc390_acb* pACB) -{ - if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ | SRB_MSGOUT)) - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); -} - - -static irqreturn_t __inline__ -DC390_Interrupt(void *dev_id) -{ - struct dc390_acb *pACB = dev_id; - struct dc390_dcb *pDCB; - struct dc390_srb *pSRB; - u8 sstatus=0; - u8 phase; - void (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *); - u8 istate, istatus; - - sstatus = DC390_read8 (Scsi_Status); - if( !(sstatus & INTERRUPT) ) - return IRQ_NONE; - - DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus)); - - //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); - //dstatus = DC390_read8 (DMA_Status); - //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); - - spin_lock_irq(pACB->pScsiHost->host_lock); - - istate = DC390_read8 (Intern_State); - istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */ - - DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus)); - dc390_laststatus &= ~0x00ffffff; - dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus; - - if (sstatus & ILLEGAL_OP_ERR) - { - printk ("DC390: Illegal Operation detected (%08x)!\n", dc390_laststatus); - dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB); - } - - else if (istatus & INVALID_CMD) - { - printk ("DC390: Invalid Command detected (%08x)!\n", dc390_laststatus); - dc390_InvalidCmd( pACB ); - goto unlock; - } - - if (istatus & SCSI_RESET) - { - dc390_ScsiRstDetect( pACB ); - goto unlock; - } - - if (istatus & DISCONNECTED) - { - dc390_Disconnect( pACB ); - goto unlock; - } - - if (istatus & RESELECTED) - { - dc390_Reselect( pACB ); - goto unlock; - } - - else if (istatus & (SELECTED | SEL_ATTENTION)) - { - printk (KERN_ERR "DC390: Target mode not supported!\n"); - goto unlock; - } - - if (istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) ) - { - pDCB = pACB->pActiveDCB; - if (!pDCB) - { - printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n"); - goto unlock; - } - pSRB = pDCB->pActiveSRB; - if( pDCB->DCBFlag & ABORT_DEV_ ) - dc390_EnableMsgOut_Abort (pACB, pSRB); - - phase = pSRB->ScsiPhase; - DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus)); - stateV = (void *) dc390_phase0[phase]; - ( *stateV )( pACB, pSRB, &sstatus ); - - pSRB->ScsiPhase = sstatus & 7; - phase = (u8) sstatus & 7; - DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus)); - stateV = (void *) dc390_phase1[phase]; - ( *stateV )( pACB, pSRB, &sstatus ); - } - - unlock: - spin_unlock_irq(pACB->pScsiHost->host_lock); - return IRQ_HANDLED; -} - -static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id) -{ - irqreturn_t ret; - DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq)); - /* Locking is done in DC390_Interrupt */ - ret = DC390_Interrupt(dev_id); - DEBUG1(printk (".. IRQ returned\n")); - return ret; -} - -static void -dc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - u8 sstatus; - u32 ResidCnt; - u8 dstate = 0; - - sstatus = *psstatus; - - if( !(pSRB->SRBState & SRB_XFERPAD) ) - { - if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) ) - pSRB->SRBStatus |= PARITY_ERROR; - - if( sstatus & COUNT_2_ZERO ) - { - unsigned long timeout = jiffies + HZ; - - /* Function called from the ISR with the host_lock held and interrupts disabled */ - if (pSRB->SGToBeXferLen) - while (time_before(jiffies, timeout) && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE)) { - spin_unlock_irq(pACB->pScsiHost->host_lock); - udelay(50); - spin_lock_irq(pACB->pScsiHost->host_lock); - } - if (!time_before(jiffies, timeout)) - printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", - DC390_read32 (DMA_Wk_ByteCntr)); - dc390_laststatus &= ~0xff000000; - dc390_laststatus |= dstate << 24; - pSRB->TotalXferredLen += pSRB->SGToBeXferLen; - pSRB->SGIndex++; - if( pSRB->SGIndex < pSRB->SGcount ) - { - pSRB->pSegmentList++; - - dc390_start_segment(pSRB); - } - else - pSRB->SGToBeXferLen = 0; - } - else - { - ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) + - (((u32) DC390_read8 (CtcReg_High) << 16) | - ((u32) DC390_read8 (CtcReg_Mid) << 8) | - (u32) DC390_read8 (CtcReg_Low)); - - dc390_advance_segment(pSRB, ResidCnt); - } - } - if ((*psstatus & 7) != SCSI_DATA_OUT) - { - DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - } -} - -static void -dc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - u8 sstatus, residual, bval; - u32 ResidCnt, i; - unsigned long xferCnt; - - sstatus = *psstatus; - - if( !(pSRB->SRBState & SRB_XFERPAD) ) - { - if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR)) - pSRB->SRBStatus |= PARITY_ERROR; - - if( sstatus & COUNT_2_ZERO ) - { - int dstate = 0; - unsigned long timeout = jiffies + HZ; - - /* Function called from the ISR with the host_lock held and interrupts disabled */ - if (pSRB->SGToBeXferLen) - while (time_before(jiffies, timeout) && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE)) { - spin_unlock_irq(pACB->pScsiHost->host_lock); - udelay(50); - spin_lock_irq(pACB->pScsiHost->host_lock); - } - if (!time_before(jiffies, timeout)) { - printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", - DC390_read32 (DMA_Wk_ByteCntr)); - printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate); - } - dc390_laststatus &= ~0xff000000; - dc390_laststatus |= dstate << 24; - DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16) \ - + ((unsigned long) DC390_read8 (CtcReg_Mid) << 8) \ - + ((unsigned long) DC390_read8 (CtcReg_Low))); - DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%u,ToBeXfer=%lu),", ResidCnt, pSRB->SGToBeXferLen)); - - DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); - - pSRB->TotalXferredLen += pSRB->SGToBeXferLen; - pSRB->SGIndex++; - if( pSRB->SGIndex < pSRB->SGcount ) - { - pSRB->pSegmentList++; - - dc390_start_segment(pSRB); - } - else - pSRB->SGToBeXferLen = 0; - } - else /* phase changed */ - { - residual = 0; - bval = DC390_read8 (Current_Fifo); - while( bval & 0x1f ) - { - DEBUG1(printk (KERN_DEBUG "Check for residuals,")); - if( (bval & 0x1f) == 1 ) - { - for(i=0; i < 0x100; i++) - { - bval = DC390_read8 (Current_Fifo); - if( !(bval & 0x1f) ) - goto din_1; - else if( i == 0x0ff ) - { - residual = 1; /* ;1 residual byte */ - goto din_1; - } - } - } - else - bval = DC390_read8 (Current_Fifo); - } -din_1: - DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD); - for (i = 0xa000; i; i--) - { - bval = DC390_read8 (DMA_Status); - if (bval & BLAST_COMPLETE) - break; - } - /* It seems a DMA Blast abort isn't that bad ... */ - if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n"); - //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); - dc390_laststatus &= ~0xff000000; - dc390_laststatus |= bval << 24; - - DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval)); - ResidCnt = (((u32) DC390_read8 (CtcReg_High) << 16) | - ((u32) DC390_read8 (CtcReg_Mid) << 8)) | - (u32) DC390_read8 (CtcReg_Low); - - xferCnt = dc390_advance_segment(pSRB, ResidCnt); - - if (residual) { - size_t count = 1; - size_t offset = pSRB->SGBusAddr - sg_dma_address(pSRB->pSegmentList); - unsigned long flags; - u8 *ptr; - - bval = DC390_read8 (ScsiFifo); /* get one residual byte */ - - local_irq_save(flags); - ptr = scsi_kmap_atomic_sg(pSRB->pSegmentList, pSRB->SGcount, &offset, &count); - if (likely(ptr)) { - *(ptr + offset) = bval; - scsi_kunmap_atomic_sg(ptr); - } - local_irq_restore(flags); - WARN_ON(!ptr); - - /* 1 more byte read */ - xferCnt += dc390_advance_segment(pSRB, pSRB->SGToBeXferLen - 1); - } - DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\ - pSRB->TotalXferredLen, pSRB->SGToBeXferLen)); - } - } - if ((*psstatus & 7) != SCSI_DATA_IN) - { - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); - } -} - -static void -dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ -} - -static void -dc390_Status_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - - pSRB->TargetStatus = DC390_read8 (ScsiFifo); - //udelay (1); - pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */ - - *psstatus = SCSI_NOP0; - pSRB->SRBState = SRB_COMPLETED; - DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); -} - -static void -dc390_MsgOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) ) - *psstatus = SCSI_NOP0; - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - - -static void __inline__ -dc390_reprog (struct dc390_acb* pACB, struct dc390_dcb* pDCB) -{ - DC390_write8 (Sync_Period, pDCB->SyncPeriod); - DC390_write8 (Sync_Offset, pDCB->SyncOffset); - DC390_write8 (CtrlReg3, pDCB->CtrlR3); - DC390_write8 (CtrlReg4, pDCB->CtrlR4); - dc390_SetXferRate (pACB, pDCB); -} - - -#ifdef DC390_DEBUG0 -static void -dc390_printMsg (u8 *MsgBuf, u8 len) -{ - int i; - printk (" %02x", MsgBuf[0]); - for (i = 1; i < len; i++) - printk (" %02x", MsgBuf[i]); - printk ("\n"); -} -#endif - -#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD) - -/* reject_msg */ -static void __inline__ -dc390_MsgIn_reject (struct dc390_acb* pACB, struct dc390_srb* pSRB) -{ - pSRB->MsgOutBuf[0] = MESSAGE_REJECT; - pSRB->MsgCnt = 1; - DC390_ENABLE_MSGOUT; - DEBUG0 (printk (KERN_INFO "DC390: Reject message\n")); -} - -/* abort command */ -static void -dc390_EnableMsgOut_Abort ( struct dc390_acb* pACB, struct dc390_srb* pSRB ) -{ - pSRB->MsgOutBuf[0] = ABORT; - pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; - pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_; -} - -static struct dc390_srb* -dc390_MsgIn_QTag (struct dc390_acb* pACB, struct dc390_dcb* pDCB, s8 tag) -{ - struct dc390_srb* pSRB = pDCB->pGoingSRB; - - if (pSRB) - { - struct scsi_cmnd *scmd = scsi_find_tag(pSRB->pcmd->device, tag); - pSRB = (struct dc390_srb *)scmd->host_scribble; - - if (pDCB->DCBFlag & ABORT_DEV_) - { - pSRB->SRBState = SRB_ABORT_SENT; - dc390_EnableMsgOut_Abort( pACB, pSRB ); - } - - if (!(pSRB->SRBState & SRB_DISCONNECT)) - goto mingx0; - - pDCB->pActiveSRB = pSRB; - pSRB->SRBState = SRB_DATA_XFER; - } - else - { - mingx0: - pSRB = pACB->pTmpSRB; - pSRB->SRBState = SRB_UNEXPECT_RESEL; - pDCB->pActiveSRB = pSRB; - pSRB->MsgOutBuf[0] = ABORT_TAG; - pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT; - } - return pSRB; -} - - -/* set async transfer mode */ -static void -dc390_MsgIn_set_async (struct dc390_acb* pACB, struct dc390_srb* pSRB) -{ - struct dc390_dcb* pDCB = pSRB->pSRBDCB; - if (!(pSRB->SRBState & DO_SYNC_NEGO)) - printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID); - pSRB->SRBState &= ~DO_SYNC_NEGO; - pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE); - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ - pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */ - pDCB->CtrlR4 &= 0x3f; - pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ - dc390_reprog (pACB, pDCB); -} - -/* set sync transfer mode */ -static void -dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB) -{ - u8 bval; - u16 wval, wval1; - struct dc390_dcb* pDCB = pSRB->pSRBDCB; - u8 oldsyncperiod = pDCB->SyncPeriod; - u8 oldsyncoffset = pDCB->SyncOffset; - - if (!(pSRB->SRBState & DO_SYNC_NEGO)) - { - printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n", - pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]); - - /* reject */ - //dc390_MsgIn_reject (pACB, pSRB); - //return dc390_MsgIn_set_async (pACB, pSRB); - - /* Reply with corrected SDTR Message */ - if (pSRB->MsgInBuf[4] > 15) - { - printk (KERN_INFO "DC390: Lower Sync Offset to 15\n"); - pSRB->MsgInBuf[4] = 15; - } - if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod) - { - printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2); - pSRB->MsgInBuf[3] = pDCB->NegoPeriod; - } - memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); - pSRB->MsgCnt = 5; - DC390_ENABLE_MSGOUT; - } - - pSRB->SRBState &= ~DO_SYNC_NEGO; - pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE; - pDCB->SyncOffset &= 0x0f0; - pDCB->SyncOffset |= pSRB->MsgInBuf[4]; - pDCB->NegoPeriod = pSRB->MsgInBuf[3]; - - wval = (u16) pSRB->MsgInBuf[3]; - wval = wval << 2; wval -= 3; wval1 = wval / 25; /* compute speed */ - if( (wval1 * 25) != wval) wval1++; - bval = FAST_CLK+FAST_SCSI; /* fast clock / fast scsi */ - - pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */ - if (pACB->glitch_cfg != NS_TO_GLITCH(0)) - pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1)); - else - pDCB->CtrlR4 |= NS_TO_GLITCH(0); - if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */ - - if (wval1 >= 8) - { - wval1--; /* Timing computation differs by 1 from FAST_SCSI */ - bval = FAST_CLK; /* fast clock / normal scsi */ - pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */ - } - - pDCB->CtrlR3 = bval; - pDCB->SyncPeriod = (u8)wval1; - - if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0) - { - if (! (bval & FAST_SCSI)) wval1++; - printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID, - 40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f); - } - - dc390_reprog (pACB, pDCB); -} - - -/* handle RESTORE_PTR */ -/* This doesn't look very healthy... to-be-fixed */ -static void -dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB) -{ - struct scsi_cmnd *pcmd = pSRB->pcmd; - struct scatterlist *psgl; - pSRB->TotalXferredLen = 0; - pSRB->SGIndex = 0; - if (scsi_sg_count(pcmd)) { - size_t saved; - pSRB->pSegmentList = scsi_sglist(pcmd); - psgl = pSRB->pSegmentList; - //dc390_pci_sync(pSRB); - - while (pSRB->TotalXferredLen + (unsigned long) sg_dma_len(psgl) < pSRB->Saved_Ptr) - { - pSRB->TotalXferredLen += (unsigned long) sg_dma_len(psgl); - pSRB->SGIndex++; - if( pSRB->SGIndex < pSRB->SGcount ) - { - pSRB->pSegmentList++; - - dc390_start_segment(pSRB); - } - else - pSRB->SGToBeXferLen = 0; - } - - saved = pSRB->Saved_Ptr - pSRB->TotalXferredLen; - pSRB->SGToBeXferLen -= saved; - pSRB->SGBusAddr += saved; - printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n", - pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr); - - } else { - pSRB->SGcount = 0; - printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n"); - } - - pSRB->TotalXferredLen = pSRB->Saved_Ptr; -} - - -/* According to the docs, the AM53C974 reads the message and - * generates a Successful Operation IRQ before asserting ACK for - * the last byte (how does it know whether it's the last ?) */ -/* The old code handled it in another way, indicating, that on - * every message byte an IRQ is generated and every byte has to - * be manually ACKed. Hmmm ? (KG, 98/11/28) */ -/* The old implementation was correct. Sigh! */ - -/* Check if the message is complete */ -static u8 __inline__ -dc390_MsgIn_complete (u8 *msgbuf, u32 len) -{ - if (*msgbuf == EXTENDED_MESSAGE) - { - if (len < 2) return 0; - if (len < msgbuf[1] + 2) return 0; - } - else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages - if (len < 2) return 0; - return 1; -} - - - -/* read and eval received messages */ -static void -dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - struct dc390_dcb* pDCB = pACB->pActiveDCB; - - /* Read the msg */ - - pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo); - //pSRB->SRBState = 0; - - /* Msg complete ? */ - if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen)) - { - DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen)); - /* Now eval the msg */ - switch (pSRB->MsgInBuf[0]) - { - case DISCONNECT: - pSRB->SRBState = SRB_DISCONNECT; break; - - case SIMPLE_QUEUE_TAG: - case HEAD_OF_QUEUE_TAG: - case ORDERED_QUEUE_TAG: - pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]); - break; - - case MESSAGE_REJECT: - DC390_write8 (ScsiCmd, RESET_ATN_CMD); - pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */ - if( pSRB->SRBState & DO_SYNC_NEGO) - dc390_MsgIn_set_async (pACB, pSRB); - break; - - case EXTENDED_MESSAGE: - /* reject every extended msg but SDTR */ - if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR) - dc390_MsgIn_reject (pACB, pSRB); - else - { - if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0) - dc390_MsgIn_set_async (pACB, pSRB); - else - dc390_MsgIn_set_sync (pACB, pSRB); - } - - // nothing has to be done - case COMMAND_COMPLETE: break; - - // SAVE POINTER may be ignored as we have the struct dc390_srb* associated with the - // scsi command. Thanks, Gerard, for pointing it out. - case SAVE_POINTERS: - pSRB->Saved_Ptr = pSRB->TotalXferredLen; - break; - // The device might want to restart transfer with a RESTORE - case RESTORE_POINTERS: - DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n")); - dc390_restore_ptr (pACB, pSRB); - break; - - // reject unknown messages - default: dc390_MsgIn_reject (pACB, pSRB); - } - - /* Clear counter and MsgIn state */ - pSRB->SRBState &= ~SRB_MSGIN; - pACB->MsgLen = 0; - } - - *psstatus = SCSI_NOP0; - DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - - -static void -dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir) -{ - unsigned long lval; - struct dc390_dcb* pDCB = pACB->pActiveDCB; - - if (pSRB == pACB->pTmpSRB) - { - if (pDCB) - printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); - else - printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n"); - - /* Try to recover - some broken disks react badly to tagged INQUIRY */ - if (pDCB && pACB->scan_devices && pDCB->GoingSRBCnt == 1) { - pSRB = pDCB->pGoingSRB; - pDCB->pActiveSRB = pSRB; - } else { - pSRB->pSRBDCB = pDCB; - dc390_EnableMsgOut_Abort(pACB, pSRB); - if (pDCB) - pDCB->DCBFlag |= ABORT_DEV; - return; - } - } - - if( pSRB->SGIndex < pSRB->SGcount ) - { - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); - if( !pSRB->SGToBeXferLen ) - { - dc390_start_segment(pSRB); - - DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.")); - } - lval = pSRB->SGToBeXferLen; - DEBUG1(printk (KERN_DEBUG " DC390: Start transfer: %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr)); - DC390_write8 (CtcReg_Low, (u8) lval); - lval >>= 8; - DC390_write8 (CtcReg_Mid, (u8) lval); - lval >>= 8; - DC390_write8 (CtcReg_High, (u8) lval); - - DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen); - DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr); - - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); - pSRB->SRBState = SRB_DATA_XFER; - - DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD); - - DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir); - //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT)); - //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status))); - //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT)); - } - else /* xfer pad */ - { - if( pSRB->SGcount ) - { - pSRB->AdaptStatus = H_OVER_UNDER_RUN; - pSRB->SRBStatus |= OVER_RUN; - DEBUG0(printk (KERN_WARNING " DC390: Overrun -")); - } - DEBUG0(printk (KERN_WARNING " Clear transfer pad \n")); - DC390_write8 (CtcReg_Low, 0); - DC390_write8 (CtcReg_Mid, 0); - DC390_write8 (CtcReg_High, 0); - - pSRB->SRBState |= SRB_XFERPAD; - DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE); -/* - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); - DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir); -*/ - } -} - - -static void -dc390_DataOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION); -} - -static void -dc390_DataInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION); -} - -static void -dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - struct dc390_dcb* pDCB; - u8 i, cnt; - u8 *ptr; - - DC390_write8 (ScsiCmd, RESET_ATN_CMD); - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - if( !(pSRB->SRBFlag & AUTO_REQSENSE) ) - { - cnt = (u8) pSRB->pcmd->cmd_len; - ptr = (u8 *) pSRB->pcmd->cmnd; - for(i=0; i < cnt; i++) - DC390_write8 (ScsiFifo, *(ptr++)); - } - else - { - DC390_write8 (ScsiFifo, REQUEST_SENSE); - pDCB = pACB->pActiveDCB; - DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5); - DC390_write8 (ScsiFifo, 0); - DC390_write8 (ScsiFifo, 0); - DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE); - DC390_write8 (ScsiFifo, 0); - DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n")); - } - pSRB->SRBState = SRB_COMMAND; - DC390_write8 (ScsiCmd, INFO_XFER_CMD); -} - -static void -dc390_StatusPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - pSRB->SRBState = SRB_STATUS; - DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - -static void -dc390_MsgOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - u8 bval, i, cnt; - u8 *ptr; - struct dc390_dcb* pDCB; - - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - pDCB = pACB->pActiveDCB; - if( !(pSRB->SRBState & SRB_MSGOUT) ) - { - cnt = pSRB->MsgCnt; - if( cnt ) - { - ptr = (u8 *) pSRB->MsgOutBuf; - for(i=0; i < cnt; i++) - DC390_write8 (ScsiFifo, *(ptr++)); - pSRB->MsgCnt = 0; - if( (pDCB->DCBFlag & ABORT_DEV_) && - (pSRB->MsgOutBuf[0] == ABORT) ) - pSRB->SRBState = SRB_ABORT_SENT; - } - else - { - bval = ABORT; /* ??? MSG_NOP */ - if( (pSRB->pcmd->cmnd[0] == INQUIRY ) || - (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) || - (pSRB->SRBFlag & AUTO_REQSENSE) ) - { - if( pDCB->SyncMode & SYNC_ENABLE ) - goto mop1; - } - DC390_write8 (ScsiFifo, bval); - } - DC390_write8 (ScsiCmd, INFO_XFER_CMD); - } - else - { -mop1: - printk (KERN_ERR "DC390: OLD Sync Nego code triggered! (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN); - DC390_write8 (ScsiFifo, EXTENDED_MESSAGE); - DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */ - DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */ - DC390_write8 (ScsiFifo, pDCB->NegoPeriod); - if (pDCB->SyncOffset & 0x0f) - DC390_write8 (ScsiFifo, pDCB->SyncOffset); - else - DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET); - pSRB->SRBState |= DO_SYNC_NEGO; - DC390_write8 (ScsiCmd, INFO_XFER_CMD); - } -} - -static void -dc390_MsgInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - if( !(pSRB->SRBState & SRB_MSGIN) ) - { - pSRB->SRBState &= ~SRB_DISCONNECT; - pSRB->SRBState |= SRB_MSGIN; - } - DC390_write8 (ScsiCmd, INFO_XFER_CMD); - //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); -} - -static void -dc390_Nop_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ -} - -static void -dc390_Nop_1( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus) -{ -} - - -static void -dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB ) -{ - u8 bval, i, cnt; - struct dc390_dcb* ptr; - - if( !(pDCB->TargetLUN) ) - { - if( !pACB->scan_devices ) - { - ptr = pACB->pLinkDCB; - cnt = pACB->DCBCnt; - bval = pDCB->TargetID; - for(i=0; iTargetID == bval ) - { - ptr->SyncPeriod = pDCB->SyncPeriod; - ptr->SyncOffset = pDCB->SyncOffset; - ptr->CtrlR3 = pDCB->CtrlR3; - ptr->CtrlR4 = pDCB->CtrlR4; - ptr->SyncMode = pDCB->SyncMode; - } - ptr = ptr->pNextDCB; - } - } - } - return; -} - - -static void -dc390_Disconnect( struct dc390_acb* pACB ) -{ - struct dc390_dcb *pDCB; - struct dc390_srb *pSRB, *psrb; - u8 i, cnt; - - DEBUG0(printk(KERN_INFO "DISC,")); - - if (!pACB->Connected) printk(KERN_ERR "DC390: Disconnect not-connected bus?\n"); - pACB->Connected = 0; - pDCB = pACB->pActiveDCB; - if (!pDCB) - { - DEBUG0(printk(KERN_ERR "ACB:%p->ActiveDCB:%p IOPort:%04x IRQ:%02x !\n",\ - pACB, pDCB, pACB->IOPortBase, pACB->IRQLevel)); - mdelay(400); - DC390_read8 (INT_Status); /* Reset Pending INT */ - DC390_write8 (ScsiCmd, EN_SEL_RESEL); - return; - } - DC390_write8 (ScsiCmd, EN_SEL_RESEL); - pSRB = pDCB->pActiveSRB; - pACB->pActiveDCB = NULL; - pSRB->ScsiPhase = SCSI_NOP0; - if( pSRB->SRBState & SRB_UNEXPECT_RESEL ) - pSRB->SRBState = 0; - else if( pSRB->SRBState & SRB_ABORT_SENT ) - { - pDCB->TagMask = 0; - pDCB->DCBFlag = 0; - cnt = pDCB->GoingSRBCnt; - pDCB->GoingSRBCnt = 0; - pSRB = pDCB->pGoingSRB; - for( i=0; i < cnt; i++) - { - psrb = pSRB->pNextSRB; - dc390_Free_insert (pACB, pSRB); - pSRB = psrb; - } - pDCB->pGoingSRB = NULL; - } - else - { - if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) || - !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) ) - { /* Selection time out */ - pSRB->AdaptStatus = H_SEL_TIMEOUT; - pSRB->TargetStatus = 0; - goto disc1; - } - else if (!(pSRB->SRBState & SRB_DISCONNECT) && (pSRB->SRBState & SRB_COMPLETED)) - { -disc1: - dc390_freetag (pDCB, pSRB); - pDCB->pActiveSRB = NULL; - pSRB->SRBState = SRB_FREE; - dc390_SRBdone( pACB, pDCB, pSRB); - } - } - pACB->MsgLen = 0; -} - - -static void -dc390_Reselect( struct dc390_acb* pACB ) -{ - struct dc390_dcb* pDCB; - struct dc390_srb* pSRB; - u8 id, lun; - - DEBUG0(printk(KERN_INFO "RSEL,")); - pACB->Connected = 1; - pDCB = pACB->pActiveDCB; - if( pDCB ) - { /* Arbitration lost but Reselection won */ - DEBUG0(printk ("DC390: (ActiveDCB != 0: Arb. lost but resel. won)!\n")); - pSRB = pDCB->pActiveSRB; - if( !( pACB->scan_devices ) ) - { - struct scsi_cmnd *pcmd = pSRB->pcmd; - scsi_set_resid(pcmd, scsi_bufflen(pcmd)); - SET_RES_DID(pcmd->result, DID_SOFT_ERROR); - dc390_Going_remove(pDCB, pSRB); - dc390_Free_insert(pACB, pSRB); - pcmd->scsi_done (pcmd); - DEBUG0(printk(KERN_DEBUG"DC390: Return SRB %p to free\n", pSRB)); - } - } - /* Get ID */ - lun = DC390_read8 (ScsiFifo); - DEBUG0(printk ("Dev %02x,", lun)); - if (!(lun & (1 << pACB->pScsiHost->this_id))) - printk (KERN_ERR "DC390: Reselection must select host adapter: %02x!\n", lun); - else - lun ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */ - id = 0; while (lun >>= 1) id++; - /* Get LUN */ - lun = DC390_read8 (ScsiFifo); - if (!(lun & IDENTIFY_BASE)) printk (KERN_ERR "DC390: Resel: Expect identify message!\n"); - lun &= 7; - DEBUG0(printk ("(%02i-%i),", id, lun)); - pDCB = dc390_findDCB (pACB, id, lun); - if (!pDCB) - { - printk (KERN_ERR "DC390: Reselect from non existing device (%02i-%i)\n", - id, lun); - return; - } - pACB->pActiveDCB = pDCB; - /* TagQ: We expect a message soon, so never mind the exact SRB */ - if( pDCB->SyncMode & EN_TAG_QUEUEING ) - { - pSRB = pACB->pTmpSRB; - pDCB->pActiveSRB = pSRB; - } - else - { - pSRB = pDCB->pActiveSRB; - if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) ) - { - pSRB= pACB->pTmpSRB; - pSRB->SRBState = SRB_UNEXPECT_RESEL; - printk (KERN_ERR "DC390: Reselect without outstanding cmnd (%02i-%i)\n", - id, lun); - pDCB->pActiveSRB = pSRB; - dc390_EnableMsgOut_Abort ( pACB, pSRB ); - } - else - { - if( pDCB->DCBFlag & ABORT_DEV_ ) - { - pSRB->SRBState = SRB_ABORT_SENT; - printk (KERN_INFO "DC390: Reselect: Abort (%02i-%i)\n", - id, lun); - dc390_EnableMsgOut_Abort( pACB, pSRB ); - } - else - pSRB->SRBState = SRB_DATA_XFER; - } - } - - DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber)); - pSRB->ScsiPhase = SCSI_NOP0; - DC390_write8 (Scsi_Dest_ID, pDCB->TargetID); - DC390_write8 (Sync_Period, pDCB->SyncPeriod); - DC390_write8 (Sync_Offset, pDCB->SyncOffset); - DC390_write8 (CtrlReg1, pDCB->CtrlR1); - DC390_write8 (CtrlReg3, pDCB->CtrlR3); - DC390_write8 (CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */ - DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */ -} - -static int __inline__ -dc390_RequestSense(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB) -{ - struct scsi_cmnd *pcmd; - - pcmd = pSRB->pcmd; - - REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense(Cmd %02x, Id %02x, LUN %02x)\n",\ - pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN)); - - pSRB->SRBFlag |= AUTO_REQSENSE; - pSRB->SavedTotXLen = pSRB->TotalXferredLen; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */ - - /* We are called from SRBdone, original PCI mapping has been removed - * already, new one is set up from StartSCSI */ - pSRB->SGIndex = 0; - - pSRB->TotalXferredLen = 0; - pSRB->SGToBeXferLen = 0; - return dc390_StartSCSI(pACB, pDCB, pSRB); -} - - -static void -dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB ) -{ - u8 status; - struct scsi_cmnd *pcmd; - - pcmd = pSRB->pcmd; - /* KG: Moved pci_unmap here */ - dc390_pci_unmap(pSRB); - - status = pSRB->TargetStatus; - - DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p\n", status, pcmd->result, pSRB)); - if(pSRB->SRBFlag & AUTO_REQSENSE) - { /* Last command was a Request Sense */ - pSRB->SRBFlag &= ~AUTO_REQSENSE; - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = SAM_STAT_CHECK_CONDITION; - - //pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status); - if (status == SAM_STAT_CHECK_CONDITION) - pcmd->result = MK_RES_LNX(0, DID_BAD_TARGET, 0, /*CHECK_CONDITION*/0); - else /* Retry */ - { - if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */) - { - /* Don't retry on TEST_UNIT_READY */ - pcmd->result = MK_RES_LNX(DRIVER_SENSE, DID_OK, 0, SAM_STAT_CHECK_CONDITION); - REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\ - (u32) pcmd->result, (u32) pSRB->TotalXferredLen)); - } else { - SET_RES_DRV(pcmd->result, DRIVER_SENSE); - //pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8); - DEBUG0 (printk ("DC390: RETRY (%02x), target %02i-%02i\n", pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); - pSRB->TotalXferredLen = 0; - SET_RES_DID(pcmd->result, DID_SOFT_ERROR); - } - } - goto cmd_done; - } - if( status ) - { - if (status == SAM_STAT_CHECK_CONDITION) - { - if (dc390_RequestSense(pACB, pDCB, pSRB)) { - SET_RES_DID(pcmd->result, DID_ERROR); - goto cmd_done; - } - return; - } - else if (status == SAM_STAT_TASK_SET_FULL) - { - scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1); - DEBUG0 (printk ("DC390: RETRY (%02x), target %02i-%02i\n", pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun)); - pSRB->TotalXferredLen = 0; - SET_RES_DID(pcmd->result, DID_SOFT_ERROR); - } - else if (status == SAM_STAT_BUSY && - (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) && - pACB->scan_devices) - { - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = status; - pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0); - } - else - { /* Another error */ - pSRB->TotalXferredLen = 0; - SET_RES_DID(pcmd->result, DID_SOFT_ERROR); - goto cmd_done; - } - } - else - { /* Target status == 0 */ - status = pSRB->AdaptStatus; - if (status == H_OVER_UNDER_RUN) - { - pSRB->TargetStatus = 0; - SET_RES_DID(pcmd->result,DID_OK); - SET_RES_MSG(pcmd->result,pSRB->EndMessage); - } - else if (status == H_SEL_TIMEOUT) - { - pcmd->result = MK_RES(0, DID_NO_CONNECT, 0, 0); - /* Devices are removed below ... */ - } - else if( pSRB->SRBStatus & PARITY_ERROR) - { - //pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0); - SET_RES_DID(pcmd->result,DID_PARITY); - SET_RES_MSG(pcmd->result,pSRB->EndMessage); - } - else /* No error */ - { - pSRB->AdaptStatus = 0; - pSRB->TargetStatus = 0; - SET_RES_DID(pcmd->result,DID_OK); - } - } - -cmd_done: - scsi_set_resid(pcmd, scsi_bufflen(pcmd) - pSRB->TotalXferredLen); - - dc390_Going_remove (pDCB, pSRB); - /* Add to free list */ - dc390_Free_insert (pACB, pSRB); - - DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done\n")); - pcmd->scsi_done (pcmd); - - return; -} - - -/* Remove all SRBs from Going list and inform midlevel */ -static void -dc390_DoingSRB_Done(struct dc390_acb* pACB, struct scsi_cmnd *cmd) -{ - struct dc390_dcb *pDCB, *pdcb; - struct dc390_srb *psrb, *psrb2; - int i; - struct scsi_cmnd *pcmd; - - pDCB = pACB->pLinkDCB; - pdcb = pDCB; - if (! pdcb) return; - do - { - psrb = pdcb->pGoingSRB; - for (i = 0; i < pdcb->GoingSRBCnt; i++) - { - psrb2 = psrb->pNextSRB; - pcmd = psrb->pcmd; - dc390_Free_insert (pACB, psrb); - psrb = psrb2; - } - pdcb->GoingSRBCnt = 0; - pdcb->pGoingSRB = NULL; - pdcb->TagMask = 0; - pdcb = pdcb->pNextDCB; - } while( pdcb != pDCB ); -} - - -static void -dc390_ResetSCSIBus( struct dc390_acb* pACB ) -{ - //DC390_write8 (ScsiCmd, RST_DEVICE_CMD); - //udelay (250); - //DC390_write8 (ScsiCmd, NOP_CMD); - - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD); - pACB->Connected = 0; - - return; -} - -static void -dc390_ScsiRstDetect( struct dc390_acb* pACB ) -{ - printk ("DC390: Rst_Detect: laststat = %08x\n", dc390_laststatus); - //DEBUG0(printk(KERN_INFO "RST_DETECT,")); - - DC390_write8 (DMA_Cmd, DMA_IDLE_CMD); - /* Unlock before ? */ - /* delay half a second */ - udelay (1000); - DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); - pACB->pScsiHost->last_reset = jiffies + 5*HZ/2 - + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; - pACB->Connected = 0; - - if( pACB->ACBFlag & RESET_DEV ) - pACB->ACBFlag |= RESET_DONE; - else - { /* Reset was issued by sb else */ - pACB->ACBFlag |= RESET_DETECT; - - dc390_ResetDevParam( pACB ); - dc390_DoingSRB_Done( pACB, NULL); - //dc390_RecoverSRB( pACB ); - pACB->pActiveDCB = NULL; - pACB->ACBFlag = 0; - } - return; -} - -static int DC390_queuecommand_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - struct scsi_device *sdev = cmd->device; - struct dc390_acb *acb = (struct dc390_acb *)sdev->host->hostdata; - struct dc390_dcb *dcb = sdev->hostdata; - struct dc390_srb *srb; - - if (sdev->queue_depth <= dcb->GoingSRBCnt) - goto device_busy; - if (acb->pActiveDCB) - goto host_busy; - if (acb->ACBFlag & (RESET_DETECT|RESET_DONE|RESET_DEV)) - goto host_busy; - - srb = acb->pFreeSRB; - if (unlikely(srb == NULL)) - goto host_busy; - - cmd->scsi_done = done; - cmd->result = 0; - acb->Cmds++; - - acb->pFreeSRB = srb->pNextSRB; - srb->pNextSRB = NULL; - - srb->pSRBDCB = dcb; - srb->pcmd = cmd; - cmd->host_scribble = (char *)srb; - - srb->SGIndex = 0; - srb->AdaptStatus = 0; - srb->TargetStatus = 0; - srb->MsgCnt = 0; - - srb->SRBStatus = 0; - srb->SRBFlag = 0; - srb->SRBState = 0; - srb->TotalXferredLen = 0; - srb->SGBusAddr = 0; - srb->SGToBeXferLen = 0; - srb->ScsiPhase = 0; - srb->EndMessage = 0; - srb->TagNumber = SCSI_NO_TAG; - - if (dc390_StartSCSI(acb, dcb, srb)) { - dc390_Free_insert(acb, srb); - goto host_busy; - } - - dc390_Going_append(dcb, srb); - - return 0; - - host_busy: - return SCSI_MLQUEUE_HOST_BUSY; - - device_busy: - return SCSI_MLQUEUE_DEVICE_BUSY; -} - -static DEF_SCSI_QCMD(DC390_queuecommand) - -static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB) -{ - struct pci_dev *pdev; - u16 pstat; - - if (!pDCB) pDCB = pACB->pActiveDCB; - if (!pSRB && pDCB) pSRB = pDCB->pActiveSRB; - - if (pSRB) - { - printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08x, Phase %02x\n", - pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState, - pSRB->ScsiPhase); - printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus); - } - printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08x\n", dc390_laststatus); - printk ("DC390: Register dump: SCSI block:\n"); - printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n"); - printk ("DC390: %06x %02x %02x %02x", - DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16), - DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State)); - printk (" %02x %02x %02x %02x %02x %02x\n", - DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1), - DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4)); - DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT); - if (DC390_read8(Current_Fifo) & 0x1f) - { - printk ("DC390: FIFO:"); - while (DC390_read8(Current_Fifo) & 0x1f) printk (" %02x", DC390_read8(ScsiFifo)); - printk ("\n"); - } - printk ("DC390: Register dump: DMA engine:\n"); - printk ("DC390: Cmd STrCnt SBusA WrkBC WrkAC Stat SBusCtrl\n"); - printk ("DC390: %02x %08x %08x %08x %08x %02x %08x\n", - DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr), - DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr), - DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl)); - DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); - - pdev = pACB->pdev; - pci_read_config_word(pdev, PCI_STATUS, &pstat); - printk ("DC390: Register dump: PCI Status: %04x\n", pstat); - printk ("DC390: In case of driver trouble read Documentation/scsi/tmscsim.txt\n"); -} - - -static int DC390_abort(struct scsi_cmnd *cmd) -{ - struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata; - struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata; - - scmd_printk(KERN_WARNING, cmd, "DC390: Abort command\n"); - - /* abort() is too stupid for already sent commands at the moment. - * If it's called we are in trouble anyway, so let's dump some info - * into the syslog at least. (KG, 98/08/20,99/06/20) */ - dc390_dumpinfo(pACB, pDCB, NULL); - - pDCB->DCBFlag |= ABORT_DEV_; - printk(KERN_INFO "DC390: Aborted.\n"); - - return FAILED; -} - - -static void dc390_ResetDevParam( struct dc390_acb* pACB ) -{ - struct dc390_dcb *pDCB, *pdcb; - - pDCB = pACB->pLinkDCB; - if (! pDCB) return; - pdcb = pDCB; - do - { - pDCB->SyncMode &= ~SYNC_NEGO_DONE; - pDCB->SyncPeriod = 0; - pDCB->SyncOffset = 0; - pDCB->TagMask = 0; - pDCB->CtrlR3 = FAST_CLK; - pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK; - pDCB->CtrlR4 |= pACB->glitch_cfg; - pDCB = pDCB->pNextDCB; - } - while( pdcb != pDCB ); - pACB->ACBFlag &= ~(RESET_DEV | RESET_DONE | RESET_DETECT); - -} - -static int DC390_bus_reset (struct scsi_cmnd *cmd) -{ - struct dc390_acb* pACB = (struct dc390_acb*) cmd->device->host->hostdata; - u8 bval; - - spin_lock_irq(cmd->device->host->host_lock); - - bval = DC390_read8(CtrlReg1) | DIS_INT_ON_SCSI_RST; - DC390_write8(CtrlReg1, bval); /* disable IRQ on bus reset */ - - pACB->ACBFlag |= RESET_DEV; - dc390_ResetSCSIBus(pACB); - - dc390_ResetDevParam(pACB); - mdelay(1); - pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 - + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; - - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); - DC390_read8(INT_Status); /* Reset Pending INT */ - - dc390_DoingSRB_Done(pACB, cmd); - - pACB->pActiveDCB = NULL; - pACB->ACBFlag = 0; - - bval = DC390_read8(CtrlReg1) & ~DIS_INT_ON_SCSI_RST; - DC390_write8(CtrlReg1, bval); /* re-enable interrupt */ - - spin_unlock_irq(cmd->device->host->host_lock); - - return SUCCESS; -} - -/** - * dc390_slave_alloc - Called by the scsi mid layer to tell us about a new - * scsi device that we need to deal with. - * - * @scsi_device: The new scsi device that we need to handle. - */ -static int dc390_slave_alloc(struct scsi_device *scsi_device) -{ - struct dc390_acb *pACB = (struct dc390_acb*) scsi_device->host->hostdata; - struct dc390_dcb *pDCB, *pDCB2 = NULL; - uint id = scsi_device->id; - uint lun = scsi_device->lun; - - pDCB = kzalloc(sizeof(struct dc390_dcb), GFP_KERNEL); - if (!pDCB) - return -ENOMEM; - - if (!pACB->DCBCnt++) { - pACB->pLinkDCB = pDCB; - pACB->pDCBRunRobin = pDCB; - } else { - pACB->pLastDCB->pNextDCB = pDCB; - } - - pDCB->pNextDCB = pACB->pLinkDCB; - pACB->pLastDCB = pDCB; - - pDCB->pDCBACB = pACB; - pDCB->TargetID = id; - pDCB->TargetLUN = lun; - - /* - * Some values are for all LUNs: Copy them - * In a clean way: We would have an own structure for a SCSI-ID - */ - if (lun && (pDCB2 = dc390_findDCB(pACB, id, 0))) { - pDCB->DevMode = pDCB2->DevMode; - pDCB->SyncMode = pDCB2->SyncMode & SYNC_NEGO_DONE; - pDCB->SyncPeriod = pDCB2->SyncPeriod; - pDCB->SyncOffset = pDCB2->SyncOffset; - pDCB->NegoPeriod = pDCB2->NegoPeriod; - - pDCB->CtrlR3 = pDCB2->CtrlR3; - pDCB->CtrlR4 = pDCB2->CtrlR4; - } else { - u8 index = pACB->AdapterIndex; - PEEprom prom = (PEEprom) &dc390_eepromBuf[index][id << 2]; - - pDCB->DevMode = prom->EE_MODE1; - pDCB->NegoPeriod = - (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2; - pDCB->CtrlR3 = FAST_CLK; - pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED; - if (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) - pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK; - } - - if (pDCB->DevMode & SYNC_NEGO_) - pDCB->SyncMode |= SYNC_ENABLE; - else { - pDCB->SyncMode = 0; - pDCB->SyncOffset &= ~0x0f; - } - - pDCB->CtrlR1 = pACB->pScsiHost->this_id; - if (pDCB->DevMode & PARITY_CHK_) - pDCB->CtrlR1 |= PARITY_ERR_REPO; - - pACB->scan_devices = 1; - scsi_device->hostdata = pDCB; - return 0; -} - -/** - * dc390_slave_destroy - Called by the scsi mid layer to tell us about a - * device that is going away. - * - * @scsi_device: The scsi device that we need to remove. - */ -static void dc390_slave_destroy(struct scsi_device *scsi_device) -{ - struct dc390_acb* pACB = (struct dc390_acb*) scsi_device->host->hostdata; - struct dc390_dcb* pDCB = (struct dc390_dcb*) scsi_device->hostdata; - struct dc390_dcb* pPrevDCB = pACB->pLinkDCB; - - pACB->scan_devices = 0; - - BUG_ON(pDCB->GoingSRBCnt > 1); - - if (pDCB == pACB->pLinkDCB) { - if (pACB->pLastDCB == pDCB) { - pDCB->pNextDCB = NULL; - pACB->pLastDCB = NULL; - } - pACB->pLinkDCB = pDCB->pNextDCB; - } else { - while (pPrevDCB->pNextDCB != pDCB) - pPrevDCB = pPrevDCB->pNextDCB; - pPrevDCB->pNextDCB = pDCB->pNextDCB; - if (pDCB == pACB->pLastDCB) - pACB->pLastDCB = pPrevDCB; - } - - if (pDCB == pACB->pActiveDCB) - pACB->pActiveDCB = NULL; - if (pDCB == pACB->pLinkDCB) - pACB->pLinkDCB = pDCB->pNextDCB; - if (pDCB == pACB->pDCBRunRobin) - pACB->pDCBRunRobin = pDCB->pNextDCB; - kfree(pDCB); - - pACB->DCBCnt--; -} - -static int dc390_slave_configure(struct scsi_device *sdev) -{ - struct dc390_acb *acb = (struct dc390_acb *)sdev->host->hostdata; - struct dc390_dcb *dcb = (struct dc390_dcb *)sdev->hostdata; - - acb->scan_devices = 0; - if (sdev->tagged_supported && (dcb->DevMode & TAG_QUEUEING_)) { - dcb->SyncMode |= EN_TAG_QUEUEING; - scsi_activate_tcq(sdev, acb->TagMaxNum); - } - - return 0; -} - -static struct scsi_host_template driver_template = { - .module = THIS_MODULE, - .proc_name = "tmscsim", - .name = DC390_BANNER " V" DC390_VERSION, - .slave_alloc = dc390_slave_alloc, - .slave_configure = dc390_slave_configure, - .slave_destroy = dc390_slave_destroy, - .queuecommand = DC390_queuecommand, - .eh_abort_handler = DC390_abort, - .eh_bus_reset_handler = DC390_bus_reset, - .can_queue = 1, - .this_id = 7, - .sg_tablesize = SG_ALL, - .cmd_per_lun = 1, - .use_clustering = ENABLE_CLUSTERING, - .max_sectors = 0x4000, /* 8MiB = 16 * 1024 * 512 */ -}; - -/*********************************************************************** - * Functions for access to DC390 EEPROM - * and some to emulate it - * - **********************************************************************/ - -static void __devinit dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd) -{ - u8 carryFlag = 1, j = 0x80, bval; - int i; - - for (i = 0; i < 9; i++) { - if (carryFlag) { - pci_write_config_byte(pdev, 0x80, 0x40); - bval = 0xc0; - } else - bval = 0x80; - - udelay(160); - pci_write_config_byte(pdev, 0x80, bval); - udelay(160); - pci_write_config_byte(pdev, 0x80, 0); - udelay(160); - - carryFlag = (cmd & j) ? 1 : 0; - j >>= 1; - } -} - -static u16 __devinit dc390_eeprom_get_data(struct pci_dev *pdev) -{ - int i; - u16 wval = 0; - u8 bval; - - for (i = 0; i < 16; i++) { - wval <<= 1; - - pci_write_config_byte(pdev, 0x80, 0x80); - udelay(160); - pci_write_config_byte(pdev, 0x80, 0x40); - udelay(160); - pci_read_config_byte(pdev, 0x00, &bval); - - if (bval == 0x22) - wval |= 1; - } - - return wval; -} - -static void __devinit dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr) -{ - u8 cmd = EEPROM_READ, i; - - for (i = 0; i < 0x40; i++) { - pci_write_config_byte(pdev, 0xc0, 0); - udelay(160); - - dc390_eeprom_prepare_read(pdev, cmd++); - *ptr++ = dc390_eeprom_get_data(pdev); - - pci_write_config_byte(pdev, 0x80, 0); - pci_write_config_byte(pdev, 0x80, 0); - udelay(160); - } -} - -/* Override EEprom values with explicitly set values */ -static void __devinit dc390_eeprom_override(u8 index) -{ - u8 *ptr = (u8 *) dc390_eepromBuf[index], id; - - /* Adapter Settings */ - if (tmscsim[0] != -2) - ptr[EE_ADAPT_SCSI_ID] = (u8)tmscsim[0]; /* Adapter ID */ - if (tmscsim[3] != -2) - ptr[EE_MODE2] = (u8)tmscsim[3]; - if (tmscsim[5] != -2) - ptr[EE_DELAY] = tmscsim[5]; /* Reset delay */ - if (tmscsim[4] != -2) - ptr[EE_TAG_CMD_NUM] = (u8)tmscsim[4]; /* Tagged Cmds */ - - /* Device Settings */ - for (id = 0; id < MAX_SCSI_ID; id++) { - if (tmscsim[2] != -2) - ptr[id << 2] = (u8)tmscsim[2]; /* EE_MODE1 */ - if (tmscsim[1] != -2) - ptr[(id << 2) + 1] = (u8)tmscsim[1]; /* EE_Speed */ - } -} - -static int __devinitdata tmscsim_def[] = { - 7, - 0 /* 10MHz */, - PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ | SYNC_NEGO_ | TAG_QUEUEING_, - MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION | LUN_CHECK, - 3 /* 16 Tags per LUN */, - 1 /* s delay after Reset */, -}; - -/* Copy defaults over set values where missing */ -static void __devinit dc390_fill_with_defaults (void) -{ - int i; - - for (i = 0; i < 6; i++) { - if (tmscsim[i] < 0 || tmscsim[i] > 255) - tmscsim[i] = tmscsim_def[i]; - } - - /* Sanity checks */ - if (tmscsim[0] > 7) - tmscsim[0] = 7; - if (tmscsim[1] > 7) - tmscsim[1] = 4; - if (tmscsim[4] > 5) - tmscsim[4] = 4; - if (tmscsim[5] > 180) - tmscsim[5] = 180; -} - -static void __devinit dc390_check_eeprom(struct pci_dev *pdev, u8 index) -{ - u8 interpd[] = {1, 3, 5, 10, 16, 30, 60, 120}; - u8 EEbuf[128]; - u16 *ptr = (u16 *)EEbuf, wval = 0; - int i; - - dc390_read_eeprom(pdev, ptr); - memcpy(dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID); - memcpy(&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], - &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID); - - dc390_eepromBuf[index][EE_DELAY] = interpd[dc390_eepromBuf[index][EE_DELAY]]; - - for (i = 0; i < 0x40; i++, ptr++) - wval += *ptr; - - /* no Tekram EEprom found */ - if (wval != 0x1234) { - int speed; - - printk(KERN_INFO "DC390_init: No EEPROM found! Trying default settings ...\n"); - - /* - * XXX(hch): bogus, because we might have tekram and - * non-tekram hbas in a single machine. - */ - dc390_fill_with_defaults(); - - speed = dc390_clock_speed[tmscsim[1]]; - printk(KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz), " - "DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i), DelayReset=%is\n", - tmscsim[0], tmscsim[1], speed / 10, speed % 10, - (u8)tmscsim[2], (u8)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]), tmscsim[5]); - } -} - -static void __devinit dc390_init_hw(struct dc390_acb *pACB, u8 index) -{ - struct Scsi_Host *shost = pACB->pScsiHost; - u8 dstate; - - /* Disable SCSI bus reset interrupt */ - DC390_write8(CtrlReg1, DIS_INT_ON_SCSI_RST | shost->this_id); - - if (pACB->Gmode2 & RST_SCSI_BUS) { - dc390_ResetSCSIBus(pACB); - udelay(1000); - shost->last_reset = jiffies + HZ/2 + - HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY]; - } - - pACB->ACBFlag = 0; - - /* Reset Pending INT */ - DC390_read8(INT_Status); - - /* 250ms selection timeout */ - DC390_write8(Scsi_TimeOut, SEL_TIMEOUT); - - /* Conversion factor = 0 , 40MHz clock */ - DC390_write8(Clk_Factor, CLK_FREQ_40MHZ); - - /* NOP cmd - clear command register */ - DC390_write8(ScsiCmd, NOP_CMD); - - /* Enable Feature and SCSI-2 */ - DC390_write8(CtrlReg2, EN_FEATURE+EN_SCSI2_CMD); - - /* Fast clock */ - DC390_write8(CtrlReg3, FAST_CLK); - - /* Negation */ - DC390_write8(CtrlReg4, pACB->glitch_cfg | /* glitch eater */ - (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? - NEGATE_REQACKDATA : 0); - - /* Clear Transfer Count High: ID */ - DC390_write8(CtcReg_High, 0); - DC390_write8(DMA_Cmd, DMA_IDLE_CMD); - DC390_write8(ScsiCmd, CLEAR_FIFO_CMD); - DC390_write32(DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT); - - dstate = DC390_read8(DMA_Status); - DC390_write8(DMA_Status, dstate); -} - -static int __devinit dc390_probe_one(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct dc390_acb *pACB; - struct Scsi_Host *shost; - unsigned long io_port; - int error = -ENODEV, i; - - if (pci_enable_device(pdev)) - goto out; - - pci_set_master(pdev); - - error = -ENOMEM; - if (disable_clustering) - driver_template.use_clustering = DISABLE_CLUSTERING; - shost = scsi_host_alloc(&driver_template, sizeof(struct dc390_acb)); - if (!shost) - goto out_disable_device; - - pACB = (struct dc390_acb *)shost->hostdata; - memset(pACB, 0, sizeof(struct dc390_acb)); - - dc390_check_eeprom(pdev, dc390_adapterCnt); - dc390_eeprom_override(dc390_adapterCnt); - - io_port = pci_resource_start(pdev, 0); - - shost->this_id = dc390_eepromBuf[dc390_adapterCnt][EE_ADAPT_SCSI_ID]; - shost->io_port = io_port; - shost->n_io_port = 0x80; - shost->irq = pdev->irq; - shost->base = io_port; - shost->unique_id = io_port; - shost->last_reset = jiffies; - - pACB->pScsiHost = shost; - pACB->IOPortBase = (u16) io_port; - pACB->IRQLevel = pdev->irq; - - shost->max_id = 8; - - if (shost->max_id - 1 == - dc390_eepromBuf[dc390_adapterCnt][EE_ADAPT_SCSI_ID]) - shost->max_id--; - - if (dc390_eepromBuf[dc390_adapterCnt][EE_MODE2] & LUN_CHECK) - shost->max_lun = 8; - else - shost->max_lun = 1; - - pACB->pFreeSRB = pACB->SRB_array; - pACB->SRBCount = MAX_SRB_CNT; - pACB->AdapterIndex = dc390_adapterCnt; - pACB->TagMaxNum = - 2 << dc390_eepromBuf[dc390_adapterCnt][EE_TAG_CMD_NUM]; - pACB->Gmode2 = dc390_eepromBuf[dc390_adapterCnt][EE_MODE2]; - - for (i = 0; i < pACB->SRBCount-1; i++) - pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1]; - pACB->SRB_array[pACB->SRBCount-1].pNextSRB = NULL; - pACB->pTmpSRB = &pACB->TmpSRB; - - pACB->sel_timeout = SEL_TIMEOUT; - pACB->glitch_cfg = EATER_25NS; - pACB->pdev = pdev; - - if (!request_region(io_port, shost->n_io_port, "tmscsim")) { - printk(KERN_ERR "DC390: register IO ports error!\n"); - goto out_host_put; - } - - /* Reset Pending INT */ - DC390_read8_(INT_Status, io_port); - - if (request_irq(pdev->irq, do_DC390_Interrupt, IRQF_SHARED, - "tmscsim", pACB)) { - printk(KERN_ERR "DC390: register IRQ error!\n"); - goto out_release_region; - } - - dc390_init_hw(pACB, dc390_adapterCnt); - - dc390_adapterCnt++; - - pci_set_drvdata(pdev, shost); - - error = scsi_add_host(shost, &pdev->dev); - if (error) - goto out_free_irq; - scsi_scan_host(shost); - return 0; - - out_free_irq: - free_irq(pdev->irq, pACB); - out_release_region: - release_region(io_port, shost->n_io_port); - out_host_put: - scsi_host_put(shost); - out_disable_device: - pci_disable_device(pdev); - out: - return error; -} - -/** - * dc390_remove_one - Called to remove a single instance of the adapter. - * - * @dev: The PCI device to remove. - */ -static void __devexit dc390_remove_one(struct pci_dev *dev) -{ - struct Scsi_Host *scsi_host = pci_get_drvdata(dev); - unsigned long iflags; - struct dc390_acb* pACB = (struct dc390_acb*) scsi_host->hostdata; - u8 bval; - - scsi_remove_host(scsi_host); - - spin_lock_irqsave(scsi_host->host_lock, iflags); - pACB->ACBFlag = RESET_DEV; - bval = DC390_read8(CtrlReg1) | DIS_INT_ON_SCSI_RST; - DC390_write8 (CtrlReg1, bval); /* disable interrupt */ - if (pACB->Gmode2 & RST_SCSI_BUS) - dc390_ResetSCSIBus(pACB); - spin_unlock_irqrestore(scsi_host->host_lock, iflags); - - free_irq(scsi_host->irq, pACB); - release_region(scsi_host->io_port, scsi_host->n_io_port); - - pci_disable_device(dev); - scsi_host_put(scsi_host); - pci_set_drvdata(dev, NULL); -} - -static struct pci_device_id tmscsim_pci_tbl[] = { - { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { } -}; -MODULE_DEVICE_TABLE(pci, tmscsim_pci_tbl); - -static struct pci_driver dc390_driver = { - .name = "tmscsim", - .id_table = tmscsim_pci_tbl, - .probe = dc390_probe_one, - .remove = __devexit_p(dc390_remove_one), -}; - -static int __init dc390_module_init(void) -{ - if (!disable_clustering) { - printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n"); - printk(KERN_INFO " with \"disable_clustering=1\" and report to maintainers\n"); - } - - if (tmscsim[0] == -1 || tmscsim[0] > 15) { - tmscsim[0] = 7; - tmscsim[1] = 4; - tmscsim[2] = PARITY_CHK_ | TAG_QUEUEING_; - tmscsim[3] = MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION; - tmscsim[4] = 2; - tmscsim[5] = 10; - printk (KERN_INFO "DC390: Using safe settings.\n"); - } - - return pci_register_driver(&dc390_driver); -} - -static void __exit dc390_module_exit(void) -{ - pci_unregister_driver(&dc390_driver); -} - -module_init(dc390_module_init); -module_exit(dc390_module_exit); - -#ifndef MODULE -static int __init dc390_setup (char *str) -{ - int ints[8],i, im; - - get_options(str, ARRAY_SIZE(ints), ints); - im = ints[0]; - - if (im > 6) { - printk (KERN_NOTICE "DC390: ignore extra params!\n"); - im = 6; - } - - for (i = 0; i < im; i++) - tmscsim[i] = ints[i+1]; - /* dc390_checkparams (); */ - return 1; -} - -__setup("tmscsim=", dc390_setup); -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/tmscsim.h b/ANDROID_3.4.5/drivers/scsi/tmscsim.h deleted file mode 100644 index 77adc54d..00000000 --- a/ANDROID_3.4.5/drivers/scsi/tmscsim.h +++ /dev/null @@ -1,550 +0,0 @@ -/*********************************************************************** -;* File Name : TMSCSIM.H * -;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter * -;* Device Driver * -;***********************************************************************/ -/* $Id: tmscsim.h,v 2.15.2.3 2000/11/17 20:52:27 garloff Exp $ */ - -#ifndef _TMSCSIM_H -#define _TMSCSIM_H - -#include - -#define SCSI_IRQ_NONE 255 - -#define MAX_ADAPTER_NUM 4 -#define MAX_SG_LIST_BUF 16 /* Not used */ -#define MAX_SCSI_ID 8 -#define MAX_SRB_CNT 50 /* Max number of started commands */ - -#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */ - -/* -;----------------------------------------------------------------------- -; SCSI Request Block -;----------------------------------------------------------------------- -*/ -struct dc390_srb -{ -//u8 CmdBlock[12]; - -struct dc390_srb *pNextSRB; -struct dc390_dcb *pSRBDCB; -struct scsi_cmnd *pcmd; -struct scatterlist *pSegmentList; - -struct scatterlist Segmentx; /* make a one entry of S/G list table */ - -unsigned long SGBusAddr; /*;a segment starting address as seen by AM53C974A - in CPU endianness. We're only getting 32-bit bus - addresses by default */ -unsigned long SGToBeXferLen; /*; to be xfer length */ -unsigned long TotalXferredLen; -unsigned long SavedTotXLen; -unsigned long Saved_Ptr; -u32 SRBState; - -u8 SRBStatus; -u8 SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */ - /*; b4-settimeout,b5-Residual valid */ -u8 AdaptStatus; -u8 TargetStatus; - -u8 ScsiPhase; -s8 TagNumber; -u8 SGIndex; -u8 SGcount; - -u8 MsgCnt; -u8 EndMessage; - -u8 MsgInBuf[6]; -u8 MsgOutBuf[6]; - -//u8 IORBFlag; /*;81h-Reset, 2-retry */ -}; - - -/* -;----------------------------------------------------------------------- -; Device Control Block -;----------------------------------------------------------------------- -*/ -struct dc390_dcb -{ -struct dc390_dcb *pNextDCB; -struct dc390_acb *pDCBACB; - -/* Queued SRBs */ -struct dc390_srb *pGoingSRB; -struct dc390_srb *pGoingLast; -struct dc390_srb *pActiveSRB; -u8 GoingSRBCnt; - -u32 TagMask; - -u8 TargetID; /*; SCSI Target ID (SCSI Only) */ -u8 TargetLUN; /*; SCSI Log. Unit (SCSI Only) */ -u8 DevMode; -u8 DCBFlag; - -u8 CtrlR1; -u8 CtrlR3; -u8 CtrlR4; - -u8 SyncMode; /*; 0:async mode */ -u8 NegoPeriod; /*;for nego. */ -u8 SyncPeriod; /*;for reg. */ -u8 SyncOffset; /*;for reg. and nego.(low nibble) */ -}; - - -/* -;----------------------------------------------------------------------- -; Adapter Control Block -;----------------------------------------------------------------------- -*/ -struct dc390_acb -{ -struct Scsi_Host *pScsiHost; -u16 IOPortBase; -u8 IRQLevel; -u8 status; - -u8 SRBCount; -u8 AdapterIndex; /*; nth Adapter this driver */ -u8 DCBCnt; - -u8 TagMaxNum; -u8 ACBFlag; -u8 Gmode2; -u8 scan_devices; - -struct dc390_dcb *pLinkDCB; -struct dc390_dcb *pLastDCB; -struct dc390_dcb *pDCBRunRobin; - -struct dc390_dcb *pActiveDCB; -struct dc390_srb *pFreeSRB; -struct dc390_srb *pTmpSRB; - -u8 msgin123[4]; -u8 Connected; -u8 pad; - -#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0) -spinlock_t lock; -#endif -u8 sel_timeout; -u8 glitch_cfg; - -u8 MsgLen; -u8 Ignore_IRQ; /* Not used */ - -struct pci_dev *pdev; - -unsigned long Cmds; -u32 SelLost; -u32 SelConn; -u32 CmdInQ; -u32 CmdOutOfSRB; - -struct dc390_srb TmpSRB; -struct dc390_srb SRB_array[MAX_SRB_CNT]; /* 50 SRBs */ -}; - - -/*;-----------------------------------------------------------------------*/ - - -#define BIT31 0x80000000 -#define BIT30 0x40000000 -#define BIT29 0x20000000 -#define BIT28 0x10000000 -#define BIT27 0x08000000 -#define BIT26 0x04000000 -#define BIT25 0x02000000 -#define BIT24 0x01000000 -#define BIT23 0x00800000 -#define BIT22 0x00400000 -#define BIT21 0x00200000 -#define BIT20 0x00100000 -#define BIT19 0x00080000 -#define BIT18 0x00040000 -#define BIT17 0x00020000 -#define BIT16 0x00010000 -#define BIT15 0x00008000 -#define BIT14 0x00004000 -#define BIT13 0x00002000 -#define BIT12 0x00001000 -#define BIT11 0x00000800 -#define BIT10 0x00000400 -#define BIT9 0x00000200 -#define BIT8 0x00000100 -#define BIT7 0x00000080 -#define BIT6 0x00000040 -#define BIT5 0x00000020 -#define BIT4 0x00000010 -#define BIT3 0x00000008 -#define BIT2 0x00000004 -#define BIT1 0x00000002 -#define BIT0 0x00000001 - -/*;---UnitCtrlFlag */ -#define UNIT_ALLOCATED BIT0 -#define UNIT_INFO_CHANGED BIT1 -#define FORMATING_MEDIA BIT2 -#define UNIT_RETRY BIT3 - -/*;---UnitFlags */ -#define DASD_SUPPORT BIT0 -#define SCSI_SUPPORT BIT1 -#define ASPI_SUPPORT BIT2 - -/*;----SRBState machine definition */ -#define SRB_FREE 0 -#define SRB_WAIT BIT0 -#define SRB_READY BIT1 -#define SRB_MSGOUT BIT2 /*;arbitration+msg_out 1st byte*/ -#define SRB_MSGIN BIT3 -#define SRB_MSGIN_MULTI BIT4 -#define SRB_COMMAND BIT5 -#define SRB_START_ BIT6 /*;arbitration+msg_out+command_out*/ -#define SRB_DISCONNECT BIT7 -#define SRB_DATA_XFER BIT8 -#define SRB_XFERPAD BIT9 -#define SRB_STATUS BIT10 -#define SRB_COMPLETED BIT11 -#define SRB_ABORT_SENT BIT12 -#define DO_SYNC_NEGO BIT13 -#define SRB_UNEXPECT_RESEL BIT14 - -/*;---SRBstatus */ -#define SRB_OK BIT0 -#define ABORTION BIT1 -#define OVER_RUN BIT2 -#define UNDER_RUN BIT3 -#define PARITY_ERROR BIT4 -#define SRB_ERROR BIT5 - -/*;---ACBFlag */ -#define RESET_DEV BIT0 -#define RESET_DETECT BIT1 -#define RESET_DONE BIT2 - -/*;---DCBFlag */ -#define ABORT_DEV_ BIT0 - -/*;---SRBFlag */ -#define DATAOUT BIT7 -#define DATAIN BIT6 -#define RESIDUAL_VALID BIT5 -#define ENABLE_TIMER BIT4 -#define RESET_DEV0 BIT2 -#define ABORT_DEV BIT1 -#define AUTO_REQSENSE BIT0 - -/*;---Adapter status */ -#define H_STATUS_GOOD 0 -#define H_SEL_TIMEOUT 0x11 -#define H_OVER_UNDER_RUN 0x12 -#define H_UNEXP_BUS_FREE 0x13 -#define H_TARGET_PHASE_F 0x14 -#define H_INVALID_CCB_OP 0x16 -#define H_LINK_CCB_BAD 0x17 -#define H_BAD_TARGET_DIR 0x18 -#define H_DUPLICATE_CCB 0x19 -#define H_BAD_CCB_OR_SG 0x1A -#define H_ABORT 0x0FF - -/* cmd->result */ -#define RES_TARGET 0x000000FF /* Target State */ -#define RES_TARGET_LNX STATUS_MASK /* Only official ... */ -#define RES_ENDMSG 0x0000FF00 /* End Message */ -#define RES_DID 0x00FF0000 /* DID_ codes */ -#define RES_DRV 0xFF000000 /* DRIVER_ codes */ - -#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)) -#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)) - -#define SET_RES_TARGET(who, tgt) do { who &= ~RES_TARGET; who |= (int)(tgt); } while (0) -#define SET_RES_TARGET_LNX(who, tgt) do { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } while (0) -#define SET_RES_MSG(who, msg) do { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; } while (0) -#define SET_RES_DID(who, did) do { who &= ~RES_DID; who |= (int)(did) << 16; } while (0) -#define SET_RES_DRV(who, drv) do { who &= ~RES_DRV; who |= (int)(drv) << 24; } while (0) - -/*;---Sync_Mode */ -#define SYNC_DISABLE 0 -#define SYNC_ENABLE BIT0 -#define SYNC_NEGO_DONE BIT1 -#define WIDE_ENABLE BIT2 /* Not used ;-) */ -#define WIDE_NEGO_DONE BIT3 /* Not used ;-) */ -#define EN_TAG_QUEUEING BIT4 -#define EN_ATN_STOP BIT5 - -#define SYNC_NEGO_OFFSET 15 - -/*;---SCSI bus phase*/ -#define SCSI_DATA_OUT 0 -#define SCSI_DATA_IN 1 -#define SCSI_COMMAND 2 -#define SCSI_STATUS_ 3 -#define SCSI_NOP0 4 -#define SCSI_NOP1 5 -#define SCSI_MSG_OUT 6 -#define SCSI_MSG_IN 7 - -/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ /* One is missing ! */ -#define ABORT_TAG 0x0d - -/* - * SISC query queue - */ -typedef struct { - dma_addr_t saved_dma_handle; -} dc390_cmd_scp_t; - -/* -;========================================================== -; EEPROM byte offset -;========================================================== -*/ -typedef struct _EEprom -{ -u8 EE_MODE1; -u8 EE_SPEED; -u8 xx1; -u8 xx2; -} EEprom, *PEEprom; - -#define REAL_EE_ADAPT_SCSI_ID 64 -#define REAL_EE_MODE2 65 -#define REAL_EE_DELAY 66 -#define REAL_EE_TAG_CMD_NUM 67 - -#define EE_ADAPT_SCSI_ID 32 -#define EE_MODE2 33 -#define EE_DELAY 34 -#define EE_TAG_CMD_NUM 35 - -#define EE_LEN 40 - -/*; EE_MODE1 bits definition*/ -#define PARITY_CHK_ BIT0 -#define SYNC_NEGO_ BIT1 -#define EN_DISCONNECT_ BIT2 -#define SEND_START_ BIT3 -#define TAG_QUEUEING_ BIT4 - -/*; EE_MODE2 bits definition*/ -#define MORE2_DRV BIT0 -#define GREATER_1G BIT1 -#define RST_SCSI_BUS BIT2 -#define ACTIVE_NEGATION BIT3 -#define NO_SEEK BIT4 -#define LUN_CHECK BIT5 - -#define ENABLE_CE 1 -#define DISABLE_CE 0 -#define EEPROM_READ 0x80 - -/* -;========================================================== -; AMD 53C974 Registers bit Definition -;========================================================== -*/ -/* -;==================== -; SCSI Register -;==================== -*/ - -/*; Command Reg.(+0CH) (rw) */ -#define DMA_COMMAND BIT7 -#define NOP_CMD 0 -#define CLEAR_FIFO_CMD 1 -#define RST_DEVICE_CMD 2 -#define RST_SCSI_BUS_CMD 3 - -#define INFO_XFER_CMD 0x10 -#define INITIATOR_CMD_CMPLTE 0x11 -#define MSG_ACCEPTED_CMD 0x12 -#define XFER_PAD_BYTE 0x18 -#define SET_ATN_CMD 0x1A -#define RESET_ATN_CMD 0x1B - -#define SEL_WO_ATN 0x41 /* currently not used */ -#define SEL_W_ATN 0x42 -#define SEL_W_ATN_STOP 0x43 -#define SEL_W_ATN3 0x46 -#define EN_SEL_RESEL 0x44 -#define DIS_SEL_RESEL 0x45 /* currently not used */ -#define RESEL 0x40 /* " */ -#define RESEL_ATN3 0x47 /* " */ - -#define DATA_XFER_CMD INFO_XFER_CMD - - -/*; SCSI Status Reg.(+10H) (r) */ -#define INTERRUPT BIT7 -#define ILLEGAL_OP_ERR BIT6 -#define PARITY_ERR BIT5 -#define COUNT_2_ZERO BIT4 -#define GROUP_CODE_VALID BIT3 -#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0) -/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */ - -/*; Interrupt Status Reg.(+14H) (r) */ -#define SCSI_RESET BIT7 -#define INVALID_CMD BIT6 -#define DISCONNECTED BIT5 -#define SERVICE_REQUEST BIT4 -#define SUCCESSFUL_OP BIT3 -#define RESELECTED BIT2 -#define SEL_ATTENTION BIT1 -#define SELECTED BIT0 - -/*; Internal State Reg.(+18H) (r) */ -#define SYNC_OFFSET_FLAG BIT3 -#define INTRN_STATE_MASK (BIT2+BIT1+BIT0) -/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */ - -/*; Clock Factor Reg.(+24H) (w) */ -#define CLK_FREQ_40MHZ 0 -#define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0) -#define CLK_FREQ_30MHZ (BIT2+BIT1) -#define CLK_FREQ_25MHZ (BIT2+BIT0) -#define CLK_FREQ_20MHZ BIT2 -#define CLK_FREQ_15MHZ (BIT1+BIT0) -#define CLK_FREQ_10MHZ BIT1 - -/*; Control Reg. 1(+20H) (rw) */ -#define EXTENDED_TIMING BIT7 -#define DIS_INT_ON_SCSI_RST BIT6 -#define PARITY_ERR_REPO BIT4 -#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) /* host adapter ID */ - -/*; Control Reg. 2(+2CH) (rw) */ -#define EN_FEATURE BIT6 -#define EN_SCSI2_CMD BIT3 - -/*; Control Reg. 3(+30H) (rw) */ -#define ID_MSG_CHECK BIT7 -#define EN_QTAG_MSG BIT6 -#define EN_GRP2_CMD BIT5 -#define FAST_SCSI BIT4 /* ;10MB/SEC */ -#define FAST_CLK BIT3 /* ;25 - 40 MHZ */ - -/*; Control Reg. 4(+34H) (rw) */ -#define EATER_12NS 0 -#define EATER_25NS BIT7 -#define EATER_35NS BIT6 -#define EATER_0NS (BIT7+BIT6) -#define REDUCED_POWER BIT5 -#define CTRL4_RESERVED BIT4 /* must be 1 acc. to AM53C974.c */ -#define NEGATE_REQACKDATA BIT2 -#define NEGATE_REQACK BIT3 - -#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2))) -#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0) - -/* -;==================== -; DMA Register -;==================== -*/ -/*; DMA Command Reg.(+40H) (rw) */ -#define READ_DIRECTION BIT7 -#define WRITE_DIRECTION 0 -#define EN_DMA_INT BIT6 -#define EN_PAGE_INT BIT5 /* page transfer interrupt enable */ -#define MAP_TO_MDL BIT4 -#define DIAGNOSTIC BIT2 -#define DMA_IDLE_CMD 0 -#define DMA_BLAST_CMD BIT0 -#define DMA_ABORT_CMD BIT1 -#define DMA_START_CMD (BIT1+BIT0) - -/*; DMA Status Reg.(+54H) (r) */ -#define PCI_MS_ABORT BIT6 -#define BLAST_COMPLETE BIT5 -#define SCSI_INTERRUPT BIT4 -#define DMA_XFER_DONE BIT3 -#define DMA_XFER_ABORT BIT2 -#define DMA_XFER_ERROR BIT1 -#define POWER_DOWN BIT0 - -/*; DMA SCSI Bus and Ctrl.(+70H) */ -#define EN_INT_ON_PCI_ABORT BIT25 -#define WRT_ERASE_DMA_STAT BIT24 -#define PW_DOWN_CTRL BIT21 -#define SCSI_BUSY BIT20 -#define SCLK BIT19 -#define SCAM BIT18 -#define SCSI_LINES 0x0003ffff - -/* -;========================================================== -; SCSI Chip register address offset -;========================================================== -;Registers are rw unless declared otherwise -*/ -#define CtcReg_Low 0x00 /* r curr. transfer count */ -#define CtcReg_Mid 0x04 /* r */ -#define CtcReg_High 0x38 /* r */ -#define ScsiFifo 0x08 -#define ScsiCmd 0x0C -#define Scsi_Status 0x10 /* r */ -#define INT_Status 0x14 /* r */ -#define Sync_Period 0x18 /* w */ -#define Sync_Offset 0x1C /* w */ -#define Clk_Factor 0x24 /* w */ -#define CtrlReg1 0x20 -#define CtrlReg2 0x2C -#define CtrlReg3 0x30 -#define CtrlReg4 0x34 -#define DMA_Cmd 0x40 -#define DMA_XferCnt 0x44 /* rw starting transfer count (32 bit) */ -#define DMA_XferAddr 0x48 /* rw starting physical address (32 bit) */ -#define DMA_Wk_ByteCntr 0x4C /* r working byte counter */ -#define DMA_Wk_AddrCntr 0x50 /* r working address counter */ -#define DMA_Status 0x54 /* r */ -#define DMA_MDL_Addr 0x58 /* rw starting MDL address */ -#define DMA_Wk_MDL_Cntr 0x5C /* r working MDL counter */ -#define DMA_ScsiBusCtrl 0x70 /* rw SCSI Bus, PCI/DMA Ctrl */ - -#define StcReg_Low CtcReg_Low /* w start transfer count */ -#define StcReg_Mid CtcReg_Mid /* w */ -#define StcReg_High CtcReg_High /* w */ -#define Scsi_Dest_ID Scsi_Status /* w */ -#define Scsi_TimeOut INT_Status /* w */ -#define Intern_State Sync_Period /* r */ -#define Current_Fifo Sync_Offset /* r Curr. FIFO / int. state */ - - -#define DC390_read8(address) \ - (inb (pACB->IOPortBase + (address))) - -#define DC390_read8_(address, base) \ - (inb ((u16)(base) + (address))) - -#define DC390_read16(address) \ - (inw (pACB->IOPortBase + (address))) - -#define DC390_read32(address) \ - (inl (pACB->IOPortBase + (address))) - -#define DC390_write8(address,value) \ - outb ((value), pACB->IOPortBase + (address)) - -#define DC390_write8_(address,value,base) \ - outb ((value), (u16)(base) + (address)) - -#define DC390_write16(address,value) \ - outw ((value), pACB->IOPortBase + (address)) - -#define DC390_write32(address,value) \ - outl ((value), pACB->IOPortBase + (address)) - - -#endif /* _TMSCSIM_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/u14-34f.c b/ANDROID_3.4.5/drivers/scsi/u14-34f.c deleted file mode 100644 index 9c216e56..00000000 --- a/ANDROID_3.4.5/drivers/scsi/u14-34f.c +++ /dev/null @@ -1,1971 +0,0 @@ -/* - * u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters. - * - * 03 Jun 2003 Rev. 8.10 for linux-2.5.70 - * + Update for new IRQ API. - * + Use "goto" when appropriate. - * + Drop u14-34f.h. - * + Update for new module_param API. - * + Module parameters can now be specified only in the - * same format as the kernel boot options. - * - * boot option old module param - * ----------- ------------------ - * addr,... io_port=addr,... - * lc:[y|n] linked_comm=[1|0] - * mq:xx max_queue_depth=xx - * tm:[0|1|2] tag_mode=[0|1|2] - * et:[y|n] ext_tran=[1|0] - * of:[y|n] have_old_firmware=[1|0] - * - * A valid example using the new parameter format is: - * modprobe u14-34f "u14-34f=0x340,0x330,lc:y,tm:0,mq:4" - * - * which is equivalent to the old format: - * modprobe u14-34f io_port=0x340,0x330 linked_comm=1 tag_mode=0 \ - * max_queue_depth=4 - * - * With actual module code, u14-34f and u14_34f are equivalent - * as module parameter names. - * - * 12 Feb 2003 Rev. 8.04 for linux 2.5.60 - * + Release irq before calling scsi_register. - * - * 12 Nov 2002 Rev. 8.02 for linux 2.5.47 - * + Release driver_lock before calling scsi_register. - * - * 11 Nov 2002 Rev. 8.01 for linux 2.5.47 - * + Fixed bios_param and scsicam_bios_param calling parameters. - * - * 28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4 - * + Use new tcq and adjust_queue_depth api. - * + New command line option (tm:[0-2]) to choose the type of tags: - * 0 -> disable tagging ; 1 -> simple tags ; 2 -> ordered tags. - * Default is tm:0 (tagged commands disabled). - * For compatibility the "tc:" option is an alias of the "tm:" - * option; tc:n is equivalent to tm:0 and tc:y is equivalent to - * tm:1. - * - * 10 Oct 2002 Rev. 7.70 for linux 2.5.42 - * + Foreport from revision 6.70. - * - * 25 Jun 2002 Rev. 6.70 for linux 2.4.19 - * + Fixed endian-ness problem due to bitfields. - * - * 21 Feb 2002 Rev. 6.52 for linux 2.4.18 - * + Backport from rev. 7.22 (use io_request_lock). - * - * 20 Feb 2002 Rev. 7.22 for linux 2.5.5 - * + Remove any reference to virt_to_bus(). - * + Fix pio hang while detecting multiple HBAs. - * - * 01 Jan 2002 Rev. 7.20 for linux 2.5.1 - * + Use the dynamic DMA mapping API. - * - * 19 Dec 2001 Rev. 7.02 for linux 2.5.1 - * + Use SCpnt->sc_data_direction if set. - * + Use sglist.page instead of sglist.address. - * - * 11 Dec 2001 Rev. 7.00 for linux 2.5.1 - * + Use host->host_lock instead of io_request_lock. - * - * 1 May 2001 Rev. 6.05 for linux 2.4.4 - * + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d) - * - * 25 Jan 2001 Rev. 6.03 for linux 2.4.0 - * + "check_region" call replaced by "request_region". - * - * 22 Nov 2000 Rev. 6.02 for linux 2.4.0-test11 - * + Removed old scsi error handling support. - * + The obsolete boot option flag eh:n is silently ignored. - * + Removed error messages while a disk drive is powered up at - * boot time. - * + Improved boot messages: all tagged capable device are - * indicated as "tagged". - * - * 16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18 - * + Updated to the new __setup interface for boot command line options. - * + When loaded as a module, accepts the new parameter boot_options - * which value is a string with the same format of the kernel boot - * command line options. A valid example is: - * modprobe u14-34f 'boot_options="0x230,0x340,lc:y,mq:4"' - * - * 22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11 - * + Removed pre-2.2 source code compatibility. - * - * 26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111 - * Added command line option (et:[y|n]) to use the existing - * translation (returned by scsicam_bios_param) as disk geometry. - * The default is et:n, which uses the disk geometry jumpered - * on the board. - * The default value et:n is compatible with all previous revisions - * of this driver. - * - * 28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104 - * Increased busy timeout from 10 msec. to 200 msec. while - * processing interrupts. - * - * 18 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102 - * Improved abort handling during the eh recovery process. - * - * 13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101 - * The driver is now fully SMP safe, including the - * abort and reset routines. - * Added command line options (eh:[y|n]) to choose between - * new_eh_code and the old scsi code. - * If linux version >= 2.1.101 the default is eh:y, while the eh - * option is ignored for previous releases and the old scsi code - * is used. - * - * 18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97 - * Reworked interrupt handler. - * - * 11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95 - * Major reliability improvement: when a batch with overlapping - * requests is detected, requests are queued one at a time - * eliminating any possible board or drive reordering. - * - * 10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95 - * Improved SMP support (if linux version >= 2.1.95). - * - * 9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94 - * Performance improvement: when sequential i/o is detected, - * always use direct sort instead of reverse sort. - * - * 4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92 - * io_port is now unsigned long. - * - * 17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88 - * Use new scsi error handling code (if linux version >= 2.1.88). - * Use new interrupt code. - * - * 12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55 - * Use of udelay inside the wait loops to avoid timeout - * problems with fast cpus. - * Removed check about useless calls to the interrupt service - * routine (reported on SMP systems only). - * At initialization time "sorted/unsorted" is displayed instead - * of "linked/unlinked" to reinforce the fact that "linking" is - * nothing but "elevator sorting" in the actual implementation. - * - * 17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38 - * Use of serial_number_at_timeout in abort and reset processing. - * Use of the __initfunc and __initdata macro in setup code. - * Minor cleanups in the list_statistics code. - * - * 24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26 - * When loading as a module, parameter passing is now supported - * both in 2.0 and in 2.1 style. - * Fixed data transfer direction for some SCSI opcodes. - * Immediate acknowledge to request sense commands. - * Linked commands to each disk device are now reordered by elevator - * sorting. Rare cases in which reordering of write requests could - * cause wrong results are managed. - * - * 18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28 - * Added command line options to enable/disable linked commands - * (lc:[y|n]), old firmware support (of:[y|n]) and to set the max - * queue depth (mq:xx). Default is "u14-34f=lc:n,of:n,mq:8". - * Improved command linking. - * - * 8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27 - * Added linked command support. - * - * 3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27 - * Added queue depth adjustment. - * - * 22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26 - * The list of i/o ports to be probed can be overwritten by the - * "u14-34f=port0,port1,...." boot command line option. - * Scatter/gather lists are now allocated by a number of kmalloc - * calls, in order to avoid the previous size limit of 64Kb. - * - * 16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25 - * Added multichannel support. - * - * 27 Sep 1996 rev. 2.12 for linux 2.1.0 - * Portability cleanups (virtual/bus addressing, little/big endian - * support). - * - * 09 Jul 1996 rev. 2.11 for linux 2.0.4 - * "Data over/under-run" no longer implies a redo on all targets. - * Number of internal retries is now limited. - * - * 16 Apr 1996 rev. 2.10 for linux 1.3.90 - * New argument "reset_flags" to the reset routine. - * - * 21 Jul 1995 rev. 2.02 for linux 1.3.11 - * Fixed Data Transfer Direction for some SCSI commands. - * - * 13 Jun 1995 rev. 2.01 for linux 1.2.10 - * HAVE_OLD_UX4F_FIRMWARE should be defined for U34F boards when - * the firmware prom is not the latest one (28008-006). - * - * 11 Mar 1995 rev. 2.00 for linux 1.2.0 - * Fixed a bug which prevented media change detection for removable - * disk drives. - * - * 23 Feb 1995 rev. 1.18 for linux 1.1.94 - * Added a check for scsi_register returning NULL. - * - * 11 Feb 1995 rev. 1.17 for linux 1.1.91 - * U14F qualified to run with 32 sglists. - * Now DEBUG_RESET is disabled by default. - * - * 9 Feb 1995 rev. 1.16 for linux 1.1.90 - * Use host->wish_block instead of host->block. - * - * 8 Feb 1995 rev. 1.15 for linux 1.1.89 - * Cleared target_time_out counter while performing a reset. - * - * 28 Jan 1995 rev. 1.14 for linux 1.1.86 - * Added module support. - * Log and do a retry when a disk drive returns a target status - * different from zero on a recovered error. - * Auto detects if U14F boards have an old firmware revision. - * Max number of scatter/gather lists set to 16 for all boards - * (most installation run fine using 33 sglists, while other - * has problems when using more than 16). - * - * 16 Jan 1995 rev. 1.13 for linux 1.1.81 - * Display a message if check_region detects a port address - * already in use. - * - * 15 Dec 1994 rev. 1.12 for linux 1.1.74 - * The host->block flag is set for all the detected ISA boards. - * - * 30 Nov 1994 rev. 1.11 for linux 1.1.68 - * Redo i/o on target status CHECK_CONDITION for TYPE_DISK only. - * Added optional support for using a single board at a time. - * - * 14 Nov 1994 rev. 1.10 for linux 1.1.63 - * - * 28 Oct 1994 rev. 1.09 for linux 1.1.58 Final BETA release. - * 16 Jul 1994 rev. 1.00 for linux 1.1.29 Initial ALPHA release. - * - * This driver is a total replacement of the original UltraStor - * scsi driver, but it supports ONLY the 14F and 34F boards. - * It can be configured in the same kernel in which the original - * ultrastor driver is configured to allow the original U24F - * support. - * - * Multiple U14F and/or U34F host adapters are supported. - * - * Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com) - * - * Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that redistributions of source - * code retain the above copyright notice and this comment without - * modification. - * - * WARNING: if your 14/34F board has an old firmware revision (see below) - * you must change "#undef" into "#define" in the following - * statement. - */ -#undef HAVE_OLD_UX4F_FIRMWARE -/* - * The UltraStor 14F, 24F, and 34F are a family of intelligent, high - * performance SCSI-2 host adapters. - * Here is the scoop on the various models: - * - * 14F - ISA first-party DMA HA with floppy support and WD1003 emulation. - * 24F - EISA Bus Master HA with floppy support and WD1003 emulation. - * 34F - VESA Local-Bus Bus Master HA (no WD1003 emulation). - * - * This code has been tested with up to two U14F boards, using both - * firmware 28004-005/38004-004 (BIOS rev. 2.00) and the latest firmware - * 28004-006/38004-005 (BIOS rev. 2.01). - * - * The latest firmware is required in order to get reliable operations when - * clustering is enabled. ENABLE_CLUSTERING provides a performance increase - * up to 50% on sequential access. - * - * Since the struct scsi_host_template structure is shared among all 14F and 34F, - * the last setting of use_clustering is in effect for all of these boards. - * - * Here a sample configuration using two U14F boards: - * - U14F0: ISA 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, MB 16, of:n, lc:y, mq:8. - U14F1: ISA 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, MB 16, of:n, lc:y, mq:8. - * - * The boot controller must have its BIOS enabled, while other boards can - * have their BIOS disabled, or enabled to an higher address. - * Boards are named Ux4F0, Ux4F1..., according to the port address order in - * the io_port[] array. - * - * The following facts are based on real testing results (not on - * documentation) on the above U14F board. - * - * - The U14F board should be jumpered for bus on time less or equal to 7 - * microseconds, while the default is 11 microseconds. This is order to - * get acceptable performance while using floppy drive and hard disk - * together. The jumpering for 7 microseconds is: JP13 pin 15-16, - * JP14 pin 7-8 and pin 9-10. - * The reduction has a little impact on scsi performance. - * - * - If scsi bus length exceeds 3m., the scsi bus speed needs to be reduced - * from 10Mhz to 5Mhz (do this by inserting a jumper on JP13 pin 7-8). - * - * - If U14F on board firmware is older than 28004-006/38004-005, - * the U14F board is unable to provide reliable operations if the scsi - * request length exceeds 16Kbyte. When this length is exceeded the - * behavior is: - * - adapter_status equal 0x96 or 0xa3 or 0x93 or 0x94; - * - adapter_status equal 0 and target_status equal 2 on for all targets - * in the next operation following the reset. - * This sequence takes a long time (>3 seconds), so in the meantime - * the SD_TIMEOUT in sd.c could expire giving rise to scsi aborts - * (SD_TIMEOUT has been increased from 3 to 6 seconds in 1.1.31). - * Because of this I had to DISABLE_CLUSTERING and to work around the - * bus reset in the interrupt service routine, returning DID_BUS_BUSY - * so that the operations are retried without complains from the scsi.c - * code. - * Any reset of the scsi bus is going to kill tape operations, since - * no retry is allowed for tapes. Bus resets are more likely when the - * scsi bus is under heavy load. - * Requests using scatter/gather have a maximum length of 16 x 1024 bytes - * when DISABLE_CLUSTERING is in effect, but unscattered requests could be - * larger than 16Kbyte. - * - * The new firmware has fixed all the above problems. - * - * For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01), - * the latest firmware prom is 28008-006. Older firmware 28008-005 has - * problems when using more than 16 scatter/gather lists. - * - * The list of i/o ports to be probed can be totally replaced by the - * boot command line option: "u14-34f=port0,port1,port2,...", where the - * port0, port1... arguments are ISA/VESA addresses to be probed. - * For example using "u14-34f=0x230,0x340", the driver probes only the two - * addresses 0x230 and 0x340 in this order; "u14-34f=0" totally disables - * this driver. - * - * After the optional list of detection probes, other possible command line - * options are: - * - * et:y use disk geometry returned by scsicam_bios_param; - * et:n use disk geometry jumpered on the board; - * lc:y enables linked commands; - * lc:n disables linked commands; - * tm:0 disables tagged commands (same as tc:n); - * tm:1 use simple queue tags (same as tc:y); - * tm:2 use ordered queue tags (same as tc:2); - * of:y enables old firmware support; - * of:n disables old firmware support; - * mq:xx set the max queue depth to the value xx (2 <= xx <= 8). - * - * The default value is: "u14-34f=lc:n,of:n,mq:8,tm:0,et:n". - * An example using the list of detection probes could be: - * "u14-34f=0x230,0x340,lc:y,tm:2,of:n,mq:4,et:n". - * - * When loading as a module, parameters can be specified as well. - * The above example would be (use 1 in place of y and 0 in place of n): - * - * modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \ - * max_queue_depth=4 ext_tran=0 tag_mode=2 - * - * ---------------------------------------------------------------------------- - * In this implementation, linked commands are designed to work with any DISK - * or CD-ROM, since this linking has only the intent of clustering (time-wise) - * and reordering by elevator sorting commands directed to each device, - * without any relation with the actual SCSI protocol between the controller - * and the device. - * If Q is the queue depth reported at boot time for each device (also named - * cmds/lun) and Q > 2, whenever there is already an active command to the - * device all other commands to the same device (up to Q-1) are kept waiting - * in the elevator sorting queue. When the active command completes, the - * commands in this queue are sorted by sector address. The sort is chosen - * between increasing or decreasing by minimizing the seek distance between - * the sector of the commands just completed and the sector of the first - * command in the list to be sorted. - * Trivial math assures that the unsorted average seek distance when doing - * random seeks over S sectors is S/3. - * When (Q-1) requests are uniformly distributed over S sectors, the average - * distance between two adjacent requests is S/((Q-1) + 1), so the sorted - * average seek distance for (Q-1) random requests over S sectors is S/Q. - * The elevator sorting hence divides the seek distance by a factor Q/3. - * The above pure geometric remarks are valid in all cases and the - * driver effectively reduces the seek distance by the predicted factor - * when there are Q concurrent read i/o operations on the device, but this - * does not necessarily results in a noticeable performance improvement: - * your mileage may vary.... - * - * Note: command reordering inside a batch of queued commands could cause - * wrong results only if there is at least one write request and the - * intersection (sector-wise) of all requests is not empty. - * When the driver detects a batch including overlapping requests - * (a really rare event) strict serial (pid) order is enforced. - * ---------------------------------------------------------------------------- - * - * The boards are named Ux4F0, Ux4F1,... according to the detection order. - * - * In order to support multiple ISA boards in a reliable way, - * the driver sets host->wish_block = TRUE for all ISA boards. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -static int u14_34f_detect(struct scsi_host_template *); -static int u14_34f_release(struct Scsi_Host *); -static int u14_34f_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static int u14_34f_eh_abort(struct scsi_cmnd *); -static int u14_34f_eh_host_reset(struct scsi_cmnd *); -static int u14_34f_bios_param(struct scsi_device *, struct block_device *, - sector_t, int *); -static int u14_34f_slave_configure(struct scsi_device *); - -static struct scsi_host_template driver_template = { - .name = "UltraStor 14F/34F rev. 8.10.00 ", - .detect = u14_34f_detect, - .release = u14_34f_release, - .queuecommand = u14_34f_queuecommand, - .eh_abort_handler = u14_34f_eh_abort, - .eh_host_reset_handler = u14_34f_eh_host_reset, - .bios_param = u14_34f_bios_param, - .slave_configure = u14_34f_slave_configure, - .this_id = 7, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, - }; - -#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD) -#error "Adjust your defines" -#endif - -/* Values for the PRODUCT_ID ports for the 14/34F */ -#define PRODUCT_ID1 0x56 -#define PRODUCT_ID2 0x40 /* NOTE: Only upper nibble is used */ - -/* Subversion values */ -#define ISA 0 -#define ESA 1 - -#define OP_HOST_ADAPTER 0x1 -#define OP_SCSI 0x2 -#define OP_RESET 0x4 -#define DTD_SCSI 0x0 -#define DTD_IN 0x1 -#define DTD_OUT 0x2 -#define DTD_NONE 0x3 -#define HA_CMD_INQUIRY 0x1 -#define HA_CMD_SELF_DIAG 0x2 -#define HA_CMD_READ_BUFF 0x3 -#define HA_CMD_WRITE_BUFF 0x4 - -#undef DEBUG_LINKED_COMMANDS -#undef DEBUG_DETECT -#undef DEBUG_INTERRUPT -#undef DEBUG_RESET -#undef DEBUG_GENERATE_ERRORS -#undef DEBUG_GENERATE_ABORTS -#undef DEBUG_GEOMETRY - -#define MAX_ISA 3 -#define MAX_VESA 1 -#define MAX_EISA 0 -#define MAX_PCI 0 -#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI) -#define MAX_CHANNEL 1 -#define MAX_LUN 8 -#define MAX_TARGET 8 -#define MAX_MAILBOXES 16 -#define MAX_SGLIST 32 -#define MAX_SAFE_SGLIST 16 -#define MAX_INTERNAL_RETRIES 64 -#define MAX_CMD_PER_LUN 2 -#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN) - -#define SKIP ULONG_MAX -#define FALSE 0 -#define TRUE 1 -#define FREE 0 -#define IN_USE 1 -#define LOCKED 2 -#define IN_RESET 3 -#define IGNORE 4 -#define READY 5 -#define ABORTING 6 -#define NO_DMA 0xff -#define MAXLOOP 10000 -#define TAG_DISABLED 0 -#define TAG_SIMPLE 1 -#define TAG_ORDERED 2 - -#define REG_LCL_MASK 0 -#define REG_LCL_INTR 1 -#define REG_SYS_MASK 2 -#define REG_SYS_INTR 3 -#define REG_PRODUCT_ID1 4 -#define REG_PRODUCT_ID2 5 -#define REG_CONFIG1 6 -#define REG_CONFIG2 7 -#define REG_OGM 8 -#define REG_ICM 12 -#define REGION_SIZE 13UL -#define BSY_ASSERTED 0x01 -#define IRQ_ASSERTED 0x01 -#define CMD_RESET 0xc0 -#define CMD_OGM_INTR 0x01 -#define CMD_CLR_INTR 0x01 -#define CMD_ENA_INTR 0x81 -#define ASOK 0x00 -#define ASST 0x91 - -#define YESNO(a) ((a) ? 'y' : 'n') -#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM) - -#define PACKED __attribute__((packed)) - -struct sg_list { - unsigned int address; /* Segment Address */ - unsigned int num_bytes; /* Segment Length */ - }; - -/* MailBox SCSI Command Packet */ -struct mscp { - -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char sg:1, ca:1, dcn:1, xdir:2, opcode:3; - unsigned char lun: 3, channel:2, target:3; -#else - unsigned char opcode: 3, /* type of command */ - xdir: 2, /* data transfer direction */ - dcn: 1, /* disable disconnect */ - ca: 1, /* use cache (if available) */ - sg: 1; /* scatter/gather operation */ - unsigned char target: 3, /* SCSI target id */ - channel: 2, /* SCSI channel number */ - lun: 3; /* SCSI logical unit number */ -#endif - - unsigned int data_address PACKED; /* transfer data pointer */ - unsigned int data_len PACKED; /* length in bytes */ - unsigned int link_address PACKED; /* for linking command chains */ - unsigned char clink_id; /* identifies command in chain */ - unsigned char use_sg; /* (if sg is set) 8 bytes per list */ - unsigned char sense_len; - unsigned char cdb_len; /* 6, 10, or 12 */ - unsigned char cdb[12]; /* SCSI Command Descriptor Block */ - unsigned char adapter_status; /* non-zero indicates HA error */ - unsigned char target_status; /* non-zero indicates target error */ - unsigned int sense_addr PACKED; - - /* Additional fields begin here. */ - struct scsi_cmnd *SCpnt; - unsigned int cpp_index; /* cp index */ - - /* All the cp structure is zero filled by queuecommand except the - following CP_TAIL_SIZE bytes, initialized by detect */ - dma_addr_t cp_dma_addr; /* dma handle for this cp structure */ - struct sg_list *sglist; /* pointer to the allocated SG list */ - }; - -#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t)) - -struct hostdata { - struct mscp cp[MAX_MAILBOXES]; /* Mailboxes for this board */ - unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */ - unsigned int last_cp_used; /* Index of last mailbox used */ - unsigned int iocount; /* Total i/o done for this board */ - int board_number; /* Number of this board */ - char board_name[16]; /* Name of this board */ - int in_reset; /* True if board is doing a reset */ - int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */ - int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */ - unsigned int retries; /* Number of internal retries */ - unsigned long last_retried_pid; /* Pid of last retried command */ - unsigned char subversion; /* Bus type, either ISA or ESA */ - struct pci_dev *pdev; /* Always NULL */ - unsigned char heads; - unsigned char sectors; - char board_id[256]; /* data from INQUIRY on this board */ - }; - -static struct Scsi_Host *sh[MAX_BOARDS + 1]; -static const char *driver_name = "Ux4F"; -static char sha[MAX_BOARDS]; -static DEFINE_SPINLOCK(driver_lock); - -/* Initialize num_boards so that ihdlr can work while detect is in progress */ -static unsigned int num_boards = MAX_BOARDS; - -static unsigned long io_port[] = { - - /* Space for MAX_INT_PARAM ports usable while loading as a module */ - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, - SKIP, SKIP, - - /* Possible ISA/VESA ports */ - 0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140, - - /* End of list */ - 0x0 - }; - -#define HD(board) ((struct hostdata *) &sh[board]->hostdata) -#define BN(board) (HD(board)->board_name) - -/* Device is Little Endian */ -#define H2DEV(x) cpu_to_le32(x) -#define DEV2H(x) le32_to_cpu(x) - -static irqreturn_t do_interrupt_handler(int, void *); -static void flush_dev(struct scsi_device *, unsigned long, unsigned int, unsigned int); -static int do_trace = FALSE; -static int setup_done = FALSE; -static int link_statistics; -static int ext_tran = FALSE; - -#if defined(HAVE_OLD_UX4F_FIRMWARE) -static int have_old_firmware = TRUE; -#else -static int have_old_firmware = FALSE; -#endif - -#if defined(CONFIG_SCSI_U14_34F_TAGGED_QUEUE) -static int tag_mode = TAG_SIMPLE; -#else -static int tag_mode = TAG_DISABLED; -#endif - -#if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS) -static int linked_comm = TRUE; -#else -static int linked_comm = FALSE; -#endif - -#if defined(CONFIG_SCSI_U14_34F_MAX_TAGS) -static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS; -#else -static int max_queue_depth = MAX_CMD_PER_LUN; -#endif - -#define MAX_INT_PARAM 10 -#define MAX_BOOT_OPTIONS_SIZE 256 -static char boot_options[MAX_BOOT_OPTIONS_SIZE]; - -#if defined(MODULE) -#include -#include - -module_param_string(u14_34f, boot_options, MAX_BOOT_OPTIONS_SIZE, 0); -MODULE_PARM_DESC(u14_34f, " equivalent to the \"u14-34f=...\" kernel boot " \ -"option." \ -" Example: modprobe u14-34f \"u14_34f=0x340,0x330,lc:y,tm:0,mq:4\""); -MODULE_AUTHOR("Dario Ballabio"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("UltraStor 14F/34F SCSI Driver"); - -#endif - -static int u14_34f_slave_configure(struct scsi_device *dev) { - int j, tqd, utqd; - char *tag_suffix, *link_suffix; - struct Scsi_Host *host = dev->host; - - j = ((struct hostdata *) host->hostdata)->board_number; - - utqd = MAX_CMD_PER_LUN; - tqd = max_queue_depth; - - if (TLDEV(dev->type) && dev->tagged_supported) - - if (tag_mode == TAG_SIMPLE) { - scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd); - tag_suffix = ", simple tags"; - } - else if (tag_mode == TAG_ORDERED) { - scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd); - tag_suffix = ", ordered tags"; - } - else { - scsi_adjust_queue_depth(dev, 0, tqd); - tag_suffix = ", no tags"; - } - - else if (TLDEV(dev->type) && linked_comm) { - scsi_adjust_queue_depth(dev, 0, tqd); - tag_suffix = ", untagged"; - } - - else { - scsi_adjust_queue_depth(dev, 0, utqd); - tag_suffix = ""; - } - - if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2) - link_suffix = ", sorted"; - else if (TLDEV(dev->type)) - link_suffix = ", unsorted"; - else - link_suffix = ""; - - sdev_printk(KERN_INFO, dev, "cmds/lun %d%s%s.\n", - dev->queue_depth, link_suffix, tag_suffix); - - return FALSE; -} - -static int wait_on_busy(unsigned long iobase, unsigned int loop) { - - while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) { - udelay(1L); - if (--loop == 0) return TRUE; - } - - return FALSE; -} - -static int board_inquiry(unsigned int j) { - struct mscp *cpp; - dma_addr_t id_dma_addr; - unsigned int limit = 0; - unsigned long time; - - id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id, - sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL); - cpp = &HD(j)->cp[0]; - cpp->cp_dma_addr = pci_map_single(HD(j)->pdev, cpp, sizeof(struct mscp), - PCI_DMA_BIDIRECTIONAL); - memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); - cpp->opcode = OP_HOST_ADAPTER; - cpp->xdir = DTD_IN; - cpp->data_address = H2DEV(id_dma_addr); - cpp->data_len = H2DEV(sizeof(HD(j)->board_id)); - cpp->cdb_len = 6; - cpp->cdb[0] = HA_CMD_INQUIRY; - - if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { - printk("%s: board_inquiry, adapter busy.\n", BN(j)); - return TRUE; - } - - HD(j)->cp_stat[0] = IGNORE; - - /* Clear the interrupt indication */ - outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); - - /* Store pointer in OGM address bytes */ - outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); - - /* Issue OGM interrupt */ - outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); - - spin_unlock_irq(&driver_lock); - time = jiffies; - while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L); - spin_lock_irq(&driver_lock); - - if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) { - HD(j)->cp_stat[0] = FREE; - printk("%s: board_inquiry, err 0x%x.\n", BN(j), cpp->adapter_status); - return TRUE; - } - - pci_unmap_single(HD(j)->pdev, cpp->cp_dma_addr, sizeof(struct mscp), - PCI_DMA_BIDIRECTIONAL); - pci_unmap_single(HD(j)->pdev, id_dma_addr, sizeof(HD(j)->board_id), - PCI_DMA_BIDIRECTIONAL); - return FALSE; -} - -static int port_detect \ - (unsigned long port_base, unsigned int j, struct scsi_host_template *tpnt) { - unsigned char irq, dma_channel, subversion, i; - unsigned char in_byte; - char *bus_type, dma_name[16]; - - /* Allowed BIOS base addresses (NULL indicates reserved) */ - unsigned long bios_segment_table[8] = { - 0, - 0xc4000, 0xc8000, 0xcc000, 0xd0000, - 0xd4000, 0xd8000, 0xdc000 - }; - - /* Allowed IRQs */ - unsigned char interrupt_table[4] = { 15, 14, 11, 10 }; - - /* Allowed DMA channels for ISA (0 indicates reserved) */ - unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; - - /* Head/sector mappings */ - struct { - unsigned char heads; - unsigned char sectors; - } mapping_table[4] = { - { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 } - }; - - struct config_1 { - -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char dma_channel: 2, interrupt:2, - removable_disks_as_fixed:1, bios_segment: 3; -#else - unsigned char bios_segment: 3, removable_disks_as_fixed: 1, - interrupt: 2, dma_channel: 2; -#endif - - } config_1; - - struct config_2 { - -#if defined(__BIG_ENDIAN_BITFIELD) - unsigned char tfr_port: 2, bios_drive_number: 1, - mapping_mode: 2, ha_scsi_id: 3; -#else - unsigned char ha_scsi_id: 3, mapping_mode: 2, - bios_drive_number: 1, tfr_port: 2; -#endif - - } config_2; - - char name[16]; - - sprintf(name, "%s%d", driver_name, j); - - if (!request_region(port_base, REGION_SIZE, driver_name)) { -#if defined(DEBUG_DETECT) - printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base); -#endif - goto fail; - } - - spin_lock_irq(&driver_lock); - - if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) goto freelock; - - in_byte = inb(port_base + REG_PRODUCT_ID2); - - if ((in_byte & 0xf0) != PRODUCT_ID2) goto freelock; - - *(char *)&config_1 = inb(port_base + REG_CONFIG1); - *(char *)&config_2 = inb(port_base + REG_CONFIG2); - - irq = interrupt_table[config_1.interrupt]; - dma_channel = dma_channel_table[config_1.dma_channel]; - subversion = (in_byte & 0x0f); - - /* Board detected, allocate its IRQ */ - if (request_irq(irq, do_interrupt_handler, - IRQF_DISABLED | ((subversion == ESA) ? IRQF_SHARED : 0), - driver_name, (void *) &sha[j])) { - printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq); - goto freelock; - } - - if (subversion == ISA && request_dma(dma_channel, driver_name)) { - printk("%s: unable to allocate DMA channel %u, detaching.\n", - name, dma_channel); - goto freeirq; - } - - if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING; - - spin_unlock_irq(&driver_lock); - sh[j] = scsi_register(tpnt, sizeof(struct hostdata)); - spin_lock_irq(&driver_lock); - - if (sh[j] == NULL) { - printk("%s: unable to register host, detaching.\n", name); - goto freedma; - } - - sh[j]->io_port = port_base; - sh[j]->unique_id = port_base; - sh[j]->n_io_port = REGION_SIZE; - sh[j]->base = bios_segment_table[config_1.bios_segment]; - sh[j]->irq = irq; - sh[j]->sg_tablesize = MAX_SGLIST; - sh[j]->this_id = config_2.ha_scsi_id; - sh[j]->can_queue = MAX_MAILBOXES; - sh[j]->cmd_per_lun = MAX_CMD_PER_LUN; - -#if defined(DEBUG_DETECT) - { - unsigned char sys_mask, lcl_mask; - - sys_mask = inb(sh[j]->io_port + REG_SYS_MASK); - lcl_mask = inb(sh[j]->io_port + REG_LCL_MASK); - printk("SYS_MASK 0x%x, LCL_MASK 0x%x.\n", sys_mask, lcl_mask); - } -#endif - - /* Probably a bogus host scsi id, set it to the dummy value */ - if (sh[j]->this_id == 0) sh[j]->this_id = -1; - - /* If BIOS is disabled, force enable interrupts */ - if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK); - - memset(HD(j), 0, sizeof(struct hostdata)); - HD(j)->heads = mapping_table[config_2.mapping_mode].heads; - HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors; - HD(j)->subversion = subversion; - HD(j)->pdev = NULL; - HD(j)->board_number = j; - - if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST; - - if (HD(j)->subversion == ESA) { - sh[j]->unchecked_isa_dma = FALSE; - sh[j]->dma_channel = NO_DMA; - sprintf(BN(j), "U34F%d", j); - bus_type = "VESA"; - } - else { - unsigned long flags; - sh[j]->unchecked_isa_dma = TRUE; - - flags=claim_dma_lock(); - disable_dma(dma_channel); - clear_dma_ff(dma_channel); - set_dma_mode(dma_channel, DMA_MODE_CASCADE); - enable_dma(dma_channel); - release_dma_lock(flags); - - sh[j]->dma_channel = dma_channel; - sprintf(BN(j), "U14F%d", j); - bus_type = "ISA"; - } - - sh[j]->max_channel = MAX_CHANNEL - 1; - sh[j]->max_id = MAX_TARGET; - sh[j]->max_lun = MAX_LUN; - - if (HD(j)->subversion == ISA && !board_inquiry(j)) { - HD(j)->board_id[40] = 0; - - if (strcmp(&HD(j)->board_id[32], "06000600")) { - printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]); - printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n", - BN(j), &HD(j)->board_id[32]); - sh[j]->hostt->use_clustering = DISABLE_CLUSTERING; - sh[j]->sg_tablesize = MAX_SAFE_SGLIST; - } - } - - if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST"); - else sprintf(dma_name, "DMA %u", dma_channel); - - spin_unlock_irq(&driver_lock); - - for (i = 0; i < sh[j]->can_queue; i++) - HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev, - &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); - - for (i = 0; i < sh[j]->can_queue; i++) - if (! ((&HD(j)->cp[i])->sglist = kmalloc( - sh[j]->sg_tablesize * sizeof(struct sg_list), - (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) { - printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i); - goto release; - } - - if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN) - max_queue_depth = MAX_TAGGED_CMD_PER_LUN; - - if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN; - - if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE) - tag_mode = TAG_ORDERED; - - if (j == 0) { - printk("UltraStor 14F/34F: Copyright (C) 1994-2003 Dario Ballabio.\n"); - printk("%s config options -> of:%c, tm:%d, lc:%c, mq:%d, et:%c.\n", - driver_name, YESNO(have_old_firmware), tag_mode, - YESNO(linked_comm), max_queue_depth, YESNO(ext_tran)); - } - - printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n", - BN(j), bus_type, (unsigned long)sh[j]->io_port, (int)sh[j]->base, - sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue); - - if (sh[j]->max_id > 8 || sh[j]->max_lun > 8) - printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n", - BN(j), sh[j]->max_id, sh[j]->max_lun); - - for (i = 0; i <= sh[j]->max_channel; i++) - printk("%s: SCSI channel %u enabled, host target ID %d.\n", - BN(j), i, sh[j]->this_id); - - return TRUE; - -freedma: - if (subversion == ISA) free_dma(dma_channel); -freeirq: - free_irq(irq, &sha[j]); -freelock: - spin_unlock_irq(&driver_lock); - release_region(port_base, REGION_SIZE); -fail: - return FALSE; - -release: - u14_34f_release(sh[j]); - return FALSE; -} - -static void internal_setup(char *str, int *ints) { - int i, argc = ints[0]; - char *cur = str, *pc; - - if (argc > 0) { - - if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM; - - for (i = 0; i < argc; i++) io_port[i] = ints[i + 1]; - - io_port[i] = 0; - setup_done = TRUE; - } - - while (cur && (pc = strchr(cur, ':'))) { - int val = 0, c = *++pc; - - if (c == 'n' || c == 'N') val = FALSE; - else if (c == 'y' || c == 'Y') val = TRUE; - else val = (int) simple_strtoul(pc, NULL, 0); - - if (!strncmp(cur, "lc:", 3)) linked_comm = val; - else if (!strncmp(cur, "of:", 3)) have_old_firmware = val; - else if (!strncmp(cur, "tm:", 3)) tag_mode = val; - else if (!strncmp(cur, "tc:", 3)) tag_mode = val; - else if (!strncmp(cur, "mq:", 3)) max_queue_depth = val; - else if (!strncmp(cur, "ls:", 3)) link_statistics = val; - else if (!strncmp(cur, "et:", 3)) ext_tran = val; - - if ((cur = strchr(cur, ','))) ++cur; - } - - return; -} - -static int option_setup(char *str) { - int ints[MAX_INT_PARAM]; - char *cur = str; - int i = 1; - - while (cur && isdigit(*cur) && i < MAX_INT_PARAM) { - ints[i++] = simple_strtoul(cur, NULL, 0); - - if ((cur = strchr(cur, ',')) != NULL) cur++; - } - - ints[0] = i - 1; - internal_setup(cur, ints); - return 1; -} - -static int u14_34f_detect(struct scsi_host_template *tpnt) { - unsigned int j = 0, k; - - tpnt->proc_name = "u14-34f"; - - if(strlen(boot_options)) option_setup(boot_options); - -#if defined(MODULE) - /* io_port could have been modified when loading as a module */ - if(io_port[0] != SKIP) { - setup_done = TRUE; - io_port[MAX_INT_PARAM] = 0; - } -#endif - - for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL; - - for (k = 0; io_port[k]; k++) { - - if (io_port[k] == SKIP) continue; - - if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++; - } - - num_boards = j; - return j; -} - -static void map_dma(unsigned int i, unsigned int j) { - unsigned int data_len = 0; - unsigned int k, pci_dir; - int count; - struct scatterlist *sg; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (SCpnt->sense_buffer) - cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE)); - - cpp->sense_len = SCSI_SENSE_BUFFERSIZE; - - if (scsi_bufflen(SCpnt)) { - count = scsi_dma_map(SCpnt); - BUG_ON(count < 0); - - scsi_for_each_sg(SCpnt, sg, count, k) { - cpp->sglist[k].address = H2DEV(sg_dma_address(sg)); - cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(sg)); - data_len += sg->length; - } - - cpp->sg = TRUE; - cpp->use_sg = scsi_sg_count(SCpnt); - cpp->data_address = - H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist, - cpp->use_sg * sizeof(struct sg_list), - pci_dir)); - cpp->data_len = H2DEV(data_len); - - } else { - pci_dir = PCI_DMA_BIDIRECTIONAL; - cpp->data_len = H2DEV(scsi_bufflen(SCpnt)); - } -} - -static void unmap_dma(unsigned int i, unsigned int j) { - unsigned int pci_dir; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (DEV2H(cpp->sense_addr)) - pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr), - DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - - scsi_dma_unmap(SCpnt); - - if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (DEV2H(cpp->data_address)) - pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); -} - -static void sync_dma(unsigned int i, unsigned int j) { - unsigned int pci_dir; - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; - pci_dir = SCpnt->sc_data_direction; - - if (DEV2H(cpp->sense_addr)) - pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr), - DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE); - - if (scsi_sg_count(SCpnt)) - pci_dma_sync_sg_for_cpu(HD(j)->pdev, scsi_sglist(SCpnt), - scsi_sg_count(SCpnt), pci_dir); - - if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL; - - if (DEV2H(cpp->data_address)) - pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address), - DEV2H(cpp->data_len), pci_dir); -} - -static void scsi_to_dev_dir(unsigned int i, unsigned int j) { - unsigned int k; - - static const unsigned char data_out_cmds[] = { - 0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e, - 0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40, - 0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d - }; - - static const unsigned char data_none_cmds[] = { - 0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e, - 0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47, - 0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00 - }; - - struct mscp *cpp; - struct scsi_cmnd *SCpnt; - - cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt; - - if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) { - cpp->xdir = DTD_IN; - return; - } - else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) { - cpp->xdir = DTD_OUT; - return; - } - else if (SCpnt->sc_data_direction == DMA_NONE) { - cpp->xdir = DTD_NONE; - return; - } - - if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL) - panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j)); - - cpp->xdir = DTD_IN; - - for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++) - if (SCpnt->cmnd[0] == data_out_cmds[k]) { - cpp->xdir = DTD_OUT; - break; - } - - if (cpp->xdir == DTD_IN) - for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++) - if (SCpnt->cmnd[0] == data_none_cmds[k]) { - cpp->xdir = DTD_NONE; - break; - } - -} - -static int u14_34f_queuecommand_lck(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) { - unsigned int i, j, k; - struct mscp *cpp; - - /* j is the board number */ - j = ((struct hostdata *) SCpnt->device->host->hostdata)->board_number; - - if (SCpnt->host_scribble) - panic("%s: qcomm, SCpnt %p already active.\n", - BN(j), SCpnt); - - /* i is the mailbox number, look for the first free mailbox - starting from last_cp_used */ - i = HD(j)->last_cp_used + 1; - - for (k = 0; k < sh[j]->can_queue; k++, i++) { - - if (i >= sh[j]->can_queue) i = 0; - - if (HD(j)->cp_stat[i] == FREE) { - HD(j)->last_cp_used = i; - break; - } - } - - if (k == sh[j]->can_queue) { - printk("%s: qcomm, no free mailbox.\n", BN(j)); - return 1; - } - - /* Set pointer to control packet structure */ - cpp = &HD(j)->cp[i]; - - memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE); - SCpnt->scsi_done = done; - cpp->cpp_index = i; - SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index; - - if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d.\n", - BN(j), i, SCpnt->device->channel, SCpnt->device->id, - SCpnt->device->lun); - - cpp->opcode = OP_SCSI; - cpp->channel = SCpnt->device->channel; - cpp->target = SCpnt->device->id; - cpp->lun = SCpnt->device->lun; - cpp->SCpnt = SCpnt; - cpp->cdb_len = SCpnt->cmd_len; - memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len); - - /* Use data transfer direction SCpnt->sc_data_direction */ - scsi_to_dev_dir(i, j); - - /* Map DMA buffers and SG list */ - map_dma(i, j); - - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) { - HD(j)->cp_stat[i] = READY; - flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, FALSE); - return 0; - } - - if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { - unmap_dma(i, j); - SCpnt->host_scribble = NULL; - scmd_printk(KERN_INFO, SCpnt, - "qcomm, adapter busy.\n"); - return 1; - } - - /* Store pointer in OGM address bytes */ - outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); - - /* Issue OGM interrupt */ - outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); - - HD(j)->cp_stat[i] = IN_USE; - return 0; -} - -static DEF_SCSI_QCMD(u14_34f_queuecommand) - -static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) { - unsigned int i, j; - - j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; - - if (SCarg->host_scribble == NULL) { - scmd_printk(KERN_INFO, SCarg, "abort, command inactive.\n"); - return SUCCESS; - } - - i = *(unsigned int *)SCarg->host_scribble; - scmd_printk(KERN_INFO, SCarg, "abort, mbox %d.\n", i); - - if (i >= sh[j]->can_queue) - panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j)); - - if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { - printk("%s: abort, timeout error.\n", BN(j)); - return FAILED; - } - - if (HD(j)->cp_stat[i] == FREE) { - printk("%s: abort, mbox %d is free.\n", BN(j), i); - return SUCCESS; - } - - if (HD(j)->cp_stat[i] == IN_USE) { - printk("%s: abort, mbox %d is in use.\n", BN(j), i); - - if (SCarg != HD(j)->cp[i].SCpnt) - panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n", - BN(j), i, SCarg, HD(j)->cp[i].SCpnt); - - if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED) - printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i); - - return FAILED; - } - - if (HD(j)->cp_stat[i] == IN_RESET) { - printk("%s: abort, mbox %d is in reset.\n", BN(j), i); - return FAILED; - } - - if (HD(j)->cp_stat[i] == LOCKED) { - printk("%s: abort, mbox %d is locked.\n", BN(j), i); - return SUCCESS; - } - - if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { - unmap_dma(i, j); - SCarg->result = DID_ABORT << 16; - SCarg->host_scribble = NULL; - HD(j)->cp_stat[i] = FREE; - printk("%s, abort, mbox %d ready, DID_ABORT, done.\n", BN(j), i); - SCarg->scsi_done(SCarg); - return SUCCESS; - } - - panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i); -} - -static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) { - unsigned int i, j, k, c, limit = 0; - unsigned long time; - int arg_done = FALSE; - struct scsi_cmnd *SCpnt; - - j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number; - scmd_printk(KERN_INFO, SCarg, "reset, enter.\n"); - - spin_lock_irq(sh[j]->host_lock); - - if (SCarg->host_scribble == NULL) - printk("%s: reset, inactive.\n", BN(j)); - - if (HD(j)->in_reset) { - printk("%s: reset, exit, already in reset.\n", BN(j)); - spin_unlock_irq(sh[j]->host_lock); - return FAILED; - } - - if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { - printk("%s: reset, exit, timeout error.\n", BN(j)); - spin_unlock_irq(sh[j]->host_lock); - return FAILED; - } - - HD(j)->retries = 0; - - for (c = 0; c <= sh[j]->max_channel; c++) - for (k = 0; k < sh[j]->max_id; k++) { - HD(j)->target_redo[k][c] = TRUE; - HD(j)->target_to[k][c] = 0; - } - - for (i = 0; i < sh[j]->can_queue; i++) { - - if (HD(j)->cp_stat[i] == FREE) continue; - - if (HD(j)->cp_stat[i] == LOCKED) { - HD(j)->cp_stat[i] = FREE; - printk("%s: reset, locked mbox %d forced free.\n", BN(j), i); - continue; - } - - if (!(SCpnt = HD(j)->cp[i].SCpnt)) - panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i); - - if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) { - HD(j)->cp_stat[i] = ABORTING; - printk("%s: reset, mbox %d aborting.\n", BN(j), i); - } - - else { - HD(j)->cp_stat[i] = IN_RESET; - printk("%s: reset, mbox %d in reset.\n", BN(j), i); - } - - if (SCpnt->host_scribble == NULL) - panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i); - - if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i); - - if (SCpnt->scsi_done == NULL) - panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i); - - if (SCpnt == SCarg) arg_done = TRUE; - } - - if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { - printk("%s: reset, cannot reset, timeout error.\n", BN(j)); - spin_unlock_irq(sh[j]->host_lock); - return FAILED; - } - - outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR); - printk("%s: reset, board reset done, enabling interrupts.\n", BN(j)); - -#if defined(DEBUG_RESET) - do_trace = TRUE; -#endif - - HD(j)->in_reset = TRUE; - - spin_unlock_irq(sh[j]->host_lock); - time = jiffies; - while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L); - spin_lock_irq(sh[j]->host_lock); - - printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit); - - for (i = 0; i < sh[j]->can_queue; i++) { - - if (HD(j)->cp_stat[i] == IN_RESET) { - SCpnt = HD(j)->cp[i].SCpnt; - unmap_dma(i, j); - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; - - /* This mailbox is still waiting for its interrupt */ - HD(j)->cp_stat[i] = LOCKED; - - printk("%s, reset, mbox %d locked, DID_RESET, done.\n", BN(j), i); - } - - else if (HD(j)->cp_stat[i] == ABORTING) { - SCpnt = HD(j)->cp[i].SCpnt; - unmap_dma(i, j); - SCpnt->result = DID_RESET << 16; - SCpnt->host_scribble = NULL; - - /* This mailbox was never queued to the adapter */ - HD(j)->cp_stat[i] = FREE; - - printk("%s, reset, mbox %d aborting, DID_RESET, done.\n", BN(j), i); - } - - else - - /* Any other mailbox has already been set free by interrupt */ - continue; - - SCpnt->scsi_done(SCpnt); - } - - HD(j)->in_reset = FALSE; - do_trace = FALSE; - - if (arg_done) printk("%s: reset, exit, done.\n", BN(j)); - else printk("%s: reset, exit.\n", BN(j)); - - spin_unlock_irq(sh[j]->host_lock); - return SUCCESS; -} - -static int u14_34f_bios_param(struct scsi_device *disk, - struct block_device *bdev, sector_t capacity, int *dkinfo) { - unsigned int j = 0; - unsigned int size = capacity; - - dkinfo[0] = HD(j)->heads; - dkinfo[1] = HD(j)->sectors; - dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors); - - if (ext_tran && (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) { - dkinfo[0] = 255; - dkinfo[1] = 63; - dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); - } - -#if defined (DEBUG_GEOMETRY) - printk ("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name, - dkinfo[0], dkinfo[1], dkinfo[2]); -#endif - - return FALSE; -} - -static void sort(unsigned long sk[], unsigned int da[], unsigned int n, - unsigned int rev) { - unsigned int i, j, k, y; - unsigned long x; - - for (i = 0; i < n - 1; i++) { - k = i; - - for (j = k + 1; j < n; j++) - if (rev) { - if (sk[j] > sk[k]) k = j; - } - else { - if (sk[j] < sk[k]) k = j; - } - - if (k != i) { - x = sk[k]; sk[k] = sk[i]; sk[i] = x; - y = da[k]; da[k] = da[i]; da[i] = y; - } - } - - return; - } - -static int reorder(unsigned int j, unsigned long cursec, - unsigned int ihdlr, unsigned int il[], unsigned int n_ready) { - struct scsi_cmnd *SCpnt; - struct mscp *cpp; - unsigned int k, n; - unsigned int rev = FALSE, s = TRUE, r = TRUE; - unsigned int input_only = TRUE, overlap = FALSE; - unsigned long sl[n_ready], pl[n_ready], ll[n_ready]; - unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0; - unsigned long ioseek = 0; - - static unsigned int flushcount = 0, batchcount = 0, sortcount = 0; - static unsigned int readycount = 0, ovlcount = 0, inputcount = 0; - static unsigned int readysorted = 0, revcount = 0; - static unsigned long seeksorted = 0, seeknosort = 0; - - if (link_statistics && !(++flushcount % link_statistics)) - printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\ - " av %ldK as %ldK.\n", flushcount, batchcount, inputcount, - ovlcount, readycount, readysorted, sortcount, revcount, - seeknosort / (readycount + 1), - seeksorted / (readycount + 1)); - - if (n_ready <= 1) return FALSE; - - for (n = 0; n < n_ready; n++) { - k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - - if (!(cpp->xdir == DTD_IN)) input_only = FALSE; - - if (blk_rq_pos(SCpnt->request) < minsec) - minsec = blk_rq_pos(SCpnt->request); - if (blk_rq_pos(SCpnt->request) > maxsec) - maxsec = blk_rq_pos(SCpnt->request); - - sl[n] = blk_rq_pos(SCpnt->request); - ioseek += blk_rq_sectors(SCpnt->request); - - if (!n) continue; - - if (sl[n] < sl[n - 1]) s = FALSE; - if (sl[n] > sl[n - 1]) r = FALSE; - - if (link_statistics) { - if (sl[n] > sl[n - 1]) - seek += sl[n] - sl[n - 1]; - else - seek += sl[n - 1] - sl[n]; - } - - } - - if (link_statistics) { - if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec; - } - - if (cursec > ((maxsec + minsec) / 2)) rev = TRUE; - - if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE; - - if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev); - - if (!input_only) for (n = 0; n < n_ready; n++) { - k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - ll[n] = blk_rq_sectors(SCpnt->request); pl[n] = SCpnt->serial_number; - - if (!n) continue; - - if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n])) - || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE; - } - - if (overlap) sort(pl, il, n_ready, FALSE); - - if (link_statistics) { - if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec; - batchcount++; readycount += n_ready; seeknosort += seek / 1024; - if (input_only) inputcount++; - if (overlap) { ovlcount++; seeksorted += iseek / 1024; } - else seeksorted += (iseek + maxsec - minsec) / 1024; - if (rev && !r) { revcount++; readysorted += n_ready; } - if (!rev && !s) { sortcount++; readysorted += n_ready; } - } - -#if defined(DEBUG_LINKED_COMMANDS) - if (link_statistics && (overlap || !(flushcount % link_statistics))) - for (n = 0; n < n_ready; n++) { - k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - printk("%s %d.%d:%d mb %d fc %d nr %d sec %ld ns %u"\ - " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n", - (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target, - SCpnt->lun, k, flushcount, n_ready, - blk_rq_pos(SCpnt->request), blk_rq_sectors(SCpnt->request), - cursec, YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only), - YESNO(overlap), cpp->xdir); - } -#endif - return overlap; -} - -static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned int j, - unsigned int ihdlr) { - struct scsi_cmnd *SCpnt; - struct mscp *cpp; - unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES]; - - for (k = 0; k < sh[j]->can_queue; k++) { - - if (HD(j)->cp_stat[k] != READY && HD(j)->cp_stat[k] != IN_USE) continue; - - cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - - if (SCpnt->device != dev) continue; - - if (HD(j)->cp_stat[k] == IN_USE) return; - - il[n_ready++] = k; - } - - if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1; - - for (n = 0; n < n_ready; n++) { - k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt; - - if (wait_on_busy(sh[j]->io_port, MAXLOOP)) { - scmd_printk(KERN_INFO, SCpnt, - "%s, mbox %d, adapter" - " busy, will abort.\n", (ihdlr ? "ihdlr" : "qcomm"), - k); - HD(j)->cp_stat[k] = ABORTING; - continue; - } - - outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM); - outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR); - HD(j)->cp_stat[k] = IN_USE; - } - -} - -static irqreturn_t ihdlr(unsigned int j) -{ - struct scsi_cmnd *SCpnt; - unsigned int i, k, c, status, tstatus, reg, ret; - struct mscp *spp, *cpp; - int irq = sh[j]->irq; - - /* Check if this board need to be serviced */ - if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) goto none; - - HD(j)->iocount++; - - if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq, - HD(j)->iocount); - - /* Check if this board is still busy */ - if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP)) { - outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); - printk("%s: ihdlr, busy timeout error, irq %d, reg 0x%x, count %d.\n", - BN(j), irq, reg, HD(j)->iocount); - goto none; - } - - ret = inl(sh[j]->io_port + REG_ICM); - - /* Clear interrupt pending flag */ - outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR); - - /* Find the mailbox to be serviced on this board */ - for (i = 0; i < sh[j]->can_queue; i++) - if (H2DEV(HD(j)->cp[i].cp_dma_addr) == ret) break; - - if (i >= sh[j]->can_queue) - panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j), - (void *)ret, (void *)H2DEV(HD(j)->cp[0].cp_dma_addr)); - - cpp = &(HD(j)->cp[i]); - spp = cpp; - -#if defined(DEBUG_GENERATE_ABORTS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) goto handled; -#endif - - if (HD(j)->cp_stat[i] == IGNORE) { - HD(j)->cp_stat[i] = FREE; - goto handled; - } - else if (HD(j)->cp_stat[i] == LOCKED) { - HD(j)->cp_stat[i] = FREE; - printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i, - HD(j)->iocount); - goto handled; - } - else if (HD(j)->cp_stat[i] == FREE) { - printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i, - HD(j)->iocount); - goto handled; - } - else if (HD(j)->cp_stat[i] == IN_RESET) - printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i); - else if (HD(j)->cp_stat[i] != IN_USE) - panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n", - BN(j), i, HD(j)->cp_stat[i]); - - HD(j)->cp_stat[i] = FREE; - SCpnt = cpp->SCpnt; - - if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i); - - if (SCpnt->host_scribble == NULL) - panic("%s: ihdlr, mbox %d, SCpnt %p garbled.\n", BN(j), i, - SCpnt); - - if (*(unsigned int *)SCpnt->host_scribble != i) - panic("%s: ihdlr, mbox %d, index mismatch %d.\n", - BN(j), i, *(unsigned int *)SCpnt->host_scribble); - - sync_dma(i, j); - - if (linked_comm && SCpnt->device->queue_depth > 2 - && TLDEV(SCpnt->device->type)) - flush_dev(SCpnt->device, blk_rq_pos(SCpnt->request), j, TRUE); - - tstatus = status_byte(spp->target_status); - -#if defined(DEBUG_GENERATE_ERRORS) - if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 200) < 2)) - spp->adapter_status = 0x01; -#endif - - switch (spp->adapter_status) { - case ASOK: /* status OK */ - - /* Forces a reset if a disk drive keeps returning BUSY */ - if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE) - status = DID_ERROR << 16; - - /* If there was a bus reset, redo operation on each target */ - else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK - && HD(j)->target_redo[scmd_id(SCpnt)][scmd_channel(SCpnt)]) - status = DID_BUS_BUSY << 16; - - /* Works around a flaw in scsi.c */ - else if (tstatus == CHECK_CONDITION - && SCpnt->device->type == TYPE_DISK - && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR) - status = DID_BUS_BUSY << 16; - - else - status = DID_OK << 16; - - if (tstatus == GOOD) - HD(j)->target_redo[scmd_id(SCpnt)][scmd_channel(SCpnt)] = FALSE; - - if (spp->target_status && SCpnt->device->type == TYPE_DISK && - (!(tstatus == CHECK_CONDITION && HD(j)->iocount <= 1000 && - (SCpnt->sense_buffer[2] & 0xf) == NOT_READY))) - scmd_printk(KERN_INFO, SCpnt, - "ihdlr, target_status 0x%x, sense key 0x%x.\n", - spp->target_status, - SCpnt->sense_buffer[2]); - - HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] = 0; - - if (HD(j)->last_retried_pid == SCpnt->serial_number) HD(j)->retries = 0; - - break; - case ASST: /* Selection Time Out */ - - if (HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)] > 1) - status = DID_ERROR << 16; - else { - status = DID_TIME_OUT << 16; - HD(j)->target_to[scmd_id(SCpnt)][scmd_channel(SCpnt)]++; - } - - break; - - /* Perform a limited number of internal retries */ - case 0x93: /* Unexpected bus free */ - case 0x94: /* Target bus phase sequence failure */ - case 0x96: /* Illegal SCSI command */ - case 0xa3: /* SCSI bus reset error */ - - for (c = 0; c <= sh[j]->max_channel; c++) - for (k = 0; k < sh[j]->max_id; k++) - HD(j)->target_redo[k][c] = TRUE; - - - case 0x92: /* Data over/under-run */ - - if (SCpnt->device->type != TYPE_TAPE - && HD(j)->retries < MAX_INTERNAL_RETRIES) { - -#if defined(DID_SOFT_ERROR) - status = DID_SOFT_ERROR << 16; -#else - status = DID_BUS_BUSY << 16; -#endif - - HD(j)->retries++; - HD(j)->last_retried_pid = SCpnt->serial_number; - } - else - status = DID_ERROR << 16; - - break; - case 0x01: /* Invalid command */ - case 0x02: /* Invalid parameters */ - case 0x03: /* Invalid data list */ - case 0x84: /* SCSI bus abort error */ - case 0x9b: /* Auto request sense error */ - case 0x9f: /* Unexpected command complete message error */ - case 0xff: /* Invalid parameter in the S/G list */ - default: - status = DID_ERROR << 16; - break; - } - - SCpnt->result = status | spp->target_status; - -#if defined(DEBUG_INTERRUPT) - if (SCpnt->result || do_trace) -#else - if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) || - (spp->adapter_status != ASOK && - spp->adapter_status != ASST && HD(j)->iocount <= 1000) || - do_trace || msg_byte(spp->target_status)) -#endif - scmd_printk(KERN_INFO, SCpnt, "ihdlr, mbox %2d, err 0x%x:%x,"\ - " reg 0x%x, count %d.\n", - i, spp->adapter_status, spp->target_status, - reg, HD(j)->iocount); - - unmap_dma(i, j); - - /* Set the command state to inactive */ - SCpnt->host_scribble = NULL; - - SCpnt->scsi_done(SCpnt); - - if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq, - HD(j)->iocount); - -handled: - return IRQ_HANDLED; -none: - return IRQ_NONE; -} - -static irqreturn_t do_interrupt_handler(int irq, void *shap) { - unsigned int j; - unsigned long spin_flags; - irqreturn_t ret; - - /* Check if the interrupt must be processed by this handler */ - if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE; - - spin_lock_irqsave(sh[j]->host_lock, spin_flags); - ret = ihdlr(j); - spin_unlock_irqrestore(sh[j]->host_lock, spin_flags); - return ret; -} - -static int u14_34f_release(struct Scsi_Host *shpnt) { - unsigned int i, j; - - for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++); - - if (sh[j] == NULL) - panic("%s: release, invalid Scsi_Host pointer.\n", driver_name); - - for (i = 0; i < sh[j]->can_queue; i++) - kfree((&HD(j)->cp[i])->sglist); - - for (i = 0; i < sh[j]->can_queue; i++) - pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr, - sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL); - - free_irq(sh[j]->irq, &sha[j]); - - if (sh[j]->dma_channel != NO_DMA) - free_dma(sh[j]->dma_channel); - - release_region(sh[j]->io_port, sh[j]->n_io_port); - scsi_unregister(sh[j]); - return FALSE; -} - -#include "scsi_module.c" - -#ifndef MODULE -__setup("u14-34f=", option_setup); -#endif /* end MODULE */ diff --git a/ANDROID_3.4.5/drivers/scsi/ufs/Kconfig b/ANDROID_3.4.5/drivers/scsi/ufs/Kconfig deleted file mode 100644 index 8f27f9d6..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ufs/Kconfig +++ /dev/null @@ -1,49 +0,0 @@ -# -# Kernel configuration file for the UFS Host Controller -# -# This code is based on drivers/scsi/ufs/Kconfig -# Copyright (C) 2011 Samsung Samsung India Software Operations -# -# Santosh Yaraganavi -# Vinayak Holikatti - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# NO WARRANTY -# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -# solely responsible for determining the appropriateness of using and -# distributing the Program and assumes all risks associated with its -# exercise of rights under this Agreement, including but not limited to -# the risks and costs of program errors, damage to or loss of data, -# programs or equipment, and unavailability or interruption of operations. - -# DISCLAIMER OF LIABILITY -# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -config SCSI_UFSHCD - tristate "Universal Flash Storage host controller driver" - depends on PCI && SCSI - ---help--- - This is a generic driver which supports PCIe UFS Host controllers. diff --git a/ANDROID_3.4.5/drivers/scsi/ufs/Makefile b/ANDROID_3.4.5/drivers/scsi/ufs/Makefile deleted file mode 100644 index adf7895a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ufs/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# UFSHCD makefile -obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o diff --git a/ANDROID_3.4.5/drivers/scsi/ufs/ufs.h b/ANDROID_3.4.5/drivers/scsi/ufs/ufs.h deleted file mode 100644 index b207529f..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ufs/ufs.h +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Universal Flash Storage Host controller driver - * - * This code is based on drivers/scsi/ufs/ufs.h - * Copyright (C) 2011-2012 Samsung India Software Operations - * - * Santosh Yaraganavi - * Vinayak Holikatti - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef _UFS_H -#define _UFS_H - -#define MAX_CDB_SIZE 16 - -#define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ - ((byte3 << 24) | (byte2 << 16) |\ - (byte1 << 8) | (byte0)) - -/* - * UFS Protocol Information Unit related definitions - */ - -/* Task management functions */ -enum { - UFS_ABORT_TASK = 0x01, - UFS_ABORT_TASK_SET = 0x02, - UFS_CLEAR_TASK_SET = 0x04, - UFS_LOGICAL_RESET = 0x08, - UFS_QUERY_TASK = 0x80, - UFS_QUERY_TASK_SET = 0x81, -}; - -/* UTP UPIU Transaction Codes Initiator to Target */ -enum { - UPIU_TRANSACTION_NOP_OUT = 0x00, - UPIU_TRANSACTION_COMMAND = 0x01, - UPIU_TRANSACTION_DATA_OUT = 0x02, - UPIU_TRANSACTION_TASK_REQ = 0x04, - UPIU_TRANSACTION_QUERY_REQ = 0x26, -}; - -/* UTP UPIU Transaction Codes Target to Initiator */ -enum { - UPIU_TRANSACTION_NOP_IN = 0x20, - UPIU_TRANSACTION_RESPONSE = 0x21, - UPIU_TRANSACTION_DATA_IN = 0x22, - UPIU_TRANSACTION_TASK_RSP = 0x24, - UPIU_TRANSACTION_READY_XFER = 0x31, - UPIU_TRANSACTION_QUERY_RSP = 0x36, -}; - -/* UPIU Read/Write flags */ -enum { - UPIU_CMD_FLAGS_NONE = 0x00, - UPIU_CMD_FLAGS_WRITE = 0x20, - UPIU_CMD_FLAGS_READ = 0x40, -}; - -/* UPIU Task Attributes */ -enum { - UPIU_TASK_ATTR_SIMPLE = 0x00, - UPIU_TASK_ATTR_ORDERED = 0x01, - UPIU_TASK_ATTR_HEADQ = 0x02, - UPIU_TASK_ATTR_ACA = 0x03, -}; - -/* UTP QUERY Transaction Specific Fields OpCode */ -enum { - UPIU_QUERY_OPCODE_NOP = 0x0, - UPIU_QUERY_OPCODE_READ_DESC = 0x1, - UPIU_QUERY_OPCODE_WRITE_DESC = 0x2, - UPIU_QUERY_OPCODE_READ_ATTR = 0x3, - UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4, - UPIU_QUERY_OPCODE_READ_FLAG = 0x5, - UPIU_QUERY_OPCODE_SET_FLAG = 0x6, - UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7, - UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, -}; - -/* UTP Transfer Request Command Type (CT) */ -enum { - UPIU_COMMAND_SET_TYPE_SCSI = 0x0, - UPIU_COMMAND_SET_TYPE_UFS = 0x1, - UPIU_COMMAND_SET_TYPE_QUERY = 0x2, -}; - -enum { - MASK_SCSI_STATUS = 0xFF, - MASK_TASK_RESPONSE = 0xFF00, - MASK_RSP_UPIU_RESULT = 0xFFFF, -}; - -/* Task management service response */ -enum { - UPIU_TASK_MANAGEMENT_FUNC_COMPL = 0x00, - UPIU_TASK_MANAGEMENT_FUNC_NOT_SUPPORTED = 0x04, - UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED = 0x08, - UPIU_TASK_MANAGEMENT_FUNC_FAILED = 0x05, - UPIU_INCORRECT_LOGICAL_UNIT_NO = 0x09, -}; -/** - * struct utp_upiu_header - UPIU header structure - * @dword_0: UPIU header DW-0 - * @dword_1: UPIU header DW-1 - * @dword_2: UPIU header DW-2 - */ -struct utp_upiu_header { - u32 dword_0; - u32 dword_1; - u32 dword_2; -}; - -/** - * struct utp_upiu_cmd - Command UPIU structure - * @header: UPIU header structure DW-0 to DW-2 - * @data_transfer_len: Data Transfer Length DW-3 - * @cdb: Command Descriptor Block CDB DW-4 to DW-7 - */ -struct utp_upiu_cmd { - struct utp_upiu_header header; - u32 exp_data_transfer_len; - u8 cdb[MAX_CDB_SIZE]; -}; - -/** - * struct utp_upiu_rsp - Response UPIU structure - * @header: UPIU header DW-0 to DW-2 - * @residual_transfer_count: Residual transfer count DW-3 - * @reserved: Reserved double words DW-4 to DW-7 - * @sense_data_len: Sense data length DW-8 U16 - * @sense_data: Sense data field DW-8 to DW-12 - */ -struct utp_upiu_rsp { - struct utp_upiu_header header; - u32 residual_transfer_count; - u32 reserved[4]; - u16 sense_data_len; - u8 sense_data[18]; -}; - -/** - * struct utp_upiu_task_req - Task request UPIU structure - * @header - UPIU header structure DW0 to DW-2 - * @input_param1: Input parameter 1 DW-3 - * @input_param2: Input parameter 2 DW-4 - * @input_param3: Input parameter 3 DW-5 - * @reserved: Reserved double words DW-6 to DW-7 - */ -struct utp_upiu_task_req { - struct utp_upiu_header header; - u32 input_param1; - u32 input_param2; - u32 input_param3; - u32 reserved[2]; -}; - -/** - * struct utp_upiu_task_rsp - Task Management Response UPIU structure - * @header: UPIU header structure DW0-DW-2 - * @output_param1: Ouput parameter 1 DW3 - * @output_param2: Output parameter 2 DW4 - * @reserved: Reserved double words DW-5 to DW-7 - */ -struct utp_upiu_task_rsp { - struct utp_upiu_header header; - u32 output_param1; - u32 output_param2; - u32 reserved[3]; -}; - -#endif /* End of Header */ diff --git a/ANDROID_3.4.5/drivers/scsi/ufs/ufshcd.c b/ANDROID_3.4.5/drivers/scsi/ufs/ufshcd.c deleted file mode 100644 index 52b96e8b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ufs/ufshcd.c +++ /dev/null @@ -1,1978 +0,0 @@ -/* - * Universal Flash Storage Host controller driver - * - * This code is based on drivers/scsi/ufs/ufshcd.c - * Copyright (C) 2011-2012 Samsung India Software Operations - * - * Santosh Yaraganavi - * Vinayak Holikatti - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ufs.h" -#include "ufshci.h" - -#define UFSHCD "ufshcd" -#define UFSHCD_DRIVER_VERSION "0.1" - -enum { - UFSHCD_MAX_CHANNEL = 0, - UFSHCD_MAX_ID = 1, - UFSHCD_MAX_LUNS = 8, - UFSHCD_CMD_PER_LUN = 32, - UFSHCD_CAN_QUEUE = 32, -}; - -/* UFSHCD states */ -enum { - UFSHCD_STATE_OPERATIONAL, - UFSHCD_STATE_RESET, - UFSHCD_STATE_ERROR, -}; - -/* Interrupt configuration options */ -enum { - UFSHCD_INT_DISABLE, - UFSHCD_INT_ENABLE, - UFSHCD_INT_CLEAR, -}; - -/* Interrupt aggregation options */ -enum { - INT_AGGR_RESET, - INT_AGGR_CONFIG, -}; - -/** - * struct uic_command - UIC command structure - * @command: UIC command - * @argument1: UIC command argument 1 - * @argument2: UIC command argument 2 - * @argument3: UIC command argument 3 - * @cmd_active: Indicate if UIC command is outstanding - * @result: UIC command result - */ -struct uic_command { - u32 command; - u32 argument1; - u32 argument2; - u32 argument3; - int cmd_active; - int result; -}; - -/** - * struct ufs_hba - per adapter private structure - * @mmio_base: UFSHCI base register address - * @ucdl_base_addr: UFS Command Descriptor base address - * @utrdl_base_addr: UTP Transfer Request Descriptor base address - * @utmrdl_base_addr: UTP Task Management Descriptor base address - * @ucdl_dma_addr: UFS Command Descriptor DMA address - * @utrdl_dma_addr: UTRDL DMA address - * @utmrdl_dma_addr: UTMRDL DMA address - * @host: Scsi_Host instance of the driver - * @pdev: PCI device handle - * @lrb: local reference block - * @outstanding_tasks: Bits representing outstanding task requests - * @outstanding_reqs: Bits representing outstanding transfer requests - * @capabilities: UFS Controller Capabilities - * @nutrs: Transfer Request Queue depth supported by controller - * @nutmrs: Task Management Queue depth supported by controller - * @active_uic_cmd: handle of active UIC command - * @ufshcd_tm_wait_queue: wait queue for task management - * @tm_condition: condition variable for task management - * @ufshcd_state: UFSHCD states - * @int_enable_mask: Interrupt Mask Bits - * @uic_workq: Work queue for UIC completion handling - * @feh_workq: Work queue for fatal controller error handling - * @errors: HBA errors - */ -struct ufs_hba { - void __iomem *mmio_base; - - /* Virtual memory reference */ - struct utp_transfer_cmd_desc *ucdl_base_addr; - struct utp_transfer_req_desc *utrdl_base_addr; - struct utp_task_req_desc *utmrdl_base_addr; - - /* DMA memory reference */ - dma_addr_t ucdl_dma_addr; - dma_addr_t utrdl_dma_addr; - dma_addr_t utmrdl_dma_addr; - - struct Scsi_Host *host; - struct pci_dev *pdev; - - struct ufshcd_lrb *lrb; - - unsigned long outstanding_tasks; - unsigned long outstanding_reqs; - - u32 capabilities; - int nutrs; - int nutmrs; - u32 ufs_version; - - struct uic_command active_uic_cmd; - wait_queue_head_t ufshcd_tm_wait_queue; - unsigned long tm_condition; - - u32 ufshcd_state; - u32 int_enable_mask; - - /* Work Queues */ - struct work_struct uic_workq; - struct work_struct feh_workq; - - /* HBA Errors */ - u32 errors; -}; - -/** - * struct ufshcd_lrb - local reference block - * @utr_descriptor_ptr: UTRD address of the command - * @ucd_cmd_ptr: UCD address of the command - * @ucd_rsp_ptr: Response UPIU address for this command - * @ucd_prdt_ptr: PRDT address of the command - * @cmd: pointer to SCSI command - * @sense_buffer: pointer to sense buffer address of the SCSI command - * @sense_bufflen: Length of the sense buffer - * @scsi_status: SCSI status of the command - * @command_type: SCSI, UFS, Query. - * @task_tag: Task tag of the command - * @lun: LUN of the command - */ -struct ufshcd_lrb { - struct utp_transfer_req_desc *utr_descriptor_ptr; - struct utp_upiu_cmd *ucd_cmd_ptr; - struct utp_upiu_rsp *ucd_rsp_ptr; - struct ufshcd_sg_entry *ucd_prdt_ptr; - - struct scsi_cmnd *cmd; - u8 *sense_buffer; - unsigned int sense_bufflen; - int scsi_status; - - int command_type; - int task_tag; - unsigned int lun; -}; - -/** - * ufshcd_get_ufs_version - Get the UFS version supported by the HBA - * @hba - Pointer to adapter instance - * - * Returns UFSHCI version supported by the controller - */ -static inline u32 ufshcd_get_ufs_version(struct ufs_hba *hba) -{ - return readl(hba->mmio_base + REG_UFS_VERSION); -} - -/** - * ufshcd_is_device_present - Check if any device connected to - * the host controller - * @reg_hcs - host controller status register value - * - * Returns 0 if device present, non-zero if no device detected - */ -static inline int ufshcd_is_device_present(u32 reg_hcs) -{ - return (DEVICE_PRESENT & reg_hcs) ? 0 : -1; -} - -/** - * ufshcd_get_tr_ocs - Get the UTRD Overall Command Status - * @lrb: pointer to local command reference block - * - * This function is used to get the OCS field from UTRD - * Returns the OCS field in the UTRD - */ -static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp) -{ - return lrbp->utr_descriptor_ptr->header.dword_2 & MASK_OCS; -} - -/** - * ufshcd_get_tmr_ocs - Get the UTMRD Overall Command Status - * @task_req_descp: pointer to utp_task_req_desc structure - * - * This function is used to get the OCS field from UTMRD - * Returns the OCS field in the UTMRD - */ -static inline int -ufshcd_get_tmr_ocs(struct utp_task_req_desc *task_req_descp) -{ - return task_req_descp->header.dword_2 & MASK_OCS; -} - -/** - * ufshcd_get_tm_free_slot - get a free slot for task management request - * @hba: per adapter instance - * - * Returns maximum number of task management request slots in case of - * task management queue full or returns the free slot number - */ -static inline int ufshcd_get_tm_free_slot(struct ufs_hba *hba) -{ - return find_first_zero_bit(&hba->outstanding_tasks, hba->nutmrs); -} - -/** - * ufshcd_utrl_clear - Clear a bit in UTRLCLR register - * @hba: per adapter instance - * @pos: position of the bit to be cleared - */ -static inline void ufshcd_utrl_clear(struct ufs_hba *hba, u32 pos) -{ - writel(~(1 << pos), - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_CLEAR)); -} - -/** - * ufshcd_get_lists_status - Check UCRDY, UTRLRDY and UTMRLRDY - * @reg: Register value of host controller status - * - * Returns integer, 0 on Success and positive value if failed - */ -static inline int ufshcd_get_lists_status(u32 reg) -{ - /* - * The mask 0xFF is for the following HCS register bits - * Bit Description - * 0 Device Present - * 1 UTRLRDY - * 2 UTMRLRDY - * 3 UCRDY - * 4 HEI - * 5 DEI - * 6-7 reserved - */ - return (((reg) & (0xFF)) >> 1) ^ (0x07); -} - -/** - * ufshcd_get_uic_cmd_result - Get the UIC command result - * @hba: Pointer to adapter instance - * - * This function gets the result of UIC command completion - * Returns 0 on success, non zero value on error - */ -static inline int ufshcd_get_uic_cmd_result(struct ufs_hba *hba) -{ - return readl(hba->mmio_base + REG_UIC_COMMAND_ARG_2) & - MASK_UIC_COMMAND_RESULT; -} - -/** - * ufshcd_free_hba_memory - Free allocated memory for LRB, request - * and task lists - * @hba: Pointer to adapter instance - */ -static inline void ufshcd_free_hba_memory(struct ufs_hba *hba) -{ - size_t utmrdl_size, utrdl_size, ucdl_size; - - kfree(hba->lrb); - - if (hba->utmrdl_base_addr) { - utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs; - dma_free_coherent(&hba->pdev->dev, utmrdl_size, - hba->utmrdl_base_addr, hba->utmrdl_dma_addr); - } - - if (hba->utrdl_base_addr) { - utrdl_size = - (sizeof(struct utp_transfer_req_desc) * hba->nutrs); - dma_free_coherent(&hba->pdev->dev, utrdl_size, - hba->utrdl_base_addr, hba->utrdl_dma_addr); - } - - if (hba->ucdl_base_addr) { - ucdl_size = - (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs); - dma_free_coherent(&hba->pdev->dev, ucdl_size, - hba->ucdl_base_addr, hba->ucdl_dma_addr); - } -} - -/** - * ufshcd_is_valid_req_rsp - checks if controller TR response is valid - * @ucd_rsp_ptr: pointer to response UPIU - * - * This function checks the response UPIU for valid transaction type in - * response field - * Returns 0 on success, non-zero on failure - */ -static inline int -ufshcd_is_valid_req_rsp(struct utp_upiu_rsp *ucd_rsp_ptr) -{ - return ((be32_to_cpu(ucd_rsp_ptr->header.dword_0) >> 24) == - UPIU_TRANSACTION_RESPONSE) ? 0 : DID_ERROR << 16; -} - -/** - * ufshcd_get_rsp_upiu_result - Get the result from response UPIU - * @ucd_rsp_ptr: pointer to response UPIU - * - * This function gets the response status and scsi_status from response UPIU - * Returns the response result code. - */ -static inline int -ufshcd_get_rsp_upiu_result(struct utp_upiu_rsp *ucd_rsp_ptr) -{ - return be32_to_cpu(ucd_rsp_ptr->header.dword_1) & MASK_RSP_UPIU_RESULT; -} - -/** - * ufshcd_config_int_aggr - Configure interrupt aggregation values. - * Currently there is no use case where we want to configure - * interrupt aggregation dynamically. So to configure interrupt - * aggregation, #define INT_AGGR_COUNTER_THRESHOLD_VALUE and - * INT_AGGR_TIMEOUT_VALUE are used. - * @hba: per adapter instance - * @option: Interrupt aggregation option - */ -static inline void -ufshcd_config_int_aggr(struct ufs_hba *hba, int option) -{ - switch (option) { - case INT_AGGR_RESET: - writel((INT_AGGR_ENABLE | - INT_AGGR_COUNTER_AND_TIMER_RESET), - (hba->mmio_base + - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL)); - break; - case INT_AGGR_CONFIG: - writel((INT_AGGR_ENABLE | - INT_AGGR_PARAM_WRITE | - INT_AGGR_COUNTER_THRESHOLD_VALUE | - INT_AGGR_TIMEOUT_VALUE), - (hba->mmio_base + - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL)); - break; - } -} - -/** - * ufshcd_enable_run_stop_reg - Enable run-stop registers, - * When run-stop registers are set to 1, it indicates the - * host controller that it can process the requests - * @hba: per adapter instance - */ -static void ufshcd_enable_run_stop_reg(struct ufs_hba *hba) -{ - writel(UTP_TASK_REQ_LIST_RUN_STOP_BIT, - (hba->mmio_base + - REG_UTP_TASK_REQ_LIST_RUN_STOP)); - writel(UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT, - (hba->mmio_base + - REG_UTP_TRANSFER_REQ_LIST_RUN_STOP)); -} - -/** - * ufshcd_hba_stop - Send controller to reset state - * @hba: per adapter instance - */ -static inline void ufshcd_hba_stop(struct ufs_hba *hba) -{ - writel(CONTROLLER_DISABLE, (hba->mmio_base + REG_CONTROLLER_ENABLE)); -} - -/** - * ufshcd_hba_start - Start controller initialization sequence - * @hba: per adapter instance - */ -static inline void ufshcd_hba_start(struct ufs_hba *hba) -{ - writel(CONTROLLER_ENABLE , (hba->mmio_base + REG_CONTROLLER_ENABLE)); -} - -/** - * ufshcd_is_hba_active - Get controller state - * @hba: per adapter instance - * - * Returns zero if controller is active, 1 otherwise - */ -static inline int ufshcd_is_hba_active(struct ufs_hba *hba) -{ - return (readl(hba->mmio_base + REG_CONTROLLER_ENABLE) & 0x1) ? 0 : 1; -} - -/** - * ufshcd_send_command - Send SCSI or device management commands - * @hba: per adapter instance - * @task_tag: Task tag of the command - */ -static inline -void ufshcd_send_command(struct ufs_hba *hba, unsigned int task_tag) -{ - __set_bit(task_tag, &hba->outstanding_reqs); - writel((1 << task_tag), - (hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL)); -} - -/** - * ufshcd_copy_sense_data - Copy sense data in case of check condition - * @lrb - pointer to local reference block - */ -static inline void ufshcd_copy_sense_data(struct ufshcd_lrb *lrbp) -{ - int len; - if (lrbp->sense_buffer) { - len = be16_to_cpu(lrbp->ucd_rsp_ptr->sense_data_len); - memcpy(lrbp->sense_buffer, - lrbp->ucd_rsp_ptr->sense_data, - min_t(int, len, SCSI_SENSE_BUFFERSIZE)); - } -} - -/** - * ufshcd_hba_capabilities - Read controller capabilities - * @hba: per adapter instance - */ -static inline void ufshcd_hba_capabilities(struct ufs_hba *hba) -{ - hba->capabilities = - readl(hba->mmio_base + REG_CONTROLLER_CAPABILITIES); - - /* nutrs and nutmrs are 0 based values */ - hba->nutrs = (hba->capabilities & MASK_TRANSFER_REQUESTS_SLOTS) + 1; - hba->nutmrs = - ((hba->capabilities & MASK_TASK_MANAGEMENT_REQUEST_SLOTS) >> 16) + 1; -} - -/** - * ufshcd_send_uic_command - Send UIC commands to unipro layers - * @hba: per adapter instance - * @uic_command: UIC command - */ -static inline void -ufshcd_send_uic_command(struct ufs_hba *hba, struct uic_command *uic_cmnd) -{ - /* Write Args */ - writel(uic_cmnd->argument1, - (hba->mmio_base + REG_UIC_COMMAND_ARG_1)); - writel(uic_cmnd->argument2, - (hba->mmio_base + REG_UIC_COMMAND_ARG_2)); - writel(uic_cmnd->argument3, - (hba->mmio_base + REG_UIC_COMMAND_ARG_3)); - - /* Write UIC Cmd */ - writel((uic_cmnd->command & COMMAND_OPCODE_MASK), - (hba->mmio_base + REG_UIC_COMMAND)); -} - -/** - * ufshcd_map_sg - Map scatter-gather list to prdt - * @lrbp - pointer to local reference block - * - * Returns 0 in case of success, non-zero value in case of failure - */ -static int ufshcd_map_sg(struct ufshcd_lrb *lrbp) -{ - struct ufshcd_sg_entry *prd_table; - struct scatterlist *sg; - struct scsi_cmnd *cmd; - int sg_segments; - int i; - - cmd = lrbp->cmd; - sg_segments = scsi_dma_map(cmd); - if (sg_segments < 0) - return sg_segments; - - if (sg_segments) { - lrbp->utr_descriptor_ptr->prd_table_length = - cpu_to_le16((u16) (sg_segments)); - - prd_table = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr; - - scsi_for_each_sg(cmd, sg, sg_segments, i) { - prd_table[i].size = - cpu_to_le32(((u32) sg_dma_len(sg))-1); - prd_table[i].base_addr = - cpu_to_le32(lower_32_bits(sg->dma_address)); - prd_table[i].upper_addr = - cpu_to_le32(upper_32_bits(sg->dma_address)); - } - } else { - lrbp->utr_descriptor_ptr->prd_table_length = 0; - } - - return 0; -} - -/** - * ufshcd_int_config - enable/disable interrupts - * @hba: per adapter instance - * @option: interrupt option - */ -static void ufshcd_int_config(struct ufs_hba *hba, u32 option) -{ - switch (option) { - case UFSHCD_INT_ENABLE: - writel(hba->int_enable_mask, - (hba->mmio_base + REG_INTERRUPT_ENABLE)); - break; - case UFSHCD_INT_DISABLE: - if (hba->ufs_version == UFSHCI_VERSION_10) - writel(INTERRUPT_DISABLE_MASK_10, - (hba->mmio_base + REG_INTERRUPT_ENABLE)); - else - writel(INTERRUPT_DISABLE_MASK_11, - (hba->mmio_base + REG_INTERRUPT_ENABLE)); - break; - } -} - -/** - * ufshcd_compose_upiu - form UFS Protocol Information Unit(UPIU) - * @lrb - pointer to local reference block - */ -static void ufshcd_compose_upiu(struct ufshcd_lrb *lrbp) -{ - struct utp_transfer_req_desc *req_desc; - struct utp_upiu_cmd *ucd_cmd_ptr; - u32 data_direction; - u32 upiu_flags; - - ucd_cmd_ptr = lrbp->ucd_cmd_ptr; - req_desc = lrbp->utr_descriptor_ptr; - - switch (lrbp->command_type) { - case UTP_CMD_TYPE_SCSI: - if (lrbp->cmd->sc_data_direction == DMA_FROM_DEVICE) { - data_direction = UTP_DEVICE_TO_HOST; - upiu_flags = UPIU_CMD_FLAGS_READ; - } else if (lrbp->cmd->sc_data_direction == DMA_TO_DEVICE) { - data_direction = UTP_HOST_TO_DEVICE; - upiu_flags = UPIU_CMD_FLAGS_WRITE; - } else { - data_direction = UTP_NO_DATA_TRANSFER; - upiu_flags = UPIU_CMD_FLAGS_NONE; - } - - /* Transfer request descriptor header fields */ - req_desc->header.dword_0 = - cpu_to_le32(data_direction | UTP_SCSI_COMMAND); - - /* - * assigning invalid value for command status. Controller - * updates OCS on command completion, with the command - * status - */ - req_desc->header.dword_2 = - cpu_to_le32(OCS_INVALID_COMMAND_STATUS); - - /* command descriptor fields */ - ucd_cmd_ptr->header.dword_0 = - cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_COMMAND, - upiu_flags, - lrbp->lun, - lrbp->task_tag)); - ucd_cmd_ptr->header.dword_1 = - cpu_to_be32( - UPIU_HEADER_DWORD(UPIU_COMMAND_SET_TYPE_SCSI, - 0, - 0, - 0)); - - /* Total EHS length and Data segment length will be zero */ - ucd_cmd_ptr->header.dword_2 = 0; - - ucd_cmd_ptr->exp_data_transfer_len = - cpu_to_be32(lrbp->cmd->transfersize); - - memcpy(ucd_cmd_ptr->cdb, - lrbp->cmd->cmnd, - (min_t(unsigned short, - lrbp->cmd->cmd_len, - MAX_CDB_SIZE))); - break; - case UTP_CMD_TYPE_DEV_MANAGE: - /* For query function implementation */ - break; - case UTP_CMD_TYPE_UFS: - /* For UFS native command implementation */ - break; - } /* end of switch */ -} - -/** - * ufshcd_queuecommand - main entry point for SCSI requests - * @cmd: command from SCSI Midlayer - * @done: call back function - * - * Returns 0 for success, non-zero in case of failure - */ -static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) -{ - struct ufshcd_lrb *lrbp; - struct ufs_hba *hba; - unsigned long flags; - int tag; - int err = 0; - - hba = shost_priv(host); - - tag = cmd->request->tag; - - if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) { - err = SCSI_MLQUEUE_HOST_BUSY; - goto out; - } - - lrbp = &hba->lrb[tag]; - - lrbp->cmd = cmd; - lrbp->sense_bufflen = SCSI_SENSE_BUFFERSIZE; - lrbp->sense_buffer = cmd->sense_buffer; - lrbp->task_tag = tag; - lrbp->lun = cmd->device->lun; - - lrbp->command_type = UTP_CMD_TYPE_SCSI; - - /* form UPIU before issuing the command */ - ufshcd_compose_upiu(lrbp); - err = ufshcd_map_sg(lrbp); - if (err) - goto out; - - /* issue command to the controller */ - spin_lock_irqsave(hba->host->host_lock, flags); - ufshcd_send_command(hba, tag); - spin_unlock_irqrestore(hba->host->host_lock, flags); -out: - return err; -} - -/** - * ufshcd_memory_alloc - allocate memory for host memory space data structures - * @hba: per adapter instance - * - * 1. Allocate DMA memory for Command Descriptor array - * Each command descriptor consist of Command UPIU, Response UPIU and PRDT - * 2. Allocate DMA memory for UTP Transfer Request Descriptor List (UTRDL). - * 3. Allocate DMA memory for UTP Task Management Request Descriptor List - * (UTMRDL) - * 4. Allocate memory for local reference block(lrb). - * - * Returns 0 for success, non-zero in case of failure - */ -static int ufshcd_memory_alloc(struct ufs_hba *hba) -{ - size_t utmrdl_size, utrdl_size, ucdl_size; - - /* Allocate memory for UTP command descriptors */ - ucdl_size = (sizeof(struct utp_transfer_cmd_desc) * hba->nutrs); - hba->ucdl_base_addr = dma_alloc_coherent(&hba->pdev->dev, - ucdl_size, - &hba->ucdl_dma_addr, - GFP_KERNEL); - - /* - * UFSHCI requires UTP command descriptor to be 128 byte aligned. - * make sure hba->ucdl_dma_addr is aligned to PAGE_SIZE - * if hba->ucdl_dma_addr is aligned to PAGE_SIZE, then it will - * be aligned to 128 bytes as well - */ - if (!hba->ucdl_base_addr || - WARN_ON(hba->ucdl_dma_addr & (PAGE_SIZE - 1))) { - dev_err(&hba->pdev->dev, - "Command Descriptor Memory allocation failed\n"); - goto out; - } - - /* - * Allocate memory for UTP Transfer descriptors - * UFSHCI requires 1024 byte alignment of UTRD - */ - utrdl_size = (sizeof(struct utp_transfer_req_desc) * hba->nutrs); - hba->utrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev, - utrdl_size, - &hba->utrdl_dma_addr, - GFP_KERNEL); - if (!hba->utrdl_base_addr || - WARN_ON(hba->utrdl_dma_addr & (PAGE_SIZE - 1))) { - dev_err(&hba->pdev->dev, - "Transfer Descriptor Memory allocation failed\n"); - goto out; - } - - /* - * Allocate memory for UTP Task Management descriptors - * UFSHCI requires 1024 byte alignment of UTMRD - */ - utmrdl_size = sizeof(struct utp_task_req_desc) * hba->nutmrs; - hba->utmrdl_base_addr = dma_alloc_coherent(&hba->pdev->dev, - utmrdl_size, - &hba->utmrdl_dma_addr, - GFP_KERNEL); - if (!hba->utmrdl_base_addr || - WARN_ON(hba->utmrdl_dma_addr & (PAGE_SIZE - 1))) { - dev_err(&hba->pdev->dev, - "Task Management Descriptor Memory allocation failed\n"); - goto out; - } - - /* Allocate memory for local reference block */ - hba->lrb = kcalloc(hba->nutrs, sizeof(struct ufshcd_lrb), GFP_KERNEL); - if (!hba->lrb) { - dev_err(&hba->pdev->dev, "LRB Memory allocation failed\n"); - goto out; - } - return 0; -out: - ufshcd_free_hba_memory(hba); - return -ENOMEM; -} - -/** - * ufshcd_host_memory_configure - configure local reference block with - * memory offsets - * @hba: per adapter instance - * - * Configure Host memory space - * 1. Update Corresponding UTRD.UCDBA and UTRD.UCDBAU with UCD DMA - * address. - * 2. Update each UTRD with Response UPIU offset, Response UPIU length - * and PRDT offset. - * 3. Save the corresponding addresses of UTRD, UCD.CMD, UCD.RSP and UCD.PRDT - * into local reference block. - */ -static void ufshcd_host_memory_configure(struct ufs_hba *hba) -{ - struct utp_transfer_cmd_desc *cmd_descp; - struct utp_transfer_req_desc *utrdlp; - dma_addr_t cmd_desc_dma_addr; - dma_addr_t cmd_desc_element_addr; - u16 response_offset; - u16 prdt_offset; - int cmd_desc_size; - int i; - - utrdlp = hba->utrdl_base_addr; - cmd_descp = hba->ucdl_base_addr; - - response_offset = - offsetof(struct utp_transfer_cmd_desc, response_upiu); - prdt_offset = - offsetof(struct utp_transfer_cmd_desc, prd_table); - - cmd_desc_size = sizeof(struct utp_transfer_cmd_desc); - cmd_desc_dma_addr = hba->ucdl_dma_addr; - - for (i = 0; i < hba->nutrs; i++) { - /* Configure UTRD with command descriptor base address */ - cmd_desc_element_addr = - (cmd_desc_dma_addr + (cmd_desc_size * i)); - utrdlp[i].command_desc_base_addr_lo = - cpu_to_le32(lower_32_bits(cmd_desc_element_addr)); - utrdlp[i].command_desc_base_addr_hi = - cpu_to_le32(upper_32_bits(cmd_desc_element_addr)); - - /* Response upiu and prdt offset should be in double words */ - utrdlp[i].response_upiu_offset = - cpu_to_le16((response_offset >> 2)); - utrdlp[i].prd_table_offset = - cpu_to_le16((prdt_offset >> 2)); - utrdlp[i].response_upiu_length = - cpu_to_le16(ALIGNED_UPIU_SIZE); - - hba->lrb[i].utr_descriptor_ptr = (utrdlp + i); - hba->lrb[i].ucd_cmd_ptr = - (struct utp_upiu_cmd *)(cmd_descp + i); - hba->lrb[i].ucd_rsp_ptr = - (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; - hba->lrb[i].ucd_prdt_ptr = - (struct ufshcd_sg_entry *)cmd_descp[i].prd_table; - } -} - -/** - * ufshcd_dme_link_startup - Notify Unipro to perform link startup - * @hba: per adapter instance - * - * UIC_CMD_DME_LINK_STARTUP command must be issued to Unipro layer, - * in order to initialize the Unipro link startup procedure. - * Once the Unipro links are up, the device connected to the controller - * is detected. - * - * Returns 0 on success, non-zero value on failure - */ -static int ufshcd_dme_link_startup(struct ufs_hba *hba) -{ - struct uic_command *uic_cmd; - unsigned long flags; - - /* check if controller is ready to accept UIC commands */ - if (((readl(hba->mmio_base + REG_CONTROLLER_STATUS)) & - UIC_COMMAND_READY) == 0x0) { - dev_err(&hba->pdev->dev, - "Controller not ready" - " to accept UIC commands\n"); - return -EIO; - } - - spin_lock_irqsave(hba->host->host_lock, flags); - - /* form UIC command */ - uic_cmd = &hba->active_uic_cmd; - uic_cmd->command = UIC_CMD_DME_LINK_STARTUP; - uic_cmd->argument1 = 0; - uic_cmd->argument2 = 0; - uic_cmd->argument3 = 0; - - /* enable UIC related interrupts */ - hba->int_enable_mask |= UIC_COMMAND_COMPL; - ufshcd_int_config(hba, UFSHCD_INT_ENABLE); - - /* sending UIC commands to controller */ - ufshcd_send_uic_command(hba, uic_cmd); - spin_unlock_irqrestore(hba->host->host_lock, flags); - return 0; -} - -/** - * ufshcd_make_hba_operational - Make UFS controller operational - * @hba: per adapter instance - * - * To bring UFS host controller to operational state, - * 1. Check if device is present - * 2. Configure run-stop-registers - * 3. Enable required interrupts - * 4. Configure interrupt aggregation - * - * Returns 0 on success, non-zero value on failure - */ -static int ufshcd_make_hba_operational(struct ufs_hba *hba) -{ - int err = 0; - u32 reg; - - /* check if device present */ - reg = readl((hba->mmio_base + REG_CONTROLLER_STATUS)); - if (ufshcd_is_device_present(reg)) { - dev_err(&hba->pdev->dev, "cc: Device not present\n"); - err = -ENXIO; - goto out; - } - - /* - * UCRDY, UTMRLDY and UTRLRDY bits must be 1 - * DEI, HEI bits must be 0 - */ - if (!(ufshcd_get_lists_status(reg))) { - ufshcd_enable_run_stop_reg(hba); - } else { - dev_err(&hba->pdev->dev, - "Host controller not ready to process requests"); - err = -EIO; - goto out; - } - - /* Enable required interrupts */ - hba->int_enable_mask |= (UTP_TRANSFER_REQ_COMPL | - UIC_ERROR | - UTP_TASK_REQ_COMPL | - DEVICE_FATAL_ERROR | - CONTROLLER_FATAL_ERROR | - SYSTEM_BUS_FATAL_ERROR); - ufshcd_int_config(hba, UFSHCD_INT_ENABLE); - - /* Configure interrupt aggregation */ - ufshcd_config_int_aggr(hba, INT_AGGR_CONFIG); - - if (hba->ufshcd_state == UFSHCD_STATE_RESET) - scsi_unblock_requests(hba->host); - - hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; - scsi_scan_host(hba->host); -out: - return err; -} - -/** - * ufshcd_hba_enable - initialize the controller - * @hba: per adapter instance - * - * The controller resets itself and controller firmware initialization - * sequence kicks off. When controller is ready it will set - * the Host Controller Enable bit to 1. - * - * Returns 0 on success, non-zero value on failure - */ -static int ufshcd_hba_enable(struct ufs_hba *hba) -{ - int retry; - - /* - * msleep of 1 and 5 used in this function might result in msleep(20), - * but it was necessary to send the UFS FPGA to reset mode during - * development and testing of this driver. msleep can be changed to - * mdelay and retry count can be reduced based on the controller. - */ - if (!ufshcd_is_hba_active(hba)) { - - /* change controller state to "reset state" */ - ufshcd_hba_stop(hba); - - /* - * This delay is based on the testing done with UFS host - * controller FPGA. The delay can be changed based on the - * host controller used. - */ - msleep(5); - } - - /* start controller initialization sequence */ - ufshcd_hba_start(hba); - - /* - * To initialize a UFS host controller HCE bit must be set to 1. - * During initialization the HCE bit value changes from 1->0->1. - * When the host controller completes initialization sequence - * it sets the value of HCE bit to 1. The same HCE bit is read back - * to check if the controller has completed initialization sequence. - * So without this delay the value HCE = 1, set in the previous - * instruction might be read back. - * This delay can be changed based on the controller. - */ - msleep(1); - - /* wait for the host controller to complete initialization */ - retry = 10; - while (ufshcd_is_hba_active(hba)) { - if (retry) { - retry--; - } else { - dev_err(&hba->pdev->dev, - "Controller enable failed\n"); - return -EIO; - } - msleep(5); - } - return 0; -} - -/** - * ufshcd_initialize_hba - start the initialization process - * @hba: per adapter instance - * - * 1. Enable the controller via ufshcd_hba_enable. - * 2. Program the Transfer Request List Address with the starting address of - * UTRDL. - * 3. Program the Task Management Request List Address with starting address - * of UTMRDL. - * - * Returns 0 on success, non-zero value on failure. - */ -static int ufshcd_initialize_hba(struct ufs_hba *hba) -{ - if (ufshcd_hba_enable(hba)) - return -EIO; - - /* Configure UTRL and UTMRL base address registers */ - writel(hba->utrdl_dma_addr, - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_L)); - writel(lower_32_bits(hba->utrdl_dma_addr), - (hba->mmio_base + REG_UTP_TRANSFER_REQ_LIST_BASE_H)); - writel(hba->utmrdl_dma_addr, - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_L)); - writel(upper_32_bits(hba->utmrdl_dma_addr), - (hba->mmio_base + REG_UTP_TASK_REQ_LIST_BASE_H)); - - /* Initialize unipro link startup procedure */ - return ufshcd_dme_link_startup(hba); -} - -/** - * ufshcd_do_reset - reset the host controller - * @hba: per adapter instance - * - * Returns SUCCESS/FAILED - */ -static int ufshcd_do_reset(struct ufs_hba *hba) -{ - struct ufshcd_lrb *lrbp; - unsigned long flags; - int tag; - - /* block commands from midlayer */ - scsi_block_requests(hba->host); - - spin_lock_irqsave(hba->host->host_lock, flags); - hba->ufshcd_state = UFSHCD_STATE_RESET; - - /* send controller to reset state */ - ufshcd_hba_stop(hba); - spin_unlock_irqrestore(hba->host->host_lock, flags); - - /* abort outstanding commands */ - for (tag = 0; tag < hba->nutrs; tag++) { - if (test_bit(tag, &hba->outstanding_reqs)) { - lrbp = &hba->lrb[tag]; - scsi_dma_unmap(lrbp->cmd); - lrbp->cmd->result = DID_RESET << 16; - lrbp->cmd->scsi_done(lrbp->cmd); - lrbp->cmd = NULL; - } - } - - /* clear outstanding request/task bit maps */ - hba->outstanding_reqs = 0; - hba->outstanding_tasks = 0; - - /* start the initialization process */ - if (ufshcd_initialize_hba(hba)) { - dev_err(&hba->pdev->dev, - "Reset: Controller initialization failed\n"); - return FAILED; - } - return SUCCESS; -} - -/** - * ufshcd_slave_alloc - handle initial SCSI device configurations - * @sdev: pointer to SCSI device - * - * Returns success - */ -static int ufshcd_slave_alloc(struct scsi_device *sdev) -{ - struct ufs_hba *hba; - - hba = shost_priv(sdev->host); - sdev->tagged_supported = 1; - - /* Mode sense(6) is not supported by UFS, so use Mode sense(10) */ - sdev->use_10_for_ms = 1; - scsi_set_tag_type(sdev, MSG_SIMPLE_TAG); - - /* - * Inform SCSI Midlayer that the LUN queue depth is same as the - * controller queue depth. If a LUN queue depth is less than the - * controller queue depth and if the LUN reports - * SAM_STAT_TASK_SET_FULL, the LUN queue depth will be adjusted - * with scsi_adjust_queue_depth. - */ - scsi_activate_tcq(sdev, hba->nutrs); - return 0; -} - -/** - * ufshcd_slave_destroy - remove SCSI device configurations - * @sdev: pointer to SCSI device - */ -static void ufshcd_slave_destroy(struct scsi_device *sdev) -{ - struct ufs_hba *hba; - - hba = shost_priv(sdev->host); - scsi_deactivate_tcq(sdev, hba->nutrs); -} - -/** - * ufshcd_task_req_compl - handle task management request completion - * @hba: per adapter instance - * @index: index of the completed request - * - * Returns SUCCESS/FAILED - */ -static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index) -{ - struct utp_task_req_desc *task_req_descp; - struct utp_upiu_task_rsp *task_rsp_upiup; - unsigned long flags; - int ocs_value; - int task_result; - - spin_lock_irqsave(hba->host->host_lock, flags); - - /* Clear completed tasks from outstanding_tasks */ - __clear_bit(index, &hba->outstanding_tasks); - - task_req_descp = hba->utmrdl_base_addr; - ocs_value = ufshcd_get_tmr_ocs(&task_req_descp[index]); - - if (ocs_value == OCS_SUCCESS) { - task_rsp_upiup = (struct utp_upiu_task_rsp *) - task_req_descp[index].task_rsp_upiu; - task_result = be32_to_cpu(task_rsp_upiup->header.dword_1); - task_result = ((task_result & MASK_TASK_RESPONSE) >> 8); - - if (task_result != UPIU_TASK_MANAGEMENT_FUNC_COMPL || - task_result != UPIU_TASK_MANAGEMENT_FUNC_SUCCEEDED) - task_result = FAILED; - } else { - task_result = FAILED; - dev_err(&hba->pdev->dev, - "trc: Invalid ocs = %x\n", ocs_value); - } - spin_unlock_irqrestore(hba->host->host_lock, flags); - return task_result; -} - -/** - * ufshcd_adjust_lun_qdepth - Update LUN queue depth if device responds with - * SAM_STAT_TASK_SET_FULL SCSI command status. - * @cmd: pointer to SCSI command - */ -static void ufshcd_adjust_lun_qdepth(struct scsi_cmnd *cmd) -{ - struct ufs_hba *hba; - int i; - int lun_qdepth = 0; - - hba = shost_priv(cmd->device->host); - - /* - * LUN queue depth can be obtained by counting outstanding commands - * on the LUN. - */ - for (i = 0; i < hba->nutrs; i++) { - if (test_bit(i, &hba->outstanding_reqs)) { - - /* - * Check if the outstanding command belongs - * to the LUN which reported SAM_STAT_TASK_SET_FULL. - */ - if (cmd->device->lun == hba->lrb[i].lun) - lun_qdepth++; - } - } - - /* - * LUN queue depth will be total outstanding commands, except the - * command for which the LUN reported SAM_STAT_TASK_SET_FULL. - */ - scsi_adjust_queue_depth(cmd->device, MSG_SIMPLE_TAG, lun_qdepth - 1); -} - -/** - * ufshcd_scsi_cmd_status - Update SCSI command result based on SCSI status - * @lrb: pointer to local reference block of completed command - * @scsi_status: SCSI command status - * - * Returns value base on SCSI command status - */ -static inline int -ufshcd_scsi_cmd_status(struct ufshcd_lrb *lrbp, int scsi_status) -{ - int result = 0; - - switch (scsi_status) { - case SAM_STAT_GOOD: - result |= DID_OK << 16 | - COMMAND_COMPLETE << 8 | - SAM_STAT_GOOD; - break; - case SAM_STAT_CHECK_CONDITION: - result |= DID_OK << 16 | - COMMAND_COMPLETE << 8 | - SAM_STAT_CHECK_CONDITION; - ufshcd_copy_sense_data(lrbp); - break; - case SAM_STAT_BUSY: - result |= SAM_STAT_BUSY; - break; - case SAM_STAT_TASK_SET_FULL: - - /* - * If a LUN reports SAM_STAT_TASK_SET_FULL, then the LUN queue - * depth needs to be adjusted to the exact number of - * outstanding commands the LUN can handle at any given time. - */ - ufshcd_adjust_lun_qdepth(lrbp->cmd); - result |= SAM_STAT_TASK_SET_FULL; - break; - case SAM_STAT_TASK_ABORTED: - result |= SAM_STAT_TASK_ABORTED; - break; - default: - result |= DID_ERROR << 16; - break; - } /* end of switch */ - - return result; -} - -/** - * ufshcd_transfer_rsp_status - Get overall status of the response - * @hba: per adapter instance - * @lrb: pointer to local reference block of completed command - * - * Returns result of the command to notify SCSI midlayer - */ -static inline int -ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) -{ - int result = 0; - int scsi_status; - int ocs; - - /* overall command status of utrd */ - ocs = ufshcd_get_tr_ocs(lrbp); - - switch (ocs) { - case OCS_SUCCESS: - - /* check if the returned transfer response is valid */ - result = ufshcd_is_valid_req_rsp(lrbp->ucd_rsp_ptr); - if (result) { - dev_err(&hba->pdev->dev, - "Invalid response = %x\n", result); - break; - } - - /* - * get the response UPIU result to extract - * the SCSI command status - */ - result = ufshcd_get_rsp_upiu_result(lrbp->ucd_rsp_ptr); - - /* - * get the result based on SCSI status response - * to notify the SCSI midlayer of the command status - */ - scsi_status = result & MASK_SCSI_STATUS; - result = ufshcd_scsi_cmd_status(lrbp, scsi_status); - break; - case OCS_ABORTED: - result |= DID_ABORT << 16; - break; - case OCS_INVALID_CMD_TABLE_ATTR: - case OCS_INVALID_PRDT_ATTR: - case OCS_MISMATCH_DATA_BUF_SIZE: - case OCS_MISMATCH_RESP_UPIU_SIZE: - case OCS_PEER_COMM_FAILURE: - case OCS_FATAL_ERROR: - default: - result |= DID_ERROR << 16; - dev_err(&hba->pdev->dev, - "OCS error from controller = %x\n", ocs); - break; - } /* end of switch */ - - return result; -} - -/** - * ufshcd_transfer_req_compl - handle SCSI and query command completion - * @hba: per adapter instance - */ -static void ufshcd_transfer_req_compl(struct ufs_hba *hba) -{ - struct ufshcd_lrb *lrb; - unsigned long completed_reqs; - u32 tr_doorbell; - int result; - int index; - - lrb = hba->lrb; - tr_doorbell = - readl(hba->mmio_base + REG_UTP_TRANSFER_REQ_DOOR_BELL); - completed_reqs = tr_doorbell ^ hba->outstanding_reqs; - - for (index = 0; index < hba->nutrs; index++) { - if (test_bit(index, &completed_reqs)) { - - result = ufshcd_transfer_rsp_status(hba, &lrb[index]); - - if (lrb[index].cmd) { - scsi_dma_unmap(lrb[index].cmd); - lrb[index].cmd->result = result; - lrb[index].cmd->scsi_done(lrb[index].cmd); - - /* Mark completed command as NULL in LRB */ - lrb[index].cmd = NULL; - } - } /* end of if */ - } /* end of for */ - - /* clear corresponding bits of completed commands */ - hba->outstanding_reqs ^= completed_reqs; - - /* Reset interrupt aggregation counters */ - ufshcd_config_int_aggr(hba, INT_AGGR_RESET); -} - -/** - * ufshcd_uic_cc_handler - handle UIC command completion - * @work: pointer to a work queue structure - * - * Returns 0 on success, non-zero value on failure - */ -static void ufshcd_uic_cc_handler (struct work_struct *work) -{ - struct ufs_hba *hba; - - hba = container_of(work, struct ufs_hba, uic_workq); - - if ((hba->active_uic_cmd.command == UIC_CMD_DME_LINK_STARTUP) && - !(ufshcd_get_uic_cmd_result(hba))) { - - if (ufshcd_make_hba_operational(hba)) - dev_err(&hba->pdev->dev, - "cc: hba not operational state\n"); - return; - } -} - -/** - * ufshcd_fatal_err_handler - handle fatal errors - * @hba: per adapter instance - */ -static void ufshcd_fatal_err_handler(struct work_struct *work) -{ - struct ufs_hba *hba; - hba = container_of(work, struct ufs_hba, feh_workq); - - /* check if reset is already in progress */ - if (hba->ufshcd_state != UFSHCD_STATE_RESET) - ufshcd_do_reset(hba); -} - -/** - * ufshcd_err_handler - Check for fatal errors - * @work: pointer to a work queue structure - */ -static void ufshcd_err_handler(struct ufs_hba *hba) -{ - u32 reg; - - if (hba->errors & INT_FATAL_ERRORS) - goto fatal_eh; - - if (hba->errors & UIC_ERROR) { - - reg = readl(hba->mmio_base + - REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); - if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) - goto fatal_eh; - } - return; -fatal_eh: - hba->ufshcd_state = UFSHCD_STATE_ERROR; - schedule_work(&hba->feh_workq); -} - -/** - * ufshcd_tmc_handler - handle task management function completion - * @hba: per adapter instance - */ -static void ufshcd_tmc_handler(struct ufs_hba *hba) -{ - u32 tm_doorbell; - - tm_doorbell = readl(hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL); - hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks; - wake_up_interruptible(&hba->ufshcd_tm_wait_queue); -} - -/** - * ufshcd_sl_intr - Interrupt service routine - * @hba: per adapter instance - * @intr_status: contains interrupts generated by the controller - */ -static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) -{ - hba->errors = UFSHCD_ERROR_MASK & intr_status; - if (hba->errors) - ufshcd_err_handler(hba); - - if (intr_status & UIC_COMMAND_COMPL) - schedule_work(&hba->uic_workq); - - if (intr_status & UTP_TASK_REQ_COMPL) - ufshcd_tmc_handler(hba); - - if (intr_status & UTP_TRANSFER_REQ_COMPL) - ufshcd_transfer_req_compl(hba); -} - -/** - * ufshcd_intr - Main interrupt service routine - * @irq: irq number - * @__hba: pointer to adapter instance - * - * Returns IRQ_HANDLED - If interrupt is valid - * IRQ_NONE - If invalid interrupt - */ -static irqreturn_t ufshcd_intr(int irq, void *__hba) -{ - u32 intr_status; - irqreturn_t retval = IRQ_NONE; - struct ufs_hba *hba = __hba; - - spin_lock(hba->host->host_lock); - intr_status = readl(hba->mmio_base + REG_INTERRUPT_STATUS); - - if (intr_status) { - ufshcd_sl_intr(hba, intr_status); - - /* If UFSHCI 1.0 then clear interrupt status register */ - if (hba->ufs_version == UFSHCI_VERSION_10) - writel(intr_status, - (hba->mmio_base + REG_INTERRUPT_STATUS)); - retval = IRQ_HANDLED; - } - spin_unlock(hba->host->host_lock); - return retval; -} - -/** - * ufshcd_issue_tm_cmd - issues task management commands to controller - * @hba: per adapter instance - * @lrbp: pointer to local reference block - * - * Returns SUCCESS/FAILED - */ -static int -ufshcd_issue_tm_cmd(struct ufs_hba *hba, - struct ufshcd_lrb *lrbp, - u8 tm_function) -{ - struct utp_task_req_desc *task_req_descp; - struct utp_upiu_task_req *task_req_upiup; - struct Scsi_Host *host; - unsigned long flags; - int free_slot = 0; - int err; - - host = hba->host; - - spin_lock_irqsave(host->host_lock, flags); - - /* If task management queue is full */ - free_slot = ufshcd_get_tm_free_slot(hba); - if (free_slot >= hba->nutmrs) { - spin_unlock_irqrestore(host->host_lock, flags); - dev_err(&hba->pdev->dev, "Task management queue full\n"); - err = FAILED; - goto out; - } - - task_req_descp = hba->utmrdl_base_addr; - task_req_descp += free_slot; - - /* Configure task request descriptor */ - task_req_descp->header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD); - task_req_descp->header.dword_2 = - cpu_to_le32(OCS_INVALID_COMMAND_STATUS); - - /* Configure task request UPIU */ - task_req_upiup = - (struct utp_upiu_task_req *) task_req_descp->task_req_upiu; - task_req_upiup->header.dword_0 = - cpu_to_be32(UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ, 0, - lrbp->lun, lrbp->task_tag)); - task_req_upiup->header.dword_1 = - cpu_to_be32(UPIU_HEADER_DWORD(0, tm_function, 0, 0)); - - task_req_upiup->input_param1 = lrbp->lun; - task_req_upiup->input_param1 = - cpu_to_be32(task_req_upiup->input_param1); - task_req_upiup->input_param2 = lrbp->task_tag; - task_req_upiup->input_param2 = - cpu_to_be32(task_req_upiup->input_param2); - - /* send command to the controller */ - __set_bit(free_slot, &hba->outstanding_tasks); - writel((1 << free_slot), - (hba->mmio_base + REG_UTP_TASK_REQ_DOOR_BELL)); - - spin_unlock_irqrestore(host->host_lock, flags); - - /* wait until the task management command is completed */ - err = - wait_event_interruptible_timeout(hba->ufshcd_tm_wait_queue, - (test_bit(free_slot, - &hba->tm_condition) != 0), - 60 * HZ); - if (!err) { - dev_err(&hba->pdev->dev, - "Task management command timed-out\n"); - err = FAILED; - goto out; - } - clear_bit(free_slot, &hba->tm_condition); - return ufshcd_task_req_compl(hba, free_slot); -out: - return err; -} - -/** - * ufshcd_device_reset - reset device and abort all the pending commands - * @cmd: SCSI command pointer - * - * Returns SUCCESS/FAILED - */ -static int ufshcd_device_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host; - struct ufs_hba *hba; - unsigned int tag; - u32 pos; - int err; - - host = cmd->device->host; - hba = shost_priv(host); - tag = cmd->request->tag; - - err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_LOGICAL_RESET); - if (err) - goto out; - - for (pos = 0; pos < hba->nutrs; pos++) { - if (test_bit(pos, &hba->outstanding_reqs) && - (hba->lrb[tag].lun == hba->lrb[pos].lun)) { - - /* clear the respective UTRLCLR register bit */ - ufshcd_utrl_clear(hba, pos); - - clear_bit(pos, &hba->outstanding_reqs); - - if (hba->lrb[pos].cmd) { - scsi_dma_unmap(hba->lrb[pos].cmd); - hba->lrb[pos].cmd->result = - DID_ABORT << 16; - hba->lrb[pos].cmd->scsi_done(cmd); - hba->lrb[pos].cmd = NULL; - } - } - } /* end of for */ -out: - return err; -} - -/** - * ufshcd_host_reset - Main reset function registered with scsi layer - * @cmd: SCSI command pointer - * - * Returns SUCCESS/FAILED - */ -static int ufshcd_host_reset(struct scsi_cmnd *cmd) -{ - struct ufs_hba *hba; - - hba = shost_priv(cmd->device->host); - - if (hba->ufshcd_state == UFSHCD_STATE_RESET) - return SUCCESS; - - return (ufshcd_do_reset(hba) == SUCCESS) ? SUCCESS : FAILED; -} - -/** - * ufshcd_abort - abort a specific command - * @cmd: SCSI command pointer - * - * Returns SUCCESS/FAILED - */ -static int ufshcd_abort(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host; - struct ufs_hba *hba; - unsigned long flags; - unsigned int tag; - int err; - - host = cmd->device->host; - hba = shost_priv(host); - tag = cmd->request->tag; - - spin_lock_irqsave(host->host_lock, flags); - - /* check if command is still pending */ - if (!(test_bit(tag, &hba->outstanding_reqs))) { - err = FAILED; - spin_unlock_irqrestore(host->host_lock, flags); - goto out; - } - spin_unlock_irqrestore(host->host_lock, flags); - - err = ufshcd_issue_tm_cmd(hba, &hba->lrb[tag], UFS_ABORT_TASK); - if (err) - goto out; - - scsi_dma_unmap(cmd); - - spin_lock_irqsave(host->host_lock, flags); - - /* clear the respective UTRLCLR register bit */ - ufshcd_utrl_clear(hba, tag); - - __clear_bit(tag, &hba->outstanding_reqs); - hba->lrb[tag].cmd = NULL; - spin_unlock_irqrestore(host->host_lock, flags); -out: - return err; -} - -static struct scsi_host_template ufshcd_driver_template = { - .module = THIS_MODULE, - .name = UFSHCD, - .proc_name = UFSHCD, - .queuecommand = ufshcd_queuecommand, - .slave_alloc = ufshcd_slave_alloc, - .slave_destroy = ufshcd_slave_destroy, - .eh_abort_handler = ufshcd_abort, - .eh_device_reset_handler = ufshcd_device_reset, - .eh_host_reset_handler = ufshcd_host_reset, - .this_id = -1, - .sg_tablesize = SG_ALL, - .cmd_per_lun = UFSHCD_CMD_PER_LUN, - .can_queue = UFSHCD_CAN_QUEUE, -}; - -/** - * ufshcd_shutdown - main function to put the controller in reset state - * @pdev: pointer to PCI device handle - */ -static void ufshcd_shutdown(struct pci_dev *pdev) -{ - ufshcd_hba_stop((struct ufs_hba *)pci_get_drvdata(pdev)); -} - -#ifdef CONFIG_PM -/** - * ufshcd_suspend - suspend power management function - * @pdev: pointer to PCI device handle - * @state: power state - * - * Returns -ENOSYS - */ -static int ufshcd_suspend(struct pci_dev *pdev, pm_message_t state) -{ - /* - * TODO: - * 1. Block SCSI requests from SCSI midlayer - * 2. Change the internal driver state to non operational - * 3. Set UTRLRSR and UTMRLRSR bits to zero - * 4. Wait until outstanding commands are completed - * 5. Set HCE to zero to send the UFS host controller to reset state - */ - - return -ENOSYS; -} - -/** - * ufshcd_resume - resume power management function - * @pdev: pointer to PCI device handle - * - * Returns -ENOSYS - */ -static int ufshcd_resume(struct pci_dev *pdev) -{ - /* - * TODO: - * 1. Set HCE to 1, to start the UFS host controller - * initialization process - * 2. Set UTRLRSR and UTMRLRSR bits to 1 - * 3. Change the internal driver state to operational - * 4. Unblock SCSI requests from SCSI midlayer - */ - - return -ENOSYS; -} -#endif /* CONFIG_PM */ - -/** - * ufshcd_hba_free - free allocated memory for - * host memory space data structures - * @hba: per adapter instance - */ -static void ufshcd_hba_free(struct ufs_hba *hba) -{ - iounmap(hba->mmio_base); - ufshcd_free_hba_memory(hba); - pci_release_regions(hba->pdev); -} - -/** - * ufshcd_remove - de-allocate PCI/SCSI host and host memory space - * data structure memory - * @pdev - pointer to PCI handle - */ -static void ufshcd_remove(struct pci_dev *pdev) -{ - struct ufs_hba *hba = pci_get_drvdata(pdev); - - /* disable interrupts */ - ufshcd_int_config(hba, UFSHCD_INT_DISABLE); - free_irq(pdev->irq, hba); - - ufshcd_hba_stop(hba); - ufshcd_hba_free(hba); - - scsi_remove_host(hba->host); - scsi_host_put(hba->host); - pci_set_drvdata(pdev, NULL); - pci_clear_master(pdev); - pci_disable_device(pdev); -} - -/** - * ufshcd_set_dma_mask - Set dma mask based on the controller - * addressing capability - * @pdev: PCI device structure - * - * Returns 0 for success, non-zero for failure - */ -static int ufshcd_set_dma_mask(struct ufs_hba *hba) -{ - int err; - u64 dma_mask; - - /* - * If controller supports 64 bit addressing mode, then set the DMA - * mask to 64-bit, else set the DMA mask to 32-bit - */ - if (hba->capabilities & MASK_64_ADDRESSING_SUPPORT) - dma_mask = DMA_BIT_MASK(64); - else - dma_mask = DMA_BIT_MASK(32); - - err = pci_set_dma_mask(hba->pdev, dma_mask); - if (err) - return err; - - err = pci_set_consistent_dma_mask(hba->pdev, dma_mask); - - return err; -} - -/** - * ufshcd_probe - probe routine of the driver - * @pdev: pointer to PCI device handle - * @id: PCI device id - * - * Returns 0 on success, non-zero value on failure - */ -static int __devinit -ufshcd_probe(struct pci_dev *pdev, const struct pci_device_id *id) -{ - struct Scsi_Host *host; - struct ufs_hba *hba; - int err; - - err = pci_enable_device(pdev); - if (err) { - dev_err(&pdev->dev, "pci_enable_device failed\n"); - goto out_error; - } - - pci_set_master(pdev); - - host = scsi_host_alloc(&ufshcd_driver_template, - sizeof(struct ufs_hba)); - if (!host) { - dev_err(&pdev->dev, "scsi_host_alloc failed\n"); - err = -ENOMEM; - goto out_disable; - } - hba = shost_priv(host); - - err = pci_request_regions(pdev, UFSHCD); - if (err < 0) { - dev_err(&pdev->dev, "request regions failed\n"); - goto out_disable; - } - - hba->mmio_base = pci_ioremap_bar(pdev, 0); - if (!hba->mmio_base) { - dev_err(&pdev->dev, "memory map failed\n"); - err = -ENOMEM; - goto out_release_regions; - } - - hba->host = host; - hba->pdev = pdev; - - /* Read capabilities registers */ - ufshcd_hba_capabilities(hba); - - /* Get UFS version supported by the controller */ - hba->ufs_version = ufshcd_get_ufs_version(hba); - - err = ufshcd_set_dma_mask(hba); - if (err) { - dev_err(&pdev->dev, "set dma mask failed\n"); - goto out_iounmap; - } - - /* Allocate memory for host memory space */ - err = ufshcd_memory_alloc(hba); - if (err) { - dev_err(&pdev->dev, "Memory allocation failed\n"); - goto out_iounmap; - } - - /* Configure LRB */ - ufshcd_host_memory_configure(hba); - - host->can_queue = hba->nutrs; - host->cmd_per_lun = hba->nutrs; - host->max_id = UFSHCD_MAX_ID; - host->max_lun = UFSHCD_MAX_LUNS; - host->max_channel = UFSHCD_MAX_CHANNEL; - host->unique_id = host->host_no; - host->max_cmd_len = MAX_CDB_SIZE; - - /* Initailize wait queue for task management */ - init_waitqueue_head(&hba->ufshcd_tm_wait_queue); - - /* Initialize work queues */ - INIT_WORK(&hba->uic_workq, ufshcd_uic_cc_handler); - INIT_WORK(&hba->feh_workq, ufshcd_fatal_err_handler); - - /* IRQ registration */ - err = request_irq(pdev->irq, ufshcd_intr, IRQF_SHARED, UFSHCD, hba); - if (err) { - dev_err(&pdev->dev, "request irq failed\n"); - goto out_lrb_free; - } - - /* Enable SCSI tag mapping */ - err = scsi_init_shared_tag_map(host, host->can_queue); - if (err) { - dev_err(&pdev->dev, "init shared queue failed\n"); - goto out_free_irq; - } - - pci_set_drvdata(pdev, hba); - - err = scsi_add_host(host, &pdev->dev); - if (err) { - dev_err(&pdev->dev, "scsi_add_host failed\n"); - goto out_free_irq; - } - - /* Initialization routine */ - err = ufshcd_initialize_hba(hba); - if (err) { - dev_err(&pdev->dev, "Initialization failed\n"); - goto out_free_irq; - } - - return 0; - -out_free_irq: - free_irq(pdev->irq, hba); -out_lrb_free: - ufshcd_free_hba_memory(hba); -out_iounmap: - iounmap(hba->mmio_base); -out_release_regions: - pci_release_regions(pdev); -out_disable: - scsi_host_put(host); - pci_clear_master(pdev); - pci_disable_device(pdev); -out_error: - return err; -} - -static DEFINE_PCI_DEVICE_TABLE(ufshcd_pci_tbl) = { - { PCI_VENDOR_ID_SAMSUNG, 0xC00C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { } /* terminate list */ -}; - -MODULE_DEVICE_TABLE(pci, ufshcd_pci_tbl); - -static struct pci_driver ufshcd_pci_driver = { - .name = UFSHCD, - .id_table = ufshcd_pci_tbl, - .probe = ufshcd_probe, - .remove = __devexit_p(ufshcd_remove), - .shutdown = ufshcd_shutdown, -#ifdef CONFIG_PM - .suspend = ufshcd_suspend, - .resume = ufshcd_resume, -#endif -}; - -/** - * ufshcd_init - Driver registration routine - */ -static int __init ufshcd_init(void) -{ - return pci_register_driver(&ufshcd_pci_driver); -} -module_init(ufshcd_init); - -/** - * ufshcd_exit - Driver exit clean-up routine - */ -static void __exit ufshcd_exit(void) -{ - pci_unregister_driver(&ufshcd_pci_driver); -} -module_exit(ufshcd_exit); - - -MODULE_AUTHOR("Santosh Yaragnavi , " - "Vinayak Holikatti "); -MODULE_DESCRIPTION("Generic UFS host controller driver"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(UFSHCD_DRIVER_VERSION); diff --git a/ANDROID_3.4.5/drivers/scsi/ufs/ufshci.h b/ANDROID_3.4.5/drivers/scsi/ufs/ufshci.h deleted file mode 100644 index 6e3510f7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ufs/ufshci.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Universal Flash Storage Host controller driver - * - * This code is based on drivers/scsi/ufs/ufshci.h - * Copyright (C) 2011-2012 Samsung India Software Operations - * - * Santosh Yaraganavi - * Vinayak Holikatti - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * NO WARRANTY - * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR - * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT - * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is - * solely responsible for determining the appropriateness of using and - * distributing the Program and assumes all risks associated with its - * exercise of rights under this Agreement, including but not limited to - * the risks and costs of program errors, damage to or loss of data, - * programs or equipment, and unavailability or interruption of operations. - - * DISCLAIMER OF LIABILITY - * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED - * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, - * USA. - */ - -#ifndef _UFSHCI_H -#define _UFSHCI_H - -enum { - TASK_REQ_UPIU_SIZE_DWORDS = 8, - TASK_RSP_UPIU_SIZE_DWORDS = 8, - ALIGNED_UPIU_SIZE = 128, -}; - -/* UFSHCI Registers */ -enum { - REG_CONTROLLER_CAPABILITIES = 0x00, - REG_UFS_VERSION = 0x08, - REG_CONTROLLER_DEV_ID = 0x10, - REG_CONTROLLER_PROD_ID = 0x14, - REG_INTERRUPT_STATUS = 0x20, - REG_INTERRUPT_ENABLE = 0x24, - REG_CONTROLLER_STATUS = 0x30, - REG_CONTROLLER_ENABLE = 0x34, - REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER = 0x38, - REG_UIC_ERROR_CODE_DATA_LINK_LAYER = 0x3C, - REG_UIC_ERROR_CODE_NETWORK_LAYER = 0x40, - REG_UIC_ERROR_CODE_TRANSPORT_LAYER = 0x44, - REG_UIC_ERROR_CODE_DME = 0x48, - REG_UTP_TRANSFER_REQ_INT_AGG_CONTROL = 0x4C, - REG_UTP_TRANSFER_REQ_LIST_BASE_L = 0x50, - REG_UTP_TRANSFER_REQ_LIST_BASE_H = 0x54, - REG_UTP_TRANSFER_REQ_DOOR_BELL = 0x58, - REG_UTP_TRANSFER_REQ_LIST_CLEAR = 0x5C, - REG_UTP_TRANSFER_REQ_LIST_RUN_STOP = 0x60, - REG_UTP_TASK_REQ_LIST_BASE_L = 0x70, - REG_UTP_TASK_REQ_LIST_BASE_H = 0x74, - REG_UTP_TASK_REQ_DOOR_BELL = 0x78, - REG_UTP_TASK_REQ_LIST_CLEAR = 0x7C, - REG_UTP_TASK_REQ_LIST_RUN_STOP = 0x80, - REG_UIC_COMMAND = 0x90, - REG_UIC_COMMAND_ARG_1 = 0x94, - REG_UIC_COMMAND_ARG_2 = 0x98, - REG_UIC_COMMAND_ARG_3 = 0x9C, -}; - -/* Controller capability masks */ -enum { - MASK_TRANSFER_REQUESTS_SLOTS = 0x0000001F, - MASK_TASK_MANAGEMENT_REQUEST_SLOTS = 0x00070000, - MASK_64_ADDRESSING_SUPPORT = 0x01000000, - MASK_OUT_OF_ORDER_DATA_DELIVERY_SUPPORT = 0x02000000, - MASK_UIC_DME_TEST_MODE_SUPPORT = 0x04000000, -}; - -/* UFS Version 08h */ -#define MINOR_VERSION_NUM_MASK UFS_MASK(0xFFFF, 0) -#define MAJOR_VERSION_NUM_MASK UFS_MASK(0xFFFF, 16) - -/* Controller UFSHCI version */ -enum { - UFSHCI_VERSION_10 = 0x00010000, - UFSHCI_VERSION_11 = 0x00010100, -}; - -/* - * HCDDID - Host Controller Identification Descriptor - * - Device ID and Device Class 10h - */ -#define DEVICE_CLASS UFS_MASK(0xFFFF, 0) -#define DEVICE_ID UFS_MASK(0xFF, 24) - -/* - * HCPMID - Host Controller Identification Descriptor - * - Product/Manufacturer ID 14h - */ -#define MANUFACTURE_ID_MASK UFS_MASK(0xFFFF, 0) -#define PRODUCT_ID_MASK UFS_MASK(0xFFFF, 16) - -#define UFS_BIT(x) (1L << (x)) - -#define UTP_TRANSFER_REQ_COMPL UFS_BIT(0) -#define UIC_DME_END_PT_RESET UFS_BIT(1) -#define UIC_ERROR UFS_BIT(2) -#define UIC_TEST_MODE UFS_BIT(3) -#define UIC_POWER_MODE UFS_BIT(4) -#define UIC_HIBERNATE_EXIT UFS_BIT(5) -#define UIC_HIBERNATE_ENTER UFS_BIT(6) -#define UIC_LINK_LOST UFS_BIT(7) -#define UIC_LINK_STARTUP UFS_BIT(8) -#define UTP_TASK_REQ_COMPL UFS_BIT(9) -#define UIC_COMMAND_COMPL UFS_BIT(10) -#define DEVICE_FATAL_ERROR UFS_BIT(11) -#define CONTROLLER_FATAL_ERROR UFS_BIT(16) -#define SYSTEM_BUS_FATAL_ERROR UFS_BIT(17) - -#define UFSHCD_ERROR_MASK (UIC_ERROR |\ - DEVICE_FATAL_ERROR |\ - CONTROLLER_FATAL_ERROR |\ - SYSTEM_BUS_FATAL_ERROR) - -#define INT_FATAL_ERRORS (DEVICE_FATAL_ERROR |\ - CONTROLLER_FATAL_ERROR |\ - SYSTEM_BUS_FATAL_ERROR) - -/* HCS - Host Controller Status 30h */ -#define DEVICE_PRESENT UFS_BIT(0) -#define UTP_TRANSFER_REQ_LIST_READY UFS_BIT(1) -#define UTP_TASK_REQ_LIST_READY UFS_BIT(2) -#define UIC_COMMAND_READY UFS_BIT(3) -#define HOST_ERROR_INDICATOR UFS_BIT(4) -#define DEVICE_ERROR_INDICATOR UFS_BIT(5) -#define UIC_POWER_MODE_CHANGE_REQ_STATUS_MASK UFS_MASK(0x7, 8) - -/* HCE - Host Controller Enable 34h */ -#define CONTROLLER_ENABLE UFS_BIT(0) -#define CONTROLLER_DISABLE 0x0 - -/* UECPA - Host UIC Error Code PHY Adapter Layer 38h */ -#define UIC_PHY_ADAPTER_LAYER_ERROR UFS_BIT(31) -#define UIC_PHY_ADAPTER_LAYER_ERROR_CODE_MASK 0x1F - -/* UECDL - Host UIC Error Code Data Link Layer 3Ch */ -#define UIC_DATA_LINK_LAYER_ERROR UFS_BIT(31) -#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK 0x7FFF -#define UIC_DATA_LINK_LAYER_ERROR_PA_INIT 0x2000 - -/* UECN - Host UIC Error Code Network Layer 40h */ -#define UIC_NETWORK_LAYER_ERROR UFS_BIT(31) -#define UIC_NETWORK_LAYER_ERROR_CODE_MASK 0x7 - -/* UECT - Host UIC Error Code Transport Layer 44h */ -#define UIC_TRANSPORT_LAYER_ERROR UFS_BIT(31) -#define UIC_TRANSPORT_LAYER_ERROR_CODE_MASK 0x7F - -/* UECDME - Host UIC Error Code DME 48h */ -#define UIC_DME_ERROR UFS_BIT(31) -#define UIC_DME_ERROR_CODE_MASK 0x1 - -#define INT_AGGR_TIMEOUT_VAL_MASK 0xFF -#define INT_AGGR_COUNTER_THRESHOLD_MASK UFS_MASK(0x1F, 8) -#define INT_AGGR_COUNTER_AND_TIMER_RESET UFS_BIT(16) -#define INT_AGGR_STATUS_BIT UFS_BIT(20) -#define INT_AGGR_PARAM_WRITE UFS_BIT(24) -#define INT_AGGR_ENABLE UFS_BIT(31) - -/* UTRLRSR - UTP Transfer Request Run-Stop Register 60h */ -#define UTP_TRANSFER_REQ_LIST_RUN_STOP_BIT UFS_BIT(0) - -/* UTMRLRSR - UTP Task Management Request Run-Stop Register 80h */ -#define UTP_TASK_REQ_LIST_RUN_STOP_BIT UFS_BIT(0) - -/* UICCMD - UIC Command */ -#define COMMAND_OPCODE_MASK 0xFF -#define GEN_SELECTOR_INDEX_MASK 0xFFFF - -#define MIB_ATTRIBUTE_MASK UFS_MASK(0xFFFF, 16) -#define RESET_LEVEL 0xFF - -#define ATTR_SET_TYPE_MASK UFS_MASK(0xFF, 16) -#define CONFIG_RESULT_CODE_MASK 0xFF -#define GENERIC_ERROR_CODE_MASK 0xFF - -/* UIC Commands */ -enum { - UIC_CMD_DME_GET = 0x01, - UIC_CMD_DME_SET = 0x02, - UIC_CMD_DME_PEER_GET = 0x03, - UIC_CMD_DME_PEER_SET = 0x04, - UIC_CMD_DME_POWERON = 0x10, - UIC_CMD_DME_POWEROFF = 0x11, - UIC_CMD_DME_ENABLE = 0x12, - UIC_CMD_DME_RESET = 0x14, - UIC_CMD_DME_END_PT_RST = 0x15, - UIC_CMD_DME_LINK_STARTUP = 0x16, - UIC_CMD_DME_HIBER_ENTER = 0x17, - UIC_CMD_DME_HIBER_EXIT = 0x18, - UIC_CMD_DME_TEST_MODE = 0x1A, -}; - -/* UIC Config result code / Generic error code */ -enum { - UIC_CMD_RESULT_SUCCESS = 0x00, - UIC_CMD_RESULT_INVALID_ATTR = 0x01, - UIC_CMD_RESULT_FAILURE = 0x01, - UIC_CMD_RESULT_INVALID_ATTR_VALUE = 0x02, - UIC_CMD_RESULT_READ_ONLY_ATTR = 0x03, - UIC_CMD_RESULT_WRITE_ONLY_ATTR = 0x04, - UIC_CMD_RESULT_BAD_INDEX = 0x05, - UIC_CMD_RESULT_LOCKED_ATTR = 0x06, - UIC_CMD_RESULT_BAD_TEST_FEATURE_INDEX = 0x07, - UIC_CMD_RESULT_PEER_COMM_FAILURE = 0x08, - UIC_CMD_RESULT_BUSY = 0x09, - UIC_CMD_RESULT_DME_FAILURE = 0x0A, -}; - -#define MASK_UIC_COMMAND_RESULT 0xFF - -#define INT_AGGR_COUNTER_THRESHOLD_VALUE (0x1F << 8) -#define INT_AGGR_TIMEOUT_VALUE (0x02) - -/* Interrupt disable masks */ -enum { - /* Interrupt disable mask for UFSHCI v1.0 */ - INTERRUPT_DISABLE_MASK_10 = 0xFFFF, - - /* Interrupt disable mask for UFSHCI v1.1 */ - INTERRUPT_DISABLE_MASK_11 = 0x0, -}; - -/* - * Request Descriptor Definitions - */ - -/* Transfer request command type */ -enum { - UTP_CMD_TYPE_SCSI = 0x0, - UTP_CMD_TYPE_UFS = 0x1, - UTP_CMD_TYPE_DEV_MANAGE = 0x2, -}; - -enum { - UTP_SCSI_COMMAND = 0x00000000, - UTP_NATIVE_UFS_COMMAND = 0x10000000, - UTP_DEVICE_MANAGEMENT_FUNCTION = 0x20000000, - UTP_REQ_DESC_INT_CMD = 0x01000000, -}; - -/* UTP Transfer Request Data Direction (DD) */ -enum { - UTP_NO_DATA_TRANSFER = 0x00000000, - UTP_HOST_TO_DEVICE = 0x02000000, - UTP_DEVICE_TO_HOST = 0x04000000, -}; - -/* Overall command status values */ -enum { - OCS_SUCCESS = 0x0, - OCS_INVALID_CMD_TABLE_ATTR = 0x1, - OCS_INVALID_PRDT_ATTR = 0x2, - OCS_MISMATCH_DATA_BUF_SIZE = 0x3, - OCS_MISMATCH_RESP_UPIU_SIZE = 0x4, - OCS_PEER_COMM_FAILURE = 0x5, - OCS_ABORTED = 0x6, - OCS_FATAL_ERROR = 0x7, - OCS_INVALID_COMMAND_STATUS = 0x0F, - MASK_OCS = 0x0F, -}; - -/** - * struct ufshcd_sg_entry - UFSHCI PRD Entry - * @base_addr: Lower 32bit physical address DW-0 - * @upper_addr: Upper 32bit physical address DW-1 - * @reserved: Reserved for future use DW-2 - * @size: size of physical segment DW-3 - */ -struct ufshcd_sg_entry { - u32 base_addr; - u32 upper_addr; - u32 reserved; - u32 size; -}; - -/** - * struct utp_transfer_cmd_desc - UFS Command Descriptor structure - * @command_upiu: Command UPIU Frame address - * @response_upiu: Response UPIU Frame address - * @prd_table: Physical Region Descriptor - */ -struct utp_transfer_cmd_desc { - u8 command_upiu[ALIGNED_UPIU_SIZE]; - u8 response_upiu[ALIGNED_UPIU_SIZE]; - struct ufshcd_sg_entry prd_table[SG_ALL]; -}; - -/** - * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD - * @dword0: Descriptor Header DW0 - * @dword1: Descriptor Header DW1 - * @dword2: Descriptor Header DW2 - * @dword3: Descriptor Header DW3 - */ -struct request_desc_header { - u32 dword_0; - u32 dword_1; - u32 dword_2; - u32 dword_3; -}; - -/** - * struct utp_transfer_req_desc - UTRD structure - * @header: UTRD header DW-0 to DW-3 - * @command_desc_base_addr_lo: UCD base address low DW-4 - * @command_desc_base_addr_hi: UCD base address high DW-5 - * @response_upiu_length: response UPIU length DW-6 - * @response_upiu_offset: response UPIU offset DW-6 - * @prd_table_length: Physical region descriptor length DW-7 - * @prd_table_offset: Physical region descriptor offset DW-7 - */ -struct utp_transfer_req_desc { - - /* DW 0-3 */ - struct request_desc_header header; - - /* DW 4-5*/ - u32 command_desc_base_addr_lo; - u32 command_desc_base_addr_hi; - - /* DW 6 */ - u16 response_upiu_length; - u16 response_upiu_offset; - - /* DW 7 */ - u16 prd_table_length; - u16 prd_table_offset; -}; - -/** - * struct utp_task_req_desc - UTMRD structure - * @header: UTMRD header DW-0 to DW-3 - * @task_req_upiu: Pointer to task request UPIU DW-4 to DW-11 - * @task_rsp_upiu: Pointer to task response UPIU DW12 to DW-19 - */ -struct utp_task_req_desc { - - /* DW 0-3 */ - struct request_desc_header header; - - /* DW 4-11 */ - u32 task_req_upiu[TASK_REQ_UPIU_SIZE_DWORDS]; - - /* DW 12-19 */ - u32 task_rsp_upiu[TASK_RSP_UPIU_SIZE_DWORDS]; -}; - -#endif /* End of Header */ diff --git a/ANDROID_3.4.5/drivers/scsi/ultrastor.c b/ANDROID_3.4.5/drivers/scsi/ultrastor.c deleted file mode 100644 index 14e0c40a..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ultrastor.c +++ /dev/null @@ -1,1210 +0,0 @@ -/* - * ultrastor.c Copyright (C) 1992 David B. Gentzel - * Low-level SCSI driver for UltraStor 14F, 24F, and 34F - * by David B. Gentzel, Whitfield Software Services, Carnegie, PA - * (gentzel@nova.enet.dec.com) - * scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu) - * 24F and multiple command support by John F. Carr (jfc@athena.mit.edu) - * John's work modified by Caleb Epstein (cae@jpmorgan.com) and - * Eric Youngdale (ericy@cais.com). - * Thanks to UltraStor for providing the necessary documentation - * - * This is an old driver, for the 14F and 34F you should be using the - * u14-34f driver instead. - */ - -/* - * TODO: - * 1. Find out why scatter/gather is limited to 16 requests per command. - * This is fixed, at least on the 24F, as of version 1.12 - CAE. - * 2. Look at command linking (mscp.command_link and - * mscp.command_link_id). (Does not work with many disks, - * and no performance increase. ERY). - * 3. Allow multiple adapters. - */ - -/* - * NOTES: - * The UltraStor 14F, 24F, and 34F are a family of intelligent, high - * performance SCSI-2 host adapters. They all support command queueing - * and scatter/gather I/O. Some of them can also emulate the standard - * WD1003 interface for use with OS's which don't support SCSI. Here - * is the scoop on the various models: - * 14F - ISA first-party DMA HA with floppy support and WD1003 emulation. - * 14N - ISA HA with floppy support. I think that this is a non-DMA - * HA. Nothing further known. - * 24F - EISA Bus Master HA with floppy support and WD1003 emulation. - * 34F - VL-Bus Bus Master HA with floppy support (no WD1003 emulation). - * - * The 14F, 24F, and 34F are supported by this driver. - * - * Places flagged with a triple question-mark are things which are either - * unfinished, questionable, or wrong. - */ - -/* Changes from version 1.11 alpha to 1.12 - * - * Increased the size of the scatter-gather list to 33 entries for - * the 24F adapter (it was 16). I don't have the specs for the 14F - * or the 34F, so they may support larger s-g lists as well. - * - * Caleb Epstein - */ - -/* Changes from version 1.9 to 1.11 - * - * Patches to bring this driver up to speed with the default kernel - * driver which supports only the 14F and 34F adapters. This version - * should compile cleanly into 0.99.13, 0.99.12 and probably 0.99.11. - * - * Fixes from Eric Youngdale to fix a few possible race conditions and - * several problems with bit testing operations (insufficient - * parentheses). - * - * Removed the ultrastor_abort() and ultrastor_reset() functions - * (enclosed them in #if 0 / #endif). These functions, at least on - * the 24F, cause the SCSI bus to do odd things and generally lead to - * kernel panics and machine hangs. This is like the Adaptec code. - * - * Use check/snarf_region for 14f, 34f to avoid I/O space address conflicts. - */ - -/* Changes from version 1.8 to version 1.9 - * - * 0.99.11 patches (cae@jpmorgan.com) */ - -/* Changes from version 1.7 to version 1.8 - * - * Better error reporting. - */ - -/* Changes from version 1.6 to version 1.7 - * - * Removed CSIR command code. - * - * Better race condition avoidance (xchgb function added). - * - * Set ICM and OGM status to zero at probe (24F) - * - * reset sends soft reset to UltraStor adapter - * - * reset adapter if adapter interrupts with an invalid MSCP address - * - * handle aborted command interrupt (24F) - * - */ - -/* Changes from version 1.5 to version 1.6: - * - * Read MSCP address from ICM _before_ clearing the interrupt flag. - * This fixes a race condition. - */ - -/* Changes from version 1.4 to version 1.5: - * - * Abort now calls done when multiple commands are enabled. - * - * Clear busy when aborted command finishes, not when abort is called. - * - * More debugging messages for aborts. - */ - -/* Changes from version 1.3 to version 1.4: - * - * Enable automatic request of sense data on error (requires newer version - * of scsi.c to be useful). - * - * Fix PORT_OVERRIDE for 14F. - * - * Fix abort and reset to work properly (config.aborted wasn't cleared - * after it was tested, so after a command abort no further commands would - * work). - * - * Boot time test to enable SCSI bus reset (defaults to not allowing reset). - * - * Fix test for OGM busy -- the busy bit is in different places on the 24F. - * - * Release ICM slot by clearing first byte on 24F. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */ -#include "scsi.h" -#include -#include "ultrastor.h" - -#define FALSE 0 -#define TRUE 1 - -#ifndef ULTRASTOR_DEBUG -#define ULTRASTOR_DEBUG (UD_ABORT|UD_CSIR|UD_RESET) -#endif - -#define VERSION "1.12" - -#define PACKED __attribute__((packed)) -#define ALIGNED(x) __attribute__((aligned(x))) - - -/* The 14F uses an array of 4-byte ints for its scatter/gather list. - The data can be unaligned, but need not be. It's easier to give - the list normal alignment since it doesn't need to fit into a - packed structure. */ - -typedef struct { - u32 address; - u32 num_bytes; -} ultrastor_sg_list; - - -/* MailBox SCSI Command Packet. Basic command structure for communicating - with controller. */ -struct mscp { - unsigned char opcode: 3; /* type of command */ - unsigned char xdir: 2; /* data transfer direction */ - unsigned char dcn: 1; /* disable disconnect */ - unsigned char ca: 1; /* use cache (if available) */ - unsigned char sg: 1; /* scatter/gather operation */ - unsigned char target_id: 3; /* target SCSI id */ - unsigned char ch_no: 2; /* SCSI channel (always 0 for 14f) */ - unsigned char lun: 3; /* logical unit number */ - unsigned int transfer_data PACKED; /* transfer data pointer */ - unsigned int transfer_data_length PACKED; /* length in bytes */ - unsigned int command_link PACKED; /* for linking command chains */ - unsigned char scsi_command_link_id; /* identifies command in chain */ - unsigned char number_of_sg_list; /* (if sg is set) 8 bytes per list */ - unsigned char length_of_sense_byte; - unsigned char length_of_scsi_cdbs; /* 6, 10, or 12 */ - unsigned char scsi_cdbs[12]; /* SCSI commands */ - unsigned char adapter_status; /* non-zero indicates HA error */ - unsigned char target_status; /* non-zero indicates target error */ - u32 sense_data PACKED; - /* The following fields are for software only. They are included in - the MSCP structure because they are associated with SCSI requests. */ - void (*done) (struct scsi_cmnd *); - struct scsi_cmnd *SCint; - ultrastor_sg_list sglist[ULTRASTOR_24F_MAX_SG]; /* use larger size for 24F */ -}; - - -/* Port addresses (relative to the base address) */ -#define U14F_PRODUCT_ID(port) ((port) + 0x4) -#define CONFIG(port) ((port) + 0x6) - -/* Port addresses relative to the doorbell base address. */ -#define LCL_DOORBELL_MASK(port) ((port) + 0x0) -#define LCL_DOORBELL_INTR(port) ((port) + 0x1) -#define SYS_DOORBELL_MASK(port) ((port) + 0x2) -#define SYS_DOORBELL_INTR(port) ((port) + 0x3) - - -/* Used to store configuration info read from config i/o registers. Most of - this is not used yet, but might as well save it. - - This structure also holds port addresses that are not at the same offset - on the 14F and 24F. - - This structure holds all data that must be duplicated to support multiple - adapters. */ - -static struct ultrastor_config -{ - unsigned short port_address; /* base address of card */ - unsigned short doorbell_address; /* base address of doorbell CSRs */ - unsigned short ogm_address; /* base address of OGM */ - unsigned short icm_address; /* base address of ICM */ - const void *bios_segment; - unsigned char interrupt: 4; - unsigned char dma_channel: 3; - unsigned char bios_drive_number: 1; - unsigned char heads; - unsigned char sectors; - unsigned char ha_scsi_id: 3; - unsigned char subversion: 4; - unsigned char revision; - /* The slot number is used to distinguish the 24F (slot != 0) from - the 14F and 34F (slot == 0). */ - unsigned char slot; - -#ifdef PRINT_U24F_VERSION - volatile int csir_done; -#endif - - /* A pool of MSCP structures for this adapter, and a bitmask of - busy structures. (If ULTRASTOR_14F_MAX_CMDS == 1, a 1 byte - busy flag is used instead.) */ - -#if ULTRASTOR_MAX_CMDS == 1 - unsigned char mscp_busy; -#else - unsigned long mscp_free; -#endif - volatile unsigned char aborted[ULTRASTOR_MAX_CMDS]; - struct mscp mscp[ULTRASTOR_MAX_CMDS]; -} config = {0}; - -/* Set this to 1 to reset the SCSI bus on error. */ -static int ultrastor_bus_reset; - - -/* Allowed BIOS base addresses (NULL indicates reserved) */ -static const void *const bios_segment_table[8] = { - NULL, (void *)0xC4000, (void *)0xC8000, (void *)0xCC000, - (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000, -}; - -/* Allowed IRQs for 14f */ -static const unsigned char interrupt_table_14f[4] = { 15, 14, 11, 10 }; - -/* Allowed DMA channels for 14f (0 indicates reserved) */ -static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 }; - -/* Head/sector mappings allowed by 14f */ -static const struct { - unsigned char heads; - unsigned char sectors; -} mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 } }; - -#ifndef PORT_OVERRIDE -/* ??? A probe of address 0x310 screws up NE2000 cards */ -static const unsigned short ultrastor_ports_14f[] = { - 0x330, 0x340, /*0x310,*/ 0x230, 0x240, 0x210, 0x130, 0x140, -}; -#endif - -static void ultrastor_interrupt(void *); -static irqreturn_t do_ultrastor_interrupt(int, void *); -static inline void build_sg_list(struct mscp *, struct scsi_cmnd *SCpnt); - - -/* Always called with host lock held */ - -static inline int find_and_clear_bit_16(unsigned long *field) -{ - int rv; - - if (*field == 0) - panic("No free mscp"); - - asm volatile ( - "xorl %0,%0\n\t" - "0: bsfw %1,%w0\n\t" - "btr %0,%1\n\t" - "jnc 0b" - : "=&r" (rv), "+m" (*field) :); - - return rv; -} - -/* This has been re-implemented with the help of Richard Earnshaw, - and works with gcc-2.5.8 and gcc-2.6.0. - The instability noted by jfc below appears to be a bug in - gcc-2.5.x when compiling w/o optimization. --Caleb - - This asm is fragile: it doesn't work without the casts and it may - not work without optimization. Maybe I should add a swap builtin - to gcc. --jfc */ -static inline unsigned char xchgb(unsigned char reg, - volatile unsigned char *mem) -{ - __asm__ ("xchgb %0,%1" : "=q" (reg), "=m" (*mem) : "0" (reg)); - return reg; -} - -#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT) - -/* Always called with the host lock held */ -static void log_ultrastor_abort(struct ultrastor_config *config, - int command) -{ - static char fmt[80] = "abort %d (%x); MSCP free pool: %x;"; - int i; - - for (i = 0; i < ULTRASTOR_MAX_CMDS; i++) - { - fmt[20 + i*2] = ' '; - if (! (config->mscp_free & (1 << i))) - fmt[21 + i*2] = '0' + config->mscp[i].target_id; - else - fmt[21 + i*2] = '-'; - } - fmt[20 + ULTRASTOR_MAX_CMDS * 2] = '\n'; - fmt[21 + ULTRASTOR_MAX_CMDS * 2] = 0; - printk(fmt, command, &config->mscp[command], config->mscp_free); - -} -#endif - -static int ultrastor_14f_detect(struct scsi_host_template * tpnt) -{ - size_t i; - unsigned char in_byte, version_byte = 0; - struct config_1 { - unsigned char bios_segment: 3; - unsigned char removable_disks_as_fixed: 1; - unsigned char interrupt: 2; - unsigned char dma_channel: 2; - } config_1; - struct config_2 { - unsigned char ha_scsi_id: 3; - unsigned char mapping_mode: 2; - unsigned char bios_drive_number: 1; - unsigned char tfr_port: 2; - } config_2; - -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US14F: detect: called\n"); -#endif - - /* If a 24F has already been configured, don't look for a 14F. */ - if (config.bios_segment) - return FALSE; - -#ifdef PORT_OVERRIDE - if(!request_region(PORT_OVERRIDE, 0xc, "ultrastor")) { - printk("Ultrastor I/O space already in use\n"); - return FALSE; - }; - config.port_address = PORT_OVERRIDE; -#else - for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) { - if(!request_region(ultrastor_ports_14f[i], 0x0c, "ultrastor")) continue; - config.port_address = ultrastor_ports_14f[i]; -#endif - -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US14F: detect: testing port address %03X\n", config.port_address); -#endif - - in_byte = inb(U14F_PRODUCT_ID(config.port_address)); - if (in_byte != US14F_PRODUCT_ID_0) { -#if (ULTRASTOR_DEBUG & UD_DETECT) -# ifdef PORT_OVERRIDE - printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte); -# else - printk("US14F: detect: no adapter at port %03X\n", config.port_address); -# endif -#endif -#ifdef PORT_OVERRIDE - goto out_release_port; -#else - release_region(config.port_address, 0x0c); - continue; -#endif - } - in_byte = inb(U14F_PRODUCT_ID(config.port_address) + 1); - /* Only upper nibble is significant for Product ID 1 */ - if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) { -#if (ULTRASTOR_DEBUG & UD_DETECT) -# ifdef PORT_OVERRIDE - printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte); -# else - printk("US14F: detect: no adapter at port %03X\n", config.port_address); -# endif -#endif -#ifdef PORT_OVERRIDE - goto out_release_port; -#else - release_region(config.port_address, 0x0c); - continue; -#endif - } - version_byte = in_byte; -#ifndef PORT_OVERRIDE - break; - } - if (i == ARRAY_SIZE(ultrastor_ports_14f)) { -# if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US14F: detect: no port address found!\n"); -# endif - /* all ports probed already released - we can just go straight out */ - return FALSE; - } -#endif - -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US14F: detect: adapter found at port address %03X\n", - config.port_address); -#endif - - /* Set local doorbell mask to disallow bus reset unless - ultrastor_bus_reset is true. */ - outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(config.port_address)); - - /* All above tests passed, must be the right thing. Get some useful - info. */ - - /* Register the I/O space that we use */ - - *(char *)&config_1 = inb(CONFIG(config.port_address + 0)); - *(char *)&config_2 = inb(CONFIG(config.port_address + 1)); - config.bios_segment = bios_segment_table[config_1.bios_segment]; - config.doorbell_address = config.port_address; - config.ogm_address = config.port_address + 0x8; - config.icm_address = config.port_address + 0xC; - config.interrupt = interrupt_table_14f[config_1.interrupt]; - config.ha_scsi_id = config_2.ha_scsi_id; - config.heads = mapping_table[config_2.mapping_mode].heads; - config.sectors = mapping_table[config_2.mapping_mode].sectors; - config.bios_drive_number = config_2.bios_drive_number; - config.subversion = (version_byte & 0x0F); - if (config.subversion == U34F) - config.dma_channel = 0; - else - config.dma_channel = dma_channel_table_14f[config_1.dma_channel]; - - if (!config.bios_segment) { -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US14F: detect: not detected.\n"); -#endif - goto out_release_port; - } - - /* Final consistency check, verify previous info. */ - if (config.subversion != U34F) - if (!config.dma_channel || !(config_2.tfr_port & 0x2)) { -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US14F: detect: consistency check failed\n"); -#endif - goto out_release_port; - } - - /* If we were TRULY paranoid, we could issue a host adapter inquiry - command here and verify the data returned. But frankly, I'm - exhausted! */ - - /* Finally! Now I'm satisfied... */ -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US14F: detect: detect succeeded\n" - " Port address: %03X\n" - " BIOS segment: %05X\n" - " Interrupt: %u\n" - " DMA channel: %u\n" - " H/A SCSI ID: %u\n" - " Subversion: %u\n", - config.port_address, config.bios_segment, config.interrupt, - config.dma_channel, config.ha_scsi_id, config.subversion); -#endif - tpnt->this_id = config.ha_scsi_id; - tpnt->unchecked_isa_dma = (config.subversion != U34F); - -#if ULTRASTOR_MAX_CMDS > 1 - config.mscp_free = ~0; -#endif - - /* - * Brrr, &config.mscp[0].SCint->host) it is something magical.... - * XXX and FIXME - */ - if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", &config.mscp[0].SCint->device->host)) { - printk("Unable to allocate IRQ%u for UltraStor controller.\n", - config.interrupt); - goto out_release_port; - } - if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) { - printk("Unable to allocate DMA channel %u for UltraStor controller.\n", - config.dma_channel); - free_irq(config.interrupt, NULL); - goto out_release_port; - } - tpnt->sg_tablesize = ULTRASTOR_14F_MAX_SG; - printk("UltraStor driver version" VERSION ". Using %d SG lists.\n", - ULTRASTOR_14F_MAX_SG); - - return TRUE; -out_release_port: - release_region(config.port_address, 0x0c); - return FALSE; -} - -static int ultrastor_24f_detect(struct scsi_host_template * tpnt) -{ - int i; - struct Scsi_Host * shpnt = NULL; - -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US24F: detect"); -#endif - - /* probe each EISA slot at slot address C80 */ - for (i = 1; i < 15; i++) - { - unsigned char config_1, config_2; - unsigned short addr = (i << 12) | ULTRASTOR_24F_PORT; - - if (inb(addr) != US24F_PRODUCT_ID_0 && - inb(addr+1) != US24F_PRODUCT_ID_1 && - inb(addr+2) != US24F_PRODUCT_ID_2) - continue; - - config.revision = inb(addr+3); - config.slot = i; - if (! (inb(addr+4) & 1)) - { -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("U24F: found disabled card in slot %u\n", i); -#endif - continue; - } -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("U24F: found card in slot %u\n", i); -#endif - config_1 = inb(addr + 5); - config.bios_segment = bios_segment_table[config_1 & 7]; - switch(config_1 >> 4) - { - case 1: - config.interrupt = 15; - break; - case 2: - config.interrupt = 14; - break; - case 4: - config.interrupt = 11; - break; - case 8: - config.interrupt = 10; - break; - default: - printk("U24F: invalid IRQ\n"); - return FALSE; - } - - /* BIOS addr set */ - /* base port set */ - config.port_address = addr; - config.doorbell_address = addr + 12; - config.ogm_address = addr + 0x17; - config.icm_address = addr + 0x1C; - config_2 = inb(addr + 7); - config.ha_scsi_id = config_2 & 7; - config.heads = mapping_table[(config_2 >> 3) & 3].heads; - config.sectors = mapping_table[(config_2 >> 3) & 3].sectors; -#if (ULTRASTOR_DEBUG & UD_DETECT) - printk("US24F: detect: detect succeeded\n" - " Port address: %03X\n" - " BIOS segment: %05X\n" - " Interrupt: %u\n" - " H/A SCSI ID: %u\n", - config.port_address, config.bios_segment, - config.interrupt, config.ha_scsi_id); -#endif - tpnt->this_id = config.ha_scsi_id; - tpnt->unchecked_isa_dma = 0; - tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG; - - shpnt = scsi_register(tpnt, 0); - if (!shpnt) { - printk(KERN_WARNING "(ultrastor:) Could not register scsi device. Aborting registration.\n"); - free_irq(config.interrupt, do_ultrastor_interrupt); - return FALSE; - } - - if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", shpnt)) - { - printk("Unable to allocate IRQ%u for UltraStor controller.\n", - config.interrupt); - return FALSE; - } - - shpnt->irq = config.interrupt; - shpnt->dma_channel = config.dma_channel; - shpnt->io_port = config.port_address; - -#if ULTRASTOR_MAX_CMDS > 1 - config.mscp_free = ~0; -#endif - /* Mark ICM and OGM free */ - outb(0, addr + 0x16); - outb(0, addr + 0x1B); - - /* Set local doorbell mask to disallow bus reset unless - ultrastor_bus_reset is true. */ - outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(addr+12)); - outb(0x02, SYS_DOORBELL_MASK(addr+12)); - printk("UltraStor driver version " VERSION ". Using %d SG lists.\n", - tpnt->sg_tablesize); - return TRUE; - } - return FALSE; -} - -static int ultrastor_detect(struct scsi_host_template * tpnt) -{ - tpnt->proc_name = "ultrastor"; - return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt); -} - -static int ultrastor_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->dma_channel != 0xff) - free_dma(shost->dma_channel); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -static const char *ultrastor_info(struct Scsi_Host * shpnt) -{ - static char buf[64]; - - if (config.slot) - sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u", - config.slot, config.interrupt); - else if (config.subversion) - sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u", - config.port_address, (int)config.bios_segment, - config.interrupt); - else - sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u", - config.port_address, (int)config.bios_segment, - config.interrupt, config.dma_channel); - return buf; -} - -static inline void build_sg_list(struct mscp *mscp, struct scsi_cmnd *SCpnt) -{ - struct scatterlist *sg; - long transfer_length = 0; - int i, max; - - max = scsi_sg_count(SCpnt); - scsi_for_each_sg(SCpnt, sg, max, i) { - mscp->sglist[i].address = isa_page_to_bus(sg_page(sg)) + sg->offset; - mscp->sglist[i].num_bytes = sg->length; - transfer_length += sg->length; - } - mscp->number_of_sg_list = max; - mscp->transfer_data = isa_virt_to_bus(mscp->sglist); - /* ??? May not be necessary. Docs are unclear as to whether transfer - length field is ignored or whether it should be set to the total - number of bytes of the transfer. */ - mscp->transfer_data_length = transfer_length; -} - -static int ultrastor_queuecommand_lck(struct scsi_cmnd *SCpnt, - void (*done) (struct scsi_cmnd *)) -{ - struct mscp *my_mscp; -#if ULTRASTOR_MAX_CMDS > 1 - int mscp_index; -#endif - unsigned int status; - - /* Next test is for debugging; "can't happen" */ - if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0) - panic("ultrastor_queuecommand: no free MSCP\n"); - mscp_index = find_and_clear_bit_16(&config.mscp_free); - - /* Has the command been aborted? */ - if (xchgb(0xff, &config.aborted[mscp_index]) != 0) - { - status = DID_ABORT << 16; - goto aborted; - } - - my_mscp = &config.mscp[mscp_index]; - - *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3); - - /* Tape drives don't work properly if the cache is used. The SCSI - READ command for a tape doesn't have a block offset, and the adapter - incorrectly assumes that all reads from the tape read the same - blocks. Results will depend on read buffer size and other disk - activity. - - ??? Which other device types should never use the cache? */ - my_mscp->ca = SCpnt->device->type != TYPE_TAPE; - my_mscp->target_id = SCpnt->device->id; - my_mscp->ch_no = 0; - my_mscp->lun = SCpnt->device->lun; - if (scsi_sg_count(SCpnt)) { - /* Set scatter/gather flag in SCSI command packet */ - my_mscp->sg = TRUE; - build_sg_list(my_mscp, SCpnt); - } else { - /* Unset scatter/gather flag in SCSI command packet */ - my_mscp->sg = FALSE; - my_mscp->transfer_data = isa_virt_to_bus(scsi_sglist(SCpnt)); - my_mscp->transfer_data_length = scsi_bufflen(SCpnt); - } - my_mscp->command_link = 0; /*???*/ - my_mscp->scsi_command_link_id = 0; /*???*/ - my_mscp->length_of_sense_byte = SCSI_SENSE_BUFFERSIZE; - my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len; - memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs); - my_mscp->adapter_status = 0; - my_mscp->target_status = 0; - my_mscp->sense_data = isa_virt_to_bus(&SCpnt->sense_buffer); - my_mscp->done = done; - my_mscp->SCint = SCpnt; - SCpnt->host_scribble = (unsigned char *)my_mscp; - - /* Find free OGM slot. On 24F, look for OGM status byte == 0. - On 14F and 34F, wait for local interrupt pending flag to clear. - - FIXME: now we are using new_eh we should punt here and let the - midlayer sort it out */ - -retry: - if (config.slot) - while (inb(config.ogm_address - 1) != 0 && config.aborted[mscp_index] == 0xff) - barrier(); - - /* else??? */ - - while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1)) && config.aborted[mscp_index] == 0xff) - barrier(); - - /* To avoid race conditions, keep the code to write to the adapter - atomic. This simplifies the abort code. Right now the - scsi mid layer has the host_lock already held - */ - - if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1)) - goto retry; - - status = xchgb(0, &config.aborted[mscp_index]); - if (status != 0xff) { - -#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT) - printk("USx4F: queuecommand: aborted\n"); -#if ULTRASTOR_MAX_CMDS > 1 - log_ultrastor_abort(&config, mscp_index); -#endif -#endif - status <<= 16; - - aborted: - set_bit(mscp_index, &config.mscp_free); - /* If the driver queues commands, call the done proc here. Otherwise - return an error. */ -#if ULTRASTOR_MAX_CMDS > 1 - SCpnt->result = status; - done(SCpnt); - return 0; -#else - return status; -#endif - } - - /* Store pointer in OGM address bytes */ - outl(isa_virt_to_bus(my_mscp), config.ogm_address); - - /* Issue OGM interrupt */ - if (config.slot) { - /* Write OGM command register on 24F */ - outb(1, config.ogm_address - 1); - outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address)); - } else { - outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address)); - } - -#if (ULTRASTOR_DEBUG & UD_COMMAND) - printk("USx4F: queuecommand: returning\n"); -#endif - - return 0; -} - -static DEF_SCSI_QCMD(ultrastor_queuecommand) - -/* This code must deal with 2 cases: - - 1. The command has not been written to the OGM. In this case, set - the abort flag and return. - - 2. The command has been written to the OGM and is stuck somewhere in - the adapter. - - 2a. On a 24F, ask the adapter to abort the command. It will interrupt - when it does. - - 2b. Call the command's done procedure. - - */ - -static int ultrastor_abort(struct scsi_cmnd *SCpnt) -{ -#if ULTRASTOR_DEBUG & UD_ABORT - char out[108]; - unsigned char icm_status = 0, ogm_status = 0; - unsigned int icm_addr = 0, ogm_addr = 0; -#endif - unsigned int mscp_index; - unsigned char old_aborted; - unsigned long flags; - void (*done)(struct scsi_cmnd *); - struct Scsi_Host *host = SCpnt->device->host; - - if(config.slot) - return FAILED; /* Do not attempt an abort for the 24f */ - - /* Simple consistency checking */ - if(!SCpnt->host_scribble) - return FAILED; - - mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp; - if (mscp_index >= ULTRASTOR_MAX_CMDS) - panic("Ux4F aborting invalid MSCP"); - -#if ULTRASTOR_DEBUG & UD_ABORT - if (config.slot) - { - int port0 = (config.slot << 12) | 0xc80; - int i; - unsigned long flags; - - spin_lock_irqsave(host->host_lock, flags); - strcpy(out, "OGM %d:%x ICM %d:%x ports: "); - for (i = 0; i < 16; i++) - { - unsigned char p = inb(port0 + i); - out[28 + i * 3] = "0123456789abcdef"[p >> 4]; - out[29 + i * 3] = "0123456789abcdef"[p & 15]; - out[30 + i * 3] = ' '; - } - out[28 + i * 3] = '\n'; - out[29 + i * 3] = 0; - ogm_status = inb(port0 + 22); - ogm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 23)); - icm_status = inb(port0 + 27); - icm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 28)); - spin_unlock_irqrestore(host->host_lock, flags); - } - - /* First check to see if an interrupt is pending. I suspect the SiS - chipset loses interrupts. (I also suspect is mangles data, but - one bug at a time... */ - if (config.slot ? inb(config.icm_address - 1) == 2 : - (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1)) - { - printk("Ux4F: abort while completed command pending\n"); - - spin_lock_irqsave(host->host_lock, flags); - /* FIXME: Ewww... need to think about passing host around properly */ - ultrastor_interrupt(NULL); - spin_unlock_irqrestore(host->host_lock, flags); - return SUCCESS; - } -#endif - - old_aborted = xchgb(DID_ABORT, &config.aborted[mscp_index]); - - /* aborted == 0xff is the signal that queuecommand has not yet sent - the command. It will notice the new abort flag and fail. */ - if (old_aborted == 0xff) - return SUCCESS; - - /* On 24F, send an abort MSCP request. The adapter will interrupt - and the interrupt handler will call done. */ - if (config.slot && inb(config.ogm_address - 1) == 0) - { - unsigned long flags; - - spin_lock_irqsave(host->host_lock, flags); - outl(isa_virt_to_bus(&config.mscp[mscp_index]), config.ogm_address); - udelay(8); - outb(0x80, config.ogm_address - 1); - outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address)); -#if ULTRASTOR_DEBUG & UD_ABORT - log_ultrastor_abort(&config, mscp_index); - printk(out, ogm_status, ogm_addr, icm_status, icm_addr); -#endif - spin_unlock_irqrestore(host->host_lock, flags); - /* FIXME: add a wait for the abort to complete */ - return SUCCESS; - } - -#if ULTRASTOR_DEBUG & UD_ABORT - log_ultrastor_abort(&config, mscp_index); -#endif - - /* Can't request a graceful abort. Either this is not a 24F or - the OGM is busy. Don't free the command -- the adapter might - still be using it. Setting SCint = 0 causes the interrupt - handler to ignore the command. */ - - /* FIXME - devices that implement soft resets will still be running - the command after a bus reset. We would probably rather leave - the command in the queue. The upper level code will automatically - leave the command in the active state instead of requeueing it. ERY */ - -#if ULTRASTOR_DEBUG & UD_ABORT - if (config.mscp[mscp_index].SCint != SCpnt) - printk("abort: command mismatch, %p != %p\n", - config.mscp[mscp_index].SCint, SCpnt); -#endif - if (config.mscp[mscp_index].SCint == NULL) - return FAILED; - - if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort"); - config.mscp[mscp_index].SCint = NULL; - done = config.mscp[mscp_index].done; - config.mscp[mscp_index].done = NULL; - SCpnt->result = DID_ABORT << 16; - - /* Take the host lock to guard against scsi layer re-entry */ - done(SCpnt); - - /* Need to set a timeout here in case command never completes. */ - return SUCCESS; -} - -static int ultrastor_host_reset(struct scsi_cmnd * SCpnt) -{ - unsigned long flags; - int i; - struct Scsi_Host *host = SCpnt->device->host; - -#if (ULTRASTOR_DEBUG & UD_RESET) - printk("US14F: reset: called\n"); -#endif - - if(config.slot) - return FAILED; - - spin_lock_irqsave(host->host_lock, flags); - /* Reset the adapter and SCSI bus. The SCSI bus reset can be - inhibited by clearing ultrastor_bus_reset before probe. */ - outb(0xc0, LCL_DOORBELL_INTR(config.doorbell_address)); - if (config.slot) - { - outb(0, config.ogm_address - 1); - outb(0, config.icm_address - 1); - } - -#if ULTRASTOR_MAX_CMDS == 1 - if (config.mscp_busy && config.mscp->done && config.mscp->SCint) - { - config.mscp->SCint->result = DID_RESET << 16; - config.mscp->done(config.mscp->SCint); - } - config.mscp->SCint = 0; -#else - for (i = 0; i < ULTRASTOR_MAX_CMDS; i++) - { - if (! (config.mscp_free & (1 << i)) && - config.mscp[i].done && config.mscp[i].SCint) - { - config.mscp[i].SCint->result = DID_RESET << 16; - config.mscp[i].done(config.mscp[i].SCint); - config.mscp[i].done = NULL; - } - config.mscp[i].SCint = NULL; - } -#endif - - /* FIXME - if the device implements soft resets, then the command - will still be running. ERY - - Even bigger deal with new_eh! - */ - - memset((unsigned char *)config.aborted, 0, sizeof config.aborted); -#if ULTRASTOR_MAX_CMDS == 1 - config.mscp_busy = 0; -#else - config.mscp_free = ~0; -#endif - - spin_unlock_irqrestore(host->host_lock, flags); - return SUCCESS; - -} - -int ultrastor_biosparam(struct scsi_device *sdev, struct block_device *bdev, - sector_t capacity, int * dkinfo) -{ - int size = capacity; - unsigned int s = config.heads * config.sectors; - - dkinfo[0] = config.heads; - dkinfo[1] = config.sectors; - dkinfo[2] = size / s; /* Ignore partial cylinders */ -#if 0 - if (dkinfo[2] > 1024) - dkinfo[2] = 1024; -#endif - return 0; -} - -static void ultrastor_interrupt(void *dev_id) -{ - unsigned int status; -#if ULTRASTOR_MAX_CMDS > 1 - unsigned int mscp_index; -#endif - struct mscp *mscp; - void (*done) (struct scsi_cmnd *); - struct scsi_cmnd *SCtmp; - -#if ULTRASTOR_MAX_CMDS == 1 - mscp = &config.mscp[0]; -#else - mscp = (struct mscp *)isa_bus_to_virt(inl(config.icm_address)); - mscp_index = mscp - config.mscp; - if (mscp_index >= ULTRASTOR_MAX_CMDS) { - printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp); - /* A command has been lost. Reset and report an error - for all commands. */ - ultrastor_host_reset(dev_id); - return; - } -#endif - - /* Clean ICM slot (set ICMINT bit to 0) */ - if (config.slot) { - unsigned char icm_status = inb(config.icm_address - 1); -#if ULTRASTOR_DEBUG & (UD_INTERRUPT|UD_ERROR|UD_ABORT) - if (icm_status != 1 && icm_status != 2) - printk("US24F: ICM status %x for MSCP %d (%x)\n", icm_status, - mscp_index, (unsigned int) mscp); -#endif - /* The manual says clear interrupt then write 0 to ICM status. - This seems backwards, but I'll do it anyway. --jfc */ - outb(2, SYS_DOORBELL_INTR(config.doorbell_address)); - outb(0, config.icm_address - 1); - if (icm_status == 4) { - printk("UltraStor abort command failed\n"); - return; - } - if (icm_status == 3) { - void (*done)(struct scsi_cmnd *) = mscp->done; - if (done) { - mscp->done = NULL; - mscp->SCint->result = DID_ABORT << 16; - done(mscp->SCint); - } - return; - } - } else { - outb(1, SYS_DOORBELL_INTR(config.doorbell_address)); - } - - SCtmp = mscp->SCint; - mscp->SCint = NULL; - - if (!SCtmp) - { -#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT) - printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp); -#endif -#if ULTRASTOR_MAX_CMDS == 1 - config.mscp_busy = FALSE; -#else - set_bit(mscp_index, &config.mscp_free); -#endif - config.aborted[mscp_index] = 0; - return; - } - - /* Save done locally and zero before calling. This is needed as - once we call done, we may get another command queued before this - interrupt service routine can return. */ - done = mscp->done; - mscp->done = NULL; - - /* Let the higher levels know that we're done */ - switch (mscp->adapter_status) - { - case 0: - status = DID_OK << 16; - break; - case 0x01: /* invalid command */ - case 0x02: /* invalid parameters */ - case 0x03: /* invalid data list */ - default: - status = DID_ERROR << 16; - break; - case 0x84: /* SCSI bus abort */ - status = DID_ABORT << 16; - break; - case 0x91: - status = DID_TIME_OUT << 16; - break; - } - - SCtmp->result = status | mscp->target_status; - - SCtmp->host_scribble = NULL; - - /* Free up mscp block for next command */ -#if ULTRASTOR_MAX_CMDS == 1 - config.mscp_busy = FALSE; -#else - set_bit(mscp_index, &config.mscp_free); -#endif - -#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT) - if (config.aborted[mscp_index]) - printk("Ux4 interrupt: MSCP %d (%x) aborted = %d\n", - mscp_index, (unsigned int) mscp, config.aborted[mscp_index]); -#endif - config.aborted[mscp_index] = 0; - - if (done) - done(SCtmp); - else - printk("US14F: interrupt: unexpected interrupt\n"); - - if (config.slot ? inb(config.icm_address - 1) : - (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1)) -#if (ULTRASTOR_DEBUG & UD_MULTI_CMD) - printk("Ux4F: multiple commands completed\n"); -#else - ; -#endif - -#if (ULTRASTOR_DEBUG & UD_INTERRUPT) - printk("USx4F: interrupt: returning\n"); -#endif -} - -static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id) -{ - unsigned long flags; - struct Scsi_Host *dev = dev_id; - - spin_lock_irqsave(dev->host_lock, flags); - ultrastor_interrupt(dev_id); - spin_unlock_irqrestore(dev->host_lock, flags); - return IRQ_HANDLED; -} - -MODULE_LICENSE("GPL"); - -static struct scsi_host_template driver_template = { - .name = "UltraStor 14F/24F/34F", - .detect = ultrastor_detect, - .release = ultrastor_release, - .info = ultrastor_info, - .queuecommand = ultrastor_queuecommand, - .eh_abort_handler = ultrastor_abort, - .eh_host_reset_handler = ultrastor_host_reset, - .bios_param = ultrastor_biosparam, - .can_queue = ULTRASTOR_MAX_CMDS, - .sg_tablesize = ULTRASTOR_14F_MAX_SG, - .cmd_per_lun = ULTRASTOR_MAX_CMDS_PER_LUN, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/ultrastor.h b/ANDROID_3.4.5/drivers/scsi/ultrastor.h deleted file mode 100644 index 165c18b5..00000000 --- a/ANDROID_3.4.5/drivers/scsi/ultrastor.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * ultrastor.c (C) 1991 David B. Gentzel - * Low-level scsi driver for UltraStor 14F - * by David B. Gentzel, Whitfield Software Services, Carnegie, PA - * (gentzel@nova.enet.dec.com) - * scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu) - * 24F support by John F. Carr (jfc@athena.mit.edu) - * John's work modified by Caleb Epstein (cae@jpmorgan.com) and - * Eric Youngdale (eric@tantalus.nrl.navy.mil). - * Thanks to UltraStor for providing the necessary documentation - */ - -#ifndef _ULTRASTOR_H -#define _ULTRASTOR_H - -static int ultrastor_detect(struct scsi_host_template *); -static const char *ultrastor_info(struct Scsi_Host *shpnt); -static int ultrastor_queuecommand(struct Scsi_Host *, struct scsi_cmnd *); -static int ultrastor_abort(struct scsi_cmnd *); -static int ultrastor_host_reset(struct scsi_cmnd *); -static int ultrastor_biosparam(struct scsi_device *, struct block_device *, - sector_t, int *); - - -#define ULTRASTOR_14F_MAX_SG 16 -#define ULTRASTOR_24F_MAX_SG 33 - -#define ULTRASTOR_MAX_CMDS_PER_LUN 5 -#define ULTRASTOR_MAX_CMDS 16 - -#define ULTRASTOR_24F_PORT 0xC80 - - -#ifdef ULTRASTOR_PRIVATE - -#define UD_ABORT 0x0001 -#define UD_COMMAND 0x0002 -#define UD_DETECT 0x0004 -#define UD_INTERRUPT 0x0008 -#define UD_RESET 0x0010 -#define UD_MULTI_CMD 0x0020 -#define UD_CSIR 0x0040 -#define UD_ERROR 0x0080 - -/* #define PORT_OVERRIDE 0x330 */ - -/* Values for the PRODUCT_ID ports for the 14F */ -#define US14F_PRODUCT_ID_0 0x56 -#define US14F_PRODUCT_ID_1 0x40 /* NOTE: Only upper nibble is used */ - -#define US24F_PRODUCT_ID_0 0x56 -#define US24F_PRODUCT_ID_1 0x63 -#define US24F_PRODUCT_ID_2 0x02 - -/* Subversion values */ -#define U14F 0 -#define U34F 1 - -/* MSCP field values */ - -/* Opcode */ -#define OP_HOST_ADAPTER 0x1 -#define OP_SCSI 0x2 -#define OP_RESET 0x4 - -/* Date Transfer Direction */ -#define DTD_SCSI 0x0 -#define DTD_IN 0x1 -#define DTD_OUT 0x2 -#define DTD_NONE 0x3 - -/* Host Adapter command subcodes */ -#define HA_CMD_INQUIRY 0x1 -#define HA_CMD_SELF_DIAG 0x2 -#define HA_CMD_READ_BUFF 0x3 -#define HA_CMD_WRITE_BUFF 0x4 - -#endif - -#endif diff --git a/ANDROID_3.4.5/drivers/scsi/virtio_scsi.c b/ANDROID_3.4.5/drivers/scsi/virtio_scsi.c deleted file mode 100644 index 1b384311..00000000 --- a/ANDROID_3.4.5/drivers/scsi/virtio_scsi.c +++ /dev/null @@ -1,596 +0,0 @@ -/* - * Virtio SCSI HBA driver - * - * Copyright IBM Corp. 2010 - * Copyright Red Hat, Inc. 2011 - * - * Authors: - * Stefan Hajnoczi - * Paolo Bonzini - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define VIRTIO_SCSI_MEMPOOL_SZ 64 - -/* Command queue element */ -struct virtio_scsi_cmd { - struct scsi_cmnd *sc; - struct completion *comp; - union { - struct virtio_scsi_cmd_req cmd; - struct virtio_scsi_ctrl_tmf_req tmf; - struct virtio_scsi_ctrl_an_req an; - } req; - union { - struct virtio_scsi_cmd_resp cmd; - struct virtio_scsi_ctrl_tmf_resp tmf; - struct virtio_scsi_ctrl_an_resp an; - struct virtio_scsi_event evt; - } resp; -} ____cacheline_aligned_in_smp; - -/* Driver instance state */ -struct virtio_scsi { - /* Protects ctrl_vq, req_vq and sg[] */ - spinlock_t vq_lock; - - struct virtio_device *vdev; - struct virtqueue *ctrl_vq; - struct virtqueue *event_vq; - struct virtqueue *req_vq; - - /* For sglist construction when adding commands to the virtqueue. */ - struct scatterlist sg[]; -}; - -static struct kmem_cache *virtscsi_cmd_cache; -static mempool_t *virtscsi_cmd_pool; - -static inline struct Scsi_Host *virtio_scsi_host(struct virtio_device *vdev) -{ - return vdev->priv; -} - -static void virtscsi_compute_resid(struct scsi_cmnd *sc, u32 resid) -{ - if (!resid) - return; - - if (!scsi_bidi_cmnd(sc)) { - scsi_set_resid(sc, resid); - return; - } - - scsi_in(sc)->resid = min(resid, scsi_in(sc)->length); - scsi_out(sc)->resid = resid - scsi_in(sc)->resid; -} - -/** - * virtscsi_complete_cmd - finish a scsi_cmd and invoke scsi_done - * - * Called with vq_lock held. - */ -static void virtscsi_complete_cmd(void *buf) -{ - struct virtio_scsi_cmd *cmd = buf; - struct scsi_cmnd *sc = cmd->sc; - struct virtio_scsi_cmd_resp *resp = &cmd->resp.cmd; - - dev_dbg(&sc->device->sdev_gendev, - "cmd %p response %u status %#02x sense_len %u\n", - sc, resp->response, resp->status, resp->sense_len); - - sc->result = resp->status; - virtscsi_compute_resid(sc, resp->resid); - switch (resp->response) { - case VIRTIO_SCSI_S_OK: - set_host_byte(sc, DID_OK); - break; - case VIRTIO_SCSI_S_OVERRUN: - set_host_byte(sc, DID_ERROR); - break; - case VIRTIO_SCSI_S_ABORTED: - set_host_byte(sc, DID_ABORT); - break; - case VIRTIO_SCSI_S_BAD_TARGET: - set_host_byte(sc, DID_BAD_TARGET); - break; - case VIRTIO_SCSI_S_RESET: - set_host_byte(sc, DID_RESET); - break; - case VIRTIO_SCSI_S_BUSY: - set_host_byte(sc, DID_BUS_BUSY); - break; - case VIRTIO_SCSI_S_TRANSPORT_FAILURE: - set_host_byte(sc, DID_TRANSPORT_DISRUPTED); - break; - case VIRTIO_SCSI_S_TARGET_FAILURE: - set_host_byte(sc, DID_TARGET_FAILURE); - break; - case VIRTIO_SCSI_S_NEXUS_FAILURE: - set_host_byte(sc, DID_NEXUS_FAILURE); - break; - default: - scmd_printk(KERN_WARNING, sc, "Unknown response %d", - resp->response); - /* fall through */ - case VIRTIO_SCSI_S_FAILURE: - set_host_byte(sc, DID_ERROR); - break; - } - - WARN_ON(resp->sense_len > VIRTIO_SCSI_SENSE_SIZE); - if (sc->sense_buffer) { - memcpy(sc->sense_buffer, resp->sense, - min_t(u32, resp->sense_len, VIRTIO_SCSI_SENSE_SIZE)); - if (resp->sense_len) - set_driver_byte(sc, DRIVER_SENSE); - } - - mempool_free(cmd, virtscsi_cmd_pool); - sc->scsi_done(sc); -} - -static void virtscsi_vq_done(struct virtqueue *vq, void (*fn)(void *buf)) -{ - struct Scsi_Host *sh = virtio_scsi_host(vq->vdev); - struct virtio_scsi *vscsi = shost_priv(sh); - void *buf; - unsigned long flags; - unsigned int len; - - spin_lock_irqsave(&vscsi->vq_lock, flags); - - do { - virtqueue_disable_cb(vq); - while ((buf = virtqueue_get_buf(vq, &len)) != NULL) - fn(buf); - } while (!virtqueue_enable_cb(vq)); - - spin_unlock_irqrestore(&vscsi->vq_lock, flags); -} - -static void virtscsi_req_done(struct virtqueue *vq) -{ - virtscsi_vq_done(vq, virtscsi_complete_cmd); -}; - -static void virtscsi_complete_free(void *buf) -{ - struct virtio_scsi_cmd *cmd = buf; - - if (cmd->comp) - complete_all(cmd->comp); - else - mempool_free(cmd, virtscsi_cmd_pool); -} - -static void virtscsi_ctrl_done(struct virtqueue *vq) -{ - virtscsi_vq_done(vq, virtscsi_complete_free); -}; - -static void virtscsi_event_done(struct virtqueue *vq) -{ - virtscsi_vq_done(vq, virtscsi_complete_free); -}; - -static void virtscsi_map_sgl(struct scatterlist *sg, unsigned int *p_idx, - struct scsi_data_buffer *sdb) -{ - struct sg_table *table = &sdb->table; - struct scatterlist *sg_elem; - unsigned int idx = *p_idx; - int i; - - for_each_sg(table->sgl, sg_elem, table->nents, i) - sg_set_buf(&sg[idx++], sg_virt(sg_elem), sg_elem->length); - - *p_idx = idx; -} - -/** - * virtscsi_map_cmd - map a scsi_cmd to a virtqueue scatterlist - * @vscsi : virtio_scsi state - * @cmd : command structure - * @out_num : number of read-only elements - * @in_num : number of write-only elements - * @req_size : size of the request buffer - * @resp_size : size of the response buffer - * - * Called with vq_lock held. - */ -static void virtscsi_map_cmd(struct virtio_scsi *vscsi, - struct virtio_scsi_cmd *cmd, - unsigned *out_num, unsigned *in_num, - size_t req_size, size_t resp_size) -{ - struct scsi_cmnd *sc = cmd->sc; - struct scatterlist *sg = vscsi->sg; - unsigned int idx = 0; - - if (sc) { - struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev); - BUG_ON(scsi_sg_count(sc) > shost->sg_tablesize); - - /* TODO: check feature bit and fail if unsupported? */ - BUG_ON(sc->sc_data_direction == DMA_BIDIRECTIONAL); - } - - /* Request header. */ - sg_set_buf(&sg[idx++], &cmd->req, req_size); - - /* Data-out buffer. */ - if (sc && sc->sc_data_direction != DMA_FROM_DEVICE) - virtscsi_map_sgl(sg, &idx, scsi_out(sc)); - - *out_num = idx; - - /* Response header. */ - sg_set_buf(&sg[idx++], &cmd->resp, resp_size); - - /* Data-in buffer */ - if (sc && sc->sc_data_direction != DMA_TO_DEVICE) - virtscsi_map_sgl(sg, &idx, scsi_in(sc)); - - *in_num = idx - *out_num; -} - -static int virtscsi_kick_cmd(struct virtio_scsi *vscsi, struct virtqueue *vq, - struct virtio_scsi_cmd *cmd, - size_t req_size, size_t resp_size, gfp_t gfp) -{ - unsigned int out_num, in_num; - unsigned long flags; - int ret; - - spin_lock_irqsave(&vscsi->vq_lock, flags); - - virtscsi_map_cmd(vscsi, cmd, &out_num, &in_num, req_size, resp_size); - - ret = virtqueue_add_buf(vq, vscsi->sg, out_num, in_num, cmd, gfp); - if (ret >= 0) - virtqueue_kick(vq); - - spin_unlock_irqrestore(&vscsi->vq_lock, flags); - return ret; -} - -static int virtscsi_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *sc) -{ - struct virtio_scsi *vscsi = shost_priv(sh); - struct virtio_scsi_cmd *cmd; - int ret; - - dev_dbg(&sc->device->sdev_gendev, - "cmd %p CDB: %#02x\n", sc, sc->cmnd[0]); - - ret = SCSI_MLQUEUE_HOST_BUSY; - cmd = mempool_alloc(virtscsi_cmd_pool, GFP_ATOMIC); - if (!cmd) - goto out; - - memset(cmd, 0, sizeof(*cmd)); - cmd->sc = sc; - cmd->req.cmd = (struct virtio_scsi_cmd_req){ - .lun[0] = 1, - .lun[1] = sc->device->id, - .lun[2] = (sc->device->lun >> 8) | 0x40, - .lun[3] = sc->device->lun & 0xff, - .tag = (unsigned long)sc, - .task_attr = VIRTIO_SCSI_S_SIMPLE, - .prio = 0, - .crn = 0, - }; - - BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE); - memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len); - - if (virtscsi_kick_cmd(vscsi, vscsi->req_vq, cmd, - sizeof cmd->req.cmd, sizeof cmd->resp.cmd, - GFP_ATOMIC) >= 0) - ret = 0; - -out: - return ret; -} - -static int virtscsi_tmf(struct virtio_scsi *vscsi, struct virtio_scsi_cmd *cmd) -{ - DECLARE_COMPLETION_ONSTACK(comp); - int ret = FAILED; - - cmd->comp = ∁ - if (virtscsi_kick_cmd(vscsi, vscsi->ctrl_vq, cmd, - sizeof cmd->req.tmf, sizeof cmd->resp.tmf, - GFP_NOIO) < 0) - goto out; - - wait_for_completion(&comp); - if (cmd->resp.tmf.response == VIRTIO_SCSI_S_OK || - cmd->resp.tmf.response == VIRTIO_SCSI_S_FUNCTION_SUCCEEDED) - ret = SUCCESS; - -out: - mempool_free(cmd, virtscsi_cmd_pool); - return ret; -} - -static int virtscsi_device_reset(struct scsi_cmnd *sc) -{ - struct virtio_scsi *vscsi = shost_priv(sc->device->host); - struct virtio_scsi_cmd *cmd; - - sdev_printk(KERN_INFO, sc->device, "device reset\n"); - cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO); - if (!cmd) - return FAILED; - - memset(cmd, 0, sizeof(*cmd)); - cmd->sc = sc; - cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){ - .type = VIRTIO_SCSI_T_TMF, - .subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET, - .lun[0] = 1, - .lun[1] = sc->device->id, - .lun[2] = (sc->device->lun >> 8) | 0x40, - .lun[3] = sc->device->lun & 0xff, - }; - return virtscsi_tmf(vscsi, cmd); -} - -static int virtscsi_abort(struct scsi_cmnd *sc) -{ - struct virtio_scsi *vscsi = shost_priv(sc->device->host); - struct virtio_scsi_cmd *cmd; - - scmd_printk(KERN_INFO, sc, "abort\n"); - cmd = mempool_alloc(virtscsi_cmd_pool, GFP_NOIO); - if (!cmd) - return FAILED; - - memset(cmd, 0, sizeof(*cmd)); - cmd->sc = sc; - cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){ - .type = VIRTIO_SCSI_T_TMF, - .subtype = VIRTIO_SCSI_T_TMF_ABORT_TASK, - .lun[0] = 1, - .lun[1] = sc->device->id, - .lun[2] = (sc->device->lun >> 8) | 0x40, - .lun[3] = sc->device->lun & 0xff, - .tag = (unsigned long)sc, - }; - return virtscsi_tmf(vscsi, cmd); -} - -static struct scsi_host_template virtscsi_host_template = { - .module = THIS_MODULE, - .name = "Virtio SCSI HBA", - .proc_name = "virtio_scsi", - .queuecommand = virtscsi_queuecommand, - .this_id = -1, - .eh_abort_handler = virtscsi_abort, - .eh_device_reset_handler = virtscsi_device_reset, - - .can_queue = 1024, - .dma_boundary = UINT_MAX, - .use_clustering = ENABLE_CLUSTERING, -}; - -#define virtscsi_config_get(vdev, fld) \ - ({ \ - typeof(((struct virtio_scsi_config *)0)->fld) __val; \ - vdev->config->get(vdev, \ - offsetof(struct virtio_scsi_config, fld), \ - &__val, sizeof(__val)); \ - __val; \ - }) - -#define virtscsi_config_set(vdev, fld, val) \ - (void)({ \ - typeof(((struct virtio_scsi_config *)0)->fld) __val = (val); \ - vdev->config->set(vdev, \ - offsetof(struct virtio_scsi_config, fld), \ - &__val, sizeof(__val)); \ - }) - -static int virtscsi_init(struct virtio_device *vdev, - struct virtio_scsi *vscsi) -{ - int err; - struct virtqueue *vqs[3]; - vq_callback_t *callbacks[] = { - virtscsi_ctrl_done, - virtscsi_event_done, - virtscsi_req_done - }; - const char *names[] = { - "control", - "event", - "request" - }; - - /* Discover virtqueues and write information to configuration. */ - err = vdev->config->find_vqs(vdev, 3, vqs, callbacks, names); - if (err) - return err; - - vscsi->ctrl_vq = vqs[0]; - vscsi->event_vq = vqs[1]; - vscsi->req_vq = vqs[2]; - - virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE); - virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE); - return 0; -} - -static int __devinit virtscsi_probe(struct virtio_device *vdev) -{ - struct Scsi_Host *shost; - struct virtio_scsi *vscsi; - int err; - u32 sg_elems; - u32 cmd_per_lun; - - /* We need to know how many segments before we allocate. - * We need an extra sg elements at head and tail. - */ - sg_elems = virtscsi_config_get(vdev, seg_max) ?: 1; - - /* Allocate memory and link the structs together. */ - shost = scsi_host_alloc(&virtscsi_host_template, - sizeof(*vscsi) + sizeof(vscsi->sg[0]) * (sg_elems + 2)); - - if (!shost) - return -ENOMEM; - - shost->sg_tablesize = sg_elems; - vscsi = shost_priv(shost); - vscsi->vdev = vdev; - vdev->priv = shost; - - /* Random initializations. */ - spin_lock_init(&vscsi->vq_lock); - sg_init_table(vscsi->sg, sg_elems + 2); - - err = virtscsi_init(vdev, vscsi); - if (err) - goto virtscsi_init_failed; - - cmd_per_lun = virtscsi_config_get(vdev, cmd_per_lun) ?: 1; - shost->cmd_per_lun = min_t(u32, cmd_per_lun, shost->can_queue); - shost->max_sectors = virtscsi_config_get(vdev, max_sectors) ?: 0xFFFF; - shost->max_lun = virtscsi_config_get(vdev, max_lun) + 1; - shost->max_id = virtscsi_config_get(vdev, max_target) + 1; - shost->max_channel = 0; - shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE; - err = scsi_add_host(shost, &vdev->dev); - if (err) - goto scsi_add_host_failed; - - scsi_scan_host(shost); - - return 0; - -scsi_add_host_failed: - vdev->config->del_vqs(vdev); -virtscsi_init_failed: - scsi_host_put(shost); - return err; -} - -static void virtscsi_remove_vqs(struct virtio_device *vdev) -{ - /* Stop all the virtqueues. */ - vdev->config->reset(vdev); - - vdev->config->del_vqs(vdev); -} - -static void __devexit virtscsi_remove(struct virtio_device *vdev) -{ - struct Scsi_Host *shost = virtio_scsi_host(vdev); - - scsi_remove_host(shost); - - virtscsi_remove_vqs(vdev); - scsi_host_put(shost); -} - -#ifdef CONFIG_PM -static int virtscsi_freeze(struct virtio_device *vdev) -{ - virtscsi_remove_vqs(vdev); - return 0; -} - -static int virtscsi_restore(struct virtio_device *vdev) -{ - struct Scsi_Host *sh = virtio_scsi_host(vdev); - struct virtio_scsi *vscsi = shost_priv(sh); - - return virtscsi_init(vdev, vscsi); -} -#endif - -static struct virtio_device_id id_table[] = { - { VIRTIO_ID_SCSI, VIRTIO_DEV_ANY_ID }, - { 0 }, -}; - -static struct virtio_driver virtio_scsi_driver = { - .driver.name = KBUILD_MODNAME, - .driver.owner = THIS_MODULE, - .id_table = id_table, - .probe = virtscsi_probe, -#ifdef CONFIG_PM - .freeze = virtscsi_freeze, - .restore = virtscsi_restore, -#endif - .remove = __devexit_p(virtscsi_remove), -}; - -static int __init init(void) -{ - int ret = -ENOMEM; - - virtscsi_cmd_cache = KMEM_CACHE(virtio_scsi_cmd, 0); - if (!virtscsi_cmd_cache) { - printk(KERN_ERR "kmem_cache_create() for " - "virtscsi_cmd_cache failed\n"); - goto error; - } - - - virtscsi_cmd_pool = - mempool_create_slab_pool(VIRTIO_SCSI_MEMPOOL_SZ, - virtscsi_cmd_cache); - if (!virtscsi_cmd_pool) { - printk(KERN_ERR "mempool_create() for" - "virtscsi_cmd_pool failed\n"); - goto error; - } - ret = register_virtio_driver(&virtio_scsi_driver); - if (ret < 0) - goto error; - - return 0; - -error: - if (virtscsi_cmd_pool) { - mempool_destroy(virtscsi_cmd_pool); - virtscsi_cmd_pool = NULL; - } - if (virtscsi_cmd_cache) { - kmem_cache_destroy(virtscsi_cmd_cache); - virtscsi_cmd_cache = NULL; - } - return ret; -} - -static void __exit fini(void) -{ - unregister_virtio_driver(&virtio_scsi_driver); - mempool_destroy(virtscsi_cmd_pool); - kmem_cache_destroy(virtscsi_cmd_cache); -} -module_init(init); -module_exit(fini); - -MODULE_DEVICE_TABLE(virtio, id_table); -MODULE_DESCRIPTION("Virtio SCSI HBA driver"); -MODULE_LICENSE("GPL"); diff --git a/ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.c b/ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.c deleted file mode 100644 index 4411d422..00000000 --- a/ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* - * Linux driver for VMware's para-virtualized SCSI HBA. - * - * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained by: Arvind Kumar - * - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "vmw_pvscsi.h" - -#define PVSCSI_LINUX_DRIVER_DESC "VMware PVSCSI driver" - -MODULE_DESCRIPTION(PVSCSI_LINUX_DRIVER_DESC); -MODULE_AUTHOR("VMware, Inc."); -MODULE_LICENSE("GPL"); -MODULE_VERSION(PVSCSI_DRIVER_VERSION_STRING); - -#define PVSCSI_DEFAULT_NUM_PAGES_PER_RING 8 -#define PVSCSI_DEFAULT_NUM_PAGES_MSG_RING 1 -#define PVSCSI_DEFAULT_QUEUE_DEPTH 64 -#define SGL_SIZE PAGE_SIZE - -struct pvscsi_sg_list { - struct PVSCSISGElement sge[PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT]; -}; - -struct pvscsi_ctx { - /* - * The index of the context in cmd_map serves as the context ID for a - * 1-to-1 mapping completions back to requests. - */ - struct scsi_cmnd *cmd; - struct pvscsi_sg_list *sgl; - struct list_head list; - dma_addr_t dataPA; - dma_addr_t sensePA; - dma_addr_t sglPA; -}; - -struct pvscsi_adapter { - char *mmioBase; - unsigned int irq; - u8 rev; - bool use_msi; - bool use_msix; - bool use_msg; - - spinlock_t hw_lock; - - struct workqueue_struct *workqueue; - struct work_struct work; - - struct PVSCSIRingReqDesc *req_ring; - unsigned req_pages; - unsigned req_depth; - dma_addr_t reqRingPA; - - struct PVSCSIRingCmpDesc *cmp_ring; - unsigned cmp_pages; - dma_addr_t cmpRingPA; - - struct PVSCSIRingMsgDesc *msg_ring; - unsigned msg_pages; - dma_addr_t msgRingPA; - - struct PVSCSIRingsState *rings_state; - dma_addr_t ringStatePA; - - struct pci_dev *dev; - struct Scsi_Host *host; - - struct list_head cmd_pool; - struct pvscsi_ctx *cmd_map; -}; - - -/* Command line parameters */ -static int pvscsi_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_PER_RING; -static int pvscsi_msg_ring_pages = PVSCSI_DEFAULT_NUM_PAGES_MSG_RING; -static int pvscsi_cmd_per_lun = PVSCSI_DEFAULT_QUEUE_DEPTH; -static bool pvscsi_disable_msi; -static bool pvscsi_disable_msix; -static bool pvscsi_use_msg = true; - -#define PVSCSI_RW (S_IRUSR | S_IWUSR) - -module_param_named(ring_pages, pvscsi_ring_pages, int, PVSCSI_RW); -MODULE_PARM_DESC(ring_pages, "Number of pages per req/cmp ring - (default=" - __stringify(PVSCSI_DEFAULT_NUM_PAGES_PER_RING) ")"); - -module_param_named(msg_ring_pages, pvscsi_msg_ring_pages, int, PVSCSI_RW); -MODULE_PARM_DESC(msg_ring_pages, "Number of pages for the msg ring - (default=" - __stringify(PVSCSI_DEFAULT_NUM_PAGES_MSG_RING) ")"); - -module_param_named(cmd_per_lun, pvscsi_cmd_per_lun, int, PVSCSI_RW); -MODULE_PARM_DESC(cmd_per_lun, "Maximum commands per lun - (default=" - __stringify(PVSCSI_MAX_REQ_QUEUE_DEPTH) ")"); - -module_param_named(disable_msi, pvscsi_disable_msi, bool, PVSCSI_RW); -MODULE_PARM_DESC(disable_msi, "Disable MSI use in driver - (default=0)"); - -module_param_named(disable_msix, pvscsi_disable_msix, bool, PVSCSI_RW); -MODULE_PARM_DESC(disable_msix, "Disable MSI-X use in driver - (default=0)"); - -module_param_named(use_msg, pvscsi_use_msg, bool, PVSCSI_RW); -MODULE_PARM_DESC(use_msg, "Use msg ring when available - (default=1)"); - -static const struct pci_device_id pvscsi_pci_tbl[] = { - { PCI_VDEVICE(VMWARE, PCI_DEVICE_ID_VMWARE_PVSCSI) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pvscsi_pci_tbl); - -static struct device * -pvscsi_dev(const struct pvscsi_adapter *adapter) -{ - return &(adapter->dev->dev); -} - -static struct pvscsi_ctx * -pvscsi_find_context(const struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd) -{ - struct pvscsi_ctx *ctx, *end; - - end = &adapter->cmd_map[adapter->req_depth]; - for (ctx = adapter->cmd_map; ctx < end; ctx++) - if (ctx->cmd == cmd) - return ctx; - - return NULL; -} - -static struct pvscsi_ctx * -pvscsi_acquire_context(struct pvscsi_adapter *adapter, struct scsi_cmnd *cmd) -{ - struct pvscsi_ctx *ctx; - - if (list_empty(&adapter->cmd_pool)) - return NULL; - - ctx = list_first_entry(&adapter->cmd_pool, struct pvscsi_ctx, list); - ctx->cmd = cmd; - list_del(&ctx->list); - - return ctx; -} - -static void pvscsi_release_context(struct pvscsi_adapter *adapter, - struct pvscsi_ctx *ctx) -{ - ctx->cmd = NULL; - list_add(&ctx->list, &adapter->cmd_pool); -} - -/* - * Map a pvscsi_ctx struct to a context ID field value; we map to a simple - * non-zero integer. ctx always points to an entry in cmd_map array, hence - * the return value is always >=1. - */ -static u64 pvscsi_map_context(const struct pvscsi_adapter *adapter, - const struct pvscsi_ctx *ctx) -{ - return ctx - adapter->cmd_map + 1; -} - -static struct pvscsi_ctx * -pvscsi_get_context(const struct pvscsi_adapter *adapter, u64 context) -{ - return &adapter->cmd_map[context - 1]; -} - -static void pvscsi_reg_write(const struct pvscsi_adapter *adapter, - u32 offset, u32 val) -{ - writel(val, adapter->mmioBase + offset); -} - -static u32 pvscsi_reg_read(const struct pvscsi_adapter *adapter, u32 offset) -{ - return readl(adapter->mmioBase + offset); -} - -static u32 pvscsi_read_intr_status(const struct pvscsi_adapter *adapter) -{ - return pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_INTR_STATUS); -} - -static void pvscsi_write_intr_status(const struct pvscsi_adapter *adapter, - u32 val) -{ - pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_STATUS, val); -} - -static void pvscsi_unmask_intr(const struct pvscsi_adapter *adapter) -{ - u32 intr_bits; - - intr_bits = PVSCSI_INTR_CMPL_MASK; - if (adapter->use_msg) - intr_bits |= PVSCSI_INTR_MSG_MASK; - - pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, intr_bits); -} - -static void pvscsi_mask_intr(const struct pvscsi_adapter *adapter) -{ - pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_INTR_MASK, 0); -} - -static void pvscsi_write_cmd_desc(const struct pvscsi_adapter *adapter, - u32 cmd, const void *desc, size_t len) -{ - const u32 *ptr = desc; - size_t i; - - len /= sizeof(*ptr); - pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, cmd); - for (i = 0; i < len; i++) - pvscsi_reg_write(adapter, - PVSCSI_REG_OFFSET_COMMAND_DATA, ptr[i]); -} - -static void pvscsi_abort_cmd(const struct pvscsi_adapter *adapter, - const struct pvscsi_ctx *ctx) -{ - struct PVSCSICmdDescAbortCmd cmd = { 0 }; - - cmd.target = ctx->cmd->device->id; - cmd.context = pvscsi_map_context(adapter, ctx); - - pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ABORT_CMD, &cmd, sizeof(cmd)); -} - -static void pvscsi_kick_rw_io(const struct pvscsi_adapter *adapter) -{ - pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_RW_IO, 0); -} - -static void pvscsi_process_request_ring(const struct pvscsi_adapter *adapter) -{ - pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_KICK_NON_RW_IO, 0); -} - -static int scsi_is_rw(unsigned char op) -{ - return op == READ_6 || op == WRITE_6 || - op == READ_10 || op == WRITE_10 || - op == READ_12 || op == WRITE_12 || - op == READ_16 || op == WRITE_16; -} - -static void pvscsi_kick_io(const struct pvscsi_adapter *adapter, - unsigned char op) -{ - if (scsi_is_rw(op)) - pvscsi_kick_rw_io(adapter); - else - pvscsi_process_request_ring(adapter); -} - -static void ll_adapter_reset(const struct pvscsi_adapter *adapter) -{ - dev_dbg(pvscsi_dev(adapter), "Adapter Reset on %p\n", adapter); - - pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_ADAPTER_RESET, NULL, 0); -} - -static void ll_bus_reset(const struct pvscsi_adapter *adapter) -{ - dev_dbg(pvscsi_dev(adapter), "Reseting bus on %p\n", adapter); - - pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_BUS, NULL, 0); -} - -static void ll_device_reset(const struct pvscsi_adapter *adapter, u32 target) -{ - struct PVSCSICmdDescResetDevice cmd = { 0 }; - - dev_dbg(pvscsi_dev(adapter), "Reseting device: target=%u\n", target); - - cmd.target = target; - - pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_RESET_DEVICE, - &cmd, sizeof(cmd)); -} - -static void pvscsi_create_sg(struct pvscsi_ctx *ctx, - struct scatterlist *sg, unsigned count) -{ - unsigned i; - struct PVSCSISGElement *sge; - - BUG_ON(count > PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT); - - sge = &ctx->sgl->sge[0]; - for (i = 0; i < count; i++, sg++) { - sge[i].addr = sg_dma_address(sg); - sge[i].length = sg_dma_len(sg); - sge[i].flags = 0; - } -} - -/* - * Map all data buffers for a command into PCI space and - * setup the scatter/gather list if needed. - */ -static void pvscsi_map_buffers(struct pvscsi_adapter *adapter, - struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd, - struct PVSCSIRingReqDesc *e) -{ - unsigned count; - unsigned bufflen = scsi_bufflen(cmd); - struct scatterlist *sg; - - e->dataLen = bufflen; - e->dataAddr = 0; - if (bufflen == 0) - return; - - sg = scsi_sglist(cmd); - count = scsi_sg_count(cmd); - if (count != 0) { - int segs = scsi_dma_map(cmd); - if (segs > 1) { - pvscsi_create_sg(ctx, sg, segs); - - e->flags |= PVSCSI_FLAG_CMD_WITH_SG_LIST; - ctx->sglPA = pci_map_single(adapter->dev, ctx->sgl, - SGL_SIZE, PCI_DMA_TODEVICE); - e->dataAddr = ctx->sglPA; - } else - e->dataAddr = sg_dma_address(sg); - } else { - /* - * In case there is no S/G list, scsi_sglist points - * directly to the buffer. - */ - ctx->dataPA = pci_map_single(adapter->dev, sg, bufflen, - cmd->sc_data_direction); - e->dataAddr = ctx->dataPA; - } -} - -static void pvscsi_unmap_buffers(const struct pvscsi_adapter *adapter, - struct pvscsi_ctx *ctx) -{ - struct scsi_cmnd *cmd; - unsigned bufflen; - - cmd = ctx->cmd; - bufflen = scsi_bufflen(cmd); - - if (bufflen != 0) { - unsigned count = scsi_sg_count(cmd); - - if (count != 0) { - scsi_dma_unmap(cmd); - if (ctx->sglPA) { - pci_unmap_single(adapter->dev, ctx->sglPA, - SGL_SIZE, PCI_DMA_TODEVICE); - ctx->sglPA = 0; - } - } else - pci_unmap_single(adapter->dev, ctx->dataPA, bufflen, - cmd->sc_data_direction); - } - if (cmd->sense_buffer) - pci_unmap_single(adapter->dev, ctx->sensePA, - SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); -} - -static int __devinit pvscsi_allocate_rings(struct pvscsi_adapter *adapter) -{ - adapter->rings_state = pci_alloc_consistent(adapter->dev, PAGE_SIZE, - &adapter->ringStatePA); - if (!adapter->rings_state) - return -ENOMEM; - - adapter->req_pages = min(PVSCSI_MAX_NUM_PAGES_REQ_RING, - pvscsi_ring_pages); - adapter->req_depth = adapter->req_pages - * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; - adapter->req_ring = pci_alloc_consistent(adapter->dev, - adapter->req_pages * PAGE_SIZE, - &adapter->reqRingPA); - if (!adapter->req_ring) - return -ENOMEM; - - adapter->cmp_pages = min(PVSCSI_MAX_NUM_PAGES_CMP_RING, - pvscsi_ring_pages); - adapter->cmp_ring = pci_alloc_consistent(adapter->dev, - adapter->cmp_pages * PAGE_SIZE, - &adapter->cmpRingPA); - if (!adapter->cmp_ring) - return -ENOMEM; - - BUG_ON(!IS_ALIGNED(adapter->ringStatePA, PAGE_SIZE)); - BUG_ON(!IS_ALIGNED(adapter->reqRingPA, PAGE_SIZE)); - BUG_ON(!IS_ALIGNED(adapter->cmpRingPA, PAGE_SIZE)); - - if (!adapter->use_msg) - return 0; - - adapter->msg_pages = min(PVSCSI_MAX_NUM_PAGES_MSG_RING, - pvscsi_msg_ring_pages); - adapter->msg_ring = pci_alloc_consistent(adapter->dev, - adapter->msg_pages * PAGE_SIZE, - &adapter->msgRingPA); - if (!adapter->msg_ring) - return -ENOMEM; - BUG_ON(!IS_ALIGNED(adapter->msgRingPA, PAGE_SIZE)); - - return 0; -} - -static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter) -{ - struct PVSCSICmdDescSetupRings cmd = { 0 }; - dma_addr_t base; - unsigned i; - - cmd.ringsStatePPN = adapter->ringStatePA >> PAGE_SHIFT; - cmd.reqRingNumPages = adapter->req_pages; - cmd.cmpRingNumPages = adapter->cmp_pages; - - base = adapter->reqRingPA; - for (i = 0; i < adapter->req_pages; i++) { - cmd.reqRingPPNs[i] = base >> PAGE_SHIFT; - base += PAGE_SIZE; - } - - base = adapter->cmpRingPA; - for (i = 0; i < adapter->cmp_pages; i++) { - cmd.cmpRingPPNs[i] = base >> PAGE_SHIFT; - base += PAGE_SIZE; - } - - memset(adapter->rings_state, 0, PAGE_SIZE); - memset(adapter->req_ring, 0, adapter->req_pages * PAGE_SIZE); - memset(adapter->cmp_ring, 0, adapter->cmp_pages * PAGE_SIZE); - - pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_RINGS, - &cmd, sizeof(cmd)); - - if (adapter->use_msg) { - struct PVSCSICmdDescSetupMsgRing cmd_msg = { 0 }; - - cmd_msg.numPages = adapter->msg_pages; - - base = adapter->msgRingPA; - for (i = 0; i < adapter->msg_pages; i++) { - cmd_msg.ringPPNs[i] = base >> PAGE_SHIFT; - base += PAGE_SIZE; - } - memset(adapter->msg_ring, 0, adapter->msg_pages * PAGE_SIZE); - - pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_SETUP_MSG_RING, - &cmd_msg, sizeof(cmd_msg)); - } -} - -/* - * Pull a completion descriptor off and pass the completion back - * to the SCSI mid layer. - */ -static void pvscsi_complete_request(struct pvscsi_adapter *adapter, - const struct PVSCSIRingCmpDesc *e) -{ - struct pvscsi_ctx *ctx; - struct scsi_cmnd *cmd; - u32 btstat = e->hostStatus; - u32 sdstat = e->scsiStatus; - - ctx = pvscsi_get_context(adapter, e->context); - cmd = ctx->cmd; - pvscsi_unmap_buffers(adapter, ctx); - pvscsi_release_context(adapter, ctx); - cmd->result = 0; - - if (sdstat != SAM_STAT_GOOD && - (btstat == BTSTAT_SUCCESS || - btstat == BTSTAT_LINKED_COMMAND_COMPLETED || - btstat == BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG)) { - cmd->result = (DID_OK << 16) | sdstat; - if (sdstat == SAM_STAT_CHECK_CONDITION && cmd->sense_buffer) - cmd->result |= (DRIVER_SENSE << 24); - } else - switch (btstat) { - case BTSTAT_SUCCESS: - case BTSTAT_LINKED_COMMAND_COMPLETED: - case BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG: - /* If everything went fine, let's move on.. */ - cmd->result = (DID_OK << 16); - break; - - case BTSTAT_DATARUN: - case BTSTAT_DATA_UNDERRUN: - /* Report residual data in underruns */ - scsi_set_resid(cmd, scsi_bufflen(cmd) - e->dataLen); - cmd->result = (DID_ERROR << 16); - break; - - case BTSTAT_SELTIMEO: - /* Our emulation returns this for non-connected devs */ - cmd->result = (DID_BAD_TARGET << 16); - break; - - case BTSTAT_LUNMISMATCH: - case BTSTAT_TAGREJECT: - case BTSTAT_BADMSG: - cmd->result = (DRIVER_INVALID << 24); - /* fall through */ - - case BTSTAT_HAHARDWARE: - case BTSTAT_INVPHASE: - case BTSTAT_HATIMEOUT: - case BTSTAT_NORESPONSE: - case BTSTAT_DISCONNECT: - case BTSTAT_HASOFTWARE: - case BTSTAT_BUSFREE: - case BTSTAT_SENSFAILED: - cmd->result |= (DID_ERROR << 16); - break; - - case BTSTAT_SENTRST: - case BTSTAT_RECVRST: - case BTSTAT_BUSRESET: - cmd->result = (DID_RESET << 16); - break; - - case BTSTAT_ABORTQUEUE: - cmd->result = (DID_ABORT << 16); - break; - - case BTSTAT_SCSIPARITY: - cmd->result = (DID_PARITY << 16); - break; - - default: - cmd->result = (DID_ERROR << 16); - scmd_printk(KERN_DEBUG, cmd, - "Unknown completion status: 0x%x\n", - btstat); - } - - dev_dbg(&cmd->device->sdev_gendev, - "cmd=%p %x ctx=%p result=0x%x status=0x%x,%x\n", - cmd, cmd->cmnd[0], ctx, cmd->result, btstat, sdstat); - - cmd->scsi_done(cmd); -} - -/* - * barrier usage : Since the PVSCSI device is emulated, there could be cases - * where we may want to serialize some accesses between the driver and the - * emulation layer. We use compiler barriers instead of the more expensive - * memory barriers because PVSCSI is only supported on X86 which has strong - * memory access ordering. - */ -static void pvscsi_process_completion_ring(struct pvscsi_adapter *adapter) -{ - struct PVSCSIRingsState *s = adapter->rings_state; - struct PVSCSIRingCmpDesc *ring = adapter->cmp_ring; - u32 cmp_entries = s->cmpNumEntriesLog2; - - while (s->cmpConsIdx != s->cmpProdIdx) { - struct PVSCSIRingCmpDesc *e = ring + (s->cmpConsIdx & - MASK(cmp_entries)); - /* - * This barrier() ensures that *e is not dereferenced while - * the device emulation still writes data into the slot. - * Since the device emulation advances s->cmpProdIdx only after - * updating the slot we want to check it first. - */ - barrier(); - pvscsi_complete_request(adapter, e); - /* - * This barrier() ensures that compiler doesn't reorder write - * to s->cmpConsIdx before the read of (*e) inside - * pvscsi_complete_request. Otherwise, device emulation may - * overwrite *e before we had a chance to read it. - */ - barrier(); - s->cmpConsIdx++; - } -} - -/* - * Translate a Linux SCSI request into a request ring entry. - */ -static int pvscsi_queue_ring(struct pvscsi_adapter *adapter, - struct pvscsi_ctx *ctx, struct scsi_cmnd *cmd) -{ - struct PVSCSIRingsState *s; - struct PVSCSIRingReqDesc *e; - struct scsi_device *sdev; - u32 req_entries; - - s = adapter->rings_state; - sdev = cmd->device; - req_entries = s->reqNumEntriesLog2; - - /* - * If this condition holds, we might have room on the request ring, but - * we might not have room on the completion ring for the response. - * However, we have already ruled out this possibility - we would not - * have successfully allocated a context if it were true, since we only - * have one context per request entry. Check for it anyway, since it - * would be a serious bug. - */ - if (s->reqProdIdx - s->cmpConsIdx >= 1 << req_entries) { - scmd_printk(KERN_ERR, cmd, "vmw_pvscsi: " - "ring full: reqProdIdx=%d cmpConsIdx=%d\n", - s->reqProdIdx, s->cmpConsIdx); - return -1; - } - - e = adapter->req_ring + (s->reqProdIdx & MASK(req_entries)); - - e->bus = sdev->channel; - e->target = sdev->id; - memset(e->lun, 0, sizeof(e->lun)); - e->lun[1] = sdev->lun; - - if (cmd->sense_buffer) { - ctx->sensePA = pci_map_single(adapter->dev, cmd->sense_buffer, - SCSI_SENSE_BUFFERSIZE, - PCI_DMA_FROMDEVICE); - e->senseAddr = ctx->sensePA; - e->senseLen = SCSI_SENSE_BUFFERSIZE; - } else { - e->senseLen = 0; - e->senseAddr = 0; - } - e->cdbLen = cmd->cmd_len; - e->vcpuHint = smp_processor_id(); - memcpy(e->cdb, cmd->cmnd, e->cdbLen); - - e->tag = SIMPLE_QUEUE_TAG; - if (sdev->tagged_supported && - (cmd->tag == HEAD_OF_QUEUE_TAG || - cmd->tag == ORDERED_QUEUE_TAG)) - e->tag = cmd->tag; - - if (cmd->sc_data_direction == DMA_FROM_DEVICE) - e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST; - else if (cmd->sc_data_direction == DMA_TO_DEVICE) - e->flags = PVSCSI_FLAG_CMD_DIR_TODEVICE; - else if (cmd->sc_data_direction == DMA_NONE) - e->flags = PVSCSI_FLAG_CMD_DIR_NONE; - else - e->flags = 0; - - pvscsi_map_buffers(adapter, ctx, cmd, e); - - e->context = pvscsi_map_context(adapter, ctx); - - barrier(); - - s->reqProdIdx++; - - return 0; -} - -static int pvscsi_queue_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - struct Scsi_Host *host = cmd->device->host; - struct pvscsi_adapter *adapter = shost_priv(host); - struct pvscsi_ctx *ctx; - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - - ctx = pvscsi_acquire_context(adapter, cmd); - if (!ctx || pvscsi_queue_ring(adapter, ctx, cmd) != 0) { - if (ctx) - pvscsi_release_context(adapter, ctx); - spin_unlock_irqrestore(&adapter->hw_lock, flags); - return SCSI_MLQUEUE_HOST_BUSY; - } - - cmd->scsi_done = done; - - dev_dbg(&cmd->device->sdev_gendev, - "queued cmd %p, ctx %p, op=%x\n", cmd, ctx, cmd->cmnd[0]); - - spin_unlock_irqrestore(&adapter->hw_lock, flags); - - pvscsi_kick_io(adapter, cmd->cmnd[0]); - - return 0; -} - -static DEF_SCSI_QCMD(pvscsi_queue) - -static int pvscsi_abort(struct scsi_cmnd *cmd) -{ - struct pvscsi_adapter *adapter = shost_priv(cmd->device->host); - struct pvscsi_ctx *ctx; - unsigned long flags; - - scmd_printk(KERN_DEBUG, cmd, "task abort on host %u, %p\n", - adapter->host->host_no, cmd); - - spin_lock_irqsave(&adapter->hw_lock, flags); - - /* - * Poll the completion ring first - we might be trying to abort - * a command that is waiting to be dispatched in the completion ring. - */ - pvscsi_process_completion_ring(adapter); - - /* - * If there is no context for the command, it either already succeeded - * or else was never properly issued. Not our problem. - */ - ctx = pvscsi_find_context(adapter, cmd); - if (!ctx) { - scmd_printk(KERN_DEBUG, cmd, "Failed to abort cmd %p\n", cmd); - goto out; - } - - pvscsi_abort_cmd(adapter, ctx); - - pvscsi_process_completion_ring(adapter); - -out: - spin_unlock_irqrestore(&adapter->hw_lock, flags); - return SUCCESS; -} - -/* - * Abort all outstanding requests. This is only safe to use if the completion - * ring will never be walked again or the device has been reset, because it - * destroys the 1-1 mapping between context field passed to emulation and our - * request structure. - */ -static void pvscsi_reset_all(struct pvscsi_adapter *adapter) -{ - unsigned i; - - for (i = 0; i < adapter->req_depth; i++) { - struct pvscsi_ctx *ctx = &adapter->cmd_map[i]; - struct scsi_cmnd *cmd = ctx->cmd; - if (cmd) { - scmd_printk(KERN_ERR, cmd, - "Forced reset on cmd %p\n", cmd); - pvscsi_unmap_buffers(adapter, ctx); - pvscsi_release_context(adapter, ctx); - cmd->result = (DID_RESET << 16); - cmd->scsi_done(cmd); - } - } -} - -static int pvscsi_host_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host = cmd->device->host; - struct pvscsi_adapter *adapter = shost_priv(host); - unsigned long flags; - bool use_msg; - - scmd_printk(KERN_INFO, cmd, "SCSI Host reset\n"); - - spin_lock_irqsave(&adapter->hw_lock, flags); - - use_msg = adapter->use_msg; - - if (use_msg) { - adapter->use_msg = 0; - spin_unlock_irqrestore(&adapter->hw_lock, flags); - - /* - * Now that we know that the ISR won't add more work on the - * workqueue we can safely flush any outstanding work. - */ - flush_workqueue(adapter->workqueue); - spin_lock_irqsave(&adapter->hw_lock, flags); - } - - /* - * We're going to tear down the entire ring structure and set it back - * up, so stalling new requests until all completions are flushed and - * the rings are back in place. - */ - - pvscsi_process_request_ring(adapter); - - ll_adapter_reset(adapter); - - /* - * Now process any completions. Note we do this AFTER adapter reset, - * which is strange, but stops races where completions get posted - * between processing the ring and issuing the reset. The backend will - * not touch the ring memory after reset, so the immediately pre-reset - * completion ring state is still valid. - */ - pvscsi_process_completion_ring(adapter); - - pvscsi_reset_all(adapter); - adapter->use_msg = use_msg; - pvscsi_setup_all_rings(adapter); - pvscsi_unmask_intr(adapter); - - spin_unlock_irqrestore(&adapter->hw_lock, flags); - - return SUCCESS; -} - -static int pvscsi_bus_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host = cmd->device->host; - struct pvscsi_adapter *adapter = shost_priv(host); - unsigned long flags; - - scmd_printk(KERN_INFO, cmd, "SCSI Bus reset\n"); - - /* - * We don't want to queue new requests for this bus after - * flushing all pending requests to emulation, since new - * requests could then sneak in during this bus reset phase, - * so take the lock now. - */ - spin_lock_irqsave(&adapter->hw_lock, flags); - - pvscsi_process_request_ring(adapter); - ll_bus_reset(adapter); - pvscsi_process_completion_ring(adapter); - - spin_unlock_irqrestore(&adapter->hw_lock, flags); - - return SUCCESS; -} - -static int pvscsi_device_reset(struct scsi_cmnd *cmd) -{ - struct Scsi_Host *host = cmd->device->host; - struct pvscsi_adapter *adapter = shost_priv(host); - unsigned long flags; - - scmd_printk(KERN_INFO, cmd, "SCSI device reset on scsi%u:%u\n", - host->host_no, cmd->device->id); - - /* - * We don't want to queue new requests for this device after flushing - * all pending requests to emulation, since new requests could then - * sneak in during this device reset phase, so take the lock now. - */ - spin_lock_irqsave(&adapter->hw_lock, flags); - - pvscsi_process_request_ring(adapter); - ll_device_reset(adapter, cmd->device->id); - pvscsi_process_completion_ring(adapter); - - spin_unlock_irqrestore(&adapter->hw_lock, flags); - - return SUCCESS; -} - -static struct scsi_host_template pvscsi_template; - -static const char *pvscsi_info(struct Scsi_Host *host) -{ - struct pvscsi_adapter *adapter = shost_priv(host); - static char buf[256]; - - sprintf(buf, "VMware PVSCSI storage adapter rev %d, req/cmp/msg rings: " - "%u/%u/%u pages, cmd_per_lun=%u", adapter->rev, - adapter->req_pages, adapter->cmp_pages, adapter->msg_pages, - pvscsi_template.cmd_per_lun); - - return buf; -} - -static struct scsi_host_template pvscsi_template = { - .module = THIS_MODULE, - .name = "VMware PVSCSI Host Adapter", - .proc_name = "vmw_pvscsi", - .info = pvscsi_info, - .queuecommand = pvscsi_queue, - .this_id = -1, - .sg_tablesize = PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT, - .dma_boundary = UINT_MAX, - .max_sectors = 0xffff, - .use_clustering = ENABLE_CLUSTERING, - .eh_abort_handler = pvscsi_abort, - .eh_device_reset_handler = pvscsi_device_reset, - .eh_bus_reset_handler = pvscsi_bus_reset, - .eh_host_reset_handler = pvscsi_host_reset, -}; - -static void pvscsi_process_msg(const struct pvscsi_adapter *adapter, - const struct PVSCSIRingMsgDesc *e) -{ - struct PVSCSIRingsState *s = adapter->rings_state; - struct Scsi_Host *host = adapter->host; - struct scsi_device *sdev; - - printk(KERN_INFO "vmw_pvscsi: msg type: 0x%x - MSG RING: %u/%u (%u) \n", - e->type, s->msgProdIdx, s->msgConsIdx, s->msgNumEntriesLog2); - - BUILD_BUG_ON(PVSCSI_MSG_LAST != 2); - - if (e->type == PVSCSI_MSG_DEV_ADDED) { - struct PVSCSIMsgDescDevStatusChanged *desc; - desc = (struct PVSCSIMsgDescDevStatusChanged *)e; - - printk(KERN_INFO - "vmw_pvscsi: msg: device added at scsi%u:%u:%u\n", - desc->bus, desc->target, desc->lun[1]); - - if (!scsi_host_get(host)) - return; - - sdev = scsi_device_lookup(host, desc->bus, desc->target, - desc->lun[1]); - if (sdev) { - printk(KERN_INFO "vmw_pvscsi: device already exists\n"); - scsi_device_put(sdev); - } else - scsi_add_device(adapter->host, desc->bus, - desc->target, desc->lun[1]); - - scsi_host_put(host); - } else if (e->type == PVSCSI_MSG_DEV_REMOVED) { - struct PVSCSIMsgDescDevStatusChanged *desc; - desc = (struct PVSCSIMsgDescDevStatusChanged *)e; - - printk(KERN_INFO - "vmw_pvscsi: msg: device removed at scsi%u:%u:%u\n", - desc->bus, desc->target, desc->lun[1]); - - if (!scsi_host_get(host)) - return; - - sdev = scsi_device_lookup(host, desc->bus, desc->target, - desc->lun[1]); - if (sdev) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } else - printk(KERN_INFO - "vmw_pvscsi: failed to lookup scsi%u:%u:%u\n", - desc->bus, desc->target, desc->lun[1]); - - scsi_host_put(host); - } -} - -static int pvscsi_msg_pending(const struct pvscsi_adapter *adapter) -{ - struct PVSCSIRingsState *s = adapter->rings_state; - - return s->msgProdIdx != s->msgConsIdx; -} - -static void pvscsi_process_msg_ring(const struct pvscsi_adapter *adapter) -{ - struct PVSCSIRingsState *s = adapter->rings_state; - struct PVSCSIRingMsgDesc *ring = adapter->msg_ring; - u32 msg_entries = s->msgNumEntriesLog2; - - while (pvscsi_msg_pending(adapter)) { - struct PVSCSIRingMsgDesc *e = ring + (s->msgConsIdx & - MASK(msg_entries)); - - barrier(); - pvscsi_process_msg(adapter, e); - barrier(); - s->msgConsIdx++; - } -} - -static void pvscsi_msg_workqueue_handler(struct work_struct *data) -{ - struct pvscsi_adapter *adapter; - - adapter = container_of(data, struct pvscsi_adapter, work); - - pvscsi_process_msg_ring(adapter); -} - -static int pvscsi_setup_msg_workqueue(struct pvscsi_adapter *adapter) -{ - char name[32]; - - if (!pvscsi_use_msg) - return 0; - - pvscsi_reg_write(adapter, PVSCSI_REG_OFFSET_COMMAND, - PVSCSI_CMD_SETUP_MSG_RING); - - if (pvscsi_reg_read(adapter, PVSCSI_REG_OFFSET_COMMAND_STATUS) == -1) - return 0; - - snprintf(name, sizeof(name), - "vmw_pvscsi_wq_%u", adapter->host->host_no); - - adapter->workqueue = create_singlethread_workqueue(name); - if (!adapter->workqueue) { - printk(KERN_ERR "vmw_pvscsi: failed to create work queue\n"); - return 0; - } - INIT_WORK(&adapter->work, pvscsi_msg_workqueue_handler); - - return 1; -} - -static irqreturn_t pvscsi_isr(int irq, void *devp) -{ - struct pvscsi_adapter *adapter = devp; - int handled; - - if (adapter->use_msi || adapter->use_msix) - handled = true; - else { - u32 val = pvscsi_read_intr_status(adapter); - handled = (val & PVSCSI_INTR_ALL_SUPPORTED) != 0; - if (handled) - pvscsi_write_intr_status(devp, val); - } - - if (handled) { - unsigned long flags; - - spin_lock_irqsave(&adapter->hw_lock, flags); - - pvscsi_process_completion_ring(adapter); - if (adapter->use_msg && pvscsi_msg_pending(adapter)) - queue_work(adapter->workqueue, &adapter->work); - - spin_unlock_irqrestore(&adapter->hw_lock, flags); - } - - return IRQ_RETVAL(handled); -} - -static void pvscsi_free_sgls(const struct pvscsi_adapter *adapter) -{ - struct pvscsi_ctx *ctx = adapter->cmd_map; - unsigned i; - - for (i = 0; i < adapter->req_depth; ++i, ++ctx) - free_pages((unsigned long)ctx->sgl, get_order(SGL_SIZE)); -} - -static int pvscsi_setup_msix(const struct pvscsi_adapter *adapter, - unsigned int *irq) -{ - struct msix_entry entry = { 0, PVSCSI_VECTOR_COMPLETION }; - int ret; - - ret = pci_enable_msix(adapter->dev, &entry, 1); - if (ret) - return ret; - - *irq = entry.vector; - - return 0; -} - -static void pvscsi_shutdown_intr(struct pvscsi_adapter *adapter) -{ - if (adapter->irq) { - free_irq(adapter->irq, adapter); - adapter->irq = 0; - } - if (adapter->use_msi) { - pci_disable_msi(adapter->dev); - adapter->use_msi = 0; - } else if (adapter->use_msix) { - pci_disable_msix(adapter->dev); - adapter->use_msix = 0; - } -} - -static void pvscsi_release_resources(struct pvscsi_adapter *adapter) -{ - pvscsi_shutdown_intr(adapter); - - if (adapter->workqueue) - destroy_workqueue(adapter->workqueue); - - if (adapter->mmioBase) - pci_iounmap(adapter->dev, adapter->mmioBase); - - pci_release_regions(adapter->dev); - - if (adapter->cmd_map) { - pvscsi_free_sgls(adapter); - kfree(adapter->cmd_map); - } - - if (adapter->rings_state) - pci_free_consistent(adapter->dev, PAGE_SIZE, - adapter->rings_state, adapter->ringStatePA); - - if (adapter->req_ring) - pci_free_consistent(adapter->dev, - adapter->req_pages * PAGE_SIZE, - adapter->req_ring, adapter->reqRingPA); - - if (adapter->cmp_ring) - pci_free_consistent(adapter->dev, - adapter->cmp_pages * PAGE_SIZE, - adapter->cmp_ring, adapter->cmpRingPA); - - if (adapter->msg_ring) - pci_free_consistent(adapter->dev, - adapter->msg_pages * PAGE_SIZE, - adapter->msg_ring, adapter->msgRingPA); -} - -/* - * Allocate scatter gather lists. - * - * These are statically allocated. Trying to be clever was not worth it. - * - * Dynamic allocation can fail, and we can't go deep into the memory - * allocator, since we're a SCSI driver, and trying too hard to allocate - * memory might generate disk I/O. We also don't want to fail disk I/O - * in that case because we can't get an allocation - the I/O could be - * trying to swap out data to free memory. Since that is pathological, - * just use a statically allocated scatter list. - * - */ -static int __devinit pvscsi_allocate_sg(struct pvscsi_adapter *adapter) -{ - struct pvscsi_ctx *ctx; - int i; - - ctx = adapter->cmd_map; - BUILD_BUG_ON(sizeof(struct pvscsi_sg_list) > SGL_SIZE); - - for (i = 0; i < adapter->req_depth; ++i, ++ctx) { - ctx->sgl = (void *)__get_free_pages(GFP_KERNEL, - get_order(SGL_SIZE)); - ctx->sglPA = 0; - BUG_ON(!IS_ALIGNED(((unsigned long)ctx->sgl), PAGE_SIZE)); - if (!ctx->sgl) { - for (; i >= 0; --i, --ctx) { - free_pages((unsigned long)ctx->sgl, - get_order(SGL_SIZE)); - ctx->sgl = NULL; - } - return -ENOMEM; - } - } - - return 0; -} - -/* - * Query the device, fetch the config info and return the - * maximum number of targets on the adapter. In case of - * failure due to any reason return default i.e. 16. - */ -static u32 pvscsi_get_max_targets(struct pvscsi_adapter *adapter) -{ - struct PVSCSICmdDescConfigCmd cmd; - struct PVSCSIConfigPageHeader *header; - struct device *dev; - dma_addr_t configPagePA; - void *config_page; - u32 numPhys = 16; - - dev = pvscsi_dev(adapter); - config_page = pci_alloc_consistent(adapter->dev, PAGE_SIZE, - &configPagePA); - if (!config_page) { - dev_warn(dev, "vmw_pvscsi: failed to allocate memory for config page\n"); - goto exit; - } - BUG_ON(configPagePA & ~PAGE_MASK); - - /* Fetch config info from the device. */ - cmd.configPageAddress = ((u64)PVSCSI_CONFIG_CONTROLLER_ADDRESS) << 32; - cmd.configPageNum = PVSCSI_CONFIG_PAGE_CONTROLLER; - cmd.cmpAddr = configPagePA; - cmd._pad = 0; - - /* - * Mark the completion page header with error values. If the device - * completes the command successfully, it sets the status values to - * indicate success. - */ - header = config_page; - memset(header, 0, sizeof *header); - header->hostStatus = BTSTAT_INVPARAM; - header->scsiStatus = SDSTAT_CHECK; - - pvscsi_write_cmd_desc(adapter, PVSCSI_CMD_CONFIG, &cmd, sizeof cmd); - - if (header->hostStatus == BTSTAT_SUCCESS && - header->scsiStatus == SDSTAT_GOOD) { - struct PVSCSIConfigPageController *config; - - config = config_page; - numPhys = config->numPhys; - } else - dev_warn(dev, "vmw_pvscsi: PVSCSI_CMD_CONFIG failed. hostStatus = 0x%x, scsiStatus = 0x%x\n", - header->hostStatus, header->scsiStatus); - pci_free_consistent(adapter->dev, PAGE_SIZE, config_page, configPagePA); -exit: - return numPhys; -} - -static int __devinit pvscsi_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct pvscsi_adapter *adapter; - struct Scsi_Host *host; - struct device *dev; - unsigned int i; - unsigned long flags = 0; - int error; - - error = -ENODEV; - - if (pci_enable_device(pdev)) - return error; - - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 && - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { - printk(KERN_INFO "vmw_pvscsi: using 64bit dma\n"); - } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 && - pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) { - printk(KERN_INFO "vmw_pvscsi: using 32bit dma\n"); - } else { - printk(KERN_ERR "vmw_pvscsi: failed to set DMA mask\n"); - goto out_disable_device; - } - - pvscsi_template.can_queue = - min(PVSCSI_MAX_NUM_PAGES_REQ_RING, pvscsi_ring_pages) * - PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE; - pvscsi_template.cmd_per_lun = - min(pvscsi_template.can_queue, pvscsi_cmd_per_lun); - host = scsi_host_alloc(&pvscsi_template, sizeof(struct pvscsi_adapter)); - if (!host) { - printk(KERN_ERR "vmw_pvscsi: failed to allocate host\n"); - goto out_disable_device; - } - - adapter = shost_priv(host); - memset(adapter, 0, sizeof(*adapter)); - adapter->dev = pdev; - adapter->host = host; - - spin_lock_init(&adapter->hw_lock); - - host->max_channel = 0; - host->max_id = 16; - host->max_lun = 1; - host->max_cmd_len = 16; - - adapter->rev = pdev->revision; - - if (pci_request_regions(pdev, "vmw_pvscsi")) { - printk(KERN_ERR "vmw_pvscsi: pci memory selection failed\n"); - goto out_free_host; - } - - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - if ((pci_resource_flags(pdev, i) & PCI_BASE_ADDRESS_SPACE_IO)) - continue; - - if (pci_resource_len(pdev, i) < PVSCSI_MEM_SPACE_SIZE) - continue; - - break; - } - - if (i == DEVICE_COUNT_RESOURCE) { - printk(KERN_ERR - "vmw_pvscsi: adapter has no suitable MMIO region\n"); - goto out_release_resources; - } - - adapter->mmioBase = pci_iomap(pdev, i, PVSCSI_MEM_SPACE_SIZE); - - if (!adapter->mmioBase) { - printk(KERN_ERR - "vmw_pvscsi: can't iomap for BAR %d memsize %lu\n", - i, PVSCSI_MEM_SPACE_SIZE); - goto out_release_resources; - } - - pci_set_master(pdev); - pci_set_drvdata(pdev, host); - - ll_adapter_reset(adapter); - - adapter->use_msg = pvscsi_setup_msg_workqueue(adapter); - - error = pvscsi_allocate_rings(adapter); - if (error) { - printk(KERN_ERR "vmw_pvscsi: unable to allocate ring memory\n"); - goto out_release_resources; - } - - /* - * Ask the device for max number of targets. - */ - host->max_id = pvscsi_get_max_targets(adapter); - dev = pvscsi_dev(adapter); - dev_info(dev, "vmw_pvscsi: host->max_id: %u\n", host->max_id); - - /* - * From this point on we should reset the adapter if anything goes - * wrong. - */ - pvscsi_setup_all_rings(adapter); - - adapter->cmd_map = kcalloc(adapter->req_depth, - sizeof(struct pvscsi_ctx), GFP_KERNEL); - if (!adapter->cmd_map) { - printk(KERN_ERR "vmw_pvscsi: failed to allocate memory.\n"); - error = -ENOMEM; - goto out_reset_adapter; - } - - INIT_LIST_HEAD(&adapter->cmd_pool); - for (i = 0; i < adapter->req_depth; i++) { - struct pvscsi_ctx *ctx = adapter->cmd_map + i; - list_add(&ctx->list, &adapter->cmd_pool); - } - - error = pvscsi_allocate_sg(adapter); - if (error) { - printk(KERN_ERR "vmw_pvscsi: unable to allocate s/g table\n"); - goto out_reset_adapter; - } - - if (!pvscsi_disable_msix && - pvscsi_setup_msix(adapter, &adapter->irq) == 0) { - printk(KERN_INFO "vmw_pvscsi: using MSI-X\n"); - adapter->use_msix = 1; - } else if (!pvscsi_disable_msi && pci_enable_msi(pdev) == 0) { - printk(KERN_INFO "vmw_pvscsi: using MSI\n"); - adapter->use_msi = 1; - adapter->irq = pdev->irq; - } else { - printk(KERN_INFO "vmw_pvscsi: using INTx\n"); - adapter->irq = pdev->irq; - flags = IRQF_SHARED; - } - - error = request_irq(adapter->irq, pvscsi_isr, flags, - "vmw_pvscsi", adapter); - if (error) { - printk(KERN_ERR - "vmw_pvscsi: unable to request IRQ: %d\n", error); - adapter->irq = 0; - goto out_reset_adapter; - } - - error = scsi_add_host(host, &pdev->dev); - if (error) { - printk(KERN_ERR - "vmw_pvscsi: scsi_add_host failed: %d\n", error); - goto out_reset_adapter; - } - - dev_info(&pdev->dev, "VMware PVSCSI rev %d host #%u\n", - adapter->rev, host->host_no); - - pvscsi_unmask_intr(adapter); - - scsi_scan_host(host); - - return 0; - -out_reset_adapter: - ll_adapter_reset(adapter); -out_release_resources: - pvscsi_release_resources(adapter); -out_free_host: - scsi_host_put(host); -out_disable_device: - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); - - return error; -} - -static void __pvscsi_shutdown(struct pvscsi_adapter *adapter) -{ - pvscsi_mask_intr(adapter); - - if (adapter->workqueue) - flush_workqueue(adapter->workqueue); - - pvscsi_shutdown_intr(adapter); - - pvscsi_process_request_ring(adapter); - pvscsi_process_completion_ring(adapter); - ll_adapter_reset(adapter); -} - -static void pvscsi_shutdown(struct pci_dev *dev) -{ - struct Scsi_Host *host = pci_get_drvdata(dev); - struct pvscsi_adapter *adapter = shost_priv(host); - - __pvscsi_shutdown(adapter); -} - -static void pvscsi_remove(struct pci_dev *pdev) -{ - struct Scsi_Host *host = pci_get_drvdata(pdev); - struct pvscsi_adapter *adapter = shost_priv(host); - - scsi_remove_host(host); - - __pvscsi_shutdown(adapter); - pvscsi_release_resources(adapter); - - scsi_host_put(host); - - pci_set_drvdata(pdev, NULL); - pci_disable_device(pdev); -} - -static struct pci_driver pvscsi_pci_driver = { - .name = "vmw_pvscsi", - .id_table = pvscsi_pci_tbl, - .probe = pvscsi_probe, - .remove = __devexit_p(pvscsi_remove), - .shutdown = pvscsi_shutdown, -}; - -static int __init pvscsi_init(void) -{ - pr_info("%s - version %s\n", - PVSCSI_LINUX_DRIVER_DESC, PVSCSI_DRIVER_VERSION_STRING); - return pci_register_driver(&pvscsi_pci_driver); -} - -static void __exit pvscsi_exit(void) -{ - pci_unregister_driver(&pvscsi_pci_driver); -} - -module_init(pvscsi_init); -module_exit(pvscsi_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.h b/ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.h deleted file mode 100644 index 3546e866..00000000 --- a/ANDROID_3.4.5/drivers/scsi/vmw_pvscsi.h +++ /dev/null @@ -1,458 +0,0 @@ -/* - * VMware PVSCSI header file - * - * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; version 2 of the License and no later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained by: Arvind Kumar - * - */ - -#ifndef _VMW_PVSCSI_H_ -#define _VMW_PVSCSI_H_ - -#include - -#define PVSCSI_DRIVER_VERSION_STRING "1.0.2.0-k" - -#define PVSCSI_MAX_NUM_SG_ENTRIES_PER_SEGMENT 128 - -#define MASK(n) ((1 << (n)) - 1) /* make an n-bit mask */ - -#define PCI_VENDOR_ID_VMWARE 0x15AD -#define PCI_DEVICE_ID_VMWARE_PVSCSI 0x07C0 - -/* - * host adapter status/error codes - */ -enum HostBusAdapterStatus { - BTSTAT_SUCCESS = 0x00, /* CCB complete normally with no errors */ - BTSTAT_LINKED_COMMAND_COMPLETED = 0x0a, - BTSTAT_LINKED_COMMAND_COMPLETED_WITH_FLAG = 0x0b, - BTSTAT_DATA_UNDERRUN = 0x0c, - BTSTAT_SELTIMEO = 0x11, /* SCSI selection timeout */ - BTSTAT_DATARUN = 0x12, /* data overrun/underrun */ - BTSTAT_BUSFREE = 0x13, /* unexpected bus free */ - BTSTAT_INVPHASE = 0x14, /* invalid bus phase or sequence - * requested by target */ - BTSTAT_LUNMISMATCH = 0x17, /* linked CCB has different LUN from - * first CCB */ - BTSTAT_INVPARAM = 0x1a, /* invalid parameter in CCB or segment - * list */ - BTSTAT_SENSFAILED = 0x1b, /* auto request sense failed */ - BTSTAT_TAGREJECT = 0x1c, /* SCSI II tagged queueing message - * rejected by target */ - BTSTAT_BADMSG = 0x1d, /* unsupported message received by the - * host adapter */ - BTSTAT_HAHARDWARE = 0x20, /* host adapter hardware failed */ - BTSTAT_NORESPONSE = 0x21, /* target did not respond to SCSI ATN, - * sent a SCSI RST */ - BTSTAT_SENTRST = 0x22, /* host adapter asserted a SCSI RST */ - BTSTAT_RECVRST = 0x23, /* other SCSI devices asserted a SCSI - * RST */ - BTSTAT_DISCONNECT = 0x24, /* target device reconnected improperly - * (w/o tag) */ - BTSTAT_BUSRESET = 0x25, /* host adapter issued BUS device reset */ - BTSTAT_ABORTQUEUE = 0x26, /* abort queue generated */ - BTSTAT_HASOFTWARE = 0x27, /* host adapter software error */ - BTSTAT_HATIMEOUT = 0x30, /* host adapter hardware timeout error */ - BTSTAT_SCSIPARITY = 0x34, /* SCSI parity error detected */ -}; - -/* - * SCSI device status values. - */ -enum ScsiDeviceStatus { - SDSTAT_GOOD = 0x00, /* No errors. */ - SDSTAT_CHECK = 0x02, /* Check condition. */ -}; - -/* - * Register offsets. - * - * These registers are accessible both via i/o space and mm i/o. - */ - -enum PVSCSIRegOffset { - PVSCSI_REG_OFFSET_COMMAND = 0x0, - PVSCSI_REG_OFFSET_COMMAND_DATA = 0x4, - PVSCSI_REG_OFFSET_COMMAND_STATUS = 0x8, - PVSCSI_REG_OFFSET_LAST_STS_0 = 0x100, - PVSCSI_REG_OFFSET_LAST_STS_1 = 0x104, - PVSCSI_REG_OFFSET_LAST_STS_2 = 0x108, - PVSCSI_REG_OFFSET_LAST_STS_3 = 0x10c, - PVSCSI_REG_OFFSET_INTR_STATUS = 0x100c, - PVSCSI_REG_OFFSET_INTR_MASK = 0x2010, - PVSCSI_REG_OFFSET_KICK_NON_RW_IO = 0x3014, - PVSCSI_REG_OFFSET_DEBUG = 0x3018, - PVSCSI_REG_OFFSET_KICK_RW_IO = 0x4018, -}; - -/* - * Virtual h/w commands. - */ - -enum PVSCSICommands { - PVSCSI_CMD_FIRST = 0, /* has to be first */ - - PVSCSI_CMD_ADAPTER_RESET = 1, - PVSCSI_CMD_ISSUE_SCSI = 2, - PVSCSI_CMD_SETUP_RINGS = 3, - PVSCSI_CMD_RESET_BUS = 4, - PVSCSI_CMD_RESET_DEVICE = 5, - PVSCSI_CMD_ABORT_CMD = 6, - PVSCSI_CMD_CONFIG = 7, - PVSCSI_CMD_SETUP_MSG_RING = 8, - PVSCSI_CMD_DEVICE_UNPLUG = 9, - - PVSCSI_CMD_LAST = 10 /* has to be last */ -}; - -/* - * Command descriptor for PVSCSI_CMD_RESET_DEVICE -- - */ - -struct PVSCSICmdDescResetDevice { - u32 target; - u8 lun[8]; -} __packed; - -/* - * Command descriptor for PVSCSI_CMD_CONFIG -- - */ - -struct PVSCSICmdDescConfigCmd { - u64 cmpAddr; - u64 configPageAddress; - u32 configPageNum; - u32 _pad; -} __packed; - -enum PVSCSIConfigPageType { - PVSCSI_CONFIG_PAGE_CONTROLLER = 0x1958, - PVSCSI_CONFIG_PAGE_PHY = 0x1959, - PVSCSI_CONFIG_PAGE_DEVICE = 0x195a, -}; - -enum PVSCSIConfigPageAddressType { - PVSCSI_CONFIG_CONTROLLER_ADDRESS = 0x2120, - PVSCSI_CONFIG_BUSTARGET_ADDRESS = 0x2121, - PVSCSI_CONFIG_PHY_ADDRESS = 0x2122, -}; - -/* - * Command descriptor for PVSCSI_CMD_ABORT_CMD -- - * - * - currently does not support specifying the LUN. - * - _pad should be 0. - */ - -struct PVSCSICmdDescAbortCmd { - u64 context; - u32 target; - u32 _pad; -} __packed; - -/* - * Command descriptor for PVSCSI_CMD_SETUP_RINGS -- - * - * Notes: - * - reqRingNumPages and cmpRingNumPages need to be power of two. - * - reqRingNumPages and cmpRingNumPages need to be different from 0, - * - reqRingNumPages and cmpRingNumPages need to be inferior to - * PVSCSI_SETUP_RINGS_MAX_NUM_PAGES. - */ - -#define PVSCSI_SETUP_RINGS_MAX_NUM_PAGES 32 -struct PVSCSICmdDescSetupRings { - u32 reqRingNumPages; - u32 cmpRingNumPages; - u64 ringsStatePPN; - u64 reqRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES]; - u64 cmpRingPPNs[PVSCSI_SETUP_RINGS_MAX_NUM_PAGES]; -} __packed; - -/* - * Command descriptor for PVSCSI_CMD_SETUP_MSG_RING -- - * - * Notes: - * - this command was not supported in the initial revision of the h/w - * interface. Before using it, you need to check that it is supported by - * writing PVSCSI_CMD_SETUP_MSG_RING to the 'command' register, then - * immediately after read the 'command status' register: - * * a value of -1 means that the cmd is NOT supported, - * * a value != -1 means that the cmd IS supported. - * If it's supported the 'command status' register should return: - * sizeof(PVSCSICmdDescSetupMsgRing) / sizeof(u32). - * - this command should be issued _after_ the usual SETUP_RINGS so that the - * RingsState page is already setup. If not, the command is a nop. - * - numPages needs to be a power of two, - * - numPages needs to be different from 0, - * - _pad should be zero. - */ - -#define PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES 16 - -struct PVSCSICmdDescSetupMsgRing { - u32 numPages; - u32 _pad; - u64 ringPPNs[PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES]; -} __packed; - -enum PVSCSIMsgType { - PVSCSI_MSG_DEV_ADDED = 0, - PVSCSI_MSG_DEV_REMOVED = 1, - PVSCSI_MSG_LAST = 2, -}; - -/* - * Msg descriptor. - * - * sizeof(struct PVSCSIRingMsgDesc) == 128. - * - * - type is of type enum PVSCSIMsgType. - * - the content of args depend on the type of event being delivered. - */ - -struct PVSCSIRingMsgDesc { - u32 type; - u32 args[31]; -} __packed; - -struct PVSCSIMsgDescDevStatusChanged { - u32 type; /* PVSCSI_MSG_DEV _ADDED / _REMOVED */ - u32 bus; - u32 target; - u8 lun[8]; - u32 pad[27]; -} __packed; - -/* - * Rings state. - * - * - the fields: - * . msgProdIdx, - * . msgConsIdx, - * . msgNumEntriesLog2, - * .. are only used once the SETUP_MSG_RING cmd has been issued. - * - '_pad' helps to ensure that the msg related fields are on their own - * cache-line. - */ - -struct PVSCSIRingsState { - u32 reqProdIdx; - u32 reqConsIdx; - u32 reqNumEntriesLog2; - - u32 cmpProdIdx; - u32 cmpConsIdx; - u32 cmpNumEntriesLog2; - - u8 _pad[104]; - - u32 msgProdIdx; - u32 msgConsIdx; - u32 msgNumEntriesLog2; -} __packed; - -/* - * Request descriptor. - * - * sizeof(RingReqDesc) = 128 - * - * - context: is a unique identifier of a command. It could normally be any - * 64bit value, however we currently store it in the serialNumber variable - * of struct SCSI_Command, so we have the following restrictions due to the - * way this field is handled in the vmkernel storage stack: - * * this value can't be 0, - * * the upper 32bit need to be 0 since serialNumber is as a u32. - * Currently tracked as PR 292060. - * - dataLen: contains the total number of bytes that need to be transferred. - * - dataAddr: - * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is set: dataAddr is the PA of the first - * s/g table segment, each s/g segment is entirely contained on a single - * page of physical memory, - * * if PVSCSI_FLAG_CMD_WITH_SG_LIST is NOT set, then dataAddr is the PA of - * the buffer used for the DMA transfer, - * - flags: - * * PVSCSI_FLAG_CMD_WITH_SG_LIST: see dataAddr above, - * * PVSCSI_FLAG_CMD_DIR_NONE: no DMA involved, - * * PVSCSI_FLAG_CMD_DIR_TOHOST: transfer from device to main memory, - * * PVSCSI_FLAG_CMD_DIR_TODEVICE: transfer from main memory to device, - * * PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB: reserved to handle CDBs larger than - * 16bytes. To be specified. - * - vcpuHint: vcpuId of the processor that will be most likely waiting for the - * completion of the i/o. For guest OSes that use lowest priority message - * delivery mode (such as windows), we use this "hint" to deliver the - * completion action to the proper vcpu. For now, we can use the vcpuId of - * the processor that initiated the i/o as a likely candidate for the vcpu - * that will be waiting for the completion.. - * - bus should be 0: we currently only support bus 0 for now. - * - unused should be zero'd. - */ - -#define PVSCSI_FLAG_CMD_WITH_SG_LIST (1 << 0) -#define PVSCSI_FLAG_CMD_OUT_OF_BAND_CDB (1 << 1) -#define PVSCSI_FLAG_CMD_DIR_NONE (1 << 2) -#define PVSCSI_FLAG_CMD_DIR_TOHOST (1 << 3) -#define PVSCSI_FLAG_CMD_DIR_TODEVICE (1 << 4) - -struct PVSCSIRingReqDesc { - u64 context; - u64 dataAddr; - u64 dataLen; - u64 senseAddr; - u32 senseLen; - u32 flags; - u8 cdb[16]; - u8 cdbLen; - u8 lun[8]; - u8 tag; - u8 bus; - u8 target; - u8 vcpuHint; - u8 unused[59]; -} __packed; - -/* - * Scatter-gather list management. - * - * As described above, when PVSCSI_FLAG_CMD_WITH_SG_LIST is set in the - * RingReqDesc.flags, then RingReqDesc.dataAddr is the PA of the first s/g - * table segment. - * - * - each segment of the s/g table contain a succession of struct - * PVSCSISGElement. - * - each segment is entirely contained on a single physical page of memory. - * - a "chain" s/g element has the flag PVSCSI_SGE_FLAG_CHAIN_ELEMENT set in - * PVSCSISGElement.flags and in this case: - * * addr is the PA of the next s/g segment, - * * length is undefined, assumed to be 0. - */ - -struct PVSCSISGElement { - u64 addr; - u32 length; - u32 flags; -} __packed; - -/* - * Completion descriptor. - * - * sizeof(RingCmpDesc) = 32 - * - * - context: identifier of the command. The same thing that was specified - * under "context" as part of struct RingReqDesc at initiation time, - * - dataLen: number of bytes transferred for the actual i/o operation, - * - senseLen: number of bytes written into the sense buffer, - * - hostStatus: adapter status, - * - scsiStatus: device status, - * - _pad should be zero. - */ - -struct PVSCSIRingCmpDesc { - u64 context; - u64 dataLen; - u32 senseLen; - u16 hostStatus; - u16 scsiStatus; - u32 _pad[2]; -} __packed; - -struct PVSCSIConfigPageHeader { - u32 pageNum; - u16 numDwords; - u16 hostStatus; - u16 scsiStatus; - u16 reserved[3]; -} __packed; - -struct PVSCSIConfigPageController { - struct PVSCSIConfigPageHeader header; - u64 nodeWWN; /* Device name as defined in the SAS spec. */ - u16 manufacturer[64]; - u16 serialNumber[64]; - u16 opromVersion[32]; - u16 hwVersion[32]; - u16 firmwareVersion[32]; - u32 numPhys; - u8 useConsecutivePhyWWNs; - u8 reserved[3]; -} __packed; - -/* - * Interrupt status / IRQ bits. - */ - -#define PVSCSI_INTR_CMPL_0 (1 << 0) -#define PVSCSI_INTR_CMPL_1 (1 << 1) -#define PVSCSI_INTR_CMPL_MASK MASK(2) - -#define PVSCSI_INTR_MSG_0 (1 << 2) -#define PVSCSI_INTR_MSG_1 (1 << 3) -#define PVSCSI_INTR_MSG_MASK (MASK(2) << 2) - -#define PVSCSI_INTR_ALL_SUPPORTED MASK(4) - -/* - * Number of MSI-X vectors supported. - */ -#define PVSCSI_MAX_INTRS 24 - -/* - * Enumeration of supported MSI-X vectors - */ -#define PVSCSI_VECTOR_COMPLETION 0 - -/* - * Misc constants for the rings. - */ - -#define PVSCSI_MAX_NUM_PAGES_REQ_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES -#define PVSCSI_MAX_NUM_PAGES_CMP_RING PVSCSI_SETUP_RINGS_MAX_NUM_PAGES -#define PVSCSI_MAX_NUM_PAGES_MSG_RING PVSCSI_SETUP_MSG_RING_MAX_NUM_PAGES - -#define PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE \ - (PAGE_SIZE / sizeof(struct PVSCSIRingReqDesc)) - -#define PVSCSI_MAX_REQ_QUEUE_DEPTH \ - (PVSCSI_MAX_NUM_PAGES_REQ_RING * PVSCSI_MAX_NUM_REQ_ENTRIES_PER_PAGE) - -#define PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES 1 -#define PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES 1 -#define PVSCSI_MEM_SPACE_MISC_NUM_PAGES 2 -#define PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES 2 -#define PVSCSI_MEM_SPACE_MSIX_NUM_PAGES 2 - -enum PVSCSIMemSpace { - PVSCSI_MEM_SPACE_COMMAND_PAGE = 0, - PVSCSI_MEM_SPACE_INTR_STATUS_PAGE = 1, - PVSCSI_MEM_SPACE_MISC_PAGE = 2, - PVSCSI_MEM_SPACE_KICK_IO_PAGE = 4, - PVSCSI_MEM_SPACE_MSIX_TABLE_PAGE = 6, - PVSCSI_MEM_SPACE_MSIX_PBA_PAGE = 7, -}; - -#define PVSCSI_MEM_SPACE_NUM_PAGES \ - (PVSCSI_MEM_SPACE_COMMAND_NUM_PAGES + \ - PVSCSI_MEM_SPACE_INTR_STATUS_NUM_PAGES + \ - PVSCSI_MEM_SPACE_MISC_NUM_PAGES + \ - PVSCSI_MEM_SPACE_KICK_IO_NUM_PAGES + \ - PVSCSI_MEM_SPACE_MSIX_NUM_PAGES) - -#define PVSCSI_MEM_SPACE_SIZE (PVSCSI_MEM_SPACE_NUM_PAGES * PAGE_SIZE) - -#endif /* _VMW_PVSCSI_H_ */ diff --git a/ANDROID_3.4.5/drivers/scsi/wd33c93.c b/ANDROID_3.4.5/drivers/scsi/wd33c93.c deleted file mode 100644 index c0ee4ea2..00000000 --- a/ANDROID_3.4.5/drivers/scsi/wd33c93.c +++ /dev/null @@ -1,2232 +0,0 @@ -/* - * Copyright (c) 1996 John Shifflett, GeoLog Consulting - * john@geolog.com - * jshiffle@netcom.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -/* - * Drew Eckhardt's excellent 'Generic NCR5380' sources from Linux-PC - * provided much of the inspiration and some of the code for this - * driver. Everything I know about Amiga DMA was gleaned from careful - * reading of Hamish Mcdonald's original wd33c93 driver; in fact, I - * borrowed shamelessly from all over that source. Thanks Hamish! - * - * _This_ driver is (I feel) an improvement over the old one in - * several respects: - * - * - Target Disconnection/Reconnection is now supported. Any - * system with more than one device active on the SCSI bus - * will benefit from this. The driver defaults to what I - * call 'adaptive disconnect' - meaning that each command - * is evaluated individually as to whether or not it should - * be run with the option to disconnect/reselect (if the - * device chooses), or as a "SCSI-bus-hog". - * - * - Synchronous data transfers are now supported. Because of - * a few devices that choke after telling the driver that - * they can do sync transfers, we don't automatically use - * this faster protocol - it can be enabled via the command- - * line on a device-by-device basis. - * - * - Runtime operating parameters can now be specified through - * the 'amiboot' or the 'insmod' command line. For amiboot do: - * "amiboot [usual stuff] wd33c93=blah,blah,blah" - * The defaults should be good for most people. See the comment - * for 'setup_strings' below for more details. - * - * - The old driver relied exclusively on what the Western Digital - * docs call "Combination Level 2 Commands", which are a great - * idea in that the CPU is relieved of a lot of interrupt - * overhead. However, by accepting a certain (user-settable) - * amount of additional interrupts, this driver achieves - * better control over the SCSI bus, and data transfers are - * almost as fast while being much easier to define, track, - * and debug. - * - * - * TODO: - * more speed. linked commands. - * - * - * People with bug reports, wish-lists, complaints, comments, - * or improvements are asked to pah-leeez email me (John Shifflett) - * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get - * this thing into as good a shape as possible, and I'm positive - * there are lots of lurking bugs and "Stupid Places". - * - * Updates: - * - * Added support for pre -A chips, which don't have advanced features - * and will generate CSR_RESEL rather than CSR_RESEL_AM. - * Richard Hirst August 2000 - * - * Added support for Burst Mode DMA and Fast SCSI. Enabled the use of - * default_sx_per for asynchronous data transfers. Added adjustment - * of transfer periods in sx_table to the actual input-clock. - * peter fuerst February 2007 - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "wd33c93.h" - -#define optimum_sx_per(hostdata) (hostdata)->sx_table[1].period_ns - - -#define WD33C93_VERSION "1.26++" -#define WD33C93_DATE "10/Feb/2007" - -MODULE_AUTHOR("John Shifflett"); -MODULE_DESCRIPTION("Generic WD33C93 SCSI driver"); -MODULE_LICENSE("GPL"); - -/* - * 'setup_strings' is a single string used to pass operating parameters and - * settings from the kernel/module command-line to the driver. 'setup_args[]' - * is an array of strings that define the compile-time default values for - * these settings. If Linux boots with an amiboot or insmod command-line, - * those settings are combined with 'setup_args[]'. Note that amiboot - * command-lines are prefixed with "wd33c93=" while insmod uses a - * "setup_strings=" prefix. The driver recognizes the following keywords - * (lower case required) and arguments: - * - * - nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with - * the 7 possible SCSI devices. Set a bit to negotiate for - * asynchronous transfers on that device. To maintain - * backwards compatibility, a command-line such as - * "wd33c93=255" will be automatically translated to - * "wd33c93=nosync:0xff". - * - nodma:x -x = 1 to disable DMA, x = 0 to enable it. Argument is - * optional - if not present, same as "nodma:1". - * - period:ns -ns is the minimum # of nanoseconds in a SCSI data transfer - * period. Default is 500; acceptable values are 250 - 1000. - * - disconnect:x -x = 0 to never allow disconnects, 2 to always allow them. - * x = 1 does 'adaptive' disconnects, which is the default - * and generally the best choice. - * - debug:x -If 'DEBUGGING_ON' is defined, x is a bit mask that causes - * various types of debug output to printed - see the DB_xxx - * defines in wd33c93.h - * - clock:x -x = clock input in MHz for WD33c93 chip. Normal values - * would be from 8 through 20. Default is 8. - * - burst:x -x = 1 to use Burst Mode (or Demand-Mode) DMA, x = 0 to use - * Single Byte DMA, which is the default. Argument is - * optional - if not present, same as "burst:1". - * - fast:x -x = 1 to enable Fast SCSI, which is only effective with - * input-clock divisor 4 (WD33C93_FS_16_20), x = 0 to disable - * it, which is the default. Argument is optional - if not - * present, same as "fast:1". - * - next -No argument. Used to separate blocks of keywords when - * there's more than one host adapter in the system. - * - * Syntax Notes: - * - Numeric arguments can be decimal or the '0x' form of hex notation. There - * _must_ be a colon between a keyword and its numeric argument, with no - * spaces. - * - Keywords are separated by commas, no spaces, in the standard kernel - * command-line manner. - * - A keyword in the 'nth' comma-separated command-line member will overwrite - * the 'nth' element of setup_args[]. A blank command-line member (in - * other words, a comma with no preceding keyword) will _not_ overwrite - * the corresponding setup_args[] element. - * - If a keyword is used more than once, the first one applies to the first - * SCSI host found, the second to the second card, etc, unless the 'next' - * keyword is used to change the order. - * - * Some amiboot examples (for insmod, use 'setup_strings' instead of 'wd33c93'): - * - wd33c93=nosync:255 - * - wd33c93=nodma - * - wd33c93=nodma:1 - * - wd33c93=disconnect:2,nosync:0x08,period:250 - * - wd33c93=debug:0x1c - */ - -/* Normally, no defaults are specified */ -static char *setup_args[] = { "", "", "", "", "", "", "", "", "", "" }; - -static char *setup_strings; -module_param(setup_strings, charp, 0); - -static void wd33c93_execute(struct Scsi_Host *instance); - -#ifdef CONFIG_WD33C93_PIO -static inline uchar -read_wd33c93(const wd33c93_regs regs, uchar reg_num) -{ - uchar data; - - outb(reg_num, regs.SASR); - data = inb(regs.SCMD); - return data; -} - -static inline unsigned long -read_wd33c93_count(const wd33c93_regs regs) -{ - unsigned long value; - - outb(WD_TRANSFER_COUNT_MSB, regs.SASR); - value = inb(regs.SCMD) << 16; - value |= inb(regs.SCMD) << 8; - value |= inb(regs.SCMD); - return value; -} - -static inline uchar -read_aux_stat(const wd33c93_regs regs) -{ - return inb(regs.SASR); -} - -static inline void -write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value) -{ - outb(reg_num, regs.SASR); - outb(value, regs.SCMD); -} - -static inline void -write_wd33c93_count(const wd33c93_regs regs, unsigned long value) -{ - outb(WD_TRANSFER_COUNT_MSB, regs.SASR); - outb((value >> 16) & 0xff, regs.SCMD); - outb((value >> 8) & 0xff, regs.SCMD); - outb( value & 0xff, regs.SCMD); -} - -#define write_wd33c93_cmd(regs, cmd) \ - write_wd33c93((regs), WD_COMMAND, (cmd)) - -static inline void -write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[]) -{ - int i; - - outb(WD_CDB_1, regs.SASR); - for (i=0; i> 16; - *regs.SCMD = value >> 8; - *regs.SCMD = value; - mb(); -} - -static inline void -write_wd33c93_cmd(const wd33c93_regs regs, uchar cmd) -{ - *regs.SASR = WD_COMMAND; - mb(); - *regs.SCMD = cmd; - mb(); -} - -static inline void -write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[]) -{ - int i; - - *regs.SASR = WD_CDB_1; - for (i = 0; i < len; i++) - *regs.SCMD = cmnd[i]; -} -#endif /* CONFIG_WD33C93_PIO */ - -static inline uchar -read_1_byte(const wd33c93_regs regs) -{ - uchar asr; - uchar x = 0; - - write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO | 0x80); - do { - asr = read_aux_stat(regs); - if (asr & ASR_DBR) - x = read_wd33c93(regs, WD_DATA); - } while (!(asr & ASR_INT)); - return x; -} - -static int -round_period(unsigned int period, const struct sx_period *sx_table) -{ - int x; - - for (x = 1; sx_table[x].period_ns; x++) { - if ((period <= sx_table[x - 0].period_ns) && - (period > sx_table[x - 1].period_ns)) { - return x; - } - } - return 7; -} - -/* - * Calculate Synchronous Transfer Register value from SDTR code. - */ -static uchar -calc_sync_xfer(unsigned int period, unsigned int offset, unsigned int fast, - const struct sx_period *sx_table) -{ - /* When doing Fast SCSI synchronous data transfers, the corresponding - * value in 'sx_table' is two times the actually used transfer period. - */ - uchar result; - - if (offset && fast) { - fast = STR_FSS; - period *= 2; - } else { - fast = 0; - } - period *= 4; /* convert SDTR code to ns */ - result = sx_table[round_period(period,sx_table)].reg_value; - result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF; - result |= fast; - return result; -} - -/* - * Calculate SDTR code bytes [3],[4] from period and offset. - */ -static inline void -calc_sync_msg(unsigned int period, unsigned int offset, unsigned int fast, - uchar msg[2]) -{ - /* 'period' is a "normal"-mode value, like the ones in 'sx_table'. The - * actually used transfer period for Fast SCSI synchronous data - * transfers is half that value. - */ - period /= 4; - if (offset && fast) - period /= 2; - msg[0] = period; - msg[1] = offset; -} - -static int -wd33c93_queuecommand_lck(struct scsi_cmnd *cmd, - void (*done)(struct scsi_cmnd *)) -{ - struct WD33C93_hostdata *hostdata; - struct scsi_cmnd *tmp; - - hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata; - - DB(DB_QUEUE_COMMAND, - printk("Q-%d-%02x( ", cmd->device->id, cmd->cmnd[0])) - -/* Set up a few fields in the scsi_cmnd structure for our own use: - * - host_scribble is the pointer to the next cmd in the input queue - * - scsi_done points to the routine we call when a cmd is finished - * - result is what you'd expect - */ - cmd->host_scribble = NULL; - cmd->scsi_done = done; - cmd->result = 0; - -/* We use the Scsi_Pointer structure that's included with each command - * as a scratchpad (as it's intended to be used!). The handy thing about - * the SCp.xxx fields is that they're always associated with a given - * cmd, and are preserved across disconnect-reselect. This means we - * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages - * if we keep all the critical pointers and counters in SCp: - * - SCp.ptr is the pointer into the RAM buffer - * - SCp.this_residual is the size of that buffer - * - SCp.buffer points to the current scatter-gather buffer - * - SCp.buffers_residual tells us how many S.G. buffers there are - * - SCp.have_data_in is not used - * - SCp.sent_command is not used - * - SCp.phase records this command's SRCID_ER bit setting - */ - - if (scsi_bufflen(cmd)) { - cmd->SCp.buffer = scsi_sglist(cmd); - cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - cmd->SCp.this_residual = cmd->SCp.buffer->length; - } else { - cmd->SCp.buffer = NULL; - cmd->SCp.buffers_residual = 0; - cmd->SCp.ptr = NULL; - cmd->SCp.this_residual = 0; - } - -/* WD docs state that at the conclusion of a "LEVEL2" command, the - * status byte can be retrieved from the LUN register. Apparently, - * this is the case only for *uninterrupted* LEVEL2 commands! If - * there are any unexpected phases entered, even if they are 100% - * legal (different devices may choose to do things differently), - * the LEVEL2 command sequence is exited. This often occurs prior - * to receiving the status byte, in which case the driver does a - * status phase interrupt and gets the status byte on its own. - * While such a command can then be "resumed" (ie restarted to - * finish up as a LEVEL2 command), the LUN register will NOT be - * a valid status byte at the command's conclusion, and we must - * use the byte obtained during the earlier interrupt. Here, we - * preset SCp.Status to an illegal value (0xff) so that when - * this command finally completes, we can tell where the actual - * status byte is stored. - */ - - cmd->SCp.Status = ILLEGAL_STATUS_BYTE; - - /* - * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE - * commands are added to the head of the queue so that the desired - * sense data is not lost before REQUEST_SENSE executes. - */ - - spin_lock_irq(&hostdata->lock); - - if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) { - cmd->host_scribble = (uchar *) hostdata->input_Q; - hostdata->input_Q = cmd; - } else { /* find the end of the queue */ - for (tmp = (struct scsi_cmnd *) hostdata->input_Q; - tmp->host_scribble; - tmp = (struct scsi_cmnd *) tmp->host_scribble) ; - tmp->host_scribble = (uchar *) cmd; - } - -/* We know that there's at least one command in 'input_Q' now. - * Go see if any of them are runnable! - */ - - wd33c93_execute(cmd->device->host); - - DB(DB_QUEUE_COMMAND, printk(")Q ")) - - spin_unlock_irq(&hostdata->lock); - return 0; -} - -DEF_SCSI_QCMD(wd33c93_queuecommand) - -/* - * This routine attempts to start a scsi command. If the host_card is - * already connected, we give up immediately. Otherwise, look through - * the input_Q, using the first command we find that's intended - * for a currently non-busy target/lun. - * - * wd33c93_execute() is always called with interrupts disabled or from - * the wd33c93_intr itself, which means that a wd33c93 interrupt - * cannot occur while we are in here. - */ -static void -wd33c93_execute(struct Scsi_Host *instance) -{ - struct WD33C93_hostdata *hostdata = - (struct WD33C93_hostdata *) instance->hostdata; - const wd33c93_regs regs = hostdata->regs; - struct scsi_cmnd *cmd, *prev; - - DB(DB_EXECUTE, printk("EX(")) - if (hostdata->selecting || hostdata->connected) { - DB(DB_EXECUTE, printk(")EX-0 ")) - return; - } - - /* - * Search through the input_Q for a command destined - * for an idle target/lun. - */ - - cmd = (struct scsi_cmnd *) hostdata->input_Q; - prev = NULL; - while (cmd) { - if (!(hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))) - break; - prev = cmd; - cmd = (struct scsi_cmnd *) cmd->host_scribble; - } - - /* quit if queue empty or all possible targets are busy */ - - if (!cmd) { - DB(DB_EXECUTE, printk(")EX-1 ")) - return; - } - - /* remove command from queue */ - - if (prev) - prev->host_scribble = cmd->host_scribble; - else - hostdata->input_Q = (struct scsi_cmnd *) cmd->host_scribble; - -#ifdef PROC_STATISTICS - hostdata->cmd_cnt[cmd->device->id]++; -#endif - - /* - * Start the selection process - */ - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id); - else - write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD); - -/* Now we need to figure out whether or not this command is a good - * candidate for disconnect/reselect. We guess to the best of our - * ability, based on a set of hierarchical rules. When several - * devices are operating simultaneously, disconnects are usually - * an advantage. In a single device system, or if only 1 device - * is being accessed, transfers usually go faster if disconnects - * are not allowed: - * - * + Commands should NEVER disconnect if hostdata->disconnect = - * DIS_NEVER (this holds for tape drives also), and ALWAYS - * disconnect if hostdata->disconnect = DIS_ALWAYS. - * + Tape drive commands should always be allowed to disconnect. - * + Disconnect should be allowed if disconnected_Q isn't empty. - * + Commands should NOT disconnect if input_Q is empty. - * + Disconnect should be allowed if there are commands in input_Q - * for a different target/lun. In this case, the other commands - * should be made disconnect-able, if not already. - * - * I know, I know - this code would flunk me out of any - * "C Programming 101" class ever offered. But it's easy - * to change around and experiment with for now. - */ - - cmd->SCp.phase = 0; /* assume no disconnect */ - if (hostdata->disconnect == DIS_NEVER) - goto no; - if (hostdata->disconnect == DIS_ALWAYS) - goto yes; - if (cmd->device->type == 1) /* tape drive? */ - goto yes; - if (hostdata->disconnected_Q) /* other commands disconnected? */ - goto yes; - if (!(hostdata->input_Q)) /* input_Q empty? */ - goto no; - for (prev = (struct scsi_cmnd *) hostdata->input_Q; prev; - prev = (struct scsi_cmnd *) prev->host_scribble) { - if ((prev->device->id != cmd->device->id) || - (prev->device->lun != cmd->device->lun)) { - for (prev = (struct scsi_cmnd *) hostdata->input_Q; prev; - prev = (struct scsi_cmnd *) prev->host_scribble) - prev->SCp.phase = 1; - goto yes; - } - } - - goto no; - - yes: - cmd->SCp.phase = 1; - -#ifdef PROC_STATISTICS - hostdata->disc_allowed_cnt[cmd->device->id]++; -#endif - - no: - - write_wd33c93(regs, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0)); - - write_wd33c93(regs, WD_TARGET_LUN, cmd->device->lun); - write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, - hostdata->sync_xfer[cmd->device->id]); - hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun); - - if ((hostdata->level2 == L2_NONE) || - (hostdata->sync_stat[cmd->device->id] == SS_UNSET)) { - - /* - * Do a 'Select-With-ATN' command. This will end with - * one of the following interrupts: - * CSR_RESEL_AM: failure - can try again later. - * CSR_TIMEOUT: failure - give up. - * CSR_SELECT: success - proceed. - */ - - hostdata->selecting = cmd; - -/* Every target has its own synchronous transfer setting, kept in the - * sync_xfer array, and a corresponding status byte in sync_stat[]. - * Each target's sync_stat[] entry is initialized to SX_UNSET, and its - * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET - * means that the parameters are undetermined as yet, and that we - * need to send an SDTR message to this device after selection is - * complete: We set SS_FIRST to tell the interrupt routine to do so. - * If we've been asked not to try synchronous transfers on this - * target (and _all_ luns within it), we'll still send the SDTR message - * later, but at that time we'll negotiate for async by specifying a - * sync fifo depth of 0. - */ - if (hostdata->sync_stat[cmd->device->id] == SS_UNSET) - hostdata->sync_stat[cmd->device->id] = SS_FIRST; - hostdata->state = S_SELECTING; - write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */ - write_wd33c93_cmd(regs, WD_CMD_SEL_ATN); - } else { - - /* - * Do a 'Select-With-ATN-Xfer' command. This will end with - * one of the following interrupts: - * CSR_RESEL_AM: failure - can try again later. - * CSR_TIMEOUT: failure - give up. - * anything else: success - proceed. - */ - - hostdata->connected = cmd; - write_wd33c93(regs, WD_COMMAND_PHASE, 0); - - /* copy command_descriptor_block into WD chip - * (take advantage of auto-incrementing) - */ - - write_wd33c93_cdb(regs, cmd->cmd_len, cmd->cmnd); - - /* The wd33c93 only knows about Group 0, 1, and 5 commands when - * it's doing a 'select-and-transfer'. To be safe, we write the - * size of the CDB into the OWN_ID register for every case. This - * way there won't be problems with vendor-unique, audio, etc. - */ - - write_wd33c93(regs, WD_OWN_ID, cmd->cmd_len); - - /* When doing a non-disconnect command with DMA, we can save - * ourselves a DATA phase interrupt later by setting everything - * up ahead of time. - */ - - if ((cmd->SCp.phase == 0) && (hostdata->no_dma == 0)) { - if (hostdata->dma_setup(cmd, - (cmd->sc_data_direction == DMA_TO_DEVICE) ? - DATA_OUT_DIR : DATA_IN_DIR)) - write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */ - else { - write_wd33c93_count(regs, - cmd->SCp.this_residual); - write_wd33c93(regs, WD_CONTROL, - CTRL_IDI | CTRL_EDI | hostdata->dma_mode); - hostdata->dma = D_DMA_RUNNING; - } - } else - write_wd33c93_count(regs, 0); /* guarantee a DATA_PHASE interrupt */ - - hostdata->state = S_RUNNING_LEVEL2; - write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); - } - - /* - * Since the SCSI bus can handle only 1 connection at a time, - * we get out of here now. If the selection fails, or when - * the command disconnects, we'll come back to this routine - * to search the input_Q again... - */ - - DB(DB_EXECUTE, - printk("%s)EX-2 ", (cmd->SCp.phase) ? "d:" : "")) -} - -static void -transfer_pio(const wd33c93_regs regs, uchar * buf, int cnt, - int data_in_dir, struct WD33C93_hostdata *hostdata) -{ - uchar asr; - - DB(DB_TRANSFER, - printk("(%p,%d,%s:", buf, cnt, data_in_dir ? "in" : "out")) - - write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93_count(regs, cnt); - write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO); - if (data_in_dir) { - do { - asr = read_aux_stat(regs); - if (asr & ASR_DBR) - *buf++ = read_wd33c93(regs, WD_DATA); - } while (!(asr & ASR_INT)); - } else { - do { - asr = read_aux_stat(regs); - if (asr & ASR_DBR) - write_wd33c93(regs, WD_DATA, *buf++); - } while (!(asr & ASR_INT)); - } - - /* Note: we are returning with the interrupt UN-cleared. - * Since (presumably) an entire I/O operation has - * completed, the bus phase is probably different, and - * the interrupt routine will discover this when it - * responds to the uncleared int. - */ - -} - -static void -transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd, - int data_in_dir) -{ - struct WD33C93_hostdata *hostdata; - unsigned long length; - - hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata; - -/* Normally, you'd expect 'this_residual' to be non-zero here. - * In a series of scatter-gather transfers, however, this - * routine will usually be called with 'this_residual' equal - * to 0 and 'buffers_residual' non-zero. This means that a - * previous transfer completed, clearing 'this_residual', and - * now we need to setup the next scatter-gather buffer as the - * source or destination for THIS transfer. - */ - if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) { - ++cmd->SCp.buffer; - --cmd->SCp.buffers_residual; - cmd->SCp.this_residual = cmd->SCp.buffer->length; - cmd->SCp.ptr = sg_virt(cmd->SCp.buffer); - } - if (!cmd->SCp.this_residual) /* avoid bogus setups */ - return; - - write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, - hostdata->sync_xfer[cmd->device->id]); - -/* 'hostdata->no_dma' is TRUE if we don't even want to try DMA. - * Update 'this_residual' and 'ptr' after 'transfer_pio()' returns. - */ - - if (hostdata->no_dma || hostdata->dma_setup(cmd, data_in_dir)) { -#ifdef PROC_STATISTICS - hostdata->pio_cnt++; -#endif - transfer_pio(regs, (uchar *) cmd->SCp.ptr, - cmd->SCp.this_residual, data_in_dir, hostdata); - length = cmd->SCp.this_residual; - cmd->SCp.this_residual = read_wd33c93_count(regs); - cmd->SCp.ptr += (length - cmd->SCp.this_residual); - } - -/* We are able to do DMA (in fact, the Amiga hardware is - * already going!), so start up the wd33c93 in DMA mode. - * We set 'hostdata->dma' = D_DMA_RUNNING so that when the - * transfer completes and causes an interrupt, we're - * reminded to tell the Amiga to shut down its end. We'll - * postpone the updating of 'this_residual' and 'ptr' - * until then. - */ - - else { -#ifdef PROC_STATISTICS - hostdata->dma_cnt++; -#endif - write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | hostdata->dma_mode); - write_wd33c93_count(regs, cmd->SCp.this_residual); - - if ((hostdata->level2 >= L2_DATA) || - (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) { - write_wd33c93(regs, WD_COMMAND_PHASE, 0x45); - write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } else - write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO); - - hostdata->dma = D_DMA_RUNNING; - } -} - -void -wd33c93_intr(struct Scsi_Host *instance) -{ - struct WD33C93_hostdata *hostdata = - (struct WD33C93_hostdata *) instance->hostdata; - const wd33c93_regs regs = hostdata->regs; - struct scsi_cmnd *patch, *cmd; - uchar asr, sr, phs, id, lun, *ucp, msg; - unsigned long length, flags; - - asr = read_aux_stat(regs); - if (!(asr & ASR_INT) || (asr & ASR_BSY)) - return; - - spin_lock_irqsave(&hostdata->lock, flags); - -#ifdef PROC_STATISTICS - hostdata->int_cnt++; -#endif - - cmd = (struct scsi_cmnd *) hostdata->connected; /* assume we're connected */ - sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear the interrupt */ - phs = read_wd33c93(regs, WD_COMMAND_PHASE); - - DB(DB_INTR, printk("{%02x:%02x-", asr, sr)) - -/* After starting a DMA transfer, the next interrupt - * is guaranteed to be in response to completion of - * the transfer. Since the Amiga DMA hardware runs in - * in an open-ended fashion, it needs to be told when - * to stop; do that here if D_DMA_RUNNING is true. - * Also, we have to update 'this_residual' and 'ptr' - * based on the contents of the TRANSFER_COUNT register, - * in case the device decided to do an intermediate - * disconnect (a device may do this if it has to do a - * seek, or just to be nice and let other devices have - * some bus time during long transfers). After doing - * whatever is needed, we go on and service the WD3393 - * interrupt normally. - */ - if (hostdata->dma == D_DMA_RUNNING) { - DB(DB_TRANSFER, - printk("[%p/%d:", cmd->SCp.ptr, cmd->SCp.this_residual)) - hostdata->dma_stop(cmd->device->host, cmd, 1); - hostdata->dma = D_DMA_OFF; - length = cmd->SCp.this_residual; - cmd->SCp.this_residual = read_wd33c93_count(regs); - cmd->SCp.ptr += (length - cmd->SCp.this_residual); - DB(DB_TRANSFER, - printk("%p/%d]", cmd->SCp.ptr, cmd->SCp.this_residual)) - } - -/* Respond to the specific WD3393 interrupt - there are quite a few! */ - switch (sr) { - case CSR_TIMEOUT: - DB(DB_INTR, printk("TIMEOUT")) - - if (hostdata->state == S_RUNNING_LEVEL2) - hostdata->connected = NULL; - else { - cmd = (struct scsi_cmnd *) hostdata->selecting; /* get a valid cmd */ - hostdata->selecting = NULL; - } - - cmd->result = DID_NO_CONNECT << 16; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->state = S_UNCONNECTED; - cmd->scsi_done(cmd); - - /* From esp.c: - * There is a window of time within the scsi_done() path - * of execution where interrupts are turned back on full - * blast and left that way. During that time we could - * reconnect to a disconnected command, then we'd bomb - * out below. We could also end up executing two commands - * at _once_. ...just so you know why the restore_flags() - * is here... - */ - - spin_unlock_irqrestore(&hostdata->lock, flags); - -/* We are not connected to a target - check to see if there - * are commands waiting to be executed. - */ - - wd33c93_execute(instance); - break; - -/* Note: this interrupt should not occur in a LEVEL2 command */ - - case CSR_SELECT: - DB(DB_INTR, printk("SELECT")) - hostdata->connected = cmd = - (struct scsi_cmnd *) hostdata->selecting; - hostdata->selecting = NULL; - - /* construct an IDENTIFY message with correct disconnect bit */ - - hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun); - if (cmd->SCp.phase) - hostdata->outgoing_msg[0] |= 0x40; - - if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) { - - hostdata->sync_stat[cmd->device->id] = SS_WAITING; - -/* Tack on a 2nd message to ask about synchronous transfers. If we've - * been asked to do only asynchronous transfers on this device, we - * request a fifo depth of 0, which is equivalent to async - should - * solve the problems some people have had with GVP's Guru ROM. - */ - - hostdata->outgoing_msg[1] = EXTENDED_MESSAGE; - hostdata->outgoing_msg[2] = 3; - hostdata->outgoing_msg[3] = EXTENDED_SDTR; - if (hostdata->no_sync & (1 << cmd->device->id)) { - calc_sync_msg(hostdata->default_sx_per, 0, - 0, hostdata->outgoing_msg + 4); - } else { - calc_sync_msg(optimum_sx_per(hostdata), - OPTIMUM_SX_OFF, - hostdata->fast, - hostdata->outgoing_msg + 4); - } - hostdata->outgoing_len = 6; -#ifdef SYNC_DEBUG - ucp = hostdata->outgoing_msg + 1; - printk(" sending SDTR %02x03%02x%02x%02x ", - ucp[0], ucp[2], ucp[3], ucp[4]); -#endif - } else - hostdata->outgoing_len = 1; - - hostdata->state = S_CONNECTED; - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - - case CSR_XFER_DONE | PHS_DATA_IN: - case CSR_UNEXP | PHS_DATA_IN: - case CSR_SRV_REQ | PHS_DATA_IN: - DB(DB_INTR, - printk("IN-%d.%d", cmd->SCp.this_residual, - cmd->SCp.buffers_residual)) - transfer_bytes(regs, cmd, DATA_IN_DIR); - if (hostdata->state != S_RUNNING_LEVEL2) - hostdata->state = S_CONNECTED; - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - - case CSR_XFER_DONE | PHS_DATA_OUT: - case CSR_UNEXP | PHS_DATA_OUT: - case CSR_SRV_REQ | PHS_DATA_OUT: - DB(DB_INTR, - printk("OUT-%d.%d", cmd->SCp.this_residual, - cmd->SCp.buffers_residual)) - transfer_bytes(regs, cmd, DATA_OUT_DIR); - if (hostdata->state != S_RUNNING_LEVEL2) - hostdata->state = S_CONNECTED; - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - -/* Note: this interrupt should not occur in a LEVEL2 command */ - - case CSR_XFER_DONE | PHS_COMMAND: - case CSR_UNEXP | PHS_COMMAND: - case CSR_SRV_REQ | PHS_COMMAND: - DB(DB_INTR, printk("CMND-%02x", cmd->cmnd[0])) - transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, - hostdata); - hostdata->state = S_CONNECTED; - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - - case CSR_XFER_DONE | PHS_STATUS: - case CSR_UNEXP | PHS_STATUS: - case CSR_SRV_REQ | PHS_STATUS: - DB(DB_INTR, printk("STATUS=")) - cmd->SCp.Status = read_1_byte(regs); - DB(DB_INTR, printk("%02x", cmd->SCp.Status)) - if (hostdata->level2 >= L2_BASIC) { - sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */ - udelay(7); - hostdata->state = S_RUNNING_LEVEL2; - write_wd33c93(regs, WD_COMMAND_PHASE, 0x50); - write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); - } else { - hostdata->state = S_CONNECTED; - } - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - - case CSR_XFER_DONE | PHS_MESS_IN: - case CSR_UNEXP | PHS_MESS_IN: - case CSR_SRV_REQ | PHS_MESS_IN: - DB(DB_INTR, printk("MSG_IN=")) - - msg = read_1_byte(regs); - sr = read_wd33c93(regs, WD_SCSI_STATUS); /* clear interrupt */ - udelay(7); - - hostdata->incoming_msg[hostdata->incoming_ptr] = msg; - if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE) - msg = EXTENDED_MESSAGE; - else - hostdata->incoming_ptr = 0; - - cmd->SCp.Message = msg; - switch (msg) { - - case COMMAND_COMPLETE: - DB(DB_INTR, printk("CCMP")) - write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); - hostdata->state = S_PRE_CMP_DISC; - break; - - case SAVE_POINTERS: - DB(DB_INTR, printk("SDP")) - write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - - case RESTORE_POINTERS: - DB(DB_INTR, printk("RDP")) - if (hostdata->level2 >= L2_BASIC) { - write_wd33c93(regs, WD_COMMAND_PHASE, 0x45); - write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } else { - write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - break; - - case DISCONNECT: - DB(DB_INTR, printk("DIS")) - cmd->device->disconnect = 1; - write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); - hostdata->state = S_PRE_TMP_DISC; - break; - - case MESSAGE_REJECT: - DB(DB_INTR, printk("REJ")) -#ifdef SYNC_DEBUG - printk("-REJ-"); -#endif - if (hostdata->sync_stat[cmd->device->id] == SS_WAITING) { - hostdata->sync_stat[cmd->device->id] = SS_SET; - /* we want default_sx_per, not DEFAULT_SX_PER */ - hostdata->sync_xfer[cmd->device->id] = - calc_sync_xfer(hostdata->default_sx_per - / 4, 0, 0, hostdata->sx_table); - } - write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - - case EXTENDED_MESSAGE: - DB(DB_INTR, printk("EXT")) - - ucp = hostdata->incoming_msg; - -#ifdef SYNC_DEBUG - printk("%02x", ucp[hostdata->incoming_ptr]); -#endif - /* Is this the last byte of the extended message? */ - - if ((hostdata->incoming_ptr >= 2) && - (hostdata->incoming_ptr == (ucp[1] + 1))) { - - switch (ucp[2]) { /* what's the EXTENDED code? */ - case EXTENDED_SDTR: - /* default to default async period */ - id = calc_sync_xfer(hostdata-> - default_sx_per / 4, 0, - 0, hostdata->sx_table); - if (hostdata->sync_stat[cmd->device->id] != - SS_WAITING) { - -/* A device has sent an unsolicited SDTR message; rather than go - * through the effort of decoding it and then figuring out what - * our reply should be, we're just gonna say that we have a - * synchronous fifo depth of 0. This will result in asynchronous - * transfers - not ideal but so much easier. - * Actually, this is OK because it assures us that if we don't - * specifically ask for sync transfers, we won't do any. - */ - - write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - hostdata->outgoing_msg[0] = - EXTENDED_MESSAGE; - hostdata->outgoing_msg[1] = 3; - hostdata->outgoing_msg[2] = - EXTENDED_SDTR; - calc_sync_msg(hostdata-> - default_sx_per, 0, - 0, hostdata->outgoing_msg + 3); - hostdata->outgoing_len = 5; - } else { - if (ucp[4]) /* well, sync transfer */ - id = calc_sync_xfer(ucp[3], ucp[4], - hostdata->fast, - hostdata->sx_table); - else if (ucp[3]) /* very unlikely... */ - id = calc_sync_xfer(ucp[3], ucp[4], - 0, hostdata->sx_table); - } - hostdata->sync_xfer[cmd->device->id] = id; -#ifdef SYNC_DEBUG - printk(" sync_xfer=%02x\n", - hostdata->sync_xfer[cmd->device->id]); -#endif - hostdata->sync_stat[cmd->device->id] = - SS_SET; - write_wd33c93_cmd(regs, - WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - case EXTENDED_WDTR: - write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - printk("sending WDTR "); - hostdata->outgoing_msg[0] = - EXTENDED_MESSAGE; - hostdata->outgoing_msg[1] = 2; - hostdata->outgoing_msg[2] = - EXTENDED_WDTR; - hostdata->outgoing_msg[3] = 0; /* 8 bit transfer width */ - hostdata->outgoing_len = 4; - write_wd33c93_cmd(regs, - WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - default: - write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - printk - ("Rejecting Unknown Extended Message(%02x). ", - ucp[2]); - hostdata->outgoing_msg[0] = - MESSAGE_REJECT; - hostdata->outgoing_len = 1; - write_wd33c93_cmd(regs, - WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - break; - } - hostdata->incoming_ptr = 0; - } - - /* We need to read more MESS_IN bytes for the extended message */ - - else { - hostdata->incoming_ptr++; - write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - break; - - default: - printk("Rejecting Unknown Message(%02x) ", msg); - write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - hostdata->outgoing_msg[0] = MESSAGE_REJECT; - hostdata->outgoing_len = 1; - write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); - hostdata->state = S_CONNECTED; - } - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - -/* Note: this interrupt will occur only after a LEVEL2 command */ - - case CSR_SEL_XFER_DONE: - -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ - - write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); - if (phs == 0x60) { - DB(DB_INTR, printk("SX-DONE")) - cmd->SCp.Message = COMMAND_COMPLETE; - lun = read_wd33c93(regs, WD_TARGET_LUN); - DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun)) - hostdata->connected = NULL; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->state = S_UNCONNECTED; - if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE) - cmd->SCp.Status = lun; - if (cmd->cmnd[0] == REQUEST_SENSE - && cmd->SCp.Status != GOOD) - cmd->result = - (cmd-> - result & 0x00ffff) | (DID_ERROR << 16); - else - cmd->result = - cmd->SCp.Status | (cmd->SCp.Message << 8); - cmd->scsi_done(cmd); - -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ - spin_unlock_irqrestore(&hostdata->lock, flags); - wd33c93_execute(instance); - } else { - printk - ("%02x:%02x:%02x: Unknown SEL_XFER_DONE phase!!---", - asr, sr, phs); - spin_unlock_irqrestore(&hostdata->lock, flags); - } - break; - -/* Note: this interrupt will occur only after a LEVEL2 command */ - - case CSR_SDP: - DB(DB_INTR, printk("SDP")) - hostdata->state = S_RUNNING_LEVEL2; - write_wd33c93(regs, WD_COMMAND_PHASE, 0x41); - write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - - case CSR_XFER_DONE | PHS_MESS_OUT: - case CSR_UNEXP | PHS_MESS_OUT: - case CSR_SRV_REQ | PHS_MESS_OUT: - DB(DB_INTR, printk("MSG_OUT=")) - -/* To get here, we've probably requested MESSAGE_OUT and have - * already put the correct bytes in outgoing_msg[] and filled - * in outgoing_len. We simply send them out to the SCSI bus. - * Sometimes we get MESSAGE_OUT phase when we're not expecting - * it - like when our SDTR message is rejected by a target. Some - * targets send the REJECT before receiving all of the extended - * message, and then seem to go back to MESSAGE_OUT for a byte - * or two. Not sure why, or if I'm doing something wrong to - * cause this to happen. Regardless, it seems that sending - * NOP messages in these situations results in no harm and - * makes everyone happy. - */ - if (hostdata->outgoing_len == 0) { - hostdata->outgoing_len = 1; - hostdata->outgoing_msg[0] = NOP; - } - transfer_pio(regs, hostdata->outgoing_msg, - hostdata->outgoing_len, DATA_OUT_DIR, hostdata); - DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0])) - hostdata->outgoing_len = 0; - hostdata->state = S_CONNECTED; - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - - case CSR_UNEXP_DISC: - -/* I think I've seen this after a request-sense that was in response - * to an error condition, but not sure. We certainly need to do - * something when we get this interrupt - the question is 'what?'. - * Let's think positively, and assume some command has finished - * in a legal manner (like a command that provokes a request-sense), - * so we treat it as a normal command-complete-disconnect. - */ - -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ - - write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); - if (cmd == NULL) { - printk(" - Already disconnected! "); - hostdata->state = S_UNCONNECTED; - spin_unlock_irqrestore(&hostdata->lock, flags); - return; - } - DB(DB_INTR, printk("UNEXP_DISC")) - hostdata->connected = NULL; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->state = S_UNCONNECTED; - if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) - cmd->result = - (cmd->result & 0x00ffff) | (DID_ERROR << 16); - else - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - cmd->scsi_done(cmd); - -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ - /* look above for comments on scsi_done() */ - spin_unlock_irqrestore(&hostdata->lock, flags); - wd33c93_execute(instance); - break; - - case CSR_DISC: - -/* Make sure that reselection is enabled at this point - it may - * have been turned off for the command that just completed. - */ - - write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER); - DB(DB_INTR, printk("DISC")) - if (cmd == NULL) { - printk(" - Already disconnected! "); - hostdata->state = S_UNCONNECTED; - } - switch (hostdata->state) { - case S_PRE_CMP_DISC: - hostdata->connected = NULL; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->state = S_UNCONNECTED; - DB(DB_INTR, printk(":%d", cmd->SCp.Status)) - if (cmd->cmnd[0] == REQUEST_SENSE - && cmd->SCp.Status != GOOD) - cmd->result = - (cmd-> - result & 0x00ffff) | (DID_ERROR << 16); - else - cmd->result = - cmd->SCp.Status | (cmd->SCp.Message << 8); - cmd->scsi_done(cmd); - break; - case S_PRE_TMP_DISC: - case S_RUNNING_LEVEL2: - cmd->host_scribble = (uchar *) hostdata->disconnected_Q; - hostdata->disconnected_Q = cmd; - hostdata->connected = NULL; - hostdata->state = S_UNCONNECTED; - -#ifdef PROC_STATISTICS - hostdata->disc_done_cnt[cmd->device->id]++; -#endif - - break; - default: - printk("*** Unexpected DISCONNECT interrupt! ***"); - hostdata->state = S_UNCONNECTED; - } - -/* We are no longer connected to a target - check to see if - * there are commands waiting to be executed. - */ - spin_unlock_irqrestore(&hostdata->lock, flags); - wd33c93_execute(instance); - break; - - case CSR_RESEL_AM: - case CSR_RESEL: - DB(DB_INTR, printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : "")) - - /* Old chips (pre -A ???) don't have advanced features and will - * generate CSR_RESEL. In that case we have to extract the LUN the - * hard way (see below). - * First we have to make sure this reselection didn't - * happen during Arbitration/Selection of some other device. - * If yes, put losing command back on top of input_Q. - */ - if (hostdata->level2 <= L2_NONE) { - - if (hostdata->selecting) { - cmd = (struct scsi_cmnd *) hostdata->selecting; - hostdata->selecting = NULL; - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - cmd->host_scribble = - (uchar *) hostdata->input_Q; - hostdata->input_Q = cmd; - } - } - - else { - - if (cmd) { - if (phs == 0x00) { - hostdata->busy[cmd->device->id] &= - ~(1 << cmd->device->lun); - cmd->host_scribble = - (uchar *) hostdata->input_Q; - hostdata->input_Q = cmd; - } else { - printk - ("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---", - asr, sr, phs); - while (1) - printk("\r"); - } - } - - } - - /* OK - find out which device reselected us. */ - - id = read_wd33c93(regs, WD_SOURCE_ID); - id &= SRCID_MASK; - - /* and extract the lun from the ID message. (Note that we don't - * bother to check for a valid message here - I guess this is - * not the right way to go, but...) - */ - - if (sr == CSR_RESEL_AM) { - lun = read_wd33c93(regs, WD_DATA); - if (hostdata->level2 < L2_RESELECT) - write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK); - lun &= 7; - } else { - /* Old chip; wait for msgin phase to pick up the LUN. */ - for (lun = 255; lun; lun--) { - if ((asr = read_aux_stat(regs)) & ASR_INT) - break; - udelay(10); - } - if (!(asr & ASR_INT)) { - printk - ("wd33c93: Reselected without IDENTIFY\n"); - lun = 0; - } else { - /* Verify this is a change to MSG_IN and read the message */ - sr = read_wd33c93(regs, WD_SCSI_STATUS); - udelay(7); - if (sr == (CSR_ABORT | PHS_MESS_IN) || - sr == (CSR_UNEXP | PHS_MESS_IN) || - sr == (CSR_SRV_REQ | PHS_MESS_IN)) { - /* Got MSG_IN, grab target LUN */ - lun = read_1_byte(regs); - /* Now we expect a 'paused with ACK asserted' int.. */ - asr = read_aux_stat(regs); - if (!(asr & ASR_INT)) { - udelay(10); - asr = read_aux_stat(regs); - if (!(asr & ASR_INT)) - printk - ("wd33c93: No int after LUN on RESEL (%02x)\n", - asr); - } - sr = read_wd33c93(regs, WD_SCSI_STATUS); - udelay(7); - if (sr != CSR_MSGIN) - printk - ("wd33c93: Not paused with ACK on RESEL (%02x)\n", - sr); - lun &= 7; - write_wd33c93_cmd(regs, - WD_CMD_NEGATE_ACK); - } else { - printk - ("wd33c93: Not MSG_IN on reselect (%02x)\n", - sr); - lun = 0; - } - } - } - - /* Now we look for the command that's reconnecting. */ - - cmd = (struct scsi_cmnd *) hostdata->disconnected_Q; - patch = NULL; - while (cmd) { - if (id == cmd->device->id && lun == cmd->device->lun) - break; - patch = cmd; - cmd = (struct scsi_cmnd *) cmd->host_scribble; - } - - /* Hmm. Couldn't find a valid command.... What to do? */ - - if (!cmd) { - printk - ("---TROUBLE: target %d.%d not in disconnect queue---", - id, lun); - spin_unlock_irqrestore(&hostdata->lock, flags); - return; - } - - /* Ok, found the command - now start it up again. */ - - if (patch) - patch->host_scribble = cmd->host_scribble; - else - hostdata->disconnected_Q = - (struct scsi_cmnd *) cmd->host_scribble; - hostdata->connected = cmd; - - /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]' - * because these things are preserved over a disconnect. - * But we DO need to fix the DPD bit so it's correct for this command. - */ - - if (cmd->sc_data_direction == DMA_TO_DEVICE) - write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id); - else - write_wd33c93(regs, WD_DESTINATION_ID, - cmd->device->id | DSTID_DPD); - if (hostdata->level2 >= L2_RESELECT) { - write_wd33c93_count(regs, 0); /* we want a DATA_PHASE interrupt */ - write_wd33c93(regs, WD_COMMAND_PHASE, 0x45); - write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER); - hostdata->state = S_RUNNING_LEVEL2; - } else - hostdata->state = S_CONNECTED; - - spin_unlock_irqrestore(&hostdata->lock, flags); - break; - - default: - printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs); - spin_unlock_irqrestore(&hostdata->lock, flags); - } - - DB(DB_INTR, printk("} ")) - -} - -static void -reset_wd33c93(struct Scsi_Host *instance) -{ - struct WD33C93_hostdata *hostdata = - (struct WD33C93_hostdata *) instance->hostdata; - const wd33c93_regs regs = hostdata->regs; - uchar sr; - -#ifdef CONFIG_SGI_IP22 - { - int busycount = 0; - extern void sgiwd93_reset(unsigned long); - /* wait 'til the chip gets some time for us */ - while ((read_aux_stat(regs) & ASR_BSY) && busycount++ < 100) - udelay (10); - /* - * there are scsi devices out there, which manage to lock up - * the wd33c93 in a busy condition. In this state it won't - * accept the reset command. The only way to solve this is to - * give the chip a hardware reset (if possible). The code below - * does this for the SGI Indy, where this is possible - */ - /* still busy ? */ - if (read_aux_stat(regs) & ASR_BSY) - sgiwd93_reset(instance->base); /* yeah, give it the hard one */ - } -#endif - - write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF | - instance->this_id | hostdata->clock_freq); - write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER, - calc_sync_xfer(hostdata->default_sx_per / 4, - DEFAULT_SX_OFF, 0, hostdata->sx_table)); - write_wd33c93(regs, WD_COMMAND, WD_CMD_RESET); - - -#ifdef CONFIG_MVME147_SCSI - udelay(25); /* The old wd33c93 on MVME147 needs this, at least */ -#endif - - while (!(read_aux_stat(regs) & ASR_INT)) - ; - sr = read_wd33c93(regs, WD_SCSI_STATUS); - - hostdata->microcode = read_wd33c93(regs, WD_CDB_1); - if (sr == 0x00) - hostdata->chip = C_WD33C93; - else if (sr == 0x01) { - write_wd33c93(regs, WD_QUEUE_TAG, 0xa5); /* any random number */ - sr = read_wd33c93(regs, WD_QUEUE_TAG); - if (sr == 0xa5) { - hostdata->chip = C_WD33C93B; - write_wd33c93(regs, WD_QUEUE_TAG, 0); - } else - hostdata->chip = C_WD33C93A; - } else - hostdata->chip = C_UNKNOWN_CHIP; - - if (hostdata->chip != C_WD33C93B) /* Fast SCSI unavailable */ - hostdata->fast = 0; - - write_wd33c93(regs, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); - write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); -} - -int -wd33c93_host_reset(struct scsi_cmnd * SCpnt) -{ - struct Scsi_Host *instance; - struct WD33C93_hostdata *hostdata; - int i; - - instance = SCpnt->device->host; - hostdata = (struct WD33C93_hostdata *) instance->hostdata; - - printk("scsi%d: reset. ", instance->host_no); - disable_irq(instance->irq); - - hostdata->dma_stop(instance, NULL, 0); - for (i = 0; i < 8; i++) { - hostdata->busy[i] = 0; - hostdata->sync_xfer[i] = - calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF, - 0, hostdata->sx_table); - hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ - } - hostdata->input_Q = NULL; - hostdata->selecting = NULL; - hostdata->connected = NULL; - hostdata->disconnected_Q = NULL; - hostdata->state = S_UNCONNECTED; - hostdata->dma = D_DMA_OFF; - hostdata->incoming_ptr = 0; - hostdata->outgoing_len = 0; - - reset_wd33c93(instance); - SCpnt->result = DID_RESET << 16; - enable_irq(instance->irq); - return SUCCESS; -} - -int -wd33c93_abort(struct scsi_cmnd * cmd) -{ - struct Scsi_Host *instance; - struct WD33C93_hostdata *hostdata; - wd33c93_regs regs; - struct scsi_cmnd *tmp, *prev; - - disable_irq(cmd->device->host->irq); - - instance = cmd->device->host; - hostdata = (struct WD33C93_hostdata *) instance->hostdata; - regs = hostdata->regs; - -/* - * Case 1 : If the command hasn't been issued yet, we simply remove it - * from the input_Q. - */ - - tmp = (struct scsi_cmnd *) hostdata->input_Q; - prev = NULL; - while (tmp) { - if (tmp == cmd) { - if (prev) - prev->host_scribble = cmd->host_scribble; - else - hostdata->input_Q = - (struct scsi_cmnd *) cmd->host_scribble; - cmd->host_scribble = NULL; - cmd->result = DID_ABORT << 16; - printk - ("scsi%d: Abort - removing command from input_Q. ", - instance->host_no); - enable_irq(cmd->device->host->irq); - cmd->scsi_done(cmd); - return SUCCESS; - } - prev = tmp; - tmp = (struct scsi_cmnd *) tmp->host_scribble; - } - -/* - * Case 2 : If the command is connected, we're going to fail the abort - * and let the high level SCSI driver retry at a later time or - * issue a reset. - * - * Timeouts, and therefore aborted commands, will be highly unlikely - * and handling them cleanly in this situation would make the common - * case of noresets less efficient, and would pollute our code. So, - * we fail. - */ - - if (hostdata->connected == cmd) { - uchar sr, asr; - unsigned long timeout; - - printk("scsi%d: Aborting connected command - ", - instance->host_no); - - printk("stopping DMA - "); - if (hostdata->dma == D_DMA_RUNNING) { - hostdata->dma_stop(instance, cmd, 0); - hostdata->dma = D_DMA_OFF; - } - - printk("sending wd33c93 ABORT command - "); - write_wd33c93(regs, WD_CONTROL, - CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93_cmd(regs, WD_CMD_ABORT); - -/* Now we have to attempt to flush out the FIFO... */ - - printk("flushing fifo - "); - timeout = 1000000; - do { - asr = read_aux_stat(regs); - if (asr & ASR_DBR) - read_wd33c93(regs, WD_DATA); - } while (!(asr & ASR_INT) && timeout-- > 0); - sr = read_wd33c93(regs, WD_SCSI_STATUS); - printk - ("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", - asr, sr, read_wd33c93_count(regs), timeout); - - /* - * Abort command processed. - * Still connected. - * We must disconnect. - */ - - printk("sending wd33c93 DISCONNECT command - "); - write_wd33c93_cmd(regs, WD_CMD_DISCONNECT); - - timeout = 1000000; - asr = read_aux_stat(regs); - while ((asr & ASR_CIP) && timeout-- > 0) - asr = read_aux_stat(regs); - sr = read_wd33c93(regs, WD_SCSI_STATUS); - printk("asr=%02x, sr=%02x.", asr, sr); - - hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun); - hostdata->connected = NULL; - hostdata->state = S_UNCONNECTED; - cmd->result = DID_ABORT << 16; - -/* sti();*/ - wd33c93_execute(instance); - - enable_irq(cmd->device->host->irq); - cmd->scsi_done(cmd); - return SUCCESS; - } - -/* - * Case 3: If the command is currently disconnected from the bus, - * we're not going to expend much effort here: Let's just return - * an ABORT_SNOOZE and hope for the best... - */ - - tmp = (struct scsi_cmnd *) hostdata->disconnected_Q; - while (tmp) { - if (tmp == cmd) { - printk - ("scsi%d: Abort - command found on disconnected_Q - ", - instance->host_no); - printk("Abort SNOOZE. "); - enable_irq(cmd->device->host->irq); - return FAILED; - } - tmp = (struct scsi_cmnd *) tmp->host_scribble; - } - -/* - * Case 4 : If we reached this point, the command was not found in any of - * the queues. - * - * We probably reached this point because of an unlikely race condition - * between the command completing successfully and the abortion code, - * so we won't panic, but we will notify the user in case something really - * broke. - */ - -/* sti();*/ - wd33c93_execute(instance); - - enable_irq(cmd->device->host->irq); - printk("scsi%d: warning : SCSI command probably completed successfully" - " before abortion. ", instance->host_no); - return FAILED; -} - -#define MAX_WD33C93_HOSTS 4 -#define MAX_SETUP_ARGS ARRAY_SIZE(setup_args) -#define SETUP_BUFFER_SIZE 200 -static char setup_buffer[SETUP_BUFFER_SIZE]; -static char setup_used[MAX_SETUP_ARGS]; -static int done_setup = 0; - -static int -wd33c93_setup(char *str) -{ - int i; - char *p1, *p2; - - /* The kernel does some processing of the command-line before calling - * this function: If it begins with any decimal or hex number arguments, - * ints[0] = how many numbers found and ints[1] through [n] are the values - * themselves. str points to where the non-numeric arguments (if any) - * start: We do our own parsing of those. We construct synthetic 'nosync' - * keywords out of numeric args (to maintain compatibility with older - * versions) and then add the rest of the arguments. - */ - - p1 = setup_buffer; - *p1 = '\0'; - if (str) - strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer)); - setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0'; - p1 = setup_buffer; - i = 0; - while (*p1 && (i < MAX_SETUP_ARGS)) { - p2 = strchr(p1, ','); - if (p2) { - *p2 = '\0'; - if (p1 != p2) - setup_args[i] = p1; - p1 = p2 + 1; - i++; - } else { - setup_args[i] = p1; - break; - } - } - for (i = 0; i < MAX_SETUP_ARGS; i++) - setup_used[i] = 0; - done_setup = 1; - - return 1; -} -__setup("wd33c93=", wd33c93_setup); - -/* check_setup_args() returns index if key found, 0 if not - */ -static int -check_setup_args(char *key, int *flags, int *val, char *buf) -{ - int x; - char *cp; - - for (x = 0; x < MAX_SETUP_ARGS; x++) { - if (setup_used[x]) - continue; - if (!strncmp(setup_args[x], key, strlen(key))) - break; - if (!strncmp(setup_args[x], "next", strlen("next"))) - return 0; - } - if (x == MAX_SETUP_ARGS) - return 0; - setup_used[x] = 1; - cp = setup_args[x] + strlen(key); - *val = -1; - if (*cp != ':') - return ++x; - cp++; - if ((*cp >= '0') && (*cp <= '9')) { - *val = simple_strtoul(cp, NULL, 0); - } - return ++x; -} - -/* - * Calculate internal data-transfer-clock cycle from input-clock - * frequency (/MHz) and fill 'sx_table'. - * - * The original driver used to rely on a fixed sx_table, containing periods - * for (only) the lower limits of the respective input-clock-frequency ranges - * (8-10/12-15/16-20 MHz). Although it seems, that no problems occurred with - * this setting so far, it might be desirable to adjust the transfer periods - * closer to the really attached, possibly 25% higher, input-clock, since - * - the wd33c93 may really use a significant shorter period, than it has - * negotiated (eg. thrashing the target, which expects 4/8MHz, with 5/10MHz - * instead). - * - the wd33c93 may ask the target for a lower transfer rate, than the target - * is capable of (eg. negotiating for an assumed minimum of 252ns instead of - * possible 200ns, which indeed shows up in tests as an approx. 10% lower - * transfer rate). - */ -static inline unsigned int -round_4(unsigned int x) -{ - switch (x & 3) { - case 1: --x; - break; - case 2: ++x; - case 3: ++x; - } - return x; -} - -static void -calc_sx_table(unsigned int mhz, struct sx_period sx_table[9]) -{ - unsigned int d, i; - if (mhz < 11) - d = 2; /* divisor for 8-10 MHz input-clock */ - else if (mhz < 16) - d = 3; /* divisor for 12-15 MHz input-clock */ - else - d = 4; /* divisor for 16-20 MHz input-clock */ - - d = (100000 * d) / 2 / mhz; /* 100 x DTCC / nanosec */ - - sx_table[0].period_ns = 1; - sx_table[0].reg_value = 0x20; - for (i = 1; i < 8; i++) { - sx_table[i].period_ns = round_4((i+1)*d / 100); - sx_table[i].reg_value = (i+1)*0x10; - } - sx_table[7].reg_value = 0; - sx_table[8].period_ns = 0; - sx_table[8].reg_value = 0; -} - -/* - * check and, maybe, map an init- or "clock:"- argument. - */ -static uchar -set_clk_freq(int freq, int *mhz) -{ - int x = freq; - if (WD33C93_FS_8_10 == freq) - freq = 8; - else if (WD33C93_FS_12_15 == freq) - freq = 12; - else if (WD33C93_FS_16_20 == freq) - freq = 16; - else if (freq > 7 && freq < 11) - x = WD33C93_FS_8_10; - else if (freq > 11 && freq < 16) - x = WD33C93_FS_12_15; - else if (freq > 15 && freq < 21) - x = WD33C93_FS_16_20; - else { - /* Hmm, wouldn't it be safer to assume highest freq here? */ - x = WD33C93_FS_8_10; - freq = 8; - } - *mhz = freq; - return x; -} - -/* - * to be used with the resync: fast: ... options - */ -static inline void set_resync ( struct WD33C93_hostdata *hd, int mask ) -{ - int i; - for (i = 0; i < 8; i++) - if (mask & (1 << i)) - hd->sync_stat[i] = SS_UNSET; -} - -void -wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs, - dma_setup_t setup, dma_stop_t stop, int clock_freq) -{ - struct WD33C93_hostdata *hostdata; - int i; - int flags; - int val; - char buf[32]; - - if (!done_setup && setup_strings) - wd33c93_setup(setup_strings); - - hostdata = (struct WD33C93_hostdata *) instance->hostdata; - - hostdata->regs = regs; - hostdata->clock_freq = set_clk_freq(clock_freq, &i); - calc_sx_table(i, hostdata->sx_table); - hostdata->dma_setup = setup; - hostdata->dma_stop = stop; - hostdata->dma_bounce_buffer = NULL; - hostdata->dma_bounce_len = 0; - for (i = 0; i < 8; i++) { - hostdata->busy[i] = 0; - hostdata->sync_xfer[i] = - calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF, - 0, hostdata->sx_table); - hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ -#ifdef PROC_STATISTICS - hostdata->cmd_cnt[i] = 0; - hostdata->disc_allowed_cnt[i] = 0; - hostdata->disc_done_cnt[i] = 0; -#endif - } - hostdata->input_Q = NULL; - hostdata->selecting = NULL; - hostdata->connected = NULL; - hostdata->disconnected_Q = NULL; - hostdata->state = S_UNCONNECTED; - hostdata->dma = D_DMA_OFF; - hostdata->level2 = L2_BASIC; - hostdata->disconnect = DIS_ADAPTIVE; - hostdata->args = DEBUG_DEFAULTS; - hostdata->incoming_ptr = 0; - hostdata->outgoing_len = 0; - hostdata->default_sx_per = DEFAULT_SX_PER; - hostdata->no_dma = 0; /* default is DMA enabled */ - -#ifdef PROC_INTERFACE - hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | - PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP; -#ifdef PROC_STATISTICS - hostdata->dma_cnt = 0; - hostdata->pio_cnt = 0; - hostdata->int_cnt = 0; -#endif -#endif - - if (check_setup_args("clock", &flags, &val, buf)) { - hostdata->clock_freq = set_clk_freq(val, &val); - calc_sx_table(val, hostdata->sx_table); - } - - if (check_setup_args("nosync", &flags, &val, buf)) - hostdata->no_sync = val; - - if (check_setup_args("nodma", &flags, &val, buf)) - hostdata->no_dma = (val == -1) ? 1 : val; - - if (check_setup_args("period", &flags, &val, buf)) - hostdata->default_sx_per = - hostdata->sx_table[round_period((unsigned int) val, - hostdata->sx_table)].period_ns; - - if (check_setup_args("disconnect", &flags, &val, buf)) { - if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) - hostdata->disconnect = val; - else - hostdata->disconnect = DIS_ADAPTIVE; - } - - if (check_setup_args("level2", &flags, &val, buf)) - hostdata->level2 = val; - - if (check_setup_args("debug", &flags, &val, buf)) - hostdata->args = val & DB_MASK; - - if (check_setup_args("burst", &flags, &val, buf)) - hostdata->dma_mode = val ? CTRL_BURST:CTRL_DMA; - - if (WD33C93_FS_16_20 == hostdata->clock_freq /* divisor 4 */ - && check_setup_args("fast", &flags, &val, buf)) - hostdata->fast = !!val; - - if ((i = check_setup_args("next", &flags, &val, buf))) { - while (i) - setup_used[--i] = 1; - } -#ifdef PROC_INTERFACE - if (check_setup_args("proc", &flags, &val, buf)) - hostdata->proc = val; -#endif - - spin_lock_irq(&hostdata->lock); - reset_wd33c93(instance); - spin_unlock_irq(&hostdata->lock); - - printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d", - instance->host_no, - (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip == - C_WD33C93A) ? - "WD33c93A" : (hostdata->chip == - C_WD33C93B) ? "WD33c93B" : "unknown", - hostdata->microcode, hostdata->no_sync, hostdata->no_dma); -#ifdef DEBUGGING_ON - printk(" debug_flags=0x%02x\n", hostdata->args); -#else - printk(" debugging=OFF\n"); -#endif - printk(" setup_args="); - for (i = 0; i < MAX_SETUP_ARGS; i++) - printk("%s,", setup_args[i]); - printk("\n"); - printk(" Version %s - %s\n", WD33C93_VERSION, WD33C93_DATE); -} - -int -wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in) -{ - -#ifdef PROC_INTERFACE - - char *bp; - char tbuf[128]; - struct WD33C93_hostdata *hd; - struct scsi_cmnd *cmd; - int x; - static int stop = 0; - - hd = (struct WD33C93_hostdata *) instance->hostdata; - -/* If 'in' is TRUE we need to _read_ the proc file. We accept the following - * keywords (same format as command-line, but arguments are not optional): - * debug - * disconnect - * period - * resync - * proc - * nodma - * level2 - * burst - * fast - * nosync - */ - - if (in) { - buf[len] = '\0'; - for (bp = buf; *bp; ) { - while (',' == *bp || ' ' == *bp) - ++bp; - if (!strncmp(bp, "debug:", 6)) { - hd->args = simple_strtoul(bp+6, &bp, 0) & DB_MASK; - } else if (!strncmp(bp, "disconnect:", 11)) { - x = simple_strtoul(bp+11, &bp, 0); - if (x < DIS_NEVER || x > DIS_ALWAYS) - x = DIS_ADAPTIVE; - hd->disconnect = x; - } else if (!strncmp(bp, "period:", 7)) { - x = simple_strtoul(bp+7, &bp, 0); - hd->default_sx_per = - hd->sx_table[round_period((unsigned int) x, - hd->sx_table)].period_ns; - } else if (!strncmp(bp, "resync:", 7)) { - set_resync(hd, (int)simple_strtoul(bp+7, &bp, 0)); - } else if (!strncmp(bp, "proc:", 5)) { - hd->proc = simple_strtoul(bp+5, &bp, 0); - } else if (!strncmp(bp, "nodma:", 6)) { - hd->no_dma = simple_strtoul(bp+6, &bp, 0); - } else if (!strncmp(bp, "level2:", 7)) { - hd->level2 = simple_strtoul(bp+7, &bp, 0); - } else if (!strncmp(bp, "burst:", 6)) { - hd->dma_mode = - simple_strtol(bp+6, &bp, 0) ? CTRL_BURST:CTRL_DMA; - } else if (!strncmp(bp, "fast:", 5)) { - x = !!simple_strtol(bp+5, &bp, 0); - if (x != hd->fast) - set_resync(hd, 0xff); - hd->fast = x; - } else if (!strncmp(bp, "nosync:", 7)) { - x = simple_strtoul(bp+7, &bp, 0); - set_resync(hd, x ^ hd->no_sync); - hd->no_sync = x; - } else { - break; /* unknown keyword,syntax-error,... */ - } - } - return len; - } - - spin_lock_irq(&hd->lock); - bp = buf; - *bp = '\0'; - if (hd->proc & PR_VERSION) { - sprintf(tbuf, "\nVersion %s - %s.", - WD33C93_VERSION, WD33C93_DATE); - strcat(bp, tbuf); - } - if (hd->proc & PR_INFO) { - sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d" - " dma_mode=%02x fast=%d", - hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast); - strcat(bp, tbuf); - strcat(bp, "\nsync_xfer[] = "); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%02x", hd->sync_xfer[x]); - strcat(bp, tbuf); - } - strcat(bp, "\nsync_stat[] = "); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%02x", hd->sync_stat[x]); - strcat(bp, tbuf); - } - } -#ifdef PROC_STATISTICS - if (hd->proc & PR_STATISTICS) { - strcat(bp, "\ncommands issued: "); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]); - strcat(bp, tbuf); - } - strcat(bp, "\ndisconnects allowed:"); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]); - strcat(bp, tbuf); - } - strcat(bp, "\ndisconnects done: "); - for (x = 0; x < 7; x++) { - sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]); - strcat(bp, tbuf); - } - sprintf(tbuf, - "\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO", - hd->int_cnt, hd->dma_cnt, hd->pio_cnt); - strcat(bp, tbuf); - } -#endif - if (hd->proc & PR_CONNECTED) { - strcat(bp, "\nconnected: "); - if (hd->connected) { - cmd = (struct scsi_cmnd *) hd->connected; - sprintf(tbuf, " %d:%d(%02x)", - cmd->device->id, cmd->device->lun, cmd->cmnd[0]); - strcat(bp, tbuf); - } - } - if (hd->proc & PR_INPUTQ) { - strcat(bp, "\ninput_Q: "); - cmd = (struct scsi_cmnd *) hd->input_Q; - while (cmd) { - sprintf(tbuf, " %d:%d(%02x)", - cmd->device->id, cmd->device->lun, cmd->cmnd[0]); - strcat(bp, tbuf); - cmd = (struct scsi_cmnd *) cmd->host_scribble; - } - } - if (hd->proc & PR_DISCQ) { - strcat(bp, "\ndisconnected_Q:"); - cmd = (struct scsi_cmnd *) hd->disconnected_Q; - while (cmd) { - sprintf(tbuf, " %d:%d(%02x)", - cmd->device->id, cmd->device->lun, cmd->cmnd[0]); - strcat(bp, tbuf); - cmd = (struct scsi_cmnd *) cmd->host_scribble; - } - } - strcat(bp, "\n"); - spin_unlock_irq(&hd->lock); - *start = buf; - if (stop) { - stop = 0; - return 0; - } - if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */ - stop = 1; - if (hd->proc & PR_STOP) /* stop every other time */ - stop = 1; - return strlen(bp); - -#else /* PROC_INTERFACE */ - - return 0; - -#endif /* PROC_INTERFACE */ - -} - -EXPORT_SYMBOL(wd33c93_host_reset); -EXPORT_SYMBOL(wd33c93_init); -EXPORT_SYMBOL(wd33c93_abort); -EXPORT_SYMBOL(wd33c93_queuecommand); -EXPORT_SYMBOL(wd33c93_intr); -EXPORT_SYMBOL(wd33c93_proc_info); diff --git a/ANDROID_3.4.5/drivers/scsi/wd33c93.h b/ANDROID_3.4.5/drivers/scsi/wd33c93.h deleted file mode 100644 index 3b463d73..00000000 --- a/ANDROID_3.4.5/drivers/scsi/wd33c93.h +++ /dev/null @@ -1,351 +0,0 @@ -/* - * wd33c93.h - Linux device driver definitions for the - * Commodore Amiga A2091/590 SCSI controller card - * - * IMPORTANT: This file is for version 1.25 - 09/Jul/1997 - * - * Copyright (c) 1996 John Shifflett, GeoLog Consulting - * john@geolog.com - * jshiffle@netcom.com - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#ifndef WD33C93_H -#define WD33C93_H - - -#define PROC_INTERFACE /* add code for /proc/scsi/wd33c93/xxx interface */ -#ifdef PROC_INTERFACE -#define PROC_STATISTICS /* add code for keeping various real time stats */ -#endif - -#define SYNC_DEBUG /* extra info on sync negotiation printed */ -#define DEBUGGING_ON /* enable command-line debugging bitmask */ -#define DEBUG_DEFAULTS 0 /* default debugging bitmask */ - - -#ifdef DEBUGGING_ON -#define DB(f,a) if (hostdata->args & (f)) a; -#else -#define DB(f,a) -#endif - -#define uchar unsigned char - - -/* wd register names */ -#define WD_OWN_ID 0x00 -#define WD_CONTROL 0x01 -#define WD_TIMEOUT_PERIOD 0x02 -#define WD_CDB_1 0x03 -#define WD_CDB_2 0x04 -#define WD_CDB_3 0x05 -#define WD_CDB_4 0x06 -#define WD_CDB_5 0x07 -#define WD_CDB_6 0x08 -#define WD_CDB_7 0x09 -#define WD_CDB_8 0x0a -#define WD_CDB_9 0x0b -#define WD_CDB_10 0x0c -#define WD_CDB_11 0x0d -#define WD_CDB_12 0x0e -#define WD_TARGET_LUN 0x0f -#define WD_COMMAND_PHASE 0x10 -#define WD_SYNCHRONOUS_TRANSFER 0x11 -#define WD_TRANSFER_COUNT_MSB 0x12 -#define WD_TRANSFER_COUNT 0x13 -#define WD_TRANSFER_COUNT_LSB 0x14 -#define WD_DESTINATION_ID 0x15 -#define WD_SOURCE_ID 0x16 -#define WD_SCSI_STATUS 0x17 -#define WD_COMMAND 0x18 -#define WD_DATA 0x19 -#define WD_QUEUE_TAG 0x1a -#define WD_AUXILIARY_STATUS 0x1f - -/* WD commands */ -#define WD_CMD_RESET 0x00 -#define WD_CMD_ABORT 0x01 -#define WD_CMD_ASSERT_ATN 0x02 -#define WD_CMD_NEGATE_ACK 0x03 -#define WD_CMD_DISCONNECT 0x04 -#define WD_CMD_RESELECT 0x05 -#define WD_CMD_SEL_ATN 0x06 -#define WD_CMD_SEL 0x07 -#define WD_CMD_SEL_ATN_XFER 0x08 -#define WD_CMD_SEL_XFER 0x09 -#define WD_CMD_RESEL_RECEIVE 0x0a -#define WD_CMD_RESEL_SEND 0x0b -#define WD_CMD_WAIT_SEL_RECEIVE 0x0c -#define WD_CMD_TRANS_ADDR 0x18 -#define WD_CMD_TRANS_INFO 0x20 -#define WD_CMD_TRANSFER_PAD 0x21 -#define WD_CMD_SBT_MODE 0x80 - -/* ASR register */ -#define ASR_INT (0x80) -#define ASR_LCI (0x40) -#define ASR_BSY (0x20) -#define ASR_CIP (0x10) -#define ASR_PE (0x02) -#define ASR_DBR (0x01) - -/* SCSI Bus Phases */ -#define PHS_DATA_OUT 0x00 -#define PHS_DATA_IN 0x01 -#define PHS_COMMAND 0x02 -#define PHS_STATUS 0x03 -#define PHS_MESS_OUT 0x06 -#define PHS_MESS_IN 0x07 - -/* Command Status Register definitions */ - - /* reset state interrupts */ -#define CSR_RESET 0x00 -#define CSR_RESET_AF 0x01 - - /* successful completion interrupts */ -#define CSR_RESELECT 0x10 -#define CSR_SELECT 0x11 -#define CSR_SEL_XFER_DONE 0x16 -#define CSR_XFER_DONE 0x18 - - /* paused or aborted interrupts */ -#define CSR_MSGIN 0x20 -#define CSR_SDP 0x21 -#define CSR_SEL_ABORT 0x22 -#define CSR_RESEL_ABORT 0x25 -#define CSR_RESEL_ABORT_AM 0x27 -#define CSR_ABORT 0x28 - - /* terminated interrupts */ -#define CSR_INVALID 0x40 -#define CSR_UNEXP_DISC 0x41 -#define CSR_TIMEOUT 0x42 -#define CSR_PARITY 0x43 -#define CSR_PARITY_ATN 0x44 -#define CSR_BAD_STATUS 0x45 -#define CSR_UNEXP 0x48 - - /* service required interrupts */ -#define CSR_RESEL 0x80 -#define CSR_RESEL_AM 0x81 -#define CSR_DISC 0x85 -#define CSR_SRV_REQ 0x88 - - /* Own ID/CDB Size register */ -#define OWNID_EAF 0x08 -#define OWNID_EHP 0x10 -#define OWNID_RAF 0x20 -#define OWNID_FS_8 0x00 -#define OWNID_FS_12 0x40 -#define OWNID_FS_16 0x80 - - /* define these so we don't have to change a2091.c, etc. */ -#define WD33C93_FS_8_10 OWNID_FS_8 -#define WD33C93_FS_12_15 OWNID_FS_12 -#define WD33C93_FS_16_20 OWNID_FS_16 - - /* pass input-clock explicitly. accepted mhz values are 8-10,12-20 */ -#define WD33C93_FS_MHZ(mhz) (mhz) - - /* Control register */ -#define CTRL_HSP 0x01 -#define CTRL_HA 0x02 -#define CTRL_IDI 0x04 -#define CTRL_EDI 0x08 -#define CTRL_HHP 0x10 -#define CTRL_POLLED 0x00 -#define CTRL_BURST 0x20 -#define CTRL_BUS 0x40 -#define CTRL_DMA 0x80 - - /* Timeout Period register */ -#define TIMEOUT_PERIOD_VALUE 20 /* 20 = 200 ms */ - - /* Synchronous Transfer Register */ -#define STR_FSS 0x80 - - /* Destination ID register */ -#define DSTID_DPD 0x40 -#define DATA_OUT_DIR 0 -#define DATA_IN_DIR 1 -#define DSTID_SCC 0x80 - - /* Source ID register */ -#define SRCID_MASK 0x07 -#define SRCID_SIV 0x08 -#define SRCID_DSP 0x20 -#define SRCID_ES 0x40 -#define SRCID_ER 0x80 - - /* This is what the 3393 chip looks like to us */ -typedef struct { -#ifdef CONFIG_WD33C93_PIO - unsigned int SASR; - unsigned int SCMD; -#else - volatile unsigned char *SASR; - volatile unsigned char *SCMD; -#endif -} wd33c93_regs; - - -typedef int (*dma_setup_t) (struct scsi_cmnd *SCpnt, int dir_in); -typedef void (*dma_stop_t) (struct Scsi_Host *instance, - struct scsi_cmnd *SCpnt, int status); - - -#define ILLEGAL_STATUS_BYTE 0xff - -#define DEFAULT_SX_PER 376 /* (ns) fairly safe */ -#define DEFAULT_SX_OFF 0 /* aka async */ - -#define OPTIMUM_SX_PER 252 /* (ns) best we can do (mult-of-4) */ -#define OPTIMUM_SX_OFF 12 /* size of wd3393 fifo */ - -struct sx_period { - unsigned int period_ns; - uchar reg_value; - }; - -/* FEF: defines for hostdata->dma_buffer_pool */ - -#define BUF_CHIP_ALLOCED 0 -#define BUF_SCSI_ALLOCED 1 - -struct WD33C93_hostdata { - struct Scsi_Host *next; - wd33c93_regs regs; - spinlock_t lock; - uchar clock_freq; - uchar chip; /* what kind of wd33c93? */ - uchar microcode; /* microcode rev */ - uchar dma_buffer_pool; /* FEF: buffer from chip_ram? */ - int dma_dir; /* data transfer dir. */ - dma_setup_t dma_setup; - dma_stop_t dma_stop; - unsigned int dma_xfer_mask; - uchar *dma_bounce_buffer; - unsigned int dma_bounce_len; - volatile uchar busy[8]; /* index = target, bit = lun */ - volatile struct scsi_cmnd *input_Q; /* commands waiting to be started */ - volatile struct scsi_cmnd *selecting; /* trying to select this command */ - volatile struct scsi_cmnd *connected; /* currently connected command */ - volatile struct scsi_cmnd *disconnected_Q;/* commands waiting for reconnect */ - uchar state; /* what we are currently doing */ - uchar dma; /* current state of DMA (on/off) */ - uchar level2; /* extent to which Level-2 commands are used */ - uchar disconnect; /* disconnect/reselect policy */ - unsigned int args; /* set from command-line argument */ - uchar incoming_msg[8]; /* filled during message_in phase */ - int incoming_ptr; /* mainly used with EXTENDED messages */ - uchar outgoing_msg[8]; /* send this during next message_out */ - int outgoing_len; /* length of outgoing message */ - unsigned int default_sx_per; /* default transfer period for SCSI bus */ - uchar sync_xfer[8]; /* sync_xfer reg settings per target */ - uchar sync_stat[8]; /* status of sync negotiation per target */ - uchar no_sync; /* bitmask: don't do sync on these targets */ - uchar no_dma; /* set this flag to disable DMA */ - uchar dma_mode; /* DMA Burst Mode or Single Byte DMA */ - uchar fast; /* set this flag to enable Fast SCSI */ - struct sx_period sx_table[9]; /* transfer periods for actual DTC-setting */ -#ifdef PROC_INTERFACE - uchar proc; /* bitmask: what's in proc output */ -#ifdef PROC_STATISTICS - unsigned long cmd_cnt[8]; /* # of commands issued per target */ - unsigned long int_cnt; /* # of interrupts serviced */ - unsigned long pio_cnt; /* # of pio data transfers */ - unsigned long dma_cnt; /* # of DMA data transfers */ - unsigned long disc_allowed_cnt[8]; /* # of disconnects allowed per target */ - unsigned long disc_done_cnt[8]; /* # of disconnects done per target*/ -#endif -#endif - }; - - -/* defines for hostdata->chip */ - -#define C_WD33C93 0 -#define C_WD33C93A 1 -#define C_WD33C93B 2 -#define C_UNKNOWN_CHIP 100 - -/* defines for hostdata->state */ - -#define S_UNCONNECTED 0 -#define S_SELECTING 1 -#define S_RUNNING_LEVEL2 2 -#define S_CONNECTED 3 -#define S_PRE_TMP_DISC 4 -#define S_PRE_CMP_DISC 5 - -/* defines for hostdata->dma */ - -#define D_DMA_OFF 0 -#define D_DMA_RUNNING 1 - -/* defines for hostdata->level2 */ -/* NOTE: only the first 3 are implemented so far */ - -#define L2_NONE 1 /* no combination commands - we get lots of ints */ -#define L2_SELECT 2 /* start with SEL_ATN_XFER, but never resume it */ -#define L2_BASIC 3 /* resume after STATUS ints & RDP messages */ -#define L2_DATA 4 /* resume after DATA_IN/OUT ints */ -#define L2_MOST 5 /* resume after anything except a RESELECT int */ -#define L2_RESELECT 6 /* resume after everything, including RESELECT ints */ -#define L2_ALL 7 /* always resume */ - -/* defines for hostdata->disconnect */ - -#define DIS_NEVER 0 -#define DIS_ADAPTIVE 1 -#define DIS_ALWAYS 2 - -/* defines for hostdata->args */ - -#define DB_TEST1 1<<0 -#define DB_TEST2 1<<1 -#define DB_QUEUE_COMMAND 1<<2 -#define DB_EXECUTE 1<<3 -#define DB_INTR 1<<4 -#define DB_TRANSFER 1<<5 -#define DB_MASK 0x3f - -/* defines for hostdata->sync_stat[] */ - -#define SS_UNSET 0 -#define SS_FIRST 1 -#define SS_WAITING 2 -#define SS_SET 3 - -/* defines for hostdata->proc */ - -#define PR_VERSION 1<<0 -#define PR_INFO 1<<1 -#define PR_STATISTICS 1<<2 -#define PR_CONNECTED 1<<3 -#define PR_INPUTQ 1<<4 -#define PR_DISCQ 1<<5 -#define PR_TEST 1<<6 -#define PR_STOP 1<<7 - - -void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs, - dma_setup_t setup, dma_stop_t stop, int clock_freq); -int wd33c93_abort (struct scsi_cmnd *cmd); -int wd33c93_queuecommand (struct Scsi_Host *h, struct scsi_cmnd *cmd); -void wd33c93_intr (struct Scsi_Host *instance); -int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); -int wd33c93_host_reset (struct scsi_cmnd *); - -#endif /* WD33C93_H */ diff --git a/ANDROID_3.4.5/drivers/scsi/wd7000.c b/ANDROID_3.4.5/drivers/scsi/wd7000.c deleted file mode 100644 index d89a5dfd..00000000 --- a/ANDROID_3.4.5/drivers/scsi/wd7000.c +++ /dev/null @@ -1,1676 +0,0 @@ -/* $Id: $ - * linux/drivers/scsi/wd7000.c - * - * Copyright (C) 1992 Thomas Wuensche - * closely related to the aha1542 driver from Tommy Thorn - * ( as close as different hardware allows on a lowlevel-driver :-) ) - * - * Revised (and renamed) by John Boyd to - * accommodate Eric Youngdale's modifications to scsi.c. Nov 1992. - * - * Additional changes to support scatter/gather. Dec. 1992. tw/jb - * - * No longer tries to reset SCSI bus at boot (it wasn't working anyway). - * Rewritten to support multiple host adapters. - * Miscellaneous cleanup. - * So far, still doesn't do reset or abort correctly, since I have no idea - * how to do them with this board (8^(. Jan 1994 jb - * - * This driver now supports both of the two standard configurations (per - * the 3.36 Owner's Manual, my latest reference) by the same method as - * before; namely, by looking for a BIOS signature. Thus, the location of - * the BIOS signature determines the board configuration. Until I have - * time to do something more flexible, users should stick to one of the - * following: - * - * Standard configuration for single-adapter systems: - * - BIOS at CE00h - * - I/O base address 350h - * - IRQ level 15 - * - DMA channel 6 - * Standard configuration for a second adapter in a system: - * - BIOS at C800h - * - I/O base address 330h - * - IRQ level 11 - * - DMA channel 5 - * - * Anyone who can recompile the kernel is welcome to add others as need - * arises, but unpredictable results may occur if there are conflicts. - * In any event, if there are multiple adapters in a system, they MUST - * use different I/O bases, IRQ levels, and DMA channels, since they will be - * indistinguishable (and in direct conflict) otherwise. - * - * As a point of information, the NO_OP command toggles the CMD_RDY bit - * of the status port, and this fact could be used as a test for the I/O - * base address (or more generally, board detection). There is an interrupt - * status port, so IRQ probing could also be done. I suppose the full - * DMA diagnostic could be used to detect the DMA channel being used. I - * haven't done any of this, though, because I think there's too much of - * a chance that such explorations could be destructive, if some other - * board's resources are used inadvertently. So, call me a wimp, but I - * don't want to try it. The only kind of exploration I trust is memory - * exploration, since it's more certain that reading memory won't be - * destructive. - * - * More to my liking would be a LILO boot command line specification, such - * as is used by the aha152x driver (and possibly others). I'll look into - * it, as I have time... - * - * I get mail occasionally from people who either are using or are - * considering using a WD7000 with Linux. There is a variety of - * nomenclature describing WD7000's. To the best of my knowledge, the - * following is a brief summary (from an old WD doc - I don't work for - * them or anything like that): - * - * WD7000-FASST2: This is a WD7000 board with the real-mode SST ROM BIOS - * installed. Last I heard, the BIOS was actually done by Columbia - * Data Products. The BIOS is only used by this driver (and thus - * by Linux) to identify the board; none of it can be executed under - * Linux. - * - * WD7000-ASC: This is the original adapter board, with or without BIOS. - * The board uses a WD33C93 or WD33C93A SBIC, which in turn is - * controlled by an onboard Z80 processor. The board interface - * visible to the host CPU is defined effectively by the Z80's - * firmware, and it is this firmware's revision level that is - * determined and reported by this driver. (The version of the - * on-board BIOS is of no interest whatsoever.) The host CPU has - * no access to the SBIC; hence the fact that it is a WD33C93 is - * also of no interest to this driver. - * - * WD7000-AX: - * WD7000-MX: - * WD7000-EX: These are newer versions of the WD7000-ASC. The -ASC is - * largely built from discrete components; these boards use more - * integration. The -AX is an ISA bus board (like the -ASC), - * the -MX is an MCA (i.e., PS/2) bus board), and the -EX is an - * EISA bus board. - * - * At the time of my documentation, the -?X boards were "future" products, - * and were not yet available. However, I vaguely recall that Thomas - * Wuensche had an -AX, so I believe at least it is supported by this - * driver. I have no personal knowledge of either -MX or -EX boards. - * - * P.S. Just recently, I've discovered (directly from WD and Future - * Domain) that all but the WD7000-EX have been out of production for - * two years now. FD has production rights to the 7000-EX, and are - * producing it under a new name, and with a new BIOS. If anyone has - * one of the FD boards, it would be nice to come up with a signature - * for it. - * J.B. Jan 1994. - * - * - * Revisions by Miroslav Zagorac - * - * 08/24/1996. - * - * Enhancement for wd7000_detect function has been made, so you don't have - * to enter BIOS ROM address in initialisation data (see struct Config). - * We cannot detect IRQ, DMA and I/O base address for now, so we have to - * enter them as arguments while wd_7000 is detected. If someone has IRQ, - * DMA or I/O base address set to some other value, he can enter them in - * configuration without any problem. Also I wrote a function wd7000_setup, - * so now you can enter WD-7000 definition as kernel arguments, - * as in lilo.conf: - * - * append="wd7000=IRQ,DMA,IO" - * - * PS: If card BIOS ROM is disabled, function wd7000_detect now will recognize - * adapter, unlike the old one. Anyway, BIOS ROM from WD7000 adapter is - * useless for Linux. B^) - * - * - * 09/06/1996. - * - * Autodetecting of I/O base address from wd7000_detect function is removed, - * some little bugs removed, etc... - * - * Thanks to Roger Scott for driver debugging. - * - * 06/07/1997 - * - * Added support for /proc file system (/proc/scsi/wd7000/[0...] files). - * Now, driver can handle hard disks with capacity >1GB. - * - * 01/15/1998 - * - * Added support for BUS_ON and BUS_OFF parameters in config line. - * Miscellaneous cleanup. - * - * 03/01/1998 - * - * WD7000 driver now work on kernels >= 2.1.x - * - * - * 12/31/2001 - Arnaldo Carvalho de Melo - * - * use host->host_lock, not io_request_lock, cleanups - * - * 2002/10/04 - Alan Cox - * - * Use dev_id for interrupts, kill __func__ pasting - * Add a lock for the scb pool, clean up all other cli/sti usage stuff - * Use the adapter lock for the other places we had the cli's - * - * 2002/10/06 - Alan Cox - * - * Switch to new style error handling - * Clean up delay to udelay, and yielding sleeps - * Make host reset actually reset the card - * Make everything static - * - * 2003/02/12 - Christoph Hellwig - * - * Cleaned up host template definition - * Removed now obsolete wd7000.h - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include - - -#undef WD7000_DEBUG /* general debug */ -#ifdef WD7000_DEBUG -#define dprintk printk -#else -#define dprintk(format,args...) -#endif - -/* - * Mailbox structure sizes. - * I prefer to keep the number of ICMBs much larger than the number of - * OGMBs. OGMBs are used very quickly by the driver to start one or - * more commands, while ICMBs are used by the host adapter per command. - */ -#define OGMB_CNT 16 -#define ICMB_CNT 32 - -/* - * Scb's are shared by all active adapters. So, if they all become busy, - * callers may be made to wait in alloc_scbs for them to free. That can - * be avoided by setting MAX_SCBS to NUM_CONFIG * WD7000_Q. If you'd - * rather conserve memory, use a smaller number (> 0, of course) - things - * will should still work OK. - */ -#define MAX_SCBS 32 - -/* - * In this version, sg_tablesize now defaults to WD7000_SG, and will - * be set to SG_NONE for older boards. This is the reverse of the - * previous default, and was changed so that the driver-level - * scsi_host_template would reflect the driver's support for scatter/ - * gather. - * - * Also, it has been reported that boards at Revision 6 support scatter/ - * gather, so the new definition of an "older" board has been changed - * accordingly. - */ -#define WD7000_Q 16 -#define WD7000_SG 16 - - -/* - * WD7000-specific mailbox structure - * - */ -typedef volatile struct mailbox { - unchar status; - unchar scbptr[3]; /* SCSI-style - MSB first (big endian) */ -} Mailbox; - -/* - * This structure should contain all per-adapter global data. I.e., any - * new global per-adapter data should put in here. - */ -typedef struct adapter { - struct Scsi_Host *sh; /* Pointer to Scsi_Host structure */ - int iobase; /* This adapter's I/O base address */ - int irq; /* This adapter's IRQ level */ - int dma; /* This adapter's DMA channel */ - int int_counter; /* This adapter's interrupt counter */ - int bus_on; /* This adapter's BUS_ON time */ - int bus_off; /* This adapter's BUS_OFF time */ - struct { /* This adapter's mailboxes */ - Mailbox ogmb[OGMB_CNT]; /* Outgoing mailboxes */ - Mailbox icmb[ICMB_CNT]; /* Incoming mailboxes */ - } mb; - int next_ogmb; /* to reduce contention at mailboxes */ - unchar control; /* shadows CONTROL port value */ - unchar rev1, rev2; /* filled in by wd7000_revision */ -} Adapter; - -/* - * (linear) base address for ROM BIOS - */ -static const long wd7000_biosaddr[] = { - 0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000, - 0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000 -}; -#define NUM_ADDRS ARRAY_SIZE(wd7000_biosaddr) - -static const unsigned short wd7000_iobase[] = { - 0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338, - 0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378, - 0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8, - 0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8 -}; -#define NUM_IOPORTS ARRAY_SIZE(wd7000_iobase) - -static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 }; -#define NUM_IRQS ARRAY_SIZE(wd7000_irq) - -static const short wd7000_dma[] = { 5, 6, 7 }; -#define NUM_DMAS ARRAY_SIZE(wd7000_dma) - -/* - * The following is set up by wd7000_detect, and used thereafter for - * proc and other global ookups - */ - -#define UNITS 8 -static struct Scsi_Host *wd7000_host[UNITS]; - -#define BUS_ON 64 /* x 125ns = 8000ns (BIOS default) */ -#define BUS_OFF 15 /* x 125ns = 1875ns (BIOS default) */ - -/* - * Standard Adapter Configurations - used by wd7000_detect - */ -typedef struct { - short irq; /* IRQ level */ - short dma; /* DMA channel */ - unsigned iobase; /* I/O base address */ - short bus_on; /* Time that WD7000 spends on the AT-bus when */ - /* transferring data. BIOS default is 8000ns. */ - short bus_off; /* Time that WD7000 spends OFF THE BUS after */ - /* while it is transferring data. */ - /* BIOS default is 1875ns */ -} Config; - -/* - * Add here your configuration... - */ -static Config configs[] = { - {15, 6, 0x350, BUS_ON, BUS_OFF}, /* defaults for single adapter */ - {11, 5, 0x320, BUS_ON, BUS_OFF}, /* defaults for second adapter */ - {7, 6, 0x350, BUS_ON, BUS_OFF}, /* My configuration (Zaga) */ - {-1, -1, 0x0, BUS_ON, BUS_OFF} /* Empty slot */ -}; -#define NUM_CONFIGS ARRAY_SIZE(configs) - -/* - * The following list defines strings to look for in the BIOS that identify - * it as the WD7000-FASST2 SST BIOS. I suspect that something should be - * added for the Future Domain version. - */ -typedef struct signature { - const char *sig; /* String to look for */ - unsigned long ofs; /* offset from BIOS base address */ - unsigned len; /* length of string */ -} Signature; - -static const Signature signatures[] = { - {"SSTBIOS", 0x0000d, 7} /* "SSTBIOS" @ offset 0x0000d */ -}; -#define NUM_SIGNATURES ARRAY_SIZE(signatures) - - -/* - * I/O Port Offsets and Bit Definitions - * 4 addresses are used. Those not defined here are reserved. - */ -#define ASC_STAT 0 /* Status, Read */ -#define ASC_COMMAND 0 /* Command, Write */ -#define ASC_INTR_STAT 1 /* Interrupt Status, Read */ -#define ASC_INTR_ACK 1 /* Acknowledge, Write */ -#define ASC_CONTROL 2 /* Control, Write */ - -/* - * ASC Status Port - */ -#define INT_IM 0x80 /* Interrupt Image Flag */ -#define CMD_RDY 0x40 /* Command Port Ready */ -#define CMD_REJ 0x20 /* Command Port Byte Rejected */ -#define ASC_INIT 0x10 /* ASC Initialized Flag */ -#define ASC_STATMASK 0xf0 /* The lower 4 Bytes are reserved */ - -/* - * COMMAND opcodes - * - * Unfortunately, I have no idea how to properly use some of these commands, - * as the OEM manual does not make it clear. I have not been able to use - * enable/disable unsolicited interrupts or the reset commands with any - * discernible effect whatsoever. I think they may be related to certain - * ICB commands, but again, the OEM manual doesn't make that clear. - */ -#define NO_OP 0 /* NO-OP toggles CMD_RDY bit in ASC_STAT */ -#define INITIALIZATION 1 /* initialization (10 bytes) */ -#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */ -#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */ -#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */ -#define SOFT_RESET 5 /* SCSI bus soft reset */ -#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */ -#define START_OGMB 0x80 /* start command in OGMB (n) */ -#define SCAN_OGMBS 0xc0 /* start multiple commands, signature (n) */ - /* where (n) = lower 6 bits */ -/* - * For INITIALIZATION: - */ -typedef struct initCmd { - unchar op; /* command opcode (= 1) */ - unchar ID; /* Adapter's SCSI ID */ - unchar bus_on; /* Bus on time, x 125ns (see below) */ - unchar bus_off; /* Bus off time, "" "" */ - unchar rsvd; /* Reserved */ - unchar mailboxes[3]; /* Address of Mailboxes, MSB first */ - unchar ogmbs; /* Number of outgoing MBs, max 64, 0,1 = 1 */ - unchar icmbs; /* Number of incoming MBs, "" "" */ -} InitCmd; - -/* - * Interrupt Status Port - also returns diagnostic codes at ASC reset - * - * if msb is zero, the lower bits are diagnostic status - * Diagnostics: - * 01 No diagnostic error occurred - * 02 RAM failure - * 03 FIFO R/W failed - * 04 SBIC register read/write failed - * 05 Initialization D-FF failed - * 06 Host IRQ D-FF failed - * 07 ROM checksum error - * Interrupt status (bitwise): - * 10NNNNNN outgoing mailbox NNNNNN is free - * 11NNNNNN incoming mailbox NNNNNN needs service - */ -#define MB_INTR 0xC0 /* Mailbox Service possible/required */ -#define IMB_INTR 0x40 /* 1 Incoming / 0 Outgoing */ -#define MB_MASK 0x3f /* mask for mailbox number */ - -/* - * CONTROL port bits - */ -#define INT_EN 0x08 /* Interrupt Enable */ -#define DMA_EN 0x04 /* DMA Enable */ -#define SCSI_RES 0x02 /* SCSI Reset */ -#define ASC_RES 0x01 /* ASC Reset */ - -/* - * Driver data structures: - * - mb and scbs are required for interfacing with the host adapter. - * An SCB has extra fields not visible to the adapter; mb's - * _cannot_ do this, since the adapter assumes they are contiguous in - * memory, 4 bytes each, with ICMBs following OGMBs, and uses this fact - * to access them. - * - An icb is for host-only (non-SCSI) commands. ICBs are 16 bytes each; - * the additional bytes are used only by the driver. - * - For now, a pool of SCBs are kept in global storage by this driver, - * and are allocated and freed as needed. - * - * The 7000-FASST2 marks OGMBs empty as soon as it has _started_ a command, - * not when it has finished. Since the SCB must be around for completion, - * problems arise when SCBs correspond to OGMBs, which may be reallocated - * earlier (or delayed unnecessarily until a command completes). - * Mailboxes are used as transient data structures, simply for - * carrying SCB addresses to/from the 7000-FASST2. - * - * Note also since SCBs are not "permanently" associated with mailboxes, - * there is no need to keep a global list of scsi_cmnd pointers indexed - * by OGMB. Again, SCBs reference their scsi_cmnds directly, so mailbox - * indices need not be involved. - */ - -/* - * WD7000-specific scatter/gather element structure - */ -typedef struct sgb { - unchar len[3]; - unchar ptr[3]; /* Also SCSI-style - MSB first */ -} Sgb; - -typedef struct scb { /* Command Control Block 5.4.1 */ - unchar op; /* Command Control Block Operation Code */ - unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */ - /* Outbound data transfer, length is checked */ - /* Inbound data transfer, length is checked */ - /* Logical Unit Number */ - unchar cdb[12]; /* SCSI Command Block */ - volatile unchar status; /* SCSI Return Status */ - volatile unchar vue; /* Vendor Unique Error Code */ - unchar maxlen[3]; /* Maximum Data Transfer Length */ - unchar dataptr[3]; /* SCSI Data Block Pointer */ - unchar linkptr[3]; /* Next Command Link Pointer */ - unchar direc; /* Transfer Direction */ - unchar reserved2[6]; /* SCSI Command Descriptor Block */ - /* end of hardware SCB */ - struct scsi_cmnd *SCpnt;/* scsi_cmnd using this SCB */ - Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */ - Adapter *host; /* host adapter */ - struct scb *next; /* for lists of scbs */ -} Scb; - -/* - * This driver is written to allow host-only commands to be executed. - * These use a 16-byte block called an ICB. The format is extended by the - * driver to 18 bytes, to support the status returned in the ICMB and - * an execution phase code. - * - * There are other formats besides these; these are the ones I've tried - * to use. Formats for some of the defined ICB opcodes are not defined - * (notably, get/set unsolicited interrupt status) in my copy of the OEM - * manual, and others are ambiguous/hard to follow. - */ -#define ICB_OP_MASK 0x80 /* distinguishes scbs from icbs */ -#define ICB_OP_OPEN_RBUF 0x80 /* open receive buffer */ -#define ICB_OP_RECV_CMD 0x81 /* receive command from initiator */ -#define ICB_OP_RECV_DATA 0x82 /* receive data from initiator */ -#define ICB_OP_RECV_SDATA 0x83 /* receive data with status from init. */ -#define ICB_OP_SEND_DATA 0x84 /* send data with status to initiator */ -#define ICB_OP_SEND_STAT 0x86 /* send command status to initiator */ - /* 0x87 is reserved */ -#define ICB_OP_READ_INIT 0x88 /* read initialization bytes */ -#define ICB_OP_READ_ID 0x89 /* read adapter's SCSI ID */ -#define ICB_OP_SET_UMASK 0x8A /* set unsolicited interrupt mask */ -#define ICB_OP_GET_UMASK 0x8B /* read unsolicited interrupt mask */ -#define ICB_OP_GET_REVISION 0x8C /* read firmware revision level */ -#define ICB_OP_DIAGNOSTICS 0x8D /* execute diagnostics */ -#define ICB_OP_SET_EPARMS 0x8E /* set execution parameters */ -#define ICB_OP_GET_EPARMS 0x8F /* read execution parameters */ - -typedef struct icbRecvCmd { - unchar op; - unchar IDlun; /* Initiator SCSI ID/lun */ - unchar len[3]; /* command buffer length */ - unchar ptr[3]; /* command buffer address */ - unchar rsvd[7]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ -} IcbRecvCmd; - -typedef struct icbSendStat { - unchar op; - unchar IDlun; /* Target SCSI ID/lun */ - unchar stat; /* (outgoing) completion status byte 1 */ - unchar rsvd[12]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ -} IcbSendStat; - -typedef struct icbRevLvl { - unchar op; - volatile unchar primary; /* primary revision level (returned) */ - volatile unchar secondary; /* secondary revision level (returned) */ - unchar rsvd[12]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ -} IcbRevLvl; - -typedef struct icbUnsMask { /* I'm totally guessing here */ - unchar op; - volatile unchar mask[14]; /* mask bits */ -#if 0 - unchar rsvd[12]; /* reserved */ -#endif - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ -} IcbUnsMask; - -typedef struct icbDiag { - unchar op; - unchar type; /* diagnostics type code (0-3) */ - unchar len[3]; /* buffer length */ - unchar ptr[3]; /* buffer address */ - unchar rsvd[7]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ -} IcbDiag; - -#define ICB_DIAG_POWERUP 0 /* Power-up diags only */ -#define ICB_DIAG_WALKING 1 /* walking 1's pattern */ -#define ICB_DIAG_DMA 2 /* DMA - system memory diags */ -#define ICB_DIAG_FULL 3 /* do both 1 & 2 */ - -typedef struct icbParms { - unchar op; - unchar rsvd1; /* reserved */ - unchar len[3]; /* parms buffer length */ - unchar ptr[3]; /* parms buffer address */ - unchar idx[2]; /* index (MSB-LSB) */ - unchar rsvd2[5]; /* reserved */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ -} IcbParms; - -typedef struct icbAny { - unchar op; - unchar data[14]; /* format-specific data */ - volatile unchar vue; /* vendor-unique error code */ - volatile unchar status; /* returned (icmb) status */ - volatile unchar phase; /* used by interrupt handler */ -} IcbAny; - -typedef union icb { - unchar op; /* ICB opcode */ - IcbRecvCmd recv_cmd; /* format for receive command */ - IcbSendStat send_stat; /* format for send status */ - IcbRevLvl rev_lvl; /* format for get revision level */ - IcbDiag diag; /* format for execute diagnostics */ - IcbParms eparms; /* format for get/set exec parms */ - IcbAny icb; /* generic format */ - unchar data[18]; -} Icb; - -#ifdef MODULE -static char *wd7000; -module_param(wd7000, charp, 0); -#endif - -/* - * Driver SCB structure pool. - * - * The SCBs declared here are shared by all host adapters; hence, this - * structure is not part of the Adapter structure. - */ -static Scb scbs[MAX_SCBS]; -static Scb *scbfree; /* free list */ -static int freescbs = MAX_SCBS; /* free list counter */ -static spinlock_t scbpool_lock; /* guards the scb free list and count */ - -/* - * END of data/declarations - code follows. - */ -static void __init setup_error(char *mesg, int *ints) -{ - if (ints[0] == 3) - printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", ints[1], ints[2], ints[3], mesg); - else if (ints[0] == 4) - printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], mesg); - else - printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], ints[5], mesg); -} - - -/* - * Note: You can now set these options from the kernel's "command line". - * The syntax is: - * - * wd7000=,,[,[,]] - * - * , where BUS_ON and BUS_OFF are in nanoseconds. BIOS default values - * are 8000ns for BUS_ON and 1875ns for BUS_OFF. - * eg: - * wd7000=7,6,0x350 - * - * will configure the driver for a WD-7000 controller - * using IRQ 15 with a DMA channel 6, at IO base address 0x350. - */ -static int __init wd7000_setup(char *str) -{ - static short wd7000_card_num; /* .bss will zero this */ - short i; - int ints[6]; - - (void) get_options(str, ARRAY_SIZE(ints), ints); - - if (wd7000_card_num >= NUM_CONFIGS) { - printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __func__); - return 0; - } - - if ((ints[0] < 3) || (ints[0] > 5)) { - printk(KERN_ERR "%s: Error in command line! " "Usage: wd7000=,,IO>[," "[,]]\n", __func__); - } else { - for (i = 0; i < NUM_IRQS; i++) - if (ints[1] == wd7000_irq[i]) - break; - - if (i == NUM_IRQS) { - setup_error("invalid IRQ.", ints); - return 0; - } else - configs[wd7000_card_num].irq = ints[1]; - - for (i = 0; i < NUM_DMAS; i++) - if (ints[2] == wd7000_dma[i]) - break; - - if (i == NUM_DMAS) { - setup_error("invalid DMA channel.", ints); - return 0; - } else - configs[wd7000_card_num].dma = ints[2]; - - for (i = 0; i < NUM_IOPORTS; i++) - if (ints[3] == wd7000_iobase[i]) - break; - - if (i == NUM_IOPORTS) { - setup_error("invalid I/O base address.", ints); - return 0; - } else - configs[wd7000_card_num].iobase = ints[3]; - - if (ints[0] > 3) { - if ((ints[4] < 500) || (ints[4] > 31875)) { - setup_error("BUS_ON value is out of range (500" " to 31875 nanoseconds)!", ints); - configs[wd7000_card_num].bus_on = BUS_ON; - } else - configs[wd7000_card_num].bus_on = ints[4] / 125; - } else - configs[wd7000_card_num].bus_on = BUS_ON; - - if (ints[0] > 4) { - if ((ints[5] < 500) || (ints[5] > 31875)) { - setup_error("BUS_OFF value is out of range (500" " to 31875 nanoseconds)!", ints); - configs[wd7000_card_num].bus_off = BUS_OFF; - } else - configs[wd7000_card_num].bus_off = ints[5] / 125; - } else - configs[wd7000_card_num].bus_off = BUS_OFF; - - if (wd7000_card_num) { - for (i = 0; i < (wd7000_card_num - 1); i++) { - int j = i + 1; - - for (; j < wd7000_card_num; j++) - if (configs[i].irq == configs[j].irq) { - setup_error("duplicated IRQ!", ints); - return 0; - } - if (configs[i].dma == configs[j].dma) { - setup_error("duplicated DMA " "channel!", ints); - return 0; - } - if (configs[i].iobase == configs[j].iobase) { - setup_error("duplicated I/O " "base address!", ints); - return 0; - } - } - } - - dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, " - "BUS_ON=%dns, BUS_OFF=%dns\n", configs[wd7000_card_num].irq, configs[wd7000_card_num].dma, configs[wd7000_card_num].iobase, configs[wd7000_card_num].bus_on * 125, configs[wd7000_card_num].bus_off * 125); - - wd7000_card_num++; - } - return 1; -} - -__setup("wd7000=", wd7000_setup); - -static inline void any2scsi(unchar * scsi, int any) -{ - *scsi++ = (unsigned)any >> 16; - *scsi++ = (unsigned)any >> 8; - *scsi++ = any; -} - -static inline int scsi2int(unchar * scsi) -{ - return (scsi[0] << 16) | (scsi[1] << 8) | scsi[2]; -} - -static inline void wd7000_enable_intr(Adapter * host) -{ - host->control |= INT_EN; - outb(host->control, host->iobase + ASC_CONTROL); -} - - -static inline void wd7000_enable_dma(Adapter * host) -{ - unsigned long flags; - host->control |= DMA_EN; - outb(host->control, host->iobase + ASC_CONTROL); - - flags = claim_dma_lock(); - set_dma_mode(host->dma, DMA_MODE_CASCADE); - enable_dma(host->dma); - release_dma_lock(flags); - -} - - -#define WAITnexttimeout 200 /* 2 seconds */ - -static inline short WAIT(unsigned port, unsigned mask, unsigned allof, unsigned noneof) -{ - unsigned WAITbits; - unsigned long WAITtimeout = jiffies + WAITnexttimeout; - - while (time_before_eq(jiffies, WAITtimeout)) { - WAITbits = inb(port) & mask; - - if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0)) - return (0); - } - - return (1); -} - - -static inline int command_out(Adapter * host, unchar * cmd, int len) -{ - if (!WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { - while (len--) { - do { - outb(*cmd, host->iobase + ASC_COMMAND); - WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0); - } while (inb(host->iobase + ASC_STAT) & CMD_REJ); - - cmd++; - } - - return (1); - } - - printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1); - - return (0); -} - - -/* - * This version of alloc_scbs is in preparation for supporting multiple - * commands per lun and command chaining, by queueing pending commands. - * We will need to allocate Scbs in blocks since they will wait to be - * executed so there is the possibility of deadlock otherwise. - * Also, to keep larger requests from being starved by smaller requests, - * we limit access to this routine with an internal busy flag, so that - * the satisfiability of a request is not dependent on the size of the - * request. - */ -static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed) -{ - Scb *scb, *p = NULL; - unsigned long flags; - unsigned long timeout = jiffies + WAITnexttimeout; - unsigned long now; - int i; - - if (needed <= 0) - return (NULL); /* sanity check */ - - spin_unlock_irq(host->host_lock); - - retry: - while (freescbs < needed) { - timeout = jiffies + WAITnexttimeout; - do { - /* FIXME: can we actually just yield here ?? */ - for (now = jiffies; now == jiffies;) - cpu_relax(); /* wait a jiffy */ - } while (freescbs < needed && time_before_eq(jiffies, timeout)); - /* - * If we get here with enough free Scbs, we can take them. - * Otherwise, we timed out and didn't get enough. - */ - if (freescbs < needed) { - printk(KERN_ERR "wd7000: can't get enough free SCBs.\n"); - return (NULL); - } - } - - /* Take the lock, then check we didn't get beaten, if so try again */ - spin_lock_irqsave(&scbpool_lock, flags); - if (freescbs < needed) { - spin_unlock_irqrestore(&scbpool_lock, flags); - goto retry; - } - - scb = scbfree; - freescbs -= needed; - for (i = 0; i < needed; i++) { - p = scbfree; - scbfree = p->next; - } - p->next = NULL; - - spin_unlock_irqrestore(&scbpool_lock, flags); - - spin_lock_irq(host->host_lock); - return (scb); -} - - -static inline void free_scb(Scb * scb) -{ - unsigned long flags; - - spin_lock_irqsave(&scbpool_lock, flags); - - memset(scb, 0, sizeof(Scb)); - scb->next = scbfree; - scbfree = scb; - freescbs++; - - spin_unlock_irqrestore(&scbpool_lock, flags); -} - - -static inline void init_scbs(void) -{ - int i; - - spin_lock_init(&scbpool_lock); - - /* This is only ever called before the SCB pool is active */ - - scbfree = &(scbs[0]); - memset(scbs, 0, sizeof(scbs)); - for (i = 0; i < MAX_SCBS - 1; i++) { - scbs[i].next = &(scbs[i + 1]); - scbs[i].SCpnt = NULL; - } - scbs[MAX_SCBS - 1].next = NULL; - scbs[MAX_SCBS - 1].SCpnt = NULL; -} - - -static int mail_out(Adapter * host, Scb * scbptr) -/* - * Note: this can also be used for ICBs; just cast to the parm type. - */ -{ - int i, ogmb; - unsigned long flags; - unchar start_ogmb; - Mailbox *ogmbs = host->mb.ogmb; - int *next_ogmb = &(host->next_ogmb); - - dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr); - - /* We first look for a free outgoing mailbox */ - spin_lock_irqsave(host->sh->host_lock, flags); - ogmb = *next_ogmb; - for (i = 0; i < OGMB_CNT; i++) { - if (ogmbs[ogmb].status == 0) { - dprintk(" using OGMB 0x%x", ogmb); - ogmbs[ogmb].status = 1; - any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr); - - *next_ogmb = (ogmb + 1) % OGMB_CNT; - break; - } else - ogmb = (ogmb + 1) % OGMB_CNT; - } - spin_unlock_irqrestore(host->sh->host_lock, flags); - - dprintk(", scb is 0x%06lx", (long) scbptr); - - if (i >= OGMB_CNT) { - /* - * Alternatively, we might issue the "interrupt on free OGMB", - * and sleep, but it must be ensured that it isn't the init - * task running. Instead, this version assumes that the caller - * will be persistent, and try again. Since it's the adapter - * that marks OGMB's free, waiting even with interrupts off - * should work, since they are freed very quickly in most cases. - */ - dprintk(", no free OGMBs.\n"); - return (0); - } - - wd7000_enable_intr(host); - - start_ogmb = START_OGMB | ogmb; - command_out(host, &start_ogmb, 1); - - dprintk(", awaiting interrupt.\n"); - - return (1); -} - - -static int make_code(unsigned hosterr, unsigned scsierr) -{ -#ifdef WD7000_DEBUG - int in_error = hosterr; -#endif - - switch ((hosterr >> 8) & 0xff) { - case 0: /* Reserved */ - hosterr = DID_ERROR; - break; - case 1: /* Command Complete, no errors */ - hosterr = DID_OK; - break; - case 2: /* Command complete, error logged in scb status (scsierr) */ - hosterr = DID_OK; - break; - case 4: /* Command failed to complete - timeout */ - hosterr = DID_TIME_OUT; - break; - case 5: /* Command terminated; Bus reset by external device */ - hosterr = DID_RESET; - break; - case 6: /* Unexpected Command Received w/ host as target */ - hosterr = DID_BAD_TARGET; - break; - case 80: /* Unexpected Reselection */ - case 81: /* Unexpected Selection */ - hosterr = DID_BAD_INTR; - break; - case 82: /* Abort Command Message */ - hosterr = DID_ABORT; - break; - case 83: /* SCSI Bus Software Reset */ - case 84: /* SCSI Bus Hardware Reset */ - hosterr = DID_RESET; - break; - default: /* Reserved */ - hosterr = DID_ERROR; - } -#ifdef WD7000_DEBUG - if (scsierr || hosterr) - dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", scsierr, in_error, hosterr); -#endif - return (scsierr | (hosterr << 16)); -} - -#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK) - - -static irqreturn_t wd7000_intr(int irq, void *dev_id) -{ - Adapter *host = (Adapter *) dev_id; - int flag, icmb, errstatus, icmb_status; - int host_error, scsi_error; - Scb *scb; /* for SCSI commands */ - IcbAny *icb; /* for host commands */ - struct scsi_cmnd *SCpnt; - Mailbox *icmbs = host->mb.icmb; - unsigned long flags; - - spin_lock_irqsave(host->sh->host_lock, flags); - host->int_counter++; - - dprintk("wd7000_intr: irq = %d, host = 0x%06lx\n", irq, (long) host); - - flag = inb(host->iobase + ASC_INTR_STAT); - - dprintk("wd7000_intr: intr stat = 0x%02x\n", flag); - - if (!(inb(host->iobase + ASC_STAT) & INT_IM)) { - /* NB: these are _very_ possible if IRQ 15 is being used, since - * it's the "garbage collector" on the 2nd 8259 PIC. Specifically, - * any interrupt signal into the 8259 which can't be identified - * comes out as 7 from the 8259, which is 15 to the host. Thus, it - * is a good thing the WD7000 has an interrupt status port, so we - * can sort these out. Otherwise, electrical noise and other such - * problems would be indistinguishable from valid interrupts... - */ - dprintk("wd7000_intr: phantom interrupt...\n"); - goto ack; - } - - if (!(flag & MB_INTR)) - goto ack; - - /* The interrupt is for a mailbox */ - if (!(flag & IMB_INTR)) { - dprintk("wd7000_intr: free outgoing mailbox\n"); - /* - * If sleep_on() and the "interrupt on free OGMB" command are - * used in mail_out(), wake_up() should correspondingly be called - * here. For now, we don't need to do anything special. - */ - goto ack; - } - - /* The interrupt is for an incoming mailbox */ - icmb = flag & MB_MASK; - icmb_status = icmbs[icmb].status; - if (icmb_status & 0x80) { /* unsolicited - result in ICMB */ - dprintk("wd7000_intr: unsolicited interrupt 0x%02x\n", icmb_status); - goto ack; - } - - /* Aaaargh! (Zaga) */ - scb = isa_bus_to_virt(scsi2int((unchar *) icmbs[icmb].scbptr)); - icmbs[icmb].status = 0; - if (scb->op & ICB_OP_MASK) { /* an SCB is done */ - icb = (IcbAny *) scb; - icb->status = icmb_status; - icb->phase = 0; - goto ack; - } - - SCpnt = scb->SCpnt; - if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */ - host_error = scb->vue | (icmb_status << 8); - scsi_error = scb->status; - errstatus = make_code(host_error, scsi_error); - SCpnt->result = errstatus; - - free_scb(scb); - - SCpnt->scsi_done(SCpnt); - } - - ack: - dprintk("wd7000_intr: return from interrupt handler\n"); - wd7000_intr_ack(host); - - spin_unlock_irqrestore(host->sh->host_lock, flags); - return IRQ_HANDLED; -} - -static int wd7000_queuecommand_lck(struct scsi_cmnd *SCpnt, - void (*done)(struct scsi_cmnd *)) -{ - Scb *scb; - Sgb *sgb; - unchar *cdb = (unchar *) SCpnt->cmnd; - unchar idlun; - short cdblen; - int nseg; - Adapter *host = (Adapter *) SCpnt->device->host->hostdata; - - cdblen = SCpnt->cmd_len; - idlun = ((SCpnt->device->id << 5) & 0xe0) | (SCpnt->device->lun & 7); - SCpnt->scsi_done = done; - SCpnt->SCp.phase = 1; - scb = alloc_scbs(SCpnt->device->host, 1); - scb->idlun = idlun; - memcpy(scb->cdb, cdb, cdblen); - scb->direc = 0x40; /* Disable direction check */ - - scb->SCpnt = SCpnt; /* so we can find stuff later */ - SCpnt->host_scribble = (unchar *) scb; - scb->host = host; - - nseg = scsi_sg_count(SCpnt); - if (nseg > 1) { - struct scatterlist *sg; - unsigned i; - - dprintk("Using scatter/gather with %d elements.\n", nseg); - - sgb = scb->sgb; - scb->op = 1; - any2scsi(scb->dataptr, (int) sgb); - any2scsi(scb->maxlen, nseg * sizeof(Sgb)); - - scsi_for_each_sg(SCpnt, sg, nseg, i) { - any2scsi(sgb[i].ptr, isa_page_to_bus(sg_page(sg)) + sg->offset); - any2scsi(sgb[i].len, sg->length); - } - } else { - scb->op = 0; - if (nseg) { - struct scatterlist *sg = scsi_sglist(SCpnt); - any2scsi(scb->dataptr, isa_page_to_bus(sg_page(sg)) + sg->offset); - } - any2scsi(scb->maxlen, scsi_bufflen(SCpnt)); - } - - /* FIXME: drop lock and yield here ? */ - - while (!mail_out(host, scb)) - cpu_relax(); /* keep trying */ - - return 0; -} - -static DEF_SCSI_QCMD(wd7000_queuecommand) - -static int wd7000_diagnostics(Adapter * host, int code) -{ - static IcbDiag icb = { ICB_OP_DIAGNOSTICS }; - static unchar buf[256]; - unsigned long timeout; - - icb.type = code; - any2scsi(icb.len, sizeof(buf)); - any2scsi(icb.ptr, (int) &buf); - icb.phase = 1; - /* - * This routine is only called at init, so there should be OGMBs - * available. I'm assuming so here. If this is going to - * fail, I can just let the timeout catch the failure. - */ - mail_out(host, (struct scb *) &icb); - timeout = jiffies + WAITnexttimeout; /* wait up to 2 seconds */ - while (icb.phase && time_before(jiffies, timeout)) { - cpu_relax(); /* wait for completion */ - barrier(); - } - - if (icb.phase) { - printk("wd7000_diagnostics: timed out.\n"); - return (0); - } - if (make_code(icb.vue | (icb.status << 8), 0)) { - printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n", icb.vue, icb.status); - return (0); - } - - return (1); -} - - -static int wd7000_adapter_reset(Adapter * host) -{ - InitCmd init_cmd = { - INITIALIZATION, - 7, - host->bus_on, - host->bus_off, - 0, - {0, 0, 0}, - OGMB_CNT, - ICMB_CNT - }; - int diag; - /* - * Reset the adapter - only. The SCSI bus was initialized at power-up, - * and we need to do this just so we control the mailboxes, etc. - */ - outb(ASC_RES, host->iobase + ASC_CONTROL); - udelay(40); /* reset pulse: this is 40us, only need 25us */ - outb(0, host->iobase + ASC_CONTROL); - host->control = 0; /* this must always shadow ASC_CONTROL */ - - if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { - printk(KERN_ERR "wd7000_init: WAIT timed out.\n"); - return -1; /* -1 = not ok */ - } - - if ((diag = inb(host->iobase + ASC_INTR_STAT)) != 1) { - printk("wd7000_init: "); - - switch (diag) { - case 2: - printk(KERN_ERR "RAM failure.\n"); - break; - case 3: - printk(KERN_ERR "FIFO R/W failed\n"); - break; - case 4: - printk(KERN_ERR "SBIC register R/W failed\n"); - break; - case 5: - printk(KERN_ERR "Initialization D-FF failed.\n"); - break; - case 6: - printk(KERN_ERR "Host IRQ D-FF failed.\n"); - break; - case 7: - printk(KERN_ERR "ROM checksum error.\n"); - break; - default: - printk(KERN_ERR "diagnostic code 0x%02Xh received.\n", diag); - } - return -1; - } - /* Clear mailboxes */ - memset(&(host->mb), 0, sizeof(host->mb)); - - /* Execute init command */ - any2scsi((unchar *) & (init_cmd.mailboxes), (int) &(host->mb)); - if (!command_out(host, (unchar *) & init_cmd, sizeof(init_cmd))) { - printk(KERN_ERR "wd7000_adapter_reset: adapter initialization failed.\n"); - return -1; - } - - if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) { - printk("wd7000_adapter_reset: WAIT timed out.\n"); - return -1; - } - return 0; -} - -static int wd7000_init(Adapter * host) -{ - if (wd7000_adapter_reset(host) == -1) - return 0; - - - if (request_irq(host->irq, wd7000_intr, IRQF_DISABLED, "wd7000", host)) { - printk("wd7000_init: can't get IRQ %d.\n", host->irq); - return (0); - } - if (request_dma(host->dma, "wd7000")) { - printk("wd7000_init: can't get DMA channel %d.\n", host->dma); - free_irq(host->irq, host); - return (0); - } - wd7000_enable_dma(host); - wd7000_enable_intr(host); - - if (!wd7000_diagnostics(host, ICB_DIAG_FULL)) { - free_dma(host->dma); - free_irq(host->irq, NULL); - return (0); - } - - return (1); -} - - -static void wd7000_revision(Adapter * host) -{ - static IcbRevLvl icb = { ICB_OP_GET_REVISION }; - - icb.phase = 1; - /* - * Like diagnostics, this is only done at init time, in fact, from - * wd7000_detect, so there should be OGMBs available. If it fails, - * the only damage will be that the revision will show up as 0.0, - * which in turn means that scatter/gather will be disabled. - */ - mail_out(host, (struct scb *) &icb); - while (icb.phase) { - cpu_relax(); /* wait for completion */ - barrier(); - } - host->rev1 = icb.primary; - host->rev2 = icb.secondary; -} - - -#undef SPRINTF -#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } - -static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host) -{ - dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length); - - /* - * Currently this is a no-op - */ - dprintk("Sorry, this function is currently out of order...\n"); - return (length); -} - - -static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout) -{ - Adapter *adapter = (Adapter *)host->hostdata; - unsigned long flags; - char *pos = buffer; -#ifdef WD7000_DEBUG - Mailbox *ogmbs, *icmbs; - short count; -#endif - - /* - * Has data been written to the file ? - */ - if (inout) - return (wd7000_set_info(buffer, length, host)); - - spin_lock_irqsave(host->host_lock, flags); - SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2); - SPRINTF(" IO base: 0x%x\n", adapter->iobase); - SPRINTF(" IRQ: %d\n", adapter->irq); - SPRINTF(" DMA channel: %d\n", adapter->dma); - SPRINTF(" Interrupts: %d\n", adapter->int_counter); - SPRINTF(" BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125); - SPRINTF(" BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125); - -#ifdef WD7000_DEBUG - ogmbs = adapter->mb.ogmb; - icmbs = adapter->mb.icmb; - - SPRINTF("\nControl port value: 0x%x\n", adapter->control); - SPRINTF("Incoming mailbox:\n"); - SPRINTF(" size: %d\n", ICMB_CNT); - SPRINTF(" queued messages: "); - - for (i = count = 0; i < ICMB_CNT; i++) - if (icmbs[i].status) { - count++; - SPRINTF("0x%x ", i); - } - - SPRINTF(count ? "\n" : "none\n"); - - SPRINTF("Outgoing mailbox:\n"); - SPRINTF(" size: %d\n", OGMB_CNT); - SPRINTF(" next message: 0x%x\n", adapter->next_ogmb); - SPRINTF(" queued messages: "); - - for (i = count = 0; i < OGMB_CNT; i++) - if (ogmbs[i].status) { - count++; - SPRINTF("0x%x ", i); - } - - SPRINTF(count ? "\n" : "none\n"); -#endif - - spin_unlock_irqrestore(host->host_lock, flags); - - /* - * Calculate start of next buffer, and return value. - */ - *start = buffer + offset; - - if ((pos - buffer) < offset) - return (0); - else if ((pos - buffer - offset) < length) - return (pos - buffer - offset); - else - return (length); -} - - -/* - * Returns the number of adapters this driver is supporting. - * - * The source for hosts.c says to wait to call scsi_register until 100% - * sure about an adapter. We need to do it a little sooner here; we - * need the storage set up by scsi_register before wd7000_init, and - * changing the location of an Adapter structure is more trouble than - * calling scsi_unregister. - * - */ - -static __init int wd7000_detect(struct scsi_host_template *tpnt) -{ - short present = 0, biosaddr_ptr, sig_ptr, i, pass; - short biosptr[NUM_CONFIGS]; - unsigned iobase; - Adapter *host = NULL; - struct Scsi_Host *sh; - int unit = 0; - - dprintk("wd7000_detect: started\n"); - -#ifdef MODULE - if (wd7000) - wd7000_setup(wd7000); -#endif - - for (i = 0; i < UNITS; wd7000_host[i++] = NULL); - for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1); - - tpnt->proc_name = "wd7000"; - tpnt->proc_info = &wd7000_proc_info; - - /* - * Set up SCB free list, which is shared by all adapters - */ - init_scbs(); - - for (pass = 0; pass < NUM_CONFIGS; pass++) { - /* - * First, search for BIOS SIGNATURE... - */ - for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++) - for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) { - for (i = 0; i < pass; i++) - if (biosptr[i] == biosaddr_ptr) - break; - - if (i == pass) { - void __iomem *biosaddr = ioremap(wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs, - signatures[sig_ptr].len); - short bios_match = 1; - - if (biosaddr) - bios_match = check_signature(biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len); - - iounmap(biosaddr); - - if (bios_match) - goto bios_matched; - } - } - - bios_matched: - /* - * BIOS SIGNATURE has been found. - */ -#ifdef WD7000_DEBUG - dprintk("wd7000_detect: pass %d\n", pass + 1); - - if (biosaddr_ptr == NUM_ADDRS) - dprintk("WD-7000 SST BIOS not detected...\n"); - else - dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]); -#endif - - if (configs[pass].irq < 0) - continue; - - if (unit == UNITS) - continue; - - iobase = configs[pass].iobase; - - dprintk("wd7000_detect: check IO 0x%x region...\n", iobase); - - if (request_region(iobase, 4, "wd7000")) { - - dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase); - /* - * ASC reset... - */ - outb(ASC_RES, iobase + ASC_CONTROL); - msleep(10); - outb(0, iobase + ASC_CONTROL); - - if (WAIT(iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) { - dprintk("failed!\n"); - goto err_release; - } else - dprintk("ok!\n"); - - if (inb(iobase + ASC_INTR_STAT) == 1) { - /* - * We register here, to get a pointer to the extra space, - * which we'll use as the Adapter structure (host) for - * this adapter. It is located just after the registered - * Scsi_Host structure (sh), and is located by the empty - * array hostdata. - */ - sh = scsi_register(tpnt, sizeof(Adapter)); - if (sh == NULL) - goto err_release; - - host = (Adapter *) sh->hostdata; - - dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host); - memset(host, 0, sizeof(Adapter)); - - host->irq = configs[pass].irq; - host->dma = configs[pass].dma; - host->iobase = iobase; - host->int_counter = 0; - host->bus_on = configs[pass].bus_on; - host->bus_off = configs[pass].bus_off; - host->sh = wd7000_host[unit] = sh; - unit++; - - dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma); - - if (!wd7000_init(host)) /* Initialization failed */ - goto err_unregister; - - /* - * OK from here - we'll use this adapter/configuration. - */ - wd7000_revision(host); /* important for scatter/gather */ - - /* - * For boards before rev 6.0, scatter/gather isn't supported. - */ - if (host->rev1 < 6) - sh->sg_tablesize = 1; - - present++; /* count it */ - - if (biosaddr_ptr != NUM_ADDRS) - biosptr[pass] = biosaddr_ptr; - - printk(KERN_INFO "Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2); - printk("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma); - printk(" BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125); - } - } else - dprintk("wd7000_detect: IO 0x%x region already allocated!\n", iobase); - - continue; - - err_unregister: - scsi_unregister(sh); - err_release: - release_region(iobase, 4); - - } - - if (!present) - printk("Failed initialization of WD-7000 SCSI card!\n"); - - return (present); -} - -static int wd7000_release(struct Scsi_Host *shost) -{ - if (shost->irq) - free_irq(shost->irq, NULL); - if (shost->io_port && shost->n_io_port) - release_region(shost->io_port, shost->n_io_port); - scsi_unregister(shost); - return 0; -} - -#if 0 -/* - * I have absolutely NO idea how to do an abort with the WD7000... - */ -static int wd7000_abort(Scsi_Cmnd * SCpnt) -{ - Adapter *host = (Adapter *) SCpnt->device->host->hostdata; - - if (inb(host->iobase + ASC_STAT) & INT_IM) { - printk("wd7000_abort: lost interrupt\n"); - wd7000_intr_handle(host->irq, NULL, NULL); - return FAILED; - } - return FAILED; -} -#endif - -/* - * Last resort. Reinitialize the board. - */ - -static int wd7000_host_reset(struct scsi_cmnd *SCpnt) -{ - Adapter *host = (Adapter *) SCpnt->device->host->hostdata; - - spin_lock_irq(SCpnt->device->host->host_lock); - - if (wd7000_adapter_reset(host) < 0) { - spin_unlock_irq(SCpnt->device->host->host_lock); - return FAILED; - } - - wd7000_enable_intr(host); - - spin_unlock_irq(SCpnt->device->host->host_lock); - return SUCCESS; -} - -/* - * This was borrowed directly from aha1542.c. (Zaga) - */ - -static int wd7000_biosparam(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *ip) -{ - char b[BDEVNAME_SIZE]; - - dprintk("wd7000_biosparam: dev=%s, size=%d, ", - bdevname(bdev, b), capacity); - (void)b; /* unused var warning? */ - - /* - * try default translation - */ - ip[0] = 64; - ip[1] = 32; - ip[2] = capacity >> 11; - - /* - * for disks >1GB do some guessing - */ - if (ip[2] >= 1024) { - int info[3]; - - /* - * try to figure out the geometry from the partition table - */ - if ((scsicam_bios_param(bdev, capacity, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) { - printk("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" " using extended translation.\n"); - - ip[0] = 255; - ip[1] = 63; - ip[2] = (unsigned long) capacity / (255 * 63); - } else { - ip[0] = info[0]; - ip[1] = info[1]; - ip[2] = info[2]; - - if (info[0] == 255) - printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __func__); - } - } - - dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]); - dprintk("WARNING: check, if the bios geometry is correct.\n"); - - return (0); -} - -MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac"); -MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers"); -MODULE_LICENSE("GPL"); - -static struct scsi_host_template driver_template = { - .proc_name = "wd7000", - .proc_info = wd7000_proc_info, - .name = "Western Digital WD-7000", - .detect = wd7000_detect, - .release = wd7000_release, - .queuecommand = wd7000_queuecommand, - .eh_host_reset_handler = wd7000_host_reset, - .bios_param = wd7000_biosparam, - .can_queue = WD7000_Q, - .this_id = 7, - .sg_tablesize = WD7000_SG, - .cmd_per_lun = 1, - .unchecked_isa_dma = 1, - .use_clustering = ENABLE_CLUSTERING, -}; - -#include "scsi_module.c" diff --git a/ANDROID_3.4.5/drivers/scsi/zalon.c b/ANDROID_3.4.5/drivers/scsi/zalon.c deleted file mode 100644 index 27e84e4b..00000000 --- a/ANDROID_3.4.5/drivers/scsi/zalon.c +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Zalon 53c7xx device driver. - * By Richard Hirst (rhirst@linuxcare.com) - */ - -#include -#include -#include -#include -#include -#include - -#include "../parisc/gsc.h" - -#include "ncr53c8xx.h" - -MODULE_AUTHOR("Richard Hirst"); -MODULE_DESCRIPTION("Bluefish/Zalon 720 SCSI Driver"); -MODULE_LICENSE("GPL"); - -#define GSC_SCSI_ZALON_OFFSET 0x800 - -#define IO_MODULE_EIM (1*4) -#define IO_MODULE_DC_ADATA (2*4) -#define IO_MODULE_II_CDATA (3*4) -#define IO_MODULE_IO_COMMAND (12*4) -#define IO_MODULE_IO_STATUS (13*4) - -#define IOSTATUS_RY 0x40 -#define IOSTATUS_FE 0x80 -#define IOIIDATA_SMINT5L 0x40000000 -#define IOIIDATA_MINT5EN 0x20000000 -#define IOIIDATA_PACKEN 0x10000000 -#define IOIIDATA_PREFETCHEN 0x08000000 -#define IOIIDATA_IOII 0x00000020 - -#define CMD_RESET 5 - -static struct ncr_chip zalon720_chip __initdata = { - .revision_id = 0x0f, - .burst_max = 3, - .offset_max = 8, - .nr_divisor = 4, - .features = FE_WIDE | FE_DIFF | FE_EHP| FE_MUX | FE_EA, -}; - - - -#if 0 -/* FIXME: - * Is this function dead code? or is someone planning on using it in the - * future. The clock = (int) pdc_result[16] does not look correct to - * me ... I think it should be iodc_data[16]. Since this cause a compile - * error with the new encapsulated PDC, I'm not compiling in this function. - * - RB - */ -/* poke SCSI clock out of iodc data */ - -static u8 iodc_data[32] __attribute__ ((aligned (64))); -static unsigned long pdc_result[32] __attribute__ ((aligned (16))) ={0,0,0,0}; - -static int -lasi_scsi_clock(void * hpa, int defaultclock) -{ - int clock, status; - - status = pdc_iodc_read(&pdc_result, hpa, 0, &iodc_data, 32 ); - if (status == PDC_RET_OK) { - clock = (int) pdc_result[16]; - } else { - printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __func__, status); - clock = defaultclock; - } - - printk(KERN_DEBUG "%s: SCSI clock %d\n", __func__, clock); - return clock; -} -#endif - -static struct scsi_host_template zalon7xx_template = { - .module = THIS_MODULE, - .proc_name = "zalon7xx", -}; - -static int __init -zalon_probe(struct parisc_device *dev) -{ - struct gsc_irq gsc_irq; - u32 zalon_vers; - int error = -ENODEV; - void __iomem *zalon = ioremap_nocache(dev->hpa.start, 4096); - void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET; - static int unit = 0; - struct Scsi_Host *host; - struct ncr_device device; - - __raw_writel(CMD_RESET, zalon + IO_MODULE_IO_COMMAND); - while (!(__raw_readl(zalon + IO_MODULE_IO_STATUS) & IOSTATUS_RY)) - cpu_relax(); - __raw_writel(IOIIDATA_MINT5EN | IOIIDATA_PACKEN | IOIIDATA_PREFETCHEN, - zalon + IO_MODULE_II_CDATA); - - /* XXX: Save the Zalon version for bug workarounds? */ - zalon_vers = (__raw_readl(zalon + IO_MODULE_II_CDATA) >> 24) & 0x07; - - /* Setup the interrupts first. - ** Later on request_irq() will register the handler. - */ - dev->irq = gsc_alloc_irq(&gsc_irq); - - printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __func__, - zalon_vers, dev->irq); - - __raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM); - - if (zalon_vers == 0) - printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __func__); - - memset(&device, 0, sizeof(struct ncr_device)); - - /* The following three are needed before any other access. */ - __raw_writeb(0x20, io_port + 0x38); /* DCNTL_REG, EA */ - __raw_writeb(0x04, io_port + 0x1b); /* CTEST0_REG, EHP */ - __raw_writeb(0x80, io_port + 0x22); /* CTEST4_REG, MUX */ - - /* Initialise ncr_device structure with items required by ncr_attach. */ - device.chip = zalon720_chip; - device.host_id = 7; - device.dev = &dev->dev; - device.slot.base = dev->hpa.start + GSC_SCSI_ZALON_OFFSET; - device.slot.base_v = io_port; - device.slot.irq = dev->irq; - device.differential = 2; - - host = ncr_attach(&zalon7xx_template, unit, &device); - if (!host) - return -ENODEV; - - if (request_irq(dev->irq, ncr53c8xx_intr, IRQF_SHARED, "zalon", host)) { - dev_printk(KERN_ERR, &dev->dev, "irq problem with %d, detaching\n ", - dev->irq); - goto fail; - } - - unit++; - - dev_set_drvdata(&dev->dev, host); - - error = scsi_add_host(host, &dev->dev); - if (error) - goto fail_free_irq; - - scsi_scan_host(host); - return 0; - - fail_free_irq: - free_irq(dev->irq, host); - fail: - ncr53c8xx_release(host); - return error; -} - -static struct parisc_device_id zalon_tbl[] = { - { HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00089 }, - { 0, } -}; - -MODULE_DEVICE_TABLE(parisc, zalon_tbl); - -static int __exit zalon_remove(struct parisc_device *dev) -{ - struct Scsi_Host *host = dev_get_drvdata(&dev->dev); - - scsi_remove_host(host); - ncr53c8xx_release(host); - free_irq(dev->irq, host); - - return 0; -} - -static struct parisc_driver zalon_driver = { - .name = "zalon", - .id_table = zalon_tbl, - .probe = zalon_probe, - .remove = __devexit_p(zalon_remove), -}; - -static int __init zalon7xx_init(void) -{ - int ret = ncr53c8xx_init(); - if (!ret) - ret = register_parisc_driver(&zalon_driver); - if (ret) - ncr53c8xx_exit(); - return ret; -} - -static void __exit zalon7xx_exit(void) -{ - unregister_parisc_driver(&zalon_driver); - ncr53c8xx_exit(); -} - -module_init(zalon7xx_init); -module_exit(zalon7xx_exit); diff --git a/ANDROID_3.4.5/drivers/scsi/zorro7xx.c b/ANDROID_3.4.5/drivers/scsi/zorro7xx.c deleted file mode 100644 index e17764d7..00000000 --- a/ANDROID_3.4.5/drivers/scsi/zorro7xx.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux. - * Amiga MacroSystemUS WarpEngine SCSI controller. - * Amiga Technologies/DKB A4091 SCSI controller. - * - * Written 1997 by Alan Hourihane - * plus modifications of the 53c7xx.c driver to support the Amiga. - * - * Rewritten to use 53c700.c by Kars de Jong - */ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "53c700.h" - -MODULE_AUTHOR("Alan Hourihane / Kars de Jong "); -MODULE_DESCRIPTION("Amiga Zorro NCR53C710 driver"); -MODULE_LICENSE("GPL"); - - -static struct scsi_host_template zorro7xx_scsi_driver_template = { - .proc_name = "zorro7xx", - .this_id = 7, - .module = THIS_MODULE, -}; - -static struct zorro_driver_data { - const char *name; - unsigned long offset; - int absolute; /* offset is absolute address */ -} zorro7xx_driver_data[] __devinitdata = { - { .name = "PowerUP 603e+", .offset = 0xf40000, .absolute = 1 }, - { .name = "WarpEngine 40xx", .offset = 0x40000 }, - { .name = "A4091", .offset = 0x800000 }, - { .name = "GForce 040/060", .offset = 0x40000 }, - { 0 } -}; - -static struct zorro_device_id zorro7xx_zorro_tbl[] __devinitdata = { - { - .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS, - .driver_data = (unsigned long)&zorro7xx_driver_data[0], - }, - { - .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, - .driver_data = (unsigned long)&zorro7xx_driver_data[1], - }, - { - .id = ZORRO_PROD_CBM_A4091_1, - .driver_data = (unsigned long)&zorro7xx_driver_data[2], - }, - { - .id = ZORRO_PROD_CBM_A4091_2, - .driver_data = (unsigned long)&zorro7xx_driver_data[2], - }, - { - .id = ZORRO_PROD_GVP_GFORCE_040_060, - .driver_data = (unsigned long)&zorro7xx_driver_data[3], - }, - { 0 } -}; -MODULE_DEVICE_TABLE(zorro, zorro7xx_zorro_tbl); - -static int __devinit zorro7xx_init_one(struct zorro_dev *z, - const struct zorro_device_id *ent) -{ - struct Scsi_Host *host; - struct NCR_700_Host_Parameters *hostdata; - struct zorro_driver_data *zdd; - unsigned long board, ioaddr; - - board = zorro_resource_start(z); - zdd = (struct zorro_driver_data *)ent->driver_data; - - if (zdd->absolute) { - ioaddr = zdd->offset; - } else { - ioaddr = board + zdd->offset; - } - - if (!zorro_request_device(z, zdd->name)) { - printk(KERN_ERR "zorro7xx: cannot reserve region 0x%lx, abort\n", - board); - return -EBUSY; - } - - hostdata = kzalloc(sizeof(struct NCR_700_Host_Parameters), GFP_KERNEL); - if (!hostdata) { - printk(KERN_ERR "zorro7xx: Failed to allocate host data\n"); - goto out_release; - } - - /* Fill in the required pieces of hostdata */ - if (ioaddr > 0x01000000) - hostdata->base = ioremap(ioaddr, zorro_resource_len(z)); - else - hostdata->base = (void __iomem *)ZTWO_VADDR(ioaddr); - - hostdata->clock = 50; - hostdata->chip710 = 1; - - /* Settings for at least WarpEngine 40xx */ - hostdata->ctest7_extra = CTEST7_TT1; - - zorro7xx_scsi_driver_template.name = zdd->name; - - /* and register the chip */ - host = NCR_700_detect(&zorro7xx_scsi_driver_template, hostdata, - &z->dev); - if (!host) { - printk(KERN_ERR "zorro7xx: No host detected; " - "board configuration problem?\n"); - goto out_free; - } - - host->this_id = 7; - host->base = ioaddr; - host->irq = IRQ_AMIGA_PORTS; - - if (request_irq(host->irq, NCR_700_intr, IRQF_SHARED, "zorro7xx-scsi", - host)) { - printk(KERN_ERR "zorro7xx: request_irq failed\n"); - goto out_put_host; - } - - zorro_set_drvdata(z, host); - scsi_scan_host(host); - - return 0; - - out_put_host: - scsi_host_put(host); - out_free: - if (ioaddr > 0x01000000) - iounmap(hostdata->base); - kfree(hostdata); - out_release: - zorro_release_device(z); - - return -ENODEV; -} - -static __devexit void zorro7xx_remove_one(struct zorro_dev *z) -{ - struct Scsi_Host *host = zorro_get_drvdata(z); - struct NCR_700_Host_Parameters *hostdata = shost_priv(host); - - scsi_remove_host(host); - - NCR_700_release(host); - kfree(hostdata); - free_irq(host->irq, host); - zorro_release_device(z); -} - -static struct zorro_driver zorro7xx_driver = { - .name = "zorro7xx-scsi", - .id_table = zorro7xx_zorro_tbl, - .probe = zorro7xx_init_one, - .remove = __devexit_p(zorro7xx_remove_one), -}; - -static int __init zorro7xx_scsi_init(void) -{ - return zorro_register_driver(&zorro7xx_driver); -} - -static void __exit zorro7xx_scsi_exit(void) -{ - zorro_unregister_driver(&zorro7xx_driver); -} - -module_init(zorro7xx_scsi_init); -module_exit(zorro7xx_scsi_exit); -- cgit